openttd-1.5.3/0000755000000000000000000000000012627373607011710 5ustar rootrootopenttd-1.5.3/os/0000755000000000000000000000000012627373447012333 5ustar rootrootopenttd-1.5.3/os/windows/0000755000000000000000000000000012627373447014025 5ustar rootrootopenttd-1.5.3/os/windows/installer/0000755000000000000000000000000012627373447016022 5ustar rootrootopenttd-1.5.3/os/windows/installer/top.bmp0000644000000000000000000006233412627373447017334 0ustar rootrootBMd6(9d  ~yˌppp˃ȵ唰f~f~yyyyyރy޿f~fw˗ºն}}}n~ow>>*""+ :((E52RE :((E5 :((E5 :(2RE :( :((E52RE(E5 :(2RE :( :( :( :(2RE(E5(E52RE(E5 :((E5 :((E5555BBBWWWbbb :(lWW :((E5 :((E52RE(E52RE :((E5 :((E5 :((E52RE(E52RE :( :(- :(555 :((E5 :( :( :(BBB- :((E52RE :((E5 :((E5 :(2RE :( :((E52RE(E5 :(2RE :( :( :( :(2RE(E5(E52RE(E5 :((E5 :((E52RE :(lWW :((E5 :(***5Ebbb/ER(E52RE :(ooobbb(E52RE(E52RE :( :(-- :( :( :( :(2RE :(-- :( :(2RE(E5yyyooo :(Byyyooo- :(- :(--" " ":% ***555LLLbbb444 *#?+&E/>eUll1UA1UA'H11UA'H11UA1UAll1UA'H11UA'H11UA'H11UA>eU'H11UA'H1'H11UA'H1'H1ll'H1>eU'H1RRR___yyyyyy>eU1UA1UA'H1>eU>eU1UA'H11UA'H11UA>eU'H1ll'H11UA'H1'H11UA'H1>eU'H17$'H1'H17$'H17$'H1'H1>eUll1UA1UA'H11UA'H11UA1UAll1UA'H11UA'H11UA'H11UA>eU'H11UA'H1'H11UA'H1'H1ll'H1>eU'H1'H1'H11UA1UA'H1444$AU;UeRRRKl|;Ue1UA'H1lll'H11UA'H1'H11UA'H1>eU'H17$7$'H1'H17$7$'H1u1UA1UA'H1|R'H17$7$7$7$. *H!7_.. 444AAA___yyyAAA *G*?f2 0!">*1VB6]H,Q7,Q7,Q77`J7`J,Q77`J,Q77`J7`JFr`,Q7,Q77`J,Q7,Q77`JFr`,Q7,Q77`J,Q7,Q7Fr`7`J7`J,Q7JJJ\\\zzz7`J,Q77`JFr`7`J,Q7,Q7zz,Q7Fr`,Q7,Q7,Q77`J7`J,Q7Fr`,Q7,Q7,Q7,Q7Fr`7`J,Q7?)?),Q7,Q77`J7`J,Q7,Q7,Q77`J7`J,Q77`J,Q77`J,Q7Fr`7`JFr`,Q7,Q77`J,Q7,Q77`JFr`,Q7,Q77`J,Q7,Q7Fr`7`J7`J,Q77`JFr`,Q77`JFr`7`J;;;)J`UzB`rzz,Q7Fr`7`J,Q7Fr`,Q7,Q7,Q7,Q7Fr`7`J,Q7?)?),Q77`JFr`說,Q7Fr`7`J?)?)?)0?) 0Q 0Q4;;;JJJkkkJJJ$E0 '''"""(3!*M5.T9Kzf;fO;fO/W;;fO/W;;fObbbե;fO/W;;fO/W;;fOKzf/W;;fO/W;/W;;fO/W;/W;/W;Kzf/W;OOObbbՒKzf;fO;fO/W;KzfKzf;fO/W;;fO/W;;fOKzf/W;/W;;fO/W;/W;;fO/W;Kzf/W;C+/W;/W;/W;/W;C+/W;/W;Kzf;fO;fO/W;;fO/W;;fO;fO;fO/W;;fO/W;;fO/W;;fOKzf/W;;fO/W;/W;;fO/W;/W;/W;Kzf/W;/W;/W;;fO;fO/W;Kzf???+Of[Gfz/W;;fO/W;/W;;fO/W;/W;;fO/W;Kzf/W;C+///OOO???C+/;fO;fO/W;C+C+37'K+Sz77???OOOrrrOOO'K'Cr6:::@@@LLLBBB-J>%D.='B+0X<0:_P+O6:eML|h0X< D, D,0X":54$%D.+O6:eM0X<.P=+O6Jxe0X<0X<0X<0X0%D.6]H.U:%D.+O6:eM0X<0X<.P=Do].U:0%D.6]H.U:eU :(4$:_P6]H:eM0X<0:_P+O60X<0:_P+O60X<eU :(0%$>0%D.6]H.U:.P=Do].U:%D.+O6:eM0X<0X<0%D.6]H.U:.P=+O6Jxe0X<0X<0X<0X0:_P+O6:eML|h0X< D, D,0X<eU" -J>%D.='B+0X<0X0%D.='.U:0%D.6]HB+ D,0X<0X<0X<0.P=zYY:eM0X<000 4 D, D,0X<04".:eM0X<0X<40X<0.P=.B+ D, D, D, D,0X0%D.6]H244 D, D,0X<eU(E50%$>04"='2 D, D,04"6]HB+44 D, D, D, D,4 D, D, D, D,L|hL|h\ll\eU2RE0%)4"+O624444`04`04`0`0P 4`044P P P \`@xx\``0\` D,\`@xx\`@xx@xx@xxl@xxl D,ll\` D,\`plPPPtttȨȤddddtPPttttttȸȨȸȨpl444 D,444444444444P P 44P P p@P 4P p@P D,tttplȸdddtttPPPPPPPPPPPPddd4 D, D,`0 p@`0 D,`0 p@h`0 p@`0 p@ p@ p@h`0`0`0Thh p@ D, D, D,0X<0X< D,0X<eU(E50%4$4"='B+4 D, D,0X< D,40X<4 D,44 D, D, D,4 D,44`0P P 4444P T`0T p@`0L|heU(E5#90 4"='20X< D,4 D,0X<4 D,444 D, D,44 D,`0`0444P P D,4P TP T`0`00X<hhT\L|h0XZk&EZ;&4ZE 47 47rrr*L4 47 47BE7hh&EZ&EZ 47******777***777777---;&;&*L4;&*L4-;&4ZEBkZBkZ;&*L4*L4;&;&;&;&;&BkZBkZBkZ;&*L4BkZ*L4*L44ZEBkZrr4ZE4ZE*L4*L4*L4*L44ZE--WWWeeeeee;&eee-;&;&*L4;&;&;&*L4BkZBkZ4ZEAjX=cS6XJ+G<$;3- ;(( + ;&;&-;&-;&)L4--)L4)L4)L4;&;&-;&-;&--;&)L4;&;&)L4)L4;&;&;&777;&rrr4ZE]4ZE)L4]BkZ)L4;&)L4)L44ZE]4ZE4ZE)L4777777777VVVEEE 47&EZ>Zk7]y&EZ&EZBkZ4ZEdddEEEBkZ4ZE&EZ7]ySn&EZ;&4ZEBkZ-4ZEBkZr 47 47BE&EZBE 47)))))))));&;&-;&;&;&;&;&;&;&)L4BkZOnOn)L44ZE4ZE)L4)L4;&;&)L4OnBkZBkZ4ZE;&4ZEBkZ4ZEBkZ)L44ZE)L44ZE)L44ZEBkZ4ZE--;&ddd;&;&;&)L4)L4;&;&;&)L4)L4;&)L44ZE4ZE;&3XD/S@5WI5UH+F<  " 4!9%-:&:&-:&)L4-)L4:&--:&--:&-:&-:&--:&)L4:&:&-:&-)L4:&qqq4YE]4YE)L4OnAjY)L44YE-:&On)L44YE]4YE4YEOnAjY)L4)L4EEEddd&EY>Yj]>Yj&EY>Yj 47 47OnOn4YEdddAjY:&&EY&EY>Yj-AjY-4YEOnOnOq 47:&AE----:&4YE4YE-:&)L4:&)L44YE)L4:&4YEOn)L44YE])L4:&)L4AjYOnOnAjYAjYAjY4YE)L44YE)L44YEAjY)L4qq)L44YE)L4-:&:&-ddd4YE)L4---:&:&:&:&-:&:&:&:&@iXYj>Yj&DY&DY7gg)K3&DY&DYOmAjY)K3AjY:&3YD:&,)K3AjYOm,>Yjqqq)K3q:&qqq777,:&)))))),DDD,777777:&,3YD)K3)K3,)K33YDOmOm3YDOm3YD)K33YD3YDAjY3YD3YD)K33YDOm\Om3YDAjY:&)K3qq)K3AjY)K3)K3)K33YD3YD)K3AjYccc,,:&:&:&ccc,,,)K3,:&,UUUAjYUUU,,:&(J2&E/*I8+F;) #" 4!+ ,,:%)K3:%,)K3,)K3:%:%:%,:%:%)K3:%,)K3,:%,)K3,:%)K3,:%N~m\jAjYcDD:"666DDDN~m,RDDDAjYUUUDDDN~m:%666AjYj\N~m 36%DY=Yj6\wNp=YjU~~\%DY%DYNpU~~NpN~mAjY)K3%DY=Yjŏ3YD,,)K3,,,)K3ppp)K3AjYN~m)K3ppppppp,:%:%:%3YD:%:%:%,DDD:%,:%:%:%:%:%)K3AjYAjY3YD3YD\AjY3YDN~m\3YD\AjYAjY3YD3YD3YD:%:%:%)K3AjY3YD3YD)K33YDAjY)K33YDAjY3YD)K3,,,,,:%:%:%3YD)K3:%,)K3)K33YDUUUDDD,9%6#5VH^^^ #" ' 'H1:%,,)K3:%,,:%,,,,:%,,,)K3,)K3:%)K3)K3,)K3,:%sUU:%)K3:%,3Q=Xi666DDDbbb@iX3XDDDD@iXN}l@iX@iX666[:%DDD 36 366X%DX[=Xi=XiNp%DX%DX[U}}=Xi=XiNp[N}l[@iX)K33XD)K3,)K3,,,)K33XD)K3@iX[N}lpNpNp3XD:%)K3@iX)K3)K3@iX)K3:%:%)K33XD:%:%:%:%,:%:%@iX3XD3XD3XD@iX[3XD@iX@iX3XD@iX3XD:%3XD@iX@iX3XD:%)K33XD@iX)K3pp)K33XD)K3pp)K33XD3XD,:%:%)K33XD3XD:%)K3)K3)K3:%:%:%)K3:%)K3DDDUUUUUUCCC;aQ5VH@@@  ,3!'G1, , , 9%, , 9%, , 9%9%, (J29%, 9%(J2, 9%, , , 9%9%(J2, ,9%,9%(J2fU>fU1UB8$1UByyy8$>fU1UBKyifY}1UBRRRyyy___BBB___yyyyyyyyy+ 8$8$'H18$8$8$'H1>fU>fU1UB>fU>fU>fU>fUKyiY}Kyi>fU>fU'H1'H1'H18$'H18$'H1'H1+ 'H1'H1'H1+ 'H11UB8$1UB>fUY}>fU1UB8$'H11UB1UB>fU1UB1UB1UB1UB1UB>fU>fU1UB'H17#$B--0!' H22#@,%E/7$* 7$* * 7$* 'G17$7$7$* 7$7$7$7$7$nQQ7$7$* nQQ1TA'G1'G17$$'$'$'$'444QQQAAAkkkkkk^^^xxx$AT 14444:Te:Te$AT$AT:Te:Te:Te:Te:Te:TeKk{Kk{:TeXKk{kkkkkkkkkkkkKxhX{e>eTKxh>eTXKxh7$:Te4Xr>eTeX{KxhQQQxxx^^^xxxxxx1TAX{e7$7$7$'G1'G17$'G11TA1TA7$1TA1TA>eTKxhX{X{e>eT1TA7$7$'G1'G17$7$* 'G1'G1'G1'G17$* 7$'G1X{>eT1TA>eT1TA'G1* 7$7$'G11TAKxh1TA'G17$'G1>eTKxh1TA>eT) 3!-% ! T::%D/7#* 7#'G07#7#7#* 7#'G07#7#0T@0T@7#'G0* 'G07#'G07#'G0#' #'PPP@@@jjjjjj#@T#@Tjjj#@T 03 03 03333:Td:Td#@T#@T:Td:Td#@T:Td:TdW}JjzJjz:Tdjjjjjjjjj]]]jjjjjjjjjjjj=dT0T@=dTJwg=dT=dTJjzWz7#3Wq#@T#@T#@TJwgwwwwwwJwgWzd=dTwww* 7#7#7#7#* 7#7#7#7#=dT=dTJwgWzWzJwg0T@'G0'G0'G07#'G07#'G07#7#'G07#'G07#'G0'G07#'G00T@=dT=dT7#'G07#7#* 'G0'G00T@0T@'G0'G00T@=dT0T@0T@=dT7#/R@' ,  !)aGG5"0S@6#) 6#6#6#6#&F06#0S@6#lPP6#PPP0S@&F0&F06##&#&#&&&&&&&iiiiiiPPP 03#@S 03#@S#@S333 03333 039Sc9Sc#@S#@S9Sc9Sc 03#@S9Sc#@S9Sc9Sc9Sc9Sc#@Siii\\\vvviiiiiiiiiiiiPPPvvv0S@VyIvfVyVy0S@#@SIvf&F0 03Ivfvvv0S@iii) 6#) 0S@=cS) ) 6#&F0&F00S@=cS0S@&F06#&F06#lPP6#0S@&F06#&F0lPP6#&F06#) ) 6#6#6#) ) ) ) 6#&F0&F06#) ) 6#&F00S@0S@6#=cS0S@0S@) 6#) & !   )$ ' 6#&E/&E/6#6#/R?&E//R?&E/6#6#&E/&E/&E/#& #&&&&&&&&&&&&&&&&222&&&&&&hhhhhhOOO /2#?R /2 /2222#?R222222#?R#?R /2#?R9RbIhx#?R /2#?R#?R#?R#?R#?RuuuhhhhhhhhhhhhOOO???222&&&/R?Iue*-O<5"%E/) %E/5"%E/5"%E/jNN/Q> "%%%%%%%%%%%%%%%%%%%%%%222%%%%%%222222222222ggggggHsd%%%%%%222 /2 /2222">Q">Q /2">Q">Q">Q">Q /2 /2222">Q8QaggggggggggggNNN>>>[[[>>>;aQ222NNNsssHsdTwHsd">Q;aQŃ[[[%E/>>>>>>NNN;aQNssNss%E//Q>%E/ggg/Q>Hsdsss;aQaHsd;aQHsd/Q>;aQ;aQ/Q>sssgggsssggg) ) 5"5"5"%E/) 5") ) ) ) ) 5"5") 5"5"5"%E/5"5") /Q>%E/%E/5"%E//Q>5"5") 4"1 +# ( /fKK.P>%D.%D.5"%D.%D."%"%%%%%%%%%%%%%%%%%%%111%%%111>>>111>>>>>>111111>>>MMM>>>MMMMMMMMMZZZffffffMMM"% .1 .1111">P .1">P111111">P .1">P">P .1111">PffffffMMM>>>111111MMMrrrZZZ>>>111;`PGrcrrr .1ZZZ%D.MMM111>>>MMMMMM.P>;`PMrr`;`P>>>5"%D..P>.P>fff;`PrrrGrcSurrrGrc;`P5"( %D.( ( ( ( ( ( 5"5"%D.5"%D.( 5".P>;`P;`P5"%D.%D.5"5"5"5"5";`P;`P( ( ( 4!*J9&B2  ...4#+++& 4!( !%%%%%%%%%%%%%%%%111%%%111111111======111LLL===LLLLLLLLLXXXLLLXXXLLLLLLXXXLLLddddddLLL!% .1 .1 .17O^!=O!=O111 .11117O^7O^!=OLLL===111LLL===LLLqqqXXX===111%%%LLLqqqXXX%C.LLL111===LLL===111LLLXXXLqq:^OLqqLLLLLLLLL===4!%C.%C..O=ddd:^OFqaqqqgLL4!4!( 4!4!4!( 4!4!4!4!4!4!4!%C.:^OFqaFqa%C..O=.O=%C.%C.4!4!%C.Fqa:^O:^O4!( -N*7% $$$,H<3TF#@,$B- $$$$$$$$$$$$$$$$$$$$$$$$000000000000<<<000<<*0hhh- 0---">*6XI">*">*GGGGGGGGGRRRGGGRRRGGGRRR888---------"""---"""""""""""" """ ---88800""">*00*I80% ">*]]]]]]GGG""*----"------*-*-8I*-"www0""""""888www www"""---hhh888888]]]]]]]]]]]]]]]hhh;%"Ln|;%"RRRwwwhhhwww6XIwwwGGG0">**I8*I8]]]000*I8">*000% % % 00">**I8*I8*I86XI6XIL|k6XI*I8*I8L|kAhZ*I8*I86XI6XI6XI6XIR88$ ,'1% ***555HHHYYYgggggg!=*uuu\\\QQQ888!=*888QQQ/!=*!=*,,,,,,,,,!!!,,,!!!,,,!!!!!!!!! !!! ,,,!!!//!=**H8!=*/!=*$ !=*!=*$ /!=*$ !=*ggggggEEE*,EEEwolwoluuuEEEEEE8H*,QQQ\\\2HV*H8!=*/uuu uuu!!!uuu,,,uuu888QQQ,,,,,,\\\\\\\\\\\\\\\\\\uuug^EEQQQ\\\888EEEQQQ/!=**H8!=*\\\//!=*/!=*!=*/!=*/!=*!=*!=*$ $ $ //!=*!=*5VH/*H8*H85VHKzj5VHKzj5VHV}@gY*H8$ )G7! &***111BBBOOOZZZDDDDDDOOODDDOOODDDOOO!<), !<)!<)!<)!<)!!!!!!!!!!!! !!!!!! .,,,DDD777!.777.!.# ..!<)!<)]DD)G7.!<)!<)....# ZZZeeessseeeeeeOOO!umjumjeee~~~~~~OOOeeeDDDOOOJWJWJW7G.OOOOOO!!!~~~,,,sss777eee,,,DDD!!!!!!ZZZZZZZZZZZZZZZOOOssseeeZZZsssOOODDD777DDD# .# 4UG!<)ZZZ.!<)),.!<)4UG!<))G7# ..)G7.# # .!<))G7)G7)G7!<)4UG4UG)G74UG4UG4UGJxh?eW?eW.# ;(gSS& !!!&&&444666+++666666CCCNNNCCCNNNccccccCCC.CCC3SF ;( ;(.   ++++++   .. ;((F6 ;(. ;(# ;( ;(# . ;(. ;(.# 666CCCCCCNNNcccqqq&3>@+FYYYYYY CccccccNNNqqqYYY0FSHVKcVq ;((F6YYYCCC+++NNN666ccc+++CCC +++ CCCYYYYYYcccNNNqqqCCC.V @iYYY{{{{{{.qqqcccYYYNNN# . ;(.# NNNNNNNNNYYY. ;(0(# ;(3SF(F6 ;((F63SF# .. ;(... ;(3SF3SF(F63SF3SF3SF3SF>cVHvf>cV3SF3SF ;(# .-6%    &&&UUUMMMBBBBBB555555555BBB555BBBMMM555555***-***(E5555***- ***555 -555- -" -- :( :(ZBB(E5- :( :(---" 555BBBBBBMMMWWWWWWbbbooo%2":5E B5E 2":*Ebbboooooo :(@UHUJb(E5-WWWMMM555555***MMM 555 BBBWWWWWWWWWWWWWWWMMMWWWBBB @-U @gWWWbbbzzz8" ooo" - :((E52RE(E5MMMbbbWWWMMMbbb :( :( :(-2RE(E5(E52RE :(2RE--- :( :(- :((E5(E5-(E5(E52RE=bUHueHueRw2RE(E5" " -'D46$YHH   % ???VVV```LLLAAA444******444444***444***444AAALLL******'D49'9',,'D4,9'" 9''D4,,9',9'" ," 444AAALLLVVVLLLVVVmmmVVV```mmm11*D*NN4D4D4D">4D/DQ,SxxxLLLYAAxxx,,9''D49''D41QD``````mmm```mmm,,,9''D41QD'D4<`S1QD9'" ,,,," ,,,,1QD1QD<`SFscFsc<`S'D49'" ,YAA,9&$>0/ -# ( @@@TTT___JJJ@@@333333333@@@333)))@@@TTT@@@JJJ&B3@@@@@@1OB8&8&+! +8&! +8&+8&! ! ! 333@@@@@@JJJJJJTTT___TTTTTTTTTTTT___kkk&)&);=)MM @;=3B&B3$.BO;TaMfvMfvMfvMfvTTTER}ER}8RfTTTJJJ))) @@@TTTTTTTTT333+)MM+TTTTTTTTTTTTTTT+)MM+TTT kkkTTTkkk___+8&&B31OB&B38&1OBkkkvvvvvvvvvvvv+8&8&8&1OB1OB;_R&B38&8&+! +! 333++! ! +8&8&&B31OB&B38&8&+! +8&J33+4#6* 4,+++ (((???]]]]]]III???222222(((((( (((222???]]]SSS++&A2+0NA7&+! +7&+! 222??????IIIIIIIIISSSSSSSSSSSSSSSSSSIII]]]iii&( 022A(KK??? ?(A:<(A-AN:S_KdsKdsKds:S_Kds]v]vKds]v]vSSSDP{DP{DP{SSS((( ???SSSSSSSSSiiiSSSIII5!Dbn5!SSS]]]SSSSSSIII}}}iiisss5!Dbn5!III}}}iii}}}iii]]]sss}}}iii}}}5!Dbn0NA:]P0NA?]]?]]sssIII&A2+7&+7&7&222???III]]]III&A2! ! +! 222++<F(<! ++<<7&++7&+! ! ! 7%(-+!$111777,,, '''111111''' ''''''>>>'''>>>GGG[[[ggg**6%6%/L@%@16%*111>>>GGGGGGGGGGGGQQQQQQQQQGGGQQQQQQQQQQQQ[[[ggg/ /1 > > >1@ /1 /1"J 9Q^JcqJcqJcqJcqJcq9Q^Jcq[tJcq[t[tlJcq[tQQQBOyBOyBOyQQQ>>>QQQQQQQQQgggQQQQQQQQQGGGT>>'JJ111QQQQQQQQQGGG>>>{{{QQQ[[[{{{[tT>>GGG{{{qqq{{{{{{{{{ggg{{{qqq{{{{{{[t%@1/L@>[[L~o/L@%@1%@1/L@6%%@16%6%6%111>>>GGGQQQqqq[[[  ** *E'; Q4E'; E'**;*6% ***  2",$<<<0%GGG;;;''' ''' '''5$000<<4$4$($&-/> ;NNNEEENNNNNNNNNNNNNNNNNNNNNNNNXXXccc!-$9 - - -$& -$& 26NZ G_mG_mG_m6NZG_m6NZ6NZ+>I6NZG_mQktXo~G_mXo~G_m -//>@LtBX~NNNNNN///(&GG(NNNNNNNNNNNNEEENNNNNNNNNNNNEEE;;;&&& 2 2;;;XXXvvvvvvvvvEEEvvvmmmvvvNNNmmm&GG(NNNvvvmmm(L 9\NNNvvvvvv-I>$>/6XL@hZ@hZ-I>4$(4$4$((4$///;;;NNN (((    ((B&9((9B&9(B&B&((  (4#!9,2&"" %%%......:::%%% '' %%%%%%'3#3#'!,58%<#8.>>888--- $$$AAAJJJRRR1!AAA1!888$$$1!8888881!1!** $:$CC-:-:-: 5-: 8AAAJJJ^^^JJJRRR^^^ 8 *!51AG^}5GrG^} 5W&G Cf5Gr Cf1A*CYf(:E3JULdmLdm3JU(:E$$$A--L883*&L88(!L88(:E3JU35!51GY$ J/ J/ J/R:>$&5 J/ J/>$>$R: J/5>$ J/ J/ J/  &0!5)(& !!!111555??????777 ,,,HHH???,,,7770!###7770!0!777!#!#24#AA 7,9 #9!9,24,9HHHHHHQQQ\\\)) 70 700? Ad4Fo4Fo 4U%F %F Ad4FoF\z AdAWdAWdAWdJbkQft'9D###?,,J77?,,J772)%J77'!J77 7,9,9;Fk=QtHHH???HHH\\\HHH???HHH???HHHHHH???777### .;0;d;Fk;'QF0;d'Q;'Q # . .777dddmmmmmmdddvvv~~~mmm\\\;U`.???mmm)D9!9,)D92QF;`S!9,###,,,777,,,###0!,,,  %%4 H. H. H.Q9 H.=#=# H.=#4=# H.=#=#=# H.Q9Q9 H. H.Q9 H.   / "'   )))777444>>>555>>>>>>"""++++++/ )B7 7+/ / /  " )++7"@@555)>>>>>>) 3555+7OOOZZZ))13+++ 3+7/3DmDZw 3S$D  $D @b3Dm @b@Ub1FQ@Ub@Ub1FQ"""I55>++>++I55>++I551)$I55&  "FFFDZw>>FFFFFFFFF>>>555""" -::&OD/:b:Di -&OD/:b&O:&O " -ZZZ555OOO  bbbkkkkkkbbbkkkI55>>>kkk1OD)B7/ )B7)B7"""++++++>>>555+++    3$<"<"<"<" F-<"O7<"<" F-<"<" F-<"O7 F-<" F- F- F-O7ZD<"   ."&  ...:::444===MMMMMM===.4446*6*..( (* 4 4 4(===```hhhhhh```===(!((6* 4.02**6*62Q#C0202#C ?`2CjG^f0EO?S`&6A!!!G44=**G44=**=**=**=**G440(#```qqq8Cf8Cf.CS======444===444======444444!!!,8&M.8`8Cf,&MC.8`(0X,&MC.8`&M8&M===XXX      XXXMMMEEEhhh(A66*(A66*6*.!!!444EEE*** # ##2:!2:! E,M6M6 E,:!:!:! E,:!:!:!:! E, E,M6 E,M6 E,:!6*###!$%%%'''333)))333;;;;;;333)))-- ')- ')';;;^^^fff^^^XRPnnnfffnnn;;;-vvvnnn''- !5E33 3 '))5!== ')/1!==/11P =^=R^%5?/CM!!!C;7;))E33;))E33;));))E33;))ffffff7Ad7Ad7Ad))))))))))))))))))))))))!!!+7-7^7Ad+%K-7^7Ad7%KA-7^'/V7%KA-7^ #;;;VVV##--5) fff;;;fffE33'?5-5)-'?5!!!)))KKK333# ##19!1#19!K519!19!9!9!K5111 C+ C+ C+K59!9!####,  $$$ (((((( &>4(((,&0&&&:::\\\lllddd\\\ &(& &F 2VPNdddddd\\\::: 2tttlll &4(,(4 &( <<4(.0 << <<.0"@44( dddddd&>4&>4,.J@,, (((222BBB222" "0"0"0"08 0""08 8 08 B*8 B*J48 ""D22,",3( 8))  +++&&&,,,&&&'''+111''''''% %''3/+%+ZZZjjjZZZbbbZZZ 3'3%E% 1TNLjjjbbb 1rrrjjj %'+ 13';;-/-/;;;;-/-AKPAA9''A959''A959''C119''C11ZZZ'''ZZZTNL+?N5?`7Ih))?5))555#I+5Z5?`5#I?+5Z%-R5#I+5Z#I)#I?+5Z999  !!!999  +%=3 IIIbbb++%=3%=3-I?'111AAA'''+  7/! !!!!/!/! !/7! A)7I37!!+!!+!+# ***777???6662& $&&2*??? ,.777`````````XXX 2!7$C RMKA00 & $&.oooggg $&*9999 ,. ,.999999"2;N??,$!"N??7&&?747&&?747&&A00 $& 0```&&&.RMK&&&4C4=^=Pk7A(; ( ( 4 ( ( 4 4 4 4"G*4X4=^ 4"G=*4X$,P ("G*4X"G 4"GPPP*4X     !!2&*! 000*!!* $;2.&&&GGG000*&&&   !6!  !!..!..6!.6 G2 G2.*** !!**  ///111---)   /#-  +- #%VVV]]]eeeVVV# 6#A 6##A %))%1## llllll 8888 +-8888/EE?//+# "M>>+# "M>>6%%>626%%>62 / #%VVVPKI%%%6?':2<[2<[':6?': ' ' 2"E 2< 2 2 2"E)2V"E '"E<)2V2<[< '"ENNN   )+E<#:1#:11%1%  +E<2RG+E< ))  )4%%%///>>>666%%%666%%%        -  - -4- -44)) )) ) )&"   ((("# -( -( &# -77TTT$$$TTTNIG$/#@55#@#@ -( #$# 555TTT[[[[[[jjjbbb 7777 *,-CC77-CC77>--*#!K<<*#!K<<5$$<51#8/(  #$TTTNIG$$$5>&81@3C`5>&85>&8 & & - 1 1 & 1 1 1!C(1T!C 1!C:(1T#*L:555 (/$/$#8/#8//$/$(#8/*C:#8//$#8/($$$$$------<<<  ---555  ,,3 <&,3 <& <&((((/$(       (*###*#.''!! (* !#XXX####>>LLLGCAZZZSSSLLL 2L?Zi?Zi*>>22-AI !+!-AI !+!22* !  9** %&>5+! 4++! 4+09!+ !!9A!+ !-:-5Q09#409+!%+!%%%% # # - - # - - - ->> %-I? 4++! 4++!%  %+!&>5+!% % 4++! 4+%  (        /(  (//7#/ >+ >+/ >+7#7#/ >+/7# %% %  8)) #    * $ **  *   EA? %D/9/9/ / 9<<<DDDWWW <<&">+4777>>>>>>DDD+++?;:>>>PPP>>>>>>++++++&44+++?;:JJJJJJPPPJJJJJJJJJPPPJJJ&.&VVVVVV%  &.& && 777>>>"7/"7/ .&#&&&+++777 DDD                              &    &.&&     ###)#))) 7&   ##  ))1 7&111)#               $   1$$    $&++&3&!=&!=NNN===***BBB===>:8============555****3&33***>:8NNNHHHHHHHHHNNNHHH'?7-&&&TTTNNN       -&===-&$55!5.-& #&&&-'3&555 HHH&-&-&&&    1$$ &            -&!5.!5.&&     !5.-&& (       # # (( #    #00(0#& #      1$$ &      $   **$$*;;;1$ ;;;;;;;;;;...@@@(((;;;;;;KKK@@@((((1(1$11(((<86FFFFFFKKKFFF#44 4-+$+$ 4-$QQQKKK +$ 4-+$ 4-$+$$ $$+-8-;N$;;;$;;;+$$$+$$$$     $  $  4-$&=5 +$ 4-+$+$. ' " "'"'  "'' 4$. 4$.'$+*@ 6J=X 6J(/(/      *    #    999999999/'''>>>'''999'''---999999>>>222'''/ ' '/ '/#/ /''':65IIICCC2+*#$;32+##*#*#NNN  #2+7--*#*###*## # +E$/##*#999*##*# #'. 5G 5G 5G 5G'. ##2+2+#2+###*####2+$;3#*#      &      -&--- 2#& 5G 5G 5G(>'.(> 5G 5G 5G 5G 5G 4F 1B %#/!            777777FFF&&&843+++FFF&&&&&&777&&&777000. & . & & & &.". .&&&8435++0*("#91"("0*"("  #91("("0*0*0*"(""("" ("AAA"0*0* (&, 3E 3E((& $ #9&,    ("("""#91"0*#91"#91("("""         $   $ $+ 0"+&,'<&,"' & ' ' & & ' & )# /       + +   555555555732555:::%%%%%%555//////, % , % , % %, %,!, ,!/)/)'!/)'!'! //"80 '! /)'!/)'! ! '!'!/) '%+&: 2C% $ & % $ )& % %   '!!"80'!!!/)!!  !/)'!'!      $        * /!*$)$ GB7% & . )$ & )% '# !                      (((333333333333###(((######333###+ # + # + # + # #+ #+  +& !6.& &  -'2((-'--   -'&  (((BBB333  & -'%8% & " # % % # # " % " "       & & &   !6.-'  & & &       "   - (""   - - " - ""(% " # <5(# " % # " " % % '$ $                """''''''3/.666"""'''"""111,,,1 " ) " ) " ) " ) " " " ") $,&$$$    $$,& 4-$$ 4-,&$ &" " " ! # " ! ! ! " # $       $ 4-$ 4-$$<5     ,'!''',!  ''!!,'  ''*# ! $ ! ! # " $ &$ " #  5/$                !!!!!!!!!%%%%%%!!!!!!/  / ! ( ! ( ! ( ! ( ! !( !##*$2+###2+*$!,2##:32+*$*$2+#:3# ! !  # ! ! $$  !  "  ! !       #####2+*$    %%%*%  %  %   %*%% /$ #  " "  # ! # $  $  #                          #    .  .   &   &  &  &    )#)#5//)#))")#  %+""")#"   "  ...# !         " !  " ( # !       ")#0*0*"81"    $)$$)$$$$)! # !   # " #   !                 $ $    "    '%  ,  ,  %  % % %!!'"'"!   !!'" .(   !.( .("  "      ! ! !        !!'".(.('"       #''####'#'#! "  "  ! "    !  0-%     #           $$  &$  +  +  $  $ $&!1,,&!*""  &!    &!-' &!    &! -'    !   !                              &  &   """&&                                          )  )  "  "$$  !&+!+%2,$ -  $2,+%#               $4                         $$ )        63*                              #!  (  (  !#)$#    *. %#)$0*                     (5.!                    # (#51(  51(  .(                                    !  &  &  !!!%! !              333CCCRRRYYY]]]___aaadddedddddfeebbb_^^[[[VVVPPPGGG888$$#         ,,                     !!!                                            $   &!        """AAAUUU```eddhhggffeddbaa`___^]^]\^]\]\[][[][[^\[]\\_^^a__baaeddgffjjikkjiiiaaaTSS???%%%       **                                                                                      444QQQdddjjjgggcba_^]\[[[ZYZYXYXWYWWYWVYVVXUUYVUYVUYWVYVUYWVYWVZXWZXW\YY\ZY^\[^\[`^]b``edciggllkoooiihTSS777     #/                                           %      %                #               ===^^^jjjkkkfeea`_]\[\ZZZYXYWVXVUXVTWTSWUSWSRVSRWSQWSQWSRWSQXSRXSRXTRXTSYUSZUT[VU\XV]YX^[Y^[Z_\[a^]b`_db`dcbhffnmlsrrpoo\[[:::   *                        -*" -*"      "((##(#(( !/(#  (((((  ##((#(( !/(( !/(  (((#    #  ###QQQmmlmllfeea```^]]\[\ZY[YWZVUYVTXTSXTRVRQVQPVQPVQOVQOVQOVQOVQNWQOXROXRPXQOYSQYSQZTRZTS\VT]XV^YW_ZX`[Ya][b^\d_^ea`gcbgedigfliiponvuuppoRQQ"""   *                         *' *'     "% -&&&!  !&  &    - !&&&&    !! !!!&&!!    !&& 444```qqplkkedcba``^^_\\]ZY]YX[WVZVUYUSXSQXRPWROXROWPNWPNVPMWOMWPMWOMWPMWOMWPMWPNWPNWQOXROYSQZSQ[US\VT\VT_YW_ZXa[Yb][e_]e`_gb`hdbjfekgfkhgliinlluttwvvccc433                     &   - !&&&&                                           ===jjitsslkkfedecbda`a^]`]\_[Y^YW\WV\WT[USZTQZSPYROYQNXPMXPLYOLXOKXOKYOKYOKWNKWNKXOLWOLXPMXPMYQNZROZSP\TQ]UR^WT_XUaYWaZXc\Ye^\f`^ga_hbaiecjedlgfligmiimkjnlksqqyxxihh222                     %%%%%%%%%%%%%,%  "                  &#&# &#     &# &#   &#&#        &#  555mllwwwnmmihghedfcbda_c_^c_]b][b[YbZX`YV`WU`WT^UQ]TP\RO[QM[PKZOKZNJZMI[NI[OJYNJXNIXNIXMJYNJYNKZPLZPL[QM\RN]SO^TP_VR`VSbXUbYVd[Xe]Yf_\g`]ia_jc`keclgelgemignjhnkjolkomlsqpzyxffe...                          $$$$         $$*!       $!   $!  $!            $!           222IJKBBB<<<:99999367567865865965:88:99?<:B=;E?=IB?LC@RGBVJEZMH]NI_OI`OIaOI`OH_NH\MHYLHZLHZLH[MH[MI\NJ\NJ]OK^PL_QM_RN`SOaUPbVRdXTeZVf[Xh]Yh^[i`]jb_kdalecmfdngfnigojiokiokjolkommusr{zy^^]                                                                   "    #""00/@??6<>/6:BBBEDDEDCFIJ8BG;BFBBA>>>;::9AE2<"-4%$$ !!#&)*2!+1(%%/*)70.?73H:5Q@:TD41I<7QA;XD=_H@aKCbLDaLE`LE`NG`NGaPIcQJdRLeTNfVPgWRhZSi[Vk^Xk_[ma]nb^odapfcpgdphfpjhpkipkjrnmfbaCAAgee~jih                                                                          222POO^__[_aCEG877233)))<<;[^`kv|~trq_gl6N[!=L *))3,*>1,L<7VB<^G@bJCcLDcMFbNGcOHdQIeRKfTNgVOhWRjYTk\Wl]Xm_Zob\pc_qeaqfcqheqigpjhuon@=<SQQ}{zyxw>==                                                               /..^^_\cf>??===KSX&2 ).0"7B )033? 1<%8(7$; (!8(? (((IHHsx|}}}VVV+*) )- 1D'; &*%%=2.L<6XB:`H@eLDeMFdNFePHePJgSLhVOjWQkZTk[Vm^Yn`Zob^pd_pebqgdsjgleb'%$ECC{yx}{{ZYY                                                               '&&gijOPPkllXfn('&CFG7KU976::;:GM %3 "! !"(:B&6  !+00B-(0+? 6&9)B+'*C :R$-2MLKzzzfv:LU %##2)'A3-S?9`H?gLCgNEfNGfPHhQKhVNiWQlYTm[Vm^Xoa\nb^pd_vkgXOM 865xuu}|{pon                                                         CCChhhy'***`fh 7D)-0\[ZT^d*8!:87=AD3HQ !*(&%)))38:-BM&3$9C*>1@%= (?-G)A.H 6#(Igwy___"!!/D&:& $ :0,N<6^F>fLCiOFiQIgSJiTNkWPlZSm\Wo^Zpa\pc^710-++xut|zzzzy...                                          433]cf+02dfg;MW*16~~}]ks(1^\\jjjotx\chkjjnnnsssortllmnnnnnnuuusuvtttvvvwvvyxxyzztx|kll___PONORS:P[?P ''B4 &4,F3O .'C*G$;JJJį|Idsqqprrsmllsz}R_e777,**7=?406.,qmm{yyJJI                                               ^bc%+uvwxz}uutov{'.68: 07 ***%%%  *BCb/=-,+ZZZ]ac+++.C.K6T)1H2O5S1 PPPÿQlz"qom}zyHGF                                            145CEF^be]``inp%)+:;;8DJ >>=888,*)))("! %$#)'',*).+*/+*/+),)(+(('%%"  !&RiOq`cd.N_7P.K 6S3O7V@UYy999 pll||DCC                                EIKXYZVWXX[]$*MMM@??<<;444***LKKba`qon{xw|{||{yvt{qnwomqptpmnhgl__eYY\VUYVTXMOYDHT9?@ ':4R6S-G 0O+I6S4@ifeӮhgg(ES6R,D pll~}877                                `ab17; GHHCCC@@@999(((QQRĸ|ztpztvwy~rqvlkrbcg^^f^ancfp`esY^mLP\LNYMOWNJGJDF=?M7:G306(#!  ?X7avn˽IHG$(4M-K4S#36T5S0M888Dev "-tqp~~'''                              :;;012145+/1567EEE222  ,,,ô|xtpzmhwrswzst{fhs]^cYZcPUeKPcINbEJ[?CT>BU;>O96=64<35A88I87B64610.(** &% ! )Cb.ISSSŝ^r}#Mb1M5R9W21@lʨXXXvrq|zz                      ---ORS455GFF444 |ywsqmyidqmmekqWX]GGO658+,4#'4!&7 ';")?!*B#,E%)A%(=!-"&4$)?$(2%/'9&+9-1;*4F+5M+4G+1 # ^yǟOOO 7U5R8V %@,K:VJdqһnnn%,Ayvtmll                =>>.01566>== ~zvvieaSNI;6=:<.-2!*$& 3!7&=(B!*D$+B##3 ' !"('/)2#)4-2959>68B-3B*/0&.'&37,='6#/  4SAc WrYdkǎCDD 2F1P2R*E 7U4R8W$$$}'Oc =}}}    455DCCf^\:1.#  (+ 8#8 2%& #!!$' (!")#*+/!,7%+:$.G"/L#,?"-? -:,4<'0>#.B#27#0>2@06A<@JO#]PB2&&! '() &?CfNkYsvvu$"!2R3Q;Y 3O/N/M0;VSR111QON]^_   ,/0=>>>>>TTTtom@97#        !!* (" '$ )).!(#)"#,0 ,>'2J%3G/8#00&61&45%0<"2:.;3<'66-=7@6&K.'OVW P?0),)(,./)9I_(((ЗEcr=X+E 8W3P>Wcdd222;<=???BBB UPP(!   !  $!%'+')'"$ !"" $#  #& '( *)#* %+")!!/* -3".<(4O!2G1>0C"2F+3=-66(71)8/.=+3>,,85'?_:BeB()N U X[TC3 ."333,-- ekpϬ[ho&>7U5S 3F xz|~ 99:@@@KKKnnn{yy?;: & @64RNMSQQGHBCF@@D;@C9>@79;237)/4&*0"&- *&'""#%((%-#-" ,!*+#/%.("//,7G%3H 3H 2I1F!2K&5K+=@69<259.05*-3$'.!)(%$%##%(+*$*$- **-$.'2'#2.%43.96+8=(6C%5G/H3K1?SX!8L?HTe=&Y\ ` d e! d f! j! h _I5 4($455HdKp/H788ige1?2R/N=V>?A>>>QQQGGG~~~zxx/,+ E73l[V|hb}i`tnj__^VUNNQHGLCBH@_>Q;JJBW^+h i!j!i"k# k" k# k$ j# j" i" k!l" l# k" j# h!cJ &4;hnp !!123===YYYBBBkjiCBA930xnk{vqmzjdvb]sb^jee[ZUOSJJNFEJ@?F::C77>269-27'44$.. &'$!!#%$(&*()#))/)0#.'0,3! 0!1 .! /!$7-KH,mHS4.W0,c/c-h2/g*dhm" o# n" m" p$p$p%o$p& q' o% n# m# n$ m# l" j!i iG!Fh/[rѴ///223efg===<<>C98?44:.17)-4$$-%*0-*&"! $&))#%"'(*+'.,.0*/*1,368!G="=?$>8fB }@b& ^ hlimn!m n!o!p! p" q" r# r#r#s$s%u' t& s&s%r%r&r%s& r& q%p$o$o$p&f"EEF689999NNNQQQ555spozy{trzrn{mjzjewc^ub]fa\aa\RVMJNHCI@@F9=A4:=/89,04()/",,-, #!$$!$'%&+,-+.2%147"eBG-s#kh j lm m"p" r" r" r# s% q# r# s#t$t$u% u&w( w( v' u' t& s% t& u( s%r%r% q% q%r&b   245877FFFVVV...$##ljj}zxysqyqo{olykgwgat`Znfa\^XWXQORIGLCEI=>D6>A18<.67*/0$/-.,!)""&&$$&*,,/025 5 !4.3"a* ,l klj j! l!m" n" r# t# u$ v$ w% w$ w$ v% v% w& v& w' x) w( w' v& v& u& u& v( u' u' s% r$ q$ s% U 000999<<>>111QQQ555IHH}{zxtrxrpxpnynjwjfwfatd`sps[^WTYNOSIIMCCI?=C9;?24;..6'+1#+, #*(%$&' )!+,"+./&1 %4*'315=K9A\CH_`EAg*dh l o!q q s! s t! u" t$ u% z& {' z' {( }) ~)~(~(~(* * * * ~* }) ~* ~* }* }) {) v(v( w) l"  ;<=)))CCCHHHtsryvuvqpwpoxolxmhuhdud_rb\qf`Z\UPTMKQGGM@@I=9A66=/08*-5')1"(++)&%&' *))%+.3)%.3/:JDFZJIrZGbg8.g!fj o!s"u$w$ y% {% '' ' ' ( ( & ~' {' v& v% s# p"m!j gea]\ZYXURPN] T **+---222MMMPPO}{{urqupnvomwnjwkgugbub]q_YicaVXPMPKIOFDK@HX24[-*_-'i(j!h l!o!o!k hbZQH? 8 2)! * !   00/"""CCC000uutvutvrqvpowomxmjwjfwfbtaYp\WgbbSUNILHEIBAH>D:9@529/#*  $ /x*x*w(x&x& v& o' m$ h _ PQ914(/+(,-1,.5,+0)',!$ '''zyyxvuvrqwqovolwliwieve`u`Zs[ToVMmPFgG>TH@@D=:>66;2+0* >.y+y*u(s's's&q% l$ l% a&iH>FT;8UF:RR0FJ)B>)>:,840959=;?0-0 444wuswrpwqovplxliwidvd_u_YrZRnSLmMEjF=SH>>C:7;5381*0(R /w+v*u)t*q)m) d" [,2kHccMZCOX.HF0GB/DI.DP-FO)DF+AE+?;9.2&.%/64>>@FCD??A+,. UTU}}wutwrqwpnxnkxkhwhcwd]s^WrYPnQInKCeF=OJ==C7>@488-)7+51!Z*7r*s*s*q)k(h&X SDkQiIdCc8S~,Hn)@a)=b!9S%>G#@S&>X+AS'=K42.+*/*/.9"%  mll|{zwtsxrpxpnxnkxkhxgbwc]t^UoVNfVJbMCXJ?QG8K?2AB28?,-@*67#3," U*"A5s9&u)t,r+k(e%Y,,i`F>3l,[)M$D!@#B|$K J$E!=u";i"8U4M'=Z+DUAW[EUaAMRGNNKVZOW]GNR/24yxxzxxxtsysqyqoynjylgyfawb[t[ThYP_ZL]REYH=]<1Y6+J;*B7%?3>1EE9 > @1}>.z*w,s+l*e&\d}dS>23+g$S+U+W)b#_#aRHLJ(U%OuLjXTG<:-1//v*w)y$v$m$l!m+p)h0jQT}^w^p{dwgu}bnp\dbW]]^bcNNN222ywvyutzsqzqnymjyiexe_sb[fbYiVMgLFcF>`@6]:/[4'X.!V'R"ROKIRO> # L"x01/r*i*^#J7>ݐ|^FQJI@4@=88,*,{,y0FR`biiqwxt{xkpnOQPFGGQQQDDD@@@<<<---***ywv{utzsqzqnymizjdwd_mf]edYkSKeLDcF<_@5^9-\2&Z-V&S Q OPNQSRK4 Fj)u-p*V `]gZb|mQ^UI@>=/+z=TZadjkoty~;::{xw{vt{sq{qnzmizjeve^mh\aaYkSJgKCeD;_>4]7,[1$Z+V&SR PQKSN$ L% _]E(*HO15s_|xzxwp]TTQQ@5{L_ifgmosv|///OON{ww{vt|tq{qm{mj{idtibdg`_aZhUKlJAgD;a=4_6+\0$Z+T&M$<*.08)K$ X]_^fgS;  AAAWqrs[ZyۀnnvwtokebeUGDOeoms~t|;<<^]]|yw{vt}ur|rn|njvjflkdci^bdXlTJnJ@jC8g=2\=/X9)_*Y'M':15/E!W^]`ccfjaJ2AAAȝccc''' $:E:mNQCO[\Zgnsuh]WRNMLPiu~}uz~EEFddc|xw|vu}ur}rnyokmnijmckgZq[PqQHnJ?lC9i>2b>.^6$U2U,X"V XVW[^`begjopZF ( [[[HHH!*AoC?EINIMTfm]GDLPPMtaz~{z}~IJKfff|yx}wv}tr{soqtpnpjtg^v^TuXNrRGnJ?lD8k=1e7*PA-G;$W)\! Z YTU\``bfjloqt"mT B( ???ۤaaa'''*Mb9}:JHE?UswYAJPPU`u~}~LMNiii}yy~xv}trzuqosompkte^w]UuXOqRFnJ?mC8j>1RC3P?+\-]%^!ZYWW`b`bfkmptw"{$ |#iR&?-" VVV䷷ooo---+BS2dBMVh}׀wQGPQWchsPQR lkk~{zyx}wtvvsqrnmpknjbw^VuXOrRFoJ?gG:\K8[A0d1"c+a)^ [XW[]^achmpsv x!|#$) z%b R2#7+#444Ł888%2@2hFe|}}[GMX]aboz~STV qpp|z~{yyzxxxsxrlnojindrbZuXOlTKdPEYQA`D4c7*_5'c.b(^ ZWY\^aehknpss!t!x"& }) -/{' ^+T<0+$nnn~~~&&&(5C8see[[Sx]_ggiryyNPQ qpp}|~|{|zvtp~okuninlbsbYuXOkULhODlF9m<0a:-]6(d-a&_ \[^_adhklkotu t! t" y% ~),/56t,^8)RA9mmm䷷^^^ #! 9QY^[I]\_djnhntt~y}HIKgff}}}}|~zwuqpk}ke{f^y_WvYOtSGtJ?iI=_I9g8*h5 d,a&`! ]Z_]\bgijkqvv u!w# }$ ( ,049? <p3aD8LB< nnnAAA*))9U^A{Vai{o}fxwmrtz~BDD]]]~}}{xvsqm}lf|f`{`XwYPwSHsK@[PHUSDi;,h4"e-c(`"[\]]]cgikoru v y"{$ % ( ,/37=F'K+>$m<,cQIA<8 GGG"""$145?[hbmmek}pwuy~?@AWWV~|ywssnlh~g`{`XxYPvSIqMAUVN[QHh:+f4$g.b(`"\ ]]^_egjnoos!w!z"|$& ) ,/28>D$K,T4S4B*jI1i5'i0h,e'a! [Z\aghkmqtsu!{%' &( ,/26<A G'L,Q2W8^?eFoNmLR:pUKonmDFG 0//<:8?BEds}~~{vrqlqkxlcmf]ae^\dVR_TQVPUNFYA5\5(b-f'a" [ [\`fhkmqtu!w!y"}$& * ,/259=C#J)M.S4Y:`CfKlQwWlKO=reaptu*++  #%!"  ...?>>??>X_atvw~||{zzvpwognfch`ac]W_VQROILEGLDKLBHE7Q4%]#^ \\^dgjmoqt!u!v x"z$ ( * -/36:@ G'J+P0W7\?bFgKmPwX}]bHwSHwvv_bc pM;z^rVX@r<*E&' kkkrrr###$$$///??>DBBBGHqdffvvv~z}zqwqhogeidadd]^ZQRLFJCGH@FHAAL>EE2Z(b ^^^begjklnq r t! w$ |& ( +.269>C$G(L-S3V7[?bEhKnQuW}_xZWCp]Wwz{DEFuN;}tk_xTiFP2x7"G"' LLLyyy'''  )))222@@@KII>>>_ghNMMaa`|x|xswpjrhbja_f`[b\QXQJNGJH?GA=?C@3E0'S[Z`bcdilopsw!w"y# }% ' +.268<?!D'H+L.S3Y8]=`CfHkNqRwX``^EmTLuwxRTUvK8xic|[tSlJfB^:81) `" ? LLLPPP...555???GGGSSSIII}v{wpvnkqjdlb\g^X`XRZSNYNHSD>I9?C59>018+.9*/:05:*Q2Y[^]b#f!abfn m! n% v% {'|(+0469 < @$C)F,J1N3T4Y8_?cCgFlLrPyU[]`DiMCrtuVXY&g_|ZwVnMiFc@\9V3N-J(E$@<87320* q% M0'201 YYY|||AAA999CCCIIIUUUHHHccdx~{szqnulenc]j]VaWR\QSWHOU>EO8=H67F.3?+-9&*5#(6!98J%QYXd8%aF3Z;*g?,k5m&l! j" o#k$j'v(y+y/25 7!;'<,?+F+K*P.S2Y8]<`?fEkHoMsPxU]pNI6g][ors())h6%axVtRnNhIaAZ9T4P/L*F'B!?;74231 / . /p1\)E"1 jjjXXX@@@HHHNNNZZZLLL888}}u{snumfpd_i[YcXT_RjXDwT:qR3RL1TC(OB$/F&*C #cM7TN61I24A$2:#4.(3096/.D.0H85GPJNOb4g$ h f# h& n)o>7i@LgHP}WX]XR92/68;< ?"C#E$I(M,P/S2W7Y:]9a@dDhEjGmLrRcE~B0[E?_9-jJkIgEdC_?Z9R2O/M,H)D$?<9641/..,+~* |(|) y' y+x*W=95MN"6,"'#(((111+++;;;EEEIIIOOOSSSXXXfffMMMstt|~w~wqxmitfvi[ycW`lghcZzR>jUHQR@ATD=M<9E49A,7>%87#46 46+2H**G.1CJIDMa.][ bbi%LCo_pe[qrYcSNE&,/3588;?C!E$H'J)L,P1R2X0Z5];`=b?dAdCiGjH]>>~ywqzplwiitc~dVwhapiaU?uQ>TSAEN&.:*9A2@E-3? 9=0HANZ?<^s5j&e a Zt@@`e=$z&, + .03567;>@ C#F%G'J*N,Q+T.W4Y7Z8\9^;_<_=^<\:Z9Z9W6U5P/M,H(F&C#@!<97651/.--*~* |, z( d+PHHNMIFXf@al<^Y9^WAeW?WM987 !$+,,$#####,,,555<</U*V&"f;4vG7mBBrJOxKLo2+o(IDD5t$ * + ,.012479;> @ A E$I'K)M+N,P.R0U2W5W4V5U3U4U4S2R1O.L+J)F%B!>;864330-,- + + * )r+s*h8"^@9O^h;_^8_R=aY@b]Kd]Yc]HGG$%&,-.100***333;;;DDDKKKRRRYYY^^^iiiooovvvzzz fff~|ytt|ooxlkqizh\_P\eSQ]MQXDNUCKUBFMN@KPGSQQ_WSTTTDQX_PWdPolVoRA& ~' * + ./014578:=?CD E#G$H%I(L*N+N,O,N.N.N.N-N-K*I)G'D#A!?:853111.,,~/p7x+) {( i0Z@-j/o3!j?/RVQ;_ZCc\De_Ke^TliZllAFA!$"   ./0=<<(((!!!000:::CCCKKKSSS[[[ddd<<A;9E'.J(0L-4G25J6:N8=O8>LDKKJHOf\XkZG- ~# ( * - / / 023667:=>?@C!F#F#G#I"K$K%J(I(I(G(H'F%D#B!@><762//10 -+* n1JUDOL>g2$p)f7&GNBIRRMPMdGCaLCAaaCd^Jh`QiaVlk[rr`qt:CD  344EEE///'''333AAAJJJSSS\\\hhhEEEYYYnnn {{uw{qxshl]kn^^kWWeQZ]LU[LPYIVUDSLBCDD E!F"E#D"D"B#A"A!@ >;:85430//-, * ( t5XLB>`oGZfh*`?1=YTD\YDchZcfkJ=L]ZFf`NjfTliZpn]tnfxuhvw1@@  "#KJIHHH<<<:::FFFSSS]]]eeevvvLLLOOOkkk@A@}x{|trzqsqdoo^akZ]fS]_Tc`Y`NAdMARWHIQ=>L;>H3>G)>B'AB#>>&0FH9D:DD+VFAZKUSJ^QH^xMQG1/'('*+,/00 . 011256689;=>??? ? A@@?==>:877321/-,,, * ) y3TI:?coQTTp*m5!FVO?flUdgiXHwJ8Xb]Jh_RkdTpi[roaspeurp}}l{}&/1 '(+YYYIIINNNGGGLLL[[[fffoooPPPRRRz~}vyyputlnofik`lgakddpeblODiE<_[YVTKDJFEHBDH=:H8@B1H=AGB[WAJQETPCQPFVYO[iJH2 #&(')*, , . 0 0 - /0114576689:<;;;==<<<99645510..,,,+ ** ~( o2`F-aD/ZAoC4l<.gUUbV]^QZ[P[aN[bKPjLJg>4jECkYcWH(#%%''&()+ , - / / +,4za{V, 01233444534556551011/-++** ~* |( ~) }( z*w*w8c?/\[OfJ8lE/~?(C.H3O7RqE9oC8i[^`Xc\Vc^Ug^Qb^Tci:,h!fr9!@%"$&&&&%&)+ + * - p`ћb:y*/00111312344443//.1.,++) ~) y(u&y( z) y+|/z2v4x?->+~?$E+G2L8~XJ~[MdX|ol}gay{~un{q^deNNN))){~x||}ztf\^U}ZP{UIyOCuH=sJ>r^^^\lfYd_S_ZPebZijE7k)n& ko"!"#%$%&%%( * ' =[ʧlw'|)/00/.///013232.,--, - +~)}( z( u&u& y) {-|/}3|5}8:"?(D-H2J5{YQdm{inp_Pgayyz~zy}v{~ ***kkk}}yphh`d[^T}ZOzUHwOCvI;pI>k]deYf^Ua^Yht]YpC-h*e'l3n( v"""###$%%% &0 i+ȸǦ}TA,/.././/011120--*+,' &* ) |( w& x){-|0|2~58 ;%?)C-F2I6}TLfj{Umlbqmtnswtvxw|z|z lll}unlfh_cY^T|YNyTHvMBrI=oXWkboh_jrcdoF2f.d=6pXV|Q9d?6p8"w!#"#$%&%&',]+лƑRz'q)z+-..///0001.*5mL;iQHv^iSC/) ) * {+|.~13}6|9#<&@)C.G3J6O?qhx[l|Xpd`ukeuvmy|t|~}}~sCCC>>>ztrkmeg^bX~^S{YOwSJ{WLrUMy`XtK;pD2h6&hG@je|d[lTQe]oT:l"y"}#%##$%%%w3 J1ͲϷp_D.~2s( u% -0/1///.}-; xL@}livoiyØnPv2~*.147:#='@*E.H3K8O=~SDqhu_o{^tkcxogywm|zz}hjjTTTlmlxspilcg^aXcZbVxVLyPCtQCsI>pA5iC:cZgXxddwgkcSy=q7$x8!v* {&%$$$#.tLfνšңv{cR{-|+}-~/...},w+E-[>|=qC;uRM_WxdeSz<$.369!<#?'B+D.H3L8O=TAXE_Vtqzjt{evsl|wxxm !!---SSSwww???|wtmjch_pijcoeZKwNCdZgTcRoio\Z\[itglyS&A)B,E/I5K9O>SAYF]L^Nkiuwj|vp~x}{y|---===KKK^^^nnnwww|||)))|zqukun~xsc}YKzSH~UG~TAwJ9}^Vmil\Zrbf{gfȾyOD 4~,-, )'|) 3C-ŴvnbTC}:/z) x) z* x*v,y-~.11568;#>'A*E.H2K6L9P?SCXG[K`PcRjfsym}uu~"""000666===FFFVVVdddmmmuuu~~~---KKK}|y}uwqlbdZ[P~UH{PCwUJtPEvRDvgkphozwQ~B"|45410/ , 0?|3^DԹ˷ϩwRx*x-{/w0137::"<#>&@+C,E0H3K7O'@(A,E0H2J6M9O=RBVFYJ]MaReVhZj\uxyw}{}~{WXX $$$...:::JJJVVV```kkkuuurrrBBBwww~{zzs{x{{ld~^R~ZO|\Sokvp{noxs{z\;?+?'?#<#<9768S!Q"rTȹiRx\U?#6:;">%?&A*C,E/F2I4L8N>>CCCEEEEEE@@@666{~togwrzv~jdlfjc}uyiMK0G0E-C*A(?%>"= 9F"j)pB˽ʹvdubM09<#=%?(B+C,F0H2I5K8M;P@RBVFYK[L_PbUfYh[l_obtozx}~z|~}~EDE }vrluq}z|}wxq|uzoWOM:L8O:P=R?TBVEXGYI\M_QaTcWgZj^l`pdqfrisjtltnupxuzz~yx{yFDD~z~yztxpynznhYaT`P]LZIXFWCS>PR>Q>TAVDXFYH[K]M^PaSdWfZi]l`ocrfrhtjtlumunupuq~vr|vszx~}655poozv|zi_`T`R]O\L\Mr\tªôĸǸƸȺɺȹ˽ʼȭyVaHSEVBVEYHZI]K^O_SbUeWgZi\k`ncqeshtiuluounuoupvr~ur{us{y{xw%%%POO~|wxx|upeh\^PfRbz÷öó´ķƷƷǸȸɸȺȹʽʹɵbdLZJ[J]M_O`QaSdWfYg[i^k`ncqfrgshtjumvpwpvpvrvr}vs{ur}{rpo///}~{~qigZcTeVn]³³´öĶķǻƼǽɿǽçjX|X^P_RbSdUeXg\i]k`mbodqgtiuj|u~~{zzxxqwrvqvs|us|wu~b`_~~~{~{{sres}¸m^[jpcdZg[i]j`landpfrguiukwm|v~ytwt~wt{vt|z|{B@@ONN}zwzzxxxxyw|~}~oubvaot{nupVVbqYv[ercj_j`lcmdpfritlvnxozqyr{u|w}yv~xu}ywjihqpo}{{wwtxu|y|vs}wv}~}~~}iq^~bUbUeUdUbThXeTm\|dl|jnvglb[|VpYkZg[f^h_halate{j~pzpxpzpypzrzs{t|u|w{w|x~{|y~yw~GFEA@@}}yyuyt}vq|ur}ws}vpzrn{qmxoujrfrg~mczf]}e[l\{^``a^[^|ZkWgYeYdYh[k\j\n_o^t_u_zdqmegt|zy~z~z}z|z}igf UUT|zy~w~wx}v{szqxmshscsauc|fknknmighhjmljopkifns{~x{qon211TTS~|y|zu|zt~}v~w~wwvutpoqrtsuvwxyzy{xw~~~ywu665TTSzzx}|{wxwrywryxrzxr|zs}{s~|s~t~stststutuvxx{}~{zx998 ???jji}|z}|ywvqutowuqwuoxunywoyxp{xp|yo}{o{p}q~q~qrstvwzzz|}}mlj443!!!QQPttr|{yzyuwuqtrmtsmusmuslvtmwtmxunywnywn{xn|yo|zp|q}r}suvwyz{|}~~~uurFEE111POOjihvusyyuxwstsorplrpksqktrltsmusluslxvnxvoywozwp{yq|zr}{t~|u}u~wxxzz{}vusLLJ776UTSkkhtsqyxuxwtwvsutqutptsnsrmsrmtsnusovtoxvqxwryxs{yt}{v~}x{~}}zihgONM..-  544GGFXXWddbnmkssqtsqttrvuswvtyxuzywzxwxwurqomljedb[ZYLLK776 openttd-1.5.3/os/windows/installer/install.nsi0000644000000000000000000006266512627373447020222 0ustar rootroot# Version numbers to update !define APPV_MAJOR 1 !define APPV_MINOR 5 !define APPV_MAINT 3 !define APPV_BUILD 1 !define APPV_EXTRA "" !define APPNAME "OpenTTD" ; Define application name !define APPVERSION "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}${APPV_EXTRA}" ; Define application version !define APPVERSIONINTERNAL "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}.${APPV_BUILD}" ; Define application version in X.X.X.X !define INSTALLERVERSION ${APPV_MAJOR}${APPV_MINOR}${APPV_MAINT}${APPV_BUILD} !include ${VERSION_INCLUDE} !define APPURLLINK "http://www.openttd.org" !define APPNAMEANDVERSION "${APPNAME} ${APPVERSION}" !define OPENGFX_BASE_VERSION "1.2.0" !define OPENSFX_BASE_VERSION "0.8.0" !define OPENMSX_BASE_VERSION "1.0.0" !define MUI_ICON "..\..\..\media\openttd.ico" !define MUI_UNICON "..\..\..\media\openttd.ico" !define MUI_WELCOMEFINISHPAGE_BITMAP "welcome.bmp" !define MUI_HEADERIMAGE !define MUI_HEADERIMAGE_BITMAP "top.bmp" BrandingText "OpenTTD Installer" SetCompressor LZMA ; Version Info Var AddWinPrePopulate VIProductVersion "${APPVERSIONINTERNAL}" VIAddVersionKey "ProductName" "OpenTTD ${APPBITS}-bit Installer for Windows ${EXTRA_VERSION}" VIAddVersionKey "Comments" "Installs ${APPNAMEANDVERSION}" VIAddVersionKey "CompanyName" "OpenTTD Developers" VIAddVersionKey "FileDescription" "Installs ${APPNAMEANDVERSION}" VIAddVersionKey "ProductVersion" "${APPVERSION}" VIAddVersionKey "InternalName" "InstOpenTTD-${APPARCH}" VIAddVersionKey "FileVersion" "${APPVERSION}-${APPARCH}" VIAddVersionKey "LegalCopyright" " " ; Main Install settings Name "${APPNAMEANDVERSION} ${APPBITS}-bit for Windows ${EXTRA_VERSION}" ; NOTE: Keep trailing backslash! InstallDirRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Install Folder" OutFile "openttd-${APPVERSION}-${APPARCH}.exe" CRCCheck force ShowInstDetails show ShowUninstDetails show RequestExecutionLevel admin Var SHORTCUTS Var CDDRIVE ; Modern interface settings !include "MUI2.nsh" !include "InstallOptions.nsh" !include "WinVer.nsh" !define MUI_ABORTWARNING !define MUI_WELCOMEPAGE_TITLE_3LINES !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "..\..\..\COPYING" !define MUI_COMPONENTSPAGE_SMALLDESC !insertmacro MUI_PAGE_COMPONENTS ;--------------------------------- ; Custom page for finding TTDLX CD Page custom SelectCDEnter SelectCDExit ": TTD folder" !insertmacro MUI_PAGE_DIRECTORY ;Start Menu Folder Page Configuration !define MUI_STARTMENUPAGE_DEFAULTFOLDER $SHORTCUTS !define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKEY_LOCAL_MACHINE" !define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "Shortcut Folder" !insertmacro MUI_PAGE_STARTMENU "OpenTTD" $SHORTCUTS !insertmacro MUI_PAGE_INSTFILES !define MUI_FINISHPAGE_TITLE_3LINES !define MUI_FINISHPAGE_RUN_TEXT "Run ${APPNAMEANDVERSION} now!" !define MUI_FINISHPAGE_RUN "$INSTDIR\openttd.exe" !define MUI_FINISHPAGE_LINK "Visit the OpenTTD site for more information" !define MUI_FINISHPAGE_LINK_LOCATION "${APPURLLINK}" !define MUI_FINISHPAGE_NOREBOOTSUPPORT !define MUI_FINISHPAGE_SHOWREADME "$INSTDIR\readme.txt" !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED !define MUI_WELCOMEFINISHPAGE_CUSTOMFUNCTION_INIT DisableBack !insertmacro MUI_PAGE_FINISH !define MUI_PAGE_HEADER_TEXT "Uninstall ${APPNAMEANDVERSION}" !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ; Set languages (first is default language) !insertmacro MUI_LANGUAGE "English" !insertmacro MUI_RESERVEFILE_LANGDLL ;-------------------------------------------------------------- ; (Core) OpenTTD install section. Copies all internal game data Section "!OpenTTD" Section1 ; Make sure to be upgraded OpenTTD is not running Call CheckOpenTTDRunning ; Overwrite files by default, but don't complain on failure SetOverwrite try SetShellVarContext all ; Define root variable relative to installer !define PATH_ROOT "..\..\..\" ; Copy language files SetOutPath "$INSTDIR\lang\" File ${PATH_ROOT}bin\lang\english.lng ; Copy AI files SetOutPath "$INSTDIR\ai\" File ${PATH_ROOT}bin\ai\compat_*.nut ; Copy Game Script files SetOutPath "$INSTDIR\game\" File ${PATH_ROOT}bin\game\compat_*.nut ; Copy data files SetOutPath "$INSTDIR\baseset\" File ${PATH_ROOT}bin\baseset\*.grf File ${PATH_ROOT}bin\baseset\*.obg File ${PATH_ROOT}bin\baseset\*.obm File ${PATH_ROOT}bin\baseset\*.obs File ${PATH_ROOT}bin\baseset\opntitle.dat ; Copy the scripts SetOutPath "$INSTDIR\scripts\" File ${PATH_ROOT}bin\scripts\*.* Push "$INSTDIR\scripts\readme.txt" Call unix2dos ; Copy some documention files SetOutPath "$INSTDIR\docs\" File ${PATH_ROOT}docs\multiplayer.txt Push "$INSTDIR\docs\multiplayer.txt" Call unix2dos ; Copy the rest of the stuff SetOutPath "$INSTDIR\" ; Copy text files File ${PATH_ROOT}changelog.txt Push "$INSTDIR\changelog.txt" Call unix2dos File ${PATH_ROOT}COPYING Push "$INSTDIR\COPYING" Call unix2dos File ${PATH_ROOT}readme.txt Push "$INSTDIR\readme.txt" Call unix2dos File ${PATH_ROOT}known-bugs.txt Push "$INSTDIR\known-bugs.txt" Call unix2dos ; Copy executable File /oname=openttd.exe ${BINARY_DIR}\openttd.exe ; Delete old files from the main dir. they are now placed in baseset/ and lang/ Delete "$INSTDIR\*.lng" Delete "$INSTDIR\*.grf" Delete "$INSTDIR\sample.cat" Delete "$INSTDIR\ttd.exe" Delete "$INSTDIR\data\opntitle.dat" Delete "$INSTDIR\data\2ccmap.grf" Delete "$INSTDIR\data\airports.grf" Delete "$INSTDIR\data\autorail.grf" Delete "$INSTDIR\data\canalsw.grf" Delete "$INSTDIR\data\dosdummy.grf" Delete "$INSTDIR\data\elrailsw.grf" Delete "$INSTDIR\data\nsignalsw.grf" Delete "$INSTDIR\data\openttd.grf" Delete "$INSTDIR\data\roadstops.grf" Delete "$INSTDIR\data\trkfoundw.grf" Delete "$INSTDIR\data\openttdd.grf" Delete "$INSTDIR\data\openttdw.grf" Delete "$INSTDIR\data\orig_win.obg" Delete "$INSTDIR\data\orig_dos.obg" Delete "$INSTDIR\data\orig_dos_de.obg" Delete "$INSTDIR\data\orig_win.obs" Delete "$INSTDIR\data\orig_dos.obs" Delete "$INSTDIR\data\no_sound.obs" ; Create the Registry Entries WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Comments" "Visit ${APPURLLINK}" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayIcon" "$INSTDIR\openttd.exe,0" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayName" "OpenTTD ${APPVERSION}" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayVersion" "${APPVERSION}" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "HelpLink" "${APPURLLINK}" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Install Folder" "$INSTDIR" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Publisher" "OpenTTD" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Shortcut Folder" "$SHORTCUTS" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "URLInfoAbout" "${APPURLLINK}" ; This key sets the Version DWORD that new installers will check against WriteRegDWORD HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Version" ${INSTALLERVERSION} !insertmacro MUI_STARTMENU_WRITE_BEGIN "OpenTTD" CreateShortCut "$DESKTOP\OpenTTD.lnk" "$INSTDIR\openttd.exe" CreateDirectory "$SMPROGRAMS\$SHORTCUTS" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\OpenTTD.lnk" "$INSTDIR\openttd.exe" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Uninstall.lnk" "$INSTDIR\uninstall.exe" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Readme.lnk" "$INSTDIR\Readme.txt" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Changelog.lnk" "$INSTDIR\Changelog.txt" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Known-bugs.lnk" "$INSTDIR\known-bugs.txt" CreateDirectory "$SMPROGRAMS\$SHORTCUTS\Docs" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Docs\Multiplayer.lnk" "$INSTDIR\docs\multiplayer.txt" CreateDirectory "$SMPROGRAMS\$SHORTCUTS\Scripts" CreateShortCut "$SMPROGRAMS\$SHORTCUTS\Scripts\Readme.lnk" "$INSTDIR\scripts\readme.txt" !insertmacro MUI_STARTMENU_WRITE_END SectionEnd ;-------------------------------------------------------------- ; OpenTTD translation install section. Copies only translations Section "OpenTTD translations" Section6 ; Overwrite files by default, but don't complain on failure SetOverwrite try ; Copy language files SetOutPath "$INSTDIR\lang\" File ${PATH_ROOT}bin\lang\*.lng SectionEnd ;---------------------------------------------------------------------------------- ; OpenGFX files install section. Downloads OpenGFX and installs it Section "Download OpenGFX (free graphics set)" Section3 SetOverwrite try NSISdl::download "http://binaries.openttd.org/installer/opengfx-${OPENGFX_BASE_VERSION}.7z" "$INSTDIR\baseset\opengfx.7z" Pop $R0 ;Get the return value StrCmp $R0 "success" +3 MessageBox MB_OK "Downloading of OpenGFX failed" Goto Done ; Let's extract the files SetOutPath "$INSTDIR\baseset\" NSIS7z::Extract "$INSTDIR\baseset\opengfx.7z" Delete "$INSTDIR\baseset\opengfx.7z" SetOutPath "$INSTDIR\" Done: SectionEnd ;---------------------------------------------------------------------------------- ; OpenSFX files install section. Downloads OpenSFX and installs it Section "Download OpenSFX (free sound set)" Section4 SetOverwrite try NSISdl::download "http://binaries.openttd.org/installer/opensfx-${OPENSFX_BASE_VERSION}.7z" "$INSTDIR\baseset\opensfx.7z" Pop $R0 ;Get the return value StrCmp $R0 "success" +3 MessageBox MB_OK "Downloading of OpenSFX failed" Goto Done ; Let's extract the files SetOutPath "$INSTDIR\baseset\" NSIS7z::Extract "$INSTDIR\baseset\opensfx.7z" Delete "$INSTDIR\baseset\opensfx.7z" SetOutPath "$INSTDIR\" Done: SectionEnd ;---------------------------------------------------------------------------------- ; OpenMSX files install section. Downloads OpenMSX and installs it Section "Download OpenMSX (free music set)" Section5 SetOverwrite try NSISdl::download "http://binaries.openttd.org/installer/openmsx-${OPENMSX_BASE_VERSION}.7z" "$INSTDIR\baseset\openmsx.7z" Pop $R0 ;Get the return value StrCmp $R0 "success" +3 MessageBox MB_OK "Downloading of OpenMSX failed" Goto Done ; Let's extract the files SetOutPath "$INSTDIR\baseset\" NSIS7z::Extract "$INSTDIR\baseset\openmsx.7z" Delete "$INSTDIR\baseset\openmsx.7z" SetOutPath "$INSTDIR\" Done: SectionEnd ;---------------------------------------------------------------------------------- ; TTDLX files install section. Copies all needed TTDLX files from CD or install dir Section /o "Copy data from Transport Tycoon Deluxe CD-ROM" Section2 SetOverwrite try ; Let's copy the files with size approximation SetOutPath "$INSTDIR\baseset" CopyFiles "$CDDRIVE\gm\*.gm" "$INSTDIR\baseset\" 1028 CopyFiles "$CDDRIVE\sample.cat" "$INSTDIR\baseset\sample.cat" 1566 ; Copy Windows files CopyFiles "$CDDRIVE\trg1r.grf" "$INSTDIR\baseset\trg1r.grf" 2365 CopyFiles "$CDDRIVE\trgcr.grf" "$INSTDIR\baseset\trgcr.grf" 260 CopyFiles "$CDDRIVE\trghr.grf" "$INSTDIR\baseset\trghr.grf" 400 CopyFiles "$CDDRIVE\trgir.grf" "$INSTDIR\baseset\trgir.grf" 334 CopyFiles "$CDDRIVE\trgtr.grf" "$INSTDIR\baseset\trgtr.grf" 546 ; Copy DOS files CopyFiles "$CDDRIVE\trg1.grf" "$INSTDIR\baseset\trg1.grf" 2365 CopyFiles "$CDDRIVE\trgc.grf" "$INSTDIR\baseset\trgc.grf" 260 CopyFiles "$CDDRIVE\trgh.grf" "$INSTDIR\baseset\trgh.grf" 400 CopyFiles "$CDDRIVE\trgi.grf" "$INSTDIR\baseset\trgi.grf" 334 CopyFiles "$CDDRIVE\trgt.grf" "$INSTDIR\baseset\trgt.grf" 546 SetOutPath "$INSTDIR\" SectionEnd ;------------------------------------------- ; Install the uninstaller (option is hidden) Section -FinishSection WriteUninstaller "$INSTDIR\uninstall.exe" SectionEnd ; Modern install component descriptions !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${Section1} "Minimal OpenTTD installation in English. You need at least one of the game graphics and sound sets installed." !insertmacro MUI_DESCRIPTION_TEXT ${Section6} "Translations of OpenTTD." !insertmacro MUI_DESCRIPTION_TEXT ${Section3} "Download the free OpenGFX game graphics set. This download is about 3 MiB." !insertmacro MUI_DESCRIPTION_TEXT ${Section4} "Download the free OpenSFX game sound set. This download is about 10 MiB." !insertmacro MUI_DESCRIPTION_TEXT ${Section5} "Download the free OpenMSX game music set. This download is about 200 KiB." !insertmacro MUI_DESCRIPTION_TEXT ${Section2} "Copies the game graphics, sounds and music from the Transport Tycoon Deluxe CD." !insertmacro MUI_FUNCTION_DESCRIPTION_END ;----------------------------------------------- ; Uninstall section, deletes all installed files Section "Uninstall" SetShellVarContext all IfFileExists "$INSTDIR\save" 0 NoRemoveSavedGames MessageBox MB_YESNO|MB_ICONQUESTION \ "Remove the save game folders located at $\"$INSTDIR\save$\"?$\n \ If you choose Yes, your saved games will be deleted." \ IDYES RemoveSavedGames IDNO NoRemoveSavedGames RemoveSavedGames: Delete "$INSTDIR\save\autosave\*" RMDir "$INSTDIR\save\autosave" Delete "$INSTDIR\save\*" RMDir "$INSTDIR\save" NoRemoveSavedGames: IfFileExists "$INSTDIR\scenario" 0 NoRemoveScen MessageBox MB_YESNO|MB_ICONQUESTION \ "Remove the scenario folders located at $\"$INSTDIR\scenario$\"?$\n \ If you choose Yes, your scenarios will be deleted." \ IDYES RemoveScen IDNO NoRemoveScen RemoveScen: Delete "$INSTDIR\scenario\heightmap*" RMDir "$INSTDIR\scenario\heightmap" Delete "$INSTDIR\scenario\*" RMDir "$INSTDIR\scenario" NoRemoveScen: ; Remove from registry... !insertmacro MUI_STARTMENU_GETFOLDER "OpenTTD" $SHORTCUTS ReadRegStr $SHORTCUTS HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Shortcut Folder" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" ; Delete self Delete "$INSTDIR\uninstall.exe" ; Delete Shortcuts Delete "$DESKTOP\OpenTTD.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\OpenTTD.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\Uninstall.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\Readme.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\Changelog.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\Known-bugs.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\Docs\Multiplayer.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\Docs\32bpp.lnk" Delete "$SMPROGRAMS\$SHORTCUTS\Scripts\Readme.lnk" ; Clean up OpenTTD dir Delete "$INSTDIR\changelog.txt" Delete "$INSTDIR\readme.txt" Delete "$INSTDIR\known-bugs.txt" Delete "$INSTDIR\openttd.exe" Delete "$INSTDIR\COPYING" Delete "$INSTDIR\INSTALL.LOG" Delete "$INSTDIR\crash.log" Delete "$INSTDIR\crash.dmp" Delete "$INSTDIR\openttd.cfg" Delete "$INSTDIR\hs.dat" Delete "$INSTDIR\cached_sprites.*" Delete "$INSTDIR\save\autosave\network*.tmp" ; temporary network file ; AI files Delete "$INSTDIR\ai\compat_*.nut" ; Game Script files Delete "$INSTDIR\game\compat_*.nut" ; Baseset files Delete "$INSTDIR\baseset\opntitle.dat" Delete "$INSTDIR\baseset\openttd.grf" Delete "$INSTDIR\baseset\orig_win.obg" Delete "$INSTDIR\baseset\orig_dos.obg" Delete "$INSTDIR\baseset\orig_dos_de.obg" Delete "$INSTDIR\baseset\orig_win.obs" Delete "$INSTDIR\baseset\orig_dos.obs" Delete "$INSTDIR\baseset\no_sound.obs" Delete "$INSTDIR\baseset\sample.cat" Delete "$INSTDIR\baseset\trg1r.grf" Delete "$INSTDIR\baseset\trghr.grf" Delete "$INSTDIR\baseset\trgtr.grf" Delete "$INSTDIR\baseset\trgcr.grf" Delete "$INSTDIR\baseset\trgir.grf" Delete "$INSTDIR\baseset\trg1.grf" Delete "$INSTDIR\baseset\trgh.grf" Delete "$INSTDIR\baseset\trgt.grf" Delete "$INSTDIR\baseset\trgc.grf" Delete "$INSTDIR\baseset\trgi.grf" Delete "$INSTDIR\baseset\*.gm" Delete "$INSTDIR\data\sample.cat" Delete "$INSTDIR\data\trg1r.grf" Delete "$INSTDIR\data\trghr.grf" Delete "$INSTDIR\data\trgtr.grf" Delete "$INSTDIR\data\trgcr.grf" Delete "$INSTDIR\data\trgir.grf" Delete "$INSTDIR\data\trg1.grf" Delete "$INSTDIR\data\trgh.grf" Delete "$INSTDIR\data\trgt.grf" Delete "$INSTDIR\data\trgc.grf" Delete "$INSTDIR\data\trgi.grf" Delete "$INSTDIR\gm\*.gm" ; Downloaded OpenGFX/OpenSFX/OpenMSX Delete "$INSTDIR\baseset\opengfx\*" RMDir "$INSTDIR\baseset\opengfx" Delete "$INSTDIR\baseset\opensfx\*" RMDir "$INSTDIR\baseset\opensfx" Delete "$INSTDIR\baseset\openmsx\*" RMDir "$INSTDIR\baseset\openmsx" Delete "$INSTDIR\data\opengfx\*" RMDir "$INSTDIR\data\opengfx" Delete "$INSTDIR\data\opensfx\*" RMDir "$INSTDIR\data\opensfx" Delete "$INSTDIR\gm\openmsx\*" RMDir "$INSTDIR\gm\openmsx" ; Language files Delete "$INSTDIR\lang\*.lng" ; Scripts Delete "$INSTDIR\scripts\*.*" ; Documentation Delete "$INSTDIR\docs\*.*" ; Base sets for music Delete "$INSTDIR\gm\orig_win.obm" Delete "$INSTDIR\gm\no_music.obm" Delete "$INSTDIR\baseset\orig_win.obm" Delete "$INSTDIR\baseset\no_music.obm" ; Remove remaining directories RMDir "$SMPROGRAMS\$SHORTCUTS\Extras\" RMDir "$SMPROGRAMS\$SHORTCUTS\Scripts\" RMDir "$SMPROGRAMS\$SHORTCUTS\Docs\" RMDir "$SMPROGRAMS\$SHORTCUTS" RMDir "$INSTDIR\ai" RMDir "$INSTDIR\game" RMDir "$INSTDIR\data" RMDir "$INSTDIR\baseset" RMDir "$INSTDIR\gm" RMDir "$INSTDIR\lang" RMDir "$INSTDIR\scripts" RMDir "$INSTDIR\docs" RMDir "$INSTDIR" SectionEnd ;------------------------------------------------------------ ; Custom page function to find the TTDLX CD/install location Function SelectCDEnter SectionGetFlags ${Section2} $0 IntOp $1 $0 & 0x80 ; bit 7 set by upgrade, no need to copy files IntCmp $1 1 DoneCD ; Upgrade doesn't need copy files IntOp $0 $0 & 1 IntCmp $0 1 NoAbort Abort NoAbort: GetTempFileName $R0 !insertmacro MUI_HEADER_TEXT "Locate TTD" "Setup needs the location of Transport Tycoon Deluxe in order to continue." !insertmacro INSTALLOPTIONS_EXTRACT_AS "CDFinder.ini" "CDFinder" ClearErrors ; Now, let's populate $CDDRIVE ReadRegStr $R0 HKLM "SOFTWARE\Fish Technology Group\Transport Tycoon Deluxe" "HDPath" IfErrors NoTTD StrCmp $CDDRIVE "" 0 Populated StrCpy $CDDRIVE $R0 Populated: StrCpy $AddWinPrePopulate "Setup has detected your TTD folder. Don't change the folder. Simply press Next." Goto TruFinish NoTTD: StrCpy $AddWinPrePopulate "Setup couldn't find TTD. Please enter the path where the graphics files from TTD are stored and press Next to continue." TruFinish: ClearErrors !insertmacro INSTALLOPTIONS_WRITE "CDFinder" "Field 2" "State" $CDDRIVE ; TTDLX path !insertmacro INSTALLOPTIONS_WRITE "CDFinder" "Field 3" "Text" $AddWinPrePopulate ; Caption DoneCD: ; Initialize the dialog *AFTER* we've changed the text otherwise we won't see the changes !insertmacro INSTALLOPTIONS_INITDIALOG "CDFinder" !insertmacro INSTALLOPTIONS_SHOW FunctionEnd ;---------------------------------------------------------------- ; Custom page function when 'next' is selected for the TTDLX path Function SelectCDExit !insertmacro INSTALLOPTIONS_READ $CDDRIVE "CDFinder" "Field 2" "State" ; If trg1r.grf does not exist at the path, retry with DOS version IfFileExists $CDDRIVE\trg1r.grf "" DosCD IfFileExists $CDDRIVE\trgir.grf "" NoCD IfFileExists $CDDRIVE\sample.cat hasCD NoCD DosCD: IfFileExists $CDDRIVE\TRG1.GRF "" NoCD IfFileExists $CDDRIVE\TRGI.GRF "" NoCD IfFileExists $CDDRIVE\SAMPLE.CAT hasCD NoCD NoCD: MessageBox MB_OK "Setup cannot continue without the Transport Tycoon Deluxe location!" Abort hasCD: FunctionEnd ;------------------------------------------------------------------------------- ; Determine windows version, returns "win9x" if Win9x/Me/2000/XP SP2- or "winnt" for the rest on the stack Function GetWindowsVersion GetVersion::WindowsPlatformArchitecture Pop $R0 IntCmp $R0 64 WinNT 0 ClearErrors StrCpy $R0 "win9x" ${If} ${IsNT} ${If} ${IsWinXP} ${AndIf} ${AtLeastServicePack} 3 ${OrIf} ${AtLeastWin2003} GoTo WinNT ${EndIf} ${EndIf} GoTo Done WinNT: StrCpy $R0 "winnt" Done: Push $R0 FunctionEnd ;------------------------------------------------------------------------------- ; Check whether we're not running an installer for 64 bits on 32 bits and vice versa Function CheckProcessorArchitecture GetVersion::WindowsPlatformArchitecture Pop $R0 IntCmp $R0 64 Win64 0 ClearErrors IntCmp ${APPBITS} 64 0 Done MessageBox MB_YESNO|MB_ICONSTOP "You are trying to install the 64-bit OpenTTD on a 32-bit operating system. This is not going to work. Please download the correct version. Do you really want to continue?" IDYES Done IDNO Abort GoTo Done Win64: ClearErrors IntCmp ${APPBITS} 64 Done 0 MessageBox MB_YESNO|MB_ICONINFORMATION "You are trying to install the 32-bit OpenTTD on a 64-bit operating system. This is not advised, but will work with reduced capabilities. We suggest that you download the correct version. Do you really want to continue?" IDYES Done IDNO Abort GoTo Done Abort: Quit Done: FunctionEnd ;------------------------------------------------------------------------------- ; Check whether we're not running an installer for NT on 9x and vice versa Function CheckWindowsVersion Call GetWindowsVersion Pop $R0 StrCmp $R0 "win9x" 0 WinNT ClearErrors StrCmp ${APPARCH} "win9x" Done 0 MessageBox MB_YESNO|MB_ICONSTOP "You are trying to install the Windows XP SP3, Vista and 7 version on Windows 95, 98, ME, 2000 and XP without SP3. This is will not work. Please download the correct version. Do you really want to continue?" IDYES Done IDNO Abort GoTo Done WinNT: ClearErrors StrCmp ${APPARCH} "win9x" 0 Done MessageBox MB_YESNO|MB_ICONEXCLAMATION "You are trying to install the Windows 95, 98, 2000 and XP without SP3 version on Windows XP SP3, Vista or 7. This is not advised, but will work with reduced capabilities. We suggest that you download the correct version. Do you really want to continue?" IDYES Done IDNO Abort Abort: Quit Done: FunctionEnd ;------------------------------------------------------------------------------- ; Check whether OpenTTD is running Function CheckOpenTTDRunning IfFileExists "$INSTDIR\openttd.exe" 0 Done Retry: FindProcDLL::FindProc "openttd.exe" Pop $R0 IntCmp $R0 1 0 Done ClearErrors Delete "$INSTDIR\openttd.exe" IfErrors 0 Done ClearErrors MessageBox MB_RETRYCANCEL|MB_ICONEXCLAMATION "OpenTTD is running. Please close it and retry." IDRETRY Retry Abort Done: FunctionEnd ;------------------------------------------------------------------------------- ; strips all CRs ; and then converts all LFs into CRLFs ; (this is roughly equivalent to "cat file | dos2unix | unix2dos") ; ; usage: ; Push "infile" ; Call unix2dos ; ; beware that this function destroys $0 $1 $2 Function unix2dos ClearErrors Pop $2 Rename $2 $2.U2D FileOpen $1 $2 w FileOpen $0 $2.U2D r Push $2 ; save name for deleting IfErrors unix2dos_done ; $0 = file input (opened for reading) ; $1 = file output (opened for writing) unix2dos_loop: ; read a byte (stored in $2) FileReadByte $0 $2 IfErrors unix2dos_done ; EOL ; skip CR StrCmp $2 13 unix2dos_loop ; if LF write an extra CR StrCmp $2 10 unix2dos_cr unix2dos_write unix2dos_cr: FileWriteByte $1 13 unix2dos_write: ; write byte FileWriteByte $1 $2 ; read next byte Goto unix2dos_loop unix2dos_done: ; close files FileClose $0 FileClose $1 ; delete original Pop $0 Delete $0.U2D FunctionEnd Var OLDVERSION Var UninstallString ;----------------------------------------------------------------------------------- ; NSIS Initialize function, determine if we are going to install/upgrade or uninstall Function .onInit StrCpy $SHORTCUTS "OpenTTD" SectionSetSize ${Section3} 6144 SectionSetSize ${Section4} 13312 SectionSetSize ${Section5} 1024 SectionSetFlags 0 17 ; Starts Setup - let's look for an older version of OpenTTD ReadRegDWORD $R8 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Version" IfErrors ShowWelcomeMessage ShowUpgradeMessage ShowWelcomeMessage: ReadRegStr $R8 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "Version" ; In the event someone still has OpenTTD 0.1, this will detect that (that installer used a string instead of dword entry) IfErrors FinishCallback ShowUpgradeMessage: IntCmp ${INSTALLERVERSION} $R8 VersionsAreEqual InstallerIsOlder WelcomeToSetup WelcomeToSetup: ; An older version was found. Let's let the user know there's an upgrade that will take place. ReadRegStr $OLDVERSION HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "DisplayVersion" ; Gets the older version then displays it in a message box MessageBox MB_OK|MB_ICONINFORMATION \ "Welcome to ${APPNAMEANDVERSION} Setup.$\nThis will allow you to upgrade from version $OLDVERSION." SectionSetFlags ${Section2} 0x80 ; set bit 7 SectionSetFlags ${Section3} 0x80 ; set bit 7 SectionSetFlags ${Section4} 0x80 ; set bit 7 SectionSetFlags ${Section5} 0x80 ; set bit 7 Goto FinishCallback VersionsAreEqual: ReadRegStr $UninstallString HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenTTD" "UninstallString" IfFileExists "$UninstallString" "" FinishCallback MessageBox MB_YESNO|MB_ICONQUESTION \ "Setup detected ${APPNAMEANDVERSION} on your system. This is the same version that this program will install.$\nAre you trying to uninstall it?" \ IDYES DoUninstall IDNO FinishCallback DoUninstall: ; You have the same version as this installer. This allows you to uninstall. Exec "$UninstallString" Quit InstallerIsOlder: MessageBox MB_OK|MB_ICONSTOP \ "You have a newer version of ${APPNAME}.$\nSetup will now exit." Quit FinishCallback: ClearErrors Call CheckProcessorArchitecture Call CheckWindowsVersion FunctionEnd ; eof openttd-1.5.3/os/windows/installer/cdfinder.ini0000644000000000000000000000046212627373447020303 0ustar rootroot; Ini file generated by the HM NIS Edit IO designer. [Settings] NumFields=3 [Field 1] Type=Groupbox Text=Transport Tycoon Deluxe Installation location Left=6 Right=294 Top=68 Bottom=100 [Field 2] Type=DirRequest Left=10 Right=290 Top=80 Bottom=92 [Field 3] Type=Label Left=17 Right=282 Top=6 Bottom=64 openttd-1.5.3/os/windows/installer/build_installers.bat0000644000000000000000000000045512627373447022055 0ustar rootroot@echo off "c:\Program Files\NSIS\makensis.exe" /DVERSION_INCLUDE=version_win9x.txt install.nsi > win9x.log "c:\Program Files\NSIS\makensis.exe" /DVERSION_INCLUDE=version_win32.txt install.nsi > win32.log "c:\Program Files\NSIS\makensis.exe" /DVERSION_INCLUDE=version_win64.txt install.nsi > win64.log openttd-1.5.3/os/debian/0000755000000000000000000000000012627373447013555 5ustar rootrootopenttd-1.5.3/os/debian/menu0000644000000000000000000000022012627373447014436 0ustar rootroot?package(openttd):needs="X11" section="Games/Simulation" title="OpenTTD"\ command="/usr/games/openttd" icon="/usr/share/pixmaps/openttd.32.xpm" openttd-1.5.3/os/debian/patches/0000755000000000000000000000000012627373447015204 5ustar rootrootopenttd-1.5.3/os/debian/patches/series0000644000000000000000000000003212627373447016414 0ustar rootrootrun-openttd-wrapper.patch openttd-1.5.3/os/debian/patches/run-openttd-wrapper.patch0000644000000000000000000000125412627373447022164 0ustar rootrootFrom: Matthijs Kooijman Subject: Use a wrapper script for running openttd The wrapper script captures stderr from openttd and displays this in case of an error. This patch makes the the .desktop file call the wrapper instead of the openttd binary directly. Index: media/openttd.desktop.in =================================================================== --- a/media/openttd.desktop.in (revision 20124) +++ b/media/openttd.desktop.in (working copy) @@ -5,7 +5,7 @@ Version=1.1 Name=!!MENU_NAME!! Icon=openttd -Exec=!!TTD!! +Exec=/usr/share/games/openttd/openttd-wrapper Terminal=false Categories=!!MENU_GROUP!! Comment=A clone of Transport Tycoon Deluxe openttd-1.5.3/os/debian/watch0000644000000000000000000000024312627373447014605 0ustar rootrootversion=3 options=downloadurlmangle=s/(.*)\/index.html$/\1\/openttd-\1-source.tar.gz/ \ http://master.binaries.openttd.org/releases/ \ (\d+(?:\.\d+)*)/index.html openttd-1.5.3/os/debian/NEWS0000644000000000000000000000227312627373447014260 0ustar rootrootopenttd (1.0.0~rc3-2) unstable; urgency=low The openttd package has been moved from contrib into main. Since the OpenGFX free graphics set has been packaged for Debian, one can now run OpenTTD without needing any of the resources from the original game (though the original resources are still supported). -- Matthijs Kooijman Thu, 18 Mar 2010 13:09:35 +0100 openttd (0.7.0-1) unstable; urgency=low Handling of AI players has changed in 0.7.0. This package no longer contains any AI players, so playing against the computer is not possible out of the box any longer. However, you can easily download AI players through the new "Content Downloading Service", after which playing with computer players is possible. Loading old savegames with computer players is supported (AI players will be converted according to the current AI settings), but at this moment there are no AIs that completely handle any existing infrastructure built by the old AI, so starting a new game might be more fun (especially since most of the new AIs are a lot less erratic). -- Matthijs Kooijman Mon, 13 Apr 2009 15:11:20 +0200 openttd-1.5.3/os/debian/README.Debian0000644000000000000000000000334412627373447015622 0ustar rootrootOpenTTD for Debian ------------------ To properly play this game, you need a base graphics and sound set. Currently, the graphics, sound and music files from the original Transport Tycoon Deluxe game (Windows and DOS versions) are supported, as well as the free graphics replacement set "OpenGFX", sound replacement set "OpenSFX" (which is in non-free due to a restrictive license) and the free music replacement set "OpenMSX". Normally, installing the openttd package should automatically install openttd-opengfx as well, allowing OpenTTD to run out of the box. If you want sound, you'll have to enable non-free sources and install the openttd-opensfx package manually (or install the original Transport Tyccon Deluxe sound files). The easiest way to install the OpenMSX music files is to use the in-game content download system, which should offer the latest version of the music files. To find out how to install the original Transport Tycoon Deluxe graphics sound files and music files, see readme.txt, section 4.1. -Playing Music In addition to installing a music set (see above), you'll also need to install the timidity midi player, available in the timidity package. Remember that not all audio devices support multiple audiostreams (music and sound), so you might have to use alsa software mixing or pulseaudio. -Scenarios There are no scenarios included in this release. Scenarios can be downloaded using OpenTTD's content service, which is available from OpenTTD's main menu. If you have obtained a scenario through other means, you can place it either in your ~/.openttd/scenario directory or in the system-wide /usr/share/games/openttd/scenario directory. -- Matthijs Kooijman Mon, 01 Feb 2010 10:42:11 +0100 openttd-1.5.3/os/debian/gbp.conf0000644000000000000000000000044312627373447015175 0ustar rootroot[DEFAULT] # Use pristine-tar pristine-tar = True [git-dch] # We use metaheaders in commit messages. meta = True # Put git commit ids in the debian changelog. id-length = 7 [git-import-orig] # Use a custom commit message for upstream imports. import-msg = New upstream release %(version)s. openttd-1.5.3/os/debian/changelog0000644000000000000000000006276712627373447015451 0ustar rootrootopenttd (1.5.3-0) unstable; urgency=low * New upstream release 1.5.3 -- OpenTTD Tue, 01 Dec 2015 21:00:00 +0100 openttd (1.5.3~RC1-0) unstable; urgency=low * New upstream release 1.5.3-RC1 -- OpenTTD Sun, 01 Nov 2015 14:00:00 +0100 openttd (1.5.2-0) unstable; urgency=low * New upstream release 1.5.2 -- OpenTTD Tue, 01 Sep 2015 21:00:00 +0200 openttd (1.5.2~RC1-0) unstable; urgency=low * New upstream release 1.5.2-RC1 -- OpenTTD Sat, 01 Aug 2015 13:00:00 +0200 openttd (1.5.1-0) unstable; urgency=low * New upstream release 1.5.1 -- OpenTTD Mon, 01 Jun 2015 21:00:00 +0200 openttd (1.5.1~RC1-0) unstable; urgency=low * New upstream release 1.5.1-RC1 -- OpenTTD Fri, 08 May 2015 21:00:00 +0200 openttd (1.5.0-0) unstable; urgency=low * New upstream release 1.5.0 -- OpenTTD Wed, 01 Apr 2015 21:00:00 +0200 openttd (1.5.0~RC1-0) unstable; urgency=low * New upstream release 1.5.0-RC1 -- OpenTTD Wed, 18 Mar 2015 21:00:00 +0100 openttd (1.5.0~beta2-0) unstable; urgency=low * New upstream release 1.5.0-beta2 -- OpenTTD Tue, 24 Feb 2015 21:00:00 +0100 openttd (1.5.0~beta1-0) unstable; urgency=low * New upstream release 1.5.0-beta1 -- OpenTTD Wed, 24 Dec 2014 21:00:00 +0100 openttd (1.4.4-0) unstable; urgency=low * New upstream release 1.4.4 -- OpenTTD Tue, 21 Oct 2014 21:00:00 +0200 openttd (1.4.4~RC1-0) unstable; urgency=low * New upstream release 1.4.4-RC1 -- OpenTTD Wed, 08 Oct 2014 19:00:00 +0200 openttd (1.4.3-0) unstable; urgency=low * New upstream release 1.4.3 -- OpenTTD Tue, 23 Sep 2014 21:00:00 +0200 openttd (1.4.3~RC2-0) unstable; urgency=low * New upstream release 1.4.3-RC2 -- OpenTTD Sun, 14 Sep 2014 19:00:00 +0200 openttd (1.4.3~RC1-0) unstable; urgency=low * New upstream release 1.4.3-RC1 -- OpenTTD Sun, 07 Sep 2014 19:00:00 +0200 openttd (1.4.2-0) unstable; urgency=low * New upstream release 1.4.2 -- OpenTTD Sat, 16 Aug 2014 21:00:00 +0200 openttd (1.4.2~RC2-0) unstable; urgency=low * New upstream release 1.4.2-RC2 -- OpenTTD Sun, 03 Aug 2014 18:00:00 +0200 openttd (1.4.2~RC1-0) unstable; urgency=low * New upstream release 1.4.2-RC1 -- OpenTTD Thu, 03 Jul 2014 21:00:00 +0200 openttd (1.4.1-0) unstable; urgency=low * New upstream release 1.4.1 -- OpenTTD Mon, 02 Jun 2014 21:00:00 +0200 openttd (1.4.1~RC2-0) unstable; urgency=low * New upstream release 1.4.1-RC2 -- OpenTTD Sun, 18 May 2014 21:00:00 +0200 openttd (1.4.1~RC1-0) unstable; urgency=low * New upstream release 1.4.1-RC1 -- OpenTTD Sun, 04 May 2014 21:00:00 +0200 openttd (1.4.0-0) unstable; urgency=low * New upstream release 1.4.0 -- OpenTTD Tue, 01 Apr 2014 21:00:00 +0200 openttd (1.4.0~RC1-0) unstable; urgency=low * New upstream release 1.4.0-RC1 -- OpenTTD Tue, 17 Mar 2014 21:00:00 +0100 openttd (1.4.0~beta5-0) unstable; urgency=low * New upstream release 1.4.0-beta5 -- OpenTTD Tue, 25 Feb 2014 10:15:00 +0100 openttd (1.4.0~beta4-0) unstable; urgency=low * New upstream release 1.4.0-beta4 -- OpenTTD Thu, 06 Feb 2014 21:00:00 +0100 openttd (1.4.0~beta3-0) unstable; urgency=low * New upstream release 1.4.0-beta3 -- OpenTTD Tue, 21 Jan 2014 21:00:00 +0100 openttd (1.4.0~beta2-0) unstable; urgency=low * New upstream release 1.4.0-beta2 -- OpenTTD Tue, 07 Jan 2014 21:00:00 +0100 openttd (1.4.0~beta1-0) unstable; urgency=low * New upstream release 1.4.0-beta1 -- OpenTTD Tue, 24 Dec 2013 00:00:00 +0100 openttd (1.3.3-0) unstable; urgency=low * New upstream release 1.3.3 -- OpenTTD Fri, 29 Nov 2013 19:00:00 +0100 openttd (1.3.3~RC2-0) unstable; urgency=low * New upstream release 1.3.3-RC2 -- OpenTTD Sun, 24 Nov 2013 19:00:00 +0100 openttd (1.3.3~RC1-0) unstable; urgency=low * New upstream release 1.3.3-RC1 -- OpenTTD Sun, 17 Nov 2013 19:00:00 +0100 openttd (1.3.2-0) unstable; urgency=low * New upstream release 1.3.2 -- OpenTTD Sat, 27 Jul 2013 18:00:00 +0200 openttd (1.3.2~RC2-0) unstable; urgency=low * New upstream release 1.3.2-RC2 -- OpenTTD Sat, 13 Jul 2013 12:00:00 +0200 openttd (1.3.2~RC1-0) unstable; urgency=low * New upstream release 1.3.2-RC1 -- OpenTTD Sun, 30 Jun 2013 12:00:00 +0200 openttd (1.3.1-0) unstable; urgency=low * New upstream release 1.3.1 -- OpenTTD Sat, 01 Jun 2013 00:00:00 +0300 openttd (1.3.1~RC1-0) unstable; urgency=low * New upstream release 1.3.1-RC1 -- OpenTTD Fri, 17 May 2013 22:00:00 +0200 openttd (1.3.0-0) unstable; urgency=low * New upstream release 1.3.0 -- OpenTTD Mon, 01 Apr 2013 00:00:00 +0200 openttd (1.3.0~RC3) unstable; urgency=low * New upstream release 1.3.0-RC3 -- OpenTTD Mon, 18 Mar 2013 00:00:00 +0100 openttd (1.3.0~RC2) unstable; urgency=low * New upstream release 1.3.0-RC2 -- OpenTTD Tue, 05 Mar 2013 00:00:00 +0100 openttd (1.3.0~RC1) unstable; urgency=low * New upstream release 1.3.0-RC1 -- OpenTTD Tue, 19 Feb 2013 00:00:00 +0100 openttd (1.3.0~beta2) unstable; urgency=low * New upstream release 1.3.0-beta2 -- OpenTTD Thu, 07 Feb 2013 00:00:00 +0100 openttd (1.3.0~beta1) unstable; urgency=low * New upstream release 1.3.0-beta1 -- OpenTTD Mon, 24 Dec 2012 00:00:00 +0100 openttd (1.2.3) unstable; urgency=low * New upstream release 1.2.3 -- OpenTTD Thu, 01 Nov 2012 00:00:00 +0200 openttd (1.2.3~RC1) unstable; urgency=low * New upstream release 1.2.3-RC1 -- OpenTTD Wed, 17 Oct 2012 00:00:00 +0200 openttd (1.2.2) unstable; urgency=low * New upstream release 1.2.2 -- OpenTTD Thu, 16 Aug 2012 20:00:00 +0200 openttd (1.2.2~RC1) unstable; urgency=low * New upstream release 1.2.2-RC1 -- OpenTTD Wed, 01 Aug 2012 00:00:00 +0200 openttd (1.2.1) unstable; urgency=low * New upstream release 1.2.1 -- OpenTTD Fri, 01 Jun 2012 00:00:00 +0200 openttd (1.2.1~RC1) unstable; urgency=low * New upstream release 1.2.1-RC1 -- OpenTTD Wed, 16 Apr 2012 22:00:00 +0200 openttd (1.2.0) unstable; urgency=low * New upstream release 1.2.0 -- OpenTTD Sun, 15 Apr 2012 14:00:00 +0200 openttd (1.2.0~RC4) unstable; urgency=low * New upstream release 1.2.0-RC4 -- OpenTTD Sun, 01 Apr 2012 00:00:00 +0200 openttd (1.2.0~RC3) unstable; urgency=low * New upstream release 1.2.0-RC3 -- OpenTTD Sun, 18 Mar 2012 18:00:00 +0100 openttd (1.2.0~RC2) unstable; urgency=low * New upstream release 1.2.0-RC2 -- OpenTTD Sun, 04 Mar 2012 18:00:00 +0100 openttd (1.2.0~RC1) unstable; urgency=low * New upstream release 1.2.0-RC1 -- OpenTTD Sun, 19 Feb 2012 23:00:00 +0100 openttd (1.2.0~beta4) unstable; urgency=low * New upstream release 1.2.0-beta4 -- OpenTTD Sat, 04 Feb 2012 16:00:00 +0100 openttd (1.2.0~beta3) unstable; urgency=low * New upstream release 1.2.0-beta3 -- OpenTTD Sat, 21 Jan 2012 16:00:00 +0100 openttd (1.2.0~beta2) unstable; urgency=low * New upstream release 1.2.0-beta2 -- OpenTTD Sat, 07 Jan 2012 00:00:00 +0100 openttd (1.2.0~beta1) unstable; urgency=low * New upstream release 1.2.0-beta1 -- OpenTTD Sat, 24 Dec 2011 00:00:00 +0100 openttd (1.1.4) unstable; urgency=low * New upstream release 1.1.4 -- OpenTTD Mon, 05 Dec 2011 00:00:00 +0400 openttd (1.1.4-RC1) unstable; urgency=low * New upstream release 1.1.4-RC1 -- OpenTTD Sun, 20 Nov 2011 17:00:00 +0100 openttd (1.1.3) unstable; urgency=low * New upstream release 1.1.3 -- OpenTTD Thu, 15 Sep 2011 21:00:00 +0200 openttd (1.1.3-RC1) unstable; urgency=low * New upstream release 1.1.3-RC1 -- OpenTTD Sun, 04 Sep 2011 17:00:00 +0200 openttd (1.1.2) unstable; urgency=low * New upstream release 1.1.2 -- OpenTTD Sun, 14 Aug 2011 17:00:00 +0200 openttd (1.1.2~RC2) unstable; urgency=low * New upstream release 1.1.2-RC2 -- OpenTTD Sat, 30 Jul 2011 21:00:00 +0200 openttd (1.1.2~RC1) unstable; urgency=low * New upstream release 1.1.2-RC1 -- OpenTTD Sun, 24 Jul 2011 21:00:00 +0200 openttd (1.1.1) unstable; urgency=low * New upstream release 1.1.1 -- OpenTTD Wed, 01 Jun 2011 00:00:00 +0200 openttd (1.1.1~RC1) unstable; urgency=low * New upstream release 1.1.1-RC1 -- OpenTTD Sun, 15 May 2011 21:00:00 +0200 openttd (1.1.0) unstable; urgency=low * New upstream release 1.1.0 -- OpenTTD Fri, 01 Apr 2011 00:00:00 +0100 openttd (1.1.0~RC3) unstable; urgency=low * New upstream release 1.1.0-RC3 -- OpenTTD Fri, 18 Mar 2011 22:00:00 +0100 openttd (1.1.0~RC2) unstable; urgency=low * New upstream release 1.1.0-RC2 -- OpenTTD Fri, 04 Mar 2011 22:00:00 +0100 openttd (1.1.0~RC1) unstable; urgency=low * New upstream release 1.1.0-RC1 -- OpenTTD Fri, 18 Feb 2011 22:00:00 +0100 openttd (1.1.0~beta5) unstable; urgency=low * New upstream release 1.1.0-beta5 -- OpenTTD Fri, 04 Feb 2011 22:00:00 +0100 openttd (1.1.0~beta4) unstable; urgency=low * New upstream release 1.1.0-beta4 -- OpenTTD Fri, 21 Jan 2011 00:00:00 +0100 openttd (1.1.0~beta3) unstable; urgency=low * New upstream release 1.1.0-beta3 -- OpenTTD Sun, 09 Jan 2011 18:00:00 +0100 openttd (1.1.0~beta2) unstable; urgency=low * New upstream release 1.1.0-beta2 -- OpenTTD Fri, 31 Dec 2010 18:00:00 +0100 openttd (1.1.0~beta1) unstable; urgency=low * New upstream release 1.1.0-beta1 -- OpenTTD Fri, 24 Dec 2010 00:00:00 +0100 openttd (1.0.5-0) unstable; urgency=low * New upstream release 1.0.5 -- OpenTTD Sat, 20 Nov 2010 21:00:00 +0000 openttd (1.0.5~rc2-0) unstable; urgency=low * New upstream release 1.0.5~rc2 -- OpenTTD Sun, 14 Nov 2010 15:00:00 +0000 openttd (1.0.5~rc1-0) unstable; urgency=low * New upstream release 1.0.5-RC1 -- OpenTTD Sun, 31 Oct 2010 15:00:00 +0000 openttd (1.0.4-0) unstable; urgency=low * New upstream release 1.0.4 -- OpenTTD Tue, 14 Sep 2010 20:00:00 +0000 openttd (1.0.4~rc1-0) unstable; urgency=low * New upstream release 1.0.4-RC1 -- OpenTTD Mon, 30 Aug 2010 20:00:00 +0000 openttd (1.0.3-0) unstable; urgency=low * New upstream release 1.0.3 -- OpenTTD Sun, 01 Aug 2010 00:00:00 +0000 openttd (1.0.3~rc1-0) unstable; urgency=low * New upstream release 1.0.3-RC1 -- OpenTTD Sat, 05 Jul 2010 17:37:21 +0000 openttd (1.0.2-0) unstable; urgency=low * New upstream release 1.0.2 -- OpenTTD Sat, 19 Jun 2010 18:36:21 +0000 openttd (1.0.2~rc1-0) unstable; urgency=low * New upstream release 1.0.2-RC1 -- OpenTTD Sat, 05 Jun 2010 23:36:21 +0000 openttd (1.0.1-0) unstable; urgency=low * New upstream release 1.0.1 -- OpenTTD Sat, 01 May 2010 00:00:00 +0200 openttd (1.0.1~rc2-0) unstable; urgency=low * New upstream release 1.0.1-RC2 -- OpenTTD Wed, 21 Apr 2010 21:36:21 +0200 openttd (1.0.1~rc1-0) unstable; urgency=low * New upstream release 1.0.1-RC1 -- OpenTTD Sat, 17 Apr 2010 23:36:21 +0000 openttd (1.0.0-1) unstable; urgency=low * [30a2162] New upstream release 1.0.0. (Closes: #570104) * [102698a] Make openttd-wrapper work with older mktemp versions. -- Matthijs Kooijman Fri, 02 Apr 2010 23:36:21 +0200 openttd (1.0.0~rc3-2) unstable; urgency=low * [279c5ef] Recommend openttd-opengfx and suggest openttd-opensfx. * [9330ad7] Update README.Debian concerning music files. * [07bde24] Move openttd from contrib to main. (Closes: #560810) -- Matthijs Kooijman Thu, 18 Mar 2010 13:16:32 +0100 openttd (1.0.0~rc3-1) unstable; urgency=low * [412d153] New upstream release 1.0.0~rc3. -- Matthijs Kooijman Thu, 18 Mar 2010 10:09:33 +0100 openttd (1.0.0~rc2-1) unstable; urgency=low * [9c99af4] New upstream release 1.0.0~rc2. -- Matthijs Kooijman Thu, 04 Mar 2010 12:22:28 +0100 openttd (1.0.0~rc1-1) unstable; urgency=low * [fe4eb51] New upstream release 1.0.0~rc1. * [6aa2be0] Note that the embedded md5 implementation has a different license. * [39eb336] Remove lintian override for empty gm directory. -- Matthijs Kooijman Fri, 19 Feb 2010 13:00:53 +0100 openttd (1.0.0~beta4-1) unstable; urgency=low * [6718224] New upstream release 1.0.0~beta4. * [7b0fa8d] Remove some more docs that we don't want in the package. * [bb9d744] Use liblzo2 instead of an embedded minilzo version. * [949c06b] Explicitly disable iconv support. -- Matthijs Kooijman Fri, 19 Feb 2010 12:59:27 +0100 openttd (0.7.5-4) unstable; urgency=low * [174d0b1] Don't use deprecated < in Replaces. -- Matthijs Kooijman Mon, 15 Feb 2010 00:35:33 +0100 openttd (0.7.5-3) unstable; urgency=low * [d12fc5a] Make openttd-data replace openttd (< 0.7.5-2). (Closes: #569679) -- Matthijs Kooijman Sun, 14 Feb 2010 16:56:31 +0100 openttd (0.7.5-2) unstable; urgency=low [ Matthijs Kooijman ] * [fbab21d] Switch to source format 3.0 (quilt). * [85c0c7d] No longer check for (and complain about missing) datafiles on installation and upgrades. (Closes: #524651, 562574) * [827eb61] Split the architecture independent data into openttd-data. (Closes: #492462) * [6fbd9c7] Update README.Debian. * [76a5148] Support cross compilation. (Closes: #550951) * [2005bf8] Simplify the rules file, make debhelper do more stuff. * [fc0500e] Remove some configure arguments. * [8ca38bb] Explicitly enable or disable all of the dependencies. * [e38fb3e] Let the upstream Makefile install documentation. * [5954fcf] Update the watch file to the new upstream url scheme. * [7249594] Fix typo in copyright file. * [660fb61] Bump the Standards-Version to 3.8.4, with no changes required. * [f94ab89] Move the packaging git repository to git.debian.org. -- Jordi Mallach Tue, 09 Feb 2010 21:40:24 +0100 openttd (0.7.5-1) unstable; urgency=high * [cdcb73a] Imported Upstream version 0.7.5. This release fixes CVE-2009-4007. -- Matthijs Kooijman Thu, 24 Dec 2009 00:55:45 +0100 openttd (0.7.4-1) unstable; urgency=low * [a2c297b0] Imported Upstream version 0.7.4 * [0232a645] Make Debian-specific patches executable. * [76be04b] Switch the Debian packaging to git. -- Matthijs Kooijman Tue, 15 Dec 2009 22:11:52 +0100 openttd (0.7.3-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release * Use printf instead of echo -en in openttd-wrapper to make it POSIX compatible (Closes: #547758). * Remove three patches that are now included in upstream. -- Matthijs Kooijman Thu, 01 Oct 2009 22:52:59 +0200 openttd (0.7.2-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release * Bump Standards-Version to 3.8.3, with no changes required. * Clean up the rules file a bit and add some lintian overrides. * Explain why openttd is in contrib (Closes: #539381). * Add the DM-Upload-Allowed control field. * Re-add dpatch infrastructure. * Fix the copyright file, since upstream only allows GPLv2, not later versions. * Add a section to the copyright file on the different license used by the "Squirrel" programming language, which is shipped with OpenTTD since 0.7.0. * Backport upstream r17226, which removes the deprecated Encoding entry from the .desktop file. * Add a wrapper script for openttd, which captures any stderr output and displays it when openttd returns an error code (Closes: #533557). * Recommend x11-utils, since we use xmessage for displaying errors. Don't depend on it, since openttd will still run fine without it, you just won't see any errors. * Backport upstream r17227 and r17229, which prevents terminal escape codes from ending up in the captured error output. * Backport upstream r17240, which improves stderr output when files are missing or corrupt. -- Jordi Mallach Fri, 21 Aug 2009 15:27:26 +0200 openttd (0.7.1-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release. * Link against libicu to enable right-to-left language support. -- Jordi Mallach Tue, 09 Jun 2009 21:46:28 +0200 openttd (0.7.0-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release. * Remove Debian specific desktop file, upstream provides one now. * Add debian/watch file. [ Jordi Mallach ] * Bump Standards-Version to 3.8.1, with no changes required. * Move to debhelper compat 7. Bump Build-Depends accordingly. * Use dh_prep. * Add "set -e" to config script. * Remove a few extra doc files that get installed by upstream Makefile. * Add more complete copyright information. -- Jordi Mallach Wed, 15 Apr 2009 18:22:10 +0200 openttd (0.6.3-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release. [ Jordi Mallach ] * Add Spanish Debconf template translation, after fixing its corrupted encoding (thanks, Germana Oliveira, closes: #499214). -- Jordi Mallach Thu, 02 Oct 2008 16:59:03 +0200 openttd (0.6.2-1) unstable; urgency=low * New upstream release. - Fixes remote crash vulnerability CVE-2008-3547. Closes: #493714 -- Matthijs Kooijman Fri, 08 Aug 2008 11:07:05 +0200 openttd (0.6.2~rc2-1) experimental; urgency=low [ Matthijs Kooijman ] * New upstream release. [ Jordi Mallach ] * Fix typo in README.Debian (lintian). * Remove dpatch build-dep and the empty debian/patches dir. * Don't ignore possible "make distclean" errors. -- Jordi Mallach Sat, 26 Jul 2008 01:35:30 +0200 openttd (0.6.2~rc1-1) experimental; urgency=low [ Matthijs Kooijman ] * New upstream release. -- Jordi Mallach Thu, 24 Jul 2008 16:09:57 +0200 openttd (0.6.1-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release. * Remove no_install_personal.dpatch, it is included upstream now. -- Jordi Mallach Thu, 05 Jun 2008 00:47:36 +0200 openttd (0.6.0-2) unstable; urgency=low [ Jordi Mallach ] * Rename XS-Vcs-* to the official Vcs-* fields. [ Matthijs Kooijman ] * Don't install anything into ~ during make install, this prevented successful builds on some architectures. Fix imported from upstream. * Put the homepage in its own Homepage field instead of in the description. * Bump Standards-Version to 3.7.3 -- Jordi Mallach Thu, 03 Apr 2008 00:07:10 +0200 openttd (0.6.0-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release: - Adds note about font-configuration for non-latin languages. Closes: #462604 * Add .desktop file, provided by Andrea Colangelo. Closes: #460073 * Add Finnish Debconf translation, provided by Esko Arajärvi. Closes: #456956 [ Jordi Mallach ] * Fixes and improvements for the .desktop file according to the spec. -- Jordi Mallach Wed, 02 Apr 2008 14:04:40 +0200 openttd (0.5.3-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release -- Jordi Mallach Tue, 18 Sep 2007 12:05:28 +0200 openttd (0.5.2-1) unstable; urgency=low [ Jordi Mallach ] * New upstream release. * Debconf translation updates: - Catalan. [ Christian Perrier ] * Debconf templates and debian/control reviewed by the debian-l10n- english team as part of the Smith review project. Closes: #422183, #419096. * Debconf translation updates: - Swedish. Closes: #422780 - Basque. Closes: #422786 - Czech. Closes: #422809 - Galician. Closes: #422831 - German. Closes: #422908 - Tamil. Closes: #423079 - Russian. Closes: #423224 - Portuguese. Closes: #423413 - French. Closes: #424436 - Brazilian Portuguese. Closes: #425585 - Dutch. Closes: #425707 -- Jordi Mallach Sat, 02 Jun 2007 06:24:34 +0200 openttd (0.5.1-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release * Add German and Swedish translations (Closes: #420258, #419097) * Remove bogus fuzzy mark from the Catalan translation [ Jordi Mallach ] * debian/control: add XS-Vcs-Svn and XS-Vcs-Browser fields. -- Jordi Mallach Mon, 23 Apr 2007 21:03:06 +0200 openttd (0.5.0-2) unstable; urgency=low * Upload to Debian. -- Jordi Mallach Sun, 11 Mar 2007 14:12:37 +0100 openttd (0.5.0-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release [ Jordi Mallach ] * Depend on ${misc:Depends}, not debconf directly. -- Jordi Mallach Thu, 8 Mar 2007 15:34:54 +0100 openttd (0.5.0~rc5-1) unstable; urgency=low [ Matthijs Kooijman ] * New upstream release * Compile with freetype and fontconfig support. [ Jordi Mallach ] * Convert debconf templates to podebconf. * Add a Catalan translation. * Minor packaging cleanups. -- Matthijs Kooijman Mon, 12 Feb 2007 09:25:41 +0100 openttd (0.5.0~rc4-1) unstable; urgency=low * New upstream release -- Matthijs Kooijman Thu, 18 Jan 2007 21:17:28 +0100 openttd (0.5.0~rc3-1) unstable; urgency=low * New upstream release -- Matthijs Kooijman Thu, 18 Jan 2007 20:21:04 +0100 openttd (0.5.0~rc2-1) unstable; urgency=low * New upstream release * Removed fix for empty scenarios dir, openttd Makefile now properly handles this. -- Matthijs Kooijman Sun, 31 Dec 2006 12:24:37 +0100 openttd (0.5.0~rc1-1) unstable; urgency=low * New upstream release. -- Matthijs Kooijman Fri, 22 Dec 2006 11:03:46 +0100 openttd (0.4.8-1) unstable; urgency=low * New upstream release * Bump standards version to 3.7.2 -- Matthijs Kooijman Mon, 14 Aug 2006 16:28:50 +0200 openttd (0.4.7-1) unstable; urgency=low * New upstream release. -- Matthijs Kooijman Mon, 27 Mar 2006 23:40:00 +0200 openttd (0.4.6-1) unstable; urgency=low * New upstream release. * Remove old terminal messages and make sure that debconf is always called. -- Matthijs Kooijman Wed, 8 Mar 2006 23:57:35 +0100 openttd (0.4.5-1) unstable; urgency=low * New upstream release * Bump Standards-Version to 3.6.2 * s/timdity/timidity/ in README.Debian. * Use debconf for prompting instead of terminal. * Fix makefile to create icon dir if necessary. * Fix syntax error in manpage. -- Matthijs Kooijman Wed, 1 Feb 2006 01:56:39 +0100 openttd (0.4.0.1-5) unstable; urgency=low * Fixed capitalization of menu item. * Install xpm icon to /usr/share/pixmaps and don't install png icon, since it is not used. -- Matthijs Kooijman Thu, 22 Sep 2005 10:35:09 +0200 openttd (0.4.0.1-4) unstable; urgency=low * Changelog was distributed twice. * Put openttd in contrib. -- Matthijs Kooijman Mon, 19 Sep 2005 23:49:18 +0200 openttd (0.4.0.1-3) unstable; urgency=low * Clarified installing instructions in README.Debian -- Matthijs Kooijman Thu, 16 Jun 2005 03:51:13 +0200 openttd (0.4.0.1-2) unstable; urgency=low * Added Suggests: timidity, freepats -- Matthijs Kooijman Thu, 16 Jun 2005 03:34:03 +0200 openttd (0.4.0.1-1) unstable; urgency=low * New upstream release -- Matthijs Kooijman Mon, 23 May 2005 13:04:24 +0200 openttd (0.4.0-1) unstable; urgency=low * New upstream release -- Matthijs Kooijman Mon, 16 May 2005 00:16:17 +0200 openttd (0.3.6-1) unstable; urgency=low * New upstream release * Modifed Makefile to install xpm icon and scenarios in /usr/share/games/openttd/ * Added openttd.32.xpm, openttd.64.xpm was too big -- Matthijs Kooijman Tue, 25 Jan 2005 19:21:08 +0100 openttd (0.3.5-2) unstable; urgency=low * Fixed some lintian warnings. * Added openttd.64.xpm (icon for menu). -- Matthijs Kooijman Mon, 27 Dec 2004 01:51:36 +0100 openttd (0.3.5-1) unstable; urgency=low * Initial Release. -- Matthijs Kooijman Fri, 24 Dec 2004 02:58:47 +0100 openttd-1.5.3/os/debian/copyright0000644000000000000000000001075112627373447015514 0ustar rootrootFormat: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: OpenTTD Upstream-Contact: info@openttd.org, #openttd on irc.oftc.net Source: http://www.openttd.org Files: * Copyright: © 2004-2012 Ludvig Strigeous and others. License: GPL-2.0 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2.0 as published by the Free Software Foundation; . This program 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 this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA . On Debian systems, the complete text of the GNU General Public License version 2 can be found in `/usr/share/common-licenses/GPL-2'. Files: src/3rdparty/squirrel/* Copyright: © 2003-2009 Alberto Demichelis License: Zlib Files: src/3rdparty/md5/* Copyright: © 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. License: Zlib License: Zlib This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. . Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: . 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. . 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. . 3. This notice may not be removed or altered from any source distribution. Files: os/dos/exe2coff/* Copyright: © 1998 DJ Delorie License: GPL-2.0 with additional restrictions This document is Copyright (C) DJ Delorie and may be distributed verbatim, but changing it is not allowed. . Source code copyright DJ Delorie is distributed under the terms of the GNU General Public Licence, with the following exceptions: . * Sources used to build crt0.o, gcrt0.o, libc.a, libdbg.a, and libemu.a are distributed under the terms of the GNU Library General Public License, rather than the GNU GPL. . * Any existing copyright or authorship information in any given source file must remain intact. If you modify a source file, a notice to that effect must be added to the authorship information in the source file. . * Runtime binaries, as provided by DJ in DJGPP, may be distributed without sources ONLY if the recipient is given sufficient information to obtain a copy of djgpp themselves. This primarily applies to go32-v2.exe, emu387.dxe, and stubedit.exe. . * Runtime objects and libraries, as provided by DJ in DJGPP, when linked into an application, may be distributed without sources ONLY if the recipient is given sufficient information to obtain a copy of djgpp themselves. This primarily applies to crt0.o and libc.a. . On Debian systems, the complete text of the GNU General Public License version 2 can be found in `/usr/share/common-licenses/GPL-2'. Comment: Given only the exe2coff.c file is distributed in the source distribution (and nothing in Debian binary distribution), it seems only the 2nd condition applies. Files: os/dos/cwsdpmi/* Source: http://homer.rice.edu/~sandmann/cwsdpmi/index.html Copyright: © 1995-2000 Charles W Sandmann (sandmann@clio.rice.edu) License: Custom binary-only license This is release 5. The files in this binary distribution may be redistributed under the GPL (with source) or without the source code provided: . * CWSDPMI.EXE or CWSDPR0.EXE are not modified in any way except via CWSPARAM. . * CWSDSTUB.EXE internal contents are not modified in any way except via CWSPARAM or STUBEDIT. It may have a COFF image plus data appended to it. . * Notice to users that they have the right to receive the source code and/or binary updates for CWSDPMI. Distributors should indicate a site for the source in their documentation. Comment: Files are distributed as binary only, so the second option in the license ("without source code provided: ...") is applicable. openttd-1.5.3/os/debian/control0000644000000000000000000000301612627373447015160 0ustar rootrootSource: openttd Section: games Priority: optional Maintainer: Matthijs Kooijman Uploaders: Jordi Mallach Build-Depends: debhelper (>= 7.0.50), libsdl-dev, zlib1g-dev, libpng-dev, libfreetype6-dev, libfontconfig-dev, libicu-dev, liblzma-dev, liblzo2-dev Standards-Version: 3.8.4 Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/openttd.git Vcs-Git: git://anonscm.debian.org/collab-maint/openttd.git Homepage: http://www.openttd.org/ Package: openttd Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: openttd-opengfx, x11-utils Replaces: openttd-data Conflicts: openttd-data Suggests: openttd-opensfx, timidity, freepats Description: reimplementation of Transport Tycoon Deluxe with enhancements OpenTTD is a reimplementation of the Microprose game "Transport Tycoon Deluxe" with lots of new features and enhancements. . OpenTTD is playable with the free graphics files from the openttd-opengfx package and optional sound files from the openttd-opensfx package (which is in non-free). Alternatively, OpenTTD can use the graphics files from the original Transport Tycoon Deluxe game (See README.Debian on how to set this up). Package: openttd-dbg Architecture: any Section: debug Priority: extra Depends: openttd (= ${binary:Version}), ${misc:Depends} Description: debugging symbols for openttd This package contains the debugging symbols for OpenTTD, the reimplementation of the Micropose game "Transport Tycoon Deluxe" with lots of new features and enhancements. openttd-1.5.3/os/debian/compat0000644000000000000000000000000212627373447014753 0ustar rootroot7 openttd-1.5.3/os/debian/openttd-wrapper0000644000000000000000000000153712627373447016641 0ustar rootroot#!/bin/sh # This is a wrapper script that checks openttd's exit status and # displays its stderr output # Get a file to capture stderr to. Use the deprecated -t option, so this # works on the old mktemp from the mktemp package (which has been # replaced by the version from the coreutils package). TMPFILE=`mktemp -t openttd.errout.XXXXXXXXX` if [ ! -w "$TMPFILE" ]; then xmessage "Could not create temporary file for error messages. Not starting OpenTTD." exit 1; fi # Capture stderr openttd "$@" 2> "$TMPFILE" ERRCODE=$? if [ "$ERRCODE" -ne 0 ]; then CODEMSG="OpenTTD returned with error code $ERRCODE." if [ -s "$TMPFILE" ]; then MESSAGE="$CODEMSG The following error messages were produced:\n\n" printf "$MESSAGE" | cat - "$TMPFILE" | fold -s | xmessage -file - else xmessage "$CODEMSG No error messages were produced." fi fi rm -f "$TMPFILE" openttd-1.5.3/os/debian/source/0000755000000000000000000000000012627373447015055 5ustar rootrootopenttd-1.5.3/os/debian/source/format0000644000000000000000000000001412627373447016263 0ustar rootroot3.0 (quilt) openttd-1.5.3/os/debian/rules0000755000000000000000000000424112627373447014636 0ustar rootroot#!/usr/bin/make -f # -*- makefile -*- # Makefile to build the openttd debian package. # Use debhelper default for all targets (but some are overridden below). %: dh --parallel $@ DEB_HOST_GNU_TYPE=$(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE=$(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) CROSS= --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE) endif # This prevents linking uselessly to libicudata and silences a warning # in the build process. DEB_LDFLAGS_MAINT_APPEND="-Wl,-as-needed" # Enable all hardening options (since openttd offers a network-listening # service that handles untrusted data). DEB_BUILD_MAINT_OPTIONS=hardening=+all # Load buildflags (this uses dpkg-buildflags). Note that we don't export # them, but instead pass them to ./configure explicitly. include /usr/share/dpkg/buildflags.mk # Pass custom options to configure. Since it's not autoconf but a custom # script, some of the option names are slightly different. We also need # to be explicit about the dependencies, in case we're not running in a # clean build root. override_dh_auto_configure: ./configure $(CROSS) --prefix-dir=/usr --install-dir=debian/openttd --without-allegro --with-zlib --with-sdl --with-png --with-freetype --with-fontconfig --with-icu --with-liblzo2 --with-lzma --without-xdg-basedir --without-iconv --disable-strip CFLAGS="$(CFLAGS) $(CPPFLAGS)" CXXFLAGS="$(CXXFLAGS) $(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" CFLAGS_BUILD="$(CFLAGS) $(CPPFLAGS)" CXXFLAGS_BUILD="$(CXXFLAGS) $(CPPFLAGS)" LDFLAGS_BUILD="$(LDFLAGS)" # Do some extra installation override_dh_auto_install: $(MAKE) install DO_NOT_INSTALL_CHANGELOG=1 DO_NOT_INSTALL_LICENSE=1 # Don't do testing. Because the OpenTTD Makefile always does dependency # generation (even on invalid targets), dh_auto_test thinks there is a # "test" target, while there isn't. override_dh_auto_test: # Call mrproper. Again, dh_auto_clean thinks there is a distclean # target, while there isn't. override_dh_auto_clean: [ ! -f Makefile ] || $(MAKE) mrproper # We want to strip the debug informatiton into the -dbg package. override_dh_strip: dh_strip --dbg-package=openttd-dbg openttd-1.5.3/os/os2/0000755000000000000000000000000012627373447013036 5ustar rootrootopenttd-1.5.3/os/os2/dedicated.cmd0000644000000000000000000000007012627373447015426 0ustar rootrootstart /n /win openttd.exe -D %1 %2 %3 %4 %5 %6 %7 %8 %9 openttd-1.5.3/os/os2/openttd.wpj0000644000000000000000000000054512627373447015241 0ustar rootroot40 projectIdent 0 VpeMain 1 WRect 0 0 10304 10020 2 MProject 3 MCommand 15 svn_version.cmd 4 MCommand 0 2 5 WFileName 17 ..\..\openttd.tgt 6 WFileName 23 ..\..\strgen\strgen.tgt 7 WVList 2 8 VComponent 9 WRect 0 0 5696 4240 0 0 10 WFileName 17 ..\..\openttd.tgt 0 0 11 VComponent 12 WRect 688 680 5696 4240 0 0 13 WFileName 23 ..\..\strgen\strgen.tgt 0 1 8 openttd-1.5.3/os/os2/svn_version.cmd0000644000000000000000000000137612627373447016105 0ustar rootroot@echo off echo Running SVN version detection script... rem rem Requires subversion (`svnversion') to be installed rem cd ..\.. if not "%RELEASE%"=="" goto forcerelease if not exist .svn goto nosvn svnversion -n . > os\os2\svnver.tmp if not "%ERRORLEVEL%"=="0" goto nosvn copy os\os2\svnver1.c+os\os2\svnver.tmp+os\os2\svnver2.c rev.c /a /y > nul 2> nul goto end :forcerelease echo Forcing release string "%RELEASE%"... echo const char _openttd_revision[] = "%RELEASE%"; > rev.c echo const int _revision_number = 0; >> rev.c goto end :nosvn echo Error executing `svnversion' or no SVN data detected echo const char _openttd_revision[] = "norev000"; > rev.c echo const int _revision_number = 0; >> rev.c goto end :end cd os\os2 del svnver.tmp > nul 2> nul rem end openttd-1.5.3/os/os2/svnver2.c0000644000000000000000000000014512627373447014607 0ustar rootroot"; const int _revision_number = 0; /* rev.c part 2 for OS/2 - ensure no newline at start of file! */openttd-1.5.3/os/os2/svnver1.c0000644000000000000000000000014512627373447014606 0ustar rootroot/* rev.c part #1 for OS/2 - ensure no newline at end of file! */ const char _openttd_revision[] = "ropenttd-1.5.3/os/os2/build_lang.cmd0000644000000000000000000000016312627373447015623 0ustar rootrootrem rem Building language files... rem cd .. strgen\strgen for %%f in (lang\*.txt) do strgen\strgen %%f cd strgen openttd-1.5.3/os/os2/installer/0000755000000000000000000000000012627373447015033 5ustar rootrootopenttd-1.5.3/os/os2/installer/download_nosound.cmd0000644000000000000000000000074512627373447021102 0ustar rootroot@echo off if "%1" == "" goto err if "%2" == "" goto err echo Downloading NoSound... %1\wget http://binaries.openttd.org/installer/nosound-NOSOUND_VERSION.7z -O %2/baseset/nosound.7z echo Extracting NoSound... %1\7za x -y -O%2/baseset %2/baseset/nosound.7z del %1\baseset\nosound.7z /n echo NoSound has been installed. goto end :err echo This batch file is only intended for use by the OpenTTD installer. echo Please visit www.openttd.org for details on downloading NoSound. :endopenttd-1.5.3/os/os2/installer/download_opengfx.cmd0000644000000000000000000000074612627373447021064 0ustar rootroot@echo off if "%1" == "" goto err if "%2" == "" goto err echo Downloading OpenGFX... %1\wget http://binaries.openttd.org/installer/opengfx-OPENGFX_VERSION.7z -O %2/baseset/opengfx.7z echo Extracting OpenGFX... %1\7za x -y -O%2/baseset %2/baseset/opengfx.7z del %1\baseset\opengfx.7z /n echo OpenGFX has been installed. goto end :err echo This batch file is only intended for use by the OpenTTD installer. echo Please visit www.openttd.org for details on downloading OpenGFX. :end openttd-1.5.3/os/os2/installer/remove_opengfx.cmd0000644000000000000000000000036012627373447020542 0ustar rootroot@echo off if "%1" == "" goto err echo Removing OpenGFX... del %1\baseset\opengfx\*.* /n rmdir %1\baseset\opengfx echo OpenGFX has been removed. goto end :err echo This batch file is only intended for use by the OpenTTD installer. :end openttd-1.5.3/os/os2/installer/remove_opensfx.cmd0000644000000000000000000000036012627373447020556 0ustar rootroot@echo off if "%1" == "" goto err echo Removing OpenSFX... del %1\baseset\opensfx\*.* /n rmdir %1\baseset\opensfx echo OpenSFX has been removed. goto end :err echo This batch file is only intended for use by the OpenTTD installer. :end openttd-1.5.3/os/os2/installer/make_installer.cmd0000644000000000000000000000372512627373447020521 0ustar rootroot@echo off set OPENTTD_VERSION=1.5.0 set OPENSFX_VERSION=0.8.0 set NOSOUND_VERSION=0.8.0 set OPENGFX_VERSION=1.2.0 echo To make the installer, you must have the WarpIN compiler (wic) installed and in echo your path, as well as wget and unzip. This file will download the various DLLs echo to be distributed with the installer. If you do not want to continue, please echo press CTRL-C now. echo. pause cd ..\..\..\bundle if not exist SDL12.dll goto getsdl if not exist FSLib.dll goto getsdl goto libc :getsdl wget http://www.os2site.com/sw/dev/sdl/sdl-1.2.10-bin-20080804.zip -O dl.zip unzip -j dl.zip SDL/FSLib.dll SDL/SDL12.dll del dl.zip :libc if exist libc063.dll goto gcc wget ftp://ftp.netlabs.org/pub/gcc/libc-0.6.3-csd3.zip -O dl.zip unzip -j dl.zip libc063.dll del dl.zip :gcc if exist gcc442.dll goto tools wget http://www.owenrudge.net/various/gcc442.zip -O dl.zip unzip -j dl.zip gcc442.dll del dl.zip :tools cd ..\os\os2\installer if exist tools goto opengfx mkdir tools cd tools wget http://download.smedley.info/wget-1.11.4-os2-20090315.zip -O dl.zip unzip -j dl.zip wget/bin/wget.exe del dl.zip wget ftp://ftp.os4.su/moveton/p7zip-9.04-bin-os2.zip -O dl.zip unzip -j dl.zip bin/7za.exe dll/ilibca.dll del dl.zip cd .. :opengfx if exist opengfx goto opensfx mkdir opengfx sed s/OPENGFX_VERSION/%OPENGFX_VERSION%/ < download_opengfx.cmd > opengfx\download_opengfx.cmd copy remove_opengfx.cmd opengfx :opensfx if exist opensfx goto nosound mkdir opensfx sed s/OPENSFX_VERSION/%OPENSFX_VERSION%/ < download_opensfx.cmd > opensfx\download_opensfx.cmd copy remove_opensfx.cmd opensfx :nosound mkdir nosound sed s/NOSOUND_VERSION/%NOSOUND_VERSION%/ < download_nosound.cmd > nosound\download_nosound.cmd copy remove_nosound.cmd nosound :end if exist openttd-%OPENTTD_VERSION%-os2.exe del openttd-%OPENTTD_VERSION%-os2.exe wic -a openttd-%OPENTTD_VERSION%-os2.exe 1 -c../../../bundle -r * 2 -ctools -r * 3 -copengfx -r * 4 -copensfx -r * 5 -cnosound -r * -U -s openttd.wis openttd-1.5.3/os/os2/installer/remove_nosound.cmd0000644000000000000000000000036012627373447020561 0ustar rootroot@echo off if "%1" == "" goto err echo Removing NoSound... del %1\baseset\nosound\*.* /n rmdir %1\baseset\nosound echo NoSound has been removed. goto end :err echo This batch file is only intended for use by the OpenTTD installer. :end openttd-1.5.3/os/os2/installer/download_opensfx.cmd0000644000000000000000000000074612627373447021100 0ustar rootroot@echo off if "%1" == "" goto err if "%2" == "" goto err echo Downloading OpenSFX... %1\wget http://binaries.openttd.org/installer/opensfx-OPENSFX_VERSION.7z -O %2/baseset/opensfx.7z echo Extracting OpenSFX... %1\7za x -y -O%2/baseset %2/baseset/opensfx.7z del %1\baseset\opensfx.7z /n echo OpenSFX has been installed. goto end :err echo This batch file is only intended for use by the OpenTTD installer. echo Please visit www.openttd.org for details on downloading OpenSFX. :end openttd-1.5.3/os/os2/installer/openttd.wis0000644000000000000000000000660412627373447017242 0ustar rootroot OpenTTD OpenTTD is an open source transport simulation game Tools required for downloading the OpenGFX/SFX packs Downloads the OpenGFX graphics pack for OpenTTD Downloads the OpenSFX sound effects pack for OpenTTD Downloads the NoSound pack for OpenTTD, to disable sound effects ~Next README.TXT Welcome to the OpenTTD installer. This program will install OpenTTD 1.0 on your system. Before we begin the installation process, please take a moment to read the following document. Select "Next" to continue, or "Cancel" to abort installation. ~Next COPYING OpenTTD is licenced under the GNU General Public License. The text of the licence is below. Select "Next" if you agree to this licence. Select "Cancel" to abort installation. ~Next On this page, you may choose which components to install. If you don't own Transport Tycoon Deluxe, you will need to download OpenGFX (3MiB) and OpenSFX (10MiB). I~nstall Press "Install" to begin installing OpenTTD. openttd-1.5.3/os/dos/0000755000000000000000000000000012627373447013120 5ustar rootrootopenttd-1.5.3/os/dos/make_dos_binary_selfcontained.sh0000755000000000000000000000050012627373447021476 0ustar rootroot#!/bin/sh # $Id: make_dos_binary_selfcontained.sh 25780 2013-09-19 07:42:13Z matthijs $ cd `dirname $0` cc -o exe2coff/exe2coff exe2coff/exe2coff.c || exit cp $1 binary.exe || exit ./exe2coff/exe2coff binary.exe || exit cat cwsdpmi/cwsdstub.exe binary > binary.exe || exit mv binary.exe $1 rm binary exe2coff/exe2coff openttd-1.5.3/os/dos/cwsdpmi/0000755000000000000000000000000012627373447014566 5ustar rootrootopenttd-1.5.3/os/dos/cwsdpmi/cwsdpmi.exe0000644000000000000000000004723512627373447016752 0ustar rootrootMZ( U>0jr :_A3 w FTh!!!!!!#N*P+j++ CWSDPMI r5 Copyright (C) 2000 CW Sandmann (sandmann@clio.rice.edu). .ڌ+><G;r:;wXҋPډ<+30! <øL!A3ɴU^KK9r]UVx9u;r+ uʁ;w! t̀+9u]U5F!“]U%FV!]UW~FN_]UF UVW^v~ N _^]UVWv~_^]3ËRPfZffRXZUb!]U^P!]UVvVt fFf fFFfFf$DF DfF fDfF fDFDD^]UVvfhV DLFD DTDPDD8DD`x^]VWFF,^&6$$$$>tm~F~FF^GFFN u=tf7a3 u ƇF|j`h$j6\ W !XFBTtV&X>u f>$Qiuf&6Nj/DI!FL!_^UVvV$0<9v'NI u^]VWFFF< u%+FPvjjhPjFv<%+FPvjFF +FPvj_^UVgr3Gg؋` uGgPhSVh^gu fwhha>thlYw$fw huxfwDfw@fw0fw,fw4fw(hSwlwPw\wXwHwTwLfw8fw s h  YjYTt &>u h$YFF^&FF^^&3^&?-FƋ^& FhY~pui~xuT\~uu9Q~suKF+PYFFF ^&F~ t~ t^FF~uڀ=-uWYF;v^@>A8& tlA uPAhjYjYjhh&RPfhh&jhha&RPfhh.jhhA&RPfhhjhfffPfhh6jhfffPfhh>hjhfjfjhVTjhfhfhh^:jhfffPfhhFjhfffPfhhNjhh#s%RPfhhjhh$S%RPfhh~jhh;3%RPfhhj/Y&P&NhhZj/TtV&X&&,I!jYjYjYj Y>!+и1!_^VWF$>F6~Ft uO~ tF fh`6h$R jKYFjBYFj9YFj0YF 2hVYj!Y"h>+h#h>+h$h>+h%h>+h~&hXj8h$j v &X$%F$>$F$$3$$jhf$ffPfhFPF $vhf$ffPfhFPf$2b!^FFF,^&F &jhfFffPfhFPcF $jhfffPfhFP0$;$t3j YFvhf$ffPfhFPFFF $F $hhj#/hhj$!_^UfFfЊN~t &]& ]UfFf&N"]UF]Uf3fff>t:?t1j6 }6hf^\]F>|%6Y6YvY6VYffF@fv u.jfvfFf@ff;vffVFfFfFf;\rhYjY33UjfvfFf;sff]V>|$д6!^Nu33?nffVffFf fFffFfFf;\vf\fFVF^F6YjfFf fP6^hv64FvdY~} h.YjY;F6f6f.ffff&.Ü.hf>f6f.ffff&..j\jXjTjPjLjHjDj@ju$3f#f$ff..$ t$$f.$4f$f$ff$$$0f$$+$;fffff$$3f$6$<.$ 6&666ffVfWfdgf_f^fSfVfPfffXf^ tfgf&gG*g&gG &gG.ff_fg3h|=u.V3Z.6X.>R..Nu) !L!16-bit DPMI unsupported. $fS3fG4GTG _"GLfG(fO,fW0g8_:fou F3ҰFú!F !FV3JFF^f&f#F^&G&;#u;#uA| F |x^VW>3 kLJxF|3 kLJF|>t 44>u_<>tPPr4PYFFO>3^&?F^&FFr_^V>3<tz} } u#:3Ҏ&<3Ҏ&GLJƄLJ<Fr>uO>tPjT3jYffVF3^##&G&FA|^U]UVWGgGL>>$kx>tb#fff+fGlffG ffGLffG$ffG8ffGPf>tfo8 j hfw8wP) GP3b#ffG8kftfG kxGLfG$03_^]U>t] t]3]UVGg2} '^]G(F~Luw(Y'U(u G(3]k']UVrw#6:r:w *#u##u##´]UVv3A;st;s B=vۋ=wL3>3Ƈ@ƇAB;r+ O$3^]UVtЁst]ø]Uw4Y]UN ЋƇ9WTuGT9WHuGH9WXuGX9W\uG\]VNffF t ffHfFFfFfVWg$G(F6h).;Ftr.glw,cY cxF=LvG4G4 FWuJu>u2t&9u;Fu  FrjY  G(LJFƇG(5=oG0 ‹G,B=.6D0D,G,$=0G,F~v V ‹F FpFX=6D, $W, ‹bF=MjGY G G(PFP/$ F= jFPK= jPfwDwH#  O4Ѓ   3Ƈ@ƇJ _4H!^(s FG4 jY   G0vV  w0dY=  ŽI!Fs FG( V]Y w0Y=x  Ž_4J!Fr WVdE FG(4- G4PY3&GG,3&&G4PY36T,&W36T0& G4Ѓ kxG,kft~G4Ѓ k6D,xfG0kftf G4PY>#t=#k؃t-#k؋G,#kffG0 u G,+G,ffff 믋G4P_Y>#3&GF3&F#؊ȋ,+un9F-;F#؋:3Ҏ&#؋<3Ҏ&GLJ#LJ<u3 tAr fG0f6D,Ƈ-3Ҏ&3&O#؃<u #V؉<#V؉:#؈>#,+u"6D0#kLJ1 =P#ZЋ#kW,؉fG0fP#kfXf;w ;6D,D0fG0f>uFV,tG,)FG,Pfvfw8wPx &>0(tn^&&F(u-G43ҋ؎&G43ҋ؎&GZfG f&?>>ffG GL&C>GL+fG8f&E>ffG8GP&I>GP3G%tg$&<>e&<>W3 tAr2fG@f6DTƇfGDfDHO,-G09G,3#-;G0uLJFrG(O4G,G@+ffGDtO4G,gG@hfGDXG(ZG4&VG, IG(-G4G,j htnfh0FP݃#RPfXfFfF#RPfXfP#RPfXfZf+fVffF VFv#RPfXfVf+v'ffFf fFj0FPfwDwHX 6~~fFfDfFDt uj Y OfG,ff%fW4fffFfPM  tVcY5fFfFfffFfHfDDG,GDffG4G@fGDfW@fffP 6~~fGDfW@fffFff;FfG,ff%fW4fffFfDf+f@fVf+fVfRt  DfFfD|tvfD\f;rjDuwfGfFfFfFfPfDf+FfPf4R fFfffFfHfDDGDffG@GDG,G@G4Dt  6~fG@fFTt;ff;Fu,fG4fFfw,fv(u3P{Yt u6~fG@fFTtg)ff;FuXfG,f fFfG4fFFuG0ufFfFfHf;Dv G(%fvfvfw0 @t uG(#fG,fW4fffFfGDfW@fffFf~}G(Pfvfv i^G4G,UfG,fW4fffFfGDfFfW@fffFfFff~ffvfv>fGDfW@fffFfG,fW4fffFfF4G4 <u fFG4fvfvfvG%t(ug$G(t(uO$G(Z#FFFVBtxfG4ffW,f ‹^f#F #G0%uFG0H% fƊVff #FG4F~gG4%FN!#F!#Fffff!#fG4%F#NG(HG4%FN!#+G4tD8-@8k@8K>O$3_^         `\y~-^ """" #;#V##~$$%%&&&&b)b)&b) 'l''''((()7)VWS36  t'.&@*.B*f>t f6' gD@z'' "* ؎.&@*f3"f##f##f##f##f##f##p't ">u'fGf t" f "3+h`!f#>t9ffPfPfPfPfPf.@*fPffP+fPf;ظ f&'&D f%"+.D*.&@*Ў؎>t'tbGg<t#3:r:v:r>:w8:u j6&.h0&1[_^À>u >t ;ðÀ>u$À>uGt >t ðÀ>u !t>d7`0d)uS3H3ۋ&G;&G[3d%3ɜ[SX%=tBSX%t4ԃ/s%&sf3f t f3@fp'%AAAAVfffXfffPfffXf3fSff^UF3ұ3F]UVF2&W&% F]UFV&W& ]U'HhffvT''jfv''hz'i''h'X'''x'h*ff''h'*'']Vfv'6~^Y~G~>~uffffffVF3f&Ƅ'F|>tfvf6@3ff f^f&F|^f&F|hfvQ&W&fFf'&z'h~'|'.'h''jf6RPfXf$f&f;f%f#^fFf fFf~fv'9fFfv'fFhVFfFf;Fv RPfXfFfFf;Fwfv'3øUV6~fDf;Frff;Fw t u3^] VWfFf&8FfFffVF&Gt[f&f fFfPh+݃fv݃hvvh+Ѓ hv6&T&F'`hv6&T&F'FF^f&F~|f'ffVFfFf %FVPF[_^VfGhfFfP t^GluTffvVF^&&Gt-6~&^f&f fFJVFf~u 6{^&%`Ff&'fFf f^f& ^&Gt3&f'ffVF^&%=f&f fFffff f fF&@tu&% F&hh+fvj8 ىVFfvh+oڃ^f&'fFf ^f& ^؋F& ^f&VF@=u=u;6;>_^ fF fFfHfFf ffPfv <Wf~ rWfv VFfF fF&'ff F^f&fF fFfF f;Fv fFfFffFfFfvVF~ ufFfF&'^&t ~ tK&L~ uFfFfGhGl tjfFf+FfPfvl ËfGh^&'fFfFf;FsfPJ L3fufvYVF^&t%&GtBf&f fP u.^&'/^&Gt^&Gtf&f fPp׃^f&fnfFf;FvUVW6~~=ff;Fu,ftfPTff+DfHfP DV5YDt u3_^]VWf3~t jFPffG0fPwH fvMVF^&F~u3%FnF~~FFtNNF%` FtF% ufvfv^&'!uF% tu ^f&Ft ^&^&'Ft^&'F%`^& fF~u jFPffG0fPwH~ F;v 3_^ pfvEVF^f&fFf&fv "VF^fFf&FufF fF&'fFfF fFf;Fv|xtplhd`\XTPLHD@<840,($  |xtplhd`\XTPLHD@<840,($  |xtplhd`\XTPLHD@<840,($  |xtplhd`\XTPLHD@<840,($  j3<.u f>n#j3 f~Fffff6gf f&gG0&gG+f&g^ffNNF 0f~FfYf_f^][fπ'<!fVfWfQf3ffgfYf_f^fVfWfQ3ffgfYf_f^f.&E>ff UVW6&.G$%>PAfSfG(fO,fW0fw@fDfot'u~t 4t| ty]ffG fFfG,FGHfFfGDGT8fF ffV ffG@Fj{YFffG fFfG,GH8fF ffV ffGDFGTfFfG@FjYF/ t  !L!> tH!rrfQiL!U>t>t67Y6!Y]RPfXfFft@fP&PYVFfFff f<t; r X!<X!<X!X!]U> rX<!XfXf;y>t6f<<< t>>tJ hYjνY>uBf<3&ff<3&ff<v f<>t RPfX fVt V<*f<s< ><$v<$f\fft1fFfv t fvfFfFf;t]V<;<t5;<<t(CRPfXfFftaft fv},fFf;!tCgut tEgtgUVWv~gff_^]øgggtf3f fUfV]f gø gø gU^N] g<<CWSPBLKc:\cwsdpmi.swp";FDivision by ZeroDebugNMIBreakpointOverflowBounds CheckInvalid OpcodeFPU unavailableDouble FaultFPU overrunInvalid TSSSegment Not PresentStack FaultGeneral Protection FaultPage FaultFPU Error Int 0x%02x%s cr2=%08lx in RMCB at eip=%lx; flags=%x eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx cs=%x ds=%x es=%x fs=%x gs=%x ss=%x error=%04x DOS 3 required. CWSDPMI V0.90+ (r5) Copyright (C) 2000 CW Sandmann ABSOLUTELY NO WARRANTY Protected mode not accessible. Descriptors exhausted. Warning: cannot open swap file %s No swap space! Swap disk full! pwhxllg>llllldlllll|lg>g>g>g>g>g>g>g>dg>g>g>g>ddddddddddg>g>g>g>g>g>g>dCWSDPMI%CWSDPMI not removed $ Error: Using XMS switched CPU into V86 mode. Error: could not allocate page table memory EMMXXXX0openttd-1.5.3/os/dos/cwsdpmi/cwsdstub.exe0000644000000000000000000005200012627373447017124 0ustar rootrootMZ* T>0jr*Hl N @ $8%%%%q%U%&. /:/k/ CWSDPMI r5 Copyright (C) 2000 CW Sandmann (sandmann@clio.rice.edu). The stub loader is Copyright (C) 1993-1995 DJ Delorie. Permission granted to use for any purpose provided this copyright remains present and unmodified. This only applies to the stub, and not necessarily the whole program. go32stub, v 2.02T@\0!<smQj>!>!3E/ ut>@B6D t=.;w.H!uЋ33.Ph˻.;w.\J!,.$\&,32u*W.>*^.>,t'K?\uC,.G tCf.EXEG=!Fع?!33ɡ=Lt=MZ  tӉBF!?!;u>LLffPff?ffHfgffLffff;sff3f.mD t H!@6&6(6"31rT31Vf661ZX666>TZX1 ɃQɛ16I1VZX1 Yɓ16I11s=41+\^`f6Hf>7f;Vf6Lf>_fcDVf>ff3ffg>F!^1f6Tf6PێV1fff%f+f+fff>b6f6F~B\?h u f;`v`f3ɋf>bfbf)ff3V^fgffuðf gh$R!iCj\ knlR[ L!CP!XuPQW3n_YXø!3f+n1À>jrX!lX!kX!X!Ü>jrPSXk2!Xl![X.ڌ+>?G;r:;wXҋPډ?+30!?øL!A3ɴU^KK9r]UVx9u;r+ uʁ;w! t̀+9u]U5F!“]U%FV!]UW~FN_]UF UVW^v~ N _^]UVWv~_^]3ËRPfZffRXZUb!]U^P!]UVvVt fFf fFFfFf$DF DfF fDfF fDFDD^]UVvfhV DLFD DTDPDD8DD`x^]VW0FF,^.&6.&,&4&.6&0>tmFFF^GFFN u=tf7A2 u Ƈ1F|j`h &j6\ W!8@t&(>u f>T&Qiuf&6j/ACI!FL!_^UVvV$0<9v'NI u^]VWFFF< u%+FPvjjhjFv<%+FPvjFF +FPvj_^UV,gr3,Gg؋ u,GgPhVh,gu fwhh>xthY,w$fw hx,fwDfw@fw0fw,fw4fw(hS,wlwPw\wXwHwTwLfw8fwu 0hY-@@% t@ u@hYjY$&)jhhD&RPfhhjhh, $&RPfhhjhh,&RPfhhjhfffPfhhkjhfffPfhhKjhfjfjh7jhfhfhhjhfffPfhhjhfffPfhhjhh.%6%RPfhh jhh &%RPfhhjhh,=$RPfhh}j/Y& &hh*j/t&(&]VWF, &>F6Ft uO~ 1tF fh`6h &q jJYFjAYFj8YFj/YF 2huYj@Y"h/h.%h/h &h/h'h/h(h(@h,=fhh,FFFFf*%v!8Yq$ <-.&F.4&06&3|&x&jhfl&ffPfhF,PF l&vhft&ffPfhF,PfD&2b!^F0FF,^&.F &jhfFffPfhF,PF h&jhf.ffPfhF,POt&;p&t3j YFvhfp&ffPfhF,PFFF t&F p&hhuj#Nhhsj$@_^UfFfЊN~t 2&]2& ]UfFf42&N"]UFD]Uf3f>f:f6>Dt:D?t1j6D }6Dh Bf6]F>|%6BY6YvY6DuYf6fF@fv u.jfvfFf@f6f;>vf>f:VFfFfFf;rh=YjY33UjfvfFf;6sf6f:]V>|D$д6!^Nu33?nffVffFf fFf>fFfFf;vffFVF^F6BYjfFf fP6}hv6SFvY~} hMYjYZF6B[YjfFf fP6%hv6v.Yfg$ghUVW6&+&th6f6r6pj=&_^]f>Ff6Jf.NfVfZf^fbh&l.nÜ.hff>Ff6Jf.NfVfZf^fbh&l.nv.jj\jXjTjPjLjHjDj@j,up&3f%fX&,xfzf.~.H& tp&h&f.X&4fX&fd&ffd&h&D&0f@&l&+t&;fvfftff`&x&3fT&F6,, &<.,x,@& 6&t6f6r6pjffVfWfdgf_f^fSfVfPfffXf^ tfgf&gG*g&gG &gG.ff_fg3hL=u.&3Z.6(.>"..u)^ !L!16-bit DPMI unsupported. $fS3fG4GTG _"GLfG(fO,fW0g8_:fou F3ҰFú!F !FV3J3FF^f&f%F^&G&; %u;%uA|3 F |x^VW>223 kLJF|3 kLJXF|,x>t N4-P40>-u_<.>t0P.P24.PY.FFB3^&?F^&FFr-../01_^V>223tz} .}0 u#3Ҏ&3Ҏ&GLJ~ƄLJFr>-uO>t0Pj3jY.ffVF3^ %%&G&FA|^U]UVW,GgGL>,>, &k>,t$fff+,fGlffG ffGLffG$ffG8ffGPf>,tfo8 j h,fw8wP) ,GP3$ffG8kf,fG k,GLfG$0,3_^]U>xt] t]3]UV,Gg2} >'^],G(F~Luw(Y'U,(u G(3]k']UVrw %.6:0r:1w *0 %u %#u % %´]UVv3A;s1t;s B=vۋ=wL3>3.,30Ƈ2@Ƈ1AB;r+ ,O$3^]UVtЁs1t]ø]U,w4Y]UN ЋƇ1,9WTuGT,9WHuGH,9WXuGX,9W\uG\]VNffF t ffHfFF,fFf2VW,g$,G(F68-.;Ftr.gl,w,cY cxF=Lv,G4G4 FW2uJ3u>,u21t&9.u0;Fu  FrjY  ,G(LJ,.F0Ƈ2,G(5=o.,G003 ‹,G,B=.6,D0.D,0,G,$3=,0G,F~v V ‹F F,2pF2X=6,D, 12$,W, ‹2bF=MjGY G ,G(,PF,PO1$ 1F= jF,PK= j,P,fwDwH# 1 ,O4Ѓ  1 3.,30Ƈ2@Ƈ1J ,_4H!^,(s FG4 jY   ,G0vV. 0 ,w0dY= .0 ŽI!Fs ,FG( V]Y ,w0Y=x .0 Ž,_4J!Fr WVdE ,FG(4- ,G4PY3&G,G,3&&,G4PY36,T,&W36,T0& ,G4Ѓ k,G,kf~,G4Ѓ k6,D,,fG0kff ,G4PY> %t= %k؃Xt- %k؋X,G, %kfT,fG0 . u ,G,+. ,G,f, f2 ff 믋,G4P_Y> %3&GF3&F %؊ȋ,,+un9F[-WW;F %؋3Ҏ& %؋3Ҏ&GLJ~ %LJu3 ~tAr ,fG0fz6,D,~Ƈ[-WW3Ҏ&3&O %؃u %V؉ %V؉ %؈> %,,+u"6,D0, %kLJX1 @P %ZЋ, %k,W,؉X,fG0fP %kfXfT.;w /;6,D,. D0, ,fG0f2 >vuvtvtFV,,tG,)FG,Pfvfw8wPx &f>f0,(tn^f&&fFt,(u-G43ҋ؎&p,G43ҋ؎&GrZ,fG f&BAf,fG GL&B,GL+fG8f&BHf,fG8GP&B,GP3G%tg$& Be& BW3 ~tAr2,fG@fz6,DT~Ƈ,fGDfDH,O,[-WW,G0,9G,3#[-WW,;G0uLJ~Fr,G(O4G,rG@+rffGDt,O4G,7G@hfGDX,G(ZG4&&,G,-0 I,G(-G4G,j hnfh0FPރe#RPfXfFfFV#RPfXfPY#RPfXfZf+fVffF VF-#RPfXfVf+(ffFf fFj0FP,fwDwHX 6fFfDfFDt uj Y O,fG,ff%fW4fffFfPM  tVY5fFfFfffFfHfDD,G,GDffG4G@,fGDfW@fffP 6,fGDfW@fffFff;F,fG,ff%fW4fffFfDf+f@fVf+fVfRt  DfFfD|tvfD\f;rjDuwfGfFfFfFfPfDf+FfPf4R fFfffFfHfDD,GDffG@,GDG,G@G4Dt  6,fG@fFt;ff;Fu,,fG4fFfw,fv(u3P{Yt u6,fG@fFtg)ff;FuX,fG,f fFfG4fFFuG0ufFfFfHf;Dv ,G(%fvfv,fw0 @t u,G(#,fG,fW4fffFfGDfW@fffFf~},G(Pfvfv i^,G4G,U,fG,fW4fffFfGDfFfW@fffFfFff~ffvfv>,fGDfW@fffFfG,fW4fffFfF4,G4 <u fFG4fvfvfv,G%t(ug$,G(t,(uO$,G(Z*%FFFVBtx,fG4ffW,f ‹^f%F *%,G0%uF,G0H% fƊVff *%,FG4F~g,G4%FN!&%F!*%Fffff!*%f,G4%F&%N,G(H,G4%FN!&%+,G4t<-t f6") g@)) ". ؎.&.f3"f%#f%#f%#f%#f&%#f*%#(t ">u',fGf t" f "/h`!f&%>t9ffPfPfPfPfPf..fPffPy/fPf;ظ f&&)& f%"m/...&.Ў؎>(tb,Gg<t#3:.r:/v:0r>:1w8u j6&.h0&1[_^À>u >t ðÀ>u$À>uGt >t ðÀ>u !t>d7`0d)uS3H3ۋ&G;&G[3d%3ɜ[SX%=tBSX%t4ԃ/s%&sf3f t f3@f(%AAAAVfffXfffPfffXf3fSff^UF3ұSF]UVFR&W&% F]UFV&W& ]U*)Hhfv()&)jfv) )h)i))h)X)))x)h.ff) )h )*$)")]Vf(6~YG>uffffffVF3f&Ƅ,)F|>tfvf6@3ff f^f&F|^f&F|hfvQ&W&fFf,))h)))h,  ))jf6RPfXf<&f (fH=f.'fJ%^fFf fFf~f(9fFf(fFVFfFf;Fv RPfXfFfFf;Fwf(3øUV6fDf;Frff;Fw t u3^] VWfFf&FfFffVF&Gt[f&f fFfPh,-݃fv݃hvvh,-у hv6&T&F,)`hv6&T&F,)FF^f&F~|f,)ffVFfFf %FVPF[_^V,fGhfFfP t^,GluTffvVF^&&Gt-6(^f&f fFVFf~u 6{^&%`Ff&'fFf f^f& ^&Gt3&f,)ffVF^&%=f&f fFffff f fF&@tu&% F&hh,-fvj8 ىVFfvh,-pڃ^f&'fFf ^f& ^؋F& ^f&VF@=u=u;6;>_^ fF fFfHfFf ffPfv <Wf~ rWfv VFfF fF&'ff F^f&fF fFfF f;Fv fFfFffFfFfvVF~ ufFfF&'^&t ~ tK&L~ uF,fFfGhGl tjfFf+FfPfvl Ë,fGh^&'fFfFf;FsfPJ L3fufvYVF^&t%&GtBf&f fP u.^&'/^&Gt^&Gtf&f fPq׃^f&fnfFf;FvUVW6=ff;Fu,ftfPTff+DfHfP DVUYDt u3_^]VWf3~t jFPf,fG0fPwH fvMVF^&F~u3%FnF~~FFtNNF%` FtF% ufvfv^&'!uF% tu ^f&Ft ^&^&'Ft^&'F%`^& fF~u jFPf,fG0fPwH~ F;v 3_^ pfvEVF^f&fFf&fv "VF^fFf&FufF fF&'fFfF fFf;Fv|xtplhd`\XTPLHD@<840,($  |xtplhd`\XTPLHD@<840,($  |xtplhd`\XTPLHD@<840,($  |xtplhd`\XTPLHD@<840,($  j3>.><.>p,>Ggfw8gP<wO,rKt%dgF00tfdgfGlf fGhfdgegA,u f>$j3 f~Ff,fff6gf f&gG0&gG+f&g^fTfNXNF 0f~FfYf_f^][fπ'<!fVfWfQf3fFfgfYf_f^fVfWfQ3fFfgfYf_f^f.&Bff UVW6&.,G$%>PAfS,fG(fO,fW0fw@fDfo(u~t ,4t| t]ffG fFfG,FGHfFfGDGT8fF ffV ffG@,F,j{YF,ffG fFfG,GH8fF ffV ffGDFGTfFfG@,F,jYF,U>t>t6@Y6*Y]RPfXfFft@fP/PYVFfFff f2>fFf fFf fHf6>f2>f6>UN£J>>H>t;H>t6H>BYJ>H>>r X!D>X!F>X!X!]U>rXF>!XD>!J>;H>tPY]UVWvxH!@>FL>;@>wdL>)@>;@>s>ff;$>s @>';@>s)@>@>+ff$>L>@>@>H!>>s N>@IN>>>L>t%)@>>>@>J!,>0>>>@>-.>3_^]Vv>y>t6f2>8>6> t>>t hoYj7Y>uBf2>3&ff6>f>6>3&ff6>xff6>333r=3&fFF^f&VDISuf&G,ff f%f2> f2>f2>f:>f>6>v f6>>t RPfX f6>f+2>f@f$>>t B>*f$>f B>>B>sB> >B>$vB>$fff6>fL>H>t,N>D>>L>,>0>.> 6B>j thYj芽Y>>"> >Pf6>ffPjjXf6>f>>@4264fffPjj'L>f(>^fFfЊNF~t  >& >ڊF& fFfFNF >^&"F>t1fFfv t fvfFfFf;6>vU>t]V0>;.>vL>N>t5;@>>>@>J!X%Fm~u>>@>-2fh} u .>.>u hYj߽Y^>t(LRPfXfFftaf(>jfPVFf:>fF5fv u#fFf@f:>f(>jfv_VFfFfFf;6>vf(>f;$>s3.>+B>;0>v#f(>0>0>&W& cwUfv4 t0jfv>t fv,fFf;:>s!f:>0>Hf&f;Fu0>f(>]3]U&>$>]U*>(>]C/R>ôP> uffôP>3ô  UV]P>ô U V]P> tËUfV]fft P> tHg5! ú(=!rش>!tCgu&t& tEgtgUVWv~gff_^]øgggtf3f fUfV]f gø gø gU^N] gLoad error: : can't open: not EXE: not COFF (Check for viruses)no DOS memoryneed DOS 3can't switch modeno DPMI selectorsno DPMI memory ??CWSPBLKc:\cwsdpmi.swp #'2;HWgtDivision by ZeroDebugNMIBreakpointOverflowBounds CheckInvalid OpcodeFPU unavailableDouble FaultFPU overrunInvalid TSSSegment Not PresentStack FaultGeneral Protection FaultPage FaultFPU Error Int 0x%02x%s cr2=%08lx in RMCB at eip=%lx; flags=%x eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx ebp=%08lx esp=%08lx cs=%x ds=%x es=%x fs=%x gs=%x ss=%x error=%04x Protected mode not accessible. Descriptors exhausted. Warning: cannot open swap file %s No swap space! Swap disk full! pwhx<<7B<<<<<4<<<<<L<7B7B7B7B7B7B7B7B47B7B7B7B44444444447B7B7B7B7B7B7B4CWSDPMI' Error: Using XMS switched CPU into V86 mode. Error: could not allocate page table memory EMMXXXX0openttd-1.5.3/os/dos/cwsdpmi/README.licensing0000644000000000000000000000030212627373447017413 0ustar rootrootThe files in this directory are not licensed under the same terms as the rest of OpenTTD. Licensing details can be found in OpenTTD's readme.txt and in this directory or subdirectories as well. openttd-1.5.3/os/dos/cwsdpmi/cwsdpmi.txt0000644000000000000000000001747212627373447017010 0ustar rootrootCWSDPMI is Copyright (C) 1995-2000 Charles W Sandmann (sandmann@clio.rice.edu) 1206 Braelinn, Sugar Land, TX 77479 This is release 5. The files in this binary distribution may be redistributed under the GPL (with source) or without the source code provided: * CWSDPMI.EXE or CWSDPR0.EXE are not modified in any way except via CWSPARAM. * CWSDSTUB.EXE internal contents are not modified in any way except via CWSPARAM or STUBEDIT. It may have a COFF image plus data appended to it. * Notice to users that they have the right to receive the source code and/or binary updates for CWSDPMI. Distributors should indicate a site for the source in their documentation. ------------------------------------------------------------------------------- CWSDPMI was written to provide DPMI services for V2 of DJGPP. It currently does not support 16-bit DPMI applications, or DPMI applications requiring a built in extender. It does support virtual memory and hardware interrupt reflection from real mode to protected mode. DJGPP V1.1x and RSX applications will also run using this server, which can be used to provide enhanced control over hardware interrupts. Some DPMI 1.0 extensions (0x506, 0x507, 0x508) have been implemented. CWSDPR0.EXE is an alternate version which runs at ring 0 with virtual memory disabled. It may be used if access to ring-0 features are desired. It currently does not switch stacks on HW interrupts, so some DJGPP features such as SIGINT and SIGFPE are not supported and will generate a double fault or stack fault error (to be fixed someday). CWSDSTUB.EXE is a stub loader image for DJGPP which includes CWSDPMI. This allows single executable image distributions. You can use the EXE2COFF program and COPY /B CWSDSTUB.EXE+yourimage yourimage.exe to create a standalone executable image. Some of the internal tuning and configuration parameters may be modified in the image using CWSPARAM.EXE (see CWSPARAM.DOC). If you want to use CWSDPMI with DJGPP, you expand the distribution into the DJGPP directory tree. CWSDPMI.EXE will be put in the BIN directory with your DJGPP images and it will automatically be loaded when they run. Directions for use (server can be used in either of two different ways): 1) "cwsdpmi" alone with no parameters will terminate and stay resident FOR A SINGLE DPMI PROCESS. This means it unloads itself when your DPMI application exits. This mode is useful in software which needs DPMI services, since CWSDPMI can be exec'ed and then will unload on exit. 2) "cwsdpmi -p" will terminate and stay resident until you remove it. It can be loaded into UMBs with LH. "cwsdpmi -u" will unload the TSR. 3) The file used for virtual memory swapping, if desired, is controlled by the "-sc:\cwsdpmi.swp" syntax on the command line. You must specify either a file with full disk/directory syntax, or "-s-" which disables virtual memory. 4) The default swap file name is c:\cwsdpmi.swp, but this can be changed with the CWSPARAM image, as can some other parameters. 5) You can disable the DPMI 1.0 extensions by starting the image with the "cwsdpmi -x" syntax. This feature allows you to run programs developed under other DPMI providers which do not behave properly with these extensions enabled (typically use of NULL pointers). I would like to give special thanks to DJ Delorie who wrote the original GO32 code on which CWSDPMI is based. Morten Welinder also provided and improved much of the code in this program. ------------------------------------------------------------------------------- This section contains a list of the error messages you might see out of CWSDPMI and some details on what they mean. Exceptions are only handled by CWSDPMI if the application does not establish an exception handler, exceptions nest 5 deep, or the error is particularly bad: "Page fault" - 1) an illegal page fault happens in a RMCB or HW interrupt, (lock all pages!) 2) all available pages have been locked, 3) the application is using non-committed pages for null pointer protection. "Double Fault" - multiple exceptions occurred "Invalid TSS" - typically due to RMCB or HW interrupt being called after the selectors/memory have been deallocated (remember to reset the mouse) "General Protection Fault" - bad parameter sent to a DPMI call "80386 required." Since 80286 and lesser processors don't have the hardware necessary to run CWSDPMI. No workaround, upgrade. "DOS 3 required." A few interrupts are used which need DOS 3.0 or higher. I don't expect to ever see this message, since 80386 machines were introduced after DOS 3.0 and that check is made first. "CWSDPMI V0.90+ (r5) Copyright (C) 2000 CW Sandmann ABSOLUTELY NO WARRANTY" An informational message displayed if the program is not run in one-pass mode. "Protected mode not accessible." This message should only be displayed if running CWSDPMI in a protected environment with no access to protected mode. In this case, DPMI should already be available and CWSDPMI would not be needed. This might happen if a 16-bit DPMI client is loaded and a DJGPP image attempts to load CWSDPMI to provide 32-bit DPMI services under Windows. "Warning: cannot open swap file c:\cwsdpmi.swp" Maybe you are out of file handles, or the swap file name is incorrectly specified in the image (change the name with cwsparam). "No swap space!" This message means you tried to use more paging file than CWSDPMI was configured to handle. Since this is protected against in the memory allocation code, you should never see this message. "Swap disk full!" This means the paging file could not be expanded when trying to page memory out to disk. This would normally not be seen, unless you are writing output to the same disk which holds the paging file. Decrease the amount of memory your DPMI application is using or free up disk space. "Interrupt 0x??" Your application tried to call an interrupt from protected mode which normally shouldn't be called (something like a data pointer). If the request was allowed to continue it would likely hang your machine. If you see this message and think the interrupt should be allowed to continue, let me know. "Error: Using XMS switched CPU into V86 mode." This message might be seen if you have your memory manager in AUTO mode. The only workaround in this case is to stop using AUTO mode. "Error: could not allocate page table memory" The page table memory (a minimum of 16Kb) is allocated from conventional memory (either in the 640Kb region or UMBs). If CWSDPMI cannot allocate the minimum necessary memory, you would see this message. Free up some conventional memory. You may also see this message if a page directory needs to be faulted in, and there are no available pages. This means too many pages have been locked for the allocated page tables available. While CWSDPMI tries to dynamically allocate these if needed, this effort failed. You need to increase the number of page tables with CWSPARAM, or increase the amount of free conventional memory if it is low. If the application which calls CWSDPMI internally manages all the DOS memory, the page tables may need to be pre-allocated at DPMI startup time (if this is needed, try using the run option flag 2 in cwsparam). "16-bit DPMI unsupported." CWSDPMI is a 32-bit only DPMI server. Ideally, on the request to enter DPMI's PM with a 16-bit request, we would just fail the call setting the carry bit like the DPMI specification describes. Some buggy 16-bit compiler tools don't check the return status and will hang the machine in this case. So, I issue an error message and exit the image instead. "Descriptors exhausted." An attempt to nest a DPMI client failed in the setup phase due to insufficient free selectors in the LDT. "CWSDPMI not removed" When the -u parameter is specified, if DPMI is not detected this message is printed. Informational. openttd-1.5.3/os/dos/exe2coff/0000755000000000000000000000000012627373447014621 5ustar rootrootopenttd-1.5.3/os/dos/exe2coff/copying.dj0000644000000000000000000000404312627373447016611 0ustar rootrootThis is the file "copying.dj". It does NOT apply to any sources or binaries copyrighted by UCB Berkeley, the Free Software Foundation, or any other agency besides DJ Delorie and others who have agreed to allow their sources to be distributed under these terms. Copyright Information for sources and executables that are marked Copyright (C) DJ Delorie 7 Kim Lane Rochester NH 03867-2954 This document is Copyright (C) DJ Delorie and may be distributed verbatim, but changing it is not allowed. Source code copyright DJ Delorie is distributed under the terms of the GNU General Public Licence, with the following exceptions: * Sources used to build crt0.o, gcrt0.o, libc.a, libdbg.a, and libemu.a are distributed under the terms of the GNU Library General Public License, rather than the GNU GPL. * Any existing copyright or authorship information in any given source file must remain intact. If you modify a source file, a notice to that effect must be added to the authorship information in the source file. * Runtime binaries, as provided by DJ in DJGPP, may be distributed without sources ONLY if the recipient is given sufficient information to obtain a copy of djgpp themselves. This primarily applies to go32-v2.exe, emu387.dxe, and stubedit.exe. * Runtime objects and libraries, as provided by DJ in DJGPP, when linked into an application, may be distributed without sources ONLY if the recipient is given sufficient information to obtain a copy of djgpp themselves. This primarily applies to crt0.o and libc.a. ----- Changes to source code copyright BSD, FSF, or others, by DJ Delorie fall under the terms of the original copyright. Such files usually have multiple copyright notices in them. A copy of the files "COPYING" and "COPYING.LIB" are included with this document. If you did not receive a copy of these files, you may obtain one from whence this document was obtained, or by writing: Free Software Foundation 59 Temple Place - Suite 330 Boston, MA 02111-1307 USA openttd-1.5.3/os/dos/exe2coff/copying0000644000000000000000000004307612627373447016226 0ustar rootroot GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program 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; either version 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. openttd-1.5.3/os/dos/exe2coff/exe2coff.c0000644000000000000000000000373412627373447016475 0ustar rootroot/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ /* Updated 2008 to use fread/fopen and friends instead of read/open so it compiles with GCC on Unix (Rubidium) */ #include #include #include #include #include #include #include static void exe2aout(char *fname) { unsigned short header[3]; FILE *ifile; FILE *ofile; char buf[4096]; int rbytes; char *dot = strrchr(fname, '.'); if (!dot || strlen(dot) != 4 || tolower(dot[1]) != 'e' || tolower(dot[2]) != 'x' || tolower(dot[3]) != 'e') { fprintf(stderr, "%s: Arguments MUST end with a .exe extension\n", fname); return; } ifile = fopen(fname, "rb"); if (!ifile) { perror(fname); return; } fread(header, sizeof(header), 1, ifile); if (header[0] == 0x5a4d) { long header_offset = (long)header[2]*512L; if (header[1]) header_offset += (long)header[1] - 512L; fseek(ifile, header_offset, SEEK_SET); header[0] = 0; fread(header, sizeof(header), 1, ifile); if ((header[0] != 0x010b) && (header[0] != 0x014c)) { fprintf(stderr, "`%s' does not have a COFF/AOUT program appended to it\n", fname); return; } fseek(ifile, header_offset, SEEK_SET); } else { fprintf(stderr, "`%s' is not an .EXE file\n", fname); return; } *dot = 0; ofile = fopen(fname, "w+b"); if (!ofile) { perror(fname); return; } while ((rbytes=fread(buf, 1, 4096, ifile)) > 0) { int wb = fwrite(buf, 1, rbytes, ofile); if (wb < 0) { perror(fname); break; } if (wb < rbytes) { fprintf(stderr, "`%s': disk full\n", fname); exit(1); } } fclose(ifile); fclose(ofile); } int main(int argc, char **argv) { int i; if (argc == 1) printf("Usage: %s ", argv[0]); for (i=1; i Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! openttd-1.5.3/os/rpm/0000755000000000000000000000000012627373446013130 5ustar rootrootopenttd-1.5.3/os/rpm/openttd-rpmlintrc0000644000000000000000000000047412627373446016545 0ustar rootroot# the man page is in the subpackage data addFilter("openttd.*: W: no-manual-page-for-binary openttd") # no other package depends on this package, so this should not matter addFilter("openttd.*: W: file-contains-date-and-time /usr/bin/openttd") addFilter("openttd.*: W: file-contains-current-date /usr/bin/openttd") openttd-1.5.3/os/rpm/openttd.changes0000644000000000000000000000644512627373446016150 0ustar rootroot------------------------------------------------------------------- Sun Mar 6 09:36:55 UTC 2011 - ammler@openttdcoop.org - upstream update 1.1.0-RC2 * Feature: XZ/LZMA2 savegame support. New default reduces savegame size by 10 to 30% with slightly more CPU usage. (requires xz-devel) * Feature: Remote administration * Feature: a lot improvements with GUI * Feature: Customizable hotkeys * Sources for openttd.grf are pngs (requires grfcodec >= 5.1) ------------------------------------------------------------------- Sun Nov 21 11:11:38 UTC 2010 - ammler@openttdcoop.org - upstream update 1.0.5 * Fix: Reading (very) recently freed memory [CVE-2010-4168] ------------------------------------------------------------------- Sun Oct 31 17:53:41 UTC 2010 - ammler@openttdcoop.org - upstream update 1.0.4 * build openttd.grf from source ------------------------------------------------------------------- Tue Aug 10 20:16:03 UTC 2010 - ammler@openttdcoop.org - upstream update 1.0.3 ------------------------------------------------------------------- Wed Jun 23 11:42:59 UTC 2010 - Marcel Gmür - upstream update 1.0.2 * Feature: Translated desktop shortcut comments (r19884) * many minor Bugfixes ------------------------------------------------------------------- Sat May 1 15:59:32 UTC 2010 - Marcel Gmür - upstream update 1.0.1 * Fix: Leaking a file descriptor * Fix a lot small bugs, like minor desync issues on Mulitplayer - no strip on make ------------------------------------------------------------------- Thu Apr 1 08:53:54 UTC 2010 - Marcel Gmür - upstream update 1.0.0 (finally!) * completely independend game but still working also with ttd original gaphics, sounds and music - Add: Recommends openmsx - requires lzo2 ------------------------------------------------------------------- Fri Dec 18 2009 Marcel Gmür - 0.7.4 - support for differen branches - easy support for dedicated branch - let openttd build system make the dektop file - split the package to data and gui - disable requires ------------------------------------------------------------------- Thu Oct 01 2009 Marcel Gmür - 0.7.3 - disable libicu for RHEL4 ------------------------------------------------------------------- Sat Sep 26 2009 Marcel Gmür - 0.7.2 - no subfolder games for datadir - cleanup: no post and postun anymore - Recommends: opengfx (for suse and mandriva) - add SUSE support ------------------------------------------------------------------- Mon Oct 20 2008 Benedikt Brüggemeier - Added libicu dependency ------------------------------------------------------------------- Thu Sep 23 2008 Benedikt Brüggemeier - Merged both versions of the spec file ------------------------------------------------------------------- Fri Aug 29 2008 Jonathan Coome - Rewrite spec file from scratch. ------------------------------------------------------------------- Sat Aug 02 2008 Benedikt Brüggemeier - Updated spec file ------------------------------------------------------------------- Thu Mar 27 2008 Denis Burlaka - Universal spec file openttd-1.5.3/os/rpm/openttd.spec0000644000000000000000000002046012627373446015463 0ustar rootroot# # spec file for package openttd # # Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. # Copyright (c) 2007-2012 The OpenTTD developers # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # Name: openttd Version: 1.5.beta1 Release: 0 %define srcver 1.5.0-beta1 Summary: An open source reimplementation of Chris Sawyer's Transport Tycoon Deluxe License: GPL-2.0 Group: Amusements/Games/Strategy/Other Url: http://www.openttd.org Source: http://binaries.openttd.org/releases/%{srcver}/%{name}-%{srcver}-source.tar.gz %if 0%{?suse_version} || 0%{?mdkversion} Recommends: %{name}-gui %endif BuildRequires: gcc-c++ BuildRequires: libpng-devel BuildRequires: zlib-devel %if 0%{?suse_version} || 0%{?mdkversion} BuildRequires: update-alternatives Requires: update-alternatives %else BuildRequires: chkconfig Requires: chkconfig %endif %if 0%{?mdkversion} BuildRequires: liblzma-devel BuildRequires: liblzo-devel %else BuildRequires: lzo-devel BuildRequires: xz-devel %endif # OBS workaround: needed by libdrm %if 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 BuildRequires: kernel %endif # for lzma detection %if 0%{?suse_version} BuildRequires: pkg-config %endif # bulding openttd.grf is not required as it is a) part of source and # b) required only, if you want to use the original set %if 0%{?with_grfcodec} BuildRequires: grfcodec %endif # Recommends would fit better but not well supported... Requires: openttd-opengfx >= 0.4.2 Obsoletes: %{name}-data < %{version} Provides: %{name}-data = %{version} BuildRoot: %{_tmppath}/%{name}-%{version}-build %description OpenTTD is a reimplementation of the Microprose game "Transport Tycoon Deluxe" with lots of new features and enhancements. To play the game you need either the original data from the game or install the recommend subackages OpenGFX for free graphics, OpenSFX for free sounds and OpenMSX for free music. OpenTTD is licensed under the GNU General Public License version 2.0. For more information, see the file 'COPYING' included with every release and source download of the game. %package gui Summary: OpenTTD GUI/Client (requires SDL) Group: Amusements/Games/Strategy/Other Requires: %{name} Conflicts: %{name}-dedicated BuildRequires: SDL-devel BuildRequires: fontconfig-devel %if 0%{?rhel_version} != 600 BuildRequires: libicu-devel %endif %if 0%{?rhel_version} || 0%{?fedora} BuildRequires: freetype-devel %endif %if 0%{?suse_version} || 0%{?mdkversion} BuildRequires: freetype2-devel %endif %if 0%{?suse_version} BuildRequires: update-desktop-files %else BuildRequires: desktop-file-utils Requires: hicolor-icon-theme %endif %if 0%{?suse_version} || 0%{?mdkversion} Recommends: openttd-openmsx Recommends: openttd-opensfx %endif %description gui OpenTTD is a reimplementation of the Microprose game "Transport Tycoon Deluxe" with lots of new features and enhancements. To play the game you need either the original data from the game or install the recommend subackages OpenGFX for free graphics, OpenSFX for free sounds and OpenMSX for free music. This subpackage provides the binary which needs SDL. %package dedicated Summary: OpenTTD Dedicated Server binary (without SDL) Group: Amusements/Games/Strategy/Other Requires: %{name} Conflicts: %{name}-gui %description dedicated OpenTTD is a reimplementation of the Microprose game "Transport Tycoon Deluxe" with lots of new features and enhancements. To play the game you need either the original data from the game or the required package OpenGFX and OpenSFX. This subpackage provides the binary without dependency of SDL. %prep %setup -qn openttd%{?branch:-%{branch}}-%{srcver} # we build the grfs from sources but validate the result with the existing data %if 0%{?with_grfcodec} md5sum bin/data/* > validate.data %endif %build # first, we build the dedicated binary and copy it to dedicated/ ./configure \ --prefix-dir="%{_prefix}" \ --binary-dir="bin" \ --data-dir="share/%{name}" \ --enable-dedicated make %{?_smp_mflags} BUNDLE_DIR="dedicated" bundle # then, we build the common gui version which we install the usual way ./configure \ --prefix-dir="%{_prefix}" \ --binary-name="%{name}" \ --binary-dir="bin" \ --data-dir="share/%{name}" \ --doc-dir="share/doc/%{name}" \ --menu-name="OpenTTD%{?branch: %{branch}}" \ --menu-group="Game;StrategyGame;" make %{?_smp_mflags} %install # install the dedicated binary install -D -m0755 dedicated/openttd %{buildroot}%{_bindir}/%{name}-dedicated # install the gui binary and rename to openttd-gui make install INSTALL_DIR=%{buildroot} mv %{buildroot}%{_bindir}/%{name} %{buildroot}%{_bindir}/%{name}-gui # we need a dummy target for /etc/alternatives/openttd mkdir -p %{buildroot}%{_sysconfdir}/alternatives touch %{buildroot}%{_sysconfdir}/alternatives/%{name} ln -s -f /etc/alternatives/%{name} %{buildroot}%{_bindir}/%{name} %if 0%{?suse_version} %suse_update_desktop_file -r %{name} Game StrategyGame %else %if 0%{?fedora} || 0%{?rhel_version} >= 600 || 0%{?centos_version} >= 600 desktop-file-install --dir=%{buildroot}%{_datadir}/applications \ --add-category=StrategyGame \ media/openttd.desktop %endif %endif %if 0%{?with_grfcodec} %check md5sum -c validate.data %endif %post gui /usr/sbin/update-alternatives --install %{_bindir}/%{name} %{name} %{_bindir}/%{name}-gui 10 touch --no-create %{_datadir}/icons/hicolor &>/dev/null || : %post dedicated /usr/sbin/update-alternatives --install %{_bindir}/%{name} %{name} %{_bindir}/%{name}-dedicated 0 %preun gui if [ "$1" = 0 ] ; then /usr/sbin/update-alternatives --remove %{name} %{_bindir}/%{name}-gui fi %preun dedicated if [ "$1" = 0 ] ; then /usr/sbin/update-alternatives --remove %{name} %{_bindir}/%{name}-dedicated fi %postun gui if [ "$1" -eq 0 ] ; then touch --no-create %{_datadir}/icons/hicolor &>/dev/null gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : fi %posttrans gui gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : # we need a file in the main package so it will be made %files %defattr(-, root, root) %dir %{_datadir}/doc/%{name} %dir %{_datadir}/%{name} %dir %{_datadir}/%{name}/lang %dir %{_datadir}/%{name}/baseset %dir %{_datadir}/%{name}/scripts %dir %{_datadir}/%{name}/ai %dir %{_datadir}/%{name}/game %{_datadir}/doc/%{name}/* %{_datadir}/%{name}/lang/* %{_datadir}/%{name}/baseset/* %{_datadir}/%{name}/scripts/* %{_datadir}/%{name}/ai/* %{_datadir}/%{name}/game/* %doc %{_mandir}/man6/%{name}.6.* %files gui %defattr(-, root, root) %ghost %{_sysconfdir}/alternatives/%{name} %ghost %{_bindir}/%{name} %{_bindir}/%{name}-gui %dir %{_datadir}/icons/hicolor %dir %{_datadir}/icons/hicolor/16x16 %dir %{_datadir}/icons/hicolor/16x16/apps %dir %{_datadir}/icons/hicolor/32x32 %dir %{_datadir}/icons/hicolor/32x32/apps %dir %{_datadir}/icons/hicolor/48x48 %dir %{_datadir}/icons/hicolor/48x48/apps %dir %{_datadir}/icons/hicolor/64x64 %dir %{_datadir}/icons/hicolor/64x64/apps %dir %{_datadir}/icons/hicolor/128x128 %dir %{_datadir}/icons/hicolor/128x128/apps %dir %{_datadir}/icons/hicolor/256x256 %dir %{_datadir}/icons/hicolor/256x256/apps %{_datadir}/applications/%{name}.desktop %{_datadir}/icons/hicolor/16x16/apps/%{name}.png %{_datadir}/icons/hicolor/32x32/apps/%{name}.png %{_datadir}/icons/hicolor/48x48/apps/%{name}.png %{_datadir}/icons/hicolor/64x64/apps/%{name}.png %{_datadir}/icons/hicolor/128x128/apps/%{name}.png %{_datadir}/icons/hicolor/256x256/apps/%{name}.png %{_datadir}/pixmaps/%{name}.32.xpm %files dedicated %defattr(-, root, root) %ghost %{_bindir}/%{name} %ghost %{_sysconfdir}/alternatives/%{name} %{_bindir}/%{name}-dedicated %changelog openttd-1.5.3/os/macosx/0000755000000000000000000000000012627373447013625 5ustar rootrootopenttd-1.5.3/os/macosx/openttd.icns0000644000000000000000000064115412627373447016173 0ustar rootrooticnsBlTOC Pis32us8mkil32l8mkit32FEt8mk@ic08Xic09ic10is32u0#{u ۲r m]jihGdF`帿LH&<]\fMbV"3aZlQaW 3bXqS_X 6cXoR^Y;X~gM$:4}h1y`+y\ *v͐Z (rQ]+m媢K)gᙁDE{q|f*FexrǑpbm$7Ybؒ`aߜ"=Wnpz`_ݝ =Ukd\ۡ DXskPڥPDG>2& E(GSFGR\\EFRVmXB GRUlμjb@ IQ[gL8]PM]Hܛ}w6:25IENJ@P{)% %8.7;7-`7}$Qk?0mf-4*A67'p=+73&/59" *73 05:!<@)74" 16:%(84#14322$"?.s8mkdC(B&< 71(?IqcV5d@mFlvһGIZ3$il32C$FW8@W*BS' CQ% DN# FL" HI JGzݱ LErɣ MC QA~ʥܨS?ӔIJU>ŹcA}n8깷g[%b:_z,V+d٬۾2<4ZSh1hݾ3@o_5OMlmi/n㐿7>klo@55[nlh-t:G}_<~k}ahyvzm-yn3O@|tyyQnsuyo-ur5LBzvySouzp.qv8ID|yhyyr0m{ =6/kBM]WUTBp.(C6653120 ]oDGUPNLJG;R$.4/-+(% +1wB@NHGECA@7B1" ).c07A@><:94$"#c .!+575310{O ܭc 1Y51*'%" ~ 1--c?23-eBxI 0-460#]?3645&%;Rax-w m}5x X$h a":ـq GW a%?E҄ a]_rMAp(Ek߃b; a68OMNqHFH a&4M% NrHFYFE0 aDM.YH NrHFYFz"r aׇmkM.YH NrHFYFeҀ aIM.YH NrHFYF v Z a &N.YH NrHFYGR Q ai#N.YH NrHFYG38 f2 aGuN.YH NrHFYQYYHg&; b$q N.YH JrHFYL %YYHՑQu0 LNYN.YH UHCY K &YYHN.YE UY K &YYI `܋ӋO.YVUYK T:&YYI$@O.YVUYJ TYY;%YYIS*m O.YYQYWSYVUYYK TY EXYYJ[H0R O-YY% HSYVUY>!Y EWYWYYJ:L O-YY%3 RYVUY<!YEWYU YYKm4YE O-YY$:YM RYVUY=WYU !YYKA)jcV> O-YY/2YM 6YVUY>WYU %YYKa)NY2 +j܎O-YR MYM,YVUY?WYU 3:$YYK y uޑO-YY!YVUY5:$YYM aP,YY%AY>$YYVUY5+B:CYYNC P,YY :Y?),-F P,YY:YSYVUY<!YYCAYYL+YYN P,YY&z \qI3xq& w \qIiV6 5m u \qI,vc ,^s \qI P VE P xi6r \qIw`x q mp \qIZq { o i ~n \qIA# KG o 2Tm \qI=& { Sq/~j \qIUc &2~~}h \qIl1v  z s~~}||{g \qI vX  =#S~~}||{zzye \qIA|]{ zj# 'J}~~}||{zzywwvc \qIY 36\~~~}||{zzywwvuttb \qI d"N{xMo~}}|{{zyywvvuttsrr` \qIGFLy~}}|{{zyywvvuttsrrqpp_ \qI~: Ӧw9Y~~}}|{{zyywvvuttsrrqppnmm] \qI}| q Ψy8V|{{zyywvvuttsrrqppnmmlkk[ \qI|] x ΠCTywwvuutssrqqpnnmllkjjiiY \qI|d \ צF.uvvuutssrqqpnnmllkjjihhggW pI{p3 ךmttssrqqpnnmllkjjihhgfeV I<y4 D 0crrqqpnnmllkjiihggfeedb. Hs1 ICmppnmmlkkjiihggfeedbbaa7H ~~n/ (&,nmmlkkjiihggfeedbba``6G~}}|wL BHlkkjiihggfeedbba`6F ~~uT3O{{zyyi:pijihhgffeddbaa`6E~~tM.!58wyywvvuuS Fhhgffeddbaa`6D~}}|#$;Rax)Їn6`6q/+ʉn6`6q/+ʇn6`6q/+ʅn6`6r/+ʃn6`6s/+ʁn6``6s/+n66t/+nu/\u=\qI\qI\qIFF\qIFUUF\qIFUF\qIFUF\qIFUF\qIFUF\qIFUF\qIFUF\qIFUF\qIFUF\qIFUG\qIFUG\qIFUG\qIFUG\qIFUG\qIFUG\qIFUG\qIFURORUG\qIFUR SUG\qIFUOE[aSUG\qIFUO[ڀSUG\qIFUOaSUG\qIFUOaSUG\qIFUOaSUH\qIFUOaSUH\qIFUOaSUH\qIFUOaSUH\qIFUJ>3( bSUH \qIFU @ !,Aw 2QUR=3\qIFUTV"1DCBBA@??>==<;::1\qIFU3Nݝ`A@??>==<;::98876.\qIFU3xp  >==<;;:9887655433+\qIFU9V @NH 2m 7;:9887665433210(\qIFU,v 2MLKF ('87665433210//.--&\qIFUMP T$KJIIC?$ xi544321 00/.--,+**)#\qIFUTS>` 9HGFF@<=0 m2100/.--,++*)(('&% \qIFU TTSRQQ/q 9EDDC= 9::- i +0/..-,++*)(('&&%$##"\qIFU TTSRQQPOON!" H"BBA@; 6776* --,++*))('&&%$##"!! \qIFUTTSRQQPOONMLLK & 5?>=8 45432 q*))('&&%$##"!! \qIFUTTSRRQPOONMLLKJJIH( +;:612100 '&&%$$#"!! \qIFTTSRRQPOONMMLKJJIHGGFE2.3 /0/..-) z $#"!! \qIDRRQPPONMMLKJJIHHGFEEDCC; vV  ,-,,+** ! !\qICPPONMMLKKJIHHGFEEDCCBA@@?A|Z.)**)(''#zi  "\qIANNMLKKJIHHGFFEDCCBAA@?>>=<&'('&%%$#  $\qI?LKKJIIHGFFEDDCBAA@?>>=<<;:98d*"##"!  %\qI=JIIHGFFEDDCBAA@??>=<<;:998776%F  '\qI=<<;::98776554338!Ӧw9  )\qI;FEDDCBBA@??>=<<;::98776554322110+ qΨy8  \qI9DCBBA@??>==<;::987765543221 0/..- xΠC  \qI7BA@??>==<;::9887655432210/..-,,+*) [צF pI5@?>==<;;:9887655433210//.-,,+*))(''& 0ך I>=<;;:9887665433210//.-,,+**)(''&%$$#" A- :998766543321 0//.--,+**)(''&%%$#""! GB 66544321'00/.--,+**)(('&%%$##"! $"321-00/.--,++*)(('&%%$##"!  > 400/..-,++*)(('&&%$##"!!   n--,++*))('&&%$##"!!   58 3))('&&%$##"!!  $;Rax%  m})&%$$#"!!  #h a1 $"!!  A a 2    a W[Ap(  k߃` a /!NqH  Ha  NrH   0aNrH  raׇkNrH da=NrH vYaNrH RMa NrH 8 f a ?NrH #9b qJrH ՑQu  KHUH      `܋      @      *k      UJ        3       m @       AaN      T%       y     c      a       a     a     a    a     a    a    C                                                                    t8mk@-/////////////////////////////////////////////////////////& iт!ҕSҕVҕVҕVҕVҕVҕVԖVo1////...-0= P* \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  \9  [9  [9  [9  [9  [9  [9  [9  [9  [9  Z9  Z9  ZљҚ9  ZҔT*ҕW,9  ZҔSҕV9  ZҔSҕV9  ZҔSҕV9  ZӔSҕV9  ZӔSҕV9  ZӔSҕV9  ZӓSpU9  ZőR89Ⲃ9  2_HH`4   ic08XщPNG  IHDR\rfiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Icbi3bŠi`P(bu!)E-͛7oTvv▖}-޲eA8Gb%!O:ugFjkkVP(1: ͟??:t#G`6M, Ճb0 JRg3! ru3$1r ?gលN'fCF1 wL;L  FR@PL  6 3AP3 ~I1 P_3D_Rb3Dڝ_Rb 'b&043(S/)f_1"'b&03(@/)fW1 $b&083W$/)fO1`Eb&03? b&0x3T __4KP"L DbA&%L 3Q4/)fѫD~I1N `53SP ~I1. `(_RG1Y/)fѡb&@?j(/)f"b&@?h(/)fY13S¨ފ@d)fa?]%L r30(K@d(f2+K!@àQ$n@uKQ'Q'C(h$==шZV\OG讘 bKE 1f(;/#VO1?edbDR0 RRR` >>e$­ b# ~RJBa0HNN"A1bBP/IPG\\AEb«h0(fSP W£ ȯP SU(*f)f>?3y3LlQ HTt'cN|LSz0(fS T6Q`eU@Ҁ(6w t i6[|wmᨙn;WBB3Py&PʕO[b&ГD [4cRPT;'$$PXXFA8NGq5;k{nޔlF{GptW>+xK1А o_sZj:Z-z$RRRt(JjĘ1c4izG$''Zt31kN)cR:9bz6IaaToQw' niAgx:5 GX~׌!V`'F!994222jN}IO4 )))RPP@zz:@gg'<ǎs0pajv>~_6JF#:ΙgJuP68+3?Rw\=HUxVIOO'334P$&&:t$%%NCѐ$$$0 Z-qqq=n{orJ>"5T\0-G/ް8s]J$Z[ Aضm?ɿn겗߽~[ͬKCL@$¿jG{{U5bl,'%%a00L&INNv/%= Ru5@RIBB̞=\=ʎ;ؽ{7弹 nsPjŃ ;;^OJJ YYYj!4 ?XxAJ 3]Q:+ 6!Q4pϿfx3&&&Ovv6j^Orr2dddd"%% |JVwmw=PNkk+Ǐje׮][jRu*Fj5ӧO'--|JJJ#))i `X3g;.wKwIsWcownG܁e3g74HftQFȠ"g߿?/r ӧO'55.L|!RɸqHOObM0z>4_K=^ =q,f$s'y2 N6Ή;Ç'wcڵk_ʷ~KCCWvG4iWY E nwkJdyyy8gU 3i$fϞͪUhhh2(kg%':줷 IApHj83rgKWi 'CRD<8Xvus{EC%1=p|̞=^{jZ[[l>$6NHcVI]Z 2IP)aE#YumG}DEEͲRdذa1v['ix9קe(y.Ȉz8|SyF#iii$%%RdmӦM\:-/YiB ~I4)y|uJ M455? l}2izpii)k4p F/x9xK3wlD DD&"oRRRh4FbrMﭬCVkvcB!Tw[*XyhiiG>رc477Jૃ- ޿@ Ҙ;y*Qac޳ xShZ /uNLWiho Á6>u42jGwߥ&P(JbM3N-=">H!%Qia_vu J9N8}i„ l.7l/)?o4qRQ&, /ޣORIZZ#G wK)e sO0xRD@7ϙf]obKZKӧO`&J Jn.Ѣ ,Ym۶QQQAKKKvmk~ xcBK~O`_M{n[|R1弮g}64?n,Nj%{C>fx OMM mmm,T*9묳tT\|rƟ8&J +h8=i\zXm=u+~JY\FOYY˗/ȑ#444*P(8sPi=\:81(01\.Tx|SE/NБJ0֋/Hnn.kkC^P\+8)W=IH+WdͽnP* xWka\{|w;xV\g zӋ(w~ x1FqAy%AAlonnF.ʤ`/JⵍǸ]:}ߘLo?+F, /RU@j8|0j $#Rd#q=+<(y%1&Я{ui7pf݅cYXx1Z;k6o&vB6w#ˆWS^^:D]]V5$P*s9|sG ƾ7~3g=-l;.7#ӴhXV:::G Bwɚ5k1b2'lv_7LrݟG[KnJO6l`ǎ;v%( 8 t:?շq^jT`Ņڈ4~1O.O;YgHc}$Biغu+jUG){G)op9I=kzN-2bZyw9t]ER*$&&2f>"€+%+.P3oLd@ ?Z޼{: ^#4=(mmm)R\\ɬXgy\7cLxt'k69dg}g3v͞={B-p `xkx!,aG!؉P1oTj_q4>Hw\.>A37eHSS3tnKc8j57teeeKL6  ֔"@}HԻvTsR^^cǎQWW MMMk,X^}U:}|'=#I󕇽ػ[<^%s'iZN1.L@ !?#_JռyI<xx TVV~6l O$= kk4 -Vsad/Xk89V& KyΓ!\<فmߖN;}|^VǨQ馛>}:Gh4Fb\x|GδLs|YԞ~P`"xmz_]'ϭV* k{|+-mõܚ=\.?>gĉpWvx饗x7صkyQ9EZ.Ȭ (|^H5Wy@3p72@ /9j޺c"xi |x_yܰ(˾`0psꩧRTT\0ZJvO?Ν;)++c֭޽*w309X4x2p}(=%Դ]ہpe7^@@o?Hg:pgխ??L0Ç8  l6f3k[[[K}}=wf߾}^fnPsv+i9@EwI']᫡2;]%^v IDATFj2'J_|$<ӶrXmtMUUݎfLcc#?~:ꨯgϞ=ݻ ӵz&Q;{).Abnݤ]WB6@pR'ݷ o'_h4n~QTTDjjjTUm6sCKKsݻ{RQQO'px wOӐ(w_JdJ 05|k YL $~|3p+𺪾pGYL?1yd]b#)A 3e˖-ڵ N%ZR!џ}'2M}YxL h ww 70{mYW^?>[Ż~ Kzk}<8`c+_݊N{K/%++9a(Z 6ff3555TUUQQQu/ijc\txUΝuxx_9Mק2O~`k.\@W@*+o  QoIގbZ***8r[lf125esULtu./Cx_i.\k[Ǣ~nX47{׶0{l~a 1.hkaGG8z(6l`ftjxbNG]pQr4^z@+`g> O>l޼: _ O7.;7`Ȃ XhYYYh4纂ݻwsϱgG)9F<4i K_&n_)|yDTq;.p{=@:{ڸFԊgRSSYp!%v1TTT~y6l=uˬ 8tʧgw}q*ׯ{}޲tȑJhXeRnW@C ] LE(pn i^p9 r#ܵ/^o01*5[$T5i&-[FKK cǎuFV F $E0R$&&j=z4---ڷH.ѕC^&\ aѕm0+m; oZ~8Bξ/---QÒKGs41!G%o^ 77ߌht8<K6jjj8x oNVq*|#p]K |zhG[?C FxSSÒKFqT(]#xt?;_7sA,peq3l0js5b7@I:;;ikk#G;Qs._CK v`P 8XjgJ@dww~.@1NK7(! h;ey6ksփ&gV*͢hZ&OW\_NCR R4jR__ϑ#Gٰa):(2to]s#HݞG¿i(C4JW?P F*Jr_n%,2?|7~7`{ﯧՆcoa0È#6lF1"l6?̙39t ~>w#p݆!, "CP[^zusM1қ'mx||{uoIIIINӝsj5Sƍ=))|RSSj$$$hthZ1 ?ш` 11JW_͒%KxzE5+eKҒVAU> uiJ~m#c(^R\0x8\7Y/}xb,x!€wN ( 4 z^R9ں}--6[ƛ}> LPWWdz>ˉ'Ț5kBVE Jis流' xX^5l#H~xDf36 Պ.6Jc{kZoƌCCk'Y}.r$ý`ߥr.τj9<@ɓtT4AU׮_?dL&۞۽+{<4w=%Kss3ގ5JzŋV`o;>Ԁ7h1#rap8ZmO:FT*juE~ ݈7!' &p9yr)^-7ex{=wx(;ӳĻMv:;;C2u{ԩ\xܾNFw8\#xxl0/dĉر#&GFFm=lF q# h]vٔ3g%%%oYIspoǭ/3Z[[X,tvzɵ-ࡇ"''F٠ x_%9'pB:TUUqeaZfRh4]U(o@_l$=񵬬fgרܪW3 a ~IkK B__m|Gۍ3N-477@o$U9묳;xjkwV y,'b26-,ՀF"B_R ?~IMV[{^xh'-N#błbM/URRRksl$0 }B~I9qĶmV 8~8g2P7K*K@ /Kk[[m ;#{WG &1NM/. 7@Nr~FQ9ѣG.eS_dm\wuӋ$&`x/o=Y'41L[[=/-RU@?OPPP8s%s) =9bɢgsvi_5mmGK%@/0" l]w}__f5I4!)zeH/I <5F )8s UuKKKs. . &dݭ,~IN&~IM+ {oj8Bb8K҈qqqQFSOq'b>@Cu t:F\H. _~ 4v+&>@W'Ko,o gAxl6555&[4d2Q\\ŋ)--7Gw~L=kaasq96aӦQW˲KYN%2_?w߮JNx +Ƞ?O̚5 зppGK}?kqxN#))YKK.)0B_R8LǫsO/%5Vn& >_NccL~4/c>7O>djl :WȲ>?4. :_~IM[v4iSRC4 H/g@ՒNQQr =Çn{Ge6(-;fHOOk%//T*Y24pM~I4`~$N{!7ñ-nnib_Vݴ.@ΰʿiiišR^/J+V{#+}X?crog >$#{+ @׫Xi 4}C4&'E( K(|Έr!LH=FCC[O@80( r ~!eeed86DY0ª*XR4NĉK)))ɄZx oN(.{H_E x@&ir鋍NJ}aE,ca82_jD>|8/`׮]$''hq1a{=l# KV;w.EEE1l0L&ZVgg'> Yv+Ejnp 7ktpSD7] gd\Gť(zJEbb")))dffGee%ǓN m{JEDQQcȑdgg;A 455aٜj4T**ʙf*V+W#duHx%)az*ַa-2  C*;vXf6os|qcg+|yo@K k b}MLJ4)>@_bFRi@j$''; B%@@8j8vrJ,X@yy9&4Yw~κ=8d#TfDL_w$ZjC̾$(}( ]{+ϡOt+Եq/|H "J yb:d [IJ&hj.K& =j5*Gr/O?E7Okin'G@Aj -M>cR-:&uN{s3pIr*}?\odhTL|j 1xS_;.p7X &")%nTiHk`KrከZhK.E/ 1 2*݋HjK->@0K k%٩> pa8q"| 9p(A[[\pO=xxze5D\VlVЭ еHb)2@(K~_dgt xD &6?Nuu5;w3رcfY'E>̔)SxѩpcaGy )SPVVFvl~;D7ej쬽 wQy,GYZZg\&m-kk~-=yٯH0kep7/ $W_asyN>,& 7`:p_M(P޻d,H4!8[kMSf hL:ѣ!P// rS x}>?V+˗/g,YYlQY-K2zhx{a|IDAT ֱ *ַ6u/UC<:Y^ qtym-뮫'#VDZ.eee|hTpt?: R'c=駟βe˜a;;;A`Æ ̜9o:NL}v8%N{1$2(r@ "#8Ç  6"x@ ]>odn59>&0Zd gC'a4HK~_sy+8Dj@֬YéʩW_}E ;”+')%b؅1pA $36fv@E,{e'!;/j\6&P%l6;jlkkwToJp牐;wrm1uT?R^^$ fcٲeL6>7S5|X~Ir@76a[uS[Ф ՗E(j\.LZ C{饗hhh` yz<9]w yǙ8q"W]u+Vp?l~3î /g5p B ՅP*T/x%3M7^@͡P(S_:OW@|κhuwCAE[$vjl]l?* D7ϗUȺ+xe/0c ƍGQQn~p<2>|lXz?N7 L<;/d,JtWc͚5lذkRSS|.5BaW'kq_ld#Vv>/bL_~PL@۷}~n?@]]I0o8\WY w /;v Vv.g=i_ X{|4 尝O/_W> k L Wloߌۏfq`^gҥ瓗dr.ѓ^z%?PWWG[[mRt0.Eg90;SsCwm'0jC_;L}RPMce` $*Fgf~"ZG-0bsѢEp L0#Fz,@jj3&^ ::qÙYpbrMW%;|u7Qt6 ЇAކZ_ $~mRa,ԟcǎQQQlf Sù28 X6v ,3&6? kf'̈́Z>mLCA ?@Ȟg+&އ(zwcJy]KKVkNz}UH;`o\iff- 1Mw7z>VǙR|*:7{?n@t77u_? C n'=dp6>V/)H/^(_&"3_|}|AF>-@)TW] J S} /*ĉwPj\5{Tc)VSi=M4‹I!T*yyyF"`ŊXVj/{Ph+</nu ub?Ia뀨"&Pwy?I uO LܳǶ$h[lW5K\򐴴I EJHIZR$"IyBEQx@JH CEJ[$Biصױcǵw%02~>fȱ9XJ -:/~ `J\ 'c^?Kq~#ZKٚdynѫľK ?hkw޻~ ilw~&6}>W<# Z إFHvAջu/Q$ D(Nw̑g?@}-LF_'[00"##p\bU[O_gl8{d!@5e& CZ@׀{ܱԿ@RQd3pY_.jPB3,ͥgkZ ~#∮Y_?@^3l${7%7D? ]~:%.!70LtFдpL g*]qoDHm}bvCɡ?qKkN̍,gMqm5t; =[݁RߜlHS9 ,fק뚓nw<~#$RX~(.92݁um y9r5喊i];)v6ӋYL1y^~sʹ%px/^v*N 9&kH?=d7Ro*RnAkҋYaz4坊&݆ Q+{oj=+P+boIQ*P+/T@27Dh7r`#W6$qsxx*^ /ӫ,~=l'1tg+$`bS+0).XwOUO ~^w!. hbg"{Sst+OD{`bN J97Q=F];,&ap {Nl\t}Ö a]?kI@/U)(= p ’ ֺ>+ hj#Q$ZbE!4pQ& H #`FL[jM"Vmg"Zq$q;~EP)vY ~K@#FD{.>Ⅼ)D EF @A,؊h^o`#W ~S !ԁtO&a&=܆,!y5j fDxmxN"bӌ՚M$ ,bk5H jAtY>F98KYn([1.B 7-nJ=ЄDW~}E @qLMDz [N[D Ÿ~!f4cѩtt8Z::UNrEIENDB`ic09PNG  IHDRxiCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- IcKل$,K6,b_H! C>1>4FiԿ?4Sִ~GZ[UoAAA@AD!@A @ADB  *s c0 sDA *dĿ De`:A7kzK_dI { 2 A1pwvΜ9W{{{{D:~/~=$<5Q 2`05&MZݍ^ѣ:t_  @e  2d,C, !a# !@e \#HDDB   ˮ`&$r l'@e(h4ʿR$ڃ0jxDA ʀ,ş  <# 2 A89Hc*D@ J?cd!@%J?or5\63ݓ 2 A K XwA&R#SwڌsR@b6 A Aو?LA(r! 2A  @ 9\ɧ3DeB tJ!ğA& *2C ) 2QY Q g ʁ Ab?LATdB'Ad!@:@O @ (2z(_Dѳ3DyB D)?LAd3DyA L)?Nn2SߢDQϰxsDV ʜr(}ײDRN @~[(Qdt C%L9?LA&DQ @G4QT3DiQ AJ(J!Q @A:QdHG!@Z($dh(D W'p>DA( ؐ }R9A Qy-A!@r[#!@Z$H!@Z% @ŇZ&!@ŅZ'A& PC& R @Z*PĿ BA /dpPE$ŇLAjb@& \=B& ^DC_DhHԊ @& rdDEB_z BQq.d"wPFT$ Ԫ@& Z6" /?DvPF=$ 3!@B-Q֐?}LA rDB_9 (KH+2eB& C-QVdBe? @cC-QrDj#JB 2DICOPZAd!'B& (IHt!@R5$J"S("%?-d"D@O 2A(H\C&tu$t?/ !' RV-$D @T"A} :c6WcXWx#ֵk}Z? !1q@ -C_? /w؇q4K0rR(()H9ҍ ?-a *o5?5=bP8H#/XFH3bymɗ~DW:b>p?V7 B fv̝;& & FQ,˵XvmLQސ v FffX,X,f -g hg`ppnjJL@.Fce~dr QHsdln锘 yLxEFdr QpHs ;x<Ԡ%A xFdr QPHs 36 . >uuujdfB< W`6d2sn7|>jkkva`6ź!b X,p:pz@,6dR wHv 0ͰZZlp8+zdRZX">K0c`4z}X)m0Q/$7!`̓4I2D)B--HJLQjPkKRa&`)$Dc5W2D @.3H " $!Lw%ğ !@j 'dh2DVF&` yZb"#H "=zZc"mH "3zZd"-H ";zZeB3$zZfB$[ņZgbLH "? DJH " ҄*$QŀZjB(,dBC5?A2D!@OŅLQ(&DH B d|C7AO:LO>`atq@C DAop}b&Q ]K` BN(IT0$b?Xd? >F#cW Xv\KcBB!/am>?>>ǎ#w gp8$?7Qhs ޡHT $Xo/{k=e֫B]]fΜ  $y Pp:O. g%@d  ?/wk=b  &o`aZa6a`ZźfF& !LWΓ+WG&H2e ou-Ty&fYdVex5kرcc~,_8_`2?,>w85kuж {_`iFVhW*Nڌ* P֐ǾHB#dmŪ ֫BKK {}gYx^a%V}+z{{сGǏG};v ^<|,_ت/:l1v\83ϝ_!`szg'=uB|SJǤWۏ sh8L&2_qAO_ }A:fhmmEUUUҘ=/Lv8o.^{ɀȀ< A0bBӃǏ]]]Ν;~tvvOkTvW-Iٳ$ I|Ybn*nܩx^\ŧҲ xL1&d mlٍ{ނGv466v=e8N8QXH70/JY<0maP(@ 000P(p8Na߾}1?Ls&m?o]s׋O?]+`V3`n:o?R7 22l:"x[w\hiiAssbx_޻g^(}|uR1Ww+D"BC @ @0DhBݍ7bv-Oۑ[w?(w)VUQSSZ֢ NVUbs`ĉ%䳏B5ˇbq\dU $OWT[,`ҤIIχȳ,3|ȟ+p> $ƴ b1 !cppP 8q%k^'|&np ױ_V]]N;-)ACCQ__j8Nl6ypWСCǿ,S_^"wp 2?5GqJB}:d}gn7n7<(|_>i^ F4E4"!%#[wށW|z+)Q[[ ۍ1QSS$TClB׾5 +Ϛ<*ɛHAB !Om'_P6˅)S^ a~w\xQUU*8 b/1^E|Yy_lĊ{'>L;B@ C⟚G_܅؎libAss3&O, 3ae?f݈c􅄵x\W"6gx7cg}6^/l6҂7555xhxS6VcqL&,]!< feaԘpc[H p$<椻Źn̞='τIuugl)kd2s |E>n1P0D$0L&\.jjjPSSjx<It vLK.nG808ҏ٭DŴj ) u9b3qo#P(Hyvd񯯯ǬY$ x~&$, Ofkm6 ("0# |xD `2p8-WUUC3Lӹ\.̘1Cx'0ť|6++ w)/x2e_U T'OI&h4JDlܸ?J%Ev!~2!2}60{ll޼YN>ٓӵO )\ya ɀ_ XףƍøqP__Zq_> /4Z?f}F#9u;{9 qAEV_@b=}(Ճ^&uBVOZ $v#ҝ'aZb`EiDI)(1HՉDɘ8q$v?z2qj?ْM57Whd}kXldC}VY4?񐾗 tl2@F A⟚Er{X8qx _җkkkEohh@mmv3AIw?(0czw`0`"x؂h|HD?/;? xYX4L@9SQOI1eqv]\ğ'>O9ng#o7X{ܹs%c "S%s *23'W:D$`&22Cf_-2˅Yfl&uuuϖiIK?gцEIoݛCૅ]Ɗ4XKw PTĆߛef3gDžpכ$555b''xy]td\Ʈ&s.RW96VK#$cь>Jb ( *CEt ZLE $UHg@R6c Qٸ;w R},pl xԇૈ~j2TȐkHʚP]]- 7ag-u[noi:,^w{DZF̘1bY$<^($L-H T2% @kH|nX0y??v'ԧڔ;v`شilقݻw?[ooӟT/4 IDAT,Ol駟UV^ы+NuVDRnHڤRWP߇xKSRU;)a.j/ֳ咩Y2%Cd(U0ĉ*Gc{|Gm _s~(|R=jI4'Ġ@ Oo=M񠥥E}>|>_-}C=_WHYi`Rs'x`J5ΙQ9- OۇG%cxK\Oqs`4 kh8rXvGnXWg$fYw"3+_b΃kj-) NFޟ,# p`0lNeAš6<;,,袋`6%R;hB2R_UـndtNeN!όذߓE!lşg^.n$8gOǏ.\;+!wߏADQ #ߴK;v z+.2lٲ}}}Bqc+M mhhĉ%lC=1|i]mcS@0ȮA޾kj^;ݧdVB9/(:BiX0n8ؿn[oV<ÈFkϙ~]2&4d%#Mr/ cJlڴ OC{{;~?088H$X,X,V Za!qgJ+Pl{|˓'>"d x2:'go< y^[[+?Ǐ[Vˬ'o~#)o]3)rr`PX&:p8gy^z)֮]B!D"kd2aɒ%mI~w~~q_~ If`7+oiŹӫ/ P0j0$qgvwJʚıdxJ<G8АЌw'uttc=N" JE=†.Bq%p_m!+ʱ/6AQy5R, Ϟ'?ۍL&XVIHf\zcFS;<qhklyI7R[$|YTAik.|&vIy$O?[o{Aww7$рx 5!+EDlrAS?_/&EXBoCyg}d{P4 ~.(G(+d[q4JY 2y(HsC?C'Fok6,Yf\.iܿ[^.?? '{ }O=VI8mx#z,]Tm? $L8w*= ouI~|%FN'Vx I迾ʉn=eY؂)Vܴo~TjzcVX}k8z8Ap``@qH@Ӓ%KtjDANuY_4 y2ET) HsˆGp:?>ݯ^~ ෿ FƬ_1yhp`&pwc߾}ֵ `N'O.ٶfG_ | LC͸K h"PdH4Bk|O/*)[ȇٺ=oHm3zDd'P>tx 7AK:$gs=hkkCgg'~?%=9`2p9Hܯ׋''0R' cFuup8W/Q>H5h!;WkDH K>;\4UK;v ?6oތ.@( `F#.ɶ #ן_*|< X2łj H3E*bC5RqW‘LyLF#,8p8p8$I޷oq ~rI(a䑼7oXjH$l~S=7$[G_ +b*w6_h$P*]RB_!ȏ+X&zȭ Кg3H^ 裏bÆ ApHx 8P3gdۚr@d) ׄFWJ(O:~3UYA4)R 5T _Hā쭪J,lbOodnhk@m* U#^{6. C(£>>]]]&Qy>y{ >M%])F.BكDi7 xL@AJ %|> Hd^WgKYϟIil80q/g-=En&(ϷN͋Z$~l۶M$&5g2l2ɶR7q|!k٦l_Hqh}^ BYM+_#P Y2ğHyE?!)fg*.c;nlltvv5`03@Uh~PŲ/p&+h+7)Pa1dDVVT~P$/cMK ?;nmu?Fv3kqzn,( `ٌSN9Eo;:¬ |~b rS=W_0l2 MWـWn<7nĚ5kD !!mh':,⍽J|~_~l#h*jʍ5d@)X(?"#? ~g{+$QD\ѺV kg7ۦkǶm$Cޠz꩒mЙg}~'cZU; mW:gI+7V 1zUS_Hg-At+Gx?W">?ďΡ|kΊVIMu*3~~B/vtuuؤB wyd盁_,C@E_v k5y(|9'5++#AIC7&Ls^{F@tI%e?0EFTPuuH#˅3ܸoteEgg'~_QߏN L5`A\'hk}#c(+*;,U۪l_^UFS5>ʂ/75.Ľ0?Oϡ^h.@(kцh,+sj箟$1Hl,-]ֆ+WK 2h4bԩhja]c eZKr/Bn_~j+~6#2 B*i&SŢ JFJVW!4M6tUm^MMM뮻$e[q>67u J`xL6vލI` ϮOٌO?]{a(׍gՐ#b5n Ȓ1GuFJVWABPh4[aO|;IbQvȅ2ȕϹn0.Ϣ7' g`2OZ}P?Kw靳'S`5' a#\l{uj|EKmIOB+R2;ԂUig&w Ȑ7.r\6$ F7>nSb7{IG1~xOb~~q$7̀w08>䪠p>sZ^u9r===(Pއ0@kk$ d452 Qͳnq}wx r!?gXuNvB#A&@EJxƸ8mOmhhH}փS2z7/c=&Yy8BSȎ Jנ\UnA4 F 6˨i xD *JY`=5Z;|Q19b$L@Z(\:˶T_-!`0(z}%n6w-]=8- ?wKRGK?-v|VdW۷o| ȇ^;Ʉ%KHo:$d_tENsV9_!1pu.2iP 7R\E|ُ6cB=P|ycv~_`&˗cժUo }|'m}p4NG)Z-{:6k֬Ak{EI<:Ch -) oN.W?/kng^qΨϙ)$`u2);{)!ς/?͛!j|y2t\O}fJ K\p!~mL:5GXǸ/|wXw?\ZǸNO\!ӃzK} "| uuu@l9 wrF];u /<XLFFJ(U@KcUumL;6Az@©^CXL|F M͛7n&˷b➿B{`N Nr JD_T%3]xN7m$C @8!<:K}AhJ@YU0۞&_jQ;sՅɀU 1 rǤE"ҏVCcCҥT硥IpZ@ B$y?k& `(߬;y_~ tGv]ߣm ~\<4d#/L x'F,0wy'|>_k"Vo'wawb_W8lN.8*J.8007|}}}= !tY|*HL$V qrκͶ-ANHMԳ^n%@IOi德Y-CnP`t\GG`7q%ifl67<lق/i7_y _ޤ}Z,LgOT|@hk0Y4Z̸qTtp 15磈xgqM7aXd :::$td\݂ < t87Qf5 XB&@F&[[~ELC{+OfG" InR`mձbfCMM z!l޼7ܬiFNVU)&|9[o@ Hg./x.=\77x#}Y;vLqUvcE$Io_Xj3ΝdFMy*#9c ۯbP& eJu1W:;?E]Tf[+ZGĭCKK "8;x)@:=gQł{wqV^?شiB⾌F#n7l6fVʅE*_5w$yimgWkOUكnt:χ}. H"%5Dzjx7qacLn|)%stnHwr y;y>Ud5ű.yގuX^/j&h4φ݋/Xz5>C :a8yNk4%wE džҾ&6XwpP5I,`C%kJ/m;)ץs|7Հ>8q>OL"#ԝl'`q{Q[[\86h+_UV.?Ƀ?#njkkYg@ %h4^{ +Vo:K ^Mv\>Uf&cXUj=h.q.c~RtYil51L@L7&IG=޼ 13Z`e5>/ePcɓ|r/ݻ'ND8h\.W-Ԃ 0LZl83` KV0 O=Π޷Hjz{{sNx<IfxꫯbW=+8i LYv,k6s"?is97k _iV%a{J(;P sg= _|1d' uu"Ju:Vb9p8AB! \Q2Fxf9i"Q({s-X8كw IDATG}ٳghkkÖ-[zX8ގKgq,;jZzms. TYqsa?Q$}}kto2u#K(G8|ytF=^DCرc|>B8\AM?WԄ@IOr ȑ#x٩:R hpam9-H>ʼg)ץs&j-5Wq_XwH16?u3jSWG5az}[X}vvi$f+ZGƪWxH U3_ѱ܃> gv\yN3ԯ$Iu,`_uLc6;T9+? NQCD\^V4plu$uIaz\H$. {0=Ǥ?s#M/ƿ}\38 eym0UyO|\w/-/#H_𕰙5WEp cti2Yo_ɇ˙?ޅf]bG}ya``@4CCC$9I|f8$##y=!Iiv\<͎O3R%ky|$Ρ+LAoǔD(9_ñظ7eO|,) qgchmmEss3x${axx&LHJ}[px.µshtˇ+|B/qgp,Οl٨He%) I5^H xfo!a0@Л Е,r_PϕNe io7t1~x>O @ \uֵ֩\dĜ7(FvRcC珞S`l!*o^dxix%gtc23$?'~$)j /f!kw3?.rEa…hmmEkk+P[[KQ_7p~!N\0͎k8dҵXl_n_R%vFm霳ڱ)'J$L ]9AI]?[WsOYWV+WCO,`–zq-`ĉ?~< FX22xf^Nqs'ᱪW&у# ۬a`a n2fg+P~ZHOWSw?]hq뭷bْUUU@ |`hhHL/fC x Sї (aP0.7W^4Oŧ|ш NǪ#3foGss3P__j\. # FpX|>:Ӄ;wcv[pN|c*ʲVFU],Wxˣ+Q&  Swo?J|Yy Ү.yqCpnl(pЪ< 6'`xxXxxX4?om=ypGݻqє`t7XͲ y|@i?tm/z|zCWJ-xDeE|hʂ ~/}i⏾0ybtH]Xl( EyS ̀|؀M#{Ν;ޞxNou޳X>Ps+@%!O^x3{0y5BcMw]UZŗۮ,~ N;`7 4-uK0 ( fEDBDZe9r$6|LY`oѫRGʋ*nu*JuūJd&K.+x@6=gk8g.GA|w~c>_1k,466NLdI| 0C{9l  H"A~|O Ugj ?:߅˧ >;$YoDSeaFa JtzUkǮ ?z ]}LRVSSsACCz,d ]af3O ,2d >c[XMr 8#Sꕸ+ . sg(؋;cCs H|>7o;7 "PȀA5#ڐP({b˖-hooWL?lל£Klw@zsꕡ+0Úߵ(&  3'USץ*uu a0'<磾555pdtXf I y# ;v 6lC߻igga5oKdXXw$u}߬W*˙P&IU5S0/))wnqǃ{g}L>Q3򥅑HD3,ڕ@ Fك 6S}WR.k(Nvr-w:k(k86J| Rh\߷к\.s=8IG`6a0h JC,*6 l޼{| ?[jFc${/0l>M@ }寱:BɕNeE|^,A)us%Q6,;DA6 W\qnf)F(O>2H$"ߏ@ ߏz [nE8NzY 636̪]=^.C& +s=> eE ~c*+Ս -9?ГSNC=I&%EdA TC|!~ vؑ>n?8φQIJ|?80o2SFrA&+( ׇ[b͚59.ӗK/SЛ d$2W}̿_VSr Ľ| B}ArFv`H%|Yy `5qmźDc-a4۱rJfL:UZ6 g'#7F& & f6 6 VU4{5558S![p84A!JIn|" ~Q%zf#)۝~M{ Bck ÷? <|Gn$nndޖ(>NT|3f… !v#!@F@(E<|4gxvڤ}Sv|%7zp9G=o#\H ЉD$(Q7̚5뎡)_F/:;7/G}嵇#~G6s30xƪUm6̞=v=6<7j(F,1bi`0w^1}8!.4<&:IN޻XBY=|% Ѷ[ <m !q #1@iD҉|=t?MxXyɘDR>T=|x?͙r み¶>mNK,wމ3gSD#h ۋ.x6qEXOJQ0w,}8~gkUp@ȣ @CCH# )`HnqƵ`$[{p,y-H[Y/64?=|c@"NQ{)Oqs꺣ǠլD3]DZ>i#Fgmmm n?jEoP^~􌵞G޻|mKYC#quĐl ]K3g^=<[S[?ֱǃU7on6\r%$2"Y1G2zE-'AOO6l؀'|t9\hWNa>OsW_GB?@1H abZ"#3ld2=Dc6afJ\ r|XPpi^z?RcW:ߡax C*L2_qu% 7@3o:Geٲ8 !@v $BR@Җ_ …BKXB([HHI !}-K<3Z<5HI4:E=y{ .(In %644n:~:;;C`B8nzn?e5 Jk߆]d, <zW>L  |v`02S &h2 M>ל;(mU lO{dpsgrPUUV\H>DH&Ikk+ \uU|b׹0kZωjks_.H?;Pv6 r|vT1юgݖF免^cGl6'O欳t@$3`Nr uvv̧~ʕW^8ox+ʬ_{&.e !Az*@ phVۋrr{q|)A" {)/045@_ا>>9f̘iFqqqA F)>PROF_@O> /I&ERh}%L@oooZ`kk+k֬ꫯ- wNѺcmLNDC d.?$F$ n?z[5bU}Ʈr]:#X9'vH(G04Pn4zH$ER`GGg?cvvE*h?%M2$zQ}9~F~s,7yw{||}- u< q_GWl  ,X{NQQa@  nkkcƍ|[ߢ+'1Z HLH&ժL&c@vϊm~{kx\bnR E%Sߩ8#_O/_Ÿ7hw7^D:{1N'. Á館ͦ0\:::hmmG?j]+ PO`?ImӠL?$^&`D q/( -6Y IDAThÁ,cwooN3`!H8NJKK)//p(mƗ_~V+(@*e1 ]_,~S]]ͽދ墢rn7. 2(/*d*y&@L ?gѢE\qx~msIO$IL@Ǫ4M^|l;^6}, p\+**(,, {1MN:'N? /sV>\[VTX,PXXHqq17pV o-pɡ78eA'zA0D=; Ghrm7$k~ʶwrpYVEzzz"< `Z)**b 6]v[0e+!3|oS 1OkVnڎ),Ĉֆ^^.V>vsg裏煍^ڟT{{{C} 8pzsXOb]=lp &w{uL6XspͲPG;_TLPWc_{1/_VWDD֫KK",!$_D/?C,\ǐ!CXx1W^y%'Ox$ˣs=Wa>J17B3gp@|81z:t(R]]MUU唕vq:!#QTTDQQ$a۹)//Sn_#F{!<1|ڦɮ|`SwwwhH,//Z:thC RJKKq:8P-||y4@H("\..Bzicې]WT7eLJ~Ygyg}J)<ĈRhN[[[(@ee%TVVRYYIEEE/zb@ |ymB1 V+\uUaQ֨JMـ7ë #~|;CGTIQɓ'3t^??M']HLM@Dk%:_0h)E pxr]#X&0 VR."yo`~|߼?Ϧ+"ٺu+W^y%G橧ʉXVƍxmAY;P.l@}|/Φ5ĝGED2(EՋXj|f@/@/$r~PQOn\"Mz{[an};K8Sؽ{wV0QGxFFR `@iO=<ڤ_Sx)'"mӇ(jSA/k~43KKKwx<9O#]mo1w '3|p6424z &CŊL6Md?-{+71|G|sw^~TF~ Hzp!JtttCoozz*zꪫ9rMh甦׈r-3`@KK ]ws᫯j#0sL-mR-魽0UhԶLI d &炿e.q"tK25f4%IԔ*K7777ۋWME{ytrwb'*kq; 6gD=5O,OU`l>SlٲۍsoDv`7O i=d`o|~},տ1A?W_G:+G&~Y&R`ٜr)v~=DÔlKʇ!gUg*yǃ>d\ ÆO}&K?; ?& ?-J/M 0 eN%]&QU>lkkkh@bi%;~7u)}~b4H'רH9 ֞j^/?5 H|H1iT<1 }ǹ瞋ͪhZzt29PLA>2``QMnxr466RQQ1 MmZ/;ܶO Q:::bYT@x`…̘1C}lj&6֏g04E+"\Lx`.T?_|;/lH&J$VVV* JBS ־G;!0<&@?я^>|Fhnnn3zh ^ z[p^h~(W_3 YbJe>~X?aH%%%q8P;._T_^bK˖-㗿eFy)@3SI /t(0~E]3/dx tM76lذoii<4HW7[|m@sS"B?$ঀ1L(fSS1#@^pԨQ\z饊6ȿI=3 ZoC{/oAz+R4)Q/48෷ȴRapM79t#6~~!oQ oT MvN| O. o9l&@TʼnJJJ;v풵p[\\Iz^.vڕ& //xU$_h*p.PH|<#CfBbN:::(?jwdf_ 񀯭NjOL?Z7hooED@@zITo,Nf5}7:y>e[R, UUUmx? j&hl ŀFbIV2eh`X,?яވ+cN] x/'@(| |u=DΰB}W/TXXHII 'Of…/n; ZۦSɺf (\rr/̖-[ɡfĂVB>Ӣx?'μ?c~.A@FaÆ󋃟[5A;|uW֤d4NE"0"0xM7)|e_6H4CτLC3D2 BfK Tn2 B&o9}J:S[|'uE7yWThfRa[[[X"< 07{aD.fpp 7p1(~cLc`ti.-=Rߦ+lh&.$MɄP/ haV ⮖C'65$E:^(Z?A۴je4uI`ʀ / P\\{ [6 ߟ=D/}^ҿo:::zaRGL &@o %d Uu =t| 4_R#N#JX?ܓZMQ P> h/VpT+( %|r| x^E2`&  @r%bHO Dz BV^Ϩj{o0*`K%{zzB"*)((!’%Ko$^?\h978|u<`.7nT|?2 JB^hcW20' |~$- OyG S. v9裹+[//Ϭs `ӦMmǛ*/&@W`X,7pC_(~mb~fzBDH HC3;0 xV*;Hu-Y>1@z^f n-9LP 3 BxYMʚ==n7 l4b/"ze@#(ZRQFqw2fvo[{T;friDWC#*?ImBYƦ̄PLt ozX-Pr[ccb@> L墲aÆq뭷rG*ꁳVs_30f^ޡ|>~x (((}FV=g S "A& 鿠lP^m%YqV$ D@qSM!1v̜9S>.}nDQ:W,gj2}tl6VjaW^ymp4 ʳe H6 %d27ǁn;Q؋$0_ N'TWWSSSu]sD{'Tn"l6[(oXc)W e2a& e HV mX&c'<]&@GGGX@>$ƥm6[QUUEMM ]v/@ ar헲,kYVjria)..fQXX- IMMMa.}.+/ & )bX׳BX-F#7i:n*͈PX^P`DߣPJjjj8))Q膛>yonO#~1ܥ6m4FᠤbV{>(Os e3nmGqr6_hP& [Il7e OssbULM:'@nN?tnV9䐰}\˳s$ ~\3jϟOii).PzB@~Z[#xg> 5 5 %=-W!uV&/ ,/ 0J"\( %+++'? ,H].{3x`*fvƙgIyy9n˅Hĺuذab5ctBT._("h4U %d`tjmmk92B"`F䉁P(,L!CXx1\s uuuayw7:LXJ`i~8r9]38C=rq\STTn1T瓪w9\M@M•|$ <`[a;Fsda\TUuvLDϨ&IlYV yW5$64eO!) |/l5 JJJXx1ǏJJKKq:_$x {=ǥ \P >R;KS[NQ^ł@(n`_ɷݜf~W+VI`Q0րp \'D9s9#8Kr}iR}W~~94EHxtݜs9=*C@B@`?7߬x>. O9W~yer _R0'dNE#X jl>i^ƗC :ݴvd&@LTEEE9>3 IDATkײgfpv/o+rQFpB FEEUUUTVVRVVпY$}Y>L_StB ph6uѵ/a^eFjkkÆfEZlP y1qD6mڵkٹsgЀ&F.x~,kwG] ϔ)S(++ SVVᠸB ,YDmvޑS2]F0 @vCUkNMB$ ~$Q4"+K=@HnP/V% Fɞ={裏4Dy8]&Wढ़b/llj2qDN>KKKCiv=~ꟿY&{&VM g[^/B{m&uxX@ ($ɐPe+L|8NII %%% 2f֯_ZL:59rRn#낍m uer8q̝;Z\.. Js8vBfĪ]]]Pl;u$̨>d_iba6Ϟ,3eWK]34@^X4k@lPI[[Nrz~CfAT <555L6Yft:)))pt:C5ŘCW(5i<4˄J OD5ru׽2J?NAwwwĩM!/((a\.WNgg']]]9n[.ϑOtFɓ7n\ȣv{ο5_$?YQ0MY.k&dčG? j O3߯4^~v%P?CSSayYL|p H%\oz$ 6(ɂIx7t:9C0a&M"I<yo_0b_hΝ\{mCp_M^ e^bܑ#b}[N6,BIlˀm,~$V4bMuY`y-LJ&y4@u9aPWWx<zzz =ټy3uuu3q1vXƌ@0EO_ (>#s9~soWd?yJ|B?Eِؽ{8P&`mx`&`D춙|!K߬e$:P^@>0)Rn|Ht:CX, Ca"ݒOκuBaм^/]]]tuua ]aJ 𨍐Q%I~;}b&i:4ʄ%LkgiQ@%AL_Dz#1X,/χ>p%~iBJ 65M^@0Z9JA1, KQQQD#$ /_XX:/yHWφ5}~*U:Z>c޾GO߶^ЮDXl?:. B4L@x rvF2Ak>h(FH:O3D)Sɖ$I\r%KCdCl3ᯟ /!$h "bNaO?4U6 , i!+2[7D@a(̅a*%IW_}5wGycʄ~J; ƾd0Aݰ?Iin&`mml})Q[5CÚ ~$W}---ah&#sep88xBCw dâDjooSNb^9Gycʄ~ M)kqPD ȇDC&Ԙog= ivD8 Z˔"$@#-[pEq9g<d$IbƍL2zKK9U9tȄ~J¿H(b<$j^5^S`?sڈ& |V%K{$IKKK f4 s%I˖-c֬YlݺU=NK|h{f(o"2cQ&@,0 ""`p+0nmc_h&ܷढ़^૥ ޮX H> J| "~AZJmFss3mmm \Iwx*,K7LyF<{co 0&@&`/i6n!K> 4.yv?"AZBUMMM6o6/fҥ466Bggbe>3$ ŋ;êίg'V*ce;V h{ҺU4d H@M mZh UO3Ɂ?@~A#~ 6WQ5:pc6+DqLKLD%I^{Mp^r-xl߾݌d$IbL:e˖~Qb>8f ;Vc'ke%xd 0*Acx_5>o+ ضGUӊ:V&t*P, "BG#?΁NKB^;_~FZ[[줫+bb_$u]ܹsٸqu >~;%=.aE2j fեg L@?xg#8NE ]:dZn%Kg$ \QK._9p4`Æ 477с U`J$^{5?pz!^eخ LKh4`tCav kq~W|7k5#LV.J+IXr%[l m܅^x!wq;w5d^n8H$9sY`ARssh?_h6>FP۞CoOqe7|]~޻t[6%0%BP<]#K" x<<,XNggv\M#3n86ev,xd(Ok?cL+ Aй;)T4~0fG\4}a%M2-syz/+&PUo[ wU$+ۯ>,рJ¶C`yE`Hi&N8.2-cpia ;VkuW`awLv&ÙL? L`L@ߤw%֩N@uI`1@> Uc|A<Oy Wӡ<½qϞ=vmuYa"M4@g}YgŤIXzuXz7r8s);?BAPG$8& 4~pM%}ox_ $}r0>p^)?k{{{X,0hc<䓊mx2E-bjmڴ+K/{::: M4J\Zn~:ӧO_K+µ`B8# ȥ7\%~X hg $^кu*dL5ꊀa%ճ&$I_W$٬po!w!<46, #ݷ>C."-ZēO>ISSS(QPP/4dpM{1czXAIi`O @w)b ؕ$>/gܝT tǔ%HMԔ`M U>!0xp;$Z~ Q_|-œ9s{ؾ}{tuu82A 7d̛7UVEl_ONI҅R/Z69 & `IMbXFR l@1JZ^-{7lxISvR嗱uKmx/T8* ?Mi2Zij6][d1øq2d9CRUUᠨ<#w$Ib޽=e'™I,?̛7I&QTTjj#// =ؖ@ @SSO<< ~i.+GC^D1;ke{?ɜݚ/ז= ,d-!L3p*Ӿ% (%Gm<y!_^c…q?^WWqGuu5Ce >!Cr(..jbXe QF{[ϏZ9 1 0qDN9-ZD]]VPD@<ԑL ?@Nj/O?ͻᆱ(I#z=4d(u2_-xX#fc uh2bK/4t9GΚl1wÙo?w\viTVVRWW0n{/ry煶[ᛳS;%lwWje̘1p uYuQ1̀@{os=NJ+–捤GuI?Ռ-휼|X rNM d Тt_(M@CTYmr(--Aqq16M3>!/ ˏKŕ?| ^&jkk3g>s%??JAA"_@R' $_b ֬Yٶm[ ~phm+7X&Zwuij?~e|Ljb5Kwc \4Kahcz89J~*AKX=oYgEaa!6-k׮eʕ]>h>F ss٨T_@/+Lc)%2Xm0jOMl_2/k&ืWW( vGcC"l6&@/I;v믿f֭l۶۷k.˾}'%iuhEBV]@۞MA OT)3 Xf7FP.WvW 7$X'U  5W%塇trBs!z_|]vo>nVg&Y>G); l~ƒ}h>N2ៈRj L@*?JÎڦ=m;2 WA hq\>N2}R+WUUdn7TTTP^^墤VG`ꪫxG ƺJ8NU:/.H^EN,c6jO3bԷ jjSaZs?+*jjj2 Ɂ0$1bv{0 fV!0VFPM Τ\?h*|I$ݐbUk&`KMQ7|eK>nD ؽB $Ʈ[a&z{{ϧAww7%%%q/E==WtCu١F! .\72˦һB\eydf2j|5ב+40 H)bԷ L`JD)UШt2Mh^XRt_(& OC\?@M@uie4L m= _29&`02M)S(6ɡ?< 4M@2/ $^QB^)1 0e*Ě(66ɜ7>^#&S!C0 V)ZM@/U^mi'iLJdqTT؋h ɰgⁿm? aL}d>~ТNqq!2zM̸% m8& ^ *'Y󰛺MLjfC~FbД%Nƞ x!2L"/ `?92cQV ,}4aI{e {>J- 8m2rB1&0~0zGX`+0RꎎvûWwF\ &)kJO2@M@_( z'91dS/nf;+WJ/ 0$(IDAT|ec/ lyrb ݮNiLJR1;5OWwLOKjGgX&@+  D`wז&HE~jêKhH1ᯟ2>&`LQW0/23#OJ ]CY4L/_(m&`H>' b)PFH }4~0D&KhyQ22B2r)Plв?#'&V7!2|ZK4M :L'0܆M&`|}/dS'vV"\h )k d &`|~ c4L ^ziimĪkv$ÿ?d 76"'&M~/U 0e*q U9ₘUT`?9:e]ҷex"2Rl1M@}3O@v7V$4կus!2]P40m3fr 2?yB/cSV:/6Cg91 0|e6u.**~ 0e* !aFbƽQM }rt7x;En_[%fmS!#_scIpU?)' d nƑm`S!7|%&*g d nT?oo2M)SP**>vmid*&)e}ߞ<2RUr L ( d 6XڏiL[/v_7L )' d HC3M)S;ke{sOr@focq]tsL`*. e uPL^9m L@haMi?w1rc;L$I =D} !v,KN/^i5cqsڧ9Or@fDU%T(L .mKiX?O!G(`cwk;4 {wh_ t*R9$I$/H4? Xvs7(o>}ގ s93 C&aUgq4M#m7aߪ0Y'I须.iii|BKz{{s ޾Mu2I)عxb ̒,]'hl@1JZ4C* H:M&氆LMM5 p8J쵉wk2Vri9}Jm~q~:mo:C&P)-_=$.Wal~?Ɉ?VqXtXb8fʌDQ#]oD7BG^QƄ뵇ޓ H7tХФ+*K`ِo,&%E& 41n/im?vR7dޤ_4W@zC儻'¢a==d_?7L0n~O6kjVOp4R-ɄdaEC)9е`sS ކ9`*_f 7o_W@m. м{{: 2MDy>6O3b#Ʉqe2M@PΚ"oiBߜKRk>1Mxe"?jm|&M c4q(M,1,_>ƖoiL%]FPƗiTAְ 0Ne2  a>ײ?=/dS鐮%.@#$(&` nFuiLRz[4ÿ~^0m7 0Y2 RLвxkqD ;زt`5t98woڎa 0Ÿ+_Xui3ywQ)6ƒ)'30He{$ U3`J_ <(thXyDYFLgLe CooOB 0tŘ*e 0៹2 @d>FU 0L BL@}3l e, &T2j E2h)&4IV.Kÿfb OЖdSQ/$7Cg9}nLgY:)f d#~I_,L,aceZVvl>svxn˵i/ˈLgL2 ϒ6 ԋ&66kA 6 ɐL 9t=y?;7OpiGw{9k6qLgLn^H H'L`*F N 2  ݖ &T2J 0៽2sR|iwǗAKɃ\fND +K|[b9&[Hm|?z_4U_(^0R 02Rt$[?S N  J Gnmc_4(/=;.4iR&uB|8Eg;44-7KHle?;:?δeZڴШ $h"1hQj Ƙ,ntcµ{.: lhMδ33{soǹs{{L/;s3koE7gO&7q"߈Eɏ@ ib0_]d'OqWxGa%..J(!~ =wۿwq}ÿ~.w=RgEmG?o[Wao(E7Zm xVο_(w!__ܞ E@XH($HY" $HPJhp5o(E/h`ഽ0_q(Y[ Oe0y$H@U8bh5 N("o(#CHh{M*КH(%~ŖXX"?$1@dXo E@HE Rj_1 <=AD5м",n^IG/D9G׏q\<A]½EmmqF?l^2 ~'$h6<Cޠ"`v\Z:V"@1t.Hj4$+Z j5_Pؚ_Č@ԆxIFҼG/bG jQF⼼E/R@k^/˛Yʿ5ϫ5?}~%FPdef6~TU[L/f ҥt'/?7}wt"y٧v:uE/G `d!^kB;/wH" t @4YɿL($ut/A Sd+b܊1`Bp8 d3[~-y_DNp: {CC8ٕ` 73 {FO: PF1XV1`{`p2Z*r7jEqA1O_@4N  '8$*#"S89ӽFey t/EkDkTXpp'oqRw\޲klp⿩]6(e2qks'wWq3l'%zE_@J 8~ y9m;Z&z}R"`79챿;Eq=AϼFEq$p'AܑϛB ŕRt@8. q2w]r't@y Oq/ݿa y٧NtJ^\Z_I/F ZgLe#lU;[ ].B91&RڑC9E(D A\q^`Vp;5_6 ٖ P_fDgg!z#vmݯI"H"Dݨf kv5\ػ,UhY>'[hۢE(DPE@-ougm4j 1D8EYzb]U"HJR6J`b?l(o)4uO-J"H"X.͚{؎yw#آ^J0h;+)ʋ({Sj;Aӷ-?iWx0~[TQ((tM;\1!H""":vيVv(bG Bd!"5B!D(B Q!B!2I IENDB`ic10PNG  IHDR+iCCPICC Profile(UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic?H0j5%7x] ^SP(b&3~>2%3fۿd׮]={ ,^\v@pjQPL??\t ippPCCCZ[[>}+V'w9UJSÿ&^Uh27|#駟?44!$~?(i:3'],(B\*c_3xGѷ.\?%Kjn[I#4jbـ}"T;/_J kddDXD nne@T9 DxxXjjjR?HEhJU + ###jjj+%}_RVeٖHT BXHxBK;Iݒt0(X!.m/AHT BTdd.uM,+6J4p_§1/K:&iDI1I㓷KM`:L¿JW5Q ;nT1 BxZK% Mޜ(2DH¿񌎗(D @բ Bg$}CQe0("TXHÿ2gc((1.@/St^"0".@QP!U%}N%@DPEߠQPf=mbW):%U2*Gg/=~)%@@+6C'MQ A9ÿA lX%¿A Jߠ%oP J LߠQPda %" s7(OI5C@TS7(/ÿA @ JyoPP(C-F@j1. rP(S !Jʊ!e(>/Jʊ) oPP;(Qߠ6P%Տ(n8X?%Ջ#_ID$pT 4e??J _(F/%ՁPC @Q(7 @!%E+ң (u_>.ˏp<PF&JeJy:KqzStHKjE%E[Q FQ 6$+Tf?& P jQkuUzңP7ΑvWj?haxҢPuP(t(T?>J( U@U @z_P<BZA J%@^( BȆC 4( wB%@(TP(J@B Q?(#JQ(+?(!ʅP@Q@& %GT %GJ J JP"@Pw+J@QaG ^Q(?ZPG6 Պ@=P?QF J@^ZC QP(2 9!j)ΤP[(Fԋi1J@ @Pk(dE+J/?Q<@ Ppe(T? S8&Pf2G ZQHs'@5 %jC@(TJ?E;2+a:С[BG::y@*22%򰶿zا7%7s_R%@R%@!JT  Ȱ^yuP;^ԎCuhP{ iߡaѡc#:68R (T NQjݎ#ڰ_wk~mm@ix$QQ; Qi~mӯ hA::X%@KwZT~R+:@!ּzdDn|MOn95/Ҧ]:0&@XӽqUJB?ȸ|@Ol>gG@VN"͛';컅~ K@hPuj402ۧMicJ$* 2k,b1566܊W_Pj†Td*6н#_]kfsӧk Ԕ&@P vvg^s/сJ?$_D"D"jnnVSSܜ~H$h4:%so3Ǹ0 P?_oWT=B (FGX~oH---X,h4h4tۡmߦÿ]eKZp=:}nfOoC)݇޿{BkWXZ>jn`JPq ~yf!ۣڪx<6u":Csw~^kM`f r!]TWW٩vU---D"@R(T*d2d2q]pZv}%-]0Co;O׾~NMo~|wN7~%Kw9Ku\}xXoڣz|Z%@AIC'o#m||%P(DGXJr~Y9KfCW.Ի. u?ZMJ?]~z+0 SpJ\P5J}hX?\M?]{fY 'Gݹ~o6 {A3h0K aX/M-t'E=?/|r(g%u'Who~J=5% ԍqNy~7 o} S}7{-;u{|MMMSD"t7E  ,yiG//;n: ~>|"ܹ864?y{sN x\Ͽ}/а&%Ң0-++jw6jڴi1cOu} A A> ;sWoi^gyzyfǢ]t>źE;oPmFcz{{u)dϼ|TJ?oyE{ϝ0[ J%CT)?Jm`x\wfӃ/iaQ\ӣN8aJ[g$ovWA7|r߼ 4S"訆400cǎ_G՞={gۋZaI?XsM+9?2>u zHD{nzJiϽ֭ȷصk~icQ?S7-gJBQ}Wto1AEQM>]3gԴio-;C~P9mojl%[϶߾qa߼D2kqR)% Sѣ:ruYF6m޽{V>}t.Ia-̙3G-A0ߛQ=_K|nϐS=N%2HR_z|G2։'Yf"KG9G݊g ev\mF]R8yÿ4Kf= :v444~mڴI[n՞={ ~\f3^Ž}+54<&Km593ŭX Iwy8y o]Ნ_KV\ IDAT~7N)Os(TRXTh43fWak~5?[7;{v÷Tb|vps5#^?J\fK/O?]K,qF+o6JbL{;j+o>t,{]1L;R)R)tI}V[߹/@ﴨ%@/-yjERRIJz0= N[v*<]]]~K9óך}n#"nsw~%e*ܾ>nF }ࠎ;7/ayl$8::[j֭ڷo_A1Nh-\ruf:Ϝ~.3R)mڴIwqF-oS4<ԃ/S~lz9@K@ݡŶn}'k؆yY3fٳ17ٯg+Yn7+{˶廍:MV*86`||<]d,L>d2dx˛H$~2LFӣmٲE[lA78O{~n}W-RC+x koooWooMF74\ηT*xڱc}u(U+i1u͍%)Xf!FG1|} ::0Ѩf͚9s樥E\C[w o^7/@ LY:8; )nS6[f x/f3l{ߞo8gێ;z꼊㴹'7~!=-]TfJ>8AhiiQ,r3%]x?`O+WzozW8ϖ~P6Ÿc)OCå*$fu)?eӮ~},aKkkNiֶUmQ>93#v7 ( ߥM4U__fϞ v4w~{ݳK H2?Q~}^oB.QgssS^Y8_ؘ6oެ5kС6lo~w>8h΃834} g7a?Mx\x\b]jP6Y 544y"z8Ks)@(!zgb777OԼyNwl߬m[#n7_:4;UsYسL `FD`Bmؘy=s:z4/ַzGOoڴiz^3?֖q 膐n߇1=+Nw?xqXi.͗?s?nXE '@QѤ>Z䯧G ,P[u$!߼7;C=?~S}/seOoSj]د#p}5kn:;v,sY]1pgu=֦[[[[z@,N^3n&z뭞=oV}:4_?w5ߢM[Ү<҂ 4m4IH=w:wNyMt^In}~nJ7W)`,fs}Y=y]>=չ,;hE)ΰCs]zr3cllL<>zާYU'8Jt_LOS? _lݹI#>v5w\tI9ᜂoo;ۣM7soKsB/Qg!م۲{y+ N$ף>_|Qcc] y睧snOggg,sar[z\066!s9"~k_ߗO)Ws9/%( #7?'6Zp"umh=u=sg`wNwK#A6I#藇w1}@gJ3f-p>%{C={s=uiM7&; 3A,l JR?n2wiժUaKq_)fa]g(jw^}G#9ݯ]r%yO7}so~^kݦۏۼnTi{L&3ByyYdR98bSy4o7oZ]VO>dHD ,Hn{c_9S.rYo$I555 sT*/طxũW: x@w >ڣavWT+?uvIJs%}V%@.'_6HJ5444P BxJuH$^͛7/}Y?sw97Y*98KF `mV=3 ^`ۜϟo+2cΜ9:SrL ίڍ'[VnΛ;-#xH ]eR3GTq`P~ =ݭSN9E풦ۣΩML7!Ō`YM6/~[`n%N2#A07\j^۷O?h뛲f-;/w}owMwB |RTչLbD":3~*j {E[ǟwj9T%*F#;[Wkph$}:;;uꩧMR樿k딝ž!&v' ë_`F?u-ZZZ%)v}{_[zHYl/s_KlZN[WoWV~l]7c P&닷~BNgϞ wDog~h?NοM``_BйG$^`kϷڿxKSg4ۛ.*̞lgJHo~ǜ+$_Se&k֬W\{ߺJ gƭMy%#.MhJ@աʀ|$ݫvO,'Iv@qNO˼F %"['ȶ_^EsOsy}Zz>謳R<O|g`~wx:۬7ke0 :'ҥKky9Sz|s=ısg nwyxTjJ@W]~L^ܩ[vbmϹߌl ^G 0ExM`OE]8 1Mmmm 36,5`y{rJ>Ey~7$J|~'@?͛Âz&;ÿ_wFЌP^سkܛ5Kev g|<$wʹqsݿsLK| gryk6+Ew[']-g際JR'P%xl]ȱ@GQ-YD'pB躽HۣΗfǞ9`7- `/0S{3o.hgslݞ9cihh({{{23+eZ)FH$ڴi.B>˵a.&S߰𨮹i 3: ?_`-[vIS.C5K{m9o?&7+s|eeeK+ Y&X{-0E{e/q|& .Toovy=?^|e Cݢ>RB(2?q}O_ww.]h4*Iya߼nZ3e-v`?d~Ehƴ@3fS)@sssw)glʔf[qVߛFgjhhYg[f}wNys_v3uMQu("?'w_Dg͚%Kd\7s^܌H)omW҂^]8/`$)WbXzι_F>s.Ǜje]>k^>2y ā?]s 4_,0բ>~%PO(?qowF 4o<&x f9o0ި0sGLy0Ai>̞k+׽u/.y MV68{Z3" #?~%}'kHe=6hn;\o;xQ&x0khhx{a=r[Vc~ZW+yO|iN[t(U L d(v}_VH$Kjڴiߞo_̹[KvL:7#ZMMMSϺ=snhUQ ؿ4.Ws9J_5?snъV_=F P?q hTK.Uww$^SfoÉR ?= nm8>>>h3#&;/6k]/Yo=.rG4>RSvl_Woj~JV'?ԋo?RXL˖-Sgg^pM,{PLG-w3~G:^UX0ݫ38C =I~ uɒ~$W\q˛v%Ğ@1ؼ; Zl::&~¿ߔuN$'0/D2F?e¿a؟5oѡ6ː$?j3nx{S?{Y:c6s}5 Wf~f?vHb\J&2J)A-g)M>`!93sr 8N7-[=y(:$%JMޢ"֭i֨o~ifb ?1:5_VoݟX,38cJwNw^ߌ3 Pb稤)η9c;,iH$t-]T##Kgp;kЏ.I4_.r9oc Z_~\U|X 3ׇLDlٲtZot3ё֖~ȤN;l{ƌs6v0tXd[GG-Z{L|?s?[c?18ϛÖk?Y ERjH{?>`3AdAGwVܬN;-c?{ThokkKo{l_-+pcإ".R{VQ < /xHABq9?7?:v:{3ߌ;;ÿ۔so/ѱvw3 ϫAW\q/ױq[sY|C-(<~sMh-|94Gm,ZH3g F.]F3vg?g iLacSS.RqcGclwH#*`@hn3(F #_c)]'@cΝ9sL A;SQ:J@Ԋl#nqnNРx<%K?PȬ|S缥 nSՍp 7jٖ}ӿ-\p(bza &J{o]t}r w9>۹g6f ne9P( /goz\{{N=Ԍͷw7`?7455+=WQe Aw[t?8H T' `غg@o7FZt%)cߔnS_g?'`/ cҽ|k/`$yH]aǏ\wCRR2%%SjN ? JJ408SN9Emmm4eڿ3#&¿?xq^ZZZl2>`i.͗yK+{l~%ܶײ7o},X Il\o7K.k/}7}xV)LJ (P(Tb,i $|kkkiS{ov'(}9uuuu7`.;kc;gYq}](30@]" IDATg/]xbE"I(݄y;w^ ^4553ot<Nɉa ~s Ky~ޕ)0@!x@͝;7=73vbSv'(y$>/ ު7E ?c 쏁/ ?a$1J$|Ԃ Lÿw;߹?@1466ꫯ=~m?P~盂<,-ݥ^}Z%@PnQ,_m1HD/NGvw fۿg@|rM>~;X)G6_?uEzJ L(P(mOd?gutLk7{lqIS៙o8 G7߬??ѥ^ٳgMxJ?D>-I'{{^8(箃og"S4o%P) T'Ql_ޮ>;=:oF\MPGGGƥKrիzj=ڰanݪ}il}{LM*R2T2ؘ뮻KgW7,:k7eyޗAB~M;]E8gQy'$t/r8`$(_Ҡ!IÓI 6>yKj0ߩ\ŶnYb.\8etޔnMMȿ#_N/n=CZvݛ5{nI===E~@qK.R`Jӑ+N/O~}]Zѓu[JQ7x&f$51 @ Z?Js?]czzzҗ 2^oo__^-9s/_OӺsμÿ$ [n).1pذn6LU`J.6Si9~~$ҷwZq&,hGOf9Pf@ 6}koh"I3sͿ]ufQ6l]wݥzHVҫZҏjժ(Dcc%Nܹs}vݷΛ?2~)@~(Lt管@NI}Zy"]ʄ5RAho__Z[[MwNK~mۦ/cw$ªAT*cy9s} ߾xdk)f?Nqx_W(#P(у=M͓=.{흸mo\%K[VÿJ(zyA]vkwX2{LTASȧx<|}~:gA.9m޴G g'ߓTJ{<vPKs>ŝQK_j`?544/my]4H)iP8c7qlT+'K  _nzs?of0?w6l 7ܠxhөsvf{4gz{RI&JRjjjJ986a||<羞fHMccɤtW*jdd|Xo^֝u=?ylJ4(P5(YF4cƌ)Ω---'?I?pAjGe3u3{;-6?ed21555)J#)YTJ~/K˖-|g:{lOC:ChllL1٩EβY(A4_<6DM_gD+?PW`%P$ bKoF[[[]ÿۮ6~oC=9"f`>ų4*d2D"U5ڍo}۞~izzޠZho`T",A^xoؖm yHz{k@/[~~:S3;yD Y$)L5/գ>kF_Wuьw.3' P\nE]{Ƿy<5\?%;ϝ% VXwْn3BJ[|D3Uܦۣj||\y{/YD"}=Aw|@O1?L ?'{=(={^ס1";['7)7ǿ|8mFn!,0!֌h;76 ۻw>1l٢} P|r.H&Ƥ{_0!gW/6縎?BJo^Q"˵$)cn߾_phY߸ ';]@w2 {$m@5)V~w[wu1"Y)08hiiҥK}&eU*3cxK >T}y<6 ݤd% tS|?m4uttL77kMa`ߗV^|3mG>Gz|*UUL`5Cj A?u]۷k`` p5{oFq4F#f5| 6Lb g CG!ג܄Mvn _Hvل076 #c{|\{CSRjIkfO=QK]~(۾u7m.r~g K M| 'H$ Qw۰iQѣdN|e[Ȫ3`P-=Oxh D1Of?PZuqu^H|mqWp^bŋ+w6a_sw߻\_+O۸/u5Atx HDR^EOʷex8ȑ#M+˪wZv4 ;w4V;+wfOgZF[*6?dƏһ6755>Y k׼yPSSf1~MjZbLo*$hIʛI~SS2dHz>1_ ٚP(uR뮻Oڝq(Y50.[-[/h!iѴ!xy[ۋ{ }ve fNKV  OV[>]~[WK?$B E$?MyYi3jԨl+.0ώfy睦vGU㑯CBƔo>WJ&/ ﬛+H ߥp(ںu+/`ŊDV6lbyϽYglmnm~_2 m`| #g]M$B y._Ww)G"FOw3H$|rttt(baዧ"^E{Us;htD .<O21nxv---O~'hjjB[[[Vm>@KrX`ɒ%J}G~k/߬R0L5_ b9 :~K}0IT$D y*LJjyyyh?)SoS;.?'T;IEswLa$43=bYiyyp7cYT оXВ͚5 ÇW{vC3 o@H&-AW-$H$QI~ҎتaFq~?t?SDw}݅sk}P1vFCsTs3Qb׮][㏧bq@Y]Z'1(0{le[Z &4K ;#e - <?oZhÇϖru]8|f¨j{tB&KOeEE0]6w$^2qnoo/KG?BsssV @V P$@)(++… m9 oZ~??g ^$Ҁ(@r]$?jCQJ@_JԺ٩u2~CWLIRoG7f& uժU؈٘b  ed*++ŋX@]CήW3&<I|d&DAi@ *ޤ_0Eԃ>F հ#4Ϯ?}Zi&|_Ů]2Ȗ]X0@,Xv$0uT;Vٍ+^E*35M(@*y,I~;;5a{οg0>?X߹t2 (:!% ?s(l1U]pמ={pcӦML~IQ]*(nɊΙ3Gv6ÿ|f6_7 @ARi$WDO}xUU˳&beAqݿgWV,;}Fs~|8 ﱅΘr<ƅ&wL>@gĚ0m3^C 0ӞZ?rꪃxsc)@*YLIVlT1o'[oz֦I3mWpWfaJK/ڊx32ĺR*!tR.=~Ufn?v3LmjB (@rT$)sO&A\aÆ-_<$3<<>e\ VYMI?iP; Tosf*zH$Y[HU0ݓ4vg7]WWq-I~ AT` H%'?LI]-HttBb>_ |[J7ֺu/=H.l~}Y}Rv߇Bxمu^?>f- @Tu͛lzQ[Aހ_lA |[i6==~~>klrEߪ_v:n tDR"'y+=ߩN¿* lH$wcE8uB)\~5kDPO/{q'" [z7xwy'=Kؘ`;P %1Sjɒ%0m~Wkv 3 RT2))'}q: > /'x-o<>~T%|Og"MG sd?tT"a|šC5e;`R 1&LP{~sM/J&r9[~=H" l䞄:P ڕ&UUϛ]OiСC+~~`9Y=xpKWc-30$~׮]я~#Gw26F5X@:2̟?_m(7I??2u5ex?]j8 &vχKz~SAQ (@$Z?V @ShV~t?c7Ny| ϚO$L6{/S {$|,u^#< w 0(vc׿E)@[_l< _\of}uM?n\[M IUST\)TlgMPKҦtycuqj;p,k7-,]ZkRq<3hmmX7Y @)h"eOWO/^Җ}17~\oM~ѷ[on,CAR1$I)&8ڦ q?J+le7M >7:Rz!EY@z{{ׇ @1gEObMl" ;#K=~W/[W]IAR$CsA6y5v#ѣD˶34kĉGڄvn-?P?^7Nn깧;路-K) +vgy g_?gKoE|̠:HAR$KQ wW5~o!uѩX,q'K/ whZ&MRoj@&&p&$S1IW_- MS0w]]]~g|( _  ShlCSOaapMu4SoQhRI˰ hvJHE{wᄲE8N.V*ti5TMM ׁgQ~ ܜҲ}WuO~q*ךEDw}7lْ R.XxжxV1& E*3>7?h[[ `ERYOs=ߥur}CZYYQ@~қ;T[[<;t&yK'>x@u |Li Lmmmo~t=65XX@A1}teq| Cπ?_L[ǁ?}NT4}K_ڪ2aAo$DRZ&ɀDZY.//7PmG,Mx#C+)SVω}0zzD<_1Cclcz{{[K& m<'U[؛vM5}7 Z`>(@rA  /I~ѷ X 'TkM`0Bb&(`>Ht+wd}NJ6%ב=4Y M?4'0ê"=޲e y䑌 ӓ~P4A&%K;m`+e0qӵ5ek.8[LUA~H#  Vɍ}~ nFq?~'5͛7ϴrdRj|(GsO j|D]Goy_ƻロUl`L v·deۗIvhQ˖Ϗ)`E 9O up_p)@*QEwI%~ }%zwdEdXdMVɝ³Lv5??Mu'L.; ^ ^ϛV>1޴֖^N>-(kYg}kWK9[u } R<omUV^?WXh- JT~dPEfn N2qUOr L{/&_OOm={/KF3@Eה@}cwĞe~ә(@(P"#{stdB!4Vڿx!_<7ڞɮscI"ȴ5~,;'Uo֬Y|=6f (`KV`֬Y>|݊e63y~ѷ~saDm| $%&|K@|)ɼe}vA^PmG}z뭨R_7}o?2Wæ&`Uۃ%c0CEx gdc+v0* X YٳmVnO@(][oѯpbkcbZېrѣ/Yi Ac17ٵsig\& OM@8nH$8vXFC[EeKus…ʶ4H L7os  [~ػ:_:l}>  W@+I&',1@Zٜ xEPicz,3@.;1n8;5gυ&d4p*|as xr~\ec&[ PA&ŋ-]Xwa UR. (5.Y,ā>'f-닥~)@(P"wSB?t&B]!1mxY~CSo=Cv?&>?t'$=e^^4gLb 6ॗ^dc*+_ СIV`ԩ3f3[8}V%@pVM|[o&ִ5?u V]GA?D"Ӓ\Xǟ} >gmd,ӓ]6Iu7ޖ'وcϏou2J>AI 3|_|1$e/#З Ι3G ɳ6aTc1%sIJ11+?'vUe B(b;!E}z{oN ^,M02xTC=lleX-b:6eۺ_Lӯ}*3sls;9RlHEoW w?|0 6W+-Z.ͭGp_MR}A% z0H]:>o^`޽XreV/3E)eeeXtX[el 3Nuh}>MnT S2UE(I.3 eM* ֗D7{1zhS߯n~{&y/[qqȀ_ 3^ 7 XP,PWW;NnX߭3Y胢1o'?vxV}2HLV$\=~In}\?˟>|&a0Z@ʏƌ~X[l :yRJ7? WbJM">1A> З̛7O. gؔ쏡%  &kUL@H78gT/k+7\顯BI^)ଳ/KSDg>}F>#HV_T<=WB] رcz뭬 ?zA >l5Ms͏Iy~6j0%V(@\(.J2ښJL*;>9Y4@Z-ؙ6KbD32)/tMM:zq˟>ĝO솥ϏnL=3p3_:o6ҴK/Gf|{r@(d6iM`.V\K*Y,؛?Uu3}6_ǯSX{RA*1l,QD/:{ߢ_[ՉɊҪoδY(@OOO]7w'?)g$g_|# w%h,~.y'ח x >1['D"PlKduF+=smk\:Y78Yf}l[>Y[UUP(P*M\`H'לX)92mf*BD}xgy6S0? &X?7$@:=gkzƍظqcF,*eee?ͫ_lK&vYlIͱ.C| *29jXuM5Hҁh_mf3@*u(AlN%Q֟z*uS-&b6,@FC ?Kol=E?_Mݒ??ߪiPV-GN񉓫𱓆zgښU @,PKd[s9veucfrkRmk׬ K7(@B(P7K.n ~7t$Vez *[e8W- #6(++ìY裏bСnߊ?_}Kߪ=iP&goʍ!w_15 csel)?Xu;cYO4WeF - %B+ mgoN ^ܭIocUUnmmMy@уļP1.\UVRۃnc=~ݯ)S2?o/6t\JٌqQ^׮]e?`B@uu5?xe1ԝ}f~(믷/[#g'Q[t$WDSqBHo/: 0ր_[;T=677g`_\[s M.3f̜9r5bO>^ڏd_%ޕ@6;?k ~̡8mbUzzzOKkA[ ?lS3|Rl;+k-j8_Fmo9. QT/z_3%SV`ӴΙlSrӯH\ `رxpZђہ?ۀ$ ޑ}>a}ؤw߲1Uw9tV^ťⶀSș^-ڝ4x폡9|7&=2g5e~k 9.   aށ_/;Y4@tM7;ǫ ȵL5ݸbQ @,SO=뮻Nfû'룥;)%9. &~m477m>ĢV Eo^` E&rp]yѽZ3I& L_  @r gT/ksbi18"i`u$N\NBKKKA,ϓbB{+^ܷzfx\-h8)%. [,@*x8NStH$+d|A@o XYJL6M 莡~^71ޙkT 6۾~Q[+)@rD 8 .-5@*|g9Y4@Z-ؙ6t[eٶ2 Wmjj¾+[ $9/q)oojhWݻLJxvc3rOL$yl]W3f )}^9Vlu֡)+ {םB`y6oMmi39jUWG)@- Pȍuy~ѷs!Ҧ_G'An?+<^"֖\/.el$+ @YY Onnj^:d;H﯏_ n?L٪'%-(~2Gyy9Ol6~:Cc>c٭̚3nЙv_fWWUUWQdO𙼃8.,tݫԟD_W59N$}PY&̛GExqnOOt ȶ*x1IV _ +V3lƾ~Nõ}h腵K[/*;ðzm6߿_ZY1wɂu`e7ww@{ UfIx4Ҥ N?q>,|d*.u*(@|$o#~XLY4CU]p`Ge0B]ѣ?u @!LȋI|@  1o<^2iϞo݃GzK{^dvwm*+QgW_MΖu )(XdҾpGRq>4??nT S}0&+ω|k}$~:@A(y" YrtUC{iZ[U.xر4Q x+~^!(++C(Byy9W_5->RK އ?|f~t$>SV#!;x{رcٓ/Ȳ=Ν;4(掁TOI/>eJ;39eJeD(@, @ך7`"~ܖOY郙OӦzyWC:MTZ[[R[Y,PRtA +6   1a?38x{G3nyp;&ݹqVoo8je,/ %#l͞"e 6Yl g IDATk_(#9k,;{,¥_[c9=L[g̾wCA?2uV-`P U" G0V߰SIo2u3dC .l]{~ _[Ҥ_ x|z5&)544`ǎE.b=.e'>nٲ?ϱg:%j^71~~6o/639}VٜAWҼ* DƕH?kU.R0M*A_o2|' W9yӴ`ʯ;=pȧtR_ɡ! #cجӧO/fA$8( ωAO>Cg?Ë/.ۯp;~B_ V0L&(a-ypҪ?,ۛ|/ ݚ5k0i$twwHp(//G8N?$ [N/ [%H9~4au>c{c@p7rEv7 Ăٮ @?RAd $,A"%{!H-u8yH3[3mg*'Ϭ67CO0Fۿa?v' O㗳uVk8~s/mcA yO/t ]L/~dԄûCVM) - H'OƯ~+kl`&V?,xʒl\[}2?\:ܴ[o`Q1@q ]wuuaŊ1uTL>wꫯ<3Hs Kt,k|~o2ۂ~{?o]U* I* x,oAjDgT9PK~쐾Ϝ1e߽صka!@ٞܲpT 2 {@qk֬e MW`0 2fbS Y/\8-%y>-[z>@V @tZ/~%K`ԨQ?ww䵇Wc\J 5u{>.t7#. VŽJ:o!iӯ)~~ySUPo>q?nqW*u- D"(//Lj#oo_zjN>1 Ւ_.l̓I|AV@\ `T@ ]^ Wӧc7+W) G`; Иu&Mm~'χE;S!k5c.ޏUW)@H֚z>+tTioR>()ڧ=>?C9٠sFG =9rD"Kʼn7̿ (1Kd?Yz_kgy՗P(2ؒҐل׭k+,_k8wZ ^lhЀtVJgggO෸ JJ)Ӿ}caŊx7lw4mt ,Y#ũs0V}PVObkOf#̙s9ɱh҅[sL œXuU Ң >~ I>X7),|;eeΝ;1lذ,VܒKV$)b`$Bz{{ 1uTqַ^{ fYǴiPQQσ\i/owåCx0r]+@WW"ۛϫ뎪b2իcᥗ^֭[۫2WE1q,'Gqh6E-4; l M.ޏU˃XHp[[_J ]'ʞ_`[D/jH,& 6ٷoN9%r! X| `YOY -8sя~mmmxO`ƍJXF8\ַ XZ60;&T])hooG8NC?_ `)1xdv _xO7ѣQNiTugME*p D0q3_/AA *߸߶O}w-o7#&;v H$ `oooz,Oe@[ i7x#:ܹ<{9߿?8~_k ĻEYI!_v苧WFEk׮g"lNݍt > (CoG}/"6mڄrT8Sœ+pى8m\oOe7UrsLArnoI(Q%C~"9uu|[Ȝ,;z$DwΝ9rt'7{Z r"#Ղ8wqV^W^y% ]^z)Ν5mKS~~~v ɕ͇~sf?l)E ֶ`&oÓO>5k֠j_ëqqpZXQho%ͯ|lZ4 .k'蛀ߦA{$-HΚ2/7ݻsIÿ bv#@;ҥKdɒo`ˊT/*= ?]i8vmۆӧg/`#Pb# U}Q ذaOP8LUXP嘖/29 s.7.R.T (఼'q[0Kss/~jeFmmmi@aJ gϱ!x_fO ǔH֭Ô)Ss~)_ ^|E<3xpA~SMegŅS+pٌF,ml -4wΜ?ՇT J& 8(?5~~:IN-IɯmL{u5AK؎;0z,qe!+;_ڊ>;,# ;Kv $ .VG3lo>466<}_ؽ{7^yشi:; c8.=1"ZZjᗀߴM2œ(AQ!y5:d~;~~~x nu<*' 0Sgtww#0[Pk _@`ߟR2/~%5:kmRȑ#V[ׯƍq!Su,u8J.y#_vmߚ?g8Տ8 JEp@M$,?gI W $ lٲg϶ 2`N0-(\0+ewg:/W9^CݻwchllDCCZ~<2E*p;2$n~~ [3;~ }05~JRD]#MAĭɮ~QUQ4vl޼'tRV!@g2粬F$~&J ?V_/Q)xG-;0V\>jLo9 ol͗S܁{ $V-KbC(vQ mzC~#{ }(\1g{eU[[6oތSN9% |v-;ex{JCIXf W@wEM#,\rylNofKo&JHW(PMy ~~C~m~߂-~tz됲"MY|-q),Dx&]ZЯP ,3VUbf)bFSL}=~ gLzj(PĢ y㪜x<"gA_Ƿ n?0*O34kii-[0k֬ gcq)5X썲[tnMVnLq ^MZ+p \0Q쏀?7y~]~@-7'Oy) MA"4)ElKrk>gq8]~>x9> @e"g~%NOvdZ@a(~QuCqx6MMMضmf̘? B eH -5Uܺ n;0&NiQ\<-r  mN_ِܸ郹]&;2 @1/$l s4;3Ӿ_FWq*ڵk1mڴ1 af$'|( :9%WƆqj<6fĒ)N6_ΖߢONՕ~(P| d.Ҹ?7N:|W]oǓR\t)N8qTWW555Auu588(***P^^p8P($RG__N?t]R#c8oj fV#"Wd=]~=%mYFTGp.V Iqɢ~Ԁt~#n[A;RAV :]H7GcohjOpk* ?=; A0-Z xhÁN|@ѣG/Gee%*FD"T0T%kDu&pI1\tB 2u?_ӆ}8ޏjlzN|)S?8#wV`#(tQ@!O?';SǯmN!о_'ݎ7*_tE2e 82, HE/1l21OΌbDe&s|b`36oo]~ gweJ@"[@0g_7|2{~4$џ`7]vY: gjTVV2D"@**g}''iQ|rV Gw -=~f~Ξ_÷DL(lQ@"Oc8j2Y e/[%o(/"L:5] X0*F(//G(,RQI a̙عs+7qD TbX41ק?c _~/(I (\Q@ t S PG7۱?+[:˗/O>_,@*6׾5<䓮NQ\rBr)+5n? Yvy~]~@-7'O6Gh @A o_b9.:_ӋonoRz3g>lTVVf?{Z, , l[Nl߾?0^~el޼]]]# Lᓳ+rM/F~W_nT @-&sqECW~ʭm7*G"\y啨Kg,H$- @oooz\D{{;ڰ~Xf 6oތv'i1\}r'0R`P-?puK|ܮ* KWZ| N[~od;˗/f-v`ORJAwwwzLmkkCkk+ZZZp1ᅬz477ǓUb?5 e~X4L (|Sw_[_ۜ[_/m>ԅ|]mѢE?~Y Fb @YBO!LfH$ގV9 hmmE"@CC6oތ={î5N5T3ʬ <~M}07mJUovG)wt4n?b~~x nu8COW_أlpbĈeRT2g`@[[cmWWQ__{qeBXpé1,9ܼA|.[כJ~gy~s[x{)l[w -A}aTw u|{zwm5SL_+e#e Ql>!t@[[[#H Hl\Egg'D"0vHNƹ1 ͯh퇱?#O_[a [%IT@6spuL~kUK1s̬,x<ҙ|$duble؝v?HZ>ӓ(aسg<WɓQI ?8[3!WLTO#, t5̞_AMMM >bСY,/gPA@R!Zl|eyqe/>ׇcǎaؿ?9 (YX8]rC l -Ԅ7~^ ]{ MT ?l l s[o`0я!5w(gϞ /0@,ŲBl%`wwwz\eKd0k{zz`AY0 Hdba{|ˑ9%rp EQ*w_ %o_&NOJ G3n6eP(˗cʔ);B, ?q|6*ݍ{b8t5\rB;DŽ Cg mހߢoWh S*pwç<~(/D7UMszJR[?`k_rNjԨQ2v`Xl[P(DY Ycc %b=`@WW{n9rNBQ|nNU%;~k>K4su1"~(}u5J: 7wsKo̽͠k Z;gq/^@,FQQQrZ @*hd2wvw_|v|QA`hooǶmЀ&Gp[[/Ώ#Ksmk\"O;sK IDATfCRvT?G vg?NA|~S;9,RWw.Ü9sA `A~[@@ARHd1x k/ e>|۶m޽{ޮSW y,eߥjVW _Lȿ6WeP &Nu.?`K7'jQoEp5`ĉuXeXY Pos d/.'Pc8pz50<)o,bbj;Or[)~CI'VLȯ2 Q3m;Wkd7LB~ۅ~=lС馛0rȌv [FAY 8 `b?1(Î Eq1,B3Y pF_e @Tt[-'/4:Oݯ00anƬ ~) @*b@~@q{wUb hmmŶm۰k.G?gfEPfxAqvtKm^e|Wevg^|2{~~-6_Tw_ ZMmΝ+2 PQQh4aQT9Y =XF)JwP-ؾ};ك6Gޛ15|(:C"Q鯦\AiO[VGUjoޫh%o~\|[X5܆C͝\r .\Feeez) KBPi)d53e,cF; ٳ۷oǁi}7S<ƥ'V[gV`I5x^ߴJ{~ X}@@EVEgV `K_F?,ѯkoL#ѥE"\{1c4 D"TT4| 4 Y l dʂ|ƜCY*qۙ,#[*m9J,9 w*@~-z: ;sRL{ <Ԯ_җP[[PUUQPVVBQ ??7  d?{簾&lܸvrdFGrӱ>~_ρ_>]~>8ᓀW( :zA&9hr CښϦ"~Y[ۏ߽~zܸqW!C3h4X,5 $t츸jwYՖl>d Nlذ۶msVr\;_JxmGo"s;ԟ 8  x1ir C~~lE% k7z9s&t=vblN"[&~R7@ %]۶mæMpߛʊ>}r?XXix ϲwb0~{Ⓜ k sk`s!{;`[0#[Iך:z?H%KpEed[  D0@U7@ uĻ :qYV}n:۷/:50n:5UʰN/7mJ_rIATpA-'ʶGv.,{'Zk/b,]4]@, vw@AR*e|@q[A`ǎڵkQ__an_ pW7%Q 9OP *eOwо0*: Sf~~&ohԣB ._ PYYX,X,. Ȗ X  el_[lAKKKNؚ /Z2W^&֟[D-~n~N`f[p/nb+=d_Ƿ[86: k~/lŸ+YX   fmPT:eLhٚY]؜&lݺ6lCECU8<;>5';ѺЀq]~+5/&( "'wP&{b}%W-W_PYY~, ai JKF:YfD@  ` qEX۽{bڵطozzCݜ(XGU~ }05!?? 6Q9>?7y_s[o`09?-}wc‡-_`nrV(Dʖ` .0A@\g?cǎ>Ν;H)ǿSHO  3u[/4z:~>: O[g*\KiLfkϟz,mHA)SV͊m'(. Yi&ہQ pr(\n KYjw 6`SE xl|@i;]*z~Ş&seTWW3XQ@@ @I$2YVjI@lDlb{ꢸcUmg|N<~F3nte @ne /Oo\Ðߦ[~}Ip eߏ^,;f͚}k @<G4  =lڷ;njF@$ \{r%~(xԀ?m T?gϧ/w+vN#>3BaHo-o_X`Ak5Oo555LA $ւ:euDO>CoV `LM9 7 u-5~?~tN ؓWO?C: mu|kAe[/}K݋,:u*Æ 9P DjVt6Qqi_@!@ Acc#|MرC :-]B,̵hܖ?GOK:2wmAo?烀ߦoQKW?>v^j'MoGDь€`0`)@"ɩ%VD7?ꫯQ;.~<*v yv ?~-zE &fv=mG7&ya,gl=I\?{V a/} gәPP$R K@`k, xw Zo>Sͮ~~K/2w[/+?ږ_omvNgC9k2u;[^H]v-[HpAHvϟdTY,`sj@Y ===hnnʕ+eS+(f?ED|DAkk;w?79: ^~zqF)5jT DH$dvdA1 E;wʕ+qaex' 5+C0r՟.]~m§)R̭\}/P~~ _;'3kv9<w__ok,{9r$nV|ɈFL, fВ)wɲ.q AqIo&ytvvZ!tr,R~#7|]B8'% 2Q@<_b9.:_1mͧ0S8ܟn|Q˞#/_e˖3h08 @KH\ 0Z`N>,~ۚOmӓGpzivnv >M=~z(٣EW0$Y~#OXr_H]|$3g<[ J[} %4߂ \Go7?vo8 y晸0lذt % eH(+NY}~$Χؼo @O/о0*: Sf~~{(FO6|h> 2dz\|ňFKd;B! <}}}U@Llٲ?8ψGVe!#/^<08tнš޾=w m-ٹ:}0u 7?[%3k&kmk<,K#whNJgy&nu"`Fm ܔX'`A~@Y@hmm#1]?fJS*uWwKݭn>O?sZj[oJRUۖXlG]OPw Km _&|8pWbZ* dfV #D2[Fx<\ _@[o^C<կGUSHpa;/&Ysk8؅!;&Y^{MMM  R[?}Ga78q饗>kJR6_$ҳ|R6@<G4E<Z*`Fի׿]]]uA>3^r sۖxl~c}H$|q/0GXd =\l6-  2d+]]]BiS믿Ʋe٩OsFzLYӂ>yqx<%WҖ00o@j/l, ,, ˗{/37{!N0s9mk:`Z kKܜL#oWgF5oK.gJ3@FddF?-`RTp8۷″aQx˅ 璘%w^O/:}L>BD jE-([f͘{s3iθxCPq,f7*lKӎ}6F g3GsK4ا>555a А.̀,#h{;izV ftttࡇ_3Q(z"9gW<~g%/xf?wI3]g&8LP~WܸsΟLsӗMm rB?&笮M_ܤzeGpغ7n8qeaРAi#/d$=R[-e&@"05> > ֯_ NioR~$/xf?߿޷o#ObȜC&B{mfVƎq4 0Vm`M(/+eks~mϦfЉ8\; 5ZʟO]=lOcƚ5kꫯ0|p444@:dJ2)?)MQ2xcUTT`„ شik[h0wuSЊ=9:=^7İ']9H>8aŀnf`3g`h4: 5g\<}*5x~mTښ @VN0 n7ے~-ofX ?{;?Dg2y<L<_~9L j 6`,  ! ǚ5kt׳,gR6 Y7/nKK1Sag-nvw8[^/+K2`ر1w\M#mH$뤶R?%du} ftvv_|y|xd wV<+bwc~o%W;b]>|8=\}٨JV' T3@"%=|&_`" IDAT[(½ދ?\iF:Óy1 9b=R,@`uX 2c GϒCM;h폧/L%7Xl~@3`g~70g}6.fe%Z9D2[Z-(NBw}7֮]y`lZLzL΋t)b@; l We@%*x ܫ9c{3ʵ?5o[y-bWӷ[F0Ϲ8Sqe^7m0C@4NdԖ b1$T  կyfmb} wZ<+bZǒ;/De1 1ke5\9]8Jpg- Kc\0:uadp\H A~ƾ%T0{l\y9r$***YJJ@"!)l@.@8F0DKK ~cݚǝ9̋(C:}%?l=*(.ջO7W@9z  * :ЫL iWio2fA49 .p&G$QĶ}^&LgO>>/NRF1-#uؔh4H$[lwމ6^7ŋ8ʠ @̸EMFgK`22WE,6kY+] @w; 0LV?`ڷ(tPlˁHlf~)ϣ0&p Xt)r @Y$R>R`UL~:wFB>8+CA}>%Y ΊEBv?3X>g+XXgݘ /;@Q Ӂ_ws,~-}MMk.([3_k^91w\83x3@oV) aKxG47ɋU cK+bu<1 ???>goMo L#ߜ7_2nk?MC6K]q}RpByYl\|&ja;CySGyssK.I_7!^៍+FQЍ̹@4V dS|1Cc4ݧ`dv&@b%7o#ҽ rm9Ю_-se~`xrcΜ9Xt)ƌ LfPVr5򀝝馛qFc=|

\ZY,Y 7KY6XkʵD@H@7^}/s)73-lWk~܅?rѣGc…8묳PSS@Y$9R2RTz@&@4E8N۶m 7ܠ2@c`p %V,5"r '?~}o?`(fE9,5ˡu8¥B{ jJ'Vw-a39ìYtRL81#+NY$R~R3DFY&GᗿfQcz<dtp% pXR~^p8Uv1~In*`5)jLo cն(ވr^d?bhK/* 0%mF"$zL?O.&&Ň~Hq`q]$lVV„ \8( ҝ0зlEQ|Wxꩧp#GDEEEz3+wz?Rh3G*.=Ζ$|2.}lPN?/W ?_=r<|?%  3թҀt1g,`Dtנ0#Z6om0ąA,7Y[+?~HY iօ5h']h[1jjj0c wy2eJVV@Y$\F3PPvVZ%=Fh!0No|RVdz*o(^^~ Qy {KS,5M@ .0Mh3@t@'?` *M~~~PiWK[9Vnq__ՍvaO9E`ȑ?>/^~e  ś'o5X=P(]v+Ԭp />- ~;+~mIgz_iy˜E `fqh&kb_;MguOryYUUU81o<̛7Ŭ2H$u5X=H$x_J~I<&e8P#wtK M_\7FsbRBu$qϪgM;[AӦM1w\|R|6 {3R ݍTfyx뭷k/CͨE(^^"_P^&f[%Y\[~c[L&WJg~ҍ65Hxcc#f̘ 裏V/)dOfT$3LH$ ҂. {?q/Cxyt/86[LuF r7* cL1yM73/+1g,ZǏW" dJ]Jd`  rJ'?A,&w^< 8qV'Lz2V$/xQ~Dol57̅J3RUo!1f?`` ?oHt㝍aDL^:|8xb >\13@fR)IfE ~`/BMV< g+9"G| !e( 6%#f`"1.m/'7 &7JOcxnlj57+FO>-Bsss.$f€@$AWWBZ[[q磥E֩Gag3?g#W֨ r2Ȏ}"/G\;SxcS a T`h}9v+6&'xcc7Qń 0o ๹F;Ó1;C֪a()gPio+m0Nq~ njKoxwK aSk^< sPnl_Hq1p|}1 `نW #TLMĩ֭e].k|(;OĂxΊG<[@f?po;f;uĶ&iWno/g7rOn㽭1î2/׸_w} xqlk~ggɓ'^I7x#L( `&]w݅g}VQ32#wV<~g9o?rPT܀t+iO_l J%A(2|=68>ޠy%<0D_vȗ ,Ѝ=&/#`;w.-ZC9D53@i$KVՅp8{bѢETc|2MLJKڦR+RxlM+6n5jZxxw$^;[bh{76_X ~^?|oɟ;7; /Sx$>ߩ LW_}59TVVdJd#%@\MB7ovء|}t<[Sc -&L:3 [(_]+6,ɷzg ; UUUE]]|>֮]+m?sD,_Am[ 86v0}tqLo>/Mod(z VD"xq]wI]1x/x/ ~+?y-R;x}S mӝh >3P[[z466:Hܧ~=޿&6ÑJMoկwxaC;7&Mo9 UUU|7D_- 6'|2٣lX  /uT*51Smn&kbc)H~r5a?m@lGdr?"%SD nI15/X[_ KÉKō1Bj^z_rT[Jttf9o ѵ)m B_ODig(ydN&EI$ T syyyF"@ ŋV5^Gj@XbKWΐ3 ИmXRp?Tڕ|Y)gIb߯_?TVVW\Vcx=&ް;O] cǎ%\3RɭM`":::pKi`9@ΊGO$g09?`<ҫM_ܢ~)DRXm om1lh5Qy<TWWhhhH{S~}ҿ/++!>@8pQ,;M9g֙ϵ/:xo$z|iuqtvv!#H LSlH!.~gS]^/:,< p$;ttx<~(g5s'k:f[c;Vzb-okOocx{K Ɩ zA}}=ЀeDd#"3T #Fw^վU[+1_O4M$DwwwV?;l?E1VEDrĩ208.BV?`<?kIՍ1%wBKcc#2ҵn(0?R2L8ojߺb?*aED"p8A?[x^7 ɭRcxGTc߮nNL3?gRn"w\g` *nKoR\ˁHlϴ=s:e@mmJ)"i V0a>۷OYׅ_jٳ"kN$D"iS^/|>QYYH$xJ?G3gᅬ6Ě(n^: uEHەR)twwgGQTVVqb4D"1NX_?u+7Y^ pIq:*`]t"~Ňs~,'7I{'F.sUg߯_?Cˀ*Λ|JٳϪ>ώp w#;QeV|'^y*B<GEEbX:ՙ yMJ'Yzqq^PwN+?"w\on2jtn#:Qok|?vwWU诫˨Я'ȬЯ7}W~+.zp޼yxץճyN q+(kU~c ǓGRDo$(͛?h  4DA$=* p @C\}@ljRWY/ZAUg___89j/^m_ D"@ ?O?k7#ۏZ?Ge"yYGu ={lt`%'XRLo|@͇~# {9 FbqP|Kf̙!zo:8/c &;<G0T}}_ݍk: ub̄~&KgHbRR-3fHMzMd8 ITT` hOoJ`(/jl c 8C #u_M}Y~sF/%À.T*6*++1w\<3O[8ޯݳu~ <_~d_N"5Z@kxi+pi29 IN;Ut6@1~q~ }/vux<}=Ȇ:JP/}~?OW~W`le]W^yEQ\?ŏAJKm/!q7ރ޽֭C,Cyyn IDAT9f̘(o?Hy`ʔ)k.86`8V$9VU~Heg8 c*ښmc@(w_m.JT2DS76z^T0p@qxU_`W#'T_CvnѺupqaΝ't."̜9p#9VJ+xK-Zf f͚.{Ųe˰l2 2gy&.Rva)Iғ`7 8m(Ox  %&3K%] v5UK e/V8B!ggzQYYdZ 6}y៉M`R)K,ޫuŀNy|< ?,ԟ~7}ݗn݊w}7ƍEᢋ.Bs_$I&UbpZuDJ\š77?`FUx=q >lrݭW0TIb_YY ϗdgGş"+XπOKzyC f sV^m_|/wqNs=K,﷨$J(//Ow{1m)w%%HiJf dM ,]{gH0#7WTۖ27ɁM4v5_?&27MiN?qωNkk'`|o ?@^0g"CUUjjjP[[Zա>աАއ_SSUWW#*~|t?x#BˀP+(NkE]$}bqoRuRRɾMܖq %r/w%\fqX|ɽ#AP-X@04s\]Hn-R[L='D ~1猇|[*ŶZ0y>&c@}#UUUi@YP]]~ߟ,83 l ,֒%K0dr$s=SN9GƲe %M3'0qDkj1?UORHM?1/##nùy_[s?cWq~ZW0a&,iB4̀b ~?~y OWWWg?}iM3P~UL+4Oߍ$t 'Zn=\tAx衇H$w"^ɛg@Z& I.T L8W쫹5/Aqŝ{d:+F^+/='z1X3Ijc~_MJY|=Yfa„ _}#kԾ&1I|"ppر_=gD"tK~?P_$Xf?@D_*ip 0-~vI~?׶`/jbg$hr(Wb|>?w*=m@o>b(,zk5c $ep=1͎W'DZsO{Vy9r$}Q}^H\]Kg̘!ݯ%oI$eM. JB]О?s{~Qjb[[[Dyq>=oT,뮻^<c-Fv~5f1Y#=҂Kbܹؾ};.ěÆ CsstwH2 f >b苹{df۳@@@iY=S[PR80sL{Cq\V9Ivjq> 8cXbƌ{T"h7N|:C*r.f_liXg?`gNc_ؼ`$b|(ZBJmI@1 ^{-~4SX`68ۗ.ᜌn2l`@UEqW裏Ɔ pi6uT~Z DP+LiP΅d\Oij~=}ЊT91G4k`7dd2;o$ oF,1mMkz:t(N88p_Nq s2xr6f@gP+W;33Ork,VmA uuDH? /Y"7$dE~s~>hƵ$7p5/2P{%yO$)dYo~*`Y xwDЗ}p3y^ <:Xh,Pm[qG> qTGcӯ3$ :  n|9 1J _Wb~mv~>+ёL&H$2 $pwҊT&\z饚q$:gP<b @m0~)>hx㍈=^Rx0p@~[ d Œf?IoАM ߅1݈KoN M7v'׊-/Ð`[[[4,3@OJ)m/VȌ׋%K{ 8~'J<7{X7Xp8 SNŞ={yHzƶ#FH]\"єvYE"@oD0>0pWl%[R_9V+pg}iloow"ȀJYXo#/Q|n%φ{S!'|د!?L:ׯOOq_***p衇Jۯ^V]V\H%'Hd{L;ؼFe[: i smf\_~q嗶ΌD"1T0LYz4if͚%ݿ+\FV1-kɐL>; ?~7o1w}7އ?.Vׄ75G-NɃ">z}3@ y>96 r ]fa@v6`?bl, 0#@2x3meep [˾L_:2+&Or zue8HZ&8åmW 'ld¿?c"qğFm E n6I~[T_'ݴX WIQ޽{k,J[w81l0i1ܺR/V9/+NFӷO,7ߌ+2#Se8H5E YPPląg!Y8_D@bKƛv_q3f@ /Ps\g(~V'o~֮vF\?YX o f]uzŨ~څ:O?]Ld}eϯzxqk{*57󹖰8/6k.|z*0e8LbrJi鲣g$Re13 0w-ⳡٜ MyH }>_z;<  ,@}I:c 5-W0 S:v-0N3ĥt^X M%Mi9@7~Y|> ਣ±+W- Xᄋcdy='_"_~{,ZZZHKt-++Ӭ]JMtP6x>]POp" O4@ qUW>$A$\碴 RgW>V\+_z 3:6#噠T] _@~&1 m|,`M|M7G 'R9 w^wAM? >}v.]hU }e藵S{kA[3؍/Ъex^ 4-Ҍul-&`?dsp`I__},YZG '>2HE?gđi/g+=" o _~+^9rQj~///رcUlsU W0P\K Q)9mmm)"+p X&@ee%*++qkq: Z4_2ƙHx_y~Y׃tX_*ZUXyM  LC]i*ƃ??ߟ@o0I oTsss_#h]]=i<@~gSe ~1V;_@(g7IbDC4Z[[jg ,ba@YYY֊~\sfO({{/_)ވZӀ˗g\(X6VQe L{B#]2A4`RtPҥK_; ]]]FHR0`|> ؇D"~-_-*BG*c߼!T @mi@7H- M`*++1k,̚5K3|f+E4wON6/ƍ([h#Tdr3p*zJt`&MT~g1|p϶D"Zx֡ E0z_^ ) 1A*/jX#Ă|-܂O/ ͒#>~ WY: ܻw/,X.22Oڦ=fSgH$Pg:BdfYP8D`z'MT|?DM9K)7g - (]|+ (Nhjj_k~J I9ɢ|4]_|q 2f@SSm'"i4xÜlOES %2L?R LŸZa /i\ͺ /OG4'xhh4c9@=_TTT. 8sL̝;W#"🫀/l_=qQzOrTs<PcQ;XL(g @ e{}76nLp%?zJ^ ?& l~ϲ&?e맿 7VG@5*ncf3LR" G L֛ʙp$.:r`h P̀b,`YYYFo+ $_ht;I]6g~9 5Dm?!8, e/~i Lv?&d?P) &e.2rPz-&/jb 5Y>K*},>uuu5W+ٸ7+6$*{Ӂ*sBP" `G,QJ"-1O B`P&kM(?&,hk)xP? bZT[ P _@ee%&MN;M37p '؀NXpݸCJ+z_!M$*3 r 3c$QX_-.ר`6/v_~qpct׶6 d2ҫ`)H `UU|>J :T3ί>^ݖc'd/_5|AtvvfѥnJZ'ȿH$Gd p#zL `Ldz 6Ŷ S~1>~Q~c_Ei7Z _ PZnjbzx<|ފ*ih 85`kPG'?텑IYo!oڊ~: J?K gr L"@ LdisSk%KbV!_Ԥǃ迸+SZA@|邀cƌ^%1r1I_q qb b1!$k>PN@rL}&f"f!sq$3Yot*g00_ ĵli>Z jզ?[Ph"̘1C3 IDAT֧bmXn0HfuX@Ayf[g?׾`/Y.m2`xz[ @,(TZnզ:>UUUߎZ͘>q833H@P 8 oꫯ;` QnrzL 7=&@IJ]/3`4I=2" (= dY~#F~#xq|5X,_=Z-yڶmp d\n&2)2zUld `YwdxPگv3'A4E0T\ @,nVDUUUOk{bp9teWZUUG4x(ھ}qkD2b&2'2Pd B+>[N[x0VR@VPMT8`M7݄*oF#7X ʉo@y;v M*"$ssNCmb&2ܥ70i@Kk~څ TW)|*PUUߏ ,~X YEW*,8 RUD&{T@?&?H>S wQV⮹/7[4IXݼeeͽlUq*oq9sfh 8 `nX@?9J E tvv"!e,*r{ZZ7$RpJ(5g~Uגrk#7Ij*Ş֫4_e&@ ۿaњ]_?C3ZP(c)@kP L&&ms e R&24J1zaJZ_쳬UNX; [q5 N H3SXQ*TWWoСC5_vG@_ruF|4E{{{Ku֡K*/@_Ld8[%g0?*Eg ?SF︜*m~,xoI#t޽YS68W;7ĥ~?~?qwZ`spK@XHp<9:ӫ2^c]T" C)5}w$*Ug"*)C~TrI8$7j>; zJ/oe0e4h~򓟠N_Nyhৌegh_NҒ@)_3'|"}z:B"Lgd eYot!TL1͐'HGGbq7p4Xe5 ?k:teusҨqҢ @^/Ԛ5ko#pJ @/~833#f/j~Bst  z]{E jE8\~z5Q< pk:MCIcqJRom&5RI_Yi27},t3e}Dq8'7ۇ~ 1_ii@z|0{ls9 &2WH!/*כq,CV{{;v!m3 "+f=J&T1YjF1ޚ_*74_EM$ߡX @TĪޥ86 ߏ38'|-p@< gg[\9E EZil^DGD&3TnPL) -g3(SۧX@m 8Tdg,XYY4G E]iӦ:+S^}韓RK_?q QUUU&!ahRpvQ)gWQz ƙN~yU`WҘ&WmW+e,ߏkGMI1)NJQEi~_@xwߕ`GH(D&@aUt9Hh;~r g(LИ 9JyXH=P]]Zz뭺M6'NBSuZj4dSQr%zkr|%_K(Z 7D@P{Tq-`̘19!6`Tq׋QJ7WVBkkɃl dDol0nY*YoT&wV<0;E-ՅP(/Vثo|~?pM7aرV`@TusG*j}Ox}}=***L 륗^>>38dd( ke Н @onL3d![5/S]% w^9rj%, @PWWoǏuwǾJFd31\o2. +JoKE"5 _ُ `\o0;w.HJŘfs(_I4P jk|O2 3L\8q}Og f7 Q;[fd xev&^Y fE&6U X, B|*OZ&@EEEt%`ԨQ0x`]Ǎs`r`gd"s]}yȑ#QWW6XqKÿ(3:FZ*l (D `kS֛^&@RS-+( 'K5믿G}w_#'`Q} x@q>}zX^I]" 9 w5b&Ӂy1Shv]dȥT=W]u9.{'[Y"/9u%3QyQFaذa0X=q ƕL&65>`P:Dr)LQ& -&_J8 &4w*FE@+u)l@#&@mm-9̟?_ 8O $/y^y*Xe1]xmfP?I-MI(bQ:%Me(Y숩+Bd@%i% @ c@f̝;\pu߮? /n7qD?]eԳI]<)m{(;zDrCd&)GΊx:bNm?ή9J,17"#>/AMM qGkma_WG|/'@A[?nЀc=6=Q~Y voH%IO^N*Q0.GŭΊgU<5ݛjK*M 7.LӬF@uu5 뮻ӦM3ԇUiˁ? IC"PWnzqI':=5=+V`Æ 6K3$׊8E&14d `vMR~1Yr*K7+EZ,_d˳L߯Xuuu8sd}7m$/zݹ@\GӧL3mG)ߘuw]\}="U-2N8d D5L~d ._x^٩%/ VM ipWcРA8m0M`KIr[>#G;~S`,o\[nśo)ms`Ҧ\'Ґ L7 f?x`L ߑ@0TW[~&*h\Z&Ү~!CSL1ܗ7`%=b$Z?{wUy$YP@A"^jzRu+ն..XzZ D "[m29'@fNNH2=_!v@(/}LПgTn58##wx faw7SK gaӿH$(PN`/\WQŐje E`>}zM 8sqy硢" aρ_ HIYjwv¬YЧOD$G]^ݶmOZ`Z]ȝ݉%@z2`1-FT~G444.| ?FpZ*EԩSqWcĉ()ɨ= 8_ˀ]!?c&`k%۲{Lee%9$DѤ_ZZTss{s#ΈlP&,7@b UGD^km @j$B\@jkkq /D~r>_\#:>&,ٞ*++1k,/\)b?ecwkllDMMMQp!@(KwrMbq4i/_+VhV0jk[Gj]Y栃 '^_^PRZ(;ꫯsvH_lY1S.XT0;WX&4o8zX. j\(S ?wЏ\{Z A/Fs#Gq>`,_+W̸8Y筼Qnn #aBMM ;8 6,?_:!VWŋwFqVdu Z@\"o^oήwF `1UM^N[KKK+jnj'J;xޤmE #<&M‡~UVU jZ[&äIpG'/ߔW[1?!MeA t=*Kի%O Υ иCEҧxR5~-XxkӿMu<@.[\P?JS[III"y8CfY۷g|UUq j dwaWeC'D<_E #Ϳ/XbEegEVOZpk Yfw./]N%@En sjoooG(Bi IDATii5vW򿩭 2@ϝz"`ĉ=z4vލ+WbƍhooOy~~o]a2Zۀoi"ӧOرcA^\a_@ |I#ERN{{;~dyIKwXJMB+]_X4y<?`1`?пؙfDw}}=Sn 4^@^@,Ԧ mT&xEsii)B^/jjj _?_~ZVV)SZ5 sh X,h4m7itׯ&MI&/_(_כT|"~NdE3?pIgEVOz0K.%@߹ K`͹gM㘖oW/1x`E DR.UwPNP^ÿ ]]](--Ÿq0rHٳ_}UbȠA On܉@) /._4bԩSq&V"_~+ ~j%x^ܰa|-pN,d@N;j% ./,Ս ,ښͽLu_X,V`\Ca_yX]]]i MZBX5)3ZW 5j?pׯO/ 5R^gٳN3#2BOF0PRխ;Y3;W>_} t%0vIV՝DH +Ӕ Z|+B]'pb"*9hZT!3Ymm-&Mɓ'# ~͔A__T id&~^,Z(}}=qVdE d$7;]3;S!_pM ` ~KfBgԦ0'ݔkD"^#"(!5Q#0p y<\< 2'NĨQRNP6S>N.R]TPv6mڄn- 8!2]J|啰=[nyY#KV_㍩_mjM3/ @ J"b;: _Y*P j@9 @Hq|8ƌۯHS-ި˃rrZNhnNcpqFY ?ɀFT{Lo1EJ|G䜲=gC/85-p@jW666bI)5|eUrp8k?[D *"`+T34;^ee%0zh;@WI#/E,Я/UV 81Kfx ٿFW dz{_}_=JR.%UP0x?dz(//GEE*++QYY*TVVO>ӧ`b˱Ҥd.(F^QYD"3:Q(rPVVuQVpɒ%6mZޏ///1vXz:th5rFA9B bشi&L#72j:vF*\`kϟt칅t#tb@.%@i'*2;pH~3MI_.(W.(^K5@ݝU2xF"^SŀX@,)OC%" A; v,Y~~İa0|ptA1bjjjzMÿ\(lTPY-@ډ_\\nx"bN@MqZ%r{@;`W_uuu3f ƍ>GI-Օ(@|>_MPNP^ї|_(T_>>Zv[VC> (pbd dex{v=Ҵx&_\ ]QQQosF%9 ^<=OS/ԄB!477'vÿr9WI /UL|@mX@^>Ӑ͞=gU#OJJJOs&(j+]oFV0kK|]_}UxsG J0}%@2G*]cJQYo43¿` :'e%J`SS666:Bʝ d3-@.'ĈH$ WururWR'w9+C~`7͛q J 8ߍN0p֬(z">_ܔe(^%g=o= ջ-Xr2/`R~5#MMMezdH\( uRAX{*rY"OP(]4r4ڰ~eO்X,p838{I{_wO~߆ϟnA~ ݊[{" 4Gl߾}k4-8 _,g/8`r JmJ 喀`}[1D0$^9`qr _O5FO!z1'cʕ8Mn>}V?Za!٨A<ˣ/Rx`͏֞)4 ,g/8lkX=P[x~C2,ښʿZWn;g+nk *VZ(B,K,,S+DA|~ax1CS>+ G[.]VEϺUor(V_f,iZ+A=|?Տ#~/.3[_zbmeL:kߵ]]]IDW _T^${QW^}V5/V ɫԫO]}.r\_/նS\#@cD裏p5d @)PW`')j!@&&¿ ,קZƍlkkۮUXh_pU `@mi78W}}}ڹ/U _VWW9wZWR+PD`ݔ1G81Pȫx@wSW @[[[RW.(F(KmșԮ^vpsMw?%Ck>lGzƀɯ^r< 7Մd,bǥ'%vzȞQ_` .c `<@ЛHDu[r!@wc%as?f {n ŭ[z-=U1$MvOu>' `ؕ13b _` W `ZR> I_& j?簧z 7tSVypIgEVOvcp7H L#Rw ZcA|$vqܴXfVXyTM=ޘonnzr1@,Ȗ7|{C(~>^3#1WuMG~|ޯns)b?+Gz7h%@2ÿ@ 41N---[r ,sՂ p3cN?L3#1ݘ j7H5Uo>SԆ.E%MHa^Xe/Px<~zO2&zWOP\@Gy_~yVW?ofbw?g""X,uQxgz̠ ݓ}t>92?ٍI ret_m O%@7 : OCCCڅAXp,ܹsk.o޼gq̙a՛HUp4uuaXlYVۯxd\$S1X0Cծw"y? (VS:ȂS¿@]6%2]jllLږV X ׿~p>(N{D(BWWW&ʀt#MD?M 6d=(s4\x *SFD!K,8- ,)K~1]`lU777 >hjj꾛6mgn---DGGGoF( ϝȭނ pꩧbϞ=Y=*og%EOvc߆K:?PqjX%@[]ΰra<+)232OŋޞQi@d3UW].Y=SAOLei!Ү]6 .^AkОÿ@|~9_WSkҿ_PNWXj!ŋcy=vӦM={6455)Gd3E~ضmpc޼yY?vP~phvo_T/׼ع kή(#cY0˹`.%-_` .P70F-6*0w{oA >˖-C[[[b4\ȋ iG\8|;g,tg]۱ku%Υ]xzt=,,Ƣ_~;~οРPH )- (@,:y0`7?Bʝ `Ԅ_~Ycm޼W^y%~ߣmmm2@P" @d t73H㇒ ; wgGV/hUj '%uXVXʅ99f8c_p8TL~xHsR -¿|6mH4,p{_~s3=U`U)~}Gt/m5KKKʭՆ+G>h> Lq7mڄ{Ԥ:-%~f~mL0^֏Xs0s^gGV/[ Š{`#,;M %@.͵,Q0nJ aV+r @p\P(B*` I@0 Jx'pO?Mȴ6U"+X8W_?֭UA&EO,M_TYDt,j\ornt/sMAب:_ ٻy=9)*w 0BBiÆ ~?سgO" @N ,[ ƍýދP(v |k?ΐč_HU؃Yp /Eg%s09i<_Y(Ca6K{U3 ϩ>gy睇g}6imNtuu%F@m4r3}Dpucɸw>PI9 @/|@s6 !A@`}Y ÿ¿NV՝Ԃ~e`{!@^{5lܸ1}gew" G޽wu.b|GhkkC[[[R P[TE>0~x}9] <: yiL(- iqK?`q (ڶvrl-1 ,'BJRU `p}}Зz* 40֮]+z+nݚٙ H  ;v9眃?k׮Kftd9 ɺ;pK Q^T(ÿ yYca.!k]PKotoX8Aei IDAT(- F۷㭷J{9Xt 0:Jpo=\FdR|[Q6!`OV]ı 1 ?ހ/>|`מlS@ KolƆ ̷GX8˰,T[@^PPmǘ7o:;;G# XWnJ0---x衇0k,)hΤE>9ka̘1[ԔqSǷ$w`O&iU'aq>JYʀI KBH%sJ& *_ x'gx5p܀?VhQ9-[n^˗'v w p}r"W_N)"/02<0'S%5E wML(%ppBrCr*@Z^{e˖ށ~hLV͌;4B͊+p饗bΜ9XjURjdg{sرcK/|1&ħ{0'Kbחikбh;_0gf6*KT `}@|4ふUA$ŋqkuk@QB *= pw]w݅Ƨ<5@' L_нx% K}KE[8)$݉u/ vh5M I *V߼y3-Z>3*X/[g:/LJa,\sΝ-[2P9"@c"ƼyPWW[nvxOO)UaOmt-~@! 1pZ뢯Ѻ+O%ڮl~Od rp=d#֑W&tпL5Kڿ_{Mcz (Y81{Q#TL~1@Ye<<] /FQ,F/7nx~oghu( |ÿ0xzrVVe %\,־XrsÿԌ0W_ծ˿#^:+Ëk!V|t0}P~hiiO>3gիUG[X7٘ݍ'|'NĬYvڼy@ÙLFY0R@ږKnhƗ/;; ,Hirnv_m!@-h4?}+e:,Q['ϟ_<xWo} _|1wEKimmo~xwO>$c0&$r6dZa }%ÿ9,W,P[+ ,Hvx`*rVBO86lҥK2lq`әpSH|."|[s=: l@Rٶm* 27t6mڔq+Sg3T&[bOuXh<,c~XZs: % khhP6@y?ׅ3{- {# ¹f\8餓0|455* 6"PNh4+V`֬Y1b͛^}ug_܍?^_` Psy,|nWVs+F<*y{n|= anRԭJY}o>yH_Gג+͚¿(IOCŁ:]>?[BiׁEi9r$ƍߏ2DUU*++QQQrEEE(*?db1a <8Vb+f! jŽUYY?^x!ƌx^AQQ<Oz$"R xg?9֛ t(rdz7=whk0b~g*9G:h cُ-WlqU늱r)jBo}Ŀo(׍6 FMMM?o~8#Q]]]j=ʯs4ʕ+qeaРA8 a'OO{1'32^#~_,pH7;(#4H(Fն 2pᅲ8 QVV>}}MPVV@ χ|(`zcٲe)W>l8qkj`mO>8c1{lL8%%%())5@~+FQz82(ZZZ0| 6`ψ%{j?>v@yyyQAA󡸸%%%I3[}͚5;vl~o$a9RB}_4ZdĈ8묳p9砺:" e~x77DkkRs~' 923ÿ 5kMب~ZSS , _Iw?jiXXS @'4SGu@ @UUU(//Gyy9`b:p/O{Otb1 n5j6|7nf̘: Ik_|\jDwSO_Ɩ-[4x>!-}49$92+AbP<_"}~s=gyn2H^דY1 [^aͅ  d` ӊUkAKBڇQ9™_` .^M1}tՅ@ y+| )S`ʕ)SSl?ds;pZɍ6M׋Cbԩ8_suR^@EvR֑,_~o>M+1~4p`Meă{7ukq?F -U1kбИ[¿=%}>f̘k!@yr'ߏ4e`D<\ӦMK{+FOSm9v Q0ĨQpG⤓N¤Ie\d\H/k9nذ/.\˗k:_ֿ8{9c 2ÿ,nK0g04P%ÿ*غX/>uMmmm*ɋȥ2.v܉͛7| 5g]`nh?)o߾2e nVթNH7e^(M6_… l2l۶Ms8z_Á3EQٗ 5d` XpkXÐ5zHG ?쳰a*pW.K[ zprtAvލŋcҥ㏱f]08@DpRt+۝Q0bט# %c+>o_` |'/^O}ݲ|gga=;G XC {(..N FB$4%@.CS=&/ƒ%K>֭nAu8}?>,9ÿk ~ruK^ a-KU :pLSk|0ÿnX6:{4v6%gXaok[og}vb( :PP6mªUg/uqFCþO}o/HNK_ÿNU,Ku,o/4,rsx> {Sl>) 8ꨣ_/,rj`@~\}_D"غu+KYk׮źui&l۶ mmm*AQk꩐! , u` W0:_d2ľv Xhgʔ)OA|>_{^ۗX P}6oތm۶a֭رcoߎݻwchhh@ss3" 098(0!rS?فe./ u` ІOS¿]8M";7L:ppK[>o~9\{oş ^o@nVсm= >?hӹ1 n.xC>1ۛc %`\ Yo3Y'~Ј+rnzQ \0 y +멡 ~g3~x\q G0G Kb$]Fb1;k֬1T_L9m1xn%a+>A!^3/{O],K'C߃޹%K> ln7,z; sZ%?zh|M*zOL(X,~w٧&sԁOaM%]lS0;q$X,&S}6 :_ ~G \KƍX8^`SRoz%@*jifYZ$AKK Յ@ h4XO{q_~ =+ӟd):&V #ufÿRy0gXP K`9_,}J%:DF[["{K?n Ku,Fޞ"Ћjvww'4I w:_ п,Űr`D0 ʰO6^ySewSb0Ɨ¿`y\S,`5=# (X.3q$~?0""(kX| }}>x'~e\03d_v =(2[;g$%GYd ` Vp ÿ@Ktww+bPz;1J@ nvv Y|=5 9}Q=JE8,rKR0;&D񅖿7<7`~nS Z㗯4c%62^uNq{D 0`ME ړkO_ӥ%@FUoHןE t+%; 8a{ DvVcGxDux=JݹL6GD NmO%@;yQl,MKq 0JXc @h4/ߺ{9ZjasBXd/U0;k %6s %:DWrHՇes$2¿_ږZ\],%z,Ա L\ݗ&_Wo"rbL+nҩ]@/ 9=\_,?;,Ա JMyE_)!+SJo[# }ȫ߂ K%}{\G/jXS AV?O"! ,3xz%&B @ ^LSmJkn5E`5͈Fg %QtA_|_"67%̭`Woa,X./3%7o%-x&) 2Wmޑ} XM pCև5Q_` K"*+$qsX0b)آx%_pD pa=:w ""2^fS3`Wo,` ¿uI ޻Ѿ%4 BQD:4%ÿ*aKmK[]l)v ""2 ]PJQ%ÿ*aڱJ%@X8J @DDd d_^]|zO2b%Z(B1tr@bxQf @DD _гXp=o 6 ,g/l[_ unq*z!%]>;oÿW 3KY= z_w tN)Uk/]DDVv;4?ÿ0?l,, {z_Z{ÿtN-QDD6v-a͏m/ /J,X03@XdgtX~ۖK + cJX[0'C fcP|僊q_Rl_ б'o'@%J?¿` X%@2#¿}Ut DDT + V@,22 Ϯ3_` @DDN_0`ga 卐_Ht(>\ߴ=_` @DDN _6ˏCo5`gb 0WkzlppbcgԵ_` @DDvI_8lJ+b19e`KKz_/ ""bO/Q03[ Ц7Z|S * ,n99 z V@', + ܧ=_ t G=Xe/ ""kL}堀ÿG ou,t @_K"":H{ \Rf?t6Q>Ƕ"-K;`3Z{׳8cw,Ȫ߾Vr|Gz|~nj8ۏCRX o,  @ED P9غ%)=k\] g׳ ""`,v_ pV%?ÿ0K%+ؿZ8gؿ;;X+0g%@vXFmwg/ ""cϝkK,; `:Z%{[JXS1ϕ%~rs?:{ IDAT M P7S}EX@6ش8M %DD4 sc 0lS窗NĔ_3ߖX%0dϴ,\^XS0kǕ%9~LW pJL D,eF `/ ""cמKo0x p)87 `5&KCKjCJ}GX]1Ǖ%>8J>Ak;gW2 ` `@"K}-' ,nnF[s¿ 0%]ÿ?Yu]c.|Ѓ bXG_` @DDV🬺.cTc{`K0XXKhY{3¿?U!c2 b `-J}) DDd5 ɔ_` ` d&<Rk|E/ ""kes Ks1XKjKDB#ÿf/G~M) ,ߍ4៬)4 /ٕfi7DDd(\ 5+ Kc%ʦ0+kC+oDDd4'A /0¿(mM0Wow ""g /?Y a `.We¿{ p K""sb- K}0K4/Zhb'b`C,_㞨fW/d[h`'+c`S,)bO%iM_Ta'c`cv)(z? e%ʍ_HUa';``sv(6 _zCK8f~_ ,/(K¿ 7 d,%3G*7#X/Q >_` YVژ/P%.QV1ݰpΰNyB_Ku,o],1pN,mnoމ.j@Uy%:DDb>1]p $$ٳo}%@Xî?W4]oE,X8K{1* {ֶm9c @D-;/WKYh.%? c `Fa7K "҆=!z ONXXۦC%@~X)_`  ,\%5mz1e?iZX%Q~ڱZ ON%XXU¿ ?,r/ЎUJr.a @D%v.ɉX KsY5 ׶X%Qzn KU0Sp!zv ,Թ- ,ct ONXKgd DD5 ,#Juݚ[ONXc CAAA͏ ?, *,? c M/g)±e #DDamOuǴ:KO_Uhv<%r @'F[SЯK"r+duAL}ǵ:J @kF[Qcӱ.K\ ϩbh4fܔ@🬺.cTʣ៴XhÌ/YZcn ]VջKL-<ͼ)rdnB%??i0f%!`v c @fIpݝEѤ[&]W#ÿQr-\ ;^b'\(nķ /5ޥ/\mz~/{EM?V`Qs ce[/Ͻz֐(֞xY^4EGG""jD"@GGZZZ QZZREEEm(.c&5w╙; ̉_ e_OR~5nE=bK$oϭ@PJvj%J+Y9۠y FS;4Te_ԥa}Ykk} i> *2Vז`g'}%(ٱjuf?;03XPZ,ҳrE8vN%j}J3ÿ(5d Q d KuvJ+%勿\33y*2៌5(k\`/;Y9f7`uX`L-lM+\j?gYX곁}>ʕ]>Oew#ƑqMUkH#(w㪀> P;bOom DXPNXKpdm.6چw,oE0`%ÿruX"`YXO jgAbOom D8b8jsdǖu5ŧԯ3w:¿(!Olb/;r_G:aOom D` N6%w7X[9rNt0?Qz, ,X3Dt (3pM`eskX|MkV>5k5Gcx]?T2[?QvXPX\\PV}>6K"r"{zԯ~DMݎOa' KK6g|n{ڣOf @DNbk~_,,(7,H3,/v,2Ӿx\b򛛱&4n,`Kk`' K}KETU`j0Rc_` @D{#>f ` ͱ` BX%c,LO? ,k%^ c `,° ݰ0XlĚyV K""-0?QXX\؀ʓs `/ "7cK}O.t]%¿܈_?@kX!X0#/_X0YhH[,0,&@ÿ܀?Y^͏@ Dc@b c /v~`| `/ "'cOV] O?U߇%092nE=bģV  s p;*qةzWևM܋#PJ5?1[gleUC8nA5|5_Ģ//46/4j$ ɪ8vA5J/Gvԅԣ%:U>L%@4CQ'5gXS0'SA`U8V`' 2KFZvS3ֿoX1'Kb'_b=_54j cR}0Ddov P\ 5?nY`SX &^"S K` c pKÿ<%1l¿x)_O(W,2XPcVX= Z%q,%K_` @Dv/hQK_`'2 ,%Y¿PH PHt-tw OdE,ȒXXz¿ȩ_ȧ" ,ϫdE,ȲXXzc36d/ "+qzr) K0K YzX% ٔz%@,M@CV+ R,Ln B@/^ʹ%?5 c @58j PY/Z͙%?ux}JvxVs+F<*y{n|= :Zw{kYYqϙsfΙZĖ*ScۤMjlcbkVi2^^1j-1m_EohR)mmHE03 s鋽yZ(#@r(UGN>/+F č/Jj N, Y]ÿ$.utwLE[g|"gxQ I~JmÿA P? AKH q@(+J %@5J PP imC Jj@i* i@(+ W7(Q!Y WF 4🇒J? d`p @%^J(@z(J ?&E P🧜K?& d`s JБRn%@5J r,Z L\#WNcim3mVݨ4%-HZۖ%해_Ҫx[WtvO#S@(<(!- LŠl]:t]ߠF OEPxbWÄ7|1o`OhP"4%LšR 'Nz^uCا7S cIJ?D 0}7_^/ܶG. {E()`(%ɇh ?%?* `D!ߠ"cJL¿ %(%mPa1O|t:KkmF6/iAҢ޶,iV} ޺K?n?o{{[syv.k9f_9uzɕ˄? `I{.d%ῈoP#÷g}^glPJC | ¿A L2)<ѽLsT_H (P@w?ߠCGj@(J$¿A PPL_wkE[?9v`&_U(!(&/ %P(/Yn%<h0"JKߠH %W7(P:?RCP%@} @3(!CL`k @;( !`rNcim3mVݨ4%-HZۖ%해_Ҫ]ɝw{q}¿k:n樨2?RC0 0%%nQ%ɧ7- G^o%rFGjFAx@ /XI8h*8,f%L ! %@\¿ #5<C (:?RC0 3JvC T?IQP>JLYxP `Z@@/! 'E X?_(PA_"Ju@GZ|B ?!K.GJwK o@( 'd pI yPBF 0B_K{?%#?P:t:6fՍJsm^҂EIKmY҅n=zE|rNGǻ5go:_Jiz=6]G  $H@K`<}$T#7,ĕ=OGQ-1_}=*MoOyQ\|V}S@ %iuλj>Q¿ u1@OX]wD?|`?l!ÿ$==QJ0 [}czoVg G~(::F /DD[7CMJߠ(KSߠFD@'_߼¿A PÿA IćP%W.u J J >@J/.vo%E OmCtQ`8?6QiE /oR`0?QsJ 0&" %@b %Ā%d%ʜ.֥C J JbA$`={?axÿA ÿA  &@"(F+- OP -@l(P .- $}C]sJ4 kVw9%@b,Nӱ6+i6/iAҢ޶,BIHZ^K>npVvPoIK|+9% 6_]l f$ V@( , sAD P¿j$]!JL f@(|^|<%7]l;WI>\hcIoT@(Q- sٿصIo PojL 0_y"HJ4>,xEIW+R_5_v :_y!H J4o/LO;_/I5I|!J˔AeH@J(P ¿\_;)i7F М¿̈́ޡE AJr躣z#!v=J?e>g}mBچOm}AJ$|2W 0_i"H!JRĚsڼx5 V$]+酾(%@8-eI{%H @(LQÿY욅Ik3`{%_7_nH25#i+@D ?Q"B ^{1k/`\-i~D-`V+W n Dd tL[vÙ ckZԟyu(J(trglP`# 0_q"PJ+<\`fyAp1QD%?hsD D *Q" YYT,K:o`|QkX\}LJ?%@2'Q0ZNIDATZ ϫ?HU8ہװ[:OY" PJI Qmn@sgwYҹhMߝ/& s=&Rd G@(J$W-r݀Q~֔^utR"|ŒⲂgϭR4 W@(`GLwW4>m*J%ݳzQ^@ ?Q@BY{쳳3 H(͗٧[T]`J&J(%@fk/p wnݐF Ѐ|̈́ %@ PÿЭ gBwV&JVD'/s-kQ"(I% K˳7yngVJd˰|Q$$Π_f>o̝٪˵QxY/8+J&<ۋA\.tmU3[u%%GP5͟:18W~QDDOzP8/ˮ:/,W@obK^ @ ?RQD D¿ȝ& I$75_J3_-#(YFK>9 {aaϫw'_t}LJ|D;{YI0׉™5u3k,fnzIoS:>V.Q 21}=&&I?Zz8MCP:0W+.tGgU ]knGJ%͗cb+^+\ W+Trwr%\ 0RůMsL v%=•?tQ -g֞[Jk%@G`$i 1#"QQ%@[0+JE?s?VP %@lAG H"h`"?`ﱔO :댺3kvA|:D|:@<P/%x&Il Wcgٸt\ ? F`b"O`4QQ %@;ӡ?9Jv`4F Ь{?Lz"(xA Ќ{?|T %f(AP ,])M (xE ?K8IwW`2ߌRKxJ~) R)!߬Js<7ӡL %-Ϥpf+h83_G (%*h!?bÙ-|PL~P!Pk @o%xFPg#˭h S.`4@c(w_#]Άȥh(3_cQh%@{_&*/Jj@(6#!?JVPtӒZ @OG2%–@:NYI$yI %-eI/t·{MlU5x8u[3uuFݙ5sܺ3{[{^]utΒ=1ζoC ?י Q( / CJ+ nKo O$ݤv?4@4J(y) 1 @(D%Jr.< ɱ -K?Ĉ@r*_ KDr*J -QHA%}7˨&R%E Z*Bw Joy<&R}j @/[%@ݙjY%8 Ncim3mV6Ism^҂EIKmY$"i{m+z}%˚ێͪ;ԟu֝s%{ )<_"i~_C̊ B KzNޭDOV"%?A)P@O\%?a)`B<@RRx&g DLRx&gT3a wJLA% v"̗ ;(aJH%@2-kXum/3c&/{dZ ˬ c _y#Tw|TȬ GI @/`_+<,~uϵdR3 HiP,I.~Uҕa;~笶J @h @/%jvY2`I6?ۇ C=cU>0,AD%PNb%.왭*{?W]``;DX @(d)M,گ *Yku ?1¿{ z(d+J |L97s7gK?4@"-h̭WEWSi `J`v&([Ѯp>o?aU΅ÿ}L$(!`M7Y.?6ئ%*s7xL<_c$%)ur  hX/i} P[ ݠO0si󕁖KSOv*0% EP{$|>c{鿻%1J{vῪ}=W y=~n{L=Yd >&@8˒^'%[%q]ՙa"jH `ϭ9_EN;=[WF<_#~GmH/Ic?H)Q(vIW[)u͗]wAWeUgaޞ[{}vyz]Wub2,.c3wYR}.R?7mذ"pG?^us3]u(Xsn8[0o7g?VϾڡiY+#%=D3v0QuD? @Xc.xJyuϒVxUgܳTfYQg{lnݥaJWZ:&cJ P(tC9ev.w/o% " ^v+ᄎslecT@TssP?L@reXև]QfnUU ۦ]ik` V!<&:h>#MuQ}ԧQ50 `Ȃwfj/tuO~^ЊD=.Qμ?Ͽe  1j/{[е~  ]|L Xc%ƹlWWO^3\ ] tLv<\wD Z ^w[UV]ֺ) 3Kuqp1Q T[ c[=OD_c uЫ=U"@8&@(` 5^zA.TpLQ5^2W[偘E.TqL8Q@XD- uPP @@((PP ~uiKuIENDB`icnV Bopenttd-1.5.3/os/macosx/splash.png0000644000000000000000000004712512627373447015636 0ustar rootrootPNG  IHDR4ȔPLTE       #  (%"  /) ' (7'<2 9 +#1$&'%G B#9':P) I,@/Y*%CG0463$D@3&"G/@&\2G9,N8$&Pj4c7*TY;ACAU@-,ZhA};iB!cE'LNKXK,4BG56؝c>E@SYHH;CJWRRO_TUΰ´\]pZ^fgjppwry}Ǵɼǖԕ bKGDH pHYs  ~tIME 4sJZ IDATx} \uo~;3զUײ%l_-e2OYEt׵r,Mev NfHh 1l!0jn<0xI۾ 3`h<}.w'~*໻_SVws M{/*`YA i*`g8?Eg])`)7{[NSSz^ԀR֦ ].俟 U=4N_`kw;޿7~?FW~ o} (PW?W@ l 6&O@K ԟB,5&! A@HC/WQb@A&GS]k5+ٿlj P?S;C Ԅ 'X!~`{t`I8A@h@1* " V|`(.`o#Aq$2<?6P{쏹S?@5@PaT8>p*7oO1O6LouҺ(`,?_BCKHAߊ3fxmjjO9u;_a"D5 7ƒ z0S)|W>@̄~= !0hE$(@HP @AM: r@gDʏAdۋN_+?>?h_=d?7~Ho  o@b]pX1;G ?6@[)60AZ!T9ߏ@Ȁ|;e~S'Qg˽TcX|7!  `]p $M:2$@T_=s I?:_DR+ &u# nYT~'KPG?E9ٿq5MW58I+5Dĺ)'.`'y?05/,_/(ÏBj"!@xv ìMOd̝9s.\\|I%HDS?X:^,m΃y½STæ:M_F!jRNv]NK]_[Y.IKN@:DSIEYР_f.wΚEu1˾}AQ#>`UN"`'C~ W峖i;bceg@0D+` !)@P@ps|;_l!Bߏ>( 0DЛQCz *_Nyutt\j{}T1`UH0D9<bet{ԉSi,|EWwWww x@藡p"u+uD+@I_&4|C FfX6RhgZO'S{AVZfҴn4TyTL!A!Q O_({vn:w_@PgP1`?$&p,DaSL  H X@E*H >JoaQ* DTtYoj~P g$Sh8)ﭢqBI47Pb4 CZEU@ B@\GRD2hX(`|l"cb$}2i X6Q@[OA ?!}|OMQ5ſ3.`}%M淪`P-v#  H.Yw~!P'AVqS2=@A*C,H C14fIiTk4}S ˶^O,޸u 3'LPe6p<@4(XL B+.`}c/~_*@oFܹO̜0n8DxWji T'U~S.`}zWL~bOL|Ν9e?w*P7>mt<^`ƍ/v)h1U4N[.`}lb ~ܩw YI$O@Lmri &L:aʔk)%;}Y>6~+640OuW~qҥ/ivY i辘jCmf@F5>p$ʌ X_ֽ @חϽwPbQ/?6mxm!Үp]\9{(9B XW)MP,@_/s(}a̱g+_|_|qȾsmm.7cgu ?֭{{6I} >d}Q r6Mn$ Эui?ss~Kס޹n|h@YTIM@#8̟Z-&V=Y Ia-_๳k6j;P[m/eO|Itr, @?4ۧ*VZ8*KgqJ=..(E"<|mu5Klk?܁ҧ ARhjؑvBUv p/5]]p~MjAC'} e:-gcU&h`F3wQ}<&ѹD df4p4ymSWNl" ADRGpvbQoHlBR*!  u{QNm: 4fx]7Qu?TSxS!>9.hRxnv0v153'pB7NzM^pqQtƴ.]خkr]f_QW 쏃VJ tdrd]:E_d'D| op6`.y w57mMS'0*) c=hȮn3MH':4]{0ϯCv5knڸu;E*XGC`DjB~?&f\;ICA*u ;ȿ eU߸u? 8~ea hm:oX!?!f.BigσA7ƆOh_.;b 1V&~e1l"L`zwiwv AfpFPP__ ^<1`2`v)ȿ[ͱonDA (byHԣ๾o;Jkt@C͙.d}1QZ+LQjAcm}-.o_~!GVD@슢}ݟ2 2RTtifpFhz|A 7|k`Ǚt@zʀsYςh'BO]ae S YH$3\ʞ ږZq5li([jU.bV? pt͏Vaq*n@l0:B"kA$;a[CmCv\w'?' n@ 0E(BZT9{ܩBzQh)Ee7oh0,/'$TN[ŝ/Zi 0_10/b]|ןhgP"P'9AD~؊1R2$x Ԃ?'daY~ћO|?~a&O3|7@7q;BA2#M'͵aˣ۶W۶mݶm`mx@_Mun40:]w3 YT P vq[PKlֻDtJ YBԚNرt߲e jzB_(v/,O䣖DR.3_"g+ۇ_?eg @Ώ6- 6?8^CŽoA̿2idEAo0ذCx}}&R Wv{iO%h#Or|a x=A%ο {𐙷oV_KbOx^^S;رrMb_ D hZ|Ɲ|.-C::R_j``Xq(@-H-d*zھ/;6S.QB&:$6{auo]N>ww!b&ڥP]m~&)A#_47T^U?۶ЗUQYPSpxzD8ۊ_MPP@W{PM( &QA x8v:+>ۺܼv[*|WPY;8W]>ĂG @So/0L#A,^{A;_=@~L'CZTW@[j 5U$:|HUPdCvtoW 0O'#í렀 A>)BX!҇ YG9ؿ*w+B]X/'iԀ+$/'0>] nU?K=}\~?l8>T``T(Ne6)0A^uyPd W@*2>9^Y\e3ڟ_XkB=, }ݮfA> 7%C,aՈ,@_6؆y9v)/׆;tQ E RWm(8`ǰO}7R :i~.W[ip[|{$ Cl .ސ/liTWo6ԃH،oF賲4p>`74F5jG Zy ?*< یSf9>|O } 9D;@x0ͨ kQ?h$gehDS765nR|;ݻi \Ӣ4@tO+s&:qU6Q; Rw<`(h/2d TQb>ptFĎ^,vLj3fFx4څ^O> KQuz|8J3O|L4~K ~]UJ(3 Mn_VYQ=5 5Wqkc Qޠ1mn&L#:~3'wV/yC1 8ơFYCH4bWձ;̞qڕ 1h((+ů6l;z]p_>uP@=5j5P'UB]Bd3 2 :;@hgB(C^,.nupnJ yDJ@P (pHoog47b@b@F١ǧOՃ>T-6"zq٬ pU̜,i@hVY^j4Dz:(hxtsqEEq1F?@ii)_\|hu3/P.ACP[tԧFScH'B ]bC iv)?@)|( L(~=be%$hs}P@|Y4;(d  Q!3G!E0+ yшZxmlmՐ5.n~^oTi\ZO HqRma^V\xe  =s٬f햆wQBm-<$FMF>Oˠ윫N0_~Ş=-55Rvz/DC?An((+,-.- 5jxC~|3i x@HG ԒKP+TU+_w(d102X+5TQx͂7 =t3_oi)++TWQ!=|;<^/$>^,v/ iLn_AطLV؞>Vky,r#д#;;ܕhGބf[ZD0Ю7aC6#;_1ّ1i "<΋=59ZSK1.A +ne[^&Ԕ7T#+eX'RRbU_(>Q|07?7,V*\tЂszCZ4@ TP[UXP4[p;Ź%Wқ5"/+%Aźe^~ޑ|@ZE.$o=z} @ölTn eWEthGl .t $A̢ҪiK1@R]Biz(?hu!ɞ Z(̿׺[h_+Wp Ǒ 4ٱ4UU4bU׮iz 3p)v$;@Or26hƪbDztx u9x4 tܫAs\ۼqh81s-Xɩ J_P;n3e<1iڟu"˛3G@2*@v R: ÃE 54ϥ+?3w5ٳg+@~-0xxYcǖm 7gj͗;? Po (FxOP;"K6E犋N^2hLD ?w}f,rw;A6 @OHtHtB?mja&?дyi H/D*vN/yՆ XbR(^w;@v&:HK$U=w!wHyk IlJ4mLC&Z\pQ1tt KXPv23X-_"SУsI^0|߫1f;_%Df߶FU e'UT=zgPwdXxiZ 4m ýQ.^@lV)%{uqeҕj _Ξ[HhEۨqKC916WV]oým-b+άcB*|f>\|Ʌ,dta~BT=/Ro^pӝ7A\~ki*aێ-r A$wDH9ż>PiL)PPE=-5%@ Ǖ 1 &E!F IDAT4>3+ r>.3DmLIN>k*tF'DZ4QΜt I׺c,"V#(bgh7c~G_-;+^v4;reܙ$y*>:R-J.ܩy:VaF \YDOD6@*j Aϛ0% 6磖b0 t!/&φtɳǣQlh4@҃-,{/h5*ZÓ #\eX_(6/mf9 !1 t Xqv| <K ).3[ ]<2@ 4@icc"|Q6N/*С5FS8f,+V0[m-VylVxWWgaRg ʞ /.Lp}i4!|۱[tԦR߾at&6WRR4k | 74Q\ $Gq-h8c(AE5L[#Gc"f aWwgT\ݤLrtq`t x28^!~Qag̑f9|\<^QFfV571⭌Ae} AMͫY?ѱ#5F 2HF>=S~i.}^ t~@:*|QF9@@:^w kA2 օX;GsDrS!2۹u/ OO; ϭ /W`Gv/+2@3֑p/?WG]'1RvV!3ҢvC;ae9;x0{KzdM!ώ+~2MT'Ҙ#xjVḢt#ԡ~!UA;@fExklL.ʚKHSͮԎ@>;Mpiӧd{nYd,Mn50Nc$At}\Q\# ^!;;:RCe+؁!9L S}8][ ݥÞ{ze|hᴳqL@QlJe)8Ʈz$ZF)xgȮ>P\}Zu⇜V5a`(L5-b ܜ6.2ݺJMSg4P^ϞA/5vᵰ{$|e<XPXMBٮ\!;[#lX¸t(MNLd#]t.?#Mcg#^.((Si1K+J1ziNDžHnqdMo}LWm]fYG1$IV(Nw69=!+E Q~(ebfRhr*hCti)RHP̾㋱'}U>)&LQ<16|@G{Jla/vGקfQ&[Ԧ&vut<Ν_,yOPYj+G̈́ڙV+Dw.M.3EQ{{^ /mbRb4Bx@V=+~ŧBx M12òuAO -)*wgg4FȏeG].!˄hx2o3[w^: ZDJ+ 1͂C|@m;M\ʆΕ P;û’Ri,}( &@@3619֛T PG`q!Eqa836?Ƥ'ԟ_- QɁLY.?R +#4Dzaph'(G| z ։1\nQ~Q~67+7 ^[V\_ <Ӷ3'*Brz嬃Z'8}h}y{H0~?+@bY21t6 5P1_E4!|+ : P0\8ǯn E :eŀ"fi&n)qNmע[;AQni# ?ؿm9Y>OIɘX>w>'>p:ֆ/ NW|b5sEo>n;l[M Lj\f.$ 'GdOlWp1;*rq 񟓳6/x3_~$ǓY1uk hf5'i$S@(q^z@$ ˦?7zZ6-Bʠ̣ ߲cwdYYo7/hCw)Y[ri@F,~ W,rH ~x>ӿ4X.sMgFC0QA @3.sb@N;|v{C!ʕY9 Ǜw%XTU{Un/yk32VN` _ɧ4X_Z<<9ow B* =fCh.tӮ~(yzRQ%2֮H D_ ῬZM'n#3dFL2]N'3ݙ- (ءF:?ƭ祦.}{Eם:!7HQ;jݼ5B@>?gZe3 /O? *A!KW$<*sقiV&P;tut| pt@P /uᴫ8=!R[3cW:'[N2x'23\80bj΍HfPT yNPB]?h]6F,7?螺pδy|`w^=A#!?xDE%+>+QN09΁0PGqr ] yǖ@{g 8x5WaGf>J(\hΜ~c  H`0qNl|s_eSr;v>tO|]3Z<7gʈYVdw܃s:|*?#GȤۨ 7k9J欘`u"}~A/GZ6F@G(j 8~"*>m2CwuxWmQQ|yLP* 01#-Y'$|Zfskyc gꟐfLv@0UN#EkHwڢ9񄝇B$6'ƭ'| sdgg{vqqw(tKi4o~H\.p?7+s1ňg@˜-ٗc"LcBdB=de·ŅqA'.TB*_?Y(ϐ?  ;|BU$ `?eYֆ#wEbb6P{EYץ_]km*?Ei!w r/|F@F.u p8&Uyc¹#AQrx!yC zIh-X{ ɧ^gWާٔҚJd@1" #ndc%(g2R"U {.Y&wX5WZ퉳]ݱ;5ܴ^ϡp|ko`^2(_R\Ԫ Q|"Wma' U +5q-{؝D vڦ?wJNU)U_)䷁@t0UBP߀^Veq+ -8b?.9zEQt,Zx6FCI3CQP$ UT9%' / ָ{ ;MR'(3 "Ѐ9^9t([ꒆЗ LMǝ֡DZz=D!S%)¯HQ2% !wyFmoT'T,g-%tc1uS&ۦXGF{;0UG>/[g鳀*Aw"3|@&ALrIczT@B.'?&{b‹AJ 'Z-IMJi pfXe|೑7Hbˆb{vT2 '~ hO8ȻŒ;(y+:-?XXԆ>@Tʐen!Esfz`lysS{=d`GcܚΞb*pa߂q> {`*D `@g Ylx.ЁХsW3uEڮ!YމIBBh+sȀ腏כ`"74z9 YO" 3$ʅk)Ѐ, \Bj l$~*]& @AeGi.~ "_X,C- j$"lI8<z/rLϧ z<ݑ\Z<9@@T{.Z0ۊ1:vOEf.7m jwx_o&>RS*:o@SVe$Y:F6vIY0nE6#O +N99+*|ȜtT-[-CbK@R*+3_yGúT'c~;-F[owr=Gɒ~Lj453hv*WBh`N|@pB 1e{>ϞR8iC;ΌzkfmC^ˎ{Bs2r^~9q7>ฒ(a91JcmH;$I)\$teq8tn,ځ6ni3=ϸ6Xݺe{E~[b DeJDG}1oaϏCʕ$LG\z_Iq߇, Xy t閊L ttGY"90?l߲4SJF H/+s*>8vY叵#^NКeMW%%F( SS]ܢO} k4:F P(=;\eǎUR-mT:b[AO%[rvu=1ƎkW&J Q I^dAъ$@B @ &Nr3FSdc#cm,k[/m2pP =z ~q&xsͲє`:i2lQZj6M,o؋<u>>p gO"&2`}, znzQ[XQ"@Je|͎oWYdDP ]4 0R0A9Z.1l >Ɖ7?}G+ˣws&ۏ!* SWG.3,ܨTꂴ\&'{'߆'|kzTUG\x(0NH(+oWWcDřrfGcY \iGD\>jrGWm (lwۇ0K5uh';xܟVL> D#Ĥk8(4W4%%{Z"1wH}nRe/9}cĄYzXDA8V!cU75$| 1 La/KQ@> 'I#R$.IAձ''+!ݐE^ LUYc9@x𗒜ydST>\@bx悈|T!l,Bu쒚F.:00Uҫqu?-I.YHj`0}I#l5A IDATGCq)49ejrZ 85G tpT A`@o&)X( F }oNSULj%BIVɚё!e}V }\{ݠgQL#2)KK2Zt1טb#Y9+"g4'?bi \slFl􀶈K>fi?&%Rd'dmѷl׊c pj?cՆ@?286>8v{dR ?/y=h]p'֭}28d=✕OW,8/#tCesZUjT /?QHcW$)jC Qj&famXj" ۚ~'M5Td_1d@?dc(mCݡ[p}@ EufF[+8?cj ]1uBro[|RlwL&!q; | ! +2xJxGH Y fF@bYD/fQ~nY$ےB/gb?f83¹GBГzY,H wԝ.+]_:$?bÓp?c`d蒍F>@֘,IF3̆IgƉi! -OwK"2zp6QΣ ,QSSsV,t:CřdlȂ4WZߴgB:Jt+V9~J^O?ze_a'_T[G2xq bH^Ӡ.8 aj/08Կ6qǷַBU8oS^'D{I8~)8aq…V?b!(z#kmz/pLXbw`a*y&`q|:픪'ēת. 7N`GY0'{2`7KSD$+I49(Δ ɩe1!nӓpgEF׋>DG`SE#jõS&a0D6i %6_O^vV"8`B{o@@HC,N;-2OMt&*ֆGDWO')+#)qi҇)UTeG?brETwH8,SЀ: hr(HhKc:n\YOQ eQ?8M?3D'4z'I+Ъ^7EB(ڤ*fhpLu04XOzYB?qZ:$ rL'HhZZwJ MHx$ (FO_|9PfNVw#7'o\hyy }H6?xg,1zg|G$:>pP}Kre]lqH(qӓeuiZjY.pw 7.B$c72F.+# !'\{I'Wؙ!o:.ᾉ}! (u\Rߠ5I({Su,Ԟ[??0%voID/?9:Dc)L}LRdF>ѯ/?11#6^yy)\nyjO :3Tk9'YZ(z | ߓKdgW$+"\VdtuFdiȷ+d%bg40K\'E#cL )1>MId [b;kND,w;߱NqnCĻL!0gѰ },uw}yn-9cG߷ >2X~[=i.crrLǧ*E3UAe* wnΛ +ZIENDB`openttd-1.5.3/os/macosx/plistgen.sh0000755000000000000000000000301212627373447016005 0ustar rootroot#!/bin/sh # $Id: plistgen.sh 15062 2009-01-13 16:30:24Z smatz $ # sets VERSION to the value if RELEASE if there are any, # otherwise it sets VERSION to revision number if [ "$3" ]; then VERSION="$3" else VERSION="$2" fi date=`date +%Y` # Generates Info.plist while applying $VERSION echo " CFBundleDevelopmentRegion English CFBundleDisplayName OpenTTD CFBundleExecutable openttd CFBundleGetInfoString $VERSION, Copyright 2004-$date The OpenTTD team CFBundleIconFile openttd.icns CFBundleIdentifier org.openttd.openttd CFBundleInfoDictionaryVersion 6.0 CFBundleName OpenTTD CFBundlePackageType APPL CFBundleShortVersionString $VERSION CFBundleVersion $VERSION NSHumanReadableCopyright Copyright 2004-$date The OpenTTD team NSPrincipalClass NSApplication " > "$1"/Contents/Info.plist openttd-1.5.3/os/morphos/0000755000000000000000000000000012627373447014022 5ustar rootrootopenttd-1.5.3/os/morphos/icons/0000755000000000000000000000000012627373447015135 5ustar rootrootopenttd-1.5.3/os/morphos/icons/drawer.info0000644000000000000000000001241612627373447017302 0ustar rootrootPNG  IHDR@@iqbKGD pHYsHHFk>zIDATx[ml\ՙ~|3'c糐uIiY%EQPDiZi?hJZaiӐ&!ZX`ـh3ر1Nq;{;̹{=5 4 HGsy}s!<ǁ,ˉbxm^߮jٳwqǩ;wWz?\iF0 #WBzP(R(hv8Y4YEQ5 cg7u,hBL$ {zz|>NeaaaͲ=,?XmN9ð,X,h4D"wuum ,!!4i-#eL&Op mlۆ$IKKKw81۶F0LR$0.0?ӧ$IS2l`6:kvoT(,˺r H #! eY8qh42#HBA, wvvft]h|&p]ZwVf4Mu]H$X,D"P(a<B(`0XfYC+N&&&ں*X^^bXof2M" " #H aC-(I$\xu}J,`&"Zm۶E1k&.B"b6.\BZ9DQ4 t:4 ##Immm{P04M3e&ò,"ѨWDQ?~ЭcYVJt:=ɲ,a4BH STr||<ݽ`Yj$Iwض=uF yRD"+N _j,o H²,aYm0 F|Cm( L>i CepP(hM?ҧ7M3QTw{[nEȲ uŕ/*r&H$4M0 P(,Y[pz@9˲`YVR\|1Ϳ2 CXe;::|> ( {{{H&ǻ-bMӄ iE xm_4}mk˲{BRT8fFqriMp`&&''{ۿ}uq\ڲ,DQD0D 80`f `VPmOdh&*20LB hmKXQUR7nHmPF\.8΁[9Kqy<σeYx+p|4 SEt miJ(*px%X("Jϝ;۸q4+:;118۷o&!48XE"XnHZ# h%zi}imc0 U*k h:y\^~ee"!Z2ov0w_2Ắh&2<)T5޲,]aۗ,iBQ躞,FaH.n&qs\FRYCeY'>qm.*VWWQՐfqj=iZ [Eq躾& x;DEQPAA(bLe# ڢ(:pbԅ BTJ[C@hct ˲, z@ej5elڴ === t"3;o4p?麮Z¶m(1m~Z" P(dtvv|jk p]WU5:Lӄi$ b@UU,..mO֖GYO4ah5iò,t]$Ih4y=,fAP(%I2" 6`ll,i"mls1t]w YZj UUh4`.^0< S04{8e;mAeh9=8m\.T*u]lB!AσpGG.EQ:$IJjP @T=Bݙ0<҈,j YaY֚M 7]3CI R`yye! y)@<#No ;j\xlرc'a Ȳrl<<{PUKKK^GӖJs|uuβ,\ Q̌6lpaM"l64::OBep?O 4͹ݛ|ax)@y{n=ZҶXWuPc \jLE9q^XaM,YWxwѨS,_|qnÆ #m۶oBT*gc0 8E}¯>4h48W0imj⁡Vy z-7;dV jՈD"֖-[ƞ|ɪG@P/K:t襇z襻{?m/-WeAZERA*Zcg[躾e˲z~55 >z5u]4$x|GV$I2ɤfSSS (x'Ç3#Gݻej&L&AMSPFeY$ y-(vSUӦn1`p3!$DNS,~&x8>>>~ĉCCCLDK.fffp{TUmނ)FzuN7WA5.*{va,/4MC aivqWɓ8qk2 ?z/˃IͲ,"TU2"^׽{{BPסi, ko)pm 4Mfh4}F!}ջ>|?8[*Dq]zz`׮]1QIs=HӨ(p~sC[N+;݆YT7;==+%O?m5k !DxWo+[8 8C>֭[=UГNJߴЂNgʊ:11q7<455i|]xG199>| 7O(k<7 GA$/ii_'xj2 izjUw:uo'&&KU' ij> MӜ'O6pѲ?uٳL&UeAY!I۽t3zV@SKkZczzsoK,_`~R?Jc=FFFFRVWW;zG?zeـ랬Kzzziښ/=PGd)˲1333v̙sj`2 yc="p]wg%?]*h=GFF^ҭ޺KeWUNV(pj^.\׫*Jz{{={Lms|,,,̌r/T*uX,tuuO?4D*R@"Jªm?ݻ,0PUBl㺮KKKrGrR eM6<_8kЕ,\pAy>SrBr րu-cccGs:˲N{ArA9Gx˖-N/n߾}{nгTUA*ʥ\K.۶,l޼`m?l?I&"b*Y\\,̜{nqqeY po|ѩ( 8\>B ~vj8q:tPahh߷o@  ,o޼O~YjϿؿ?=G e2kНwĎ;:"M3F??CBoP,qqFQtMWJ^lڴ&޶m>#:؏7W{W{=sZtl^(icOnoS-IENDB`openttd-1.5.3/os/morphos/icons/OpenTTD.info0000644000000000000000000001625512627373447017300 0ustar rootrootPNG  IHDR@@iqsBIT|d pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time12/19/04TIDATxݛwtUU?w_Iz'A(4E bw2GGt J"bAE !BH^l3kZww߻g9RJru<'JH)Sآu =}~M[w8ԳMC5]$ =תy۬-Ӓd[\w|bl M/ؼU.&WKһx!'_-F³mFyW\&^B':O'`֛3Wvh,2o!-[yzO%`Lͥ%_Z6&eD~ko !?Si|:Sn &㜶 )e ̸/7i ?K)~!~ݗw<ȊC^8AYyvMUbIؖ2z)%sKJYWB:%vi>З=2)/ V>W qh 66PE c5gK)_?VY%xݽ[gAs^k5B/m%9u J#iQp3\ IJ9)[!g3 p׶fճxM.f?ΗEבz}|_?,QDF,$01Gx]q-Dr/0wMqgw.׊Ip~5j=]P) Y SW6)K)%ϊ(4gx\9m-BtMA`KUUT EQN@" 2qh ' _FN`bY;.8?mY\7} BD^W2v(" "ضm -4%J)8*.۩d`o"J,P\47|wcsðx'f/p.-2{3l0w9X2yC8¹BQR/i2?Y`_o{6}eWeAbr*E˧[2iݩZQhР>na_HcϡRЪMah$bH n%>>1[sKRoΔ3"`^jݺ{j-UUWѧO/q4 !\J颤-d֟y8:tewx9mqpAbWc$| .|ڗkeL_yP ĻɓM۝t@rRn\EQ XIRR2{gS۫.^oy8N2N]͞#净ˤ/+ ^z'֬]7a° &9 lo2oݺPn]4MZ0*`cn7Hƍ9I@aYˬe~8Y>ݍBNWj5_=r4;/eWPUc%^Vm)fQtHbbBs⛯cy8E UUq5BJIbbZbх VaEbhbȨ!H=k\yoOԛ/R|4aXӋJ% e Q"6oXOׇ ./Mc޻qyQ)ۓWšLJ"O47+FjѲ\sg?oK mY9XBf5Jt{U(((؎uꛊ;rJKKPC')^}aYx$"EU@"He``$PCv&%X$h[HE;V~zI~&iU$"aWĥAMaz)pݕK[Q ߿,P8eY!maYn0H UYM<||W{z!ƿF0/n/g\kwO0 Y98VUCHt]CQضE|Ӌco>4k-)}P3}Z -%!Yg XU+TfޚDBp6%NK 7VvIoӗP  !*W2mYG`~}0 RQ:.2 İ,'gL('_8aUXZX&¬%\nҜ8C ! 7|7`?l[ *V+ >7"Ovq8qLx+Ykޢ.zx";B"l62TH$϶rH)S+zm#.[5w`і4^Jzm@"snMdk1bu=v۾Vz5#n ) R">/RZư+m< l>s 3*)ei=p= 'AWP$ڝW6"8QVΔ!nz:mAEBuR;M9ylX-YAznL$$B bVH) #U$6խtQh)eY fE~ܸ}IׇSSbNgˡ3ײ3vҋt ˲~wEd5kb͜I  /[ޮLFIPܰ ,S#`\5hע1:W2Ns$ ݩrqf6hoxj'S %]pĢ<@[c41ҲU &jpxphOHDe=BxmG7оs7HUEi;D÷?l${HnFe*/p?{JTՠn_УI\{;UP};58ؐ{h~ :ѶC[~s9I},sgfWT!POR] >xfLXIqvuԜjB pn^`!(N)>jWn vʽA  ,>]ҌGȨȘ9Y7~</CY oY%%%tygy枱l߹W\)P$ФkvD+@]y%)uMfƱkҌg SΈ]6V #ѫG@ phJRΗ[}(Ze PHB0mWÌ־`Y9è ѰY;ʜy?GR1 &'Ӝ 95jk/g^gA6eu_& +0cfaf">X2:\4xDznS!Y1*-Zבܝy#QM5)QhH.X [.h+ IgZ7 ui x7Ϛ1w9w2xz+>s DXAaIQ|9eU 0,.bv/F D"N#{$UއB$?3y7| F}$h# 'c$^oMy N=KӴK!:* . gok?df&b׼} $XA2^Bpf$B_| VvU1AlZ:C$r,g$̟|tK`t8P ] ^oM ˲B P@y|8goѶsH9IKͨJhCB {4vEF*:H$ߟЩߥ{ l"Sal-zҳa`//vҖ!cKNy<#G] R!N\_aBrD=A\PN%d&${A ́UM_߼iОSnDC|_Ka-{0CǥdN1yaFBHN RQ%,5z_p!tGUTt]iO Jvɢn:('3_s'u|{jpW{y5~ĕ#YOs'/Җ/߫u$:۸g"G; {mʏ1TZ J8zfxPVUs}$vMhty@ضmt]XE&4o֔)uIGUT]Aj z KKkX_`} }<ݓiwq"[fgI1 )q#!w1gwHɴDe+ 98ٗO[9vGޛOz1J RJ O|θDJ,[YBK4e~K>\<"&$e:6ؒ1 iwe G~,ǕɃlz( ^Rڥw#>iK-Yu>"AgƕSǂvpmiMe< $ibJO0>2#?>㋃/W=İ 4{mN8fѿgY ;$~Ri)&Nr>-aݞE Wsb2TS+>~I OdcIY~W{B^Q_ņt.<9Kp% E 4e>&p)q'C|R=杰 %M8w\ fiˆSٵಷpxC9k LNJ)k㵶˽1֔ε\U ;p|ocvamR}$`nhNb@ "9t G5ڷMI 'O$Ε%!cujOuN-0M3i3x mCu1L90 x(j-FvU8/<;XtN%=eYVu/g&Tn&L[ aR2 % !NTl0R.!Pyp%t–Y1=aTJ:]$~2r>;P㲷ڠh[(1i-v*33 ` @4MUq\nŁjܱec'alqx:x'Aۑ),v'Fy<@~zi_ί C-?)1?q72>;Ezs#~x0ənh_\\Ptoʺ6zV P! 'ޛyx &FƐ[⮧cK qഖ㷜p[B૭GS.ٚwn%)I ,i$CAuX9!= hC;ŝi iڌ{+M"PꃋOA~KWs/T橯}n!ܳ) w~ o&C45Y׽\49*Dȼ0Wͩ\e#̾MTPsRJ]*E4$PUGgB>?+b} %~!`(2)uU嚥ќq|xvdyC؄Pd쒣8T?Ŵh& W|d)tҹ]O6 4̊'AIv%cw!AכS6 KpM GOvkoO<Š۲iui]<,rYρUE,Wt{$ &\NiL!uPuͩ`[#^f/[a ٘!sppfPgtHНK'o7stnZ G |0kd$ $ B/XpD;H )eu ~~crF%Ccxi>A28guh:HI*Co]t#6\Xayj#, 6{] dJhGf L1a34ѡ9!=G١/G/ TV6Pa\SE:f`Qb@LڽS9=ZY959Ɋ[F6Ww)S)l=Gݖ.z?(@`$|?y۲gN@Xh~~da-UK`.kѭeMZ q2ݼ`id;p#;k׵PyM䃅zɾ7DLjbbBh q䍝 1 Hiڣ~gNSϐn\ (T?L[ ۀic#;!1!MD c@"8$ n]z-g)%R UhR!V|' Hx H:x)%z p/zIDATx[ml\ՙ~|3'c糐uIiY%EQPDiZi?hJZaiӐ&!ZX`ـh3ر1Nq;{;̹{=5 4 HGsy}s!<ǁ,ˉbxm^߮jٳwqǩ;wWz?\iF0 #WBzP(R(hv8Y4YEQ5 cg7u,hBL$ {zz|>NeaaaͲ=,?XmN9ð,X,h4D"wuum ,!!4i-#eL&Op mlۆ$IKKKw81۶F0LR$0.0?ӧ$IS2l`6:kvoT(,˺r H #! eY8qh42#HBA, wvvft]h|&p]ZwVf4Mu]H$X,D"P(a<B(`0XfYC+N&&&ں*X^^bXof2M" " #H aC-(I$\xu}J,`&"Zm۶E1k&.B"b6.\BZ9DQ4 t:4 ##Immm{P04M3e&ò,"ѨWDQ?~ЭcYVJt:=ɲ,a4BH STr||<ݽ`Yj$Iwض=uF yRD"+N _j,o H²,aYm0 F|Cm( L>i CepP(hM?ҧ7M3QTw{[nEȲ uŕ/*r&H$4M0 P(,Y[pz@9˲`YVR\|1Ϳ2 CXe;::|> ( {{{H&ǻ-bMӄ iE xm_4}mk˲{BRT8fFqriMp`&&''{ۿ}uq\ڲ,DQD0D 80`f `VPmOdh&*20LB hmKXQUR7nHmPF\.8΁[9Kqy<σeYx+p|4 SEt miJ(*px%X("Jϝ;۸q4+:;118۷o&!48XE"XnHZ# h%zi}imc0 U*k h:y\^~ee"!Z2ov0w_2Ắh&2<)T5޲,]aۗ,iBQ躞,FaH.n&qs\FRYCeY'>qm.*VWWQՐfqj=iZ [Eq躾& x;DEQPAA(bLe# ڢ(:pbԅ BTJ[C@hct ˲, z@ej5elڴ === t"3;o4p?麮Z¶m(1m~Z" P(dtvv|jk p]WU5:Lӄi$ b@UU,..mO֖GYO4ah5iò,t]$Ih4y=,fAP(%I2" 6`ll,i"mls1t]w YZj UUh4`.^0< S04{8e;mAeh9=8m\.T*u]lB!AσpGG.EQ:$IJjP @T=Bݙ0<҈,j YaY֚M 7]3CI R`yye! y)@<#No ;j\xlرc'a Ȳrl<<{PUKKK^GӖJs|uuβ,\ Q̌6lpaM"l64::OBep?O 4͹ݛ|ax)@y{n=ZҶXWuPc \jLE9q^XaM,YWxwѨS,_|qnÆ #m۶oBT*gc0 8E}¯>4h48W0imj⁡Vy z-7;dV jՈD"֖-[ƞ|ɪG@P/K:t襇z襻{?m/-WeAZERA*Zcg[躾e˲z~55 >z5u]4$x|GV$I2ɤfSSS (x'Ç3#Gݻej&L&AMSPFeY$ y-(vSUӦn1`p3!$DNS,~&x8>>>~ĉCCCLDK.fffp{TUmނ)FzuN7WA5.*{va,/4MC aivqWɓ8qk2 ?z/˃IͲ,"TU2"^׽{{BPסi, ko)pm 4Mfh4}F!}ջ>|?8[*Dq]zz`׮]1QIs=HӨ(p~sC[N+;݆YT7;==+%O?m5k !DxWo+[8 8C>֭[=UГNJߴЂNgʊ:11q7<455i|]xG199>| 7O(k<7 GA$/ii_'xj2 izjUw:uo'&&KU' ij> MӜ'O6pѲ?uٳL&UeAY!I۽t3zV@SKkZczzsoK,_`~R?Jc=FFFFRVWW;zG?zeـ랬Kzzziښ/=PGd)˲1333v̙sj`2 yc="p]wg%?]*h=GFF^ҭ޺KeWUNV(pj^.\׫*Jz{{={Lms|,,,̌r/T*uX,tuuO?4D*R@"Jªm?ݻ,0PUBl㺮KKKrGrR eM6<_8kЕ,\pAy>SrBr րu-cccGs:˲N{ArA9Gx˖-N/n߾}{nгTUA*ʥ\K.۶,l޼`m?l?I&"b*Y\\,̜{nqqeY po|ѩ( 8\>B ~vj8q:tPahh߷o@  ,o޼O~YjϿؿ?=G e2kНwĎ;:"M3F??CBoP,qqFQtMWJ^lڴ&޶m>#:؏7W{W{=sZtl^(icOn܀ր IENDB`openttd-1.5.3/os/morphos/icons/document.info0000644000000000000000000001054312627373447017633 0ustar rootrootPNG  IHDR@@iqbKGDC pHYs  d_IDATx͛oם?s#9CJ"EG-Ye[A|QX? hЧ-aeca_(6آ)6Au ˱|-Ñ˶I)R" 4sΙ}~~wu]GFF& H:u(Eƅ_4/"Z.\up@Ǹ|_ h$"A1@4E$"j^P(DQD4 @Da|??' ľ7mqHG)D͈D-G-גx/ heeo xxH !v@0 0, 41 w~ӧ$ @M.׭_ut]87 4,D"}+/onc_A еf뺋qt]1MS 4 N8qWկx7Sk8'xGVŋB/(nsD;cFzN&ҥKW~_+ J;\.f˼nDv( ayD}@9' a0D4lwzםNDJBuW‮;UtZNfxx˗/+d&>ġx9H !j52_~% _S4BpĉS?LrmA.Bk;C7nI CL$JNy8|o~ M "!JẮrNܹ;ݻwy|ZF>Ƕm߿OP ,">EjWAТ/HN 0 ,+;66 z`pp˗/sa+yFGG(Jd2^{5yj*'OV!P(P&4Mu/Y?"  ZlR(}!)Bp!LNN"```$ɡ|^]/B{Ʋ_ʒN2!E3 6rDwn_tg236⎓aaa$p{?@+Pړ(W!,(4M󻶞;(rځi'n݈:]GB h$"DԊvh. !7T?MuSþH%lc.ra$DS5uCr@|aC;FxGP "666h4(s7sqdBC=J&!ONN8a*((BvܡU= _XZZbyy!677Y\\̙3\\\A(,`\UaiiT*E" JQV}fgg) lnn"u=N100J'i4J; ]Ų,* Q*4),baa]9uZB&4""4;Tlc6,$SSS8C"@AXdxxT*ř3gHDQDRٳijQNf:t0z]8yQT-&uӁ`e8Õ+WfR,)jCn&2~/PI= uB?"WJLtkkKߞ) "~vgϞ1;;ٳguj8㰼L\f||۶}_̍FT*=zTՎPi48 Aճg~@^}"d2+پfϩ* 0u];;2ʺv"Mdm8Ç~eYض믿ǕEj\p7|q|2iz||\eL[o>@M͝dj- i)ad L&/4dT*E*j]j5ĶE@J(Wrܹ]8,,,` 5٬RhYyIFΑfN7n0==m۪B9%֙u]fffr-J0"fffڵkj5²,t]gkk/NrqDk׮X:VJ6iɓ'E, .^iA2ȝJt5qd%tr]$dR-ܹsضݒՉ{\nGN"|A !O>eqqqgkkKere΋/.˃RDE(n962jqct`PƱcXYYa}}!&''y&KKKJ%X__X,:sssu677q]#G?b:_~%?яx1sssT*\UB={T* y}^uu:44DZ?!z0z*jÇSV۶M:fpp!*m300В`f Jq…>;gY˸8qeN fib;-#*m- mjG;̗\^ M(Jܿ_%A}u:+3w… r9j) ڔX M }`llGQ(~:9m%ܾ}{ׯ+i=C5MQ.iBѭjSPR l&accO>iz]%>t]'6ͱҌVZ]*v[u۩@`J \q9Dyҍ~S|澔 컮KLo~@~`RGx.^[/It$gΜazzZKDK4mGnGٶӎ4eڟ o4ň@+/Zfԁ=AOhzd;e Ğ) vEӻ Q˗/D" +^4nsT 0r\{˗3M>`ܧ&h~fQ.W**joFA  mm=@ַ*嗣I{h`Wu]ŠWBUWY.#HgYicOn  multiviewL^IENDB`openttd-1.5.3/.ottdrev0000644000000000000000000000002412627373453013373 0ustar rootroot1.5.3 27462 0 1.5.3 openttd-1.5.3/bin/0000755000000000000000000000000012627373446012461 5ustar rootrootopenttd-1.5.3/bin/ai/0000755000000000000000000000000012627373446013052 5ustar rootrootopenttd-1.5.3/bin/ai/compat_0.7.nut0000644000000000000000000002714712627373446015464 0ustar rootroot/* $Id: compat_0.7.nut 26407 2014-03-17 20:05:38Z frosch $ */ /* * 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 . */ AILog.Info("0.7 API compatibility in effect:"); AILog.Info(" - AITown::GetLastMonthProduction's behaviour has slightly changed."); AILog.Info(" - AISubsidy::GetDestination returns STATION_INVALID for awarded subsidies."); AILog.Info(" - AISubsidy::GetSource returns STATION_INVALID for awarded subsidies."); AISign.GetMaxSignID <- function() { local list = AISignList(); local max_id = 0; foreach (id, d in list) { if (id > max_id) max_id = id; } return max_id; } AITile.GetHeight <- function(tile) { if (!AIMap.IsValidTile(tile)) return -1; return AITile.GetCornerHeight(tile, AITile.CORNER_N); } AIOrder.ChangeOrder <- function(vehicle_id, order_position, order_flags) { return AIOrder.SetOrderFlags(vehicle_id, order_position, order_flags); } AIWaypoint.WAYPOINT_INVALID <- 0xFFFF; AISubsidy.SourceIsTown <- function(subsidy_id) { if (!AISubsidy.IsValidSubsidy(subsidy_id) || AISubsidy.IsAwarded(subsidy_id)) return false; return AISubsidy.GetSourceType(subsidy_id) == AISubsidy.SPT_TOWN; } AISubsidy.GetSource <- function(subsidy_id) { if (!AISubsidy.IsValidSubsidy(subsidy_id)) return AIBaseStation.STATION_INVALID; if (AISubsidy.IsAwarded(subsidy_id)) { return AIBaseStation.STATION_INVALID; } return AISubsidy.GetSourceIndex(subsidy_id); } AISubsidy.DestinationIsTown <- function(subsidy_id) { if (!AISubsidy.IsValidSubsidy(subsidy_id) || AISubsidy.IsAwarded(subsidy_id)) return false; return AISubsidy.GetDestinationType(subsidy_id) == AISubsidy.SPT_TOWN; } AISubsidy.GetDestination <- function(subsidy_id) { if (!AISubsidy.IsValidSubsidy(subsidy_id)) return AIBaseStation.STATION_INVALID; if (AISubsidy.IsAwarded(subsidy_id)) { return AIBaseStation.STATION_INVALID; } return AISubsidy.GetDestinationIndex(subsidy_id); } AITown.GetMaxProduction <- function(town_id, cargo_id) { return AITown.GetLastMonthProduction(town_id, cargo_id); } AIRail.RemoveRailWaypoint <- function(tile) { return AIRail.RemoveRailWaypointTileRect(tile, tile, true); } AIRail.RemoveRailStationTileRect <- function(tile, tile2) { return AIRail.RemoveRailStationTileRectangle(tile, tile2, false); } AIVehicle.SkipToVehicleOrder <- function(vehicle_id, order_position) { return AIOrder.SkipToOrder(vehicle_id, order_position); } AIEngine.IsValidEngine <- function(engine_id) { return AIEngine.IsBuildable(engine_id); } AIEngine._GetName <- AIEngine.GetName; AIEngine.GetName <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return null; return AIEngine._GetName(engine_id); } AIEngine._GetCargoType <- AIEngine.GetCargoType; AIEngine.GetCargoType <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return 255; return AIEngine._GetCargoType(engine_id); } AIEngine._CanRefitCargo <- AIEngine.CanRefitCargo; AIEngine.CanRefitCargo <- function(engine_id, cargo_id) { if (!AIEngine.IsBuildable(engine_id)) return false; return AIEngine._CanRefitCargo(engine_id, cargo_id); } AIEngine._CanPullCargo <- AIEngine.CanPullCargo; AIEngine.CanPullCargo <- function(engine_id, cargo_id) { if (!AIEngine.IsBuildable(engine_id)) return false; return AIEngine._CanPullCargo(engine_id, cargo_id); } AIEngine._GetCapacity <- AIEngine.GetCapacity; AIEngine.GetCapacity <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetCapacity(engine_id); } AIEngine._GetReliability <- AIEngine.GetReliability; AIEngine.GetReliability <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetReliability(engine_id); } AIEngine._GetMaxSpeed <- AIEngine.GetMaxSpeed; AIEngine.GetMaxSpeed <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetMaxSpeed(engine_id); } AIEngine._GetPrice <- AIEngine.GetPrice; AIEngine.GetPrice <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetPrice(engine_id); } AIEngine._GetMaxAge <- AIEngine.GetMaxAge; AIEngine.GetMaxAge <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetMaxAge(engine_id); } AIEngine._GetRunningCost <- AIEngine.GetRunningCost; AIEngine.GetRunningCost <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetRunningCost(engine_id); } AIEngine._GetPower <- AIEngine.GetPower; AIEngine.GetPower <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetPower(engine_id); } AIEngine._GetWeight <- AIEngine.GetWeight; AIEngine.GetWeight <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetWeight(engine_id); } AIEngine._GetMaxTractiveEffort <- AIEngine.GetMaxTractiveEffort; AIEngine.GetMaxTractiveEffort <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetMaxTractiveEffort(engine_id); } AIEngine._GetDesignDate <- AIEngine.GetDesignDate; AIEngine.GetDesignDate <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetDesignDate(engine_id); } AIEngine._GetVehicleType <- AIEngine.GetVehicleType; AIEngine.GetVehicleType <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return AIVehicle.VT_INVALID; return AIEngine._GetVehicleType(engine_id); } AIEngine._IsWagon <- AIEngine.IsWagon; AIEngine.IsWagon <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return false; return AIEngine._IsWagon(engine_id); } AIEngine._CanRunOnRail <- AIEngine.CanRunOnRail; AIEngine.CanRunOnRail <- function(engine_id, track_rail_type) { if (!AIEngine.IsBuildable(engine_id)) return false; return AIEngine._CanRunOnRail(engine_id, track_rail_type); } AIEngine._HasPowerOnRail <- AIEngine.HasPowerOnRail; AIEngine.HasPowerOnRail <- function(engine_id, track_rail_type) { if (!AIEngine.IsBuildable(engine_id)) return false; return AIEngine._HasPowerOnRail(engine_id, track_rail_type); } AIEngine._GetRoadType <- AIEngine.GetRoadType; AIEngine.GetRoadType <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return AIRoad.ROADTYPE_INVALID; return AIEngine._GetRoadType(engine_id); } AIEngine._GetRailType <- AIEngine.GetRailType; AIEngine.GetRailType <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return AIRail.RAILTYPE_INVALID; return AIEngine._GetRailType(engine_id); } AIEngine._IsArticulated <- AIEngine.IsArticulated; AIEngine.IsArticulated <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return false; return AIEngine._IsArticulated(engine_id); } AIEngine._GetPlaneType <- AIEngine.GetPlaneType; AIEngine.GetPlaneType <- function(engine_id) { if (!AIEngine.IsBuildable(engine_id)) return -1; return AIEngine._GetPlaneType(engine_id); } _AIWaypointList <- AIWaypointList; class AIWaypointList extends _AIWaypointList { constructor() { ::_AIWaypointList.constructor(AIWaypoint.WAYPOINT_RAIL); } } AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation; AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id) { if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id); } AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation; AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id) { if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id); } AIBridgeList.HasNext <- AIBridgeList_Length.HasNext <- AICargoList.HasNext <- AICargoList_IndustryAccepting.HasNext <- AICargoList_IndustryProducing.HasNext <- AIDepotList.HasNext <- AIEngineList.HasNext <- AIGroupList.HasNext <- AIIndustryList.HasNext <- AIIndustryList_CargoAccepting.HasNext <- AIIndustryList_CargoProducing.HasNext <- AIIndustryTypeList.HasNext <- AIList.HasNext <- AIRailTypeList.HasNext <- AISignList.HasNext <- AIStationList.HasNext <- AIStationList_Vehicle.HasNext <- AISubsidyList.HasNext <- AITileList.HasNext <- AITileList_IndustryAccepting.HasNext <- AITileList_IndustryProducing.HasNext <- AITileList_StationType.HasNext <- AITownList.HasNext <- AIVehicleList.HasNext <- AIVehicleList_DefaultGroup.HasNext <- AIVehicleList_Group.HasNext <- AIVehicleList_SharedOrders.HasNext <- AIVehicleList_Station.HasNext <- AIWaypointList.HasNext <- AIWaypointList_Vehicle.HasNext <- function() { return !this.IsEnd(); } AIIndustry._IsCargoAccepted <- AIIndustry.IsCargoAccepted; AIIndustry.IsCargoAccepted <- function(industry_id, cargo_id) { return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED; } AIAbstractList <- AIList; AIList.ChangeItem <- AIList.SetValue; AIRail.ERR_NONUNIFORM_STATIONS_DISABLED <- 0xFFFF; AICompany.GetCompanyValue <- function(company) { return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER); } AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied; AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID; AIEvent.AI_ET_TEST <- AIEvent.ET_TEST; AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER; AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED; AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED; AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED; AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW; AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW; AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE; AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER; AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT; AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED; AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST; AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT; AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE; AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN; AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE; AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE; AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE; AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED; AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED; AIOrder.AIOF_NONE <- AIOrder.OF_NONE AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID openttd-1.5.3/bin/ai/compat_1.1.nut0000644000000000000000000000623412627373446015451 0ustar rootroot/* $Id: compat_1.1.nut 26407 2014-03-17 20:05:38Z frosch $ */ /* * 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 . */ AILog.Info("1.1 API compatibility in effect."); AICompany.GetCompanyValue <- function(company) { return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER); } AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied; AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID; AIEvent.AI_ET_TEST <- AIEvent.ET_TEST; AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER; AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED; AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED; AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED; AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW; AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW; AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE; AIEvent.AI_ET_COMPANY_ASK_MERGER <- AIEvent.ET_COMPANY_ASK_MERGER; AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER; AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT; AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED; AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST; AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT; AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE; AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN; AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE; AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE; AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE; AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED; AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED; AIEvent.AI_ET_TOWN_FOUNDED <- AIEvent.ET_TOWN_FOUNDED; AIOrder.AIOF_NONE <- AIOrder.OF_NONE AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID openttd-1.5.3/bin/ai/compat_1.5.nut0000644000000000000000000000120412627373446015445 0ustar rootroot/* $Id: compat_1.5.nut 26410 2014-03-17 20:28:48Z frosch $ */ /* * 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 . */ openttd-1.5.3/bin/ai/compat_1.4.nut0000644000000000000000000000126512627373446015453 0ustar rootroot/* $Id: compat_1.4.nut 26410 2014-03-17 20:28:48Z frosch $ */ /* * 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 . */ AILog.Info("1.4 API compatibility in effect."); openttd-1.5.3/bin/ai/compat_1.2.nut0000644000000000000000000000126512627373446015451 0ustar rootroot/* $Id: compat_1.2.nut 26407 2014-03-17 20:05:38Z frosch $ */ /* * 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 . */ AILog.Info("1.2 API compatibility in effect."); openttd-1.5.3/bin/ai/compat_1.0.nut0000644000000000000000000001201412627373446015441 0ustar rootroot/* $Id: compat_1.0.nut 26407 2014-03-17 20:05:38Z frosch $ */ /* * 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 . */ AILog.Info("1.0 API compatibility in effect."); AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation; AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id) { if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id); } AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation; AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id) { if (AIRoad.IsRoadStationTile(tile) && AICompany.IsMine(AITile.GetOwner(tile))) return false; return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id); } AIBridgeList.HasNext <- AIBridgeList_Length.HasNext <- AICargoList.HasNext <- AICargoList_IndustryAccepting.HasNext <- AICargoList_IndustryProducing.HasNext <- AIDepotList.HasNext <- AIEngineList.HasNext <- AIGroupList.HasNext <- AIIndustryList.HasNext <- AIIndustryList_CargoAccepting.HasNext <- AIIndustryList_CargoProducing.HasNext <- AIIndustryTypeList.HasNext <- AIList.HasNext <- AIRailTypeList.HasNext <- AISignList.HasNext <- AIStationList.HasNext <- AIStationList_Vehicle.HasNext <- AISubsidyList.HasNext <- AITileList.HasNext <- AITileList_IndustryAccepting.HasNext <- AITileList_IndustryProducing.HasNext <- AITileList_StationType.HasNext <- AITownList.HasNext <- AIVehicleList.HasNext <- AIVehicleList_DefaultGroup.HasNext <- AIVehicleList_Depot.HasNext <- AIVehicleList_Group.HasNext <- AIVehicleList_SharedOrders.HasNext <- AIVehicleList_Station.HasNext <- AIWaypointList.HasNext <- AIWaypointList_Vehicle.HasNext <- function() { return !this.IsEnd(); } AIIndustry._IsCargoAccepted <- AIIndustry.IsCargoAccepted; AIIndustry.IsCargoAccepted <- function(industry_id, cargo_id) { return AIIndustry._IsCargoAccepted(industry_id, cargo_id) != AIIndustry.CAS_NOT_ACCEPTED; } AIAbstractList <- AIList; AIList.ChangeItem <- AIList.SetValue; AIRail.ERR_NONUNIFORM_STATIONS_DISABLED <- 0xFFFF; AICompany.GetCompanyValue <- function(company) { return AICompany.GetQuarterlyCompanyValue(company, AICompany.CURRENT_QUARTER); } AITown.GetLastMonthTransported <- AITown.GetLastMonthSupplied; AIEvent.AI_ET_INVALID <- AIEvent.ET_INVALID; AIEvent.AI_ET_TEST <- AIEvent.ET_TEST; AIEvent.AI_ET_SUBSIDY_OFFER <- AIEvent.ET_SUBSIDY_OFFER; AIEvent.AI_ET_SUBSIDY_OFFER_EXPIRED <- AIEvent.ET_SUBSIDY_OFFER_EXPIRED; AIEvent.AI_ET_SUBSIDY_AWARDED <- AIEvent.ET_SUBSIDY_AWARDED; AIEvent.AI_ET_SUBSIDY_EXPIRED <- AIEvent.ET_SUBSIDY_EXPIRED; AIEvent.AI_ET_ENGINE_PREVIEW <- AIEvent.ET_ENGINE_PREVIEW; AIEvent.AI_ET_COMPANY_NEW <- AIEvent.ET_COMPANY_NEW; AIEvent.AI_ET_COMPANY_IN_TROUBLE <- AIEvent.ET_COMPANY_IN_TROUBLE; AIEvent.AI_ET_COMPANY_ASK_MERGER <- AIEvent.ET_COMPANY_ASK_MERGER; AIEvent.AI_ET_COMPANY_MERGER <- AIEvent.ET_COMPANY_MERGER; AIEvent.AI_ET_COMPANY_BANKRUPT <- AIEvent.ET_COMPANY_BANKRUPT; AIEvent.AI_ET_VEHICLE_CRASHED <- AIEvent.ET_VEHICLE_CRASHED; AIEvent.AI_ET_VEHICLE_LOST <- AIEvent.ET_VEHICLE_LOST; AIEvent.AI_ET_VEHICLE_WAITING_IN_DEPOT <- AIEvent.ET_VEHICLE_WAITING_IN_DEPOT; AIEvent.AI_ET_VEHICLE_UNPROFITABLE <- AIEvent.ET_VEHICLE_UNPROFITABLE; AIEvent.AI_ET_INDUSTRY_OPEN <- AIEvent.ET_INDUSTRY_OPEN; AIEvent.AI_ET_INDUSTRY_CLOSE <- AIEvent.ET_INDUSTRY_CLOSE; AIEvent.AI_ET_ENGINE_AVAILABLE <- AIEvent.ET_ENGINE_AVAILABLE; AIEvent.AI_ET_STATION_FIRST_VEHICLE <- AIEvent.ET_STATION_FIRST_VEHICLE; AIEvent.AI_ET_DISASTER_ZEPPELINER_CRASHED <- AIEvent.ET_DISASTER_ZEPPELINER_CRASHED; AIEvent.AI_ET_DISASTER_ZEPPELINER_CLEARED <- AIEvent.ET_DISASTER_ZEPPELINER_CLEARED; AIOrder.AIOF_NONE <- AIOrder.OF_NONE AIOrder.AIOF_NON_STOP_INTERMEDIATE <- AIOrder.OF_NON_STOP_INTERMEDIATE AIOrder.AIOF_NON_STOP_DESTINATION <- AIOrder.OF_NON_STOP_DESTINATION AIOrder.AIOF_UNLOAD <- AIOrder.OF_UNLOAD AIOrder.AIOF_TRANSFER <- AIOrder.OF_TRANSFER AIOrder.AIOF_NO_UNLOAD <- AIOrder.OF_NO_UNLOAD AIOrder.AIOF_FULL_LOAD <- AIOrder.OF_FULL_LOAD AIOrder.AIOF_FULL_LOAD_ANY <- AIOrder.OF_FULL_LOAD_ANY AIOrder.AIOF_NO_LOAD <- AIOrder.OF_NO_LOAD AIOrder.AIOF_SERVICE_IF_NEEDED <- AIOrder.OF_SERVICE_IF_NEEDED AIOrder.AIOF_STOP_IN_DEPOT <- AIOrder.OF_STOP_IN_DEPOT AIOrder.AIOF_GOTO_NEAREST_DEPOT <- AIOrder.OF_GOTO_NEAREST_DEPOT AIOrder.AIOF_NON_STOP_FLAGS <- AIOrder.OF_NON_STOP_FLAGS AIOrder.AIOF_UNLOAD_FLAGS <- AIOrder.OF_UNLOAD_FLAGS AIOrder.AIOF_LOAD_FLAGS <- AIOrder.OF_LOAD_FLAGS AIOrder.AIOF_DEPOT_FLAGS <- AIOrder.OF_DEPOT_FLAGS AIOrder.AIOF_INVALID <- AIOrder.OF_INVALID openttd-1.5.3/bin/ai/regression/0000755000000000000000000000000012627373446015232 5ustar rootrootopenttd-1.5.3/bin/ai/regression/regression.cfg0000644000000000000000000000042612627373446020075 0ustar rootroot[misc] display_opt = SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|WAYPOINTS language = english.lng [gui] autosave = off [game_creation] town_name = english [ai_players] none = regression = [vehicle] road_side = right plane_speed = 2 [construction] max_bridge_length = 100 openttd-1.5.3/bin/ai/regression/regression_info.nut0000644000000000000000000000117212627373446021156 0ustar rootroot/* $Id: regression_info.nut 26895 2014-09-21 16:41:03Z fonsinchen $ */ class Regression extends AIInfo { function GetAuthor() { return "OpenTTD NoAI Developers Team"; } function GetName() { return "Regression"; } function GetShortName() { return "REGR"; } function GetDescription() { return "This runs regression-tests on some commands. On the same map the result should always be the same."; } function GetVersion() { return 1; } function GetAPIVersion() { return "1.5"; } function GetDate() { return "2007-03-18"; } function CreateInstance() { return "Regression"; } } RegisterAI(Regression()); openttd-1.5.3/bin/ai/regression/empty.sav0000644000000000000000000027670312627373446017122 0ustar rootrootOTTZhx[Kv&:ul7*Ӟ<K0BHHTZBAbx4>!^E{,O~Ϭʺd]-^x =7"/UZ}/b+VĿ,ˆ~}qޯ?_;_ϳ^^_˿]zW_O2w >Mq fæ?læ?l?AksWzk xkMVm9^[upVKυ*{ЄbZE:|wVUc4m[_s-E%\SCΒbA |;D-w]1 ݤ5+ m5\]}3~IA7z=ڞogY}b{ ne9,/LD5CY"+o(C`@AO&n1ڜn~$:\$R{k*~kX@Oԝ埛w!PNL;]zCh{6u]3 ~.D?'?G*'U5Y * ƖƵA51}_f;woݺ{ *c/?֪==2=0H `oKf0@+Y>l.QO`0;$;ߺuK(YB; R_eng(Dk2䚋ׇAЉԯH埓p(؟pA_*Pwe]gQ@ݾwW2@lYQ<}DaԱ W .86/H%Ü Q՟E]¦ zp#&qI=hI巉Q<~ 2r _ļPw{f`#/|Zb DAt!]RjB-zdДEv~WoC_;0E }(g0g* ~ T돍8dP5l>~Z ?ݝ5ඊ1+">2 עP"W2@=tAyFC ~p^^~.jn=ƞ mo'#aPč5% vbtk&?n^ܺE: v4~7A 8e /22}(&!~X['3F\TMk_wøm- zI/")KXUzo__Q$gx?P/S hPbK8Ęb v>;<'/PyAP +H0$k𝎺;ܾ@0nORaC1BL}+z0!YyPJD;h^-r8F߇(UT+*zDGK~ ~=PV@]8Po @a%(X*>Џ0d>!U?Cghpwo*yQ^U ~ۊ?tQfGp2"!N`HM/ rWT|h^ =Lܡh3 *`RǦ;k?g8ՋZ*=߉ rw>:`SGCa$[1)'1KcݍCRy=$n 9%u3 Xr_=G+BkV~-|Ȍ(= %(p4NyX/+dJ3T r*, PTw(zQn`S x)/tmV7 @!l?Sޯh@C{aʸyf@.CP5nJu;,K֒vKIE|\BPlŋG+4VFcN7zh0`(`}@2/! Mz}̶t-[ &/V,p> &UL:Uږt&{ ?e8 5_] ̍4>=x"q x1|EKaa^!lt/_T}h X1'9wG2Pg{?'ߒ|/_ 1 ) FG*EkX_R.8.}'ێ` ,UEduK7g\ghq )vįZ1(| 7 G"~Jt}`D|MT}WɊƫ6b?O/QZgĀfN f ?=><]JqѦ鯪{JhbgG,0@wsvA6y>g89٧AqIUO~~3 P^:oZDTAeaza6C th"oq3"?nsCm5_ `{.j*xt`H#M\"bPAm9"Sca2CTl_C/0bB61YiHa&@)IAy(ӟ ~6R~KKXnuNUXQEߦB'$&k|-FQF?N4~Cv]o;̀k s 8_5Dt/U 0Ȥ@jZ\Z^~ X|W' _>?-//,.(g(]o`D =} :s6w]^C8d0ձ>J3( 9`s047-u÷ؿQ s6;CN113\9 "A?׾7.f۹$GfKz)OZgP  /ss_ȯuPe,|0bt>.~L83~k, r" %O"=O' @_eϮO"I8SE}- ߒQn` i*oX!#-,/CpC2~%+FʲTT~q`AHqQOi$?Ҵ|00}143~kzG_)h?/&:pUSED߫>_w ԉa͋1@n7~%At#YS U7"lp0FN?b+$E|1d`7K%lAKS ~Q5 0]~@WW~+8kڇlBQ2*OF0̒W*#7W&dVE('0` ]8JDn ^o7‚c3\U%6 7n0y:gh ;`w_麸ɷi}*@b/4`2a_]3 (?llǏ7  <|%#Nt xerN z`r5? AOg3;RKy7AQe 瀖Y48cufh$B,?WS_Ѽl/Ȫ  VJYܩB7<ᴃ  ? 8oʿxT("‚+GK? ߓ׌f^dP=V^%r,bQF4kMdI>[k_!FW̜a.-/z'R@R—H؏{ķ_G `S\f?bԄ3x "ܕǫ$j$ X50%&>5CGds~)ZM$rTѯפ!TE 6pqq_] `aEF6!Vov$mj~ LğXU}Skggш?dU[@U~كJtg @?Wpn;=v}qe0x}Ot@%N`_f N(D>=?؟a0[HIkku(|kJdxﮒ_e&``* yT3ʦYF~ AQO6зRʻ~.Sĉ/ $jAC_Umn'XP⟕.@[hi:@XD7?jyNkJu,T{Sӗͷa ?ƿrĖy2hà!ZZ7!hD?v2@d/1+}>-_Yщ`0xhPq-Z:%P?ש{'n +VWV,+ 0%(Jp 3E x, {#W /Lߖݥ9 +FOdl^_gNȌ2̆K_Ts 1H,?@yϦ2@o`a4L:Oá ^eγ|58%m+kHߘ>J 0+y1utj"/5#T731V5 p}pitMuT10 ( SRjcs$}?c9)|BӖp 3O2<¿{˼: Oc?#HBA+dLNU3/D %]XrbP Ji:.`=0h̄?yŮ!PkT!ſXsᔹR,( LX_t;Zmgo~xf1&G5KpH* _q p {y $ )[EH5@"H)TH h!GA[Sy -YB^Iz<#oҼ>{O X& >ߌ ~庐ڠ?/9;,S8$ͥ7JC#ܰ ϜMqԁVxxF3FĒ!uG\@y҇?tZLJMjL=1RP3Hk`9%P~W9-?&3\r] 4Y nR_xĊSk(&L2m!:<]o]KO}*oho{<nqLHB9?,he?4]BKF:؀1yvGABIsڲ&2?rą^l_^^FC_Rj6n^#d.ހmc?گF,_B ;dd`4U=Tp~)xGnUj%>Z$ES18tHMg5˅8_^tM鰝=cVC/$]v_AW~鼚XCq^(C&1~_ ʂcyN! "0 b^_b8dP/v(p9'Vp#D~^JD20wyHVrG%/k)c5@;MjȑF 8]T=mN/A&K&߇0]$8BL2< E}2OdP+&۫(ir!~,`Ϛ?@{mByROewMHy4Sz(+f2;=`Gu@˿ʜm .IH8Ѵg_SgtXC}Xi_<_ƚ&ξO9`/J p +{dſ#KбxG9Cy`݇ 0*6=o-$V|p{? XY(Ft,>s  8?P(Y@ , *=C:l>dh`߀6=|SG'%.i0E#q|>ho8 8_V?z'7s6jhlALXft_qp$sCϤ~n|@E>ˋK~`L6>o冡>bY^f3\:[OQ! zL[u畁4!Y&cAtA|3۴/4K>pHNc:qߤǣϲ;S0K 2}6V}AqR$Ýa)z[#8UyWD^Aߢއa ?KV_# x!&m:W~,ɷ jiOO0RC 7- ~?@Ђ#Ǔd~ 9 }BF²24%@fԭ#~aȒË̚eP1QݳJ!o!c$ |$ygi64}Pt/X~8dd㥏ȟ3oEF߾*@)F4,+ր:qOҦ&^9^CQWBv9P\TX&@@̟X>!Ѐ.Uf^ݾDfSQ Cd-0J\4/y(%lެ~m9b3)y8" _?bom}Qsj8`|H] tXІ(lUrF^/{8{BRm|ʤcoetg}G P/^Ɓ iWXu5'A~.┠ukm(GT=!q\W:[\^@`O$c+av. !>yΕU9(7NC !qH&| ,8Q߀Z& gGs٣J!hҹOXm{=@՞{ܜCTC a8%__7۽h3]uMq7(zKKŲX9o%Fl9?.Nnޤ6X%a^X4/O@׈j +gx%~7.,#\>C[?Opu1n4!SESՋG{ۗ+f`7We޴HqOE$%u`smR6zÁuYme /OIDovKx}=0E{|ط8dkh}-p<&4ef6?/!oyMrB2ϳ{w,6,΋[XFa TpU2 r\oECVA1Hr<šk4WiEdGa +4 WȸK1?G߉xmy~?hG#G6[]%]LQe3}OCJUTm?SjyP׊|~oK}cTH>_ ̂FV'm)1boyb@MJOC SxW$b_6p GYr&G":j)1A94|GV=?Gz/4G7$.l+~,5jJ*T6|^aϏUDpԎx߇8Rő2TH!x=ML/A g0yK4~눦fY=^w#B;'xM .W|I=~)G$ 9~EZC?'\ IvS}5vOlXΏ2[jWx^?4Hic4)7-s/#h_~ Z/.d c%Š5 "pD9(a%!׷JV El:^~C?`GBK8d$%<~dm0;x'|? \C+~UU-50{~mXcke u馺4̀yɛL.`]z/?R߸B(R샿!e(ȂàS9\(9m ,M H\͙8!;|bBE¡(7?HCiVIKo<\Vt?d{G~I4 `eþ+FY!W0(ͯ9 xَzT'! |,+/{Q4NL{ӥnH^AG L */nxO?w~P 5|(#癱Q2@c W dH&61@N~eA#qowo ZeF%\Di/.~R0dNP@ "lj_T"\iį:PAm`8ڏYGS";I(m %E$*E"nsH41'bݿc2B3::իlhU%>U,Q\4;nq@P,Kboso[>V$I >U? NM0jK`#}z4(}<`Kub '6/s-Ao-s1i~p'x_Pk5 HL~P2| }>otDy>I O/|OPW"G}z*R@$ōwA4sCNXl=JJP!t@QO Ȱ,`if􃦼Pu԰M!u4wEg +ΗqM}hs~<}27iepm(kOw=Gm+ ר0 ]`/)~@ęi W]bNS0lOȫ#7 cH:+տep\n΂BTt.-Gbԓ!pJ\ЫȹFdW}XH~ǀ\޵+?8Op$q/e*oW,B mѫ,;~@$gv#./͓zI^ɥ#*m)H7\!+i͒]ځ0ar?]{ɧH kQ>_?Ԩ&7_Ǔ'l_[񮊟7HvĿ,j`/B=d`JOc/OJ?(?9p'XYS(a5uxEe~' iGc rt~ J Dz*B Ԣ%TeQγ! G[^Pʌ[B฾ =v Cj=B[WWJceY%/0CHś{<,0&0&pB*V?Ν={b eA?7 !T h -WgK3Qh"u6i4R`Ew)*m%{?PeQzWF5 Sߚ,Z]'5hς'>='#EXl_A;C $> &?Q=ezk=^d+4܀W՟8 $ЮONW'z܇{ew)[i#/RLw2؅ޯ`;eO77\('Z߷1@wrGp YpmO߄7$ }G)56`D:'#xmO֫ nst@w`<_$]k/F<+2ňoy?7ïSPzʀcsZaV4~5hW~UF4~5"^LR~YB}kXoָx9i¾!*o>DzC:?+=Ԉ"=)>[#?I3cErWD~}݀p[MLzbRC)oitJT!ݵ"c_ʉ"~(zm/'u3ͭ;Ccv5) xVd8>)^=i{^dZLrC?=~-rɟ IyR ni*( erTNmd&' 7|31H/|\Ǭ֏~>?A(:GІWC~*vĖoUx10͚[h|̄E)aFݢ?)"Q .w]ڌ!g1wYO"D m"ûº*,a/bY>qRƒٟ`>aRűǧZZp(G I53K-vrRlv06 \x?Dg-a_'> :?KpZ'>Oz26D׵%k=Sď5sgkOK{{N1lMMtO"]tw±tLw֬J7T"O^lM?*@Ќ#>#>7>tO?læ?læ?læ/n >Ry&"Wɢ ț34ÞxS)|v3:=qCOJ ߌ91nDfxD[N*DS'$RGWɖ n)j0 gǟ:lE.OHs?P9͖"FVt=R?Xe _{.G/--ZS5_T\PDk۴8ҒԴr7uFz +YSGo.Nh .MvJ큱c&hߜ&{i: nh6Yj+40_N^Df?)MRH#~sRQNe5od':hFYgNs"Q'ٍNEUfLM\?R쿮d~sGMcZ6w[WNNj)צhR[goh$ dG&Pծwhg_M]/x(<?c3;*_g7jƃ?!#qk_j5n07̂_pZ9G4O3o\,l)Яt>P{pQ;1 ]O:Ww&ߖO?oRʺtinBn8NÃ9.4#MG̦K\KOGLq;-K7hSG7ɯ΀;? z yw惿Q2ǀriǤT}9W!DMV7٦SU3~lөq~%ي/<5~NYz)N9I3Mi=*,j(S6g3oםz3 'Vϻ)YΈ?]B4IFil>>6RSPV6ggܛHH7a ؑ^EhV7/%{&MdلIY;{kj0bWZo9D^\z')uF64f埩/ NLc#B_dk2[a 33J GUO.O9RSG_1/u<50~)2?4MGKװ` sF6?uF+6U;ݿ 9;K;o3#ͥIuu\v_&=3`*{_7EjEOpqU͝;ud~n!+r?=<[v2Htфy?7TI_J<'?4ƋiW$nS(w2 De4AOdG&BH৩%vOD#M-ĉÃd6!M-ӑ4oߒu|GdLӵڮ?ɨd[L[^'* SE+bK&?\+:oƥ\;.ī)_*Nqei}zfh\eJ b3)ۤl {&?&[=7hRbO+!ؿ.~Z:zeBxTjNkʄԕj%|`3n@Q3n<Rn4Ӈﺱtpܼ_I) ?e.B,LLA"Ì4*~p?8W&SutgB e*e!_~s/#_`5L+>fR- tw醿:Xjn5iWԒ^3u3x t#3n~πnI~s2=0u+Y}yԌ?<2y^h^} o<^ ogJB4w4Z"*Z73@?MfhFY&.&^h|+bWLԆE ۷ϻO)t^)/Y@3?mt J6qN:%^,}Egd_9| 2u)KO^2>!S\}!ǪP[ϣ8J`x⧝f-&-4$*/iO?S/Ț{ݭv_#K?qTekА_[B{܆mg;] Jy拴҆ogw % vO'C^Ry.uU^V{Lju~介5 >Q[;i;vyt`oZKS.Ƽ$fS4An]Ow MT_JD]O΀3ϖ,Lq]g邧 ,<%2uʠfMTe;ÀovM uNk:gf'#5GoMϝVΑb܊zIOk| hbP+d1}QG3cjϛ TJw|_ygҫ.-G?;`]OzͶ+{q 7NO/ jη?V|gKߟgQ?~pI67usSW,E=Y͓4i9/!~^L\,gl? Kûnh3.{D7fZ/%N?ze%f}j8EO_Z2\Izh{glnДb+Y?to6lOEA<./ M+*ůk\iдe=I6_sV8\{+GYLE??MҦu 761ݦ.jܳF_{vo כ-4*ffM2)75~Ȁ,^ 77OhMr%=Z\Mڛ44DV_6ӿ]ZA2p^r_x)W[ZֆǴ+Zn ᐦviRnuq7loR7Gg-mkkPxH㟧Xl9b&Ak}Bgsk:'*~v?Mq?ub7_vl(ѻTڅo VMR Җ.8Ad:!lk7ntŸj AUkni<ڔ$.!e+]gdjnѿŸ:i f/1 8لDGmK*DUi?6>qS}E:WZ{ .Ua*qKn}?57Nfn:C6W|NOQ?Vr@3yG6}aG6}aSӯv/˯#}>GH#}>GH#}>GHf;݄te? >Iq:6J^~m uv*i z|zm^S;h}~f{ \?wZ?k51彯~8s:l\?D;ذ?m?Bpu}sz~V9e0&ocKiBC][:mH|;n7WOM:t-xx> z^[lN4~˽0:v/vpש{w}[F}lz\#}xA=>YT\ȫ.|{4Vs/%_y?q{J?׆l/\[>qWɞ?8G/Ϛ23tac, (Yw7:3tI{:b$''9wi幓눛ia\*);sg|㈠g9kd^kߪ}%w84 3}GڲgvS ӎ<ѣ]Cup ǜVߚ2#ۖb :uBDc̉?y3I]Өȴx[)WO=XgR88&i7_8*y9-YmQ)"rȓ? !yI50RL2_Zs3;M55J͊leg*1u |쾁Cn\lτ[ Nb՘z>z~s_ou\Hţmh i X ǹ̌{GvƑYlLhGxr'n&YM}lDboO9#g/}(~4䧎bgڷ1t ~YRB f@N?lf,Fb_u7I2jӶPwvG.8n}xy΁Cme~`[vCn}lGZ)wHGGU~ڽ?3z!ؽ L d5M0wE}wŸ:]9-J6zN?*DEq\'LjǍee HbjƓhIӴ_TO>0al!j"3wa^t[h a{Id-Q[Z\W?c~_ϒ6}ݜ%D<%|]9ϓ}+x͇clK6OO\/y3yQS[(_RKe_?SG + Pk-H@1r(}!oɱ6 lY+ py^:r5Wq&LQWO} !m4Seğqky`yeޏKUDGS?끼Ù(S`g#sYMrrAt\sbHdsem3krY"+'y~`=,puIn"}vZ7D!XF_VgCoQ,ˌbQ<^ei)}:郤(Hhazm"UgcFÝHJFI xy +߻VP :;ޝ~HBڪ-z|!/h'83-sWym{-`ӽ=P[Ct1_]=۞x)>c|gvbhxCwz5NmU6Z iS{ "nbMUz ԀdpM/n⫭ڼS3: L\ki#:u{:Ase-fSmH,tȷ$˸rY*f=HѿQX1| mUMրMj= U(db4v+oW7ƜZj hHk\1/DQIHǑ_ir4>" 4ǻ[ٟВ򷴇\J5'3f {pF2-s%C05Uʢ djrle Л^zǿS2qӽ郏pa.4ޢ|tCܡ,3OLks3]_fdk;ZKJc~>מ ;dH)¶RT߿ĨЇ-:uw 'sh^)J;-`Ĉ==4?dtV]u\# 90f'6ԏ玴&g^Z^chIt "[~GX"h=ζЋyvEG'?LG[=1G(?oh~VLK`u&χd2ouXDZ_۳Vtn˚4dbsk:4?S'8 ڀM̦,CǼcАZMmShZ'ydlq[%>Ak &O*qF+ ma("O*!l?ӟt Vjc'>GohNʸV2qK68)b&7LƷXψ|υAtzյ7+jf4l rX'L&b{g4`NfOm!j֟pukvXٯqua1krV,+qcϻPڒk7%=, HqXݳ"~aex ǧ:ųo ڪxWc=o ߫WAVT:'IV?B{jypc-!р_ĻeW\z\`=rzs\q{"[B߽lF䈯tT Ȕ惠l;q47ы<.L\=Yq{ ~J}3W~^{nBu_h_; QXK.+=/: z?|ܲׄ)|W/m=ӋeM?So0ӡ|KeO&MAf6y쉎Gqd+?88z!,KmkO^4y}~<8+$hkbut%9Zujr}$| WA/yՒh]a8v9R{3.B< /934>֣10#P91F[zXoY@{nr4ΰ)Az'yP Yg O)'n>8Kzu@Z=bM~~)(k( C+o8AT!5RF3uqCG&;y*ieXʹ,W/|Mue`Ń_uWP #yP U&$zh=a2 }tuz_LiX;$2KZ>c6MG:UY[Kv}3lqn vӈ|GYʽ<{ќriBw~[r8y,I}9䌿<>/Qsc.pJtb1oG@v fWxyqt q SlG23/V5ĕb[=9xI&ſ`tsי |tl~ޯ_CS? ^ru3wso3o$+vs^gb1>9j3SC}KlҒ>GyY;dܲGڗh_|oh[gR%#6%6ym,˪DbC3ܛS1[,y d+g^פ>\dgX05/MC>b;Kr╒!/H!ky)0 =*4Ny|3t/p5qE?8Ƶ>skVzFs-, F_]/;SY D1qfe릁RRV._sh ZW}EOhz*,I :[yL+q4#Q}Vd.qV5?%&Ž(= m3 eWt,0J,mZ_ysW5ְ[U 6Y%7vwگQM"I5j* ؅4C ) O~58o3K?7,gYS3̭gZͺrƊMf骴Fde lg%,S~{| ~Dw'oT'sY,վMU'<:EOyV"-Cϟ#96ۘ# #޷+NIv:^輅EP(v wxG<= =a͇aØ*P*9 򏟻0nhȆr,曎k&'(yQy*yniƊPe(sBT/o@Uw7iR~ǚhi7qk,K"KWzr ʣ,UEA{|ЧMc=1j ?u=OALvδ ta=^Z~pGhGA+U"I6Qv'8/۾vi>\Sܫ"#=5`KGd%'Ou/Dw-{26w]4 k&1[{VquIc&vïX2U-L{Nbqlj]FRks4p#[S<ԜK1bE_Y Q"tφA%w5_%` GB4xc+#>WY@\ 9!e)uys^a?f]y X,9'>nz뗟`58/!5!u RSuT-z{(O/x [|!=?|^Z-y/ >mce7"(?􊫋o[x1Yԑ@R.fv:O m^>Vp|ӤʟV1|D]|9~9MXI?K;uр:l(ʢRT^OwoZ@:{=NqՀ(T;ٿ❌1EDi*PЯr/VWsefMqUڭ?R;RA~rfX ki'r K߸jpg6KQ◔@^`Ϭ> "m=5)k7G ŊO@L x XOq}|:NWugQu>A*UZ*38G?h_9#uiGV]4dUyqlGg <~낫2'/[6'n^T=|v 6)7T ׵fh[JQF]bTϟ0%Z9$VOLl VZO) wyJg:k hO uZ=֕^̀ \\GVYs<QmZ.A>qz'&`m˨QǽkVYW,{:3Qގzn*8 =vjxih}JJ(FJ^c`=Tα'7Re3t:&zDpLԴ2MQ&hM/ NTs&k\w1WItv7|6ʝq#uSjB?&ԈcÖcK6_įU7 qFu h/Y }H5#Z7xKvzm ϰ"3\},\3h噡BAD= ptwǘ;+?Zc&dY$Rvhy^{Vuχ^/_}xT,K8o;0՟ObzL#}zE3uln^42~;^Vz~PˠsJF91m_rn'YKNB?MKUVbO s&纋P-P('Ju<MY w< y7{ ]\ߍ1zI{(sW{F+W_i*8x(CSM2=HNx_v/E[D455ά3eQB*1=88C_yeuu=^ىD+3|gsOE=e'p մrk|?GJW?>r#XW=w~ 5G=? bWPn& k;Htb}diy{vMK?(I@ez5?C6:"dI󱧑 :?E ;9h!^Y>'gt\loJ*7 qǵï&}y%'s̪+UdM-]z;I<]Cϥ)`&"mSeū5y{ zڥf34{xJֽw蜤KU d^0'9 V>]nOg W9?Z"PuWH'PwؒM^h 1d& g`_1{1f7<)w gaƸ;uL|8y|{5g_c}Ra]F@pr۸0YXGzYZ1s| Yu/xb*&)HՒM46篂x]} yC&V.z.Gϓ8G>WTUNSD w"jJgٵ ~h =ŝvU1Sl$-|sEPv=evumG8 A!j)EBv(|x+ hMFWWG[5vµoW(})p^eiNVK.?3cG |K]asY sFkzw h֜5ҘޔɉE Yq-`}1Q(jH2*oW6Ny=÷{npxGlw@ g.Z Khww~D}׼my/{1`i1"08kZ`#mA6u)㙽p<ŽÎP6qE+zuv;QP> >\6FS+{UHU)&wK9_:G3 OT#YFY0'}b:Z;fg~W ]\- ?kK_1'~ =gi'T_F{-* ٻ!sO8~s]@"7+O~n.x'g[~x"=]v|O6'{o)5ϕGc~f-}L)90:%FMFWgcNF>fӳMZo>{ٻnOtBOh^vڽ ^qGiz>?;JGqe7!~&Xi{ Y9dwXr HznF3eɺx7V K)J_klh+6[S&$ _[CX;u YFD'7zZy~o߆e[? $G.dN@dG$I߲2`vedt j9H$"H$_!sx<0wxꅽ TDD1ͷ̮vws[_EEUvU= ߷NX{ጰ%tؓq|ww {v?.x >䥞5Y֏}?A"SRkDb{@=T' \HG^>5QrK|;jjOΟ5=<)/O/|a=ÿNd4; ) 7~):-- zctFʧ>s:qk>T_\ypW>s):+}Et ewCJ68"v^vMXqN].? Z5NЮH>?{pYi q Z;.7!oQKka(5!g]=deɦe{>Ϸ}GWGL^!#pb,㵕@?E=܍\x/ ؿ*v0|~_ wY{Ȇ+}r'A{vpd GwZHK藸;X M#殓FtMSa;PnQniDAv.M A;wzZW>7 Cd<;C%x[7F;{}VA.jlk S'vBxzqfX6ˁ#bGYGTkS{wE#x;W8kiBXK Nj>mw)XYoQSdVpoSrsFrgj|tru WڿZ;a|Ļ(gW:Gd{%}{i>$㟗uO;^T!>=Eoym\|Ch89U6?a|=ųC,i59C;kw{뻩v{ ~Mz;~p6JgV۱zu/ Iֺ rˑ.pT4Av>li}'I3?K&҅(Y=cφ}/E.X_!;s}Btw Ae8OwXخ x?Jz&|{/[5 \03z~/kcϰRkj tpMk93eZп||}=^=Zgx.]//h4v[k +`a\[튏Ώauq eq?wg׽=rԈN[bLo%9o(c:LbFOgG0Gy֔\ W;C,VRbȏw(KDU}u\绿kӱx#?5*x}8 2x5>(ZעGGUM9=]fPXUt o;z~+Udh |ǥW_i t]Myv w3qԿV+Oc'11PG: =%r^vXΨ#GaaqQ/&Ϸ܍ϹKOZ{7U_ȗGt8g ^Jفp09 ;2Aay_G5/d" Я1~4@*ysdc`{wY]kG{hnv]'USK\/뎍v[eTL|vw 3C*~? i_>w3>#Uc!i<98=3T:>ڧ3\ VޕW!MLE^XQe$kqN WbNU10tщ%~Ϋmz]J'ŋw>q PxpI+J=JKCx(u]d^ GoQjp4}Afvxg]Gx(%$s?s|k;#lAGw#w.ƸOo== Wu}*^+Pvd.$Wm0)A?uScc'X;1k1;= xM+^u@٩Ñm֊.E<~ J#.-qѣ0Y F9FB>6=Ed*g׃ +`T[W/%~}ὖ4nd }>:~$Gf7J3{#]Ǥ+w/Np8B_/>hHgÝ>9ww2|+wd8tvd$ϩ2 %w^Mk<,o;+Е/Gk s5LAJ~3Li}j{>9?Iuԟ_̅k#WO&,? ++7򈳮e7`)D(C+i'oivzkmkIF<h=j ӰMk>hH3t'+WvguuKǷ_'{Lݗ#x1z˪GXO /ki;ӫ b,F¬球\ZnCSzOq 3P+- qfLY;׉鯾v`sqw?UW+7XQ˹4o|~v2bd< 0syp]+~6 +X$<(sbdHչȆܓ ʤ}-/\*}~jwh7-r}6 ;}lAPsv֟s} Y/x \N1-Zr1.;r1sSJS;T\=,%3f+?Z>t=3WK=1>!ퟐaiHӃ;Vݩdmzb%S{oB;Wcyk{w ~e 'kWq[ 8CH3pg=H <{hp;4W=B/'1{GzdW~L6 =i(Z7AiK_U dw6xC 3cBN"`;圆O3t^8(o߽+jXwMIt+9`ܽvԅ9;B4H䓗:O-cnf^8K%<̽^˘ݯ HWxz'ղD}J2{>a%˄ ~?zm\9߻ҟ;mC{|:$w|/O쪩IV],/ͼU2ӝ;ïDғ1(ؿi\~JKxrIq>>>Ryg2 :p8PlYm!hev(}; 2Ǝb]O}A ; w?S]pcw,ݳktF~p`h`{1CK.3!ĜI+;&->pɃ!C ju^žJ٩|7 H%S6{Pꓹ$4uOA˳@a/!l^1naW& NXk {T[r~^RBSg-ޜ|li4;4؁Ѿ8>n_:m9ʄk"׆~3UD{]W]U9D &>_ckDւ4XN~@=xtg ;7.Wizjeɫ>Kudy{1Rz'xLg83> W>1}mT?y÷?ّO“ekbk\DRHA I>OWWL{x_"ʳ$YKв>~wd{]UzۡME_SVjy#I&4jpvKԀ w` Qo{8>'E"=?gѿ_Ɣ= b&Lt/?4\ 8hSb>c̙s%K~{XqG8ŧŸ_cbrϽǶ$j;pl{㷓3WNEU=d.c\Ex;J vsLw9VAjk+Ϻ:f;yY9f2M)Yy䑠@mz|o9,|~10-z\wΨ`~N{b1lψc]!7{!6׻{t~&cMuʣ8:*p npA^|R/Elc |1~cA0JVQ3sύ-/q@AX5v'E_G{MSwƲzn\wtLf܇: w@O3v ɺf9w!%4$yԳraoǩ1_1lkDP^ Tq^z85}Gia)+y\r$%Sv. ] KDhVe9q439xG;-D~]21D+AMH]`<_KtGqg_\ }pWʻ?S`]do(*}r./p_x3iwqכWk!ܳpqw}|zuݔ 8?#ztiZ{g<ھ=zh~=U,'cwSSNDZ'3;ϳ5!MLi<Ök@G}]LMi ~=I_̟6Wzf0׺2y#ۚR'Kg5y8F Hiw!5{m i#s^YLt Y?&V8X%֘Oܩv Q71 we.ϕ5\vܻ`=Py#QO:*`oQzD"!wPv?Qz!bZ kdcӌ X 0ʇ/ͩEo)qI2wT[ CSO8ĹG;b/{q`|(\^4̫ߙ<=f`G BRx}i G> +"%$UoW{ӣ`NtVNxjFgϡ\װϥߓƿ#sw6YL]dPyq$]hxj=K?5G>ۇf cVXU,0FzQr)Vk˵#=\:8"E;ޜ`O,2X- ?Us]ΌHJ <.a- q'HmNz-9o}bSi Ol_oO-+rk\os<%MЯÃ"{Ltdl\SOsvewNy+U)_w Ɣ3ŧlo#ojE6!! ?|!y]p]z7Qp=gHv{Ox99c^[^}/#s)P/(w,%#4@kYoS}WyScK n}|? 59,ߋgW"X} zUݗz\'7 BFO.ȿPS=p<= 83w<?+"4(/h]]~߿uYځ'mu7 yD|4h|/Qvdi-ޙxA#g^?V `ػ@goۿ% ęthg=b@Mhi?} ~.vϔ! ΐgskSŸ7=g+C/ ;W0 Y\D}'X8|bL5O`#B#Y,cO]x@7><4|wҹA2#zx_xS;{go?kx 3߼F}_A$b+5} O܈k"ϝmu"!W` ]RqH>Wߟ11wJyz*ҪNrbF{%ZW>3+`(4d߇_ߠD-0%?]oO0JZa,x /{w(iz6/xПzhw3eמle}pE@Ze_?&^J'yܛ} R%{R9ƪWœ=A/7fgyiOgq2gz]L%SSߋvϟOMo1_ר `ՍX ǒK9wp;<+Rz<@u7n_{O+^F(n-'~ۓnK.׽׾@׼Xy]w2ԿZe-ix냫6[}糇HoCWg~;"/ )%ՃH)Jn8! 4s+I*\#x=A.1^8nAMqt9I4EG}e={?koo p$vt|4sxYha_ݮb:nJ?gm^hC_>C ySC{Pޟktӟ^ND 53T܆cĮmTNι /_=f!C5lO.tFwWwXy4Yz;8 -]$7 p(ɪVN>2{*ƠΗR|'6?@}:t7脨U')n |z/ fڟӧ?(yLj ߗ 0tSBE|=uZ fK}L[ xC}tĞ_MrԣsόaOqy=@#')>{Zu;eSy] r<8G1O0 :` (}/M3%^/κg@wYk35u6p]{p-7lz US':e]U,*yAw*OP4}^!m􎮧Fva'c_XҏU,r[B9<+ar]3Tn7V2ÍQowh<5]Zh[Ɯ~dLQ`*`s)[Ms;̙KTB)eY0No6N>9^ytVӀZu. ó,dj״2cXS7v;tbkkEpMo$31h2N<L$mWӉYi},<Tl+"o7~w1 h,IKLFHhRY, b{{t=}x&G7Ͳ{ kպZ6͒֙4IEZKe (གG&Xlmo9HbzO`^۶MjbDJ[9@Ku`_#J{9Rణ՟0b~?܍1y,fؕK` 6TS: yˎwodnˉ&Rs@ZЈm9[Zku3& 2IжYF;ٲ.hZ]grY[! >:Y"]dʚRXV"`n L&b߳g&lK+-#+,cZCtu[1Z݊),P @-;|X6.+Wb\+Lë*Magܖ*MK`LUuP!Fr3iڇ̧pk'5oxYG!S7X5֖UY䅌Lax@̮ސO`%NgD|wY&+Fm9hk`hOVeub r)? > =oZaiSSE˙Vvy%) z,* 91΄2[uJlTt!vW=,r3`x[.mtBFם2*_J`ںPcv(i/h}؛wEm̥?.2M+@%tZd(&fLj[Nq_ YcspЍaYSYZd7i b]y 5NnYf zaҢµFxl|RĒ:^2霵H ÚH@ <ߥiW7yR]N/hVDZAX%T6*i:-u@g[ ^[}5Q& 6ei wlMWu=Kķ_HMq^JIYcRoe&JZ^ljCLvVe&c9k>tCfMIfDm2qe, iBӁ[!.Ywa`QHh;f 4U4-Ve1w7wW TZ2,R(ۋCs,[aY⥭]V?ϣg?eK4$ Ə_vȼ?QuXb(NSc@̭ 6YJH_1))"$==<$ +lӫ)2lڶ*J6hߪvmfzt6EJ.FNlC9Y(?V@DbX/:[f T#.̖84& dL!MiUn[f^jإPx|)Opfhvgmô,?~c"^gQ&'g i#z`lߚ {%mfŬvAĢ.Nە/<<~+3C R%aS7:+ۻ$sȂwC*C]5$A?%֏-,֥1C+{[1p䁩mGҰ VG\gۉڭIL(" '{ 39{XI~pc,?416(}URV};O] /F.dvEZ /#4SZUP1lL^Vlef.ZVEQ`f8oWԔk#t34_m,Vf74(g ݳncAZ002,x߮;%e Kڮ.=`֗'ދiaXێZ;*oE } ` Ec?a#ž(9N݀Ok &h{:V9CAĦ̅`%k]cD`9cߒ R ,2#dLĊV evBG1Xu")5&AQ3|TmK ^4cU&웠8 q^/i@0m)]zGh?o ۆh]yWKrYeV *BgB1h`?kYm+y;"Vs#IXXHa d˚IV;wZ2B.1MM()%qB˪l-t$X܏02"OQ@%/[8] rH9A_ :CZYx?4}0UOD- u_F'w#OT HϹΊpPvT SQ!$ߒ4vrۣBn$f*O%|0IUp!QeI64m"[s@B D22ZB51 ''UQ1y+uD˶vq~zLV]pNZ8i#z_,L* `lyK_xnC˨;r6YK }$Rk ";x tH0[e°ݓ&Ew&u*Y<@/2<4 q ?, 3I.RRrX!88ef@c,%iη2"\[&Ih(vlU lydO ւ&Fg//:@˪ӮAE1謅%s*mIQ{G,H/W)wH&mRyظuXLLRVJ9."?plbER4ƤCoh4yUrY[Ma%u*vPRZ@֌zQ]WI 4Iʍat!Q. @)f?g1U.Ѥ{f{jAP4IXb8y"'HLЀ(Ypɶi ĥ3rbf4@_:BpVͭ<7 dM \ƑRM Z" vgS،8擄ܺ. dCGZ+3v{#XV6rgˢFܸPfcj/S;l3[s:+Ez!`Q֢mܣP7!='`.f?1C7vX$8'h++&< 2'a Mm urW^ *6KP"g0l?ߝwOoet=˫$[ƄH -z뢴_|"Q'0X*B^p~/zB:I^ o_qtd+=1i2\W"5>Ro/<=n W%nPY/kVߡO9,m[QnKU/pTKPR]egfJ,B?Xj#bw(%bu!dBgְL YDkU~io U$C_QΔp)A łobù+ae]i9ݶ葑DMY t9XV'Ɔ |,wQB] *^*w33UV?==)) *sY9(t\#ӵʁe4HA8@ ,]$F/rFO<gtfF<)oEO_~(ʜ}3$pş! [ ,#)A%x֏dUJd#}s:Pƀu`Fʍ1U$A4YAXaCHnBaN.fLn* J7)^8ִ*ښmij+\B;J~N;1ru#ױYA5c5'w;eTIk'du י̶ZmsuZ>"'2=ysx:+r=@$B?Q)5<2KE5LzTzԾdN'JFP@!ڌ?RJ,X4)2_創̀X;]ɧⵎ#% 5# e5VhHiXfh̀&j dOW EWM9?<8`7 uJ-PSuے/Z<7 4?ѿrd>K2xHB^N {pҨhm'VtYe%n.*iy rj@3T *!F{^_Zᯝ ؇ؙ=~`hDQM pETiKz 7IJNRDk"1[_@(} TB'0"49jjeLOS4)$W)vYʅ$DJtM@2<N'rz95n1e!p.#*v V <<Ui_f%gh ` yπ#+MX+Vٍy1֛.҈A4BE"Y1zI*# 1%H;N'(^&EПQSJ"RjZTh8% :]JB4V&PT/Ui "LCsF?2ժF@m=GdkC04+!F2rCWk=O[3":'ka{CJ1$}M7p+4"#ЄJA=L02  WӊO)6 S=yeuBY!<"$gTѭҔ4&M_ Ս. TM8%RIKF'1 B iՈdӢ?qVK+rBQ٤)c򤶫 :Ibcp郘п1VFWFT9[*I)Y" }dڶ#]$Y%$S|~l?)e7g?Ol6\)~gy?mPQ ^w5yDXZ],vB&W 7}R}U,좳 G[c;P曠4AK8d[熀 OAz()DWNKN|"܄jÝ?Tv×|ܾj{ 9?ȥ3IZBg\yBMZ2QSKhmň*l OcL8krjWʼՁNFk$}U&.%3wr,N_nD8;TUT;Xu{F0}YQ>?p"YVVm&H'9V} "?Aťǟkev ߠx[EZzz4\J+?;aWVmEp7#f@eQYy?85$D֙T?mI(2Cz6/8Bߍ б5ʊ(o /t#hQڠƗzQ[pO^2Ǥ>dfWanA uRh o':4Eo 6`mVc˥2T5?)u-+|FXڂ…1(`6UQl$3Ñ0t E+~KsPyǟy)ui Yn+W $IW=PA%iO,}G_?IO E63 drױޝ hU ta诩)^K 5jI•KFcW|:+B eoS\P|G 08B qҜ/Ll?Q/dqO܆H-6/CvO{tr[%݆]4Ol$h2g^_)ulaafmt.;di,`7~Nv$^v.Aݷ>WB#QE^:.mݏ{R;E;ưK)Óx,89NһvӬt:GN#TC'{mon Qapq+M E9AS"uRcFG-rd)$OXp{;oIS.Eǂ~d 7B\F: 8͙Ku"LAMH@#L}*vƇb]DW/Zxsoy_, aPŚmmm4+w 8VТ 51*՗o MLT/_Ok-F*P EJ*+jlZ2u%Iy&Hy<RuLU#(Ve,4]/H OI)SW+ IDUo [=@`!6MϪ) DY;%u(Wl:nN觕Fs67%Gb5&3tV2LJ [zWF#CumQ455%KY^e 8;4c0yZKvjWJ]HOYݏ6XV~*,p(S /uB#ϒ֩ԆҍI^A?lˋ'$y32̊c-R:|<>8I8 <2+F}T*^j?4iWp]MN9l$U_B^;RVj[J˼t2[Ùdi#й+m->+am\)?r~H.rnNG,q P6AtJR0%'`GcEs/J}О:̨;`~B6F!~iMP3Àiɧ%#9ʨC?(W&Eh߷v%pFP-.N[tJ["_%x MF8G&rN|5)ږS!FgLAMr u~ : iBe߷-L\aa =Ie ^Tm!SB=ӌR.QCoŨ" s†rt*T`ܹ JU>Yy 5Y]6H&ucMa5}/ku$SA1U9dVkSl$.F!&7#;N&$Bq1|̓"3_zKڛ?M:gP6Dw*t,r)u :0kBβq,}HF'$/q_#R? hD3Tp`Y30`}ka!dS2fG-$d& ng7M9(\иJ7>pzއ.=@mRIZhk%#"T%@ӂKX=pX\Eh&P) qrKqHdhUrF8fa_v%:lƩQ4Huh å?6-Hk+ZIR+lW(=V xW0(\2!m\&4PWuG9RF%Gӱz~r,1SAt\bϪK+޷D\B*p`J.\8[v!'EP)T(7t*Ȋ2$6Ov:4qM;"<|qХ-Ơ߀!dTdN3j|IQFGt-khlgls3oR̡cU\f9cǟ-!}S9CohB\vvKu%B9SVD!|w!gI̩s"dq+ @yV.LlJ^%vmZʮh\UjhIne!4@E. raQ69{_װH2M.C*4 ZJZTd\g]K:|'oWUR)K.Q {J\r3)CغڴpU` X~)%:8WFZG'Fi bٹlMʬns>%ɹKh8 Mӡ":Ȋ+jʩ *z *Ӌ4E ~>rI3)Ɍ(P2lL"ңX[{mS:ҔB EVpMZ+Htd؊DJ\k(=w(hDMn+29R]ۨ؊ՄOLp4ibdeWmeRqQ cOc،>hjFqYQIܑҒ6#/@pqRwIעޟ:h; QitiЏUK %+.a(Y&#\`=-[qNÂ>T|At$i)d6:E (u XUB~K= J{ Oe,X@DL m=:۶z$C`3[ivH(#U0aܜ~-uLn\ 2ek:ϭ*o5 ]>KX hE`[])PE֬ Y[FgC#>>JGg V~9iusڜk0lsTGBo~3+ڮd|/"-!7|Z!)>JWgDg2l s_!L9; D g@  U^[4b~HqVpjkpkߏA@3bCWMܥxb\o 79m*>/G4z/o%@KeT]tf7^ N`tB1;sXq,_'ʅn1r(䪳o'A4l {T0rB~f[D%4cec\ nU8iR?&"gP,"ğ!ڍ84 rͲL-}vgQ`P :쵒&|L޾Q)Au]PT|sDяdI+n{DNb ,F3>ʦʺk\!nTQrR]jW܉!N'pǓ1'm`@*#4. v6um.Ŵ)sv# F?̪Hjs99+ ::?9}a8Hy-xϵܡ-$[B3w}-󆎖F@WpmHPVCu u-SϢuŐ5nrn"m8tb&7CZ.&/5$z chLq*mCQAZ^!ă.v :%?.C,HRKŎ7EZ;cx;fYf0T‘8A,Z(mZ)p7ц,Zq5`4,5\^MNiOt TS /2f(8dܚ$& @M/:F}RLS?%nMIrgN}/35b{?XJ+X y(hvEVL?lT Q$G^h)48jhƨ=ܶfaqޟ~%m"7 Ÿ;<ӄ.PHCMIJ Y|< 4\qT&-0mQvjf6uZ9՝ҽ:ԛ$8]7!T+O]9_e5nVGiRU8PÚGxkð/{6kPm|IBWO %,kX"W, 5-JkYʑ^]k8}ݺcXm &N/#P2G)K#ҝ0h@I6l"=H7pKq;HiĈv\!-߷u!>ezHkzy9 ePIσB[Zp"8$mAbK~څt0EN Jvu7fg!YU v&BgsE\MrZ*قoVRz).η_'ND2q|"l"sEi\薂r26vK(͆. *V`?٧\ aR ӽZ]gV  un,Ma;77)Ci4퐑oTf)e+N 7и<^(1XOpwgRC[EnƆ*ˋw]qa۠%{?1$Sfֳ$irn'CxR5ϸRohQ1[k'&LP \;+Ÿ> Aɷv4%~X<"|sշ1’;#QmoȆk2B(Ō SFq&-Ծ~Ė4fDvdwOƘܯ|ѳNg` I7_3S10y]ApD{HmMMN l8ϥ7oW@/ٹbM׊ s/r䁚y 6I=JNOu͝T*~YjuAPb$* mKNM2GK0j砀#o& gfnR% OUs{? !-KQ*Pq|"¿&>r?-\O.g5,])&) 5i9? ZY()RTH#/vb9)Yu)\"hB3{LF[;?z)吵NG-E^Ua*jD"zz7 fyD&zM!C&N%NRfXxuǜোWk.t l-]J^ f YxG}h|t` -9FĔ IӌV1zA^.iF]y\)]]ܫTK#l f.tY > VFM_x!hWNelF|/LkZǍPvo-)*>"xRdWShv,3~|,~kvl9.p;H+op)/-.\0~˙O,+ +poo<_Յg_w?⧜/YoYg?>{cVf36vuú8۶u@/援Xdq|6xWxzK&]-Ͽ^`qfӪӢ|S86mk/YQD"kXO_3{OT WfxHiM~qk,/SG5$t< ?'9lTyxwdk'΃X߂ֿƓl8?| oCu "oUEɓ?hۆvr~ucR$qIp[@'UެjQ(҇MI}ݵM]>gcζ*`"'.o^Fm Ex}^|2`oW¼,*O(?Eq8󗰼R=xg[b[ ~j)`w+#xCm{χY08W^r8}&AL}Z+{(ie,2{.ǿgpYma b >^ >{&O^e,2 c )?Ɲ*hls=jOI?zHd^rj%\B]~RoPU)U~U~*^۫W UJT{߾y:Sb3R~ 3ȿ7e4dKoL;W{( ?~2c)ԪY8tn滹2N=_;aq&W6kzh ?VGHl~V|k}w /=ﰁ\EžT-O?t|N_ۨvuH,ː!{>EXTWzu WDЦw$aC]5eQw,<Ǘ찦D߾wZJRucPAAD;٭wrD`NVu&]4'FW}W-뿥Ï$-}ͷi2?)ZR޽oU^eT/rwұI+Q.g/_޲+ʘꟸ1b)=Yz.Twl2Kd6x1ɩWbvT&D-MtT{";ղk;߽e2C hIb؋[6peK=Xk5yZ4ݛkT/rC@o6 nepY,C,N=n n И5 /Zޚ_d;qCCتkʲ>/_i/" Mf[z{E&f_c,o~'¯.o|),/?TZG SsawTwJn~A"h+WjhATFw_B_6eg.QSk)?A-{/K~C]]; 'Wu/'(c_g!x'w;x|g޼%"S! g{<g͓exƟ'%,.|Y(Ky蕝}׎'}cIJ˘*~Yj[WD?we{G0*c+)wq~zZB)#Ħ_~/wMZ޿-g%,ι[ ^\J#|B|"HeqI%8RT"h@CgwW յ<:{^}y9h)%>П\޾~ $޼/5"Vz8}ן[^Wh_83$bƸ,MCD8eu8⍜T~E=Hb ^[B~1, Y @?{G/G:U#NEzJ?%w,/Ϥ?C OqZ>nsR~~^?}|,4_P{vx9TӗYo9}bgOyoz&7e}AʓWݻNKh C_\=:g8bYcV2iRi_ğ _+-% xD Z8$,[/}+j?msP Xܷڻr2ZOEncyGXsivb7 u?7܈| ͟vX˷)\5Թ |&޽ڽU!5^'tߦs&Hy~{wUv2k! =~;ƝiL}|˨!#ŧ~faY9淛qp+UҮvgR.!aK~|RF+& }-~+|BЇ|tn[U[F^OrY! _[ :e"og)s=I=R2#NtETA<.폖..Z3˩4*_)Ӻczg#q*T'{_FCiP _#ex߉vX_4|́-?ђot5 N wZjl7qc!419{?;1 ~"|$qP wn,Av"ir'n}I:Gњ3ueQ=~9Z8OH8GB.#ٍtيv o7O\"ߦoW?}{"+OU߆p^%7>n!O8kM`70oUiEvcMh!ut Fyg/Q)wU7~e+"x//-Z1_8G=MG do7y|_SlH>#W{KQ| B#L-=EhJ61`4:~葹Rp0ƥS]X y8z ap~ gѷo/i%nS]D>'=Cke~;vxm9cpFmG~QvCaOewV?{OtIyG~qV_˞y qh? }v̿6 K_>vASPFf vXe3Š}yVWbTvŏԿ8ӥPr ]|W+ߕw]|W??݋w]|W+ߕPU ^ö1WkRSxP+>Ɨo[T8%=F/է5?* Dq\Cu.~>ڽcCɸ"k}O|ɔFƥQ+50|cUPQ,';1I5 __Ze)F"S:T@wUgqڮYP+LF4/w7J[ Y4g;js*3`ls@bTz~('~L >hGU%QBQ֑] x3{_a'Ai,T{_>aۚg.Ɓu Vya{Rw@* \o@ e0QFml](9 ܉j*WWvc&wʂ#?bI(W=`zeĵA*!݂fs+o79dPAaѨ'+=*un[idJS9n}qq ۇ@S>aQ;&TQU՞`t"UH"P]6\Ѩ[lS?r@5qPTmjYj ¬NzmӛS=s@sZ(v}ZS}eVA;=h'50SDj zCtYY-^2Zm S#)_4 ~A~.Hpfh|p" gV,:ANGud4 @Į6)z1g+d<]gVx&[LA'Pz 8 ^=0+(T;˥z/(%N'LD/@ᱹJ~>b:q'V-4ۍ @5iۇB ڮ' ?dKmW@Ai}qYYO,"W: = E#@6:F:'҆Lo06/rsf na)E-kd~fTc0~n]_Kug*bޗ.U:}dnA31)MF*7 xi > ?ɴ:(ҵrgbQRHtW3YlZe&G'JY?8T1wmåzfTf'PŤ#S)=17~2NNb5ZvjD?b:?===?,},gIL7nKQd$S=RQD+@CXS_ N(u6Æ[j"pO gJ ~4 ,d_w*߀X}J yRs /~̈́4WR39maKdI5+h*g u h|ąFƿg F/(fz@z_fg]PA:A?S _B=[(J} u4~ )D_s 4PxCo<5D15 ()z"Z'd X֘;>跺iZ`>tprd4d*2s`3O0/H톦r\Yu;C5j8*qD~:4).- v黏1JU: 9ÒZXs +H,9WMhnfŖ-`ebQ{T:ɤYD|J(_+4jϬ'Fz#GG5.1By#vJ(Έ,Z tUonW/k9\fH^' =X~dӭN~" 7dV/0[nX?_\ GGPY-v|azS"!ȣѕï3(X`&]*fË'uQͥՠ+&7q'AaW$\tdhB$48wG&2(2,QfY}T'ls/ ǾD!w> `~ 8:/s0JٺZڹeЪ, ϹLz5یnI3q*&I=%2fvxmߩ#qMG;7!t&2Elj: (vggX,dYk;5ɦ%O7$cMҁ ]6pKctwԃΛ_9>2<D zIiZ_;?G,P-6gqjYX]dMs5lIfYtx@>6f W4~+Ůb!\?ϛkZ"CG]Lk#1:"Mz0x2Z/Z{_ m;^Zz B`Z~N6$ƈOkB]V\*ÛnREU.WU#@ Uy]mCUv᯾{4xW* +ڷX*W;p& a֮j<–7Z3o[ d H%(b^\k o;V3T<( ZKwWሓO]_&4 ?7.-Cˑf"}.&n,[ϟCɉs#LZ?.SDs vxE_u./tHEJ|Lo=Q:lύblGN|G~t*ԮVdҼ؟~$zv=8: 9V[;hLIDvCC%h "wWy !U'ՋY?]Wv,hkw(H[)ws3&CC8^ލd0m͔X Zn+7B6҈-Y{&<@hݠ{աxzS2\tX43#>"eR!rvcs)7)(z$>ɾf}n5Bdvb@^Ԭ"${,qMp Bbl{g b_Yx0a"n8F-١qP%&FK&#$̷..3DaU0̰ڌ8tyCCv8ypp#^tmV(dNIT%OfD͟T㐘 Tɼuǜe 1@*#͚?R 1T60㈕x!6 su/oF:\N`2' V:/4P8$ƍT_҈EސKTEGl LRS'6 FA ؉2G#&SrӨ 7csJfX+PB۷q]Umn){Y- j"F1jKPN ˚SgL0u.sX㣣c?fX@oLNAo2T_lP nBBQ3~Pe2Q$+/Գ$fSh`~?vUOq )ru`N Aw?Εn*}ng. "#f8 ]*LEx5wU[?ams%,λS@{߻^ՙFzq$ `$(ޤi6]zVANHnQLaZZi3S?1QlG v&գp܇'DM,'sE4w[f9XbyRhz]zNJY"N/.dR[ wU,viuϬ_?Fxt= g s\Y$s&P4 V;D,`A  D aI+sΔx$b@K' H'Q0A2z *z~s8G $f,~ƶUb/ JOdH_&}K2Y^C+9" e H!C R=g]Z)uJϋD T섟TiSkRRM[x2jfgE], QfZcf-'gw1OR'\ICy"[0pTve{|7O͆}ɡJcDD6z3Ggjfw1pKjw)]8^':_wh? "ʏz`\wi$@Y|gTf*z.O ˨7͊BcLQ^ u>F-Vۇq,?>uph+? X sN}44ͣ  n\ֱ`[ : Yw@Y >5ޠ=k^=l uOVY^~yC158C" {9+4]'@mS5AH ֣Hp {Yֶ8I1|K ؕ:'#\;&GA \83)h}a&'D־h>vr4a 544Zt\hc-͆ZaX',iijDkjyPY4;>ʫJ,l u[mUMsl~ 㵾DR20 S$NhҕPJ#vGd'yrKn݈szmQY59 ݓ+pdn=&@{Y':Z-A"n0tA$:g7c*>Za<<bL)3sJ{lSDv@bFvߤ(M<)0/Iؽ?J}2?J]E~\ЅS0 MnuVSF765I1! ]%Ŝ,;R+F5ꌆ=?>dWOr%عω 4$h \inZ ~IM*u)t>@ih[ dQOax:'؈`I-fU]y!xŬBaDzc14zļ!I7fB,T7y*>e'@kb[2UNަ0?L?iBK(Zu#+l-1fgF;*?a[+td9 OE~棊&9KhhGcC\ 9jG+8&s,IG i i O6 I_F+%^Ez fWuI_+??9 _[3TLk|tBjcL\V?{9v'$ zP#57$I 8qu^cA^wl+G0LEbw.FRS';4)3CW3h$xC̞fGj"TߪAUKW՞V/ĝs"\]Ȩ*oxYTw9[jj9[G]_~bG,y_C.܂0P~^goiײtie{;=EN6Φ2S}Y{gUZ<I'aW^PĩDK{;f?LK&Cˤ?ްj_ qSY 'L{Bbm5aնO&Tٟ֞}"94\ǫ*,/vmd`6ztJP<2O]d3ŅԝzRtIPsE+w{{^5D\_=Xȑ,)Q}񄭪4̠-36z"lJE[%;4HɃ0 ?-ҥOy >X1e55tE S;y?CbU9Hwkߑ@4Ix Ad u/IE2~h /Dge9;\͠La?ڇj(:r65ef/A?&7~g@<̑O>M^҆1J>n= 7͹a"QJx^|,l7@mx! ✘JT JaE"A?;%ٵRE?Dߣ~"+R^aeA~ Ƥ"W/&u oWn}w }Q3?NTacThCg~E#m[jGE8p^LІT&օ̔;s^R rdcD\}x 1`"YgyuESO }Xݹha) n55st1Bml7W>-f@'g81p.MFz3k:͐4Bu'Ah.UG~K9lǢILt={?NpBgEp< 0;U" #:v]c]`] UkB??~j$6'Tc&|{*aWܹ k@&gȞm!Crɰaߋ#O{FS'I$81'#H34wI|ku.c6|2ٚ ?U ;8/JfUO4Ljo!\˜"T۷wnlƛHaQ6еwם 81>\g6gpH;v.ڮ}J2c\RtA!6m.@=P7MԳCN@|:5eCՒvןѓMR2usfQJc3uS]QV\*_=g>mq<'UZM mrrz*~vw>d+dН\O-*.BH w<)6$T)3wu,th]u%Tx2G Ʃ05b/g*ܒU>@zXM%| 4_h<+9%RDBMZ6hVz5C>L? ,i_tڍ~M:J|3PA SHfȼD]ZkW7UY CGĮ1*}^&PJc8ୋ?:_qCUTTbdFC,cSJ7[ˣ)'J"}B /- t |vbeihх"$bjZýgHQkg`ie"ha5nY?kc?qBS0]PSIn`\ք5N1bqp7r%[ax7(#fkHʲ ۏ4/OSY& J7@lRG-Oob;gH6yRH=!O$-RL}:p4]LWrE'=>)bqt 9{ 2=^=Yzʹ]<̇GhIj <'8,|7Dkki߽CF?.M@O#gyn_QaH.1Ȓ p=(H?Jbw'$!#Oz.5i~ߩ8/ |r![|ܓ,=q2+K=O3M+b3L(svDVWl}ͽ Azy͜DuÅIqSeзip8 n#)j{ű%By2BRHsMky.V \pfnԴ!s*+ ȴlj4plps;Z֬dgi?GF0J0tcsSk PV:J\,<\XW,َX4HmI󉰶Pxjb<gW="CNl.'J Hb8nL AKJbX>G׼`ۡFkdD(5%ELAZHex˦i.:.a&,! ,$ZӔh'6P怒% D!~Ntar;o* QD&/3}ը ]PNw@Ɗ.URt |@;*lg4;Hr&bmk}dlQ6޶fp0a\CAMok$gg9N԰Z^jpO. 6Ba"j-TUo[<Ȱfj-@FN{{[AoC/FB| :N Wuk Q>E@i: ȧ8 lgIs4ӑM9 zЗ lo1/6 r@ÂQ YzGj牍9̕9((#`7#&m{I]ftqSģ7ۺVPKg|ݡFBB #dX4[?B@3$Y(pW/a͋UxCȣh c'I?1~W ^tϜ=AG-lY꼊) hķa.9H#tRX>L`GwT#o LR!`n[krE9qo4ؙ?u+q 8 ,!hƬd%<=6- d{i1NrjZp!WsCf(\B jL簮z$Ho¡ ndqf,}J~\hO 5gDswSي9BZˆJVdCrk Xs%8/ y C<wZNGjl>IϞ])`(k쎀 E{xW?ŬjNöʍj!n*^ CSpthVcl5#u@ 0_圆\ ~x&ս?A\xe81U NN~GN@W?a6)Pk3KNADA5"K܈bb”ݴ""Z+5 '+!aR0x\oWߑ`!]V1'RU="]\\X`עCl]vpfS< ir7: &B"fÂ. 'C"4ڗXrILKX7.GӌLmnZ_/4MqЊD3C땬MQK8!3"á/}USVŅ#ޑU}?乶f=dL2)$׎qJ278Ygf/7#i iClsDRn-tŹJ7h%IN}N&l 7f'i'&iaK*D$tG76fՀ5AŒ~8}ϵ]1Ҭ`}mXDn(i|b8~֮E-@s|`N~uKj$1P'Ưku5zM9z*X ~-?,GSIu(7f>=3d&%l&4=R7&h\18 ݶ,j6:߱ɯ7coPhϏg|Th cqL$Fv,d?2*XJ#iqIc(9i)ibWLYS#;dBc~44;ܻNZw9uZoœgU`r}^CC= P2 4VE5Ju6Fȇc9hM:Y`y.pëF8Ѧ'z4"._n BJ^b_]9 kKlAaT:#a/Y% =>| %daM$R0Hy S"7n+;QB=ҔZ%~Ir +B$b'SW[)/QheMSݕFNdWNUk'Ny++D,3cBr"#iÜєP]2 s!_66kIS/NgE^DF$e"؊U 4N4hq}poȇTEӭ]GhyG`o{0TKB̀vsh&8 9ECWXآrӢlNYF77qBjڕ% 1BdnW be^ NYӌptƃ qM؎l<ZA}.S"9RF3re18w}qU=Nzʰ1'Ⱦ)x0+ {o,' >g"y>_Z0Mei(DCJ!oNB-~s22B \1 zAԾў`jUȷ ."R" L6!y GI]Xt8mkAcn?H~G%A|xz'N?f>Yp>3.#1Vx~i{*wTh UT?՟C?̆zA6ayYS?IQb(yzrXB^j l6hrl#zftY$$AcLJH+V[+u3ی,+=~iHxG4naN09]gC?M8YP0I֣V4t!sl㨇Ͱ׏qmw O*{ ^_zO~~&㼐G|(˩s~Q9-)ّЯ~a`ӵ>X2;/x?X!ØelX/R"TwarkK_3o%po+E!F:m9 G)L-Y O~~Bѧ_Em0x@SH > F޶ HHJӵ^':oyͰft(Su6dtH~į7*E{Z Цc?V8Y&'i"~Vɧ8Pj (tb#+0{I?_.ţF>~ytӒ)AVW nL&f㖠X)#+Hn!Ef500{ʝqU@~Vd0t2˻=keWE8&gxgH_(e"@7:|5UJɼawXm]Rڤ=e*Un|\.tgzH̉= 5aK=Jΰ#p[rV6pLI ɒ}HqV˪XҒ+0@,/)3 OǬXS4Y#bg*| p0hX,Syn٘3xC@xO)?i͊MhϬ%ԖlͬO1HȸV J#Re4 Jdh_ÊuSd6}\?ۋ 9$5 }uD*3$bf&ʫχ9l_vO!j 7 "~9ujEO̖"?Ґ>us#5fjJIjn7_8ސoEj=[n($h3fx}H21A@AK8&@`r?a&Adbd?>r KsB$\ e:[ s\H: kKRU;V<,tzPJ2yFh1AG?t>w*]mܭٿJKa,/LM  4TOcZ#8>熿$Oi"^nE$qf9/&I\SUot!WD͜>A6*9_ڍO.s~bf&3=]-FFq >FŮuy; Dp5nfR0;@SNTxs%G$jbKnNG+X<>;{ ܫK4m!Ro47`IAS}DXv>h P͂97w~?dlU' q욞Ν;bڌoz|jK.#^LMGX7`usؿLy*bŖCVNޏDr̷:ªy k`RU7)b%Wq@lfT7AK >-N,n6LֳY c(n8(5|V!'$6zOČ% 2fnS\ioAj /)qOଆjDB}a q,FK9O@Drp@B@\|x f~ z VY hnmfdޗ$m5 .$EY/ItRRquC\-vWldƎg=a&#pKp/xlAKC+Ƨռs@' &(;D l'aPH ˏ~jAbcoq)3 |s wCm4VGz ٔ1˾F1SdChzl5Q 9P2 jn0xVd8cG-!:UuxoK-x׷S4;B7>İ~A;E r$goMGw X632?2FWan!L^/rodcU>Qs91\UE$<3&|bDq4~|RdӶSAqnir$ekvnp=M2l1i)3-."-'* ck?&jIĥfk7Qt;'L4&GHoนc77e֬b#Y.y?V {Rq"_ARYgK~/o$(L Dd!25qdGlV}[4Ǧ㷦Jz` 8$CWk֏@!~B(0$>z 'qxi0[sW1HY鵩[LΉU{ycf+КmG?ׄrK ܾ V(V38'ak`!i@<"*||!K oc$X #0T ʔ!E$ (c՝L6ƮLLO :j8X(fCp~ /CőEXئ!~bflv=dgZ1<9??Fs =RƮ!N*HMW#J_c<&|W{E^\HBq CJTH$EEQD J Æ"(($Gt&)nKc${;7oޔy mlj&~::%蘔-2CL;s/ç<]Fȗ BO(O򅡪(GKZpr]ڰ1^JzK?; 6XoNHo/;mk#5~8ϕ%ܛ1ڎG%d!)iΥY^~^2TdZG!0:%|y'ã/WH[GXN4TiZ 0pT؀$\iMe`j<@/7G'mI%磷t|Αr2h8 hMW_Ѡ/3|1g$V^:\DJa9!SK5ʹ$Is(2j[ܰWȆ^ҏS󎼬.KnY W}r۲}l7uODb"o r&ƻat" s,! :@ qi%vBPr)W|ZΚcC U\}#|v}0"IJe`oj /İP^TtR{.~cVdz}l@ /ݛQ0@^P >(w9ΉQ>v1t.0JJx-X_"+DzKcDtOvAgpG4OĸIM#1^ZJU$pG`/8={'n X݅!6Z˟C06G V]ut@2΍f3/.%(|LV޹%ruC 92mpAS NO)݂_pqYS$á NM?!Ce8acǪ,_rײwL^>,fKgd䵟3@c>/jޞ7m -6snOA1Z /y4UG>6hL RJ3IJB랩Kef%n~fa!o2mXd/vGK6n{ƭIOq6-rLڵx 9NOp.7nL_NL ~L %_(X9$cIr/!1f՝酧YK9^I޿MY^_㟕  ̗|Y]%|wbsӌu~|˧BQ9[K?Gew(>F34bW^]̌Iw~ej|YGT22Υ>zlN'6+&7F sQŔ (M*c}C[rKXuzpdji앙.YnmVlW]s^u>U ̀U=+\o{ -@kJG.8+>_/?'_G-i ״.,=G*Ɲ9?_ 8&ȚTA_ƿT1Hy3GyivdnR6BO'ҙT{[Z:Z ߈,_liM VRWCS`ꁱgez5>AIf{Ѿ#@3mjcKҙ#|%') 1!J 6we:}K>ONYpQ&$$@M;DzH][4[ʅGY5rW}|l5?1rNO 6Q[a-l|Dl4 a叚?!Ծ`}l97A)'Kzכ?-E7*5ÜO"/;(l?m$͙zN6CEk|M+\u%; WVgi$6 [*Ue66&IzcxPGGFF$`u:V5COy9ݬ4GՕX|<_/ɫ2?g6>? 4,%X&ǹ4F!cbi#zʚeb&F|/ v망!}W꺲l:E'FewoS_]1¡$fСdhl-z!V/ei|QY+W%{||Av?D~UN^L6Ģm_j׫G . i۟%i{"S3 yjÔN-p:g$'ˠ:k 倽%øٴN \r]4T/(A]Jli,7|::h_5t:,|;^Fd Cܘӎ:${ɖ!R=qaϓTI9I)錱/DE^v{zUn+#DOHW_}ȟtrj?!r6^<$6wVʈf|K6u[WNNsfaW^QIpV 2|W |^+,='[)qX_S4 AGH[f i/jmlA#aPOxF_iBf/J%v}rzDžmGЋZcCK&83 T죵7׹YMHxn:4j:zi#u H>jeu=̈́i`l{~g@@*& ;} ˩-Z~ Swi5DOq)#|# (C7:.:H-?==Rt^VOt9 ^y܆Il-;MDIHeT*F?B-.σ{'j]HZ$Xl>>q! [ˏ պ וGvy x@qT@@@@@@@@EOQ@@@@@@@@@@@@@@@|$hi ,Bb5XMb(V,XZ($,%L}QTE/h>hR8KK Π)(%g(Swn& PbAI>ss(E˼Rzw"JQ.Z"2Wbb5XMb(e桥,E6 \NCJAdCr%/ `!a 3PBK  RVĐLʟP QNl_2z\6釒ἬүH%ej% jŁ"8…Zһz"Y]6c=(U,%(Ҁe0ک\B|}LTJ6rpKJ쁊[ u,U)I:,ʩ7"ՔbA >Q)+,Rr.JAU,JE]U,i.KIZQ"ݚP.e,Bz4B_)mW._B_UHڱBP&`1 X j!@(,,+V!\bk?+VS eY ŀeP֋b5XMb(V,FY*VepHY#+VSeO@@@@@ ? X jO+Vele\`(wR(wR(P7)>|A)]7Rp%V |_(&(V(Y\wr% FCEJ|H0/9&#,+xIQ [%|TITB*m8\R(V((}E)+\R\Q jC'(V0 X j`-+A)֠XR*eKCK|fh`ك,{p+9XlA/k5'Xh2^Kk9 k4  4f}~g/Ix}g봻0; FwΝ`{R;F l7 6' D$($I6ǥBux]zz (&+'sLnӞs8L O;1VQUx|\V{Tgtn ]Ti DR0,,^j*W5.'Ųޙ֪>U<5z]$% |Nу!MTşo:EuO5CAt6a٠SS q5r&zTΑ/Fqӟұ}hаrڧQϹ H=|<\ڧ>k=$V6 R<%QSF|6WF~yyFcguN<#8g]< #5yx cex~v?'x=5$֏gOW(<#rٿY=Q/Kl 3F0 #L gyC xex]%taψvv2iҎ d}bn&Uyy?h΃a.fY~:䧢ׅ?̟ZPm˲qڴl$*<52違? AԺ8Ɠlgb'GXxV &,²],{k >r#gDXu|ȡ֣*k+tv2MtOYrl֕g3 HG-e<kvy#,8"Ã/ l|ޙ} pVzqL?*Y)$=Yiσp?9+,?#Bzd-,?!g۸?B%ò!:qPxle OڇϘPx.5xòq-Og(<٥1u_G:lh1=U{Pe|!rLv⺾! 8Cn~dqc1& 0# <3)O P_d(Ţ]۱:x߸HpELJwX,_}>G3Iǁ磞 S ޜjDZ|# P%Mggb;E [?#ɯׯʗf+0.k})16b?މ9=* :w?ϻ\D}`+f3]o - <\UP"x2k3 9UCȯSk畤3r)ׯ{<{ Uc__uF|h{Mw7v?lf/إɿwG'AUo`&{{ dxބRM+'CmЄMfP"h_\ufa00ׄmM~3bYXG`Vc0q}_x&?w7 czۗȯk4,)G};a"go8uQ&WiX1]r~ޞoAM~GL;kY~1q]߮q^0'\wTOY/XC ?zD~&?۠~aIzu}uK*zA 7 {A,Y&靣/0D>F/sk0Tk^G gUww5`{̾;0ӆc(_Ol67%D 0ӄUr FmbU=6TF4ۈC{ 9 Mt;f4?mu1&ɺ}sG˖k޴M8k]M~du:lC>.'i Wa}1=5'vMjK`[(v'=fW6*cy-1cZ:I}F|~3 &=tw=80 Sa#z{*ܿ)3{`&5-}v3o'ӱuM?ۇ_^ס|3F?c;V X "1&`&\q{rO9޼T},kYtLϙGA{kG{b('xgxٷ_?Fw.6Zp6˻?cP?k:q?]~m4?OغvC私d?2ȼ6?s59쿺L?1ߡ?a{_MóA9%}OWBAq궙^`It?6 Yz7sLE>N>btgog` 75m']iRַϚ zQtzL{~?U:w%g;e"?Vׇw6vw Մ/^6&ɂ[>@>?įחq~`L&9~ Wc~GOޞ#OI?wա/:Q 55swtm?[h{#糰D;~%#ӦM{Hc꠱|6Rf%E֗R^ʙ:ݚb{T׹~g'QXt,Y]ʏJM&<l&PLcϡ|# ]t>sNz.M`q4' 'k݊.!NGg%<МӖ ?q)3ڋ|14Cczo\c>+{83&LK['w&mC 640ݤH~>h_8ӧM^_\<4`c4Ο/itp7T'o$g׉FʉFw|b']Lق尣w$Dڒa1kbn?i'O?U gH?>(l_n#|$6h]lOo4@S/WA8'&|Njlj'a}ΡOawOG}N|EϵAڬ:{Ds1s>/uGˣu3q}gN~C}f662a7o(ɘ*_ӑ]?@ l1`ێHψ54A i]#D<֚uׂs}5& ]u?MڋL[O< ` 97͹ho|\~solII|oC۶W}d‡o<<];<=o3Wgi̟;٢![a=O0ϛ0ܺ nu]vhcF>oҎ];|ǮVn!O׀d 5C~L^g@6΄rl%,`?o>M4])h\^,gXhelnU&嵍?~To%S.9ز*Dc}k?oaqÍ1ȟgUn %+؊B5lL*:b?Ӗ*ؚfZ}fN=h?oY&C'hW'\~5泂OnO.}g>Um&qƫ{هMʋI:H??c^!&1rn ـ<˽aa߿0R=2z׷=fg#X>j߂?-]zWZt{b#{C~x߷4i&/Ikah̚ey4vp[ .?kv  |f~/t1;OB{8f\).rRxt1o=x>fP`5|n>?/lk}!UՌ]t}wILVscϢ/ opJ1xڇN`)WMN}?_`?if$vx$q'غWl b{x8L?GO_'fs13m }{ VGnd}͏ HM.BrQQX3{ss̆X;v0蟾oKx+Us,h,.9_CxX*Z c@ÏG2U;F1鑳lGO1V0X}NY ): eR٢z>>}P;X-ߘ?s ˌP&_W{mhb1CO>A3xdX CYGП?˭g73Sn{>m54~vC8z^ VO']iczNg>0v|W0<{X<[xFHP5sI<w;ў9S7̟~.8i ywÃx\"D @"N֝Fp+,RO4`}qpM3N*6Yy`1@NF9WPV4KK8&O#`2U9<\D4PC7=d^ExCf5Cp.hht9¤YM9Y7˫FU!UFŧk ѫa5bryZ-iE$ z2=91w=pyE;J0*dV+ܜU;/.+:4n6004 Y*esVdFU- hr^UmY±Nъ@_묞A*8 [4{%x[PY Ys ކ?4a0WurVQ_S8VnR#^U#\cE+VhVZhe!z_es~ph :{%"02dVn2jchEXՄBΪYTzNn6{`4CΫksV-?gJڃYWAh?Ϊݩi4_4ڜ<\V]rVlߨhuNs0yWU!۫8 .:H?e2YTui;+=*8EAY6TzFBf%G W]f$iW 3Zv6TJqcElȂ^VЫ:pV'|SXQ>7C:ef.@ բ.]ֆsPoެXA-KЩsNtHIR&[hpOﰰjeVK=xJ=朘pg&,`)MI=' eŪac87"ky=^|_]V SZ{JR'׷܀=ؽWְ oM- Pi?N -.|8& |l?cћڷ.Aˎ4Oi߅ưck7䐚)w^Pn1xQXRZCgQҏgV_MnBH˩{mVq԰ayXƏT3<ܞ5zp^oϋ9`[?9ۛU8_=openttd-1.5.3/bin/ai/regression/completeness.sh0000755000000000000000000000340512627373446020274 0ustar rootroot#!/bin/sh # $Id: completeness.sh 26895 2014-09-21 16:41:03Z fonsinchen $ if ! [ -f ai/regression/completeness.sh ]; then echo "Make sure you are in the root of OpenTTD before starting this script." exit 1 fi cat ai/regression/tst_*/main.nut | tr ';' '\n' | awk ' /^function/ { for (local in locals) { delete locals[local] } if (match($0, "function Regression::Start") || match($0, "function Regression::Stop")) next locals["this"] = "AIControllerSquirrel" } /local/ { gsub(".*local", "local") if (match($4, "^AI")) { sub("\\(.*", "", $4) locals[$2] = $4 } } /Valuate/ { gsub(".*Valuate\\(", "") gsub("\\).*", "") gsub(",.*", "") gsub("\\.", "::") print $0 } /\./ { for (local in locals) { if (match($0, local ".")) { fname = substr($0, index($0, local ".")) sub("\\(.*", "", fname) sub("\\.", "::", fname) sub(local, locals[local], fname) print fname if (match(locals[local], "List")) { sub(locals[local], "AIAbstractList", fname) print fname } } } # We want to remove everything before the FIRST occurence of AI. # If we do not remove any other occurences of AI from the string # we will remove everything before the LAST occurence of AI, so # do some little magic to make it work the way we want. sub("AI", "AXXXXY") gsub("AI", "AXXXXX") sub(".*AXXXXY", "AI") if (match($0, "^AI") && match($0, ".")) { sub("\\(.*", "", $0) sub("\\.", "::", $0) print $0 } } ' | sed 's/ //g' | sort | uniq > tmp.in_regression grep 'DefSQ.*Method' ../src/script/api/ai/*.hpp.sq | grep -v 'AIError::' | grep -v 'AIAbstractList::Valuate' | grep -v '::GetClassName' | sed 's/^[^,]*, &//g;s/,[^,]*//g' | sort > tmp.in_api diff -u tmp.in_regression tmp.in_api | grep -v '^+++' | grep '^+' | sed 's/^+//' rm -f tmp.in_regression tmp.in_api openttd-1.5.3/bin/ai/regression/run.sh0000755000000000000000000000327312627373446016402 0ustar rootroot#!/bin/sh # $Id: run.sh 26898 2014-09-21 17:22:50Z rubidium $ if ! [ -f ai/regression/run.sh ]; then echo "Make sure you are in the root of OpenTTD before starting this script." exit 1 fi if [ -f scripts/game_start.scr ]; then mv scripts/game_start.scr scripts/game_start.scr.regression fi params="" gdb="" if [ "$1" != "-r" ]; then params="-snull -mnull -vnull:ticks=30000" fi if [ "$1" = "-g" ]; then gdb="gdb --ex run --args " fi if [ -d "ai/regression/tst_$1" ]; then tests="ai/regression/tst_$1" elif [ -d "ai/regression/tst_$2" ]; then tests="ai/regression/tst_$2" else tests=ai/regression/tst_* fi ret=0 for tst in $tests; do echo -n "Running $tst... " # Make sure that only one info.nut is present for each test run. Otherwise openttd gets confused. cp ai/regression/regression_info.nut $tst/info.nut sav=$tst/test.sav if ! [ -f $sav ]; then sav=ai/regression/empty.sav fi if [ -n "$gdb" ]; then $gdb ./openttd -x -c ai/regression/regression.cfg $params -g $sav else ./openttd -x -c ai/regression/regression.cfg $params -g $sav -d script=2 -d misc=9 2>&1 | awk '{ gsub("0x(\\(nil\\)|0+)(x0)?", "0x00000000", $0); gsub("^dbg: \\[script\\]", "", $0); gsub("^ ", "ERROR: ", $0); gsub("ERROR: \\[1\\] ", "", $0); gsub("\\[P\\] ", "", $0); print $0; }' | grep -v '^dbg: \[.*\]' > tmp.regression fi if [ -z "$gdb" ]; then res="`diff -ub $tst/result.txt tmp.regression`" if [ -z "$res" ]; then echo "passed!" else echo "failed! Difference:" echo "$res" ret=1 fi fi rm $tst/info.nut done if [ -f scripts/game_start.scr.regression ]; then mv scripts/game_start.scr.regression scripts/game_start.scr fi if [ "$1" != "-k" ]; then rm -f tmp.regression fi exit $ret openttd-1.5.3/bin/ai/regression/tst_regression/0000755000000000000000000000000012627373446020304 5ustar rootrootopenttd-1.5.3/bin/ai/regression/tst_regression/require.nut0000644000000000000000000000014012627373446022503 0ustar rootroot/* $Id: require.nut 26895 2014-09-21 16:41:03Z fonsinchen $ */ print(" Required this file"); openttd-1.5.3/bin/ai/regression/tst_regression/main.nut0000644000000000000000000024277312627373446021777 0ustar rootroot/* $Id: main.nut 26896 2014-09-21 16:44:37Z fonsinchen $ */ class Regression extends AIController { function Start(); }; function Regression::TestInit() { print(""); print("--TestInit--"); print(" Ops: " + this.GetOpsTillSuspend()); print(" TickTest: " + this.GetTick()); this.Sleep(1); print(" TickTest: " + this.GetTick()); print(" Ops: " + this.GetOpsTillSuspend()); print(" SetCommandDelay: " + AIController.SetCommandDelay(1)); print(" IsValid(vehicle.plane_speed): " + AIGameSettings.IsValid("vehicle.plane_speed")); print(" vehicle.plane_speed: " + AIGameSettings.GetValue("vehicle.plane_speed")); require("require.nut"); print(" min(6, 3): " + min(6, 3)); print(" min(3, 6): " + min(3, 6)); print(" max(6, 3): " + max(6, 3)); print(" max(3, 6): " + max(3, 6)); print(" AIList Consistency Tests"); print(""); print(" Value Descending"); local list = AIList(); list.AddItem( 5, 10); list.AddItem(10, 10); list.AddItem(15, 20); list.AddItem(20, 20); list.AddItem(25, 30); list.AddItem(30, 30); list.AddItem(35, 40); list.AddItem(40, 40); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.RemoveItem(i - 10); list.RemoveItem(i - 5); list.RemoveItem(i); print(" " + i); } list.AddItem(10, 10); list.AddItem(20, 20); list.AddItem(30, 30); list.AddItem(40, 40); print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.SetValue(i, 2); print(" " + i); } print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i); } list = AIList(); list.Sort(AIList.SORT_BY_VALUE, AIList.SORT_ASCENDING); print(""); print(" Value Ascending"); list.AddItem( 5, 10); list.AddItem(10, 10); list.AddItem(15, 20); list.AddItem(20, 20); list.AddItem(25, 30); list.AddItem(30, 30); list.AddItem(35, 40); list.AddItem(40, 40); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.RemoveItem(i + 10); list.RemoveItem(i + 5); list.RemoveItem(i); print(" " + i); } list.AddItem(10, 10); list.AddItem(20, 20); list.AddItem(30, 30); list.AddItem(40, 40); print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.SetValue(i, 50); print(" " + i); } print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i); } list = AIList(); list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_DESCENDING); print(""); print(" Item Descending"); list.AddItem( 5, 10); list.AddItem(10, 10); list.AddItem(15, 20); list.AddItem(20, 20); list.AddItem(25, 30); list.AddItem(30, 30); list.AddItem(35, 40); list.AddItem(40, 40); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.RemoveItem(i - 10); list.RemoveItem(i - 5); list.RemoveItem(i); print(" " + i); } list.AddItem(10, 10); list.AddItem(20, 20); list.AddItem(30, 30); list.AddItem(40, 40); print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.SetValue(i, 2); print(" " + i); } print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i); } list = AIList(); list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); print(""); print(" Item Ascending"); list.AddItem( 5, 10); list.AddItem(10, 10); list.AddItem(15, 20); list.AddItem(20, 20); list.AddItem(25, 30); list.AddItem(30, 30); list.AddItem(35, 40); list.AddItem(40, 40); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.RemoveItem(i + 10); list.RemoveItem(i + 5); list.RemoveItem(i); print(" " + i); } list.AddItem(10, 10); list.AddItem(20, 20); list.AddItem(30, 30); list.AddItem(40, 40); print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { list.SetValue(i, 50); print(" " + i); } print(""); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i); } list.Clear(); foreach (idx, val in list) { print(" " + idx); } print(" Ops: " + this.GetOpsTillSuspend()); } function Regression::Std() { print(""); print("--Std--"); print(" abs(-21): " + abs(-21)); print(" abs( 21): " + abs(21)); } function Regression::Base() { print(""); print("--AIBase--"); print(" Rand(): " + AIBase.Rand()); print(" Rand(): " + AIBase.Rand()); print(" Rand(): " + AIBase.Rand()); print(" RandRange(0): " + AIBase.RandRange(0)); print(" RandRange(0): " + AIBase.RandRange(0)); print(" RandRange(0): " + AIBase.RandRange(0)); print(" RandRange(1): " + AIBase.RandRange(1)); print(" RandRange(1): " + AIBase.RandRange(1)); print(" RandRange(1): " + AIBase.RandRange(1)); print(" RandRange(2): " + AIBase.RandRange(2)); print(" RandRange(2): " + AIBase.RandRange(2)); print(" RandRange(2): " + AIBase.RandRange(2)); print(" RandRange(1000000): " + AIBase.RandRange(1000000)); // 32 bit tests print(" RandRange(1000000): " + AIBase.RandRange(1000000)); print(" RandRange(1000000): " + AIBase.RandRange(1000000)); print(" Chance(1, 2): " + AIBase.Chance(1, 2)); print(" Chance(1, 2): " + AIBase.Chance(1, 2)); print(" Chance(1, 2): " + AIBase.Chance(1, 2)); AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_ROAD); } function Regression::Airport() { print(""); print("--AIAirport--"); print(" IsHangarTile(): " + AIAirport.IsHangarTile(32116)); print(" IsAirportTile(): " + AIAirport.IsAirportTile(32116)); print(" GetHangarOfAirport(): " + AIAirport.GetHangarOfAirport(32116)); print(" GetAirportType(): " + AIAirport.GetAirportType(32116)); for (local i = -1; i < 10; i++) { print(" IsAirportInformationAvailable(" + i + "): " + AIAirport.IsAirportInformationAvailable(i)); print(" IsValidAirportType(" + i + "): " + AIAirport.IsValidAirportType(i)); print(" GetAirportWidth(" + i + "): " + AIAirport.GetAirportWidth(i)); print(" GetAirportHeight(" + i + "): " + AIAirport.GetAirportHeight(i)); print(" GetAirportCoverageRadius(" + i + "): " + AIAirport.GetAirportCoverageRadius(i)); } print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" GetPrice(): " + AIAirport.GetPrice(0)); print(" BuildAirport(): " + AIAirport.BuildAirport(32116, 0, AIStation.STATION_JOIN_ADJACENT)); print(" IsHangarTile(): " + AIAirport.IsHangarTile(32116)); print(" IsAirportTile(): " + AIAirport.IsAirportTile(32116)); print(" GetAirportType(): " + AIAirport.GetAirportType(32119)); print(" GetHangarOfAirport(): " + AIAirport.GetHangarOfAirport(32116)); print(" IsHangarTile(): " + AIAirport.IsHangarTile(32119)); print(" IsAirportTile(): " + AIAirport.IsAirportTile(32119)); print(" GetAirportType(): " + AIAirport.GetAirportType(32119)); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" RemoveAirport(): " + AIAirport.RemoveAirport(32118)); print(" IsHangarTile(): " + AIAirport.IsHangarTile(32119)); print(" IsAirportTile(): " + AIAirport.IsAirportTile(32119)); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" BuildAirport(): " + AIAirport.BuildAirport(32116, 0, AIStation.STATION_JOIN_ADJACENT)); } function Regression::Bridge() { local j = 0; print(""); print("--Bridge--"); for (local i = -1; i < 14; i++) { if (AIBridge.IsValidBridge(i)) j++; print(" Bridge " + i); print(" IsValidBridge(): " + AIBridge.IsValidBridge(i)); print(" GetName(): " + AIBridge.GetName(i)); print(" GetMaxSpeed(): " + AIBridge.GetMaxSpeed(i)); print(" GetPrice(): " + AIBridge.GetPrice(i, 5)); print(" GetMaxLength(): " + AIBridge.GetMaxLength(i)); print(" GetMinLength(): " + AIBridge.GetMinLength(i)); } print(" Valid Bridges: " + j); print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); print(" GetBridgeID(): " + AIBridge.GetBridgeID(33160)); print(" RemoveBridge(): " + AIBridge.RemoveBridge(33155)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" GetOtherBridgeEnd(): " + AIBridge.GetOtherBridgeEnd(33160)); print(" BuildBridge(): " + AIBridge.BuildBridge(AIVehicle.VT_ROAD, 5, 33160, 33155)); print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); print(" GetBridgeID(): " + AIBridge.GetBridgeID(33160)); print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33155)); print(" GetBridgeID(): " + AIBridge.GetBridgeID(33155)); print(" GetOtherBridgeEnd(): " + AIBridge.GetOtherBridgeEnd(33160)); print(" BuildBridge(): " + AIBridge.BuildBridge(AIVehicle.VT_ROAD, 5, 33160, 33155)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" RemoveBridge(): " + AIBridge.RemoveBridge(33155)); print(" IsBridgeTile(): " + AIBridge.IsBridgeTile(33160)); } function Regression::BridgeList() { local list = AIBridgeList(); print(""); print("--BridgeList--"); print(" Count(): " + list.Count()); list.Valuate(AIBridge.GetMaxSpeed); print(" MaxSpeed ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIBridge.GetPrice, 5); print(" Price ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIBridge.GetMaxLength); print(" MaxLength ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIBridge.GetMinLength); print(" MinLength ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list = AIBridgeList_Length(14); print(""); print("--BridgeList_Length--"); print(" Count(): " + list.Count()); list.Valuate(AIBridge.GetMaxSpeed); print(" MaxSpeed ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIBridge.GetPrice, 14); print(" Price ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } function Regression::Cargo() { print(""); print("--AICargo--"); for (local i = -1; i < 15; i++) { print(" Cargo " + i); print(" IsValidCargo(): " + AICargo.IsValidCargo(i)); print(" GetCargoLabel(): '" + AICargo.GetCargoLabel(i)+ "'"); print(" IsFreight(): " + AICargo.IsFreight(i)); print(" HasCargoClass(): " + AICargo.HasCargoClass(i, AICargo.CC_PASSENGERS)); print(" GetTownEffect(): " + AICargo.GetTownEffect(i)); print(" GetCargoIncome(0, 0): " + AICargo.GetCargoIncome(i, 0, 0)); print(" GetCargoIncome(10, 10): " + AICargo.GetCargoIncome(i, 10, 10)); print(" GetCargoIncome(100, 10): " + AICargo.GetCargoIncome(i, 100, 10)); print(" GetCargoIncome(10, 100): " + AICargo.GetCargoIncome(i, 10, 100)); print(" GetRoadVehicleTypeForCargo(): " + AIRoad.GetRoadVehicleTypeForCargo(i)); } } function Regression::CargoList() { local list = AICargoList(); print(""); print("--CargoList--"); print(" Count(): " + list.Count()); list.Valuate(AICargo.IsFreight); print(" IsFreight ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AICargo.GetCargoIncome, 100, 100); print(" CargoIncomes(100, 100) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list = AICargoList_IndustryAccepting(8); print(""); print("--CargoList_IndustryAccepting--"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i); } list = AICargoList_IndustryProducing(4); print(""); print("--CargoList_IndustryProducing--"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i); } } function Regression::Company() { print(""); print("--Company--"); /* Test AIXXXMode() in scopes */ { local test = AITestMode(); print(" SetName(): " + AICompany.SetName("Regression")); print(" SetName(): " + AICompany.SetName("Regression")); { local exec = AIExecMode(); print(" SetName(): " + AICompany.SetName("Regression")); print(" SetName(): " + AICompany.SetName("Regression")); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); } } print(" GetName(): " + AICompany.GetName(AICompany.COMPANY_SELF)); print(" GetPresidentName(): " + AICompany.GetPresidentName(AICompany.COMPANY_SELF)); print(" SetPresidentName(): " + AICompany.SetPresidentName("Regression AI")); print(" GetPresidentName(): " + AICompany.GetPresidentName(AICompany.COMPANY_SELF)); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" GetName(): " + AICompany.GetName(240)); print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); print(" GetMaxLoanAmount(): " + AICompany.GetMaxLoanAmount()); print(" GetLoanInterval(): " + AICompany.GetLoanInterval()); print(" SetLoanAmount(1): " + AICompany.SetLoanAmount(1)); print(" SetLoanAmount(100): " + AICompany.SetLoanAmount(100)); print(" SetLoanAmount(10000): " + AICompany.SetLoanAmount(10000)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); print(" SetMinimumLoanAmount(31337): " + AICompany.SetMinimumLoanAmount(31337)); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); print(" SetLoanAmount(10000): " + AICompany.SetLoanAmount(AICompany.GetMaxLoanAmount())); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" GetLoanAmount(): " + AICompany.GetLoanAmount()); print(" GetCompanyHQ(): " + AICompany.GetCompanyHQ(AICompany.COMPANY_SELF)); print(" BuildCompanyHQ(): " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(127, 129))); print(" GetCompanyHQ(): " + AICompany.GetCompanyHQ(AICompany.COMPANY_SELF)); print(" BuildCompanyHQ(): " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(129, 129))); print(" GetCompanyHQ(): " + AICompany.GetCompanyHQ(AICompany.COMPANY_SELF)); print(" BuildCompanyHQ(): " + AICompany.BuildCompanyHQ(AIMap.GetTileIndex(129, 128))); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" GetAutoRenewStatus(); " + AICompany.GetAutoRenewStatus(AICompany.COMPANY_SELF)); print(" SetAutoRenewStatus(true); " + AICompany.SetAutoRenewStatus(true)); print(" GetAutoRenewStatus(); " + AICompany.GetAutoRenewStatus(AICompany.COMPANY_SELF)); print(" SetAutoRenewStatus(true); " + AICompany.SetAutoRenewStatus(true)); print(" SetAutoRenewStatus(false); " + AICompany.SetAutoRenewStatus(false)); print(" GetAutoRenewMonths(); " + AICompany.GetAutoRenewMonths(AICompany.COMPANY_SELF)); print(" SetAutoRenewMonths(-12); " + AICompany.SetAutoRenewMonths(-12)); print(" GetAutoRenewMonths(); " + AICompany.GetAutoRenewMonths(AICompany.COMPANY_SELF)); print(" SetAutoRenewMonths(-12); " + AICompany.SetAutoRenewMonths(-12)); print(" SetAutoRenewMonths(6); " + AICompany.SetAutoRenewMonths(6)); print(" GetAutoRenewMoney(); " + AICompany.GetAutoRenewMoney(AICompany.COMPANY_SELF)); print(" SetAutoRenewMoney(200000); " + AICompany.SetAutoRenewMoney(200000)); print(" GetAutoRenewMoney(); " + AICompany.GetAutoRenewMoney(AICompany.COMPANY_SELF)); print(" SetAutoRenewMoney(200000); " + AICompany.SetAutoRenewMoney(200000)); print(" SetAutoRenewMoney(100000); " + AICompany.SetAutoRenewMoney(100000)); for (local i = -1; i <= AICompany.EARLIEST_QUARTER; i++) { print(" Quarter: " + i); print(" GetQuarterlyIncome(); " + AICompany.GetQuarterlyIncome(AICompany.COMPANY_SELF, i)); print(" GetQuarterlyExpenses(); " + AICompany.GetQuarterlyExpenses(AICompany.COMPANY_SELF, i)); print(" GetQuarterlyCargoDelivered(); " + AICompany.GetQuarterlyCargoDelivered(AICompany.COMPANY_SELF, i)); print(" GetQuarterlyPerformanceRating(); " + AICompany.GetQuarterlyPerformanceRating(AICompany.COMPANY_SELF, i)); print(" GetQuarterlyCompanyValue(); " + AICompany.GetQuarterlyCompanyValue(AICompany.COMPANY_SELF, i)); } } function Regression::Engine() { local j = 0; print(""); print("--Engine--"); for (local i = -1; i < 257; i++) { if (AIEngine.IsValidEngine(i)) j++; print(" Engine " + i); print(" IsValidEngine(): " + AIEngine.IsValidEngine(i)); print(" GetName(): " + AIEngine.GetName(i)); print(" GetCargoType(): " + AIEngine.GetCargoType(i)); print(" CanRefitCargo(): " + AIEngine.CanRefitCargo(i, 1)); print(" GetCapacity(): " + AIEngine.GetCapacity(i)); print(" GetReliability(): " + AIEngine.GetReliability(i)); print(" GetMaxSpeed(): " + AIEngine.GetMaxSpeed(i)); print(" GetPrice(): " + AIEngine.GetPrice(i)); print(" GetMaxAge(): " + AIEngine.GetMaxAge(i)); print(" GetRunningCost(): " + AIEngine.GetRunningCost(i)); print(" GetPower(): " + AIEngine.GetPower(i)); print(" GetWeight(): " + AIEngine.GetWeight(i)); print(" GetMaxTractiveEffort(): " + AIEngine.GetMaxTractiveEffort(i)); print(" GetVehicleType(): " + AIEngine.GetVehicleType(i)); print(" GetRailType(): " + AIEngine.GetRailType(i)); print(" GetRoadType(): " + AIEngine.GetRoadType(i)); print(" GetPlaneType(): " + AIEngine.GetPlaneType(i)); } print(" Valid Engines: " + j); } function Regression::EngineList() { local list = AIEngineList(AIVehicle.VT_ROAD); print(""); print("--EngineList--"); print(" Count(): " + list.Count()); list.Valuate(AIEngine.GetCargoType); print(" CargoType ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIEngine.GetCapacity); print(" Capacity ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIEngine.GetReliability); print(" Reliability ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIEngine.GetMaxSpeed); print(" MaxSpeed ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIEngine.GetPrice); print(" Price ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } function Regression::Prices() { print(""); print("--Prices--"); print(" -Rail-"); print(" 0,BT_TRACK: " + AIRail.GetBuildCost(0, AIRail.BT_TRACK)); print(" 0,BT_SIGNAL: " + AIRail.GetBuildCost(0, AIRail.BT_SIGNAL)); print(" 0,BT_DEPOT: " + AIRail.GetBuildCost(0, AIRail.BT_DEPOT)); print(" 0,BT_STATION: " + AIRail.GetBuildCost(0, AIRail.BT_STATION)); print(" 0,BT_WAYPOINT: " + AIRail.GetBuildCost(0, AIRail.BT_WAYPOINT)); print(" 1,BT_TRACK: " + AIRail.GetBuildCost(1, AIRail.BT_TRACK)); print(" 1,BT_SIGNAL: " + AIRail.GetBuildCost(1, AIRail.BT_SIGNAL)); print(" 1,BT_DEPOT: " + AIRail.GetBuildCost(1, AIRail.BT_DEPOT)); print(" 1,BT_STATION: " + AIRail.GetBuildCost(1, AIRail.BT_STATION)); print(" 1,BT_WAYPOINT: " + AIRail.GetBuildCost(1, AIRail.BT_WAYPOINT)); print(" -Road-"); print(" ROADTYPE_ROAD,BT_ROAD: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_ROAD)); print(" ROADTYPE_ROAD,BT_DEPOT: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_DEPOT)); print(" ROADTYPE_ROAD,BT_BUS_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_BUS_STOP)); print(" ROADTYPE_ROAD,BT_TRUCK_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_ROAD, AIRoad.BT_TRUCK_STOP)); print(" ROADTYPE_TRAM,BT_ROAD: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_ROAD)); print(" ROADTYPE_TRAM,BT_DEPOT: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_DEPOT)); print(" ROADTYPE_TRAM,BT_BUS_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_BUS_STOP)); print(" ROADTYPE_TRAM,BT_TRUCK_STOP: " + AIRoad.GetBuildCost(AIRoad.ROADTYPE_TRAM, AIRoad.BT_TRUCK_STOP)); print(" -Water-"); print(" BT_DOCK: " + AIMarine.GetBuildCost(AIMarine.BT_DOCK)); print(" BT_DEPOT: " + AIMarine.GetBuildCost(AIMarine.BT_DEPOT)); print(" BT_BUOY: " + AIMarine.GetBuildCost(AIMarine.BT_BUOY)); print(" -Tile-"); print(" BT_FOUNDATION: " + AITile.GetBuildCost(AITile.BT_FOUNDATION)); print(" BT_TERRAFORM: " + AITile.GetBuildCost(AITile.BT_TERRAFORM)); print(" BT_BUILD_TREES: " + AITile.GetBuildCost(AITile.BT_BUILD_TREES)); print(" BT_CLEAR_GRASS: " + AITile.GetBuildCost(AITile.BT_CLEAR_GRASS)); print(" BT_CLEAR_ROUGH: " + AITile.GetBuildCost(AITile.BT_CLEAR_ROUGH)); print(" BT_CLEAR_ROCKY: " + AITile.GetBuildCost(AITile.BT_CLEAR_ROCKY)); print(" BT_CLEAR_FIELDS: " + AITile.GetBuildCost(AITile.BT_CLEAR_FIELDS)); print(" BT_CLEAR_HOUSE: " + AITile.GetBuildCost(AITile.BT_CLEAR_HOUSE)); } function cost_callback(old_path, new_tile, new_direction, self) { if (old_path == null) return 0; return old_path.GetCost() + 1; } function estimate_callback(tile, direction, goals, self) { return goals[0] - tile; } function neighbours_callback(path, cur_tile, self) { return [[cur_tile + 1, 1]]; } function check_direction_callback(tile, existing_direction, new_direction, self) { return false; } function Regression::Group() { print (""); print("--Group--"); print(" SetAutoReplace(): " + AIGroup.SetAutoReplace(AIGroup.GROUP_ALL, 116, 117)); print(" GetEngineReplacement(): " + AIGroup.GetEngineReplacement(AIGroup.GROUP_ALL, 116)); print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_ALL, 116)); print(" AIRoad.BuildRoadDepot(): " + AIRoad.BuildRoadDepot(10000, 10001)); local vehicle = AIVehicle.BuildVehicle(10000, 116); print(" AIVehicle.BuildVehicle(): " + vehicle); print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_ALL, 116)); local group = AIGroup.CreateGroup(AIVehicle.VT_ROAD); print(" CreateGroup(): " + group); print(" MoveVehicle(): " + AIGroup.MoveVehicle(group, vehicle)); print(" GetNumEngines(): " + AIGroup.GetNumEngines(group, 116)); print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_ALL, 116)); print(" GetNumEngines(): " + AIGroup.GetNumEngines(AIGroup.GROUP_DEFAULT, 116)); print(" GetName(): " + AIGroup.GetName(0)); print(" GetName(): " + AIGroup.GetName(1)); print(" AIVehicle.SellVehicle(): " + AIVehicle.SellVehicle(vehicle)); print(" AITile.DemolishTile(): " + AITile.DemolishTile(10000)); print(" HasWagonRemoval(): " + AIGroup.HasWagonRemoval()); print(" EnableWagonRemoval(): " + AIGroup.EnableWagonRemoval(true)); print(" HasWagonRemoval(): " + AIGroup.HasWagonRemoval()); print(" EnableWagonRemoval(): " + AIGroup.EnableWagonRemoval(false)); print(" EnableWagonRemoval(): " + AIGroup.EnableWagonRemoval(false)); print(" HasWagonRemoval(): " + AIGroup.HasWagonRemoval()); } function Regression::Industry() { local j = 0; print(""); print("--Industry--"); print(" GetIndustryCount(): " + AIIndustry.GetIndustryCount()); local list = AIIndustryList(); list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { if (AIIndustry.IsValidIndustry(i)) j++; print(" Industry " + i); print(" IsValidIndustry(): " + AIIndustry.IsValidIndustry(i)); print(" GetName(): " + AIIndustry.GetName(i)); print(" GetLocation(): " + AIIndustry.GetLocation(i)); print(" IsCargoAccepted(): " + AIIndustry.IsCargoAccepted(i, 1)); local cargo_list = AICargoList(); for (local j = cargo_list.Begin(); !cargo_list.IsEnd(); j = cargo_list.Next()) { if (AIIndustry.IsCargoAccepted(i, j) || AIIndustry.GetLastMonthProduction(i,j) >= 0) { print(" GetLastMonthProduction(): " + AIIndustry.GetLastMonthProduction(i, j)); print(" GetLastMonthTransported(): " + AIIndustry.GetLastMonthTransported(i, j)); print(" GetStockpiledCargo(): " + AIIndustry.GetStockpiledCargo(i, j)); } } } print(" Valid Industries: " + j); print(" GetIndustryCount(): " + AIIndustry.GetIndustryCount()); print(" GetIndustryID(): " + AIIndustry.GetIndustryID(19694)); print(" GetIndustryID(): " + AIIndustry.GetIndustryID(19695)); } function Regression::IndustryList() { local list = AIIndustryList(); print(""); print("--IndustryList--"); print(" Count(): " + list.Count()); list.Valuate(AIIndustry.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIIndustry.GetDistanceManhattanToTile, 30000); print(" DistanceManhattanToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIIndustry.GetDistanceSquareToTile, 30000); print(" DistanceSquareToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIIndustry.GetAmountOfStationsAround); print(" GetAmountOfStationsAround(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIIndustry.IsCargoAccepted, 1); print(" CargoAccepted(1) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list = AIIndustryList_CargoAccepting(1); print("--IndustryList_CargoAccepting--"); print(" Count(): " + list.Count()); list.Valuate(AIIndustry.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list = AIIndustryList_CargoProducing(1); print("--IndustryList_CargoProducing--"); print(" Count(): " + list.Count()); list.Valuate(AIIndustry.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } function Regression::IndustryTypeList() { local list = AIIndustryTypeList(); print(""); print("--IndustryTypeList--"); print(" Count(): " + list.Count()); list.Valuate(AIIndustry.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" Id: " + i); print(" IsRawIndustry(): " + AIIndustryType.IsRawIndustry(i)); print(" ProductionCanIncrease(): " + AIIndustryType.ProductionCanIncrease(i)); print(" GetConstructionCost(): " + AIIndustryType.GetConstructionCost(i)); print(" GetName(): " + AIIndustryType.GetName(i)); print(" CanBuildIndustry(): " + AIIndustryType.CanBuildIndustry(i)); print(" CanProspectIndustry(): " + AIIndustryType.CanProspectIndustry(i)); print(" IsBuiltOnWater(): " + AIIndustryType.IsBuiltOnWater(i)); print(" HasHeliport(): " + AIIndustryType.HasHeliport(i)); print(" HasDock(): " + AIIndustryType.HasDock(i)); } } function CustomValuator(list_id) { return list_id * 4343; } function Regression::List() { local list = AIList(); print(""); print("--List--"); print(" IsEmpty(): " + list.IsEmpty()); list.AddItem(1, 1); list.AddItem(2, 2); for (local i = 1000; i < 1100; i++) { list.AddItem(i, i); } list.RemoveItem(1050); list.RemoveItem(1150); list.SetValue(1051, 12); print(" Count(): " + list.Count()); print(" HasItem(1050): " + list.HasItem(1050)); print(" HasItem(1051): " + list.HasItem(1051)); print(" IsEmpty(): " + list.IsEmpty()); list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); print(" List Dump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(CustomValuator); print(" Custom ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(function (a) { return a * 42; }); print(" Custom ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIBase.RandItem); print(" Randomize ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.KeepTop(10); print(" KeepTop(10):"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.KeepBottom(8); print(" KeepBottom(8):"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.RemoveBottom(2); print(" RemoveBottom(2):"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.RemoveTop(2); print(" RemoveTop(2):"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } local list2 = AIList(); list2.AddItem(1003, 0); list2.AddItem(1004, 0); list.RemoveList(list2); print(" RemoveList({1003, 1004}):"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list2.AddItem(1005, 0); list.KeepList(list2); print(" KeepList({1003, 1004, 1005}):"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list2.Clear(); for (local i = 4000; i < 4003; i++) { list2.AddItem(i, i * 2); } list2.AddItem(1005, 1005); list.AddList(list2); print(" AddList({1005, 4000, 4001, 4002}):"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list[4000] = 50; list[4006] = 12; print(" foreach():"); foreach (idx, val in list) { print(" " + idx + " => " + val); } print(" []:"); print(" 4000 => " + list[4000]); list.Clear(); print(" IsEmpty(): " + list.IsEmpty()); for (local i = 0; i < 10; i++) { list.AddItem(i, 5 + i / 2); } local it = list.Begin(); print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); list.Sort(list.SORT_BY_VALUE, list.SORT_ASCENDING); it = list.Next(); print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); it = list.Begin(); print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); list.SetValue(it + 1, -5); it = list.Next(); print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); list.RemoveValue(list.GetValue(it) + 1); it = list.Next(); print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); list.RemoveAboveValue(list.GetValue(it)); it = list.Next(); print(" " + it + " => " + list.GetValue(it) + " (" + !list.IsEnd() + ")"); while (!list.IsEnd()) { it = list.Next(); print(" " + it + " => " + list.GetValue(it)); } } function Regression::Map() { print(""); print("--Map--"); print(" GetMapSize(): " + AIMap.GetMapSize()); print(" GetMapSizeX(): " + AIMap.GetMapSizeX()); print(" GetMapSizeY(): " + AIMap.GetMapSizeY()); print(" GetTileX(123): " + AIMap.GetTileX(123)); print(" GetTileY(123): " + AIMap.GetTileY(123)); print(" GetTileIndex(): " + AIMap.GetTileIndex(123, 0)); print(" GetTileIndex(): " + AIMap.GetTileIndex(0, 123)); print(" GetTileIndex(): " + AIMap.GetTileIndex(0, 0)); print(" GetTileIndex(): " + AIMap.GetTileIndex(-1, -1)); print(" GetTileIndex(): " + AIMap.GetTileIndex(10000, 10000)); print(" IsValidTile(123): " + AIMap.IsValidTile(123)); print(" GetTileX(124): " + AIMap.GetTileX(124)); print(" GetTileY(124): " + AIMap.GetTileY(124)); print(" IsValidTile(124): " + AIMap.IsValidTile(124)); print(" IsValidTile(0): " + AIMap.IsValidTile(0)); print(" IsValidTile(-1): " + AIMap.IsValidTile(-1)); print(" IsValidTile(): " + AIMap.IsValidTile(AIMap.GetMapSize())); print(" IsValidTile(): " + AIMap.IsValidTile(AIMap.GetMapSize() - AIMap.GetMapSizeX() - 2)); print(" DemolishTile(): " + AITile.DemolishTile(19592)); print(" DemolishTile(): " + AITile.DemolishTile(19335)); print(" Distance"); print(" DistanceManhattan(): " + AIMap.DistanceManhattan(1, 10000)); print(" DistanceMax(): " + AIMap.DistanceMax(1, 10000)); print(" DistanceSquare(): " + AIMap.DistanceSquare(1, 10000)); print(" DistanceFromEdge(): " + AIMap.DistanceFromEdge(10000)); } function Regression::Marine() { print(""); print("--AIMarine--"); print(" IsWaterDepotTile(): " + AIMarine.IsWaterDepotTile(32116)); print(" IsDockTile(): " + AIMarine.IsDockTile(32116)); print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(32116)); print(" IsLockTile(): " + AIMarine.IsLockTile(32116)); print(" IsCanalTile(): " + AIMarine.IsCanalTile(32116)); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" BuildWaterDepot(): " + AIMarine.BuildWaterDepot(28479, 28478)); print(" BuildDock(): " + AIMarine.BuildDock(29253, AIStation.STATION_JOIN_ADJACENT)); print(" BuildBuoy(): " + AIMarine.BuildBuoy(28481)); print(" BuildLock(): " + AIMarine.BuildLock(28487)); print(" HasTransportType(): " + AITile.HasTransportType(32127, AITile.TRANSPORT_WATER)); print(" BuildCanal(): " + AIMarine.BuildCanal(32127)); print(" HasTransportType(): " + AITile.HasTransportType(32127, AITile.TRANSPORT_WATER)); print(" IsWaterDepotTile(): " + AIMarine.IsWaterDepotTile(28479)); print(" IsDockTile(): " + AIMarine.IsDockTile(29253)); print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(28481)); print(" IsLockTile(): " + AIMarine.IsLockTile(28487)); print(" IsCanalTile(): " + AIMarine.IsCanalTile(32127)); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); local list = AIWaypointList(AIWaypoint.WAYPOINT_BUOY); print(""); print("--AIWaypointList(BUOY)--"); print(" Count(): " + list.Count()); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + AIWaypoint.GetLocation(i)); } print(" HasWaypointType:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + AIWaypoint.HasWaypointType(i, AIWaypoint.WAYPOINT_RAIL) + " " + AIWaypoint.HasWaypointType(i, AIWaypoint.WAYPOINT_BUOY) + " " + AIWaypoint.HasWaypointType(i, AIWaypoint.WAYPOINT_ANY)); } print(""); print(" RemoveWaterDepot(): " + AIMarine.RemoveWaterDepot(28479)); print(" RemoveDock(): " + AIMarine.RemoveDock(29253)); print(" RemoveBuoy(): " + AIMarine.RemoveBuoy(28481)); print(" RemoveLock(): " + AIMarine.RemoveLock(28487)); print(" RemoveCanal(): " + AIMarine.RemoveCanal(32127)); print(" IsWaterDepotTile(): " + AIMarine.IsWaterDepotTile(28479)); print(" IsDockTile(): " + AIMarine.IsDockTile(29253)); print(" IsBuoyTile(): " + AIMarine.IsBuoyTile(28481)); print(" IsLockTile(): " + AIMarine.IsLockTile(28487)); print(" IsCanalTile(): " + AIMarine.IsCanalTile(32127)); print(" GetBankBalance(): " + AICompany.GetBankBalance(AICompany.COMPANY_SELF)); print(" BuildWaterDepot(): " + AIMarine.BuildWaterDepot(28479, 28480)); print(" BuildDock(): " + AIMarine.BuildDock(29253, AIStation.STATION_JOIN_ADJACENT)); } function Regression::Order() { print(""); print("--Order--"); print(" GetOrderCount(): " + AIOrder.GetOrderCount(12)); print(" GetOrderDestination(): " + AIOrder.GetOrderDestination(12, 1)); print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER)); print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER | AIOrder.OF_UNLOAD)); print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33416, AIOrder.OF_TRANSFER | AIOrder.OF_FULL_LOAD)); print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33417, AIOrder.OF_SERVICE_IF_NEEDED)); print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(33417, AIOrder.OF_STOP_IN_DEPOT)); print(" AreOrderFlagsValid(): " + AIOrder.AreOrderFlagsValid(0, AIOrder.OF_SERVICE_IF_NEEDED | AIOrder.OF_GOTO_NEAREST_DEPOT)); print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_LOAD_PERCENTAGE, AIOrder.CF_EQUALS)); print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_RELIABILITY, AIOrder.CF_IS_TRUE)); print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_REQUIRES_SERVICE, AIOrder.CF_IS_FALSE)); print(" IsValidConditionalOrder(): " + AIOrder.IsValidConditionalOrder(AIOrder.OC_AGE, AIOrder.CF_INVALID)); print(" IsValidVehicleOrder(): " + AIOrder.IsValidVehicleOrder(12, 1)); print(" IsGotoStationOrder(): " + AIOrder.IsGotoStationOrder(12, 1)); print(" IsGotoDepotOrder(): " + AIOrder.IsGotoDepotOrder(12, 1)); print(" IsGotoWaypointOrder(): " + AIOrder.IsGotoWaypointOrder(12, 1)); print(" IsConditionalOrder(): " + AIOrder.IsConditionalOrder(12, 1)); print(" IsCurrentOrderPartOfOrderList(): " + AIOrder.IsCurrentOrderPartOfOrderList(12)); print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 1)); print(" AppendOrder(): " + AIOrder.AppendOrder(12, 33416, AIOrder.OF_TRANSFER)); print(" InsertOrder(): " + AIOrder.InsertOrder(12, 0, 33416, AIOrder.OF_TRANSFER)); print(" GetOrderCount(): " + AIOrder.GetOrderCount(12)); print(" IsValidVehicleOrder(): " + AIOrder.IsValidVehicleOrder(12, 1)); print(" IsGotoStationOrder(): " + AIOrder.IsGotoStationOrder(12, 1)); print(" IsGotoDepotOrder(): " + AIOrder.IsGotoDepotOrder(12, 1)); print(" IsGotoWaypointOrder(): " + AIOrder.IsGotoWaypointOrder(12, 1)); print(" IsConditionalOrder(): " + AIOrder.IsConditionalOrder(12, 1)); print(" IsCurrentOrderPartOfOrderList(): " + AIOrder.IsCurrentOrderPartOfOrderList(12)); print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 0)); print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 1)); print(" GetOrderJumpTo(): " + AIOrder.GetOrderJumpTo(12, 1)); print(" RemoveOrder(): " + AIOrder.RemoveOrder(12, 0)); print(" SetOrderFlags(): " + AIOrder.SetOrderFlags(12, 0, AIOrder.OF_FULL_LOAD)); print(" GetOrderFlags(): " + AIOrder.GetOrderFlags(12, 0)); print(" GetOrderDestination(): " + AIOrder.GetOrderDestination(12, 0)); print(" CopyOrders(): " + AIOrder.CopyOrders(12, 1)); print(" CopyOrders(): " + AIOrder.CopyOrders(13, 12)); print(" ShareOrders(): " + AIOrder.ShareOrders(13, 1)); print(" ShareOrders(): " + AIOrder.ShareOrders(13, 12)); print(" UnshareOrders(): " + AIOrder.UnshareOrders(13)); print(" AppendOrder(): " + AIOrder.AppendOrder(12, 33421, AIOrder.OF_NONE)); print(" GetStopLocation(): " + AIOrder.GetStopLocation(13, 0)); print(" BuildVehicle(): " + AIVehicle.BuildVehicle(23596, 8)); print(" BuildRailStation(): " + AIRail.BuildRailStation(7958, AIRail.RAILTRACK_NE_SW, 1, 1, AIStation.STATION_NEW)); print(" AppendOrder(): " + AIOrder.AppendOrder(20, 7958, AIOrder.OF_NONE)); print(" GetOrderCount(): " + AIOrder.GetOrderCount(20)); print(" GetStopLocation(): " + AIOrder.GetStopLocation(20, 0)); print(" SetStopLocation(): " + AIOrder.SetStopLocation(20, 0, AIOrder.STOPLOCATION_MIDDLE)); print(" GetStopLocation(): " + AIOrder.GetStopLocation(20, 0)); local list = AIVehicleList_Station(3); print(""); print("--VehicleList_Station--"); print(" Count(): " + list.Count()); list.Valuate(AIVehicle.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } print(" foreach():"); foreach (idx, val in list) { print(" " + idx + " => " + val); } } function Regression::RailTypeList() { local list = AIRailTypeList(); print(""); print("--RailTypeList--"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" RailType: " + i); print(" GetName(): " + AIRail.GetName(i)); print(" IsRailTypeAvailable(): " + AIRail.IsRailTypeAvailable(i)); print(" GetMaxSpeed(): " + AIRail.GetMaxSpeed(i)); } } function Regression::Rail() { AIRail.SetCurrentRailType(0); print(""); print("--Rail--"); print(" IsRailTile(): " + AIRail.IsRailTile(10002)); print(" BuildRailTrack(): " + AIRail.BuildRailTrack(10002, AIRail.RAILTRACK_NW_SE)); print(" BuildSignal(): " + AIRail.BuildSignal(10002, 10258, AIRail.SIGNALTYPE_PBS)); print(" RemoveRailTrack(): " + AIRail.RemoveRailTrack(10002, AIRail.RAILTRACK_NW_NE)); print(" RemoveRailTrack(): " + AIRail.RemoveRailTrack(10002, AIRail.RAILTRACK_NW_SE)); print(" BuildRail(): " + AIRail.BuildRail(10002, 10003, 10006)); print(" HasTransportType(): " + AITile.HasTransportType(10005, AITile.TRANSPORT_RAIL)); print(" HasTransportType(): " + AITile.HasTransportType(10006, AITile.TRANSPORT_RAIL)); print(" RemoveRail(): " + AIRail.RemoveRail(10005, 10004, 10001)); print(" Depot"); print(" IsRailTile(): " + AIRail.IsRailTile(33411)); print(" BuildRailDepot(): " + AIRail.BuildRailDepot(0, 1)); print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33411)); print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33414)); print(" BuildRailDepot(): " + AIRail.BuildRailDepot(33411, 33412)); print(" GetRailDepotFrontTile(): " + AIRail.GetRailDepotFrontTile(33411)); print(" IsBuildable(): " + AITile.IsBuildable(33411)); local list = AIDepotList(AITile.TRANSPORT_RAIL); print(" DepotList"); print(" Count(): " + list.Count()); list.Valuate(AITile.GetDistanceManhattanToTile, 0); print(" Depot distance from (0,0) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } print(" RemoveDepot(): " + AITile.DemolishTile(33411)); print(" BuildRailDepot(): " + AIRail.BuildRailDepot(23596, 23597)); print(" Station"); print(" BuildRailStation(): " + AIRail.BuildRailStation(0, AIRail.RAILTRACK_NE_SW, 1, 1, AIStation.STATION_NEW)); print(" BuildRailStation(): " + AIRail.BuildRailStation(7958, AIRail.RAILTRACK_NE_SW, 4, 5, AIStation.STATION_NEW)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7957)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7958)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7959)); print(" RemoveRailStationTileRectangle():" + AIRail.RemoveRailStationTileRectangle(7959, 7959, false)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7957)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7958)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7959)); print(" DemolishTile(): " + AITile.DemolishTile(7960)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7957)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7958)); print(" IsRailStationTile(): " + AIRail.IsRailStationTile(7959)); } function Regression::Road() { print(""); print("--Road--"); print(" Road"); print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); print(" BuildRoad(): " + AIRoad.BuildRoad(0, 1)); print(" BuildRoad(): " + AIRoad.BuildRoad(33411, 33411)); print(" HasTransportType(): " + AITile.HasTransportType(33413, AITile.TRANSPORT_ROAD)); print(" BuildRoad(): " + AIRoad.BuildRoad(33411, 33414)); print(" HasTransportType(): " + AITile.HasTransportType(33413, AITile.TRANSPORT_ROAD)); print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); print(" HasRoadType(Road): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); print(" HasRoadType(Tram): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); print(" GetNeighbourRoadCount(): " + AIRoad.GetNeighbourRoadCount(33412)); print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33411)); print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33412)); print(" RemoveRoad(): " + AIRoad.RemoveRoad(19590, 19590)); print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33414)); print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33411, 33414)); print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33413, 33412)); print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33413, 33412)); print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33413, 33412)); print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33412, 33413)); print(" BuildOneWayRoad(): " + AIRoad.BuildOneWayRoad(33413, 33412)); print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33412, 33413)); print(" AreRoadTilesConnected(): " + AIRoad.AreRoadTilesConnected(33413, 33412)); print(" RemoveRoad(): " + AIRoad.RemoveRoad(33411, 33412)); print(" IsRoadTypeAvailable(Road): " + AIRoad.IsRoadTypeAvailable(AIRoad.ROADTYPE_ROAD)); print(" IsRoadTypeAvailable(Tram): " + AIRoad.IsRoadTypeAvailable(AIRoad.ROADTYPE_TRAM)); print(" SetCurrentRoadType(Tram): " + AIRoad.SetCurrentRoadType(AIRoad.ROADTYPE_TRAM)); print(" GetCurrentRoadType(): " + AIRoad.GetCurrentRoadType()); print(" Depot"); print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(0, 1)); print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33411, 33411)); print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33411, 33414)); print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33411, 33412)); print(" HasRoadType(Road): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); print(" HasRoadType(Tram): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); print(" GetLastError(): " + AIError.GetLastError()); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" GetErrorCategory(): " + AIError.GetErrorCategory()); print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); print(" GetRoadDepotFrontTile(): " + AIRoad.GetRoadDepotFrontTile(33411)); print(" IsRoadDepotTile(): " + AIRoad.IsRoadDepotTile(33411)); print(" IsBuildable(): " + AITile.IsBuildable(33411)); local list = AIDepotList(AITile.TRANSPORT_ROAD); print(" DepotList"); print(" Count(): " + list.Count()); list.Valuate(AITile.GetDistanceManhattanToTile, 0); print(" Depot distance from (0,0) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } print(" RemoveRoadDepot(): " + AIRoad.RemoveRoadDepot(33411)); print(" RemoveRoadDepot(): " + AIRoad.RemoveRoadDepot(33411)); print(" Station"); print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(0, 1, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(33411, 33411, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(33411, 33414, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadStation(): " + AIRoad.BuildRoadStation(33411, 33412, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" IsStationTile(): " + AITile.IsStationTile(33411)); print(" IsStationTile(): " + AITile.IsStationTile(33412)); print(" HasRoadType(Road): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); print(" HasRoadType(Tram): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); print(" IsRoadTile(): " + AIRoad.IsRoadTile(33411)); print(" GetDriveThroughBackTile(): " + AIRoad.GetDriveThroughBackTile(33411)); print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33411)); print(" IsRoadStationTile(): " + AIRoad.IsRoadStationTile(33411)); print(" IsDriveThroughRoadStationTile: " + AIRoad.IsDriveThroughRoadStationTile(33411)); print(" RemoveRoadStation(): " + AIRoad.RemoveRoadStation(33411)); print(" RemoveRoadStation(): " + AIRoad.RemoveRoadStation(33411)); print(" Station Types"); print(" BuildRoadStation(bus): " + AIRoad.BuildRoadStation(33411, 33410, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadStation(truck): " + AIRoad.BuildRoadStation(33421, 33422, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadStation(truck): " + AIRoad.BuildRoadStation(33412, 33413, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadStation(bus): " + AIRoad.BuildRoadStation(33411 + 256, 33411, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadStation(truck): " + AIRoad.BuildRoadStation(33412 + 256, 33412 + 256 + 256, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); print(" BuildDriveThroughRoadStation(bus-drive): " + AIRoad.BuildDriveThroughRoadStation(33413, 33412, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" BuildDriveThroughRoadStation(truck-drive): " + AIRoad.BuildDriveThroughRoadStation(33414, 33413, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); print(" BuildDriveThroughRoadStation(bus-drive): " + AIRoad.BuildDriveThroughRoadStation(33415, 33414, AIRoad.ROADVEHTYPE_BUS, AIStation.STATION_JOIN_ADJACENT)); print(" BuildDriveThroughRoadStation(truck-drive): " + AIRoad.BuildDriveThroughRoadStation(33416, 33415, AIRoad.ROADVEHTYPE_TRUCK, AIStation.STATION_JOIN_ADJACENT)); print(" BuildRoadDepot(): " + AIRoad.BuildRoadDepot(33417, 33418)); print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33411 + 256)); print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33412 + 256)); print(" IsDriveThroughRoadStationTile: " + AIRoad.IsDriveThroughRoadStationTile(33415)); print(" IsBuildable(): " + AITile.IsBuildable(33415)); print(" GetDriveThroughBackTile(): " + AIRoad.GetDriveThroughBackTile(33415)); print(" GetRoadStationFrontTile(): " + AIRoad.GetRoadStationFrontTile(33415)); print(" IsRoadTile(): " + AIRoad.IsRoadTile(33415)); } function Regression::Sign() { local j = 0; print(""); print("--Sign--"); print(" BuildSign(33410, 'Some Sign'): " + AISign.BuildSign(33410, "Some Sign")); print(" BuildSign(33411, 'Test'): " + AISign.BuildSign(33411, "Test")); print(" SetName(1, 'Test2'): " + AISign.SetName(1, "Test2")); local sign_id = AISign.BuildSign(33409, "Some other Sign"); print(" BuildSign(33409, 'Some other Sign'): " + sign_id); print(" RemoveSign(" + sign_id + "): " + AISign.RemoveSign(sign_id)); print(""); local list = AISignList(); list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { j++; print(" Sign " + i); print(" IsValidSign(): " + AISign.IsValidSign(i)); print(" GetName(): " + AISign.GetName(i)); print(" GetLocation(): " + AISign.GetLocation(i)); } print(" Valid Signs: " + j); } function Regression::Station() { print(""); print("--Station--"); print(" IsValidStation(0): " + AIStation.IsValidStation(0)); print(" IsValidStation(1000): " + AIStation.IsValidStation(1000)); print(" GetName(0): " + AIStation.GetName(0)); print(" SetName(0): " + AIStation.SetName(0, "Look, a station")); print(" GetName(0): " + AIStation.GetName(0)); print(" GetLocation(1): " + AIStation.GetLocation(1)); print(" GetLocation(1000): " + AIStation.GetLocation(1000)); print(" GetStationID(33411): " + AIStation.GetStationID(33411)); print(" GetStationID(34411): " + AIStation.GetStationID(34411)); print(" GetStationID(33411): " + AIStation.GetStationID(33411)); print(" HasRoadType(3, TRAM): " + AIStation.HasRoadType(3, AIRoad.ROADTYPE_TRAM)); print(" HasRoadType(3, ROAD): " + AIStation.HasRoadType(3, AIRoad.ROADTYPE_ROAD)); print(" HasRoadType(33411, TRAM): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_TRAM)); print(" HasRoadType(33411, ROAD): " + AIRoad.HasRoadType(33411, AIRoad.ROADTYPE_ROAD)); print(" HasStationType(3, BUS): " + AIStation.HasStationType(3, AIStation.STATION_BUS_STOP)); print(" HasStationType(3, TRAIN): " + AIStation.HasStationType(3, AIStation.STATION_TRAIN)); print(" GetCoverageRadius(BUS): " + AIStation.GetCoverageRadius(AIStation.STATION_BUS_STOP)); print(" GetCoverageRadius(TRUCK): " + AIStation.GetCoverageRadius(AIStation.STATION_TRUCK_STOP)); print(" GetCoverageRadius(TRAIN): " + AIStation.GetCoverageRadius(AIStation.STATION_TRAIN)); print(" GetNearestTown(): " + AIStation.GetNearestTown(0)); print(" GetNearestTown(): " + AIStation.GetNearestTown(10000)); print(" GetNearestTown(): " + AIStation.GetNearestTown(3)); print(""); print("--CargoWaiting--"); for (local cargo = 0; cargo <= 1000; cargo += 1000) { for (local station0 = 0; station0 <= 1000; station0 += 1000) { print(" GetCargoWaiting(" + station0 + ", " + cargo + "): " + AIStation.GetCargoWaiting(station0, cargo)); for (local station1 = 0; station1 <= 1000; station1 += 1000) { print(" GetCargoWaitingFrom(" + station0 + ", " + station1 + ", " + cargo + "): " + AIStation.GetCargoWaitingFrom(station0, station1, cargo)); print(" GetCargoWaitingVia(" + station0 + ", " + station1 + ", " + cargo + "): " + AIStation.GetCargoWaitingFrom(station0, station1, cargo)); for (local station2 = 0; station2 <= 1000; station2 += 1000) { print(" GetCargoWaitingFromVia(" + station0 + ", " + station1 + ", " + station2 + ", " + cargo + "): " + AIStation.GetCargoWaitingFromVia(station0, station1, station2, cargo)); } } } } print(""); print("--CargoPlanned--"); for (local cargo = 0; cargo <= 1000; cargo += 1000) { for (local station0 = 0; station0 <= 1000; station0 += 1000) { print(" GetCargoPlanned(" + station0 + ", " + cargo + "): " + AIStation.GetCargoPlanned(station0, cargo)); for (local station1 = 0; station1 <= 1000; station1 += 1000) { print(" GetCargoPlannedFrom(" + station0 + ", " + station1 + ", " + cargo + "): " + AIStation.GetCargoPlannedFrom(station0, station1, cargo)); print(" GetCargoPlannedVia(" + station0 + ", " + station1 + ", " + cargo + "): " + AIStation.GetCargoPlannedFrom(station0, station1, cargo)); for (local station2 = 0; station2 <= 1000; station2 += 1000) { print(" GetCargoPlannedFromVia(" + station0 + ", " + station1 + ", " + station2 + ", " + cargo + "): " + AIStation.GetCargoPlannedFromVia(station0, station1, station2, cargo)); } } } } } function Regression::Tile() { print(""); print("--Tile--"); print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33148)); print(" IsFarmTile(): " + AITile.IsFarmTile(32892)); print(" IsRockTile(): " + AITile.IsRockTile(31606)); print(" IsRoughTile(): " + AITile.IsRoughTile(33674)); print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33404)); print(" IsFarmTile(): " + AITile.IsFarmTile(33404)); print(" IsRockTile(): " + AITile.IsRockTile(33404)); print(" IsRoughTile(): " + AITile.IsRoughTile(33404)); print(" IsSnowTile(): " + AITile.IsSnowTile(33404)); print(" IsDesertTile(): " + AITile.IsDesertTile(33404)); print(" PlantTree(): " + AITile.PlantTree(33404)); print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33404)); print(" PlantTree(): " + AITile.PlantTree(33404)); print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33661)); print(" PlantTreeRectangle(): " + AITile.PlantTreeRectangle(33404, 2, 2)); print(" HasTreeOnTile(): " + AITile.HasTreeOnTile(33661)); } function Regression::TileList() { local list = AITileList(); print(""); print("--TileList--"); print(" Count(): " + list.Count()); list.AddRectangle(27631 - 256 * 1, 256 * 1 + 27631 + 2); print(" Count(): " + list.Count()); list.Valuate(AITile.GetSlope); print(" Slope(): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); print(" " + i + " => " + AITile.GetComplementSlope(list.GetValue(i))); print(" " + i + " => " + AITile.IsSteepSlope(list.GetValue(i))); print(" " + i + " => " + AITile.IsHalftileSlope(list.GetValue(i))); } list.Clear(); print(""); print("--TileList--"); print(" Count(): " + list.Count()); list.AddRectangle(34436, 256 * 2 + 34436 + 8); print(" Count(): " + list.Count()); list.Valuate(AITile.GetCornerHeight, AITile.CORNER_N); print(" Height(): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetCornerHeight, AITile.CORNER_N); print(" CornerHeight(North): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetMinHeight); print(" MinHeight(): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetMaxHeight); print(" MaxHeight(): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetSlope); list.KeepValue(0); print(" Slope(): done"); print(" KeepValue(0): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Clear(); list.AddRectangle(41895 - 256 * 2, 256 * 2 + 41895 + 8); list.Valuate(AITile.IsBuildable); list.KeepValue(1); print(" Buildable(): done"); print(" KeepValue(1): done"); print(" Count(): " + list.Count()); list.Valuate(AITile.IsBuildableRectangle, 3, 3); print(" BuildableRectangle(3, 3) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetDistanceManhattanToTile, 30000); print(" DistanceManhattanToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetDistanceSquareToTile, 30000); print(" DistanceSquareToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.AddRectangle(31895 - 256 * 5, 256 * 5 + 31895 + 8); list.Valuate(AITile.GetOwner); print(" GetOwner() ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetTownAuthority); print(" GetTownAuthority() ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetClosestTown); print(" GetClosestTown() ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITile.GetCargoAcceptance, 0, 1, 1, 3); list.KeepAboveValue(10); print(" CargoAcceptance(): done"); print(" KeepAboveValue(10): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIRoad.IsRoadTile); list.KeepValue(1); print(" RoadTile(): done"); print(" KeepValue(1): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIRoad.GetNeighbourRoadCount); list.KeepValue(1); print(" NeighbourRoadCount():done"); print(" KeepValue(1): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.AddRectangle(54421 - 256 * 2, 256 * 2 + 54421 + 8); list.Valuate(AITile.IsWaterTile); print(" Water(): done"); print(" Count(): " + list.Count()); print(" ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list = AITileList_IndustryAccepting(0, 3); print(""); print("--TileList_IndustryAccepting--"); print(" Count(): " + list.Count()); list.Valuate(AITile.GetCargoAcceptance, 3, 1, 1, 3); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list = AITileList_IndustryProducing(1, 3); print(""); print("--TileList_IndustryProducing--"); print(" Count(): " + list.Count()); list.Valuate(AITile.GetCargoProduction, 7, 1, 1, 3); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list = AITileList_StationType(4, AIStation.STATION_BUS_STOP); print(""); print("--TileList_StationType--"); print(" Count(): " + list.Count()); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } function Regression::Town() { local j = 0; print(""); print("--Town--"); print(" GetTownCount(): " + AITown.GetTownCount()); local list = AITownList(); list.Sort(AIList.SORT_BY_ITEM, AIList.SORT_ASCENDING); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { if (AITown.IsValidTown(i)) j++; print(" Town " + i); print(" IsValidTown(): " + AITown.IsValidTown(i)); print(" GetName(): " + AITown.GetName(i)); print(" GetPopulation(): " + AITown.GetPopulation(i)); print(" GetLocation(): " + AITown.GetLocation(i)); print(" GetHouseCount(): " + AITown.GetHouseCount(i)); print(" GetRating(): " + AITown.GetRating(i, AICompany.COMPANY_SELF)); print(" IsCity(): " + AITown.IsCity(i)); } print(" Valid Towns: " + j); print(" GetTownCount(): " + AITown.GetTownCount()); } function Regression::TownList() { local list = AITownList(); print(""); print("--TownList--"); print(" Count(): " + list.Count()); list.Valuate(AITown.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITown.GetDistanceManhattanToTile, 30000); print(" DistanceManhattanToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITown.GetDistanceSquareToTile, 30000); print(" DistanceSquareToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITown.IsWithinTownInfluence, AITown.GetLocation(0)); print(" IsWithinTownInfluence(" + AITown.GetLocation(0) + ") ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITown.GetAllowedNoise); print(" GetAllowedNoise() ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AITown.GetPopulation); list.KeepAboveValue(500); print(" KeepAboveValue(500): done"); print(" Count(): " + list.Count()); print(" Population ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } print(" HasStatue(): " + AITown.HasStatue(list.Begin())); print(" GetRoadReworkDuration(): " + AITown.GetRoadReworkDuration(list.Begin())); print(" GetExclusiveRightsCompany(): " + AITown.GetExclusiveRightsCompany(list.Begin())); print(" GetExclusiveRightsDuration(): " + AITown.GetExclusiveRightsDuration(list.Begin())); print(" IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE)); print(" PerformTownAction(BUILD_STATUE): " + AITown.PerformTownAction(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE)); print(" IsActionAvailable(BUILD_STATUE): " + AITown.IsActionAvailable(list.Begin(), AITown.TOWN_ACTION_BUILD_STATUE)); print(" HasStatue(): " + AITown.HasStatue(list.Begin())); } function Regression::Tunnel() { print(""); print("--Tunnel--"); print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(29050)); print(" RemoveTunnel(): " + AITunnel.RemoveTunnel(29050)); print(" GetOtherTunnelEnd(): " + AITunnel.GetOtherTunnelEnd(29050)); print(" BuildTunnel(): " + AITunnel.BuildTunnel(AIVehicle.VT_ROAD, 29050)); print(" GetOtherTunnelEnd(): " + AITunnel.GetOtherTunnelEnd(29050)); print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(29050)); print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(28026)); print(" RemoveTunnel(): " + AITunnel.RemoveTunnel(29050)); print(" IsTunnelTile(): " + AITunnel.IsTunnelTile(29050)); print(" --Errors--"); print(" BuildTunnel(): " + AITunnel.BuildTunnel(AIVehicle.VT_ROAD, 7529)); print(" BuildTunnel(): " + AITunnel.BuildTunnel(AIVehicle.VT_ROAD, 8043)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" RemoveTunnel(): " + AITunnel.RemoveTunnel(7529)); } function Regression::Vehicle() { local accounting = AIAccounting(); print(""); print("--Vehicle--"); print(" IsValidVehicle(-1): " + AIVehicle.IsValidVehicle(-1)); print(" IsValidVehicle(0): " + AIVehicle.IsValidVehicle(0)); print(" IsValidVehicle(12): " + AIVehicle.IsValidVehicle(12)); print(" ISValidVehicle(9999): " + AIVehicle.IsValidVehicle(9999)); local bank = AICompany.GetBankBalance(AICompany.COMPANY_SELF); print(" BuildVehicle(): " + AIVehicle.BuildVehicle(33417, 153)); print(" IsValidVehicle(12): " + AIVehicle.IsValidVehicle(12)); print(" CloneVehicle(): " + AIVehicle.CloneVehicle(33417, 12, true)); local bank_after = AICompany.GetBankBalance(AICompany.COMPANY_SELF); print(" --Accounting--"); print(" GetCosts(): " + accounting.GetCosts()); print(" Should be: " + (bank - bank_after)); print(" ResetCosts(): " + accounting.ResetCosts()); bank = AICompany.GetBankBalance(AICompany.COMPANY_SELF); print(" SellVehicle(13): " + AIVehicle.SellVehicle(13)); print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); print(" IsStoppedInDepot(): " + AIVehicle.IsStoppedInDepot(12)); print(" StartStopVehicle(): " + AIVehicle.StartStopVehicle(12)); print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); print(" IsStoppedInDepot(): " + AIVehicle.IsStoppedInDepot(12)); print(" SendVehicleToDepot(): " + AIVehicle.SendVehicleToDepot(12)); print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); print(" IsStoppedInDepot(): " + AIVehicle.IsStoppedInDepot(12)); bank_after = AICompany.GetBankBalance(AICompany.COMPANY_SELF); print(" --Accounting--"); print(" GetCosts(): " + accounting.GetCosts()); print(" Should be: " + (bank - bank_after)); print(" GetName(): " + AIVehicle.GetName(12)); print(" SetName(): " + AIVehicle.SetName(12, "MyVehicleName")); print(" GetName(): " + AIVehicle.GetName(12)); print(" CloneVehicle(): " + AIVehicle.CloneVehicle(33417, 12, true)); print(" --VehicleData--"); print(" GetLocation(): " + AIVehicle.GetLocation(12)); print(" GetEngineType(): " + AIVehicle.GetEngineType(12)); print(" GetUnitNumber(): " + AIVehicle.GetUnitNumber(12)); print(" GetAge(): " + AIVehicle.GetAge(12)); print(" GetMaxAge(): " + AIVehicle.GetMaxAge(12)); print(" GetAgeLeft(): " + AIVehicle.GetAgeLeft(12)); print(" GetCurrentSpeed(): " + AIVehicle.GetCurrentSpeed(12)); print(" GetRunningCost(): " + AIVehicle.GetRunningCost(12)); print(" GetProfitThisYear(): " + AIVehicle.GetProfitThisYear(12)); print(" GetProfitLastYear(): " + AIVehicle.GetProfitLastYear(12)); print(" GetCurrentValue(): " + AIVehicle.GetCurrentValue(12)); print(" GetVehicleType(): " + AIVehicle.GetVehicleType(12)); print(" GetRoadType(): " + AIVehicle.GetRoadType(12)); print(" GetCapacity(): " + AIVehicle.GetCapacity(12, 10)); print(" GetCargoLoad(): " + AIVehicle.GetCargoLoad(12, 10)); print(" IsInDepot(): " + AIVehicle.IsInDepot(12)); print(" GetNumWagons(): " + AIVehicle.GetNumWagons(12)); print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(12, 0)); print(" GetWagonAge(): " + AIVehicle.GetWagonAge(12, 0)); print(" GetLength(): " + AIVehicle.GetLength(12)); print(" GetOwner(): " + AITile.GetOwner(32119)); print(" BuildVehicle(): " + AIVehicle.BuildVehicle(32119, 219)); print(" IsValidVehicle(14): " + AIVehicle.IsValidVehicle(14)); print(" IsInDepot(14): " + AIVehicle.IsInDepot(14)); print(" IsStoppedInDepot(14): " + AIVehicle.IsStoppedInDepot(14)); print(" IsValidVehicle(15): " + AIVehicle.IsValidVehicle(15)); print(" IsInDepot(15): " + AIVehicle.IsInDepot(15)); print(" IsStoppedInDepot(15): " + AIVehicle.IsStoppedInDepot(15)); print(" BuildVehicle(): " + AIVehicle.BuildVehicle(28479, 204)); print(" IsValidVehicle(16): " + AIVehicle.IsValidVehicle(16)); print(" IsInDepot(16): " + AIVehicle.IsInDepot(16)); print(" IsStoppedInDepot(16): " + AIVehicle.IsStoppedInDepot(16)); print(" BuildRailDepot(): " + AIRail.BuildRailDepot(10008, 10000)); print(" BuildVehicle(): " + AIVehicle.BuildVehicle(10008, 9)); print(" BuildVehicle(): " + AIVehicle.BuildVehicle(10008, 27)); print(" BuildVehicle(): " + AIVehicle.BuildVehicle(10008, 27)); print(" MoveWagonChain(): " + AIVehicle.MoveWagonChain(18, 0, 17, 0)); print(" GetNumWagons(): " + AIVehicle.GetNumWagons(17)); print(" GetLength(): " + AIVehicle.GetLength(17)); print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17, 0)); print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 0)); print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17, 1)); print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 1)); print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 2)); print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 2)); print(" GetWagonEngineType(): " + AIVehicle.GetWagonEngineType(17 3)); print(" GetWagonAge(): " + AIVehicle.GetWagonAge(17, 3)); print(" --Errors--"); print(" RefitVehicle(): " + AIVehicle.RefitVehicle(12, 0)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" SellVehicle(): " + AIVehicle.SellVehicle(12)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); print(" SendVehicleToDepot(): " + AIVehicle.SendVehicleToDepot(13)); print(" GetLastErrorString(): " + AIError.GetLastErrorString()); local list = AIVehicleList(); print(""); print("--VehicleList--"); print(" Count(): " + list.Count()); list.Valuate(AIVehicle.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetEngineType); print(" EngineType ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetUnitNumber); print(" UnitNumber ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetAge); print(" Age ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetMaxAge); print(" MaxAge ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetAgeLeft); print(" AgeLeft ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetCurrentSpeed); print(" CurrentSpeed ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetRunningCost); print(" RunningCost ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetProfitThisYear); print(" ProfitThisYear ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetProfitLastYear); print(" ProfitLastYear ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetCurrentValue); print(" CurrentValue ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetVehicleType); print(" VehicleType ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetRoadType); print(" RoadType ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetCapacity, 10); print(" VehicleType ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIVehicle.GetCargoLoad, 10); print(" VehicleType ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } function Regression::PrintSubsidy(subsidy_id) { print(" --Subsidy (" + subsidy_id + ") --"); print(" IsValidSubsidy(): " + AISubsidy.IsValidSubsidy(subsidy_id)); print(" IsAwarded(): " + AISubsidy.IsAwarded(subsidy_id)); print(" GetAwardedTo(): " + AISubsidy.GetAwardedTo(subsidy_id)); print(" GetExpireDate(): " + AISubsidy.GetExpireDate(subsidy_id)); print(" GetSourceType(): " + AISubsidy.GetSourceType(subsidy_id)); print(" GetSourceIndex(): " + AISubsidy.GetSourceIndex(subsidy_id)); print(" GetDestinationType(): " + AISubsidy.GetDestinationType(subsidy_id)); print(" GetDestinationIndex(): " + AISubsidy.GetDestinationIndex(subsidy_id)); print(" GetCargoType(): " + AISubsidy.GetCargoType(subsidy_id)); } function Regression::Math() { print(""); print("--Math--"); print(" -2147483648 < -2147483647: " + (-2147483648 < -2147483647)); print(" -2147483648 < -1 : " + (-2147483648 < -1 )); print(" -2147483648 < 0 : " + (-2147483648 < 0 )); print(" -2147483648 < 1 : " + (-2147483648 < 1 )); print(" -2147483648 < 2147483647: " + (-2147483648 < 2147483647)); print(" -2147483647 < -2147483648: " + (-2147483647 < -2147483648)); print(" -1 < -2147483648: " + (-1 < -2147483648)); print(" 0 < -2147483648: " + ( 0 < -2147483648)); print(" 1 < -2147483648: " + ( 1 < -2147483648)); print(" 2147483647 < -2147483648: " + ( 2147483647 < -2147483648)); print(" -1 > 2147483647: " + (-1 > 2147483647)); print(" -1 > 1 : " + (-1 > 1 )); print(" -1 > 0 : " + (-1 > 0 )); print(" -1 > -1 : " + (-1 > -1 )); print(" -1 > -2147483648: " + (-1 > -2147483648)); print(" 1 > 2147483647: " + ( 1 > 2147483647)); print(" 1 > 1 : " + ( 1 > 1 )); print(" 1 > 0 : " + ( 1 > 0 )); print(" 1 > -1 : " + ( 1 > -1 )); print(" 1 > -2147483648: " + ( 1 > -2147483648)); print(" 2147483647 > 2147483646: " + ( 2147483647 > 2147483646)); print(" 2147483647 > 1 : " + ( 2147483647 > 1 )); print(" 2147483647 > 0 : " + ( 2147483647 > 0 )); print(" 2147483647 > -1 : " + ( 2147483647 > -1 )); print(" 2147483647 > -2147483648: " + ( 2147483647 > -2147483648)); print(" 2147483646 > 2147483647: " + ( 2147483646 > 2147483647)); print(" 1 > 2147483647: " + ( 1 > 2147483647)); print(" 0 > 2147483647: " + ( 0 > 2147483647)); print(" -1 > 2147483647: " + (-1 > 2147483647)); print(" -2147483648 > 2147483647: " + (-2147483648 > 2147483647)); print(" 13725 > -2147483648: " + ( 13725 > -2147483648)); } function Regression::Start() { this.TestInit(); this.Std(); this.Base(); this.List(); /* Do this first as it gains maximum loan (which is faked to quite a lot). */ this.Company(); this.Airport(); this.Bridge(); this.BridgeList(); this.Cargo(); this.CargoList(); this.Engine(); this.EngineList(); this.Group(); this.Industry(); this.IndustryList(); this.IndustryTypeList(); this.Map(); this.Marine(); this.Prices(); this.Rail(); this.RailTypeList(); this.Road(); this.Sign(); this.Station(); this.Tile(); this.TileList(); this.Town(); this.TownList(); this.Tunnel(); this.Vehicle(); /* Order has to be after Vehicle */ this.Order(); print(""); print(" First Subsidy Test"); PrintSubsidy(0); while (AIEventController.IsEventWaiting()) { local e = AIEventController.GetNextEvent(); print(" GetNextEvent: " + (e == null ? "null" : "instance")); print(" GetEventType: " + e.GetEventType()); switch (e.GetEventType()) { case AIEvent.ET_SUBSIDY_OFFER: { local c = AIEventSubsidyOffer.Convert(e); print(" EventName: SubsidyOffer"); PrintSubsidy(c.GetSubsidyID()); } break; case AIEvent.ET_VEHICLE_WAITING_IN_DEPOT: { local c = AIEventVehicleWaitingInDepot.Convert(e); print(" EventName: VehicleWaitingInDepot"); print(" VehicleID: " + c.GetVehicleID()); } break; default: print(" Unknown Event"); break; } } print(" IsEventWaiting: false"); this.Math(); } openttd-1.5.3/bin/ai/regression/tst_regression/result.txt0000644000000000000000000071622512627373446022400 0ustar rootroot --TestInit-- Ops: 9988 TickTest: 1 TickTest: 2 Ops: 9990 SetCommandDelay: (null : 0x00000000) IsValid(vehicle.plane_speed): true vehicle.plane_speed: 2 Required this file min(6, 3): 3 min(3, 6): 3 max(6, 3): 6 max(3, 6): 6 AIList Consistency Tests Value Descending 40 25 10 40 30 20 10 40 30 20 10 40 30 20 10 Value Ascending 5 20 35 10 20 30 40 10 20 30 40 10 20 30 40 Item Descending 40 25 10 40 30 20 10 40 30 20 10 Item Ascending 5 20 35 10 20 30 40 10 20 30 40 Ops: 8673 --Std-- abs(-21): 21 abs( 21): 21 --AIBase-- Rand(): -54346916 Rand(): -937374575 Rand(): 823953997 RandRange(0): 0 RandRange(0): 0 RandRange(0): 0 RandRange(1): 0 RandRange(1): 0 RandRange(1): 0 RandRange(2): 1 RandRange(2): 1 RandRange(2): 1 RandRange(1000000): 966676 RandRange(1000000): 289525 RandRange(1000000): 170283 Chance(1, 2): false Chance(1, 2): true Chance(1, 2): false --List-- IsEmpty(): true Count(): 101 HasItem(1050): false HasItem(1051): true IsEmpty(): false List Dump: 1 => 1 2 => 2 1000 => 1000 1001 => 1001 1002 => 1002 1003 => 1003 1004 => 1004 1005 => 1005 1006 => 1006 1007 => 1007 1008 => 1008 1009 => 1009 1010 => 1010 1011 => 1011 1012 => 1012 1013 => 1013 1014 => 1014 1015 => 1015 1016 => 1016 1017 => 1017 1018 => 1018 1019 => 1019 1020 => 1020 1021 => 1021 1022 => 1022 1023 => 1023 1024 => 1024 1025 => 1025 1026 => 1026 1027 => 1027 1028 => 1028 1029 => 1029 1030 => 1030 1031 => 1031 1032 => 1032 1033 => 1033 1034 => 1034 1035 => 1035 1036 => 1036 1037 => 1037 1038 => 1038 1039 => 1039 1040 => 1040 1041 => 1041 1042 => 1042 1043 => 1043 1044 => 1044 1045 => 1045 1046 => 1046 1047 => 1047 1048 => 1048 1049 => 1049 1051 => 12 1052 => 1052 1053 => 1053 1054 => 1054 1055 => 1055 1056 => 1056 1057 => 1057 1058 => 1058 1059 => 1059 1060 => 1060 1061 => 1061 1062 => 1062 1063 => 1063 1064 => 1064 1065 => 1065 1066 => 1066 1067 => 1067 1068 => 1068 1069 => 1069 1070 => 1070 1071 => 1071 1072 => 1072 1073 => 1073 1074 => 1074 1075 => 1075 1076 => 1076 1077 => 1077 1078 => 1078 1079 => 1079 1080 => 1080 1081 => 1081 1082 => 1082 1083 => 1083 1084 => 1084 1085 => 1085 1086 => 1086 1087 => 1087 1088 => 1088 1089 => 1089 1090 => 1090 1091 => 1091 1092 => 1092 1093 => 1093 1094 => 1094 1095 => 1095 1096 => 1096 1097 => 1097 1098 => 1098 1099 => 1099 Custom ListDump: 1 => 4343 2 => 8686 1000 => 4343000 1001 => 4347343 1002 => 4351686 1003 => 4356029 1004 => 4360372 1005 => 4364715 1006 => 4369058 1007 => 4373401 1008 => 4377744 1009 => 4382087 1010 => 4386430 1011 => 4390773 1012 => 4395116 1013 => 4399459 1014 => 4403802 1015 => 4408145 1016 => 4412488 1017 => 4416831 1018 => 4421174 1019 => 4425517 1020 => 4429860 1021 => 4434203 1022 => 4438546 1023 => 4442889 1024 => 4447232 1025 => 4451575 1026 => 4455918 1027 => 4460261 1028 => 4464604 1029 => 4468947 1030 => 4473290 1031 => 4477633 1032 => 4481976 1033 => 4486319 1034 => 4490662 1035 => 4495005 1036 => 4499348 1037 => 4503691 1038 => 4508034 1039 => 4512377 1040 => 4516720 1041 => 4521063 1042 => 4525406 1043 => 4529749 1044 => 4534092 1045 => 4538435 1046 => 4542778 1047 => 4547121 1048 => 4551464 1049 => 4555807 1051 => 4564493 1052 => 4568836 1053 => 4573179 1054 => 4577522 1055 => 4581865 1056 => 4586208 1057 => 4590551 1058 => 4594894 1059 => 4599237 1060 => 4603580 1061 => 4607923 1062 => 4612266 1063 => 4616609 1064 => 4620952 1065 => 4625295 1066 => 4629638 1067 => 4633981 1068 => 4638324 1069 => 4642667 1070 => 4647010 1071 => 4651353 1072 => 4655696 1073 => 4660039 1074 => 4664382 1075 => 4668725 1076 => 4673068 1077 => 4677411 1078 => 4681754 1079 => 4686097 1080 => 4690440 1081 => 4694783 1082 => 4699126 1083 => 4703469 1084 => 4707812 1085 => 4712155 1086 => 4716498 1087 => 4720841 1088 => 4725184 1089 => 4729527 1090 => 4733870 1091 => 4738213 1092 => 4742556 1093 => 4746899 1094 => 4751242 1095 => 4755585 1096 => 4759928 1097 => 4764271 1098 => 4768614 1099 => 4772957 Custom ListDump: 1 => 42 2 => 84 1000 => 42000 1001 => 42042 1002 => 42084 1003 => 42126 1004 => 42168 1005 => 42210 1006 => 42252 1007 => 42294 1008 => 42336 1009 => 42378 1010 => 42420 1011 => 42462 1012 => 42504 1013 => 42546 1014 => 42588 1015 => 42630 1016 => 42672 1017 => 42714 1018 => 42756 1019 => 42798 1020 => 42840 1021 => 42882 1022 => 42924 1023 => 42966 1024 => 43008 1025 => 43050 1026 => 43092 1027 => 43134 1028 => 43176 1029 => 43218 1030 => 43260 1031 => 43302 1032 => 43344 1033 => 43386 1034 => 43428 1035 => 43470 1036 => 43512 1037 => 43554 1038 => 43596 1039 => 43638 1040 => 43680 1041 => 43722 1042 => 43764 1043 => 43806 1044 => 43848 1045 => 43890 1046 => 43932 1047 => 43974 1048 => 44016 1049 => 44058 1051 => 44142 1052 => 44184 1053 => 44226 1054 => 44268 1055 => 44310 1056 => 44352 1057 => 44394 1058 => 44436 1059 => 44478 1060 => 44520 1061 => 44562 1062 => 44604 1063 => 44646 1064 => 44688 1065 => 44730 1066 => 44772 1067 => 44814 1068 => 44856 1069 => 44898 1070 => 44940 1071 => 44982 1072 => 45024 1073 => 45066 1074 => 45108 1075 => 45150 1076 => 45192 1077 => 45234 1078 => 45276 1079 => 45318 1080 => 45360 1081 => 45402 1082 => 45444 1083 => 45486 1084 => 45528 1085 => 45570 1086 => 45612 1087 => 45654 1088 => 45696 1089 => 45738 1090 => 45780 1091 => 45822 1092 => 45864 1093 => 45906 1094 => 45948 1095 => 45990 1096 => 46032 1097 => 46074 1098 => 46116 1099 => 46158 Randomize ListDump: 1 => -200078348 2 => -29799264 1000 => 1630721656 1001 => 959306175 1002 => 1527421791 1003 => 1259692483 1004 => -1289244298 1005 => -1572996668 1006 => -2069479746 1007 => -1819131606 1008 => -1007163964 1009 => -1185394870 1010 => -1471365065 1011 => 364354366 1012 => -1478084253 1013 => 405281367 1014 => -11170062 1015 => 156767750 1016 => 1288924796 1017 => 1796884876 1018 => -1947073702 1019 => -1999614238 1020 => -231292809 1021 => 966621566 1022 => -606766557 1023 => -1138727825 1024 => -749544262 1025 => 2004771271 1026 => 686734186 1027 => 923274744 1028 => -1672035149 1029 => -1642064950 1030 => 1363389551 1031 => -559500928 1032 => 1656196991 1033 => 1655354425 1034 => -1027156689 1035 => 1952644328 1036 => 1217870217 1037 => 242274100 1038 => 201816080 1039 => 2127464758 1040 => 446043650 1041 => -319728455 1042 => 204701002 1043 => -571265398 1044 => -1422217131 1045 => -391208397 1046 => -1822628371 1047 => -1499755350 1048 => -1422137641 1049 => 1621693134 1051 => -1428728134 1052 => -147587573 1053 => 681719500 1054 => 1172011190 1055 => -1834344882 1056 => 1157634586 1057 => 1902133676 1058 => -1967780161 1059 => -1618025531 1060 => -810220453 1061 => 1582854921 1062 => -410004643 1063 => 1159917159 1064 => -1377804984 1065 => -738843914 1066 => -1578756103 1067 => -464090986 1068 => 1711504679 1069 => 545330655 1070 => 379462570 1071 => 514511099 1072 => -1813251176 1073 => 1424958266 1074 => -825255131 1075 => 539054595 1076 => -1764192010 1077 => -1243277769 1078 => 2017874281 1079 => -1972353607 1080 => 1879761467 1081 => 1638986560 1082 => -1832287507 1083 => -492411882 1084 => 658940812 1085 => -1044199400 1086 => 1586504918 1087 => -125492611 1088 => -1562883174 1089 => -1013778441 1090 => 1560228607 1091 => -550265689 1092 => 524767105 1093 => -713387661 1094 => 1425927738 1095 => 942653932 1096 => 1233220698 1097 => 1313602368 1098 => -140318584 1099 => 1199179892 KeepTop(10): 1 => -200078348 2 => -29799264 1000 => 1630721656 1001 => 959306175 1002 => 1527421791 1003 => 1259692483 1004 => -1289244298 1005 => -1572996668 1006 => -2069479746 1007 => -1819131606 KeepBottom(8): 1000 => 1630721656 1001 => 959306175 1002 => 1527421791 1003 => 1259692483 1004 => -1289244298 1005 => -1572996668 1006 => -2069479746 1007 => -1819131606 RemoveBottom(2): 1000 => 1630721656 1001 => 959306175 1002 => 1527421791 1003 => 1259692483 1004 => -1289244298 1005 => -1572996668 RemoveTop(2): 1002 => 1527421791 1003 => 1259692483 1004 => -1289244298 1005 => -1572996668 RemoveList({1003, 1004}): 1002 => 1527421791 1005 => -1572996668 KeepList({1003, 1004, 1005}): 1005 => -1572996668 AddList({1005, 4000, 4001, 4002}): 1005 => 1005 4000 => 8000 4001 => 8002 4002 => 8004 foreach(): 1005 => 1005 4000 => 50 4001 => 8002 4002 => 8004 4006 => 12 []: 4000 => 50 IsEmpty(): true 0 => 5 (true) ERROR: Next() is invalid as Begin() is never called ERROR: IsEnd() is invalid as Begin() is never called 0 => 5 (false) 0 => 5 (true) 2 => 6 (true) 3 => 6 (true) 9 => 0 (false) --Company-- SetName(): true SetName(): true SetName(): true SetName(): false GetLastErrorString(): ERR_NAME_IS_NOT_UNIQUE GetName(): Regression GetPresidentName(): E. McAlpine SetPresidentName(): true GetPresidentName(): Regression AI GetBankBalance(): 100000 GetName(): (null : 0x00000000) GetLoanAmount(): 100000 GetMaxLoanAmount(): 500000 GetLoanInterval(): 10000 SetLoanAmount(1): false SetLoanAmount(100): false SetLoanAmount(10000): true GetLastErrorString(): ERR_NONE GetBankBalance(): 10000 GetLoanAmount(): 10000 SetMinimumLoanAmount(31337): true GetBankBalance(): 40000 GetLoanAmount(): 40000 SetLoanAmount(10000): true GetBankBalance(): 500000 GetLoanAmount(): 500000 GetCompanyHQ(): -1 BuildCompanyHQ(): true GetCompanyHQ(): 33151 BuildCompanyHQ(): true GetCompanyHQ(): 33153 BuildCompanyHQ(): false GetLastErrorString(): ERR_AREA_NOT_CLEAR GetAutoRenewStatus(); false SetAutoRenewStatus(true); true GetAutoRenewStatus(); true SetAutoRenewStatus(true); true SetAutoRenewStatus(false); true GetAutoRenewMonths(); 6 SetAutoRenewMonths(-12); true GetAutoRenewMonths(); -12 SetAutoRenewMonths(-12); true SetAutoRenewMonths(6); true GetAutoRenewMoney(); 100000 SetAutoRenewMoney(200000); true GetAutoRenewMoney(); 200000 SetAutoRenewMoney(200000); true SetAutoRenewMoney(100000); true Quarter: -1 GetQuarterlyIncome(); -1 GetQuarterlyExpenses(); -1 GetQuarterlyCargoDelivered(); -1 GetQuarterlyPerformanceRating(); -1 GetQuarterlyCompanyValue(); -1 Quarter: 0 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); -210 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); -1 GetQuarterlyCompanyValue(); 1 Quarter: 1 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 2 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 3 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 4 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 5 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 6 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 7 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 8 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 9 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 10 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 11 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 12 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 13 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 14 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 15 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 16 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 17 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 18 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 19 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 20 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 21 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 22 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 23 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 Quarter: 24 GetQuarterlyIncome(); 0 GetQuarterlyExpenses(); 0 GetQuarterlyCargoDelivered(); 0 GetQuarterlyPerformanceRating(); 0 GetQuarterlyCompanyValue(); 0 --AIAirport-- IsHangarTile(): false IsAirportTile(): false GetHangarOfAirport(): -1 GetAirportType(): 254 IsAirportInformationAvailable(-1): false IsValidAirportType(-1): false GetAirportWidth(-1): -1 GetAirportHeight(-1): -1 GetAirportCoverageRadius(-1): -1 IsAirportInformationAvailable(0): true IsValidAirportType(0): true GetAirportWidth(0): 4 GetAirportHeight(0): 3 GetAirportCoverageRadius(0): 4 IsAirportInformationAvailable(1): true IsValidAirportType(1): false GetAirportWidth(1): 6 GetAirportHeight(1): 6 GetAirportCoverageRadius(1): 5 IsAirportInformationAvailable(2): true IsValidAirportType(2): false GetAirportWidth(2): 1 GetAirportHeight(2): 1 GetAirportCoverageRadius(2): 4 IsAirportInformationAvailable(3): true IsValidAirportType(3): false GetAirportWidth(3): 6 GetAirportHeight(3): 6 GetAirportCoverageRadius(3): 6 IsAirportInformationAvailable(4): true IsValidAirportType(4): false GetAirportWidth(4): 7 GetAirportHeight(4): 7 GetAirportCoverageRadius(4): 8 IsAirportInformationAvailable(5): true IsValidAirportType(5): false GetAirportWidth(5): 5 GetAirportHeight(5): 4 GetAirportCoverageRadius(5): 4 IsAirportInformationAvailable(6): true IsValidAirportType(6): false GetAirportWidth(6): 2 GetAirportHeight(6): 2 GetAirportCoverageRadius(6): 4 IsAirportInformationAvailable(7): true IsValidAirportType(7): false GetAirportWidth(7): 9 GetAirportHeight(7): 11 GetAirportCoverageRadius(7): 10 IsAirportInformationAvailable(8): true IsValidAirportType(8): false GetAirportWidth(8): 4 GetAirportHeight(8): 2 GetAirportCoverageRadius(8): 4 IsAirportInformationAvailable(9): false IsValidAirportType(9): false GetAirportWidth(9): -1 GetAirportHeight(9): -1 GetAirportCoverageRadius(9): -1 GetBankBalance(): 499790 GetPrice(): 5400 BuildAirport(): true IsHangarTile(): false IsAirportTile(): true GetAirportType(): 0 GetHangarOfAirport(): 32119 IsHangarTile(): true IsAirportTile(): true GetAirportType(): 0 GetBankBalance(): 489890 RemoveAirport(): true IsHangarTile(): false IsAirportTile(): false GetBankBalance(): 489626 BuildAirport(): true --Bridge-- Bridge -1 IsValidBridge(): false GetName(): (null : 0x00000000) GetMaxSpeed(): -1 GetPrice(): -1 GetMaxLength(): -1 GetMinLength(): -1 Bridge 0 IsValidBridge(): true GetName(): Wooden rail bridge GetMaxSpeed(): 32 GetPrice(): 450 GetMaxLength(): 66 GetMinLength(): 2 Bridge 1 IsValidBridge(): true GetName(): Concrete rail bridge GetMaxSpeed(): 48 GetPrice(): 630 GetMaxLength(): 4 GetMinLength(): 2 Bridge 2 IsValidBridge(): true GetName(): Steel girder rail bridge GetMaxSpeed(): 64 GetPrice(): 811 GetMaxLength(): 7 GetMinLength(): 2 Bridge 3 IsValidBridge(): true GetName(): Reinforced concrete suspension rail bridge GetMaxSpeed(): 80 GetPrice(): 946 GetMaxLength(): 12 GetMinLength(): 4 Bridge 4 IsValidBridge(): true GetName(): Steel suspension rail bridge GetMaxSpeed(): 96 GetPrice(): 1042 GetMaxLength(): 66 GetMinLength(): 5 Bridge 5 IsValidBridge(): true GetName(): Steel suspension rail bridge GetMaxSpeed(): 112 GetPrice(): 1081 GetMaxLength(): 66 GetMinLength(): 5 Bridge 6 IsValidBridge(): true GetName(): Steel cantilever rail bridge GetMaxSpeed(): 160 GetPrice(): 1261 GetMaxLength(): 9 GetMinLength(): 5 Bridge 7 IsValidBridge(): true GetName(): Steel cantilever rail bridge GetMaxSpeed(): 208 GetPrice(): 1306 GetMaxLength(): 10 GetMinLength(): 5 Bridge 8 IsValidBridge(): true GetName(): Steel cantilever rail bridge GetMaxSpeed(): 240 GetPrice(): 1396 GetMaxLength(): 11 GetMinLength(): 5 Bridge 9 IsValidBridge(): true GetName(): Steel girder rail bridge GetMaxSpeed(): 256 GetPrice(): 1351 GetMaxLength(): 4 GetMinLength(): 2 Bridge 10 IsValidBridge(): false GetName(): (null : 0x00000000) GetMaxSpeed(): -1 GetPrice(): -1 GetMaxLength(): -1 GetMinLength(): -1 Bridge 11 IsValidBridge(): false GetName(): (null : 0x00000000) GetMaxSpeed(): -1 GetPrice(): -1 GetMaxLength(): -1 GetMinLength(): -1 Bridge 12 IsValidBridge(): false GetName(): (null : 0x00000000) GetMaxSpeed(): -1 GetPrice(): -1 GetMaxLength(): -1 GetMinLength(): -1 Bridge 13 IsValidBridge(): false GetName(): (null : 0x00000000) GetMaxSpeed(): -1 GetPrice(): -1 GetMaxLength(): -1 GetMinLength(): -1 Valid Bridges: 10 IsBridgeTile(): false GetBridgeID(): -1 RemoveBridge(): false GetLastErrorString(): ERR_PRECONDITION_FAILED GetOtherBridgeEnd(): -1 BuildBridge(): true IsBridgeTile(): true GetBridgeID(): 5 IsBridgeTile(): true GetBridgeID(): 5 GetOtherBridgeEnd(): 33155 BuildBridge(): false GetLastErrorString(): ERR_ALREADY_BUILT RemoveBridge(): true IsBridgeTile(): false --BridgeList-- Count(): 10 MaxSpeed ListDump: 9 => 256 8 => 240 7 => 208 6 => 160 5 => 112 4 => 96 3 => 80 2 => 64 1 => 48 0 => 32 Price ListDump: 8 => 1396 9 => 1351 7 => 1306 6 => 1261 5 => 1081 4 => 1042 3 => 946 2 => 811 1 => 630 0 => 450 MaxLength ListDump: 5 => 66 4 => 66 0 => 66 3 => 12 8 => 11 7 => 10 6 => 9 2 => 7 9 => 4 1 => 4 MinLength ListDump: 8 => 5 7 => 5 6 => 5 5 => 5 4 => 5 3 => 4 9 => 2 2 => 2 1 => 2 0 => 2 --BridgeList_Length-- Count(): 3 MaxSpeed ListDump: 5 => 112 4 => 96 0 => 32 Price ListDump: 5 => 6489 4 => 6252 0 => 2703 --AICargo-- Cargo -1 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' IsFreight(): false HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): -1 GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 GetRoadVehicleTypeForCargo(): 1 Cargo 0 IsValidCargo(): true GetCargoLabel(): 'PASS' IsFreight(): false HasCargoClass(): true GetTownEffect(): 1 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 3 GetCargoIncome(100, 10): 38 GetCargoIncome(10, 100): 3 GetRoadVehicleTypeForCargo(): 0 Cargo 1 IsValidCargo(): true GetCargoLabel(): 'COAL' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 7 GetCargoIncome(100, 10): 71 GetCargoIncome(10, 100): 6 GetRoadVehicleTypeForCargo(): 1 Cargo 2 IsValidCargo(): true GetCargoLabel(): 'MAIL' IsFreight(): false HasCargoClass(): false GetTownEffect(): 2 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 5 GetCargoIncome(100, 10): 55 GetCargoIncome(10, 100): 5 GetRoadVehicleTypeForCargo(): 1 Cargo 3 IsValidCargo(): true GetCargoLabel(): 'OIL_' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 5 GetCargoIncome(100, 10): 53 GetCargoIncome(10, 100): 5 GetRoadVehicleTypeForCargo(): 1 Cargo 4 IsValidCargo(): true GetCargoLabel(): 'LVST' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 5 GetCargoIncome(100, 10): 52 GetCargoIncome(10, 100): 4 GetRoadVehicleTypeForCargo(): 1 Cargo 5 IsValidCargo(): true GetCargoLabel(): 'GOOD' IsFreight(): true HasCargoClass(): false GetTownEffect(): 3 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 7 GetCargoIncome(100, 10): 74 GetCargoIncome(10, 100): 6 GetRoadVehicleTypeForCargo(): 1 Cargo 6 IsValidCargo(): true GetCargoLabel(): 'GRAI' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 5 GetCargoIncome(100, 10): 58 GetCargoIncome(10, 100): 4 GetRoadVehicleTypeForCargo(): 1 Cargo 7 IsValidCargo(): true GetCargoLabel(): 'WOOD' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 6 GetCargoIncome(100, 10): 60 GetCargoIncome(10, 100): 5 GetRoadVehicleTypeForCargo(): 1 Cargo 8 IsValidCargo(): true GetCargoLabel(): 'IORE' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 6 GetCargoIncome(100, 10): 62 GetCargoIncome(10, 100): 5 GetRoadVehicleTypeForCargo(): 1 Cargo 9 IsValidCargo(): true GetCargoLabel(): 'STEL' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 6 GetCargoIncome(100, 10): 69 GetCargoIncome(10, 100): 6 GetRoadVehicleTypeForCargo(): 1 Cargo 10 IsValidCargo(): true GetCargoLabel(): 'VALU' IsFreight(): true HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): 0 GetCargoIncome(10, 10): 9 GetCargoIncome(100, 10): 90 GetCargoIncome(10, 100): 7 GetRoadVehicleTypeForCargo(): 1 Cargo 11 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' IsFreight(): false HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): -1 GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 GetRoadVehicleTypeForCargo(): 1 Cargo 12 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' IsFreight(): false HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): -1 GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 GetRoadVehicleTypeForCargo(): 1 Cargo 13 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' IsFreight(): false HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): -1 GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 GetRoadVehicleTypeForCargo(): 1 Cargo 14 IsValidCargo(): false GetCargoLabel(): '(null : 0x00000000)' IsFreight(): false HasCargoClass(): false GetTownEffect(): 0 GetCargoIncome(0, 0): -1 GetCargoIncome(10, 10): -1 GetCargoIncome(100, 10): -1 GetCargoIncome(10, 100): -1 GetRoadVehicleTypeForCargo(): 1 --CargoList-- Count(): 11 IsFreight ListDump: 10 => 1 9 => 1 8 => 1 7 => 1 6 => 1 5 => 1 4 => 1 3 => 1 1 => 1 2 => 0 0 => 0 CargoIncomes(100, 100) ListDump: 10 => 74 5 => 62 1 => 62 9 => 60 8 => 54 7 => 54 3 => 50 2 => 50 6 => 49 4 => 41 0 => 30 --CargoList_IndustryAccepting-- Count(): 1 ListDump: 7 --CargoList_IndustryProducing-- Count(): 1 ListDump: 7 --Engine-- Engine -1 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 0 IsValidEngine(): true GetName(): Kirby Paul Tank (Steam) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): 75 GetMaxSpeed(): 64 GetPrice(): 8203 GetMaxAge(): 5490 GetRunningCost(): 820 GetPower(): 300 GetWeight(): 47 GetMaxTractiveEffort(): 139 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 1 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 2 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 3 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 4 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 5 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 6 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 7 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 8 IsValidEngine(): true GetName(): Chaney 'Jubilee' (Steam) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): 80 GetMaxSpeed(): 112 GetPrice(): 15234 GetMaxAge(): 7686 GetRunningCost(): 1968 GetPower(): 1000 GetWeight(): 131 GetMaxTractiveEffort(): 388 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 9 IsValidEngine(): true GetName(): Ginzu 'A4' (Steam) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): 84 GetMaxSpeed(): 128 GetPrice(): 22265 GetMaxAge(): 7320 GetRunningCost(): 2296 GetPower(): 1200 GetWeight(): 162 GetMaxTractiveEffort(): 480 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 10 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 11 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 12 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 13 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 14 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 15 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 16 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 17 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 18 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 19 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 20 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 21 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 22 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 23 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 24 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 25 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 26 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 27 IsValidEngine(): true GetName(): Passenger Carriage GetCargoType(): 0 CanRefitCargo(): false GetCapacity(): 40 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1447 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 25 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 28 IsValidEngine(): true GetName(): Mail Van GetCargoType(): 2 CanRefitCargo(): false GetCapacity(): 30 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1335 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 21 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 29 IsValidEngine(): true GetName(): Coal Truck GetCargoType(): 1 CanRefitCargo(): true GetCapacity(): 30 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1031 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 18 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 30 IsValidEngine(): true GetName(): Oil Tanker GetCargoType(): 3 CanRefitCargo(): false GetCapacity(): 30 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1171 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 24 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 31 IsValidEngine(): true GetName(): Livestock Van GetCargoType(): 4 CanRefitCargo(): false GetCapacity(): 25 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1125 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 20 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 32 IsValidEngine(): true GetName(): Goods Van GetCargoType(): 5 CanRefitCargo(): false GetCapacity(): 25 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1113 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 21 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 33 IsValidEngine(): true GetName(): Grain Hopper GetCargoType(): 6 CanRefitCargo(): false GetCapacity(): 30 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1066 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 19 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 34 IsValidEngine(): true GetName(): Wood Truck GetCargoType(): 7 CanRefitCargo(): false GetCapacity(): 30 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1060 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 16 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 35 IsValidEngine(): true GetName(): Iron Ore Hopper GetCargoType(): 8 CanRefitCargo(): false GetCapacity(): 30 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1048 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 19 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 36 IsValidEngine(): true GetName(): Steel Truck GetCargoType(): 9 CanRefitCargo(): false GetCapacity(): 20 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1148 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 18 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 37 IsValidEngine(): true GetName(): Armoured Van GetCargoType(): 10 CanRefitCargo(): false GetCapacity(): 20 GetReliability(): -1 GetMaxSpeed(): 0 GetPrice(): 1494 GetMaxAge(): -1 GetRunningCost(): 0 GetPower(): -1 GetWeight(): 30 GetMaxTractiveEffort(): -1 GetVehicleType(): 0 GetRailType(): 0 GetRoadType(): -1 GetPlaneType(): -1 Engine 38 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 39 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 40 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 41 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 42 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 43 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 44 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 45 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 46 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 47 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 48 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 49 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 50 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 51 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 52 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 53 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 54 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 55 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 56 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 57 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 58 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 59 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 60 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 61 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 62 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 63 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 64 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 65 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 66 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 67 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 68 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 69 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 70 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 71 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 72 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 73 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 74 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 75 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 76 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 77 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 78 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 79 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 80 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 81 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 82 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 83 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 84 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 85 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 86 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 87 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 88 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 89 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 90 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 91 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 92 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 93 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 94 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 95 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 96 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 97 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 98 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 99 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 100 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 101 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 102 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 103 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 104 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 105 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 106 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 107 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 108 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 109 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 110 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 111 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 112 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 113 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 114 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 115 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 116 IsValidEngine(): true GetName(): MPS Regal Bus GetCargoType(): 0 CanRefitCargo(): false GetCapacity(): 31 GetReliability(): 78 GetMaxSpeed(): 56 GetPrice(): 4921 GetMaxAge(): 4392 GetRunningCost(): 426 GetPower(): 90 GetWeight(): 10 GetMaxTractiveEffort(): 29 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 117 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 118 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 119 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 120 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 121 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 122 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 123 IsValidEngine(): true GetName(): Balogh Coal Truck GetCargoType(): 1 CanRefitCargo(): true GetCapacity(): 20 GetReliability(): 77 GetMaxSpeed(): 48 GetPrice(): 4429 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 124 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 125 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 126 IsValidEngine(): true GetName(): MPS Mail Truck GetCargoType(): 2 CanRefitCargo(): false GetCapacity(): 22 GetReliability(): 92 GetMaxSpeed(): 48 GetPrice(): 4716 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 127 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 128 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 129 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 130 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 131 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 132 IsValidEngine(): true GetName(): Witcombe Oil Tanker GetCargoType(): 3 CanRefitCargo(): false GetCapacity(): 21 GetReliability(): 98 GetMaxSpeed(): 48 GetPrice(): 4511 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 133 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 134 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 135 IsValidEngine(): true GetName(): Talbott Livestock Van GetCargoType(): 4 CanRefitCargo(): false GetCapacity(): 14 GetReliability(): 97 GetMaxSpeed(): 48 GetPrice(): 4306 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 136 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 137 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 138 IsValidEngine(): true GetName(): Balogh Goods Truck GetCargoType(): 5 CanRefitCargo(): false GetCapacity(): 14 GetReliability(): 87 GetMaxSpeed(): 48 GetPrice(): 4388 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 139 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 140 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 141 IsValidEngine(): true GetName(): Hereford Grain Truck GetCargoType(): 6 CanRefitCargo(): false GetCapacity(): 20 GetReliability(): 97 GetMaxSpeed(): 48 GetPrice(): 4675 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 142 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 143 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 144 IsValidEngine(): true GetName(): Witcombe Wood Truck GetCargoType(): 7 CanRefitCargo(): false GetCapacity(): 20 GetReliability(): 98 GetMaxSpeed(): 48 GetPrice(): 4839 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 145 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 146 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 147 IsValidEngine(): true GetName(): MPS Iron Ore Truck GetCargoType(): 8 CanRefitCargo(): false GetCapacity(): 22 GetReliability(): 97 GetMaxSpeed(): 48 GetPrice(): 4962 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 148 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 149 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 150 IsValidEngine(): true GetName(): Balogh Steel Truck GetCargoType(): 9 CanRefitCargo(): false GetCapacity(): 15 GetReliability(): 82 GetMaxSpeed(): 48 GetPrice(): 4593 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 151 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 152 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 153 IsValidEngine(): true GetName(): Balogh Armoured Truck GetCargoType(): 10 CanRefitCargo(): false GetCapacity(): 12 GetReliability(): 76 GetMaxSpeed(): 48 GetPrice(): 5947 GetMaxAge(): 5490 GetRunningCost(): 421 GetPower(): 120 GetWeight(): 9 GetMaxTractiveEffort(): 26 GetVehicleType(): 1 GetRailType(): 255 GetRoadType(): 0 GetPlaneType(): -1 Engine 154 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 155 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 156 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 157 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 158 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 159 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 160 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 161 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 162 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 163 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 164 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 165 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 166 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 167 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 168 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 169 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 170 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 171 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 172 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 173 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 174 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 175 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 176 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 177 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 178 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 179 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 180 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 181 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 182 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 183 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 184 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 185 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 186 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 187 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 188 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 189 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 190 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 191 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 192 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 193 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 194 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 195 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 196 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 197 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 198 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 199 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 200 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 201 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 202 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 203 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 204 IsValidEngine(): true GetName(): MPS Oil Tanker GetCargoType(): 3 CanRefitCargo(): false GetCapacity(): 220 GetReliability(): 99 GetMaxSpeed(): 24 GetPrice(): 30468 GetMaxAge(): 10980 GetRunningCost(): 2296 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 2 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 205 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 206 IsValidEngine(): true GetName(): MPS Passenger Ferry GetCargoType(): 0 CanRefitCargo(): false GetCapacity(): 100 GetReliability(): 88 GetMaxSpeed(): 32 GetPrice(): 18281 GetMaxAge(): 10980 GetRunningCost(): 1476 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 2 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 207 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 208 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 209 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 210 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 211 IsValidEngine(): true GetName(): Yate Cargo Ship GetCargoType(): 5 CanRefitCargo(): true GetCapacity(): 160 GetReliability(): 81 GetMaxSpeed(): 24 GetPrice(): 24375 GetMaxAge(): 10980 GetRunningCost(): 2460 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 2 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 212 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 213 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 214 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 215 IsValidEngine(): true GetName(): Sampson U52 GetCargoType(): 0 CanRefitCargo(): false GetCapacity(): 25 GetReliability(): 58 GetMaxSpeed(): 236 GetPrice(): 28710 GetMaxAge(): 7320 GetRunningCost(): 2390 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 3 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): 1 Engine 216 IsValidEngine(): true GetName(): Coleman Count GetCargoType(): 0 CanRefitCargo(): false GetCapacity(): 65 GetReliability(): 95 GetMaxSpeed(): 236 GetPrice(): 30761 GetMaxAge(): 8784 GetRunningCost(): 2812 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 3 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): 1 Engine 217 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 218 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 219 IsValidEngine(): true GetName(): Bakewell Cotswald LB-3 GetCargoType(): 0 CanRefitCargo(): false GetCapacity(): 30 GetReliability(): 77 GetMaxSpeed(): 236 GetPrice(): 30761 GetMaxAge(): 10980 GetRunningCost(): 2756 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 3 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): 1 Engine 220 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 221 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 222 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 223 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 224 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 225 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 226 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 227 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 228 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 229 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 230 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 231 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 232 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 233 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 234 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 235 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 236 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 237 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 238 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 239 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 240 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 241 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 242 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 243 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 244 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 245 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 246 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 247 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 248 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 249 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 250 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 251 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 252 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 253 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 254 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 255 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Engine 256 IsValidEngine(): false GetName(): (null : 0x00000000) GetCargoType(): 255 CanRefitCargo(): false GetCapacity(): -1 GetReliability(): -1 GetMaxSpeed(): -1 GetPrice(): -1 GetMaxAge(): -1 GetRunningCost(): -1 GetPower(): -1 GetWeight(): -1 GetMaxTractiveEffort(): -1 GetVehicleType(): 255 GetRailType(): 255 GetRoadType(): -1 GetPlaneType(): -1 Valid Engines: 31 --EngineList-- Count(): 11 CargoType ListDump: 153 => 10 150 => 9 147 => 8 144 => 7 141 => 6 138 => 5 135 => 4 132 => 3 126 => 2 123 => 1 116 => 0 Capacity ListDump: 116 => 31 147 => 22 126 => 22 132 => 21 144 => 20 141 => 20 123 => 20 150 => 15 138 => 14 135 => 14 153 => 12 Reliability ListDump: 144 => 98 132 => 98 147 => 97 141 => 97 135 => 97 126 => 92 138 => 87 150 => 82 116 => 78 123 => 77 153 => 76 MaxSpeed ListDump: 116 => 56 153 => 48 150 => 48 147 => 48 144 => 48 141 => 48 138 => 48 135 => 48 132 => 48 126 => 48 123 => 48 Price ListDump: 153 => 5947 147 => 4962 116 => 4921 144 => 4839 126 => 4716 141 => 4675 150 => 4593 132 => 4511 123 => 4429 138 => 4388 135 => 4306 --Group-- SetAutoReplace(): false GetEngineReplacement(): 65535 GetNumEngines(): 0 AIRoad.BuildRoadDepot(): true AIVehicle.BuildVehicle(): 12 GetNumEngines(): 1 CreateGroup(): 0 MoveVehicle(): true GetNumEngines(): 1 GetNumEngines(): 1 GetNumEngines(): 0 GetName(): Group 0 GetName(): (null : 0x00000000) AIVehicle.SellVehicle(): true AITile.DemolishTile(): true HasWagonRemoval(): false EnableWagonRemoval(): true HasWagonRemoval(): true EnableWagonRemoval(): true EnableWagonRemoval(): true HasWagonRemoval(): false --Industry-- GetIndustryCount(): 71 Industry 0 IsValidIndustry(): true GetName(): Kennville Oil Refinery GetLocation(): 19695 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 1 IsValidIndustry(): true GetName(): Satown Forest GetLocation(): 45122 IsCargoAccepted(): 0 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 2 IsValidIndustry(): true GetName(): Fudhattan Forest GetLocation(): 41929 IsCargoAccepted(): 0 GetLastMonthProduction(): 108 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 3 IsValidIndustry(): true GetName(): Beningville Forest GetLocation(): 44640 IsCargoAccepted(): 0 GetLastMonthProduction(): 80 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 4 IsValidIndustry(): true GetName(): Nefingbridge Forest GetLocation(): 8793 IsCargoAccepted(): 0 GetLastMonthProduction(): 135 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 5 IsValidIndustry(): true GetName(): Hutford Forest GetLocation(): 55429 IsCargoAccepted(): 0 GetLastMonthProduction(): 99 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 6 IsValidIndustry(): true GetName(): Great Hinninghall Forest GetLocation(): 6533 IsCargoAccepted(): 0 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 7 IsValidIndustry(): true GetName(): Tonston Forest GetLocation(): 27609 IsCargoAccepted(): 0 GetLastMonthProduction(): 115 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 8 IsValidIndustry(): true GetName(): Planfield Sawmill GetLocation(): 17318 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 9 IsValidIndustry(): true GetName(): Hutford Sawmill GetLocation(): 60050 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 10 IsValidIndustry(): true GetName(): Natborough Sawmill GetLocation(): 54184 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 11 IsValidIndustry(): true GetName(): Prundinghall Sawmill GetLocation(): 48499 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 12 IsValidIndustry(): true GetName(): Fratston Sawmill GetLocation(): 51419 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 13 IsValidIndustry(): true GetName(): Fort Frindston Sawmill GetLocation(): 15950 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 14 IsValidIndustry(): true GetName(): Grinnway Sawmill GetLocation(): 20001 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 15 IsValidIndustry(): true GetName(): Trenningville Coal Mine GetLocation(): 51854 IsCargoAccepted(): 0 GetLastMonthProduction(): 126 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 16 IsValidIndustry(): true GetName(): Kennville Coal Mine GetLocation(): 11734 IsCargoAccepted(): 0 GetLastMonthProduction(): 99 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 17 IsValidIndustry(): true GetName(): Great Hinninghall Coal Mine GetLocation(): 13947 IsCargoAccepted(): 0 GetLastMonthProduction(): 171 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 18 IsValidIndustry(): true GetName(): Little Frutford Coal Mine GetLocation(): 23682 IsCargoAccepted(): 0 GetLastMonthProduction(): 126 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 19 IsValidIndustry(): true GetName(): Hutford Coal Mine GetLocation(): 57429 IsCargoAccepted(): 0 GetLastMonthProduction(): 99 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 20 IsValidIndustry(): true GetName(): Mendston Coal Mine GetLocation(): 8562 IsCargoAccepted(): 0 GetLastMonthProduction(): 171 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 21 IsValidIndustry(): true GetName(): Tonston Coal Mine GetLocation(): 29147 IsCargoAccepted(): 0 GetLastMonthProduction(): 117 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 22 IsValidIndustry(): true GetName(): Quarfingfield Coal Mine GetLocation(): 27822 IsCargoAccepted(): 0 GetLastMonthProduction(): 153 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 23 IsValidIndustry(): true GetName(): Muningville Coal Mine GetLocation(): 43035 IsCargoAccepted(): 0 GetLastMonthProduction(): 90 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 24 IsValidIndustry(): true GetName(): Grinnway Coal Mine GetLocation(): 17943 IsCargoAccepted(): 0 GetLastMonthProduction(): 40 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 25 IsValidIndustry(): true GetName(): Satown Power Station GetLocation(): 48182 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 26 IsValidIndustry(): true GetName(): Tunford Power Station GetLocation(): 33934 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 27 IsValidIndustry(): true GetName(): Quarfingfield Power Station GetLocation(): 23714 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 28 IsValidIndustry(): true GetName(): Kennville Power Station GetLocation(): 20170 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 29 IsValidIndustry(): true GetName(): Nuntburg Power Station GetLocation(): 6685 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 30 IsValidIndustry(): true GetName(): Beburg Power Station GetLocation(): 29022 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 31 IsValidIndustry(): true GetName(): Beningville Power Station GetLocation(): 44160 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 32 IsValidIndustry(): true GetName(): Fort Frindston Oil Wells GetLocation(): 14701 IsCargoAccepted(): 0 GetLastMonthProduction(): 108 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 33 IsValidIndustry(): true GetName(): Nuntburg Oil Wells GetLocation(): 5659 IsCargoAccepted(): 0 GetLastMonthProduction(): 40 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 34 IsValidIndustry(): true GetName(): Beningville Oil Wells GetLocation(): 36728 IsCargoAccepted(): 0 GetLastMonthProduction(): 64 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 35 IsValidIndustry(): true GetName(): Grinnway Oil Wells GetLocation(): 14361 IsCargoAccepted(): 0 GetLastMonthProduction(): 63 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 36 IsValidIndustry(): true GetName(): Muningville Oil Wells GetLocation(): 36908 IsCargoAccepted(): 0 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 37 IsValidIndustry(): true GetName(): Tonston Oil Wells GetLocation(): 34237 IsCargoAccepted(): 0 GetLastMonthProduction(): 108 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 38 IsValidIndustry(): true GetName(): Fort Frindston Iron Ore Mine GetLocation(): 17742 IsCargoAccepted(): 0 GetLastMonthProduction(): 108 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 39 IsValidIndustry(): true GetName(): Tonston Iron Ore Mine GetLocation(): 25545 IsCargoAccepted(): 0 GetLastMonthProduction(): 30 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 40 IsValidIndustry(): true GetName(): Fudhattan Iron Ore Mine GetLocation(): 47838 IsCargoAccepted(): 0 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 41 IsValidIndustry(): true GetName(): Nuntburg Iron Ore Mine GetLocation(): 8763 IsCargoAccepted(): 0 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 42 IsValidIndustry(): true GetName(): Larborough Iron Ore Mine GetLocation(): 60866 IsCargoAccepted(): 0 GetLastMonthProduction(): 81 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 43 IsValidIndustry(): true GetName(): Tunford Iron Ore Mine GetLocation(): 41155 IsCargoAccepted(): 0 GetLastMonthProduction(): 108 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 44 IsValidIndustry(): true GetName(): Chenfingbourne Iron Ore Mine GetLocation(): 19529 IsCargoAccepted(): 0 GetLastMonthProduction(): 135 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 45 IsValidIndustry(): true GetName(): Natborough Farm GetLocation(): 52931 IsCargoAccepted(): 0 GetLastMonthProduction(): 81 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 81 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 46 IsValidIndustry(): true GetName(): Larborough Farm GetLocation(): 59604 IsCargoAccepted(): 0 GetLastMonthProduction(): 81 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 50 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 47 IsValidIndustry(): true GetName(): Chenfingbourne Farm GetLocation(): 24366 IsCargoAccepted(): 0 GetLastMonthProduction(): 63 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 30 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 48 IsValidIndustry(): true GetName(): Wruntown Farm GetLocation(): 36847 IsCargoAccepted(): 0 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 126 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 49 IsValidIndustry(): true GetName(): Little Frutford Farm GetLocation(): 28287 IsCargoAccepted(): 0 GetLastMonthProduction(): 90 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 50 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 50 IsValidIndustry(): true GetName(): Hutford Farm GetLocation(): 57432 IsCargoAccepted(): 0 GetLastMonthProduction(): 117 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 90 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 51 IsValidIndustry(): true GetName(): Tonston Farm GetLocation(): 23519 IsCargoAccepted(): 0 GetLastMonthProduction(): 81 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 54 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 52 IsValidIndustry(): true GetName(): Nuntburg Farm GetLocation(): 10773 IsCargoAccepted(): 0 GetLastMonthProduction(): 126 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 53 IsValidIndustry(): true GetName(): Satown Farm GetLocation(): 48206 IsCargoAccepted(): 0 GetLastMonthProduction(): 40 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 40 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 54 IsValidIndustry(): true GetName(): Quarfingfield Farm GetLocation(): 24005 IsCargoAccepted(): 0 GetLastMonthProduction(): 72 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): 81 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 Industry 55 IsValidIndustry(): true GetName(): Little Frutford Steel Mill GetLocation(): 21107 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 56 IsValidIndustry(): true GetName(): Quarfingfield Steel Mill GetLocation(): 23727 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 57 IsValidIndustry(): true GetName(): Beburg Steel Mill GetLocation(): 41813 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 58 IsValidIndustry(): true GetName(): Franinghead Steel Mill GetLocation(): 8852 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 59 IsValidIndustry(): true GetName(): Larborough Steel Mill GetLocation(): 59867 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 60 IsValidIndustry(): true GetName(): Satown Steel Mill GetLocation(): 55360 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 61 IsValidIndustry(): true GetName(): Fratston Steel Mill GetLocation(): 52953 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 62 IsValidIndustry(): true GetName(): Chenfingbourne Factory GetLocation(): 24893 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 63 IsValidIndustry(): true GetName(): Fort Frindston Factory GetLocation(): 20819 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 64 IsValidIndustry(): true GetName(): Fudhattan Factory GetLocation(): 46278 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 65 IsValidIndustry(): true GetName(): Prundinghall Factory GetLocation(): 53096 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 66 IsValidIndustry(): true GetName(): Kennville Factory GetLocation(): 14818 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 67 IsValidIndustry(): true GetName(): Muningville Factory GetLocation(): 34375 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 68 IsValidIndustry(): true GetName(): Trenningville Factory GetLocation(): 44181 IsCargoAccepted(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 69 IsValidIndustry(): true GetName(): Wruntown Oil Refinery GetLocation(): 39663 IsCargoAccepted(): 0 GetLastMonthProduction(): 0 GetLastMonthTransported(): 0 GetStockpiledCargo(): -1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Industry 70 IsValidIndustry(): true GetName(): Mendston Power Station GetLocation(): 6498 IsCargoAccepted(): 1 GetLastMonthProduction(): -1 GetLastMonthTransported(): -1 GetStockpiledCargo(): 0 Valid Industries: 71 GetIndustryCount(): 71 GetIndustryID(): 65535 GetIndustryID(): 0 --IndustryList-- Count(): 71 Location ListDump: 42 => 60866 9 => 60050 59 => 59867 46 => 59604 50 => 57432 19 => 57429 5 => 55429 60 => 55360 10 => 54184 65 => 53096 61 => 52953 45 => 52931 15 => 51854 12 => 51419 11 => 48499 53 => 48206 25 => 48182 40 => 47838 64 => 46278 1 => 45122 3 => 44640 68 => 44181 31 => 44160 23 => 43035 2 => 41929 57 => 41813 43 => 41155 69 => 39663 36 => 36908 48 => 36847 34 => 36728 67 => 34375 37 => 34237 26 => 33934 21 => 29147 30 => 29022 49 => 28287 22 => 27822 7 => 27609 39 => 25545 62 => 24893 47 => 24366 54 => 24005 56 => 23727 27 => 23714 18 => 23682 51 => 23519 55 => 21107 63 => 20819 28 => 20170 14 => 20001 0 => 19695 44 => 19529 24 => 17943 38 => 17742 8 => 17318 13 => 15950 66 => 14818 32 => 14701 35 => 14361 17 => 13947 16 => 11734 52 => 10773 58 => 8852 4 => 8793 41 => 8763 20 => 8562 29 => 6685 6 => 6533 70 => 6498 33 => 5659 DistanceManhattanToTile(30000) ListDump: 59 => 287 46 => 279 42 => 266 61 => 258 12 => 254 40 => 243 66 => 238 16 => 238 45 => 236 0 => 232 69 => 228 48 => 217 9 => 215 10 => 214 64 => 213 51 => 201 2 => 199 28 => 193 43 => 190 5 => 184 58 => 183 15 => 179 7 => 179 6 => 177 21 => 175 54 => 173 39 => 171 8 => 168 37 => 157 68 => 156 56 => 152 20 => 150 50 => 147 65 => 146 19 => 144 70 => 142 27 => 139 11 => 139 17 => 138 31 => 135 22 => 135 4 => 124 32 => 121 33 => 116 60 => 115 29 => 110 26 => 109 18 => 107 3 => 105 55 => 102 52 => 102 53 => 101 34 => 98 41 => 94 49 => 86 13 => 85 35 => 84 57 => 83 38 => 78 25 => 77 1 => 77 24 => 72 23 => 72 63 => 71 44 => 66 14 => 54 30 => 50 67 => 40 62 => 33 36 => 31 47 => 24 DistanceSquareToTile(30000) ListDump: 59 => 42697 46 => 40121 0 => 38162 69 => 37850 48 => 37157 61 => 36482 12 => 36130 42 => 35716 66 => 35284 40 => 35037 16 => 32740 51 => 31301 45 => 29530 21 => 29257 7 => 28661 64 => 26469 2 => 25525 28 => 25237 39 => 23733 43 => 23458 9 => 23293 10 => 23236 54 => 22777 37 => 20137 5 => 17026 58 => 16889 56 => 16754 8 => 16424 15 => 16061 22 => 15957 6 => 15689 27 => 13621 68 => 13226 50 => 13049 19 => 12818 20 => 11412 65 => 11236 70 => 10964 60 => 10057 11 => 9673 17 => 9594 33 => 9466 31 => 9425 26 => 9061 29 => 8642 4 => 8570 18 => 7349 32 => 7321 41 => 7010 52 => 6354 49 => 6290 53 => 5941 34 => 5860 55 => 5714 3 => 5553 25 => 5077 35 => 4250 13 => 3925 1 => 3805 57 => 3485 38 => 3204 23 => 3042 24 => 2834 63 => 2521 44 => 2306 30 => 2132 14 => 1746 67 => 818 36 => 745 62 => 569 47 => 488 GetAmountOfStationsAround(30000) ListDump: 70 => 0 69 => 0 68 => 0 67 => 0 66 => 0 65 => 0 64 => 0 63 => 0 62 => 0 61 => 0 60 => 0 59 => 0 58 => 0 57 => 0 56 => 0 55 => 0 54 => 0 53 => 0 52 => 0 51 => 0 50 => 0 49 => 0 48 => 0 47 => 0 46 => 0 45 => 0 44 => 0 43 => 0 42 => 0 41 => 0 40 => 0 39 => 0 38 => 0 37 => 0 36 => 0 35 => 0 34 => 0 33 => 0 32 => 0 31 => 0 30 => 0 29 => 0 28 => 0 27 => 0 26 => 0 25 => 0 24 => 0 23 => 0 22 => 0 21 => 0 20 => 0 19 => 0 18 => 0 17 => 0 16 => 0 15 => 0 14 => 0 13 => 0 12 => 0 11 => 0 10 => 0 9 => 0 8 => 0 7 => 0 6 => 0 5 => 0 4 => 0 3 => 0 2 => 0 1 => 0 0 => 0 CargoAccepted(1) ListDump: 70 => 1 31 => 1 30 => 1 29 => 1 28 => 1 27 => 1 26 => 1 25 => 1 69 => 0 68 => 0 67 => 0 66 => 0 65 => 0 64 => 0 63 => 0 62 => 0 61 => 0 60 => 0 59 => 0 58 => 0 57 => 0 56 => 0 55 => 0 54 => 0 53 => 0 52 => 0 51 => 0 50 => 0 49 => 0 48 => 0 47 => 0 46 => 0 45 => 0 44 => 0 43 => 0 42 => 0 41 => 0 40 => 0 39 => 0 38 => 0 37 => 0 36 => 0 35 => 0 34 => 0 33 => 0 32 => 0 24 => 0 23 => 0 22 => 0 21 => 0 20 => 0 19 => 0 18 => 0 17 => 0 16 => 0 15 => 0 14 => 0 13 => 0 12 => 0 11 => 0 10 => 0 9 => 0 8 => 0 7 => 0 6 => 0 5 => 0 4 => 0 3 => 0 2 => 0 1 => 0 0 => 0 --IndustryList_CargoAccepting-- Count(): 8 Location ListDump: 25 => 48182 31 => 44160 26 => 33934 30 => 29022 27 => 23714 28 => 20170 29 => 6685 70 => 6498 --IndustryList_CargoProducing-- Count(): 10 Location ListDump: 19 => 57429 15 => 51854 23 => 43035 21 => 29147 22 => 27822 18 => 23682 24 => 17943 17 => 13947 16 => 11734 20 => 8562 --IndustryTypeList-- Count(): 12 Location ListDump: Id: 9 IsRawIndustry(): true ProductionCanIncrease(): true GetConstructionCost(): -1 GetName(): Farm CanBuildIndustry(): false CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 5 IsRawIndustry(): true ProductionCanIncrease(): true GetConstructionCost(): -1 GetName(): Oil Rig CanBuildIndustry(): false CanProspectIndustry(): false IsBuiltOnWater(): true HasHeliport(): true HasDock(): true Id: 12 IsRawIndustry(): false ProductionCanIncrease(): true GetConstructionCost(): 747070 GetName(): Bank CanBuildIndustry(): true CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 11 IsRawIndustry(): true ProductionCanIncrease(): false GetConstructionCost(): -1 GetName(): Oil Wells CanBuildIndustry(): false CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 1 IsRawIndustry(): false ProductionCanIncrease(): true GetConstructionCost(): 703125 GetName(): Power Station CanBuildIndustry(): true CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 3 IsRawIndustry(): true ProductionCanIncrease(): true GetConstructionCost(): -1 GetName(): Forest CanBuildIndustry(): false CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 2 IsRawIndustry(): false ProductionCanIncrease(): true GetConstructionCost(): 656250 GetName(): Sawmill CanBuildIndustry(): true CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 18 IsRawIndustry(): true ProductionCanIncrease(): true GetConstructionCost(): -1 GetName(): Iron Ore Mine CanBuildIndustry(): false CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 0 IsRawIndustry(): true ProductionCanIncrease(): true GetConstructionCost(): -1 GetName(): Coal Mine CanBuildIndustry(): false CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 8 IsRawIndustry(): false ProductionCanIncrease(): true GetConstructionCost(): 629882 GetName(): Steel Mill CanBuildIndustry(): true CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 4 IsRawIndustry(): false ProductionCanIncrease(): true GetConstructionCost(): 714843 GetName(): Oil Refinery CanBuildIndustry(): true CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false Id: 6 IsRawIndustry(): false ProductionCanIncrease(): true GetConstructionCost(): 609375 GetName(): Factory CanBuildIndustry(): true CanProspectIndustry(): false IsBuiltOnWater(): false HasHeliport(): false HasDock(): false --Map-- GetMapSize(): 65536 GetMapSizeX(): 256 GetMapSizeY(): 256 GetTileX(123): 123 GetTileY(123): 0 GetTileIndex(): 123 GetTileIndex(): 31488 GetTileIndex(): 0 GetTileIndex(): -257 GetTileIndex(): 2570000 IsValidTile(123): true GetTileX(124): 124 GetTileY(124): 0 IsValidTile(124): true IsValidTile(0): true IsValidTile(-1): false IsValidTile(): false IsValidTile(): true DemolishTile(): false DemolishTile(): true Distance DistanceManhattan(): 54 DistanceMax(): 39 DistanceSquare(): 1746 DistanceFromEdge(): 16 --AIMarine-- IsWaterDepotTile(): false IsDockTile(): false IsBuoyTile(): false IsLockTile(): false IsCanalTile(): false GetBankBalance(): 479851 BuildWaterDepot(): true BuildDock(): true BuildBuoy(): true BuildLock(): true HasTransportType(): false BuildCanal(): true HasTransportType(): true IsWaterDepotTile(): true IsDockTile(): true IsBuoyTile(): true IsLockTile(): true IsCanalTile(): true GetBankBalance(): 465257 --AIWaypointList(BUOY)-- Count(): 1 Location ListDump: 28481 HasWaypointType: false true false RemoveWaterDepot(): true RemoveDock(): true RemoveBuoy(): true RemoveLock(): true RemoveCanal(): true IsWaterDepotTile(): false IsDockTile(): false IsBuoyTile(): false IsLockTile(): false IsCanalTile(): false GetBankBalance(): 459862 BuildWaterDepot(): true BuildDock(): true --Prices-- -Rail- 0,BT_TRACK: 75 0,BT_SIGNAL: 48 0,BT_DEPOT: 450 0,BT_STATION: 285 0,BT_WAYPOINT: 450 1,BT_TRACK: -1 1,BT_SIGNAL: -1 1,BT_DEPOT: -1 1,BT_STATION: -1 1,BT_WAYPOINT: -1 -Road- ROADTYPE_ROAD,BT_ROAD: 71 ROADTYPE_ROAD,BT_DEPOT: 375 ROADTYPE_ROAD,BT_BUS_STOP: 150 ROADTYPE_ROAD,BT_TRUCK_STOP: 150 ROADTYPE_TRAM,BT_ROAD: -1 ROADTYPE_TRAM,BT_DEPOT: -1 ROADTYPE_TRAM,BT_BUS_STOP: -1 ROADTYPE_TRAM,BT_TRUCK_STOP: -1 -Water- BT_DOCK: 262 BT_DEPOT: 525 BT_BUOY: 262 -Tile- BT_FOUNDATION: 187 BT_TERRAFORM: 187 BT_BUILD_TREES: 15 BT_CLEAR_GRASS: 15 BT_CLEAR_ROUGH: 30 BT_CLEAR_ROCKY: 150 BT_CLEAR_FIELDS: 375 BT_CLEAR_HOUSE: 1200 --Rail-- IsRailTile(): false BuildRailTrack(): true BuildSignal(): true RemoveRailTrack(): false RemoveRailTrack(): true BuildRail(): true HasTransportType(): true HasTransportType(): false RemoveRail(): true Depot IsRailTile(): false BuildRailDepot(): false BuildRailDepot(): false BuildRailDepot(): true BuildRailDepot(): false GetRailDepotFrontTile(): 33412 IsBuildable(): false DepotList Count(): 1 Depot distance from (0,0) ListDump: 33411 => 261 RemoveDepot(): true BuildRailDepot(): true Station BuildRailStation(): false BuildRailStation(): true IsRailStationTile(): false IsRailStationTile(): true IsRailStationTile(): true RemoveRailStationTileRectangle():true IsRailStationTile(): false IsRailStationTile(): true IsRailStationTile(): false DemolishTile(): true IsRailStationTile(): false IsRailStationTile(): false IsRailStationTile(): false --RailTypeList-- Count(): 1 ListDump: RailType: 0 GetName(): Railway construction IsRailTypeAvailable(): true GetMaxSpeed(): 0 --Road-- Road IsRoadTile(): false BuildRoad(): false BuildRoad(): false HasTransportType(): false BuildRoad(): true HasTransportType(): true AreRoadTilesConnected(): true IsRoadTile(): true HasRoadType(Road): true HasRoadType(Tram): false GetNeighbourRoadCount(): 2 RemoveRoad(): false RemoveRoad(): true RemoveRoad(): false RemoveRoad(): true BuildOneWayRoad(): true AreRoadTilesConnected(): true AreRoadTilesConnected(): false BuildOneWayRoad(): true AreRoadTilesConnected(): false AreRoadTilesConnected(): false BuildOneWayRoad(): true BuildOneWayRoad(): true AreRoadTilesConnected(): true AreRoadTilesConnected(): true RemoveRoad(): true IsRoadTypeAvailable(Road): true IsRoadTypeAvailable(Tram): false SetCurrentRoadType(Tram): (null : 0x00000000) GetCurrentRoadType(): 0 Depot IsRoadTile(): false BuildRoadDepot(): false BuildRoadDepot(): false BuildRoadDepot(): true BuildRoadDepot(): false HasRoadType(Road): true HasRoadType(Tram): false GetLastError(): 260 GetLastErrorString(): ERR_AREA_NOT_CLEAR GetErrorCategory(): 1 IsRoadTile(): false GetRoadDepotFrontTile(): 33412 IsRoadDepotTile(): true IsBuildable(): false DepotList Count(): 1 Depot distance from (0,0) ListDump: 33411 => 261 RemoveRoadDepot(): true RemoveRoadDepot(): false Station IsRoadTile(): false BuildRoadStation(): false BuildRoadStation(): false BuildRoadStation(): true BuildRoadStation(): true IsStationTile(): true IsStationTile(): false HasRoadType(Road): true HasRoadType(Tram): false IsRoadTile(): false GetDriveThroughBackTile(): -1 GetRoadStationFrontTile(): 33412 IsRoadStationTile(): true IsDriveThroughRoadStationTile: false RemoveRoadStation(): true RemoveRoadStation(): false Station Types BuildRoadStation(bus): true BuildRoadStation(truck): true BuildRoadStation(truck): true BuildRoadStation(bus): true BuildRoadStation(truck): true BuildDriveThroughRoadStation(bus-drive): true BuildDriveThroughRoadStation(truck-drive): true BuildDriveThroughRoadStation(bus-drive): true BuildDriveThroughRoadStation(truck-drive): true BuildRoadDepot(): true GetRoadStationFrontTile(): 33411 GetRoadStationFrontTile(): 33924 IsDriveThroughRoadStationTile: true IsBuildable(): false GetDriveThroughBackTile(): 33416 GetRoadStationFrontTile(): 33414 IsRoadTile(): true --Sign-- BuildSign(33410, 'Some Sign'): 0 BuildSign(33411, 'Test'): 1 SetName(1, 'Test2'): true BuildSign(33409, 'Some other Sign'): 2 RemoveSign(2): true Sign 0 IsValidSign(): true GetName(): Some Sign GetLocation(): 33410 Sign 1 IsValidSign(): true GetName(): Test2 GetLocation(): 33411 Valid Signs: 2 --Station-- IsValidStation(0): true IsValidStation(1000): false GetName(0): Beningville Airport SetName(0): true GetName(0): Look, a station GetLocation(1): 29253 GetLocation(1000): -1 GetStationID(33411): 4 GetStationID(34411): 65535 GetStationID(33411): 4 HasRoadType(3, TRAM): false HasRoadType(3, ROAD): false HasRoadType(33411, TRAM): false HasRoadType(33411, ROAD): true HasStationType(3, BUS): false HasStationType(3, TRAIN): false GetCoverageRadius(BUS): 3 GetCoverageRadius(TRUCK): 3 GetCoverageRadius(TRAIN): 4 GetNearestTown(): 15 GetNearestTown(): 65535 GetNearestTown(): 10 --CargoWaiting-- GetCargoWaiting(0, 0): 0 GetCargoWaitingFrom(0, 0, 0): 0 GetCargoWaitingVia(0, 0, 0): 0 GetCargoWaitingFromVia(0, 0, 0, 0): 0 GetCargoWaitingFromVia(0, 0, 1000, 0): -1 GetCargoWaitingFrom(0, 1000, 0): -1 GetCargoWaitingVia(0, 1000, 0): -1 GetCargoWaitingFromVia(0, 1000, 0, 0): -1 GetCargoWaitingFromVia(0, 1000, 1000, 0): -1 GetCargoWaiting(1000, 0): -1 GetCargoWaitingFrom(1000, 0, 0): -1 GetCargoWaitingVia(1000, 0, 0): -1 GetCargoWaitingFromVia(1000, 0, 0, 0): -1 GetCargoWaitingFromVia(1000, 0, 1000, 0): -1 GetCargoWaitingFrom(1000, 1000, 0): -1 GetCargoWaitingVia(1000, 1000, 0): -1 GetCargoWaitingFromVia(1000, 1000, 0, 0): -1 GetCargoWaitingFromVia(1000, 1000, 1000, 0): -1 GetCargoWaiting(0, 1000): -1 GetCargoWaitingFrom(0, 0, 1000): -1 GetCargoWaitingVia(0, 0, 1000): -1 GetCargoWaitingFromVia(0, 0, 0, 1000): -1 GetCargoWaitingFromVia(0, 0, 1000, 1000): -1 GetCargoWaitingFrom(0, 1000, 1000): -1 GetCargoWaitingVia(0, 1000, 1000): -1 GetCargoWaitingFromVia(0, 1000, 0, 1000): -1 GetCargoWaitingFromVia(0, 1000, 1000, 1000): -1 GetCargoWaiting(1000, 1000): -1 GetCargoWaitingFrom(1000, 0, 1000): -1 GetCargoWaitingVia(1000, 0, 1000): -1 GetCargoWaitingFromVia(1000, 0, 0, 1000): -1 GetCargoWaitingFromVia(1000, 0, 1000, 1000): -1 GetCargoWaitingFrom(1000, 1000, 1000): -1 GetCargoWaitingVia(1000, 1000, 1000): -1 GetCargoWaitingFromVia(1000, 1000, 0, 1000): -1 GetCargoWaitingFromVia(1000, 1000, 1000, 1000): -1 --CargoPlanned-- GetCargoPlanned(0, 0): 0 GetCargoPlannedFrom(0, 0, 0): 0 GetCargoPlannedVia(0, 0, 0): 0 GetCargoPlannedFromVia(0, 0, 0, 0): 0 GetCargoPlannedFromVia(0, 0, 1000, 0): -1 GetCargoPlannedFrom(0, 1000, 0): -1 GetCargoPlannedVia(0, 1000, 0): -1 GetCargoPlannedFromVia(0, 1000, 0, 0): -1 GetCargoPlannedFromVia(0, 1000, 1000, 0): -1 GetCargoPlanned(1000, 0): -1 GetCargoPlannedFrom(1000, 0, 0): -1 GetCargoPlannedVia(1000, 0, 0): -1 GetCargoPlannedFromVia(1000, 0, 0, 0): -1 GetCargoPlannedFromVia(1000, 0, 1000, 0): -1 GetCargoPlannedFrom(1000, 1000, 0): -1 GetCargoPlannedVia(1000, 1000, 0): -1 GetCargoPlannedFromVia(1000, 1000, 0, 0): -1 GetCargoPlannedFromVia(1000, 1000, 1000, 0): -1 GetCargoPlanned(0, 1000): -1 GetCargoPlannedFrom(0, 0, 1000): -1 GetCargoPlannedVia(0, 0, 1000): -1 GetCargoPlannedFromVia(0, 0, 0, 1000): -1 GetCargoPlannedFromVia(0, 0, 1000, 1000): -1 GetCargoPlannedFrom(0, 1000, 1000): -1 GetCargoPlannedVia(0, 1000, 1000): -1 GetCargoPlannedFromVia(0, 1000, 0, 1000): -1 GetCargoPlannedFromVia(0, 1000, 1000, 1000): -1 GetCargoPlanned(1000, 1000): -1 GetCargoPlannedFrom(1000, 0, 1000): -1 GetCargoPlannedVia(1000, 0, 1000): -1 GetCargoPlannedFromVia(1000, 0, 0, 1000): -1 GetCargoPlannedFromVia(1000, 0, 1000, 1000): -1 GetCargoPlannedFrom(1000, 1000, 1000): -1 GetCargoPlannedVia(1000, 1000, 1000): -1 GetCargoPlannedFromVia(1000, 1000, 0, 1000): -1 GetCargoPlannedFromVia(1000, 1000, 1000, 1000): -1 --Tile-- HasTreeOnTile(): false IsFarmTile(): true IsRockTile(): true IsRoughTile(): true HasTreeOnTile(): true IsFarmTile(): false IsRockTile(): false IsRoughTile(): false IsSnowTile(): false IsDesertTile(): false PlantTree(): true HasTreeOnTile(): true PlantTree(): false HasTreeOnTile(): false PlantTreeRectangle(): true HasTreeOnTile(): true --TileList-- Count(): 0 Count(): 9 Slope(): done Count(): 9 ListDump: 27631 => 29 27631 => 65535 27631 => true 27631 => false 27888 => 13 27888 => 2 27888 => false 27888 => false 27376 => 12 27376 => 3 27376 => false 27376 => false 27375 => 12 27375 => 3 27375 => false 27375 => false 27889 => 9 27889 => 6 27889 => false 27889 => false 27887 => 8 27887 => 7 27887 => false 27887 => false 27632 => 8 27632 => 7 27632 => false 27632 => false 27633 => 0 27633 => 15 27633 => false 27633 => false 27377 => 0 27377 => 15 27377 => false 27377 => false --TileList-- Count(): 0 Count(): 27 Height(): done Count(): 27 ListDump: 34956 => 4 34700 => 4 34444 => 4 34955 => 3 34954 => 3 34953 => 3 34699 => 3 34698 => 3 34697 => 3 34693 => 3 34692 => 3 34443 => 3 34442 => 3 34441 => 3 34439 => 3 34438 => 3 34437 => 3 34436 => 3 34952 => 2 34951 => 2 34950 => 2 34949 => 2 34948 => 2 34696 => 2 34695 => 2 34694 => 2 34440 => 2 CornerHeight(North): done Count(): 27 ListDump: 34956 => 4 34700 => 4 34444 => 4 34955 => 3 34954 => 3 34953 => 3 34699 => 3 34698 => 3 34697 => 3 34693 => 3 34692 => 3 34443 => 3 34442 => 3 34441 => 3 34439 => 3 34438 => 3 34437 => 3 34436 => 3 34952 => 2 34951 => 2 34950 => 2 34949 => 2 34948 => 2 34696 => 2 34695 => 2 34694 => 2 34440 => 2 MinHeight(): done Count(): 27 ListDump: 34956 => 4 34700 => 4 34444 => 4 34955 => 3 34954 => 3 34953 => 3 34699 => 3 34698 => 3 34697 => 3 34443 => 3 34442 => 3 34441 => 3 34436 => 3 34952 => 2 34951 => 2 34950 => 2 34949 => 2 34948 => 2 34696 => 2 34695 => 2 34694 => 2 34693 => 2 34692 => 2 34440 => 2 34439 => 2 34438 => 2 34437 => 2 MaxHeight(): done Count(): 27 ListDump: 34956 => 4 34955 => 4 34700 => 4 34699 => 4 34444 => 4 34443 => 4 34954 => 3 34953 => 3 34952 => 3 34951 => 3 34950 => 3 34949 => 3 34948 => 3 34698 => 3 34697 => 3 34696 => 3 34693 => 3 34692 => 3 34442 => 3 34441 => 3 34440 => 3 34439 => 3 34438 => 3 34437 => 3 34436 => 3 34695 => 2 34694 => 2 Slope(): done KeepValue(0): done Count(): 12 ListDump: 34956 => 0 34954 => 0 34953 => 0 34700 => 0 34698 => 0 34697 => 0 34695 => 0 34694 => 0 34444 => 0 34442 => 0 34441 => 0 34436 => 0 Buildable(): done KeepValue(1): done Count(): 35 BuildableRectangle(3, 3) ListDump: 42415 => 1 42414 => 1 42413 => 1 42412 => 1 42411 => 1 42410 => 1 42159 => 1 42158 => 1 42157 => 1 42156 => 1 42155 => 1 42154 => 1 41903 => 1 41902 => 1 41901 => 1 41900 => 1 41899 => 1 41898 => 1 41647 => 1 41646 => 1 41645 => 1 41644 => 1 41643 => 1 41642 => 1 41641 => 1 41391 => 1 41390 => 1 41389 => 1 41388 => 1 41387 => 1 41386 => 1 41385 => 1 42153 => 0 41897 => 0 41384 => 0 DistanceManhattanToTile(30000) ListDump: 42415 => 175 42414 => 174 42159 => 174 42413 => 173 42158 => 173 41903 => 173 42412 => 172 42157 => 172 41902 => 172 41647 => 172 42411 => 171 42156 => 171 41901 => 171 41646 => 171 41391 => 171 42410 => 170 42155 => 170 41900 => 170 41645 => 170 41390 => 170 42154 => 169 41899 => 169 41644 => 169 41389 => 169 42153 => 168 41898 => 168 41643 => 168 41388 => 168 41897 => 167 41642 => 167 41387 => 167 41641 => 166 41386 => 166 41385 => 165 41384 => 164 DistanceSquareToTile(30000) ListDump: 42415 => 18433 42159 => 18338 41903 => 18245 42414 => 18180 41647 => 18154 42158 => 18085 41391 => 18065 41902 => 17992 42413 => 17929 41646 => 17901 42157 => 17834 41390 => 17812 41901 => 17741 42412 => 17680 41645 => 17650 42156 => 17585 41389 => 17561 41900 => 17492 42411 => 17433 41644 => 17401 42155 => 17338 41388 => 17312 41899 => 17245 42410 => 17188 41643 => 17154 42154 => 17093 41387 => 17065 41898 => 17000 41642 => 16909 42153 => 16850 41386 => 16820 41897 => 16757 41641 => 16666 41385 => 16577 41384 => 16336 GetOwner() ListDump: 42415 => -1 42414 => -1 42413 => -1 42412 => -1 42411 => -1 42410 => -1 42159 => -1 42158 => -1 42157 => -1 42156 => -1 42155 => -1 42154 => -1 42153 => -1 41903 => -1 41902 => -1 41901 => -1 41900 => -1 41899 => -1 41898 => -1 41897 => -1 41647 => -1 41646 => -1 41645 => -1 41644 => -1 41643 => -1 41642 => -1 41641 => -1 41391 => -1 41390 => -1 41389 => -1 41388 => -1 41387 => -1 41386 => -1 41385 => -1 41384 => -1 33183 => -1 33182 => -1 33181 => -1 33180 => -1 33179 => -1 33178 => -1 33177 => -1 33176 => -1 33175 => -1 32927 => -1 32926 => -1 32925 => -1 32924 => -1 32923 => -1 32922 => -1 32921 => -1 32920 => -1 32919 => -1 32671 => -1 32670 => -1 32669 => -1 32668 => -1 32667 => -1 32666 => -1 32665 => -1 32664 => -1 32663 => -1 32415 => -1 32414 => -1 32413 => -1 32412 => -1 32411 => -1 32410 => -1 32409 => -1 32408 => -1 32407 => -1 32159 => -1 32158 => -1 32157 => -1 32156 => -1 32155 => -1 32154 => -1 32153 => -1 32152 => -1 32151 => -1 31903 => -1 31902 => -1 31901 => -1 31900 => -1 31899 => -1 31898 => -1 31897 => -1 31896 => -1 31895 => -1 31647 => -1 31646 => -1 31645 => -1 31644 => -1 31643 => -1 31642 => -1 31641 => -1 31640 => -1 31639 => -1 31391 => -1 31390 => -1 31389 => -1 31388 => -1 31387 => -1 31386 => -1 31385 => -1 31384 => -1 31383 => -1 31135 => -1 31134 => -1 31133 => -1 31132 => -1 31131 => -1 31130 => -1 31129 => -1 31128 => -1 31127 => -1 30879 => -1 30878 => -1 30877 => -1 30876 => -1 30875 => -1 30874 => -1 30873 => -1 30872 => -1 30871 => -1 30623 => -1 30622 => -1 30621 => -1 30620 => -1 30619 => -1 30618 => -1 30617 => -1 30616 => -1 30615 => -1 GetTownAuthority() ListDump: 33183 => 65535 33182 => 65535 33181 => 65535 33180 => 65535 33179 => 65535 33178 => 65535 33177 => 65535 33176 => 65535 33175 => 65535 32927 => 65535 32926 => 65535 32925 => 65535 32924 => 65535 32923 => 65535 32922 => 65535 32921 => 65535 32920 => 65535 32919 => 65535 32671 => 65535 32670 => 65535 32669 => 65535 32668 => 65535 32667 => 65535 32666 => 65535 32665 => 65535 32664 => 65535 32663 => 65535 32415 => 65535 32414 => 65535 32413 => 65535 32412 => 65535 32411 => 65535 32410 => 65535 32409 => 65535 32408 => 65535 32407 => 65535 32159 => 65535 32158 => 65535 32157 => 65535 32156 => 65535 32155 => 65535 32154 => 65535 32153 => 65535 32152 => 65535 32151 => 65535 31903 => 65535 31902 => 65535 31901 => 65535 31900 => 65535 31899 => 65535 31898 => 65535 31897 => 65535 31896 => 65535 31895 => 65535 31647 => 65535 31646 => 65535 31645 => 65535 31644 => 65535 31643 => 65535 31642 => 65535 31641 => 65535 31640 => 65535 31639 => 65535 31391 => 65535 31390 => 65535 31389 => 65535 31388 => 65535 31387 => 65535 31386 => 65535 31385 => 65535 31384 => 65535 31383 => 65535 31135 => 65535 31134 => 65535 31133 => 65535 31132 => 65535 31131 => 65535 31130 => 65535 31129 => 65535 31128 => 65535 31127 => 65535 30879 => 65535 30878 => 65535 30877 => 65535 30876 => 65535 30875 => 65535 30874 => 65535 30873 => 65535 30872 => 65535 30871 => 65535 30623 => 65535 30622 => 65535 30621 => 65535 30620 => 65535 30619 => 65535 30618 => 65535 30617 => 65535 30616 => 65535 30615 => 65535 42415 => 3 42414 => 3 42413 => 3 42412 => 3 42411 => 3 42410 => 3 42159 => 3 42158 => 3 42157 => 3 42156 => 3 42155 => 3 42154 => 3 42153 => 3 41903 => 3 41902 => 3 41901 => 3 41900 => 3 41899 => 3 41898 => 3 41897 => 3 41647 => 3 41646 => 3 41645 => 3 41644 => 3 41643 => 3 41642 => 3 41641 => 3 41391 => 3 41390 => 3 41389 => 3 41388 => 3 41387 => 3 41386 => 3 41385 => 3 41384 => 3 GetClosestTown() ListDump: 31127 => 24 30872 => 24 30871 => 24 30617 => 24 30616 => 24 30615 => 24 42415 => 3 42414 => 3 42413 => 3 42412 => 3 42411 => 3 42410 => 3 42159 => 3 42158 => 3 42157 => 3 42156 => 3 42155 => 3 42154 => 3 42153 => 3 41903 => 3 41902 => 3 41901 => 3 41900 => 3 41899 => 3 41898 => 3 41897 => 3 41647 => 3 41646 => 3 41645 => 3 41644 => 3 41643 => 3 41642 => 3 41641 => 3 41391 => 3 41390 => 3 41389 => 3 41388 => 3 41387 => 3 41386 => 3 41385 => 3 41384 => 3 33183 => 3 33182 => 3 33181 => 3 33180 => 3 33179 => 3 33178 => 3 33177 => 3 33176 => 3 33175 => 3 32927 => 3 32926 => 3 32925 => 3 32924 => 3 32923 => 3 32922 => 3 32921 => 3 32920 => 3 32919 => 3 32671 => 3 32670 => 3 32669 => 3 32668 => 3 32667 => 3 32666 => 3 32665 => 3 32664 => 3 32663 => 3 32415 => 3 32414 => 3 32413 => 3 32412 => 3 32411 => 3 32410 => 3 32409 => 3 32408 => 3 32407 => 3 32159 => 3 32158 => 3 32157 => 3 32156 => 3 32155 => 3 32154 => 3 32153 => 3 32152 => 3 32151 => 3 31903 => 3 31902 => 3 31901 => 3 31900 => 3 31899 => 3 31898 => 3 31897 => 3 31896 => 3 31895 => 3 31647 => 3 31646 => 3 31645 => 3 31644 => 3 31643 => 3 31642 => 3 31641 => 3 31640 => 3 31639 => 3 31391 => 3 31390 => 3 31389 => 3 31388 => 3 31387 => 3 31386 => 3 31385 => 3 31384 => 3 31383 => 3 31135 => 3 31134 => 3 31133 => 3 31132 => 3 31131 => 3 31130 => 3 31129 => 3 31128 => 3 30879 => 3 30878 => 3 30877 => 3 30876 => 3 30875 => 3 30874 => 3 30873 => 3 30623 => 3 30622 => 3 30621 => 3 30620 => 3 30619 => 3 30618 => 3 CargoAcceptance(): done KeepAboveValue(10): done Count(): 15 ListDump: 41897 => 29 41385 => 26 41384 => 26 42153 => 25 41641 => 23 41899 => 17 41898 => 17 41387 => 17 41386 => 17 41643 => 14 41642 => 14 42411 => 13 42410 => 13 42155 => 13 42154 => 13 RoadTile(): done KeepValue(1): done Count(): 0 ListDump: NeighbourRoadCount():done KeepValue(1): done Count(): 0 ListDump: Water(): done Count(): 45 ListDump: 54941 => 1 54940 => 1 54939 => 1 54938 => 1 54937 => 1 54936 => 1 54935 => 1 54934 => 1 54933 => 1 54685 => 1 54684 => 1 54683 => 1 54682 => 1 54681 => 1 54680 => 1 54679 => 1 54678 => 1 54677 => 1 54429 => 1 54428 => 1 54427 => 1 54426 => 1 54425 => 1 54424 => 1 54423 => 1 54422 => 1 54421 => 1 54173 => 1 54172 => 1 54171 => 1 54170 => 1 54169 => 1 54168 => 0 54167 => 0 54166 => 0 54165 => 0 53917 => 0 53916 => 0 53915 => 0 53914 => 0 53913 => 0 53912 => 0 53911 => 0 53910 => 0 53909 => 0 --TileList_IndustryAccepting-- Count(): 47 Location ListDump: 21234 => 16 21233 => 16 21232 => 16 21231 => 16 21230 => 16 21229 => 16 20978 => 16 20977 => 16 20976 => 16 20975 => 16 20974 => 16 20973 => 16 20722 => 16 20718 => 16 20717 => 16 20466 => 16 20462 => 16 20461 => 16 20210 => 16 20206 => 16 20205 => 16 19954 => 16 19950 => 16 19949 => 16 21490 => 8 21489 => 8 21488 => 8 21487 => 8 21486 => 8 21485 => 8 21484 => 8 21235 => 8 21228 => 8 20979 => 8 20972 => 8 20723 => 8 20716 => 8 20467 => 8 20460 => 8 20211 => 8 20204 => 8 19955 => 8 19948 => 8 19699 => 8 19698 => 8 19694 => 8 19693 => 8 --TileList_IndustryProducing-- Count(): 92 Location ListDump: 46920 => 1 46919 => 1 46918 => 1 46917 => 1 46916 => 1 46915 => 1 46914 => 1 46913 => 1 46912 => 1 46911 => 1 46664 => 1 46663 => 1 46662 => 1 46661 => 1 46660 => 1 46659 => 1 46658 => 1 46657 => 1 46656 => 1 46655 => 1 46408 => 1 46407 => 1 46406 => 1 46405 => 1 46404 => 1 46403 => 1 46402 => 1 46401 => 1 46400 => 1 46399 => 1 46152 => 1 46151 => 1 46150 => 1 46149 => 1 46146 => 1 46145 => 1 46144 => 1 46143 => 1 45896 => 1 45895 => 1 45894 => 1 45889 => 1 45888 => 1 45887 => 1 45640 => 1 45639 => 1 45638 => 1 45633 => 1 45632 => 1 45631 => 1 45384 => 1 45383 => 1 45382 => 1 45377 => 1 45376 => 1 45375 => 1 45128 => 1 45127 => 1 45126 => 1 45121 => 1 45120 => 1 45119 => 1 44872 => 1 44871 => 1 44870 => 1 44869 => 1 44868 => 1 44867 => 1 44866 => 1 44865 => 1 44864 => 1 44863 => 1 44616 => 1 44615 => 1 44614 => 1 44613 => 1 44612 => 1 44611 => 1 44610 => 1 44609 => 1 44608 => 1 44607 => 1 44360 => 1 44359 => 1 44358 => 1 44357 => 1 44356 => 1 44355 => 1 44354 => 1 44353 => 1 44352 => 1 44351 => 1 --TileList_StationType-- Count(): 4 Location ListDump: 33667 => 0 33415 => 0 33413 => 0 33411 => 0 --Town-- GetTownCount(): 28 Town 0 IsValidTown(): true GetName(): Planfield GetPopulation(): 787 GetLocation(): 15508 GetHouseCount(): 30 GetRating(): 0 IsCity(): true Town 1 IsValidTown(): true GetName(): Trenningville GetPopulation(): 243 GetLocation(): 46751 GetHouseCount(): 17 GetRating(): 0 IsCity(): false Town 2 IsValidTown(): true GetName(): Tonston GetPopulation(): 380 GetLocation(): 28365 GetHouseCount(): 19 GetRating(): 0 IsCity(): false Town 3 IsValidTown(): true GetName(): Tunford GetPopulation(): 176 GetLocation(): 41895 GetHouseCount(): 11 GetRating(): 0 IsCity(): false Town 4 IsValidTown(): true GetName(): Wruntown GetPopulation(): 426 GetLocation(): 41450 GetHouseCount(): 18 GetRating(): 0 IsCity(): true Town 5 IsValidTown(): true GetName(): Fratston GetPopulation(): 205 GetLocation(): 55007 GetHouseCount(): 11 GetRating(): 0 IsCity(): false Town 6 IsValidTown(): true GetName(): Muningville GetPopulation(): 679 GetLocation(): 38200 GetHouseCount(): 28 GetRating(): 0 IsCity(): false Town 7 IsValidTown(): true GetName(): Hutford GetPopulation(): 950 GetLocation(): 59234 GetHouseCount(): 33 GetRating(): 0 IsCity(): false Town 8 IsValidTown(): true GetName(): Satown GetPopulation(): 358 GetLocation(): 51267 GetHouseCount(): 20 GetRating(): 0 IsCity(): true Town 9 IsValidTown(): true GetName(): Frindinghattan GetPopulation(): 478 GetLocation(): 5825 GetHouseCount(): 18 GetRating(): 0 IsCity(): false Town 10 IsValidTown(): true GetName(): Nuntburg GetPopulation(): 737 GetLocation(): 6446 GetHouseCount(): 26 GetRating(): 6 IsCity(): false Town 11 IsValidTown(): true GetName(): Fort Frindston GetPopulation(): 180 GetLocation(): 14935 GetHouseCount(): 13 GetRating(): 0 IsCity(): false Town 12 IsValidTown(): true GetName(): Gintborough GetPopulation(): 982 GetLocation(): 32740 GetHouseCount(): 28 GetRating(): 0 IsCity(): true Town 13 IsValidTown(): true GetName(): Great Hinninghall GetPopulation(): 310 GetLocation(): 9595 GetHouseCount(): 14 GetRating(): 0 IsCity(): false Town 14 IsValidTown(): true GetName(): Prundinghall GetPopulation(): 432 GetLocation(): 51298 GetHouseCount(): 18 GetRating(): 0 IsCity(): false Town 15 IsValidTown(): true GetName(): Beningville GetPopulation(): 807 GetLocation(): 42338 GetHouseCount(): 33 GetRating(): 6 IsCity(): false Town 16 IsValidTown(): true GetName(): Kennville GetPopulation(): 780 GetLocation(): 17345 GetHouseCount(): 33 GetRating(): 0 IsCity(): true Town 17 IsValidTown(): true GetName(): Quarfingfield GetPopulation(): 218 GetLocation(): 24252 GetHouseCount(): 13 GetRating(): 0 IsCity(): false Town 18 IsValidTown(): true GetName(): Nefingbridge GetPopulation(): 262 GetLocation(): 10574 GetHouseCount(): 13 GetRating(): 0 IsCity(): false Town 19 IsValidTown(): true GetName(): Mendston GetPopulation(): 243 GetLocation(): 6511 GetHouseCount(): 14 GetRating(): 0 IsCity(): false Town 20 IsValidTown(): true GetName(): Chenfingbourne GetPopulation(): 437 GetLocation(): 22585 GetHouseCount(): 15 GetRating(): 6 IsCity(): true Town 21 IsValidTown(): true GetName(): Franinghead GetPopulation(): 802 GetLocation(): 9634 GetHouseCount(): 27 GetRating(): 0 IsCity(): false Town 22 IsValidTown(): true GetName(): Natborough GetPopulation(): 221 GetLocation(): 51891 GetHouseCount(): 12 GetRating(): 0 IsCity(): false Town 23 IsValidTown(): true GetName(): Larborough GetPopulation(): 652 GetLocation(): 59622 GetHouseCount(): 27 GetRating(): 0 IsCity(): false Town 24 IsValidTown(): true GetName(): Little Frutford GetPopulation(): 668 GetLocation(): 19596 GetHouseCount(): 34 GetRating(): 4 IsCity(): true Town 25 IsValidTown(): true GetName(): Grinnway GetPopulation(): 563 GetLocation(): 16433 GetHouseCount(): 15 GetRating(): 0 IsCity(): false Town 26 IsValidTown(): true GetName(): Beburg GetPopulation(): 362 GetLocation(): 39505 GetHouseCount(): 18 GetRating(): 0 IsCity(): false Town 27 IsValidTown(): true GetName(): Fudhattan GetPopulation(): 390 GetLocation(): 45525 GetHouseCount(): 19 GetRating(): 0 IsCity(): false Valid Towns: 28 GetTownCount(): 28 --TownList-- Count(): 28 Location ListDump: 23 => 59622 7 => 59234 5 => 55007 22 => 51891 14 => 51298 8 => 51267 1 => 46751 27 => 45525 15 => 42338 3 => 41895 4 => 41450 26 => 39505 6 => 38200 12 => 32740 2 => 28365 17 => 24252 20 => 22585 24 => 19596 16 => 17345 25 => 16433 0 => 15508 11 => 14935 18 => 10574 21 => 9634 13 => 9595 19 => 6511 10 => 6446 9 => 5825 DistanceManhattanToTile(30000) ListDump: 23 => 297 5 => 272 9 => 240 4 => 230 27 => 225 22 => 216 16 => 195 21 => 194 12 => 190 1 => 176 3 => 165 7 => 164 2 => 164 17 => 163 0 => 157 19 => 155 13 => 155 24 => 133 14 => 133 18 => 106 8 => 102 15 => 98 11 => 98 10 => 94 26 => 70 25 => 54 6 => 40 20 => 38 DistanceSquareToTile(30000) ListDump: 23 => 46349 5 => 40034 4 => 36532 12 => 32500 27 => 30825 9 => 30050 2 => 24698 22 => 24386 16 => 23525 17 => 20129 21 => 19396 1 => 16546 3 => 16277 7 => 15496 0 => 13249 19 => 12433 13 => 12025 24 => 10145 14 => 9389 10 => 8468 8 => 7250 18 => 6676 11 => 5002 15 => 4804 25 => 2810 26 => 2458 6 => 1088 20 => 922 IsWithinTownInfluence(15508) ListDump: 0 => 1 27 => 0 26 => 0 25 => 0 24 => 0 23 => 0 22 => 0 21 => 0 20 => 0 19 => 0 18 => 0 17 => 0 16 => 0 15 => 0 14 => 0 13 => 0 12 => 0 11 => 0 10 => 0 9 => 0 8 => 0 7 => 0 6 => 0 5 => 0 4 => 0 3 => 0 2 => 0 1 => 0 GetAllowedNoise() ListDump: 27 => 2 26 => 2 25 => 2 24 => 2 23 => 2 22 => 2 21 => 2 20 => 2 19 => 2 18 => 2 17 => 2 16 => 2 14 => 2 13 => 2 12 => 2 11 => 2 10 => 2 9 => 2 8 => 2 7 => 2 6 => 2 5 => 2 4 => 2 3 => 2 2 => 2 1 => 2 0 => 2 15 => 1 KeepAboveValue(500): done Count(): 11 Population ListDump: 12 => 982 7 => 950 15 => 807 21 => 802 0 => 787 16 => 780 10 => 737 6 => 679 24 => 668 23 => 652 25 => 563 HasStatue(): false GetRoadReworkDuration(): 0 GetExclusiveRightsCompany(): -1 GetExclusiveRightsDuration(): 0 IsActionAvailable(BUILD_STATUE): true PerformTownAction(BUILD_STATUE): true IsActionAvailable(BUILD_STATUE): false HasStatue(): true --Tunnel-- IsTunnelTile(): false RemoveTunnel(): false GetOtherTunnelEnd(): 28026 BuildTunnel(): true GetOtherTunnelEnd(): 28026 IsTunnelTile(): true IsTunnelTile(): true RemoveTunnel(): true IsTunnelTile(): false --Errors-- BuildTunnel(): true BuildTunnel(): false GetLastErrorString(): ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY RemoveTunnel(): true --Vehicle-- IsValidVehicle(-1): false IsValidVehicle(0): false IsValidVehicle(12): false ISValidVehicle(9999): false BuildVehicle(): 12 IsValidVehicle(12): true CloneVehicle(): 13 --Accounting-- GetCosts(): 11894 Should be: 11894 ResetCosts(): (null : 0x00000000) SellVehicle(13): true IsInDepot(): true IsStoppedInDepot(): true StartStopVehicle(): true IsInDepot(): false IsStoppedInDepot(): false SendVehicleToDepot(): true IsInDepot(): false IsStoppedInDepot(): false --Accounting-- GetCosts(): -5947 Should be: -5947 GetName(): Road Vehicle 1 SetName(): true GetName(): MyVehicleName CloneVehicle(): 13 --VehicleData-- GetLocation(): 33417 GetEngineType(): 153 GetUnitNumber(): 1 GetAge(): 0 GetMaxAge(): 5490 GetAgeLeft(): 5490 GetCurrentSpeed(): 7 GetRunningCost(): 421 GetProfitThisYear(): 0 GetProfitLastYear(): 0 GetCurrentValue(): 5947 GetVehicleType(): 1 GetRoadType(): 0 GetCapacity(): 12 GetCargoLoad(): 0 IsInDepot(): false GetNumWagons(): 1 GetWagonEngineType(): 153 GetWagonAge(): 0 GetLength(): 8 GetOwner(): 1 BuildVehicle(): 14 IsValidVehicle(14): true IsInDepot(14): true IsStoppedInDepot(14): true IsValidVehicle(15): false IsInDepot(15): false IsStoppedInDepot(15): false BuildVehicle(): 16 IsValidVehicle(16): true IsInDepot(16): true IsStoppedInDepot(16): true BuildRailDepot(): true BuildVehicle(): 17 BuildVehicle(): 18 BuildVehicle(): 19 MoveWagonChain(): true GetNumWagons(): 3 GetLength(): 24 GetWagonEngineType(): 9 GetWagonAge(): 1 GetWagonEngineType(): 27 GetWagonAge(): 1 GetWagonEngineType(): 27 GetWagonAge(): 0 GetWagonEngineType(): 65535 GetWagonAge(): -1 --Errors-- RefitVehicle(): false GetLastErrorString(): ERR_VEHICLE_NOT_IN_DEPOT SellVehicle(): false GetLastErrorString(): ERR_VEHICLE_NOT_IN_DEPOT SendVehicleToDepot(): false GetLastErrorString(): ERR_UNKNOWN --VehicleList-- Count(): 5 Location ListDump: 13 => 33417 12 => 33417 14 => 32119 16 => 28479 17 => 10008 EngineType ListDump: 14 => 219 16 => 204 13 => 153 12 => 153 17 => 9 UnitNumber ListDump: 13 => 2 17 => 1 16 => 1 14 => 1 12 => 1 Age ListDump: 17 => 1 16 => 1 14 => 1 13 => 1 12 => 1 MaxAge ListDump: 16 => 10980 14 => 10980 17 => 7320 13 => 5490 12 => 5490 AgeLeft ListDump: 16 => 10979 14 => 10979 17 => 7319 13 => 5489 12 => 5489 CurrentSpeed ListDump: 12 => 21 17 => 0 16 => 0 14 => 0 13 => 0 RunningCost ListDump: 14 => 2756 17 => 2296 16 => 2296 13 => 421 12 => 421 ProfitThisYear ListDump: 17 => 0 16 => 0 14 => 0 13 => 0 12 => -1 ProfitLastYear ListDump: 17 => 0 16 => 0 14 => 0 13 => 0 12 => 0 CurrentValue ListDump: 14 => 30761 16 => 30468 17 => 22265 13 => 5947 12 => 5947 VehicleType ListDump: 14 => 3 16 => 2 13 => 1 12 => 1 17 => 0 RoadType ListDump: 13 => 0 12 => 0 17 => -1 16 => -1 14 => -1 VehicleType ListDump: 13 => 12 12 => 12 17 => 0 16 => 0 14 => 0 VehicleType ListDump: 17 => 0 16 => 0 14 => 0 13 => 0 12 => 0 --Order-- GetOrderCount(): 0 GetOrderDestination(): -1 AreOrderFlagsValid(): true AreOrderFlagsValid(): false AreOrderFlagsValid(): true AreOrderFlagsValid(): true AreOrderFlagsValid(): true AreOrderFlagsValid(): true IsValidConditionalOrder(): true IsValidConditionalOrder(): false IsValidConditionalOrder(): true IsValidConditionalOrder(): false IsValidVehicleOrder(): false IsGotoStationOrder(): false IsGotoDepotOrder(): false IsGotoWaypointOrder(): false IsConditionalOrder(): false IsCurrentOrderPartOfOrderList(): false GetOrderFlags(): 65535 AppendOrder(): true InsertOrder(): true GetOrderCount(): 2 IsValidVehicleOrder(): true IsGotoStationOrder(): true IsGotoDepotOrder(): false IsGotoWaypointOrder(): false IsConditionalOrder(): false IsCurrentOrderPartOfOrderList(): false GetOrderFlags(): 8 GetOrderFlags(): 8 GetOrderJumpTo(): -1 RemoveOrder(): true SetOrderFlags(): true GetOrderFlags(): 64 GetOrderDestination(): 33411 CopyOrders(): false CopyOrders(): true ShareOrders(): false ShareOrders(): true UnshareOrders(): true AppendOrder(): true GetStopLocation(): -1 BuildVehicle(): 20 BuildRailStation(): true AppendOrder(): true GetOrderCount(): 1 GetStopLocation(): 2 SetStopLocation(): true GetStopLocation(): 1 --VehicleList_Station-- Count(): 1 Location ListDump: 20 => 23596 foreach(): 20 => 23596 First Subsidy Test --Subsidy (0) -- IsValidSubsidy(): true IsAwarded(): false GetAwardedTo(): -1 GetExpireDate(): 714080 GetSourceType(): 1 GetSourceIndex(): 15 GetDestinationType(): 1 GetDestinationIndex(): 7 GetCargoType(): 0 IsEventWaiting: false --Math-- -2147483648 < -2147483647: true -2147483648 < -1 : true -2147483648 < 0 : true -2147483648 < 1 : true -2147483648 < 2147483647: true -2147483647 < -2147483648: false -1 < -2147483648: false 0 < -2147483648: false 1 < -2147483648: false 2147483647 < -2147483648: false -1 > 2147483647: false -1 > 1 : false -1 > 0 : false -1 > -1 : false -1 > -2147483648: true 1 > 2147483647: false 1 > 1 : false 1 > 0 : true 1 > -1 : true 1 > -2147483648: true 2147483647 > 2147483646: true 2147483647 > 1 : true 2147483647 > 0 : true 2147483647 > -1 : true 2147483647 > -2147483648: true 2147483646 > 2147483647: false 1 > 2147483647: false 0 > 2147483647: false -1 > 2147483647: false -2147483648 > 2147483647: false 13725 > -2147483648: true ERROR: The script died unexpectedly. openttd-1.5.3/bin/ai/regression/tst_stationlist/0000755000000000000000000000000012627373446020501 5ustar rootrootopenttd-1.5.3/bin/ai/regression/tst_stationlist/test.sav0000644000000000000000000027021412627373446022201 0ustar rootrootOTTX7zXZi"6!#,)b]#!|TKB Dy_03q-Z금le; M߿xvGW׬SLN4">7ҋFQ`)8bpqڧ쉷vtBI%-3g;4`ŕ)}.6Y<"y)NǎńD!fsTӋW6]x? ];";WV+&_;a Slm{}zT涍$ia|RV͗*t Pv]VUA& v>*W˞Mf].XQv$Gl0ika5 l<#}tqez<G_ 6pc%C\J^!p,&QG%6HQhM&jmA>VMX.Q[8t_ :s%W+7ue!w5dhXNا/";V!~b2x ѷ_Mr#O4,l]e@Ijcl1֙#n#My&O%:̟kύ1#@14-crݷb6$kKs|ARFvYI(Y#L`"7([fS~β\4 D}7CgnJHn]Y\uX1fRSLi]"!' ^_]fGTB1~ku{|W]v'E^#,H>qu( _UvA9j4bxI5;pv$Xxklk{m;N}T([^uIyݟi5Z~U?R&o@,o9lX!y*83aP*>/p濴-̠{,;hG POƺQJzQ1]])U:w?f>h=0j%1*oT ¨^QiZȫbXeҶ*ZPCp9d-#}X5Уr@*H\+ ]:Wl]N:}P~5K9K׸Z= %#hKtK/n,-4eQaB:) Hv_9}N E du:4+W[R4N=KYGbޕ90G|7/,ykob$!z⪢IJ\/ɫ Qc5\4){}lC~0(U 0p|îތ1-A!d&@-fI,V#T+|τa^esf 6 \!oEnEKgZi: zS,AJ^id.RmvR!GM% 6zK+@oׇNњf1ic: xU˩yfe<}R^(j!:ie<cQ50> ݯ;]hU?k:]̍J3d|s y=iDxثhYu&=#}iՈN_qW 5f [g'#:-|,v̏o/sQRAG/doqcmz.χ(S^PMr94M-͑gHq٣5|k7cC4e8l\5jO2Ys7yT<;h=$wd[ ^bIj~hg%] /kEJޭ"drfMXIknK opR"=κ2UNh{./U=Vb~Jڴ*o aĴ޼|b`Ks/7 X4sW%cZX\R&?V_]daPT=.i<ųr}F6Eqn+e}T>8.#@dBn~Yؤ#h;=T;}T?=`5oe#7K+SjPy\ye4!3wGZU4 pqnʒ(mŖGLPjbS1*[C0:"*f Sݼ%~MO4 V.%`sGzu.TT7TBM&@A07U)q(W)g~v_6^J*^r7͟.LTzX9O1E]B^k`_7[Fq@l˓!p^;y! %jFczX ?8uFS?kJ$eUO*+WZ8j "B$C|CʄiR}I}^LFAVxf)PhW5~{D-[ӰcDe";0$w۴VcoE cA. (L4Vn+M~r=5kn ))-2h8L}2AkFtcTT-bXHl #`a]8Tw-c=;-ē K=PGQ™%oGufHCpcKPYK-&H_ɗITwc}iX⮘w{&(TMt]& W 8::CY|K}Fc-:aƻnScR0y72:6M闳 ;i]gw U8g_&L\Di/$#ġ7"hW_B~C/x$%ݮkb=lk謔KS(/FxCzY~p:s\ppyTͧ}q<--gsq[.(x-ɤv# Ŭ |nLvQfmKoަUŝrbfU2=}gtA0|?cF7__H?$ًj{<70+'lb"^R!&'euM|%Zf\ݥi|cU=qӪ1i%T{ Cb 7A n(4`JPqlU^0=WgIRl 2 MZqђ9U8ma-AXJ8 JBqlj_U0!ڥ6ȝ=vSi8}MXU͘U(n(θwJb{̚n'SQݣK=hp=H-HP3b^YH2Oty:’ O#)BLmV:ͽ5Z ,7A9&з`"&B+@h{QT`D5-jÆ`j $ΞSY!)rd=<-z}Shԋm[,XBh%w)Θi\J3[hgkC۷TB jG/\?Muo>*V7}F / αoJU?Ox݁ >|29)a8X;ɪ5#!pa;Ns+:"i)'eeX>rZ?@)S}9A Um.:9lJC1 Um 䊊[@C-zVL|ąM}w^ƸtIxZ?Lv(L]PEA&|t tFѳmD&R)7ȷvD;gşKF%'ZJQ!J~* y.Fе?fM2\g՜ʥfp#V?xuJ0$'RָgiU^RŴD\?õ.q^GWãúu5Ц̴s9M{1 AS$WhdE"TUTPI ,m~E U6cgā;#K9B%OX-(:¦ʇY`ZΠ8dzw7ZH)~ ~[Ք]5]> Koi{+ +l?Qӹ#ja3{H/>G|Qw?T,4;O66jҵzEQL $ip (D4E/KkIa(aFv@fI> Iڮd7̭)Md:p<ّ"Cd{K5ΖF+M9ϜBEo.O}d䆪T/ $w]Eb^/ɭ;VQEp8h[|}-2>M(iT*cƶ'ڏIGk's:D]o? 0SLe?a_$eE 'ؖ9h*d]o@Kn܅GeWܕ)^amSv`c龼rHQS4 t3V$v%rZOGdxGCbJߜq;ő" {H^QL_RR*E=ͬPR̍vx1JU799i]BqcHyK2) )8ҸFB1Yk[4+~_ t6]9{OHRl4Ag͓7k=|y)A?^uoFe)%6R=NЮV0 iY'msw_*(ﻜ_E|d5f,Me 3ٴe:3F"B~H_,NAir^ωjԽ޼ t1AWLF@O m_*[R2dHx7`*`8+^'`nCH2 w?FtKNZ^p5]MRCsԾEdSA L6BbHtrUYK7mznM]͏H&^\W2{@6݀o~5C:ODɢh;XҬ%;™QJiD1+a m7""Q|0:Gz} 'jH }D'a16a5.EmT3"OW7oc_%FM&F?@,!2ꕑr|gSu_0} H}($NZQTlN;g`]lp6&4=>b; uw :=-DH6!BSl LNA (jo!.Vʂozl΍7G]&6}2c}HYBŊ\D!vG0vYO82(,&r]^rh:Ur(,M֚n [;4qn$+g<^0m{}M#\l5VW$I$o2 Z{Qg2K28 !<Ee[ W49'`\iZJI u'CƗ끽.WRK;IJA\ན,^jTM4ȫ sUAMnoZmA-3`]*9IJPJvr}r+t!څ+oysB酄 b|`+'`6}Ȝ'CjD&3dG`P5IwC5%Ps*!nuC~ȡ-p Cڪ*$uHlhANB`L1=dP<; )nT`&rn3By \U=2qk­EJhk(s{*.18ȰDaad(~ o-*X)pM߹=vx9?͔ #5w;xX:^c>pTtup;qquTԆ܈`l|6\Cq{CcB mQ#L;Q{g@9? 8Ζ|Z{L]iehDA DCHXh)|VQD6٠: ~ӈT^*r澺2I.a%_ͮėAp wIPҭ@TIK9 =#(!^aaJS߁߱rE]Mԣl{ۮ6f`GB?di+0j*jI4{25Z+$u]V{mnLO%+jruhcD-{Px+RaLڹ ¶CƩ-Hh0!][3;0Ill]&7dUSbK 2g ۭ7u^' N Ck>m.4_#y.+ʭBVQN ݷB/6du&]>'3, ^HrqqwK)PN@TFCp%4S]_]Τ1}KBe,Zi<`?, laGuI"%uLXJx^!Uǿ.0)Ne2 oHtaH+DK3ne`R|ڽ~wh'\ϼg8ׇ#b. b&KhVK+H[gG:jTYz}2=3Yd"ّ6i1Tr ^$iѲ*ȩ:] &r֮kq@zxErM6ς3҃x=NpFs d"j8A^DȗGZVVg9ΏɩQN؁Lz8@#%YlnC ~uO{;]ިii޽nڡ3C]}Q>H !z#ͧk7-t%ŐZ> ӿj$hI$1Õ/ũ>j[҂^:%?J /KjGA*#SED) ;m3!Ѱĕ =Py$q;d@DGiy_Efk {WMmr#qs:ҳu/jjN'siBq)dwy:.H 1{brVWUce2TzI*: f'cJukj"\T,ҁdml$ E^_DA3G RB0vYt0FQ T CM?1-Q [vMWeVhK7+!NX]Н:5VQ*Pr(qoc p6QU/=wJ_2q́YCL5#ˌj&]$X,l+}=X쵕o\*^`tNx>ĊFGadiEq laneJ܈ <ТҶn{!Xt{DRXm#QK@N@*l`4jŊ|$ҙzwD,NWN28֓¿֚OswkgUS@_5e3R],+Bh( nE]P&mjaˮ<'7|9GSI Hn~Zg?cKH"뱋~aFXzݽNtKKvX)ǢH/uBK!.X<^@o1;[ٴW +&0jr(b׬G /ûzԲޫb!NB|WՄ[wg{^-7@Z%Cz@ԏ3kA=94o1 6WrL{Dӱ%Q$s,^;Kѻ; "4kdO1i, N<)v•(+Z2уzDc]-aj,nXɿdk6q· ZY,[x=ߴǟESEaB}M_MX/8YfO{ > ;l1}W>[z̘[8O{a,P Qq޶x2lCM{$rq ?`!9čn*M;L8Tb%fG2X9%IͿ;:B "߰j`rT& c64I^Xԣ)XR<=`C7$;2'*8 >H2{(<gC?E~oX 4$I&6P4<)aZV]K,Pe闲60D?.5Ct#=v6gYooƚ`%JA1Hvzy$峗ᦧ}m hl~\i(m-O7P떬_#ngM~n.m- B;B]JbihK#r=x:Vl0~c˷?[#Gpz$TN !`%36B%Xj><ۭҝ؁.n@5x鿅%/^ ͯ~C-1!GZSQ&ec܊˼dPb~tY+ ru ԯ2p3D#9-:'- y!TT?^-8=DkcܵJVa4+fJڤO/At"|b=WƢfT$˔~QYa;x80<0ǰ4 YpnT3hUiV/\ZuӋEp'ei`ieRt_%3" +3,IBлxRf6'ӽ||]T_=:z:]z͍5ۛ" !'Jh:~IA`$$Aǎu.BJewbVmA$a2fxbs69d/, M d"Q9;ADLc-Y+\Q9{qknN߾/R6}PMpLY[(Va 5DȜ8z0%`y?|`$m* ¥w2+K vH*%gʖ -B v z|_nE ^x2q!Ox7и|;UH13Ɠ.zetkÏ=7\d5{&ʨ-7T9z*e1H#d 1NFPFES''wEyGXp`F:7PreL? E;jYzv̄35X9+e}|xh},][1Ri ࠋHu,/o sY[{ηAPp foٯ2<1rjZȂ[} O5zYsO)fW=Vm.)^03@݋읟tΣcbp@C@'R6gQ>֜szÙe"!CV xB‡&n%HO:f͓ۢʔkk&V'ȽcjγL=a)B3&CYp߻ͮ_Sg7V:y3vUG YkjV q^W-dC|.cWyD7Gثo2?v͵-yun=,lMV]Hޭ{͟fLAc;R@~*mZ걩Zn)1[E;^X1b)l$f~,$QC@e b~*D!m-N1K"$}A]؀4֍N'@趫 l &4ޣENV ԟ;CTܛc S%2{א~O_m`dS1kSmp56 M(a ;-U;ӌ,KL"FeSO#_C'bDEAH:.ʕPXK\W^ p1Cv5jX5n|x.zCVىؼONa{c c/ m s5S2>v*_oPӑ MN^`z:5f f٪Ds2h!@y1t70f'~3$nk&oZCM8[]?Į' G~ XCe TE}%F2d҂g cj>k EszkLOQ Z E'1BX&cٍm E uݝuw:= 0VQHj&NQ‘yrf1n{Vm] ѝNƻ[@)<{^΄]3@]z7m&M &_: [ԛC|i NPZv:Z]9ohȬ7'c>:/:sN_ Vjc"Zk=σfyˢބ6=T<)AlIXx&{G,BP' zAנAu}5z$ ,DxRcRP ]=H|`c֚AK MY  m F_Fi$ކzrLsp~U;@ߨy.t%~Q᠕&.KM }SbTwR C- ,]+nMaPUϯ2-S&ODR ZxyzS]wvx``{+%ߦ8jQY|EҞ1ky'm=>*JoNǶvV*;DK1(L"8Sf3FYu6% }} p*^ᖅy_~|'40#3wg`X0,C(+Mr%b]NQ@_y!-C!zftқkJWZH~㰕+ T$F ǘ2[hk~{ tg;EE@;5vkvXQE7qa }7fi-5;Ad7̀F*BDҳŏ~geA&wpfv!m{G׭Rz1Tߠ yR _ As:x8<1NMxҾӦ&p|8b|9h/r!JI.Vw{{=j30ȆeqGi Ȃ-E}/k璊cF /a%xe݅5h$T4WvÕ1~K >/9r[wPsjxo"t %Ep# 3'lq'3āc bw0Ev\+ViVp '̧y({iw` zC0Yf+ztnh.j .f0ĺ-&_!+dP-Psi6Aj mb/R1 qA[gd$Qx7;.tJ)9ED^|K9w`bEI*hك$MW(qpyq' Y8o6UoHEw=m?_lŢx"Lq ޞcQ>\Ӯ(1֜I;TӺnz &bƳ됑`ccdI%BRQڹ3M!hD^H3O'1@iӝf O ͿFj,NX}2t\]^#fT$f쉄`(MQh6p;wJn [f=:c;T j.<>OjZߝn,q.n2N1[!1*e 1l%5s oҡf1Z^6 )Cd4|ҏg)tc~bOC]m"BTэچW&o8%*l-g_/(6<WN;v3<Bh\dpK`2kl '$F(B ר#t8FSӿZUJT_/]_o"Z\n[.E.~PSk5zdM HT-Ͽr5;~Qvdoo[ε[01v{I;MEIEC`VA{D-zcFj|܏1Wx<`9Iwb ]Tb`)؃, 64qw:3GdP cyz%{x>&GaIfMg[&-N֎pjB}Nq,)vc-`f Ct"Y!E\EIOݔ`\2=19˟W((Aė=}Jot8.Ҕ -eٽZw r}sxT/w@A`qSQYwDnZzIǼa;򪘷fk]$Rtj/kϝS&8=!OOHs5}5F vv+T.>cYfT>8FLXEm_5[II^/@k}S#b*0!rK+á.Q;{ndf)Ԟ]߯q#6fа7Jqy^c {}Ok5k1֋9!JL|;)wՎz.$m'"Z?f=/d`/Qv Rc @XvYFOAyl ZŔ1h #w;wh4BrqEYMWшqTwz0hoD Soodh<| .g\%9`WWHkb/, yVYZBf:3UI2Y_ƎZ ՞]NrP`- Ǡ,U3xɯ A>ia ~ZhɟhTYY5_rA#E0Jԥ>皜XEߪew(WO|3O پՌK:s390XqcSAhJ>%/jh8$j!Cp jD@id/W8 ;@{, ie#_kmi&['WiCe: V۷646[?(qˢ $U{) 3g3,""}tjD_YHdrPA,mNIp;JeF/~݊m m1[Qhŀ V\C. gO_&s@@NAB2{TK"N5}pq4nυzNJЙ⹻q-* l L #K6M^߀qay'쵦 %ι'Ugሖ w.X5zbX8d"IG-ӑI)LZOFCư:#4nzz5+t-ɌlXKh鲿Pvm?:̤u`(AYg>:-W ttXtJʼn=z(.a.8WmnU6La, +ysG(I9{ #?=DS}^$~۩0@(bV=ts5ϛ*A,U?Rp]@8E"FMTG;r޶RZ+-ơ58]2wB9fM勞teQ1yQ&yAAceR?Š7mz ™+|0泠˳N|nZ6sK>rң DM46q5)ilhE &-.&sC;D- fO+RBV{'d?{4ql  ;j쳚Eշ~rvr̐t p6йiDY+A+0;%n*G`l\^j*THrX&Z٭.Q^rmWHJc'' u3ց="%kxn ;InG]4NoOH!'{?\ڤRld>T[Ǿbyip_y>Ƞ5Lhjz  gavKWz@Wnm t#"m{8iXȃTW}&b $dSjzhg 9$T? +ctmM¿F}݄+O*ҶgQP$5q,%xz@|Jk-,c7$=Mb&Aܞ9GgqR 1%?0uONٔ"WVktxxK%H\1C (7m|,-B(7Cϩ,|Ua*P>)X\EzjLXۻ>x!,E' I$wi}K=H:rnegN>#ρFUV\hKeTdXrwS%m/3E`~:Xhs04PˠLĚiΑ vb:xEP+ǡC+\=bq>#4j(35hݚۻҺ=h?i9jTFeQ~ZVr0yaŭ};x7ɵ^fbje#Eu;j/}/>TM}WC7,H!? |rUw\ZXXXW?轐ȮCUFWznz Yk Yvq4/Z9-9}69f>Ad.'>~o&<'%xT \D/E+: yi k_u,'~W3ǒzRb:/EIbͳs^H'k71{R~WDW._O }Lq#]R'R+{Bل A;]@w]Ƌ* FbXҺ&Zq`voGǂHflg'_)? R4QۍD*J㏧4o M3;,߰$7~I=.:,{x5pL.m76Q ?:Eѣ$H`brC9>'N@B t |{NIef0,I{CKs 1$G:@'N `"&]?Do9 ->:㏴DAFwxcN{W{,Fa+tP.._sxgEAy'u~5psruW/`[I:t̮o=qݰ^*9ԴgfҌ}Pu _Ӎ :fL"MZAHUs䟽M9~^xJw_EQP\\7+G\dy$7앍mk >%Lb@sCcP7 mMaQ=lJ9Pg$Aln6w^tvݗ=gh] ?a }i}c\j+.nYTgJ(jv '+4d_OTgogՊC5{>9[Q泭 Q!㈼D `xD-d3' [c^JNaDU!qRh/iX`wȅ@F\c?Y0"QMB&O$i Cdn?j3"/nAz<I׽K G.z;OUkwB?3#[2d/f%Χ  44kXb^e*5Qӽ qmD &KmE x/Ӣ;4F" 8h|ω6e S$;q?'#)JcO%AְAӯN&+VRn W ).o Z ?!qoS 딷{jKV~"Zsrs@Ba!jW`PGvJU\YIS}ۻ2IЕU-|{ @hjI%zR>eLclHTX8¢J{`ԑ"*DGӕ`ΰ(udu/PMz>0#g ֕`_cĴ:%ķ d1jW9A#'r5_l-̿/}f*ȪT#%|߉O*| zrjH9*-Yy /n$b}WP(˳Z-T__P 5X'1)>8zC-"B"1v aǼlB| N,4қTֳ.a+ o,_1J٩U9kAlDQyrz/AT7(jPdN[2DzͳAtݳk?Sʪ1ם}q=g$1U;Å[8Bdž#џAVRL;_ 8JljGif36~t(܅>z CB{zLҕ!jxgoya/һ8<= d `V{u/o^cʏѬ_z#z0ɼ1)r"|=*.PP{"㾫=cpytot.{_n6֪Hl:I=wSܱOHV`oܬ(hRF%AmÓ湮p٧e5<) I@Ҳ/KuW1h4Ȏ&= :4Hfn --C[WUFy5P&9N֊ͥWn$R |]09 Th췡6Kӣ7q{Q|( E-vOJ:lLy'E|Q"t1UC< ՜:Q%pROˣ>IN];+g mr)\E, @ *me?;bvr\FH}&`ȿblP^KFэ+G>Lմg&P GXIX':G \ͮzbW*>@Cۥ.d{+F7|8,W&e3c^,AxbyM90˼O\~/C 1&Oj>HQ2[`#J lYcqu]cnecC\x] Ǭ᳍&͕T]+rGl/FA,{"LuWAPxH0n$pra== YyɁܾʑ.-ED uG~ɚ_C:$% SR_-|Ϯ&೅knL[{Nh4pE){^JM e#Mt3בNN&^Ԥ80aG7ͶQBnБqI/ _H6I՚9p!Gy&TBP0LҒI,nq2+ҙ;؞SAc$9VPWboֲD؆GotwmARh{/G4a_Q5sJ8Z"l|d2/1ByOM3 w:!'1/ͭTq:8R~~Kf p= `912,A ] Ğ1-}(^H#]m(B'S9F3--D8PSd1X(@&xanGy뉎߁ηSD ;*Tgx=Hi ~ۚ@(&ϋi t-aڟTDU{A9ezy C*N)#7.FGE9څ𢣃daI<1nq?bN~" ]ĥ`VZͬ,mAyqEGlٺ"VᗶcYeAvƂ]?TVyX'U w۫ytVajC}%ܫC< @^ l/IelUDn𾉠Yo^|;~<7Umb/ŷv%tP#y 𢋃+t=cʞcɩ3Lr^t__NDbtp)aN$ ^døD N_xn5cGb<;znSMR29kFuPsyX5aI8H1G9kTHiOg? ItȄL vHׁ%hZYH>Q$v+]zHBN"ٜə..A3`0n0F864b J&a& db,f}--ijqv!."/qP;; _m8R^XF`q6|/5ό+Tؔubv{KjO؇y)J bS 9.;k@Cd?s˞٧TJ,D7ixGN(!vuEIWŽ990W |%JpV7+ hmZsF% /R)LarsG\D}Sܧ[ U$`C7i߁Rѳ޶SRuEfv 950JPsmJ"s-}.08!+XJ$.;.=ke% ZPjw4a%^LM$r>w`}MmE|:E[7>\&dGr67w`0ж')I>,VV Ax)ۆ Hd"ջl>#PK':(IY5Ȼ;4Co&dFjx'c󵾸/pS%dOM\F;ц=_ŀPBN-9zd+7Oba܍)6LiYF&EDhS"nŕ&]]hp҉_C_Z P?7%bzB(npn['aPĺo}3noL[c!ś(d'0`کr%E=@vd$ppk>#qC2R ݛL ׀f/>" VAr`gմ.NjYp3"ϏӊER`_'<!$"#5E3Xk.!ZYG0p԰m?m%I]Մ/_V$]啣lh'? Z-2BG+"CZ$ɾ,lE%dXE GDSylm3l(5XO;KsY%FBXm>1@V̖o`rv0\3f__a/;h2`ZwY"mE(xdy2:'Q{H[%.q&Kv<#;>Tt6[u+7U Z2'5Od&VР4Xy<0g:[}o=xkzUR/~,"X5q2Q |}y9?'zl}N` QpJ *;<& B{rY,upLdEܧD"~R7=VuFf>4mi ^2&ihßqd]5 LR<2pWkpn8ь. D_`1_"Ux>3elaHKp\8bI Pu0@rFJ~j [۩Z I1hc[BQg(1ٙ4D(86=:e+ 6&5׉%xƨ@8U]a 7mcz!~~a8QPjObvS fi|m IpD٩s&#wDFCK6s[7"sBoG~LZko6]љӸ # uTtF7܅^S, ᄘWК'~*=&OaR6迺W$/^Aϖxa{숟AQ Wu(r1?7<4)V/b܋54h Jm>!|9;/L6S;d=Oq*>"I\yx]9A>5tؔ֗&THkwfv ":p=ع7*ߩza4~l$C>r2G&#2:62l3U #06ʩgUyy͊EYc)\/ih[jmڠ}{R{L%QK7ѷA(2,wlBlu0-,Ъ) ף%j{{ElЅ)MzHy);;(/&:i1JX6hD.cG:pAdwڑhsevӯWoVV(R |7YsL?:3W-2hNl<]or]_9ʼ6Q՝R t2_4F4p_U]“fҽ: #Wp_i-JߐI]m@ :wnX +jy_lANEJRw)ȁ Xl;+Z/;?o^ΐVF6KP.Fd ,Cnn< /LWȕ5) Ӄ_S.iG`'.7nQFFEg&j/C{#T-fhCm(gPh4TՏUkDJ*\iTN;Jx"(U.ӿ2ܓa&:T]ĬE<, 4疥}3bo$m) ɾ-M/\KQ4S|5JQQFͿފXVk{U;m>i«:? —oӟ&"[Vb'ט3|s& Vs-3:1PՁeZn]N:|߬0ш1W2L?@knma|ʤߊE@J{jdJrH̀#kkZ Ťрm5M[K ?5g+b+FIb\ǂfe2%5٠=#x=#C?$'gԦ2O3-03dÈe_BO~7o%g]KPVxBs%#GzezAx Y?_9!( M*="cv0^0)V),`(Դ?vWe,䠊`ݓюqV{EYLYRh8IƣC[VgB=A0b5 p;dX\(RP?S`uL9 $z(BxTϺwam"2 .2X뇫r|6ĸ@8Ym&ԧԌfo1VfjvȊĞ0N1Ÿ=2ZRv( ＀{cYuXi;Gv0|Wq"YOy,78:ehOVzhﺮzP`.gݞcqV-co4:*;[j` ^[0Y^z5S6us)xo+Lb|ɻyHMr؀ DdK;ERٝ U'maQ{i  ;G!/0-/fLE*9%mHbH(d9RZiL_;VeYz#Y ђ tjY C#36BES qhu),qڱЃFYFH `ʰG@aXW™= ݺT t=3)7SMz W+xubr %YnSXer$3Mߐw(5;jQDt𯽻+,1l|%߾fUBo|w[͠F`JrL5Y6,ŦyȖ9Z[v} }o_t8\f;Tq}z'~&i&5! $.@ ѐ ]('n7_ Vnajޛxk "/-{P Tu AX7'o:qg6$yg&ݡDL߸Rm Ʃ'cIU%5G' VasHAtr]+x'1o췤 tm\GٷcX޳i UsJj`Ï"IQ&[eEW0ZnH6:sӫSb ҈zJ r3߃8CN/`*Xەb]pΡhv0zfN ?mWUֈz4BK<rh9xcM$(y`:yf-tHOh g]g5 =XIkڶJ?ۮ8A$Y+(mHd/c9\}TpnI{$ _,1RMqZ>'%}jP9,܊`xJS2dF…+d&5CV05i053o2=Ҳ>`QpD#yS#Af%G ^XUM{HIV'9QyJ%gQgaE:9ɖ S !2@{5wxVa{t}t d ɠHtXض:Q߳')Pq~8 eBˣ-zt[:}!ir5t*A?6ӢMxňv;:{Scvr+{\acKEq乶65ϵ1pw!b8կ2"ŕ\NLmR Gmz>uJȮHrGe͘5K(Udޢ3"/xØB&rC0`҉BFi]+]Fim` ("J7ww[2 >wewVx{%T-v+uOHpΆA'TlDڲbO[1]S/hoG.[8xrŵe|?_ïJgL@)sےKJCfF][Ca\>*#-L.7IMx=ޱtLveTn!e֙l2 c-uJ7Hӛ>_ڠWlo,w!^+t-R%fhF|a9-rL*X˶b+W<|Y,i&F<"rq':4N3菥1M7#`f67bO%EPH׹)laފzOl*u}*k#{{ɴC#eBXJ=HI LjލтftV9Y+C qVA0E[:O)!cq +T[_*`n9`9_<Ϳ~pU@m͸+Mu5q$~-]3r (lJvW☟1J;#YIGFA"7;sMbPyѐB0gl7|$RI"Ez ')yj1w^|*R_Bd+0gE?|ivWQV7I30!DT!$sv4ەa/'0q*f]%$vq p[8[h]9["WfG}8HzgHN`ߌy3b`Y7A/Qre4D3E!Ϋ~3EcVlQ{a%NN\K*/t/˔DթFoNsS#Z ð;8e!^F>E\Ԫ>τY1=Z%i&RJ}rnpm 8FRx|3" X࿁Z{p)&h7֜nvCxx`S\Ág5F .@͛?zw' A> O ={s~Ta *@>v4 HT#tV2w_ |3f ei|V !GNAy8BqD] g 6ȗS3-KW'nPJXT>T6 .-(4r %pl7B|,sS1 G&p4~ndM.#'OJ)U9` 5,G]R/Ro[ZVQvN);,:1Cvx.ywS/8ho<$#33͋e96Wm)Jw=Qrr-=&9kSiGg%Ǩ0L~fb/:W EE[}rG\o!yP?|l[e779<0+7z6Ltjo໧yJҌѤHnCyO[$mo'bzT,53VatW4ĒnS ii0✍O9ǝ N,d\} <ߤ xXB6xX䏅pA|!'G_S-o i~\1 t{Rg R&ʤhck74 .ʢrH!{o}+:VQ`ϰNC< =F~wcJD3JJVo:^o}EctuH"0a {mc$N޼F5|ACDHtZ8ߢ¨&*kRti-R?~-mIGj;UxSH)7dd2O^+^< m=O.]Ně.,gᗐAeSozm^@eK*\m]fhCzݳW&g0J2u^. 0%G& 1#hC]4J6Փyrl#;B5d ~ԺU }Ϫqo)Y_;p`b\C μRV4?rhھTT] u2]FPi 3F 0[1Ѡٹ o)-_D7cdߔ70LqJhXQFtxp^)aׄꬡ2jIbK䠶lXkp>yz{}}URj`E5$ E417gp)$rLjA'b["jTՁ֥ VTv1ҍpNKdw|OEW?0pZ@9p&"@-@odo;l ,zHVLGR-O!@F!>z١Dp!eC @i2"1p獢~.&Qb 1HUsbvT{8Dm0۰-/`!wscQu Gz~mMIOGΐf_ɦB5hnWm&_HHtêzL̓1mM\顎@`~ځ/g#GqC" ;˝|%VF$Ӵ>9fN5sD[ R{TWT 6yH$!)`ȭ?\;%5&Gp0NjSVѻU7>9)tQK<ĔQTsq&chdo|6[d. zOCw"jL=|Z|"[SΡ(.>6מ>81 DBzݒq2ͦdPt{wm˿M]3ugq(:PxgM3 ek]%(%Q=Xp dɂK+:]9G'A֡2v:p]>&p[snlI_lo{U) g-lj}Ju-q!24N%W޺\6yY00ZsAWG*| #=syy[HzltͶPo_!/pqH%b[9Hmn7lF;V#y_)N;svFB=u_ =@knగ<l"bOpvGnYEa>8S CV2*X|}h6v 12~F C&?n/XPB"ia6՛{@!ƶ%=8!ܰv/,)fl=Á+s"|FBtZƜ2~W ."Z(sJxW4uk2Tj.N$VKK@s(Q GNa(WorRH3w"#NHUZX{Oꚣ #W'™UMyK p,V3W|qfL;V+|~5ycYaKN},.TW'ガ.  wei@l+)kZN _,ZelJuGʞt ɿJ,4ؘBa⫐4%yBHe2G9s#?9T/N' 8l:Mԋ\ߝJ cLÜwEʥ c"SRq(~yْ5mWevwtAHz2ɵ}㢬բO^#]+·XCѐ2 ssA'>hK!Lp)P` a<2'\BIW4ߨ/fa:$ SWô*?$VV= +k/[CfzgOnYL ӡBEVMsvΪMX0N+O|r' /q!L-KYyOyhG7S.i$qy7E@PA>'Z^XORlXc fxk Qp[< r!ɚkRHb!sVԚC8*"=rMq(@&Cz.[M+6̫72xDY)-؍/ *!D4A^š[UR!+8s sVȇS&IG?Y5 sz/Rj<9E063eA}8}Wc::"n1 88p: >.CibTm!P翙4[Ч$sAoA43V7ZC*XzCT@Ly[E(ע=J+kWħO]̶ TAb8Ga. [qWh#`;FHzB0K;neka(Jtݾ#5^P* K#tU 1Δ)+ۻsm֒X Dx5ur>~cIDI< =;77My6:G[^Z6{Ij9(@!{4b$d!I7I.ӠHPv>knUQ"L6*^ ׬ (NWqے'ؚXiqYw vs{%P1_9i>-I _&^a8-~{m-t5xVd!4_[|sTO|yW's2QRsGfg9cߔIt6Ac-8׬t@gdSڑDMH#lQeu2G{@Kk#xaWJ=0ɋE 3 ӾhX4.,.c L],Ď CwkoA[_KFl;Frx9א =rٶ@uR ?t㣔u5ayBdYG,G 7gN )$EJexѴy\+`pL`w7L^ZYz+!A"*!8]׈UukaS"kv'oο%%1Y[rQye {"PG< bڒ#NEaŠQTTLoHq &o\ЭJ 9rZ9N(uK%x.Xi-1&銖B(rG\hWXPlաFNQ}Z恊} O30^!rplI벳WO'aZr7I[N^hS>{e^2% h\ڼ1mV;+0de#G [/9+ g& C\NtfsGԢ/" GU#擙<623oZ _&cϑ\0|ZrDlsj jyQ-@=0GKvOOm1qrgiODZ? K4sӤ|/`Z:KdUB{ ËȞ=&m_I:}(x?3* 8}D`>@OKհ;O4%#S:Ǿ2T=5K9z2'&b(S]>ɚ$9_04Qql&F`-JJ yPû&)BgE#һѧ~\ Q^]j꬜IS^:L,޳Yr FpvRGv([!EL&̏1 Mno[})uW 9ЊWv+-fJ%%Z]Ok9J.h$/eDk- b2`bc-̑vJL\*}cmR5\q{$pzV^[T{MWŽ4Q/ޏC_`RRkpw,0[oo: `y ^Swb70cϸ;l-x:M;0 EVF#΋m}X),b'1<9Lξ#0+i1S9`E9ǔEuD jQ酋]w=pk0~aָÔ4<fu:g+nVGLr]6` >D$%S!RGZ3>/Ptl>߫7YQ-\$b>bl3em:$Exda{''qc.N{”vŴ+кQ); S$ Gl"6jz<wD*(Oi 6&'%Yl{,A^.1LJgJj2AKwFlY0!nދGB|懻|Y;98]@'J+n?̕{b =DCG/?̛F YUFPefw-5S!%z(ԑv `J ʄnL(<ͺ Oع4^ӡBxbR7D'ny .f=Rbi+ݶ-Y5LlX޽^EV^!7ú} $hY?-a5{cFy|G*e&Hf|#aUNGO`׿d `m-'(& !۬n>DY`tƻ%;CKƲ/ Nh{E6 m YN#yC_k<В>,. )d"vy2U1>_= Qj N@_tO-cuPv(ǖ-!CƮƄZ'zN:IP}@$Tê*0>PGU&؎΄ƈPMB4Ƣ04xTo&zJOOnDz \d8-vh6'Pl{!dK 4"*蚖a6d7?f/*dUQ&z2=Tq4坤q G4:=6DK1kz[3>aoHk\ŵ B - uD;*UL=gϱVf Zx HLs|f<չM;[Zp{rS{TU:j5Fg46׳j w@a0dV8)'3jvqw%|:Mnρx[7x+$·ipt몆D=THʇמ.BXkާ?Q[E?zwM&I5U.l3WRPJ2p-)YIo7 `S3ڣK  {RԩHר?)bsr byG|B_ct㊥#4QT,flf_)%ZXY] ZքwE;E}ݒ7Fu# @xW)EonB>E\|ڬfǜ 52H+=c-IY2s#a-q`cS) ާSB'rAsBJqA~ 9/WL2jے~iw?ٖYYGYB:tG6tfu`tI ϵ bYyXDŽvH;nzӞcG?K.r)rX3u G+p\5-:ƴ# u@, -,ǛNv0Ԍb#Ʊ2Y؁>rꦏEbp|}hacM[I]h;R,1:zf 3xRdHP/!h8^wzM)wJ&Pޫ~y*\O79mc H܊xM)}gB! `Pԙ0MA(9v-Ya1{( }H0q3jn0)N]u+ɎZ3Z?-q+ru8 TǤp7tk%u1Q1WkeGӑNvZ߶j,[S?/ Ρ#8d#q5`-ho wt>>tyDcoL*FG?I2.__3~zV0ŃZXRv!n(02t.b؂Iza`(*+R@ s6ކ2f&hڢ^K_\zgf&l1]'x!P;&wq >^~A|Jl89zH~[y +@(y'aݬMpnkPֲLv>bǿ)@\rK:'7J3泵l:` iNjkkMa^]8, ҠյAS51ƅo'fRUs[O-u\KDXSI I `Hc"f.}_A}q:mC,TU.]xiEA QH 8iK)]2);(FYX8R1t.Qx@臧[1~!E| 6'pڎי?;UÍCVt>SFٲ"<5qE{PPyRkorD>bp*~2wW0Vy IhM!}"0Up)4ƢRׁc,@0whw+6lrur*9+ph8F~}p~]G]VF=V>Cvǝ:9wa=!{ݔݨib Z &٤t+|G6pɮ.p7*S@}+vV"$pթ؉CA-tn ?wOU{5y^6;>;5z3}!A97 |:8ƁѪL3!,,'/%0xP6+dBf,ǩl%M#95xw=qjڴ4g|3½Fzf_/UXAezLbs>-ґt\p cCXQDtXmXLT#)QL Z!HzB+x i$GXD9L)fc UbcdGD-p`Ͻ,?1ČK+׍.E[geϾ"5GzSċX ݓ 3U+~nd9RNb,lt~q+[kg6zq."pn1v:|,̨Toj@^RYrx-=]`4;IsݔQoyj>ӗ)FA LfM;ǖ A٢g֫xsWX"y.4eҮ 1Ileԓ* k')ݑ$w# g!V]~CT'eV+1җz+9X&IhCuV 8,JVj o]|WrCߠ%R}LNrnDd0K Ǔvh^M(2nEHۯA>xřOiDL;x*CmoI˨i5&8i R"xϽIH!pG_H9H(HѿBe<{`y:n (+Ic}@ഃ(J $l)0RܛN (ګMC5q3UBO]67 C&HZ^D,u; R$0 C9";#gzKUeeĹ+؟~?ZՊgv܋3#[üR'2!pKj j 8X,G!? Td\wr߲m< w*k;0z_F#>d#'MO6p,#h09KG}ZP-{IfG-E*oO?iG ҄VGe,422 w˂IcxCb5m*?19nLo>C4cgV3df7*?nb_ieL&KW&zZIu(Cf#A` 6L7TF7V'Xpjc-3n!Da< 7 ͕`Q@q[wL.D&{#A5 iTlP2EJyv#Ry\5E )a:Ǽ᥁>0˯;Fžتi#B,ϱlބ1c*j3$*?y0xԻ (,rBjֺP'F;N@A2I'"PZU=Utr RHТyZ,6> $T#dR&*s+v-l3l{~1v8| N- jCe źP-_gvRS=hDP.OTwI >i@ʮCUv c*{@z5\UW`LBwF0hGь^.'7_Qtst,O*9A!%\r1,8UhVYÿ=E\4 -/ @uSz7֧ u+l]sdIn>V$/O25i,=AW(- "W[ Z@ U>Lhp8d )瞩Ooh)N7uNJ!85Vώ F]"8k]?/7ύ,ALHN|r*$&! blK), >j!.Ab~n"zj\ ͆vephѦ=\D?e2AEhrBw;bq'=|˵A"7m*[v:&X|aGAKw}&';3 (oo=C;YU_. q=عNc4-g#J1+PSۚ_L9C{N(&М#ͻ8eL2zD8l!﹗5$-&V}>>j\qb AwLcqwNUj#/C"7|ZY새e65̠+Ughϝ+ui,ch *]\qyFq+kP,jT[ RC>n^LN( ̠v$2 Z${zӽ`4h\Y9PӔqΪpHU]3ϟ9nw_/t U}uiߢ &XF~x +aUrV | `{R:S\Ɨ^KTOޥa\7(H,F`!$JY㕺[x0 2SzrrIevFWG iq`s@8iju}@;/ŧ/v˳t>rlg'5cRQhޚj]>5#ɐ< 8nl4|c~M^ԋ`W!i7nqz'X%(K`u=&ƨp#Փ =j p'NOPfQof@X JtCԮKD䢝U2ZM0"<*Fn)d6N]I1T4z\l ZlB؍/(;s )gab+-XE[Ȍ@ΆA*;cXu?3!DQ5FtH2R!;_hƘVNo=Pl./,On9)[,kuTQcҊ'䌃dQª?  No˱q/-S_"cX7KCO,nC횂xa;|ߪ]GMNf©12BEO)0ތ*W kl [Ji87Gm"]K|(!\ p~ܝAOϕ]pcBB;.P>b>eF#S{`E *M5O@E5> _A¡ h`DŠRnOEK 6?3ef=BpͭUBĉ H}k} aʑ{ ^ZݱyIN'85x0:hU!V+x}(˵woKTU55Arf\q{ #oEƾS9A~M*9_m{+5qQL>dHyUWLo?c_a2P~QYdh@tn/r`tV/]I?m >V\$.ޛ'} Z+)^"/nm"7UKE6A^0C;͎ 2BGr)j+b )b;_>bDs/hT? &ibBt[osɃ[mP}n,@R%+7Xxj:*W20ryC{#պſS`\ CP,8YA_kGȾFmc+$'˅;U6TЉ+C.[kDal3Љ-KpߊĽ^2ndOPUլ 9}=f/Y;%Հ3 BwgZ; '<<@XPO$wxK2?V|o뜌?B $b/z])WfOCE`hlK 0HՂ[_OApGrm[tis 3co_nUi!|{rĺ|FK ($2M0[jrԛORbUV9vDi!8ӭa:Di'7Ne7"ƨuIxKn Z2??=lѡmTYlr̓q VD9m) 8MܣJj'NrʱWɧc1g`<os 4J`Sn=FP^peJhnJ2\ "R?5pIt{'Fa?Ah]ūρiy ,;cĢ,xfM ^6T}m_>g7mg.XsNuhz߿1}BV[cZ 6:%O/) E&~Z M≸`_gZZBI H`L|T]1d嫈1n%g(/9ŹA`OCzEs:M R`w3V 3?)a:,-˛aIZQNRQS#Ψ(sEvQȀo&Jc:qC]:hWR6$@m*yszZ*3i!1W*c\NѹsΥ|%|t%Tx Џ ^$EhyWׯu$I[u#蚍 rZSݘExڛ ,?+,7]>NaQhG3ު$aXZkõKoMCKpxC(PU֒{]7o\ULkoxפ>زV~nEa\8$ AF?~! SnGσ֬ItLFt`a xXLҺ.f{&1 ՁY d3͑7.n\$".Sl&Mfz>HYR;LF%_>cꚪ;`C1 ,T]yc}'?D)SIYdW@wXi{zT?uj9y(Y)rJ1L.\J BkaE'SbZ.bQ]P% -aA,$'* ɽ-?٣:c =Bɪ27- 8 ڟvz}شj|cw,2:PA,7pڃٴ u'F=F8O/w-TM!B"+sXYq!a1l-=pjk%:~ÐoxؗXcw|Yg?:(N |ѕAq{I5}3T78H[PDRe^:J k2f(Tc s1H~U{, M0`0a(xMy1W9B\LęOj?5_ rK^wlqgR7*b_@M)(R;p06T8dVSE?>,h'+ePImc>)J7y6"@+"!֥6qa->}Vs7Q_`swZ0j eoW5$3dAud)GdvM$KG r 'o~=|eV?ACCF:6I& VCo-[̿ k ;tol,$9{dȫ;Lݦ{\ݯ3-;I1?K-Nk*LHx;sԤv``_FgX5ڝ&+Ļ =b2Q%  \jH/+6Lș^j|6"йѠ/'buWuAh,p #W +L*K;T},w$Ctioei3!uX/Za|_ssFO@t^h%~Ɖ+5p>NrR'v0` _%l=Q+AZ1*6:\Dr"3|;Oa/ɧd&~'mfqr7 L)E[C^s=%(svg}/.Zg՟X=r A߹*~x˂qJ1N[*jµ:J~Y9+kl31BArr`I(<1b*daI"[5k>/zX(.Zxݷ+@W5qlS漇et`X߅Wҟra@a}=?%zFsS9/PU3_?# D5g9KxTL(?" rCQwCm "W< pn^u'!$ n3q  XJ$ȔN[6L%?YHC" Xs0Naʼnx.Y{/ )*KbYD]n''{t E.]p\_JE4gz^ku .q{Y:0qy"V;(ΔTM!eOMF>Hk*^*Q\ X"=aK䀐yFP !0Nj䚿yfTJπ^n1eFi1+RTжZ9Se筛-T%rQb6BmY|aAG&xpkO 6ֈuǶVUN 7)WQ0O]_u H"u08´< {/~P`pًڰvZPg؎H܎FͮmAznQ]" ]u#V%Cq''-2AV$+=9nhvi[a\iwccV9*Ҙ,UV*`c,T.weЊGˈ֨*u,hN*' )B`:= w)9K#{^axc8L`gSNxXuߤ2@31{.xvfy/߽9D}݀B2^Y' B]ek^r ^>薎Vk>!LMV' `\=.ԇĽ.A{%~TL{>Jx d5lVܨW[0+LU|%-X@- }]F>d^ K:(oOڙӱj8zϸUEYz}W?9Pfd7:'̏3" QY+h\q-nvE,= XdVw\P,1n8}h ,Qjro׃L iu\Ik$kZtEB07`r~ؚ&ka:`8$=V< kUL$hޝw(17}ƐTDJ@Q5MPѠjx, Lz߂hN*X,IǮ&㩠 FaSsHY?x)pvWs/@24RMNng@o'N K[;k%r *|t[YtQaM?unbw pɜU癙 $sʢ]@`D,%XZ'|hSG 'y֒00,sNe"4] 33~:0:fx Az]LmjeBcD_A?GMMrڝjE`ɮk֥Ÿ]QoΆu}zr00nhdW2tp{|vdZ6H6)50 8 8=fFe ˲6o2؎3"oP꟦t(_0þB̴ȿPE)0iN4]3 /pY G!Y)h_ΪpWd|賧i?mN>;5*szBT(jY]mjN L1uq7إy+aP~weh;nqoK@utij`+LwW6|LE/O9Q1ѕ5E^FVMP3N&sB \dF@b19[j7Mw'"~2y9dgdjêI5d7)Pt@gX#Ő7%jjO4$ (J@Ҧ: n֋-#oN}n )҆sꐏPGg,,튭C5-+[%p;w/3Ԥue @Rh=T=2gT0JruD [Q˺eIES*a/Hx ۶v$Cf lcK؎{kq@|>&5NjЏ$ˢ֤cml Vc^>l9=;4n=n?ҁQMF=RstSeZfX/e2c";]XLۅWm qߟj~s/,(:P^y@Xl4E|$IOU!&ӛSmMs ޘ)ઋhE?7X|HtԫZhsUlF^ ,RW#Q u&{OɒW -(5Hj'C9ƝìLC*6dڗpi}VI/jЖXfv/ uc!U)j33 <²l~hD;7` qcײWTM)s2>SCjX1R*[TDhljuzڟ'ro4= qiŕT" FӚԁښe6=CUHCz'k5O%$̟DҼ\YM51VHP&̯'!m(ݡjlT Cw}hR-ϽG[Ce]6ctXR{:|$z*APԄ◑DmWZ & TY灵0DrpbwǗv2܄v('7=lNCAP|ix1op?CU@ُQ z}!)h`WǢ śػ5^PP㥺CIrZj,&J6RHfZCNx, 2Rs7$erhvL$QLgm<WYMjY \Әv1.(6g:QܙHm; |gV6ꋹ9IS|oG9ʠ^7(xS= ' YMR.Oh-a3ؖ8@KV:h,?O8=~aYVs X6fExrqŠ\_&E9]i=v NZ.W&Ѝ0Ч[9>: UBhbLq]Uɡ(f#5lBL){ h_19% Ѫ0X,WMP=u"بH@  =slr1f+ą\neK>`0o5T={gj~^N~B(cb2gh90EQ4E"b(ԈW /RpOL<}4?jm%1h'ol ijWH*V$^V $jƹRnh؜#_[9IQq87uL"BR?q%&M4;ȌQÝg"V~]p>5"/.fXYJsOL( 5|NY_Kj:T+\{P@;G?)B#E {ֺBP2NoT&|U\R$>+ЇoT>m6(TyB.[OIQ9emO<(\:j<4DeЬ/!; "}-w"ţPsiۦ.%vAe7<2wmK6cWh;hVJZ,zݴ{ݴmcafȉs re?@>Er ODZ4:FX*_/lNdTYlSUdnE/;=G{;t|oВJvju)7F|ru)/ 42ٍ1ɔ[ Kn_[4]sDQhRz,DPE8: ~Gᝬ̷,'ᗶDF Jzzg5hSi]BVx}]l*aAj8o> =ĩN+@vbU?qT]TA/μ(Q2-y6,P,C86xն,4hvbtou3+o `_Ӌ 8B̶\Q3RZj+Xqv a2i8L1(oJ[(o"_Թ$@VT` 4+Py[&di tۑ "^*d'< 臕V]r ,fUeq=씊sE$,O7:DUx8 gif)f,L8>zR.OC=c+um ,O֐.aaʆJ7@_R~+56҅up%?ҎoDz-z#C?ZB8o٫L}ulz#갶 C#" pXqҤWz[ߝ05 5̵Si۞xċϬ,Ҩ$"}/^)d&n.sDn#,=CXF9 m>AK{&r*zQؘ +xi3͒|QǬ(cc)KYY<w `$Mΐl=VSҺ&Eع:pX[2[)nOY3HrDN XsIEn 2܋Ez]!ںpLeF957հ,C+kaϴhQda6OCN/,o@s,W.vk=cQQk|Q;v͐tXYNm&i C4kN] /mR7 *#F +^C2 cpiHA,M4v(' 2,>Wt8W]t oxʿa;WXpGUcveJa`0nI{/'n=s "r<waWӇ&\|pd/⛴=|4 'ʧvdZ\b'ɴ:OA+Rw|<*C.|*rVE^qUli"T`gk`xX qAfΦS!Fyn Wf\'2*#6(Eϟ0䶐{)0K`s Y.-W s&ǞsJHWWJ>V]pwx!dQɏ<<Z'M +Ku4OEvDש2wRp2 Jz1yԇ^1 '3),d":;*V_Jpkn$ ?) `an@8>A^ӭ?Vm&6q mV6~=Qd%KiP*;o8O'm|z4f6c䏴Ԧ,J,?g८əLTߑڊqU\:6 %;oGj4Sݹ;bhv "i״қ) >󚌒iV`reA7&q%c€XkMJ Fp o@t(պ358|A&4+v 7'엌n,{4eR2ZtOnf:()হ1 xnzW`7e=c9/6`C <0T}{~ Rax&T@9F4&CKiK3e'"ZllrXuwaJB#} 99"ltHB'"?Bb+'tAB|o 9+}r+;ˀu'z6/0L3]oD"Mӳ"ȒL=d*h@[A?qRn`+`DH fX-Ձm6@: { Y~/`I,pJN>>[i6 YMZşڕq\8xpdYŌuh7,C2ʻ {R$umx=kܛ[)6+9ٕhJ nAx4~Էbn_YOHOбkNKlycaj5&(菩-X1&27@g?,i|#[ebUWei^4kbwl42>>ǪWB[ h#:BxWԔ˜h]uG:@U}gפK^QBwurOZ' CyA鬞*\SZؓW2TTy㍣]$"Jj Af]4rjUzcȢL6boQSM鯷A LSAYZ f'D/.ܐɶUoÕviEJTB 7qoBj셬[nq~e]Qs*)Yx\&"W-ϗRb@seL1[2ɆudCOu/ۓR/6,X뇚_p`T.#NGв44YwܖEls6M37".$(dҜ:a@jأ%A_N{^3ddG;L0. {zr9.3?CM81M  w'J1j^ͰFB=+<_ߖvJթ;|c,njjsJ3aAH~DgԿǛ-fGeWESgW_:P[Qsn 8 M[YzmQ/8R';ߘ#CNk@- 1 yBI4_#[Q|::/fiܽ\ 鈗ۈ&8Mt\Wp.rvjKD%Yn%x ӽ܈5 Te4͊^ȸSB߽:$N<@;5rCdL1rkkZ`L 7ң|;p|h(b*7eBm5&eQOlhx V stÓEBف8`8(| cD G IR*5^<FWxi(Pleuh\?cbOt|;.W۶i'k*na ۜP|mXmuxMpѰsA">jAp3lV][H۲9 D,j E?C}bh?9!jwS SΈnL2Y$yj}8 lEsni3䍒 ː ՜ I Kfy6_}f!fqW0[x{ܪR;~{q|uP$X.xnv jSozc޶lGc˟q/"bh3) nHN$&y=l^px=TTx< 'l'Z(6M4bͭIQs;ӥK%KG F?x'"Iq<7Pss6d}YY]'C0; 4NUHE.ؔ'g]I .Yl2RhL Wp+вȚ~ҫ 3>U %bVXdJ!m*0mzIQNRqt-<՛!;` 7Ik⩿ (< "3q$mK=?;;?qD\-ih7bMz'`\@:Z 3doC4 -F} Dofnm%^YczeXbQ1jqjKO̦/A5h?y .wѐ?;,q Ҹ9cl?uk˚7$ם礱4@ Y"Y)YzRCw(aCt=<2cbYWl9SV\1'smTb . !X9>* O6nttHbKi߶l P?1u㵁$ J".# 6%z[fyM>opٽ}̛TbF Wu_]E q97* 4MW7D'1~Əu[9#IPΠrp@~sT?jj|FA8ߍZM)} `3otTg)2#cYt}/Xtq p'wJh|\1e^|ﴲF6^̧*A[3P[^ ~[_|z_Uekm!-W{=P{_g KC(+ie.oYA, W@ݎ-&Z/z^$x6a!,S8& Kȁʷˤ#=yMD6ϮGoA U:H9)?i 9Y+9{ gͼ u@f$CqksF)0^ RJ-NnZ5‹PrҌxO$(JQwᡵnu7:(XH݈4V K}M|vjJYX]nA!3Nm缤62޴I+3Hsxu>fh 5YJ 4/oj~\X\ n5q+:šO,Eb_0Q6篗 }b<<_c WVNݰ: tDTJSPhhn* ;+I02$d2WÞ1;H_9qA;s=GTx{#خH0VP]z/b|x6UY݈<֦2@؇'A8YQ9:92M-hiʉ*xIgs?ş%,  NqDsu FN92.ZZ P#&1i8Ujaz¡nm+G1󬪅3xuݏQ]ɋۃ=>ևu tZZJ=?tQ3>2:yz$]%PbbqwPN<΂GVVaCLAI?' stڮ0iaH6D~33wMOa~u8n#r$.[ۊ|'}6 )0M;M()91P8@eS;KzcP!t{19O2i,bkFuXT-5* *KA֙>] 'm4DF㰕i@?Myy#jI\.k~"j:+{󑴨~&'IϞ4CThf(`n+%;M#' I3U†tMӨard</I&L> 6$}*>ыj$/WdM-(08&o?il)>Qk) |C˒[A40d4U6iTw3ZMk26"qsB3|@y4 #fIŔһEn{c2>#ڦ+K7=g,z̫S8^euc,yrxU2*( %7ߍeeoG΍A~ΦR*&l #TY+mC$!"*65\֕ G1QLj|^h-ݒfyL_VSu^ fՉ)Kz(P n @!(21~&t #>w"cҮ"˽?A GBEVCJRy[yIE,ZIѽ4{f6pt:-|%ڍ\jd~L:.˫"6Mga " AN|\8 CE`N C+?u$l]Ѯ}[#l~u󺡮pshQtQp;QPp="Jk \E'+3!}\R{wCr'a8KVK0 MG(`'TKp#W&A{3ϽsǑ6n)gES8DWLͽzmpgIJ;)oA*"i:V|_] pb/o OQ kLKX]miٿK@4iyƙZ(g!~a{g 3hfCeq!3 Ĵʕ {1qbOw(^N:kz ͌trYvQ_2ik; ݰo~^ʀ|CT'lFHF9RSAAqLa86)[(j5X S%K>~^[%u>U+[5udNc`լWHnǜDz?J*䃶G oab פ{=%"PGP>Ü1n#(Јn\E03ݧ2lE=VVu+%TӦVZŶ+'1\"0+qɴ;igY{%%?$l|8 g(t;%B-YGb /q 69ٗʲ+Bz?~q֡¡F: 2dFjΨo9KJc3NUKnX[$_{πluDa2zrLq*42B:.a;5% m_J16y׈ɸp@pQ?1\9+Z; ~3C=hI4{4*U&(:+Q1<QaG˺o 2K<7W%CT_LAM,%PܮqJ:dTg%oJNJjg1sB\\caqraaMN.`&%# noU@; Zj7?b 8S$Y$T8jI`Gf-?Qװe5M f/b_4$ 5TF>R5@nFlV8@bu^]ne=K+tt# /V&-"P`fQ] |,H]ߓ5XTB)(ޟ׹djnǷ95 &^j9^ H@8Zz[q-y+|FT,KE>U//& 2D :u4K|m}uxoo܅/&*OO^k9MB=1=/,mleG8xtt+^=@#zumlKPV/7) S_-1bƦUpJPHAxkqz̋ϳ>+>o<$wuG寂U~ЩA.DB+2P:ob&Sp>H1LSI{֏w 3DTZ.W EOپn*?&@7P_w*VeKGҀ >nH^ ~ O *xm;zRNq]J+Cf*aD0^BO`Tk4O\+Yؑa;e>'3[ע@GN|Y# M yVKjy埲 Y2oqoKyIUTEfc 91E9r*4yx{AjDaQ^m/4bނ7*R!{JQzȏl`xν+hLw0!LY0rDb9ZS:l`kuOb IuV嵮?v &@rI7*cE ~IY4@t<@hj.s[Z";4#UNkm?G<06]c΀"f-$>  Y@$-ȁ}*;N6DTrBr!Ԭ`NrjC)=PrrF"!ڔX@N ϫ0k*fLDno`kp ̂γUQEKa'd&YX돼Y[W-PH`Lۄ9 "~BtfxɅCb\-fDEPu!+0!NRf1@ M]DqDlocN›K>җ|_ 2!V2^{nV:/KnhF,J;S9m]a2G,;KPSPSL A<1š*Jwx].7.pb)M)9@Jvd3,,((zKLb]X;_0Fg#/3ewIg~6lumZľ9!Dc8*r:n[9ȸ8銛KRjVt95[TuE[d[2\:c4~ 'K_aהE+:/WZŮSL<W_A9ła듘d@ۓyi[ M~ Fd"5?,khSs[b?>^v&}2!{4e +,.L4חjB7 {p%B2&~pX; 'Ln'bp ˅v doo/'VbK=gz]Fs >XWñً̿Ź6$P1Gi'F֎l/RXZ`S1]k;*j!@c%O,3:* 35Zz##g{AV"9qpKY/Z$T7٠=ҪU Q<&a r(sZY/xzv&7'-$x EA";¨Z{2{;%O7A9V%MAB}2w o|u?Cg.s33Mek>'~L`/UuԊ?VdbJ>U1ߍ$iXUH,))0s :&']|PZg󨒼>*!aO 2$M#: qnC4y>k$ljntpO xM)C765 fg1KjoҎz-qLgV5 mܣDWvT O;V % e?9f9nEs`*; O(_aJ1eFQqKmżI_ oXwM m1Ƚ"G#7?"ύ̶_&bܵIerNZסOIN l;s)(LI}[ ċ^X()497W~>O&75ۘ($<Z 3!H$n${NU •(x%eO*|RpNKHIRi.EN'ۜaˬ)fh\8rϒsn@W(8Wu9s3!K/J~DpqZϬg!z0gO\Ґ(e/Eex+LR溙w3&zAc`8 qz)z@wsa[L5 y2A<GuYd P(g D'/RkufMZhFUhaf3?jN,Ok~ D,]/U_ta(t!ٿ bfS7d$?&`X3f2z;g6mie-`o-% ϯʯX`5J)w )[t Ax,"s{Gj#+#}zn@ii,W-F,1ng؝e U-muFe*ej[uzPc(^-yފ^a'sĄ'̫_,栴*E<&aUOr "v2k{V-eX#\CqrH}M=0t3_GjvŊwߤNe|l홃!E~ Yr(9M+L4FEx.*tRQ8(g$V5RΡu쫇 hBZwytNefD:^ [<$8m0 (Jϑ[1^z̬.qW#okT-ȟˠ 7lvHU"MOiC!!ɨ(.OP@U!-ǓLتnw܉ym}?*Uzfh bL>oટ'_^ ZX C*iuNs;U qB8 ΀ Q\A}*mUr T=zZye$v=xY sdcUD(Ȩf.upXtMyHLNh S8{!^؉T[zrJ%"0?EULU!RYd-즒JۀQּH>YE -{+$9D֛~l/i5y.=,IGg{я/=+ȊrxVz:z)1#e *DNg[['یREճ)b:2/UwQQZWWڽDݠ.Ӂ-1)rUn\>.N&eW?Ҍ&t-|[2^I&b2~O "|0]sMc(E]*%xiw/M!(S0ż{C#%z܆nxMr?ԁS>h[]O[kluq7 = H$BHEm`%S㽚F#R Bʚ;*00Y V(G#$rt6p&7ݏpWͮpb,INJЉ{&č;MIM0 O(}=jBJ༑*/SsƜ#3h2iyp 6@WT9 E^8J!X/CY&,Om␫KBMi xL@*DV;ABXNݲ!I(ua+oeFuܮ^דrr(.6 6OhU i3qS`Dkr B8aP+YH+/Pa M1,GiuepBhLHVki󱧞ɮ~ӲEcxUbel@'x፜j4fʷy2N4 M5'[( 8708{c5Y=Bi4$` m" <'aaQ׳&o3M&J|iFsXaz6ڿLTڐ Jt xa]D>uR(Z-6)U {TЍ[ߠ&eɹP)r,RǼ9& bwx.6Ֆե|n#W5{p٥<ĸhQp|yD<f ~Vm}?<Q=/hƃѵF9W hJJ+#HAPy:/n;^ch ]E(~?ۋ#N0 pjn<"C77I2S }QQ\gLhgB<]/'+#)lgz]o+jROABP.Pb5yڂu=S$1xȰN;^RD4*YeʤNJ$ꦜ7%F cGzf"Z.AIvJPhg=~$nW*v*s6(-Nr_0u|s שKZvbmv$8 )[S|:ˢ)6+qH?$hs# [L~N73Ȁ61G \[]hqbix6ۛPr]]kl>]B2=_IBW8lc)BCwEqe!Wr&+a_ mkm6n.SF?[|FB|(6*T3`r6Mi <qUM$u~“diJ*bՂ G N76cg{&OV/  NO@]/VIbe3| {RʪICWUĻ.a2x8 =2[FQc($GMPmQӓAlQʠʹPq;_$Г>/S 4TsJ8Amrz eKfMi7T@Oۚ_k:!*:P7 ;%4kf|ISaL{-]XqvW(b'D O{2xKL[9L߲7x(w8 a،4^T >)-hW|h\ʯgmQ<P7HXa3  -OKy/Jƀ/Bd10TB,xWgzZ7O)}2t-%&k^RǓ %"7I7d?A  DOE5IO7W(JE*gյm"|&EJIpcM80&T:Wk- ef(㕻ڔk$Em.,0=h:R{F_IugV"u*BFk*3 ['ɸ|\>G3Q?돠i~VI]c7PO<2.?kOlr9fP`zk;SXםO;oX0Kr]0[nL(˶EG,FYd6[a냆-UR=-q* ٘@McyS;~G=WMvYmpH 7*/ù$4Vum8Jj{wd=ŀkz[m!rJʚ^Ù1qܝo:;%0ͶQJ%)%u0:*}UR/AFb%SY˜ܪ\ixpsrozg0).a=UsvYP9H7a8-@:(v9N_[1 (d]7} /5^* 2|0lBnU=0sR n3rReW㙼zN[H\K1ȖW$QB5 =@)cOnFs{˭A sD%M0|2'UPBjy'Qd`m"%)b̎YrkTMOuz yhղ-@~8B2?)۔~ KurHF+fҽ$|\T5e6x┮Yjø6cR}Z].k3| 4^jUMN#Yuܙms ,V S>Fo"nc!= Sj X5Y3. a~-GФIaҹY).X;6z ~X`Mt{*G|tA>2cm]_l;|V2]X/`!W?c8{n=+vW T\ Ɓ/e˜v:lBkr gӱBNA[!;畕/Kvl}`|1tF?bhh ykIv=kvu%%}Ns6K< 朼ɠק/4uzZ9%Hxj4+ŅTE:e kwx*+78&}aYxǾx{~ Y59wuXigPmr+-G$_N*K{*x 3Gǚ(I07|)FtĿKl˗R9!>e72:٣/"x#':-=ЋL}^)d0V l~(2ݸ#+Ef67=z-M 2 9s} )}Zc/bI_!Pr"q6;+v/u\.`N+x"Zv I0}<aP,'Qw~WÎk1i|ɟ$"2(*?9U^e^*3cÐ7 ]K~9&'&n{tXp.̦%WGbj@kv#[RD9)A)I},[+{ں^xnN6'iZUd h_y2hʒN~]%E˖n5|Mw7o1D5A'sќl|Ϭf尽C"F) {QK MNg7yczf6Kr3QxŐ :S*Nt:/|7 oOX2a `RE5&T7[z̔z\~z~ HUێDԶ M\޵7AfG!B2D8v"-:-bekxf2͚N]KxcK#ouUS)eoAH{83>/AdTEզxt1z ᐎNsDnF\38v/S5&aF9[%5rv@}t9iȨgHdN#%">sE?ć2|t* fbܵ\:GtTHHJڦ@Bw<}u K)J;u`:JV偬 V1U-:B +MheN*f;]cFE}9uNE ^f˨/#m, M@qr5̱AFm8U5I'n)} % {Z@{PiP^q㜉8#|\aLn浽eKa~>ebИ7Y1R{}!V-~O3Gh5;˙;uTF e sep)*<' _q1&ߐ~_ ə71p}@' /ӝ>^bkkqDYtt_NwV>F3 }Tn\!sP7er8=m5_|fQ-nр1uGh^ p~tF+:V݌~/HnTvh&\_( u!dK[Ē`Q۬ #4fd*ϨK |ip/9" m7,¡'lTC|@ yMIh7"71eP9t0Zl "W,#$݇X`ԞjY(&ːņP:wV>(]Aޔ;i uujI;Erc `3RUfEV@+8+ cUP˻#zGgl%AF7;p4jo^#); ?O a/dOqlKN3U'귧=Κ*}پCZ2ZᖝıQ:wkJZyZ^8Q̩'po"u"wēN(*O!{¯8q}ջԿ"\aNO&y{D& aڣ:O,eܩ`hrJ=1>FlWQHP9U,Us*BNLup6H { }lr# RFm@3j];&"fWJ E.>f+RO[洡֫e""xQ4sKt-ܢV!]& Np DG_b>0%I[?o_T!V OCvA(K^'"Trj[qЈyR-[ QqxSN%PӞ16_nx$vR Dy]]@m"ipT8!w$E A5ЂV%6Ndww KS@9Y#O?1% .]Qq@]pj"ۖkO7ai -CR[3b0N˽$fxɋhUP$NGܲX]F8 ܮǚ900Ċd&01qo ڱmyQ{fJ/smit2ddnvRf 첫'<,}8S-IGy|(QcvIEA6y>ALc֩ RWm>v6pg/42_X';+16_X`FP#aCM%Ju2t,߇bkW=~mU51? {\j_lԭ݀fS(2 hDo[ei:P^H0{Zo~} ̠#}p"rqcLr +? ~^}E-)э|`a{df 94 PG b r_I_\9}[)%=CyRa38*h\{y+ez%?/}SOc?`wIcq;NI,h=dn8Ô]vv j񬪷juy MS VPZh(lXD5A2H-(ݳ;'n>gr}c~aD*bƨly2|%X!']\qtӫ%xǩUJʶ )զ )7e)к LR<Ʌ(Lu@"仁_m,Wp, RƝ, W18$qq5"W{?FAz[ CQ{ :Q:}MZ\ m˥ٓϏ[}FL+Su~LzzQWDe 4ӺjG#A Ű RKk).z V?S2dW ]fXyboW&3je#ÏDlc7(DŽqXg@Y*O\|?nW xQ&sXfS0]Ϗ> K._Q]',.{*6Cގ?Zw [>Ś6-mfՒ [xb6+,/;mPbfGbVJQwSm %50T},ZcwP(G0+þ$Vz[ i+5y*ǀe7PdSu$Ci_{}8" 98}X%$o j_`{rnue6ƚpSG(VrbNr.S]L76W0|@kt g)mA*DA+(l"JXX.VVyYCV[y (tKo ҪŦyASuYcBq. 0V@7mW Yы+I3k7x54VL#I7.IlSVf;s* (뙝WfOӨtmrp&u"Ằ!=r.)"Qq9G~ ~j!zk.O۫xSe[߱[LJNM[p0G3>o\M#a؝ˣ'h#9\w]P5ӼV]SۛT$ʞܥS}UD6ߑ(E{å{ʛIy)B;lw& yZwQq6+T`(~ʅwϢC+fF2&SjV/=iGvdWxXZlabiRzaiYVOUv|t\ġsUJq#2eĖh ` Th~ ìʦH+Z,/JCT AHbF?X su6MbM-|^ 5s]#Ⱀ5T3|t$rɄ;=2.:dvj6Ԃb՜܍BONmQejiж45oY6]`U/=nyRneWZ򙓰4pL);5}4I fn:=ӧ?Je^̓t~̎X!HrҤ:GAQ?/ULTY֫)9*;M9|b}F2qiwo+Dp]Iceb:^_ `M-ͽ [b-Yϩ5@IwQ,q D^VW~rsݠot0x nbU`IU︬t֘^>8P)hϴ9R9'J`EmPL_ݣL *h%͔ٳ(;abh^VuNdKiWI VTcˏ5X%͂JڸsLt#MwPAڠ׍ is{,‡<< cf /A.to\N°@*rBw=0隋Sc5.F]Ssp $B,pLʪeL:7'̮vYr8$:Umsa:?QVh-xNiҊIK mxn? AOQ9_ Kox8b+=P~tU|2t-]+|9ubCW1|5eqűfWiOsc  J^LJnmB1F:5gΟ(HC,&1y/nʯ/5hnHtxn?f&I\J{gNU8q`dS#&TP^o0 a lrRQR9t'ɴQ`MGs\8cAP+Tf}yNm)ʍex2ĝ_q0rE0΃Bz](J<85 T@(mߓVݦu!dp{V˜>J_q bШ6o0'w(:lbT9 IǛT@{{7~D \#&mZe٩G!+_d PpR@r5\|ؽ3f]2qd*_tRZ`c8cUTTWdg}ym@?X\ x $E2 PVֱpY~`O MbKJ.S,v ) ߬"XҘ"=f`Q7X$D @B*L1|̘Z˒)xܡ a" ʑEd evܺcf:\?oxi.LK9V}5ۓ?G;aH9Il8GVUi$ZSؚ*6)ʔ4:eB!!B^`dWypCө]>{hOm(+}5._,d~N\Nq_6$ Fw<< Ϋv?Đߐ y՚H?*)T#GbDh%,o@|QQOmQNJ,`6Qaה;~rB0K*&r,Sj˫=JuT:L=]N6qϾdn4;䁍׀.H5 PwsyAuUA.[~YFK֍CH6>d@S|$zV6c{|zɤH^Cw?@вRueU ϏwMIb8͝;[;"\V&ݾ[R^^08ː/ ~W( dJ? 2F`V-U EWa+lx-9i.4GG]輘{oĹSIf!)SWgt@tGHpd]뙨kvZ9ae SbFkN\ XWAu)ŨXՌ^,5qdM,k1^3]N;_`:~bIsvumT9ܶ־)Xڊ[={UyᦔWWOÍC<Щۈei rq#̤W ,Fw!F޿WN?u;59( ܘ ?a ź`e>έxJKm,[#Z3 >.[ʱZbw'IDWP_$Zt jZ0 Uϧ[q6pYkQUrVd􇾤I3/y(|l?;R\jtsl 8"@!(}1|.N. >^ґە8ɩ^B !Д& 8@m(uXK +!q(\9iP}İߐGӁǡm -b;u;c8&o76rt#KP 0Dzqg ۜ[w@'v&ӁtPR{AQw藑'hO9NI25j*U(chO+XWDк<6ZJL: F%^*>bJ(LzX/a+#38 G^ 75-~rx ;-a#bX{ 8Q{(@zb ~/&ù%^%7 .2sķL%{\)rJ=uT]ĨלJsfĵQ\5#NvMN#5 Pw'ŊYѵuB56>W0ia"w~˿E;T1e͊ sh m}H 90H=Z͇scZ^z> t储ˉ 5T94&w&nrj5l`YDFp+gFxuJ*玵FϊpO?1K}q-|$CJYOUR 4h~*'uMدՐ%S61opMG m [Bm, Ω:d\l .cM˷0 5.[|c d:C}{_Ʒƍ!qo 6-nI+|L4mXDUݲ?P|6wR\=lrP9C3 ' YV䖴 r84H=Z{ҌC\l>0 YZopenttd-1.5.3/bin/ai/regression/tst_stationlist/main.nut0000644000000000000000000001523012627373446022156 0ustar rootroot/* $Id: main.nut 26897 2014-09-21 16:45:51Z fonsinchen $ */ class Regression extends AIController { function Start(); }; function Regression::StationList() { local list = AIStationList(AIStation.STATION_BUS_STOP + AIStation.STATION_TRUCK_STOP); print(""); print("--StationList--"); print(" Count(): " + list.Count()); list.Valuate(AIStation.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.GetCargoWaiting, 0); print(" CargoWaiting(0) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.GetCargoWaiting, 1); print(" CargoWaiting(1) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_Cargo() { print(""); print("--StationList_Cargo--"); for (local mode = AIStationList_Cargo.CM_WAITING; mode <= AIStationList_Cargo.CM_PLANNED; ++mode) { print(" " + mode); for (local selector = AIStationList_Cargo.CS_BY_FROM; selector <= AIStationList_Cargo.CS_FROM_BY_VIA ; ++selector) { print(" " + selector); local list = AIStationList_Cargo(mode, selector, 6, 0, 7); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } } }; function Regression::StationList_CargoPlanned() { print(""); print("--StationList_CargoPlanned--"); for (local selector = AIStationList_Cargo.CS_BY_FROM; selector <= AIStationList_Cargo.CS_FROM_BY_VIA; ++selector) { print(" " + selector); local list = AIStationList_CargoPlanned(selector, 6, 0, 7); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } }; function Regression::StationList_CargoPlannedByFrom() { print(""); print("--StationList_CargoPlannedByFrom--"); local list = AIStationList_CargoPlannedByFrom(2, 0); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_CargoPlannedByVia() { print(""); print("--StationList_CargoPlannedByVia--"); local list = AIStationList_CargoPlannedByVia(2, 0); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_CargoPlannedViaByFrom() { print(""); print("--StationList_CargoPlannedViaByFrom--"); local list = AIStationList_CargoPlannedViaByFrom(6, 0, 7); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_CargoPlannedFromByVia() { print(""); print("--StationList_CargoPlannedFromByVia--"); local list = AIStationList_CargoPlannedFromByVia(6, 0, 7); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_CargoWaiting() { print(""); print("--StationList_CargoWaiting--"); for (local selector = AIStationList_Cargo.CS_BY_FROM; selector <= AIStationList_Cargo.CS_FROM_BY_VIA; ++selector) { print(" " + selector); local list = AIStationList_CargoWaiting(selector, 6, 0, 7); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } }; function Regression::StationList_CargoWaitingByFrom() { print(""); print("--StationList_CargoWaitingByFrom--"); local list = AIStationList_CargoWaitingByFrom(2, 0); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_CargoWaitingByVia() { print(""); print("--StationList_CargoWaitingByVia--"); local list = AIStationList_CargoWaitingByVia(2, 0); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_CargoWaitingViaByFrom() { print(""); print("--StationList_CargoWaitingViaByFrom--"); local list = AIStationList_CargoWaitingViaByFrom(6, 0, 7); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_CargoWaitingFromByVia() { print(""); print("--StationList_CargoWaitingFromByVia--"); local list = AIStationList_CargoWaitingFromByVia(2, 0, 2); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } }; function Regression::StationList_Vehicle() { local list = AIStationList_Vehicle(12); print(""); print("--StationList_Vehicle--"); print(" Count(): " + list.Count()); list.Valuate(AIStation.GetLocation); print(" Location ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.GetCargoWaiting, 0); print(" CargoWaiting(0) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.GetCargoWaiting, 1); print(" CargoWaiting(1) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.GetCargoRating, 1); print(" CargoRating(1) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.GetDistanceManhattanToTile, 30000); print(" DistanceManhattanToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.GetDistanceSquareToTile, 30000); print(" DistanceSquareToTile(30000) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } list.Valuate(AIStation.IsWithinTownInfluence, 0); print(" IsWithinTownInfluence(0) ListDump:"); for (local i = list.Begin(); !list.IsEnd(); i = list.Next()) { print(" " + i + " => " + list.GetValue(i)); } } function Regression::Start() { StationList(); StationList_Cargo(); StationList_CargoPlanned(); StationList_CargoPlannedByFrom(); StationList_CargoPlannedByVia(); StationList_CargoPlannedViaByFrom(); StationList_CargoPlannedFromByVia(); StationList_CargoWaiting(); StationList_CargoWaitingByFrom(); StationList_CargoWaitingByVia(); StationList_CargoWaitingViaByFrom(); StationList_CargoWaitingFromByVia(); StationList_Vehicle(); } openttd-1.5.3/bin/ai/regression/tst_stationlist/result.txt0000644000000000000000000000343412627373446022564 0ustar rootroot --StationList-- Count(): 5 Location ListDump: 6 => 42341 2 => 41831 7 => 41825 5 => 33421 4 => 33411 CargoWaiting(0) ListDump: 7 => 6 6 => 6 2 => 3 5 => 0 4 => 0 CargoWaiting(1) ListDump: 7 => 0 6 => 0 5 => 0 4 => 0 2 => 0 --StationList_Cargo-- 0 0 6 => 6 1 6 => 2 2 2 => 4 7 => 2 3 1 0 7 => 18 6 => 16 2 => 7 1 6 => 8 2 => 3 2 2 => 16 6 => 14 7 => 11 3 6 => 10 2 => 8 --StationList_CargoPlanned-- 0 7 => 18 6 => 16 2 => 7 1 6 => 8 2 => 3 2 2 => 16 6 => 14 7 => 11 3 6 => 10 2 => 8 --StationList_CargoPlannedByFrom-- 7 => 8 6 => 8 2 => 7 --StationList_CargoPlannedByVia-- 2 => 16 6 => 7 --StationList_CargoPlannedViaByFrom-- 6 => 8 2 => 3 --StationList_CargoPlannedFromByVia-- 6 => 10 2 => 8 --StationList_CargoWaiting-- 0 6 => 6 1 6 => 2 2 2 => 4 7 => 2 3 --StationList_CargoWaitingByFrom-- 2 => 3 --StationList_CargoWaitingByVia-- 6 => 3 --StationList_CargoWaitingViaByFrom-- 6 => 2 --StationList_CargoWaitingFromByVia-- 6 => 3 --StationList_Vehicle-- Count(): 2 Location ListDump: 5 => 33421 4 => 33411 CargoWaiting(0) ListDump: 5 => 0 4 => 0 CargoWaiting(1) ListDump: 5 => 0 4 => 0 CargoRating(1) ListDump: 5 => -1 4 => -1 DistanceManhattanToTile(30000) ListDump: 5 => 106 4 => 96 DistanceSquareToTile(30000) ListDump: 5 => 8818 4 => 7058 IsWithinTownInfluence(0) ListDump: 5 => 0 4 => 0 ERROR: The script died unexpectedly. openttd-1.5.3/bin/ai/compat_1.3.nut0000644000000000000000000000126512627373446015452 0ustar rootroot/* $Id: compat_1.3.nut 26407 2014-03-17 20:05:38Z frosch $ */ /* * 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 . */ AILog.Info("1.3 API compatibility in effect."); openttd-1.5.3/bin/game/0000755000000000000000000000000012627373446013372 5ustar rootrootopenttd-1.5.3/bin/game/compat_1.5.nut0000644000000000000000000000120412627373446015765 0ustar rootroot/* $Id: compat_1.5.nut 26410 2014-03-17 20:28:48Z frosch $ */ /* * 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 . */ openttd-1.5.3/bin/game/compat_1.4.nut0000644000000000000000000000160312627373446015767 0ustar rootroot/* $Id: compat_1.4.nut 27164 2015-02-22 17:25:29Z alberth $ */ /* * 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 . */ GSLog.Info("1.4 API compatibility in effect."); /* 1.5 adds a game element reference to the news. */ GSNews._Create <- GSNews.Create; GSNews.Create <- function(type, text, company) { return GSNews._Create(type, text, company, GSNews.NR_NONE, 0); } openttd-1.5.3/bin/game/compat_1.2.nut0000644000000000000000000000242212627373446015765 0ustar rootroot/* $Id: compat_1.2.nut 27164 2015-02-22 17:25:29Z alberth $ */ /* * 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 . */ GSLog.Info("1.2 API compatibility in effect."); GSTown._SetGrowthRate <- GSTown.SetGrowthRate; GSTown.SetGrowthRate <- function(town_id, days_between_town_growth) { /* Growth rate 0 caused resetting the custom growth rate. While this was undocumented, it was used nevertheless (ofc). */ if (days_between_town_growth == 0) days_between_town_growth = GSTown.TOWN_GROWTH_NORMAL; return GSTown._SetGrowthRate(town_id, days_between_town_growth); } /* 1.5 adds a game element reference to the news. */ GSNews._Create <- GSNews.Create; GSNews.Create <- function(type, text, company) { return GSNews._Create(type, text, company, GSNews.NR_NONE, 0); } openttd-1.5.3/bin/game/compat_1.3.nut0000644000000000000000000000242212627373446015766 0ustar rootroot/* $Id: compat_1.3.nut 27164 2015-02-22 17:25:29Z alberth $ */ /* * 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 . */ GSLog.Info("1.3 API compatibility in effect."); GSTown._SetGrowthRate <- GSTown.SetGrowthRate; GSTown.SetGrowthRate <- function(town_id, days_between_town_growth) { /* Growth rate 0 caused resetting the custom growth rate. While this was undocumented, it was used nevertheless (ofc). */ if (days_between_town_growth == 0) days_between_town_growth = GSTown.TOWN_GROWTH_NORMAL; return GSTown._SetGrowthRate(town_id, days_between_town_growth); } /* 1.5 adds a game element reference to the news. */ GSNews._Create <- GSNews.Create; GSNews.Create <- function(type, text, company) { return GSNews._Create(type, text, company, GSNews.NR_NONE, 0); } openttd-1.5.3/bin/scripts/0000755000000000000000000000000012627373446014150 5ustar rootrootopenttd-1.5.3/bin/scripts/on_server.scr.example0000644000000000000000000000013112627373446020310 0ustar rootrootecho "Setting default network server settings..." net_sync_freq = 100 net_frame_freq = 0 openttd-1.5.3/bin/scripts/autoexec.scr.example0000644000000000000000000000012412627373446020125 0ustar rootroot# send chat messages from the console with # ] s i love this chat # alias s "say %!"openttd-1.5.3/bin/scripts/on_server_connect.scr.example0000644000000000000000000000003712627373446022026 0ustar rootroot# Show a MOTD say "Welcome..." openttd-1.5.3/bin/scripts/pre_dedicated.scr.example0000644000000000000000000000016512627373446021071 0ustar rootroot# set default server port, and have the dedicated server listen on all interfaces server_ip = all server_port = 3979 openttd-1.5.3/bin/scripts/pre_server.scr.example0000644000000000000000000000007612627373446020472 0ustar rootroot# set the server port to the default value server_port = 3979 openttd-1.5.3/bin/scripts/on_dedicated.scr.example0000644000000000000000000000022012627373446020707 0ustar rootrootecho "Setting dedicated network server settings..." # empty the server password server_pw = "*" server_name = "My example dedicated gameserver" openttd-1.5.3/bin/scripts/on_client.scr.example0000644000000000000000000000010212627373446020256 0ustar rootrootecho "Setting default network client settings..." name = "myname" openttd-1.5.3/bin/scripts/readme.txt0000644000000000000000000000166112627373446016152 0ustar rootrootScripting --------- OpenTTD supports scripts. local scripts: - 'autoexec.scr' is executed on gamestart [all - use this for custom aliases per ex.] +network scripts: should be used to set client optimization settings: - 'on_client.scr' is executed when you join a server [all clients] - 'on_server_connect.scr' is executed on the server when a client has joined (MOTD) should be used to set the servers port/ip and/or server optimization settings/patches: - 'pre_server.scr' is executed before the servers tcp stack is started [in-game only] - 'pre_dedicated.scr' is executed before the servers tcp stack is started [dedicated only] should be used to set the servers name, password and so on: - 'on_server.scr' is executed after starting a server [dedicated and in-game] - 'on_dedicated.scr' is additionally executed after starting a server [dedicated only] For examples how a script can look, check the .example examples. openttd-1.5.3/bin/scripts/game_start.scr.example0000644000000000000000000000001712627373446020437 0ustar rootrootstart_ai MyAI openttd-1.5.3/bin/baseset/0000755000000000000000000000000012627373446014107 5ustar rootrootopenttd-1.5.3/bin/baseset/opntitle.dat0000644000000000000000000050553412627373446016453 0ustar rootrootOTTX7zXZi"6!X]#!Pm:[wG{HX"i887/34$mYdwbK1 W'C[ݚ?ZK}5+ # E|ܤڜ|9?[v_@^Ե4&#@y'<5 ->1Z t"Ճ/DZ0{(=`L IoZ^A!͹Hb|6w+]E盲_sȣ# sRof<5Pcg7vI 'wgfZ،dτ*(( k"igXZ?xZým|Ԅ$4tdG*:J3 >5Xz-= ) 8U#`UMc,L8UjsI C!t-6}r%HDߙَ|ۯb7;' Prhnf$q}8Tʼ?r᠗Q&xyRgCSg1$vvhC6·^yfJ5aFF;jjttyK-Y :P߀[ާ5sQz"4gĒ =, C0I|PHlN?|cuHQmC^d/2%aeNtHn.%[\~B9EƝlotixeGǜ.lT(?o,dP,meoNBFIX0Mij,!PjYg8JEܤRpkBczOu.D9Z؍؛ɭQii2]luA%7p忏i!2  k# zN{2]n#pA00| DF< g&LV,M#kхfHSH ß겵/׼mWS:}֫ETcT䢻F*Go<]ˆb]I%1V{  ]d4Wgw߳/F]eGŦ&W Y֟l@/A罽|8C$I&8doS g It. (պa-\UKb1Edza9n]`M#i_H3/n"Ru20DGb8\49U=kp{9Χo9 $._Ke .H3 ʮ[02"C$ЇG_W"i>MVEQĭ9 װt@ݰi15Ƽq'WT(8d~2vo'mW%*E Sd8szQ?DEcl:<ӻ5[:ڦ1˥*dM A%곮O'[M>AMp:#fm>R=[QRe?>@pdPE:ư:RH޽YDd>ssԧ'UC$0FCE%@WYV'tezmm 4Emw# 2jb!2D?d^tEoRe.;sUD}#[쾌8Ͽqɒmj7fdRyHsƦ"&ctPL,cJE(l!Uș?Al"#"C3؋7hQȺ]GPB3 L0fe3/e<$lC=2#?us!X'+ަqMxr^9⽆z' a*Eɇ>qư$/:пQl2,WŎzj>-ԇISQ;gjrjML>-NRȵ!N`".U琊ySdy.QqIǿKtST K9 `PjYCyZf趖e0/͏O#sliPyxX A9M% HRZĥtX\kv.]]6^A)'`1UhX90yȌ.NUǑH<|yK\"\wO(}GR@g(#m;NA hl̆#AeG%1N\OcjlL\D+G1rE1*L-Bw%ZTco 8[x5][$'0bSNMm2C݄j&AAn~c[pM]fO+)R7RkŤy=MђR{TH1nF(]ሃ$EZwx<э,}(?kb@(s Y!Wg缽/=X[gg*HܯvՄaiZ[W2xC# ֵᐿX`,sNbAU%fsRgႏ/9yԩS `N=*E<L)3?nWsN_(FUy r1B݈ I}:}COth;&jD7t<h9= 5ro$E7|+;/ 6C5'doDkm4jzeAzhPP}=%j,TZ%?ܳӯc1zgⱻJ. ڏȰzo9/DBtN.e:a4p?bVii@by%_w +{HM憳?r} xYFaIݞM0kxkH"@*hm$ # tZ CSmT#̯["x/29o_#5W ,e"b;6mY4_b~쩊rrX hTk~#9,"rXb7g)a]9VHM`=I!X:%Ȣ y(.<.R,Z^ZxA: a/K ʂ~e|'8KqciETʱkm\A>/'kp55<5ĈrV(NcTeJ_eMn;e!ބGN0e) Lk`5zt.c6[U GZU+ZOju45ʌ 5/\\?F/"u2]@u t[-p2z6 &HS`F fET9QJTsGbλ}F4Xk *jgѝA*1P=mh}(>߱3hܾQ5P=~0l֭:Hw:į|of~8^\oH?$ tb>sX&Ӽ gc̮Kx]˩Hbf!>tU%y$S/mef:a1Dp o=')hstlgI DjVxv MdRDd#gv6OWTY suT;/t.= VzDP33,%/0C/^dxnP2ic ,<6ͯ|K_nYE*M:EZ%12B bE١*ep1\aHF0!B {ɛ} !{O/yS AopeUq%f&iV4~,i ^g2;EUeeJG"Rԅ]j&G87#e.U%H=I(4``\\y ^lĝ;4TKVnķK57cSXwj D[a#oTĴNe;o"!Q'8!gɄ̽菕KY>\bLck "R!gI[KR!FC x ϩ;DY;acc䖶~nLTW*cKXuSޘ,sͅ{NqI̓ob]4j3(vQCTAP:yq)0o~cO7!Y>}_8O ,7+';n SMK*Z!XŏA|+ͷqM8Spb_)ƍ.~3(<JD.:: U4Ig0|1<uu| Fj/ފ`_gsi>ˬt|ۣXnsWc8 NL^698 yi\XAΉ^_Ik+Ct6|{;F^>)t/u)ꬪ =oF{i3cuޱ86C7՛!\e{ e\!ם ~){yfredF*:T$K)Sך멭`U|*il1,%3^;POZw,&q)f|?䪦~IgAukjV_3ރl yt)kCCU y3-XD8.ToihkjfW&wI!`TRYg<ؔ.8RŊ0Vh< #!M0|I%E&]9_{O_UFH9F:2rDC\ˉ=`* -9> %enTe.W cgFŤS _m,*c&hkS oc:.2evVo eG/D&CPM4m & SZbC`7mF*}Tm0+ԳX ŦEV:7̦ 8ڔ=+-FP_MA` hRN4bAoe]mnls&X3Z]~1̸ c:VyedGd f,҇c#&AIy9'Q_B7pɶ7)NJkwwV EKm NЉ$ʞ櫧o]JEqD= +yQ'8aYΌޅɭE9jҡ!h!?`صN:(!LnB~VcY4|םʨװc&e!BttY beX>J&r#Ck^a;sNCxƣ_*ߌ7$؁整%I 8 &uaPw6+|Ter C nzF>b9s=ysPSN2@ !j`3G5e M8gKLw3Rj[HtiW RQYY&Ha|AʰK# ުzY0[rdK3 o,b/o2q#͕UX"GvT2Õ(n;aTٙF׍Ϥjڽkj.?H `h,P qʋ!eM :bs=|᷇J/L"G f5XVQB1/KiTa=ZNOR<uPSۮj{zH&xw.3-(}=Y:y쥘%c o +BZo1׾2m#_   :JӸ<t>B!C{@bŽo.uRϟ9=' SPtD?W\%~3JGߵI {QP^LCOt[)+4Rle^Bf| AP9@kvCy^'l(K9e_<~۞+ 5j<I7N|"qvDL+EIӬ4("λd ~}&UTr0.Y<]/!af&| 8z\@QuKv~']م&UOI1ҫuSp#cv3p& 2*Ԣ* bHqjdק{tKYP?!nJ֩CDP63ҥEaopI Vʒ={EY=jas!/†KBU묀M͊sIn6&#=Xu4Pr 9:v3 ۝TH!nG5 u: R w~澲nJވkj?ʳg+@D09@)vlCBlJG>^Ì3up Ƣ nN@;NIOk Ko~{K͑sF|Oq?OXc8j#[aކhrq~^;E bM Ð*/TA(o'Um=SN59H:!ڢs:Әw{X,'`nZ1nG_,Kiz^?y+5-AԶ.ϼg|E4㮮l,,vXĆޛ_V̱o!pǞ?84(Ŕ]ÁMmU% \obs\`!0 Vz0+ά{%rPnR3!+ezkd`8:"s-'9LFf׀Eev#G=ثx|ݣ*h<2rjO .Us8]>΀r)XGo50㰴\6iKy Qcݻ+X^aE%S <;MHfS`tʱ>٭'ۓ}+:䊾!X?˫#~NE_G[ATwi냒PG]r7,q?p>>'F6ýBkcl趈)a>$1^58V6ӀBz.6+ؿ%ι;p);ΤLn^0g]OGxb|ڌS0-DO( Y8-߶lv*e-U,4jKfՎNvmՊ Jn A 7/+N7_bak".\t) 䈇\eb%?R}{;WNp~Mfu] &/-T&E(3$ >Q. qC(eL]'S8b+* O0HyWBms-:[y G"m,9UmP\$AT cFûPvq%Sz*"I0FR9vZyurWʭ1}_(pgI>]1 p}kke:>{9ogMG)h,{Omnr:eI2dCjRHǐXBElU\As,/ˮ:N @&?ﶛ%`/''ڿMA⺘ލۆTf^901d61P*b.ٜWFAB%Yoӂr N1~xƤsgKr{*}Z{=cBW~D\vX<,Fd@db>KVu QKu{6Yy'}(#T/*U#'3lm=DmNs'АAIp/GphBIMf-WE?+}&b祕›ӶEk oo?vjm<}0ڊp O \WBVfRy EWb>%i &VPsrcK%X(v:F& Hމ3żّ{G3JLVi4隆v[3MRh`[`wr_/K22òhKBMh;-BicaZx=\v1c}<4A$RuJExA(UeqX#lu!>CO:i~ɀόoz%M";}X Ƞ,S Vd'1.Dpl q Knl*3Y!ʳbU"b˦gvG.LڪMc&עd_YJ13_eQ>u!X齥&uf&ltds tā9S'XXET0rCA)5܁KT}&70ABtJgۘ}H4Lr[v)=L⺢%if37/Mw`ʈ<ĐY"D?G6(>s~E ̌ƭGbwط $gd>!٣D *t(*o=0ECP:W*d(5v}ֵ)e6U {d *uXO 2u&<2L ΖrDg۔QS$71=#VhC7:5p"՛w:S5; T9L*{?a0D N߄#6Ep7ܬE [{2yejTOchF #j'{/~p-}]P׆,zLRb2& ȹ4r+b@NxdL(ю&ե +qjSW=ܕuh1 1R#7V]6%`b[5V CrY Vmrw%dDJ# B|{l͘›%x╹>ɩk(MV1j޲y'uȓPn{o)koM@l6QE L7vx-+hs-k#Y$mxՀ & & xKdrEZlo +؟,rԜ Oz?E~Ad(Z )h j4v[<3p\!J¦L_2n p$-B9wihEΩ7 Ew9 FA*EMt }k5eHF6;]IU+ƫ4pu=1at2|VoYsu S4^HHes 3 Z+#Ц?[$]eҭFS|贅&b4s@@AZpM:S-w(O6cjM# k0ѭ?MNLÀQL`j@7kU,>=Ld='yFS2[ä;r D#%xZᕿ@Jy "OЄoa,qq*[(~Tb$ =qbޭ3IVM )`)[.v5W3J&vHi:4430YyjͶ p38?BLFjV@|3 EA㭦N+%a'#XTiq)U_(j"ӿ^K$vֿQt{ s5Iƹy~iJD_' 7I~9^$:Swke;Zp}BuAa':p.FYJ*XUܱ~Ҩꅼ,+Q g1 ;N1L Pn3)f_lnյ+\@V 9(}xS}S}"t>|*:M]Iה ^ m$E 3c"wɖAj_yX =Kڧ/2ٛӛ1{C<-KkEa#']RcXym#qř=~yey[{zcq2'"ߕBjn5,ﭜhǗkH0(M3ynq1D}+}(~'xP9)<4þzbG19^2yȻ?9exHW|bg)d[CoaЫNLigڕ [#aaƁ$#S>=k0C+YX &8n+W?DԔDw^ftdm۴Z9D!eV<#>]֧n]| fZ}ya.zwpJ#M ԑ-1Bq1J:=xIjTC{%~O*xa@גPlQk{Aym2q @<6މa{H JrI׸I ._>\D7%jٹ+WFrc7gEށUyPv\('5 {qoQǃ RިP/tI#:$sq}H%U<KIhOLw9)9/?s g1Oۋ8+θhLe(1e %I"y,,c4ɤ)~n4'+ 9e-GX k;+sK}`ua)(0%#3Cq2l<.zb]$ת&=$=U% ,[ExZ,Н$۲Ӏo}S|C\suz=oKs*Yxbжj(x O_np(['5LRJpQ[Qڳfvu+n2+qѰ8*nNuna&֭+xzR: |NOr~+9M#{۱We(]S| 0EmBS{ȯd'^.=֛JL81@ΖDہތm@rU)&i9-LG1EN Jچ#F>i/>&ސ,eX2_l/8jcQTީYaoSNw`Mbu (A.wB<ESIBN`b0-R3UD$S)ΐWDub9׿ET^|jQ;q68B,KlȾ[jE @@fu1'i y0 w`:3ImHp0*ߩg*\Gn\XhȂ3KA8Ĥ\ y8lq^Z1r{%h<~r!>Om'F3N -F&[YVMduI$HћoAM0)Hˀl(ZY mWT9V.h 0pA>46`5w&1i-o!(ѹʋVlau{ټT# ޝYXNpjx#G{w2. - #pt+ڌ 5ǥ@q%tDUtϾwZw5`xqL^4;T_O/3oc~x1H3G7N -`xY]º^sPP̭^g:*W>D q1)_Xx Jg1f>D)W6{nh -Fx‘#yf屃a^8=d7Z&Cߕ}}lUvN+x1G>4ܭM~vi ׯ&S@U_G0аJ+z &[Ϧ56nt@=Jn œ'BJ 9?Y,qP젼gt7u?lIBNOO }fYG cNϬhmQɷBLӵү-m1$Jzk^ͲC$Op {Ǿ1Dl auXK9G͊f?kCp- u9VZ': uZfދ]PQE? P^NF,TH˟gƒ?S{pI`G$1G6Cb[i>\Zk4Mw:S-q;-j1c[m>feyQ݅8da 0YfŽnE2my@iݶϴoT CH;nA9 ϾtAJ!(y$Yď+#PZb<[1H)Cl 'z,*=3A8 >dsҡ!]Ss"h?rj|ۯi} tºM2|]NV5+JNT%/ &qigt`vli%luՎ~HG){t9 M I7{:Vh2B GpRRƄkGFI`$1Ugp# .G%9:_hJ Vx`JL#&m_~#EvEJĩm 7ܝ'AUD!䙋$2N#"o:X^= jaL~Ce/sk_}N uAN૩IpH]i(;"C@1C`%{VY6VFGtBvʑģ >9kMH];Adq@ S[&A$gL %70q+ fU;ix5ʂx,dnE1H3b3!h`NB`plH>{ΛAF%HHΐ: DyPfh05ܡ>΅1C{8@O$B[bG/(h}3(3O#;:!">1 !2h;r 30TBUՊ҃3h+_ e/EGti=Xsv$F6ie#Myã{8s0ސ߹EnE_ 0ZF2=1&"k @YF63w'yEV}QGvsix(rfaQ]%3F]FHIY#NHe#q-V:JzRÞ0çԔ+P``wiY-^xn.-E^"7!" N`O_uLH>Gi vr{ݲMG)͸H_O!m呏Yf od>= ~?h!=]zw[g}c9‡3yN]>m)|?GZUFcZxy}0rEyj%hb+YI)n:хzeU~i#_;`V D/#uMo7JN#xuZ&҂坴x @p#Dztr5 _$1m޲]aƯK](i1DXE[sKҗ侀;>r6O iY ebj.WN6?P0~5 ƿ"/_DRy)ם$4lAib5{rl v-NCfbgŏ:}yQf^ag04#ȘSI%x1$TxӉxftojK֐FTo:a~[gwlAl zOTo1RCLh@|x~kK56D Vvt?K~BƅYtj,odW3Z,k;N"3鸄u/L:b|bm( a^16 f`b-Fa!"6a*fC2|S'vuOCzԩ+|4TkװD(7-#4 K[LrPV!w&NoZKW,6yLI4tro 1ͦk[lI}yrN6Q(/ǟ%+ʤw$EFLjc@BD!lHQƟ*"Yk)==A:Mɶ W©w!K1hKwX/OeŲa,[w~ȈeT[&}>jf3ҕzZ!['BTۥ3IR+0Upo4hz Q*ƃX1-3guaH˗xbu6  +%U9iu%z%Q`#}ym4}Uܙ&.GjkMfpK̪%jZA?" v_w(|6A$2*3|&"9΁mR[8?JvFy 荷 bCօE|P2&xͯg@m$(4V)6ƭ8ahG3!=CA4CrRMGQcbjwMjҀdw"mLR10a'Hm}3"Z1<{*T,nܖ}x}pRZ*˫\6:~P֝(f}N]-RGi4^(4p-_eUR#IQp'mbG6\\fT05 HzSE]q4hRݲ{nB#: +ֿiHپ87IY{~=$Y7Ak;%ХMLW_N%k$DL֧`xukЎ}$e]mGrpav^:O.dsX+VF/ӻm9PZ$KEI)s*k?8qgHF Ōt#1 mrtΧZHŗ6$WKs'.1NxxO\k^qGwFP%$W뮼MJ"Q!לa;J] KŁDr>zo0`Y1C1>/dafVWЫ$A p "\TYkˢU5zc@E{* КbmvQ@o;H.gӊf\˛ۋ_f(hINabK9uu F,25% M)SS%gO ,}IȓouODipG0tQhN=nȂ1dqAO |ϊG|O:yU6@PN{ˁHJl37* =sTO:@ZD9hmA 4'X_NJ ~W.r9à(k Mxgk8f`" R,k;H\3,j (A2|i37YB\>֌=${2}R -鮸կ"edRR *X _ X>&7 "`מ͙zSVO.c+Pi7˻Ddu3lWj|`h RT@e~HXBiSV*"_0F2.>1FrYxvO" $3],h O'u%h3X$^0{*(ݑB<$|6HÔIL|׀*ॗ IUMۯWBJ6Y-+֧+%A[(_'۲dlGֱSvq[%~{gFb3|gAбǝ M^d?[Ϳ+5khҾXi'acAl{.'GRhGYpRnOcW U8kFJeJSfJB5t7rᎌ,gwlY>],Rг2 Rܴ̐gyBr!xCXLocbٕ5C /];ZAmw͢YV)p2Kq'j2֧IU(lt)R8#v9R<6 r|>/-wzC˜Y7QX o]+}b~F\ -_E bCུę6bVrO_!f rUq(&?9 ّ~n4;y4wEVѻ~}Hvn3c9;TMиPrnDΌƗq%(KcJ$vB|VxNxe {@,9z'2E hO|D֨U@,H%z-!tM22,twhIK?Zxɬ*!8k+6@PӢyRY֕.qPYZ :[X;;*'³a:=F6>aF΋`mwLVA Gzk80d@> bw8'= /y&֊EED4bc~؇p HBb=βkm=SsLb̫B_oʤҳU]@%;e_}B|Xrx>Y?bld/-JL6t 9[{Vі1"l T[TT=@;|0**C[AJwAdI  6h9T?H\%+KX]/G5bdaԑUm;!O%CQz3#Ey84>"(xJ̼ hFŁTHR])+4L#WL|:Ddnf=s^|oG[B=rTyZ גAܴ\ǣ{MǿMbޕ!թdWrv.I?:S``f4AyjYn<2֐}&R~zҪ]̑0 |E@oSI*5YY;ghI7"z3SnM),{A$&S/GHc5$Z #]|XӢZ[(鳙5" ,Z,icrY4oN6[8ÐТӓuVDgd bxV_H=MPph?4<̔#QP\#SJֆkp<> +!Bvx9a%53 d3pV29V@O 6jnX"]7sZ69: *{5GbwNViMN>/x0}mِI[M#!6|D3*tA݄HLisXb뙦'E!IwK]Z, tH ЧMnnm@{3Q46xpw-++HHZؽ/~gossi;ݗ2|\1rR$Gfheho/Gvb 8r%O_"gYux.cH}U%\.| jT.>=W)d~ٝ} ιqx7}cj2e%02^tqDi< bk*hˤR$@]mK$L/=t"O kCS,&7!v$ tAܠ%*R,@:xG~8"ա(?|K!Mq:tf[nZ 9Vm_4{Gj>fVyZ:1Pā}[DSg2蒬1j$ĞNd{/jCZۗ֫Vi ;(j6ؠrL):W(~xWhe:<ӈֱW@윮]>#‚Ӎ/?,ω io0| ~|a3ʥbzGE#[6F,)MO Me?S:ܜ{~i9i(hEA؀osaH{p幄Vq\ TZĔ^] v2c.WXEL2w4r8 Zaf`"AP>-.OT>B`B 0vpx5S,߫hr2"h%e9a67W-"0M~m~WodZ\X!يVZ'Q#q:7R{?u-xpI :!#l.˛~LʀnRk =([)0"zVyHf݄i w˯YcXF"I(=$?1T=;tR2:&`tpbGIec&8Gdn8Պ}֥wnP[&Wf$,&.nCFX4ݬ2_T<=څz'6yLXyPw@D=@{mQl2XZf \mقƟ>=*';] ~w\D|+?Ȏ++D:u-fW{\k7:w]82='Q<t0;ʫz`\JO('xvlV0{o{+=+tR|/. GhCRRK vcvPmB1 c9H:76*qa̳bٛzMKJ-0]u݉k8oغ=^c_u[$i u_ ?fq.A3~p2GtC4·ƧUj0.'/V|Pd..nFX ie( )Ph7ɺT%^i_X,HHbn];jPV.yجm3Cuvr[C3_ ~X$WB~oݽoZ=OS@o .-;<fs8v}Y4 X?ضz +qS@sŽp}N+Rvp#?O5qz5o8pa6%t M[gkN--=֗cl_uyYx-3Y@؇#!|A)[,D*'Uѝ23;R/N{o{9:]iwlۚеͻS'6T*lqJʒpcH0/;V3 ~`A8xԧ 'L@^*$q!xzdNsr'BgJL|̇VVк.C~M%5:O1M(n.I6eLhd< b{_ 3N\ta;mL]l%N"l" HsY(džVxK-Cy +k=q6:Bnq*} ۵iU ssҥ)Qh !szNU2p|ED釢L8 dܘϰ")~*q>VTܨ9âBO8Q}OsۍS/uȄ nwh'ReFz7ýQôo@pqH֝j‡ק[nKx}=$ƅ4asrވ;ld$&:jqˌzd_D9`X3d: ).@i{rjlnloeR=.<Y{IE 7h{8Xd1ݳyH~SԶMؼIpz"`F]n/ia^!WJ*`=#ӫ/W.@M'6{w\c$YJ1\4:Jv5侻Lkk/-xQ[٫`gx%w֗P&/ϜCy@}hy$3zY8(<+rˎrHb솰\-Wd`F`@|x,8Nޒk?]@wBbj;Y$k!_ggV]}%P$6R ]bP˶{K:@n柶b .–]F14+,x;T'mzMY&O8ZuyǢ!#ʠ@Φ{RVۋ";`,QZ]dF0k/hUGαS!XM 3$xFSq$"k#1װR;+bNGe+xMa +-;J zH)ض∬À6 {b[ ]{1sԌ[I3 I|֓l18#[J6z`/D,j Iʑ'*iZ: b24@E;"EM8XiuV0>?ӝP6./WĴWN%Ĝ1qZKlPV7,_:C(f@}ZgH¤Gہv&n,Al(fVr L|pImQ*&P=LW49LUZ{< Ll?n\]vV$Ҡ/JnHl+Z&'0$&.! s;H5KX,7RHώ$lWMe=X6O5uy-gaR)td) ;]TWm&1vqr6$诅xB_>_!wuKm؞ngn F9zC~qF&mĔYih6m2p'fhfܩV (敄y_#^vd<UЯǷ`rwt}8gt-.a0i0m 263Ō_ b xÞM^N&Yx3RT $boD[os~],yӡJdFxMFL.<4w+l<{ށLT3DR/J$P0zU#*}|-v7uW&vsmu?rʠZVke;ڄsg;H ]6жASz仆@.<5_E ۥϤ#wӷ(c.4J1w&gn,%?o g84j<c.V&.%-zGuC2Vu\g0>yT<<8S[򵺞,ۗAgZdOV@ %n0FJ5 hzЁ5% KNZm 6WCN©p2_7 1[KV5TH$'ќ؃݇ @81 B}EY7Y!J=9|.(I@-C>}u$ -pFVJ%w ?a A^lGlBw?@?Q.Z ,{֣55+4-/0R֭E(߄ 04?ZW*%] kͰ>;˜Vnx^|a؊6q ҝAD/h瑗I9H#KW}z Kz/Mσɑ \V$ dً7W7 6H2?-< NM뱾R-,b@_Oxe.%G?%(C~.W:`ufJZaO *ݪxM K 0bqЮ{?UWՕjYT큢`24tBF2aFQ;Q'v%+Ɂu94Xb99M&7Yk_h;PNQ*7a7dtL6J:u¸@uyq":O~Io[B23<M $]IK ަɯ"3SG8YOvyNͤ=XI"nHAya_Uo%}rD^mEG _Lkv}c0%Vnc.{qWCR49:`}fčvizDaVAT?DlD %eqv;n *<%Ĝ!Pv&2v=B5hŴȴd&I$O{ R:o7 xJ&oogh5Eb\x=ޔ'6>]gI_mɲ;^Q&3qh&3Ә $q ɍ4ttҏ=P:{N) Ā6ߌ[V xODÝnlX>ZC8\ՁN'x*0;*BFLhV\} >1UbFGOw/Rgti)~7i#2ȃ2q xqܗѸ [Kdp lBNJBqH<8̞7eZ7$[(PAӄk02PʷO|ԌưJicy:ӳI֭jP\vjg{D+!-'!"üףP(k(n-SkX=Cp|,9;mg gie44e,}S:ֲ)ϯy WBR{i2Q: f7 ;|8q1?E=yG0;zvZ(gs',0֗# K"*e ;oKS-,XXCnx֒cDh~0^5ZΉ{@%v]+aA{!;. gSQǂhq6=SG +]]7Ysp蘆`zЮFW1V%cXB`]T FY|Eht]!%Q)zu}I7IGyV/sa$yAJ0(W|_ڪ.zɐ1SDٰ31f=/HqX*q|G{Mv6@F7jT9+zBAKIׇM94FYϹTz~%EԈfϛ+9q՝{v;4ije9Fg&'&g#*s?8d؍c]ht3yvE. 6-$(W`c 7*i{dN; /FMa_L]NZE7 /"䛠RP=6H>ا 1f?䑍n=`;Ia-i>U PxȇɻF'Mbb++1zA7$ D%;2_ܮ7g+\XuR<ze/_˄1?pN g:670}y/6^%l a +apL!SY+>D^G`;cPGX̼iouP& &s^;a.ۄȊ8sHq拜e)nmc< Z+ZTnHn /MȰl 0.TѽE] 4v<~n_-"RrIweP}k,. O9-f]49_oԖ͈9o#㦝p!i3gCeTo+_Mz[P JY~d}Qum4n a}_㧴o;ebJtƵ w+z-T~E~}fm皕YIߟ %#&omM ,qomF=ڋj{f)/mQlJv t zE_ը]?r+2d񢹷R>$48׏ClUT@1AU>v;r}NծLS&}4>s}JKR(G`G bMKߺ=,{,ภϸ2~GzJC_g05six$Z׳̴ONZ*eNn|a#7>k@of,GI[!/ϬP]7BcY]V)؋$AyQN-%*E3Sn$kv r{qPXF8^Nlz6RcjBwzuڃ'h9n39 "n y Y4۵`O5T7jmdOU"#HL =Oilw流|JEg]c\B/r_Laxný%KHL#W]Oڣ[nP-#(kOF%3\ &D~~^]Kegkyɼ];j2U7r}v +{ /ĝͻoD8Eز 8ulBU蕫rO⫫j@$ SjEyh%Q#8p*?(y5^`[=-F*@6@Ui'S~5 8t!E Ko dF)q+:JT'-3‹b4c$|GhR}8Rm (n}:!ԌhKe#ЄSi_[s#?{Oە%U͌S(&ؒرsG?&#zj4_HUάW#e+`XUpe"D(l!Th'Jg7eݤl ,lWWQd8EAEc{uWvơ놘H;ac.,Q./WƦ_v(2l4#EZ?EFBT8]&)iNBVCvf)I2Z^<"H'.O.nohނ,qw^@IC1^u )&? hL{GJWƍ~GoQ~3IъDWEa}L d( Id&]f4/~NW ̷*Cv6yL xLI /ǜ8XNB۴QBp\嗢V% BFI~|p/Z<u^" 3vjKvBv{ ,aNQKή5`H~Ёb(vGJ7k+ݍzF wZ2ENQڽ*_PKj̄j{U KSSz[؎YH4:vR_nkڹGa[\~;0N>nґPBQK0 EsPuюk##*mM4s#Ҹ!4r|ưz(I5*bexPʎzf i臩'D+'ziɈgZarj}z㢡{lk_Et!n+:!j7ݰAUe {DF +w.Hη AsSޑ!ȜZ!¥.*XLV^ sn1Xcj1 6*s(,X\AϞcO/ Ei󃏘*32גfZLZ]&=ϔZK,7MkQzy%, 0\,+ yPlaK)u2~ ~>3uF% Qg0j1\0/8l n[12|5m@@ʯLFDQǛ/$CTՃ>h TR+,q;HolɌ\y+t:{[q9> (0ɐl;\fA>Y9 V҉ic?\Mk HX͙4\\pdT nFgo~Y> +An|]{}]8sI; (˽b;~E,.%U0I MZı`R{)] ,!|؏j"xM! ZD|~jmwM0gN7*QoC>+03Wa2t$ԩW LHI_\${鋁ldq8'dzh;ȢsOrIZ.M7Ey|B7vɬR#7y΅2`s/$8y))lPny-8@Egț1O_/s%ZZ;:lN)ݯIV- )vjq}Aa< Y@iFMs]mKyΩ f:U? _@ <L}@k ]+F!EaNK8(9ܶ (Q5:CfA\15I-f<p< Hg7vԞa.qŧ' {[x6oAs#!w:5Rmg EaHTu߱]P2C93 u8^\WhPl ZK`?z (i#ę~B"{h]YhhKW"TgGsmKs Z;SHM f~!:|} ,:F'R!ڱZBqQ!cAnݣQ\ +-9Bt_-$wc}l"A 2Hz;}wl2Bb[߈~$ApDƒE+2ĿFTH\kʺAĹ$X"Zd%0lg&HZr֒4$ PISk sI4iùj, Tf F ߶ ݘvf9O\O{E[Y(!ZQjChR>AXNqv =Q4GǴWgr]6Q.K!o60Ro [X(y'^"ue+gֱX$Ö].S?L5 p2U +`j#;Ӥ9aiKﲓ_FSԓ,q2AuR`g>EsG]ރ,L6AY.ag}.[w#1gĩ ˶lT(v(`vVuێNR݆z6k}jE5w{xNo8&@@N<=gS'H)\lHbI'(%W$}Dv~ QCӼɥF!^%>Jf<_/}:qT~U᜔rp-L} }еYM=8/!223/d"pJe.X1+7U"`2)fq-E@@yCKlMRZw揄\Zީ/?I槼OqoKƜ>yd y_,#~뇰ZT^kdbp=QSNƃ[Ad@E3Z4c(Mʱ7? qP>_xjs۸SIȔg VLFЁG90S^eznz P/t-V8"$e/ƙӗ`6U-+!T1uզ׏r)&f:lGq:dplLXS|Ykr}=p\Ivׁ#~Np.ŗP^v=/!w-7F}`,uyc#pp9-k觇V'8=vKZϥr6I/SEߐ\3NNMU~s$ҹ}˩"'cƤk)?mu[tѩ˯l>b9>X@;,C6YJ?{ڕz-0}d1a*Jj}o<B`}#@zey.%b7aw}?^_0uM6KFŰ喟sZX!h+?"(ImWn]$6f$KxebuKI WB#J-"%0ܫXGIM? ]z: JGY\ */<-6 ? ؿNNw(<{Ev=wJ؄ÄSiJ ؃Y]M]CՆUQ꘯s$ʺ(o KPp[b0P87CoWB:y'*~oOT/Qus:t .$)Zl^ 5zU]Я+Xzܱ^۱_vgxcxLl@Ef/,vh r?QyPOY,'0QsޏL8~S u|jtz着`/+~lƒ\$jMڌ4cW9Rrb`VJgb:UJWT-U% qxΥp ▉(K(A~rmD_NG^`<]]g&dmTв6,S h!͸׏/:F izRb(Z  ae0T6 u1#%n:FF> o5ܪDWo^Fw+qBI#?&z.qp2۬TmW0?3*0n #?q`I2,seIF" T cEb–u5JĆĪ$pm n~/G&>p@7% ݀repE(?]]6X_[dxoɌMo#$HZR:LhEM"f6Ĕ!;$|' r ^H 6֚ӈ;J5s+} c',9H\ ٵFaWg8Ɍ̾*l l&̹٩u9xW=9w_̲y!B:{aFI/y;ߕaylmb Ey^*LM.W+ʱ*wߌ.U17*hOvJ4:;4̈zsjo(z._ό+ov/ {O Fq\}79+32"~#?q5Oo'(zZ!3x"cv.B[+SV,;%/"Jqmtݡ{%2gnnI 0*$ 6/mׂ H\#7S,#m6꿘AK"3V&i./гqKQ[p8VwhG 1HWa\N#YKƺV6EF*<L_>eT*ؼ |7K7-i30>KZ4Íؓ,; wҳHi![OJE7˿@Oht'4!Yd*m`иJoA|˿^usv)͟ƺL )Kħk 4Z)ڃySM t0>5 Qng+RҐ W]g8hSԷ)w1v8'L%bUHbny8LE/,2-Q;Ɂj䍒B'6|l4(ӌEC)s~OOUnD2yr(ɫ2nΫ6Y^5+ow^-SpOe :> lk5<֜:\:QP{ *Uxanz^K۰c8ܰ N&(ECMHkq ]+mKZh-1cHBږ~A*ٴ:cBLB5 jտ`*##g]}Y.{+@)@1FV&iH5N@E%+;6rҙs3O6L#`CS >#3mS+<ͬa&#*r)l&;l(x|v0 (t'ahZ#!et#b'Ӯv>966=|`A5& b"zpݧw'6d$n~߆,r]{ڪ`I׮W|BϔTGmk 9sOQ{jfKKaՊi:HYi?z# # ~#3'cJ-⡼IX.p`*g8D+@g3|4E6y^#U/=wGi * `CVD-i#G4X-3չ^J f {u0qXfgP_ݪ9W] ҁI;f+v0S!ln<$]Y˛mB>aqDž': c㛦p0$t]I䅅.`jpVvv5\oV3rC0(y19p B%j4:3`n#T*ѱ% 0hiYAK\ePllWiE݂ %6gyI)V`?kљnUF khFk9>UJT- /w5] Y}1hi+s\:RlC^,f0Bdz,9S;̽z͡;xMDҋtȭQ.Rq1^&Ȼ圂OCȖrxԕ3&hi2En8ؕ~j՗,S`̓LT2yw{D';dZ7"befYe#q0`\$z4PQNj=sLmI4,r>wc|0OVX #M*ß/dm{4Q?~w+w噔ԇ+@B5޻7`y ke'ik5@#7IOK|NHp rl"?D'#qթ(^**;63oGWWMnYBvFW4ũ\VWCҨ&t( a!p*sgI3m&WuuL'b+Ȝrf2%זW&4f0|95EVjmy{l]I[,B./w9^rt۪'t0*c̦\0o$Py'UaZ+:]tӗ)>Rtxڒm';r̫bs 2LgSஷe`mEQZDH8!H`<=HT^vȘi-rq^6|t[̭=۬mJ2hdȞ f(q+bG`n4ǽoST[Kʥ(a`'Pq, 5hJp5w rsaLWO *l1r?K}(*>ys^S'IIkHvMI~ʏ^p0Y3 z',nq˜Fc$* e`,u4օAܹ6ڠ|™5r|RѦQpz_J3anmX!!Mh]sO=B.|B9b~^X1fw1WN Lq0|bB&ℕRڝV4($L҄= b-8xd|u]|քdkzkkJ Yw|͗H}WݿV A[@2k5t7Z~zw$ o ^#TM2IgJOit#Gglw$zEDb vpŪɛXVpX$T m=w NAqj UM?N= b?e9׎dOmy[ Q}]~Q Q<җfCyh"n g*{!9+xpv(+c_5G .GXʪ33LǎX `2tBM좶GOQn0=~emJ7(򔔚rȸ6d_s>5<̑3)6:Lw_βJU0kP)je|WFaf G5 03=̱ JcJW9ow)',VyBt([ Bѯmg[);-Y me!2R b/X->1'+MWoLY:x̕0)Y'epksNhz(ҧڍAnD+|QB@e(s?Gˉ:DŽ% ƙ~}_ic'pgq9^mLzJe*~Q>Z1ulBTK#7CWw-`1N~%L0T}cQkLuKx[Rn{?1d9^c ~с6D\\Q_XP74yv~9Wyomϳ/]Ѐ@ݞ(^yǟޕrP&cf'4m#Ӎ٠N-u/ml9S| A{AĜ7Ɵv4hF=(BIb} Q+`khD& =6VO|lx]GC.堺yIǁ^֓ZLLj7W1,s!KKz 0Y}ar:pOlty|r+@9)sdE^+Ľzua%S l慓z ?TMFq)L2",v[8땝=pF6k~D:Q$iu4-JrH$a HkΘ1$j ۘMA͛Au訆6)%3S(uovF&cU!(#ӔBpxڑ''U[Aidyݨ6}&_շ;r&Uo)/R]\[(Үp5'TqԿ1CiO{ btSnתO mqd<KM یmDM)`6vi~^w9 {%m$dt؜R ]s?KkEno: ˊ[K$M,d$Tכԓ̛~wd-D m^cgw@WsO*M WҢ ~; !iTdI{S"){KuZ*?-SayfwYh-rՆ 0ԯn5ݩ*zESyоτ%kJzw|P:x Nk\vf@}ab/9PN>=FxѤ'TFv`Lä́c^5:m|B:k.T'IVڛS8fM@LB .9{[^28qjEj+;!>-i {Z-}.cRomH{Fa;}  -xr^;pSկ2aK6=a(?ypo*3}x;g_FW}s94nDmiLJwڲVvSeڍ}:%. X<?EvEaXƦqm 4ŏ #&Rޜ"mɋrvWx` ~ TTkC+hQazxZaDKǒ\zH'[ntb)kgd6a89IQQ^KcK#g6_lMECe\ kf\!W#CRŮaձu`!^KZ4YiW RS_ɽoZͷۂ'%匄8zo" Z*EQ\=[=`aY3 /`+@,~a hxjX|xWQٜZ7sPXu+CJ\\KV¦qwF m(rtQS9+=hծ qrI0+9 O@.^tQgN&Z `ߟG-MnvAOvV/X`DD xWȏd6[,.+]*M| !xS)Kw[|}("~ÓT G/6jײ{bh:(SIR2օìUkV6\$agb`9Cë-3Vw ly0&|2ZIm@$Zm0nAhp~܇C[$(l ?ւЃ~Q-[nǓЍ-7`;Qxi&,|ÍZK!"Iy.$Nw=R&Y,aɓ7zEVY@ےL.liıAD(2t sWHkr3@&DC6l!r_/|Q x݁t6C1xto ^1ml2yr Q?@(Nu7PCC[Pѧv DC1w3EV\?~4'ʊ5arPpqGU n1 8Nj/X㜺 L5org;}p?L JC~XQ &{}gJT kҦ)R ha;U"S|a+>~` WAj)ShuhG 1@5x"JK.]K">BiN'ڋ&;0n^\U霋Z-:t-o$XU nf  3SwD(hǴX@U8Ƶ,OoR|%qjy~mߖNֿaV SlWC*Ry&qSĸ?QZFwڕr.M2j2|,O7Z[΍ْGw]W0ȏS[xH6C`ʥ$X>XmFOW)#E\<;wT}|eO$֨SCkT|ODL|ޓ5cu(siQ c`gfǭ8;ڄԿR={O ]sN&qN 0J5q)v{m͌5_ٶ~FiK݀+|~e*8k\mɼ~%}'3n (SpF̱M8|ӜX 0H^,Sx'E/61i:}aØXHe 9^#5x3J RA}hv-jJ//ޯL!THL̈́MT7zKHg.o>7- [GGT޾~YӦfEen$rcГxaDEpbsŮosEӬTXQYb}oi?nᕛklUpq_,}d2peFnOO-ebsf5C %𠓅E?3oVEbG6XO#E;?W͡Wvb&IkΩKnh/HFWwȂhaj@̣A8O RtjÜuB4!`2g-4̫BW.ﱥ 5$eL7ѱe" +K5lA>;濼TY6:Zj,!=N /ɘGDrrnwsw;i ~'mECvKhfWx˯cd Œ-d Hb%k_u_lB, >&3 jg"SaRG‡?Sx@630rci+3p`[i04|n`6uS˦7]^Jdh$_H2c72ކ)N( V/#LezV9;Y03 Q^jP՗Cl=䈱(Gl~Tu[[|H$/XE~Z=;rOoR˕#:CWH'~\"LhB. qG`^7Ȅ%D5u^w{QqేNnpj #v'^UmT. t+dy!7*28m2vh'-ɔ y'jU]5T N/D//T&#Y6Gwn$~^gȾV)}׫ Ap\?1(ޢ)ɿ'=e1s3?j*BFrү P!P92U~`KCژRP*-ۈI#x5Ӄ2#A!fwseqĹlI W`\= DydK?GA#9[4Pv,mǮS/@ ~7{ϸ_,!񼀭$tQZW[ Zj&ݘ9yOyF>K^ .S\cp. .RzLS+ъ2 D0R0wl3 ;ū@rejvE,&Էw|g0ՔtT]|Û.HQ?Cri8X]ƫ3Ceٝ-9`l}ӡNw'¬/נ8C[G3]\OAtiJqEVמ{˙PM:c1p}Y ?i,~_ܼ  ٌ3bԳ|#9[=$d"wX=fs dґs7u{Aڋf>[0ԭtPur&K"K|wf 4\rݣꉩFʞؒq8 ;ϣ=-2IȂQ7/7'n>'ϡ"pMVW)T &aͳHDM>j "Wtnb2b pYv_U}]Ry̏xg}BNMEHZ'S!o3HfgD&quO˝N5.T H5Pч_eac˽}#ns+ `_)W&}<0Ud c2Z'i;vo/ e(;tC,:L>+EصYd $^gW2wX Է 5 ro ;3°.x@r+bKP0~de y&"b73- {.ڧ%;vjvQ(?sF[àQюɺ;b̳3~kGCB[w#O˅6GQk7&t̛ [:)`H' T ;{O8FE NL-;Uyg=m#to9щWa%+

6/vua(1V/a0TeF㐶|mm qe)&7nhgF?̲:Kt8>Jf Y_,C&}@RkL`-{Ex{7-$$]V&.?ټVR?4t!w{#|ek,,r@B9E40Mb\iT 2du!b3Bqf/u}bɏo)3Ԑwi< /Lc-E MM?| RDT5$sleL./u9Z&v\FM",!N;2hy5 P<Ɨ,"^_Yɼ1x 9:Y hE68;@y}҇C]|Q~Өa㽐/ϥ5m<_t?cnRٽyK2˄|vӗ;rV >r[+~H,9oL/?lq[j.*NŠ:x;}Qr`]:f]1: 0cuP' s w/':X pSyB: p_OUwozy ~?8! :|& /В vVusģؙ3Owos\-9B_0NOmw)/ dHDKc=_ +J<"/\!HU;eGUt(ejG HAԐЈ7cg;t:inT-9_ŀgD*!K#S I//lCΠ5ᛨǘֺbdMςw>LKD 8q&ĐrjGS :o`WkOrlZtsOD1¸6,[@[墕 SLzmܰXJoKCr.JŖZ8k|S-$6 > n!jN/g\oPh,z+u H€7sU~2J' h!eTxgС櫎2H8Vʒ=sWo=$%1=ZC)x^sϟƁFrc'M ՎνqĊVU)F(jetPc:ZL-΍.7ȁJĝC!\@]}exQLN;`N&M ;/RK}w:uy(!I K-X1Fͳ7 f keYa>*w1E׍ 갅#Ǻ -F-(h"WS^"m͓>Jfv&OmT rNي匣͈/kR c_PcK`>WoRvs$RHgV𒼇NѦ`H!c:S=6V/^t 1HWk^cn@qVxrT}}Vuv>vA)|dh8 EUOm:T2HG=)#a&CbSXރ%R5SW Y{>cH<A+Ϫ2/kD7.Q% 9sTNkzT0QG7lSAJ_TYyz< YU2?43mY%cKH byv35.SasyNfWdժ~#ŭ p_An;r[~Ǭf2nImd>^^k2hwQT"0Y\|acYz T+4+*X$bXVXt:$?s7//q7rO+W(yE+]t2f׸1݃Ƙ:m7wc?=tp9Za ªN %[j8F ny9y:X^e{^7XyQ>%|7 |s#[rs} c:Ał7@,#B+,H4;gmp']DJ7F?zcb] CUdpc*26sƋe%Oh%$d)$}C ,  fgDrt8yN86k׶ן{ l:`hjw7!M#X#;*n+f q y X|v~"0aQePb }ĵk"g(ЦD||Oqza&}g86[72*+AM2mpɆĬ |S5@y.99X KCyݷ-L c!ݮ*-"ڳ3h^T(}"7$"In9sU6Vkd6$=f|cD߭npHO(GJ)9i^뗯 j7aOݠe)DzW^u \^#&c`;e1+1eJr̆1b sc*݃]XpQ4#^\#hMBGM`dD^qFVffb)͡h+'Cj=  p(cb>շp*S@Wi'-cS:jEdFA0y!:Iǣkn;Y=aJvZ9}`﯆bTaq 9o X /@|5cc.:HFA.ַ^T7ją_ >nh1-OO.4V/5iʈWfn;áDYȈ EطqO!5MqlO{A WmeXaVrڦÒzLb=<:"Xm[n2sx>jfOYCg|MPzP Ȑ5ư-+(2vFT> K(kDv$<gj;OJ@m9mddB>y[2K"Å.Z,NH^`2~@w)ؗ``q?=WmXXOgмen@ix C8YFvKK ){~wCDAH(T F@Ƞۏ2Dv]l֩*=q7덬vf)ӶQ Q|&'p]E 2!O;* | =U@L[8}}j)gקiCAEARdg=ԋ/KvZw GS;fD)v􀐗B~ajq.MRꢡy>B^=6q#s/fnH^Si(ǒGsQ p#YfIh|e9XĈӿ-3DܰOi$sd3{ rswF4^D Oo ȯj{5z|nt]1\([L'2#Ld z&ry58m ^ZѼMݞl!kkqQK;;vۆ05?UϹXM!C'c)Sb&̳<0:%:_g?j']<+Þ&dkr=,C.4R.M0jwW3ԫ@F)}*HUryh8623bMO%I寤M?PIC0gXܖ\ R{POhͅ0崱x@.u۞$߲g b(-ulA/K Z Ǡ':t] ,:߶S.]ھ$o㫽Y܅dӎAcV$SPtR`%ḞCdxY f*_Ńv x@E,˧d&؞F*"Λ},jMв~6:D]) ]y1-ީQʖP췭H6|baGtz` uNA^E \h`>MPu귻__y2lmv;b " )PXx0QFnάt64dN:!, /GԪi M[S w Lڪ2_MG DZa Ԛܾ:uR}&)$T|9nܿ[3[;=ɳ4&m/yD3<2VIm~`-)bl_'*߇(M%hFpc<" -;ܠȾ$Y[)S,BA08uMĝg?H0 寇:vq~g@tTkΥu <7&Olk*ũ]zQHSdHw@RԵ?c|t:bEl3iq 0gZۨtqԁu KQHX}PW3&'$@>X݋)Q_ 9/T!Q3kAzR(RIބW_b~Յ9!8(1d(nFޱGww3*@u2B1̱ҫft>K'][2:xՈd窶l$7FbR+ nM˷(r|VXkQ{w3w5`;L ^KfDKi1gRC?5u9Zj(MiC (7vx>MLmm)*8z"YgѡORoP(M >ծW*r{'Rۜ <]%)]xdz$ -2f^j * 8 ]dW.X"*hxT[dh9uLJxce 0yVl.1_'9P4/11<ͭ*xA|Ŏ!=~cS9w1Cܢun\g5C"JVy^iu6{14E6$t͑9I\4[a*7`cƅ] ]uof Y cWO17'k."#&UbL0 tE&cjpx;o3Ojdl~L5hew(XٓLC*(xA"Sک0Ԭ2ʍOq> pb*DTEp9Er{͈S]'_>)(0|,+ m[ G;c~Py%\>y]ҟ^{%t h%LvB"2˔@1΍'͠;ߕ|-yC2tbt{B5R;| iIvs !6̣nPmEB_^B4Aab'^ʥUWYx؇󷹧hJlIx.Y}]1h'0_,!8 pGЧUMnX*yGvfƒd\8.A+ ?4yDW˚IW|kO`=͋`t>gk{5 D;q ȴX22Bق 4˫)B􊬋5 y/"'Z5LY= zo*\ )~x% G2H*r. _Y@}5"1R |R[w8&Y}):wl(7PYDusѱJƐ-ՄV 7 }&urmqɖ\He'Y_n7H>ox҂wz=5\75ir(x% Ua-wI}F*wI ޙ'br/J? 쭘tiF]a*^:c\DkBҔE:*Lye}t_<#NaU,-:Ln@Wf}-ݙ6v`Ge/I)/&Ӳv(n)p8^83oÔyׁ ,$DŽ'QlӇS߻GINLLx&QZⱋO 0vrV^@C?4؅D5ljAggpI|e^3-; !CwY3K2/*Vy}߳˖Wd $ x0$SRqrC"+[ICjN`o{8^rEu!Y*Ubi8Е4 PA2,BNEiv/Lӆ'a= |;1b5Uq0oН ~ U#ɄwfN.E! J5SHotM+:yyVcք! EmHʞ uS1T jsE-;I~JͣD6u;->,b Ww$2G -]Io)q)]Ux8։qYhR!fޒ' R 4 I)ms0WD'4 1@6t`OW-PFTռ>Ƭ ^&4ҊIEqQˏ唐 lIVr'Dh-t6Ao2)ԡԠoq>OS *lgq^bBdKXـ՝, +ғOm)/tp&!ɍ}[tPs%ahQXc&Fzm8\3,/g@ZVHF;G2TfƦJ $pNh:w aݕ9_ .y%$Z/֚y:wX_ZZ 6y;׳> XT 2US%MդQڬ/-^$@ha]8ͨ-.4<m_CffQa'Kf-|8BL4xA#Ӛ"{E4z+KX;&?szh/5dZy߰am&oRC>WQ]m)[&_$>Q`} KI$ ;a0݃X䍻71j#C֍ZZ6fpEE^"#QFʁ<G(Bm{LA]> O%#h89S Pc?gEzЫIcai~%(5w$׈`*F&ˈ%eF<^1ߩdm+(W7 G(1X 󮛀 4;bYȜ=#ߠ]=m$">=?!Qe^(xξ4A%1SVMp,U '2>Bw+K!B$eS-ෑ0ݺEĵW9=尔_ڝ֯{Q5"A>p~ Dp>c8csq7TCn-XOHyAGAۦ-z0R؀͒_ko w;9%%ݸ%Lhg;Ekc>( j8EI)𸷸6JJRzqއ՗C>- CIC'zCka]uz c'nBrH**S_IEM. ~^>/&]/;s!ܯJZ |]}1,ӕ"W ۮ܂x޶|rާ+JM} lG_.T%Ri`(ñgӂ8묫d*Α3hWʹMp"fگ i,S_j*Ùgۢ_{GZ (NsHlo0+'қ)'t*M]SVʲM|DFoUeס"37!2F10E];f>P95|瘗 Nĩ|W4itVBm 8Tql7Mud0B˞?5>Q=VRPH"0#( qL$ ɱsq#$ iJC0yJ_ĝqYcm`C(5yև+ɜ%&@Jd"u:w&q `d%#[WS*o˜Z*6jbk!T->@`kf[D}4DW%@^)~*V zu>u'3eʽQ!T,?cԡUt~$ZӐH/tL\$Ժˉ&:PJUPmHIV@BrngZIҷ?v\(=ɡE ~ʿ6+ҏ;2lEaNR.rxK].c Yq-Ә4 ANB3)/~q$^EQwn_2vYDNPgq{&u~rq ._]U$IP i!J4]'ۤU^O \N*?ѡ"_\aXG6 >m]$NyK^\gp$QtB!HI< B>ywkk j_ry\4.JnYg>rQFosSESqW`(8fm:)aIf.ejޕei־u^_l?'guΉ:)!/c:ķ1Jk9> D\IZ2jp3ʑ.`x<ð-v&yY/Tp~fйת@XTz6AxӥL8\)Ea:>蠘_$x!dx"6dQsVϯѣDVGKG_K0CD\Y 7>pl0.xxj$!3 6`9+E+ Q (6$?*qR; c!B4 qw!OkE&ZDlTV|H˂ʭnic ,<g mHs 6;$ah3Ѿ>r)AS»X\\dus3#?-&QAQPr~5lH*UVߐCR$3w>}ӛr6#^ItB0EZ6&8{P~؞.V] >=5vX6~ %J1~?Hg^Ѧ H8FѯRU$L@d)Ш#yϳ| wDG|MբY@ў374H $ 44\l[àQWWϊ8B^ :䃗Kga?D8 SZD1b߼WReC/Y׵oP>~v.۠3CJ7`˸-7Xӌ _PVQJ<&'>{R^l-En/#[=D 鋶 bpCl31 a*=w~ТL=dRf\ݺ+w) 2^+?^&WC\.P|R@D"qdlX`^ΡCTjd'^A*y&Cڂ7W) a1. Bo؈FTL5#smR/^BJ@jVxuX}jдh){7rQljSs5I9]~NGf=]]aRzu[c0$#Ѕ2x.\ke^>q)1{.)4/g"}D̑-MEpQ?D V:Вewb FSN&XhA_mF$!- W$ICtua=`T5˲UX!3RCWEѣ"@2qh߿9QE@N 5>rbim"aC t`3rn2'8-T9JƷ=y86I%NGAZra{&ID&Ȳx w/p}_/ >QES[ 0 ᢰ4Yx4&QLDTxJ:(GK#7PM\1P+ٵRBkaxj(]e p(z}BY &GTXq/KrwԬš_ܼ?!T|8c׷u <|Xݵ{5Y9/4zNoc `Yر7k7 ^VyؑMbq{jg޹y;lHiھDsK\I`**CJ)f $%m,Q$(ޣƥIAW5kK]Wӈzn~JT'^u…M+VIST9"`[aP`)Dkz2+FW@!fL_'z ,*R X xaFZߤ7Z%OuKYPQt=PgH٠L6DrVV^2dg;_mJfa1ZjXz1,wmev?JkBѧ`/iu_ƹEo߮sֿY" .5=P )F:ҍt ,RXLKXV)0=H 8^e+Nrxwa C&#IxN2Bӑ<+wpgrGC&EXN"٬/QȷGsN* |8b4,OO{$הhC/kw.yot1c^\>`G!"baqY9:F1E'#\^E3o$`.Ot_>Уa5+Vgdz.Sr 3j=|4ZʵEEVa:X;|)޵Std޷@)[7ތc(0X KwL':4|^>_zwr-hwĦkE_pLh1Gn^%s6} 5ݘq4,j8P_sA8ufu~w1ٶǡ="YN98 AE$ۜ]ê\(7_ GK[Y .?:MK%\ y-;w+,}Wzխv.{%B1+EԟNp\bξHBV|ȿ6$ö!AgGj8v=s"ڬOry|κr$@jKpL`@*4ҏ fr3To(iTQ1I=xWӌQKŧ3̢?<->*1q d9 ɡԏIy}boc^nj~DZ*}5ć@GG2;UZƩ l]ar{}oHqz|_:$t\s6ʰ>/0W.l\YZCR$͗1ϩpwX޶ dI?d}+0^aCȾGΖEȧ#dO]_Vsx`bcз',8sM h|Y]0nzy5i1Rs7E#uYx-c]<׭Oj4~zx5^9vs'Uo#CjړσYeemw30\߻޽T񡾁Xf0olfjYX*K>^u#Kjꅉ*"<D/dy<_%2JSP :xT%i'u0A&n 3:Jפ'EsW{+-4j S(Jr!{ݹiRd')G|A]fEr:wx=-*Ǯ~O PGڂb@ڮz9^oZZcrYauj-2KP|-k+砪T 78܍t`H\0{XH\J` 𮳐ۃ:{ni(Y`*E ^*#4πB@oRv?&vX"{lPtޔ`J< %0Jpp@V6M?,zt FA(!} f!iw{TC jOyd$9P7ޡȉVzd6Obi3cH(M({̪Ia^{+ߝb1JIuѾi%a4d >.xIFcp y Foz3\PX.M6I"M^QNWnCg޶'fji5QAP3Jf?c}ր}7,,Kfv$zVCQTib8uUX؃MО4e#k)rql/M6сtQ4 Θհ_+l'[: Q+|`O42".o%gCKXXV;{tˌ{b; 9ry}uc5ؕd=M C酳3?Ch5ZJRFհM7€p`{^ y6|fJ\sCE`⍌]UΆ®4^$i6 HMkc㌎>P3AƎ o 5*N%4ǔ'4WHc\r yHEnX$rP4eΨm6AFͅ% i2d(r$, KgԸ*Ie7(9jE <z<0pJ@>5zOY7aoVRr\6 U裩2]TTLdօנM*_>"kɨb+4szAa/D>!'&i+55 Q2=$)&m:qQ#y2%qہ h2SE < &6.Hh<~'<#-$S Y>?ݼ{3s );';\I|5a"%%_F l2/}O+Yk[QS6KrusV '蓷G~73^L Ed +ТD\(^Xl܃k4N?e<%V2%;f߭m)IR6v nj!> {Nc?fQNsўi(SA E1qӘ!*91y; 5?"HX561K{P#Ƶ뽂ҖssrmmfPQ#Am?ZF?.W'~h:6f$sJPƗbϵ\Gwr+s(nPsϹ+wmZ"Sv7[nϬ br,'c??2h%{g- ŧdQ^ӹN$)IB_.Yٺ @2)~TQ*2z.4I+% [[i!0ƞH߳-۸}`̕Hu֙g 61 jr݋ƌ he x:CAXKa::=nF&?pwtpw5ĄZFbg鍑9GD͍froUz|~Kyhܹy U4_på81Rk@6-ü&v@,K٬.Ǡ%E]6/6y%\W챵}ٶ\RvGs#^eKynkbe4Or8߯ ZS\R4942w[_zп'DOB7¾VWMHl< If_'SZG-D-kbDŸ:vs( 17_`pm;ⷨKU?1*v&L9#t,/#_I+Hˮh75UFeJr1vjvk$^!IoT`iA% tY.wф_l;q͎ IC%S q%FYkeE[Ʃ%I4[yzs!g0 XRsX4#L?r#ĂV.n6"#ks{_aW ,"8*fgRSgAOZoH/?J6z4ywQn Oۿ0{9mIhH,ujqu-y$yǘ-;)6Rk[p:B J2 % m.< ER)5w|M =_d̈́{9O¡}nm{Y9;']r 6l>LIܕᓫ ܛt|n':>4B^ps9\oާt%\WB~+?x Cf<SnQ)2e%|P^ͅ+\5=K߶EwW4bLU[&JӋ+p;D?7EZ{)R ."wǘBD֪J[y858`N(0ӏ71#%FcVjGP/<WfnsV@kl^e2X@46$¿ Ԁ/6`Wcygc}}MA~,'O612?g威.v1|w)Jg7 (քY/cpQwKo\U]E r)ңk}v iP?:sXG!͎-+aNOih}{ @v%~[l6T1_ŻcKm)Zz+}ɐ)`;%W J[:6Kq^q.څ*:`U@OT>n c E k{Lv2V׺XMlAar^q<~RW 0!"(v#zjM1qNdeTu6oJ@>"9(7vӝ%Lq ͮfU 4Z&]pE8Xr-ܼ8iݱF6)}dڮKֳ|hPhdcGЉqqײR.x85[Ԣ#egJp+]&ih)-ͣYoh 9$P0M˶*Q@ Aguj&3.e{D8PO{J-`Ȼum2w31[oyAZoϸd^~'b?4OugSg!vDxX6йTuHO})&K_uД$/A0SCO?>G0Z"6JWAVYGI$ڐV[gri~IPJV K'2o}=ْC?dT2/ ][BKI9H ITO!M Y("=9a{.(LqcQ\TF</(%mMG}gsޭ0=.$E赯޹d>bUS7+㯥&L BM_Q_}/f`zy]-pa)ϖ!-^Zq_^.(q@tĖ<xYH ilRl3`hXM3T؊<ø}!\N1i_O2֥/LBo 8OsZe9&|eiȖ$Jfk-NA nS&Ьf{a!F=v ÚP?ƷQf2PBOa4ƾP4#[yEiDɥHoTмNxThbt vDc @K˽$C}v4NϨps\bwjgrsʅPb>&qQl(L7F4VGwW}H0\( hΉTֵ ((o_fFl75j]?q%A3n-]2sqaP{V/`+_Zь+ÿϏe8-L*W^ :Ħ?VeqRcnZâhs~>ep~bgD7Kz/tA}$Y$ / Q{%!< c͊ p9thR%Zw xCe7+t"}cL`)i 7z`sY8M0ܑE;<*(|k(-(q@6Eհ ؍nKja/zN4pXFbU*٠۩<ԈE|f⫉Rذ ۟VN݊x_u緿fdBCcOӋp,ޖ" 8"´!oNC|I1fΰ)a\p%j!SȘUo4=4qxwoEQu/:6gE3}|6xI낲zJݠi;ȊUoQNOg)",>QuGU3<0l_v;VSt3ZȭQbP?fϛؼ+q6_Jc4in@/̞/gż+hJUݝ'CzcCZE>``/ 檆btF2Gtz3L⹇) '!+_aTIH!f{i2^"%CXȵs1VZr\IdRZŎ䵟.gX.C+B^OE0VJ3]G֐&iOcOշM/ yy~Bf|gAV0]:ÆC5•.rշ$-y$@˄{ ̸@s`{QBxGSs U|0'!Sju%k̯uv]]p5MN;R,O6֪y,)f( y\[-^lX-E:*c(os5i"| , 󼰅'zq5g\3/طY;v(ڝBjк'"{߳*>ܤ,I>~ulRuaތˡԳBcztIqV_o!jIJ*|\Oc ]ўH|8frstj9{e,ƹ+[…)n=E'W5>!F+jʡhhzd3ؑQA(yF W[: ) ;A؞L3poy7 Sg3Q-HuW*XZ(ςXlFP1Kg+'BP: 5#;hq䕧"<_"'3 ωDg*yA,"jxۄ8"XE#D}R8]Ѐ肰%>Ko[ymW.!Fjȷ* :Vi쌴\dsHmH7Қ77>+bv1-d%m(]6 r }hՊEχ!kD򷋗 Cz Ig )$:D)'XIϧbb^g !17מ7N2 3mP60|tj3וCrMy_CbhLuU 6=FG@ u toS4"P r|C%m`g[o>z;Ohkq ș˰e%OW4fo}kAӹQjsNH!߹ۉ#B?yEh\Xˎ45ek iaM|lKz2p:_F^}#p؟ޮVܕKz sf6q_͝^dEL)q3]'Q(5EDf;ibR0;pI]tyWk{Gb})pir1k""#;` lWI3Rw2)N9S3hVG׀1tL<\ΧMpNy/6F2Jd˾DsVw8 G3$Hq{#Zg l&@d|b} h8>5+hfD/&&ɷu*AmrC$,#O: 栳iKO+Kius|?Ǫ0*|?D^|j?* _nC wꁷEmh<} FM2/"_˵Sگ&@7@N9 Bյ[ݕYk7>*l4يrf<,U"Bs1-*e+dZ:&6ȱE+dsLϒe@ֲR>Dr|^PU%X_蜵u ko jwU* 'G-1,qęAʕ&(RWM`oڦ2|^`ޛhP]MoO@y]m29'kܘ cI˃bM*g"r ~@m Vvx*EC87R&ԛn[RhK85HI[Ҹꡈi7H>M I\xE*ܯ T&A_6諨TH헹-uO/el_搏Al9y9o9ۊe4arIi{p@)u\&5=ϹTJP14tyMx >RGym-u@.glkb^娻Q\|7d1UOcd\SݙCa)gQ$ #̨mA_=>pkKG+T˥⳽R[58א8Iz_C<W2Vf 7SVmJ04只A#hO3lI,c|AorMQMmDHQopH|ϛQ/!B9=LPϴ2>eq-A=iFX|3}5׃O-`fYzHopc= jV|(s}0ړѠТq:o*e)oRp AyʚC9TK4*BCd/eIU U9RzlƫBŗC{CO*~c~3蹯]5ӷHOJٳ(hS;J~rOP͇&H^;_kOw!`%]o:>0ܧq@Սtֽs h0 #pm̅/['@sӌyy7?vgĈ(dq8!wNZ>>U-)uw yԧ$t7风R.Xt sϨ;$C , aDL]בbCƮ.ht#=i6_TsPqdz^qΒ&XD?xWg:J}~.gq\QI>06 Yܣ1Ef}ԛ-$l&ؙM}芛'GL~V=0/k>Fx#N!ZČn,ӱYw&ܺ!nHg`u#k Hk=߉5qUCm)S;e-{^-S>ӡy[ /ĸ'_ wlS9FUE.!"\zQlɼ6H yq@KNuX0h !H] wŬ_Y8r+Xn@6O,+֟2v&es@3-j5Y@D~4kus '1T!tirR-8GM.+7iS"oZ('ٻLwcųdDL}(-/lUFͅEZՂYo /d,:/E"pz(1qE>*UtjogrGo)݄ʿ,`os )OE-)L, w>ltl]+様6PNυ*s?Oua8 I_3jډJMh(& ZO*:5{')O;Jʧ)3oШlW:hma`ρ ,`ZR?ӑH4:c )2QS|cq$CE 7>1:Zbyc`L*ڠFݗ<ӯՍU+I%cq]>,ጠI =h^K|@KHR]7Is{닀R['~Ȅ;ERfQU+Z0wvB@9۫HPe=K }%̿dpAKr-WENTnPS@%ׄi^i¶~0POw;[ҵ̨1-igKBTk4 pK+Mk ґ5:X$poGe rz:ѭԆ+tSHGs| 8맡ꥧBjKXLt1$W<BٔubfN*>r]`&/nmb\Bsh% t6P~,Kѣʬ(eY5rQE> CB?+ !2^,EM$1J,l t浐e]WG")ꀦwE ͪ Ë[SSh|y~E? ˁG BCӒ4iCS0ӜYIu= u-e<*EM-=M.Z8/܍ԉѷ3I|gs|K:<fsz~(xG:#8!$ tW?"J{i_Ȗ(uLiV?)&c: (!Vi#:=Dy_[ Td,=Y3y($sn@>^i4g/occ<6 oPjr#a=v3;acGMRxs 啦O<"٣& ؖQB ?̭}͞>ll/XDÎ_YpmG,NG=dLxQ1* 3BոVNAR0XB zobV3 : t $s291g[Dو%ːA~O5H@P~z(QxBT 0^eȷLgpD8p5m_jkuqyzUDUEM ST,/B85AyL\~#7$Q:TV) x ]Ex<*y<~ qR_BU2E"^L(96U bH]h,ՠc*:׮ ǀJ:f@;nӔB< CLe9b@MM`^~4B+nH3Lj_3l@5{MP-*z#- }vt$89r0KdOPՒT뒍dXQTv9oW:"AcI)]55skJյfO߀ftcs۩nۨ=aZհ:'ȝ_fD̀^`ݝrg"__\ݿP'UxBַ7 o==3!.)x@xVi 1ŬlF&\cm O$'a"E@]h܃OH.1^d\mCȑ+dW4+lz=d}f}Vr#|h"A zRϽ%l"~Rt%K1c} Yd{7Oik{z|`vonI%'Dž?VmKt܀y:ŽV6pKMحs)JF^|ʞuTǙ| .c:o{;d`jLLyA-=!S4P #v"8DCf9xel8 5r]p waMJe,y ,hwoa&n+.B>L=ypo)b%jML G9[Muv3ld2Um暯7:&C¢ϝ dpb ʊRC*=OaԖEAJRI(Wk8p5VN"c * w`Ina$ X\&SӅ^K} 'T:mw8$_nkhe>fW,J-kJ =ڮS(!o=}0"Ms?\9Oc4VEp!ZoTqȈ%Tj(P7\Xg+oǑCapJCݕ'&נP ǍLߜfhsRA Կ(KK4'#(ہ`^ Bth@j` fc/MnO Q=rKd⎤.U*YklD(Fۿ\^8HT?J7Pڲ+0 Yᾧz2arHhFGPnkbF㶉a*h%2u!& 1S.Yyd %*I5"Vu^O01VAFt~>AqW`gjZl&nxh&ri4hth7ى|oXa[h8҅4E[cuU q(zvʬe"6%H~Q]-t* k %S؃ e?뫑/0fypOR *K'~-AXɰܱeG.+lO*z'!WF]g : ѭAqh4j{G7ܼU9LpOa"vvOʀH $8lFA*A6w/|`'q[&HqՓ,/.*0MXB>nˣd/ ⍞嚤%yߙZP+*M#X_M0snD۴$yLQoap8(~}#\ao\ݙL8]gW--~KȜ)aM9&CiQ&EfoDS7Ub\U2}hcIS}c=|9 |[.{uR3\3PXظPo?-}?~%7>+5(B $RU*J^TJ-0)+-QOzgoW[yWcNμk(FZR·a\k~!;*ݠM7#Pɼ eP,UN8;a Ob[nHjp7uuf3tW#ГsRg3^wʰ<61Xw]*4~jEC"]6hffEבL@;`d m C~0Ru8!/řx ٫ݸh Ӆ>hFQ/Q2Dz%/?8'HDm>W=Tpz<\G+ljT̯",Lțߵ]NkÄ4>2C,$7?V.«NL,m ͨS/5zXR}E8i XIMR/r%bǸI:ླ{ t( ىG6{nZjDJٕ1(i9t׽hY9ϤA *Ի'vj|$b,͖NU,$|V )?'HѦ]FFY4w] 1"8ڞ2 /L'ÂpC'R+g>pqLooQ`7GrNrх<=sm %9V.x_Q=ҹ*Ɵl䥆W!f(eQBNTn'a5a[#"Ȯu7|ӵW2jvpz R -0:'̝$٫mC\%{8#.:>^ {jKS=sɚX+P0KCybnb)Iː.bFmɰU[~m7l]EUz(fYL^ӵxb\c|N\NwQ*UlaɡJ aɩ!)ۈT1/wIԜ1Ҙ@QJ+ӊ[R iq42-M"`yߩUN+=<,Hըg3eRy ! 8Hu8f_xY%[ F~2Ea0ͦሮL-jZ=} )4[r4&Esln{^c'r.ZF 2 S9$2b$%FdeR9PN͞$6݂:_́sp?}xfH#X4" !v\c+:ϖCO¡ cL15m!H,?~Xs7¡/n?,V0[=Oة+-k2M M:.?HEe3b:"b}*Y7j`@#FҞO?'Ӟ{f[~ FWa9cppQSD/6}qBEKj4b5 !Q话CW~²Q&}0qFgeђmDl;c%;dt}]LzT)$>ʹh07-O8ceȴgE#o@t<*ϼ[T&_C>2~$Q~Ppxubȷiq[ M݈n7 x _'Y벼dh%S/eVL5އ8U^;U%𔅣q&ER=/^ vYj; 1StI\8ȷEt4(RP>P^vʍ.@Չ@<4;ff(D`Ag1?FG`Dzm5(ЏI zhh]wtdxGG4rz,~%/(qL@~5JpI!Ӽ V5i0GmnInibʐAd(IFH;bW6xBM Y` \LMC/x%'|th4+Bg w|^ ,FMtWϋ&bZ&F^Yr/v*=rn^sK6Ż?)r/Fz81ѵ} 1ziʴڡ}A`?`xQ7cZ<%\SܽtDnŸ>5өī'X^/ /sJ`5zƑ g{OUF)Խtkf]~*.- .a숓ưkjYm{`6A㯠TUf+5Ўߋ vO:9"^9ifǿAK8jrGN񅹡M e?0|+10%o:;Æ4ʢZl,eZC^-/)Gx9&7F79YՎQW nHBdAJY1ŽܪٲHB +Fك}ѱ$h5dz|$c U-~Tn0 l@ u%.n۰VҤU{ #è)PVRŏ=#07ܕ|4i?9T%:F<)O@y:TdX z3ȅ_ԅy; Ebםm[8ע R^MV@"ۋ0t}3),Cy\NaۀG7``RIO1W#oM!=vOhh5=a%o/&XSE&gϵ)} jDl2[Dwm̄޲K0ˍurNL\܌|?EhSIY4QB@xw%u h6bwqx)cFO y*+C "Dع|ː Ov5 A]|)qذWZ2O["Sxb(լJ!T· h "G<" HZz&ܭo{}eFelJL\ XY@^b/RgSeOڞ[oS ]Tc2Rn NW8\P;.v>x q/wƨi=N x7ÑEЈZa9m%\Z`5H"4 Ȥ"β4Jg̚gD)p|\<4CK1G}B4^rZB\2Æ r"EFaXῺ (_nnu㥦 \Q-A4+Fh[c1՚˄~ y`< J8ݾ-d&nK[\:CXa׃hqU,RNPMN!##-ix'æƙ; 1"|1V"Aԇ]w|B^SE㻝Ăɸ#]`{L*mqpe3Hw!0Ƙ%웟UoyLn3΃` e R Њ04%+]?EwʻȔIZ؍jP,x7L04$;c7} _9?)Si{y@l&nbX*@IPBu|ϡ}?qYn4Pn0IMdl(o2ISZQtɯA7-3g5+1j4o~VGIw$ÌtoէJ t[Wﰡr0$M$~Z_fMIsB(u&1=8$'35 Ǝ=\ B#:F,[küJrz;eiY%)J>n5=t@}c #(ܫѭŰ,nmyS"y]E;0!P5J[=꽔ML/ -!Rdɴ WK.?Nt B!iWr+gJZJŋAL5gαw GR=4;2w\~8'xCq;0ږ= +A*aKo% x3G[QaYGqDXyRCD*X|BUV"5Q hޤv(ʱH\678Q7z[c x(Pnz )1 C*XY WH@[Ȧ \<yV匊B$p-a=w Q9P ,6 &*3vMu$8!fɇÕGGqo'C1zb.]DQ>t^Avqt &\aVB(|CMG }d9³ }1KHs;?J'Bl[7ο:0 X[.g#Pfgc]荂'TH]<qH`}9c$<t0Hqp4Gd+D:%zZ9='Z!VnI`9ֈA} ÷')ѡ)ˉ@_e ":)߸0]]iaYIVpmCRP*hWÄ2I1d ةHGƝ:ݢ10 WH"Ju V>E՚>,x({CN[Oc$9}G؆h EI)FaHT8o[^qh/'W5ma55s lmB9L ` $WKd̪إ5l~K~v@H-. dj k+ \2X, =@=dIi.qٶFel$$3pۻuR:(e3ofqU"0)+a<~8xUz7=IKJ-c}ʖ2Ό q-0uRCnWJ c)$l'V 0;щV-I4_,(bd>qQW1mW0WBvh JP"OkK-8o?) -Yo/z G{2"2T9ӑ[czW]1P]OȪ\PpD TDB4sUP=p*qRCDZ󴀊؍J,0RДE5|4Jr$P(V6۳1LaW-c->ޕrP6v]?jkJb|ݘnv} TYք4H5(b)=' B'4?S\Z%539hd<ZM 2{1 ?P3 J_Vɘ.`f>LWQl o++BL;˓m,Z(]:Xz^Ms$d ÕUz fMڼoc)s8KSc:Q;BxE&*}:&#ҟdu6xD-ҡe]'w \Y*a.aiP zKc/ƀ63<.aҳq Z6 -JY=gb;BF˛aec޸݄ P.p{ۦd+^Vlk)ӌ%2)0BIy,o+|8wwebdp>)A.PvoEQ>6Z*sW=ɪ1Xi3* PLՙ yzD.|e:F%r0ZD]{'y&f8bp召p?BVT.nt = mv`8{ IO11TF" T>JlB}IF__<*/#¶=kpIP-s7ka8`[32e2Pe< fgZ:։Rr] \>=udL>#˪%` 1rli'b␔@sVԌQךiɤ:βX=QidOngVnK_&clV<y}h!o#yɁ2Ki`k﹩~ PRߙS}jYF/ܴLZ Q",NsN=y2u鼆*Eض.Hc3zWq!1թ6y9wSFKY?,D#ZbaDv]c8@ؼH%P68 RzeFۭ"ϤbfUfG꜉ɚM6c*3 > .p) dir:T[^]^5G R!.;[vv뛥U9V2i];O+b|~Q\h\ע-pVﶂ"u|s:0G1qA /*3Q4o KW(Tj!>MR$ck;>Fn.z~)"$k9'T141*X y2XJ妇#'. Bf##ƷwRxl6Qȝ< aJӣ{eKJ ͨXdhpPgne[+?OM hh=oAxi 7V :\z 3bV9r u?̪L-xmfwl%:(m>$=o>h؍N F(R`%v ` CZ#S*6uR0ps .W^☻dt<8 U <KbIˋ?NRlvh ȥ}=y`8 MPAA<31'_X`_SҚ@*y +r~g:gF-%epDd6_t74? 6ֽs Z;NJ! Ŏ<ڈdsU..*01\1^F@ ފesRE2nSt vņQi{Ph6rOnd!0/z& ",@5|dUh7ju+2Z@.פ3 0n3e?73B E?w{( ?x B{wW7a( cn1{pyG|z)R7@zFb#[ib^Q\M}K'-J0_&?`J'~ޭ2ktZ.m:Mm7i۟2$z~Ɨ*f/ajmXأ!6K$]#M04 &D:Ea?ښn?6Ԋ$iLFz;I8uV+ l#Ic- #EVt-`Fyf^mV^p 'm|ȼ{Uc2 7c 8z 5"zӧn:hX0\UPjQaxE;4_D[ux pf$SLe)IB"c[N FtIG 8GlUxN`bB./#żv4# Hlµԋ]xr'G[dyB?=S6?—\#MrgZHQnEOI2uSZ[Y Y*xxII"XDdm@$"!/m$lBݰc"]+3 8) ^{+fb~jEvnϕ ӽ\(J H#v+ls9_(ynG_W(r[Ô,R4t5lP_ՙY/ؑ8Ezgډ9mUcS=jZ ܬVDa#E.ҝ OOcBjl}K 冸)d15BO[zkQ&wO`ӫ;ZQGzx1 OP\2sn?|ȁMSҀrl(eB Vsu d V"ydWw9|&]d8?8_0WWyފ36 ,P i˟1ض&iUMoešhK~=|.Z6:mIibA1~)OfL&2&$>Gp(:߲/jsu:#+lߗ\ S OI'_lR1ۅ.8dx)Du;Eႅ ]ch,t>/'0ׇUĒ( {3'r%܈d-wh7=Gn9`!?rAGqBiUSߒ11 ~13SE v!鿣 \;~IUU$2't3ZƖi:DHZ~f9nM;@W-Ǝ'V9/Y}HWs;>iY9*L&iuNw 2R砫 X{jD1^( z:OLa %ѮeZu:dqC&Gf03>C}<:g7xp҇nH9>zq?q J[g4jxaj}Eʭo7 $#޴*xԘ'f旮2~؍ɷ>Έ@ Àemǁv(0͂Ey/ʣS)IF}֗w_]ja8Î`iV'|]Xj~./k9e\D ']Z0,ĮRfy@&H[WF=&@0wpAB/ۛ") "ֺ9 -ȋ.m~\<(\H:.E蠬$V5".qBfJVZhKS yWTҮW᳥h> Jb%=Oރ+v&cDE;2$5ǺO Bn9u[=j6-k5f8bHt9\by&<ݚ,LZrPZ+#FcS;1iɾ`ʔqqˀO 2Xŏg3ɕE)NOeiԓXϏ!C[];foFYfG䘹i\J*lֲ#ag $7`RB%̪3Ruc^V;j\W^vC@K^VZB]9faK;a\So*^ɡ>ӧu 1XœeӒ5n3\E·nJI+*VW_y3V {,rAl6hé҆Ժ\UÙy.#F.c+Jsf*g,[B :sv_vQ|Z4L)a<}YFɢаA?{r=˗݉<J<`~d0mFܕt/#*$ʻwוD: >uyk[n!*Xʅň`g{,,G` x{R~orߌ3ksz3zwI9jDF/|fdM>Zzǧ^흝RL d08~m"K̴xpRqfd<L=cAM$@&8 0j<8jw06ұhY򝮑1*x !lsӊ5{*GV:7 5v8 7fx]Ć ugӼTnq[CVrC/jqu(mO ^ cսnlY?p!4Z.%X/n'M5LkjNzsXĎ*lBvt^ G],hr<ib~Y05ߪS$ 1"4gJʝaE[*(<wAa|b$047Jĝuo'T_i:7E]sGLiLm?x긖Gܐ8tD(uXGyLu{h7@:‰ց[\D/ ҕsJ @\{{u_l\l*nqo^N=jҏnp,l`L+E_3;!cPcݭWxJ @ #efcNym{^o[pym5v0?fqH͞SoĴ@-)ȕQ,;.6!h!N L-/H6aGH ӳ!͕7d}) qZ4S_⧝# Ok#+sٿP|>x*^SOfJ:OA$瓼S斛|!t&.,7gX k=a.RO&M#*5Y]TECŐU|pLqiZ~׾n$J9njeU0G2a"w~8D}׽}.׀b,[SWOQEߠAY.ʊߠƘdOGkXw>B_h ̚|1JF~Hg#&EdPT5|c댤[l&i3+u]X~ZPr",e D],Ҫ'CsQ5pN SaJ 2GiAaMm2Lp6rhJ>9+3qc:ϋdIIOӰxbX. \6[zugw MWM:  S4\"LT=Ot N0$:iJBA|!֐93 "'c<\'вhn,XZ8>LZ |fޜLj. )A(Âڋm$A)!ɩyr=:Fox"6y*[]w= ;ҧtDVQ|cb'Hn{8'˗]!d.cZHqc 9T4QLW=J<l7*)b4ى>TswWhB񓊌uc 'Lb#Ke E߼5yYAKER$j N&Pd+jtN_|[q h"iZԠຢwt?Җ-I#f@l|\4ArZ,Q۩*kRSXis`Q,u!&|O,دxp sWW#~Ѝ4/^2 ʼPލٚKw+0{;v pe#DCI^'?]hg N* ݟ}MSͧn#smE+ӦЎz╮ +9T Fb[ct8 ;`e㹗S-KPO}NH|YbP`Fe}RaVII*F]ھ'VlUcnשO}ATۢӗRC3&|03>\5EN\2OrMہ %^ S.6.&tđblRuw(`XCj @mroWSF5/uG违ْ}ϺIENlC[`"5\ڒ0[B=˅vEA9FLM9 G+Ixbw;HQTtF{icszUE8VNZh L}5[nvΗHv1տ-;wdtP/#D}'#zJ+abOFw}LyL?훟BGmڶ;"a5%kiWLKH{RVtæFӍZ"5aK5_Bz0ӨȾϬ,y+R/3e4sguba!W7Z[71FWs{DV78i%>Ø7y7_)}~;XD '+F< _ٻ*ʠ ,HiqFJlT]6e?V8KJx0XJDek%h*h5b$SoR:ef*egDRxjg\E+Y߭1vQ֖/tcipxb2DY|9X*bDfG`$2 ]V=@χ<@+{Qx?E!+_ǽ.hɪ$Dio5.QY8^kvc/MԱ\s_)vZPn/7D#5: |$@@AȡZ{ccw뎟*=E0V9;K6>lDzdq7d.;jz} CVyda臇|ǼmYoj+ȃ*GrL }&3^}HsgfpSH{r} %{f2`ʇ#Xqy:9o3yJٝ00 y\ZTK O휓N~.QKPA13|DwXc3Њ9\v:Z@"8ɕ?B; m:mEz2޽CiH֜E^ :O;}_*zkC= *71r\׋ V]]7#Z]T6'oP[DYmVb! f_NnpnO0 dj0T$>HdIؘ1b8e:Y:s:u$~L*?5翠E0)B C!mum9Aֶ{=0umU?]T# '_$eH-UKS> 㣊]4{!\~" akCE6]>9lY/g+<|K >8-Wp'eEJ9Rg&/k{fxƒjv=ak"ȅ+`l|ۦu=|YSNG`~/ݳ cP *vs^I" R,s( QbLq>_lzL9cCф/LceN`mǀ m V6'FE bx8VyR= 1Pu"a`{P?jjz p^~~uoL͊y* b5%ʡ{6R\m)b&J<| RT0 t}~!Ҏ_j1HE32E:콉́uoaAInAIYt3\Liўz~L*KG6J4rF]mrԻg&f!;L`PyMZBju_ iQ|57g5`jtP~߶{2%u~{~ ôf&` sQ811pƴc60&,OQ- V&&F݉U ` e@zi(EɗQXfy5Yǐ-{ ˼/m)jgy~"A ]/ Z 2 tEY,4Hwxk&JgHq{^JՀ6 40A1 hU:b?CP˪L&}9#.P|ͬ/'[7̼iw(/.;/)u2|gTjƪLi6AKShR)v74Z;F=ֹ0 1݂V`?~s`P?Dȧ|^ci ~ B޿lʘZ] t@ bsl*6!y:pFrdo25W0ܩx,y(cTY9{KI ˭D,T̫XF$5L0mˏ"@9e!`h*>itMoICꞳ@C4M+MP{{i'JtݨPNz /#wHCZX2?$^?׹^zS>(`x *\Rȶ4z>H1? I^;zo8r@8A=- ,9\U"O 嬏{KPW$`e{BPI2U?[< ]+F+Ѥ'n@*,ߞj&GgQY1ɴcsYEfmF&&(tOif-Qv˽ ƒ1LJrڬ$zdPn~S'/wbZTe [8z~Q%׭O1,q̡ uD啴 >X<=r^.q.ٰ_ḍ7028w8n]48ô|q|{y$;V.:!:@ͧ#&9؇i$3C[:).;:[ i?~W?vy}d&8ɴ?'KF;A5ti[opBa ME>*‰Z^"ٸz%}p|IYK X `;̀_4 IM6zF`6@ipx(ՆFRQv׊ċ.e tRWԏ98]oDw$wb>ΫJ0X=jB_{bJc,:;$!b{acR`rC\e+dCmŢdY٤BkHZAшzpt5ܾ3ڢ řeZ DALǻ&ok2;?&̽W&J[. }ZӴ:d.km4cWn-^t*%Hh`g{. ] +-+x߯fz !OԲijTrv.|b9B.2]21~ЯiJ6]5N;hi<].5~$bbG!\7Hop΀<5aufbw+@(%ODZE;T"U0#f1+6W":̬4i;2<$]gGZ`|h7֐j\+$>̙rՁC4ƧȟL?f$#ŌҰ:qw/@O+QMLOHMo ˂6|2`ܼ]YOFuJXCO -!TUjr,[d)/82,]xaJ|Z=@2ԕ1 wT8$G0;0l+5V:(NS2@YT;BF|LK9ՇG`E&t*wo*2pުa5+ miqm"re㓍ط֡$Vޞ;R6$]X6>|&y۶Z>쁪D[zZ-46Qn8zN-߂E iu)&J)LPqy1{5 )#"ͿxTW-<[l%=5VVNyQnYZ:+7䖋[>2D/k#^T")|/!N%>F FSOa|~:&84ٍ^bQ5QT_Sa>*:e6o+& H06u\)Ӓ~rq.QvYNLߍRoFXCޢ]}/ϣxH?e)J+F煖\v/sGSk}Ut(QJn7 u ?ScM}2`E '1~O hK%vR#]C_#M}i(m!G@t,Sx/mSP8CUVT;LhBL6'!@0.3RU h!p{)(J\Ǧ !K QI 6zAOϢ\z%~D3{43|mۂ gcp4 TcA#'OU05ytVgM%`5PhX# Ջ\Zdaڪ0c{Z_9WV$ٶ26Zu;\LMOP"8 _ԃ\F%dqnMxڹpcKwٮY}_צ:d /֬ {u- QޕG0mdN9W2~ۋ|fYդ!K{^_LЗy' $<슒cCĻ+l?bFf/mu #Oz5ou}!:;rc>;rWfO%I #Ќ]*C3U07YS&E*8`ksMi H'^L$_ZŜxPg9y-e28T|QVS!Fk=s1o`ݛ)g-tdCLfSeckO}Տ (^<\m^\"C›X^gBn t騄I%>M`w^r VV%oU!eh J2gG^x3Vxɯ| ;Larm:,P)b(cLcranvT[.|H84,T0vo&}Q3g`E^ȣ1CRf-e)pk%)<̄Xr)M)O@)olR&?W5 a(Q7@ 6I'o9Ax2'H\Bv>rJ0WBe7ƒX^赭/sJ`֞H+UO7*dmw#A\F=wN!(IG?eC>lQef(JKȨ5B?4#F0'Hioc4rsK`G k_%_;.6Pg#+@{9~&d45EzjNN&5Moݝr<A-ߧյGV;ޞV6DꍜHi|Ǧ7%A#X *gqYص8~g$Dija{wC?Vl7@9hh hcWID<*rGsAyt2@8$s72o$y7>A6]"W[aPq5f&norpWNbSQ/ sNhE{\cxy%-F4duG{ `=v%_#,cNc3ft* .ЙAd;7 w%+9Ah*k2M/Ys3?YSw+RNFBygnBJ}N;j\! dVEݵ"NzbYTރyF6ѱh%h>>WV/ x$KF#/wܜ@yYJYl;t1Z7,7s10ؐgi_͌.-5;g\t_>rK+a;cr52bF<]&<ᪧ(:5Q-7"P)x^àe46iu)#>So@lֱM 9)I@Yj3!H$Y_uxN=.{$/a``p?ϐ44-J9Nh"ٟP_sӾYw1l‘[O\=(N)/ ?zgEV6E9aAwa}E?K iI_Ip +\v )8jBOmHSsy,)5*lLt@8JΨuWô:M}Gjh I{A) 9_%0cIPxZa V_ԮQh/Fh(-uѢ1P,(6H w]WCZ&8ʢ9ZIA B @Ҏ VF:=t\v/]=]XGLq?l gn u<:0 qgD~<٥^w UJ|!VcBjj}mr,!Z#i`wG6hr5&RqN#ƽ52sDQ9yLˊ۸8ڜ4 Ir\heO.&@'&=JzvRdkF8)=G|\J []¾L?uE(gv;]>S:j53= [EKY_O{k 6Ucc{Cd>vv5ވdyv搼)+&;Blkzp~u~Rw3hƦ8Gz5sebh(GObuOh,e69 y2eƸTGxVȒh*PmԆAniT9 jE{d}U&؍PSì9nZE곚JKcWwJeZ'=6FqS2_#ݙ!3\5tU.3أ`0ƄiO"^tNLJ{o NBLEQLJGGUwWBȕq~~{F !}+gx2z1\isъ(V\,XwJZE{]fGMW=HjUtkz"햢 4 oL,I)[#~y JrA7!U#alV?gK;u{8ʾlXUCmo#Lu,X[No9YIFC3D&-ip Sl~# I/ /ZA {`eU {&fQ"z⺎T %3DSi:MْcK4#n2+Um>sCr԰?z+tP iP(V?n8/NGnIJ*U<"<ʻMcٺp69I[i#f]y84 {G&~fzdQӞ|ZDqsʑ,yU~M5^}!`9+9S:nPYwl~!u GFɷD?!y+Z%s6i߭1wrAV#i_Bè$w2|gW/'x3|/3%OS6TǪvfzգ>x y]fۇ@mg8BdWoPC̱5XdbĪRji>gUSҢ,u7&X눸.|<脎b%% o>9]\#|^xa*bmGlz!3&}!dm.?2 X}*ƚT.]/k.(dms!0H ÿ__̿=zŐ٬-Mշ(xtom LJE6 &W-Rv6!O$';PŠא cDغkI` J[m{yЁҘC%[f۝GȹnNU{0,qc BE?nuq(/LF&<.x4D,^ȚӜzJ(_ wjwzVL5R]řK|U{͕oo@-6 yD7ƜcĞLϳ3#}o#@=UXCZүgtiQ So"7RLxpSگ9}qNT~ tINVUiusnbV/R9+买qYD`ɗ9LhFۖSkŮI>cz$a >LfeJ8MjZWxe䇳k\`VƸ,X4}T(!I[BE% d9 H]gGv 2UbX"n1[sRbb?c|/*L;`q3}|-1kRџRV#k/0bGp7/C];9^ %sS+ psZLv*/5Y@V1Jk?Io£ܛhnHPE\"X с9 G<޼p7O~#&v? Pxl 0<[C `sf0,dQHJEґsPDӬ!L_%P⻊sy0/޼-w2!&2ESk~zXOj7ooFW%:@LUYZV0Q֘x$_m˦aR72nxwA-ByyFPgJ f/( =]˧(-Z…kZ,9PXOeuhS uh=rMiwޫigqҶѢu~9I`ws'HE6C0BDbBܔZ_ SD4`LltP 2=.MF j3 [!)r}M{xTYQ}n!x 5C% @׿"1 x-Ҳ+UpO=fFf A׳Eg͒ګ-eB`n|&eP'.VWwКFSmjQ/^~.ا7Xazzv [ފ}\ïMp% .Fz0hzY)T:7*gwmWu^5 fMUP^mqdoUh u)-+ЂδY'mЄ.:7+Vn 2;3_jw*kX/]hݢHآ9祍S>Mb#{s)[}9 U*oqb׍=;&yqF(QkBw $|<EjF,Ի8 :%4ev3=:6!k'Ze&5!j6uoK FMPlpicTsdS0 unkR)rpM|^Y @lhp!g$$O܃qγ6M|JT8ȬwK###մ7a&Z=[$n\V*`6 @)E|1(cک~po ]d:b( {6G-dQ;J2of.jzQ-*ͯ7۷A89}Y]uiΰ?n+Zz; ,^1x$C5 Wɩqa_;BwOd2O1;\!`xDӞ T{?hax'fȗ8cכZ8\ʯ%r@ (|dawnEBah\YA4|D{aA.;_՟Yg X;{FԆE>jHw<.ʤ|)(=U @bޓ};+j!u.!Sـ7EV~Zぎiޜ[BvXjv"4%M7`K\4Bgʱ(,*DPD >ḷFBfBTHrJG]%?+J ȑv>s\,}lC*p6E[*w Zr1D^A=X$7W#ei: 8QPM2M9C>Z'H=i%[[/l^κ6hQ67U3 -`oD:8%mׁTӭ *N˖k])w)iNīu{>f5ߔG+KngM pEQmAtW}(*Y!}'^  73f"뢉ѺJw.YX~ME~dಿ#񏸵 .ʯƢ!.)]1FGpI@@5X? +܄^5y&#W <ЫZI0g'3S{.jk)Qy1A-Qt#9[{l jI)Bkmr{k*u yMBJ|aݱ(#RJ;'Xުp)ҋx`Orޞ *%|.*DÁy o sq+e~2XVkh YN9]ҢӈƯp,U76dr >؋=Pfju" ?Q3lEnj#:iiKnhUH~0&4I1t%m$k2A|=yD"7.g! I]sʂECh1jhi݈sgn!,q{`xyQA<:A|]SĜ(yrD ҖMhD![*3m;H?d!#! R"sG RY_ܜ 3qZ;Yqp3f] z2O93_Fmu%{ē`#e!67>YGlIJ q">JB o0xQ;?"5!8WmL]ɺXG85[a]&;|1z[&;2t}ٌ3ЅtwmRb?ʳ#]Ϻ|Efthql&4r4[ F*u`mH" Ыt˒P 4#D|ThD2✀ mçJmFB2Br$6ב欅" c _ϐ׈ }_Ujl)+Ub*+iCRiuވe"cWWeX׹lxgt0dvy\JJֻ+7=V8HqwɆ.AhKԙ?ù:x| 39ꎐpSB;je06ނCVX[\ vɻd<~$+F71#FгȩҴؠlEw[w R)<m}Fd2 |xRUفZ OKuʭSҳx|M5^"A3K߅[fao%CN:vbo#N%;ˊN}'&g&8n$[jYt8_޼/"uH{KRXܞ':EO][ aCʍm „i` {F¼= 8%:b54q&Nd7DXEa([H"vtǀ/F?CqplmCW b]Θ¼`*{`X}kE%uû oҸ́n0K^?:DɎg}a%X+pwLZ,\!Vnɓ;9(gle&. ;B>ޤ3{`Fr1*AY^A"ïC%^v]iyj4@Ů!  I-{A@;i r}{Z诬ҋe&oOB&H4ޫϬģP2QŌ-T)dMV"r`of>⅓5W!qCvB\ۏ7sGD]ZjA 1Hle|dҢz5;3eA~\y}hz:m5l:_t{=d'F sgu58EODGԷ2PrvGdFȗg)gbj1{P(+ND&{r` }~n+9fD_})e„-hx9\-O?= =S G?|8\ETbѴ! "?N Juy\-sp'?%ewhbTc.o>S:!𪴋_%F>% 'X06%H5 Qs2<0[f[~%S-NDd=8#n\Ͱx8 r1t`&g ۋ3 0oc4qS)FƁ~5WORA;]j^p%[$v‡zgqi.֐3/k;n 8_iB;vb=i4 X6/=|Z,  ]rP:XmT}͝^.I@Sh`4AffAJM\\߭)Y혅szI^X| V'֫p,2JkW˺}u\)Vҧ_aXeFsװ^CPYn0f>':5)_ 0r.>*eB:;OjӊXC@yvYaŗUCFc-̇W[5I>>a2ݾ/Y$ٛuEKV-% MA麀eCv*H:\p wZ1e-#6Hoƈ~4NUr:"$ts aGe5ܮࡢޘ.%E\]?׵J`A 0gif?z0RqYu_2rWzL\ڝ PQSe4884^^_X>{ٓh_F wll,ċ4u tϘTv)/+ 'W,$^%J>r'rSSYPDb*DVmĭ%BXމ(c_垪;˵;N=K,] Mm"0*yl{`iܤ*@})zծW[/6$*somuQtFrډM1BqI5Pq{(0q}x(<`'*d }63r7\Ό˪IfڮEPqըrl [Ɨ*Yf+jƙUWNA[ .>52ݥġ4Os>/Di!'vT0˖įR8TY_àXx,z?_^IҧA*` 5{&VN>SP&z)Ró>.*Vttg͸:V nuۡg3ݤjtPN-gٷ#J@VUSC?] !zriO~:7h%tlI4Ƒ ڶ{w/Գ:0A.hJp5ڻT ^Б<\9`Cgx./21§!ΖBϲS֝bp5 U6#"eVr4h: I8yEu]R `팖vYr ]uށB61hŝFNIBy:H}ݐOHƼO}0eE:ڃK|;g:|:"y\:>4?P d9:#iCEW*il<ބ= }F'>,h P ~`YL7&5 0(('9OA9j!Msb^xدjFP2͙k@5`˧>ڀL"vQ#') ?&_H޿.p%$`w} 7btlВ*\uyǀC0g DXdן4ݻWxOP\UMD7K]q`8Qk=s=f5M+kUī/LuաA[ ›"˵RYیN0Z3br,@΀=Qۼ6 6>yVue Z`jTZ>y1mAn/ IF&ja/AX9KcYn Dx.qbXm %SZ8b2qmIk6kG1e9"}]4R;B ~3X-^!"]I*gH E`7?REq]v|8o\s兦+lU'8&;KM;x9)>(& ,H3{ FyLH|"%UK߃4 <:mi/_%I"./Iy|{>ܲK8Fwe|˟(/PP ^o2(t2.H(JfC+A2Gyu\"kMuo!AGNpb/s5V/; Gnzֿ'VmB4kvu. Z)p81X}h7`_,򦎧DqaNSζ'O(deC g>+֚NXmFJ=31dfcg:žB'\QDqL(¹lgLO3s}8+~*u&K&)א4Cd9L!tC-hJij0sԃ|to.;xQf7]RSGBlDŽChpKl餯P91h[}G$1['D*jSgiߑfr#{8Foi d~xpڊ榨t^LllLNe;gY?&%d ︆iVftB9~mԫ56/-KZfjO:?X+>0[' ;M؟=Xd[hbpM)e:]?8Ҋ3- O&1ao -+ɨdebY<<,(:pU[Y^R68`X $J2L"4tHJhD{WrE<`p=9Ju9QpuG~Hf8Zv\*\H4P$E,3̥(u uP<8A-BzSSfA 9M=N=Cs( ^5asVH-ˑܐdwB3u0uP4Z=U&;G=sXQ4hN4 IIgJLG `$4m0;2)͇'fWQir:6q, #c7RI;r%B>7Ì0 5bL,E :rڹ&23BiH%[#S˖%S~ sX+~} )% d(~P0}|j< ]&wk֯(dڜs }1>嘄D3J~(Og?fVbqiI`f8 v T/_A"`~8-PSOQVL{+W \XpgM#w=i#+.h4O#>^d|U }mY{vHo<ް-`ޤ._N0#wi.˜H +̑BK ?R >G@ғ "r|⋤ǃBN5D,/,3րŪi)[̈*sWZ?$]Tz(x4iT~ $\ʣᖐ4(W(䮕7/"ȍIU "ǶfA v$_3NE?P(`*1_!`Y)(di T9l@H`~ {`EٷJܝ=yd+ogc1KSoaQ[>kg}XB<:?xKLm:i3̠VPϪpKVy3oJ5F@Ѿ@ 9\o%xm:J l%ExBO' 7lNJv E)CՠCPFz-f"'6i+9)`*̨#f 9Ϭ' (&?)]]i^}r4ץqViᤘbוd9dqdD[ ڥZ'c jPZH rPL MH)U~Es鑄rQ0rrFw]У1ddGc^aGE,21YLp>gQ{T_'C$ κ#& #k/H^/3NW uaoPfE 6J/KՌ%Ncr$OM[=l'{[{vko=I{rq 0*<_$[$CAï|k @Hji;*AM!к'!J80VqO2]طìk_}KT12#/T+%RX$]:ލ"X:)=Z ,PPpq *mTx@g8 lrqO>Le/0Yy{WrfXۺ!qBC} 0zBZO{e;$o#Րpf=T(= gAHo.s;&i-$> 7Z1GaҹAVq(6T}! Zz#q*[LmXɣ5T2|Q])i3ot5"{>yǨt\mתžvc6%wī*~,[)c\G^p 8IYtP"~ ˜@/@s9*C"j}c=67'zäˋoW$O mˀ ?.nkUx!V׷$;%߇s,aSQ2'5KmkF5^7wZZ pmTZQ >9w-&5xNW2-Rx@}9;0"@S}suAgKnu|5 ioP W@"h6g}1L\Iu~^Y c۴-,WL-WXKsjTÙ}`l;+-#!˼` w*FP}j60&ME$ =>WY˽ `> o$チك֏0#-.sQ15D6tZG14j@Cse4q" T W[flRf0W_S+$K,^(jN.p1I x"w!RML85fR]]\Г9ԶE<2F[}-E:v@Z ̳Qk˃pC+KOjTov}k |J܅;˽ٷigg_76Q>*zt4LB;~Yj2QBckGdjk-! Ce&"[ ^-b\^Upg9t9Hj-^b<UdLy8c} f4uYĂPieY=GVp8**EYaޙՄ,Kj@Qa-VE%u?g鬙Bؙ3 1zhH}TڒPF?e'P\65DF>b@h_4\ eu #b+D&O-rel[F F#gO`Ǵ޸mbdfFUe3F#%pݿ0F_: '骩[8i'q[T|3)}_pޛw=~O8Ql`8<Lk8W 5RQJ^E-Uref5ɥѯveWsqڦ$? b<\Kg_*;찤_645׀z%]o]Es푧.#s}?y3>0M~{a,%D@S[Q3*Nog2@a@ذNt'RbCŢ7<>M}Jsaڕv7sUO2t30Ax'E 3E#L3\ߟPKVXԀfކ%4./2pl7Edzz=@&h)Ixb.d;ϱ\`?EGٮg6C1 yNLǑfmȽu3]NQ)De}H4oY s"#kŨ_ IET%5g ʷV;c}v&B Dn>|o`ugC"zjh 71Q%"f Z!m勚#A(hG+Ip,?EB;'C"OQ%pext(밽1=L 1rO&k 3ϲk>͌蝏Uvzc8@8T!WLrPCIϦ Mk vtvzT'ĖZ)TMj숶 lۦ3vFZ]KyzaӍ|]-69kQ]b3W#Oǝfv;JٔN\ˑ)}QG4h996dpGw鍂!zXQ^z6$%)0~2UmGH͡{ƸMCV7i@`qsn% k-\ G]|3g!*&\ h?hqSoBuԬm|ċhOJC{۩9Ze6PG&g|;xkP;.~d-nlm}w֭l$k~j?)SM'BL,S!0֘9u*7TZOm mpXA#" q I#̩7>r'SREl(z3yGd_sҍt!A*)qD:5iy׆FfJݭ25~H8pߛ ]o%Cu@8VG`#{N*h2M(osGa"PWW,S['35 {?>k!/Gv2=9sZ,19;hDŽՃYO^8VsY"H鲣}58r}P!ed旛KsH6`)/ӎxQ$l ;cl/ [:wF(Zp9}:˨2CPŕ/gV HK}oȣmҡ_kL]!M(w%q5NI5D^Z e։>ZWì*2{e%!M‡r)nD7rET[x< βl [BAMY_<+BPy~-o-D~ЁtxYttfG%Dl-1UbE=5n,ԛ֫TM/`ۄ\=̺L^w˃NMk850M[t 0{TBLV!JSLcJ(Ǝ^jg8ěg _⠥4hFB#j9*ːh2>v V3PAh֏g&0NFF ]a\2bmJ (#}Y;]}H%!Bpwi%=Nѕeu*KRW{:y]g=)* yLw:Hd7QZ?|粶*}odpo]~HA֐*yP@|2{EFZ[ NzE\LN`ba7,L_H") LJ Wɏ} 4l!U?^`Ժ3>{& S@*S^xy\1>h, &+q2Sd8i8nֽMv*=ׂWGKހ\ ߡ+VEϰD-g(YEc})G4SA6-*~2RUxo.G#_Yf[ei -,Q Uz{Ԥ#+`qc2fF :eVb~K'#檥R3ݘinxDoIj 8`1qcx"hE<&!$!jW6bvE,,w!q};[CR%#HS^Iq\ZxQPHs oZH"T_ Es0*'ǖ,bg;\"Rޥ#AVFp|!4|9]OVQ|:m/-ne+y`2ܮˋ.DAa<ҊMSWAJsFVݍ` %^ۘuʓ/ňi`?F<+?;r4/rz˷Qxޫ=$wS.2͎M>3;}Bd+bjQx_&x)/a\i mg9Ӊgz@{Df>I6c/R-AKƂۚe'1Ou` -N;^@!|bD2z@^DAu)2gS|&w qNI?rM;W|&AGuzT8;!gXQ`xX ~ A.S㇁=҄QJ5X܋hCrܝE| <&_̅o',啩_$V2%/rS*n$vR(DX .k9J*2ASaf>[Z*>g qZd\Q7%w6=ހ⎏xYq걟DL W&tFL\*ҝۈ,uy ДKHDl*/I׵buRϻ,<ϔ˽;=|g݈'`-Csw$x| ]BxX8I ,rK,_ÇzğT)HϠA1)Dk#/f8`9qZwCYEА6rezW !=[jla VrB7ݎHс4_'EB:,,xfƆJIe*#'%}UsgM860Ŷb|% +V6ZC"ysYi[e'(g.bMq"{Cϼ`aCEҽ4 6 bCZXVQ' OҦ } FWOI4sVbcSI7"MRvΗO !:c,_Ew[ EJ[ Ҳ6?gpAz=Qz'MLfvv|6N~ZP`h@4}ˡmgyzc[/@̶=^;GHӹM^n LA=LhUw!Oyl'! 4 ߯4w~p|=DYd^)vIˎ'w`BG!RV7 I\r_|-9LEH|-9D ='H6o0*g 3wPslI۱jrW$ZPY[2 Z20>;SL+vq/r%:l<fDf[|!ޘݾ= gӨ+ٕ$(oz,"$T$ky"E y':3`n4&K|(9™Jk,ѿAʫDOGQv&>9e| n`c\JP\s6SpTxfWDꤒ,,2dEwIj3]׈6rbևuFkmzՂ5VCI$R&/Oj ePKGi;ϜHb%0E}_^Jkn+p2S5/Ҟ;C%i l:lVx1n0hcڄ _TLyʀO'kjҋ8WZ4&W@8 9)-1SUo@eߣfDi9sʈDR^]l=x|~NH!YRS;%cw;rs&a  ߈v":;wz6=R3CE˗>0_L.gircAm8Of=ՄXH]|BTv67E7Lh#[\:jM23L~/)zt2S7h-Ԟc jmNJ-n.F.ӳ GFߊ2ҞgtGЕg4W̘JO3zf |4tpS, .tq\jح1a{/ Q  4D4@6_ KUL3[U˝T9FnxaG]ڴ$٦#a-+;hM5PN%?wvu!"o= ,4ɢ+ |శ50Mn _KP4q] Dd,R +Sґ@ eo@άOsNMCJ{'R:‚L8M.4+Ker0$qsp:qrD|QZyݛ.nNiُi]Vy ٦]$~/$ òT ihnc╚炵iNͩB"5DiB Sv bSן䏌h xc*T1j{\J..{؞ q-f8 6CR/teeO&*2 <jC A~0wc$Z)ʱK(e.w,5"(1녫'^Ɔ$L l/?-ǽ:GGZ.DyrxIA:FgE5:rX##&Kl5)͎"U[9.QEpB]VN먿OW}6wܯGHR .zfD z3o]88HJN~Y;5 #N:3 o+,}F6×(X1VN()2&C^0掵NѳK*ov˶KvX0QiPQar42bZ IPrOΤzo#31GDwvC!!+d`ɬ!Wt-cMTc1)naڕ MQyfקw;v֧ibUkKhWLD~&*!g2SD)ٞ@t{m "8MM"7}4 t\9IF@9:7!ִ D|̍)JTz>uŎ/V eV.ovp\DD|&Zڱ=JiD jHeD%%[+Ԟ>p(h;;d]7g|[憡M;Ltڵ`(q[*KBμ4dÎ_P|T)e:19߫AQ<6}9前XBG4{rA ylTjiZ@lk۝%}U_@{4$JqQd7;I-&xpگE+ B 1 c,lSY][ (Ft^+BWJǵIZ#%(/߶-ͦt,l%኷!=QC])(?q@ZU6 S#\•jɠ9Jh>=~ +yoRoRƀ)BdD] cӅ4 Lbz[D-hrMZ5_Ǫ9H3 Ȋ!x wah65]^" |L}h^ZCϭh"ADS8E9o,9Γ9vY߳+iʺO;_쯨D>qǦ;.i?k\ t |6ޏqdDZN 'u[.p[C< +#4ujEQlaWuoMK!6{K<0ZŨ؛p&f idHi %ߨ1x'G-wȆYE>^GG)jlE7OqZJ"DʿIFTV$g]ףq'+ض [6Lm h1TibzY jXC^yZFK b.Z0 hi␗&|.}7K9 }iKyѝ[}dKζ@Is͌,*TEܹ+dʿ޿`Td {&NetŦT0!mp:e;}0PZ$OO+k3rUbj87p$D ᤈquJy' v`yQ +%:gSڞJK5k-qmg -8+qjl˲Ư$N}fuz#b U 4QhH6?О9:P7BJNlQǶň<1a櫽>M.Z{Rd$;}k{1#Go .T˚QmkIpKtXv3:URbUCCoPFPS7~dBg椝/4dO,"_9PN=E"Tڋ?7ђYft[-7W[`Zϔ,`L$ׂS95]4ahM"\%6dn.<Λ֍D]R5KQc:)ύJ ,VeP&p39 Ֆ݃7Je۟Q*Јzt,gm/1jM)gopZ|ۥ/Nadvgw}nѐqaNr!"ZT3Bc.ϗO۞sYKw3~aj2I5cN}`i.0}K},ZܞQFM4ۃTEAFN'S*+*¥4\ݏxHd=9-34 ~5S @p%&;R2;$e 5",J$'~ie ]xK'{CvT-iR'[izd]VALY~@e0_X܎J*VyQ,{IDO1+/|=܏x ɂȒqBhZx4Lچ#t^!:jPH!,kiPm2^ɕ/a ":=R&g|Ѣri N.Gs۟=fsW3ZQq7J`Z< r' oi3L,Uh>G35O>WE0FR;KњO!qp߷ʪ/S 7%g#$+]%|2Q7l H$>2ꞓFUUB4/դH0]DKESo[垎9H'|{=fW:v\кhq' f*ٻqrX"Bo+@H>n~j8U-Qt ЉQ|ǝb-g1p5>hI ҙU0Ҷj)ޑȂ!AU^? 7G f4&Ytrzx&_Z7ݷm* 07 NO=q_ar:R=" ou $HA-Liygw6r"=hgʀ4c8 uRB0 e%k!%x0]9ڥ R %goܠD; ~fgD67zG hWQ䐽#cvPW]8K7#n^4C2neDYpZϸP|*X\qV6$ 2n☠Tcjn wO#Wܜ@6PGMa·dmK2'Rj]A[L)7 BglDf[_L~X"b&FF'8XPNm _@;+4Fܱ>1أ;mq-o7 ?,0\) adiZK*zKj3Y"Q%pV k}).-2>_t}W"qD6xVG\O",HYpK% O "w̭] ,dꟌ%Ajj'| '<)IBg 푣67|jFї*ub(~븙Q # H)ΕNJkF=̿ky6E @&3ץf pEr3Hp $l(6NNX#lVl\)W=k6Mhy[q2UҬ*WSO@A#El-4BNtjIH_ u/h~9|ۛRl0}OˉZ )n[ጄxvߙeQ:@g'\j (iP.g޽5WM1+_LKߐU+kxƶW"K[\EWeWR΅(: 4$0 x9~rCs4#.u5X~sE9_+JS{Xy1Grh{~Pi$\gm;C\SrnG;.b:#u7~*uxsy&8 ZUh8a{/v钵ءa+ BO@G7ُo|8HKqɍS)9 >bl)æA_FvIGn-|ۤNC'5A>̼AK]6d-sx"-QC*{D&KKц5zOϿGB;Gw:-P$o͡,/hL vZ YsB:zr^Top Ss.8]v^Jzb-HF^enƲ: "P 46&q.^N!\qԕ)}ڌ; *kչkmk(~ ,yG ~5[ cI/&A`lRsNUE7=jd}G$>d>{` kf6vl}}>igf7$F]f|f>Y{i`%=Nưp|hޢ|H9Qf^wIᩘAހ/e꿃@3ixF#nQq2gliSG0`AI.e4϶DG=̢0m sEHQO6>=Ҏ;4OzC+=e;K2 CDx$U_ `MBo0Fex7Is[dW5K?t09ؤ\\ _\S{PWA1qUgQTRMAF. EA0GqD$Ba5jfak_2Tk0]n΢WU|Qc$PHϲ)Xp^TcėݒPzW BRGj5 L9(ĜNz' 2+;xK^7 HiYNl^Jٍ:1-ȴdͭOּEb&6*IXzoO' a]$gJ7B g9 |n(0m?O;Iqt"bÔG61$5cؾ?'Ƃ\,: ZU1Ɋ[l~+5+ư5 oSɲ }ha!#'X lxB5zxB^h]u=jRY;>O7baeEbog)>RB+FiH[Fe`K|x-U2?\wpZG>$(ls,}-eh(%Fͳv%8ZDtiDK48R{P-oiP8yT*?,İ^S߱wzᲔ<[2Ώ% >k97Gu^+6TW53?s`^81U_ͅ)@J),H37s$u"+B,qF܂OAODH D۬'3,^DYAeJrQ_9[1^;5'ic.ؕ= `aL2? +ccU@ZA0U{fsd|1>ũDgٓl:v|+>F[H5[N-KVy ]9sk;@ry@)V\K'&sN#Z,`vc¨}OE HlMA?'L 価m'`c~0khm‹e9wn vt%_3 `*(q%C_" i5 KS Y]㏕>D$sihs|L ,c§8 M4D fY(*b@N)Hi>v:z<%x}}$ &-Ʃ==ͪk:XxAOK q| {,Ē/!~*=0L@' cqh1$2zZ)aVass<#G9:wiKZSKH8)h]T\?Xz w@Y(YIJkwp!&AY/84=UnU yކPh".gEi/Tt}G;PJz64PX8GK ,vMeO|M0,$cs,m* 1k<ͮ" *^)Q;Er$JޘUm`tt a#]zEy{)6ZsΛT Jj%V=KgtT1L@œ,y.8eX4T){mW*8Pgj [1bی@%_eLb%4K m"n~=8EPekDU4FLJNli$JfV>OGӨlP)T+cg i.d<ޱE'tIC;C,;+ʥ)T-<%qkrodJytO5U2h? a||dgVPvat>rJsKJӥu+-A ؔͲG%9DTGJ^G] 6y;wN+Bx6`bg;ya#JSr:n<x`҇95J$TU,rcu„t4ULDYuB'̑O}]ǡv k6,lSۺR1V[Qʧ/_4VAUm{~W^FDac0F h$ J`MQdqEL)3b3}~)v.7#s܋D=O8Af G[5:1xcDV Դ}x uVWhN,=aj7F=A&m=W(zbH 10 ^_7U:cmt:m֢_oi(9$[iAmH<њVq i؇v,/,.oK뀗gr2(sbM|"k~KB}g ͖g뱳/Pz 9Fo$*rR/4 "45\;y=Yi TSܤ:d ށ:E0}p]+ L}>]DM1E 68GM&L3( Grm|K&v$[[HH{)r*M +=3qJ2A$FT 4ӌKo|CDA+ImlUZ)bILFCFS |Rn.7'0q %z~SYiMtƒ}Vw0١\WHLSv&WTbM4Zhxѭ^\=vY6!(Twrz2޿sXЎ\#c,Yy'QUa,RL3Aؒt3ּ4FWY`,p?$S16j2 x߯bm9UUU~A M{eEc;~yҭ@cQQ04݈?O/? MuO'2|3srGQ:S^tu4$ݫ[W{XY-=ە5>+9zm_kɺJ.%eu<8=P"M@\ &$;] +3;[@C=[w;z}a $,Iw(_ Ǹ'W FvC _8/F,aӊ\[N~h!0YhuuAS (7&NC-/ߓ4 :.-mGJc4rי 2Ç B lwB47:Zm0E6 G,yUmyV.4?KyCkXc-5z,UKת|N>c~3^ ;K z-Ņ'0^s8,R?_z; ƘN5E ^Lv=g) W2ӁbUI04X!tɻ#qb>) ׬^Z(lw6D=Ϋ;$cJ W#x=cK2"//T+1d|b@v)@Ɖr5,=TOO4Ñ9`?4ow ʼniT`_1UɍLm9>vƗڄ.B=k#߃L]A0Vqyռ9E$g&J\@K`ʢ)V}SPFysIHy=xM58f+gt? xU^oEtXZE<[chz b+eY R50rB/9̲*CbXn"Ẑ"!kS 'xئ|TOY]97#]`'VN$4& \ד'B'ο[$7ٹO:gLP P=^Au`X&6o K2: zG,ևNtX "b଻m[:v!:~%9ONb:7SeFߵ&dm9ɀz|/P4|wEnoE0[Tˮ ! -+a&nrKCĚo JxV`<ש]E#l@9@T.+3Y]}[G'fI9kSfb+ouy# {-y8 [U*p/ (jwl:mқܯE*6HQ꘰F9bTX$90_IؖLL֐ Kkr7t}oqvwB)dQ6(yr%w[M{=_ǠZ m!U}1˃]9eA7F/>##M$TnM !NުIL`,OI6!(Y;>& rQܡyO^wRV,:vB+*DJcAtz<=kM;}.`P$dzx"uԤRm+ic4œvo*kMi73^70Y$`[Crq`(0qphk<4BķjŶA>?E7KƠ#Pa;$@01A#Foh=VDBOh=j} K-w„7kԙ&A^1&ܗ=[CVO;>r$&%I j7-1;7ҥGhOc<5ȏ@]ir%wA>i)6YHb03JubsMϱCPtvX7J)BZ?~srcM!%_bבROM3f>qt*Ф~3F+5-{WD#Pf|g.E@!6Ы4ϴStY< iп!r14j!½¹$DGEMۘe|#uU[+u%& Bvn0wC5=[HYI:fOB+y]KY^R<ؖp7^Ꭸszka[#:A;elNsbŰ-s麨,--TIY8i8~:E,­wkIu3HHKLf—_[SMs눉v6-%St4_zL3BFZǝ5ZܤpMCE7ND_(R5 ulX7=ppBx'"6<_CO ݅Cw]YLb۩ot>}*2^2lK[u \s=78(Kbn8.I(5,8IE֖7ogG]$ Ī{)q#׼[tNa!WfdLboݤKC<A'KNط~oa~_ER%MA~kH8@bsσ9T䏞)WN|4@DCcG;zc@y[J>BdD\ Dj=J4ZciQzqY$K 6PjB p_!~ v̑Z1uI  C!-܏&v;:IJnޥMyAD)<ŕ\96{{ŕ`R[eqmW5#Gº|1d%35 ,!*, )әX /q|SՌ…\qVaN +Y9d."xDz\aR`k-0;zҖvzJwfTj?TXO b g (W1 PAG2#8EM,̨Ni;h5kI(80,&t<; A>"񌔹3nN?ُ̋p MKgV,Mo6؉aJJHvAj:/ 2>n.<[yJjBi ~^l2s~amN7_󵻉dK9X+miZJؾYmռ2!GxvSb 1L {b}2Yخ?quwcZM}^ӕ1ҳЃ%A vkm c&Şoϴ o[[e$g ,OH뮰 9A. 0G&)&_(ӇEظZWz?N$.B򔬜`P|Rϴ @% $.}n*չ>ae.4୕g祋Z~-uL-M!Z[W ہ"tf `p=gO}-O2e&H )ֆVʄMh.Қ؎+_>`\y4&UH. i Lh/ox!!4ھ=2$i2e'6%ߝ́n6xf7팷?2/z<.x SoAH+_`4B&z̍!@rv×~6W~V),"R?Nxm* TXb#Yi.QCg)O[Pczh@b뀢qjl~bqZ]x3YħY*W ŕP.wm:VUۯǖ(Y3Ѽ\`޼$zH0S|F5eWzTg0+W_+֋.E1,+ח?+ ?ADLtK)B (1$ov <- 5z-WP>ry~Ohױ}gbdG] rBlfX b+%km?g.x *Sl3F+GcwSErKO_,q17 LA/lOٷ;l/ĕ36@iX,)Vb>کO##&׀j*mu~h\% V@%mD@BT(tD}|8G[|J`}fZS&2|\05Pϊ X̅LKQ0eQp Pr3QĒ6[}tV,Nqq}&7|S䒛Sf[6 =z"Fc7&8]S%6Z;'p96j=އlI[u#o +hVtaIA=UHp#(D4myK>;p6{տxۄNL[~NW/.@ށZb/7+?Z֌r*aK0T%,ǧnۚa7Q(.JCMM|łλh>Z$zlnxuYRj[q)X KJ ZSHI3W_ ϟABI)" *4+ !'{?g."BLJ'%0?1C7Y.2g=to# `1$1;쏎ڊ Xšzўkp[C  t4om$5cA,QB%&&+,mĵQ;Tt1Of*n\RzlQoɧms=VXk`ˈ/wOVn,!ɒ*^-kq*pmi޾qU$}Mpk:4{5-0aIגk|vl%Ѧ<54(Aj!<]$^ 5[ t_*.@_@kyL0] QL))Fزcv_8Q8IsN!@\f5JYzomKIt4|PO$q ;Zp,Kx( }jI'¦?'r664 q&K%0rl*FSj6 z<%jz >ye:1C5Oڅ2}N՜k`"/-a9'v#!)4>UFqmPk<7Tw``5L~""zKҸُ^̡N_MIXF޿Qٝ6T4Zbz'b(BMtŜL̐egWn)rMn'WS V"^"R_7terʼȲŎ?INZ",ʞ v?͐BQ}n0gD{QOnw8I*!|i254M2=b|?S[TQZ1t7hL? QIQ4F7a,!39[ܪqل~vc.I@˸Hƽp6;MXz . Vp bzU6b&4/Z0IrYDIu8(:Az#w^8M]_ƅ;G;1|N+2 +/ rv3֭D3h1ʴB2Mhc'}*֍N 5;(\u-L~\n~arq\ I":2@Ƈ!-Ekr*Z[['V~[<lG7.}cЁ c-L;k>*ww O/dw3h%Y) Yl3*86%Np.}~T쇸`Fn@sv# y"5<45 C@^3;Ӊ)BLٺXVikA{Y Z>'Ҙ5*$i5_UC' +142@;PC,cOl}uBr"${؍YΫ1sFF:S@SRnɆ"# :Y}Ρi9  d5헥)irV*^r:߼Avs!*\K"EpVm~O UJkSUyH&̴& jQSdX䜿#clS%qV->U&&PFX U^ҝd(0*qN8)@ʜ/*JkX) j &\w`GcAt!EJnO;2= 79[r.(/Cs6b5 O*dL0:?$igb$ jM6>opH1-3<2 ,'g u`':/? OgȆ*IY~9p#p=P f}\"&jӵc_5r{CJmeXU韩/ a8yvQ 7\l܂k5 Lq^R.F5:՝ZqlZ`96nsqUy,G?A 0_+`px!Ɍ5Jˍg7cyA<+482t?m#Tc(K$E, 7(SEu٤ FY/i;`1T^~P1璾"D;Cc`rwS-؏Zj7ZUXk|ʠateq_F*uwn 3W;hQ7ºu{xG%sV&Q76^DF"dȖʹo:$C<4O8@t=zXq\sQ=9apYX1|A-ӣZG)Ɖ/d:rДWiol&Gí{9HO'] `aqWWCњz"r 8@#WC9:l(qEwx-0ʚ=\ًSIzk^ Bty0V6%UY^iV(Wŗ !.s4Qkx:%qCSVmt:LAMFE@k1Cϕn$(5ްB)y kΪehV‚5jed.ZFw_`&ℜW2J/R @^@ KQ[5mǽޥBˈ?\N&(q=$p#_(lrA+!\vyZM+*\Uk:p^1.(ܕv7yoihxP6-P{ [i, ٛ! u TX1>0 YZopenttd-1.5.3/bin/baseset/orig_win.obg0000644000000000000000000001223712627373446016422 0ustar rootroot; $Id: orig_win.obg 27041 2014-10-25 12:35:48Z rubidium $ ; ; This represents the original graphics as on the Transport ; Tycoon Deluxe for Windows CD. ; [metadata] name = original_windows shortname = TTDW version = 0 palette = Windows description = Original Transport Tycoon Deluxe Windows edition graphics. description.af_ZA = Oorspronklike Transport Tycoon Deluxe Windows uitgawe grafieke. description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الرسومية نسخة وندوز description.be_BY = Арыґінальная ґрафіка з Transport Tycoon Deluxe для Windows. description.bg_BG = Оригинални графики на Transport Tycoon Deluxe за Windows. description.ca_ES = Gràfics originals de Transport Tycoon Deluxe per a Windows. description.cs_CZ = Původní sada grafik Transport Tycoon Deluxe (verze pro Windows). description.cy_GB = Graffeg gwreiddiol fersiwn Windows o Transport Tycoon Deluxe. description.da_DK = Originalgrafik fra Transport Tycoon Deluxe Windows-version. description.de_DE = Original Transport Tycoon Deluxe Windows Basisgrafiken. description.el_GR = Αρχικά γραφικά από το Transport Tycoon Deluxe έκδοση Windows. description.en_AU = Original Transport Tycoon Deluxe Windows edition graphics. description.en_US = Original Transport Tycoon Deluxe Windows edition graphics. description.es_ES = Gráficos originales de Transport Tycoon Deluxe versión Windows. description.et_EE = Algse Transport Tycoon Deluxe Windowsi versiooni graafika. description.fi_FI = Alkuperäiset Transport Tycoon Deluxen Windows-version grafiikat. description.fr_FR = Graphiques originaux de Transport Tycoon Deluxe (version Windows). description.ga_IE = Grafaicí bunaidhTransport Tycoon Deluxe, eagrán Windows. description.gd_GB = Grafaigeachd aig an deasachadh Windows tùsail aig Transport Tycoon Deluxe. description.gl_ES = Graficos da edición orixinal de Transport Tycoon Deluxe para Windows. description.hr_HR = Originalna grafika za Transport Tycoon Deluxe Windows izdanje. description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának grafikája. description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi Windows. description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe Windows útgáfunni. description.it_IT = Grafica originale di Transport Tycoon Deluxe, edizione Windows. description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (Windows) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 윈도 에디션의 그래픽입니다. description.la_VA = Graphica ex editione originale Transport Tycoon Deluxe Windows. description.lb_LU = Original Transport Tycoon Deluxe Windows Editioun Grafik. description.lt_LT = Originali Transport Tycoon Deluxe Windows leidimo grafika. description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for Windows. description.nl_NL = Originele graphics van de Transport Tycoon Deluxe Windows-versie. description.nn_NO = Original grafikk frå Transport Tycoon Deluxe for Windows. description.pl_PL = Oryginalna edycja grafik dla Transport Tycoon Deluxe Windows. description.pt_BR = Gráficos Originais do Transport Tycoon, Edição Windows. description.pt_PT = Gráficos originais da edição Windows de Transport Tycoon Deluxe. description.ro_RO = Setul grafic original al Transport Tycoon Deluxe pentru Windows. description.ru_RU = Оригинальная графика из Transport Tycoon Deluxe для Windows. description.sk_SK = Pôvodná grafika Transport Tycoon Deluxe (Windows). description.sl_SI = Originalna grafika Transport Tycoon Deluxe za različico oken(windows). description.sr_RS = Originalni skup grafika Transport Tycoon Deluxe Windows izdanja. description.sv_SE = Originalgrafiken från Transport Tycoon Deluxe, Windows-utgåvan. description.ta_IN = அசல் டிரான்ஸ்ஃபோர்ட் டைகூன் டீலக்ஸ் விண்டோஸ் பதிப்பு அசைவூட்டங்கள். description.th_TH = กราฟฟิกต้ำตำหรับของ Transport Tycoon Deluxe Windows edition description.tr_TR = Özgün Transport Tycoon Deluxe Windows sürümü grafikleri. description.uk_UA = Оригінальна графіка з Transport Tycoon Deluxe Windows edition. description.vi_VN = Đồ họa gốc từ phiên bản Transport Tycoon Deluxe trên Windows description.zh_CN = 运输大亨Windows豪华版原版图形包. description.zh_TW = 原版 Transport Tycoon Deluxe Windows 版的圖形。 [files] base = TRG1R.GRF logos = TRGIR.GRF arctic = TRGCR.GRF tropical = TRGHR.GRF toyland = TRGTR.GRF extra = OPENTTD.GRF [md5s] TRG1R.GRF = b04ce593d8c5016e07473a743d7d3358 TRGIR.GRF = 0c2484ff6be49fc63a83be6ab5c38f32 TRGCR.GRF = 3668f410c761a050b5e7095a2b14879b TRGHR.GRF = 06bf2b7a31766f048baac2ebe43457b1 TRGTR.GRF = de53650517fe661ceaa3138c6edb0eb8 OPENTTD.GRF = 505d96061556d3bb5cec6234096ec5bc [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. OPENTTD.GRF = This file was part of your OpenTTD installation. openttd-1.5.3/bin/baseset/no_music.obm0000644000000000000000000000717312627373446016432 0ustar rootroot; $Id: no_music.obm 27041 2014-10-25 12:35:48Z rubidium $ ; ; This represents more or less nothingness ; [metadata] name = NoMusic shortname = NULL version = 0 fallback = true description = A music pack without actual music. description.af_ZA = 'n Musiek stel sonder enige musiek. description.ar_EG = مجموعة موسيقى بدون موسيقى description.be_BY = "Пусты" набор музычнага афармлення, які не зьмяшчае ніякай музыкі. description.bg_BG = Празен музикален пакет. description.ca_ES = Un joc de música sense cap música. description.cs_CZ = Prázná hudební sada. description.cy_GB = Pecyn cerddoriaeth heb unrhyw gerddoriaeth ynddo. description.da_DK = En musikpakke uden musik. description.de_DE = Ein Musikset ohne Musik. description.el_GR = Ένα πάκετο μουσικής χωρίς πραγματική μουσική. description.en_AU = A music pack without actual music. description.en_US = A music pack without actual music. description.es_ES = Un conjunto de música vacío. description.et_EE = Muusikakogu ilma muusikata. description.fi_FI = Musiikkipaketti, jossa ei ole musiikkia. description.fr_FR = Un pack de musiques sans musiques. description.ga_IE = Pacáiste ceoil gan aon cheol iarbhír ann. description.gd_GB = Pacaid ciùil anns nach eil fonn sam bith. description.gl_ES = Un conxunto de músicas sen ningunha música. description.hr_HR = Muzički paket bez ikakve muzike. description.hu_HU = Zenei alapcsomag zene nélkül. description.id_ID = Paket musik tanpa musik sungguhan. description.is_IS = Tónlistarpakki sem er í raun án tónlistar. description.it_IT = Un pacchetto musicale non contenente alcuna musica. description.ja_JP = 空の音楽パック description.ko_KR = 실제 음악이 없는 음악 목록입니다. description.la_VA = Sarcina musicae sine ulla musica. description.lb_LU = E Musikpack ouni aktuell Musik. description.lt_LT = Muzikos pakas be muzikos. description.lv_LV = Mūzikas kopa bez mūzikas description.nb_NO = En musikkpakke uten noe musikk. description.nl_NL = Een muziekset zonder muziek. description.nn_NO = Ei musikkpakke utan noko musikk. description.pl_PL = Zestaw utworów muzycznych nie zawierający żadnej muzyki. description.pt_BR = Um pacote de músicas sem músicas. description.pt_PT = Um conjunto de música vazio. description.ro_RO = Un set de muzică fără muzică inclusă. description.ru_RU = "Пустой" набор музыкального оформления, не содержащий никакой музыки. description.sk_SK = Sada hudby neobsahujúca hudbu. description.sl_SI = Glasbeni paket z vključeno glasbo. description.sr_RS = Prazan skup muzičkih numera. description.sv_SE = Ett musikpaket utan någon musik. description.ta_IN = இசை இல்லாத இசைத்தொகுப்பு. description.th_TH = ชุดเพลงประกอบแบบไม่มีเสียงเพลง description.tr_TR = Müzik içermeyen boş bir müzik paketi. description.uk_UA = Порожній набір музики. description.vi_VN = Gói âm nhạc này không có nhạc nào. description.zh_CN = 一个没有实际内容的音乐包. description.zh_TW = 不含任何音樂的音樂集。 [files] theme = old_0 = old_1 = old_2 = old_3 = old_4 = old_5 = old_6 = old_7 = old_8 = old_9 = new_0 = new_1 = new_2 = new_3 = new_4 = new_5 = new_6 = new_7 = new_8 = new_9 = ezy_0 = ezy_1 = ezy_2 = ezy_3 = ezy_4 = ezy_5 = ezy_6 = ezy_7 = ezy_8 = ezy_9 = [md5s] [names] [origin] default = This file was part of your OpenTTD installation. openttd-1.5.3/bin/baseset/openttd.grf0000644000000000000000000311477412627373446016305 0ustar rootroot 0  is not for TTDPatch. Use ttdpatch(w).grf.  PO 1.1 (or trunk r20304)> Requires OpenTTD version 1.1 (or trunk r20304) or better. CINFOBPALSD>OTTOpenTTD's base graphics License: GNU General Public License version 2 Marcin Grzegorczyk: non-halftile foundations Michael Blunck: catenary, signals George: canals David Dallaston: tram tracks Jonathan G. Rennison: aqueducts Bilbo, Jasper Vries: font Andrew Parkhouse: rivers OpenTTD developers: other graphics 2CC map   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO`abcdefgXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO*+,-./01XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO>?@ABCDEXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNORSTUXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOrstuvwxyXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO@'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO !"#$%&'XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`abcdefg  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~*+,-./01  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~>?@ABCDE  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ų  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Ś  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~RSTU  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~XYZ[\]^_  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Œ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~rstuvwxy  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ŀ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ň  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~@'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ !"#$%&'  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNO XYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ : Pre-signal, semaphore, and PBS graphics by Michael Blunck$$7 A G)333\b  *q$$ / 5;333\b  *q $$7*A G3 3\ 1 % 1+ $$6*A G3 3[ 1 % 1+    * I33 / $ /   $* I33 / $ /  $07   = 333d $ 07  $$6   + 333d $ 07 $6* A  O3*0 $6* A  O3*0   $*<  G3$ *0<   $*<  53$ *0<$6  G3333* *0<YYY YY $6  53333* *0< $+6  L 33 3**0< $+6  L 33 3**0<$$7B I     l rq$$B I     l rq $$7* B I    * 0s $$6*  H    * 06    *  H     0   $*  H     0  $07 B H    % 1 7  $$6B H    % 1 7 $6* C    *(B $6* C    *(B   $*;    *<   $*)    *<$6B B  Z6 <<YYY YY $6) 6  N* << $+6 B <    *0< $+6 B <    *0<$$7B I33   l rq$$B I33   l rq $$7* B I 33 * 0s $$6*  H 33 * 06    *  H 33  0   $*  H 33  0  $07 B H33  % 1 7  $$6B H33  % 1 7 $6* C 3 * q $6* C 3 * q   $*;  3 *<   $*)  3 *<$6BB33 Z6 <<YYY YY $6)633 N* << $+6 B < 33 *0< $+6 B < 33 *0<     0  (2FP 2  (*?      ( 2<FZdx  2      %6 $6?  -      %6 $6?  -    ! 2 *     &(2 G     - l      % 5 ! ,z  3 3 ! ,M  -  33 8     ! , 7BMc~ ȅ Ȑ3 3    ! 7 ƨ      )< (2 y Ѓ3 3     2       )< (2 y Ѓ3 3     2      ' ; f m3 3   # ؏    *!,7BMz   3 3 , CM      % 5Ѹ ! ,z   3 3 , CM \     3 3   h    3 3   d   3 3   p    3 3        $ G3 3     - l z + 6   *0ez + 6   *0ez  *      7z  *      7z    + 6   *0z    + 6   *0z         7z         7z  / :    <z  / :    <z   17 =  $*6z   17 =  $*6z *    6 $6zYYY YY*    6 $6z   %*   *0 G     - Q      % 5 Cd   3 3 ! ,M  -шC 0 33 8     !   !OZMc~ ȅ Ȑ3 3    ! 7 ƨ      )  HZ  y Ѓ3 3     2       4   2Z  y Ѓ3 3     2        P f m3 3   # ؏    *! KC ,MX   3 3 , CM      % 5Ѱ Cd    3 3 , CM \   C   3 3   h    C   3 3   d   3 3   p    3 3        $RCT`  33 $ G3 3     - Q ;$$7 A G)333\b  *q$$ / 5;333\b  *q $$7*A G3 3\ 1 % 1+ $$6*A G3 3[ 1 % 1+    * I33 / $ /   $* I33 / $ /  $07   = 333d $ 07  $$6   + 333d $ 07 $6* A  O3*0 $6* A  O3*0   $*<  G3$ *0<   $*<  53$ *0<$6  G3333* *0<YYY YY $6  53333* *0< $+6  L 33 3**0< $+6  L 33 3**0<$$7B I     l rq$$B I     l rq $$7* B I    * 0s $$6*  H    * 06    *  H     0   $*  H     0  $07 B H    % 1 7  $$6B H    % 1 7 $6* C    *(B $6* C    *(B   $*;    *<   $*)    *<$6B B  Z6 <<YYY YY $6) 6  N* << $+6 B <    *0< $+6 B <    *0<$$7B I33   l rq$$B I33   l rq $$7* B I 33 * 0s $$6*  H 33 * 06    *  H 33  0   $*  H 33  0  $07 B H33  % 1 7  $$6B H33  % 1 7 $6* C 3 * q $6* C 3 * q   $*;  3 *<   $*)  3 *<$6BB33 Z6 <<YYY YY $6)633 N* << $+6 B < 33 *0< $+6 B < 33 *0<       $ I9P UZ dx  2!,LBXw, B3B3!3 B !n    &' :  g69H66l3633 6 Zl   .      #%A$H`HyHȐ3  3$3HHب       5>   " BXw, e 3  3!3BBn     ! 0$;  B +,} Ƞ  333 !Bcƈ   *+ <M  ,$Ђ l  333 6Q {    8 <F3. d    F <F3. dq    (- < 3F3<(     @ , 363<(   E'NRNNn4v ؠ23333 'h      /   <  r  (&3333 X ]c n    !  ,Mư   + 5    q       (F      $  9  .(EX ]c n  3 3 ! ,Mư   + 5    q   3 3  (F      $  9  .(E 2  S , B.B, n   . .n    &' :L    6666l   & &        H  H %iHyH   $.Hب       '> I  , B "+,B Ȣ   !*Bc     ! 0 ; /L  C+}~ # ث !MBlƈ   *+ <MX  3#6ȃ  l ?6Xl{    3=B   (FZ    EK<   (FZq  $C(-  <  (Z     37; @ ,  (J<    E'NRNNCl9  ȫ  '؜Ј      /  J(  C(} ȑ   P<~x       #=J N Ni 4 Iȶ 'N     ! -<A L   < <(<؀ Td <      B'BP> C[Bn    !  ,Mư   +5 ?4N   3)<      (F       .9 .  L ( <*<(y Г  Н    2شx   "# 4D   000w0     (Ȑ        B  B "`BoByȏ  Ț    !7ƨ       $9 C  ( < '(< Г  Н    2شд   +5 +  Ciq     ( 2  %& 5DN 3m0 8     (`Ѐ^{    8< <    Z    F< <    Zq    C-   <      C[Bn  3 3 ! ,Mư   +5 ?4N   3)<  3 3  (F       .9 .  L ( <*<(y Г Н33   2شx   "# 4D   000w0 33 (Ȑ        B  B "`BoByȏ Ț33   !7ƨ       $9 C  ( < '(< Г Н33   2شд   +5 +  Ciq   3 3 ( 2  %& 5DN 3m0 8 33  (`Ѐ^{    8<<3 33Z    F<<3 33Zq    C-  <3 3 3M\z   Ԙ Z.L҉j,Jĉ‰h  . $(,048<@DHLPTX\   (,4(       g047:>ADHKNRUX\_bfilpsvz}       ! 2L 8"(.4:@     L D"(.4:@      d047:>ADHKNRUX\_bfilpsvz}        2h  & $(,048<@DHLPTX\         h  & $(,048<@DHLPTX\     (    m036:=@DGJNQTX[^behlorvy|                L D"(.4:@    L "(.4:@  '     036:=@DGJNQTX[^behlorvy|          h  & $(,048<@DHLPTX\      h  & $(,048<@DHLPTX\          (    047:>ADHKNRUX\_bfilpsvz}          L D"(.4:@      L "(.4:@'    ?047:>ADHKNRUX\_bfilpsvz}>                    , :Vdr $B H Z l : H V d r    $ 6Hfl +   (  P   +    +  # *(8 H   + '  +<i (   +      ,          +  " (08 H  +    P     ii ii i   + 4 4 4 4  4 ii 4  4 h4 h4 4i h[4   М i iМ4lH   $:6  Z$+ u   Ai5 ( $HP$GSP$S߰$HЇ$$(A4H       < <(i        < DK:2 <<<=H  . ,>  B +,n7   i ( C P ,PM BM,iM,X,ȑ,7|&    &$   L  && & &Z L&B + r   蕈&& % = i i'&  ii i ii L<&r ppq  l&kk& LИi&&噙 kk prr%&q&|V K0  &q0ii Ⱦ&'pp r&N 0 0uɢ Ș& iآ: pѢ&:Ⱦ qLj&`00چj ӐX&ڬ&L8 ꊔN] <' ,H`X^dp|:Tm%_7i1c+]%W  $*0<6H6 U  i S^ d  4i i k h    n= L:;t(;Wc   :9<闰89=ٛp7iqkx .gi5421`4`i ıO + ` Z،0 `u2 `'  `5酉 `2+ ` d" ` `p,2`2Ui`dF `2 5`|@ `2G@552`,{@`^ӯ`4@2 2   '3 #, &,5,3?,+ J  - +ZшA +- +Z6 +Xgа ,    */+- 饠А ,ى ,,ɴqX,i   ,,,      X   ,pipkik  X    Tqiq`\q (qq4,   ,;  Kጉ ɸ,' ,HfX RL~Fx@rR #=Xr     20 1 ?$   '2   M2 d0452 `kqi4h05i4蘘h2 Ўih 0dh + ؖ h 8 C,5h 8^銈h8 󹐈h8 +ˆhi [xXh2p2ib ڥd  85 28 ણ 255p Òpӝ  '6ӡ : :; v9o҈E: :>   >@%5 A^C_]5 yx da]N +X&R غ +* *$ QQ[[QQ[7S7S\\&QSQ7]*:7\Q  i?QS]M  \T\SSS\[  Q[S\sQТ S}[[Qз Q QQ[\( Q\SX[\ S[Pk[Q%i T<;5BQPQW.rDRWlh     @O      ! !`    !3  ! 6! !QQ[[QQ"y[7S7S\\"r QSQ!7]B ^7\Q c QS]}  \ \SSS\[  Q[ S\Q"SŲ2[![Q#Q Q@ Q[\@ "Q\S ;[\b !S [k""BQ=i" B`_5f P@"r2 RrڈDr ,  K !  '6ETcr̈ۈ  '6ETcr̈ۈ5 Foundations. Non-halftile ones by Marcin Grzegorczyk[Z (@TPRTVXZ\^`chou{ &C`y$pp# p$  p#  # "p/# p $ #p pp  i#   #p=p p#p# 9h#i" 4q$"$ 0| p#" "pNp, p p  $ $'؜ 0p" i#i#8pp8 p $pp$"$/#"pi$UElL,p*B $p#$ #u#"$iNd #p#  (@PU]dksz$ p!p" # p$$"%i$ '$# (p )#p"+ 3, #p-pp/ 0X1$3p4#5$p7i89#;$

$% @D@BDFHJLNPSX_ekrx} $pp# p$  p#  # "p$##p" $$p#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN$% @D@BDFHJLNPSX_ekrx} <"#$"p'"#i #,$i0"4$ 9i p=>p<  :p 8 i# # $6# ppp#p"4p#& #pi$ 2 ip-M 0"$6$#>. $2=ip##pp,=#c#I* pj ( "$ #&5$k"p (@xPU]dkszp "p$$#&p p(  * , #p.,p02 # 4 p 637#8  :"  < " ># p# $ #p#  (@TPRTVXZ\^`chou{ &C`y-"#$"p'"#i #,$i0"4$ 9i p=/>< :p 8 p64p# 2 ip 0"$ i#. $_ , #p#p i* Q pi" v ( "$ # #]p&F # "i#pp ؙ$a  "#pip"$1 #d"#p #i# $p$"$$$ pi$Sؖ$ p+ $" $#$p#$D#p.(  (@xPU]dksz &1<FOX`gnty~p "p$$#&p p(  * , #p.,p02 # 4 p 63,#8  :"  < " ># p# ?p$=( #< 3 p;# # $#9 ppp#p" 8 #pi$ 7 p i  5#p-Q #4,ip##43## $1 $f$0 i#"$/p$- Cp", iip+ $pp)Y"('% "$i ##!$ (@PU]dksz &1<FOX`gnty~$ p!p" # p$$"%i$ '$# (p )#p"+ 3, #p-pp/ 0X163p4#5$p$7i#p"8$$p 9##$i$;$p$#pp $? pppipD "i#p##$""p#$i#""#i Kp" _ # A # =p ;("#p## $p$ $ipp$##$p$f (@fPTX\`dhlptx|,Gb~ "5DPY "p$$&p( *,.0 2 4 p638 :" < ">##>p <  ":p  p 3p# # $$ 6'ppp#p"#p 4 #pp p>upFBM i%0"$OX##W <. $HYp#p d#5,]i##i" :$$"$l(li p#" "Ж- p  $ $J# [<" i#i" "? <$pp$"L#"pi$V+WB $p#$ #u#"$iNd n  @V@DHLPTX\`dhlptx|2Tr "p$$&p( *,.0 2 4 p608 :" < ">#$#>p#p" <  $$p ":p #$i@i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp ii miypiE"i#pg 0"$rF#'z$"Hp. $e~< i="# ,# i" *k "$ ( "$ #p8p&b$$"p( @V@DHLPTX\`dhlptx| "p$$&p( *,.0 2 4 p68 :" < ">#`>p< :p  $ p# # $6ppp#p"4 #ppTp/p,60"$6##>. $2=p#,=!##n^\ (>k#$k"pf (@fPTX\`dhlptx|,Gb~ "5DPY "p$$&p( *,.0 2 4 p6'8 :" < ">#$#>#p" < $$p  :p #$i8p p$#ppi$$$ 6 p#i"$$ 4p# $ppp ~ ip pipd"i#pi( 0"$ i##$"#p. $J "p#$i#"9# , j"#i-p pi" "$ ( "$ # #pp&k  # p  $$؉  iyp"$5{"# p:#2 # $p$$L$ Pؠ$ 8g+$" $p#$#pf p3 (@fPTX\`dhlptx|*@Vn "p$$&p( *,.0 2 4 p68 :" < ">##> < :p p +p$ 6#p 4p#  pp Ypp  i 0"$ p #p. $,  p#p# ,C#i" Zpp"$ (En # "^ +  $ $$& C  i#i p" "/#pp$"jpi$Fp4  $p#$ #^$i? #p( @V@DHLPTX\`dhlptx| "p$$&p( *,.0 2 4 p68 :" < ">#`$##p" $$p "#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN p$ @V@DHLPTX\`dhlptx| "p$$&p( *,.0 2 4 p68 :" < ">#b (@fPTX\`dhlptx|Bf>`~ "p$$&p( *,.0 2 4 p608 :" < ">#$#>p#p" <  $$p ":p #$i@i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp ii miypiE"i#pg 0"$rF#'z##$"p. $f= p"p#$i#"#H,#$"#i7" $8y p$$".i"$%( "$a$ $pap&؏Jp$ # p  $` %#p" ,i"$C)ip"# poG#?5$ppp$r$!w;"$ ^$ Z4$"pp$p& "i "#$ $f (@fPTX\`dhlptx|,Gb~ "5DPY "p$$&p( *,.0 2 4 p638 :" < ">##>p <  ":p  p 3p# # $$ 6'ppp#p"#p 4 #pp p>upFBM i%0"$OX##W <. $HYp#p d#5,]i##i" :$$"$l(li p#" "Ж- p  $ $J# [<" i#i" "? <$pp$"L#"pi$V+WB $p#$ #u#"$iNd n  @V@DHLPTX\`dhlptx|2Tr "p$$&p( *,.0 2 4 p608 :" < ">#$#>p#p" <  $$p ":p #$i@i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp ii miypiE"i#pg 0"$rF#'z$"Hp. $e~< i="# ,# i" *k "$ ( "$ #p8p&b$$"p( @V@DHLPTX\`dhlptx| "p$$&p( *,.0 2 4 p68 :" < ">#` >p<  :p $i# # $6 ppp#p"4p#&#pi$ Tip-i=0"$6$#>. $2=ip##pp,=#c#I^pj ( "$ #&5$k"pF (@TPRTVXZ\^`bdfhjlnpry 'B^{$09"$#>#p" < $$p ":p #$i 8 p p$#ppi$$$ 6 p#i"$$ 4p# $ppp 2 ip pipd"i#pi( 0"$ i##$"#p. $J "p#$i#"9# , j"#i-p * pi" "$ ( "$ # #pp&k  # p  $$؉  iyp"$5{"# p:#2 # $p$$L$ Pؠ$ 8g+$" $p#$#pf p3 (@TPRTVXZ\^`bdfhjlnprx~  6NfzE#> <  ":p p 8 p$ 6#p 4p#  pp 2 ip  i 0"$ i #p. $,  p#p# ,C#i" * Ypi"$ ( "$ # "pfp&J  $ $$a   i#i p"$(#Z/#i$"$$Gpi$F~$ p$x$" $p "i$i?  p#  @C@BDFHJLNPRTVXZ\^`bflt~$##p" $$p "#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN p$ (@TPRTVXZ\^`bdfhjlnprux| &C\r*#  "p $ #p pp  i#   #p=p p#p# 9p# #i"  4p$ $"$ 0 p#p#" "pNp,/p p  $ $'  0p" i#i#"8pp8#$pp$"$/#"pi$UElLB $p#$ #u#"$iNd #p# (@}PSWZ]adgknqux{ $!p"# $$%i$'$(p)#p+,-pp/01 34#5$p7i89#;$

$ @C@BDFHJLNPRTVXZ\^`bflt~$##p" $$p "#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN p$% @D@BDFHJLNPSX_ekrx} <"#$"p'"#i #,$i0"4$ 9i p=>p<  :p 8 i# # $6# ppp#p"4p#& #pi$ 2 ip-M 0"$6$#>. $2=ip##pp,=#c#I* pj ( "$ #&5$k"p (@fPTX\`dhlptx| "p$$&p( *,.0 2 4 p68 :" < ">#z (@TPRTVXZ\^`chou{ &C`y-"#$"p'"#i #,$i0"4$ 9i p=/>< :p 8 p64p# 2 ip 0"$ i#. $_ , #p#p i* Q pi" v ( "$ # #]p&F # "i#pp ؙ$a  "#pip"$1 #d"#p #i# $p$"$$$ pi$Sؖ$ p+ $" $#$p#$D#p.( H (@fPTX\`dhlptx|&,16:= "p$$&p( *,.0 2 4 p68 :" < ">#?p= <* ;# # $9 ppp#p"8 #pi$ 7 p i  5#p' 4)ip##13## $1 $Y$0 i#"$/p$- Cp", iip+ $pp)Y"('% $i ##!$R (@}PSWZ]adgknqux{")06;@DG $!p"# $$%i$'$(p)#p+,-pp/01 34#5$p$7i#=8$$p 9##$G ;$p$#ppS$? pppipD "i#p##$""p#$i#""#i Kp" _ # A # =p ;("#p## $p$ $ipp$##$p$f (@nPTX\`dhlptx|,Gb~ "5DPY p p" #   #p, 087p#>p <  ":p  p 8 p# # $$ 6s ppp#p"#p 4 #pp p>2%DBM i%0"$OX##W <. $HYp#p d#5,]i##i" *ep$$"$l(li p#" "Ж&p#p" <  $$p ":p #$i8 i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp 2 ii miypiE"i#pg 0"$rF#'z$"Hp. $e~< i="# ,# i" *k "$ ( "$ #p8p&b$$"p( @^@DHLPTX\`dhlptx| p p" #   #p, 08p`>p< :p  8 p# # $6_ ppp#p"4 #ppt2-p,60"$6##>. $2=p#,=!##n*k@V(>k#&^$k"pf (@nPTX\`dhlptx|,Gb~ "5DPY p p" #   #p, 08'p$#>#p" < $$p ":p #$i8 p p$#ppi$$$ 6z p#i"$$ 4p# $ppp 2 ip pipd"i#pi( 0"$ i##$"#p. $J "p#$i#"9# , j"#i-p * pi" "$ ( "$ # #pp&k  # p  $$؉  iyp"$5{"# p:#2 # $p$$L$ Pؠ$ 8g+$" $p#$#pf p3 (@nPTX\`dhlptx|*@Vn p p" #   #p, 08*p#> < ":p p 8 p$ 6f#p 4p#  pp 2 pp  i 0"$ p #p. $,  p#p# ,C#i" * pp"$ (E # "^ &p+  $ $$& C  i#i p" "/#pp$"jpi$FXp4  $p#$ #^$i? ^( @^@DHLPTX\`dhlptx| p p" #   #p, 08p`$##p" $$p "#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN p$ @^@DHLPTX\`dhlptx| p p" #   #p, 08pb (@nPTX\`dhlptx|Bf>`~ p p" #   #p, 08$p$#>p#p" <  $$p ":p #$i8 i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp 2 ii miypiE"i#pg 0"$rF#'z##$"p. $f= p"p#$i#"#H,#$"#i7" $*y p$$".i"$%( "$a$ $pap&؏Jp$ # p  $` %#p" ,i"$C)ip"# pG#?5$ppp$r$!w;"$ ^$ Z4$"pp$p& "i "#$ $F (@TPRTVXZ\^`bdfhjlnpry 'B^{$093#>p <  ":p  p 8 p# # $$ 6'ppp#p"#p 4 #pp p>2%DBM i%0"$OX##W <. $HYp#p d#5,]i##i" *ep$$"$l(li p#" "Ж&p#p" <  $$p ":p #$i8 i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp 2 ii miypiE"i#pg 0"$rF#'z$"Hp. $e~< i="# ,# i" *k "$ ( "$ #p8p&b$$"p @C@BDFHJLNPRTVXZ\^`bflt~ >p<  :p 8 i# # $6 ppp#p"4p#& #pi$ 2 ip-i=0"$6$#>. $2=ip##pp,=#c#I* pj ( "$ #&5$k"pf (@nPTX\`dhlptx|,Gb~ "5DPY p p" #   #p, 08'p$#>#p" < $$p ":p #$i8 p p$#ppi$$$ 6z p#i"$$ 4p# $ppp 2 ip pipd"i#pi( 0"$ i##$"#p. $J "p#$i#"9# , j"#i-p * pi" "$ ( "$ # #pp&k  # p  $$؉  iyp"$5{"# p:#2 # $p$$L$ Pؠ$ 8g+$" $p#$#pf p3 (@TPRTVXZ\^`bdfhjlnprx~  6NfzE#> <  ":p p 8 p$ 6#p 4p#  pp 2 ip  i 0"$ i #p. $,  p#p# ,C#i" * Ypi"$ ( "$ # "pfp&J  $ $$a   i#i p"$(#Z/#i$"$$Gpi$F~$ p$x$" $p "i$i?  p# ( @^@DHLPTX\`dhlptx| p p" #   #p, 08p`$##p" $$p "#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN p$ (@TPRTVXZ\^`chou{ &C`y$pp# p$  p#  # "p/# p $ #p pp  i#   #p=p p#p# 9h#i" 4q$"$ 0| p#" "pNp, p p  $ $'؜ 0p" i#i#8pp8 p $pp$"$/#"pi$UElL,p*B $p#$ #u#"$iNd #p# (@nPTX\`dhlptx| p p" #   #p, 08pz% @D@BDFHJLNPSX_ekrx} $pp# p$  p#  # "p$##p" $$p#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN$ @C@BDFHJLNPRTVXZ\^`bflt~ >p<  :p 8 i# # $6 ppp#p"4p#& #pi$ 2 ip-i=0"$6$#>. $2=ip##pp,=#c#I* pj ( "$ #&5$k"p (@PSWZ]adgknqux{p # p #pp#  # !   p# $ #p#  (@TPRTVXZ\^`bdfhjlnprux| &C\r0>< :p 8 p64p# 2 ip 0"$ i#. $"p, #p#p "#i #* ;pi" $i( "$ # #]p"&F # "i#pp $ $a  "#pi^p"$1 #d"#p #i# $p$"$$$ pi$Sؖ$ p+ $" $#$p#$#p.( R (@PSWZ]adgknqux{")06;@DGp # p #pp#  #    p# ?p$=  #< 3 p;# # $#9 ppp#p" 8 #pi$ 7 p i  5#p-Q #4,ip##43## $1 $f$0 i#"$/p$- Cp", iip+ $pp)Y"('% "$i ##!$H (@nPTX\`dhlptx|&,16:= p p" #   #p, 08>p$#p"$$p #$i$p$#ppi$p#i"$$$ppppip4 "i#p##$""p#$i#""#i Ep" V # A # =p ;("#p## $p$ $ipp$##$p$F (@TPRTVXZ\^`bdfhjlnpry 'B^{$093#>p <  ":p  p 8 p# # $$ 6'ppp#p"#p 4 #pp p>2%DBM i%0"$OX##W <. $HYp#p d#5,]i##i" *ep$$"$l(li p#" "Ж&p#p" <  $$p ":p #$i8 i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp 2 ii miypiE"i#pg 0"$rF#'z$"Hp. $e~< i="# ,# i" *k "$ ( "$ #p8p&b$$"p @C@BDFHJLNPRTVXZ\^`bflt~>p< :p  8 p# # $6ppp#p"4 #pp2-p,60"$6##>. $2=p#,=!##n*k@V(>k#&^$k"pF (@TPRTVXZ\^`bdfhjlnpry 'B^{$09"$#>#p" < $$p ":p #$i 8 p p$#ppi$$$ 6 p#i"$$ 4p# $ppp 2 ip pipd"i#pi( 0"$ i##$"#p. $J "p#$i#"9# , j"#i-p * pi" "$ ( "$ # #pp&k  # p  $$؉  iyp"$5{"# p:#2 # $p$$L$ Pؠ$ 8g+$" $p#$#pf p3 (@TPRTVXZ\^`bdfhjlnprx~  6NfzE#> < ":p p 8 p$ 6#p 4p#  pp 2 pp  i 0"$ p #p. $,  p#p# ,C#i" * Ypp"$ (En # "^ &p+  $ $$& C  i#i p" "/#pp$"jpi$Fp4  $p#$ #^$i? #p @C@BDFHJLNPRTVXZ\^`bflt~$##p" $$p "#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN p$ @C@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~.< (@TPRTVXZ\^`bdfhjlnprz"Fj@^x$#>p#p" <  $$p ":p #$i8 i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp 2 ii miypiE"i#pg 0"$rF#'z##$"p. $f= p"p#$i#"#H,#$"#i7" $*y p$$".i"$%( "$a$ $pap&؏Jp$ # p  $` %#p" ,i"$C)ip"# poG#?5$ppp$r$!w;"$ ^$ Z4$"pp$p& "i "#$ $F (@TPRTVXZ\^`bdfhjlnpry 'B^{$093#>p <  ":p  p 8 p# # $$ 6'ppp#p"#p 4 #pp p>2%DBM i%0"$OX##W <. $HYp#p d#5,]i##i" *ep$$"$l(li p#" "Ж&p#p" <  $$p ":p #$i8 i# # $ p$#ppi$$$ 6 pppC p#i"$$ 4p#R#pi$ $ppp 2 ii miypiE"i#pg 0"$rF#'z$"Hp. $e~< i="# ,# i" *k "$ ( "$ #p8p&b$$"p @C@BDFHJLNPRTVXZ\^`bflt~ >p<  :p 8 i# # $6 ppp#p"4p#& #pi$ 2 ip-i=0"$6$#>. $2=ip##pp,=#c#I* pj ( "$ #&5$k"pF (@TPRTVXZ\^`bdfhjlnpry 'B^{$09"$#>#p" < $$p ":p #$i 8 p p$#ppi$$$ 6 p#i"$$ 4p# $ppp 2 ip pipd"i#pi( 0"$ i##$"#p. $J "p#$i#"9# , j"#i-p * pi" "$ ( "$ # #pp&k  # p  $$؉  iyp"$5{"# p:#2 # $p$$L$ Pؠ$ 8g+$" $p#$#pf p3 (@TPRTVXZ\^`bdfhjlnprx~  6NfzE#> <  ":p p 8 p$ 6#p 4p#  pp 2 ip  i 0"$ i #p. $,  p#p# ,C#i" * Ypi"$ ( "$ # "pfp&J  $ $$a   i#i p"$(#Z/#i$"$$Gpi$F~$ p$x$" $p "i$i?  p#  @C@BDFHJLNPRTVXZ\^`bflt~$##p" $$p "#$i p$#ppi$$$ p#i"$$ $ppp pipF "i#pi#  T$"&#pi"&# ppR "$  pN p$ (@TPRTVXZ\^`bdfhjlnprux| &C\r*#  "p $ #p pp  i#   #p=p p#p# 9p# #i"  4p$ $"$ 0 p#p#" "pNp,/p p  $ $'  0p" i#i#"8pp8#$pp$"$/#"pi$UElLB $p#$ #u#"$iNd #p# (@OPRTVXZ\^`bdfhjlnprtvxz|~ .p<  :p 8 i# # $6 ppp#p"4p#& #pi$ 2 ip-i=0"$6$#>. $2=ip##pp,=#c#I* pj ( "$ #&5$k"p (@OPRTVXZ\^`bdfhjlnprtvxz|~ .< :p 8 p64p# 2 ip 0"$ i#. $"p, #p#p "#i #* ;pi" $i( "$ # #]p"&F # "i#pp $ $a  "#pi^p"$1 #d"#p #i# $p$"$$$ pi$Sؖ$ p+ $" $#$p#$#p.( ( (@QPRTVXZ\^`bdfhjlnpruz *H ?p= <* ;# # $9 ppp#p"8 #pi$ 7 p i  5#p' 4)ip##13## $1 $Y$0 i#"$/p$- Cp", iip+ $pp)Y"('% "$i ##!$( (@QPRTVXZ\^`bdfhjlnpruz *H9$#p"$$p #$i$p$#ppi$p#i"$$$ppppip4 "i#p##$""p#$i#""#i Ep" V # A # =p ;("#p## $p$ $ipp$##$p$ (@_PT[bipw~ #0>L[hs}p p  "  p# #  1 #?#?p *T"p[W#kU#$"jp3$l#pu" ppq i# $ #N  p#p# #i" "$ع "pF $  $ $ ii#i $g "$pi$)rp$p#$ $i$ !@FBDFHJLNPRTVXZ\^`0Tv$#"  $ p  p p$p""#"$#)01pD >p#p"  (@[PT[bipw~ #0>L[hs} p "p$$ & ( p* ,.*0 2  #4 ?p6*8 :""< "b># >r#p(-K #:$ , "p "m #pp} K#    #6 bp  !@nBHPX`hpxF N p"p $$p&p"(  *# ,(.0 0  82  #p4 p68  8 `:"  < "p>#$#" $ p  p p$p""#"$#)01ppp $p$$$# T   "pB$##p$p#$#$ im iP "B!ipi#$p#p##"pi $ipp#i $#"l #HOp i#lB p$p#i## pp"iO5 #i""zppi"# #"A#ai E i##iX "Bp$$ipEؗ$~i?$iB$"ip"\#p$iiqE@D9B ?pp~$+ipg"p$"$7 #f (@VPSVY\_behknqtwz}+6@IPV[p  #$"'0#  p 3$D#pP" pp ] i# d$ #pr p#p# #i" "$0p "pF $  $ $ ii#i P$g "$pi$)rp$p#$ $i$ !@FBDFHJLNPRTVXZ\^`0Tv$#"  $ p  p p$p""#"$#)01pD >p#p"  (@[PT[bipw~ #0>L[hs} p "p$$ & ( p* ,.*0 2  #4 ?p6*8 :""< "b># >r#p(-K #:$ , "p "m #pp} K#    #6 bp ۬ !@XBFJNRVZ^bfjnrvz~JR "p$$&p( *,.0 2 4 p68 :" < ">#$#"  $ p  p p$p""#"$#)01ppp $p$$$# T   "pB$##p$ap#$#$ im iP "B!ipi#$p#p##"pi $ipp#i $#"l #HOp i#lB p$p#i## pp"iO5 #i""zppi"# #"A#ai E i##iX "Bp$$ipEؗ$~i?$iB$"ip"\#p$iiqE@D9B ?pp~$+ipg"p$"$7 # (@_PT[bipw~ #0>L[hs}p p  "  p# #  1 #?#?p *T"p[W#kU#$"jp3$l#pu" ppq i# $ #N  p#p# #i" "$ع "pF $  $ $ ii#i $g "$pi$)rp$p#$ $i$ !@FBDFHJLNPRTVXZ\^`0Tv$#"  $ p  p p$p""#"$#)01pD >p#p" f (@VPSVY\_behknqtwz}+6@IPV[ p   #$"'0>< :p 8 p p6"4p# 2 p#$0"$% . $, #p#p+* =pH(-K #:&p ~$ , "p "m #pp} K#    #6 bp  !@`BFJNRVZ^bfjnrvz~JR p p" #   #p, 08 p$#" $ p O p p$p""#"$#)01ppp $p$$$# T   "pB$##p$p#$#$ im iP "B!ipi#$p#p##"pi $ipp#i $#"l #HOp i#lB p$p#i## pp"iO5 #i""zppi"# #"A#ai E i##iX "Bp$$ipEؗ$~i?$iB$"ip"\#p$iiqE@D9B ?pp~$+ipg"p$"$7 #f (@VPSVY\_behknqtwz}+6@IPV[p  #$"'0#  p 3$D#pP" pp ] i# d$ #pr p#p# #i" "$0p "pF $  $ $ ii#i P$g "$pi$)rp$p#$ $i$ !@FBDFHJLNPRTVXZ\^`0Tv$#"  $ p  p p$p""#"$#)01pD >p#p" f (@VPSVY\_behknqtwz}+6@IPV[ p   #$"'0>< :p 8 p p6"4p# 2 p#$0"$% . $, #p#p+* =pH(-K #:&p ~$ , "p "m #pp} K#    #6 bp  !@FBDFHJLNPRTVXZ\^`bd*l2tvxz|~$#"  $ p  p p$p""#"$#)01ppp $p$$$# T   "pB$##p$ap#$#$ im iP "B!ipi#$p#p##"pi $ipp#i $#"l #HOp i#lB p$p#i## pp"iO5 #i""zppi"# #"A#ai E i##iX "Bp$$ipEؗ$~i?$iB$"ip"\#p$iiqE@D9B ?pp~$+ipg"p$"$7 #2[Z (@TPRTVXZ\^`chou{ &C`y-HzJHLIKzJMJLz NJMKJOINJLOJOILO/ IIJIHK  H{ H !=H G|9hGJ)4qHJB0| FJGA,L{L'؜M{LJE |2Y#IbG:kGHm6mlpiH_HKaGбF^  (@fPU]dkszNJJNJ!HJNJ#H$K%HK'G(K,")GJM{+H MI,J MJ-FJMK/F70JMI1G|MJ3GKz4K5H{7H8J9FI;JHzJHLIKzJMJLz NJMKJOINJLOJOILOJIKHJIJH{KGJHLFJGK |FJHLJI,JG|HK4H"<-|GK{K_26\ NGLr6-I$ @D@BDFHJLNPRW^djqw|~ :$HFJ'FJHJH,KG|F0JFJG4LG|HK9H{HJ=HJI>IL{G KKzJKG|J (@TPRTVXZ\^`chou{ &C`y-"H$HFJ'FJHJH,KG|F0JFJG4LG|HK9H{HJ=HJI/>HJH {KK?Lz=LOJIJJHI>ILI JLzKzJH D.XL{ G|5,aGJg*gJHJl(lH FJGo&oH q$qH |;t"tHGHGHwptHHKa2G$FG  @J@DHLPTX\`dhlptx|2Tr J"HJ$&( *,. 0HH2JH468 :<>JHJI>ILKHJIJH` >IL{GJI>HKH {GI>HIJI` JIKHJIJH{JGJHHFJG||,4*HKN{GA2B >rnI @J@DHLPTX\`dhlptx| KH"{H$&JH(*,. 0HJ2FJ468 :<>FJb (@^PTX\`dhlptx|Bf>`~ H{"HK$HJ&(*, .Hp0JH246 8:<>JHJI>ILKHJIJHI>ILI JLzKzJH D.XL{ G|5,aGJg*gJHJl(lH FJGo&oH q$qH |;t"tHGHGHwptHHKa2G$FG  @F@DHLPTX\`dhlptx|2Tr JI"$& (*,.0 2JH468 :<>JHB>ILKHJIJH` >ILIKH IIIL{Gz (@TPRTVXZ\^`chou{ &C`y-"H$HFJ'FJHJH,KG|F0JFJG4LG|HK9H{HJ=HJI/>HJH?L=LOJILI JLzKzJH D.XL{ G|5,aGJg*gJHJl(lH FJGo&oH q$qH |;t"tHGHGHwptHHKa2G$FG  @F@DHLPTX\`dhlptx|2TrNJ M{ MI MJMKKzJI>ILKHJIILHKH HIrnI @F@DHLPTX\`dhlptx|NJ M{ MI MJMKKzb (@VPTX\`dhlptx|Bf>`~NJ M{ MI MJMKKzJI>ILKHJIILI JLzKzJH D.XL{ G|5,aGJg*gJHJl(lH FJGo&oH q$qH |;t"tHGHGHwptHHKa2G$FG  @F@DHLPTX\`dhlptx|2TrNJ M{ MI MJMKKzJI>ILKHJIILIKH IIHzJHLIKzJMJLz NJMKJOINJLOJOILOJIKHJIJH{KGJHLFJGK |FJHLJI,JG|HK4H"<-|GK{K_26\ NGLr6-I @C@BDFHJLNPRTVXZ\^`bflt~ >ILHILI JLzKzJH D.XL{ G|5,aGJg*gJHJl(lH FJGo&oH q$qH |;t"tHGHGHwptHHKa2G$FG  @D@BDFHJLNPRTVXZ\^`bjv4Rj~JI>ILKHJIILHKH HIrnI @C@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~.< (@TPRTVXZ\^`bdfhjlnprz"Fj@^xJI>ILKHJIILI JLzKzJH D.XL{ G|5,aGJg*gJHJl(lH FJGo&oH q$qH |;t"tHGHGHwptHHKa2G$FG  @D@BDFHJLNPRTVXZ\^`bjv4Rj~JI>ILKHJIILIKH IIILHL[hs}NLNJIL*M{* MI8 M8MKFKzb^3 J@HLIK H{ H ( G|GJ-J D FJG3 5 |8GGH:48H HK-u GFJHF !@FBDFHJLNPRTVXZ\^`0TvILIL.<JI>ILKHJIL[hs} L{ I"HK L$HJ&(H*,.Hp*0JH82L468:<*>JH Ll>Ik<$IL8ILO6L42 0 I.E, N* L(& M$I"I (JL 3KL <{LJ (LIK #zK= Kz KzJ J !@RBHPX`hpxF NNJH{NJ"HK$HJ&(  * (, 0.HpM{0JH MI2 MJ4MK6 8  :( <0Kz>JHILIL.<MJMJKJK:LJLJIK(6K Bɠ8< b H +;KIKIKH  $8B04 .KHJHJH.<f (@VPSVY\_behknqtwz}+6@IPV[LI $0I6J HLIK H{ H ( G|GJ-J D FJG3 5 |8GGH:48H HK-u GFJHF !@FBDFHJLNPRTVXZ\^`0TvILIL.<JI>ILKHJIL[hs} L{ I"HK L$HJ&(H*,.Hp*0JH82L468:<*>JH Ll>Ik<$IL8ILO6L42 0 I.E, N* L(& M$I"I (JL 3KL <{LJ (LIK #zK= Kz KzJ J !@PBFJNRVZ^bfjnrvz~JR H{"HK$HJ&(*, .Hp0JH246 8:< >JHILIL.<MJMJKJK:LJLJIK(6K Bɠ8< b H +;KIKIKH  $8B04 .KHJHJH.< (@]PT[bipw~ #0>L[hs}NLNJIL*M{* MI8 M8MKFKzb^3 J@HLIK H{ H ( G|GJ-J D FJG3 5 |8GGH:48H HK-u GFJHF !@FBDFHJLNPRTVXZ\^`0TvILIL.<JI>ILKHJII9<I:IL8ILO6L4J,2 0 I.E, NW* L(D& Mx$I"I (JL 3KL <{LJ (LIK #zK L{Kz KzJ J !@HBFJNRVZ^bfjnrvz~JRNJ M{ MI MJMK KzILIL.<MJMJKJK:LJLJIK(6K Bɠ8< b H +;KIKIKH  $8B04 .KHJHJH.<f (@VPSVY\_behknqtwz}+6@IPV[LI $0I6J HLIK H{ H ( G|GJ-J D FJG3 5 |8GGH:48H HK-u GFJHF !@FBDFHJLNPRTVXZ\^`0TvILIL.<JI>ILKHJII9<I:IL8ILO6L4J,2 0 I.E, NW* L(D& Mx$I"I (JL 3KL <{LJ (LIK #zK L{Kz KzJ J !@FBDFHJLNPRTVXZ\^`bd*l2tvxz|~ILIL.<MJMJKJK:LJLJIK(6K Bɠ8< b H +;KIKIKH  $8B04 .KHJHJH.<2[Z (@TPRTVXZ\^`chou{ &C`y       /        != 9h "4q40|  L],+`'؜  pg#3 NehV TO SK'(   (@mPU]dksz  !  #$%'(,),+ 3, B-;/I0 X1,X3_!45789; < = ?% @D@BDFHJLNPSX_ekrx}               NLA \ 2Sr,؄6  % @D@BDFHJLNPSX_ekrx} "$',0  49 = > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ " (@bPU]dksz  "  $ & ( * ,, ., 03 2B 4B 6I 8X :X<_:">    (@TPRTVXZ\^`chou{ &C`y"$',0  49 = /> <: 8 6 4 2 0. _,$ i* ~i( E &X* +.$T1V "6b; 8 @7И Iп(m     (@bPU]dksz*5@JS\dkrx}  "  $ & ( * ,, ., 03 2B 4B 6I 8X :X<_:'> ?  =  < ; "9  8$7 5 4# 3 ! 1 "0,/O -z ,Q +M)H(C'%d"#! (@mPU]dksz*5@JS\dkrx}  !  #$%'(,),+ 3, B-;/I0 X1,X3_45 7 8 9;   <  = $? D@ / 9 B'SZaCl f (@VPTX\`dhlptx|,Gb~ "5DPY "$& (*,.0 2$4(6,80:4<8> >  <  :   8 6&  !48"4 2';   0,B1  g.tF  5,K5 P*6 6l(Pl &9$   Џ" XwXT賠K >  @F@DHLPTX\`dhlptx|2Tr "$& (*,.0 2$4(6,80:4<8>    <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  "( @F@DHLPTX\`dhlptx| "$& (*,.0 2$4(6,80:4<8> ` > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ "f (@VPTX\`dhlptx|,Gb~ "5DPY "$& (*,.0 2$4(6,80:4<8>  >  < :  8 6 $4 4':2 ,308 .H 3r І,b Fj*57P(  Ѕ&8 آ$o:q": 9 7 I( >  <  8  6  4   2   0 ?.*   ,; " *#%$E( V d&h) *p$P, ug"-D[. F-D  ;!إY    ( @F@DHLPTX\`dhlptx| "$& (*,.0 2$4(6,80:4<8> `        NLA \ 2Sr,؄6  @F@DHLPTX\`dhlptx| "$& (*,.0 2$4(6,80:4<8> b (@VPTX\`dhlptx|Bf>`~ "$& (*,.0 2$4(6,80:4<8>    <  :  8 "  66 *04P1HH6N28S =D 0@^E $L$.Цd $H H,iHdؑ*H(ll(jؐ д&д ة$ А"   Ѣ f (@VPTX\`dhlptx|,Gb~ "5DPY "$& (*,.0 2$4(6,80:4<8> >  <  :   8 6&  !48"4 2';   0,B1  g.tF  5,K5 P*6 6l(Pl &9$   Џ" XwXT賠K >  @F@DHLPTX\`dhlptx|2Tr "$& (*,.0 2$4(6,80:4<8>    <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  "( @F@DHLPTX\`dhlptx| "$& (*,.0 2$4(6,80:4<8> ` > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ "F (@TPRTVXZ\^`bdfhjlnpry 'B^{$09  >  < :  8 6 $4 4':2 ,308 .H 3r І,b Fj*57P(  Ѕ&8 آ$o:q": 9 7 I(  < :  8  6  4   2   0 ?.*   ,; " *#%$E( V d&h) *p$P, ug"-D[. F-D  ;!إY     @C@BDFHJLNPRTVXZ\^`bflt~        NLA \ 2Sr,؄6   (@TPRTVXZ\^`bdfhjlnprux| &C\r        != 9  "4 40 % L], +`'    pg# G8 Ne OV TO SK(   (@}PSWZ]adgknqux{ ! #$%'()+,-/0 1345789; < = ? @C@BDFHJLNPRTVXZ\^`bflt~        NLA \ 2Sr,؄6  % @D@BDFHJLNPSX_ekrx} "$',0  49 = > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ " (@VPTX\`dhlptx| "$& (*,.0 2$4(6,80:4<8> z (@TPRTVXZ\^`chou{ &C`y"$',0  49 = /> <: 8 6 4 2 0. _,$ i* ~i( E &X* +.$T1V "6b; 8 @7И Iп(m    H (@VPTX\`dhlptx|&,16:= "$& (*,.0 2$4(6,80:4<8> ? = < ; 9  87 5 4  3 ! 1 "0,/L -m ,Q +M)H(C'%d#!V (@}PSWZ]adgknqux{ &-4:?DHK ! #$%'()+,-/0 1345 7= 8 93 ;   S<  = $? D@ / 9 B'SZaCl f (@VPTX\`dhlptx|,Gb~ "5DPY   $ ( 048 >  <  :   8 6&  !48"4 2';   0,B1  g.tF  5,K5 P*6 6l(Pl &9$   Џ" XwXT賠K >  @F@DHLPTX\`dhlptx|2Tr   $ ( 048  >  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  "( @F@DHLPTX\`dhlptx|   $ ( 048 ` > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ "f (@VPTX\`dhlptx|,Gb~ "5DPY   $ ( 048  >  < :  8 6 $4 4':2 ,308 .H 3r І,b Fj*57P(  Ѕ&8 آ$o:q":n9 7 I(  < :  8  6  4   2   0 ?.*   ,; " *#%$E( V d&h) *p$P, ug"-D[. F-D  ;!إY    ( @F@DHLPTX\`dhlptx|   $ ( 048 `        NLA \ 2Sr,؄6  @F@DHLPTX\`dhlptx|   $ ( 048 b (@VPTX\`dhlptx|Bf>`~   $ ( 048  >  <  :  8 "  66 *04P1HH6N28S =D 0@^E $L$.Цd $H H,iHdؑ*H(ll(jؐ д&д ة$ А"  ֑Ѣ F (@TPRTVXZ\^`bdfhjlnpry 'B^{$09>  <  :   8 6&  !48"4 2';   0,B1  g.tF  5,K5 P*6 6l(Pl &9$   Џ" XwXT賠K >  @F@DHLPTX\`dhlptx|2Tr   $ ( 048  >  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  " @C@BDFHJLNPRTVXZ\^`bflt~ > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ "f (@VPTX\`dhlptx|,Gb~ "5DPY   $ ( 048  >  < :  8 6 $4 4':2 ,308 .H 3r І,b Fj*57P(  Ѕ&8 آ$o:q":n9 7 I(  < :  8  6  4   2   0 ?.*   ,; " *#%$E( V d&h) *p$P, ug"-D[. F-D  ;!إY    ( @F@DHLPTX\`dhlptx|   $ ( 048 `        NLA \ 2Sr,؄6   (@TPRTVXZ\^`chou{ &C`y       /        != 9h "4q40|  L],+`'؜  pg#3 NehV TO SK'(   (@VPTX\`dhlptx|   $ ( 048 z% @D@BDFHJLNPSX_ekrx}               NLA \ 2Sr,؄6   @C@BDFHJLNPRTVXZ\^`bflt~ > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ " (@}PSWZ]adgknqux{             !    (@TPRTVXZ\^`bdfhjlnprux| &C\r> <: 8 6 4 2 0. ,$ * ( E   &X* +.$T1V_ "6b; 8 @7И Iп(m    V (@}PSWZ]adgknqux{ &-4:?DHK             & ?  =  < ; "9  8$7 5 4# 3 ! 1 "0,/O -z ,Q +M)H(C'%d $ #!H (@VPTX\`dhlptx|&,16:=   $ ( 048       :9 / 9 B'SZaCl F (@TPRTVXZ\^`bdfhjlnpry 'B^{$09>  <  :   8 6&  !48"4 2';   0,B1  g.tF  5,K5 P*6 6l(Pl &9$   Џ" XwXT賠K >  @D@BDFHJLNPRTVXZ\^`bjv4Rj~ >  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  " @C@BDFHJLNPRTVXZ\^`bflt~ > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ "F (@TPRTVXZ\^`bdfhjlnpry 'B^{$09  >  < :  8 6 $4 4':2 ,308 .H 3r І,b Fj*57P(  Ѕ&8 آ$o:q": 9 7 I(  < :  8  6  4   2   0 ?.*   ,; " *#%$E( V d&h) *p$P, ug"-D[. F-D  ;!إY     @C@BDFHJLNPRTVXZ\^`bflt~        NLA \ 2Sr,؄6  @C@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~.< (@TPRTVXZ\^`bdfhjlnprz"Fj@^x >  <  :  8 "  66 *04P1HH6N28S =D 0@^E $L$.Цd $H H,iHdؑ*H(ll(jؐ д&д ة$ А"   Ѣ F (@TPRTVXZ\^`bdfhjlnpry 'B^{$09>  <  :   8 6&  !48"4 2';   0,B1  g.tF  5,K5 P*6 6l(Pl &9$   Џ" XwXT賠K >  @D@BDFHJLNPRTVXZ\^`bjv4Rj~ >  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  " @C@BDFHJLNPRTVXZ\^`bflt~ > < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ "F (@TPRTVXZ\^`bdfhjlnpry 'B^{$09  >  < :  8 6 $4 4':2 ,308 .H 3r І,b Fj*57P(  Ѕ&8 آ$o:q": 9 7 I(  < :  8  6  4   2   0 ?.*   ,; " *#%$E( V d&h) *p$P, ug"-D[. F-D  ;!إY     @C@BDFHJLNPRTVXZ\^`bflt~        NLA \ 2Sr,؄6   (@TPRTVXZ\^`bdfhjlnprux| &C\r        != 9  "4 40 % L], +`'    pg# G8 Ne OV TO SK(   (@OPRTVXZ\^`bdfhjlnprtvxz|~ . < : 8 6  4$$2) 0.  .NR,eW "*n.(r8& @$ " (@OPRTVXZ\^`bdfhjlnprtvxz|~ . <: 8 6 4 2 0. ,$ * ( E   &X* +.$T1V_ "6b; 8 @7И Iп(m    ( (@QPRTVXZ\^`bdfhjlnpruz *H? = < ; 9  87 5 4  3 ! 1 "0,/L -m ,Q +M)H(C'%d $ #!( (@QPRTVXZ\^`bdfhjlnpruz *H       :9 / 9 B'SZaCl  (@]PT[bipw~ #0>L[hs}    ** 8 88FTTb^k       %  (   #  D[ 5 MD+;*' b !@FBDFHJLNPRTVXZ\^`0Tv  ! ;D>  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  " (@YPT[bipw~ #0>L[hs}  " $&(*,*.*08284F6F8T:T l>k<$ x86 4 , 2  6 0  . ,(  *( 0&D3$3 "e   L M    !@NBHPX`hpxF N  "$&(  *((,00.880@ @2H H4P@6XX8``:hh   ! ;B 2)#"J;  ;-+\?C O E=ЮȾSȈȘؖJO'Mƙ1AAU\J   & f (@VPSVY\_behknqtwz}+6@IPV[   *36=  E    %  (   #  D[ 5 MD+;*' b !@FBDFHJLNPRTVXZ\^`0Tv  ! ;D>  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  " (@YPT[bipw~ #0>L[hs}  " $&(*,*.*08284F6F8T:T l>k<$ x86 4 , 2  6 0  . ,(  *( 0&D3$3 "e   L M   ۬ !@HBFJNRVZ^bfjnrvz~JR "$& (*,.0 2$4(6,80:4<8 >  ! ;B 2)#"J;  ;-+\?C O E=ЮȾSȈȘؖJO'Mƙ1AAU\J   &  (@]PT[bipw~ #0>L[hs}    ** 8 88FTTb^k       %  (   #  D[ 5 MD+;*' b !@FBDFHJLNPRTVXZ\^`0Tv  ! ;D>  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  "f (@VPSVY\_behknqtwz}+6@IPV[  *0> 9< : 8 6 4 , 2  6 0  . E,(  *]( 0&D3$3 "e   L M     !@HBFJNRVZ^bfjnrvz~JR   $ ( 048   ! ;B 2)#"J;  ;-+\?C O E=ЮȾSȈȘؖJO'Mƙ1AAU\J   & f (@VPSVY\_behknqtwz}+6@IPV[   *36=  E    %  (   #  D[ 5 MD+;*' b !@FBDFHJLNPRTVXZ\^`0Tv  ! ;D>  <  :  8 "  66 *04P1H # 28S "!0@^  %В}.Х# ",س, B d*7X(nl& ~# $  "f (@VPSVY\_behknqtwz}+6@IPV[  *0> 9< : 8 6 4 , 2  6 0  . E,(  *]( 0&D3$3 "e   L M     !@FBDFHJLNPRTVXZ\^`bd*l2tvxz|~  ! ;B 2)#"J;  ;-+\?C O E=ЮȾSȈȘؖJO'Mƙ1AAU\J   & 2[Z (@TPRTVXZ\^`chou{ &C`ysO~sOOOO~ OyOO/ oo~oss  r s !=s "9h;4qsM0p 3W,+y'OOy~s #Nƨ~s:sOy'Ț>~sL~ss~s (@mPU]dkszyO~yO!s~yO#syy$s%ss's(s,),+s 3,s B-,;/sI0sX1BX3s_!4s5ss7s8s9sy;OH~oo% @D@BDFHJLNPSX_ekrx} "r$rss'sssss,0 49~=s~o>yO~o OOOOo~sssss (@TPRTVXZ\^`chou{ &C`y"r$rss'sssss,0 49~=s~o/>y~o OOO?OO=OOOo~< Os; Os9 ss8 Os7 O5 ~s4 3 1"0,/ ->,F+)T(Z'%d"s#s!s (@mPU]dksz*5@JS\dkrx}yO~yO!s~yO#syy$s%ss's(s,),+s 3,s B-,;/sI0sX1BX3s_4s5ss~7sss~8sss9sy s;O ~o yOo~sL~sns~s @F@DHLPTX\`dhlptx|2Tr ~o"$& (*,.0 2$4(6,80:4<8>~o yOss~o~o` >yO~o~o>yss W`rs~ (@VPTX\`dhlptx|*@Vn ~o"$& (*,.0 2$4(6,80:4<8>~oo>yo~o` ~oss~o  ,<rN~o#\ 2r>H~oo @F@DHLPTX\`dhlptx| ~o"$& (*,.0 2$4(6,80:4<8>~ob (@ ~o"1@OBm|Ljֈƈ0?NJl{ƉՉΉ >M\RzŊԊ֋=L[jZċӋތ- KZixyOssb>O@Bь>@">@ƍUd>@6>@JوrA?~sB0>~r>BΊ.6>ƊRΊ.JZ~o6㜊.ΐ@ΈlRl㜊f (@VPTX\`dhlptx|,Gb~ "5DPY ~o"$& (*,.0 2$4(6,80:4<8>~o yOo~sL~sns~s @F@DHLPTX\`dhlptx|2Tr ~o"$& (*,.0 2$4(6,80:4<8>~o yOss~o~o` >yOyss W`rs~ (@TPRTVXZ\^`bdfhjlnprx~  6Nfz o>yoH~oo (@TPRTVXZ\^`bdfhjlnprux| &C\r oo~oss  r s !=s "9O~s;4OOOM0 3W,+y'OOy~s #Ny:sOyȚ>~sL~ss~s (@iPSWZ]adgknqux{ ~!s~#s$s%ss's(s) +s,s-/s0s13s4s5(7s8s9sy;OH~oo% @D@BDFHJLNPSX_ekrx} "r$rss'sssss,0 49~=s~o>yO~oz (@TPRTVXZ\^`chou{ &C`y"r$rss'sssss,0 49~=s~o/>y~o?O=OOO<O;O9OO8 O7 O5 ~s4 3 1"0,/ ->,F+)T(Z'%ds#s!sV (@iPSWZ]adgknqux{ &-4:?DHK ~!s~#s$s%ss's(s) +s,s-/s0s13s4s5ss~7ss=8sss9sy s;O SyOo~sL~sns~s @F@DHLPTX\`dhlptx|2TryOyy  $ ( 048yO~o>yOss~oyOyss W`rs~ (@VPTX\`dhlptx|*@VnyOyy  $ ( 048%yOo>yoH~oo @F@DHLPTX\`dhlptx|yOyy  $ ( 048yOb (@VPTX\`dhlptx|Bf>`~yOyy  $ ( 048yO~o>yOss~oyOo~sL~sns~s @F@DHLPTX\`dhlptx|2TryOyy  $ ( 048yO~o>yOss~oyOyss W`rs~ (@TPRTVXZ\^`bdfhjlnprx~  6Nfz o>yoH~oo (@TPRTVXZ\^`chou{ &C`ysO~sOOOO~ OyOO/ oo~oss  r s !=s "9h;4qsM0p 3W,+y'OOy~s #Nƨ~s:sOy'Ț>~sL~ss~s (@VPTX\`dhlptx|yOyy  $ ( 048yOz% @D@BDFHJLNPSX_ekrx} sO~sOOOO~ OyOO~oss~o  ,<rN~o#\ 2r>H~oo @C@BDFHJLNPRTVXZ\^`bflt~ >yOy,F+)T(Z'%d $~s#s!sH (@VPTX\`dhlptx|&,16:=yOyy  $ ( 048yO~ss~sssss s sr s $/ 9 BKSZagl rsrrF (@TPRTVXZ\^`bdfhjlnpry 'B^{$09o>yOo~sL~sns~s @D@BDFHJLNPRTVXZ\^`bjv4Rj~~o>yOss~oyOyss W`rs~ (@TPRTVXZ\^`bdfhjlnprx~  6Nfz o>yoH~oo @C@BDFHJLNPRTVXZ\^`bdfhjlnprtvxz|~.< (@TPRTVXZ\^`bdfhjlnprz"Fj@^x~o>yOss~oyOo~sL~sns~s @D@BDFHJLNPRTVXZ\^`bjv4Rj~~o>yOss~oyOyss W`rs~ (@TPRTVXZ\^`bdfhjlnprx~  6Nfz o>yoH~oo (@TPRTVXZ\^`bdfhjlnprux| &C\r oo~oss  r s !=s "9O~s;4OOOM0 3W,+y'OOy~s #Ny:sOyȚ>~sL~ss~s (@OPRTVXZ\^`bdfhjlnprtvxz|~ .H~oo @C@BDFHJLNPRTVXZ\^`bflt~ >yOy,F+)T(Z'%d $~s#s!s( (@QPRTVXZ\^`bdfhjlnpruz *H ~ss~sssss s sr s $/ 9 BKSZagl rsrr (@]PT[bipw~ #0>L[hs}yoyOOoyy** 8 88FTTb^ok$~ soOs r O s ( +@ U %H q x+s'Mos !@FBDFHJLNPRTVXZ\^`0TvOoOo.<~o>yOss~oL[hs} oo O"~o$O&(*,.*0*28486F8F:T~o l>yk<$yOx8yO~6o4yO2 s0%. (, !O*@( U& H$q"O~ s  ~~s~%~  ~ !@NBHPX`hpxF NyO~oyO"$yy&(  *((,00.880@ @2H H4P@6XX8``:hh~oOoOo.<~~~ '6BO^mBLjֈƉ!0N]l{soso.<f (@VPSVY\_behknqtwz}+6@IPV[oO $39o~@soOs r O s ( +@ U %H q x+s'Mos !@FBDFHJLNPRTVXZ\^`0TvOoOo.<~o>yOss~oL[hs} oo O"~o$O&(*,.*0*28486F8F:T~o l>yk<$yOx8yO~6o4yO2 s0%. (, !O*@( U& H$q"O~ s  ~~s~%~  ~ !@HBFJNRVZ^bfjnrvz~JR ~o"$& (*,.0 2$4(6,80:4<8 >~oOoOo.<~~~ '6BO^mBLjֈƉ!0N]l{soso.< (@]PT[bipw~ #0>L[hs}yoyOOoyy** 8 88FTTb^ok$~ soOs r O s ( +@ U %H q x+s'Mos !@FBDFHJLNPRTVXZ\^`0TvOoOo.<~o>yOss~oy9<O:yO 8yO~6o4yO2 s00%. (, !O*@( U& H$q"O~ s  ~~s~%~  ~ !@HBFJNRVZ^bfjnrvz~JRyOyy  $ ( 048 yOOoOo.<~~~ '6BO^mBLjֈƉ!0N]l{soso.<f (@VPSVY\_behknqtwz}+6@IPV[oO $39o~@soOs r O s ( +@ U %H q x+s'Mos !@FBDFHJLNPRTVXZ\^`0TvOoOo.<~o>yOss~oy9<O:yO 8yO~6o4yO2 s00%. (, !O*@( U& H$q"O~ s  ~~s~%~  ~ !@FBDFHJLNPRTVXZ\^`bd*l2tvxz|~OoOo.<~~~ '6BO^mBLjֈƉ!0N]l{soso.<2! Canal graphics by George / PaulCAd @I.5BVpHzBt4HU % 4".S1`(p 4WJV8:{y:Q~'=0YŸ@|fGE xЇП FSjLc'0بЌxɕ_pЌx];AhyxȆ^ٛ+?9ZEsW+  ŊIA '@ "1@Ods ĸ~ 膈y*9HxC膉l{xwІyІ7ІА2ACIАtN萉΢sҊX╋:>rҊۋ|/j}R܉yۼ#ob۲ۭQoK/Bۨ}CX6:5lx*p6q'ص- 452vہ2m1Ǐy&孏Jxя@ "1@O dswB4{<<>GƉ8ml*<R؛٣iٮp؊>|L`'ɮ؊р\Pψ>z1ج?N&tB>CL&⫉Z& KA鞙&:ɯъԋZqԺٌAԚ?ԊٳH<ԊԌԊԌʔԌ֊ԍ,;JƊm|Ձ׍ '@ !0?Ncr A > '6EChwt?w6z|y؆|C?І,;.@{r6=ϊٮm؉A?Ҫ%@*ɮlۊ3SʑBSʑ땓㱊BȐa DАᤊ?ҕѰmVٵܓ?{rܛص/.ɮ ܎>7>?B.|=Ҋ܎N>ۼ8ʊێұiXU.65L3{˥Svz>Sy;IVBY@93 1v(  *8  Tc ~ R} * LS}Ts)U  +Y҈ UW)~ PgȨ d ( &P *S* *~ ~Шa }W~ || @" 3&|JL  KU  2 J8 "Gt Rڠ 'w꠫ L< &*в뉋ӡ-ɶS2׈Tr!*  $3B P_ '|( & x*  x'yP xПy&x,@@ ) 'h ?) ) x@PQT   )ؠ@ 0@ s i /4 ڀ HҀgHS⛋H R Yg{Tҁ ㉈+ʁ  (~يdR; 閊T P< }&錳۴ԌRV2AF\(  "1@ *Z v r%O+ r$K ]JLx% Jq   '$rM ȼ ] 0r0B P ;WlC W@ 'ؼ   0 zh {؏   O,ɢ /P  P ;BЏMWI٢YYnh`e YY V : RHN2.C#I"hЎp"*    ,;, ,f Z VW  [Z ܸ ,~ , ,~  бi`w ~خY< "܈  ^Y^ &  _BO` ,U`5B, ,ذB脱1\g_.  e;ڔ@0┓j0 59ꔋ0Y/C^뗋`0 lX*2 24    _f   58QٳM P03 /Ԍ,B xjc݇h     "1DSD@#f  ع  Be    L]\ٞrN \ic{"p{  p + "j@   Ј 3>1BOh   / @<`o Z@x   [# z; ؖ:<,:Y  Zȴ ,ؔ M@ Z  +T  ؔ  舸x  o   ?o;@  @е2o= }=?  KY  _'6ꩋCRh#   "1  DS "tF`CfȠ$  " "f "  ЉD $؆E2ciર     w Ȉ ?wȫ " A!f Q"؈|fwsљ s^s  8;ˊncs   Eqy2dR  K5  6 鍈 󋾓܉ ,H,( )  )8' )_x z 󈢈؟ ʈP P (򈠉O? jx R (&     4L ^  *  p*T )P IY҈: p \U~0%G$ب =~~: WpTS*r   p*بr- *SP ےt  +*&|"  *#Rl jd p R  s ȅ xl~&,] ~ Ѕ%~lR(Ig(~؅ꝕn~ ɵSv }hz QMzn({OڠLz⠎zЅr!*  $ 2A P  ]l ') +( d x + * x'y, ا  NU;T Tx') T (ȨШ)N" ' O |    g ы @@rTVl  m*)Р@  I4a0@ S * S TOe䨙KM w) /% gx'A鵰x+ 8xPT1_ER 鿨 bI ⸙?  șNȡ*ؙ uy5ʸ~#i hѓ  A{hzȍ4CX[ (  "1@  L[   v  *r% r$6 K&  $M% _ 0 'Ir ИoH] 0H U ;LC ɾ '   P "   _|ؿV؏ mO,L1Z P娏@٢-r-U `Џ؏rLnN%&i3[ 0@؏pJؙX`؏< osӀ`k V0`   VO 1uVtk) '+9 Ve R +R MVuV ~׈F WY* XȬ   ؂X + Y.+u" Wd   X 89 6ت-XZJ  R6T +  gR6ٯ.X76T+D t6  X ,6 X {( $  6 wӍR6,U D+ ؁)U*륋Urz{q~WcuqTу,$ˎH "    $2   H@%lB& $ ^$H # ^=M  ^ PIl ;ؐ NlHr. K^H#$`   ^$ؐ`'Z! b Zs %$j  $F` 4sX  $l o=s B$t6lsy4 l s6llsTos̢lslߢ*eKHlfD !j̈,v!"&  &5D L[Hr l#L l'#m(0lFM 0lش# |h|V %F | hА    l f̹ H   :Y%А     &  K`@Љ 3 L@ȉ-  d`CT!ilx eZ  È 铨0Z)'yqȉ靋&N 鼌<  Ylr3-鸌} l|Z~,"  )  =! #m  򈤐 D D  񈈉9 4\ o~Fh   ذ  "    $`  ; 0`!  Ӳ _AS  !=` Ѐ]<Q `~ I  /Y@  !ؽ  w S@ء w 7Cw D"_w: $w'bѶ鄐w *ww`ɰ wىwt85щpщO⣊nʌwऐD5ꔍ [XUċ띍"&  (7F  P_*xȇ А'P  ط   ' ؾLw ( ؘwP ' Lu9VȠ QS>(И UȠ L L  y@  ѢAِ RL x x? &   v@X3  ط؞XD    , (n oc 3ّ W3 *&v k3  . )3 @d `/!   3 3ؾx (  xD x*[˖:='c\ZmqN2xxZH Иx%蘌h* (,:U  Xg V ,| PXXY" ܈  Y+ `{Ȱ   ` ,XW, аe <4lfh\ ,^ -, Єيi  0 ԰_ ]d\ьhUʓЋ+  "1@  O^)   |{  -{(`԰{)(  {Q`8 w# dUH *  q Фu (HJ  H Dz  ( *(  PcHqW  Q JR LR@* UP %l褈+CXKᙉ$@quمŠ?qNj5   )  6M 74 63 ؅  6 27   1dk)j j2З  ^= ud(  4d     [8 fB   6  c04  hʦ / 55/̉3f20h/ - n@/F5 ږ D˱۵45 -e 陈>M 8ˉťդ?%+ 2  ,;* ,e Ȯ 􈮈 وV V /=󈬉gW . Xى +-  1@\ -lR  }Y K] - 0./Z %[Z  L ሴ. [ ȴ .Lh ^L-M -  zLX;ˆY; LgXl C <Pi  J(D;S;|;u Cܹ镍-&    (7FP_ P L)xЏ  И   '  rNw  * Hw PQ@ Ly~@  Q'x(ИVȠ  X( y@  O Rx xР &ev@(ظР< (x )( x v(1 2   @i K@u Hr迋M%"  )  =! #m  񈤐 D D  􈈉9 4\ o~Fh   ذ  "  є  $`iN ;  h`!?N 7\ 4 !  ЀZ  `8 p _ q( !  u:  l@ءEA hCW D`N᥌(H`s٘Ɍ&  &5D L[Hr l#L   '#m(0lFM 0ش#|h r %F 耙 hА  l H  EH E4 %А    @hT@$ x 顊  n( & 鱊$$裋x 铈Hꏊ      "1 "<  fZ\ 5dG  %#$6E 6 i઩E f fȈ 6ث "66e ""Bf   6 VTvvt`ڜ(  *8  Tc ~ R} * LS}Ts)U  +Y҈ UW)~ PgȨ d ( &P *S* *~ ~Шa }W~ || @" 3&|JL  KU  2 J8 "Gt Rڠ 'w꠫ L< &*в뉋ӡ-ɶS2׈Tr!*  $3B P_ '|( & x*  x'yP xПy&x,@@ ) 'h ?) ) x@PQT   )ؠ@ 0@ s i /4 ڀ HҀgHS⛋H R Yg{Tҁ ㉈+ʁ  (~يdR; 閊T P< }&錳۴ԌRV2AF\(  "1@ *Z v r%O+ r$K ]JLx% Jq   '$rM ȼ ] 0r0B P ;WlC W@ 'ؼ   0 zh {؏   O,ɢ /P  P ;BЏMWI٢YYnh`e YY V : RHN2.C#I"hЎp"*    ,;, ,f Z VW  [Z ܸ ,~ , ,~  бi`w ~خY< "܈  ^Y^ &  _BO` ,U`5B, ,ذB脱1\g_.  e;ڔ@0┓j0 59ꔋ0Y/C^뗋`0 lX*2 24    _f   58QٳM P03 /Ԍ,B xjc݇h     "1DSD@#f  ع  Be    L]\ٞrN \ic{"p{  p + "j@   Ј 3>1BOh   / @<`o Z@x   [# z; ؖ:<,:Y  Zȴ ,ؔ M@ Z  +T  ؔ  舸x  o   ?o;@  @е2o= }=?  KY  _'6ꩋCRh#   "1  DS "tF`CfȠ$  " "f "  ЉD $؆E2ciર     w Ȉ ?wȫ " A!f Q"؈|fwsљ s^s  8;ˊncs   Eqy2dR  K5  6 鍈 󋾓܉ ,H (    *8   TL+~N, * p*T )P pIY : p \U~ P%G$ب d~~: WpTS*r   p*بr-ٖQP t  +*&|L  *#Rl jd p R  s ȅ xl~&,] ~ Ѕ%~lR>Ig(~؅ꝓ~ 덳Sv }hz Q.Mzn({OڠLz⠌zЅr!*  $3B P_ '|( x+ *x'y, 谈xNU;&x') @@)N" ' h    g @@r驰Tl   "e)Р@  I4a0@ S  S TO/KM w)2 % gx'A鵰x+ ~PT1_ER 鿨PbI ⸙?  șbNȡ*ؙ uy5ʸ~#i hѓ  A{hzȍ4CX[ (  "1@  L[   v  *r% r$6 K&  $M% _ 0 'Ir ИoH] 0H U ;LC ɾ '   P "   _|ؿV؏ mO,L1Z P娏@٢-r-U `Џ؏rLnN%&i3[ 0@؏pJؙX`؏< osӀ`k V0`   VO 1uVtk) '+9 Ve R +R MVuV ~׈F WY* XȬ   ؂X + Y.+u" Wd   X 89 6ت-XZJ  R6T +  gR6ٯ.X76T+D t6  X ,6 X {( $   6wӍR6,U D+ H+ ؁TU*륋Urz{q~WcuqTуФऌY$ˎH "    $2   H@%lB& $ ^$H # ^=M  ^ PIl ;ؐ NlHr. K^H#$`   ^$ؐ`'Z! b Zs %$j  $F` 4sX  $l o=s B$t6lsy4 l s6llsTos̢lslߢ*eKHlfD !j̈,v!"&  &5D L[Hr l#L l'#m(0lFM 0lش# |h|V %F | hА    l f̹ H   :Y%А     &  K`@Љ 3 L@ȉ-  d`CT!ilx eZ È 铨0K0Z)ꚸy= ȉ靋&؉ 鼌< uYlr-鸌 l|Z~H "  +  @   ds  $`  0 ?   {A S  !=` Ѐ]<Q < I /@  !ؽ    w S_ء w 7Cw$ D"_w: $w'bѶ鄐w *ҀWww`ɰ wىwt85щₚщOڣn&wʋBwऐD5ꔋ 2[Cċ띌-<"&  (7F  P_*x'P  Ș& Lw (wP'ؾuR{Ȉ QS>  UȠ V  y@ (Aِװ(w x x?^X   v@X3  ط؞0XD    , (X oc 3ّ.W3*&v k3  . )3 @ `/!   3 3ؾx ,(  xD x*[n| Kxc\ZmqN2xxZHx Иx%蘌h* (,:U  Xg V ,| PXXY" ܈  Y+ `{Ȱ   ` ,XW, аe <4lfh\ ,^ -, Єيi    0 E<_ ]nd\ьhUʓЋ+  "1@  O^)   |{  -{(`԰{)(  {Q`8 w# dUH *  q Фu (HJ  H Dz  ( *(  PcHqW  Q JR LR@* UP %l褈+CXKᙉ$@quمŠ?qNj5  "1@ 7g3   6LjЙ27 ډ Й1dk1@2З  fud(  4d  ҹ2    8fB   6?  c0w 4  h2/ 5/̉3f2d/ 53` /F5 ږ /˱۵45 -e  陈FU 8ˉ|̌ݤ;+  .  -ZQYYZ/l؈ /  QY^  荈 ^%^^R/눼  ?IxABx*ؼAI 草u.hȼx3y,I`04ET٧pÛ׋īe)  .=IXgZZRau' N Ra V'N'PQZP''Q 'Q'tukCN833ȜNSB Ȝ'L'ꉭ uu"8Sѭʢ 8 u&5PJ?Nz*  ++:SQYYZVe~,  QY,TSTS,,ܨ,TT,,ܐXY, X܉=T,腈܉d}ST?4VȰAB`SZ ,4W44E`鹉lTX4 ٌ<ٸ U8Gj+ !0?M\)ZZRaz){R RaԨ)  )   - U  (C zH33 ϸB褈˱    r  ,Gٚ   Ø-Ë& qN]jyA  'YZ>SQY ?0 QYABHH   ZZZ9\ZZZZ RRa ZZRaPQZPcQc( Qc(<CaP(ذP(SZkPP<ƈ<܈ (YZ2AZZQY?4 ZZCRaQYABN ZZ33RaNBB 4, NBTT6 Z PQSTZ:QT4fPZ,ZSTTS4  ,Z44BQJUOPQBfPYv &.ZZEE*CRa?Z33Ra ~TB~ * ~Z? ~ YZ Y YZTSTSB; QYYZTTT[|)T3J2YZATLK|YYSTKL|QwVdddZ }L1ȯȉЖT2 ZZYZ, RaQY4 Nn n, 4YnB  n(   Q $ X( n>.CRGP^zY{g   YRZYZ*QQY YQYYZ& Zdnx  ZZYZRaQYi؃  "*PPSv  QY ZZ aZZRa M Xc YZ2 ZZZZQYRav4؂QY    1 PA\krTTTTTUURRT]U8A TSSTVRSm"m8AUUUUSm8@8TSSUU$TS8(BJ     .m <   C   kl   <-       x     R n@@@ - 4/>Z?AAC/l؈ /  ?A^  荈 ^%^^R/눼  SIxTUx*ؼTI 草u.hȼx3y,I`04ET٧pÛ׋īe)  .=IXgCCB@u' N B@ V'N'ՠԠ''ӈ' 'ԉDtN'VN8WWȜNuU ÈLӊ8ꉭuԠꈜѭ蜈Ú 8ꉭ%4JYz*  ++:S?AACVe~,  ?A,Ԡ,,ܨ,,,ܙX X܉=X腈܉dXS4XȰTU` ,4`4E4鹉lذ ٌ<` `8G4j+ !0?M\)CCB@z){R B@Ԩ)  )   - U  (V zHWW ϸU褈˱    r  ,Gٚ   Ø-Ë& qN]jyA  'AC>S?A S0 ?ATUHH   CCC9\CCCC BB@ CCB@ՠԠcӠc( /c((@P(ذP(dЌӑ(᳐PŐPۈ (AC2ACC?AS4 CCVB@?ATUN CCWWB@NBU 4, NB6 Zՠ:4fPZ,Ӡ4  ,:4XBLhXbB, &.CCEE*VB@?CWWB@ ~TU~ * ~C? ~ AC A ACԠB; ?AAC|)2J2ACA2LK|AY2L|?KdKѦد蕉Ԡd CCAC, B@?A4 Nn n, 4AnB  n(   ? $ X( n>.CRGP^zY{g   ABCAC*??A A?AAC& Zdnx  CCACB@?Ai؃  "*v  ?A CC BCCB@ M Xc AC2 CCCC?AB@v4؂?A    1 PA\kr - 4/>Z?AAC/l؈ /  ?A^  荈 ^%^^R/눼  SIxTUx*ؼTI 草u.hȼx3y,I`04ET٧pÛ׋īe)  .=IXgCCB@u' N B@ V'N'"'' 'NtukVN8WWȜN'U Ȝ[L'ꈜuu"8"ѭ_ʢ 8u&5"?Nz*  ++:S?AACVe~,  ?A,"",,ܨ,,,ܙX X܉=9X腈܉dX9S4;XȰTU` ,444E`鹉l4"9, ٌ<S?A S0 ?ATUHH   CCC9\CCCC BB@ CCB@"cc( /c(C@P(WP(P[،P<ƈ<܈ (AC2ACC?AS4 CCVB@?ATUN CCWWB@NBU 4, NB"6 Z 99:["4fPZ,"9  ,4"4XJe"Bfn"v &.CCEE*VB@?CWWB@ ~TU~ * ~C? ~ AC A AC""B; ?AAC"|)2J2ACA92LK|AY9dL|?K;2dЖ ѦЯ蕉KȉЯ9 CCAC, B@?A4 Nn n, 4AnB  n(   ? $ X( n>.CRGP^zY{g   ABCAC*??A A?AAC& Zdnx  CCACB@?Ai؃  "*v  ?A CC BCCB@ M Xc AC2 CCCC?AB@v4؂?A    1 PA\kr - 4/>Z?AAC/l؈ /  ?A^  荈 ^%^^R/눼  SIxTUx*ؼTI 草u.hȼx3y,I`04ET٧pÛ׋īe)  .=IXgCCB@u' N B@ V'N'rmrm''r 'mNt'kVNu8WWȜNøU Ltt. Éu"8tuѭ_ 8 "&58JYz*  ++:S?AACVe~,  ?A,@vv@,,ܨ,w,,ܙvX X܉=wX腈܉dXS4XȰTU` ,t4,44E鹉l4Є@w, ٌS?A S0 ?ATUHH   CCC9\CCCC BB@ CCB@rmrmcrc( mm/c(C@P(<ȰP(.CRGP^zY{g   ABCAC*??A A?AAC& Zdnx  CCACB@?Ai؃  "*mmrmv  ?A CC BCCB@ M Xc AC2 CCCC?AB@v4؂?A    1 PA\kr - 4/>Z?AAC/l؈ /  ?A^  荈 ^%^^R/눼  SIxTUx*ؼTI 草u.hȼx3y,I`04ET٧pÛ׋īe)  .=IXgCCB@u' N B@ V'N'`YZY''` 'YNt'kVNZ8WWȜN[øU Ȝ[L'ꈜuu"8Zѭ_ 8`8&5JYz*  ++:S?AACVe~,  ?A,[\\[,,ܨ,],,ܙ\X X܉=]X腈܉dXS4WXȰTU`W ,444E鹉l4Є[], ٌS?A S0 ?ATUHH   CCC9\CCCC BB@ CCB@`YZYc`c( YY/c(C@P(ZWP([.CRGP^zY{g   ABCAC*??A A?AAC& Zdnx  CCACB@?Ai؃  "*YZYYv  ?A CC BCCB@ M Xc AC2 CCCC?AB@v4؂?A    1 PA\kr - 4/>Z?AAC/l؈ /  ?A^  荈 ^%^^R/눼  SIxTUx*ؼTI 草u.hȼx3y,I`04ET٧pÛ׋īe)  .=IXgCCB@u' N B@ V'N'ZZZ['' '[NNuV QQQP8WWȜNR'U 'L8u[SR. uԸZ[ѭ 8RR%4QSLz*  ++:S?AACVe~,  ?A,\]^^,,܈,,܈X, X܉=؄腈܉d}TUVUS4,UUXȰTU`XUV ,WȰ\4Eٌ鹉l`` ٌ<艌` `8GWUUj+ !0?M\)CCB@z){R B@Ԩ)  )   - U  (V zHWW ϸU褈˱    r  ,Gٚ   Ø-Ë& qN]jyA  'AC>S?A S0 ?ATUHH   CCC9\CCCC BB@ CCB@ZZZ[cc( [c((E@P QQQPWP(Rx茠<[[SR܈ (AC2ACC?AS4 CCVB@?ATUN CCWWB@NBU 4, NB^^6 Z[Z\]:ZZZ[fPZ[ TUUV  XRQQP4TUVU,4RRmQSB &.CCEE*VB@?CWWB@ ~TU~ * ~C? ~ AC A AC\]^^B; ?AAC|)J2ACAKLK|AYTUVUL|?UU2dV K1d\ȉȉȸ CCAC, B@?A4 Nn n, 4AnB  n(   ? $ X( n>.CRGP^zY{g   ABCAC*??A A?AAC& Zdnx  CCACB@?Ai؃  "*QSQPv  ?A CC BCCB@ M Xc AC2 CCCC?AB@v4؂?A    1 PA\kr One way road graphics  '6ETcrΈшш1,ΠM,q,^С,ap '0ш,,2H,,u؍,ш +:IXgv '6ETc33333q'0?1WH與$3BQ`o ш40aш4b4Ɉ؈#2AP_n} '6ETcrΈш/шCш4.I4w4840hv '6ETc333m09H1H|$3BQ`o! Tram track graphics by PikkaBird q       ,   B !, ,XX؜,ЪBXXn     ,$ B6   Y$ H$H$ؤH$׈ $@ '6ERap>=BB- {ڀ@@> ? /> @ ?l{A@A˰@A@     @O @A?S  @ ٹA   v鹈A  B`@A=BK7B>  ? ?  `6 BQHp ɡJxCF  BF` ĈB ߌH ڌ ဨBJ`@> >@ ^  ꛈ?B A$> '6EQ`o=L[j| >>֊ =$ > =P_%>?ۭ>?ˋ> t     >?=A  > ٫?b髈?< >N>?dd <<|d&xشK౸ Z l ? @B>@BDFJR]hs/E[o    %% 88 C Y, o!B#X%n')+-ư/ 1.ɨp @B>@BDFJR]hs/E[o(& $ "   !2400C C.8Y,No*dzȮ м    ߨԨɰL^p@ '6ETcr̈ۈ*9,      l{k BGJ>Btȁ؄|461GJv6x==J@BDFTn=f+@P[fqz %    " *2/ 353f0 K@2 \ g 0c |؂ ,Ј X述ЄA NԈO/P@%ؓJLt BFP"Id sQȥѓ. Xn-' V% /M10!#%' A @B>@BDFTn=f+@P[fqz %    " )1.35/a, eE2 ]  Y^0d | +؇Ȉ ؟@xʸȴ &YZ RST ຈMOJBJIldVnO? ѓx ɫwC  ?UAl @B>@BDFJR]hs)Mt !;S\^`b    %  0 8D . \ \7nPv  Sim Xء Tصaȸ {]FBO'gFHM32L *( _-e ! H/Ʌ ; ɗ11;K)Qȃ y"4  ' l @B>@BDFJR]hs)Mt !;S\^`b(& $ "   )*2 80D L .; \Kl,J vf*ؐ8誸q  =Gا)k舸DIC ЋN L i(, " nIH/?B 7O1ZKC2H; Sm"4s(  @?>@BDFJR]hr"3BLWbkprtv,     / 6  )$  $ =rR UGK ,L nN ؙУ "2<G@2 @B>@BDFRl 2Tp&       456- W2 l0D ,Zy` xح  7ЊФЊ V*PC Ћ8BJ @?>@BDFJR]hr"3BLWbkprtv,(& $ " ! 1% 0?/1; .9L.Ty- -,L LLm^С/ȳ0!*!" # @%8'O2 @B>@BDFHJLNPRTVXZbz .D^v    &,2! D@( #Lq$E{ $ - F/ 1{uЄ x "0j'B( '@RNPRTVZakt} /BTfx ('%$#"2! 1:'/CL.L6-V_,7J*d)n&%!  ;7 DD h pp }яɏɎN @2.0246;FVfv *7>@BD    55 P#P `'  +/صT!%N @2.0246;FVfv *7>@BD' #   01PE-` `)p }% Д!( '@RNPRTVZakt} /BTfx        0-4 :1 CV L8 rhTJȄ J7"7#o$o&Ё'(*)+2,./%h0{!p2 я%ɏ @B>@BDFJR]hs.BUh{(& $ "   !2400C C.8Y,No*dzȮ )'& b )4 FR _k @B>@BDFHQ]m,BXn    & 'V.2(h!= H#%,,'BB)XX+nn-/ 1Ȩ @B>@BDFHQ]m,BXn&+$  "    ! )0 , '  +>t=*s)R(] &,$,BB XX n  N @B>@BDFJR]hs.BUh{    %% 88 C Y, o!B#X%n') +議-' &-M b(c %f'nF @J>EO[i}3I_u(168:<%ʈ$ $ $%##  < G(%$[;; )$; ; 5)+ %; ;   ,/%; ; Ё o;;  7 & !<,#RB%h'~)+-/W1部ɨF @G>EO[i}3I_u(168:<̈̊ Ɍ # ###( .$ &  %%: $$%#$ % %$" % % 1  % % F 2 %%% \0Ё% t.g,},*BXn 밚  İ ԨߨԨɰ} @B>@BDFHJLNPRTV[cn| Ɇ     : %%% :::;%:6 ɐ :%:%; ;; ;%:; ;2:J:; ;;;:;%; ;8:;;; @B>@BDFHJLNPRTV[cn|1ˆ/ˉ-ˌ+ )%';;;&C/ ;&%% ;%;&% % %;&% % ;3&%  %&%%%8(% @B>@BDFLVdv 2X~8Vp 5q i kkkk 5kqq5k( Fkrk50Pk :qqr`q\qkrkqpr@n|kqHЖiq[r5: iLȀk i5rk`:5.*Ștk5r-M5ٌ5kqr_Rikm0ٔkᡤr xqk*Вiqr 5N"iiB$i9x @B>@BDFLVdv 2X~8Vp &5$i k" q kkk* kkqqkk65krqPkq55n8r`5NrkpqZt55qryqrki8kLq5iK5 N5Hslq ~5t;qȾ5k|5^qrqk Eሡmki $qrጡ$5ikk>Д.T"rqib5:ii+ix @B>@BDF[v 8j0^Flq5i!ipkiq    3kkk2 qk5q4= $k55 #5kqrkJq]5G5! qqq5ik*&n'kqq} خ.rmYкr5Чؾ^ ؋iqȅEi6k#2_^k2 irHtakrqi kٜ٭ɳ './1h3X\ޠ[\rE865FUCWcn !k5rk'9( Q nqkk$:qkC<5dkV5"һ&[k5rұ)_r]5k5/r< ipi"iii5qqӮt @B>@BDFZt2d'Qy 6HV`fhj qii" k   58q0 qqk52;  erk5"5k HrMv"#C kqqq5ikrq5Ikqz ت.rmX kkrqؾ +t55@qkq5c *(=iC؏uZ2 ihcْ"#ы krqi i5Ѧuɬ kkkipѲkLrq|[YPiqљBqUk5R qkёiХq!rIiikmQYkV}k? t 5ko@5iqr 5r(iZ$~q(t @B>@BDFZt2d'Qy 6HV`fhj qii" k   q 15.q0 5q56; # rkq5kqqkqrgHr;vEq5! qq5ikkqkv &&F ت qkk5rkk kmr*5о55!X XClii :+> qkq(Оkk6>"6qiqkrq inefqki kwɮQ5i ihqVwq{5 ?fS iRfɤi^Ѵ5rqk Wmki صkqkpR #V ؀kq5O{rrqiZr5niiSi(D @B>@BDFLVdv 2Y8f&68: 55 i q5qrk 55kqqqkkk( FqkqK Pk :<keq(|5k5q\5 rؐkiqRR5e fЖi&k Zr%5k4k iqrk_oq k i`u zq irvCn г-_ 5&kQi ik5OX )kk_Vɰi.W5!C4ْ  5rks\q^ k+rrC&kr-2kr6rkk5 \~&"ұzn qfG r҈ ipi"iii5qqD @B>@BDFLVdv 2Y8f&68: &5$i 5" q  krq5 kkkqqqk5k@2EqkqqZ k,V8r }5Lq5kt5؂К [5qnЖqqiHg5qrz in qr krqi  [x iЇ Ixri _б2P<3k95 [kkk*b5kiz/ [B56d3i Nkr-٧rkrkq (rr*-kk,k>qqU 08r(k5*&.Vjk&55zؾkr q@ |i qq5iii"ipip @B>@BDFLVdv:Xv3DR\bdf ii5 k r qi5qrkk 5kqqqkkk5(i qkqk5q ri 7k55qkq3@,Kl:9kqiid.kq5krVk5k |r"Ti ikqkrq q ki i [b ir,5<eظqjLqi i-qq kiqX5ki  k5q/Oqli sxkq^dbV5i؁{sp}ii$ @B>@BDFZt2d$Jftvxz|~qqiii"ipikqqk  qqi5kq qq k&  5 qqqk5q;k5M]* erkq"5k tCE rq#k cqqq5ikk.rx& q.rm=[qd"krrkk5 &5kl,Ti3i5 \qqr55P7iiiC.^,24rrdLrqi i; 5rre k]r5i i0k[]@2iiliq-Rqii4\? 5iiiqikip5k$6>Fp @B>@BDFLVdv:Xv3DR\bdf&ii$ 5"iq rk kkrq5i 5kkkqqqk5ir q5kq kqq-qkq/q5KPiqk32lNY5Yk kTk5qr 5Isii)Nik qrkiil  X}=0k r<؋~kk5ieG q?-x k5q iilq*/XrMAhuye%fi=~miibskr iigd0"7rr$i$X @B>@BDFHJLNPRTVXbzLz $:JLNiiik5piii55krqqqkkk5kkii   qilii5kqrq5q) qqi i5CkkM7k-+i iq*UPk! kST6ii.U*kkkГc2k`.q(rkkq21 2 X*5q mA>&r.v5Z5kqn1*8'kq}ұsؾqk ؖipi" t '@RNPRTV[dp>^~>^~*=LXafhj'i%<i$i p#l klpp5!ip$555< .#R85qTi Bkq-lkn<p&Lpk6F<VklkMpqppi]:yE }pqkq`5> nADkHqpfg *kx5xJU5qekඐp5FFl5k^~>^~*=LXafhj  kkil  llllmr mllqk".li kkl8lq Mlq.qqqNUle]qqlklrlLi0\,kl"pVir|،0] /[q` irlrm ip}԰ rrؐаmll/mis<\$nmrrrlа~My@lmqk0qrٜiПki@kqqp.klkk ``m?kppLlq Oqq ᶹڠkkiѭȬrkk!~rl#M% @B>@BDFLVdv 2X~/Lf| &5$i q"   kkkq k5k5qkkkk6kqqqPrq.k8r`bkrКЂqn5ZE5*zyk5qrq5Oi蹰kr5i5Șې 5 5q q?5kr+ȅ kq krqPqqow55k H&3&W} k dak mki  k`5ik9k  B'  qrqi@ ^r5ig @B>@BDFHR`rAf >Xnkki  ii kq55 + #qi kkrq*k kk5krkqq rk kqqqkrkkkkr: q:;kqq5[ks 5ȁr!5kqB"k qk5prqr%k 5q薸rkGȋȩ\[mϠ5q5ik5r55&`-_Aikm'qqki'هk!xikkoqkiqrc SQ"ii$i` @B>@BDFHR`rAf >Xn $ikk "ii   5 q5k  q% k8*qkkqqkrqq1k5rkkkk k5qk krik: qqkk5qqk=>qs ;5$ȝ5!rq5E5kqk襰$qq55ȋȠ~ 5krȃkq @55k5qqq55k9*Kk W@mki [YȲ@5ikrȀДkЪQsrqi_5iii` @B>@BDFLVdv 2X~/Lf| 5q i qkkk 5kkkq5k5k( Fkr-0Pk : qqqqqrkqq`q\Apr@RЂB5HЖi[i5O: iI5q跰5k i5kk(kq_ݸ.k5@^rrk5T q q5k5erprb5rk] Gikmv  kkء}e k qn52k;) iqr 5k  5+ H#i g@ "ʈ*9H> BʈBv> A?Bк{ %#B  %##B6E B@$Ɖyt=B%# %$B;;uB D $B; @زBB%; 6C  %; 6Ђ{;;;ڔ6):@ٔB/B؇6꫙xJ ٲnBA$^eƉβBjˀő¹QR¬lvZBnv 6|t2ÉxMex696l{x6ž p3Bds쏯@ "1@>> Bp> A>#@ ؂ƈ|###  *9$@|l{%%к$$%#< >F% %>$>ƉΉ% %>ض9|͊ %௸~> Q tʃ%%%|щJ>l% t| hu6Ϋ;rˑѝZ>t|QB$xNB+ '|أ ̙Bh~B >*\>|ɍB&SɶvJxیʍՈJF6EʎJzJ譀ֺվR,;JBq缘 ̈˨ɘ6#$###6$(%%6$$%(% %$% %< %Yu%%%ȁxux(us /-/  -.,- d,s>RPu+ @B>@BDFHQby8Up !    =<< ;{{ +90 < '6ETcr ψވ< -x  \k  ٺ :  ܉   < +@=Xgv Ѐ>NJ rȀ  ?ʊْ( $tDSb4؀ 8t>΋Ѐt   949郌>M\ Y"< }- "Y9% <ʣ%? ""  "<%% d ";@:IXYY"@99n""Y@9 |`" ""@<| >  ,IY Y> =@C4|  B *ȴ] Y"YH?H{Bi<m{}E@ #x?<(€xu€:k{|js@A@찈t˓zʋ6Kʊ{H:{{. @B>@BDFHTe|;Xs "$&+<<$   {{H<" &* KJJ 1"  LJKJ8=D LKK$C $,#"KKLHH "!AeKK+cb<^*Ь9z(s& 1$G(, ]%B s  F@> '6ETcr ߈< @,;x @jy  > @ < ,;@=hw Ѐ> NJ 4Ѐ  ?ڊ %44ش芋Tcrt8t>ދtt+  949 \ Y"<  "Y9% <>٤?"""<%% ( ";@HWʤ YY"@99  ""Y@92< |Y" ""@|   >| =@C Y Y>h<  | $HH@{ KK| Y @^< Y< ?<*@x> ؍Z빘~x >< |4 xx  Kw >BxJox  z:x?Oyx{J,?<KJ=xHxhJ{{H<K{yx< @@A{<{{x{|̠@|xxJ{͈@{{*xx>@'hxO؟Љ=JvxyJ|ـ਴K<ѧ@Xж>?th}>ྈ6LL3v@oL4&LJqѩ~,E.8m迈xKw$<$@.16>ػ|7,غV,YLLtҚK<щ6XͷЏ˯HyB!n{HM@> '6ETcr̈ۈ&5DSbqˉډ%4CRap < @Њߘx @ O^m > ӫ@ < T  @| @=<  Ѐ> [,4Ѐ  =@C  < 鎌͉tЀ?H @{ KK tt8H@<GV&ȴt@x>t < |  94 9 Kw  Y"<2 ȎA "Y9%?<KJ??"""< %%<K{鹎 ";@J*xKJ{z C<YY"@99{{H{<{x ?<  ""Y@9JJ{~x|Y" ""@9xrx |D >|99!"xx `Y Y>\sx?OyxF zxx|D Yx< HF@4܋hx<J{{H~{@ xx>?H{Bٓh/{}E=J>?@xypJ|5਴K<>XжruxD4иJ9Hh}6-t ྸ,2:G6LL3v56OL4&@nt8K؅JJLJqѩ~,%ѪB}Hr趹m迸<@ػ '6ETcr̈ۈ&5DSbqˉډ%4CRap < ϊފx  +  \ج :      < ܸ͋< @=x Ѐ>njL =@ rȀ  ? <r ƌ|< Ѐt K  949郍 ^ > Y"<Pw@OHJ?  "Y9% <{<|{{H ""  "<%%IJ{KK: ";@0 eJ{<{YY"@99@m JJ{""Y@9∈@^޸{<|`" ""@9㭠=2=. >|99|Y Y>  :| ȀH<@t! YH?H{Bi<KJ=|{}E@ cx=J?xyJ|€៨K<>€жr39?Ģt9HكxyI|мt ྸ,ٱ:?@6LL3v56 L4&9Ȭ8 JJLJqѩ~,6BFJNRVZ^bfjnrvz~     &    ! :# 8 % 6-'!40%) 2 + 0 -3 ,/I *1_g (3!3&#/)"%t'( )З  , 0@`behknqtz} '.6>BFJNRVZ^bfjnrvz~"$&(*,).0)@2'4%6#38! : 3 1 /+  -6 !+  7)  '  % f#  Q!  grI_% )  $, 0@ '6ETcr>GLjws0? l{Jtt󉲊 Ί> ׊z)R. 犔B>֊P c߳" (*6 J'V˪16 VZx6Jɔ 6ʹJR,k6J)ɮ̲!5ʶ1Os͈JƊBu9ÀG¤ƀÀ6E p@􍀏򉀏@Էɏ؈@ݏ@T 0@`bhntz2Kar "&*.26:>BFJ"$&(*-,).0  +2 '4 %6 ##38 ! :  3 J !14%GU #/L4Lnn%- yeK'O+m  ) 24 &0 T3 (Ȁ,48*4S(8vn )"'= )  ,T 0@`bhntz2Kar "&*.26:>BFJ"$&(*-,).0  +2 '4 %6 ##38 ! :  3  M !1U:G X #/`L  q%-yeH'L+m  ) ؼ *, V Ё$,Я?GW["n ~%ю=c   $,\ 0@`bhntz);Le|"&*.26:>BFJNR"$&(* ,).'0 )2 @ '4  %6` #38@! : 3 !14 = #/B4B_%- j B'F+_  ) 24 z '0  U3 lȄ,4 *4 (DtZi#)".G 2  ,\ 0@`bhntz);Le|"&*.26:>BFJNR"$&(*H(,.&0 2 $4 26 "8 0:     ! . =  # B o % ,j B'  أ ) ا 轠&+  R-3}k/Ю"*1>(3!iZ h#`)'%B9'X  .2  , 0@d`dhlptx|  $4. 0@p`bekntw}.;KRblw       -B   R    0    \ 7D r Q 腸 7讨T q*԰ؕ   v k  !(  8< 0@`bhntz>Ri} "$&(*-,).0  12 4 6 38:  1<  - ?`=*,)xuri:V j)j  % +  W@  0@m`bekntw}.;KRblw"$& (*,).0*2* )4(6 '38&:!%4< $ 4:  ;#8 " 6! 4 k4 D4 7 T4q4q(J &$ط)И(1 )  )k  $(` 0@d`bdfhjlnprtvxz| 6Vj"&*.26:>BFJNRV < S    "$&(*,.02468:Z bW8hb%p4 {2   g  %3x)~*- Ȧ  (1 &  ) <JV  \,8 D LP $(z 8@tptx| $,48<@DHLPTVXZ\^`bdfhjlnp  $ <  $  8d0PT Nj 0@d`dhlptx $(,048<@DFHJLNPRTVXZ\^`   <   (88   @$<<8脈 $ 8j 0@d`dhlptx $(,048<@DFHJLNPRTVXZ\^`    L@@BDFJR]hq|    # 28 7 E P[fqqmeZ  @B>@BDFJR]hq|(& $ " ""2"107".:,E*Pg[nfqqqm" @B>@BDFLVdt$6FT`jrx|~ 5q i kkkk kqq5k& @krk5*q .qqr]Hqkrkq\Rd`kqqq=ryi i2жhr i5j.k5\qxk55kqrrikmk[kq>F @B>@BDFLVdt$6FT`jrx|~ &5$i k" q" kkk"kkqqk"*5krkN""q5'Z"D56rkd"qF 0@_`bdfhjlnprtvxz|~@  zN^l 0@c`bdfhjlnprvz~    ! # $    RbpȀ 0@c`bdfhjlnprvz~)'%#!  3 1 / -$+ ) '% RbpȀ 0@_`bdfhjlnprtvxz|~@-/13z#%')N^lj 0@d`dhlptx| $,4<DFHJLNPRTVXZ\^`  $  <  08@<x 6j 0@d`dhlptx| $,4<DFHJLNPRTVXZ\^`  $  <  08@<x 6j 0@d`dhlptx| $,4<DFHJLNPRTVXZ\^`  $  <  08@<x 6j 0@d`dhlptx| $,4<DFHJLNPRTVXZ\^`  $  <  08@<x 6j 0@d`dhlptx| $,4<DFHJLNPRTVXZ\^`  $  <  08@<x 6j 0@d`dhlptx| $,4<DFHJLNPRTVXZ\^`  $  <  08@<x 6j 0@d`dhlptx| $,4<DFHJLNPRTVXZ\^`  $  <  08@<x 6 0@d`dhlptx|  $4. 0@d`dhlptx|  $4. 0@d`dhlptx|  $4. 0@_`bdfhjlnprtvxz|~@.@BDFKTar"Df (?Ralsvxz q  kkkkkqq5k& Akrk5.L 7qqr\Xqkrkqlr؊ zukqCЎ Qr5 Dkqr"ȈȈfFr/5k55env^prvٽjqkЁ!t#%'q8 @B>@BDFKTar"Df (?Ralsvxz'% k# q! kkkkkqqk35krkULkq53irr\5Krk}}qWp5x5qrq胸ȯkrkD 5@gQ* _5V qȪ \5q y>f qrhkqkakq8 '@RNPRTVZalz8Qk 9Sm('i%p$klpp5# 555<")p 35qN=kq*lkfFfk1uKqk`kKȊ-g8ȳqkqMJ<5lM5kqp<qMlЛl$5<NqpW s'*k5ki5iK5q[k; .k<]qpا5kV+~y<5qpq-l5p]p5!Z%p @2.0246;FWn1Vu' #  i lllklrqlrll4q<=llsW"l"'q B$Q zq %,Sgmtqqm Xr '@RNPRTVZalz8Qk 9Sm k l  lllmr llqk * kkl4 Eklq*qqqHO UlklrlF `lkl"c hwM ȢlHqqlrmNd谰grrrشmllmgI3rr.hk47hmqkزqrOOٔ6OɯkqqpOOkk0kٜOmkpp N!mi "'kk$rkk%8rl&c( ƒ 6 Missing shore tile graphics for the temperate climate @ AA@@AA#2APRSTSmSSTTSRRmgv TRRQQSQQRTU>SRCQQQZZRZ@RZGSRQSPP>S51GJ6SOSYQQPP4;r6SZTZKQKTOEwf_b-мح7S?TQQЉءȁCa(!.C!uEBS].7SRCQQQZZRZ@RZGSRQSPP>S51GJ6SOSYQQPP4;r6SZTZKQKTOEwf_b-мح7S?TQQЉSTZgS?83!SaTmT1MPE4SRZ@l?RɒhsCR)T\#QISZS QiT饡Z4N<.ZS# oZ RQ!>^uMѝV|BJ)~Mطψ|@ЧBy/{ T=Ἁ6eCt;xRRC1J؈|rYl2ARٳds֊药 /@ QS!0?NZZSZTZcr?TTSSZ?TTSTZST@STBZĉ5DU|}hw:SؽDESFS ZZQ 6CESA:{y>ц{4{؂L@NQKȼȰU?FZZ|@ZTᓋ9ZZsBچ ZQ/б R٩0SSM7/3ѯ>ؽI SZ2SvкSQTTU땉4w?=TSقUTU)&:ȻQGDWаؐ*SS1س~:ɵU[UQ(șҵ/wkZZSOVQ_#@>сGKѷ3Nھ1$-QnFP0uw8ŌRvS\̹2HLONn۷x˃۝pݲq Tw{}1̀Aӝї4ݾ>ֹmq@Ə݈ ј軏9AϿ ٛDڶmzBFUTVʏ<RTSRUT]VTT3U?BIV}RRR?@脏ҮW؀SRϧm"͏8"@ ZQS!0?NRRSZTZcr>@VTQRTTTST:>QZTZSJ'6E>; ZRSTSVS SVGvQZSTZQZcVTVTTT胉tS{ZZ;ESʉZoyZQRQzTV:tQu|Z^OSDSɊ{7ESSىl;S6>:F.v1TG<T TSI1lصZQ/QSTUBVSTVS&T+/URQT]dt33Z<:SQBT ?BZQMн STVVV T]됋гC~ZQ1>QTSUvTF WSUSRz}>VTQTSRR}ڈ @yV VR"m8AzZTѳ]V? R8AAA?TZzѳTUڈ =u,y:BBEUw ᚎBB8GAgv 팏 '@ RRQR"1@>SSTTRBr>ZZRBQRTTTAQTTQZSRQ>9QZZFSB6E>ZTSQR;S QxTZQZS؈SZJt8ZSAQZLZT8:RQATQE=2/|Qщ1ZzQZEQST R.s)SZ鐊.v1  TSꖫ?Q/tQنJ&TU1Z 5GQDQR 697et#J0.5ؼTS()^SZ?e(rMJ]G*}؁؃un>Zؗ?؂؞ok, TOZ٢HO`QS?GM%ܙxF+|SSZTSۍG\u}A2 1Zې 4tm?ۓsGMB؍ɎٰĹ ј軈ʍ83 />tܵEnm|wܲ sTUɂUTV >3TSUT]VTT3U1B苏VoRR?@L؀Sm"8"@ QQR"1@OPQQTTRBr?RZQSZRB ZRQQZTTQZSRQؼZQ?QZZTSZZSB6ERZQSSTZ芉x:{?ZSQZ 9?ASTS ƉΉZ~C Ί?4R3QTTTTJ镊t4s|RRSTZI͉syZ<T Z鐊x|4ɹ{AwE4QRQQDs}RZQQZ@FQZR>RE@E;6S؍Z@~Z~SA։V:<CFRSPSQRΉV9}9R1K蜉ݹ4yBMɉOxwRؽهZSQZSRZ4={Ȃ±ѱ8 ؇ةxЦ3ٳQ}ɵ*цكMUUi@чȶꅋ²t,tQفꐉxmة-MʑaDs2=-Q갺㑌P8:‚۝jpC;/tۣt =SjrSQ@/yx쌍J{@8m",8͹A@8TЮڠ|CȨSTS`&Z7P40u?EvEZQ(iRD$/>l{V~ @o@DL\v2t*b$Nv*>P`lv~AmRTUVAA88@mRRQTTTTTT@A88@A@ QQQQTZSTVUTSSAAmAARS# SSSTTVTTSTVVURA88%S#ZQfSTS,+Z RAmmATTUV-QZZQ3 QTSZVS7rSSmg8AmUQRSZRZ عVSU>U{ TVSRS":D"Sز~QT SR8AAFR~E1TUc'S"m>@@m""?QZRSQZ`TUV]U8x`Ʌt{TSVUVT]@tTRФ Z].CqcRRjѠTVMSg Sm'34 MUUUS38AU [58 ySUlTAAAA-x 5 TV]VU@@ɢaQQ PP^NmUڇڍJu UU@@mm@@Tɰn$!ѠTmRHHA@"ـH8oZ}ZZDLTAST]bRQ m@zQ88mRW@@A"TSA""@SAmmS8@ QS!0?NZZSZTZcr?TTSSZ?TTSTZST@STBZĉ5DU|}hw:SؽDESFS ZZQ 6CESA:{y>ц{4{؂L@NKȼȰ=UU?F?UTUVx; JUVLTTU֋s?AѺUTVMTڄSQUS~RR=UT]GAVqRSi?BsTUASRSأVS$+R.0="@VJ肉sRmc}@GRRm8mR"R"mmm"fVSTAAA"dTU# mmTSm888AC8m mA @m@@@AAm@A@R,L8e @RmAm"""?%B-7 @8jkUm8}A8;88@c8 mmm8@" 88"8@8"J !,@ASRȀ=SRQRAATUY@8Rky?RTm@8mm]QQZZRZQJZQSQQDGZ6;A:ITQ;r͈w 7 Missing shore tile graphics for the sub-arctic climate @ AA@@AA#2AP"m"mgv3""FHws="[Dг4""/x"[w$ژ"y[&87 [Г[lOa HZC[3n"Ԉ_.jه["ЈKػ\͹z2}zO;Mj2_Dدڊꁊ9HV;s͈w@ "1@O9Aq; ;9"$9<9y8$e"<99;:E& _5гm:v 99_999;%9";F* [ _9:%_?H9g;p9::e9:9<99ɱ-dw9_:$d}{]99 ;< _ɐ&_$_eQߊ 9C ֊Ι:8 : 9&C;;]_;鎋Q; |%r;9; {_9]e_ؠ$Ӫ ;br$% R:YL9 9;;_&]"`%Vo:" b{:%@e^㝋Q1-T"9 Q;_M$Je ܃_F]%;%}q6&:$L%\"""A@ۄ"$%!$?A$W%$Je"mA= ;P`WB9%Ȏ¶[99eEHw 9x괈9HĈt*@ AA@@AA#2AP"8mgv""A" w+="[A"C"ODسkBHy""4ȳ/q"[w$-"y[&87 [I8?ؓ[~`"7"s[6[P-"ZB?I[L"v[@@[9 [[ ""[b2 i>BS}J*1c[[#;[_m<"ᅐ|I4ptV:%>Bp}r~ؔD|A'Bi}ƈ!JJ`6eVꂉt:Ak=tIzٵȶ߉ yR ؊l3BRꗊr։ /@^bjt$FjJ~,l*d2^2Ldx[[%"9"99"[9 9' 9[""9[[[9[T"$"% ""[Z""9J [d9N[""3""s<*"][;W9c&O[[z9"O9 FK[B [m&[5 [9 9%99+{.% ["' 9&9O9"0PQI>""ȯrr"U[mT $fec [9J"9|"K%M#9Q:"%:}! MKXpz<j9>bc_[[[Hkѳ:[<H""#B)w"Ѕ99[["هg etڭЇc}8U[$ښJ7 ~phRC[[R[*{R:ٱ_p)؞ vv> ۺvHܺL" "jj&"j۔9Љܰr4"fu..:.dd,nݖ|"6" 6&[6<8"N A@"8@A@ "1@O[Ap>"@9|?"9e"к "[[_4C>"""[99";Fv6"=[\999t|[ 9>99ɉ6 "_9$;8<[؂9F999_Ɋxt"[">؃~9&_ ["I 9EIɒ/""A:&0{3E9_Ae9;鎋Q|1[[E""9% :Ꮫt[[38"A@:]e__MMQ.I? [{; : Bw[9 _&9 I;%VBـʻ:"; C???w9ePҔʀ<=[~"9 ;_M"Bq>"""B<["d ƈ ""[[Z[[B5D>""[;[x| "Z"E9Mtu=[[ZΉ6[[d["#ZΊ=.[d"[{O""Jƙt1{*#9Qᑈƨ]uZ"#>RJl/-O?"_\3""Z{-Z"ڂ""$Z"["Zdn= "[#G[Zډ\FZ0l[1F""_"dq9$$9$Q[9W[?"9oZDH}لlچ2"&K&?БC9kw>99G9K"D?[bk %%>bg9o["<%a%=[ 9{ 4%~G9%9"9ق\"%A[ر?"EBML  :Gx@69^[`gH퉉eM㔏/>ی zANJsD[XtLEЏш&nz҉98mBB@ "1@OBq?["¨"[ƈ> "[7F9 ""x< ""[[>AA"Ɖ;>[[>""}F"[[["Ί9~" ?"{鐊։}<"A?[[L} "["؂蔋Z9:"Dk;v=  u; )"[<>[ђq5c>錛V/u2L̊o6=}@ؼ듓uNt9@O2;:Aj{ㅊZAပR@8mg}Ё}鎍A@8ضou냍J"Є|Ԁt8Ds}CEм""@芈D >[@~؊""[͉xsFAK V09= E"O"[.x|P韊?4~N"ɊZ9G؂x"0ن yAب~zȽCq<Ȕ9}&ٯщ~U9ٝ4"6Dڐu.Ex^с)tټs4ҧ%;7ᦫ5ȌĦu&71B ͢*+qI:Z*D.z@8mF1ݻA@8U/tۢȵ`Є1۶7>[$¸DEvE["䍎cSюŽD 2A*@pw @ !0?NAmcr AA88@mD";9"@A88@A@<999AAmAA"ED=<99;?A88A}A?[Dwt:w999t9AmmA؀ ""[ "[ _9:%_?_M 8Am"U;_tu_:9Am8"9C"B "["9+3?EJq_6_9]99 "m@@m"Ї"Z<&_$_8A@H1y %;9@п萚:x%<< CO;"}; ?AAA7;AAmu" 5;:=C@@A}v;9e;A{@m;~ټ_N @@mm@@xA:mF9=}>?A@uzLe_8@yG;?A/AyB+:IK>ixm@@@밈?88m~@A"3B~dsA@m@A @l>BJT`p&Jr*^ L$F`p[[%"9"99"[99' 9[""9[[[9[T"$"% ""[Z""9J [d9N[""3""s<*"][;W9c&O[[z9"O9 FK[B [m&[5 [9 9%99+{.% ["' 9&9O9"jp""!&2k(]me2E" mv#m~A8zc)c "m@AAAA@88 8J A`Em"mm@9?(09@@.C`8A^@88@A8m8m mm@@868'/ح   *,|||||@Amz@A 8@|&8m7"68+""H5DV"N2 9 Missing shore tile graphics for the sub-tropical climate @ AA@@AA#2AP YYZY\\Z\Z gv;ZZZ Ew=Y[Y`?`JDس`Z6:~ЂZBؒ`T/ضx[ VȳY+,%78Y[`g["[jlb௘ϘB  ư4K΢Wnj<Ί.rCƊό62ARn}Ҕ; /@^bjt$FjJ~,l*d2^2LdxZ[Z[\[[ZZ\^[]\ZZZ\]][[[\][\\[\ \[Z#[ZZ Z\Z[Z8D\[:-Z[\BZ$i+`]AC葸Z.X2&ئEZe\]\Z^]]Z [؂Z r[ []^]]49$1^]Z .i[%QCS\^ن2ѰZٰؕZs E$C\[ĉmpK`K=Cjzr=*8]ڻ[[YO& HҩY؂\w f[[A k>~4tXdwۋ滬R-CRR긺?vvṿ̋̌jjjT..dd S\݆&Z[S[[<ZR[\RZA@Y[YZ@A@ YZ\!0?>ZZ[]\[cr>Z\[]^[Z[?\]W][?A\\]\\\5D>ZW\]\^vtZ\[?]ty>ĉ68[]]^\W :ɲwF]\W zv4ZZz~E^LID ɉ:،Ί.stzWp8W]WG1I邱^\ГԈZ^B^ ԉ[< Ռhꃺ ^ꒌ@8òKA^Ţً Ҿ][j}BʾZ8@BҾ뉪8@AۃuO\\Y=>ڷʎ|AԉQŒrɾʎW6E=lr '@ YZZY"1@>Z[Z[Bq|Z\[¸\Z[?Z ƈ?\CĈB5D>u[؈Jy6zG[[Zωк؈ωΉ68<[Ќϊ.,{ĉΉqJпĈƉİXĠX\᪱HZ2ydٚڨڲLLZy]\]][]3H]qZZ ?a&]8^[]A?]\\PT[Z}°؊\]%?Ag]%Z[]sy듰%}B0&\^A%?Fw锈\%Ѓ]^]l[%A $}$E3:G$h3`ڍʹXҍ⹊f<|4{Eַz L/2/GǏNj8mB@ `ZY"1@>`@Bq}`YZ[Z[˜YA\Z[\ƈYZYZZ؃7F9YAD[[Ex`肉Y`J<[\H>x?YZ?[ R7Z{A x|ѽ[:Bwɀف? [ؽɀZмC 9ZZyؼG? Z`?y} ړZ>A498ұ:4x9؉R@8m"̿A@87<Č.۾5wJzӼ?0?Bq@ YYYY#2AP ZZ``YYY[Du}`Y@`Z ZмZ7?@ID .Z[Ђ[@}Y`Z~؊[͉~=ȇ ؐ 9>FZ`T͊9? YZa??Ќ`Z}x{u6 ϊ{ZYyZعcaG<pAJx5ٱtY:~tmt4/tȚs*tNɶttԧ Ұtt/ˬjgtx@8m"`Y9 ݻA@@8`1yz y|`![К)8(bQhwm[ZYКðBD/-<:[Pcr~~ @ !0?NmRcr[\]8AA@mRY`[\\^][[[Z@A@A@YZYY[``Z<]]]\ZR[[AAA[[Y[\CBZ<>]\E\[Y\A8A\ZZ[`ZBDY`tȳ\^\]|[[UC [AmmAS\Z9YZ?J`` [\[W\]\^W]]I{Z? [[mA8Am[w; Yg\W\?H^Z}Z"8mA8"=F~?ZY1]]^WZZAA8؇ѹs^\]<]ZY"m8@@mp5:Zo }[?A8h{6ER^]?A؅ ϣ;;~SZZmA@?Z{賹;>Z~?0[BRADYоrHB\AAAZ\A|؂88@,t9]mA@m`Yt6YZ@@m@@hhtL>[;@mZYt0?ܸ^\YZ[A@">to~L5??^[YRZZC|₉:8G[SNix[\Tm@@@"8Z@A"3BTA"@mr?8@ Z[!0?NZ[\[[Zcr}\^[]\ZA?]][[[\]Ĉ\\[\?\ĉ4CRz[ZZ Z\v?Z>B\[ȉ9Z\9uC}|,;6[Z] {4tyH茊Lұx\]Kȼ]]Ή<}Љ N4v\s^]rozZZ^}=Bٕ%ȼYYR[SZYRلZOTRұYYnGQZR[T$\YY]x?YRGYKRR""mm"REZ\"'"m"LP YmmYZm888A88C[ Sழ [@AAAAm@Y, 8"R mR"8m][<@>D-5[@@.Z[}Ae@88@#8m8m 2mm@@88ح$8$"&?B=@3mSm@<8@8sm@8mZPE\Z^\Q36A[YBAꥎM<:IE|YZڏgvw 4 Missing shore tile graphics for the toyland climate @ ?@@@@@#2A<A@BADr ;GB?A D<  DدoAA =A@?4* E A 輘# BA؁ ,TSRRRRR$S#ST6 Ȁ<0 ST [["A =SDST[[].T؅BaQyQj[[\\]\]EȓST\\R;=;C[ADш<8GͱAuD*@ 24444"1@<44E42cr]]^^^]E>肈AU=_^_A_><VVVVWW~CB'6UW=BAE\ABW\]ø4E ,^]Aø ]_44  BmkAE|4>ЀWؽAADEE?EEEEGȽ<>AĈ<; ԊLTBႨ҅BŨ X@Ћ©;42WA BVl?RR@C؂C@ϋԋQEԌԌ ~|A^^ՀӎB2뷹:˾ÎQ.Ѽ ԅA9Hčp@@ ?@@@@@#2A<A@BADr ;GB?A D<  DدoAA =A@?4* E A 輘# BA؁    TTT[ [TS0\[B>SSRSBB> >@>RTSTD؄N | >|}RR脸U|>mCg RBETT\p >BTC[\]]B |>^]B"|=B،Bt;B y|Ċ-VUWĉ2AȀsё]\:؄V\]\]]]]\>}?^]],;?>мm|^}\ؼ{^؂F Ċ;,ꁠS\4@~⏋R/м@R4мلSnt\>U>.x ,>ŰW ,> "V }? \.W? )VU #S>#> p ˀ"ȼV2>a P ` p r 44،0?c ȴЀ  4222 . 22,Р 224ȡ2ټ-A bPArE SnA -B?pO2EQ/a4Ě}`QV 7&22B-!HȬnأBxABĐxȝ2BAم3E}GQ АqĺD,.Ɂ!߈G2QBʟ9шQ-C 4xL#!4 mB!QQE؋Q֋QrԓыΓ̏B@ ?AB24"1@>BB@2cr|A@AB耈AABAAE\[=ȀAB'6E[\]]B4v>]]^]B@@E |=B@  BRRSTB>:>TSSBBAx|S}TSRЃĈ|~SD B|EEEG=RAETсBT@E L>=@BlT JE2@<Γᄚ@;42 BPVx?QRR<1؂B@@ ϋ}KԌɽPQ ~|R>?ÎQЮ?Ѽ >A7FBu@ '@ SRSR"1@OTTSBq|}>R|SSDƈ\[=ETT\[\[*9H[\]]BTCBy>^]BR}|=BΉlخD=R|٬p |MU   B Z> BN    44^bନR@ G4222POY22^ 224q2 ?-A .?AE Sn>A, -B>?pb2 ЌE Q/a4İ?}`QVd7&9B-!HȬnأBxABĐxȝ2BAم3E}GV АqĺD,.Ɂ߈G2Bʟ9ш- # 4xL ¿!=BNm|~mBېQēQEQQrыB@ ??@"1@>A@BAABr}@@@BB˜?A=BB}BB\[\[*9H}}B[\]]Bw}}>^]BAA|=BTR? AB>SSRSB@? ؀>TDt=?|}BRR9@فB}SUD芉0w<ȀEȊ5:º:CB⁲}/Sm@BA?ؾ~Ђ‹Rq@A| >⁢4ҿ~D/o@F/ڱ.xŠ/rB>z*A}̀5s} <Byű}?  @ۊO<>2A:Br@ ?@@?#2A>A@@@@Du} @BBABAAZ[[[ZZؼA@AB@>\AD BAZ>\[ZSRSRQ4C}Bؼ~TSRRAQ͉z>z}RSSRTCT>Aؼ:>T? AA@мC? ؀;м}=?=;|T?@AA O:όх@.5BDxm0B?}CTRQ/}زATSm~Ђ B-A| }З<94ҿWӅT/@A/ڱx}/m˯rBA@.DAZڰծECȊ44}A s}? C@??BҎŽOzB2AP@q~~ @ !0?N222?cr< 4442BAA@A@@D  E4EB@BABAB ȳ=A 2|2@A A D<س4EE~CEBAB? AΉг2E=BA B~z ~B  ABE A~ }@OBC mA z ؼ:>Bm.rE23~Гɓl 2B@мؔЭ؃D;Jк༚1E?QBAB2O<>QB?mх@}2BlBBႨ A?}CB@?ځ@ < @}:۳x BAA/25B2B742Eĉ2AȀsё :؄4  >}  ,;?C мm|  ؼ{ F ;4 >~2QRؐ/ȼSnt >2>.xl.ŰWѬ>4G0.E2 EE SڕꞲs2AAAABAB 2 .?A" 9&B@BBBER@T^,   . T@@b@B "#B42r/8 .LEa?y?y\  EL[Rv)\z)U Рz)4\z\#zz\Ozt{\zn\󰣠\znDz\nzc\\虗\ nz):ꈸ\ٗ܈):z\׳.\z.:5,.Z֋Y/ ) --9T-`{I-I-sJvZw-[Zeمډ T*  /& LL&uL&)]&N]L_&&L&MLnLLj򈘊-<*  +9U VdP+ S+ vLw++W L .θ%LЁL㉴L:܈L6 3L/ᐊL/ɐЂ@X+ `^7*,ɱL؂L 㺌6E\j.ĺA!  / B b@_c_ ň_Lj\ĉ|iYÊYYY'6R !   %3%" c%uoJoooߨo މ$\ "   D f !౉>n>aj׉ˊ̈Ԋ@^|Ԋ|̱ԋ0 )!H!fB|׈Ӊ1O^mddljdd0]7{H   >I]IggIHڈH5>  *<5!5BkVk5表6ˆ, =L:eWˆˆˆ߈߈ˆ‰8GVeg݉ ()FFFcFF Extra airport graphics@ "1@Ods :B膈>}HC*9|y:臈Bxtz~}>x9B҉ѻ ЈؖΙt}ѻXt|ٰ}>؉Ι6طȖ#ȸ؜fꚫdȃᲱ{ҕ6n4~ٻ4٨`GCXZqٿ˘e$L؊ǫQaFRѨѺ䰽;RٻhCȾR@>>­u}ˍRBʭqÍԐjѻۀݶI.=H똎l{R9;Ä(/.2AC롏ds&@ "1@OCds ### ƈ  "$ "*9>BBz6AEB A  #Ɖ{  BFGA " $"T26 BЂC ֊t6辸B6ȄHR[_#.lhHЎ頩t.n6{ KЉJf1n bؽ7?#Ba##B' 3˪ A Xj]Yяj.0 ١p*##/zаـRY.e7x|e}Ѭ0[Xh0ۋ֍##R.=me؅Il{6w2Adlrd @U>DN\n.\<~,^6L^lv" ## #." $";.QBW^` !&y@ #?  *؝%%؀SQ  *+rБQ .1YR##ر&`諰Ҹ_ #SPWȖma(@QSh* ؝@|SQ" с ## Mٌѡ) #* ##]o}ɒюѾ;gXٳ)S:؁&٣|qbOwpj٧ѐ: -2PЌhs ڸ%1nOQ$|tUɁFr##⧢AʘAۼo`b8@ "1@OCds RR #ƈ " $"lj*9>BBz6AEB ## AK   BFGAK26 BЂCPt6辸Bᘉ6ȄHI#'lw< dt< SYB.?t?K VTؽ7Bb6+ #B##B2ٳЩX˪e[EʹJF#f|elu}>Ȅ0٦ٴҎZp&UBڴۋY­.e7xыae܇Ӈ[X2Oۋ֍##R.=me؅Il{¹񫮎2Adrd @G>DN\n.\<~,^6L^lv"  ## #+ " $"5-=H FVR ## ;c #?  ## M鬹 B #*##]}ɒ;jXٳ)ꓹ:ʅapB   Ql{6A    #r{   B >غ BS6ȺBBQ=6BR~  #=tSt|:t؄  TSQf࿉tJ  # ڥ‰t>Y #B##tX,˪dptX*[dt.0ЄtȺZ$p#=tt]>.dtYatЄtuЄ"쵙t~Sٲ4엎.=d)I76ytGtB##㚊.4Cd.qd 7@  (7= ^m|  B> B }zƉ1}o}}~} ΢: ?:  R脉Є  Є  Ҕz؄ Z؄È A #@Ɍ B?ƈӜ < ""B>@#"㜨>B 輈| B 8>"BҔɴȈ>@"iiBҔɈ>@BB؄~ʈ>@B4ˈ>@ڰѲ̈>@ppƉ@@BɌ@Є9@By@ƙ@@@"@t@@@R" @@#$@@@R @ꔈ@B@@"@@ňB@@@J@ʱ@Ί=LΊyRČӊR  ϰ| > B|膈B||‰t||t| 9t| z. t| |FAlt||  |t ; |& |||d l| || tA| |t|@ H ||A@Hl|BlA |@B||""Bd|| "#BJ| >LjBH| Ɏl j"ƀɸdt>ii"@ʸ|>>@B˹Ȋl>@̱l|@RtȺpp@t>@Rd>ٲ>@R|>@J>ɲ|@"t@@Z "@$#@@@@ @@*"@Љ@|ˉ@@@@|Ή@@t?N{Ɗ/>Mhw荳Œ& "1:   pp""($# ppHZidZiieZppZ:Z\ZZ ش - 7@  (7= ^m|  B> B }zƉ1}o}}~} ΢: ?:  R脉Є  Є  Ҕz؄ Z؄È A #@Ɍ B?ƈӜ < ""B> "#"㜨>"B 輈|>" B 8|"BҔɴȠ> ""iiBۜɰ> @BQ؄>ii@B4ː>@~t|@ppƉ辱tȺpp@@BɌ>t>@@Є>@B>@Ȅ|@""t@@@R" "@@#$#@@@@@R9@@  @"@ϊ@@ˊ‰@@>@@|B@|Ɖ@ʼnΊtB;JwΊ .=Ll{ 7@  ,;JY  C}>  ϰ| > B|膈B||‰t||t| 9t| z. t| |FAlt||  |t ; |& |||d l| || tA| |t|@BH ||A@Hl|BlA | "B||>""DBd||"#"BJ| > H|w   BɎl j"xBdt>ii@iiBQJ|>>@B˹Ȋl>@NJl|@ppơtȺpp@@Bt>@@Єd>ٲ>@B|>@؄>ɲ|@""t@@@R" "@@#$#@@@@@R @@ *@"@@򲀯‰@@>@@|B@|Ɖ@Ɍ6DΊt˪Rף.=LBl{ @A>@BDFHJLNQW]ciu "   * $(17&C LP!W]  蕱 @V>DKT_m|"Ac2G[m|RQQSkRQTUSRSTS  TSR"SS> USTUTTTUSSR/T;',RWUTUVc;)0A?ARUTh8$+G:OR_z صިN%cT5{`ESR[bZۙ3ScG_Aٹ<6nIb0YQRR @V>DKT_m|!@b1FZl{QQRRkSRSUTQ STSRST !SS(RSSUTTTUTSUJT @5NPUTU ;=;1/A &f4[|ؕ2ؑRhSȥ SQ]Tȷ* cUTFFSS\ؽdS_D1cȺKE蓹?: 4HXRO# Road stop graphics3  ɰ  ̨ %        A  e   w     ̸   & ʰ $         <  C  S c  .   ȉ.F'   ʈ Ɉ8 ̈?R *& ?&  & Y v *؄ ȓ  Ш#˘}=*7Iʈ*T*h?~&! . F(( k (  ( ,/() BL (  G  _ ز ,%} Wؚ;п/)QGQq( KJJJKL JLˈ"1H LDMJ{H D J{"D A4{JK{D `J{DJfЈ {H{HDJJH H{? @JHeKJLKL @ZD ؀bЃKLv@ء؃@vО`DJ`ȠD `р $J' $:I $ʺh $芊|@$ `$*```${{ {ˈ+J{Jnlʠ"o5<2 Aqueduct graphics by Jonathan G. Rennison / PaulC  =  />M^m|;ZZRa;܈v Ra*';  Zi';  ' A؉'  ~C' @33'r؀࿊bBbaj6 ډ b x괡;b  ?xҴb nn;  >d;10;N %ћD;;O; f,;;Iٙ(/m' ;ZZ';a"<';AsڐVJҴv=N xbz썶?blj'b b+ZZbdszbʉώގ؏#2bP_n%> .=L_n}QYYZ@ @  QY*9 @m| @ @< @@)x> @ ?19KAB“а5:;Aذ~@ғ0а5? YZа4D @.=GR=@@ QYYZ4uی@B@ ؀+9oى@D @t~  @9r8Mtt>ھōJ @@F̍@S=3@Qnv ͌3M^m|;ZZRa;܈v Ra*';  Zi';  ' A؉'  ~C' @33'r؀࿊bBbaj6 ډ b x괡;b  ?xҴb nn;  >d;10;N %ћD;;O; f,;;Iٙ(/m' ;ZZ';a"<';AsڐVJҴv=N xbz썶?blj'b b+ZZbdszbʉώގ؏#2bP_n%> .=L_n}QYYZ@ @  QY*9 @m| @ @< @@)x> @ ?19KAB“а5:;Aذ~@ғ0а5? YZа4D @.=GR=@@ QYYZ4uی@B@ ؀+9oى@D @t~  @9r8Mtt>ھōJ @@F̍@S=3@Qnv ͌3M^m|;ZZRa;܈v Ra*';  Zi';  ' A؉'  ~C' @33'r؀࿊bBbaj6 ډ b x괡;b  ?xҴb nn;  >d;10;N %ћD;;O; f,;;Iٙ(/m' ;ZZ';a"<';AsڐVJҴv=N xbz썶?blj'b b+ZZbdszbʉώގ؏#2bP_n%> .=L_n}QYYZ@ @  QY*9 @m| @ @< @@)x> @ ?19KAB“а5:;Aذ~@ғ0а5? YZа4D @.=GR=@@ QYYZ4uی@B@ ؀+9oى@D @t~  @9r8Mtt>ھōJ @@F̍@S=3@Qnv ͌3M^m|;CCB@;܈v B@*';  Zi';  ' A؉'  ~V' @WW'r؀࿊bUbaj6 ډ b x괡;b  ?xҴb nn;  >d;10;N %ћD;;O; f,;;Iٙ(/m' ;CC';a"<';AsڐVJҴv=N xbz썶?blj'b b+CCbdszbʉώގ؏#2bP_n%> .=L_n}?AAC@ @  ?A*9 @m| @ @< @@)x> @ S19KTU“а5:;Tذ~@ғ0а5? ACа4D @.=GR=@@ ?AAC4uی@B@ ؀+9oى@D @t~  @9r8Mtt>ھōJ @@F̍@S=3@Qnv ͌3M^m|;CCB@;܈v B@*';  Zi';  ' A؉'  ~V' @WW'r؀࿊bUbaj6 ډ b x괡;b  ?xҴb nn;  >d;10;N %ћD;;O; f,;;Iٙ(/m' ;CC';a"<';AsڐVJҴv=N xbz썶?blj'b b+CCbdszbʉώގ؏#2bP_n%> .=L_n}?AAC@ @  ?A*9 @m| @ @< @@)x> @ S19KTU“а5:;Tذ~@ғ0а5? ACа4D @.=GR=@@ ?AAC4uی@B@ ؀+9oى@D @t~  @9r8Mtt>ھōJ @@F̍@S=3@Qnv ͌3M^m|;CCB@;܈v B@*';  Zi';  ' A؉'  ~V' @WW'r؀࿊bUbaj6 ډ b x괡;b  ?xҴb nn;  >d;10;N %ћD;;O; f,;;Iٙ(/m' ;CC';a"<';AsڐVJҴv=N xbz썶?blj'b b+CCbdszbʉώގ؏#2bP_n%> .=L_n}?AAC@ @  ?A*9 @m| @ @< @@)x> @ S19KTU“а5:;Tذ~@ғ0а5? ACа4D @.=GR=@@ ?AAC4uی@B@ ؀+9oى@D @t~  @9r8Mtt>ھōJ @@F̍@S=3@Qnv ͌3@BDFHNXbr&:Nbr| ( & $ ".$ $,$8*8L\L`jtt~ĸظ 츂  ~tj4N @B>@BDFHNXbr&:Nbr| ( & $ ".$ $,$8*8L\L`jtt~ĸظ 츂  ~tj4N '@RNPRTVX]elx '7EUes) (  ' &/$  ."#"-)",7 +*2)S8i U &+9%k$,,"4ج!-n ...Lq \\\y[ ȉk = AЬȴ` ]t /@b^`bdfhmu|&4DR`p~ ) ( '  &/$ .!#)-("/,6 * *2*_h +&3V%,H$,,",Ђ!Xt XXXЮЄРЄȄȄаа ȰȰ 6 ::* UYt~ш@ '6ETc l{? ̘}? ?Ɖ?NƉ{Ɖƈ 4CyƊ> |6EƋm|ǐ.)8ꊱet}3g.'6gCcr䋫agۍ-&5Dg[jy|'Ə(7FUdsZ @2.0246:DTh-<EHJLNP( $  .$*>>&NO^"   !! @@ YYj苨y 0 @-$+9Ia "$&' "   1-6((F6$W gg ? 6舨n @B>@BDFHQ`r'7CJLNPRTVXZ\^`bd % ! #! +;, 'MB;"^  nn Н?  ئFڱ   @B>@BDFHNXbr&:Nbr|     $8(L<`Pj dn"xn$n&n(n*ȸn,ܸn.n0j`VN @B>@BDFHNXbr&:Nbr|     $8(L<`Pj dn"xn$n&n(n*ȸn,ܸn.n0j`VNZ @2.0246:DTh-<EHJLNP  ".. =NNd!"!!&BB*a.z#'+ 0 @3$+9Ia "$&    %( 66F!?uP&B*/ط 6$)n @B>@BDFHQ`r'7CJLNPRTVXZ\^`bd   *< ;; M "DU& + /ؾ %4)   '@RNPRTVX]elw.<JZhv       &  4A!(6d*f *`!F؎"ؕ U$ثЋ%ز$&,(,з), ,*X",X#-X$X.Ȅ&(0/ '01?(W+Ti /@b^`bdfhmu|&4DR`p~       !/ 5"C RY8`g ,k~ ,d!,,"XЪ$XА%XX&Ȅ(Єм)Є Ȅ*Ȱ",а#-а$Ȱ.&.0'51D(2 *T+\, t~ш@ '6E Vet ABAAĉ'6ĉcrĉĉ~ሉʊ-<~ʊix )8GϋpŊ ʊ ӓՌ9HRuψϠՌR5DSՌʍSʍBQݞtʎΎY֎ 7FUds$ @?>@BDFHb  2   8G @O^ $ @?>@BDFHb  2   8G @O^ d /@b^`bdfh "$&(*,.02468:<>@BDFHJLNPRTVXZ   8G @O^ "20 @@47>IXk{ "$&+ ) '  % #  !38D`dh..4.4 .У @:.18DUk~+ ) &  #  $5;35a 5eȓ؉[ ȃ: @F>DO_t "$&(*,.0* ' $ !(&;9N ` 苠qЎ !%س  0 @@47>IXk{ "$&    " 0@Q Wt(.(.)Ю @:.18DUk~      '%&8` 19"o&Rؚ)Ȑ: @F>DO_t "$&(*,.0   %&&99L _ q#&) $ @B>@BDFHJLNPRTVXZ\^`bdfh    P_ HW$ @B>@BDFHJLNPRTVXZ\^`bdfh    P_ HW @! "$&(Rx    P_ HW& @?>@BDFHJLNPRTVXblv,  * ( & $  "  $ X`@hntp0(XU '@RNPRTVXZ\^`bdfhjlnprtvx/;ACEGIK( %"$-'1*5=9< ؐ@<ࠠ# @B>@BDFHJLNPRTVXdq* ' $ !!  " y9ȁ~%Г& @?>@BDFHJLNPRTVXblv      $0bjLr0 ("PU '@RNPRTVXZ\^`bdfhjlnprtvx/;ACEGIK ! 5 I!<[s >؟#@&*ࢠ# @B>@BDFHJLNPRTVXdq -*"3Ј"J%#(Г" @B>@BDFHKPV_jv         $0HT`lвؽŰ" @B>@BDFHKPV_jv         $0HT`lвؽŰ  @M>@BEKVbnz         $0HT`l Ъ  J @B>@BDFHKPV_jv*5;>@        $0HT`lԨ @1.02468;@FOZfr~        $0HTkЅࠋ @/ "%+5@KValv|       !,AQZa '@RNPRTVX[`foz ".:FR^irx}        $0HT`l̈ب%2 /@b^`bdfhjlnqu{ ,8DP\hs}        ' 0@BDFHKPV_jv  + +  1 1 $@BDFHKPV_jv  + +  1 1 $@BDFHKPV_jv*5;>@ + +  1 1 $@BEKVbnz  + +  1   $@BDFHKPV_jv         $0HT`lвؽŰ" @B>@BDFHKPV_jv  + +  1 1 $@BEKVbnz  + +  1   $@BEKVbnz         $0HT`l Ъ   Flag graphics$`     ! 7N`  ,C`    L`   !,M` b  b   b!7bb`  b bb L`   + ,N`   ! N`  !,7N`    L`  b  ,b b`  !,7N` bb b bb bbbba `  !,7N`   b,M`   !7N`      ,7N`  b bb L`  !,7N`   N` ζ  b !,bbbQ`  !,M`    L`    #& N`      L`  A @u!7N`  !,7N`   !7N`   N`   !7 N`  N~N / .  N` ,M`    L`     L` +,N`   ,7N OpenTTD GUI graphics @M>CKUao/?O_o       %  0 @ P`p @` 0@^x٭ @B>@BDFHJLNPRTVXZ,@Th|   '6  '6 4>42((0< <.P P,dd*xx(&$"Z& @L>CKUao/?O_o       $& (0*@,P.`0p2468 @` @^x٭ @P>DN\n"6t       *"$((&<<(PP*d d,x x.024&&..Ѐ| @K>BIQZer-:GVk    # ( %(((PP P x x x `i%1迸JBIQZer-:GVk   ## $/%('5(()P+],P-x/0x1345788 3.۰$ p+[uj|v  @3.6F`J  ?# :_#(ua؅)tЫ ̈(u @F>DO_s %3@M[hu   &  #BU1mG؍W ؄qؑ(((߸P PͰP Px  @4[  @2.02468:<>@BDFHJ,Rt  '6> 'zB<~(%& &#%؈ʘFЪT @K>DO_s "/<IVcp}      $#!(2-J2J`7^p9| 6أ&5&3&2&0@/gZ.',g+'*N'N%ب$i#{%{ ɏ|h '@\NRZdp (8HVfvDFHJLNPRTVXZ\^      !"6,$..%.>&..(\\)\l*\\,Њ Ȋ-Ȋ Ț.Ȋ Њ0и ȸ1ȸ2ȸи45682c #ؓjjn. ~<^ -1DSAZÈqA. \PgˈJȡ.񈊈Љ7푃BBx>Z0LHf`؆8xAè8#AZ;H0`H`xA A8ة GAP~_AI A.| 8.FZZZ[(FGJLFGIJKJ GI, FGFFFGGJKFGKJ FG  3.28>DJPV\`bdfhjntzFGGFJK KJFG>FF6LI TJGI(FGJLFGIJKJGI,  FFIKFGJLFGIJ IJGI  9.39?EKQW]acegikou{FIKFGJLIJ IJGI<<< $<GI(pp5kkri 5"r, pp5qqip5k" kkr"r  -.4:@FLRX^`bdfhjlrx~ pp5kkr i5"r>qq >" \"r(pp5kkri 5"r, pp5qqip5k" kkr"r  9.4:@FLRX^`bdfhjlrx~pp5qq ip5k" kr"r  >5>(h>><(h>>>(      ,         -.4:@FLRX^`bdfhjlrx~    >>>>> >(   ,     F.4:@FLRX^`bdfhjlrx~       >>>> >>l     2;[_H!8G 3C23CB22B$G  $6G  7l  hh*  ?9  $ $$$H  .:Y   @BL@"H  ,'4    ii1!$ /76AMH SlZhwh l7l ؄lؤأAػSѸ7$8  '78G8 p888 7 8 7$389N]p9 P    897 DE4 ف9̈&遰9   J 8Ѹ96:;56Olkqi:tl6iqkЉ65i:li5:87РitlSr t"l t"l诰 5t"p t\l5௨8 ẠtzlPtDɖl0.Dl86DD0\DGD8ii i5D0젊`FD,P5p p p 㲒55t8쒈Dˆ8&lDt`r,`8̚ˆƬͤH +8 Hb7 'Ř <<<ABBBBA<>=ACCCC=?C@?>=ACCCC!r=? C@c ><؁a@?6+َp kqi: _ 6iqkƨ  q5i5tl i5q譼R ik tl kS ' k tТl k 谘8 t"l  诡 Nk"p t\l   zш  5"5颊08.iG886ED8ŸG~Dlɰii5D¸0`FiHlɰ5pk¸,ؔ~Dfp 㝠l55t,8טlD”װ&lYtˌи:l6:lͰ6Խ@8 = 'v<<< ABBBBA<>=ACCCC=?C@?>=<>=ACCCC!r=? C@c ><؁a   ]         ,   FKH!ggKHB  LB! ZB!B x! v>!HJ{J h! hH{K;!>hHKL\B>!{HKKi!!K8iW ʓSѸ*sv   \4   c,$tZ HZnlHX~HXКH    $8  '78G8 p888 7 8 7$389N]p9 P    897 DE4 ف9̈&遈9FU8Ѹ9{P:6 o:6ȍ87 :6r :68 tlƈpˈɰLj8ʨDZPᖘ؈88Ѱа؈pЉ0Љ8ЉЊ0г0ɰfh,۟8볒ڸ$pʸʸ8ڌ鎺H 8˸ GJ 쌿b7 'Ř <<<ABBBBA<>=ACCCC=?C@?>=ACCCC!r=? C@c ><؁a@?Dr D ZDD Ȟ Ȟ D@26DB5  "D"#B$ ǀ"#DBYY"##  ɂ##D B##""h"#˄"#D "A $##%"hQ#D" "%%#"5@ "#˄##B#5""$"@(D%#$D`H"#&Rr j|r , r _        3  "/ D" U"TxD T`sU  ثȽ$8  '78G8 p888 7 8 7$389N]p9 P    897 DE4 ف9̈&遈9'8Ѹ9 :6 I :6 :6:7 t:6 p O6)y G:% W6  C :   l Ht 8 : ؃68: L6Y6 6:  і ~0Ѱ ЈphʈٰQʸp¸70ɰڸhx wFʈD8:ʈ~tڈ~8ˆ򤩶HЬߘ8 GJ 쌿b7 'Ř <<<ABBBBA<>=ACCCC=?C@?>=ACCCC!r=? C@c ><؁a@?}:yt0 : Z t ,W خ#   #  $S" #$s5 5 $%6"#5 #5% 5$"5 "$"ȣ #o#"#A>6̃̈́ZAA7:;̃7t"tQ͢m78:[6̈Q]'#   %4%WC %{C$ o% J J؍J  J̈%J̈J %ޙ{̈J%ʉ(Jʰމo(( *(  M(  #r FI il ▊۪f ׈# F,  i rB  ⎋_F a 9E Z# 5F5 " $i5 5 #%Ŵ$  5#"#"5  F$ $#: ؈" ,  =L #\ 7 : :WwW: ː ̘ ::ɐ; T W9ʐW t9ɐW e87x 't: :aWT W Б  C#   #  >$ 9 #  $# W $5 5 #"5 55# 5$#" 5"%$ "o#$%#Ȃ$#Ȃɂ>6ͤCȁ=Ct]VT≠t<=Ю[z66'"  /  D d@ ` ! @ @@ @ @證/@A@ˈ@ !ʉˉ頰胈 Ɉ@   " D ofD 슱 " DD  ӈD -9W؋^m }"YD Df0 '65 IX$" 5Yl!#5 5f "# 5 $ #5" 5"#%Ӡh$ !D$A!  3   ,+G% @(PO PxwxȠР$8  '78G8 p888 7 8 7$389N]p9 P    897 DE4 ف9̈&遈9   8Ѹ96:8l-=@ 8 q8876r7Tp k 6 9;  :H7ku zv !D SX8 /7?C8 v^$n؀iᔠСu Щ*70(2 дph#6ٖ؀zp 7؞ȡD <{2XT0: .9  |h ո<؀ 4˾8up&آ9_9a 5IH8ø 뻷bۀۅ #   $       &  $ G8  (= 5 7 P $oK;8 oz ؠ8 r٪>'сEo G _ى|س70HQXЧ֐phpȝqp 5#;D{ھRkЮd#0 .D@D2| hո z 4㈋H8JuD HӽpEٌStI 5+_H;*8b 'M''+G37UI~K) K{ 2 Q QXJ  4  PL3 QL J*wQ M  `&kN;r~NO#  $Rt ȝ} Рfcd +888, V 1D( &37钊PɴQ蔊ts ,HfX RL~Fx@rR2H^t     20 1 ?$1  USTVUUUSm8@8%   /TSSUUm8A42 N/4 TS802  c   Ne2   Ndh jNKؖ R   NL,T "  ɠ ^STg l 2 ѠdT  %2  ȖTTT f4 2    STS5 Z   z ؖ m=T7  Ҋ UURRT]U8ѠjʼVRSm"Ѡ7 G^ Q<  ^ 8o 5 2롳 XƓ  m' Yw  4  s v9:bW_ :  9 ^ : 9<  o9GK J9   ] \," k8Z |؞$ؽ '6ET[R$  $ ZR a Z  a!P Za ZQa6ʘ$CRap ,HfX RL~Fx@rR2H^t     20 1 ?$   '薈2? J2 dr [cb  2 z ZbaؖΘZYZ 2[ZZbd .^8VYfj,ZVU Ȝ^ R 6bcpbY Zca ^ Za \c YZaaZ[^ڊ(cY0YHS> ZP  }RYbaaYb^ ZUab`& 2YPRanY aPZXYö' Yه[d 4 C 7Yp*鰈9oP{j: :U  4  |m} g |@,V" k8Z |؞$ؽL  D& D9 L  & ? ? $?% 6?  Z $Т g ĸ ); '6ETcYYt» \$[НȒ     @O      ! !`    !3  ! 6و! !RbrYY » ٨   `( QZ 2H@Ѐˆ(ȡy[Y[QQ[S[[\[Z\Z[\\R[\S\[Q @ #[[)@D\D\J^@`"`IfRrڈ" ,  K !LLL&9$#U&cbceȐdbP"f``fdfb# a`dbdbbbbcc``cacaca#aaa  LLL&9$#U&U ؖ#5S͘G [{#LLL2&xF@X# U& f9 y$6 6H  ALLL&9W#D& f9 ˘w ͨ ʘh ͸&T~  L LceLdbf``fdfd&"#a`dbdbb&Rc`ac3aIU_II)IcbcefI%PI:ѰbbcУ`cacac#aaa "-0L  LL,&"I9TW#hU&IfrIؓI蒨IrВʰ͘ؤ  0 /LxLL@ '&" '9W '#'U_'f ''H ' ''$' 6''N2>=  .5 : OP7AA'):jN~|ً     @O      ! !`    !3  ! 6! !R>r!    `dE \b   2=%FM R@  " ҏ"" D@ e ?A@#ঈ E rڈer  + !l  -2F\l ¸  -2F\9     * 8 8Tp@&.5@ -4@ +H !8H!8HCBBA@@@@?A>!@?8HUTTTTSUR!TS8X  .(FF DDB B B5  Xdq}b <!@?8HUTTTTSUR!TS8     *Fb  .6*Fb~H 2 jjjjj!lllljj    !l     #  (   3( ( 9 (( (P  khh~qm#tTTJTJUSHR{{J& -mRSih5@ GikrmBhiKKRK} SRJJK< 0kRSQ5hi~i5kq}~pSUTK{LTSLSTUKRLLK6iA5ȃF ii5qrmr ph5pUTULJKRUF SLRSLJLA8gZЀ 5iBqr5phk5TST{KLRRTKK K̈́{Rax \UPVi\F5pbprQR"TS ^SHTTټU RUdx `dekyhki22VkpkU [S:  d,ahkp2r,ش ZEUp=lLhOlaݟkii5n,R ST^WRTUlMvpDGhiqirk5iqp SQ c>gcUvRt()p9!%prkp"irpiWSW7ٻnTM tIؘM?p5qp UOR ؉Sz/؇Gg5q"34 sQ47j R.pe؅E5qi"rko kQUSQ^Clڨ5UTrؤDXC%%qgl;QR q[t}bۑRQSQQ!kW=R ȮAWW%"]qSSW R[T^QQmUSR /SD N?ըCskpRRq#DRfKoӑ.qRRSmVVUS" Wت=5ⵋpiXqprR U0$TC͢BRRr5RSRrTVUVrmy%  _ڦҲ;:qp55rpcoS B;3O%Urf݊QT6{mmhTVV' Z l s9䏔ipkqpI|e6 %|-R[R|vY{o:G5S&5(kTUTVrT* L̵ء]ܤT73rqXqpQQRVR52AqSRq/5qKq5"އOc͸ȵ"-ۺ= mVUSah#ԕ @Rq4tמرj܄\VTkKݾL۷PӼ5܄R QPqk5i5rѺXݙi׃ؼЭ[RlRR[rVS5jH(ۺHl 5sqi/= Rzio]UTmUTRUpYeVqgd!RRq\dh5 `iqޢxشzӈ}RUUVRnYRYRqDhqkroҺpU&аafeX;RUmVrmsmY-"[YRudSͰ,iݠ[PnL[BuVUUU ݒR1zqՐq5ҖGߴ׻N[RRUVRURm'ApҙKq>5"ȒܙR mTVS65Fv S ܘz"mr|h*HeRjm5TVTyb<RL )GkT0e b'%k\{OT[UT6U6YpYR,k>|ؔ`5iGו,EQSPhK%'STmUrkzYٿy TD ii"\޲PLН VkU5(ۄO9(kH!bk,TNQ؃{0ѪRSVUeR\`޳kRS԰#RSTܑڥwX{/r mR4p7)w8kކR6%s[ҩqTcԈ<SS5_ى:ZSk S'RTSKzZ1TUR0u3s?Gׅ$ ,)zS7Q>KVUSRvwۛ{5R*+RUdsyR9w|VVTk zrj6bt-dTUg} ܝxTrTSSY=vRqU/SbNRեTmUT pJ(ID:YRsYRqoP1J_I=+1UVRװx*r*YR,SS3ӢڍRR[̈מSQzbcܞ2ѡzqڈ5UTo"p5pي Ο7`QúVUUUVk<5Yߎتwdό9@قlR5d#TRJJ; &RTRrQ` VRTRR,=ڒڃQ5PݴXة5UK?NeԀRR> # ֆkƄA0DHRPҠCҀRSВ P"ʼESRL,aGT̀nѨ̀ɘITT;γӏ4@KkSۼ67Tk Ms%T:ޣO`SRX5$g}@(͡5RRpl&5܀WlܒYtRS@[R5#]r_ۧzabʀ,  "$&(*,.0259>FR`o!QH|,pPFLc' ^ 8  0e `p#H@?XM !""@##R$$P%%>&&'''K(()V)))=***+9+n++++,;,X,q,,,,,,,,,,,,,,,,,,1x w vtr p oioii$ oii ii#$ npii"  l #  j%  %? h''  "fS[wU0 F%d;>+# iC &333`b  #f `  iii$fii1\Qk#$  &fAd# ؠL[ "  P(f3 i<,3r3 *f ir i,f p"$" pipn.  1ئp#: "p#"جh > d3ȳ $ " "$#+CUD_D5#p "  "$$ qB Fd:c$"F PHІQH  a=N$ iؘR \ M_=a؈S x# S R]@_  pTɼ TGT 2 i[B]  U  VoijpVؤTYD[   p "i %" 1S  L WEY  ""p"##ip   $W W UGW   Z#"""دګ"л $I Y SIUp#   V1"pp ˡ :  [ش[QKS[p##]] b "##"͙   ] OMQup#$  ~  ]#$ډ _ MOO  e##$ O~  _ $ii) KQMae /a##i""N#44#cISKg. c 6"b @'$) GVI)lp   /p" L p "  h E_Gh"$$   0^dߧ!eY Y3j  CaEK"#l N jؖ2O}1  $ zlAcC~ om"٫rnKpC ^ poF  ?gAr###ܹ tnt"E Rr=k?'X $Ѿ r"5 "RTaQv;o=-<(E[x6 eㆫoiMQSTQ6 ZQz  9t;x؃ Uljppఫ RZSSZZTQ؃   79˚=z pp#?ppҐV QZSZZZTZ STTZ 57G "6 $؎ RZTTSZTRS Q ZR 35m"$$#  ppppi$Ԛ 6RTZTQ  .RZ2 134o= ##p#E#"Q@USRSQZZS1  SQTTS ; W/1Eؤ%ߙأ #-"evSSR_V SZRZSw /y´Yn" yܙ۝STUSTRZQQRS QU 묤j"#;#iV8ܪUQTQQTZQQQST  ԕg $T $p$USUTSMUURR5QWWSu^ĺ 2  #T::STZUUUUUҵRZgZ^Ȳ beح޼ii$^^SUTSUҽS@S@"ȴ ಍ۢ@| ۰TUTRUTQS֗ۧ2B | 9Cܭ ߍ@ < ׈RQR`ܰ+‰R$"/ H#밍z   RS7kSQbSQ7k7QS7SSm7SU7lC RSR7rRR7;B#<%ɄI ۰ -   QRYm.Q1 B"$ռEy۪樥Zl   ~ 5N) B#Rkڶ" ЛF:H+:(RRSTeSR    Ʌ iS~çQ& QURQTT7kQ#]&i(2-߰UU  ʄ˘ SS.S7܉HCRS*Go*/ST>AS Ƀٿ gR4RִްQQSUL|#T1"5]DЏɀ DU-TRQDѮ3SͩO؏UTU٧ ѧ И,5T4[l\5T͈TUٛ ʁ*雈SRRwA\QYT$"#7؁э@ʉmэ 1dd9U酪&ɑyRSQߢDB;q  i}lT" =ˁ Zs@RQ܁+߬?R ToZI7`#޻ARRZZm ZT S ZQm/T SQֵ" g˺CRZgM  TSZe }ZST Sm#bڲ$EQZ R Zc-TZRRTcǏGSa#SXZZj ZSb%7h\ՏI]TTT[}ZQ S[ B|ϞzzKZTZQS Q Z ST TQZܚRU#m8MUQT Q ZTp{Sn篚OU;QISQ>"fʊδQw9TQRSخttSʸI),ʸ20UҘZS8Z˜WxB xʷYX4\QXppf[8QQT80  00]j   Kʫ_  3 azTTR,#V/ pc N IЇ0eh !{hgDoiǨcߞkeW6mKoq(ssʀL  "$&(*,.02468:<>@BDFHJL[rHsJu'T7i1c+].`( Z ) _  ? w " \  < t VNHn "$&(*,.02468:<>@B.qmj&7h2+/ ɡg<0ɣfC& 2Ck2 / Ie MrF  3pd؏  2PL42 QcP -zrU +T  ؋ gV vV6}Vʩc 2(Z)2 +, аqko+X BOOO)H q 5`TcWG+ 9:-+ c%eZyx4э, c eُk c e!g.0W,  c!g\^"0c g /b-   e /,`Y7 c WWPB- aT dڢm+ _ #h  X 1  _ I  D b dh5   d kl  2`d 6en!"d d yع8 d2d4e.0 d2_2d4P0d2 _hd~d2dx42dٰd2042d  dM0 _48 0  _ ʃ4hd`02 _ 3˄ 8td2 ȁ  ]8˅ 6;#4   ] Gʅ 7?/ W' 5 % _6 jA4) j 24 A0) \b4 A) 0A) 0>&0:"8 8 _9!]:=%[lC[Y 18p: 8:Ţ=s:UY?خ:"W8"{[# Y`\)&Y] ] /*:8_<3.ta; 솊55a 5:Y,:a @6mٍa M왌F6mٍ`  7L6ڥ;^R t6Y[<]  y7 Y[а^  Fn§ $ذ  FW  riHU pݘ ?B  Sx    ʅ  8 T>     B [| %  +Lѣ^   Yg>c  ٢a^ ([d ƞ*h]td '_ Ʌڶ8 a%?CBP c%[~`keO < ڿgTizIVk `m  o,q.2+  "$&(*,.0259>FR`o#Jq:kLX6&z(L   + nn6aa#TaJ| !!)""1##'$$ %z%%H&&'_''(R(((!)^))))**S*x******+ +++++++++ +"+$+&+(+1x w vtr p oioii$ oii ii#$ npii"  l #  j  4h  f<DU>b$dz i7 d'HJz~ f sbH  iiifii'F#$ f,O  ) "  f* i3*O$*fk~ i_la IV,f p" pipZ$ y ؇p#/ "p#"؍SF Kdͳȓ $ " "$#88ȟ#p "  "$$ 26IcШ$": <n< aͻ?$ i}pAڨ   _ͽaDw 7 D ]Ϳ_  pFm FkF  u[]  u^}  Hۏi$Y[j   p "i  ҧ WY ; ] ""p"##ipٝ ( ژ $ UW   M#"""#{ؔ<"Р SUp#  ~"pp ˠ QSNP#PP  "##"͘ Ƞ OQTpp#$  N 2 P#$+ MO  1##$ 4W  R $iiKMT XhL T##i""ꈈIKتvZJ V "⡉GVI*p _ |/[p" EZG^ޏ"$A$ ^   :ljppcફyٟ -   79dD Tp#pp*tL 3 ` 57,#ҦpA"x$؎Mk@Ӱ` 1 35r"B$$#  ppppin @` 13μX^7 ##p#D4@P`4  9 U/1-Qأ -آ #"txmMjM`mR /f±FO" f܆ۖ䆈``" S 먤\|"#'|#iBO0̜b# c ̌؋$R Ԭ$p$ VbSO   \ - #R44V# 3ȱ ``جii$WWwy9Xȳ ͙"ȳ ్4]`tt豍\{ \ K8 Dۢ@| |UTنUÍ  ^欭 @ < ύQύ밍ڝ"   RS7kSQRSRSQ7k7Qڍ=in ۰    Qػyy۪ୠl   "ríڍ1  & Yˎڍ%˜Εծb n@΍!R͍|՜  ^6ͼܕZ# ͍dثȅ  ؍䍤ŤĽ$&%্G(   bǍeŅ'͍h͈Fȃ  ihFffh)hQQQTQS5Q: QQHHFFh:+:RJRSTRT   Ʌh(&&H֚-藼SSUUTSU  ʄˍH((/STSTTTTS Ƀٿ(ƌ1"SU؁Џɀ5ȌȼƜ3SؐTUTU٧ ѧ茨Ĩ5T͈TUٛ ʁ*̌Ȍ7؁э@ፌfffd9U酪&əDDDd|;q  """"B =ˁ Z ?R ToZRދދދ0ARRZZm ZT S ZQZRCRZgM  TSZe }ZiEQZ R ZcSZTSRދxGSa#SSXZZRޏX޿I]TTT[}ZQ|ל|8zKZTZQS Q ZQQQRR:  ::Z8MUQT Qo   OUTZM S p֊QTTRtCO tS, Ў 22RژU AWհȄŠxY̏åpXp[޿Bз080]_apؑFcʉehgxxiXXk86moq(s7 '2>JVblw*=Pf >t+pQYaG 7 / - 3 Ks MKm+{HgJ) !!"}#H$%%&L'((e)**Z++,+--M.._//]00K11)222X334c445J555 6F6{6?667'7H7e7~7777777 F  $$Kh  T x w~ .> }"P}1" |~"  H{K[  sz)qs| oqym o Z>km  #!  ikD    $ gi  1 b S -1eg\ \7  NQ3_ 6c!e/ g   پg o a#c$"` 9 #8   r  _'a"h RAذ C ]+_؄G#RTQEiiG  ii[]^ FcQSTQ< ZQRpiHD iD$Y[Ȇ #RZSSZ TQQ J"pi" WYFR cT QZSZZZTZDSTT " $  UW!Pq RZTTSZTRS Q "- TSU16- 1"$"RTZTQ  aSZX XQSPMG#sZSQZZS  SZ  \OQovoFS[aTZ ZSTS  hMO`&5a<RTTb!ZQZRd dKMd|3юR+T"QQTZQQQ&̘h 4IKϺ#m1RQ4SS@  lGIWSeR?ZR XpܨpEG CH0tTR pt oICE.. .KNR oӔ"v stAoCJJg8 5h p"px x t  ?oAee^ֆۅ """piMx "=o?~~ MvA˞ }"i}f p $;o=Bn e ]ֶX "#i*wUip 9;y iK ޙP "k $79~2 yӼ̼ p}ɂ 57܎؀, acy     @@b>`  `` +ip, 猍R"p *@`bŀ@"" :  p @bַ ƍ`"iȅn Bb" m]"#""K     Ò!bߥ ꩱ ލ||\V ȃg WǐB޵ގ`RN  э՛]iipg  ˎBQ    ᦘ <.&i""<<ii g   Ʌό B<ִ#    | ;[ {"["  ʄӊ{B;[S ߌ L   鶨姎ZܦzWz"z $ Ƀ׈ڇBBZz# fɶ  =T\AYp ɀۆ B\ ;  " u ߄ BiҠW֏  َ 6ޑѺ ʁ̏B33²#(ھ"i gdߪA檣꣈BBHHzpº[ p $r  G:p ؈ڠBBVV ʦ |œSi)xr֎ Ԋ Bڏ\^Ѳ "ѭsc$vs階p . Ќ B؏Zvz #߅<ڀʅ ld p+   ̎BΏPQEpT)ٝT ZZ7܎#   ȐB>Q?n^ٚ$hCŎŎ  Ēܑ ֥$4磮 %%eT9)CގhIhhhs "hʎHhhhhe&(֚-藕(H((hh/Ŵ(HH1"22((Ƭ3! 22 Ȍ5ԨxȌȌĈ7) 22 Ƽfdd9 }2dDB|;y u BBbb"! =] ?ދޣA܋ܫ ܋˺C˺܋ExGxx \0XϼIXX  X܋8zzK8E Tߏz88M 8O:ִQ9쩎ttSrR20U03ʻWsaRpͰYQpհpf[f00  S00]R   ʫ_ 3 a,#V/쟤pc N IЇ0eh !{hgDoiǨcߞkW6mKoq(sj  "$&(*,.02468:<>@GMUan{1Jav!Be?gRA%y=  0 L p %?QXN4 o-,yH$Qz )27:<>@BDFHJLNPRTVXZ\^`x{ xww  w!  x@v = DÑt8  tAA u@"  5-  t    r     o   o  F q2, q p qȅ  q   qȃ   r'  l r =$  Ʌ j r  ʄI hC  ɃTf< !$#ɀ] dA I H dc f N ʁ$ &g & kkcii&  iiɈlpi& i"$lH%&?"pi"%  c-M" $-$c" $(   |r]r r G *ͫy ȠyrS0*ͭ؀z,ͯ؇-1Qͱ-^ ] ͳ/ _=_5ͷa "X,oOn_2X _7IzЂ[Ϳ]S) * $ُ %KZ"Y[Gp"pH p"##٪ ًK؋WYٸ"""pJ"H"Ǹ wSUWP"ii"" IȕSUP'&"#iۊ ڂ'' 6 QS٭/ // OO 3  OQ ڻ]] }} 2jMOv 2F2mҮ0 rKM4 2 2 / xIKcy|ƊԾ .H GI+ 2D2 ދ++uK2R- Gb 2脋bbh  1ň" - ⛖ ]Pڈ #  ݻ,m 娳ݭƋ S   Kk阦k#j1ԯ,ȑ  ڼ،ꠌֿƿ%S,"ȓ 葌..$.0  = 0 , $ G;;[ ؔ[^M"$"y  &#&i ݸ2"YY翤k#ՂѿR  ,p $fȏȼf( ]rfլ  !!yip pppp߉Apѽ" Ka$ssssK s(̳#٫ɰR 쫌rrrrD rk'؞̲< Mƌmmmm3Q'џ&¼ڭDdddddԧb$-+6 VVVVVxԖ3/7ꓬ"BBBBB ߾@1ڂ +++++y&03~o\5iΫ7Sڋڋڋڋڋջ 9͋; ͏=eΏΏΏ΋xx?͏xXXA]cXcc8.C඗*J**(EUGҞҎIss¸KSRR220MʻOxRPͰQXͰpհpfS80 (漍0U  +ʫW   HYv,#V/烬p[ N Ї0]h !{h_DoaǨcߞcW6eKgi(kkʀE  "$&(*,.02468:<>@BDFHJLNPRTVXZ\crId an'GyO  -   { u tvfFx0&p6p0Vx   !#%')+-/13579;.<$I F D  B  *A1t ? >h r  >HHOp+  "=WV]n]`56%< kl; 8d||"BYŜCBzyz{ 2~2} ;:زvgŤR|ފ] xi g<NjŦ\W;hX ߕb`r>rZ`ܵ`ޒ& K z@D^O^^\JKD RSJB߂"VVVI+͸8&DɌ$HH5Hbz{2F64w: X֓^HpNغָ ɱ:@J$n:LM L֞z˺9wrNr鸮פhClP6$v׎ζR  >ީv~~ TrʐQBBʼV XY*`Xޠɶx@Z>@\ϟ@^h3`ʭxʁXb8J.٠dPZ@HʜfeŎh̋jػ@lN̻nprsʀ.<  "$&(*,.02468:<>@BDFHJLNPRT_jv:fB*5Rnb h  > h'Om{u_9bgH<o2Mdx.g  gge ca"(_ 80] [T # D"Y$ $ # W  #S  U, #Q ; Sب #" RR70 0Qȸ 4ȸ  4SQSSQSP:O@SRZZTQZtp>M8D ZRTTSSTSZZR2  K@AD 4ZSRSZSQR4 NI  TTZQRSZSTh RG(   ZQTUSʨVE>Y  GI(2N Z B3DT_  ȃ ۊӔ^[  Ak{   3SUCip$?}ʠX  hax p$=ۋ|qˋ ̳   ё";˼鹊x¸  ̹x   ј9<  ި Gf73͚ HkK $L5$< ii HK K $d3d i# 0 { JH J{1/  < $6@ެ/S zȜ ~ i4 0؉- 227 pi iiL+L  ii  { p"  (Ϝ)ﯟ (#  22pi i :' ` #  ip" p"   좊$$Џ ؏ 鈊2 i pp ""$p /͍'CȲ1$  #͸  # "鋊08 $ ""$  - @͌XR;&  #O  Q<,i ""$i P  '˒blX(+#Z#SRƖ"p Q"$i ؟p i  ⓎGgSRZZR q*ߥTZR STR,""& s" i" $  r龜le`TTS`b܆,t QZTZSSSQm}u"" Y " # c T`ZSR`bT.*TTZQRSZ̰j ܀ $" p#  ``˒ͮ10CZQS޳*]T "X "$, `ܧ2T TT  ﹪TR"""  `~4T Е TTi   Iː"°6R ߸ RR""  $rR8NK휊NN"i n$5 US D :    K F"$ OQ a<Ď  H J{:"$ 컎~*&##(͂>~ip$W~~"$澊Vs@Q$lh뗊  MB ނ"ND d tDF BRbbԉHŋ<΋ΉJ  ɴLjQ #NSTR hhPЗSUTU_RHHR8TTTTغ (TtSTSSWwVd SSSSSRSQSS8XTSRZZTQZ!+tTRZTZR@ZKT\R\TZZSSQZS^nTZQRSZЍ`hZQ=zʵbHTTHPdʭflbh<S Tj' l #& #Cʝn  (ҜpBClrʚ<s ʊwyѩ{TT.6)  "$&(*,.5DWn<i9s1s9{AIQ b P  a + n XRXdp|'3?KWco{ !!"""j##:$$$T%%%J&&&'Z''''*(T(z(((((( ))))) )")$)&)()*),)$      *1 ~ 8b}88?p|?>E}{ K z Qy*W W %x]+Uwc u cwh  ѓvm!Јmm vr褈r /uFBD  P@B""D@B#"/@؄D ˆG B D B@ppB"DҚȨ""JiiDҡɸ#$JDSD ؈ppBJDF@nDJ@iDJZ̉ iitJ[Dɘ0: JJЈnJDʀADJJpɀ?FHJJ* "B>؃莹Js KKe" ABFҕq GN#$BKOQF$oEI#$I(2 Gmq [ ˁZcEZzWrٟV_^a_j-Es ܹf\\bcb_op vx H҉gd_HH ! 1^D#b%;یig^l\` HKHHꝐ FDںөџi^?nj n KK8ӺW Zl] \t,rpӤ\cʧzѴ qZr v M^t VtY{H$f   Z y 6˹PyVJ{H~q~J|zJH|ؔ {uIbA+Ӆ99RUhK   2uE]ttRB }J{{ly@5˵y ˂NQ؃/ نy$ K{ާ@TN%^їыH{٣{݈@m{ ˂JMy_)?/{J 7{П@ېQ JFQѝϓ?>?@@ ˂FI+ߦMLk[k@u@׫F QTJIᏑ@@@ ˂ BE圏uφT_ꏵ@@@B!&וсVٻՏՈ@@@0 ˂>A0 嘲'e΋@@>- ؅+@dz@@ 0:=Ї ڡׯ@@@0:!$ّ)'ϻ*@5@@0069ڟqiנ v ܮȘ@ٰ@I@K6Ә:qїߚ%d@ݾQ@ ˂25Q;zЇ"ȓȃ@ͱ\޼͈@02]շ؅֊nٕ؀@@Fམ@T ˂.1؃ʣJё@@슲@.]S@@+@<˂0*-_^b%*J{ڤ@@ר@0*T؆ُ̋6اF㲈@@@0T&)ّ՞ /@@@?& <̇%}@@@۾<0<"%RƊӔƣ}@@@0"]T 0 ٻ׈@7@@T!Hgۼ0u%5=W@@]:_T -@@ 0Ї͵/ڜ y߃@@@0Q$nҚ&Bi4j@5@@00ڢt֬WĪҚ* ؘ@@L@Nߘ=jN@2䶗@˂?&ȑJIȁ@͵`@4UqIٕ @Kň߉༘@WGˮȺCшؽ܈@@@ ءYκ8فΈ@@و@.ߚ μϼ+\}ؑ@˷@ys٠̙ڠ@׫ޚB.͓@@^̏!ڸˏُُُُُ#ُ%.ᰏ͏͏ύ'|bbb)X1qqq1+L>>>-͎/ĎĎ1xE3CCCʼ579@;@@r=?A@C@ʜEGI`K@MOQ1 Font characters by PaulC, Bilbo and Jasper Vries AP  ' B8   h     HWt   +4N[d P  '    0- B-3-fp h  #,$6;RYh   )5:5AO h  +.1,7<49Nh    +$5:> h   $N    # # $:$7 VKTzȉh   ,/ 8,8,WC\   /"GM\  (/"9E\ ")/69" 8  '8  D  $" h    "  5:L t  ((??A[ct  $ .)/;?GW t  0+1 ?V t   " 0(??Ua h  8OVh  *8?M h  9M t   $,5>G> i h    :!$(PYP   &+;P   */>P  0'+'/P   %)'/ P  : P   *+P ++ 8    )-8  (-D  ,28D    4 P   (+P    &+P  0'+P    %* P   *&+;P   .*/>P  0'+ \  ) =P     &0  " }$ G    ,:         \ - A. '' ?-T8Jagu8È F  '  2FZ. ' &-JgrFGG !!    #2@ A^b//Ok ݈ #2AP_n}ȌX ''/8V(B AMȠЉ />M PX ''/48Yd0TpЉ,;J R  )$Rap  '6  $<0  ">M\kz   =L[jy \  *GVet `X ' #0'@5Zz2iiຠ}ۉ$3B b .=Qdf{苈)?Řgaf{Π[hQ`o~ (7OOdy艈)?Øgaf{Π[hO^m| &*7PPedz芈yЏĘaf{[hP_n}*)Q&Q;e:dxyaȭƠʸԠ°%h&5DS @?R:Oy)?gafʸԠ°{Π[h[jy (3(Qcez芈)Ј>رRĘgaf{Π[hP_n} '6E(0<@HSX\X\.0t󰨐P̐H%8lj։ j. $?[*/P*8Tpш#. #1=Y*/P*8Tpӈ#.  25=BJ^*/pPTpш. '&2N*/oP*8Tp#   $6?Qlг  $6?Qlظ   #-6-?H`l    $6?Ql m '8>cl"D"fw݉"1@O^ &% /Mm*>C \""3DUfwщ'6ETm  ';@ Y""3DUfwш"\m %-?A P"33DUfwшRm .3 L"33DUfwԈщ />M\. #1 I-d8Jgu8LjՈ. ',.6>DM*Fb. '  #*G8F3%p     F%:AF3'V$(t!iш  '6ETcrȁ "3>MRW9DDW9A\AP_n}    -,1 !icLjC ' W)0PI_F-h  '.7;(18 P $0'+h  .!79SP   %*=Eh   $ $/3(98"(P  *h    #86?Lt    ! -N \ht    ?#[e\  #0FO\    02"JP    +$+;A\     2#/2P    *<D\    /"JP    )*=E\ *.CLP   ,A\    .#/2P  *h  '26 (18MXP  + 37h  */(28@MP    * 16h  . (29SP    % 16h  "!,$%5BP     + +0h  ($ 7\ 11/4M8  \ 15:,  \ #FMP  =C\ # FMP   4=Ch  #PYD 28h    :5:LP    (0?h    0B V P    %@ h   ) 2 6;JNP    ),t   ! QZch    0K P    + t ( ?\gP     +$+;At   ' >GV P     *%*<Dt  1(?@?CO\ ##*2.    %&( MQ [V[t    %[\ 959ED  "\  %50:K D    \    959DP     ) \  2#8DP  '*/>\ " 371B P  +\  &)'1-@P   "\  ,#1A P  '*\ ;*@1=D  ##\   "1 \  .,$EP\ 3IPP  >h    *9 P  0%)h 9NWP     ++;Ah    *8J P    *%*;h   !*/N P   :h $,79 \ 02  h  ,-;LP    -B    #) ).&R TITq ؄   #03# <3*F^lt  ",7? @ a\ #, F@h  '!(MP  "0?h   (SP    >h   !''(MP  "+D  39          + +                 + +         +       $ $ $$$$$ $ 2 &$$    $ $                       +  +            ??[Rpfy|БatǠ˸ՠ°{&h[jy  ' J(3:@GT]'o 'c6=܈  !?'RO裈3"Ufü#RX ' /<>EPc 0HIp|"1@m '8>dl"D"fw݉"1@O^. '*48?FLT/=*Fb諨~r. '&-2N*/&V*8TpLj   ' F%/6 BNUMYeIɈ؈. &-2Nk\/&V*8TpȈԈ    E*15ASYiQZTЈߐ. %$'/4LP*/&VTpɈ   ' D#%,37  gt}TlΈ݈. '(*/&V*8b~f h  '6ET    DQZTl|5@Z.   @&\B*/}PTpɈՈ   1%7B  D[*ӈ '5GJMV_gq/UGȂؾklJ؈ (7v    ?8@ Q!..Mgثo;6ȩ 6KBKS]eU5$ȸ躘klJ"1c    =:)4CEKQ-i|؈QZЬ֠C '6ETc  -1MQZ[8 /. %39 *8Fb~˸͈ۈ "*8FTeoy. ',*8Tbp~蒰࠸ǰ  *8F[]ksy. ' &: **8F莰Tby    &) -?uJ. ',*8Wbp࠸   2A PZn. ',*GSTp~蒠P  ,18?#]{ "'?B O_&,$9L_xؘtĠى%4CRaC 'T47M '- !Qc#T:Q.\sψX+dۗ '6ETcrȁ 3!&o_sETcrX &8 @b`h`pň :   &) : .9!7czĈX ' 0Prpxp̨ՉH  '6E #.9!7cD|X ",4 .9alcyĈ. $4<@M5D}evq@aНtЈ߈!   &(*. 8 C &$Rp.  )89#?]mevػ@aмÈ҈   ') .9DQ T_jRm. '  $25D1vsqP~蚰oآЫQՈ"  '6E& &$R?-p|.   ?LA^ev؟@aňԈ   )+- 79F ]hFx   %,39FS'4N[hȼɐؠ   ([GhRsg     ' 4:A^N['ʈ  ' '*,)AM0 ["3DUfw𸫠ш OC 'V65-c  2597AXc  ?=c   *;AWc  #BHWc   #FUc  ;Fc  ),?Jc  *;AWc  03AGWc   *ETc  03GVc  ETc  #03Jc  -Jc  *03Jc  :Dc   GQc  .;AWc   4:Wc  :Dc   5?c    HWc  .53Sc   .3Rc    8BXc  1Mc    9Dc  #4?c *: c #3 c   GVc   !#FUc   :Dc "5Rc   +;AWc  39Wc   :Dc  !4>c  , 9Dc  2"3>c  #$8BTc $1;Xc   %?c   ",4c  *$9Dc "+,"3>c   >c   %8@c  =Gc    Jc   GVc   #%ETc  >8AJc * G c  8AVc    GVc  79CSc  5?c +-Bc  5?c +-: c  G c  +-;Bc   5Pc   )*?Ic )#8Uc   *?Tc    #Jc  #/*?Ic (#7Tc   DSt  #"&%1?1.XcX ' 0) :!k E؅fȤI'6Ec    "IXt  3 34L . ' (+6OR)mz`Ljmc   $ $ . ' % ?LV4N[ș   '6E  )1!,^ jVԈc   *Jc   #J\  &)'13MP   "\ ;=D  "      . '  $25D1vsqP~蚰oآЫQԘz   '6E& &$R?ny   %,39FS'4N[h݈֠   ([Goqc   :@Wc   "39Wc   ;AWc   %?EYYYYP    =  '6ET  *6; <[)Έ݈c   IX,  \ "Nc   />MP E   +:IXgvc .=t   & )8_i$   '6-$U]R$$lk@Wnprtvxz| $D '6ETcr &5DSbqc  '7FUc  '8GVc  '8GV    8  8  8  8   \ *2\ *\  '\  + !   G#G7G ':G !9    HWfu   GVet  '6ETcrЁ    "& KZixc   />Mc   />Mc  '6Jc  !0?Nc   "1@Oc   "1@Oc  '6 Lc $P& & & &   '6Ep+ C '6ETcr ,c  '6FU9 9 9 9 D  /D   -      ix  & 8Fixc   BQc  BQ    t  #,67676dh   /1,-R\h  0EQZh   9!4R\$ $  $   .    E0`EKnȅЬКТΈ X '',8K[Y_ ry'~u`Љ *9H   % '9PS4     H BXBFc   "*6Lc   $ Jc   GVc   &IX       )2 do2  % '  &9$9FR Nr$$ȅZ$吲9HWfuc  .GV        ,(Xfcqb .   *F*~bp҈ c   *APc   8Nc     -FUc   DSc   $*8N        /3/CG61h\ ?!FMh !)2;ES[2 % $ m '6;AS:Ȏ|Оض#7'6ET   %''E' _l'4N. ' "*4*7bq c   !&Kc  %HWc   J!!!!   .8KNm       ) B5D'WEcuw@  02%? '6E )88ST6kpw q Ȩ'E&u6QQ_Deh։!0X ''/04$0lPCFXЉ-Mc  7FUc   APc   $+CRc    %#-1?Uc   !HWc   FUc   $IXc    +GVc  *FUc  FUc   $IXc  *FUc   *HWc   #)IXc   *FUc  *ETc   #/IXc  .GVc   *FUc   #*APc   *,:Sc   +GVc   Jc   HWc  +-FUc   ,HWc  'GVc   *GVc   HWc    *Jc  *:Wc  -ETc   *?Wc   / 5?5<6??@<)?""%90 56 ?"9%1@_ <<5 "9Y<?<Y H<"056?<<56ˀ <<5ɀˀ,"Ɂ_"˄Z̸؅蛱-ʈa(h  )>@?6. @??6<5?5H(9%""?/H <<%9"? 65"</ 5?5<6??@<)?""%90 56 ?"9%1@_ <<5 "9Y<? <Y H<"0 56? <<56)ˀ. <<5̃́- "l+q _"X˱a[ʩ,-a(h  )>@?6. @??6<5?5H(9%""?/H < <%9"? 65" <b'gPXSʹX)$(78 ̓́̈́ +  H'xL^̀$̓̀LOeHH$H8X  ˃ ˁ$< ̄ ̃lo    m,  #H ˈ$ )N T   %       X% X X 8              H ͘# ""  "",  A "  " "<3 "6    $1$H$$X       ̃  ́j   ̈́Tؓ̓qt   ! 8 [8 $H    X  t. ,%ˀ*, ̃́>,b'g,P,SʹX),$          ̓́̈́ +  H     H d3x ̀$̓̀$L$O$e$$ɰ$X     ˃  ˁ  ̄j   ̃Tؓlo        m!   MH ˈ $     5      V, ,XX8+ 5>>665 6?>?>6>@???> @>@>@> 6?? ?# >8@508@680@I>:5X>?@ Q >>@@? ?BQ>>@??>>BQ>>?> ?@66BQR> >6 Q? >?655Q>> 6>6gP+065PDPXX    8̃:T ͈́p| ̈́> >@>@>@ 6>@̓?>?>??> (qt?@6 5? >666>665Z56>s  h  -/</</<@?>/<>? ?@/5>>?? ???>6@0 6?6056)ˀ. 566<5̃́- 65l+q 5<X˱a[ʩ,-a( 5>>665 6?>?>6>@???> @>@>@> 6 ?? >?@?@@( ?@56@?>@H>>? ̓́̈́ +  h  ),)H)H)>?@H)@? ?><>??? ??>>5 ?6( @6̀65(6r̓̀5<665 T 56?<5oOAOWX     ˃88 ˁT ̄ʈpp̃@>6 @>@>>  >lo>?>>????5?6?@&? >6556N 6>666>m   h ˈ ( =/ / ,/_ p< @?>/_ <>? ?@@@>/0 >>??0?>0  66@0?06>?>>?5>6@>>?>6 `]>6`5(` ؙ  {JJ{{{JKJKJ{KLKKKJ KJLK (LH(L0(LL9KLJJL0HHXHgh ͈'6͈0̘G ̨J{r˰KJLKBLKKJJBK{(KL* PKJKHfPH{JP+0PPXX  ͈͈8̃: ́W ̈́JKJLJJJJLJLK{JL̓KLKKJ'*qtL.KL*KKJ{JKHJJ{{H HHsv  3<h '6EKZJ{LKJJKLKL<JJKJKKKJ{ʅ{. J{KH0H{)ˀ. Ʌ{{cUckh ̈ʈ5ɈK S   h ʃ   @  H H HH H ʅ H ]{{H KuH {˹ `ɅJ{`Z !#h ͈'6͠0 ̰G     r˸<  B< JB< {<   <K{  H P+HPPXh ' 5  L  2 2 2 JJ2ʅ 2HJ )ˀ. Ʌ{2 ̃́- Ʌl+q <X˱a[ʩ4-a(h '6 ?  V    <  C< <{J< ̀<JH̓̀R { T <l?<oOAOWh ˈɈ((Ȑ d  {     H H HHH  ʅ  H Ʌ{{H KH H {̰`H `ɅJ{ʙF` ] Hɘʠ&ͨ *   ̓ ̈́ːL  $  6 III JI%' #0 L />LKP_nLKHKKH56"/J/#$#^ H5"#"$$$#d$]."65HW/`#. 6z]\$#/ʉL-6/\"6oʉ$"$] "ؚ@&pЌ^T/JLGҘ^HGw$؝|/0#"٨0Gu2#ٳ_]bFrGJ/56GN0^/65-UIINҼ]_"6JJ0Ќ/^KKLNw؊⏺^BrJJYuG_HH؍،08_ ڬ$"vڍҽHG8cv6딨f650덗vԊmX0w#,ԉSԎ#0 L /01P_HKb"651%%$#"6HIĈ$%%#151" #$%&1'F#6 c2%#5I$$#621%&$%$ň/#1ؔ 56"$#$# bȔ%#"1I 1Y: b(#1K#1(鼈2IL5"R$3$HY1Lzb6(1ټ"c6"۰/_JHJؔ/(VIJ)X2PZ"ἋwJJJKД6ɋځ""6KK(8GJKLN"%&ዤ JLK(c1ыb-HLnZZ# HȔ$,"6c(%>ځ(.F(³GځG㪍ȍ˩p$3xێRa p 1 JKLKJ&5"66"6555Ve#$#2486/#$3#""6k "###5#5j555 6 _j; 6555I 56"65l@Ђ 565506KKLJM65j0$>66HJ3LLLK""5؟5553J566:#HI5"#6-/QJHJI؟LL#Y>uKKNLGJHظ>6bKLNڽGk"#j66ӰLKHGG6K" IILL IH1@J΋[jaЈ #0 L />LKP_nLKHKKH56/JH5 ^H5 /%Ȼ]HW،23z]+2L/*dk,] d  ،+. .5+ ]5pӡ Ѝ5LG2Ќ/HGѤI|/0غ| 0G B6_50a ]GJe ،GN0 05IINڼb0JJ0Ќ0ػKKLNw ^.rJJY0x_HH^]_JH⼣H JH w 駻HӨ8IbH딨fIȌ dHȌ2H60w#2핉Sb5Ԏ#0 L /01P_HKb51 HIĈ 1c1" c1'F-.15Iv .5ДřU. 15 \ c12 2 5Y: 5c 5'(1KL5Г (2IbД. 1O1L6(WѼ( (Y6(2( `JHJȔ \^"PVIJ)ДN(䊁JJJKVPKK뇉(~KLNДP(LK2(1u"PLnZcڂxH  (Px >xwl(@G ȍ׫x.$3xnRa p 1 JKLKJ&5555Ve  46/  5k46k5//5kk5I ]/gkj /2kȠ@5KKL gk>Ƞ HJ3LL6൸k9j6 3J5ktHI5Kk q?FJHJI؟ֈ/{KKNLGJHk ^bKLNڽGk?ӰLKHGG6K IILL IH1@J΋[jaЈ #0 0 />0/P_n0/,//,56"/.5/#$#^]#"$$$#d$/###""6-HW6/6-/ 6z/ʉ0/6./ "-/.-65"]/,+ /55.//p//665-/."5/.0.]/*6T565蛊0} /ٱ5|/Ѥ"b  +*Ќ2/غ0v+.ӹ"6,-+10_00Vؙv,+--1і_4..0#,-.^//01/_^/0..Y؍،_^_,Ѥҽ5_5.,/., ٕ#"_0_8c0_딨f65+*،+øڝ6G%,ԉSԎ#0 0 /01P_,/b"661%$#""6,-Ĉ$%%%$2661" -#21'F#6 /-1"6-6 1###1.c566"##%# -.51 $% +,Y: 1"+,.(b 5c1- Ŋ2-1*1#Y10(1$ɼ#*+ /Y$#+"^.,.Дt(17V-.)Ɋ2 -,f`../(ي6P(//(+ІF./01Ȇ.蔊0/Y$ڂ1⁹,0nZ1%"6 F a#"Pɍ> nl1 PG?+éè"2x5"`=/p 1 ./0/.&555555Ve#"6636/####"4= /."465 6 ./.-"66555- +,./- 565  *4 50"E//0. +, /.0i>/0000/6L"5؟F=5.޸5265C,-5-5r656/Q.,.-؟00"6ٓ>Ԋu//10+.,>6b/01ڽ+k"" 66Ӱ0/,++6/" --00 -,1@.΋[jaЈ #0 0 />0/P_n0/,//,56/.,5^,5/%Ȼ]02UЌ،2Ȍ/20/*dkޠ]0d/.5]5pӉ50G誑،/,+Ѥ|/0|Ќ0+6_50u+.ӡѤ+100Ѥ--1ʼ0..0Ќ0//01w0r..Y0__,Hʍ_.,ԫHu٤., HӨ8U딨fxȌ_ðdH60w#2핉Sb5Ԏ#0 0 /01P_,/b51,-Ĉ1c1"c1'F.15-.b蔈š.9ؔ5\j5 5Y: 51ؐ' 1/05ؔГ(2-bȔV^ 1O106(((Y(Y6(2( `.,.Ȕ(3"(V-.)(ዢP1.../VP鋊//뇉(И(/01P.0/(ڂPځP0nZx x,(ő( >V xl(zGYȍ׻(.$3x=Ra p 1 ./0/.&5555V/46^ 5k465՘//5kk5- /ikj  /kհ@ 5//0/jk9t,.3000صkȦ@3.5k;t,-5/kj?F.,.-؟ֈ/~//10+.,k^b/01ڽ+kӰ0/,++6/ --00 -,1@.΋[jaЈ  ) G e@xpp҈p;YPwPpP @Bq|B@ƈ|Ɖ1@m|6‰JtJ:I.v{. B.=L@ Bl{S  A ?.=L pB?锋}و D>̌|T>A|956xJښ   p4CBK&jye6 /2  *9  4]0 40 24ˆ0 0 4(1 4Z1h  1 ωl 0 3010 lP4<4ɰ14A邈  C    ba 4< 6 4n(h  4\8hc h)@'*cg  h& 2hJо/  hQ1 '/ ؖ h!N/2 h8y zАa   h8 H /  43 80 d  h 4 52/) 4h/dȐ[ ꗨ4ؐ  X,4g и4^EX ,4 1 )    4      ,KX hd -1l  1 4740 ) 024h ?0 4ɰ4N 04lv @d04- 20 0X훈8X  Fݣݱl L@ RRQR"1@>SSTTRBr>ZZRBQRTTVAQTTQZSRQ#"65URZSQZZTB6E%%$#"#655SQRSQx$%$$C65TUQZSZJ>:>E 5TSUTSQQZTƉΉ$#$#%C%#<QE=$#?؀#QZTVTщ6>"#RRSVZI͉ɲ2"?BV6<T Z鐊QZ}%65YSTUSꖫQRZQ<#t$ 5YRR&T"14~و ȏ%%"YQZR ZZ[b?T#6QSZXJTST"пIM#6"6RUQ8?ZSuȀAU6""PRQSqRQ&?S#"`Uɋ<&OS"BȸIo"Aލ6и<ЀG—ڒ$$tByЁKݍY|B:똎.=F?CJЉl{7<"tǸJYȎB`R``RY``&5D>tp>@ RRQR"1@>SUTTRBr>SZRB#"#"  #%$#$$$%$$ % #*9H%8=? %%l{7t%%KȉM>з=BBиA#t#"Cȃ \!K|&7AKC"56""?؂ п?""5QRSZY5661$Ȅɺ#665RQ>ZSZZZZAs* R%6SZB&T?TB5VɄ%"5ZTSZ ZZSTZTTSZQZQ>x?"6Z0/BT?SIZQɉ{ɷ $"653>&SCHZ55A<ؿU$#5ZQQBT"ЇK["@RBHSYSSS :RJSTEߍ6~I5"܆[tQK W:TS? .=_WBzxQY2ARZQۦfu>@ RQRR"1@>RTTSSBq>RZZSQRSZQTTQBVTTRQ>y TZZQSZRQ56"#*9QSRQS556#"#$%%l{6ZSxQ}UT|$$$%$tSQQSTUSQ5|>B$B|;QG#%=%#$#tٯTVT>#"й#Ѐ##A#K ZTZVSRRص=脉6TSTTD|u~>A?""5jRUTSYvйЄ665RRRjؼRRY5txC6SZ” Yl"(2x~E#"5ZTZ6(RZSQ躹tp`6.BA8QUR6"t37Ⱦ"65T TSTSQRP""6+n?Ȁً$#5ZgSU`lʦ-1ھN@RMI-}?"AaC'29⭰DHt}оoЇ$F)ȍ5(.=#6:Aуl{7ɿvYB`R``RY``&5DVpB@ RRQR"1@>SUTTRBr>SZRB#"#"  #%$#$$$%$$ % #*9H%8=? %%l{7t%%KȉM>з=@EӉ#ุ?ȏ2>?;C ?!t6>""}L>؝؉c~ф """65QZ7ٴ#" "665YZSRQ>RZQ<#k.=EX?ZZZZSZB&T"4|9>TBTSZZ[STZ>{: QZQZSTTZTSZZQBTST"oAOQZ7SAT>&ZSuʼؼێ58=SZRQi<(T<SZQ}m?ѱSSSY';<:BzlSTTS2Zwѱ6mtz:o5躈°2ؽBɳSAa8|)~QTSyFκTTvBŠl4CqRR> @P>DN\n/^>.`8N`nxRRQRRRSUTTRR SZR#"#" #%$#$$$%$$ % #% %%(%%'=)6:8=$n#hX#S $#'n ## %+" 9t#"#Ї """5QZ+eȺ 665RQQRZQJ#ȱgHТ6SZRQT"*س&ѯ#) "5ZTSRRZ[STZV>AGq 6ZTSZZQRRQTST"HACQ65TT>RRZSY*Rm$#5RRQTtȸ8aڼ  !/"E$ т:%N0؁ȵnplo+"\ٹ㎠bAêȪʰY Q`R``RY``*::RR L@ "1@>Bq>#]"""¨|#[[[#"65\\"7F %%$#"#655?[x$%$$C65p["["[>:>E5"\##Ɖ|#$#%C%#h`>[6#?؀# Y66[["Ω64؀#""Y͊ɲ2?B# r`p""i~}% Y"\[芚&qv=tٌQ\#[\"Z`"1<A|C%"YY[R髱?T#662## RA"6ٺ?وɌ #6"6h#""øp߻@ "1@>Bq|Y" #$%$%$$$$$" #$#3$C K#*9H$%%vB$#Bw>yؿ%%F؉|.=B)9CA Jtz{ \ #J|"#"cBAG%"56""?cF ȝ#'BB6$Ȅ$#6$i6["YYA\iɉIRM"6Z& [["Y`5{VɄ%a"65`[[[""-`>xf56"B ""[Y`ɉ{?65"Y55AK<ؿ66߉BɊ 26["#Y" :ړE6""J邍6B" "5"DԔtA[[ꫫݍL"#?[" .=[#\IWBzxHM\؏3BRꗏBr@ "1@>Bq|"""]#B|[#[["\\56"#*9 556#"#$%%l{t["["[p|$$$%$##\"5|>B$Bt|"B`h#%=%#$# "[[66Yй#Ѐ##A#J>[Y""u>w~J"#"| ""p`r|u~>A"ԈBlv [\"Yvй6$B6&"\[#\/tȹC#"6Z.[gYYl"(2x~?5`[.##y6躹tp"56oBh6"t37Ⱦ$65"""6+K"?Aܤhhlʦ-A6-1M"6-}?13Ȋ½C'2jpDȍt}о$qMȍ.+ȍf*r.=#$6:Aكl{۴ه0?>V&jy @i>DN\n.\<~,^6L^lvY"#$%$%$$$$$" #$#$ #$%%+"$#1?E"$R[`f#2$uL'#؃ؔ#$ #qus& '% %#"#"ط*q%" """65i1E N"#"62qW7"tQ"ȃ"67YY"["`tjЯس5`"[[[荹gT>? `Y""[[:A"6At`Y[k""xq6Ѹ@55Y"jx+wkэ#$^.Шэ""Y#"[^ .х"0 2u6"51"ZȵmQ[['~ Y#C[[`'"[؀\#" t(8 @i>DN\n.\<~,^6L^lvY"#$%$%$$$$$" #$#$ #$%%+"$#1?E"$R[`f#2$uL'#؃ؔ#$ #qus& ! %#"#"T.طثq%"" 1 ""##"i1ؑ6$66qJ:"tQ_l6"`tjЯس$ѭ#65`[[軰a>?G"56"BA"6Gн$65n,i'@@ػf66+wkkɮ;x6Шٜ?Y"6 ./## 240ȵm؆5Ќ {^ٻ`®؎#pصoҴ"(""(8 Lf@ YZZY"1@>\ZBr|[Z[?ȺYZ]]Z\D\ƈ #"65ZYY[\\\؁艉8G %%$#"#655]]Zx$%$$C65Y[ >:>E؄HJ|#$#%C%#YIˊ6#?؀#ЄYG[\[R64؀#YY]=ЊѲ2?B#][JBi}%X6`YYpv"$#tь`YZ=؂&Y;<%~و ȏ%%"C]ZZSb|?O##6ҎZ@+пIM#6"6QSYȰ5SɌ$6""Z[Z]ZZ|x53?S#"\ـ3&QU脌B"?"Aލ6|и<ЀG—ڒ$$tyЁKݍY|B:똎.=F?CTl{J9="t#55[tA&5D>[Br@ YZZY"1@>\ZBr|YZY #$%$%$#"#$"$#3$C$ K*9H$%%~<#DBz>y%%F腸|з=CE$)9uAPJt#"زC \!#J|"&AI%"Y6""?c?؂ п#'BYY``66$Ȅ$#6$i6&\[\B\iɉIRM"6YZ&[ZBAxVɄ%a"65YZYZ[eg[[Y%ȁ|B5[BDBى{? AY[Kы<ؿ$?"66h[[ZY[``#"۽2P6Fً[Y`6`N :ړE6BٌZY`̺邍6[ J~չ ΍tp ݍR66Bt .= AWBzxM ኈ>|㜎&(7Fds@ YZZY"1@>\ZBr|[>[ø|[Z[\Z]]ZYƈw \\\[YYZ56"#*9ZZZ\]] 556#"#$%%l{yZY|$$$%$68ظYY|>B$Bqu\>"##%=%#$#.\q[z\>#"й#Ѐ##A#J>uC]YYص~J"#">6[]|u~>A"ԈBZ[`6vй6$B6غ~CZY`tȹC#"6YZ&Z-t`l"(2x~?5YZ&mr}6tp"5"B-d/6"t37Ⱦ$AYZZ]7Z""6+K?"66%vlʦ-A6|٥-1M"6-}?13Ȋ½C'2jpDӉt}о$qٴ؇$F+ȍа#v-솎.==6:Aكl{w|ɿ55[F&5DBr@ YZZY"1@>\ZBr|YZY #$%$%$#"#$"$#3$C$ K*9H$%%~<#DBz>y%%F腸|з=@E$)Ьu?ȏ2t#;C ?%tʃ%C}L>؝%2п> W"""6RYia)Aَ""66``Yꕫ&Yp/ٰI=EX">>\[Z&YZ<89>Z[ZZYZKY蛹٨>{:%Y[<Z[B\@xooAI>=Ԡ&YʼؼP""5[賩"(#``[?[\ཌрm "`6`Y[u:|2+l`t།|wG6R.Z5z΍BӃr <)&mJy&.3ڔm༎f(62An}Ϲ @J>DN\n.\<~,^6L^lvYZZYYZ\ZYYY#$%$%$#"#$"$#$$ $%%+*6##*-G%%"9J %$$uL9#S ##qn ! %/8s%""Ѓc 1 ""##"Yi؋d5ئؑ6$66YYYpJ"VrAeFU"65Y7aس$ѭ#65YYZ[xa>?G 52[ZЀ@P$G$AYnY_(R%$/ "66YYbYkk{;x6dٜ?Y"6 g/## ˱40ȵme`[$% }^ٻ\ȍڇ$ص0"#55[YYY([+Y8@ mttm"1@>@tBr>@@vtBrm??vAЃƈ#"65mqm?<@tvB5D%%$#"#65irmmtmAx$%$$C656BvC>:>E؄>r?JΉ|#$#%C%#>>?n$v@wƊ<##?؀#6r?t= t64"#i>??tmNsSѲ?B#>mmG $66|п%#6"?@vv#Pm5r6v=tь=t?AZ&5>51<A|C%66qmr:Ztt>6$"uѽ?T>t??Ri5"s?وɌ=QmXm6+:?5QSɌ $6""m6>tL?6&< ?S#"=mр3&OS"qqB "Aލ6|и<ЀG—ڒ$$tyЁKݍY|BӉ똎.=F?Cal{J>錎#66"6t r>s>s>rr>r6&5D?m?m?mrds@ mttm"1@Orm?mrds 6r>lrr=r6#$%$##$" $#3=%% %M*9H8<#؏l{>tȉ|.=B)CAPJtzxCȃ \ #J|"#"cBAG%".6"?c?؂ TȝfB??rl6$ȄDVi6 mt@@t@m?r6>A RM"6r5Z>#@tt@"6?AxVɄ%"65>5@v@tvtmt>5"%ȁ|B"55>tt@:v@<tt#Bى{?A豸tvvm?>q>ы<ؿ6mZBvI?m>q#"2P6st>?>5=PғERBF#@r?>>=̺邍6BoӉt @ Rݍ<r56Jt:G@##"t .=wt>l{x#N@v??>>BYvӺ,;J~Br@ mttm"1@>@tBr>tv@@B}?v??mr>vо t?mqm56"#*9?mtmmr556#"#$%%l{|@;m6|$$$$%$t15m?r>|$#>B$Bкwv@$n?>>"##%=%L2.m|w@t?r6й#Ѐ###Jl0s2mt??>itȵJ"#"l$2mm>ط~>AB|#vv@?uvй#$""#66#?t=ٸC#"6r5Z&ٳ:mrmq6l"(2x~?5>5ZȺ'@??t>tp"55>B@6?r=tCGȾ$Al?Lt>6+1KA"66mZ|>>Yʦ-r6qq-1M"-}?3Ȋ½C'2(9pDȍt}о$0Mȍ.'hȍƻ%r65D:=A:x|xу66##6"ꕎ 6r>s>s>rr>r.4CRr?m?m|p߻@ mttm"1@Orm?mrds 6r>lrr=r6#$%$##$" $#3=%% %M*9H8<#؏l{>z|;>CR)ЬC?PHJtxCȅ ?%tʃ%#"#""}L>؝%$$"?: ن"""6R66#6?Aَ#"S"#6lr??m5r;ٮ.wȗ"> "66r?m@t@@Zmt@5>5(89#6"|@tt@#Btt>6?>{:66>t|tmmtvt@vi5mA{غ#qm@@v:m6<P"6>q>?mvs@vìZ6-"ڦ(#$"6q>m?7Cрm?ѱ|=5>?>ts|2zl=>>?r@:鷈>|w6=mt @ *6rẍB#h9:7.=twcxwB>??q#ᴎ|)Ǝڭl1@>؂Brd @J>DN\n.\<~,^6L^lvmttmrm?mr6r>lrr=r6#$%$##$" $#%% %!+,#4;AD.73JG#2$uL'#4ؔ#$ #quQ ! %#"#"T.8Ѝq%""/ 1#"66#63E ؑЃ]66m5r37"\ jU "6r5mmt@5>5tjЯٻ$ѭ#63@tmtt>6T>?G"55>:Ѐi5#"(н$Atm68ѸRk6mm6m"*еx6ٜ?Y"6 ./## +\0ȵm5Ќ {me`}ЎŽyбȸW66"6$$ s>s>rr>r6(?)(8 @J>DN\n.\<~,^6L^lvmttmmt@tm @@vt5i6> tm5qq5i2v ks5iltmLP  qkLv tm"r5i>l?rvm % H&k"#bv@wf  'PrUؐrrk5?wPmtm Q  krskimmmmtstm5i3؇`аmqil?@665i d5 rqi>@vvm* tr5kr5 Ȣ&`rk t@#rl;mmq5kk L^qltt:? tt>qkmk |٠>>غ@m>5ri Ѐ;ɼllP9t>k5*o`imK>6k5C8t|fl5dصpr ̨64œ3ڿS ț4 E  cU      rkkiikgmrkir>s>s>rr>r6r??m?mr8 @J>DN\n.\<~,^7M_mwmttmrm?mr6riiir=i6kkkkkrmiikikk            *00 6N LRdg "r~  ki & p<ȐЯi5mm*6]0إy i566mt@@t>ikm:؛ 4  5rk5rt:@t=i5x\ >  kk5qmmtmv@tvt@5ȁ  kmkq>tt:t@:v@@r"i  ir5>m@tmtt@t9rt  55k{h5AmtɍH 5k6hmstqpp355 2@?tm@mt5D .mlʠ ( }i5rX4œ qmt?!:@?"Ɂ'mam Я? pkqi@v?Dm9@ mttm"1@>@tBr>tv@@B}?>6i5>vȾi5qq5*9?mtli5sk l{|@>>kq> t15@t?l>i5r| кwv@#"k>|   ƒ.m|w?5krrw? tl0 stmmmmiksrktiqr?K i566mmlt#>ikt|غ 5rk5rt:ttlqwy kk5qmo'@>>.г  kmkq>B@@ll躈?؆ ir5>ml>K鵈q3{5khlz}}D 5k6t9:ѿ5;<>C 6E-{tBl:ɍ) tq̎:I  l{    rkkimrk ir>s>s>rr>r0???m?mrds @J>DN\n.\<~,^7M_mwmttmrm?mr6riiir=i6kkkkkrmiikikk            * -9 = LH= mqA 5iCaвظ ik665i )ȑ2X mmtr5kr5 Г EN6mki>t@@tmmtmmq5kk  {  p5i;t@>tt>qkmk ?(jx>mwmtvt@v:@m>5ri ѓZ@iqr@@v:@x t>k55  r'v6t:6k5 *A &p5tt;m5иhXtmtsk` ‘5tm@mt?-Ȩl)tl( q 5r5t @!im?ma"?;:12B96pHؼomq4?t@`4?v|)m9 @J>DN\n.\<~,^7M_mwmttmrm?mr6riiir=i6kkkkkrmiikikk         +20 6=XL: &G2bYЃO 5iЛj(Ш83 i5665i ]3ؾ8 i566tr5kr5 e؛: и 5rk5rtmtmmq5kk $/?؋ kk5qm9 tt>qkmk L ؄{ /q>:m@m>5ri ЀVȻCЀ ir5>m@tmt>k5 }8 55k{6k5 0zj- 5k65b@ʅ55 ɔڠҧ̺/ +W qȨ rʬ%ڒ | _    rrmrkir>s>s>rr>r6)??)9 e@ Ԡ"1@>҈Bq>D°;@ԡ҈ƈȺؽC8Gt8?=Ol{#$#"B $# "B~ "##"# 5B#$$sGK ""#$" 52666B%$$#>#ƺl"# "%>5ڪBC8ʸ|][>(" 6|#B|'56 "ْ1Z|~q666#j)n|k#" >U%n؀r $6}563ѲЂ,Bȅ%%$>$#.±F'l m9lٰKғC$$ª66#5Zˌ$%l#"oQ""5"65ْYk#"AY.=LBl{BC 솎ƎRŽ>0?>Bq  /@ 'KMN/>M>MNIKJp>KJMNA L>IKÑ\]^] >á?[\]_\B>غLHHKȅt^Y^\[\G>IKMKHÉz=Z[Y[[ HJ5LHJHZZ][^[]Y[Z]Z^[|  HIMN>؂B Y]^ZZZ\Z[[ > A7{7>@]`A>[]_ @AEǩ}] \>Z?>]A[\^ B AzELj `]@>@?Z\[Z؄AIJHEKJNI Y8][?@"@F^@ \]^]AK|\[`A?vn@\][[\Q]MNGKGHH 6"#NZ QEG> 6NLY:QE|  ߈ nw [] Qڊ < MN Y  ؁QZڊ @=>| oN ZYY@Y]Qڊ  >?> nxY@\Q >  ? Znw]QZ    > YoNBQY| @ |  S Z[\ZM B"n{    @  >[[N@nL ۑl @  ܷZZ [ZB@Nz>؀t [6GYYnw;ۑ??  B9??MNٌ 2|ѲYZ@BZ :!.ٲ5 |@nxٌۑ< к>B@<@wɌ4|l>B7л9<oNɌs6>BٺػQR>Y*}V66ػYɑ6J Z[ZZ6BZY7 T 6|ғ[>r YŨBғٲ]\>MP  >ǨB a؀^8G 6v tb  J   , HHGGHJKGHKJ GH, HHGGHJKGHKJ GH,  GHGHHGGHJKGHKJ ,  GHGHHGGHJKGHKJ   v GH KHIFKHKGHIFJJHJIFGHGHKG/HHJ  !T j G LGHKHIGFKHHKGHIFJJHJIFGHGHKG/HHJ  !^Ha^v HGIHK HKFJFIHGKIGFIJHHGGKHG JH2IJMGC av HGIHK HKFJFIHGKIGFIJHHGGKHG JH2IJMGC a   , ++**+./*+/. *+, ++**+./*+/. *+,  *+*++**+./*+/. ,  *+*++**+./*+/.   v +, /,-*/,/+,-*..,.-*+,+,/+/,,.  !T j + 0+,/,-+*/,,/+,-*..,.-*+,+,/+/,,.  !^,a^v ,+-,/ ,/*.*-,+/-+*-.,,++/,+ .,2I.M+C av ,+-,/ ,/*.*-,+/-+*-.,,++/,+ .,2I.M+C a  (  LLLLOONNN8G OD LONe !@IIJJ <>I!ᖠaHII [ >H!![HHHH cIIHd KL<@ AS[@IJi [!@ JJ< JK@ 1[K@!K<K! I<[@HK8>IH@ J<HII[Z`<@Z ⓈZ9Wu,Jh2, LLLL!0*OONNNP_n +O\) LON+ +-}T- KKT+KK-}+  JKKZT JJKiT+ J-+X-PVXIIJJӹ)TVI-TT+HIId'ȗXH-w+ HHHHwӨ+)IIHwTX, LwӸIJII-R+ٍawT bJKXw`KXx'TK-w+Ѵ^w+X`-Ѱ+VIHHxw}T*H,+Tސ*HIK''T,NTTXHHNw),Jҍ ITʙJyP?ᤉP'ʘXO,"벉`"щ"<H'6GHHGHW,},GHK؏֏刄܈5-.  &5 LLLLOO HWf OONNOL/- LON/+-/ Ո-/K/- KKLK 3X JKK/XX -/J]݈- J/ LL+z/ N-II.OLL+I/N/X-HII]K+HH.z\-HHH麨-.ẠX .KK/L-CJIKKH.-XIHHJKJKI.,HIIJJȲAKJJȄ,./-JX%HIK ٙ-∄.I+/X-\HHZ-HJܐQ+`.HJI&+JJfZY\䍱.h< ph8GetV龎GHHGŐ.J.*؊KJ@O|戸֏C-.  *9 OOLLLLKZ- LONNOO z-NOL / ؃/1-K-/ KLKK /-KKJ ^o KJ- 1`  -J /  -h`.II/Nᰑ-I1LސIIH-/LLN4.HH/aʷHH\/Kߊ./O-KKH. `ް.IJA/L-HHI0?^8.0ؐIS-0АJJKCMJ蝓`KJ/t/-.0K\٣KI4/3 r/bތ `1KH `J. *9먍Xg . ލú@Hp.p%>MkzGHV.HHGȎא\B.0?GH\kňq2,LLLLKNNNOO.-DKJ E=!#IIKJ D/C}KeK_KK! HHHI@eKH "!J DB鐐@"eJJ DIIDJJ ňK"DQfoTvјωH  4  $3 H57Zi35 HH3j4h݉ HH5255(7452qk55^mhj2k 4IIhdrr532ilhJJhkk2iilh2d=64Jdrrkȡ5iklɐ,d kkir259imkiٴdrsȠd2^, d5d2s3ɐiiȈ˜sr,k,dm5rdX'k^@rXkȉrXdd剐&0?l&Xkz퉊Xԍ  2  #2/H Wf131HH 4125541HH /55kq41d2` k41dډi4k5rrh1II2`ii45kkdJJd ؑhk4dki5ȑkrrhk5J2rikkh5Љikmikk5Ј4hsh4h5h5r8i5rsrsЉmh8h1r5؋kɠrkprJh zh쉠iڌ띍 p8:I؍jyw4  $3 H57Zi35 HH3j4h݉ HH52(74526lhjd14IIhd 6hJJh 6 hdg  54J2 Alɐe25ޑ3$c3ٴd1f2ِ[ 002-Вވ\$,]ð.d2X$ᑈȜ;ھZɑ҉rёc*+& 2&7FёXkzD  2  #2/H Wf131HH 41241HH 041d2`3h1dډ0 41II20 idJJdؐ1  ehII%3 43J21؟g蟹35834f5Јh4ggh6€6-dq<mh4׸џ٠:phѠٟl=֌J8џzl:4ɠhЉL 0Љ880؋שppJвpzp ڌЈ`Ҥ:I jyw ( `( !'LJ  (I  PPLHKKHHHJI  IJ%HGHG+G.I(ЈJ((S@ Zbnz @Y>DO]o/]=-_7M_mwYZZYYZ\ZZ[Z[ZZZ YZ]]Z\[\ZYYY[\\.5qZ[;i5rrq557m 5rsk_ ?ZZ5sqi"H%&@ iqk5i F,)H1 G-V[Prrk} 5ik2]Ƞ90k@562imZY\ pn6Qsh5iZYټGyp^ii]YZ[Zٍɀx\4YZ=)ɼYZY }؀[YY`mkmE9zZ]gYYD\6Z}iYY\Y i5k`HBY rlkr`Dڜ p8 ҝ5liѼ*HiJ٠ʐLmkiؚ"fi`NsqkiTɹSZQRS TSSQTQTZTTTRRRR ZQSRRRRRR @R>DO]o/]=-_7M_mwYZZYZZ\ZYY ZZZ[Z[YZ\ [\Z]]Z5\\[YY55qrr5i=[Zq Q ksr5 ZZ1 i"kqs5ZNP9! i5kqi&"#@ P~'$) ki5skrrX%sR,ak`ȰЀ[.YZAkmi$baip :5h'\ZZ]٥iiBixoY[YZ\\ٹɀ!\[ \Z[ YZYɜz7eQn]ZF>3pkm<Y\YYiK.x:tٌ[ZZY~tQ kk5i Y }/DkrغEӲ@Otɜkr5`3wiҳMikm|ER0\iZDY [ikq\ YnZ ZY9 @Y>DO]o/^>.`8N`nxYZZYYZ\ZZ[Z[ZZZ YZ]]Z\[\ZYYY[\\.5qZ[;i5rrq557m 5rsk_ ?ZZ5sqi"H%&@ iqk5i F,)H1 G-V[Prrk} 5ik3^ȡȬkA562im ZY\ pn6Qsh5iZYٽHyp_ii]YZ[َɁx\4 Z\=)ɽYZY }؀\umkmE:{Z]hZZ[D\6[~iYY\Y i5kaICY rmkUbEڝ q8 Ҟ5miѼ*`iJ٠ʐLmkiؚ"fi\`Ntqki[Y \Yi * ZY: @R>DO]o/^>.`8N`nxYZZYZZ\ZYY ZZZ[Z[YZ\ [\Z]]Z5\\[YY55qrr5i=[Zq Q ksr5 ZZ1 i"kqs5ZNP9! i5kqi&"#@ P~'$) ki5tkrrY&tS-bkaȱЁ\.YZBkmi$bajp!:5h(\ZZ]٦iiCjxoZ[YZ\\ٺɁ"\[ \Z[ YZYɝ{7fRo]ZG>3pkm<Y\YYiL/x:tٌ[ZZYtQ kk5i Y }/DkrٺEԲ@Otɜkr5`3wiҳMikm|FR0\iZDY [ikq\ YnZ ZY: @Q>DO]o/]=-_7M_mwmttmmt@tt @@v mq>?v@@+ hrlt?ttv95rh=Kt;i5rqp557 ="tt 5rsk_ ? K5sqi"H%&@ iqk5i F,)H1 G-V[TPrrk} 5ik2]Ƞ90k@562im rmmt?> pn6Qsh5itm#?>诨p^iirh@tmrٍɀxr1Ȁtr"=)ɼ lK> >@t@9[@t>mkmE9h?vL@mgtmrlL\6Z}>>>?m i55`HBl lkr`Dڜ p8 ҝ5liѼ*HiJ٠ʐLmki!"fi>`NsqkiK>>Kk?t?r?mlm@ tm9 @R>DO]o/]=-_7M_mwmttmtt@tmm v@@ @@v?>q5(vt?tlr55pqr5i=tK=r Q ksr5 tt"=1 i"kqs5KNP9! i5kqi&"#@ P~'$) ki5skrrX%sR,ak`ȰЀ[.mrAkmi$baip :5h'>?tmmt@ёriiBixoY?#xrɀvȀ vt@> t>Klɜz7"rQy@@Lv?F>3pkm>t@ymht@?>>>K.x:t|lrmtl~tQ k55i m }/DkrغEӲ@Otɜkr5`3wiҳMikm|ER0>iZDK> >Kikqr?@?klm?mnt@ @m9 @Q>DO]o/^>.`8N`nxmttmmt@tt @@v mq>?v@@+ rlt?ttv95r=Kt;i5rqp557 ="tt 5rsk_ ?ZK5sqi"H%&@ iqk5i F,)H1 G-V[Prrk} 5ik3^ȡȬkA562im rmmt?> pn6Qsh5itm#?Hyp_iirѸ@@@tmrَɁxr2Ȁt r"=)ɽ lK> >@t@:\@t>mkmE:?vL@mhtmrlM\6[~>>>?m i55aICl mkUbEڝ q8 Ҟ5miѼ*`iJ٠ʐLmkiؚ"fi>`NtqkiK>>Kk?t?r?mlm@ tm: @R>DO]o/^>.`8N`nxmttmtt@tmm v@@ @@v?>q5(vt?tlr55pqr5i=tK=r Q ksr5 tt"=1 i"kqs5KNP9! i5kqi&"#@ P~'$) ki5tkrrY&tS-bkaȱЁ\.mrBkmi$bajp!:5h(>?tmmt@ђriiCjxoZ?#xrɁvȀ vt@> t>Klɝ{7"rRz@@Lv?G>3pkm>t@zmht@?>>>L/x:t}lrmtltQ k55i m }/DkrٺEԲ@Otɜkr5`3wiҳMikm|FR0>iZDK> >Kikqr?@?klm?mnt@ @m: @Y>DO]o/]=-_7M_mwYZZYYZ\ZZY[Z[ZZ YYZ]]Z\\ZYZYY[[Z56"#ZR[;i56#"#%$%7SNZ 56$$#$$#?Zp58##"" "H%QY5"D"  F,)QQ6J#&66# G-V[VZQ5*""2]4X 065567 2gZY\ pn>5"#hяZY\Gyry56655ZZYZ[sp>#Ѡ.[ZRЀRW|ZYZ d\Аu55ٞ:؂YzZ]ZZ؈4#";\6Z`9Z\Yhf` jڰ#L`Dڜ %p5Iθٗ$l5Zꄈ*`Zɠ~L%#5ir $$$%#ki\e##i[ٸ \[ZY) ZY9 @R>DO]o0^>.`8N`nxYZZYZZ\ZYY ZZ[Z[YYZ\\Z]]ZY#"65Z[[YYZ%$%#"#65i=[SZ#$$#$$65 lQ1 #!##55YNP9! 'G"5#$A  #66*#6QQ'$) "".5QNsMR,a562" 6Ȋ,Ѐ[.YZB6-)_ȉazj56#"5i;h(\Z٦Z556rj;oZ[RZ[Gٺ"<u"Z\[- YZYٜ3ndefRoZZ]iYYGу55ZmYYY`ZLدцы5"L6<`@Tp3l Y p5ʜ ٺE%Otɜ5`rр#?i5#|F  \ik#%$$$DY [i##\^YnZ ZY: @Y>DO]o/^>.`8N`nxYZZYYZ\ZZY[Z[ZZ YYZ]]Z\\ZYZYY[[Z56"#ZR[;i56#"#%$%7SNZ 56$$#$$#?ZY558##"" "H%&5"D"  F,)QQ6J#&66# G-V[VZQ5*""3^5Y 165567 2hZYQRZS pn?5"#65 ZYRRSTٽHyrz56655`Z RRQZZSTQtq>$ɡ/ZZ\[ЀQT ZZX|YF b؀RR\ TSmQ55ٟ:؂Z[\[؈4#";\6YRhѪY kڱ#L9ڝ %q5J,rҞ$m5QѼ*`ʐL%#5i@9 $$$%#ki``##i`YɹZYYhZ\* ZY: @R>DO]o0_?/a9OaoyYZZYZZ\ZYY ZZ[Z[YYZ\\Z]]ZY#"65Z[[YYZ%$%#"#65i=[SZ#$$#$$65 lQ1 #!##55YNP9! 'G"5#$A  #66*#6QQ'$) "" Y5QOtNS-b562" 6ȋ,Ё\.YZC6.)_Ȋazk56#"5i;h)TQRRZ٧`556rk;o[QZQZRRYZ[\ZZỹ္"=uR#TZSBЀ1 -Yɝ3odeSSQSZSRR[\[Hу55Qm=RQh[Mدцы5"L6<SYATp3m R q5ʝ ںE%OtɜQ5`rр#?i5#|G  `ik#%$$$DZ: Y`i##\O\Y^Z\nZ ZY; @Y>DO]o/]=-_7M_mwmtmmmt@ttrm@@@t mr>?t@?trlrltttK56"#r>Kr;i56#"#%$%7 >#tt 56$$#$$#?ZK>58##"" "H%>5"D"  F,)r>6J#&66# G-V[ZK5*""2]X 065567 2gmmt>> pn>5"#hُttm@#?Gyry56655r @tmmttvrsp>Ѡ?@v1Ȁt#>&| mK> ?@t@w[ >K>rr55ٞ:؂>tL=tmg4#";\6 >>=>6mmmhfl jڰ#L=Dڜ %p5Iqҝ$l5rҚ*`~ҐL%#5i@8 $$$%#ki>e ##iK6>Kl>>! ?l6Kmt?llm? tm9tm @R>DO]o0^>.`8N`nxmmtmtt@tmm t@@@mrlrt?@t?>r#"65Kttlr%$%#"#65i=rK>r#$$#$$65 ttl1 #!##5>KNP9! 'G"5#$A  #66*#6>'$) "".5KNsMR,a560 6Ȋ,Ѐ[.mB6-)_Эazmttj56#"5ihЖh( >>tmmt@v٦r556rjoZ?tmxv@?ٺ"<ur"wt t@? =>Kmɜ3ndeR>@?Lt>Gհ55rr>Zzmh6>=>>Lد5"L6<l@ɿmp3l m d5ʜ ٺE%Otɜr5`rɀ"?i5#6F  >ik#%$$$DKR6Ki##K6l?O>>lll?tmnt@ ?m: @Y>DO]o/^>.`8N`nxmtmmmt@ttrm@@@t mr>?t@?trlrltttK56"#r>Kr;i56#"#%$%7Ttt 56$$#$$#?ZK>58##"" "H%&5"D"  F,)r>6J#&66# G-V[ZK5*""3^Y 165567 2hmmt>> pn?5"#65ɐttm@?Hyrz56655r Q@tmmttvrtq>ѡ?@v2Ȁt &| mK> ?@t@w\ >K>rr55ٟ:؂>tL=tmh4#";\6 >>=>6mmmhѪl kڱ#LlEڝ %q5J,rҞ$m5rѼ*`ʐL%#5i@9 $$$%#ki>`##iK6>Kl>>! ?l6Kmt?llm? tm:tm @R>DO]o0_?/a9Oaoymmtmtt@tmm t@@@mrlrt?@t?>r#"65Kttlr%$%#"#65i=rK>r#$$#$ $65 ttl>1 #!##5>KNP9! 'G"5#$A  #66*#6>'$) "" Y5KOtNS-b560 6ȋ,Ё\.mC6.)_Юazmttk56#"5ihЖh) >>tmmt@v٧r556rko[?tmxv@?ٻ္"=ur#wt t@? =>Kmɝ3odeS>@?Lt>Hְ55rr>[{mh6>=>>Mد5"L6<lAɿnp3m m d5ʝ ںE%Otɜr5`rɀ"?i5#6G  >ik#%$$$DKR6Ki##K6l?O>>lll?tmnt@ ?m; @Y>DO]o/]=-_7M_mwYZZYYZ\ZZYZ[ZZ[ YZ\[Z\\Y`5ZZ\]]qq5[O;s5 7Y`5k  ?Z8 "H%"@    F,)؀Cf;*) G-V[*ȐL. e2].Ƞ1`  i56272gY\ p6ɏYZYټGyРpkYZY鉱 Vi3[Ȁ iki`Y b[iS>Bbz[\YgZL/6[YR`=ڲ lϱ.J pҝlꬨ*#&}0m` 65rZZqki\$) ZY9 @R>DO]o0^>.`8N`nxYZZYZZ\ZYY [ZZ[ZY5`Y\\Z[\Z5qq]]\ZZ 5s=S[  5`Y1"NP"   1'$!& '&sVFK(t 4*~ TS*i X/б22YB61\aYZYj:Ц'h(~YY\x:[YZZZZi$ y"5\#Ѐ/ YY`i܈ SkiR=YGIG:S=hط[Lh+:6St(+2‘R D2. sвOҝ 4Ғ. Mɨ[m`DZZ r56\ikq YnZ ZY: @Y>DO]o/^>.`8N`nxYZZYYZ\ZZYZ[ZZ[ YZ\[Z\\Y`5ZZ\]]qq5[O;s5 7Y`5k  ?Z8 "H%"@    F,)؀Cf;*) G-V[*ȐL. f3^/ȡ2a  56272hY\ p6ɐYZYٽHyѠpkYZY銱 Wi3[Ȁ iki`Y c\iS>Bc{[\YhZM06\YRa=ڳ mб.K qҞmڛ*L}0m` 65rZZqki\$* ZY: @R>DO]o0_?/a9OaoyYZZYZZ\ZYY [ZZ[ZY5`Y\\Z[\Z5qq]]\ZZ 5s=S[  5`Y1"NP9!   I'$A '&sVF$)   + %+:  Y/в2\.YC61YZYk:Ц(h)YY\x:[YZZZZi$ #5\$Ѐ0 YY`i݈ SkiS>YGIH:S=hط[M0+:6Sڀt)+2’R 2 ںE꜐вOo 4`. ҳMʨG[mDZZ r56\ikq YnZ ZY; @Y>DO]o/]=-_7M_mwmtmmmt@ttrm@@@t mr>?t@?trlrltttK5r>Kr;i5 7>Ktt 5 ?ZK"H%"@    F,)؀Cf;*) G-V[*ȐL. e2]`.Ƞ1`  5i56芈72'gmmt>> p6яttm@?GyР5r K@tmmttvr V?@v1Ȁt> mK> ?@t@w[>K>rr>Bb>tL=tmgrr55:6} >>=>6mmm5`=l lϱ.J pҝlꬨ*#&}fki>` 6iK6>Kl>>! ?l6Kmt?llm? tm9tm @R>DO]o0^>.`8N`nxmmtmtt@tmm t@@@mrlrt?@t?>r5Kttlr 5i=rK>r 5 ttK1"KNP"   1'$!& '&sVFK(t 4*~ TS*i5 X/б22mB561\amttj:Ц'h( >>tmmt@K٦r5x:?Z@xv@?ٺ$ Br"t@vtȀ v@t@? 5>Km>5R>@?Lt>G>rr>Zzmh6>=>>Lh+:655rrlt(+2ґ5m D2. sвOҝ 8Ғ. Mɨ[>ikښDKR6Ki6K6l?O>>lll?tmnt@ ?m: @Y>DO]o/^>.`8N`nxmtmmmt@ttrm@@@t mr>?t@?trlrltttK5r>Kr;i5 7Ktt 5 ?ZK"H%"@    F,)؀Cf;*) G-V[*ȐL. f3^a/ȡ2a  556苈72(hmmt>> p6ɐttm@?HyѠ5r K@tmmttvr W?@v2Ȁt > mK> ?@t@w\>K>rr>Bc>tL=tmhrr55:6~ >>=>6mmm5a=l mб.K qҞmꭨ*&}fki>` 6iK6>Kl>>! ?l6Kmt?llm? tm:tm @R>DO]o0_?/a9Oaoymmtmtt@tmm t@@@mrlrt?@t?>r5Kttlr 5i=rK>r 5 ttK>1"KNP9!   I'$A '&sVF$)   + %+: 5 Y/в2\.mC561mttk:Ц(h) >>tmmt@K٧r5x:?Z@xv@?ٻ$ Br#t@vtȀ v@t@? 5>Km>5S>@?Lt>H>rr>[{mh6>=>>M0+:655rrlt)+2Ғ5m 2 ںE꜐вOo 8`. ҳMʨG[>ikښDKR6Ki6K6l?O>>lll?tmnt@ ?m; F @F>DN\n.\<~,^6L^lv  *9(EBQ`oи  ҈K2APwhw +:IgvhЊЊߊ0 88Ȋ0M@@,ۄAA  %$5` II!AI{IIb"IH""""{". 3@ 'JJKL1@O?h"aYa[HAB@g>aa[{whЄ>׉aqЁHh1>H<{dHa R|Q{cKHBa>B9|Hrۈ|Q|ԧ<>$DN\n.\<~,^6L^lv  *9(O[Bioa@숇f P.sZY ZT"]S\SYU"I>hؽjYTUY{"1и{؝ Y"YTpYUYT'o;>?ii=v YTYYIZz>?>"{ $ YY"I>?><"piM>@YIp >?xp:&|}I?Ȯp-qIsIZ"L4q ؖ{/>.MZ {{։* II}Z&`ҀY""?>Dr """Y6Y 2YY"'p""YpI"YY"Z"Yp" :1 L.=L{NQ`o cbNK1 /&bTcĉb߉& *WHWوMzWԊɊɋ?N1L dsAJJJKLxKJLf֛HLKLKfbJf7F0LfjyLfKfʔf {f19LL0f/bjf/ɴ/Hٕ^{<1/1+؍Br>By@ƈ"Yy@7>YYȀ@JyTYILjƉ@ Zr@Έ>Z?}{TYUJ6UYvD?>%YUv: ii<>??>&>YTYY"z{"B>?BȄY"퉻ip"ZYsBp" >?>BYY";ېp{B>?>ZZ"m|{JAKጉYٕBUZ]0?B6FTr tBY>"Y+ڐYB.=Jz֭:BB".4CBdsJ䏤j*- J"1@O^m|JKLh@Bq|B@ƈ|Ɖ1@m|6‰JtJ:I.v{Ί YY0?NY"YpY芳ŠYY*7F=耋w>ྌ*Ġ>">l|YY>p=΍6|>"tptΈ6 ;>"ڢ{I; K{:<h'ڢ{0l88~rv^svHhJ{@@AA\IrY;KH:m;KK"qYNج+MlkKKIm"l*h:ڢkJ mYluhwy:';LkmllHHiIrL'r{J>=QQ; lmllkllllmHmKrm>hz=;b+55{qHIHJlටr>>dfvlJlmIJqIImlKL>=?vpK{klIpHZmyrϼz>?N pK{lpKHqi+J9rϼ>vuOH<Y^ {lKH{IHr5rr߼==' <<"ppJql5:ڸr߼z( "Ip{lI5pHIl자9Ǽ̟ HH""<HH5HHmIrhiw"ktJlHriip"ui<䈹>9"{iypHi"p9ލKpd9{p9絉ȉ=r;DzH@ "1@>@Bq|B@ƈ|Ɖ1@m|6‰JtJ:I2.xPt.. >֊l:IH:YSn}؆S|YSY>YY@ |""@;BS1@[Y=ˆB} ["YYU>BY"UST>TΈBN"YSTYUTYDʀ<YZZJS|BS[STSΈT"tY [ƺ6"63BRSYr? 23 JJKL(7JhN hKJHh54H<5bh誔٠0JHď>{Hb{H䮏@ "1@>@Bq|B@ƈ|Ɖ1@m|6‰JtJ:I.v{Ί l9HuZȊ׊*7FU‹sB͌V. 6E;t΍w2<8@U@>|86荎l{غHĸЄل&5D>ʏds| .@ '{H1@O YhKKL؀{H{a!H@JK 3?{Jaa"aYa[HAB@g>aa[{whЄ>a aЁHh>a q;.G>  ي a R| K{j a ap  |KKHKߍ @aB9||Qk|ƈŢ<ڜ@Bq|B@ƈ|Ɖ1@JxthJ<Ɗ2.BOFtʃ>:Jl(BЀpppȮ ІpB?ОxJp<p5dQpBلp"p"<5>:N<юY"""B>؉ؔ m"6:>¯⺈"5|>5C|"g!ɪB""pp褌"V:p"F>I͘""蟍tيnqkq">Ɋpp"tȩ܀""5qydsJ 32 L.=L<3`o2KH2ĈNɈK+:2P_^  :L h 2 {JJJKLh"1@KJLh4aKh dh1LhLh͋+:Kh6_h{h  LL1h 02%h `d'`W0{<ƑL 02 0 NؐؐKR pȐ`J2JJȐKȖ ؐKHKdh  HJ⊏̨dhN2 0<2 BLrȹ,J ـH68K jK HBr>B>@ƈط@7>w@Jy>@кr@Ή6ywJ6"~KH%pq"":h<ؙtYquBHB p"p퉻BX> ""u-;Bq"@;qطFJ@yB>Ҷ4#"-P""؄x0?%$>؋rq꧍tBqƹ26ʱ <JzBJaȑtJΌ.4CdsJ䏤*/ J"1@O^m|Ljֈ!0?N]l{ƉՉ />IX( H{/g/@Bq|B@ƈ|Ɖ1@m|6‰JtJ:I.v{Ί 0?Np芳ŠB6ET=耋w>>싹|s>p>||{6tp>6 ;жѶ{I`h@J6$Ѷ !ߪhvѶJa';vѶ.'K`v,Ѷ=вKL͐N(ѶL<L׸;b;ٶ۪PЈvdvBs۴B LJ᜘vѶ+Ӭri"{i׵fi"pi:kO,>i"p9ݡ݉Ve9{p9zȉ=r;DzH@ "1@>@Bq|B@ƈ|Ɖ1@m|6‰JtJ:I2.xPt.. >֊l:IH:n}؆5@ |;BC/>~>Jq@趙B׋@B@,蕌7Fڀ)6E׌ytB6>WΊt6<l{겉Ƒ>a6.=Lfu.,3 3:If fuؙ ȩ{HH3KXHL>sҋKJh54H<5bh誓$<{j>J{f>KJK<vf>hH{5f>hJvK{E ><\b{1 >HHď>{Hb̏ɏԮ }@ R"1@OiRQBpT}q66q胈 STTT65p6@ƈ>TRR@Ym5DTl6=56pmkЃJz 66l6qzRYY@6 T6qkrq5w6rAΉVTRl5kq55kY<T@U> kkmqqqY@Y5<хQUt6kqrkkrkkii555i5i@UFT. STRk56555kr5=к iiii<<5<ȁ<56-.VSRi65Y@/?ik5r<5k5kYrqGp55175ilm6YrY ikqpYrkr qkFPiqk<<<5dS?kp6Yq|tiYkY66&55RT>TU}kk5qkYYn>:Ai65k5k5i?TRTA

krYY8qTQ#twrkpq"6`tBR5c <  KLvL>  JLL  HHJK!v  HJ!KJKBL Z! JcA 4>{"HLLȞѴJJټKKLP>FL>FL]LKnK|؛Єȑ=Y"=]Yz "YKLBz""!>"Lv?c]KY""^>9|ڨ"Y"?"9YtvL!Y"""Y """9Y"HMN""LNYY >L{!?v9Y<BYNFJc"YYY>vBYHvN kLvqt6 ? LLS LLWHڨ KLW8]B|bw騍xT>s[/ NN  !Nv7 G  vL]  Kv ?JLLLvvv  {KLvN>  H{JKB]  {HHHH#JJKLveB J{&LLHB :K{$LLK{ JJ^KLdk:>uٖK>JLK>t]JJ]=Y">=]Y;إz"YB|z""!>"Lv?c]KY""7>9|ڨ"Y"?"9Y@Y"""Y """9Y"H/N""LNYY >L{!?v9Y<BYNFJc"YYY>[vBYHvN kLvqSt6b ? LLⰩ LLW•Hڨ KLW-´]䠈|w7>R5;x:[ͧ/NN vv' LLLLLKr 4KKJNNB  JKJ{{{vvNB \vN' \ KJLv{{HJ ]{LvJJ {JLL, B K>}{} K]J> tKK]JJ|>=Y"]=]YVz"YBz""!>"Lv?c]KY""7>9|ڨ"Y"?"9YfY"""Y """9Y"HN""LNYY >L{!?v9Y<BYNFJc"YYY><vBYWHvN kLvqt6 ?v LLWHڨ KLW-]砈|w7>R;Qv[ͪ/NN v+vL'vLLLG6LKBUNNBt:{HvNBȵ L% JKv{HJK JKLvJK {HLLA ^g ~K>^ JJ J JK]t{>J=Y"}=]Yu z"YB z""!_и"Lv?c~LY""7>9ڨ"Y"?"9YY"""Y """9Y"HN""LNYY >L{!?v9Y<SBYNFJّc"YYY>"vBYW* kLvqڴKI ?,>, LLWHKKL-]砈|wʍ7>R;ƍv[ͪ1 vLK4CNN{BVJBvLJBvLJv<vNNBZDN`J سKLv:>{ 3JLL> KJ{JK` YK>   KLLB {`J> {J{KJK {J {L[Y"U K=]Y И"YB_ z""! "@4 Y""7>9 ڨ"Y"?"9YY"""Y """9Y"HvN""LNYY >L{!?v9Y<Л!YNFJ>c"YYY>vBYђHvN kLvq,K  ?>,\LLWOHK KLW-n %(Ew騍[>;#?[T4 vLKLK4CLLJKB[JKB={KBNN=BNv=B==>طNN=]vvNLv{=KLL]=zKK>ɪOJOJ| LKBJK {{KmJJ TY" Kٯ]Y?{"YB? ""! J{"@  CY""7>9  P"Y"?"9Y8 Y"""Y """9Y"WAN""LNYY >{?N?v9Y<؛{{ H!YNFJJ#!"YYY>BBvBY>HvNٮ kLvqۍK ?>؛ LLWÍHغ KLW-ì;?[6E }@ R"1@OiRQBpq66q胈>65p6@ƈ|i@YmK8i5iii56pmkЃJzi6ilRYY@|qkrq5w6rAΉ6 "i5kq55kY< ""ikkmqqqY@Y5<хٌt""[iiqrkkrkkii555i5i@"Bi555kr5=кi<<5<ȁ<56Bli5Y@/ik5r<5k5kYrqGp5<[> i5pm6YrY ikqpYrkr qkFP<<<,| 5i6kp6Yq|tiYkY66&t[[}k5qkYYn>krYY[q[`ikrkpq"66F[[i"@65p6@ƈ t@tstm@6Eml656pCkЃJz 66l6qz##t@6 6qkrq5w6rAΉt ml5kq55k<t> kkmqqqtk=v5<хGFtl6kqrkkrkkii555i5i@ٕt mk56555kr5=к iiii<<5<ȁ<56.i65@/?ik5r<5k5k@rqGp55nl5ilm6trtikqptrkr@kqkFPiqk<<<఺@#?kp6#q|timkt66qm@l v@5ikk5qk5>mi65k5k5iim>B@A

kqCt8mqm5tt rkpq"6th:t:tc <SSTTRBr>ZZRBQRTTTAQTTQZSRQ>9QZZFSB6EZTSQR;S Qx QQSTZQZTS؈SZJk9ZSAQZLS@:RQATQE= QSUSTQщ>?SQTEEQST͉ȺA4FSZ鐊|@STUٷ/ TSSꖫ;6TTZZZJ{;Dk7;RQGPQR 9ـ1RRTUvu|Vّ:AAy#QQفQ鄫@QRU!1QڌVA?ѴRQEvϋJ¾:uӀSIN>Sض~xϋƍRA{yQ/ZT LRȍʎ;||2x1~ݷB62A>㶏q@ RRQR"1@>SSTTRBr>ZZRBQRTTTAQTTQZSRQ>9QZZFSB6E>ZTSQR;S QxTZQZS؈SZJt8ZSAQZLZT8:RQATQE=2/|Qщ1ZzQZEQST R.s)SZ鐊.v1  TSꖫ?Q/tQنJ&TU1Z 5GQDQR ت3-RhBT,fvu|VّmS77RSURS7mr SSU7S"Sի5k7QQRQVUS7"R  RRQQ QR QS/J:? 6EFtAJ 1DH FG9.=BD7 S>zQ}@<>&5DSˆr>d @H>DN\n.\<~,^6L^lv  -( '9"QFb\;DINVXQE2  SmR3>ITQ QQSR7Syо4tyikQRRRSZSRSQȂb[QRQRRQ2ZZRTRRH6k5,R7Z7RS78ɋ}$QSTSTTpTrTZ7{-ٺ QTRTZQZQx RRQZZSTZTTTQ)1شMqD3SQpSQT?SQSQrI\aф'"?RSmSRєf ٜQkRZRQhZSS7 аNSSQ,ُTm :{\YR-\qLcfUT` ҽeڞ~2Sʙ>Ӎʏ/*)cK+ @P>DN\n.\<~,^6L^lvRRQRRRSSTTRR ZZR RSRQQRQS7 RQRRQQQR &   3 + 8 -$  *)J 1_OWg%}د`'؏G%cQآȮZ -jj~͉5&*6>Eh.Xpm* S 0Q SQQkQSk kS TQ5QmQ kQTkQZ>T4TQT).H7SRQmTTZSZZ QRRROkSZSS(QZZTT(DZ_ZT;ZJSSA|mRyT~SZ<(QQ(*(8RR @J>DN\n.\<~,^6L^lv   & F )# =a8q$rWW3Q#Ryzإ&  QR'jrءpR Q QQZS-yc, QQRRRSZ0ب5 QkQZRRQ24QRصحF)eTQZ6QRZ7QRQ!R؜T9`TTQRRTrTR;pORR,QZRR STZTTSZQSlFЮɟt`jSQpSQT?RRлU8PȆQRl?RS7kk`sm0V]TRQh<RڗʃcڼusSTR77ʳ5ڼdQRr QR¨,)ڨ,DE7g\Rm Ҩ wUژ˱ОЖi< @i>DN\n.\<~,^6L^lvRRQRRRSSTTRRSS7RSRS7mr7QQRQS77RkQQQRQR QS "    %)      !8 F UP$\J< Zm"M$'ؖG="رGح$Ƞ ЪȏЊ~ =]@FXv ؿ~  PELcc t%x *QQ  QQi QQQkQQSQ````5C # RSQSZSSZTTZ[SZ6 QZQ RRRRZZZ*, QZZTTSZZ,ZT7RZSZTS#T"CZRSSSQoQST2ZQFyR7@T_ZzH0QSR=0؂ (*8@ RRQR"1@>SSTTRBr>ZZRBQRTTTAQTTQZSRQ>9QZZFSB6E>ZTSQR;S QxTZQZS؈SPt8ZSAQZL7BZT8:RQATQJ2t/|QؖRt1ZzQZEQS TS7.sFSZTTSQ.l1  TSQB?Q/tQنJrR&T}&R5GQDSmSRFۢت3-7@~AT,fvu|&гZ7yDفRQـ=<T/; 77@@邌m;ٳٴRQѝrS@}BTuHQUmRR|zw~xɚTR逋 3y SUR>/W푍2ȍF;|xBG7둎|AB62ARBrR>@ "1@Ods>QCQ QQQQSQ`TSQQkQ5*9> RSQTRSTRTSSRTQkSz|ZSTZQZ QZSZRR RRSSTZZSTSTZT莈B>TZTTSZSZZQRQATSB6RQu|QTTVƉ1{ZZRS `14;FSZRQRYJٲ}1$8F TSSZ^?Q/t<LTQTUZ *OQ؉ R Rt3-R hBTڦZZfvu |Vّг,~Z7y#ف鄫<5!1@+ ;ٱѝƳ:^uHQSI¢zw~xɚꐋƌ:28 yR6/~6U;>Tx4㑌|ܵ0?j᳏ds΍@ RRQR"1@>SSTTRBr>ZZRBQR7mr7S7RkRSRQQRQS7*9>BQQQl{<DG< ?D Ў BFNR蜈B@=A Tt=4KJ? Zd6}BD{P|غ.\i>w؄L ș&Ȅr4_ A'x H۰'/4.1p}€җp4 Z'3Q rNMkQQSQ5Q RSS'RQ6B-3S95SQUISQRRRTfthZSSZTTZ{SZ QHRRZZ7SDQZZTTFDLBSZTS?T>wZIʎ;|QSTQx.TZTEZFJS|QB2Aٳds>   L @ "1@>Bq>"["""¸ "[["["9["76u"""[| JzQ"=[[z ؈[k|Ɖ S89A?O[> Q[؂9[|LPR>?S""؃?TкAT+s" S"鐊|@Sky ?TLQwن"["؂[Z{;D:; ]Z9Qкv P[ْT"[v؀>Y:AAS9(u2XᡉBٿ@Qx1=ـ듋AktyL¾Rx9ʄʀ >S+ȷѸBXQk.΍vԀt86ku䃎wBȶ㋎{ށ1@>p߻@ "1@>Bq>"["""¸ "[["["9["76u"""[| Jz|=[[z ؈[t|[ Ɖ6x[9A?S[[.e[[؂9[| PRt*>؃?T`s" S"/ )GL с?TL[Eن[؂(LZ|U1[[Ei ]Z[صrкv1ْB[[1? v؀>cYwiz9 O 7RSRS7m7Rk QQRQS7US7"R  RRQQ QR> QS/J:? 6EFtAJ 1DH FG9.=BD7 S>zQ}@<>&5DSˆr>d @H>DN\n.\<~,^6L^lv  -( '9"QFb\;DINVXQE2  mR3>ITQ ""7Syо4tyikQ"[QȂb[ QR"3""RRH6kQQ[6[S78ɋ}$QS/p[q"[[RS-ٺQ+"j [[>[Q)1شMqDR[{""[Ѐ?IrI\aфRQpSRєf ٜQk_h: аNQjSQ,ُTm :{\Y  R-\qLcfUT` ҽeڞ~2Sʙ>Ӎʏ/*)cK+ @P>DN\n.\<~,^6L^lv "["""RSRQQRQS7 RQRRQQQR &   3 + 8 -$  *)J 1_OWg%}د`'؏G%cQآȮZ -jj~͉5&*6>Eh.Xpm* S 0Q SQQkQSk kS TQ5QmQ kE"[N [[[[ ZB[*"""-Ok["["Y(""Q5#"ht*]jEJ "!((8 @J>DN\n.\<~,^6L^lv   & F )# =a8q$rWW3Q#Ryzإ&  R'jrءpR Q ""Ryc,QQ"[ب5 QkQ"3""QRصحF)e"[6[Q!R؜T9`Q/p[q"[[R;pORR,j [[>[[SlFЮɟt`T[{""[Ѐ?IRRлU8PȆQRpkk`sm0V<_h:""RڗʃcڼuQRj77ʳ5ڼdQRr0QR¨,)ڨQRDE7g\Rm Ҩ wUژ˱ОЖi< @P>DN\n.\<~,^6L^lv )"["""QQRQS77RkRSRQQQRQR QS "    %)      !8 F UP$\J< Zm"M$'ؖG="رGح$Ƞ ЪȏЊ~ =]@FXv ؿ~  PELcc t%x *QQ  QQi QQQkQQSQ````5RRQ #R1TQR #R"[[["""[7"[["[" [(""SQ"#"L[[[eT]j"8""J`( "7!((8@ "1@>Bq>"["""¸ "[["["9["76u"""[| Jz|=[[z ؈[St|[ S7B6x[9A?S[SQQ2.<[؂9[| SRtt*>؃? TS7Ⱥ/s"SQ"#")GL сKQB[E|[rR|1[[E2mSRFۢ[[38Ѹ=[7@~A2[1? vSSwiz9 ~TRQـ=Bـʻx"77@@邌m/ptyL\DSrS@}<x҄ʀ"mRR|3z7D逋EBRA."RRB?VGQ.=Nwu䃎wBж[ŴyƎJ؏3Bҍo~׺@ "1@Ods>QCQ QQQQSQ`TSQQkQ5*9H""""[[  l{>=[[" ["||[ "16[9AS[[ƈe[[؂9[" [[P6">؃?Q`'s"@ "6/ )GLAс?[ѩ[Eن[؂(L|U1[[Ei= ]Rt[صrкv1ْB[[1? vP؀>cݸ0wiz9 OBـʻx1Kр!+ӋNlyqtyL\A⣊Ƣ<x҄ʀ녊3ȷѸBXF|!.5tV䀉t8{녍zBBȶҍ>ƼyJ؍3Bҍo~R6@ "1@>Bq>"[""" QR7mr7RSSS7RkRSRQQRQS7*9>BQQQl{<DG< ?D Ў BFNR蜈B@=A Tt=4KJ? Zd6}BD{P|غ.\i>w؄L ș&Ȅr4_ A'x H۰'/4.1p}€җp4 Z'3Q rNMkQQSQ5Q RSS'RQ6B-3"9 RQQSRSQ"ISQRRR"9Rktp"[[["""[ݲ"[["w:[" [D""΍BC?"[[[ˎ ;"w؄""ùJ|ށ"7}3B"яBr   L  @F>DN\n.\<~,^6L^lvYZZYZZ\ZY [\ZYY[\[[YY %YD0PQZ\AZ[[<`kH\zSq\[Sإ Y Q{?4[ȔY +SZZW[КZY1T<Y`4S+;IZYQ@طr7@t`隈QП؀T*11Shi贉hhhحkЉ0XR00^ \]SR؊Q ``ȋ(8@ YZZY"1@>ZZZ\Bq>[\¸\>[[CFƈ7<؁86>vtZ\Z[[Ȉ؂B<J68м[؏ىъ.4sLъRدLЊv|Lـ ։9GEK ȼ N Z ѫBp| 7RSRS7m7Rk QQRQS7US7"R  RRQQ QR> QS/J:? 6EFtAJ 1DH FG9.=BD7 S>zQ}@<>&5DSˆr>d @H>DN\n.\<~,^6L^lv  -( '9"QFb\;DINVXQE2  YZmR3>ITQ YZZZ7Syо4tyikQYYZ\Z[\SQȂb[QRZZYY0Z[Z[RRH6kQQZY6Z\S78ɋ}$QS[\gZY\[;[[RS-ٺQTjZY<TQ)1شMqDRӍʏ/*)cK+ @F>DN\n.\<~,^6L^lvYZZYZZ\ZY [\ZYRSRQQRQS7 RQRRQQQR &   3 + 8 -$  *)J 1_OWg%}د`'؏G%cQآȮZ -jj~͉5&*6>Eh.Xpm* S 0Q SQQkQSk kS TQ5QmQ kQZkQRRZ[>\4\Q^8ZQH7SRQ#\j|[y[ZYOkS[#/QR5![&SQ`]dY_Y(D(8 @J>DN\n.\<~,^6L^lv   & F )# =a8q$rWW3Q#Ryzإ&  YZR'jrءpR Q YZZZRyc,QQYYZ\Z[\ب5 QkQZZYY0Z[Z[QRصحF)eTZY6Z\Q!R؜T9`Q[\gZY\[;[[R;pORRjZY<SlFЮɟt`TDN\n.\<~,^6L^lvYZZYZZ\ZY [\"ZYQQRQS77RkRSRQQQRQR QS "    %)      !8 F UP$\J< Zm"M$'ؖG="رGح$Ƞ ЪȏЊ~ =]@FXv ؿ~  PELcc t%x *QQ  QQi QQQkQQSQ````5RRQ #&ZQZQZSRQ[Z#RZYo\el[|[y[}7+&%ӡ;SQ5J[&SY`]d_(З(8 @F>DN\n.\<~,^6L^lvYZZYZZ\ZY [\ZYY[\[[YY %YD0P`\AZ[[<[ZS~]>zS7S؄q\[SZQQ [{?4 [[STR ZW[8ؚ S7<\[SQ] +;I[\Q@@Ș[[rR ``\mSRuB7zA躈SSTRQd9hhh770jЉйSrS(a000mRR҈[RD؊RSUR ZRRS``Qȋ(8@ "1@Ods>QCQ QQQQSQ`TSQQkQ5*9>RSQTRS[RZSSR[[CkSz YZZ\[[Z[Z[[Z[\Y><C\;<B|\Zl6E\AL菈Ơ>L c, JYc9sGUK >-4ȼ ̉ \ ѫBp {/>Nynj|x0?ʈl{ @ YZZY"1@>ZZZ\Bq>[\ QR7mr7RSSS7RkRSRQQRQS7*9>BQQQl{<DG< ?D Ў BFNR蜈B@=A Tt=4KJ? Zd6}BD{P|غ.\i>w؄L ș&Ȅr4_ A'x H۰'/4.1p}€җp4 Z'3Q rNMkQQSQ5Q RSS'RQ6B-3SRSZ5SQZISQRRR JRktp\1[\[<[?[[ݲ-1JKIMJqp[FЏ:6ȽĎvBJHм0?>l{   L @ SRSR"1@OTTSBq|}>R|SSDƈ\[=ETT\[\[*9H[\]]BTCBy>^]BR}N?AwU|@R{;Dڔ9R:AA;Bٿ@A >Սt̀4C㮉o~}Ǝ/>Mkzט@ SRSR"1@OTTSBq|}>R|SSDƈ\[=ETT\[\[*9H[\]]BTCBy>^]BR}|=BΉlخD=R|٬p |MURҔ𹾈B ڮ; Rp Ɉ  6E(tAJ 1DH FG9.=BD7 S>zQ}@<>&5DSˆr>d @H>DN\n.\<~,^6L^lv  -( '9"QFb\;DINVXRRE2  RTSS3>ITR RSRSTTyо4tyi,SRXZ\ bT+R\[1R556k \[\[[\]]:TRmɋ}$T0\[:^]>Rٺ0\[x=B7{1شMqD0DRX"ɃI\aф0hɔf ٜhR аNh,ُTml {\Y-\qLcfUT` ҽeڞ~2Sʙ>Ӎʏ/*)cK+@ SRSR"1@OTTSBq|}>R|SSDƈ  *9HHJl{>J + S8 G T2>E< t>=/v As{%ء6'|3ؿS%Xwe҈|1f1>RYJ5i҉٣Ђ>>RYN)6qҒ٪*p@ ؁pȳ 8\[=ENB T[\]]BTCRB8>^]BR}N|y鐈|Ǝ/>Mkzט缄 @J>DN\n.\<~,^6L^lv   & F )# =a8q$rWW3RR#Ryzإ&  RTSS'jrءpR R RSRSTTyc,)XZSSب5T+R\[1R4صحF)e \[\[[\]]:TR!R؜T9l0\[:^]>RS,pOR0\[x=BTlFЮɟt0DR8PȆ0h`sm0Vh ڗʃcڼuhʳ5ڼd T\&)ڨ DE7g\R Ҩ wUژ˱ОЖi< @I>DN\n.\<~,^6L^lvSRSRTTSSRS R # R    %)      !8 F UP$\J< Zm"M$'ؖG="رGح$Ƞ ЪȏЊ~ =]@FXv ؿ~  PELc⛘ t%x i TT\[ 0 &/[\]].DRQ&^]* H!&XR"؜뻰\[RȘ\[\[R8@ SRSR"1@OTTSBq|}>R|SSDƈ\[=ETT\[\[*9H[\]]BTCBy>^]BR}|=BΉlخDSR2>Tt|٬pT|MUS@BƉF[TR@~AƉRᄚ;=p?@}p@|t>BŽ8sƎƏ&5DBq@ "1@Ods>C  \[TSSSRSTSTT\[\[*9H[\]]BTCBy>^]BR}|=BRRBB>58<|p |DjU RҔ𹾈B ڮ; R`끈 BFB"BŽ8s )8Gtr.@ SRSR"1@OTTSBq|}>R|SSDƈ  *9HCIM l{<DG= ?D Ў BFNR蜈B@=A Tt=4KJ? Zd6}BD{P|غ.\i>w؄L ș&Ȅr4_ A'x H۰'/41p}€җ2o Z' Nیp5TT\[= TC[\]]B RR}>^]B|=B،΍B탰\[.=BR>y鐈|Ǝ/>Mkz  ;K:DQat8VtFq'Njv~JKJJKLIJJHGKKLIJI IIKLLLLK LLKKK:HG?KI38K IKI<[C K/D*/ L IIH JJcwn KL HvWPjIK   ! ^d     KJLIK  2 HJK @K N < HIK @ N ZH L @ 9L_ NX[ d :] y NN\\\ ፐ G#V\! N  % ,V]]"   ) .V|$]VT S  0X \VT & . 26V. L 1K. 4\^5V Lr e [ 8 , 6V]\ O 38Y S N7J B:SLN67  ; )8:=ettՠAt:߈ȮӠӈ="0?B| к}B2A} xt=~;|}FKٲо|yG5و;6~IJJGоB͊s/: IIJKLKJG Rʫl6u>LNKKJJHIHM6H|KLMLLDCBN׋8.tG<MN?MJLGJHIL>JMN؆JAG軱~cG>JKNA~LJIG К>LM} >BG#|ʩB~?ц| A|IKGG©CG GIGGļJIKKGGjم:|ѢGGGGKKKFBкGGJFL<LGGJAItKIGM|MFHIH tHH|JHN@GI䉌 tJ|KGOJLH tH6|LH@GKN& tHtL|LI@ItN|K@0GL5G4tN|딱LIILHGIGI tK|[@HIKDJIH˙tN|NNJIFH㤉II tNKKNOJH tR|HJK>ЄFt|KI@뀸t|뀪HMJ?t|뀢@JHKMNNt|뀫HIt|뀫@KT?t|ۀT?t|ۀzNNOOt|NNNCt|ÀJJJJtJDJF눑t@IK tˀJ@FHbKIMdtˀM뀾@I؄t|뀾@&I ؄Ӏtۿ@JJGHЄ〙t| ?IG 䱙Kˀt|GKIK GJEt غGINlK GI"MJ?:IMKJ> BۀL>-J B]B Iڔh> J AGк|G  кԨ>FЄI IJL >  BG @ KK.|K J6) GKf >IG66ҐRI=J頉tDK&셉6}JN NYVLLꬊ. KЀK;JB؁zeHE@ ֈ!0?>ԠՈBq|ӠՠԈB>AՈ>AҠԠƉ6E||ӠӈBvt>؀|Iؾ֝Bĉ8>IJJGӠᄉym}>KLKJG脩ՊRnѵ| KLLNKKJJHIي?B>KLMLLDCB>ҊQ~BȺ<MN?MJLGJH$AB֝GJMN؆JAJb]&֝>JKNA~LJI:ZҠAiXBI{} I|B<GB~?ц>)ԝ|IKGsoCG>GGļJIKKGAo:|GGKK KFHIJGҪg62؂|JFL<LGGJAoɋ֝tVT\IGM|MFHIHHI䮹= t֝HH|JHN@GI䩋 AtJ|KGOJLHl FttK|LH@GKNH tL|LI@IIKы?AtN|K@0GLJ~GGGGAtN|딱LIIL HHHGIGIGI肱tK|[@HIKDJIH[tN|NNJIFH㤉III ǩtNKKNOJH tR|HJK>ЄFt|KI@뀸t|JHMJ?t|뀢@JHKMNNt|뀫HIt|뀫@KT?t|ۀT?t|ۀzNNOOt|NNNCt|ÀJJJJtJDJF눑t@IK tˀJ@FHbKIMI@tˀM뀾@I؄t|뀾@&I ؄Ӏtۿ@JJGHЄ〙t| ?IG 䱙Kˀt|GKIK GJEt غGINlK GIMJ?:IMKJ> BۀL>-J B B Iڔh> J AGк|NG  к>FЄI IJL >  BG @ KK.|K J6) GKf >IG66ҐRI=J頉tDK&셉6}JN NYVLLꬊ. KЀK;JB؁ze ~K6   '6!  8 ]l!48l 7pѸ47866289=;hk:=yJ(uਉJ31`اI\7 P4xw ( 7$Я h4٧CW qB؝ي ]  7<ٯ>  '<V  6l8ؾX;d4  lp- 4 l'ٹhdk6l<҃ o4llGf4lzlpd:dl ԡRla @dCHLZy وo JL㐸l <  C e l ٠\Pl ؜p  وl4 l{ 2e> `l * ڬcmz s  ]  H+ 8  .(!a 5v |Ĥ:D آ X̤.  ̤ ⾪ $ ɰ *% кlٰ\w OԒٰw  l㐊8̼8G̊̊8̊xe*  p-P  Nܜ  YΊGTp {ԜjxgHG88 א쿾IH8%ϐZJJ8M X$HIJJΊJJJKHpߌ4JLΊJKJK8  i^4 JJLJ =E S 5HJ#NL޾mH6_GGG XGHgNLL%H 6D G5L 6 LLL݊6P. {HHILLF6ގmֆl  P >GHII6 ގdjuPoPHGIIJIL4擄48aL3PIJ6ྐ4p PD GKLLLbK4plP LL7K ň44Hv 6 p Ƹnp l*ȨS)Ј߹UKF]ԈhE띉ԉtPzوԢK6  ,;J  8cr48 7pҐ478 289=Bhk:=yy (u431`اIh7 PȜ4xw7$Я04٧CM&һ  B؝ъ#$ 7  4Ѯ> 4&' 8 .. V4'%G--9 . 8Xh #$''&%$ }, 8. 8ɩaيh4HI6/p.8'+&4JJl/p r o4'4KLȢ  xN4hKLL6G8 6ѝhLLKHG8 l-. KLlKDIH8lH'hJJ8Ѹ4hKJJJ8 // 5L\ JK87 8:i5L ͙l8 ĐhL lH86h5 l 8hLLM Z¾ 8PMLMLMl 48وINؤ>4H*--됈G68lLM4IJ8 ,a8IH I8lK 4KÖ 8 8NLK 4 6 Zp68L㑢pɈL 8Hӊ,  L 8IJ *)p 8JK***)` 8²6 PӘ488 mP` 8p.>/ 8  /.* P / 8**.68 p/  8H 8 / ҈8  4K 8 / 8 Hp88R8cPЊ8ݫ T8ߛ T898硞6 Hd4Hn86Ċ4c 884솾ٸL4LK8n8؜KޓK8h(  8lGHh(  LT45ΐ T KJ4ގ m8 lȨGHIIh471p 8GIyLh48LMJLK4pPGb*JB4^PMN؜hP L&hpP ٠ Ј ɠۙP ?N  ԉtP꤉ԉԢK6 Ո,;JՠՈ8cr4h4ӈ8ψ47;p҈?4Т ԉm؜k mب88, rp8d dஈpȜ <~ Ӊبһ? u 0ɫ4&'6 8 .. pw4'%l--9 . 87yМ''&%$ Ȣ, 8. 8yةh4HI6/p.8m&4JJl/p rTmڄ4'4KLȢ  ы껠hKLL6G8 67h4KHG8 l-KLlKDIH8lH('hJJ8ѸhKJJ8 // 5L y JK87 8:i5L ʾl8 ĐhL lH86h5 lȢ 8hLLM ¾ 8PMLMLMl 48وINؤ>4H*-- G68lLM4IJ`a8IH I8lK 4KÖ 8 8NLK 4 6 Zp68L㑢.L 8Hӊ,  L 8IJ *)p P 8JK***)Ԩ8²6 P8488 mP` 8p.>/ 8  /.* P / 8*68 p/  8HԨ8 / ҈8JHKp / 8H ..8ފ88R8pP8ݫ7PT8ߛ T898n6 Hd4Hn86Ċ4c884솾ٸL4LK8n8؜KޓK8h(  8lGHh(  LT45ΐ T KJ4ގ m8 lȨGHIIh471p 8GIyLh48LMJLK4pPGb*JB4^PMN؜hP L&hpP ٠ Ј ɠۙP ?N  ԉtP꤉ԉԢU #$    Rapid graphicsd @I.5BVpHzBt4HU  4".S1`(DWV8:{y: Q~e0Wb@ E  x ؟ LЌjLc0بne~_pUx];hyبxȆ,sћЖ?9x;NU+ѻ y IЃ3Lو '@ "1@Ods ĸ~ 膈8G>CzxwІ|Іɷ7ІА2ACGIАtyNy ؋萉΢s|؋X:>ۋ|/j}  R܉yoۼ#ob۲ٮQoڏK/Bڅܨ}bDX 6:5lx*6qɮ'qi欉 ԉ45  Ɖ8m <ơ*)<R؛٣iٮp؊>|L`'؊р\Pψ>z1جQN&tB>CL#&⫉& K&:ɯFѺԋZqٌ;ѮԌ=H ԌԌʔѮ֊ԍ,;Jƺԍgv׍ '@ !0?Ncr A >'6EAvt?w 6z| ʉ|C? :.@mlɮ6=ϊٮmkSU܊5>SҪ$ٮ(@S*{G֚2S{ʑBSʑ땓㱪BȐA  EАᤤ$?ҕqѰmVٵܘ ?8rۛ ص/5g .ɮ  ܎>7>?BiS=ҊNwۼ8ʊұi ɏD'K{RSvNSy;I<딏Bˏ{3 1<v@ #2AP gv|=< 0F4Cps< Xy|*OX't{89YQabа:7Q}B؞Ԋ.*<9L'_ І؃oŠ_  а|وM&´ȺȞ6ʴDKهᙊҿ¯ұŠ|⦊ʊʴl{0ʴc@ڴ´Ҋ65t4Cʴds> '@ "1@Ods ĸ~ 膈y*9HxCl{xw y7 А2ACIАt/ NЋ΢sҊX╋:>ڊۋ|/j} R܉y Vۼ# o҅Kb۲ۭQoⅱۣ/Bڅ$ۨ}ӭCX6:5lx*p6q'ӭص-c 452vہ2m1&4J7d @I.5BVpHzBt4HU %* CO%8 2^0WNftT SdO[=kLekP' FjLؚdZ|p}4dp*2Б F'\> ?rsa x F7xfCMyyWˊډ%j '@ !0?Ncr A > '6EChwt?w6z؆|x?,;.@{r06S=ϊٮm؉A?Ҫ%1(@**'({S{ۊSꊺBȐ땓 뱊{BXȐDАᤓu ? ҕѰmaۓ)8rܛɮ9/.ɮ ܎>7>B.|=Ҋ.ɱۼ8ʊұiU.65LܽB˥Sv>Sy;TIVBY@93u*1; vd @I.5BVpHzBt4HU  % 4".S(p 4WJV8:{:Q '=0YŸ@|"E xП F^LЌj'0ب Ќxٕ&> Ќ/];Ah|.،xЖ,sћЖ?9Zs +  I3 '@ "1@Ods 膈y*9HxC膉l{xwІyІ97Іؐ2ACIt 萉΢sҊҕ:rٮ>rڊ ܉?}Rۉyۼ#Q SP۲ۭQt RL)B }C X˭ ۭ6۸Cĉ$ӭ5l x*ۭ'67'ۭ 'ص|̉ 45&yٺW\$.)?٧ '@ !0?Ncr A > '6EChwt?w6z|y؆|C?І,;.v@{r6=ϊٮm5 ؉AɮxEҪ%ٮ@ڇ*Rɮl D3 S{҇ґ Bٮ BV땓⭱&{BȐa6 АᤊٹE܋ҕӯ97m̋Vٵܓï)8ܛص/u-ɮ  b܎>7> B܎|9,ʊ܎Nۼ7ێڱXU.65LK{˥Svz>Sy;kVBʌ 3v8< rہ;vd @I.5BVpHzBt4HU  4" .S1`(p WJV8: :Q~'=0 @|fGE x ؟q ،jLcm0z  jЌx~ح_p ɳЌ/];A hyȖ_{ũ#9x;sЀN+   I A  '@ "1@Ods ĸ~ 膈y*9HxC膉l{xwІyІ7ІА2ACIАt蹱N萉΢s Ҋ╋:>ڊۋ|/j}Nۉyyۼ#ob۲ۭQ ȚK)Bۨ}bCX6:ڱ5x*p6ɮ'ص- @̉    ̉ 45< ̎s.{? -䉎 zGԏ/ x{ m|<swH #ȏ2~ގ1Ǐy&孏Jx@ "1@O dswB4{<<>G**om l*+)<؛٣iٮp؊>|L`'ɮ؊р\P?z1?N&tB>I#⫉& K鞙&:Gъ|qyLٌ4Ԫӈ ԊٳHԌyԌʔ J  :Iq׍ '@ !0?Ncr   C'6EChwtwEF6z|y؆|6C? ؆,;.JO{r6S=ϊnm؉AҪ *ɮl Xړgdɮ3S{҇ʑBSʑ땓-BȐaDА֜?ڊҕѰ?E˪Vۥ}?)8rܛص/ .ɮ ܎>ۉ??B ܎|M=Ҋ N> 8ʊ ұi U 65L3 ˥SvzI>Sy;I쨏BY@Nˏہ3攎Ï 1<vd @P.5BVpHzBt4HU  4  S1j  W~8 :S~= b@'i G' n؆ FnjL'بЌx ٕ2}pɳPЌ/]FUyx ^ٛЖ?9ZE sW9س ۺ s0թɳ '@ "1@Ods ĸ~ 膈y8Gx l{x  ؆Ȑ2ACАtN ֲs5 Ҋ╋:> Bڊۋ|/? RZІۼ#ob۲ۭQoK/Bۨ}ΠFٹ ̉Q95l> x* 'ص- @ĉ 8Q454Vd#p*2Б F'\> ax,wF7x0LyvWoj '@ !0?Ncr A  > C'6EChw?w6z|y؆|CІ,;x@S{oٮr6=ٮmSU阊Ѯ? Ҫh Ѯ@*Ѯɮ 꿲ʑ   ʑ땓㱊2Ba Dڊؐᤊٹ܋QѰ< ۑF?LR ۛص. g .]܎>7?B-|Cʊ܎N>Šڎұz ш.6L3  R㥏SzI ŽSyIVBY@99ȏ =1v@ #2AP gv|=< 0F4Cps<F R͘|*OQQt*8NAYQa*а:7SQ *а7Bq/*<9L'l%i.аА7ڊ_аȐوM&銴?Ȟ(DKRᙪҿ¯Ѱ´ |⦊Ҵy0ڴ괌t4Cʊds> '@ "1@Ods ĸ~ 膈y膉*9Hx l{xyІ7؆Ȑ2ACIАttN萉΢s5ҊX╋:>r؆؋ۋ|/}R܉yۼ#ob۲ۭ?SK) B  剮6ٹCٚɮlxp yq'ӭص檊ʵɮ7 452vہ2?m1Jxяd @I.5BVpHzBt4HU %* 8%8 FH 0WNft8S YOkHe(} )%T#p <;Q# F'\{ sax;01٩x&yyC\Q%Hj '@ !0?Ncr A > '6EChwt?w6z|y؆|C?І,;.@mlr6ϊٮm?Ҫ%@*ɮlۊ3SґB?Vґ땓B؆a Dؐᤊ?ҕѰmНܓï?{̋SܛF:̋.ɮ ܎>7>?ܻ.|==Ҋ%N>ʊیұiXU.65L3{˥Svz=Sy;I䨏BY@93 1R@ #2AP gv|=<> 0F4Cps<FXy|*OQQt*8NA闰Q*а:7SQ>*а7Bq"*/9L'l%i.аАI _(ȰȐوM&銴Ȑ( G:RᙊB¯Ѱ|⦊l{芴´ⴌ&5Dds⊍ '@ "1@Ods ĸ~ 膈y*9HxC膉l{xwyІІА2ACIАt/N΢s X╋: ڊۋ|/ 1څN yJ#oPۭQoK/˭Bۨ}(bCX)۸C:5lx*p6q'ص- 452[2m1Ǐy&孏Jx7d @I.5BVpHzBt4HU %* CO%8 FH0WNftS O[k  e P' FUjLrv p / 4'V9T#لp<* S# ?F'\{ Y?saٷ w1  &ywW\m譱.%Y '@ !0?Ncr A > '6EChwt?w6z|  ؆|C  І,;.@ O{6ϊٮm 阊?Ҫ%1ٮ@*ٮp(SeٮS҇聚3SBS땓㱊{ X؆a E܋ᤜ? ċ ѰSǪܓ?{S/. "р]W܎> 7>?B.| =Ҋ.NP>]ێiXUو.65:J{˥Sv>SyVB@Nˏہ3 1く;d @I.5BVpHzBt4HU    S1GY(p 4W~=8:{:j~'=0YŸ@ |fGE xЇП FSjLc'0بЌxɕ_ٳЌx];AhxȆ^+?ZEesWࢊ+  ŊIA '@ "1@Ods 膈y*9HxC膉l{xwІyІ97؆А2AIАtN ȋ萉΢sҊ╋:rٮ>Fۋ|?}ۉy ۼ#o҅ҏb۲ۭ?oK/Bۨ}ӭbCΠ٠$˭5lx*p6qɮꃳCKЊ-ۊɮ7р\ԉ413m2ގ1&RJxяd @I.5BVpHzBt4HU %* CO%8 FH0WNftS O[k  e P' FUjLrv p / 4'V9T#لp<* S# ?F'\{ Y?saٷ w1  &ywW\m譱.%Y '@ !0?Ncr A > '6E>Chwt?wz|y؆|C?І,;.5@S{6S=ٮmSU܊?Ҫ%@s*Aɮl3Sʑ "Sʑ땛 ⭪&B rDАᤊٹEXQ7mVٵܓ 8Rܛ ..ɮ ܎>7>?B.|<@=Ҋ܎Nw-B8ʊێұXUQD'K{åSvz>Sy;I䨏BY@9ہ3>Gvd @I.5BVpHzBt4HU % 4".S1`(p 4WJV8:{y  Q~'=0 @@|fGEu Ї, FSjLc'0بЌx_pЌx]FhyxȆ^s٧3+?9x@s+    '@ "1@Ods ĸ~ 膈y*9HxC膉l{xІ؆؆2A+I t/Nʊ΢sҊX╋:>rڊۋ|/j}vNۉyۼ#o҅ҏb۲ۭQ=А ۣ/Bܨ}CАΠ6ԉ:5 <܉ x*'6 q77-  s  45< B L̎s.±'*6{?¹f/,A6ʊ ܰzG/{Pm|zHÍvہ2}m~ K xяd @I.5BVpHzBt4HU %* CO%8 FH0WNftTSdYO[=kHe4 Vdp*2< |/ # ?rs Bx wF7x%yW ?tj '@ !0?Ncr A > '6E Chwt?w 6z |6? ؆,;.JO{06S=ϊyѮ阊(>Ҫ y(@S*ɮ(SɮlSDۊ3S{ȐBzS땓㱊XȐaАᤊFԋdܖ&Ѱm̋Vٵܓ8rkܚ s.ɮxQ>6?R B-|=Ҋ܎Nұ#/-C7ʊڎұ iXU.65L{˥Sv>SyٻI㥏BY@93 1<く;wvd @Y.5BVpHzBt4HU   4" S1`(p 4WJV8:{y:Qj~'=0Y@ | E x 7ПMFSLc'  JҥHc2{I4 پAb/>c H  ܵKz18d @I.5BVpHzBt4HU %*  CO%8  FH WNf TSdYO k e ' AUؠL d  4V-d#V2o# |\># YpaB YٷwF7ᴊyW9.?ڻڏڏ '@ !0?Ncr A > '6EChwtw6|y؆| ?І,;. @{r6=ϊٮm؉A?Ҫ%v*l ɮl{  gdɮ3%S ʑ븸Sʑ땓㱊B a Dڊ [ڋFċ   ܒo̼ Vٵܓï)8苲ܛɮҋ/.ٮ92 ܎>7>?B.|}܎N+ /-C8ێ%iXUR65޾B Ǎv>zOy I  ʌہn1v d @I.5BVpHzBt4HU   % 4  .S`j( 4^IJV8:{y:Q~ec0YŸ@ifGE xЇП FЌjwc';Ќxɕ `pЌx];AU yxȆ^ٛ 3+?9ZE5 sW U  o hI Aѳ '@ "1@Ods ĸ~ 膈y*9HxC膉l{xwІyІ7ІА2ACIАt/N 萉΢sҊ╋:>ڊۋ|/j}ۉy ۼ#o b۲ۭQo R)CBbCXۭí6۸C5C axw1> Z&y0W\[ '@ !0?Ncr A > '6EChwt?w6z|y؆| ?І,;. @{=ϊٮm؉A'E?%@ІUsY1vۊ3%SґB zS5?Vڑ땤x  ɮ&  n DАᤊ ïFٹEҕѰm ŠVٵܓy?{ ܛص/̋.ɮ <a܎>7>?B܎|=܎N[C8ʊێұXUQD!J RSvz>RyٻkVB@9ہ3 ⅏1rہ;v d @I.5BVpHzBt4HU % 4".S1`(p 4 WJV8:{y:~'=0YŸ@|fGE xЇП FSjLc'0بЌxɕ_pЌx];AhyxȆ^ٛ3+ІZEsk+  PhIA '@ "1@Ods ĸ~ 膈y*9HxC膉l{xwІyІ7ІА2APCIАtN 萉γ  ҊX╋:  rҊۋ|/}Rܓnyۼ #oʏ ۲ D K/ ꁉۨ}b CX6 :5lx*pn'7ۍl2vہ2m1Ǐy&孏Jx7d @I.5BVpHzBt4HU %* CO%8 F0WNftTSdYO[=Hy '6E>Chwt?w6z|y؆|C?І,;.@ {r6  ϊٮm S܊ٮҪ%ٮ@*ɮ ɮ SXۊ]ʑB" JޜW KȐꦊ1Dڊ_-ٹEԋ  ѰmVٵܓ 8rܛٮ /.  ԋ܎> >?BM.| =ҊϾ ұ3 ێ 'zɈ.653{9RSv9SyI䨏BY@39{3,v d @K.5BVpHzBt4HU*  ".S`(p 4&JV8{y:QS~a= Y@' `|}fGE x ؆ FLnjwcDm0بЌx(`pU[x]Fhy餹xȆ^Zћ3+?9ZEj s+  0Lɳ '@ "1@Ods ĸ~ 膈y*9HxC膉l{xwІyІ7Іؐ2ACI t 萉΢sҊX╋:>rҊ |/j}R@Zۼ#ob۲ۭQo ۣ/CB ۨ}'X6u5lxí'6q ۭص㭩ԉ45<B̎s.s6{?껱/,A6zG  =4 J{Kzz- ?axwxW U  H  '@ !0?Ncr A > '6EChwt?w6zy؆|C?І,;.{r=ϊٮm؉AEҪ%@l骱ɮlSۊ$1SʑBSޜW&B a D ᤊٹE^QѰmVٵܓ?{苰ܛصs̋.ɮ; ܎>7>FB.|}=Ҋ.Nұ>LʊێzXaو QD' 3SSvz5>åyAVBY@99ȏ 1v d @P.5BVpHzBt4HU  4  S1j  W~8 :S~= b@'i G' n؆ FnjL'بЌx ٕ2}pɳPЌ/]FUyx ^ٛЖ?9ZE sW9س ۺ s0թɳ '@ "1@Ods ĸ~ 膈y*9HxC膉l{xwІ   ؐ2ACؐtN ʊ^֪s5ڊX╋:(>r ۋ|/j}yR܉ټۼoQQo R/B   ۨ}C JӴ6  %5l۱x*('7qٮ'eص-ۍ :45<DB ێs.*}ڠ? *ݻ䉎drzG<<`m{Pm|؄zH2v 2m=y&孏J描d @I.5BVpHzBt4HU  %*  CO%  FH0WN VdY[=kHZ ?s:x,wF7xZaKylj '@ !0?Ncr A   '6EChwt w膉rzy ؆   ?  ,;.@ Aml8/05G ٮ,5S鉊t>轢ҪѮ(:*i?S{҇PRɮl{SDړgcɮ3%S{ȐBሲR㱊B=듸`(̋[ۯ?ԋܒ ٮqo̪Vܓl88Jf.8)ص/5Q9р]<Ҋa܎>7>?ܻ.|==Ҋ܎Nұ#/-Cێ'iX 65L3 ˥Sv5Sy;I쨏BY@393 I1< d @J.5BVpHzBt4HU%  4".Sj(8&JV8:{y:Q~'=0WbҰ@|fGE xЇП jwc'0بЌ {5:'}pѳ، x;Ahyx Іٛ?ZE5 sW  Ū NI  Aو '@ "1@Ods ĸ~ 膈y*9HxC膉l{xw؆yІ7ІА2ACIАtN萉΢syҊX╋:>rFۋ|/jRۉyۼ#ob۲ۭ?oK/ Bۨ}C࠼̉:5l x*p6qC'ص-2܉ە 452vہ2m1Ǐy&孏d @I.5BVpHzBt4HU %* C%8 FH0  NftTSd NOkLe kP'jؠLihZ5|p)/}4Vd*2葠 _F'\>  x F7x xy vمCɺ j '@ !0?N cr A > '6E>Chwt?w6z|y؆|?І,;.@S{6=ϊٮm ؉A? EҪ%v*ɮl{ۊ$ٮ3SʑBA ?Vʑ땓㱺&?Ȑa  EҊؐᤊ?Ҋ 7mVٵۓ?r ܛص/ .. ]ԋ  ܎>7> B.|I=Ҋ܎N -C8ʊێұXa.65L{åSvz5>åyHVBY@Nˏہ3 =1vd @I.5BVpHzBt4HU % 4".S1`(p 4;WJV8:{y:Q~e0YŸ@|fGEE xЇП FЌjLcبЌxɕpЌx];Ah |xȆ^ٛ9ZE;sW+ٻw PhyIA '@ "1@Ods ĸ~ 膈y*9HzxwІ yІ7ІА2ACIАtؐ萉΢sҊX╋:>ro|/j} R܉ۼٮGybۭܲQo ȚK)BܳCҊX6 :5lڊϡx*˭p6q'ۭ ص 45Q ?B̎ss6{?<<ݻ6ʊ ± zHو< J{Pm|zH Z `  _F\># b ?rFsax;wFMx鹊/@Cx?j '@ !0?Ncr A > '6EChwt w膉6 |yʉ|?膊,;.@{r=ϊٮm؉A>Ҫ%vD *ɮl{S֚3% ʑBʑ땓㱊BA EАᤊ?7m НV 8rܛص/ܕɮ2 <܎>7>?B.|?@܎Nұ#/{Šێұi.65Lo{ SvzSy;I{˥BY@99ȏ 1v' < Temperate river graphics by andythenorth (Andrew Parkhouse)<&RRQR $SSTTR($RSZZR(\TT'QTTQZSRQxZSQZZ,S(QR!STwQSOsQZSZȘTSQQZTx&TuQ+PKTTZZ@>SZ􉐐S钉Zv钉FOTȊb%Th(ʢĴ&  RQR"1$RSSTTR(HRSZZR(~QRTTT'QTTQ$QZZTTZTlSlCTZQZKNl4Rk߉JTHn D(SDBZITءhghTI"ᵊF QTvH& RRQR $SSTTR($RSZZR(\T'QTTQZSRQxSQZZ,S(!STwQQZsQZSZȈSQQZTxTZQ+PKTuTZ@>SZ􉐉钉Zv钉SRF=OTȊb|08& RRQR"1$SSTTR(HRSZZR(~QRTTT'QTTQZS$QZZT$$ZTlSQRHlbTZQZj TNZT$ZTฉ*Hp DHo DBJ Zܹhgh针TIHSZlDQTSQl{Rɼó  SQTTSZSTZRR RSSZZRQSSZQ)TQ*RSRZTQ?QR).TZSTSQdeQTPSTvQv2rZSSTS1ED蝘 TZTZSZTZQZTTSTTS QZSZZQZS)SSTTTZT&  QR  SSQTTRRQR%$nRRDS  RRSZZZSSQZZTTTTSQ ZQT(T3T#6ZDQDT4SZQYQTDSmnlSRQQ>T*9p芘 RRQR SSTTRZZRQRTTTQTTQZSRTS QZZSSZT*SQR S ZQZ(TS&(T S97ZzTST8 QRRQZQZ QZTZS TZRQ &8 ZSSSTSSQQRTTTTZ RRRRZZQS RR 8 QRZ RRSTZRRQZZST TT RRZS(*D RRQR SSTTRZRSZZRQTT  QZSZSQZZT  (@A@mm   @A8mRRSQRR,;' STYY`RYQ`QQPYLM8RYRRYSRRRRYR`,Н 8SQYQOQ PY,|``{YYSaQPR-,WZ R`QYYYZYQQQVVZ+aRPY ZYPى[YUL' '6YPP`RKZ PP`QYR`Qu%h`QYQRR% `h`YYYRR`YJPPPRYR%hQ$5D hPPR`RPo(`Q`Px%PYRP((PPQQRYJN`Qq癗`ؔQ`h JHYRhPYaQYoYQQP0ؙQQኮ &  ' A@8m"4$A$Z*_nA8RQQYYZTZ*VTQ'QYRR Q+Ⱦ -(ZRTTRRȀ+ YQQRYTTZU~UZRRQS~0 RZRQZR+VUQz 't$+8FTbp~QQYPQ`PQ`S`YZZZnQYQQR[Y[[n#`RYRRY`Z[[ ~RPQYRYYZY[:PRZRYSZZ[ $QR,QYa\b^~P`YQ`R[#$aGa$~ QPFbo$ ', YZ[cYPp8n$PRQpZF`}SYU\$PYQZ[b[pc[~Yyn R`RRYSYR`QPRY YRRQZRYRQ QY YR Y`QRYPYRl"qa%QA+AqG*ZSGS`(QaT`ec PhZYZZPh`Y[Z`Y`PYQYQRRZZYRRY`QY`RYR`RZRQYRPQ`Q QRPYL`YQ`   YQYRQYQRZ[$#`RYQQ`Y]$P YRY\8Q`RRPRZRc[[Z[R``)QTZZYZZZdAQ`Q?c Q`YPQ `PQQS`QPPRQYQQRZQYY`RYRR`R`YYP YYZYZYSaY% ZTZ[m#r#Y\bI"q#m0`PQ`h`RYPYR`hQRR`pP`YG, P`YYQYYYY``hh PYQYQQ ( Y[\PYYZ\\QQYSRZc[a[$@ "*QQYP``QYSYRYZZ$YZYY Y[cn$rn#m"qsn##r$&`RP YQYR`Q(7 PRPRYRRR`YP_hPLY(YRPpPh`K*R`RPGQ`YQ!v袈PG`PsuRYPȠ(PQ`QaSYQyxp``qZ'PxYPPChw FG`QQYQQ`(i`PQ`<*RQYP>RPp`hP>ZQQiPZRZP`YY(G`YXx&Z/}QQZ`Ɗp[& PP"1@%Y(WJPRRZPnQQQZMH RZ``QSHZQYRYQQSSRRRYRR%QR%KQZRn%PhQYIQo`Yo%PYJRQP`YS%J%o܊Z `QQYYQJ`Q`JJZY݊Q$P`R`&RRR踋 8TTRR-]A8TRS*QtA8TU%O@8% [ Y[[d'6 QSZ[\[\N# YRYRZZZc\cukYRRRNcNn``)aSaTb[\uQaRQSTZ[[NP`RZZSb蜈é`RSaQYTNdSRRyauia`&SRSu`RYu_Ñ";`ԡ8SZQPꉆN8鮉8PYQa'\I?K`RNZoQYaY`HQRPQ & RYZ"1$ZYR`T(X%QRYZZrn PYTYRZ[HQZ[RYTRa$JR`QYYIJ ZRYRYRRnR`R``&``ntnKR%ܙSYS%&TZضJYR钉n`SZYY$6PYQ$&%KaRTQP$ZQZZaQRQQ'JoRQJ&TQRQS&TTRSRSR]AA8&TT݋(8TU8ދP@88x  RYQRRYQ `R`YRYRZR` YRRRQZQQP$ PPQQYZRZPY6HPQ0S`6YPpRQ4HWR`SR`De PQYSYR`QYhK`SYP [\c['P`PTZ[ZZZY`YY`RYRaSZYSaR`RYYRYQPRRaR`Q` RQP)QT``QQ``bS`RpwP}  Q`RRSaRT[\ RYQYPRYSc#$RZPRaZ\, YRRYRRYYZ[=Y QRa#SZc!`YAaZ[$SaSRZ[3s PYRZQYQZSZe4 QYP YQYRQQ PR`RYRYQ`YQQQQRQRZ#`SSaRRRR9Y Z RYS[[YZZY`R*YZ[#$"##k"``YQ@PPhRYQPYRZY PYYRRh`QZi (`/: ``Y`YZZPhPRYRZZZ``RQRYY`RY@ [Y[\`S[[dQYRYZ[\RYRRRZ[cQYZc^($P QYP YQYR`RYPRPRYRZZZ$PYYYYTZ[ "p ZT[c::p"s##n#E 'Q$+8FTbp~T"YY[UU\UZppYSZTU[TGpYZTTThYZ+ STiTZ( UZ Y* ZU\TZ iYY5UT FkU[U\G*T8hZZDqS[T[UTG}UU\T[hiZZETiGYR U[[pR VTG7Z &  88@ /$Sm8AHW$RT'P"$ SS[ZUR"8@(D!ZZ[TUTSRm"SU[UTTTTT" ST[TUZ"؅SSdTUD+ZZ[UTZCMTTTZU"n( 'N$&-9EQ]iu[[\]TZUV[W]]][U[V\]]T[V\TZ ^ZUU[0 U$ <UHZTH]ZTUG]T`T^SG[T1 l[`mTU]\\\ZZ[ ( m8A@"1 [ZS[U"m8@AL[ TZTUTUU[SR*A*UHUU[U[\UZZZ*ZTU'ZZSSi \UZI"&kdi[ #"$STf T[T[h H4( U\T茈 `Ijyز pSUTUUZ qT[U[UU[T Y[UUUU[,YT'TATZZZZ6\VT)[T'FKVZTZMc ]^]]]] YZV]\\Z TV\V\UTZTS[U[UZTTSUZL;[UZSSUU\VUU[T[[[ST[UZVTU[V][UUTU[U($$#~M[UV[mdTZ[U[V8c T [TZ[UU\UZUUUTUZU[[T \\[U\ZT\\$~m#"ZZ$"nnRppRZ( YZT[RZUT[GYS, [ZZ[[[]ZTTU\\\ZZ[0[[]ST\UV][U\]]Z]$D T lYY[UV\Z p[[\[U[[" qsnnn~nsms$ &STS $YTSS(6YZSTT'\'YZSZ' YTSSZN ZZTZ]'N'RtNvQRTS蠈vv QYSZvv`ĉoZ_Qvbو'S鲉؉;YTOYST]ÉYTڊNT%Rv#SST&SS('Yu:ZT袋N蚈'FbqQ8AAA(]sAOsA8ы$%  Q />PYFUQYSTTl{ hRYYTSTUZYQSTSSUTUSS PRRSTTTSTYRYh#TZFTSh[R"i`RFYSS$h^ RYTZTSZ豈ҨiFH[UYRIɁQYS^ShgTSHRRYU>_]&UᆉǒSYaꊰ' %R RRT\&5SRTUcUULY SSUZ[VsMST[UVssSTMVSSSTT\TsSV\s&T[U2>LT]MfLYMUT[V饉YTUUỶSSU[]VYT[Ts馉̊L3̊p3ZeScTT迊?sⱊVUꌊVZUs$\馋J%TUUTsAAApKSsAmA8X &G(-6BQcu)8CKSSZSTTTSSTTUTSTTSZU SUT[[TSUT[U[U[onT[T[9[] oR%CZU\]~$USTTU8\\#~ToZUG s TYTTSG6\o~ SSkE[\]#o6ZUZ]~STn [V\:~TDTU[liUUUZoSgZZ [UU\ :S2]~#ZQ>:T|o~Zn$  ZTT[USSS FYTTUSTT"STTT RTU[UTUUZ4YRYUSSTUPSSTZARYTYT!aWTST[S[RoS<S} []QRT\\[TYSYYSTTTTZTSTTTUU[ T[TSTRRTU "RUZ$5+V30ZScR/ vSY}  TTTTT[TSUTUTS[TTUTS UUUTU\\SUZ,[~TYTUTZUTTV[V~^Y[N[\mUSTU\}YZTZ]]] SS STTTS TSTUSZST'ZU[UTU TT TTYS[7TZU CUTU2[UZ [[ TZTTV[\##$HYSST@ PR YTTYRSTUZSSUTSi`RTF(: ZYZU[\TYTS[U\]RTZUT[VST[UZ@[\TT]SSZUU[\]SU["\\:0[P SS YTTTS STT YTUT[/ T[[[ r< G#rn}s <&SQQQ QZQ(5RRRQTTQTOP^(*xQNZx(`ȈPy'Lj(PQRR[QQY( QQRZ[S+@P(SSZhxvwE`RRȈ'ވ'S?SQ0@XYRYc|Ĵ&  PY"1 RYSYPJJ$RZYYTQQQrHIYRYZ$$ RZRZZH$SZSRl$YSHGS#RF$T#jYRRQ؈!SZ$RRSQQ RRlTSR萉.!RYZSQP赉vڅYP& S  SS]TS)8 TTVTR(( UUTSR(z( U]UTRzxTPTUQTUUȈ]USɈNLU'>tRS@S=TR>UVQ.zURSyW0USRS{XS$& RRYS"1$ZTSSZJHSTUUTSSrQRSZSSRRSUVZlZVH#"SUUmEHSRRhVSRnQSqhT#R$$VUjRڑUVRR lhSUSgSSTTSEhZTU!VRRz蒊ꯈي  `RZRYQRRRR YYRY[RYRZSYZYQZQSSRZTY?<QYTYSRYYQOQYZ9SSYPawSZYTZ$RYF`Y3ZY蝘 c]`[[d\PYZ[[\[ZZZYYYYQYSZS[ZSZZRSTZZTYSY RZYRRZRSZ#YYY"' lRYYTZRR|RY   YRYRYRZZS[ SSZSZSZ[[\#&RRYYZZ[\$~ YYYTZSRZT[\s$"ZRZR6Y6YSYTZ[\mnR\ad*'`]*ud\ RZRY YYTZSQSZTYSY$ ZSYSYRSZRSZ[S2$Z;TZZRZYT[[Z[TRYRR #]##r"mGPYR[$~zi`8 hPY`PYZR hPR Q`YSYiY`R p8 YYZ[[ `YYSYTZZ[ZQYSZSYRYY 8 Z[]RYZZ\dRYYTYS\\SZ[ Z\#(oD RYYSYYTZSZRZTZZ[YYYYY (QQYPQ   `PQ`S`QPPR,;YYPZQYY`RYQ`QQPYsRYRRYSRRRRYR`,.SQYQOQQRR PY,|``{YYSaQPR-, R`QYYYZYQQ І+aRPY ZYPى[YUL' '6`PQQKZ% h``QYYPYRuPh$QRROJ`YYYRR`YJPPPRYR%hP`RQ$P`QYR`< hPPR`RPoPo`Q`Px%%PR(PsRYJN`Qqr`ؔQ`h JHYRh'PYaQYo+YQQPؙQQኮ &   QQ*$ QQRZZ*U$ QQYYZTZS~MQYQYRR +*{(ZRTTRRȀӰUQRYTTZU~UZRRQS& RZRQZR+L[`UQp 't$+8FTbp~QQYPQ`PQ`S`YZZZnQYQQR[Y[[n#`RYRRY`Z[[ ~RPQYRYYZY[:PRZRYSZZ[ $QR,QYa\b^~P`YQ`R[#$aGa$~ QPFbo$ ', YZ[cYPp8n$PRQpZF`}SYU\$PYQZ[b[pc[~Yyn R`RRYSYR`QPRY YRRQZRYRQ QY YR Y`QRYPYRl"qa%QA+AqG*ZSGS`(QaT`ec PhZYZZPh`Y[Z`Y`PYQYQRRZZYRRY`QY`RYR`RZRQYRPQ`Q QRPYL`YQ`   YQYRQYQRZ[$#`RYQQ`Y]$P YRY\8Q`RRPRZRc[[Z[R``)QTZZYZZZdAQ`Q?c Q`YPQ `PQQS`QPPRQYQQRZQYY`RYRR`R`YYP YYZYZYSaY% ZTZ[m#r#Y\bI"q#m0`PQ`h`RYPYR`hQRR`pP`YG, P`YYQYYYY``hh PYQYQQ ( Y[\PYYZ\\QQYSRZc[a[$@ "*QQYP``QYSYRYZZ$YZYY Y[cn$rn#m"qsn##r$&`RP YQYR`Q(7 PRPRYRRR`YP_hPLY(YRPpPh`K*R`RPGQ`YQ!v袈PG`PsuRYPȠ(PQ`QaSYQyxp``qZ'PxYPPChw FG`QQYQQ`(i`PQ`<*RQYP>RPp`hP>ZQQiPZRZP`YY(G`YXx&Z/}QQZ`Ɗp[& PP"1@%Y(WJPRRZPnQQQZMH RZ``QSHZQYRYQQSSRRRYRR%QR%KQZRn%PhQYIQo`Yo%PYJRQP`YS%J%o܊Z `QQYYQJ`Q`JJZY݊Q$P`R`&K#'ZP`q-]nꒊPP(`(% [ Y[[d'6 QSZ[\[\N# YRYRZZZc\cukYRRRNcNn``)aSaTb[\uQaRQSTZ[[NP`RZZSb蜈é`RSaQYTNdSRRyauia`&SRSu`RYu_Ñ";`ԡ8SZQPꉆN8鮉8PYQa'\I?K`RNZoQYaY`HQRPQ & RYZ"1$ZYR`T(X%QRYZZrn PYTYRZ[HQZ[RYTRa$JR`QYYIJ ZRYRYRRnR`R``&``ntnKR%ܙSYS%&TZضJYR钉n`SZYY$6PYQ$&%KaRTQP$RQZZaQZYQ'JJZT)aZR'RRTYSZRYZ(ڋL  RYQRRYQ `R`YRYRZR` YRRRQZQQP$ PPQQYZRZPY6HPQ0S`6YPpRQ4HWR`SR`De PQYSYR`QYhK`SYP [\c['P`PTZ[ZZZY`YY`RYRaSZYSaR`RYYRYQPRRaR`Q` RQP)QT``QQ``bS`RpwP}  Q`RRSaRT[\ RYQYPRYSc#$RZPRaZ\, YRRYRRYYZ[=Y QRa#SZc!`YAaZ[$SaSRZ[3s PYRZQYQZSZe4 QYP YQYRQQ PR`RYRYQ`YQQQQRQRZ#`SSaRRRR9Y Z RYS[[YZZY`R*YZ[#$"##k"``YQ@PPhRYQPYRZY PYYRRh`QZi (`/: ``Y`YZZPhPRYRZZZ``RQRYY`RY@ [Y[\`S[[dQYRYZ[\RYRRRZ[cQYZc^($P QYP YQYR`RYPRPRYRZZZ$PYYYYTZ[ "p ZT[c::p"s##n#E 'Q$+8FTbp~T"YY[UU\UZppYSZTU[TGpYZTTThYZ+ STiTZ( UZ Y* ZU\TZ iYY5UT FkU[U\G*T8hZZDqS[T[UTG}UU\T[hiZZETiGYR U[[pR VTG7Z &   /"HW SUZTTp"CE#[ZUU\T(D! ZZ[TU"K" SU[U!" ST[TU[ب؅SdTUD+ SSZZ[UTZCMTTTZU"n( 'N$&-9EQ]iu[[\]TZUV[W]]][U[V\]]T[V\TZ ^ZUU[0 U$ <UHZTH]ZTUG]T`T^SG[T1 l[`mTU]\\\ZZ[  (A*>XvT[ZS[UTTZTUTUU[U[U[[[U"U\UZZZ ZT8UZZSSJ \UZ:~XQV[TSTT[Z^ U\Tr'Cl pSUTUUZ qT[U[UU[T Y[UUUU[,YT'TATZZZZ6\VT)[T'FKVZTZMc ]^]]]] YZV]\\Z TV\V\UTZTS[U[UZTTSUZL;[UZSSUU\VUU[T[[[ST[UZVTU[V][UUTU[U($$#~M[UV[mdTZ[U[V8c T [TZ[UU\UZUUUTUZU[[T \\[U\ZT\\$~m#"ZZ$"nnRppRZ( YZT[RZUT[GYS, [ZZ[[[]ZTTU\\\ZZ[0[[]ST\UV][U\]]Z]$D T lYY[UV\Z p[[\[U[[" qsnnn~nsms$ &STS $YTSS(6YZSTT'\'YZSZ' YTSSZN ZZTZ]'N'RtNvQRTS蠈vv QYSZvv`ĉoZ_Qvbو'S鲉؉;YTOYST]ÉYTڊNT%Rv#SST&SS('Yu:ZT袋NSS:TTTnQZT:Q묋:Yы:%  Q />PYFUQYSTTl{ hRYYTSTUZYQSTSSUTUSS PRRSTTTSTYRYh#TZFTSh[R"i`RFYSS$h^ RYTZTSZ豈ҨiFH[UYRIɁQYS^ShgTSHRRYU>_]&UᆉǒSYaꊰ' %R RRT\&5SRTUcUULY SSUZ[VsMST[UVssSTMVSSSTT\TsSV\s&T[U2>LT]MfLYMUT[V饉YTUUỶSSU[]VYT[Ts馉̊L3̊p3ZeScTT迊?sⱊVU VZU\2%sUڲ][pKVTRRL#& RSS!0$RTTS(V$SUTS(p$ STSUT[Uv$ TUUSRR[Ul T[TTT[Y$$ UT]U]ZY$ TTUV[SH TTUUU[TMTS[\TT V]RRRU[YS萉hZU]VRYذl TVVRVURؠU]U@2SR[TZTZUR'SUTSFn(DSZ鰊v҉  ZTT[USSS FYTTUSTT"STTT RTU[UTUUZ4YRYUSSTUPSSTZARYTYT!aWTST[S[RoS<S} []QRT\\[TYSYYSTTTTZTSTTTUU[ T[TSTRRTU "RUZ$5+V30ZScR/ vSY}  TTTTT[TSUTUTS[TTUTS UUUTU\\SUZ,[~TYTUTZUTTV[V~^Y[N[\mUSTU\}YZTZ]]] SS STTTS TSTUSZST'ZU[UTU TT TTYS[7TZU CUTU2[UZ [[ TZTTV[\##$m"HYSST@ PR YTTYRSTUZSSUTSi`RTF(: ZYZU[\TYTS[U\]RTZUT[VST[UZ@[\TT]SSZUU[\]SU["\\:0[P SS YTTTS" STT" YTUT[/ T[[[ r< G#rn}s!" !"9 Arctic river graphics by andythenorth (Andrew Parkhouse)<& $(5$Ԉ(\$ԡ҈x(,҈(HwxFsSx#u;PI^hLj(@>ҡ҄vߊF0*Ogb%|h芪Ĵ&  Ԉ"1$(W$Ԉ(H$t$ԡHl҈҄ԡKNl4k߉J Hn D(҈hnJژ%軈ISۉhxɔ&  $(5$Ԉ(\$ԡ҈xԡ,҈(!wxsSx#tPHhu'Lj(@>ҡ@҄vߊF0=Ogbߊ0ɰ& Ԉ"1$(W$Ԉ(l$ԡ҈$ԡ$HlԈH҄ԡj N$܉*DHp DHo hJ ܨ%ҡI(H"ᵈlDҊJzИʔó  ҡ҄)Ը*);).TdePv2r^qo蛰 ҡԡ)3&8  &n?  ҡҨ" (3#DD4YDmL\>*9p芘  ԡ ҡ*  ҄&1 97z8 ԡԡ ԡ !8   8 ԡ   (*D  ҡ ԡ֡ԡ  (@A@mm   @A8mԈ,;'Ԡ)YLM8KQ 8'.,W\,W0تԡЈՈVZ45Zى[*L' '6ՠԈKZ%*%%Ո%oLtooEj蓈oJSoNx%MJoՠ癗ВԠ*ML)V+{ؙU &  ' A@8m"4$A$ա*_nA8 *V'-+Ⱦ)8Ȁݐ+U~U~0*+VUz' Ԉ#2 ԠҠԡnNJn#tJr LԡO: ҡ $q輈o#J$MooྉynMމ&ԉ(QՉ(+IxL2cwMQ Ԡ -l"q(A)DqGBS3ec աԡՠաԠ !L"W ԡ$#$6%;աM>de2c Ԡ  Ҡ$&m#r#3II"q#m0ՠԠpԠG, ԠԠ  ( ՠԡԡ$@ *Ԡՠ $ԡ n$rn#m"qsn##r$& ԠՈ(6%)P^&SxpOG*ȨPG$x(҈Ȉxp؟'ȈPP@hwFG](i魹hPpˉiLȐ(hRXxɸv}1ՊƊp[& Ԉ"1@%Ԉ(WJ'Pn$uHnՠ҈HE҈% %)%Kԡމ,%)oىMع%JIԈ%5-K݊sJ&Jފnʹn○ۋ 9[A8'tA8%O@8%  d'6$ҡՠՠNG ԡԠԈu$)NԈNNՠurKvՈNNԡNQNdr*uitu|ƈÉ3a`ԡ8&ꉆ8؞8d'INo"Պ'm & ԡ"1$Ԡ(X%Mrnr$IJnJظ%nԠ&q܉n&跈ܡ%&趉Jn$ԠI$&$&Hoᕊ&'Jo┊JҊ&m깊_AA8&݋(88ދP@88x ԠԠ"($ HBҠ&p 4WԠVe/g! ՠ ա ՠҡ  $&T7b:pw}  Ԡՠ#$ԡա!ո,ҡ!0%աը23bRԡҡe4  Ԡ"!&ԡL9 !R P ԡ#$"##k"a@ ՠ!i (ՠ/: Ԡԡ ՠ  @ ՠ dԡՠԡ($P  Ԡ ԡ$  "p::p"s##n#E'  "$ա)8 ppҡRaGpա()ԡ|҈i{ֲ͐{Έ͉ỉ-xHUG~){{JÉqpĉqiŠ#iGՉLigGbʮ &  88@ /$m8AHW$'P"$ ա"8@(D! m"C!""%"CDC",!Oc͈"n( 'B$&-9EQ]iuՠԊԊ  Ԋ# ա0 0/Ԋ <H/H`"`kGԊwR؄ l_ Ԡա ( m8A@"1 ա"m8@AL# *A*H" աՈ*"I+ա#ipA!#&akqip #"$% Ho؎茈 `IjyUȲ pԡq,,)Aա8;'ҡMc ԡ աԠա ҠҠ-L;U ',$$#LM:md:Q8c   ա &)Ԡ"$Lm#"ա$"nnRppԡ(  ա G, աա0$D  lҠաp$" qsnnnLnsms$ & $҈(6ԡ(O^'ԡҡ'xҡN(Ԉ'NOtNvsҡvvRvv`ĉoԉvለ'8鲉؉;OM'MڊN%Ԋv8u&'L&u:dŊN蚈'F8bq8AAA(ԄsAOsA8ы$%  Ԉ />Ո&TF$lF ՈFJ҈$!ihjFeG،Ո$hҡґ^iFԉIXbѩ;\ȱW;aꊰ' % &5LXLsMssM҈MsMҠs&=&MfLYs3YỶ ՉYMY馉̊L3̊oYef?걊h؋ ҡY2eًJ%?sAAApK҄sAmA8& ҈!0?҈(W$pl#$ՈHl$SonL oI L$ȴ#L*ػsԉNԠoHh&#Di#Ոm: Ԉؑhg贉Dȑ :JnkL#nG"萈HJԉDҕnԊ  աF"1%4A2!aW[(oW+} Ԡ  +=(5*V38bC v}    3*,@LHLL^Lmmԡ2   ҡ' !(,$ %4>$Ԡ##$H@   iF(: աՠա@ՠ ҡ ":0P    / r< G#rn}s0<& $[[""($[(\""'""[x[,[(!["w[Os[Ș"["x&"u+PK""@>[􉐐[钉v钉FO"Ȋb%Th(ʢĴ&  "1$[[""(H[(~"""'""$"""l[lC"KNl4k߉J"Hn D([DBI"ءhgh"I"ᵊF "vH&  $[[""($[(\"'""[x[,[(!["ws[Ȉ["x"+PK"u"@>[􉐉钉v钉[F=O"Ȋb|08& "1$[[""(H[(~"""'""[$"$$"l[Hlb"j "N"$"ฉ*Hp DHo DBJ ܹhgh针"IH[lD"[l{ɼó  [""[[" [[[[)"*["?)."[de"P["vv2r[["[1ED蝘 ""["""[""[ [[)[[""""&    [[""%$nD[  [[[""""[ "("3"#6DD"4[Y"D[mnl[>"*9p芘  [["""""""["[ [["*[ [ ("[&(" [97z"["8  "[ " &8 [[["[["""" [  8  ["[" "" [(*D  [[""[""  [["  (@A@mm   @A8m[,;'["`YLM8L [`,Н 8[O4,"```{5--,WZ]ZYVZ؀+a ZP`[UL' '6``KZ h`*%J%o%`tooh`o po;h#oo-x%'OMoKJs``癗`ؔ`h JHh'aKV+&rؙ  &  ' A@8m"4$A$*_nA8"*V"&) Ⱦ)(""Ȁݨ+""U~U[~0+VUz ':$+8FTbp~``[`n[[[n#``[[ ~[:[[ $,ab^~``[#$aGa$~ Q8bo$ ',8n$FSU$؋[pOc[~yn `[`  `l"qaA+AqG=S`(a"`ec hh`[`` ```!L"  [$#``$$&6`c[[``OPdAO?c ` `[  ```*[a "#r#0bI"q#m0``h``h`p`G, ```hh  ( [[c[a[$@  *``[$[cn$rn#m"qsn##r$&` `(7 `(^hLO+Pph`K*`(G`vVȰPGLȘ(Qa[xp`'PxPChwFG"`(i`R>Pp`h0i?`(Xx/}0vp[& "1@%(WJPnMH ``[HL[[%)%o,%h݈no`ඈo%݈݉I%J%oJK`܊}J`vJމ$o`&J 9""-]A8"[*tA8"%O@8% [ [[d'6$[[NG ccu$NcN``)a[a"b[ura[x[[N`%b蜈é`[aQ"Nd[yauia`&[[u`M_Ñ";`ԡ8[aꉆN8鮉8a'I"蝊o`H؜ & "1$`"(X%rn "[ ["a$J`Jqn```&`)qܙnK%ܙ[[L%&"ضJ齉$`[&$&$&%Ka"LaIJ'JooJ%[&""[[꿊^AA8&""݋(8"8ދP@88x   ``` $ 6H0[6pREHW`[HeB[gthK`[ [c[`"[`a[[a`a `` )T` ``bS`pw6}  `[a"[ [c#$a,$[a#[c!`"a[/[a[e[e4  ``))`[[a9  [[Q [#$"##k"``@h h`i (`/: ```h```@ [[`[[[d[c^($P  ` $"[ "p#"[c::p"s##n#E 'L$+8FTbp~"[""[pp["["Gp ""h+ ["i"(8 78 iS5" FkdG*"phDT[[""G} "[hi6TiGb؋[p 9"G7 &  88@ /$[m8AHW$"'P"$ [[["8@(D![""[m"[[""""""["[""؅[[d"D)A"CM"""͈Cp( 'B$&-9EQ]iu[["9[W[[9 "[9 #^[ [/ <HTH"#"`k^[G["kx< lbV[ ( m8A@"1 [[["m8@AL[ """[[*A*H[*"'[[%DJ"&["kdKg #"$"H["/[h H4(茈 `Ijyز p[" q"[[[" [,"'A""69")["'FK9 Mc ^ 9 "9""[[[""[L;[U[[9[" ["[[[[" 9$ "[94"[($$#~M.mdQ98c "[" ["[ " [["".$~m#;$"nnRpp( "["[G[, [[[[""[0[[["9[$D "[" l[9 p[[[[[" qsnnn~nsms$ &["[ $"[[(6[""'\'[''"[[N "'N'tNv"[蠈vv[vv`ĉo_vbو'[鲉؉;"O["É"ڊNav$u"&[[('&u:"袋N蚈'Fbq8AAA(sAOsA8ы$%   />&TF[""l{ h"["F ["[["[[ȯ$""["h#"FЯ"[h`FA"F[[$H%ҠiFHIɁ٤[^[ hg;H>_]&ᆉǒ[aꊰ' % "&5[#cLY [[[9sM[")9ss["M9[[["""s[9s&"[ 2 pMfLYM"[9饉Y"Ỷ [9Y"["s9̊KY&̊r3e[c""迊?sⱊ9ꌊ9s$馋J%sAAApK[sAmA8& [[!0?["""[(W """[""pl [vH[H&[[on%ؓ) o$"%~$ [""#~*!G[sN![loHh[$H#l$k"[9: [ةhn贉D :Jk~#nG萈HDҕnԊ  ""[[[[ F""[""[""" "["4[["[["A""!aW"[-[^I\I؀ ["["[[""" ["""[ "["["" &$5+V30/ vf}  """""["[""[[""% "[,[~""<""9[9~^Y3[Mq[B}S [[ ["""[ "["[["'[" "" ""[7" C"[2[ [O$ ""9[##$H:@  ""["[["[i`"F(: [""[[""[9["[[@[""[[[ [":0[P [[ """[ ["" ""( "[[[ r< G#rn}s1<& ԡ(5GP_(*x*ԡx()|ȈPy'Lj(yউ(щ@PEhxvuȈވz?zf0@ɎȊa᷈슄Ĵ&  Ԉ"1%҈(W$ԈPHn!($I$ҡ蓈#҈HG#$ڈFHvj؈lH鎉 Fl@ᐊ"1!FUgw(l&   )8 (('-(z(Ozx'xzQȈ(ɈNL?ԉsu@f?'Q.zٹW0Ҋ{X$& ҈"1$ҡJH(P$Ik#HH#"mEhnDIq$#$Hg&#lgC؎h!Vzs蒊ꯈي  ԡ )/(#ԡ*<%?O*9)eawҡ|_F#% dԡՠա ҡաҡ '%#^4' lK)z]Ȉ   ҡҡҡՠ#"$ՠ$L31ՠs$D66԰Y#*ՠmnZd*'`=?ҡd ԡ Ҹҡ$ҡ2$;Q%ա ###r"mG>$Lzi֠8 ԡ  ԠiԠ p8 ԡ ՠաҡ 8 ԡdҠҡ #(oD  ҡԡՄ" (  ԠҠՈ,8 ԡS0YrK]Z.'.,W\,+ش Չ Z45Zى[.L' '6ԈKZ%'*$OJItJnEjoJSoNx%LJosrВԠ*ML)V+U &   *$ ԡա*U$(ԡ+~)2+SUȀӐUӈ~&*+L[Up'' Ԉ#2 ԠҠԡnNJn#tJr LԡO: ҡ $q輈o#J$MooྉynMމ&ԉ(QՉ(+IxL2cwMQ Ԡ -l"q(A)DqGBS3ec աԡՠաԠ !L"W ԡ$#$6%;աM>de2c Ԡ  Ҡ$&m#r#3II"q#m0ՠԠpԠG, ԠԠ  ( ՠԡԡ$@ *Ԡՠ $ԡ n$rn#m"qsn##r$& ԠՈ(6%)P^&SxpOG*ȨPG$x(҈Ȉxp؟'ȈPP@hwFG](i魹hPpˉiLȐ(hRXxɸv}1ՊƊp[& Ԉ"1@%Ԉ(WJ'Pn$uHnՠ҈HE҈% %)%Kԡމ,%)oىMع%JIԈ%5-K݊sJ&JފnѸ○K# '܋Wfzҹ(%  d'6$ҡՠՠNG ԡԠԈu$)NԈNNՠurKvՈNNԡNQNdr*uitu|ƈÉ3a`ԡ8&ꉆ8؞8d'INo"Պ'm & ԡ"1$Ԡ(X%Mrnr$IJnJظ%nԠ&q܉n&跈ܡ%&趉Jn$ԠI$&$&HoG܊'Jo┊Jԡ#&ظ'Mr(ڋL ԠԠ"($ HBҠ&p 4WԠVe/g! ՠ ա ՠҡ  $&T7b:pw}  Ԡՠ#$ԡա!ո,ҡ!0%աը23bRԡҡe4  Ԡ"!&ԡL9 !R P ԡ#$"##k"a@ ՠ!i (ՠ/: Ԡԡ ՠ  @ ՠ dԡՠԡ($P  Ԡ ԡ$  "p::p"s##n#E'  "$ա)8 ppҡRaGpա()ԡ|҈i{ֲ͐{Έ͉ỉ-xHUG~){{JÉqpĉqiŠ#iGՉLigGbʮ &   /"ՈHW #p"CE ա(D!""K"B">%荘ب؅DCҡҹOc͈̉p( 'B$&-9EQ]iuՠԊԊ  Ԋ# ա0 0/Ԋ <H/H`"`kGԊwR؄ l_ Ԡա ( "1ա(ՈLG!Q(Ո*j" աhII ա#ipA!#$kqi #"$Э% lo؎[IjyyȲ pԡq,,)Aա8;'ҡMc ԡ աԠա ҠҠ-L;U ',$$#LM:md:Q8c   ա &)Ԡ"$Lm#"ա$"nnRppԡ(  ա G, աա0$D  lҠաp$" qsnnnLnsms$ & $҈(6ԡ(O^'ԡҡ'xҡN(Ԉ'NOtNvsҡvvRvv`ĉoԉvለ'8鲉؉;OM'MڊN%Ԋv8u&'L&u:dŊN:'ԡa:؋ы:%  Ԉ />Ո&TF$lF ՈFJ҈$!ihjFeG،Ո$hҡґ^iFԉIXbѩ;\ȱW;aꊰ' % &5LXLsMssM҈MsMҠs&=&MfLYs3YỶ ՉYMY馉̊L3̊oYef?걊h ҡ2e̋VespK?ԋ & ҈!0$҈(V$(p$%(v$ lF$ ԡ$HH$M L萉hبؙ #@2eԈ'nFn("鰊v҉  աF"1%4A2!aW[(oW+} Ԡ  +=(5*V38bC v}    3*,@LHLL^Lmmԡ2   ҡ' !(,$ %4>$Ԡ##$m"H@   iF(: աՠա@ՠ ҡ ":0P  " "/ r< G#rn}s2<&[ (5"""OP^(*x"x(`ȈPy'Lj(P([[A@P[[hxvwE`Ȉ'ވ'z?[O0@XfdĴ&  "1 [JJ$"PHI($ $[ް$[HG[#!܉JFE"#jؐ![$[Eڹl"[萉.!Sgw(& [  [["[)8 ""9"(('"[(z("zx"P"xxȈ[ɈNL'>t[@[=">9Q.zf[yW0.[[{X[$& ["1$"[[JH[""[[r[[[[9l9H#"[mEH[h9[n[qh"#$$9jڑ9 lh[g[[""[Eh"!Vz蒊ꯈي  `[%([:[["?<"[U"HO9[[aw["AsF`3Y蝘 c`[[d[[[[[""[ [#4"' l"|   [[[[[[#&[$~ "["[s$"6Y[*mn\ad*Q`=ed  "[["[$ [[[[[[2$;"$" ###r"mGD$~zi`8 h`  `[i` p8 [[ `["[[[ 8 [d"[[[ #(oD ["["[  (   ``[`,;LS`ZYs[`,.[4,"```{5-,P] V؄؀+a5ZP`[UL' '6`KZ% h``uh$OJI`tJJh`opo;h`oo`/x%'S(sJN`qr`ؔ`h JHh'aKV+ؙ. &   *$ *U$L"S~qt ~*(""ȀӠU""ӈ~[&+L[`Up ':$+8FTbp~``[`n[[[n#``[[ ~[:[[ $,ab^~``[#$aGa$~ Q8bo$ ',8n$FSU$؋[pOc[~yn `[`  `l"qaA+AqG=S`(a"`ec hh`[`` ```!L"  [$#``$$&6`c[[``OPdAO?c ` `[  ```*[a "#r#0bI"q#m0``h``h`p`G, ```hh  ( [[c[a[$@  *``[$[cn$rn#m"qsn##r$&` `(7 `(^hLO+Pph`K*`(G`vVȰPGLȘ(Qa[xp`'PxPChwFG"`(i`R>Pp`h0i?`(Xx/}0vp[& "1@%(WJPnMH ``[HL[[%)%o,%h݈no`ඈo%݈݉I%J%oJK`܊}J`vJމ$o`&K#'I-]'݋~ۍ`(%  '6$NG'""u$N"N``)aa"buraxv`%b蜈é&aQ"yauia`&u`M_Ñ";88aꉆN8酉8+aٮIÊo`H؜ & "1$`"(X%rn "[ ["a$J`Jqn```&`)qܙnK%ܙ[[L%&"ضJ齉$`[&$&$&%Ka"LaI'J&J")aފ'[$陋(ۋL   ``` $ 6H0[6pREHW`[HeB[gthK`[ [c[`"[`a[[a`a `` )T` ``bS`pw6}  `[a"[ [c#$a,$[a#[c!`"a[/[a[e[e4  ``))`[[a9  [[Q [#$"##k"``@h h`i (`/: ```h```@ [[`[[[d[c^($P  ` $"[ "p#"[c::p"s##n#E 'L$+8FTbp~"[""[pp["["Gp ""h+ ["i"(8 78 iS5" FkdG*"phDT[[""G} "[hi6TiGb؋[p 9"G7 &   /"HW [""p"CE#["(D!["$"K" [[C"["["؍بЅd"D)A"CM""""n( 'B$&-9EQ]iu[["9[W[[9 "[9 #^[ [/ <HTH"#"`k^[G["kx< lbV[ ( "[""1 [[["L["""[[[[[vH# HG[[%DJ"$["kdKg #"$"H["/[h l;([OIjyಉ p[" q"[[[" [,"'A""69")["'FK9 Mc ^ 9 "9""[[[""[L;[U[[9[" ["[[[[" 9$ "[94"[($$#~M.mdQ98c "[" ["[ " [["".$~m#;$"nnRpp( "["[G[, [[[[""[0[[["9[$D "[" l[9 p[[[[[" qsnnn~nsms$ &["[ $"[[(6[""'\'[''"[[N "'N'tNv"[蠈vv[vv`ĉo_vbو'[鲉؉;"O["É"ڊNav$u"&[[('&u:"袋N[[:"""n؞":꜋:ы:%   />&TF[""l{ h"["F ["[["[[ȯ$""["h#"FЯ"[h`FA"F[[$H%ҠiFHIɁ٤[^[ hg;H>_]&ᆉǒ[aꊰ' % "&5[#cLY [[[9sM[")9ss["M9[[["""s[9s&"[ 2 pMfLYM"[9饉Y"Ỷ [9Y"["s9̊KY&̊r3e[c""迊?sⱊ9 92%̋V[pKL#& [[!0$""[(V$["[(p$%[v$"[Pl"["$$ "$ 9[[H$"M"ظ"" 9[[萉h9ذl"9%D"9ؠ@2['[#Fn([鰊v҉  ""[[[[ F""[""[""" "["4[["[["A""!aW"[-[^I\I؀ ["["[[""" ["""[ "["["" &$5+V30/ vf}  """""["[""[[""% "[,[~""<""9[9~^Y3[Mq[B}S [[ ["""[ "["[["'[" "" ""[7" C"[2[ [O$ ""9[##$m"H:@  ""["[["[i`"F(: [""[[""[9["[[@[""[[[ [":0[P [[ """[" [""" ""( "[[[ r< G#rn}s340152364569 Tropic river graphics by andythenorth (Andrew Parkhouse)<&@@m@ $ttvv@($@trr@(\vv'mvvmrt@mxrtmrr,t(m@!tvwmtOsmr覈Șvtmmrvx&vum+PKv@vrr@>tr􉐐t钉rv钉FOvȊb%Th(ʢĴ&  @m@"1$@ttvv@(H@trr@(~m@vvv'mvvm$mrrvvrvltlCvrmrKNl4@k@߉JvHn D(tDBrIvءhghvI"ᵊF mvvH& @@m@ $ttvv@($@trr@(\v'mvvmrt@mxtmrr,t(!tvwmmrsmr覈Ȉtmmrvxvrm+PKvu@vr@>tr􉐉钉rv钉t@F=OvȊb|08& @@m@"1$ttvv@(H@trr@(~m@vvv'mvvmrt$mrrv$$rvltm@Hlbvrmrj vNrv$rv@ฉ*Hp DHo DBJ rܹhgh针vIHtrlDmvtml{@ɼó  tmvvtrtvr@@ @ttrr@mttrm)vm*@t@rvm?m@).vrtTtmdemvPtvvmv2rrttvt1ED蝘 vrvr@trvrmrvvtvvt mrtrrmrt)ttvvvrv&  mAt mvv@@m@%$n@@Dt  @@trrrttmrrvvvvtm rmv(v3v#6rDmDv4trmYmvDtmnlt@mm>v*9p芘 @@m@ ttvv@rr@m@vvvmvvmrt@vt mrrttrv*tm@ t rmr(vt&(v t97rzvtv8 m@@mrmr mrvrt vr@m &8 rtttvttmm@vvvvr @@@@rrmt @@ 8 m@r @@tvr@@mrrtv vv @@rt(*D @@m@ ttvv@r@trr@mvv  mrtrtmrrv  (@A@mm  @A8m@@t,;' tvll=@lm=mmkYLM8@l@@lt@@@@l@=,Н 8tmlmOm kl,|=={lltamk@-,WZ @=mlllrlmm VZ+@kl ZlPى[lUL' '6kh=llKZ%=mkkk@l@*J=mlm@@m=ol@@=t=ohk=@m@ l@=< hkk@=@koko=m=kx%kl@krkkmm@lJ=mq瑗ؔm=h JHl@hlmlolmmkr0mU &  ' A@8m"4$A$r*_nA8@mmllrvr*Vvm'ml@@ m+Ⱦ -(r@vv@@Ȁ+ lmm@lvvrU~Ur@@mt~0 @r@mr@+VUmz 't$+8FTbp~mmlkm=km=t=lrrrnmlmm@tlttn#=@l@@l=rtt ~@kml@llrlt:k@r@ltrrt $m@,mltb^~k=lm=@t#$aGa$~ QkFbo$ ',lblkp8n$P@mprF=}tlU$klmrtbtpct~lyn @=@@ltl@=mk@l l@@mr@l@m ml l@ l=m@lkl@l"q%mA+AqG*rtGS=(mv=ec khrlrrkh=ltr=l=klmlm@@rrl@@l=ml=@l@=@r@ml@km=m m@klL=lm=   lml@mlm@rt$#=@lmm=l$k l@lt8m=@@k@r@tttrm@==)mTrrlrrrdAm=m?c m=lkm =kmmt=mkk@mlmm@rmll=@l@@=@=llk llrlrltl% rvrtm#r#ltbI"q#m0=km=h=@lkl@=hm@@=pk=lG, k=llmllll==hh klmlmm ( ltt kllrttmmlt@t$Dmmlk= =mltl@lrr$lrll lttn$rn#m"qsn##&=@k lml@=m(7 k@k@l@@@=lP_hkLl(l@Ppkh=K*@=@PGm=lm!v袈PG=ksu@lkȠ(km=mtlmyxp==qr'PxlkPChw FG=mmlmm=(i=km=<*Rmlk>@Pp=hk>rmmikr@rk=ll(G=lXx&r/}mmr=Ɗp[& kk"1@%l(WJk@@rPnmmmrMH @r==mtHrml@lmmtt@@@l@@%m@%Kmr@n%khmlIQo=lo%klJ@mk=lt%J%o܊Z =mmllQJ=m=JJrl݊m$k=@=&@@@踋 8vv@@-]A8v@t*mtA8vx%O@8% t lttd'6mtrtttN#l@l@rr(ukl@@@Nm==)tvbum@mtTk=@rrtb=@tQlvd8t@@yi=&t@t8=@lu_[tr;鈉ԡ8trmPN8酈+lklmÊRlK=@romll=Hm@km & @lr"1$rl@=v(X%m@lrrrn klvl@rtHmrt@lv@@$J@=mllIJ r@l@l@@n@=@==&==ntnK@%ܙtlt%&vrضJl@钉n=trll$6klm$&%K@vmk$rmrrm@mm'Jo@mJ&vm@mt&vv@t@t@]AA8&vv݋(8vx8ދP@88x  @lm@@lm =@=l@l@r@= l@@@mrmmk$ kkmmlr@rkl6Hkm0t=6lkpRm4HW@=t@=De kmltl@=mlhK=tlk tttt'k=kvrtrrrl=ll=@l@trlt@=@ll@lmk@@@=m= @mk)mT==mm==bS=@pwk}  m=@@t@vtt @lmlk@ltt#$@rk@rt, l@@l@@lll m@#trt!=lA1$tt@" kl@rmlmrtre4 mlk lml@mm k@=@l@lm=lmmmm@m@r#=tt@@@@9l r @ltttlrrl=@*lrt#$"##k"==lm@kkh@lmkl@rl kll@@h=mri (=/: ==l=lrrkhk@l@rrr==@m@ll=@l@ tlt =tttdml@lrtt@l@@@m^($P mlk lml@=@lk@k@l@rrr$kllllvrt "p rvtt::p"s##n#E 'Q$+8FTbp~vtv"lltxxtxrppltrvxtvGplrvvvhlr+ tvivr( xr l*r8r ill5xv FkatG*vp8hrrDqt% tx@vG}xxthirrTiGlR xttp@ xvG7r &  88@ /$tm8AHW$@v'P"$ tttrx@"8@(D!rrtvxvt@m"txtx@vvvvv" tvtvxtxr"؅ttdv@xD+rrtxvrCMvvvrx"n( 'H$&-9EQ]iutttvrxxtątxtx@tv vr@^/@0 .< I@rI"&tvkdpt #"$v@ vtvth H4( xtv@茈 `Ijyز ptxvxxr qvtxtxxtv ltxx@x@xt,lv'v@Avrrrr6)tv'FKrvrMc ^ lrx@@ttr vxtxtxvrvt rvvtx@rL;tUrttxxtx@xtvxvttttvtxr rv'@4x@v@7(@$$#~MHNmdvr[xt@x8c vtv tvrtxxtxrxxxvxrxttv tttxtrvt@t$~m#"rr$"nnRpp@r( lrvt@rxvtGlt, trrtttrvvx@tttrr 0tttvtxxtxtr$D vtv llltxxtr ptt@ttxtt" q@snnn~nsms$ &tvt $lv@tt(6lrtvv'\'lrtr' lvt@trN rrvr'N'@tNvm@vt蠈vv mlt@r@vv`ĉor_mvbو't鲉؉;lvOltvÉlvrNv%@#ttv&tt('lu:rv袋N蚈'Fbqm8AAA(sAOsA8ы$%  m />klFUmltvvl{ h@llvtvxrlmtvttxvxtt k@@tvvvtvl@lh#vrFvth@"i=@tFltt$h^ @lvrvtr豈ҨiFHxl@IɁmlt^thgH@@lx>_]&xᆉǒtlaꊰ' %@ @@vt&5t@vxtxxLYttxrt&sMtv)xss@tvMxttvtvst@xts&@v@tx2>Lv@@MfLYMxvsYvx̉ttx@txY1#Y馉̊L3@@@̊p3res迊?sⱊꌊ@xrxs$J%vxxvsAAApKtsAmA8& tt!0?rtvvvt(W vvxvtvvplrx txĈvHtHx&txt@on%ؓ)ą o@Irxtą~$ xtăvvxnt#~*!rxsNlvvtltoHht$t#lrx$v : رhx"x贉Dtvrtxxt :Jt~#nG萈HtDҕnԊ  rvvtxttt Flvvxtvv"tvvv @vxtxvxxr4l@lxttvxkttvrA@lvlv!aWvt-t@oI\} tąm@vtttvltlltvvvvrvtvvvxx tvtv@@vx "@xr$5+V30rtc@/ vtl}  vvvvvtvtxvxvttvvx% xxxvxtttxr, t~vlvxvrx,tx~^Y3ttmxt @}lrvr]ą tt tvvvt vtvxtrtv'rxtxvx vv vvlt7vrx Cxvtxx2txr tOrvr5 ##$H:@ k@ lvvl@tvxrttxvti=@vF(: rlrxttvlvttxt@vrxv trr@ttvvą rxxtttxtvtt:0tP tt lvvvt tvv lvxv( vttt r< G#rn}s@<&ZZYZ $\\[[Z($Z\'ZZZ(\[['Y[[Y/YxZ\YKS(%\wY\OsYZࣈ[\YYZ[x&[uY+PK9[:h@>\Z􉸠钉%pF[Ȋb%|[܊(ʢĴ&  ZYZ"1$Z\\[[Z(HZ\'ZZZ(~YZ[[['Y[[Y$YZ%ްlC[ZYZK݈ܙ1[߉J[Hnذ#D\DeI[ءh%Y蔉[ѯJk鵊F Y[vH& ZZYZ $\\[[Z($Z\'ZZZ(\['Y[[Y/Yx\YKS(\TYTࣈxYZ[x[ZY+PK9v[:h[\>\Z􉸑@\\钉%pZF=[ȊbP%|08& ZZYZ"1$\\[[Z(HZ\'ZZZ(~YZ[[['Y[[YZ\$YK$$h%Hlb[j [[$Z[ฉ*Hpذ#DorDeI[\ h%YZ[ѯZᵈlDY[\Yl{Ᲊó  \Y[[\Z\[ZZZZ\\Y\\Y)[)\ZZ[)+?6.[Z\T\Yd$[P\[vYsZr\q7 [Z[Z\Z[ZYZ[[\[[\ YZ\ZZYZ\)\\[[[Z[&  !\\\Y^E&XZDHzЈ  ZZ\Z\YZ[[[[\YY[+[3[#6ZD$[4\ YY[D\@mno\Ys[[C*9p芘 ZZYZ \\[[ZZZZYZ[[[Y[[Y[\ Y'\&\D5Y([\&(X\\97z[\[8 YZZ YZ[Z\ [ZZY &8 Z\\\[\\YYZ[[[[ZZZZZY\  8 YZZZZ\[ZZZ\[ [[ \(*D ZZYZ \\[[Z ZZZY[[  YZ\Z\Y  (@A@mm   @A8mZZ\YZZ,;'\[YY`ZYYXYLM8ZL Y\ZZZZYZ`,Н 8\YYYOY4,|``{YYZ-,WZZ]YYVZYS(aZXY ZYU`[%UL' '6Xh`XXKZ `X`ZYYZYZuJYYYZZYJ%ZZ`%XnJhX`YYo: hXXZ`ZXoX`Y`Xx%XYZXrXXLJ`Yq發`ؔY`h JHZh'XYaKVYYYXؙ  &  ' A@8m"4$A$Z*_nA8ZYYYYZ[Z*V[&)ZZ +Ⱦ)Y(ZZ[[Zݨ+ZY(U~UZZZY\~0)ZZ+VUYz' YYYXY#2 `XY`\`YZZZnNJ YZ[Y[[n#tJZFY`Z[[ ~ZXYYZY[: XZZZY\ZZ[ $ZqYYa\b^oJ`YI[#J$ZYXp[[or`ZqYZ[cXnnޑL\\(MqKb[(+I~cO`YMQ Z`ZZY\YZ`YXZYYZYYY`XYZl"qaA1AqG*\ZS`(a[`ec XhZYZZXh`Y [Z`Y`XYYYZY`YY`'`"YZX!XYL"  YYYZZ[$#``Y]$X$&Z\6`ZZXc[[Z[MZ``O+/dAO?YZc Y`YXY `XYY\`YXXZYYYYZ `ZYZZ`Z`Y* \a Z[Z[m#r#0\bI"q#m0`XY`h`ZYXYZ`hYZZ`pX`G, X`YYYY``hh XY ( Y[\XYYZ\\YYY\ZZc[a[$@ *YYYX``YY\YZYZZ$Y Y[cn$rn#m"qsn##r$&`ZX YYYZ`Y(7 XZXZYZZZ`(^hXLO+PpXh`K*Z`(GY`YY!+PPG`wxXȠ(XQa\Zxp`'PxYXPChwFG`eX`(i`RY@鑉p`hXٍiXZZX` 0(GYXx.eɈ`Ɗp[& XX"1@%Y(WJXZZZPnYYYZMH ZZ``Y\HZHYY\\YZ%)%KYZr,%Xh݉Qo`ඈo%X%݉XI%针%᷉݊K`܊}J`YvJlKY%ኹ`L&ZpJ 9[[ZZ-]A8[Z\*YtA8[\%O@8% [ Y[[d'6$\Z[\[\NG YZYZZZZc\cu$#ZNcN``Ka\a[b[\uraZY\T[[NX`ZZy\b蜈é`Z\aQ[Nd\OaZauiau\8`M_ÑL]`ԡ8\YaꉆN89XYYax\I[ZoY`H؜ & ZYZ"1$%`[(X%YZZrn XY[YZZ[YYZ[JY[ZanJZ`YYYJ$n%Z`Z``&`)`nt%ܙ\Y\L%&[趉Jnᒉn`\q$6XYY$&%KaZ[YX$a蓊Y'JoJY\&[[Z\Z\Z]AA8&[[݋(8[\8ދP@88x  ZYYZZYY`Z`YZZ` YX$XXY2ZXY6HX0\`6YXpREYZWZ`\ZHeB\YgtXhK`\_ [\c[ X`X[Z[ZZZY`YY`ZYZa\ZY\aZ`ZYYXZZa ZZ`Y` X YT` YY``bS`ZpwX}  Y`ZZ\aZ[[\ ZYYYXZY\c#$ZZXZaZ\,YZZYZ$Z[a#\Zc!`Ya1[/\a\ZbpXAY4e4 YYX YZYYXZ`ZY`XYZY )`\\aZ9Y ZY\[[<Q Z[#$"##k"``YY@XXhZYYXYZZYXY h`YZi (`/: ``Y`YZZXhXZ ZZ``ZYZYY`Y@ [Y[\ `\[[dYYZYZ[\ZZZ[cc^($P YYX YZ`ZY XZXZYZZZZ$XY[Z[ "p#[[c::p"s##n#E 'N$+8FTbp~[[["YY[\\\\ZppY\Z[\[[GpYZ[&hY+[i[Z(0 Y*ZZ iYY5\[ Fk\dG*F[8hZ8\qQ [[\[G}hiZZETiGb[pZ ][G7Z &  88@ /$\m8AHW$Z['P"$ \\[Z\Z"8@(D!ZH[\[\Zm"\\[\[[[[["\A"؅\\d[)",Z[Z(!O[[[ZJCqبe 'N$&-9EQ]iu[[\][Z\][W]]][\[]\]][[]^\^[Z ^Z\\[^0 [\\$ <\HZ[^H]ZUG][`T^\G[[^1 l[`m[2 ^]\\\ZZ[ ( m8A@"1 [Z\[\"m8@AL[[Z[%)Z*A*\HI[+\\ZZZ*Z[^K^[\^ZZ\>BZI"&[[kdK #"$\[ [[h H[^茈 `Ijyز p\\[\\^Zq^[[[[ Y[\\\\[,Y[^'[A[ZZZZN][)['^K]Z[ZMc ]^]]]] YZ]]\\Z []\ [Z[\[\[\Z[[\\ZL/UZ\\\\\]\[[ \[[[^^[^[\[[\Z][\[]^][\\[\[)^$$#~M\][md[Z[\[]8c [[[ [Z[\\\\Z\\ \Z\^[[[^\Z7.\$~m#"ZZ$"nnRppZZ( YZ[[ZZ\[[GY\, [ZZ[[[] \\\\ZZ[0[[]\[\\]] Z]$D [[[ lYY^[\]\Z p[[\[^\" qsnnn~nsms$ &\[\ $Y[\\(6YZ\[['\'YZ\Z' Y[\\ZN ZZ[Z]'N'\Nv蠈vv\Zv؝`ĉoZ_Yvለ'`鲉؉;Y[OY\[]ÉY[ڊN[%*v#\\[&\\('Yu:Z[袋N蚈'FbqY8AAA(]sAOsA8ы$%  Y />X&TFY\[[l{ hZYY[\[\ZF\[\\\[ XZZ\[[[\[YZYh#[ZF[h[Z"i`ZE\FY\\$h^ZY[Z豈ҨiFH[\YZIɁYY\\ h\HZZ=>_]&醉ǒ\Yɉꊱ' %Z ZZ[\&5\#c\\LY\\)]sM\[[\]ss\[M]\\\[[\[s\]\s&[ 2 [[]Mf'XY ]饉Y[\\Ỷ ]]Y[s馉̊L3̊q3Ze\c ?sY]\ꌊ]Z\s$'J%[sAAApK\sAmA8& \\!0?Z\[[[\(W [[\[\[lII[[^'H\H\^pPon^^] oдIZ\\^]~$^L\#~*mG[^sNYF^\oHh@H[\]#lZ$&^][]\: f^ةh\贉D\\ :JFk]~#n#萈Hk]DҕnԊ  Z[[[\\\\ FY[[\\[["\&Z[\[\\Z4YZY\ \\X\\AZY[Y_caW\[Zo7\} [^]^YZ[^\\[[Y\YY\ [^[[[[\\[ [ZZ^\"Z\Z$5+VJ0Z\cZ> v\Y}  [[[[[[[\\[\[\ \\7\Z,[^~[Y.Z1][]~^YN^Mq>\}YZ[@^]] \\ \[[[\[\ Z\['Z![[^+[Y[#C\\E/Z[Z[[][^\##$HY$@ XZ Y[[YZ\[\Z\\\[\i`Z[F(: ZYZ\[\[Y[ \]Z[Z\[[]\[Z@[\[^]\\Z\\[\]\\[(\:0[P \\ Y[[[\ \[[ Y[\[^ [^&^ r< G#rn}sA<&tmmm mrm(5@@@mvvmvOP^(*xmNrx(=ȈPy'Lj(Pm@@l( mm@rttA@P(ttrhxvwE=@@Ȉ'ވ't?tO0@Xl@lc|Ĵ&  kl"1 @ltlkJJ$@rllvmmmrHIl@lr$$ @r@rrH$trt@l$ltHGt#@F$v#jl@@m؈!tr$@@tmm @@lvt@萉.!@lrSmk赉vڅlk& t  ttvt)8 vvx@@@v@(( @x@xvt@(z( @xxv@zxvPvQvxxȈxt@@ɈNLx'>tPt@t=v@>xُQ.zx@tyW0x@t@t{Xt$& @@lt"1$rvt@trJHtvxxvttrmD @tt@@txxrlrxH#"HmEH@tshx%%mtqhE$$j@ڑxx@@ lhFtgttvvtEhrvx!D"z蒊ꯈي  =@r@lm@@@@ ll@lt@l@rtlrlmrmtt@rvl?<mlvlt@llmOmlr9ttlPawtrlvr$@lF=l3rY蝘 t=ttdtklrttttrrrllllmltr@tvrrvltl @rl@@r@tr#lll"' l@llvr@@|@l   l@l@l@rrttttrtrtt#&@@llrrtt$~ lllvrt@rvtts$"r@r@6l:Ytl*Zn@\d*Q`*u(t @r@l llvrtmtrvltl$ rtltl@tr@trtt2$r;vrr@rlT$v@l@@ ###r"mGkD$~zi=8 hkl=klr@ hk@ m=ltlil=@ p8 llrtt =lltlvrrtrmltrtl@ll 8 rt@lrrtd@llvlttttr rt#(oD @lltllvrtr@rvrrtlllll (mmlkm   =km=t=mkk@,;llkrmll=@lm=mmkYs@l@@lt@@@@l@=,.tmlmOmm@@ kl,|=={lltamk@-, @=mlllrlmm І+@kl ZlPى[lUL' '6=kmmKZ% h==mllkl@ukh$m@@OJ=lll@@=lJkkk@l@%hk=@m$k=ml@=< hkk@=@koko=m=kx%%kR(ks@lJN=mqr=ؔm=h JHl@h'klmlo+lmmkؙmmኮ &   mm*$ mm@rr*U$ mmllrvrS~Mmlml@@ +*{(r@vv@@ȀӰUm@lvvrU~Ur@@mt& @r@mr@+L[=Ump 't$+8FTbp~mmlkm=km=t=lrrrnmlmm@tlttn#=@l@@l=rtt ~@kml@llrlt:k@r@ltrrt $m@,mltb^~k=lm=@t#$aGa$~ QkFbo$ ',lblkp8n$P@mprF=}tlU$klmrtbtpct~lyn @=@@ltl@=mk@l l@@mr@l@m ml l@ l=m@lkl@l"q%mA+AqG*rtGS=(mv=ec khrlrrkh=ltr=l=klmlm@@rrl@@l=ml=@l@=@r@ml@km=m m@klL=lm=   lml@mlm@rt$#=@lmm=l$k l@lt8m=@@k@r@tttrm@==)mTrrlrrrdAm=m?c m=lkm =kmmt=mkk@mlmm@rmll=@l@@=@=llk llrlrltl% rvrtm#r#ltbI"q#m0=km=h=@lkl@=hm@@=pk=lG, k=llmllll==hh klmlmm ( ltt kllrttmmlt@t$Dmmlk= =mltl@lrr$lrll lttn$rn#m"qsn##&=@k lml@=m(7 k@k@l@@@=lP_hkLl(l@Ppkh=K*@=@PGm=lm!v袈PG=ksu@lkȠ(km=mtlmyxp==qr'PxlkPChw FG=mmlmm=(i=km=<*Rmlk>@Pp=hk>rmmikr@rk=ll(G=lXx&r/}mmr=Ɗp[& kk"1@%l(WJk@@rPnmmmrMH @r==mtHrml@lmmtt@@@l@@%m@%Kmr@n%khmlIQo=lo%klJ@mk=lt%J%o܊Z =mmllQJ=m=JJrl݊m$k=@=&K#'rk=q-]nꒊkk(=(% t lttd'6mtrtttN#l@l@rr(ukl@@@Nm==)tvbum@mtTk=@rrtb=@tQlvd8t@@yi=&t@t8=@lu_[tr;鈉ԡ8trmPN8酈+lklmÊRlK=@romll=Hm@km & @lr"1$rl@=v(X%m@lrrrn klvl@rtHmrt@lv@@$J@=mllIJ r@l@l@@n@=@==&==ntnK@%ܙtlt%&vrضJl@钉n=trll$6klm$&%K@vmk$@mrrmrlm'JJrv)r@'@@vltr@lr(ڋL  @lm@@lm =@=l@l@r@= l@@@mrmmk$ kkmmlr@rkl6Hkm0t=6lkpRm4HW@=t@=De kmltl@=mlhK=tlk tttt'k=kvrtrrrl=ll=@l@trlt@=@ll@lmk@@@=m= @mk)mT==mm==bS=@pwk}  m=@@t@vtt @lmlk@ltt#$@rk@rt, l@@l@@lll m@#trt!=lA1$tt@" kl@rmlmrtre4 mlk lml@mm k@=@l@lm=lmmmm@m@r#=tt@@@@9l r @ltttlrrl=@*lrt#$"##k"==lm@kkh@lmkl@rl kll@@h=mri (=/: ==l=lrrkhk@l@rrr==@m@ll=@l@ tlt =tttdml@lrtt@l@@@m^($P mlk lml@=@lk@k@l@rrr$kllllvrt "p rvtt::p"s##n#E 'Q$+8FTbp~vtv"lltxxtxrppltrvxtvGplrvvvhlr+ tvivr( xr l*r8r ill5xv FkatG*vp8hrrDqt% tx@vG}xxthirrTiGlR xttp@ xvG7r &   /"HW txrvvp"CE#trxxtv(D! rrtvx"K"tAx@!"tvtvx؍بЅdv@xD+rtxvrCMvvvrx"n( 'H$&-9EQ]iutttvrxxtątxtx@tv vr@^/@0 .< Xvvtvtrttx@vvrvxvxxtxtx@tttx"xrrr rv8xtxrrtYH@r:~XQmTtv@vtZ^ xtv@r'Cl ptxvxxr qvtxtxxtv ltxx@x@xt,lv'v@Avrrrr6)tv'FKrvrMc ^ lrx@@ttr vxtxtxvrvt rvvtx@rL;tUrttxxtx@xtvxvttttvtxr rv'@4x@v@7(@$$#~MHNmdvr[xt@x8c vtv tvrtxxtxrxxxvxrxttv tttxtrvt@t$~m#"rr$"nnRpp@r( lrvt@rxvtGlt, trrtttrvvx@tttrr 0tttvtxxtxtr$D vtv llltxxtr ptt@ttxtt" q@snnn~nsms$ &tvt $lv@tt(6lrtvv'\'lrtr' lvt@trN rrvr'N'@tNvm@vt蠈vv mlt@r@vv`ĉor_mvbو't鲉؉;lvOltvÉlvrNv%@#ttv&tt('lu:rv袋Ntdrvvv꜋bmrvxu묋:lы:%  m />klFUmltvvl{ h@llvtvxrlmtvttxvxtt k@@tvvvtvl@lh#vrFvth@"i=@tFltt$h^ @lvrvtr豈ҨiFHxl@IɁmlt^thgH@@lx>_]&xᆉǒtlaꊰ' %@ @@vt&5t@vxtxxLYttxrt&sMtv)xss@tvMxttvtvst@xts&@v@tx2>Lv@@MfLYMxvsYvx̉ttx@txY1#Y馉̊L3@@@̊p3res迊?sⱊ걊 xrxt2%sU%@tpKVAL#& @tt!0$@vvt(V$txvt(p$t@vtxv$vxxtPlvtvl$$ xvxrl$vv@otHvvx%vMvиvv x@@@xtlt萉hrxx@lذl!@Dv%ؠGp@2thrvrx@'txnFn(ir鰊v҉  rvvtxttt Flvvxtvv"tvvv @vxtxvxxr4l@lxttvxkttvrA@lvlv!aWvt-t@oI\} tąm@vtttvltlltvvvvrvtvvvxx tvtv@@vx "@xr$5+V30rtc@/ vtl}  vvvvvtvtxvxvttvvx% xxxvxtttxr, t~vlvxvrx,tx~^Y3ttmxt @}lrvr]ą tt tvvvt vtvxtrtv'rxtxvx vv vvlt7vrx Cxvtxx2txr tOrvr5 ##$m"H:@ k@ lvvl@tvxrttxvti=@vF(: rlrxttvlvttxt@vrxv trr@ttvvą rxxtttxtvtt:0tP tt lvvvt" tvv" lvxv( vttt r< G#rn}sB<&\YYY YZY(5ZZZY[[Y[OP^(*xYNV(`ȈPy'Lj(Pulj(Z[\@P(\\ZhxvE`('ވ'z?\Y0@c1XfdĴ&  XY"1 ZY\YXJJ$ZZYY[YYPHIYZY($JM$\Z\H$Y\HG\#ڈ$F$[jY"؈!ֈZZ\GڹDl[鲉/鎊$TYX鋉v(& \  \\][\)8 [[][Z(( \\[\Z(z( \]\[Zzx[P[\Q[\\Ȉ]\ɈNL\'>tZ\@=hZ>(.z\yW0\{ٸ$& ZZY\"1$Z[\\ZJH\[\rYZ\Z\\Zl \\]ZlZ]H#"H\mEH\ZZh]\ZnY'qh$Z$$]kڑ Z lhh\g\[[\EhZ[ؔkWZZz蒊ꯈي  `ZZZYYZY[ZY%(\Y: ZY\\ZZ[Y?<Y[Y\U[ O9\\aw\`asYFr`Y3t c]`[[d\XYZ[[\[ZZZYYY\Z\\ [Y\Y ZZZYY4[' lz7   YZYZYZZZ\^[ \\Z\Z\Z[[\#&ZZY!YZ^[\$~YYY[#"s$"A6Y6Y\L*[\mnjZad*'`]*ud\ ZZZY YY[Z\Y\Z[Y\Y$\Y\Z\2$Z;[OZYX=[[ ^#]##r"mGXYZ[^$~zi`8 hXY`XYZZ hXZ Y`Y\YiY`Z p8 YYZ[[ `YY\Y[ZZ[Z\Z\% 8 Z[] YZZ\dZYY[Y\\\\Z[ Z\#(oD ZYY\YY[Z\ZZZ[ZZ[YYYYY (YYYXY   `XY`\`YXXZ,;YYXZS``ZYsZYZZY\ZZZZYZ`,.\4,|``{YY\-XZ,Z]V؄YS(aZXY ZYU`[%UL' '6`XYYKZ% h``YYYXYZuXh$ZZOJIZZ`tJ`XXXZYJhX`ZKX`YYo: hXXZ`ZXoXo`Y`Xx%OZXR(XsZYJN`Yqr`ؔY`h JHZh'XYaKV+Yؙ. &   YY*$ YYZZZ*U$(YZ[ZS~MPQ +*Y(ZZ[[ZӠUY(U~ZZZY\&)+L[`UYp' YYYXY#2 `XY`\`YZZZnNJ YZ[Y[[n#tJZFY`Z[[ ~ZXYYZY[: XZZZY\ZZ[ $ZqYYa\b^oJ`YI[#J$ZYXp[[or`ZqYZ[cXnnޑL\\(MqKb[(+I~cO`YMQ Z`ZZY\YZ`YXZYYZYYY`XYZl"qaA1AqG*\ZS`(a[`ec XhZYZZXh`Y [Z`Y`XYYYZY`YY`'`"YZX!XYL"  YYYZZ[$#``Y]$X$&Z\6`ZZXc[[Z[MZ``O+/dAO?YZc Y`YXY `XYY\`YXXZYYYYZ `ZYZZ`Z`Y* \a Z[Z[m#r#0\bI"q#m0`XY`h`ZYXYZ`hYZZ`pX`G, X`YYYY``hh XY ( Y[\XYYZ\\YYY\ZZc[a[$@ *YYYX``YY\YZYZZ$Y Y[cn$rn#m"qsn##r$&`ZX YYYZ`Y(7 XZXZYZZZ`(^hXLO+PpXh`K*Z`(GY`YY!+PPG`wxXȠ(XQa\Zxp`'PxYXPChwFG`eX`(i`RY@鑉p`hXٍiXZZX` 0(GYXx.eɈ`Ɗp[& XX"1@%Y(WJXZZZPnYYYZMH ZZ``Y\HZHYY\\YZ%)%KYZr,%Xh݉Qo`ඈo%X%݉XI%针%᷉݊K`܊}J`YvJlKY%ᑸX`L&K#'ZIYZ-]n܊XX`(% [ Y[[d'6$\Z[\[\NG YZYZZZZc\cu$#ZNcN``Ka\a[b[\uraZY\T[[NX`ZZy\b蜈é`Z\aQ[Nd\OaZauiau\8`M_ÑL]`ԡ8\YaꉆN89XYYax\I[ZoY`H؜ & ZYZ"1$%`[(X%YZZrn XY[YZZ[YYZ[JY[ZanJZ`YYYJ$n%Z`Z``&`)`nt%ܙ\Y\L%&[趉Jnᒉn`\q$6XYY$&%KaZ[YX$a蓊Y'J┊JIaZZ,'Y\ZZػwڋL  ZYYZZYY`Z`YZZ` YX$XXY2ZXY6HX0\`6YXpREYZWZ`\ZHeB\YgtXhK`\_ [\c[ X`X[Z[ZZZY`YY`ZYZa\ZY\aZ`ZYYXZZa ZZ`Y` X YT` YY``bS`ZpwX}  Y`ZZ\aZ[[\ ZYYYXZY\c#$ZZXZaZ\,YZZYZ$Z[a#\Zc!`Ya1[/\a\ZbpXAY4e4 YYX YZYYXZ`ZY`XYZY )`\\aZ9Y ZY\[[<Q Z[#$"##k"``YY@XXhZYYXYZZYXY h`YZi (`/: ``Y`YZZXhXZ ZZ``ZYZYY`Y@ [Y[\ `\[[dYYZYZ[\ZZZ[cc^($P YYX YZ`ZY XZXZYZZZZ$XY[Z[ "p#[[c::p"s##n#E 'N$+8FTbp~[[["YY[\\\\ZppY\Z[\[[GpYZ[&hY+[i[Z(0 Y*ZZ iYY5\[ Fk\dG*F[8hZ8\qQ [[\[G}hiZZETiGb[pZ ][G7Z &   /"HW \\Z[[p"CE#[Z\\\[(D!ZD\"K" \\[\!"^Aب؅\d[Z[(ҹO[[[ZJqب 'N$&-9EQ]iu[[\][Z\][W]]][\[]\]][[]^\^[Z ^Z\\[^0 [\\$ <\HZ[^H]ZUG][`T^\G[[^1 l[`m[2 ^]\\\ZZ[ ( [[["1 [Z\[\^[L[[Z[%)[\[T؃\H+ \\ZZZHZ[hp[\^ZZ\>BZI"$[kdKg #"$\[ [h l[^[Ijyಉ p\\[\\^Zq^[[[[ Y[\\\\[,Y[^'[A[ZZZZN][)['^K]Z[ZMc ]^]]]] YZ]]\\Z []\ [Z[\[\[\Z[[\\ZL/UZ\\\\\]\[[ \[[[^^[^[\[[\Z][\[]^][\\[\[)^$$#~M\][md[Z[\[]8c [[[ [Z[\\\\Z\\ \Z\^[[[^\Z7.\$~m#"ZZ$"nnRppZZ( YZ[[ZZ\[[GY\, [ZZ[[[] \\\\ZZ[0[[]\[\\]] Z]$D [[[ lYY^[\]\Z p[[\[^\" qsnnn~nsms$ &\[\ $Y[\\(6YZ\[['\'YZ\Z' Y[\\ZN ZZ[Z]'N'\Nv蠈vv\Zv؝`ĉoZ_Yvለ'`鲉؉;Y[OY\[]ÉY[ڊN[%*v#\\[&\\('Yu:Z[袋N\\:[[[nYZ[:꜋:Yы:%  Y />X&TFY\[[l{ hZYY[\[\ZF\[\\\[ XZZ\[[[\[YZYh#[ZF[h[Z"i`ZE\FY\\$h^ZY[Z豈ҨiFH[\YZIɁYY\\ h\HZZ=>_]&醉ǒ\Yɉꊱ' %Z ZZ[\&5\#c\\LY\\)]sM\[[\]ss\[M]\\\[[\[s\]\s&[ 2 [[]Mf'XY ]饉Y[\\Ỷ ]]Y[s馉̊L3̊q3Ze\c ?sY]\ ]Z\\2%̋Uڲ][pKV[ZZL#& Z\\!0$Z[[\(V$\\[\(p$JOHmt\l[[[Y$$ \[]\]ZY$ [[\][\H[M&%]]ZY\萉hZ$YبI ]\ZءD\]\@2\ٯZ'\\Fn(Z鰊v҉  Z[[[\\\\ FY[[\\[["\&Z[\[\\Z4YZY\ \\X\\AZY[Y_caW\[Zo7\} [^]^YZ[^\\[[Y\YY\ [^[[[[\\[ [ZZ^\"Z\Z$5+VJ0Z\cZ> v\Y}  [[[[[[[\\[\[\ \\7\Z,[^~[Y.Z1][]~^YN^Mq>\}YZ[@^]] \\ \[[[\[\ Z\['Z![[^+[Y[#C\\E/Z[Z[[][^\##$m"HY$@ XZ Y[[YZ\[\Z\\\[\i`Z[F(: ZYZ\[\[Y[ \]Z[Z\[[]\[Z@[\[^]\\Z\\[\]\\[(\:0[P \\ Y[[[\" \[[" Y[\[^ [^&^ r< G#rn}sCD@AEBCFDEF: Toyland river graphics by andythenorth (Andrew Parkhouse)<&RRQR $SSTTR($RSZZR(\TT'QTTQZSRQxZSQZZ,S(QR!STwQSOsQZSZȘTSQQZTx&TuQ+PKTTZZ@>SZ􉐐S钉Zv钉FOTȊb%Th(ʢĴ&  RQR"1$RSSTTR(HRSZZR(~QRTTT'QTTQ$QZZTTZTlSlCTZQZKNl4Rk߉JTHn D(SDBZITءhghTI"ᵊF QTvH& RRQR $SSTTR($RSZZR(\T'QTTQZSRQxSQZZ,S(!STwQQZsQZSZȈSQQZTxTZQ+PKTuTZ@>SZ􉐉钉Zv钉SRF=OTȊb|08& RRQR"1$SSTTR(HRSZZR(~QRTTT'QTTQZS$QZZT$$ZTlSQRHlbTZQZj TNZT$ZTฉ*Hp DHo DBJ Zܹhgh针TIHSZlDQTSQl{Rɼó  SQTTSZSTZRR RSSZZRQSSZQ)TQ*RSRZTQ?QR).TZSTSQdeQTPSTvQv2rZSSTS1ED蝘 TZTZSZTZQZTTSTTS QZSZZQZS)SSTTTZT&  QR  SSQTTRRQR%$nRRDS  RRSZZZSSQZZTTTTSQ ZQT(T3T#6ZDQDT4SZQYQTDSmnlSRQQ>T*9p芘 RRQR SSTTRZZRQRTTTQTTQZSRTS QZZSSZT*SQR S ZQZ(TS&(T S97ZzTST8 QRRQZQZ QZTZS TZRQ &8 ZSSSTSSQQRTTTTZ RRRRZZQS RR 8 QRZ RRSTZRRQZZST TT RRZS(*D RRQR SSTTRZRSZZRQTT  QZSZSQZZT  (@A@mm   @A8mRRSQRR,;' STYY`RYQ`QQPYLM8RYRRYSRRRRYR`,Н 8SQYQOQ PY,|``{YYSaQPR-,WZ R`QYYYZYQQQVVZ+aRPY ZYPى[YUL' '6YPP`RKZ PP`QYR`Qu%h`QYQRR% `h`YYYRR`YJPPPRYR%hQ$5D hPPR`RPo(`Q`Px%PYRP((PPQQRYJN`Qq癗`ؔQ`h JHYRhPYaQYoYQQP0ؙQQኮ &  ' A@8m"4$A$Z*_nA8RQQYYZTZ*VTQ'QYRR Q+Ⱦ -(ZRTTRRȀ+ YQQRYTTZU~UZRRQS~0 RZRQZR+VUQz 't$+8FTbp~QQYPQ`PQ`S`YZZZnQYQQR[Y[[n#`RYRRY`Z[[ ~RPQYRYYZY[:PRZRYSZZ[ $QR,QYa\b^~P`YQ`R[#$aGa$~ QPFbo$ ', YZ[cYPp8n$PRQpZF`}SYU\$PYQZ[b[pc[~Yyn R`RRYSYR`QPRY YRRQZRYRQ QY YR Y`QRYPYRl"qa%QA+AqG*ZSGS`(QaT`ec PhZYZZPh`Y[Z`Y`PYQYQRRZZYRRY`QY`RYR`RZRQYRPQ`Q QRPYL`YQ`   YQYRQYQRZ[$#`RYQQ`Y]$P YRY\8Q`RRPRZRc[[Z[R``)QTZZYZZZdAQ`Q?c Q`YPQ `PQQS`QPPRQYQQRZQYY`RYRR`R`YYP YYZYZYSaY% ZTZ[m#r#Y\bI"q#m0`PQ`h`RYPYR`hQRR`pP`YG, P`YYQYYYY``hh PYQYQQ ( Y[\PYYZ\\QQYSRZc[a[$@ "*QQYP``QYSYRYZZ$YZYY Y[cn$rn#m"qsn##r$&`RP YQYR`Q(7 PRPRYRRR`YP_hPLY(YRPpPh`K*R`RPGQ`YQ!v袈PG`PsuRYPȠ(PQ`QaSYQyxp``qZ'PxYPPChw FG`QQYQQ`(i`PQ`<*RQYP>RPp`hP>ZQQiPZRZP`YY(G`YXx&Z/}QQZ`Ɗp[& PP"1@%Y(WJPRRZPnQQQZMH RZ``QSHZQYRYQQSSRRRYRR%QR%KQZRn%PhQYIQo`Yo%PYJRQP`YS%J%o܊Z `QQYYQJ`Q`JJZY݊Q$P`R`&RRR踋 8TTRR-]A8TRS*QtA8TU%O@8% [ Y[[d'6 QSZ[\[\N# YRYRZZZc\cukYRRRNcNn``)aSaTb[\uQaRQSTZ[[NP`RZZSb蜈é`RSaQYTNdSRRyauia`&SRSu`RYu_Ñ";`ԡ8SZQPꉆN8鮉8PYQa'\I?K`RNZoQYaY`HQRPQ & RYZ"1$ZYR`T(X%QRYZZrn PYTYRZ[HQZ[RYTRa$JR`QYYIJ ZRYRYRRnR`R``&``ntnKR%ܙSYS%&TZضJYR钉n`SZYY$6PYQ$&%KaRTQP$ZQZZaQRQQ'JoRQJ&TQRQS&TTRSRSR]AA8&TT݋(8TU8ދP@88x  RYQRRYQ `R`YRYRZR` YRRRQZQQP$ PPQQYZRZPY6HPQ0S`6YPpRQ4HWR`SR`De PQYSYR`QYhK`SYP [\c['P`PTZ[ZZZY`YY`RYRaSZYSaR`RYYRYQPRRaR`Q` RQP)QT``QQ``bS`RpwP}  Q`RRSaRT[\ RYQYPRYSc#$RZPRaZ\, YRRYRRYYZ[=Y QRa#SZc!`YAaZ[$SaSRZ[3s PYRZQYQZSZe4 QYP YQYRQQ PR`RYRYQ`YQQQQRQRZ#`SSaRRRR9Y Z RYS[[YZZY`R*YZ[#$"##k"``YQ@PPhRYQPYRZY PYYRRh`QZi (`/: ``Y`YZZPhPRYRZZZ``RQRYY`RY@ [Y[\`S[[dQYRYZ[\RYRRRZ[cQYZc^($P QYP YQYR`RYPRPRYRZZZ$PYYYYTZ[ "p ZT[c::p"s##n#E 'Q$+8FTbp~T"YY[UU\UZppYSZTU[TGpYZTTThYZ+ STiTZ( UZ Y* ZU\TZ iYY5UT FkU[U\G*T8hZZDqS[T[UTG}UU\T[hiZZETiGYR U[[pR VTG7Z &  88@ /$Sm8AHW$RT'P"$ SS[ZUR"8@(D!ZZ[TUTSRm"SU[UTTTTT" ST[TUZ"؅SSdTUD+ZZ[UTZCMTTTZU"n( 'N$&-9EQ]iu[[\]TZUV[W]]][U[V\]]T[V\TZ ^ZUU[0 U$ <UHZTH]ZTUG]T`T^SG[T1 l[`mTU]\\\ZZ[ ( m8A@"1 [ZS[U"m8@AL[ TZTUTUU[SR*A*UHUU[U[\UZZZ*ZTU'ZZSSi \UZI"&kdi[ #"$STf T[T[h H4( U\T茈 `Ijyز pSUTUUZ qT[U[UU[T Y[UUUU[,YT'TATZZZZ6\VT)[T'FKVZTZMc ]^]]]] YZV]\\Z TV\V\UTZTS[U[UZTTSUZL;[UZSSUU\VUU[T[[[ST[UZVTU[V][UUTU[U($$#~M[UV[mdTZ[U[V8c T [TZ[UU\UZUUUTUZU[[T \\[U\ZT\\$~m#"ZZ$"nnRppRZ( YZT[RZUT[GYS, [ZZ[[[]ZTTU\\\ZZ[0[[]ST\UV][U\]]Z]$D T lYY[UV\Z p[[\[U[[" qsnnn~nsms$ &STS $YTSS(6YZSTT'\'YZSZ' YTSSZN ZZTZ]'N'RtNvQRTS蠈vv QYSZvv`ĉoZ_Qvbو'S鲉؉;YTOYST]ÉYTڊNT%Rv#SST&SS('Yu:ZT袋N蚈'FbqQ8AAA(]sAOsA8ы$%  Q />PYFUQYSTTl{ hRYYTSTUZYQSTSSUTUSS PRRSTTTSTYRYh#TZFTSh[R"i`RFYSS$h^ RYTZTSZ豈ҨiFH[UYRIɁQYS^ShgTSHRRYU>_]&UᆉǒSYaꊰ' %R RRT\&5SRTUcUULY SSUZ[VsMST[UVssSTMVSSSTT\TsSV\s&T[U2>LT]MfLYMUT[V饉YTUUỶSSU[]VYT[Ts馉̊L3̊p3ZeScTT迊?sⱊVUꌊVZUs$\馋J%TUUTsAAApKSsAmA8X &G(-6BQcu)8CKSSZSTTTSSTTUTSTTSZU SUT[[TSUT[U[U[onT[T[9[] oR%CZU\]~$USTTU8\\#~ToZUG s TYTTSG6\o~ SSkE[\]#o6ZUZ]~STn [V\:~TDTU[liUUUZoSgZZ [UU\ :S2]~#ZQ>:T|o~Zn$  ZTT[USSS FYTTUSTT"STTT RTU[UTUUZ4YRYUSSTUPSSTZARYTYT!aWTST[S[RoS<S} []QRT\\[TYSYYSTTTTZTSTTTUU[ T[TSTRRTU "RUZ$5+V30ZScR/ vSY}  TTTTT[TSUTUTS[TTUTS UUUTU\\SUZ,[~TYTUTZUTTV[V~^Y[N[\mUSTU\}YZTZ]]] SS STTTS TSTUSZST'ZU[UTU TT TTYS[7TZU CUTU2[UZ [[ TZTTV[\##$HYSST@ PR YTTYRSTUZSSUTSi`RTF(: ZYZU[\TYTS[U\]RTZUT[VST[UZ@[\TT]SSZUU[\]SU["\\:0[P SS YTTTS STT YTUT[/ T[[[ r< G#rn}sP<&SQQQ QZQ(5RRRQTTQTOP^(*xQNZx(`ȈPy'Lj(PQRR[QQY( QQRZ[S+@P(SSZhxvwE`RRȈ'ވ'S?SQ0@XYRYc|Ĵ&  PY"1 RYSYPJJ$RZYYTQQQrHIYRYZ$$ RZRZZH$SZSRl$YSHGS#RF$T#jYRRQ؈!SZ$RRSQQ RRlTSR萉.!RYZSQP赉vڅYP& S  SS]TS)8 TTVTR(( UUTSR(z( U]UTRzxTPTUQTUUȈ]USɈNLU'>tRS@S=TR>UVQ.zURSyW0USRS{XS$& RRYS"1$ZTSSZJHSTUUTSSrQRSZSSRRSUVZlZVH#"SUUmEHSRRhVSRnQSqhT#R$$VUjRڑUVRR lhSUSgSSTTSEhZTU!VRRz蒊ꯈي  `RZRYQRRRR YYRY[RYRZSYZYQZQSSRZTY?<QYTYSRYYQOQYZ9SSYPawSZYTZ$RYF`Y3ZY蝘 c]`[[d\PYZ[[\[ZZZYYYYQYSZS[ZSZZRSTZZTYSY RZYRRZRSZ#YYY"' lRYYTZRR|RY   YRYRYRZZS[ SSZSZSZ[[\#&RRYYZZ[\$~ YYYTZSRZT[\s$"ZRZR6Y6YSYTZ[\mnR\ad*'`]*ud\ RZRY YYTZSQSZTYSY$ ZSYSYRSZRSZ[S2$Z;TZZRZYT[[Z[TRYRR #]##r"mGPYR[$~zi`8 hPY`PYZR hPR Q`YSYiY`R p8 YYZ[[ `YYSYTZZ[ZQYSZSYRYY 8 Z[]RYZZ\dRYYTYS\\SZ[ Z\#(oD RYYSYYTZSZRZTZZ[YYYYY (QQYPQ   `PQ`S`QPPR,;YYPZQYY`RYQ`QQPYsRYRRYSRRRRYR`,.SQYQOQQRR PY,|``{YYSaQPR-, R`QYYYZYQQ І+aRPY ZYPى[YUL' '6`PQQKZ% h``QYYPYRuPh$QRROJ`YYYRR`YJPPPRYR%hP`RQ$P`QYR`< hPPR`RPoPo`Q`Px%%PR(PsRYJN`Qqr`ؔQ`h JHYRh'PYaQYo+YQQPؙQQኮ &   QQ*$ QQRZZ*U$ QQYYZTZS~MQYQYRR +*{(ZRTTRRȀӰUQRYTTZU~UZRRQS& RZRQZR+L[`UQp 't$+8FTbp~QQYPQ`PQ`S`YZZZnQYQQR[Y[[n#`RYRRY`Z[[ ~RPQYRYYZY[:PRZRYSZZ[ $QR,QYa\b^~P`YQ`R[#$aGa$~ QPFbo$ ', YZ[cYPp8n$PRQpZF`}SYU\$PYQZ[b[pc[~Yyn R`RRYSYR`QPRY YRRQZRYRQ QY YR Y`QRYPYRl"qa%QA+AqG*ZSGS`(QaT`ec PhZYZZPh`Y[Z`Y`PYQYQRRZZYRRY`QY`RYR`RZRQYRPQ`Q QRPYL`YQ`   YQYRQYQRZ[$#`RYQQ`Y]$P YRY\8Q`RRPRZRc[[Z[R``)QTZZYZZZdAQ`Q?c Q`YPQ `PQQS`QPPRQYQQRZQYY`RYRR`R`YYP YYZYZYSaY% ZTZ[m#r#Y\bI"q#m0`PQ`h`RYPYR`hQRR`pP`YG, P`YYQYYYY``hh PYQYQQ ( Y[\PYYZ\\QQYSRZc[a[$@ "*QQYP``QYSYRYZZ$YZYY Y[cn$rn#m"qsn##r$&`RP YQYR`Q(7 PRPRYRRR`YP_hPLY(YRPpPh`K*R`RPGQ`YQ!v袈PG`PsuRYPȠ(PQ`QaSYQyxp``qZ'PxYPPChw FG`QQYQQ`(i`PQ`<*RQYP>RPp`hP>ZQQiPZRZP`YY(G`YXx&Z/}QQZ`Ɗp[& PP"1@%Y(WJPRRZPnQQQZMH RZ``QSHZQYRYQQSSRRRYRR%QR%KQZRn%PhQYIQo`Yo%PYJRQP`YS%J%o܊Z `QQYYQJ`Q`JJZY݊Q$P`R`&K#'ZP`q-]nꒊPP(`(% [ Y[[d'6 QSZ[\[\N# YRYRZZZc\cukYRRRNcNn``)aSaTb[\uQaRQSTZ[[NP`RZZSb蜈é`RSaQYTNdSRRyauia`&SRSu`RYu_Ñ";`ԡ8SZQPꉆN8鮉8PYQa'\I?K`RNZoQYaY`HQRPQ & RYZ"1$ZYR`T(X%QRYZZrn PYTYRZ[HQZ[RYTRa$JR`QYYIJ ZRYRYRRnR`R``&``ntnKR%ܙSYS%&TZضJYR钉n`SZYY$6PYQ$&%KaRTQP$RQZZaQZYQ'JJZT)aZR'RRTYSZRYZ(ڋL  RYQRRYQ `R`YRYRZR` YRRRQZQQP$ PPQQYZRZPY6HPQ0S`6YPpRQ4HWR`SR`De PQYSYR`QYhK`SYP [\c['P`PTZ[ZZZY`YY`RYRaSZYSaR`RYYRYQPRRaR`Q` RQP)QT``QQ``bS`RpwP}  Q`RRSaRT[\ RYQYPRYSc#$RZPRaZ\, YRRYRRYYZ[=Y QRa#SZc!`YAaZ[$SaSRZ[3s PYRZQYQZSZe4 QYP YQYRQQ PR`RYRYQ`YQQQQRQRZ#`SSaRRRR9Y Z RYS[[YZZY`R*YZ[#$"##k"``YQ@PPhRYQPYRZY PYYRRh`QZi (`/: ``Y`YZZPhPRYRZZZ``RQRYY`RY@ [Y[\`S[[dQYRYZ[\RYRRRZ[cQYZc^($P QYP YQYR`RYPRPRYRZZZ$PYYYYTZ[ "p ZT[c::p"s##n#E 'Q$+8FTbp~T"YY[UU\UZppYSZTU[TGpYZTTThYZ+ STiTZ( UZ Y* ZU\TZ iYY5UT FkU[U\G*T8hZZDqS[T[UTG}UU\T[hiZZETiGYR U[[pR VTG7Z &   /"HW SUZTTp"CE#[ZUU\T(D! ZZ[TU"K" SU[U!" ST[TU[ب؅SdTUD+ SSZZ[UTZCMTTTZU"n( 'N$&-9EQ]iu[[\]TZUV[W]]][U[V\]]T[V\TZ ^ZUU[0 U$ <UHZTH]ZTUG]T`T^SG[T1 l[`mTU]\\\ZZ[  (A*>XvT[ZS[UTTZTUTUU[U[U[[[U"U\UZZZ ZT8UZZSSJ \UZ:~XQV[TSTT[Z^ U\Tr'Cl pSUTUUZ qT[U[UU[T Y[UUUU[,YT'TATZZZZ6\VT)[T'FKVZTZMc ]^]]]] YZV]\\Z TV\V\UTZTS[U[UZTTSUZL;[UZSSUU\VUU[T[[[ST[UZVTU[V][UUTU[U($$#~M[UV[mdTZ[U[V8c T [TZ[UU\UZUUUTUZU[[T \\[U\ZT\\$~m#"ZZ$"nnRppRZ( YZT[RZUT[GYS, [ZZ[[[]ZTTU\\\ZZ[0[[]ST\UV][U\]]Z]$D T lYY[UV\Z p[[\[U[[" qsnnn~nsms$ &STS $YTSS(6YZSTT'\'YZSZ' YTSSZN ZZTZ]'N'RtNvQRTS蠈vv QYSZvv`ĉoZ_Qvbو'S鲉؉;YTOYST]ÉYTڊNT%Rv#SST&SS('Yu:ZT袋NSS:TTTnQZT:Q묋:Yы:%  Q />PYFUQYSTTl{ hRYYTSTUZYQSTSSUTUSS PRRSTTTSTYRYh#TZFTSh[R"i`RFYSS$h^ RYTZTSZ豈ҨiFH[UYRIɁQYS^ShgTSHRRYU>_]&UᆉǒSYaꊰ' %R RRT\&5SRTUcUULY SSUZ[VsMST[UVssSTMVSSSTT\TsSV\s&T[U2>LT]MfLYMUT[V饉YTUUỶSSU[]VYT[Ts馉̊L3̊p3ZeScTT迊?sⱊVU VZU\2%sUڲ][pKVTRRL#& RSS!0$RTTS(V$SUTS(p$ STSUT[Uv$ TUUSRR[Ul T[TTT[Y$$ UT]U]ZY$ TTUV[SH TTUUU[TMTS[\TT V]RRRU[YS萉hZU]VRYذl TVVRVURؠU]U@2SR[TZTZUR'SUTSFn(DSZ鰊v҉  ZTT[USSS FYTTUSTT"STTT RTU[UTUUZ4YRYUSSTUPSSTZARYTYT!aWTST[S[RoS<S} []QRT\\[TYSYYSTTTTZTSTTTUU[ T[TSTRRTU "RUZ$5+V30ZScR/ vSY}  TTTTT[TSUTUTS[TTUTS UUUTU\\SUZ,[~TYTUTZUTTV[V~^Y[N[\mUSTU\}YZTZ]]] SS STTTS TSTUSZST'ZU[UTU TT TTYS[7TZU CUTU2[UZ [[ TZTTV[\##$m"HYSST@ PR YTTYRSTUZSSUTSi`RTF(: ZYZU[\TYTS[U\]RTZUT[VST[UZ@[\TT]SSZUU[\]SU["\\:0[P SS YTTTS" STT" YTUT[/ T[[[ r< G#rn}sQRPQR? Tunnel portal overlays for railtypes by Snail (Jacopo Coletto)!# X'!ZZ;J"[#l YY\[[[Z[C"ZZZ[]eB]'[\͸DZZ\j.Y\]"Z\r\FiJ]HZ\]"tڠeY[Y]A!\EXY["ЬQ踸 XYZZY\Y]]BSe ^[Q=Z@\E؊B%ȩ]]]]]^V\c^EZiZVf]^+KXD]] F^X^ؾɘҫk%%Ц٫^%Ȗ4oٻЕлkoқaД\[ċق!/Ԑ%hҫZY2B⮋܌m%(XYX &YY*7MZYZYYZZTa'%-*tNZTq[\[Z[%[\CZ\\][.])\Ҹ(MP\])\ZY&P]\^]S\P{ [[]]]]^[\\,\]$YZzz]^QR YSP*p\]\1[[)^*[\^\ɢZ[]\ Z\&ဈ*+NrYX銚L]$~%v{%]\URI҈\\^^]]us[JnV'H;Y[d\hc]<6fc9c[8XҪY[ѯ-Y&[[F{[[Ìy;MxgY=x:xUc@{~# YZ[[[#!ZZZDB qc\A脈"!Z\[[d\\[")iZZSa@iZ\Gа!Q[[ఊY/FI'ypOҊvȝx(XZZ[ZX ZXZ[\\]\[\[ZY-& YYZ[]^]^]\.,tYrL"*]^^]YX'u%'*XYYt?]N*؆[ZYNZ\\UJث\YY[[z},)Y[ZZZ[+X+Z\(]ZUXKJ[Z?,ȃBt'YX-"&'*X%[&X)Ёr(OUఊ RS_@Zб -X$(k"wѐPCXcټ*,CQ#ZYZZY ZZ\%2&[JWf[J{Iؓ\H跈k(\['MZЎm%AБ%i\-i&moi،ȘZ Z+F[\'Ȍ]\][\j;]\C"^!x( \[Z[Z[.[[%ZZYZJ$\\[\JZZ[/ZYtHIp%U[\]]]聐k\\Z"V[]^]^)؏?ؼ\[L^)ؐ`'pK]^^)غл p^ MRظ[[MآMGNwy*ؚ^S]Q x=w࢙Z\qhl ȅlt0ټ~m\X.Z\ZѺaXȫر鯊4:m^겊вZ[AD[['+ Q\UMk!#[ ZZ\%4#[$VZ[\]\[[ZmZ"]][\Z\\]^]^HJ"]]J&\\[G^]]\\\]!ZY`$]]]o%$ZYYZkTYZ$Ym]\෠%ZY9[J^\^][؆Xm?D[[ZZLcl]^]W\\lZ$z5^l^\ewYF^]e>KS]^^nlehlZEH\\謐FmdHѱص&ڬ \$ԉȳ$ ZY^ZY` :!=e!vg!F/>ZBҸY}fNj`vzZ\#۩_8G\]g%( [[\!0&\\ZZ[[KZ&]\\\[Z)r[\^\\]ZR)L\]Q,ZY|]]^\*]\[ZY*H\^*]*Z&\O][YY0Z*,^OzZP0[\[\\PS^][u[\WY\[-]]&'|W]MQ\覈&\\Zx[-腐t ['MZ|{[^WHZR$}uW]][У~ؑ_wZ[YD*`nuY[!ZZ=yYH\{%HKx2DuVx5Y,/%Su[^ꛊŋw]أZY F/\ZS}ۿ⋋e4Nj̃^쇌^,"PPK[h{\t)!# r'!mt;JrItm^mrIN@@@t@C@"tttw:B:NwxN@NȩINttNtwwLt@mCt"tt@CkF mtmu@wNwN:Dt@vmmBeuLNt5CtmNut@utmF"mm@Q@uxwN fmr@൹sr::Dm6EC2wAu tB @@Bwtu:u"6NN@N@xwxu"@r6u@"x?h# +u"66ps/xr(p6e@FxNmm6NV cҼmII_JYLsy1tZ%p@mt#z'4%œH @ ص1UN|t:ȶ#v?tt L#@X@뻋%Ì=`o؊%(rmr &mt*7Mtrm)TatmttP~MImrttrt@mTllpt@tm@N@t) r@@Nt@@tr)(PNtNtN0@mmt&=rs?tSN'}N@r&fIN@wwPw*zq)OwxNxNwNxmm@t?tNwxw)R-)L%'wt@Z{̉{sz@Wxr?wH駉mL@xx{sᯚ"rn%@m?&p@2s#R؝m؜؟MҋN_tc??mIӝsWtb&r8@?r?LҨt?mx6a?m>5{Nm?>FM@ty>?m?mȋ@0Amm?;kUbC{~# mttmt#!@t!Bt@@dc!؄@!"t@N:NNN쐥@@@N tNtN@EBHS!t#NtftJ#'tX!CiHL@@#@l@tmNdtmmF'@F0F'CNNڊkOЋ犋^x(rmttmq mrrt@@N@t@t -K IIrtmtwNwN@.,tqsm N*NwwNNX'mmt%'*XtlmCNtN*rбp'?@HJ@m@ rt?Kttt??+,)N$lm'?,@@@mrmО]+PSUKrtrN>t?R)VK?1|mKrmK~UlKrImrK)U鞉hKIrrK$X}z|rIr+.Irmr?& tN' )KK/I_RmV &zKrmIImIL%5*YZIʐQ~)Nl#tmttm tt@%2&%Ve@o{؊N%$Gt@J@HNGwo2 Jm&MjtmmmtsKr~8@$r@NN#ᔈJ#FK$t蔉tt:@ro=mg oK:aNwNN%j4@N w:wN=wN$]x( tmtrtm# @tmrrIrtIJGFHrm-@tNNmmIItHNJtr ttt@@NwNww[)#t%m@#%4wx*;|GN8@m!LNN@xxw)$`rNmtt&"v+)*#л3wxwx}utt+e"x'PNxwuu)~w@@@'L)W wN?NxE}Qq{Nx@7w _$2JIvءMh0PpuxwTetwwLu:umu&چ@tsP&@@bꏋ#]`cULk!#@ m?%3N?w$V@NwxwNwtmN@"xxNNt!ww"xww$"tdD@JNwNN@@klmtm@mt?tw@xxLN#tmlmmtm$kNxNNwGt@l$%NwwI@@%kJ"tt@Jltq@tfNxF@@:Nt$t?NK@@ttkع??muN@]!#g#ku%wttmi%utu@s'kk6$NMHtmcquk6"m@LNN@::-$~fU@@w:m"tNn:>jO$m?At$QຢbЭR#$Њ!Nm!t?w*NuLr_鰈B u@Ls@sqpBCgNLtrqpin#}ˌFg%( @N@!0&w*WLN@Nwt@Sr NNwNxwxwN)NNNx)@,ǸqNNwxtSmmLxNwsN)|( wJ wN?s@yKPO)N?Lm$ؕI wxxLu@?sr|t wؠ??K' @NLtww@t#xL?KVu@uwNu:@?t0OutLLw@)xNKruN@tuwSN@m?Nw@@LuNu?@Nw? LuuLut@t@tL*N7B@LNL+UNl?`uz)t6mwAzu@ttL )tNL7M2 *tuNm>Pu>s/@uq!N@NNvPLL@LM܌F?Lst?!??t?uUS٘us?mwwMK>LLٸLl ȍ+"x$Sm|荕P%!# S'RRR;J"S#lQQTSSSRlC"kSCRB'STeZSTRRTj.؆ZdjRTrCQiFiJHRZR;?tڠQSQ]g$SZQERQSZ"ЬQYTZ/RZQTQ]UT7TBZ5QCQaUTUVUS RuRW\"Q TU]ЊBTZZTZ UUU]]VUBSe'NQcV!\TTQlVT]]UVbZ@DUUQZZlQSeVQC.T"ʊSm zRQѬзr%(SyhWR%CQS<"TVvI>w*SI( %nF%(PQP &QQQQQR*9 RZQRQQZTN%Z*R!vTZTQRRSTSZS%STRS4 ZRRRTTUS&U1R諈*MPT])TRQ(RUTVUSV S&SSUUU$VTV*]VUZ(@TSVKVV&,]TQT)z*GR&zSS~S)V&TVTѢUT,ZT#{VTZu٣R~UUzTT+z"{J0TS2T>TTkOHZRzxoSo9x@qDUS%OP Ҿ4<⊳8AuZZS R^Z몋'W&&F̌Rm?i@Q \(Cc<@+a{W# RRZST#!ZZ!BR qQRTZRTT!cQZSTZQSSTZ누ZTTSZSQ -aS%f)<Z THRQ"Q،QSTZBSS) bQ&)SSQRR%SH'&SRZQӊkdQSR#؞ŊNx(TSRSSRRRRRTUSRQQQQ-& QQSTSTUSVUVQQYvQRr VTVSTVUUWTXZ,'" TTVTTUVUU)U*SZRQ臨Ouy)'U.TS,-'lSTS.UcUTZZSQS C3UYQSRR SXS ITJZ(RSRR,RSU"TR"RRZRTQ3/SFKz$TRTᛑSZ,S!ZwSLRw,o6:P!,Z2W^LRZxVڢTS[L}?ZTR,*Om#SRZRZ RSTRR%4&%VeZSRQo~$%HRQSQZSZZTQZToޡTZQQ%J$TTZZS藉M\STZ&Q%MZTTSQZSTɣ>TSRSSSZmTTQZQSSRQ QRQ'RILTQRQRRTVSUTTVSUZ_T9UVU=^Z\耈{x( TSRSRS.SS%QRSQSRRJ$TTSTJTTUTtkSTUUr'SU&UV)Z;TS&.(&UVV)k&VhUSTJU%VVUGVOTSUmSpqVVR])soTV'TSV"]V(VD]% ]ؚ'L)wVV8,TK]U#]Q^>T1q!]VUU9P&$PUVT MjP<SUUp U(mZx~.c:'RZV9Ɋ&A *ڕLGVMk!#S RR%3FS$VRSTUTSTmBR"UUST%TTUVUVHU"UJHTTSGVUUUVI!RQZRZ$U]!IST# ZQRZRSRRTTkMJE RRQRQSSZ]VVTZESEISSToZ=HKOZSBV]]TZc%QZST]V]mZPZsS$VTSZTZ'ZZZSUVFVUQ$QQSTQSZZ U]UV+#}e SeHTTYS['SHhZQSQJTT)TRTڬhLTSQZSZ$ZZRQ RQ.7Q?'KRR:93!=DT!7Ќ<VTQR:RcauRQR%!U8GTUg%( SST!0?ZTTRRSSKZ TTUTTTSR)&STVTVURR)LTUT]VS)| STUUVV]VUUR|И UTUTV]]V]RSZU]V]U,]*(SZVVV!OWUTSSPSU)PMTB/U]ȑVp]Q)Vt9=S SZST[+]}TT9UTRFU:TMULST'cSp$U]ّJ Ty蝊ZS-O醉ڹUVTZSS剈y͊%(VZآೊM[ERp:gMjb_+ŢSSRU_SQ) *TVSQU]VSe'VMԀꮋ]ԍˣV,"裍$SKSh{)R!# 'ՠԈ;J^mӈe"ӈJB'҈"hm>"蔉fiIiJHȇ?O ڙ/g$/ؓ!iB w !fe}!hІ4ؓ|e XeFQ?AنFvkc؃#6!<_^hJ-7r^MEĒr؉Ȩڥ?H( zڼcһ o/ځKF].B 2Ì=!ҌjF%( &ՠԠԈ*7Mӈ*`'&՞ՈTtI%,Ԉt(K'՞Qֈ(J6T֟&&JP ">)艉PnT~L[)飈*)"֟ѥ y)͉#&[,Έ"[[[xQ"(SR)""PXG؞"' ""[sӋ( """[7[;'wʼn豒"y^P"٫x8蚉\LeJmz؞茠h+xDCk9kUbȍ{W# ӈ#!҈DB qcԈAcԈ҈"#ɐe)$!Ӊ2k $ѭN8ا#'M)`HT-&`LҊ<%'Nx(՞Ո-K*,r!,X&V[b- R}_,PȨЪ)Wǐ%*',O"R?Ѱ9O"""[ȨԠH"'"1m'ԟ [["Aq&""Vg&x["[)5&UASQԐr(UԊXzp֟Պ~|-ՠLTE!#,LOm#ԠԠ ҈%2&JWfӈo|$HkވKjԈJ!ۈoFMt٥h"M+載dзTkEjJlGԉҊ^">x( "՞ӈ."$ՈJ$$#tՠ՟$/Ҩ~ՠ> %r*Ч$ԟ"qNIMԠԟ'2ؘPK"s,QȘ"wИȘ)"$/ДИ"$$""87% "$(V)e$_v$Px*l$$_" (T%:$:;$0*Ԡ:""U"֊Xgt56$$$X`d'Ҋ‚՟)-0ԟdy-/ԊI-?Uv!!#Ҩ ӈ%4$VՈHe"ӈ%i$"$GJ!#HJ&#nI"&lGءImzJ$lH$ЇGpyJ!"mZW"а{-А٘wCfr; BA>!Q4ع@^0(ѤԠ&}J!#Gj!^ҠF! F0B0ڮ[cibB!ѢDBA%4g%( ӈ!0&҈*XLSr՞*҈&N+LtULOHLT0@UP੉0 z|'ԑlT$$"ЂɈ&}%"MTӠv$֠M)%$""$ղ&* ՠe$"$$X% ԟ"""-6)Ҡ֠$"e[$$f$"$)O"*"(ة՟N$P|ȧ֠[=LТ""eoҟȠԟmS֑?gtɞꨈx*;q֟US,|X袌lԠ͌•ԌX,S%m|C}l !# '!";J"^m[""I"[!6B6[H["[[j"""[re[i"F"6 [[!/6#!Q6D" uxZQ "#[6BZZȎe"""6BZ!"[D$#""`!"!!!D 8"""&Z :$$BdHk$"|$"""["!Z0"]&![me%6[pR[e"![h"`X"omo " D%OjDZ o$n=%0o[J"҈o"鈘"[[軉i"[m[ ![3+\FحK[蕊j "4"^x( "# "##[[#JY"F) 8$6tk"["68$#$#)""I* 8$%##R$$$"S14#c$$'$"[%"$#]CJ"p$%$"[_%$6+*#"e ] 6"#U8 $"$%" $$6_8"8""$_$ 6,a#JE#[Y$##[86Y6#[rYY606" 6[6[p~$L6""P7P ["YZ&Щ&_[#"T$""$$)" &K"OULL!#" ""%3FIW6##$y6"#m!##$$H#"J$6#G$#!6"6"$om "6"666##k$G""6666&KPl"EI$$#$I[[[Jm6a"$% [""I#% """[MK]$k"["6&Z"$Hm [[6$"%""ieJ""#رI"BF ["6"F[xI$[po[[ZY ^H`'[!%CE!F1Ȁ錈B# 6،[Bw c$#"ꞈHD$JӪ걋9DxYh%( ""!0&#"*YL$#Sr$')&" %#$|" _$#Y[6oN%#M$$"##R$%$#"%&6#$%)G #]Ut"u"#60]#"#*k]A#ZVNT$$r"#|["{"#[PT6"$c["[Z[#$"6YB["66"D[![666rm_e$[$$"Y6. $" ZZY=2"$e[$mZYh""("["{"{ݓ?6裙 ^"6YYȔ*" YUSf"]Y"J#ᑌ##!R|(Sm|u !# ['Z\];J[\]^^m"]]]^Ie[[\$[SSS%J^]\QSRTRRT[K^]]\S!RSTSR\["QhItSHQbSCTSk 0 e(R[sSSZST-Bv"TBѵ%G RBOQj %SZ Й([\J\SQE!G=%dEЎQP%TheRQ} k!WѠثʫZl5ЭHJMnF%Iڔk%IMңPRTS!Q$23#J%hQ%(QRQ &RSR*7'RSTTUTUTN RPRSVUTTVT[\~&PS$U&]]\[&NO[Z]]]^*RQUUL&,TTRSSv&UTSR&ST'T*&USP+*ST%UUURz$AST%V+)*TS@TZ[Z*OUUS)STUZ\]\)VP[PR')Z']*SN^h{*N\\L'^^^{t%)P\\&SsVZ)]\)Р&UV*蠊&ُt'Zr)A7(R)ٶxwVA)P'ݱi^)᳊(\Z+)T[⤊QPP*Fh')\O댡Ḉ'MЌ.x( TUUSRR. \]^^]\SRQTSRS+$^' RQRSTSTSQQUkVUVN&[R%SX]\% WVWU]\[\\]%T[\][k]\%VU[[&]*&^]^*QS&xUP^]] SjvTTT)&VVVU*Q21$ TWWWW*T\QT0PM$|W0\[UU%N)S0\Uw& R2)W[\j5&3Rឨ*{S&艊*2~ TH_Кdɹhl #TTGVTW$!#V W^W%4^_$V^____$yVW$^^WWU"!WV$ST$!VV$TS%!UUUTSRQSRJ!s,ZQQR"TT$%GSRRRRQISo"mEKSIG!HLPTG"`THSTEL^]Fb\[SQK^n$ST ST[\]]\[R&TUBُ$إ!^]%V!&m[TB %RSg mخ%\[ST$Ȏ k!mЯ:9B?U@F(ROᵑӐ!Ѥcw\[%!AJB#@o^"b9E4Zf%( UVU!0&WWW*XLTU&*t\[TVTTRT)[\]]*UTV|&]]^]]]Z*V*SL%*\[UU~^^]* SSRTTTSRQ0WUU4*&#S,RR&.)+LSR&|U.TSUN,|UsTRTZ[ZUv^&PJ'\]\ZQTT&__)V')&_^_^STZh^R]^^^),QZ\)uNSQSO^^\(y~ቭТءآ O&ْ*\\[$ِ~Z=L C'VUR(5 4SxS'Ș|ۊ'^[ٿZ\(O@&>)@IRhٞSSۺl_VW,ETm|Cl All black paletteopenttd-1.5.3/bin/baseset/orig_dos.obs0000644000000000000000000001077012627373446016426 0ustar rootroot; $Id: orig_dos.obs 27041 2014-10-25 12:35:48Z rubidium $ ; ; This represents the original sounds as on the Transport ; Tycoon Deluxe DOS CD. ; [metadata] name = original_dos shortname = TTDO version = 0 description = Original Transport Tycoon Deluxe DOS edition sounds. description.af_ZA = Oorspronklike Transport Tycoon Deluxe DOS uitgawe klanke. description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الصوتية نسخة الدوس description.be_BY = Арыґінальны набор гукавога афармленьня з гульні Transport Tycoon Deluxe для DOS. description.bg_BG = Оригинални звуци на Transport Tycoon Deluxe за DOS. description.ca_ES = Sons originals de Transport Tycoon Deluxe per a DOS. description.cs_CZ = Původní sada zvuků Transport Tycoon Deluxe (verze pro DOS). description.cy_GB = Effeithiau sain gwreiddiol fersiwn DOS o Transport Tycoon Deluxe. description.da_DK = Originallyd fra Transport Tycoon Deluxe DOS-version. description.de_DE = Original Transport Tycoon Deluxe DOS Basissounds. description.el_GR = Αρχικοί ήχοι από το Transport Tycoon Deluxe έκδοση DOS. description.en_AU = Original Transport Tycoon Deluxe DOS edition sounds. description.en_US = Original Transport Tycoon Deluxe DOS edition sounds. description.es_ES = Sonidos originales de Transport Tycoon Deluxe versión DOS. description.et_EE = Algse Transport Tycoon Deluxe DOSi versiooni helid. description.fi_FI = Alkuperäiset Transport Tycoon Deluxen DOS-version äänet. description.fr_FR = Sons originaux de Transport Tycoon Deluxe (version DOS). description.ga_IE = Fuaimeanna bunaidh Transport Tycoon Deluxe, eagrán DOS. description.gd_GB = Fuaimean aig an deasachadh DOS tùsail aig Transport Tycoon Deluxe. description.gl_ES = Sons da edición orixinal de Transport Tycoon Deluxe para DOS. description.hr_HR = Originalni zvukovi za Transport Tycoon Deluxe DOS izdanje. description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS verziójának hangjai. description.id_ID = Efek suara orisinil Transport Tycoon Deluxe versi DOS. description.is_IS = Upprunalega hljóðið úr Transport Tycoon Deluxe DOS útgáfunni. description.it_IT = Suoni originali di Transport Tycoon Deluxe, edizione DOS. description.ja_JP = Transport Tycoon Deluxe オリジナル版 効果音 (DOS) description.ko_KR = 오리지널 트랜스포트 타이쿤 도스 에디션의 효과음입니다. description.la_VA = Soni ex editione originale Transport Tycoon Deluxe DOS. description.lb_LU = Original Transport Tycoon Deluxe DOS Editioun Sound. description.lt_LT = Originalūs Transport Tycoon Deluxe DOS leidimo garsai. description.nb_NO = Originale lyder fra Transport Tycoon Deluxe for DOS. description.nl_NL = Originele geluiden van de Transport Tycoon Deluxe DOS-versie. description.nn_NO = Originale lydar frå Transport Tycoon Deluxe for DOS. description.pl_PL = Oryginalna edycja dźwięków dla Transport Tycoon Deluxe DOS. description.pt_BR = Sons Originais do Transport Tycoon Deluxe, Edição DOS. description.pt_PT = Sons originais da edição DOS de Transport Tycoon Deluxe. description.ro_RO = Setul de sunete original al Transport Tycoon Deluxe pentru DOS. description.ru_RU = Оригинальный набор звукового оформления из игры Transport Tycoon Deluxe для DOS. description.sk_SK = Pôvodné zvuky Transport Tycoon Deluxe (DOS). description.sl_SI = Originalni zvoki Transport Tycoon Deluxe različice DOS. description.sr_RS = Originalni skup zvukova Transport Tycoon Deluxe DOS izdanja. description.sv_SE = Originalljuden från Transport Tycoon Deluxe, DOS-utgåvan. description.ta_IN = அசல் டிரான்ஸ்ஃபோர்ட் டைகூன் டீலக்ஸ் DOS பதிப்பு ஒலிகள். description.th_TH = เสียงต้นตำหรับของ Transport Tycoon Deluxe DOS edition description.tr_TR = Özgün Transport Tycoon Deluxe DOS sürümü sesleri. description.uk_UA = Оригінальний набір звуків з Transport Tycoon Deluxe DOS edition. description.vi_VN = Âm thanh gốc từ phiên bản Transport Tycoon Deluxe trên DOS description.zh_CN = 运输大亨DOS豪华版原版音效包. description.zh_TW = 原版 Transport Tycoon Deluxe DOS 版的音效。 [files] samples = SAMPLE.CAT [md5s] SAMPLE.CAT = 422ea3dd074d2859bb51639a6e0e85da [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. openttd-1.5.3/bin/baseset/orig_win.obm0000644000000000000000000001550112627373446016425 0ustar rootroot; $Id: orig_win.obm 27274 2015-05-08 17:45:13Z rubidium $ ; ; This represents the original music as on the Transport ; Tycoon Deluxe for Windows CD. ; [metadata] name = original_windows shortname = TTDW version = 1 description = Original Transport Tycoon Deluxe Windows edition music. description.af_ZA = Oorspronklike Transport Tycoon Deluxe Windows uitgawe musiek. description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الموسيقية نسخة وندوز description.be_BY = Арыґінальны набор музычнага афармленьня з гульні Transport Tycoon Deluxe для Windows. description.bg_BG = Оригинална музика на Transport Tycoon Deluxe за Windows. description.ca_ES = Música Original de Transport Tycoon Deluxe per a Windows. description.cs_CZ = Původní hudba Transport Tycoon Deluxe (verze pro Windows). description.cy_GB = Cerddoriaeth gwreiddiol fersion Windows o Transport Tycoon Deluxe. description.da_DK = Originalmusik fra Transport Tycoon Deluxe Windows-version. description.de_DE = Original Transport Tycoon Deluxe Windows Musikset. description.el_GR = Αρχική μουσική από το Transport Tycoon Deluxe έκδοση Windows. description.en_AU = Original Transport Tycoon Deluxe Windows edition music. description.en_US = Original Transport Tycoon Deluxe Windows edition music. description.es_ES = Música original de Transport Tycoon Deluxe versión Windows. description.et_EE = Algse Transport Tycoon Deluxe Windowsi versiooni muusika. description.fi_FI = Alkuperäinen Transport Tycoon Deluxen Windows-version musiikki. description.fr_FR = Musiques originales de Transport Tycoon Deluxe (version Windows). description.ga_IE = Ceol bunaidh Transport Tycoon Deluxe, eagrán Windows. description.gd_GB = Ceòl aig an deasachadh Windows tùsail aig Transport Tycoon Deluxe. description.gl_ES = Música da edición orixinal de Transport Tycoon Deluxe para Windows. description.hr_HR = Originalna muzika za Transport Tycoon Deluxe Windows izdanje. description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának zenéje. description.id_ID = Musik pengiring orisinil Transport Tycoon Deluxe versi Windows. description.is_IS = Upprunalega tónlistin úr Transport Tycoon Deluxe Windows útgáfunni. description.it_IT = Musica originale di Transport Tycoon Deluxe, edizione Windows. description.ja_JP = Transport Tycoon Deluxe オリジナル版 音楽 (Windows) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 윈도 에디션의 음악입니다. description.la_VA = Musica ex editione originale Transport Tycoon Deluxe Windows. description.lb_LU = Original Transport Tycoon Deluxe Windows Editioun Musik. description.lt_LT = Originali Transport Tycoon Deluxe Windows leidimo muzika. description.lv_LV = Oriģinālā Transport Tycoon Deluxe Windows izdevuma mūzika. description.nb_NO = Original musikk fra Transport Tycoon Deluxe for Windows. description.nl_NL = Originele muziek van de Transport Tycoon Deluxe Windows-versie. description.nn_NO = Original musikk frå Transport Tycoon Deluxe for Windows. description.pl_PL = Oryginalna edycja utworów muzycznych w Transport Tycoon Deluxe Windows. description.pt_BR = Música Original do Transport Tycoon Deluxe, Edição Windows description.pt_PT = Música original da edição Windows de Transport Tycoon Deluxe. description.ro_RO = Setul de muzică original al Transport Tycoon Deluxe pentru Windows. description.ru_RU = Оригинальный набор музыкального оформления из игры Transport Tycoon Deluxe для Windows. description.sk_SK = Pôvodná hudba z Transport Tycoon Deluxe (Windows). description.sl_SI = Originalna glasba Transport Tycoon Deluxe različice oken(windows). description.sr_RS = Originalni skup muzičkih numera Transport Tycoon Deluxe Windows izdanja. description.sv_SE = Originalmusiken från Transport Tycoon Deluxe, Windows-utgåvan. description.ta_IN = அசல் டிரான்ஸ்ஃபோர்ட் டைகூன் டீலக்ஸ் விண்டோஸ் பதிப்பு இசை. description.th_TH = เพลงต้นตำหรับชอง Transport Tycoon Deluxe Windows edition description.tr_TR = Özgün Transport Tycoon Deluxe Windows sürümü müzikleri. description.uk_UA = Оригінальна музика з Transport Tycoon Deluxe Windows edition. description.vi_VN = Nhạc gốc từ phiên bản Transport Tycoon Deluxe trên Windows description.zh_CN = Transport Tycoon Deluxe(运输大亨Windows豪华版)的原版音乐包 description.zh_TW = 原版 Transport Tycoon Deluxe Windows 版的音樂。 [files] theme = GM_TT00.GM old_0 = GM_TT02.GM old_1 = GM_TT06.GM old_2 = GM_TT03.GM old_3 = GM_TT12.GM old_4 = GM_TT08.GM old_5 = GM_TT13.GM old_6 = GM_TT14.GM old_7 = GM_TT10.GM old_8 = old_9 = new_0 = GM_TT04.GM new_1 = GM_TT01.GM new_2 = GM_TT05.GM new_3 = GM_TT15.GM new_4 = GM_TT11.GM new_5 = GM_TT16.GM new_6 = GM_TT09.GM new_7 = new_8 = new_9 = ezy_0 = GM_TT18.GM ezy_1 = GM_TT19.GM ezy_2 = GM_TT21.GM ezy_3 = GM_TT17.GM ezy_4 = GM_TT20.GM ezy_5 = GM_TT07.GM ezy_6 = ezy_7 = ezy_8 = ezy_9 = [md5s] GM_TT00.GM = 45cfec1b9d8c7a0ad45e755833cbf221 GM_TT01.GM = ab14ed3392d848abd2a2e90a9d75d121 GM_TT02.GM = dd4f696e4be5987ce738257b08b50171 GM_TT03.GM = a1bfde23343df9e4063419bf29c166b8 GM_TT04.GM = 4e6943aa0c455203d76c79389054747d GM_TT05.GM = cee281cb85a2e2343552d97640545a47 GM_TT06.GM = 26d1de5efa8675f94065784e9d539e49 GM_TT07.GM = 6f2691e17558f552ec4c565e4ab7139c GM_TT08.GM = a42bf2cb3340a822f1a69646fc7a487d GM_TT09.GM = eb35761a58a8df3c59ed8929cce13916 GM_TT10.GM = 42fecd686720a785d20a78590c466a82 GM_TT11.GM = 50ef1ef02e49d2112786dd45e69dc3ee GM_TT12.GM = 4ce707a0e0e72419f0681dd9bd95271b GM_TT13.GM = e765753be29d889ec818f38009103619 GM_TT14.GM = 270e2d63bd32b95a4d007ce15a6ce45f GM_TT15.GM = 89e116a1c0c69f1845cc903a9bfbe460 GM_TT16.GM = f824e2371b3bedfe61aad4b9c62dd6be GM_TT17.GM = 1b23eebb0796c1ab99cd97fa7082cf7b GM_TT18.GM = 15650de3bad645d0e88c4f5c7a2df92a GM_TT19.GM = 7aec079e15bd09588660b85545ac4dfc GM_TT20.GM = 1509097889dee617aa1e9a1738a5a930 GM_TT21.GM = a8d0aaad02e1a762d8d54cf81da56bab [names] GM_TT00.GM = Tycoon DELUXE Theme GM_TT01.GM = Snarl Up GM_TT02.GM = Easy Driver GM_TT03.GM = Little Red Diesel GM_TT04.GM = City Groove GM_TT05.GM = Aliens Ate My Railway GM_TT06.GM = Stoke It GM_TT07.GM = Don't Walk! GM_TT08.GM = Sawyer's Tune GM_TT09.GM = Fell Apart On Me GM_TT10.GM = Can't Get There From Here GM_TT11.GM = Hard Drivin' GM_TT12.GM = Road Hog GM_TT13.GM = Hold That Train! GM_TT14.GM = Broomer's Oil Rag GM_TT15.GM = Goss Groove GM_TT16.GM = Small Town GM_TT17.GM = Cruise Control GM_TT18.GM = Stroll On GM_TT19.GM = Funk Central GM_TT20.GM = Jammit GM_TT21.GM = Movin' On [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. openttd-1.5.3/bin/baseset/orig_dos_de.obg0000644000000000000000000001307412627373446017062 0ustar rootroot; $Id: orig_dos_de.obg 27041 2014-10-25 12:35:48Z rubidium $ ; ; This represents the original graphics as on the German Transport ; Tycoon Deluxe DOS CD. It contains one broken sprite. ; [metadata] name = original_dos_de shortname = TTDD version = 0 palette = DOS description = Original Transport Tycoon Deluxe DOS (German) edition graphics. description.af_ZA = Oorspronklike Transport Tycoon Deluxe DOS (German) uitgawe grafieke. description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الالمانية نسخة الدوس description.be_BY = Арыґінальная ґрафіка зь нямецкай версіі Transport Tycoon Deluxe для DOS. description.bg_BG = Оригинални графики на Transport Tycoon Deluxe за DOS (немски) . description.ca_ES = Gràfics originals de Transport Tycoon Deluxe per a DOS (Alemany). description.cs_CZ = Původní sada grafik Transport Tycoon Deluxe (německá verze pro DOS). description.cy_GB = Graffeg gwreiddiol fersiwn DOS (Almaenig) o Transport Tycoon Deluxe. description.da_DK = Originalgrafik fra Transport Tycoon Deluxe DOS (Tysk) version. description.de_DE = Original Transport Tycoon Deluxe DOS (Deutsch) Basisgrafiken. description.el_GR = Αρχικά γραφικά από το Transport Tycoon Deluxe έκδοση DOS (Γερμανικό). description.en_AU = Original Transport Tycoon Deluxe DOS (German) edition graphics. description.en_US = Original Transport Tycoon Deluxe DOS (German) edition graphics. description.es_ES = Gráficos originales de Transport Tycoon Deluxe versión DOS (Alemán). description.et_EE = Algse Transport Tycoon Deluxe DOSi (Saksa) versiooni graafika. description.fi_FI = Alkuperäiset Saksassa julkaistun Transport Tycoon Deluxen DOS-version grafiikat. description.fr_FR = Graphiques originaux de Transport Tycoon Deluxe (version DOS allemande). description.ga_IE = Grafaicí bunaidhTransport Tycoon Deluxe, eagrán DOS (Gearmánach). description.gd_GB = Grafaigeachd aig an deasachadh DOS (Gearmailteach) tùsail aig Transport Tycoon Deluxe. description.gl_ES = Graficos da edición orixinal (alemá) de Transport Tycoon Deluxe para DOS. description.hr_HR = Originalna grafika za Transport Tycoon Deluxe DOS (Njemački) izdanje. description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS (német) verziójának grafikája. description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi DOS (Jerman). description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe DOS (þýsku) útgáfunni. description.it_IT = Grafica originale di Transport Tycoon Deluxe (tedesco), edizione DOS. description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (DOS・ドイツ版) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 도스 에디션(독일)의 그래픽입니다. description.la_VA = Graphica ex editione originale Transport Tycoon Deluxe DOS (Germanica). description.lb_LU = Original Transport Tycoon Deluxe DOS (Däitsch) Editioun Grafik. description.lt_LT = Originali Transport Tycoon Deluxe DOS (Vokiečių) leidimo grafika. description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for DOS (tysk). description.nl_NL = Originele graphics van de Duitse Transport Tycoon Deluxe DOS-versie. description.nn_NO = Original grafikk frå Transport Tycoon Deluxe for DOS (tysk). description.pl_PL = Oryginalna edycja grafik dla Transport Tycoon Deluxe DOS (German). description.pt_BR = Gráficos Originais do Transport Tycoon Deluxe, Edição DOS alemã. description.pt_PT = Gráficos originais da edição DOS (Alemã) de Transport Tycoon Deluxe. description.ro_RO = Setul grafic original al Transport Tycoon Deluxe pentru DOS (ediţia germană). description.ru_RU = Оригинальная графика из немецкой версии Transport Tycoon Deluxe для DOS. description.sk_SK = Pôvodná grafika Transport Tycoon Deluxe (DOS) (v jazyku nemčina). description.sl_SI = Originalna grafika Transport Tycoon Deluxe za nemško različico DOS. description.sr_RS = Originalni skup grafika nemačkog Transport Tycoon Deluxe DOS izdanja. description.sv_SE = Originalgrafiken från Transport Tycoon Deluxe, DOS-utgåvan (tyska). description.ta_IN = அசல் டிரான்ஸ்ஃபோர்ட் டைகூன் டீலக்ஸ் DOS (செருமன்) பதிப்பு அசைவூட்டங்கள். description.th_TH = กราฟฟิกต้นตำหรับของ Transport Tycoon Deluxe DOS (German) edition description.tr_TR = Özgün Transport Tycoon Deluxe DOS (Almanca) sürümü grafikleri. description.uk_UA = Оригінальна графіка з Transport Tycoon Deluxe DOS edition (німецького). description.vi_VN = Đồ họa gốc từ phiên bản Transport Tycoon Deluxe trên DOS (tiếng Đức) description.zh_CN = 运输大亨DOS豪华德语版原版图形包. description.zh_TW = 原版 Transport Tycoon Deluxe DOS 版 (德國版) 的圖形。 [files] base = TRG1.GRF logos = TRGI.GRF arctic = TRGC.GRF tropical = TRGH.GRF toyland = TRGT.GRF extra = OPENTTD.GRF [md5s] TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 TRGC.GRF = ed446637e034104c5559b32c18afe78d TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 TRGT.GRF = fcde1d7e8a74197d72a62695884b909e OPENTTD.GRF = 505d96061556d3bb5cec6234096ec5bc [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. OPENTTD.GRF = This file was part of your OpenTTD installation. openttd-1.5.3/bin/baseset/no_sound.obs0000644000000000000000000000634212627373446016445 0ustar rootroot; $Id: no_sound.obs 27103 2015-01-01 20:51:18Z rubidium $ ; ; This represents more or less nothingness ; [metadata] name = NoSound shortname = NULL version = 2 fallback = true description = A sound pack without any sounds. description.af_ZA = 'n Klank stel sonder enige klanke. description.ar_EG = مجموعة صوت بدوت اصوات مضافة description.be_BY = "Пусты" набор гукавога афармленьня, які не зьмяшчае ніякіх гукаў. description.bg_BG = Празен звуков пакет. description.ca_ES = Un joc de sons sense cap so. description.cs_CZ = Prázdná sada zvuků. description.cy_GB = Pecyn sain heb unrhyw effeithiau sain ynddo. description.da_DK = En lydpakke uden lyde. description.de_DE = Basissounds ohne Sound. description.el_GR = Ένα πάκετο ήχων χώρις ήχους. description.en_AU = A sound pack without any sounds. description.en_US = A sound pack without any sounds. description.es_ES = Un conjunto de sonidos vacío. description.et_EE = Helikogu ilma helideta. description.eu_ES = Soinurik gabeko soinu pakete bat description.fi_FI = Äänipaketti, jossa ei ole ääniä. description.fr_FR = Un pack de sons sans sons. description.ga_IE = Pacáiste fuaimeanna gan aon fhuaimeanna ann. description.gd_GB = Pacaid fhuaimean anns nach eil fuaim sam bith. description.gl_ES = Un conxunto de sons sen ningún son description.hr_HR = Zvučni paket bez ikakvih zvukova. description.hu_HU = Hang alapcsomag hangok nélkül. description.id_ID = Paket efek suara tanpa suara apapun. description.is_IS = Hljóðpakki án hljóðs. description.it_IT = Un pacchetto sonoro non contenente alcun suono. description.ja_JP = 空の効果音パック description.ko_KR = 아무런 효과음도 없는 효과음 팩입니다. description.la_VA = Sarcina sonorum sine ullis sonis. description.lb_LU = E Soundpack ouni iergendee Sound. description.lt_LT = Garsų pakas be jokių garsų. description.nb_NO = En lydpakke uten noen lyder. description.nl_NL = Een geluidset zonder geluid. description.nn_NO = Ei lydpakke utan nokon lydar. description.pl_PL = Zestaw dźwięków nie zawierający żadnych dźwięków. description.pt_BR = Um pacote de sons sem sons. description.pt_PT = Um conjunto de sons vazio. description.ro_RO = Un set de sunete fără nici un sunet inclus. description.ru_RU = "Пустой" набор звукового оформления, не содержащий никаких звуков. description.sk_SK = Zvuková sada neobsahujúca zvuky. description.sl_SI = Zvočni paket brez zvoka. description.sr_RS = Prazan skup zvukova. description.sv_SE = Ett ljudpaket utan några ljud. description.ta_IN = ஒலிகள் இல்லாத ஒலி தொகுப்பு. description.th_TH = ชุดเสียงแบบไร้เสียง description.tr_TR = Ses içermeyen boş bir ses kümesi. description.uk_UA = Порожній набір звуків. description.vi_VN = Gói âm thanh này không có âm thanh nào. description.zh_CN = 一个空的音效包. description.zh_TW = 不含任何音效的音效集。 [files] samples = [md5s] [origin] default = This file was part of your OpenTTD installation. openttd-1.5.3/bin/baseset/orig_dos.obg0000644000000000000000000001171112627373446016406 0ustar rootroot; $Id: orig_dos.obg 27041 2014-10-25 12:35:48Z rubidium $ ; ; This represents the original graphics as on the non-German Transport ; Tycoon Deluxe DOS CD. ; [metadata] name = original_dos shortname = TTDD version = 1 palette = DOS description = Original Transport Tycoon Deluxe DOS edition graphics. description.af_ZA = Oorspronklike Transport Tycoon Deluxe DOS uitgawe grafieke. description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الرسومية نسخة الدوس description.be_BY = Арыґінальная ґрафіка з Transport Tycoon Deluxe для DOS. description.bg_BG = Оригинални графики на Transport Tycoon Deluxe за DOS. description.ca_ES = Gràfics originals de Transport Tycoon Deluxe per a DOS. description.cs_CZ = Původní sada grafik Transport Tycoon Deluxe (verze pro DOS). description.cy_GB = Graffeg gwreiddiol fersiwn DOS o Transport Tycoon Deluxe. description.da_DK = Originalgrafik fra Transport Tycoon Deluxe DOS-version. description.de_DE = Original Transport Tycoon Deluxe DOS Basisgrafiken. description.el_GR = Αρχικά γραφικά από το Transport Tycoon Deluxe έκδοση DOS. description.en_AU = Original Transport Tycoon Deluxe DOS edition graphics. description.en_US = Original Transport Tycoon Deluxe DOS edition graphics. description.es_ES = Gráficos originales de Transport Tycoon Deluxe versión DOS. description.et_EE = Algse Transport Tycoon Deluxe DOSi versiooni graafika. description.fi_FI = Alkuperäiset Transport Tycoon Deluxen DOS-version grafiikat. description.fr_FR = Graphiques originaux de Transport Tycoon Deluxe (version DOS). description.ga_IE = Grafaicí bunaidhTransport Tycoon Deluxe, eagrán DOS. description.gd_GB = Grafaigeachd aig an deasachadh DOS tùsail aig Transport Tycoon Deluxe. description.gl_ES = Graficos da edición orixinal de Transport Tycoon Deluxe para DOS. description.hr_HR = Originalna grafika za Transport Tycoon Deluxe DOS izdanje. description.hu_HU = Az eredeti Transport Tycoon Deluxe DOS verziójának grafikája. description.id_ID = Grafik orisinil Transport Tycoon Deluxe versi DOS. description.is_IS = Upprunalega grafíkin úr Transport Tycoon Deluxe DOS útgáfunni. description.it_IT = Grafica originale di Transport Tycoon Deluxe, edizione DOS. description.ja_JP = Transport Tycoon Deluxe オリジナル版 グラフィック (DOS) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 도스 에디션의 그래픽입니다. description.la_VA = Graphica ex editione originale Transport Tycoon Deluxe DOS. description.lb_LU = Original Transport Tycoon Deluxe DOS Editioun Grafik. description.lt_LT = Originali Transport Tycoon Deluxe DOS leidimo grafika. description.nb_NO = Original grafikk fra Transport Tycoon Deluxe for DOS. description.nl_NL = Originele graphics van de Transport Tycoon Deluxe DOS-versie. description.nn_NO = Original grafikk frå Transport Tycoon Deluxe for DOS. description.pl_PL = Oryginalna edycja grafik dla Transport Tycoon Deluxe DOS. description.pt_BR = Gráficos Originais do Transport Tycoon Deluxe, Edição DOS. description.pt_PT = Gráficos originais da edição DOS de Transport Tycoon Deluxe. description.ro_RO = Setul grafic original al Transport Tycoon Deluxe pentru DOS. description.ru_RU = Оригинальная графика из Transport Tycoon Deluxe для DOS. description.sk_SK = Pôvodná grafika Transport Tycoon Deluxe (DOS). description.sl_SI = Originalna grafika Transport Tycoon Deluxe za različico DOS. description.sr_RS = Originalni skup grafika Transport Tycoon Deluxe DOS izdanja. description.sv_SE = Originalgrafiken från Transport Tycoon Deluxe, DOS-utgåvan. description.ta_IN = அசல் டிரான்ஸ்ஃபோர்ட் டைகூன் டீலக்ஸ் DOS பதிப்பு அசைவூட்டங்கள். description.th_TH = กราฟฟิกต้นตำหรับของ Transport Tycoon Deluxe DOS edition description.tr_TR = Özgün Transport Tycoon Deluxe DOS sürümü grafikleri. description.uk_UA = Оригінальна графіка з Transport Tycoon Deluxe DOS edition. description.vi_VN = Đồ họa gốc từ phiên bản Transport Tycoon Deluxe trên DOS description.zh_CN = 运输大亨DOS豪华版原版图形包. description.zh_TW = 原版 Transport Tycoon Deluxe DOS 版的圖形。 [files] base = TRG1.GRF logos = TRGI.GRF arctic = TRGC.GRF tropical = TRGH.GRF toyland = TRGT.GRF extra = OPENTTD.GRF [md5s] TRG1.GRF = 9311676280e5b14077a8ee41c1b42192 TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 TRGC.GRF = ed446637e034104c5559b32c18afe78d TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 TRGT.GRF = e30e8a398ae86c03dc534a8ac7dfb3b6 OPENTTD.GRF = 505d96061556d3bb5cec6234096ec5bc [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. OPENTTD.GRF = This file was part of your OpenTTD installation. openttd-1.5.3/bin/baseset/orig_win.obs0000644000000000000000000001140612627373446016433 0ustar rootroot; $Id: orig_win.obs 27041 2014-10-25 12:35:48Z rubidium $ ; ; This represents the original sounds as on the Transport ; Tycoon Deluxe for Windows CD. ; [metadata] name = original_windows shortname = TTDO version = 0 description = Original Transport Tycoon Deluxe Windows edition sounds. description.af_ZA = Oorspronklike Transport Tycoon Deluxe Windows uitgawe klanke. description.ar_EG = النسخة الاصلية من ترانسبورت تايكون ديلوكس الصوتية نسخة وندوز description.be_BY = Арыґінальны набор гукавога афармленьня з гульні Transport Tycoon Deluxe для Windows. description.bg_BG = Оригинални звуци на Transport Tycoon Deluxe за Windows. description.ca_ES = Sons originals de Transport Tycoon Deluxe per a Windows. description.cs_CZ = Původní sada zvuků Transport Tycoon Deluxe (verze pro Windows). description.cy_GB = Effeithiau sain gwreiddiol fersiwn Windows o Transport Tycoon Deluxe. description.da_DK = Originallyd fra Transport Tycoon Deluxe Windows-version. description.de_DE = Original Transport Tycoon Deluxe Windows Basissounds. description.el_GR = Αρχικοί ήχοι από το Transport Tycoon Deluxe έκδοση Windows. description.en_AU = Original Transport Tycoon Deluxe Windows edition sounds. description.en_US = Original Transport Tycoon Deluxe Windows edition sounds. description.es_ES = Sonidos originales de Transport Tycoon Deluxe versión Windows. description.et_EE = Algse Transport Tycoon Deluxe Windowsi versiooni helid. description.fi_FI = Alkuperäiset Transport Tycoon Deluxen Windows-version äänet. description.fr_FR = Sons originaux de Transport Tycoon Deluxe (version Windows). description.ga_IE = Fuaimeanna bunaidh Transport Tycoon Deluxe, eagrán Windows. description.gd_GB = Fuaimean aig an deasachadh Windows tùsail aig Transport Tycoon Deluxe. description.gl_ES = Sons da edición orixinal de Transport Tycoon Deluxe para Windows. description.hr_HR = Originalni zvukovi za Transport Tycoon Deluxe Windows izdanje. description.hu_HU = Az eredeti Transport Tycoon Deluxe Windows verziójának hangjai. description.id_ID = Efek suara orisinil Transport Tycoon Deluxe versi Windows. description.is_IS = Upprunalega hljóðið úr Transport Tycoon Deluxe Windows útgáfunni. description.it_IT = Suoni originali di Transport Tycoon Deluxe, edizione Windows. description.ja_JP = Transport Tycoon Deluxe オリジナル版 効果音 (Windows) description.ko_KR = 오리지널 트랜스포트 타이쿤 디럭스 윈도 에디션의 효과음입니다. description.la_VA = Soni ex editione originale Transport Tycoon Deluxe Windows. description.lb_LU = Original Transport Tycoon Deluxe Windows Editioun Sound. description.lt_LT = Originalūs Transport Tycoon Deluxe Windows leidimo garsai. description.nb_NO = Originale lyder fra Transport Tycoon Deluxe for Windows. description.nl_NL = Originele geluiden van de Transport Tycoon Deluxe Windows-versie. description.nn_NO = Originale lydar frå Transport Tycoon Deluxe for Windows. description.pl_PL = Oryginalna edycja dźwięków dla Transport Tycoon Deluxe Windows. description.pt_BR = Sons Originais do Transport Tycoon Deluxe, Edição Windows. description.pt_PT = Sons originais da edição Windows de Transport Tycoon Deluxe. description.ro_RO = Setul de sunete original al Transport Tycoon Deluxe pentru Windows. description.ru_RU = Оригинальный набор звукового оформления из игры Transport Tycoon Deluxe для Windows. description.sk_SK = Pôvodné zvuky Transport Tycoon Deluxe (Windows). description.sl_SI = Originalni zvoki Transport Tycoon Deluxe različice oken(windows). description.sr_RS = Originalni skup zvukova Transport Tycoon Deluxe Windows izdanja. description.sv_SE = Originalljuden från Transport Tycoon Deluxe, Windows-utgåvan. description.ta_IN = அசல் டிரான்ஸ்ஃபோர்ட் டைகூன் டீலக்ஸ் விண்டோஸ் பதிப்பு ஒலிகள். description.th_TH = เสียงต้นตำหรับของ Transport Tycoon Deluxe Windows edition description.tr_TR = Özgün Transport Tycoon Deluxe Windows sürümü sesleri. description.uk_UA = Оригінальний набір звуків з Transport Tycoon Deluxe Windows edition. description.vi_VN = Âm thanh gốc từ phiên bản Transport Tycoon Deluxe trên Windows description.zh_CN = Transport Tycoon Deluxe Windows (运输大亨Windows豪华版)的原版音效包. description.zh_TW = 原版 Transport Tycoon Deluxe Windows 版的音效。 [files] samples = SAMPLE.CAT [md5s] SAMPLE.CAT = 9212e81e72badd4bbe1eaeae66458e10 [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. openttd-1.5.3/findversion.sh0000755000000000000000000001241512627373446014601 0ustar rootroot#!/bin/sh # $Id: findversion.sh 27079 2014-12-11 12:25:53Z planetmaker $ # 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 . # Arguments given? Show help text. if [ "$#" != "0" ]; then cat <\t\t\t REV a string describing what version of the code the current checkout is based on. The exact format of this string depends on the version control system in use, but it tries to identify the revision used as close as possible (using the svn revision number or hg/git hash). This also includes an indication of whether the checkout was modified and which branch was checked out. This value is not guaranteed to be sortable, but is mainly meant for identifying the revision and user display. If no revision identifier could be found, this is left empty. REV_NR the revision number of the svn revision this checkout is based on. This can be used to determine which functionality is present in this checkout. For trunk svn checkouts and hg/git branches based upon it, this number should be accurate. For svn branch checkouts, this number is mostly meaningless, at least when comparing with the REV_NR from other branches or trunk. This number should be sortable. Within a given branch or trunk, a higher number means a newer version. However, when using git or hg, this number will not increase on new commits. If no revision number could be found, this is left empty. MODIFIED Whether (the src directory of) this checkout is modified or not. A value of 0 means not modified, a value of 2 means it was modified. Modification is determined in relation to the commit identified by REV, so not in relation to the svn revision identified by REV_NR. A value of 1 means that the modified status is unknown, because this is not an svn/git/hg checkout for example. CLEAN_REV the same as REV but without branch name By setting the AWK environment variable, a caller can determine which version of "awk" is used. If nothing is set, this script defaults to "awk". EOF exit 1; fi # Allow awk to be provided by the caller. if [ -z "$AWK" ]; then AWK=awk fi # Find out some dirs cd `dirname "$0"` ROOT_DIR=`pwd` # Determine if we are using a modified version # Assume the dir is not modified MODIFIED="0" if [ -d "$ROOT_DIR/.svn" ] || [ -d "$ROOT_DIR/../.svn" ]; then # We are an svn checkout if [ -n "`svnversion | grep 'M'`" ]; then MODIFIED="2" fi # Find the revision like: rXXXXM-branch BRANCH=`LC_ALL=C svn info | "$AWK" '/^URL:.*branches/ { split($2, a, "/"); for(i in a) if (a[i]=="branches") { print a[i+1]; break } }'` TAG=`LC_ALL=C svn info | "$AWK" '/^URL:.*tags/ { split($2, a, "/"); for(i in a) if (a[i]=="tags") { print a[i+1]; break } }'` REV_NR=`LC_ALL=C svn info | "$AWK" '/^Last Changed Rev:/ { print $4 }'` if [ -n "$TAG" ]; then REV=$TAG else REV="r$REV_NR" fi elif [ -d "$ROOT_DIR/.git" ]; then # We are a git checkout # Refresh the index to make sure file stat info is in sync, then look for modifications git update-index --refresh >/dev/null if [ -n "`git diff-index HEAD`" ]; then MODIFIED="2" fi HASH=`LC_ALL=C git rev-parse --verify HEAD 2>/dev/null` REV="g`echo $HASH | cut -c1-8`" BRANCH="`git symbolic-ref -q HEAD 2>/dev/null | sed 's@.*/@@;s@^master$@@'`" REV_NR=`LC_ALL=C git log --pretty=format:%s --grep="^(svn r[0-9]*)" -1 | sed "s@.*(svn r\([0-9]*\)).*@\1@"` if [ -z "$REV_NR" ]; then # No rev? Maybe it is a custom git-svn clone REV_NR=`LC_ALL=C git log --pretty=format:%b --grep="git-svn-id:.*@[0-9]*" -1 | sed "s@.*\@\([0-9]*\).*@\1@"` fi TAG="`git name-rev --name-only --tags --no-undefined HEAD 2>/dev/null | sed 's@\^0$@@'`" if [ -n "$TAG" ]; then BRANCH="" REV="$TAG" fi elif [ -d "$ROOT_DIR/.hg" ]; then # We are a hg checkout if [ -n "`HGPLAIN= hg status | grep -v '^?'`" ]; then MODIFIED="2" fi HASH=`LC_ALL=C HGPLAIN= hg id -i | cut -c1-12` REV="h`echo $HASH | cut -c1-8`" BRANCH="`HGPLAIN= hg branch | sed 's@^default$@@'`" TAG="`HGPLAIN= hg id -t | grep -v 'tip$'`" if [ -n "$TAG" ]; then BRANCH="" REV="$TAG" fi REV_NR=`LC_ALL=C HGPLAIN= hg log -f -k "(svn r" -l 1 --template "{desc|firstline}\n" | grep "^(svn r[0-9]*)" | sed "s@.*(svn r\([0-9]*\)).*@\1@"` if [ -z "$REV_NR" ]; then # No rev? Maybe it is a custom hgsubversion clone REV_NR=`LC_ALL=C HGPLAIN= hg parent --template="{svnrev}"` fi elif [ -f "$ROOT_DIR/.ottdrev" ]; then # We are an exported source bundle cat $ROOT_DIR/.ottdrev exit else # We don't know MODIFIED="1" BRANCH="" REV="" REV_NR="" fi if [ "$MODIFIED" -eq "2" ]; then REV="${REV}M" fi CLEAN_REV=${REV} if [ -n "$BRANCH" ]; then REV="${REV}-$BRANCH" fi echo "$REV $REV_NR $MODIFIED $CLEAN_REV" openttd-1.5.3/Makefile.grf.in0000644000000000000000000000713112627373446014535 0ustar rootroot# $Id: Makefile.grf.in 26708 2014-07-30 17:21:42Z rubidium $ # 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 . # # Building requires GRFCodec and NFORenum. Older versions of GRFCodec are # known to miscompile the graphics. # # Recent nightlies (including sources) of both can be found at: # http://www.openttd.org/download-grfcodec # http://www.openttd.org/download-nforenum # # The mercurial repository of both can be found at: # http://hg.openttdcoop.org/grfcodec # http://hg.openttdcoop.org/nforenum # ROOT_DIR = !!ROOT_DIR!! GRF_DIR = $(ROOT_DIR)/media/extra_grf BASESET_DIR = $(ROOT_DIR)/media/baseset LANG_DIR = $(ROOT_DIR)/src/lang BIN_DIR = !!BIN_DIR!!/baseset OBJS_DIR = !!GRF_OBJS_DIR!! OS = !!OS!! STAGE = !!STAGE!! # Check if we want to show what we are doing ifdef VERBOSE Q = E = @true else Q = @ E = @echo endif GRFCODEC := !!GRFCODEC!! NFORENUM := !!NFORENUM!! CC_BUILD := !!CC_BUILD!! MD5SUM := $(shell [ "$(OS)" = "OSX" ] && echo "md5 -r" || echo "md5sum") # Some "should not be changed" settings. NFO_FILES := $(GRF_DIR)/*.nfo $(GRF_DIR)/rivers/*.nfo PNG_FILES := $(GRF_DIR)/*.png $(GRF_DIR)/rivers/*.png # Build the GRF. ifdef GRFCODEC all: $(BIN_DIR)/openttd.grf $(BIN_DIR)/orig_dos.obg $(BIN_DIR)/orig_dos_de.obg $(BIN_DIR)/orig_win.obg $(BIN_DIR)/orig_dos.obs $(BIN_DIR)/orig_win.obs $(BIN_DIR)/no_sound.obs $(BIN_DIR)/orig_win.obm $(BIN_DIR)/no_music.obm else all: endif # Make sure the sprites directory exists. $(OBJS_DIR)/sprites: $(Q)-mkdir "$@" $(OBJS_DIR)/langfiles.tmp: $(LANG_DIR)/*.txt $(E) '$(STAGE) Collecting baseset translations' $(Q) cat $^ > $@ $(BIN_DIR)/%.obg: $(BASESET_DIR)/%.obg $(BIN_DIR)/openttd.grf $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk $(E) '$(STAGE) Updating $(notdir $@)' $(Q) sed 's/^OPENTTD.GRF = *[0-9a-f]*$$/OPENTTD.GRF = '`$(MD5SUM) $(BIN_DIR)/openttd.grf | sed 's@ .*@@'`'/' $< > $@.tmp $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $@.tmp >$@ $(Q) rm $@.tmp $(BIN_DIR)/%.obs: $(BASESET_DIR)/%.obs $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk $(E) '$(STAGE) Updating $(notdir $@)' $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $< >$@ $(BIN_DIR)/%.obm: $(BASESET_DIR)/%.obm $(OBJS_DIR)/langfiles.tmp $(BASESET_DIR)/translations.awk $(E) '$(STAGE) Updating $(notdir $@)' $(Q) awk -v langfiles='$(OBJS_DIR)/langfiles.tmp' -f $(BASESET_DIR)/translations.awk $< >$@ # Compile extra grf $(BIN_DIR)/openttd.grf: $(PNG_FILES) $(NFO_FILES) $(OBJS_DIR)/sprites $(GRF_DIR)/assemble_nfo.awk $(E) '$(STAGE) Assembling openttd.nfo' $(Q)-cp $(PNG_FILES) $(OBJS_DIR)/sprites 2> /dev/null $(Q) awk -f $(GRF_DIR)/assemble_nfo.awk $(GRF_DIR)/openttd.nfo > $(OBJS_DIR)/sprites/openttd.nfo $(Q) $(NFORENUM) -s $(OBJS_DIR)/sprites/openttd.nfo $(E) '$(STAGE) Compiling openttd.grf' $(Q) $(GRFCODEC) -n -s -e -p1 $(OBJS_DIR)/openttd.grf $(Q)cp $(OBJS_DIR)/openttd.grf $(BIN_DIR)/openttd.grf # Clean up temporary files. clean: $(Q)rm -f *.bak *.grf # Clean up temporary files mrproper: clean $(Q)rm -fr sprites .PHONY: all mrproper depend clean openttd-1.5.3/projects/0000755000000000000000000000000012627373446013542 5ustar rootrootopenttd-1.5.3/projects/openttd_vs100.vcxproj.filters.in0000644000000000000000000000051112627373446021636 0ustar rootroot !!FILTERS!! !!FILES!! openttd-1.5.3/projects/openttd_vs90.vcproj0000644000000000000000000025044412627373446017336 0ustar rootroot openttd-1.5.3/projects/settingsgen_vs80.vcproj0000644000000000000000000000477512627373446020216 0ustar rootroot openttd-1.5.3/projects/strgen_vs100.vcxproj.filters0000644000000000000000000000242712627373446021066 0ustar rootroot {5894294c-d4dc-41f0-be31-e56cff4e0405} cpp;c;cxx;rc;def;r;odl;idl;hpj;bat Source Files Source Files Source Files Source Files Source Files openttd-1.5.3/projects/settings_vs90.vcproj0000644000000000000000000000364012627373446017513 0ustar rootroot openttd-1.5.3/projects/openttd_vs100.vcxproj.filters0000644000000000000000000032504112627373446021241 0ustar rootroot {c76ff9f1-1e62-46d8-8d55-000000000000} {c76ff9f1-1e62-46d8-8d55-000000000001} {c76ff9f1-1e62-46d8-8d55-000000000002} {c76ff9f1-1e62-46d8-8d55-000000000003} {c76ff9f1-1e62-46d8-8d55-000000000004} {c76ff9f1-1e62-46d8-8d55-000000000005} {c76ff9f1-1e62-46d8-8d55-000000000006} {c76ff9f1-1e62-46d8-8d55-000000000007} {c76ff9f1-1e62-46d8-8d55-000000000008} {c76ff9f1-1e62-46d8-8d55-000000000009} {c76ff9f1-1e62-46d8-8d55-000000000010} {c76ff9f1-1e62-46d8-8d55-000000000011} {c76ff9f1-1e62-46d8-8d55-000000000012} {c76ff9f1-1e62-46d8-8d55-000000000013} {c76ff9f1-1e62-46d8-8d55-000000000014} {c76ff9f1-1e62-46d8-8d55-000000000015} {c76ff9f1-1e62-46d8-8d55-000000000016} {c76ff9f1-1e62-46d8-8d55-000000000017} {c76ff9f1-1e62-46d8-8d55-000000000018} {c76ff9f1-1e62-46d8-8d55-000000000019} {c76ff9f1-1e62-46d8-8d55-000000000020} {c76ff9f1-1e62-46d8-8d55-000000000021} {c76ff9f1-1e62-46d8-8d55-000000000022} {c76ff9f1-1e62-46d8-8d55-000000000023} {c76ff9f1-1e62-46d8-8d55-000000000024} {c76ff9f1-1e62-46d8-8d55-000000000025} {c76ff9f1-1e62-46d8-8d55-000000000026} {c76ff9f1-1e62-46d8-8d55-000000000027} {c76ff9f1-1e62-46d8-8d55-000000000028} {c76ff9f1-1e62-46d8-8d55-000000000029} {c76ff9f1-1e62-46d8-8d55-000000000030} {c76ff9f1-1e62-46d8-8d55-000000000031} {c76ff9f1-1e62-46d8-8d55-000000000032} Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code Core Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code GUI Source Code Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Widgets Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Command handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Save/Load handlers Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables Tables MD5 MD5 Script Script Script Script Script Script Script Script Script Script Script Script Script Script Script Script Script Script Script Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers Squirrel headers AI Core AI Core AI Core AI Core AI Core AI Core AI Core AI Core AI Core AI Core AI Core AI Core AI API Game API Game Core Game Core Game Core Game Core Game Core Game Core Game Core Game Core Game Core Game Core Game Core Game Core Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Script API Implementation Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Blitters Drivers Drivers Drivers Sprite loaders Sprite loaders Sprite loaders NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF NewGRF Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Map Accessors Misc Misc Misc Misc Misc Misc Misc Misc Misc Misc Misc Misc Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Network Core Pathfinder Pathfinder Pathfinder Pathfinder Pathfinder Pathfinder NPF NPF NPF NPF NPF NPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF YAPF Video Video Video Video Music Music Music Sound Sound Sound Windows files Windows files Windows files Threading Threading openttd-1.5.3/projects/strgen_vs80.vcproj0000644000000000000000000000627412627373446017162 0ustar rootroot openttd-1.5.3/projects/langs_vs100.vcxproj0000644000000000000000000011055712627373446017225 0ustar rootroot Debug Win32 langs {0F066B23-18DF-4284-8265-F4A5E7E3B966} langs MakeFileProj Utility false <_ProjectFileVersion>10.0.30319.1 ..\bin\lang\ ..\objs\langs\ Generating strings.h ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\objs\langs\table ./langs.tlb Generating english language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\english.lng;%(Outputs) Generating afrikaans language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\afrikaans.lng;%(Outputs) Generating arabic_egypt language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\arabic_egypt.lng;%(Outputs) Generating basque language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\basque.lng;%(Outputs) Generating belarusian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\belarusian.lng;%(Outputs) Generating brazilian_portuguese language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\brazilian_portuguese.lng;%(Outputs) Generating bulgarian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\bulgarian.lng;%(Outputs) Generating catalan language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\catalan.lng;%(Outputs) Generating croatian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\croatian.lng;%(Outputs) Generating czech language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\czech.lng;%(Outputs) Generating danish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\danish.lng;%(Outputs) Generating dutch language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\dutch.lng;%(Outputs) Generating english_AU language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\english_AU.lng;%(Outputs) Generating english_US language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\english_US.lng;%(Outputs) Generating esperanto language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\esperanto.lng;%(Outputs) Generating estonian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\estonian.lng;%(Outputs) Generating faroese language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\faroese.lng;%(Outputs) Generating finnish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\finnish.lng;%(Outputs) Generating french language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\french.lng;%(Outputs) Generating gaelic language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\gaelic.lng;%(Outputs) Generating galician language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\galician.lng;%(Outputs) Generating german language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\german.lng;%(Outputs) Generating greek language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\greek.lng;%(Outputs) Generating hebrew language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\hebrew.lng;%(Outputs) Generating hungarian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\hungarian.lng;%(Outputs) Generating icelandic language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\icelandic.lng;%(Outputs) Generating indonesian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\indonesian.lng;%(Outputs) Generating irish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\irish.lng;%(Outputs) Generating italian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\italian.lng;%(Outputs) Generating japanese language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\japanese.lng;%(Outputs) Generating korean language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\korean.lng;%(Outputs) Generating latin language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\latin.lng;%(Outputs) Generating latvian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\latvian.lng;%(Outputs) Generating lithuanian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\lithuanian.lng;%(Outputs) Generating luxembourgish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\luxembourgish.lng;%(Outputs) Generating malay language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\malay.lng;%(Outputs) Generating norwegian_bokmal language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\norwegian_bokmal.lng;%(Outputs) Generating norwegian_nynorsk language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\norwegian_nynorsk.lng;%(Outputs) Generating polish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\polish.lng;%(Outputs) Generating portuguese language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\portuguese.lng;%(Outputs) Generating romanian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\romanian.lng;%(Outputs) Generating russian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\russian.lng;%(Outputs) Generating serbian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\serbian.lng;%(Outputs) Generating simplified_chinese language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\simplified_chinese.lng;%(Outputs) Generating slovak language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\slovak.lng;%(Outputs) Generating slovenian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\slovenian.lng;%(Outputs) Generating spanish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\spanish.lng;%(Outputs) Generating swedish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\swedish.lng;%(Outputs) Generating tamil language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\tamil.lng;%(Outputs) Generating thai language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\thai.lng;%(Outputs) Generating traditional_chinese language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\traditional_chinese.lng;%(Outputs) Generating turkish language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\turkish.lng;%(Outputs) Generating ukrainian language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\ukrainian.lng;%(Outputs) Generating vietnamese language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\vietnamese.lng;%(Outputs) Generating welsh language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\welsh.lng;%(Outputs) {a133a442-bd0a-4ade-b117-ad7545e4bdd1} false openttd-1.5.3/projects/openttd_vs100.vcxproj0000644000000000000000000021652512627373446017600 0ustar rootroot Debug Win32 Debug x64 Release Win32 Release x64 openttd {668328A0-B40E-4CDB-BD72-D0064424414A} openttd Application false Unicode Application false Unicode true Application false Unicode Application false Unicode true <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ false $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ false $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ AllRules.ruleset AllRules.ruleset AllRules.ruleset AllRules.ruleset $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(ProjectDir)..\bin .\Release/openttd.tlb /MP /J %(AdditionalOptions) Full AnySuitable true Size true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) true Sync MultiThreaded 4Bytes false true All $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true ProgramDatabase FastCall Default NDEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true %(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 true false MachineX86 true .\Debug/openttd.tlb /MP %(AdditionalOptions) Disabled ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true EditAndContinue FastCall Default _DEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 false MachineX86 X64 .\Release/openttd.tlb /MP /J %(AdditionalOptions) Full AnySuitable true Size true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) true Sync MultiThreaded Default false true All $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true ProgramDatabase FastCall Default NDEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true %(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 true MachineX64 true X64 .\Debug/openttd.tlb /MP %(AdditionalOptions) Disabled ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true ProgramDatabase Cdecl Default _DEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 MachineX64 {0f066b23-18df-4284-8265-f4a5e7e3b966} false {a133a442-bd0a-4ade-b117-ad7545e4bdd1} false {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} false openttd-1.5.3/projects/openttd_vs80.vcproj.user0000644000000000000000000000123012627373446020275 0ustar rootroot openttd-1.5.3/projects/openttd_vs100.sln0000644000000000000000000001346012627373446016672 0ustar rootrootMicrosoft 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 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs100.vcxproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs100.vcxproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" 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 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.Build.0 = Debug|Win32 {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|Win32.ActiveCfg = Debug|Win32 {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 EndGlobalSection GlobalSection(DPCodeReviewSolutionGUID) = preSolution DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} EndGlobalSection EndGlobal openttd-1.5.3/projects/settings_vs100.vcxproj.in0000644000000000000000000000470112627373446020357 0ustar rootroot 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!! openttd-1.5.3/projects/generate0000755000000000000000000002531212627373446015265 0ustar rootroot#!/bin/bash # $Id: generate 27152 2015-02-15 14:56:21Z frosch $ # 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 . # This file generates all project files based on sources.list, so everyone who # can start a bash process, can update the project files. ROOT_DIR="`pwd`/.." if ! [ -e "$ROOT_DIR/source.list" ] then ROOT_DIR="`pwd`" fi if ! [ -e "$ROOT_DIR/source.list" ] then echo "Can't find source.list, needed in order to make this run. Please go to either" echo " the project dir, or the root dir of a clean SVN checkout." exit 1 fi # openttd_vs100.sln is for MSVC 2010 # openttd_vs100.vcxproj is for MSVC 2010 # openttd_vs100.vcxproj.filters is for MSVC 2010 # langs_vs100.vcxproj is for MSVC 2010 # strgen_vs100.vcxproj is for MSVC 2010 # strgen_vs100.vcxproj.filters is for MSVC 2010 # generate_vs100.vcxproj is for MSVC 2010 # version_vs100.vcxproj is for MSVC 2010 # openttd_vs90.sln is for MSVC 2008 # openttd_vs90.vcproj is for MSVC 2008 # langs_vs90.vcproj is for MSVC 2008 # strgen_vs90.vcproj is for MSVC 2008 # generate_vs90.vcproj is for MSVC 2008 # version_vs90.vcproj is for MSVC 2008 # openttd_vs80.sln is for MSVC 2005 # openttd_vs80.vcproj is for MSVC 2005 # langs_vs80.vcproj is for MSVC 2005 # strgen_vs80.vcproj is for MSVC 2005 # generate_vs80.vcproj is for MSVC 2005 # version_vs80.vcproj is for MSVC 2005 # First, collect the list of Windows files allegro_config="" sdl_config="1" png_config="1" os="MSVC" enable_dedicated="0" enable_ai="1" with_cocoa="0" enable_directmusic="1" with_threads="1" file_prefix="..\\\\src\\\\" safety_check() { li="" for i in `cat $1 | grep -v "#\|ottdres.rc\|win32.cpp\|win32_v.cpp" | xargs -n 1 basename | sort`; do if [ "$li" = "$i" ]; then echo " !! ERROR !!" echo "" echo "The filename '$i' is already used in this project." echo "Because MSVC uses one single directory for all object files, it" echo "cannot handle filenames with the same name inside the same project." echo "Please rename either one of the file and try generating again." echo "" echo " !! ERROR !!" exit 1 fi li="$i" done } grep '\.h' "$ROOT_DIR/source.list" | grep -v '../objs/langs/table/strings.h\|../objs/settings/table/settings.h' | sed 's/ //g' | 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." diff tmp.headers.source.list tmp.headers.src | grep '[<>]' | sort echo "" fi rm tmp.headers.* load_main_data() { # Read the source.list and process it RES="`cat $1 | tr '\r' '\n' | awk ' /^( *)#end/ { if (deep == skip) { skip -= 1; } deep -= 1; next; } /^( *)#else/ { if (deep == skip) { skip -= 1; } else if (deep - 1 == skip) { skip += 1; } next; } /^( *)#if/ { gsub(" ", "", $0); gsub("^#if", "", $0); gsub("^ ", "", $0); if (deep != skip) { deep += 1; next; } deep += 1; if ($0 == "ALLEGRO" && "'$allegro_config'" == "") { next; } if ($0 == "SDL" && "'$sdl_config'" == "") { next; } if ($0 == "PNG" && "'$png_config'" == "") { next; } if ($0 == "OSX" && "'$os'" != "OSX") { next; } if ($0 == "OS2" && "'$os'" != "OS2") { next; } if ($0 == "PSP" && "'$os'" != "PSP") { next; } if ($0 == "DOS" && "'$os'" != "DOS") { next; } if ($0 == "DEDICATED" && "'$enable_dedicated'" != "1") { next; } if ($0 == "AI" && "'$enable_ai'" == "0") { next; } if ($0 == "COCOA" && "'$with_cocoa'" == "0") { next; } if ($0 == "BEOS" && "'$os'" != "BEOS") { next; } if ($0 == "WIN32" && "'$os'" != "MINGW" && "'$os'" != "CYGWIN" && "'$os'" != "MSVC" ) { next; } if ($0 == "WINCE" && "'$os'" != "WINCE") { next; } if ($0 == "MSVC" && "'$os'" != "MSVC") { next; } if ($0 == "DIRECTMUSIC" && "'$enable_directmusic'" != "1") { next; } if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; } if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; } skip += 1; next; } /^( *)#/ { if (deep == skip) { gsub(" ", "", $0); gsub("^#", "", $0); gsub("^ ", "", $0); if (first_time != 0) { print "#1 "; } else { first_time = 1; } filter = $0; print "#1 "; print "#3 "; printf "#3 {c76ff9f1-1e62-46d8-8d55-%012d}\n", i; print "#3 "; i += 1; } next; } /^$/ { next } { if (deep == skip) { gsub(" ", "", $0); gsub("/", "\\\\", $0); print "#1 "; print "#1 "; split($0, file, "."); cltype = "ClInclude" if (file[2] == "cpp") cltype = "ClCompile"; if (file[2] == "rc") cltype = "ResourceCompile"; print "#2 <"cltype" Include=\\"'$file_prefix'"$0"\\" />"; print "#4 <"cltype" Include=\\"'$file_prefix'"$0"\\">"; print "#4 "filter""; print "#4 "; } } END { print "#1 "; } '`" eval "$2=\"\$RES\"" } load_lang_data() { RES="" for i in `ls $1` do i=`basename $i | sed s~.txt$~~g` if [ "$i" == "english" ] then continue fi RES="$RES #1 #1 #1 #1 #1 #2 #2 Generating "$i" language file #2 ..\\objs\\strgen\\strgen.exe -s ..\\src\\lang -d ..\\bin\\lang \"%(FullPath)\" #2 ..\\src\\lang\\english.txt;..\\objs\\strgen\\strgen.exe;%(AdditionalInputs) #2 ..\\bin\\lang\\"$i".lng;%(Outputs) #2 #3 #3 Translations #3 " done 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 # Everything above the !!FILTERS!! marker cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' /^$/ { next } /!!FILTERS!!/ { stop = 1; } { if (stop == 0) { print $0 } } ' > "$ROOT_DIR/projects/$2" echo "$3" >> "$ROOT_DIR/projects/$2" # Everything below the !!FILTERS!! marker and above the !!FILES!! marker cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' BEGIN { stop = 1; } /^$/ { next } /!!FILTERS!!/ { stop = 2; } /!!FILES!!/ { stop = 1; } { if (stop == 0) { print $0 } if (stop == 2) { stop = 0 } } ' >> "$ROOT_DIR/projects/$2" else # Everything above the !!FILES!! marker cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' /^$/ { next } /!!FILES!!/ { stop = 1; } { if (stop == 0) { print $0 } } ' > "$ROOT_DIR/projects/$2" fi echo "$1" >> "$ROOT_DIR/projects/$2" # Everything below the !!FILES!! marker cat "$ROOT_DIR/projects/$2".in | tr '\r' '\n' | awk ' BEGIN { stop = 1; } /^$/ { next } /!!FILES!!/ { stop = 2; } { if (stop == 0) { print $0 } if (stop == 2) { stop = 0 } } ' >> "$ROOT_DIR/projects/$2" } safety_check "$ROOT_DIR/source.list" load_main_data "$ROOT_DIR/source.list" openttd openttdfiles=`echo "$openttd" | grep "^#4" | sed "s~#4~~g"` openttdfilters=`echo "$openttd" | grep "^#3" | sed "s~#3~~g"` openttdvcxproj=`echo "$openttd" | grep "^#2" | sed "s~#2~~g"` openttd=`echo "$openttd" | grep "^#1" | sed "s~#1~~g"` load_lang_data "$ROOT_DIR/src/lang/*.txt" lang langfiles=`echo "$lang" | grep "^#3" | sed "s~#3~~g"` 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" generate "$openttdfiles" "openttd_vs100.vcxproj.filters" "$openttdfilters" generate "$lang" "langs_vs80.vcproj" generate "$lang" "langs_vs90.vcproj" generate "$langvcxproj" "langs_vs100.vcxproj" generate "$langfiles" "langs_vs100.vcxproj.filters" generate "$settings" "settings_vs80.vcproj" "$settingscommand" generate "$settings" "settings_vs90.vcproj" "$settingscommand" generate "$settingsvcxproj" "settings_vs100.vcxproj" "$settingscommand" generate "$settingsfiles" "settings_vs100.vcxproj.filters" openttd-1.5.3/projects/settings_vs100.vcxproj.filters0000644000000000000000000000212612627373446021420 0ustar rootroot {21deca6c-8df4-4f34-9dad-17d7781cd5a0} INI INI INI INI INI INI INI openttd-1.5.3/projects/settingsgen_vs100.vcxproj0000644000000000000000000000710212627373446020442 0ustar rootroot 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 openttd-1.5.3/projects/strgen_vs100.vcxproj0000644000000000000000000001106012627373446017410 0ustar rootroot Debug Win32 strgen {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} strgen Application false MultiByte <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)..\objs\strgen\ $(SolutionDir)..\objs\strgen\ false AllRules.ruleset .\Debug/strgen.tlb /MP %(AdditionalOptions) MinSpace Size STRGEN;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) Default MultiThreadedDebug All $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 true true ProgramDatabase _DEBUG;%(PreprocessorDefinitions) 0x041d true true $(IntDir)strgen.pdb Console false MachineX86 openttd-1.5.3/projects/settingsgen_vs90.vcproj0000644000000000000000000000503212627373446020202 0ustar rootroot openttd-1.5.3/projects/openttd_vs90.vcproj.in0000644000000000000000000002646212627373446017744 0ustar rootroot !!FILES!! openttd-1.5.3/projects/generate_vs90.vcproj0000644000000000000000000000212312627373446017440 0ustar rootroot openttd-1.5.3/projects/openttd_vs100.vcxproj.in0000644000000000000000000004405212627373446020177 0ustar rootroot Debug Win32 Debug x64 Release Win32 Release x64 openttd {668328A0-B40E-4CDB-BD72-D0064424414A} openttd Application false Unicode Application false Unicode true Application false Unicode Application false Unicode true <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ false $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ false $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ AllRules.ruleset AllRules.ruleset AllRules.ruleset AllRules.ruleset $(SolutionDir)..\objs\$(Platform)\$(Configuration)\ $(ProjectDir)..\bin .\Release/openttd.tlb /MP /J %(AdditionalOptions) Full AnySuitable true Size true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) true Sync MultiThreaded 4Bytes false true All $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true ProgramDatabase FastCall Default NDEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true %(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 true false MachineX86 true .\Debug/openttd.tlb /MP %(AdditionalOptions) Disabled ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;WIN32_ENABLE_DIRECTMUSIC_SUPPORT;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true EditAndContinue FastCall Default _DEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 false MachineX86 X64 .\Release/openttd.tlb /MP /J %(AdditionalOptions) Full AnySuitable true Size true ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) true Sync MultiThreaded Default false true All $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true ProgramDatabase FastCall Default NDEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true %(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 true MachineX64 true X64 .\Debug/openttd.tlb /MP %(AdditionalOptions) Disabled ..\objs\langs;..\objs\settings;..\src\3rdparty\squirrel\include;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_CONSOLE;WITH_SSE;WITH_ZLIB;WITH_LZO;WITH_LZMA;LZMA_API_STATIC;WITH_PNG;WITH_FREETYPE;WITH_ICU;U_STATIC_IMPLEMENTATION;ENABLE_NETWORK;WITH_PERSONAL_DIR;PERSONAL_DIR="OpenTTD";_SQ64;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug $(IntDir) $(IntDir) $(IntDir)$(TargetName).pdb Level3 false true ProgramDatabase Cdecl Default _DEBUG;%(PreprocessorDefinitions) 0x0809 winmm.lib;ws2_32.lib;imm32.lib;libpng.lib;zlibstat.lib;lzo2.lib;liblzma.lib;libfreetype2.lib;icuuc.lib;icuin.lib;icudt.lib;icule.lib;iculx.lib;%(AdditionalDependencies) true LIBCMT.lib;%(IgnoreSpecificDefaultLibraries) true Windows 1048576 1048576 MachineX64 !!FILES!! {0f066b23-18df-4284-8265-f4a5e7e3b966} false {a133a442-bd0a-4ade-b117-ad7545e4bdd1} false {1a2b3c5e-1c23-41a5-9c9b-acba2aa75fec} false openttd-1.5.3/projects/langs_vs80.vcproj0000644000000000000000000007055712627373446016771 0ustar rootroot openttd-1.5.3/projects/generate.vbs0000755000000000000000000003332012627373446016054 0ustar rootrootOption Explicit ' $Id: generate.vbs 26227 2014-01-05 10:19:59Z zuu $ ' ' 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 . Dim FSO Set FSO = CreateObject("Scripting.FileSystemObject") ' openttd_vs100.sln is for MSVC 2010 ' openttd_vs100.vcxproj is for MSVC 2010 ' openttd_vs100.vcxproj.filters is for MSVC 2010 ' langs_vs100.vcxproj is for MSVC 2010 ' strgen_vs100.vcxproj is for MSVC 2010 ' strgen_vs100.vcxproj.filters is for MSVC 2010 ' generate_vs100.vcxproj is for MSVC 2010 ' version_vs100.vcxproj is for MSVC 2010 ' openttd_vs90.sln is for MSVC 2008 ' openttd_vs90.vcproj is for MSVC 2008 ' langs_vs90.vcproj is for MSVC 2008 ' strgen_vs90.vcproj is for MSVC 2008 ' generate_vs90.vcproj is for MSVC 2008 ' version_vs90.vcproj is for MSVC 2008 ' openttd_vs80.sln is for MSVC 2005 ' openttd_vs80.vcproj is for MSVC 2005 ' langs_vs80.vcproj is for MSVC 2005 ' strgen_vs80.vcproj is for MSVC 2005 ' generate_vs80.vcproj is for MSVC 2005 ' version_vs80.vcproj is for MSVC 2005 Sub safety_check(filename) Dim file, line, regexp, list ' Define regexp Set regexp = New RegExp regexp.Pattern = "#|ottdres.rc|win32.cpp|win32_v.cpp" regexp.Global = True ' We use a dictionary to check duplicates Set list = CreateObject("Scripting.Dictionary") 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 Not regexp.Test(line) Then line = FSO.GetFileName(line) if list.Exists(line) Then WScript.Echo " !! ERROR !!" _ & vbCrLf & "" _ & vbCrLf & "The filename '" & line & "' is already used in this project." _ & vbCrLf & "Because MSVC uses one single directory for all object files, it" _ & vbCrLf & "cannot handle filenames with the same name inside the same project." _ & vbCrLf & "Please rename either one of the file and try generating again." _ & vbCrLf & "" _ & vbCrLf & " !! ERROR !!" WScript.Quit(1) End If list.Add line, line End If Wend file.Close End Sub Sub get_files(srcdir, dir, list) Dim file, filename Dim rekeep, reskip ' pattern for files to keep Set rekeep = New RegExp rekeep.Pattern = "\.h(pp)?$" rekeep.Global = True ' pattern for files to exclude Set reskip = New RegExp reskip.Pattern = "\.svn" reskip.Global = True For Each file in dir.Files filename = Replace(file.path, srcdir, "") ' Remove */src/ filename = Replace(filename, "\", "/") ' Replace separators If rekeep.Test(filename) And Not reskip.Test(filename) Then list.Add filename, filename End If Next End Sub Sub get_dir_files(srcdir, dir, list) Dim folder ' Get files get_files srcdir, dir, list ' Recurse in subfolders For Each folder in dir.SubFolders get_dir_files srcdir, folder, list Next End Sub Sub headers_check(filename, dir) Dim source_list_headers, src_dir_headers, regexp, line, file, str ' Define regexp for source.list parsing Set regexp = New RegExp regexp.Pattern = "\.h" regexp.Global = True ' Parse source.list and store headers in a dictionary Set source_list_headers = CreateObject("Scripting.Dictionary") 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 source_list_headers.Add line, line End If Wend file.Close() ' Get header files in /src/ Set src_dir_headers = CreateObject("Scripting.Dictionary") get_dir_files dir, FSO.GetFolder(dir), src_dir_headers ' Finding files in source.list but not in /src/ For Each line In source_list_headers If Not src_dir_headers.Exists(line) Then str = str & "< " & line & vbCrLf End If Next ' Finding files in /src/ but not in source.list For Each line In src_dir_headers If Not source_list_headers.Exists(line) Then str = str & "> " & line & vbCrLf End If Next ' Display the missing files if any If str <> "" Then str = "The following headers are missing in source.list and not in /src/ or vice versa." _ & vbCrLf & str WScript.Echo str End If End Sub Function load_main_data(filename, ByRef vcxproj, ByRef filters, ByRef files) Dim res, file, line, deep, skip, first_filter, first_file, filter, cltype, index res = "" index = 0 ' Read the source.list and process it Set file = FSO.OpenTextFile(filename, 1, 0, 0) While Not file.AtEndOfStream line = Replace(file.ReadLine, Chr(9), "") ' Remove tabs If Len(line) > 0 Then Select Case Split(line, " ")(0) Case "#end" If deep = skip Then skip = skip - 1 deep = deep - 1 Case "#else" If deep = skip Then skip = skip - 1 ElseIf deep - 1 = skip Then skip = skip + 1 End If Case "#if" line = Replace(line, "#if ", "") If deep = skip And ( _ line = "SDL" Or _ line = "PNG" Or _ line = "WIN32" Or _ line = "MSVC" Or _ line = "DIRECTMUSIC" Or _ line = "AI" Or _ line = "SSE" Or _ line = "HAVE_THREAD" _ ) Then skip = skip + 1 deep = deep + 1 Case "#" if deep = skip Then line = Replace(line, "# ", "") if first_filter <> 0 Then res = res & " " & vbCrLf filters = filters & vbCrLf Else first_filter = 1 End If filter = line res = res & _ " " & vbCrLf filters = filters & _ " " & vbCrLf & _ " {c76ff9f1-1e62-46d8-8d55-" & String(12 - Len(CStr(index)), "0") & index & "}" & vbCrLf & _ " " index = index + 1 End If Case Else If deep = skip Then line = Replace(line, "/" ,"\") if first_file <> 0 Then vcxproj = vcxproj & vbCrLf files = files & vbCrLf Else first_file = 1 End If res = res & _ " " & vbCrLf & _ " " & vbCrLf Select Case Split(Line, ".")(1) Case "cpp" cltype = "ClCompile" Case "rc" cltype = "ResourceCompile" Case Else cltype = "ClInclude" End Select vcxproj = vcxproj & " <" & cltype & " Include="& Chr(34) & "..\src\" & line & Chr(34) & " />" files = files & _ " <" & cltype & " Include="& Chr(34) & "..\src\" & line & Chr(34) & ">" & vbCrLf & _ " " & filter & "" & vbCrLf & _ " " End If End Select End If Wend res = res & " " file.Close() load_main_data = res End Function Function load_lang_data(dir, ByRef vcxproj, ByRef files) Dim res, folder, file, first_time res = "" Set folder = FSO.GetFolder(dir) For Each file In folder.Files file = FSO.GetFileName(file) If file <> "english.txt" And FSO.GetExtensionName(file) = "txt" Then file = Left(file, Len(file) - 4) If first_time <> 0 Then res = res & vbCrLf vcxproj = vcxproj & vbCrLf files = files & vbCrLf Else first_time = 1 End If res = res & _ " " & vbCrLf & _ " " & vbCrLf & _ " " & vbCrLf & _ " " & vbCrLf & _ " " vcxproj = vcxproj & _ " " & vbCrLf & _ " Generating " & file & " language file" & vbCrLf & _ " ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang " & Chr(34) & "%(FullPath)" & Chr(34) & "" & vbCrLf & _ " ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs)" & vbCrLf & _ " ..\bin\lang\" & file & ".lng;%(Outputs)" & vbCrLf & _ " " files = files & _ " " & vbCrLf & _ " Translations" & vbCrLf & _ " " End If Next 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) & "..." Set srcfile = FSO.OpenTextFile(dest & ".in", 1, 0, 0) Set destfile = FSO.CreateTextFile(dest, -1, 0) If Not IsNull(data2) Then ' Everything above the !!FILTERS!! marker line = srcfile.ReadLine() While line <> "!!FILTERS!!" If len(line) > 0 Then destfile.WriteLine(line) line = srcfile.ReadLine() Wend ' Our generated content destfile.WriteLine(data2) End If ' Everything above the !!FILES!! marker line = srcfile.ReadLine() While line <> "!!FILES!!" If len(line) > 0 Then destfile.WriteLine(line) line = srcfile.ReadLine() Wend ' Our generated content destfile.WriteLine(data) ' Everything below the !!FILES!! marker While Not srcfile.AtEndOfStream line = srcfile.ReadLine() If len(line) > 0 Then destfile.WriteLine(line) Wend srcfile.Close() destfile.Close() End Sub Dim ROOT_DIR ROOT_DIR = FSO.GetFolder("..").Path If Not FSO.FileExists(ROOT_DIR & "/source.list") Then ROOT_DIR = FSO.GetFolder(".").Path End If If Not FSO.FileExists(ROOT_DIR & "/source.list") Then WScript.Echo "Can't find source.list, needed in order to make this run." _ & vbCrLf & "Please go to either the project dir, or the root dir of a clean SVN checkout." WScript.Quit(1) End If safety_check ROOT_DIR & "/source.list" headers_check ROOT_DIR & "/source.list", ROOT_DIR & "\src\" ' Backslashes needed for DoFiles Dim openttd, openttdvcxproj, openttdfilters, openttdfiles openttd = load_main_data(ROOT_DIR & "/source.list", openttdvcxproj, openttdfilters, openttdfiles) generate openttd, ROOT_DIR & "/projects/openttd_vs80.vcproj", Null generate openttd, ROOT_DIR & "/projects/openttd_vs90.vcproj", Null generate openttdvcxproj, ROOT_DIR & "/projects/openttd_vs100.vcxproj", Null generate openttdfiles, ROOT_DIR & "/projects/openttd_vs100.vcxproj.filters", openttdfilters Dim lang, langvcxproj, langfiles lang = load_lang_data(ROOT_DIR & "/src/lang", langvcxproj, langfiles) 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 generate langfiles, ROOT_DIR & "/projects/langs_vs100.vcxproj.filters", 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 openttd-1.5.3/projects/langs_vs90.vcproj.in0000644000000000000000000000322612627373446017364 0ustar rootroot !!FILES!! openttd-1.5.3/projects/openttd_vs80.vcproj.in0000644000000000000000000002645312627373446017743 0ustar rootroot !!FILES!! openttd-1.5.3/projects/openttd_vs80.vcproj0000644000000000000000000025043512627373446017335 0ustar rootroot openttd-1.5.3/projects/langs_vs100.vcxproj.filters0000644000000000000000000001413712627373446020671 0ustar rootroot {2a164580-9033-4a01-974b-b21da507efda} Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations Translations openttd-1.5.3/projects/version_vs100.vcxproj0000644000000000000000000000456312627373446017605 0ustar rootroot Debug Win32 version {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} version Makefile MultiByte <_ProjectFileVersion>10.0.30319.1 $(SolutionDir)..\objs\version\ $(SolutionDir)..\objs\version\ cscript "$(ProjectDir)/determineversion.vbs" cscript "$(ProjectDir)/determineversion.vbs" ..\src\rev.cpp del ..\src\rev.cpp openttd-1.5.3/projects/version_vs90.vcproj0000644000000000000000000000176412627373446017345 0ustar rootroot openttd-1.5.3/projects/settings_vs100.vcxproj0000644000000000000000000000623612627373446017757 0ustar rootroot 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 ..\src\table\window_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 openttd-1.5.3/projects/openttd_vs90.vcproj.user0000644000000000000000000000123012627373446020276 0ustar rootroot openttd-1.5.3/projects/langs_vs100.vcxproj.in0000644000000000000000000000574112627373446017630 0ustar rootroot Debug Win32 langs {0F066B23-18DF-4284-8265-F4A5E7E3B966} langs MakeFileProj Utility false <_ProjectFileVersion>10.0.30319.1 ..\bin\lang\ ..\objs\langs\ Generating strings.h ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\objs\langs\table ./langs.tlb Generating english language file ..\objs\strgen\strgen.exe -s ..\src\lang -d ..\bin\lang "%(FullPath)" ..\src\lang\english.txt;..\objs\strgen\strgen.exe;%(AdditionalInputs) ..\bin\lang\english.lng;%(Outputs) !!FILES!! {a133a442-bd0a-4ade-b117-ad7545e4bdd1} false openttd-1.5.3/projects/version_vs80.vcproj0000644000000000000000000000172312627373446017337 0ustar rootroot openttd-1.5.3/projects/settingsgen_vs100.vcxproj.filters0000644000000000000000000000216312627373446022113 0ustar rootroot {a4678737-b3b3-4be5-9db1-fa6ccd164c59} Source Files Source Files Source Files Source Files Source Files openttd-1.5.3/projects/settings_vs80.vcproj0000644000000000000000000000357712627373446017523 0ustar rootroot openttd-1.5.3/projects/langs_vs90.vcproj0000644000000000000000000007062012627373446016761 0ustar rootroot openttd-1.5.3/projects/settings_vs100.vcxproj.filters.in0000644000000000000000000000073312627373446022027 0ustar rootroot {21deca6c-8df4-4f34-9dad-17d7781cd5a0} !!FILES!! openttd-1.5.3/projects/openttd_vs90.sln0000644000000000000000000001401412627373446016616 0ustar rootrootMicrosoft Visual Studio Solution File, Format Version 10.00 # Visual C++ Express 2008 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} {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} = {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strgen", "strgen_vs90.vcproj", "{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs90.vcproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" ProjectSection(ProjectDependencies) = postProject {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} = {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs90.vcproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" 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 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.Build.0 = Debug|Win32 {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|Win32.ActiveCfg = Debug|Win32 {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 EndGlobalSection GlobalSection(DPCodeReviewSolutionGUID) = preSolution DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} EndGlobalSection EndGlobal openttd-1.5.3/projects/generate_vs80.vcproj0000644000000000000000000000206112627373446017440 0ustar rootroot openttd-1.5.3/projects/langs_vs100.vcxproj.filters.in0000644000000000000000000000061112627373446021266 0ustar rootroot {2a164580-9033-4a01-974b-b21da507efda} !!FILES!! openttd-1.5.3/projects/settings_vs80.vcproj.in0000644000000000000000000000204412627373446020114 0ustar rootroot !!FILES!! openttd-1.5.3/projects/langs_vs80.vcproj.in0000644000000000000000000000316512627373446017365 0ustar rootroot !!FILES!! openttd-1.5.3/projects/settings_vs90.vcproj.in0000644000000000000000000000210512627373446020113 0ustar rootroot !!FILES!! openttd-1.5.3/projects/determineversion.vbs0000755000000000000000000003000412627373446017640 0ustar rootrootOption Explicit ' $Id: determineversion.vbs 24826 2012-12-19 02:42:25Z glx $ ' ' 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 . Dim FSO Set FSO = CreateObject("Scripting.FileSystemObject") Sub FindReplaceInFile(filename, to_find, replacement) Dim file, data Set file = FSO.OpenTextFile(filename, 1, 0, 0) data = file.ReadAll file.Close data = Replace(data, to_find, replacement) Set file = FSO.CreateTextFile(filename, -1, 0) file.Write data file.Close End Sub Sub UpdateFile(modified, revision, version, cur_date, filename) FSO.CopyFile filename & ".in", filename FindReplaceInFile filename, "!!MODIFIED!!", modified FindReplaceInFile filename, "!!REVISION!!", revision FindReplaceInFile filename, "!!VERSION!!", version FindReplaceInFile filename, "!!DATE!!", cur_date End Sub Sub UpdateFiles(version) Dim modified, revision, cur_date cur_date = DatePart("D", Date) & "." & DatePart("M", Date) & "." & DatePart("YYYY", Date) If InStr(version, Chr(9)) Then revision = Mid(version, InStr(version, Chr(9)) + 1) modified = Mid(revision, InStr(revision, Chr(9)) + 1) revision = Mid(revision, 1, InStr(revision, Chr(9)) - 1) modified = Mid(modified, 1, InStr(modified, Chr(9)) - 1) version = Mid(version, 1, InStr(version, Chr(9)) - 1) Else revision = 0 modified = 1 End If UpdateFile modified, revision, version, cur_date, "../src/rev.cpp" UpdateFile modified, revision, version, cur_date, "../src/os/windows/ottdres.rc" End Sub Function ReadRegistryKey(shive, subkey, valuename, architecture) Dim hiveKey, objCtx, objLocator, objServices, objReg, Inparams, Outparams ' First, get the Registry Provider for the requested architecture Set objCtx = CreateObject("WbemScripting.SWbemNamedValueSet") objCtx.Add "__ProviderArchitecture", architecture ' Must be 64 of 32 Set objLocator = CreateObject("Wbemscripting.SWbemLocator") Set objServices = objLocator.ConnectServer("","root\default","","",,,,objCtx) Set objReg = objServices.Get("StdRegProv") ' Check the hive and give it the right value Select Case shive Case "HKCR", "HKEY_CLASSES_ROOT" hiveKey = &h80000000 Case "HKCU", "HKEY_CURRENT_USER" hiveKey = &H80000001 Case "HKLM", "HKEY_LOCAL_MACHINE" hiveKey = &h80000002 Case "HKU", "HKEY_USERS" hiveKey = &h80000003 Case "HKCC", "HKEY_CURRENT_CONFIG" hiveKey = &h80000005 Case "HKDD", "HKEY_DYN_DATA" ' Only valid for Windows 95/98 hiveKey = &h80000006 Case Else MsgBox "Hive not valid (ReadRegistryKey)" End Select Set Inparams = objReg.Methods_("GetStringValue").Inparameters Inparams.Hdefkey = hiveKey Inparams.Ssubkeyname = subkey Inparams.Svaluename = valuename Set Outparams = objReg.ExecMethod_("GetStringValue", Inparams,,objCtx) ReadRegistryKey = Outparams.SValue End Function Function DetermineSVNVersion() Dim WshShell, version, branch, modified, revision, clean_rev, url, oExec, line, hash Set WshShell = CreateObject("WScript.Shell") On Error Resume Next revision = 0 ' Try TortoiseSVN ' Get the directory where TortoiseSVN (should) reside(s) Dim sTortoise ' First, try with 32-bit architecture sTortoise = ReadRegistryKey("HKLM", "SOFTWARE\TortoiseSVN", "Directory", 32) If sTortoise = "" Or IsNull(sTortoise) Then ' No 32-bit version of TortoiseSVN installed, try 64-bit version (doesn't hurt on 32-bit machines, it returns nothing or is ignored) sTortoise = ReadRegistryKey("HKLM", "SOFTWARE\TortoiseSVN", "Directory", 64) End If ' If TortoiseSVN is installed, try to get the revision number If sTortoise <> "" Then Dim SubWCRev Set SubWCRev = WScript.CreateObject("SubWCRev.object") SubWCRev.GetWCInfo FSO.GetAbsolutePathName("../"), 0, 0 revision = SubWCRev.Revision version = "r" & revision modified = 0 if SubWCRev.HasModifications then modified = 2 url = SubWCRev.Url End If ' Looks like there is no TortoiseSVN installed either. Then we don't know it. If revision = 0 Then ' Reset error and version Err.Clear version = "norev000" modified = 0 ' Set the environment to english WshShell.Environment("PROCESS")("LANG") = "en" ' Do we have subversion installed? Check immediatelly whether we've got a modified WC. Set oExec = WshShell.Exec("svnversion ../") If Err.Number = 0 Then ' Wait till the application is finished ... Do While oExec.Status = 0 Loop line = OExec.StdOut.ReadLine() If line <> "exported" Then If InStr(line, "M") Then modified = 2 End If ' And use svn info to get the correct revision and branch information. Set oExec = WshShell.Exec("svn info ../") If Err.Number = 0 Then Do line = OExec.StdOut.ReadLine() If InStr(line, "URL") Then url = line End If If InStr(line, "Last Changed Rev") Then revision = Mid(line, 19) version = "r" & revision End If Loop While Not OExec.StdOut.atEndOfStream End If ' Err.Number = 0 End If ' line <> "exported" End If ' Err.Number = 0 End If ' InStr(version, "$") If version <> "norev000" Then If InStr(url, "branches") Then branch = Mid(url, InStr(url, "branches/") + 9) End If If InStr(url, "tags") Then version = Mid(url, InStr(url, "tags/") + 5) End If Else ' version <> "norev000" ' svn detection failed, reset error and try git Err.Clear Set oExec = WshShell.Exec("git rev-parse --verify HEAD") If Err.Number = 0 Then ' Wait till the application is finished ... Do While oExec.Status = 0 Loop If oExec.ExitCode = 0 Then hash = oExec.StdOut.ReadLine() version = "g" & Mid(hash, 1, 8) ' Make sure index is in sync with disk Set oExec = WshShell.Exec("git update-index --refresh") If Err.Number = 0 Then ' StdOut and StdErr share a 4kB buffer so prevent it from filling up as we don't care about the output oExec.StdOut.Close oExec.StdErr.Close ' Wait till the application is finished ... Do While oExec.Status = 0 WScript.Sleep 10 Loop End If Set oExec = WshShell.Exec("git diff-index --exit-code --quiet HEAD ../") If Err.Number = 0 Then ' Wait till the application is finished ... Do While oExec.Status = 0 Loop If oExec.ExitCode = 1 Then modified = 2 End If ' oExec.ExitCode = 1 Set oExec = WshShell.Exec("git symbolic-ref HEAD") If Err.Number = 0 Then line = oExec.StdOut.ReadLine() line = Mid(line, InStrRev(line, "/") + 1) If line <> "master" Then branch = line End If ' line <> "master" End If ' Err.Number = 0 Set oExec = WshShell.Exec("git log --pretty=format:%s --grep=" & Chr(34) & "^(svn r[0-9]*)" & Chr(34) & " -1") if Err.Number = 0 Then revision = Mid(oExec.StdOut.ReadLine(), 7) revision = Mid(revision, 1, InStr(revision, ")") - 1) End If ' Err.Number = 0 If revision = "" Then ' No revision? Maybe it is a custom git-svn clone ' Reset error number as WshShell.Exec will not do that on success Err.Clear Set oExec = WshShell.Exec("git log --pretty=format:%b --grep=" & Chr(34) & "git-svn-id:.*@[0-9]*" & Chr(34) & " -1") If Err.Number = 0 Then revision = oExec.StdOut.ReadLine() revision = Mid(revision, InStr(revision, "@") + 1) revision = Mid(revision, 1, InStr(revision, " ") - 1) End If ' Err.Number = 0 End If ' revision = "" ' Check if a tag is currently checked out Err.Clear Set oExec = WshShell.Exec("git name-rev --name-only --tags --no-undefined HEAD") If Err.Number = 0 Then ' Wait till the application is finished ... Do While oExec.Status = 0 Loop If oExec.ExitCode = 0 Then version = oExec.StdOut.ReadLine() If Right(version, 2) = "^0" Then version = Left(version, Len(version) - 2) End If branch = "" End If ' oExec.ExitCode = 0 End If ' Err.Number = 0 End If ' Err.Number = 0 End If ' oExec.ExitCode = 0 End If ' Err.Number = 0 If version = "norev000" Then ' git detection failed, reset error and try mercurial (hg) Err.Clear Set oExec = WshShell.Exec("hg id -i") If Err.Number = 0 Then ' Wait till the application is finished ... Do While oExec.Status = 0 Loop If oExec.ExitCode = 0 Then line = OExec.StdOut.ReadLine() hash = Left(line, 12) version = "h" & Mid(hash, 1, 8) ' Check if a tag is currently checked out Err.Clear Set oExec = WshShell.Exec("hg id -t") If Err.Number = 0 Then line = oExec.StdOut.ReadLine() If Len(line) > 0 And Right(line, 3) <> "tip" Then version = line branch = "" End If ' Len(line) > 0 And Right(line, 3) <> "tip" End If ' Err.Number = 0 Err.Clear Set oExec = WshShell.Exec("hg status ../") If Err.Number = 0 Then Do line = OExec.StdOut.ReadLine() If Len(line) > 0 And Mid(line, 1, 1) <> "?" Then modified = 2 Exit Do End If ' Len(line) > 0 And Mid(line, 1, 1) <> "?" Loop While Not OExec.StdOut.atEndOfStream Set oExec = WshShell.Exec("hg branch") If Err.Number = 0 Then line = OExec.StdOut.ReadLine() If line <> "default" Then branch = line End If ' line <> "default" End If ' Err.Number = 0 Set oExec = WshShell.Exec("hg log -f -k " & Chr(34) & "(svn r" & Chr(34) & " -l 1 --template " & Chr(34) & "{desc|firstline}\n" & Chr(34) & " --cwd ../") If Err.Number = 0 Then line = oExec.StdOut.ReadLine() If Left(line, 6) = "(svn r" Then revision = Mid(line, 7) revision = Mid(revision, 1, InStr(revision, ")") - 1) End If 'Left(line, 6) = "(svn r" End If ' Err.Number = 0 If revision = "" Then ' No rev? Maybe it is a custom hgsubversion clone Err.Clear Set oExec = WshShell.Exec("hg parent --template=" & Chr(34) & "{svnrev}" & Chr(34)) If Err.Number = 0 Then revision = oExec.StdOut.ReadLine() End If ' Err.Number = 0 End If ' revision = "" End If ' Err.Number = 0 End If ' oExec.ExitCode = 0 End If ' Err.Number = 0 End If ' version = "norev000" End If ' version <> "norev000" If version = "norev000" And FSO.FileExists("../.ottdrev") Then Dim rev_file Set rev_file = FSO.OpenTextFile("../.ottdrev", 1, True, 0) DetermineSVNVersion = rev_file.ReadLine() rev_file.Close() Else If modified = 2 Then version = version & "M" End If clean_rev = version If branch <> "" Then version = version & "-" & branch End If If version <> "norev000" Then DetermineSVNVersion = version & Chr(9) & revision & Chr(9) & modified & Chr(9) & clean_rev Else DetermineSVNVersion = version End If End If End Function Function IsCachedVersion(ByVal version) Dim cache_file, cached_version cached_version = "" Set cache_file = FSO.OpenTextFile("../config.cache.version", 1, True, 0) If Not cache_file.atEndOfStream Then cached_version = cache_file.ReadLine() End If cache_file.Close If InStr(version, Chr(9)) Then version = Mid(version, 1, Instr(version, Chr(9)) - 1) End If If version <> cached_version Then Set cache_file = fso.CreateTextFile("../config.cache.version", True) cache_file.WriteLine(version) cache_file.Close IsCachedVersion = False Else IsCachedVersion = True End If End Function Function CheckFile(filename) CheckFile = FSO.FileExists(filename) If CheckFile Then CheckFile = (FSO.GetFile(filename).DateLastModified >= FSO.GetFile(filename & ".in").DateLastModified) End Function Dim version version = DetermineSVNVersion If Not (IsCachedVersion(version) And CheckFile("../src/rev.cpp") And CheckFile("../src/os/windows/ottdres.rc")) Then UpdateFiles version End If openttd-1.5.3/projects/openttd_vs80.sln0000644000000000000000000001401412627373446016615 0ustar rootrootMicrosoft Visual Studio Solution File, Format Version 9.00 # Visual C++ Express 2005 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} {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}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "langs", "langs_vs80.vcproj", "{0F066B23-18DF-4284-8265-F4A5E7E3B966}" ProjectSection(ProjectDependencies) = postProject {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} = {A133A442-BD0A-4ADE-B117-AD7545E4BDD1} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "version", "version_vs80.vcproj", "{1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}" 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 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|Win32.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Release|x64.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|Win32.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Debug|x64.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|Win32.Build.0 = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.ActiveCfg = Debug|Win32 {0F066B23-18DF-4284-8265-F4A5E7E3B966}.Release|x64.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|Win32.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Debug|x64.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|Win32.Build.0 = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.ActiveCfg = Debug|Win32 {1A2B3C5E-1C23-41A5-9C9B-ACBA2AA75FEC}.Release|x64.Build.0 = Debug|Win32 {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}.Debug|Win32.ActiveCfg = Debug|Win32 {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 EndGlobalSection GlobalSection(DPCodeReviewSolutionGUID) = preSolution DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000} EndGlobalSection EndGlobal openttd-1.5.3/projects/generate_vs100.vcxproj0000644000000000000000000000450012627373446017701 0ustar rootroot Debug Win32 generate {2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34} generate Utility <_ProjectFileVersion>10.0.30319.1 Document Running %27generate.vbs%27 ... cscript "$(ProjectDir)generate.vbs" %(FullPath);%(AdditionalInputs) $(SolutionDir)openttd_vs80.vcproj;$(SolutionDir)openttd_vs90.vcproj;$(SolutionDir)openttd_vs100.vcxproj;$(SolutionDir)openttd_vs100.vcxproj.filters;$(SolutionDir)langs_vs80.vcproj;$(SolutionDir)langs_vs90.vcproj;$(SolutionDir)langs_vs100.vcxproj;%(Outputs) openttd-1.5.3/projects/strgen_vs90.vcproj0000644000000000000000000000635512627373446017163 0ustar rootroot openttd-1.5.3/config.lib0000644000000000000000000034200112627373446013646 0ustar rootroot# $Id: config.lib 27462 2015-12-01 19:36:48Z frosch $ # 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 . log() { if [ $1 = "1" ]; then shift echo "$@" else shift fi echo "$@" >> $config_log } set_default() { ignore_extra_parameters="0" # We set all kinds of defaults for params. Later on the user can override # most of them; but if they don't, this default is used. build="" host="" cc_build="" cc_host="" cxx_build="" cxx_host="" windres="" strip="" lipo="" awk="awk" os="DETECT" endian="AUTO" cpu_type="DETECT" config_log="config.log" prefix_dir="/usr/local" binary_dir="games" data_dir="share/games/openttd" doc_dir="1" icon_dir="share/pixmaps" icon_theme_dir="1" personal_dir="1" shared_dir="1" install_dir="/" man_dir="1" menu_dir="1" menu_group="Game;" menu_name="OpenTTD" binary_name="openttd" enable_debug="0" enable_desync_debug="0" enable_profiling="0" enable_lto="0" enable_dedicated="0" enable_network="1" enable_static="1" enable_translator="0" enable_unicode="1" enable_console="1"; enable_assert="0" enable_strip="1" enable_universal="0" enable_osx_g5="0" enable_cocoa_quartz="1" enable_cocoa_quickdraw="1" with_osx_sysroot="1" with_application_bundle="1" with_menu_entry="1" with_allegro="1" with_sdl="1" with_cocoa="1" with_zlib="1" with_lzma="1" with_lzo2="1" with_xdg_basedir="1" with_png="1" enable_builtin_depend="1" with_makedepend="0" with_direct_music="1" with_sort="1" with_iconv="1" with_midi="" with_midi_arg="" with_libtimidity="1" with_freetype="1" with_fontconfig="1" with_icu="1" static_icu="0" with_psp_config="1" with_threads="1" with_distcc="1" with_ccache="1" with_nforenum="1" with_grfcodec="1" with_sse="1" save_params_array=" build host cc_build cc_host cxx_build cxx_host windres strip lipo awk os endian cpu_type config_log prefix_dir binary_dir data_dir doc_dir icon_dir icon_theme_dir man_dir menu_dir personal_dir shared_dir install_dir menu_group menu_name binary_name enable_debug enable_desync_debug enable_profiling enable_lto enable_dedicated enable_network enable_static enable_translator enable_unicode enable_console enable_assert enable_strip enable_universal enable_osx_g5 enable_cocoa_quartz enable_cocoa_quickdraw with_osx_sysroot with_application_bundle with_allegro with_sdl with_cocoa with_zlib with_lzma with_lzo2 with_xdg_basedir with_png enable_builtin_depend with_makedepend with_direct_music with_sort with_iconv with_midi with_midi_arg with_libtimidity with_freetype with_fontconfig with_icu static_icu with_psp_config with_threads with_distcc with_ccache with_grfcodec with_nforenum with_sse CC CXX CFLAGS CXXFLAGS LDFLAGS CFLAGS_BUILD CXXFLAGS_BUILD LDFLAGS_BUILD" } detect_params() { # Walk over all params from the user and override any default settings if # needed. This also handles any invalid option. for p in "$@"; do if [ -n "$prev_p" ]; then eval "$prev_p=\$p" prev_p= continue fi optarg=`expr "x$p" : 'x[^=]*=\(.*\)'` case "$p" in --help | -h | -\?) showhelp; exit 0;; --config-log) prev_p="config_log";; --config-log=*) config_log="$optarg";; --build) prev_p="build";; --build=*) build="$optarg";; --host) prev_p="host";; --host=*) host="$optarg";; --os) prev_p="os";; --os=*) os="$optarg";; --cpu-type) prev_p="cpu_type";; --cpu-type=*) cpu_type="$optarg";; --cc-build) prev_p="cc_build";; --cc-build=*) cc_build="$optarg";; --cc-host) prev_p="cc_host";; --cc-host=*) cc_host="$optarg";; --cxx-build) prev_p="cxx_build";; --cxx-build=*) cxx_build="$optarg";; --cxx-host) prev_p="cxx_host";; --cxx-host=*) cxx_host="$optarg";; --windres) prev_p="windres";; --windres=*) windres="$optarg";; --awk) prev_p="awk";; --awk=*) awk="$optarg";; --strip) prev_p="strip";; --strip=*) strip="$optarg";; --lipo) prev_p="lipo";; --lipo=*) lipo="$optarg";; --endian) prev_p="endian";; --endian=*) endian="$optarg";; # Alias --prefix with --prefix-dir, for compatibility with GNU autotools --prefix-dir | --prefix) prev_p="prefix_dir";; --prefix-dir=* | --prefix=*) prefix_dir="$optarg";; --binary-dir) prev_p="binary_dir";; --binary-dir=*) binary_dir="$optarg";; --data-dir) prev_p="data_dir";; --data-dir=*) data_dir="$optarg";; --doc-dir) prev_p="doc_dir";; --doc-dir=*) doc_dir="$optarg";; --icon-dir) prev_p="icon_dir";; --icon-dir=*) icon_dir="$optarg";; --icon-theme-dir) prev_p="icon_theme_dir";; --icon-theme-dir=*) icon_theme_dir="$optarg";; --without-icon-theme) icon_theme_dir="";; --menu-dir) prev_p="menu_dir";; --menu-dir=*) menu_dir="$optarg";; --without-menu-entry) menu_dir="";; --menu-name) prev_p="menu_name";; --menu-name=*) menu_name="$optarg";; --binary-name) prev_p="binary_name";; --binary-name=*) binary_name="$optarg";; --man-dir) prev_p="man_dir";; --man-dir=*) man_dir="$optarg";; --personal-dir) prev_p="personal_dir";; --personal-dir=*) personal_dir="$optarg";; --without-personal-dir) personal_dir="";; --shared-dir) prev_p="shared_dir";; --shared-dir=*) shared_dir="$optarg";; --without-shared-dir) shared_dir="";; --install-dir) prev_p="install_dir";; --install-dir=*) install_dir="$optarg";; --menu-group) prev_p="menu_group";; --menu-group=*) menu_group="$optarg";; --enable-debug) enable_debug="1";; --enable-debug=*) enable_debug="$optarg";; --enable-desync-debug) enable_desync_debug="1";; --enable-desync-debug=*) enable_desync_debug="$optarg";; --enable-profiling) enable_profiling="1";; --enable-profiling=*) enable_profiling="$optarg";; --enable-lto) enable_lto="1";; --enable-lto=*) enable_lto="$optarg";; --enable-ipo) enable_lto="1";; --enable-ipo=*) enable_lto="$optarg";; --enable-dedicated) enable_dedicated="1";; --enable-dedicated=*) enable_dedicated="$optarg";; --enable-network) enable_network="2";; --enable-network=*) enable_network="$optarg";; --disable-network) enable_network="0";; --disable-static) enable_static="0";; --enable-static) enable_static="2";; --enable-static=*) enable_static="$optarg";; --disable-translator) enable_translator="0";; --enable-translator) enable_translator="2";; --enable-translator=*) enable_translator="$optarg";; --disable-assert) enable_assert="0";; --enable-assert) enable_assert="2";; --enable-assert=*) enable_assert="$optarg";; --disable-strip) enable_strip="0";; --enable-strip) enable_strip="2";; --enable-strip=*) enable_strip="$optarg";; --disable-universal) enable_universal="0";; --enable-universal) enable_universal="i386 ppc";; --enable-universal=*) enable_universal="$optarg";; --disable-osx-g5) enable_osx_g5="0";; --enable-osx-g5) enable_osx_g5="2";; --enable-osx-g5=*) enable_osx_g5="$optarg";; --disable-unicode) enable_unicode="0";; --enable-unicode) enable_unicode="2";; --enable-unicode=*) enable_unicode="$optarg";; --disable-console) enable_console="0";; --enable-console) enable_console="2";; --enable-console=*) enable_console="$optarg";; --disable-cocoa-quartz) enable_cocoa_quartz="0";; --enable-cocoa-quartz) enable_cocoa_quartz="2";; --enable-cocoa-quartz=*) enable_cocoa_quartz="$optarg";; --disable-cocoa-quickdraw) enable_cocoa_quickdraw="0";; --enable-cocoa-quickdraw) enable_cocoa_quickdraw="2";; --enable-cocoa-quickdraw=*) enable_cocoa_quickdraw="$optarg";; --with-allegro) with_allegro="2";; --without-allegro) with_allegro="0";; --with-allegro=*) with_allegro="$optarg";; --with-sdl) with_sdl="2";; --without-sdl) with_sdl="0";; --with-sdl=*) with_sdl="$optarg";; --with-cocoa) with_cocoa="2";; --without-cocoa) with_cocoa="0";; --with-cocoa=*) with_cocoa="$optarg";; --with-zlib) with_zlib="2";; --without-zlib) with_zlib="0";; --with-zlib=*) with_zlib="$optarg";; --with-lzma) with_lzma="2";; --without-lzma) with_lzma="0";; --with-lzma=*) with_lzma="$optarg";; --with-liblzma) with_lzma="2";; --without-liblzma) with_lzma="0";; --with-liblzma=*) with_lzma="$optarg";; --with-lzo2) with_lzo2="2";; --without-lzo2) with_lzo2="0";; --with-lzo2=*) with_lzo2="$optarg";; --with-liblzo2) with_lzo2="2";; --without-liblzo2) with_lzo2="0";; --with-liblzo2=*) with_lzo2="$optarg";; --with-xdg-basedir) with_xdg_basedir="2";; --without-xdg-basedir) with_xdg_basedir="0";; --with-xdg-basedir=*) with_xdg_basedir="$optarg";; --with-libxdg-basedir) with_xdg_basedir="2";; --without-libxdg-basedir) with_xdg_basedir="0";; --with-libxdg-basedir=*) with_xdg_basedir="$optarg";; --with-png) with_png="2";; --without-png) with_png="0";; --with-png=*) with_png="$optarg";; --with-libpng) with_png="2";; --without-libpng) with_png="0";; --with-libpng=*) with_png="$optarg";; --with-libtimidity) with_libtimidity="2";; --without-libtimidity) with_libtimidity="0";; --with-libtimidity=*) with_libtimidity="$optarg";; --with-freetype) with_freetype="2";; --without-freetype) with_freetype="0";; --with-freetype=*) with_freetype="$optarg";; --with-libfreetype) with_freetype="2";; --without-libfreetype) with_freetype="0";; --with-libfreetype=*) with_freetype="$optarg";; --with-fontconfig) with_fontconfig="2";; --without-fontconfig) with_fontconfig="0";; --with-fontconfig=*) with_fontconfig="$optarg";; --with-libfontconfig) with_fontconfig="2";; --without-libfontconfig) with_fontconfig="0";; --with-libfontconfig=*) with_fontconfig="$optarg";; --with-icu) with_icu="2";; --without-icu) with_icu="0";; --with-icu=*) with_icu="$optarg";; --with-libicu) with_icu="2";; --without-libicu) with_icu="0";; --with-libicu=*) with_icu="$optarg";; --static-icu) static_icu="1";; --static-icu=*) static_icu="$optarg";; --static-libicu) static_icu="1";; --static-libicu=*) static_icu="$optarg";; --with-psp-config) with_psp_config="2";; --without-psp-config) with_psp_config="0";; --with-psp-config=*) with_psp_config="$optarg";; --disable-builtin-depend) enable_builtin_depend="0";; --enable-builtin-depend) enable_builtin_depend="2";; --enable-builtin-depend=*) enable_builtin_depend="$optarg";; --with-makedepend) with_makedepend="2";; --without-makedepend) with_makedepend="0";; --with-makedepend=*) with_makedepend="$optarg";; --with-direct-music) with_direct_music="2";; --without-direct-music) with_direct_music="0";; --with-direct-music=*) with_direct_music="$optarg";; --with-sort) with_sort="2";; --without-sort) with_sort="0";; --with-sort=*) with_sort="$optarg";; --with-iconv) with_iconv="2";; --without-iconv) with_iconv="0";; --with-iconv=*) with_iconv="$optarg";; --with-midi=*) with_midi="$optarg";; --with-midi-arg=*) with_midi_arg="$optarg";; --without-distcc) with_distcc="0";; --with-distcc) with_distcc="2";; --with-distcc=*) with_distcc="$optarg";; --without-ccache) with_ccache="0";; --with-ccache) with_ccache="2";; --with-ccache=*) with_ccache="$optarg";; --without-nforenum) with_nforenum="0";; --with-nforenum) with_nforenum="2";; --with-nforenum=*) with_nforenum="$optarg";; --without-grfcodec) with_grfcodec="0";; --with-grfcodec) with_grfcodec="2";; --with-grfcodec=*) with_grfcodec="$optarg";; --without-osx-sysroot) with_osx_sysroot="0";; --with-osx-sysroot) with_osx_sysroot="2";; --with-osx-sysroot=*) with_osx_sysroot="$optarg";; --without-application-bundle) with_application_bundle="0";; --with-application-bundle) with_application_bundle="1";; --with-application-bundle=*) with_application_bundle="$optarg";; --without-threads) with_threads="0";; --with-threads) with_threads="1";; --with-threads=*) with_threads="$optarg";; --without-sse) with_sse="0";; --with-sse) with_sse="1";; --with-sse=*) with_sse="$optarg";; CC=* | --CC=*) CC="$optarg";; CXX=* | --CXX=*) CXX="$optarg";; CFLAGS=* | --CFLAGS=*) CFLAGS="$optarg";; CXXFLAGS=* | --CXXFLAGS=*) CXXFLAGS="$optarg";; LDFLAGS=* | --LDFLAGS=*) LDFLAGS="$optarg";; CFLAGS_BUILD=* | --CFLAGS_BUILD=* | --CFLAGS-BUILD=*) CFLAGS_BUILD="$optarg";; CXXFLAGS_BUILD=* | --CXXFLAGS_BUILD=* | --CXXFLAGS-BUILD=*) CXXFLAGS_BUILD="$optarg";; LDFLAGS_BUILD=* | --LDFLAGS_BUILD=* | --LDFLAGS-BUILD=*) LDFLAGS_BUILD="$optarg";; --ignore-extra-parameters) ignore_extra_parameters="1";; --* | -*) if [ "$ignore_extra_parameters" = "0" ]; then log 1 "Unknown option $p" exit 1 else log 1 "Unknown option $p ignored" fi ;; esac done if [ -n "$prev_p" ]; then log 1 "configure: error: missing argument to --$prev_p" exit 1 fi # Clean the logfile echo "" > $config_log log 2 "Invocation: $0 $*" } save_params() { # Here we save all params, so we can later on do an exact redo of this # configuration, without having the user to re-input stuff echo "Running configure with following options:" >> $config_log echo "" >> $config_log configure="$CONFIGURE_EXECUTABLE --ignore-extra-parameters" for p in $save_params_array; do eval "v=\"\$$p\"" p=`echo "$p" | sed 's@_@-@g;s@\n@@g;s@ @\\ @g'` # Only save those params that aren't empty configure="$configure --$p=\"$v\"" done echo "$configure" >> $config_log echo "$configure" > config.cache echo "" >> $config_log } check_params() { # Some params want to be in full uppercase, else they might not work as # expected.. fix that here endian=`echo $endian | tr '[a-z]' '[A-Z]'` os=`echo $os | tr '[a-z]' '[A-Z]'` cpu_type=`echo $cpu_type | tr '[a-z]' '[A-Z]'` # Check if all params have valid values # Endian only allows AUTO, LE and, BE if [ -z "`echo $endian | egrep '^(AUTO|LE|BE|PREPROCESSOR)$'`" ]; then log 1 "configure: error: invalid option --endian=$endian" log 1 " Available options are: --endian=[AUTO|LE|BE]" exit 1 fi if [ "$endian" = "PREPROCESSOR" ] && [ "$os" != "OSX" ]; then log 1 "configure: error: invalid option --endian=$endian" log 1 " PREPROCESSOR is only available for OSX" exit 1 fi # OS only allows DETECT, UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, MORPHOS, BEOS, HAIKU, SUNOS, CYGWIN, MINGW, OS2, DOS, WINCE, and PSP if [ -z "`echo $os | egrep '^(DETECT|UNIX|OSX|FREEBSD|DRAGONFLY|OPENBSD|NETBSD|HPUX|MORPHOS|BEOS|HAIKU|SUNOS|CYGWIN|MINGW|OS2|DOS|WINCE|PSP)$'`" ]; then log 1 "configure: error: invalid option --os=$os" log 1 " Available options are: --os=[DETECT|UNIX|OSX|FREEBSD|DRAGONFLY|OPENBSD|NETBSD|HPUX|MORPHOS|BEOS|HAIKU|SUNOS|CYGWIN|MINGW|OS2|DOS|WINCE|PSP]" exit 1 fi # cpu_type can be either 32 or 64 if [ -z "`echo $cpu_type | egrep '^(32|64|DETECT)$'`" ]; then log 1 "configure: error: invalid option --cpu-type=$cpu_type" log 1 " Available options are: --cpu-type[=DETECT|32|64]" exit 1 fi # enable_debug should be between 0 and 4 if [ -z "`echo $enable_debug | egrep '^[0123]$'`" ]; then log 1 "configure: error: invalid option --enable-debug=$enable_debug" log 1 " Available options are: --enable-debug[=0123]" exit 1 fi # enable_desync_debug should be between 0 and 3 if [ -z "`echo $enable_desync_debug | egrep '^[012]$'`" ]; then log 1 "configure: error: invalid option --enable-desync-debug=$enable_desync_debug" log 1 " Available options are: --enable-desync-debug[=012]" exit 1 fi detect_awk detect_os check_build check_host # Check for universal builds; they only make sense for OSX, so fail if enabled for another OS if [ "$enable_universal" = "0" ]; then log 1 "checking universal build... no" else if [ "$os" != "OSX" ]; then log 1 "configure: error: --enable-universal only works on OSX" exit 1 fi log 1 "checking universal build... yes, for: $enable_universal" fi # Already detected by check_build log 1 "checking build cc... $cc_build" log 1 "checking host cc... $cc_host" check_cxx_build check_cxx_host check_windres if [ "$enable_strip" != "0" ]; then check_strip else log 1 "checking strip... disabled" fi check_lipo if [ "$enable_builtin_depend" != "0" ]; then log 1 "checking builtin depend... yes" makedepend="\$(SRC_OBJS_DIR)/\$(DEPEND)" else log 1 "checking builtin depend... no" fi check_makedepend detect_cputype detect_sse_capable_architecture if [ "$enable_static" = "1" ]; then if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "MORPHOS" ] || [ "$os" = "DOS" ]; then enable_static="2" else enable_static="0" fi fi if [ "$enable_static" != "0" ]; then log 1 "checking static... yes" if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "OSX" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "DOS" ]; then log 1 "WARNING: static is only known to work on Windows, DOS, MacOSX and MorphOS" log 1 "WARNING: use static at your own risk on this platform" sleep 5 fi else log 1 "checking static... no" fi if [ "$enable_unicode" = "1" ]; then if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "DOS" ]; then enable_unicode="2" else enable_unicode="0" fi fi if [ "$enable_unicode" != "0" ]; then log 1 "checking unicode... yes" else log 1 "checking unicode... no" fi # Show what we configured if [ "$enable_debug" = "0" ]; then log 1 "using debug level... no" elif [ "$enable_profiling" != "0" ]; then log 1 "using debug level... profiling (debug level $enable_debug)" else log 1 "using debug level... level $enable_debug" fi if [ "$enable_desync_debug" = "0" ]; then log 1 "using desync debug level... no" else log 1 "using desync debug level... level $enable_desync_debug" log 1 "WARNING: desync debug functions slow down the game considerably." log 1 "WARNING: use only when you are instructed to do so" log 1 " or when you know what you are doing." sleep 5 fi if [ "$enable_lto" != "0" ]; then # GCC 4.5 outputs '%{flto}', GCC 4.6 outputs '%{flto*}' has_lto=`($cxx_build -dumpspecs 2>&1 | grep '\%{flto') || ($cxx_build -help ipo 2>&1 | grep '\-ipo')` if [ -n "$has_lto" ]; then log 1 "using link time optimization... yes" else enable_lto="0" log 1 "using link time optimization... no" log 1 "WARNING: you selected link time optimization but it is not found." sleep 5 fi else log 1 "using link time optimization... no" fi if [ "$os" != "OSX" ] && [ "$with_osx_sysroot" != "0" ]; then if [ "$with_osx_sysroot" = "1" ]; then with_osx_sysroot="0" log 1 "checking OSX sysroot... not OSX, skipping" else log 1 "configure: error: --with-osx-sysroot only works if OSX is the target" exit 1 fi fi if [ "$with_osx_sysroot" != "0" ]; then if [ "$enable_universal" = "0" ] && [ "$with_osx_sysroot" != "1" ] && [ "$with_osx_sysroot" != "2" ]; then # Sysroot manually specified? Check for usability log 1 "checking OSX sysroot... $with_osx_sysroot" if ! check_osx_sdk "$with_osx_sysroot"; then log 1 "Passed sysroot not found/not functional" exit 1 fi else # If autodetect and no universal, use system default if [ "$with_osx_sysroot" = "1" ] && [ "$enable_universal" = "0" ]; then log 1 "checking OSX sysroot... no (use system default)" else log 1 "checking OSX sysroot... automatically" detect_osx_sdk fi fi if [ -n "$osx_sdk_path" ]; then if [ "$enable_universal" != "0" ]; then if [ -z "$osx_sdk_104_path" ]; then log 1 "WARNING: Could not find a usable 10.4u SDK, the resulting" log 1 "WARNING: binary will only run on OSX 10.5 or later" osx_sdk_104_path="$osx_sdk_path" fi OSX_SYSROOT="-isysroot $osx_sdk_104_path" OSX_LD_SYSROOT="-Wl,-syslibroot,$osx_sdk_104_path" else OSX_SYSROOT="-isysroot $osx_sdk_path" OSX_LD_SYSROOT="-Wl,-syslibroot,$osx_sdk_path" fi fi else if [ "$os" = "OSX" ]; then log 1 "checking OSX sysroot... no (use system default)" fi fi detect_allegro detect_sdl detect_cocoa if [ "$enable_dedicated" != "0" ]; then log 1 "checking GDI video driver... dedicated server, skipping" log 1 "checking dedicated... found" if [ "$enable_network" = "0" ]; then log 1 "configure: error: building a dedicated server without network support is pointless" exit 1 fi else if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then log 1 "checking GDI video driver... found" else log 1 "checking GDI video driver... not Windows, skipping" fi if [ -z "$allegro_config" ] && [ -z "$sdl_config" ] && [ "$with_cocoa" = 0 ] && [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then log 1 "configure: error: no video driver development files found" log 1 " If you want a dedicated server use --enable-dedicated as parameter" exit 1 else log 1 "checking dedicated... not selected" fi fi if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; then log 1 "checking console application... not Windows, skipping" elif [ "$enable_console" = "1" ] && [ "$enable_dedicated" != "0" ]; then log 1 "checking console application... dedicated server, enabled" enable_console="2" elif [ "$enable_console" = "1" ]; then log 1 "checking console application... disabled (only used when forced)" enable_console="0" elif [ "$enable_console" = "0" ]; then log 1 "checking console application... disabled" else log 1 "checking console application... enabled" fi if [ "$enable_network" = "1" ] && [ "$os" = "DOS" ]; then log 1 "checking network... DOS, skipping" enable_network=0 elif [ "$enable_network" != "0" ]; then log 1 "checking network... found" else log 1 "checking network... disabled" fi log 1 "checking squirrel... found" SCRIPT_SRC_DIR="$ROOT_DIR/src/3rdparty/squirrel/include" if [ "$enable_translator" != "0" ]; then log 1 "checking translator... debug" # -t shows TODO items, normally they are muted strgen_flags="-t" else log 1 "checking translator... no" strgen_flags="" fi if [ "$enable_assert" != "0" ]; then log 1 "checking assert... enabled" else log 1 "checking assert... disabled" fi pre_detect_with_zlib=$with_zlib detect_zlib if [ "$with_zlib" = "0" ] || [ -z "$zlib" ]; then log 1 "WARNING: zlib was not detected or disabled" log 1 "WARNING: OpenTTD doesn't require zlib, but it does mean that many features" log 1 "WARNING: (like loading most old savegames/scenarios, loading heightmaps," log 1 "WARNING: using PNG, or using fonts, ...) will be disabled." if [ "$pre_detect_with_zlib" = "0" ]; then log 1 "WARNING: We strongly suggest you to install zlib." else log 1 "configure: error: no zlib detected" log 1 " If you want to compile without zlib use --without-zlib as parameter" exit fi fi pre_detect_with_lzma=$with_lzma detect_lzma if [ "$with_lzma" = "0" ] || [ -z "$lzma_config" ]; then log 1 "WARNING: lzma was not detected or disabled" log 1 "WARNING: OpenTTD doesn't require lzma, but it does mean that many features" log 1 "WARNING: (like loading most savegames/scenarios and joining most servers)" log 1 "WARNING: will be disabled." if [ "$pre_detect_with_lzma" = "0" ]; then log 1 "WARNING: We strongly suggest you to install liblzma." log 1 "configure: error: no liblzma detected" else log 1 " If you want to compile without lzma use --without-lzma as parameter" exit fi fi pre_detect_with_lzo2=$with_lzo2 detect_lzo2 if [ "$with_lzo2" = "0" ] || [ -z "$lzo2" ]; then log 1 "WARNING: liblzo2 was not detected or disabled" log 1 "WARNING: OpenTTD doesn't require liblzo2, but it does mean that" log 1 "WARNING: loading old savegames/scenarios will be disabled." if [ "$pre_detect_with_lzo2" = "0" ]; then log 1 "WARNING: We strongly suggest you to install liblzo2." else log 1 "configure: error: no liblzo2 detected" log 1 " If you want to compile without liblzo2 use --without-liblzo2 as parameter" exit fi fi detect_xdg_basedir detect_png detect_freetype detect_fontconfig detect_icu detect_pspconfig detect_libtimidity if [ "$with_direct_music" != "0" ]; then if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ]; then if [ "$with_direct_music" != "1" ]; then log 1 "configure: error: direct-music is only supported on Win32 targets" exit 1 fi with_direct_music="0" log 1 "checking direct-music... not Windows, skipping" else check_direct_music fi fi detect_sort if [ "$os" = "OSX" ] && [ "$endian" = "AUTO" ]; then endian="PREPROCESSOR" fi log 1 "checking endianness... $endian" # Suppress language errors when there is a version defined, indicating a release # It just isn't pretty if any release produces warnings in the languages. if [ -f "$ROOT_DIR/version" ]; then lang_suppress="yes" log 1 "suppress language errors... yes" else lang_suppress="" log 1 "suppress language errors... no" fi if [ "$enable_debug" = "0" ] && [ "$enable_profiling" = "0" ] && [ "$enable_strip" != "0" ]; then if [ "$os" = "MORPHOS" ]; then strip_arg="--strip-all --strip-unneeded --remove-section .comment" elif [ "$os" = "OSX" ]; then strip_arg="" elif [ "$os" = "OS2" ]; then strip_arg="" # OS2 uses strip via gcc, because it needs to be feed to emxbind LDFLAGS="$LDFLAGS -s" elif [ "$os" = "SUNOS" ]; then # The GNU strip does know -s, the non-GNU doesn't # So try to detect it (in a bit of an ugly way) strip_arg="`$strip -s strip.test 2>/dev/null && echo \"-s\"`" else strip_arg="-s" fi log 1 "checking stripping... $strip $strip_arg" else strip="" log 1 "checking stripping... skipped" fi if [ "$with_distcc" = "0" ]; then log 1 "checking distcc... no" elif [ "$with_distcc" = "1" ]; then with_distcc="0" log 1 "checking distcc... no (only used when forced)" elif [ "$with_distcc" = "2" ]; then distcc="distcc" else distcc="$with_distcc" fi if [ "$with_distcc" != "0" ]; then res="`$distcc --version 2>/dev/null | head -n 1 | cut -b 1-6`" if [ "$res" != "distcc" ]; then distcc="" log 1 "checking distcc... no" if [ "$with_distcc" = "2" ]; then log 1 "configure: error: no distcc detected, but was forced to be used" exit 1 fi if [ "$with_distcc" != "1" ]; then log 1 "configure: error: '$with_distcc' doesn't seem a distcc to me" exit 1 fi fi log 1 "checking distcc... $distcc" fi if [ "$with_ccache" = "0" ]; then log 1 "checking ccache... no" elif [ "$with_ccache" = "1" ]; then with_ccache="0" log 1 "checking ccache... no (only used when forced)" elif [ "$with_ccache" = "2" ]; then ccache="ccache" else ccache="$with_ccache" fi if [ "$with_ccache" != "0" ]; then res="`$ccache --version 2>/dev/null | head -n 1 | cut -b 1-6`" if [ "$res" != "ccache" ]; then ccache="" log 1 "checking ccache... no" if [ "$with_ccache" = "2" ]; then log 1 "configure: error: no ccache detected, but was forced to be used" exit 1 fi if [ "$with_ccache" != "1" ]; then log 1 "configure: error: '$with_ccache' doesn't seem a ccache to me" exit 1 fi fi log 1 "checking ccache... $ccache" fi detect_grfcodec detect_nforenum if [ -z "$grfcodec" ] && [ -n "$nforenum" ]; then log 1 "checking nforenum/grfcodec... nforenum needs grfcodec enabled, disabling nforenum" nforenum="" fi if [ -z "$nforenum" ] && [ -n "$grfcodec" ]; then log 1 "checking nforenum/grfcodec... grfcodec needs nforenum enabled, disabling grfcodec" grfcodec="" fi if [ "$os" = "DOS" ]; then with_threads="0" fi if [ "$os" != "OSX" ] && [ "$with_application_bundle" != "0" ]; then if [ "$with_application_bundle" = "1" ]; then with_application_bundle="0" log 1 "checking OSX application bundle... not OSX, skipping" else log 1 "configure: error: --with-application-bundle only works if OSX is the target" exit 1 fi fi if [ "$os" = "OSX" ] && [ "$with_application_bundle" = "1" ]; then OSXAPP="OpenTTD.app" else OSXAPP="" fi if [ "$os" = "OSX" ]; then # Test on ppc970 (G5) - we can optimize there if [ "$enable_osx_g5" != "0" ]; then log 1 "detecting ppc970 (G5)... yes (forced)" else # First, are we a real OSX system, else we can't detect it native=`LC_ALL=C uname | tr '[A-Z]' '[a-z]' | grep darwin` # If $host doesn't match $build , we are cross-compiling if [ -n "$native" ] && [ "$build" = "$host" ]; then $cxx_build $SRC_DIR/os/macosx/G5_detector.cpp -o G5_detector res=`./G5_detector` rm -f G5_detector if [ -n "$res" ]; then # This is G5, add flags for it enable_osx_g5="2" log 1 "detecting ppc970 (G5)... yes" else enable_osx_g5="0" log 1 "detecting ppc970 (G5)... no" fi else enable_osx_g5="0" log 1 "detecting ppc970 (G5)... no (cross-compiling)" fi fi else if [ "$enable_osx_g5" != "0" ]; then log 1 "configure: error: ppc970 (OSX G5) selected, but not compiling for OSX" log 1 "configure: error: either select OSX as OS, or deselect ppc970" exit 1 fi fi if [ -d "$ROOT_DIR/.svn" ] && [ -n "`svn help 2>/dev/null`" ]; then log 1 "checking revision... svn detection" elif [ -d "$ROOT_DIR/../.svn" ] && [ -n "`svn help 2>/dev/null`" ] && [ -n "`LC_ALL=C svn info $ROOT_DIR/.. | grep '^URL:.*tags$'`" ]; then # subversion changed its behaviour; now not all folders have a .svn folder, # but only the root folder. Since making tags requires a (sparse) checkout # of the tags folder, the folder of the tag does not have a .svn folder # anymore and this fails to detect the subversion repository checkout. log 1 "checking revision... svn detection (tag)" elif [ -d "$ROOT_DIR/.git" ] && [ -n "`git help 2>/dev/null`" ]; then log 1 "checking revision... git detection" elif [ -d "$ROOT_DIR/.hg" ] && [ -n "`HGPLAIN= hg help 2>/dev/null`" ]; then log 1 "checking revision... hg detection" elif [ -f "$ROOT_DIR/.ottdrev" ]; then log 1 "checking revision... source tarball" else log 1 "checking revision... no detection" log 1 "WARNING: there is no means to determine the version." log 1 "WARNING: please use a subversion, mercurial, or git checkout of OpenTTD." log 1 "WARNING: you can only join game servers that have been compiled without" log 1 "WARNING: version detection." log 1 "WARNING: there is a great chance you desync." log 1 "WARNING: USE WITH CAUTION!" sleep 5 fi if [ "$doc_dir" = "1" ]; then if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ]; then doc_dir="share/doc/openttd" else doc_dir="$data_dir/docs" fi else doc_dir="`echo $doc_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" fi if [ "$icon_theme_dir" = "1" ]; then if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ]; then icon_theme_dir="share/icons/hicolor" else icon_theme_dir="" fi else icon_theme_dir="`echo $icon_theme_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" fi if [ "$personal_dir" = "1" ]; then if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ] || [ "$os" = "DOS" ] || [ "$os" = "HAIKU" ]; then personal_dir="OpenTTD" elif [ "$os" = "OSX" ]; then personal_dir="Documents/OpenTTD" else personal_dir=".openttd" fi else personal_dir="`echo $personal_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" fi if [ "$shared_dir" = "1" ]; then # we are using default values if [ "$os" = "OSX" ]; then shared_dir="/Library/Application\\\\ Support/OpenTTD" else shared_dir="" fi else shared_dir="`echo $shared_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" fi if [ "$man_dir" = "1" ]; then # add manpage on UNIX systems if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ] || [ "$os" = "OSX" ]; then man_dir="share/man/man6" else man_dir="" fi else man_dir="`echo $man_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" fi if [ "$menu_dir" = "1" ]; then # add a freedesktop menu item only for some UNIX systems if [ "$os" = "UNIX" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ]; then menu_dir="share/applications" else menu_dir="" fi else menu_dir="`echo $menu_dir | sed 's@\([^\]\)\\\\ @\1\\\\\\\\ @g;s@\([^\]\) @\1\\\\\\\\ @g'`" fi detect_iconv if [ -n "$personal_dir" ] then log 1 "personal home directory... $personal_dir" else log 1 "personal home directory... none" fi if [ -n "$shared_dir" ] then log 1 "shared data directory... $shared_dir" else log 1 "shared data directory... none" fi if [ -n "$install_dir" ] then log 1 "installation directory... $install_dir" else log 1 "installation directory... none" fi if [ -n "$icon_theme_dir" ] then log 1 "icon theme directory... $icon_theme_dir" else log 1 "icon theme directory... none" fi if [ -n "$man_dir" ] then log 1 "manual page directory... $man_dir" else log 1 "manual page directory... none" fi if [ -n "$menu_dir" ] then log 1 "menu item directory... $menu_dir" else log 1 "menu item directory... none" fi } make_compiler_cflags() { # Params: # $1 - compiler # $2 - name of the cflags variable # $3 - name of the cxxflags variable # $4 - name of the ldflags variable # $5 - name of the features variable eval eval "flags=\\\$$2" eval eval "cxxflags=\\\$$3" eval eval "ldflags=\\\$$4" eval eval "features=\\\$$5" if [ `basename $1 | cut -c 1-3` = "icc" ]; then # Enable some things only for certain ICC versions cc_version=`$1 -dumpversion | cut -c 1-4 | sed s@\\\.@@g` flags="$flags -rdynamic" ldflags="$ldflags -rdynamic" if [ -z "$first_time_icc_check" ]; then first_time_icc_check=no if [ $cc_version -lt 90 ]; then log 1 "WARNING: you seem to be using a very old version of ICC" log 1 "WARNING: OpenTTD hasn't been tested with this version" sleep 5 elif [ $cc_version -lt 120 ]; then log 1 "WARNING: you seem to be using an unsupported ICC version" log 1 "WARNING: ICC older than 12.0 is known to fail to compile OpenTTD" sleep 5 fi fi flags="$flags -Wall" # remark #111: statement is unreachable flags="$flags -wd111" # remark #181: argument is incompatible with corresponding format string conversion # ICC is very picky about signedness of operands, warnings provided by GCC are enough flags="$flags -wd181" # remark #271: trailing comma is nonstandard flags="$flags -wd271" # remark #280: selector expression is constant flags="$flags -wd280" # remark #304: access control not specified ("public" by default) flags="$flags -wd304" # remark #383: value copied to temporary, reference to temporary used flags="$flags -wd383" # remark #444: destructor for base class ... is not virtual flags="$flags -wd444" # remark #593: variable ... was set but never used flags="$flags -wd593" # warning #654: overloaded virtual function ... is only partially overridden in class ... flags="$flags -wd654" # remark #810: conversion from ... to ... may lose significant bits flags="$flags -wd810" # remark #869: parameter ... was never referenced flags="$flags -wd869" # warning #873: function ... ::operator new ... has no corresponding operator delete ... flags="$flags -wd873" # remark #981: operands are evaluated in unspecified order flags="$flags -wd981" # remark #1418: external function definition with no prior declaration flags="$flags -wd1418" # remark #1419: external declaration in primary source file flags="$flags -wd1419" # remark #1572: floating-point equality and inequality flags="$flags -wd1572" # remark #1599: declaration hides variable/parameter ... flags="$flags -wd1599" # remark #1720: function ... ::operator new ... has no corresponding member operator delete ... flags="$flags -wd1720" if [ $cc_version -lt 110 ]; then # warns about system headers with recent glibc: # warning #1292: attribute "__nonnull__" ignored flags="$flags -wd1292" fi if [ $cc_version -ge 100 ]; then # warning #1899: multicharacter character literal (potential portability problem) flags="$flags -wd1899" # vec report defaults to telling where it did loop vectorisation, which is not very important flags="$flags -vec-report=0 " fi if [ $cc_version -ge 110 ]; then # remark #2259: non-pointer conversion from ... to ... may lose significant bits flags="$flags -wd2259" # Use c++0x mode so static_assert() is available cxxflags="$cxxflags -std=c++0x" fi if [ "$enable_lto" != "0" ]; then has_ipo=`$1 -help ipo | grep '\-ipo'` if [ -n "$has_ipo" ]; then # Use IPO (only if we see IPO exists and is requested) flags="$flags -ipo" features="$features lto" fi fi elif [ `basename $1 | grep 'clang'` ]; then # Enable some things only for certain clang versions cc_version="`$1 -v 2>&1 | head -n 1 | sed s@[^0-9]@@g | cut -c 1-2`" # aliasing rules are not held in openttd code flags="$flags -fno-strict-aliasing" # -W alone doesn't enable all warnings enabled by -Wall; on the other hand, # -Weverything enables too many useless warnings that can't be disabled (as of 3.0) flags="$flags -Wall -W" # warning: unused parameter '...' flags="$flags -Wno-unused-parameter" # warning: expression result unused flags="$flags -Wno-unused-value" # warning: multi-character character constant flags="$flags -Wno-multichar" # warning: explicitly assigning a variable of type '...' to itself # it happens when using the FOR_ALL_WINDOWS_FROM_BACK_FROM macro flags="$flags -Wno-self-assign" if [ "$cc_version" -lt "30" ]; then # warning: equality comparison with extraneous parentheses flags="$flags -Wno-parentheses" # warning: operands of ? are integers of different signs: 'unsigned int' and 'int' flags="$flags -Wno-sign-compare" fi if [ "$cc_version" -ge "30" ]; then # warning: equality comparison with extraneous parentheses # this warning could be useful, but it warns about code in squirrel flags="$flags -Wno-parentheses-equality" fi if [ "$with_ccache" != "0" -o "$with_distcc" != "0" ]; then # ccache and distcc run separate preprocess and compile passes, # both are fed with the same CFLAGS. Unfortunately, clang # complains about -I when compiling preprocessed files: # "clang: warning: argument unused during compilation: '-I /usr/include'" flags="$flags -Qunused-arguments" fi if [ "$enable_assert" -eq "0" ]; then # do not warn about unused variables when building without asserts flags="$flags -Wno-unused-variable" fi # rdynamic is used to get useful stack traces from crash reports. ldflags="$ldflags -rdynamic" else # Enable some things only for certain GCC versions cc_version=`$1 -dumpversion | cut -c 1,3` if [ $cc_version -lt 33 ]; then log 1 "configure: error: gcc older than 3.3 can't compile OpenTTD because of its poor template support" exit 1 fi flags="$flags -Wall -Wno-multichar -Wsign-compare -Wundef" flags="$flags -Wwrite-strings -Wpointer-arith" flags="$flags -W -Wno-unused-parameter -Wredundant-decls" flags="$flags -Wformat=2 -Wformat-security" if [ $enable_assert -eq 0 ]; then # Do not warn about unused variables when building without asserts flags="$flags -Wno-unused-variable" if [ $cc_version -ge 46 ]; then # GCC 4.6 gives more warnings, disable them too flags="$flags -Wno-unused-but-set-variable" flags="$flags -Wno-unused-but-set-parameter" fi fi if [ $cc_version -ge 34 ]; then # Warn when a variable is used to initialise itself: # int a = a; flags="$flags -Winit-self" fi if [ $cc_version -ge 40 ]; then # GCC 4.0+ complains about that we break strict-aliasing. # On most places we don't see how to fix it, and it doesn't # break anything. So disable strict-aliasing to make the # compiler all happy. flags="$flags -fno-strict-aliasing" # Warn about casting-out 'const' with regular C-style cast. # The preferred way is const_cast<>() which doesn't warn. flags="$flags -Wcast-qual" fi if [ $cc_version -ge 42 ]; then # GCC 4.2+ automatically assumes that signed overflows do # not occur in signed arithmetics, whereas we are not # 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 # Use gnu++0x mode so static_assert() is available. # Don't use c++0x, it breaks mingw (with gcc 4.4.0). cxxflags="$cxxflags -std=gnu++0x" fi if [ $cc_version -eq 45 ]; then # Prevent optimisation supposing enums are in a range specified by the standard # For details, see http://gcc.gnu.org/PR43680 flags="$flags -fno-tree-vrp" fi if [ $cc_version -ge 47 ]; then # Disable -Wnarrowing which gives many warnings, such as: # warning: narrowing conversion of '...' from 'unsigned int' to 'int' inside { } [-Wnarrowing] # They are valid according to the C++ standard, but useless. cxxflags="$cxxflags -Wno-narrowing" # Disable bogus 'attempt to free a non-heap object' warning flags="$flags -Wno-free-nonheap-object" fi if [ "$enable_lto" != "0" ]; then # GCC 4.5 outputs '%{flto}', GCC 4.6 outputs '%{flto*}' has_lto=`$1 -dumpspecs | grep '\%{flto'` if [ -n "$has_lto" ]; then # Use LTO only if we see LTO exists and is requested if [ $cc_version -lt 46 ]; then flags="$flags -flto" else flags="$flags -flto=jobserver" fi ldflags="$ldflags -fwhole-program" features="$features lto" fi fi has_rdynamic=`$1 -dumpspecs | grep rdynamic` if [ -n "$has_rdynamic" ]; then # rdynamic is used to get useful stack traces from crash reports. flags="$flags -rdynamic" ldflags="$ldflags -rdynamic" fi fi eval "$2=\"$flags\"" eval "$3=\"$cxxflags\"" eval "$4=\"$ldflags\"" eval "$5=\"$features\"" } make_cflags_and_ldflags() { # General CFlags for BUILD CFLAGS_BUILD="$CFLAGS_BUILD" # Special CXXFlags for BUILD CXXFLAGS_BUILD="$CXXFLAGS_BUILD" # LDFLAGS for BUILD LDFLAGS_BUILD="$LDFLAGS_BUILD" # FEATURES for BUILD (lto) FEATURES_BUILD="" # General CFlags for HOST CFLAGS="$CFLAGS" # Special CXXFlags for HOST CXXFLAGS="$CXXFLAGS" # Libs to compile. In fact this is just LDFLAGS LIBS="-lstdc++" # LDFLAGS used for HOST LDFLAGS="$LDFLAGS" # FEATURES for HOST (lto) FEATURES="" make_compiler_cflags "$cc_build" "CFLAGS_BUILD" "CXXFLAGS_BUILD" "LDFLAGS_BUILD" "FEATURES_BUILD" make_compiler_cflags "$cc_host" "CFLAGS" "CXXFLAGS" "LDFLAGS" "FEATURES" CFLAGS="$CFLAGS -D$os" CFLAGS_BUILD="$CFLAGS_BUILD -D$os" if [ "$enable_debug" = "0" ]; then # No debug, add default stuff OBJS_SUBDIR="release" if [ "$os" = "MORPHOS" ]; then CFLAGS="-I/gg/os-include -noixemul -fstrict-aliasing -fexpensive-optimizations -mcpu=604 -fno-inline -mstring -mmultiple $CFLAGS" LDFLAGS="$LDFLAGS -noixemul" fi if [ "$enable_profiling" = "0" ]; then # -fomit-frame-pointer and -pg do not go well together (gcc errors they are incompatible) CFLAGS="-fomit-frame-pointer $CFLAGS" fi CFLAGS="-O2 $CFLAGS" else OBJS_SUBDIR="debug" # Each debug level reduces the optimization by a bit if [ $enable_debug -ge 1 ]; then CFLAGS="$CFLAGS -g -D_DEBUG" if [ "$os" = "PSP" ]; then CFLAGS="$CFLAGS -G0" fi fi if [ $enable_debug -ge 2 ]; then CFLAGS="$CFLAGS -fno-inline" fi if [ $enable_debug -ge 3 ]; then CFLAGS="$CFLAGS -O0" else CFLAGS="$CFLAGS -O2" fi fi if [ $enable_debug -le 2 ]; then cc_host_is_gcc=`basename "$cc_host" | grep "gcc" &>/dev/null` if [ -n "$cc_host_is_gcc" ]; then # Define only when compiling with GCC. Some GLIBC versions use GNU # extensions in a way that breaks build with at least ICC. # This requires -O1 or more, so debug level 3 (-O0) is excluded. CFLAGS="$CFLAGS -D_FORTIFY_SOURCE=2" fi cc_build_is_gcc=`basename "$cc_build" | grep "gcc" &>/dev/null` if [ -n "$cc_build_is_gcc" ]; then # Just add -O1 to the tools needed for building. CFLAGS_BUILD="$CFLAGS_BUILD -D_FORTIFY_SOURCE=2 -O1" fi fi if [ "$os" = "OSX" ] && [ $cc_version -eq 40 ]; then # Apple's GCC 4.0 has a compiler bug for x86_64 with (higher) optimization, # wrongly optimizing ^= in loops. This disables the failing optimisation. CFLAGS="$CFLAGS -fno-expensive-optimizations" fi if [ "$enable_profiling" != "0" ]; then CFLAGS="$CFLAGS -pg" LDFLAGS="$LDFLAGS -pg" fi if [ "$with_threads" = "0" ]; then CFLAGS="$CFLAGS -DNO_THREADS" fi if [ "$with_sse" = "1" ]; then CFLAGS="$CFLAGS -DWITH_SSE" fi if [ "`echo $1 | cut -c 1-3`" != "icc" ]; then if [ "$os" = "CYGWIN" ]; then flags="$flags -mwin32" LDFLAGS="$LDFLAGS -mwin32" fi if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ]; then if [ $cc_version -lt 46 ]; then flags="$flags -mno-cygwin" LDFLAGS="$LDFLAGS -mno-cygwin" fi if [ "$enable_console" != "0" ]; then LDFLAGS="$LDFLAGS -Wl,--subsystem,console" else LDFLAGS="$LDFLAGS -Wl,--subsystem,windows" fi LIBS="$LIBS -lws2_32 -lwinmm -lgdi32 -ldxguid -lole32 -limm32" if [ $cc_version -ge 44 ]; then LDFLAGS_BUILD="$LDFLAGS_BUILD -static-libgcc -static-libstdc++" fi if [ $cc_version -ge 47 ]; then CFLAGS="$CFLAGS -mno-ms-bitfields" fi fi fi if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "OPENBSD" ] && [ "$os" != "MINGW" ] && [ "$os" != "MORPHOS" ] && [ "$os" != "OSX" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ] && [ "$os" != "PSP" ] && [ "$os" != "OS2" ]; then LIBS="$LIBS -lpthread" fi if [ "$os" != "CYGWIN" ] && [ "$os" != "HAIKU" ] && [ "$os" != "MINGW" ] && [ "$os" != "DOS" ] && [ "$os" != "WINCE" ]; then LIBS="$LIBS -lc" fi if [ "$os" = "WINCE" ]; then LIBS="$LIBS -lcoredll -lcorelibc -laygshell -lws2 -e WinMainCRTStartup" fi if [ "$os" = "PSP" ]; then CFLAGS="$CFLAGS -I`$psp_config -p`/include" LDFLAGS="$LDFLAGS -L`$psp_config -p`/lib" CFLAGS="$CFLAGS -fno-exceptions -fno-rtti -D_PSP_FW_VERSION=150" LIBS="$LIBS -D_PSP_FW_VERSION=150 -lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk -lpspnet -lpspnet_inet -lpspnet_apctl -lpspnet_resolver -lpsputility -lpspuser -lpspkernel -lm" fi if [ "$os" = "MORPHOS" ]; then # -Wstrict-prototypes generates much noise because of system headers CFLAGS="$CFLAGS -Wno-strict-prototypes" fi if [ "$os" = "OPENBSD" ]; then LIBS="$LIBS -pthread" fi if [ "$os" = "OSX" ]; then LDFLAGS="$LDFLAGS -framework Cocoa" # Add macports include dir which is not always set a default system dir. This avoids zillions of bogus warnings. CFLAGS="$CFLAGS -isystem/opt/local/include" if [ "$enable_dedicated" = "0" ] && ([ "$cpu_type" = "32" ] || [ "$enable_universal" != "0" ]); then LIBS="$LIBS -framework QuickTime" else CFLAGS="$CFLAGS -DNO_QUICKTIME" fi if [ "$enable_universal" = "0" ]; then # Universal builds set this elsewhere CFLAGS="$OSX_SYSROOT $CFLAGS" LDFLAGS="$OSX_LD_SYSROOT $LDFLAGS" fi if [ "$enable_universal" = "0" ] && [ $cc_version -gt 40 ]; then # Only set the min version when not doing an universal build. # Universal builds set the version elsewhere. if [ "$cpu_type" = "64" ]; then CFLAGS="$CFLAGS -mmacosx-version-min=10.5" else gcc_cpu=`$cc_host -dumpmachine` if [ "`echo $gcc_cpu | cut -c 1-3`" = "ppc" -o "`echo $gcc_cpu | cut -c 1-7`" = "powerpc" ]; then # PowerPC build can run on 10.3 CFLAGS="$CFLAGS -mmacosx-version-min=10.3" else # Intel is only available starting from 10.4 CFLAGS="$CFLAGS -mmacosx-version-min=10.4" fi fi fi fi if [ "$os" = "BEOS" ] || [ "$os" = "HAIKU" ]; then LIBS="$LIBS -lmidi -lbe" fi # Most targets act like UNIX, just with some additions if [ "$os" = "BEOS" ] || [ "$os" = "HAIKU" ] || [ "$os" = "OSX" ] || [ "$os" = "MORPHOS" ] || [ "$os" = "FREEBSD" ] || [ "$os" = "DRAGONFLY" ] || [ "$os" = "OPENBSD" ] || [ "$os" = "NETBSD" ] || [ "$os" = "HPUX" ] || [ "$os" = "SUNOS" ] || [ "$os" = "OS2" ]; then CFLAGS="$CFLAGS -DUNIX" fi # And others like Windows if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then CFLAGS="$CFLAGS -DWIN" fi if [ -n "$allegro_config" ]; then CFLAGS="$CFLAGS -DWITH_ALLEGRO" CFLAGS="$CFLAGS `$allegro_config --cflags`" if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then if [ "$enable_static" != "0" ]; then LIBS="$LIBS `$allegro_config --static --libs`" else LIBS="$LIBS `$allegro_config --libs`" fi fi fi if [ -n "$sdl_config" ]; then CFLAGS="$CFLAGS -DWITH_SDL" # SDL must not add _GNU_SOURCE as it breaks many platforms CFLAGS="$CFLAGS `$sdl_config --cflags | sed 's@-D_GNU_SOURCE[^ ]*@@'`" if [ "$os" != "MINGW" ] && [ "$os" != "CYGWIN" ] && [ "$os" != "WINCE" ]; then if [ "$enable_static" != "0" ]; then LIBS="$LIBS `$sdl_config --static-libs`" else LIBS="$LIBS `$sdl_config --libs`" fi fi fi if [ "$with_cocoa" != "0" ]; then CFLAGS="$CFLAGS -DWITH_COCOA" LIBS="$LIBS -F/System/Library/Frameworks -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox" if [ "$enable_cocoa_quartz" != "0" ]; then CFLAGS="$CFLAGS -DENABLE_COCOA_QUARTZ" fi if [ "$enable_cocoa_quickdraw" != "0" ]; then CFLAGS="$CFLAGS -DENABLE_COCOA_QUICKDRAW" fi fi if [ "$with_zlib" != "0" ]; then if [ "$enable_static" != "0" ] && [ "$os" != "OSX" ]; then LIBS="$LIBS $zlib" else LIBS="$LIBS -lz" fi CFLAGS="$CFLAGS -DWITH_ZLIB" fi if [ -n "$lzma_config" ]; then CFLAGS="$CFLAGS -DWITH_LZMA" CFLAGS="$CFLAGS `$lzma_config --cflags | tr '\n\r' ' '`" if [ "$enable_static" != "0" ]; then CFLAGS="$CFLAGS -DLZMA_API_STATIC" LIBS="$LIBS `$lzma_config --libs --static | tr '\n\r' ' '`" else LIBS="$LIBS `$lzma_config --libs | tr '\n\r' ' '`" fi fi if [ "$with_lzo2" != "0" ]; then if [ "$enable_static" != "0" ] && [ "$os" != "OSX" ]; then LIBS="$LIBS $lzo2" else LIBS="$LIBS -llzo2" fi CFLAGS="$CFLAGS -DWITH_LZO" fi if [ -n "$xdg_basedir_config" ]; then CFLAGS="$CFLAGS -DWITH_XDG_BASEDIR" CFLAGS="$CFLAGS `$xdg_basedir_config --cflags | tr '\n\r' ' '`" if [ "$enable_static" != "0" ]; then LIBS="$LIBS `$xdg_basedir_config --libs --static | tr '\n\r' ' '`" else LIBS="$LIBS `$xdg_basedir_config --libs | tr '\n\r' ' '`" fi fi # 64bit machines need -D_SQ64 if [ "$cpu_type" = "64" ] && [ "$enable_universal" = "0" ]; then CFLAGS="$CFLAGS -D_SQ64" fi CFLAGS="$CFLAGS -I$SCRIPT_SRC_DIR" if [ -n "$png_config" ]; then CFLAGS="$CFLAGS -DWITH_PNG" CFLAGS="$CFLAGS `$png_config --cflags | tr '\n\r' ' '`" if [ "$enable_static" != "0" ]; then if [ "$os" = "OSX" ]; then # fontconfig_config goes via pkg-config on all systems, which doesn't know --prefix # Also, despite the reason we link to the .a file ourself (because we can't use -static), we do need to ask pkg-config about possible other deps LIBS="$LIBS `$png_config --variable=prefix`/lib/libpng.a `$png_config --libs --static | sed s@-lpng[0-9]*@@`" else LIBS="$LIBS `$png_config --libs --static | tr '\n\r' ' '`" fi else LIBS="$LIBS `$png_config --libs | tr '\n\r' ' '`" fi fi if [ -n "$fontconfig_config" ]; then CFLAGS="$CFLAGS -DWITH_FONTCONFIG" CFLAGS="$CFLAGS `$fontconfig_config --cflags | tr '\n\r' ' '`" if [ "$enable_static" != "0" ]; then if [ "$os" = "OSX" ]; then # fontconfig_config goes via pkg-config on all systems, which doesn't know --prefix # Also, despite the reason we link to the .a file ourself (because we can't use -static), we do need to ask pkg-config about possible other deps LIBS="$LIBS `$fontconfig_config --variable=prefix`/lib/libfontconfig.a `$fontconfig_config --libs --static | sed s@-lfontconfig@@`" else LIBS="$LIBS `$fontconfig_config --libs --static | tr '\n\r' ' '`" fi else LIBS="$LIBS `$fontconfig_config --libs | tr '\n\r' ' '`" fi fi if [ -n "$freetype_config" ]; then CFLAGS="$CFLAGS -DWITH_FREETYPE" CFLAGS="$CFLAGS `$freetype_config --cflags | tr '\n\r' ' '`" if [ "$enable_static" != "0" ]; then if [ "$os" = "OSX" ]; then LIBS="$LIBS `$freetype_config --prefix`/lib/libfreetype.a" else # Is it possible to do static with freetype, if so: how? LIBS="$LIBS `$freetype_config --libs | tr '\n\r' ' '`" fi else LIBS="$LIBS `$freetype_config --libs | tr '\n\r' ' '`" fi fi if [ -n "$icu_config" ]; then CFLAGS="$CFLAGS -DWITH_ICU" CFLAGS="$CFLAGS `$icu_config --cppflags | tr '\n\r' ' '`" # Some icu-configs have the 'feature' of not adding a space where others do add the space if [ "$static_icu" != "0" ]; then LIBS="$LIBS `$icu_config --ldflags-searchpath` `($icu_config --ldflags-libsonly; $icu_config --ldflags-layout) | tr '\n\r' ' ' | sed s/licu/lsicu/g`" else LIBS="$LIBS `$icu_config --ldflags-searchpath` `($icu_config --ldflags-libsonly; $icu_config --ldflags-layout) | tr '\n\r' ' '`" fi fi if [ "$with_direct_music" != "0" ]; then CFLAGS="$CFLAGS -DWIN32_ENABLE_DIRECTMUSIC_SUPPORT" # GCC 4.0+ doesn't like the DirectX includes (gives tons of # warnings on it we won't be able to fix). For now just # suppress those warnings. if [ $cc_version -ge 40 ]; then CFLAGS="$CFLAGS -Wno-non-virtual-dtor" fi fi if [ -n "$libtimidity" ]; then if [ "$enable_static" != "0" ]; then LIBS="$LIBS $libtimidity" else LIBS="$LIBS -ltimidity" fi CFLAGS="$CFLAGS -DLIBTIMIDITY" fi if [ "$with_iconv" != "0" ]; then CFLAGS="$CFLAGS -DWITH_ICONV" if [ "$link_to_iconv" = "yes" ]; then LIBS="$LIBS -liconv" if [ "$with_iconv" != "2" ]; then CFLAGS="$CFLAGS -I$with_iconv/include" LIBS="$LIBS -L$with_iconv/lib" fi fi if [ "$os" != "OSX" ] && [ "$have_non_const_iconv" != "no" ]; then CFLAGS="$CFLAGS -DHAVE_NON_CONST_ICONV" fi fi if [ -n "$with_midi" ]; then CFLAGS="$CFLAGS -DEXTERNAL_PLAYER=\\\\\"$with_midi\\\\\"" fi if [ -n "$with_midi_arg" ]; then CFLAGS="$CFLAGS -DMIDI_ARG=\\\\\"$with_midi_arg\\\\\"" fi if [ "$enable_dedicated" != "0" ]; then CFLAGS="$CFLAGS -DDEDICATED" fi if [ "$enable_unicode" != "0" ]; then CFLAGS="$CFLAGS -DUNICODE -D_UNICODE" fi if [ "$enable_network" != "0" ]; then CFLAGS="$CFLAGS -DENABLE_NETWORK" if [ "$os" = "BEOS" ]; then LDFLAGS="$LDFLAGS -lbind -lsocket" fi if [ "$os" = "HAIKU" ]; then LDFLAGS="$LDFLAGS -lnetwork" fi if [ "$os" = "SUNOS" ]; then LDFLAGS="$LDFLAGS -lnsl -lsocket" fi fi if [ "$enable_static" != "0" ]; then # OSX can't handle -static in LDFLAGS if [ "$os" != "OSX" ]; then LDFLAGS="$LDFLAGS -static" fi fi if [ "$enable_assert" = "0" ]; then CFLAGS="$CFLAGS -DNDEBUG" CFLAGS_BUILD="$CFLAGS_BUILD -DNDEBUG" fi if [ "$enable_desync_debug" != "0" ]; then CFLAGS="$CFLAGS -DRANDOM_DEBUG" fi if [ "$enable_osx_g5" != "0" ]; then CFLAGS="$CFLAGS -mcpu=G5 -mpowerpc64 -mtune=970 -mcpu=970 -mpowerpc-gpopt" fi if [ -n "$personal_dir" ]; then CFLAGS="$CFLAGS -DWITH_PERSONAL_DIR -DPERSONAL_DIR=\\\\\"$personal_dir\\\\\"" fi if [ -n "$shared_dir" ]; then CFLAGS="$CFLAGS -DWITH_SHARED_DIR -DSHARED_DIR=\\\\\"$shared_dir\\\\\"" fi CFLAGS="$CFLAGS -DGLOBAL_DATA_DIR=\\\\\"$prefix_dir/$data_dir\\\\\"" if [ "$enable_lto" != "0" ]; then lto_build=`echo "$FEATURES_BUILD" | grep "lto"` lto_host=`echo "$FEATURES" | grep "lto"` if [ -z "$lto_build$lto_host" ]; then log 1 "WARNING: you enabled LTO/IPO, but neither build nor host compiler supports it" log 1 "WARNING: LTO/IPO has been disabled" fi if [ -n "$lto_build" ]; then LDFLAGS_BUILD="$LDFLAGS_BUILD $CFLAGS_BUILD $CXXFLAGS_BUILD" fi if [ -n "$lto_host" ]; then LDFLAGS="$LDFLAGS $CFLAGS $CXXFLAGS" fi fi log 1 "using CFLAGS_BUILD... $CFLAGS_BUILD" log 1 "using CXXFLAGS_BUILD... $CXXFLAGS_BUILD" log 1 "using LDFLAGS_BUILD... $LDFLAGS_BUILD" log 1 "using CFLAGS... $CFLAGS" log 1 "using CXXFLAGS... $CXXFLAGS" log 1 "using LDFLAGS... $LIBS $LDFLAGS" # Makedepend doesn't like something like: -isysroot /OSX/blabla # so convert it to: -isysroot -OSX/blabla. makedepend just ignores # any - command it doesn't know, so we are pretty save. # Lovely hackish, not? # Btw, this almost always comes from outside the configure, so it is # not something we can control. # Also make makedepend aware of compiler's built-in defines. if [ "$with_makedepend" != "0" ] || [ "$enable_builtin_depend" != "0" ]; then # Append CXXFLAGS possibly containing -std=c++0x cflags_makedep="`echo | $cxx_host $CXXFLAGS -E -x c++ -dM - | sed 's@.define @-D@g;s@ .*@ @g;s@(.*)@@g' | tr -d '\r\n'`" # Please escape ALL " within ` because e.g. "" terminates the string in some sh implementations cflags_makedep="$cflags_makedep `echo \"$CFLAGS\" \"$CXXFLAGS\" | sed 's@ /@ -@g;s@-I[ ]*[^ ]*@@g'`" else makedepend="" fi if [ "$with_distcc" != "0" ]; then cc_host="$distcc $cc_host" cxx_host="$distcc $cxx_host" log 1 "" log 1 " NOTICE: remind yourself to use 'make -jN' to make use of distcc" log 1 "" fi if [ "$with_ccache" != "0" ]; then cc_host="$ccache $cc_host" cxx_host="$ccache $cxx_host" fi } check_compiler() { # Params: # $1 - Type for message (build / host) # $2 - What to fill with the found compiler # $3 - System to try # $4 - Compiler to try # $5 - Env-setting to try # $6 - GCC alike to try # $7 - CC alike to try # $8 - "0" gcc, "1" g++, "2" windres, "3" strip, "4" lipo # $9 - What the command is to check for if [ -n "$3" ]; then # Check for system if [ -z "$6" ]; then compiler="$3" else compiler="$3-$6" fi machine=`eval $compiler $9 2>/dev/null` ret=$? eval "$2=\"$compiler\"" log 2 "executing $compiler $9" log 2 " returned $machine" log 2 " exit code $ret" if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then log 1 "checking $1... $compiler not found" log 1 "I couldn't detect any $6 binary for $3" exit 1 fi if [ "$machine" != "$3" ] && ( [ "$8" = "0" ] || [ "$8" = "1" ] ); then log 1 "checking $1... expected $3, found $machine" log 1 "the compiler suggests it doesn't build code for the machine you specified" exit 1 fi elif [ -n "$4" ]; then # Check for manual compiler machine=`$4 $9 2>/dev/null` ret=$? eval "$2=\"$4\"" log 2 "executing $4 $9" log 2 " returned $machine" log 2 " exit code $ret" if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then log 1 "checking $1... $4 not found" log 1 "the selected binary doesn't seem to be a $6 binary" exit 1 fi else # Nothing given, autodetect if [ -n "$5" ]; then machine=`$5 $9 2>/dev/null` ret=$? eval "$2=\"$5\"" log 2 "executing $5 $9" log 2 " returned $machine" log 2 " exit code $ret" # The user defined a GCC that doesn't reply to $9.. abort if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then log 1 "checking $1... $5 unusable" log 1 "the CC environment variable is set, but it doesn't seem to be a $6 binary" log 1 "please redefine the CC/CXX environment to a $6 binary" exit 1 fi else log 2 "checking $1... CC/CXX not set (skipping)" # No $5, so try '$6' machine=`$6 $9 2>/dev/null` ret=$? eval "$2=\"$6\"" log 2 "executing $6 $9" log 2 " returned $machine" log 2 " exit code $ret" if ( [ -z "$machine" ] && [ "$8" != "3" ] ) || [ "$ret" != "0" ]; then # Maybe '$7'? machine=`$7 $9 2>/dev/null` ret=$? eval "$2=\"$7\"" log 2 "executing $7 $9" log 2 " returned $machine" log 2 " exit code $ret" # All failed, abort if [ -z "$machine" ]; then log 1 "checking $1... $6 not found" log 1 "I couldn't detect any $6 binary on your system" log 1 "please define the CC/CXX environment to where it is located" exit 1 fi fi fi fi if [ "$8" != "0" ]; then eval "res=\$$2" log 1 "checking $1... $res" else log 1 "checking $1... $machine" fi } check_build() { if [ "$os" = "FREEBSD" ]; then # FreeBSD's C compiler does not support dump machine. # However, removing C support is not possible because PSP must be linked with the C compiler. check_compiler "build system type" "cc_build" "$build" "$cc_build" "$CXX" "g++" "c++" "0" "-dumpmachine" else check_compiler "build system type" "cc_build" "$build" "$cc_build" "$CC" "gcc" "cc" "0" "-dumpmachine" fi } check_host() { # By default the host is the build if [ -z "$host" ]; then host="$build"; fi if [ "$os" = "FREEBSD" ]; then # FreeBSD's C compiler does not support dump machine. # However, removing C support is not possible because PSP must be linked with the C compiler. check_compiler "host system type" "cc_host" "$host" "$cc_host" "$CXX" "g++" "c++" "0" "-dumpmachine" else check_compiler "host system type" "cc_host" "$host" "$cc_host" "$CC" "gcc" "cc" "0" "-dumpmachine" fi } check_cxx_build() { check_compiler "build c++" "cxx_build" "$build" "$cxx_build" "$CXX" "g++" "c++" 1 "-dumpmachine" } check_cxx_host() { # By default the host is the build if [ -z "$host" ]; then host="$build"; fi check_compiler "host c++" "cxx_host" "$host" "$cxx_host" "$CXX" "g++" "c++" 1 "-dumpmachine" } check_windres() { if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then check_compiler "host windres" "windres" "$host" "$windres" "$WINDRES" "windres" "windres" "2" "-V" fi } check_strip() { if [ "$os" = "OS2" ]; then # OS2 via gcc is a bit weird.. stripping HAS to be done via emxbind, which is via gcc directly log 1 "checking host strip... using gcc -s option" elif [ "$os" = "OSX" ]; then # Most targets have -V in strip, to see if they exists... OSX doesn't.. so execute something echo "int main(int argc, char *argv[]) { }" > strip.test.c $cxx_host strip.test.c -o strip.test check_compiler "host strip" "strip" "$host" "$strip" "$STRIP" "strip" "strip" "3" "strip.test" rm -f strip.test.c strip.test else check_compiler "host strip" "strip" "$host" "$strip" "$STRIP" "strip" "strip" "3" "-V" fi } check_lipo() { if [ "$os" = "OSX" ] && [ "$enable_universal" != "0" ]; then echo "int main(int argc, char *argv[]) { }" > lipo.test.c $cxx_host lipo.test.c -o lipo.test check_compiler "host lipo" "lipo" "$host" "$lipo" "$LIPO" "lipo" "lipo" "4" "-info lipo.test" rm -f lipo.test.c lipo.test fi } check_osx_sdk() { local sysroot="" if [ -n "$1" ]; then if echo "$1" | grep -q / ; then # Seems to be a file system path osx_sdk_path="$1" else osx_sdk_path="/Developer/SDKs/MacOSX$1.sdk" fi if [ ! -d "$osx_sdk_path" ]; then # No directory, not present or garbage return 1 fi # Set minimum version to 10.4 as that's when kCGBitmapByteOrder32Host was introduced sysroot="-isysroot $osx_sdk_path -Wl,-syslibroot,$osx_sdk_path -mmacosx-version-min=10.4" fi cat > tmp.osx.mm << EOF #include int main() { kCGBitmapByteOrder32Host; return 0; } EOF execute="$cxx_host $sysroot $CFLAGS tmp.osx.mm -framework Cocoa -o tmp.osx 2>&1" eval $execute > /dev/null ret=$? log 2 "executing $execute" log 2 " exit code $ret" rm -f tmp.osx.mm tmp.osx return $ret } check_direct_music() { echo " #include #include #include #include #include int main(int argc, char *argv[]) { }" > direct_music.test.c $cxx_host $CFLAGS direct_music.test.c -o direct_music.test 2> /dev/null res=$? rm -f direct_music.test.c direct_music.test if [ "$res" != "0" ]; then if [ "$with_direct_music" != "1" ]; then log 1 "configure: error: direct-music is not available on this system" exit 1 fi with_direct_music="0" log 1 "checking direct-music... not found" else log 1 "checking direct-music... found" fi } check_makedepend() { if [ "$enable_builtin_depend" != "0" ]; then with_makedepend="0" fi if [ "$with_makedepend" = "0" ]; then log 1 "checking makedepend... disabled" return fi if [ "$with_makedepend" = "1" ] || [ "$with_makedepend" = "2" ]; then makedepend="makedepend" else makedepend="$with_makedepend" fi rm -f makedepend.tmp touch makedepend.tmp res=`$makedepend -fmakedepend.tmp 2>/dev/null` res=$? log 2 "executing $makedepend -f makedepend.tmp" log 2 " returned `cat makedepend.tmp`" log 2 " exit code $ret" if [ ! -s makedepend.tmp ]; then rm -f makedepend.tmp makedepend.tmp.bak if [ "$with_makedepend" = "2" ]; then log 1 "checking makedepend... not found" log 1 "I couldn't detect any makedepend on your system" log 1 "please locate it via --makedepend=[binary]" exit 1 elif [ "$with_makedepend" != "1" ]; then log 1 "checking makedepend... $makedepend not found" log 1 "the selected file doesn't seem to be a valid makedepend binary" exit 1 else log 1 "checking makedepend... not found" with_makedepend="0" return fi fi rm -f makedepend.tmp makedepend.tmp.bak log 1 "checking makedepend... $makedepend" } check_version() { # $1 - requested version (major.minor) # $2 - version we got (major.minor) if [ -z "$2" ]; then return 0 fi req_major=`echo $1 | cut -d. -f1` got_major=`echo $2 | cut -d. -f1` if [ $got_major -lt $req_major ]; then return 0 elif [ $got_major -gt $req_major ]; then return 1 fi req_minor=`echo $1 | cut -d. -f2` got_minor=`echo $2 | cut -d. -f2` if [ $got_minor -lt $req_minor ]; then return 0 fi return 1 } detect_awk() { # Not all awks allow gsub(), so we test for that here! It is in fact all we need... # These awks are known to work. Test for them explicit awks="gawk mawk nawk" awk_prefix="echo \"a.c b.c c.c\" | tr ' ' \\\\n | " awk_param="' { ORS = \" \" } /\.c$/ { gsub(\".c$\", \".o\", \$0); print \$0; }' 2>/dev/null" awk_result="a.o b.o c.o " log 2 "Detecing awk..." log 2 "Trying: $awk_prefix $awk $awk_param" res=`eval $awk_prefix $awk $awk_param` log 2 "Result: '$res'" if [ "$res" != "$awk_result" ] && [ "$awk" = "awk" ]; then # User didn't supply his own awk, so try to detect some other known working names for an awk for awk in $awks; do log 2 "Trying: $awk_prefix $awk $awk_param" res=`eval $awk_prefix $awk $awk_param` log 2 "Result: '$res'" if [ "$res" = "$awk_result" ]; then break; fi done if [ "$res" != "$awk_result" ]; then log 1 "checking awk... not found" log 1 "configure: error: no awk found" log 1 "configure: error: please install one of the following: $awks" exit 1 fi fi if [ "$res" != "$awk_result" ]; then log 1 "checking awk... not found" log 1 "configure: error: you supplied '$awk' but it doesn't seem a valid gawk or mawk" exit 1 fi log 1 "checking awk... $awk" } detect_os() { if [ "$os" = "DETECT" ]; then # Detect UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, HPUX, MORPHOS, BEOS, SUNOS, CYGWIN, MINGW, OS2, DOS, WINCE, and PSP # Try first via dumpmachine, then via uname os=`echo "$host" | tr '[A-Z]' '[a-z]' | $awk ' /linux/ { print "UNIX"; exit} /darwin/ { print "OSX"; exit} /freebsd/ { print "FREEBSD"; exit} /dragonfly/ { print "DRAGONFLY"; exit} /openbsd/ { print "OPENBSD"; exit} /netbsd/ { print "NETBSD"; exit} /hp-ux/ { print "HPUX"; exit} /morphos/ { print "MORPHOS"; exit} /beos/ { print "BEOS"; exit} /haiku/ { print "HAIKU"; exit} /sunos/ { print "SUNOS"; exit} /solaris/ { print "SUNOS"; exit} /cygwin/ { print "CYGWIN"; exit} /mingw/ { print "MINGW"; exit} /os2/ { print "OS2"; exit} /dos/ { print "DOS"; exit} /wince/ { print "WINCE"; exit} /psp/ { print "PSP"; exit} '` if [ -z "$os" ]; then os=`LC_ALL=C uname | tr '[A-Z]' '[a-z]' | $awk ' /linux/ { print "UNIX"; exit} /darwin/ { print "OSX"; exit} /freebsd/ { print "FREEBSD"; exit} /dragonfly/ { print "DRAGONFLY"; exit} /openbsd/ { print "OPENBSD"; exit} /netbsd/ { print "NETBSD"; exit} /hp-ux/ { print "HPUX"; exit} /morphos/ { print "MORPHOS"; exit} /beos/ { print "BEOS"; exit} /haiku/ { print "HAIKU"; exit} /sunos/ { print "SUNOS"; exit} /cygwin/ { print "CYGWIN"; exit} /mingw/ { print "MINGW"; exit} /os\/2/ { print "OS2"; exit} /gnu/ { print "UNIX"; exit} '` fi if [ -z "$os" ]; then log 1 "detecting OS... none detected" log 1 "I couldn't detect your OS. Please use --os=OS to force one" log 1 "Allowed values are: UNIX, OSX, FREEBSD, DRAGONFLY, OPENBSD, NETBSD, MORPHOS, HPUX, BEOS, HAIKU, SUNOS, CYGWIN, MINGW, OS2, DOS, WINCE, and PSP" exit 1 fi log 1 "detecting OS... $os" else log 1 "forcing OS... $os" fi } detect_allegro() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_allegro" = "0" ]; then log 1 "checking Allegro... disabled" allegro_config="" return 0 fi if [ "$with_allegro" = "2" ] && [ "$with_cocoa" = "2" ]; then log 1 "configure: error: it is impossible to compile both Allegro and COCOA" log 1 "configure: error: please deselect one of them and try again" exit 1 fi if [ "$with_allegro" = "2" ] && [ "$enable_dedicated" != "0" ]; then log 1 "configure: error: it is impossible to compile a dedicated with Allegro" log 1 "configure: error: please deselect one of them and try again" exit 1 fi if [ "$enable_dedicated" != "0" ]; then log 1 "checking Allegro... dedicated server, skipping" allegro_config="" return 0 fi # By default on OSX we don't use SDL. The rest is auto-detect if [ "$with_allegro" = "1" ] && [ "$os" = "OSX" ] && [ "$with_cocoa" != "0" ]; then log 1 "checking Allegro... OSX, skipping" allegro_config="" return 0 fi if [ "$with_allegro" = "1" ] || [ "$with_allegro" = "" ] || [ "$with_allegro" = "2" ]; then allegro_config="allegro-config" else allegro_config="$with_allegro" fi version=`$allegro_config --version 2>/dev/null` ret=$? log 2 "executing $allegro_config --version" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ]; then log 1 "checking Allegro... not found" # It was forced, so it should be found. if [ "$with_allegro" != "1" ]; then log 1 "configure: error: allegro-config couldn't be found" log 1 "configure: error: you supplied '$with_allegro', but it seems invalid" exit 1 fi allegro_config="" return 0 fi log 1 "checking Allegro... found" } detect_sdl() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_sdl" = "0" ]; then log 1 "checking SDL... disabled" sdl_config="" return 0 fi if [ "$with_sdl" = "2" ] && [ "$with_cocoa" = "2" ]; then log 1 "configure: error: it is impossible to compile both SDL and COCOA" log 1 "configure: error: please deselect one of them and try again" exit 1 fi if [ "$with_sdl" = "2" ] && [ "$enable_dedicated" != "0" ]; then log 1 "configure: error: it is impossible to compile a dedicated with SDL" log 1 "configure: error: please deselect one of them and try again" exit 1 fi if [ "$enable_dedicated" != "0" ]; then log 1 "checking SDL... dedicated server, skipping" sdl_config="" return 0 fi # By default on OSX we don't use SDL. The rest is auto-detect if [ "$with_sdl" = "1" ] && [ "$os" = "OSX" ] && [ "$with_cocoa" != "0" ]; then log 1 "checking SDL... OSX, skipping" sdl_config="" return 0 fi if [ "$os" = "OSX" ]; then log 1 "WARNING: sdl is known to fail on some versions of Mac OS X" log 1 "WARNING: with some hardware configurations. Use at own risk!" sleep 5 fi if [ "$with_sdl" = "1" ] || [ "$with_sdl" = "" ] || [ "$with_sdl" = "2" ]; then sdl_config="sdl-config" else sdl_config="$with_sdl" fi version=`$sdl_config --version 2>/dev/null` ret=$? log 2 "executing $sdl_config --version" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ]; then log 1 "checking SDL... not found" # It was forced, so it should be found. if [ "$with_sdl" != "1" ]; then log 1 "configure: error: sdl-config couldn't be found" log 1 "configure: error: you supplied '$with_sdl', but it seems invalid" exit 1 fi sdl_config="" return 0 fi log 1 "checking SDL... found" } detect_osx_sdk() { # Try to find the best SDK available. For a normal build this # is currently the 10.5 SDK as this is needed to compile all # optional code. Because such an executable won't run on 10.4 # or lower, also check for the 10.4u SDK when doing an universal # build. # Check for the 10.5 SDK, but try 10.6 if that fails check_osx_sdk "10.5" || check_osx_sdk "10.6" || osx_sdk_path="" if [ -z "$osx_sdk_path" ] || [ "$enable_universal" != "0" ]; then # No better SDK or universal build enabled? Check 10.4u SDK as well local old_sdk="$osx_sdk_path" if check_osx_sdk "10.4u"; then osx_sdk_104_path="$osx_sdk_path" else osx_sdk_104_path="" fi if [ -z "$old_sdk" ]; then osx_sdk_path="$osx_sdk_104_path" else osx_sdk_path="$old_sdk" fi fi if [ -z "$osx_sdk_path" ]; then log 1 "Your system SDK is probably too old" log 1 "Please install/upgrade your Xcode to >= 2.5" exit 1 fi } detect_cocoa() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_cocoa" = "0" ]; then log 1 "checking COCOA... disabled" return 0 fi if [ "$with_cocoa" = "2" ] && [ "$enable_dedicated" != "0" ]; then log 1 "configure: error: it is impossible to compile a dedicated with COCOA" log 1 "configure: error: please deselect one of them and try again" exit 1 fi if [ "$enable_dedicated" != "0" ]; then log 1 "checking COCOA... dedicated server, skipping" with_cocoa="0" return 0 fi # By default on OSX we use COCOA. The rest doesn't support it if [ "$with_cocoa" = "1" ] && [ "$os" != "OSX" ]; then log 1 "checking COCOA... not OSX, skipping" with_cocoa="0" return 0 fi if [ "$os" != "OSX" ]; then log 1 "checking COCOA... not OSX" log 1 "configure: error: COCOA video driver is only supported for OSX" exit 1 fi log 1 "checking COCOA... found" if [ "$enable_cocoa_quartz" != "0" ]; then log 1 "checking whether to enable the Quartz window subdriver... yes" else log 1 "checking whether to enable the Quartz window subdriver... no" fi detect_quickdraw } detect_quickdraw() { # 0 means no, 1 is auto-detect, 2 is force if [ "$enable_cocoa_quickdraw" = "0" ]; then log 1 "checking Quickdraw window subdriver... disabled" return 0 fi # Assume QuickDraw is available when doing an universal build if [ "$enable_universal" != "0" ]; then log 1 "checking Quickdraw window subdriver... found" return 0 fi # 64 bits doesn't have quickdraw if [ "$cpu_type" = "64" ]; then enable_cocoa_quickdraw="0" log 1 "checking Quickdraw window subdriver... disabled (64 bits)" return 0 fi cat > tmp.osx.mm << EOF #include #import int main(int argc, char *argv[]) { SetEmptyRgn(NULL); return 0; } EOF execute="$cxx_host $OSX_SYSROOT $OSX_LD_SYSROOT $CFLAGS -mmacosx-version-min=10.3 tmp.osx.mm -framework Cocoa -o tmp.osx 2>&1" eval $execute > /dev/null ret=$? log 2 "executing $execute" log 2 " exit code $ret" rm -f tmp.osx.mm tmp.osx if [ "$ret" != "0" ]; then log 1 "checking Quickdraw window subdriver... not found" # It was forced, so it should be found. if [ "$enable_cocoa_quickdraw" != "1" ]; then log 1 "configure: error: Quickdraw window driver could not be found" exit 1 fi enable_cocoa_quickdraw=0 return 0 fi enable_cocoa_quickdraw=1 log 1 "checking Quickdraw window subdriver... found" } detect_library() { # $1 - config-param ($with_zlib value) # $2 - library name ('zlib', sets $zlib) # $3 - static library name (libz.a) # $4 - header directory () # $5 - header name (zlib.h) # $6 - force static (if non-empty) if [ -n "$6" ]; then force_static="1"; fi # 0 means no, 1 is auto-detect, 2 is force if [ "$1" = "0" ]; then log 1 "checking $2... disabled" eval "$2=\"\"" return 0 fi log 2 "detecting $2" if [ "$1" = "1" ] || [ "$1" = "" ] || [ "$1" = "2" ]; then eval "$2=`ls -1 /usr/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /usr/include/$4$5... no" eval "$2=`ls -1 /usr/local/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" fi eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /usr/local/include/$4$5... no" eval "$2=`ls -1 /mingw/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" fi eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /mingw/include/$4$5... no" eval "$2=`ls -1 /opt/local/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" fi eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /opt/local/include/$4$5... no" fi if [ -z "$res" ] && [ "$os" = "NETBSD" ]; then eval "$2=`ls -1 /usr/pkg/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /usr/pkg/include/$4$5... no" fi fi if [ -z "$res" ] && [ "$os" = "HAIKU" ]; then eval "$2=`ls -1 /boot/common/include/$4*.h 2>/dev/null | egrep \"\/$5\$\"`" eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /boot/common/include/$4$5... no" fi fi eval "res=\$$2" if [ -n "$res" ] && ( [ -n "$force_static" ] || ( [ "$enable_static" != "0" ] && [ "$os" != "OSX" ] ) ); then eval "res=\$$2" log 2 " trying $res... found" # Now find the static lib, if needed eval "$2=`ls /lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /lib/$3... no" eval "$2=`ls /usr/lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" fi eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /usr/lib/$3... no" eval "$2=`ls /usr/local/lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" fi eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /usr/local/lib/$3... no" eval "$2=`ls /mingw/lib/*.a 2>/dev/null | egrep \"\/$3\$\"`" fi eval "res=\$$2" if [ -z "$res" ]; then log 2 " trying /mingw/lib/$3... no" log 1 "configure: error: $2 couldn't be found" log 1 "configure: error: you requested a static link, but I can't find $3" exit 1 fi fi else # Make sure it exists if [ -f "$1" ]; then eval "$2=`ls $1 2>/dev/null`" else eval "$2=`ls $1/$3 2>/dev/null`" fi fi eval "res=\$$2" if [ -z "$res" ]; then log 1 "checking $2... not found" if [ "$1" = "2" ]; then log 1 "configure: error: $2 couldn't be found" exit 1 elif [ "$1" != "1" ]; then log 1 "configure: error: $2 couldn't be found" log 1 "configure: error: you supplied '$1', but it seems invalid" exit 1 fi eval "with_$2=0" return 0 fi eval "res=\$$2" log 2 " trying $res... found" log 1 "checking $2... found" } detect_zlib() { detect_library "$with_zlib" "zlib" "libz.a" "" "zlib.h" } detect_lzo2() { detect_library "$with_lzo2" "lzo2" "liblzo2.a" "lzo/" "lzo1x.h" } detect_libtimidity() { detect_library "$with_libtimidity" "libtimidity" "libtimidity.a" "" "timidity.h" } detect_pkg_config() { # $1 - config-param ($with_lzma value) # $2 - package name ('liblzma') # $3 - config name ('lzma_config', sets $lzma_config) # $4 - minimum module version ('2.3') # 0 means no, 1 is auto-detect, 2 is force if [ "$1" = "0" ]; then log 1 "checking $2... disabled" eval "$3=\"\"" return 0 fi log 2 "detecting $2" if [ "$1" = "1" ] || [ "$1" = "" ] || [ "$1" = "2" ]; then pkg_config_call="pkg-config $2" else pkg_config_call="$1" fi version=`$pkg_config_call --modversion 2>/dev/null` ret=$? check_version "$4" "$version" version_ok=$? log 2 "executing $pkg_config_call --modversion" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version_ok" != "1" ]; then if [ -n "$version" ] && [ "$version_ok" != "1" ]; then log 1 "checking $2... needs at least version $4, $2 NOT enabled" else log 1 "checking $2... not found" fi # It was forced, so it should be found. if [ "$1" != "1" ]; then log 1 "configure: error: pkg-config $2 couldn't be found" log 1 "configure: error: you supplied '$1', but it seems invalid" exit 1 fi eval "$3=\"\"" return 0 fi eval "$3=\"$pkg_config_call\"" log 1 "checking $2... found" } detect_lzma() { detect_pkg_config "$with_lzma" "liblzma" "lzma_config" "5.0" } detect_xdg_basedir() { detect_pkg_config "$with_xdg_basedir" "libxdg-basedir" "xdg_basedir_config" "1.2" } detect_png() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_png" = "0" ]; then log 1 "checking libpng... disabled" png_config="" return 0 fi if [ "$with_zlib" = "0" ] || [ -z "$zlib" ]; then if [ "$with_png" != "1" ]; then log 1 "checking libpng... no zlib" log 1 "ERROR: libpng was forced, but zlib was not detected / disabled." log 1 "ERROR: libpng depends on zlib." exit 1 fi log 1 "checking libpng... no zlib, skipping" png_config="" return 0 fi detect_pkg_config "$with_png" "libpng" "png_config" "1.2" } detect_freetype() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_freetype" = "0" ]; then log 1 "checking libfreetype... disabled" freetype_config="" return 0 fi if [ "$with_freetype" = "1" ] && [ "$enable_dedicated" != "0" ]; then log 1 "checking libfreetype... dedicated server, skipping" freetype_config="" return 0 fi if [ "$with_zlib" = "0" ] || [ -z "$zlib" ]; then if [ "$with_freetype" != "1" ]; then log 1 "checking libfreetype... no zlib" log 1 "ERROR: libfreetype was forced, but zlib was not detected / disabled." log 1 "ERROR: libfreetype depends on zlib." exit 1 fi log 1 "checking libfreetype... no zlib, skipping" freetype_config="" return 0 fi if [ "$with_freetype" = "1" ] || [ "$with_freetype" = "" ] || [ "$with_freetype" = "2" ]; then freetype_config="freetype-config" else freetype_config="$with_freetype" fi version=`$freetype_config --version 2>/dev/null` ret=$? log 2 "executing freetype_config --version" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ]; then log 1 "checking libfreetype... not found" # It was forced, so it should be found. if [ "$with_freetype" != "1" ]; then log 1 "configure: error: freetype-config couldn't be found" log 1 "configure: error: you supplied '$with_freetype', but it seems invalid" exit 1 fi freetype_config="" return 0 fi log 1 "checking libfreetype... found" } detect_fontconfig() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_fontconfig" = "0" ]; then log 1 "checking libfontconfig... disabled" fontconfig_config="" return 0 fi if [ "$with_fontconfig" = "1" ] && [ "$enable_dedicated" != "0" ]; then log 1 "checking libfontconfig... dedicated server, skipping" fontconfig_config="" return 0 fi if [ "$with_fontconfig" != "2" ] && [ -z "$freetype_config" ]; then log 1 "checking libfontconfig... no freetype, skipping" fontconfig_config="" return 0 fi if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "WINCE" ]; then log 1 "checking libfontconfig... WIN32, skipping" fontconfig_config="" return 0 fi if [ "$os" = "OSX" ]; then log 1 "checking libfontconfig... OSX, skipping" fontconfig_config="" return 0 fi detect_pkg_config "$with_fontconfig" "fontconfig" "fontconfig_config" "2.3" } detect_icu() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_icu" = "0" ]; then log 1 "checking libicu... disabled" icu_config="" return 0 fi if [ "$with_icu" = "1" ] && [ "$enable_dedicated" != "0" ]; then log 1 "checking libicu... dedicated server, skipping" icu_config="" return 0 fi if [ "$with_icu" = "1" ] || [ "$with_icu" = "" ] || [ "$with_icu" = "2" ]; then icu_config="icu-config" else icu_config="$with_icu" fi version=`$icu_config --version 2>/dev/null` ret=$? check_version '3.6' "$version" version_ok=$? log 2 "executing $icu_config --version" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version_ok" != "1" ]; then if [ -n "$version" ] && [ "$version_ok" != "1" ]; then log 1 "checking libicu... needs at least version 3.6.0, icu NOT enabled" else log 1 "checking libicu... not found" fi # It was forced, so it should be found. if [ "$with_icu" != "1" ]; then log 1 "configure: error: icu-config couldn't be found" log 1 "configure: error: you supplied '$with_icu', but it seems invalid" exit 1 fi icu_config="" return 0 fi log 1 "checking libicu... found" } detect_pspconfig() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_psp_config" = "0" ]; then log 1 "checking psp-config... disabled" psp_config="" return 0 fi if [ "$with_psp_config" = "1" ] && [ "$os" != "PSP" ]; then log 1 "checking psp-config... not PSP, skipping" psp_config=""; return 0 fi if [ "$os" != "PSP" ]; then log 1 "checking psp-config... not PSP" log 1 "configure: error: psp-config is only supported for PSP" exit 1 fi if [ "$with_psp_config" = "1" ] || [ "$with_psp_config" = "" ] || [ "$with_psp_config" = "2" ]; then psp_config="psp-config" else psp_config="$with_psp_config" fi version=`$psp_config -p 2>/dev/null` ret=$? log 2 "executing $psp_config -p" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ]; then log 1 "checking psp-config... not found" log 1 "configure: error: psp-config couldn't be found" # It was forced, so it should be found. if [ "$with_psp_config" != "1" ]; then log 1 "configure: error: you supplied '$with_psp_config', but it seems invalid" fi exit 1 fi log 1 "checking psp-config... found" } detect_iconv() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_iconv" = "0" ]; then log 1 "checking iconv... disabled" return 0 fi if [ "$with_iconv" = "1" ] && [ "$os" != "OSX" ]; then log 1 "checking iconv... not OSX, skipping" with_iconv="0" return 0 fi # Try to find iconv.h, seems to only thing to detect iconv with if [ "$with_iconv" = "1" ] || [ "$with_iconv" = "" ] || [ "$with_iconv" = "2" ]; then iconv=`ls -1 /usr/include 2>/dev/null | grep "iconv.h"` if [ -z "$iconv" ]; then iconv=`ls -1 /usr/local/include 2>/dev/null | grep "iconv.h"` fi else # Make sure it exists iconv=`ls $with_iconv/include/iconv.h 2>/dev/null` fi if [ -z "$iconv" ]; then log 1 "checking iconv... not found" if [ "$with_iconv" = "2" ]; then log 1 "configure: error: iconv couldn't be found" exit 1 elif [ "$with_iconv" != "1" ]; then log 1 "configure: error: iconv couldn't be found" log 1 "configure: error: you supplied '$with_iconv', but I couldn't detect iconv in it" exit 1 fi return 0 fi if [ "$with_iconv" = "1" ]; then with_iconv="2" fi log 2 "found iconv in $iconv" log 1 "checking iconv... found" # There are different implementations of iconv. The older ones, # e.g. SUSv2, pass a const pointer, whereas the newer ones, e.g. # IEEE 1003.1 (2004), pass a non-const pointer. cat > tmp.iconv.cpp << EOF #include "src/stdafx.h" #include int main() { static char buf[1024]; iconv_t convd = 0; const char *inbuf = ""; char *outbuf = buf; size_t outlen = 1023; size_t inlen = 0; return iconv(convd, &inbuf, &inlen, &outbuf, &outlen); } EOF execute="$cxx_host $OSX_SYSROOT $CFLAGS -c tmp.iconv.cpp -o tmp.iconv -DTESTING 2>&1" eval $execute > /dev/null ret=$? log 2 "executing $execute" log 2 " exit code $ret" if [ "$ret" = "0" ]; then have_non_const_iconv="no"; else have_non_const_iconv="yes"; fi log 1 "checking if iconv has non-const inbuf... $have_non_const_iconv" cat > tmp.iconv.cpp << EOF #include "src/stdafx.h" #include int main() { static char buf[1024]; iconv_t convd = 0; char *inbuf = ""; char *outbuf = buf; size_t outlen = 1023; size_t inlen = 0; return iconv(convd, &inbuf, &inlen, &outbuf, &outlen); } EOF execute="$cxx_host $OSX_SYSROOT $OSX_LD_SYSROOT $CFLAGS tmp.iconv.cpp -o tmp.iconv -DTESTING 2>&1" eval $execute > /dev/null ret=$? log 2 "executing $execute" log 2 " exit code $ret" if [ "$ret" = "0" ]; then link_to_iconv="no"; else link_to_iconv="yes"; fi log 1 "checking whether to link to iconv... $link_to_iconv" rm -f tmp.iconv tmp.iconv.cpp } _detect_sort() { sort_test_in="d a c b" sort_test_out="a b c d" log 2 "running echo | $1" if [ "`echo \"$sort_test_in\" | $1 2>/dev/null`" = "$sort_test_out" ]; then sort="$1" log 2 " result was valid" else log 2 " result was invalid" fi } detect_sort() { if [ "$with_sort" = "0" ]; then log 1 "checking sort... disabled" return fi if [ "$with_sort" = "1" ] || [ "$with_sort" = "2" ]; then _detect_sort "sort" if [ -z "$sort" ]; then _detect_sort "/sbin/sort"; fi if [ -z "$sort" ]; then _detect_sort "/usr/sbin/sort"; fi if [ -z "$sort" ]; then _detect_sort "/usr/local/sbin/sort"; fi if [ -z "$sort" ]; then _detect_sort "/bin/sort"; fi if [ -z "$sort" ]; then _detect_sort "/usr/bin/sort"; fi if [ -z "$sort" ]; then _detect_sort "/usr/local/bin/sort"; fi else _detect_sort "$with_sort" fi if [ -z "$sort" ]; then if [ "$with_sort" = "2" ]; then log 1 "checking sort... not found" log 1 "configure: error: couldn't detect sort on your system" exit 1 elif [ "$with_sort" != "1" ]; then log 1 "checking sort... $with_sort not found" log 1 "configure: error: '$with_sort' doesn't look like a sort to me" log 1 "configure: error: please verify its location and function and try again" exit 1 else log 1 "checking sort... not found" fi else log 1 "checking sort... $sort" fi } detect_grfcodec() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_grfcodec" = "0" ]; then log 1 "checking grfcodec... disabled" grfcodec="" return 0 fi if [ "$with_grfcodec" = "1" ] || [ "$with_grfcodec" = "" ] || [ "$with_grfcodec" = "2" ]; then grfcodec="grfcodec" else grfcodec="$with_grfcodec" fi version=`$grfcodec -v 2>/dev/null | $awk '{print $3}' | sed 's/[rM]//g;s/-/0/'` ret=$? log 2 "executing grfcodec -v" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version" -lt "985" ]; then if [ -n "$version" ] && [ "$version" -lt "985" ]; then log 1 "checking grfcodec... needs at least version 6.0.5 (r985), disabled" else log 1 "checking grfcodec... not found" fi # It was forced, so it should be found. if [ "$with_grfcodec" != "1" ]; then log 1 "configure: error: grfcodec couldn't be found" log 1 "configure: error: you supplied '$with_grfcodec', but it seems invalid" exit 1 fi grfcodec="" return 0 fi log 1 "checking grfcodec... found" } detect_nforenum() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_nforenum" = "0" ]; then log 1 "checking nforenum... disabled" nforenum="" return 0 fi if [ "$with_nforenum" = "1" ] || [ "$with_nforenum" = "" ] || [ "$with_nforenum" = "2" ]; then nforenum="nforenum" else nforenum="$with_nforenum" fi version=`$nforenum -v 2>/dev/null | $awk '{print $3}' | sed 's/[rM]//g;s/-/0/'` ret=$? log 2 "executing nforenum -v" log 2 " returned $version" log 2 " exit code $ret" if [ -z "$version" ] || [ "$ret" != "0" ] || [ "$version" -lt "985" ]; then if [ -n "$version" ] && [ "$version" -lt "985" ]; then log 1 "checking nforenum... needs at least version 6.0.5 (r985), disabled" else log 1 "checking nforenum... not found" fi # It was forced, so it should be found. if [ "$with_nforenum" != "1" ]; then log 1 "configure: error: nforenum couldn't be found" log 1 "configure: error: you supplied '$with_nforenum', but it seems invalid" exit 1 fi nforenum="" return 0 fi log 1 "checking nforenum... found" } detect_cputype() { if [ -n "$cpu_type" ] && [ "$cpu_type" != "DETECT" ]; then log 1 "forcing cpu-type... $cpu_type bits" return; fi echo "#define _SQ64 1" > tmp.64bit.cpp echo "#include \"src/stdafx.h\"" >> tmp.64bit.cpp echo "assert_compile(sizeof(size_t) == 8);" >> tmp.64bit.cpp echo "int main() { return 0; }" >> tmp.64bit.cpp execute="$cxx_host $CFLAGS tmp.64bit.cpp -o tmp.64bit -DTESTING 2>&1" cpu_type="`eval $execute 2>/dev/null`" ret=$? log 2 "executing $execute" log 2 " returned $cpu_type" log 2 " exit code $ret" if [ "$ret" = "0" ]; then cpu_type="64"; else cpu_type="32"; fi log 1 "detecting cpu-type... $cpu_type bits" rm -f tmp.64bit tmp.64bit.cpp } detect_sse_capable_architecture() { # 0 means no, 1 is auto-detect, 2 is force if [ "$with_sse" = "0" ]; then log 1 "checking SSE... disabled" return fi echo "#define _SQ64 1" > tmp.sse.cpp echo "#include " >> tmp.sse.cpp echo "#include " >> tmp.sse.cpp echo "#include " >> tmp.sse.cpp echo "int main() { return 0; }" >> tmp.sse.cpp execute="$cxx_host -msse4.1 $CFLAGS tmp.sse.cpp -o tmp.sse 2>&1" sse="`eval $execute 2>/dev/null`" ret=$? log 2 "executing $execute" log 2 " returned $sse" log 2 " exit code $ret" if [ "$ret" = "0" ]; then log 1 "detecting SSE... found" else # It was forced, so it should be found. if [ "$with_sse" != "1" ]; then log 1 "configure: error: SSE couln't be found" log 1 "configure: error: you force enabled SSE, but it seems unavailable" exit 1 fi log 1 "detecting SSE... not found" with_sse="0" fi rm -f tmp.sse tmp.exe tmp.sse.cpp } make_sed() { T_CFLAGS="$CFLAGS" T_CXXFLAGS="$CXXFLAGS" T_LDFLAGS="$LDFLAGS" SRC_OBJS_DIR="$BASE_SRC_OBJS_DIR/$OBJS_SUBDIR" # All the data needed to compile a single target # Make sure if you compile multiple targets to # use multiple OBJS_DIR, because all in-between # binaries are stored in there, and nowhere else. SRC_REPLACE=" s@!!CC_HOST!!@$cc_host@g; s@!!CXX_HOST!!@$cxx_host@g; s@!!CC_BUILD!!@$cc_build@g; s@!!CXX_BUILD!!@$cxx_build@g; s@!!WINDRES!!@$windres@g; s@!!STRIP!!@$strip $strip_arg@g; s@!!LIPO!!@$lipo@g; s@!!CFLAGS!!@$T_CFLAGS@g; s@!!CFLAGS_BUILD!!@$CFLAGS_BUILD@g; s@!!CXXFLAGS!!@$T_CXXFLAGS@g; s@!!CXXFLAGS_BUILD!!@$CXXFLAGS_BUILD@g; s@!!STRGEN_FLAGS!!@$strgen_flags@g; s@!!LIBS!!@$LIBS@g; s@!!LDFLAGS!!@$T_LDFLAGS@g; s@!!LDFLAGS_BUILD!!@$LDFLAGS_BUILD@g; s@!!BIN_DIR!!@$BIN_DIR@g; s@!!ROOT_DIR!!@$ROOT_DIR@g; s@!!MEDIA_DIR!!@$MEDIA_DIR@g; s@!!SOURCE_LIST!!@$SOURCE_LIST@g; 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; s@!!LANG_DIR!!@$LANG_DIR@g; s@!!TTD!!@$TTD@g; s@!!BINARY_DIR!!@$prefix_dir/$binary_dir@g; s@!!DATA_DIR!!@$prefix_dir/$data_dir@g; s@!!DOC_DIR!!@$prefix_dir/$doc_dir@g; s@!!MAN_DIR!!@$prefix_dir/$man_dir@g; s@!!ICON_DIR!!@$prefix_dir/$icon_dir@g; s@!!ICON_THEME_DIR!!@$prefix_dir/$icon_theme_dir@g; s@!!PERSONAL_DIR!!@$personal_dir@g; s@!!SHARED_DIR!!@$shared_dir@g; s@!!INSTALL_DIR!!@$install_dir@g; s@!!BINARY_NAME!!@$binary_name@g; 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; s@!!CFLAGS_MAKEDEP!!@$cflags_makedep@g; s@!!SORT!!@$sort@g; s@!!CONFIG_CACHE_COMPILER!!@config.cache.compiler@g; s@!!CONFIG_CACHE_LINKER!!@config.cache.linker@g; s@!!CONFIG_CACHE_ENDIAN!!@config.cache.endian@g; s@!!CONFIG_CACHE_SOURCE!!@config.cache.source@g; s@!!CONFIG_CACHE_VERSION!!@config.cache.version@g; s@!!CONFIG_CACHE_SOURCE_LIST!!@config.cache.source.list@g; s@!!CONFIG_CACHE_PWD!!@config.cache.pwd@g; s@!!LANG_SUPPRESS!!@$lang_suppress@g; s@!!OBJS_C!!@$OBJS_C@g; s@!!OBJS_CPP!!@$OBJS_CPP@g; s@!!OBJS_MM!!@$OBJS_MM@g; s@!!OBJS_RC!!@$OBJS_RC@g; s@!!SRCS!!@$SRCS@g; s@!!OS!!@$os@g; s@!!CONFIGURE_FILES!!@$CONFIGURE_FILES@g; s@!!AWK!!@$awk@g; s@!!DISTCC!!@$distcc@g; s@!!NFORENUM!!@$nforenum@g; s@!!GRFCODEC!!@$grfcodec@g; " if [ "$icon_theme_dir" != "" ]; then SRC_REPLACE="$SRC_REPLACE s@!!ICON_THEME_DIR!!@$prefix_dir/$icon_theme_dir@g; " else SRC_REPLACE="$SRC_REPLACE s@!!ICON_THEME_DIR!!@@g; " fi if [ "$man_dir" != "" ]; then SRC_REPLACE="$SRC_REPLACE s@!!MAN_DIR!!@$prefix_dir/$man_dir@g; " else SRC_REPLACE="$SRC_REPLACE s@!!MAN_DIR!!@@g; " fi if [ "$menu_dir" != "" ]; then SRC_REPLACE="$SRC_REPLACE s@!!MENU_DIR!!@$prefix_dir/$menu_dir@g; " else SRC_REPLACE="$SRC_REPLACE s@!!MENU_DIR!!@@g; " fi } generate_menu_item() { MENU_REPLACE=" s@!!TTD!!@$TTD@g; s@!!MENU_GROUP!!@$menu_group@g; s@!!MENU_NAME!!@$menu_name@g " log 1 "Generating menu item..." mkdir -p media < $ROOT_DIR/media/openttd.desktop.in sed "$MENU_REPLACE" > media/openttd.desktop } generate_main() { STAGE="[MAIN]" make_sed # Create the main Makefile log 1 "Generating Makefile..." echo "# Auto-generated file from 'Makefile.in' -- DO NOT EDIT" > Makefile < $ROOT_DIR/Makefile.in sed "$SRC_REPLACE" >> Makefile cp $ROOT_DIR/Makefile.bundle.in Makefile.bundle echo "# Auto-generated file -- DO NOT EDIT" > Makefile.am echo >> Makefile.am # Make the copy of the source-list, so we don't trigger an unwanted recompile cp $SOURCE_LIST config.cache.source.list # Add the current directory, so we don't trigger an unwanted recompile echo "`pwd`" > config.cache.pwd # Make sure config.cache is OLDER then config.cache.source.list touch config.cache touch config.pwd if [ "$menu_dir" != "" ]; then generate_menu_item fi } generate_lang() { STAGE="[LANG]" make_sed # Create the language file mkdir -p $LANG_OBJS_DIR log 1 "Generating lang/Makefile..." echo "# Auto-generated file from 'Makefile.lang.in' -- DO NOT EDIT" > $LANG_OBJS_DIR/Makefile < $ROOT_DIR/Makefile.lang.in sed "$SRC_REPLACE" >> $LANG_OBJS_DIR/Makefile echo "DIRS += $LANG_OBJS_DIR" >> Makefile.am 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="[BASESET]" make_sed # Create the language file mkdir -p $GRF_OBJS_DIR log 1 "Generating grf/Makefile..." echo "# Auto-generated file from 'Makefile.grf.in' -- DO NOT EDIT" > $GRF_OBJS_DIR/Makefile < $ROOT_DIR/Makefile.grf.in sed "$SRC_REPLACE" >> $GRF_OBJS_DIR/Makefile echo "DIRS += $GRF_OBJS_DIR" >> Makefile.am } generate_src_normal() { STAGE=$1 make_sed # Create the source file mkdir -p $SRC_OBJS_DIR log 1 "Generating $2/Makefile..." echo "# Auto-generated file from 'Makefile.src.in' -- DO NOT EDIT" > $SRC_OBJS_DIR/Makefile < $ROOT_DIR/Makefile.src.in sed "$SRC_REPLACE" >> $SRC_OBJS_DIR/Makefile echo "DIRS += $SRC_OBJS_DIR" >> Makefile.am echo "SRC_DIRS += $SRC_OBJS_DIR" >> Makefile.am } generate_src_osx() { cc_host_orig="$cc_host" cxx_host_orig="$cxx_host" CFLAGS_orig="$CFLAGS" LDFLAGS_orig="$LDFLAGS" for type in $enable_universal; do if [ -n "$osx_sdk_104_path" ]; then # Use 10.4 SDK for 32-bit targets CFLAGS="-isysroot $osx_sdk_104_path $CFLAGS_orig" LDFLAGS="-Wl,-syslibroot,$osx_sdk_104_path $LDFLAGS_orig" fi # We don't want to duplicate the x86_64 stuff for each target, so do it once here if [ "$type" = "ppc64" ] || [ "$type" = "x86_64" ]; then # 64 bits is always 10.5 or higher. Furthermore it has a non const ICONV # and they also removed support for QuickTime/QuickDraw if [ -n "$osx_sdk_path" ]; then CFLAGS="-isysroot $osx_sdk_path $CFLAGS_orig" LDFLAGS="-Wl,-syslibroot,$osx_sdk_path $LDFLAGS_orig" fi CFLAGS="$CFLAGS -D_SQ64 -DNO_QUICKTIME -UENABLE_COCOA_QUICKDRAW" LIBS="`echo $LIBS | sed 's/-framework QuickTime//'`" fi case $type in ppc) BASE_SRC_OBJS_DIR="$OBJS_DIR/ppc" cc_host="$cc_host_orig -arch ppc -mmacosx-version-min=10.3" cxx_host="$cxx_host_orig -arch ppc -mmacosx-version-min=10.3" generate_src_normal "[ppc]" "objs/ppc";; ppc970) BASE_SRC_OBJS_DIR="$OBJS_DIR/ppc970" cc_host="$cc_host_orig -arch ppc970 -mmacosx-version-min=10.3 -mcpu=G5 -mpowerpc64 -mtune=970 -mcpu=970 -mpowerpc-gpopt" cxx_host="$cxx_host_orig -arch ppc970 -mmacosx-version-min=10.3 -mcpu=G5 -mpowerpc64 -mtune=970 -mcpu=970 -mpowerpc-gpopt" generate_src_normal "[ppc970]" "objs/ppc970";; i386) BASE_SRC_OBJS_DIR="$OBJS_DIR/i386" cc_host="$cc_host_orig -arch i386 -mmacosx-version-min=10.4" cxx_host="$cxx_host_orig -arch i386 -mmacosx-version-min=10.4" generate_src_normal "[i386]" "objs/i386";; ppc64) BASE_SRC_OBJS_DIR="$OBJS_DIR/ppc64" cc_host="$cc_host_orig -arch ppc64 -mmacosx-version-min=10.5" cxx_host="$cxx_host_orig -arch ppc64 -mmacosx-version-min=10.5" generate_src_normal "[ppc64]" "objs/ppc64";; x86_64) BASE_SRC_OBJS_DIR="$OBJS_DIR/x86_64" cc_host="$cc_host_orig -arch x86_64 -mmacosx-version-min=10.5" cxx_host="$cxx_host_orig -arch x86_64 -mmacosx-version-min=10.5" generate_src_normal "[x86_64]" "objs/x86_64";; *) log 1 "Unknown architecture requested for universal build: $type";; esac done } generate_src() { if [ "$os" = "OSX" ] && [ "$enable_universal" != "0" ]; then generate_src_osx else generate_src_normal "[SRC]" "objs" fi } showhelp() { echo "'configure' configures OpenTTD." echo "" echo "Usage: $0 [OPTION]... [VAR=VALUE]..." echo "" echo "To assign environment variables (e.g., CC, CFLAGS...), specify them as" echo "VAR=VALUE. See below for descriptions of some of the useful variables." echo "" echo "Defaults for the options are specified in brackets." echo "" echo "Configuration:" echo " -h, --help display this help and exit" echo "" echo "System types:" echo " --build=BUILD configure for building on BUILD [guessed]" echo " --host=HOST cross-compile to build programs to run" echo " on HOST [BUILD]" echo " --windres=WINDRES the windres to use [HOST-windres]" echo " --strip=STRIP the strip to use [HOST-strip]" echo " --awk=AWK the awk to use in configure [awk]" echo " --lipo=LIPO the lipo to use (OSX ONLY) [HOST-lipo]" echo " --os=OS the OS we are compiling for [DETECT]" echo " DETECT/UNIX/OSX/FREEBSD/DRAGONFLY/OPENBSD/" echo " NETBSD/MORPHOS/HPUX/BEOS/SUNOS/CYGWIN/" echo " MINGW/OS2/DOS/WINCE/PSP/HAIKU" echo " --endian=ENDIAN set the endian of the HOST (AUTO/LE/BE)" echo "" echo "Paths:" echo " --prefix-dir=dir specifies the prefix for all installed" echo " files [/usr/local]" echo " --binary-dir=dir location of the binary. Will be prefixed" echo " with the prefix-dir [games]" echo " --data-dir=dir location of data files (lang, data, gm)." echo " Will be prefixed with the prefix-dir" echo " [share/games/openttd]" echo " --doc-dir=dir location of the doc files" echo " Will be prefixed with the prefix-dir" echo " [$doc_dir]" echo " --icon-dir=dir location of icons. Will be prefixed" echo " with the prefix-dir [share/pixmaps]" echo " --icon-theme-dir=dir location of icon theme." echo " Will be prefixed with the prefix-dir" echo " and postfixed with size-dirs [$icon_theme_dir]" echo " --man-dir=dir location of the manual page (UNIX only)" echo " Will be prefixed with the prefix-dir" echo " [$man_dir]" echo " --menu-dir=dir location of the menu item. (UNIX only, except OSX)" echo " Will be prefixed with the prefix-dir" echo " [share/applications]" echo " --personal-dir=dir location of the personal directory" echo " [os-dependent default]" echo " --shared-dir=dir location of shared data files" echo " [os-dependent default]" echo " --install-dir=dir specifies the root to install to." echo " Useful to install into jails [/]" echo " --binary-name the name used for the binary, icons," echo " desktop file, etc. when installing [openttd]" echo "" echo "Features and packages:" echo " --enable-debug[=LVL] enable debug-mode (LVL=[0123], 0 is release)" echo " --enable-desync-debug=[LVL] enable desync debug options (LVL=[012], 0 is none" echo " --enable-profiling enables profiling" echo " --enable-lto enables GCC's Link Time Optimization (LTO)/ICC's" echo " Interprocedural Optimization if available" echo " --enable-dedicated compile a dedicated server (without video)" echo " --enable-static enable static compile (doesn't work for" echo " all HOSTs)" echo " --enable-translator enable extra output for translators" echo " --enable-universal[=ARCH] enable universal builds (OSX ONLY). Allowed is any combination" echo " of architectures: i386 ppc ppc970 ppc64 x86_64" echo " Default architectures are: i386 ppc" echo " --enable-osx-g5 enables optimizations for ppc970 (G5) (OSX ONLY)" echo " --disable-cocoa-quartz disable the quartz window mode driver for Cocoa (OSX ONLY)" echo " --disable-cocoa-quickdraw disable the quickdraw window mode driver for Cocoa (OSX ONLY)" echo " --disable-unicode disable unicode support to build win9x" echo " version (Win32 ONLY)" echo " --enable-console compile as a console application instead of as a GUI application." echo " If this setting is active, debug output will appear in the same" echo " console instead of opening a new window. (Win32 ONLY)" echo " --disable-network disable network support" echo " --disable-assert disable asserts (continue on errors)" echo " --enable-strip enable any possible stripping" echo " --without-osx-sysroot disable the automatic adding of sysroot " echo " (OSX ONLY)" echo " --without-application-bundle disable generation of application bundle" echo " (OSX ONLY)" echo " --without-menu-entry Don't generate a menu item (Freedesktop based only)" echo " --menu-group=group Category in which the menu item will be placed (Freedesktop based only)" echo " --menu-name=name Name of the menu item when placed [OpenTTD]" echo " --with-direct-music enable direct music support (Win32 ONLY)" echo " --with-sort=sort define a non-default location for sort" echo " --with-midi=midi define which midi-player to use" echo " --with-midi-arg=arg define which args to use for the" echo " midi-player" echo " --with-libtimidity enables libtimidity support" echo " --with-allegro[=allegro-config]" echo " enables Allegro video driver support" echo " --with-cocoa enables COCOA video driver (OSX ONLY)" echo " --with-sdl[=sdl-config] enables SDL video driver support" echo " --with-zlib[=zlib.a] enables zlib support" echo " --with-liblzma[=\"pkg-config liblzma\"]" echo " enables liblzma support" echo " --with-liblzo2[=liblzo2.a] enables liblzo2 support" echo " --with-png[=libpng-config] enables libpng support" echo " --with-freetype[=freetype-config]" echo " enables libfreetype support" echo " --with-fontconfig[=\"pkg-config fontconfig\"]" echo " enables fontconfig support" echo " --with-xdg-basedir[=\"pkg-config libxdg-basedir\"]" echo " enables XDG base directory support" echo " --with-icu[=icu-config] enables icu (used for right-to-left support)" echo " --static-icu try to link statically (libsicu instead of" echo " libicu; can fail as the new name is guessed)" echo " --with-iconv[=iconv-path] enables iconv support" echo " --with-psp-config[=psp-config] enables psp-config support (PSP ONLY)" echo " --disable-builtin-depend disable use of builtin deps finder" echo " --with-makedepend[=makedepend] enables makedepend support" echo " --with-ccache enables ccache support" echo " --with-distcc enables distcc support" echo " --without-grfcodec disable usage of grfcodec and re-generation of base sets" echo " --without-threads disable threading support" echo " --without-sse disable SSE support (x86/x86_64 only)" echo "" echo "Some influential environment variables:" echo " CC C compiler command" echo " CXX C++ compiler command" echo " CFLAGS C compiler flags" echo " CXXFLAGS C++ compiler flags" echo " WINDRES windres command" echo " LDFLAGS linker flags, e.g. -L if you" echo " have libraries in a nonstandard" echo " directory " echo " CFLAGS_BUILD C compiler flags for build time tool generation" echo " CXXFLAGS_BUILD C++ compiler flags for build time tool generation" echo " LDFLAGS_BUILD linker flags for build time tool generation" echo "" echo "Use these variables to override the choices made by 'configure' or to help" echo "it to find libraries and programs with nonstandard names/locations." } openttd-1.5.3/Makefile.msvc0000644000000000000000000000332412627373433014316 0ustar rootroot# $Id: Makefile.msvc 22581 2011-06-13 10:35:19Z rubidium $ # 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 . # # Makefile for creating bundles of MSVC's binaries in the same way as we make # the zip bundles for ALL other OSes. # # Usage: make -f Makefile.msvc PLATFORM=[Win32|x64] BUNDLE_NAME=openttd--win[32|64] # or make -f Makefile.msvc PLATFORM=[Win32|x64] BUNDLE_NAME=OTTD-win[32|64]-nightly- # # Check if we want to show what we are doing ifdef VERBOSE Q = else Q = @ endif AWK = "awk" ROOT_DIR := $(shell pwd) BIN_DIR = "$(ROOT_DIR)/bin" SRC_DIR = "$(ROOT_DIR)/src" BUNDLE_DIR = "$(ROOT_DIR)/bundle" BUNDLES_DIR = "$(ROOT_DIR)/bundles" TTD = openttd.exe PDB = openttd.pdb MODE = Release TARGET := $(shell echo $(PLATFORM) | sed "s@win64@x64@;s@win32@Win32@") all: $(Q)cp objs/$(TARGET)/$(MODE)/$(TTD) $(BIN_DIR)/$(TTD) include Makefile.bundle.in bundle_pdb: @echo '[BUNDLE] Creating $(BUNDLE_NAME).pdb.xz' $(Q)mkdir -p "$(BUNDLES_DIR)" $(Q)cp objs/$(TARGET)/Release/$(PDB) $(BUNDLES_DIR)/$(BUNDLE_NAME).pdb $(Q)xz -9 $(BUNDLES_DIR)/$(BUNDLE_NAME).pdb regression: all $(Q)cp bin/$(TTD) bin/openttd $(Q)cd bin && sh ai/regression/run.sh openttd-1.5.3/known-bugs.txt0000644000000000000000000005702512627373446014555 0ustar rootrootOpenTTD's known bugs Last updated: 2015-12-01 Release version: 1.5.3 ------------------------------------------------------------------------ Table of contents ----------------- 1.0) About 2.0) Known bugs 1.0) About ---- ----- All bugs listed below are marked as known. Please do not submit any bugs that are the same as these. If you do, do not act surprised, because we WILL flame you!! The current list of known bugs that we intend to fix can be found in our bug tracking system at: http://bugs.openttd.org Also check the closed bugs when searching for your bug in this system as we might have fixed the bug in the mean time. 2.0) Known bugs ---- ---------------------------------- This section lists all known bugs that we do not intend to fix and the reasons why we think that fixing them is infeasible. We might make some minor improvements that reduce the scope of these bugs, but we will not be able to completely fix them. No suitable AI can be found If you have no AIs and an AI is started the so-called 'dummy' AI will be loaded. This AI does nothing but writing a message on the AI debug window and showing a red warning. There are basically two solutions for this problem: Either you set the number of AI players to 0 so that no AI is started. You find that setting at the top of the window in the "AI / Game Scripts Settings" window. The other solution is acquiring (downloading) some AI. The easiest way to do this is via the "Check Online Content" button in the main (intro) menu or directly in the "AI / Game Scripts Settings" dialogue via the "Check Online Content" button. After a while of playing, colours get corrupted In Windows 7 the background slideshow corrupts the colour mapping of OpenTTD's 8bpp screen modes. Workarounds for this are: a) Switching to windowed mode, instead of fullscreen b) Switching off background slideshow c) Setting up the 32bpp-anim or 32bpp-optimized blitter Long delay between switching songs/music On Windows there is a delay of a (few) second(s) between switching of songs for the "win32" driver. This delay is caused by the fact that opening a MIDI file via MCI is extremely slow. DirectMusic, known as "dmusic" in OpenTTD, has a much shorter delay. However, under some circumstances DirectMusic does not reset its state properly causing wrongly pitched/bad sounding songs. This problem is in DirectMusic as it is reproducable with Microsoft's DirectMusic Producer. DirectMusic has been deprecated since 2004 and as such has no support for 64 bits OpenTTD. As a delay is favourable over bad sounding music the "win32" driver is the default driver for OpenTTD. You can change this default by setting the "musicdriver" in your openttd.cfg to "dmusic". Custom vehicle type name is incorrectly aligned Some NewGRFs use sprites that are bigger than normal in the "buy vehicle" window. Due to this they have to encode an offset for the vehicle type name. Upon renaming the vehicle type this encoded offset is stripped from the name because the "edit box" cannot show this encoding. As a result the custom vehicle type names will get the default alignment. The only way to (partly) fix this is by adding spaces to the custom name. Clipping problems [FS#119] In some cases sprites are not drawn as one would expect. Examples of this are aircraft that might be hidden below the runway or trees that in some cases are rendered over vehicles. The primary cause of this problem is that OpenTTD does not have enough data (like a 3D model) to properly determine what needs to be drawn in front of what. OpenTTD has bounding boxes but in lots of cases they are either too big or too small and then cause problems with what needs to be drawn in front of what. Also some visual tricks are used. For example trains at 8 pixels high, the catenary needs to be drawn above that. When you want to draw bridges on top of that, which are only one height level (= 8 pixels) higher, you are getting into some big problems. We can not change the height levels; it would require us to either redraw all vehicle or all landscape graphics. Doing so would mean we leave the Transport Tycoon graphics, which in effect means OpenTTD will not be a Transport Tycoon clone anymore. Mouse scrolling not possible at the edges of the screen [FS#383] [FS#3966] Scrolling the viewport with the mouse cursor at the edges of the screen in the same direction of the edge will fail. If the cursor is near the edge the scrolling will be very slow. OpenTTD only receives cursor position updates when the cursor is inside OpenTTD's window. It is not told how far you have moved the cursor outside of OpenTTD's window. Lost trains ignore (block) exit signals [FS#1473] If trains are lost they ignore block exit signals, blocking junctions with presignals. This is caused because the path finders cannot tell where the train needs to go. As such a random direction is chosen at each junction. This causes the trains to occasionally to make choices that are unwanted from a player's point of view. This will not be fixed because lost trains are in almost all cases a network problem, e.g. a train can never reach a specific place. This makes the impact of fixing the bug enormously small against the amount of work needed to write a system that prevents the lost trains from taking the wrong direction. Vehicle owner of last transfer leg gets paid for all [FS#2427] When you make a transfer system that switches vehicle owners. This is only possible with 'industry stations', e.g. the oil rig station the owner of the vehicle that does the final delivery gets paid for the whole trip. It is not shared amongst the different vehicle owners that have participated in transporting the cargo. This sharing is not done because it would enormously increase the memory and CPU usage in big games for something that is happening in only one corner case. We think it is not worth the effort until sharing of stations is an official feature. Forbid 90 degree turns does not work for crossing PBS paths [FS#2737] When you run a train through itself on a X junction with PBS turned on the train will not obey the 'forbid 90 degree turns' setting. This is due to the fact that we can not be sure that the setting was turned off when the track was reserved, which means that we assume it was turned on and that the setting does not hold at the time. We made it this way to allow one to change the setting in-game, but it breaks slightly when you are running your train through itself. Running a train through means that your network is broken and is thus a user error which OpenTTD tries to graciously handle. Fixing this bug means that we need to record whether this particular setting was turned on or off at the time the reservation was made. This means adding quite a bit of data to the savegame for solving an issue that is basically an user error. We think it is not worth the effort. Duplicate (station) names after renaming [FS#3204] After renaming stations one can create duplicate station names. This is done giving a station the same custom name as another station with an automatically generated name. The major part of this problem is that station names are translatable. Meaning that a station is called e.g. ' Central' in English and ' Centraal' in Dutch. This means that in network games the renaming of a town could cause the rename to succeed on some clients and fail at others. This creates an inconsistent game state that will be seen as a 'desync'. Secondly the custom names are intended to fall completely outside of the ' ' naming of stations, so when you rename a town all station names are updated accordingly. As a result the decision has been made that all custom names are only compared to the other custom names in the same class and not compared to the automatically generated names. Extreme CPU usage/hangs when using SDL and PulseAudio [FS#3294] OpenTTD hangs/freezes when closing, OpenTTD is slow, OpenTTD uses a lot of CPU OpenTTD can be extremely slow/use a lot of CPU when the sound is played via SDL and then through PulseAudio's ALSA wrapper. Under the same configuration OpenTTD, or rather SDL, might hang when exiting the game. This problem is seen most in Ubuntu 9.04 and higher. This is because recent versions of the PulseAudio sound server are configured to use timer-based audio scheduling rather than interrupt-based audio scheduling. Configuring PulseAudio to force use of interrupt-based scheduling may resolve sound problems for some users. Under recent versions of Ubuntu Linux (9.04 and higher) this can be accomplished by changing the following line in the /etc/pulse/default.pa file: load-module module-udev-detect to load-module module-udev-detect tsched=0 Note that PulseAudio must be restarted for changes to take effect. Older versions of PulseAudio may use the module-hal-detect module instead. Adding tsched=0 to the end of that line will have a similar effect. Another possible solution is selecting the "pulse" backend of SDL by either using "SDL_AUDIODRIVER=pulse openttd" at the command prompt or installing the 'libsdl1.2debian-pulseaudio' package from Ubuntu's Universe repository. For other distributions a similar package needs to be installed. OpenTTD not properly resizing with SDL on X [FS#3305] Under some X window managers OpenTTD's window does not properly resize. You will either end up with a black bar at the right/bottom side of the window or you cannot see the right/bottom of the window, e.g you cannot see the status bar. The problem is that OpenTTD does not always receive a resize event from SDL making it impossible for OpenTTD to know that the window was resized; sometimes moving the window will solve the problem. Window managers that are known to exhibit this behaviour are KDE's and GNOME's. With the XFCE's and LXDE's window managers the resize event is sent when the user releases the mouse. Incorrect colours, crashes upon exit, debug warnings and smears upon window resizing with SDL on Mac OS X [FS#3447] Video handling with (lib)SDL under Mac OS X is known to fail on some versions of Mac OS X with some hardware configurations. Some of the problems happen only under some circumstances whereas others are always present. We suggest that the SDL video/sound backend is not used for OpenTTD in combinations with Mac OS X. Train crashes entering same junction from block and path signals [FS#3928] When a train has reserved a path from a path signal to a two way block signal and the reservation passes a path signal through the back another train can enter the reserved path (only) via that same two way block signal. The reason for this has to do with optimisation; to fix this issue the signal update has to pass all path signals until it finds either a train or a backwards facing signal. This is a very expensive task. The (signal) setups that allow these crashes can furthermore be considered incorrectly signalled; one extra safe waiting point for the train entering from path signal just after the backwards facing signal (from the path signal train) resolves the issue. Crashes when playing music [FS#3941] Mac OS X's QuickTime (default music driver) and Windows' MCI (win32 music driver) crash on some songs from OpenMSX. OpenTTD cannot do anything about this. Please report these crashes to the authors of OpenMSX so the crash causing songs can be removed or fixed. Crashes when run in a VM using Parallels Desktop [FS#4003] When the Windows version of OpenTTD is executed in a VM under Parallels Desktop a privileged instruction exception may be thrown. As OpenTTD works natively on OSX as well as natively on Windows and these native builds both don't exhibit this behaviour this crash is most likely due to a bug in the virtual machine, something out of the scope of OpenTTD. Most likely this is due to Parallels Desktop lacking support for RDTSC calls. The problem can be avoided by using other VM-software, Wine, or running natively on OSX. OpenTTD hangs when started on 32 bits Windows [FS#4083] Under some circumstances OpenTTD might hang for hours on the initialisation of the music driver. The exact circumstances are unknown except that it is the "dmusic" music driver that has the problem and that the "win32" music driver does not. As a result using the "win32" music driver will work around this issue. As the exact circumstances are unknown, and the obvious configuration settings related to the music driver are at their default we are not able to detect this failure, except when Windows' music initialisation function returns after several hours and then there is no point in switching the music driver anymore. The reason we still use the "win32" music driver as default are described in the "Long delay between switching music/song" section of this document. Pre- and exit signals are not dragged [FS#4378] Unlike all other signal types, the entry- and exit signals are not dragged but instead normal signals are placed on subsequent track sections. This is done on purpose as this is the usually more con- venient solution. There are little to no occasions where more than one entry or exit signal in a row are useful. This is different for all other signal types where several in a row can serve one purpose or another. Station build date is incorrect [FS#4415] The tile query tool will show the date of the last (re)construction at the station and not the date of the first construction. This is due to compatability reasons with NewGRFs and the fact that it is wrong to say that the station is built in a particular year when it was completely destroyed/rebuilt later on. The tile query tool can be fixed by changing the "Build date" text to "Date at which the last (re)construction took place" but this is deemed too specific and long for that window. Can't change volume inside OpenTTD [FS#4416] Some backends do not provide a means to change the volume of sound effects or music. The mixing of music and sound is left to external libraries/the operating system we can't handle the volume control in OpenTTD. As a result you can't change the volume inside OpenTTD for backends such as SDL; just use the volume control provided by your operating system. Can't run OpenTTD with the -d option from a MSYS console [FS#4587] The MSYS console does not allow OpenTTD to open an extra console for debugging output. Compiling OpenTTD with the --enable-console configure option prevents this issue and allows the -d option to use the MSYS console for its output. Unreadable characters for non-latin locales [FS#4607] OpenTTD does not ship a non-latin font in its graphics files. As a result OpenTTD needs to acquire the font from somewhere else. What OpenTTD does is ask the operating system, or a system library, for the best font for a given language if the currently loaded font does not provide all characters of the chosen translation. This means that OpenTTD has no influence over the quality of the chosen font; it just does the best it can do. If the text is unreadable there are several steps that you can take to improve this. The first step is finding a good font and configure this in the configuration file. See section 9.0 of readme.txt for more information. You can also increase the font size to make the characters bigger and possible better readable. If the problem is with the clarity of the font you might want to enable anti-aliasing by setting the small_aa/medium_aa/large_aa settings to "true". However, anti-aliasing only works when a 32 bits blitter has been selected, e.g. blitter = "32bpp-anim", as with the 8 bits blitter there are not enough colours to properly perform the anti-aliasing. (Temporary) wrong colours when switching to full screen [FS#4511]: On Windows it can happen that you temporarily see wrong colours when switching to full screen OpenTTD, either by starting OpenTTD in full screen mode, changing to full screen mode or by ALT-TAB-ing into a full screen OpenTTD. This is caused by the fact that OpenTTD, by default, uses 8bpp paletted output. The wrong colours you are seeing is a temporary effect of the video driver switching to 8bpp palette mode. This issue can be worked around in two ways: a) Setting fullscreen_bpp to 32 b) Setting up the 32bpp-anim or 32bpp-optimized blitter Train does not crash with itself [FS#4635]: When a train drives in a circle the front engine passes through wagons of the same train without crashing. This is intentional. Signals are only aware of tracks, they do not consider the train length and whether there would be enough room for a train in some circle it might drive on. Also the path a train might take is not necessarily known when passing a signal. Checking all circumstances would take a lot of additional computational power for signals, which is not considered worth the effort, as it does not add anything to gameplay. Nevertheless trains shall not crash in normal operation, so making a train not crash with itself is the best solution for everyone. Aircraft coming through wall in rotated airports [FS#4705]: With rotated airports, specifically hangars, you will see that the aircraft will show a part through the back wall of the hangar. This can be solved by only drawing a part of the plane when being at the back of the hangar, however then with transparency turned on the aircraft would be shown partially which would be even weirder. As such the current behaviour is deemed the least bad. The same applies to overly long ships and their depots. Vehicles not keeping their "maximum" speed [FS#4815]: Vehicles that have not enough power to reach and maintain their advertised maximum speed might be constantly jumping between two speeds. This is due to the fact that speed and its calculations are done with integral numbers instead of floating point numbers. As a result of this a vehicle will never reach its equilibrium between the drag/friction and propulsion. So in effect it will be in a vicious circle of speeding up and slowing down due to being just at the other side of the equilibrium. Not speeding up when near the equilibrium will cause the vehicle to never come in the neighbourhood of the equilibrium and not slowing down when near the equilibrium will cause the vehicle to never slow down towards the equilibrium once it has come down a hill. It is possible to calculate whether the equilibrium will be passed, but then all acceleration calculations need to be done twice. Settings not saved when OpenTTD crashes [FS#4846]: The settings are not saved when OpenTTD crashes for several reasons. The most important is that the game state is broken and as such the settings might contain invalid values, or the settings have not even been loaded yet. This would cause invalid or totally wrong settings to be written to the configuration file. A solution to that would be saving the settings whenever one changes, however due to the way the configuration file is saved this requires a flush of the file to the disk and OpenTTD needs to wait till that is finished. On some file system implementations this causes the flush of all 'write-dirty' caches, which can be a significant amount of data to be written. This can further be aggravated by spinning down disks to conserve power, in which case this disk needs to be spun up first. This means that many seconds may pass before the configuration file is actually written, and all that time OpenTTD will not be able to show any progress. Changing the way the configuration file is saved is not an option as that leaves us more vulnerable to corrupt configuration files. Finally, crashes should not be happening. If they happen they should be reported and fixed, so essentially fixing this is fixing the wrong thing. If you really need the configuration changes to be saved, and you need to run a version that crashes regularly, then you can use the 'saveconfig' command in the console to save the settings. Not all NewGRFs, AIs, game scripts are found [FS#4887]: Under certain situations, where the path for the content within a tar file is the same as other content on the file system or in another tar file, it is possible that content is not found. A more thorough explanation and solutions are described in section 4.4 of readme.txt. Mouse cursor going missing with SDL [FS#4997]: Under certain circumstances SDL does not notify OpenTTD of changes with respect to the mouse pointer, specifically whether the mouse pointer is within the bounds of OpenTTD or not. For example, if you Alt-tab to another application the mouse cursor will still be shown in OpenTTD, and when you move the mouse outside of the OpenTTD window so the cursor gets hidden, open/move another application on top of the OpenTTD window and then Alt-tab back into OpenTTD the cursor will not be shown. We cannot fix this problem as SDL simply does not provide the required information in these corner cases. This is a bug in SDL and as such there is little that we can do about it. Inconsistent catchment areas [FS#5661]: Due to performance decisions the catchment area for cargo accepted by a station for delivery to houses or industries differs from the catchment area for cargo that is delivered to stations from houses or industries. Conceptually they work the same, but the effect in game differs. They work by finding the closest destination "around" the source which is within a certain distance. This distance depends on the type of station, e.g. road stops have a smaller catchment area than large airports. In both cases the bounding box, the smallest rectangle that contains all tiles of something, is searched for the target of the cargo, and then spiraling outwards finding the closest tile of the target. In the case of a station with two tiles spread far apart with a house that is within the station's bounding box, it would be possible that the spiraling search from the house does not reach one of the station tiles before the search ends, i.e. all tiles within that distance are searched. So the house does not deliver cargo to the station. On the other hand, the station will deliver cargo because the house falls within the bounding box, and thus search area. It is possible to make these consistent, but then cargo from a house to a station needs to search up to 32 tiles around itself, i.e. 64 by 64 tiles, to find all possible stations it could deliver to instead of 10 by 10 tiles (40 times more tiles). Alternatively the search from a station could be changed to use the actual tiles, but that would require considering checking 10 by 10 tiles for each of the tiles of a station, instead of just once. Trains might not stop at platforms that are currently being changed [FS#5553]: If you add tiles to or remove tiles from a platform while a train is approaching to stop at the same platform, that train can miss the place where it's supposed to stop and pass the station without stopping. This is caused by the fact that the train is considered to already have stopped if it's beyond its assigned stopping location. We can't let the train stop just anywhere in the station because then it would never leave the station if you have the same station in the order list multiple times in a row or if there is only one station in the order list (see FS#5684). Some houses and industries are not affected by transparency [FS#5817]: Some of the default houses and industries (f.e. the iron ore mine) are not affected by the transparency options. This is because the graphics do not (completely) separate the ground from the building. This is a bug of the original graphics, and unfortunately cannot be fixed with OpenGFX for the sake of maintaining compatibility with the original graphics. openttd-1.5.3/configure0000755000000000000000000001422012627373446013617 0ustar rootroot#!/bin/sh # $Id: configure 26194 2014-01-02 08:35:45Z rubidium $ # 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 . check_path_characters() { if [ -n "`echo $ROOT_DIR | grep '[^-_A-Za-z0-9\/\\\.:]'`" ]; then echo "WARNING: The path contains a non-alphanumeric character that might cause" echo " failures in subsequent build stages. Any failures with the build" echo " will most likely be caused by this." fi } CONFIGURE_EXECUTABLE="$_" # On *nix systems those two are equal when ./configure is done if [ "$0" != "$CONFIGURE_EXECUTABLE" ]; then # On some systems, when ./configure is triggered from 'make' # the $_ is filled with 'make'. So if that is true, skip 'make' # and use $0 (and hope that is correct ;)) if [ -n "`echo $CONFIGURE_EXECUTABLE | grep make`" ]; then CONFIGURE_EXECUTABLE="$0" else CONFIGURE_EXECUTABLE="$CONFIGURE_EXECUTABLE $0" fi fi # Find out where configure is (in what dir) ROOT_DIR="`dirname $0`" # For MSYS/MinGW we want to know the FULL path. This as that path is generated # once you call an outside binary. Having the same path for the rest is needed # for dependency checking. # pwd -W returns said FULL path, but doesn't exist on others so fall back. ROOT_DIR="`cd $ROOT_DIR && (pwd -W 2>/dev/null || pwd 2>/dev/null)`" check_path_characters # Same here as for the ROOT_DIR above PWD="`pwd -W 2>/dev/null || pwd 2>/dev/null`" PREFIX="$PWD/bin" . $ROOT_DIR/config.lib # Set default dirs 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" MEDIA_DIR="$ROOT_DIR/media" SOURCE_LIST="$ROOT_DIR/source.list" if [ "$1" = "--reconfig" ] || [ "$1" = "--reconfigure" ]; then if [ ! -f "config.cache" ]; then echo "can't reconfigure, because never configured before" exit 1 fi # Make sure we don't lock config.cache cat config.cache | sed 's@\\ @\\\\ @g' > cache.tmp sh cache.tmp RET=$? rm -f cache.tmp exit $RET fi set_default detect_params "$@" check_params save_params make_cflags_and_ldflags EXE="" if [ "$os" = "MINGW" ] || [ "$os" = "CYGWIN" ] || [ "$os" = "OS2" ] || [ "$os" = "DOS" ] || [ "$os" = "WINCE" ]; then EXE=".exe" fi 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@" else PIPE_SORT="$sort" fi if [ ! -f "$LANG_DIR/english.txt" ]; then echo "Languages not found in $LANG_DIR. Can't continue without it." echo "Please make sure the dir exists and contains at least english.txt" fi # Read the source.list and process it AWKCOMMAND=' { } /^( *)#end/ { if (deep == skip) { skip -= 1; } deep -= 1; next; } /^( *)#else/ { if (deep == skip) { skip -= 1; } else if (deep - 1 == skip) { skip += 1; } next; } /^( *)#if/ { gsub(" ", "", $0); gsub("^#if ", "", $0); if (deep != skip) { deep += 1; next; } deep += 1; if ($0 == "ALLEGRO" && "'$allegro_config'" == "") { next; } if ($0 == "SDL" && "'$sdl_config'" == "") { next; } if ($0 == "PNG" && "'$png_config'" == "") { next; } if ($0 == "OSX" && "'$os'" != "OSX") { next; } if ($0 == "OS2" && "'$os'" != "OS2") { next; } if ($0 == "PSP" && "'$os'" != "PSP") { next; } if ($0 == "DEDICATED" && "'$enable_dedicated'" != "1") { next; } if ($0 == "AI" && "'$enable_ai'" == "0") { next; } if ($0 == "COCOA" && "'$with_cocoa'" == "0") { next; } if ($0 == "DOS" && "'$os'" != "DOS") { next; } if ($0 == "BEOS" && "'$os'" != "BEOS" && "'$os'" != "HAIKU") { next; } if ($0 == "WIN32" && "'$os'" != "MINGW" && "'$os'" != "CYGWIN" && "'$os'" != "MSVC") { next; } if ($0 == "MORPHOS" && "'$os'" != "MORPHOS") { next; } if ($0 == "WINCE" && "'$os'" != "WINCE") { next; } if ($0 == "MSVC" && "'$os'" != "MSVC") { next; } if ($0 == "DIRECTMUSIC" && "'$with_direct_music'" == "0") { next; } if ($0 == "LIBTIMIDITY" && "'$libtimidity'" == "" ) { next; } if ($0 == "HAVE_THREAD" && "'$with_threads'" == "0") { next; } if ($0 == "SSE" && "'$with_sse'" != "1") { next; } skip += 1; next; } /^( *)#/ { next } /^$/ { next } /\.h$/ { next } /\.hpp$/ { next } { if (deep == skip) { gsub(" ", "", $0); print $0; } } ' # Read the source.list and process it # Please escape ALL " within ` because e.g. "" terminates the string in some sh implementations SRCS="`< $ROOT_DIR/source.list tr '\r' '\n' | $awk \"$AWKCOMMAND\" | $PIPE_SORT`" OBJS_C="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.c$/ { gsub(\".c$\", \".o\", $0); print $0; }'`" OBJS_CPP="`echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.cpp$/ { gsub(\".cpp$\", \".o\", $0); print $0; }'`" OBJS_MM="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.mm$/ { gsub(\".mm$\", \".o\", $0); print $0; }'`" OBJS_RC="` echo \"$SRCS\" | $awk ' { ORS = \" \" } /\.rc$/ { gsub(\".rc$\", \".o\", $0); print $0; }'`" SRCS="` echo \"$SRCS\" | $awk ' { ORS = \" \" } { print $0; }'`" # In makefiles, we always use -u for sort if [ -z "$sort" ]; then sort="sed s@a@a@" 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" generate_main generate_lang generate_settings generate_grf generate_src check_path_characters openttd-1.5.3/changelog.txt0000644000000000000000000171761112627373446014417 0ustar rootroot1.5.3 (2015-12-01) ------------------------------------------------------------------------ (None) 1.5.3-RC1 (2015-11-01) ------------------------------------------------------------------------ - Fix: When selecting a refit cargo for orders, do not check whether the vehicle is in a depot or station, and do not ask whether the vehicle currently allows station-refitting. Also hide the refit cost for orders, it is not predictable (r27428) - Fix: Use the NewGRF railtype sorting order in the infrastructure window (r27427) - Fix: Crash when switching to or taking over companies, when an order window of a vehicle of the new company was opened. Now close those windows [FS#5842] (r27425) - Fix: Towns did not connect roads to existing roads, unless they had only a single roadbit. Otoh, towns also tried to connect to single roadbit tiles such as tunnels and depots, even though they were not connectable in the direction of interest [FS#6374] (r27424) - Fix: When towns expanded single-bit roadtiles using a grid-layout, they used the layout position of the neighbouring tile (r27423) - Fix: Aircraft picked the wrong airport entry point, if airports were rotated by 180 degree [FS#6341] (r27422) - Fix: Consider text and icon sizes when drawing the client list [FS#6265] (r27421) - Fix: GrowTownAtRoad sometimes returned false, even when a house was built [FS#6362] (r27420) - Fix: CmdSellRailWagon did not revert all actions properly when no orderlist could be allocated [FS#6369] (r27419) - Fix: Desync due to incorrect storage of segments with different railtype in the YAPF cache [FS#6329] [FS#6379] (r27418) - Fix: When a dedicated server was paused with no clients, the master server advertisement interval was slowed, causing deadvertisement of the server [FS#6368] (r27400) - Fix: [Makefile] Game script directory and compat*.nut were never installed on *nix (r27399) - Fix: There are two different availability conditions for fdatasync in the manpage. Use them both, since at least on some MinGW versions one is not enough (r27389) - Fix: win32 sound driver failed to report errors (r27383) - Fix: Clickareas in settings tree were misaligned when the filter warning was displayed, if the setting height was defined by the icons instead of the font [FS#6358] (r27366) - Fix: Center settings filter warning also vertically, and also in case of multiple lines (r27365) 1.5.2 (2015-09-01) ------------------------------------------------------------------------ (None) 1.5.2-RC1 (2015-08-01) ------------------------------------------------------------------------ - Change: Auto-complete partial roads when building level-crossings [FS#6283] (r27309) - Fix: Do not rerandomise the town name when only cost-estimating the founding [FS#6332] (r27341) - Fix: Make variety distribution not assume that sea level is at height 0.2 / 3 * TGPGetMaxHeight() [FS#6335] (r27331, r27330, r27329, r27328) - Fix: Remove corner-case optimisation for line drawing, which failed for dashed lines (r27324) - Fix: Clipping of inclined lines did not account for the 'horizontal width' being bigger than the 'real width' (r27323, r27322) - Fix: Incorrect owner assignment when adding/removing road/tram to/from bridges [FS#6317] (r27313, r27312) - Fix: Mark infrastructure window dirty in more cases (r27311) - Fix: Prevent breaking of tram-reversal points by adding more road pieces [FS#6283] (r27308) - Fix: Error message window with manager face failed with GUI zoom [FS#6259] (r27307) - Fix: Account for road-bridges and drive-through-stops in CanFollowRoad [FS#6320] (r27306, r27305) - Fix: Password window layout with GUI zoom [FS#6321] (r27304, r27303) - Fix: Speed-only timetables got assigned times in stations [FS#6313] (r27302, r27301) - Fix: Enforce the company's default service intervals when purchasing another company [FS#6254] (r27282, r27281) - Fix: Cloning/autoreplace/autorenew did not copy custom service intervals (r27280) 1.5.1 (2015-06-01) ------------------------------------------------------------------------ (None) 1.5.1-RC1 (2015-05-08) ------------------------------------------------------------------------ - Fix: Do not consider road junctions with trivial dead ends as branch points during town growth [FS#6245] (r27260, r27259, r27244) - Fix: ScriptList::RemoveList failed to remove a list from itself [FS#6287] (r27258) - Fix: Combined button+dropdown widgets in order and autoreplace GUI had incorrect hitbox when using GUI zoom [FS#6270] (r27255) - Fix: When building a lock on DC_AUTO-removable water-based objects, the water class was always set to canal [FS#6264] (r27254) - Fix: When crossing tram tracks with railroads, cost of extra roads was not being counted [FS#6282] (r27253) - Fix: Invalid infrastructure counting when crossing tram tracks with railroads [FS#6281] (r27252) - Fix: Broken error message in configure [FS#6286] (r27250) - Fix: In some cases town growth failure was considered as success [FS#6240] (r27249, r27247) - Fix: Town labels on smallmap and zoomed-out viewports were not centered [FS#6257] (r27248) - Fix: Removing a rail waypoint used the remove-rail-station cost [FS#6251] (r27245) - Fix: Duplicate frees due to pool item classes not having copy constructors [FS#6285] (r27243) - Fix: Crash when no AIs were installed due to improper handling of non-ASCII characters by the string pointer lexer [FS#6272] (r27233) - Fix: Compilation on DragonflyBSD [FS#6274] (r27224, r27223) - Fix: Use the current maximum speed as limited by bridges, orders etc. for all vehicle types alike when considering increased smoke emissions of vehicles [FS#6278] (r27222) - Fix: Multi-value keys in the desktop entry shall end with a trailing separator (r27221) - Fix: Draw path reservation on the whole bridge, not only on the bridge heads (r27209) - Fix: Draw correct overlay sprites for path reservations on bridges and tunnels (r27208) 1.5.0 (2015-04-01) ------------------------------------------------------------------------ - Fix: [NewGRF] Add Misc. GRF Feature Flag 6 to enable the second rocky tile set [FS#6260] (r27200) 1.5.0-RC1 (2015-03-18) ------------------------------------------------------------------------ - Feature: [NewGRF] Display relative offset changes in the sprite aligner [FS#6236] (r27174) - Fix: Original road vehicle acceleration crashed for vehicles taking over [FS#6255] (r27190) - Fix: GCC 5 compilation (r27185, r27183) - Fix: Data race due to lazy initialisation of objects [FS#5969] (r27178) - Fix: Compilation with MinGW64 (r27176) - Fix: Use the regular clipping functions in the sprite aligner instead of some magic [FS#6237] (r27173) - Fix: Windows randomly drops SetCursorPos calls, breaking the RMB-scrolling [FS#6238] (r27172) 1.5.0-beta2 (2015-02-24) ------------------------------------------------------------------------ - Feature: [NoGo] Game scripts can point to a location, station, industry, or town when publishing news (r27164) - Feature: Allow changing max heightlevel in scenario editor (r27151) - Feature: Make use of both rocky tile sets from the base graphics (r27117) - Change: Scale (non-custom) default window sizes according to GUI zoom (r27147) - Change: Make statusbar and chat-entry window use the same width as the toolbar (r27146) - Change: The chatbox-width setting now uses percent of screen width instead of pixels (r27144) - Change: [NewGRF] Interpret negative positions in industry layouts depending on GRF version (r27138) - Fix: [SDL, Windows] Right-mouse-button scrolling scrolled/jumped too far, when OpenTTD lagged during mouse event processing (r27167) - Fix: Toolbars were not invalidated when changing max-vehicles settings [FS#6204] (r27163) - Fix: Tile selection was drawn outside of map in some cases [FS#6208] (r27162) - Fix: Reimplement the viewport drawing algorithm [FS#6156] [FS#6206] (r27161) - Fix: Issues with smallmap and viewport coordinates and transformations (r27160, r27159, r27158) - Fix: Mark bridge middle tiles dirty when building/removing/changing bridges (r27157) - Fix: Rounding and unit-conversion inconsistencies in calls to MarkAllViewportsDirty (r27148) - Fix: Oilrig empty-tile checks were incorrect due to wrong TileIndexDiff->TileIndexDiffC conversion (r27137) - Fix: Misalignment in generate world window in case of small fonts (r27135) - Fix: Dragging of free wagons in depot failed with GUI zoom (r27133) - Fix: Reduce memory footprint of map array by shuffling its members [FS#6218] (r27132, r27126) - Fix: Dropdown- and tooltip-windows should not steal the focus (r27131) - Fix: [NewGRF] Action 7/9 condition 0A failed for present, but disabled, NewGRF (r27119) - Fix: Road vehicles could not reverse to be sent to depots when the following tile has the right type to run on, but could not be entered [FS#6183] (r27107) - Fix: Use the actual max speed of the vehicle in front when determining if a RV can overtake [FS#6176] (r27106) - Fix: grow_counter was not properly bounded by growth_rate, but by some other value used to calculate growth_rate [FS#6195] (r27105) - Fix: [Script] Support 64 bits integers in ScriptLists [FS#6194] (r27104) - Fix: [Script] Money values would end up wrong in strings when outside the bounds of a 32 bits integer [FS#6194] (r27102) 1.5.0-beta1 (2014-12-24) ------------------------------------------------------------------------ - Feature: Support .txt.gz and -txt.xz changelog, readme and license files in basesets, NewGRFs, etc (r27035, r27034) - Feature: More height levels [FS#4126] (r27010) - Feature: Latin translation (r26993) - Feature: Add option to choose normal, double or quad-size interface (r26990) - Feature: [Script] Swap method for script lists (r26894) - Feature: [Script] ScriptStationList_Cargo for sorting cargo by from and via (r26893) - Feature: [Script] API for retrieving planned flow (r26892) - Feature: [CargoDist] Predict links for station-autorefitting vehicles (r26889) - Feature: Setting for limiting the height of bridges (r26882) - Feature: Make aircraft ascend/descend when they are too close to the ground or too far away (r26866) - Feature: Allow hiding of non-interesting engines in the GUI (r26805, r26804) - Feature: Vehicle sorting in autoreplace GUI [FS#1640] (r26800) - Feature: [NewGRF] Advanced visual effects with multiple effect sprites independent of spawning model (r26988, r26747) - Feature: Warn about missing industries after generating a map (r26729) - Feature: Upgrade currently active NewGRFs to newest installed version (r26613) - Feature: Save and load grfid and md5sum of NewGRFs in config file (r26611) - Feature: Select an editable preset name for saving (r26610) - Feature: Cancel cargo delivery from industries/houses to stations after about 21 months of not having picked up any of the cargo (r26582) - Feature: Give a warning when a plane's orders tell it to use a runway which is too short for it [FS#6009] (r26566) - Feature: [Script] Extended API for CargoDist (r26557) - Feature: Show measured order times in timetable GUI also when not timetabled (r26550) - Feature: Prompt for confirmation when deleting a vehicle group (r26455) - Feature: Hierarchical vehicle subgroups (r26450) - Feature: Allow more sound sleep for dedicated servers when there's nothing to do and nobody paying attention (r26449) - Feature: [NewGRF] Add vehicle modflag 1 (unloading in progress) (r26430) - Change: Improvements to the man page (r27091, r27012) - Change: Allow to set the granularity of the tooltip hover time in milliseconds instead of seconds. New default value is 250ms (r26815) - Change: Follow SI recommendation about spaces between numbers and units [FS#6086] (r26733) - Change: [CargoDist] Save locations instead of distances in link graphs to reduce size (r26646) - Change: [Squirrel] Make the internal integer for scripts always 64 bits, so scripts behave the same on 32 and 64 bit architectures and money can be represented properly (r26585, r26584) - Change: Reshuffle advanced settings tree (r26614, r26536) - Change: Add backend-independent config-file setting to disable 8bpp video modes, and disable 8bpp by default (r26522) - Fix: [OS/2] Compile again [FS#6186] (r27092) - Fix: Compilation with freetype2 version 2.5.4 and newer [FS#6185] (r27079) - Fix: Variable 47 used the carge translation table of the wrong GRF in case of callback 1D [FS#6182] (r27075) - Fix: Some lists did not use natural string sorting [FS#6172] (r27063) - Fix: Mercurial version detection failed if personal presets were configured (r27059) - Fix: [OSX] Don't require double-press from non-dead console hotkeys [FS#5812] (r27046) - Fix: Crash when having the vehicle list opened from a buoy or oil rig when the buoy/oil rig is removed (r27030) - Fix: Unit number was not always fully shown in depots [FS#6102] (r27014) - Fix: [CargoDist] Reserve cargo only after unloading finished or if the vehicle has the desired cargo already [FS#6110] (r26918) - Fix: [Squirrel] Loading a value saved as boolean caused it to be of type integer instead of boolean (r26785) - Fix: [Squirrel] Harden string handling (r26777) - Fix: [OSX] Implement more of the text editing API to prevent crashes and improve IME support [FS#5972] (r26758) - Fix: Incorrect saving of order backups [FS#6066] (r26700) - Fix: Ordering a vehicle to a competitor's rail waypoint displayed an error message. Ignore the click as is done for the other order types to competitor's stuff [FS#6059] (r26692) - Fix: [Script] Loading/parsing of info .nuts was done in the same VM, causing e.g. constants to break the loading of info of other scripts [FS#5973] (r26617) - Fix: [CargoDist] Improve estimation of link capacitites (r26549) - Remove: A bunch of archaic settings from the GUI (r26528, r26526, r26525) 1.4.4 (2014-10-21) ------------------------------------------------------------------------ (None) 1.4.4-RC1 (2014-10-08) ------------------------------------------------------------------------ - Fix: Image widgets stored 32bit SpriteID in uint16 (r26971) - Fix: Owner of road depot road types were not properly changed upon bankruptcy [FS#6126] (r26955) - Fix: Compilation on HAIKU (r26922) - Fix: Crash when enabling 'Full animation' if multiplayer chat text is on screen [FS#6096] (r26919) - Fix: Height computation of game script text in town GUI did not consider margins [FS#6119] (r26859) - Fix: [Squirrel] Debian lintian issues (r26853) - Fix: Compilation of strgen on various platforms like Solaris (r26850) - Fix: Better display of refit information for articulated vehicles [FS#6113] (r26849, r26848) - Fix: Do not assign a next hop when returning cargo [FS#6110] (r26847) - Fix: The ok-button in the OSK for the signs list should just close the OSK [FS#6116] (r26827) 1.4.3 (2014-09-23) ------------------------------------------------------------------------ (None) 1.4.3-RC2 (2014-09-14) ------------------------------------------------------------------------ - Fix: Crashes on joining a server with pending order backups [FS#6112] (r26819) - Fix: Crashes on start due to dereferencing the -1 index of the file names array of music files (r26809) 1.4.3-RC1 (2014-09-07) ------------------------------------------------------------------------ - Fix: TC_NO_SHADE did not work for 32bpp text rendering (r26792) - Fix: Loading a game with order backups leaked Orders and left unreachable items in the pool (r26787) - Fix: Buffer overrun in SQCompiler::Error (r26764) - Fix: Desync due to not always properly restoring game state from the savegame (r26753) - Fix: [Script] Crashes and infinite loops when using lists in item-descending order [FS#6085] (r26744) - Fix: Incorrect CFLAGS when enabling gprof profiling (r26737, r26735) - Fix: Do not reset the last selected airport or layout, unless it is really necessary [FS#6083] (r26732) - Fix: Use the normal search path to look for xdg-open at Unix [FS#6077] (r26724) - Fix: Properly check for cargo acceptance of houses [FS#5997] (r26723) 1.4.2 (2014-08-16) ------------------------------------------------------------------------ (None) 1.4.2-RC2 (2014-08-03) ------------------------------------------------------------------------ - Change: Use awk instead of trying to convince cpp to preprocess nfo files (r26708) - Fix: CMD_CLEAR_ORDER_BACKUP should not be suppressed by pause modes (r26716) - Fix: [NewGRF] Parameters to SCC_NEWGRF_PUSH_WORD and SCC_NEWGRF_UNPRINT were not skipped during drawing (r26713) - Fix: [OSX] Compilation fails with some lzo2 versions, if __LP64__ is defined to 0 instead of checking whether it is defined [FS#6069] (r26709) - Fix: Wrong breakdown sound was played for ships [FS#6015] (r26706) - Fix: Integer overflows in acceleration code causing either too low acceleration or too high acceleration [FS#6067] (r26702) - Fix: Discard incorrectly saved order backups when clients join [FS#6066] (r26700) - Fix: Do not crash when trying to show an error about vehicle in a NewGRF and the NewGRF was not loaded at all (r26699) - Fix: Slovak uses space as group separator in numbers [FS#6064] (r26695) - Fix: Tighten parameter bound checks on GSCargoMonitor functions, and return -1 on out-of-bound parameters (r26685) 1.4.2-RC1 (2014-07-03) ------------------------------------------------------------------------ - Fix: CargoPacket::SourceStation() returns a StationID (r26660) - Fix: Days in dates are not represented by ordinal numbers in all languages [FS#6047] (r26657) - Fix: Production cheat cannot be allowed to be active in multiplayer for desync reasons, even when activated in singleplayer previously [FS#6044] (r26656) - Fix: Make sure an 'abs' is used that supports int64 when using 'abs' on those variables (r26651) - Fix: Support save/load chunk lengths of up to (1 << 32) - 1 [FS#6041] (r26650) - Fix: Incorrect usage of string commands in the base language [FS#6037] (r26642, r26640, r26639, r26632) - Fix: Segmentation fault when encountering a .obg/.obs/.obm with empty string/zero length MD5 checksums [FS#6038] (r26637) - Fix: The 'Load' button was not properly enabled/disabled for old savegames without NewGRF information (r26634) - Fix: If the video driver fails to supply a list of resolutions, display an error message [FS#6012] (r26629) 1.4.1 (2014-06-02) ------------------------------------------------------------------------ - Fix: First send packages about new company, then clients joining it to admin port [FS#6025] (r26616) 1.4.1-RC2 (2014-05-18) ------------------------------------------------------------------------ - Fix: Save/load issues on big endian machines (r26593, r26590, r26589) - Fix: Consider multiheaded trains in station refits [FS#5995] (r26586) - Fix: Game script could be changed in game by double clicking [FS#5974] (r26583) - Fix: Transfer stations also should have a cargo rating [FS#5989] (r26581, r26580) - Fix: [Network] AIs would not reset certain network state information upon creation of their company [FS#6003] (r26578, r26576) - Fix: [Network] Client of non-dedicated server was not correctly put into the first company for all state variables [FS#6001] (r26577) 1.4.1-RC1 (2014-05-04) ------------------------------------------------------------------------ - Change: Remove demand calculation based on tiles (r26484) - Change: Use pkg-config for libpng as well (r26435, r26433, r26432) - Change: Use better distance metric for link graph [FS#5941] (r26411) - Fix: [Windows] Crash when the operating system performs the "paint" callback during window creation [FS#5994] (r26539, r26538) - Fix: OpenBSD compilation [FS#5992] (r26523) - Fix: prevent from ever reading huge (or negative) amounts of data in strgen (r26521) - Fix: Severity rating of dedicated server messages during world generation (r26518) - Fix: Buffer overruns in handling of symbolic links inside tars (r26514) - Fix: Incorrect usage of strecpy (r26505, r26485) - Fix: Reading console input on dedicated server relied on unspecified behaviour (r26496) - Fix: Allow single-vehicle consists to station-refit in a meaningful way (r26483) - Fix: Prevent comparing to NULL when strndup could not allocate memory (r26476) - Fix: Potentially undefined shifts in NewGRF code (r26475) - Fix: Make sure there is no uninitialised sprite data (r26473) - Fix: Draw text shadow for ellipses (r26467) - Fix: Add special handling for PALETTE_CRASH to work for non-8bpp-mapped sprites (r26463) - Fix: Avoid division by 0 when scaling flow values [FS#5970] (r26448) - Fix: Draw links to match _settings_game.vehicle.road_side [FS#5961] (r26445) - Fix: Load button for heightmap list was missing [FS#5953] (r26428) - Fix: Do not crash when supplying an invalid filename without extension to cmd parameter -q (r26423) - Fix: Some road constructions used the rail sound effect [FS#5946] (r26422) - Fix: Goal GUI failed to shade [FS#5948] (r26420) - Fix: Shares button state was not appropriately updated when switching setting or company [FS#5947] (r26416) 1.4.0 (2014-04-01) ------------------------------------------------------------------------ (None) 1.4.0-RC1 (2014-03-18) ------------------------------------------------------------------------ - Feature: [Script] APIs to get cargo waiting from/via other station (r26396) - Fix: Do not explain "symmetric" cargodist mode when the setting does not allow it [FS#5939] (r26394) - Fix: Update distances between link graph nodes when station sign is moved (r26393) - Fix: No need to call OnFocus twice [FS#5933] (r26392) - Fix: Select a specific font size when freetype fails to select one automatically [FS#5885] (r26389) - Fix: Return correct values from ICU iterators in case of leading or trailing whitespace [FS#5924] (r26384) - Fix: All goal commands invalidated the goal list of company 0 [FS#5932] (r26382) 1.4.0-beta5 (2014-02-25) ------------------------------------------------------------------------ - Feature: Warn the user about empty setting search results, and about missing setting search results due to filtering (r26322, r26321) - Feature: [NewGRF] Extend object variable 0x60 to also return the view [FS#5696] (r26316) - Feature: Allow map sizes up to 4096x4096 (r26319) - Feature: [NoGo] Allow GS to hide story page date (r26307) - Feature: [NoGo] More story APIs: RemovePageElement, GetCompany, GetDate, SetDate (r26306) - Feature: [NoGo] ScriptStoryPageElementList() - a list of all story page elements for a given page (r26305) - Feature: [NoGo] ScriptStoryPageList() - a list of all story pages (r26303) - Change: improve the performance of map generation (r26313, r26312, r26311, r26310, r26309, r26308) - Fix: Station sizes > 8 were always allowed [FS#5929] (r26375) - Fix: [NewGRF] Mixed up callback mask flags in station inspect window [FS#5928] (r26374) - Fix: Calling DoCommandP during the gameloop cleared pending persistent storage changes [FS#5831] (r26371) - Fix: [Windows] Use a separate event to indicate that the drawing thread has finished initialising, preventing potential deadlocks (r26367) - Fix: [Windows] Protect the whole video driver from concurrent access (r26366) - Fix: [Windows] Do not draw the cursor when its sprite is not ready and set _screen.dst_ptr immediately when the buffer changes [FS#5867] (r26365) - Fix: Writing out of the bounds of the rail type map [FS#5892] (r26364) - Fix: Reset the default window size icon size just like all the other cached icon sizes [FS#5906] (r26362) - Fix: ClientSizeChanged is only called via WndProcGdi which already has the mutex [FS#5922] (r26360) - Fix: Some order options do not combine with others, e.g. go via + full load [FS#5845] (r26357) - Fix: Protect all VideoDriver_SDL methods with the (now recursive) _draw_mutex (r26351) - Fix: Make sure link graph jobs can delete themselves after SLA_NULL [FS#5898] (r26347) - Fix: Call Layouter::ReduceLineCache from GenerateTownName in all cases to keep cache size in check [FS#5870] (r26346) - Fix: Rewrite SmallStack so that it does not use a pool and is re-entrant (r26343) - Fix: Reroute cargo when automatic distribution is switched off [FS#5902] (r26341) - Fix: Do not redraw the link graph overlay if it is empty [FS#5908] (r26338) - Fix: Some inconsistencies regarding link graph (job) IDs (r26331) - Fix: The case of rerouting cargo from one VehicleCargoList to another (r26330) - Fix: Take care of next_station when reassigning from MTA_DELIVER to MTA_TRANSFER [FS#5901] (r26327) - Fix: when autosaving the message about a save already happening could be shown, even though the code's intention was to not show it [FS#5871] (r26326) - Fix: Check whether NewGRF change vehicle capacity when they are not supposed to, and truncate cargo appropriately if they are allowed to [FS#5897] (r26317) - Fix: The giant-screenshot confirmation window only triggered for ridiculously big screenshots, not for ludicrously big ones [FS#5899] (r26314) 1.4.0-beta4 (2014-02-06) ------------------------------------------------------------------------ - Change: [NewGRF] Make vehicle variable 61 return 'not available' instead of zero when using it in invalid callback contexts (r26294) - Feature: Display speed limit also for road bridges in the TileInfo window [FS#5849] (r26277) - Fix: [NoGo] Invalid DoCommand return callback for method returning bool (r26298) - Fix: Correctly identify opposite ends of bridges and tunnels when converting rails [FS#5866, FS#5888] (r26291) - Fix: Prevent infinite recursion also in RefreshLinks [FS#5878] (r26283) - Fix: [NoAI] Some RemoveRail methods required to set a valid railtype, though it was not used anyway. Remove the need to set one [FS#5853] (r26279) - Fix: Do not spawn link graph jobs for link graphs with only one node [FS#5874] (r26276) - Fix: [NewGRF] If NewGRF provided the same station name for different industry types, stations would end up with same name. So also consider the provided name, not only the industry type (r26275) 1.4.0-beta3 (2014-01-21) ------------------------------------------------------------------------ - Feature: Several small performance improvements with the SSE blitters (r26260, r26259, r26256, r26255, r26254) - Feature: [NewGRF] Add StringCodes 9A 1B, 9A 1C and 9A 1D to display amounts of cargo (r26244) - Fix: Do not run into infinite recursion when getting next stopping station [FS#5865] (r26267, r26263) - Fix: Update smallmap overlay if player joins different company and make sure company masks are valid [FS#5860] (r26266) - Fix: Do not rebuild the link graph overlay cache twice in a row (r26265) - Fix: Custom currency was reset on game start (r26262) - Fix: Possible out of bounds reads with the SSE blitters [FS#5854, FS#5855] (r26247) - Fix: Do not over reserve after autorefit, but do reserve mail for aircraft (r26236) - Fix: Decimal and digit separators were swapped for Korean language (r26235) 1.4.0-beta2 (2014-01-07) ------------------------------------------------------------------------ - Feature: Blitter autoselection is now based on full animation state, so a non-animated specialised blitter will generally be chosen when animation is turned off (r26217) - Feature: Specialised animated SSE4 blitter, and non-animated SSE4.1, SSSE3 and SSE2 blitters, improving the blitting significantly in many situations (r26214, r26213, r26212, r26211) - Feature: Specialised SSE 4.1 sprite sorter, improving the sorting performance significantly (r26205) - Fix: Validate everything from ini, obg, obs, obs, ... files [FS#5829] (r26206) - Fix: Allow refitting at station if cargo has already been reserved (r26187) - Fix: Visual effects did not work for articulated RV parts (r26180) 1.4.0-beta1 (2013-12-24) ------------------------------------------------------------------------ - Feature: [NewGRF] Vehicle variable 4D for determining the position within an articulated vehicle (r26157) - Feature: [NewGRF] Invalidate vehicle colour palette when leaving a station [FS#5669] (r26027) - Feature: [NoGo] New goal type that show a story page when clicked (r26012) - Feature: Optional filter parameter to the 'content state' console command, to limit the content list to only content where the name match the filter (r26000) - Feature: When calling the 'content select' console command without args, display all selected content (r25999) - Feature: XDG base directory support [FS#5385] (r25975) - Feature: [Script] ScriptTown::GetFundBuildingsDuration (r25969) - Feature: [Script] ScriptTown::TOWN_GROWTH_NONE to indicate no town growth via ScriptTown::SetGrowthRate and GetGrowthRate (r25968) - Feature: [NoGo] GSTown::TOWN_GROWTH_NORMAL to reset a town growth rate set previously via GSTown::SetGrowthRate (r25967) - Feature: [NewGRF Debugging] Inspecting other vehicles in a chain (r25946) - Feature: [NewGRF] Object property 0x18 to allow specifying the number of objects of that type being placed upon map creation (r25878) - Feature: [NewGRF] Object property 0x10, bit 13 indicating that object amount scales with water content of map border (e.g. used for lighthouses) (r25874) - Feature: Highlight active goto item in order list dropdown [FS#5784] (r25859) - Feature: [Admin] Send info on bankruptcy quarters also in ADMIN_PACKET_SERVER_COMPANY_INFO [FS#5756] (r25845) - Feature: Increase maximum number of object instances on the map from 64k to about 16M (r25844) - Feature: Increase the total number of object types from 256 to 64000 (r25835) - Feature: [NewGRF] Increase the object class limit from 32 to 255 (r25831) - Feature: Toggle button for wrapping lines in the textfile GUI [FS#5748] (r25816) - Feature: [NoGo] Game Scripts can now charge fees and give money to companies (r25788) - Feature: [Script] Allow AIs and GS to found towns. Allow GS to rename towns (r25785) - Feature: Add keywords to the openttd.desktop.in file (r25783) - Feature: Sticky and shade buttons for jukebox window [FS#5743] (r25776) - Feature: Additional layered main toolbar arrangements (r25772) - Feature: Allow implicit orders even if no explicit ones are given (r25735) - Feature: [OSX] Pinch gesture support for zooming [FS#4760] (r25666) - Feature: Split unit localisation choice into a choice per type of unit, and move it to the advanced settings (r25508) - Feature: Have tractive effort in imperial (lbf) and metric (kgf) units, have weights and volumes in imperial units (short tons, gallons) [FS#5482] (r25508) - Feature: Differentiate between total waiting cargo count and available (not reserved) cargo count in the station list and sort based on the cargo count, not the cargo value (r25405) - Feature: Timetable spreading of vehicles by Ctrl+Click when setting a start date (r25377) - Feature: Allow opening a goal list and story window specific to a company (r25372, r25369) - Feature: Show cargo by next hops and final destinations in the station GUI (r25365) - Feature: Consider cargo waiting at other stations for rating at the origin station (r25362) - Feature: Distribute cargo according to plan given by linkgraph (r25361) - Feature: [NoGo] GUI for viewing story pages (r25344) - Feature: Add industry list to scenario editor's map menu (r25335) - Feature: [NoGo] Allow more concurrent goals in a game (r25299) - Feature: [NoGo] Goals can now have a progress text and/or be marked as completed (r25296) - Feature: Allow saving window sizes as default sizes (r25295) - Feature: Add another button to window title bars to resize the window to its default size (r25294) - Feature: Save stickyness of windows when Ctrl+Clicking the sticky button (r25292) - Feature: When opening the object-build window, restore the object build-window to the previous state (r25284) - Feature: Show the approximate monthly supply to a station of the different cargoes (r25272) - Feature: [Win32] Driver param for the DirectMusic driver to specify the output port to use [FS#5552] (r25269) - Feature: Linkgraph overlay over main viewport (r25264) - Feature: Linkgraph overlay for smallmap (r25262) - Feature: Display imminent closure of an industry in its view window (r25238) - Feature: [NewGRF] Expose sprite base of foundation and shore sprites via Action D Game Variables (r25230) - Feature: [NewGRF] Variable 0x82 for canals and rivers (dike map) (r25229) - Feature: [Script] ScriptStation::HasRating [FS#5514] (r25150) - Feature: Add sorting on rating for the town directory window [FS#5288] (r25097) - Feature: Introduce dropdown for selecting the sort criterion in the town directory window (r25094) - Feature: Georgian Lari and Iranian Rial as currencies [FS#5212] (r25076) - Feature: Collapse subtypes in the refit GUI and only expand them after selecting the cargo type (r25044) - Feature: Only display subtypes in the refit GUI which are available for all selected vehicles. Also add a generic list item to refit while keeping the subtypes of individual vehicles [FS#3764] (r25043) - Feature: Show the amount of cargo that has already been reserved by full loading vehicles in the station (r25013) - Change: [NewGRF] Reset the temporary storage registers for every sprite resolving (r26173) - Change: Improve layout of build-airport GUI [FS#5832] (r26165) - Change: Make it slightly more clear what ports are coming from where in the debug output when listening (r25997) - Change: Preselect the current replacement in the right-side list of the autoreplace GUI, instead of selecting the first resp. previous item [FS#5734] (r25919) - Change: Unify behaviour when clicking on different items in the goto dropdown list when giving orders (r25894) - Change: Do not offer subsidies for auto-distributed cargo [FS#5766] (r25882) - Change: Allow to remove unowned objects unless they have the 'unremovable' flag (r25879) - Change: In scenario editor allow to build all objects which were available at any point in the past to support building scenarios with historic items (r25875) - Change: Display the cost to upgrade a bridge at the end of bridge that was clicked and not the other end, which could be outside of the screen in some cases (r25854) - Change: [NewGRF] Lower the limit of airport tile types, house types, industry tile types and object types per NewGRF from 256 to 255 to prevent usage of ID 0xFF in Action3, and thus allowing it to become an extended byte somewhen (r25841, r25839, r25837, r25834) - Change: Clarify the relevance of the permissible palettes (r25792) - Change: [NewGRF] Invalidate vehicle recolour palette during (un)loading [FS#5669] (r25648) - Change: If an editbox is configured to be cleared with ESC, but the editbox is already empty, unselect the editbox instead (r25647) - Change: Make the bridge and object picker not restore their previous size, but the previously saved size (r25543) - Change: Right align the infrastructure statistics [FS#5595] (r25515) - Change: Clarify the meaning of the server advertisement settings (r25252) - Fix: Unify the time a RV needs to travel through a curve [FS#5831] (r26169) - Fix: Certain hotkeys crashed the content GUI when the list was empty [FS#5834] (r26167) - Fix: Backup data of altered persistent storage arrays was freed twice [FS#5830] (r26161) - Fix: [Script] Various API functions did not check whether ScriptRoad::SetCurrentRoadType was called appropriately [FS#5825] (r26149) - Fix: [Script] API failed for vehicles with only implicit orders [FS#5824] (r26148) - Fix: Several fixes found by static code analysis (r26132, r26130-r26097, r26091-r26077, r26073-r26046) - Fix: Invalidate vehicle colour palette again when rearranging consist, reversing, etc (r26026) - Fix: [NoGo] Properly validate the range of the growth rate passed to GSTown::SetGrowthRate, instead of masking it to 16 bit (r25966) - Fix: [Admin] The frame of a command packet was not set for the packets that were sent via the admin interface (r25770) - Fix: [OSX] The new 10.7 fullscreen code can now also be compiled with older SDK versions [FS#4744] (r25657) - Fix: Under certain circumstances a track type change would make the end-of-line-is-red setting ineffective [FS#5216] (r25609) - Fix: Highlight the right entry in the sorting selector in station view window (r25426) - Fix: Suppress focusing editboxes which are not visible (r25413) - Fix: Add missing compatibility settings in afterload (r25390) - Fix: Allow changing GS settings in-game via the AI/GS config window [FS#5507] (r25104) - Fix: [NewGRF] Do not compare GRF local cargo subtype IDs from different GRFs (r25042) - Remove: Ordered refit with subtypes, since the cases where it worked were corner cases rather than the general case [FS#3764] (r25041) 1.3.3 (2013-11-29) ------------------------------------------------------------------------ - Fix: Aircraft crashing near the map's border due to a lack of airports could trigger a crash [CVE-2013-6411] [FS#5820] (r26134) 1.3.3-RC2 (2013-11-24) ------------------------------------------------------------------------ - Fix: [Script] Prevent scripts from crashing OpenTTD when they send text with command codes to user editable texts such as sign and station names [FS#5818] (r26093, r26092) - Fix: Occasional hanging when client joins [FS#5811] (r26043) - Fix: Multi line text was handled incorrectly causing glitches [FS#5809] (r26037, r26036) 1.3.3-RC1 (2013-11-17) ------------------------------------------------------------------------ - Fix: Crash when the ICU layouter thinks a font is corrupted [FS#5711] (r26029, r26018, r26017, r26016, r26015) - Fix: Make the installer warning about Windows XP SP3 not trigger on the 64 bit Windows XP which is not really Windows XP to start with [FS#5773] (r26028) - Fix: Only forward key presses to the IME system if an edit box has the input focus (r26023, r25693, r25691, r25689, r25686, r25684, r25682, r25681, r25667) - Fix: Having trains miss a platform that is just being modified is less of a problem than having trains stop twice without moving [FS#5684] (r26013) - Fix: --help text of ./configure for packages that require pkg-config (r26011) - Fix: The AI/GS library name to use in Import, is not the name given by GetName but GetInstanceName [FS#5662] (r26010) - Fix: [Windows] Conditional expression with enumeral with non-enumeral type (r26009) - Fix: Game script showing vehicle on e.g. a goal, then the vehicle being removed and eventually being replaced by a non-user vehicle (most likely smoke) causing an assertion to trigger [FS#5804] (r26007, r26006) - Fix: Crash when transferring savegame from server to client [FS#5478] (r26005) - Fix: [OSX] Text input into an edit box would trigger hotkeys [FS#5705] (r26003, r25743, r25671) - Fix: Comma key collided with F12 key for hotkeys; also remove '+' as that is generally not a key (the '+' on the numpad is a separate one) [FS#5679] (r25973) - Fix: Rail laying sounds of others could be heard in multiplayer [FS#5665] (r25972) - Fix: [SDL] Recursive mutex locking when changing blitter [FS#5787] (r25970) - Fix: The wrong vehicle would be taken in a shared order vehicle list window when the ID >= 65536, causing assertions triggering later on [FS#5800] (r25965) - Fix: [OSX] Compilation under OSX 10.9 [FS#5797] (r25962, r25951, r25950, r25913) - Fix: [NewGRF] A powered rail type implies it is compatible as well, but some NewGRF did not state that causing the path reservation code to bail out in some cases because there was no compatible path [FS#5779] (r25961) - Fix: Temporary persistent storage modifications, e.g. command tests or those from GUI, were not properly reset, creating the possibility of desyncs [FS#5772] (r25956) - Fix: Train's 'force proceed' status gets reset when the track on the other side of the tile has a signal [FS#5723] (r25955) - Fix: Wrong signal conversions for savegames from before 0.4.5 [FS#5731, FS#5732] (r25954, r25953) - Fix: Do not skip numbers when skipping spaces and other sorting 'improving' characters [FS#5719] (r25952) - Fix: Text direction forcing characters were not filtered out, but shown as ? when ICU was not used for layouting. These are included in chat and console messages to force them to be displayed right [FS#5683] (r25949) - Fix: NewGRF inspect window in RTL mode (r25943) - Fix: [NoGo] Preserve the relative town growth progress when changing the town growth rate [FS#5786] (r25931) - Fix: Several drawing overflows in the signal GUI [FS#5733] (r25929, r25928, r25927) - Fix: Centre the edit sign window like all query windows (r25918) - Fix: Initialisation of default objects swapped cost and dates (r25868) - Fix: Use the actual sprite dimensions for sizing the dropdown arrow of dropdown widgets (r25864) - Fix: If the child widgets of a NWidgetHorizontal container do not fill the complete container, align them according to text direction [FS#5686] (r25862, r25729) - Fix: When clearing font cache, also clear layout cache [FS#5737] (r25860) - Fix: Goto button in order window was not always lowered when it should [FS#5783] (r25858, 25857) - Fix: Searching for a suitable font failed, if one of the fonts had no '?' glyph, and no baseset is installed [FS#5704] (r25822, r25820) - Fix: Sprite 0 was considered available, even if no baseset was loaded (r25821) - Fix: [GS] Language file scanner considered filenames starting with '.' as valid translations, resulting in languages with empty name, which causes trouble [FS#5750] (r25818) - Fix: [GS] Handle savegames which contain GS translations for languages with empty name more gently [FS#5750] (r25817) - Fix: [Script] ScriptTile::IsBuildableRectangle could report true for tiles outside of the map, if they happened to wrap around into a valid area [FS#5754] (r25815) - Fix: [Script] Decoding JSON data with an empty array from Admin port failed (r25809) - Fix: Ensure the vehicle bar is high enough for the start/stop vehicle graphics [FS#5740] (r25805) - Fix: Lower sprite and text at the vehicle bar if it is pressed [FS#5739] (r25804) - Fix: Draw start/stop graphics of the vehicle bar at the right place in RTL mode [FS#5738] (r25803) - Fix: [NewGRF] Do not allow changing palette when it is set by the NewGRF (r25794, r25793, r25972) - Fix: Some spelling corrections to Catalan and Latin American town names [FS#5746] (r25775, r25774) - Fix: If old savegames contain bridges over owned land, keep on drawing the bridges nevertheless [FS#5725] (r25753) - Fix: Several RTL alignment issues [FS#5692] (r25733, r25732, r25731) - Fix: NWidgetMatrix used pip_pre and pip_post inconsistently and incorrectly, causing misalignment for RTL [FS#5686] (r25727) - Fix: Right side of object class string was misaligned (r25726) - Fix: [OSX] Do not pass -mmacosx-version-min to compilers that do not support it (r25706) - Fix: Autoreplace/renew also refits free wagons [FS#5700] (r25698) - Fix: Textbuf caret rendering for complex scripts (e.g. Tamil) (r25696, r25694, r25652, r25651, r25092, r25091) - Fix: Vehicle::MarkDirty must be called for the front engine [FS#5700] (r25695) - Fix: [Win32] Several issues regarding conversion of characters (r25677, r25676, r25675, r25674, r25673) - Fix: [Win32] Handle Unicode characters from outside the BMP correctly (r25672, r25670, r25669, r25668) - Fix: [OSX] Crash when unhiding the main window [FS#4689] (r25665) - Fix: [OSX] Bootstrap downloading of a baseset did not work [FS#4847] (r25664) - Fix: [OSX] Monospace font detection [FS#4857] (r25663, r25662) - Fix: [OSX] Rework font detection to work even if no default font sprites are present [FS#4847] (r25661) - Fix: [OSX] The name is OpenTTD, not OTTD (r25660) - Fix: [OSX] System mouse cursor could become visible during dragging [FS#4420] (r25659) - Fix: [OSX] The mouse cursor would sometimes jump near the window borders [FS#4392] (r25658) - Fix: [OSX] The new 10.7 fullscreen code can now also be compiled with older SDK versions [FS#4744] (r25656) - Fix: [OSX] Mouse cursor was not displayed properly after switching to fullscreen on 10.7+ (r25655) - Fix: Improve character and word deletion for CJK languages and complex scripts (r25654, r25653) - Fix: [OSX] Define version constants before they are used (r25643) - Fix: Some icu_config scripts are too stupid to separate two ldflags by spaces, thus only call it with one (r25642, r25638) - Fix: Do not suggest a start date for the game when there will be no vehicles available at all (r25640, r25639) - Fix: City list sort of population and rating are reversed compared to the icon [FS#5666] (r25630) - Fix: [Script] Give a slightly less generic error when removing nonexistent rail [FS#5651] (r25614) - Fix: [Script] Do not return ERR_UNKNOWN when trying to move an order to its current location [FS#5648] (r25612) - Fix: Various misreferences in AI and GS changelog [FS#5649] (r25607) - Fix: [Script] If a NewGRF returned station type that could not be built by an AI via callback 18, an unknown error would be thrown instead of falling back to the default station [FS#5641] (r25605) - Fix: Only the front engine's date of last service was updated [FS#5550] (r25604) 1.3.2 (2013-07-27) ------------------------------------------------------------------------ (None) 1.3.2-RC2 (2013-07-13) ------------------------------------------------------------------------ - Fix: [Admin] End-of-rcon data could not be determined reliably for any rcon command [FS#5643] (r25598, r25588, r25587) - Fix: [Content] When the server closed the connection, the client would for eternity try to read a packet and never timeout making it impossible to reconnect [FS#5635] (r25597) - Fix: [Script] Changing the script difficulty level in-game would also change the settings using the default even though they were not allowed to change in-game [FS#5644] (r25592) - Fix: [Admin] Ensure that sent and received length of JSON strings are the same [FS#5646] (r25590, r25589) - Fix: [Squirrel] Stack overflow did not show an error, due to the stack to throw the error already being full [FS#5320] (r25585) - Fix: [Script] Documentation implied that XXList::AddItem has a default for value if it is not filled in [FS#5638] (r25579, r25577) - Fix: Layouter caused significant slowdown with text heavy windows, cache it to make it manageable (r25574, r25570, r25569, r25567, r25564) - Fix: Make content list appear faster (r25573) - Fix: Non-ICU layouter started new lines with the space which triggered the linebreak (r25568) - Fix: If the next order cannot be resolved, reset the current order property instead of leaving it in an intermediate state [FS#5633] (r25562) - Fix: [Squirrel] Infinite recursion loop in freeing data via a looping set of references [FS#5568] (r25558) - Fix: One could build bridges over owned land of another company [FS#5524] (r25557) - Fix: [Script] Texts from scripts were not validated before they were shown, causing an assertion to trigger [FS#5632] (r25555) - Fix: Provide a warning when no vehicles are available, and tell what to do in that case [FS#5530] (r25553) - Fix: Possible reading of uninitialised memory due to undefined execution order (r25551) - Fix: [Windows] Race condition between two drawing threads could crash OpenTTD [FS#5571] (r25550) - Fix: ICU returns the width of the visual run as if the trailing space was added (in case a newline was added). This caused the width to be more than the requested width, but it would still be drawn correctly [FS#5626] (r25547) - Fix: Small memory leaks (r25546) - Fix: [GS] The checks and validations for setting the extra text in the town window became too stringent [FS#5625] (r25544) 1.3.2-RC1 (2013-06-30) ------------------------------------------------------------------------ - Remove: SETX(Y) does not work at all with other than default fonts, so get rid of it (r25454) - Fix: strndup should not examine strings beyond its upper limit [FS#5621] (r25527) - Fix: Proper support for Brahmic scripts (e.g. Tamil and Thai) [FS#5481] (r25526, r25525, r25524, r25514, r25513, r25512, r25511, r25501, r25493, r25485, r25483, r25482, r25481, r25478, r25477, r25476, r25474, r25473, r25472, r25471, r25470, r25469, r25468, r25467, r25466, r25465, r25463, r25462, r25455, r25452, r25451, r25450, r25447, r25446, r25445, r25444, r25443, r25442, r25441, r25440, r25439, r25438, r25437, r25436, r25343, r25157) - Fix: SDL does not give an event when an application gets mouse focus while going to full screen, so manually force the mouse-is-in-window state [FS#5587] (r25523) - Fix: [NewGRF] When cargo NewGRF define a multiplier to modify vehicle capacities, use the same multiplier to modify loading speed (r25497, r25479) - Fix: When adding bits to a (train) station, the train trying to stop there could overshoot the (new) stop location and not stop at all [FS#5553] (r25495) - Fix: The face of the manager differed on clients when the company was started after the clients joined [FS#5610] (r25491, r25490) - Fix: Do not send encoded texts to names, but decode them into a plain C string and then pass them on [FS#5613] (r25489, r25488) - Fix: Do not allow control codes in names of things (signs, vehicles, towns, stations, etc), so they have a known maximum fixed size and are, by definition, the same for everyone (r25487) - Fix: Missing length validation for town and president names in script APIs (r25486) - Fix: [OSX] OS X SDK versions >= 10.5 always have a non-const iconv declaration (r25480) - Fix: Disable the depot-refit button in the order GUI, if the consist is not refittable unless it already has a refit order (r25459, r25458, r25457) - Fix: When town creation failed, removing remnants of the construction failed on protected houses [FS#5603] (r25429) - Fix: There were two hotkeys to toggle between 'unload' and 'unload if possible' (r25406) - Fix: The size of station construction windows could oscillate when resizing the window moved the mouse into the window [FS#5596] (r25395) - Fix: Restrict renaming engines to the server, just like renaming towns (r25394) - Fix: Loading only 8 bits into a 16 bit variable could cause endianness problems (r25337) - Fix: Check for zero width space in translations and fail upon finding them [FS#5589] (r25326) - Fix: [SDL] Keyboard input stopped working after fullscreen toggle [FS#5580] (r25318) - Fix: Proper size-estimation for numbers with n digits, i.e. not assume a particular number is the widest [FS#5562] (r25314, r25313) - Fix: Do not focus the editbox in the NewGRF window, if there is no editbox visible (r25307) - Fix: Game Script APIs that execute a DoCommand were returning the same result as in TestMode during world generation [FS#5561] (r25305) - Fix: Build railway fences next to objects, even if they are owned by the same company [FS#5565] (r25302) - Fix: gcc4.6 removed -mno-cygwin option (r25266) 1.3.1 (2013-06-01) ------------------------------------------------------------------------ - Fix: When overbuilding a reserved track with a non-track station tile, that tile would remain reserved and eventually trigger a crash upon removal [FS#5540] (r25251) 1.3.1-RC1 (2013-05-17) ------------------------------------------------------------------------ - Feature: Translations of baseset descriptions via language files (r25209, r25205) - Feature: Faroese and Scottish Gaelic translations (r25198, r25176) - Feature: Plural form to be used by Scottish Gaelic (1,11; 2,12; 3..10, 13..19; other) (r25078) - Change: [strgen] Allow any number of colour codes in translations (r25193, r25192, r25191) - Change: [Win32] MSVC 2010 comes with stdint.h (r25128) - Change: Be slightly more lenient with trying to detect a subversion repository in case someone has a sparse tags checkout. In that case the .svn folder misses from the $ROOT_DIR because it is in the $ROOT_DIR/.. (i.e. tags) folder (r25107) - Fix: 'No station' error was given, even when there was a station that way occupied or not yours [FS#5546] (r25243) - Fix: Crash when AI is executing a command as it is bankrupted (removed from the game) [FS#5547] (r25236) - Fix: Give bridges owned by no one (from bankrupt companies) to the first company which replaces the bridge. Everyone could have removed/rebuild the bridge anyway [FS#5541] (r25231, r25227) - Fix: [NewGRF] Revise when vehicle running sound effects 04, 07 and 08 are played; in depot or tunnel, or when crashed or stopped: No sound. Braking: Effect 08 instead of 07 [FS#5538] (r25226) - Fix: [NewGRF] Play vehicle sound effect also for planes (r25225) - Fix: [NewGRF] cur_speed is only valid for the front engine, so make other engines in the consist use the speed of the front [FS#5534] (r25224) - Fix: [NewGRF] Make tick_counters work the same for vehicles (r25223, r25222) - Fix: [NewGRF] IsCompatibleTrainStationTile() is not a symmetric function. Clarify the parameters and fix the cases were they were swapped (r25221) - Fix: Consider map border as water with respect to river/canal continuation (r25220) - Fix: [Script] Clarify on which tiles IsDesertTile and IsSnowTile work, i.e. the ones without infrastructure or buildings, and introduce GetTerrainType for the cases where IsDesertTile/IsSnowTile do not work [FS#5537] (r25213) - Fix: The level crossing sound is an ambient sound and not a new year sound (r25200) - Fix: Original train and road vehicle acceleration did no longer respect bridge speed limits [FS#5523] (r25167) - Fix: [Win32] Do not statically link to SHGetFolderPath as it may not exist, and improve its emulation [FS#5522] (r25155, r25153) - Fix: [Win32] Do not store invalid paths in the search path list (r25154) - Fix: Remove stray reservation from savegames affected by FS#5510 et al. upon loading [FS#5520] (r25152) - Fix: [Script] XXBase::Chance function did not work for large values (>65535) [FS#5517] (r25148) - Fix: Several typos/inconsistencies in English strings [FS#5496] (r25144, r25143) - Fix: When extra dynamite was disabled, towns would be allowed to clear bridges with trams (r25141) - Fix: Towns are build as OWNER_TOWN, so they also need to be removed as OWNER_TOWN otherwise parts might remain [FS#5519] (r25140) - Fix: Editboxes could become too small when resizing windows (r25121) - Fix: Game script language files did not work, when inside a tar [FS#5509] (r25117, r25114) - Fix: [NewGRF] Acceleration of NewGRF aircraft was too fast, while acceleration of default aircraft was way too slow (r25115) - Fix: Pass $LDFLAGS_BUILD to all endian_check compilations (r25108) 1.3.0 (2013-04-01) ------------------------------------------------------------------------ - Fix: Station rebuilding could leave reserved tiles which caused crashes later on [FS#5510, FS#5516] (r25132) - Fix: When the count for a scrollbar was 0, the inter distance was subtracted too much causing a scrollbar with a negative size (r25123) 1.3.0-RC3 (2013-03-18) ------------------------------------------------------------------------ - Fix: Limit aircraft property 0D to 19, since the conversion result to km-ish/h needs to fit into a byte [FS#5492] (r25099) - Fix: Clicking the statusbar crashed, when news were pending but no news were shown yet [FS#5486] (r25093) - Fix: Make editbox character filters also apply to pasted content from clipboard (r25090, r25089) - Fix: Catch exception anonymously, if the exception content is not of interest [FS#5500] (r25081) 1.3.0-RC2 (2013-03-05) ------------------------------------------------------------------------ - Fix: Make sizes of the station preview list and direction selection identical in the station build window [FS#5472] (r25064) - Fix: When allocation of the sprite cache fails, try to allocate less memory and display an error message later on (r25061) - Fix: Refactor Script Debug GUI to only set widget states in OnInvalidateData [FS#5490] (r25052) - Fix: Do not let gcc include files from the 'standard C' include directories to avoid inclusion of header files at the top of the preprocessed nfo files, which cause NFOrenum/GRFcodec to make invalid assumptions about the NFO version (r25050) - Fix: Minimise gaps feature caused removal to only happen at the signal build interval instead of the implicit interval of 1 [FS#5479] (r25038) - Fix: Green path signals would be shown when building them 'under' a train, and they would keep showing green until they were passed again [FS#5480] (r25037) 1.3.0-RC1 (2013-02-19) ------------------------------------------------------------------------ - Feature: Searching of (missing) content via GrfCrawler (r25024, r25023) - Change: Cleanup goals and cargo monitors of companies when they go bankrupt or are taken over (r24986) - Change: Apply the same name sorting rules to content and NewGRF list as for the server list (r24983) - Fix: [SDL] Crash after bootstrap download of 32bits base set due to referencing a deleted mutex [FS#5466] (r25017) - Fix: [SDL] Improve 8bpp hardware palette support. Instead of always requesting SDL_HWPALETTE, it is now only done for 8bpp blitters in fullscreen mode (r25003, r25002, r24993) - Fix: Set vehicle's service interval is percent flag appropriately on creation [FS#5137] (r24998) - Fix: When choosing a train in a depot to attach a newly purchased wagon to, do not consider trains currently moving in and out of the depot (r24987) - Fix: [Script] Crash when passing too many parameters [FS#5465] (r24982, r24981, r24980) 1.3.0-beta2 (2013-02-07) ------------------------------------------------------------------------ - Feature: [NewGRF] Station randomisation triggers (r24906, r24905) - Feature: Settings type filter included in the advanced settings GUI (r24862, r24863) - Change: Revert to opening the vehicle GUI again when cloning vehicles using the clone-button from the depot GUI [FS#4458] (r24955) - Fix: Additional zoom in levels could glitch by a few pixels due to incorrect rounding [FS#5463] (r24975) - Fix: Honour pause_on_newgame setting when running as a dedicated server [FS#5279] (r24974) - Fix: [NewGRF] Prevent access to tile-based variables when tile is invalid [FS#5462] (r24973) - Fix: Do not make overbuilding rivers with canals insanely expensive [FS#5258] (r24972) - Fix: Crash when an infinite loop occurred during loading of a script [FS#5346] (r24970) - Fix: company window was not updated when shares were enabled/disabled [FS#5379] (r24968) - Fix: Trams would get stuck on water [FS#5228] (r24966) - Fix: With YAPF the docking behaviour differed per direction; now favour docking in the direction you approached [FS#5416] (r24964) - Fix: Do not stop loading if there are reservations left [FS#5435] (r24963) - Fix: Reserve all capacity while unloading to avoid 'stealing' cargo, i.e. loading cargo onto a second vehicle when the first cannot be fully filled yet [FS#5438] (r24962) - Fix: If a platform is enlarged and there is a reservation, reserve the whole platform [FS#5362] (r24961) - Fix: Inconsistencies in the 'thanks to' lists [FS#5423] (r24960) - Fix: Set 'replace when old' flag when replacing an autoreplace (r24950) - Fix: Deleting implicit orders was not able to deal with the various side-effects of DeleteOrder [FS#5452] (r24944) - Fix: Redraw autoreplace window properly in network games (r24939) - Fix: Never put a space between cargo name and subtype [FS#5447] (r24938) - Fix: Do not allow order refit to be set for no-load orders [FS#5446] (r24936) - Fix: Make group names unique per company and vehicle type [FS#3473] (r24933) - Fix: Prevent more NewGRFs being selected than is possible to load [FS#5158] (r24932) - Fix: [GS] Do not try to pause or unpause crashed scripts [FS#5415] (r24929) - Fix: [Squirrel] Update line information before processing 'while' token of 'do'-'while' statement [FS#5408] (r24928) - Fix: Add a tooltip to the mapsize selection mentioning possible deviations [FS#5395] (r24925) - Fix: When an object built on a river is removed, restore the river [FS#5441] (r24923) - Fix: Upgrading bridges could steal road types [FS#5389] (r24912) - Fix: [GS] Allow GSs to pass negative integer string parameters (r24908) - Fix: 'Train loads/unloads cargo' station animation triggers on individual platform (r24904) - Fix: Cached station animation triggers were only set when removing parts of a station (r24903) - Fix: The station build window did not update when the station spread changed [FS#5434] (r24899) - Fix: Do not unpause the game when closing the highscore window if it was already paused before the highscore screen was shown (r24898) - Fix: Improvements and fixes for the base translation [FS#5411, FS#5420, FS#5421, FS#5422, FS#5427] (r24896, r24875, r24872, r24869) - Fix: Allow downgrade of road bridges in the scenario editor [FS#5436] (r24895) - Fix: Invalidate station selection window when station spread changes [FS#5434] (r24894) - Fix: Distribute GS compat_.nut with OpenTTD (r24890) - Fix: Pass proper UTF-16 strings instead of UCS-2 to ICU in order to preserve characters outside the BMP (r24885) - Fix: A completely emptied vehicle could trigger an assert (r24883) - Fix: Desync when NewGRF changes the stats related to acceleration (power, weight, tractive effort, etc) during service or 32 day triggers (r24882) - Fix: Incorrect Romanian own name (r24874) - Fix: Make invalid sprite references to mapgen sprites behave the same as invalid references between recolour and real sprites [FS#5404] (r24858) - Fix: Do not let UFOs and coal mines clear water (r24857) - Fix: Do not let UFOs and coal mines destroy depots [FS#5406] (r24856) - Fix: Do not send aircraft to depots that are out of range of the next destination [FS#5405] (r24855) - Fix: Only consider vehicles available in the climate for purchase/depot cell size (r24854) - Fix: Extend widget data member to 32 bits so that sprite IDs >= 2^16 can be used (r24853) 1.3.0-beta1 (2012-12-24) ------------------------------------------------------------------------ - Feature: Advanced settings to disable certain sound effects (r24846) - Feature: [NewGRF] Support oversized purchase list sprites [FS#5271] (r24839) - Feature: Improve pylon placement around station tiles that display neither pylons nor catenary (r24836) - Feature: When using a non-release version of OpenTTD and the basegraphics are missing some sprites, also suggest to use a non-release version of the basegraphics (r24821) - Feature: Consider engine preview windows always sticky, so non-shift mass-closure does not affect them [FS#2632] (r24809) - Feature: When share-cloning vehicles do not open the vehicle window of the new vehicle [FS#4458] (r24808) - Feature: Enable usage of 'companies' console command also in singleplayer [FS#2820] (r24807) - Feature: Ask for confirmation before creating giant screenshots [FS#3148] (r24806) - Feature: Separate subdirectory for screenshots (r24804) - Feature: Unify the difficulty settings window with the advanced settings window (r24791, r24792) - Feature: Various methods to open the OSK (r24785) - Feature: Add a string filter to the server list [FS#3852] (r24769) - Feature: Add industry type and cargo dropdown selection for easier navigating in the industry chain window (r24763) - Feature: Introduce GUI icons for deleting to the left/right (r24749) - Feature: Add clear button to all editboxes (r24748) - Feature: Reset the vehicle engine pool when starting a scenario (r24716) - Feature: Add basic/advanced/expert filters to the advanced settings GUI [FS#5355] (r24671) - Feature: Draw cargo labels in the station list black or white depending on the background colour [FS#5311] (r24668) - Feature: Do not display the preview window for disabled vehicle types (r24660) - Feature: Add new filter option to the advanced settings window to show only changed settings (r24647) - Feature: Add text filtering to advanced settings (r24632) - Feature: Add buttons to expand/collapse all to advanced settings GUI (r24631) - Feature: [GS] Allow GameScripts to construct and prospect industries without having a sponsor (r24623) - Feature: Pay interest also on a negative cash value (r24618) - Feature: Sort cargo filter by cargo name/label at the company stations window [FS#5311] (r24615) - Feature: More options for the auto-scroll setting (r24590) - Feature: Allow AI/GS script developers to break the execution of their scripts and pause the game using ScriptController::Break() (r24542, r24575) - Feature: Scripts can be suspended even if the game is still progressing, thus break-on-log now works also for Game Scripts (r24537) - Feature: Highlight industries on the smallmap when the mouse is over an entry in the legend (r24534) - Feature: [NewGRF] Allow resolving var 5F via vehicle var 61 (r24527) - Feature: [OSX] Additional high-resolution icons for the app bundle [FS#4539] (r24525) - Feature: Ctrl+Backspace/Delete to remove characters up to next word beginning in text edit boxes [FS#5203] (r24521) - Feature: Ctrl+Arrow keys to move entire words in text edit boxes [FS#5203] (r24520) - Feature: When using autorefit only load/refit vehicles if other wagons cannot already take all cargo without refitting [FS#5106] (r24497) - Feature: [GS] Useful behaviour for GSEngine::IsValidEngine and GSEngine::IsBuildable when outside GSCompanyMode scope (r24492) - Feature: Display GS dead state in AI debug window [FS#5230] (r24489) - Feature: Add buttons to view textfiles from the online content window [FS#5236] (r24488) - Feature: Make the pathfinder decide whether ships shall leave depots towards north or south [FS#5127] (r24481) - Feature: [GS] API compatibility scripts for Goal Scripts [FS#5219] (r24468) - Feature: Display in the advanced settings description a setting type which explains the scope of changes to a particular setting [FS#5244] (r24411) - Feature: [GS] Allow game scripts to monitor cargo pickups and deliveries done by companies (r24406) - Feature: [NewGRF] Allow vehicle variable 61 for callback 2D (recolour) and re-randomisation (r24371) - Feature: [NewGRF] Customisable signals for rail types (r24367) - Feature: Allow filtering for multiple words (separated by whitespace resp. quoted) in script breakpoints, the sign list, content and NewGRF-GUIs (r24337, r24342) - Feature: Add dropdowns to NewGRF configurations, if all values have labels (r24318) - Feature: Add dropdowns to AI configurations, if all values have labels (r24317) - Feature: Allow to select advanced settings with limited range with a dropdown list (r24316) - Feature: Display default values for advanced settings in the settings description (r24298) - Feature: News item for exclusive transport rights [FS#2688] (r24287) - Feature: [GS] Additional GSNews::NewsItem::NewsTypes (r24286) - Feature: [NewGRF] Variable with the current max speed for vehicles [FS#5052] (r24246) - Feature: Descriptions explaining the meaning of advanced settings (r24237) - Feature: Split the renew-months setting text in two string values (one before life time and one after) (r24210) - Feature: Show a hint in the supplies tab of station windows, if the station is affected by exclusive transport rights [FS#5178] (r24205) - Feature: [NewGRF] Callback to set industry production level on construction (r24186) - Feature: South Korean and South African currencies [FS#4907] (r24148) - Feature: Randomise count of passengers killed in a crash [FS#3576] (r24142) - Feature: Display rating in the town directory window (r24141) - Feature: Show group name in the replace vehicle window caption [FS#1117] (r24140) - Feature: Allow to create a new vehicle group by drag and drop (r24139) - Feature: Ctrl+Drag to add all vehicles with a shared order list to a group (r24138) - Feature: Draw indicator icon in the replace vehicle window for vehicles which have a replacement set (r24137) - Feature: Autoreplace vehicles only when they get old [FS#4465] (r24136) - Feature: Add configurable limits for tree planting, and remove tree drag size limit (r24134, r24135) - Feature: Lithuanian currency [FS#4984] (r24133) - Feature: Ctrl+Clicking to change colour of all colour schemes at once [FS#1952] (r24131) - Feature: Deselect 'remove' button when changing signal types in the GUI [FS#2314] (r24130) - Feature: Option to minimise signal distance when dragging over obstacles [FS#3660] (r24129) - Feature: Allow closing airports for incoming aircraft [FS#1497] (r24127) - Feature: Drag and drop support for the NewGRF list window [FS#3854] (r24126) - Feature: Drag destination highlighting to the group GUI [FS#3705] (r24125) - Feature: [NewGRF] Misc engine flag to disable breakdown smoke [FS#4658] (r24124) - Feature: Be more careful with the population of a small town while placing a statue (r24105) - Feature: Debug option for showing the redrawn dirty blocks/rectangles [FS#5101] (r24065) - Change: News display options are now shown in the advanced settings window (r24842, r24843, r24844, r24845) - Change: Drop 'signal density' from the advanced settings GUI. It is more suited to be only changed via the signal GUI (r24670) - Change: Check for bankruptcy on a monthly basis (r24619) - Change: Only bankrupt, if you have negative money considering you took max loan (r24617) - Change: When building long roads or tramways, only build the roadbits at the beginning and the end if they can connect to something [FS#5228] (r24503) - Change: Disallow original and better road layouts to build roads under bridges along the bridge direction [FS#5229] (r24391) - Change: Allow cloning of orders which are unreachable for the destination vehicle if they were already unreachable for the source vehicle [FS#5213] (r24390) - Change: Allow building/modifying/removing signals even if a train is on the belonging track (r24356) - Change: [NewGRF] Make bounding boxes of road vehicles change according to the vehicle length to make alignment easier [FS#5204] (r24331) - Fix: [NewGRF] Consider regearing-like cargoes as no-cargo in cargo filters [FS#5386] (r24848) - Fix: [NewGRF] Draw NewGRF railtypes in NewGRF station previews (r24840) - Fix: Do not consider blocked rail station tiles that display wires as non-reachable for masking out unnecessary catenary wires (r24837) - Fix: The autorefit dropdown in the order GUI was not always updated when modifying vehicle consists [FS#5396] (r24834) - Fix: [NewGRF] Incorrect values are better than a crash when a NewGRF queries vehicle variable 4C before vehicle initialisation is completed [FS#5398] (r24831) - Fix: determineversion.vbs could hang in a git checkout (r24826) - Fix: Close pending preview windows when the engine is introduced to everyone (r24812) - Fix: Close engine preview window when another client accepts it (r24811) - Fix: Make engine preview offers more robust with regard to changes in the company ranking (r24810) - Fix: When displaying the previous news message, do not consider news which are turned off [FS#4224] (r24802) - Fix: Glitch in timetable GUI [FS#5327] (r24800) - Fix: Unify checks for editability of settings (r24787) - Fix: Invert the focus handling of the OSK. Keep the focus at the OSK and close it on losing focus (r24774) - Fix: Shift in the OSK behaved like capslock (r24773) - Fix: [Win32] Do not crash when switching to an unsupported fullscreen display mode (like 8bpp modes in Windows 8) [FS#5359] (r24762) - Fix: Crash on corrupted savegame [FS#5367] (r24754) - Fix: Some editboxes had a different colour than the rest of the window (r24747) - Fix: In various windows the OSK looked shiny but using it had no effect whatsoever (r24727) - Fix: AI debug GUI crashed when using disabled buttons via hotkeys (r24723) - Fix: When starting a scenario apply the local company settings to the new company [FS#5139] (r24717) - Fix: [NewGRF] Allow stations to draw snow/desert aware ground sprites with railtype overlays [FS#5335] (r24715) - Fix: [NewGRF] Draw default foundations if resolving of custom station foundation sprites fails [FS#5337] (r24714) - Fix: [NewGRF] Tolerate old NewGRFs returning invalid values via CB 11 [FS#5262] (r24713) - Fix: [NewGRF] Station variables 61 and 62 returned incorrect values, if no vehicle ever tried loading [FS#5303] (r24712) - Fix: Check whether to not display a ^ loading indicator at drop stations only worked if there was no other vehicle unloading for 255 ticks (r24711) - Fix: [NewGRF] Station var 48 should report acceptance, not supply (r24706) - Fix: Station rating might consider very old vehicles very young (r24705) - Fix: Disallow closing oilrig airports in the scenario editor (r24703) - Fix: Workaround for an overoptimisation done by GCC 4.5 [FS#5246] (r24701) - Fix: Get packing right on MinGW GCC 4.7 (r24573) - Fix: Make sure all template functions are instantiated by at least one compilation unit [FS#5276] (r24496) - Fix: Do not load order backups when loading a server-saved game in single player (r24445) - Fix: Allow overbuilding bridges with the same type when adding a roadtype [FS#5221] (r24413) - Fix: Cargo lists cannot have genders (mostly because it is very unclear what gender it would have) (r24374) - Fix: Off by one errors with regard to clicking on setting buttons (r24313) - Fix: STRING1 probably means STRING1 (r24295) - Fix: squirrel_export should match key words like 'virtual', 'static' and 'const' only as whole words (r24288) - Fix: Hide object specs/classes from the GUI, if they will never be available to the user [FS#4967, FS#5120] (r24171) - Fix: Unify the spacing in 'AI/Game Script' and never just say 'Game' when 'Game Script' is meant [FS#4898] (r24020) 1.2.3 (2012-11-01) ------------------------------------------------------------------------ (None) 1.2.3-RC1 (2012-10-17) ------------------------------------------------------------------------ - Change: [NewGRF] Set the reference brightness of 32bpp mask recolouring to 128 (r24610) - Fix: Configure script did not properly handle _BUILD flags during reconfigure (r24601) - Fix: Configure script failed to detect libfontconfig 2.10 as newer than 2.3 (r24598) - Fix: When fontconfig is not available, the bootstrap download crashed [FS#5336] (r24597) - Fix: Crash when a gamescript provided too many parameters to a GSText object [FS#5333] (r24593) - Fix: [Script] API documentation mistakes/omissions (r24584) - Fix: Do not add duplicates to the ban list [FS#5308] (r24580) - Fix: Draw the window resize sprite bottom-aligned [FS#5324] (r24577) - Fix: Vehicle list at buoys did no longer work [FS#5319] (r24576) - Fix: [Windows] Do not cast away const in OS specific code (r24572, r24571) - Fix: Naming of bundles was somewhat broken (r24569) - Fix: Non-train vehicle lists were not resorted when vehicles were renamed [FS#5261] (r24567) - Fix: Stop both price and payment inflation if either of them has reached MAX_INFLATION (r24565) - Fix: Limiting the inflation did not quite work [FS#5312] (r24564) - Fix: Do not show profit from refits as cost in the refit window [FS#5297] (r24544) - Fix: Do not limit to reading one UDP packet per game loop (r24532) - Fix: Max script chance was too big (r24531) - Fix: [NewGRF] RandomAction 84 should interpret register 100 as signed (r24528) - Fix: [OSX] Some compile problems in mac-only code [FS#5296] (r24524) - Fix: The gender of an industry name is defined by the industry-type part of the name, not by the town-name part, even if it comes first (r24523, r24522) - Fix: GStexts were compiled incompletely when containing certain string codes (r24516, r24515) - Fix: The mousewheel did not work in the build waypoint window [FS#5285] (r24507) - Fix: [NewGRF] Airport variables 60 to 65 and 69 used the wrong cargo translation table for translations (r24506) - Fix: Do not show the global goals as company goals for spectators (r24500) - Fix: Clarify description of command line option -n (r24485) - Fix: Do not call RebuildSubsidisedSourceAndDestinationCache() before subsidy savegame conversion is finished [FS#5232] (r24482) - Fix: Trains were unable to reverse in stations when using NPF (r24479) - Fix: The --xxx yyy format (instead of --xxx=yyy) for configure did not work (r24471) - Fix: --prefix was not accepted by configure (r24470) - Fix: Changing auto-refit for a 'goto station' order was inadvertently modifying the full load state [FS#5264] (r24457) 1.2.2 (2012-08-16) ------------------------------------------------------------------------ (None) 1.2.2-RC1 (2012-08-01) ------------------------------------------------------------------------ - Fix: In some cases ships could be covered with land [CVE-2012-3436] [FS#5254] (r24449, r24439) - Fix: Copy constructor and assignment operator cannot be implicit template specialisations [FS#5255] (r24448) - Fix: Make (non-refittable) vehicles with invalid default cargo unavailable [FS#5256] (r24438) - Fix: CFLAGS/CXXFLAGS ignored for helper binaries (r24432, r24429, r24427, r24365) - Fix: [Windows] Unbreak NewGRF MD5 sum calculation. Macros and side effects do not mix, especially if there is some obscure '#define min' in a windows header that nobody thinks of [FS#5231] (r24416) - Fix: Disallow removing roadtypes from bridges when not dragging in bridge direction [FS#5221] (r24414) - Fix: Draw wires under low bridges if the bridge is transparent, not if the wire is transparent (r24403) - Fix: Station properties 11 and 14 were combined incorrectly [FS#5243] (r24402) - Fix: [Windows] Changing resolution did not resize the window (r24394) - Fix: Use the 'all vehicles' group for the autoreplace window from the vehicle list [FS#5239] (r24392) - Fix: Do not consider not finding a particular base set critical; just load a different one and display an in-game error later on [FS#5233] (r24388) - Fix: Make IsInDepot() functions behave consistent across vehicle types and add IsChainInDepot instead, if that is what shall be checked [FS#5188] (r24384) - Fix: Call Vehicle::IsStoppedInDepot only for the first vehicle in a chain (i.e. primary vehicle or free wagon) (r24382) - Fix: Do not resize the object GUI when selecting objects. Rather clip the object name (r24379) - Fix: ReInit could crash for windows with NWidgetMatrix widgets [FS#5218] (r24378) - Fix: [NewGRF] Extended action A1 did not work correctly [FS#5227] (r24369, r24361) - Fix: [NewGRF] Ship-specific 80+x variables were missing for unknown reason [FS#5224] (r24360) - Fix: When airport construction was denied due to noise, the error message named the wrong town (r24354) - Fix: [NoAI] A TileIndex is not a station id, so do not use it as one [FS#5215] (r24353) - Fix: When highlighting the drop position for vehicles in depots, make space for all articulated parts (r24352) - Fix: Short vehicles were not properly positioned at the cursor when dragging for RTL languages (r24351) - Fix: EQUALSIZE widget containers within EQUALSIZE containers were initialised with wrong sizes (r24346) - Fix: The cursor in the company password window was not blinking due to wrong magic constants (r24335) - Fix: [NewGRF] Change the length of 8/8 road vehicles in vehicle lists to 32 pixels; this is in fact the correct length as can be seen in corners for short articulated parts following each other [FS#2553] (r24332) - Fix: [NewGRF] Group vehicles in the purchase list properly by source GRF, but also consider engine GRFID overrides [FS#4254] (r24330, r24321) - Fix: Make the AI settings window behave more like the other settings window by closing the query window whenever selecting a different row (r24315) - Fix: Editing NewGRF parameters using the query window showed wrong values, if there was no direct relation between parameter index and parameter register (r24314) - Fix: Centre object previews in 1- and 2-view selectors based on the 4-view selector layout [FS#5057] (r24299) - Fix: Increase the left and right margins of the text in the yes/no query window (r24293) - Fix: [NewGRF] GetReverseCargoTranslation() was unnecessary complicated and also returned the wrong thing for cargoes not present in the translation table (r24273) - Fix: [NewGRF] Load cargo- and railtype-translation during both reservation and activation stage. That way they can be selected using Action7 depending on present cargo- or railtypes (r24272) - Fix: Use the same colour scheme for the script selection window as in other comparable windows (r24268) - Fix: Make the oilrig-vehicle list accessible to spectators and colour its caption neutrally grey [FS#5126] (r24260) 1.2.1 (2012-06-01) ------------------------------------------------------------------------ - Fix: [Script] ScriptTown::GetGrowthRate() returned wrong values after usage of SetGrowthRate() (r24302) 1.2.1-RC1 (2012-05-16) ------------------------------------------------------------------------ - Fix: Change the unit of the sprite-cache size setting from megabytes to megapixels, so it depends on the blitter being used. Also increase it from 64 to 128, and change the name in the cfg file, so everyone gets the new default [FS#5162] (r24252) - Fix: Do not immediately display error messages from parsing the cfg file, but schedule them for displaying after the GUI is prepared for it [FS#5154] (r24250, r24249, r24248, r24247) - Fix: Dereferencing uninitialised pointer causing a crash [FS#5159] (r24224) - Fix: Lag counters were not properly reset when switching states making it possible to get disconnected for lagging when you were not lagging [FS#5166] (r24221) - Fix: Adopt ICU version detection to also deal with the new versioning scheme since ICU 49 [FS#5182] (r24220) - Fix: Immediately do the cargo payment on vehicle crashes instead of when they are cleared [FS#5152] (r24219) - Fix: The confirmation window to abort world generation was hidden during world generation, so actually you could not abort it [FS#5159] (r24214) - Fix: If a company is taken over or bankrupts, transfer exclusive transport rights to the new owner respectively cancel them (r24204) - Fix: Make the engine name not overdraw the engine count in the autoreplace GUI (r24203) - Fix: Make the size of the details in the autoreplace GUI match more the size of the details in the purchase list (r24202) - Fix: Mark group list dirty when setting/clearing autoreplace for an engine type [FS#5170] (r24201) - Fix: Invalidate build vehicle windows every month, in case they need resorting due to changed reliabilities [FS#5149] (r24200) - Fix: If you consider a settings to potentially cause desyncs via NewGRFs and thus disallow changing it in network games, you should probably also sync it to clients (r24193, r24191) - Fix: Use default value when reading an invalid setting value [FS#5153] (r24192, r24146) - Fix: [Windows] When going to fullscreen and back, restore to the resolution you were, not to the fullscreen resolution (r24189) - Fix: [Windows] When changing the basics of a window (fullscreen, 8bpp/32bpp), and a window already exists, it was forced out of maximise mode, and its resolution/position was reset, often causing unwanted side-effects [FS#5151] (r24188) - Fix: Town radii were not updated immediately after construction/destruction of houses, resulting in desyncs [FS#5169] (r24183) - Fix: The population of a town was computed incorrectly for overridden houses when loading a game (r24182, r24181, r24179) - Fix: The object name from property A was not displayed in the object GUI [FS#5110] (r24178) - Fix: The arctic 'shops and offices' used the 'church' sprite in one of its four views [FS#5148] (r24177) - Fix: The object GUI did not draw objects when all objects of a class are disabled (r24176) - Fix: If you spent hard work on finding an available object ID, you should probably also use it instead of always 0 (r24159) - Fix: Town producing no cargo at all could spawn passenger subsidies (r24158) - Fix: The music volume was set too early during startup causing it to be not set correctly (r24155) - Fix: [Squirrel] Crash when trying to create an array with negative size [FS#5160] (r24153) - Fix: [NoAI] Do not return the last 'cached' speed of vehicles when they are stopped/crashed [FS#5157] (r24152) - Fix: [Script] Typo in script documentation (r24151) - Fix: Glass-sprite of bubble-generator was not drawn anymore for completely constructed tiles [FS#5143] (r24107) - Fix: Conflicting strategies for resizing the main toolbar and statusbar after resizing the main window [FS#5136] (r24089) - Fix: Significantly reduce the area that is redrawn for text effects [FS#5103] (r24068) - Fix: Do not redraw up to 25% of the map when making a new vehicle visible for the first time (r24067) - Fix: Do not redraw the text effect when nothing changed (r24066) 1.2.0 (2012-04-15) ------------------------------------------------------------------------ - Fix: When starting GS or AI, always use the settings of the game, not the new-game settings [FS#5142] (r24108) - Fix: Provide translated comments in the desktop file without language name postfix (r24100) - Fix: Cloning orders of aircraft with limited range failed [FS#5131] (r24086) 1.2.0-RC4 (2012-04-01) ------------------------------------------------------------------------ - Fix: Reversing trains while they were entering or leaving a depot could lead to stuck trains [FS#5093] (r24078, r24071) - Fix: The 'last joined' server was not properly selected anymore [FS#5098] (r24070) - Fix: Immediately start querying the last joined server instead of waiting for the requery loop [FS#5097] (r24069, r24062) - Fix: Make the full snowiness level of houses the same as roads and rails [FS#5121] (r24064) - Fix: With certain versions of GCC and compiler flags the compiler could reorder some code badly causing the 32bpp depot flag not working [FS#5125] (r24063) - Fix: Do not freeze aircraft mid-flight when skipping to an out-of-range destination [FS#5123] (r24060) - Fix: Wrong numbering of string parameters causing wrong capacities to be shown [FS#5124] (r24058) - Fix: Crash when timetabling a maximum travel speed of 0 [FS#5111] (r24053) - Fix: [NewGRF] Imported GRF sounds were inserted into the wrong slots [FS#5107] (r24052) - Fix: [NewGRF] Realsprites inside the action 11 block were not skipped correctly (r24050) - Fix: Improve error messages for the placement restrictions of banks, water towers and toy shops [FS#5095] (r24040) 1.2.0-RC3 (2012-03-18) ------------------------------------------------------------------------ - Feature: Allow display of baseset textfiles (r24037) - Feature: Increase the station class limit from 32 to 256 (r24031) - Fix: After opening a text window with the monospaced font, all other text started glitching (r24038) - Fix: [NoAI] Reset 'is random' status of temporary variable during saveload as it is not always written to when loading an AI which means it would be taking the 'is random' setting of another AI (r24033) - Fix: [NoAI] Make AIEngine::IsArticulated return true if the articulated callback flag is set, do not try to run the callback (r24029) - Fix: Pass cases down into the list of cargoes [FS#5090] (r24024, r24023, r24022) 1.2.0-RC2 (2012-03-04) ------------------------------------------------------------------------ - Fix: [Script] AI used in names in API for GSOrder [FS#5088] (r24006) - Fix: Improve rounding when converting display speeds to internal speeds [FS#5079] (r23995) - Fix: Also reset the font glyph cache when switching blitters (r23992, r23987) - Fix: [NewGRF] Also display the cargo subtype for vehicles which have no capacity, but a subtype [FS#5076] (r23991) - Fix: Zero the offsets of disabled zoomlevels, so they do not influence offset calculations (r23989) - Fix: Invalid reads when scaling an odd-sized sprite smaller (r23986) - Fix: Inconsistent quit/abandon/exit game/scenario/editor strings [FS#5074] (r23985) - Fix: Fix the order of lights on the helipad [FS#5082] (r23984) - Fix: Tarred heightmaps would not be found [FS#5083] (r23983) - Fix: Do not load a game during UpdateWindows as that might trigger changing the blitter which triggers re-entrant locking (r23980, r23977) - Fix: [SDL] Palette update was done too late making switching from 8bpp -> 32bpp look ugly (r23978) - Fix: Sprites of different zoom levels were not always padded correctly to a common size (r23976) - Fix: Also save the maximum travel speed for the current vehicle order (r23973) 1.2.0-RC1 (2012-02-19) ------------------------------------------------------------------------ - Feature: [NewGRF] Customisable tunnel portals for rail types (r23952) - Feature: Timetabled maximum travel speeds for non-flying vehicles (r23947) - Feature: Readme/licence/changelog viewer for AI and game scripts [FS#5047] (r23936) - Feature: [NewGRF] 32bpp sprites in GRFs (r23897) - Feature: [NewGRF] Support for RealSprites with multiple zoom levels (r23890) - Feature: [NewGRF] Support for container version 2 (r23887) - Fix: Refittability should never depend on the current capacity of a vehicle [FS#5070] (r23965) - Fix: Do not look for missing sprites twice during startup [FS#5072] (r23963) - Fix: [Script] Infinite recursion within a script was not caught properly, so they could cause crashes of OpenTTD instead of the AI [FS#5068] (r23962) - Fix: [NewGRF] Make the properties for always/never refittable cargo types not behave incremental, but reset them on reassignment (r23960) - Fix: [Network] Do not allow chat messages from pre-active clients. As they have not got the savegame yet, they will not have the interface to send them either (r23958) - Fix: [Network] Allow sending chat to pre-active clients as the clients start accepting once they send 'map ok' to the server, which is the same moment we change their status to pre-active [FS#4990] (r23957) - Fix: When the population of a town changes the town view might even have to change size due to different cargo requirements [FS#5062] (r23953) - Fix: [NoGo] Never show GSGoal::Question() to spectators [FS#5063] (r23950) - Fix: Better rounding when converting internal speed to displayed speed (r23945) - Fix: Also list DEITY signs in the signlist in the scenario editor [FS#5061] (r23943) - Fix: Infrastructure cache of standard road stops would get messed up when buying a company with them (r23942) - Fix: Scale infrastructure cost of rail tracks by the total number of all tracks and not independently for each rail type (r23931) - Fix: [Script] Do not close the parameter window when a script starts [FS#4944] (r23930) - Fix: Do not accelerate, for smoke purposes, when you reached the track's maximum speed [FS#5053] - Fix: 32bpp animated blitter was optimised a bit too far regarding not needing to update the colour mapping when (re)initialising the palette [FS#5056] (r23927) - Fix: [NoGo] Some news messages would cause an assertion to be triggered due to a missing proper location for the viewport of the news message, so only allow building when valid data for the viewport is provided or no viewport is used [FS#5054] (r23924) - Fix: Consider only the middle tile of a lock for lock-infrastructure costs. The other two tiles may be owned by other companies. Also do not count the middle tile of a lock as canal, independent of whether it is build on ground or river slope (r23920) - Fix: [NewGRF] When determining the first refittable cargotype according to CTT order, do not rely on the GRF assigning the refit_mask property. Also check for GRFs setting the default_cargo or refittable-cargo-classes or -types properties (r23916) - Fix: [NewGRF] Do not test validity of cargobits using a mask of cargoslots (r23914) - Fix: [NewGRF] When testing whether a engine shall only carry the default cargo, check ctt_include_mask for being empty before applying cargo translation (r23912) - Fix: [SDL] Handle the SDL_VIDEOEXPOSE event to solve issues with SDL 1.3 (r23910) - Fix: [SDL] Fix keyboard-related segfault when compiling against SDL 1.3 (r23909) - Fix: [Makefile] Make sure bin/baseset/openttd.32.bmp is removed on make clean (r23908) - Fix: [Makefile] Let 'make clean --dry-run' not delete Makefiles (r23907) - Fix: [Windows installer] OpenMSX got downloaded to and extracted in the wrong (non-existent) folder [FS#5045] (r23905) - Fix: Memory leak every time one clicked a savegame in the load GUI (r23901) - Fix: [NewGRF] It was not possible to import sounds from a NewGRF later in the load order (r23883) - Remove: PNG sprite loader; use 32bpp sprites in a NewGRF (r23898) 1.2.0-beta4 (2012-02-04) ------------------------------------------------------------------------ - Feature: [NewGRF] Give NewGRF defined level crossings and rail depots access to the townzone (r23866) - Feature: [NewGRF] New algorithm (activated via an engine flag) to determine the capacity of vehicles. This allows vehicles to better control the capacity for cargotypes which they know; and let cargo NewGRFs influence the capacity for cargoes the vehicle NewGRF does not know, but which the vehicle is refittable to due to cargo classes (r23861) - Feature: [NewGRF] Add cargo property 1D to set the capacity multipliers when refitting vehicles, which do not use callback 15 (r23860) - Feature: Allow command line options -e and -g to be combined to load saves/scenarios directly into SE (r23839) - Feature: [NoGo] Allow querying orders of vehicles [FS#4994] (r23837) - Change: Do not let towns (ever) remove objects [FS#5001, FS#5002] (r23842) - Change: Make signs placed in scenario editor belong to the GS. That way they are always shown in game and are not editable [FS#4999] (r23835) - Fix: Generate industry subsidies again [FS#5039] (r23876) - Fix: [NoGo/NoAI] Scripts with a bad comparator could lock up OpenTTD [FS#5004] (r23870) - Fix: Make the colour of the dropdown items for opening the vehicle list for which the company has no vehicles looking less horrid [FS#5020] (r23867) - Fix: Railtype overlays were drawn 'only transparent' on invisible bridges (r23864) - Fix: Inserting conditional orders for ships checked the wrong orders wrt. maximum distance (r23859) - Fix: Out of bounds read for slowdown parameter caused desync when railtype >= 4, vehicles were fast, and the original acceleration model was used [FS#5007] (r23855) - Fix: Infrastructure cache could get out of sync when overbuilding a drive through road stop (r23851) - Fix: When the network is lagging, you try to copy a vehicle's order but accidentally create a station order and then copy the vehicle's order (before the first command is executed) one could trigger an assertion from the pool [FS#5008] (r23849) - Fix: When removing road or tram from a tram+road stop, the owner of the road stop's cache was updated instead of the owner of the removed infrastructure (r23847) - Fix: Infrastructure count for stations was not updated properly on company takeover. And do not count buoys while loading a game either (r23844) - Fix: Clear NewGRF vehicle cache when their owner changes (r23841) - Fix: Assertion got hit when destroying a dock when a ship was loading [FS#5000] (r23838) - Fix: If a vehicle is not refittable to any cargo in the CTT, then pick the first refittable cargoslot (r23836) 1.2.0-beta3 (2012-01-21) ------------------------------------------------------------------------ - Feature: [NoGo] Allow to chose the goal question window's title from a (small) set of options [FS#4992] (r23827) - Feature: [NewGRF] Enhance some fatal NewGRF errors with the sprite number that caused the problem (r23809) - Fix: Loading empty GS strings/translations failed [FS#4996] (r23829) - Fix: Return early from SlString() for empty strings, before doing invalid things which surprisingly do not break everything (r23828) - Fix: The detailed performance rating window showed the cargo count of the current quarter instead of the last quarter like the tooltip says [FS#4972] (r23826) - Fix: Removal of towns with 0 population failed during map generation [FS#4951] (r23819) - Fix: [Network] Desync due to different NewGRF version at client and server [FS#4962] (r23817) - Fix: [NewGRF] Textstack was not properly used when storing parameters for the error message window [FS#4969] (r23803) - Fix: Game lobby GUI not updated when new company information becomes available [FS#4968] (r23802) - Fix: Reading the UTF-8 BOM from AI/GS files on big-endian machines failed (r23801) - Fix: Move 'refittable to' text above custom NewGRF text in build vehicle GUI [FS#4958] (r23792) - Fix: [NewGRF] Resize text panel for parameter description if it does not fit in 4 lines [FS#4960] (r23791) - Fix: [NewGRF] While we can only show one error per NewGRF, fatal errors should always disable the GRF. Also give those errors precedence over other information (r23789) - Fix: [NewGRF] Failure to load NewGRF files that use action 0 general prop 15 with a missing language file (r23788) - Fix: Crash due to genders used for station name in hangar string of Italian translation [FS#4965] (r23782) - Fix: Under certain circumstances, e.g. a single invalid order, trying to determine the next order state could end up in an infinite loop [FS#4964] (r23781) - Fix: [Network] Missing naming of some errors[FS#4963] (r23780) - Fix: Trim all control codes and the likes from strings being passed into the AI. If the AI would be displaying them later we would be showing those control codes as question marks [FS#4957] (r23778) - Fix: Hide the PCX screenshot format from the options window, if a 32bpp blitter is used (r23775) - Fix: [NewGRF] Update all cached train properties if a train vehicle enters a new railtype (r23773) 1.2.0-beta2 (2012-01-07) ------------------------------------------------------------------------ - Feature: [NewGRF] Allow read-only display of NewGRF parameters, if GRF list may not be edited (r23760) - Feature: [NewGRF] Alternate rail type label list (r23758) - Feature: Make the default secondary sort method for the server list the number of clients instead of the name (r23710) - Feature: Try harder to sort text instead of fancy characters in the server names (r23709) - Feature: Make a distinction between fully zoomed in and default zoomed in screenshots [FS#4916] (r23695) - Feature: Add ability to adjust brightness of colour after remapping for 32bpp sprites (r23670) - Feature: [GS] GSGoal::Question(), to ask a question to a(ll) company(ies). It can contain random text, and at most 3 buttons from a collection of 17 (r23731) - Feature: Australian translation (r23730) - Fix: Make default timeouts for certain network states lower and configurable [CVE-2012-0049] [FS#4955] (r23764) - Fix: Check whether a water tile is really empty when overbuilding it with an object [FS#4956] (r23763) - Fix: The check for duplicate town names was not really working [FS#4951] (r23759) - Fix: Missing locking causing crash is extreme case when being in the MP lobby [FS#4938] (r23752) - Fix: [Win32] Work around a possible deadlock when initialising threaded drawing (r23749) - Fix: Make vehicle variables A8 and A9 always return 0. Returning cur_image is a potential desyncer due to Action1 in static NewGRFs (r23748) - Fix: Also set 'info' to NULL if 'instance' dies (for both AI and GS); avoids invalid memory reads (r23746) - Fix: If autorefit fails, count the vehicle capacity nevertheless, if it is already carrying the right thing (r23745) - Fix: [NewGRF] Check the version of the right GRF [FS#4923] (r23744) - Fix: [NewGRF] Call CB 15E for all vehicles before actually executing any refit [FS#4906] (r23743) - Fix: Cheating to different climates messes things even more up than changing NewGRFs in-game so it was removed [FS#4939] (r23733) - Fix: When cheating into another company, the SignList was not updated [FS#4942] (r23728) - Fix: Reading memory of a temporary (already deconstructed) object is invalid (r23721) - Fix: [Script] Show the script debug window also when the game script crashes [FS#4935] (r23720) - Fix: Extraction of music packs failed [FS#4930] (r23719) - Fix: [AI] Rescanai caused crash when the AI settings of an AI was opened [FS#4936] (r23718) - Fix: Ships going to wrong dock location when moving the dock while the game is paused [FS#4927] (r23717) - Fix: The amount of goals was too low [FS#4928] (r23699) - Fix: Hardcode the original defaults for loading old savegames if they could totally mess with the game's behaviour [FS#4859] (r23693) - Fix: Infrastructure count of canals/locks/ship depots was not updated properly when a company went into bankruptcy or was taken over [FS#4921] (r23686) - Fix: When fitting another engine the cargo capacity of wagons could become lower, causing them to contain more than they should. This caused the cargo transfer from the replaced parts to put even more stuff in the already full wagon. Prevent this from happening by reducing the amount of cargo in the vehicle to the capacity when moving vehicles/wagons around, or when autoreplacing [FS#4912] (r23683) - Fix: Vehicle numbers got miscounted when autoreplacing failed due to length checks [FS#4914] (r23681) - Fix: [AI] Prevent removal of the (AI) company the local player is in [FS#4915] (r23680) - Fix: [Script] Close the editbox of settings when changing an AI, to avoid invalid memory read/write (r23678) - Fix: [Script] Invalidate AI Parameters window when changing AI [FS#4909] (r23677) - Fix: When removing road stops the wrong tile was checked for updating the infrastructure cache [FS#4913] (r23676) - Fix: [Script] The 'Configure' button in the 'AI / Game Configuration' window did not get enabled when activating a GameScript (r23668) 1.2.0-beta1 (2011-12-24) ------------------------------------------------------------------------ - Feature: Ability to run a game script; a script that controls some of the logic of the game, e.g. to implement goals or tutorials (r23637) - Feature: Allow to place locks also on river rapids and restore rivers, if locks are deleted [FS#4872] (r23512) - Feature: Aircraft ranges (r23504) - Feature: Configurable linewidth in plots (r23497, r22292) - Feature: Add 'view website' button to the online content and NewGRF windows (r23495, r23492) - Feature: [NewGRF] Action14 node INFO->URL_ to add an url (r23494) - Feature: When looking for missing content, automatically select it so you can easily start the download [FS#4827] (r23468) - Feature: Automatically close the online content window after confirming the download with 'ok' [FS#4827] (r23467) - Feature: Add 'find missing content online' button to 'load savegame' and 'find network game' windows [FS#4827] (r23465) - Feature: [NoAI] AIStation.GetStationCoverageRadius(StationID) (r23453) - Feature: Infrastructure maintenance costs (r23415) - Feature: Allow to create subsidies for any combination of source and destination types (r23408) - Feature: Diagonal dragging the rail conversion tool when pressing CTRL [FS#4841] (r23338) - Feature: Add ability to zoom in to 2x and 4x level (r23316) - Feature: Settings to restrict viewport zoom levels (r23314) - Feature: An economy.fund_buildingssetting, to disallow funding buildings (r23303) - Feature: [NoAI] AITown::GetCargoGoal and AITown::GetGrowthRate to query statistics about a town regarding its growing (r23302) - Feature: Show on the GUI when a town grows and what the requirements for growing are (r23300) - Feature: [NewGRF] Properties to always include/exclude cargo types from the refit mask (r23291) - Feature: A monospaced sprite font for the readme reader (r23288, r23274) - Feature: Attempt to show a window for downloading the base graphics set if it is missing (r23244) - Feature: In-game (translatable) readme.txt reader [FS#4780] (r23182, r23178) - Feature: [NoAI] AICONFIG_AI_DEVELOPER flags to hide AI settings unless gui.ai_developer_tools is enabled (r23169) - Feature: Always draw fences around field tiles [FS#1824] (r23168) - Feature: Support for NewGRF version 8 (r23159) - Feature: [NewGRF] Patch/setting variable 14: get the maximum height of the map (r23158) - Feature: [NewGRF] Road vehicle property 23 to shorten vehicles without callback usage (r23149) - Feature: [NewGRF] Allow passing 32bit parameters to 60+x variables (using var 7B). Currently most useful for vehicle var 60 (r23138) - Feature: [NoAI] AICargoList_StationAccepting [FS#3799] (r23134) - Feature: [NewGRF] Property for the rail type name (r23129) - Feature: [NoAI] Allow AIs to query the amount of remaining operations for the current tick (r23118) - Feature: [NewGRF] Ambient sound effect callback (r23114) - Feature: Auto-refitting of vehicles during loading at a station when the vehicle allows it (r23089, r23087) - Feature: [NewGRF] Callback to change refit cost depending on old and new cargo type (r23086) - Feature: [NewGRF] Use variable 10 to enable vehicle GRFs to draw different sprites on the map and in various GUIs (r23080) - Feature: [NewGRF] House callback 0x148 (r23072) - Feature: [NewGRF] House variable 0x64 (r23070) - Feature: [NewGRF] Long date of last service for vehicles, also available in the purchase list (r23068) - Feature: A -q command line option to read a savegame, write some general info and exit (r23065) - Feature: [NewGRF] stringcodes 9A 19 and 9A 20 to print 'short volume' and 'short weight' respectively (r23063) - Feature: [NewGRF] Allow use of NewGRF text stack during callback 23 (r23040) - Feature: Support company colour for the airports' runways [FS#4797] (r23010) - Feature: [NewGRF] Allow to use offsets for all types of action5 except sea shores [FS#4795] (r23004) - Feature: [NewGRF] Action2 variable 0x62 to get curvature/position difference to the n-th vehicle in vehicle chain [FS#2521] (r22998) - Feature: [NewGRF] Allow access to other vehicles in the vehicle chain in VarAction 2 (r22997) - Feature: Display autoreplace status in group GUI (r22985) - Feature: Display profit icons for groups in the group GUI (r22984) - Feature: Display the number of vehicles in the group GUI also for the ALL and DEFAULT groups (r22983) - Feature: Allow road corners on steep slopes (r22968) - Feature: Allow depots, standard road stops and airports on steep slopes (r22960) - Feature: [NewGRF] Allow Action4 to change text IDs 0x00D1 to 0x00E0 for feature 48 (r22954) - Feature: [NewGRF] Extended Action1 format to define arbitrary spriteset IDs (r22926) - Feature: [NewGRF] Allow referencing spritesets from different Action1 in a single Action2 (r22925) - Feature: Allow towns to build bridges over canals and rivers (r22899) - Feature: Resize the tree build GUI to according to tree size (r22862) - Feature: Conditional order depending on remaining lifetime of a vehicle (r22858) - Feature: [NewGRF] Allow replacing depot sprites without having to provide rail overlays (r22854) - Feature: Display separate ocean and canal speeds in the ship purchase list, if they differ (r22850) - Feature: [NewGRF] Bits 8-31 in station variable 43 (r22848) - Feature: [NewGRF] Also age wagons and articulated parts (r22816) - Feature: [YAPF] Take canal/ocean speed fraction of ships into account (r22801) - Feature: Progress bar for scanning NewGRFs (r22797) - Feature: [NewGRF] Stringcodes for printing 0-based dates, unsigned words in power units (r22779, r22778) - Feature: River generation (r22767) - Feature: [NoAI] AITile::GetTownAuthority() (r22764) - Feature: [NewGRF] Implement feature 04 property 18 bit 5 (r22746) - Feature: [NewGRF] Per vehicle custom cargo ageing period (r22713) - Feature: Display option to hide competitors' signs and station names [FS#4701] (r22708) - Feature: Add a menu entry for the sprite bounding box debugging feature in the help menu and enable bounding boxes only in conjunction with the NewGRF developer tools (r22675) - Feature: [NewGRF] Provide random bits in var 0x10 for callback 0x3B in all cases [FS#4690] (r22673) - Feature: Do not spawn explosion effects when bulldozing in paused mode. They block the view (r22670) - Feature: [NewGRF] Support for the land slope check callback for stations (r22659) - Feature: [NewGRF] Custom error messages for object callback 0x157 (r22658) - Feature: [NewGRF] More default error messages for the industry shape and location callbacks (r22657) - Feature: [NewGRF] Add water class to the 'land info of nearby tiles' vars (r22655) - Feature: [NewGRF] Support for ship props 14/15 (ocean/canal speed fraction) (r22639) - Feature: [NoAI] Add several functions to AICompany to find out performance information (r22584) - Feature: [NewGRF] Persistent storage for towns (r22569) - Feature: [NewGRF] Support for station variable 0x69 (r22543) - Feature: [NewGRF] Advanced sprite layouts with register modifiers (r22518) - Feature: Save heightmap in scenario editor (r22514) - Feature: Make the transparency options for industries also affect the effect vehicles created by industries [FS#4625] (r22506) - Feature: [NewGRF] Implement variable 18 for custom station foundations (r22453) - Feature: [NewGRF] When NewGRFs are disabled via Action E or due to GRM failure, also display an error in the GUI (r22444) - Feature: [NewGRF] Allow to filter by town of the current industry when using industry variable 0x68 [FS#4591] (r22434) - Feature: An advanced setting to specify the default palette to use for NewGRFs without action 14 palette information; this makes the default choice independent from the used base graphics (r22417) - Feature: Sort the items in the currency dropdown; separate the 'Custom' item with a horizontal line from the rest (r22312) - Feature: Separate default and NewGRF-supplied townnames with a horizontal line and only sort them within these groups (r22312) - Feature: [NewGRF] Allow docks to feature company colour (r22293) - Feature: Apply the same inflation to the initial loan as to the maximum loan. Note that this is no change to the economy; it only saves players some clicks when starting companies in later years (r22253) - Feature: [NewGRF] Make var 0x48 available in CB 0x15C (r22231) - Change: [Win32] Move painting the window and doing palette animation into a separate thread (r23482) - Change: [SDL] Move 32bpp-anim palette animation to the draw thread instead of the single threaded bit of the game loop. This causes a speedup of up to 15% when animation is turned on with the 32bpp-anim blitter (r23451) - Change: Make the company GUI somewhat smaller if there are no shareholders (r23424) - Change: [NewGRF v8] Allow translating multiple languages with Action 13 (r23391) - Change: Bring Squirrel to 2.2.5; besides some nice bug fixes, it mostly solves the sort() issues (r23383) - Change: Move the 'default' overrides out of the base set in order to ensure they all use the same values (r23232) - Change: Different directories for base sets and newgrfs. So data to base set or newgrf, and gm to base set (r23219) - Change: [NewGRF v8] Do not override rail type prop 1B with prop 09 (r23166) - Change: [NewGRF v8] Format of extra callback info for callback 144 (r23157) - Change: [NewGRF v8] Use height level units in var 8A of callback 28 (r23155) - Change: [NewGRF v8] Use height level units in nearby tile info variables (r23154) - Change: [NewGRF v8] Use height level units in variable 20/A0 (r23153) - Change: [NewGRF v8] Snow line height table uses values between 0x00 and 0xFF independent of number of height levels (r23152) - Change: [NewGRF v8] Deprecate callback 11 and 12, and use callback 36 instead (r23151, r23150) - Change: [NewGRF v8] Unify the return values of boolean callbacks, and check the results for validity (r23147) - Change: [NewGRF v8] Make callback 22 return a probability to use instead of property 18 (r23146) - Change: [NewGRF v8] Determine the 'first' refittable cargo of vehicles using the cargo ordering from the cargo translation table (r23145) - Change: [NewGRF v8] Consider the 'default cargotype' properties as indices into the cargo translation table (r23144) - Change: [NewGRF v8] Return the translated cargobit in vehicle var 42 (r23143) - Change: [NewGRF v8] Unify the return values of callbacks returning D0xx texts (r23142) - Change: [NewGRF v8] Invert result bit 10 of callbacks 149 and 157 to make them consistent with other slope check callbacks (r23141) - Change: [NewGRF v8] Do no longer apply base cost fallbacks (r23139) - Change: [NewGRF v8] New result format for callback 16 (r23137) - Change: [NewGRF v8] Deprecate old-style callback results 0xFF?? (r23136) - Change: Open the query string window centred as it (almost) always requires your attention [FS#4825] (r23130) - Change: [NewGRF] Enforce that the default cargo type of a vehicle is one of the refittable cargoes in case of refittable engines (r23077) - Change: Use the currency -> euro conversion rate for currencies that have been replaced with the euro, so when the switch happens the conversion rate at that point is roughly that of the real world conversion rate (r23056) - Change: Disable palette animation for pixels with alpha, as the alpha and previous colour information will be lost when the palette is animated (r23016) - Change: More suitable default news settings instead of everything on 'full' (r22897) - Change: Always use the DOS palette for drawing, remove the '-i' option for palette selection (r22419) - Change: Make YAPF the default pathfinder for ships, do not discourage players from using it anymore (r22352) - Change: Remove pixel limiter for query strings (r22343) - Fix: Dates cut off in the message history [FS#4896] (r23643) - Fix: Fix transparency for steel mill, colour translations in some arctic buildings and a wrongly replaced sprites [FS#4892] (r23639) - Fix: Draw PBS reservations also for bridges and tunnels with railtype overlays (r23586, r23584) - Fix: Add missing characters for certain languages and the large font [FS#4870] (r23582) - Fix: Extending a path reservation starting at a partially reserved rail station could fail [FS#4888] (r23564) - Fix: [NoAI] ScriptSign::BuildSign() returned wrong result if the sign name was too long [FS#4886] (r23516) - Fix: Drawing of newspaper headlines used different padding than the initial sizing of the window [FS#4884] (r23509) - Fix: [Squirrel] Provide a proper error message when the _cmp meta-function does not return an integer (r23496) - Fix: Make autoreplace, autorenew, cloning and autorefit check all articulated parts of a vehicle to find a shared cargo subtype (r23487) - Fix: In case you already have orders, ignore the vehicles when adding an extra order [FS#4770] (r23484) - Fix: Replace OS error messages with internal error messages when that is possible [FS#4594] (r23480) - Fix: Clear the backed up orders of a removed station as well, otherwise one could create orders to a station that was never in the original backupped orders. For example a road vehicle trying to go to a buoy [FS#4876] (r23464) - Fix: Do not assume all industries that cut trees have tile (0,0) and wait until all tiles of an industry are completed before starting to cut trees (r23458) - Fix: Mark company window dirty when moving a rail engine creates or deletes a train (r23454) - Fix: Some airport functions did not take the layout into account resulting in wrong noise levels or nearest towns [FS#4764] (r23441) - Fix: Perform checks for NFORenum/GRFCodec in configure, including a version check so a proper error can be given when a too old GRFCodec or NFORenum is used [FS#4867] (r23438) - Fix: Recolouring of some animated colours from the Windows (=least consistent) palette went wrong [FS#4868] (r23433) - Fix: Prevent windows to be resized beyond the bounds of the (main) window [FS#4842] (r23429) - Fix: [NoAI] The AIEvent.ET_COMPANY_NEW was only triggered if a company named itself, which seems like a very odd place to do so. Trigger it when the company is created instead (r23398) - Fix: Bring some more order in the ordering of the windows, e.g. do not let a save or load dialogue get hidden by a news message [FS#4709] (r23336) - Fix: Road vehicle purchase info failed to display vehicles carrying no cargo [FS#4820] (r23334) - Fix: Abort building/moving HQ when clicking on the button again, just like when building rail, stations, etc [FS#4851] (r23331) - Fix: Change the centre of train vehicles to depend on the vehicle length instead of being fixed at 4/8th of the original vehicle length to make sure shortened vehicles do not block tiles they should not block [FS#2379,FS#3569] (r23290) 1.1.5 (2012-01-14) ------------------------------------------------------------------------ - Fix: Make default timeouts for certain network states lower and configurable [CVE-2012-0049] [FS#4955] (r23764) - Fix: Check whether a water tile is really empty when overbuilding it with an object [FS#4956] (r23763) - Fix: Missing locking causing crash in extreme case when being in the MP lobby [FS#4938] (r23752) - Fix: Clear the backed up orders of a removed station as well, otherwise one could create orders to a station that was never in the original backupped orders. For example a road vehicle trying to go to a buoy [FS#4876] (r23464) - Fix: Do not assume all industries that cut trees have tile (0,0) and wait until all tiles of an industry are completed before starting to cut trees (r23458) 1.1.4 (2011-12-05) ------------------------------------------------------------------------ - Fix: Savegames made with the Catalan town name generator would trigger a 'savegame corrupt' exception [FS#4866] (r23418) - Fix: [Network] Do not send chat messages to clients that have not joined yet [FS#4826] (r23337) - Fix: Assertion could be triggered in case a station was removed just after a vehicle delivered cargo to it [FS#4849] (r23312) - Fix: Pathfinders go haywire when you build a lock over a ship going perpendicular to the axis of the new lock [FS#4845] (r23284) - Fix: [NewGRF] Prevent against writing data for unknown fonts (r23283) 1.1.4-RC1 (2011-11-20) ------------------------------------------------------------------------ - Fix: 3-column view of NewGRF GUI had too much space for certain font sizes (r23251) - Fix: Ignore special characters, such as the train 'character', when determining a fallback font (r23237) - Fix: [NewGRF] Make train var 0xF3 consistent with TTDPatch (r23231) - Fix: Invalidate build vehicle window when changing the setting for wagon speed limits (r23211) - Fix: [NoAI] Hide AIObject from the documentation as it cannot be used (r23204, r23201) - Fix: [Network] Unstable sorting in the network list when two servers had the exact same name [FS#4829] (r23202) - Fix: Oil rigs that 'expired' did not get removed from the station list [FS#4822] (r23199) - Fix: [Squirrel] replace custom qsort by std::sort to fix stack overflow [FS#4830] (r23190, r23187, r23186) - Fix: Do not display railway fences between track and waypoints [FS#4627] (r23163) - Fix: [NoAI] AIOrder did not handle implicit orders correctly in all cases [FS#4823] (r23135, r23133) - Fix: When any keys on the on-screen keyboard were pressed the text cursor disappeared (r23132) - Fix: [NoAI] AIOrder::IsCurrentOrderPartOfOrderList return false for valid vehicles and crashed for invalid ones (r23131) - Fix: [NoAI] calling require() to include a file gave you 100.000 opcodes for free (r23117) - Fix: Allow accessing the server's client info as well in the admin network [FS#4813] (r23115) - Fix: [NewGRF] Run StartupEngines() if NewGRFs changed during loading a savegame, just like it is running when NewGRFs are changed during a game (r23083) - Fix: Account for snow line table when determining the snow line for building houses (r23082) - Fix: [NewGRF] If a NewGRF overrides a default house the minimum start year for that house was set to 1930 [FS#4794] (r23059) - Fix: [NoAI] AIOrder::GetOrderCount() did not hide implicit orders (r23057) - Fix: [NewGRF] When vehicles break down, update the image cache after changing the vehicle state (r23050) - Fix: Use the same forest-check for the vegetation-map colour as for nearby station names [FS#4810] (r23049) - Fix: Check that the selected font size is valid the font face in use and choose the nearest size to that selected if not. Font metrics should then just work (r23038) - Fix: [NewGRF] Strip newlines from NewGRF strings that should not have newlines, e.g. the NewGRF's name [FS#4769] (r23036, r22970) - Fix: The last custom playlist items went lost when the files in the .obm are not contiguous [FS#4776] (r23035, r23034, r23033) - Fix: Palette conversion windows to DOS for light house / stadium animated colour was mixed up (r23032) - Fix: For the admin 'bots' there was no distinction between bankruptcy and manual removal of companies even though the API suggested that [FS#4804] (r23031) - Fix: Always show a chat message and send an admin packet when a new company is made [FS#4796] (r23030) - Fix: Pass bottom of dropdown item rather than bottom of dropdown window, so the dropdown gets drawn better with different font sizes (r23018) - Fix: AI backlog was to short to fully display the backtrace of some AI crashes [FS#4798] (r23012) - Fix: When the last used server is deleted from the list also clear the last used server if it is the same [FS#4791] (r23011) - Fix: [NewGRF] Make sure temporary storage is cleared before test and exec runs for DoCommands so NewGRF callbacks cannot change the result between the runs (r22996) - Fix: [NewGRF] Tile was cleared before the object-placement callback was run, resulting in possible differences in test and exec run [FS#4775] (r22994) - Fix: [NoAI] Do not return ERR_UNKNOWN when the vehicle would become too long (r22988) - Fix: Draw buoy sprite without outline on the map, fix minor issues with original graphics (r22974, r22973, r22971, r22962) - Fix: The savegame description and loading of savegames would crash with savegames from a patched stable (which did not bump the savegame version) [FS#4778] (r22958, r22957) - Fix: Guard from reading outside the silly name list (r22955) - Fix: [NewGRF] Properly limit the length of strings in a choice list (r22952) - Fix: [NewGRF] Do not call CB 32 for disaster, effect vehicles or aircraft shadows/rotors (r22947) - Fix: [NewGRF] Crash when accessing vehicle var 44 for a non-front aircraft [FS#4781] (r22946) - Fix: Calculate the size of the start/stop vehicle button correctly (r22941) - Fix: [OSX] Various OSX 10.7 issues causing OpenTTD to not work [FS#4751] (r22921, r22895, r22893, r22889) - Fix: [NewGRF] Properties for feature 0x05 were not zeroed for each NewGRF, thus waterfeatures could glitch when the properties were set by a previous NewGRF and the NewGRF assumed the properties to be unmodified (r22918) - Fix: Old TTO/TTD savegames could get non-stop via orders upon savegame loading, even when those orders did not exist back then. This 'conversion' feature is something for TTDPatch and old OpenTTD savegames [FS#4716] (r22914) - Fix: The icon would (almost) never be shown for SDL builds [FS#4617] (r22910) - Fix: The name of the heightmap glitches in the 'play heightmap' window (r22902) - Fix: Locks would be incorrectly assembled (r22108) 1.1.3 (2011-09-15) ------------------------------------------------------------------------ - Fix: Prevent authentication bypass for the admin port when a new game is started [FS#4771] (r22934) - Fix: TTO savegames with any aircraft not in an hangar caused crashes during load (r22915) - Fix: Windows 2000 and XP without service pack 3 must use the win9x binary/installer; the newer MSVC compiler of the compile farm does not support those versions of Windows anymore [FS#4749] (r22909) 1.1.3-RC1 (2011-09-04) ------------------------------------------------------------------------ - Add: River graphics for the original base set (r22766) - Fix: [NewGRF] DCxx text references via the text stack are not allowed, but caused crash [FS#4758] (r22882) - Fix: Harden memory allocation (r22881, r22880, r22875) - Fix: Miscalculation of train curve speed limits (r22879) - Fix: Validate image dimensions before loading [CVE-2011-3343] [FS#4747] (r22878, r22877, r22874, r22873) - Fix: Report an error in the news if autoreplace/renew fails due to the engine type being no longer available [FS#4712] (r22876) - Fix: Perform stricter checks on RLE compressed BMP images [CVE-2011-3343] [FS#4746] (r22872, r22871) - Fix: [NewGRF] Variables 40 and 81 of callback 18 are not the same as 80 (r22867) - Fix: [NewGRF] Generic callbacks shall chain to the next GRF when the callback fails (r22866, r22865) - Fix: Perform stricter checks on some commands [CVE-2011-3341] [FS#4745] (r22845) - Fix: Harden savegame load against too many AI config settings [CVE-2011-3342] [FS#4748] (r22843) - Fix: Compilation with GCC 4.7 (r22832, r22728, r22719) - Fix: Allow to demolish aqueducts built in the scenario editor [FS#4741] (r22821) - Fix: Towns expanding from the 'wrong' side of a tunnel or bridge [FS#4731] (r22810, r22809) - Fix: [NewGRF] String codes for dates should use unsigned words, like old OpenTTD did before it learned dates before 1920 (r22774) - Fix: [NoAI] Clarify the meaning of AIStation::IsWithinTownInfluence(), AITile::IsWithinTownInfluence() and AITown::IsWithinTownInfluence() [FS#4702] (r22763) - Fix: [NewGRF] Also free allocated depot tables of NewGRF airports (r22760) - Fix: [NewGRF] Invalid memory access when querying the grfID of the default objects [FS#4730] (r22757) - Fix: When marking tile selections dirty, use the height information of the corners instead of the surface slope. This is more accurate when the foundation is kind of undefined [FS#4727] (r22755) - Fix: Make aircraft point to the exit when leaving the hangar [FS#4696] (r22743, r22742, r22741) - Fix: Display the size of the levelled platform in the measurement tooltip of terraforming operations [FS#4708] (r22740, r22739) - Fix: Setting company passwords via the GUI on servers (including starting a company with the default password) failed, so no client could join that company [FS#4722] (r22738) - Fix: [NewGRF] The construction stage sprites were incorrectly selected in cases other than 1 or 4 sprites per set (r22731) - Fix: [NoAI] AITile::GetCargoAcceptance, AITile::GetCargoProduction and AIRail::BuildNewGRFRailStation did not check the cargo argument for validity (r22726) - Fix: [NewGRF] Always draw NewGRF supplied texts with a default colour (r22725) - Fix: [NewGRF] Do not restrict AdvVarAct2 to 255 operations (r22723) - Fix: If there is no point in opening the rail/air toolbar, do not open it for people who use hotkeys either rather than only for those using GUI elements (r22716, r22715, r22714) - Fix: [NoAI] Allow AIAirport::GetNoiseLevelIncrease() also for expired airports [FS#4704] (r22710) 1.1.2 (2011-08-14) ------------------------------------------------------------------------ - Fix: Some corrupted savegames could crash OpenTTD instead of showing the 'savegame corrupted' message [CVE-2011-3342] [FS#4717] (r22737, r22736) - Fix: [NewGRF] Triggering NOT_REACHED when playing with a NewGRF that supplies genders/cases for a language that was not installed [FS#4718] (r22735) 1.1.2-RC2 (2011-07-30) ------------------------------------------------------------------------ - Fix: Cost of adding an extra road type to a bridge or tunnel was undercalculated [FS#4680, FS#4681] (r22700, r22699) - Fix: Only insert cleared object tiles into _cleared_object_areas if clearing actually succeeds, else subsequent tests of the same tile will be skipped and considered successful [FS#4694] (r22698) - Fix: When building a house it could be built at the wrong place if multitile houses failed some tests (r22697) - Fix: [Network] Failed network address resolving could trigger temporary freezes [FS#4697] (r22696, r22695) - Fix: [NewGRF] The override managers were not reset in some cases like creating a new scenario [FS#4691] (r22693) - Fix: [NewGRF] Aircraft defined with IDs above the default aircraft's always defaulted to passenger cargo (r22690) 1.1.2-RC1 (2011-07-24) ------------------------------------------------------------------------ - Change: [NewGRF] Only allow access (via hotkey and menu) to the bounding box visualisation when NewGRF developer tools are enabled (r22675) - Fix: [NewGRF] Disallow accessing variable 1B in network games due to desync reasons (r22682) - Fix: Switching from a red to a white highlight (by switching to another tool) without switching the highlight mode (HT_RECT etc.) did not mark the selection dirty [FS#4670] (r22649) - Fix: [NewGRF] Parameters from NewGRFs were not properly parsed in all cases [FS#4599] (r22648, r22630, r22629, r22628, r22627) - Fix: GetSection() does not return a LockPart [FS#4678] (r22645) - Fix: [NewGRF] Disallow building NewObjects on water tiles owned by another company (r22643) - Fix: [NewGRF] Disable the 'set parameters' button in the NewGRF GUI, if the GRF specifies to have no parameters and one would not be able to set any parameters anyway (r22642) - Fix: Keep the previous owner of the upper and lower lock parts if they are built on existing water (r22638) - Fix: [NewGRF] Airports should not expose the tile specific random bits of the north tile. Only airport tiles should access those (r22636) - Fix: [NewGRF] Correctly reseed random bits of industries and industry tiles (r22635, r22634) - Fix: [NewGRF] Implement variables 25 and 7F for railtypes (r22633) - Fix: [NewGRF] Additional text in fund industry window is NewGRF supplied and thus should have a default colour (r22631) - Fix: Also initialise _old_vds with newgame settings; TTD savegames do not contain these settings [FS#4622] (r22626) - Fix: Do not zero the orders of disaster vehicles when converting savegames [FS#4642] (r22625) - Fix: When closing an AI company the local player cheated to, we need to cheat him to another company [FS#4654] (r22624, r22623) - Fix: When closing down companies their shares in other companies must be sold even if share trading is disabled at that point of time (r22622) - Fix: When asking the user to confirm an unsafe unpausing, there is no need to execute a command if 'no' is chosen. This also prevents crashing when clicking unpause while the confirm window is shown (r22621) - Fix: Enforce refit orders to be 'always go to depot' orders; service-only and stop-in-depot orders make no sense with refitting [FS#4651] (r22620) - Fix: Consider the size of the vehicle sprite for the lineheight in the company GUI. This also makes the widget containing the sprite not skip drawing it, if the bounds of the widget are outside of the drawing area though the sprite actually needs drawing [FS#4662] (r22619) - Fix: When changing difficulty settings over the network, do not just reopen the difficulty window if any game options window is opened; instead invalidate them properly [FS#4653] (r22618, r22617) - Fix: [NewGRF] If callback 33 returns a value out of range, no sound effect shall be played [FS#4656] (r22614) - Fix: Use rotated heightmap sizes for reporting scaling problems [FS#4663] (r22608) - Fix: Do not show cargo accepted/produced in the new station window when no tiles are selected (mouse hovering a window or toolbar) [FS#4647] (r22595, r22593) - Fix: Add active NewGRFs to the list of available ones when selecting the empty preset [FS#4644] (r22594) - Fix: Reading of heightmaps with uncommon BMP formats failed due to uninitialised variables [FS#4645] (r22592) - Fix: PBS order forecasting modified the current order index in case of a goto-nearest-depot order and no depot could be found [FS#4641] (r22589) - Fix: Remove BaseStorageArrays from _changed_storage_arrays on destruction (r22583, r22551) - Fix: Do not increment STL iterators after they have been invalidated (r22582) - Fix: Do not lower the arrow buttons in the NewGRF/AI parameter windows if they are clicked when disabled (r22553, r22499) - Fix: Clear airport persistent storage on construction/removal of airports (r22552) - Fix: Possible crash when opening the airport build window for the first time [FS#4619] (r22538) - Fix: Replace the half small airport structure on the intercontinental airport with some grass [FS#3494] (r22537) - Fix: Documentation omission regarding admin protocol [FS#4632] (r22536) - Fix: [NoAI] Doing rescan_ai in a game with running AIs caused a crash [FS#4631] (r22534) - Fix: Do not create an implicit order if the current order is the first order in the order list and we visit the station of the last entry of the order list (r22532) - Fix: MinGW 64 related compilation issues [FS#4623] (r22522, r22491, r22490, r22489) - Fix: The layout selectors of the airport build GUI did not latch properly (r22497, r22495) - Fix: Callback result for airport layout name was incorrectly used (r22496) - Fix: Airport preview sprite can depend on the layout, so update the cached SpriteID when the layout changes (r22494) - Fix: Engine IDs for coal and mail wagons were swapped in the TTO savegame conversion [FS#4622] (r22487) - Fix: The caption of centred windows could be moved out of the main window and thus become inaccessible when resizing the main window (r22485, r22484) - Fix: No client error packet was sent to the admin bots [FS#4585] (r22384) 1.1.1 (2011-06-01) ------------------------------------------------------------------------ - Change: Automatic orders are better called implicit orders as no real order influencing path finding is added (r22474, r22473) - Fix: Only try to insert implicit orders for ground vehicles. Aircraft may reach unscheduled terminals when skipping orders [FS#4624] (r22492) 1.1.1-RC1 (2011-05-15) ------------------------------------------------------------------------ - Feature: [NewGRF] Allow to filter by town of the current industry when using industry variable 0x68 [FS#4591] (r22434) - Change: Improve the speed of YAPF by tweaking hash tables size (r22351, r22350, r22348) - Change: Show one digit of the fractional train length in the depot (r22336, r22305, r22304, r22303) - Fix: When determining the executable path failed, the working directory was used instead, circumventing the not-home-directory check [FS#4613] (r22465) - Fix: [Windows] Prevent a crash when launching OpenTTD with -d from a MSYS console [FS#4587] (r22464) - Fix: Update the saveload window immediately after scanning a new directory, so queued events reach the window when already updated [FS#4615] (r22463) - Fix: [NewGRF] The c and p parts of station vars 40, 41 and 49 were incorrect for large stations (r22455, r22286) - Fix: [NewGRF] Zero register 0x100 as specified before resolving custom station foundations (r22452) - Fix: Do not 'log' the NewGRFs in the screenshot when in the menu [FS#4610] (r22450) - Fix: [NewGRF] When GRFs are disabled via Action E or due to GRM failure, also display an error in the GUI (r22444, r22443) - Fix: [NewGRF] Do not popup fatal NewGRF error messages in the intro screen. The GRFs are not going to be activated there anyway and the GRF settings GUI will not display the errors either (r22442) - Fix: Catenary was drawn incorrectly next to level crossings with foundations (r22437) - Fix: [NewGRF] Apply railtype property 12 (station graphics) also to station groundsprites from action 1 (r22436) - Fix: Git revision detection would return too much when tags are involved (r22435) - Fix: [NewGRF] When action14 specified different values for the palette, the values were OR-ed. Use the last set value instead (r22416) - Fix: [Network] Kicking yourself via remote console crashes the server [FS#4606] (r22414) - Fix: [NewGRF] Make sure the action2 ID of a generic feature callback is valid (r22409) - Fix: Check the availability year of all houses, not just the NewGRF houses, when making sure that at least one is available onwards from year 0 [FS#4581] (r22389, r22300, r22299) - Fix: When a game uses a lot of NewGRFs the buffer for storing that information in the PNG is too small (r22388) - Fix: Windows' recv seems to return 'graceful closed' before having passed the remaining buffer which causes OpenTTD to think all connections are 'incorrectly' terminated, i.e. without the 'I am leaving' packet from the client. So let the client wait a tiny bit after sending the 'I am leaving' packet and before gracefully closing the connection [FS#4601] (r22387) - Fix: When the last AI company gets removed, the 'dead' state was not reset in the AI debug window [FS#4602] (r22386) - Fix: Recolouring of silicon bridge was done incorrectly (r22380, r22379, r22378) - Fix: Crash when clicking a removed company in the vehicle list dropdowns [FS#4592] (r22373) - Fix: Keep better accounting of the order in which clients joined; client cannot be starved from joining and they get shown the amount of clients waiting in front of them (r22372, r22370, r22369, r22368, r22367, r22366, r22365, r22364, r22363, r22362, r22361) - Fix: Make sure saving has completely and utterly finished before starting a new one. Otherwise you could start a save, which would be marked as done by the previous save stopping and then yet another save could be started... and that could create a deadlock [FS#4596] (r22371) - Fix: Delete the client list popup when the client got removed (instead of previously selecting some other client) (r22360, r22359, r22358) - Fix: When inserting automatic orders, do not create consecutive duplicate orders (r22333, r22332, r22331, r22330, r22329, r22328, r22327) - Fix: Destinations of conditional orders were update incorrectly when deleting orders in front of the conditional orders, if the target order was the order just before of the conditional order (r22326) - Fix: Vehicles skipped orders when inserting automatic orders failed (r22324) - Fix: [NewGRF] When determining refittability use the cargo translation table of the GRF setting the refitmask instead of the GRF defining the action 3 (r22316) - Fix: Make road vehicles, ships and aircraft skip orders if they are leaving a depot and heading to the same one again; just like trains (r22309) - Fix: Waiting on a server could kick the client, or rather the client would kick itself due to an unexpected packet [FS#4574] (r22308) - Fix: When drawing the town authority window, check whether the availability of the actions changed, and force a complete redraw in that case (r22307) - Fix: The 'freeform edges' setting could be enabled when there were buoys on the northern border [FS#4580] (r22297) - Fix: Reset Window::scrolling_scrollbar when raising scrollbar buttons [FS#4571] (r22294) 1.1.0 (2011-04-01) ------------------------------------------------------------------------ - Fix: In the scenario editor you could build a ship depot using the appropriate hotkey. Removing that depot causes an assertion to trigger [FS#4558] (r22266) 1.1.0-RC3 (2011-03-18) ------------------------------------------------------------------------ - Fix: New game settings were applied too early when starting a game via a heightmap [FS#4557] (r22259) - Fix: Do not resort town, industry and signs list directly in OnInvalidateData(). There might be a scheduled rebuild which needs execution first. So, only set a trigger for resorting [FS#4546] (r22249, r22248, r22247, r22246, r22245, r22244, r22243, r22242, r22241, r22236, r22228, r22227, r22226) - Fix: [NewGRF] Object variable 0x48 was not available in callback 0x15C (r22231) - Fix: Compilation when compiling with --disable-ai (r22222) - Fix: When downloading a file via HTTP failed mid-way and OpenTTD fell back to the old system the partial downloaded amount would be counted twice [FS#4543] (r22208) - Fix: The 'center' (for movement) of vehicles is (currently still) always at 4/8th original vehicle length from the front, so trains should stop at the same location regardless of the length of the front engine [FS#4545] (r22206) - Fix: Make the base costs for building and demolishing NewObjects also local to the individual NewGRFs (r22204) - Fix: Removing a station order could stop when removing first automatic order (r22200) - Fix: Invalidate the object build window when using the date cheat (r22193) 1.1.0-RC2 (2011-03-04) ------------------------------------------------------------------------ - Fix: Following a vehicle with a very high VehicleID was impossible (r22181) - Fix: [NewGRF] Memory leak if an industry NewGRF had more than one prop A or 15, or a station NewGRF had more than one prop 09 (r22175, r22165) - Fix: [NewGRF] Disable a station NewGRF when it contains an unterminated spritelayout in action0 prop 08 instead of crashing (r22164) - Fix: Building a station part adjacent to both an existing station and a rail waypoint failed [FS#4541] (r22163) - Fix: No update of NewGRF window when unknown GRF name becomes available [FS#4533] (r22162) - Fix: [NewGRF] Industry prop 0x11 is 4-bytes long, not 3 bytes (r22157) - Fix: Stations/infrastructure were not properly sold on some clients during bankruptcy [FS#4529] (r22154) - Fix: The Greek translation did not work as it breached the 200.000 bytes 'limit' for loading language files [FS#4536] (r22153) - Fix: Windows video driver crashed when it could not go to full screen at the resolution of the configuration file when starting OpenTTD [FS#4521] (r22149) - Fix: Do not run savegame conversion during SlNullPointers; the pointer might not be converted or be NULL at that point (r22146) - Fix: Some valid keycodes were ignored along with the invalid ones (r22142) - Fix: When commands need to invalidate windows, process these events asynchronously before the next redraw. Calling window code directly from command scope uses wrong _current_company and might issue nested DoCommands() which interfere with the running command [FS#4523] (r22141, r22140, r22135, r22134) - Fix: [NewGRF] Skipping only the invalid part of an action14 failed, the rest of the action was skipped instead (r22138) - Fix: Spectators had crashes when closing buoy windows (r22131) - Fix: Build-station-window showed wrong selection when reopening [FS#4530] (r22128) - Fix: Canals would get drawn as land in the smallmap when using the owner window (r22127) - Fix: The animation-ness of two goldmine tiles were swapped, causing the wheeltower to not work properly, and the bottom corner to show the wrong sprite [FS#4528] (r22125) - Fix: CommandQueue::Pop() did not update 'last'; popping the last item caused the queue to disconnect unless there was only one item [FS#4522] (r22123) - Fix: When a NOT_REACHED in saveload can be reached due to an invalid savegame, use SlErrorCorrupt instead. In other words, do not crash but show an error message (r22122) - Fix: In case of high frame_freq one could get commands executed after a new network game was started (r22121) - Fix: [NoAI] Prevent AIs from getting consistently over their allowed amount of operations by subtracting the amount they went over 'budget' from the budget for the next 'tick' (r22120) - Fix: The refit window was not correctly updated after selecting with Ctrl+Click [FS#4525] (r22118) - Fix: CanRemoveRoadWithStop() failed for _current_company = OWNER_TOWN, and for OWNER_NONE-owned road (r22117) 1.1.0-RC1 (2011-02-18) ------------------------------------------------------------------------ - Feature: [NewGRF] Test all possible industry layouts during construction and prospecting [FS#4131] (r22012, r22010) - Feature: Wheel scrolling in the console (r21982) - Feature: Console command to reset the engine pool. It removes the traces of engines which are no longer associated to a NewGRF, and can be used to e.g. 'fix' scenarios which were screwed up by the author. You can only use it when there are no vehicles in the game though (r21975) - Feature: Add a setting to enable/disable funding local road reconstruction (r21974) - Feature: Introduce 'minimal' number of industries as a replacement for the old 'none' setting in the new game window (r21969) - Change: When loading old savegames with long trains set the maximum train length to the length of the longest train (r22061) - Change: Always report mammoth trains are disabled to NewGRFs, and allow the maximum train length to be modified in multiplayer as well [FS#4471] (r22004) - Fix: Remove invalid keycodes when reading hotkeys.cfg [FS#4510] (r22094) - Fix: The server list did not get sorted with one item in it, so the 'position in the list' variable was never updated causing problems when using the keyboard shortcuts for scrolling [FS#4514] (r22093) - Fix: When deleting towns, only relocate objects during DC_EXEC (r22087) - Fix: [Windows] If fullscreen fails with current resolution, use desktop resolution [FS#4489] (r22081) - Fix: The owner view of the smallmap was not updated after a company colour change (r22079) - Fix: Maximum train length interfered with wagon replacement when wagon removal was turned on [FS#4499] (r22078) - Fix: NewGRFs with invalid multi-tile houses could cause a valid 1x1 house following it to be seen as multi-tile, causing crashes [FS#4501] (r22075) - Fix: Immediately update the train weight when you change the multiplier for train cargo weight (r22073) - Fix: Some hotkey names in hotkey.cfg for the scenario editor toolbar were completely bogus (r22071) - Fix: Crashes when disconnecting after requesting the map [FS#4503] (r22070) - Fix: Delete all savegame packets, not just the first one (r22069) - Fix: Return 'connection lost' instead of 'okay' when SendPackets closed the connection, so we do not try to do anything else with the closed socket (r22068) - Fix: Do not hold a mutex when sending packets and thus possibly closing the connection as that wants to acquire the mutex again (r22067) - Fix: Verify we can allocate an Order, OrderList, CargoPacket, CargoPayment, and others before we actually try to do so (all corner cases) [FS#4468] (r22066, r22057, r22047, r22042, r22040, r22033, r22031, r22026, r22025, r22024, r22023, r22022) - Fix: Crash when disconnecting and reconnecting while the server is still saving the savegame [FS#4497] (r22064) - Fix: Memory leak when saving with LZMA or zlib fails mid-way (r22062) - Fix: Make the send chat message window follow the position of the status bar (r22059) - Fix: Metric and imperial HP are not the same. As imperial HP are used internally, set a conversion rate for metric HP [FS#4408] (r22056) - Fix: [Squirrel] Some invalid squirrel code caused the squirrel compiler to crash [FS#4490] (r22055) - Fix: The land area information window was not updated after a language change (r22053) - Fix: Roads under road stops would get a wrong owner after overbuilding (r22051) - Fix: In ancient savegames, e.g. TTO savegames, non primary vehicles (wagons and such) could have unitnumbers or even orders. However, these orders would not be updated when a station is removed. As such some savegames have wagons with current orders to invalid stations which triggers trouble in the load conversion. So, trash any orders/unitnumbers a non-primary vehicle has [FS#4496] (r22050) - Fix: [NewGRF] Company 0 does not always exist, so put temporary vehicles in a valid company (r22048) - Fix: Make sure order indices stay in range when copying, sharing, unsharing or deleting all orders [FS#4487] (r22046) - Fix: Update the consist cache when a part of a train is flipped in the depot [FS#4493] (r22044) - Fix: Invalidate the right windows when a part of a train is flipped in the depot (r22043) - Fix: Tab completion in chat did not cycle through all possible options (r22038) - Fix: Crash when watching the vehicle view of a vehicle that has multiple sequential nearest depot orders (or consists of a single nearest depot order) when there is no depot with index 0 [FS#4488] (r22034) - Fix: The server list got not resorted/redrawn after NewGRFs were downloaded [FS#4482] (r22029) - Fix: When paused and having the allowed actions while paused setting on 'no actions' cheating money would fail [FS#4479] (r22016) - Fix: Only show one AI per unique ID instead of all versions in the output of 'openttd -h' (r22007) - Fix: Smoke/sparks of trains would be shown under bridges, or rather through bridges [FS#4480] (r22006) - Fix: When the difference between force and resistance is smaller than the mass(*4) there would be no acceleration anymore, even when at higher (or lower) speed the force and resistance balance out better [FS#4473] (r21997) - Fix: [YAPF] Under some circumstances vehicles could be lost [FS#4472] (r21996) - Fix: [NewGRF] Make computations of closest-land/water-distances handle waterish tiles more correctly (r21994) - Fix: When building a lock on dry land costs for clearing water were deducted rather than for building canals (r21993) - Fix: AIs trying to change the AIOF_GOTO_NEAREST_DEPOT flag for existing orders triggered an assert. Explicitly forbid this as precondition for SetOrderFlags [FS#4467] (r21992) - Fix: The share/copy-orders-cursor was not updated to refer to the new vehicle when it got autoreplaced/-renewed [FS#4466] (r21991) - Fix: Vehicle status bar glitches on speed changes (r21989) - Fix: Scrolling of the console in pages used wrong line height and scrolled too much (r21979) - Fix: Redraw the town authority window after modifying town authority settings (r21973) - Fix: Crash when a multiplayer company goes bankrupt with 'you' in it [FS#4464] (r21970) 1.1.0-beta5 (2011-02-04) ------------------------------------------------------------------------ - Feature: GUI setting to disable reversing at signals (r21962) - Feature: Not loading and not unloading is now possible (r21961) - Change: [NewGRF] Disable the flipping of train engines/wagons in the depot by default for NewGRFs [FS#4462] (r21966) - Change: Show the length of vehicles in tiles, instead of half tiles in the depot (r21960) - Change: Replace longbridges settings with custom maximum bridge and tunnel length setting (r21959) - Change: Randomise the vehicle a small UFO targets, do not use the one with lowest index (r21949) - Fix: Do not count the number of vehicles but the length of vehicles to (configurably) limit train length [FS#4461] (r21960) - Fix: [NewGRF] Reset the carry flag every 4 bytes in Action 6 when adding more than one variable (r21951) - Fix: Road vehicle was moved under the bridge when it was destroyed by an UFO while on a bridge (r21948) - Fix: Crash when converting a savegame with vehicles crashed in a tunnel entry, or with vehicles reversing there (r21947) - Fix: Funny behaviour when a road vehicle reverses while overtaking, so abort the overtake attempt when reversing the road vehicle [FS#4447] (r21946) - Fix: Not all vehicles should be tested to be inside a tunnel upon savegame load [FS#4460] (r21940) - Fix: Do not remove existing road/tram bits when overbuilding stops of the opposite road type [FS#4457] (r21936) - Fix: Allow to overbuild road stops which are built over trams (r21935) - Fix: Automatic orders behave now stable wrt. service orders and are not added or removed depending on the need of servicing [FS#4440] (r21933) - Fix: The town window would not be invalidated in the scenario editor if the ground changed and thus the required cargoes for town growth [FS#4554] (r21929) - Fix: Converting an expensive rail type to a cheap one could give more money than removing and rebuilding cost (r21919) - Fix: Languages improperly sorted in the 'start server' window [FS#4443] (r21918) - Fix: The minimum speed needed for (realistic) acceleration to work properly can sometimes be more than the (temporary) maximum speed causing Clamp to 'fail'. Make sure that the minimum speed always overrules the maximum speed [FS#4442] (r21916) - Fix: Include the capacity of non-refittable vehicles in the refitted-capacity, if their cargo matches (r21904) - Fix: Do not count articulated parts when passing the number of vehicles to refit to the command. That may exceed 8 bits (r21902) - Fix: [NoAI] Hide automatic orders from AIs as they have no way of dealing with them (r21900) - Fix: Do not show a vehicle selection in the RefitWindow for refit orders. You cannot select anything anyway (r21899) - Fix: Using a pointer-iterator and adding things (thus reallocating) to the iterated array caused OpenTTD to crash on invalid pointers [FS#4438] (r21898) - Fix: Only some scenarios from the main scenario folder and no heightmaps could be started in the 'start server' window [FS#4421] (r21892) - Fix: Crash when scrolling outside of the main window (with some video backends) [FS#4434] (r21889) - Fix: [NewGRF] String codes 0x80 and 0x81 were broken since the typechecking of string parameters [FS#4422] (r21885) - Fix: When a train after reversing ended at the last bit of a bridge ramp and directed outside the bridge, it could still have track set to TRACK_BIT_WORMHOLE (r21880) - Fix: When a single-vehicle train was reversed while on a slope, its GOINGUP/DOWN were not swapped (r21874) - Remove: Settings for vehicle speed in the vehicle view, long date in status bar, drawing of bridge pillars, support for depot orders, time tabling and joining of stations upon building (r21958, r21957, r21956, r21955, r21954) - Remove: The non-uniform stations setting; it has been broken for over a year, and thus not used [FS#4456] (r21953) 1.1.0-beta4 (2011-01-21) ------------------------------------------------------------------------ - Feature: [NewGRF] Rail type property to influence sorting of rail types in the drop down list [FS#4394] (r21866) - Feature: [Network] Console command to change the password of other companies for servers [FS#4368] (r21855) - Feature: [NewGRF] Introduction dates/required types for rail types; e.g. introduce a particular rail type in 1960 (or when a vehicle using it is introduced), but also allow limiting its introduction to only happen when the required railtypes are available [FS#4393] (r21842) - Feature: Limit vehicle lateness to the length of a full timetable cycle, e.g. when a cycle takes 50 days and the vehicle is 65 days later reduce the lateness to 15 days (r21832) - Feature: After building a road or tram bridge/tunnel, connect it to any existing road or tram (r21778, r21777) - Feature: Display NewGRF object sprites during object picking (r21772) - Feature: Display NewGRF station sprites during station picking (r21755) - Change: Allow LMB scrolling with the mouse outside of the extra viewport instead of cancelling scrolling when going slightly over the edge (r21838) - Change: Only show rail/road types that will eventually be available in-game. For example do not show trams when there is no tram NewGRF loaded (r21817) - Change: Keep aqueducts and road/tram tunnels and bridges after removing a company (r21780) - Fix: Distant-join station would build at the wrong location when having persistent building turned on and selecting a 'second' location for the station tile [FS#4430] (r21864) - Fix: Slowing down of trains was done by reducing the speed by 10%, but also when you are just 1% too fast, so limit the slowdown till the new maximum speed [FS#4423] (r21847) - Fix: Left-mouse-button dragging would switch over to other viewports instead of staying locked to the viewport you started on [FS#4419] (r21837) - Fix: When a train was reversed while inside a tunnel/bridge, it would not have (re)set the GOINGUP/DOWN bits after leaving the tunnel/bridge (r21836) - Fix: Desync debug savegames might not be actually saved in case threading is enabled, which is enabled by default [FS#4427] (r21833) - Fix: Service orders for trains/aircraft would (sometimes) not get a time when autofilling [FS#4414] (r21831) - Fix: Crash with the small map window on big endian platforms [FS#4417] (r21830) - Fix: The expectations from the 'always build infrastructure' setting name/description did not match the behaviour [FS#4007] (r21826) - Fix: Allow dragging of combo signals (again) [FS#4378] (r21816) - Fix: [YAPF] Apply a pathfinder penalty for back of one-way path signals so those are not preferred over other possibilities [FS#3908] (r21815) - Fix: Check GRF version from action 8, and disallow usage of GRFs with versions above 7 (r21814) - Fix: Crash when displaying the owner view [FS#4411] (r21813) - Fix: Do not create automatic orders when there are no manual orders, and remove unreached automatic orders when reaching an ordered waypoint or depot [FS#4404] (r21809, r21808) - Fix: Loading a TTO savegame failed after loading a TTDP savegame (r21799, r21798) - Fix: The size (in characters) of the string inputs was too small for loading some TTD savegames (r21797) - Fix: Drive through road stop state was not properly converted from TTDPatch savegames [FS#4398] (r21796) - Fix: Broken usage of GetTileOwner() caused wrong conversion of old savegames (r21793) - Fix: Terraforming limit was off-by-one when terraforming a single tile height [FS#4407] (r21791) - Fix: TTDPatch savegames can have train waypoints encoded as buoys [FS#4398] (r21790) - Fix: When the font misses the fallback character '?', use the sprite font's '?' instead [FS#4405] (r21789) - Fix: Crash due to invalid rail station width and height data stored in TTDPatch savegames [FS#4398] (r21786) - Fix: Crash when converting savegame with custom waypoint name (r21784) - Fix: Diagonal tile iterator failed for A * 0 selections [FS#4396] (r21768) - Fix: Do not limit tile clearing during bankruptcy [FS#4397] (r21767) - Fix: PBS reservation was not shown on road crossings with NewGRF railtypes [FS#4369] (r21765) - Remove: The 'stopall' console command, as its functionality was broken. Group start/stop commands can be used instead [FS#4409] (r21804) 1.1.0-beta3 (2011-01-09) ------------------------------------------------------------------------ - Feature: Configurable limit amount of tiles that can be cleared/terraformed by a company [FS#4331] (r21728) - Feature: Show a list of companies in the owner legend and allow them to be toggled for visibility (r21720, r21718) - Feature: Console command 'list_ai_libs' to get a list of recognised AI libraries [FS#4372] (r21703) - Feature: Allow changing the AI configuration in the scenario editor / in game [FS#4362] (r21696) - Change: Tune 'realistic' acceleration even more to make more trains reach their top speed, and make it behave more like TTDPatch (r21712) - Change: Display the minimum height of the tile in the LandInfo window instead of the height of the northern corner. So it is more useful for NewGRF and AI developers, and maybe more transparent for players (r21711) - Fix: The diagonal iterator would iterate twice over some tiles [FS#4395] (r21747) - Fix: [NewGRF] Canal variable 83 accessed water random bits also for non-water tiles (e.g. watery industries or objects) (r21746) - Fix: [NewGRF] Canal variable 80 shall return consistent heights within a lock (r21745) - Fix: Allow Ctrl+Clicking automatic orders for scrolling to their destination (r21744) - Fix: Coast tiles were not drawn under bridges [FS#4386] (r21743) - Fix: Make clearing refit orders work again [FS#4388] (r21739) - Fix: Start loading when cur_order_index points to the destination station, i.e. after deleting not-reached automatic orders [FS#4384] (r21738) - Fix: A loading order was also marked as 'not part of orders' when the order before the current order was deleted (r21737) - Fix: Admin bots were not always notified of password changes [FS#4377] (r21727) - Fix: Vehicle sprite was cached into a 16 bit variable, causing incorrect sprites to be displayed (r21709) - Fix: [NewGRF] Report TTDPatch flag 4A (newobjects) as set (r21708) - Fix: The old ship pathfinder is too stupid to provide 'lost' notices; it would even get lost while following its own path [FS#4370] (r21706) - Fix: Do not perform any more checks after the connection is closed [FS#4374] (r21704) - Fix: Changing AI settings ingame was impossible when the difficulty level was other than custom (r21694) - Fix: Due to an error in the Debian changelog building of Debian/Ubuntu packages failed (r21682) 1.1.0-beta2 (2010-12-31) ------------------------------------------------------------------------ - Feature: Command logging using the admin interface (r21668) - Feature: Concept of automatic station orders; add stub orders for intermediate stations and remove them when not visiting them anymore. This allows you to see what trains visit a station without actually having to order a vehicle to stop at all stations (r21642) - Add: [NoAI] AIEventTownFounded (r21664) - Add: [NoAI] AIRail::GetName() to get the name of a railtype (r21663) - Add: [NoAI] AITown::IsCity() so AIs can find out which towns grow faster than others (r21654) - Change: Do not show price to build a bridge in the scenario editor as they are free to build there [FS#4358] (r21673) - Change: Do not highlight tile when selecting a vehicle to clone or an order to skip to (r21616) - Fix: Estonia introduced the Euro in 2011 (r21670) - Fix: Autofill timetable had side effects in test mode, possibly causing desyncs in MP [FS#4354] (r21660) - Fix: Cargo payment graph was not properly invalidated when payment rate changed [FS#4351] (r21658) - Fix: Use a bool instead of uint8 to store a bool and use the dedicated accessor function when reading boolean settings [FS#4345] (r21656) - Fix: Infinite loop in the road pathfinder due to bouncing around in an 'one way' trap; two one ways pointing towards each other making it impossible to leave [FS#4338] (r21651) - Fix: Make '[centre|main] view' consistent, and make '[main|global] view' consistent [FS#4339] (r21650) - Fix: Newly created skip-to order was created at wrong place (r21633) - Fix: Ships with the old pathfinder would easily show up as lost, even when it would eventually find a path. Now also the distance from the 'end' of the pathfinding run to the destination is compared to the current distance to the destination; if the distance to the destination at the end of the pathfinder run is less than the current distance from the destination the ship will not be marked as lost. This means that the ships with the old pathfinder will less likely get marked as lost, but due to the design of the old ship pathfinder there 'lostness' is merely a best guess. When you still get a lost message you need to build buoys to guide the ship pathfinder [FS#4325] (r21631) - Fix: Version detection of subversion branches and tags got broken (r21630) - Fix: Crash under certain circumstances when using autorail [FS#4327] (r21619) 1.1.0-beta1 (2010-12-24) ------------------------------------------------------------------------ - Feature: [NewGRF] Variable 7B for accessing 60+x variables while taking the parameter from the accumulator (r21604) - Feature: Allow to refit only the selected part of a train consist (r21567) - Feature: Store the used OpenTTD version, base graphics set, NewGRFs and AIs in the PNG screenshots (r21558, r21553) - Feature: Make the delay of the chat messages timing out unrelated to the number of passed game days, i.e. do not stop ageing chat messages when the server is paused, and make the timeout user configurable [FS#532] (r21513, r21512) - Feature: Vehicle lost messages for ships and road vehicles [FS#1956] (r21511, r21510) - Feature: Diagonal tile clearing and terraforming by pressing Ctrl [FS#730] (r21500) - Feature: [NewGRF] Use the station graphics property to determine a fallback for the depot sprites [FS#4279] (r21473) - Feature: Add explicit make 'shared orders' an option in the orders menu (r21464) - Feature: Make it more clear that you are stopping a shared order, and make it possible retain the order list upon unsharing [FS#3711] (r21461) - Feature: Hotkey Ctrl+W for returning to the main menu [FS#3217] (r21459) - Feature: Scroll to the inserted order [FS#4215] (r21457) - Feature: Building while paused always works in the scenario editor [FS#1521] (r21430) - Feature: Perform the compression of savegames to send to the client asynchronously. This will reduce the lag of the other clients to the time it takes to make the memory dump and it will speed up downloading the map as the download starts earlier (possibly with a slightly lower bandwidth due to slow compression) [FS#4284] (r21399) - Feature: Do not store savegames to disk when transferring it from the server to a client (r21398, r21397) - Feature: Use alphabetical order when sorting industries by type at the industry directory window (r21389) - Feature: Allow entering of the new year in a text box when cheating the year [FS#4289] (r21388) - Feature: Support for limiting the amount of (accepted) incoming data for a server (r21363) - Feature: Natural sorting of strings using ICU [FS#4214] (r21344) - Feature: [NewGRF] Implement action0 visual effect properties for ships and RVs (r21240) - Feature: [NewGRF] Support callback 0x10 for RVs and ships (r21238) - Feature: [NewGRF] Make positioning of diesel fumes and electric sparks actually work (r21230) - Feature: [NewGRF] Support OpenTTD's genders, cases and plurals (r21216, r21211, r21209) - Feature: Display mail capacity when refitting an aircraft to passengers (r21214) - Feature: Make the statusbar's location configurable [FS#4201] (r21179) - Feature: Forced construction of missing industries (r21175) - Feature: Do not build industries during economic recession (r21169) - Feature: Use desired industry counts rather than relative probability to decide which industry to build (r21168) - Feature: Allow to sort purchase lists for trains and road vehicles by tractive effort (r21105) - Feature: [NewGRF] Add CB36 support for road vehicle property 0x15 (Speed) (r21100) - Feature: [NewGRF] Implement stringcode 9A 0C (station name), 9A 0D (weight) (r21086, r21085) - Feature: [NewGRF] Add CB36 support for road vehicle properties 0x13 (Power), 0x14 (Weight) and 0x18 (Tractive effort) (r21058) - Feature: XZ/LZMA2 savegame support. New default reduces savegame size by 10 to 30% with slightly more CPU usage. With maximum settings it reduces savegame size by 20 to 30%, but that takes 7 to 14 times longer. Map saving + downloading takes, on average, 5% less (r21044) - Feature: Chat directly to the server or a bot/admin/IRC channel monitoring the server (r21000) - Feature: Remote administration (r20975-r20963) - Feature: [NewGRF] The concept of minimum loadable version to NewGRFs when choosing compatible NewGRFs (r20960, r20958) - Feature: Centre new extra viewports on the tile below the mouse. Only centre on centre of main viewport if mouse is not in any viewport (r20956) - Feature: [NewGRF] Make it possible to distinguish player built/randomly placed industries in the location and land slope check callbacks (r20942) - Feature: Highlight all destination tiles when building a lock [FS#4153] (r20932) - Feature: Transfer orders imply 'leave empty' by default [FS#3905] (r20927) - Feature: Allow to select a custom percentage of water in the map generation window (r20832) - Feature: Make it possible to select vehicle to clone and vehicle to clone orders from directly from vehicle lists and depot window [FS#3999] (r20753) - Feature: Separate GUI icons for vehicle/company profit, exclusive rights and unread news (r20720) - Feature: [NewGRF] Support for newobjects (r20670) - Feature: Make the (flat) area around an industry configurable (r20659) - Feature: [Network] Allow rate limiting of incoming commands (r20553) - Feature: Filter signs at the sign list window [FS#3472] (r20516) - Feature: Ignore _ in console command names so there is no 'inconsistent' behaviour w.r.t. underscores anymore without breaking backward compatibility greatly (r20515) - Feature: A new screenshot type that makes a zoomed-in screenshot of the visible viewport [FS#3973] (r20508) - Feature: Setting for none/original/more smoke [FS#3093] (r20376) - Feature: Airport previews (r20381, r20369) - Feature: [NewGRF] Support for callback 0x147 ('add sprite offset') for canals (r20353) - Feature: [NewGRF] Support for property 09, feature 05, i.e alternate canal sprite layout (r20352) - Feature: Add rescan_newgrf console command (r20344) - Feature: [NewGRF] AdvVarAct2 operators for SHL, SHR and SAR (r20332) - Feature: [NewGRF] Air drag property support for trains and road vehicles. Air drag for vehicles with air drag not set or set to zero will use a default value depending on their max speed (r20303, r20302, r20301, r20300, r20299) - Feature: More user-friendly gui to change NewGRF parameters (r20258) - Feature: [NewGRF] Add support for static NewGRF information, i.e. Action 14 (r20250) - Feature: Display suppliers and customers of an industry or cargo (r20206) - Feature: Allow horizontal resizing for all vehicle lists [FS#3955] (r20174) - Feature: [NewGRF] Information (var 4A) about the current railtype a train is on (r20165) - Feature: Tooltips are shown by hovering the mouse over a widget instead of by right clicking on it [FS#3913] - Feature: Customisable hotkeys (r20055) - Feature: Wrap console lines when they are too long [FS#3816] (r20046) - Feature: [NewGRF] Variable 43 depot build date for railtypes [FS#3886] (r20003) - Feature: Show some savegame details when selecting items in saveload GUIs (r19984) - Feature: Open vehicle view when clicking on the caption of vehicle news (r19944) - Feature: [NewGRF] Access to industry founder (var A7) during callbacks 28 and 2F (r19901) - Feature: Add highlighting of drag destination in depot and order GUI gui [FS#3705] (r19889, r19888) - Feature: Configure NewGRFs from a single window (r19841) - Feature: Give depots an unique name in the same manner buoys and waypoints are named. Also allow them to be custom named [FS#3691] (r19801, r19799) - Feature: Hide all other industries when Ctrl+clicking an industry type in smallmap legend (r19770) - Feature: [NewGRF] Access to random bits of houses and industries from construction callbacks 17, 28 and 2F. That is: The random bits the house/industry will start with, if construction succeeds [FS#3477] (r19744) - Feature: A simple sprite alignment helper. It does not store the new offsets anywhere so as soon as the sprite is reloaded the offsets are gone (use a bigger sprite cache if this happens). Also anything that reloads NewGRFs (new games, loading games or (re)applying NewGRFs) clears the sprite cache and as such resets the offsets (r19723) - Feature: New base costs for building/clearing canals, building/clearing aqueducts and building/clearing locks (r19720) - Feature: Ctrl+click on a vehicle to start/stop it (r19714) - Feature: NewGRF debugging/inspecting of (primarily) enabled callbacks and values of variables (r19709) - Feature: Graphs with negative values are no longer forced to have the zero axis in the middle, resizeable graphs (r19662, r19631) - Feature: [NewGRF] Support callback 36 for aircraft speed also in the build menu (r19660) - Feature: Add an input box to the AI Debug window where you can input a break string [FS#3496] (r19544) - Feature: Add buttons to enable/disable all cargoes at the cargo payment rates graph (r19542) - Feature: Sort industries alphabetically at the smallmap legend, fund industry list; sort cargoes alphabetically at cargo payment graph, build vehicles cargo filter dropdown, station ratings and refit options (r19541, r19540, r19436, r19535, r19522, r19503) - Feature: Console command 'reload_newgrfs'; only available when NewGRF developer tools are enabled (r19515) - Feature: Enter the starting year in the scenario editor by clicking at the date panel (r19397) - Feature: Configurable slope steepness for road vehicles from 0% to 10%, default is 7% (r19346) - Feature: Realistic acceleration for road vehicles (r19345) - Feature: Allow to (over)build and remove multiple road stops using drag and drop (r19231, r19230, r19229) - Feature: Show warnings and errors in console as well, not only in a message box (r19225) - Feature: [NewGRF] Action 0/1/2/3 support for NewGRF airporttiles (r19194) - Add: [NoAI] AIOrder::IsVoidOrder to find void '(Invalid Order)' orders (r20389) - Add: Support for MSVC 2010 (r20032) - Add: [NoAI] AIIndustry::GetIndustryID(TileIndex) (r19773) - Change: Make it possible to start actions that require selecting stuff (landscaping, vehicle cloning, etc) in the viewport while paused. As side-effect you will get an error message explaining the command cannot be executed because the game is paused instead of seemingly nothing happening when you click. Additional side effect of this is that you can make use of the measurement tooltip while paused [FS#4292] (r21480) - Change: Make building aqueducts behave more like building tunnels. They cannot be built on flat (or foundation) tiles, so there is at most one destination tile like there is only one for tunnels [FS#4153] (r21471) - Change: Place the bridge building window under the mouse instead of somewhere randomly on the screen and change the default sort order [FS#3975] (r21460) - Change: Make sure the client is listening, or rather receiving, our frames (r21361) - Change: Read some metadata from (official) source tarballs so you will more likely get the right version/revision out-of-the-box (r21351) - Change: Be more explicit that the game state can get broken by changing NewGRFs (r21335) - Change: Use the last red instead of last red exit penalty for making sure other waypoint entries are evaluated as well when they are occupied, e.g. when there are no signals before the waypoint but a train just beyond the waypoint is stopped (like for stations) (r21271) - Change: Do not receive money for removing the rail of non-rail rail station tiles, i.e. rail station tiles for which the NewGRF has prevented trains to be routed through (r21266) - Change: Show a different 'lag' message when a client is lagging because of connection trouble or lagging because the client is just slow (r21254) - Change: Mention the OpenTTD version on the console/logs when starting an OpenTTD dedicated server like we mention it in the title bar for the GUI version (r21253) - Change: Filter stations by cargo they have a rating for instead of having cargo waiting [FS#4206] (r21144) - Change: Limit the number of exceptions in the refittable cargo list to 7 (r21083) - Change: Reduce the chances to accidentally break savegames with NewGRFs by limiting loading of savegames that miss NewGRFs or change NewGRF settings in-game [FS#3012] (r21116) - Change: Tuned realistic acceleration to be a bit more realistic in order to make acceleration 'slower', which highlights the differences between vehicle types more (r21106) - Change: Do not make client reconnect waiting time depend on the company; in coop games that does not spread clients at all, and most companies have a low number causing it not to be spread out either. Use the ClientID instead (r21008) - Change: Add installing options or rather options to not install certain documentation, in a similar way to GRFCodec/catcodec (r20999) - Change: Only display liveries in the livery window if they are used by some vehicle somewhen (r20849) - Change: [NoAI] Rename AIAbstractList to AIList (r20563) - Change: [NoAI] AIOrder::GetOrderFlags returns AIOrder::AIOF_INVALID for void orders (r20389) - Change: [NewGRF] Adapt vehicle var FE bit 6 to new railtypes (r20175) - Change: [NewGRF] Call callbacks 14A, 14B and 14C after all industry variables have been assigned, so more variables are valid during the callbacks (r19907) - Change: [NoAI] Remove HasNext() from all lists/iterators and add IsEnd() instead (r19294) - Change: Add the default installation directory of lzo/zlib for Mac OS X/MinGW to the paths where (the headers of) those libraries are searched [FS#3638] (r19285) - Fix: Crash due to cargo payments belonging to a non-existing company [FS#4324] (r21605) - Fix: Company league table used stats from two quarters ago instead of last quarter [FS#4323] (r21601) - Fix: The default visual effect only depends on properties of the Engine (wagon or not, tractiontype, ...), not whether it is used as articulated part, front engine or whatever in a specific consist [FS#4275] (r21598) - Fix: [OSX] A double mouse cursor was shown under certain circumstances [FS#2585] (r21578) - Fix: Show 'plant trees' button lowered on the terraform toolbar, like how other buttons are lowered when you selected a 'build' action [FS#4315] (r21539) - Fix: 2CC recolour sprites were the same for DOS and WIN palette, thus 'dark green', 'brown', 'grey' and 'white' were wrong for DOS [FS#4312] (r21535) - Fix: Do not apply the last signal red pathfinder penalty when the signal is a path signal [FS#4302] (r21524) - Fix: Tooltips were not removed when their related window got closed [FS#4300] (r21477) - Fix: Make sure the query window is only opened once per parent window/callback [FS#4298] (r21472) - Fix: Crash when news item gets removed at just the wrong moment [FS#4180] (r21458) - Fix: [NewGRF] Ensure the parameter for house variable 60 is the id of an original house (r21456) - Fix: [NewGRF] A NewGRF with incomplete string codes at the end of a string could cause invalid memory reads (r21433) - Fix: The server did not check for the paused state when allowing to execute commands [FS#3771] (r21429) - Fix: Vehicles could be built while the game is paused. Now you can enable or disable that with a setting, which replaces the build-while-paused cheat [FS#4021] (r21428) - Fix: Purchase lists were not invalidated when using 'resetengines' (r21374) - Fix: Fields were not cleared under snow though they were intended to be [FS#4283] (r21367) - Fix: New railtypes with overlays did not use the shore sprites as groundtiles for three-corner-raised slopes (at shore) [FS#4277] (r21353) - Fix: Buffer overflow in strgen for strings with very large arguments (r21346) - Fix: Bogus cache mismatch warnings with desync debugging because some cache was invalidated but never reset [FS#4272] (r21338) - Fix: Make it more likely that the savegame and transferred file are the same file and not different ones [FS#4271] (r21334) - Fix: Use the correct font sizes when checking for missing glyphs (r21321) - Fix: [Content] Crash when creating file download by the content download system failed (r21319) - Fix: AIs in an infinite loop in e.g. autosave, but also getting settings and such from info.nut, would not be interrupted after a while causing OpenTTD to seem to not respond [FS#4260] (r21311) - Fix: [Content] Do not add HTTP connection to list of connections when it fails in the beginning (r21302) - Fix: Fonts set in openttd.cfg were not properly checked for missing glyphs on language change [FS#4261] (r21298) - Fix: FreeBSD introduced strndup as well [FS#4259] (r21295) - Fix: [Windows installer] Check for existence of save/scenario dirs before asking for deletion confirmation [FS#4251] (r21294) - Fix: Under some circumstances two vehicles could leave a non drive-through road stop at once [FS#3935] (r21263) - Fix: [NewGRF] Custom station foundations using the 'simple foundations'-method did not draw any sprite for WSE-slopes when there are foundations on both neighboured tiles in the north. As there must be at least one sprite to provide the correct offset for the groundsprite draw the (empty) default foundation sprite in that case [FS#4246] (r21262) - Fix: The main menu error messages would not show when you had an error message open in the game while whatever triggered you to go back to the main menu (r21255) - Fix: Rescanning AIs did not 'forget' removed AIs [FS#3952] (r21250) - Fix: Upon rescanning AIs the new AIs would (after some time) show up in the AI list but you could not select all (r21246) - Fix: [YAPF] Road vehicles not finding the nearest depot in some (corner) cases [FS#4130] (r21229) - Fix: [NewGRF] The specs' cargo strings and OpenTTD's use of the clashed. Provide properties so NewGRFs can provide cargo strings tailored for OpenTTD while retaining (some) backward compatibility [FS#4172] (r21224) - Fix: Use proper plural for the short cargo unit names (r21223) - Fix: Under some conditions, group count would be wrong after moving train engines in the depot window [FS#4207] (r21205) - Fix: [OSX] Do not let the mouse cursor jump when switching to full screen mode (r21200) - Fix: [OSX] Finding a fallback font failed when compiling for OSX 10.4 as it tried to match also OpenTTD-specific control characters [FS#4001] (r21197) - Fix: Use non-interactive randomness for townnames on map generation, so they are controlled by the generation seed as well [FS#4226] (r21192) - Fix: [OSX] Unify compiler flags with other OS and work around a compiler bug in gcc-4.0.1 which breaks graphics display in x86_64 binaries [FS#4210] (r21149) - Fix: Station list was not updated when a new cargo got a rating (r21145) - Fix: Station ratings were not updated (anymore) after an aircraft crashed (r21137) - Fix: Bridge speed limits should apply to all wagons of a vehicle, not just the head of the vehicle [FS#4213] (r21136) - Fix: Helicopter flight altitude was determined inconsistently in different places (r21119) - Fix: Do not use the maximum track speed where the maximum vehicle speed is meant (r21107) - Fix: Display the real maximum speed for aircraft instead of always using the engine value (r21096) - Fix: Aircraft speed would ignore callback 36 result when it is greater than the engine speed (r21094) - Fix: [OSX] Mouse cursor would leave footprint with 8bpp blitter when switching to full screen (r21037) - Fix: [OSX] Properly set the palette when using the 8bpp blitter during start-up (r21036) - Fix: Centre industry gui and waypoint gui after resize [FS#4171] (r21021) - Fix: Draw bridge pillars with correct length on all tile corners by drawing only half of the pillar sprite if required (r20950, r20947) - Fix: Accidentally moving the mouse of the scrollbar arrows while pressing it clicks the button next to the arrow [FS#4071] (r20922) - Fix: Refit costs were not shown for long cargo names [FS#4160] (r20921) - Fix: When using non-smooth or NewGRF-economy changing production rates does not work, so allow changing the production multiplier instead (r20901) - Fix: The station with the second highest rating was doubly penalised when distributing cargo. Now the penalty is completely removed and the granularity/precision of the distribution in increased by using fractional cargo. This should make competing stations less all-or-nothing [FS#3637] (r20857) - Fix: Make sure (gradual) loading is properly terminated for consists with multiple cargo types. Do not stop loading if the timetabled wait is not over yet [FS#2534] (r20843) - Fix: Place less trees at once when planting random trees at the scenario editor [FS#4094] (r20829) - Fix: Do not use new game settings when creating many random towns/industries at the scenario editor [FS#4094] (r20712, r20711) - Fix: Keep _current_company and _local_company in sync during GUI operation [FS#3804] (r19933) - Fix: When building a lock, do not add the cost of building canals if they are already built, pay for clearing the other tiles and do not add the first bridge type's cost to aqueducts (r19719, r19718, r19717) 1.0.5 (2010-11-20) ------------------------------------------------------------------------ (None) 1.0.5-RC2 (2010-11-14) ------------------------------------------------------------------------ - Fix: Reading (very) recently freed memory [CVE-2010-4168] (r21182) - Fix: Default service interval for ships/aircraft got switched [FS#4222] (r21155) - Fix: Size of sort buttons for save/load and build vehicle list gui could be too small [FS#4221] (r21151) - Fix: [Windows] Make sure to be upgraded openttd is not running when installing [FS#4212] (r21146) - Fix: [NewGRF] Crash when disabling static NewGRFs (when joining/starting a server) [FS#4208] (r21130, r21129, r21128) - Fix: Upper limit for snowline was too low [FS#4203] (r21078) - Fix: Wrong (maximum) value shown for generation seed in the in-game console [FS#4192] (r21075) - Fix: Under some circumstances the file handle of the downloaded savegame would not be closed, and validity of the handled was not checked in all cases (r21027) - Fix: [NewGRF] Crash when getting an industry ID at an offset that uses some 'old' style industry tile [FS#4157] (r20912) 1.0.5-RC1 (2010-10-31) ------------------------------------------------------------------------ - Change: Make OpenTTD aware of XZ/LZMA compressed savegames so loading those gives a proper error message (r21047) - Change: Make it possible to make .tar.xz bundles (r21042) - Fix: Missing default values for the custom town number in the world generation options (r21034) - Fix: Dropdown menu glitched in small screenshots, when issuing them from the menu (r21031) - Fix: Do not let the resize button go past the bottom of the screen [FS#4176] (r21015) - Fix: The detailed performance rating window could be too narrow [FS#4102] (r21010) - Fix: For the compact notation 1.000.000k and 1.000M would be shown depending on the initial (and later rounded) value. Make everything that would round to 1.000.000k be drawn as 1.000M as well (r21009) - Fix: Do not consider the text direction character when searching for missing glyphs (r21007) - Fix: Chat/console messages got sometimes messed up due to LTR names in RTL translations and vice-versa [FS#3746] (r21006, r21004) - Fix: Size of sort buttons for order and vehicle list gui could be too small (r20997) - Fix: [NewGRF] The X and Y offsets in the parameter for industry vars 60, 61, 62, 63 are unsigned instead of signed (r20996) - Fix: When removing a rail station, do not leave track under non-station tiles (r20990) - Fix: [NewGRF] Ignore the variable for Action7/9 condition type 0x0D and 0x0E as documented (r20979) - Fix: Crash when, while the 'go to' cursor is active, you open the order list of a vehicle of another company and then select a 'go to' destination [FS#4159] (r20916) - Fix: Helicopters fired a bit too late [FS#4155] (r20910) - Fix: Road/water toolbars did not get updated when the first vehicle of their type becomes available [FS#4141] (r20856) - Fix: Smallmap legend buttons must all be equal in size, even if their contents is not (r20851) - Fix: Deadlock when aborting map generation on Windows [FS#3707] (r20822) - Fix: Be a bit more lenient with invalid savegames; do not crash on saveload related NOT_REACHEDs, just show the user an error that the savegame is corrupted [FS#3714] (r20819) - Fix: Make the crash-on-saveload message clearer and more correct [FS#3791] (r20818) - Fix: [NewGRF] Clamp/convert some vehicle variables so NewGRFs get their specified range (r20800, r20799, r20792) - Fix: [NoAI] Document that AITile::HasTransportType does not work for TRANSPORT_AIR [FS#4117] (r20798) - Fix: [NewGRF] Disable houses without a size that are available according to their building flags (r20797) - Fix: [NewGRF] Make sure all houses in the house spec array are valid. It was possible that part of a multitile house was not copied because the array was full (r20796) - Fix: Building 2x2 houses did not work for 2x2 road layouts on all map sizes (r20791) - Fix: [NewGRF] Remove a check which is wrong for NewGRF houses and serves no use for original houses [FS#4118] (r20790) - Fix: Spelling mistake in Slovak real town names (r20787) - Fix: Do autosave-on-exit as well when using kill/CTRL-C to terminate a dedicated OpenTTD (r20783) - Fix: [NoAI] AIEventCompanyAskMerger was disguised as AIEventCompanyMerger (r20765) - Fix: [NewGRF] Assert when an industry previously build on water was flooded because its NewGRF changed/is missing [FS#4112] (r20754) - Fix: Do not use new game settings when creating many random towns/industries in the scenario editor [FS#4094] (r20712, r20711) - Fix: Graphics glitch when switching to a different-sized font while the chat message box was visible (r20705) - Fix: Vehicle lists of non-trains could not resize horizontally causing truncation of texts [FS#4123, FS#3955] (r20174) 1.0.4 (2010-09-14) ------------------------------------------------------------------------ - Change: Move removal of bin/data/opentt[dw].grf from distclean to maintainer-clean (r20752) - Fix: Recent NFORenum does not know '-?' (r20715) 1.0.4-RC1 (2010-08-30) ------------------------------------------------------------------------ - Change: Merge the extra GRF's sources and make it possible to rebuild them easily (r20490) - Fix: Empty NewGRF presets were not selectable [FS#4087] (r20694) - Fix: Desync checker checked the wrong variable (r20677) - Fix: Drawing the 'OpenTTD' text in the intro game caused crashes with very low resolutions [FS#4081] (r20618) - Fix: Crash when a NewGRF defined an invalid substitute type for a house and the NewGRF was removed during the game, disable houses with different size than their substitute [FS#3702] (r20611, r20610, r20609) - Fix: Retain information about all base sets that are found and not only the latest version to stop confusing people that use newer versions of the base sets than those available via BaNaNaS (r20607) - Fix: Let NewGRFs var43 var (information about liveries) for vehicles not be influenced by the local setting determining whether to show liveries or not [FS#4063] (r20605) - Fix: 'Downscale' a full load order to a load if possible order when removing the order while the vehicle is loading. This to prevent the vehicle from (possibly) staying forever in the station [FS#4075] (r20600) - Fix: Crash when the tooltip is wider than the window is [FS#4066] (r20596) - Fix: No (proper) savegame conversion was done when _date_fract got a new value range (r20592) - Fix: Autoreplace failed while attaching non-replaced wagons to the new chain, if to-be-sold-engines would become front-engines and the unitnumber limit would be exceeded (r20583) - Fix: Autoreplace can trigger an assertion when at the vehicle limit [FS#4044] (r20582) - Fix: Go via station and go via waypoint behaved differently when a train went back to the same (unordered) station again [FS#4039] (r20580) - Fix: Draw bounding boxes using white instead of pure white, so they are recoloured to grey in coloured newspaper instead of blue [FS#4051] (r20578) - Fix: Scroll button flickering when pressed [FS#4043] (r20577) - Fix: Warn OpenGFX users when they are using a base set that misses sprites (r20566) - Fix: Wrong tooltip for the company select button in the AI debug and performance rating windows [FS#4053] (r20556, r20555) - Fix: In old savegames aircraft can have an invalid state (r20528) - Fix: Crash when the content download tried to get a MD5 checksum of an 'originally' loaded NewGRF [FS#4038] (r20519) - Fix: Draw error messages in white by default, they may not have a colour set when coming from a NewGRF (r20514) - Fix: Entering half the 'generation seeds' in the console's 'newgame' command failed to set the correct seed [FS#4036] (r20512) - Fix: Desync when vehicles change NewGRF properties such as visual effect when changing railtype [FS#3978] (r20505, r20504, r20503, r20502) - Fix: Desync when converting rail all as trains with a part on the converted rails need updating and not only the engines (r20500) - Fix: Ignore the non-stop state when comparing one order type to another order type, otherwise non-stop nearest depot orders fail [FS#4030] (r20498) - Fix: Non-dedicated servers failing to load a game caused the introgame to be the server's game causing desyncs when people tried to join [FS#3960] (r20497) - Fix: [NoAI] checking whether water tiles are connected failed in some cases [FS#4031] (r20489) - Fix: Statues were not removed when towns would be removed (r20481) - Fix: Do not spend cash when building a statue fails [FS#3985] (r20469, r20227) - Fix: Adding 'goto nearest depot and stop' orders in one go was denied. This caused both AI adding those orders and backed up order restoration to fail [FS#4024] (r20441) - Fix: For docks 'facing' north, i.e. having the watery part a the northern side, the station joiner had an off-by-one to the north w.r.t. the station spread against the actual other (correct) building tools [FS#4022] (r20438) - Fix: Make snow on bridges depend on bridgeheight and make snowiness of bridgeheads depend on the tileheight at the entry [FS#3947] (r20424, r20423, r20422, r20421, r20420) - Fix: During world generation the snow-mapbits are not yet available, so test the snowline variable directly (as they were before) [FS#4017] (r20418) - Fix: PBS reservations were always displayed on halftile foundations if the railtype uses overlays [FS#4013] (r20408) - Fix: Make the default minimum width for editboxes 10 pixels to prevent crashes [FS#4010] (r20394) - Fix: Prevent buying more vehicles than allowed or buying companies when you'd get too many vehicles [FS#3993] (r20393, r20392, r20391, r20390) - Fix: Initialise fund-industry buttons when opening window (r20386) - Fix: Update cursor dimensions when reloading grfs resp. changing base graphics, so the cursor does not glitch if it becomes bigger (r20384) - Fix: Stop vehicle following after zooming out [FS#3989] (r20361) - Fix: [NoAI] Ship depots were constructed along the wrong axis [FS#4004] (r20348) - Fix: Fallback font selection due to missing glyphs did not work as intended (r20296) - Fix: When it is known the loading an old savegame is going to fail, bail out immediately (using an exception) instead of going on until e.g. the expected number of byte is read (r20247) - Fix: The caption of the 'Available vehicle' lists was black, whereas for building those vehicles, which uses the exact same window, it was white (r20244) - Fix: [NoAI] Clarify the documentation for AIBaseStation::GetLocation (r20238) - Fix: Refit costs from refit orders are subtracted from the vehicle yearly income [FS#3988] (r20234) - Fix: Road vehicles could be dead locked with one way roads. This allows one wayness to be removed if there are vehicles on a tile; it does not allow you to add one wayness to roads that have vehicles on them as it makes turning vehicles jump [FS#3961] (r20230) - Fix: 'Service at nearest depot' behaved the same as 'Go to nearest depot' [FS#3986] (r20229) - Fix: Depot did not become unsnowy, when snowline rises [FS#3976] (r20224) - Fix: Strip non-printable characters before showing it in an edit box, so when renaming a vehicle type you will not get the 'SETX stuff' that some NewGRFs use [FS#3974] (r20220) - Fix: NewGRFs that defined a vehicle without either loaded or loading groups could crash OpenTTD [FS#3964] (r20199) - Fix: [NewGRF] GetNearbyTileInformation can be used to get the terrain type of a MP_VOID tile [FS#3963] (r20197) - Fix: [NewGRF] Vehicle var FE bit 6 did return incorrect values for new railtypes (r20175) - Fix: Inconsistencies w.r.t. to km/h vs km-ish/h as 'base' unit for aircraft speeds [FS#3870] (r20164) 1.0.3 (2010-08-01) ------------------------------------------------------------------------ - Fix: Make it possible to properly assess the length of the rail toolbar caption, do not require '{WHITE}' control codes (r20242) - Fix: Check for disallowed level crossings also when converting rail (r20237) - Fix: Haiku uses a 'special' location for headers (r20219) - Fix: Desync due to (temporary) wrong railtype; when loading a savegame the railtype of some (high ID) trains could be wrong [FS#3945] (r20137) 1.0.3-RC1 (2010-07-17) ------------------------------------------------------------------------ - Feature: [NewGRF] Textstack support for CB 38 (r20086) - Feature: [NewGRF] Add a railtype flag to disallow level crossings per railtype (r20049) - Change: Improve desync debugging, crash log data and the Debian packaging (by making a debug symbols package) (r20138, r20136, r20129) - Fix: Do not scan /data and ~/data (if they happen to be your working directory). If it is the directory where your binary is located it will still scan them [FS#3949] (r20166) - Fix: Integer comparison failed in case the difference was more than 'MAX_UINT'/2 [FS#3954] (r20162) - Fix: [YAPP] Converting a one-way block to a path signal with trains on both sides could lead to a train crash [FS#3937] (r20156) - Fix: [NewGRF] Improve handling of snowing of railtypes and (infra)structures on foundations [FS#3883] (r20153, r20132, r20126, r20125) - Fix: Ships were not marked as dirty when stopping inside a depot [FS#3880] (r20142) - Fix: Some windows ignored all hotkeys [FS#3902] (r20141, r20140, r20139) - Fix: Do not allow building a rail track to the water using a tree-tile [FS#3695] (r20110) - Fix: [NoAI] AITown::GetRating() returned wrong values [FS#3934] (r20103) - Fix: Reading deleted memory when selecting a NewGRF in the content download window of which the data has not been acquired from the content server. The crash would occur after the content server's reply was processed and the ContentInfo object was replaced with another [FS#3899] (r20089, r20082) - Fix: If after loading a savegame (including intro game) one tried to save a game (including autosave) and that failed (very) early on because it could not open the file for writing all pointers would be converted to NULLs which then causes corrupted game states [FS#3786, FS#3887, FS#3920, FS#3923] (r20087) - Fix: gitignore and hgignore had more missing/wrong entries (r20078, r20033, r20031) - Fix: Remove the space between 'open' and 'ttd' in the title screen (r20077) - Fix: Road vehicles could get crashed twice in a tick [FS#3896] (r20053, r20034) - Fix: Coloured_news_year was stored in savegames while it should be a client setting [FS#3916] (r20051) - Fix: Crash when spectator tried to open a vehicle list without selecting any company [FS#3892] (r20041) - Fix: Instead of loading the intro game when loading a savegame fails on the dedicated server, generate a new game [FS#3907] (r20039) - Fix: Tram tracks did not show at level crossing with the new railtypes [FS#3911] (r20036) - Fix: Under some circumstances you could get into an infinite loop [CVE-2010-2534] [FS#3909] (r20035) - Fix: The 64 bits TortoiseSVN was not always properly detected (r20029) - Fix: Do not close the sort dropdown in the (original) vehicle list when there are no vehicles. That code is meant for the 'actions' dropdown [FS#3881] (r20014) - Fix: When joining a company with a password you could only enter 20 characters of the password (r20012) - Fix: Sign sorting was unstable [FS#3893] (r20009) - Fix: Trains should also have running cost while slowing down for stop (r20006) - Fix: [NewGRF] Stringcodes 82, 83 and 84 were not properly converted to openttd codes so they did not work (r20004) - Fix: Clear force_proceed when entering depots and when loading, resetting of force_proceed on manual stopping did not work [FS#3878] (r19992) - Fix: Do not show an error message when trying to start/stop a crashed plane [FS#3874] (r19953) - Fix: Allow turning of roadvehicles while waiting in a queue (r19945) - Fix: Disallow moving of vehicle news window [FS#3865] (r19943) - Fix: Under some (unlucky) circumstances the wrong company would be 'current company' when changing company colour or orders [FS#3903] 1.0.2 (2010-06-19) ------------------------------------------------------------------------ - Fix: Owner of the Waypoint View window was not properly set (r19990) - Fix: Close list of vehicles with given oil rig in orders when the oil rig is deleted (r19956) - Fix: Close list of vehicles with given buoy/oil rig in orders when switching company (r19955) - Fix: Do not close list of waypoint's trains when the waypoint view is closed when it is sticky (r19952) - Fix: Close buoy's vehicle list when the buoy is deleted [FS#3869] (r19951) 1.0.2-RC1 (2010-06-05) ------------------------------------------------------------------------ - Feature: Translated desktop shortcut comments (r19884) - Change: Name invalid engines, cargoes and industries 'invalid', if the player removed the supplying NewGRFs, hide invalid engines from the purchase list (r19879, r19877) - Fix: When 'pause on new game' is set, pause the game before CleanupGeneration() to avoid conflicts with concurrent GUI code [FS#3857] (r19934) - Fix: Pay for the rail/road when constructing tunnels, bridges, depots and stations [FS#3859, FS#3827] (r19925, r19887, r19881) - Fix: Closing chatbox could cause glitches when news message was shown [FS#3865] (r19921) - Fix: [YAPP] Inform the pathfinder as well about the fact that the backside of an one-way path signal can be a safe waiting point [FS#3803] (r19896) - Fix: Allow loading savegames from the console without specifying the '.sav' extension, i.e. make it consistent with saving savegames from the console [FS#3761] (r19885) - Fix: Dropdowns did affect positioning of new windows because they were not yet removed when the new windows were positioned [FS#3812] (r19883) - Fix: [NoAI] AIEngine::IsValidEngine() and AIEngine::IsBuildable() returned false positives. Especially wagons of unavailable railtypes were reported available (r19880) - Fix: Default vehicle group texts were drawn one pixel too low [FS#3851] (r19878) - Fix: It was not possible to send all trains with common waypoint order to depot (r19876) - Fix: Compilation for NetBSD [FS#3809, FS#3840, FS#3845] (r19874, r19859, r19853, r19781) - Fix: If the (guessed initial) destination tile of a road vehicle was not a road stop but was a T-junction or turn, the road vehicles would jump around in circles [FS#3817] (r19873) - Fix: When a network connection gets lost and a game with AIs was loaded the client might crash due to the AIs not being loaded while the game loop is executed [FS#3819] (r19869) - Fix: Use non-breaking spaces for currency pre-/postfixes (r19867) - Fix: Crash when changing/viewing locale settings in the console [FS#3830] (r19865, r19864, r19863, r19862) - Fix: Drawing fallback sprites for unavailable NewGRF waypoints failed (r19852) - Fix: Ensure that both texts of the NewGRF gui download button fit (r19823) - Fix: Kicking clients by IP did not work [FS#3784] (r19818) - Fix: Compilation with MinGW GCC 4.5.0 and UNICODE (r19787) - Fix: If a waypoint is immediately followed by a path signal a reservation would be made from that path signal before the waypoint is marked passed. As a result the order to go to the waypoint is used to reserve the path after the waypoint and as such trains get lost [FS#3770] (r19784) - Fix: NULL pointer deference when testing relative scope *action2 on an unbuilt engine [FS#3828] (r19782) - Fix: Crash on too long paths [FS#3807] (r19780, r19779, r19778, r19777, r19776) - Fix: MP_VOID tiles shall have no tropic zone [FS#3820] (r19769) - Fix: Half-desert tiles would never revert back to clear tiles (r19768) - Fix: Height in smallmap was different from measured heights [FS#3808] (r19767) - Fix: [NewGRF] Vehicle var 43 missed AI information in purchase list (r19761) - Fix: Blocked roadvehicles should first check whether they are still blocked before accelerating again, instead of continuous starting/stopping (r19755) - Fix: Try harder to find a suitable font that can be loaded, i.e. while searching for a suitable font test whether you can open it [FS#3740] (r19753) - Fix: Make sure the chat area fits in the default window size; if you want it larger, you can always change/override it in the config file [FS#3798] (r19751) - Fix: [NewGRF] Industry var 0x43 is not 'safe' during callbacks 22 and 38 either (r19750) - Fix: [NewGRF] Possible divide-by-zero if a NewGRF checked industry var 42 while the production level was 0 (r19749) - Fix: Do not recenter usually centred windows when resizing main window or changing language, if they have been moved/resized before [FS#3675] (r19746) - Fix: The GUI is controlled by _local_company, not _current_company (r19745) - Fix: NewGRFs could access map bits of not yet constructed industries and houses during construction callbacks (r19748, r19743) - Fix: [NewGRF] Passing some invalid data to industry variable 67/68 could cause a crash (r19713) - Fix: Check for industry availability more thoroughly and cancel object placement when selecting not available industries [FS#3787] (r19701) - Fix: Avoid showing building toolbars behind the main toolbar when the 'Link landscape toolbar' setting is active [FS#3781] (r19696) - Fix: Under some circumstances the player's name could be empty (r19693) - Fix: Do not show an error message when trying to give another client an amount of 0 money [FS#3779] (r19684) - Fix: Do not display an error message when double clicking on a vehicle in the 'available vehicles'-window (r19669) 1.0.1 (2010-05-01) ------------------------------------------------------------------------ - Fix: Crash when using restart via rcon (r19722) - Fix: Leaking a file descriptor [CVE-2010-0406] [FS#3785] (r19695) - Fix: Crash when the music/graphics metadata files were unreadable [FS#3774] (r19674) 1.0.1-RC2 (2010-04-22) ------------------------------------------------------------------------ - Fix: Desync when joining the game because of using the wrong variable (r19687) - Fix: Truncated archives were not detected when using zlib 1.2.3. This also fixes zlib 1.2.4 compatibility, zlib 1.2.5 is bug free (r19686) - Fix: Towns with 3x3 and 2x2 road layouts could not expand (r19683) - Fix: When joining a MP game all clients with company ID > 0 would be shown as if they were a spectator [FS#3775] (r19680) - Fix: Client status was shown incorrect in the console (r19678) 1.0.1-RC1 (2010-04-17) ------------------------------------------------------------------------ - Feature: [NewGRF] Support for extended text code 0x9A 11, print qword (r19570) - Feature: Give more detailed error message when trying to build a too long bridge (r19561) - Feature: Add rail speed limit to land area information window (r19556, r19434) - Add: [NoAI] AIRail::GetMaxSpeed(RailType) to get the speed limit of railtypes (r19591) - Change: Sync Debian packaging updates from Debian, but keep building a single package (r19572) - Fix: Crash of a dedicated server if the null blitter is overridden and (after a while) there is no company 0 on new year anymore [FS#3749] (r19664) - Fix: In rare cases, update of signals could be missed (r19663) - Fix: Various improvements of command handling, missing error messages, improper validation causing crashes [CVE-2010-0402] [FS#3748] (r19658, r19657, r19656, r19655, r19654, r19637, r19633, r19621, r19616, r19605, r19604) - Fix: Industry generation failed for large maps and lots of industry types (r19652, r19643) - Fix: When a company is sold, move connected clients to spectators [FS#3745] (r19651) - Fix: A client would not be properly moved when moved while joining, e.g. when entering a company's password. This caused the client to be in the wrong company (according to the rest of the clients) and the client being kicked on the first command [FS#3760] (r19648) - Fix: Trains loaded above the original IDs did not have a default railtypelabel assigned to them, causing them to be unavailable. Could cause desyncs if the multiplayer game was not started from a savegame [FS#3768] (r19647) - Fix: Do not allow building cacti outside of the desert or rain forest trees outside of the rain forest area. This to prevent people from thinking planting rain forest trees makes the rain forest bigger and thus adds more place to build a lumber mill [FS#3728] (r19644, r19635, r19634) - Fix: Desync when taking over companies (r19636) - Fix: Chat message caused glitch when rejoining a network game [FS#3757] (r19629) - Fix: Desync when a command is received and in the queue while a client starts joining, i.e. save the game state. This can happen in two ways: with frame_freq > 1 a command received in a previous frame might not be executed yet or when a command is received in the same frame as the join but before the savegame is made. In both cases the joining client would not get all commands to get in-sync with the server (and the other clients) (r19620) - Fix: Company related graphs were not updated correctly after changing the company colour [FS#3763] (r19615) - Fix: Possible invalid read when server moves client to spectators before he finishes joining [FS#3755] (r19613) - Fix: Crash when opening a savegame with a waypoint from around 0.4.0 [FS#3756] (r19612) - Fix: Improve joining behaviour; kicking clients when entering passwords that was just cleared, 'connection lost' for people failing the password, access restriction circumvention [CVE-2010-0401] [FS#3754] (r19610, r19609, r19608, r19607, r19606) - Fix: Desync debugging; false positives in the cache validity checks and saving/loading the command stream (r19619, r19617, r19602, r19601, r19600, r19596, r19593, r19592, r19589, r19587, r19586) - Fix: Presence of online content was not properly updated after download due to duplicate slashes in the path (r19600) - Fix: [NewGRF] Setting industry prop 0x24 to 0 caused empty station names (r19590) - Fix: Crash when pressing 'h' (non-stop) in the order window of a ship or aircraft [FS#3744] (r19584) - Fix: Graphs were not properly updated when going toggling keys (i.e. companies) (r19574) - Fix: The timetable button was not automatically raised [FS#3739] (r19571) - Fix: [NewGRF] Possible buffer underflow in NewGRF string code (r19569) - Fix: [NewGRF] Do not return a random colour for unowned industries in var 45; TTDPatch does not seem to set the colour data in that case either and it could lead to desyncs (r19566) - Fix: Window::OnResize() was not always called while resizing a window causing incorrect windows [FS#3730] (r19563, r19558) - Fix: Bridge build error message should not show the same message twice (r19560, r19559) - Fix: [NewGRF] During NewGRF loading, store rail type labels in temporary data and process after loading has finished. This avoids deactivated rail vehicles being reactivated if the climate property is set after the rail type property (r19557, r19502) - Fix: Improperly scaled cargo payment graph when having lots of cargo (r19550, 19543) - Fix: [NewGRF] Properties set before property 08 (house, industry, industry tiles) should be ignored, not trigger the NewGRF to be disabled [FS#3725] (r19547) - Fix: Sorting industries by production was broken for NewGRF industries (r19538) - Fix: Vehicle details window did not resize correctly after refitting a road vehicle to a longer variant [FS#3720] (r19533) - Fix: Prevent drawing industries disabled at the smallmap as land tiles when they are built on water (r19523) - Fix: Tunnels, bridges and road stops are build with only one roadtype (r19506) - Fix: Remove same_industry_close setting did not do what it said and caused NewGRF trouble (r19499) - Fix: Keep number padding intact when cloning vehicle names [FS#3710] (r19498) - Fix: [NewGRF] Bytes and words get sign-extended for temporary/persistent storage (r19497) - Fix: Stop reducing the size of the vehicle list after selecting a vehicle with a long description (r19480) - Fix: Implement custom sound effect for helicopter take-off [FS#3668] (r19364) - Update: Plural type of Slovak (r19452) 1.0.0 (2010-04-01) ------------------------------------------------------------------------ - Fix: Network clients would crash while connecting to a server with AIs (r19526) - Fix: [NPF] Crash when finding a waypoint before finding the closest depot [FS#3703] (r19460) 1.0.0-RC3 (2010-03-18) ------------------------------------------------------------------------ - Feature: Append rail type speed limit (if set) to rail type selection list, and toolbar title (r19431) - Feature: [NewGRF] Smallmap colours for railtypes (r19307) - Change: Make the drive through and cargo list consistency checks only run when 'desync' debugging is enabled (r19403, r19398) - Change: Update documentation for console command connect to use ip:port#company parameter format, in line with command line help (r19374) - Change: [NewGRF] Increase railtype cost range (r19306) - Fix: Mark industry windows dirty more often [FS#3701] (r19443) - Fix: Custom group names are misaligned with default ones when using rtl languages [FS#3700] (r19438) - Fix: With certain game settings one could clear tiles for free when building long roads (r19436) - Fix: When loading a savegame created with a house NewGRF without that NewGRF available all houses became tall office blocks (r19435) - Fix: Limit rail clearance earnings to 3/4s of rail build cost, to avoid money making loophole when rail build cost is less than rail removal earnings (r19433) - Fix: Crash when the error message 'owned by ' was shown [FS#3696] (r19432) - Fix: [NoAI] When the title game contains an AIPL block the AI settings where overwritten by those from the title game (r19429) - Fix: Gracefully handle the case where we cannot open a .tar file (r19427) - Fix: [YAPP] A train on a bridge/tunnel was not always found when checking for trains on a reserved path (r19425) - Fix: [NoAI] The AI Debug window did not open if an AI or library fails to compile when loading a savegame [FS#3669] (r19395) - Fix: One could not level the whole map anymore at once (r19392) - Fix: Only show the 'No AIs available' error message when explicitly changing the number of AI opponents [FS3676] (r19389) - Fix: [NoAI] When reloading a savegame, an AI failing to compile could trigger (trying) to read the not yet loaded information of another AI via the AI Debug window and its 'open with the most recently used AI' feature [FS#3666] (r19388) - Fix: Close all orders windows when switching companies [FS#3671] (r19387) - Fix: [IPv6] Netmask calculations were wrong if cidr >= 32 [FS#3684] (r19385) - Fix: Overbuilding bridges, rail stations did not properly update PBS reservation [FS#3680] (r19384, r19383) - Fix: [NoAI] List valuator could cause invalid iterators [FS#3665] (r19367) - Fix: Close error messages about missing ownership when the company closes or is taken over [FS#3663] (r19358, r19357) 1.0.0-RC2 (2010-03-04) ------------------------------------------------------------------------ - Feature: [YAPF] Consider the railtype imposed speed limit for pathfinding (r19301) - Feature: BaNaNaS support for music sets (r19262) - Feature: [NewGRF] Add 2 bits of pseudo-random data for rail types, based on tile location (r19235) - Feature: [Windows] Add OpenMSX to the installer (r19220, r19219) - Feature: [NewGRF] Add CB36 support for aircraft properties 0F and 11 (r19218) - Feature: Scroll to current order destination when ctrl+clicking the start/stop bar (r19216, r19215) - Feature: Concept of fallback base sets, i.e. do not automatically load the NoMusic/NoSound sets when there is another set; make NoSound part of base installations (r19214, r19213, r19212, r19211, r19206) - Feature: Support for genders for cargoes, industries, vehicles, stations (r19180, r19179, r19178, r19177) - Change: Increase the default small font size for freetype fonts as 6 point fonts are usually unreadable [FS#3655] (r19308) - Change: [NewGRF] Railtype cost factor from byte to word value (r19306) - Change: Improve error message with track building when signals are in the way (r19190, r19189) - Change: Do not print the absolute path to AI script files in the AI debug window, use the relative path from /ai/ instead (r19166) - Change: The Debian packaging; bring it in sync with the packaging used at Debian excluding package splitting (r19162) - Fix: [Windows] Disable sound when a sound error happens instead of crashing [FS#3652] (r19304) - Fix: [NewGRF] Return the TTD airport type in station var 0xF1 (r19299) - Fix: [NewGRF] Segfault when station vars 0xF2/0xF3 is accessed when there is no truck/bus stop (r19298) - Fix: [NoAI] Some methods of AIAbstractList left invalid iterators [FS#3566] (r19293) - Fix: [YAPP] If reversing at path signals was disabled, a train would not reverse when hitting the back of an one-way signal (r19286) - Fix: [NewGRF] Ensure prices cannot be set to zero. Zero prices break a lot of the internal logic to determine whether something has been done [FS#3646] (r19277) - Fix: 'Cannot build here... in the way' showed the to-be-built industry twice, instead of the to-be-built industry and the industry that is in the way [FS#3618] (r19265) - Fix: Writing (console) output to a file failed on Windows if the date would not be logged [FS#3639] (r19252) - Fix: [NewGRF] Some GRF error messages did not free the previous error messages, creating a memory leak (r19251) - Fix: With RTL languages clicking a horizontal scrollbar that could not scroll could cause a crash [FS#3643] (r19250) - Fix: Start and end tiles were swapped in CMD_REMOVE_LONG_ROAD causing too much road to be removed [FS#3642] (r19249) - Fix: DOS 'port' did not compile anymore (r19248) - Fix: The -M command line option did not work (r19233) - Fix: GetDestination() is invalid for nearest-depot orders (r19210) - Fix: Compilation was broken for gcc 3.3 (r19207) - Fix: The vehicle info in the autoreplace gui was drawn even when the window was shaded [FS#3634] (r19187) - Fix: When selecting 'build many industries' in the scenario editor the 'build' button was not enabled [FS#3632] (r19176) - Fix: Buoys are no Stations, only BaseStations (r19174) - Fix: Under some circumstances timidity (via extmidi) would not shut down properly causing all kinds of trouble (e.g. blocked audio output). Try harder to shut down timidity and first shut down the music so shut down order is the inverse of initialisation order (r19168) - Fix: Industry 0 could be chosen even if not available [FS#3631] (r19167) - Fix: Vehicle running costs should not be changed in a running game [FS#3629] (r19165) 1.0.0-RC1 (2010-02-18) ------------------------------------------------------------------------ - Feature: Allow to select different land colours for the smallmap (r19064) - Feature: [NewGRF] Action 3/2/1 (i.e. new graphics) support for rail types (r19056) - Feature: Add zoom-out to smallmap (r19039) - Add: [NoAI] AIOrder::[G|S]etStopLocation to get/set the stop location of trains in a rail station (r19014) - Change: Move home directory to a better place in Haiku [FS#3625] (r19151) - Change: Do not load the 'new game' NewGRFs when you are certain the savegame would not have been saved with them, i.e. do not load the 'new game' NewGRFs for TTO savegames (r19044) - Fix: Invisible depots draw the track, so also draw the overlays (r19154) - Fix: [v]seprintf should return the number of added characters excluding '\0' on truncation [FS#3627] (r19149, r19148) - Fix: [YAPF] Look-ahead for multitile waypoints 'made up' data that should not go into the cache, causing desyncs in MP [FS#3619] (r19141) - Fix: Report a more useful error when failing to build a bubble generator (r19137) - Fix: Resize station cargo widget when needed to display all accepted cargo types [FS#3617] (r19123) - Fix: [NewGRF] Industry property 0x17 was interpreted incorrectly and in some cases circumvented the density difficulty setting (r19120) - Fix: Removing towns (in the scenario editor) that had stations/depots refer to them or vehicles were on the town's road could cause a crash [FS#3616] (r19119) - Fix: In the order window the Non-stop dropdown was not enabled for depot and waypoint orders and some buttons were raised too soon [FS#3593] (r19118, r19117) - Fix: Do not crash on broken lng file and prevent it from happening again [FS#3611] (r19113, r19112) - Fix: Not all news data was properly freed when starting a new game [FS#3614] (r19105) - Fix: The BeMidi driver was broken [FS#3610] (r19097) - Fix: Crash when one of the items in the news_display group in the config file has no value (r19096) - Fix: Crash when a base set has an empty metadata field (r19095) - Fix: Possible read/write after free when the client triggered the server to close the connection [FS#3599] (r19072) - Fix: Remove Bidi control characters from the reordered text so they are not drawn [FS#3604] (r19067) - Fix: [NewGRF] Settings that are part of the 'TTDPatch flags' can cause desyncs if they are changed in network games (r19066) - Fix: When banning yourself via rcon do not send the 'command response' to the client as the connection has already been terminated [FS#3598] (r19054) - Fix: Mass stopping/starting/autoreplacing gave empty errors when there were no vehicles [FS#3577] (r19024) - Fix: City airport introduction date had become 5 years later (r19023) - Fix: Loading old (0.1-ish) savegames failed (r19022) - Fix: Do not NULL the pointers when saving the savegame on an error during saving; the savegame is still valid, so do not make it invalid [FS#3570] (r19021) - Fix: When removing roads, the player was also charged for removing the foundations [FS#3591] (r19016) 1.0.0-beta4 (2010-02-04) ------------------------------------------------------------------------ - Feature: Content mirroring support (r18994) - Feature: Show empty query after creating new group (instead of 'Group nnn') (r18981) - Feature: [NewGRF] NewGRF-settable rail type properties, increase number of possible rail types, per rail type speed limits (r18970, r18969) - Feature: [NewGRF] Allow layering of multiple groundsprites in spritelayouts of stations, houses and industrytiles; so hacks with zero-sized bounding boxes are no longer needed and no longer cause trouble (r18959) - Feature: [NoAI] Introduce GetBuildCost functions in several classes to get easier cost estimations before you start building (r18955) - Feature: [NoAI] Allow editing AI settings while an AI is running (r18953) - Feature: Make it possible to change newgame settings from within a game via the console (use setting_newgame instead of setting) [FS#2885] (r18943) - Feature: Add a setting to reduce/disable aircraft crashes [FS#2678] (r18942) - Feature: Make the crash position of aircraft a bit random by giving aircraft a chance to crash every tick they are breaking (r18940) - Change: [NoAI] Use the highest version of an AI that can load the AI data from a savegame instead of the exact same version [FS#3232] (r18944) - Fix: Off-by-one in the music playlist (song missing) [FS#3588] (r18997) - Fix: [NewGRF] industry var A5 (=high 8 bits of var A4) returned the high 8 bits of var A2. Same problem for 9B/9A/98 (r18988) - Fix: [NoAI] Make building long rails fail for AIs if there is an obstacle in the way (r18987) - Fix: Possible invalid memory access when merging companies [FS#3584] (r18978) - Fix: Estimating the cost of removing statues could clear the presence flag in the town (r18976) - Fix: CMD_BUILD_ROAD missed CMD_AUTO. Also do not access tiles anymore after clearing them; that fails either in test or exec run [FS#3578] (r18974) - Fix: Train acceleration for original acceleration model was not updated if the train's power changed (r18971) - Fix: Make sure the values of settings loaded from a savegame are valid (r18950) - Fix: After clicking move up/move down in the NewGRF/AI the selected item could be out of range [FS#1510] (r18948, r18947) - Fix: It was possible to change AI settings without changing to the custom difficulty level by using the query text window (r18946) - Fix: Remove the loading indicators as soon as a train crashes [FS#3575] (r18941) - Fix: [NewGRF] Industrylayout's special water tile check did not properly check for crossing north border of map (r18938) - Fix: [NewGRF] Value of variables 90 and 91 were not what NARS expects [FS#3551] (r18935) - Fix: [Windows] In some rare case a deadlock could happen when stopping sound driver (r18934, r18913, r18892) - Fix: [NoAI] Autoreplace is also valid for the default group (r18930) - Fix: Preserve some timetable related vehicle flags during autorenew/-replace [FS#3568] (r18929) - Fix: AIOrder::GetOrderDestination could return a non-waypoint tile when the waypoint was a multitile waypoint [NoAI] (r18924) - Fix: On bankruptcy the company value did include the loan and as such the value at which you bought the company was too low [FS#3561] (r18908) - Fix: Writing LZO-compressed savegames would produce invalid files and potentially overwrite memory (r18904) - Fix: [Windows] File locations for Windows were not documented correctly for all versions of Windows [FS#3562] (r18903) - Fix: Pressing cancel for the query windows of the world generation window caused the default to be set instead of no changes to the value [FS#3558] (r18896) - Fix: Avoid duplicate path separator when searching for PNG files which prevented tar-lookups (r18891) - Fix: [NewGRF] Perform bounds checking for all NewGRF data reads. Explicit length checks (which were not always correct) are no longer needed so these are removed to simplify code (r18884) - Fix: Aircraft can be send to an hangar when the target airport has one and when it can land, not only when it has a plane terminal (r18880) - Fix: [NewGRF] Crash when a NewGRF used var62 in an industry tile chain when the industry tile was part of an original industry (r18878) 1.0.0-beta3 (2010-01-21) ------------------------------------------------------------------------ - Feature: Make building (long) roads work like building rail; build upon the first obstruction instead of failing totally [FS#3318] (r18803) - Feature: Allow user customisable compression levels for the zlib compression (r18772) - Feature: [NoAI] Rerandomise AIs on reloading (via the debug window) when they were randomly chosen [FS#3095] (r18763) - Feature: [NewGRF] Implement VarAction2Houses variables 66 and 67 (r18736) - Change: [SDL/Allegro] Make the number of samples/frequency runtime configurable (r18821, r18820) - Change: Be consistent with airport naming [FS#3493] (r18819) - Change: [NewGRF] Consider callback 19 only broken after subcargoes 0 to 255 have been used, instead of stopping at 15 (r18774) - Change: Replace MiniLZO with the real library (r18769) - Fix: Town noise population settings could not be changed in-game [FS#3532] (r18864) - Fix: Do not pass AI strings through iconv [FS#3544] (r18862) - Fix: Do not do screen redraw when the landscape contains broken slopes [FS#3540] (r18850) - Fix: Default-waypoint was drawn incorrectly for monorail and maglev in the waypoint picker (r18841) - Fix: In some cases error messages were not properly sent to the client before closing the connection. As a result the client would say 'connection lost' when the cause was something completely different (r18801) - Fix: In some cases with invalid packets one can crash OpenTTD (r18800) - Fix: [SDL] Possible deadlock when killing OpenTTD while starting it [FS#3521] (r18796) - Fix: When copying an 'image' back into the buffer the 32bpp anim blitter triggered palette check of the whole window instead of only the part the got copied back [FS#3504] (r18791) - Fix: Viewport could jump under high CPU load [FS#3515] (r18790) - Fix: Crash when getting the tooltip of the industry amount in the world generation window [FS#3516] (r18787) - Fix: [NoAI] NoAI's custom implementation of DoCommandP has several flaws (not masking of bits, not resetting town authority updates on checks/estimates, ...). Let it use DoCommandPInternal, DoCommandP without showing error messages and such, instead [FS#3507] (r18786) - Fix: [NoAI] AIs did update their last cost incorrectly in network games if the cost of the DC_EXEC phase differed from the ~DC_EXEC phase (r18781) - Fix: [YAPP] Remove a special check for two-sided signals when reserving a path as this causes trains to get stuck in front of them [FS#3483] (r18778) - Fix: Assertions because the unloading and signal wait counter got into each others way [FS#3422] (r18764) - Fix: [NewGRF] Spritelayouts do not need an Action 1 if only using default sprites [FS#3497] (r18761) - Fix: [NewGRF] Action 9 did not properly detect whether an Action 8 was encountered already [FS#3500] (r18760) - Fix: [NewGRF] Do not segfault when a NewGRF contains an Action 2 and Action 3 but no Action 0 (r18759) - Fix: [NewGRF] CircularTileSearch skipped a few tiles close to the starting tile, as a result some NewGRF houses could be placed too close together [FS#3495] (r18755) - Fix: The cargo payment button states were not properly set on opening the window [FS#3492] (r18750) - Fix: [NoAI] The AI's name and version in the debug panel was not properly centred [FS#3491] (r18749) - Fix: Clear the cached NewGRFs of a server when receiving a reply instead of when requesting the information. With slow/unstable network connections it would look like the NewGRF settings button went randomly missing [FS#3489] (r18746) - Fix: Do not toggle the sticky- and shading-button twice per mouseclick when clicking fast [FS#3487] (r18744) - Fix: [NewGRF] House prop 1D was trashed when a NewGRF contains prop 14 after prop 1D (r18742) - Fix: Building trees on snow with rocks underneath caused an assert [FS#3501] (r18739) - Fix: When a tree died while there was snow the amount of snow on the tile changed (r18738) - Fix: [NewGRF] VarAction2Station variable 67 was not swapped properly for orientation (r18737) 1.0.0-beta2 (2010-01-05) ------------------------------------------------------------------------ - Feature: Do not delete the rough/rocky status of a tile when it is covered by snow, this allows rocky tiles under snow if you have a variable snowline (r18719) - Feature: [NewGRF] Add support for custom station foundation graphics (r18708) - Feature: Allow virtually paying a percentage of the leg profit in feeder chains. This to give the user a better chance to get a feeder system without 'losses' (r18703) - Feature: Configurable slope steepness for trains from 0% to 10%, default is 3% as before [FS#3459] (r18674) - Feature: Allow contour-map to be shown with coloured industries in smallmap [FS#567] (r18665) - Add: [NoAI] AIEngine::IsBuildable to check if you can build a certain engine (r18687) - Change: [NoAI] Merge buoy and waypoint functions (r18725) - Change: [NoAI] AIEngine::IsValidEngine will now also return true when you have at least one vehicle of that type even if you cannot build it anymore (r18687) - Change: Update Squirrel from 2.2.3 to 2.2.4 (r18639) - Fix: New viewports did not centre on the correct position [FS#3414] (r18730) - Fix: The lock in the company window was only drawn for your own company [FS#3427] (r18729) - Fix: Some invalid gender/plural indices in strings, which could eventually cause crashes [FS#3480] (r18727) - Fix: With non-uniform industries the 'supplies' text when building a station could be incorrect (missing a cargo) [FS#3463] (r18726) - Fix: Refitting a non-refittable vehicle to its default cargotype failed, causing problems for AIs [FS#3475] (r18724) - Fix: The join station window did not account for scrolling, so if you did scroll the station was not joined with the selected station [FS#3476] (r18713) - Fix: The wrong town is mentioned in the error when trying to make one way roads of town owned roads [FS#3478] (r18710) - Fix: Animation buffer for 32bpp-anim blitter was only validated during sprite blitting, other drawing operations did not check it. Initial startup and window resize could therefore lead to crash [FS#3464] (r18709) - Fix: Enable DrawGroundSpriteAt() to deal with foundations as DrawGroundSprite() does, and use this for drawing one-way-road-signs and clear-land-fences [FS#3467] (r18702) - Fix: When deleting an industry on water (oil rigs) the tiles on water were not marked dirty (r18700) - Fix: [NewGRF] GRF parameters were not properly initialised to zero, and not always checked for valid range (r18699) - Fix: Crash when scrolling to an item removed by filtering in the 'add NewGRF window' [FS#3471] (r18697) - Fix: [NoAI] AITile::IsCoastTile returned false for coast tiles with trees on them [FS#3404] (r18696) - Fix: After a company went bankrupt it was impossible to build a new waypoint close to a deleted one until the grey sign was gone (r18692) - Fix: Some keys that open windows that want to be located relatively to the toolbars/statusbar could cause a crash when in one of the end game screens [FS#3469] (r18690) - Fix: In some cases _sl.chs is used when not initialised. As _sl.chs always refers to a single table when initialised replace _sl.chs with the actual table [FS#3470] (r18686) - Fix: [NewGRF] Tile area of waypoints was not correctly given to NewGRFs in case of multi tile waypoints (r18679) - Fix: [NewGRF] If an action B did not have a 'data' string but would print it OpenTTD would segfault [FS#3452] (r18671) - Fix: Update all tiles when snowline height changes in larger steps than one tile [FS#3455] (r18670) - Fix: [NoAI] Crash when trying to get the order destination of a 'nearest depot' order [FS#3454] (r18667) - Fix: Aircraft on the metropolitan airport took a long route to the closest loading pad [FS#3169] (r18661) - Fix: [NewGRF] Wrong strings drawn for cargo subtype in vehicle details [FS#3443] (r18658) - Fix: When trying to attach a wagon to an existing free wagon chain, do not attach it to itself [FS#3442] (r18653) - Fix: [NoAI] When AI tried to create NO_UNLOAD order, GOTO_NEAREST_DEPOT order was created instead [FS#3438] (r18651) - Fix: [YAPP] Treat the backside of an one-way path signals as a safe waiting point [FS#3430] (r18648) - Fix: [YAPP] A train inside a station was not always found when checking for trains on a reserved path (r18647) - Fix: [YAPP] Do not extend the reserved path through a newly built path signal directly in front of a stopped or loading train. Also restore the reserved path in more cases after removing a signal [FS#3418] (r18646) - Fix: Company league window was too narrow [FS#3434] (r18644) - Fix: Rotation could not be changed for heightmaps [FS#3436] (r18643) - Fix: When a company goes bankrupt and has vehicles on a drive through road stop that is not theirs, the 'filled' cache of the road stops would get corrupted [FS#3432] (r18642) - Fix: Downloading music sets would fail (r18638) - Fix: Crash when invalid pointers are left due to saveload failing at e.g. decompressing the savegame [FS#3421] (r18634) - Fix: When making a screenshot the name of the previous screenshot went missing in the 'successful screenshot' message and the console command would be shown twice [FS#3419] (r18631, r18630) - Fix: (un)loading counter being reset while loading a train and changing the (path) signal setup around the station [FS#3422] (r18628) - Fix: {CARGO} takes 2 parameters, not 1. This made {N:XYZ} commands after CARGO mess up their indices and that then triggered an assertion [FS#3425] (r18626) 1.0.0-beta1 (2009-12-24) ------------------------------------------------------------------------ - Feature: Music replacement sets, like graphics and sound replacement sets (r18608) - Feature: Add shading and unshading of windows [FS#2943] (r18588) - Feature: Initially select the last joined server when going to the server list [FS#3311] (r18578) - Feature: Additional map variety option for TGP landscape generator (r18541) - Feature: Add the possibility to not make new tree tiles in-game (r18522) - Feature: Moving of AIs in the AI configuration window [FS#3359] (r18516) - Feature: Make maximum pathfinder penalties for finding depots customisable, also increase it slightly to 20 tiles worth of penalties (r18481) - Feature: [Strgen] Allow G and P to 'select' substrings of STRINGn for getting their gender (r18444) - Feature: Make penalty for road stop occupancy user configurable (r18404) - Feature: Fully scalable, by font size and content, GUI and improved right-to-left language support [FS#1905] (r15800-r18350) - Feature: Set the start time of a timetable (r18294) - Feature: Show the expected arrival/departure dates in the timetable window (r18285) - Feature: [NewGRF] Add new price bases for removing industries, building/removing unmovables (new objects), building/removing rail-waypoints/buoys, interacting with town-authority, building foundations, funding primary industries (when not prospecting) and towns (r18283) - Feature: Founding towns in-game (r18281) - Feature: [NewGRF] Make price base multipliers related to vehicles only apply to the GRF locally, if it defines engines of that type itself (r18268) - Feature: [NewGRF] CB 36 for roadvehicle property 09 'running cost factor' (r18011) - Feature: Non-automatic screenshot name can be entered in console (r17938) - Feature: Make it possible to disable background saving, only via the config file/in game console though [FS#2633] (r17893) - Feature: Automatically select the railtype with the most engines for the autoreplace window/try to avoid showing an empty autoreplace list [FS#1760] (r17892) - Feature: Show maximum tractive effort in the 'exclusive test'/'early offer'/'engine preview' window [FS#1619] (r17891) - Feature: Double clicking on a NewGRF opens the parameters window (r17890) - Feature: Double click on a item in the refit list refits without the need to click on the refit button (r17889) - Feature: [NewGRF] Textstack support for CB 37 [FS#1862] (r17802) - Feature: [OSX] Implement automatic fallback font selection for OSX (r17794) - Feature: Translatable base sound/graphics set descriptions (r17790) - Feature: Show the nickname of the person you are PMing [FS#3116] (r17741) - Feature: [OSX] Add a MIDI driver using Cocoa/CoreAudio [FS#3223] (r17710) - Feature: [OSX] Implement clipboard support for OS X [FS#2053] (r17708) - Feature: Possibility to choose (randomise or enter custom) town name before its creation (r17612) - Feature: [NewGRF] Callbacks for houses to disable drawing foundations and to disable slope changes, like industry tile callbacks 30 and 3C (r17558) - Feature: [NewGRF] Implement callback 145 (custom station rating) (r17547) - Feature: Filtering in Add-NewGRF dialogue (r17541) - Feature: Add the date to all logging in the (real, not in-game) console if show_date_in_console is set. For dedicated server binaries the default is 'on', for the rest it is 'off' [FS#2339] (r17488) - Feature: Reconnect console command (r17466) - Feature: Allow building rail stations over existing rail without signals but will upgrade normal rail to electrified rail if necessary (r17460) - Feature: Crash logger for all Unixy OSes in a similar way as the Windows crash logger (r17453) - Feature: Open the 'Rename group' dialogue after creating new group (r17281) - Feature: [NoAI] Older API compatibility wrappers, so one can get the 0.7 API in later versions while keeping the real API clean (r17214) - Feature: The Windows installer can now optionally download OpenGFX and OpenSFX (r17191) - Feature: Sort vehicle lists on (timetable) delay [FS#2945] (r17182) - Feature: Localised decimal separator (r17157) - Feature: Improved the sample rate conversion a bit (r17146) - Feature: Allow higher sample rate and higher quality samples (r17140) - Feature: Sound replacement sets, like graphics replacement sets (r17139) - Feature: Multi tile waypoints (r17002, r17000, r16993) - Feature: [NewGRF] Turn variable 0E/8E (vertical offset for trains in depot) and variable 1E/9E bit 3 (wagon width in depot) into grf-local variables (r16867) - Feature: Highlight whole articulated vehicles in traindepot instead of only the first part (r16818) - Feature: Ability to enter server and company password via command line when joining a server [FS#570] (r16555) - Feature: Give the town generator a slight tendency to build towns near water by not discarding watery random tiles but by searching for near land [FS#2635] (r16147) - Feature: Configurable digit group separator per language with user override (r16129) - Feature: Make the first 4 rail building tools behave more like autorail (r16095) - Feature: Allow sorting stations by the lowest cargo rating instead of only by the highest cargo rating [FS#597] (r16045) - Feature: Allow filtering of vehicle purchase lists by cargo [FS#1941] (r16042) - Feature: Allow (per order) to let a train stop at the near end, middle or far end of a platform from the point of view of the driver of the train that enters the station (r16037) - Feature: Listen on multiple IPs/sockets and register all IPs to the master server (r16014, r15975, r15973, r15971) - Feature: Full IPv6 support (r16000) - Feature: Allow train vehicles to be shorten to 1/8 length, even if not at the end of the train (r15793) - Add: [NoAI] AIOrder::AIOF_GOTO_NEAREST_DEPOT for goto nearest depot orders (r18518) - Add: [NoAI] Enable the squirrel standard math library (r17498) - Add: [NoAI] A vehicle list for all vehicle that are ordered to a specific depot (r17486) - Add: [NoAI] AISubsidy::SubsidyParticipantType, AISubsidy::GetSourceType, AISubsidy::GetSourceIndex, AISubsidy::GetDestinationType, AISubsidy::GetDestinationIndex for better subsidy management (r17115) - Change: Forbid industries to clear sea/river when levelling land (r18554) - Change: Make it visible when you are to pass the next signal on danger and possible to cancel it (r18515) - Change: Move the 'check online content' button from the AI list window to the AI configuration window. This makes it consistent with the NewGRF windows [FS#3340] (r18507) - Change: Use zł instead of zl for the Polish Zloty [FS#565] (r18434) - Change: Show different texts in town GUI when the town does not need food the whole year to grow (r18433) - Change: Make road vehicles behave more like trains 'around' stations and use pathfinder penalties to determine to which 'part' to go (r18382) - Change: Do not split up articulated vehicles in the train details view. If an articulated vehicle it too 'wide' draw the information on the next line and if there are multiple cargoes split that over multiple lines too [FS#2923] (r18344) - Change: Make pause on join pause during the whole joining (including download) phase [FS#3287] (r18054) - Change: Prefer extmidi over allegro midi and allegro over null driver [FS#3272] (r17875) - Change: Several improvements to the performance of CargoPackets/CargoLists; time spent in those functions reduces by 55-85% (r17840, r17836, r17818, r17814, r17812, r17801, r17736, r17735, r17733, r17731, r17730) - Change: [SDL] Make 'update the video card'-process asynchronous. Improvements of 2%-25% (real time) during fast forward on dual core/hyperthreading-enabled CPUs (r17776) - Change: [NoAI] Make AIEngine:CanRefitCargo() not report refittability to Mail by default for aircraft. It is not necessarily true, and the special case of carrying both passenger&mail is better handled by AIs themself than by the API (r17719) - Change: [OSX] Do not use deprecated methods/undocumented functions [FS#1411] (r17712, r17711) - Change: Make SDL's video driver more likely to be loaded than Allegro's video driver; SDL seems to perform better (r17583) - Change: Do not assume that there is always 'another' industry tile after two '0x18' industry tiles (r17521) - Change: Make the performance ratings harder to exploit; only count profitable vehicles and recently serviced stations [FS2459] (r17485) - Change: When removing a station or waypoint keep the rail unless Ctrl is pressed. This makes the behaviour consistent between the two (r17471) - Change: Show the client id in join messages at the server (r17467) - Change: NewGRF price modifiers now take effect every time when loading NewGRFs instead of once on gamestart (r17433) - Change: Make a distinction between missing and corrupted data files. If (at least) one data file is missing do not consider the set to be usable. Do also no autodetect sets with missing files (r17241) - Change: Update MiniLZO to 2.0.3 (r17215) - Change: Update Squirrel to 2.2.3 (r17195) - Change: Remove UNICODE notice in windows installer (r17186) - Change: Apply the subsidy when subsidy's destination is in station's catchment area and cargo packets originate from subsidy's source [FS#265,FS#2094,FS#2589] (r17113) - Change: Subsidies are not bound to stations after awarding anymore, they still apply to town or industry, no matter what station is used for loading and unloading. Awarded subsidies from older savegames are lost [FS#1134] (r17113) - Change: [NoAI] Add AIBaseStation as a parentclass for AIStation and AIWaypoint, and move GetName, SetName and GetLocation to AIBaseStation (r17011) - Fix: Conditional orders were seen as 'valid' and as such aircraft with only conditional orders did not crash (r18615) - Fix: Pressing default for the starting year/snow line height edit boxes of the world generation windows did not work [FS#3398] (r18586) - Fix: [OSX] Try to get a generic RGB colour space if getting the system colour profile failed [FS#3198] (r18573) - Fix: [NewGRF] House property 15 did not work [FS#2613] (r18567) - Fix: Do not try to overtake a vehicle in a road station as overtaking in a station is not allowed [FS#3390] (r18561) - Fix: Make aircraft behave the same on autoreplace/autorenew as other vehicle types (r18553) - Fix: First do the time-since-last-service check and only then determine whether autoreplace needs to take place. This way they will not keep autoreplacing continuously on failure, but only after some timeout. Also check some minimal requirements (engine availability, refittability) and a heuristic for the needed money when sending vehicles for autoreplace [FS#1762] (r18551, r18549) - Fix: Do not account for path reservation costs when entering a signal block via a 'block' signal. This way you will not get double penalties, both red signals and reservation costs, for the block signalled tracks [FS#2722] (r18535) - Fix: [NewGRF] An industry NewGRF that defined a too small size for action0 prop 0A could cause a crash (r18527) - Fix: Allegro does not like to work with extmidi, so warn the user about that [FS#3272] (r18520) - Fix: When you pass a signal at danger, in a PBS controlled area, do not try to do the 'safe' thing and stop, but continue going; the user wanted the train to pass the signal at danger so (s)he has to suffer the consequences. Of course one can always stop the train manually [FS#2891] (r18515) - Fix: No error message was created for the first fatal NewGRF error [FS#3368] (r18506) - Fix: Improve airport movement on several airports [FS#3169] (r18505) - Fix: Autoreplace and autorenew always reset their cargo sub type to 0. Now find a sub cargo type with the exact same name and use that, otherwise fallback to 0. So cargo sub types can be maintained via autoreplace *if* the new vehicle supports the same cargo sub type [FS#3159] (r18499) - Fix: Cloning of vehicles could create vehicles with invalid cargo sub types for the build year of the vehicle. Fall back to another cargo sub type with the exact same name, otherwise fallback to cargo sub type 0 [FS#2616] (r18498) - Fix: [NewGRF] Direction is accounted for long before motion counter is updated (r18479) - Fix: Moving vehicles around/selling vehicle in the train depot could create states that are not allowed by the NewGRF attach callback [FS#3146] (r18472, r18470) - Fix: Unselect an AI in the AI Settings window when it falls out of the range of active AIs [FS#3357] (r18436) - Fix: Road vehicles would not pick an empty drive through stop. Now they will *if* the penalty for driving around is less than the occupancy penalty [FS#1944] (r18404) - Fix: Long (articulated) road vehicles could block loading of others when the following road vehicle already got 'permission' to go to the next bay even when it could not reach it [FS#1495] (r18404) - Fix: The tree 'which one to draw' hash was not anywhere near random and thus showed a very visible repeated pattern when only one tree type was used [FS#3343] (r18398) - Fix: [NoAI] Make AIIndustryType::GetConstructionCost() return -1, if the industry is neither buildable nor prospectable (r18276) - Fix: Use free type ascender/descender metrics to position font offset correctly (r18096) - Fix: Make the 'pause' chat message when actually executing the pause command. This to prevent showing paused and especially unpaused to be shown when the state does not change. Output now mentions whether pause changes keep the game paused and what reasons for pausing there 'currently' are (r18052) - Fix: [NoAI] Improve behaviour of (AIEngine|AIEventEnginePreview)::GetCargoType() and AIEngine::CanRefitCargo() wrt. articulated vehicles (r17898) - Fix: [NewGRF] CB15 and CB36 (capacity) were not always called when they should [FS#3255] (r17897) - Fix: Invalidate cache of vehicle vars 40-43 after testruns of certain commands, that change them temporarily (r17894) - Fix: [OSX] The splash image was not displayed if the Quartz video driver was used (r17793) - Fix: Do not let aircraft drive a while over the grass when landing at high altitude airports [FS#3259] (r17762 - Fix: Make the -c location relative to the current directory instead of the directory of the binary [FS#3247] (r17686) - Fix: Some semaphore signals fell outside of the signal GUI. Now the signals are properly centred which should make that problem go away [FS#3242] (r17657) - Fix: Some inconsistencies with the difficulty settings in the scenario editor. Also re-enable changing some difficulty settings (e.g. max loan) in the scenario editor [FS#3219] (r17644) - Fix: Do not accept cargo produced in the same industry; generalise and improve the check used only for valuables (r17437) - Fix: Pay only for cargo actually delivered, not for all cargo unloaded at station; can differ with 'stockpiling' industries (r17436) - Fix: Improve movement of aircraft; do not make turns bigger than 45 degrees while in flight, do not move while turning on the ground (r17415, r17405) - Fix: Crash in order GUI when changing some orders with both the mouse and keyboard at the exact same time [FS#2859] (r17384) - Fix: Trains would not show smoke if the load/unload counter was not 0, though there does not seem to be a reason to check that variable anyhow anymore [FS#3162] (r17352) - Fix: One was not offered to take over bankrupt companies anymore; caused by the introduction NoAI, although NewAI had the same problem too [FS#2769] (r17345) - Fix: Minor improvements of the airport state machines (r17338, r17337, r17334) - Fix: Road vehicles forgetting their servicing order when the path takes them away (in bird distance) from their destination first [FS#3057] (r17333) - Fix: Mention of Ctrl modifier was missing from some tooltips [FS#3120] (r17300, r17297) - Fix: Keep vehicle news and viewports following vehicles, when autoreplacing/renewing them [FS#3048] (r17147) - Fix: Inconsistency between signs of stations and waypoints [FS#3081] (r17040) - Fix: NewGRF stations would be triggering assertions for waypoints all over the place when using the more advanced station types [FS#2996] (r16909) - Fix: Skipping a 'nearest depot order' because none could be found could cause multiple orders to get skipped [FS#2925] (r16457) - Fix: Makedepend cannot handle the amount of files we have and it also miss some dependencies. So use our custom implementation of makedepend (r16307) - Fix: Autopause and manual pausing conflict with each other, new game + pause on new game + autopause make the game not unpause on the first join [FS#2864] (r16242) - Remove: [NoAI] AIVehicle::SkipToVehicleOrder as it was a duplicate of AIOrder.SkipToOrder (r18504) - Remove: OPF for RVs and NTP for trains; both the oldest path finders (r18362) - Remove: Support for gcc2. It has not been able to compile OpenTTD for months. All attempts to do another workaround failed (r16492) 0.7.5 (2009-12-23) ------------------------------------------------------------------------ (None) 0.7.5-RC1 (2009-12-14) ------------------------------------------------------------------------ - Add: Some missing latin-ish characters from the OpenGFX set (r18431) - Change: Recolour the bubble generator just like any other industry [FS#3349] (r18409) - Fix: Read after free in case no network connection could be made with the content server (r18493) - Fix: [NewGRF] Initialisation of cargo payment was broken for NewGRF cargoes [FS#3344] (r18475) - Fix: [NoAI] AIOrder::SkipToOrder did not properly resolve ORDER_CURRENT (r18471) - Fix: When moving a wagon and only the last part of a dual headed engine you could split the dual headed engine over two vehicles. This could be used to crash servers [CVE-2009-4007] (r18462) - Fix: [Windows] Forgot to load the symbol from SDL.dll (r18439) - Fix: Do not run the 'jam protection' for vehicles in a depot [FS#3360] (r18428) - Fix: [Windows] The help window would be too large in some cases [FS#3327] (r18424) - Fix: Under some circumstances a pointer could be left untouched and then freed. Make sure this does not happen by ensuring it starts out as NULL instead of 'garbage' [FS#3298] (r18418) - Fix: On slopes the original and better road layouts did not check their minimum distance requirements [FS#3332] (r18415) - Fix: Aqueducts were not influenced by the 'long bridges' setting [FS#3338] (r18407) - Fix: Drive through road stops did not get flooded (r18401) - Fix: [YAPP] Trains on bridges were not found, when searching for the origin of a reservation [FS#3345] (r18392) - Fix: (Invalid) GRFs could trigger invalid reads (r18391) - Fix: One could not share orders between buses carrying different cargoes (r18380) - Fix: Off-by-one in the preconfigured music lists [FS#3339] (r18369) 0.7.4 (2009-12-01) ------------------------------------------------------------------------ - Fix: Endianness issue with saving the zoom level [FS#3333] (r18351) - Fix: [NewGRF] When starting a new game the values of action D variable 13 were incorrect [FS#3324] (r18207) 0.7.4-RC1 (2009-11-15) ------------------------------------------------------------------------ - Change: Prefer extmidi over allegro midi and allegro over null driver [FS#3272] (r17875) - Change: [NewGRF] Apply default refitmasks only when the NewGRF did not set any of the three refittability properties (xor mask, positive classes, negative classes) (r17663) - Fix: Crash when an articulated RV is turning on a drive through road station that gets forcefully (bankrupt) removed [FS#3310] (r18049) - Fix: GCC 4.5 compiling (r18045) - Fix: AIs failed to load their data from savegames by crashing them when they tried [FS#3290] (r18038) - Fix: Screen jumped a bit for at least SDL and Allegro when right-click-dragging (r18030) - Fix: [NewGRF] Improve parsing of RIFF data. Skip unknown chunks and check chunk sizes (r17999) - Fix: When you start giving money (input window for amount), then get moved to spectators and you click 'Ok' a crash would occur (r17953) - Fix: Use 24bpp BMP format instead of 32bpp for screenshots. Saves space and is supported by more image viewers (r17943) - Fix: Close BMP file when making screenshot fails (r17941) - Fix: Deadlock when trying to create screenshot with too long name (including path) (r17936) - Fix: Crash when closing NewGRF parameter window with no NewGRF selected [FS#3291] (r17922) - Fix: 32bpp BMP screenshots were in wrong colours on big endian machines and broken when screen width was not a multiple of 4 (r17910, r17909) - Fix: Uninitialised values in some paths of loading TTO savegames [FS#3288] (r17908) - Fix: Make the plane speed setting unchangeable in network games because it can be read by NewGRFs on game load and thus if it changes cause desyncs (r17902) - Fix: [NewGRF] 'subtract-in' is also signed for production callback version 0 (r17857) - Fix: [NewGRF] _date_fract runs from 0 to 73 since r2041. Variable 0x09 should not (r17824) - Fix: Do not fail hard when no soundcard could be detected; just fall back on the null-driver [FS#3268] (r17788) - Fix: CJK languages do not have spaces, so for adding newlines (multi line strings) we need to (properly) handle the case when there are no spaces instead of truncating the string [FS#3264] (r17772) - Fix: Powernaut Helicopter got wrong 'load amount' (r17758) - Fix: [NewGRF] 'last_value' and 'reseed' are shared between procedure and main chain, 'scope' and 'count' are not (r17672) - Fix: Count only active clients (not those waiting for map download) when checking min_active_clients limit (r16506) 0.7.3 (2009-10-01) ------------------------------------------------------------------------ - Fix: [NewGRF] Crash when trying to build an industry that has no industry layout defined [FS#3233] (r17638, r17633) 0.7.3-RC2 (2009-09-24) ------------------------------------------------------------------------ - Update: Documentation about bug reporting and known bugs (r17554) - Fix: When a command did not fail in test run and failed in execution run, error message was not set. Affects only few commands (r17607) - Fix: [NewGRF] Crash when defining the same tile in a tile layout twice [FS#3218] (r17605) - Fix: Vehicle image was not always updated when needed (r17594) - Fix: [NoAI] Could not query the size of small airports when they could not be build anymore [FS#3212] (r17591) - Fix: Erroneous message about changing the difficulty level [FS#3220] (r17588) - Fix: Assertion triggered when the second vehicle in a 101+ (or 11+ if mammoth trains is disabled) vehicle free wagon chain is an engine and the first vehicle is moved to another chain [FS#3208] (r17576) - Fix: [NewGRF] Memory leak when viewing the NewGRF settings of a server (r17563) - Fix: [NewGRF] The NewGRF settings of (remote) network games did not get properly updated when the NewGRFs were rescanned causing reading of freed data [FS#2972] (r17562) - Fix: [NewGRF] Close the 'Add NewGRF' window when you close the 'NewGRF Settings' window. The add window has a pointer to the settings which means that not deleting it would cause dereferencing an already freed pointer [FS#3206] (r17559) - Fix: Vehicles waiting for their time table did not load anymore after their initial load was completed [FS#3201] (r17551) - Fix: Aircraft were given an unfair advantage in station rating calculations (r17550) - Fix: [NewGRF] Sign extending of profit calculation did not work (r17546) - Fix: [NoAI] AIs had 'infinite' time when running code from the global scope [FS#3202] (r17545) - Fix: [NoAI] Crash when doing commands in the 'global' scope [FS#3202] (r17544) 0.7.3-RC1 (2009-09-13) ------------------------------------------------------------------------ - Add: [NoAI] AITown::GetLastMonthTransportedPercentage and AIIndustry::GetLastMonthTransportedPercentage (r17294) - Add: [NoAI] AICompany::Get/Set PresidentGender (r17016) - Add: [NoAI] AIEngine::GetDesignDate (r17014) - Add: [NoAI] AIStation::GetConstructionDate (r17012) - Add: [NoAI] AIAbstractList::SORT_ASCENDING/SORT_DESCENDING (r17005) - Change: [NoAI] AITown::GetLastMonthProduction now returns the same value as AITown::GetMaxProduction (r17293) - Change: Mention the MD5 checksum of the original NewGRF in the 'saveload failed horribly'-error message and make it more clear that the filename is of the current NewGRF [FS#3139] (r17267) - Change: Make overbuilding the front tile of a road station/depot with road consistent with overbuilding the front tile of tunnels/bridges [FS#2802] (r17239) - Change: Improve error output on missing or corrupt files (r17238) - Change: [Unix] Only use colourised error output on interactive terminals (r17227) - Change: [NoAI] Crash an AI when it uses a DoCommand/Sleep instead of just printing an error message in the AI Debug Window [FS#2980] (r17223) - Change: [NoAI] When the API requests a string as parameter allow every squirrel type and convert to a string [FS#3101] (r17221) - Change: Make strgen warn if the translation uses STRINGn or RAW_STRING instead of STRING (r17137, r17129) - Change: [NoAI] Load the API before compiling an AI script so AIs can subclass API classes and use API constants as part of their own constants (r17043) - Change: Add notion of Ctrl+Click in the tooltip for Loan borrow/repay buttons [FS#3066] (r16979) - Change: [MSVC] Make all language files depend on english.txt (r16975) - Change: There is no point in not randomising engine introduction-date before 1922. Instead disable the randomisation for the first two years after game-start, so you do not have to wait for the first engine (r16929) - Fix: [Squirrel] In some cases the call stack would not be cleaned up properly during crash handling. Occasionally this causes asserts to be triggered or crashes [FS#3189] (r17515) - Fix: When loading GRFConfigs from ini file, validate them wrt. duplicate GRF IDs [FS#3197] (r17510) - Fix: When building a part fails during cloning, sell what was already cloned instead of leaving it 'for free'. Also make cloning multiheaded trains possible with with 'max - 1' vehicles existing [FS#3196] (r17509) - Fix: [NoAI] The wrong value was restored to SetAllowDoCommand possible resulting in an AI that was not allowed to do any actions (r17500) - Fix: Road vehicles could get lost when the preliminary destination (for the pathfinder heuristics) is unreachable [FS#3188] (r17491) - Fix: When building roads is not allowed for town, then do not build the initial piece either [FS#3173] (r17444) - Fix: Destruction of depots did not remove any vehicle lists related to the depot, causing windows pointing to deleted depots and (thus) crashes [FS#3180] (r17442) - Fix: Economy recession would never end when economy is set to Steady while in recession (r17426) - Fix: The index of orders loaded from old savegames was overwritten with an uninitialised value (r17419) - Fix: Incomplete check on validity of industry type when building industries (r17413) - Fix: [Squirrel] Guard against Squirrel stack overflows (r17403) - Fix: [NoAI] During every save a few slots on the Squirrel stack were leaked (r17402) - Fix: [NoAI] Several AITile::* functions did not check whether their parameters were valid (r17378) - Fix: Memory leak when trying to bankrupt the local company, other minor improvements of bankruptcy (r17342, r17341, r17340) - Fix: Not all non-ASCII characters were entered with escapes in the About window (r17309) - Fix: [NoAI] AIRail::RemoveRailTrack returned ERR_PRECONDITION_ERROR for road/rail-crossings (r17307) - Fix: [NoAI] Reloading an AI started a new AI in the first available company slot causing other AIs to be started [FS#3153] (r17298) - Fix: [NoAI] AITown::GetLastMonthTransported did not work as documented at all, make it return what AITown::GetLastMonthProduction did (r17293) - Fix: Crash after upgrading base graphics set when opening the game options menu and you were using the upgraded set [FS#3147] (r17291) - Fix: [Squirrel] Stack was not always cleared properly with tail recursion (r17284) - Fix: [Squirrel] Calling a function that has default parameters with not enough parameters can cause a crash (r17273) - Fix: Other tunnel end not shown if building rail tunnels and the first railtype is not available yet [FS#3141] (r17251) - Fix: [NoAI] AIs that crashed during Save() were not killed as they should [FS#3134] (r17231) - Fix: [NoAI] Do not assert when an AI uses AI*Mode objects incorrectly but crash the AI instead (r17230) - Fix: Remove the (deprecated since 2006) Encoding entry from the openttd.desktop file (r17226) - Fix: With time tables vehicles would stay in the 'loading' state after they have finished loading [FS#3129, FS#3130] (r17222) - Fix: Do not ignore white space changes (e.g. alignment fixes) in the exporter (r17220) - Fix: [NoAI] IsRoadTypeAvailable(GetCurrentRoadType()) was not a precondition for several AIRoad::* functions (r17203) - Fix: [NoAI] Do not say you are building a depot when you are actually building a station (API docs typo) (r17201) - Fix: Accept monthly production values in the scenario editor [FS#2406] (r17198) - Fix: [Squirrel] FPE when an AI tried to do '% 0' (r17195) - Fix: [NoAI] Guard the valuator against 'external' modifications of the valuated list which could cause it to go into an infinite loop [FS#3124] (r17193) - Fix: Do not return exit value of rm, but of the actual configure run (r17163) - Fix: A stuck train could free the reservation of another train if it was reversed or did crash (r17152) - Fix: A train entering a PBS section through a block signal could cause a train crash if another reservation ending at a safe tile was already present in the section [FS#3104] (r17151) - Fix: Update vehicle position cache when the vehicle sprite changes [FS#3060] (r17121) - Fix: Mark industry tiles dirty when trigger are triggered (r17118) - Fix: Squirrel_export.sh failed for some locales (r17109) - Fix: Make restart command work again and make the help show how it works and how it does not work [FS#3092] (r17097) - Fix: News message about ordered refits failing was not very clear [FS#3091] (r17096) - Fix: Crash when renaming some stations [FS#3082] (r17078) - Fix: RPM spec file failed for CentOS; apparently their rpmbuild is pickier or so [FS#3024] (r17077) - Fix: [NewGRF] Mark house tiles dirty when triggers were triggered (r17047) - Fix: [NewGRF] Trigger house trigger 02 only for the north tile [FS#3085] (r17046) - Fix: Graphical glitch with graph key [FS#3083] (r17041) - Fix: '[bd]ash'-ism in configure [FS#3076] (r17026) - Fix: Infinite recursion in content dependency checking [FS#3075] (r17015) - Fix: Concatenating strings in Squirrel when non-ASCII strings were received from OpenTTD failed [FS#3074] (r17013) - Fix: [NoAI] Documentation of AITile::LevelTiles was wrong (r17049) - Fix: [NoAI] AIBridge::GetPrice returned incorrect values (r16986) - Fix: Make it so that failing to generate many random towns in scenario editor returns a failing message [FS#3059] (r16977) - Fix: The last manually added server would not be saved [FS#3062] (r16981) 0.7.2 (2009-08-01) ------------------------------------------------------------------------ - Fix: Vehicles would wait 'very long' when they had nothing to unload and gradual loading was disabled [FS#3054] (r16933) 0.7.2-RC2 (2009-07-21) ------------------------------------------------------------------------ - Fix: When marking trains stuck do not reset the unload/stuck counter when the vehicle is unloading. It will be automatically reset once the vehicle wants to leave the station [FS#3038] (r16901) - Fix: [NoAI] Small errors in the API documentation [FS#3037] (r16865) - Fix: Savegames from before 0.4 would get their waypoint 'index' messed up (r16854) - Fix: Cargo payments were not destroyed when a vehicle was destructed. This only happened when you crashed a vehicle while it was unloading [FS#3032, FS#3046] (r16801) 0.7.2-RC1 (2009-07-15) ------------------------------------------------------------------------ - Add: Plural 'rule' for Korean (r16811) - Add: [NoAI] AIVehicle::GetReliability to get the current reliability of vehicles (r16790) - Fix: Call the AI Save() function only once so AIs can not crash OpenTTD [FS#3034] (r16834) - Fix: Use the palette of the vehicle being drawn instead of the one of the front vehicle (r16819) - Fix: Automatic resizing of SelectCompanyLiveryWindow was not working as expected [FS#3021] (r16809) - Fix: Service orders did not behave like conditional orders; if a train does not need service it did not completely skip the order, but still go in the direction of the depot [FS#3031] (r16802) - Fix: Houses would not get build on the map edge [FS#3025] (r16795) - Fix: Audio playback rate was fixed at 11025Hz regardless of the rate specified to the audio driver, resulting in incorrect playback speed. It is still preferable to use 11025Hz output rate if possible as OpenTTD's sample rate converter is very low quality (r16784) - Fix: Do not use the same error message for turning around road vehicles and flipping parts of trains in the depot [FS#3019] (r16772) - Fix: [Windows] The binary packages would not get their readme converted to DOS line endings (r16769) - Fix: [NoAI] AITile::GetCargoProduction/Acceptance did not accept a radius of 0 anymore (r16767) - Fix: In the refit window the 'Select cargo type to carry' line always showed the ship refit tooltip [FS#3018] (r16757) - Fix: When loading a savegame Engine::grffile might be left NULL in certain cases (dynamic_engines enabled, articulated vehicle with only wagon-override action3s) (r16737) - Fix: Show Close instead of Cancel when there is nothing to cancel in the content downloading window [FS#2991] (r16732) - Fix: [NoAI] AIDepotList contained wrong tiles for hangars when st->xy != st->airport_tile (r16731) - Fix: The Join station window did not show all stations nearby in some cases (r16728) - Fix: Invalidate subsidies with invalid source or destination when converting older savegames (r16710) - Fix: The list of animated tiles could have duplicates (only for old savegames) and tiles that were not animated [FS#2994] (r16709) - Fix: When SDL/Allegro fail to initialise, fall back on another video driver but not to the null driver (r16702, r16700, r16699) - Fix: Limit the screen's resolution to 65535x65535 so the dirty pixels stay within bounds of a 32 bits integer [FS#3001] (r16701) - Fix: Only pay for whatever has been actually unloaded and perform the payment when unloading has finished [FS#2995] (r16694) - Fix: Missing debug string for ESRB_SAFE_TILE in YAPF debugging helper [FS#3002] (r16690) - Fix: When there is no AI version that can load data from the savegame, load the latest version of the same AI instead of a random AI (r16651, r16650, r16649) - Fix: Loading of some town data from old savegames was broken (r16631) - Fix: [NewGRF] Some of the var action 2 80+ variables contained wrong results from NewGRF perspective (r16615, r16613) - Fix: Antialiased fonts broken; check pixel_mode instead of palette_mode (r16602) - Fix: Give a more meaningful error message when console commands expect an integer but do not get one (r16600) - Fix: Mouse would under some circumstances not be undrawn when drawing the first chat line causing two mouse pointers to be visible [FS#2969] (r16594) - Fix: Do not crash when tars/NewGRFs are removed, just tell the file could not be opened/found [FS#2967] (r16590) - Fix: Set default stack size to 1MB to prevent _chstk crash (MSVC) [FS#2978] (r16589, r16588) - Fix: [Network] Always send the starting date from the game you are currently playing instead the starting date from the config file (r16573) - Fix: Also catch FPEs in saveload and the warning about missing NewGRFs; only happens when assertions are disabled and NewGRFs are missing (r16572) - Fix: In some cases, train could be stuck in depot [FS#2974] (r16571) - Fix: [NoAI] AIMarine::AreWaterTilesConnected did not return true for bridge head<>neighbouring water tile (r16563) - Fix: Removing of duplicates of base graphics set could behave randomly (r16548) 0.7.1 (2009-06-09) ------------------------------------------------------------------------ - Fix: When finding duplicate graphics sets favour the more complete one (r16538) - Fix: [Squirrel] Crash that occurred when an AI was halted while one or more generators were still in a 'running' state [FS#2942] (r16534) - Fix: [Squirrel] Do not copy an object when we just checked that the pointer to it is NULL (r16532) - Fix: Notify small UFOs on deletion of road vehicles, so they can head for somewhere else instead of stumbling over a ghost (r16525) - Fix: [NoAI] StationIDs from oilrigs were not considered valid by the API (r16529) - Fix: Draw PBS reservation as groundsprite resp. childsprite of foundation/bridgehead [FS#2959] (r16528) - Fix: Missing guards in the NoAI API making it possible to hit an assert in OpenTTD [FS#2963] (r16524) - Fix: [NoAI] Possible assert in AI debug window when an AI was stopped and a human company took its CompanyID [FS#2962] (r16522) - Fix: [NoAI] Make sure AIBridge::BuildBridge returns what the documentation says it does (r16520) 0.7.1-RC3 (2009-06-03) ------------------------------------------------------------------------ - Add: [NoAI] AISignList that can be used to get a list of valid signs (r16400) - Change: [NoAI] Stop an AI when it takes too long to initialise or load [FS#2869] (r16425) - Fix: Base graphics names must be unique, so do not add duplicates (r16503) - Fix: [NoAI] When an AI was suspended while in a function called (indirectly) via call/acall/pcall OpenTTD crashed. Fix this by disallowing AIs to be suspended while called via call/acall/pcall [FS#2935] (r16502) - Fix: [NewGRF] Invalidate NewGRF variable caches of more vehicles in more places. Esp. they were only invalidated for trains (r16480) - Fix: [NewGRF] Call callbacks after initialisation of vehicle variables (r16479) - Fix: [NewGRF] Determining most common (sub-)cargo-type was broken due to someone confusing similarly named variables (r16478) - Fix: Loading indicator when 'unload' in and 'no loading' is off was pointing in the wrong direction [FS#2936] (r16477) - Fix: Track reservation was drawn at bridge heads in the menu (r16470) - Fix: [NoAI] Another try/catch related bug (r16454) - Fix: Road vehicles ending up on the pavement when they are in a drive through station that got removed due to bankruptcy [FS#2909] (r16448) - Fix: [NoAI] AIRail::GetRailStationDirection returned incorrect information (r16440) - Fix: Crash when a company is deleted while a dropdown with company names is open (r16430) - Fix: Do not allow content download via the console when there is no zlib as it is done for the GUI already [FS#2919] (r16420) - Fix: Some 64bit architectures require size_t to be aligned at 8-byte boundary, ensure it for MemBlock (r16415) - Fix: [NewGRF] Disable multitile houses with non-zero population on additional tiles as they cause desyncs and because the specs do not allow that either (r16383) - Fix: [NewGRF] Valid UTF-8 sequences between 0x20 and 0xFF should be allowed as is instead of being treated as control codes (r16374) - Fix: [NewGRF] Use a valid StringID as fall-back when undefined generic NewGRF strings of vehicles are requested (r16366) 0.7.1-RC2 (2009-05-21) ------------------------------------------------------------------------ - Fix: The previously selected NewGRF station type was still remembered after switching to a different game without newstations enabled, preventing stations from being built (r16363) - Fix: Pointer incremented with wrong count (r16361) - Fix: Delete invalid depots in TTD savegames caused by improper SVXConverter conversions (r16357) - Fix: Invalid read when OpenTTD savegame contains VEH_INVALID (r16353) - Fix: Signal handler could end in endless loop (r16351) - Fix: [NewGRF] When overriding 'original sounds', only allow overriding of the 'original sounds' and not any other that is already loaded (r16339) - Fix: Desyncs when removing lots of stations/towns (r16329, r16328) - Fix: Desyncs due to the fact that depot searching with a maximum search depth simply does not work with YAPF's caches [FS#2900] (r16323) - Fix: Trains could get stuck in a depot when they wanted to go to the same depot again [FS#2873] (r16322) - Fix: In the scenario editor change the (starting) game year of the scenario, not the (starting) game year for new games/scenarios (r16321) - Fix: Loading of savegames created in revision between 0.3.5 and 0.3.6 caused crash (r16320) - Fix: [NoAI] Set the autorenew settings for new AI companies to the default values, not to 0 or the local settings (r16316) - Fix: [NewGRF] Allow accessing the house age when the house is not yet built (r16314) - Fix: (Get|Set)TrackBits() is only valid for RAIL_TILE_NORMAL and _SIGNALS (r16311) - Fix: Parameter is invalid when it is equal to length of an array (r16308) - Fix: Close all windows before unloading the AI system as closing the content-download window will rescan for AIs [FS#2901] (r16306) - Fix: ICC (Intel C++ Compiler) defined __GNUC__ but does not define __builtin_bswap32, so fall back to the default swap method for ICC (r16295) - Fix: Road vehicles were unable to find a depot when turning around (in some cases), causing 'nearest depot' orders to be occasionally lost [FS#2893] (r16291 - Fix: Unable to (re)set the desert state for watery tiles [FS#2888] (r16290) - Fix: Possible (in theory) desync related to autorenew settings (r16287) - Fix: Crash after using the 'Reset landscape' function and remove all waypoint signs and buoys after resetting landscape (r16280) - Fix: [NewGRF] Disable multitile houses for which the NewGRF does not define proper additional tiles (r16274) 0.7.1-RC1 (2009-05-11) ------------------------------------------------------------------------ - Add: [NoAI] AIController::GetVersion, this returns the version of OpenTTD in the same way as for NewGRFs (r16253) - Add: [NoAI] AIAirport::GetPrice, returning the building cost of an airport (r16252) - Add: [NoAI] Two new error codes to AITile: ERR_AREA_ALREADY_FLAT and ERR_EXCAVATION_WOULD_DAMAGE (r16171) - Add: [NoAI] AITile::Get(Min|Max|Corner)Height (r16166) - Add: [NoAI] Several functions to AIOrder to check the what kind of order an order is and AIVehicle.SendVehicleToDepotForServicing [FS#2801] (r16165) - Add: [NoAI] UseAsRandomAI as function in info.nut. When an AI returns false, it will never be chosen as random AI (r16113) - Add: [NoAI] AIOF_STOP_IN_DEPOT to the orderflags in AIOrder to allow stop-in-depot orders (r16107) - Add: [NoAI] GetURL() as possible function to info.nut. If AIs implement it, that url is shown when the AI crashes and also in the AI selection window [FS#2808] (r16093) - Change: [NoAI] Reverse the order of the lines in the AI debug window [FS#2778] (r16091) - Change: Harden string copying on places where it is possible (r16024) - Change: Use recent Czech language for plural form (r15965) - Fix: Wrong number of parameters or wrong parameter types sent to printf-like functions at several places (r16269) - Fix: [NewGRF] When callback 2E returns an amount of 0, do not transport 1 unit to the station (r16268) - Fix: [NoAI] Various documentation omissions with respect to IDs of various objects and corners for AITile::(Raise|Lower)Tile (r16267, r16266) - Fix: [NoAI] Check slopes passed to the API better for validity (r16264, r16262) - Fix: [NewGRF] Interpret setting bridge property 08 to 0 as always available (r16263) - Fix: [NoAI] Enable parameter checking for AIController::* functions again (r16249) - Fix: [NoAI] Make sure AITunnel::BuildTunnel returns what the documentation says it does (r16244) - Fix: [NoAI] CmdBuildTunnel could be called with invalid parameters from the API code, causing crashes later [FS#2875] (r16243) - Fix: Improve corner case order handling: mark order as done only when actually done, obey non-stop orders, do only stop/refit at the depot in the order (r16240, r16228, r16199, r16198, r16187) - Fix: [NoAI] Use the stop/non-stop intermediate orderflags AIs can give for goto-depot orders (r16239) - Fix: [NewGRF] ActionB should use the online parameters from GRFFile instead of the initial user-specified values from GRFConfig. Also use the values as they were set when the ActionB was executed, not as they are set when the message is shown (r16223) - Fix: Possible crashes when quiting OpenTTD or forcing resizes/redraws of the screen during map generation [FS#2862] (r16220) - Fix: Shared orders without orders were not properly converted causing corrupt/invalid orders when loading pre 0.7 savegames [FS#2878] (r16214) - Fix: Hardcoded (old sized) MAX_COMPANIES constant (r16182) - Fix: [Squirrel] The traps variable was not restored, causing try/catch blocks to be 'forgotten' during a suspend (r16181) - Fix: Do not try to reserve path for trains crashed in station [FS#2866] (r16178) - Fix: Forbid joining AI companies via the 'move' and 'join' console commands/multiplayer lobby (r16176, r16175) - Fix: [NoAI] AIOrder::GetOrderDestination and AIOrder::GetOrderFlags did not work on ORDER_CURRENT when the vehicle was loading/leaving in a station (r16165) - Fix: [NoAI] Change WAYPOINT_INVALID to 0xFFFF from -1 as that is the value the AIs got (due to casting) (r16150) - Fix: The overflowsafe type did not like dividing by int64 larger than MAX_INT32 causing division by negative numbers and small anomolies when drawing graphs [FS#2855] (r16130) - Fix: Road was removed when both the Remove button was active and Ctrl was pressed [FS#2582] (r16119) - Fix: [NoAI] Make sure AIOrder::GetDestination always returns a tile belonging to the station (16109) - Fix: [NoAI] When giving an aircraft a goto-hangar order do not let it be a normal goto-station order (r16108) - Fix: [NoAI] AIOrder::SetOrderFlags always removed 'Service if needed' from goto-depot orders (r16106) - Fix: Connect tried to validate too much of the company ID with too little information on hand [FS#2849] (r16096) - Fix: [NoAI] AIDebug window profiled the blitters by invalidating itself unconditionally on repaint. On the other hand it was not invalidated in other cases when needed (r16094) - Fix: The language is called Slovak, not Slovakish (r16090) - Fix: Insanely fast trains would not stop in time for stations/'jump' over waypoints/via stations within a tick, which would cause the order not to be processed causing the train to go in loops until (with luck) it 'hit' the tile [FS#2824] (r16079) - Fix: Content download progress bar 'resetting' due to mathematical overflow [FS#2845] (r16071) - Fix: Memory leak when querying a server multiple times (r16064) - Fix: [NoAI] MOF_COND_DESTINATION was not accepted by CmdModifyOrder() (r16063) - Fix: Non advanced vehicle list did not handle company switching correctly (r16054) - Fix: Do not warn that crashed vehicles are getting old; upgrading them is impossible [FS#2740] (r16048) - Fix: The currency abbreviation for the Romanian Leu is now RON [FS#774] (r16041) - Fix: Dash was not able to run iconv detection (r16035) - Fix: [NewGRF] Do not give '... Mines' as name to the station of oil rigs, or more general: do not add '... Mines' when the all of the cargoes are part of the liquid, passenger or mail classes [FS#2785] (r16029) - Fix: Storing/loading some currencies failed due to inconsistent settings 'tables' [FS#2826] (r16028) - Fix: Usage of uninitialised memory when trying to build a random new industry, but there are no industrytypes to choose from (i.e. all appearance probabilities are zero) (r16027) - Fix: 'Build separate station' in the station picker would reuse deleted stations [FS#2818] (r16025) - Fix: 32 bpp sprites in tars would also be shown in the list of heightmaps [FS#2817] (r16023) - Fix: Sometimes the unregister 'query' thread could be delayed so much that the network stuff was already closed and the packet would never reach the master server causing the server to appear online longer than necessary (r16022) - Fix: Chance16() did not work for b = 1. Also transform the formula to not use divisions (r16006) - Fix: Inconsistency between using NETWORK_NAME_LENGTH and NETWORK_CLIENT_NAME_LENGTH for the length of client names (r15988) - Fix: [NewGRF] Abort production callback after 0x10000 iterations and show a messagebox blaming the NewGRF [FS#2787] (r15958) - Fix: [NewGRF] Set callback_param1 (var 10) to 1 only when requested (r15957) - Fix: Tooltip of detailed ratings window button showed wrong message (r15943) 0.7.0 (2009-04-01) ------------------------------------------------------------------------ - Feature: Watermark crash.sav and do not generate crash information if a loaded crash.sav causes a crash so the real crash report does not get overwritten (r15893) - Feature: Add autoclean_novehicles setting which will, when autoclean_companies is true, remove any company with no vehicles and no active client after autoclean_novehicles-months (r15848) - Add: [NoAI] AIIndustryType::IsBuiltOnWater(), HasHeliport() and HasDock(). Just like AIIndustry (r15901) - Add: [NoAI] AIBridge::GetBridgeID() so AIs can get the type of bridge that are already build (r15875) - Add: [NoAI] AIRoad::GetRoadVehicleTypeForCargo() to tell whether a certain cargo needs a bus- or a truckstop (r15860) - Fix: Chat completion got called twice causing tab completion to seemingly fail (r15905) - Fix: YAPF did not apply the platform length (too long/too short) penalties (r15900) - Fix: Fixing the slopes was done a bit more often than intended making map generation with the original generator horribly slow (r15895) - Fix: YAPF used different penalties for aqueducts than for other water tiles (r15891) - Fix: Round the production rate up, so e.g. oilrigs always produce some passengers on lowest production level [FS#2772] (r15888) - Fix: Libtimidity cannot handle frees of NULL (in contrast of most other frees) [FS#2770] (r15886) - Fix: Make sure house class/ID counters do not overflow (r15831) 0.7.0-RC2 (2009-03-23) ------------------------------------------------------------------------ - Change: [NewGRF] Expose GRF ID of engines in var action property 0x25 (r15739) - Fix: Some (newer) GCCs have trouble compiling the Windows specific part of fontcache.cpp; jumps across variable declarations [FS#2752] (r15818) - Fix: When sorting on cost do not sort on the running cost [FS#2749] (r15778) - Fix: Do not show the message about reporting an AI crash for the dummy AI (r15774) - Fix: Number of active clients was not always properly updated [FS#2475] (r15773) - Fix: Settings from the [gameopt] section (from old 0.6 config files) were overwritten with default values (r15771) - Fix: Infinite loop when skipping sprites when a GRF is invalid (or truncated) (r15767) - Fix: Crash when opening the content list window twice; inconsistencies when clicking download twice [FS#2744] (r15766) - Fix: Add Engine::GetDisplayDefaultCapacity() and use it everywhere, so CB 36 is also used everywhere (r15763) - Fix: [Windows] Inlined UTF-8 characters (in the source code) are not handled properly on Eastern versions of Windows so escape them (r15762) - Fix: [Windows] On some system searching a font using its English name fails. So now we search the font using the localised name and use the English name for the final 'validation' only (r15757) - Fix: Number of houses in house variables 0x44, 0x60 and 0x61 were incorrect after 0xFF had been reached and could desync clients joining afterwards (r15755) - Fix: Crash when clicking the small area between the savegame list and the save button in the save game window [FS#2742] (r15753) - Fix: Do not try to (un)draw the cursor when the screen is not ready (r15752) - Fix: The big UFO sometimes landed just outside the map. Instead of landing, just disappear (fly away) in those cases (r15750) - Fix: Crash because submarines would sometimes start far outside of the map [FS#2739] (r15748) - Fix: Road ownership getting lost when removing a road stop [FS#2736] (r15747) - Fix: Update threading code for OS/2, add mutex support, fix compilation (r15746, r15745) - Fix: When town generator failed to create requested number of towns, there were too many cities (r15744) 0.7.0-RC1 (2009-03-16) ------------------------------------------------------------------------ - Feature: Pop up the AI Debug Window if one of the AIs crashed and show a message that the user should report the crash [FS#2728] (r15708) - Feature: Allow the number of towns that will be generated in the generate world window to be customised [FS#2672] (r15695) - Fix: Enabling freeform edges could cause submarines to get stuck on land tiles (r15733) - Fix: Centring on a vehicle did not respect its z coordinate (r15725) - Fix: Do not show passenger-/mail-capacity if the aircraft carries only cargo (r15705) - Fix: Blame NewGRFs returning inconsistent information in purchase-list/after building before users have a chance to blame OpenTTD for incorrectly autorenewing/-replacing [FS#2595] (r15701) - Fix: Just sell the old engines after autorenew/replace. Do not bother about trains exceeding the trainlimit, which will be sold anyway [FS#2721] (r15692) - Fix: Do not crash when the generate map does not contain a suitable location for a town [FS#2720] (r15689) - Fix: Do not crash when someone substitutes the 'map generation' sprites with garbage [FS#2720] (r15685) - Fix: Vehicle images would be determined during the process of moving the vehicle which means that only the (orientation) data for the vehicles in front of it is valid. Now the data for the vehicles behind the vehicle are valid too [FS#2546] (r15677) - Fix: It was possible to remove rail tunnels/bridges and aqueducts build by rival companies [FS#2718] (r15667) - Fix: Sorting of engines in the purchase list did not use the same numbers as the GUI showed, e.g. articulated parts were not taken into account when ordering by capacity [FS#2689] (r15666) - Fix: Handling of aircraft crash counter did not take account of the reduced number of calls (from 6 down to 2) to the aircraft event handler, resulting in crashed aircraft taking three times longer than they should to clear. Compensate by increasing the counter by 3 on every call instead of 1 (r15665) - Fix: Growing of vsize as (some) threads were not properly released (r15663) - Fix: Do not mark a company as having ratings in a town when querying the cost of a command (r15662) 0.7.0-beta2 (2009-03-10) ------------------------------------------------------------------------ - Feature: Allow downloading scenarios and heightmaps via the in game content download (r15632) - Feature: When cloning a vehicle with a custom name, add and/or increment a number at the end of name and assign it to the new vehicle (r15621) - Feature: Show scenarios/heightmaps from both your home directory and installation directory (r15615) - Feature: Allow building road stops on road/tram tracks of competitors (r15601) - Feature: Show required/already-delivered cargo needed for town-growth in town-view-window and only if it is really needed (r15559) - Feature: [NewGRF] Support vehicle vars 0x47 and 0xF2 in purchase list (r15542) - Feature: [NewGRF] Show the cargo subtype in the vehicle details window (r15480) - Change: The background of the the waypoint sign is now in the company colour (r15593) - Change: Allow the default debug level of 6 for a dedicated server to be overridden by -d (if used after -D) (r15543) - Change: [NewGRF] To decide whether a vehicle is refittable do not test its current capacity for being zero, but always use the 'capacity property' (r15541) - Fix: [Squirrel] Almost infinite loop in garbage collection (r15659) - Fix: Undeterministic file sorting when the date is equal for all files [FS#2716] (r15657) - Fix: Changing vehicle.dynamic_engines when there are already vehicles can cause crashes (r15656, r15586) - Fix: Only ever call any vehicle callbacks after the whole articulated engine has been built (except 0x16) (r15654) - Fix: C++'s new (this) is seldom a good idea as destructors of member variables are not run causing memory leaks [FS#2706] (r15652) - Fix: [OSX] Hack around an OSX stupidity in < 10.4 w.r.t. signals by not having any signal handling support for OSX < 10.4 (r15648) - Fix: Add an EngineOverrideManager to give the term 'compatible NewGRF' again some sense and to not crash because of trivial changes [FS#2612] (r15645) - Fix: Closing a network connection twice in the case that sending packets starts failing while disconnecting [FS#2710] (r15644) - Fix: Game crashes when network pools are empty, so always allocate at least one pool block [FS#2712] (r15641) - Fix: Do not allow more than 64 road vehicles to reserve a slot at a single road stop. 255 + 1 gives trouble, but 64 is even more than the road stop would be able to handle within the slot timeout time [FS#2707] (r15635) - Fix: Kicking/banning a client from the Client list window crashed the server [FS#2705] (r15628) - Fix: UTF8 string handling could cause buffer overruns [FS#2698] (r15626) - Fix: When trying to reserve a self-crossing path the failed reservation was sometimes not cleared completely [FS#2701] (r15619) - Fix: Towns would only build houses where the grid would not be, even when they are not allowed to build roads and the user 'implements' another layout [FS#2661] (r15604) - Fix: Crash when using an extraordinarily large sprite as cursor [FS#2696] (r15601) - Fix: Crash when opening viewport while scrolling the map and the mouse 'lands' on the window decoration of the viewport [FS#2695] (r15598) - Fix: [NewGRF] Refit-info in purchase list did only check the first articulated part (r15592) - Fix: Change owner of waypoints and deleted stations when merging companies or when a company bankrupts (r15588) - Fix: Last activity time not properly updated causing downloads to be aborted after a minute [FS#2684] (r15580) - Fix: Force unload not working when trying to force unload at the station where you received the cargo [FS#2680] (r15574) - Fix: Theoretical buffer overflow when a company with too long name funded a road reconstruction (r15572) - Fix: When building signals by dragging from a pre/entry/combo block signal, the signal you started at became a normal block signal [FS#2674] (r15567) - Fix: Dependency information was not requested after the content state was reset causing the dependencies not always being selected (and thus downloaded) automatically [FS#2675] (r15565) - Fix: Crash when saving a preset with unknown NewGRFs [FS#2646] (r15561) - Fix: The font width cache was not updated when changing fonts causing the font spacing to be off when changing fonts in-game (auto font detection) (r15557) - Fix: -v null crashing in 2051 due to trying to show the high score of the spectator (r15554) - Fix: [NoAI] Crash when setting a depot order to the southern part of a ship depot [FS#2656] (r15551) - Fix: The keep_all_autosave setting was ignored for dedicated servers/spectators [FS#2651] (r15546) - Fix: If a buoy was placed directly in front of a dock, that dock was seen as a buoy and thus skipped once within 3 tiles [FS#2653] (r15545) - Fix: Extracting downloaded content did not work for Windows if one uses a non-ASCII path [FS#2650] (r15544) - Fix: [NewGRF] When articulated parts have no available default cargo, use the cargo type of the first part for livery selection [FS#2617] (r15541) - Fix: Testing of 'only_this' in CmdRefitRoadVeh() could be skipped by 'continue' (r15540) - Fix: [NewGRF] If an aircraft cannot carry any available cargo, it should not be available either instead of falling back to passenger/mail. Just like the other vehicle types also do (r15539) - Fix: Do not allow special sprite characters (e.g. the ship sprite) as characters in input like filenames or text that is sent over the network (r15537) - Fix: The local command queue did not get properly cleaned when leaving a game meaning you could end up executing commands of the previous network game [FS#2644] (r15529) - Fix: Do not try to find the AIs the server runs when joining a multiplayer server (r15525) - Fix: Use distance to closest station tile as estimate for YAPF too (NPF already does so). This makes it behave 'better' with wide stations [FS#2631] (r15518) - Fix: [NewGRF] Wagonoverrides and articulated engine parts use the colour scheme of the engine, but not its recolour callback, nor its 2CC flag. Same applies to roadvehicles [FS#2642] (r15517) - Fix: [NewGRF] Livery overrides for articulated parts of roadvehicles were not applied (r15516) - Fix: Make the join/spectate command require to be connected to a network game; in SP it could lead to crashes (r15514) - Fix: Generating a map with the original map generator with freeform edges on resulted in a crash [FS#2641] (r15511) - Fix: Pre-0.5 OpenTTD stored new_nonstop and full_load_any in a different way, savegame conversion was not working for them (r15500) - Fix: Crash when opening the game options when the currently loaded base graphics pack has less than 2 valid graphics files. For example when someone replaces all his/her original base graphics with custom work (but keeps the name) or renames the dos ones to windows or vice versa [FS#2630] (r15476) 0.7.0-beta1 (2009-02-16) ------------------------------------------------------------------------ - Feature: Make it possible to have multiple windows with edit box open simultaneously (r15424) - Feature: Add ability to select which base graphics set is used from the Game Options window. The change takes effect when the window is closed. This option can only be used from the intro menu, as reloading graphics during a game may cause issues (r15389) - Feature: Do not draw superfluous catenary wires [FS#1761] (r15347) - Feature: Add option to group and subtotal expenses list in the company finance window (r15301) - Feature: Allow moving clients between companies/spectators by the server and the clients themselves (r15242) - Feature: Native support for Transport Tycoon (Original) savegames (r15216) - Feature: Allow terraforming of the tiles at the edges of the map (r15190) - Feature: [NewGRF] Allow a grf to customise house name via callback 0x14D, during Tile Inquiry process (r15172) - Feature: Downloading content from a central server (content.openttd.org) where authors can upload their NewGRFS/AI etc. This should make joining servers that use only NewGRFs that are distributed via this system easier as the players can download the NewGRFs from within the game. It should also make it easier to see whether there are updates for NewGRFs and make the necessary updates (r15126) - Feature: Add support for IP range bans using CIDR notation (r15094) - Feature: An AI framework so people can write their own AIs. This also removes the old cheating and heavily broken AI (r15027) - Feature: [NewGRF] Support var 0x45 (curvature info) also for road vehicles (r14945) - Feature: [NewGRF] Automatically set last engine ageing year to the last 'introduction year plus half model life', to allow engines later than 2050 to appear (r14926) - Feature: Distant joining of stations (r14919) - Feature: Advanced setting to keep various building tools active, which are usually closed after placing an object (r14902) - Feature: Remove the window limit, but leave a configurable limit on the number of non-sticky non-vital windows (r14899) - Feature: Allow road vehicles to move multiple steps in a tick (code based on train movement code) and add support for RV prop 15. This gives RVs a maximum speed of 318mph instead 79mph. This only implements higher speeds, not 'realistic acceleration' (r14869) - Feature: Automatic reversing in front of block signals can now be disabled by setting pf.wait_oneway_signal respectively pf.wait_twoway_signal to 255 (r14852) - Feature: Few (optional) optimisations to making (initial) orders; like keeping goto selected [FS#1984] (r14827) - Feature: Make the road grids of town match, when all are using the same road layout of course [FS#2390] (r14821) - Feature: Pressing CTRL while dragging to build a bridge builds the last built bridge type if possible [FS#2238] (r14805) - Feature: Make the date format for default savegame/screenshot names configurable (r14792) - Feature: Allow scrolling with the left mouse button pressed (if enabled). Primarily useful for systems with touch screen (r14789) - Feature: Allow up to 15 companies (r14735) - Feature: Allow up to 255 clients in multiplayer games (r14730) - Feature: When the chosen language is not supported by the current font, try to find a font that does and use that instead (r14618) - Feature: [NewGRF] Action0Industries property 24 (industry supplies default name for nearby station) (r14598) - Feature: Non-destructive autofill with option to keep waiting times [FS#1124] (r14592) - Feature: Stop-in-depot order; after this order you have to manually start the vehicle again (or sell it) (r14524) - Feature: Arrow key scrolling in the server list (r14517) - Feature: Initial support for handling bidirectional scripts and connecting Arabic characters (r14479) - Feature: Allow sorting vehicles by remaining life time (r14352) - Feature: Ability to reset name to default/automatic value (for vehicles, engines, towns, groups, stations, waypoints, managers and companies) (r14334) - Feature: [NewGRF] Add Variational Action 2 Variable 0x47 for houses, Coordinates of the house tile (r14294) - Feature: Allow overriding the palette of the base GRFs. This way you can play with NewGRFs made for the Windows palette with the DOS palettes base GRFs (and vice versa). Note that for this to work correctly ALL NewGRFs must use the same palette; mix and match is not yet supported (r14229) - Feature: Double click to join selected server/company (r14209) - Feature: Allow both the German as well as non-German toyland graphics as 'correct' and official graphics (r14197) - Feature: Allow people to create their own base graphics easily and without requiring code changes (r14197) - Feature: [NewGRF] Add support for property 0x13 for Bridges. In other words, one can now specifies a 16 bits cost multiplier (r14172) - Feature: Make it possible to choose between the DOS and Windows graphics packs while retaining the possibility to override the palette (r14151) - Feature: Increase the size of the console backlog. Now it'll only remove backlog items when there are more than a threshold and when they are there longer than (another) threshold (r14056) - Feature: Make it possible to filter list_patches output like it is done for other list_* console commands (r14041) - Feature: Path based signalling (r13926-13967) - Feature: Show [total-]cargo info in depot when [ctrl-]right-clicking on vehicle (r13923) - Feature: NewGRF presets, selected by a drop down list in the NewGRF window. Presets are saved in the config file (r13781) - Feature: Add a few extra columns with information to the server list (r13732) - Feature: [NewGRF] Add var 65 in Variational Action 2 Variables for Houses (r13603) - Feature: [NewGRF] Implement var 63, variational action2 variable for Houses. Or, in more simple terms, the check for the animation frame of nearby house (r13519) - Feature: Aqueducts (r13464) - Feature: [NewGRF] Add var 0x69 for industries, long format construction date (r13443) - Feature: [NewGRF] Add long format introduction and maximum construction year for house (r13437) - Feature: [NewGRF] Add access to current long year and date from Action 7/9/D and VarAction2 (23/24 or A3/A4), and add access to (long format) building year, in Variational Action2 Variable 49 for Vehicles (r13376) - Feature: Splitting of the main toolbar when the resolution becomes very low so the buttons are still visible and usable (r13339) - Feature: Make news messages use a linked list instead of a moving circular buffer. This makes it possible to store more news messages in the history (r13317) - Feature: The number of news messages is reduced by removing every news message that is a configurable amount older than when it would not be shown in the newspaper popup/ticker, which is e.g. a month for industry production changes and half a year for subsidy offers. As a result the more important messages will stay longer in the message history (if longer than 30 messages) (r13317) - Feature: Allow to have more than only two airports per town. The number of airports is now controlled by the noise each of them generates, the distance from town's centre and how tolerant the town is (13226) - Feature: Introducing the so called 'engine pool' which primarily removes the fixed engine type limits and also happens to allow (with the patch option 'dynamic_engines') multiple NewGRF vehicle sets to coexist (r12924) - Feature: [NewGRF] The ability to play NewGRF sounds for industries and stations (r12817) - Feature: [NewGRF] Add some support for NewGRF station animation (r12798) - Feature: Sorting vehicle lists by road vehicle/train length (r12766) - Feature: Conditional 'skip/jump' orders (r12667) - Feature: Ability to send a vehicle (using default orders) to the nearest depot (r12661) - Feature: Ability to force a vehicle to not load or to not unload at a station (r12650) - Feature: Four different non-stop types, individually selectable per order. Replaces 'TTDP compatible order' setting (r12648) - Feature: Three different load type in a single game instead of two. One can choose full load all and full load any instead of full load being governed by the 'full load any' patch setting (r12648) - Feature: Financial and Player Selection Face windows are now remembering their position when toggling sizes (r12634) - Feature: Show what cargoes a station could be supplied with (r12596) - Feature: [NewGRF] Add random action 2 type 84. For vehicles only (r12452) - Feature: [NewGRF] Add support for var A2/22 for action 7/9/D: Difficulty level (r12449) - Feature: Add +/- toggle buttons to station cargo waiting list to show/hide the detailed transferred cargo information (r12446) - Feature: Open the time table when pressing the order button while pressing the CTRL key (r12441) - Feature: On Screen Keyboard for input fields so someone without a keyboard can enter text too [FS#1846] (r12425) - Change: When checking for unique names, compare only with manually set names [FS#1923] (r14958) - Change: Apply the 'warn if train's income is negative' setting to other vehicle types, too (r14835) - Change: When loading games in 'network' mode use the start date of the save game for the server and all clients when loading the NewGRFs instead of the current date. Prevents desyncs caused by action 7/9s skipping parts of the GRF based on the date or some other variables that can differ at NewGRF load time (r14769) - Change: Only say a engine/vehicle is refittable when it can be refitted to at least two cargo type or when it has subcargoes (r14683) - Change: [NewGRF] Since our NewGRF handling is better than it used to be, disable a NewGRF if unexpected sprites are reached (r14184) - Fix: A town could build a statue under a bridge [FS#2618] (r15397) - Fix: Multiple vehicles could be filling the timetable and only the data from one vehicle would be taken. Now only allow one to be filling at a time [FS#2466] (r15382) - Fix: When testing for parallel road two tiles away, do not move more than one tile along the road (r15381) - Fix: [NewGRF] The subcargo returned by vehicle variable 0x42 should be the most-common-subcargo of the most-common-cargo. If nothing is transported 0x..FFFF00 should be returned (r15378) - Fix: A tram circling around in a depot did never actually 'enter' the depot [FS#2605] (r15375) - Fix: Changing town road layout in-game caused ugly road networks [FS#2121] (r15340) - Fix: Company could never have auto-assigned colour 0 (dark blue) (r15281) - Fix: Deadlock (with wide fonts) or desync when generating manager name (r15279) - Fix: Close all windows *before* starting a new game/loading a game instead of doing that as one of the latest steps of loading the game. This caused, in some cases, the NewGRF settings to be reset when the game was already loaded resulting in instant desyncs when joining a network game [FS#2577] (r15256) - Fix: Aircraft could be 'loading in the air' or have zero speed while in air after converting old savegames [FS#2571] (r15230, r15227) - Fix: Tile error location not reset when levelling land causing a tile to be highlighted when there was nothing to flatten [FS#2542] (r15138) - Fix: Signs with sign 'Sign' were lost when converting from TTD savegames (r15137) - Fix: [NewGRF] Add support for 8 byte action7/9 data, used as a mask for GRFID checks (r15114) - Fix: [NewGRF] Keep industry variables 8E and 8F in sync with 93, when changing production using results 0D, 0E or 0F of callback 29 or 35 (r15103) - Fix: [NewGRF] Disable a NewGRF from loading if it contains multiple Action 8s (r14979) - Fix: Wrong defaults for service interval when switching between service interval in days and service interval in percentages [FS#2508] (r14959) - Fix: [NewGRF] Building new station parts did not allocate a new station spec effectively breaking variable 41. This was due to the limited number of station specs that we can have per station. This fix makes newly build station parts create a new spec until one cannot allocate new station specs anymore and it'll revert to the old behaviour (sharing station specs) [FS#1832] (r14956) - Fix: [NewGRF] Station specs did not get deallocated when building a new station part over them (r14955) - Fix: Sharing/cloning/inserting of orders that the/a vehicle (in the shared list) cannot go to (wrong station type etc) [FS#1890] (r14954) - Fix: The 'animation state' of the bubbles was stored in a variable that was not stored in the savegame. Using a variable that gets saved in the savegame solves the desync and makes it a bit clearer [FS#2512] (r14931) - Fix: Abort dragging of vehicles in the group window when they are deleted [FS#2500] (r14925) - Fix: Do not unnecessarily reset the cursor, when a different vehicle is dragged (r14924) - Fix: [NewGRF] First create all articulated parts of roadvehicles, then call callback 36 capacity, also call it for all articulated parts (r14903) - Fix: Overflow of number of orders per vehicle [FS#2495] (r14830) - Fix: Off-by-one causing possible out-of-bounds reads (r14811) - Fix: In an MP game in SP mode no company would go bankrupt. Furthermore companies that passed the 'bankrupt' period (4 quarters) would not go bankrupt when loading the game back in MP. Now any company that is in MP or not 'currently controlled by the player' in SP will bankrupt [FS#1993] (r14750) - Fix: Do not let any disaster vehicle (Helicopter or Airplane) target invalid industry (r14746) - Fix: Memory leak in Action 0x0F (new town names) (r14737) - Fix: Writing a single char to the config file caused reading outside a buffer (r14729) - Fix: First transfer the whole load of a vehicle chain to industries before triggering any processing. This reduces callback usage and resolves critical rounding errors when using input-cargo-multipliers instead of production callbacks [FS#2460] (r14705) - Fix: Zeppeliner (disaster) should target st->airport_tile, not st->xy (r14694) - Fix: [NewGRF] Gradual filling graphics were not chosen according to the NewGRF spec [FS#2435] (r14678) - Fix: [NewGRF] Check sprite size when executing action 6 (r14674) - Fix: [NewGRF] Property 7 and callback 12 were broken for aircraft. Now callback 12 is properly called also for 'mail'. If the callback is not used, 'mail' uses 1/4 of property 7 (rounded up) [FS#2444] (r14672) - Fix: Possible stack corruption when reading corrupted sprites [FS#2415] (r14610) - Fix: [NewGRF] Return the current year as construction year for unfinished houses (r14608) - Fix: [NewGRF] When callback 1E fails, use the standard random colour (r14605) - Fix: The company ID is off-by-one with respect to the rest of the GUI in the cheat window [FS#2422] (r14603) - Fix: The range for kicking/banning clients is based on the maximum number of clients, not the maximum number of companies [FS#2414] (r14588) - Fix: Allow capacity callbacks (15, 36) to return zero capacity (r14578) - Fix: Crashes when a NewGRF sends an invalid string [FS#2395] (r14563) - Fix: Order pool seemed to look full when it was not as it only checked whether it was possible to allocate a new block of pool items instead of checking for free pool items (r14547) - Fix: Do not deliver cargo to industries not inside station catchment area [FS#2138] (r14530) - Fix: Allocate stub (empty) sound entries when loading an empty/corrupt/incorrectly sized sample.cat instead of making valid NewGRFs fail to load (r14527) - Fix: Make sure trains stop at the end of a station; a 3/8th length train did stop 2/8th of its length too early causing a 63/8th long train not to fit in a 4 tile station [FS#2379] (r14526) - Fix: Small possible chance of desync due to sorting on pointer instead of by (station) index [FS#2348] (r14463) - Fix: When a road stop gets moved make sure to update the destination of RVs going to that road stop [FS#2330] (r14446) - Fix: Support for spaces in directories passed to ./configure [FS#1802] (r14440) - Fix: Trains would sometimes move one time too often/little when moving from diagonal<->non-diagonal tracks [FS#1793] (r14436) - Fix: Balance the monthly random industry changes, by introducing a daily random industry change [FS#1885] (r14332) - Fix: Save the palette of the loaded NewGRFs in the savegame, so joining with a server using Windows palette will make a client with the DOS palette do palette conversion and (thus) not cause a desync (r14233) - Fix: Glitches (alignment issues/inconsistent vehicle graphics) in original graphics (r14214, r14211) - Fix: One could not get a list of vehicles sharing an order when the number of orders was 0; you could see that the vehicles had a shared order though [FS#2085] (r14097) - Fix: Various assorted autoreplace issues/misbehaviours [FS#1264, FS#2037, FS#2038, FS#2110] (r14083) - Fix: The autoreplace gui showed vehicle types for replacement which CmdSetAutoReplace() did not accept (r14037) - Fix: Automatically recalculate inflation if NewGRFs are changed and cargo types are added, so that cargo payment rates are correct [FS#2074] (r13836) 0.6.3 (2008-10-01) ------------------------------------------------------------------------ - Fix: NewGRF VarAction 2 variable 43 for industries saw MP_VOID tiles as land tiles and was inefficient (r14417, r14416, r14415) - Fix: Possible buffer overrun/wrong parameter type passed to printf (r14414, r14397) - Fix: Generation seed set using -G was always overwritten by -g (r14408) - Fix: Do not allow extending signals by dragging in any direction other than the track direction [FS#2202] (r14013) 0.6.3-RC1 (2008-09-22) ------------------------------------------------------------------------ - Fix: Invalid v->u.air.targetairport could cause crashes at several places [FS#2300] (r14383, r14344, r14343) - Fix: Moving the first vehicle of a train elsewhere might require a new unitnumber for the remaining chain which might not be available (r14384) - Fix: Trams jumping when reversing on a single trambit (like caused during road construction reworks) or when (manually) reversing in a corner [FS#1852] (r14371) - Fix: Multiheaded parts in free wagon chains were not connected (could cause desyncs) (r14366, r14362) - Fix: [Windows] Some keypress combinations could be handled twice [FS#2206] (r14363) - Fix: The ownership of roadtiles was not properly set for very old savegames (including TTD's) making it impossible to remove some pieces of road [FS#2311] (r14359) - Fix: Desync due to randomly ordered vehicle hash by flooding and road vehicle overtake/following (r14356, r14258) - Fix: Signs were not updated on company bankruptcy/sell, and thus could have the colour of invalid player (r14348) - Fix: Delete the RenameSignWindow when 'its' sign is deleted (r14345) - Fix: Signs from old savegames were lost (causing little memory leaks) (r14340) - Fix: When a company was renamed and then manager was renamed before building anything, company name changed (r14328) - Fix: When you rename a town before building something and build something near that town your company would be called ' Transport' [FS#2251] (r14327) - Fix: Free any blocks that a helicopter may have on an oilrig when the helicopter gets forcefully removed (bankruptcy). For other airports this is not needed as they cannot be used by multiple companies [FS#2241] (r14324) - Fix: Possible assert when renaming removed waypoint (r14322) - Fix: Properly delete orders so the pool does not fill up (r14319) - Fix: Do not allow building road over level crossings and drive-through road stops in the wrong direction; do not allow adding roadtypes to non drive-through road stops; pay for all added road bits [FS#2268] (r14316, r14315, r14314, r14308) - Fix: Aircraft frozen above oil rig when the next order is invalid [FS#2244] (r14309) - Fix: [YAPF] Only reserve road slots for multistop when they are really reachable [FS#2294] (r14305) - Fix: One could be trying to get the station name of a station that is outside of the pool (r14297) - Fix: Default for sound effects and music volume should be in the valid range for that setting [FS#2286] (r14289) - Fix: Make small UFO aware of articulated RVs so they crash the complete vehicle instead of a small part of it (r14270) - Fix: Desyncs after deleting a waypoint because of explicit destructor call instead of using operator delete (r14265) - Fix: Merge keycode for 'normal' 0-9 keys and keypad 0-9 keys so people do not get confused that the keypad does not work as expected [FS#2277] (r14260) - Fix: Clicking on the smallmap did not break the 'follow vehicle in main viewport' [FS#2269] (r14243) - Fix: The engine-purchase-list-sorter doubled running-cost and halved capacity of double-headed engines [FS#2267] (r14239) - Fix: Feeder share was computed wrong when splitting cargo packet (r14234) - Fix: Signs (town name, station name, ...) could be too long for 8bit width in pixels (r14221) - Fix: 10 days != 6*2.5 days, effectively causing the payment graph to show the wrong data (r14219) - Fix: When determining length of a string with limited size, first check if we are not out of bounds already (r14204) - Fix: Properly update the current timetable's travel/wait times instead of only doing it for one vehicle in the shared order chain and only when some bit has not been set [FS#2236] (r14192) - Fix: Sprite payload skipping would not skip enough bytes in a very small subset of compressed sprites (r14191) - Fix: After applying NewGRF settings, all rail and road types were available as the engine availability check was performed too early (r14182) - Fix: Close all related vehicle lists when closing a station window (and not only the train list) (r14180) - Fix: RemoveOrderFromAllVehicles() did not mark enough windows dirty (r14179) - Fix: Incorrect cargo weights (r14144) - Fix: GetSlopeZ() gets a virtual coordinate, not a tile (r14139) - Fix: Close the 'manage vehicles' dropdown once the number of vehicles in the list reaches 0 [FS#2249] (r14133) - Fix: [Strgen] Changing order of parameters {X:...} did not work for strings including some {StringY} (r14111) - Fix: Desync due to bubbles in toyland (r14110) - Fix: Make NewGRF action 0x06's changes persistent over the several loading stages [FS#1986] (r14102) - Fix: Make the 'Transfer Credit' display aware of the entire consist, not only the first vehicle (r14098) - Fix: Do not flood a NewGRF industry when it implicitly tells that it wants to be build on water (land shape flags bit 5) [FS#2230] (r14093) - Fix: The vehicle window of articulated road vehicles would show the clone/refit button when the vehicle was not completely stopped in the depot (r14090) - Fix: Flawed parsing of words (as in 2 bytes) in GRF strings due to sign extension [FS#2228] (r14087) - Fix: Division by 0 in NewAI [FS#2226] (r14062) - Fix: NewGRF callback 23 did not use the NewGRF compatible text stack [FS#2224] (r14058) - Fix: NewGRF text stack's 'push word' did not move the data around properly (r14057) - Fix: Long strings in the edit box would cause OpenTTD to stop drawing the string. This is especially noticeable with low resolutions and the chat input box (r14054) - Fix: [OSX] Changed the condition for selecting 8 or 32 bpp blitter by default. Now we will pick 32 bpp if no 8 bpp fullscreen resolutions are available on the main display (the one with the dock) (r14032) - Fix: Crash when the AI tries to find the depot of an airport that does not have a depot [FS#2190] (r13999) - Fix: MSVC cannot handle changed files in the prebuild event, so make the version determination a separate subproject [FS#2004] (r13998) - Fix: The dedicated console removed any character that was not a printable ASCII character instead. Now it allows UTF8 formatted strings too [FS#2189] (r13992) - Fix: Resetting construction stage counter reset more than it should (r13981) - Fix: Wrong tooltip for the industry directory's list [FS#2178] (r13917) 0.6.2 (2008-08-01) ------------------------------------------------------------------------ - Fix: Custom vehicle names from TTD(Patch) games were lost (r13884) - Fix: NewGRF Callback 10 (visual effect and powered wagons setting) and powered wagons operation were not performed for articulated wagons [FS#2167] (r13870) - Fix: In some cases the sprite cache could be filled with unremovable items [FS#2153] (r13869) - Fix: Return of wrong parent scope of (NewGRF) industry variables (r13868) - Fix: Loading of TTD(Patch) savegames from the command line did not work (r13859) - Fix: Buffer overflow for too long filename supplied as '-g' parameter [CVE-2008-3577] (r13858) - Fix: Cargo type lookup was incorrect for NewGRF version 7 files without a translation table [FS#2157] (r13855) - Fix: GetTownByTile() is only valid for houses and roads (r13851) - Fix: Power, running cost and capacity of multiheaded engines were (too often) doubled in newspaper resp. offer window (r13844) - Fix: FreeType may return a bitmap glyph even if a grey-scale glyph was requested [FS#2152] (r13832) 0.6.2-RC2 (2008-07-25) ------------------------------------------------------------------------ - Fix: Building through the wrong side of a drive through station was allowed [FS#2166] (r13822) - Fix: Check for vehicle length changes outside a depot (callback 0x11) and give a warning about that [FS#2150] (r13816) - Fix: Several minor memory leaks. They only happened once per game (r13809, 13810) - Fix: Checking for train waiting at other side of two-way signal was broken [FS#2162] (r13806) - Fix: Some revision checking code was unintentionally disabled (r13776) - Fix: Enforce the validity of a NetworkAction (chat packet) issued by a client (r13775) - Fix: Selecting non-full length vehicles in the depot gui would place the 'mouse pointer' out of the centre of the vehicle making it hard to 'aim' [FS#2147] (r13759) - Fix: NewGRF rail continuation would always mark a tunnel on the same axis as connected, even when the tunnel faces the wrong direction (r13734) - Fix: Assumption that non-north tiles of a house do not have the 1x1 building bit set was flawed with some NewGRFs. This caused the amount of houses to differ, which causes the town radii to differ, which causes desyncs when towns are expanded (r13729) - Fix: Possible desync on the autorenew settings 20+ game years (i.e. 4.5+ hours) after a company was started (r13718) - Fix: Any player could construct new companies [FS#2144] (r13716) - Fix: Remove the unique_id from the message that a client has joined as it is only exposes the unique_id more than needed (r13714) - Fix: Possible crash on creating a network packet [CVE-2008-3547] (r13713) - Fix: Enforce the length restrictions of company and president name in the commands too (r13712) 0.6.2-RC1 (2008-07-16) ------------------------------------------------------------------------ - Fix: Possible buffer overflow in string truncation code [CVE-2008-3576] (r13700) - Fix: Handle SETX(Y) properly when truncating a string instead of ignoring it and returning a too long string (r13699) - Fix: In some cases the (sound) mixer could overflow causing artifacts in the sound [FS#2120] (r13695) - Fix: Do not rely on .tar files always ending with a block of zeros (r13693) - Fix: Make sure a command is ran in the context of autoreplace or not (r13691) - Fix: In the case that elrails and 'realistic' acceleration are disabled all electrified engines would have no power on load, until the vehicle got turned around, loaded or got into a depot [FS#2102]- Fix: Saving TTD imported games in recession failed due to wrong (and unneeded) type conversions in the saveload code [FS#2131] (r13679) - Fix: Inactive companies from old (TTD) saves could be marked active in some cases, which then loads garbage in their statistics and such [FS#2126] (r13676) - Fix: Memory leak when NewGRFs got forcefully disabled and they defined GOTO labels (r13675) - Fix: Crash when drawing a non-real sprite caused by NewGRF interference [FS#2127] (r13674) - Fix: Desync when building electrified trains on a dedicated server that was started with electrification disabled [FS#2122] (r13673) - Fix: Bus/truck forgetting go-to-depot order when entering a non-drivethrough road stop [FS#2117] (r13664) - Fix: Server crashing when banning the rconning client (r13661) - Fix: Signals were not updated correctly when a player removed a non-existing track piece (r13626) - Fix: Crash when one tries to raise the northern corner of MP_VOID tiles (i.e. the southern corner of the tiles on the southern map edge) in the scenario editor [FS#2106] (r13624) - Fix: Only the front of a RV would be considered when determining to what cargoes a vehicle can be refitted instead of all cargoes [FS#2109] (r13622) - Fix: If the first bridge can not be build for a given length, then none of the other bridges can. Effectively meaning that if someone replaces the first bridge with a bridge that can be only 3 tiles longs then only other bridges that can be 3 tiles long will be buildable, but only if they are 3 tiles long [FS#2100] (r13611) - Fix: Signal states could be propagated through waypoints built in orthogonal axis (r13589) - Fix: [OSX] 10.5 failed to switch to fullscreen (r13584) - Fix: RVs continuing onto next DT station when they are build adjacent to them [FS#2040] (r13581) - Fix: Disable static NewGRFs when non-static NewGRFs query them in the context of network games. This makes it impossible for static NewGRFs to disable non-static NewGRFs and 'bad' things happening because the non-static NewGRF does not know about the static NewGRF (r13576) - Fix: Properly count number of non-north housetiles [FS#2083] (r13518) - Fix: Incorrect usage of strtoul (r13508) - Fix: Clear the memory for the new AI during the loading of a savegame so it does not try to execute commands generated in a different savegame, which could be resulting in the AI trying to give orders to stations that do not exist (r13505) - Fix: Drawing of zoomed out partial sprites could cause deadlocks or crashes (r13502) - Fix: First determine where to *exactly* build a house before asking a NewGRF whether the location is good instead of possibly moving the house a tile after the NewGRF said the location is good (r13489) - Fix: Track was not removed on company bankruptcy when there was a ship on lower halftile (r13488) - Fix: Let ships also navigate on half-tile sloped watery rail tiles (r13485) - Fix: Division by zero when one would press 'd' (skip order) when there's no order (r13409) - Fix: Do not crash when resolving vehicle sprite groups with zero sprites (r13397) - Fix: In the purchase list, CB36 for capacity was not called for the first part of rail and road vehicles (r13385) - Fix: Loading of very old OpenTTD savegames was broken (r13373) 0.6.1 (2008-06-01) ------------------------------------------------------------------------ - Fix: Industry tiles would sometimes tell they need a 'level' slope when they do not want the slope (r13348) - Fix: Attempts to make the old AI perform better (r13217, r13221, r13222) 0.6.1-RC2 (2008-05-21) ------------------------------------------------------------------------ - Fix: Do not send rcon commands of the server to the first client but do directly execute those on the server (r13137) - Fix: For multiheaded engines, halve power and running cost when used instead of when loading, to allow callback values to work properly (r13074) - Fix: Loading of TTDP savegames with rivers in them [FS#2005] (r13066) - Fix: Update build industry window when raw_industry_construction setting is modified (r13060) - Fix: Revert changes to multihead engine weight -- the original values were correct (r13023) - Fix: Debugging was not possible with MSVC 2008 (r12996) - Fix: List used for sorting GRFs was not freed (r12993) - Fix: Default difficulty settings were different to TTD's original settings [FS#1977] (r12951) - Fix: All vehicles would be available when an original scenario would be played [FS#1982] (r12948) - Fix: Keep only first 15 bits for non failed callback results (r12947) - Fix: Reading/modifying invalid data under some circumstances (r12943) - Fix: Minor errors related to industries accepted/produced cargo (r12933) - Fix: Town rating was affected even after the test run (r12920) - Fix: Flood road tiles even when there are road works in progress [FS#1965] (r12919) - Fix: Do not initialise Station struct with tile=0, buoys will never change that value [FS#1960] (r12915) - Fix: Game crash when a spectator/server tried to show an engine with no owner when a NewGRF requested a specific variable (r12914) - Fix: Report reverse sprite status (FD/FE) to NewGRF for manually toggled vehicles (r12910) - Fix: Vehicles going twice to a depot when the automatic service interfered with the current order [FS#1985] (r12629) 0.6.1-RC1 (2008-04-26) ------------------------------------------------------------------------ - Fix: Vehicle groups, engine replacement rules and player/company names were not properly reset/freed after bankrupt (r12906) - Fix: Remove trams from savegames saved in OpenTTD without tram support, it is better than to simply crash [FS#1953] (r12904) - Fix: GCC on FreeBSD does not support -dumpmachine causing configure to fail. Use g++ instead [FS#1928] (r12876) - Fix: Make the town rating tests use less memory and much quicker (r12859) - Fix: Usage of AutoPtr made (trying to) build stuff very (time) expensive (r12857, r12855) - Fix: Ensure that prop 25 is set for all vehicles in the consist before other properties as it could cause desyncs (r12856) - Fix: Too much catenary was drawn about tunnel entrances, middle bridge pieces and non-rail station tiles (r12853, r12852) - Fix: Use YAPF for fairly old savegames from before YAPF was introduced (r12845) - Fix: The industry tick trigger should only be triggered once every 256 ticks, not every tick... Also bail out of the triggers a little earlier if you know they are not going to happen anyway (r12844) - Fix: Inconsistent use of 8/15-bitness of NewGRF callback results with respect to TTDP's implementation of the specification (r12819, r12818, r12759) - Fix: Possible out of bounds array access (r12809) - Fix: Enforce autorenew values range in command (r12808) - Fix: Vehicles could break down during loading and keep loading. The intention of the break down code is not to break down when having zero speed, therefor break downs now do not happen when loading [FS#1938] (r12795) - Fix: [OSX] In some rare cases when using an uncalibrated monitor the system colour space could not be retrieved. Show an error when this happens instead of just trying an assertion (r12776) - Fix: Slope checking for NewGRFs failed (r12759) - Fix: Check the TILE_NOT_SLOPED flag of the _north_ tile of multi-tile houses to decide if autoslope is allowed (r12717) - Fix: Do not move windows below the toolbar on resizes unless they would go behind the toolbar [FS#1904] (r12714) - Fix: Increase default sound buffer size only for Vista [FS#1914] (r12708) - Fix: Do not crash very hard on unrecognised savegames, just go back to the intro menu instead (r12707) - Fix: In some cases a news messages would not be shown [FS#1906] (r12683) - Fix: Removing road pieces from a town gave you twice the intended penalty [FS#1920] (r12682) - Fix: When a road vehicle has a tram only stop multiple times in a row in its orders, only the first one would be skipped [FS#1918] (r12678) - Fix: Colour remaps on station sprites only worked for company colours [FS#1902] (r12674) - Fix: Remove buggy buoys at tile 0 from old TTDP savegames (r12642) - Fix: Possible NULL pointer dereference when reading some NewGRF data [FS#1913] (r12637) - Fix: Infinite loop in case your compiler decides that enums are unsigned by default (r12622) - Fix: The convert signal button disallowed signal dragging when the signal GUI was closed (r12577) - Fix: Binding to a specific IP could cause OpenTTD to not register properly with the masterserver if one has multiple external interfaces (r12574) - Fix: The function min() has 32bit arguments, clamping of 64bit values did not work (r12572) - Fix: Towns could not terraform when inflation raised terraform prices enough (r12564) - Fix: Do not affect town rating change by the order in which we examine stations (r12561) - Fix: Redraw the signal GUI when the signal drag density changes in the patch settings and vice versa (r12553) - Fix: Do not install scenarios into the current user's homedir when running 'make install', that is silly. Simply always install scenarios system wide instead (r12542) 0.6.0 (2008-04-01) ------------------------------------------------------------------------ - Fix: Final formatting of some string codes from NewGRFs was not done correctly [FS#1889] (r12488) - Fix: Timetable times for aircraft were always doubled [FS#1883] (r12477) - Fix: Remove broken endian-dependent code and unnecessary rgb to bgr swapping [FS#1880] (r12453) - Fix: Do not 'disable' the drawing of autorail overlays when the tile is 'error'-marked (red pulsating selection) [FS#1871] (r12439) - Fix: Plural rule for Icelandic was wrong (r12417) 0.6.0-RC1 (2008-03-26) ------------------------------------------------------------------------ - Feature: Show whether a town is a 'city' in the town description title bar (r12391) - Feature: Increase house animation frame number from 32 to 128 (r12347) - Fix: Loading of TTD savegames (r12399, r12401) - Fix: Vehicle lists related to stations not closed when the station is deleted [FS#1872] (r12393) - Fix: Trams failing to turn on bridge heads/tunnel entrances [FS#1851] (r123890) - Fix: Train could break apart when reversed while partially in a depot [FS#1841] (r12386, r12384) - Fix: Non-breaking spaces should not be broken (r12385) - Fix: Check return of AfterLoadGame for success or failure when loading TTD games [FS#1860] (r12383) - Fix: Use 'items' unit for batteries, fizzy drinks, toys and bubbles in total cargo tab [FS#1864] (r12382) - Fix: The number of houses was not computed right [FS#1835, FS#1535] (r12381) - Fix: Update train acceleration and max speed after setting cached value to ensure the correct max speed is used with disabled real acceleration (r12380) - Fix: Refresh vehicle details window when cached values are updated (r12378) - Fix: Set cached value for vehicle property 25 before other cached values [FS#1854] (r12377) - Fix: Do not close a dropmenu when clicking on a dropdown widget (r12374) - Fix: Windows music driver fails if path is too long or if containing non-latin chars [FS#1849] (r12373, r12372) - Fix: Do not let window hide behind the main toolbar after resizing the screen [FS#1823] (r12371) - Fix: Close language drop down when parent window is clicked/closed [FS#1853] (r12370) - Fix: Reset train speed limits when _patches.realistic_acceleration changes (r12369) - Fix: Commands were sent to clients waiting for map download causing 'executing command from the past' error [FS#1650] (r12367) - Fix: Do not allow building 'zero' road bits (r12363) - Fix: Randomise variable 8F only once per callback 28 (r12362) - Fix: openttdd.grf was using the wrong colours for glyphs due to a grfcodec bug (fixed in grfcodec 0.9.10 r1837) (r12360) - Fix: Some callback-results were treated as 8 bit, when they were 15 bit, and vice versa (r12352, r12358) - Fix: Do not try to flood water tile [FS#1836] (r12350) - Fix: NTP skipped junction just after bridge end (r12348) - Fix: Remove duplicated and inconsistent code wrt. autoreplace with rules in both vehicles' group and ALL_GROUP [FS#1748, FS#1825] (r12346) - Fix: Do not try to restore backupped timetable when timetabling is disabled [FS#1828] (r12345) - Fix: Slow helicopters never got the 'chance' to finish the landing routine (r12343) - Fix: GRM buffer for cargoes was incorrect size [FS#1827] (r12341) - Fix: Recalculate cached train data after clearing reversing flag when entering depot (r12339) 0.6.0-beta5 (2008-03-04) ------------------------------------------------------------------------ - Feature: Vehicle variable FE bit 5, 6 and 8 [FS#1812] (r12331, r12330) - Feature: Support loading full range of 0xD0xx NewGRF strings which includes 0xD000 to 0xD3FF (r12316) - Feature: Ability to change aircraft speed factor, from so called 'realistic' (matching other vehicles) (1/1) to original TTD speed (1/4) (r12293, r12294) - Change: Update readme about where openttd looks for files (r12321) - Fix: Do not pause/unpause the game when showing load/save windows when the game is paused due to missing GRFs [FS#1733] (r12336) - Fix: Disallow building level crossings over one-way roads as this allowed competitors to remove the one-way state [FS#1819] (r12329) - Fix: Wrong Y pillar specified for girder with arch bridge (r12328) - Fix: Vehicles could be sorted in a wrong order when a vehicle name changed - cached name was not invalidated (r12324) - Fix: Vehicle sorting by name was broken, it was comparing the same string (when caching was not used) [FS#1821] (r12323) - Fix: Endian issue when saving/loading group owner (r12322) - Fix: Wrong transparency options could be saved after toggling all [FS#1817] (r12320) - Fix: Map string IDs that are embedded from other strings [FS#1815] (r12317) - Fix: Include prop 25 data for all train parts, not just those that carry cargo (r12314) - Fix: YAPF and NTP did not apply penalty for uphill tracks on steep slopes (r12313) - Fix: Restore timetable from backupped orders and add group ID to the backup [FS#1549] (r12296) - Fix: Do not draw trees nor lamps between tram tracks (r12290) [FS#1807] - Fix: [Windows] Do not create save dir on install (r12269) - Fix: Autoreplace did not update vehicle index for timetable window [FS#1805] (r12261) - Fix: GetProductionAroundTiles() may fail if only the second production slot exists (r12258) - Fix: Town variables 0x9E to 0xAD (company ratings) returned wrong values (r12247) - Fix: Typo resulting in no players are given the engine preview offer (r12244) - Fix: Mac OSX bundle display name should be 'OpenTTD' [FS#1798] (r12234) - Fix: [NewGRF] Support using any base price for rail and road vehicles' running cost, show running cost of wagons if available (r12209) - Fix: When loading a savegame fails, do not start creating a new game, just go straight back to the intro screen (r12202) - Fix: Force AI to build rail or road instead of bridges if possible, so it does not build bridges everywhere (r12200) - Fix: 'Transparent buildings' now only toggles buildings, so show tick when buildings are transparent [FS#1789] (r12198) - Fix: Show correct last year profit when the train had negative income [FS#1788] (r12197) - Fix: There can be oil rigs at map borders, do not set water class for them [FS#1787] (r12195) - Fix: Do not start overtaking if the RV reaches wrong-way one-way-road in the next tiles (r12191) - Fix: Assert when trying to play tile sound at NW border of map (placing buoys, levelling land) [FS#1784] (r12186) - Fix: Take into account possible loan when AI is deciding which bridge to build, so it will not build wooden bridges every time (r12184) 0.6.0-beta4 (2008-02-18) ------------------------------------------------------------------------ - Feature: Allow buttons to resize in NewGRF settings window (r12172) - Feature: Change colour of autorail and autoroad selection when Ctrl is pressed (r12167) - Feature: Separate catenary transparency settings from building transparency settings (r12103) - Feature: Allow locking individual transparency settings so they will not be changed by pressing 'x' (r12102) - Feature: Add some missing VarAction2 variables (r12124) - Feature: Make snow appear on rail tiles dependant on track height, not on height of the lowest part of the tile (r12098) - Feature: [NewGRF] Specify the purchase, rail and road description of a bridge (r12069) - Feature: [NewGRF] Add support for var 12, Variational Action 2 (r12045) - Feature: Allow trees on shore (r12029) - Feature: Invisible trees are now separate from the building concept (r12022) - Feature: Add support for passenger engine designation for AI-use, NewGRF property 0x08 for trains (r12019) - Feature: Show all cargo sources (en-route from) in the station view cargo waiting list instead of just one (r11990) - Feature: [NewGRF] Resizable industry view window on callback 3A (r11987) - Feature: [NewGRF] Implement var 8F (random bits) during callback 28 [FS#1697] (r11985) - Feature: [NewGRF] Add support for Action 0D, var 13: information about current map size (r11961) - Feature: Support Action5 type 0D (newwater) (r11947) - Feature: Allow building bridge heads on more slopes (r11937) - Feature: [NewGRF] Add support for Rivers. Rivers can currently only be placed with-in the scenario editor (r11926, r11938, r11949, r12071) - Feature: Generate.vbs script to allow project files generation for users unable to run generate bash script (r12123) - Feature: Sort the strings in languages dropdown (r11886) - Codechange: Drop MSVC 2003 support (r11979) - Fix: Test purchase list loading/loaded sprites instead of unconditionally returning a possibly non-existent sprite (r12180) - Fix: Return correct bridge price for AI when DC_QUERY_COST is set [FS#609] (r12171) - Fix: When drag&drop mode was cancelled by keyboard input, depot/group window was not updated [FS#337] (r12166) - Fix: Buffer overflow when drawing scrolling news [FS#1652, FS#1773] (r12165) - Fix: If a train is 'stopping' when entering a depot, do not let it leave again [FS#1705] (r12163) - Fix: Towns should not build over houses owned by another town [FS#1757] (r12162) - Fix: Towns will no longer build houses > 1x1 there where should be road (with 2x2, 3x3 grid town layouts) (r12161) - Fix: Remove the arbitrary limit of 64 waypoints per town [FS#1744] (r12160) - Fix: Chance16I was now biased towards zero - round to nearest now (r12156) - Fix: Adjust aircraft slowing algorithm (r12144) - Fix: Callback 0x3D always gets a cargobit in var 0x18, independent of grf version [FS#1766] (r12142) - Fix: Do not allow adding tram to rail-road crossing when there is a vehicle on it (r12138) - Fix: Show cargo capacity for articulated vehicles correctly in the purchase list. Multiple cargo types can also now been shown [FS#1769] (r12137) - Fix: With mammoth trains disabled, maximum train length was limited to 9 (r12131) - Fix: Use tile index 0 for planes in the air, so it cannot have an invalid tile index [FS#1745] (r12109) - Fix: X/Y axis swap for station tiles in GetNearbyTile() was wrong way around [FS#1753]( r12108) - Fix: Loading older savegames fixes (r12096, r12097) - Fix: When a company bankrupts, remove drive-through road stops, ship depots and buoys too. Update owners of water and road [FS#1703] (r12095) - Fix: Do not set station owner for buoys when merging company (r12093) - Fix: Keep production level within delimited boundaries, while using var result 0D/0E and than multiplying/dividing it [FS#1755] (r12092) - Fix: Assert when loading savegame with wrong tiletype at south map borders (r12088) - Fix: Check overrides only for industries when mapping NewGRF entities to 'real' entities [FS#1747] (r12086) - Fix: Update waypoint signs when changing language (r12080) - Fix: Use search paths when opening console scripts (r12079) - Fix: When reusing a renamed deleted waypoint, keep the new name (r12076) - Fix: Make docks at sea flood neighboured tiles (r12072) - Fix: Possible deadlock when there are no houses available to build at given tile (r12062) - Fix: Houses with zero probability could be built (r12062) - Fix: Do not clear tiles when the town will not be able to build any buildings anyway (r12060) - Fix: Allow building 2x2 building on slopes if not explicitly forbidden (r12060) - Fix: It was possible to build 2x1 and 1x2 buildings on slopes even if it was not allowed (r12060) - Fix: Teach NPF where road vehicles and trams can reverse (r12058) - Fix: Ships can drive through opponents' ship depots (r12058) - Fix: Slowdown train when approaching 90deg turn when 90deg turns are forbidden (r12057) - Fix: Enable YAPF to start searching inside a wormhole [FS#1704] (r12056) - Fix: Another way to fix AI trying to build road through depots (r12055) - Fix: The cargo translation table was loaded at the right time, but all the other global variables were now loaded too early [FS#1737] (r12052) - Fix: Random_func broke for desync debug (r12050) - Fix: Memset on multibyte array with wrong byte count (r12049) - Fix: Crash when centring on a vehicle (aircraft) that is outside of the map [FS#1741] (r12044) - Fix: Allow building transmitters and lighthouses on tree tiles [FS#1736] (r12043) - Fix: Reimplement how rivers and canals are stored in the map, allowing the sea/river/canal status to also be stored for buoys, docks, locks and depots. All these are now allowed on rivers and removal of them will revert to the original water type [FS#1676] (r12042) - Fix: Change ownership of or remove statues when merging/bankrupting companies (r12038) - Fix: For station tiles, only get road types for road stops (r12036) - Fix: Teach YAPF where trams can reverse, and where not [FS#1702] (r12035) - Fix: Do not show train speed as zero after loading paused game (r12033) - Fix: When removing a statue, remove town statue flag for the statue owner, not current player (r12032) - Fix: Prevent towns from removing or claiming ownership of player owned tiles when growing [FS#1689,FS#1719] (r12031) - Fix: In one case trees could spread under bridges (r12024) - Fix: Put a better suited text in the quit-dialogue [FS#1690] (r12023) - Fix: Restore initial intent on the invisible tree while transparent building patch setting [FS#1721] (r12018) - Fix: When you have more than 9 network interfaces you'll enter the wonderful world of overflows (r12017) - Fix: Better work on strings in regard to gender [FS#1716] (r12015) - Fix: Lighthouses and transmitters were never supposed to be build on a slope (r12014) - Fix: When modifying watered tiles, mark neighboured canals and rivers dirty in more cases (r12013) - Fix: Enable TownRatingTestMode during cost estimation with 'shift'-key (r12012) - Fix: Do not consider one-corner-raised-shores to be watered tiles from all sides [FS#1701] (r12011) - Fix: Avoid loading sample.cat if it 'looks' incorrect, and avoid later null pointer dereferences by moving volume lookup deeper [FS#1707] (r12009) - Fix: Possible reading from an invalid pointer [FS#1717] (r12005) - Fix: When skipping Action 11 or 12, also skip belonging sprites (r12001) - Fix: Do entrance-slope-check for every tile of railstations (r11999) - Fix: Possible remote assert by setting bit 6 of p1 for CMD_REMOVE_ROAD [FS#1692] (r11998) - Fix: Update train statusbar when stopping from zero speed [FS#1706] (r11996) - Fix: Resize station/road stop/dock/airport construction windows if cargo acceptance list is too long (r11993) - Fix: When building two rail stations close to each other (with control) so they looked like one long track trains would see them as one (r11992) - Fix: Resize autoreplace window to fit purchase information text if it is too large (r11989) - Fix: Build system ignored changes to table/control_codes.h which require strgen to be rebuilt (r11986) - Fix: Also draw corner shores under rail tracks (r11984) - Fix: Use unicode glyph mapping to fix up missing/shuffled sprites in original data files instead of shuffling or skipping sprites directly [FS#1698] (r11981) - Fix: Industries using results 0D/0E on callback cb29/35 were a bit too eager to close down (r11976) - Fix: Shore and sea tiles under bridges were converted to canals in old savegames [FS#1684] (r11974) - Fix: Use grass tiles for corner shores, if shores got replaced by ActionA [FS#1683] (r11973) - Fix: Old AI should not build fast planes with a small airport in orders(r11972) - Fix: MP_ROAD can have railbits too - OPF searching over rail of diffen t owner behind crossing (r11967) - Fix: OPF was searching through depots and normal road stops [FS#1403, FS#1506] (r11966) - Fix: Tropic zone data was returned incorrectly [FS#1685] (r11964) - Fix: NewAI could not build any road vehicles when there were any tram grfs loaded (r11958) - Fix: Disallow building locks and docks on rapids [FS#1675] (r11956) - Fix: Do not allow modifying roadbits when other roadtypes would need different foundation (r11953) - Fix: Loading of very old savegames was broken (r11951) - Fix: Slope detection of bridge ramps. Helps YAPF and Trolly (r11946) - Fix: [Windows] FileExists() failed for non latin paths (r11945) - Fix: Allow building drive-through road/tram stops at road/tram track that has no owner (r11944) - Fix: 'BRIDGE_TOO_LOW_FOR_TERRAIN'-check was wrong for steep slopes (r11936) - Fix: [Autoreplace] Single to dualhead locomotive replace failed when player had enough money to replace and refit one but not enough to refit the last one as well [FS#1624] (r11929) - Fix: [Autoreplace] Autoreplace could refit train engines to the wrong cargo type if the old engine had no cargo capacity and the new one had (r11928) - Fix: Loading old, pre savegame version 2, savegames (r11925) - Fix: AI was reading wrong tile slope while building road bridge (r11917) - Fix: Set correctly crossing state after train reversal, train leaving crossing, train crash (r11900) - Fix: Segmentation faults/wrong frees due uninitialised memory in the AI [FS#1658] (r11887) - Fix: Assert when trying to remove rail from a house or industry tile [FS#1663,FS#1665-6-7-8,FS#1680,FS#1686-7-8 FS#1715 FS#1742 FS#1771 FS#1776](r11883) - Fix: Crash in MP in vehicle group window if the currently selected group is deleted by another player (r11878) - Fix: Another way to crash competitors' train in a station (r11877) - Fix: Automatically sending aircraft to depot for autoreplace/renew is now triggered by the correct conditions (r11875) - Fix: EngineHasReplacementForPlayer() did not look in ALL_GROUP (r11872) - Fix: Do not update signals after each tile when building/removing a large block of track/signals/station [FS#1074] (r11871) - Fix: Slow down train when approaching tile we cannot enter in more cases (r11870) - Fix: Do not make crossing red when we cannot enter it in any case (r11870) 0.6.0-beta3 (2008-01-16) ------------------------------------------------------------------------ - Feature: Replaced fixed size custom name array. Names are now attached to their object directly and there is no limit to the amount of names (r11822) - Feature: Add drag-n-drop support to the raise/lower land tools. Land is raised/lowered at the start and the rest of the area levelled to match (r11759) - Feature: Add support for NewGRF's train 'tilt' flag. Trains with tilt capability (specific details are per NewGRF set) will be given a 20% speed limit bonus on curves (r11741) - Feature: Added sorting for cost, running costs and speed to road vehicles and ships build windows (r11710) - Feature: List neutral stations where the player has service in the station list too (r11670) - Feature: Check whether (some) characters are missing in the current 'font' for the 'currently' chosen language and give a warning when that does happen (r11646) - Feature: Support shore replacement via Action 5 (r11726) - Fix: When two NewGRFs 'fight' to define the same cargo it could happen that the strings are defined by one cargo and the 'action2' by another and when one assumes that both come from the same NewGRF [FS#1559] (r11862) - Fix: Recompute town population when removing a 'newhouses' grf, or when loading a game with missing 'newhouses' grfs [FS#1335] (r11855) - Fix: Road vehicle count was incorrect in network lobby window (r11844) - Fix: Mark dirty canal tile even in diagonal direction from flooded tile, draw correctly canal next to half flooded rail tile (r11843, r11838) - Fix: At least one instance of dmusic driver is needed for it to be registered and usable (r11826) - Fix: An articulated road vehicle could split up when it turned around at a corner and then would enter a drive through station at the next tile [FS#1627] (r11825) - Fix: Switch _screen to the output buffer and disable usage of 32bpp-anim animation buffer during giant screenshots [FS#1602] (r11813) - Fix: Do not crash trains when leaving depot to a very long track [FS#716] (r11802) - Fix: Take town rating into account when testing if a command can be executed [FS#1616] (r11795) - Fix: Reversing a train when loading at a station with an adjacent station in the same axis crashed [FS#1632] (r11794) - Fix: Group names got not deallocated in the command test run [FS#1614] (r11743) - Fix: Run window tick events when paused, so that news pop-ups and the about window still progress. For other windows the events are ignored when paused [FS#1319] (r11742) - Fix: Modify and possibly discard key events for code points in the unicode private use area [FS#1610] (r11740) - Fix: Set the new scroll position after zooming in instead of before, as the zoom will cancel it out [FS#1609] (r11739) - Fix: Do not reset loading indicator IDs when only reloading NewGRFs [FS#1574] (r11735) - Fix: Elrail merge gave elrail, monorail & maglev unintended speed bonuses for curves, as the bonus was based on the railtype index. The bonus is now specified by a property of the railtype (r11732) - Fix: Clear sprite override data before performing NewGRF wagon attach callback. This stopped the callback working for autoreplace and when moving wagons from train to train in a depot [FS#1582] ( r11731) - Fix: If there are no houses that can be build in a specific year yet, force the houses with the earliest introduction year to be available [FS#1577] (r11727) - Fix: Make it impossible (for users) to circumvent the length checking of the NewGRF 'allow wagon attach' callback by moving several wagons at a time (r11724) - Fix: Do not put more than one Random() in function calls because parameter evaluation order is not guaranteed in the C++ standard [FS#1561] (r11716) - Fix: Do not allow player inauguration date on scenarios to be bigger than current year [FS#1569] (r11714) - Fix: Add more house string id ranges to MapGRFStringID so NewGRFs use the proper string ids (r11712) - Fix: Do not allow refitting flooded (destroyed) vehicles (r11707) - Fix: Trains could have sprites with wrong direction when reversing, also was inconsistent with save/load process [FS#1557] (r11705) - Fix: When removing buoys, return to water or canal depending on their owner (r11666) - Fix: Animation information should not be copied from original industry tile spec, while doing an action 00, industry tile, prop 08 (r11665) - Fix: Do not allow modifying non-uniform stations when non-uniform stations are disabled [FS#1563] (r11659) - Fix: 'Initialised' NewGRFs could still be deactivated in the later 'activation' pass (r11650) - Fix: Vehicles were still followed when sold [FS#1541] (r11632) - Fix: Many viewports could crash the scenario editor [FS#1527] (r11629) - Fix: Popping from text reference stack must be done in a precise order. But some compiler (MSVC) over optimised it and inverted this order [FS#1532] (r11627) - Fix: There were still some cases where one could not build a tram track, but the tram could become blocked [FS#1525] (r11621) - Fix: Do not make crossing red behind depot the train is entering [FS#1531] (r11619) - Fix: Buoys are just waypoints, so do not allow load/unload/transfer for them (r11618) - Fix: Sometimes large values could go off the chart [FS#1526] (r11616) - Fix: Temperate banks can only be built in towns (over a house) (r11615) 0.6.0-beta2 (2007-12-09) ------------------------------------------------------------------------ - Feature: Allow setting a default password for new companies in network games (r11556) - Feature: Signal selection GUI for the ones that really like to use that over CTRL (r11547) - Feature: Make the bridge selection window resizable (r11539) - Feature: [OSX] Added support for using Quartz instead of Quickdraw in windowed mode on OS X 10.4 and higher (r11496) - Feature: Allow to resize on creation the smallmap gui in order to show all the types industry available, allow to enable/disable individually or all at once, the industries shown on small map (r11474) - Codechange: Send and store the passwords a little more secure to/in the servers (r11557) - Fix: Wrong error messages were shown when trying to build some industries in the scenario editor [FS#1524] (r11609) - Fix: [NewGRF] Do not trigger industries, but only the industry's tiles (r11608) - Fix: Wrong count of Kirby trains when a ship was build [FS#1482] (r11605) - Fix: Tiles were not marked dirty in some cases when removing a lock or flooding (r11582, r11604) - Fix: Make price for railtype conversion more realistic; conversion should not be more expensive than removing and rebuilding [FS#1481] (r11603) - Fix: Do not allow changing network only patches settings from console when not in network game (r11594) - Fix: IsSlopeRefused() result was half wrong causing banks to be built on wrong places (r11590) - Fix: When ship depots got destroyed they always returned to water, even when it should have been canals [FS#1514] (r11589) - Fix: The one way road button was not reset on abort (r11587) - Fix: Windows could get completely missing when one resized the window to something very small [FS#1484] (r11583) - Fix: Invalidate 'list trains/roadvehs/ships/planes' widgets when station part is added/removed so it does not become glitchy (r11577) - Fix: Flood train stations when there are no trains on border tiles too (r11574, r11570) - Fix: Reinitialise windows system before loading a savegame because not doing so can cause crashes [FS#1494] (r11572) - Fix: Road vehicle getting to the wrong side of a station when trying to overtake in there [FS#1493] (r11571) - Fix: Full paths sometimes did not work correctly [FS#1480] (r11568) - Fix: Break the chain before moving a vehicle after another in the same chain instead of causing an infinite loop [FS#1512] (r11566) - Fix: Aircraft sometimes stopped mid-air when the airport got destroyed [FS#1503] (r11562) - Fix: Group list was not updated when removing the last group [FS#1504] (r11561) - Fix: Overflow when drawing graphics with high company values [FS#1505] (r11558) - Fix: If ever the air/heliport is suddenly not available while the 'chopper' is descending, just go back into flying instead of stopping mid air [FS#1496] (r11546) - Fix: Cargo translation was sometimes done when it should not be done [FS#1501] (r11544) - Fix: [OSX] Detect statvfs at runtime (based on OSX version) instead of compile time. This should prevent a crash on OSX 10.3 with the precompiled binaries (in the load/save windows) (r11541) - Fix: [OSX] Do not try to compile the quartz video driver on OSX 10.3 as it will fail (r11540) - Fix: Do not do all kinds of 'updates' for town, waypoint, station and other signs when you have not converted the map to the 'current' format as that means you are going to read data in the 'old' format when you assume that it is in the 'current' format, which is eventually going to break (r11525) - Fix: Assertion when tram reversed at a station [FS#1485] (r11524) - Fix: The scrollbar of the network gui could run out of bounds (r11522) - Fix: [OSX] The cocoa video driver let the mouse cursor escape the window when using rmb scrolling (r11520) - Fix: Signs totally illegible when transparent signs is turned on and zoomed out more than one level [FS#1463] (r11507) - Fix: Selling vehicles could cause the window of others to scroll to that location [FS#1471] (r11506) - Fix: Do not do standard production change if callbacks 29/35 failed, disable smooth economy for industries using callbacks 29/35 (r11502) - Fix: Two small layout issues with the vehicle grouping GUI (r11478) - Fix: A road vehicle must not show that it is driving max speed when it is standing still waiting for the vehicle in from of it [FS#1451] (r11477) - Fix: OpenBSD has ALIGN already defined, causing compilation failures [FS#1450] (r11467) - Fix: Operator priority problem resulting in problematic autoroad placement in some cases (r11466) 0.6.0-beta1 (2007-11-18) ------------------------------------------------------------------------ - Feature: Make news messages related to the industry (production) changes better configurable; you can now disable news messages popping up for industries you are not servicing (r11442) - Feature: When sorting stations by cargo sum, only sum the cargoes that are selected in the filter (r11437) - Feature: Show all players who have shares, not just the first two (r11435) - Feature: Make OpenTTD's sprites replaceable using Action 5 and make replacing contiguous subsets of sprites in for some types possible in Action 5 (r11433) - Feature: Allow town-bridges to be build on slopes (r11395) - Feature: Auto-road; same as auto-rail, but for road and trams and only on X and Y direction (r11339) - Feature: OpenTTD version checking for NewGRFs. This allows NewGRFs to do something different for different versions of OpenTTD, like disabling it for too low versions or loading different graphics (r11330) - Feature: Half tile- and anti-zig-zag-foundations (r11319) - Feature: Control-Clicking the Centre Main View button on the vehicle window allows the main viewport to follow the chosen vehicle (r11304) - Feature: User customisable faces (r11269) - Feature: Make more advanced rail types more expensive to build (r11265) - Feature: Implement the 'moreanimation' feature of TTDP, so we can properly support newindustries (r11228) - Feature: [NewGRF] Add support for newindustries (r11204) - Feature: Sort the NewGRFs by name, making searching a specific NewGRF a lot easier (r11175) - Feature: Add possibility to show the bounding boxes of sprites using CTRL-B so one can get a better understanding of the used bounding boxes to fix the glitches that still exist. Note that showing the bounding boxes is not glitch free; it only gives you some knowledge where the bounding boxes are (r11174) - Feature: Remove the arbitrary limit of 10 articulated parts for a vehicle (r11120) - Feature: Autoslope, changing of slopes of tiles that already have something build on them. Does not work for tiles of houses/industries/stations that do not allow autosloping (r11107) - Feature: Support for encapsulating files into a .tar file; you can pack all files in your data/ directory in how ever many .tar files you like, keeping the directory-structure equal to the unpacked version, and OpenTTD can handle them just like the files were unpacked (r11106) - Feature: Allow slopes under statues (r11069) - Feature: [OSX] Added more options for right click emulation (controlled from the interface tab in the patch window) (r10996) - Feature: Allow building and removing tracks and signals when there is a train on a parallel diagonal track that does not interact with this one (r10922) - Feature: Added TileHeight to the Land Area Information tool [FS#653] (r10878) - Feature: [OSX] OpenTTD will now pick the same language as finder is set to if no config file is found (r10851) - Feature: Provide an infrastructure to have resizable windows that are smaller than the default window size. Useful for playing on very low resolution systems (r10704) - Feature: Support for autosave_on_exit in the console, so dedicated servers can use it (r10658) - Feature: Add a soft limit of 4096 'entities' in a station's waiting queue and a hard limit of 32768 so (malicious) people cannot cause a 'denial of service' attack by filling cargo lists (r10555) - Feature: Replace all the windows for Industry building by a more flexible one (r10496) - Feature: Support for 'prospecting' raw industries, i.e. you pay an amount of money and then it might (with a given chance) build a raw industry somewhere on the map (r10451) - Feature: Automatic signal completion, enabled by pressing CTRL when dragging signals. Signals will continue following track until an existing signal, junction or station are reached. This currently replaces the existing use of CTRL-drag for changing existing signal type (r10437) - Feature: New sign editor features including switching to previous/next sign (r10401) - Feature: Disallow (in the GUI) the building of infrastructure you do not have available vehicles for. This means that the airport building button is disabled till you can actually build aircraft. The game itself will not disallow you to build the infrastructure and this 'new' behaviour can be overridden with a patch setting [FS#669] (r10353) - Feature: Add the possibility of automatically filling in timetables based on the times from the first (or subsequent) run-throughs (r10331) - Feature: Option to select the 'default' rail type when you start a new game or load a game. This is done either static, i.e. rail, electrified rail, monorail and maglev, or dynamic which takes either the first or last available railtype or the railtype that is used most on the map [FS#812] (r10329) - Feature: Give a better explanation why the loading of a savegame failed and do not crash on loading savegames that were altered by patches or branches [FS#917] (r10300) - Feature: A sticky button for the client list window [FS#885] (r10293) - Feature: Allow double-clicking on certain places: add NewGRF window, build-vehicle and town-action (r10265, r10267) - Feature: Loading indicator, which shows in % how full a vehicle is while loading/unloading (r10254) - Feature: Introduce a form of timetabling for vehicles (r10236) - Feature: [NewGRF] Add support for action 0F (town name generator) (r10211) - Feature: Add support for personal directories on Windows (r10182) - Feature: Add support for anti aliased typefaces via FreeType. This is configurable for each font size in the configuration settings and requires using the 32bpp blitter and suitable fonts (r10166) - Feature: 32 bpp sprite support and dedicated driver does not blit nor render by default. Can be overruled by user (r10121) - Feature: Add support for articulated road vehicles (r10097) - Feature: Allow moving of orders instead of removing them and readding them somewhere else [FS#828] (r10071) - Feature: Replace hard coded spritecache size with a configuration option, sprite_cache_size. The default size is 2MB and the value can range from 1 to 64MB. If you experience slow-downs when scrolling the map, try increasing this setting (r10042) - Feature: Skip to the selected order in the order list when clicking on the 'skip' button while pressing CTRL [FS#760] (r10033) - Feature: Sort the strings in server language dropdown and the town names dropdown (r10032, r10036) - Feature: Build windows of trains, road vehicles and ships can now be sorted by cargo capacity (planes already had this option) (r10024) - Feature: More languages flags for servers [FS#790] (r10017) - Feature: Allow different signal types on one tile [FS#362] (r10006) - Feature: Support for oneway roads (r9999) - Feature: Add smooth viewport scrolling. This must be enabled with patch setting 'smooth_scroll' (r9962) - Feature: Allow terraforming under bridges (r9950) - Feature: Support for trams (r9923) - Feature: Allow building new stations adjacent to existing stations by holding down control (r9905) - Feature: Add one new zoom-out level: 8 times (r9884) - Feature: Advanced vehicle lists a.k.a. group interface. Now you can make groups of vehicles and perform all kinds of tasks on that given group (r9874) - Feature: Make 'improved loading' a proper improved loading instead of loading one (semi-)random vehicle at a time. Furthermore fill multiple vehicles at once when there is enough cargo to do so (r9838) - Feature: Add drag and drop removal of station tiles (r9810) - Feature: Support for 'curvature info', Action 2 for train, variable 45 (r9803) - Feature: [NewGRF] Add action 1, 2 and 3 support for canals (r9797) - Feature: Add the possibility to choose different road patterns for towns to use (r9779) - Feature: Add an option to automatically pause when starting a new game (r9734) - Feature: Add the concept of cities. A (configurable) proportion of towns can start off larger, and will grow twice as quickly as other towns (r9667) - Feature: Add NewGRF Action 5 (Sprite Replacement) support for 2cc colour maps, airport, and road stop sprites (r9645) - Feature: Increase cargo types from 12 to 32 and enable newcargo flag in NewGRF loader (r9638) - Feature: Make it possible to have some control over the town growth (r9613) - Feature: Add list_patches console command. This shows all patches along with their current values (r9565) - Feature: Add more finer control to transparency options, including a new toolbar (r9563) - Feature: Add support for variable snow lines in the arctic climate, supplied by NewGRF files (r9371) - Feature: [NewGRF] Add support for newhouses (r9315) - Feature: [NewGRF] Add support for Action 13, which allows you to translate GRF-specific texts. The translations will only be shown if you are using a language with a GRF language id and if a string has not already been set specifically for the language you are using (r9037) - Feature: Translation dependant formatting of dates (r8906) - Feature: If an action 7/9 leads to skipping the rest of the file, disable the NewGRF if an action 8 has not been encountered yet (r8831) - Feature: Stop loading and disable the current NewGRF if a fatal error message in Action B is encountered. Also be more strict on the values accepted (r8830) - Feature: Build aircraft windows will no longer show aircraft that cannot use the airport in question (r8771) - Feature: Drive-through road stops (r8735) - Feature: Allow upgrading bridges by building a new bridge over the top (r8567) - Feature: Provide aircraft with vertical separation depending on their altitude and velocity (r8534) - Feature: When linking the terraform toolbar to the build toolbars place them side by side instead of on top of each other (r8436) - Feature: The vehicle build windows are now resizable in horizontal direction as well (r8331, r8336, r8338) - Feature: Automatically build semaphores before a configurable date, which can be set by each network player separately (r8151) - Feature: Increase sprite limit from 16384 sprites to 16777216 sprites (r8128, r8129) - Feature: Add the ability to load savegames when you do not have the exact GRF files in your list. GRF files that are found based on GRF ID (but not on matching md5sum) are used instead of disabling them. This does not affect MP games, there you still need an exact match (r8106) - Feature: Show the activated status of the GRF list after pressing 'apply' in the NewGRF window, instead of the local list (r8094) - Feature: The station list does now remember the sort settings (r8065) - Feature: Make it possible to override the bind address and port of a dedicated server from the command line (r7802) - Feature: Add command line option to prevent saving of high score and configuration on exit and a console command to manually initiate a configuration save (r7801) - Feature: Add support for tractive effort to 'realistic' acceleration (r7592) - Feature: Allow to build bridges of arbitrary rail/road combinations (including signals) (r7573) - Codechange: Do not allow configuration changes, that NewGRFs can directly use to change their behaviour, during network games as this can cause desyncs (r11452) - Codechange: Make opening a new toolbar not overlapping its parent one, by locating it under the parent, and aligned with the left side of it [FS#1310] (r11256) - Codechange: Do not brute force determine the first vehicle in the chain or previous vehicle, but do it by properly accounting the previous and first pointers when updating the next pointer. This gives a performance increase of about 15% when there are a lot of vehicles in the game (r11011) - Codechange: Cache expensive NewGRF station variables during sprite lookups/callbacks (r10509) - Codechange: Keep track of the origin, time of travel and accumulated feeder share (transfers) of individual pieces of cargo. This means that cargo is not thrown on a big pile when it is put in a station or unloaded at a station, however the GUI does not reflect these changes yet so you will not actually see it (r10266) - Codechange: Do not limit the cost of tunnels (r10248) - Codechange: Add new vehicle hash table for collision detection and finding vehicles on a tile. The hash area scanned is far smaller than the old hash table, which is now used for viewport updates only. This should give a significant performance improvement for games with many vehicles (r10111) - Codechange: Do not redraw all station tiles when cargo is added or removed if the station has no custom graphics (r10062) - Codechange: Add some support for NewGRF var 7D, temporary storage array (r9707) - Codechange: Add support for returning 'TTDPatch variables' (Action D) (r9701) - Codechange: Implement NewGRF callback 36, which allows changing of various properties which were previously static (r9671 and several others) - Codechange: Add support for multiple 'base' directories for NewGRF searching (r9560) - Codechange: Implement actions 1/2/3 for cargoes, callback handler and custom icon sprites (rmany) - Codechange: Rename the 'New ' button of the global vehicle lists to 'Available ' as it is a view-only list, not one from which you can purchase (rolling) stock (r8420) - Codechange: Remove the landscaping button from the build toolbars (r8143) - Codechange: [NewGRF] Do not mark as unsafe those NewGRFs that set their own parameters (via action D) and/or change only bridge sprite table layouts (action 0, property D) (r7831) - Fix: The CHANCE16 functions were biased; a 32768 in 65536 chance was really a 32769 in 65536 chance (r11454) - Fix: Do not create shores in canyons (r11438) - Fix: Starting OpenTTD with DOS files made it look weird out of the box (r11433) - Fix: Properly support genders coming from NewGRFs instead of crashing [FS#1430] (r11422) - Fix: Do not ignore the autorenew settings for new games when creating a new game [FS#1428] (r11415) - Fix: Do not do a 270 degree turn when 90 degrees is enough on a commuter airport [FS#1422] (r11408) - Fix: In rare cases OpenTTD could segfault when resizing and scroll the main window (r11405) - Fix: Manually replacing a vehicle with shared orders makes it lose it is order index and service interval [FS1384] (r11370) - Fix: Road vehicles must not drive through each other on bridges/in tunnels [FS#1258] (r11366) - Fix: When stopping a ship or aircraft, set their speed to 0 so they will not continue at the speed where they were stopped at [FS#1288] (r11365) - Fix: Cloning vehicles with non-standard sub-cargotypes (i.e. livery refits) failed [FS#1380] (r11362) - Fix: Loading too many GRFs was not handled gracefully causing crashes and such [FS#1377] (r11355) - Fix: Add missing elrail sprites for some rail build buttons/cursors (r11350) - Fix: Trees can now be planted on bare land without making it grassy, planting tree in desert does not make it grassy for the first tile-cycle and when a tree dies in desert, it no longer becomes a snowy tile for the first tile-cycle (r11244) - Fix: The explosion vehicles were placed too far to the south [FS#1312] (r11234) - Fix: One could sell vehicles that were crashed in a depot, which would still yield money/one could construct trains of crashed vehicles [FS#1307, FS#1228] (r11229, r11230) - Fix: Electric trains were not shown as stopped in depots when converting it from elrail -> normal rail [FS#1260] (r11167) - Fix: A lot of graphical glitches by changing some bounding boxes. It is not perfect yet, but a *very* good step into the right direction (r11128) - Fix: When autorenew is enabled and it cannot renew the vehicle anymore (because the player cannot build the engine), the ageing warnings as if autorenew is not enabled are shown [FS#553] (r11064) - Fix: Inconsistency between rail<->elrail conversions of different kinds of rail containing tiles (normal rail, stations, depots, etc) [FS#1182] (r11059) - Fix: Crash when having the Finance window opened of the player you are cheating to [FS#1177] (r11028) - Fix: Switching players (using the cheat) crashed on Big Endian machines [FS#1150] (r11023) - Fix: The canal border determination did not take oil rigs into consideration (r11022) - Fix: Do not display income/expenses when they do not belong to a 'valid' tile, like the money cheat/giving money [FS#1175] (r11021) - Fix: One could not give money when (s)he had too much money or rather: when casting the amount of money to an int32 becomes negative [FS#1174] (r11020) - Fix: When determining the gender of a string, do not assume that the gender is in the front of the string when there can be case switching code at that location [FS#1104] (r10792) - Fix: Determining whether there is a tunnel going under the lowered area is only needed in two directions instead of all four, so take the directions (one for each axis) to the nearest border (along the given axis) [FS#1058] (r10686) - Fix: Graphical glitches when the 'link landscape toolbar' patch is turned on when opening one of the construction toolbars [FS#1076] (r10685) - Fix: Trolly AI did not know about steep slopes, and used wrong tileh in some cases [FS#1070] (r10655) - Fix: Be consistent with the space between the company name and the player number, i.e. always put a space between them [FS#1052] (r10627) - Fix: [YAPF] Ships received curve penalty for non-diagonal straight move (r10578) - Fix: Do not segfault when you quit in the end-of-the-game screen [FS#1020] (r10548) - Fix: When Cheat-Window is open and a new month happens, the window was not redrawn instantly (r10547) - Fix: You can now have both Available Train as Available Ship window open [FS#1026] (r10546) - Fix: Cargo payment rates overflow and cargo payment rates diverge from cost rates making it impossible to make any profit after a certain number of years. Both are solved by stopping the inflation after 170 years; there is absolutely no point in continuing the inflation after that as it only makes the game have overflows at some point that cannot be solved; using larger variables only delays the inevitable [FS#1028] (r10541) - Fix: Error dialogue was sometimes shown on all clients when a command failed instead of only the client that actually did the command [FS#1015] (r10501) - Fix: The network protocol check for required NewGRFs sent static NewGRFs too (r10414) - Fix: When landscape generating, allow for 200ms between screen updates instead of updating every 200ms. Previously slow screen updates would result in very slow map generation (r10396) - Fix: One could only build a limited number of stations before one had to rename them [FS#278] (r10320) - Fix: Acceleration not calculated properly when a train goes up a hill between tunnels [FS#786] (r10317) - Fix: [YAPF] Now it is no longer needed to invalidate the YAPF segment cache every tick in MP (read performance increase). Segment cost now does not contain the curves between segments. As a result the cache should be now accurate (r10302) - Fix: [YAPF] Assertion triggered in some special cases [FS#901] (r10301) - Fix: Flush stdout on dedicated server output to ensure an update of stdout [FS#775] (r10295) - Fix: With smooth_economy, when industry production hit 32, it stayed there for ever. Give it some chance to get out of that uber-lowness (although it is a very slim chance, at least it has one) (r10290) - Fix: Also age engines that are not front-engines [FS#202] (r10288) - Fix: Money overflow bugs in many locations [FS#723] (r10212) - Fix: Fix issues related to fixed names, fixed places of files/directories and application bundles [FS#153, FS#193, FS#502, FS#816, FS#854] (r10182) - Fix: A vehicle without visual effects is not per definition unpowered (r9802) - Fix: Do not assume that trains running on monorail/maglev cannot smoke/spark (r9801) - Fix: Play sound effects based on the engine class, not the rail type (r9800) - Fix: Separate engine class and engine running cost class (r9799) - Fix: Clone vehicles will no longer refit for free (r9689) - Fix: Improved loading does not use a huge amount of processing power anymore when having a lot of trains [FS#423] (r9683) - Fix: Truncate the NewGRF information text in the NewGRF GUI if it is too long (r9449) - Fix: Cancel in password queries reduces amount of players in the network game when they have not joined the game yet [FS#688] (r9378) - Fix: If all news-setting buttons show 'full', make the ALL-button show 'full' too (r9137) - Fix: Open and close messages now have their own setting, so you can hide economy changes, but do show open/close of industries [FS#525] (r9097) - Fix: Do not make owner signs transparent, as then you loose the information who it owns [FS#637] (r9067) - Fix: Store the owner of a statue, so when it gets removed, the town is notified of it [FS#638] (r9066) - Fix: Inactive connections are not automatically kicked, i.e. people who only open a telnet (or similar) connection to a server [FS#115] (r9038) - Fix: Do not select a disabled platform length/number of track count when going out of drag-drop mode [FS#450] (r8999) - Fix: Make an aircraft at 400 km/h go as fast as a train at 400 km/h (r8973) - Fix: You were unable to build roads in the scenario editor when there is no town 0, even though there are other towns (r8608) - Fix: Road Vehicles now can obtain a slot even if the station is very spread out [FS#577] (r8536) - Fix: Allow lumber mill to cut trees only when they are full grown (r8535) - Fix: Segmentation fault when the toolbar gets removed and you have selected one of the items in a sub menu of the toolbar (r8533) - Fix: Remove phantom oil rigs sometimes present in old savegames (r8485) - Fix: When a station is removed, vehicles do not get excessive payment any longer, as the origin TILE is now stored as long as the origin STATION for the transported cargos (r8144) - Fix: The game could crash when the chat key () is pressed too vehemently during the join of the game. Your client's id does not exist in the clients list yet, and returns NULL (r8132) - Fix: Rail vehicles can no longer enter tunnels or bridgeheads with wrong railtype (r7976) - Fix: When path finding onto a bridge or tunnel end from previous tile (but not warping from the opposite end) check the enter direction. This fixes signal setting if a rail ends on the top of a tunnel end (r7718) - Fix: When following path for signals, do not skip back to the previous tile, as for tunnels and bridge ends the entering direction is wrong (r7717) - Fix: [YAPF] Suppress 'Train is lost' message if path finding ended on the first two-way red signal due to YAPF.rail_firstred_twoway_eol option (r7628) - Fix: [OPF] Signal update was incorrectly propagated (r7620) 0.5.3 (2007-09-15) ------------------------------------------------------------------------ - Fix: Possible NULL pointer dereference that could be triggered remotely (r11074) - Fix: Removing CMD_AUTO from some commands could remotely trigger an assertion [FS#1179] (r11040) - Fix: Underflow that caused overflows in the performance rating [FS#1179] (r11039) - Fix: [Windows] MIDI does not stop when closing openttd [FS#1164] (r11029) - Fix: Do not unconditionally assume that a tile has a depot (r11027) - Fix: Give a more correct error when building some things on tile 0 [FS#1173] (r11024) - Fix: Do not display income/expenses when they do not belong to a 'valid' tile, like the money cheat and giving money [FS#1175] (r11021) - Fix: One could not give money when (s)he had too much money [FS#1174] (r11020) - Fix: Disallow buying/selling shares in your own company or a bankrupt company [FS#1169] (r11018) - Fix: Crash when quiting the game in one of the end score windows [FS#1218] (r11071) 0.5.3-RC3 (2007-08-30) ------------------------------------------------------------------------ - Fix: Spectators are not allowed to issue commands (r11006) - Fix: Make the AI not crash when it has ships as the AI does not support them [FS#1133] (r10942) - Fix: Trains would not get flooded when they are at the lower part of a tile that would become a coast tile after flooding [FS#1127] (r10892) - Fix: Removing road with the road removal tool would also work with a negative bank account, making the bank account even more negative than it was [FS#1125] (r10890) - Fix: Some isocodes were wrong, resulting in some NewGRF not working properly for the affected languages (r10877) - Fix: [Windows] Do not try to minimise or restore the window when closing OpenTTD [FS#998] (r10835) - Fix: Trains going over bridges would get the 'going down hill' accelerate bonus, which causes trains to go faster on bridges than they would be going on level land [FS#1096] (r10739) - Fix: Trains being split into two pieces when loading an old savegame [FS#1062] (r10735) - Fix: [OS/2] Fix chdir problem with open/save dialogue (r10650) - Fix: One could not remove locks that were build in a (very) old version of OpenTTD [FS#1038] (r10593) - Fix: One cannot navigate using arrow keys in the game name text box [FS#1038] (r10500) - Fix: Ship's maximum speed wrongly shown [FS#1013] (r10497) - Fix: [OSX] Of the resolution is changed to something that is too high for the monitor, then it is reduced to fit the monitor size, solving several crashes and graphical glitches [FS#458] (r10410) - Fix: NPF was leaking memory each time it got initialised, except for the first time (r10357) - Fix: [YAPF] 'target_seen' flag that is set prematurely in some cases (1 tile long cached segment followed by target station) which caused asserts to trigger [FS#884] (r10199) 0.5.3-RC2 (2007-07-07) ------------------------------------------------------------------------ - Fix: Visual glitches when a window is resized in the WE_CREATE callback (r10465) - Fix: [Windows] _wnd.has_focus was not properly set after using ALT-TAB [FS#962] (r10399) 0.5.3-RC1 (2007-06-28) ------------------------------------------------------------------------ - Feature: Make the client list window (for network games) stickyable (r10293) - Feature: Console command to get the current game date (r10137) - Fix: Waypoints could be renamed when you are not the owner (r10368) - Fix: Smooth economy did not close primary industries and it allowed increasing of production of industries that should not have rising productions (r10348, r10347, r10290) - Fix: Acceleration for trains on slopes is not calculated properly [FS#786] (r10344, r10317) - Fix: The 'old' pathfinders (OPF and NPF) for road vehicles could not find a path when in a tunnel [FS#290] (r10345) - Fix: Only add the autoreplace menu when autoreplace actually knows about the group [FS#880] (r10337) - Fix: Signal state sometimes not properly set when the signal 'pathfinder' reached the end of a line [FS#910] (r10336) - Fix: News messages were shown over the endgame/highscore windows [FS#943] (r10333) - Fix: Rail could be destroyed when building tunnels (r10306) - Fix: Flush the output of the dedicated server console (r10295) - Fix: The 'pause' key did not work in the scenario editor (r10294) - Fix: Age non-front engines too (so when you move engines around in the depot they do not get age 0 when they are much older [FS#202] (r10288) - Fix: Do not make everyone spectator if 1 joining client failed to create new company (r10284) - Fix: Remove invalid characters (for the file system) from savegame names [FS#916, FS#850] (r10272, r10116) - Fix: Some old savegames could have the wrong bits unset (r10268, r10147) - Fix: Do not look in every direction for tunnels when building one, one direction is enough (r10258) - Fix: [Windows] Do not mess desktop when using ALT-TAB [FS#876] (r10251, r10186) - Fix: Take the age of the front vehicle for station rating (r10246) - Fix: Terraforming wipes out canals. Now you always have to remove the canal before terraforming, instead of 'just' removing the canal [FS#594] (r10240) - Fix: Only 2 trains could crash at one time as collision checking stopped on the first hit. This could technically cause desyncs in network games as the collision hash order is not guaranteed [FS#892] (r10222) - Fix: Land under foundations was terraform when it should not be terraformed [FS#882, FS#890] (r10219) - Fix: Do not make a 270 degree turn on the international airport when a 90 degree turn is enough (r10187) - Fix: Crash when trying to get the aircraft movement state of an aircraft going to a just deleted airport [FS#874] (r10165) - Fix: Airports did not flood when there are aircraft on the airport [FS#601] (r10155) - Fix: Some vehicles were not drawn when having a high resolution and a high zoom-out level [FS#870] (r10154) - Fix: Vehicles disappear when crossing certain tiles [FS#869] (r10153) - Fix: Train disconnects in some old TTD savegames [FS#862] (10151) - Fix: OpenTTD assumes that the resolution is at least 1 by 1, so force the resolution to be always at least 1 by 1 (r10139) - Fix: When you got a sufficiently small resolution, there is a possibility for a division by zero when a sound is played (r10138) - Fix: When removing a dock, a ship will always try to reach the old location of the dock even when it cannot anymore because it the old location of the dock is now land instead of water [FS#810] (r10131) - Fix: SetCurrentGrfLangID returned the wrong language ids for most languages (r10130) - Fix: Some NewGRFs use the same (unused in the 'current' climate) sprite IDs. Normally this gives some artifacts, but when one NewGRF expects it to be a sprite and another NewGRF overwrites it with a non-sprite nasty things happen (drawing a non-sprite crashes OpenTTD) [FS#838] (r10109) - Fix: Multiple subsequent 'give money' actions could result in duplicate messages that money has been transferred when it only happened once, or tell you paid money when you did not [FS#834, FS#839] (r10087, r10085) - Fix: 'Deactivate Electrified Railways' did not work [FS#836] (10083) - Fix: Memory leaks in the networking code [FS#846, FS#844] (r10082, r10075) - Fix: Coverage area highlight was still show when it was turned off for docks [FS#835] (r10068) - Fix: Do not use override engine type for articulated wagon parts (r10048) - Fix: Sprite resulting from '?' substitution was reloaded into the cache entry for SPR_IMG_QUERY instead of the original sprite cache entry. This resulted in unaccounted missing sprite cache memory, and was exacerbated because the original missing sprite was not cached, so it did it again and again and again. Slowdowns and boom (r10038) - Fix: One could build on (some) slopes when building on slopes was disabled [FS#823] (r10030) - Fix: When deleting the first engine of a train with multiple engines, only reopen the train window if the player had the original train window open. This fixes 'random' windows opening for multiple players of the same company (r10028) - Fix: When selling trains, if there were no wagons between multiheaded engines the rear part could be checked despite having already been deleted (10023) 0.5.2 (2007-05-29) ------------------------------------------------------------------------ - Feature: Add threading support for MorphOS (r9759) - Fix: Bridges and tunnels were not always removed on bankruptcy, thus leaving tunnels/bridges with an invalid owner that would crash the game when clicking with the query tool on them (r9966) - Fix: Null pointer dereference under MorphOS and AmigaOS (r9861) 0.5.2-RC1 (2007-05-16) ------------------------------------------------------------------------ - Feature: Windows 95/98/ME check in Windows 2000/XP/2003/Vista builds (r9834) - Feature: Add password protected status to 'players' (network server) console command (r9771) - Feature: Add server_lang in [network] section of openttd.cfg (r9716) - Fix: Loading some TTDP savegames caused an instant assertion on loading (r9857) - Fix: [NewGRF] Catch occurrence of division-by-zero in varaction handling (r9837) - Fix: Only non dedicated servers cannot have 0 players [FS#765] (r9785) - Fix: Remove arbitrary limit on length of NewGRF strings (r9775) - Fix: [NewGRF] Ignore axis-bit of station tile layouts [FS#756] (r9758) - Fix: [Windows] Dead key and open/close console (r9728) - Fix: When you have closed the 'Load game'/'New game' windows which you started from the 'start server' menu, you should not start a server when starting a new game [SF#1244842] (r9757) - Fix: Trains were lost after autorenewal/autoreplace [FS#732] (r9753) - Fix: Stop flooded towns from building roads on water [FS#598] (r9743) - Fix: Station signs were not resized when the language changed [FS#672] (r9741) - Fix: In news history, newlines were not replaced with spaces [FS#677] (r9731) - Fix: Crash when destroying bridge with train partially on it [FS#738] (r9726) - Fix: Planes made a 270 degree turn instead of a 90 degree turn on the southern runway of the intercontinental airport [FS#743] (r9725) - Fix: In-game private messages did not work for clients with high ClientIDs (r9719) - Fix: Do not allow building of rail vehicles whose railtype is not available (r9718) - Fix: [YAPF] The guessed path was ignored for ships [FS#736] (r9694) 0.5.1 (2007-04-20) ------------------------------------------------------------------------ (None) 0.5.1-RC3 (2007-04-17) ------------------------------------------------------------------------ - Feature: Add list_patches to console commands; shows all patches and values (r9565) - Fix: Select 'Custom' in the difficulty settings gui when changing a setting [FS#733] (r9647) - Fix: Building rail on steep slopes ignored build_on_slopes patch setting (r9602) - Fix: Wrong characters in Finnish town names (r9641) - Fix: When checking for no vehicle on ground-tiles, do not take into account vehicles that are in the air (r9542) - Fix: Bankrupt AIs no longer buy over themselves (also added safeguards to prevent in future) (r9540, r9541) - Fix: When company is removed, sell all shares of the and in the company (r9533) - Fix: Crash when 2 or more clients joined at roughly the same time (r9529) - Fix: Custom currency was overwritten and fix euro introduction (r9467, r9469) - Fix: Values of diff_custom and snow_line in .cfg were not checked properly (r9455) - Fix: When deleting a vehicle which has shared orders with one more vehicle and no orders, segfaulted (r9429) 0.5.1-RC2 (2007-03-23) ------------------------------------------------------------------------ - Fix: Crashes when the chatbox would be drawn outside of the main window [FS#701] (r9420) - Fix: Reading out of an array caused a segmentation fault [FS#694] (r9394) 0.5.1-RC1 (2007-03-20) ------------------------------------------------------------------------ - Feature: Translation dependant formatting of dates (r8906) - Feature: Kick inactive initial network connections after some time [FS#115] (r9038, r9061) - Feature: Add an extra news group for opening and closing of industries (r9097) - Codechange: Disable shares by default and increase the default maximum distance from edge for oil refineries (r9339) - Codechange: When you started openttd with '-g' you got the same map every run (r9205) - Codechange: When all news-setting buttons are 'full', make the for-all button show 'full' too (r9137) - Codechange: Disable the ability to make flooding water with the canal build tool. In the scenario editor you can still make both canals and flood water at height level 0 [FS#622, FS#629] (r9105, r9115) - Codechange: The station list, sorted by cargo rating, now takes stations into account that have no cargo waiting [FS#595] (r9062) - Fix: Close the Shared Order Vehicle List if you remove the shared link with only 2 vehicles (r9338) - Fix: A34-1000, Z-Shuttle, and Kelling K1 are now listed as small aircraft (r9298) - Fix: Shared orders got messed up when the 'first' trains got removed in the depot [FS#685] (r9277) - Fix: Use a less CPU-intensive algorithm to find a random industry for the AI to prevent it slowing down the game [FS#644] (r9251) - Fix: When loading games, enroute_from was updated in the wrong place, causing issues with TTD savegames/scenarios (r9147) - Fix: 'Train is lost' message is generated incorrectly [FS#676] (r9146) - Fix: Difficulty level button was not selected when opening the difficulty window (r9117) - Fix: The wrong catenary wires were drawn for tunnel entrances [FS#612] (r9077) - Fix: The intercontinental airport used 'T-junction' runway sprites when there is no exit in the middle of the runway as in the city airport [FS#529] (r9076) - Fix: [Windows] Dedicated console now does not need an extra 'enter' to fully quit [FS#459] (r9074) - Fix: Take over companies properly in multiplayer games [FS#459] (r9071) - Fix: When a bribe failed and you have not picked up cargo yet, you would never be able to do so for a given station [FS#404] (r9070) - Fix: Do not keep on scrolling for non-numeric values in settings, but require reclick [FS#663] (r9064) - Fix: The personal (.openttd) directories were hidden in the load/save directory listings [FS#652] (r9043) - Fix: Desync caused by buffer overflow [FS#664] (r9027) - Fix: When cutting strings into multiple lines also take into consideration whitespace characters of more than 1 byte length (r9012) - Fix: Play the correct engine sound based on the engine type instead of the sprite (r9009) - Fix: New locomotive names were not announced in the news, it said 'new railway locomotive available - railway locomotive' [FS#581] (r9000, r9001) - Fix: [NewGRF] Do not select a disabled platform length/number of track count when going out of drag-drop mode [FS#450] (r8999) - Fix: [Windows] Resolution doubled in cfg file when fullscreen mode used [FS#642] (r8994) - Fix: The industry list should also be (re)set when the number of industries is 0 [FS#656] (r8980) - Fix: [Windows] Possible buffer overflow if unicode text is pasted into an input box and needs trimming (r8975) - Fix: [Windows] Support compilation with the Vista Platform SDK (r8974) - Fix: Crash on loading savegames with GRFs that do not have their GRF info/name set (r8955) - Fix: [NewGRF] Support for vehicle variable 48 was wrong (r8943) 0.5.0 (2007-02-27) ------------------------------------------------------------------------ - Feature: Add the ability to load newer TTDP games (the tile information for coasts has changed) (r8738) - Feature: Selecting 'end of orders' and deleting will delete all the vehicle's orders (shared mode unchanged) (r8685) - Codechange: Call GetFirstVehicleInChain only for trains thus increasing performance in large games (r8744) - Fix: Possible crashes, problems with aircraft and airport removal (r8921) - Fix: Do not show the 'edit sign' window for spectators (r8808) - Fix: Adhere order types for ship order insertion to determine destination type (r8802) - Fix: It was possible to take over buoys by building a station next to them (r8794) - Fix: Cloning unaware of articulated locomotives that could refit without refitting the front unit (r8777) - Fix: Loading times for overhanging trains are miscomputed (r8709) 0.5.0-RC5 (2007-02-08) ------------------------------------------------------------------------ - Feature: Requery gameservers that did not respond to their first query (r8520, r8542) - Feature: Logging of the IP address and port of invalid/illegal UDP packets (r8490) - Codechange: Replace missing sprites with a red question mark (r8634) - Codechange: Add Korean, Simplified Chinese and Traditional Chinese languages as an official translation (r8286, r8324, r8616) - Codechange: Increase the size of the sound/video/music-drivers to 32 bytes (instead of 16) so their actual parameters can be passed. Sound has for example bufsize' and 'hz' (r8497) - Codechange: Be more strict about language generation and fail any languages not having the mandatory ##name, ##ownname and ##isocode pragma's (r8253) - Fix: Draw canal edges under buoys that are in a canal (r8635) - Fix: Buoys on canal tiles do not flood anymore (r8620) - Fix: Store the ownership of a water tile in the buoy tile and set the ownership of the water tile when the buoy is removed. Prevents certain abuses (r8619) - Fix: When the currently selected player in the performance details window is no longer active, choose the first active player instead of the first player as that may also be inactive [FS#582] (r8612) - Fix: Road vehicle very close after another (slower) road vehicle gets its speed reset to 0 when entering a tunnel, which causes a traffic jam outside of the tunnel (r8609) - Fix: Bridges do not get destroyed when the bridge head gets flooded and there is a vehicle on the bridge [FS#564] (r8593) - Fix: Road Vehicles now can obtain a slot even if the station is very spread out [FS#577] (r8536) - Fix: Segmentation fault when the toolbar gets removed and you have selected one of the items in a submenu of the toolbar (r8533) - Fix: Deleting a vehicle with shared orders, but no orders would fail to reset prev_shared and next_shared (r8294) 0.5.0-RC4 (2007-01-18) ------------------------------------------------------------------------ - Feature: Increase spritecache size to 2MB, will increase performance in games using NewGRF files (r8218) - Feature: OS/2 support with GCC (Watcom is dropped) (r8042) - Codechange: Add Japanese, Slovenian language as an official translation and split Norwegian into Bokmal and Nynorsk (r7987, r8084, r8069) - Codechange: Show error messages about our own data files as a popup, or to stderr if console is available (and not to stdout) (r8013, r8134) - Codechange: Change the ordering of the network list, compatible servers just missing grf files are below fully compatible servers, not on the bottom (r8118) - Fix: Return proper error value when unthreaded save fails, prevents server sending 0-sized files (r8171) - Fix: Network client crashes when a server sends a 0-sized savegame [FS#556] (r8167) - Fix: Several desync fixes (incorrect road stop update of old games, autoreplace bugs) [FS#551] (r8137, r8147, r8157) - Fix: Some disaster-events fixed: combat chopper shoots from right position, submarine once again moves around (r8140, r8158) - Fix: 'out of sprite memory' warning messages due to incorrect assumption of requested memory for sprites (r8133) - Fix: Buoys are now built and numbered 1..9 not 9..1 [FS#538] (r8123) - Fix: Clicking for more news properly cycles through the news history backwards, and does not show the first item doubly if it is already open (r8049) - Fix: Crash when removing a town in the scenario editor while the query window is open for one of the town's tiles (r8030) - Fix: Overflow of system-ticks was not handled properly, resulting in a possibly unresponsive server/client (r8028) - Fix: Automatic pause interfering with 'pause_on_join setting' in MP when is pressed [FS#486] (r8027) - Fix: Picking up en-route cargo will also have virtual profit deducted for trains as well (r8026) - Fix: Out-of-bounds read access on _clients array (harmless) (r7984) 0.5.0-RC3 (2007-01-07) ------------------------------------------------------------------------ - Codechange: Add Lithuanian language as an official translation (r7806) - Fix: The configure script did not work work for dash, a sh compatible shell [FS#485] (r7893) - Fix: [OSX] Control + enter no longer fullscreens, interfered with team-chat (r7886) - Fix: Offset engines/wagons by half width in details window; fixes overflowing for display (r7864) - Fix: [OSX] Remove incorrect debug message about missing grf files (r7766) - Fix: [SDL] Sometimes ALT-TAB could trigger the fast forward (r7727) 0.5.0-RC2 (2006-12-31) ------------------------------------------------------------------------ - General Removed support for OSX older than 10.3.9. Either upgrade, or use 0.4.8 (compatible with OSX 10.2) - Codechange: Drastically reduce the CPU usage in certain cases (AI using CheckStationSpreadOut()) (r7585) - Fix: Internal bug in updating the animated_tiles table caused desyncs between (different endian) machines in MP (r7631) - Fix: Signal update got propagated through incompatible railtypes and under certain circumstances tunnels and rail on top (r7620) - Fix: Remove landscaping toolbar option from road construction toolbar in scenario editor [FS#473] (r7586) - Fix: The server could under certain circumstances tell a client too late to start syncing if it has been waiting to join (r7566) - Fix: Removing towns in scenario editor did not remove their subsidies causing possible crashes [FS#468] (r7563) - Fix: Internal and (patches) GUI were disagreeing about autorenew settings [FS#431] (r7561) - Fix: No new company could be created if more than 8 clients were connected, even if not all 8 companies were used (r7560) - Fix; Clicking 'full load' could under certain circumstances change the current depot order [FS#456] (r7559) - Fix: Do not wait till a crashed vehicle is removed before starting to load other vehicles [FS#464] (r7558) - Fix: MorhpOS compile and install fixes (r7548) - Fix: Removing rail station cost was calculated on occupied area not on number of tiles with an actual station on (r7547) 0.5.0-RC1 (2006-12-21) ------------------------------------------------------------------------ - General fixes and improvements to TTDPatch's NewGRF format, most noticeable are newstations, newsounds, more callbacks and I18n - Added languages: Bulgarian, Esperanto, Russian, Ukrainian, Languages with proper diacretics: Czech, Hungarian, Turkish - Feature: Show NewGRF compatibility of network games; green for full compatibility, yellow for missing NewGRFs and red for invalid revision (r7505) - Feature: Load a list of NewGRFs from the config (in the [NewGRF-static] section) that should always be loaded (r7490) - Feature: Double the length of the cargo and rating indicators in the station list window for better visibility (r7466) - Feature: NewGRF set up window and browser which allows modification and viewing of NewGRF settings ingame or the main menu (r7357) - Feature: Support for saving NewGRF settings with savegames (r7348) - Feature: Add support for gradual (un)loading of vehicles (r7326) - Feature: Add freight trains patch option which is a multiplier for the weight of cargo on freight trains, to simulate longer heavier trains (r7269) - Feature: UNICODE/UTF8 support, with (optional) usage of fonts rendered by Freetype instead of sprites. This means full unicode support (input, rendering, file/io) and greatly enhanced internationalisation for non-latin languages (utf8) (r7182) - Feature: Add Slovak, Brazil and Slovenian currency [SF 1243657, 1171147; FS#131] (r7160, r5964) - Feature: Allow towns to be built on top of trees in the scenario editor [FS#396] (r7152) - Feature: Allow over-building of compatible railtypes, i.e. normal and electrified rail. If building electrified rail, normal rail is upgraded for you (at a cost) (r7106) - Feature: Additional positioning for long dropdown lists with scrollbar support if dropdown list would not fit (r7086) - Feature: [Windows] Remember the window size between restarts when quit in fullscreen mode (r7061) - Feature: Increase the chatbuffer of chat messages, messages longer than the graphical box will be wrapped to a new line (r6956) - Feature: Allow typing longer text than visible for an editbox; it will scroll properly now (r6954) - Feature: Allow spectators to team-speak to each other (r6933) - Feature: Allow for ' to be in console tokens. Escape them with \. eg \' (r6875) - Feature: Change the functionality of the chat window. SHIFT+ENTER (SHIFT+T) sends a message to all players, CTRL+ENTER (CTRL+T) sends a message to all team mates and ENTER (T) is customisable (r6824) - Feature: (Train is) lost message is now generated immediately when pathfinder cannot find the path (r6800) - Feature: Add a measurement tool that will show dimensions and height differences of various draggable tools (r6758) - Feature: Added sort options to the build aircraft and train windows (r6708) - Feature: Depot lists are now sorted, so vehicle 1 is always first and so on (r6652) - Feature: Ability to pause a server if not enough players are connected. The setting for this is 'min_players' (r6628) - Feature: Ability for servers to execute a script just after a client has connected, e.g. for a MOTD, etc (r6625) - Feature: Add refit commands to vehicle orders (can only be done in goto depot orders) (r6624) - Feature: Support cargo subtypes in the refit window. The refit window has been altered to support resizing and scrolling (r6601) - Feature: Depot and vehicle list windows reworked a bit with more buttons to include 'Autoreplace all' (instantly), 'Sell all', 'Start all' and 'Stop all' (r6542, r6552, r6515) - Feature: Using goto depot with a different control selection will now alter the service/stopping in depot flag instead of cancelling the goto depot order (r6295) - Feature: When automatically detecting the language try to first match language+territory (e.g. de_CH), then just language (e.g. de) and fall back to en_GB otherwise (r6290) - Feature: Add a 'goto depot' button to various vehicle list windows (r6229, r6246) - Feature: Save max_companies/clients/spectators in the config file (r6170) - Feature: Vehicle status bar will show the heading string in different colours to visually discern the difference between a service and a forced stop (r6165, r6414) - Feature: Control clicking Goto Depot will now make the vehicle service instead of stop in depot (r6165) - Feature: List of vehicles with the same shared orders, accessible from the orders-window of a given vehicle (r6161) - Feature: Added -s (source) and -d (destination) to strgen to specify paths for input and output files (r6089) - Feature: After removing a farm, its farmland is removed too (over time) [FS#82] - Feature: Clicking twice on the location button in the smallmap centres to your position, clicking twice centres your viewport [FS#54] (r6040) - Feature: Change the original date format to a 32 bits format based at the year 0. Highest date is the year 5.000.000AC (r5999) - Feature: Auto-completion in chat-window. It completes Player and Town names (in that order) using (r5968) - Feature: Catalan Town Names generator [FS#261] (r5965) - Feature: Possibility to generate scenarios by importing heightmaps. It can be in PNG or BMP format - Feature: New (optional) landscape generator based on TerraGenesis Perlin noise with GUI, progress bar and fine-tuning options (r5946) - Feature: Filter for textboxes to only allow input of certain patterns (like numbers only) (r5944) - Feature: [Windows] Remember the maximised state of the game window and restore on start [FS#234] (r5874) - Feature: Add an icon to the SDL openttd executable (r5872) - Feature: Also allow horizontal and vertical rails on steep slopes (r5864) - Feature: Allow building of (certain) rails, roads and bridge ramps on steep sloped tiles (r5833) - Feature: Replacing from a train engine without cargo capacity to one with cargo capacity will now make autoreplace refit the engine to carry the cargo type from the last wagon in the train (r5465) - Feature: [OSX] Macs with touchpads that support two finger scrolling can now use this 'scrollwheel' to scroll up/down (r5460) - Feature: Allow building canals at sea-level, using ctrl to toggle canal or plain water tile. This allows building of non-raisable sea-level water ways (useful in multiplayer) and dikes for low-level areas (r5403) - Feature: Add 4 new airports. 2 for aircraft, 2 for helicopters (r5346) - Feature: Implement smooth horizontal depot and, vehicle list scrolling for trains (r5046) - Feature: Add new pathfinder, YAPF. Has greatly improved performance and better, fully configurable, pathfinding (yapf) (r4987) - Feature: Add a new console command 'players' that lists current players along with basic stats [FS#150] (r4828) - Feature: Station List View can now be sorted and filtered (by waiting cargo type and facilities) (r4822) - Feature: The integer-list parser now accepts a space character as an item separator next to the comma for openttd.cfg (r4490) - Feature: Add support for electric railways as a separate tracktype. Electric trains will not run on non-electrified track unless otherwise controlled by patch option (elrails) (r4150) - Feature: A new multi-lingual multi-measuring-unit system (r4126) - Feature: Add proper OPENTTD <> LOCALCODE conversion using iconv. Savegames with special characters will be legible in filesystem (r4105) - Feature: Undraw the mouse when it leaves the window and draw it again when it enters (r4075, r4083) - Feature: It is now possible to turn a single unit in a train (CTRL+Click on unit in depot) (r3944) - Feature: Delete news items about vehicles when they get stale (r3757) - Feature: Save patch settings with the savegame so you are presented with the same behaviour when loading the game on another machine/installment (r3726) - Feature: Add 2cc (two company colours) livery schemes. This replaces the original colour selection window (r3717, r6455) - Feature: [OSX] Added support for triple binaries (binaries optimised for G3, G5 and i686) (r3674) - Feature: Allow autoreplacing of train wagons (r3535) - Feature: Allow sorting of vehicle lists by model or value (r3528) - Feature: Allow trains details view to be resized (r3521) - Codechange: Improve the usability of the signal-dragger, do not bail out at (certain) errors, just silently ignore them [FS#149] (r7127) - Codechange: Make the zoom in/out buttons of the extra viewport into proper push-buttons (r7078) - Codechange: Make the AI choose road vehicles based on a rating (currently max speed * capacity) instead of either the cost or the index of the vehicle (r7070) - Codechange: Truncate text in window captions to prevent overflow (r7058) - Codechange: Allow standard ini-file style comments (;) (r6972) - Codechange: Send server messages with format NETWORK_ACTION_SERVER_MESSAGE so it is general colour like the rest of the server messages. Spectators speak in grey (r6932) - Codechange: Change textmessage format a bit. Only the sender's name and target are in the sender's colour, the actual message is in white. Should improve readability (r6932) - Codechange: Add an MD5 sum check of our own data files, and warn if they do not match (r6921) - Codechange: Add strict bounds checking in string formatting system to check for possible buffer overflows (r6884) - Codechange: Have the dropdown menus fall fully inside the top toolbar (r6745) - Codechange: Determine the length of the main toolbar dropdown list based on the length of the strings in that list (r6744) - Codechange: When vehicles never expire they will stay at peak reliability instead of the lowest to make them useful even when old (r6681) - Codechange: Show more correct capacity of articulated wagons in the train purchase list (r6650) - Codechange: When showing tooltips, properly position the tooltip taking into account window dimensions and cursor (r6405) - Codechange: Speed up the animated cursors a bit so they move once in a while at least (r6367) - Codechange: Remove the 'unsorted' vehicle sorter, because it is plain useless (r6270) - Codechange: Remove MSVC6 support. The compiler was too stupid and too many workarounds were needed. Please switch to mingw or VC2005++ express (r5286) - Codechange: Allow a switch in Makefile.config to disable threads in OpenTTD (r5978) - Codechange: [Windows] Add native x64 target to VS2005 project files (r5813) - Codechange: [Windows] The exception dialogue showed the last modification-date of win32.c instead of the last compilation-date (r5801) - Codechange: Add owner attribute to canals and locks. This makes them more useful in multiplayer games, as only the owner can delete them. Does not affect usage (r5084) - Codechange: [Windows] Add MSVC2005 support, project and solution files are in the _vs80.* files (r4581) - Codechange: [OSX] Shark (Xcode's profiling tool) can now relate CPU usage to lines (r3611) - Codechange: Rewrite the multistop slot assignment system. More resource-friendly, several slot-assignment improvements (r3730, r4259) - Codechange: Completely remove the deprecated -p parameter (is superseded by -n) (r3508) - Fix: Town ratings were not reset when a company went bankrupt (r7433) - Fix: With realistic acceleration, guarantee a minimum braking force is applied. This ensures trains will stop when going down hill (r7425) - Fix: Changed 'kick off' acceleration resulted in only a small amount of power being applied; this resulted in a perceived delay before trains moved (r7421) - Fix: Long delay for message windows to appear. Immediately show a new message if present if no news window is open, or has just been closed instead of waiting for the timer of the current news to time out [FS#255] (r7402) - Fix: Deleting Train in depot with autoreplace fails [FS#418] (r7385) - Fix: Do not update vehicle images when turning a train around. During this procedure the train is split into parts which can result in incorrect images being used (r7378) - Fix: OpenTTD could crash under certain circumstances when a vehicle as autoreplaced and a news window was open [FS#332] (r7368) - Fix: Segmentation fault in the SDL video driver when one goes to fullscreen and there are no suitable resolutions (r7332) - Fix: When loading a game from a dedicated server the local player set to 0, theoretically enabling the dedicated server to also play (r7312) - Fix: TTDPatch vars are little endian (r7282) - Fix: Always display the excavation of roadworks even when fully zoomed out or 'full details' are off (r7240) - Fix: Window allocation and deletion messed with the actual window pointer, possibly crashing OpenTTD [FS#350, SF#1560913] (r7205) - Fix: Callback not executed for non-player based patch changes in multiplayer for all clients; possible desync issue (r7190) - Fix: Station sign (and base station coordinates) did not move along with station when station moved by walking [FS#388] (r7169) - Fix: MiniMap was misplacing vehicles sometimes [FS#402] (r7166) - Fix: Some mouse events possibly lost under high CPU load, handle mouse input right away instead of waiting for GameLoop [FS#221, SF1168820] (r7157) - Fix: Some keyboard events possibly lost under high CPU load, handle keyboard input in place instead of global variables magic [FS#279] (r7153) - Fix: 'Position of Main Toolbar' option is not honoured when starting new game or loading saved [FS#172] (r7130) - Fix: Synchronise the engine-renew settings of a player when joining a multiplayer game (r7126) - Fix: Several errors/glitches related to multiplayer and bankruptcy (mainly server), and non-updated company-information (r7125) - Fix: Cloning a vehicle that has been refitted would incur the expense as running costs, not new vehicles [FS#371] (r7115) - Fix: Do not let ships enter partial water tiles under bridges; they will travel up land... (r7110) - Fix: AI tried to build road from the back or side of road stop/depot (r7069) - Fix: Zooming out near map-borders would previously fail because the new centre would be outside the map [FS#317] (r7047) - Fix: 'Goto' button in orders window got depressed along with all other buttons when an existing order was modified [FS#311] (r7046) - Fix: Scenario bridges/tunnels cannot be demolished [FS#200] (r7028) - Fix: Pressing F1 in scenario editor did not work (r7023) - Fix: Properly guard against viewing company-sensitive information from invalid players (eg spectators) which could lead to crashes [FS#292] (r7022) - Fix: In the replace vehicle window, the left vehicle list was not drawn when an engine was not selected (r7009) - Fix: Crash at game end when server company is bankrupt [FS#369] (r7008) - Fix: List of actions panel in the town authority window went underneath its scrollbar (r6885) - Fix: Pressing ^D (EOF) at a dedicated console caused it to repeat the last command, instead of doing nothing (r6835) - Fix: Do not add up running cost of articulated engine parts (r6765) - Fix: If a rail is not available, do not show toolbar even with hotkey 'A' (r6740) - Fix: Only apply the virtual transfer profit if the order is a transfer order, rather than to any unload order (r6738) - Fix: Disable main toolbar buttons showing company list drop downs when there are no companies [FS#356] (r6695) - Fix: Autoreplace can now use the money for selling the old vehicle to build the new one (r6640) - Fix: A loop-hole that allowed docks to be built regardless of town authority rating (r6477) - Fix: [Windows] The dedicated server could overwrite the keyboard input buffer before it was handled by OpenTTD (r6449) - Fix: Reset the location of the last sound as that location can be outside the map when you are loading another, (smaller) map (r6437) - Fix: Show an error message when executing 'scrollto x' with x < 0 or >= MapSize() instead of asserting later on [FS#340] (r6435) - Fix: Station catchment area persists after switching tools [FS#136] (r6368) - Fix: Do not reset the current cursor action when centring on a depot/hangar (r6360) - Fix: Go to hangar orders for aircraft could get spuriously removed when a road or rail depot got deleted (r6355) - Fix: Due to some off-by-one errors the width or height of a clipping rectangle could become 0, which is not sensible. This should fix a very rare and hard to trigger assertion in GfxFillRect() (r6351) - Fix: Never allow scrolling the map in the main menu (scroll-settings were not reset if switched to mainmenu) (r6037) - Fix: Never set I-am-a-thread bool to true IN the thread, dual-core machines could flip [FS#78] (r5977) - Fix: Town-growth removed houses under construction to make way for road; unwanted behaviour [FS#49] (r5970) - Fix: Cloned toad vehicles are not refitted to correct cargo [FS#275] (r5917) - Fix: Bugfix for errors in FindNearestHangar function in aircraft_cmd.c [FS#235] (r5914) - Fix: Sort order for produced amount and transported percentage was reversed in the industry list (r5912) - Fix: Changing patch settings through the console did not accept on/off or true/false [FS#170] (r5903) - Fix: Differing price calculation for tunnels depending on starting point [FS#253] (r5901) - Fix: Goto sepot not always working for road vehicles [FS#249] (r5898) - Fix: Bus trying to service in depot of other company [SF1519167] (r5897) - Fix: If vehicles break down and service is turned off, the vehicles failed to enter any depots; now they will quickly go to a depot if set to be replaced (r5888) - Fix: Incomplete removal of player owned property due to lack of money [FS#273] (r5886) - Fix: < > boxes in patch-settings did not grey out when they hit the limit of their range (r5714) - Fix: Check the configuration file for valid values and clamp them to their ingame minimum/maximum [SF1288024] (r3726) - Fix: Remove the restriction that the 'patch' console command can only be run from network games [SF1366446] (r3723) 0.4.8 (2006-08-12) ------------------------------------------------------------------------ - Fix: A ship in a depot must be stopped before it can be cloned - Fix: After changing directory in 'Play Scenario', the default scenarios did not show up in 'New Game' 0.4.8-RC2 (2006-07-31) ------------------------------------------------------------------------ - Feature: Add Italian town names as we have an official Italian translation - Codechange: Verify the presence of music files in the gm/ folder. This should also solve some 100% CPU buildup for some users - Fix: Certain combinations of trains crash when moved around inside the depot - Fix: Reversed arrow-sign in the multiplayer list column headers on sort by name - Fix: Industry production change button does not work for oilrig passengers - Fix: Helicopters stopping in depot after autorenew/autoreplace - Fix: MorphOS crashes when you go a level up in the root level - Fix: UDP sockets were used even if network-availability was set to false - Fix: Crash when trying to build a vehicle type that is set to a max of zero 0.4.8-RC1 (2006-06-28) ------------------------------------------------------------------------ - Feature: Add Turkish town names as we have an official Turkish translation - Feature: Add a fully optional configure script that is a wrapper around the cumbersome makefile.config - Codechange: [NPF] Disable NPF totally for ships as it wholly kills performance. Only for 0.4/ branch and 0.4.8 - Fix: Redraw the screen when switching the signal side in the patches window - Fix: It was possible to dig into a tunnel if certain rail combinations were on top of it - Fix: A HQ could only be flooded at its northern tile, the other 3 were immune to water - Fix: Fix several glitches concerning foundations. Houses, property (rail/road/bridge/etc.) and cursor are now aligned properly - Fix: Prohibit altering a road tile while road works are in progress. This fixes some glitches like 'turning' the excavation by adding/removing road bits or removing the road piece - Fix: Only advertise the server to your external IP/network (eg not to 127.0.0.1) and use proper broadcast addresses - Fix: '-f' switch is not valid on windows, so do not show it in help - Fix: [Autoreplace] Autoreplaced trains can leave all wagons in depot under certain circumstances - Fix: The wrong IP could get unbanned, e.g. 'unban 1.2.3.42' could result in unbanning 1.2.3.4 - Fix: It was possible to convert the railtype of a bridge while a train was on it - Fix: It was possible to rename signs or waypoints with the chat box - Fix: Be more strict what it means for an aircraft to be in a hangar: It is not just being stopped on a hangar tile - Fix: If a road vehicle is on a road depot tile and stopped does not mean it is in the depot. Use the proper test for this - Fix: [AI] The AI should send a plane into a hangar if it is not in a hangar _or_ not stopped, not when it is not in a hangar _and_ not stopped - Fix: [AI] The trolly AI used information from the wrong industry when calculating the amount of to be transported goods - Fix: [NTP] Fix NTP over bridges: do not check the rail type when on a bridge - Fix: Truncate text in dropdown lists to stop text overflowing - Fix: 'Erroneous train reversal on waypoints'. When processing the next train order, do not even consider reversing the train if the last order was to a waypoint - Fix: Starting a new scenario did not adhere to local difficulty settings but took it from the scenario itself. That mode is for 'play scenario' - Fix: Vehicles on a sloped tile under a bridge were affected by the bridge speed limit - Fix: Issue with train pathfinding over level crossings - Fix: [AI] The AI no longer attempts to build signals under bridges - Fix: Refresh build vehicle window (if opened) when converting rail depot - Fix: Crash when sorting an empty server list - Fix: The build-tree window button defaulted to a place-push-button on opening where no treetype is selected - Fix: Game crashes when cloning/autoreplace reaches train-limit - Fix: [NTP] Properly check for railtypes on non-plain-rail-tiles - Fix: Trains could enter certain sloped rail tiles under bridges with incompatible rail type - Fix: Ensure the map memory is cleared after it is allocated. This fixes random deserts that sometimes occurred - Fix: Some weird behaviour with tile selection near bridges - Fix: Do not allow PF to enter train depot from the back (signal updates) - Fix: Game no longer crashes when the last vehicle servicing a station has been deleted - Fix: Reset the last built railtype when starting a new game - Fix: Cloned vehicles get the same service interval as the original vehicle - Fix: Game no longer errors out when 'Many random towns' is selected in the scenario editor - Fix: Obscure road dragging bug. The road build command did not return the appropriate error message of invalid-slope when building road - Fix: Temperate bank will no longer appear (during game) in tropic landscape. This bug is from the original game - Fix: Specify the 'stopall' console command as a debug command - Fix: Fixed a problem that caused DeliverGoodsToIndustry to not work as intended - Fix: Ships and aircraft can now be used as feeders as well - Fix: When a multiheaded train is sold the pointers were not updated correctly causing sporadic crashes/disconnects - Fix: New plantations now cause the correct '.. being planted ..' news item - Fix: Danish town names were saved/loaded as Swiss - Fix: Removing roads on crossings was done without a check for ownership - Fix: [Autoreplace] Fix drawing of train list for outdated engines - Fix: Malicious clients/servers could crash the game [CVE-2006-1999, CVE-2006-1998] - Fix: [Autoreplace] Allow replacement of wagons even when the engine fails to be replaced - Fix: Certain operations involving trains inside a depot could cause a crash - Fix: [Autoreplace] Cost for refitting a new vehicle is added to the cost animation (player always paid for it, it just was not shown) - Fix: [OSX] Save/Load issues solved for OSX 10.3.9 universal binaries - Fix: Illegal servers in the master-server list could kick the client back to the main menu, effectively making Multiplayer impossible - Fix: [NPF] Do not mark tiles when debugging in multiplayer, this will cause desyncs - Fix: Several fixes to chatbox code, mainly plug a buffer overflow 0.4.7 (2006-03-26) ------------------------------------------------------------------------ - Feature: [OSX] Add support for triple-binaries (PPC, PPC970, i386) (r4102) - Fix: [OSX] Crash when going to fullscreen (r4100) - Fix: Allow unused wagons to have their first cache set. Fixes faulty cache-warning message and noticeably speeds up depot operations (r4094) - Fix: [NPF] Trains & buses were unable to find a route when leaving a depot or bus stop (r4072) 0.4.6 (2006-03-22) ------------------------------------------------------------------------ - Codechange: [Windows] Show the revision in crash.txt and enable the button to show the crash text in the crash-window (r3965) - Codechange: Add additional linker information to release builds to help figure out crashes more easily (r3526) - Fix: [OSX] Cannot save game if name contains german umlauts (loading savegames with certain chars still look odd) [SF#1157244] (r4038) - Fix: [OSX] Major speedup for PPC fullscreen (r4034) - Fix: [Makefile] Make sure the ICON_DIR gets created before copying files there (r4032) - Fix: [Windows] Change compiler settings to use the multithreaded CRT. This prevents certain crashes on multi-threaded machines (r4031) - Fix: [NPF] Road vehicles planning through the back of depots and stations [SF#1453646] (r4029) - Fix: Use the title of a savegame in the saveload dialogue-editbox (r4018) - Fix: Improper resolution written to the configuration file when exiting from fullscreen (r4017) - Fix: When removing rail track from a tile where only X and Y pieces exist, explicitly update signals in both directions (r4016) - Fix: Default the patch-setting 'pause_on_join' to true (r4015) - Fix: Slope and height information returned for some tile types is wrong (r4014) - Fix: Fixes a bug introduced by r3228 which allowed steep rail tiles resulting in ... unwanted effects such as display artifacts (r4012) - Fix: Update french translation (r3978) - Fix: Missing glyph(s) in big-font. Added several missing glyphs for the big font [FS#56] (r3970) - Fix: Increase client list window width so at least most languages fit [SF#1439907] (r3969) - Fix: Update german and finnish languages (r3968) - Fix: Properly set back the owner of a crossing/road-under bridge after removing it (r3967) - Fix: [Autoreplace] Autoreplacing trains now keep their tile length instead of their pixel length [FS#67] (r3964) - Fix: Mark the right tile as dirty. It is just a graphical glitch which happened in r1592 (r3962) - Fix: Fix crash when resizing news history window (r3961) - Fix: Correctly implement minimum search, so road vehicles head towards the closest station, not the last one in the list (r3960) - Fix: The tooltips for raising and lowering land buttons in the scenario editor are interchanged [FS#61] (r3959) - Fix: Correctly restore the roadside after roadworks are finished (r3957) - Fix: [Multistop] Check the status of the destination road stop instead of a station's first road stop. This only has effect with road vehicle queueing disabled (r3956) - Fix: Validate the setting of max_companies/spectators through the console (r3955) - Fix: Improve game-load times (r3954) - Fix: On loading a game, GetPlayerRailtypes() did not account for the fact that vehicles are introduced a year after their introduction date. This will also relieve possible (rare) network desyncs (r3952) - Fix: Restore plural forms of cargo types for several languages (r3951) - Fix: [Windows] Add directives to allow Visual Studio 2005 compilation (r3950) - Fix: Crash in string code with openbsd/zaurus; alignment issues [SF#1415782] (r3948) 0.4.5 (2006-01-31) ------------------------------------------------------------------------ - Feature: [NewGRF] Implement varaction2 property 0x41 and 0xDA (r2361) - Feature: Giving server_ip a value of 'all' will make the server listen on any interface (r2374) - Feature: Shortcut CTRL + U that clears the current input-box (r2385) - Feature: [NewGRF] Implement the mechanism for handling NewGRF callbacks (r2389) - Feature: [NewGRF] Implement the 'refit capacity' callback (r2389) - Feature: Saving games happen in a separate thread (r2391) - Feature: [NewGRF] Implement powered wagons, and the callback that goes with it (r2414) - Feature: [NewGRF] Implement shorter train vehicles (r2428) - Feature: New display option: 'transparent station signs' (r2438) - Feature: You can now give transfer order to set up feeder systems (r2441) - Feature: Removing tracks with the 'remove' tool, automatically removes signals on the tracks (r2469) - Feature: [Localisation] Allow changing the order of parameters in translated strings (r2573) - Feature: [Localisation] New way to specify plural forms (r2592) - Feature: [Localisation] Support genders (r2594) - Feature: [Localisation] Support cases (r2597) - Feature: Add support for truncating strings to a given (pixel) length (r2607) - Feature: Overhaul DirectMusic MIDI backend, remove 'experimental' status (r2712) - Feature: Change the driver probing algorithm: Use the first music/sound/video which succeeds initialising instead of bailing out after the first. No need to specify -snull if no soundcard is present anymore (r2728) - Feature: The Main Toolbar Dropdown Menu can now display disabled items (r2734) - Feature: Clone vehicles (r2764) - Feature: When starting without a config file determine the language on basis of the current locale (r2777) - Feature: [NewGRF] Add support for 'extended bytes' (r2872) - Feature: [Localisation] Major step towards ISO-8859-15: Implement missing characters (r2879) - Feature: Implement the console command rm to remove savegames (r2941) - Feature: Danish town names (r2957) - Feature: Menu option to toggle console (r2958) - Feature: Calculate proportions of non-square giant screenshot correctly (r2963) - Feature: [NewGRF] Implement current set of action D (ParamSet) operations (r2968) - Feature: [NewGRF] Show a wagon's speed limit in purchase list (r2969) - Feature: [NewGRF] Support loading VarAction2 parameter for variables 0x60-0x7F (r2971) - Feature: [NewGRF] Add patch option for wagon speed limits (r2982) - Feature: [NewGRF] Support loading of bridge attributes and tables from GRF (r3004) - Feature: Native Support for Win64 (r3008) - Feature: OSX now uses quicktime to play midi files (r3022) - Feature: [OSX] Command+Q now works in main menu (r3027) - Feature: Allow unbanning players based on banlist-id (as well as IP) (r3067) - Feature: 'status' and 'clients' now show the IP of the players (r3067) - Feature: Make it possible to create a screenshot from the console that is both big and has no console, or any combination of (r3068) - Feature: [NewGRF] Add support for rail vehicle weight greater than 255 tons (r3071) - Feature: 'HOME' icon to saveload dialogues that jumps to the default save/load directory based on the dialogue (r3096) - Feature: Turkish translation (r3120) - Feature: [NewGRF] Support positioning of rail vehicle visual effects (r3132) - Feature: [NewGRF] Support for articulated rail vehicles (r3139) - Feature: [NewGRF] Add support for cargo refitting specification by cargo classes (r3148) - Feature: [NewGRF] Action 7/9 new value : is it TTDPatch or OpenTTD? (r3152) - Feature: Drag and drop rocky areas in scenario editor (r3153) - Feature: Added patch option to link the terraform toolbar to the rail, road, water and airport toolbars (r3157) - Feature: Right-Click-Scrolling optionally moves in the opposite direction (r3222) - Feature: Native cocoa sound and video drivers for OSX (r3281) - Feature: [NewGRF] Allow train running cost class to differ from engine class (r3388) - Feature: Kick and ban now with IP numbers (r3407) - Feature: Allow seeing and setting the maximum amount of companies and spectators for a server. This can be changed/viewed during runtime as well in the console (r3427) - Feature: Allow the network game list to be sorted (by name/clients/compatibility ascending/descending) (r3441) - Feature: Make it possible to ban offline clients (r3469) - Fix: The refit window now shows the correct refit options (r2365) - Fix: Refitting to a cargo which is already carried by some vehicles takes their capacities into account for display (r2365) - Fix: Add 'multihead' TTDPatch option to OpenTTD NewGRF flags-emulation (r2368) - Fix: Make install tried to install scenarios in the (non-existing) personal dir when USE_HOMEDIR is specified (r2371) - Fix: [Console] Update the example scripts in the scripts/ directory to reflect the new console functionality (r2372) - Fix: [Console] Any line starting with a '#' is a comment so ignore it (r2372) - Fix: [Console] The special variables whose value can only be set by a custom process should, also print out their newly set value there (r2372) - Fix: [NewGRF] Ignore action 0 prop 0x20 (air drag) (r2377) - Fix: [NewGRF] Further property stubs, help prevents subsequent incorrect reading of NewGRF data (r2378) - Fix: Build year for mail compartment of planes was not set correctly, affected station ratings (r2380) - Fix: Endgame window on easy difficulty resulted in infinite loop (r2381) - Fix: Check the airport type when building an airport (r2382) - Fix: Monkey-testing turned up some command crashes (r2383) - Fix: Check selling land and setting player colour. Also an extra map-bounds check for terraforming (r2384) - Fix: [Realistic acceleration] Very slow trains no longer get an increase in maximum speed when part of them is in a depot (r2388) - Fix: [NewGRF] Load power for dual-headed engines correctly (r2400) - Fix: [NewGRF] When resolving callbacks, don't ignore wagon overrides (r2410) - Fix: Station ratings are not affected by speed limits from realistic acceleration anymore (r2411) - Fix: Building vehicles without depot crashed the game (r2412) - Fix: Certain resolutions caused a crash when minimap was partly dragged outside the game window (r2424) - Fix: Deleting canals under bridges removed bridges first in certain configurations (r2436) - Fix: [NPF] Vehicles try to drive into a tunnel entrance from above (r2471) - Fix: [NewGRF] Some road vehicle action 0 properties were loaded as the wrong type (int8, int16, int32) causing undefined results, like cargo types being wrong (r2474) - Fix: The console variable autoclean_unprotected was linked to the variable _network_autoclean_protected (r2498) - Fix: Old bug in the PCX writer: The first pixel column contained garbage, the picture was shifted one to the right, and the last column was dropped (r2512) - Fix: Using the mouse wheel could lead to a crash if mouse was not over a widget (r2530) - Fix: Blinking 'lock' gfx in multiplayer games (r2548) - Fix: Remove original train pathfinder. Enhanced old pathfinder (r2553) - Fix: Spaces in the path to the MIDI files caused the Windows MIDI player to fail (r2563) - Fix: Set server map name to the loaded name of the game/scenario (r2610) - Fix: Improve the old pathfinder. Changed it to A* instead of Dijkstra. Benchmark shows that NTP is now around 10x faster than NPF (r2635) - Fix: Correctly save and load company_value, it is 64 bits wide, not 32 bits (r2684) - Fix: Volume control works now for the DirectMusic MIDI backend (r2712) - Fix: Change the fence algorithm so it removes fences when no farm tile is adjacent (r2739) - Fix: Tree tiles above the snow line got redrawn disproportionately often (r2750) - Fix: Depots could build trains of the wrong track type (r2764) - Fix: Sort the directories in the scenario/savegame list (r2860) - Fix: On OS/2 show the trailing \ if the current directory is a root directory (r2860) - Fix: Return a proper version number, when testing the TTDPatch version in the SkipIf action (r2862) - Fix: Change the way NewGRFs are loaded, this saves quite some sprite slots - about 2000 for DBSetXL for example (r2868) - Fix: Several format string vulnerabilities and buffer overflows in the network code [CVE-2005-2764, CVE-2005-2763] (r2899) - Fix: Fixed issue where autorenewed vehicles did not get all stats updated (r2912) - Fix: Exit the child of the extmidi backend with _exit() instead of exit(), because we do not want any atexit handlers - especially flushing output streams - to run, if exec() fails (r2938) - Fix: Server crash with 'say'-command (r2950) - Fix: Fix Windows midi volume level control which did not work (r2960) - Fix: [OSX] Quitting the game no longer leaves a process behind that eats all the CPU power (r3281) - Fix: Fix for UFO-broken waypoint [SF#1216203] (r2961) - Fix: [NewGRF] Include missing grf feature canal - Fix: [NewGRF] Add bounds checking to VehicleChangeInfo for vehicles - Fix: [NewGRF] Wagon speed limits do not apply for wagons with livery overrides - Fix: Align settings pool items to the size of void* to fix bus errors on 64bit architectures which require aligned variables (r2976) - Fix: Restart_game_date is an UINT16, not a BYTE. Now setting the game restart year via the console should work (r2987) - Fix: [NewGRF] Some GRF files do not specify a name or description, in which case the Action 8 is 8 bytes, not 9 (r3005) - Fix: The finnish markka was never abbreviated with capital letters (r3021) - Fix: Improve handling of non-existent sprite sets (r3044) - Fix: Do not attempt to map and empty sprite group to a vehicle (r3045) - Fix: Fixed typo and hang for BeOS Networking (r3053) - Fix: On Win98 and lower when you go to the root directory of a drive (eg. C:\) you were stuck there indefinitely and could not change any directories or see any files (r3056) - Fix: Complete rewrite of autoreplace; multiheaded train engines are replaced correctly (r3081) - Fix: A new train is now made if the front unit is an engine and the former front engine is moved away (r3144) - Fix: There are only 2 possible directions for ship depots, not 4 (r3199) - Fix: Allow bribing up to the maximum rating for bribing, do not disable this option at some arbitrary value early (r3201) - Fix: Do not lower land on tunnel, even with diag tracks on it (r3228) - Fix: Crash when making a screenshot in the main menu (r3235) - Fix: Crash when starting a scenario via 'New Game' fails (r3235) - Fix: Determine clicked status of sticky icon from window flags rather than the widget click state (r3247) - Fix: Graphical glitch with autorail tool on a certain tile-types (r3254) - Fix: Centre the X of the window close button (r3302) - Fix: [NewGRF] Unload engine names before loading grf files (r3316) - Fix: Network window crash when it receives invalid information for example from the integrated nightly, so validate the network-input when it is received (r3322) - Fix: Build failed if SDL is built without pthread support (r3326) - Fix: Move initialisation of vehicle random_bits to DC_EXEC blocks to allow use of Random() instead of InteractiveRandom(), which will alleviate some possib le network desyncs (r3352) - Fix: The default AI tried to change the service intervals of vehicles via the CMD_CHANGE_TRAIN_SERVICE_INT command - regardless of the type of the vehicle (r3367) - Fix: Out-of-bounds array access when road vehicles overtook in a curve caused desyncs (r3371) - Fix: Update signal states when building or removing rail station blocks (r3372) - Fix: Do not allow trains to get bigger than 100 via drag and drop (r3374) - Fix: Do not reset date in the scenario editor when pressing RandomLand (r3376) - Fix: [NewGRF] Running cost should be halved for dual head vehicles (r3384) - Fix: No fence was placed when placing fences and the neighbouring tile is a rail configuration which permits a fence but has a signal (r3389) - Fix: [NewGRF] Ignore non-climate dependent cargo types (r3394) - Fix: [NewGRF] Only add a random number of days to an engine's base introduction date if that date is not 0 (r3410) - Fix: When changing the server password via the console, actually set the password as well as flag whether it is required (r3411) - Fix: Under certain conditions placing a road tile parallel under a bridge would, instead of failing, succeed and place a perpendicular piece (r3413) - Fix: Disable the Fund New Industry menu item and window when connected to a server as a spectator (r3414) - Fix: Disable the clone and refit buttons in the train view when viewing another player's vehicles, or as a spectator (r3415) - Fix: Disallow building an oil rig above sea level (r3416) - Fix: When removing a town-owned tunnel the player's rating was not reduced (r3418) - Fix: (Possible) game crash on removing track/road under bridge if a vehicle was on the track/road under the bridge and the track/road sloped (r3419) - Fix: [NewGRF] Only power should decide whether a rail vehicle is an engine or a wagon (r3424) - Fix: Incorrect validating of tree-planting command which can allow a buffer-overflow (r3446) - Fix: [NewGRF] When changing the sprite ID of a vehicle, if it is not FD (custom graphics), the value needs to changed from a 16bit array offset to an array index (r3449) - Fix: You could not remove an item from a list-type of config ingame from the configuration file (r3475) - Fix: [NewGRF] Always reinitialise the TTDPatch flags as patch settings may have changed (r3486) - Fix: Price for demolishing a bridge was dependent on orientation and map size (r3487) 0.4.0.1 (2005-05-21) ------------------------------------------------------------------------ - Feature: Add 'clear' command and CTRL+L to empty console window - Feature: Add the possibility to print out the current debug-level - Fix: [MacOSX] Default path for midi player on mac is now correct again - Fix: Updated makefile for FreeBSD - Fix: Text overflows in about box - Fix: Link error while compiling as dedicated server - Fix: Do not execute empty commands - Fix: Make OpenTTD icon look good on Win2K and earlier - Fix: NetworkUDPRemoveAdvertise was not completely correct - Fix: Signs in multiplayer did not work - Fix: Dedicated server desyncs - Fix: Error: !invalid string id 0 in GetString, dedicated server endgame crash [SF#1197216] - Fix: Do not allow things to be renamed to nothing - Fix: Windows installer deletes spritecache files on uninstall - Fix: Depot window did not get redrawn when a non-train-engine was sold - Fix: Do not scroll the game with the arrow keys when the chatbox is open - Fix: Remove warning from release build when assertions are no longer active - Fix: It was possible to open more than one tree window 0.4.0 (2005-05-15) ------------------------------------------------------------------------ - Feature: Bigger maps. Enjoy playing up to 2028x2048 (64 times as big as you were used to!) - Feature: New realistic acceleration; should be much better. Includes bigger penalty on narrow curves and speedlimits in depots/stations - Feature: It is now possible to build multiple road stations (up to 8) on a single station - Feature: New PathFinder (NPF). Support for train/road and ship based on A*. No more braindead pathfinding - Feature: Dynamic towns/industries/stations/vehicles/signs/orders/everything, up to 64K - Feature: Brand new OldLoader so OpenTTD is TTD(Patch) compatible again. Also endian safe - Feature: Even better NewGRF support, except for callbacks, everything works (ok, almost) - Feature: Improved multiplayer. More console options, less desyncs and more fun - Feature: Protected OpenTTD from interference of hacked clients, so it should be safe to play again - Feature: Saving vehicle sorting criteria for each vehicle type [SF#1093261] - Feature: Resizable orders GUI [SF#1107690] - Feature: Focus keyboard on input-box in Multiplayer Menu [SF#1166978] - Feature: Terrain hotkeys nonfunctional in scenario editor (D,Q,W,E,R,T,Y,U fltr) [SF#1174313] - Feature: Complete rework of console and new commands like ls, save, load, help, etc - Feature: Signs are shown in the colour of the player who created them - Feature: Add cheat option to set production of raw-material industries in game - Feature: Replace train GUI remembers railtype selected from the dropdown menu - Feature: Improved Autoreplace - Feature: Many more smaller features - Fix: A wrong error message was displayed when trying to [SF#1108618] - Fix: Game does not crash any more when a NewGRF file does not exist [SF#1110407] - Fix: Clearing land for free by reallocating HQ [SF#1112469] - Fix: Clearing land for free by reallocating HQ [SF#1112469] - Fix: Crash when accessing hi-scores in editor, it is now disabled [SF#1113037] - Fix: Game no longer crashes when right-clicking a disabled Full Load button [SF#1113399] - Fix: Dedicated server boots again [SF#1114100] - Fix: Game crashed sometimes when there were no industries in the map [SF#1114950] - Fix: In the main menu, when starting a new game while the load game dialogue is open, openttd asserts [SF#1115200] - Fix: Non-stop orders are no longer accidentally skipped [SF#1117538] - Fix: Generate the correct smoke type for diesel trains [SF#1116619] - Fix: Max passengers/mail variables are now 32 bit [SF#1119308] - Fix: Better test if a string actually contains any console command [SF#1109400] - Fix: 'Play scenario' now loads game options and difficulty, 'Load game' starts game with user-selected values [SF#1108637] - Fix: Carriages of NewGRFs can be refitted again [SF#1143587] - Fix: Production values of temperate-climate banks can now be altered [SF#1117730] - Fix: Mapwrap fixed in ship_cmd.c (was implicitly ok before biggermaps) [SF#1118810] - Fix: Assertion error on kick. When a company is cleaned all its windows need to be closed. For global vehicle lists, the no-station index of -1 was not taken into account [SF#1117327] - Fix: Speeding up when pressing ALT+TAB (Windows) [SF#1114261] - Fix: Signals disappear after typing text and pressing enter!. Signs in Scenario Editor have no owner so ignore that [SF#1149403] - Fix: Single tile Bridge in Volcano City scenario. Some bridges still had the old single-tile bridge bug that was caused by improper town growth in combination with DC_AUTO. Fixed the scenario [SF#1149766] - Fix: Stop startup memory corruption crash using optimised MSVC6. MSVC6 workaround as it is too stupid again for its own good [SF#1119147] - Fix: Dedicated server now accepts '-g' (load game) as param [SF#1101874] - Fix: Crash with German umlauts in station names [SF#1155696] - Fix: Segmentation fault when loading savegame, out of bounds array check [SF#1158618] - Fix: Autosave ignoring settings [SF#1149487] - Fix: [Windows] Infinite access for A:\. Only requery drive(s) if the user changes a directory, also suppress the OS error box that pops up on some windows machines [SF#1024703] - Fix: Create Lake and draggable Create Desert tools [SF#1095110] - Fix: Trains 'Go to depot' button: click twice skip to next order [SF#1172878] - Fix: Engine power not updated w/auto replace' autoreplace now forces an update of the cache [SF#1146215] - Fix: [Windows] Path displaying as 'C:\\' [SF#1173690] - Fix: Click & drag removal of road assertion fail [SF#1179892] - Fix: Max loan always in euros, use _opt_ptr instead of _opt [SF#1174237] - Fix: AI orders its vehicles to a competitor's truck stop [SF#1184201] - Fix: Song in main menu screen should loop when it ends [SF#1188986] - Fix: Non-existing sprite #5125 (presignal). The DOS grf file trgi.grf has 6 less sprites than the windows one [SF#1188777] - Fix: Changing mapsize crashes game with highlighting [SF#1190625] - Fix: [NPF] Trains ignoring their railtype (mono, maglev) [SF#1190896, SF#1184378] - Fix: Clicking ship list on buoy asserts GetPlayer() [SF#1202115] - Fix: No HQ present for competitor, disable 'View HQ' button [SF#1187613] - Fix: Pre-signal stays red when there is only a single exit signal [SF#1193048] - Fix: Train in tunnel is not properly detected by signal code [SF#1185176] - Fix: [NewGRF] Rotors of custom helicopters are displayed correctly in the hangar window - Fix: Scenario Editor now handles human-made roads better (try to build a city layout before placing the city, finally that works very nice) - Fix: [NewGRF] Helicopters are correctly recognised - Fix: [Autoreplace] Made sure that planes only show planes in replace GUI and helicopters only show helicopters - Fix: Crash when generating tropical maps - Fix: [Autoreplace] Cheaters can no longer exploit autoreplace to get vehicles, that is not invented yet - Fix: [Autoreplace] Fixed a stupid bug introduced in r1687, that made a crash if anybody tried to autoreplace anything but an aircraft - Fix: Expand rail stations beyond maximum spread - Fix: [Autoreplace] Fixed a typo that could prevent autoreplaced aircraft from automatically go to a hangar - Fix: Hacked clients can no longer be used to build vehicles that are not available yet - Fix: Minimum profit of vehicles was calculated wrong for Performance Rating - Fix: No longer a station where you only unload is bad for your town-rating - Fix: Crash in scenario-editor with terraforming out-of-map bounds - Fix: Game would crash if you full-screened with the 'fullscreen' button than chose a resolution from the dropdown box that was no longer valid - Fix: Scrolling with the arrow keys is now smooth and it now also scrolls exactly in tile direction if e.g. up and left are pressed 0.3.6 (2005-01-24) ------------------------------------------------------------------------ - Feature: Resizeable windows. All useful windows are already made resizeable - Feature: Highscore chart (accessible from the difficulty window) with top 5 companies for a given difficulty (select the difficulty in the menu) - Feature: Endgame score on 1 Jan 2051 where you are added to the highscore if sufficiently large points have been accumulated. Game is paused while - Feature: Visually enhanced autorail placing - Feature: Autoreplace Vehicles (accessible from the vehicle lists) - Feature: A counter to tell how many engines you have of each type to the autoreplace vehicle windows - Feature: A display for the total map population to the town display - Feature: [Network] RCon (Remote console) - Feature: Hotkeys for dock and airport toolbar (see http://wiki.openttd.org/index.php/Hotkeys) - Feature: [Network] Banning system (mostly tnx to guru3) A server can ban people via ClientList using 'ban', 'unban', 'banlist' - Feature: [Network] Server can now pause and unpause a game through the console. Use 'pause' and 'unpause' - Feature: [OS/2] OS/2 support is now finished (Fixes for networking, file selection, keyboard input, plus many other minor issues) - Feature: [SDL] Show revision number in window title - Feature: [Unix] Check which gcc version is present and only set available compiler flags - Feature: [Windows] CTRL+V (Paste) now works on all editboxes. This includes 'Add Server', chat, etc - Feature: [Windows] Dedicated server is now functioning correctly - Feature: Added keyboard shortcuts for the order window - Feature: Aircraft refit options have been restricted to 'sane' values - Feature: Allows setting the production values of the raw material producing industries in the editor - Feature: Console support for loading maps. Use 'load', 'list_files' and 'goto_dir' to navigate and load games - Feature: Display server port in the multiplayer game info window - Feature: Dynamite in landscaping toolbar (hotkey 'D') - Feature: Improved Network Lobby GUI with a green dot if company income is positive (else red dot) and lock icon if company is password protected - Feature: Make OpenTTD compile on Zeta - Feature: MD5 hash check for TTD files - Feature: New companies receive a 5-year protection period against buying-up - Feature: Norwegian townnames - Feature: Order Checking is only execute for ONE vehicle in an order-share system - Feature: Passengers aircraft now ignore the amount of mail for 'full load any' options - Feature: Place multiple accepting industries nearby in the editor mode if the appropriate patches are set - Feature: Population in label of the town (patch setting) - Feature: Scrolling credits list (in alphabetical order) - Feature: Train window now shows the number of vehicles per row - Feature: Swiss town-names [SF#1039061] - Feature: Adding 16:10 resolutions for mainly laptops [SF#1090950] - Feature: (dis)Allow Shares. Add patch options to allow buying/selling of shares [SF#1098254] - Add: A brand new set of icons - Change: AutoRenew is now a client-side patch instead of a game-side patch - Change: Removed the 'close ALL windows' from the toolbar since shift+del does this - Fix: Catchment area shows when buying sign [SF#1031451] - Fix: Flood and wagons in depot [SF#1040119] - Fix: Buying trains sometimes accounted for incorrectly [SF#1050990] - Fix: Delayed news messages [SF#1084074] - Fix: Slopes under high bridges were not flooded [SF#1090495] - Fix: In scenario editor, when trees are placed randomly, they are no longer placed on farmland [SF#1092473] - Fix: On create, the scrollbar of the server-list was not updated [SF#1092661] - Fix: Placing rocks in scenario editor. You can place rocks on trees and vice versa [SF#1092707] - Fix: Drive side in new games. Setting the driver side is possible during the game until someone buys road vehicles. In networked games only the server can change it [SF#1093200] - Fix: No more glitches with many maps in the scenario list when creating server [SF#1093466] - Fix: Disappearing rocks in Scenario Editor [SF#1093485] - Fix: Toolbars accessible via keyboard in spectator mode [SF#1094092] - Fix: When all stations in an aircraft's order list are demolished, the plane eventually crashes (running out of fuel) [SF#1095020] - Fix: Servers list now also saves the port [SF#1095143] - Fix: Crash when all vehicles from a vehicles per station list had been removed [SF#1098553] - Fix: Starting year patch goes out of range. Clamped year between 1920-2090 [SF#1099101] - Fix: Bug Fix - Vehicle Lists not updated at Acquisition [SF#1099225] - Fix: Game crashes after the click on Rename (see also Bug 10992). There was no check for non-selected engine [SF#1099451] - Fix: Wrong tooltip for place desert button [SF#1100736] - Fix: Fast forward in main menu [SF#1100767] - Fix: Crash if generating land while industry window is open. This also happened for towns and the land information window [SF#1101179] - Fix: Configure Patches window text overflow [SF#1101906] - Fix: Console in dedicated server [SF#1101963] - Fix: Game crashed when clicking 'new face' or 'company colour' twice [SF#1102275] - Fix: Vehicle lists are now redrawn when a vehicle arrives in a depot. Station-specific vehicle lists are now redrawn daily as well (not only the master list) [SF#1099535, SF#1102776] - Fix: Font size changing. Dedicated server did not have code filtering, 'tab' could result in bigger fonts [SF#1103113] - Fix: Order Check messages are now validated before displayed [SF#1103187] - Fix: Rail road tracks on slopes were not flooded [SF#1103301] - Fix: Crashed trains do not initiate the lost vehicle message anymore [SF#1104350] - Fix: On horizontal/vertical tracks you are also charged for building/removing signals on the parallel track on the same tile [SF#110452] - Fix: Aircraft in hangar messages are now revalidated before display [SF#1104969] - Fix: Destroyed train locks crossings [SF#1105112] - Fix: Upgrade rail fails when train under bridge [SF#1105281] - Fix: Trains do not think they are on a slope any more while they drive around in a tunnel [SF#1105959] - Fix: Buoys can now only be removed if no ship has it in their schedule. This makes buoys more usable in multiplayer games again, as buoys cannot be deleted by other players if they are used [SF#1105963] - Fix: Graph's keys get confused [SF#1106354] - Fix: Placing signals with 2x1 drags is treated as placing a single signal [SF#1106930] - Fix: Console ignoring return character occasionally [SF#1107350] - Fix: Scenario creation bug; engines are of correct year when scenario is saved [SF#1108008] - Fix: Little red box in scenario editor [SF#1092474] - Fix: Scrolling through console sometimes crashed the whole game [SF#1099197] - Fix: Catchment area with drag&drop stations [SF#1099209] - Fix: [Network] 'kick 1' did crash dedicated servers - Fix: [Network] A server no longer crashes when a client sends an invalid DoCommand, but drops the client instead - Fix: [Network] Added packet protection. No longer a client or server - Fix: [Network] Bug in bind system. Advertising failed on systems with more than 1 ip, and server_bind active to one of them - Fix: [Network] Disabled 'money-cheat' (read: bug which could give people a lot of money) - Fix: [SDL] Now the binary never links to SDL if DEDICATED is set - Fix: [Windows] Somehow mousewheel was disabled on windows using SDL; re-enabled again - Fix: A modified client could try to replace a vehicle to an invalid engine ID and crash the server - Fix: Autoreplace vehicle lists are now redrawn when a new vehicle becomes available - Fix: Buy Vehicle GUI now shows HPs bigger than 32000 correctly - Fix: Console alias, load_game functionality and load fix - Fix: Correct error message for when trying to build a rail station over a bus/truck/etc-station - Fix: Correct landscaping buttons in monorail and maglev toolbars - Fix: Dedicated server also writes to log file if active - Fix: Desert-landscape does no longer crash - Fix: Expand town is a bit more aggressive - Fix: Finally zooming in/out always works - Fix: Fixed chat-bug (that from a certain moment, nobody could talk) - Fix: Fixed weight for double-head trains and with that the acceleration (now maglev lvl4 can reach their top speed, and are faster than lvl3) - Fix: Full-Loading trains no longer get 'lost' after a while - Fix: Graphs were not updated correctly when one graph with a certain selection was already open and another graph window was opened - Fix: In multiplayer clientlist can only be opened once - Fix: Loan does not count against the company value - Fix: Nasty bug where one could build one station OVER the other - Fix: No crash when creating a game with New English town names any more - Fix: Now helicopters will use a hangar in schedule to be replaced in, even if they are only set to service there. Since helicopters are serviced at helipads, they will only go there if they needs to be replaced or renewed. They will also use a hangar in an airport in the schedule if needed - Fix: Only a server can rename a town in a MP game - Fix: Really old maps do load again - Fix: Refit engine button is now disabled when cargo capacity equals zero - Fix: Server issue where some company names were wrong - Fix: Ship Vehicle Lists are now redrawn correctly - Fix: Signal stays red if a track is removed - Fix: Solve AI related order-problem - Fix: Starting openttd with -g now acts normal - Fix: The cost for an autorenew was not always send to the right player ;) - Fix: Autorenewing multiheaded train engines now costs the correct amount. Used to be twice the correct price - Fix: The scrollbar in the network gui (server list) now updates when scrolling - Fix: Train crashes should no longer desync the game - Fix: When deleting an order, the next pointer was not cleared, resulting in some unusual behaviour from time to time - Fix: You can now also delete automatically found servers by pressing 'del' - Fix: You should no longer be able to delete bridges on any type of underground when there is a vehicle on it 0.3.5 (2004-12-24) ------------------------------------------------------------------------ - Feature: [Network] New network, very stable, a lot of new features - Feature: [Network] Ingame Serverlist (with online game-servers to join) - Feature: [Network] Webbased Serverlist: http://servers.openttd.org/ - Feature: [Network] Added dedicated server support - Feature: [Network] Cheat protection in MultiPlayer - Feature: [Network] Patch settings are also synced with the server - Feature: [Network] Chat - Feature: Custom currency settings - Feature: Per-station vehicle lists - Feature: More realistically sized catchment areas - Feature: Sticky windows - Feature: Even better support for NewGRF-files - Feature: Implement improved vehicle loading algorithm - Feature: Even more advanced console - Feature: Game compiles under BEOS_SERVER - Feature: Game compiles under OS/2 (no network-support) - Feature: OpenTTD runs with the grf files of the DOS version - Feature: [Big Endian computers, which are mac and MorphOS] Load savegames by TTD(Patch) - Add: 'l' opens the landscaping toolbar globally - Add: Make the town sometimes build streets on slopes - Add: Manpage - Add: New checkpoint graphics - Add: SHIFT+DEL now deletes all non-vital windows (only status bar and main bar remain) - Add: Windows now shows revision, release information in title bar - Add: Windows snap at each other - Add: Spanish, Catalan and Icelandic - Change: [OSX] Moved data and lang folders inside OpenTTD. This got rid of the package system too, making installing/updating easier - Fix: [OSX] Music is now on by default again - Fix: [OSX] Made error opens the console - Fix: [SDL] Added a confirmation dialogue when quitting the game - Fix: A train can leave and enter the same depot at the same time, then the train simply got stuck - Fix: Crash when making png screenshot with odd resolution - Fix: Directories in *nix are now sorted alphabetically in ascending order - Fix: Do not consider a road station as street when growing the town - Fix: Engines from other climates do not appear any more when never_expire_vehicles is enabled - Fix: Game options (like drive side) are not taken from the scenario when using 'new game' command - Fix: Order checker now correctly detects station with invalid facilities - Fix: Polished GUI in a lot of ways - Fix: Saving or loading a map doesn't pauses the game anymore - Fix: Some bridge part is not displayed transparent in transparent mode - Fix: Starting with -r option allows all resolutions - Fix: The pathfinder no longer sees rail with another owner as a possible route - Fix: Unable to select other screenshot format in Game Option - Fix: Unwanted town renaming - Fix: Vehicles slow down under bridge if the track is on a foundation - Fix: You can no longer change name of waypoints whom are owned by somebody else - Fix: Shares are now also sold when a company goes bankrupt [SF#1090313] - Fix: It is no longer possible to crash trains of other companies by building a depot close to a station; trains do no longer enter tiles that do not belong to his owner [SF#1087701] - Fix: Crashed trains are not reported to have too few orders any more [SF#1087403] - Fix: Backup-order-list was not closed with an OT_NOTHING, [SF#1086375] - Fix: Docks now have a button to display the catchment area [SF#1085255] - Fix: Invisible trains. Weird macros and MSVC optimising do not always mix [SF#1070274] - Fix: Number of passengers and mail in exclusive test offer window is swapped [SF#1068269] - Fix: Pause key pauses the game [SF#1066504] - Fix: Resetting file name after deleting a file [SF#1066121] - Fix: Code error in win32.c Thanks Shai [SF#1066114] - Fix: Windows can be placed behind toolbar [SF#1065247] - Fix: Editor Map-Menu wrong String [SF#1064742] - Fix: Always report a bus/lorry station as impassable [SF#1058809] - Fix: Refit train window stays open [SF#1053397] - Fix: Incorrect Tooltip in Road Vehicle List [SF#1050993] - Fix: Monorail and Maglev sounds are swapped [SF#1048596] - Fix: Flooded wagons in depots do not keep constantly exploding any more [SF#1040119] - Fix: Bug about lowering tracks built on slopes [SF#1035303] - Fix: 'Allow goto depot' turned off, no checkpoints in orders [SF#1035066] - Fix: Place sign and blue message box [SF#1034318] - Fix: Wrong mapping between music titles and songs [SF#1033947] - Fix: Some screen sizes crashes OpenTTD. Fix in general bug that only allows resolutions which were multiple of 8 in width and height. Also use closest possible resolution in fullscreen if window size is not a valid resolution [SF#1030393] - Fix: 'Service at' orders ignored after 2090. After 2090 year is reset to 1. Jan 2090, so most of the time, last service was in the future and no service ensured [SF#1030275] - Fix: Building a station acted weird in some rare situations [SF#1029064] - Fix: Ships could unload cargo at stations without docks [SF#1022227] - Fix: Wrong trees (toyland's) in sub-tropical landscape style [SF#999669] - Fix: High bridge rendering error [SF#993500] - Fix: Disabled buttons flicker no more [SF#991101] - Fix: Start/stop flag in train depots always works, regardless of the horizontal scroll position [SF#985925] - Fix: Un-owned rail. Trains could cross competitor's tracks if there was a road-crossing over it [SF#985439] - Fix: Pathfinding bug; train likes the roundabout. If train needs servicing it will now look 16 tiles along the track instead of 12 tiles Manhattan style [SF#982611] - Fix: Fullscreen. New button 'Fullscreen' in 'Game Options' menu which lets you set fullscreen ingame [SF#967096] - Fix: No longer road/rail crossing signals hang when a train is reversed at the wrong moment [SF#958098] - Fix: Ctrl + d bug. Longest outstanding bug has been fixed [SF#926105] 0.3.4 (2004-09-14) ------------------------------------------------------------------------ - Add: Dutch translation - Add: Generalised A* Algorithm - Add: Generalised queues (Fifo, Stack, InsSort, BinaryHeap) - Change: Changed 'terraforming' to 'landscaping' - Change: Changed default options (road side, distance units, currency) to most commonly used options - Change: Disable 'Submit Report' and 'Show Details' on OpenTTD error window on Windows. Currently of no use, since no developers have assembly knowledge - Change: Removed patch no_train_service. Instead you can set the default service interval for any vehicle type to 'disabled' - Codechange: Comments added to the code - Codechange: Made bridge building code more readable [SF#996244] - Feature: 'None' as option for number of industries in difficulty settings - Feature: Add many random industries and towns in scenario editor - Feature: Added Autosignals, just like Autorail. Can copy signal style, convert signal<->semaphore, etc - Feature: Added level land button to scenario editor - Feature: Added never_expire_vehicles to patches GUI - Feature: Added new icons for landscaping toolbar - Feature: Added original vehicle names file. Select it from the list. Vehicles will have real name, all other strings are in English - Feature: Added/heavily modified patch by truesatan cheat change date - Feature: Align toolbar left/centre/right patch - Feature: All TTDLX kind of savegames are supported (.SS1, .SV1, .SV2, .SV0, .SS0) - Feature: Alpha version of a new AI - Feature: Autodetect server in LAN via udp - Feature: Build_date of station (viewable with Query tool) - Feature: Cheat switch climate - Feature: Company HQ can now be moved somewhere else (cost 1% of company value). Water floods HQ - Feature: Competitors menu under patches - Feature: Copy/share orders now works from ship depot window for ships and hangar window for aircraft - Feature: Difficulty settings window has been changed - Feature: Enable/disable all buttons in message settings - Feature: Executable is now openttd(.exe) always - Feature: General protection around Sprites - Feature: Ingame console - Feature: Invalid (void) orders in schedule are highlighted in red - Feature: Invisible trees when in transparent mode (patch entry) - Feature: Option to sort vehicles in vehicle-list window by different criteria - Feature: Performance details window in company league menu - Feature: Proper crediting to graphics artists to about box - Feature: Removing town roads has been fine tuned - Feature: Safeguard against invalid values in Patches window. Values will stick to their defined min and max values - Feature: Sorting savegames, scenarios by name/date - Feature: Terraforming toolbar (in the plant tree menu) - Feature: The extra dynamite patch has been changed a bit - Feature: Warning when a vehicle has invalid orders - Feature: Water floods everything, including vehicles - Feature: Working multiplayer gui - Feature: No extra frequent jet crash on small airports [SF#976127] - Feature: Scrollto Station in Orders. CTRL click on orders of a vehicle and main-window scrolls to that station [SF#992998] - Feature: Improved industry directory [SF#997115] - Feature: Euro introduction news item [SF#1003350] - Feature: Percent-based service intervals. Send a vehicle to depot after it has lost X% of its reliability [SF#1009708] - Feature: Extra Viewport [SF#1009710] - Feature: Show max loan in finances window [SF#1024044] - Fix: (Unix) loading old scenarios (.sv0) works again - Fix: 64bit CPU fixes - Fix: 64x64 stations are now nicely painted - Fix: A lot of network fixing - Fix: A lot of old AI fixed - Fix: All scenarios, savegames show up with their correct name - Fix: Automatic oil refinery generation in editor - Fix: Autosave folder was not created on MorphOS - Fix: Bridge slope fix again - Fix: Bulldozing stuff with cheat magic_dynamite turned on does not lower city ratings - Fix: Change SDL_HWSURFACE back to SDL_SWSURFACE (Diablo-3D); better performance - Fix: Coast line near edge of map and near oilrigs - Fix: Company-value was not updated immediately if legend was changed - Fix: Delete canal under bridge was not possible - Fix: Disable Fast Forward in network games visually (did not work anyways, just showed graphical output) - Fix: Error message for 'game load failed' when no town is in a scenario - Fix: Game not pausing when saveload dialogue is clicked in main menu - Fix: Load Scenario fix - Fix: Make Endianness check 100% accurate - Fix: Memory leak in news system - Fix: Monorail/maglev became available around 1927 - Fix: Move around sort-widgets a bit so it looks more natural - Fix: Music now finally works on WinXP. DirectMusic is now default for an OS >= WinNT4 (WinNT4, Win2k, WinXP), and MIDI driver for lower OS's (Win95, Win98, WinME, etc) - Fix: Old scenarios have correct colour - Fix: Placing/editing signs signs is possible in paused mode - Fix: Player window fixes, Getstring id0 fixes, Finances window is now ok - Fix: Playing new game with scenarios in windows works - Fix: Possible to disable some patches (e.g. default service interval) again by setting them to 0 - Fix: Problems around exclusive transport rights - Fix: Rail road crossings on slopes are now possible - Fix: Random crash when player-face was displayed in error-dialogue - Fix: Rare mousewheel scrolling with scrollbar crash - Fix: Road vehicles do not get stuck any more at stations - Fix: Savegames are sorted with newest date first by default - Fix: Scenario editor now asks before it generates a random landscape - Fix: Slopes graphics fix - Fix: Small gap between station button and signal button in rail toolbar - Fix: Some minor fixes around GetTileTrackStatus - Fix: Sorter icon pointing down 'v' sorts in every window lowest value first, '^' highest value first - Fix: Starting a new game in DesertLandscape crashed the game - Fix: Stupid bug in company league window if non-player is first - Fix: Two non-AI players when loading a scenario - Fix: Unix uses same sorting of directories, files as windows - Fix: When adding parts to a station max size is not 15x15 anymore, but _patches.station_spread - Fix: Win98 crashes related to music/sound - Fix: Wrong building of road-slopes for a future AI/Town - Fix: Wrong pathfinding when northern station tile is missing - Fix: You cannot take ownership of an oilrig by building right next to it - Fix: [Makefile] Fixed issue where sdl-config was needed even on systems without SDL - Fix: [SDL] Performance fix fo palette animation and mouse jumping - Fix: [SDL] Same resolution was displayed more than once in game options - Fix: [SDL] Smoother mouse and performance fix, like in the Windows video driver - Fix: Wrong trains you can buy with scenarios [SF#963056] - Fix: Minimap crash [SF#972087] - Fix: Bug in 'weird non-uniform stations handling' [SF#972247] - Fix: Parent_list was too small [SF#976583] - Fix: Memory leak in parent_list [SF#981934] - Fix: Max_loan in editor bug [SF#982666] - Fix: Bridge building over boats [SF#987888] - Fix: Cargo delivery area patch for bug [SF#990770, SF#989322] - Fix: No tunnel crash [SF#992726] - Fix: Light House Placement Bug [SF#993339] - Fix: Pressing alt locks the game - sort of a bug [SF#993374] - Fix: Buildings on water [SF#993493] - Fix: No canal building under bridge [SF#993512] - Fix: UDP Fixes [SF#993829] - Fix: Train drivers dies two times [SF#994067] - Fix: Road depot - bus/lorry station [SF#994720] - Fix: _local_player fixes. Fixes wrong memory access [SF#996025] - Fix: Bridge Bug fixed bug fixed again [SF#996065] - Fix: Weird two tile bridges on slopes [SF#996065] - Fix: Empty strings in signs [SF#997303] - Fix: Junction after tunnel bug [SF#997703] - Fix: 'autosave' directory creation (MorphOS/AmigaOS) [SF#999592] - Fix: I lost all wagons. Half-assed fix for lost wagons. But now users can at least fix this problem. Consolecommand 'resetengines' [SF#1001540] - Fix: BuildRoadOutsideStation fix [SF#1006530] - Fix: Autorenew issues [SF#1006715] - Fix: Copy orders between bus/truck possible [SF#1007272] - Fix: Scenario editor pause bug [SF#1007630] - Fix: Signals not updated after ClearTunnel Bug [SF#1008605, SF#985920] - Fix: Too many save games prevented loading [SF#1009385] - Fix: Problem with transferred cargo crashes game [SF#1009567] - Fix: Build in pause is now a cheat instead of a patch [SF#1009621] - Fix: Wrong multihead selling [SF#1009631] - Fix: Turning on the magic bulldozer removes oil rigs [SF#1010833] - Fix: Drunk pilot [SF#1012086] - Fix: TileAddWrap() gave wrong results [SF#1014278] - Fix: Cached_sprites does now work again [SF#1016954] - Fix: Bug when dragging a part of a multiheaded engine to 'sell-whole-train' [SF#1022689] - Fix: Fix for MouseWheel assert error in non-zoomable viewports. Zooming now will only occur if mousepointer is either in an extra viewport window, or main game-window [SF#1023971] - Fix: Company value problem (again). Now company value rightly shows the value, including ALL your money [SF#1025836] - Fix: Company values bigger than int32 were put to negative [SF#1025836] - Fix: Long bridges had negative value [SF#1025836] - Fix: Vehicle depots not transparent with transparent buildings [SF#1026271] 0.3.3 (2004-07-13) ------------------------------------------------------------------------ - Feature: MorphOS/AmigaOS network support - Feature: Improved German town name generator - Feature: Transparent station signs - Feature: Show total cargo per wagon type in train details window - Feature: Bridges on slopes - Feature: Added Galician translation - Feature: Extra dynamite, allow the removal of town-owned roads, bridges, tunnels for a popularity rating penalty - Feature: Magic bulldozer cheat, that lets you remove industries, unmovables and town-owned buildings, roads and bridges - Feature: Enabled 'remove' button for stations - Feature: Cheat GUI (activate with ctrl-alt-c) The game remembers if you have used a cheat - Feature: Station sort implemented using qsort() - Feature: Station list shows #of stations owned by player - Feature: Split canal/lock tool in two tools, one for building canals, one for locks - Feature: Make the HQ generate passengers and mail - Feature: Display number of houses in town overview window - Feature: Land info now shows type of signal - Feature: Realistic train reversing - Feature: Added support for 64 bit CPUs - Feature: Added water quantity level 'very low', which is the default for easy mode now - Feature: Realistic acceleration turned on, train must first slow down and stop before it can reverse - Feature: [MorphOS] Various small improvement to make the the game feel more native - Feature: Alt + f now toggles full screen (alt + enter still works) - Feature: [OSX] Command + q shows the quit window and command + f or enter toggles full screen (alt and control still works too) - Feature: Autorenew, autorenews vehicles if enabled - Feature: (Incomplete) news history window - Feature: Larger smallmap size - Feature: Austrian Citynames - Feature: Repaying most possible debt - Feature: Added Polish translation - Feature: Added Danish translation - Feature: Initial GRF support.You have to enable it in openttd.cfg using [NewGRF] setting - Feature: Smooth economy changes - Feature: TTDPatch-style gotodepot. Ship depots and aircraft hangars can be inserted in the schedule as well - Feature: Ability to add 'service if needed' orders (the 'full load' button changes to 'service' after selecting a depot order) - Feature: If a vehicle has depot orders in its schedule, automatic servicing is disabled - Feature: Patch setting so that helicopters get serviced automatically on helipad - Feature: Centre toolbar on screen - Feature: Sort savelist by date - Feature: Allow scrolling in both directions - Feature: Two new airports (metropolitan in 1980 and international in 1990) - Feature: Resizing the window in all SDL builds - Feature: Added MIDI flag to makefile to set custom path to midi player - Change: Autosaves are now placed in save/autosave - Change: Default savegame directory is /save in Linux - Change: Screenshots are saved to PERSONAL_DIR (unix) - Change: Scenarios now have the file extension .scn - Change: Default network port from 12345 (known trojan) to 3979 - Change: Crossing tunnels is now considered a cheat - Change: Made helicopters able to land on small airports again - Fix: Removing and upgrading tracks under a bridge when a train is on the bridge - Fix: Pause button was not synced in network games - Fix: Crash caused by invalid screen resolutions - Fix: AI can not build tubular bridges in 1950, etc. Same restrictions apply to it, as to human players - Fix: Volume, litres, was x100, should be x1000 - Fix: Bridge building by towns was screwed when executed without testing first - Fix: Better AI route finding - Fix: AI builds less inner-city bus stations - Fix: Better industry spreading on random maps - Fix: Two industries that accept the same goods can never be very close to each other - Fix: Destroying bridge (over water or 'higher bridge' with vehicle on it) - Fix: Game crashes when you hit the build rail button - Fix: Some scenarios had a max_railtype of 0 - Fix: Bribe Authority. A failed attempt to bribe is now also stored in savegame - Fix: 80% CPU load paused in fast-forward - Fix: Some airport runways were treated - Fix: Minor minimap glitch - Fix: Station sorting scroll fails with not enough stations - Fix: Desert ground for depots in the desert - Fix: Trains could run on wrong track type under bridges - Fix: Screenshot hangs - Fix: Wrong sound with ships - Fix: Toy shop closes even though it has supply - Fix: Nordic characters - Fix: Also restore Service Interval when rebuying vehicle - Fix: Crash with map bits > 8 - Fix: UFO crash in bus stop - Fix: Town actions has empty row - Fix: Train stuck with the head in one depot and tail in another - Fix: Optimised random radio tower spreading - Fix: Ground below trees is sometimes not covered by snow - Fix: Fast forward button in scenario editor - Fix: Screenshot hotkey does not function in scenario editor - Fix: Allow deleting a bridge if a vehicle is below - Fix: Crash loading a scenario - Fix: Build tracks on water - Fix: Fast forward button pressed with tab - Fix: Vehicles do not get old - Fix: Finance bug with some original scenarios - Fix: 'Stopped' is shown when train is stopping and 'Reverse' is clicked - Fix: 100% CPU bug - Fix: Crash when AI builds airport - Fix: Plays wrong music on main screen - Fix: Inflation was way too high when interest rate = 0 - Fix: Cannot sell anything if money is TOO negative - Fix: Fast forward button resets - Fix: 'Refit train' button remains - Fix: Enable up/down scrolling with the mouse - Fix: 1920 all trains - Fix: Wrong heli breakdown speed - Fix: Station list cargo waiting display bug - Fix: Bug that could allow rails on steep slopes - Fix: Train depots and checkpoints not flooded by water - Fix: Added command line option (-i) to deactivate the grf check - Fix: Signal bug [SF#949929] 0.3.2.1 (2004-05-23) ------------------------------------------------------------------------ - Feature: Now builds on FreeBSD - Feature: Now builds on MorphOS - Fix: Use english.lng by default - Fix: No bridges available in 1920 - Fix: Czech file was missing 0.3.2 (2004-05-22) ------------------------------------------------------------------------ - Feature: HP for trains limited to 16bit int - Feature: Added Czech translation - Feature: Train refitting - Feature: Auto euro - Feature: Industry directory - Feature: Added extend vehicle life/noexpire patch - Feature: Show revision number in title bar - Feature: Random network games - Feature: Smallmap remembers size - Feature: Remember value of show town names in smallmap - Feature: Norwegian translation - Feature: Norwegian currency - Feature: Slovak language - Feature: Use SO_REUSEADDR on listen socket - Feature: Unix sigabort handling - Feature: Hungarian translation - Feature: Added Norwegian translation - Feature: Added more default resolutions - Feature: Return error message if DOS grf files are used - Feature: Bemidi support - Feature: Added Icelandic currency - Change: Plant area of trees now allowed for 20x20 area - Change: 'kmh^-1' to 'km/h' - Change: Show original savegame names for oldstyle savegames - Change: Autosave go to autosave/ - Fix: Do not allow building rail stations on airports or bus stations - Fix: Canal tool resets after 1 use - Fix: Enable mouse wheel scrolling and zooming in SDL - Fix: Construct industries producing raw materials - Fix: Loading TTD saves gave incorrect reliability parameters for wagons - Fix: Fixed order restore bug in network play - Fix: Network sync fix for train goto depot - Fix: Only one statue per player per town - Fix: Enhanced patch configurator - Fix: If realistic acceleration was enabled, train did not accelerate if they entered a tunnel right after a slope - Fix: Remove SDL frameskip message - Fix: Road vehicle on hills speedfix - Fix: CompanyValueGraph window too small for currency - Fix: Mkdir() problem in unix.c - Fix: Client kills server if it leaves a networkgame - Fix: Smoother mouse cursor - Fix: Fixed a couple of overlapping memcpys - Fix: Quit to beos - Fix: Dragging to build canals sometimes crashed - Fix: Cactus plants died on desert - Fix: Invalid letters in Spanish town names - Fix: Rail upgrade button - Fix: Makefile reorganisation - Fix: Zoom out button not greyed out - Fix: No space between some values and units - Fix: Station catchment outline-tiles were not shown properly on slopes - Fix: Oil rig station was not properly deleted - Fix: Fixed making screenshots in scenario editor - Fix: Mac patches - Fix: Fixed alignment issue in station drawing 0.3.1 (2004-04-26) ------------------------------------------------------------------------ - Feature: Bridge pillars for higher bridges - Feature: Remember cargo payment rates selection, default to all - Feature: Fast forward button - Feature: Copy/share orders from trains in depot - Feature: Swedish translation - Feature: Dragging to construct canals - Feature: Can now have more than 128 towns - Feature: Always allow building small airports patch - Feature: Colourful newspaper after a certain date - Feature: Build while paused patch - Feature: Polish town names - Feature: Clear area now works in scenario editor - Feature: Drag&drop stations - Feature: More realistic train starting and stopping - Change: New directory structure (*.grf+sample.cat in data subdir, *.lng in lang subdir) - Fix: Shift+arrows keys scrolls faster - Fix: 'Monorail in 1985' which allowed you to build monorail/maglev at any year [SF#941880] - Fix: Town ratings when companies are deleted/merged - Fix: Vehicle reliability calculation in third phase - Fix: Random world button in scenario editor does not build cities, industries, trees - Fix: Loading worlds with no towns now fails - Fix: Outdated sort order after station renaming - Fix: Better train detection for copy orders - Fix: Euro currency bug [SF#938481] - Fix: Go to xxx road depot selection bug (2) [SF#938170] - Fix: Scrolling and newspaper in title screen [SF#934520] - Fix: Incorrect cargo_days for trains - Fix: Array bounds error with train breakdown speeds - Fix: Towns deleting random tiles around houses - Fix: Incorrect road vehicle list caption for competitors - Fix: Vehicle menu greying after a bankruptcy - Fix: Selective road removal - Fix: Make houses available in 1920 to prevent hang - Fix: Duration of breakdown smoke - Fix: Slope bug under bridges - Fix: Do not play invalid sounds (fixes road reconstruction crash) - Fix: Display correct train power with multihead engines - Fix: Buffer overflow caused by too long string in english.lng - Fix: Destroying things with no money 0.3.0 (2004-04-14) ------------------------------------------------------------------------ - Feature: Cost estimation with Shift - Feature: Added patch for starting_date, takes a value on the form yyyy, yyyymm or yyyymmdd - Feature: Support for multiheaded trains - Feature: Sell whole train by dragging loco to special trashcan - Feature: Drag the whole train with ctrl in depot - Feature: Added convert rail tool - Feature: Patch to select what vehicle types the ai will build - Feature: Better slope graphics - Feature: New pathfinding algorithm for trains (enable with new_pathfinding) - Feature: Added patch to use timidity for BeOS - Feature: Mousewheel can now be used to scroll in windows - Feature: Added coordinate display to landinfo window - Feature: Change default servicing interval for vehicles - Feature: Change max # of vehicles per player - Feature: Nonuniform stations patch - Feature: Moved error message box out of the way - Feature: Canals/shiplifts - Feature: Build tree of random type - Feature: Build trees on area - Feature: Added colour coded vehicle profits - Feature: Ability to close error messages with space - Feature: Network games (currently unsupported) - Feature: Bigger demolish tool - Feature: Two more bridges - Feature: Improved depot finding - Feature: Bribe the town authority - Feature: Allow building many trees on a single tile - Feature: Added snow_line_height setting, only affects new games - Feature: Errmsg_duration controls how long error messages are displayed - Feature: Fullscreen_bpp setting in [win32] sets the bpp to use in fullscreen mode - Feature: Euro symbol - Feature: High bridges - Feature: ZLIB savegames (smaller than before) - Feature: PNG, PCX screenshot support - Feature: Indicate with grey in vehicle popup menus if company has no vehicles of that type - Feature: Clicking on the money brings up finances - Feature: [OSX] Distribution now uses Apples package system for easier updates - Feature: [OSX] Application is now a proper bundle application - Change: [Windows] Use save/ as save folder - Change: Moved date in news window - Change: Do not check if tiles around the clicked station is a station in order gui - Change: Keep checkpoint button down after placing - Change: [Windows] Moved disk devices to bottom of list - Change: Changed speedkey from Shift to Tab - Change: Enhanced patches window with pages - Change: Do not slow down trains as much on hills - Change: Limit amount of radiotowers - Change: Changed intro graphics - Change: All player stuff is deleted when you load a scenario - Fix: Aircraft terminal was not properly freed if aircraft crashed - Fix: Fixed station acceptance bug - Fix: Fixed buy shares in company - Fix: Only deliver goods to stations that have a rating != 0 - Fix: Added F hotkeys in scenario editor - Fix: Unable to raise land next to signal - Fix: Aircraft was shown instead of ships in player overview window - Fix: Updated installer to take care of savegames more carefully - Fix: Do not make a new subsidy if there already exists one that is currently active by a company - Fix: Town directory sometimes showed huge numbers - Fix: Fixed bugs when changing owners of items (pieces of rail were not always deleted), - Fix: Fixed bug with large stations in train pathfinder - Fix: Deleting docks does not produce land - Fix: Deleting ship depot does not produce land - Fix: Buoy is now treated as water when flooding - Fix: Combo presignals bug fix - Fix: Prevent going to 0,0 if airport/docks is deleted - Fix: French town names had bad letters in them - Fix: Order list when replacing train did not work properly - Fix: Start in the middle of the map - Fix: More error tolerant saveload code - Fix: [OSX] Now runs even if SDL is not present on the system - Fix: [OSX] Now runs on systems older than 10.3 - Fix: [OSX] Altered compiler settings to make a completely stable app 0.2.1 (2004-04-04) ------------------------------------------------------------------------ - Feature: 'A' hotkey now always opens autorail - Feature: X can be used to toggle transparent buildings - Feature: Hotkeys 1-9 can be used to build a bridge in the bridge window - Feature: Added more hotkeys in the road build window - Change: Moved autorail button - Fix: Copy orders crashed if you clicked on a wagon - Fix: Do not show transparent buildings in intro - Fix: Installer does not delete savegames 0.2 (2004-04-03) ------------------------------------------------------------------------ - Feature: Autoscroll (only works to left/right) - Feature: Train checkpoints, instead of TTDPatch's nonstop handling - Feature: TTDPatch compatible nonstop handling - Feature: Refresh rate configuration setting - Feature: Town directory sorting options - Feature: Pre-signals (ctrl-click on existing signals to change signal type) - Feature: Show semaphores on the right side if right-sided traffic - Feature: Patch options configuration window - Feature: Autorail build tool - Feature: 'Show yearly finances window' option - Feature: 'Signals on drive side' patch - Feature: 'Show full date in statusbar' option - Feature: Italian translation - Feature: Road and rail removal by dragging a selection - Feature: News item for 'train is unprofitable' - Feature: News item for 'train is lost' - Feature: [Windows] Double size mode (Ctrl-d to toggle) - Feature: 'Multiple similar industries in close proximity' option - Feature: 'Multiple industries per down' option - Feature: 'Crossing tunnels' option - Feature: Order sharing and copying ('goto' on other vehicle to copy, ctrl+'goto' to share) - Feature: Remember last built rail type - Feature: 'Debtmax' faster loan management with ctrl key - Feature: 'Go to depot' orders option - Feature: 'Long bridges' option - Feature: 'Select goods' option - Feature: 'No train service' option - Feature: 'No inflation' option - Feature: Automatically detect available resolutions - Feature: 'Full load any' option, as in TTDPatch - Feature: Automatic detection of available language files - Feature: German translation - Feature: Finnish town names - Feature: Remember custom difficulty settings - Feature: Configuration file system - Feature: Show vehicle speed in vehicle view windows - Feature: Train depot window now has horizontal scrollbar - Feature: Mammoth trains - Feature: On-the-fly language selection - Feature: Load old premade ttd maps (must be renamed to .sv1 extension) - Change: Increased number of windows on screen to 20 - Change: [OSX] Start when doubleclicked - Change: [OSX] Significant performance increase - Change: Optimised startup time - Change: Sorted savegame list - Fix: News window was moved strangely when resizing - Fix: Fixed sign drawing bug in max zoom out mode - Fix: Road vehicles sometimes getting stuck - Fix: Connecting tracks behind depot causing incorrect signal behaviour - Fix: Save/load diskspace bug - Fix: Incorrect bridge cost for long bridges - Fix: Disallow buoy in north corner - Fix: Shift key now increases game speed only when game window is active - Fix: Ctrl button now works with SDL driver - Fix: Incorrect weight displayed in 'new trains' window - Fix: Incorrect train running cost in newspaper 0.1.4 (2004-03-25) ------------------------------------------------------------------------ - Feature: Crash submit system on Windows - Feature: Autosave - Feature: In-game resolution selection via settings window - Feature: Dutch town names - Feature: Added load game menu item - Feature: Build on coasts - Feature: Allow building transmitters, lighthouses and company headquarters on slopes - Feature: Now builds on MacOSX - Change: New savegame format - Change: New format for english.lng - Fix: Train smoke clouds - Fix: Train engine sounds - Fix: Play all sounds at 11025 hz (fixes certain sounds) - Fix: Scenario editor desert button now makes desert instead of lighthouse - Fix: Creating random town in scenario editor crash - Fix: Candy bubbles sometimes caused crash - Fix: Wrong speed was shown in news window for some vehicles - Fix: Graph colour bleeding - Fix: Arrow keys with SDL driver - Fix: Do not allow trains to road depots - Fix: Road vehicle was sometimes shown inside depot - Fix: Arrow keys in sdl driver were wrong - Fix: Endianness bugs in save/load - Fix: Now builds on FreeBSD - Fix: Screenshot feature now works - Fix: Rail foundations sometimes displayed unnecessarily - Fix: Minor AI bugs - Fix: Fixed industry sounds - Fix: Bug where ship depots were very expensive - Fix: BeOS build - Fix: Yearly expenses data being the same for the past two game years - Fix: Adding songs to playlists other than custom1 and custom2 - Fix: First and last tracks playing the wrong music - Fix: Palette animation for SDL video - Fix: Get remaining disk space on most Unix-en - Fix: Screen went black when resizing 0.1.3 (2004-03-18) ------------------------------------------------------------------------ - Feature: Swedish town names - Feature: More currencies - Feature: Better window resizing/zooming - Feature: Added goto road vehicle depot for road vehicle orders - Feature: Possibility to use either semaphores or signals (Ctrl key) - Feature: Limited the scrolling rate for year selector in scenario editor - Feature: Improved mouse scroll zooming - Feature: Larger stations and possibility to join stations - Fix: Message options window - Fix: Company takeover/purchase - Fix: Station code so it is not possible to steal another player's temporarily deleted station - Fix: Subsidy owner bug when deleting station - Fix: Crash when deleting a bridge with a train on it - Fix: Missing candy initial cargo payment values - Fix: Goods and Food/FizzyDrinks subsidies - Fix: Graphical glitch in subsidies window - Fix: Take over company dialogue was not shown properly - Fix: Crash if player windows were open while the company went bankrupt - Fix: Train slowness on hills 0.1.2 (2004-03-15) ------------------------------------------------------------------------ - Feature: Mouse wheel can be used to zoom in out on Windows - Feature: Implemented some support for resizing the window dynamically in Windows - Fix: Tunnel mouse icon for maglev and monorail 0.1.1 (2004-03-14) ------------------------------------------------------------------------ - Feature: Preliminary presignal support - Feature: Centre windows properly in higher resolutions - Feature: Command line -g flag now optionally takes a game to load - Add: External MIDI driver for Unix version - Add: DirectMusic driver for Windows version - Add: 'build tracks on slopes' feature - Fix: Problem where directories were not displayed under Linux - Fix: Colours in map window for routes - Fix: Road drive side - Fix: 'Fund road construction' not clickable when unavailable openttd-1.5.3/Doxyfile0000644000000000000000000002232312627373447013422 0ustar rootroot# $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 . #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = OpenTTD OUTPUT_DIRECTORY = docs/source/ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = ./ STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 2 ALIASES = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ./src/ FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.h \ *.hpp RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = */3rdparty */.svn */script/api EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH =./docs/ INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = YES CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = YES DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = YES TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = ENABLE_NETWORK WITH_ZLIB WITH_LZO WITH_LZMA WITH_SDL WITH_PNG WITH_FONTCONFIG WITH_FREETYPE WITH_ICU UNICODE _UNICODE _GNU_SOURCE FINAL= EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = objs/openttd.tag ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO openttd-1.5.3/media/0000755000000000000000000000000012627373446012770 5ustar rootrootopenttd-1.5.3/media/openttd.32.xpm0000644000000000000000000001437512627373446015430 0ustar rootroot/* XPM */ static char *openttd.32[] = { /* columns rows colors chars-per-pixel */ "32 32 257 2", " c #000000", ". c #00000A", "X c #03090D", "o c #000017", "O c #00001C", "+ c #060D12", "@ c #060C1C", "# c #0C131B", "$ c #0A1117", "% c #15031F", "& c #1D1B18", "* c #0D0024", "= c #070022", "- c #0C1827", "; c #150223", ": c #180324", "> c #1B0C22", ", c #19002A", "< c #151825", "1 c #1A1E34", "2 c #1A242C", "3 c #1E2327", "4 c #1A2630", "5 c #201825", "6 c #201427", "7 c #21262C", "8 c #24292D", "9 c #28292B", "0 c #232C33", "q c #2C2631", "w c #3B2C2F", "e c #352B30", "r c #37392D", "t c #313231", "y c #353C31", "u c #383532", "i c #351C43", "p c #383D42", "a c #294335", "s c #2A4C36", "d c #2C5436", "f c #2F5935", "g c #354031", "h c #384533", "j c #3B542D", "k c #315F33", "l c #326B2E", "z c #30642F", "x c #3A762D", "c c #3B7B2D", "v c #36712E", "b c #3E4042", "n c #432D2D", "m c #4B312B", "M c #52352B", "N c #6B3B29", "B c #763D21", "V c #4F335D", "C c #405C32", "Z c #5A402A", "A c #5F4435", "S c #456B33", "D c #4D6A3F", "F c #487434", "G c #4B7D33", "H c #537D3F", "J c #7D401F", "K c #684527", "L c #634734", "P c #7D502B", "I c #72583A", "U c #434241", "Y c #4B4640", "T c #43484F", "R c #424C56", "E c #434D59", "W c #49535D", "Q c #46505B", "! c #544A40", "~ c #564C59", "^ c #4C5661", "/ c #555D65", "( c #5A4763", ") c #55606B", "_ c #7F6549", "` c #63696F", "' c #6E7377", "] c #7A6F62", "[ c #7E7162", "{ c #7A7C7B", "} c #3E822D", "| c #40862D", " . c #4E8334", ".. c #518B35", "X. c #508735", "o. c #5CAB35", "O. c #5EB335", "+. c #61BB36", "@. c #62C435", "#. c #65CC34", "$. c #69CF37", "%. c #66D134", "&. c #68D532", "*. c #6BDB35", "=. c #6EE236", "-. c #71EA37", ";. c #833C03", ":. c #8A451C", ">. c #83421E", ",. c #944E1B", "<. c #9A551A", "1. c #8F5720", "2. c #835834", "3. c #995922", "4. c #8C643C", "5. c #9B6B3A", "6. c #AC5306", "7. c #BE4B00", "8. c #BA5503", "9. c #B15D16", "0. c #A35A1B", "q. c #BE661D", "w. c #AE6324", "e. c #A5743F", "r. c #B36624", "t. c #B76E31", "y. c #BA773B", "u. c #8A6643", "i. c #936E47", "p. c #9A754D", "a. c #9C7552", "s. c #907D6C", "d. c #A67747", "f. c #A77D50", "g. c #B27D43", "h. c #C05900", "j. c #CD660D", "k. c #CC6409", "l. c #DB690A", "z. c #D96706", "x. c #D16E18", "c. c #C16B23", "v. c #CA762B", "b. c #D87E30", "n. c #CB792E", "m. c #E36E0A", "M. c #EA6D03", "N. c #EC7105", "B. c #F76F00", "V. c #FE6F00", "C. c #F37503", "Z. c #FE7500", "A. c #FE7A00", "S. c #FD7C0C", "D. c #F4790E", "F. c #FE7E11", "G. c #C27E42", "H. c #9D8065", "J. c #9A8570", "K. c #BD834E", "L. c #B5814B", "P. c #B28452", "I. c #BF8C56", "U. c #BE8E63", "Y. c #B79779", "T. c #D5863F", "R. c #FF8209", "E. c #FE8215", "W. c #FC821B", "Q. c #EE8934", "!. c #FC8623", "~. c #FF8A23", "^. c #FA8A2C", "/. c #FA8728", "(. c #F98E33", "). c #F7953E", "_. c #FC9234", "`. c #F9933B", "'. c #FF9B3D", "]. c #C48B52", "[. c #CD9456", "{. c #C79156", "}. c #D38D44", "|. c #DA9D5B", " X c #D39858", ".X c #C48A4A", "XX c #C99561", "oX c #C29D7A", "OX c #C19C76", "+X c #DEA15F", "@X c #E18D43", "#X c #EC9542", "$X c #E09C52", "%X c #F59741", "&X c #F69945", "*X c #F59D4A", "=X c #FB9940", "-X c #F89D49", ";X c #E3A25C", ":X c #EBA55A", ">X c #FFA047", ",X c #FFA74B", ".A.Z.A.6.dXNXm.Z.A.N.n v &.*.=.F : YXYXYXYX", "YXYXYXYXO y +.=.*.#.s >.A.A.z.K.XXD.A.N.m l &.*.=.G > YXYXYXYXYX", "YXYXYXYXYX= y +.=.*.@.s :.A.A.Z.Z.A.C.m l &.*.-. .> YXYXYXYXYXYX", "YXYXYXYXYXYX* y +.=.=.@.s ,.A.Z.A.C.M z &.*.=.X.> YXYXYXYXYXYXYX", "YXYXYXYXYXYXYX* g @.*.-.G 4 <.A.C.Z - j $.-.X.> YXYXYXYXYXYXYXYX", "YXYXYXYXYXYXYXYX; h $...< @ 0 <.K - YX, C X.5 YXYXYXYXYXYXYXYX", "YXYXYXYXYXYXYXYXYX: y 9 YX3 0 2 YXYX6 6 YXYXYXYXYXYXYXYXYX", "YXYXYXYXYXYXYXYXYXYX. YXYXYX YXYXYXYXYXYXYXYXYXYXYXYXYXYXYX" }; openttd-1.5.3/media/openttd.256.png0000644000000000000000000003744112627373446015477 0ustar rootrootPNG  IHDR\rfsRGBbKGDC pHYs B(xtIME 'v>IDATxx7$$!{/BHM( A( Q^lWE{mZ^zU:(&ݝٝzlfggs>>>~>1rZ .|rԩvԩP B^<&Ll˖-n6lխ['$X`\o֬%&&"X`>f+U%*hj E>|~s'X>bK:aE>|+OMeE>|kOOcE>|~.|s|8\"^E>|~.|s|8\">?>qE>\ |8\">?>qE>|~.|s/Pۣ">?>qE>|~.|p}~.|p}~.|p}~.|5$!!!Կ***QFiĉ4i$;]X  9>yf٪5..|p5#FҥKK/ћoIoUk"""\&\Hv>s;v,[^|E/˗/[5~W >8= _~wDGG\@6nHfx>8>.\pE >8>.\p =~_.|p}\4~.\s"߆}{t"za@:''^ ?ju`:#M.̧yfW\\+i&  ]Tґ^߶ {F4fuR)O cPjըvڬЌ3hΝ;Е+WT oFMno>xdI.fW"@m.|xol.qs)=1OTjUfm2ȇJ~!_l4e>}:͛7֮]K'N?_N"HOOgFƹ C;J((_Qј;D"EʩI\P\ ?֮6enVDoѢ 8>f!!233zTF v#/￧7o2f -|pMO{>ᣐ%zCҸqhڴiLf͚>ᵘh%zrtE^TZ ~ܹrJdؓz-?A~)?aOчիWķn2UR?^7|C߿֬YCf$ }VSL I>ԩSiժUcڷo -Z6+-NS?1^q̮E1|GIwu-Y6l{gYI>.^`׮]cO۷oӝ;w~3S\2 ޣ:*?t<&L\ч?Jۗ#8y$ۆ`aVgKͿR$6avh*iE:.Eirݺuiy=жmt9 xx<9V-JE!_aϞ=liu_e3 … 4+OԦM7hm4]?.(zl$ᇓoaQa,pԽ{wv^ۏXן:ux ׿ŞDƒlӧi׮]Իwoӓ,0K@/L.]bK˗~Z^];:EC0MFL$Gfk|x9X7nY; z[bf!8paa!sa&??^yv]$Ec#D; ڑa4] .~/YɴתU+}l׽ l]'>dݝ=+f-X#~ d;2"6Ĉ; l/ GKD;ᡂT" l|/H k%}=z%5l5><]6#ht^=#.,pNn%3G;hCE; +kpIiR;LhճgO֦ {Xc^qiOTOߒ@ 3G|n!ӠVխ"Ʈ>5ʹS O~x̙ pBޚ_}@Ν;^?lK q=_}=xbڵ+4DN,c xuMW7wܕ>O6B%}hD .~ַZ$`ݏ 8&os>MDSb  jhKzҭ}=4U:k?29G7q%3ϰj@7dBt(u,Ƞ9b #Kɛ'qޝS^;Ӎ߲o%feggsC).cꏽ~H^ƒiZ6ۂ;4F6/=LHc}:HZLKjte >kOW3BH'Ѳ2?^n/o,yR^Ga$ Sw 5bbxױFZ*T8--}Qڋ)aIk?j PGC͠C1vw6Nt[: "E/ZNU **/DE8m x6 a|QxeU>sxnYgʯgJeA/k5"j]'whKmWp{.ib@V 5ދZj"Ϯ魨 }QQ:g]9XDKJ}c6݀S+KM^?>w|7͝miD. ?l߼n&o;2pA/ֳZ@x!kX-ue&Ů F3 fэ{*P0[s̠/i}̬-;p=KRLǾpܰCeC;~Pq|Q'Ņ0xxPK~iZ%7(/q?w1nnoM#'s^-w)!faOE>P- +> a|GVy_?VPZOB(c74X+3kID=:+k;K46ׯ>|c]~=ά覸;k'\חz6H5<@0|vGE wr"mvX 3*[sLo^M[d8gC8c qK]}vpŽ+zSaCQPX8@ 3ܚshLvkKS,{o )R|i@/)MVY/PzYًMWRM#A\?RӻTU5 ̚0 \e'u[Fn|"#o]Q!/Nvew_ߴiSV@oz)v(e[s6o ̶46Ftks#A} ?(( 4{dO,qq[vwW 1N^|,H h1F*j uf&,[65M8 ~i(@ "ؔ $̶Y^ wۻ)Y?IQPDмysvCi6WGXK𣐆g_>ؗXvm@6 JKצ1]Mo:&[:|SXP%,Ft k߾=;ξQTԥ3[k֡}L,_.K'~f%a5e-Z?ӳ|Ԋ 8s=qhP4:bN/ _ԩSTBA-RVm׾EBZ: gBfR'O~}ES z37ـ> 6lb˺ZD{XIvn͕^^>sCc^ bΟ?V%`¶V'`Nnjkw陹mA``.\2QLŇҐF  ^z3Eˢ;$I_F6N  ;7Gf4MQ E4nrg6Ћd 2ўe`coVdADi? &[UdޛJ#Ȋ57?:ʉ,ljLS܇~l8wӧiƍTRRB\iz:77R }9FՕ͠O-{S2E0Yzoi}ˏt*% @d xO>mm!W\v;*AZl0MkWͪyց3ƲNxx}-++1"`j#؋wjX6,F䡧2%ӖR\p1K,Œ!Ȓ :AeB~Z)J7;a/^/૩>!EKm,,Ot?#tދ x{N7>2~zzwUgùL3$`*=,D~/ϟD+zзs\| 4ݹ'^WTbU$!L4]#%bnݺ" O&Wqb] 7^z+?3Jg DUaB - #?"& McuXo{kι0K-ٟ ԭl` X̙SW?]s-M,ʩ\󝞞N? B(7@2]|3ࣝ|0;=ȟB*`)X`Y9?**O3mo^>s67kPvriPCOH<)o|6-2ۆȤkk `N`&X qLk&wq3X֦ox&L* ^:YeI3Y-b U7!}[Ǐg?8΍OtR^),f3+_`/X#^q*AEޥ},P=2*e&~"k#G)3i4+ 0yL>87e7e[x ;Z0Ӄ ?,V(XM"TJh E`j#v6|tkΝKܐ'A H=99Et10 `k"РAe8x¿XvK0HVˣ3sI-k2p%\^|EVMuh(ݚx;ht% HDQ@ xmK]]_gW_KgFcRth/p"{c\@81vCYȖ~8|]kY)6yW|s[Xӿ5mFc()26 K.oI'>ƌC/iB %Cƍ6I˃oN&i󀿾>^QVJu'l&er4)u3imD\vo:NEZV'ƹ#5 +b\|\ ~"bkSolo5Rg괸k2I"##YN|&MW^[j^4Y8K/qa+WL{9=:ontUIynmv/^icg'U퓨QpS\io;?֕=7oNcE10-GYf1f7yT1o޼{9VSjO,QFi5|7^{~u"0DivgYuwZu4`رcvݜ9syhrYcARSSYd+|8?c￯M; *f4\,]U@v|!bCK)1aͣe˖۷XO>$+(7$., 6nWS7_/N3 Ih֭ofjʓXH &5"/Х{:P ok,5L0d7n-X=Q Ow P'qBxapΡ(OҴ׋**D?Rܹ3]`/lhx :_o,m]Lɿh"B̙3E/ Ï=m oڴt&S7_/LqX pc6mXs'糱s nӷo_Zv-+sxKK8RT]z}Yf5+uoJ~ej`c9{Tyh~"܁mg6~c N*l=XXIò MJ]}0Y3qa][K; )74J*VĹbdS +ni8ڞIԭ[^͆5=@),HQ #5|$`ALhs"UQt@4&Q<75m ev<~YHNN>!Ux1]R^>sK_ٔdુAna,F8.RWONGW4 6ݼ{f@Z4lؐ_= D=| /#EEEݷlrS z75T|sib[}pafL [Pb ]_Pok&?ͳmLQ(ŇHGD)j ?`[-X` )1uԖҥKYXT+xwhhqBq!K35g+~hG1'<[}{8 mW]"6X @<׿~Gh!ޥKSGMPTҌP @]]e#b(7,bAJӽ~"p"0gΜf۶ms~"!N%TpcmZ;++VXAOfmԄ[ xAtZTa6+\Pm:]PZ!,]8_an&Zo[bu^ƒ5FZ0w b+nj 0R`8,jKӃ4uT7T!/C )zxï@F;U߶8x7Wdzlk u6$V}|kQ˖-E tr@RWNJWxx8 ߿>7w~["}xk,Y+A ...fyե$ ai|l(5@ƛ^*Z쉌6$gg4ww8 ~".Z^f/~Pm߾=[,W_j)BBG-T {PE<'FaKT]XW=]&smLm@SUMUD֣?O.]tk.86aӦM3LJPo?ۻ*M0PfhтyVQ8Po/YNWo["]|gE+WLN=|{Cm*`wY٦5@/1`p<3@޽{Yf$ZJ@1!5wW 4WoSF(ԛ_KcɯgؿG0^`SOQQQ,;`:'"iV}! isCDڶmgisI+#, hto)7zڵ.\kiOY";uĺI0qDuo:,gONUKx{IgOu"W80]U\bzET@is:vn=z`O[8[ BW_}J4jD$,w3A$@͔K2-OsqA-^a_T`+??_ .UϟDB ~EǘYc9Mŭ@ĨL89v0xWرclF$ tҌJ`[TjUʡc?.0׺'޻jnq~f+`F. 6(тZ nh!K`w=Dw4$X͒b$jBѳ> ~59Fb ;<qrpLtp\=aV2 Q;o|,X'%,Yr*9tV!|8QmŽ=J~SJl?BR"Z(YZH$-{řz!h9p|XjWb#^*bk%X,_XU9tŭK[xzݙ!ԩl+ SnGj8"Ҍ,j@X011 b%ג M_.*z l`Y[.F*E@@` O @t^T'uu6Ib(|!H2?q+ v`Cc\X0j^"` A'rFZXkXrlhйs4U4=u` %%<=7 e.KL#g*H`[K>s;piʕC6cM  eџ݂l` l[2{E+P ""@۹xb:yb?C^m೎3Ɣx_#l`ML*.$-* B P "{'YDfΞ=EaLImνi0P N7o@5kfZwߒUg_k@u7YSZL3~wRr~dOqo7T;_Yu$+,));w[#~;<UmUgG6]/5קaO}h562)N8[x#%b7lplRS3@^" #a޲,(N2og/+)Fgz3wXƾՐ3**&}&mfZxSիYY,ku3&݌WzxJp8Ǐp@wz&,JX6QZ+wXF-"P[E`4KLm~|zxi^YZ!,1"̮_VC?DK G*1B8ԹsgӹÏڔ^C ~Dg?ߐҚ:i J"ЮxBڼy3{Ji$;> زJ3 uwl!bV,1>s6ТfKw_5@PDyGïnY .HC`;}tV&̙3L gu;>p8fe?Kll,ʆIZ$% G?##nX@'7iߥ~@$s`s7P{@-pZ0(r#go0lݺu/ P+ɀ>|n77i|߁:r鵊#:?*a Or @1ʯd$RT '>`C5P^ >$`I]@k٫oek{_PHє4-." @,l{jL* Bg}@ DLM`q;P}ZqU>bЛT?ϷPlTh3"PVF^j*5='z5Xi/d&"`yĠt75̎q~jHQ/|@p(+&MbBMHiU`sG𗫥W0:!_Wo_,B_)7f6l3^5nX_6R֋\loK)z4No_ X| y]>H_3k (/ɕv D\\?vߖ:@Nq."./_%(z:W #S6 gD|~ͷ%[:dnm"K~"+:huDï ;~["P F[cuę9}EVrgn%f %"ײK, oKꏱc ,_-B0 9N"%֒6m$.=746"42wj[D@--W𳔓p]% h5U/-h?R~%DX%~|yŒ=]Q쁿L\I[}Z߅" g͔yPÆM<\J8n&_~͟ #6&P_PEqxEf"$\3Z"m)T/X?*5xx AAe){E $ "` s3ZP.k "~DRAwCoa* & dx+`E+Kwᇤ0{EGyXNFxオ=&w@t*FSqq1;sLV%Ț5K P ?[k"x]YL ˊ@^Y@tu3@ݜc",BjJ Ӵ*o"~wt^1Sұ%Ԅ5 ~Dx1_!Z@ ,66k)GlV#~[P|%WE :](} ~p"0ljb8zCe~OգZ Jd(s~oG9މplE^rLlE@-w G@~$` ކ̉KtFŭ>&}7eE@OЉށ+*p]/n6dn |GD: ?1#:FkF~ XpOΒ!/7L ֢n?E@`Wi# DCRw\n?@`-BQeg~ow;(2 c{Ӓχ'JhڏZ ";|5QzhMd[&'goKdsQ6χO෴ϯ5DOc}\¹q_55+dR?Ρ8Q׍59|xp6 ]Z,/D丫w؂ߝDχ."1ƓAOw?."#쬳EUAmEA SM젳D+EχGwD"3]E@h;\!~>|O4_s~K"EK"1~!wXt_l"3v['Z&"#E'¯Jzl"`wuL8~DχG@,A~ny5?)̙ .VB47m מx ,x ӌ4_C>}HS l|bK]Zrύ:||| oIENDB`openttd-1.5.3/media/openttd.ico0000644000000000000000000011560612627373446015152 0ustar rootroothh V   h  #00 %3@@ (B^Y( @D9/$ D1"R|Cd E.Qx\\A[v D*QxVmX>WoE) QuUljb;Uk H$ Pq[gL3KfL&Ll]H}w6:-Ea&H( DfNJ@P{)%  =],-2@b;7-`7{}q|f5/gB^:A0e`xrmfpb-mL,>?3:6]7\'Yfbp=`+aM7b0Q'3*5a9Z"Wln pz`*_Q7a1T  %/'5b:X!Uqk<@d)\S7_3U '6+6c:X%Xosk(PR8^2W %>-1U) =n2U+sD'yz{|}~ijklmnopqrstuvYZ[\]^_`abcdefIJKLMNOPQRSTUV9:;<=>?@ABCDEF+,-./0123456 !"#$%&'( ?( @%>-1U) =n2U+sD'6+6c:X%Xosk(PR8^2W %/'5b:X!Uqk<@d)\S7_3U 5a9Z"Wln pꑬɳz`*_Q7a1T  6]7\'Yfbp=`+aM7b0Q:A0e`xrʪmfкpb-mL,>2@b;7-`7{˚}q|f5DfNJ@P{)%  =]Ll]H賽ꛪ}ɓw6:-EaPq[gL3KfQuUlϼjb;UkQxVmX>WoQx\\A[vR|Cd?( @ "(!)%+(%,+(--+./-.10/60/:/0A01I21Q32V33X44W35T47Q38L3:F4;D5yMJD+l^lʳn|r8GKM5>MIE+|iV{p8HIK33LKF+{d߸ݍ{o:IJM9E+t+jc{{o;M?,oojjw{|m7 )jXi{||{m .ggkn}lb^a+ "\`cg. !Y_kÔ/ !Vh_֓d "ccۼ”d "c򳙚c $0пαc $cccTccc $d⫠c $]S &^YS 'S 'T (V(3???( @ 0>5&&&3*"("2F87g5R#5-!V&Ei+ 1Z?5P2B76c6n7q2I3T~v*@Z*+S:7i7q5P1?56b6m6m4b7M+N|vyu+5R/d02i7l7o4N1;46a6n6m4c6F(F|yvvzt+2N/i12h7l7o5M0736`6n6l4d6I)D|yhOayyr,0I.m42i7l7o4{K0325^6n6l4f7L*BzvySʸ ouzp-.E.q63i7l7n4vI1216]6n6l4f7O*@}|tyyQnsuyo--A.u83j7l7n4rH0..6\6n6l4g7R,!>y}a̎?hu|(yvzm/-=.y:3j7m7n3nF0<45[6n6l4h6V-!4k7l7o2]@?}S2h3_1-<:94$f"Y#kcn  | zyx|g-39A<7@uNHGECA@7B~겷1n"~ )Eg-#CB@GUPNLJG;wퟩRu$c.4/-+(% +P}0'A>=M]WUTBpꗟ.z(rŬC665312U/$A@>Sd^^DӁ W4zą?@?>=6[.#@@@VgdRbq~Iw܉BJII;a-#@ABVfd=hvPSUAg,#ACEWhY:Xrɟƾb_aGn+"@DGXh\?tIebozO;nHj^hMu+$@EIYge^9j_c`gNx+%@FL[efGz^bgP|,&!@GN\f[C}JbgQ,'"@IQ\fedgR-($@JS]dfS-)&ALW`V.+)@KV1473???(  @ |z'|{qheH%>-1U) =n2U+sDM'6+6c:X%Xosk(PR8^2W K%/'5b:X!Uqk<@d)\S7_3U I '3*m5a9Z"Wln pz`*_Q7a1T  ?3:q6]7\'Yfbp=`+aM7b0QgB^:A0e`xrmfpb-mL,>-"2@b;7-`7{}q|f5/eH( ?DfNJ@P{)%  =],EL&(Ll]H}w6:-Ea&B H$ 1Pq[gL3KfGE) 7QuUljb;Uk LD*Wo PE.BQx\\A[v UD1"CR|Cd TD9/$ h?( @ '$*0>5&&&&!3*"("&C%% )2F87g5R# -5-!V&Ei+ (81Z?5P%#$2B76c6n7q2I3T~v*@Z*+S:7i7q5P# 1?56b6m6m4b7M+N|vyu+5R/d02i7l7o4N" 1;46a6n6m4c6F(F|yvvzt+2N/i12h7l7o5M! 0736`6n6l4d6I)D|yhOayyr,0I.m42i7l7o4{K! 0325^6n6l4f7L*BzvySʸ ouzp-.E.q63i7l7n4vI1216]6n6l4f7O*@}|tyyQnsuyo--A.u83j7l7n4rH} 0..6\6n6l4g7R,!>y}a?hu|(yvzm/-=.y:3j7m7n3nFw?/ 0<45[6n6l4h6V-!4k7l7o2]@ubEYX?}S2h3_1-<:94$f"Y#kcn  | zyx|g-39SqqgA<7@uNHGECA@7B~1n"~ )Eg-#jfa7CB@GUPNLJG;wRu$c.4/-+(% +P}0'i]U?A>=M]WUTBp.z(rC665312U/$ g\QEA@>Sd^^D W4z?@?>=6[.#dZPL@@@VgdRbq~IwBJII;a-# ^UKQ@ABVfd=hvPSUAg,# `UIWACEWhY:Xrƾb_aGn+" \QI^@DGXh\?tIebozO;nHj^hMu+$ ZPFe@EIYge^9j_c`gNx+% &ZNEk@FL[efGz^bgP|,&! +XLCq@GN\f[C}JbgQ,'" 0WKBw@IQ\fedgR-($ 6VJ@@JS]dfS-)& ;TJ?ALW`V.+) AUKE@KV147 ANGB-'"|1 ???(0` %, ($!")++(}/,.'5\B5jG&! ""%2-+6203/+ ?0+-*$(7/'4Q=6j6n5bD$$3-'347d$Jv5,!#9/&,5U6P)$3.'4M<6h6m6k6l4cC"!0+%431d~v(Eg5+!s >1'-5R6p6n6xK)#..'4J;6g6m6j6j6n2_43-5/-b|vyv)Cc3)""0L7o6k6k6n6tJ&!*,'3G:6f6m6j6j6k2b4P65+*a|vvvyt*@]5) 'H2f6j6j6k6m5oG&'+%4D:6e6m6j6j6k2d3Q75$&`|vvuuuyt+=Y4( (G2f6j6j6k6m6kG&!#-'3A86d6n6j6j6k2e3U86#%^|vw|~zuzs,;T3( (H2f6j6j6l6m5gE& *$w3=66b6n6j6j6k2e3X;6"#\|vwra@yN6yuzr.9O3) (J3g6j6j6l6l5cD$*$q3:55a6n6j6j6k2f3\<6"!Z|vvy]W`j^xuvzq.7L2+!(K3g6j6j6l6k5^C$*#k3846`6n6j6j6k3f2`>7" X|uuvyZZiz\ttvvzp05H2-"(M3g6j6j6l6k5ZA"+#d4646^6n6j6j6k3f2c?7!V|}~xuy_Zlb yuuv{o14D1.#(N3h6j6j6l6j5W@#*%_3226]6o6j6j6k3g2e@7!T|tc?w2}tLyIz)ty|tv{m22@00$(O4h6j6j6l6j4S>!("X2015[6n6j6j6k3g2jB8!S|zXjpv` g8;1$2Ou.-+)'%# ^!] aYhyXVtwvtvvvv|b6),-I/)T7)% &&&r1( 5Np543210.-Novm^oDswuvvvvv|`7,+* =***q2*#6Oj=<:986544#b(>XQ\hnnm*k)!x"^b yyxwvvv|^60*'# #555_30,8PkCCA@?><;:98-kb!oGrLmz~}| { zyxw|^445&$"KIH122GLHGFEDBA@>=>51kZnp# ~}| |'Hp4.'KuuuCJGD5DSNPMLKIHGFDC?/a4[q.,+(&$" #Z41-**( x||LHB<5DSSURQONMKJL-qhw2Z]3C:220/-,*(&")_5-%*)'wwzSF@:7GWXZWUTSQQHA`]z%y/Di|\=6644210//d4.&*)&wwyZF@:9JZ^^[ZYWX>^lw(JoamyqI%j|?;<;98664j4.'+)& sss_D>8;M^bc`_]_@_jsL{1alwx4ex^EBB@?>>8o3.),(& sssfB<6WmdcbfAzINSSUUSUH30.,(% nllx?83?Zreccb.W}SUVi_[[]N310,(%llj>72A]wecd`1^:HT}~}p~/DWUfadT322+(%jjh<61B`|eccfO2_4Pj2CRkGN/Vy5`[dfX445*(%#hhg<60Cdecbee_8t]gn|dcdeceY578,'$'hge;5/EgfcbbfJhs{b`bbfZ58:+'$/fdb:4/FjfcbeKHOS_zdabe[6:=,'$4cca93.Hnfbc^:f4]9gSdbf\7D,'# >`_]72.Ktfbbcbbe^9@H,'""C_^\72.Lxfbbbe_9BJ,'"""I^[Z61.M{fbe_:EO,'" ##N ]ZY62/Oi`;HS,&"!$$T ZYV643N}?Qb-&!"$$Z ZYX52..,)""%YSRR333>1<>??????(@ B  #F "?#E#D *Y :}>;t:sz= a.b{}k5.Z 7|>=x6k7k:rt:5 ]xz+^t y^.9q;t,W 3|=,Vy<:r6j7k:qr8 Yvvzy(WpzZ-9p7l6j:r+U0q8>z3d +v:;t6j7l4e  Wvvvvzx&RQ(7l7l6j6j6j:r*S ,v;-Y }>=w4g 3 ?8n4e?Svvvvvvzw"L ?5g5g6j6j6j6i#?6yxwe+Hjudr@ tVKwJm+m! svvv~d # &K2b:q(O !@ 10`u:= /3e )n6>zf3D"7k5h!v;2sxvzEoux@mn,R|Up9}rvvvb # ,Y'M ,WAo7y<=yh4 6 &4f:qQ(A :r7k&K%B/l}xvww=n~tBwsvvv` +{= -W)Q ,V9p9qa1...B  ,2b9p7k:qM&>6q8%B+f|xvvws9vBxsvvv] 5}> 5 /)P:r6i7l9p]/?<>  !F=w6i6j7l9pH$c1'H*`}zvvvwlAj9|uvvvZ2*T3c8m6j6j6j7l8o\.t unu%937 )U:r6j6j7k9p&F)Y ~ zyyxy^7PltzlyPk,n)7JGosvvvvX1-Z4f6i6j6j6i:q3e :.5 +X:r6i8m&E&S~~}| | ~RYdoH_{%v%8M${xuvvvvU3-Z4g6i6j8o5i8H8,4 ,Y:r'G %M!E~D[t[\BSdf zl4f%kuvvvvvR6.[5f8m6j9N 4*2(!}> "E*)'%#"  Cn{W XCSdgd'Gl1m tvvvvvvO:0_4f=T$%" "B01.-,*)'&%~EuP\DSdgmD$f uvvvvvvvLC>[C "<5632210/.-,s.D^Hd~ eJZmmVi~ ^|vvvvvvvvwIuB 69=9876543211"n.@eec]+),_Xhy\spzxwvvvvvvvwI< 0>B>=<;:9987652!b@y4[+=<;:99960'x+$iBaE[tt~}}| { { zyxwxA-*)?QIHGFEDCBBA??>=<;>+2YTaod$ ~}}| { z{*W<VVRD%"1KNPLKKJIHGFEDCBA@B+|AVn6Kdd-)('%#" ~~ U hddL!0JSTOONMLKJIHHGEF92LiK\mOx0/0.-,*)'%$" [eeeS4NWWSRQQPONMLKJK#Vmu0IgO%p:ON>23210/.-,*)'%'abb_X9T\[WVUTSRQPOP=ATf`s f3>)Zu{~qWx[J565433100..0 g ``]_ =Z`]ZYXXWVUTU,dswyNXdeoxpGD,|P^m|F=::98765436&n ]]Ze#B_ea^]\[ZYYX'R~.S{YHUbtPC$MzD@?>=<;:98<,tYVVj'Hfhdaa`_^]](QxXoR9~LV`uX!YWrKCCBA@@?>B1z ZXUq (Klhdbbbbba,Wmop`zuBJPgOcp|{ETMLKJIHM<%UPP~ .UyicbbbdY%=Sq|QTQPPOMRC *QOK 0Zicbbbe9l5 =pjbbbbdd`Y0cGRZyeadeeebbfa+<GD?< ?tkbbbbbcgEOZb|f`bccbbfb.@P@=9BykbbbbbeEP[dzf`bbbbfd2GT?;7 E|jbbbbeD9?CVfsdabbbee6LZ >95 GjbbbdX*If)D].Li1RpG{ebbbee!:Q` <62 Jjbbbc^XZ]dbbbef$?Xf94. Ljbbbdddcbbbeg&C]l72.Nibbbbbbbbdh)Heq72-Qibbbbbbdh+Ljx4.*Ribbbbdi-Qq|2,'Thbbcj0Ux#0*%"Wicj3Z~&.("%Yn5^++& (81X|||-)&"XXXH888888 ?x0??????openttd-1.5.3/media/openttd.64.xpm0000644000000000000000000003037212627373446015430 0ustar rootroot/* XPM */ static char * openttd_64_xpm[] = { "64 64 252 2", " c None", ". c #212429", "+ c #030006", "@ c #402F20", "# c #80582F", "$ c #000100", "% c #252B31", "& c #2B1C0D", "* c #DC9C55", "= c #FFC36A", "- c #1F180E", "; c #D09351", "> c #FEBA6A", ", c #ECAB62", "' c #7E5935", ") c #F1AE5F", "! c #F8AE62", "~ c #2E3339", "{ c #6F4B28", "] c #150D04", "^ c #C3884C", "/ c #F4AB5F", "( c #684B2B", "_ c #353B3E", ": c #11100E", "< c #FCB265", "[ c #5D4327", "} c #BA8144", "| c #E9A863", "1 c #E2A15A", "2 c #563B1E", "3 c #AC7A45", "4 c #694D32", "5 c #383937", "6 c #929492", "7 c #A5A8A8", "8 c #9B9E9D", "9 c #665D51", "0 c #49321A", "a c #3E4144", "b c #090F13", "c c #D5DADD", "d c #E7EDEF", "e c #F9FBF8", "f c #988E82", "g c #0A0201", "h c #A2703D", "i c #D9DBD7", "j c #F6F8F5", "k c #9A8A78", "l c #916333", "m c #5D5449", "n c #F1F3F0", "o c #EAA859", "p c #4B4D4F", "q c #9A6B37", "r c #696762", "s c #DFE1DE", "t c #EFF1EE", "u c #917E6B", "v c #332312", "w c #936D47", "x c #563E28", "y c #4F4842", "z c #767470", "A c #B1B3B0", "B c #CDD1D0", "C c #E9EBE7", "D c #F3F5F2", "E c #C0C2BF", "F c #6F6051", "G c #635345", "H c #FFB25F", "I c #050A06", "J c #664220", "K c #403A34", "L c #858886", "M c #C2C8CC", "N c #EDEFEC", "O c #DFE5E7", "P c #797064", "Q c #A8A29B", "R c #BE8953", "S c #ADB3B7", "T c #E5E7E4", "U c #9F7E5E", "V c #F4A554", "W c #F3A956", "X c #D98F46", "Y c #443D37", "Z c #B1B0A7", "` c #FDFFFC", " . c #927960", ".. c #FFA652", "+. c #FBAA59", "@. c #11181E", "#. c #C9C5BD", "$. c #A89E91", "%. c #F6A052", "&. c #FBA950", "*. c #1A0B00", "=. c #AC783D", "-. c #A68666", ";. c #7E6C5D", ">. c #BB7B44", ",. c #F69F4A", "'. c #F79A48", "). c #FFA349", "!. c #845728", "~. c #FDC880", "{. c #C3813D", "]. c #9E7047", "^. c #F5983F", "/. c #D07D2D", "(. c #7A5028", "_. c #817E79", ":. c #85705A", "<. c #CA8136", "[. c #985A22", "}. c #98908A", "|. c #8B6C50", "1. c #F9953F", "2. c #C77228", "3. c #D1D1C8", "4. c #F39A4E", "5. c #FF9C3D", "6. c #F98F34", "7. c #F79335", "8. c #945A2A", "9. c #C17A3D", "0. c #EE8C36", "a. c #ED8632", "b. c #E8903D", "c. c #654B35", "d. c #B36420", "e. c #FF9030", "f. c #FB8B33", "g. c #FB8A29", "h. c #C06B20", "i. c #884914", "j. c #DD863C", "k. c #FB8427", "l. c #FD8E23", "m. c #B15B11", "n. c #E78024", "o. c #FC841D", "p. c #F37E13", "q. c #F89A41", "r. c #D77921", "s. c #655340", "t. c #FE801C", "u. c #FE7F0C", "v. c #FE7A08", "w. c #FF8814", "x. c #C4600D", "y. c #FF8700", "z. c #4E2505", "A. c #000205", "B. c #745C46", "C. c #DF7216", "D. c #F2760D", "E. c #FE7404", "F. c #FF8000", "G. c #974600", "H. c #7A3F12", "I. c #593513", "J. c #513D2D", "K. c #6A421A", "L. c #9C520F", "M. c #F67300", "N. c #3E210D", "O. c #BBC0C3", "P. c #CE6000", "Q. c #E86E00", "R. c #FF7500", "S. c #FF7B00", "T. c #A14800", "U. c #7A3601", "V. c #1E3E10", "W. c #352A35", "X. c #122509", "Y. c #3A7E1E", "Z. c #813A00", "`. c #8B8074", " + c #C25600", ".+ c #A1836B", "++ c #F46B00", "@+ c #B57031", "#+ c #AD5000", "$+ c #1A3710", "%+ c #62C52C", "&+ c #61CC34", "*+ c #382D38", "=+ c #0B1A07", "-+ c #5BB92A", ";+ c #6DE73A", ">+ c #4A9222", ",+ c #D05B00", "'+ c #DF5F00", ")+ c #662E00", "!+ c #55B32E", "~+ c #6AD432", "{+ c #69DC39", "]+ c #1D380B", "^+ c #0A1608", "/+ c #72E236", "(+ c #438D24", "_+ c #752500", ":+ c #A64002", "<+ c #BC5700", "[+ c #17320B", "}+ c #57AC28", "|+ c #42861D", "1+ c #5A2900", "2+ c #152C0C", "3+ c #0A1104", "4+ c #100001", "5+ c #469724", "6+ c #73F43D", "7+ c #234912", "8+ c #2E5F18", "9+ c #50AF29", "0+ c #6EDE32", "a+ c #295914", "b+ c #5CC132", "c+ c #255114", "d+ c #38761E", "e+ c #3F8222", "f+ c #52A025", "g+ c #6F2F00", "h+ c #894000", "i+ c #377019", "j+ c #7DFF3F", "k+ c #346A1C", "l+ c #C96E14", "m+ c #FF7004", "n+ c #0B200A", "o+ c #74EC36", "p+ c #7C4A1D", "q+ c #DE6701", "r+ c #210901", "s+ c #20440F", "t+ c #4EA529", "u+ c #8C3D00", "v+ c #4D9C27", "w+ c #66CF2D", "x+ c #C55301", "y+ c #2C0F00", "z+ c #142806", "A+ c #361500", "B+ c #421C02", "C+ c #3E7A1A", " ", " . + ", " . @ # $ ", " % & * = # $ ", " % - ; > , > ' $ ", " % - ; > , ) ! > ' $ ", " ~ - ; > ! ! , ) ) > { $ ", " ~ ] ^ > ! , , ! / , ! > ( $ ", " _ : ^ > , ! ! , / ! , , > < ( $ ", " ~ : ; > , ! , , < , / ! / / > < [ $ ", " _ : } > , , ! ! | 1 1 , ) , , , ) < 2 $ ", " _ : 3 = , , < , * 4 [ 4 ( 3 < / , ! > , 2 $ ", " _ : } > / ! , ! , } 5 6 7 8 9 | < , , ) ) < 0 $ ", " a b 3 > ! , | ! , < ^ 9 c d e f | ) ! , ! , > , 0 $ ", " a g h > , ! ! , , > > } 9 i j e k | , ! , ! ! / > / @ $ ", " a + h > , ! , , < ! , * l m i n e k | ! ! < > , , , > o @ $ ", " p b q = , , ! < , 1 h { [ @ r s t e u ; > ; # # 3 ! , ! > | v $ ", " p b w > / ! ! ) | q x y z 8 A B C t D E F # 2 p z G 1 ! , / H 1 v $ ", " p I l > , , , < * J K L M i C C C C n N D O 6 P M d Q R < ) ) / < * & $ ", " p b # > , , ! < | ( a S i N n n n D n t C t n n T C e B U < V V V W H X & $ ", " p b # > ) < , , ) q Y Z s C n t e ` j t n n n n t N N t C ./ V / V ..V +.X - $ ", " @.b # > , ! , ! < 1 x L i n n n D #.u $.e C C D ` C n C t e f * V %.%.V %.&...X *.$ ", " @.b { > > , ! , , < =.y M N t C e Q -.^ ;.C D e k Q ` n n t e Q >...,.,.,.,.,.'.).X ] $ ", " @.b { > ) , , , / ! ) !.z i t n j s U ~.{.9 i t j u !.f j t n e B ].&.'.'.'.'.'.^.'.)./.] $ ", " @.@.( > < / ! / , , / / (._.C n t n C :.V <.G i n j k %.[.}.j t D N |.,.'.^.'.^.1.^.1.1.).2.] $ ", " @.: 2 > ! / / / / / +.V +.(.}.C C t t ` Z ' [.9 3.n e u 4.5.(.E D n ` $.X 1.^.1.1.1.6.7.1.6.5.2.g $ ", " @.@.2 H W / V V V V V V V &.8._.C D C n n e E G P T t e k ,.5./.F n j i _.9.6.7.6.0.1.a.6.6.6.6.5.2.g $ ", " @.@.2 +.+./ V V V %.%.V %.,.V b.c.i D t t t N D d i C t j :.d.0.5.[._.u U R '.6.1.6.6.e.6.f.f.6.f.g.e.h.g $ ", " @.@.0 +.+.%.V V %.V ,.%.,.%.,.,...8.Q j t C n t t n N C t D #.z [ i.2.j.4...1.6.g.6.f.6.g.g.g.f.g.k.g.g.l.m.g $ ", " @.@.0 ..&.%.,.4.,.%.,.,.'.,.,.'.'.^.b.4 3.` n n C t t t n t t j D B 8 F i.n.e.k.f.f.f.g.k.f.g.g.o.o.o.o.p.o.l.m.g $ ", " @.. 0 &...,.%.,.'.,.'.'.'.'.^.^.^.^.q.1.r.s.B ` D n t t C n t t t t N t d 7 c.h.e.g.k.g.g.o.k.k.o.k.o.t.u.t.v.u.w.m.] $ ", " % g j.&.'.,.^.'.,.'.'.'.^.1.1.1.1.1.7.1.5.n.# 6 C ` j n n t t t t t t t N D O F x.l.o.t.t.t.t.u.t.u.t.t.u.v.u.u.v.y.z.A. ", " A.& j.).'.'.1.1.0.^.1.^.1.0.1.6.1.e.7.a.r.n.d.|.f i e e C n t t t t t t N e d B.C.o.p.t.u.D.v.D.v.v.v.v.v.E.v.F.G.g A. ", " g v b.q.0.^.1.5.a.7.6.7.6.6.6.a.d.H.I.J.K.e.k.2.8. .#.j t t D n t t t t N e M L.u.v.u.t.u.v.v.v.M.E.v.E.M.F.G.A.A. ", " A.N.^.6.7.a.7.1.6.6.6.6.6.e.h.@ r 6 O.6 d.g.g.l.P.:.C t t C e e t t t t N ` :.Q.v.E.E.v.R.E.R.v.E.E.R.F.G.+ A. ", " A.N.1.6.6.f.g.f.f.f.g.f.f.C.c.M N t O |.k.o.o.P.G i t e .:.3.e t t t n ` 7 x.v.S.v.E.R.R.R.E.R.S.F.T.A.$ ", " . $ N.6.e.f.g.g.g.f.o.k.k.k.K.S n D e A L.w.w.P.s.i t e U C.U.#.D C n t e M d.F.E.E.R.S.R.R.R.R.F.T.A.V.V.$ ", " W.X.Y.g N.6.l.g.k.k.p.k.o.w.t.Z.Q n t t D `. +u. +G i n D .+D.++J s n n C j M @+u.E.R.S.R.S.R.S.F.#+I $+%+&+V.$ ", " *+=+-+;+>+g z.k.o.p.t.u.t.t.u.u.G._.t t t n d B.,+'+s.i n e .+D.++)+O.t n t ` A d.u.M.R.R.R.S.R.F.#+A.$+!+~+{+~+]+$ ", " *+^+-+/+~+~+(++ z.w.o.u.t.t.v.u.t. +F C n t t j O B._+c.i n j U D.:+J.#.t n t ` k n.R.R.R.R.R.R.F.<+$ [+!+~+&+~+{+~+]+$ ", " ~ =+}+/+~+{+~+/+|+A.1+u.u.v.M.v.v.v.,+c.s n t C D j d _.`.i n ` |.)+@ 6 i C n j O ].l.E.R.S.R.R.F.<+g 2+-+&+~+~+{+&+;+&+3+$ ", "a 4+5+6+~+~+~+{+7+8+(+A.1+F.v.v.E.R.E.++K.#.n n n t t N t T C t D #.7 E i N n n e f j.S.E.M.R.M.F. ++ [+9+&+{+~+{+~+0+{+a+I @. ", " + 2+b+{+{+/+c+V.]+d+e++ )+v.v.R.R.E.E.U.S t n n e D t t N t C t j N C t t D ` Q >.w.E.R.R.R.F.P.g $+d+$+2+f+/+~+~+/+8++ A. ", " b X.&+/+c+V.{+~+I >+e++ g+S.S.S.S.E.h+}.t ` u u T ` D n t n t t n n D ` C }.>.g.E.R.R.R.F.P.g 2+d+=+!+f+=+}+{+/+8++ $ ", " + 2+&+X.i+j+k+V.{+~+i+A.g+S.R.E.v.T.z ` i h l+(.Q T e C n C e ` ` T A |.9.w.m+R.R.S.F.P.*.n+!+f+3+!+j+i+d+j+k+g A. ", " g $+&+$+2+V.o+-+3+Y.e+g U.F.v.E.'+{ `.P j.w.M.<+p+$.e n j 3.$.k w d.l.F.E.E.R.S.S.,+*.n+5+&+/+f+=+e+[+b+i++ A. ", " g V.-+8+0+b+^+e+[+|+k+$ U.F.S.E.v.k.f.t.m+R.S.'+B.N t j .9.n.o.u.R.E.R.S.R.F.q+r+n+e+[+!+{+o+>+=+!+e+g $ ", " + V./+&+=+3+f+}+A.&+d+$ Z.S.v.R.R.E.E.E.S.S.,+G 3.n j .+u.m+E.E.R.R.M.R.S.q+*.=+e+3+V.6+~+~+{+0+e++ $ ", " + s+!+f+%+n+=+t+b+5+k+I u+F.S.S.R.S.R.R.S.,+G i D e .+D.E.v.R.R.R.R.F.Q.r+3+t+c+e+V.i+/+~+;+e++ $ ", " + 7+;+;+}+v+w+X.=+>+k+A.h+F.R.S.R.R.S.S.x+G T ` ` .+p.R.R.M.S.R.S.Q.y+^+(+&+~+;+~+2+e+o+e++ $ ", " + 7+{+;+&+2+3+e+z+(+8+g G.F.R.R.R.R.M.,+J.S O.M :.o.R.R.R.R.F.Q.y+^+|+V.!+/+~+{+b+>+>+b $ ", " + 7+o+$+c+%+z+k+v+/+c+A.T.F.S.R.R.R.E.x.d.@+9.j.u.E.R.R.F.M.A+I e+=+s+o+~+~+~+o+>++ g ", " + 8+}+n+}+!+v+{+[+5+a+$ T.F.S.R.R.R.S.F.w.w.v.E.R.R.S.Q.A+A.5+a+8+$+(+/+~+;+>+b $ ", " g i+}+n+~+{+2+8+X.t+c+$ #+F.S.R.R.R.v.E.E.v.R.S.S.M.B+$ |+&+&+/+b+n+(+6+>++ $ ", " I k+~+b+z+d+j+(+I b+7+A.#+F.S.R.E.E.E.E.R.R.S.M.B+$ e+&+&+{+~+/+!+v+t+: I ", " g i+!+e+;+~+[+e+0+&+V.g #+F.S.R.v.E.R.S.S.D.z.g e+&+~+~+~+{+~+o+}+I $ ", " g i+6+%+2+C+;+~+{+&+n+g <+F.R.R.R.R.S.M.z.A.I c+~+0+~+~+~+/+t+: I ", " + e+}+d+/+~+{+/+i+g + ] <+F.S.M.S.S.1+g + 8+{+~+{+/+}+: A. ", " + d+6+~+~+;+i+A.$ A.g P.F.R.S.1++ + 8+/+;+!+3+A. ", " + e+o+;+d++ A. $ g P.F.)+g b k+b+3+A. ", " + e+(+b $ g *.1+A. + + + ", " g + g $ A. I ", " $ ", " "}; openttd-1.5.3/media/openttd.48.png0000644000000000000000000001070712627373446015412 0ustar rootrootPNG  IHDR00WsBIT|d pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time12/19/04TIDAThY\֎@@XB *XPD(ʐ=TE p8[jmkڪR/b[; I "w~&ysyq`~%ɚL73Bfo+/h273|)8d'" N33Ӑ<Yӣ!3>8|kWe}gFbIhD  Gxgp-J3S_Vh#Bw#Y͇"y2wc8'ܔk2/E ," ~[o7xMDDH+ >cX\cϿȨr[#JL/#Ǣ!?QPJķ;CSK~O%Sf+rBqp:Qx7 X*FQ.AJT,jvXWDh?@tL\@u?|\\(C8+BKlV8fY 3K~hCJ .>X q,LOrD,^f(:qxK[Cf^w}K%D澡!NhO6O/ ǡTGąd8Z (&j:+fс!@ %oODc]τ8esCV 8Y)B-z)(]oy[|C If+qitHbl}!$'ܑ:4\q$#Pf>^'Npޏhl\ނay`/ڀ¸өh|~*BWHI!rv*MfiA8hx2YV5MMDMTNjO vlަ5d?NeyZ+/ ,JMCdW6'qWEt_ܼUfVA`]3q]:yi 'r~Yؘ{M(2\vgh=  סJּuMuVh - wtB$ֿ;(-$֖ԳB=| &QLWߺp-sfMdK2P\1x^Q=C׎P1Plrm;Q9<ngD +33y脖a6 -B 7{ѱ:'GF g{#;ɳDֆoΧ֘Sfxgv0?25}4y} ]d,rD[RTbXRX|p[2\zw{;|:ԇBZٞd!h܈6q롤VUK?uhU(%+73^(/// Kpn,Ƃm 1]C^uP6;Zs Db^9A%A t'л@N'BEێԻ~`>7ANr'$H& Kbez9䛶OZ`UVҔFP@\6pںB[[{P7 ~B{|G , X DF=Jb$Ae=mƏ]mTvU;+SBP3o rA P z6C^ ia ]]]nRC Ɏ=!F"9AU|O"u\cY;? lsm3DlH ge Ptf%љ5ѕ]}Æ; ϟϵe,@n,qe>u%+4 :Hh(2dp;{LphW ; zt23vS| 0`P#}pot? k{.c3W]r1O(/A GuBZ; [ñrm!>D;VECP`!&aoLy8\Q:3Tm  t g0DkYp9ycQ]ZǸGB*ߌۏx}>XP^]Pc``T 3~jiikQ(q$w:eSAJ՝x8iZJuG O >Yu[ %>j]ac1(kLЕψl4 QrTh!7% h%@N؍8) f"p"?`>8KZ* CE[+)=>j yks<` ~zR  >YBI,GY}jP!{09X2߽'#XZ Z 8ȈǣFʴsqs:a/nļN]=-&3\ 1/<>ԀONj)ƅZ5R$'5%;\ j袛R$TƐbdL͎~-`..^SNgCbf|hW`sLĎ[Eo޽g&UF.jr HxCvvv‰[y413D3$.}sFp`>(}piV8 #RfhY%ܹw}Y[83}}|1,*!nK.~b4Ыwa1ڋ:BûOI+YCc=#A=}h"[ه+Pu-2]qسB+Yg.\`(Qk_8N9@,@.yWp%zy*nZM'3J3q_0.!ሒQl2R_Kh5q%'*ĶK?V>/4):g࿙3vB 0G6uu)bRA ]G~Y*1*u.Kw.jO|!8(-D[m[ p4k.ДIsMscPSmρCM=H !&x{0׵K;.Eʝ%EW"xDiHٽ}Iahpr愠r+^}zߙ^b{pm_JOǂ,k*=?:'E8+$!L!́MhSql,M{x=ӂ&|!&md[7BM##31UbYgH?U!\g`lB'i 1"_ݾq /Lc~0·ؒmnh3LftWHKDH 1p.H5 rCq&s &O># d #  ( B ~}!K=\DZ"D'?BOD0Jiʒ`36rja ,EYcg=i;>N rgb1~A2}Q@nS ދ&ƢgVKjp&bxz<.0aqJ:{f$QOgy]R{#t>σ${.e~5oՐlt(F$nhZ+||D"7c_VY9EVb톍X~3&%£]TÛ@gӄPC/Z GCC;GXF?CqY<{e(Z8 wIFٞq7;&+z3 }X[[Ϛ7<Sinw$ P^UՕ(^ՌwGHBJ.  A)Q-u_EQ376`gĆĹ gQZZrLŃ]I(%>ֿ*@2?vg=rSVMC Fr29 ʶ@n.cZ#6L11-׮]K2#vŒH[;-*'<>|'mG], RkaIw C* a-пW7dLpiܹsO>BeU|'afp2ea ~2f ?tPHU5ڠ w{^. y v ߿Ǐ$ꨬ,ÙMdEvz pN@\5M̌uޞuƆ'5/Ec|{݃7q`25Ua#p)MaN]q(:H["QvJ71{pii/Ue$\p-˲ 9ʕTUWO?™{[10+LkZTD r~. CmCPIl 8:0.RZ=EM[L #mVnGFB{˞kA 4|^ؗ1C>+ǥT2ױlYS981)Cp VaE,y(hSykΧXcxsp- 0_G||0*hF`۸|..v L`W`T-CղZꃪ%Ip2 W"RWG koo<=eQ]|KGb}=N7#k=5'#1Lθ$r*X7knOYH EIYg]AnN񗂥X"\UŞ~˝ Xcc-$ǐAe$x#aDbtv&>F35(2[Il)yW.]yH芋W4!@wʅF'X][a),_eg`uό—7j =b E,\P]̣f#jRpơS8 G(tZ#?SR7nwPKQlF *ؿEW}P0Eky[3;'sS^X4w\_)yU ^ \`8ؚoy6k9$Kppx;(+CZ/}u+{;r@mLs*AҮ\ԓwR?l}PB.3grJ K PP`k l 30Alc6 p(sPh `PTteE}po El75ϻrŪ.TA9cuŷ Yٓ$BVeOqmlٱ}"E%׮aOԥLRse`%ٕm';S~F Mgi~:ꧩӕ%Dٲ~+fB9ŻNb^B#R ZQG! TSsV;S;"x֭ZϝGU}`F>;n!f`8:[t5JTD S"yF@1SƵGow6V^ʭzDp<犽 fڥ  LΨ[cc:bYMOuJilBdԑ'QaiX1VL,B L`iwV f؎B$SfQEU5i>mj%]Xstq4$,] 9Eg(5%4CKqr2Ò dr X8iW)`V@5}18^6ߪv?l'd jXh#'N%%%Y!ȕǏIHM^&<' ٩@Tݢ Xعu=z_׋e:E %%%WKWv0>d2,qiUo%dPmF8ɧ>Pj:b+\^UM)8`:teY34yԗx?#C ?Y~k_ox$@PN1Npenv50 UQ5ߖpMS b+,F&O;?hĝ;},EWUljh g/H g4D_h$F/Nhѐ wo>wFwϷ*V XqOZj9hw|sAٯ eی $A"j6ycwN F@ $zcHvWƇi:xo&w7S2/\^S ?r$HQQ !!Ɔt5G6JTaQ z+-dCδt̝:kó]C1^^6X|).]:8" -q4-.0Fä0--EF]M`@M:Um_pB,[MI0婿 1%;heBXҊ%0C䨥>N`ӝ`+ܽE%ralݱ?.ţG]aYU sp)d9K",GcPf]5#r+ς7Wt KŶH8A |aOA =5=A8 vYͥ3Gk/&u42/AχR*x} 6:7PoXA}g?9TuVmqN,&tNЅ0^5)yPSW7X";/0]v-%9YeH':tsR,%P]C-gEtܼ^> @Fk b?ߨU %@N &0/n/ =[>pn {ddmNjH 6kipKn6?xd3N$WɅ0NŘqrӺKlp{lP_n|SP[w`](S3 :[?@Y@B1ۣZ+("j=r^ 7SK>PB1TUՂ%bF^L~3>s"LcO:ճ T7ءpvfOLĵ4"竡A;7j4;lipkl-z `YZoHC%g mx1KU <]rE0_.J'ޛ>Դcz\NnskN"9t$e* CTeF>!rB>`R\_!E0Y'{l+rfv["HNt f0p;qOיn 2LVEzM3MQe%002? WhvPlF$-9E!udɗ0EXd4n&GTU`ܱ 2ޚXkJL!RKsc?ntzM]rd }4y6xy ?MebXG6JKxT<,1Zuj#NYIs/4:u9Ix6E,!"P@NGa[l`7H3M90ng&&fBabٿ%`:ڂV [k]*TntGZN[]_N' U@\yՒ}T<*LnV\ zRθsbM'#^\32ڷƔEZFBe/Lu\RrT٦еVEE4܈*ut;,~#__Fx&$K %2I9jb8RX\}^:!di'^ 7GVxb؄a)W٩/xZ{V9 !-I`}@&¡T CSq!ߏָz~AK&KML] ]fjcK2yx ?7y80q>eZfʈeAҒ(]udf\ܻu0C*Zsi¤I2[9dz%"z9c%F>4Y5W}yE~+c S)x@BIQ9c&#=1WFOw;srrhPOJ‹Mͻ>_F4 $. # # Awk script to automatically generate a comment lines for # a translated desktop shortcut. If it does not exist there # is no output. # /##isocode/ { lang = $2; next } /STR_DESKTOP_SHORTCUT_COMMENT/ { sub("^[^:]*:", "", $0); print "Comment[" lang "]=" $0; sub("_.*", "", lang); print "Comment[" lang "]=" $0; next} openttd-1.5.3/media/openttd.32.png0000644000000000000000000000465312627373446015406 0ustar rootrootPNG  IHDR szzsBIT|d pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time12/19/04TIDATXýTT"0@Ti(3 " ("()#"HQbB<Q@Lx2H?K2 3;3]&ĒZ{̹;ߧ\ 4spEpY'aYKo h/Z->05VKy_ .FoZth8/LËKa ³J8N{ad7 tEq.\<84 Φ8z,t ͅ X- 0/m  \ñ$|9٤= =oL{A > LoPWg.|>35AZ@RpZ]##Gk}y.ӹݷtcQiH BSsqf"#j&@n;'W=A|8;PgImŊS}W6[#CgkQ# "9]1.24oTTU wN"? BLD_& }fdI@.R<͠mB/T%:Af㓢x.pDw sѳ ={y#rP[7-BGG+6]+R oѿAtDZuSG y&rd~KdfƁswћmޝSѷk 28f_}F8+V4HVĤ)CL"IDHV)T`*Ӣ{{5:,{tw,1 B[8LIkP\Y`")W'M(X.tJ3o 8d`S20%!?rb7Ԍǒ8!֔e F&}܋T{eUοYpy/kh |)\M@(DD'v@X %t:h`)Jm[E. Sq% D IW##C|SE[4kCIz߉t;9eų)l r$ Q7w# i}ĒlxV?XPs~QX-lDeҗ[ $@C$&HKKQ e(!3d75s+د!eM>oqCu).kwD1وcJ;= t@"M{ށK"R Aw/Xvjn T"F$Α )脿`@4^Ä"To0lCu*#FRv<^+(Gd&Oi4KLM@T.yf0#O]R(kuwaL #RrDs)߮kQ \vrYph4z*L׽G3XX Y#'رj@p\ףb_g qUPWKJg<ӆ^2#FH%]<][ )@sP\%kB@Udmm+jer"NfT<10 &κ!*xrgdhecamzl:IdOD$]6׺%H! Ʉ;v2U%""t&F3 ehhx\64khLdv#}*UrX5XӶh#8,hS*e. # # Awk script to automatically remove duplicate Comment[i]= lines # BEGIN { FS = "="; last = "" } { if (last != $1) { print $0 }; last = $1 } openttd-1.5.3/media/openttd.128.png0000644000000000000000000004553212627373446015475 0ustar rootrootPNG  IHDR>abKGD pHYs  ~tIME!0w\(,JIDATx]\V~}F n.ٳfl.9kl[Qy9pHܾ߽u}?G@Euppr011QI4Og^t oo=4iEוH?7Wg?waX``C(nV"dɒô$, {fhaJwPKUSSFw3[?ۧ{ ]-kD$}WUF$Hd$+f~UJ11QH{;a05ЖHЍX$?ƶX%<ۇ;xš<$%xOґDGN_SbV;%yG,A` ?dUkUFڞH؞|I% ,YzڜOHH? !C+U|gaaqU'lo'r`,M=aIS1;ϺzS-2ꕝ Ѿ@%IсvrV'~E҈Dj S5vxdXеC5?%فAC^.I 9|Zu.ciCxT@%IcN<&|#+UC;;[Li5zkO"{<{dz1H ĉBj׍Z†Bf@)d' m/YK" d@#|j׭wZoo;|s #s)xIPN_igLڰQ㫖6v[:l rSwwBZ @JӧO]e;G j:|1$H&̢_%@Oo*?nxMqDl-O?~B* B('a1ƷƔ6>X[ۇV!КZظ/ĠUU'GHE#ǚ3fj٪hZٙLxK 櫙foX .npuwGX[a|rH{C<-jZI$VhK5qÆR۴kfokw/k3+WĶm{LٷfL&݀à t1F"(j+;qXk_4%l qoMsޡ+j"}-_RdQ? 6ᷧ6v(3ovoBۚcs ۲ [>f)ōnmI@/b%,?>kW:th?ۿ,¼mp~ACQW@`rx ./nc3ᇉgtVuTy`Ѧe?'dȏ7YVB~ /%|Ǟ[t$feXwU.]by!͊oG |{LojgEcX٧fu Bڮ`;SW)V-3gO޽۹oz" 0^1p &~BMlCq`l >3┖t-i(" t$K2uqO@BlzݗL; Z5ĦWuKLePEQت!ƏÅ ga|.|w3|l mH5>s#Ĺ8< mmok|3?h]"Q-ؕ2H0RFHx=?(ne8,J;}7V4}xzyv05^B0vmӧ`يX~nۂ}ę3kB/K߼y{`>D9G~T5JB:훠olK%-vrueT 1wwHOSviT`p4?W+ZkFasz֭c b8i!1 Fp27n\O>8/2/HSRG߉cxte>{AfE>9 gOAty'[ v{ 2hQ߭+J[ɤ6ޯlƼd /H/e >{?|zUEĚ~dmG_2kZ3FtݚdS|rS[߽{Ĥ]25Gtrsi\^z-@޾a+0[KHx"`Pr3l.+jɤ&.U ux𩚺zCR]K-~V4p@dxOl1K9;r/ b¢ƘD0A}V2y_IIN=,lWԒ@x^9rdtnYN-‡I}`F?rsݐp&&,:RVDk`R#g(Ak)/B1WDis~Enc+T%\ S] g7'>84ܭkZ\r ޿/T.Xd.RR3k  =#;/AxsWx؂D"q)AD eY ӛ:}bfYIY~}VU-fv 'r%^EKwV5/^Ѩa}lٶqG9M$;hR3 {..GX<^[ϱ4V/@͠C6!nlt1qd^s7Yke-Lf˴{iuQ%hA‘8I *UAjp m 5< ?YǏ[%f֘.{;B*M_EM׳#~/I~fx㯋h[+8IѲzس, Nw3zvA[ԋ_DVKe-^K$B&$.C-5p1E,Gx4˨޴ńe"|kV\^>MW6~a5A=Ïq?/M|K'hC)):^p,`CM\fU.maa>[ܚݤKUV#Z(0ʧF16)7 `7o^?߀ RpTTt6ƳίiShN iH)Y]:,J]6wy ش5=f/i"$+RyaY2(~N9/jqT-#/ pKw@FS/5~ikyl!"l*N65 O9xXc'^! hPuqcvuΟeТ+h|{"~p3Ǯ-k\ %=fMz>D@3y?\x gJ .7S|.8s8!SX6m융%mim vC3Q eچdNuqoAMB`\^P ; y>yӿIoarR:4lkC=ߑf5 y<|Zj"چ{3;Vm#,=[{V0: i "3`OOi\O%͢ɆJ MB9g9ow[gt7)[[MvnnOSAN.ޮWkcG 9`ͪ>Sm ɝ{qe\"+aطu [[ cY8ޑNWHU}d_ ų!wPAnG`',V΁neݑ܌ϒ.i\tOA&{⎔InDwZ. T K_byfMqtCp<_[ȼzьssj pR{Kӷˣn7zӶ؃ H$L9HA܃;WtXԭ]WwE373vVnO îpҿi\ >?  i"^d.{4r[woKwXj%: 2‚pw/g=4G2љ  l cIH,:ićIx642IJL=&Yڸ]v[}P#wS^M#qz%Z0`Q9`ٺ`BZfߒ/іp.?O?0 q_ Xx,Ε+qI<#u*Z)9g!m:̽ \22'e"iv&LlE햃M2Bs.CRZQ%`b)[ 6@ @ǡ۴iA6x74\IV5{ 4F.eWjZʢJH[ZCK" Og/}v d<{^ߎ`PXؕG}Gt/A%=Iةe\{dDEYgiX X{ ɨRs)%֌n#mD1%n 5ŃF(oHR$su7X僨+ܚGf jÌ/(g(9KB5-q~OŰ2z7m[7x} "H#&ؘr,ܷ{;*z C)7͸hslL]35;ky.NUB->”7Apc3"1dw{"2+eT>_  2x8?~W<# JI),elboC测|ի_l2Xf=hY:qc]>G&n+ R2`.>̀@'dÞZp4QHStZr7iʇ5spN7/=l5>0ǝڝV&+_'O&IaI%&ކ9ӻȠR/9".Y0>|DkУ*[h'dLv͸u6s<)&4Qк"H% d F*JK e'$rE~5Rt4q .XW3ܚ]ȶ缂ڞY2[<ɳJ)0=xe-ҪXƑr`]bx8 j?Nx'O1E0 D<5{dͲhLEksALA*d TP?*jiH#`x8 `bbcfV/2&ZןH$-)xz 49۞sBsʳ#)\سI=Fx97QX^TŽhmJdFh?Nc2))>%v K^ZbKsg:ٹ}4{pn\0d*Qɥ55t6ĉ%krS.|ހdTTsq+uvh \tQAUk/'ȂF@?lhY3 .ŹSǐK832])W-Cu{%ލƗp˴k p l plg(5Q$MpӼ9a}e}"x ;3L_ " \ Ԓ`W2}h ̲"bLl}]-*XÿN DV fҦ9t?Hx;tB+>5; s7/E0Ř! <}6 AJfva B KS>hW"h_o W_"A1bD&cEES.K삕yɧO-mm9h>pG 1o7̝6lZoá{l}BVXM99 ++PX[.N>ɶ5M5"?iHǚE3c(3i`36{ԋv6e0Ւ1d6;@O@GGg"\J"A4=evH4`WlimRzѽ̜[7Oq8}$n޹q]m~0ҦY~dgo .%ݶqfT|x})HJy_Lo }n S]̀q%`Mwy ښw,vn/!aw).-'.N~1u0mD_;K_Cw%ttz\6u1+Jg)9KG*g{%PWWKMMxRX)%\h )U|d/dbmgo䬑Kmɹ[i]f .Ez}_]怳Q̓?+,=]4(E$!be1a%q> xx~܋!6k Щ!̱`{> [OBkCJ xNhp-A૫g&@ܧ!|:sCA҅Zn!Wi\'_y.j{z1 uDWQiDG$s8ktWI0z(?C␃"'J'V50%"bfx5v6ҁ>LyL{X\mM; ʙ)ӴݺW_op/F;2F}~_SI YL&RA$@j{jDֺe`Z.np' n ";!/S ӗO e?m"~:` th)p@:}#qC pYT&2qe>K |N>yAo=⋎{`(@TVS,p"H6nt=-zYbX:@Sd `_U(B g]<aL;ay=WҲ5FJrNQfx38 BQq8}\-{`>7gW0iVa{F9 AEuQ ؙN@~`kPϟkeU ??衆 Vٷlo}] D셲z, E0ՖbD+[mx!( +=Ųr>I?> –J6^$O@gu,nNk\2F@c\bV 3p< I(Ց4ԱVaidδU`Y>Vز}?MDԌ4,^U- 0D[OqO5T"~_Y_rYA0MM͉:rw9(yvM4`匀zUB $@nx180Rl{`pw+nC}GJU/?gL;PP2# Uuu+<̟ʕzrg鷞0( u2][GgI>.4> ?8Y'$ w?6aªRgMF|gky]bSC䩃u6WR ع?ك-0B ߾{6!5-[IZϝNY8m:P6{kHsD =zuinDž Ixt<"?fտa/oj߸>3I/~6>iJu(Bh u˳ΜnߴqNVme+y#eO.Ngb7J [*8Ԙ:L.hz%ɚ"<{O dibղp|"3^<ũ?"A$JD7f܅ydűZUy,[ ?>$[0}S&&}>| ؝wQֺ Ͼ~)I7r}\K:xXp%Ԯ{~-(KoHgCvzR\Uj"@l\sO 2ݽ8ъo&N3N $lظx*vjmU$"=B#wao`8w\K{h\GGE&TOS㖔_[_0y(>D/lik!!!&:»9:_ >n>/؅OtZMwzh :z#q6Wxz9O cm:3p0N޼M8zN!_ g`{KJE-`^UCk/G:7|1;Ph͗ Vb &}HT,)<==|JDU(p oPy2աċMyP1Of:8S(pzC$hBfN54滁sQ.w/_g ;"&F9@ W4'rq|8,WP5UA+08 b@5*Q:CAO7Prqgfz f&vhuHp;; 9aGT<^}')]h&Kx |n@q >H Z(ck̙<7;…3ؾ>^9HsN&_Gb+E?u Y`aQuVp+e>[꨷]?Nrם<Q]T){a |9RߟhikѝHPQWz/LJQ?Xz֨0X Ȃe2?e*6"zZi?-w@EK0$`.ZGan̩lg$b͜(@t.gOsp^B)HHuP{S"Ͼ!BoH_}0k櫴Q\A<+cJ,S}E:f{ F4'h W"a]  gAj5 DXoSL b/B%7`igb V,~0Q ؈sR?nw2M'yO zd[Ҵ8=2A%UhT"~ؿ i}Z*>0i9@W ;6G O3T|O2D9ܿ?zȥ|y)W1ڠ8׸t]=cN TISR_Jҧ`ď=~eMv*ƛC, AV'FPuEYQJˆI2X|)đcl8D8+ qkꖵ@X1"LR iǾۄ HJM6d *tq0inD _K 7k)P p\efU5@Yݹ^qnvXd>z$m?ǭE^= an#@*}O) v8Sv|<$&MЫQ#:bÃ`FX5u0,|'{޾B2l2ū~/v PֹF԰¹:Od /:Gr@}x)K3lrj߫ey#GJxtL5x')W@?E 7-Td t ,4r&?Ꮑ/R$T,|"{R [DY.G 9Ib֏Oj(kSٗD9P~7y J,Dn.07ƺJT3W Kx?;ppfѱѩ?ۡI9tǽٔ-yь2_y f_TU&>Ǿ[VMe=,b cniqnqN<>cfj7 5C?HxQf 5wni83q(T*Y^ |2IL 4LaLz%5RzbVϛLKNSF u_MYV#XZsAicɍ)܆d HO;VzD`NP>:VקשAQ5ruQ\V4iBU,RkZfέi7yGF B(Xb3Vt3)/]zxRGM,6 tua<$wR=% B^~ϖ%E gI\8 5,%󫔑yWJ4kGaࢀ@n@!vPΎt*o}6 J|+>NS\Yhr'r/ϯ آ/z%~}VpWVw)XPngzwTq^,+ɡ<$R:R@ߙHYHa7"R3Ѵ$?-00_I@S(e1цRn &6/{d$~jVϟ3a%#@l+2FU Ǟ~g^X|PlОjrg啔 @Ĭl{hV'. !4ϧ744tTiʞ(Bʳy@SG]Y >> Q:]ëPNPւ.ms]/fJ{)g/@ BpaF$)ZEn_[|zz֙9!b={̷#* [|̳Z.I,' {b/M1O&3$5`H)aF|5b:uAf5b/&?;BCO:G [/?qn R@&ZBPb4œE௭}}%r6Q]R8iVO6z 0 ߘ9 =?r2E:-\"004WqTݞ\(kDMMـBﻡ""NU&U />M _V`kmF`bʛ E嵬 :dUդ}n2yy>ihIqRd%ёƶgeSinOXHjPzחV͏ 0 bo#]/  T  B)&Cd3RiR=d+V*k84SBٞN|-4UU—1@"%GqSJgbr@YvVV@QS QʟzoJ{~ H؏^3H)0PSS<{}vy|w1$ ћ'UPnb,JQp_KA|8,Oc-ÏHhhNi$%'ОmjDq]"ˠ aa'{ b~v_]0eA)+ۄ+oe2Gi(5%LO朹2Kޚ: hq']J @."lxլ6iViVu0y0]wV|<'Om"pE9Loe$ t[6v9Aպ$jwVq=/7D-E,J$50ЯB2b͹YƗɋ[]+ "V}N)xJp"!=lxtLѲ &l Qɽ4*{Z%*! (|o~ROL) txs(2ܯ7>p|]=Tq$P,Kŋ$`H$\KC:{Y#sK5lf?-'̫op *4"6YX[[VcD ;XOUTSmXS CB-ue`}M~e0li |ێ$_/rA'cp)N૩Y 0&PG+ nSbB*VJߵ?~<,/TUiapdրկ5tաmB|G}Xd Y2~]*lְy`+n A0E\#c2:!c;2fx"c EZ8A>b>%7Mo2^ߙ;gxe0k|IվƫKفNSBX'xG弑3eEj.v`3aQoU ]pm{`_oooɿlGCζAC95]<Ã4v,x:Ip`AVp>o3~,>53/ NJmE_K tuu4_;`iԽY[V$Y=,cҏŦ+9Hc}*G*2vZȈ h(&̲p-2Ԇj-vF]" Ijs͒v{6HeEsa.9*-ٲ&x6z"!bEЌyYCn xƼn`Pg,/ g',0,a+B#ARGَ<0dA`0kfmj!{^W 18Gnт .E4MouG=%rHˬ zN)˒xKz{6( Ec }q8zVWRtSW^3&Y#׃[wA:kͺdR+NIhv+_|r39DU8>:g+[@'Y06RIm1+5 %`PGW+)ZЉX|0YTemV3D\mn/9zAI8d?>RQEo|c{K sylFw1G8!M+5`ۣmiu56(J)V[;_/J 4Dw xmZű fYHy7 Y )C8Bؕc U*l!l}qY*jUEcߵ(˚ׄRwF1  t44XiBk7^$_"a)0b3˛` ?l@+`a?8⦴Y>0裆NZ|W}4`K۱ 00ђ2I#1[5o#@NK@"wZ;^0džKJz Nalxk+V:H}>07■$9UC1uu_LdH a3'Bn+TcѹR]3ACz .*=ԍA>6Pq$jX1' 'TGGg,}4΢fVa`wTP8^-*M Zڿﲉ ;m1t4KC7->+^^eGOId4ȫSi=T*E[ %Uiͤ+FMȿ`Zm B(M}@ҙMhkWVih.>|5'.d˭lFGOT{5MyFiJCRӐNh/NXkrmmLT/J-)f5Uop5I 6ihjbm;/qJ7w״kKո3$UD,:bJKƗ#{9@_….sZFZ~ ,2&KjoeKOufg'{EN[ӱlRH:@Gl5@Ctk@)3ZTSPWW^H+J5':Jfh4hccL%& L?(-kċh- ~Wɮ[M,>ea;VT8*YvUa. 5"bAY+/ƅ}#@T艦~IGќZu:猂@}j^hIP WIb5H}VɀҔ,Öʿ#@^d,ϡU9Ak4`?LIENDB`openttd-1.5.3/media/openttd.svg0000644000000000000000000003622012627373446015171 0ustar rootroot image/svg+xml openttd-1.5.3/media/openttd.16.png0000644000000000000000000000157612627373446015411 0ustar rootrootPNG  IHDRasBIT|d pHYs  ~%tEXtSoftwareMacromedia Fireworks MX 2004vtEXtCreation Time12/19/04TIDAT8},qǿUh9:g=C$3#+&IZ!]X5zZ&SPPLggl^?@V[< kB 0s{~WJUJ&A6ulyn9< BI ,TqF!DbMO奈fQOnz9q,Cr !;VlasӳUG̽~t5 &f.t/B>B̷/3~à?/k0 >.z+0pAaV'!\%f#}ph~Na$׭0 o&BM17jo~^2SiU`j^$z7Ϥ"%Qx^G~ۉd=|x^ 9^D3 6`Ś7jRX$CvcNFP_a|Ѡ qF [(4uRl=A*.BEB0 '0 6`Ƥp&"z(g,vwq!삤]@. # # Awk script to extract translations for baseset descriptions # from lang files for insertion into .obg/obs/obm files. # If there is no translation, there is no output. # # The input file is scanned for the pattern # !! # # The lang files (passed as variable 'langfiles') are scanned for and # the translations are added to the output file: # . = # # Simple insertion sort since not all AWKs have a sort implementation function isort(A) { n = 0 for (val in A) { n++; } for (i = 2; i <= n; i++) { j = i; hold = A[j] while (A[j - 1] > hold) { j--; A[j + 1] = A[j] } A[j] = hold } return n } /^!!/ { ini_key = $2; str_id = $3; file = langfiles while ((getline < file) > 0) { if (match($0, "##isocode") > 0) { lang = $2; } else if (match($0, "^" str_id " *:") > 0) { sub("^[^:]*:", "", $0) i++; if (lang == "en_GB") { texts[i] = ini_key " = "$0; } else { texts[i] = ini_key "." lang " = "$0; } } } close(file); count = isort(texts); for (i = 1; i <= count; i++) { print texts[i] } next } { print } openttd-1.5.3/media/openttd.32.bmp0000644000000000000000000000407012627373446015371 0ustar rootrootBM86(   /-<0,5# % 0)+4+ -'"/*&,$*#B=8/$1(5-#˻DCABA?6D*7L*6V-3_1/g1.o5.|;.v:-@->4~K2C72h7q6o6n4k3j6m7n6m6l4i7l4f5e7i5c6a6_6\5Q4N4tI?}S7kH2\@-T;0<5122ABB@EHjt{ggh059SR^JC}b\Yaedffeb]Y]VHySQQ~Mu:XrIe@GM~ WBPDU@u_;kG^\TBgGnPwyAKUACEyz|{u f(y1+v7=>@A4zDHHI?JM;wRNbckl}uvrvohoZygS n j |y f~n]$$f(Z+.#k.V2$f$c5640~:1nCB~+P}9^*@ZQ<2UNK)Bh4FbD ?{$'k]SS.8?'󢟿*R^bR⽠18=6LJ4(ûe06E3$jceęW/Oܧd^ \𭬫ٺ)S*X"ši lc*YY*ͤ l"X*STj nSTM]ܧ uV&&_P[ ~fzmd)&+e# Z~xv"#[TY"*l ~fsVMXSQq a|hrd_M{h a|xynM}qtg}uwV}tfxpozf{uvvf{vxziopenttd-1.5.3/media/extra_grf/0000755000000000000000000000000012627373446014751 5ustar rootrootopenttd-1.5.3/media/extra_grf/foundations.png0000644000000000000000000015330012627373446020012 0ustar rootrootPNG  IHDR @@*NsRGBPLTE 000@@@PPPdddttt4^xXIY R'/_>ןχibL`4D$OJK-Mޘc?ۊɯ:֟tte")V2u+QҸaUVN6WkszA9W?遫񁥙V< (.Z끨~^k:i=Co[ML``.+S0.nuDxYQ#z{g  z;r8vje3y?@dnjXsgnǘ=9u{o,?4>{u[y='>c'z}X<D][։aM?t~*U7n^Y?|Pw#?`TzpqNEV^?uުJ4?_9ԟooݕ?Rਓ8r] |y$:@SS|.VRp.Ue{[6zF9+Wdv̟;nS/~rMG#E^o>_Q] n֮0.XS;\t~k~ !f|0qN2HiXIm :*zy?YZUks@s;юpWGkfM[>n_!YV P2Ї+a"ompnD@:)[%1Ч7gcO vВ~ ˯^{d@KʇFubh4 F@h4 F@h4 F@h4 F@h4 FQ 4BQ 4BQ 4B-N ~ ,:,;xcpg_ F 'P"\]&XQ$KZahq&.@0?0ą"r,`~ZBW C $n)Fh /A~<1[GauiBGek/X!'6M<⥏'B>M\߂J<⥎'>n 2 :}xKO^ux)㉘7)$H<⥋'^uZGTD;. AxKOĿ42D A/E<1歪D$^;,skGrk$H<⥅'~q=$v3]xce^8A{@W׸C~\mxw}|MN'xvЊ庒zųx'Qø6z 3^,7#EZIJ` dxT\PV_o^͊S8??*痶̟y-V׈wb| _?u+qCPy3e.[ Mp,JeJsJ8~ xN*{@MCnax*/ݽ N,+qu+_a ?ϵTK%*={rU?sR+Wn,$qTxoP\#AxGoy vv7>=1\)C^]@Z篒 ģ@ 0Uf+{}aj7F {=W8\Q %؟sJ.Mga8, ţ@&I[[}yaDV,Eůq@fMڸAQ1xJbgo9 R={ipoB=xORn(((FhFhFhFhFhFkHA#$I X3Ū*۰{+? d6=ŏnJ_e/G</[@d4~SRUJai,~se~i( ?'` N`MZ A 2zfkv7C&8k\I@$|wc̣z*ċמ4^+7r1HX V T>'=^~l$ċי4^Ye&Ut_诃F[[cRϾT(8~ Q`5p>Ï{i "reepJu@b I6 ˇVU&kH_3YT&*wAx&* ]>,2'&|f+YJ/r#aCB$) V~>y\ $vm 6y2-[F߮k]Ax^ KH0BdY}>0TsGVfT:ڕU˥KN8\0!xnyb+?|(}պ끨Q7Pu_Ә&Y@WlIR K_T ³FIi+ *C>/k} jd 9ܕ+Ϝ*q9yL̍Z#8^lTY}=L|=׬M3͊^J?Cɭ7-ԣjՐ^hzeQ0N~zM+2xX]ꯅ_tkXY?)s5_\xVT0c?~93 [_SߚL_Py*7YDZoG7]%UV=0'~&2k ~}@x1fDԟ߃̙ͬ0rݙ^nsmO3_^"kͼ*st3[ΒWq7Sv쥗79vZS=xy/XSCǯ/0/jmeQWJ4 ?YF<;~x 凎_^@HLSJzn3m*g`!׾iw|;* ƻ,c|ïa7(~HpzV,ו)UMQZ 9<?yqu+pmJK }sRUvkx$י`eD_cn04j0kWXPٖ Ax/A2- ->+2^2Do o``B#M>le\SÅ* >Jj#W ?ip5G>rkf QJUks{;|W?y/g_3F+@~-~NpJ:~x/̟Sڠǀq_q׍ȯ` ^SM,X -Ⱥu|7~^~ \*&~P7yf-.4ڬeh4 F@h4 F@h4 F@h4 F@h4 FQ 4BQ 4BQ 4B-N A}~/~@h=@@ ';-P<ళa $ $/:%-8vZ:,8 ?00yz@s[$ՙ|&`x<Ţ(m8ёk0Hx] v^Ou$;O @r&V25q^x2 Q Z06I";f@Ja{m~ط6?$Wi;F 6N R"5?;l4Z2F N` FI&Hؖ] JM`޻Vw7ٞkY RN`{SJ7@F; D{C~Rʸ5&HĦA w.ߎ+M'5Ҫ  {7~+eߊ߄t8Gf<D F,GOM_&)~'!/ͣO8p(~-34o ?7@&WLPFbsY(f1ZOux:Nt2z9(G @29XRKr /mO/_gtL/^XF[[c\VJIku'DNŦV/B= DW2ծi*b%Db )ƃ d"Q2n״3Y߰ JVJr<;܍o1 /cJ0j2z~wҶ쥗7Y?Iu,>(~ P0h<@&R/pݺ=W^4.*nsQrhim M/ ~agg7z ΅[̭ n_\8䩔Z:;Vf8 _pXJ4e b쥙3|_C\W.?,sV+0CL*S7^l\ݞ)zL jK=)1x~W3jՐ^~h(F~~zE@ rH2:?~lZ)9u7gOn4@(AKJ1`ެ tuP ͠%׃fN{ؕy3hOC@Q 4BQ 4BQ 4BQ 4BQ 4(((ma>8v|( |%ދc83!o_K|M0rB)) IDATFhۜ/X{J0R`~x{@1OZ&x/$œ &+ D#}*7@ &K D񆿶Cek- O*&x/& LWBIeӖ & Dbz<)`⽞@"6 Mx2{A(^p/m(UL0^Q V3!{wVj{gԣ}4?t_ZIym`j'F:~ xc%.+[ JcyJ*/)bmPo7?‹:~mQ[T+HG2#Un̠Wn_ϪD54?tb%.%+_@]vCÌj3g6`9B_po=~x.~c~K\ *7B\OxWq7v;_G@J ƫ::~x Z}sȈnMxZܨQDc n0}x}b1%nvg~WV_w7?4ؤ8{qazLW?Gm-S|%3lkóO;:\@&mċ ĭ2_k+&iP<} xW_# Dm\#6>j)B%x~ xWI[@XJ1eݑ!x,nm$x'F Kd֐H<H}Yw K^ 4((((hFhFhFh2 q#?'ދIO<K83! 7I❊B蓸iVpH< 8/ &XP\TLo.?8?I7=H3@߃ S,FXxGxGxGxGxB< $xGxGxGxc} ƃI ,?7@_jX0lp8O5MO Fk.(~o`X)(륱zX&gxc /_{A T3xZFl#$bVx~`x:  P/VƘ H!kg-+D?8Q(8~x0`Un8nWR[UFEY8bM/hxW0 oHA+0L Pflf0wVr-LVzG _;" /F P/3[!Bܸٛi/Ի9Rj݈7!a7` x B&Y淡VuVnw,ܬgxH~2/<~C Ƴ\({LJ+LsOCnW-+`:@u/o|hYZgK82((Rzfl"5knOǛ߱E mL;njOǦ> S!xKHkƭxdD~(ﭩ2[8#W UgÍ% U#B,L""5eJ#g^k}>9vwBxt~BFCO'C.|{\op<>{ {!zC:$xp}A] ̑@)+&v8Oh4 Fa&"g@[^/0~ȢGҳU="wQ(ū_a* x=xuTI %rg zoC?@wM6=%oDI{7,taysX@NܙP o0/"rti~t[UѴ+3F>m"p4G,ޑZuk[2W-:ȉG1affJTnβN#xϨ{GWk黇׊6~QQ~T"T. Z5.Yf3A69kƃW6َ|͇4kN&ڮVʬ2lTU=IZP?H"rT :u㲟DJ[_ Żׄϯi_,s'WF:W71mH'?@\{s_rGl'm#?meo' >3c DэJs8V~=M:9 ~" L?JͳG@Vo0lƏX+9d^{0?s7yXyGEoq}yWC Dz"`ݞߗ޴V & ǜh-)}J4g G 21P~cT@槟.u(((((FhFhFh8ç+ VyG~O8@!($CO^pɮW|P!E n"=n+42ca7eA_{xEQ 4ڈkGXSP5"0~?KkRQDf]mg0U3L>˛+?9H72݊eh]I73~?/]%s3Lѭ,..&-xSʥTnN.ǫzQ6~N׾zϱ5ү~>׭T+A\fn.T~WrTЯ}FuMfeܥYTUrZW4utk7|f^8~n*wKK/Q~k(AӀg;V:7d?~YO^vOgҭtn|p~_lmct'&MhWB㗙o{A~]L]ܭ} I \b^6~+(0siU,FU}%QϤw+KV.P岅aG1 Qwx6$!Qw2~{8eni12!2x#|1~_͊WQ 9VMR}G'(`Wx ůnLVFrN8$D,S/wW>~OZ#@<ȪX[#RIpU*sJQoMob~bkMe}`dS0qB f3bmO h+ 7g!vHiXmd ff3 RTh$?C3~3 ̦`o=C iP'`oMNF[Q 4BQ 4BQ 4BQ 4BQ 4B((('q8V^x{'Dx8E%ו;qG_w $ 30+@_@C7E<-K (?`AvE݃&UBIAs{KCD<x'uFht,_o-W|?7Mܗ|#u߿d
7o9Z3QVv+swm_!aV|~"5]@>bKthQvo:m~LE O9ބ|~ˀ #h$,b.E ͟ MoO;~4_?x^;_1G~ /T3V@0H+]x@HIM^ _迷 v+M^aS[`i&`K3J{*cZhw '7I`III ]6 ~{7X Zi1Fg*d̤3aFYy-EdBm#[QnR$kw[ DVXmV͔2ZSHLXwb"Ɣ ,7)e/׊21&:ֺ/Y~]jq~ys7J=O:HK`,;Ⱥ, ;Oc&N@~7X VU\g:ȴo~QK-}+3FI.AoQ#$wor1 :lfVM,4׋w{xeF{xSn2w ,vg;{A~~{*XMۘDTUjrj,sS HE DDcʯǙ׉@,It׊ɯS>@ nV+|%[ڟ\6Wnɍ4~" Q[ܪR>Ykxi6w@u{Y%u`X \r)YokKdc}~z`~oc~s>N 7ϡ%~3+j~{l+t;ߎzx;'K|s2=\".cΑ>-ޣ;~? Dtނ%K {8~^?u{v%0_fOz3P"1nQ/0G~o'zֿڋ\X=7S>Xn8lO.8wsL6p}>ooN$uq܋\xGg@"7@wN 2Hy.@c@1%m{ d=A"K>{->ʷ7ImA{(qڋ@";T"$g߶2a/>ex;pKR IDAT=Mw]>x;V $&~L0?h~!(((((FhFhFh8N.'J-l؀HqAB0}I'L<Ŝ1o,8։mx/z`B'>v6޵Dxyw] ^w"o) Cpx6XD&X 'H`y` q{Dx^"G<1e$>:mr(+xbxKٌ `q 7}t:&C %o`~oL߄8bAz3oY|Hqk+@$^<:MN{ܟGb '(║f S7l!Op{r ؎7N@~+j~eDDMNB p߻|n% Dᕞ'LAow};xv;mv X_j~~Њ߃L$:ȠU W_j܈Cg>hy +@ޑG^djLBa{v1!z] !xE0sױ{/-0̾׳ځ^ǦVq C| /@^Ju`KxI{; اx׏$¯Nq1_X//f/2ϭ ^~V>xww?i$QϤ׳eZ ҵMpK ›Cl6ZOuJ C2&~U {r|\J1j į?]rc3->~8~OťFu9`h4 F@h4 F@h4 F@h4 F@h4 FQ 4BQ 4BQ 4B-N b#㣊Hx/~@h=O1l@i2%fxc 0?N B%%lĻa,fg0/_{BxQstT/#rpcYE̪LoD_`"z=GDa^ބ|% K@~:GY!)x}b I/s7zIA %f8Kٷwo`Bxq5zy@%B gwBa+j }ou: 4`&R/Hw 2K}J~:!=)9 u/,!xܪ3zA[(\ϒ]7yӹj'7_p}z4oQa$,Z"woK ^7Ygg<.0ǜ#uc@N qh}C·3Li`U/hO7`}ϫKxBx{8~Yɏ,C Kut72JGޏNoP?J,iJ߀ aֿ_|_XAfDz:;{OsO\Hc6S>XDhL;EU\<>W{P( &uzAWbo"sq+̺ě)AL1ԟK)N7W5˃c?1,d.͖[~_^A?1çY1(|Q cOa8#oO|2ļ*2o=Șs;Y`fNGhS coqf/C@Q 4BQ 4BQ 4BQ 4BQ 4(((mq9|"N.'KxOI"c"?̒#ޓrh]4|ċ%G K xۯq G' AnnM dwO0m< _#8~ ߱-Z\'=xwAƥWS ߑ[<(.>6sٻ7NX~5f "M⍓ǯ#A#s{OpQ@Oፓ_w_-p߻,v(]kC\>7J@~}+=Ot /m_3`un~ @/@^Zq{d~cBkޏY 3h:-$?t:>b"S HYm DϾY8 !xE0?tzu^d E|~ ̅zV;5;)FW"zfY_iW<@7:~CؽWQ/19jݷ+${ly;Kߧx׏$¯~~E$ ~!ӬiVEϨm,C%8o֏7s2<~.pQϪ%X q}%C҆Kp 1~o^dů^Br5 q(=̾MdpBn ;c/:~c(9_o zVaξͳdTBj< Nfq/:~ݤ%K@gA)l6KnAx/"&! gA)m|g2T/iO}q:o%_'׃_t 9~e@J|XBWD6m+%_t+ !~e@;Є H&-fJeE/%7^ k@,g˶Y| ^^/bw U,#UDOYe@ vHb6 2OYeqhʍ!(((((FhFhFh8*儇zO? 1`=O9l3;M5d $'\xE{pܣW#q_J1'n h"{0xEC ڧV#9lB 57zCO Ha{_~ Oȟ2 =%.?e*;K\ !{F%.@{m~ ;-ƊW痸@>7wa^2YWTC_6řk߁_ M- /eK\ 1ʿ?K\ q|vv˿o/ql+*mvߊ߂NGylmvK08wOM_eRA6pˇ\Pq5'7e G<w._[Bx Ln qrڃDP4*zi0xfGςތ;n[ƻ>UB-?/7S$ڞmS;EOHsMx:.jUr9;nzߓ _ |SϪmzк;$R ҍ alJ9IdwɼHM @Bgrًb6Qx $2uvylj9ES_ ļ|Ez>6`"7&C_>Dx߷F@h4 F@h4 F@h4 F@h4 F@h4BQ 4BQ 4BQ 4B@ FtGx{^xWx{, &p 9Cdx _K& " OwRQh<ۃ 8_R\'n[0`-i*~8y AGr|AIP7 o''4x'x(h4 Fw;l7K!x`~%ެx;,~y) yvD,Y0 g}nY0 6qA, D c=X0HvDZ LɩZWFKA ?O?Eh[kX>bFR2% ?tJoE?ՉKG+^$?nzQvgsuፐ:~R$ \r.hd-w_ۯhh.?.%AֹA䇎_ޑG^d@l~v}6s!Yo Ͼپ8 !xE0?tzu^dȅgC,3^]MkJ7avhiĪCX |׻|XϾ}7] ~Efۃft4y,=W{?ۣP cͅ&g҅cBoϳ`~Cqo$7d/2)VQԳς)>am{{=UŻowDf>=nN`Ǭl}};6=,}_4@Ws2~׫,X~\m{6m6o9.ΪY} ĥw d>o r݈,.i.b \w+4 o*~Q+^ !KxR Y\.f0o2~@/^8KU [_*8lV=K~E oX@B4/M8?]:=._fݷ/nAxF'd^x /_XA S\֫Op=ʹa^8?5/0~WT ~+~ސzIU n;޵Ζ^%o -_A6r/_Hr%^R!Gˬz?-P3o( /vЇdrHgǽ`x,>.!1xww&*⫘| IDATϩٲiG{TuLH,^oo%7MQ f=(fBhK%/|,~xקJc[~!fY^ A_x[@AxS;6,ݶWtx]D-M 7or=(mdñxHsƎx3 D%iRm%#6uC(#O&.T Ymp8 o! o6Dw9md1xKuPl1x3 D%qWNw[@T"@)p0ޒRO'Do^(((((hFhFhFhH]rC=v'ދ*o"AcHz9ၺdx k~hh<`)kť"$z`Ňu:xȉc0q~@$x'xvD(-vC8 t6ޟ]wDZ`O)6o~߄f x=xrY@^=Y!^޹\A{7BrYHi_"ݔb:H![eA.i;{X xWݱ@'AݿP'ƣ@ sӳ@'AK:^P oYX %oD(7\ %oD(kAK:^P o1/\J:^P o9/J:^P o\[6qpPҁJ!t_˯@'A l&p~[sY02elЂkw[h72^b gY,Ͽ^Sn_=v{Dpw@6;@[O%.|oo|[cYŘUU0I8~o ]`>j!lİ9KcsT67Y r!LMS t1hA%>|(7! ,vX ]Cw6O@ے߈^/c v.?V}m؃b-9|NۯRCl9{zM`>j9 ­nUpn͖c rzlܦ$)$^w'Qߚ.:`+lvs\*GJ|܋P/!xjW ?]d t;4;潪d~wSc@/1-B0ߝۣ]=BMnOnLAIݦrw^ۣ(Ч%a^N dX/{?K$.͝|Q Oq:GBM^ @&i;U G= dSg=lSx؋Mk׀ .|P ]D0~S7@&=VdP~cG 3C@Q 4BQ 4BQ 4BQ 4BQ 4(((mq9~"L.'<^g~Ph=O.i%N2|/U<1^887xL^40U7 ﳜ;4+।1>~,AZO%׍:h {$Jǯc`Ip%׌9`{m 6xۯW#A{?odUpCn_ߡl 7%r4,o۫?wm~8bSVͮ߮lϷ7c^5~=H;de?ቖzuZ7W?\zs7Zj.6`>6ϧ[1~/S|nBL{Y=^+Vo[q3>m"frSl[__Wc7[+?w{1+pu*v4͂gzk~aoי{](z6~QYok=/c%:=Bj񻿒-d̺ѕxp%+ߋV9)vik/MgzgU{5܋u7m<#esq|uǭ@<;+ůnޏ w7e u)w2~/vOthWC^αE f^&~mσ#?9v:_S8 D[߿>NxU~ةc^!~sSSSL={h@I|41~_χ6w+&U~&o2%ʏ[x?'LM>d@h4 F@h4 F@h4 F@h4 F@h4 FQ 4BQ 4BQ 4B-O w י_ \ߟdJ)˹8rrK=_w$f^&_O'x?@6ȕ<ܗ_}Kw .;d ׻Ǯ\?vᅲzƏdQ!}}m%4~ $NMUwKpiA i@~7fS .;8! -c .;ȠAh(Vy˯3w_Kr5vGK}ɯ;m .;﷌+W iW\;WhLR^KBZJaagٹ>RKzY0ڵqhq_FU> G E~3ߍ i:^գS}hCde9O(DEĞE(αx :AƲy~0;ARD/^V{ ڍ>uT |)4"gv `$PAv3ֆǬI.LA A B4A A B4A A A B4A A r0/u}>]|JWݵ I4>XR䛨|a&M%ͧ0ꪠ+ ;%m`P|*m>u`ZP|KjC fSW+V8KSԂ?-pk@{x| ɧ|xa~#!U^^%/ \~o_dBD/>AnS.G#Y r}DM"ȗ ;$I"ȗ +{XTI"ȗ { #tGt4cpk{Gt^ bq&U"ȗ V{*p-|Koa-{ #d)|Kof}!8H>7azQF1S"ȗ x=B |H$/,Q"ȗ_=VA $|)!4 +|KFYo_BEC4 ,?k^/,}`}iBarElŘ@ { 1sC٘?|9fOlRaWVh&H7LC=%-w}0>+  &HˇlLC}>O7+3F>]'Hbu1&ć{{/q9_ by++f>a%9rrOY+%{\k>&1s[e|eY|aU_Y`g/($`Ǔe/Otʦ4 ؅?7}E&G76;ޣspprpmBnEp7v碯ȱss{ ?~ipl$d>瞹߰$lz9>|S6>ϧ_Oͯ36k+'q|kMBߺC ˷(- lL{A\/axXqX r[^ιrRk>]3 ,O{ȱ+d@qʟ_O/j2,&x~|Ds"Xw*8))/ lO/ȅ;Gwsu/zd8^Ź#^m?Oη_:O/S=iSǫÛ_ov?[9}L,œaϝ?s)Zp\>%?eIS[Eϝ?s{8|?~ۓCTsO,\7ϝ3/SVǡoAMUFv7?/ȟW` ll9~xwy 6>>''v r glEKL}8>`j)bz T=wM\OSH> A4AH."݌ۓ//9_m-N0 ˋ/˟O)76JIh>$/rhAB˟k)w&Jih>$/Ͼ.n|)hO2$`4 "˾0|RA|Y?/pM0i;E͟$%ex|4/OT eDW//B)q D "iVQTX%2h>Dė"#*4&G@$o|Ӭ_ $v\~_ ̰|aXar<^Ri JR/H P} ـTOk,/!zB  4`vQ{ŋdȗs>.L|r} O0OnnKg%[9'W l4!; wU~}Q#'Wla$\ad9/_ =3%%`nWlk 0d7exA7H_!1b%ey-Sv_[AN>y4 E/p֪S6=` /؅oQSȟ_l{=F\x17zҺ* N~u]N%E_)C9ϻaNwS'^P0cۛϹGδ ;f¯ '$=9-3͹=/_"4Vy-.D/be\pwʰ|I洱?߮X|k%AA/CJF'aDi0Z}sgsx/_"d{|)rhRE4Bo\q|/ l}=Kxa n!_{eq8x[/a>w8y  :t2/2|6^mbkw!p~:La+)T}ŹnA|AEnO8|{x|9o$D?)"_&ۭ }?gu+ B,6ZqE\&۱}gYd$۳z 4"eO|woNAP2{\lÿ4ȷ h7 hA! hA! h hA! hA`CuEwv}@w)6$gI$>{KtgG|J{+xſ*p+/paWOa&_fңP>P}t>2c IDAT7>C,XN3J05q}0>O!/p#!E_c{.|{A,͗0}#w v@U>}ߛ b/\fED|ymu!߷ &P=}.Do)_&>}ߛ /} _]|N9E4ȫE>}9eY4-—{O}u8YZ$O#'IDgA sz.No\y H(_@BobQ2"|,<}.c#~`_nO`H]|ADd/$0,}.(7;KHRl-wWxrcyW}%/,}h}%8|a7-"!}|aCO/q=s5_,3+|ACO'חA.-s>+Q__l֗@7I%noX 8ܘL>]O<=6 K }9 am,٨QaogI=6?#D_V-p\E;3D]:e=nK<+[,;ߔ?/}ʟ?d.Hz%|d0'WgOm|e o?W}=!|i^ZV?EX.DN%G=-޾=/n|C77EO}]甿7nN =VZm=ߨXdC|?my7MWgߛA~^hfodm֖aO͖BߺC˷h=|%p>pB⤤o wׇs}w}"t,ϟY_c'%ruKqRRw(̼Ol՚Wѷȡ-\zj 8\kmsVw%Yӷ>~ ·o>~)3lz[Ne{^,'}2}-ԱK}usK<{A |~qwV ?Wdyn~PG,hO9n1?=;Aw?gCd~n>.9zx6]g_6Y  A|;mG_$b{ɏ2Hfxe_#N wj1H|6Ș²l9 s~qxmk1swdxSSߑ |  hA! hA!  hA! hAS r{'q%w#i>HjC\6z5R=)9x|=B-0d9LO8Ab<~`mpk|| ɧ|x~#!E&G}}&qR K>{AR ޓ@ꣾ7G;H}F?G}o4H}I?M -0%\䟧oa= L}}mG]4 _&ܻ_/E} "O/9}?}?_ !(0%sr`}aw=>#ߑ_2"0 W0} /A湜g?|dOalY^ )v 8'Xa2 \2]`Mp|.g8($W&IY:A'2oYg!_2a|O00>͆F w Yn؋˩m s0|^{[ ?#DKC2,l@}l_մo|15v\_ bd++f>96?E_@=ewenmG~.rK'__&[_YU0 Wn sBϣO`>AnN%N9(oO>eS6+ypA\||/!<|km}+({~zXnXM^^k w Ỳ˕+v?䱑q5 (Q8ne6#VܩOHÒ7@r|D'>~^ӄǫqlo|ʰ|`[7sHA|W3Ozp}Maűs}y x1OH ʟOj9dE_U닮j8_0"_,K "_Y'{_`S>=9>źw\ƣi߄|g˟'[/c2 }oO!8^-Rs\^`]bZ_A.)2! b_|K{@,)8|36EaBeq}i>8ya\fi}jFl:O8 "3fa}kGp> j)~ϟ'ߎK|?+?q 2d6x=+-OT7yA B4A A B4A AA B4A A B4A|And=~B:> ߸rX>;'S8E dH廢^OUJO),9BSp>TASWl)Q/4)Kp^S`>X}!,5q 'aA| ɧ|xA4A.w~|뻤/|@'s ۶x\A \؀4vܦ[ߘ@>w{i{W|AN P=4ڃ M'lh|N;0}{ z߃ H M6|N; }r{ b67x!^˴>}A.S$.XKEi++ <"\|2}x@%2B}Їv&, 2^ 2GoWA_QЇtu?sF4 i[TLJy үVL 'g__JpJE΂v EL)<˃)ޓGmxYP__L}]s^_< 2Im&>"=}'cdžI܍T_W).|?+A`nG+4uƦXdC|`6=6M|W_) p|αg  w]a>^s {}W}j6JL|-6ZxkA.`4#ùD#1PmnCJ }}w}K=kWR_[6 r)-/火qRR w(̼OlWѷ\_)ߢJkʟA.[c}/VSV!ku]O㭌{=bo>.|@'}tnxf0@v;C{l]˟ >7r~_Akii}{vw4DKi>@^A cxϮg8]ϑlt6qwDD"|5sNчg1>A'? Q n+2K wj1Hm1es>p|) {;An@wdD'Iڗ)  hA! hA!  hA! h8AP?b8]!oGObX>l>4xO}MeA]QIJO)`mBSp>X@)s@>6LuK >Txp|@@~{YqC,Xj]xO\Q| ɧ|x~#!EF>!h!h!h!h|4H> $h!h!h!gL;0}}OT*>Akb+uSAz "3]X^i2b5v>J'_]_?E^ G rKjZv";!|+"F>Afl N|S6ї2Ɠev} 瑿'yp\|7DV_mEm}+;7=K̆a5Nrn{{aN)̀yos'GM <с8oe6雭}K?겡or`|W'>s}5b Vq^,6 }fc}K)79$|n+ _}qmcaA>K?78M}òkfy$|PO‡?9k{{>y+|~|Œ %}/'r?)^peZb]/S{Ei<-w)~ȟK}ʣ]s} QAƫCϑ/va=A >%e؄{ɟ+.YSHGS!+B9da}j>x/}FeY}kFl:O($|?r/˟nyl $;|?O " 2l){x;zJ{3^ br}oOTM./LA A B4A A B4A A A B4A A r{&u'q@+O y`FQ>}kz\SW z_xΧ|=BdV d ?(1[!oeMEh^q j| >=8AA  B>vzv-B/hNEhYq  B >=(7)^'nAd-VQTo X%o ַGyXȆR6m8M}= /^`,/,k>}=5ȸG;oV&_d-e [0s>r)Ix3c}EZ« үYg"WrX_~ = 끎Tr~׷G yA4̰7TX=L>ꁎob~ oU =3E決),Xe{h03Ĩ"E~ oU6eYEAﰤ{Kt=i_BU87 NT_5x1`H_1uW-=Fߣ9zA8e/-Kx}KzĻ~ 7 iauN6~e|}@+o{{ %=1O/"f [x#&%[02nwJ@_܂AB` }U}xoU)"m\| |b}-'iyPT} zEd s%oOt}O㭌 |`[x#ARGav2ӹ}=>8^];X_=hywl2ۣ~C݀Dz~qgZ$ʊ5w(vnoAvgEBbv8G~w}AD}|\gu>xĹ4H=cu;Gc}= S$Ehz b9҇> ^A )}Ovnﮯ_=hNJm[5S,!h7 hA! hA! h hA! hA`ߡRW q'S*m>H4|KA 廢^wU)A^)$(z6(0#JOa&bS@ np|WH'P?Ăf)l{> 5 B)<6^ABtn6o|͸zG] 癿 %xqyʳ&6^`n b7Nŭğ7AwL%>yuğ8A7K&xӗS Y= xAt%\@oQ/0=`5, ~d[޺ğA|q,gOxGO{:AK$0ހiDb'ğ?AP ~w0AX KD(z|c "7[&0^A b&H=Ar_~bW@xQU_Xi|cOEXa2 /v,_B 2y, ~?0%+E׀5{*+<<%0+q+`[>w EP6i+翗~&03D/r>%j\J4͵~!&+`eye~%WrX~@+4c>8Ɋ%?nJI/w'"zx}p-ZtpS˦1 9% <S"7\??Y1S.~XxҔǷ}C ;%} c-_~ZIK4nt1_;駗.|+rYWaN^s_< IDAT~N0:z߰$oV[QA_/QYr,ѰV~]ܐpPfޚ=V9<}_~uŕ 1o>O&]{u ^9;=~ǵo%n|-k3^WN~aPcޔ0eot -}[Anc.=%]}woG}Ce> S&6/pYicv߾KUwv6pz"OWs LH[k%#! hA! hA!  hA! h8AnPޤ¼B[yTX>zA?TէL VgX^|h}ݎd9B{X%^.2`$O>{Cdo~5|q LfK 'yA]w7T4[OC7H dY:D> !-B|A48C Yg^|A0o> )Wp Mh>0O:"q2H5{3`!FK  U.8[oӷid{n8A}!>.Hl} @6YxOބ|cJ|&mUa|@Iq8Z$>NpH{Ϡ%Z{ۚpEb6HQnSO m@{U.hvݟO  >^ 8fF(,ʐ;Aʗn3%I4`cR2H[4$IP1;{# )4"Yb~g2H>Rh=pKPt5~y.b "5$"lo'iZ. }-V~E.|.Qr) {<[8cF9\$+`e2Hz4 LGYg~zMoiHP9ṛgm/-"TF4o !PySdƇdU SXb(7hbI[zYUFS4A@`XY$EӣHn0&h}-}:ĺ,1o-kA1ek6Ȼj&0`;,2:"[_" jEz9So?O}Q >ǯ0[ڣkROӮlF(w:lbxr5`GB<-r#Hv]n<־:6z)2Lgp0Śo鏴-x;"!ڕ9viʰd1+b-&N-8˞[Z`v㭍/Du|k%)2X#dQBmՂ{O^{ZD՘cx}; ,-rՙC>A'aV4k;.ZkZssWiGv1 )r{Cp)o yg {6.j~LA A B4A A B4A A A B4A A 2s8Qa^/y+IEW 2溉ȧz6R=ǫ0\WW  3L2^Ol`U'±`}+X?PGC=dA̧O!A4A.ҭH7l_)a|>MJmulB'|^(:gb|~\(]km|3HU9Q l?9LiʑE`J hG>_T[-WdG>_T3D4pH|<([UoG> l7G>t*/JvH Uȷŧ1HIi83D#^ RR R (_4M||KTʵVD2N77HU(!g,l#_ 2{j-4ƀBm_ׇΟol}^ 4]C4  +X:}{[߇A:?4nCZce!!ՇΟ, "he,Ϙ@A^1u ?Tߞw4H#!zרfހ0> `& I Y/0}V$aL}{핵SԮ!íZsE|D:c]AW Nt]X7a$)eV}0{`u|ml}ybKvp|{ 5]`]|J|C,Fw,"3ȼڀXXC~ W]ؕϵ ?7Zj={/*XnZBօk竭)l׽X`>|8>|"S8]Hiޭmoy= [dqI2d=< 2 §+o__Z_~kO8%~lW+l>&NcC gf  .uȟ+ߧϭ_< rZ{8uno4|?Cw&cAjg8Q |n%+͟GϹ_\ bɠkA\-q7 ]1 ,uχ/,0AT (F?K7SF1W Uĕ=\y>OAkX <C;tԗϫ_>Aj7 hA! hA! h hA! hA`ߡzf0ӗ<^"ī]rs S_wEU@+'Edـ8^f*YyA_s,z⻂T|ip \<" .7>v(0>*^h j@[P"0u>$:ZP&0u>$>[P*0u>$i  L k  : "k  : "ko4k L5id݂GHD·J&pނSA|FLa@4[p|4IziL2ȳQGL3ȣqGVt[@- 8u>D"# C bNQI:f/&|mnеZ`  `0} րK ~'ȟzi~' O_(_>ևl!^`ܷX2!3'gn4!+^\} SKnBeyI⒮k/-p1:@|y4 %/_V7 %k5]`.|>%u!-lv{ .FK,0`W>W &}5Lc8&:{֐۵}\,2u~Ղ_K}Q!~E_3 Ê.*u%|6!j06 S-"/zK7_O`W%uOޓ,2 _>4KF$ ˖S8Og)Nͷ_xì\}  >bz~м LPv|VbZ_AcSw|-b]F̷AK28^Njdi~vn)NחYu# 25Xe|{DZ_dT <-b]FķAAVX? lWHv44Ȫg*ۡGdHeׯaj=ԗY߮i>)x5|_߯3A4A A B4A A B4A4A A B4A Aħd|#q¼>OS*m*AF\x/UqA]QJ%WkPK+|'\<>BFR,} Hy3}W>pPԧ`>0| χM h]۱=?DЇึR;0rih{ p}÷]ͧւ7\j]AkC[05}m|S mj4 ׄ~jEOC[0}{9ȗ6kh] cFϧKO6k dF5~ _|ʿ-߀uD هϷKOIVe JnhA9_ͧd[y J/ĺ3n|r/m>%fx` 1 O7DL|;_T?Z0&A]9DZ/u>r4 -ܩHj _|*XvhAXCoc…|i>Hk, +Sᄆw6+%_iWkN U/h}) Ң WU/n.!}? _ 2nCZc ׇ V:Jk0$kXFg'(I;^1Y K p;Ġϳ$3o0> җCO I|Jl?>_=`6K CcNŦSd~Uk. \[c%nz6k|uf>,Ϫf?7-G޲=˫풬OW]υϧ C,{5ȼ&}bXW]ϕ"a|";mjѡiVXdC$:{jku/χ"BjEv7:^}M.TTc6i9$|[W{ZdNjt^ 5 >D+~z[k:+>E[KkB0Gyn9$q2˃]ha?BgH`}|/Kwetcc"}l=<-K>:mUeAD{!NjM{ԱK}k98=n.Sh]B bȡ>A`c bdx h=o]Q RCdB۸ 0Y 7va(e|53@jK=a r_ AWwXAT] 1+;AZE;\]im!b,o[8^tl  hA! hA!  hA! hAS r'ky;ɇy+> HbJ/B `G3zE!T|wEN?ǫ [ ? 4lUSx1Y+^҇$, /glPԧlSrO!ˇ A !H5|>06@4:G}qC' mC' nnsC' tn|RyćE @>m DH}a_-h>t/i}ͻ OgCַk[DBgCRշͶU ]`KS`tM,͇.0 " D L}$戯f:@4ԗ>7vF*͇.0' _[[ SIShEЧѧo(_>wPHSN2t#b0H>>sC7$cPV37 Oh GI8}a`|2} K >)|Q|m5 Oϥ|0kv4`-kw' fBg5/Uԍ_ 5!| ׹5 WGC4m)pN]jۺV>u C,oq/k;o\jO}Ӧ# |^[W?7Zj} Kq+7N#/{:-XDo ~I %ַvFVW[)-/c:_}h"R}ss7YKlC5Nʧ'ZV C4AipQ]-"o1NZhgIA|[d|^$fސ7EKl[V7a+I ?]- J abN!p-K3L%qbZd]b{fS ' =A%u;ABR "! 2/Dw /C"2 "A ,qQE|42AķA=A%X uS6 ߎQ~I c% 'Z?䞿tΟ'ߞJ{h o}fg|G6- ?5 >4A A B4A A B4A A A B4A A r{j| ؓ:Z<}]H/B `sO}kz\WOi1HTKR$4^Z+6`>ff6 8>A 1wO@StO` `<}_@xE4A\|wkSn*}Ah؃Ac-᫪/6=4!A ~|A ۗOgd_4i\%^>_{ d뻹p[>{ dOpU]>=h̑rUAs xC_O6= RI̱{G'  RopBA VQA_=h]N Xhd#_AJC{C7_& MF ĩNk`!/O7A&"IKBOi zR_>e2HEPب?[g,0<^A}۶2YNY "&GWT=|7x=k_T_gHo0 ~I`؎35A0O}m􋵾~ԶAd x&k|!+W&IDATk֮]ԣ57/}MEB^5'!,ꁎש[t}c3wQXX$,vFRCok9Ħoy .|>٪Nz-HH*XZ;^Pӷ٠O^W{]_W>WlwI-E\k{"[AyHnyn9$q2˃]hdn= m>|.ۥC-Z.Ї&˖3޿mq@'}u ۪2@䵧C՚xG뗰 /)./!1QT%Q%4K 7'6HEkW}i_A^Rh1R:C׫Q1EZ_%[*)g> / /)U>ۧCO "/ ­k`w~/ ʧ67ԇ/t/=\ݘA! hA! hAA! hA!"'ux|JbJ/B `s2⹾dH廢^wUJBkS%a#Q] } ̟bOl`"аKﶶ(0,O}W>pPԧ`/]Ǻ-A !HG# # B> # B> # B> # ‚aG0# B> # B> # B> # B׾N`zSISEq6`ӄIm}mUAJF }%l+}Io] 䋡On>S}5:cH (܀26 \H}"ݓ!$P.q4VE'N_go7;m5T^wQ|m7֮ơe3G. Xa3_}'!}&Lbl[KXA"soQMyK_u7|Rn>_-w[W睿εNzmlm\K%qյį՞ϕ+nh>jby4t-ϣ.%ֵ>(_o1obyDyO_еĽ*Z_mշZN?~It+:meȟSAj=f+j06I'闤O4K )=4N|pK48R %3< y*o\ /n,|o6VN[ScxCc/i)d}?y}J HY(\ dYb{;5_!Biz&"xcykGqDIvq,FE<. E|?~I6>.S_`G7,S ϫ_O5cV <Xq_wyK?My*Q |ϟwĮS@4A A B4A A B4A4A A B4A q0~@za^ȧ?|W,RiEW hf4yBt4"IդK%WA{?P'> 4ć̟/NjL,]r$H5KZ.8}>OE_|)_DSH>{&A4A.c~A W BJU4g× JvDN0='g'g'g'g'g'g'wG! Ӄ|ڃ|km&!w=A?4ėK;]R*lxC a8AR6Htk*izh끎9AB嵾-VH 7HEplq7Wi 4x-]} -AK mաQ Ҡ5o~y.n} ҼY#}a`= ˁTj~1wv%m N}i^_Ge7HP߿=\1o-k .}h ՖAt 0ufP}uMjuzX^ՍBlvTX$L_̞#W_^k9ĦOS*nlw}'h\iE ׮Wc e0} {]GMZpθ疣XD]nxku-*j>E6[jj5{"R}&y{[otོZk}kC/VWbmH;.ZkmVo-rȦeUqŵyu[k߱ЩtD_5o;m֍8m<8_~qqJǞ1 ҾX[>걼tCES_ SxI\siaX[{:I_~b7 AğKXGH=>{-kN .ZiE6!GȡDW}QNrU/ ?Dog}uڨ ϡD=3Hޓj}DMiwC,-Q=0ATjRi]TrHo e, l4Ⱥc:58^~A B4A A B4A AA B4A A B4A|AndOćy+> w)6_x KDMT ɧz4R=ǫ0\@iqHTeW 2+2^Ol`c" x+OAX}>y rq `<}_p{c]S h] |wM? y~FI|p|J(B+l8@p|o$0| x&=D^WmVϛ xak&HJ)wJ&սa|ǚ xA%mzLsI\7A`B7WLw{LSI9A@L{M}Iw@ ߪ?A8At% ܖw 70/ k Z@7y|ǟ OS LuI} 7 z|2A%1 t=wv 8z|?D/߽vϚ  gLJNNgIte|7AgGN=QWryzϜ x'H=d,Z`W>`W@xQU_X'H+̗/xW? + v'HK` 4 CM#/q[UrdR_w{;P_`iVK?:W$KJ<2GȟxP ] N k  d_GYR7HE '' Bpp  B 4 B 4 Bpp '' rG!c?Bگ>ϟ  4rUm?=4 X "` 8AJ H,27AڪS4H7t%3E@M=hteh?A|,f|A1omJnW큘 =EX C䵥'HYdi _g3_6DiZZ,Vnvgn|oQ 2wk+sIoL468D-4omHFӼ#_GMQ~6X՘#dY,"A!/iO2!y qO,! fO;D.o=!DQ8]w|ܝ 3.Aڪ2nh"ACywlN`C f+>A۬C㢟 0#5E5 ۬ 5. // -1 * 0 0C "Font characters by PaulC, Bilbo and Jasper Vries" // Replace original characters -1 * 5 0A 01 02 41 00 -1 sprites/chars.png 8bpp 10 10 6 12 0 -1 normal -1 sprites/chars.png 8bpp 20 10 4 12 0 -1 normal -1 * 5 0A 01 02 86 00 -1 sprites/chars.png 8bpp 50 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 70 10 9 12 0 -1 normal -1 * 5 0A 01 01 8A 00 -1 sprites/chars.png 8bpp 120 10 6 12 0 -1 normal -1 * 5 0A 01 01 A0 00 -1 sprites/chars.png 8bpp 230 10 10 12 0 -1 normal -1 * 5 0A 01 04 A2 00 -1 sprites/chars.png 8bpp 260 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 290 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 320 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 350 10 8 12 0 -1 normal -1 * 5 0A 01 06 A7 00 -1 sprites/chars.png 8bpp 410 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 440 10 12 12 0 -1 normal -1 sprites/chars.png 8bpp 470 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 480 10 7 12 0 -1 normal -1 sprites/chars.png 8bpp 500 10 7 12 0 -1 normal -1 sprites/chars.png 8bpp 520 10 7 12 0 -1 normal -1 * 5 0A 01 03 AE 00 -1 sprites/chars.png 8bpp 560 10 4 12 0 -1 normal -1 sprites/chars.png 8bpp 570 10 4 12 0 -1 normal -1 sprites/chars.png 8bpp 580 10 5 12 0 -1 normal -1 * 5 0A 01 05 B3 00 -1 sprites/chars.png 8bpp 620 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 640 10 9 12 0 -1 normal -1 sprites/chars.png 8bpp 660 10 9 12 0 -1 normal -1 sprites/chars.png 8bpp 680 10 9 12 0 -1 normal -1 sprites/chars.png 8bpp 700 10 9 12 0 -1 normal -1 * 5 0A 01 03 BB 00 -1 sprites/chars.png 8bpp 770 10 8 12 0 -1 normal -1 sprites/chars.png 8bpp 10 70 8 12 0 -1 normal -1 sprites/chars.png 8bpp 30 70 8 12 0 -1 normal -1 * 5 0A 01 01 BF 00 -1 sprites/chars.png 8bpp 70 70 9 12 0 -1 normal -1 * 5 0A 01 05 C1 00 -1 sprites/chars.png 8bpp 450 70 8 12 0 -1 normal -1 sprites/chars.png 8bpp 110 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 120 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 130 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 140 70 6 12 0 -1 normal -1 * 5 0A 01 01 C7 00 -1 sprites/chars.png 8bpp 160 70 6 12 0 -1 normal -1 * 5 0A 01 03 CA 00 -1 sprites/chars.png 8bpp 200 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 210 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 220 70 6 12 0 -1 normal -1 * 5 0A 01 04 CE 00 -1 sprites/chars.png 8bpp 230 70 4 12 0 -1 normal -1 sprites/chars.png 8bpp 240 70 4 12 0 -1 normal -1 sprites/chars.png 8bpp 250 70 5 12 0 -1 normal -1 sprites/chars.png 8bpp 260 70 5 12 0 -1 normal -1 * 5 0A 01 05 D3 00 -1 sprites/chars.png 8bpp 290 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 310 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 320 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 330 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 340 70 6 12 0 -1 normal -1 * 5 0A 01 03 DB 00 -1 sprites/chars.png 8bpp 390 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 400 70 6 12 0 -1 normal -1 sprites/chars.png 8bpp 410 70 6 12 0 -1 normal -1 * 5 0A 01 02 DF 00 -1 sprites/chars.png 8bpp 420 70 7 12 0 -1 normal -1 sprites/chars.png 8bpp 430 70 6 12 0 -1 normal -1 * 5 0A 01 01 22 01 -1 sprites/chars.png 8bpp 20 30 2 7 0 0 normal -1 * 5 0A 01 01 7D 01 -1 sprites/chars.png 8bpp 220 30 4 7 0 0 normal -1 * 5 0A 01 02 80 01 -1 sprites/chars.png 8bpp 230 30 9 7 0 0 normal -1 sprites/chars.png 8bpp 250 30 3 7 0 0 normal -1 * 5 0A 01 01 89 01 -1 sprites/chars.png 8bpp 470 30 3 7 0 0 normal -1 * 5 0A 01 01 9F 01 -1 sprites/chars.png 8bpp 70 90 3 7 0 0 normal -1 * 5 0A 01 01 A9 01 -1 sprites/chars.png 8bpp 190 90 3 7 0 0 normal -1 * 5 0A 01 02 BF 01 -1 sprites/chars.png 8bpp 420 90 3 7 0 0 normal -1 sprites/chars.png 8bpp 430 90 3 7 0 0 normal -1 * 5 0A 01 01 02 02 -1 sprites/chars.png 8bpp 20 40 4 21 0 -2 normal -1 * 5 0A 01 01 41 02 -1 sprites/chars.png 8bpp 30 40 14 21 0 -2 normal -1 * 5 0A 01 06 46 02 -1 sprites/chars.png 8bpp 50 40 10 21 0 -2 normal -1 sprites/chars.png 8bpp 70 40 14 21 0 -2 normal -1 sprites/chars.png 8bpp 90 40 3 21 0 -2 normal -1 sprites/chars.png 8bpp 100 40 13 21 0 -2 normal -1 sprites/chars.png 8bpp 120 40 7 21 0 -2 normal -1 sprites/chars.png 8bpp 130 40 16 21 0 -2 normal -1 * 5 0A 01 01 50 02 -1 sprites/chars.png 8bpp 150 40 16 21 0 -2 normal -1 * 5 0A 01 04 52 02 -1 sprites/chars.png 8bpp 170 40 8 21 0 -2 normal -1 sprites/chars.png 8bpp 180 40 9 21 0 -2 normal -1 sprites/chars.png 8bpp 190 40 6 21 0 -2 normal -1 sprites/chars.png 8bpp 200 40 6 21 0 -2 normal -1 * 5 0A 01 01 5C 02 -1 sprites/chars.png 8bpp 210 40 7 21 0 -2 normal -1 * 5 0A 01 01 60 02 -1 sprites/chars.png 8bpp 230 40 16 21 0 -2 normal -1 * 5 0A 01 07 62 02 -1 sprites/chars.png 8bpp 260 40 20 21 0 -2 normal -1 sprites/chars.png 8bpp 290 40 20 21 0 -2 normal -1 sprites/chars.png 8bpp 320 40 20 21 0 -2 normal -1 sprites/chars.png 8bpp 350 40 20 21 0 -2 normal -1 sprites/chars.png 8bpp 380 40 20 21 0 -2 normal -1 sprites/chars.png 8bpp 410 40 20 21 0 -2 normal -1 sprites/chars.png 8bpp 440 40 24 21 0 -2 normal -1 * 5 0A 01 18 6A 02 -1 sprites/chars.png 8bpp 480 40 14 21 0 -2 normal -1 sprites/chars.png 8bpp 500 40 14 21 0 -2 normal -1 sprites/chars.png 8bpp 520 40 14 21 0 -2 normal -1 sprites/chars.png 8bpp 540 40 14 21 0 -2 normal -1 sprites/chars.png 8bpp 560 40 9 21 0 -2 normal -1 sprites/chars.png 8bpp 570 40 9 21 0 -2 normal -1 sprites/chars.png 8bpp 580 40 9 21 0 -2 normal -1 sprites/chars.png 8bpp 590 40 9 21 0 -2 normal -1 sprites/chars.png 8bpp 600 40 17 21 0 -2 normal -1 sprites/chars.png 8bpp 620 40 18 21 0 -2 normal -1 sprites/chars.png 8bpp 640 40 15 21 0 -2 normal -1 sprites/chars.png 8bpp 660 40 15 21 0 -2 normal -1 sprites/chars.png 8bpp 680 40 15 21 0 -2 normal -1 sprites/chars.png 8bpp 700 40 15 21 0 -2 normal -1 sprites/chars.png 8bpp 720 40 15 21 0 -2 normal -1 sprites/chars.png 8bpp 740 40 9 21 0 -2 normal -1 sprites/chars.png 8bpp 750 40 16 21 0 -2 normal -1 sprites/chars.png 8bpp 770 40 17 21 0 -2 normal -1 sprites/chars.png 8bpp 10 100 17 21 0 -2 normal -1 sprites/chars.png 8bpp 30 100 17 21 0 -2 normal -1 sprites/chars.png 8bpp 50 100 17 21 0 -2 normal -1 sprites/chars.png 8bpp 70 100 14 21 0 -2 normal -1 sprites/chars.png 8bpp 90 100 14 21 0 -2 normal -1 sprites/chars.png 8bpp 450 100 14 21 0 -2 normal -1 * 5 0A 01 01 85 02 -1 sprites/chars.png 8bpp 140 100 12 21 0 -2 normal -1 * 5 0A 01 01 88 02 -1 sprites/chars.png 8bpp 170 100 19 21 0 -2 normal -1 * 5 0A 01 02 92 02 -1 sprites/chars.png 8bpp 270 100 11 21 0 -2 normal -1 sprites/chars.png 8bpp 290 100 15 21 0 -2 normal -1 * 5 0A 01 01 97 02 -1 sprites/chars.png 8bpp 340 100 11 21 0 -2 normal -1 * 5 0A 01 02 99 02 -1 sprites/chars.png 8bpp 360 100 9 21 0 -2 normal -1 sprites/chars.png 8bpp 370 100 11 21 0 -2 normal -1 * 5 0A 01 01 A0 02 -1 sprites/chars.png 8bpp 430 100 14 21 0 -2 normal // New characters, all fonts except monospaced // U+007B: Left Curly Bracket // U+007C: Vertical Line // U+007D: Right Curly Bracket // U+007E: Tilde -1 * 14 12 03 00 04 7B 00 01 04 7B 00 02 04 7B 00 -1 sprites/chars.png 8bpp 10 130 5 12 0 -1 normal -1 sprites/chars.png 8bpp 20 130 3 12 0 -1 normal -1 sprites/chars.png 8bpp 30 130 5 12 0 -1 normal -1 sprites/chars.png 8bpp 50 130 7 12 0 -1 normal -1 sprites/chars.png 8bpp 10 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 20 150 1 7 0 0 normal -1 sprites/chars.png 8bpp 30 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 50 150 4 7 0 0 normal -1 sprites/chars.png 8bpp 10 160 9 21 0 -2 normal -1 sprites/chars.png 8bpp 20 160 3 21 0 -2 normal -1 sprites/chars.png 8bpp 30 160 9 21 0 -2 normal -1 sprites/chars.png 8bpp 50 160 10 21 0 -2 normal // U+007F: No-Break Space -1 * 14 12 03 00 01 7F 00 01 01 7F 00 02 01 7F 00 -1 sprites/chars.png 8bpp 70 130 2 12 0 -1 normal -1 sprites/chars.png 8bpp 70 150 1 7 0 0 normal -1 sprites/chars.png 8bpp 70 160 5 21 0 -2 normal // U+00AA: Feminine Ordinal Indicator -1 * 14 12 03 00 01 AA 00 01 01 AA 00 02 01 AA 00 -1 sprites/chars.png 8bpp 80 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 80 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 80 160 7 21 0 -2 normal // U+00AC: Not Sign // U+00AD: Soft Hyphen -1 * 14 12 03 00 02 AC 00 01 02 AC 00 02 02 AC 00 -1 sprites/chars.png 8bpp 90 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 110 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 90 150 4 7 0 0 normal -1 sprites/chars.png 8bpp 110 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 90 160 12 21 0 -2 normal -1 sprites/chars.png 8bpp 110 160 9 21 0 -2 normal // U+00AF: Macron -1 * 14 12 03 00 01 AF 00 01 01 AF 00 02 01 AF 00 -1 sprites/chars.png 8bpp 130 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 130 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 130 160 12 21 0 -2 normal // U+00B4: Acute Accent // U+00B5: Micro Sign // U+00B6: Pilcrow Sign // U+00B7: Middle Dot // U+00B8: Cedilla // U+00B9: Superscript One -1 * 14 12 03 00 06 B4 00 01 06 B4 00 02 06 B4 00 -1 sprites/chars.png 8bpp 150 130 4 12 0 -1 normal -1 sprites/chars.png 8bpp 160 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 180 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 200 130 3 12 0 -1 normal -1 sprites/chars.png 8bpp 210 130 4 12 0 -1 normal -1 sprites/chars.png 8bpp 220 130 5 12 0 -1 normal -1 sprites/chars.png 8bpp 150 150 2 7 0 0 normal -1 sprites/chars.png 8bpp 160 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 180 150 6 7 0 0 normal -1 sprites/chars.png 8bpp 200 150 1 7 0 0 normal -1 sprites/chars.png 8bpp 210 150 2 7 0 0 normal -1 sprites/chars.png 8bpp 220 150 2 7 0 0 normal -1 sprites/chars.png 8bpp 150 160 4 21 0 -2 normal -1 sprites/chars.png 8bpp 160 160 15 21 0 -2 normal -1 sprites/chars.png 8bpp 180 160 13 21 0 -2 normal -1 sprites/chars.png 8bpp 200 160 3 21 0 -2 normal -1 sprites/chars.png 8bpp 210 160 5 21 0 -2 normal -1 sprites/chars.png 8bpp 220 160 6 21 0 -2 normal // U+00BC: Vulgar Fraction One Quarter // U+00BD: Vulgar Fraction One Half -1 * 14 12 03 00 02 BC 00 01 02 BC 00 02 02 BC 00 -1 sprites/chars.png 8bpp 230 130 10 12 0 -1 normal -1 sprites/chars.png 8bpp 250 130 10 12 0 -1 normal -1 sprites/chars.png 8bpp 230 150 9 7 0 0 normal -1 sprites/chars.png 8bpp 250 150 9 7 0 0 normal -1 sprites/chars.png 8bpp 230 160 16 21 0 -2 normal -1 sprites/chars.png 8bpp 250 160 16 21 0 -2 normal // New characters, all fonts // U+0100 ... U+017F: Latin Extended-A -1 * 34 12 08 00 78 00 01 00 07 79 01 01 78 00 01 01 07 79 01 02 78 00 01 02 07 79 01 03 78 00 01 03 07 79 01 -1 sprites/chars.png 8bpp 270 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 300 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 320 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 350 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 370 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 400 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 420 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 440 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 460 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 480 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 500 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 520 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 540 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 560 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 580 130 8 12 0 -1 normal -1 sprites/chars.png 8bpp 600 130 9 12 0 -1 normal -1 sprites/chars.png 8bpp 620 130 9 12 0 -1 normal -1 sprites/chars.png 8bpp 640 130 7 12 0 -1 normal -1 sprites/chars.png 8bpp 660 130 7 12 0 -1 normal -1 sprites/chars.png 8bpp 680 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 700 130 7 12 0 -1 normal -1 sprites/chars.png 8bpp 720 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 740 130 7 12 0 -1 normal -1 sprites/chars.png 8bpp 760 130 6 12 0 -1 normal -1 sprites/chars.png 8bpp 10 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 30 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 50 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 70 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 90 190 8 12 0 -1 normal -1 sprites/chars.png 8bpp 110 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 130 190 8 12 0 -1 normal -1 sprites/chars.png 8bpp 150 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 170 190 8 12 0 -1 normal -1 sprites/chars.png 8bpp 190 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 210 190 8 12 0 -1 normal -1 sprites/chars.png 8bpp 230 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 250 190 8 12 0 -1 normal -1 sprites/chars.png 8bpp 270 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 290 190 10 12 0 -1 normal -1 sprites/chars.png 8bpp 310 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 330 190 5 12 0 -1 normal -1 sprites/chars.png 8bpp 340 190 5 12 0 -1 normal -1 sprites/chars.png 8bpp 350 190 5 12 0 -1 normal -1 sprites/chars.png 8bpp 360 190 5 12 0 -1 normal -1 sprites/chars.png 8bpp 370 190 5 12 0 -1 normal -1 sprites/chars.png 8bpp 380 190 5 12 0 -1 normal -1 sprites/chars.png 8bpp 390 190 3 12 0 -1 normal -1 sprites/chars.png 8bpp 400 190 3 12 0 -1 normal -1 sprites/chars.png 8bpp 410 190 3 12 0 -1 normal -1 sprites/chars.png 8bpp 420 190 3 12 0 -1 normal -1 sprites/chars.png 8bpp 430 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 460 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 480 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 500 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 520 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 540 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 560 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 580 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 600 190 4 12 0 -1 normal -1 sprites/chars.png 8bpp 610 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 630 190 3 12 0 -1 normal -1 sprites/chars.png 8bpp 640 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 660 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 670 190 7 12 0 -1 normal -1 sprites/chars.png 8bpp 690 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 710 190 8 12 0 -1 normal -1 sprites/chars.png 8bpp 730 190 5 12 0 -1 normal -1 sprites/chars.png 8bpp 740 190 8 12 0 -1 normal -1 sprites/chars.png 8bpp 760 190 6 12 0 -1 normal -1 sprites/chars.png 8bpp 10 250 8 12 0 -1 normal -1 sprites/chars.png 8bpp 30 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 50 250 8 12 0 -1 normal -1 sprites/chars.png 8bpp 70 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 90 250 9 12 0 -1 normal -1 sprites/chars.png 8bpp 110 250 8 12 0 -1 normal -1 sprites/chars.png 8bpp 130 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 150 250 9 12 0 -1 normal -1 sprites/chars.png 8bpp 170 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 190 250 9 12 0 -1 normal -1 sprites/chars.png 8bpp 210 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 230 250 9 12 0 -1 normal -1 sprites/chars.png 8bpp 250 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 270 250 13 12 0 -1 normal -1 sprites/chars.png 8bpp 300 250 9 12 0 -1 normal -1 sprites/chars.png 8bpp 320 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 340 250 5 12 0 -1 normal -1 sprites/chars.png 8bpp 360 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 380 250 5 12 0 -1 normal -1 sprites/chars.png 8bpp 400 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 420 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 440 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 460 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 480 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 500 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 520 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 540 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 560 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 580 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 600 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 620 250 5 12 0 -1 normal -1 sprites/chars.png 8bpp 630 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 650 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 670 250 7 12 0 -1 normal -1 sprites/chars.png 8bpp 690 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 700 250 8 12 0 -1 normal -1 sprites/chars.png 8bpp 720 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 740 250 8 12 0 -1 normal -1 sprites/chars.png 8bpp 760 250 6 12 0 -1 normal -1 sprites/chars.png 8bpp 10 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 30 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 50 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 70 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 90 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 110 310 7 12 0 -1 normal -1 sprites/chars.png 8bpp 130 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 150 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 170 310 12 12 0 -1 normal -1 sprites/chars.png 8bpp 200 310 10 12 0 -1 normal -1 sprites/chars.png 8bpp 230 310 9 12 0 -1 normal -1 sprites/chars.png 8bpp 250 310 7 12 0 -1 normal -1 sprites/chars.png 8bpp 270 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 290 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 310 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 330 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 350 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 370 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 390 310 5 12 0 -1 normal -1 sprites/chars.png 8bpp 270 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 300 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 320 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 350 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 370 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 400 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 420 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 440 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 460 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 480 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 500 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 520 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 540 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 560 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 580 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 600 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 620 150 5 7 0 0 normal -1 sprites/chars.png 8bpp 640 150 5 7 0 0 normal -1 sprites/chars.png 8bpp 660 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 680 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 700 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 720 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 740 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 760 150 3 7 0 0 normal -1 sprites/chars.png 8bpp 10 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 30 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 50 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 70 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 90 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 110 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 130 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 150 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 170 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 190 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 210 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 230 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 250 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 270 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 290 210 5 7 0 0 normal -1 sprites/chars.png 8bpp 310 210 5 7 0 0 normal -1 sprites/chars.png 8bpp 330 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 340 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 350 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 360 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 370 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 380 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 390 210 2 7 0 0 normal -1 sprites/chars.png 8bpp 400 210 2 7 0 0 normal -1 sprites/chars.png 8bpp 410 210 1 7 0 0 normal -1 sprites/chars.png 8bpp 420 210 1 7 0 0 normal -1 sprites/chars.png 8bpp 430 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 460 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 480 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 500 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 520 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 540 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 560 210 5 7 0 0 normal -1 sprites/chars.png 8bpp 580 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 600 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 610 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 630 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 640 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 660 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 670 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 690 210 3 7 0 0 normal -1 sprites/chars.png 8bpp 710 210 4 7 0 0 normal -1 sprites/chars.png 8bpp 730 210 4 7 0 0 normal -1 sprites/chars.png 8bpp 740 210 4 7 0 0 normal -1 sprites/chars.png 8bpp 760 210 4 7 0 0 normal -1 sprites/chars.png 8bpp 10 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 30 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 50 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 70 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 90 270 6 7 0 0 normal -1 sprites/chars.png 8bpp 110 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 130 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 150 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 170 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 190 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 210 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 230 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 250 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 270 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 300 270 4 7 0 0 normal -1 sprites/chars.png 8bpp 320 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 340 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 360 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 380 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 400 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 420 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 440 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 460 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 480 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 500 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 520 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 540 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 560 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 580 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 600 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 620 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 630 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 650 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 670 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 690 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 700 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 720 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 740 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 760 270 3 7 0 0 normal -1 sprites/chars.png 8bpp 10 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 30 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 50 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 70 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 90 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 110 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 130 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 150 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 170 330 5 7 0 0 normal -1 sprites/chars.png 8bpp 200 330 5 7 0 0 normal -1 sprites/chars.png 8bpp 230 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 250 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 270 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 290 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 310 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 330 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 350 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 370 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 390 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 270 160 20 21 0 -2 normal -1 sprites/chars.png 8bpp 300 160 13 21 0 -2 normal -1 sprites/chars.png 8bpp 320 160 20 21 0 -2 normal -1 sprites/chars.png 8bpp 350 160 13 21 0 -2 normal -1 sprites/chars.png 8bpp 370 160 20 21 0 -2 normal -1 sprites/chars.png 8bpp 400 160 13 21 0 -2 normal -1 sprites/chars.png 8bpp 420 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 440 160 11 21 0 -2 normal -1 sprites/chars.png 8bpp 460 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 480 160 11 21 0 -2 normal -1 sprites/chars.png 8bpp 500 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 520 160 11 21 0 -2 normal -1 sprites/chars.png 8bpp 540 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 560 160 11 21 0 -2 normal -1 sprites/chars.png 8bpp 580 160 17 21 0 -2 normal -1 sprites/chars.png 8bpp 600 160 16 21 0 -2 normal -1 sprites/chars.png 8bpp 620 160 17 21 0 -2 normal -1 sprites/chars.png 8bpp 640 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 660 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 680 160 12 21 0 -2 normal -1 sprites/chars.png 8bpp 700 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 720 160 12 21 0 -2 normal -1 sprites/chars.png 8bpp 740 160 14 21 0 -2 normal -1 sprites/chars.png 8bpp 760 160 12 21 0 -2 normal -1 sprites/chars.png 8bpp 10 220 14 21 0 -2 normal -1 sprites/chars.png 8bpp 30 220 12 21 0 -2 normal -1 sprites/chars.png 8bpp 50 220 14 21 0 -2 normal -1 sprites/chars.png 8bpp 70 220 12 21 0 -2 normal -1 sprites/chars.png 8bpp 90 220 18 21 0 -2 normal -1 sprites/chars.png 8bpp 110 220 13 21 0 -2 normal -1 sprites/chars.png 8bpp 130 220 18 21 0 -2 normal -1 sprites/chars.png 8bpp 150 220 13 21 0 -2 normal -1 sprites/chars.png 8bpp 170 220 18 21 0 -2 normal -1 sprites/chars.png 8bpp 190 220 13 21 0 -2 normal -1 sprites/chars.png 8bpp 210 220 18 21 0 -2 normal -1 sprites/chars.png 8bpp 230 220 13 21 0 -2 normal -1 sprites/chars.png 8bpp 250 220 17 21 0 -2 normal -1 sprites/chars.png 8bpp 270 220 15 21 0 -2 normal -1 sprites/chars.png 8bpp 290 220 17 21 0 -2 normal -1 sprites/chars.png 8bpp 310 220 15 21 0 -2 normal -1 sprites/chars.png 8bpp 330 220 9 21 0 -2 normal -1 sprites/chars.png 8bpp 340 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 350 220 9 21 0 -2 normal -1 sprites/chars.png 8bpp 360 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 370 220 9 21 0 -2 normal -1 sprites/chars.png 8bpp 380 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 390 220 9 21 0 -2 normal -1 sprites/chars.png 8bpp 400 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 410 220 9 21 0 -2 normal -1 sprites/chars.png 8bpp 420 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 430 220 19 21 0 -2 normal -1 sprites/chars.png 8bpp 460 220 13 21 0 -2 normal -1 sprites/chars.png 8bpp 480 220 13 21 0 -2 normal -1 sprites/chars.png 8bpp 500 220 10 21 0 -2 normal -1 sprites/chars.png 8bpp 520 220 18 21 0 -2 normal -1 sprites/chars.png 8bpp 540 220 15 21 0 -2 normal -1 sprites/chars.png 8bpp 560 220 15 21 0 -2 normal -1 sprites/chars.png 8bpp 580 220 14 21 0 -2 normal -1 sprites/chars.png 8bpp 600 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 610 220 14 21 0 -2 normal -1 sprites/chars.png 8bpp 630 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 640 220 14 21 0 -2 normal -1 sprites/chars.png 8bpp 660 220 9 21 0 -2 normal -1 sprites/chars.png 8bpp 670 220 14 21 0 -2 normal -1 sprites/chars.png 8bpp 690 220 10 21 0 -2 normal -1 sprites/chars.png 8bpp 710 220 14 21 0 -2 normal -1 sprites/chars.png 8bpp 730 220 7 21 0 -2 normal -1 sprites/chars.png 8bpp 740 220 18 21 0 -2 normal -1 sprites/chars.png 8bpp 760 220 15 21 0 -2 normal -1 sprites/chars.png 8bpp 10 280 18 21 0 -2 normal -1 sprites/chars.png 8bpp 30 280 15 21 0 -2 normal -1 sprites/chars.png 8bpp 50 280 18 21 0 -2 normal -1 sprites/chars.png 8bpp 70 280 15 21 0 -2 normal -1 sprites/chars.png 8bpp 90 280 19 21 0 -2 normal -1 sprites/chars.png 8bpp 110 280 18 21 0 -2 normal -1 sprites/chars.png 8bpp 130 280 13 21 0 -2 normal -1 sprites/chars.png 8bpp 150 280 15 21 0 -2 normal -1 sprites/chars.png 8bpp 170 280 11 21 0 -2 normal -1 sprites/chars.png 8bpp 190 280 15 21 0 -2 normal -1 sprites/chars.png 8bpp 210 280 11 21 0 -2 normal -1 sprites/chars.png 8bpp 230 280 15 21 0 -2 normal -1 sprites/chars.png 8bpp 250 280 11 21 0 -2 normal -1 sprites/chars.png 8bpp 270 280 23 21 0 -2 normal -1 sprites/chars.png 8bpp 300 280 19 21 0 -2 normal -1 sprites/chars.png 8bpp 320 280 16 21 0 -2 normal -1 sprites/chars.png 8bpp 340 280 11 21 0 -2 normal -1 sprites/chars.png 8bpp 360 280 16 21 0 -2 normal -1 sprites/chars.png 8bpp 380 280 11 21 0 -2 normal -1 sprites/chars.png 8bpp 400 280 16 21 0 -2 normal -1 sprites/chars.png 8bpp 420 280 11 21 0 -2 normal -1 sprites/chars.png 8bpp 440 280 14 21 0 -2 normal -1 sprites/chars.png 8bpp 460 280 10 21 0 -2 normal -1 sprites/chars.png 8bpp 480 280 14 21 0 -2 normal -1 sprites/chars.png 8bpp 500 280 10 21 0 -2 normal -1 sprites/chars.png 8bpp 520 280 14 21 0 -2 normal -1 sprites/chars.png 8bpp 540 280 10 21 0 -2 normal -1 sprites/chars.png 8bpp 560 280 14 21 0 -2 normal -1 sprites/chars.png 8bpp 580 280 10 21 0 -2 normal -1 sprites/chars.png 8bpp 600 280 13 21 0 -2 normal -1 sprites/chars.png 8bpp 620 280 8 21 0 -2 normal -1 sprites/chars.png 8bpp 630 280 13 21 0 -2 normal -1 sprites/chars.png 8bpp 650 280 12 21 0 -2 normal -1 sprites/chars.png 8bpp 670 280 13 21 0 -2 normal -1 sprites/chars.png 8bpp 690 280 8 21 0 -2 normal -1 sprites/chars.png 8bpp 700 280 17 21 0 -2 normal -1 sprites/chars.png 8bpp 720 280 15 21 0 -2 normal -1 sprites/chars.png 8bpp 740 280 17 21 0 -2 normal -1 sprites/chars.png 8bpp 760 280 15 21 0 -2 normal -1 sprites/chars.png 8bpp 10 340 17 21 0 -2 normal -1 sprites/chars.png 8bpp 30 340 15 21 0 -2 normal -1 sprites/chars.png 8bpp 50 340 17 21 0 -2 normal -1 sprites/chars.png 8bpp 70 340 15 21 0 -2 normal -1 sprites/chars.png 8bpp 90 340 17 21 0 -2 normal -1 sprites/chars.png 8bpp 110 340 15 21 0 -2 normal -1 sprites/chars.png 8bpp 130 340 17 21 0 -2 normal -1 sprites/chars.png 8bpp 150 340 15 21 0 -2 normal -1 sprites/chars.png 8bpp 170 340 24 21 0 -2 normal -1 sprites/chars.png 8bpp 200 340 22 21 0 -2 normal -1 sprites/chars.png 8bpp 230 340 14 21 0 -2 normal -1 sprites/chars.png 8bpp 250 340 16 21 0 -2 normal -1 sprites/chars.png 8bpp 270 340 13 21 0 -2 normal -1 sprites/chars.png 8bpp 290 340 12 21 0 -2 normal -1 sprites/chars.png 8bpp 310 340 13 21 0 -2 normal -1 sprites/chars.png 8bpp 330 340 12 21 0 -2 normal -1 sprites/chars.png 8bpp 350 340 13 21 0 -2 normal -1 sprites/chars.png 8bpp 370 340 12 21 0 -2 normal -1 sprites/chars.png 8bpp 390 340 10 21 0 -2 normal -1 sprites/mono.png 8bpp 10 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 170 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 190 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 210 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 230 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 230 7 13 0 0 normal // U+018F: Latin Capital Letter Schwa -1 * 18 12 04 00 01 8F 01 01 01 8F 01 02 01 8F 01 03 01 8F 01 -1 sprites/chars.png 8bpp 410 310 9 12 0 -1 normal -1 sprites/chars.png 8bpp 410 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 410 340 16 21 0 -2 normal -1 sprites/mono.png 8bpp 10 250 7 13 0 0 normal // U+0192: Latin Small Letter F With Hook -1 * 18 12 04 00 01 92 01 01 01 92 01 02 01 92 01 03 01 92 01 -1 sprites/chars.png 8bpp 430 310 9 12 0 -1 normal -1 sprites/chars.png 8bpp 430 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 430 340 14 21 0 -2 normal -1 sprites/mono.png 8bpp 25 250 7 13 0 0 normal // U+01B5: Latin Capital Letter Z With Stroke // U+01B6: Latin Small Letter Z With Stroke -1 * 18 12 04 00 02 B5 01 01 02 B5 01 02 02 B5 01 03 02 B5 01 -1 sprites/chars.png 8bpp 450 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 470 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 450 330 4 7 0 0 normal -1 sprites/chars.png 8bpp 470 330 4 7 0 0 normal -1 sprites/chars.png 8bpp 450 340 14 21 0 -2 normal -1 sprites/chars.png 8bpp 470 340 12 21 0 -2 normal -1 sprites/mono.png 8bpp 40 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 250 7 13 0 0 normal // U+0218: Latin Capital Letter S With Comma Below // U+0219: Latin Small Letter S With Comma Below // U+021A: Latin Capital Letter T With Comma Below // U+021B: Latin Small Letter T With Comma Below -1 * 18 12 04 00 04 18 02 01 04 18 02 02 04 18 02 03 04 18 02 -1 sprites/chars.png 8bpp 490 310 7 12 0 -1 normal -1 sprites/chars.png 8bpp 510 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 530 310 7 12 0 -1 normal -1 sprites/chars.png 8bpp 550 310 5 12 0 -1 normal -1 sprites/chars.png 8bpp 490 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 510 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 530 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 550 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 490 340 14 21 0 -2 normal -1 sprites/chars.png 8bpp 510 340 10 21 0 -2 normal -1 sprites/chars.png 8bpp 530 340 13 21 0 -2 normal -1 sprites/chars.png 8bpp 550 340 8 21 0 -2 normal -1 sprites/mono.png 8bpp 70 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 250 7 13 0 0 normal // U+0259: Latin Small Letter Schwa -1 * 18 12 04 00 01 59 02 01 01 59 02 02 01 59 02 03 01 59 02 -1 sprites/chars.png 8bpp 560 310 6 12 0 -1 normal -1 sprites/chars.png 8bpp 560 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 560 340 12 21 0 -2 normal -1 sprites/mono.png 8bpp 130 250 7 13 0 0 normal // U+02BB: Modifier Letter Turned Comma -1 * 18 12 04 00 01 BB 02 01 01 BB 02 02 01 BB 02 03 01 BB 02 -1 sprites/chars.png 8bpp 580 310 3 12 0 -1 normal -1 sprites/chars.png 8bpp 580 330 1 7 0 0 normal -1 sprites/chars.png 8bpp 580 340 4 21 0 -2 normal -1 sprites/mono.png 8bpp 145 250 7 13 0 0 normal // U+02C7: Caron -1 * 18 12 04 00 01 C7 02 01 01 C7 02 02 01 C7 02 03 01 C7 02 -1 sprites/chars.png 8bpp 430 370 6 12 0 -1 normal -1 sprites/chars.png 8bpp 430 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 430 400 7 21 0 -2 normal -1 sprites/mono.png 8bpp 130 270 7 13 0 0 normal // U+058F: Armenian Dram Sign -1 * 18 12 04 00 01 8F 05 01 01 8F 05 02 01 8F 05 03 01 8F 05 -1 sprites/chars.png 8bpp 590 310 9 12 0 -1 normal -1 sprites/chars.png 8bpp 590 330 4 7 0 0 normal -1 sprites/chars.png 8bpp 590 340 18 21 0 -2 normal -1 sprites/mono.png 8bpp 160 250 7 13 0 0 normal // U+0E3F: Thai Currency Symbol Baht -1 * 18 12 04 00 01 3F 0E 01 01 3F 0E 02 01 3F 0E 03 01 3F 0E -1 sprites/chars.png 8bpp 610 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 610 330 5 7 0 0 normal -1 sprites/chars.png 8bpp 610 340 15 21 0 -2 normal -1 sprites/mono.png 8bpp 175 250 7 13 0 0 normal // U+2010: Hyphen -1 * 18 12 04 00 01 10 20 01 01 10 20 02 01 10 20 03 01 10 20 -1 sprites/chars.png 8bpp 480 370 4 12 0 -1 normal -1 sprites/chars.png 8bpp 480 390 2 7 0 0 normal -1 sprites/chars.png 8bpp 480 400 6 21 0 -2 normal -1 sprites/mono.png 8bpp 160 270 7 13 0 0 normal // U+2013: En Dash // U+2014: Em Dash // U+2015: Horizontal Bar -1 * 18 12 04 00 03 13 20 01 03 13 20 02 03 13 20 03 03 13 20 -1 sprites/chars.png 8bpp 630 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 450 370 12 12 0 -1 normal -1 sprites/chars.png 8bpp 490 370 10 12 0 -1 normal -1 sprites/chars.png 8bpp 630 330 4 7 0 0 normal -1 sprites/chars.png 8bpp 450 390 6 7 0 0 normal -1 sprites/chars.png 8bpp 490 390 5 7 0 0 normal -1 sprites/chars.png 8bpp 630 340 15 21 0 -2 normal -1 sprites/chars.png 8bpp 450 400 21 21 0 -2 normal -1 sprites/chars.png 8bpp 490 400 18 21 0 -2 normal -1 sprites/mono.png 8bpp 190 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 270 7 13 0 0 normal // U+2018: Left Single Quotation Mark // U+2019: Right Single Quotation Mark // U+201A: Single Low-9 Quotation Mark // U+201B: Single High-Reversed-9 Quotation Mark // U+201C: Left Double Quotation Mark // U+201D: Right Double Quotation Mark // U+201E: Double Low-9 Quotation Mark // U+201F: Double High-Reversed-9 Quotation Mark -1 * 18 12 04 00 08 18 20 01 08 18 20 02 08 18 20 03 08 18 20 -1 sprites/chars.png 8bpp 510 370 4 12 0 -1 normal -1 sprites/chars.png 8bpp 650 310 4 12 0 -1 normal -1 sprites/chars.png 8bpp 520 370 4 12 0 -1 normal -1 sprites/chars.png 8bpp 530 370 4 12 0 -1 normal -1 sprites/chars.png 8bpp 660 310 7 12 0 -1 normal -1 sprites/chars.png 8bpp 540 370 7 12 0 -1 normal -1 sprites/chars.png 8bpp 670 310 7 12 0 -1 normal -1 sprites/chars.png 8bpp 550 370 7 12 0 -1 normal -1 sprites/chars.png 8bpp 510 390 1 7 0 0 normal -1 sprites/chars.png 8bpp 650 330 1 7 0 0 normal -1 sprites/chars.png 8bpp 520 390 1 7 0 0 normal -1 sprites/chars.png 8bpp 530 390 1 7 0 0 normal -1 sprites/chars.png 8bpp 660 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 540 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 670 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 550 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 510 400 3 21 0 -2 normal -1 sprites/chars.png 8bpp 650 340 3 21 0 -2 normal -1 sprites/chars.png 8bpp 520 400 3 21 0 -2 normal -1 sprites/chars.png 8bpp 530 400 3 21 0 -2 normal -1 sprites/chars.png 8bpp 660 340 9 21 0 -2 normal -1 sprites/chars.png 8bpp 540 400 9 21 0 -2 normal -1 sprites/chars.png 8bpp 670 340 9 21 0 -2 normal -1 sprites/chars.png 8bpp 550 400 9 21 0 -2 normal -1 sprites/mono.png 8bpp 190 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 270 7 13 0 0 normal // U+2026: Horizontal Ellipsis -1 * 18 12 04 00 01 26 20 01 01 26 20 02 01 26 20 03 01 26 20 -1 sprites/chars.png 8bpp 560 370 11 12 0 -1 normal -1 sprites/chars.png 8bpp 560 390 5 7 0 0 normal -1 sprites/chars.png 8bpp 560 400 15 21 0 -2 normal -1 sprites/mono.png 8bpp 265 270 7 13 0 0 normal // U+2039: Single Left-Pointing Angle Quotation Mark // U+203A: Single Right-Pointing Angle Quotation Mark -1 * 18 12 04 00 02 39 20 01 02 39 20 02 02 39 20 03 02 39 20 -1 sprites/chars.png 8bpp 580 370 5 12 0 -1 normal -1 sprites/chars.png 8bpp 680 310 5 12 0 -1 normal -1 sprites/chars.png 8bpp 580 390 2 7 0 0 normal -1 sprites/chars.png 8bpp 680 330 2 7 0 0 normal -1 sprites/chars.png 8bpp 580 400 7 21 0 -2 normal -1 sprites/chars.png 8bpp 680 340 7 21 0 -2 normal -1 sprites/mono.png 8bpp 280 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 250 7 13 0 0 normal // U+20A1: Colon Sign // U+20A2: Cruzeiro Sign // U+20A3: French Franc Sign // U+20A4: Lira Sign -1 * 18 12 04 00 04 A1 20 01 04 A1 20 02 04 A1 20 03 04 A1 20 -1 sprites/chars.png 8bpp 690 310 9 12 0 -1 normal -1 sprites/chars.png 8bpp 710 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 730 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 750 310 8 12 0 -1 normal -1 sprites/chars.png 8bpp 690 330 4 7 0 0 normal -1 sprites/chars.png 8bpp 710 330 4 7 0 0 normal -1 sprites/chars.png 8bpp 730 330 4 7 0 0 normal -1 sprites/chars.png 8bpp 750 330 3 7 0 0 normal -1 sprites/chars.png 8bpp 690 340 14 21 0 -2 normal -1 sprites/chars.png 8bpp 710 340 16 21 0 -2 normal -1 sprites/chars.png 8bpp 730 340 13 21 0 -2 normal -1 sprites/chars.png 8bpp 750 340 11 21 0 -2 normal -1 sprites/mono.png 8bpp 265 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 250 7 13 0 0 normal // U+20A6: Naira Sign -1 * 18 12 04 00 01 A6 20 01 01 A6 20 02 01 A6 20 03 01 A6 20 -1 sprites/chars.png 8bpp 770 310 10 12 0 -1 normal -1 sprites/chars.png 8bpp 770 330 6 7 0 0 normal -1 sprites/chars.png 8bpp 770 340 18 21 0 -2 normal -1 sprites/mono.png 8bpp 325 250 7 13 0 0 normal // U+20A8: Rupee Sign // U+20A9: Won Sign // U+20AA: New Shequel Sign // U+20AB: Dong Sign // U+20AC: Euro Sign // U+20AD: Kip Sign // U+20AE: Tugrik Sign // U+20AF: Drachma Sign -1 * 18 12 04 00 08 A8 20 01 08 A8 20 02 08 A8 20 03 08 A8 20 -1 sprites/chars.png 8bpp 10 370 12 12 0 -1 normal -1 sprites/chars.png 8bpp 40 370 13 12 0 -1 normal -1 sprites/chars.png 8bpp 70 370 12 12 0 -1 normal -1 sprites/chars.png 8bpp 90 370 7 12 0 -1 normal -1 sprites/chars.png 8bpp 110 370 9 12 0 -1 normal -1 sprites/chars.png 8bpp 130 370 8 12 0 -1 normal -1 sprites/chars.png 8bpp 150 370 7 12 0 -1 normal -1 sprites/chars.png 8bpp 170 370 14 12 0 -1 normal -1 sprites/chars.png 8bpp 10 390 6 7 0 0 normal -1 sprites/chars.png 8bpp 40 390 7 7 0 0 normal -1 sprites/chars.png 8bpp 70 390 7 7 0 0 normal -1 sprites/chars.png 8bpp 90 390 4 7 0 0 normal -1 sprites/chars.png 8bpp 110 390 4 7 0 0 normal -1 sprites/chars.png 8bpp 130 390 4 7 0 0 normal -1 sprites/chars.png 8bpp 150 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 170 390 6 7 0 0 normal -1 sprites/chars.png 8bpp 10 400 22 21 0 -2 normal -1 sprites/chars.png 8bpp 40 400 24 21 0 -2 normal -1 sprites/chars.png 8bpp 70 400 17 21 0 -2 normal -1 sprites/chars.png 8bpp 90 400 13 21 0 -2 normal -1 sprites/chars.png 8bpp 110 400 14 21 0 -2 normal -1 sprites/chars.png 8bpp 130 400 18 21 0 -2 normal -1 sprites/chars.png 8bpp 150 400 13 21 0 -2 normal -1 sprites/chars.png 8bpp 170 400 28 21 0 -2 normal -1 sprites/mono.png 8bpp 340 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 250 7 13 0 0 normal // U+20B1: Peso Sign // U+20B2: Guarani Sign // U+20B3: Austral Sign // U+20B4: Hryvnia Sign // U+20B5: Cedi Sign -1 * 18 12 04 00 05 B1 20 01 05 B1 20 02 05 B1 20 03 05 B1 20 -1 sprites/chars.png 8bpp 200 370 9 12 0 -1 normal -1 sprites/chars.png 8bpp 220 370 9 12 0 -1 normal -1 sprites/chars.png 8bpp 240 370 10 12 0 -1 normal -1 sprites/chars.png 8bpp 270 370 9 12 0 -1 normal -1 sprites/chars.png 8bpp 290 370 9 12 0 -1 normal -1 sprites/chars.png 8bpp 200 390 5 7 0 0 normal -1 sprites/chars.png 8bpp 220 390 5 7 0 0 normal -1 sprites/chars.png 8bpp 240 390 5 7 0 0 normal -1 sprites/chars.png 8bpp 270 390 5 7 0 0 normal -1 sprites/chars.png 8bpp 290 390 4 7 0 0 normal -1 sprites/chars.png 8bpp 200 400 15 21 0 -2 normal -1 sprites/chars.png 8bpp 220 400 18 21 0 -2 normal -1 sprites/chars.png 8bpp 240 400 20 21 0 -2 normal -1 sprites/chars.png 8bpp 270 400 14 21 0 -2 normal -1 sprites/chars.png 8bpp 290 400 14 21 0 -2 normal -1 sprites/mono.png 8bpp 460 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 250 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 270 7 13 0 0 normal // U+20B7: Spesmilo Sign // U+20B8: Tenge Sign // U+20B9: Indian Rupee Sign -1 * 18 12 04 00 03 B7 20 01 03 B7 20 02 03 B7 20 03 03 B7 20 -1 sprites/chars.png 8bpp 310 370 10 12 0 -1 normal -1 sprites/chars.png 8bpp 330 370 7 12 0 -1 normal -1 sprites/chars.png 8bpp 350 370 8 12 0 -1 normal -1 sprites/chars.png 8bpp 310 390 6 7 0 0 normal -1 sprites/chars.png 8bpp 330 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 350 390 4 7 0 0 normal -1 sprites/chars.png 8bpp 310 400 17 21 0 -2 normal -1 sprites/chars.png 8bpp 330 400 13 21 0 -2 normal -1 sprites/chars.png 8bpp 350 400 14 21 0 -2 normal -1 sprites/mono.png 8bpp 55 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 270 7 13 0 0 normal // U+2116: Numero Sign // U+2117: Sound Recording Copyright -1 * 18 12 04 00 02 16 21 01 02 16 21 02 02 16 21 03 02 16 21 -1 sprites/chars.png 8bpp 370 370 14 12 0 -1 normal -1 sprites/chars.png 8bpp 590 370 13 12 0 -1 normal -1 sprites/chars.png 8bpp 370 390 8 7 0 0 normal -1 sprites/chars.png 8bpp 590 390 6 7 0 0 normal -1 sprites/chars.png 8bpp 370 400 27 21 0 -2 normal -1 sprites/chars.png 8bpp 590 400 16 21 0 -2 normal -1 sprites/mono.png 8bpp 100 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 270 7 13 0 0 normal // U+2122: Trade Mark Sign -1 * 18 12 04 00 01 22 21 01 01 22 21 02 01 22 21 03 01 22 21 -1 sprites/chars.png 8bpp 400 370 13 12 0 -1 normal -1 sprites/chars.png 8bpp 400 390 9 7 0 0 normal -1 sprites/chars.png 8bpp 400 400 20 21 0 -2 normal -1 sprites/mono.png 8bpp 115 270 7 13 0 0 normal // U+2212: Minus Sign -1 * 18 12 04 00 01 12 22 01 01 12 22 02 01 12 22 03 01 12 22 -1 sprites/chars.png 8bpp 610 370 6 12 0 -1 normal -1 sprites/chars.png 8bpp 610 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 610 400 9 21 0 -2 normal -1 sprites/mono.png 8bpp 310 270 7 13 0 0 normal // U+27E8: Mathematical Left Angle Bracket // U+27E9: Mathematical Right Angle Bracket -1 * 18 12 04 00 02 E8 27 01 02 E8 27 02 02 E8 27 03 02 E8 27 -1 sprites/chars.png 8bpp 620 370 5 12 0 -1 normal -1 sprites/chars.png 8bpp 630 370 5 12 0 -1 normal -1 sprites/chars.png 8bpp 620 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 630 390 3 7 0 0 normal -1 sprites/chars.png 8bpp 620 400 6 21 0 -2 normal -1 sprites/chars.png 8bpp 630 400 6 21 0 -2 normal -1 sprites/mono.png 8bpp 325 270 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 270 7 13 0 0 normal openttd-1.5.3/media/extra_grf/airports.png0000644000000000000000000001455012627373446017327 0ustar rootrootPNG  IHDR sRGBPLTE 000@@@PPPdddttt4O00ΓP8I8R8?`Ώcw5<Ϟz?i\vI(I_OYnYHWű >2^^B ,Xޟ"Q!/bC ^O(bxd? 38DJ"3>+g,Er?!I,#?(r?@e=U!$|l'@NB#}?dso뢀FdFDwu#\̹Xl(BREBUs%{jbڟErx~T<{,(v;!{K5C0@o$@pi548IDFƣJ `Qw6L=Ga緜O}V(Iѩ̅,S̲Sh DD5GQX-wPhT-rUtTBPCoy4_k~~P!̿| ҫg{XǾ|jHH`mH X&bxRC<BiT6ҍD[l_Z;$PqM[/_?zxgs /]W;qHH`>Y @MVBwx2 f(!1@VV~|>h\rtjAT+}E" "^! YB-أC)Dn-`Ko s^ч*̷nʴ˟Τ# d9|fHvOT[&C SoIBdzyy(<ϲ X-҇#jr%= &VzCj: ?UXH 8>kIiP^b `?nK"W hП2*fYoͲwR "e .!.e% ,)(J.0?gĄ3TߚgZH"o_ΚJίU\15a9e}k.8>==DaC"n}1o; VfU|`3?t4~fئյ&?><#%{~hŕE& BgYY˲YGM#Da=m'=:PzVҠË#ڱXnCiD*R|!$O(3:֞Zj؟'P$x+8? 8/Tb7|K!=,+lȲR6BDptNC {)n:r}QW~!b Y`+8n4 <\`JOWk#u2ɟ97#0EyLeP\u~ŕ۟ G7Ȳtde6=$GHSKiސc^lW*'cA^Cd*ޘNÃ1U UK[x~49?gS+]Tܩ,1J̲+˪L'2SC#E?Hhӥ„ifu>UZ}oJx /ӥ⫒F1ܱݒx4&9| W#%@,+\YV~,=y 8O񂮯1POxŽW*E1V ]%&9v|q9tYj??,+lEzrh1o:}~wW:CV+ zeE-3L~NϨƙ+C#ێ6o}4/ΕgcG.SVt򀘱R?]wx21}qz\vdY̲pV~Mȯ>[gJ}Ǜ>@ V ^M'a^ nb=}V|Q+J,Mճlgє.z9D6{3y&O,XH?}ݬ)wA!f G< p?.{6}w?JB@N|(8ƚ>,Ak}/qJoFT#VEuc?t߽.RބY &<Kkvk8+,cd!ӉO51=+a}iOIK6߽oMY6ջ6hc*@jQqGe6EX߱ڐl"@~s1NXd=4'CRYM1Vg RAg!{4<k "XDv̔upƨvOAi GUjc@ D~UZw E5&k'NIgB-kcqϊXG]-xB\_:cHw\*,~c<Ο>8w VLJubΕU}S\޻csrX}nXBmuc>@Mj(޳cs@ܚ"VmrȲ*V 5 ؃Dzz\@"ֆ!xHزMMxrH'9; "%Dz#>JP?<!٪FHo9$t]"B+F>]QI媞/'sI"Dzv֞ۺ9$ B"O꯮ fHs I"%b1k$oFE^cHdp^ .@ \Ooh}! B="vuMyx$@LݻH3D>Ɋd7>w "}ܳy Cbd*NC dBw&C7R)GyS"=x#D(${,o@/2wދHx>0K##@Z!t+~:D VF_cH5 [kW##@!tu~H=7z  dd22BFF!##@ ddd22BFF!##@>@e2m r.oA!!^ܷ1MK:it~ 2>`ExC# B擝 ddSc|i~^O#I(I_OY@qK(/DBGE~"@K/B{PHvuk8 2֟rJ,XǾ|W_eJ,@ȶ"l(b(t׻ߠlCl$@c_>5H J,ۯȰ(l .ؿjrk*o; 2E8RE6 (PÖX+2\w{l%Tb d=|(%?%I[,TX~qC% ,e,SbCQ`{`mB^qa! ax$ ƾH -6 u1Rj(exxL(P_VBARkv3]ݭ\lh 3W]!%G٣(=h1(ֽKZuQ;'t؀.G©,:E NC {=K^К=DķͻfcHd{z3̋)bI =$GHd\@`/|5Hlj{mS싴U[C456Y ===Rd=߿q7R#%Votv.fg!]!I7 [{w.A{Kb&@X|̇Iߏ ! QDTW3XPEˏHlG"{3:FaĶb,*ZI?D=RdbG^Ff:J,&@VgԂH̕f!ZūW@(\.fYb5Q "}b=xaUu54"k( C*NA΢Ab?ȇ`Xfj΢.Y }"$KkvkB̲n [];',*ȚaRDN!Gd=Rmuk؇6 =SD4D~Z9"{gQ*],B< NRL7!"=NH.6ԓ"m19:>D:X/B%YH D#ku n Rh-{pӹ2pt2*5DMߘ{zcddW[X-[фGH'#"}א4 t2-[5:W#D:g'$Hdm d$W M NF" d/gtY&Y8E)b1Q$9DFt:G8AdHӭd "cD:&{< t?1Xtdtc;;WH"< dDj"b@Fi`.)dsN!#tB$BFF!##@ dd22BFFF!##@ dd22s#ٌ8IENDB`openttd-1.5.3/media/extra_grf/sloped_tracks.nfo0000644000000000000000000000276512627373446020324 0ustar rootroot// // $Id: sloped_tracks.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Sloped tracks" -1 * 3 05 0F 0C -1 sprites/sloped_tracks.png 8bpp 50 8 42 29 -19 -3 normal -1 sprites/sloped_tracks.png 8bpp 98 8 41 13 -20 5 normal -1 sprites/sloped_tracks.png 8bpp 146 8 42 14 -19 5 normal -1 sprites/sloped_tracks.png 8bpp 194 8 42 29 -21 -3 normal -1 sprites/sloped_tracks.png 8bpp 242 8 33 25 -15 -1 normal -1 sprites/sloped_tracks.png 8bpp 290 8 33 10 -15 7 normal -1 sprites/sloped_tracks.png 8bpp 338 8 34 10 -15 7 normal -1 sprites/sloped_tracks.png 8bpp 386 8 34 25 -15 -1 normal -1 sprites/sloped_tracks.png 8bpp 434 8 31 23 -13 -1 normal -1 sprites/sloped_tracks.png 8bpp 482 8 32 10 -15 7 normal -1 sprites/sloped_tracks.png 8bpp 530 8 31 10 -15 7 normal -1 sprites/sloped_tracks.png 8bpp 578 8 31 23 -16 -1 normal openttd-1.5.3/media/extra_grf/assemble_nfo.awk0000644000000000000000000000232312627373446020112 0ustar rootroot# $Id: assemble_nfo.awk 26708 2014-07-30 17:21:42Z rubidium $ # 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 . BEGIN { # Very basic variant function; barely any error checking. # Just use the first argument as the file to start from when assembling everything path = ARGV[1]; gsub("[^/\\\\]*$", "", path); assemble(ARGV[1]); } # Recursive function for assembling by means of resolving the #includes. function assemble(filename) { while ((getline < filename) > 0) { if (NF == 2 && $1 == "#include" ) { # Remove the quotes. gsub("[\"'<>]", "", $2); assemble(path $2); } else { print $0; } } if (close(filename) < 0) { print "Could not open " filename > "/dev/stderr"; exit -1; } } openttd-1.5.3/media/extra_grf/shore.nfo0000644000000000000000000000675612627373446016613 0ustar rootroot// // $Id: shore.nfo 23993 2012-02-26 08:23:32Z rubidium $ // // 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 . // -1 * 6 07 83 01 \7! 00 0C -1 * 54 0C "Missing shore tile graphics for the temperate climate" -1 * 3 05 0D 0A -1 sprites/shore.png 8bpp 82 8 64 15 -31 0 normal -1 sprites/shore.png 8bpp 162 8 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 242 8 64 23 -31 0 normal -1 sprites/shore.png 8bpp 322 8 64 47 -31 -16 normal -1 sprites/shore.png 8bpp 402 8 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 482 8 64 39 -31 -8 normal -1 sprites/shore.png 8bpp 562 8 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 642 8 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 722 8 64 32 -31 -1 normal -1 sprites/shore.png 8bpp 2 72 64 31 -31 -8 normal -1 * 6 07 83 01 \7! 01 0C -1 * 55 0C "Missing shore tile graphics for the sub-arctic climate" -1 * 3 05 0D 0A -1 sprites/shore.png 8bpp 130 72 64 15 -31 0 normal -1 sprites/shore.png 8bpp 210 72 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 290 72 64 23 -31 0 normal -1 sprites/shore.png 8bpp 370 72 64 47 -31 -16 normal -1 sprites/shore.png 8bpp 450 72 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 530 72 64 39 -31 -8 normal -1 sprites/shore.png 8bpp 610 72 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 690 72 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 2 136 64 32 -31 -1 normal -1 sprites/shore.png 8bpp 82 136 64 31 -31 -8 normal -1 * 6 07 83 01 \7! 02 0C -1 * 57 0C "Missing shore tile graphics for the sub-tropical climate" -1 * 3 05 0D 0A -1 sprites/shore.png 8bpp 210 136 64 15 -31 0 normal -1 sprites/shore.png 8bpp 290 136 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 370 136 64 23 -31 0 normal -1 sprites/shore.png 8bpp 450 136 64 47 -31 -16 normal -1 sprites/shore.png 8bpp 530 136 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 610 136 64 39 -31 -8 normal -1 sprites/shore.png 8bpp 690 136 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 2 200 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 82 200 64 32 -31 -1 normal -1 sprites/shore.png 8bpp 162 200 64 31 -31 -8 normal -1 * 6 07 83 01 \7! 03 0C -1 * 44 0C "Missing shore tile graphics for the toyland climate" -1 * 3 05 0D 0A -1 sprites/shore.png 8bpp 290 200 64 15 -31 0 normal -1 sprites/shore.png 8bpp 370 200 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 450 200 64 23 -31 0 normal -1 sprites/shore.png 8bpp 530 200 64 47 -31 -16 normal -1 sprites/shore.png 8bpp 610 200 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 690 200 64 39 -31 -8 normal -1 sprites/shore.png 8bpp 2 264 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 82 264 64 31 -31 -8 normal -1 sprites/shore.png 8bpp 162 264 64 32 -31 -1 normal -1 sprites/shore.png 8bpp 242 264 64 31 -31 -8 normal openttd-1.5.3/media/extra_grf/roadstops.nfo0000644000000000000000000000230212627373446017470 0ustar rootroot// // $Id: roadstops.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Road stop graphics" -1 * 3 05 11 08 -1 sprites/roadstops.png 8bpp 34 8 13 23 5 -11 normal -1 sprites/roadstops.png 8bpp 66 8 13 15 5 -2 normal -1 sprites/roadstops.png 8bpp 98 8 21 19 -20 -7 normal -1 sprites/roadstops.png 8bpp 130 8 22 17 -25 -4 normal -1 sprites/roadstops.png 8bpp 162 8 32 25 -5 -9 normal -1 sprites/roadstops.png 8bpp 210 8 28 26 -3 -12 normal -1 sprites/roadstops.png 8bpp 258 8 29 25 -24 -12 normal -1 sprites/roadstops.png 8bpp 306 8 32 25 -25 -9 normal openttd-1.5.3/media/extra_grf/openttdgui.nfo0000644000000000000000000002776512627373446017660 0ustar rootroot// // $Id: openttdgui.nfo 25916 2013-10-27 15:09:41Z frosch $ // // 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 . // -1 * 0 0C "OpenTTD GUI graphics" -1 * 3 05 15 \b 175 // OPENTTD_SPRITE_COUNT -1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 306 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 386 8 64 31 -31 -1 normal -1 sprites/openttdgui.png 8bpp 466 8 64 39 -31 -1 normal -1 sprites/openttdgui.png 8bpp 546 8 64 31 -31 -1 normal -1 sprites/openttdgui.png 8bpp 626 8 64 23 -31 7 normal -1 sprites/openttdgui.png 8bpp 706 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 2 72 64 23 -31 7 normal -1 sprites/openttdgui.png 8bpp 82 72 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 162 72 64 39 -31 -1 normal -1 sprites/openttdgui.png 8bpp 242 72 23 26 0 0 normal -1 sprites/openttdgui.png 8bpp 274 72 24 26 0 0 normal -1 sprites/openttdgui.png 8bpp 306 72 4 8 28 16 normal -1 sprites/openttdgui.png 8bpp 322 72 4 9 0 1 normal -1 sprites/openttdgui.png 8bpp 338 72 32 23 0 1 normal -1 sprites/openttdgui.png 8bpp 386 72 4 8 -31 15 normal -1 sprites/openttdgui.png 8bpp 402 72 4 9 -3 0 normal -1 sprites/openttdgui.png 8bpp 418 72 32 23 -31 0 normal -1 sprites/openttdgui.png 8bpp 466 72 4 8 28 16 normal -1 sprites/openttdgui.png 8bpp 482 72 4 9 0 1 normal -1 sprites/openttdgui.png 8bpp 498 72 32 23 0 1 normal -1 sprites/openttdgui.png 8bpp 546 72 4 8 -31 15 normal -1 sprites/openttdgui.png 8bpp 562 72 4 9 -3 0 normal -1 sprites/openttdgui.png 8bpp 578 72 32 23 -31 0 normal -1 sprites/openttdgui.png 8bpp 626 72 4 8 28 16 normal -1 sprites/openttdgui.png 8bpp 642 72 4 9 0 1 normal -1 sprites/openttdgui.png 8bpp 658 72 32 23 0 1 normal -1 sprites/openttdgui.png 8bpp 706 72 4 8 -31 15 normal -1 sprites/openttdgui.png 8bpp 722 72 4 9 -3 0 normal -1 sprites/openttdgui.png 8bpp 738 72 32 23 -31 0 normal -1 sprites/openttdgui.png 8bpp 786 72 4 8 28 16 normal -1 sprites/openttdgui.png 8bpp 2 136 4 9 0 1 normal -1 sprites/openttdgui.png 8bpp 18 136 32 23 0 1 normal -1 sprites/openttdgui.png 8bpp 66 136 4 8 -31 15 normal -1 sprites/openttdgui.png 8bpp 82 136 4 9 -3 0 normal -1 sprites/openttdgui.png 8bpp 98 136 32 23 -31 0 normal -1 sprites/openttdgui.png 8bpp 146 136 10 10 0 0 normal -1 sprites/openttdgui.png 8bpp 162 136 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 178 136 7 9 0 0 normal -1 sprites/openttdgui.png 8bpp 194 136 9 7 0 0 normal -1 sprites/openttdgui.png 8bpp 210 136 9 7 0 0 normal -1 sprites/openttdgui.png 8bpp 226 136 10 10 0 0 normal -1 sprites/openttdgui.png 8bpp 242 136 7 7 0 0 normal -1 sprites/openttdgui.png 8bpp 258 136 7 4 1 2 normal -1 sprites/openttdgui.png 8bpp 274 136 7 4 1 2 normal -1 sprites/openttdgui.png 8bpp 290 136 4 7 1 1 normal -1 sprites/openttdgui.png 8bpp 306 136 4 7 2 1 normal -1 sprites/openttdgui.png 8bpp 322 136 8 8 1 1 normal -1 sprites/openttdgui.png 8bpp 338 136 9 9 0 0 normal -1 sprites/openttdgui.png 8bpp 354 136 7 8 0 0 normal -1 sprites/openttdgui.png 8bpp 370 136 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 386 136 20 13 0 4 normal -1 sprites/openttdgui.png 8bpp 418 136 56 36 0 0 normal -1 sprites/openttdgui.png 8bpp 482 136 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 514 136 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 562 136 20 16 0 3 normal -1 sprites/openttdgui.png 8bpp 594 136 56 43 0 0 normal -1 sprites/openttdgui.png 8bpp 658 136 20 19 0 1 normal -1 sprites/openttdgui.png 8bpp 690 136 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 738 136 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 2 200 31 31 1 1 normal -1 sprites/openttdgui.png 8bpp 50 200 20 15 0 3 normal -1 sprites/openttdgui.png 8bpp 82 200 56 36 0 0 normal -1 sprites/openttdgui.png 8bpp 146 200 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 178 200 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 226 200 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 258 200 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 306 200 19 11 0 6 normal -1 sprites/openttdgui.png 8bpp 338 200 56 36 0 0 normal -1 sprites/openttdgui.png 8bpp 402 200 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 434 200 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 482 200 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 514 200 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 562 200 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 594 200 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 626 200 52 32 0 0 normal -1 sprites/openttdgui.png 8bpp 690 200 29 33 -27 -16 normal -1 sprites/openttdgui.png 8bpp 738 200 35 39 -29 -29 normal -1 sprites/openttdgui.png 8bpp 2 264 29 34 1 -17 normal -1 sprites/openttdgui.png 8bpp 50 264 34 39 -3 -28 normal -1 sprites/openttdgui.png 8bpp 98 264 20 13 0 4 normal -1 sprites/openttdgui.png 8bpp 130 264 56 36 0 0 normal -1 sprites/openttdgui.png 8bpp 194 264 20 13 0 4 normal -1 sprites/openttdgui.png 8bpp 226 264 56 36 0 0 normal -1 sprites/openttdgui.png 8bpp 290 264 39 18 -9 -9 normal -1 sprites/openttdgui.png 8bpp 338 264 72 44 -16 -35 normal -1 sprites/openttdgui.png 8bpp 418 264 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 450 264 72 44 -16 -35 normal -1 sprites/openttdgui.png 8bpp 530 264 18 18 1 1 normal -1 sprites/openttdgui.png 8bpp 562 264 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 594 264 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 642 264 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 674 264 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 706 264 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 738 264 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 770 264 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 2 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 34 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 66 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 98 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 130 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 162 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 194 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 226 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 258 328 16 16 0 0 normal -1 sprites/openttdgui.png 8bpp 290 328 16 16 0 0 normal -1 sprites/openttdgui.png 8bpp 322 328 16 16 0 0 normal -1 sprites/openttdgui.png 8bpp 354 328 16 16 0 0 normal -1 sprites/openttdgui.png 8bpp 386 328 35 31 0 0 normal -1 sprites/openttdgui.png 8bpp 434 328 33 30 0 0 normal -1 sprites/openttdgui.png 8bpp 482 328 36 33 0 0 normal -1 sprites/openttdgui.png 8bpp 530 328 37 33 0 0 normal -1 sprites/openttdgui.png 8bpp 578 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 610 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 642 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 674 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 706 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 738 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 770 328 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 2 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 34 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 66 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 98 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 130 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 162 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 194 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 226 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 258 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 290 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 322 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 354 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 386 376 18 18 0 0 normal -1 sprites/openttdgui.png 8bpp 418 376 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 450 376 19 22 0 0 normal -1 sprites/openttdgui.png 8bpp 482 376 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 514 376 54 44 -16 -35 normal -1 sprites/openttdgui.png 8bpp 578 376 7 7 3 4 normal -1 sprites/openttdgui.png 8bpp 594 376 7 7 3 4 normal -1 sprites/openttdgui.png 8bpp 610 376 10 9 2 3 normal -1 sprites/openttdgui.png 8bpp 626 376 10 9 2 3 normal -1 sprites/openttdgui.png 8bpp 642 376 11 7 2 1 normal -1 sprites/openttdgui.png 8bpp 658 376 9 9 3 3 normal -1 sprites/openttdgui.png 8bpp 674 376 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 706 376 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 738 376 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 786 376 10 10 0 0 normal -1 sprites/openttdgui.png 8bpp 2 440 10 10 0 0 normal -1 sprites/openttdgui.png 8bpp 18 440 7 7 0 0 normal -1 sprites/openttdgui.png 8bpp 34 440 14 13 4 4 normal -1 sprites/openttdgui.png 8bpp 66 440 7 8 0 0 normal -1 sprites/openttdgui.png 8bpp 82 440 7 8 0 0 normal -1 sprites/openttdgui.png 8bpp 98 440 7 8 0 0 normal -1 sprites/openttdgui.png 8bpp 114 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 130 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 146 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 162 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 178 440 8 10 0 0 normal -1 sprites/openttdgui.png 8bpp 194 440 13 10 0 -2 normal -1 sprites/openttdgui.png 8bpp 215 440 9 10 0 0 normal -1 sprites/openttdgui.png 8bpp 232 440 8 10 0 0 normal -1 sprites/openttdgui.png 8bpp 248 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 264 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 280 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 296 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 312 440 14 10 0 0 normal -1 sprites/openttdgui.png 8bpp 328 440 14 10 0 0 normal -1 sprites/openttdgui.png 8bpp 348 440 8 8 0 0 normal -1 sprites/openttdgui.png 8bpp 362 440 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 388 440 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 414 440 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 440 440 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 466 440 20 20 0 0 normal -1 sprites/openttdgui.png 8bpp 490 440 20 20 0 0 normal openttd-1.5.3/media/extra_grf/elrails.png0000644000000000000000000001362112627373446017115 0ustar rootrootPNG  IHDR sRGBPLTE 000@@@PPPdddttt4/ [?rYzWH|!*8xAr}8Xf pWC%q&Bs v$A0E|[a$ QK+Ś7v:> 7T> L<rSHT>[4~>&恜byup@wKa[y[8ےO-j].^>r)j`bU1G).N.Iʏߧ:* P.Y uiYY/ Kr@5ie_y1[Ѿ,wx(P{"1!,wx(P{"7YۺXywJ[`I}rOd"3[^~G.}cAp~@qWk"G$ ՝Ӑ|ٍ]m5ߔ ,'nOImP(3 h+HKCZ9CZ|Veq"G,8QsD}nIRdr@Io~e4r{ ̞9Drd9F Hj>6Ld|ۗ! Z.P}l0NH~&Oo3%}Ҿ"0Mz h.B})hBõc݀(B B@P(B@P(B@P(B@P(B@P(B! (B! (B! (%F ZV~y//?dm{'-_6'Սl UsOw&;ov~Ko +T %€w@`ǃag:@6,v!q:I^D@{P]PyOeFcΟ_B,6 㬾" ]@}nW'Ԡ|}RClQ!B! (jku3ZHj)J)1nn 9_ ޭOw]T̞*/g j:LE#^PZ)~s]W%W[ $T @˵_WbEwޥu_˱sbw𾫍ۛ޵TfrBЂ 🿬/n]U4콟 FVݺlrhUXÚ7Hu̗9]Z­O-F[|hw׹E{.xF4  < e+)0ݐ#|}ϵD:hYbԡR-eaXanCۇYZgc5ۀX 0KnƧ#$bnV7][ס(ʘ,<{D6^j%a)ބ<@R3 uXӡ >I@y -@(чPNQ!e) ȉRbt׷v '’-@R$[$=.XZ.vˀA,:QELoW)$aXY|d2{a H|]NdZVC /o20)=IA|B 6 nbY,;QMSD x&ND6\h@|@ĊQo`LhF1Dtx)g\TI Ӗ=q4pZ7w9n S( -^q*^X.B›SyE$YaZ!L@dCz\c3PWWU\;8 Ax.,4 R~oЀWD(EO4ڪ5-]t\[n `=L?.1X.TjJd[Scvxlt.1 A\;n "K&B-2141HCvt8ReUc"m ruVq&|~H}$@A< Xk_ AdZdZUٿd@ÇD^cnb%SS}P*uF@`{6V":@zhCRpg֢*". @Y#+ >?Y H\ K+] \Gтs\y\ctoٚa]S|Eq Y"_*r@{@F79ҨIK"I)7R1.l~b\Hk]NgA4S>DVE@8B򰀸Yx=v BF1HKQȀ!__w~ Y;-%Ԧyq)/e C%K~IT} Q! 9. ˲b2,`w$K k\' 䰀 ]~7!vCRcGwC3sqя (zhC[~G BDPBa C@PH7{pB@2I3ѓ#MB B@P(B@P(B@P(B@P(B@P( yt@/ {!;d?o;@<dBIrg!-g1>d(OU+C"[$Ώ ,Dv8[ ?*@P(BuVJIﶌ)з纮|~n_AgvUUʷi~Kq@^<ѿ1&Jry\c2! D@k'&b4k (0}}|D<A@PI@\S6@,(# <HqyB |RuiUKbOa,5O,-!mEx"}}|\{&B&y䪕@@zX|Ӵ)H3V1]~)Yӥ.xmk A@,ji\hAӳEe ʬ5aYC[Q7,@T? {, 1O ]+"㳌Hy?LRI6=j 2 ͗'O+UUoT" m[^q{] |vpҀL' ǘQ4o)҉сBZ.=" cG' {XӞ BAA72ϲ"]ф\ɰQv;^ˇ5)Abwey~J_xUN@+(ۀ5"%+3)A@@f#{6yUO@md"\|H.vqŝ ީ!qxšYTg`@cV wtXwtRJUI)d:.` \ch ٍla]}ǎw~LJA@鸀G)ʓ5RE'Q5?gP@ٱBj1H* .g%De9CdbAK_ٯ^R9y}򧏵?elAjwR XHCXtflO׾r| lя&q-Z* u훔(v+Zm= 3beZJKiɶ݈z* WЀ-_L PI)TNA l1bb,wS|⛊d@ZB|L2ZӹX YJwR z?CـBk g~deW"R$F֏X؃ jXҼDm4nk_ T1V"I) P YJʵ ݤy.cDiBV OJxʵBH)8P}~RP:Z@0A ?/1P(B@P(B@P(B@P(B@P(B! (Bmx+eE-IENDB`openttd-1.5.3/media/extra_grf/tramtracks.nfo0000644000000000000000000001775312627373446017645 0ustar rootroot// // $Id: tramtracks.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Tram track graphics by PikkaBird" -1 * 3 05 0B 71 -1 sprites/tramtracks.png 8bpp 18 8 20 13 0 4 normal -1 sprites/tramtracks.png 8bpp 50 8 20 13 0 4 normal -1 sprites/tramtracks.png 8bpp 82 8 64 36 -18 -8 normal -1 sprites/tramtracks.png 8bpp 162 8 62 36 -16 -8 normal -1 sprites/tramtracks.png 8bpp 242 8 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 322 8 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 402 8 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 482 8 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 562 8 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 642 8 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 722 8 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 2 56 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 82 56 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 162 56 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 242 56 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 322 56 64 39 -31 -8 normal -1 sprites/tramtracks.png 8bpp 402 56 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 482 56 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 562 56 64 39 -31 -8 normal -1 sprites/tramtracks.png 8bpp 642 56 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 722 56 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 2 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 82 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 162 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 242 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 322 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 402 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 482 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 562 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 642 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 722 120 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 2 168 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 82 168 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 162 168 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 242 168 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 322 168 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 402 168 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 482 168 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 562 168 64 39 -31 -8 normal -1 sprites/tramtracks.png 8bpp 642 168 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 722 168 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 2 232 64 39 -31 -8 normal -1 sprites/tramtracks.png 8bpp 82 232 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 162 232 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 242 232 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 322 232 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 402 232 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 482 232 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 562 232 20 20 0 0 normal -1 sprites/tramtracks.png 8bpp 594 232 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 674 232 62 64 2 -49 normal -1 sprites/tramtracks.png 8bpp 2 312 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 82 312 62 64 -62 -49 normal -1 sprites/tramtracks.png 8bpp 162 312 62 64 -62 -49 normal -1 sprites/tramtracks.png 8bpp 242 312 62 64 2 -49 normal -1 sprites/tramtracks.png 8bpp 322 312 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 402 312 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 482 312 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 562 312 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 642 312 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 722 312 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 2 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 82 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 162 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 242 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 322 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 402 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 482 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 562 392 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 642 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 722 392 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 2 472 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 82 472 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 162 472 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 242 472 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 322 472 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 402 472 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 482 472 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 562 472 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 642 472 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 722 472 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 2 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 82 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 162 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 242 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 322 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 402 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 482 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 562 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 642 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 722 552 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 2 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 82 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 162 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 242 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 322 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 402 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 482 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 562 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 642 616 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 722 616 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 2 696 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 82 696 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 162 696 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 242 696 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 322 696 64 56 -31 -25 normal -1 sprites/tramtracks.png 8bpp 402 696 64 48 -31 -17 normal -1 sprites/tramtracks.png 8bpp 482 696 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 562 696 64 31 -31 0 normal -1 sprites/tramtracks.png 8bpp 642 696 64 39 -31 -8 normal -1 sprites/tramtracks.png 8bpp 722 696 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 2 776 64 23 -31 0 normal -1 sprites/tramtracks.png 8bpp 82 776 64 39 -31 -8 normal openttd-1.5.3/media/extra_grf/airport_preview.nfo0000644000000000000000000000247512627373446020706 0ustar rootroot// // $Id: airport_preview.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Airport previews" -1 * 0 05 16 09 -1 sprites/airport_preview.png 8bpp 50 8 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 290 8 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 530 8 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 2 168 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 242 168 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 482 168 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 2 328 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 242 328 230 140 0 0 normal -1 sprites/airport_preview.png 8bpp 482 328 230 140 0 0 normal openttd-1.5.3/media/extra_grf/flags.nfo0000644000000000000000000000550512627373446016556 0ustar rootroot// // $Id: flags.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Flag graphics" -1 * 3 05 14 24 -1 sprites/flags.png 8bpp 34 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 50 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 66 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 82 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 98 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 114 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 130 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 146 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 162 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 178 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 194 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 210 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 226 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 242 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 258 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 274 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 290 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 306 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 322 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 338 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 354 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 370 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 386 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 402 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 418 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 434 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 450 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 466 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 482 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 498 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 514 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 530 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 546 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 562 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 578 8 11 8 0 0 normal -1 sprites/flags.png 8bpp 594 8 11 8 0 0 normal openttd-1.5.3/media/extra_grf/foundations.nfo0000644000000000000000000006071212627373446020014 0ustar rootroot// // $Id: foundations.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Foundations. Non-halftile ones by Marcin Grzegorczyk" -1 * 6 07 83 01 \7! 00 5B -1 * 3 05 06 5A -1 sprites/foundations.png 8bpp 82 8 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 8 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 8 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 8 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 8 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 8 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 8 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 8 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 8 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 72 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 72 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 72 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 72 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 72 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 72 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 72 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 72 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 72 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 72 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 136 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 136 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 136 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 136 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 136 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 136 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 136 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 136 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 136 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 136 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 200 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 200 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 200 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 200 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 200 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 200 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 200 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 200 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 200 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 200 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 264 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 264 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 264 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 264 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 264 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 264 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 264 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 264 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 264 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 264 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 328 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 328 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 328 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 328 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 328 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 328 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 328 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 328 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 328 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 328 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 392 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 392 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 392 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 392 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 392 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 392 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 392 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 392 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 392 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 392 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 456 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 456 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 456 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 456 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 456 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 456 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 482 456 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 562 456 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 642 456 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 722 456 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 2 520 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 82 520 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 162 520 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 242 520 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 322 520 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 402 520 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 482 520 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 562 520 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 642 520 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 722 520 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 2 584 64 33 -31 -9 normal -1 * 6 07 83 01 \7! 01 5B -1 * 3 05 06 5A -1 sprites/foundations.png 8bpp 114 584 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 194 584 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 274 584 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 354 584 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 434 584 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 514 584 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 594 584 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 674 584 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 648 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 648 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 648 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 648 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 648 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 648 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 648 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 648 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 648 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 648 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 712 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 712 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 712 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 712 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 712 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 712 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 712 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 712 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 712 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 712 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 776 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 776 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 776 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 776 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 776 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 776 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 776 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 776 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 776 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 776 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 840 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 840 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 840 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 840 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 840 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 840 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 840 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 840 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 840 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 840 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 904 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 904 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 904 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 904 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 904 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 904 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 904 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 904 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 904 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 904 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 968 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 968 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 968 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 968 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 968 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 968 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 968 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 968 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 968 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 968 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1032 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1032 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1032 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1032 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1032 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1032 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1032 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 562 1032 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 642 1032 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 722 1032 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1096 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 82 1096 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 162 1096 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 242 1096 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1096 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 402 1096 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 482 1096 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 562 1096 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1096 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 722 1096 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 2 1160 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 82 1160 64 33 -31 -9 normal -1 * 6 07 83 01 \7! 02 5B -1 * 3 05 06 5A -1 sprites/foundations.png 8bpp 194 1160 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 274 1160 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 354 1160 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 434 1160 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 514 1160 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 594 1160 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 674 1160 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1224 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1224 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1224 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1224 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1224 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1224 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1224 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1224 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1224 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1224 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1288 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1288 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1288 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1288 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1288 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1288 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1288 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1288 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1288 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1288 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1352 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1352 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1352 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1352 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1352 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1352 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1352 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1352 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1352 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1352 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1416 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1416 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1416 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1416 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1416 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1416 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1416 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1416 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1416 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1416 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1480 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1480 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1480 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1480 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1480 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1480 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1480 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1480 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1480 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1480 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1544 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1544 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1544 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1544 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1544 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1544 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1544 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1544 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1544 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1544 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1608 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1608 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1608 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1608 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1608 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1608 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1608 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1608 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 642 1608 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 722 1608 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 2 1672 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1672 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 162 1672 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 242 1672 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 322 1672 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1672 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 482 1672 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 562 1672 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 642 1672 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1672 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 2 1736 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 82 1736 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 162 1736 64 33 -31 -9 normal -1 * 6 07 83 01 \7! 03 5B -1 * 3 05 06 5A -1 sprites/foundations.png 8bpp 274 1736 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 354 1736 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 434 1736 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 514 1736 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 594 1736 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 674 1736 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1800 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1800 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1800 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1800 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1800 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1800 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1800 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1800 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1800 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1800 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1864 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1864 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1864 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1864 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1864 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1864 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1864 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1864 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1864 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1864 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1928 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1928 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1928 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1928 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1928 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1928 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1928 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1928 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1928 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1928 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 1992 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 1992 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 1992 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 1992 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 1992 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 402 1992 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 1992 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 1992 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 1992 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 1992 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 2056 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 82 2056 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 2056 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 242 2056 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 2056 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 2056 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 2056 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 2056 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 642 2056 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 722 2056 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 2 2120 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 2120 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 162 2120 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 2120 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 322 2120 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 2120 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 482 2120 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 562 2120 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 2120 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 722 2120 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 2 2184 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 82 2184 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 162 2184 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 242 2184 64 32 -31 -9 normal -1 sprites/foundations.png 8bpp 322 2184 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 402 2184 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 482 2184 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 562 2184 64 40 -31 -9 normal -1 sprites/foundations.png 8bpp 642 2184 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 722 2184 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 2 2248 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 82 2248 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 162 2248 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 242 2248 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 322 2248 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 402 2248 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 482 2248 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 562 2248 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 642 2248 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 722 2248 64 33 -31 -9 normal -1 sprites/foundations.png 8bpp 2 2312 64 40 -15 -17 normal -1 sprites/foundations.png 8bpp 82 2312 64 33 -31 -25 normal -1 sprites/foundations.png 8bpp 162 2312 64 40 -47 -17 normal -1 sprites/foundations.png 8bpp 242 2312 64 33 -31 -9 normal openttd-1.5.3/media/extra_grf/airports.nfo0000644000000000000000000000317512627373446017326 0ustar rootroot// // $Id: airports.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Extra airport graphics" -1 * 3 05 10 0F -1 sprites/airports.png 8bpp 18 8 64 31 -31 0 normal -1 sprites/airports.png 8bpp 98 8 64 31 -31 0 normal -1 sprites/airports.png 8bpp 178 8 64 31 -31 0 normal -1 sprites/airports.png 8bpp 258 8 64 31 -31 0 normal -1 sprites/airports.png 8bpp 338 8 64 31 -31 0 normal -1 sprites/airports.png 8bpp 418 8 64 31 -31 0 normal -1 sprites/airports.png 8bpp 498 8 64 55 -2 -38 normal -1 sprites/airports.png 8bpp 578 8 18 17 16 -1 normal -1 sprites/airports.png 8bpp 610 8 64 55 -2 -38 normal -1 sprites/airports.png 8bpp 690 8 18 17 -30 1 normal -1 sprites/airports.png 8bpp 722 8 64 55 -2 -38 normal -1 sprites/airports.png 8bpp 2 88 64 55 -2 -38 normal -1 sprites/airports.png 8bpp 82 88 64 31 -31 0 normal -1 sprites/airports.png 8bpp 162 88 64 31 -31 0 normal -1 sprites/airports.png 8bpp 242 88 64 31 -31 0 normal openttd-1.5.3/media/extra_grf/palette.nfo0000644000000000000000000000272512627373446017121 0ustar rootroot// // $Id: palette.nfo 26869 2014-09-21 07:57:45Z rubidium $ // // 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 . // -1 * 0 0C "All black palette" -1 * 0 05 18 01 -1 * 0 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 openttd-1.5.3/media/extra_grf/autorail.png0000644000000000000000000001257712627373446017313 0ustar rootrootPNG  IHDR pwsRGBPLTE 000@@@PPPdddttt4^f45 ~5:߫Zh~]Ú_px_diY 9-p2o7"_ploEI6e;W-h ǎ ^y^9tC>zl~9oE㿢-pD[*?p=7Xx_>y=58JU8~ ǏGP@<c-tS/eZ(" 8?V"[DMu-JplAC+Hίl8#jϠ{o@FWXDzrMz_o~rA@6!%dBjt{+oѷl @g@ @   @A @B  B@!A@ a &&٦,_ZM.#p4rBVO<^oЅ^<װÊ*p5ż; &$>ײ_=[hf|i;iL?b)BЮ~\_2D~W~rZ|0>+ 'p)OH@ EDOz)[ #-j.@T_ QJd~?k<~ D4J/;{߫YޖwIߛ"[a";7N~FjmV;/|!qF)ٰT٘ϟу^w]i A)H|;ͲOR~mV-緥3&8zrmHc^4+4kQ6ץ&8HG!r*\y7D_4~Ug7WmB8Ų}x&$5W{{jaE @l"M"$_RR"~v )`2C$^$\0_(hr `ͳ/*в~!!!7HR^j}vFm >S0jB=r ,[";,"K=ǵHi6",rЄ_}U"Hٱ<g((! ?b /L}"BWiEG--%pu @!kmQ" 2vB~VO0@(E@ YyEBw=;|Y&dF>?eM\zO L @0r~0 @  @B q !A@!A@' 6M zߤ3ay~g/MGO<^m߫-pu]L<^3Mf@G_?3Kz~mrg@aOϔ~ӎwY)BОk_{EKZZJz|,~eg~<> N5~NHy|O .{ #2K0fr:ǣp5 ]3k _ e۠2% :^v5i#р4R('{~%G|_kM3'tq* qZ&7{"\u3r:8R'0E0%C$ Ղ5<{K 6EV@SYe[I 0<_=dP{U l8jX'?ZSM{c)wF%7q A쾀O;CU>&_0+ Em_ Uߏ^)* = w]isVwɄ#S<b~ @_J/ C/NHj@; [[u+wmosc`|ٟݻB_Ԗ-J [oFBעJXܩ[~-W-l0?-o?*'OMNb}:n*n lI{[X 0Z6w@>-N0_2kż_z@r , $t+ & [~+z $ , vP݄nMz5+$/z΀\c@  @5AB  B  B@!A@!A<^"UIo0^~F:+Ӷpx {.~ ӎ  #~wWi-b9oGA}ל=Q~0d% I[r Hj)lIp sD:zM0 1 0  @uc'r4A=&S6< 2 sgt{V,3o:@@@j!i8 䪀$w8 [䲀XA8${@P2@r ( WNA @Š7 t Y@@NJ@r= YA@!A@NB@!A@!AnaZl?Q"IENDB`openttd-1.5.3/media/extra_grf/aqueduct.nfo0000644000000000000000000000353012627373446017271 0ustar rootroot// // $Id: aqueduct.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Aqueduct graphics by Jonathan G. Rennison / PaulC" // temperate aqueduct -1 * 6 07 83 01 \7! 00 09 -1 * 3 05 12 08 -1 sprites/aqueduct.png 8bpp 34 8 61 32 -30 -9 normal -1 sprites/aqueduct.png 8bpp 114 8 62 31 -29 -9 normal -1 sprites/aqueduct.png 8bpp 194 8 61 32 -30 -9 normal -1 sprites/aqueduct.png 8bpp 274 8 62 31 -29 -9 normal -1 sprites/aqueduct.png 8bpp 354 8 61 32 -30 -4 normal -1 sprites/aqueduct.png 8bpp 434 8 62 31 -29 -4 normal -1 sprites/aqueduct.png 8bpp 514 8 33 23 -31 0 normal -1 sprites/aqueduct.png 8bpp 562 8 33 23 0 1 normal // non-temperate aqueduct -1 * 6 07 83 01 \7= 00 09 -1 * 3 05 12 08 -1 sprites/aqueduct.png 8bpp 34 48 61 32 -30 -9 normal -1 sprites/aqueduct.png 8bpp 114 48 62 31 -29 -9 normal -1 sprites/aqueduct.png 8bpp 194 48 61 32 -30 -9 normal -1 sprites/aqueduct.png 8bpp 274 48 62 31 -29 -9 normal -1 sprites/aqueduct.png 8bpp 354 48 61 32 -30 -4 normal -1 sprites/aqueduct.png 8bpp 434 48 62 31 -29 -4 normal -1 sprites/aqueduct.png 8bpp 514 48 33 23 -31 0 normal -1 sprites/aqueduct.png 8bpp 562 48 33 23 0 1 normal openttd-1.5.3/media/extra_grf/tramtracks.png0000644000000000000000000006253212627373446017642 0ustar rootrootPNG  IHDR @ZsRGBPLTE 000@@@PPPdddttt4,|ƟcKd3k63|gdt 0x=g藅7GF`3.ڏtz4lrx}sD׽Y 8Xƀa{D<z?_[zRԢdχxAuы43GG21k =`+"wB¥Gg&fܘZ(gsχIY+Cn%{8NFb߾YSgijUJ蜐n<Ŏ/ q&Wl&Qo( </EѓVAҏGk#;Nqm 䄨eHʗ⨧2ޣ^b]=`dRwf'ۍ7o*OĝV3BD1'|ew䧗:`;0&zzSGLD?¿Zd~ ꬝qP/ț"oߌG'5 Q;!x WpR_%!I?_0hiؗMQ$_#_|PL!czD6"J]x4'b`Y_EOĵ<ZzHc3O{=x|8+443~pULТI/h9Oǚu$RO@ӿ_+hNJz{ѥr4o2IMy1==<fh1=\Je1iOI?Ψqaf ;=ײ̧>^\͘w@noEG]t]Gcz4vn{c4E5\+c&z/zxCf2Vzq^ĺ]pղupֿ7Nz'"#M&zLNY)N.7ae<ƲxrV.A$Ўw6[FzByHV1oucDGaoA9"w,1-DP+Bc@Q83CK/(v#:+7߅5޲y>w@=F V#_"|-6z}}쎗YouX#+*,*xDaGmDiU j ;>/7ğl9o, 5"F'h q'}^\ŃW^xT;) ckҽXa=Bj bvvҧL>;bd4z䃩-uz' QшbQkUQMB4M㡥W^Lb[\e?HXE42țoVCH%xƀZ7T c-s||ՊJDU?"z=VރxxDŽ bɄ5y/` XXŝx] ŭNB+E>HS ^\MXB@L=H/dؚ{%zm%9"1RU;fG7 0F4 Be]=BĈUR mZ["4Ը_. U$ޓߢ(VH [, <1g ` 0 `8IqӢfc.,ɑZsr-ϱfѳ<^x=YIӛ),x3wUbee,MI3gOϱ-z/69plc`3qsG! @==u0 bz6ֳ}Bi y x^}s~{Q~'bE38OU7[.oGGy &eS=z_p7Nj3@F`PDŽt͟z"@|;$hW!oBiW>\%"JHAbNx!6VSDÿQ8X-1ij3TXp5X<Ń/5 QSC]Q+tߔR'+Mԟ&v40ym@U]Ow{ZZQ+=w~#m*d4,!}&=ۀ˫f> >sRzӓE4؃P^Ш,LBX*VhsP拡z ( p5sJvTPkқYWQ5 χ%V6j=@⶿l p莒֪S%=*e rxǨ^O1n- ɀz-Dݡ H<>MP@,@"z5Uf] s)WW lQ,y/l9FV@ Q-Vk@׮F@9 L@ 0@`W;` 0 @`0 ` ` 0 @`$ )B❕0^ǪozEXUn΢gyv}=y5ze0cyc]ϱz~ fdaQh,cAEsԳۃu̬I'B}?G OԂu>"'/ ?Gd\]% ?#2'{  Ի^DكK|_N9`&s㗑VzSKxznf)/bft51Q"JݽG=|@4ђʐ_giei X9zIU!M&"EW3n2"z!|F}@xx\: 7\p E)5J!k8("2E: joՅG]d@hAAVImV+HkzԚg-wJe}^]'ƛ TAz#x[8(!2QǏUvrɋ*YVA$_V#YjsObWҜk]"uBP!\ύyvGi" ]ᫀDuN~RN_ZU/z[dMԣ/&\IDp ?0p9x;6l?ɢDD!8~m;ſjAuPJTEEGiun _Vi?/D3C1Bd գ Hh5!}R=m<hF__*/́IjؘWCT9JSV6%|ILwo㍳+zn^ 2zCz+)uk~mZkͩV$nKkGF}t&&'|$TONyŧ|xV£t)uݢJ: '׳5^ x.D&މw]gC7i-{dVMoi,Jy[-vyil/Es: ސ>c@xTF/"έjA+Wb{(my"{ Ɉyd{N[G{y(s9! 2a;Z`YimdZ "Xf|g9/-ZKܾ=9IruW,jd$zh1\VK q):75K={ Ek2D?\&^!=?|D9߿^C/Mj!{ZDd`Ưr'ʡ֮':=Vf!a+W|[rXWb3W$\4NpgHk"2hy?cHIۀսUPETL]H*Q$կ_*]`2iQCXo.5n"Uѫb.Z')yDT%"K&BY <`"}"4fM\4OqQ89A|E*9.Tb됏WzK?\4Op3;Izהձ>^^d{LZ.u<4vI5P+_Տ<ēμI=6ȭMŻEH Wd'Dǟ}l]2iw1\!;uRZ/exog}-GuSpǕ:o`e^z`q ww5ӛ} Ky9/ZVPI~ÿ펛q}?0\Tiu자a`Z/X>>˶Iӛƻ6yq4?d1G㉞p}C@9|֧G_eswx"3B?T<̊Y3wxSj=ʗ VIA^z;!!$\"}aL]=N0<~iN -?2{$&= ۽(xH(-6JIvJdܿ!}ǿ~4.'3͚R/3lqcZNHZ>H<~]f_ Se.%L.?~iM.=LBJwDʀT5·lūmHㇽg";섥v}њ鑥~&c>7~JSc C'D<./ϩKx<~̗GIxsC3`{8Լ< M{@yy%b9t>jГ2 ٿU+s&>?d]z/ lͩHv&OQM3|TPǭvʳ0i&"&)H`?veL>4h>"'ŽSo;T;O)!(v=+¼?J>'TJ-=;wG\{qb$gRq"Y R_1H6 X^HJ|B!-o>v\n"PA_=sPeEUFU'Hj˝2lccKpFS2!4q`\z{ڟETNHHW ޑ1\+fy/_5#B f]ø}3w0|svlyZ,ĴO:X3^ڋN* $UvĢRNW4ڸ )RHV-{bQ4 FX$f#8oX^MFioԿ;jxKOӻIlE.Vxɽe _<2pw/ٚ+;sRQK}jm'U*{C|W3K[]SjHtդs"di*/ŶMTQb=?Ld0Zn||od_]g5^4U8^#$Tjӭٌ* 7@GߤRnk6CoEQTZ%bM~:"kp0lۚ=-MIٮo{u_l.'ɞZCtx3v\+=}^ q5ݥA92_2џIJp۷_, Tgɕ5yjvϗhE3ZmVd'WMľEsDdL*&|0s)2eM\- IDAT1{[T[mxGQBdˆٷʭN*^X@!wY++.Np\@;3؆פhzu,^ 9u,L!Mru;R ѓ⪴:M;㕳|L[Z9~8"5&P,يn<Ǘd&Q_hٚUS5ЃڞƮXʳG [фX" }9Y\e4̋)NQOV?Zi+oL ~jҤwqm-o0ۭ =15\n,2ZŢ WqE*<Dc)_ּlSſ<]v,I$b_}juO ^mȵ)NžL؅K2,:dZNbzbEdxZ2Uؚӥ¿~=CV?r[O#-9QEDA¹xp 4hO.މtʊl3Y+MLZsvm&ShL|J>h!j[zУ˻\Y1\,Ed&+v4An EmsjRe"6Jf0G-?K/ VyIiInv}Z9~عvX"xA~]$q УK9:7?UŦP*'Q:zGĚ,ed*rg8^Uhbi8+/$:\kk74h)'~Yo2 #]qztjƢ54MdzzEr_&>vꮜ2]ܿDp#KXgdQW\(PأMĵzWk7XWZsu?k(OqPEr˫z;緼7ףߕeyl뙴qlX͗ſD~郺;}Wx:: MCZg,;;].yea<[gɀBZ(#*z4N3FpݑD0=(ɨ4D [_]yo'B$fg2ir`5oqyPP%r";Tg$1:KSPhW^|-i"23_Dt2dUjN#n틨b{U[R^UWַ?Dx[B/9X[{eV*:NIE 1SV{^:W]uwmX8CAJ:jU6GlA( XVūMӻj^=j뽼D(ˬ^ xxboY^~qiS]k*zcvؙ#Pܙ$츳ױzMikD'^G\bC;! v|CNawt/w6")Lo5xh-uS+sM,kk+kc>KiSY/bkXܽz7W*Wє{Q>a>BqRfx'E0te!gz`|TI^{h5[=Xe٘G VG ؚR:]R;@.]. &[s]=ٮs2ߝ' I0uA]o?j5z(|֟ U"څ֜Ԯ^|~#nB@S=bűXӳ? 𢡄w,F<[We{Ym Pf?bax?yX D(}';/ <|w,hW6z>޴ҵw&@"ƋbA<=pD|_ok H"x}bWλO; y77Q2HF~ۗ$">_8?UDfj> f(xcލ"2jVǗ߾D/*#"Rl2밳 q>xk~SdzƗ/7E>7nV"r @97,NDAYT]y/UENhD2?jl\7dY$<=r"pBNO"ijta#"DCo99@ɳH 0-ve |uޛ1Bwl'eY ׳;c-<؟_r{ @`0ӊmuuI.^o:]=2; kϛ|x&=rIě|x ϛs,w-z$U/" 0eCztnN`1 u/"dSJ^ϲנCoZ'$X8-ۍǴгOF 8An1tB4NDЃXwzOp<$<_q0AD%*؊W cϛ=]OYDQ?2ȭ@$H*+^H;<O-cQtzȧO}Y`"'d 8YDa,OKzh^@jtDOӯ<?BvګG 퐕_ׯ(f<|~Wjzꟲ &xrB؇wWj +mjopmhFRԋ+z3cGo̿)B.:˃qAZE*VeQ Q{"A2|:{~ؐiն<kz5X'^<ǖ޸*W5E@$gكH b"3+%=|._ݩ{0T]U CzS[xgo} ߗ=OOAGލ).<!ߺUDȺU kcuiw3BZatU  (n,Iog}CJDAA&Rf~Pi<)l#b-=N7,y,uXE>[dZ#S>O;P!o&CEHgo.Bs?Y?_2떫hۂ]rW^<Uh6?ŗH@O"^{tȝT$9OOE+>>E#DnG d; DʅX߯e=bZ(l-m!9H-@<VGGWt-c IE$Be'`7A2>'k}5\ٍ݈RA=2 ȧ_˒Mo7qs7zr Sy *fedD\*qڗX}03 dv@P1^Fʹ6{ 'DL͏̯#y7 OBGoݽb)@='Q䷪5@Z6٢i%@%,#.6tA= 9@|3TuR}OV9Mn x4@ kzJr óϱȰ @ȼ8σ{٪ި 0 ` 0 @`0"we0^ǪŦ{cQ#Ţs候o3U@pD38L* z'd]+Yz2j_+9~>LW,Dd=AV*B@3U3e֜4-b͛A*x(^*7%Vou[x}рTΔAx":x&;ی$ uTwm$GN))wҫ~jX￯ӿAjp.6# Vzx^KUgω]x;H]pжLj#%ȔTێRh֊EgiH _h%GHU^6pжm@´e H_d @gnle׿3e; 2תu@.&XD_^@4,ί@ \=2fWA22 @ BOz_K/ @  re4tv@/|80@` @ Z ` 0 @`0 `0 ` 0. &/k=7͢7x9?zRpVt,,n"g9s93ųl=:o%/3_). fı{: -pe=|oyL h}B=!X@^<^=  0iC8`+<zW9U=ώ7+bZ'c3k[xWABPYs 04=oR̮ScIn2DyV,rׯ)o pAĪLbKL̏9"۹rb2ܚo!Ѯ+]u7q֛Ⱥ5;vƨӚξnnl,٦zM8+U܊}%x< xJ,Miғ43rW*fUmbJ[֬FIY4 ԋ҃z E JImF]hϘ/>yi _{7s-͗AQл-!ycvzJH l&c A I6y)GCβg%كx}9<9uG﷈k ]yq Ѯ8Dw݀xy&} cgּ>%!$@m,`~6ڭ9 X~ U4.V<k^g[^W)۷҈ ծvSx@֝9  iaz!*@A^1  @Ѓ @AA rр\  aC@ @`] zՍ @`0 ` 0  0 @`0 `W)Kqz3ױ[#頓h=㵘gѳ}W7SY ,?cڝ~-. ֲgT3,:93 2O~r`Mmƾcyc]ϱz~S=@dnX^,̑DUgQ^@ؚrY|rpvz @`0&}V+7,]7]f(W6 z<3{/2ȒY0kzޜx/227x~erěeJ y3WAl@<=F_97 AȐ7xid zE;x{_b? Hy{ [Y06 -m,9zs){ @&xz HKؾ=g .$fjҙAӺmk{uisB1/\@gMX;no팷K}2@. 8=`QXut89 3jW]+-{9jע m˯i|{*zWly~k 3SJFZP 7:gh_;4^jm b0^ d՚Zϫ\3 =-@[^xkׇY-1Vn]G K ٚ]ot л,@z. d=pxSڼ9 {x %bi㕯5 kEbmuAȥ2\~=d@.K}kx12 w ФC  @@KYj  @ Y]  z@A@zzл@`sm@,{ @  0@`0Z! @`0 ` 0  0 @`0{zKo:Vs^6^l9+eAԳYl<,W6h9;Y uzk-ý\ 3h?zR\ӳ 8e^5oUŦ1^M=Z f\b&; @oy%ᩥAe!z@ <'C@#L,= \wt]f|Lc̝Cg,π̏U1:~O]1wkrcL Aey:z.ѡxd7E¡m뎥yz1}j4M]H˳_f|t'z$$DfS. Qd2]GleIE4_Mi DO zm${VdX7 ;cWo(z~p?wwIiZё҄"UED|T+Hk7/ e*Il? bK$ nDָ֫ ^=5.-gD Q#b]=yyE|$}O|$¸;{! ̨]ޠCǯ_`UקW;x{0"Cp#q+i&˫i]֜'מHdL Q+bBޭ'g@HCz]q=R5}Heeyqr,T$%y>QIً\B־ras4,2Heƌ@:UČoWŝ ZT29dtEK|TQ UǡRpeRWb'@|_D $K*uzbv42H8񫤇<:f"Ԋh)Z뷲C89$'3SjHt luJ@{ٮ+酡u ֜hͣKG_- ]A!=Pe[f[5d]uZ@ 3Hw# z} _Hh 3(dpk^Y &,wh5+;]}.ҏL# d}"@YY+羅׿3?ARh%A HtZőu9cwv gd4yJ,4z=CM/AuoD׹P@',<_҃tg H^ɑWW lBnqafB?BiU@WټM. y=U$Hd+^ J'Sg# =4coՉ3XњM>9FCuz t߿q@'q wU *'ģkFenͣ7^+ }wX/AZzX4@ڭy 2.$l@+d^NhdՔU(La !ذM)^7enC2pjy@ߘpϷ! %G5w@]_. 쫸(@|d^՚]|/8H4{eϊY Ě!\r9\! @=  @ uV@  @, @`0 ` 0 @`0 @`0 `@;[qa)C / 02Pb®Ī}PbRxUd @`0kЁ *x @` #}nLN )ߚI!}*@pvtwt/{:ZI] M88xv;@vdYʓj[: 88AD:dkC_2 .jTѮ"rFeN l*iӮRYY8)RTYQaR^.IDATQyUCs.Nf 2 ' _csƮ02 '$Kl7*V3rx2/pR`^dOJp/9vCvw^آ{pleևkDpR` ֮O7',ޭF'x@vE6ڋ= Y8) 9D8%CW/^ !(pR`c#Rzo{9OYz]I- 2KC2 ':9^XlwY8)W HYffٞ{eN RYiJ$}XI^@ʫĮz߷,+业ߋin>7#~@77X|EF v^QԂJbqw( bȶJA{J[=݃:@SAAbؙ ydi4zAAvA ]Aq#{ s#P1Ժ7RR*b5e"L!bp+}Qѥ "kgO'?^woN~ @ǾOSpS~ "D޽x8j:!wcRK<xəU- ͟fRM*FNU+]!肮t'@S&g~m$O|h:'jzWrjJgCr_ϰԚ$ZfkUMnF]Ŋ9׌%B-c߅a%^ǜЁtK]b)Z|avA6TݑgGATrO,x>(u:+.:p5Dۡ#ѽ\ݻs.c:Pʵ ws@n:VE Cl`bW~rU  2|3k_in3+_49i-e4 iXVt+]!芛CSʥt>9=׸ c3\X=\UOM[ tsйQU&$}ou ,^pq92Tbr=J !RR2<VnR+@%0$a襞yJu:3Y \L#i60{wKCgiz!XYF8WН=CS/3ra\V)6}E.{GI;g4ra&j>UuGm)2aM×>^69T9Vt+]!3V>rJ]+tTЕ RAW*J]+t)t BxWzK^~'pH՛I?.t[ _et0f]R|+ͼKwp2)Csz0^:(2Xu_/}Vh3}dz6EIH?CW tScuLM@w.O}A=H Չ:g:d+NҝWl\:V8TF+s;8<Ǒ[JF+3Uu-?{:ܮ2>1Y5%Kt2c+frf$ho{d[:@otO&r 9s5-*՟Sbo7A>5)%aShiU! AWB-ƚBF25S$ʬ݌1u-;Gö|e~{C%OggV o99_`ZA^u̳RKVMrD׍X*BˉN~ԓ/zKӚ:tc*XntZvRmEnzb5x:З}{t; %LQ^ S{=}]fxKB{q+̊'|kUS7.BK AWBtſ$əR  #OF/᭄g5Plɏ.."MK']2ؤZO%98SSҍze3RT#7(X+ڦ&NmGZO+jκa##/;~L)AfۄT5BBܥr@yj d#B?iqU̍iCh}o2]A_>:O/~<=n&諮S}详oK5=ȅW~aZ nWc[] amSo=d[)iM! AWBxDbM8}xSk9QU 9nKy U`/R.v[kULf,.KU"֔VmCvf1eZ trZkx9tQmuSzCtǏk+:9@Dp=izQɨnyd뜩Mk-nm-j]rOPQZ.W:V/TA\_7j^pk:h9ӺY.AX5D|0RgYAfeG~zu"j >g:٩W:{aVٴʦt+]! AW< Ne>rt.c9əڌ[>9tR#G|raK})xťf|*5U}vnWTfk٬+[7f  V ~>EriB_n4oAxC9`-F5 M.r;-^p^X1tP-_ց{MAߤ[ZWQ!-jޝ֒'&;|Bjv==pƠ' ZlJ<Wiy WlZeSBt+]h p gJlg=ǹ YqBzcz0)_D8xq%<.X ȍ;9:wSR@ @쭡2bV9:BIVJDu Xu:\ΫPL{{Q2C4{i'ZőB匧 ;$uM2pÎutT.ߪ8Щ2**Bݻ7HG8%A&H\G5dA_r9kspNEMY36^WFt0׹okR=sUϘ>D7~Yxy*tUt3=)0jlӰHQ9Vt+]!芵JȂ.䣡}nZ*wCF~pg㲯HڵD|BgD9:(+$ƫu!L Jaۻ@^Q3*.\Tb-t+jm-e\Y?zcr=*7o>{n^y-{Eбz1m⴫nėYQ=9]sa. AWBt+]! AWBt+jTÕWIENDB`openttd-1.5.3/media/extra_grf/fix_graphics.nfo0000644000000000000000000005016112627373446020126 0ustar rootroot// // $Id: fix_graphics.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Fix bugs in the original graphics. By Addi and PaulC." // Non-toyland specific -1 * 6 07 83 01 \7= 03 3D // Fix missing wheels on the wood trucks -1 * 14 0A 04 01 87 0C 01 89 0C 01 07 0E 01 09 0E -1 sprites/fix_graphics.png 8bpp 82 8 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 114 8 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 146 8 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 178 8 22 16 -14 -7 normal // Show correct graphics for various 3rd generation trucks -1 * 5 0A 01 28 C4 0D -1 sprites/fix_graphics.png 8bpp 226 8 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 242 8 20 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 274 8 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 322 8 20 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 354 8 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 370 8 20 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 402 8 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 450 8 20 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 482 8 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 498 8 20 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 530 8 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 578 8 20 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 610 8 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 626 8 20 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 658 8 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 706 8 20 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 738 8 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 754 8 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 2 40 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 50 40 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 82 40 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 98 40 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 130 40 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 178 40 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 210 40 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 226 40 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 258 40 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 306 40 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 338 40 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 354 40 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 386 40 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 434 40 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 466 40 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 482 40 20 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 514 40 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 562 40 20 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 594 40 8 18 -3 -10 normal -1 sprites/fix_graphics.png 8bpp 610 40 20 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 642 40 28 12 -14 -6 normal -1 sprites/fix_graphics.png 8bpp 690 40 20 16 -6 -7 normal // Fix clipping on the 2nd generation paper truck -1 * 14 0A 04 01 9D 0C 01 9F 0C 01 A1 0C 01 A3 0C -1 sprites/fix_graphics.png 8bpp 738 40 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 770 40 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 2 72 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 34 72 22 16 -6 -7 normal // Fix clipping on the 1st generation paper truck -1 * 14 0A 04 01 5D 0D 01 5F 0D 01 61 0D 01 63 0D -1 sprites/fix_graphics.png 8bpp 82 72 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 114 72 22 17 -5 -7 normal -1 sprites/fix_graphics.png 8bpp 146 72 22 17 -14 -8 normal -1 sprites/fix_graphics.png 8bpp 178 72 22 16 -6 -7 normal // Fix clipping on the 3rd generation paper truck -1 * 14 0A 04 01 1D 0E 01 1F 0E 01 21 0E 01 23 0E -1 sprites/fix_graphics.png 8bpp 226 72 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 258 72 22 16 -6 -7 normal -1 sprites/fix_graphics.png 8bpp 290 72 22 16 -14 -7 normal -1 sprites/fix_graphics.png 8bpp 322 72 22 16 -6 -7 normal // Fix clipping on the toyland toy van in the German DOS graphics -1 * 6 07 83 01 \7! 03 02 -1 * 5 0A 01 01 5D 0C -1 sprites/fix_graphics.png 8bpp 18 296 20 16 -14 -7 normal // Non-toyland specific -1 * 6 07 83 01 \7= 03 08 // Fix offsets for the monorail bridge heads -1 * 8 0A 02 01 EA 10 02 EC 10 -1 sprites/fix_graphics.png 8bpp 370 72 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 434 72 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 498 72 49 21 -24 3 normal // Fix offsets for the maglev bridge heads -1 * 8 0A 02 01 12 11 02 14 11 -1 sprites/fix_graphics.png 8bpp 322 486 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 386 486 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 450 486 49 21 -24 3 normal // Toyland specific -1 * 6 07 83 01 \7! 03 0F // Fix offsets for the toyland monorail bridge heads -1 * 8 0A 02 01 EA 10 02 EC 10 -1 sprites/fix_graphics.png 8bpp 610 630 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 674 630 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 738 630 49 21 -24 3 normal // Fix offsets for the toyland maglev bridge heads -1 * 8 0A 02 01 12 11 02 14 11 -1 sprites/fix_graphics.png 8bpp 18 678 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 82 678 48 35 -23 -7 normal -1 sprites/fix_graphics.png 8bpp 146 678 49 21 -24 3 normal // Fix colours for toyland maglev junction overlays -1 * 5 0A 01 06 91 04 -1 sprites/fix_graphics.png 8bpp 338 630 30 16 -14 8 normal -1 sprites/fix_graphics.png 8bpp 386 630 30 16 -14 8 normal -1 sprites/fix_graphics.png 8bpp 434 630 40 7 -19 4 normal -1 sprites/fix_graphics.png 8bpp 482 630 40 7 -19 20 normal -1 sprites/fix_graphics.png 8bpp 530 630 12 19 11 6 normal -1 sprites/fix_graphics.png 8bpp 562 630 12 19 -21 6 normal // Fix transparency of cinema -1 * 5 0A 01 02 34 11 -1 sprites/fix_graphics.png 8bpp 578 72 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 658 72 50 47 -28 -20 normal // Fix misaligned undergrounds for temperate monorail -1 * 6 07 83 01 \7! 00 06 -1 * 5 0A 01 05 4C 04 -1 sprites/fix_graphics.png 8bpp 2 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 162 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 242 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 322 136 64 31 -31 0 normal // Fix misaligned undergrounds for arctic monorail -1 * 6 07 83 01 \7! 01 06 -1 * 5 0A 01 05 4C 04 -1 sprites/fix_graphics.png 8bpp 434 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 514 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 594 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 674 136 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 184 64 31 -31 0 normal // Fix misaligned undergrounds for tropical/desert monorail/maglev -1 * 6 07 83 01 \7! 02 10 -1 * 11 0A 03 05 4C 04 05 66 04 05 B8 04 -1 sprites/fix_graphics.png 8bpp 114 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 194 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 274 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 354 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 434 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 514 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 594 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 674 184 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 232 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 232 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 162 232 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 242 232 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 322 232 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 402 232 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 482 232 64 31 -31 0 normal // Fix misaligned X crossing for snow-covered monorail -1 * 6 07 83 01 \7! 01 02 -1 * 5 0A 01 01 65 04 -1 sprites/fix_graphics.png 8bpp 594 232 64 31 -31 0 normal // Fix offsets for the tropical house -1 * 5 0A 01 01 FF 11 -1 sprites/fix_graphics.png 8bpp 706 232 64 47 -31 -16 normal // Graphics metadata pixel higher than actual graphics -1 * 6 12 01 00 01 AC E2 -1 sprites/fix_graphics.png 8bpp 66 296 9 10 0 0 normal // Non-toyland specific -1 * 6 07 83 01 \7= 03 0A // Fix offsets for the tubular bridge pillars -1 * 5 0A 01 04 05 0A -1 sprites/fix_graphics.png 8bpp 98 296 4 9 2 -1 normal -1 sprites/fix_graphics.png 8bpp 114 296 4 9 2 -1 normal -1 sprites/fix_graphics.png 8bpp 130 296 4 9 -4 0 normal -1 sprites/fix_graphics.png 8bpp 146 296 4 9 -4 0 normal // Fix offsets for the cantilever bridge pillars -1 * 5 0A 01 04 DD 09 -1 sprites/fix_graphics.png 8bpp 178 296 10 11 2 -3 normal -1 sprites/fix_graphics.png 8bpp 194 296 10 12 2 -2 normal -1 sprites/fix_graphics.png 8bpp 210 296 10 11 -10 -1 normal -1 sprites/fix_graphics.png 8bpp 226 296 10 11 -10 -1 normal // Toyland specific -1 * 6 07 83 01 \7! 03 0A // Fix offsets for the toyland tubular bridge pillars -1 * 5 0A 01 04 05 0A -1 sprites/fix_graphics.png 8bpp 248 296 4 9 2 -1 normal -1 sprites/fix_graphics.png 8bpp 264 296 4 9 2 -1 normal -1 sprites/fix_graphics.png 8bpp 280 296 4 9 -4 0 normal -1 sprites/fix_graphics.png 8bpp 296 296 4 9 -4 0 normal // Fix offsets for the toyland cantilever bridge pillars -1 * 5 0A 01 04 DD 09 -1 sprites/fix_graphics.png 8bpp 328 296 10 11 2 -3 normal -1 sprites/fix_graphics.png 8bpp 344 296 10 12 2 -2 normal -1 sprites/fix_graphics.png 8bpp 360 296 10 11 -10 -1 normal -1 sprites/fix_graphics.png 8bpp 376 296 10 11 -10 -1 normal // Wrong, non-translated colours in tubular bridge in 'normal' climates // Toyland has separate sprites which are not colour translated, thus // this does not apply there; // Pillars are changed for all climates further up -1 * 6 07 83 01 \7= 03 \b22 // Main tubular bridge sprites -1 * 5 0A 01 \b6 \w2559 -1 sprites/fix_graphics.png 8bpp 2 330 32 40 -30 -26 normal -1 sprites/fix_graphics.png 8bpp 52 330 44 50 -42 -26 normal -1 sprites/fix_graphics.png 8bpp 116 330 46 45 -42 -21 normal -1 sprites/fix_graphics.png 8bpp 180 330 46 45 -2 -20 normal -1 sprites/fix_graphics.png 8bpp 244 330 44 50 0 -25 normal -1 sprites/fix_graphics.png 8bpp 308 330 32 41 0 -25 normal // start rail bridge -1 * 5 0A 01 01 \w2569 -1 sprites/fix_graphics.png 8bpp 350 330 52 29 -25 -4 normal // start rail + road bridge -1 * 5 0A 01 02 \w2574 -1 sprites/fix_graphics.png 8bpp 420 330 50 29 -25 -4 normal -1 sprites/fix_graphics.png 8bpp 489 330 52 29 -25 -4 normal // start road + monorail bridge -1 * 5 0A 01 02 \w2580 -1 sprites/fix_graphics.png 8bpp 559 330 50 29 -25 -4 normal -1 sprites/fix_graphics.png 8bpp 629 330 52 29 -25 -4 normal // start monrail + maglev bridge -1 * 5 0A 01 02 \w2586 -1 sprites/fix_graphics.png 8bpp 699 330 50 29 -25 -4 normal -1 sprites/fix_graphics.png 8bpp 489 283 52 29 -25 -4 normal // start maglev bridge -1 * 5 0A 01 01 \w2592 -1 sprites/fix_graphics.png 8bpp 559 283 50 29 -25 -4 normal // GUI sprite -1 * 5 0A 01 01 \w2600 -1 sprites/fix_graphics.png 8bpp 433 298 40 15 0 5 normal // Remove road markings from tropical rail crossings -1 * 6 07 83 01 \7! 02 19 -1 * 14 0A 04 04 5A 05 08 62 05 08 6E 05 04 7A 05 -1 sprites/fix_graphics.png 8bpp 2 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 162 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 242 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 322 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 402 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 482 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 562 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 642 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 722 390 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 162 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 242 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 322 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 402 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 482 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 562 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 642 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 722 438 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 486 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 486 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 162 486 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 242 486 64 31 -31 0 normal // Fix transparency of steel mill -1 * 5 0A 01 06 46 08 -1 sprites/fix_graphics.png 8bpp 162 870 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 242 870 64 51 -31 -21 normal -1 sprites/fix_graphics.png 8bpp 322 870 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 402 870 49 58 -29 -29 normal -1 sprites/fix_graphics.png 8bpp 466 870 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 546 870 45 42 -18 -12 normal -1 * 5 0A 01 0A 4D 08 -1 sprites/fix_graphics.png 8bpp 610 486 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 690 486 59 61 -31 -33 normal -1 sprites/fix_graphics.png 8bpp 2 566 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 566 51 50 -25 -21 normal -1 sprites/fix_graphics.png 8bpp 606 870 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 686 870 64 46 -31 -16 normal -1 sprites/fix_graphics.png 8bpp 2 945 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 945 50 51 -29 -21 normal -1 sprites/fix_graphics.png 8bpp 146 945 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 226 945 47 42 -18 -12 normal -1 * 5 0A 01 04 58 08 -1 sprites/fix_graphics.png 8bpp 162 566 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 242 566 59 52 -31 -24 normal -1 sprites/fix_graphics.png 8bpp 306 566 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 386 566 51 44 -25 -15 normal // Fix transparency of oil well -1 * 5 0A 01 07 7D 08 -1 sprites/fix_graphics.png 8bpp 2 630 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 482 566 31 50 -11 -28 normal -1 sprites/fix_graphics.png 8bpp 530 566 31 47 -11 -25 normal -1 sprites/fix_graphics.png 8bpp 578 566 31 47 -11 -25 normal -1 sprites/fix_graphics.png 8bpp 626 566 31 47 -11 -25 normal -1 sprites/fix_graphics.png 8bpp 674 566 31 49 -11 -27 normal -1 sprites/fix_graphics.png 8bpp 722 566 31 52 -11 -30 normal -1 * 6 07 83 01 \7! 01 02 -1 * 5 0A 01 01 7D 08 -1 sprites/fix_graphics.png 8bpp 114 630 64 31 -31 0 normal -1 * 6 07 83 01 \7! 02 02 -1 * 5 0A 01 01 7D 08 -1 sprites/fix_graphics.png 8bpp 226 630 64 31 -31 0 normal // Fix city airport's grass for temperate -1 * 6 07 83 01 \7! 00 0A -1 * 5 0A 01 09 4C 0A -1 sprites/fix_graphics.png 8bpp 242 678 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 322 678 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 402 678 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 482 678 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 562 678 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 642 678 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 722 678 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 726 64 31 -31 0 normal // Fix city airport's grass for arctic -1 * 6 07 83 01 \7! 01 0A -1 * 5 0A 01 09 4C 0A -1 sprites/fix_graphics.png 8bpp 194 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 274 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 354 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 434 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 514 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 594 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 674 726 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 774 64 31 -31 0 normal // Fix city airport's grass for tropical -1 * 6 07 83 01 \7! 02 0A -1 * 5 0A 01 09 4C 0A -1 sprites/fix_graphics.png 8bpp 194 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 274 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 354 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 434 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 514 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 594 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 674 774 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 822 64 31 -31 0 normal // Fix city airport's grass for toyland -1 * 6 07 83 01 \7! 03 0A -1 * 5 0A 01 09 4C 0A -1 sprites/fix_graphics.png 8bpp 194 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 274 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 354 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 434 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 514 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 594 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 674 822 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 2 870 64 31 -31 0 normal -1 sprites/fix_graphics.png 8bpp 82 870 64 31 -31 0 normal // Wrong, non-translated colours in arctic buildings -1 * 8 0A 02 01 1F 06 01 DB 11 -1 sprites/fix_graphics.png 8bpp 305 945 59 29 -29 -12 normal -1 sprites/fix_graphics.png 8bpp 369 945 59 29 -29 -12 normal -1 * 8 0A 02 01 76 11 01 E6 11 -1 sprites/fix_graphics.png 8bpp 449 945 64 69 -31 -38 normal -1 sprites/fix_graphics.png 8bpp 529 945 64 69 -31 -38 normal -1 * 8 0A 02 02 7E 11 01 E1 11 -1 sprites/fix_graphics.png 8bpp 625 945 54 75 -25 -47 normal -1 sprites/fix_graphics.png 8bpp 2 1037 54 75 -25 -47 normal -1 sprites/fix_graphics.png 8bpp 66 1037 54 75 -25 -47 normal // Fix buoy in-game; don't show black outline -1 * 4 01 05 01 \b1 -1 sprites/fix_graphics.png 8bpp 575 490 7 11 7 4 normal -1 * 7 02 05 17 01 00 00 00 -1 * 7 03 05 01 08 00 17 00 openttd-1.5.3/media/extra_grf/roadstops.png0000644000000000000000000000507512627373446017504 0ustar rootrootPNG  IHDR 0ސ\sRGBPLTE 000@@@PPPdddttt4 D"@H_dN-۷_YSXk_ʤbjֶ۟-1|=HC%SM *|y("VVs>PX}{0 veFh]z pNɐL55@xT=X) b(w2s(ƎR*_\OW"u 9wBlT반E)@@W|GR"sdr_ LO]C?XJ ơ$!M@+xåɷ9 Rf/]W;ki@2!NyDPdw9l R̤7q#-3L_L;U9"(]6 v3=Cz M <sDZ/DȂ~@lzp.D; M<a?k {Ds@$E@lzH:= %DbmH; o/ uz"CC)|Ia :EHa 4ijKHʉL51@ x m bȈ, @LIvkEfpC2 }?qhb-v|Br8|Pid> g{ϡ\q۝C\U[Inq>=zYVmH;*] d F vY m ժ'{|\c"3Kخ`z# GK\:==!frb%> iv4[ d={Z5B '>XIG@jKwXBffOb&? c[fOPk!@>!vhX:ZIхB|@$lҝK? PD|/4y@H$D"@H$D"@H$D"@H$D" $B" $B" $B"}qTƭIENDB`openttd-1.5.3/media/extra_grf/fix_graphics.png0000644000000000000000000023060212627373446020130 0ustar rootrootPNG  IHDR 4oޗsRGBPLTE 000@@@PPPdddttt4Pl@hB?/Ћ9B1o8z?t EDXGD\%!lGT b}T~ӌf3 џRg*gBZ ,D A EOE Hi-D6y TJ iR:!mC$5KeR#@xc"l?ZxBLӉ#|pKK/} k[X6IgRhBy& NpԬ^0z?RT)wPYRb,e94OY{#_-J]*Q\~iWpz֪!틕Z[%_h)Wjl YW5F~FZqVGxgz2pp_h}u"I?hPꅈpU S ߪ饇UHiWj u8:~C˪$ @oݾ~d3z}Q1%IeP5WNO_l_y }? NMO^È8 |0Q=a)hiA5l4݈!I:qj־uh !  Q4_bY-OR? ꁳH~WSpe7oBq8dgrS g` V>GEC->jg{uw9 z,V,^Ai3KYkFj.߯o>mɭVlrbFgF}Mz5@0EMbGWDY>ę0_y$,WoND&R^āTݟ?=}aZh!OO~+ ɏn?+fk#B~Ij!fq=b֋!d#L~ˊy1~T޹rg 0}]nxz}[^7LChA| ꞽO`n$|cXՇקADCR< Z-/}`oŢ;{k>RF/KJCkx#|"KVblb7)Ak'wO8cVnuއ it+y>0 YUTxxSzy@Dㆢ4oovߐ,P46 ]! 8 7 ~.B|8}/Xzgﺬìp W5B~2Ǻ> J!"> |8>Q}=pe*:JqE [ 6:GL{/<>\Ŋ-ICM{.x*Tϓ~`' ;}hH\w]]4u^FlD$A~!%X7!@~F'UIu[~I. JC{~UQ f;\a[v1 cB'j=AFՏAdɞrX\zfF Q"F!D~!"pr/rx}cnqhlAĒ=bQW4(`H,4'#j"ADVO寱[ X䯱E} {x߲b`=A ].&ؓ=^b SUz0qY| x94Cњ8٬^z.^--:1RfcW>=&s+-VŪ3!׼1z"! $b`oD)(xDpf+(ZXW5J~Bq}GQ /Bk`$b*cHJ֣UTLgJWn6/^y-ȫW/WƱq6~Vx⮿:}oS@t\ >Apx(К絢X.*JADWep٨r'xܨ)oVW*gzeCAuCPJ/( .p~E)qZV K>Ă"DdlO뙻kKAѽ*O8*X隬Svgx]X=ApWo<R_*7pmvoB,x֎T}gG孂3Ey#<߉j%} bXxxW{TwRT@%UM-RH&?ZzR#B~ˆ "Z]ł,C_?6z}45 /Vop8u+8j^@! ih5HEQP\?!>[%׎ EoAqlz -g;1̷5Z1_!QH@1dZ$-q^\/p.,8lX%[XäS?_E_F"c#vry! 7޼92 Vo4;Cm=iY4sQHU4V"&D^$@p^Y.^`/%aqRZtUqédG -1O=/}Ea zg|{\5X$= <0qQzzz+|fŌ4qax\XO t,V>U鄁K,û삲HYR,e)R)KYJ,?͟,Dq?snE_ I<󛤥!IP>vGAw0BXOo~7XB?F]_t!C~3h?=!·!D^!!%S+_!e~FȖ">D-:,4hD/ĥGHyO?/nh˟,kEK)Sa\h?q1;r`7@v gL>gᦗ6D:Do#z6B[Plf` rI8Cu d<@H@6ʟ e:"_|֧w^\8 ,DjX,DH|B@>`nAFh܂'ɿl$`6ӓcX1>+C+ @n`>@6? w_+vZ .R˂ 9R\A0b>$!7׿f| 7f|& >)SD@NץC9'œ/Db}0 - ,9QO=vYWD`z)^#⼿~Y|Ȣsx>1 n[:'dv;J~*Cy C 7á\A|ɿ ,~"IL;W<ދ'ne͂ߟtKG&?i@k+ǎҫ:{=toAzy+H_,m>yA:q| T#'C,p?J~h腈˂@hnAh[>f_-0L~*! zDl\Axq߻ Q`ݾ񢸓d[WEs].IJ'^rl]#.UpTr~~F䃸uٴnj?#ۅA:>Ϯ Q!@q QdG9SA[[uA dTޮ< F#r7gT> aQƾ P1铟cB39$7cg" \aˆ#cZ?(/ODN,#w 8ai9N\@6B1ʬHp;тfHڸfgA-1_ϔiI|*gP ]ŽJAiKV <4*=T@@{F#&RRO$!DV'>=#|TQMXźE _1> ɏm3D~P/Dbz.]|(2.??/N LP[_~j#K'',4 y";3? Xi{^mHًA;L4;d:A+ӗσ z`k)ZFl& ÛKO>(ڿ9b?7#pAb$?g^ _ߺSpoFL?E~F! >h,' ҟܔcQs`n| hA<'x!qe-/`-.C@,-'Pd'4߁w rJ?ռJUo"G&ofeH1o `~}1x0#'qz=9F!- ,"/(1{rL8%(QEr[cǨ'y|@ p_C 0Y\KR5z>~ϟ#20L ¸ | 0ׁC}I1Pì&jB ?/ނt{Nmv"(_b̊BAdR6A??F+21Z^̇K'NC_,Њci9W`'nO@z>ؗ#24w0̐| k0j%2kn!y;b1z/oi=ٓ"KA:e!Sh*"1%1$0H:+ 21XZ",/ `+4 oy 6Mi=MÊNvPF|$<͋Ju7.-oeʢsZ>vi:_."Ldn p,*zy|(n۾9t+2!Q?]@|69#"l3a !:ލ:R÷IAJ~p‹xR|.+(sRy_d謝f*)Z>\ $D! 8fBKHXe11_/^ z /%~ z@bd0jH`F$ A1aA:nwrʈqVk7_b /5 |6gEe/U.-?G_~/E Av={ܥ-?*HYruJ HYR,e)R)KYJ,?X~"/KoOS?1 /r&J}o0ES?/ؓ=>g4~Zϻ_RABNB-//,SI qZ,~]qg=wj:5OeA?BL{BWepDi&IdArȔc0G~s$fxJQr`6M^R*VYR,eI=)G<~ ) U*o@*yIdˢ(4 ?I}?"_G:~.LS3 #$9"R@Z-Ѹp7\;NLgN !2 ?A#@G 4g!]%/@ZFCU!rqnv$`>֍| pxdS 9ב 04  B"<@DQ}%@@@nZ4} dtr yUHq  ?kACud'CmRv Dm5UM8miaLJVpxH5In6u@<7`}$aN>[BV2aj_P c ԓ(P !FBBQ7͆idI(`B͊Qƞ CJXjj5@Zyo:+o `Z >F|_~kYh#ud' |tPQ 5N-Ute!d?@ V% CfF&$J 1\>_.t݀_ 6Gv/ҕ1oS[_~*l?}Ǜ$(?Z?'ĽB|P(Mj`D"] D3J+a>".(zSIJ W xD ^x~FݓN1 ǰX| SoyY@~$'? !A"^ZCf]MS.|Δ":Nx ⯏9 &ÁQ@B@:RDLP\5۷oo6!D /_\:1S>(?qmAX>ԩ( _zz v<'"?D@ 'GQ}N!V(4R.CIܬ.C~ (- H!*$P$YCex8+ZgnA^:.^@+(E&)FI1N-^< fv^Z]D,QPWzh&WRhZ[KöoћY]] qP"DtDѴ-l驂t1yQaUq5O} ,WN> ;(H)$^ >V+LfsC[?!Wpk,!):Ez"}BI.7 f?س@&,.ZUU+Yj+`܄o@rL ro0G` W> +‹Wc {1F_ ?o'(߇+I!zWx5 B:g^fE? $:-`Dbn^ NãF,yboJ .,d4aq69uf| bi3L,W*rO31?Cdp(̽`LP4ﵮ@袣eZn֯h0!Fw;oꖙ#HN`; Z^!(K] &g .`p5B+:ի W n"Ď ̑!ax^q "+)RHdAA IDAT{s%+5EYm\5|Žzub &3 nu;]'Q>nV" wU Sc` =hWfE͖X+DhEG;(fuFBD{jo!]FS)reB76 Sy?j&c?DQPpz%@2@ъ2Fz}B.[/ԺW%tIM 8\'|4D6(4)Կ5<^,A8?ZuW?C-ROea9HkjuZQVbdpC],ČUnm݁T*'aC!KG\C(RO ^` lTjzBj,e8Zxu~!YU|蔥, D bIN!)'"V*HY>m0NzCnHYJг [jӔ) hEʲ )KY. \.(KYJ,%@R e)K HYR,e)R)KY>E^}|Xz(`/{b 套C U@g3":7,UQpoڱ-xFPNO B&x RH "U3`z-b-P  'ԏ+~¿cBЂ'ȋAR)KY{n/޽]jգW(@hL#s>|2^wU&-vv@N&}?r vvLv>1^vw4mKR4f{]=`Myo_$=P{y)ߘξ5wl|Ƀ,}J/+@p6wS5UOiױ`V7X֎= `f?ߞ<|t(D G)x W&a_vz㵹ls#-\S-?ڣ흝G77 n ^Mxp΃8 I ]fսv{`]</Y棟bE\ȲNl]'%Գ뱅p6:xX㊳қ#r- AC}vJYݿ?y ^壗 ;xvUۚj tKc[6^r-c>hh<|p8zLV&:he ɽ{Qvz^,/^Z hG{Xl<Ҁ-`+'@::kPP'%V$Z =ǹWzh=,VFMgK' h$YSp9joA84EJQ6ŏW.3u-mMC:Q%E^tXc3!=:zxJsX-ÒtM[ܚ>nWvx%7~Hw ±7l߿fL $&qIv{]񅺴VlD}\?߿?6J7W薈_^g&lvQ%/ @{z)3j6a~Oh;X_0=qQ #mA-b1㕀G޸Qлk<|!`hÅ8w?ߛ%8;YM0V@-sd]۶tɛQc'NI"=RؔE҃r"̤-A3q_\DSwVBhR^|dς{`椗=[:㵹iB4Ӄ5!p/ ѭ;^/w@˸m_C^Wf;uV 5/܇CϡRO 4ݙ:U8?x>0w\++Uwz~y6=o|~ $% 1I0^nnZjk:'vxiެf;x>^O0giY hg}ރ3Lh 0G qݖ̊vG7bge#O:Y$! :L_muf`k %LǎNf$6҂Gk3'(K1{2<ڮk/D`ncm,-|*\,ͤ㕌[ޠɶ6q}t6G6S>]`q7 `nz#2]ӎͨζгu[ @ u:%Iת½)no*p농fnchC<9,æotegvg0~24"-ubާ08v+)=;,ĕ]zHCv^z74g,תBhj? NV$-ޞۈgO2&rYLs{c4b"zzuS>梧۱C?IO;^h!B;v{+iloO2c1Ÿqj3?AvLr۷ <?v,@_|}+2Ғ}ڛ㶮KOrǮc9ٓH':->XBi!f{̞>4RQH>fo2?AO=^x`JT=^O+:nhI,tZ |k Y!Ƈ&45ߣ#Zvr+?ڥeg݃{.,Ϥ<|:y3^G:lj;3Xվ&-x8H[- ω=&ѰΚ,,$wv"ƫPhlZ[\ mI^=Vla* J-)C{`-g++b7z^ސB'@f^zE L)EKqXa~rɓ'+SIbW ]ͅE!";{vvQ7ŞZsY)ioo_͊cJ}{=7\,S*.NogK.n^6Eߞ^;;@R)KYJ,%@R e)K HYR,e)R)KYی/)?,}+~.5H(p(+zWlD8,f3 pVBW<=-H.O "|,T]h.Ԧ FJ(Z l?Lp>m ӻ21HYR e)Kf|؊6LE>qVGovt4Z {lg~Eu`I/|ϊ7g=H ^@1lo"od ?Et ̦[[ | g7KowQ &g{y{,?`90\^QxWc']Ѱd|@M8n^S|7X 'LOLK@ = >нBɦhZI#[ސű2 䥗?txhgw?i"p?5Df4=2GC Hzz3Qvv:6ɏ1fxsH]umOLd :Jl+Hg{cu4ݺ`"[ܝNOwb#Oސy.5MF/13cn?d<_a"H10x̍z?dj;M=k+(n~6f 8}`O I» K4ƿ9G LA3h Hz~y҅y4Fxz#.Kr3GXj~N12G+ QH6f/;?UMk1zMKHk+4q1Wf 1:q13{G Ny|=Eq7gG=slXxD˸*]g$kʶ[i6yV*kګ'0m&YuxP':tkG$LM]P)#X^Ouɓ)wU /NdxbVI}YxT"zTQ)~DⲮȮY;/dH3 >LgʚpMb$[КBhD$Rwoﹻ?u/Y`F}zdzg - Pb^g|gϊ;mZ]lmئ̽}']SF]#⚴<w vzd̵˝?u/~?A)N_ CL`8r]Nˮ)"g?1z(!W)q`%;|! ~q,^V pHg- P]n1Mx 3;1!TonfKï֍fSIq9{v٥:Ċӓ%&$*?Iėrz3X,g t3ؑ%?r.zM!;GK "_1#۹rcoрBRj\]LyĴR4=U/?"8=_Hz o~便7;HPLu,֐1 K6{5)iM T1;w޽ᆪkVq`ŦSz4p@pCRĕqsIXI3 EӳB&~vӵ8ZG(!LCo]3F,V4!7k-)qb|Nt1j0N@8Y ffK7ޛޣ:(Ҩ7\AДP,2op֞aYRzH~6۫2Qf1o W{%ij̵Pҳ1 boKOvL_^k( iDi:Wn#< >d,-̴AhȀBdlZ ]W8W<1pם.ɀ$5ٱ_N,ׇ3(G_, =tSmc ,|*ȵ0 m|}|~=?{ZXo&g ˱ 7\NbBm醚\ef<TU-0"7PXbEtBǻkf⢷ɿBo@DAXk:ke?;ヲ$y@$q U-@X̞f Gg*@DZ-oQL|wl=lokZqP R[d8`?M٦~TŚ+q /<\hRon+b"O'"-'w{ɣ:A٠Uw&,dׁK:mB,#fY؀$GFw4ި˲57AbAѮ>0r;8j "kujn@3? Gxz=sփ+7Rz\^X_baf wxXгM xrI_P~;""\5늤}ֵ»\? _q(?z1!}2JPg dyFu]=0 :I-uJ *fgaSIսTEin<{zth$̊xbWZSGHClJ9W8:z'׏P[gɫ@J֚|Sb8|HOqB ,&} x}S#Ohi <*[&[ҏA'H "<>v=46}Ρlȟ#x ަhv(jn7A#J{s0KI&swal1 pv!%n+BȳCףLGapveq"PA?o$z3kö|zFG W,c?0P,>_\aփxsc\Ψ:6=r͈3-6V&=8ZO!v =A>;8<<E5;2}h{],'⯩>Cas%Ou)}ۋ/[gלu5XlswEvohTu9$أhyb3N聺ч\#=MQq3V$))-3]O~vKsӠXDQzbz3W|I%6t2+1=e8S{Oӎd2kV0KX&`aMݰ ]kt"qC w !D4/\G@9cvTǥnӲ~zdD:toOv.b)O߲vGف17X#E9m,lN;{pJӷ}{3#g6)={AXrfN5*7wkٱHQajdb]|ya7W͊ӣ3Unj<f#Yym\64:O&St@, wY{5 ?}[ݲYлeT(=Z+.ݢ+|<  i4th:}4m"@Xt!W[ $^9ݕz^GE5V%rtyW*WjѲֽbRx@,L:>[Õl x1ȻBAQs#)7+,W 1AAg:|TZhMC'4OjV,W r0 V_r%@ !‚5Jiтd2%@I "$ E*1BmL'SGk:NHY @"JnUƳx)'  "(RK.OPA㬧K|Ba-|_sBD4ُחtL5 94MEH]^ DZ<ϟḋ-| S eD(p) e)K HY.O,!ԄkLRwC \l  V@$ |) 2#!Kg` y*b]oC %@FLƇP,?AKq#2=@~)~l AB)C>霢+BZ~8*,-=DI5>%\ۂ[o suIN ]RhA!6,{`jtL.|/ !J2`8VdoO)Wr`#3@؃E2f{  KBc"b<@0SSsd*A,)+rr'%(?D3U֭׿uW>>\Wb]ejTh 4a'r:]-(VB޿3:`Opw7R[:}Wo>+s{CcRw<],DRv,xE>(by@$jA] 0`F זwy^quנ. r= i] -1 ba1XD7u ćp^q(C;;  o~[Ay7:%@(Q{4c\VXDHÿ/rL#W/HEh絿 {ـc mo#ol@| X~:5@F= k{"r@,r5w_E>˂;B>םgcAnAHq@BV,D =EAUf]yf=b b `  !X-o?_@T{a;先\=x~Q|3b! źXD?`bn!B@CpK~ # r(܂T|gC Gi^wb{DzRU>ďX8@PW`:):Wn9\-ש-H1!+CGA(/rcB\Uze /胲mC˾=eZV,1H-+nw*̹JD7qh]U!Dt?Y5VTRB<[nkG_W{F ~ Հ8DHzi"} ?cu*Պxpp5 {_P <^Վ=j\ݝ qy%Jq' #Q{\X'{ >W@ ^DYvo\H{/Ѻy}%(1ٳ;{j#͊"WQde0 äIb )˕HYJ,%@R e)K HYR,e)R)KYR,e)RODYg|9R \lJ *D2F)ZJ%xs|E%QT3/݇Ąxf & eN֏2Ε"dTJdGJVx9wMĮ/'T^Z9%|S?k?QlOJ<'&<$KDZΟ+///䯟$WOSɮ^"B~V(;3Rb,%@R3 }eJ.ckWׯ}>r;JZ:koml1~X*J"@^R/޽C ׯmdk׿2F]͐:7~(7[A+&97V( u=8KP{>TX=$RI:Uoh0NeR8UHLPT9?VbyIpMcoxrΒհFt !J]0 ,G`$a6ɫ M^+`Hc%^.TTuv$auHnjXgZ5BFzxpQ?B*1ڭB+r$=hk IDAT k@ nJ3 áV$aQ0k,y`PO V*T+qdi%1@\?j 'H^HB5LjRO쩂aV$ Xt١ab:yE0\ RVj:VBłH+0uMtx d+Lp4BOd'Kǚj&TBU7`uu#oC*BMOFTũTǡ(R]+)u *ZaS ~VPk5*YTQVv"zr^V$9/ p )k;ªI_P+5@C^9Њ߇:5`])iV`(Tp= 5@L&/| rh|F{{)aZUjUIɒH+AIIU .^z` Kf2^VS:V2m+xAkxA[GB ;Ym$QZ4i=5$CoоB5aVGf:yxhpQ;:8DD%S p0/[]DY)qڎ:+ b¬xW$@m|V$/v:s#pB ;QsURAH|`–-U"ϗܸv=R`qRp"D`TRai^T4 ѬQ47FDY ]+ãfz4/iDNJ$%uƗdOd*{{i$ Ƞj(SZ`OB Yzs:nDʐơc=C0\p>wȡcaJ ݡy et-R8+&~^(|dh[6<  SVDP)jk.Y*졎 /]XM#$]iBs[q/~jz"Beƺ`qz{s(_"rм) j2yV1oI"XO)t|--F"uVXCbS0^^ #*.+u[y70qk N`oo.ȎmmEJU[ö*GPؓ+% Fg0DRfhq_<8X@*HbXCb; XV!X 2 B VvuWQ3 ԣx᠂6 1E#-Mhr@V^ ;sTwڜjLq:@hUv)sp>7*Bn|[bn=l 9H^j97"X$\u5LzR^d6+A|X$ahߙF`2ȎjͽTh^4umBFl8[SCs{|sxO6bY2N,'G79ҰR#nXEY{s kXmE4֚U!1HDW"n{ PKu1hl[]A{UR?h;C+0jTt9Zϊa^be۱~TӲR@v,V}-+fv}G\b9e"Oi G\Tko6Ȏn{@%ł@b{DǽZ|OJ-LCj=]u+27v׈vͫ[Y$۱yVhٱ:ZzPZ֣g,DHp2P dqC-Ł .\Dlv4ڪG %B^S懵 hF9phA*3W 쑊 "DN6M+æ|W;E4}N1 Ȟ5+traA‚ڞq]qyP!HɹBx B9Z2@fWfd@a 2ӞJ#;p=jAşE\<43V+|<+hR8Lut7<0 =z^xuc:ųjMYIddNe/-3܊X=m6Bp; h ED[4΅YU,{#'+mH*o=X"iXK)҆:4B= j{[%g0S 2r#g,F2η1ٳJeiHb=?dEpE+vĎq T03A:}Px6偠ٱHa]l10 jGj-ռ " v!zi'9B=^/h'ڴPIsJn%ŋ{E Gdr*RtWJ ~m0#g,\K +є!zak~zX1d d-g.8EE򢳃ydȧZ*RtW`CswYB @T5_5GsduM,!~*Z ,HqAv,@"G, CɶdH|5*X?b޻lNRm$J=ɶ,i>%6$ Q <A 63_\*ܞ}"A2i;ö,+VF/3#>_XG弗* ŏ (C''`Ey ?7\(Z yHqNvhSLKE |v9iڢҴݟ4"bX9HcP d.~@>3d)) v3.~@ p?- /Zs?=ĹE+ X*Zdb `#:)ZkHAVH 0v9ٟ@])ZъVhE+Rs*}KO6 WH$FJbfŚhz&OJhzW2z7QD. h WnƔ6_c~+Q5ipWqs*}PzHzxzbXz㯈bh@V<&VDtkm< z?x1򯿊a_eu$z>oށ)?0]4~@f"b?? oϪU;,G`zI bȷD4&[Zp6LUFA@SדK_)^i㗀?Dzm*$B]VXmDCu3t9McH;On1iKtUFߪ.HBǚG/?gcy0z}HDQ9<*lUi!BHş 2a?)Np8Q8I3P{4: t[dݐ&iÇ8(6~u27{[1!_jqyGRc;TM率?`|b>\TouNr ciKUFB8zsߋo<=?K;~S͓wvE/ Nr=4_2P!:VbYqf%`Ik ӈETAƈpȪO~\e1rj_C2 Ш,d'>TJkq$n{ Y wqw~EK8~\O$q hdNj5%Uq ,GEu"XNM@A4QҔ~ ^\ rz/(-ή &;S*z&qM9UA`5I&V*@+bϐI9v8`6?V̟_5{ƒ\BvuP{`"%?W0&bA ˇO# ˃~|"l>;Sp,8 =4\a=/}:5j,7}V*]w<=XqFo$0<&`G-j)}ݨ\AJd@\_G-)H"ּ4 ~a%NY>7wQxp5hAh.g>k]\DdM/Xc=ɫ>ak8Z`Q4kNЙ_6a/|-R(~E0xd>].'n9D" U\c Gc0QF#:hM"w&BDӋs,7soC]jKmK}9珙m.D5˃Ck(v"PDH}, K&m~Ehd 61g%&Mr,o/#:{s0 r?"ys/a1,Ya;I59h.xA7+n8:>pcڪʌ&#gݼ㗅*>pNb eG-e5a-bM̺)9 y@v=XÓ^Ǯvs!"?,F1(ռXnMΐNjށqLVwV[c*^#_͕5Pm o`kRAVcTz|Q& C`dIAg͟[suY CB&3QGCJ;I7H*&-SÓ>"+/5=^sZYhat>(! CCU7Yt@Qow%}w;J//0wUG9v5 {$vInK/P/+B9b[\/w/9?O"@&笆|$?V&{X+bӛAt¯JX21;9UkW&7Fpǩz7s}  mn<2Z7oY^_/D $_ ;hxG_]ioq>Hъ h@V E+ZHъVhE+R)Z h_(@$IMMXzV&F'q2ĠlI h6yY +qoABHp%$+I}+cW/HC{N'X WqEtϭxzHzxzbXz㯈bh@V<&'Xqcom6_(}i>$3;SbShOŎP?U"ҿG} fW ~Bo2vۦ'BA 4~]>68bm#v+򗎿(?d1X|)WS&gӋs쳛n/gQ9g^tH ~K+/=eߋxJ(/ ߜma)Mٮ7VgS[6F@f"?98?ZC-?]$??ߧ/ M#ءJCvxX⣪ٹCgfײFǒRdτp+(58ó7/-`g޹vcjI<ܳDέ(zMDw6#VXCQACAڀ.ոJk{0 KxBǷOwCKUmΎcz,х6b:?䁗3%[~82`4ٳqe.ߖ+}= _ Wj֗cW_/2M~f. O QT>xv]ey0?|f΂9GΡѣa%+񧯇2p%Wk۝ٹl}EMW_/AkxJ;58`z10m w|3 N T01͑? X->j[W%ף痥Ϳ.y[_f}y  p^ժ!l9u 'mn1R]CӢzA Aӳ:߈?ޔ#cwvE/ żd0 oC+϶7vC"hl}* X=vW? "T[q0'N^U,/ǰ&ğm-4yƋm}ofNŴՙޭgl{m-c5F!z|h 1:I7H2LZ-DFKBo_&}EW3~>[?7c#KJofnd}'f\u@I˗{ec 8V2~yc5MxU75Z[%/tW>Ob]%;@%-/v85>SmQKl}nj̋V0X&˵N/VқXڢc/DBbg쌭V75n٪zvv#?V({ݎDJpt+_bwV&~)ojECY)Mϧnn mn{Z7yB^ߦ vwE= E+ZZHъVhE+R)Z h@V E+Z +7o$Q4WCXz ˃yw:W:iK8yOq%^Ȍ y6E*aC}<#DG t( ɦ\(=8|yuC] GӇ1D$5GiB$+7 Qv0y zC4k/B}?=I$=iCJq`&%q>HъV E+Zv{. 7Ƣ߰lV[Rզݲ hZM!O.ſ=<n*67C7L \-HjY ȼosUtrLxm"fvODsA $3a>ioح1̲Pl @d_3ޮRBDO/ܳdv1=?(yqDw/?lݰjre͊AHx [m`U!ZkE3" xfZagMm7yʹXy@w/?fÒ岡'(ȲָleI>k-WX N`㽠=M" MN3dZ츬ςtp}&O-+M![NKrV ;P"Q 4JЍH*QTE`?ҲYy]@A tuiΎYpVy:(# OƟ~*U\/oJp-(DH+@LT ]tTI\{K0@_9%@䈖m,zbB~ٹqi`,89[5bi=(_z?hD{(`'"|( t`*?1@~U@AV']Nؒw2=a:%pn5[JxЕ,8֗chJ= 4"p2+Eo[*vv-LBͬ"( $*A;䳺*N? rlCM>LMDP?sp,kk:蠫s A: l%]\F/^r=އ1NB-|[e/)mm#D3b_V㒃FU=甘%ftϥ$S=eVWSv +Ѱ˶=?;Eq)mnEѭ{u0}32d:fClx%"J`^mJhe%fY7K $J! eDHy+ ,gHk;N{4d:;@ӳ3M*$D\4\=>fR 7yAsVg΢'w/?z2,44~Ǭm_4+!fuJ@o w;~o;&y dCn4dƂmˠ:R%|.֙-jJ^ fU0zS&q}߇P{e.EY1a敂U;fW3![⽥%3+QӸ-'^ybFx: ҨyZ=Py|v<}6+pii $0ƿ8oMP`kA;sdݲ*zw烀P2EJNUWUf9P=;_-Yl>O\ռY)}%5"ڣ5=n^I 4X֒moxUp O~wV"\%[߲&RLb#|XT{``w E[?7o*GfWhaF"k&FajxVG?o>kqU\DFj\^gb M܄`ɟF+Sgi=rַm80v|+dL ՟Gp,P"Ah<3+qy0<~ͦ HTeQ{ZQɼn5sDal{k8j5ZB%7Îo^! M cW{F,4./%=DL,V kf%kC75&D ;µnjiX(Qz X/[qd{@%9ẠWS00Y*woI^M2&(|Åj"P[0>+?&DneL}y46?f^W{$ AVgfW U~kmz@h>̜z]GMI1Kj^Slmw"Fޢ~([.ګ- ybf3Ƈ6UB|l,7ii$"`VI^oE*QV=2q٪7g7 {, J;=Uz3E>(*&}~zs} ?Lj0Xu"ETMlaf̢YTX"Y0:@ WQh4Ch4g\=kmQ$2^FCP0SEa),2!GI4Ϳ9H>xmbz㸦+ʨokNZ߯F ({@Ҩ%݁Hwd"~i#@"8HRM5^?Smj]';zƒ5{(#Xz]<)v3fyjضkfJe4 ,MZ,l\Ņy);8C>-"u|?i0.x4ZHHJ";F?ctz , iyV[b9tz~si#EAZSLJ qc:XHo* ,^><?;fiVhhjzwqIR.K?l4\k"OoQ $ {^ثhfU~\%; A}-yM2S MAuSIU YjBe}wc\mQ_L;DJ"Il]oXBҤ "D N.:`ZF=n E%[AUn:⛆kna޺Q>DөFyauNZ@ֽB:W͆fZc)AV=UM7  T|"Rh 0!T-QŘ| R"Zk 7 {&SQ܈kՠl|Kʾo5ɤ bc[Q#Otik.#@ ĪF05YX|YӾ  ׍A(ANQ+=3bHѾ, XµU2rM =FFyqA于&*{76SаeDGsx*`a7)ڗAQ5@ܨ[U2֠2Ll5Ǘ"U/  AߜF|V0jF,nh_n7Rdng B5(7{,{6k76dRh_!`X*}Ӻ7bMnN& E$9e JL56fǥmǯ R/šĺa;h@_ѡaxhnj\t os0~_id>:4MeC7)abϑ׹A0u]_ٳ.XXFslSɬH>6vO!zv~~zen^ٍ. 6gTh_@"S~wvΜtJo+ƍݘ^6&=*M}}S̤׫W7Mf5+RO B(U!Z\Z7/c)' IrΑ⯥ f+* Ѱ,@D [ Zj *:Ѽi|H>aHuGzݮT@Y. $a=ΆzUҨ_lSh8@! f2 9H>}FWڴ~5to}x^lzs& E,x6/Rc1E+ZHъVhE+R)Z h@V E+Zh@V7\RWuk5?aÕx()g]/>$yy]@Iw1,,^-zN؊G8t/B =zi|קP5Ci:L"WfVz^G Ocv=bP.2ʥ#XMY So(C50v2gDe9bn_6"wR\:8!5+G2 j)^yLGy!zRM:< x/5xhq澇\JSLa$>8>6X\ΡUN|*qf5c`5YIS@$[BTZl/*!0:Elϴ-=j_sI!\OZ1"{86WkBdT]xWUDXnn%5vy'F+cJd,6RdҿL|(t,{ʤ\s@ cF` $8 ?M2"iUӁ{DHӮQue AfA[&+FcqSj]O{ /*CGL'n$+VDGP^Gz)K a9.5"9BQfu M&nը 0UOqAVi1SVWQSuS[tT&U8F h5uYF5+ݾ[%ķZWTGK,qbјUC)~tʤx'0j%SC?L,l2c "hHTe^{\7rh&] E_Vs?TƟ\ Vb#E2C1SD~ Ag-:*c8F7 (jFm>2|Z$J=up1cnGlIiݡ}nW~zu+AI"(x Fo "> ǜ8H8Ւ Ta'S~4H+_$1? 3ЂƁ)QǼIhi)WN?-:*j1gbue >tb&WdDh_DՌ`h^5(Hi>8ڃqD٫lIkg!_n]i4LUޱȟ=gU>iVtT&b*p&Gb4E<Aޚ A|Gb~6e6k\DdppX}5lIi1EH}7w} [ۉ4ff:]r0LxϠPp |}t+Jxxy{[K ?JUh"hM2xd5қ@,w݁#jU}k;4zح>V[sp2mԯe'{I{pE~H}`H;MT4"xH:VxELq욯Oq`Z$3@"~_RDpT&w,"Oǟ " IQ:Y˅=$XM6%gIve6ilV)i[HMpw}J#{ƌLϤ7) avŢLpY ? BL"&Ũ0~i KڮOqfvp~Ȫ2roz4 {aCY}fs34UCj3dM H5it#tʪ\i5NBѰ0 ri,e d4Yt-JqA{UDeDp@A,UqbbR5oy|CvM.lؕ+5f_S%n^fKڮϦ5d8Δj2y[˲ʝtuB3*!#dAfs-hfo 0 XۦX[I&Ϭ'|x "a W۔XSbx*bqˤ E|E3}ӜռBȪOqju9*S4L@xNB_ڐ֫(\!@V)ws0ViÕ jOqj̇Ar2CXNT=*= W5y-Xki>Ŋ&͖=mZci&%U\V$՘ 3 B`Tfd(*3d6lf&-Cċh iCZ߄pmI4NR.2LEe*VWޘB);s y[AzYV㲛@Q}$'\@|Q&u5bQ=*#?-eҹy&^B Qޯ q4:De0KQFeF)' fɐ6'ʈYVgCtJpNTK+`JVcn@FeVߊdXb,V%?Aa!`C8i5DXTf5pd>?R$8坯ν@qi8z%=7}L1$ٯOɏs'eKc_/Ifk 方]/'aHB1R]dHK&@Q#y$Eǘ>>dxR?>)b/c7EhE+Rr8[GWmV?M޻>tDR/'' Dv57>P?A]7? o_~i.XE$9@zjrؽ7>l! n߬ 'Girtr Zr[0JdfRW-@{o<?d "G# ZaI].uȪU<!b0R I2t^Wp@Ã}7ӿw\#,"QGhpD]f}>1haR<~}4 @J;'%X NI7ªuv$"v2pP>DH$VZ!o<9@H}V=OG?kk(_SViu%5Rzd.וZFV`m5OD(ֆП`p > peŦGN9>>- r Ѕ)n<9:>yZ.y 52<$ ^v4]k/j4CE(xӇ}>x"k? @9==)Z@kfy)Gq tf |T-hލ5dkoԗtEzH׼: \ӱ|K5ۄ;@H}[= ZV5,sDYW+ܮRmO\x h|{+Q`UoԙvRV=Q!<盎ߝ i7>O>a@:<,fV5Z)JU"sK>I;$ $Q>HWNFH Z5\g0Dj8ʾVD71}V" H~,WZ)Ȩ+I|t~ᶦ&qfrcH!`n}$a:#rWF pwHp#nde.+@̸&qU#Bc&=@ 's艮[[:=Y/P #  0K͒]ƣΰV @ /C4>#kRF֨?-kn#@{0q="ô >߂x͜ 2>?:|τBhZ#\fE|t@rzZUy-I\2@z[Ú2'!:V^' 8  ^MYvr!ZpiOttDrSщJ_4j2|^*[ GQ}d'ؑ,nI|\eYh,K#uHC12Mk H  4S?JH`CH1Y~o_: wwn-_]_nkX$tN Mpu#}Ճ^@]^L<8-!JPT|wN>rZcꄐG\ȋJ$cx%'`KNz KlumS5pX뻣[&`:^6  ȪAck4]& E@!/'W WfsDWs,ǒhz9zt8 u;mpoF(8NDg"4',Fu߯!\7Ai;?A@ws.5/2 @®gyW}>|U;fj De@!h%3+@^[ 0R: R,W}&>:~e.bD;u7wEew|q5U$zY.y+q33c#BdtbZ=@]OXL^Vwf$꺻7OwҮ<$Iꁐ<8 nE>A30Zf% /IzTz\꯸nGIjvUe{\phu:J}8BS}hag4*\ vvUٯ#5x+b:^wg׼ Si"ϝccjrrzsS3RN ?_1{v:cn'+@YE*Q@b  B R*cm"*Έj'ѶZ|v$B`w!OQD @$ԟ+_mbFH,~Uzf/D,N敔 ,i8"U-h@`Aw݉J3V UJZU@C+J}*u>cHъVhE+R)Z h@$.!|_Im< ғ8-;$]zF0/?j!Zz sj)yp+@ ' =D>$x)yP ]2 H\%W\Q9,//Q ĬX._ZE3艖M hE+R HuR](N%)_z|rzr,앿7(;$T8=0̍O׍M/-Y7 ,˪eED @:n5!:Ì: _zzirzry#a of왈H\ꃘ_{ c{6<[m#)aP֬D۷?HU ;^N;guVha >8贻_~:3FsgYgDg>Ȓ~Lໟe-†yݻ~-Cj-8%Bҡბk8!\=\}HAY4rt-WEy!(td:D7sceu 'G%xOI!%<~|PJzD@TL=PvƮ߶Cqz8"!"Hy "`1Thh8FU3E̢z~F\.֖}Ug/|d7?"4@|'*4konw_mwM{pt:Y&MtSg}DDT7 =MMcIFOuK~#x>Lw?C$ 2OzܿU~S%x^ M. ,^Юq(R2GOE|IE"GR LSKKi:'Uu&-=8rb``LMo0U+ >~!|2} W [ff:"b IDAT? AӒ*P 8@ r>g˜qWhz0zm?-lFICoţ4uzm\5!^ P8 !KCO G\qPQ;.op&7  )dfYDGr:T 4O|&Piwr M0t= HNL( ;AeBݑ&h4&/){A|pn2K\wouDSK}/ < yA%s?@_,@ I'I T^Ǭ, \c̯`E@ vuWheND`)X vuBL d1 8:sl\ѫ7~|FNO ,?󿀐7VST%$W,-%E; D:*QkcWhv<=SAWFtl3 F=P`$њl|&kyCX^a k>*{6:yfdzƱP@Cm$ UB&{NS $\ :3YhnAEH~,5ktmJ=+ <|{6vPOvG$&zNFb75?_%~-3   +څx~SX#3YYhVB"?9uJ@DL0=.J4`&A4alRJi*D8mh{a&@ "tXw >osp&O2yX[25n,k>'nf)Wd^쐇)nf1xgѬ@Ȣ#A==vTZR_d7K+>( /-50֝o,SLy5.W8拋 v {(zyQ: 7Q؊A‚eFk==a'|22Jc ~&߹+EQN!(QhfE0i;YYT"Q;GGO8(9yXѩИ5a^buY&7pF T=ru^ꒃ0/^k+4kB1l%Wo@7y+np/ɟ` /{ϋcnx`n#zFx@Q F  ݏ̼RC,P4k!0O=GOƖkwdGb:!ثlV@p~VvQvbEI' !;'(M~AyJk8Ŋ&3D>|ctsOD4HkdR &Gf* B ^ Nf9f}`f%ת$Ag.Ļ4mZ쾆UƤ0@S;1v`gzx#;;JaV+uc./Iւ Mt}߳cUs̝&0 ؉?_|X>_$oMQ,F1rrdQxx+T|rz8JŢY20⽉B7 N (ߓJ*E,Au)T؋8TgjO6IDaڤkLΜtYx洸MnW(? pt*8܎X4M:-C`g<0A{S3)@`^bA̫'ӧGhC,3is&Fk@iگYWc+ʾe#M @%WIrNSW1QMg">/IumEf?(]Nv>Kߠ왬`"/iz˜:3I0~Թ,Fɰ+2Z?bt6P}9zeyh~6 kf%;^~7 lEE̵ b_N_9y8sϠ =׹U&qOU\1N5oF]׶8!s8Ŋ :+Y&3Kܥٯ^|i|ht sRaӡ(m&IW{%BG䭓4"/݃ uQD,6v23_^E/vYuRz)ձ)pԙ+,*vo= z0yUyu?3Q]Q5ebz1&omL FXV(H#V[cp-e.U~ \qˋyhɱ JW]4^P zk~EA"ī">TM\:7Aff,ڬu(NH73p$ ;[= g~^*uxtL,(:ѣ78PqJoY&zkgx8=M<>Jq1sDdVJ㽲u hKOHwڈ2亂B.>/͘>G*@ͩCi޲!."W71|t:KpBu<{f;ӛ.7!W%8aथuC=˫qIʼnG:ֺu=ohsqͫ< .Do< "`e GK(z ΑXFbWĬ bZ]YgL ,}E:zwc}޸SvռΛJ ͫ wqY4}J!֩:>`4XJ$G)Uъ9$jKT1*ְhE$H>ڀOOb,Z6 E+Z h@V E+ZHъ88Dp]B}.Ԥ($m6,;O z8z%BJZ|IMOZ@) i$G [W`ARFM"+,|;tD7?'xQv!-/A}(EI"I}uih@V&VD :Z>]o%mRɿhz8Ο_zzBl)`ܐ(;yW?uҋdi|#M/ =o,d ~0o'.W:V+ը!\=9b&Ƕem"  %:l٫W*ՃU*.zCއk~#\-)vh.߶<n?w[%@`q䮪/lC@8{S90ࠞ< 9ש33Bӱ^nCGp'd,MWV*C0SAWBVuc{2|0cr_簲ѡ}; . =~tre?;yC@|`k ݰlِ 0zg[\[Js4p:Dң K:DDO 9SS3#4AשffMwxx>@(S^q'lPxB/h2tI MG _PBS*8z)IҶph-c1ӛفɪ<9R͋!#9kig Bbt:=vni\ОL@ wL}$.wy;%R ^i08Khz 6FM򧅭Z؁5HIguzm:yEW7^Йsg &p>`)WVCI <]v>8:#NCǏ ^%[0̹߻h7YpXࢂ_Td/aP_U$0Ǒ"_0GhSf 1᳿C)^ @Nx9-;oh\ ;hVP%vB.A%ohxn6A m^a Bn =]_7G2Qt3`^cbm A؟*s|% `\^@q )1xRK D"o,9^#>U3Y&CZR. %\1{[K-- 7JGmǮjI0'p>@& [3pD7pih ;9c=ci|M頽%%m5|0gG"Ig'gCqPIGpj54fb͔/6k ?(Q[P;?r DcKE=&  &בBgEgK4A= Jv$2j]Ga A(b|>Ofyd &PU`\cl&+RWe0zNӎǬz=m9(u)_Zkr5Dr|#RP4{"AȦL QhUu]@x m4_1)6^zClF&_̡'Trﲬ>LҐNO\aCG`Z?* Dq8z`ĮJ{CJHѴBg}7a A:kn2F0;1RBA5{>z6EE]d .YO''vYlΘ~M^tUp؋%:ս,W8J @*rp9{vj}?}3'})VLΜtYB+<j8˫5v'?h! 4="4$p~aX)ùlOvd^G} +ʦl<09t=uk WɫlŒ=oLsgXQ)Ҥ0&/5Uao۟_l^$*SIC0a`.:W[.Uб(qZeb@0i{^LDG%8JÒ&ݰb+V6 I:8# 2ZO۟˯yZ?E+9Pb7r-"]E)0q:<}|yUr-ETt՟Xdҷp/#RnlDa?~OboPnw 3ZΟW2w/Uܗ*Cw+{q\{5j>4dNO< j[yz7TqT'˺>} uvr7۫E5f>D]w:ԋ=RU5&qW6e[zr*7W7?*T8캼&T "< et_={!k|xv۸d$ ({oj)UQ}L#+ ;JxV'~XN:(Fηϧ YDB:Fv`ɜ*7!F$mOIʡ{fܹ΋t3b,2-Wknz#]9Ub-?3*d8Y5?u>N>^ |@卩f?ɂc>{5* ܤ}$7NΟ(/iL懦 ie;ݲb,pX2r~k("k\"N"; IDAT:}s~E535ak뺊U9v$C|quA%EhwnR@IVPz3]&\?9y2zִN4grРwj$KB&:i?m+lJC i4յG6'|Q<UD X NUWh4 꺪:!k9[w>~M:K%]/gIm>]7⧪fWąLd;بl8W#nؿ®-]qYtvYo˿QQC_,P"{dE43H65a}TNaJ__?8YںSQ+,dc++s,HCܨ,ڱWNVF4扴p>jTj4zm6Vm׵2㘌o^mSo1`i(TH~_,CO;_iEa>׆q\I @~ A49H:x07dKH=P'-8#e:pvqS \uU%~_J55W]_]?T㔍oR)^˽U߿u@*~ù*P 65ږ"ZWXڒ4ߡkBXrЫ(UŖᘵ"| @MIO_(ͯޛd]C[CWS)r국jw`*E$B8T/[r vz/O6 = ? .RBՁ4Hߛ#`ѽE~,QUN~Ȭ+2y#Dfͻ)+d@&,ϯޛڨߡכ ~8yz(EYI@ 9iE+Z&)PL^nZ) x~sA2?9M dϿGZH˝g`VN' orJ_mЛu%?Ջ:sQA VVlHUn]%e @G"`;ql BN}{~ưvȂܚkQn0y> &Ǻ ˕|NlljwhsQuqvI֩)lUڎҜ&0 _*T^h$t{fM^,BKesl- t I:):̛T4LLVTɼ*LoT!n~ՠ-}MC*z ':QY$*"阜y$zOd~6''u>#N;*z"߸CjLӘ?А?Pk&fAIr7T-܊qq[Fl&&&S7#JX5M;O Es1 uC>C\V]!gڿ.4$}apo]`{T2w/UwL J^yq׍6 :}/psrrr_ 0v0z4l_7Tq_*r;.sֿ4dTe灰P@V%@Q<=:}*.@DwYodD>L;Tχ7'1t+zK*jlUg@Ο|SC{?yǯć\}gMD:"U"-. ?Ad@ YX|ʺݷq;Q-ɂI@ BhECX\3?*/ TGV(AbwgNtPލjoO5n>zCzI*jMnؖR48|7mkߛ,2-Wknz#]9Ub-?3*d8Y5?u 5|ZW,4IYI 3n!#!;LMoG.ۡdtŒ ϔ%dDtd-jgj9;CրkYM (Ɋ@ok;Nӓ[~*~\xe;4jME5n%q!dpE%ؤnJ!4Zfn꜏|Q<iREMXPUՙeE Y\v7ٺ\;@h$^'65ߡ͆TܢΕHFEEf+욚"7YtvFu[ W[P0qэQ* prcnm gf#~q̗/QC"0R?\`¦=_\WL[Wҵt2@|h乶:{)Ԝ"FeԎvR6DUH~񼟼o^/Iih/36U\~Y AZ/ 7_iEg> )㸒|;ϨW/#)zȽOZpFfu[ h rD Y?y߼_;Uq7Gj?TGRsU؊mUumKL-a&T=#v@2Vdސt6]y ,ͷ7n߅YC[5Tz\&zm&*#5HDF3[ܿlE@+OO?*COjHe#^I$2,QUN~Ȭ+2y#Df͛V͟>Z{[~Fz:Nıyt V/_*reR E0M|xE#J˝g`VN' orEY.UV/E5[Yq[WyAdi/\lGY"S.AχAU "j6C$j>.WI'U[46;t ʵDGESo5M;W;fJshHPy"PQ1I΀X2&#~cXjG LANr~^MYL;HOFe5'xi0}Dz[ ZWCPv(NSۿ?^l۩:ʓl$>HΘ?`Ce&99  ?IE_9?"4ғEtq-FCCkrE׸&&+d^U*H/Vנ_ۆTE(_{I^?S%?YI|nZ"鴣ZM "U.Z}hTwL#gb|H5|^[Q#SadW*N~ݓ\k@9yAH \?%ko?Օ%'Ш[4%*]^nCJPFzjTDg8WmJlKq+Iuw lV9:rv[ټvMUmu|]v4c#=N5QFn>wRaT24,)Il vjf~=;RI#~mσ8?\myHWQ L+n*?_yUr-ETtI?%׹3IL&tWe\w"+yUlM8x^O @"ewY5y>$oNq|$YvׇJ (-k#Կ4d+.rdD\;ї{J"^BۡMuHo&Ȩ.- t?%7u ͯ;@b`jG[.~7]iHu6ז筻Zמ_k0111@ LL &&abb011@R`|E^~oGZ7 b=O7ܩQtyG;g52Hou־nUe`w@@]vh;~1v u@aw8IѠC{2>ڷ*Ah۴& 9L"iQٱ[}mHR}Nm/GUa-8jNn4{.Htݦ(+އhW8/Կ|o-JxfliNY-)̈́$R&aEIqv9^b;adڽHFv1eag "4@:@Mc qx;HynЇQ@; q0{tQ.Μ@Hl]cƘmn @&HU.*j 4LU{&Wv?@&@ggBIxmo(aB";x_2R];Q-I,P3*H3@P tԿ@N!NUrι{cihL^˼< v:9'QPu JU0i *&zo p]<^E*g蝻7"0c'Rİ8# O@6u[U,T/)kU%{ "+HfAo٭e?*R9EŽ1̌鸶"e\c Tl![w.xunR@IVPz3]q:!u0XOWwwOi)Lf޼c_ b?nUr6ֹ#n]i)b{dC.lӓ8F [ TQCנ꛳u~9?6"?k]2;&~c(W`7> rzW}T9s'B .efyJx1M:ԟ6 n[)CƯE7-7*~qLv"/1mʙ鎒 ٧gB4|l`y&}(!h)&VGq{$'uqpDBs۩ף:ܲ"[@ =eC?]Y,qv +z*FF8nZ?X0~+j|~ 8?'ۨ5b} F ;;rlOdR2'3@jlVE*'QD%T13RhQ"G&F.X isyK$yܼggg٢F\ D?wtR9-\5N"{i)ōn6;];Bd!dy*`f~+=~уj2; EC>-67$=K1]:[8 /-%DOw6 ߌ,ۼFaR*YH 48t@jNVEYɪҶj*cmT'Azѧ, +ťʇb!FL[䛺E<3 ugO@ l i7sfa_,H8'c)B$\T{Hiu]퇈v. $q;.AzeY׿ <~At:f d3 -Yl ~KSps~]D O|\ӟCe!,_g. hGfr~odBq${rDl=[ݾ Ћ>]3GJw$>{XbA Z7OMc!M.A仺R!\`~m0CorB_mt_+Pғk]Xlj/%Z/2RyΝxzѧ}R3 AݲҲwb]4UO! "DsEJmzœ 1MGx+3fo9i9iIT !яebu'q^)R:Z6W-4ձ3I},D#'b!. U[0Qaj LG0\e&/@2u "U}hlC/,)W+W%m@|XAV~lծEk"DjڅH+-E AJDX`:N.~w.V8H\,J @j1*KhlBc{.VN:]rـЈi<";/MY]9 &?#>*W7Xu&7mk^>A(Wg6GvYbugg5qlٸE:qh*o>Hͪ5]9{D7?54ȸѸ ;j0Kw0gJb!,y-מ0g6*bׁ[ߟ=&MK  ΃`O"E7)0L.~ZG /dY.]'V"` @Y} 03oɬ̹y3 8momImzd϶P;#Q_4 %EP3*g$E&>L)FIO&;r)z,l&:zal} DXv{e -IO8M3 WmFǍs9cHVcX0;ds{t`0B.[ IDAT̸6Jg'kEc~dG86 0SڟV".gj=q9aӬ/m]Q pMFJX g\:.N'v7`譾0dzZbE86<\a33ѲEB tF] Fim}f$EPNkTi)=i1܄mGiί'* t@;;3u
\$D azH*+$.J¥drZoc`]Vz56lۺ7#x\0W4֞}қ]ڠgdն #u9rr'@7}C唔-0#x  m3g"@} T9@v'.2c#`<=&3D`h2R+~E4hH+r@T$K- &Ȕb fK$"c/~KzZV kHY\\r g/QzF AoSTzK%"jZ2@$DwET4JX(E0 [z KOaƊ5,zr5 |"Ӳ%H I/DGcz jV|_wJ-AtHCx:jJ%HrZO5eGG#k0@4z!wuh&@r_v/A@䌡mE#'AnGA UW u̙a١S6HFZP0@% )C/9Z})AUC-g,hR-\U [4x["x0@ 2TRnC H5 l)W! R-\"b LHma(Q*Vra0@"@b0@ U(=  &&&abb011@ LL &&S ORdCw~*wBo$dBztNW!堕\,{BkgnAh}^N e,AhZϴ*wWѼe"^Fъԩr)`G;ݑGk@i2F:1"FWSDͥy6D0111@XwfF'tr k9ߟU{ +^HWF}{H]_tdCqc:S+%k=??/A-D\}u-X86\_]}]`a6sP^H6Bq/WKrac!J4w}zuHn Y Npȑwꆣ?}'8G"$ h _ӗkr BLܱ;v$ٽ-|uYfdBBt,*0ӟ _%XDa ~u7o*! hXv%D#xZ$Gp胄 2xC,ɖFz X Q7:&@>gH\n }GH؎ Rz Er(C D\Daĸ؆S$du]{"J"@|A +f~M_qͽV$}6H~H aeH=i ! 5$@ *"m]Ǻ=l E̼ҟyje/d̦buf !W7]BX!6u5@A"D*=%lxr_$JWTfeV~ i @8&;DU{N;k RB iD fLypkO]=7i)`!%țU$E+Rn^ R[1@$5vpNj @hYv"V &r3wD)BwM^->rMyħXJ4QO&&6H rh_is䇰mlGRRqH?GJx Wo.*4@ -b  i,*Ts&>nA^&H*7{"*\}#$"o"|TdKTVGDdBf:*e\g tPBDPW+ jxBLZg\i[Eft&9={mAFRDB# D~.2ۛ`o6S Wg$Q "_K8cع4"xLj[I^"X(PQW-B2$e4?cN!DiD( =o1蕭* ;k8nB: QKWRĘȝ=狅[ <4M2M1]`I^>?kװTo_}Y֐930%(~6X~*\qY ~yq<,ZGQC; e @0z۵ʣl~gjn+ALVRX؟mV2}V_,\Qp"D©"3dsL(O_յ/鏴1Zc1G V>F aYZU ׯKV?E$<н|R\s"C~uOܦQe:sfX=ȤUgm+Xҗ$c?[<[~#m;vK"l1?VLi)سrxq @l75ėZ9>`/rLTa( T(X=~L W7;sUԧU)Wׄp2QI<(a! R-r(D/& Rub@Ht\ )-?aAWb.EnF=_kcxa?4 /@(IQ>)J=BM G\X͏GԌV#!&\;} " !#4?yώ =1  (Ahϖ :@$^L% "  #E- ?XԩX6Jt-db!H䤃@|DGL>ӽ-'"Q{Tq)T8a`$L$1=c2)28\ڴi!G(C _'Gl͑L毲nT~ki_\*W*A@DF9A%$"d<ҵMwpk+X<{j>PSkAX4" _ "D: iٓ1GЮn=B ‚#trJȕ%i)=\B~# yvLMcW9zU¯JLDD;ĘJ!2F "$öH+W3X`>w]RĴ'(=\6"V-@(j+8p(L gЇNSB{B>)6@`埪 >7o^xo,5 ~j|NȾG.ChOòR_}%ݠͱ0HY(N J?!c<E.BP^-J8b=+FòaU.]9?r 8@v<13""|8 }x7})" /<"s=%"IL{@MUd'{ԛ=.o>SB =_®eΣ5yVGr^s)@nR-yzxu R2f$Iʣ4Yd{xV7 D!{-[̨',30)c2-H:/щeuj /Vv-w\`>{ Y~7C ~W蹪Wd117 q4' A| 9~ʡu}su\_x^5: r| ;W  SټiJHxvM S\HM҇ERÔG+G˿Y-⟔v 8_ȯq$F 0;wbT@(jj#oP|{BTPbޟ Gᮿm;п LUPaWI L3I.!@G- zDQ0"0.\w\sdmC9PIU6 ]v0yV>XV 5+*N*wDfe0Y1 1A$}kPHϕE%5DP"[ݰ"U3Ô q۶眧)yu+K^d ^ebd&a7(y 2+0I Nwib)]w "L۶眭ݾI6~E*9xĘyyLr#,t3i8Q.n#ϕ1S ]_[ ֻeڶBv&ټ:I8($[]fN+l=L_4 rqFGJ"eC Spn_ͫ_IIOe =W(="NBRC RuB*QzV'!8breLaDz598%[ꧾ4b6WQ*Ǒ-/ OŠre8ix0@z NI0@SZ__t]9IW qOre[`](iR1G`GT\_W(|O#%sw,=W/ Y-V*(8N'"7o|𽌤ၶ Zzo}4=U2(>~']$lbG:OY_eٷOG _̉Vq0J *zkxW›2@4jIh<^4G/Rmr~'(a30DtPw >r޹\,;.iʅ\pmcC IDAT S :m 8HYx#F$ | 1<` tҒ!GAp`5[)/O`SJ\> dj tI @ċGTf q/O.JQAZb4-,NA]X-%=0VDAIKLLC}ŋeCfBȶn4t8\{(~^ ۶ă-lW!7yQԞiK?Z TI՞ěx>q?pɸFri4x?/?2 ĽYyZ^환=_~(}⎽dyS,ޫ=bQ!,t:2,GᣊHzLLC}Dx裩7kI՞i3r+\,w?ڢa$W{&D)7\1MMa$W{&*MXb0ޫ=)WGSw0ޫ=Ӡ2gIjOGSKU ߿:gb4@x, ot2m V~ߺgb6@`1O|Y='+EE±zΕ]}a"M31  Qq"b5ۧ Ҹ=ӰUP{DHx~LLHT GJy[I89dm4loHQyzq0|-oMɷoٞiI>Ly&,o?*ҷ=Ӡ.%8dV$v.VLLH$KO;Mp  W{Uiժ=Vn4r;,J4o4tI!C$LE.\L{HLLCRǙ7NLyjGma}환 XxIϋRo2Tt\n>환xcT+x`$;^환\B'S=R_jandyoG{&H +\z GǤM,tnt?2 (9ϕGjBY#DV8tlt_H,S{&4*ϓ_ޥО>$H9ϽY5HLL I\C-JltK^HLL ʗw-@Zgb%^q{&Aabb011@ LL &&abb011@ LL &&abb0111@ LL &&abb011@ LL &&abb011@ LL &&&abb011@ LL &&abb011@ LL &&abb011@ LL &&abbb011@ LL &&abb011@ LL &&abb011@ LL &&&S|k20IENDB`openttd-1.5.3/media/extra_grf/tunnel_portals.nfo0000644000000000000000000001046012627373446020527 0ustar rootroot// // $Id: tunnel_portals.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 63 0C "Tunnel portal overlays for railtypes by Snail (Jacopo Coletto)" // Tropical sprites. -1 * 6 07 83 01 \7! 02 11 -1 * 3 05 17 10 -1 sprites/tunnel_portals.png 8bpp 5 88 35 33 -31 -2 normal -1 sprites/tunnel_portals.png 8bpp 43 88 40 37 -7 -38 normal -1 sprites/tunnel_portals.png 8bpp 86 88 35 21 -31 0 normal -1 sprites/tunnel_portals.png 8bpp 124 88 40 22 -7 -29 normal -1 sprites/tunnel_portals.png 8bpp 168 88 35 21 -2 0 normal -1 sprites/tunnel_portals.png 8bpp 206 88 40 22 -31 -29 normal -1 sprites/tunnel_portals.png 8bpp 249 88 35 33 -2 -2 normal -1 sprites/tunnel_portals.png 8bpp 287 88 40 37 -31 -38 normal -1 sprites/tunnel_portals.png 8bpp 5 170 35 33 -31 -2 normal -1 sprites/tunnel_portals.png 8bpp 43 170 40 37 -7 -38 normal -1 sprites/tunnel_portals.png 8bpp 86 170 35 21 -31 0 normal -1 sprites/tunnel_portals.png 8bpp 124 170 40 22 -7 -29 normal -1 sprites/tunnel_portals.png 8bpp 168 170 35 21 -2 0 normal -1 sprites/tunnel_portals.png 8bpp 206 170 40 22 -31 -29 normal -1 sprites/tunnel_portals.png 8bpp 249 170 35 33 -2 -2 normal -1 sprites/tunnel_portals.png 8bpp 287 170 40 37 -31 -38 normal // Temperate grass + snow sprites. -1 * 6 07 83 01 \7= 02 25 -1 * 3 05 17 10 -1 sprites/tunnel_portals.png 8bpp 5 6 35 33 -31 -2 normal -1 sprites/tunnel_portals.png 8bpp 43 6 40 37 -7 -38 normal -1 sprites/tunnel_portals.png 8bpp 86 6 35 21 -31 0 normal -1 sprites/tunnel_portals.png 8bpp 124 6 40 22 -7 -29 normal -1 sprites/tunnel_portals.png 8bpp 168 6 35 21 -2 0 normal -1 sprites/tunnel_portals.png 8bpp 206 6 40 22 -31 -29 normal -1 sprites/tunnel_portals.png 8bpp 249 6 35 33 -2 -2 normal -1 sprites/tunnel_portals.png 8bpp 287 6 40 37 -31 -38 normal -1 sprites/tunnel_portals.png 8bpp 5 129 35 33 -31 -2 normal -1 sprites/tunnel_portals.png 8bpp 43 129 40 37 -7 -38 normal -1 sprites/tunnel_portals.png 8bpp 86 129 35 21 -31 0 normal -1 sprites/tunnel_portals.png 8bpp 124 129 40 22 -7 -29 normal -1 sprites/tunnel_portals.png 8bpp 168 129 35 21 -2 0 normal -1 sprites/tunnel_portals.png 8bpp 206 129 40 22 -31 -29 normal -1 sprites/tunnel_portals.png 8bpp 249 129 35 33 -2 -2 normal -1 sprites/tunnel_portals.png 8bpp 287 129 40 37 -31 -38 normal // Arctic grass sprites. -1 * 6 07 83 01 \7! 01 09 -1 * 4 05 97 08 00 -1 sprites/tunnel_portals.png 8bpp 5 47 35 33 -31 -2 normal -1 sprites/tunnel_portals.png 8bpp 43 47 40 37 -7 -38 normal -1 sprites/tunnel_portals.png 8bpp 86 47 35 21 -31 0 normal -1 sprites/tunnel_portals.png 8bpp 124 47 40 22 -7 -29 normal -1 sprites/tunnel_portals.png 8bpp 168 47 35 21 -2 0 normal -1 sprites/tunnel_portals.png 8bpp 206 47 40 22 -31 -29 normal -1 sprites/tunnel_portals.png 8bpp 249 47 35 33 -2 -2 normal -1 sprites/tunnel_portals.png 8bpp 287 47 40 37 -31 -38 normal // Toyland sprites. -1 * 6 07 83 01 \7! 03 09 -1 * 4 05 97 08 00 -1 sprites/tunnel_portals.png 8bpp 5 211 35 33 -31 -2 normal -1 sprites/tunnel_portals.png 8bpp 43 211 40 37 -7 -38 normal -1 sprites/tunnel_portals.png 8bpp 86 211 35 21 -31 0 normal -1 sprites/tunnel_portals.png 8bpp 124 211 40 22 -7 -29 normal -1 sprites/tunnel_portals.png 8bpp 168 211 35 21 -2 0 normal -1 sprites/tunnel_portals.png 8bpp 206 211 40 22 -31 -29 normal -1 sprites/tunnel_portals.png 8bpp 249 211 35 33 -2 -2 normal -1 sprites/tunnel_portals.png 8bpp 287 211 40 37 -31 -38 normal openttd-1.5.3/media/extra_grf/canal_locks.png0000644000000000000000000003775112627373446017745 0ustar rootrootPNG  IHDR sRGBPLTE 000@@@PPPdddttt4pk`hI&%#5]]+r%G{&~鞈i_MdIOLsZϛa]t]/+9r\iZ^k2_sЁT ~0sC_}$CS:4,CN~qv|ȿ eB.˽zZ.r{\\^c2W_s0hS&pscy0idGY9v|*U(9װ4:+/m'\y/ʁ՚~^+~bOV+"Lfׯ (~T;7Kȴ<GR8cb[Y u9R٘v|ȿ +&0,HkIqMw^ GP wd>_1XN57`t8~0AāS aS7F~{LW>72 Vd$Κei]Cd;wd^+OR0P  ǹ@ƨܪI]1OķDT2Hύiu!7Ne'pὨ5bLp}`qgWڀ. /OWGBw.g ;KABցawn+#1y!jUei`Q7C2y1-/S2@EΚ (0B /+;SQH=qU+n_> UPzAU3T8!__TbnZ aaڐ ƭ:y0 @'19JYqS7.3 u*MR ŴRyK9Xo8Q!Pp;#V)1s}`ډO6 L=St6/@K 8y0bw`so(1r"|>gC0 {d@lMR72$/npL+w 9KMP.ٜEa<s 6(_.OQ"MAv԰\:u \M#8͕sE Fi ? U`X*|Aǔ65ip+i.UI")}Љy.Fw;MCߋ漪ݹ;T,AGپe屜Ǟ|qɘdB}K@r!BC;Q7-#ygcZv+IC.q8R}|)m|W[$NT'" 9n70I;:K]k3:4sn򒉁'?b ).A"4 #ÞU/XPҼ4;cZv+MiR2'frsb):1 [h^L 82X!vmjsnS\\UΦ=đQ+q mؑy=_P7|!HtB N+vMsNr.AiTqf-7a9"1t݈8_HPew̑X8 /: mm[`Tջ/K>=择(hwd߾$/ / ډ1q !:KCVeĹބtRe2m^|QԝZ;WbZ=CpM6tPйD*rkxV̗gg@?I͹ڸϧ2U0c ?zgB܍n"z1LG;Xo .ENgvO=@5}:%嶑#^# _4ꃐV3ϫYkСz5 %(B<U/;܄Xu{V F :xlb-{Y %_~׀AgO_~ͫ#PxVCs9EVEt@|=LlכIJ'Иt-QsI 3wI(N1-S xUg ? ݊_?[65БqE/Hq\@[ΌgI5- v/eK> P% n7f9z@*ߗ8CA`~A~ HKؐqVnS8RYrx&k |fT7Pasq6|}l]{YR> MiqZZZk`hZk`hZk`hZk`hZk`hZk`hZk`hZk`hZk`hO_e zƣך'7sw*w|Pw!GǮ?[Fʕ&yR=!,od7rnR)ra\쏨ɪ#_ 3;^?*2]zB*\n꿆C$OjI|>? 7?(ghZk c/>Y. C*4?,RȈO,)hb KAzvhd!'m/m7juΦ )Ҟe'Nx @"*^kL8;sCdvQGE-[l``RLƸidzm>2!00}?D댉9y^~v<5*\jO 5EQ }ϸGd S_J5.W1z_.L|v%)|>գxkXƘ6]{S%JylDujĥNhI=]0fw?N`1 BUξg#(_!d$LX'F``xwR!/7r?^B+cgn4X4=1$\0gױ?PI`Gw|_1=M&1MN`p]!b\@h\y9I'nUG%/ I.=EKFlg/9#?#.pڞPҋ wvy'C^"z۷haP!‹M(2oߦpK2N0zS!`$Ntَ8!y'A2c-_M`s=ۈN X{ϮgH|d߿OȐ|#j\hd8b`&ķo-j\\{ E3CP4[D+QOq9`fc ٲ+k!Np={ 8;=CKB%~l: U>2%.|;Gľ7p1R&3|+\W&aHyx#|GK5 }NpqMB¼ٓmX26ֵ0@/qXo'7B=f9Y2Kր!h\v%vz[6d6iDk}DX$4shXpx̘Ȗݽ`lE`=$k  Q}B+u`yٸapcrff )"B#׵}Fь zX5uT8F g!ј;͈G1SUU!`!CH\َX֯W]{2\ö:Z/^fő!W!gʗʪtK]9D0:`V&+ Ab:XyuݕKlAZ3Yhr&a}JVUm[ LO~VkG,u_O\Jp)1mR )Sʧ?}*} _![w6M,A-iVqJ3j庻f<`ǽ ^̴ R%ɺ3?;{dS-BUU9YRUsd=pp].`IdP>>*x|߿@jH=~Xg-xs 9R^?2-m.{> *T1x"^ɒŷLp薋l!cUUy9LKN:|[hBfe%%.,Է?  ʳ}UVN_@z9$ -# LZ]xIyH|RFp1FɃ|F1K9LI& )S-ڢ"eH@+Eb=`hf(灆F"I_j9 BQm)8rBzNV#ir>w9>#0d'?On$PՂߔv{`YK$Y^Uu'>.0mS^β̤5`$z: {k@3J)C>wLq&  X0Y^UaO *+f6)g_'ڮ}IݩY-OЇ9 ]KÊ2Rψg&? Erruf_/3fyUUH3õXbQD=vżP}#=1 uR)]T;sbBMNȪ= ?ʏ1u)Sp;+KyUU豼Ǭy5VιY]yx q/ ; >#Ȓ÷VC 0`?Ȗ =y Ǯ7zs#k{gv8I:3}gT`7)4Ҝ3]UUz}Ƞ 1{.bV̛^ ]ѵ0޾0U!r{O9ts87cIDATq ;e?TUUY q u 꺈Nn N%7GnwRyeܯ9Y~*}w#[^xUU;.Y p s j]^eڞqle\_;bd!\JtUUbd>*쁨vz㠶*+>Uƅk{g~iNd+r*!KG#>E֛âJܕ`G'm iC 佁VƝj{g>+UU ]P`౶gP Ǫ7?w =*?+Q`qnm {UG5k~0on=^ӂaX[ȭ8[XwmUG;Oiu"VgS>bk2k{>*~ZkZkZkZkZkZkZkq`0UŨP7ߠꟼ֔"Nߠy}NUԏѵ+MFaD W9PJ}Jx64y<ԇj~}H%rHIJA+O*!ZWK#Uuy4RvV/䵺*PrJNL3s[M8Ա5\ ds5^OzW?GB}qm׿ gkۿ`lmUm2^[ sgvyd.R #Yz|'yp[:+_MJ_':D^yj5{g&ʯ~2vU7K946-e/Ej;ivcZ9g(/r7 >fjd= _ 7S]E`w1.xb9JHk?NyfhUF2~L@g|Nj!j ^ڢRMٸ$CByii-*8 6+?!Ed*b+'CXok3MfNR;^pEj#!y9>4V.?xog| 9,w(-FKts!Cd 4`l ۪+dNe-u9qXYv xYH"R[4K;9[wI hA;YLRl1N0I /vknE;fq{~2vے́=7A[qx˕mˌ u$y)ŴRyKλIi =x7,hǢ2{F2 /v:,ؿhsgۆA#riLOwTP}[Y>5 $ܜ~kKoh \ŝ;J]wr 1 3t@M-쉳Pc=g#)l|#$];8?UJEÂSr sM\L>w4x6=CbiyyJ3@>ʃ{{tIŸE=12d-?$C,ypSdPw6 jˁCjFε1` z9Mn̾nꇪS8k䅝;"C0}aʕBw-ۓ-k}\ lDFw],= ֮8Ujrl80r2{`rw]%Ֆ^$/|X(N9Z.oݞj0;Z{gg1l|&2p9C'ڋ漪ݸ#,LQ\29!z ؗC9wvtL %ty#3YTﴵ*uhC ;p+%;&qp[)q S.@U>VMƹGjmOż!T-`J޵ƣ;x S8ޒ5?X;A~dYtt[/ϘܘZ"U~Z\o r0 鶻6\"0K=r$Ois4KD|'Tmb9CݛY/ ARRlϗ<_뽒 qaPټx>?˪*ߔ7#)XPb8כ0N@q]cXIM2u0`ȑsUi(r/~HrX~@jnl:YyX$ ۱H_hܿw`\;Z/{t;$y63Vb`@σ?K{kscٵq '*/k02jx 7ag_/ |L^C83j}C  ^"yݛLL;' ^#䀼>ޤca7&]B'=CiMTSj 1L(y\Bǔm6Z'!84ޘP\4Vp ,vO[GQm R]@w /Lͺ^a,qii._`4ǘ:B#);1PüoAmsL.J+1D֣(\_KEc x5n,pVld<]"^R`ιUg#zydo[$pI' "!d1KJW  3w4@!Zpi7* 䨼ɆPþoMÁ g) b#əKk"(mG! M 1rp1oH2hՐ 9^ ʖB<^/o gU$nA^n> P%byU0x$@(78%N@N˃a+Gl+%fSm)9&L9y_DxKwvqdd;[ykE/b/3x`R:9RS% V50H<,eqy 1-.P~}}}eoKđӣs*}%FrYIh?N:>N~ )t?Qp,vKš"-o| hD `]*VZ1eCn䴼M}t\,y`'`AiH k,;R\cz,%xhd [׼S4YwCmqeyϏ]6q,d_*=1V}t$\ gufܼoA/j) 9J|S )$X {1gGU]Kfiw/C*ȠvZ qP rj}eƴ:f(ݝ>9QLU,c؞c1Li_T~asM q(ga׼l9:ǻ !ey^ɣ@LBK]hoi@v B}ٽryFVeRT۩kN[=ۃ f\[f?R`5/́(z}”uߦ  ňfĴـ\ ^H4Ԇ/s{LkZP y|[u>̼V̮٣Cd{h]l$'  ds_9 `2O"UEzy"*PuS-/`Uk>DP;o3ܴrWER/_O  ZCky`?dI=g*S:%ȋKG/(PPHIP=q;0W}`'u%`Ks-"W%/ܑԂS7'|g`7cr 3"#Ȁoח>$u`i+0x!"j 0-rxUҧ280 Ûv g N R}\ި.o>qO`{+\90S~瑔ҾeI+00Yksc1cTԁ?۷]ҝ kmCW͔iEoRj`pLa?4,v{ _x$e`i.37'|W`P֚k9!E=_Ʊ`?#2N"1ԭqTN|b#)Ñ9oNufB(75byvaRi37k eoJǫ|~}D\ 꼪ZK8^[Z LЫ/X1=V**ʷIчmϗO)ߜ}AD^BiA0rzܨgTsrx󩽪5J0x-d+U#CEGRp}G YdPᲯ^luj 3:=.?.Qd.)P5_%U t$Ѿ|L /pGֆS |? U$ZR挏W#_NFRa 'aȠo"W/uѓr$FgN\s5#(ﺜ{q0 ?xݟWHGRo݆oN݃^uSl6*R9qrǫZ`P *ȗQ>l|@ۑ}c )R9{ MX&d942Uљ<$\Ƞ'_3Q>ҏqÙKw0hoS7ch8@C`o]5}q5TB'Y7d?@|&Hn}79C&⍩d=8gOӄ(Ia}kg[ˀݫĪ2gʧMH-v`n탃5s|hi`h`hZk`hZk`hZk`hZkZkZkZk ļ׌gi1TPhXh?rZk`hZk`i?ǿ͐}J0P?~e4C)00 ??tf>%V៿e84C)@{.?^"Ck527x!BklsF}=Lz.SCk NOr609@Tb|LzgI˾l2 OS3dk }7Q߾M }N0,|vx0FZ`MwC'~O ڧʺ-]O'9$v'Im].Tnk abrYf>1){g'[f(c>-nZ˺.J>Ck j7z],k3ywSpm3Zk Zk Zk Zk ZCk50Z"UxIENDB`openttd-1.5.3/media/extra_grf/shore.png0000644000000000000000000005210012627373446016575 0ustar rootrootPNG  IHDR 0xsRGBPLTE 000@@@PPPdddttt4bZQ ud@_ {=|-[\y3'޿]X$H;`䦙4L/@*yZ-H)yaaE$}S/g&`\`Bg@/.aဘThՙ/ <$cL*]x"9e:;G2^v\xd4<" : >D^i{J~C1G8zF W F(`@S`FhaIݿe|tCFȮjuD>^Qp#:8+Q]+gO/0P//5#P{ILj>|XGû<Gn!écrp8RV{\p 7 x5m_$ ~1@I߳Bs =y!/ s*]h-yj)/|O&/!_\wE'T!Y7dz 8ɞ,ߠOƾB S{#C?ɻH%y<_g1 R@+ yS̖,p#B~INI6D_5 5BǿZƤ(d#3)`^yl@ ޓJPoxhy Y=ՉTL0bcQ d=|=uR ?&SA$aH(##̸Rs :؆XVDVKXlK YR $$k!Qak7m[>}(3[ }QHyHB2?U xv` \,k̪x\8z&3SnxK #?ч@AjNI|T &KFN~`ō$VW^I/*̊B?Pـ2LuY&]Vgw"uEN0́DwP-.w/k1݃hNT F^Yfl*Ruن8S Pe? =P#xG%G<$"/h13)?A< */ևjɂLF 7bӻ&5e@VIG.9W.ؓ`qRGmCfsC"dz`R[aUŒ`p;&,˭ 轗Ӱ#i,6ghICx$PvB !9 noa3 u1璯II.V91!,N!ͬ2aR{ Da/Cc?9X^̊!D^F벂!v2zсuo"0b"_I4ZG:-_I4=ч*7z~۞[pc /L itb?na0_x>/ y'@^bQGQX*łXuV%<:)zJaAѷE9$y6 mGʖ;$ubM]y3d !s]T:bP I!Lbp* -WKĉPy-y*=qDi.^(@E#O 1)WMNJU0&)-nGZ!sL?~ܚ[ *?bاaHuf U8hxuQ}ajM y )]") rWe P ,qQni5K䁼!o40]pj chM*E'T: W#Xy͚=e\wPg yuK^Kv޿]4*G9n(dx"2c pd u~IpfbRKJr擃`a"qyAx  @xQ0'ChrTy+Þ;N +4x)LzR1c%q-YZpo5…$ āMH%[^%nRouٟvIgU"o; 4{ZT,v6,סjc' 3`)? . J^W"D?3|%z^rW_3D`l1a: #a%ވDe}V\Ԥ|)Om|ؤufu\5F7*?@*' 8#BXZ 9y< RV(:^*)Y lɯ;.ͪ(4A] sƻ HL.SZE[iނ[C-^K؏;m w+9$/Hn d xݗ^1ix;zc0kˤZ+!Mk n;±jͺ]\at/M=W4:qӎ7VhWBl0 xNt@r_ ضY*]pU@nlX`0ō!XQԤoi ʽY!7#eCD 8ī7l$`>һCw 0;]2|T\vQuX93Zbg\y+[y}r<օacf+WiddTWڲ,?0 }j5Z%nsHV xs^Kc79ou׋ IDATJ/EIq5Ֆ]+/v!7H ̻Hۯ\ _FbJW؉SD#v.X`AS_#iHaE,Vr54M#R%/qk m5F FAgz=`x@sK{,qu.[[.D`y%@"k^kWi6%DžE{ؖB%54V< I/pg9㵤4e#p0: 3QVcJLɭą%l\Vd)O$?j֤OFh0L&_?F>e'7O?h<?f[8;Di} Fn!ʝFIg|:DzbT8̫l`:92U>O=^,hd7;O#0v_,qi^htKry$\eyIUl،b>{dZS 2*hAB]7;c;N:0;x`vK40ia0 {WU6ODaxёR~[2$oK>e+9}/>jIhW[(G"/YI¼`Ys~pi?0ԈLu9~54A xvgX!rYn ƜIjVM@?%&"am nJ1iyESՊfp>pHD@/c+r$:k,!ԁHw~}gGyUyX̅T|OUץ8.Xmjűjj2qW):Nu*Q't {H7p1V]oe_ўgX]DtU]?KW[n/^-FD~c!Mǣ=ϰ&OSv+"e^rtM|wWzuj b7<^&((;tjzG(췴p: {_hʏ3a  : fr$̵ @LF3͇dXVĴ(y=9p/6  䲗VĴ=*Vy}e @LӮ @DkĴ" g01 y,Xy Ry]Ώg01(Ǘyw,<iŝ`?NĴX \G  HkU111n0 @ @L34 @L34 @L34L314L314L{z% "I_Eĺl_Ix~ ͆D3WAzBjNi֯Bg M(;4!zO yWQ0VAw+ۂUoo޳:z9lER7 }_s14 @L3m3'=Kp[ jKZfi<>WD׋E=u[Vv=U}b'o^/Q?`o;A-x8vHの*yӦ_r6]=h k/Kw:i7@{7-<6Ou)ѿ>)>פQG:==n{  SWoVk-ug'%`~n4=n{0[SG*!e Yu-&KkPh2lG4+hyf[4[\^in&^;cydyw.nRŕARx2~JY{t 7bC[A.(a<`!(x#ݿEz:F=n=(] I!*,/! }ܕ)<[:| !R8hWwzq,f>jr^{v{P/7~Fr7D-S-\!upͦ/\}RbII)?~W4I4nE<?]m) eX$V%A4tx $BdȲac VkUSRp{h㞮D> ) 3.]dҎ*ǃADZ8ϧ1=W[G1{d#l8Vd0m`lߡxoy!']Y$zz:Mk yǍMh-,CVqv"5ztV {lǸWƻE(3xf2zWԂ^1g 8xN%C+nˋҏ\0A 2ՊVЬ>R4_6ِ.c$qE\0=᪷rEl^ZBsCV-͞\7p Kt~WܸV+2  혌; Bs,$>JPs~j5#RTf ' 1=Y _x332OVjlGyէ&s#/x]~m&o:>5(&QPdpء0ȯWM䭷 .a5f=Fר5Ʊ ;j|6ncV;Lp(b8.!S̰Jgj1P+>%&}f3, >*J%F[\fgx"ͨla_҉Vŷț_2~5[0Z -^tX:oF|x8٤x" ݚ2B(n*Dp q.8.Y@ܪ)z(~!h}T-b/8W& ĬHF aQaro86,ZѾLUĉ-'񥖳Ьyve[ݥFN:쾾!zIAc<᧪dB\ 1 hsr^;xVAFZ^8o<4kEYUSy+`LBC)UH2Lai"7?fEJ/bx+=޹My"p'1^<%_(tXo^כ{HdoX2 V°hGb|h!uZDȘ,% wIӈQ =(]8v3t/9f+4›[h+ c3A.=>Fj*h1%A*a2hY'y95BxL~#"H0bu"Y!c~`3v^<֞j%|S^-h]ZIO^էZR>6?-6>R_MLƻH7ǫE܊L +N"~:wMRm$n$maYS|B#~V6 Ƈs,=Nyٔ6+"q9}Hs? n%Ry2Ql棿 h[([?5zy ytV _ӬXE+L+.,I'׀s{gGj9aV ˆhD%e_bӇ'| t2FÃ|la7uxXؔ}(} wJ6Q]B^<O1gSl+*)L )*5y=&&yUV q)r¬حrTTMu7.m))}p0r$c&\3jL]&L1/mM4Uÿ#dr@,LR/VOX 숼s֛udL +ڝUm1mZ.r+0Fg,W, ЬC }Y Q/Wl3Xh< ,U9Xb3d/wrx^1BX8p;AĆzi񎘖m XqH:lUd>8[YKDP CB-`n!Cö\Ρ|zb8!3IÒղiԨdu+^QĐMHGyoafg9ö/ Wf%北  bD jpaؕcՖNe͵!4Ԇ5j߱  ! ^|H(iIЬ#C2/ƭب|0-v~5[Iq\]o#1nYY? B"+ج"2G k(&  [5zlH4"F?{PRsHu^~Z%mOK f | Ԥmj动T儰"M[P,>ܹn Å5>E 7V {"IC э+v$U'%eн#xv^p]ˑߨ|f e/GJݟSѫ-Gy9ۋbe?n!_ukV h5-y1l >7ZV%0j4VK@ȕ$ gk*<]-V_ۏSK,?J"O˔0P%',V([1t!VEZ͛&Mj kEפ?NF?7zxh8z22B<~2s2}'i&‚p4K"+Dv@JEr1B]~Ko8غ# h8 ,j<,I"͋ꃾj% ,^W⢘1$LE0p$Fu-^71 >ARh/3-Y,uEƻ*3sռ;.,zlynmY@|Qv5{HW9[gy<@*8ݭx_TIǕxr-|ɍy R{" r%eC{Dt\[UWw+^Lf֒gu|t}Gђgؓʏ m ^;Ĵmp<| >obV maA_bbv eaQMebڶ Ua4hb MaDt3F3dqlj @ @2}?2Ŧ  p3-Smb0114L314L314L314L34 @L3m{pƒA<U/夤wHe|>F>?YfimhsCM*qnk>;^1+} MxΩi<>Wko%w{qO>] @DVUgzn:mL>a@ ܝ.W[CWr@qu,GG{Cjg0\0qsmL&ㆇkl(&'l_מc-/y w,x}x+F?0BuKԿlz,H)( l@g7CC1"Q]Е!I_E@$+@_*q4aHDPr'loW/JO''D_>}ιRR}ttz=q9 (fY):8-0&h6Vh/ߠ JRf+dC=a 0Bh΢6nh'P>9Կ"'s_Z7sC,+5"ӟ>=-4#0Ow|6K W')tB)5|ya 4+|Ea o,}!}E?HOn|pI D-~}AI'c$7ŘmF{K)g0\])4+.h&Qy"aED lWhDd)7x}a2>ĚY(kL>5m1ИA_aDp}! w2!B%Ǘ$R~淗"dxD}c1,zlQ fR,`oPCsƸE 7묬؊c? p2u'xVʈ8O!12fЎW,V>~x3V}x%(]Dż1$㲬 rK+8`ČXvv2!GO P;9IuUm(O5?p|=(?<& ve,kl¬xǂcu#¾Ȁ'M R4 L! 5I<K8W?KpA¯pyȚSWo> ;aJbuA釅|g΂oj!d;\\نŐdޭ8#sɚ haL{lECo2a|0!*f`ؘD$XbU,ȵYB.HӋ$Z^yt/srP2K),yɃɉ@@Ls\7MEe,p&ʋ4jMF*$9bW'>6#HjN>8rv~5cCn\y|D[ՙ,x/ 0/' f]+|,f-[Ƀ//nfod!z;=-Ep,Qx.C% >>q= FWQtq=,V4K#34bVd^ ,ȪOsڬNxNymN9d Wv2y;*ZRׅѣE}Lez>?Q5U=·5I CpƈCrz[pqV8؋GL)xa%Y8WdR%Eؤ6)Hڤ\VRr6+I4iDRvS4! axL^SkHtl:ϸ _#?;.Gؗwn]MCJO bD*`RUlV? nUO3l_NMKZ"dM˟σ0o tAّX͝ŀkb)WV&VU'[za\|j hh4FFbڠw)~IS/2@cTt/#nx,h3:9'-trT&OӞ`'^]@ bS<9\9<UU"PnVt1Y_jcƗ1= D\l\yÖmH4z ען=Cm y@˰~s}&/<*]a(rOUiA ``LZ*L WEb!ͩЫ󳴝n(v3 [6'Mʑcr@}8 1rD xp }=#˃X@fkny&*i%Yy; )ObFZ\ާe]*O3);6Mzh,,HZ5-7a>cN]DzgPYI3® փ2±8\n~E3OŌDl6kc-&HWynay 2*hA* lDgAAyyhE\>blONJHAʍwN'FD@ *BTYS=\'!Vzb[,K?C\8VM5Z .q"u!$Zk/.ҀϪڤ]oipyA E;3H!* Uwg 2"mbbڞpgy'4BVhQĴ ;3d7yӾ$`b @L?`byL314L314 @L34 @L34 @L34Ӟ@OR@z 8V 4j4NʨKEYm pV}Vôѭ:Nc>L>Np 1#74 @L34@֬ {S$zSި y֮3710@{絴) k9 )%L#p?gbZ1tjFQ@Ƿ8gG۶& @L+<{v),k~m$E]//ڭklٿvrikUK' J^ xG2΀_p3B3@R^{zʁm LmE` "E0'Jُ0}~'* -wg\ڄcB@oҿ  -'HAL J̇~HQʷV;9`t#0il r;9i+B:wȳq<"@f)A`x3F%C ),Hy+xEw|rzzr|X @ @性dhҷ".CyZ _2*!N\^jB~t#zՖ )}[O l|]DmO @ @f3ã$ Ԅ ʂ%iDk.KuDlyOT\bNd>#Cl:(ҿ6.Jos3LHd6Y3qKRLS͋*`R%:AXӄ_+%^{Y9xX?N|6|"i$vhg ӼHfɋ0NgOsI xVĄW/BUrPXy9Q(4',4?.@޷TOJ v?Qlysj|)tL36x4#OYZ "WSzC\eGjqY-o1Ns- y䃴<<IZ$ rOZGG& #/"O^\uc6( …d?>Ts>f7K*y]`Hϧ%JbGQ>I:WX䗜[LŽ @~T(tՒ˃ɤk+BH∠y(. "X&^ %hg'?GA^==`4qYW/O~S՞ϤXX^A0hhLzWf2hdVmhQ9vRV~>+dhrڬ#ǰ7<&h2d2=<'È&///?'Mh{.pRYr:w0 Y9J /g>!iжX?l}j)K@86ZR^K~˫dx^wVщA]訥J f+Fi~LV88JzGzMj)u!X05ڛN]ߣtqdv}$.حn%yS^ʿhQ ixqyg`l0FԿCyX5YV 9(&}Fb)z;e'xH9p p^:eZ:Q. // -1 * 0 0C "One way road graphics" -1 * 3 05 09 06 -1 sprites/oneway.png 8bpp 34 8 24 16 -12 -8 normal -1 sprites/oneway.png 8bpp 66 8 24 16 -12 -8 normal -1 sprites/oneway.png 8bpp 98 8 24 16 -12 -8 normal -1 sprites/oneway.png 8bpp 130 8 24 16 -12 -8 normal -1 sprites/oneway.png 8bpp 162 8 24 16 -12 -8 normal -1 sprites/oneway.png 8bpp 194 8 24 16 -12 -8 normal openttd-1.5.3/media/extra_grf/airport_preview.png0000644000000000000000000007152012627373446020705 0ustar rootrootPNG  IHDR jsRGBPLTE 000@@@PPPdddttt4e[e`%J^̓eٙIi=(үx_;;5ar`]1o`|oFra_RZB6 3/{{]|Z@삱k ƞ.{`Z@삱k ƞ.{$ ƞd/ϵ ƞ Q܈.{iz>Dy.{!WZ@gm(ǧyO0@g El$D',|s#G8'W2Ez[<>=C`C҄K ˋ@l EGME&.,]/ !܅5u! 'ϡp)|rr.9'MQ !<&K $6~c| O! e\TC 8 TBD>'#`. x4Mxd{#Af˗_$m_k &秓wHXAVAb /G A> R Lѥ=A<\j=; B$(σ()) `9 O :cM. cUxJ8𸽫wwwv&];ISL _)XI  ouT:~5\=Î8cDp q)zfܴ>(Ս2J ,g r<\{.rWw-vt$ XI)D$"/;{Njm^?pUQQi ˅;|w}\]^s "e:R=dX2H{x~`%bAm}wڨD:XG~5ni2"`F#SI%C߇(aE 7xedxYt`}7ڷXXi3iEnJ.¦SgLr;~FP5TqA'@.L1${r*{ȭ|ؑ?C M;@xd7Qp!uXdn^)VEz |4&ht6TNs.;2KR,Ȼ\'$ +K<"QX+CAOC9;DѣAT1zi"=:3@" D221s0Kx!>.k kB @4-я)4)J8O4/x0lmG҈㴢* Hi "b#w} DҮn`>|FF@R,dR,1 9( "':1h@`pXco z7з)f+o >Dar+? VPDcDpu{[0/ǤvnJ)!Q hnx])(g@H w'@(tZ`A[\r%t!X6n8zז >T:ͺ^$AB(ϊ/2%LV]+aQ(E 2x,$)*V1ykB="H0H٦?] @5̽7\ux0m+"U@V%FRQq>M%! ȻtEh FA@w"K!pv1̪UǑ)*XLH⻎lDLp>,ڽ?#T=1HHro^W)]V -G6%p7q㸫p ;*b-14{"&Y=,=Hz}C5?B{|u )X X@y‸np@rChk ya \xL ;^\7p6\Qa6=D7^(!=WߐX{:FhPИ~o)ŠV|A:=ݦn Gp!}!ƒ3N ULT;  QgA>g%k1PXYvo Hj,yX ۴rxwȴ\6@ix VRqpc~JV85 8P|N[ !ix^3A`?<8࡛/`_*ZyUQXŪ8 $!+ $I"ݧUX=?`‡%D.aJ7a8v K !* 0:`uEu]劬CQ4$<$S391x`@Run7BIN|[~1"A_\#H\D7C%$K.~G㇮Ax@f+WTbi `W0vI4&q)He^fٸ'F@}3`P~#) >2-3xpi"p!M$n a[*|!mS5!DGgE[3Rb|"yBj< x3Z ;|1Ei+W=ôG *)!A=&D0 -{-?9/@Fg'?ӧC,} H1GuA|_i BCL MEh$Fêiƀ' @t!DPRM VD<E4HS.kE+Zp)-TcŇEo%<1t9|ʧ Hށ$}/B_.!!i h  2Xܑc߄;,FQA(C2  <W DIAAMm,Tn:jZdx.7x 敫a`i`4b%=HBT$vV$N_&}z9HYtf紹CxH-%&Z\k y,&Bo[e q˜^?@Vc0(bOE>S)Z*(OgA +BŊFt[Ld%ôTҕݩaZJN&' M;+-wfZO?Kz l80׉]=by}'-KU~ 64LKtH`i.-wIrO^ BD^lGOGcz#Ay1 d #.#=ʂ\k 1I'ô7ôZ b%QBC$-'0 Oxo7'Ok~=70&j|s/Are^ b PЛɱ%DX"|aZ/AJ+w[L5"7\q2X<m1mu3vK>?m`d?\xiir_yk')O (5+7|? O?iZrZiCB@4@USE+(F*W쀏sp08 ^PcՉE w=6=X=LKQ)f!XJܜ4?(L1Q{ gyUXCJ_,~PD$ЈL|22kK} CF)F X^F* !#c$~]ҖLJh@ŭ-9 h<|@ØP>/2:K@0B&S]PВσ~jbe)!&~>(=w't{~ko1ҁJ!O1Hu =")5^>E >9cqIqS&3bjq>N/rj 51x@4-$(4+C8wvw+U.waqE6@mОaںu\t)aA=3@aCH;Dǫ)֛g`,F ,C<3sb=H"S(Kz߃|_CP!/#!7nE-vo"H|D@E2ߢLx5(46"KAqEK2\A=w@ 4@wpu zkQ<[)5™^VOrvniMGUWD)[2`UWR=t%%?5?3= !E`x>L(I[4ᷗ5#\zg (5h_cz^d}]P>)#(BBl]7䋰apBE+W!gx{C?'),pK #4sBxƉcUgi뺰cQ Dw,aSE>S-f3ޫvPa ɡ]8.~CPb,"Ʋ#5f 1GDN! +eEC :<בFTo57X`ģH9V" F틬AtH/(Vo8['ѢpfLLeq0]pG0C< `r:m#.ޢw՛iY* JO̧f,oڃ]17}&\>j *$&//0`\nQ! Ӿ5\Wzk|$ì3PM=AD/&"v+ZUqN:Vk40hK8׊SFGZ^a#iZmNowogZ+p6֟'BLkTGmТr4RhԋG FZ 0@@f})yO8R7j 鹯A߄HeFEj}DtGX*Vx:77:҈J]EPk&jKÓ_13LGMPALqdzļx ~iYD+;>)ņ]ro߮Uxf$<7Z$@x\0t:3(w|pσ@ȕ>fVR}徉%1l)/¶/J ݡz^њ\npl8s "hQ~PJG( R7 䪯)Al!FrUhYo͔Qn+Ma(&xq|ѣ9`H=Av' m%|y)N%C}ފ%&WQ(A<''_UEKOITw7 LSsWLAvo^0ôh(~t IDAT7ME.I&@e_]mغnv;rE$0!tY%X j:pb3Ո(Hf~lRw89&b S&3:$  #7IԫR<鄈I[pFw(̃o܁:PC._HO|X,IP9=J^vI%cOĜ-Y\^όzI]9DJI9(<<`")A^:lFm%WCSlc'"̍^L;IT"u[1uq@et r Eƿ: K4J }.MbwH1qu@0w,@ MD׍i'ݑ;7j;lܥ)u.1?.C5q$S.1 @&J/zl]ieaM#(rС\б\Ǻ"m8.p!"X.I}QL=I mWAq#uyVtxhQmt$@zA [v1io2ȟn7$͝d/ܸ׸H9`tg|]?'>l4hvJc9sqnyzLNoh!L]7fKZ=6\0c9 }]k/Nx>‡̧d{.e0J_̈́8uU%1NxmĆ#NIgoIMAPrOO]%J|An** 5yaWW8KҧD $Ju 1 u%7NRncZ:L.F6s|x`"9.=J| %Aw}WQ$U'?&0,4~FC|!i2 xň wqwgFLb->RR,'`RoI7U\k2I ԝIm8KoJ&TC7,L;;lbI4%|E I]Eb!jU4PaĴk^RxE:c׈놽CF)#liCә98?h >JӨ@Bj;k{n-t+W]I >Pm*Zm9~77oƵUŸViJ2T_?"׍4iLL.mЅ]Ӵ>!rZLYuî6̍L%l*Y=6Z0c^]{} _o>QDGt@Ե3Cΰ̕vSLg3_~Ӊq0@z*dh=QTr*Vףz/􋷼v8BІ'A&fi܏$^ qi?w:H>anܬ7kIjnG]3C+W[,\/=ƾ}<}tejeRY1t 5 K t/M0CXѿQyQBG;$ZO\OoIgG$~n>q|ͺN{}doxﳉ?n+OcNT"4⩦]Zlܡ=-m]fIj{KM%zc HrcjGDp9=c*/QEPh+Z: 30tm!Dn2L h) *obcz"̄lb01;4|e5 d,`[=A6"טc{e "jL'q8WRU*29Rj4C⸞mw/i4FpۨT)л04v8 VPL s3Yd|\ HKxviv YLO$9VwE>@/$FFiSy=-&3>ޤw*~b ͵csd@ =xDo8nrPD!ŔJ?tq)^ ѢING>uFȼ[}Y'$bM~kC7'V{s2kzxco -^sOOJA>FϽXy)Ɉ-{0ݥ\{TBN/ŔJ?1|(uJnVHuQs;]9^4h{PE.m->zlǫ FK5 ҈/KY{ID{V1XT (tE+Ħ^Q\i< %Z.D+׫vk{Y[471M@+^'8dZKwq^sCSQnw=`dTҎN) RF@Xf*nOBz)=pp]PL{6ʇ~ +Rh\iӤ t3s3GCmP CSyyǞ`{Va0uhzŁɼǜﱬcH?U^<|ȱ,{aTL5Xkq?\A jBw**se[ʴ'$&,=pp]ܫ@*;I*_\ࡰ""CxG#Ÿˀ1G 2l`F>{8Ђ)jDG}(ANQ(hFz38KP~=`FkCo[;)0Aל W{ E Z`E@oBC_?%@r_Z`f@̝r-H48k0C7=|h (q5GrW}ǾHaރ8@LEE\aaǩRE0ӊ'H>uX:\ʢ(^0}s{u_A&5'_d' Ņ@I،C՛%;dw4d$6w4q}V;R<)|' ..SČP!%8ӌĐ0n F"ky{+}7;ƬFNӷW;]XP=N`h_d}w:q€8U@r{4\<3w6MPwl$L,=, !Lz B&Wof_[qWI}w'`/; Jqw306,ĺyY0_; =<}G\0w]5qB Yz_ݰaje='eו,3ұ{2 f:_ ZGoAc.':Mxi66=Nl,͝dD jFAFR'G, kny "mLOA4vI^vO'`6}bbĐ*OD̄{5q f[@ EY|'a}{Y"w7q @6F :{pd!E`2@ek)0zO 49im"YV=%D에lR~J$ɅD$Hx~daa 9@prX@ƃ 1 )/J!M2Ѐrt@BC7H$ > #.- >dHIɄƃ3? "BqdƟ FV?ڂ<\J'<0wp߼,?$"8pf\ eyTd kL#一ojY:8CTђ/~%ʲx, %ng :A +4J- +,SB&C 2j !GX0:z(!RhB"pQ`fy2 b])s@\QEC2S@|ύ[%I !ȴ1}]8w@ HZ@.шMXOϘb]+vNFq΢U i #*LhJZVruIW{nxm|8d%)$S|Ey dz-5JӤ n4*w #!rD@/;C<ࢧX ,H Hb ҕG:cbY|],xy 8,j[RrG*bD#+h-hIM[RpQ$iZ pMS,)쇻D8h=@i)ԛ6*_83I7|0`"WQ[:> IDAT=L+WQ -%=8%Wؓuz a1!:Z 4)XߗH*DH_GH*Qek#BX*OO t7ovVJ)zzVjgE_=-Y߃@сZ<1cHLhŅWBL'8^1{=b-Z8Ry.d Ї*RT 5y0(ZQ'bE*uNdοt06Z{R@pυ竵62re4biz)J3 "ḇ@b9x;C)nAoSKŴݮ]HE8heGEaAhxt5E43 z>"BrcQyNRMe(!ۀjJx&} eDC]g 9k{`le84)BbbzUg4AR_umL"*HdV:<kSHL7/]Z bb8Њ/ "R_S,b=RZr"R`{|u 9kR(lÇAFje'.;1"> \OXŪH HGA  CC0RtpTUId1J/srUջI1ÙW3'.D'H40)@ {1xȂ(^3J˼?<8Vf|h)VE!_0`VS[]L EZ!nhxdwRq—D3 Y 1x)QZun7WhվHAV*:R| NUV{:x Gj_<_ "lz)S4WzGʕ"B(4Hȴ~\Ѱ-y}5tGGd1R+c"AQ"&B@*gbMW`8 #yBxDD\#kpT'ć0r"AH{LVi|hc9W  _{yY5QjP ǾޚlHB(+d81+* sN.\qqZ8ZǴh&њ Pժ~._PȪy[R &45ٴ/r6\WۜS, Vʼn׾QLb5 ټ fD+d"Z_P_`(FGd­TIO"d\Ds,5't Ejr犈{O%1#:9iLA׏.VH6AQo+%ltp@֚XE)ܚltZ659vEcT^xxZ,mÅS֌)%f? XT*Ȋv{,ZokOZ|N~Sor=QjS­f|HU._^_u(r@RXЌxpQT"7ҙMp p!r˖m_ڭ[N"y Y5ٌ/2U`L5]NvY2!m=6Q\>kQGDL|x)QK;yt0l4Q/B)̭fS\:59Fy3MEqz춢ux@o"0X݌ړ'ǏŕZuLDlwl81/ܭST#_feUa,X'"d&ca3^k6H4 hTD |c߯KZfb\ͤ3["ߚ$EE 5]|CxﱠҫzHq1x1_t}9.i7n5)Y\0b_d%) _`)j:٩/rh@l"0lWkZ>e>- ?ۍ澉Fk:ҿo /~Ygaj+žHɭɖHMQ^i}ܹ/r`@o"0l7kRҬwݾ.Mf>IpSLZ{@j&uJu/Rvk"[&d ˣ*7>˛2U6} l}M&_s7DX{`1:l:ޚlռȖɫYbxQq/ȁYl]ט4eu7Y<}[)&&Z>Wԡd+_d֘*5y /;\kp'>}j9C|Ќ"X,y$Z$nb-c6uJuYpkE6OMd r }#5Ňd&fExЌ*]IoyV)fhh^Y`/ 2V%+5پRYz 1SqUa Xd&8P**:H_bQ9ӌ4&ѧ0ˍDiR]pSLHP4o,\0犗}-V%+5֬H=Vv,|L"p*a-:H_"8׌A?DkmQDzf| &=&uV+5c֛Ym{yuTxEqHJ#zQ],/R`֚I[bdR[odb֑EMƒf ?tikK"у5!Js%&[zf;@V_|gTo".%x%{7 .EFl Z{|MkMYЩbdoz /'/mvgtn"H45I8(k\ꋌpF5;_ZS:b.5Z#۴lA_CP ~zOhb&eԂp+o\UgHywf/2NoM7Y9io{l> :Zh,och#S6="ˮ: f0_ZpdxXӷ&[kxl*k[cng!Do"0%4Q7 .EF޲unLW֔ "xkGl׶"}151Z$\G46cG;XNɂ)W̏ "kdۏHM_/s?zOBdN3]I3]_Zc: f_Z3:,EfS,}kmFJM^#7+^+Szf<:Xz˺`о}kTiː?9OO3&|xu"}ck#5iY,uY3˙;ߣ*  -פen3wkFNMlV}XՌwHcyj/dld}SIFY}fC[.R-|e&,ݰf+DV_G=ND$F3|Gh}^8u@ ")Vh+̺5Ev{ eת^}_hJ4xՂYZ٭7@_{=E eޒf\0+S";=H8w<"x|W/թ־>|2*N8@ Z$mKV|$c fej/cπUʼn"qjM7JRi5ZQ|,ƾ|_= |Q )4I 6-DǎLYjQvR=(& :jxq$I#mI=v`fRo=yx}}Ex = o%|Ѷ&=v` vǼǑYVX>K{ 9MEZ=v`b/Oj@/tQj$Fo58\ǎN-t뱣Y>;z F2o =v`pQlyCdn.h9:Vi+.\@ e[z ǁ)/χ!͕{e}7|BQd&{=x5?ﱧZdc"=+6Ѿ>Ū^W"=ysdfs^5}ǑY>J{/ SC|Z2H|q6^p_www?qD@CGd9^HW8Gd}>\-b6^r_]拄7){|qހKk~zڿg}RW%oT:qt@}>N8w@xzۿDI 8w@N^ʜR?q OFQQx 9q\X@ζ^|;s=j9?@Z/{EJ2q=j9G@X/?H Z@}BsHô(|9J@ dFQ- Q_=C'2j9QT t Z@, `nkX@, ;9nkX@, ;9nkDͶX@, ;"obv[k, {`Z@b{b{X@a =a=, {b{b{X@a =W@.$|"xa۾x,%6.l`# Ab5vj{1=, S,=_ibccb=_ ]0|- vcb=_ ]0|- { ]0'sa|a ƞoa\Y@삱[<n{Bb9 0_X@|Ξr=X@, x>>@{X@|!~:" ðw(b^!rn |E`a !br+)_X@, u?tuQRH(bNQ$(TiQrVyw8Ek%QDW"b?=FQDPQKH0"by=`EEYQE\X@, o|2E(c;D, 3:_("Gxt`G8D((E|*8Oɑ7"G>w`~`j)FQDHޣ5;#"Rp$ D9Eӷ=4}]i\Ȼ#";DJ1"<7u93;$@ӏ D:QD=nA@˹,Ipt "sZ1v7Au9q BDBp>,ӈt%Qz?x`vko -f)8 %Q$XuEFBw.Ec`vm b & AE @qAʛz,)DfW"oIl>xp !<8"=DPŧs)i%QęH\Ƴv`H\8 ?j^C1#ENEr׈TT 2xC)`Bd +!CIG*7[2x@!狜H7ȣH|[x^O*N=~x$$i0A)tH^E7\ ӛ뢓+1dCG~-S+\.[т(y-9"Z` ցF䭉uʕxap=@EkO L{Ҋ4IҤՊ9-!w})/\IyE㭉uᴈw0iǾ˂)_UD[I@J1h :{ADzU@@{HR[˜Q .z /О"+(M[8i%Bh rT@.Dwuj|:ߒHn_e$ /pav1o|,8"@ 4ӣEZO<6}ǓڵN$4?@>zl >+9]>8FX1o/CC D#} 8Lk.q2EDіgH\"ұN5yYu(pxË3< IuG_< !\O{3d7ZPD6|. ѢpGĕu"ŸZ U=k\.D@ʵ qKx\*}.Pqv0r0aHVkh}o<5ZC7\(z4 kE"r"}}]L{wsNf WxO!k@+=iq)eۅK]W~Zug-"ͮ_F6 XLOq {=bN y)O:yUoyg(7%'P]||8$,@xNo VԞ1`ը!|]foAk\e Sj=_*- h}o xҦ@bEBJR~N5=/!4To3u>ϡ(+|rr8C޲ηCQ.>f5HR8x2AT3,DJ-"z//@^0hi{Te[|Xrh2?/у E&u·-J>i}`YYÂA$i+v IChqZA٫~ɪZy!b"D{Gk0+|}/=C<ȧE.̥[D맱~^D,|x^tҷׅ:G_ā?0zAt(=kη3Sw7Zޙ%aX4IpN0ONR^|l3rA\ UIaѮ7>b $+zu %-_ PHr#O+zF8|H}R/"*=UϭТx=W_:-xSxGuv%l68|c E06L=0S>WeDA"G}%VD~gAů1)^];g ȣ:ѩ+_aȟq:p~6ybt. [y>N8=PL$ |Sy>eL*}j 1,"N&#`1%Vrqk_C^"$7xq*\IKYՁe9|z0gJu N;>{XXgٲDO#jrXy˻Zh'IjEU 06uXa:|$ jN:n i%d\;&E\_! f׵|^qh|JAYSOkգ@V+ݹׅf@rDkD_+5uϯއ~- FdDuD||U&26,o)~`:ZԭZ$WB?` {f:5R+liUBpc\CqD\_vzI@, KQL[=u+oq'AB~]܃5s֡}_kxCR1t?=߇FE|_V* >7ѵOm|F=uKoXiz=0)WMeo1^6{-oJ=uZ$_}?y#KxL!51(wYh?_ "HR`EQ 8 =ZD;-"ɥ(RD_~_AZ~]&,#,hϝp)zO/QD,nZ<,7WKsY"bOIGOEZLjឿZmF`u`?:05~ӟk k|bU3-Cȝǧ=S;5"#=~oLBErTk5C%}ui΂~]XߣkD=\~ǁaHAח/uEcmw=\~CBgΜ\ko3@H[npD{2&==)"|2E+_]߅ ǚx8 ^WoS@F}~~+K݋ Bt٤%Ϸ1 ZĆ/suQ^W=ƻ!/'XhZ|2EG k%qP@"|"KUXq`Q3>Zʵ\hA We@&hir{ N"<1Ҥ=#Zqp@`(S3^-kCEC*ޑ:~Z"+HG ų=EC.tk d:,ޅtxF=xq9<:8=Yz*wkṱ:,{j<;[5TR?r;@"كlOj<;S5\ SvdeYq'^rd@`4{Lw;h# t{LWǝ{HEցr:n&+qG~u`o]ǝ{HEׁDKe{HEׁDS="jbJ ]{_$ߢ ]Q@@]Q@@]Q@@][@@{  JE=x kB?18! nA@ w۾b|[C@Ļ]?E[C@ĻM?MIsx|`0^E@x|`0^xA@|`0^W; 8p@@p@@p@@p@@p@@p@@p@@p@@p@@pq82IENDB`openttd-1.5.3/media/extra_grf/flags.png0000644000000000000000000000334312627373446016556 0ustar rootrootPNG  IHDR FsRGBPLTE 000@@@PPPdddttt4jm6Yi=B8sS*BZHcErq: jP\8$5BJ5 j f( MMAXPlϺ4JQ ! K( ;A@ h QWiWW۷~?0{<{5ZcL]׃Us~_慎uz^oWVc|xy|fYox,']eȶ|<"a2rǓo4>kzx F+, |¬q /ҭ12 i?N1wd_# טA~.>qTיMv-*Xx4ߚ6B{G-ry24DfvR+// ^1f@l[ $dz<;#_P ?*8b]f4@J+k5N_S#>B$ QHٗD26xɗt>?K8C.aw*{:}^*޳(uA @ @ A Az0.6gIENDB`openttd-1.5.3/media/extra_grf/sloped_tracks.png0000644000000000000000000000467712627373446020332 0ustar rootrootPNG  IHDR 0ސ\sRGBPLTE 000@@@PPPdddttt4ɢڮ7ȱ+̄d-@dޏzՆ+#@3^C Y7 9r}Qќg#"G?#Boȥd o!|(P)H""6 Áۂ 7 :f2 UH fHj H݀xX(΀1| 1䆉$[8RvN9a=#%I,p fRܶYqbB~J; vYg4 ސB3*?O"$BHx{)ɻ pB߁c[J;d ռ--٭T'U{"ppJY&STc- {eW{(IZ{,ɯPͲ,"&ڭ|Jjdv a ӫ$JYr_j/[{U-' =#UzolN2ѫ*BHJ/*~4K"%idYI"łkQY/y繆 kmn^~ԃph Uj=~@*, )?o>Z&SI߃#WTl"rr;.o{:R|YAvL µ'HIUz6@(lEww~- ^}쩑Lķt}#Uh>[#$y#ROܝHs$*~z:Q^9j64f'ӫ[#{*^{zXl֤ۊVj@r/"r= i֝e{u Ͳd3p$Ӭ;B+]@*v/s2٬tn~­j,IϧW6W*G>ڬO?F$=)ёWq z>= H7DtW@ȐRb(Ӭh};uUPez5" P$2+YP)vZc H; wo"2 ~uG@%^I`4@ (/[ HK> ج|=# Hfpj@;MGV@jӫYY<< MUW.F]lCp,Ӭ7ynq9 r/WWYy2 ,W|vwD@ԃURh56"@v D6KE@vW HH "!!HH "!!HH =OlL=P]OIENDB`openttd-1.5.3/media/extra_grf/rivers/0000755000000000000000000000000012627373446016263 5ustar rootrootopenttd-1.5.3/media/extra_grf/rivers/arctic_brown.png0000644000000000000000000003526012627373446021453 0ustar rootrootPNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPLTE 000@@@PPPdddttt4@وé N;H )f#S 9_وM_'1@RjxtSA@RM5<ς|v"$%K+`79x[SoҀ4 MIҤi@4 H~~'aoN, g#YI(qWr9]@zû^K@?W]- D@977vYE-&l/'?Tb:Ao?Z߼~ HX @Jm7 , ȋEq[H%HT~}́BI36d B4lPMVVpLz+Wl]?>pvzy}B\  /I%'/ `PG~A&#4ĤBSJ`` fvB v+4 ج7KPk pis?0F[vB+TVQ1VNAcY0픷P{5faz1m>S/+Yy3 |lk]qWJ8-~B /v× +v~_HN+Nla/b~U*V6?ʀ"o@J*ͤw جbQ@G8E Ris3_2 穽C3_}No' 3@ AzK)2.˟G3} ÌƸA+@*I+\Og--U o\Ke}U5n@.KQYE`(e| k> 4X ǼF(WVqu| )ې~YU)yZ laR 釩r]죌mFrδ Ay$I?A{7{w.Q `b‡^߂2bbFO^uTlI`ܧu^dCwFN\i@sE|} 4SO '@jqweϳgN=]]>ԃ@sH۠C"ФVr?+"7b+_uw8qAߺ`0ydÒ_]TȪhYgny̔/h%/6 ]K%^*CߵfgH̖1I)]\J>މ@׹ v'Wj&٩XrY*v<3(G=W\MuH@h ˹nQ d`tU%!v`! 9o^^̿v@s{hR+"4l%GPY9瀐 !bI۫zYjO^UhX2+z;zB3,h}mX''$u.{W)kYev)q0!:r8]|:B*\3@h(@ɋMlҷW0S׋N0Ɇ9<I⢖XR:{Rl3'0Bh+ ~S΋b Zn?̾_yӒ|URO+ٕS*6GX[2.Y1c?ƹр L~PJ,@H2@(Sr"A~*eYbE̷d7Q*7s ȱ?ÏxzfN9g$y/h)޼]-iҀ7: כׯ~3н:pݺټr(}nm3u} H43QR'4C @fOSz3{2$~sr; zm@f)S7So3q} ,t]w1ܗFɗ[Zd {6z3o~RaK߼f.m޹ƘPr[-w="nr4 .{)Qw@wչ4j #HfYo֋s$3^)8]4wff߼NPa\݊ap[,&[.u~~~H'sSonn.ٽf߿>|OT. 3͟>lB|?!A-;!ֹ˭w@w}rLr&mN]tܖzu'wa_rX~;@U3!aVˉ@̶NJ)rޞwMYLar U։rt~ga4R~?@ 3)õ_~Yob(nrۃ12sW7kJbxCOGCL_HJ0z3zsDŰe[14:pP109Tnnpq|"gHf&#ݱL)Ed;33% )]| +,4ql`haMN6 $%\M6q {Mq 1zsغ2{|j܃ϖNuMj๬q7yفd2K{.ߙ׳IIaw{']k와dC$ \2$~|y5 W gh!Y\sgp`35Ֆp& HҤi@4 HiҀ4i@;闋NO~OAL[ .o ,B.i:"XJbyNFh.F>x}') d8"BoaTp:{haѢ}V}r# c`Y= (bb[7O*,a8u.,,,I )B@B2Yp }Cۚ$s;wDثw'r. nIZiYz 2 :atϹMF, 1,"lz{#yǜ: sﺏ @zݔ"LiP7u~Hxg\@ʽSJzuM3; (<.qN K1[G81r( MfS+ܧKmg A@P OsD OHfOO_ 0B w>wTgy)ٙ-&֌ H+Xҧ @[w/+:Y4 (Bv8VB.gE)/yno/.&/ eP'}̯SS s0w]`7 @ > (a!N R}YMNeDDkǗtA#9(_X ƶ<_=an{V/:(l).vcE(TFDK:w |'9VFtۃAo_hŹWΓ޳x=nM9l 9'm);֛Rv֟HR|Ѷ |ʾ YL,>Y%rrZB_@zG瓪Q@Ru<-$%տ0 )q[yj/ Hz2_|a M& HҤi@4 HiҀ4i@& HҤi@4 HIҀ4i@& HҤi@4 MIҀ4i@& HҤiҀ4 MIҀ4i@& HiҀ4 Mg=q:OΒJ } Y8m}-#U"4.o`Xnp:1|`݃$B98B]Sr~ ԙwQ0 L&l;&ƽQ* lWaG&M!"9Ea׋BkG,"y$O*C rH&L$@@} >MVa}IOm&/Q@ SH_V$Gx݅ѩ@Hwrr(}@T/k t/+w4ug|1 ^>IHfιBmxtxmd)X,3GfT 8d[f;woϋ{]ŗAOvs)AfLKC<O]R /$k7r8f"ܝ*.Ty2\ A/ؼu^,r)>*΋\(qIGD /H&Lc"YV/:/rC®9gR=ܷw*#O|I9,yΥ0Z~"4:NE/CD^,ׇAUț:*ޕ^\B#/Щp*@^SRJ͡z@r6g'dO wHXʙghH iȹa`[(3{t}p^԰K"v8'Y2CRByb{yNO.VݤiҀ4 MIҀ4i@& HY p4]NԹ>myV+.d]\.Th:?_zx׽kW_IPjm U܅?H-Lț#PN}N3p[$`qonn f)^:$jgzYxzyYnnvlRM @|2@ʣZ맡X9ofO/ ҇ %A(Uԩ@ ![LYpho`p>j!y("O`-c(')7[c Ţ_]?H%HT~}́BI36d djc[*tg??q>a֛f". rTR/+v_ @O^ }@Xm9PG~A&rKp M)k4AJϱBsJ)jruR&"6 #c5`')BL?Ou*@`u"\,v[r0?㌘6yRڬs΋`>ȫR p"v~B /v× +v~_HN+Nla/b~U*Vv{e@y7y f׻{Dly( #"rM)`˹/ɈR0ܢv.ElR*+j)GSۦ9EpJެ"qʫRRpHbΩ0= 3YCJ HIҀ4i@& HҤi@4 Mi 8<2ֹ_=(oOS}uܬơn{jŐwۀ_aA0F! *a[4ɤ\ JF1 adʭ N!BtYsRͤrYNlGy0 Q@ ? ďf@@q%V#+'TV2ZZX я˫n߸jv{\>wҧYx< 4X ٽ+䪏reE[0M)ې~-U)yZ Խ rRЧa\}W.(cnѣ\3BeP~fOBD]A AXĄu"){c ?~ ڧ"H+zӌɺ*$0JS:/;#ZAlc 87iJᵧ2*pŕO\VԊߕ{WهY.jad ׹H$mܡS\z+O;(U~^H^RɂVitAߺ`0ydCtuQP"nyr\ELRbf[C،/w}v/!ʇZ=gЭ3ԙ-?cRMw}SV;q\VXaf? {Se5vʪ#ό# fӊ+&tvgg'jl[v&|uRnfOr5W0+Ɔ8Zbd}]v@p^ '[$F;0\ǀIoj*y.Ԃ=q|X6l%GP|?ϧ|H*|OTXM6Lan#Բia:yXyKl4s/Ԯe< ۬7;AŰe[14:pP109Tnnpq|"gHf&#ݱL)Ed;3_|YoAp}0 -̻Ɇ0RK=a)8>R7FocN[R{OmPoϒNuMj๬q7yفd2K{.ߙ׳IIaw{']k와dC$ \2$~|y5 W gh!Y\sgp`35Ֆp& HҤi@4 HiҀ4i@;闋t{ b*CXߩw`e*r0"ӿ8|d|}<ç(Xy"R8@#?^SY ELDADH3߇便 º]}@e$ 1{9FNBʃ ya:*ߢ *bBPDPL`p0&]1,&l}DNP%m^:I 7-K^o<ratϹMF, 1,"lz)yǜ: Txt"/z3]n@>8$M^enJ(LO*X,2B0B w>wTg7H_ l)4ifVAp\p>ef[k(2A!a̴r8+LyRˎ Z z @zep N%F&ʓa-RPv"fpP0,Щ>A /aQyR\s$MrH|a^Sc~yl+"lD^|q@ֹ@хdsN!toD>+-B&#αؼ|YyrAX$@۪yKp_T9;Gb&G Q`nk8iN!~9@&Lw>"\<޹)Eu;t8.Y>򂀤fwD ZO'#`Hݗ}Γ*L'稜~q;HMec'/0zXnuKx&I _;Mrʒ:%"3I5D?&g\} IB?9ct(d󴐭k':5joSMn/0& HiҀ4 MIҀ4i@4 HiҀ4 MIҤi@4 HiҀ4 M& HҤi@4 HiҀ4i@& HҤke}uIENDB`openttd-1.5.3/media/extra_grf/rivers/temperate.nfo0000644000000000000000000002106312627373446020757 0ustar rootroot// // $Id: temperate.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Temperate river graphics by andythenorth (Andrew Parkhouse)" -1 * 4 01 05 01 3C -1 sprites/temperate.png 8bpp 10 10 38 19 -5 0 normal -1 sprites/temperate.png 8bpp 58 10 38 18 -5 13 normal -1 sprites/temperate.png 8bpp 106 10 38 18 -31 13 normal -1 sprites/temperate.png 8bpp 154 10 38 19 -31 0 normal -1 sprites/temperate.png 8bpp 202 10 19 9 14 11 normal -1 sprites/temperate.png 8bpp 234 10 16 9 -7 22 normal -1 sprites/temperate.png 8bpp 266 10 19 9 -31 11 normal -1 sprites/temperate.png 8bpp 298 10 16 9 -7 0 normal -1 sprites/temperate.png 8bpp 330 10 8 6 25 13 normal -1 sprites/temperate.png 8bpp 346 10 12 4 -5 27 normal -1 sprites/temperate.png 8bpp 364 10 8 6 -31 13 normal -1 sprites/temperate.png 8bpp 380 10 12 5 -5 0 normal -1 sprites/temperate.png 8bpp 10 40 40 11 -7 0 normal -1 sprites/temperate.png 8bpp 58 40 39 18 -6 5 normal -1 sprites/temperate.png 8bpp 106 40 38 11 -31 12 normal -1 sprites/temperate.png 8bpp 154 40 39 18 -31 0 normal -1 sprites/temperate.png 8bpp 202 40 20 6 13 5 normal -1 sprites/temperate.png 8bpp 234 40 13 7 -6 16 normal -1 sprites/temperate.png 8bpp 266 40 20 6 -31 12 normal -1 sprites/temperate.png 8bpp 298 40 13 7 -5 0 normal -1 sprites/temperate.png 8bpp 330 40 8 5 25 6 normal -1 sprites/temperate.png 8bpp 346 40 12 3 -5 20 normal -1 sprites/temperate.png 8bpp 364 40 8 4 -31 13 normal -1 sprites/temperate.png 8bpp 380 40 15 4 -7 0 normal -1 sprites/temperate.png 8bpp 10 70 38 20 -5 -8 normal -1 sprites/temperate.png 8bpp 58 70 38 26 -5 5 normal -1 sprites/temperate.png 8bpp 106 70 37 20 -31 11 normal -1 sprites/temperate.png 8bpp 154 70 38 27 -31 -8 normal -1 sprites/temperate.png 8bpp 202 70 16 9 17 3 normal -1 sprites/temperate.png 8bpp 234 70 15 9 -7 22 normal -1 sprites/temperate.png 8bpp 266 70 16 9 -31 11 normal -1 sprites/temperate.png 8bpp 298 70 15 9 -6 -8 normal -1 sprites/temperate.png 8bpp 330 70 8 7 25 5 normal -1 sprites/temperate.png 8bpp 346 70 10 5 -4 27 normal -1 sprites/temperate.png 8bpp 364 70 8 7 -31 11 normal -1 sprites/temperate.png 8bpp 380 70 12 6 -5 -8 normal -1 sprites/temperate.png 8bpp 10 100 39 18 -6 0 normal -1 sprites/temperate.png 8bpp 58 100 38 11 -5 12 normal -1 sprites/temperate.png 8bpp 106 100 39 18 -31 5 normal -1 sprites/temperate.png 8bpp 154 100 40 11 -32 0 normal -1 sprites/temperate.png 8bpp 202 100 20 6 13 12 normal -1 sprites/temperate.png 8bpp 234 100 13 7 -5 16 normal -1 sprites/temperate.png 8bpp 266 100 20 6 -31 5 normal -1 sprites/temperate.png 8bpp 298 100 13 7 -6 0 normal -1 sprites/temperate.png 8bpp 330 100 8 4 26 13 normal -1 sprites/temperate.png 8bpp 346 100 12 3 -5 20 normal -1 sprites/temperate.png 8bpp 364 100 8 5 -31 6 normal -1 sprites/temperate.png 8bpp 380 100 15 4 -6 0 normal -1 sprites/temperate.png 8bpp 10 130 38 27 -5 -8 normal -1 sprites/temperate.png 8bpp 58 130 37 20 -4 11 normal -1 sprites/temperate.png 8bpp 106 130 37 26 -31 5 normal -1 sprites/temperate.png 8bpp 154 130 38 20 -31 -8 normal -1 sprites/temperate.png 8bpp 202 130 16 9 17 11 normal -1 sprites/temperate.png 8bpp 234 130 15 9 -6 22 normal -1 sprites/temperate.png 8bpp 266 130 16 9 -31 3 normal -1 sprites/temperate.png 8bpp 298 130 15 9 -7 -8 normal -1 sprites/temperate.png 8bpp 330 130 8 7 25 11 normal -1 sprites/temperate.png 8bpp 346 130 10 5 -4 26 normal -1 sprites/temperate.png 8bpp 364 130 8 7 -31 5 normal -1 sprites/temperate.png 8bpp 380 130 12 6 -5 -8 normal -1 * 7 02 05 20 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/temperate.png 8bpp 10 210 38 19 -5 0 normal -1 sprites/temperate.png 8bpp 58 210 38 18 -5 13 normal -1 sprites/temperate.png 8bpp 106 210 38 18 -31 13 normal -1 sprites/temperate.png 8bpp 154 210 38 19 -31 0 normal -1 sprites/temperate.png 8bpp 202 210 19 9 14 11 normal -1 sprites/temperate.png 8bpp 234 210 16 9 -7 22 normal -1 sprites/temperate.png 8bpp 266 210 19 9 -31 11 normal -1 sprites/temperate.png 8bpp 298 210 16 9 -7 0 normal -1 sprites/temperate.png 8bpp 330 210 8 6 25 13 normal -1 sprites/temperate.png 8bpp 346 210 12 4 -5 27 normal -1 sprites/temperate.png 8bpp 364 210 8 6 -31 13 normal -1 sprites/temperate.png 8bpp 380 210 12 5 -5 0 normal -1 sprites/temperate.png 8bpp 10 240 40 11 -7 0 normal -1 sprites/temperate.png 8bpp 58 240 39 18 -6 5 normal -1 sprites/temperate.png 8bpp 106 240 38 11 -31 12 normal -1 sprites/temperate.png 8bpp 154 240 39 18 -31 0 normal -1 sprites/temperate.png 8bpp 202 240 20 6 13 5 normal -1 sprites/temperate.png 8bpp 234 240 13 7 -6 16 normal -1 sprites/temperate.png 8bpp 266 240 20 6 -31 12 normal -1 sprites/temperate.png 8bpp 298 240 13 7 -5 0 normal -1 sprites/temperate.png 8bpp 330 240 8 5 25 6 normal -1 sprites/temperate.png 8bpp 346 240 12 3 -5 20 normal -1 sprites/temperate.png 8bpp 364 240 8 4 -31 13 normal -1 sprites/temperate.png 8bpp 380 240 15 4 -7 0 normal -1 sprites/temperate.png 8bpp 10 270 38 20 -5 -8 normal -1 sprites/temperate.png 8bpp 58 270 38 26 -5 5 normal -1 sprites/temperate.png 8bpp 106 270 37 20 -31 11 normal -1 sprites/temperate.png 8bpp 154 270 38 27 -31 -8 normal -1 sprites/temperate.png 8bpp 202 270 16 9 17 3 normal -1 sprites/temperate.png 8bpp 234 270 15 9 -7 22 normal -1 sprites/temperate.png 8bpp 266 270 16 9 -31 11 normal -1 sprites/temperate.png 8bpp 298 270 15 9 -6 -8 normal -1 sprites/temperate.png 8bpp 330 270 8 7 25 5 normal -1 sprites/temperate.png 8bpp 346 270 10 5 -4 27 normal -1 sprites/temperate.png 8bpp 364 270 8 7 -31 11 normal -1 sprites/temperate.png 8bpp 380 270 12 6 -5 -8 normal -1 sprites/temperate.png 8bpp 10 300 39 18 -6 0 normal -1 sprites/temperate.png 8bpp 58 300 38 11 -5 12 normal -1 sprites/temperate.png 8bpp 106 300 39 18 -31 5 normal -1 sprites/temperate.png 8bpp 154 300 40 11 -32 0 normal -1 sprites/temperate.png 8bpp 202 300 20 6 13 12 normal -1 sprites/temperate.png 8bpp 234 300 13 7 -5 16 normal -1 sprites/temperate.png 8bpp 266 300 20 6 -31 5 normal -1 sprites/temperate.png 8bpp 298 300 13 7 -6 0 normal -1 sprites/temperate.png 8bpp 330 300 8 4 26 13 normal -1 sprites/temperate.png 8bpp 346 300 12 3 -5 20 normal -1 sprites/temperate.png 8bpp 364 300 8 5 -31 6 normal -1 sprites/temperate.png 8bpp 380 300 15 4 -6 0 normal -1 sprites/temperate.png 8bpp 10 330 38 27 -5 -8 normal -1 sprites/temperate.png 8bpp 58 330 37 20 -4 11 normal -1 sprites/temperate.png 8bpp 106 330 37 26 -31 5 normal -1 sprites/temperate.png 8bpp 154 330 38 20 -31 -8 normal -1 sprites/temperate.png 8bpp 202 330 16 9 17 11 normal -1 sprites/temperate.png 8bpp 234 330 15 9 -6 22 normal -1 sprites/temperate.png 8bpp 266 330 16 9 -31 3 normal -1 sprites/temperate.png 8bpp 298 330 15 9 -7 -8 normal -1 sprites/temperate.png 8bpp 330 330 8 7 25 11 normal -1 sprites/temperate.png 8bpp 346 330 10 5 -4 26 normal -1 sprites/temperate.png 8bpp 364 330 8 7 -31 5 normal -1 sprites/temperate.png 8bpp 380 330 12 6 -5 -8 normal -1 * 7 02 05 21 01 00 00 00 -1 * 14 02 05 22 81 80 00 FF 01 20 00 00 00 21 00 -1 * 6 07 83 01 \7! 00 01 -1 * 7 03 05 01 06 00 22 00 openttd-1.5.3/media/extra_grf/rivers/temperate.png0000644000000000000000000003737712627373446021000 0ustar rootrootPNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPLTE 000@@@PPPdddttt4YśOwSv:B>s(z|sA> ͂-d%kN(X(,dd Y2 $Kd@2,HrD@sPZl}fRbEo_uO-**wOWppG(11$D"f+쮥/>~C/UE2PXE7*33' 323bO/7[r"PUPb 11(Ϥ#m߽ lF`+ tWTosT>]a|Ұӷ4(we*0)MUeUQ@=Jw3A0|L403}J㗵!y߆ܼ̤6w=s}}=mA)V36D03V"*ҾۍO־DyˤuޘYt2q]{3~J̲!FXHTvHaJ /4偉&_`3L 5 J }i1| D*W"w.'ʫҿT'gY;42xReVb"&b@9}\1)_cZ!Q[G܁%e͌'1̬JC;SAX Gb~'~[*-*MmHiY_9c7bՠ3oh1tjx4ap3bz#ƮO[:=K Ơy#Owz_ȼ7jx8b̴7xw i1fqjxNcn Գd H $ɒd@2,H%y>@:o~~(9NVR(^bJcA5ׇ4jT0OD@D$ݵ i@tHo^C$8}WvnI5$Jo "( Ho*h/4$ @}E]DtPj/H-w6ME!AQ=o^#I(OR8߼y+Zk~"Qb|rWADEP s}}}-*5IdH-UGi@*$I vP] QQxt?k(Q0PR_$pkv$ JЯk *@z$DQPPaM- Fܔ5;r,c̶.Z0|QyqQ'A,N7Y f:0_OWfc̫?N}Q ]?s ",)?bEI.춝R'1~p.E~"rM];L8mrWQv~R (zk~:' ؐu0A. YRp̼n[.0/E-حU?a h<k;y fVu 2Rݒ_Q5_SyQ_T@S}ߒMy2?oOu.8f]A)X /~[ks ]|:A-kb=:'/O,cd$s#/ ޘ $K%@d H $ɒd Y2,j 8i[[{J}?jlG5{5rl^Nn@1/aAJDME%" x W%ߞ`bWE*iFU$Rb"\ RdLA(7$7c{ k }Eu=(だʏ"Lo5ZZ鬥5&/jA'NEP Q57{F@.j._ݘ. P~y#`-,HǺEj5 &H8 ";Q"wO ER?<ƻ!E-"!IcP>U{eQ?P=(/H@P{W߾)9=$ & "FDfp!"bE(W"$m^rZ /) klON5:kGٗ/QHPQ)`(C557{@ "q?u@ɬQ7g]@lA$k$d/*&AgR%u,5Ƹ0Q]h! H<}X2˳ yHq:үz>Kڍkv}\*:8Dy| JY8EU̖ϱ1Ɯ] $K*h݉(1< vNr __ .~Zv눻5mƓW''UJ_1gR'X# c\E}7l"q?pP!9ggsgu{p^ - `tuBBB \ |oS .app?+[Zz`:%5 { HB$1, Cb B]isY"*n1HeSqH: mk?>$R@Yӯ9 * nvIQTUkk /F@$T Tdx։ߞ0rH{ 8]Z Q56q]lsfkc`BPD*. @$gd!ըS@PQ@S)k!cR]hRp{e IUs:u޳L52ζ9{U'7+(T?h lkpvleRpk{l_vGt6'㿯j6ap8u<#\@ C@| d[ܯ0fdFXgH׌ČGFaXןm|[3yαH 俰K??u t^3}{I>p~~¬~9lzn|g%|hU3US,k,c\ݥ7>ƕ+Ch)Z7{@|@bëw~3N91ZkK4هCEV? Q. K.Cd{\ntwaxLy)}?Qavnu޽~skXyOjd8 _{1xPXޖUjRj ce ʾ qYmUCG+XZ)chV;WX5qbL5~v)N3@2mmZQԀ^~e qY5Ob!PEC77奔2WoY6W!e *qS|79gJ~ux׻Nl).JQCh.S4 .rlKeB1M  .]KCdX9bA!mN]e!>7MC'z^(Y}>?Fa!gV]/H ^wF6T( UvwBByv%{ +묺XCqN^iKͲGJea=vnbasđA{0gY^CjЄ]2K/ ĘNnUضZk+Ȟ#s^CU#10*7N8.}#-X !.Bbb W]ab栤ĘoT!lI_a\raơ6Udhd;'5!WZr61Qy3{صኒ*.,pZxƾoro8>9cC鼸>ͪi Hߙ``1Yn%@d H $ɒd Y2,E CLGX L[CjJUpM~߬67kpo>,s̑TF7W)5f}<{pu8Rԥ)g'DG!9ēp7MYJ!)3ODcLy{ݩnԱ00Mos]8QK7{pyxۄC(@q~+'_ {\$b̑&乜 k۔DBlnߋB+L.}7KB\lq CSMBAY:Ę]8J%t>2sIW\0"%31_/+P`i.rwu'r2jW`7˓Ӣ7!b@n-bfV#\;`bղfl=E4x^)ZVD de2fZıa?+LyЙb:\څ劈 8m%st{_\%kbYcvpB ⒕c:&q²''te03s?~\nDʣN2*_`!Teu`&O"flr\Ђo=)Cc[7<=6̀כןǨ?7 u|d@d H $ɒd Y2 $K%@d H $ɒd Y2,H%@d H $ɒd@2,H%@d H $Kd@2,H%@d Y2 $Kd@2,1"8|կ=U拂Abƈxoq58Oe=HRXk I=:ނVLj Q*~yDЉI[s.d ؜.J;$R$Vzj[+)$Df`8]- Da+ϼ{ƅHi8& ml!(J23D(؜~0"* )k",tw0xŪM {^Y[ 3W Lj? iEs km* tFJQIwAa%T_c$JBz{3A!@眓^Y[A{^م+P?*g v}@RYضAyFBIYrRHJB{tiѪw#1vaؐja+|3)Mqy%A$]MXXI)GAT$RFUDIXcDYUQUz/{9jHu(쪵 犂vcxdI!H49niN܅ 9u>㻳d Y2 $Kd@2,H%2 &@j8]hQ=7u- QH0A}X2xz)Ut d>U{~$""xmsTCE]c](STmyAEADAMEc̋"I drhvڙ.J/^+]\$Zb{k 6Ƙ"' P ԟ $]ҿkcjۙOp%'w}AI0Ph$}ߩ "Hw՝v&b z{WQxt؅p(BS E}qŢ.>HBA1_? B)QU%LH(Xwu D|p0k] _&u/c}ʬ4\cyɻ/ ']_qPD8EL/N0w@GR笵 mI j'_7CĶuCAF\|SN"|TtE[F]AUA~@nl:'-[&Huqpa85 *07d!J"_w1mmºt_`V} ۮ2g!a/_~a'x̪PƽQ _ "z /ꋔ H4p[ա)@NGݬ+HPyy<" E}Q@8"w%_><ԲI!shĒ>HzQ_HpU!$s#/ ޘ $K%@d H $ɒd Y2,j 8iRe']Da@漎9wS&|GZ#qj$ITX+J= ɘ+[R{QbI &a2EiFU$Rb"\ RtYbzC/Pzq3Q:A@03Vc7Arں46y<T@Q>ADP-&ZcBe]/!ָf:ki ǽZPSHoc^ẐJ]Cw 7"@N(( [bE$WE] ީ?%Ika\~W_$nEBD WEML@"""ilΛGA@5^pP&l"Iϛ} ۂ21].d@&FAD7x̐u nڅUv~yHI״_c|*tY; ξ|F= JFq"(Hi&O zK_urd֨˳T_` W BDn5Nj kAqʿDpf=,d 5ƽ Eh*(B;1FCsyVC5b"]4CHq:үz>Kڍkv}vC' QT%lceJJ+[۝_>!a?8 ;-nL;넉d}?pWu6F髓*Ygb ֈ@X WvQ_p5<-k\\&THw׾R?Β8!n@Z[$>:AT!9KL󏷩sH88@[Zz`:%5 { HB$1, X}~@A> )"FE2UXb1tQ4u~}H_oWs@PU}m֩9$ւax[g$k1 Tȗ]_d@d %\'\>Mm:y`oo7-ægTRYVgTBOTqujWfFc D\ ^vnֺrY=H,bqox!j][J->"Ǎ X._r9l\r&;܄vÿM d2K!Cd ۶vkº2ܱe7jKVρ1P8m!e އ*T!~eUƫZBt/C\Vj= a>Dz?mcNߕ1VM܄g=$ ۶va50s2 b ^U g2WoY6W!e *qS|79gJ~ux׻Nl).JQCh.S4yφpfsL_*MBob8W8.ڻZ%PE.C is*C 1e|a<i2?}KvyE։܍< ۶۝2*ܴPkhd}>:ws L5ͭ.KbhHn/uD5rŁu!?B{Wtf/ξR=8%}qɥYʾT>e0\.pć`^kɡڬHF|?a׆+Jc-$pZxƾoro8>9cC鼸>ͪi Hߙ``1Yn%@d H $ɒd Y2,E CLGoQ L[P';Ѩ7ShNf]H|aKf<;4 UJ Fio W7H E]ʞq} ݝJX8,%s 'E1$f4_vt)oܴ7dD-\Q@Qh5!}( $&ݏce4*]={V.y1EaR\NqN5mJf" !6 a=O.&r.P@DqYv DS8A1p~ >DbfL'C|ٚ4PM|^}Au)cwILI>vIɁ&NYuN%qI8 Lqv~2D"c(.}}}}}%n8t?OlH#sc/2oC%k( uHC!|[&ƸIy"(3gS0UcrQ\Q8kmoȨg %yD9gf!,X2.?LL ٳ~b{;|"nzk.{@eD* J̬{DssA āWabva0ku1#ތ1%sdq3u~1CbQܛ?2)>HNES0q8̰u" HwzCL.}7KB\lq CSMBAY:Ę]8J%t>2sIW\0"L̡ !ro=y ]ɡaZXMsݫ/f"akFa9"% &Z-ak"1{BGo-TJʤe̴c~VaBZڅ劈 8a\rIG8.^*aD) W8gĴۅB&> Pб68Y^yDbZkĘubHyIF ,Ju̚BWQ~3)2e@gNgH猂1D(x*XG^g[#g$1PUp˗5` aeH7Vq &"*,YY+!ଏ1)++)UH bV !H؇hC|SHlʣ2*'Ӊn@;#C7gĴۅu&wD|<ɴ3y=d$D9~o֊ҝ%+Q9SY$;{3Ln Bzc(qD$^?wS(*V,@ qиE@$Z f&>>cgqg Z@j1TUEt39FI!WulUk|&~;la69%ɒd Y2 $Kd@2,H $ɒd Y2 $Kd@d H $ɒd Y2 $K%@d H $ɒd Y2,H%@d _lIIENDB`openttd-1.5.3/media/extra_grf/rivers/toyland.png0000644000000000000000000003737712627373446020464 0ustar rootrootPNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPLTE 000@@@PPPdddttt4YśOwSv:B>s(z|sA> ͂-d%kN(X(,dd Y2 $Kd@2,HrD@sPZl}fRbEo_uO-**wOWppG(11$D"f+쮥/>~C/UE2PXE7*33' 323bO/7[r"PUPb 11(Ϥ#m߽ lF`+ tWTosT>]a|Ұӷ4(we*0)MUeUQ@=Jw3A0|L403}J㗵!y߆ܼ̤6w=s}}=mA)V36D03V"*ҾۍO־DyˤuޘYt2q]{3~J̲!FXHTvHaJ /4偉&_`3L 5 J }i1| D*W"w.'ʫҿT'gY;42xReVb"&b@9}\1)_cZ!Q[G܁%e͌'1̬JC;SAX Gb~'~[*-*MmHiY_9c7bՠ3oh1tjx4ap3bz#ƮO[:=K Ơy#Owz_ȼ7jx8b̴7xw i1fqjxNcn Գd H $ɒd@2,H%y>@:o~~(9NVR(^bJcA5ׇ4jT0OD@D$ݵ i@tHo^C$8}WvnI5$Jo "( Ho*h/4$ @}E]DtPj/H-w6ME!AQ=o^#I(OR8߼y+Zk~"Qb|rWADEP s}}}-*5IdH-UGi@*$I vP] QQxt?k(Q0PR_$pkv$ JЯk *@z$DQPPaM- Fܔ5;r,c̶.Z0|QyqQ'A,N7Y f:0_OWfc̫?N}Q ]?s ",)?bEI.춝R'1~p.E~"rM];L8mrWQv~R (zk~:' ؐu0A. YRp̼n[.0/E-حU?a h<k;y fVu 2Rݒ_Q5_SyQ_T@S}ߒMy2?oOu.8f]A)X /~[ks ]|:A-kb=:'/O,cd$s#/ ޘ $K%@d H $ɒd Y2,j 8i[[{J}?jlG5{5rl^Nn@1/aAJDME%" x W%ߞ`bWE*iFU$Rb"\ RdLA(7$7c{ k }Eu=(だʏ"Lo5ZZ鬥5&/jA'NEP Q57{F@.j._ݘ. P~y#`-,HǺEj5 &H8 ";Q"wO ER?<ƻ!E-"!IcP>U{eQ?P=(/H@P{W߾)9=$ & "FDfp!"bE(W"$m^rZ /) klON5:kGٗ/QHPQ)`(C557{@ "q?u@ɬQ7g]@lA$k$d/*&AgR%u,5Ƹ0Q]h! H<}X2˳ yHq:үz>Kڍkv}\*:8Dy| JY8EU̖ϱ1Ɯ] $K*h݉(1< vNr __ .~Zv눻5mƓW''UJ_1gR'X# c\E}7l"q?pP!9ggsgu{p^ - `tuBBB \ |oS .app?+[Zz`:%5 { HB$1, Cb B]isY"*n1HeSqH: mk?>$R@Yӯ9 * nvIQTUkk /F@$T Tdx։ߞ0rH{ 8]Z Q56q]lsfkc`BPD*. @$gd!ըS@PQ@S)k!cR]hRp{e IUs:u޳L52ζ9{U'7+(T?h lkpvleRpk{l_vGt6'㿯j6ap8u<#\@ C@| d[ܯ0fdFXgH׌ČGFaXןm|[3yαH 俰K??u t^3}{I>p~~¬~9lzn|g%|hU3US,k,c\ݥ7>ƕ+Ch)Z7{@|@bëw~3N91ZkK4هCEV? Q. K.Cd{\ntwaxLy)}?Qavnu޽~skXyOjd8 _{1xPXޖUjRj ce ʾ qYmUCG+XZ)chV;WX5qbL5~v)N3@2mmZQԀ^~e qY5Ob!PEC77奔2WoY6W!e *qS|79gJ~ux׻Nl).JQCh.S4 .rlKeB1M  .]KCdX9bA!mN]e!>7MC'z^(Y}>?Fa!gV]/H ^wF6T( UvwBByv%{ +묺XCqN^iKͲGJea=vnbasđA{0gY^CjЄ]2K/ ĘNnUضZk+Ȟ#s^CU#10*7N8.}#-X !.Bbb W]ab栤ĘoT!lI_a\raơ6Udhd;'5!WZr61Qy3{صኒ*.,pZxƾoro8>9cC鼸>ͪi Hߙ``1Yn%@d H $ɒd Y2,E CLGX L[CjJUpM~߬67kpo>,s̑TF7W)5f}<{pu8Rԥ)g'DG!9ēp7MYJ!)3ODcLy{ݩnԱ00Mos]8QK7{pyxۄC(@q~+'_ {\$b̑&乜 k۔DBlnߋB+L.}7KB\lq CSMBAY:Ę]8J%t>2sIW\0"%31_/+P`i.rwu'r2jW`7˓Ӣ7!b@n-bfV#\;`bղfl=E4x^)ZVD de2fZıa?+LyЙb:\څ劈 8m%st{_\%kbYcvpB ⒕c:&q²''te03s?~\nDʣN2*_`!Teu`&O"flr\Ђo=)Cc[7<=6̀כןǨ?7 u|d@d H $ɒd Y2 $K%@d H $ɒd Y2,H%@d H $ɒd@2,H%@d H $Kd@2,H%@d Y2 $Kd@2,1"8|կ=U拂Abƈxoq58Oe=HRXk I=:ނVLj Q*~yDЉI[s.d ؜.J;$R$Vzj[+)$Df`8]- Da+ϼ{ƅHi8& ml!(J23D(؜~0"* )k",tw0xŪM {^Y[ 3W Lj? iEs km* tFJQIwAa%T_c$JBz{3A!@眓^Y[A{^م+P?*g v}@RYضAyFBIYrRHJB{tiѪw#1vaؐja+|3)Mqy%A$]MXXI)GAT$RFUDIXcDYUQUz/{9jHu(쪵 犂vcxdI!H49niN܅ 9u>㻳d Y2 $Kd@2,H%2 &@j8]hQ=7u- QH0A}X2xz)Ut d>U{~$""xmsTCE]c](STmyAEADAMEc̋"I drhvڙ.J/^+]\$Zb{k 6Ƙ"' P ԟ $]ҿkcjۙOp%'w}AI0Ph$}ߩ "Hw՝v&b z{WQxt؅p(BS E}qŢ.>HBA1_? B)QU%LH(Xwu D|p0k] _&u/c}ʬ4\cyɻ/ ']_qPD8EL/N0w@GR笵 mI j'_7CĶuCAF\|SN"|TtE[F]AUA~@nl:'-[&Huqpa85 *07d!J"_w1mmºt_`V} ۮ2g!a/_~a'x̪PƽQ _ "z /ꋔ H4p[ա)@NGݬ+HPyy<" E}Q@8"w%_><ԲI!shĒ>HzQ_HpU!$s#/ ޘ $K%@d H $ɒd Y2,j 8iRe']Da@漎9wS&|GZ#qj$ITX+J= ɘ+[R{QbI &a2EiFU$Rb"\ RtYbzC/Pzq3Q:A@03Vc7Arں46y<T@Q>ADP-&ZcBe]/!ָf:ki ǽZPSHoc^ẐJ]Cw 7"@N(( [bE$WE] ީ?%Ika\~W_$nEBD WEML@"""ilΛGA@5^pP&l"Iϛ} ۂ21].d@&FAD7x̐u nڅUv~yHI״_c|*tY; ξ|F= JFq"(Hi&O zK_urd֨˳T_` W BDn5Nj kAqʿDpf=,d 5ƽ Eh*(B;1FCsyVC5b"]4CHq:үz>Kڍkv}vC' QT%lceJJ+[۝_>!a?8 ;-nL;넉d}?pWu6F髓*Ygb ֈ@X WvQ_p5<-k\\&THw׾R?Β8!n@Z[$>:AT!9KL󏷩sH88@[Zz`:%5 { HB$1, X}~@A> )"FE2UXb1tQ4u~}H_oWs@PU}m֩9$ւax[g$k1 Tȗ]_d@d %\'\>Mm:y`oo7-ægTRYVgTBOTqujWfFc D\ ^vnֺrY=H,bqox!j][J->"Ǎ X._r9l\r&;܄vÿM d2K!Cd ۶vkº2ܱe7jKVρ1P8m!e އ*T!~eUƫZBt/C\Vj= a>Dz?mcNߕ1VM܄g=$ ۶va50s2 b ^U g2WoY6W!e *qS|79gJ~ux׻Nl).JQCh.S4yφpfsL_*MBob8W8.ڻZ%PE.C is*C 1e|a<i2?}KvyE։܍< ۶۝2*ܴPkhd}>:ws L5ͭ.KbhHn/uD5rŁu!?B{Wtf/ξR=8%}qɥYʾT>e0\.pć`^kɡڬHF|?a׆+Jc-$pZxƾoro8>9cC鼸>ͪi Hߙ``1Yn%@d H $ɒd Y2,E CLGoQ L[P';Ѩ7ShNf]H|aKf<;4 UJ Fio W7H E]ʞq} ݝJX8,%s 'E1$f4_vt)oܴ7dD-\Q@Qh5!}( $&ݏce4*]={V.y1EaR\NqN5mJf" !6 a=O.&r.P@DqYv DS8A1p~ >DbfL'C|ٚ4PM|^}Au)cwILI>vIɁ&NYuN%qI8 Lqv~2D"c(.}}}}}%n8t?OlH#sc/2oC%k( uHC!|[&ƸIy"(3gS0UcrQ\Q8kmoȨg %yD9gf!,X2.?LL ٳ~b{;|"nzk.{@eD* J̬{DssA āWabva0ku1#ތ1%sdq3u~1CbQܛ?2)>HNES0q8̰u" HwzCL.}7KB\lq CSMBAY:Ę]8J%t>2sIW\0"L̡ !ro=y ]ɡaZXMsݫ/f"akFa9"% &Z-ak"1{BGo-TJʤe̴c~VaBZڅ劈 8a\rIG8.^*aD) W8gĴۅB&> Pб68Y^yDbZkĘubHyIF ,Ju̚BWQ~3)2e@gNgH猂1D(x*XG^g[#g$1PUp˗5` aeH7Vq &"*,YY+!ଏ1)++)UH bV !H؇hC|SHlʣ2*'Ӊn@;#C7gĴۅu&wD|<ɴ3y=d$D9~o֊ҝ%+Q9SY$;{3Ln Bzc(qD$^?wS(*V,@ qиE@$Z f&>>cgqg Z@j1TUEt39FI!WulUk|&~;la69%ɒd Y2 $Kd@2,H $ɒd Y2 $Kd@d H $ɒd Y2 $K%@d H $ɒd Y2,H%@d _lIIENDB`openttd-1.5.3/media/extra_grf/rivers/arctic_snowy.png0000644000000000000000000003274412627373446021507 0ustar rootrootPNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPLTE 000@@@PPPdddttt46~" 9D*@/";E`~^fFsAFͤ}~̌077X(Ҍ~t*1j p34_qط47\'lϯnnphH~`f9}j0|)άDO4Ȏ O4[^>|q=if>X`@?6d~86 k`\J|ņaƵe[`$`vo^6XG]f6YSk@o~Q gBp=&-ׯ?r=NW?֢]VFI qhcO4PXF#}*כf(k]eyeNOFV5=͎_~?3٬47ld2c_D&I7vc0X^O#](I1=OvՏѬ']֔ < IԹÑlDq7v)]c6H|L}9~tV)wQeU]q:32׏z RӻNM65 =[&s$`ʝ4KHC'd8Jݥ. H;^N,[$QٜHmَeoBJJҀҀ4 4 H+ HJJ/ dx>Vu0 U:_0UF.B:Ք/!hm=h=pwY"ǻ 6P"o.1̌TR%p`켾 jf%`ZَP$Ws }rhہ!31q8Q%7K%R=kdj7NJeh|K܆3 Z >Hp,aӀiRg]ц; q*@@&A)؅vIO5 y|:I367{x#-)YI75SnTOr4^ڐno z(>tuxG.V9~vKK ]QI@Z q4d!VryuQ:w$,[3.;$8)W?WzxM9}\yn5n%ǁ }b/&gKzTS}T&-,b@ݜ%ݫ8'Yl1%ǀMP]%s-8W7$rh4vf>bB}_yMK6?G܍ȉ.In'})G5LFV쟯!뛫Jgi~i@c7Sw\@h$r.~4ߑzHJU^9Fik H$Ÿ$K< @k<֏H)[l3&_Hc-8$Qmt}@h/HOIemm)9[3s?{_B3v<༽ߞ(2I[>͡U6k32Dn!WY׎f/mfJZT۵!<=Y׏np9v3Y HMEM9sJ&id2i? }<*{?N?q}#-S^ gYl9bKSMe%j}JWXռR{ lS`M?ْf< =9.0=ohNG23|Zڟ- c<۵vN5_|MϻvѿȣBzY[loJo:$={y33] :OkۦgO~ hL&ITA$w,9+RdoXQ~7̅_S>} Xm?,erU!ՙ\&A>A% ]HÚ?IQ$&|[~R`~b ۫(VVii@Zi@VV !w,^Kĭ g~wS 5uz"z' w~FePFDN_@Lbؿs]9n J9kk ~lGBo?4I=ǨN> #'s0hъ\ q @P->o0:!H0y Q"nC{*`wǮ58 >LDY`"1| ^~K@n@!.@>~~, 8hHO9ڐ]DL2ݒar?%Ro*ON6Q۸̫moK rUȸEowFH߷=~wQkd` ӗw k&f srRlVKYXx2G D. Jr؈<ۆڭ$6(7XȇCBN; UZmT;;Vo=r+; V67?Ӏ ݖë֊DxTfSZ}%ϻJGnӾR`pOc$z;؉)Es+OվZse(w%Rwuokq05Sm<9YՕQjݥf%E1Eыm_5ҍGE+C#KGAۚQ(Nxy0ֽw?/:o.0@X<'hkBmۀ싒;)Ϊ iA 1]dCM_} _|1F6i@'iii@Zi@Viii@Zi@Viii@Zi@Viii@Zi@Viii@Zi@Viii@Zi@VB~8sMw?Qd%y}rT\FX?}8{u|\)i6?j\;r!F4[>1#HNXO$g[8[(L#qTNZv777)]/~'ana?% 3?`n*n"9E`ϝH#A^;Fq)^N XA'3)27V4*܅6 5p,n7! `po\ea[H E26אrS]W!NI]료ѝ\f,-$iPq3ꤹI%MA o]{ 1$vQ zuD`s$iV!(S1*c@p&)n&G叐ˋ fK 4b s-Ttif0c+6bIM$jϯP= tT]>$iDFsW!it[4'Li `lh͖%cϿysL׺IӋvԯN+s;᤽iDs#jvw첆O&in)&XA2r yr5ٸVzD0?s:Q n 6*>J:{M(M_W@ʧNDɊb6Q~$v]f}q}(plIHj]NR%c?y_F <;\(ʜ Dy6opzygu@sWhotF!0HBd\q@BŽu*`nfowׇ<Ϝ]'Y.'ӂV(wgw?[éBnii@Zi@Viie($wa8ڏ3o'SK7r-ddNnVb^^^Bq9,[Q JayǴos&D&OӀ4!o1Ѭ^)K"kN~*Fuql/lBef7K Tg=ԫ$4[*ne  y(=\ }%R d9NH5zPQ{ȡFf!+ %$c*3.ɲN&}W^}>BfVMC8ZiZ?.<%ؚnzJ]c%笜d'H)vߖ6-WB2^^H7YqM\^= 6Jk{H"SJi4 ܯWz|Y:MMmАo-J(w(llM 뿮q/]cbTm{oȾWFYs*I}m)Rݝd8 8]!?H֓AW%A@(&jx ͕$&ׁ0fͯE솀cz=Z ΎtA]}[ԖfvA< M鲦$nQH6'&[-8ϛ_;q( .f5OxL:;̨ ~8F~׏z RӻNM65 =[&s$`^4KHC'wRB$rzgF N/'-@l?$LlGRV}7ziii@Zi@Vii2O>Vu0 i///:_0UF.Bi5JƗ4 Ifa.g'7,9EBwB#lMudfL*cMX]P0 f.v':F }rhہ!31N FU Jz!4ՂQoj.1 {f@^}.!a^^p-əM2ڰcg!0cSS$T|Q=?#$ӧ<>⤙^=%%:+}|NG{ R{܍*)7YqK2 my]-A/e癮=}H e*ni16?R")^ "@Q1΂u ;<ĪQ..ʴB?T'EoketDeQ=G$ (jVUK$L~QOj Ӥ%cV喟P࿼nI-KWqOr}4cNcEK)Hue]kę!a糊vf>bB}_yMK6?G܍] Bt$uQVagQJy*b~&7 9v8Hpyǵ hL~z)&w2_TR۬R8IqB0X<@'R~%@J.X$ q%R?jC ny^o}9/HOIemm));FR} ~{d4&o9X6{WTj; . Hn!WY׎!<ϞٗE3% ZfCe,<$\rFpF?R5 6Q)= INɤX&\9"dW޳69v i00jv6 c D/rU]9#+~a gW L6x/.ZvR7!܈}h@Vi"G4 u_ɻ Fn<ҥu) W;wYfk'et?ll!ig>ZVV $\kѤ<ə =\XyX6=!$4}/Z2-LFƃIXs W$&~tFJJ|3\S>} Xm?c,erU!ՙ\&A>A% ]HÚ?IQ$&|[~R`~Jvl0~r©/òkۂ$^^^^`J2ʄ@]9IPOi<2C0 O|HY1FI.Nd( 3bQ(&]/ A nĠ\5 \GCIM?~ِ Y3g,gQ2h Y ՠ@)&/j.e*|y1%!JSgVʒ".1f#cH!sOcCNH@B&r~bH1pŠ 2C ̒Hs$n2}N_-7BAI$ۧ2ْro ckbhXqM~@% L5gtԄ-3u+: \Kn6 7ӧ3 Asj\/k#Tf zw !ȕ\l@NG\ $Ax܀u}bz $ G*;w#Hـ^[d4h I} ȩ HOxlvj@Zi@Zi@Vii@Zi@Zi@]Oޢv,7{-ءvyYj_rUO5ZnߧF@ؿh6I ?E6.?d -^Y \H&ǝC{ hч E, ֑>CHB9ځ* ps$}a W"ymd׉4m"'L$lʽ+YlMw>OC 5 00\^'}r9{/rat0C(]V%":z Y;Yv:xW8 8 [gW6$xa;.,{S@h &!S秿6dd:#E:LpO%YoJRnly˼z @(W]eP Y}o~}{Z~%<I 0}fHX61vnz !8 厥zțJ Ǔt>J$\ pqMV v.'ۆڭ$6(7XȇCBN; UZm!! c k+aKt-Wt+ e[TV$`-NLJm> sGNԺ 2OI,:"?W2kz:mW$Nt±m-ƹ~M24'[\GVTcn2b7닢[3jrD';#'[b?yq@(:w[3 Ip6Oƺw|:ښ9#˸P|Ya"0@Xf<'q74qF*pG|1@Bi1 `_ 0mM熫2[gϖgc!3$;!-[XC uQr:tAK:yt'K~tr>н.FK2r 4Lzr]׉t nAġJ@,lsՀ"]0.@y fNtѐ%egGa܌ۢwe@Zi@Zi@Vii@Zi@Zi@Vii@Zi@Zi@Vii@Zi@Zi@Vii@Zi@Zi@VW*?uIENDB`openttd-1.5.3/media/extra_grf/rivers/tropic_forest.png0000644000000000000000000003546512627373446021670 0ustar rootrootPNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPLTE 000@@@PPPdddttt4dw8O>靎8HS/d%F+ OW?4S^)?., ̵㏤v}L_p/rNJ0c 3 ?M?qQ2QmL/iBquι(3@ie5򏯟)_ؖXw64K16Y QՀ8D86FJ/qPQ,#b3>/v $w2_aw} qM@(WCL@yt6bfNK@td6b:n(3F>owzct@N5|Ti? ˳S ,N~6@jxteF@}O\?N~V@vcS5,H%@d Y2 $Kd@Hկoߞ4{NO+fg#!Zꝴs 3xy1Ƕ~hIA ܱ:G }-q^Ƕy˷/[ݾlK=khYhll۹xa]VnPsf2p9߯^"̢Y@wmɜ{oML ff4%3Xr0-f6 候@]af6 Ā8ЏY.ܾyWb]NZH믯^ |4r  u>;^>|QxO@"  fڢ))ކ " @]M~M#倈hMnmx..7Y/{ >Zjl :0z>I~63 *E6Q @|^] ajKGk| z6,Y1q|G>9s?'I I@Z Osh5MZhm)ooaf1Y!7|{Ee& s{_>nIX<-|4eؙc@ fo_2Ϯ,~{^8{ۯ $VB03̰ư1?kC;Y{_M fyq7eQ/b(ߵm@ļ_2e_z}N4‡`#>YFDmЁ]S%X 3#NoM }V4V>,oϟa'xAϪm`(qoۏz K4pjK\Z[ۼzvK Y{mY{b6o-ڒ@LVECo\%ɒd Y2 $Kd@2,H ?5mf4oۙ<}𞒓)nQk-*3?k11ZzwE%l+bf=[߶ֶWO0Dl#oD-c9.(0Mif;A܌k۔m kjH o@ A' 3!k [8LkY Z-" )qr}5oˈ`v }q\nSDs?H`m{X>-@ `"6Ew1m( X(WDpkgo,ֶ[`3-Y@x )[33?͵R3, ?i_瓥hk= f?~sp ID3`،I^^k 68 :xh_*}|ō|˂ɺ mMZ} }MS Xk(}.c5g6fEKAkf7DLOokܷ?$_xwUlwoѾR`HS5~rHaqɉk1R'˴IԺޚc@3^>,Uk@>@z-m3> b3ӖR=J8`)yE|sW71&M[Q48؝8-aP~R{FDy^ ㈻ŋE_lάof0é@n}^rpzj"`1ߟY\`Nv@z_F 7Η_G#u K75i/=@n}[;pG˷10 [ `1M8nbi&$#u}mw_2tJB1H}F@&^1.LHLGMm(l% vqy{|߆-n9o{fxSamdQ0ێ=:4zΕޛaл:t, @kJ_lrfk羿i!n)8]>a08\p`̬s)ksWW-Ӟi֗"IUsv9ams-X=69 Zmf?-MN?%7qN`X\={24F.)l>> |4u_`@W ~g$\n᥯^"qbCն\brz/8o6S__~M_nGI9ܫc{3,V5\_6u to_3}ZꩇV]nR%RרzKb.ո-h| Y$xAo_Iu ^}q\դ(Mu]Ud-"W\ HT{\_X 6+5e{WE,nI 1f-LmM>Po_sϪ"jEۗ^ XEյ5bU4M'հ g: +kVM7V%^ y*T%"w"q%r6Ս& YTئއ ‹bרD5)P^[eY(Axaݩj58B*J Q䪹0+֪I3_YP}o()?޽s>ĕו$ Kd/BYvCX[iu_D+jB/6wQX!rjQI[RW%;06yWjxb{ݛ"jSMCZTCr5O4NRcd4˲,x=[Q5D+RRTMd@ۋP^VZD?V5$MEC"^V f,Z5$.!|*V9|.%S*,*lo!RElnoM5Z2\C'[7bMfc`o9TnipucR +jPD58$PTsH-ج: %箾*1dU)eB0r@ רZ=5#uTTHF}|PVbMIIrŮYuMj\4FV:h%OĹZup=@N sdj;ȽyoU4;{" C$ ݠc]=9j*3+@ IU')9ua'Q,H $ɒd Y2 $Kd@d UpMc鞂6n 6>(*. )IWL"YErtx߹a j}<{Hz e[M33TȔ?JcMUcHd&>-*<7kj߹a4(JzulE'r,XH2ZaX5G9*\5WY4m; i %f5$ׁEv$H>,T5xz7E0p UQ ]cbM&WE*꽾5SDS ={FWWw`=_!nb*D 9':_ Ӧ?7X2) :ř )Hq("Ul^ĠϬ1R鮅8}On= m҇V& V#]wJ.ޝh~c! RMR %RԴN3>dM"&s_~){IDULkdoQ Q>\/eYSێwMa@?{;!@ACFEn:-#@TiUHI[L5^bT%J\-p&W8E0S7<HX 6dCbz|zD֪.'k HnRJ/.Lj@vfKԬZPXisp\"4gV?+i?>WއFhVLN~Lޚ⏳˹E0d')-Xr+ŋمI׹UW~8$DF&V)ө>Ab%u89Tv?~pYI7>ɨ|Tq@k԰FFǽ"*uDkqY#ޗ&vsfnBڍUdoz?8뼽_A4O\I3UZHI"uOn,ZI?rv )d`T&i9S!b4aJ>\aFI5lHbϞN٠B-tYIT ӗO'#dOQ4B+3.ÿ (#yɽ o/a#5 4 f,YlŒz9*3 1|xof!`z_eu[_IN'4:~}@H2x_l͠fFߓ'@&43A  Ew9_x >-e4Kz_,l<CQ> t E:$i Ԫ Ld1ydZ}8:N葍: E;.oPH*C7}OtiX"KCŻ%52 !4^eoS~36Vg 0#>⑓L=p87lI 4 4pMZ xt#ٹF}>xI _}-v(|Zt_[S_7ߝ%ɒd Y2 $Kd@2,HE pkBwsSǫ?<"`2DkЃWzNzaf//[ؖ6OӪŃ(7x9R@l-*Zٶx,X Yrsx/m`H/ @0h)ؚm3s}xx}m.9R< `m30fg1>ߧ!)@h介 lKfh$`"ZlgBmxɧO[1 cÅo3I夅{_`XNۧwCGSIZ $ px`-Bq6d a~$;vhMּ׻/|oM}CGK-5$^G3FϷb̀BĀmڗd|Gya:2YMV6P!ƴ6Lk| z f1mx`3rum;y`o9; H 0r`f m-X60֐뢲yzYιM/|}f$,}@]1^e ࣑(C|b0~[}x}veQ9܋?/~U `5Y--v{PJqp@hq}QPl0"r]D̻OK%KDe[F») -[ccնb[uXld?.(S~‡xĩ?k!UM{ |v 6nRGE.8򬽎hIsKx ml#Y~HݸB@/#R@ץE ?-q\B亍#$?sH $Kd@2,H%@d Y2@qӤ}ΔS܆~ݕOQ֥-:Ry6M[ |wxY;9Ѣn] |d2ַ$7  &)*7.IzY˙pmLkaz}q9Fl|z}{=qur5 7a@a-R m۲жCE=`\[`Z#EVb g-maHяgXFCQSru" =HJ3k=,dzH hmKhqn̐b vl=k[aO>HyZu~d}oB^@`0D `PLZm'-$!Ef|Hz&YصY 1}CtR{/n _LUhmҹ~{ ĩ[oX`(8Y 09DYlR| Qh=ӛd WOŻEnb{#n6GaR'kmm%RcH |!*Y;b%Ni-0Di5!뷡ǀ8g|H2~nZѼ9cc|ӡ) gZ}@fZkibn6b<~G gLdڽe_*\lMIgfVrTa/ %v'NGhmkqxi@N (A=Cwχ53&/..׋ؖY\Y-`S6ۛi`k8 bH}+v6{~O:&c@؏AZ3?৽lځ8ZiJI?Y ~~7ĹXc=@z_Y{ϱk#Yb8Mnc\6 OX oV`;8㼽ooCo 3<߰F:3 p-`$ÙqUCM=akz0]:, @kJ_lrfk羿i!M`|_wudnIwgo_(gs\!箮b[=ѳ'"IUsv9ams-X.j|@W s E 3̙ڸ0~\[XH@{s{+ ŕS럮*,CX:Ko}`ݒ tyn O3k[E]r諒G";H R2[钁hGD?dvĝg 3Nm/I6u2h<.ɒd@KLr_&:y`5zWբTPO=L:zvsg*Fw]_Zu+`Evw]MvnAc /%oM}&@jRݣzհUMTo]ץ{[jHMR-z XD`XR]wUnŠj"Tئ J BN-UEUr*ըzi:U8PUQ`]]j-izTEVS:v.و+_d_XkEmM_x}2(v+HTÚje~CUVب^֝:&X-԰Eˋ Pbd=s.yݻ޿}9C\y]jJM2 p؜VVZk%W`j$QZPx.2*@:jjԪLڒ*QT퇱SJWלԑ7eEb-ԧ(lۇ2(֒&Չ@jluY%{Q5D+RRTMd@ۋP^VZD?V5$MEC"^V f,Z5$.!|*V9|.%S*,*loCYG05hp l݈5ɚ!쎁PqՍJz.(>HA #@Q!941fUסL۟Z]}oUc}@a+hƱ!X7FS$C':0SĚvP$b׬&5x.k#]+'\:ug q Dz\O 9^5 ɼ7W*J̝=! nPUTݱs5DiFIXUp_YZNGoH $Kd@2,H%@d Y2*@RNޢvOAKjLFnݕ )M~I~0HydVf%VZ w@ʶff'I4TX8+JfӢSp~DnSOo iQoٮ E0xlj0 4 2Z V$jV9,l @ay%B|ᨰڪSِ*WO+R+ʦeJ -EZsW\\׬xJ薉ܣ }h5m`5"uY>q e7& RMR %R@*픘!4ٱ0Hք(1yo"8wQ頋=rDD~QT&K>3.@Q| o'eYSכsJJj*ZQޛ9LJ}  L62L,uilH٨#V9w^(VZL5Qu grqs_35zվ>`aC͏HH5yu>PZB w儞~ UM t\fW3[fւJ3d+ 4]9PJ"Q~#B#ӀX &yF򀨮 U$-d')-E+ŋمI*e(/,~StZX +T r,nR>ut; m|0O 5Qⶁ<$a׍{=ɺwzޗ&vsfnB؍ &T)5eDaĕ4SQ䱁$Qwhѐ`T&i9S!b4p2ku@2@<ӢDZ=.AdDYC9# >-;"H5uAƓso73ΓsT.A|VO0)`&#nuH2$~:wP)Ħ~$J->$6?<;Y`qj`8<>9c& ˴F:5ΪSߛ-dm3_|e Y2,H%@d H $ɒd@2,H%@d H $Kd@2,H%@d Y2 $Kd@2,H%ɒd Y2 $K-5BIENDB`openttd-1.5.3/media/extra_grf/rivers/tropic.nfo0000644000000000000000000004251112627373446020272 0ustar rootroot// // $Id: tropic.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Tropic river graphics by andythenorth (Andrew Parkhouse)" -1 * 4 01 05 01 3C -1 sprites/tropic_desert.png 8bpp 10 10 38 19 -5 0 normal -1 sprites/tropic_desert.png 8bpp 58 10 38 18 -5 13 normal -1 sprites/tropic_desert.png 8bpp 106 10 38 18 -31 13 normal -1 sprites/tropic_desert.png 8bpp 154 10 38 19 -31 0 normal -1 sprites/tropic_desert.png 8bpp 202 10 19 9 14 11 normal -1 sprites/tropic_desert.png 8bpp 234 10 16 9 -7 22 normal -1 sprites/tropic_desert.png 8bpp 266 10 19 9 -31 11 normal -1 sprites/tropic_desert.png 8bpp 298 10 16 9 -7 0 normal -1 sprites/tropic_desert.png 8bpp 330 10 8 6 25 13 normal -1 sprites/tropic_desert.png 8bpp 346 10 12 4 -5 27 normal -1 sprites/tropic_desert.png 8bpp 364 10 8 6 -31 13 normal -1 sprites/tropic_desert.png 8bpp 380 10 12 5 -5 0 normal -1 sprites/tropic_desert.png 8bpp 10 40 40 11 -7 0 normal -1 sprites/tropic_desert.png 8bpp 58 40 39 18 -6 5 normal -1 sprites/tropic_desert.png 8bpp 106 40 38 11 -31 12 normal -1 sprites/tropic_desert.png 8bpp 154 40 39 18 -31 0 normal -1 sprites/tropic_desert.png 8bpp 202 40 20 6 13 5 normal -1 sprites/tropic_desert.png 8bpp 234 40 13 7 -6 16 normal -1 sprites/tropic_desert.png 8bpp 266 40 20 6 -31 12 normal -1 sprites/tropic_desert.png 8bpp 298 40 13 7 -5 0 normal -1 sprites/tropic_desert.png 8bpp 330 40 8 5 25 6 normal -1 sprites/tropic_desert.png 8bpp 346 40 12 3 -5 20 normal -1 sprites/tropic_desert.png 8bpp 364 40 8 4 -31 13 normal -1 sprites/tropic_desert.png 8bpp 380 40 15 4 -7 0 normal -1 sprites/tropic_desert.png 8bpp 10 70 38 20 -5 -8 normal -1 sprites/tropic_desert.png 8bpp 58 70 38 26 -5 5 normal -1 sprites/tropic_desert.png 8bpp 106 70 37 20 -31 11 normal -1 sprites/tropic_desert.png 8bpp 154 70 38 27 -31 -8 normal -1 sprites/tropic_desert.png 8bpp 202 70 16 9 17 3 normal -1 sprites/tropic_desert.png 8bpp 234 70 15 9 -7 22 normal -1 sprites/tropic_desert.png 8bpp 266 70 16 9 -31 11 normal -1 sprites/tropic_desert.png 8bpp 298 70 15 9 -6 -8 normal -1 sprites/tropic_desert.png 8bpp 330 70 8 7 25 5 normal -1 sprites/tropic_desert.png 8bpp 346 70 10 5 -4 27 normal -1 sprites/tropic_desert.png 8bpp 364 70 8 7 -31 11 normal -1 sprites/tropic_desert.png 8bpp 380 70 12 6 -5 -8 normal -1 sprites/tropic_desert.png 8bpp 10 100 39 18 -6 0 normal -1 sprites/tropic_desert.png 8bpp 58 100 38 11 -5 12 normal -1 sprites/tropic_desert.png 8bpp 106 100 39 18 -31 5 normal -1 sprites/tropic_desert.png 8bpp 154 100 40 11 -32 0 normal -1 sprites/tropic_desert.png 8bpp 202 100 20 6 13 12 normal -1 sprites/tropic_desert.png 8bpp 234 100 13 7 -5 16 normal -1 sprites/tropic_desert.png 8bpp 266 100 20 6 -31 5 normal -1 sprites/tropic_desert.png 8bpp 298 100 13 7 -6 0 normal -1 sprites/tropic_desert.png 8bpp 330 100 8 4 26 13 normal -1 sprites/tropic_desert.png 8bpp 346 100 12 3 -5 20 normal -1 sprites/tropic_desert.png 8bpp 364 100 8 5 -31 6 normal -1 sprites/tropic_desert.png 8bpp 380 100 15 4 -6 0 normal -1 sprites/tropic_desert.png 8bpp 10 130 38 27 -5 -8 normal -1 sprites/tropic_desert.png 8bpp 58 130 37 20 -4 11 normal -1 sprites/tropic_desert.png 8bpp 106 130 37 26 -31 5 normal -1 sprites/tropic_desert.png 8bpp 154 130 38 20 -31 -8 normal -1 sprites/tropic_desert.png 8bpp 202 130 16 9 17 11 normal -1 sprites/tropic_desert.png 8bpp 234 130 15 9 -6 22 normal -1 sprites/tropic_desert.png 8bpp 266 130 16 9 -31 3 normal -1 sprites/tropic_desert.png 8bpp 298 130 15 9 -7 -8 normal -1 sprites/tropic_desert.png 8bpp 330 130 8 7 25 11 normal -1 sprites/tropic_desert.png 8bpp 346 130 10 5 -4 26 normal -1 sprites/tropic_desert.png 8bpp 364 130 8 7 -31 5 normal -1 sprites/tropic_desert.png 8bpp 380 130 12 6 -5 -8 normal -1 * 7 02 05 40 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/tropic_forest.png 8bpp 10 10 38 19 -5 0 normal -1 sprites/tropic_forest.png 8bpp 58 10 38 18 -5 13 normal -1 sprites/tropic_forest.png 8bpp 106 10 38 18 -31 13 normal -1 sprites/tropic_forest.png 8bpp 154 10 38 19 -31 0 normal -1 sprites/tropic_forest.png 8bpp 202 10 19 9 14 11 normal -1 sprites/tropic_forest.png 8bpp 234 10 16 9 -7 22 normal -1 sprites/tropic_forest.png 8bpp 266 10 19 9 -31 11 normal -1 sprites/tropic_forest.png 8bpp 298 10 16 9 -7 0 normal -1 sprites/tropic_forest.png 8bpp 330 10 8 6 25 13 normal -1 sprites/tropic_forest.png 8bpp 346 10 12 4 -5 27 normal -1 sprites/tropic_forest.png 8bpp 364 10 8 6 -31 13 normal -1 sprites/tropic_forest.png 8bpp 380 10 12 5 -5 0 normal -1 sprites/tropic_forest.png 8bpp 10 40 40 11 -7 0 normal -1 sprites/tropic_forest.png 8bpp 58 40 39 18 -6 5 normal -1 sprites/tropic_forest.png 8bpp 106 40 38 11 -31 12 normal -1 sprites/tropic_forest.png 8bpp 154 40 39 18 -31 0 normal -1 sprites/tropic_forest.png 8bpp 202 40 20 6 13 5 normal -1 sprites/tropic_forest.png 8bpp 234 40 13 7 -6 16 normal -1 sprites/tropic_forest.png 8bpp 266 40 20 6 -31 12 normal -1 sprites/tropic_forest.png 8bpp 298 40 13 7 -5 0 normal -1 sprites/tropic_forest.png 8bpp 330 40 8 5 25 6 normal -1 sprites/tropic_forest.png 8bpp 346 40 12 3 -5 20 normal -1 sprites/tropic_forest.png 8bpp 364 40 8 4 -31 13 normal -1 sprites/tropic_forest.png 8bpp 380 40 15 4 -7 0 normal -1 sprites/tropic_forest.png 8bpp 10 70 38 20 -5 -8 normal -1 sprites/tropic_forest.png 8bpp 58 70 38 26 -5 5 normal -1 sprites/tropic_forest.png 8bpp 106 70 37 20 -31 11 normal -1 sprites/tropic_forest.png 8bpp 154 70 38 27 -31 -8 normal -1 sprites/tropic_forest.png 8bpp 202 70 16 9 17 3 normal -1 sprites/tropic_forest.png 8bpp 234 70 15 9 -7 22 normal -1 sprites/tropic_forest.png 8bpp 266 70 16 9 -31 11 normal -1 sprites/tropic_forest.png 8bpp 298 70 15 9 -6 -8 normal -1 sprites/tropic_forest.png 8bpp 330 70 8 7 25 5 normal -1 sprites/tropic_forest.png 8bpp 346 70 10 5 -4 27 normal -1 sprites/tropic_forest.png 8bpp 364 70 8 7 -31 11 normal -1 sprites/tropic_forest.png 8bpp 380 70 12 6 -5 -8 normal -1 sprites/tropic_forest.png 8bpp 10 100 39 18 -6 0 normal -1 sprites/tropic_forest.png 8bpp 58 100 38 11 -5 12 normal -1 sprites/tropic_forest.png 8bpp 106 100 39 18 -31 5 normal -1 sprites/tropic_forest.png 8bpp 154 100 40 11 -32 0 normal -1 sprites/tropic_forest.png 8bpp 202 100 20 6 13 12 normal -1 sprites/tropic_forest.png 8bpp 234 100 13 7 -5 16 normal -1 sprites/tropic_forest.png 8bpp 266 100 20 6 -31 5 normal -1 sprites/tropic_forest.png 8bpp 298 100 13 7 -6 0 normal -1 sprites/tropic_forest.png 8bpp 330 100 8 4 26 13 normal -1 sprites/tropic_forest.png 8bpp 346 100 12 3 -5 20 normal -1 sprites/tropic_forest.png 8bpp 364 100 8 5 -31 6 normal -1 sprites/tropic_forest.png 8bpp 380 100 15 4 -6 0 normal -1 sprites/tropic_forest.png 8bpp 10 130 38 27 -5 -8 normal -1 sprites/tropic_forest.png 8bpp 58 130 37 20 -4 11 normal -1 sprites/tropic_forest.png 8bpp 106 130 37 26 -31 5 normal -1 sprites/tropic_forest.png 8bpp 154 130 38 20 -31 -8 normal -1 sprites/tropic_forest.png 8bpp 202 130 16 9 17 11 normal -1 sprites/tropic_forest.png 8bpp 234 130 15 9 -6 22 normal -1 sprites/tropic_forest.png 8bpp 266 130 16 9 -31 3 normal -1 sprites/tropic_forest.png 8bpp 298 130 15 9 -7 -8 normal -1 sprites/tropic_forest.png 8bpp 330 130 8 7 25 11 normal -1 sprites/tropic_forest.png 8bpp 346 130 10 5 -4 26 normal -1 sprites/tropic_forest.png 8bpp 364 130 8 7 -31 5 normal -1 sprites/tropic_forest.png 8bpp 380 130 12 6 -5 -8 normal -1 * 7 02 05 41 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/tropic_desert.png 8bpp 10 210 38 19 -5 0 normal -1 sprites/tropic_desert.png 8bpp 58 210 38 18 -5 13 normal -1 sprites/tropic_desert.png 8bpp 106 210 38 18 -31 13 normal -1 sprites/tropic_desert.png 8bpp 154 210 38 19 -31 0 normal -1 sprites/tropic_desert.png 8bpp 202 210 19 9 14 11 normal -1 sprites/tropic_desert.png 8bpp 234 210 16 9 -7 22 normal -1 sprites/tropic_desert.png 8bpp 266 210 19 9 -31 11 normal -1 sprites/tropic_desert.png 8bpp 298 210 16 9 -7 0 normal -1 sprites/tropic_desert.png 8bpp 330 210 8 6 25 13 normal -1 sprites/tropic_desert.png 8bpp 346 210 12 4 -5 27 normal -1 sprites/tropic_desert.png 8bpp 364 210 8 6 -31 13 normal -1 sprites/tropic_desert.png 8bpp 380 210 12 5 -5 0 normal -1 sprites/tropic_desert.png 8bpp 10 240 40 11 -7 0 normal -1 sprites/tropic_desert.png 8bpp 58 240 39 18 -6 5 normal -1 sprites/tropic_desert.png 8bpp 106 240 38 11 -31 12 normal -1 sprites/tropic_desert.png 8bpp 154 240 39 18 -31 0 normal -1 sprites/tropic_desert.png 8bpp 202 240 20 6 13 5 normal -1 sprites/tropic_desert.png 8bpp 234 240 13 7 -6 16 normal -1 sprites/tropic_desert.png 8bpp 266 240 20 6 -31 12 normal -1 sprites/tropic_desert.png 8bpp 298 240 13 7 -5 0 normal -1 sprites/tropic_desert.png 8bpp 330 240 8 5 25 6 normal -1 sprites/tropic_desert.png 8bpp 346 240 12 3 -5 20 normal -1 sprites/tropic_desert.png 8bpp 364 240 8 4 -31 13 normal -1 sprites/tropic_desert.png 8bpp 380 240 15 4 -7 0 normal -1 sprites/tropic_desert.png 8bpp 10 270 38 20 -5 -8 normal -1 sprites/tropic_desert.png 8bpp 58 270 38 26 -5 5 normal -1 sprites/tropic_desert.png 8bpp 106 270 37 20 -31 11 normal -1 sprites/tropic_desert.png 8bpp 154 270 38 27 -31 -8 normal -1 sprites/tropic_desert.png 8bpp 202 270 16 9 17 3 normal -1 sprites/tropic_desert.png 8bpp 234 270 15 9 -7 22 normal -1 sprites/tropic_desert.png 8bpp 266 270 16 9 -31 11 normal -1 sprites/tropic_desert.png 8bpp 298 270 15 9 -6 -8 normal -1 sprites/tropic_desert.png 8bpp 330 270 8 7 25 5 normal -1 sprites/tropic_desert.png 8bpp 346 270 10 5 -4 27 normal -1 sprites/tropic_desert.png 8bpp 364 270 8 7 -31 11 normal -1 sprites/tropic_desert.png 8bpp 380 270 12 6 -5 -8 normal -1 sprites/tropic_desert.png 8bpp 10 300 39 18 -6 0 normal -1 sprites/tropic_desert.png 8bpp 58 300 38 11 -5 12 normal -1 sprites/tropic_desert.png 8bpp 106 300 39 18 -31 5 normal -1 sprites/tropic_desert.png 8bpp 154 300 40 11 -32 0 normal -1 sprites/tropic_desert.png 8bpp 202 300 20 6 13 12 normal -1 sprites/tropic_desert.png 8bpp 234 300 13 7 -5 16 normal -1 sprites/tropic_desert.png 8bpp 266 300 20 6 -31 5 normal -1 sprites/tropic_desert.png 8bpp 298 300 13 7 -6 0 normal -1 sprites/tropic_desert.png 8bpp 330 300 8 4 26 13 normal -1 sprites/tropic_desert.png 8bpp 346 300 12 3 -5 20 normal -1 sprites/tropic_desert.png 8bpp 364 300 8 5 -31 6 normal -1 sprites/tropic_desert.png 8bpp 380 300 15 4 -6 0 normal -1 sprites/tropic_desert.png 8bpp 10 330 38 27 -5 -8 normal -1 sprites/tropic_desert.png 8bpp 58 330 37 20 -4 11 normal -1 sprites/tropic_desert.png 8bpp 106 330 37 26 -31 5 normal -1 sprites/tropic_desert.png 8bpp 154 330 38 20 -31 -8 normal -1 sprites/tropic_desert.png 8bpp 202 330 16 9 17 11 normal -1 sprites/tropic_desert.png 8bpp 234 330 15 9 -6 22 normal -1 sprites/tropic_desert.png 8bpp 266 330 16 9 -31 3 normal -1 sprites/tropic_desert.png 8bpp 298 330 15 9 -7 -8 normal -1 sprites/tropic_desert.png 8bpp 330 330 8 7 25 11 normal -1 sprites/tropic_desert.png 8bpp 346 330 10 5 -4 26 normal -1 sprites/tropic_desert.png 8bpp 364 330 8 7 -31 5 normal -1 sprites/tropic_desert.png 8bpp 380 330 12 6 -5 -8 normal -1 * 7 02 05 42 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/tropic_forest.png 8bpp 10 210 38 19 -5 0 normal -1 sprites/tropic_forest.png 8bpp 58 210 38 18 -5 13 normal -1 sprites/tropic_forest.png 8bpp 106 210 38 18 -31 13 normal -1 sprites/tropic_forest.png 8bpp 154 210 38 19 -31 0 normal -1 sprites/tropic_forest.png 8bpp 202 210 19 9 14 11 normal -1 sprites/tropic_forest.png 8bpp 234 210 16 9 -7 22 normal -1 sprites/tropic_forest.png 8bpp 266 210 19 9 -31 11 normal -1 sprites/tropic_forest.png 8bpp 298 210 16 9 -7 0 normal -1 sprites/tropic_forest.png 8bpp 330 210 8 6 25 13 normal -1 sprites/tropic_forest.png 8bpp 346 210 12 4 -5 27 normal -1 sprites/tropic_forest.png 8bpp 364 210 8 6 -31 13 normal -1 sprites/tropic_forest.png 8bpp 380 210 12 5 -5 0 normal -1 sprites/tropic_forest.png 8bpp 10 240 40 11 -7 0 normal -1 sprites/tropic_forest.png 8bpp 58 240 39 18 -6 5 normal -1 sprites/tropic_forest.png 8bpp 106 240 38 11 -31 12 normal -1 sprites/tropic_forest.png 8bpp 154 240 39 18 -31 0 normal -1 sprites/tropic_forest.png 8bpp 202 240 20 6 13 5 normal -1 sprites/tropic_forest.png 8bpp 234 240 13 7 -6 16 normal -1 sprites/tropic_forest.png 8bpp 266 240 20 6 -31 12 normal -1 sprites/tropic_forest.png 8bpp 298 240 13 7 -5 0 normal -1 sprites/tropic_forest.png 8bpp 330 240 8 5 25 6 normal -1 sprites/tropic_forest.png 8bpp 346 240 12 3 -5 20 normal -1 sprites/tropic_forest.png 8bpp 364 240 8 4 -31 13 normal -1 sprites/tropic_forest.png 8bpp 380 240 15 4 -7 0 normal -1 sprites/tropic_forest.png 8bpp 10 270 38 20 -5 -8 normal -1 sprites/tropic_forest.png 8bpp 58 270 38 26 -5 5 normal -1 sprites/tropic_forest.png 8bpp 106 270 37 20 -31 11 normal -1 sprites/tropic_forest.png 8bpp 154 270 38 27 -31 -8 normal -1 sprites/tropic_forest.png 8bpp 202 270 16 9 17 3 normal -1 sprites/tropic_forest.png 8bpp 234 270 15 9 -7 22 normal -1 sprites/tropic_forest.png 8bpp 266 270 16 9 -31 11 normal -1 sprites/tropic_forest.png 8bpp 298 270 15 9 -6 -8 normal -1 sprites/tropic_forest.png 8bpp 330 270 8 7 25 5 normal -1 sprites/tropic_forest.png 8bpp 346 270 10 5 -4 27 normal -1 sprites/tropic_forest.png 8bpp 364 270 8 7 -31 11 normal -1 sprites/tropic_forest.png 8bpp 380 270 12 6 -5 -8 normal -1 sprites/tropic_forest.png 8bpp 10 300 39 18 -6 0 normal -1 sprites/tropic_forest.png 8bpp 58 300 38 11 -5 12 normal -1 sprites/tropic_forest.png 8bpp 106 300 39 18 -31 5 normal -1 sprites/tropic_forest.png 8bpp 154 300 40 11 -32 0 normal -1 sprites/tropic_forest.png 8bpp 202 300 20 6 13 12 normal -1 sprites/tropic_forest.png 8bpp 234 300 13 7 -5 16 normal -1 sprites/tropic_forest.png 8bpp 266 300 20 6 -31 5 normal -1 sprites/tropic_forest.png 8bpp 298 300 13 7 -6 0 normal -1 sprites/tropic_forest.png 8bpp 330 300 8 4 26 13 normal -1 sprites/tropic_forest.png 8bpp 346 300 12 3 -5 20 normal -1 sprites/tropic_forest.png 8bpp 364 300 8 5 -31 6 normal -1 sprites/tropic_forest.png 8bpp 380 300 15 4 -6 0 normal -1 sprites/tropic_forest.png 8bpp 10 330 38 27 -5 -8 normal -1 sprites/tropic_forest.png 8bpp 58 330 37 20 -4 11 normal -1 sprites/tropic_forest.png 8bpp 106 330 37 26 -31 5 normal -1 sprites/tropic_forest.png 8bpp 154 330 38 20 -31 -8 normal -1 sprites/tropic_forest.png 8bpp 202 330 16 9 17 11 normal -1 sprites/tropic_forest.png 8bpp 234 330 15 9 -6 22 normal -1 sprites/tropic_forest.png 8bpp 266 330 16 9 -31 3 normal -1 sprites/tropic_forest.png 8bpp 298 330 15 9 -7 -8 normal -1 sprites/tropic_forest.png 8bpp 330 330 8 7 25 11 normal -1 sprites/tropic_forest.png 8bpp 346 330 10 5 -4 26 normal -1 sprites/tropic_forest.png 8bpp 364 330 8 7 -31 5 normal -1 sprites/tropic_forest.png 8bpp 380 330 12 6 -5 -8 normal -1 * 7 02 05 43 01 00 00 00 -1 * 14 02 05 44 81 81 00 FF 01 40 00 01 01 41 00 -1 * 14 02 05 45 81 81 00 FF 01 42 00 01 01 43 00 -1 * 14 02 05 46 81 80 00 FF 01 44 00 00 00 45 00 -1 * 6 07 83 01 \7! 02 01 -1 * 7 03 05 01 06 00 46 00 openttd-1.5.3/media/extra_grf/rivers/rapids.nfo0000644000000000000000000001340012627373446020247 0ustar rootroot// // $Id: rapids.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Rapid graphics" -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 10 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 10 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 10 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 10 64 39 -31 -8 normal -1 * 7 02 05 00 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 60 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 60 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 60 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 60 64 39 -31 -8 normal -1 * 7 02 05 01 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 110 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 110 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 110 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 110 64 39 -31 -8 normal -1 * 7 02 05 02 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 160 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 160 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 160 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 160 64 39 -31 -8 normal -1 * 7 02 05 03 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 210 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 210 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 210 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 210 64 39 -31 -8 normal -1 * 7 02 05 04 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 260 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 260 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 260 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 260 64 39 -31 -8 normal -1 * 7 02 05 05 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 310 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 310 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 310 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 310 64 39 -31 -8 normal -1 * 7 02 05 06 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 360 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 360 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 360 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 360 64 39 -31 -8 normal -1 * 7 02 05 07 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 410 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 410 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 410 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 410 64 39 -31 -8 normal -1 * 7 02 05 08 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 460 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 460 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 460 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 460 64 39 -31 -8 normal -1 * 7 02 05 09 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 510 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 510 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 510 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 510 64 39 -31 -8 normal -1 * 7 02 05 0A 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 560 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 560 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 560 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 560 64 39 -31 -8 normal -1 * 7 02 05 0B 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 610 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 610 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 610 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 610 64 39 -31 -8 normal -1 * 7 02 05 0C 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 660 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 660 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 660 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 660 64 39 -31 -8 normal -1 * 7 02 05 0D 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 710 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 710 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 710 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 710 64 39 -31 -8 normal -1 * 7 02 05 0E 01 00 00 00 -1 * 4 01 05 01 04 -1 sprites/rapids.png 8bpp 10 760 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 90 760 64 39 -31 -8 normal -1 sprites/rapids.png 8bpp 170 760 64 23 -31 0 normal -1 sprites/rapids.png 8bpp 250 760 64 39 -31 -8 normal -1 * 7 02 05 0F 01 00 00 00 -1 * 39 02 05 10 80 00 01 10 00 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A 00 0B 00 0C 00 0D 00 0E 00 0F 00 -1 * 7 03 05 01 05 00 10 00 openttd-1.5.3/media/extra_grf/rivers/tropic_desert.png0000644000000000000000000003633612627373446021652 0ustar rootrootPNG  IHDRa pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPLTE 000@@@PPPdddttt4~"m${ 뛚OQݝz/86 oNuBgNW_vffFp/8F{F!fDzoigw_0?_o+in/if99Cw;\57!`P:;Q͜fUS ON5q>wW_ֱcr&ls ݝNؐ˒nXN+ p77Mvj'S_N7v_{/8?c쏬Tx,+ra )R_|:tNnkf'fI˴7~r9yy.'ʛfF,k𭙝2B7;,3wNUn@B_親o~i4{Nku\G`n^v03}r<)@BPww3Ly?Gb(? 77SʫS~xb,H~1jOη oıIH88t5|BӫljrWynOJ{#v] /s>og5@BF<^N?>_4߾ U  _ 7i@& HҤiҀ4 MIzl}VhrwgWa YȄkp=B⸾ç|N3dɏ-yAUC X{'TpE|{}7e@YCy P*z76ڛ:*fY=Ufu ǿ Nj!tY1<>WHhVȐudY1n֛ &PODD Yswww'&F˒Q2j*!@{QQvT"&"fB~OϿ>]\~"Ī*< H"|qq0= DLo6+r 0@'BP,U텋 `]}Cl֛u]DrYUȄjڨ(`g`frjҐUZ=˱rͪA}¨ATnF*"fY!:ƸSBV"& &} ț!C,Q7UܭK).S@R?>?0Sʬo!yOƾ !b͐5 1{;-"n@,aF^\{:.1u " Tfr0$dLՄ Ր.8}]~7՟2c?YĔDq†y螻0|*:7d2@D]Q7:.b'M7ƵUUu6=#oa'/={3aP)Ǐ@ 9w5]ߒd~ޞr$3|r/f4 Gߒk ]|! U%XOI`ĒH~3\K:M2g;!k[BBh@4 MIҀ4i@& HҤiҀNt:T]O( ?|H6!b}V8v285Cx3,Yl?{AT¶i WrA᰼*@`[ayksIr7.=RV dLQvp ى N@qQA0@p 8t`ðW^i; Y@T"CS@2PYKdǣÛA`s)Dvd<ԸݟE8r=!SUa-2>`8 b!CD56 k>*ce0F :fDG ^{CADčM_,Xd]FXϬʋp _HqS?~愽7d CE!6DP7@6AA^ 1=FDɿ YWIlIL/yJa븈-9 PYsH$To( ::R(G*NeQTTq}2`q5:U|w]\|5*"A 6v$8:LjJU)7A&2ԽY9OϒIszx! mh) !/jЬF>:a|X~01iK AS2J|8 Q>~SQuIH#?bB*0 [NZ!n?< q}p=dd6~ZiHzlc..w9~? !\ɐI*8m\ *z?\O |XiN)_Yſ_4qb{I e95JS@_9Ÿy}I012FDҧ.c>NrT$P(!H7WS3tδ9pI?&n@Z~E@B&_98$ǐGO33YƵ+!)\{u7vιFCoڕGEZ!Ttm@4 ]'^{s7yf{07싗ү?0?N{Yee J[L~jT'aF@މ$Ę?I._ Na\R\.gK: Uj/XnA?;1{ ׂ̫(HVg)ˇ"V,M&㿹Z}_zĘÞ6սZ{@}AAaV%ٛT>PVgb‚{2*e>YwOH* GRIL_H2O UfY/b1%V=>`.oHaRX7.}RQ{ч}aaݼ7!QX+\^^|b_/=D+I %~yӧO?]Nِ]WpΖL*l&c,%wBlW^2~5W(+UJ]bnլx_@b6:R+χC^W$ 箬>/7|[_Q6vL]bwwqK8HoFw]יYۻv*z!xnnrC QI^jeGyonެ7q)%:,cz[)\aY+/xb缟*./}+>&3zcL#+w?17Y0kl=Sf#ͭnk_Xx"DZo,nuʼnuHba$!бŸ(u g{-UWVfaZXH)F^+ҵUc_;ڟ5)WV}$SF=mkvmW(^?? d^K@Bُ y@Bh  ޯ; n@t}JRYXXՁ#i@pwtZY}@B}+, ȹݕyA}W˃ )%|; mj[ HiҀ4 MIҀ4i@4 E'gN[©z.;D;{ߵD^ݝ>sr6h|jޏ>{ 8Ng?H7T9R0Lq S{'{X8W$]*E(nN{hBϝҝ&'~7w촻Hb{M /,+{{7tB'e ) )s,H+|~:qg;nIh~f"qV/VL.tqy ZYz@k)v5bpwI/q"eZa~yT_@}nKe_z<%^?hS\@$iWxU!ҹ(%._ YX}-/L]2>q ^9 Wu_Ջ5uwJy!!\}ErMڐM3s[yBaiHwgr`n,\2[t;Vw hHdV*{T"es/'l^X>O y޻/Đ1ÍOqo;_]اMLgT {w#77$sI pzq/n 2kuCtI[ǡpbRPg)@߻'!똒i4{.Nl__s pf:T{-B^|>@NԣgI╳ƭxb@RYB, , )#{ׇpLHfxg?V q=B OOr*{Y-@ۋˮ!aakFa ٻ{e:`©akjmJRcJ< A1 ,Ygʓe4ˋHbzNzYo<݋̯SVr>$" t) AYk);LN6pw>֬$:i~Iwշ9&rnpV{fV:vB_:wn.8r"tg3CW<__zy{777mƕ X,_ytG)ݕ1VeU^]2dnn4S7"IWv}[+2U0Qdvl씇VtÖ%-6ͽpŋi1%.VϳO$ݗbcW__iřW"b|$'ߠ"}|I0g-Ivo(^DJ麸nu9AuNo$Qm2/Թ-@:br^BI |1W_/jU !ߦ@W$Ŀ>6F}+/m [ IҤi@4 HiҀ4 M& HҤi@4 HiҀ4i@& HҤi@4 HIҀ4i@& HҤi@4 MIҀ4i@& HҤiҀ4 MIҀ4@B5S]nw%\Q&3s[?wGW/AD}߱5U{Y [E [p@s[>&$1'uF*w/~u,bGrN'0ʄΌ$,H': 1@lE^~k@c CAt( D\o7s#%MPw?Ioc 1((NE\߮]JwD) sa1h@ "n9Q1Q(%${Λ$FI)%Y .ַq:Xwʲ8$`)u)f+p ̅1 i|xȓq 7 G|mf#aqc1ؐ"eUsqH]G#kw/heIt1.KTQx<` a&C@(F{`snJ>~\߽]EUGQ:.R: c{.7 YI2&nrlCB92}Fn?mome;5N u$vkMwDzD0ݪ>-^Ekԓ \ܦfYIgI[!7,Ņӫnd|;U+ydFa _c;P'x!\ SdzmGfO! .KNȸTvoc9 0_8OWRH:WxKmL*`ߖL] G8N Ac/a?*x!]kq]e`ϼ_E@qHDJqx@21K!qn1]߮"v*cR*Gc>m)@J1_,y]~Ƶ[v)u@,Q). ,"nvg8.KR:yde qw K).ַ{ Kq9^)pH]*v1TBg Ӯo 0sxaA*"N B@3{>Jp|χȀPu,{v*SU0^^|ԝ~,""!ñC ȃff/4Eܜr{}z(/*@EfbBpgd@T,̓V;uk,2cl B]V@.H!US Ѭ:|1| AUaclDE5B~x c@uO9wwwwbb,y}ߪK8uI = DLD̄tyC"% *13 YE58JsK).@2low+ygU G4zPL*S=D30Iۋ2@Hofdl }ӅOv91d7:ELUEUU@Ey|E8~!UUQ~WUM).`P Fy=RBC*0y11aLCsJ%sV2a({0 XUUWU;2:Ԥ!@z4*6GjVzܨvQED,+YqcJ*UD!ФOys=d`"v4ꦊu)u "CT*oB}j\"»?/WRRU!Db1&Ai>UwZJ1Eܬ Y4ÌqpOu\,bD~"aHȘ69wӫ UA!u]?v0@1)lVÐ5Ʌ$࡫ܐ!ucG93߬7븈)0o7 תU挺fdQ1=gof5 "=Ǐ@ 9w5]ߒd~ޞr$3|r/f4 vo. uA$0~~zbI_$S=5h9рL YC BBҤiҀ4 MIҀ4i@& H4muRe0L'JBlDtHj) 'N~Tfo%Y8eD dm(c՗ ~2kNLvR'# n=  }ua+@` ,] @Mu*MX!)  鬥2cQ 0yŹ"2ԸݟE8r=} 1ͬ nySHA\`N0 =TB8:` )>*a՟3DN ! cߦz/ug,2 ܮo#,gV{E8KF٩ sޛC "(QMPxebȻci?6=FDɿ YWIlIL/yJa븈-9 PYsH$To( ::R(G*NeQTT#@)+&2LƟU|w]\|5*"A 6v$8:LjJUiLW 2zPyz4Nu V@p|'lC;O Axd!\ h\WA0{>,?d %OcbsCa>܊$ I1U+m`vrZ_e722e}?4uCE=1ƋwûEndZ$ 6.kfnj>,4~V~x 1'c!*{D (ANOL~wb !c4eg\<Ȏ8Y~R;v S>$ *w*Zcq: g_~C31dѱSk)̸Lq~yHl!j'T(vl  DR<ʀ*CbwĨչ+{DnL Ŧe!+2L_/UE/rF. jlwm.*M~@BCjy憝.kjN?{Ve*\[_%ǕӔo3L Woh Y)5jIJ&O)x(fw~mxWz++~` Ϯ6?g)~KUaH^|.TaaЀjJ\_H2O UfY/b1nurKV+YXz3R\<H*ޯXX_y}8Bݼ7!QX+\^^|b_/=D+I %~yӧO?]Nِ]WpΖL*l&c,%ww?!^YV{dռ_үXV)ubcefz=TNO9uՑZ~>J"YhO?weycW¾X¶)cSƔQwK8HoFw]יY;ҳ[;޳mV]n(}!> ^~֋wV^qH5֛&.1Dv`Lϲz++#k¾/X>ZeOc2w$R}yfYo F0榽= fQ;gJPuՍx <_ĘHŭN8I,,D;İ:V}^ެR[0^804YSJ7V !kƾewƵ?kS0NԭIzښ=H]%{g.J.G_HW?%ZJOWB~pm@GTXg\_H~Ip3Uʯ$~IrW¸[al@ݯk zKZHh@N/IlCVm@4 HiҀ4 MIҤd.:?9u*qBG~꒹Ldzj]kH|ӟr6gcڏ7VvOLg*G )0S{'{X8W$]*E(nN{hBtwr&{Kw\,{ߔ&,X^D$^XJw`J?BHn=}n^> N{S@RY5V wV}fDgf˟-r gbuOKכH8 @k)v/;M*w/x) ḲsCt~_*q.IC:$ˁHJdBsQJ\@z)Xnyw'Dfꊕ NZYʽT^c-#EVc +l҆lbLr KC;{#tc)䒙twJz3d JeoJb qV !{Ž>f!Nm 5}9, SzvdFI>7lЋ/$."77츸YB{OB՝;WSUxN LB·cJ @:MBws pf:`(|<Wsя$xTV 1QX)^CBER!{=\}Rt8XW$@wBߙ:)={΅@nTw17Z.pŋ?n@-:'u*Ld鴂,  v)(ðe \9p3`:ry<@/e PثM\$1I=HI^ܫWӽ8K:J5Qp+ԥWHXoIOBn"<&^K)anFZ0:I|NX}A3k" , RzЗΝ \dYi,plIRP%-6._A^؉6}Jqr篼IahI778K E277WP}\~+}gd_/eI{_KFl'Ny{a_N;lw@:tFBZ<򊀄fSoh<{dI}Y.9tF8M"b|$ 9*_8)=yכ" uH)ݸx &#HXaZ7 9[RKHm ȼ61&cbc  9FImz8l9Іs172QƱMl/3& HiҀ4 MIҀ4i@4 HiҀ4 MIҤi@4 HiҀ4 M& HҤi@4 HiҀ4i@& HҤqF*LeYIENDB`openttd-1.5.3/media/extra_grf/rivers/toyland.nfo0000644000000000000000000002047712627373446020453 0ustar rootroot// // $Id: toyland.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Toyland river graphics by andythenorth (Andrew Parkhouse)" -1 * 4 01 05 01 3C -1 sprites/toyland.png 8bpp 10 10 38 19 -5 0 normal -1 sprites/toyland.png 8bpp 58 10 38 18 -5 13 normal -1 sprites/toyland.png 8bpp 106 10 38 18 -31 13 normal -1 sprites/toyland.png 8bpp 154 10 38 19 -31 0 normal -1 sprites/toyland.png 8bpp 202 10 19 9 14 11 normal -1 sprites/toyland.png 8bpp 234 10 16 9 -7 22 normal -1 sprites/toyland.png 8bpp 266 10 19 9 -31 11 normal -1 sprites/toyland.png 8bpp 298 10 16 9 -7 0 normal -1 sprites/toyland.png 8bpp 330 10 8 6 25 13 normal -1 sprites/toyland.png 8bpp 346 10 12 4 -5 27 normal -1 sprites/toyland.png 8bpp 364 10 8 6 -31 13 normal -1 sprites/toyland.png 8bpp 380 10 12 5 -5 0 normal -1 sprites/toyland.png 8bpp 10 40 40 11 -7 0 normal -1 sprites/toyland.png 8bpp 58 40 39 18 -6 5 normal -1 sprites/toyland.png 8bpp 106 40 38 11 -31 12 normal -1 sprites/toyland.png 8bpp 154 40 39 18 -31 0 normal -1 sprites/toyland.png 8bpp 202 40 20 6 13 5 normal -1 sprites/toyland.png 8bpp 234 40 13 7 -6 16 normal -1 sprites/toyland.png 8bpp 266 40 20 6 -31 12 normal -1 sprites/toyland.png 8bpp 298 40 13 7 -5 0 normal -1 sprites/toyland.png 8bpp 330 40 8 5 25 6 normal -1 sprites/toyland.png 8bpp 346 40 12 3 -5 20 normal -1 sprites/toyland.png 8bpp 364 40 8 4 -31 13 normal -1 sprites/toyland.png 8bpp 380 40 15 4 -7 0 normal -1 sprites/toyland.png 8bpp 10 70 38 20 -5 -8 normal -1 sprites/toyland.png 8bpp 58 70 38 26 -5 5 normal -1 sprites/toyland.png 8bpp 106 70 37 20 -31 11 normal -1 sprites/toyland.png 8bpp 154 70 38 27 -31 -8 normal -1 sprites/toyland.png 8bpp 202 70 16 9 17 3 normal -1 sprites/toyland.png 8bpp 234 70 15 9 -7 22 normal -1 sprites/toyland.png 8bpp 266 70 16 9 -31 11 normal -1 sprites/toyland.png 8bpp 298 70 15 9 -6 -8 normal -1 sprites/toyland.png 8bpp 330 70 8 7 25 5 normal -1 sprites/toyland.png 8bpp 346 70 10 5 -4 27 normal -1 sprites/toyland.png 8bpp 364 70 8 7 -31 11 normal -1 sprites/toyland.png 8bpp 380 70 12 6 -5 -8 normal -1 sprites/toyland.png 8bpp 10 100 39 18 -6 0 normal -1 sprites/toyland.png 8bpp 58 100 38 11 -5 12 normal -1 sprites/toyland.png 8bpp 106 100 39 18 -31 5 normal -1 sprites/toyland.png 8bpp 154 100 40 11 -32 0 normal -1 sprites/toyland.png 8bpp 202 100 20 6 13 12 normal -1 sprites/toyland.png 8bpp 234 100 13 7 -5 16 normal -1 sprites/toyland.png 8bpp 266 100 20 6 -31 5 normal -1 sprites/toyland.png 8bpp 298 100 13 7 -6 0 normal -1 sprites/toyland.png 8bpp 330 100 8 4 26 13 normal -1 sprites/toyland.png 8bpp 346 100 12 3 -5 20 normal -1 sprites/toyland.png 8bpp 364 100 8 5 -31 6 normal -1 sprites/toyland.png 8bpp 380 100 15 4 -6 0 normal -1 sprites/toyland.png 8bpp 10 130 38 27 -5 -8 normal -1 sprites/toyland.png 8bpp 58 130 37 20 -4 11 normal -1 sprites/toyland.png 8bpp 106 130 37 26 -31 5 normal -1 sprites/toyland.png 8bpp 154 130 38 20 -31 -8 normal -1 sprites/toyland.png 8bpp 202 130 16 9 17 11 normal -1 sprites/toyland.png 8bpp 234 130 15 9 -6 22 normal -1 sprites/toyland.png 8bpp 266 130 16 9 -31 3 normal -1 sprites/toyland.png 8bpp 298 130 15 9 -7 -8 normal -1 sprites/toyland.png 8bpp 330 130 8 7 25 11 normal -1 sprites/toyland.png 8bpp 346 130 10 5 -4 26 normal -1 sprites/toyland.png 8bpp 364 130 8 7 -31 5 normal -1 sprites/toyland.png 8bpp 380 130 12 6 -5 -8 normal -1 * 7 02 05 50 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/toyland.png 8bpp 10 210 38 19 -5 0 normal -1 sprites/toyland.png 8bpp 58 210 38 18 -5 13 normal -1 sprites/toyland.png 8bpp 106 210 38 18 -31 13 normal -1 sprites/toyland.png 8bpp 154 210 38 19 -31 0 normal -1 sprites/toyland.png 8bpp 202 210 19 9 14 11 normal -1 sprites/toyland.png 8bpp 234 210 16 9 -7 22 normal -1 sprites/toyland.png 8bpp 266 210 19 9 -31 11 normal -1 sprites/toyland.png 8bpp 298 210 16 9 -7 0 normal -1 sprites/toyland.png 8bpp 330 210 8 6 25 13 normal -1 sprites/toyland.png 8bpp 346 210 12 4 -5 27 normal -1 sprites/toyland.png 8bpp 364 210 8 6 -31 13 normal -1 sprites/toyland.png 8bpp 380 210 12 5 -5 0 normal -1 sprites/toyland.png 8bpp 10 240 40 11 -7 0 normal -1 sprites/toyland.png 8bpp 58 240 39 18 -6 5 normal -1 sprites/toyland.png 8bpp 106 240 38 11 -31 12 normal -1 sprites/toyland.png 8bpp 154 240 39 18 -31 0 normal -1 sprites/toyland.png 8bpp 202 240 20 6 13 5 normal -1 sprites/toyland.png 8bpp 234 240 13 7 -6 16 normal -1 sprites/toyland.png 8bpp 266 240 20 6 -31 12 normal -1 sprites/toyland.png 8bpp 298 240 13 7 -5 0 normal -1 sprites/toyland.png 8bpp 330 240 8 5 25 6 normal -1 sprites/toyland.png 8bpp 346 240 12 3 -5 20 normal -1 sprites/toyland.png 8bpp 364 240 8 4 -31 13 normal -1 sprites/toyland.png 8bpp 380 240 15 4 -7 0 normal -1 sprites/toyland.png 8bpp 10 270 38 20 -5 -8 normal -1 sprites/toyland.png 8bpp 58 270 38 26 -5 5 normal -1 sprites/toyland.png 8bpp 106 270 37 20 -31 11 normal -1 sprites/toyland.png 8bpp 154 270 38 27 -31 -8 normal -1 sprites/toyland.png 8bpp 202 270 16 9 17 3 normal -1 sprites/toyland.png 8bpp 234 270 15 9 -7 22 normal -1 sprites/toyland.png 8bpp 266 270 16 9 -31 11 normal -1 sprites/toyland.png 8bpp 298 270 15 9 -6 -8 normal -1 sprites/toyland.png 8bpp 330 270 8 7 25 5 normal -1 sprites/toyland.png 8bpp 346 270 10 5 -4 27 normal -1 sprites/toyland.png 8bpp 364 270 8 7 -31 11 normal -1 sprites/toyland.png 8bpp 380 270 12 6 -5 -8 normal -1 sprites/toyland.png 8bpp 10 300 39 18 -6 0 normal -1 sprites/toyland.png 8bpp 58 300 38 11 -5 12 normal -1 sprites/toyland.png 8bpp 106 300 39 18 -31 5 normal -1 sprites/toyland.png 8bpp 154 300 40 11 -32 0 normal -1 sprites/toyland.png 8bpp 202 300 20 6 13 12 normal -1 sprites/toyland.png 8bpp 234 300 13 7 -5 16 normal -1 sprites/toyland.png 8bpp 266 300 20 6 -31 5 normal -1 sprites/toyland.png 8bpp 298 300 13 7 -6 0 normal -1 sprites/toyland.png 8bpp 330 300 8 4 26 13 normal -1 sprites/toyland.png 8bpp 346 300 12 3 -5 20 normal -1 sprites/toyland.png 8bpp 364 300 8 5 -31 6 normal -1 sprites/toyland.png 8bpp 380 300 15 4 -6 0 normal -1 sprites/toyland.png 8bpp 10 330 38 27 -5 -8 normal -1 sprites/toyland.png 8bpp 58 330 37 20 -4 11 normal -1 sprites/toyland.png 8bpp 106 330 37 26 -31 5 normal -1 sprites/toyland.png 8bpp 154 330 38 20 -31 -8 normal -1 sprites/toyland.png 8bpp 202 330 16 9 17 11 normal -1 sprites/toyland.png 8bpp 234 330 15 9 -6 22 normal -1 sprites/toyland.png 8bpp 266 330 16 9 -31 3 normal -1 sprites/toyland.png 8bpp 298 330 15 9 -7 -8 normal -1 sprites/toyland.png 8bpp 330 330 8 7 25 11 normal -1 sprites/toyland.png 8bpp 346 330 10 5 -4 26 normal -1 sprites/toyland.png 8bpp 364 330 8 7 -31 5 normal -1 sprites/toyland.png 8bpp 380 330 12 6 -5 -8 normal -1 * 7 02 05 51 01 00 00 00 -1 * 14 02 05 52 81 80 00 FF 01 50 00 00 00 51 00 -1 * 6 07 83 01 \7! 03 01 -1 * 7 03 05 01 06 00 52 00 openttd-1.5.3/media/extra_grf/rivers/arctic.nfo0000644000000000000000000004213112627373446020235 0ustar rootroot// // $Id: arctic.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Arctic river graphics by andythenorth (Andrew Parkhouse)" -1 * 4 01 05 01 3C -1 sprites/arctic_snowy.png 8bpp 10 10 38 19 -5 0 normal -1 sprites/arctic_snowy.png 8bpp 58 10 38 18 -5 13 normal -1 sprites/arctic_snowy.png 8bpp 106 10 38 18 -31 13 normal -1 sprites/arctic_snowy.png 8bpp 154 10 38 19 -31 0 normal -1 sprites/arctic_snowy.png 8bpp 202 10 19 9 14 11 normal -1 sprites/arctic_snowy.png 8bpp 234 10 16 9 -7 22 normal -1 sprites/arctic_snowy.png 8bpp 266 10 19 9 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 298 10 16 9 -7 0 normal -1 sprites/arctic_snowy.png 8bpp 330 10 8 6 25 13 normal -1 sprites/arctic_snowy.png 8bpp 346 10 12 4 -5 27 normal -1 sprites/arctic_snowy.png 8bpp 364 10 8 6 -31 13 normal -1 sprites/arctic_snowy.png 8bpp 380 10 12 5 -5 0 normal -1 sprites/arctic_snowy.png 8bpp 10 40 40 11 -7 0 normal -1 sprites/arctic_snowy.png 8bpp 58 40 39 18 -6 5 normal -1 sprites/arctic_snowy.png 8bpp 106 40 38 11 -31 12 normal -1 sprites/arctic_snowy.png 8bpp 154 40 39 18 -31 0 normal -1 sprites/arctic_snowy.png 8bpp 202 40 20 6 13 5 normal -1 sprites/arctic_snowy.png 8bpp 234 40 13 7 -6 16 normal -1 sprites/arctic_snowy.png 8bpp 266 40 20 6 -31 12 normal -1 sprites/arctic_snowy.png 8bpp 298 40 13 7 -5 0 normal -1 sprites/arctic_snowy.png 8bpp 330 40 8 5 25 6 normal -1 sprites/arctic_snowy.png 8bpp 346 40 12 3 -5 20 normal -1 sprites/arctic_snowy.png 8bpp 364 40 8 4 -31 13 normal -1 sprites/arctic_snowy.png 8bpp 380 40 15 4 -7 0 normal -1 sprites/arctic_snowy.png 8bpp 10 70 38 20 -5 -8 normal -1 sprites/arctic_snowy.png 8bpp 58 70 38 26 -5 5 normal -1 sprites/arctic_snowy.png 8bpp 106 70 37 20 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 154 70 38 27 -31 -8 normal -1 sprites/arctic_snowy.png 8bpp 202 70 16 9 17 3 normal -1 sprites/arctic_snowy.png 8bpp 234 70 15 9 -7 22 normal -1 sprites/arctic_snowy.png 8bpp 266 70 16 9 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 298 70 15 9 -6 -8 normal -1 sprites/arctic_snowy.png 8bpp 330 70 8 7 25 5 normal -1 sprites/arctic_snowy.png 8bpp 346 70 10 5 -4 27 normal -1 sprites/arctic_snowy.png 8bpp 364 70 8 7 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 380 70 12 6 -5 -8 normal -1 sprites/arctic_snowy.png 8bpp 10 100 39 18 -6 0 normal -1 sprites/arctic_snowy.png 8bpp 58 100 38 11 -5 12 normal -1 sprites/arctic_snowy.png 8bpp 106 100 39 18 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 154 100 40 11 -32 0 normal -1 sprites/arctic_snowy.png 8bpp 202 100 20 6 13 12 normal -1 sprites/arctic_snowy.png 8bpp 234 100 13 7 -5 16 normal -1 sprites/arctic_snowy.png 8bpp 266 100 20 6 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 298 100 13 7 -6 0 normal -1 sprites/arctic_snowy.png 8bpp 330 100 8 4 26 13 normal -1 sprites/arctic_snowy.png 8bpp 346 100 12 3 -5 20 normal -1 sprites/arctic_snowy.png 8bpp 364 100 8 5 -31 6 normal -1 sprites/arctic_snowy.png 8bpp 380 100 15 4 -6 0 normal -1 sprites/arctic_snowy.png 8bpp 10 130 38 27 -5 -8 normal -1 sprites/arctic_snowy.png 8bpp 58 130 37 20 -4 11 normal -1 sprites/arctic_snowy.png 8bpp 106 130 37 26 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 154 130 38 20 -31 -8 normal -1 sprites/arctic_snowy.png 8bpp 202 130 16 9 17 11 normal -1 sprites/arctic_snowy.png 8bpp 234 130 15 9 -6 22 normal -1 sprites/arctic_snowy.png 8bpp 266 130 16 9 -31 3 normal -1 sprites/arctic_snowy.png 8bpp 298 130 15 9 -7 -8 normal -1 sprites/arctic_snowy.png 8bpp 330 130 8 7 25 11 normal -1 sprites/arctic_snowy.png 8bpp 346 130 10 5 -4 26 normal -1 sprites/arctic_snowy.png 8bpp 364 130 8 7 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 380 130 12 6 -5 -8 normal -1 * 7 02 05 30 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/arctic_brown.png 8bpp 10 10 38 19 -5 0 normal -1 sprites/arctic_brown.png 8bpp 58 10 38 18 -5 13 normal -1 sprites/arctic_brown.png 8bpp 106 10 38 18 -31 13 normal -1 sprites/arctic_brown.png 8bpp 154 10 38 19 -31 0 normal -1 sprites/arctic_brown.png 8bpp 202 10 19 9 14 11 normal -1 sprites/arctic_brown.png 8bpp 234 10 16 9 -7 22 normal -1 sprites/arctic_brown.png 8bpp 266 10 19 9 -31 11 normal -1 sprites/arctic_brown.png 8bpp 298 10 16 9 -7 0 normal -1 sprites/arctic_brown.png 8bpp 330 10 8 6 25 13 normal -1 sprites/arctic_brown.png 8bpp 346 10 12 4 -5 27 normal -1 sprites/arctic_brown.png 8bpp 364 10 8 6 -31 13 normal -1 sprites/arctic_brown.png 8bpp 380 10 12 5 -5 0 normal -1 sprites/arctic_brown.png 8bpp 10 40 40 11 -7 0 normal -1 sprites/arctic_brown.png 8bpp 58 40 39 18 -6 5 normal -1 sprites/arctic_brown.png 8bpp 106 40 38 11 -31 12 normal -1 sprites/arctic_brown.png 8bpp 154 40 39 18 -31 0 normal -1 sprites/arctic_brown.png 8bpp 202 40 20 6 13 5 normal -1 sprites/arctic_brown.png 8bpp 234 40 13 7 -6 16 normal -1 sprites/arctic_brown.png 8bpp 266 40 20 6 -31 12 normal -1 sprites/arctic_brown.png 8bpp 298 40 13 7 -5 0 normal -1 sprites/arctic_brown.png 8bpp 330 40 8 5 25 6 normal -1 sprites/arctic_brown.png 8bpp 346 40 12 3 -5 20 normal -1 sprites/arctic_brown.png 8bpp 364 40 8 4 -31 13 normal -1 sprites/arctic_brown.png 8bpp 380 40 15 4 -7 0 normal -1 sprites/arctic_brown.png 8bpp 10 70 38 20 -5 -8 normal -1 sprites/arctic_brown.png 8bpp 58 70 38 26 -5 5 normal -1 sprites/arctic_brown.png 8bpp 106 70 37 20 -31 11 normal -1 sprites/arctic_brown.png 8bpp 154 70 38 27 -31 -8 normal -1 sprites/arctic_brown.png 8bpp 202 70 16 9 17 3 normal -1 sprites/arctic_brown.png 8bpp 234 70 15 9 -7 22 normal -1 sprites/arctic_brown.png 8bpp 266 70 16 9 -31 11 normal -1 sprites/arctic_brown.png 8bpp 298 70 15 9 -6 -8 normal -1 sprites/arctic_brown.png 8bpp 330 70 8 7 25 5 normal -1 sprites/arctic_brown.png 8bpp 346 70 10 5 -4 27 normal -1 sprites/arctic_brown.png 8bpp 364 70 8 7 -31 11 normal -1 sprites/arctic_brown.png 8bpp 380 70 12 6 -5 -8 normal -1 sprites/arctic_brown.png 8bpp 10 100 39 18 -6 0 normal -1 sprites/arctic_brown.png 8bpp 58 100 38 11 -5 12 normal -1 sprites/arctic_brown.png 8bpp 106 100 39 18 -31 5 normal -1 sprites/arctic_brown.png 8bpp 154 100 40 11 -32 0 normal -1 sprites/arctic_brown.png 8bpp 202 100 20 6 13 12 normal -1 sprites/arctic_brown.png 8bpp 234 100 13 7 -5 16 normal -1 sprites/arctic_brown.png 8bpp 266 100 20 6 -31 5 normal -1 sprites/arctic_brown.png 8bpp 298 100 13 7 -6 0 normal -1 sprites/arctic_brown.png 8bpp 330 100 8 4 26 13 normal -1 sprites/arctic_brown.png 8bpp 346 100 12 3 -5 20 normal -1 sprites/arctic_brown.png 8bpp 364 100 8 5 -31 6 normal -1 sprites/arctic_brown.png 8bpp 380 100 15 4 -6 0 normal -1 sprites/arctic_brown.png 8bpp 10 130 38 27 -5 -8 normal -1 sprites/arctic_brown.png 8bpp 58 130 37 20 -4 11 normal -1 sprites/arctic_brown.png 8bpp 106 130 37 26 -31 5 normal -1 sprites/arctic_brown.png 8bpp 154 130 38 20 -31 -8 normal -1 sprites/arctic_brown.png 8bpp 202 130 16 9 17 11 normal -1 sprites/arctic_brown.png 8bpp 234 130 15 9 -6 22 normal -1 sprites/arctic_brown.png 8bpp 266 130 16 9 -31 3 normal -1 sprites/arctic_brown.png 8bpp 298 130 15 9 -7 -8 normal -1 sprites/arctic_brown.png 8bpp 330 130 8 7 25 11 normal -1 sprites/arctic_brown.png 8bpp 346 130 10 5 -4 26 normal -1 sprites/arctic_brown.png 8bpp 364 130 8 7 -31 5 normal -1 sprites/arctic_brown.png 8bpp 380 130 12 6 -5 -8 normal -1 * 7 02 05 31 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/arctic_snowy.png 8bpp 10 210 38 19 -5 0 normal -1 sprites/arctic_snowy.png 8bpp 58 210 38 18 -5 13 normal -1 sprites/arctic_snowy.png 8bpp 106 210 38 18 -31 13 normal -1 sprites/arctic_snowy.png 8bpp 154 210 38 19 -31 0 normal -1 sprites/arctic_snowy.png 8bpp 202 210 19 9 14 11 normal -1 sprites/arctic_snowy.png 8bpp 234 210 16 9 -7 22 normal -1 sprites/arctic_snowy.png 8bpp 266 210 19 9 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 298 210 16 9 -7 0 normal -1 sprites/arctic_snowy.png 8bpp 330 210 8 6 25 13 normal -1 sprites/arctic_snowy.png 8bpp 346 210 12 4 -5 27 normal -1 sprites/arctic_snowy.png 8bpp 364 210 8 6 -31 13 normal -1 sprites/arctic_snowy.png 8bpp 380 210 12 5 -5 0 normal -1 sprites/arctic_snowy.png 8bpp 10 240 40 11 -7 0 normal -1 sprites/arctic_snowy.png 8bpp 58 240 39 18 -6 5 normal -1 sprites/arctic_snowy.png 8bpp 106 240 38 11 -31 12 normal -1 sprites/arctic_snowy.png 8bpp 154 240 39 18 -31 0 normal -1 sprites/arctic_snowy.png 8bpp 202 240 20 6 13 5 normal -1 sprites/arctic_snowy.png 8bpp 234 240 13 7 -6 16 normal -1 sprites/arctic_snowy.png 8bpp 266 240 20 6 -31 12 normal -1 sprites/arctic_snowy.png 8bpp 298 240 13 7 -5 0 normal -1 sprites/arctic_snowy.png 8bpp 330 240 8 5 25 6 normal -1 sprites/arctic_snowy.png 8bpp 346 240 12 3 -5 20 normal -1 sprites/arctic_snowy.png 8bpp 364 240 8 4 -31 13 normal -1 sprites/arctic_snowy.png 8bpp 380 240 15 4 -7 0 normal -1 sprites/arctic_snowy.png 8bpp 10 270 38 20 -5 -8 normal -1 sprites/arctic_snowy.png 8bpp 58 270 38 26 -5 5 normal -1 sprites/arctic_snowy.png 8bpp 106 270 37 20 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 154 270 38 27 -31 -8 normal -1 sprites/arctic_snowy.png 8bpp 202 270 16 9 17 3 normal -1 sprites/arctic_snowy.png 8bpp 234 270 15 9 -7 22 normal -1 sprites/arctic_snowy.png 8bpp 266 270 16 9 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 298 270 15 9 -6 -8 normal -1 sprites/arctic_snowy.png 8bpp 330 270 8 7 25 5 normal -1 sprites/arctic_snowy.png 8bpp 346 270 10 5 -4 27 normal -1 sprites/arctic_snowy.png 8bpp 364 270 8 7 -31 11 normal -1 sprites/arctic_snowy.png 8bpp 380 270 12 6 -5 -8 normal -1 sprites/arctic_snowy.png 8bpp 10 300 39 18 -6 0 normal -1 sprites/arctic_snowy.png 8bpp 58 300 38 11 -5 12 normal -1 sprites/arctic_snowy.png 8bpp 106 300 39 18 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 154 300 40 11 -32 0 normal -1 sprites/arctic_snowy.png 8bpp 202 300 20 6 13 12 normal -1 sprites/arctic_snowy.png 8bpp 234 300 13 7 -5 16 normal -1 sprites/arctic_snowy.png 8bpp 266 300 20 6 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 298 300 13 7 -6 0 normal -1 sprites/arctic_snowy.png 8bpp 330 300 8 4 26 13 normal -1 sprites/arctic_snowy.png 8bpp 346 300 12 3 -5 20 normal -1 sprites/arctic_snowy.png 8bpp 364 300 8 5 -31 6 normal -1 sprites/arctic_snowy.png 8bpp 380 300 15 4 -6 0 normal -1 sprites/arctic_snowy.png 8bpp 10 330 38 27 -5 -8 normal -1 sprites/arctic_snowy.png 8bpp 58 330 37 20 -4 11 normal -1 sprites/arctic_snowy.png 8bpp 106 330 37 26 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 154 330 38 20 -31 -8 normal -1 sprites/arctic_snowy.png 8bpp 202 330 16 9 17 11 normal -1 sprites/arctic_snowy.png 8bpp 234 330 15 9 -6 22 normal -1 sprites/arctic_snowy.png 8bpp 266 330 16 9 -31 3 normal -1 sprites/arctic_snowy.png 8bpp 298 330 15 9 -7 -8 normal -1 sprites/arctic_snowy.png 8bpp 330 330 8 7 25 11 normal -1 sprites/arctic_snowy.png 8bpp 346 330 10 5 -4 26 normal -1 sprites/arctic_snowy.png 8bpp 364 330 8 7 -31 5 normal -1 sprites/arctic_snowy.png 8bpp 380 330 12 6 -5 -8 normal -1 * 7 02 05 32 01 00 00 00 -1 * 4 01 05 01 3C -1 sprites/arctic_brown.png 8bpp 10 210 38 19 -5 0 normal -1 sprites/arctic_brown.png 8bpp 58 210 38 18 -5 13 normal -1 sprites/arctic_brown.png 8bpp 106 210 38 18 -31 13 normal -1 sprites/arctic_brown.png 8bpp 154 210 38 19 -31 0 normal -1 sprites/arctic_brown.png 8bpp 202 210 19 9 14 11 normal -1 sprites/arctic_brown.png 8bpp 234 210 16 9 -7 22 normal -1 sprites/arctic_brown.png 8bpp 266 210 19 9 -31 11 normal -1 sprites/arctic_brown.png 8bpp 298 210 16 9 -7 0 normal -1 sprites/arctic_brown.png 8bpp 330 210 8 6 25 13 normal -1 sprites/arctic_brown.png 8bpp 346 210 12 4 -5 27 normal -1 sprites/arctic_brown.png 8bpp 364 210 8 6 -31 13 normal -1 sprites/arctic_brown.png 8bpp 380 210 12 5 -5 0 normal -1 sprites/arctic_brown.png 8bpp 10 240 40 11 -7 0 normal -1 sprites/arctic_brown.png 8bpp 58 240 39 18 -6 5 normal -1 sprites/arctic_brown.png 8bpp 106 240 38 11 -31 12 normal -1 sprites/arctic_brown.png 8bpp 154 240 39 18 -31 0 normal -1 sprites/arctic_brown.png 8bpp 202 240 20 6 13 5 normal -1 sprites/arctic_brown.png 8bpp 234 240 13 7 -6 16 normal -1 sprites/arctic_brown.png 8bpp 266 240 20 6 -31 12 normal -1 sprites/arctic_brown.png 8bpp 298 240 13 7 -5 0 normal -1 sprites/arctic_brown.png 8bpp 330 240 8 5 25 6 normal -1 sprites/arctic_brown.png 8bpp 346 240 12 3 -5 20 normal -1 sprites/arctic_brown.png 8bpp 364 240 8 4 -31 13 normal -1 sprites/arctic_brown.png 8bpp 380 240 15 4 -7 0 normal -1 sprites/arctic_brown.png 8bpp 10 270 38 20 -5 -8 normal -1 sprites/arctic_brown.png 8bpp 58 270 38 26 -5 5 normal -1 sprites/arctic_brown.png 8bpp 106 270 37 20 -31 11 normal -1 sprites/arctic_brown.png 8bpp 154 270 38 27 -31 -8 normal -1 sprites/arctic_brown.png 8bpp 202 270 16 9 17 3 normal -1 sprites/arctic_brown.png 8bpp 234 270 15 9 -7 22 normal -1 sprites/arctic_brown.png 8bpp 266 270 16 9 -31 11 normal -1 sprites/arctic_brown.png 8bpp 298 270 15 9 -6 -8 normal -1 sprites/arctic_brown.png 8bpp 330 270 8 7 25 5 normal -1 sprites/arctic_brown.png 8bpp 346 270 10 5 -4 27 normal -1 sprites/arctic_brown.png 8bpp 364 270 8 7 -31 11 normal -1 sprites/arctic_brown.png 8bpp 380 270 12 6 -5 -8 normal -1 sprites/arctic_brown.png 8bpp 10 300 39 18 -6 0 normal -1 sprites/arctic_brown.png 8bpp 58 300 38 11 -5 12 normal -1 sprites/arctic_brown.png 8bpp 106 300 39 18 -31 5 normal -1 sprites/arctic_brown.png 8bpp 154 300 40 11 -32 0 normal -1 sprites/arctic_brown.png 8bpp 202 300 20 6 13 12 normal -1 sprites/arctic_brown.png 8bpp 234 300 13 7 -5 16 normal -1 sprites/arctic_brown.png 8bpp 266 300 20 6 -31 5 normal -1 sprites/arctic_brown.png 8bpp 298 300 13 7 -6 0 normal -1 sprites/arctic_brown.png 8bpp 330 300 8 4 26 13 normal -1 sprites/arctic_brown.png 8bpp 346 300 12 3 -5 20 normal -1 sprites/arctic_brown.png 8bpp 364 300 8 5 -31 6 normal -1 sprites/arctic_brown.png 8bpp 380 300 15 4 -6 0 normal -1 sprites/arctic_brown.png 8bpp 10 330 38 27 -5 -8 normal -1 sprites/arctic_brown.png 8bpp 58 330 37 20 -4 11 normal -1 sprites/arctic_brown.png 8bpp 106 330 37 26 -31 5 normal -1 sprites/arctic_brown.png 8bpp 154 330 38 20 -31 -8 normal -1 sprites/arctic_brown.png 8bpp 202 330 16 9 17 11 normal -1 sprites/arctic_brown.png 8bpp 234 330 15 9 -6 22 normal -1 sprites/arctic_brown.png 8bpp 266 330 16 9 -31 3 normal -1 sprites/arctic_brown.png 8bpp 298 330 15 9 -7 -8 normal -1 sprites/arctic_brown.png 8bpp 330 330 8 7 25 11 normal -1 sprites/arctic_brown.png 8bpp 346 330 10 5 -4 26 normal -1 sprites/arctic_brown.png 8bpp 364 330 8 7 -31 5 normal -1 sprites/arctic_brown.png 8bpp 380 330 12 6 -5 -8 normal -1 * 7 02 05 33 01 00 00 00 -1 * 14 02 05 34 81 81 00 FF 01 30 00 04 04 31 00 -1 * 14 02 05 35 81 81 00 FF 01 32 00 04 04 33 00 -1 * 14 02 05 36 81 80 00 FF 01 34 00 00 00 35 00 -1 * 6 07 83 01 \7! 01 01 -1 * 7 03 05 01 06 00 36 00 openttd-1.5.3/media/extra_grf/rivers/rapids.png0000644000000000000000000004236312627373446020263 0ustar rootrootPNG  IHDRJ*ӜD pHYs   OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3- cHRMz%u0`:o_FPLTE 000@@@PPPdddttt4W1rp NEYvR#hZq;szEEYU96폅EU#G ܤGKX|qxVMH1()+H QLEqbaYf)xpT>#+n:xSfMzM+)a5,"\(&,$l($* .!p~QO?]XXrTe!j twtO;[Je3w7pv~k&Q$jDyݲt ;0jTvFݤ2Qf:HQ#ο/r!oMHW~ڼ}edyvF|V_oJUy0q!ׇ+&ԶS6_\֛oMY` bdz,!Km+C>,>{>sm H"udwouټUf7(>quߏS'~_5Y4bw6|öH Ʃ>8j,oy|dwqDC8Op;Kپ l,|qram;kwFQM8]b빪 Oƌ'4>7DVGƩC5;Q+V{.ITA?\#pgWhwۭ|<h-G~;+PuYE;^^@}|P Zpcs_ˋ"D[]ӥ|L@ED,Кk9ΨQփEQxq㬏-(6nv"۽QW_^!F|7Z,%ݫwGU¢,8( /` ¡q5|RB0zODUan]xU<[tT(B3A;>U4GVafm_+JOd\fm`)w%̢,-| r]|kJ J)K)K)UJYJYJYJYRRʿE)R`M -JA" JJRcB˗B),R0ʗJ)PNȂR`R+&ґ ϫJ`n" ޢ7 N]R *S)@?=vl[h%Q &6"#>5T FT -*jS**aJщ&X ^JApI)ާmJmU\@U RO(ڤKnY)JALLgZ _N{T X=JARnS -R臓)f9!Z$JAuA)>U vO+RNJ;Jфy(R3!jR>*R-/:RZR$;5~B)_U ^pyQ6å|J[X^D[S)cP ˋF)hR bJX'PSltR\V 'R_-o(TTM bW o(D++J\+oM)A)e)e)eJ)K)K)K)UJYJǕ|\)0)FO(rR?@Q R)U3W trց?Kto)MtI)ޫ( iIB)R)܄/oM+lgUZؤk"!%P +Ûlntݟ*^Y|l5M(^ )]JAX ~/nҵY4=J܄MR@/ (p|FM)%;~R''WG{֪(&R8)| hI)@L)*O{D){R=xC)vJXS _)Mi"^T +f$2 KV)h'S)f^)@;Tw*kqۈI]bbfJ#hV )oAB R`u4t/\P (=znA)@JF>p%D G!RO/(֕,$47)zV)!Jdӎq`ҳpgQ6JAe:ӎN)tR#fL3W ]J ׳`h2Q f=˴=]||])MϭsR 4%45H.BfJ}bJ :1}؄# V y-~@)04HH?L )wyBY)+JBJD*bQ v6[DRV R*~G,J҂_Q @lG|*,,,,W)e)e)e)eJ)K)RRM)8SlS+o7'*z T J_ 8ަ[eRtuJ \R T MXW #_RR7+ OHm}F)J·p`g:% ١yYsJtI ^7J~@6pV)wKcCpX)024f+tO)iOjq XFaJ6bT)lڥ:_T ɰr塷믷}JA;N5W7VNHW tT^)Zi^6(OlX9w(!fYfR?. + RܥL:)Nz-a8dk>(@)uWM+y&=kR@oS K)JO&W %n`WGvwIFVtR)ؑRɢ;hg+8}0FcJAO'@ro>!|Y)XZ^4,W_T s+ 0}U)X\^gWi l2S eeR^JN)x.,]sk]^nyqRJA\th uFJ(hC): @BZC2Q ƒZPuFJaJ,PyJi$_)P)@\gx_gˋT)l9 Y*P)(`3gRP)$[)мa¢\*宄Y()>2Q bQ uRRRR\})R0fo(lvQ>cwuLR<^lM)xFD)4U LM+RMmҽh_nMѱl[ўj:Rp h鑷7)Uq\OU GR MعR`H"[㧿z`t JMt(JܩH@*)+JIX]T X R BR@W/)ޣ$JǹR' U Q |:M+OVxTddqI)R$PFTJrR0I8ɾo%R@L]GϛJ0^XN|fa`R:\(xR|&R3NEzP}t`dfJ(&?25]O)@&<N<}E)$JATic2i*~ߤ?yJS]LU ]IWn(_J)K)K)K)UJYJYJYJYRRʿE)#7+NT |)MY*AR |w)MJT|InSmJuS %O绨'zRw,WR g*KO)a}JkqbF)йRMnO+a-8`Ie`e,SJV pR`sS ${^J N)E)%bJ'V yqe*R @oP KJHf.۔3J3g+%്83oyBMJA),tJ6nI}Ƞ.'L@ hp4(MN|n+JJ:$S `C)hJA=J|I)xI(ʁ{`QJCd :E)O&W)MGR+R;X`L*0R \㺗&pE)u4;S V&GyXQ R0,fݩ,@Tzi)mG@,~C)X. |B)h:Zw;~!LT =0,5w qo)0aZs (V:2C6JZ,E `=aJH)XIȑW)R0LhTEU ̔+R0LXC|'@Rp"jQ F-JA¨E)H(  eP ( =b4E)UJYJYJYJYRRRRrRR,JSJ$R &~P)$JU 6T Ng/G?H%a{\):Xj|.R`KJ\T h;szپu~K>Dyid| ď(oqIXedˬhYR'zI" b5濠8R08TZ)7zT׷v.pzH|nQ |J)0tE)&pRg)F ^)7R A+O)S L)F(ߤxr(hTRM[ beQ)@C)nY~R<o 8. J&zjN)>!^Q p~b2R^TtG$VDMpr`vR^_\i&N` )R`v;USٿ<ʉR9R =2P*@*ϗR 47R=MtA)0ƓŋJm"aQ:R$!$S 0R?+tR0J.#`wG; !RmBCfhnl&еw,Ra|Q)] E),#[7|<ߥ.JRW ,)gP)T E)HQG,SJ  E)RPkdRpRE)\ʡR(JR ]qg7P4jJ)J׮RRRRrRRRR/eQ FT)fsQ)w9JW\)n.pTDfmE)]ʑR@E)H=JA :'`z)R`y{U)p6^J(P *&JdaX)PQ#KuR0{B)lhR1rJAp"hY+,g:RfJRg:+̲iT,")} ,%@:ބGa~Ʃw* U)MugIߋ;JJwJrMy*io(k=R0;1y^)pGGW &K{n@)na.J=(+7N\W $ ,l;B29+ B@ I9*kmJ.Gb :pd09)PX)"(R< VER.̕ @>J̔S)0T(J)PMP)P P@JSJڟQ RJt™lXQ@)E)HIR𥫔\*,KYѯӉ 3Q iZ#`Jƒ}Q vRgdXҠfE)%R)yJ$V ꭓ85|F)pRF@N)r^)hK NT &N+EN+R[JKhRl°R0xrvuE)x:v2S Fn !x?_<pOh=\\:P@9R06+`|Tm{tea':#@XYq@_T _^4Pׯ濯\)9)EbJr`RPżR)h.M=Z^̕Y)E GfE)8_^,Ja(J)`Rp5pĺ3rU InJXelJx4o(jae,JW (i=b,JRRRRrRRRR/;RH)0(ɔZq+[J+hSJA}RT  R*fr0T-&Kcws=;nRT׹=JA͕ۡw'cRwI)J뾸v~Z RDͧ`R~i.h;JAH\W g:0z)vtaSQF)iC\S $yaJ 6K)I}nCJEV kU6RPEoaҜV Fg:. S *Ey&u,!=L'c-JSB m) ƾU &Jq;l?y҄JAh\)xƩolzJWJA4ȹU6R0AR0Yh>y4FLS)b}mG[xJ$R 4C&T >&{RГq)"sQ `1@) #}'gŎ~i)D)\>WKJJAqV),BH)6Ry^)@H)x03iyJ2:[R4Q  7 JAl=PhC 3@/+uETT hQB)Kd|bcezE)@z̔CdQ0lXT rS )zI)p)R3W 2T o *:)YXo(`uJ4SH])h 0ZRp= UԢk)%(,,,W)e)e)e)eJ)K)RS (3R gFE>WdԓM<+SJƟ7K0d/(zR'J5Y Q t`|RU "qޏ7"Y/1D8,>6RR[`(}lo#4uY`푷镂M;)]{SUA_2#S 9LVii `Y9՟?~[}5te RCP۔M vRj*0; G)ۿ|zQ 5rOc`vlR0X&S u=R0 :g;$<~2nהyU)t]U WkO>yGcaqGoI ݳwe`B)WIJQG JR ܚR b=Wu4ؾ'&݈36R}W}G;}J+8*ӆ `"鼨L))՛3',Q{:$T f Q 8{8r ?KK e@YR.JrG;JZה(L=:lE?R+t@ N(έ&?.)ouJ_DzB(J؟P |vJR LpY(K A rQ qD)B)XZ^ 6;KrT @NJA4! N nغ%lJlJ)򣄜RjI"R0qb\fu lGe_Q &=N)0!ܔ1ܤ(Fߤ'0s[R}bR@$-ߠ l'xT)඙.;91yZ)xZg-{e% \S нnR V&pbQ l*`Lו_4kS dG@Y[inxSJ6&)f3MjR F]lФT ɘ\2\@:^Ìӄh.(LA]fu]GCL)UR0L“_ϺclJW )AOw^)i~`#аkJMf>!ZQR0R#N)JAKzQ0V 1hR@9RPSfJtJȭ(H^ehU mHȑfH6J(;K]B\NR)h0[`(klc|Rg(gP3Q'JrB)Q 3U (WKxHJmB*JRR y+P$Rū\*,KYܦhR(W@6]^);ME)8_W ߩ/(sJ(^tJݧHnJ*࿣TJ]+eyW R ʐH)rR`JS RR$Hw^)0!<#qwR``~ FֈJAR؍DN(nwR``80ޡ4tK}@)2NJJA;%Q (RU ڮ`t%aJ`|RbX͕zRo#%`Rд锂ٙN<J`C);HD)kJA0J %r0Ʃn0gd ( `*2R XÓI; l'<&c+`pў'h9rdrdp7N]Y}k(<WGFFO+E-[;KhI`Q\.R+fZRM&wc*dz.F(|J)xޥ )H(+ M)v#zL)0n>S</fJ΄W mv"eJ+a0X씂WGea1 ˟_U ڄbVz.e )G`b4y`d@>JAݦR9+}KKJA+(MBCmD)@RR |&JW)xE)8uI)hrE)8!,E)8~F)Q $G)0*GNEey* + A_P gSr5*,,,,W)e)^ʢ|T) 2U wa5jԯo<&R1&II)h>&X)]T Gl/M-p2T _T cJeh@M甂T t/I+ uB D)sD N)Ӈ &S  IZP ЧT kW fۈ|?JR`yR@]>H|i9qJ!&&q7(&CJAhZP &#כ*(N)ЫJAv`iJA\)F?~TޤiB{^)ubѣR(pY)JU JPɕ v+!R@R 8RaJ+O)0lfJm:FACToIe< JAHUQGt4pmk{b +ON<)g:(n0,!bSJ-=9;R`BN,t4@5"QIV6giŠ |/(]B`O*3R`&&!{I@wJAш"IN(3R`]M&=.(tA)JAuIRPںMz.~I)]e@).:0J|y,#Y(POeZN>Xu@3'`1l6D)@R+@H)'K) J:NR>2گ1HDnA)0j6J,hB)0/)÷:`9*<ä}Q RDny(Wံ( 0E)H_)\(Jި*ϢO |6_Q xRRRR\})RIÉ|F)J7*mp5MJALJAMR)h%S N٦;8uE)0Wn6+&I)X>xrA)J0iJL)X}T9`pXRQhRxz)ull=kS X`B)`R0N)X{J)>RRIVV?L_R(rRОH:9Lf_J+w*`&3JAH7^V /S* `&JmmM{J),P)#JʙN*bȾ6!R =P,)fRS*ϑR79&R .>RvR`\IJ*pRPOLk<u4ЌSRݤHut&5-(J3*^V *ʙԷ'Ky`x +GT5; #`( +tJAkF{ͧJ)e%W/%LTPGe;`Rݤ4~.UJ JA7Yu /*88sw)`RQtEd Qa`:lQG0օaqI:1R,@yJ)x)m*f  "Q J,$iBzs}wiG,YB-Кz@R> ´G))OTOw>7`G)@,Y)g6JA0[@9Ң {rR '@)PVQZ63R &T+|nP (R)?Ti*1"?9Lf"RJ@6RWno#>s>ؿF)&!0^S ډɅM)Ro#tJAslRtN7P Rӯˈ~Τ!9L6MxE)g:G`)R0 8R0V_Q ;:l7&Q \)J7F\j K &H9*z\)4FJmO|EoC e.*ߎSVF)Tbd:Rv_U V;I=De{\)@iX8yB)(V)XM@)'+9jT gR)X)&#<)dCwA7P:@\P b53Ga@K}C)P ճLQRPY^H) YJZGW).$4sF6`-aVJR)&4)`~A)h$!|_)tueO(}*B^J?t !3S ,3JARהR(JAeB)\)*PQ^[$QR,jQ ʵ֔RRR\I52.aIENDB`openttd-1.5.3/media/extra_grf/signals.png0000644000000000000000000005630312627373446017126 0ustar rootrootPNG  IHDR i\sRGBPLTE 000@@@PPPdddttt4]@DjYFH"jz./=>R/E+ i]Pj.RtR#_]_a 8'EQlP?-^@_Uk$u r)% )D]_v5A蓯A UT *Uܐ dI3l`Rq?`я~':x!ȝO;x}~ z0o<7؏ח܉233fgn3`v` o@lg wH/-b3lvJ:ng%Lr$a7?~5/-0ay"D (.{EtWa㺆/aP-Mm&5Ho`"YHƧ,7_ ,X7H) 1]'ۄF`˷!;w 6F6gۜmi߂ S뽄ޯoĊ~uM%:7-@L9 o,\mĊ~u; o _jR TRJ .U]]jGmZ;miX5͞>.z2EoOK V.n^Ef:[1s:45'?R-x›'ic]A7orl?ooz>vS*OE,5]J֤k]_-Ҧw f|m( zD9cAM!t}DwH 5 `>^'_hqJ* U  @,C:;\8c"+Glr#قAyi>|^#Z-cn!3{E E?X8Q9^s #C;?O5.x0% ` D{:~޹|K px ZvcNG -:; s@?`>9/G"1 k5!vn&C A.1Lӈl hH"gnb)t0s"Ztn3{׃9\9K?۟l1$x }X28+ B! pXt]D"9/s\M=W$p2~fO Ce YABvr`_k{NsqpƱ~ޟ}xt !<($Dya_rP-;HjyLۧg<[ دO-Z6~fτ ̜`yL4_4۟lE y#fޑ DDu$fN&H< /2b5[$w9FfT FN#`bAXE5s ̜`9p, 4Ǯ%:JXŽWyX $++> "8ļ\b]0B axnUd%Rbek$HZC5e%ID, @ #H U&HVrA^3Fu`-A^5d%׻ s-AM 3QF!! Ȍ?v!!d!F ! 2sAdFeЂdyE2!%Wd/K%IXr!v<DD$H {*A*Aޞ ñQoE?-{QA*Aȸ1N&H>-8#dܷf kMmqb{3[9h/!"|e@^!H_DBS R\L|7kOZcڹC)]{jp%,nUsg!"ćqVew5N.ۣ^z <%A/?^1q(Z{څ)]Fၑa(_T4*HWK'k3AF"  QnjoU:)K"K B [g)CZTSĨwSQ;5kO41$6i٤%]/)G]_TƷx RJJ*U$HAb1Á7$~9~?hε>q]6A?b j7~}r#&cODl2b?;y85wxGD{M2L<(;CC.L/sx/a~gC/?aEQFsލ5Gv#Gʰws?<, k ? sg)~7?S@?'H 9$BX0BJA {' lI ;bg&G~N8;>LyS`>;#&b; b"wFĴ"612x0w<+s7HRq Ν)2b8qFN@>bD=&;wX߭[~dj r0wF:Yd%RBE5vF"k?aJ8\!JwOKgw;XD}w$Og :Z| rU64jygi`Z4J1f'a5w ߖEuC9 BR, qOc$2P"mĚ=qiQN!p9xuq%HFGǣ}'a"5aa>5^Kvt|sï&țí7Gǣ?$2^Aso45\9f >qbړmgN 9L W]s/ )Fc: 8xߵ}I4>u)U78K9f]KYl35&^ uh H17&ȡkHātc컶OM8KA KӍ g>cTcM(_,ü?)Csc^&.ʕ #ķAX77&4y Ӯ 8gÚo/㱁SyIj\b B :۩qŗ -XKĚ3_b 㢽^vOM+vSw/ceCO1 ?5魗CN-8K žEpEZxBLz?5=1|)C /Vnc^څm1p},Dۼk,zOq']&O֋m`E[B$ 05^KAK'WSW^r>;ۧG h2pIZ\dy_T`aIpEA \hS %׿G$ A] > QU}*ATTYF*UTTR RJ%H* UTTR RJ%H* UTTR RJJ*U*ATRJ@Y1/Sl'RiK0˭r;N[%b?RG}W]aiXi~8m/d5iRhWƷ:> v~._?)#eدp?SdAHJY_@QZJ\DH"BXdH2k?G+fRnW)^Ѳv~(*(,YSVB,K(>r?]c;)?jǯ/*/j짎/*J OjUUJ(uƱcDLx1fF[~oE;˹cM#h[)(#|%;?^_~;±1~o|4߀A@d3?833''3xa̱فv~g`|!y52Ak⟞烍/폏Sx1)g;米w3jЏ,f3Yn Al~||Fg%WĿ>z ! Sx'~82 b$Ês'ᇀ%F)>@ĈƒTr?(3+)ϟBvrsRv;as8_ygz kЃ3?0Y$ A*9fJL#F)1Ae8wȈ-1B BȾ ͔X` R57⿽Ŀ>*_xL_y>QG4WO B'%H0^O'е@O W韻~Cj+4]}+ƿ&D%DbTڵT=~ZpWvR_:^A#k/'%=h+G\@W(LH0c;)Y e B+kzRAu%ėkvZҾKۇ_ŪRe.V*U+BGK;vgهbqA( d!z !H ,."~"ޭ!: c]M=W$p2~fO2`A0`dx%A HC)HCڑ 4csi #T4@eC$+;S柍3qfN0<&$Hg`0=,OΧlh`5La"ה ne Ν\"eUHE}-Z'7O-:3}K A.G{=,OΧl>lJ)Lfye3"8k$Z?DKE3c36]" ޗ\Jؘ̧Xb,9\sAJ"}"Xb1fR&=%wVbYN3.K,K\!c9/AK Z8Q왖9\s٤~aưA+,'xa>+BdO AG/%ȇfĜ 2Hj~=_F E,'HOz "pޮ_i ~ .o\͋Iwx4d@oN? .o\͛Z|$ "+A6 JBtc/ 1칁 Y n;cnBA}k r}ލ R2Aa%9eڿA}kftIM8AL{ofqۙ1|d>1OWRsq_KL&9 x3 'kSmDm @1Ϭ04oSמRu~_!+08,AÄ~%`A HOsS` 6 |f 0AIеTۄ,DЌ  a$@uc$ '9M黶OMx-A.H~>}`耾-:(K/J,N$̐QJrN+ķAƛ0+s8K^Lfa:47&4y Atc[ 2w%oW$H^ca @@VZۏGN,ڮ*0-A&go=/Fg%5Ȁ}% yɵĚ3_b aǾN%ֈ/- "XIz!jTb%!L"-%o6E-Etl|:8/8_fךi>7N4I/DAheUb;c$>\D9#̕K^[Kۼy"g>~}>AkAV Ò rs8 r(dQa> s ߉ ɄdoE3IZ /LFd}EΫx5̯۞W߿|XryM \1UVDsM<JJ*/ATR RJ%H* UTTR RJ%H* UTTR RJ%H*U*ATRJJ*U> D Dz"9^oQ;]I?n/_/Neɣ\TnEH Y?LE'͗δdQ=jǧR9"DQ8S}ֲ2̾<>]_ 1va|~RG WcGFJUJWSV@OoQ)| ȩĺD o⸇ \+Kqkhz@lJF.NXy(qE~.V}6k"~&j"46lP ,қtm|-_P뙻]"m^5\} \+yyk uɾKSK2*iJn' [D}k?4"GZe tARSPQ@J\_)2>RƷHi|gW_"ؾMZRzJD/_/a1JJ)5iW)^?*W)^?2ڌ/R$+nQHS;)?jEe| kzZ@Y3&iyix5b]*U*ATAȘ\i Yw̯;x]v*p=KAA fG]?M@x#M.z1eDh9So^h^?'܂D܂wO1˝7ƿÿw_^AxN/ ;(ܙ;n ⧮O3q{up=c`Aڠd@فi|B40ً gup? 2Ad)Fzy6 ; ?s옃><3 rgCxKDq s]o'ȐA.sA @1B2eCP?d/*3d?՟[-edހ:g'3Y \?IK?̊ "rx SI)~NuzGX: 6X0_@i뺮vv;u {B@|(Zkz?'nAjBn0 eQ]xJ.Q0c~KE O!$k?8@@ԥg|QQgud+ %^ q9gu uT2bE&*lgQQjA=8 \HG A#@?$hD(zkBc%" %";d!@v>;6&cAz֖K,~4Eh"k-9hABp=l"%iD܂j0܂y%K !f-Qڄ Α!D_Xb]A& y-@)Xkycu],ֺ=Dh! 6͟R{%U& H-ha\܂3 H̀]EzwN T b(\i8!^mwx 뭵3&J3?Ϯ}>dq^mu`Sp5'Hi2"B e׳ N^Y+b -H-H"J]]&-8\Xy"%k X48,bF@`%4Am.A.W.Rl?BA.Vj@"nA2dDeAxcwV– }'  [ۼ?ǰӮ%+59@ !1Z(B?fkq!Hq /"P r is j?+ q b@b|;& c-ص 9AH DbA{)ʋr X aE :!],s $gsA mp AgJV&Hj@u7pP|sӃ bWE$u ®}$b gZAf!b | VK2V3XZɥeb$sjym=|d|Cɜ@?by|wƀo/Dzw) Xdw'Hq c],>ALJ@~-Y.U #$5 HvSo$LMe7M1VƗ}K b]ĒA],K.X!AX2ݖAJ{suI,H.1܂8qc1F"Hj@q905ef@WƗe5HRO3|+]G}bsޙ$L~)/ 2&"o/s”u0}#g}et߂u@Aڕ75Gd+Y X-bĸ%L&!HB b5&;1p R%kVr AۖXP!kn b2Xzk ],^9w2e I & KAO\+ nmEzEIO $ED*bAn9ȿ.kw07B),5zĞW1r.h??\3FԿ΂.?OoAP O:W9h.$b3[9,W$5`%Ȳ8Dw3B{,~ɫfw$R)@&P}a{ݐ _M=|Q{} R RJ%H* UTTR RJ%H* UTTRJJ*U*ATRJJ*U*AT BD1 ?翓=Ao0㝽2tۅ]/)H;\OۯO'GGTnivӐ~]_;ޙEBMS#4Ql_>uFOfxg[p1Qax^b|k;wvIi_d_R"cF%o_?)h_!C[L Z?FؔAů1XqV)e+$AQ2+kL!Z( bE5ȵD} !6Q RT"l/O+˖Yo^U]rF.ݳCݶc"xo$~"'bҧ=:_}1S~.;8Zm@{;:t}oYdp±1KQOYdaa 6;g%l'bg&G~FsZ׺nȵ)1QOYdw1;#by J2&&<` d=&$B>6BZV[l"I֓\B~O}G]` 5 ukO|nu],&G0NUh}( #kKׇR}mxJK yI:P~2`-zO}'%3ǻ XFy` 55H ]Z Yo4ݟF! >]|ZP,^-8̥Eb1 X [˷]Z 7$LN¶2M+xR< J!]K#%+ZxC̜QgWp)1>C\ ۆ1xx'Hq /Ƈmr_9]/4`E %CVRhVw?q^_T(QO9p R8p &Ga}N}N7 H7Gc MceQ"$_]]{?=껔bwhxǒ 0dA}N=}z>}}+q[A&^?L{f7=ň"$*AuqZ 2*T}43X 3 p?Sof7Ebs8\A 2 x>I}?gכSڧӃ}2`Ha}pφ]j]JɁ .5o ug"GH6CK,T Xb sR}S-Ժ}z\*Av,'bjN[罹qw.VZM%H1n fz7>YBJ.e^"89Hꯩ 2eG}C}zωe nR%I/;4bjiE]m̬$x sp=ld%\8\6f Oy4G)w>X S`^O>I/rsz?Y/bW],^/E5\z\F">"~1W$HFsR.pUp>'O/ا_kA$O/W|z~3[GzЗ[%|b%]"]I}q}j Af 9Oa>_ %{XaKkT^^wi0~,)6b#X>IOPSRɮ}CU K\KBCrB}99}bdnc81b+#$|#d'.6!bJO%ȶ!>A}]TR RJ%H* UTRJJ*U*ATRJJ*U*ATRJ* U'?tyCNS;N[څ]v"GUNӖvi|Q_Te$EI)I8]4%MSJRwj'eFŀI}~a|OH"$_Q&NJIa,EV,;iS;k `yU-! M>W'J{YbJbmj 5nTjENGjMkq|UbEH)TRnVr%A8o?86w"6ƈ1z?1G1ҋ~Q᎝±1 wW>Aro:c#oenfF)Fz; 'wg0 0~f3`o~S@Mo:4:p|FQ$ Sd\7?~p|__jgX8XoV$X vy1[$Lr$a8A#d ?>/ǚoo wjuA[\?IXΈ?ňnǣ}'a"-t~׮ n9F](a/ Ncl`M |7͟"#H$|<~Iw4M:DM)_82xoyJGm1.=qkBL#wjey'c}`lyKh@#F' [SӤ#>=9~zp`'kO[9F4{oͿ ~IxA ab})X)4;4kPkněl`M?5e|l*AX5XƐF=l:AZ H i Mǯ` -@V&H0ݽETɘڮiEhsp^b)%K)n^by9^z/Sӊ{kht۰ @ ,X7HoV.ҵ)W6Ez鍲HwmI1y$~^8[ϿmGk3(uͩgЍ۴W[r zky WU 'ȭ33_UATT"j*U*ATR-=y1NӖk(]&c,њ\WBQ9!*G,-Ʒvy| ?殧t#%~B|Rg |RgX Ʒvkj>#| R ^?{J{?)ϟ4{3-;?$NJx~xTηX7\0`҂:(Mt*{,k]/;C^n1yEe|WAV]&[YYQxΏnaGXUhѧJ*BYb4o"SGDax!uo?cVY_ H WX]?MX=4ףO=L󧂾{~ԟ'0EDB-瞟4E+u0 [ןк9ǧ? ]~iBieNzi׏G ;d/*?B6( 8 EK9 A֝0><=pKs2ȥ}1pn3HXAB28FB?qhE}rGϱy 3ȼ :LG[_ JO &Ƈ0,\Mv\ǮG}DX b .i AfwЁ'{Qj/ HAOG-H: 6X0 ڏ$Ѥ?5Bܿh1!A֝BRaFSuc7uu ~NDL_xbS2`I/Sf uT2bE&*lgQQjA58 \ ڏ$ͷп(/Z_f2Ⱥ6 YF9Wc%" %8gAzm`UMtz9d-XxipDZ\ABp=Fqڋ(Is bF HM[_-/0O?xklRfvkiDDk8G]ׇВ66eTHwR2A¥3)G"PM 6ًR{eK$M0 AAD0IK}Q_ȿu ’ Pa+ tocX `(Wֿ&q A/K1 Ihi ?Y_3` 2L6Fԉi-H|˲ B(P2ȱ], C)g D!7*\$ℷG A=b)$eh܍d(Q_T/t3|tZs>GvU(mXx=kA|0%W?ƒBX],` b|WjQG܂D>+wR H`@Xs6~.OM@8eXvlmAf v2J}!9A’Z .~Y_Z-be~VF4~nA"p :p%f99C r80FL% b~`azs}$k]ߴ%l.C"/A H0%f*KkAO~'f?9%֘`yDO2@%AQ& Sr!Ș "n 0{?p}+ٔHNrdtK A @"-/"wD|s$>Fn?MA -X:Q*ly6NL@Tߘ Jugf2A^3%\aiF$e׈ c 43̬k*b%Bȑ PRaR 8`KwxzJ C3ޚQ_9l~Q.C"_HwĈ jXVڲQ8fa7̯9潔\IEB,N%] ͛DJ.ŀS ۏXhlQDTBCFI3_NK<"\D W-Xkc K>OA.> U|aUTR RJ%H* UTTR RJ%H* UTTR RJJ*U*ATRJ$b,}'>i:>ۉv, 7ڳm B4=N\'>IiRr?_z`2ׯl1!%BK/|iThwj"[AH͘kѴvuA,^|z?MnGAV̋k2} rqWGZ׮dRbUR Rg Q `ygc۶pݬppw7R O'@Dۿ5Or/qǷ{(' Cw\` $,!0"s@l9ץچKfp2Tp`OA v;u M)gTyoda!9ŸZ+ bI2.Dv p}ې.;,S J᭳]kn M;U!.4["4vsdN%k1O\,Y٧ʇgqpڲ ϟ;ޖGj d=O ԹyouSBdLjhUXTyg EK:rv?U@e[j {'XE4$ %eslvLs5vqB[P~()A&gYs5HP"NʉF %gO %ThfMSw XR `p@p{ޗ`' y5AN=_?Aec]^O_eq}7A8@ĒB%2`Qx;E[^oDF} %8\A m I}?d`󶟽ޜzѓEtcgK#X!A+ Xrڱj]JɁ .7B94{}o&<0`,T Xb O.kӲ#dVr)AEhRM%H1bz7kVr>Yɥ,KSAZXM8\6f $}(p7+ b~Qc6OJ*^bAɅڧ@>d{ dK\  Q-!bz\fd^O>%H)_Ug #$\oKt1B&Em^]4gzЗ[͋%>ERTy] \%1%`9T],9f׃b]кF\MA]S F|@+#!! }K1ck"^= _ [2Z RJJ*U*ATRJJ*U*ATRJJ*UTTR RJ%H* U|?=#8IENDB`openttd-1.5.3/media/extra_grf/autorail.nfo0000644000000000000000000001017012627373446017274 0ustar rootroot// // $Id: autorail.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Autorail graphics" -1 * 3 05 13 37 -1 sprites/autorail.png 8bpp 18 8 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 98 8 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 178 8 64 39 -31 -1 normal -1 sprites/autorail.png 8bpp 258 8 64 47 -31 -9 normal -1 sprites/autorail.png 8bpp 338 8 64 31 -31 -5 normal -1 sprites/autorail.png 8bpp 418 8 64 23 -31 7 normal -1 sprites/autorail.png 8bpp 498 8 64 18 -31 4 normal -1 sprites/autorail.png 8bpp 578 8 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 658 8 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 2 72 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 82 72 64 23 -31 7 normal -1 sprites/autorail.png 8bpp 162 72 64 18 -31 4 normal -1 sprites/autorail.png 8bpp 242 72 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 322 72 64 39 -31 -1 normal -1 sprites/autorail.png 8bpp 402 72 64 47 -31 -9 normal -1 sprites/autorail.png 8bpp 482 72 64 31 -31 -5 normal -1 sprites/autorail.png 8bpp 562 72 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 642 72 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 722 72 64 47 -31 -9 normal -1 sprites/autorail.png 8bpp 2 136 64 26 -31 4 normal -1 sprites/autorail.png 8bpp 82 136 64 23 -31 4 normal -1 sprites/autorail.png 8bpp 162 136 64 31 -31 -3 normal -1 sprites/autorail.png 8bpp 242 136 64 26 -31 4 normal -1 sprites/autorail.png 8bpp 322 136 64 23 -31 4 normal -1 sprites/autorail.png 8bpp 402 136 64 31 -31 -3 normal -1 sprites/autorail.png 8bpp 482 136 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 562 136 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 642 136 64 15 -31 7 normal -1 sprites/autorail.png 8bpp 722 136 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 2 184 64 39 -31 -1 normal -1 sprites/autorail.png 8bpp 82 184 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 162 184 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 242 184 64 39 -31 -1 normal -1 sprites/autorail.png 8bpp 322 184 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 402 184 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 482 184 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 562 184 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 642 184 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 722 184 64 23 -31 7 normal -1 sprites/autorail.png 8bpp 2 248 64 15 -31 7 normal -1 sprites/autorail.png 8bpp 82 248 64 39 -31 -1 normal -1 sprites/autorail.png 8bpp 162 248 64 47 -31 -9 normal -1 sprites/autorail.png 8bpp 242 248 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 322 248 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 402 248 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 482 248 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 562 248 64 23 -31 7 normal -1 sprites/autorail.png 8bpp 642 248 64 15 -31 7 normal -1 sprites/autorail.png 8bpp 722 248 64 39 -31 -1 normal -1 sprites/autorail.png 8bpp 2 312 64 47 -31 -9 normal -1 sprites/autorail.png 8bpp 82 312 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 162 312 64 31 -31 -1 normal -1 sprites/autorail.png 8bpp 242 312 64 23 -31 7 normal -1 sprites/autorail.png 8bpp 322 312 64 31 -31 7 normal -1 sprites/autorail.png 8bpp 402 312 64 31 -31 7 normal openttd-1.5.3/media/extra_grf/canals.png0000644000000000000000000001413412627373446016723 0ustar rootrootPNG  IHDRJU[sRGBPLTE 000@@@PPPdddttt4QYo%T#J±u~&վ3ЗM t(V펤Ad1;}P7xu*Cf. T N!S 'E\VF \6v'YN 6XY͞o?ެ2vdbw$Jc Ƭ f) ^zwI<`26.2fQh8X , p4TJ0! *d7wz\6Wf5o??MϷMjߨ K}jnIʘiޗ`.LMb!y8$7 @lW4MP!JfB]]u=֧߬ =|΁ahM vV0㥮K5VD^\ q:Op#HF=4dL:ZYbzJo4&o,SyLOuLj6Znז17qp]?&˾c:Q2&eeڂ3Uۂz&qxٗeҵ>0 >~: exv7>Wm.6ʑٷ ^gWf_oGI^9Wtȋex7jm85'n& {~ÞٻɱZ7Ma+ܸ&>?DZJyVx]>93\qG2s6fy&aceaS܊(a$ 6&(ǫeCzЧh-_Gn26Q4=4lLjMq+=;Ȇj|5bix(nͣew>`b6acX[o[qh\iV!' VrOgX±P'm)H[J-iKDRڢ 㫭-q|x/wx4{|[,ϟ=q|9>QY۠k-nn/^[TVzmY|W2ku}mWEW,V]_KRl([+M>Zx9>UR,Z, Ϩl4@[Swx4? J(r|Gi Pi!T/XEaQ6W:<㓑/䇠4z9>#P61'j|^1?++݊ѵr|Gguu}Y,[K^Q[{,exF[[Udt|v0bwG s^ JL]p|ޣq ?}JX=TחslsVQǷXD笔2'R;O)VQ'gq8>noj`$?\8{nlV9(qD'_zjoTps|2T>o5:ǧ+YIҘG1kycW-'MR-WLJkr|Wm8*m1GR\]y7Oy?ǷX$3PEGq|G ؤs| Z 2'[9#s|ȘHu]qNYp|x8>m|bEvA)?覙>>Gas|uK_Tq|ʘ<SL߇T}|Ɍ>~_m}{hؘ@kaqWפk/.^6~ذ89\]2& 'H"܊3q3dұщǯW6Wghr|\CƤso[qBY%&(ߜ\~:Wc?ܷIcV{p8>IoKǫar|rBeir||mCƤ3Vڃk9Lzq}#DZw

N6&LMv1ϼs X/1N6<&\[9>[@[p|,q|^B[9lYyMz+m|BgX±P#m)H[J-iKDRڢ 㫭-q|xǷ&!E=٘2#!aFewѸ=K_'_3+ǷWXo%OO~.q|]p|uo`x~Jp|{WaoTޏ?xK{Va3so_w<#/6DO"*XM9l\q> !W2@ݽ?^%^i_):ʳq'O1g1FP7War| m cҘ++j*_iےˍI f$7p|l`Ar|&6&x9v7&o8>lLZ^ ϼ1鍵U>i[3Ik=}lyMz mxn!5魴>ΰ>cDR"m)-%ҖiKi.#Eߚ8E=CqKr|'4 wuyu)_ݻu34z$^qw.q|q|m{.// ;1v[9Wgc8n9M({x}j/s5xgcywc9z`r|Wot{ *;Leg'ݞ9>d҅{ }fmjhdžBso(3LL]` ^8>ۚgXHLbLy G^lx0ȁ;瓹+tT_v֫+ ϵhw*+ƕgϱ㳘t|kW=$ 'Ic@8>IoKǫ!r|l8abA3#sfx='39+<ނӤ7?SLJIK믧3oyLzcmx\!Ǟ>6&U=>O}k.q|p|UsrߛrYXo_K__em]ĚdӦMϷ߀R-ߛz,;Ϸ=p|oKyW/ؽg5_L ~_]>bC&]xO]0MuL?|3zPqQDO0~ 5жgXW0~b72dȋ N9l\q>{^8IG YyagJ>~d>p|ٸ97q|n/YWa~_ms|fjstYMzX>^ߛߘӓ`cf$7p|l`As|As|ژ94 E>~lacҒBx8>IoVm_ou.^gq|c3k[h+=е5b_z"M֨-жl"#W/MW81eѸy^9T^Kf984,7^%Os[>8۳߂>e.R+"cWm Rr^9>z[}|l[x{Leg@s|X9Ǘ^ W}|5;.(8g^9>ä>%8 >~;{..NOjau_LSƲxņ}|uH&d/_ɤ^I8|Z{r| 7Ҵ1LJMwŤcZ >^]?`~p[O\7]q|V(WXj3#sfx=']cϧl H.8>Io-[f#'r|X[9>Ә^oyMz mxxǗR_H[J-%ҖDR"m)}uݨq(IENDB`openttd-1.5.3/media/extra_grf/mono.nfo0000644000000000000000000003410312627373446016426 0ustar rootroot// // $Id: mono.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Monospaced characters (Liberation Mono)" -1 * 0 12 01 03 60 20 00 -1 sprites/mono.png 8bpp 10 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 30 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 50 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 70 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 70 7 13 0 0 normal -1 * 0 12 01 03 80 80 00 -1 sprites/mono.png 8bpp 10 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 90 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 110 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 130 7 13 0 0 normal -1 sprites/mono.png 8bpp 10 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 25 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 40 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 55 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 70 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 85 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 100 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 115 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 130 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 145 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 160 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 175 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 190 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 205 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 220 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 235 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 250 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 265 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 280 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 295 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 310 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 325 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 340 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 355 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 370 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 385 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 400 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 415 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 430 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 445 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 460 150 7 13 0 0 normal -1 sprites/mono.png 8bpp 475 150 7 13 0 0 normal //U+0178 Latin Capital Letter Y With Diaeresis (only needed for mono as it is in the base set, but relocated by some code) -1 * 0 12 01 03 01 78 01 -1 sprites/mono.png 8bpp 370 230 7 13 0 0 normal openttd-1.5.3/media/extra_grf/openttdgui.png0000644000000000000000000006353412627373446017654 0ustar rootrootPNG  IHDR njPLTE 000@@@PPPdddttt4^__ ʼ :PSgƍϷp]q} H*|멾#0t/cW@r\J7;jGBi81yL Tԗ)  Wf[4Hhka13Xae+K@rDη틣#2h,I}hdM>lsH^5 jnvվrDOf+U'5DsH82TVu?VߥdDRS9gU("Wf[He<#dnO R_H";f[Her?uSO ru9jϣV#R'aGX똫k1 U sivՈT.1UPn֜VH|o5"F#'wLN ,G @>fO^c-&%Xf ѴyϒvHO&+Z^HXY}Y=q=ms ]>,Af̳MܤINɬ]1R1Ś,QOX; h;&s2]}Cdz^O=鳸;{4o_T&t^;[.}!!@c}]3't`nVշS)$Hۧ ?kϝ"}>ynu1i;8T@Z>WɊ?'+9 ɀu(yH'S ?:gl޾ə' CTc.!bM2<=}oHbJeRO#%f<)MO ɓ F@nVg@<LݪOc7y:Ibi4SH{e1<݀t @1b1bbĈĈ##F F@11b1bbĈ##F F@11b1bbȓ iZgJh ~{^NG#}mpkoHbkKfR_X;x҄XMGIËS=|]mZ)ZG-Z:J zU7HUe|ϷbאX,8fOدo#=Fp'1-}*`\~[Eb'|ION '' c{,pUL11XF0xFQƤo$I$Y+\|)[߷o?7kOo_T ۢ Z,oҾtuE9tsUէ- =D@}m^QYJ Q{E@.ηR/¶(_۷oWMWUB/^+Kקbi I_~/RB-ȥB>7 tѳ E.K]?\@ k -S]W g H \孂B>7i_U}۪,F.V@.mGɿMߘIR@>z ,ȥd_ق,6 GŚ@:kν6@{}\DJIZUUx/XR eϺ +f3@8a0?)_jWzB~gHE`W\ z]\(ЧXPg,oҾ,|]]Ŷn %BWvn Y\g/xTҷC¶J^_QIwiQ",WNs]{gìo,H\RYX(,} RjrJ_UڙTS$yAYP|oaٿjZ{%qt,ԧu^ysJzmby 4Zop(![PXݼVeWҍ*yk ^_HVV sP #[\X%M3]'[;U=,/%sr[+뫱]f]w Zr-OnWTrRW@H&]e)9 2fhGqKMc @߂ EJ7lvY&,V}W> ȖW[OET,.o*fDxXQ) ƂԘeȽ;Z6|dH S8S~9 / o@AJxyꭝj^S-@_A)ly|Հ4[>,QXO!RTR}ƀ_%Rgm>Yl H7op|  X_,0~U0sD'=rH4pR<_WیF mkVL7 Rx0Q=o@o@>biA, X#G bb1b11@@ F #Ĉ# ##F F@11b1bb##F F@11b1bbĈĈ#F F@qSj;SoZ? $Ֆ.ƻ ,'VOꫮ7~5'mݞxgҕ2k]uݟhmF*lsUU_ᆴ,oU_N7lo) Z! /^~Uרh-ւTYF# 8"j~SQ {/now TwX@0췭?MH'_CwuԪ3:TwB ]\zo #!<Ĉ##FB)sIQ<Ķm$4}RxsA{ͳmFoqk(#>;|)h40 ?QV/ @ˆ(lQ_^ѳm Spklxlgsscc2؉BZ"sB~4V?'?,BeД;<~yi"v G񘃻8sBd|@Yw|dyܽ5bYm^@p{g]]c @8V BS>NkfyB [< 4Hހ f\?ə,l[xhFTZ@${iX>7K{kYDb)Muuu|p>V%*>yL-\x,H*Oˀ>g[ p?pA20x}|yE80w{8=wfܵ#")"qݨ{q{p>ԀY/gy 9 RE-H9ɻd»B<ױį9fU_G)G{O޳k[ CPȑ|MYC>>ϝ$&$uqm2^)XRПyxgԶ]q?L"6ѷ WU (.VA|31ƺױm%";E H1 BWWT߯?bM??\@ẙѦj \gf7m5T!@#H;@ӧ+Ee BY%dngɩ^ʺ$"q  R<:8K9@ LyO Џ| 8#Wf\KbK ~s|njײ!s4\SƦ9GE=83Dfq\Q۱f@%QHBNUą)@zhh[/D;BBbD_`0X DPo4kZ:^BRظ9]5`3W ɱ QѩF$01uN[ye@.a~ڛ6'޺a-۵/]zţ SMx'QkܠnmW:EfޤcҭǮ?/޼.@  Rj]YV1@Y W_5]< @͙+ą/&&_|8^25 B8tvO>D#!8 hÔ G ?HrJ@Kָ2<|Iօ5&v ozˊi޺L()\~зi] H%R!^JJ 011ĺ91@䒉A< S88ԚZ9׷N Dd Ǥ _4.W*0WS "}< 8dOދ7?@hNP23@K.i7t5I@AJHz%2d .sWu s_"H/X*-9siiLK̴~~n^\y^^_3[,w7@@P #)zS8~^!ރINKÇtZp{vH_pUMbĦz¥9n.VuɄTdbv7,Oy#Je +{8zs9ܻbxB! A(&/NKiס12[M3 ==d.?sg \+BʧYnZM{}{ O Ŭ9:㧷N\h$˹w9^s|n^7h^ȓH9klvilB "ty,7-ݦ.k^ȓ{N)kn(ޥV~ E(/mڷ>_\slhaV+ 2ܻ頳X˘)(C{ O #AkNǩS5Z-cڶw(vYo$s_UvQB@*u5D߿1 22`a/$[BTWGA@?qܙqM6aъMp}w=hJ<í06x{qA@=[h H A0$*as@PHM  I=@ F1(l4 7gQAΖdؐhXTAjgCsO/z&g@WVX 'd}# `A m瀑甀pDj+R9!~N # U ~>3|U+HM9+"AűqD|5e}-# j? * "z@2Opva4q9 +¹B+d3#Ѥ 1Y+"WzaG"~ay;oGkd2rmǀEަO.zYj@͇ʊTSB>0Ov8H\ F3cD^$>Hȗ.X_BX@u>ϮiA9 <yp2a7&ܖOWXC+!"z@B-ҟZ5IH,~>~nxׯ_B1"WJ Ҡx}\(xrLDw BOB}e?'lLЂhAD|׆̊TN5bYbv=0 qM$}GPTCp~g={Uw6u``yXm"T?W?#׾uT8/t|pr=ahAD7&HɊm@s-7c+kD$ДN hr(/reI౸tdAAD_ &?(ӥ9ů؃O9gA{ y>H>AL֋4 kd-b?ƽ̲Fc9~D?0ﱾc^$SDu$^g\)֟U ^ť؊г BLK:Rh8;7 <1;(D?;Z\e :C#z kӜ2rY4 J@"⌖x#׳K}@8,ADk- JGĉ+1b8ST `?~%4hڏg|s.gZ_f ss<ۋDIby,~H;=K*/oL 9w5 E>d?)8(v IDATgrሬ3Z_8mVd`(I vZDST:,9gy'..Y\"o~Y|- 0軶 D<| /r'YDoDDn++75y kbFgnA (YK"2Zee]Xo6:>=[H]AdG| Vd6"--WȖtċ+N"bSjs<B@$b e~p[t9Ηµ?'ɹ+-# ^ *;w& bFKX2 вa̲st$:(<_Ŀ+U.åKœ9.`Du(""6ʻX><:@[y}*Ϩ2EaLF7~sPĈxʄ6 q^hd8? HgL?tGdǀ%>ߕsiY"kK'=aEIrwNx\NqVqqy߆ ů,Q'Q,.ľ*_# :h& DgAߟeVD h-`IJ]ۺ8ҥ.^0^,@5>Y,2nߕsΚ le}{{@}Ϻǣh=ߵ{_<8!hENDg .P&~qz8PG d9w9  Dto'~w jbHZ\dat~͋a8R'@@&Ic, A9gL~Yd9 Jp|e:[4'0%^]Oz':&XXUB\(JD@d\w'4lTk%dxƈ/txE/H"|yc.(R~~gZ!%fXr+DppB%xpd9 РkkIZ}+Q<'DpC<caK'BHX o sfiq/eC5]`>0i f'^7\"= Avś׮ťK4s@2k0ԡ]_bνמ[*@RX;1emscsڂKAZj tqnU6/cM+AMK/rt$YiAtVq5or`!k֔" 3A@~csr 5e@%< )"]Y}$\9q֜#"^~:`vH'6 @Jx4 5@f:%*#rY5B˗$we/ˤpN|UQ Wj@tk ҎwOC"{ҟ?uW76j=#QH!=/?2^[T>@j=t@?B:ƎbK_;@j(!OyZr/bQdp@@a'N_~p#F F@11b1bbĈĈ##F F11b1bbĈĈ##F F@y!w!Ȋ'H{RCyٟ]C꯮׷zF#Dɔۓڣn?ɞdI!nzzϪ;[y=mDڍmi3`A{ bD&ΟT*VBOf6$w`׿WjH9d#?'=!= W[]N1#FLj#j sr/wf~XXXʁ֟e;TfDh$j%Wz=M*r%jOU+)ʅ {d8<ږǶ,73ߡZ)0,t~v}ٿmH8~|N^iys@;qb _HF9FGLP`/ADBf!T^xx_R5֪ q-q-qpx+W~. 33@uXcIڔrHc_hT܉S+`+0ӟv @B;z,Dk "ѯ|zH0@X@Gdwc[{ x쁅R}F ˀ}Hz{?T 17|o^N0`d*'Bq#vLZCq,RZs @#֏N'z<BzuЈDy:xl GYsgy㷽, W]4/;9{p >AN߲KOOÀ"Q>TX\CTSNb HUN?<]P dcmzL6z K #A@;oo%~!a7 ͇Pps#mPXj;{K , ƒ\{ xh 8W;Ϲ3xq\_X0>q޸~y *Y9 ?y#]Q8"qaAڤd11bJfi6 J#C[,_@,`Aԩ|@Pn[οlMp(`=HtRK O yΩ09}> 2*@N(F_fJ=dLyVl uc!+#4DDL$ €ڀ$c1 y$#wAn1HD&y1hFr+G5f^:`  - \˙Ehm-bow}i{ s½{x;k9;{^n1 ӉuZbYJh;u gxY~h+(I<r@Jl* $!TbAX5VŊ:|v3qw3oأ8B˓ Ϙa}P) eqdJ }8*x`DEV(7‘qx,ۇ :lmw<&Ӽ8 61ovvقxcAǥDZ@yoHu[rGQ< B9tf^X;5lnlL4}nقdOQX:)43|Σ~!oh>+|7^i᫯OeK' _u Cd'(Aws^IxAv?f-L<Q:-f]7n\@u8GRLbQWB%@< ԜR:s5)΄$dplsLw0F&bQhٿq:zN2'Ghq@ |IbXHǒ8ᔎmhD8!SqSRyq3!Xx@ u>ƪe`plD< vpwgbhS,b{+& A_n({㵫' Nau٫;׮qӾz:}:^j~׿UW^]}W1\@.km}*hpx =\ @Ă<@pqo@D„1D#NL6IEa|O:cY8g=9>|=\7]bhxcSKkxL{8.r xv$G^߸%<,o .j0 w 8wv`@NܴI'ů] yZȹE@N\Zdvrum-F㱱 ōx\A9!m/<3p U&*&W*,_͟i":٢Vx0SނǓrEMsW_܏,Y_["?Ç*@ōl">BVxӅHӃX+@q(O˻/И Hqgt(dg!!z ,܏& \o?#"ṇd7j  s\[M iH~#thRaxhļ ;€F6,ksCd7bt,;Y(W_ ~G1iU^a)>Ġy=^JiD4" tq8ldJ4"_?NBgIc3Vv$zx^)D .P-V.nA ԄUx~->t$W?!1V DVy;^X9D6,wCkō3cߘ?l<{v~˴gq1_aΎ;;@xOZU57LtEvҳdY|{_r_G@fTxZ׮_=u4Kcة} fUx٥"Fo6 U,.n\:ɀrRi> lYb@ T]Ox#U>Q8@HmԵRYb7@gr0 Fz$d31bbĈĈ##F F@11b1bbĈĈ##F F "j\rՊϺ5'lו)חҮ4F~rB iQNbݚ&dZ.oAvyIATKHӵw?]yЯ PDIET_;ti;x~Z@uiy IDAToB+w_iAbKITUW{Ir+'\)o}oߵTf9ѕr3eHY,#Fh0({K&OPS}y,c|zeVV9miy 74ݞHϏ1Wӊ?4*}!L×h@o:Օ'VgVc]dW`i93&/c9ovcu}#k My  }:u]l߃)ՀPסJ@_xl +˱_?#]9?>C GV_YJOWVV@P$  Q'{̘*]7織Qm  VV  @LskR}IqB#*ʅ4Rs@<>>:+/O 42k܈Ê"΀k țxׯ/ 0$@ bpFQJ@/l}I 0ax<>w|/*(swE) )Ϗ@u;Ԕ㻾 ח =>A\rhD$W>'hDr@ʧOQN? \(nO yͭP `pYJ@@#I@T74ݞgJ *- tO .|oH}Eyr|OZA *б,5-onnG9,%Rsʧ*S>QIѹQ\h-\; `e?~cG] R#m߼~t 0~ GgTʃtqUy@0R5\~|,sYcy|+'+cl,pBȃhwY蟺\(n?Q`i.rLlH,gA>#D(\aίF"%mןߥ1A pW. BrL1D]ĈHHOtTbũhY OY+O)ŢDNsA+KN@&qAF e`!!+ SLq*k=_إz$ .hix 'c#'P]lpqtHo E4Be\ׯߐ(u mVJP !!"7P6پl{ER?  .?կTqԯ\ɊP2z'/Hr~lDcdfiVSS*x|DTI@7x5Hv}e#Iy؃O`e2 c(1v][MHAKۧQ Hy{AUԠ%@{ɚಇP_!6~|Ia,++|ctL7'?i9I0'-' Dba] t>k ?6tsŏ_uR$Hgj/$=lhI~ϣR@ۻAᢂ xzY\*5 @CFD1Fg4k 2?x|DļEfpm*I ޭ|Z,d߱r8> eAz]Y3q\IT>=GN39R>d=r@ &x[ !RL9Fk!<JbS|j)cOH<+M^P+b |H76z2,!SKfAg|0) Cw` M.a0 YL܂MpkZf{|dHEB5F)%EBrS'ʧ*D?HdZ/IQ="Sx= ·k9?qLP˲8Z@>v ^S7YYL/w *HR"y T+K?W>my:;g7%D̲,\V09O 8 8] H  0*;@~:LVfx|RVߐ<@2DjLJU+ g-ۺ h2bƓ$ m,kު$3ԫ$o57DNfu|s2al7ICȉy/ /3S>4@ppY5 CA'Ȅ*r-O1 :/ )6.^kRYMP2Z8>Hb0P9^#959$@Fu,x|! ה ?'BLcL lx`Rb_ @4t;+&59$ 2|00 Mڂ`B? ӧ|k,-#֍=`UX?dЏV(`PGbpb!O7Y7_v % |Y::W$G>&6 3Ǫ}mLBabMF Y,t4`ĘbQ#"Ə>Y,d% [lj1rp;ro|PYb)c5 |Mȣ=p|O'  Wǖe;[Yf M(ۻk{`aXW RµuFމȡ1y*o  2"|>04`; ibbDfڵX=Vi1XAe&0:tɆ M"_|{(pyqc"!#%!c@».aނP:&͍G+ӼOfSŻ F۶0*ݢpv[BLT.3yz,TDUoզ@11b1bbĈ##F F@@ijԸ$DHdw.>NGbE uh_Nҕ.39?2ݍ*+]3-:w6i?{wݿ#fA+Fvj˵:Ͽ# =LHzD_N夢kmX5MjB@3Bf1|bO׹u/'}]49}F:pWIk?ݿ|:DWNIR(z.1Hv+''ongfs 1gzo'k y>|q5S}9?V=^?yI/ibT߿twln;\Q{5aϝs)ϜKK}UϖO]r`iJG/8DQ>Ui9e>n0~qR7'y>ٌ}̪r,ߩ5rϧAf|EJIWWΝw^'5HoO@B]7:Y@7@2|xy R5zx_5Q_h},U99ؠXΎc*SL9('mQyCύq5֕rҸ ? !Ν-IM@F˨X7 xՎ<!Δ!}= m|% tWP$ރO=rjg0JKTxxQ|n|9.gshYg[ovr!',(HZYe@п UDl *R@oLӟ~*g_(G@ @eEqB2OhpEVDZ.ш()r'/% :]9?og?~Yv\~bR_WIm@@>v٩oA&E Bb B)(,.xkw36dêh_DC%Q`K @.ErCnr <{+IrsP ǯ(']~3ۿED" (v,ֿWeG%*)X UҋA?-_y;[>=W"$P !FgThp{>?!B 8*F/ B%@2Ar9J|ydLX2@`>C_F\$F$⹒MxXQ8\+Ey"/v)Q_8HCP=>*˃ ` ?X>?xd\{w iH.41 `AJXtXVo!5khyj 8ՐuITC>˂͍llnʎ~qEZ_(DU.Rr|E_$ e][Ӽa{Xs]B bY (]Yν. 9 ]񻉁 ˺7?/4zVW~FO5D XD " 5r+= Jk.V,qk?/;w <, W 1,Q"w pIo߉L鵁, ]z||Meԙ˗˧_"ec_,=B /rņkr$^_La)-@s HVC j@6˕hOj9 ,IgM󋆲{ @̷L}h7br@ܔR&;_n 8)Dhd8 O 3%츴{h:vqj Q^",H; /r' x+3g6|ԃv/E>` #Yy7Ƨώþk~pT e9w$5\"|u~asO^0iHH0V!#kA!ϹLxb) |W"|?F`> Fxܿ<'ȟ# U\H1\;e@Ln) |Rq( Vy;5i HC5L@<P:](Io2(=a`p)@D,=~r>b1RKه=;c1oz]SH^RQ_8c1B F TbiuZ#&Hb),Ux@<$`Ta1TBҧ@ Fʀo< F bĈĈ##F F@1b1bbĈĈ##F F=@w+qIUk8OZrӴnGi{ئo۵HLz_ޡi*_qKV( $ijnO}e϶HdTK2-W W^3N:Jbl1&/@r5AKZڱF9Y^HE+IVL}_קWHCu:˝2rdo[_\DQ0ݢgxc@,##F݈O wo藚tgfs3vL?;9$ۈq1r# d4*o_{?|/ҝo% 6`S>G3$zU\xP U~F:h^J g?;{v9˿\YUL/: z1fL/Wf񷐐ZA,:YX J=.ǽ޻sN{ڲ@|&'?#5cAHbA,}Mk$|WArql sqJ̷Ν;ӵȇ彖|R%ZK'#Kߖ--.^{?}ۉ]>Cbg86R@}'H@ǒZZR EkGg\3/`$_) @Φ HH_@>(BKbo %/wnZۋwoߎ!@ߙePw$%oA }qC3:*ijԟt S2Bc#cA:¢h@oӠNGd%ڷֻ>[@0#gp, 3 }{>bG@Dg,H)Re1=L;Uf~~^Ff j+J BЄg3A:Xc1ȹl ҵm #/|/os{» ν[o_n9 Kb?L`,nIW V.ࣤ@d.ڂ€ ?y|4hfA3ʂbw0E}{{Vݾxs۹{)yB<i<QIDAT|nABNRmWXd7667776N5 yy@[g{,oA-ކ{`P컩'>VقD 1 ye9hTwMH:@:w\iDC;r}7p$^x|o_u $!d9uЂwV΂SB; X!Q(ȱ4.+  ԙ[i;by{xjpwGkv3) @x+#@3;)F$;bD H]U@lWC ĉ-H_OQ Ԃ9sxlƂwŀ # @(oqD)HUU&H]@b -ȭ "c߱?x/D=9{n{b? XFjcs!u=385Kv»`AR ])L9(?_S }}zw}e\~1қ5.A oٷ.ܽ{c}p]}bQŚ%Wr@~<0.z/ާ^}Ln7˱ 2\{sYw޽wѭ'@H ȭ>qߡL*X܂8w!@ B$>H~Ą֭ǭ;w(Ea1! 8-UBy۝|ĄA{- |<d.cb9Yݹwҽ{K+^W@>!m]obd\,\×~xޟ{z!%Y Ȗ|pBDa=@槫 @ $ B;~y|f?_ #F F@112B^j~O{IENDB`openttd-1.5.3/media/extra_grf/canals.nfo0000644000000000000000000002304412627373446016721 0ustar rootroot// // $Id: canals.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Canal graphics by George / PaulC" -1 * 3 05 08 41 // Canal slopes -1 sprites/canal_locks.png 8bpp 66 8 64 23 -31 0 normal -1 sprites/canal_locks.png 8bpp 146 8 64 39 -31 -8 normal -1 sprites/canal_locks.png 8bpp 226 8 64 23 -31 0 normal -1 sprites/canal_locks.png 8bpp 306 8 64 39 -31 -8 normal // Lock sides -1 sprites/canal_locks.png 8bpp 386 8 40 26 -7 -12 normal -1 sprites/canal_locks.png 8bpp 434 8 42 33 -31 -13 normal -1 sprites/canal_locks.png 8bpp 482 8 40 25 -31 -12 normal -1 sprites/canal_locks.png 8bpp 530 8 42 34 -9 -14 normal -1 sprites/canal_locks.png 8bpp 578 8 32 27 -1 -17 normal -1 sprites/canal_locks.png 8bpp 626 8 32 35 -29 -17 normal -1 sprites/canal_locks.png 8bpp 674 8 32 27 -29 -17 normal -1 sprites/canal_locks.png 8bpp 722 8 32 35 -1 -17 normal -1 sprites/canal_locks.png 8bpp 2 72 40 44 -7 -24 normal -1 sprites/canal_locks.png 8bpp 50 72 42 33 -31 -13 normal -1 sprites/canal_locks.png 8bpp 98 72 40 32 -31 -12 normal -1 sprites/canal_locks.png 8bpp 146 72 41 31 -8 -12 normal -1 sprites/canal_locks.png 8bpp 194 72 34 32 -1 -13 normal -1 sprites/canal_locks.png 8bpp 242 72 38 34 -35 -17 normal -1 sprites/canal_locks.png 8bpp 290 72 34 44 -29 -26 normal -1 sprites/canal_locks.png 8bpp 338 72 38 34 -1 -17 normal -1 sprites/canal_locks.png 8bpp 386 72 42 24 -9 -4 normal -1 sprites/canal_locks.png 8bpp 434 72 43 24 -31 -4 normal -1 sprites/canal_locks.png 8bpp 482 72 53 24 -31 -4 normal -1 sprites/canal_locks.png 8bpp 546 72 43 37 -10 -16 normal -1 sprites/canal_locks.png 8bpp 594 72 38 26 -1 -9 normal -1 sprites/canal_locks.png 8bpp 642 72 34 37 -29 -18 normal -1 sprites/canal_locks.png 8bpp 690 72 38 26 -35 -9 normal -1 sprites/canal_locks.png 8bpp 738 72 32 23 -1 -5 normal -1 sprites/canal_locks.png 8bpp 2 136 40 26 -7 -12 normal -1 sprites/canal_locks.png 8bpp 50 136 42 33 -31 -13 normal -1 sprites/canal_locks.png 8bpp 98 136 40 25 -31 -12 normal -1 sprites/canal_locks.png 8bpp 146 136 42 34 -9 -14 normal -1 sprites/canal_locks.png 8bpp 194 136 32 27 -1 -17 normal -1 sprites/canal_locks.png 8bpp 242 136 32 35 -29 -17 normal -1 sprites/canal_locks.png 8bpp 290 136 32 27 -29 -17 normal -1 sprites/canal_locks.png 8bpp 338 136 32 35 -1 -17 normal -1 sprites/canal_locks.png 8bpp 386 136 40 32 -7 -12 normal -1 sprites/canal_locks.png 8bpp 434 136 42 33 -31 -13 normal -1 sprites/canal_locks.png 8bpp 482 136 40 32 -31 -12 normal -1 sprites/canal_locks.png 8bpp 530 136 41 31 -8 -12 normal -1 sprites/canal_locks.png 8bpp 578 136 34 32 -1 -13 normal -1 sprites/canal_locks.png 8bpp 626 136 38 34 -35 -17 normal -1 sprites/canal_locks.png 8bpp 674 136 34 32 -29 -14 normal -1 sprites/canal_locks.png 8bpp 722 136 38 34 -1 -17 normal -1 sprites/canal_locks.png 8bpp 2 184 42 24 -9 -4 normal -1 sprites/canal_locks.png 8bpp 50 184 43 24 -31 -4 normal -1 sprites/canal_locks.png 8bpp 98 184 53 24 -31 -4 normal -1 sprites/canal_locks.png 8bpp 162 184 43 25 -10 -4 normal -1 sprites/canal_locks.png 8bpp 210 184 38 26 -1 -9 normal -1 sprites/canal_locks.png 8bpp 258 184 34 25 -29 -6 normal -1 sprites/canal_locks.png 8bpp 306 184 38 26 -35 -9 normal -1 sprites/canal_locks.png 8bpp 354 184 32 23 -1 -5 normal // Canal edges (temperate) -1 sprites/canals.png 8bpp 30 10 45 22 -11 -1 normal -1 sprites/canals.png 8bpp 94 10 41 21 -8 10 normal -1 sprites/canals.png 8bpp 142 10 42 21 -31 10 normal -1 sprites/canals.png 8bpp 190 10 43 22 -31 -1 normal -1 sprites/canals.png 8bpp 238 10 22 22 11 4 normal -1 sprites/canals.png 8bpp 270 10 24 16 -11 15 normal -1 sprites/canals.png 8bpp 302 10 23 23 -31 4 normal -1 sprites/canals.png 8bpp 334 10 24 18 -11 -1 normal -1 sprites/canals.png 8bpp 366 10 12 11 21 10 normal -1 sprites/canals.png 8bpp 398 10 19 10 -8 21 normal -1 sprites/canals.png 8bpp 430 10 11 10 -31 10 normal -1 sprites/canals.png 8bpp 446 10 24 16 -11 -6 normal // Canal icon -1 sprites/canal_locks.png 8bpp 50 232 20 20 0 0 normal // Differentiation for the climates starts here // Canal edges (arctic snowy) -1 * 4 01 05 01 \b12 -1 sprites/canals.png 8bpp 30 40 45 22 -11 -1 normal -1 sprites/canals.png 8bpp 94 40 41 21 -8 10 normal -1 sprites/canals.png 8bpp 142 40 42 21 -31 10 normal -1 sprites/canals.png 8bpp 190 40 43 22 -31 -1 normal -1 sprites/canals.png 8bpp 238 40 22 22 11 4 normal -1 sprites/canals.png 8bpp 270 40 24 16 -11 15 normal -1 sprites/canals.png 8bpp 302 40 23 23 -31 4 normal -1 sprites/canals.png 8bpp 334 40 24 18 -11 -1 normal -1 sprites/canals.png 8bpp 366 40 12 11 21 10 normal -1 sprites/canals.png 8bpp 398 40 19 10 -8 21 normal -1 sprites/canals.png 8bpp 430 40 11 10 -31 10 normal -1 sprites/canals.png 8bpp 446 40 24 16 -11 -6 normal -1 * 7 02 05 10 01 00 00 00 // Canal edges (arctic normal) -1 * 4 01 05 01 \b12 -1 sprites/canals.png 8bpp 30 70 45 22 -11 -1 normal -1 sprites/canals.png 8bpp 94 70 41 21 -8 10 normal -1 sprites/canals.png 8bpp 142 70 42 21 -31 10 normal -1 sprites/canals.png 8bpp 190 70 43 22 -31 -1 normal -1 sprites/canals.png 8bpp 238 70 22 22 11 4 normal -1 sprites/canals.png 8bpp 270 70 24 16 -11 15 normal -1 sprites/canals.png 8bpp 302 70 23 23 -31 4 normal -1 sprites/canals.png 8bpp 334 70 24 18 -11 -1 normal -1 sprites/canals.png 8bpp 366 70 12 11 21 10 normal -1 sprites/canals.png 8bpp 398 70 19 10 -8 21 normal -1 sprites/canals.png 8bpp 430 70 11 10 -31 10 normal -1 sprites/canals.png 8bpp 446 70 24 16 -11 -6 normal -1 * 7 02 05 11 01 00 00 00 // Choose the right arctic canal edges -1 * 14 02 05 12 81 81 00 FF 01 10 00 04 04 11 00 -1 * 6 07 83 01 \7! 01 01 -1 * 7 03 05 01 02 00 12 00 // Canal edges (tropic desert) -1 * 4 01 05 01 \b12 -1 sprites/canals.png 8bpp 30 100 45 22 -11 -1 normal -1 sprites/canals.png 8bpp 94 100 41 21 -8 10 normal -1 sprites/canals.png 8bpp 142 100 42 21 -31 10 normal -1 sprites/canals.png 8bpp 190 100 43 22 -31 -1 normal -1 sprites/canals.png 8bpp 238 100 22 22 11 4 normal -1 sprites/canals.png 8bpp 270 100 24 16 -11 15 normal -1 sprites/canals.png 8bpp 302 100 23 23 -31 4 normal -1 sprites/canals.png 8bpp 334 100 24 18 -11 -1 normal -1 sprites/canals.png 8bpp 366 100 12 11 21 10 normal -1 sprites/canals.png 8bpp 398 100 19 10 -8 21 normal -1 sprites/canals.png 8bpp 430 100 11 10 -31 10 normal -1 sprites/canals.png 8bpp 446 100 24 16 -11 -6 normal -1 * 7 02 05 13 01 00 00 00 // Canal edges (tropic rainforest) -1 * 4 01 05 01 \b12 -1 sprites/canals.png 8bpp 30 130 45 22 -11 -1 normal -1 sprites/canals.png 8bpp 94 130 41 21 -8 10 normal -1 sprites/canals.png 8bpp 142 130 42 21 -31 10 normal -1 sprites/canals.png 8bpp 190 130 43 22 -31 -1 normal -1 sprites/canals.png 8bpp 238 130 22 22 11 4 normal -1 sprites/canals.png 8bpp 270 130 24 16 -11 15 normal -1 sprites/canals.png 8bpp 302 130 23 23 -31 4 normal -1 sprites/canals.png 8bpp 334 130 24 18 -11 -1 normal -1 sprites/canals.png 8bpp 366 130 12 11 21 10 normal -1 sprites/canals.png 8bpp 398 130 19 10 -8 21 normal -1 sprites/canals.png 8bpp 430 130 11 10 -31 10 normal -1 sprites/canals.png 8bpp 446 130 24 16 -11 -6 normal -1 * 7 02 05 14 01 00 00 00 // Choose the right tropic canal edges -1 * 14 02 05 15 81 81 00 FF 01 13 00 01 01 14 00 -1 * 6 07 83 01 \7! 02 01 -1 * 7 03 05 01 02 00 15 00 // Canal edges (toyland) -1 * 4 01 05 01 \b12 -1 sprites/canals.png 8bpp 30 160 45 22 -11 -1 normal -1 sprites/canals.png 8bpp 94 160 41 21 -8 10 normal -1 sprites/canals.png 8bpp 142 160 42 21 -31 10 normal -1 sprites/canals.png 8bpp 190 160 43 22 -31 -1 normal -1 sprites/canals.png 8bpp 238 160 22 22 11 4 normal -1 sprites/canals.png 8bpp 270 160 24 16 -11 15 normal -1 sprites/canals.png 8bpp 302 160 23 23 -31 4 normal -1 sprites/canals.png 8bpp 334 160 24 18 -11 -1 normal -1 sprites/canals.png 8bpp 366 160 12 11 21 10 normal -1 sprites/canals.png 8bpp 398 160 19 10 -8 21 normal -1 sprites/canals.png 8bpp 430 160 11 10 -31 10 normal -1 sprites/canals.png 8bpp 446 160 24 16 -11 -6 normal -1 * 7 02 05 16 01 00 00 00 -1 * 6 07 83 01 \7! 03 01 -1 * 7 03 05 01 02 00 16 00 openttd-1.5.3/media/extra_grf/chars.png0000644000000000000000000004114112627373446016560 0ustar rootrootPNG  IHDR _sRGBPLTE4@փn ( Іv ;|Zu09aܛiˑ"m;HDy/>2{ / @eHJ#qd p %ԘK^%@:_Oo7@&h-V`hP)pDE 4HY!|CF&V lyᮚWdMZ"7UeA:ᮠ깲Lw$@DI8;=-'Զ6ɏ ~H@g@?MFK萤}ӭuiB B psge d.@4pc R1 J3pRۼ9}xi5Q3{ӧT ]p(@xZYAiՅoYB](v Q,p +W+nj ,ªB#ƒtN˦ݣ.{.@h = YAʭ{$K[{Ssi'5ՓՇ1 F!@꨷YItBm p& y#@Ujq @ b&8uOoR"cD>ޔ IEy a^ʯQ~YBRaOEX=Q,a^P : ODt,7zj ?G .B G16+28Qg%}M2r%=RzZIoZEv8჻y׵Y@J`]b͊6cU߃k/ŲG`n^vm0ݼY@䃩HS/@  uߤ@ .@ AAHPP$(( ;F6D6Ce;Gq9;lE'UPJpUg j;~䨽 z0DJ8C!T/7|"i;87u# gpjo;Ԟr"<Ջ}X _ĕ2EːocZ_^E,lYO <\6+I jo;N>'³E^k3e"wq_\ 6XkM/Н `P}Pz*I/U;_5M29wfl6t7F"V) dM<\7O_ 4 v kn_荱n*m(smvp7su0nG3eG9ܚ_8.FIJBimg7 9BH a BA | 6@ fak5ĺ 0o_fd@B^4@GR ۓqP1;o |"̻#K"6Ѿ4]fEn:oFvRk:\P(2Cݼ]{b{$ @ Nt AAAHPP$(( @ AA e!Vhdgђmgyvjo+m+ sY.RіgsZcz?66A,Ic>IsHX=>o>@aPP.y$mG/ L-q= )\R2%+ ٞ`Dy4%|ۥۻU$0wX=R8֖" !y*=I҂T2cdK5R땶ܐ;4@3Il~8?6"l'qR-M_G}pj8wB iIL\yWx4HKr0;37f]ol~,=g_ i* h U`Z|)Sj^U$4{J*%i_:Na7i{n'&gUL@dZLu qM'}lI%[^b'U2^w>#(i%@>Hz\7 4H2X Kr7@ȚX)uX|XSI͐K-'οdHߧTBn 2rZa^J0@a Nu 7X,Dۜ9@c F$Z{2yaXq/@^XH :86nmΜ5 @ ';ϽR}aAR2%M*-mGyq59í[bB*k!;om+a!=oYI.eaAW'rǭ& TQ"| AAAHPP$(( @~ RH|zi |clտA =F} ]ip~r[Wl 9k Rqm%u&7@+Ӹu?5B  fg4H)LiO)}])J^~J`iJ{NGHw!m ;CnϏ bC <5M@xRt4܂}aA!  oVҾ@@\Af;錝@:\h4βMEiw ?Qw8XѯX AAAHPt={s]pwP|VԴQ;!f/_V{8hFٻ4Q}>O~'@CSwd*i@ڑ_>/@Jw@^A7wGp[.H%}3f|qk$eHd9ô;Q T/@J,O@'w`Jny㴣OoT)hpTw;Hc&XRN>UH @HFxڂ3Y>|u>){ebuQ V$#K{ @}<8m -}pڭQ';S>kP5 \BO3Lv<7=oޒf;2惂_&k>6| Y>x6 [[@enk㖉EkI}hNEddK9(m({ z>12/" RW c*)uJ;1,*MM[@bCQn;T0AZ' & 9&V%ػVҷlYqVxu(oIZ6maޛdmQDd<oxS|!v}3|0,lR\~l%Q@*I| 52Ϋ7@DA>[| <Dìc%//]F%FpJz _o-t 9d=p0 ?,^}bO>ڋUMy|Szao6{v^fb20u nݼ3wN{S3 @uHk| w` Dkeu` @^,}}r+|rߥAAĺ@ AAHPP$(( @ @в"Zi\O)i 6?rȏ^*WmWu;rxZr.}jK7l:|zJ u6UZȿt @YLgZZ&+thb,f.aG̲t<TԶ_RP7g*@W8M&VѹH"coz#˃ͧkn dҊd$GK I&U$HWq~ɼ DBK>~U҆ *GklVPd`4>*f0aDd$YKA&nQ2Oiah@풜1@d;_M\|dꫤ씒PzP63VZ` еs.$4Py ܗy#ͮE.ad[J԰$%.ՌUqJ5"db 8 W$naBVg4}@߳Srl>gk0j_RiHMlL *H^Jk .>b?Tr p1ЦjnMv@A_gb%06M|Rl=|$_~a+!_-sB`2 4 Q1TTU|4FrFqjDFiV"jw.D3JL0qVI60,kl1c\ħNZZR{EY{ 9 &i䐈\JO&iP}Z~v `q7Z݄f:dV= {%J#((< h\7{F .wW/ӓ?k[M]4 @ AAHPP$((A&( ݛ4av%&.><[>`ot|橬U;ܰ(NLhM[iD̪*U4I^u|b<և ʸ>iuvkUs_ < i@Fx@i ^Llw5=4؟fS9YvW:=0 idy'@fX B wOF Urf8n_TNXI&> N;ל(^e1QNzPPP$((4 {n9o7 oH>/$M5^|u_/F7V^ýQ YI@&][?)Y@p$3۲GiN3k080V>yG@s@D_Z@*:e@@uv .[uz)ReB r|Z|EosRcKEJp6Ci\ŠjdbabGlide<ug:}u.@Z@buvCPhVv_nH/%t+]sB#b Yz00ģ/OE=ciy]Azeԣu*;B} vSP|6,'K64x - !09oL N j4ɻC(T-|B i bՂLS ;M`+5aG4-FOh + @8 KJ֙b,:m @X?e Rc/@M,BjჂp ؛_KY o&MM;mba D   :ZQfMd@gLh AAF>7IPx # }ұ`ƃ2K뫕E دA$V ^nnT)}_ ֩{HiIW̷K ԖiÅ1sKQ,D̀t| )j9!6dn 4H  #>cY|  $|}]yNp T&(~ ;X!zDqv=Ua'@ iy|zRj !@'D.=a'@ :+vb|Cg3|ͽXjm'ߡXӸP=B@L+Jc Z^IΧe~:]]xwwy"y7>^U-`դG1j r#Թrʍ_t|@95RCfB-mWzS)1a4~@Pva4M P{,@6;F=XB} Aؚޝf4@kV-.?Pgc>AX;w_ku'wpaj2IDAT 7@ AAHPP$(( @ @Т"ZfT'!hIR| Cww5}.g*MFviN\3 s)Yt%8C<k J4]gB06a csD^mF;ZҋmcTO(RDkyy t)c 2[:]G@!!-Fi2aeVrXDi^~ [3~y*6df5?UdLNa$+ޠE 40>㣄4É @*>NbE #䋤Yqr7̻5MխOID#'!ЄLBN7 BWd=L5uC|[iM0(]k=|BW؄;[s|'v~_ Cβ#1{=px|)[>Ӝ7|pV&Sy |۳|R+̛L"F5۔p~0t ڲVpYpBv>n1]I?7a%ݵB79< ^qGaDQ^I bg*E̒ ̅N!fpP{ AAAHPP$(( @~ h yPZkYcjG(+"ofׯ{s  Q[ɾGҺFxx`]^ 7o `JiMo˘Aol/ $B'ke1lvwq kKsהMR_Oz7@N#;@vkɂ̏|{"K˘{i:cNA rio{t? }uL8X^ߙM9 M6ia.:Myh=ġnFܓsEU;o Uno7|~TZ>Z7s3n : 3A~>hL.@|S'D@꾘s:Fj6MH[|claL,˗_ WGȱIJ/Ar;ܷcV-rH@57jbG.kUI\MSȋaȰf`s9>;e^+}4_I`縺P#o|sDFPɶF8Zsi 9 OM Κ<| I]qȁ/sOmĐ86r_._.@Z1@(܎:JjR~h  ,n@(5g|Wt >t>48w c u*3 m4H;I| Z 1>/|DGZ}    MB>P ?(ЗBab R&9BgB]oo5 )hs \VY^Gފ1gZpJ'CK)"fjUsy8mh l>Pͦu?WGdQH?.2Hݼov|zjs74Lo6vԶx#=Lw` |6!N\Cݏ|vSgb>RȡFʗPޓY5fAVYbG~Z7@ d5|L"hF FkHPP$(( @ AA?bu^c=un64&uHzLIh뒨U 0=T ۻ.:o.>F~\9d4PHp60ΕUNys$2gL ۙ vK EAw&U?eo0+Xh`DJ(Vε dN4HbY/9M3|t,v+Bdg^kJ$; ,\=eyr$4B)>kh߬8N;$y1IGf!P2IdMLS0( ]þE@Bw$ 5&|y͋UI-&[w> [l5FZ [3ӻP(\g뇑7jVlڽ {VdO[nC)Gc!_g >Jz:VD2(}d%s!0E> @ >h\|)}fI^̽VHPP$(( @ AA tJ#/1+ ֎dSwșwt&iʅO2\~UOp04R[''δ4#T@>7dGWP?rSg4$(ӄձ ,~|qP[BW}6&IhT46;x~@-yLkV#ƥA@ʛAӥE}odr'id?@ :|i&뤿%>ҎDhvb@ AA\:]ߞ[O<cݾo[^J޹\nŗFmv8Y]snk̭odWm~VjlG Qc@!;v;zyru ?*A*|HD^JEs n)@x#@VV@kȌQ)Rcv G=:UYB|F G.JZ(2uq"ܞ$ !_ ui̵eh{#PgZW%n;n\SS)֪7:pA.]F!uo+* kyu74dc,@l;3D󓕦܎`e@90ױ\WDRd mh@I#Z`>b^\A&&Uh{M| 3) ּQO tz=1E>eYiS4Վ᭒5@:l/ۑV>~`AjyNYWWWc a `Zu/@HL+L++m_.U#S+ | 2{ іxA&9.xZXo6 l[IRQD)L" J^EQ| L]d5KI߀T `51>W@lz e#k4]|CY!P Сnp7eqD`A (9r@Dz4mGy ЀeQ\>?@JHH ~֨+}H=ü 9'¼K'Ȣ A*5V!HO:p݂Q~,@мF@zW֯K ׭A*k  - b!cTGqg`z>슇H5@l> lbTF5ʩf{)`$$rS Y}ٺ! ,V Z|/3o[[cbSbe"=Pkj>͓`'(mL&"뫈L@yu;ե(@&h&Vh3ۘD_@jʈ;#թZ\>sXX*S|-;B ,jB+^qQR~#Grc@T>"dB>! l5![- (;n'ݬ~a#k(@hݽxE#G;򣲵Gzz{}tfE19BO"E띩Pn 0o BUX{?\>;w-. |[lw;4@KÒoŎ= 0)=㎋b?A?T]@:nDZ&!|K9 f"^I'Ar) @ AAHPP$(hRJ| k@xp&^㾗Ou׏Ztjm[EauhXjVGLMpoRHY44ՙAztWSg,6Gas_nUW \Z^CbJjRTΚ^)$u@ -5LJ(9s yjlC֯\8jkW{VEHMrN˯4ȫ%@VWd>ZKb6NhF%1 _" $6 Wc,a.+XkkXgZsH` A*,\d R9q$g. $HS0sPd1dqk{%%RiFl3zr@A nN$Ar!ʰX7L)R4jJ NS8?h4 o4HJ2^$+[lU*&?5lj$4 ݙ!GXJ{V#V):i‡=opқCeXHlNPo̼@fh9d1,@6C* QTĤGm&V-,|ԚnA6Kj04_20 AlmF`¢` (!@F2@?0: *A^&ײ[z.vfV`ݶQJ F'TZc|Zq/I!1*NXMA-uü_Xѽ0[ Þdʚ%#li 7%QZ K)\4#3HF LMRaޥy3aoYIJs~}%YI/:oanIJd}r &AAAHPP$(( @~ ]cHni23i zKT\1#}۸_nu>M;>ů4 /17}娟M] HD?rkԫY۽:Z4S3K4;FVa(uO8ByP/oTwPn蜉iGހ@pV Xw5 -&rdމaj;fHYF@<קUWH bRH\f-Z>jlk/j3#Q+sC"&*L jG˲Ekۥ5ip2)06f@ܠB f2H-AZpy@AJy%r0K%1%k]+F:Dd-hgs;78@dom% JĬb ՟dÂ+\UKC z |%Ԃ΅-i% + ;BDL]do. // -1 * 0 0C "Electrified rail by Michael Blunck" -1 * 3 05 05 30 -1 sprites/elrails.png 8bpp 66 8 32 16 -29 -2 normal -1 sprites/elrails.png 8bpp 114 8 32 16 -1 -2 normal -1 sprites/elrails.png 8bpp 162 8 32 1 -1 -2 normal -1 sprites/elrails.png 8bpp 210 8 1 16 0 -3 normal -1 sprites/elrails.png 8bpp 226 8 32 24 -29 -2 normal -1 sprites/elrails.png 8bpp 274 8 32 9 -1 6 normal -1 sprites/elrails.png 8bpp 322 8 32 9 -29 6 normal -1 sprites/elrails.png 8bpp 370 8 32 24 -1 -2 normal -1 sprites/elrails.png 8bpp 418 8 32 16 -29 -2 normal -1 sprites/elrails.png 8bpp 466 8 32 16 -1 -2 normal -1 sprites/elrails.png 8bpp 514 8 32 1 -1 -2 normal -1 sprites/elrails.png 8bpp 562 8 1 16 0 -3 normal -1 sprites/elrails.png 8bpp 578 8 32 24 -29 -2 normal -1 sprites/elrails.png 8bpp 626 8 32 9 -1 6 normal -1 sprites/elrails.png 8bpp 674 8 32 9 -29 6 normal -1 sprites/elrails.png 8bpp 722 8 32 24 -1 -2 normal -1 sprites/elrails.png 8bpp 2 56 32 16 -29 -2 normal -1 sprites/elrails.png 8bpp 50 56 32 16 -1 -2 normal -1 sprites/elrails.png 8bpp 98 56 32 1 -1 -2 normal -1 sprites/elrails.png 8bpp 146 56 1 16 0 -3 normal -1 sprites/elrails.png 8bpp 162 56 32 24 -29 -2 normal -1 sprites/elrails.png 8bpp 210 56 32 9 -1 6 normal -1 sprites/elrails.png 8bpp 258 56 32 9 -29 6 normal -1 sprites/elrails.png 8bpp 306 56 32 24 -1 -2 normal -1 sprites/elrails.png 8bpp 354 56 16 8 -29 6 normal -1 sprites/elrails.png 8bpp 386 56 16 8 -1 -2 normal -1 sprites/elrails.png 8bpp 418 56 16 8 -13 -2 normal -1 sprites/elrails.png 8bpp 450 56 16 8 15 6 normal -1 sprites/elrails.png 8bpp 482 56 8 16 -7 -14 normal -1 sprites/elrails.png 8bpp 498 56 8 18 0 -17 normal -1 sprites/elrails.png 8bpp 514 56 8 16 0 -14 normal -1 sprites/elrails.png 8bpp 530 56 8 18 -7 -17 normal -1 sprites/elrails.png 8bpp 546 56 2 16 0 -15 normal -1 sprites/elrails.png 8bpp 562 56 2 18 0 -16 normal -1 sprites/elrails.png 8bpp 578 56 8 16 0 -15 normal -1 sprites/elrails.png 8bpp 594 56 8 16 -7 -15 normal -1 sprites/elrails.png 8bpp 610 56 13 16 4 2 normal -1 sprites/elrails.png 8bpp 642 56 20 16 0 2 normal -1 sprites/elrails.png 8bpp 674 56 20 16 0 2 normal -1 sprites/elrails.png 8bpp 706 56 20 16 0 2 normal -1 sprites/elrails.png 8bpp 738 56 38 30 -3 -14 normal -1 sprites/elrails.png 8bpp 2 104 72 44 -16 -8 normal -1 sprites/elrails.png 8bpp 82 104 44 35 -21 -2 normal -1 sprites/elrails.png 8bpp 146 104 72 44 -16 -35 normal -1 sprites/elrails.png 8bpp 226 104 20 19 0 1 normal -1 sprites/elrails.png 8bpp 258 104 32 32 0 0 normal -1 sprites/elrails.png 8bpp 306 104 12 22 -9 -18 normal -1 sprites/elrails.png 8bpp 338 104 12 22 -1 -18 normal openttd-1.5.3/media/extra_grf/tunnel_portals.png0000644000000000000000000004437012627373446020540 0ustar rootrootPNG  IHDRN2) pHYs   cHRMz%RX:oZPLTE 000@@@PPPdddttt4ϓ(4"}ǙH!R<u]J*RZ*VoOFC*c%))7jJʳ8oJ(RH%BJ.4(6"M~aȍQF*c(!ȥFJJ!ȅJ;,Q)e4Fq)%J<, _hdEuORPJBP*y"]Y33B=s!B )M.i..Lk«\foynƘq #T. x+LRfGp>2&73*U@y]"Z^w]7PR\J\i{ mN RJUh]"/>;E.2}&BH #+b־(4(JJ)L.BH#宭o)ަ'$(D.cNR2WJvK/ tB^$Oid.r!ſ )$HUB+]3RJJq /2\\^+%o{4FnP].*~K`;4cRJF)#Sim.ʥE*LI] rOBKT&(Kl HZ+OCsa1HT\BɥT6$g<ύQRT.ȡ.T.|g.tw*K\ $FH#/|u ~ H O6G8E\+W70kJ"BP(ȔykR]1M RE.˅Hv'TR\{c7&7HQ&7d^Rwg:YS2XF\!ŋLB+]e/RTZҠZT{8<RBiFOh J")R2ύMH*(%EnriQdB"E<uvwyrDFFiD~26J&TJ%XuI,\ )ui]dEm+{)>%Rq2WP蔨( #'F *VJkL.3's)s!ޙ\ e|~(IӇNgz":_*V HJYbsriL.ȥΊEi%ՠ뺁 )J)JR8<ϕ̕QB aI0+3Q[)yֈ=D09#cWJ #eogZ']DE!Qv,B%v+T&BURZ)З*4JɔT&?Ʃ -A)PJ&rAyK#P*4qBg onk'RcK#1NUEO()G{/δ/WS)$J+2B<7ýT]Ia^We͚OTR>cTHɥ0J;)scN}ß$I罇Is\ȤJDI %q|p&zEnr)mߒRH)7z a1R4*7FA.|TZJ!05)r/1(qﶂTIH!~(tPQRF=SFXp\ |JN J)-I>HKe1Jq3J8.BB Kŭ}J)UwBspnvrMKc('2GZI F|Ɓx_( y8SPsy;F܈?&hPA@*Usq"W<0v!i>~c[^+` rcP$1gλ=DIkF. ` V8[>/nTZ.4F 5?ᔗNpS Up oϷ0p~y@?:}M kZbwGQG؆K !g/}pU4B#a48&쌲b(|iZ"!pRBDŽ-vLI~ #h%W00}N(ygcHK% St'!@&G9BR#FF @/a {B /0};K4པ%[xNϐMqL,CG@(P qsK)L0dP4„RlKcl 9t)!@Pf`3k60n0)S:& l L224Ó8FϱE?f,0y k³#ލtjFxtacJ EhJ & 5SK-~6(֓,P,QdgJ aA)d AӮ=)t<d0gz!U&>C  }@(SЈmw"KϞbB)q0ud:5j*RZGS0SB0<'u0aZl<&o2xM Ocu݀t| @@`WA^JBcgbY c4"3JTkb'c)OdO]3`-%@ 8N ;LOsJ@0Ř .NK)P)=z = L2&<~62Af: L}JxM%Г ń P11a/(<R!b!ݍ)L-(vlsZJP)%;q= ;~7Ŗ1 Ⴤ'@?Z1= 2%@`2AO̺``;Nd:XM'z={LF!cL:>[BE62%a4߾[+XRR d<ChCbĂ%!NC}h&XB)>`[JoG co@~`Spu`1OДN d<g@~DFENɿ9#%bc aJ1" e ɀ,”HJ1Z%ZbJM(B!2!4OirXl#۔؟kOtL1vED]QA)%>6Nn(P2&bD&O);>B &XCP a tQ0QF]!M =gAbG,?b[KSB} &b麎PJ-贈?)ASDdl2ۺ  %bb)P2%sF"0dB bl1z73 vh "[lhɩN鶵?ZLeGu KB!pՀX `SGR RM SR "](P `-2ň,){A3t]7g L ƔL`Lar!D)l(0J[Lo>.@0znG{b!1&1'm0x1Bߡ0 =ݗO)`!SrdB%a$c@S1$lPKBN)&"2=fEcBhLbKu(B(c-J㓚RJ=" B^Gv% (iubb1l)dYn(@b %S40=NGhtL,9ĉ-c:# ES5;J-":#~^(230dJBu6?`K6)0t LHNdB_(F3x|hD @6SJb 8πdasZlj &sx%`X1X aJ0#xicl1g"-P'}v bKamLa`+q_RBۄt!oXJ({J}'#ht cө%GP9)&xFfj1`Jȡ kЩ!؁N SB/9WQ1}UKcBp"NqɘN`Lȓ)~ (<€0"ңD ӌFq6&0!:1g F"adG#4{L3dx%FSLp!t #\yj$#S%8Ѷ~Wd"4Bȯi0/5% 9on,N9,;=j7oyo{Os@]vo8=__{s2kZ3c5c̘ٗYc=3~ ֺWE7Ɯf|6 Ǔ1fg19דּiƸ@ϼZg13c5Pcܗb3ڇ1331^\̘͌s?n?tDc/=^uc:OpӞyQsi͜;F$" ۴fXwϽ"Y: `Zu{gPcw֚Z7wg1Yk~gꛙlxzv3c4Ө1ֺ K?{S;.ۓ݁nu h%#foqyo:;Ι2c5;kMm͌&q悫; ̌uzt61g}heZgSk:g:wwK=!;kg{wf^yc3ƙ~9`1yuƝJ'W13ƽߵk8gs{}~{q5%:ciuuDk1ȝ{?Ȳij:py";"΃{?O53skXcuw8Yu[瞘ٓ;Gޱi8}3}'vvstM%RY#ZYwfY}\s{cw.˼ϽsY7f:Oٚvͽs>Ywyg4h33x~B06ƦSYQ51Xc|V圵6y>"hu`ଙYg}?y$59\YܧY1q1g5Z⦅[p9:oLέbf1.Qƚ1&m&9sX|ü&nG%nMR^)~Y(ٓ1րοȼw;g/ ).siͳߤ 'pfvfuc8MCf)nl/(b–1֘8S;3@o.閱J֔:| ng>{t]Yhz`ցxYMLu['pf~Xch~w9g1=Ul`&q `of7g3?k'ӑn$?-K2}WΛScfb~g쮟N5)%뺮KbYk8n"~ܹTTY .kZ7O~Ykm~9ZkR 3m@n]ݡ773=53ssd0S8kfnkq{'˶Ν;3%lݶ._;筵v.kysnfffg=}/&N [v8?Xsӻͦ1<Ό53st|vAwJ;{gsr&M`m vGC?<{1ϼnuk[g'\Ξy3͜9sk3N9k_s|4OXk̍7{bRywnܘ٥)|Zi1$c}fI?MM_o;Kn)Ǯؙs޺MDc=$]Y{7mNDIr؝w{CiƂ/}LBX}+nz9>ƚ;os22RdsO6ҩ}fN䝳7͞<^sgv{߻n9Tai sy뭱)3֙K5i>{뜃όygniCf6YsOs;E{9p97؏;:7$cl}8kNw>r${M澭wM뮩w-fTUzp'L dv?Xp&HH*K^/5}4Jq}>|nhEwk>X8kOu(mZ}uEu}5TfjӞ)C>{֦0tܠ{ W}:>Yôsy~WԜB=GsIϵvܼw[?}Tr(II1'cNk.=$U}r;!!B>sYdvԉ<8FRl6OkZ=Лٱvc-1Ɯ, U^ l"q|`f\8lfj>7 ui{>`p3s33Cc7Or3x8w֞yYw<;Jf6#g;@%{y7w} ffΜ\"p|Ѵnn\a/igO}"=v}=='98=.| idJZ*6M;i?\W_^Jmsfh4uન]S޳UzgT cƶQ{~'@ϼ%t|h8lSCc| M=ދsSb16^\*ĺMml[F>g7/=zmֱC? O(H an&6SbcVԱu3lmLHk1?<Ѓ#L>c;l6'Hg4u~hĹuF5610alױڵEc>ծblOqݦ1ֱ]7CcM]г4m268Wi 릉6WqsWg\Ŧ6: c~hcl?ƸEMctw/X:wKMa=S<Ҵ;&6pbcclCpO=Ulꦩwkۤ9{L>W1jW>Φn@kWqZW6yIĦa=)Hym&61=6_bq?>*6ng?`mbmۘgX) MBC16]CFMmb3z8F4IlǤ~h\5ib:&66|hcq_%-Zc?ZŪlj[Ml?xlc16iuZ~Tjbɒ%i`MIrܱMlꤡ0}Vƶ]C 7v8&ٻ:MĴ즉mml#^1#Gx$v:m\q;4]&YҚ@;@'m4Mĺx&v6vclFvccfߚfPPn&Ob nsu5m麥QgSױq=վ%#Юu|Ji:6u3ˏinznm4Kfg*MuPYq;CӶm3ldmӮ c4uSM3P;ŴaWidz;~a1z'1M\m-]O~ޤ_tu]uQ$9lNLԩZO@uۮ]my*UM]4u3lbӬ:w>4kvشMdIҮmF060Cc[DרkD[b[\Uxl! &%1*6dMoZbM`u]i{myg zXulVm$v=yƶ5{Rf&6u,7A-nZZqػw^867NbLjzu۶q㦩:6uc=Уq۶]lS  cѮXi6pn0\&@ iSG8Wmޅfw׊pӢ5Fa6M!15*6ôib4TwbPu\#ǡhS:&i艼jW~& &<.nb۶mMa=6qծsB'لL-۳k1Pi0ƦJZEYfZ仮[/hs6׈`D#Dcx~4ä'15@Fa cuI&ic61eIp ď) Ic *XǺaU_ |o=_S1Bɦ4wߧI)MRxm&-Bvc'naS@xAc[kXkٺM`SXmL a3naԫzBN`k38ULz^nQuXwT1[an9n3Jk>cہH HgJMS= nRBݬ:ehӤ{E1z8M't[%/tW+㦉8zgpX8<@Sz8cl =}zUԫ߁vv&C8pզ`k}mSo6Ə`'kxp+#|DzԱnͧýMoC.X;a0uc}n^Q*~${3SUHr)V? qLmat@[ &bzSS9_z?~.MO9c/x 8S>z8q{Ei9l9zy8˚yjMÆp=:w2=kZe Wx$77ymg9hꯩoꯇC?hߞoa4~q2]?xM e.ƶPP~{C;??} WE2zQ>/e ,Qb,P.w2C`yo"hyžDYz/˽eXe(/20;E(C+*I%^z!,"2eЫ4ϋ08U/}8/9c,eB,fԿe(93^Uſ쳳 &8 ee!0+^U,C 8ZV-OxU}|Y-?T-?Uw\e(oY+ gV2>}_8'lqdG(cM`ooիp^]+z9!Ey|qYuQ+3yrY-?-9_V) %+U`r5]$yeR?>UK~Ź('%ղb6e/gUgOge8HVQƒh pPU 1",>1J}Q3xxeŗSA(+P^0Ŗ|q8_VZ~r'vldOv-Kl3猳jɗKXY]{H026k{*^«p^]+U`!#,e~,НQղ/O>-3no=xūO=0ZVիټsQx]V݆d1j2\^-+{BН S4g!18WjX,WիURrΟYH;061Qw_.WKΗ*'Uu1; >-+޳2:TO+*ΫkVWEqV_2rgQe`ɧ^$0ʭg,p6NZ,嫲,_W!J4>:Wi<c|HղVKu]/o}Udog)[Vٚ=Ub6_B`ZUƗbՒUpxrxU.b^W*,ʣ28E8PnM(r^/TW<^;B+CœCثg6挿{^UՒիY %UnetX`={Ūxo,eX(c>Y4"\\= WR;ʲ !X`^nӲZdP*t]X]Vꪼ8ЮR3-gq弪8+6EY-m-gUJ~|y͒C(C2Hue0N(_\\W.RI}c>P̺x` U^0e9~+˫noyz]1|1~_V*[XLio+% xhY mB`eP+e20Ndye^.^.BY}~cd3 Si|5oEY|yu|J;CJZR/ v]x*YY`쿧dS*38! 20e9)SW銇}˔Ne* \eYWno{ʮz/)-C|7%*^߾ ᖱ^_-.*_M|L}= 8T 2 {ta(,'pNKESn]r1c e`mؔ;]*]_^އ}sye!2“yG,ivVzV٤:Ug{*o_ ᖗ_ 串0NmWsP*1DZIcaؕF3v{6>9e[Oְ?20Bm|48\}Lk8ݸPbUoo9{}e`쯌װ s!|X<#_1Ǔ97tgK^qn[0#Me5CߙWWUyu?~89e,%GC2n(_sx(t>"ا!pU8<᪺MaU'7KN %g_=\pi,2߮ӫEpk"%'FOU3ήϻjP2٘ݰEQtB:HegْSd6Wg=5(S w|rUW'7 %??8 cU?ETp3Cіc3v^jc /9{՗+*StQJ#>g/9 x9ze״ʽ٢<\"`2Xunn2}g8[tπsQ\|Wľv۞A| 7ߞdJ^ӒB ;J^mR )Jk)ęŗ 8b\).gJIvF )ʅcd*%/=^sz=Atq}}u~~NB*d7y^D+}}]\__iԹUB+U(TRL(TB*X+E}YJ,QItq}]Zb/v I"?3BRJ[뜵I;RIfZZôhNu9)RI!T*)JHc1Fs)RJeB)]ErާK\ tNQe_AZ"٧H)83BI!PRIkJH)~iZ:z'B )JJ2)fK9C{'RJ%ZEw]70y.B ֺ؆3$.TƙS&(B )T[o֨TZB=]{H6w餐BYNPw~PT|j#DN(ij뺁B\RJ4w ~ﵺ.Tq'V˳yg6M^\J%jBVJkTRNB*Fz)EzKy8{3L*|>TZ_EQ\]שdg"Of tGAw&=j mQJi"*)xHV )M;RJQi^FkJ&)H&Y&ީpNf18JVSJU[ *2;RlnVWHV )dUD{JZ o\w[Nܪu޹>ONzUiuQh]XgLRM_ 7BZ`OqR=]4ޥTZ뜵vSrlݪgDR!sz8'=I?օys2B>oYgV rsg.Z[u~{WFvB !u9{+sY^+S黮So!sfϳ:?SUf~}](]he|>o8yk}B|^&~yk5W=y't>ઁ?.\&)t~w]wR(Ul`y33Oy3(Z&1wp*B)ב;y&irz|8%JElJ&Vʺ:|;]*)ku;6ް|ͼ1.VZk?Tcu[kkVԡvO0BBnBBާN7RxSV)BZ 꺷7s6}"ɼA }99"u'YsN|杛6cv{U߰+ }1TJ }DS"}N(!wԧj/L}VR=F'RRK0ʇll5T b &0Svt8|TbTEq\^i͇;TJLXH.řr3y``غI9Gv洘{{'2Z}t7!;wwRk64e(SIAB+tC^sZ)!ǂ3.B>97?h>R}1VHm9?yB露J#2v@n>ds}yOadsXuDԺ^=9&񴟃sۮ5BFDZc#=.:ZIa?@_"yg B*Ȟ>ǛLR+yY|3!p 4 >Na=,2UieԴ{S|5\S |<״y oW!NG믉`-tIENDB`openttd-1.5.3/media/extra_grf/openttd.nfo0000644000000000000000000000701312627373446017133 0ustar rootroot// Automatically generated by GRFCODEC. Do not modify! // (Info version 32) // Format: spritenum imagefile depth xpos ypos xsize ysize xrel yrel zoom flags // // $Id: openttd.nfo 26869 2014-09-21 07:57:45Z rubidium $ // // 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 . // // Sources for OpenTTD's required base graphics. // Checks whether the correct version of OpenTTD is used before // allowing it to be used. // // // Number of sprites, it is wrong, but GRFcodec automagically gets it right. // 0 * 4 00 00 00 00 // // Check whether we are running OTTD or not. // -1 * 0 07 9D 04 \7= 01 00 00 00 01 -1 * 0 0B 03 7F FF 80 " is not for TTDPatch. Use ttdpatch(w).grf." 00 // // Check for OTTD's version number // // First step... Variable A1 might not exist. If that's the case it always // skips. As we do not want to skip out of the whole testing, we skip over // the real version check. -1 * 0 07 A1 04 \7= FF FF FF FF 02 // Real version check. -1 * 0 07 A1 04 \7> \w20304 01 01 03 // If the version check is supported, the string is translateable via OpenTTD // itself. Use it!. -1 * 0 0B 03 7F 06 "1.1 (or trunk r20304)" 00 // Some OTTD versions before r11130 did support Action B, so use the English // phrase there -1 * 0 0B 03 7F FF "Requires OpenTTD version 1.1 (or trunk r20304) or better." 00 // Final fallback. No Action B support, just skip to the end of the file. -1 * 0 07 A1 04 \7= FF FF FF FF 00 // We are a DOS paletted NewGRF, so tell OpenTTD that. Then it can actually // do the right thing. Yay for that feature as that means no duplicate NewGRF! -1 * 0 14 "C" "INFO" "B" "PALS" \w1 "D" 00 00 // GRF ID, must start with FF so it gets ignored -1 * 0 08 08 FF "OTT" // Name of the GRF "OpenTTD's base graphics " 00 // Description of the GRF. "License: GNU General Public License version 2" 0D "Marcin Grzegorczyk: non-halftile foundations" 0D "Michael Blunck: catenary, signals" 0D "George: canals" 0D "David Dallaston: tram tracks" 0D "Jonathan G. Rennison: aqueducts" 0D "Bilbo, Jasper Vries: font" 0D "Andrew Parkhouse: rivers" 0D "OpenTTD developers: other graphics" 00 // // The real data of the GRF is acquired from several subfiles. // #include "2ccmap.nfo" #include "signals.nfo" #include "elrails.nfo" #include "foundations.nfo" #include "canals.nfo" #include "oneway.nfo" #include "tramtracks.nfo" #include "shore.nfo" #include "sloped_tracks.nfo" #include "airports.nfo" #include "roadstops.nfo" #include "aqueduct.nfo" #include "autorail.nfo" #include "flags.nfo" #include "openttdgui.nfo" #include "airport_preview.nfo" #include "chars.nfo" #include "mono.nfo" #include "fix_graphics.nfo" #include "rivers/rapids.nfo" #include "rivers/temperate.nfo" #include "rivers/arctic.nfo" #include "rivers/tropic.nfo" #include "rivers/toyland.nfo" #include "tunnel_portals.nfo" #include "palette.nfo" openttd-1.5.3/media/extra_grf/aqueduct.png0000644000000000000000000000703112627373446017273 0ustar rootrootPNG  IHDRXdmsRGBPLTE 000@@@PPPdddttt4c7UǠO0KjZpF!|q8uȱD 竢EY@UUe5WC |7Sqho;Ab_u ­𬓩J+D D2h~RZ㛖>h-(%0=g/c}pmm&JﱫQxyySp($ f-xǝO׭P(` 8/s\$E39XH˺N*`fe1L}^ZZ8C7 tqax.* A MAj wpk,6\a1॒"g@ Ç;r,:jQ}ڗa0lH U1qHMQǝRRci]H;*PC[an R!UQbFYX/JDieFjJqS>7Ԁ_yI)sv@V"lj\)- oai"lWrB>2 5+K! wXp'B/_n!Bt/޵ͱaҶ~-b.y0 $"'{*bb+>.V"|B#c_]/ K54E1/!\P+Ig7p]q'-iO _n!,BkCe5Hp%:^Njh X남j\{~8&g } $An[ani\ pRocEu WVQw0^D%| ڭ0u7m3 hN -%/nO5·v-8gҶ7߽E&ủ'PmɔOt@\sET7=9t8̍ŝ:wf w_eú(< }QG~:\G%Fm21>D)8|XY&8-7`3m@++&>Lr ȱȱȱȱȱȱȱȾc]#t Wyo͏Z뇺SGE9g7M QjbuY؉ruʷu)G &͑fyg't)j*&RG͑tO56~bS)ZauX:'9V؉%gJ24y?X6XH5W!|qzEV{޼i KtʷujCeaOn@ZەoQC$NFBZ)j%IuʻyArHt ߭p,vaNN?tLC7-::b_$uKNLNyӄ—_njLѲ )ZZ84@|[&L5!|q鼳&0\mS4h )MN.Psh/ʄDZu-:zNQ'|鼟G/ uʻsN,Q'|\D ]U):ohEt7_ʗC' u 鼳=)1:~!:p!)NSԨINK΂k@i)֩t 耩+<}aM.sc'3NÙOG <ᅝopGrH tʱVGG c)o}df)/u8:/ptuoglHidn|.h]7:/xd5:5SiIS̠Nű'IGK[ cMt,QѱHG 4"##"#"#"##"#"#"##"#"#"##"#"#"##"#"#"##"#"#"##"/'%{ [IENDB`openttd-1.5.3/media/extra_grf/signals.nfo0000644000000000000000000007451712627373446017133 0ustar rootroot// // $Id: signals.nfo 23982 2012-02-24 22:29:44Z rubidium $ // // 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 . // -1 * 0 0C "Pre-signal, semaphore, and PBS graphics by Michael Blunck" -1 * 3 05 04 F0 -1 sprites/signals.png 8bpp 66 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 82 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 98 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 114 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 130 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 146 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 162 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 178 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 194 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 210 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 226 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 242 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 258 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 274 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 290 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 306 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 322 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 338 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 354 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 370 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 386 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 402 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 418 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 434 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 450 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 466 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 482 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 498 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 514 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 530 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 546 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 562 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 578 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 594 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 610 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 626 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 642 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 658 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 674 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 690 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 706 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 722 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 738 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 754 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 770 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 786 8 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 2 40 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 18 40 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 34 40 10 21 -6 -19 normal -1 sprites/signals.png 8bpp 50 40 7 23 -3 -21 normal -1 sprites/signals.png 8bpp 66 40 10 21 1 -19 normal -1 sprites/signals.png 8bpp 82 40 9 21 1 -19 normal -1 sprites/signals.png 8bpp 98 40 9 21 1 -19 normal -1 sprites/signals.png 8bpp 114 40 6 23 1 -21 normal -1 sprites/signals.png 8bpp 130 40 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 146 40 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 162 40 2 21 1 -19 normal -1 sprites/signals.png 8bpp 178 40 2 24 1 -22 normal -1 sprites/signals.png 8bpp 194 40 2 23 1 -21 normal -1 sprites/signals.png 8bpp 210 40 2 26 1 -24 normal -1 sprites/signals.png 8bpp 226 40 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 242 40 8 21 -4 -19 normal -1 sprites/signals.png 8bpp 258 40 11 21 1 -19 normal -1 sprites/signals.png 8bpp 274 40 8 21 1 -19 normal -1 sprites/signals.png 8bpp 290 40 12 21 -6 -19 normal -1 sprites/signals.png 8bpp 322 40 9 23 -3 -21 normal -1 sprites/signals.png 8bpp 338 40 12 21 -1 -19 normal -1 sprites/signals.png 8bpp 370 40 11 21 -1 -19 normal -1 sprites/signals.png 8bpp 386 40 11 21 -1 -19 normal -1 sprites/signals.png 8bpp 402 40 8 23 -1 -21 normal -1 sprites/signals.png 8bpp 418 40 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 450 40 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 482 40 4 21 1 -19 normal -1 sprites/signals.png 8bpp 498 40 4 24 1 -22 normal -1 sprites/signals.png 8bpp 514 40 4 23 -1 -21 normal -1 sprites/signals.png 8bpp 530 40 4 26 -1 -24 normal -1 sprites/signals.png 8bpp 546 40 13 21 -7 -19 normal -1 sprites/signals.png 8bpp 578 40 10 21 -4 -19 normal -1 sprites/signals.png 8bpp 594 40 13 21 -1 -19 normal -1 sprites/signals.png 8bpp 626 40 10 21 -1 -19 normal -1 sprites/signals.png 8bpp 642 40 11 21 -6 -19 normal -1 sprites/signals.png 8bpp 658 40 8 23 -3 -21 normal -1 sprites/signals.png 8bpp 674 40 11 21 0 -19 normal -1 sprites/signals.png 8bpp 690 40 10 21 0 -19 normal -1 sprites/signals.png 8bpp 706 40 10 21 0 -19 normal -1 sprites/signals.png 8bpp 722 40 7 23 0 -21 normal -1 sprites/signals.png 8bpp 738 40 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 754 40 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 770 40 4 21 1 -19 normal -1 sprites/signals.png 8bpp 786 40 4 24 1 -22 normal -1 sprites/signals.png 8bpp 2 88 4 23 -1 -21 normal -1 sprites/signals.png 8bpp 18 88 4 26 -1 -24 normal -1 sprites/signals.png 8bpp 34 88 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 66 88 9 21 -4 -19 normal -1 sprites/signals.png 8bpp 82 88 12 21 0 -19 normal -1 sprites/signals.png 8bpp 114 88 9 21 0 -19 normal -1 sprites/signals.png 8bpp 130 88 11 21 -6 -19 normal -1 sprites/signals.png 8bpp 146 88 8 23 -3 -21 normal -1 sprites/signals.png 8bpp 162 88 11 21 0 -19 normal -1 sprites/signals.png 8bpp 178 88 10 21 0 -19 normal -1 sprites/signals.png 8bpp 194 88 10 21 0 -19 normal -1 sprites/signals.png 8bpp 210 88 7 23 0 -21 normal -1 sprites/signals.png 8bpp 226 88 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 242 88 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 258 88 4 21 1 -19 normal -1 sprites/signals.png 8bpp 274 88 4 24 1 -22 normal -1 sprites/signals.png 8bpp 290 88 4 23 -1 -21 normal -1 sprites/signals.png 8bpp 306 88 4 26 -1 -24 normal -1 sprites/signals.png 8bpp 322 88 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 354 88 9 21 -4 -19 normal -1 sprites/signals.png 8bpp 370 88 12 21 0 -19 normal -1 sprites/signals.png 8bpp 402 88 9 21 0 -19 normal -1 sprites/signals.png 8bpp 418 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 434 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 450 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 466 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 482 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 498 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 514 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 530 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 546 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 562 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 578 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 594 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 610 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 626 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 642 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 658 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 674 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 690 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 706 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 722 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 738 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 754 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 770 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 786 88 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 2 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 18 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 34 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 50 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 66 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 82 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 98 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 114 136 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 130 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 146 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 162 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 178 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 194 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 210 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 226 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 242 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 258 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 274 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 290 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 306 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 322 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 338 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 354 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 370 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 386 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 402 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 418 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 434 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 450 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 466 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 482 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 498 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 514 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 530 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 546 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 562 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 578 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 594 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 610 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 626 136 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 642 136 10 21 -6 -19 normal -1 sprites/signals.png 8bpp 658 136 7 23 -3 -21 normal -1 sprites/signals.png 8bpp 674 136 10 21 1 -19 normal -1 sprites/signals.png 8bpp 690 136 9 21 1 -19 normal -1 sprites/signals.png 8bpp 706 136 9 21 1 -19 normal -1 sprites/signals.png 8bpp 722 136 6 23 1 -21 normal -1 sprites/signals.png 8bpp 738 136 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 754 136 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 770 136 2 21 1 -19 normal -1 sprites/signals.png 8bpp 786 136 2 24 1 -22 normal -1 sprites/signals.png 8bpp 2 184 2 23 1 -21 normal -1 sprites/signals.png 8bpp 18 184 2 26 1 -24 normal -1 sprites/signals.png 8bpp 34 184 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 50 184 8 21 -4 -19 normal -1 sprites/signals.png 8bpp 66 184 11 21 1 -19 normal -1 sprites/signals.png 8bpp 82 184 8 21 1 -19 normal -1 sprites/signals.png 8bpp 98 184 12 21 -6 -19 normal -1 sprites/signals.png 8bpp 130 184 9 23 -3 -21 normal -1 sprites/signals.png 8bpp 146 184 12 21 -1 -19 normal -1 sprites/signals.png 8bpp 178 184 11 21 -1 -19 normal -1 sprites/signals.png 8bpp 194 184 11 21 -1 -19 normal -1 sprites/signals.png 8bpp 210 184 8 23 -1 -21 normal -1 sprites/signals.png 8bpp 226 184 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 258 184 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 290 184 4 21 -1 -19 normal -1 sprites/signals.png 8bpp 306 184 4 24 -1 -22 normal -1 sprites/signals.png 8bpp 322 184 4 23 1 -21 normal -1 sprites/signals.png 8bpp 338 184 4 26 1 -24 normal -1 sprites/signals.png 8bpp 354 184 13 21 -7 -19 normal -1 sprites/signals.png 8bpp 386 184 10 21 -4 -19 normal -1 sprites/signals.png 8bpp 402 184 13 21 -1 -19 normal -1 sprites/signals.png 8bpp 434 184 10 21 -1 -19 normal -1 sprites/signals.png 8bpp 450 184 11 21 -6 -19 normal -1 sprites/signals.png 8bpp 466 184 8 23 -3 -21 normal -1 sprites/signals.png 8bpp 482 184 11 21 0 -19 normal -1 sprites/signals.png 8bpp 498 184 10 21 0 -19 normal -1 sprites/signals.png 8bpp 514 184 10 21 0 -19 normal -1 sprites/signals.png 8bpp 530 184 7 23 0 -21 normal -1 sprites/signals.png 8bpp 546 184 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 562 184 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 578 184 4 21 1 -19 normal -1 sprites/signals.png 8bpp 594 184 4 24 1 -22 normal -1 sprites/signals.png 8bpp 610 184 4 23 -1 -21 normal -1 sprites/signals.png 8bpp 626 184 4 26 -1 -24 normal -1 sprites/signals.png 8bpp 642 184 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 674 184 9 21 -4 -19 normal -1 sprites/signals.png 8bpp 690 184 12 21 0 -19 normal -1 sprites/signals.png 8bpp 722 184 9 21 0 -19 normal -1 sprites/signals.png 8bpp 738 184 11 21 -6 -19 normal -1 sprites/signals.png 8bpp 754 184 8 23 -3 -21 normal -1 sprites/signals.png 8bpp 770 184 11 21 0 -19 normal -1 sprites/signals.png 8bpp 786 184 10 21 0 -19 normal -1 sprites/signals.png 8bpp 2 232 10 21 0 -19 normal -1 sprites/signals.png 8bpp 18 232 7 23 0 -21 normal -1 sprites/signals.png 8bpp 34 232 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 50 232 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 66 232 4 21 1 -19 normal -1 sprites/signals.png 8bpp 82 232 4 24 1 -22 normal -1 sprites/signals.png 8bpp 98 232 4 23 -1 -21 normal -1 sprites/signals.png 8bpp 114 232 4 26 -1 -24 normal -1 sprites/signals.png 8bpp 130 232 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 162 232 9 21 -4 -19 normal -1 sprites/signals.png 8bpp 178 232 12 21 0 -19 normal -1 sprites/signals.png 8bpp 210 232 9 21 0 -19 normal -1 * 6 07 85 01 \70 3B F2 -1 * 6 07 86 01 \70 04 F1 -1 * 3 05 04 F0 -1 sprites/signals.png 8bpp 274 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 290 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 306 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 322 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 338 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 354 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 370 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 386 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 402 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 418 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 434 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 450 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 466 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 482 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 498 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 514 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 530 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 546 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 562 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 578 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 594 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 610 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 626 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 642 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 658 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 674 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 690 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 706 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 722 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 738 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 754 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 770 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 786 232 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 2 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 18 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 34 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 50 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 66 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 82 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 98 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 114 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 130 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 146 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 162 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 178 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 194 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 210 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 226 280 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 242 280 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 258 280 10 23 -8 -21 normal -1 sprites/signals.png 8bpp 274 280 10 23 -7 -21 normal -1 sprites/signals.png 8bpp 290 280 7 26 -5 -24 normal -1 sprites/signals.png 8bpp 306 280 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 322 280 10 23 -6 -21 normal -1 sprites/signals.png 8bpp 338 280 10 23 1 -21 normal -1 sprites/signals.png 8bpp 354 280 7 26 2 -24 normal -1 sprites/signals.png 8bpp 370 280 3 23 0 -21 normal -1 sprites/signals.png 8bpp 386 280 3 26 0 -24 normal -1 sprites/signals.png 8bpp 402 280 3 21 0 -19 normal -1 sprites/signals.png 8bpp 418 280 3 24 0 -22 normal -1 sprites/signals.png 8bpp 434 280 12 21 0 -19 normal -1 sprites/signals.png 8bpp 466 280 9 24 0 -22 normal -1 sprites/signals.png 8bpp 482 280 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 514 280 9 24 -6 -22 normal -1 sprites/signals.png 8bpp 530 280 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 562 280 11 23 -9 -21 normal -1 sprites/signals.png 8bpp 578 280 11 23 -7 -21 normal -1 sprites/signals.png 8bpp 594 280 9 26 -5 -24 normal -1 sprites/signals.png 8bpp 610 280 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 642 280 11 23 -6 -21 normal -1 sprites/signals.png 8bpp 658 280 11 23 0 -21 normal -1 sprites/signals.png 8bpp 674 280 9 26 0 -24 normal -1 sprites/signals.png 8bpp 690 280 5 23 0 -21 normal -1 sprites/signals.png 8bpp 706 280 5 26 0 -24 normal -1 sprites/signals.png 8bpp 722 280 5 21 -2 -19 normal -1 sprites/signals.png 8bpp 738 280 5 24 -2 -22 normal -1 sprites/signals.png 8bpp 754 280 13 21 -1 -19 normal -1 sprites/signals.png 8bpp 786 280 10 24 -1 -22 normal -1 sprites/signals.png 8bpp 2 328 13 21 -9 -19 normal -1 sprites/signals.png 8bpp 34 328 10 24 -6 -22 normal -1 sprites/signals.png 8bpp 50 328 11 21 -8 -19 normal -1 sprites/signals.png 8bpp 66 328 10 23 -8 -21 normal -1 sprites/signals.png 8bpp 82 328 10 23 -7 -21 normal -1 sprites/signals.png 8bpp 98 328 8 26 -5 -24 normal -1 sprites/signals.png 8bpp 114 328 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 130 328 10 23 -6 -21 normal -1 sprites/signals.png 8bpp 146 328 10 23 1 -21 normal -1 sprites/signals.png 8bpp 162 328 8 26 1 -24 normal -1 sprites/signals.png 8bpp 178 328 5 23 0 -21 normal -1 sprites/signals.png 8bpp 194 328 5 26 0 -24 normal -1 sprites/signals.png 8bpp 210 328 5 21 -2 -19 normal -1 sprites/signals.png 8bpp 226 328 5 24 -2 -22 normal -1 sprites/signals.png 8bpp 242 328 12 21 0 -19 normal -1 sprites/signals.png 8bpp 274 328 9 24 0 -22 normal -1 sprites/signals.png 8bpp 290 328 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 322 328 9 24 -6 -22 normal -1 sprites/signals.png 8bpp 338 328 11 21 -8 -19 normal -1 sprites/signals.png 8bpp 354 328 10 23 -8 -21 normal -1 sprites/signals.png 8bpp 370 328 10 23 -7 -21 normal -1 sprites/signals.png 8bpp 386 328 8 26 -5 -24 normal -1 sprites/signals.png 8bpp 402 328 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 418 328 10 23 -6 -21 normal -1 sprites/signals.png 8bpp 434 328 10 23 1 -21 normal -1 sprites/signals.png 8bpp 450 328 8 26 1 -24 normal -1 sprites/signals.png 8bpp 466 328 5 23 0 -21 normal -1 sprites/signals.png 8bpp 482 328 5 26 0 -24 normal -1 sprites/signals.png 8bpp 498 328 5 21 -2 -19 normal -1 sprites/signals.png 8bpp 514 328 5 24 -2 -22 normal -1 sprites/signals.png 8bpp 530 328 12 21 0 -19 normal -1 sprites/signals.png 8bpp 562 328 9 24 0 -22 normal -1 sprites/signals.png 8bpp 578 328 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 610 328 9 24 -6 -22 normal -1 sprites/signals.png 8bpp 626 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 642 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 658 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 674 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 690 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 706 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 722 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 738 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 754 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 770 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 786 328 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 2 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 18 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 34 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 50 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 66 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 82 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 98 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 114 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 130 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 146 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 162 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 178 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 194 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 210 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 226 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 242 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 258 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 274 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 290 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 306 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 322 376 6 19 -2 -17 normal -1 sprites/signals.png 8bpp 338 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 354 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 370 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 386 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 402 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 418 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 434 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 450 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 466 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 482 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 498 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 514 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 530 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 546 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 562 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 578 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 594 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 610 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 626 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 642 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 658 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 674 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 690 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 706 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 722 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 738 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 754 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 770 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 786 376 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 2 408 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 18 408 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 34 408 6 21 -2 -19 normal -1 sprites/signals.png 8bpp 50 408 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 66 408 10 23 -8 -21 normal -1 sprites/signals.png 8bpp 82 408 10 23 -7 -21 normal -1 sprites/signals.png 8bpp 98 408 7 26 -5 -24 normal -1 sprites/signals.png 8bpp 114 408 10 21 -7 -19 normal -1 sprites/signals.png 8bpp 130 408 10 23 -6 -21 normal -1 sprites/signals.png 8bpp 146 408 10 23 1 -21 normal -1 sprites/signals.png 8bpp 162 408 7 26 2 -24 normal -1 sprites/signals.png 8bpp 178 408 3 23 0 -21 normal -1 sprites/signals.png 8bpp 194 408 3 26 0 -24 normal -1 sprites/signals.png 8bpp 210 408 3 21 0 -19 normal -1 sprites/signals.png 8bpp 226 408 3 24 0 -22 normal -1 sprites/signals.png 8bpp 242 408 12 21 0 -19 normal -1 sprites/signals.png 8bpp 274 408 9 24 0 -22 normal -1 sprites/signals.png 8bpp 290 408 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 322 408 9 24 -6 -22 normal -1 sprites/signals.png 8bpp 338 408 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 370 408 11 23 -9 -21 normal -1 sprites/signals.png 8bpp 386 408 11 23 -7 -21 normal -1 sprites/signals.png 8bpp 402 408 9 26 -5 -24 normal -1 sprites/signals.png 8bpp 418 408 12 21 -7 -19 normal -1 sprites/signals.png 8bpp 450 408 11 23 -6 -21 normal -1 sprites/signals.png 8bpp 466 408 11 23 0 -21 normal -1 sprites/signals.png 8bpp 482 408 9 26 0 -24 normal -1 sprites/signals.png 8bpp 498 408 5 23 -1 -21 normal -1 sprites/signals.png 8bpp 514 408 5 26 -1 -24 normal -1 sprites/signals.png 8bpp 530 408 5 21 -1 -19 normal -1 sprites/signals.png 8bpp 546 408 5 24 -1 -22 normal -1 sprites/signals.png 8bpp 562 408 13 21 -1 -19 normal -1 sprites/signals.png 8bpp 594 408 10 24 -1 -22 normal -1 sprites/signals.png 8bpp 610 408 13 21 -9 -19 normal -1 sprites/signals.png 8bpp 642 408 10 24 -6 -22 normal -1 sprites/signals.png 8bpp 658 408 11 21 -8 -19 normal -1 sprites/signals.png 8bpp 674 408 10 23 -8 -21 normal -1 sprites/signals.png 8bpp 690 408 10 23 -7 -21 normal -1 sprites/signals.png 8bpp 706 408 8 26 -5 -24 normal -1 sprites/signals.png 8bpp 722 408 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 738 408 10 23 -6 -21 normal -1 sprites/signals.png 8bpp 754 408 10 23 1 -21 normal -1 sprites/signals.png 8bpp 770 408 8 26 1 -24 normal -1 sprites/signals.png 8bpp 786 408 5 23 0 -21 normal -1 sprites/signals.png 8bpp 2 456 5 26 0 -24 normal -1 sprites/signals.png 8bpp 18 456 5 21 -2 -19 normal -1 sprites/signals.png 8bpp 34 456 5 24 -2 -22 normal -1 sprites/signals.png 8bpp 50 456 12 21 0 -19 normal -1 sprites/signals.png 8bpp 82 456 9 24 0 -22 normal -1 sprites/signals.png 8bpp 98 456 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 130 456 9 24 -6 -22 normal -1 sprites/signals.png 8bpp 146 456 11 21 -8 -19 normal -1 sprites/signals.png 8bpp 162 456 10 23 -8 -21 normal -1 sprites/signals.png 8bpp 178 456 10 23 -7 -21 normal -1 sprites/signals.png 8bpp 194 456 8 26 -5 -24 normal -1 sprites/signals.png 8bpp 210 456 11 21 -7 -19 normal -1 sprites/signals.png 8bpp 226 456 10 23 -6 -21 normal -1 sprites/signals.png 8bpp 242 456 10 23 1 -21 normal -1 sprites/signals.png 8bpp 258 456 8 26 1 -24 normal -1 sprites/signals.png 8bpp 274 456 5 23 0 -21 normal -1 sprites/signals.png 8bpp 290 456 5 26 0 -24 normal -1 sprites/signals.png 8bpp 306 456 5 21 -2 -19 normal -1 sprites/signals.png 8bpp 322 456 5 24 -2 -22 normal -1 sprites/signals.png 8bpp 338 456 12 21 0 -19 normal -1 sprites/signals.png 8bpp 370 456 9 24 0 -22 normal -1 sprites/signals.png 8bpp 386 456 12 21 -9 -19 normal -1 sprites/signals.png 8bpp 418 456 9 24 -6 -22 normal openttd-1.5.3/media/extra_grf/2ccmap.nfo0000644000000000000000000062041312627373446016630 0ustar rootroot// // $Id: 2ccmap.nfo 21535 2010-12-18 13:04:05Z frosch $ // // 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 . // // This is the DOS 2CC translation map which OpenTTD translates if needed upon loading. // -1 * 0 0C "2CC map" -1 * 0 05 0A FF 00 01 -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F C6 C7 C8 C9 CA CB CC CD 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 60 61 62 63 64 65 66 67 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 2A 2B 2C 2D 2E 2F 30 31 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 3E 3F 40 41 42 43 44 45 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F B3 B4 B5 B6 B7 A4 A5 A6 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 9A 9B 9C 9D 9E 9F A0 A1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 52 53 54 55 CE CF D0 D1 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 58 59 5A 5B 5C 5D 5E 5F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 92 93 94 95 96 97 98 99 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 72 73 74 75 76 77 78 79 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 80 81 82 83 84 85 86 87 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 88 89 8A 8B 8C 8D 8E 8F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 40 C0 C1 C2 C3 C4 C5 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 20 21 22 23 24 25 26 27 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 04 05 06 07 08 09 0A 0B 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 60 61 62 63 64 65 66 67 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 2A 2B 2C 2D 2E 2F 30 31 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 3E 3F 40 41 42 43 44 45 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 B3 B4 B5 B6 B7 A4 A5 A6 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 9A 9B 9C 9D 9E 9F A0 A1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 52 53 54 55 CE CF D0 D1 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 58 59 5A 5B 5C 5D 5E 5F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 92 93 94 95 96 97 98 99 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 72 73 74 75 76 77 78 79 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 80 81 82 83 84 85 86 87 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 88 89 8A 8B 8C 8D 8E 8F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 40 C0 C1 C2 C3 C4 C5 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 20 21 22 23 24 25 26 27 CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 04 05 06 07 08 09 0A 0B CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF -1 * 0 00 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 08 09 0A 0B 0C 0D 0E 0F 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 08 09 0A 0B 0C 0D 0E 0F CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF openttd-1.5.3/Makefile.setting.in0000644000000000000000000000667112627373446015444 0ustar rootroot# $Id: Makefile.setting.in 26497 2014-04-24 18:09:10Z rubidium $ # 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 . SETTINGSGEN = !!SETTINGSGEN!! ENDIAN_CHECK = !!ENDIAN_CHECK!! SRC_DIR = !!SRC_DIR!! CXX_BUILD = !!CXX_BUILD!! CFLAGS_BUILD = !!CFLAGS_BUILD!! CXXFLAGS_BUILD = !!CXXFLAGS_BUILD!! LDFLAGS_BUILD = !!LDFLAGS_BUILD!! STAGE = !!STAGE!! SETTING_OBJS_DIR = !!SETTING_OBJS_DIR!! ENDIAN_TARGETS := endian_host.h endian_target.h $(ENDIAN_CHECK) # Check if we want to show what we are doing ifdef VERBOSE Q = E = @true else Q = @ E = @echo endif all: table/settings.h settingsgen.o: $(SRC_DIR)/settingsgen/settingsgen.cpp $(SRC_DIR)/string_func.h $(SRC_DIR)/strings_type.h $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/ini_type.h $(SRC_DIR)/core/smallvec_type.hpp $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< alloc_func.o: $(SRC_DIR)/core/alloc_func.cpp endian_host.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< getoptdata.o: $(SRC_DIR)/misc/getoptdata.cpp $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/misc/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< string.o: $(SRC_DIR)/string.cpp endian_host.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< ini_load.o: $(SRC_DIR)/ini_load.cpp $(SRC_DIR)/core/alloc_func.hpp $(SRC_DIR)/core/mem_func.hpp $(SRC_DIR)/ini_type.h $(SRC_DIR)/string_func.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSETTINGSGEN -c -o $@ $< $(SETTINGSGEN): alloc_func.o string.o ini_load.o settingsgen.o getoptdata.o $(E) '$(STAGE) Compiling and Linking $@' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $^ -o $@ table/settings.h: $(SETTINGSGEN) $(SRC_DIR)/table/settings.h.preamble $(SRC_DIR)/table/settings.h.postamble $(SRC_DIR)/table/*.ini $(E) '$(STAGE) Generating $@' @mkdir -p table $(Q)./$(SETTINGSGEN) -o table/settings.h -b $(SRC_DIR)/table/settings.h.preamble -a $(SRC_DIR)/table/settings.h.postamble $(SRC_DIR)/table/*.ini # The targets to compile the endian-code endian_host.h: $(ENDIAN_CHECK) $(E) '$(STAGE) Testing endianness for host' $(Q)./$(ENDIAN_CHECK) > $@ $(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp $(E) '$(STAGE) Compiling and Linking $@' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ depend: clean: $(E) '$(STAGE) Cleaning up settings files' $(Q)rm -f settingsgen.o alloc_func.o getoptdata.o ini_load.o $(SETTINGSGEN) $(ENDIAN_TARGETS) table/settings.h mrproper: clean .PHONY: all mrproper depend clean openttd-1.5.3/Makefile.bundle.in0000644000000000000000000002537612627373446015243 0ustar rootroot# $Id: Makefile.bundle.in 27430 2015-11-01 11:55:45Z frosch $ # 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 . # # Creation of bundles # # The revision is needed for the bundle name and creating an OSX application bundle. # Detect the revision VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh") REV := $(shell echo "$(VERSIONS)" | cut -f 1 -d' ') # Make sure we have something in REV ifeq ($(REV),) REV := norev000 endif ifndef BUNDLE_NAME BUNDLE_NAME = openttd-custom-$(REV)-$(OS) endif # An OSX application bundle needs the data files, lang files and openttd executable in a different location. ifdef OSXAPP AI_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/ai GAME_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/game BASESET_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/baseset LANG_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/lang TTD_DIR = $(BUNDLE_DIR)/$(OSXAPP)/Contents/MacOS else AI_DIR = $(BUNDLE_DIR)/ai GAME_DIR = $(BUNDLE_DIR)/game BASESET_DIR = $(BUNDLE_DIR)/baseset LANG_DIR = $(BUNDLE_DIR)/lang TTD_DIR = $(BUNDLE_DIR) endif bundle: all @echo '[BUNDLE] Constructing bundle' $(Q)rm -rf "$(BUNDLE_DIR)" $(Q)mkdir -p "$(BUNDLE_DIR)" $(Q)mkdir -p "$(BUNDLE_DIR)/docs" $(Q)mkdir -p "$(BUNDLE_DIR)/media" $(Q)mkdir -p "$(BUNDLE_DIR)/scripts" $(Q)mkdir -p "$(TTD_DIR)" $(Q)mkdir -p "$(AI_DIR)" $(Q)mkdir -p "$(GAME_DIR)" $(Q)mkdir -p "$(BASESET_DIR)" $(Q)mkdir -p "$(LANG_DIR)" ifdef OSXAPP $(Q)mkdir -p "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources" $(Q)echo "APPL????" > "$(BUNDLE_DIR)/$(OSXAPP)/Contents/PkgInfo" $(Q)cp "$(ROOT_DIR)/os/macosx/openttd.icns" "$(BUNDLE_DIR)/$(OSXAPP)/Contents/Resources/openttd.icns" $(Q)$(ROOT_DIR)/os/macosx/plistgen.sh "$(BUNDLE_DIR)/$(OSXAPP)" "$(REV)" $(Q)cp "$(ROOT_DIR)/os/macosx/splash.png" "$(BASESET_DIR)" endif ifeq ($(OS),UNIX) $(Q)cp "$(ROOT_DIR)/media/openttd.32.bmp" "$(BASESET_DIR)/" endif $(Q)cp "$(BIN_DIR)/$(TTD)" "$(TTD_DIR)/" $(Q)cp "$(BIN_DIR)/ai/"compat_*.nut "$(AI_DIR)/" $(Q)cp "$(BIN_DIR)/game/"compat_*.nut "$(GAME_DIR)/" $(Q)cp "$(BIN_DIR)/baseset/"*.grf "$(BASESET_DIR)/" $(Q)cp "$(BIN_DIR)/baseset/"*.obg "$(BASESET_DIR)/" $(Q)cp "$(BIN_DIR)/baseset/"*.obs "$(BASESET_DIR)/" $(Q)cp "$(BIN_DIR)/baseset/opntitle.dat" "$(BASESET_DIR)/" $(Q)cp "$(BIN_DIR)/baseset/"*.obm "$(BASESET_DIR)/" $(Q)cp "$(BIN_DIR)/lang/"*.lng "$(LANG_DIR)/" $(Q)cp "$(ROOT_DIR)/readme.txt" "$(BUNDLE_DIR)/" $(Q)cp "$(ROOT_DIR)/COPYING" "$(BUNDLE_DIR)/" $(Q)cp "$(ROOT_DIR)/known-bugs.txt" "$(BUNDLE_DIR)/" $(Q)cp "$(ROOT_DIR)/docs/multiplayer.txt" "$(BUNDLE_DIR)/docs/" $(Q)cp "$(ROOT_DIR)/changelog.txt" "$(BUNDLE_DIR)/" ifdef MAN_DIR $(Q)mkdir -p "$(BUNDLE_DIR)/man/" $(Q)cp "$(ROOT_DIR)/docs/openttd.6" "$(BUNDLE_DIR)/man/" $(Q)gzip -9 "$(BUNDLE_DIR)/man/openttd.6" endif $(Q)cp "$(ROOT_DIR)/media/openttd.32.xpm" "$(BUNDLE_DIR)/media/" $(Q)cp "$(ROOT_DIR)/media/openttd."*.png "$(BUNDLE_DIR)/media/" $(Q)cp "$(BIN_DIR)/scripts/"* "$(BUNDLE_DIR)/scripts/" ifdef MENU_DIR $(Q)cp "$(ROOT_DIR)/media/openttd.desktop" "$(BUNDLE_DIR)/media/" $(Q)$(AWK) -f "$(ROOT_DIR)/media/openttd.desktop.translation.awk" "$(SRC_DIR)/lang/"*.txt | $(SORT) | $(AWK) -f "$(ROOT_DIR)/media/openttd.desktop.filter.awk" >> "$(BUNDLE_DIR)/media/openttd.desktop" $(Q)sed s/=openttd/=$(BINARY_NAME)/g "$(BUNDLE_DIR)/media/openttd.desktop" > "$(ROOT_DIR)/media/openttd.desktop.install" endif ifeq ($(TTD), openttd.exe) $(Q)unix2dos "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/COPYING" "$(BUNDLE_DIR)/changelog.txt" "$(BUNDLE_DIR)/known-bugs.txt" ifeq ($(OS), DOS) $(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi/cwsdpmi.txt" "$(BUNDLE_DIR)/docs/" ifndef STRIP $(Q)cp "$(ROOT_DIR)/os/dos/cwsdpmi/cwsdpmi.exe" "$(TTD_DIR)/" endif endif endif ### Packing the current bundle into several compressed file formats ### # # Zips & dmgs do not contain a root folder, i.e. they have files in the root of the zip/dmg. # gzip, bzip2 and lha archives have a root folder, with the same name as the bundle. # # One can supply a custom name by adding BUNDLE_NAME:= to the make command. # bundle_zip: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).zip' $(Q)mkdir -p "$(BUNDLES_DIR)" $(Q)cd "$(BUNDLE_DIR)" && zip -r $(shell if test -z "$(VERBOSE)"; then echo '-q'; fi) "$(BUNDLES_DIR)/$(BUNDLE_NAME).zip" . bundle_7z: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).7z' $(Q)mkdir -p "$(BUNDLES_DIR)" $(Q)cd "$(BUNDLE_DIR)" && 7z a "$(BUNDLES_DIR)/$(BUNDLE_NAME).7z" . bundle_gzip: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.gz' $(Q)mkdir -p "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)" $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.gzip/$(BUNDLE_NAME)/" $(Q)cd "$(BUNDLES_DIR)/.gzip" && tar -zc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.gz" "$(BUNDLE_NAME)" $(Q)rm -rf "$(BUNDLES_DIR)/.gzip" bundle_bzip2: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.bz2' $(Q)mkdir -p "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)" $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.bzip2/$(BUNDLE_NAME)/" $(Q)cd "$(BUNDLES_DIR)/.bzip2" && tar -jc$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.bz2" "$(BUNDLE_NAME)" $(Q)rm -rf "$(BUNDLES_DIR)/.bzip2" bundle_lzma: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.lzma' $(Q)mkdir -p "$(BUNDLES_DIR)/.lzma/$(BUNDLE_NAME)" $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lzma/$(BUNDLE_NAME)/" $(Q)cd "$(BUNDLES_DIR)/.lzma" && tar --lzma -c$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.lzma" "$(BUNDLE_NAME)" $(Q)rm -rf "$(BUNDLES_DIR)/.lzma" bundle_xz: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).tar.xz' $(Q)mkdir -p "$(BUNDLES_DIR)/.xz/$(BUNDLE_NAME)" $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.xz/$(BUNDLE_NAME)/" $(Q)cd "$(BUNDLES_DIR)/.xz" && tar --xz -c$(shell if test -n "$(VERBOSE)"; then echo 'v'; fi)f "$(BUNDLES_DIR)/$(BUNDLE_NAME).tar.xz" "$(BUNDLE_NAME)" $(Q)rm -rf "$(BUNDLES_DIR)/.xz" bundle_lha: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).lha' $(Q)mkdir -p "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)" $(Q)cp -R "$(BUNDLE_DIR)/"* "$(BUNDLES_DIR)/.lha/$(BUNDLE_NAME)/" $(Q)cd "$(BUNDLES_DIR)/.lha" && lha ao6 "$(BUNDLES_DIR)/$(BUNDLE_NAME).lha" "$(BUNDLE_NAME)" $(Q)rm -rf "$(BUNDLES_DIR)/.lha" bundle_dmg: bundle @echo '[BUNDLE] Creating $(BUNDLE_NAME).dmg' $(Q)mkdir -p "$(BUNDLES_DIR)/OpenTTD $(REV)" $(Q)cp -R "$(BUNDLE_DIR)/" "$(BUNDLES_DIR)/OpenTTD $(REV)" $(Q)hdiutil create -ov -format UDZO -srcfolder "$(BUNDLES_DIR)/OpenTTD $(REV)" "$(BUNDLES_DIR)/$(BUNDLE_NAME).dmg" $(Q)rm -fr "$(BUNDLES_DIR)/OpenTTD $(REV)" bundle_exe: all @echo '[BUNDLE] Creating $(BUNDLE_NAME).exe' $(Q)mkdir -p "$(BUNDLES_DIR)" $(Q)unix2dos "$(ROOT_DIR)/docs/"*.txt "$(ROOT_DIR)/readme.txt" "$(ROOT_DIR)/COPYING" "$(ROOT_DIR)/changelog.txt" "$(ROOT_DIR)/known-bugs.txt" $(Q)cd $(ROOT_DIR)/os/windows/installer && makensis.exe //DVERSION_INCLUDE=version_$(PLATFORM).txt install.nsi $(Q)mv $(ROOT_DIR)/os/windows/installer/*$(PLATFORM).exe "$(BUNDLES_DIR)/$(BUNDLE_NAME).exe" ifdef OSXAPP install: @echo '[INSTALL] Cannot install the OSX Application Bundle' else install: bundle @echo '[INSTALL] Installing OpenTTD' $(Q)install -d "$(INSTALL_BINARY_DIR)" $(Q)install -d "$(INSTALL_ICON_DIR)" $(Q)install -d "$(INSTALL_DATA_DIR)/ai" $(Q)install -d "$(INSTALL_DATA_DIR)/game" $(Q)install -d "$(INSTALL_DATA_DIR)/baseset" $(Q)install -d "$(INSTALL_DATA_DIR)/lang" $(Q)install -d "$(INSTALL_DATA_DIR)/scripts" ifeq ($(TTD), openttd.exe) $(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}.exe" else $(Q)install -m 755 "$(BUNDLE_DIR)/$(TTD)" "$(INSTALL_BINARY_DIR)/${BINARY_NAME}" endif $(Q)install -m 644 "$(BUNDLE_DIR)/lang/"* "$(INSTALL_DATA_DIR)/lang" $(Q)install -m 644 "$(BUNDLE_DIR)/ai/"* "$(INSTALL_DATA_DIR)/ai" $(Q)install -m 644 "$(BUNDLE_DIR)/game/"* "$(INSTALL_DATA_DIR)/game" $(Q)install -m 644 "$(BUNDLE_DIR)/baseset/"* "$(INSTALL_DATA_DIR)/baseset" $(Q)install -m 644 "$(BUNDLE_DIR)/scripts/"* "$(INSTALL_DATA_DIR)/scripts" ifndef DO_NOT_INSTALL_DOCS $(Q)install -d "$(INSTALL_DOC_DIR)" $(Q)install -m 644 "$(BUNDLE_DIR)/docs/"* "$(BUNDLE_DIR)/readme.txt" "$(BUNDLE_DIR)/known-bugs.txt" "$(INSTALL_DOC_DIR)" endif ifndef DO_NOT_INSTALL_CHANGELOG $(Q)install -d "$(INSTALL_DOC_DIR)" $(Q)install -m 644 "$(BUNDLE_DIR)/changelog.txt" "$(INSTALL_DOC_DIR)" endif ifndef DO_NOT_INSTALL_LICENSE $(Q)install -d "$(INSTALL_DOC_DIR)" $(Q)install -m 644 "$(BUNDLE_DIR)/COPYING" "$(INSTALL_DOC_DIR)" endif $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.xpm" "$(INSTALL_ICON_DIR)/${BINARY_NAME}.32.xpm" ifdef ICON_THEME_DIR $(Q)install -d "$(INSTALL_ICON_THEME_DIR)" $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/16x16/apps" $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.16.png" "$(INSTALL_ICON_THEME_DIR)/16x16/apps/${BINARY_NAME}.png" $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/32x32/apps" $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.32.png" "$(INSTALL_ICON_THEME_DIR)/32x32/apps/${BINARY_NAME}.png" $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/48x48/apps" $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.48.png" "$(INSTALL_ICON_THEME_DIR)/48x48/apps/${BINARY_NAME}.png" $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/64x64/apps" $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.64.png" "$(INSTALL_ICON_THEME_DIR)/64x64/apps/${BINARY_NAME}.png" $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/128x128/apps" $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.128.png" "$(INSTALL_ICON_THEME_DIR)/128x128/apps/${BINARY_NAME}.png" $(Q)install -d "$(INSTALL_ICON_THEME_DIR)/256x256/apps" $(Q)install -m 644 "$(BUNDLE_DIR)/media/openttd.256.png" "$(INSTALL_ICON_THEME_DIR)/256x256/apps/${BINARY_NAME}.png" else $(Q)install -m 644 "$(BUNDLE_DIR)/media/"*.png "$(INSTALL_ICON_DIR)" endif ifdef MAN_DIR ifndef DO_NOT_INSTALL_MAN $(Q)install -d "$(INSTALL_MAN_DIR)" $(Q)install -m 644 "$(BUNDLE_DIR)/man/openttd.6.gz" "$(INSTALL_MAN_DIR)/${BINARY_NAME}.6.gz" endif endif ifdef MENU_DIR $(Q)install -d "$(INSTALL_MENU_DIR)" $(Q)install -m 644 "$(ROOT_DIR)/media/openttd.desktop.install" "$(INSTALL_MENU_DIR)/${BINARY_NAME}.desktop" endif endif # OSXAPP openttd-1.5.3/COPYING0000644000000000000000000004344412627373446012755 0ustar rootrootThis is the license which applies to OpenTTD with the exception of some 3rd party modules. See readme.txt for details GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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; either version 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. openttd-1.5.3/Makefile.lang.in0000644000000000000000000001011012627373446014667 0ustar rootroot# $Id: Makefile.lang.in 26497 2014-04-24 18:09:10Z rubidium $ # 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 . STRGEN = !!STRGEN!! ENDIAN_CHECK = !!ENDIAN_CHECK!! SRC_DIR = !!SRC_DIR!! LANG_DIR = !!LANG_DIR!! BIN_DIR = !!BIN_DIR!! LANGS_SRC = $(shell ls $(LANG_DIR)/*.txt) LANGS = $(LANGS_SRC:$(LANG_DIR)/%.txt=%.lng) CXX_BUILD = !!CXX_BUILD!! CFLAGS_BUILD = !!CFLAGS_BUILD!! CXXFLAGS_BUILD= !!CXXFLAGS_BUILD!! LDFLAGS_BUILD = !!LDFLAGS_BUILD!! STRGEN_FLAGS = !!STRGEN_FLAGS!! STAGE = !!STAGE!! LANG_SUPPRESS = !!LANG_SUPPRESS!! LANG_OBJS_DIR = !!LANG_OBJS_DIR!! ifeq ($(LANG_SUPPRESS), yes) LANG_ERRORS = >/dev/null 2>&1 endif # Make sure endian_host.h is reachable as if it was in the src/ dir CFLAGS_BUILD += -I $(LANG_OBJS_DIR) ENDIAN_TARGETS := endian_host.h endian_target.h $(ENDIAN_CHECK) # Check if we want to show what we are doing ifdef VERBOSE Q = E = @true else Q = @ E = @echo endif RES := $(shell mkdir -p $(BIN_DIR)/lang ) all: table/strings.h $(LANGS) strgen_base.o: $(SRC_DIR)/strgen/strgen_base.cpp $(SRC_DIR)/strgen/strgen.h endian_host.h $(SRC_DIR)/table/control_codes.h $(SRC_DIR)/table/strgen_tables.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< strgen.o: $(SRC_DIR)/strgen/strgen.cpp $(SRC_DIR)/strgen/strgen.h endian_host.h $(SRC_DIR)/table/control_codes.h $(SRC_DIR)/table/strgen_tables.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< string.o: $(SRC_DIR)/string.cpp endian_host.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< alloc_func.o: $(SRC_DIR)/core/alloc_func.cpp endian_host.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< getoptdata.o: $(SRC_DIR)/misc/getoptdata.cpp $(SRC_DIR)/misc/getoptdata.h $(SRC_DIR)/safeguards.h $(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/misc/%.cpp=%.cpp)' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) -DSTRGEN -c -o $@ $< lang/english.txt: $(LANG_DIR)/english.txt $(Q)mkdir -p lang $(Q)cp $(LANG_DIR)/english.txt lang/english.txt $(STRGEN): alloc_func.o string.o strgen_base.o strgen.o getoptdata.o $(E) '$(STAGE) Compiling and Linking $@' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $^ -o $@ table/strings.h: lang/english.txt $(STRGEN) $(E) '$(STAGE) Generating $@' @mkdir -p table $(Q)./$(STRGEN) -s $(LANG_DIR) -d table $(LANGS): %.lng: $(LANG_DIR)/%.txt $(STRGEN) lang/english.txt $(E) '$(STAGE) Compiling language $(*F)' $(Q)./$(STRGEN) $(STRGEN_FLAGS) -s $(LANG_DIR) -d $(LANG_OBJS_DIR) $< $(LANG_ERRORS) && cp $@ $(BIN_DIR)/lang || true # Do not fail all languages when one fails # The targets to compile the endian-code endian_host.h: $(ENDIAN_CHECK) $(E) '$(STAGE) Testing endianness for host' $(Q)./$(ENDIAN_CHECK) > $@ $(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp $(E) '$(STAGE) Compiling and Linking $@' $(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) $< -o $@ depend: clean: $(E) '$(STAGE) Cleaning up language files' $(Q)rm -f strgen.o string.o alloc_func.o getoptdata.o table/strings.h $(STRGEN) $(LANGS) $(LANGS:%=$(BIN_DIR)/lang/%) lang/english.* $(ENDIAN_TARGETS) mrproper: clean $(Q)rm -rf $(BIN_DIR)/lang %.lng: @echo '$(STAGE) No such language: $(@:%.lng=%)' .PHONY: all mrproper depend clean openttd-1.5.3/src/0000755000000000000000000000000012627373446012500 5ustar rootrootopenttd-1.5.3/src/goal_gui.cpp0000644000000000000000000003635512627373445015005 0ustar rootroot/* $Id: goal_gui.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 goal_gui.cpp GUI for goals. */ #include "stdafx.h" #include "industry.h" #include "town.h" #include "window_gui.h" #include "strings_func.h" #include "date_func.h" #include "viewport_func.h" #include "gui.h" #include "goal_base.h" #include "core/geometry_func.hpp" #include "company_func.h" #include "company_base.h" #include "story_base.h" #include "command_func.h" #include "string_func.h" #include "widgets/goal_widget.h" #include "table/strings.h" #include "safeguards.h" /** Goal list columns. */ enum GoalColumn { GC_GOAL = 0, ///< Goal text column. GC_PROGRESS, ///< Goal progress column. }; /** Window for displaying goals. */ struct GoalListWindow : public Window { Scrollbar *vscroll; ///< Reference to the scrollbar widget. GoalListWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_GOAL_SCROLLBAR); this->FinishInitNested(window_number); this->owner = (Owner)this->window_number; this->OnInvalidateData(0); } /* virtual */ void SetStringParameters(int widget) const { if (widget != WID_GOAL_CAPTION) return; if (this->window_number == INVALID_COMPANY) { SetDParam(0, STR_GOALS_SPECTATOR_CAPTION); } else { SetDParam(0, STR_GOALS_CAPTION); SetDParam(1, this->window_number); } } /* virtual */ void OnClick(Point pt, int widget, int click_count) { if (widget != WID_GOAL_LIST) return; int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GOAL_LIST, WD_FRAMERECT_TOP); int num = 0; const Goal *s; FOR_ALL_GOALS(s) { if (s->company == INVALID_COMPANY) { y--; if (y == 0) { this->HandleClick(s); return; } num++; } } if (num == 0) { y--; // "None" line. if (y < 0) return; } y -= 2; // "Company specific goals:" line. if (y < 0) return; FOR_ALL_GOALS(s) { if (s->company == this->window_number) { y--; if (y == 0) { this->HandleClick(s); return; } } } } /** * Handle clicking at a goal. * @param s @Goal clicked at. */ void HandleClick(const Goal *s) { /* Determine dst coordinate for goal and try to scroll to it. */ TileIndex xy; switch (s->type) { case GT_NONE: return; case GT_COMPANY: return; case GT_TILE: if (!IsValidTile(s->dst)) return; xy = s->dst; break; case GT_INDUSTRY: if (!Industry::IsValidID(s->dst)) return; xy = Industry::Get(s->dst)->location.tile; break; case GT_TOWN: if (!Town::IsValidID(s->dst)) return; xy = Town::Get(s->dst)->xy; break; case GT_STORY_PAGE: { if (!StoryPage::IsValidID(s->dst)) return; /* Verify that: * - if global goal: story page must be global. * - if company goal: story page must be global or of the same company. */ CompanyID goal_company = s->company; CompanyID story_company = StoryPage::Get(s->dst)->company; if (goal_company == INVALID_COMPANY ? story_company != INVALID_COMPANY : story_company != INVALID_COMPANY && story_company != goal_company) return; ShowStoryBook((CompanyID)this->window_number, s->dst); return; } default: NOT_REACHED(); } if (_ctrl_pressed) { ShowExtraViewPortWindow(xy); } else { ScrollMainWindowToTile(xy); } } /** * Count the number of lines in this window. * @return the number of lines. */ uint CountLines() { /* Count number of (non) awarded goals. */ uint num_global = 0; uint num_company = 0; const Goal *s; FOR_ALL_GOALS(s) { if (s->company == INVALID_COMPANY) { num_global++; } else if (s->company == this->window_number) { num_company++; } } /* Count the 'none' lines. */ if (num_global == 0) num_global = 1; if (num_company == 0) num_company = 1; /* Global, company and an empty line before the accepted ones. */ return 3 + num_global + num_company; } /* virtual */ void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_GOAL_LIST) return; Dimension d = maxdim(GetStringBoundingBox(STR_GOALS_GLOBAL_TITLE), GetStringBoundingBox(STR_GOALS_COMPANY_TITLE)); resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); } /** * Draws either the global goals or the company goal section. * This is a helper method for #DrawWidget. * @param pos [inout] Vertical line number to draw. * @param cap Number of lines to draw in the window. * @param x Left edge of the text line to draw. * @param y Vertical position of the top edge of the window. * @param right Right edge of the text line to draw. * @param global_section Whether the global goals are printed. * @param column Which column to draw. */ void DrawPartialGoalList(int &pos, const int cap, int x, int y, int right, uint progress_col_width, bool global_section, GoalColumn column) const { if (column == GC_GOAL && IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, global_section ? STR_GOALS_GLOBAL_TITLE : STR_GOALS_COMPANY_TITLE); pos++; bool rtl = _current_text_dir == TD_RTL; uint num = 0; const Goal *s; FOR_ALL_GOALS(s) { if (global_section ? s->company == INVALID_COMPANY : (s->company == this->window_number && s->company != INVALID_COMPANY)) { if (IsInsideMM(pos, 0, cap)) { switch (column) { case GC_GOAL: { /* Display the goal. */ SetDParamStr(0, s->text); uint width_reduction = progress_col_width > 0 ? progress_col_width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT : 0; DrawString(x + (rtl ? width_reduction : 0), right - (rtl ? 0 : width_reduction), y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_TEXT); break; } case GC_PROGRESS: if (s->progress != NULL) { SetDParamStr(0, s->progress); StringID str = s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS; int progress_x = x; int progress_right = rtl ? x + progress_col_width : right; DrawString(progress_x, progress_right, y + pos * FONT_HEIGHT_NORMAL, str, TC_FROMSTRING, SA_RIGHT | SA_FORCE); } break; } } pos++; num++; } } if (num == 0) { if (column == GC_GOAL && IsInsideMM(pos, 0, cap)) { StringID str = !global_section && this->window_number == INVALID_COMPANY ? STR_GOALS_SPECTATOR_NONE : STR_GOALS_NONE; DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, str); } pos++; } } /** * Draws a given column of the goal list. * @param column Which column to draw. * @wid Pointer to the goal list widget. * @progress_col_width Width of the progress column. * @return max width of drawn text */ void DrawListColumn(GoalColumn column, NWidgetBase *wid, uint progress_col_width) const { /* Get column draw area. */ int y = wid->pos_y + WD_FRAMERECT_TOP; int x = wid->pos_x + WD_FRAMERECT_LEFT; int right = x + wid->current_x - WD_FRAMERECT_RIGHT; int pos = -this->vscroll->GetPosition(); const int cap = this->vscroll->GetCapacity(); /* Draw partial list with global goals. */ DrawPartialGoalList(pos, cap, x, y, right, progress_col_width, true, column); /* Draw partial list with company goals. */ pos++; DrawPartialGoalList(pos, cap, x, y, right, progress_col_width, false, column); } /* virtual */ void OnPaint() { this->DrawWidgets(); if (this->IsShaded()) return; // Don't draw anything when the window is shaded. /* Calculate progress column width. */ uint max_width = 0; Goal *s; FOR_ALL_GOALS(s) { if (s->progress != NULL) { SetDParamStr(0, s->progress); StringID str = s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS; uint str_width = GetStringBoundingBox(str).width; if (str_width > max_width) max_width = str_width; } } NWidgetBase *wid = this->GetWidget(WID_GOAL_LIST); uint progress_col_width = min(max_width, wid->current_x); /* Draw goal list. */ this->DrawListColumn(GC_PROGRESS, wid, progress_col_width); this->DrawListColumn(GC_GOAL, wid, progress_col_width); } /* virtual */ void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_GOAL_LIST); } /** * 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->vscroll->SetCount(this->CountLines()); this->SetWidgetDirty(WID_GOAL_LIST); } }; /** Widgets of the #GoalListWindow. */ static const NWidgetPart _nested_goals_list_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_GOAL_CAPTION), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN), SetDataTip(0x0, STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetScrollbar(WID_GOAL_SCROLLBAR), NWidget(WWT_EMPTY, COLOUR_GREY, WID_GOAL_LIST), SetResize(1, 1), SetMinimalTextLines(2, 0), SetFill(1, 1), SetPadding(WD_FRAMERECT_TOP, 2, WD_FRAMETEXT_BOTTOM, 2), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_GOAL_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), }; static WindowDesc _goals_list_desc( WDP_AUTO, "list_goals", 500, 127, WC_GOALS_LIST, WC_NONE, 0, _nested_goals_list_widgets, lengthof(_nested_goals_list_widgets) ); /** * Open a goal list window. * @param company %Company to display the goals for, use #INVALID_COMPANY to display global goals. */ void ShowGoalsList(CompanyID company) { if (!Company::IsValidID(company)) company = (CompanyID)INVALID_COMPANY; AllocateWindowDescFront(&_goals_list_desc, company); } /** Ask a question about a goal. */ struct GoalQuestionWindow : public Window { char *question; ///< Question to ask (private copy). int buttons; ///< Number of valid buttons in #button. int button[3]; ///< Buttons to display. byte type; ///< Type of question. GoalQuestionWindow(WindowDesc *desc, WindowNumber window_number, byte type, uint32 button_mask, const char *question) : Window(desc), type(type) { assert(type < GOAL_QUESTION_TYPE_COUNT); this->question = stredup(question); /* Figure out which buttons we have to enable. */ uint bit; int n = 0; FOR_EACH_SET_BIT(bit, button_mask) { if (bit >= GOAL_QUESTION_BUTTON_COUNT) break; this->button[n++] = bit; if (n == 3) break; } this->buttons = n; assert(this->buttons > 0 && this->buttons < 4); this->CreateNestedTree(); this->GetWidget(WID_GQ_BUTTONS)->SetDisplayedPlane(this->buttons - 1); this->FinishInitNested(window_number); } ~GoalQuestionWindow() { free(this->question); } /* virtual */ void SetStringParameters(int widget) const { switch (widget) { case WID_GQ_CAPTION: SetDParam(0, STR_GOAL_QUESTION_CAPTION_QUESTION + this->type); break; case WID_GQ_BUTTON_1: SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[0]); break; case WID_GQ_BUTTON_2: SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[1]); break; case WID_GQ_BUTTON_3: SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[2]); break; } } /* virtual */ void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_GQ_BUTTON_1: DoCommandP(0, this->window_number, this->button[0], CMD_GOAL_QUESTION_ANSWER); delete this; break; case WID_GQ_BUTTON_2: DoCommandP(0, this->window_number, this->button[1], CMD_GOAL_QUESTION_ANSWER); delete this; break; case WID_GQ_BUTTON_3: DoCommandP(0, this->window_number, this->button[2], CMD_GOAL_QUESTION_ANSWER); delete this; break; } } /* virtual */ void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_GQ_QUESTION) return; SetDParamStr(0, this->question); size->height = GetStringHeight(STR_JUST_RAW_STRING, size->width) + WD_PAR_VSEP_WIDE; } /* virtual */ void DrawWidget(const Rect &r, int widget) const { if (widget != WID_GQ_QUESTION) return; SetDParamStr(0, this->question); DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_HOR_CENTER); } }; /** Widgets of the goal question window. */ static const NWidgetPart _nested_goal_question_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_GQ_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GQ_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GQ_BUTTONS), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(65, 10, 65), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(25, 10, 25), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_3), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 8), EndContainer(), }; static WindowDesc _goal_question_list_desc( WDP_CENTER, NULL, 0, 0, WC_GOAL_QUESTION, WC_NONE, WDF_CONSTRUCTION, _nested_goal_question_widgets, lengthof(_nested_goal_question_widgets) ); /** * Display a goal question. * @param id Window number to use. * @param type Type of question. * @param button_mask Buttons to display. * @param question Question to ask. */ void ShowGoalQuestion(uint16 id, byte type, uint32 button_mask, const char *question) { new GoalQuestionWindow(&_goal_question_list_desc, id, type, button_mask, question); } openttd-1.5.3/src/spriteloader/0000755000000000000000000000000012627373435015173 5ustar rootrootopenttd-1.5.3/src/spriteloader/grf.hpp0000644000000000000000000000220512627373435016461 0ustar rootroot/* $Id: grf.hpp 23897 2012-02-04 22:18:57Z michi_cc $ */ /* * 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 grf.hpp Base for reading sprites from (New)GRFs. */ #ifndef SPRITELOADER_GRF_HPP #define SPRITELOADER_GRF_HPP #include "spriteloader.hpp" /** Sprite loader for graphics coming from a (New)GRF. */ class SpriteLoaderGrf : public SpriteLoader { byte container_ver; public: SpriteLoaderGrf(byte container_ver) : container_ver(container_ver) {} uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp); }; #endif /* SPRITELOADER_GRF_HPP */ openttd-1.5.3/src/spriteloader/grf.cpp0000644000000000000000000002723512627373435016466 0ustar rootroot/* $Id: grf.cpp 27004 2014-10-12 20:43:25Z peter1138 $ */ /* * 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 grf.cpp Reading graphics data from (New)GRF files. */ #include "../stdafx.h" #include "../gfx_func.h" #include "../fileio_func.h" #include "../debug.h" #include "../strings_func.h" #include "table/strings.h" #include "../error.h" #include "../core/math_func.hpp" #include "../core/alloc_type.hpp" #include "../core/bitmath_func.hpp" #include "grf.hpp" #include "../safeguards.h" extern const byte _palmap_w2d[]; /** The different colour components a sprite can have. */ enum SpriteColourComponent { SCC_RGB = 1 << 0, ///< Sprite has RGB. SCC_ALPHA = 1 << 1, ///< Sprite has alpha. SCC_PAL = 1 << 2, ///< Sprite has palette data. SCC_MASK = SCC_RGB | SCC_ALPHA | SCC_PAL, ///< Mask of valid colour bits. }; DECLARE_ENUM_AS_BIT_SET(SpriteColourComponent) /** * We found a corrupted sprite. This means that the sprite itself * contains invalid data or is too small for the given dimensions. * @param file_slot the file the errored sprite is in * @param file_pos the location in the file of the errored sprite * @param line the line where the error occurs. * @return always false (to tell loading the sprite failed) */ static bool WarnCorruptSprite(uint8 file_slot, size_t file_pos, int line) { static byte warning_level = 0; if (warning_level == 0) { SetDParamStr(0, FioGetFilename(file_slot)); ShowErrorMessage(STR_NEWGRF_ERROR_CORRUPT_SPRITE, INVALID_STRING_ID, WL_ERROR); } DEBUG(sprite, warning_level, "[%i] Loading corrupted sprite from %s at position %i", line, FioGetFilename(file_slot), (int)file_pos); warning_level = 6; return false; } /** * Decode the image data of a single sprite. * @param[in,out] sprite Filled with the sprite image data. * @param file_slot File slot. * @param file_pos File position. * @param sprite_type Type of the sprite we're decoding. * @param num Size of the decompressed sprite. * @param type Type of the encoded sprite. * @param zoom_lvl Requested zoom level. * @param colour_fmt Colour format of the sprite. * @param container_format Container format of the GRF this sprite is in. * @return True if the sprite was successfully loaded. */ bool DecodeSingleSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, int64 num, byte type, ZoomLevel zoom_lvl, byte colour_fmt, byte container_format) { AutoFreePtr dest_orig(MallocT(num)); byte *dest = dest_orig; const int64 dest_size = num; /* Read the file, which has some kind of compression */ while (num > 0) { int8 code = FioReadByte(); if (code >= 0) { /* Plain bytes to read */ int size = (code == 0) ? 0x80 : code; num -= size; if (num < 0) return WarnCorruptSprite(file_slot, file_pos, __LINE__); for (; size > 0; size--) { *dest = FioReadByte(); dest++; } } else { /* Copy bytes from earlier in the sprite */ const uint data_offset = ((code & 7) << 8) | FioReadByte(); if (dest - data_offset < dest_orig) return WarnCorruptSprite(file_slot, file_pos, __LINE__); int size = -(code >> 3); num -= size; if (num < 0) return WarnCorruptSprite(file_slot, file_pos, __LINE__); for (; size > 0; size--) { *dest = *(dest - data_offset); dest++; } } } if (num != 0) return WarnCorruptSprite(file_slot, file_pos, __LINE__); sprite->AllocateData(zoom_lvl, sprite->width * sprite->height); /* Convert colour depth to pixel size. */ int bpp = 0; if (colour_fmt & SCC_RGB) bpp += 3; // Has RGB data. if (colour_fmt & SCC_ALPHA) bpp++; // Has alpha data. if (colour_fmt & SCC_PAL) bpp++; // Has palette data. /* When there are transparency pixels, this format has another trick.. decode it */ if (type & 0x08) { for (int y = 0; y < sprite->height; y++) { bool last_item = false; /* Look up in the header-table where the real data is stored for this row */ int offset; if (container_format >= 2 && dest_size > UINT16_MAX) { offset = (dest_orig[y * 4 + 3] << 24) | (dest_orig[y * 4 + 2] << 16) | (dest_orig[y * 4 + 1] << 8) | dest_orig[y * 4]; } else { offset = (dest_orig[y * 2 + 1] << 8) | dest_orig[y * 2]; } /* Go to that row */ dest = dest_orig + offset; do { if (dest + (container_format >= 2 && sprite->width > 256 ? 4 : 2) > dest_orig + dest_size) { return WarnCorruptSprite(file_slot, file_pos, __LINE__); } SpriteLoader::CommonPixel *data; /* Read the header. */ int length, skip; if (container_format >= 2 && sprite->width > 256) { /* 0 .. 14 - length * 15 - last_item * 16 .. 31 - transparency bytes */ last_item = (dest[1] & 0x80) != 0; length = ((dest[1] & 0x7F) << 8) | dest[0]; skip = (dest[3] << 8) | dest[2]; dest += 4; } else { /* 0 .. 6 - length * 7 - last_item * 8 .. 15 - transparency bytes */ last_item = ((*dest) & 0x80) != 0; length = (*dest++) & 0x7F; skip = *dest++; } data = &sprite->data[y * sprite->width + skip]; if (skip + length > sprite->width || dest + length * bpp > dest_orig + dest_size) { return WarnCorruptSprite(file_slot, file_pos, __LINE__); } for (int x = 0; x < length; x++) { if (colour_fmt & SCC_RGB) { data->r = *dest++; data->g = *dest++; data->b = *dest++; } data->a = (colour_fmt & SCC_ALPHA) ? *dest++ : 0xFF; if (colour_fmt & SCC_PAL) { switch (sprite_type) { case ST_NORMAL: data->m = _palette_remap_grf[file_slot] ? _palmap_w2d[*dest] : *dest; break; case ST_FONT: data->m = min(*dest, 2u); break; default: data->m = *dest; break; } /* Magic blue. */ if (colour_fmt == SCC_PAL && *dest == 0) data->a = 0x00; dest++; } data++; } } while (!last_item); } } else { if (dest_size < sprite->width * sprite->height * bpp) { return WarnCorruptSprite(file_slot, file_pos, __LINE__); } if (dest_size > sprite->width * sprite->height * bpp) { static byte warning_level = 0; DEBUG(sprite, warning_level, "Ignoring " OTTD_PRINTF64 " unused extra bytes from the sprite from %s at position %i", dest_size - sprite->width * sprite->height * bpp, FioGetFilename(file_slot), (int)file_pos); warning_level = 6; } dest = dest_orig; for (int i = 0; i < sprite->width * sprite->height; i++) { byte *pixel = &dest[i * bpp]; if (colour_fmt & SCC_RGB) { sprite->data[i].r = *pixel++; sprite->data[i].g = *pixel++; sprite->data[i].b = *pixel++; } sprite->data[i].a = (colour_fmt & SCC_ALPHA) ? *pixel++ : 0xFF; if (colour_fmt & SCC_PAL) { switch (sprite_type) { case ST_NORMAL: sprite->data[i].m = _palette_remap_grf[file_slot] ? _palmap_w2d[*pixel] : *pixel; break; case ST_FONT: sprite->data[i].m = min(*pixel, 2u); break; default: sprite->data[i].m = *pixel; break; } /* Magic blue. */ if (colour_fmt == SCC_PAL && *pixel == 0) sprite->data[i].a = 0x00; pixel++; } } } return true; } uint8 LoadSpriteV1(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) { /* Check the requested colour depth. */ if (load_32bpp) return 0; /* Open the right file and go to the correct position */ FioSeekToFile(file_slot, file_pos); /* Read the size and type */ int num = FioReadWord(); byte type = FioReadByte(); /* Type 0xFF indicates either a colourmap or some other non-sprite info; we do not handle them here */ if (type == 0xFF) return 0; ZoomLevel zoom_lvl = (sprite_type != ST_MAPGEN) ? ZOOM_LVL_OUT_4X : ZOOM_LVL_NORMAL; sprite[zoom_lvl].height = FioReadByte(); sprite[zoom_lvl].width = FioReadWord(); sprite[zoom_lvl].x_offs = FioReadWord(); sprite[zoom_lvl].y_offs = FioReadWord(); if (sprite[zoom_lvl].width > INT16_MAX) { WarnCorruptSprite(file_slot, file_pos, __LINE__); return 0; } /* 0x02 indicates it is a compressed sprite, so we can't rely on 'num' to be valid. * In case it is uncompressed, the size is 'num' - 8 (header-size). */ num = (type & 0x02) ? sprite[zoom_lvl].width * sprite[zoom_lvl].height : num - 8; if (DecodeSingleSprite(&sprite[zoom_lvl], file_slot, file_pos, sprite_type, num, type, zoom_lvl, SCC_PAL, 1)) return 1 << zoom_lvl; return 0; } uint8 LoadSpriteV2(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) { static const ZoomLevel zoom_lvl_map[6] = {ZOOM_LVL_OUT_4X, ZOOM_LVL_NORMAL, ZOOM_LVL_OUT_2X, ZOOM_LVL_OUT_8X, ZOOM_LVL_OUT_16X, ZOOM_LVL_OUT_32X}; /* Is the sprite not present/stripped in the GRF? */ if (file_pos == SIZE_MAX) return 0; /* Open the right file and go to the correct position */ FioSeekToFile(file_slot, file_pos); uint32 id = FioReadDword(); uint8 loaded_sprites = 0; do { int64 num = FioReadDword(); size_t start_pos = FioGetPos(); byte type = FioReadByte(); /* Type 0xFF indicates either a colourmap or some other non-sprite info; we do not handle them here. */ if (type == 0xFF) return 0; byte colour = type & SCC_MASK; byte zoom = FioReadByte(); if (colour != 0 && (load_32bpp ? colour != SCC_PAL : colour == SCC_PAL) && (sprite_type != ST_MAPGEN ? zoom < lengthof(zoom_lvl_map) : zoom == 0)) { ZoomLevel zoom_lvl = (sprite_type != ST_MAPGEN) ? zoom_lvl_map[zoom] : ZOOM_LVL_NORMAL; if (HasBit(loaded_sprites, zoom_lvl)) { /* We already have this zoom level, skip sprite. */ DEBUG(sprite, 1, "Ignoring duplicate zoom level sprite %u from %s", id, FioGetFilename(file_slot)); FioSkipBytes(num - 2); continue; } sprite[zoom_lvl].height = FioReadWord(); sprite[zoom_lvl].width = FioReadWord(); sprite[zoom_lvl].x_offs = FioReadWord(); sprite[zoom_lvl].y_offs = FioReadWord(); if (sprite[zoom_lvl].width > INT16_MAX || sprite[zoom_lvl].height > INT16_MAX) { WarnCorruptSprite(file_slot, file_pos, __LINE__); return 0; } /* Mask out colour information. */ type = type & ~SCC_MASK; /* Convert colour depth to pixel size. */ int bpp = 0; if (colour & SCC_RGB) bpp += 3; // Has RGB data. if (colour & SCC_ALPHA) bpp++; // Has alpha data. if (colour & SCC_PAL) bpp++; // Has palette data. /* For chunked encoding we store the decompressed size in the file, * otherwise we can calculate it from the image dimensions. */ uint decomp_size = (type & 0x08) ? FioReadDword() : sprite[zoom_lvl].width * sprite[zoom_lvl].height * bpp; bool valid = DecodeSingleSprite(&sprite[zoom_lvl], file_slot, file_pos, sprite_type, decomp_size, type, zoom_lvl, colour, 2); if (FioGetPos() != start_pos + num) { WarnCorruptSprite(file_slot, file_pos, __LINE__); return 0; } if (valid) SetBit(loaded_sprites, zoom_lvl); } else { /* Not the wanted zoom level or colour depth, continue searching. */ FioSkipBytes(num - 2); } } while (FioReadDword() == id); return loaded_sprites; } uint8 SpriteLoaderGrf::LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) { if (this->container_ver >= 2) { return LoadSpriteV2(sprite, file_slot, file_pos, sprite_type, load_32bpp); } else { return LoadSpriteV1(sprite, file_slot, file_pos, sprite_type, load_32bpp); } } openttd-1.5.3/src/spriteloader/spriteloader.hpp0000644000000000000000000000572312627373435020410 0ustar rootroot/* $Id: spriteloader.hpp 23897 2012-02-04 22:18:57Z michi_cc $ */ /* * 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 spriteloader.hpp Base for loading sprites. */ #ifndef SPRITELOADER_HPP #define SPRITELOADER_HPP #include "../core/alloc_type.hpp" #include "../gfx_type.h" /** Interface for the loader of our sprites. */ class SpriteLoader { public: /** Definition of a common pixel in OpenTTD's realm. */ struct CommonPixel { uint8 r; ///< Red-channel uint8 g; ///< Green-channel uint8 b; ///< Blue-channel uint8 a; ///< Alpha-channel uint8 m; ///< Remap-channel }; /** * Structure for passing information from the sprite loader to the blitter. * You can only use this struct once at a time when using AllocateData to * allocate the memory as that will always return the same memory address. * This to prevent thousands of malloc + frees just to load a sprite. */ struct Sprite { uint16 height; ///< Height of the sprite uint16 width; ///< Width of the sprite int16 x_offs; ///< The x-offset of where the sprite will be drawn int16 y_offs; ///< The y-offset of where the sprite will be drawn SpriteType type; ///< The sprite type SpriteLoader::CommonPixel *data; ///< The sprite itself /** * Allocate the sprite data of this sprite. * @param zoom Zoom level to allocate the data for. * @param size the minimum size of the data field. */ void AllocateData(ZoomLevel zoom, size_t size) { this->data = Sprite::buffer[zoom].ZeroAllocate(size); } private: /** Allocated memory to pass sprite data around */ static ReusableBuffer buffer[ZOOM_LVL_COUNT]; }; /** * Load a sprite from the disk and return a sprite struct which is the same for all loaders. * @param[out] sprite The sprites to fill with data. * @param file_slot The file "descriptor" of the file we read from. * @param file_pos The position within the file the image begins. * @param sprite_type The type of sprite we're trying to load. * @param load_32bpp True if 32bpp sprites should be loaded, false for a 8bpp sprite. * @return Bit mask of the zoom levels successfully loaded or 0 if no sprite could be loaded. */ virtual uint8 LoadSprite(SpriteLoader::Sprite *sprite, uint8 file_slot, size_t file_pos, SpriteType sprite_type, bool load_32bpp) = 0; virtual ~SpriteLoader() { } }; #endif /* SPRITELOADER_HPP */ openttd-1.5.3/src/vehicle_func.h0000644000000000000000000001357312627373441015307 0ustar rootroot/* $Id: vehicle_func.h 26863 2014-09-20 15:31:26Z rubidium $ */ /* * 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 vehicle_func.h Functions related to vehicles. */ #ifndef VEHICLE_FUNC_H #define VEHICLE_FUNC_H #include "gfx_type.h" #include "direction_type.h" #include "command_type.h" #include "vehicle_type.h" #include "engine_type.h" #include "transport_type.h" #include "newgrf_config.h" #include "track_type.h" #include "livery.h" #define is_custom_sprite(x) (x >= 0xFD) #define IS_CUSTOM_FIRSTHEAD_SPRITE(x) (x == 0xFD) #define IS_CUSTOM_SECONDHEAD_SPRITE(x) (x == 0xFE) static const int VEHICLE_PROFIT_MIN_AGE = DAYS_IN_YEAR * 2; ///< Only vehicles older than this have a meaningful profit. static const Money VEHICLE_PROFIT_THRESHOLD = 10000; ///< Threshold for a vehicle to be considered making good profit. /** * Helper to check whether an image index is valid for a particular vehicle. * @param The type of vehicle. * @param image_index The image index to check. * @return True iff the image index is valid. */ template bool IsValidImageIndex(uint8 image_index); typedef Vehicle *VehicleFromPosProc(Vehicle *v, void *data); void VehicleServiceInDepot(Vehicle *v); uint CountVehiclesInChain(const Vehicle *v); void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc); void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc); bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc); bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc); void CallVehicleTicks(); uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *colour); void VehicleLengthChanged(const Vehicle *u); byte VehicleRandomBits(); void ResetVehicleHash(); void ResetVehicleColourMap(); byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type); void ViewportAddVehicles(DrawPixelInfo *dpi); void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical); CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore = NULL); void DecreaseVehicleValue(Vehicle *v); void CheckVehicleBreakdown(Vehicle *v); void AgeVehicle(Vehicle *v); void VehicleEnteredDepotThisTick(Vehicle *v); UnitID GetFreeUnitNumber(VehicleType type); void VehicleEnterDepot(Vehicle *v); bool CanBuildVehicleInfrastructure(VehicleType type); /** Position information of a vehicle after it moved */ struct GetNewVehiclePosResult { int x, y; ///< x and y position of the vehicle after moving TileIndex old_tile; ///< Current tile of the vehicle TileIndex new_tile; ///< Tile of the vehicle after moving }; GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v); Direction GetDirectionTowards(const Vehicle *v, int x, int y); /** * Is the given vehicle type buildable by a company? * @param type Vehicle type being queried. * @return Vehicle type is buildable by a company. */ static inline bool IsCompanyBuildableVehicleType(VehicleType type) { switch (type) { case VEH_TRAIN: case VEH_ROAD: case VEH_SHIP: case VEH_AIRCRAFT: return true; default: return false; } } /** * Is the given vehicle buildable by a company? * @param v Vehicle being queried. * @return Vehicle is buildable by a company. */ static inline bool IsCompanyBuildableVehicleType(const BaseVehicle *v) { return IsCompanyBuildableVehicleType(v->type); } LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v); const struct Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting); SpriteID GetEnginePalette(EngineID engine_type, CompanyID company); SpriteID GetVehiclePalette(const Vehicle *v); extern const uint32 _veh_build_proc_table[]; extern const uint32 _veh_sell_proc_table[]; extern const uint32 _veh_refit_proc_table[]; extern const uint32 _send_to_depot_proc_table[]; /* Functions to find the right command for certain vehicle type */ static inline uint32 GetCmdBuildVeh(VehicleType type) { return _veh_build_proc_table[type]; } static inline uint32 GetCmdBuildVeh(const BaseVehicle *v) { return GetCmdBuildVeh(v->type); } static inline uint32 GetCmdSellVeh(VehicleType type) { return _veh_sell_proc_table[type]; } static inline uint32 GetCmdSellVeh(const BaseVehicle *v) { return GetCmdSellVeh(v->type); } static inline uint32 GetCmdRefitVeh(VehicleType type) { return _veh_refit_proc_table[type]; } static inline uint32 GetCmdRefitVeh(const BaseVehicle *v) { return GetCmdRefitVeh(v->type); } static inline uint32 GetCmdSendToDepot(VehicleType type) { return _send_to_depot_proc_table[type]; } static inline uint32 GetCmdSendToDepot(const BaseVehicle *v) { return GetCmdSendToDepot(v->type); } CommandCost EnsureNoVehicleOnGround(TileIndex tile); CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits); extern VehicleID _new_vehicle_id; extern uint16 _returned_refit_capacity; extern uint16 _returned_mail_refit_capacity; bool CanVehicleUseStation(EngineID engine_type, const struct Station *st); bool CanVehicleUseStation(const Vehicle *v, const struct Station *st); void ReleaseDisastersTargetingVehicle(VehicleID vehicle); typedef SmallVector VehicleSet; void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles); void CheckCargoCapacity(Vehicle *v); #endif /* VEHICLE_FUNC_H */ openttd-1.5.3/src/tilehighlight_func.h0000644000000000000000000000323512627373442016510 0ustar rootroot/* $Id: tilehighlight_func.h 21627 2010-12-24 15:08:19Z alberth $ */ /* * 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 tilehighlight_func.h Functions related to tile highlights. */ #ifndef TILEHIGHLIGHT_FUNC_H #define TILEHIGHLIGHT_FUNC_H #include "gfx_type.h" #include "tilehighlight_type.h" void PlaceProc_DemolishArea(TileIndex tile); bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile); bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyle mode); void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w); void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num); void ResetObjectToPlace(); void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method); void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process); void VpSetPresizeRange(TileIndex from, TileIndex to); void VpSetPlaceSizingLimit(int limit); void UpdateTileSelection(); extern TileHighlightData _thd; #endif /* TILEHIGHLIGHT_FUNC_H */ openttd-1.5.3/src/newgrf_industrytiles.h0000644000000000000000000000653412627373435017151 0ustar rootroot/* $Id: newgrf_industrytiles.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 newgrf_industrytiles.h NewGRF handling of industry tiles. */ #ifndef NEWGRF_INDUSTRYTILES_H #define NEWGRF_INDUSTRYTILES_H #include "newgrf_animation_type.h" #include "newgrf_industries.h" #include "core/random_func.hpp" /** Resolver for the industry tiles scope. */ struct IndustryTileScopeResolver : public ScopeResolver { Industry *industry; ///< Industry owning the tiles. TileIndex tile; ///< %Tile being resolved. IndustryTileScopeResolver(ResolverObject &ro, Industry *industry, TileIndex tile); /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; /* virtual */ uint32 GetTriggers() const; /* virtual */ void SetTriggers(int triggers) const; }; /** Resolver for industry tiles. */ struct IndustryTileResolverObject : public ResolverObject { IndustryTileScopeResolver indtile_scope; ///< Scope resolver for the industry tile. IndustriesScopeResolver ind_scope; ///< Scope resolver for the industry owning the tile. IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &indtile_scope; case VSG_SCOPE_PARENT: return &ind_scope; default: return ResolverObject::GetScope(scope, relative); } } }; bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds); uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile); CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type); void AnimateNewIndustryTile(TileIndex tile); bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random = Random()); bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigger iat); /** Available industry tile triggers. */ enum IndustryTileTrigger { INDTILE_TRIGGER_TILE_LOOP = 0x01, ///< The tile of the industry has been triggered during the tileloop. INDUSTRY_TRIGGER_INDUSTRY_TICK = 0x02, ///< The industry has been triggered via its tick. INDUSTRY_TRIGGER_RECEIVED_CARGO = 0x04, ///< Cargo has been delivered. }; void TriggerIndustryTile(TileIndex t, IndustryTileTrigger trigger); void TriggerIndustry(Industry *ind, IndustryTileTrigger trigger); #endif /* NEWGRF_INDUSTRYTILES_H */ openttd-1.5.3/src/cargopacket.cpp0000644000000000000000000007235112627373441015472 0ustar rootroot/* $Id: cargopacket.cpp 26575 2014-05-11 12:49:51Z fonsinchen $ */ /* * 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 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" #include "cargoaction.h" #include "order_type.h" #include "safeguards.h" /* Initialize the cargopacket-pool */ CargoPacketPool _cargopacket_pool("CargoPacket"); INSTANTIATE_POOL_METHODS(CargoPacket) /** * Create a new packet for savegame loading. */ CargoPacket::CargoPacket() { this->source_type = ST_INDUSTRY; this->source_id = INVALID_SOURCE; } /** * Creates a new cargo packet. * @param source Source station of the packet. * @param source_xy Source location of the packet. * @param count Number of cargo entities to put in this packet. * @param source_type 'Type' of source the packet comes from (for subsidies). * @param source_id Actual source of the packet (for subsidies). * @pre count != 0 * @note We have to zero memory ourselves here because we are using a 'new' * 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) { assert(count != 0); this->source_type = source_type; } /** * Creates a new cargo packet. Initializes the fields that cannot be changed later. * Used when loading or splitting packets. * @param count Number of cargo entities to put in this packet. * @param days_in_transit Number of days the cargo has been in transit. * @param source Station the cargo was initially loaded. * @param source_xy Station location the cargo was initially loaded. * @param loaded_at_xy Location the cargo was loaded last. * @param feeder_share Feeder share the packet has already accumulated. * @param source_type 'Type' of source the packet comes from (for subsidies). * @param source_id Actual source of the packet (for subsidies). * @note We have to zero memory ourselves here because we are using a 'new' * that, in contrary to all other pools, does not memset to 0. */ CargoPacket::CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share, SourceType source_type, SourceID source_id) : feeder_share(feeder_share), count(count), days_in_transit(days_in_transit), source_id(source_id), source(source), source_xy(source_xy), loaded_at_xy(loaded_at_xy) { assert(count != 0); this->source_type = source_type; } /** * Split this packet in two and return the split off part. * @param new_size Size of the split part. * @return Split off part, or NULL if no packet could be allocated! */ CargoPacket *CargoPacket::Split(uint new_size) { if (!CargoPacket::CanAllocateItem()) return NULL; Money fs = this->FeederShare(new_size); CargoPacket *cp_new = new CargoPacket(new_size, this->days_in_transit, this->source, this->source_xy, this->loaded_at_xy, fs, this->source_type, this->source_id); this->feeder_share -= fs; this->count -= new_size; return cp_new; } /** * Merge another packet into this one. * @param cp Packet to be merged in. */ void CargoPacket::Merge(CargoPacket *cp) { this->count += cp->count; this->feeder_share += cp->feeder_share; delete cp; } /** * Reduce the packet by the given amount and remove the feeder share. * @param count Amount to be removed. */ void CargoPacket::Reduce(uint count) { assert(count < this->count); this->feeder_share -= this->FeederShare(count); this->count -= count; } /** * Invalidates (sets source_id to INVALID_SOURCE) all cargo packets from given source. * @param src_type Type of source. * @param src Index of source. */ /* static */ void CargoPacket::InvalidateAllFrom(SourceType src_type, SourceID src) { CargoPacket *cp; FOR_ALL_CARGOPACKETS(cp) { if (cp->source_type == src_type && cp->source_id == src) cp->source_id = INVALID_SOURCE; } } /** * Invalidates (sets source to INVALID_STATION) all cargo packets from given station. * @param sid Station that gets removed. */ /* static */ void CargoPacket::InvalidateAllFrom(StationID sid) { CargoPacket *cp; FOR_ALL_CARGOPACKETS(cp) { if (cp->source == sid) cp->source = INVALID_STATION; } } /* * * Cargo list implementation * */ /** * Destroy the cargolist ("frees" all cargo packets). */ template CargoList::~CargoList() { for (Iterator it(this->packets.begin()); it != this->packets.end(); ++it) { delete *it; } } /** * Empty the cargo list, but don't free the cargo packets; * the cargo packets are cleaned by CargoPacket's CleanPool. */ template void CargoList::OnCleanPool() { this->packets.clear(); } /** * Update the cached values to reflect the removal of this packet or part of it. * Decreases count and days_in_transit. * @param cp Packet to be removed from cache. * @param count Amount of cargo from the given packet to be removed. */ template void CargoList::RemoveFromCache(const CargoPacket *cp, uint count) { assert(count <= cp->count); this->count -= count; this->cargo_days_in_transit -= cp->days_in_transit * count; } /** * Update the cache to reflect adding of this packet. * Increases count and days_in_transit. * @param cp New packet to be inserted. */ template void CargoList::AddToCache(const CargoPacket *cp) { this->count += cp->count; this->cargo_days_in_transit += cp->days_in_transit * cp->count; } /** Invalidates the cached data and rebuilds it. */ template void CargoList::InvalidateCache() { this->count = 0; this->cargo_days_in_transit = 0; for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) { static_cast(this)->AddToCache(*it); } } /** * Tries to merge the second packet into the first and return if that was * successful. * @param icp Packet to be merged into. * @param cp Packet to be eliminated. * @return If the packets could be merged. */ template /* static */ bool CargoList::TryMerge(CargoPacket *icp, CargoPacket *cp) { if (Tinst::AreMergable(icp, cp) && icp->count + cp->count <= CargoPacket::MAX_COUNT) { icp->Merge(cp); return true; } else { return false; } } /* * * Vehicle cargo list implementation. * */ /** * Appends the given cargo packet. Tries to merge it with another one in the * packets list. If no fitting packet is found, appends it. You can only append * packets to the ranges of packets designated for keeping or loading. * Furthermore if there are already packets reserved for loading you cannot * directly add packets to the "keep" list. You first have to load the reserved * ones. * @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. * @param action Either MTA_KEEP if you want to add the packet directly or MTA_LOAD * if you want to reserve it first. * @pre cp != NULL * @pre action == MTA_LOAD || (action == MTA_KEEP && this->designation_counts[MTA_LOAD] == 0) */ void VehicleCargoList::Append(CargoPacket *cp, MoveToAction action) { assert(cp != NULL); assert(action == MTA_LOAD || (action == MTA_KEEP && this->action_counts[MTA_LOAD] == 0)); this->AddToMeta(cp, action); if (this->count == cp->count) { this->packets.push_back(cp); return; } uint sum = cp->count; for (ReverseIterator it(this->packets.rbegin()); it != this->packets.rend(); it++) { CargoPacket *icp = *it; if (VehicleCargoList::TryMerge(icp, cp)) return; sum += icp->count; if (sum >= this->action_counts[action]) { this->packets.push_back(cp); return; } } NOT_REACHED(); } /** * Shifts cargo from the front of the packet list and applies some action to it. * @tparam Taction Action class or function to be used. It should define * "bool operator()(CargoPacket *)". If true is returned the * cargo packet will be removed from the list. Otherwise it * will be kept and the loop will be aborted. * @param action Action instance to be applied. */ template void VehicleCargoList::ShiftCargo(Taction action) { Iterator it(this->packets.begin()); while (it != this->packets.end() && action.MaxMove() > 0) { CargoPacket *cp = *it; if (action(cp)) { it = this->packets.erase(it); } else { break; } } } /** * Pops cargo from the back of the packet list and applies some action to it. * @tparam Taction Action class or function to be used. It should define * "bool operator()(CargoPacket *)". If true is returned the * cargo packet will be removed from the list. Otherwise it * will be kept and the loop will be aborted. * @param action Action instance to be applied. */ template void VehicleCargoList::PopCargo(Taction action) { if (this->packets.empty()) return; Iterator it(--(this->packets.end())); Iterator begin(this->packets.begin()); while (action.MaxMove() > 0) { CargoPacket *cp = *it; if (action(cp)) { if (it != begin) { this->packets.erase(it--); } else { this->packets.erase(it); break; } } else { break; } } } /** * Update the cached values to reflect the removal of this packet or part of it. * Decreases count, feeder share and days_in_transit. * @param cp Packet to be removed from cache. * @param count Amount of cargo from the given packet to be removed. */ void VehicleCargoList::RemoveFromCache(const CargoPacket *cp, uint count) { this->feeder_share -= cp->FeederShare(count); this->Parent::RemoveFromCache(cp, count); } /** * Update the cache to reflect adding of this packet. * Increases count, feeder share and days_in_transit. * @param cp New packet to be inserted. */ void VehicleCargoList::AddToCache(const CargoPacket *cp) { this->feeder_share += cp->feeder_share; this->Parent::AddToCache(cp); } /** * Removes a packet or part of it from the metadata. * @param cp Packet to be removed. * @param action MoveToAction of the packet (for updating the counts). * @param count Amount of cargo to be removed. */ void VehicleCargoList::RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count) { assert(count <= this->action_counts[action]); this->AssertCountConsistency(); this->RemoveFromCache(cp, count); this->action_counts[action] -= count; this->AssertCountConsistency(); } /** * Adds a packet to the metadata. * @param cp Packet to be added. * @param action MoveToAction of the packet. */ void VehicleCargoList::AddToMeta(const CargoPacket *cp, MoveToAction action) { this->AssertCountConsistency(); this->AddToCache(cp); this->action_counts[action] += cp->count; this->AssertCountConsistency(); } /** * Ages the all cargo in this list. */ void VehicleCargoList::AgeCargo() { for (ConstIterator it(this->packets.begin()); it != this->packets.end(); it++) { CargoPacket *cp = *it; /* If we're at the maximum, then we can't increase no more. */ if (cp->days_in_transit == 0xFF) continue; cp->days_in_transit++; this->cargo_days_in_transit += cp->count; } } /** * Sets loaded_at_xy to the current station for all cargo to be transfered. * This is done when stopping or skipping while the vehicle is unloading. In * that case the vehicle will get part of its transfer credits early and it may * get more transfer credits than it's entitled to. * @param xy New loaded_at_xy for the cargo. */ void VehicleCargoList::SetTransferLoadPlace(TileIndex xy) { uint sum = 0; for (Iterator it = this->packets.begin(); sum < this->action_counts[MTA_TRANSFER]; ++it) { CargoPacket *cp = *it; cp->loaded_at_xy = xy; sum += cp->count; } } /** * Choose action to be performed with the given cargo packet. * @param cp The packet. * @param cargo_next Next hop the cargo wants to pass. * @param current_station Current station of the vehicle carrying the cargo. * @param accepted If the cargo is accepted at the current station. * @param next_station Next station(s) the vehicle may stop at. * @return MoveToAction to be performed. */ /* static */ VehicleCargoList::MoveToAction VehicleCargoList::ChooseAction(const CargoPacket *cp, StationID cargo_next, StationID current_station, bool accepted, StationIDStack next_station) { if (cargo_next == INVALID_STATION) { return (accepted && cp->source != current_station) ? MTA_DELIVER : MTA_KEEP; } else if (cargo_next == current_station) { return MTA_DELIVER; } else if (next_station.Contains(cargo_next)) { return MTA_KEEP; } else { return MTA_TRANSFER; } } /** * Stages cargo for unloading. The cargo is sorted so that packets to be * transferred, delivered or kept are in consecutive chunks in the list. At the * same time the designation_counts are updated to reflect the size of those * chunks. * @param accepted If the cargo will be accepted at the station. * @param current_station ID of the station. * @param next_station ID of the station the vehicle will go to next. * @param order_flags OrderUnloadFlags that will apply to the unload operation. * @param ge GoodsEntry for getting the flows. * @param payment Payment object for registering transfers. * return If any cargo will be unloaded. */ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment) { this->AssertCountConsistency(); assert(this->action_counts[MTA_LOAD] == 0); this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_DELIVER] = this->action_counts[MTA_KEEP] = 0; Iterator deliver = this->packets.end(); Iterator it = this->packets.begin(); uint sum = 0; bool force_keep = (order_flags & OUFB_NO_UNLOAD) != 0; bool force_unload = (order_flags & OUFB_UNLOAD) != 0; bool force_transfer = (order_flags & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0; assert(this->count > 0 || it == this->packets.end()); while (sum < this->count) { CargoPacket *cp = *it; this->packets.erase(it++); StationID cargo_next = INVALID_STATION; MoveToAction action = MTA_LOAD; if (force_keep) { action = MTA_KEEP; } else if (force_unload && accepted && cp->source != current_station) { action = MTA_DELIVER; } else if (force_transfer) { action = MTA_TRANSFER; /* We cannot send the cargo to any of the possible next hops and * also not to the current station. */ FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source)); if (flow_it == ge->flows.end()) { cargo_next = INVALID_STATION; } else { FlowStat new_shares = flow_it->second; new_shares.ChangeShare(current_station, INT_MIN); StationIDStack excluded = next_station; while (!excluded.IsEmpty() && !new_shares.GetShares()->empty()) { new_shares.ChangeShare(excluded.Pop(), INT_MIN); } if (new_shares.GetShares()->empty()) { cargo_next = INVALID_STATION; } else { cargo_next = new_shares.GetVia(); } } } else { /* Rewrite an invalid source station to some random other one to * avoid keeping the cargo in the vehicle forever. */ if (cp->source == INVALID_STATION && !ge->flows.empty()) { cp->source = ge->flows.begin()->first; } bool restricted = false; FlowStatMap::const_iterator flow_it(ge->flows.find(cp->source)); if (flow_it == ge->flows.end()) { cargo_next = INVALID_STATION; } else { cargo_next = flow_it->second.GetViaWithRestricted(restricted); } action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station); if (restricted && action == MTA_TRANSFER) { /* If the flow is restricted we can't transfer to it. Choose an * unrestricted one instead. */ cargo_next = flow_it->second.GetVia(); action = VehicleCargoList::ChooseAction(cp, cargo_next, current_station, accepted, next_station); } } Money share; switch (action) { case MTA_KEEP: this->packets.push_back(cp); if (deliver == this->packets.end()) --deliver; break; case MTA_DELIVER: this->packets.insert(deliver, cp); break; case MTA_TRANSFER: this->packets.push_front(cp); /* Add feeder share here to allow reusing field for next station. */ share = payment->PayTransfer(cp, cp->count); cp->AddFeederShare(share); this->feeder_share += share; cp->next_station = cargo_next; break; default: NOT_REACHED(); } this->action_counts[action] += cp->count; sum += cp->count; } this->AssertCountConsistency(); return this->action_counts[MTA_DELIVER] > 0 || this->action_counts[MTA_TRANSFER] > 0; } /** Invalidates the cached data and rebuild it. */ void VehicleCargoList::InvalidateCache() { this->feeder_share = 0; this->Parent::InvalidateCache(); } /** * Moves some cargo from one designation to another. You can only move * between adjacent designations. E.g. you can keep cargo that was previously * reserved (MTA_LOAD), but you can't reserve cargo that's marked as to be * delivered. Furthermore, as this method doesn't change the actual packets, * you cannot move cargo from or to MTA_TRANSFER. You need a specialized * template method for that. * @tparam from Previous designation of cargo. * @tparam to New designation of cargo. * @param max_move Maximum amount of cargo to reassign. * @return Amount of cargo actually reassigned. */ template uint VehicleCargoList::Reassign(uint max_move, TileOrStationID) { assert_tcompile(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); assert_tcompile(Tfrom - Tto == 1 || Tto - Tfrom == 1); max_move = min(this->action_counts[Tfrom], max_move); this->action_counts[Tfrom] -= max_move; this->action_counts[Tto] += max_move; return max_move; } /** * Reassign cargo from MTA_DELIVER to MTA_TRANSFER and take care of the next * station the cargo wants to visit. * @param max_move Maximum amount of cargo to reassign. * @param next_station Station to record as next hop in the reassigned packets. * @return Amount of cargo actually reassigned. */ template<> uint VehicleCargoList::Reassign(uint max_move, TileOrStationID next_station) { max_move = min(this->action_counts[MTA_DELIVER], max_move); uint sum = 0; for (Iterator it(this->packets.begin()); sum < this->action_counts[MTA_TRANSFER] + max_move;) { CargoPacket *cp = *it++; sum += cp->Count(); if (sum <= this->action_counts[MTA_TRANSFER]) continue; if (sum > this->action_counts[MTA_TRANSFER] + max_move) { CargoPacket *cp_split = cp->Split(sum - this->action_counts[MTA_TRANSFER] + max_move); sum -= cp_split->Count(); this->packets.insert(it, cp_split); } cp->next_station = next_station; } this->action_counts[MTA_DELIVER] -= max_move; this->action_counts[MTA_TRANSFER] += max_move; return max_move; } /** * Returns reserved cargo to the station and removes it from the cache. * @param max_move Maximum amount of cargo to move. * @param dest Station the cargo is returned to. * @param ID of next the station the cargo wants to go next. * @return Amount of cargo actually returned. */ uint VehicleCargoList::Return(uint max_move, StationCargoList *dest, StationID next) { max_move = min(this->action_counts[MTA_LOAD], max_move); this->PopCargo(CargoReturn(this, dest, max_move, next)); return max_move; } /** * Shifts cargo between two vehicles. * @param dest Other vehicle's cargo list. * @param max_move Maximum amount of cargo to be moved. * @return Amount of cargo actually moved. */ uint VehicleCargoList::Shift(uint max_move, VehicleCargoList *dest) { max_move = min(this->count, max_move); this->PopCargo(CargoShift(this, dest, max_move)); return max_move; } /** * Unloads cargo at the given station. Deliver or transfer, depending on the * ranges defined by designation_counts. * @param dest StationCargoList to add transferred cargo to. * @param max_move Maximum amount of cargo to move. * @param payment Payment object to register payments in. * @return Amount of cargo actually unloaded. */ uint VehicleCargoList::Unload(uint max_move, StationCargoList *dest, CargoPayment *payment) { uint moved = 0; if (this->action_counts[MTA_TRANSFER] > 0) { uint move = min(this->action_counts[MTA_TRANSFER], max_move); this->ShiftCargo(CargoTransfer(this, dest, move)); moved += move; } if (this->action_counts[MTA_TRANSFER] == 0 && this->action_counts[MTA_DELIVER] > 0 && moved < max_move) { uint move = min(this->action_counts[MTA_DELIVER], max_move - moved); this->ShiftCargo(CargoDelivery(this, move, payment)); moved += move; } return moved; } /** * Truncates the cargo in this list to the given amount. It leaves the * first cargo entities and removes max_move from the back of the list. * @param max_move Maximum amount of entities to be removed from the list. * @return Amount of entities actually moved. */ uint VehicleCargoList::Truncate(uint max_move) { max_move = min(this->count, max_move); this->PopCargo(CargoRemoval(this, max_move)); return max_move; } /** * Routes packets with station "avoid" as next hop to a different place. * @param max_move Maximum amount of cargo to move. * @param dest List to prepend the cargo to. * @param avoid Station to exclude from routing and current next hop of packets to reroute. * @param avoid2 Additional station to exclude from routing. * @oaram ge GoodsEntry to get the routing info from. */ uint VehicleCargoList::Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge) { max_move = min(this->action_counts[MTA_TRANSFER], max_move); this->ShiftCargo(VehicleCargoReroute(this, dest, max_move, avoid, avoid2, ge)); return max_move; } /* * * Station cargo list implementation. * */ /** * 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 the next hop * @param cp the cargo packet to add * @pre cp != NULL */ void StationCargoList::Append(CargoPacket *cp, StationID next) { assert(cp != NULL); this->AddToCache(cp); StationCargoPacketMap::List &list = this->packets[next]; for (StationCargoPacketMap::List::reverse_iterator it(list.rbegin()); it != list.rend(); it++) { if (StationCargoList::TryMerge(*it, cp)) return; } /* The packet could not be merged with another one */ list.push_back(cp); } /** * Shifts cargo from the front of the packet list for a specific station and * applies some action to it. * @tparam Taction Action class or function to be used. It should define * "bool operator()(CargoPacket *)". If true is returned the * cargo packet will be removed from the list. Otherwise it * will be kept and the loop will be aborted. * @param action Action instance to be applied. * @param next Next hop the cargo wants to visit. * @return True if all packets with the given next hop have been removed, * False otherwise. */ template bool StationCargoList::ShiftCargo(Taction &action, StationID next) { std::pair range(this->packets.equal_range(next)); for (Iterator it(range.first); it != range.second && it.GetKey() == next;) { if (action.MaxMove() == 0) return false; CargoPacket *cp = *it; if (action(cp)) { it = this->packets.erase(it); } else { return false; } } return true; } /** * Shifts cargo from the front of the packet list for a specific station and * and optional also from the list for "any station", then applies some action * to it. * @tparam Taction Action class or function to be used. It should define * "bool operator()(CargoPacket *)". If true is returned the * cargo packet will be removed from the list. Otherwise it * will be kept and the loop will be aborted. * @param action Action instance to be applied. * @param next Next hop the cargo wants to visit. * @param include_invalid If cargo from the INVALID_STATION list should be * used if necessary. * @return Amount of cargo actually moved. */ template uint StationCargoList::ShiftCargo(Taction action, StationIDStack next, bool include_invalid) { uint max_move = action.MaxMove(); while (!next.IsEmpty()) { this->ShiftCargo(action, next.Pop()); if (action.MaxMove() == 0) break; } if (include_invalid && action.MaxMove() > 0) { this->ShiftCargo(action, INVALID_STATION); } return max_move - action.MaxMove(); } /** * Truncates where each destination loses roughly the same percentage of its * cargo. This is done by randomizing the selection of packets to be removed. * Optionally count the cargo by origin station. * @param max_move Maximum amount of cargo to remove. * @param cargo_per_source Container for counting the cargo by origin. * @return Amount of cargo actually moved. */ uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_source) { max_move = min(max_move, this->count); uint prev_count = this->count; uint moved = 0; uint loop = 0; bool do_count = cargo_per_source != NULL; while (max_move > moved) { for (Iterator it(this->packets.begin()); it != this->packets.end();) { CargoPacket *cp = *it; if (prev_count > max_move && RandomRange(prev_count) < prev_count - max_move) { if (do_count && loop == 0) { (*cargo_per_source)[cp->source] += cp->count; } ++it; continue; } uint diff = max_move - moved; if (cp->count > diff) { if (diff > 0) { this->RemoveFromCache(cp, diff); cp->Reduce(diff); moved += diff; } if (loop > 0) { if (do_count) (*cargo_per_source)[cp->source] -= diff; return moved; } else { if (do_count) (*cargo_per_source)[cp->source] += cp->count; ++it; } } else { it = this->packets.erase(it); if (do_count && loop > 0) { (*cargo_per_source)[cp->source] -= cp->count; } moved += cp->count; this->RemoveFromCache(cp, cp->count); delete cp; } } loop++; } return moved; } /** * Reserves cargo for loading onto the vehicle. * @param max_move Maximum amount of cargo to reserve. * @param dest VehicleCargoList to reserve for. * @param load_place Tile index of the current station. * @param next_station Next station(s) the loading vehicle will visit. * @return Amount of cargo actually reserved. */ uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next_station) { return this->ShiftCargo(CargoReservation(this, dest, max_move, load_place), next_station, true); } /** * Loads cargo onto a vehicle. If the vehicle has reserved cargo load that. * Otherwise load cargo from the station. * @param max_move Amount of cargo to load. * @param dest Vehicle cargo list where the cargo resides. * @param load_place The new loaded_at_xy to be assigned to packets being moved. * @param next_station Next station(s) the loading vehicle will visit. * @return Amount of cargo actually loaded. * @note Vehicles may or may not reserve, depending on their orders. The two * modes of loading are exclusive, though. If cargo is reserved we don't * need to load unreserved cargo. */ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next_station) { uint move = min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move); if (move > 0) { this->reserved_count -= move; dest->Reassign(move); return move; } else { return this->ShiftCargo(CargoLoad(this, dest, max_move, load_place), next_station, true); } } /** * Routes packets with station "avoid" as next hop to a different place. * @param max_move Maximum amount of cargo to move. * @param dest List to append the cargo to. * @param avoid Station to exclude from routing and current next hop of packets to reroute. * @param avoid2 Additional station to exclude from routing. * @oaram ge GoodsEntry to get the routing info from. */ uint StationCargoList::Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge) { return this->ShiftCargo(StationCargoReroute(this, dest, max_move, avoid, avoid2, ge), avoid, false); } /* * We have to instantiate everything we want to be usable. */ template class CargoList; template class CargoList; template uint VehicleCargoList::Reassign(uint, TileOrStationID); openttd-1.5.3/src/textbuf_type.h0000644000000000000000000000637212627373435015401 0ustar rootroot/* $Id: textbuf_type.h 25692 2013-08-05 20:37:57Z michi_cc $ */ /* * 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 textbuf_type.h Stuff related to text buffers. */ #ifndef TEXTBUF_TYPE_H #define TEXTBUF_TYPE_H #include "string_type.h" #include "strings_type.h" #include "string_base.h" /** * Return values for Textbuf::HandleKeypress */ enum HandleKeyPressResult { HKPR_EDITING, ///< Textbuf content changed. HKPR_CURSOR, ///< Non-text change, e.g. cursor position. HKPR_CONFIRM, ///< Return or enter key pressed. HKPR_CANCEL, ///< Escape key pressed. HKPR_NOT_HANDLED, ///< Key does not affect editboxes. }; /** Helper/buffer for input fields. */ struct Textbuf { CharSetFilter afilter; ///< Allowed characters char * const buf; ///< buffer in which text is saved uint16 max_bytes; ///< the maximum size of the buffer in bytes (including terminating '\0') uint16 max_chars; ///< the maximum size of the buffer in characters (including terminating '\0') uint16 bytes; ///< the current size of the string in bytes (including terminating '\0') uint16 chars; ///< the current size of the string in characters (including terminating '\0') uint16 pixels; ///< the current size of the string in pixels bool caret; ///< is the caret ("_") visible or not uint16 caretpos; ///< the current position of the caret in the buffer, in bytes uint16 caretxoffs; ///< the current position of the caret in pixels uint16 markpos; ///< the start position of the marked area in the buffer, in bytes uint16 markend; ///< the end position of the marked area in the buffer, in bytes uint16 markxoffs; ///< the start position of the marked area in pixels uint16 marklength; ///< the length of the marked area in pixels explicit Textbuf(uint16 max_bytes, uint16 max_chars = UINT16_MAX); ~Textbuf(); void Assign(StringID string); void Assign(const char *text); void CDECL Print(const char *format, ...) WARN_FORMAT(2, 3); void DeleteAll(); bool InsertClipboard(); bool InsertChar(uint32 key); bool InsertString(const char *str, bool marked, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL); bool DeleteChar(uint16 keycode); bool MovePos(uint16 keycode); HandleKeyPressResult HandleKeyPress(WChar key, uint16 keycode); bool HandleCaret(); void UpdateSize(); void DiscardMarkedText(bool update = true); private: StringIterator *char_iter; bool CanDelChar(bool backspace); void DeleteText(uint16 from, uint16 to, bool update); void UpdateStringIter(); void UpdateWidth(); void UpdateCaretPosition(); void UpdateMarkedText(); }; #endif /* TEXTBUF_TYPE_H */ openttd-1.5.3/src/newgrf_railtype.cpp0000644000000000000000000001330612627373435016406 0ustar rootroot/* $Id: newgrf_railtype.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_railtype.cpp NewGRF handling of rail types. */ #include "stdafx.h" #include "debug.h" #include "newgrf_railtype.h" #include "date_func.h" #include "depot_base.h" #include "town.h" #include "safeguards.h" /* virtual */ uint32 RailTypeScopeResolver::GetRandomBits() const { uint tmp = CountBits(this->tile + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE); return GB(tmp, 0, 2); } /* virtual */ uint32 RailTypeScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { if (this->tile == INVALID_TILE) { switch (variable) { case 0x40: return 0; case 0x41: return 0; case 0x42: return 0; case 0x43: return _date; case 0x44: return HZB_TOWN_EDGE; } } switch (variable) { case 0x40: return GetTerrainType(this->tile, this->context); case 0x41: return 0; case 0x42: return IsLevelCrossingTile(this->tile) && IsCrossingBarred(this->tile); case 0x43: if (IsRailDepotTile(this->tile)) return Depot::GetByTile(this->tile)->build_date; return _date; case 0x44: { const Town *t = NULL; if (IsRailDepotTile(this->tile)) { t = Depot::GetByTile(this->tile)->town; } else if (IsLevelCrossingTile(this->tile)) { t = ClosestTownFromTile(this->tile, UINT_MAX); } return t != NULL ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; } } DEBUG(grf, 1, "Unhandled rail type tile variable 0x%X", variable); *available = false; return UINT_MAX; } /* virtual */ const SpriteGroup *RailTypeResolverObject::ResolveReal(const RealSpriteGroup *group) const { if (group->num_loading > 0) return group->loading[0]; if (group->num_loaded > 0) return group->loaded[0]; return NULL; } /** * Constructor of the railtype scope resolvers. * @param ro Surrounding resolver. * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. * @param context Are we resolving sprites for the upper halftile, or on a bridge? */ RailTypeScopeResolver::RailTypeScopeResolver(ResolverObject &ro, TileIndex tile, TileContext context) : ScopeResolver(ro) { this->tile = tile; this->context = context; } /** * Resolver object for rail types. * @param rti Railtype. NULL in NewGRF Inspect window. * @param tile %Tile containing the track. For track on a bridge this is the southern bridgehead. * @param context Are we resolving sprites for the upper halftile, or on a bridge? * @param rtsg Railpart of interest * @param param1 Extra parameter (first parameter of the callback, except railtypes do not have callbacks). * @param param2 Extra parameter (second parameter of the callback, except railtypes do not have callbacks). */ RailTypeResolverObject::RailTypeResolverObject(const RailtypeInfo *rti, TileIndex tile, TileContext context, RailTypeSpriteGroup rtsg, uint32 param1, uint32 param2) : ResolverObject(rti != NULL ? rti->grffile[rtsg] : NULL, CBID_NO_CALLBACK, param1, param2), railtype_scope(*this, tile, context) { this->root_spritegroup = rti != NULL ? rti->group[rtsg] : NULL; } /** * Get the sprite to draw for the given tile. * @param rti The rail type data (spec). * @param tile The tile to get the sprite for. * @param rtsg The type of sprite to draw. * @param content Where are we drawing the tile? * @return The sprite to draw. */ SpriteID GetCustomRailSprite(const RailtypeInfo *rti, TileIndex tile, RailTypeSpriteGroup rtsg, TileContext context) { assert(rtsg < RTSG_END); if (rti->group[rtsg] == NULL) return 0; RailTypeResolverObject object(rti, tile, context, rtsg); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->GetNumResults() == 0) return 0; return group->GetResult(); } /** * Get the sprite to draw for a given signal. * @param rti The rail type data (spec). * @param tile The tile to get the sprite for. * @param type Signal type. * @param var Signal variant. * @param state Signal state. * @param gui Is the sprite being used on the map or in the GUI? * @return The sprite to draw. */ SpriteID GetCustomSignalSprite(const RailtypeInfo *rti, TileIndex tile, SignalType type, SignalVariant var, SignalState state, bool gui) { if (rti->group[RTSG_SIGNALS] == NULL) return 0; uint32 param1 = gui ? 0x10 : 0x00; uint32 param2 = (type << 16) | (var << 8) | state; RailTypeResolverObject object(rti, tile, TCX_NORMAL, RTSG_SIGNALS, param1, param2); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->GetNumResults() == 0) return 0; return group->GetResult(); } /** * Perform a reverse railtype lookup to get the GRF internal ID. * @param railtype The global (OpenTTD) railtype. * @param grffile The GRF to do the lookup for. * @return the GRF internal ID. */ uint8 GetReverseRailTypeTranslation(RailType railtype, const GRFFile *grffile) { /* No rail type table present, return rail type as-is */ if (grffile == NULL || grffile->railtype_list.Length() == 0) return railtype; /* Look for a matching rail type label in the table */ RailTypeLabel label = GetRailTypeInfo(railtype)->label; int index = grffile->railtype_list.FindIndex(label); if (index >= 0) return index; /* If not found, return as invalid */ return 0xFF; } openttd-1.5.3/src/viewport_func.h0000644000000000000000000000751612627373445015553 0ustar rootroot/* $Id: viewport_func.h 27161 2015-02-22 14:42:34Z frosch $ */ /* * 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 viewport_func.h Functions related to (drawing on) viewports. */ #ifndef VIEWPORT_FUNC_H #define VIEWPORT_FUNC_H #include "gfx_type.h" #include "viewport_type.h" #include "window_type.h" #include "tile_type.h" #include "station_type.h" static const int TILE_HEIGHT_STEP = 50; ///< One Z unit tile height difference is displayed as 50m. void SetSelectionRed(bool); void DeleteWindowViewport(Window *w); void InitializeWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom); ViewPort *IsPtInWindowViewport(const Window *w, int x, int y); Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y, bool clamp_to_map = true); Point GetTileBelowCursor(); void UpdateViewportPosition(Window *w); void MarkAllViewportsDirty(int left, int top, int right, int bottom); bool DoZoomInOutWindow(ZoomStateChange how, Window *w); void ZoomInOrOutToCursorWindow(bool in, Window * w); Point GetTileZoomCenterWindow(bool in, Window * w); void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out); /** * Zoom a viewport as far as possible in the given direction. * @param how Zooming direction. * @param w Window owning the viewport. * @pre \a how should not be #ZOOM_NONE. */ static inline void MaxZoomInOut(ZoomStateChange how, Window *w) { while (DoZoomInOutWindow(how, w)) {}; } void OffsetGroundSprite(int x, int y); void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0); void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0); void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = NULL); void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent = false, const SubSprite *sub = NULL, bool scale = true); void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2 = 0, Colours colour = INVALID_COLOUR); void StartSpriteCombine(); void EndSpriteCombine(); bool HandleViewportClicked(const ViewPort *vp, int x, int y); void SetRedErrorSquare(TileIndex tile); void SetTileSelectSize(int w, int h); void SetTileSelectBigSize(int ox, int oy, int sx, int sy); void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom); bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant = false); bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant = false); void RebuildViewportOverlay(Window *w); bool ScrollMainWindowToTile(TileIndex tile, bool instant = false); bool ScrollMainWindowTo(int x, int y, int z = -1, bool instant = false); void UpdateAllVirtCoords(); extern Point _tile_fract_coords; void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset = 0); void MarkTileDirtyByTileOutsideMap(int x, int y); Point GetViewportStationMiddle(const ViewPort *vp, const Station *st); #endif /* VIEWPORT_FUNC_H */ openttd-1.5.3/src/settings_internal.h0000644000000000000000000001522712627373434016411 0ustar rootroot/* $Id: settings_internal.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 settings_internal.h Functions and types used internally for the settings configurations. */ #ifndef SETTINGS_INTERNAL_H #define SETTINGS_INTERNAL_H #include "saveload/saveload.h" /** * Convention/Type of settings. This is then further specified if necessary * with the SLE_ (SLE_VAR/SLE_FILE) enums in saveload.h * @see VarTypes * @see SettingDescBase */ enum SettingDescTypeLong { /* 4 bytes allocated a maximum of 16 types for GenericType */ SDT_BEGIN = 0, SDT_NUMX = 0, ///< any number-type SDT_BOOLX = 1, ///< a boolean number SDT_ONEOFMANY = 2, ///< bitmasked number where only ONE bit may be set SDT_MANYOFMANY = 3, ///< bitmasked number where MULTIPLE bits may be set SDT_INTLIST = 4, ///< list of integers separated by a comma ',' SDT_STRING = 5, ///< string with a pre-allocated buffer SDT_END, /* 10 more possible primitives */ }; typedef SimpleTinyEnumT SettingDescType; enum SettingGuiFlagLong { /* 1 byte allocated for a maximum of 8 flags * Flags directing saving/loading of a variable */ SGF_NONE = 0, SGF_0ISDISABLED = 1 << 0, ///< a value of zero means the feature is disabled SGF_DISPLAY_ABS = 1 << 1, ///< display absolute value of the setting SGF_MULTISTRING = 1 << 2, ///< the value represents a limited number of string-options (internally integer) SGF_NETWORK_ONLY = 1 << 3, ///< this setting only applies to network games SGF_CURRENCY = 1 << 4, ///< the number represents money, so when reading value multiply by exchange rate SGF_NO_NETWORK = 1 << 5, ///< this setting does not apply to network games; it may not be changed during the game SGF_NEWGAME_ONLY = 1 << 6, ///< this setting cannot be changed in a game SGF_SCENEDIT_TOO = 1 << 7, ///< this setting can be changed in the scenario editor (only makes sense when SGF_NEWGAME_ONLY is set) SGF_PER_COMPANY = 1 << 8, ///< this setting can be different for each company (saved in company struct) }; DECLARE_ENUM_AS_BIT_SET(SettingGuiFlagLong) typedef SimpleTinyEnumT SettingGuiFlag; /** * A SettingCategory defines a grouping of the settings. * The group #SC_BASIC is intended for settings which also a novice player would like to change and is able to understand. * The group #SC_ADVANCED is intended for settings which an experienced player would like to use. This is the case for most settings. * Finally #SC_EXPERT settings only few people want to see in rare cases. * The grouping is meant to be inclusive, i.e. all settings in #SC_BASIC also will be included * in the set of settings in #SC_ADVANCED. The group #SC_EXPERT contains all settings. */ enum SettingCategory { SC_NONE = 0, /* Filters for the list */ SC_BASIC_LIST = 1 << 0, ///< Settings displayed in the list of basic settings. SC_ADVANCED_LIST = 1 << 1, ///< Settings displayed in the list of advanced settings. SC_EXPERT_LIST = 1 << 2, ///< Settings displayed in the list of expert settings. /* Setting classification */ SC_BASIC = SC_BASIC_LIST | SC_ADVANCED_LIST | SC_EXPERT_LIST, ///< Basic settings are part of all lists. SC_ADVANCED = SC_ADVANCED_LIST | SC_EXPERT_LIST, ///< Advanced settings are part of advanced and expert list. SC_EXPERT = SC_EXPERT_LIST, ///< Expert settings can only be seen in the expert list. SC_END, }; /** * Type of settings for filtering. */ enum SettingType { ST_GAME, ///< Game setting. ST_COMPANY, ///< Company setting. ST_CLIENT, ///< Client setting. ST_ALL, ///< Used in setting filter to match all types. }; typedef bool OnChange(int32 var); ///< callback prototype on data modification typedef size_t OnConvert(const char *value); ///< callback prototype for conversion error /** Properties of config file settings. */ struct SettingDescBase { const char *name; ///< name of the setting. Used in configuration file and for console const void *def; ///< default value given when none is present SettingDescType cmd; ///< various flags for the variable SettingGuiFlag flags; ///< handles how a setting would show up in the GUI (text/currency, etc.) int32 min; ///< minimum values uint32 max; ///< maximum values int32 interval; ///< the interval to use between settings in the 'settings' window. If interval is '0' the interval is dynamically determined const char *many; ///< ONE/MANY_OF_MANY: string of possible values for this type StringID str; ///< (translated) string with descriptive text; gui and console StringID str_help; ///< (Translated) string with help text; gui only. StringID str_val; ///< (Translated) first string describing the value. OnChange *proc; ///< callback procedure for when the value is changed OnConvert *proc_cnvt; ///< callback procedure when loading value mechanism fails SettingCategory cat; ///< assigned categories of the setting }; struct SettingDesc { SettingDescBase desc; ///< Settings structure (going to configuration file) SaveLoad save; ///< Internal structure (going to savegame, parts to config) bool IsEditable(bool do_command = false) const; SettingType GetType() const; }; /* NOTE: The only difference between SettingDesc and SettingDescGlob is * that one uses global variables as a source and the other offsets * in a struct which are bound to a certain variable during runtime. * The only way to differentiate between these two is to check if an object * has been passed to the function or not. If not, then it is a global variable * and save->variable has its address, otherwise save->variable only holds the * offset in a certain struct */ typedef SettingDesc SettingDescGlobVarList; const SettingDesc *GetSettingFromName(const char *name, uint *i); bool SetSettingValue(uint index, int32 value, bool force_newgame = false); bool SetSettingValue(uint index, const char *value, bool force_newgame = false); void SetCompanySetting(uint index, int32 value); #endif /* SETTINGS_INTERNAL_H */ openttd-1.5.3/src/widget.cpp0000644000000000000000000033022012627373441014462 0ustar rootroot/* $Id: widget.cpp 27348 2015-07-30 18:45:29Z frosch $ */ /* * 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 widget.cpp Handling of the default/simple widgets. */ #include "stdafx.h" #include "company_func.h" #include "window_gui.h" #include "viewport_func.h" #include "zoom_func.h" #include "strings_func.h" #include "transparency.h" #include "core/geometry_func.hpp" #include "settings_type.h" #include "querystring_gui.h" #include "table/sprites.h" #include "table/strings.h" #include "table/palettes.h" #include "safeguards.h" /** * Compute the vertical position of the draggable part of scrollbar * @param sb Scrollbar list data * @param top Top position of the scrollbar (top position of the up-button) * @param bottom Bottom position of the scrollbar (bottom position of the down-button) * @param horizontal Whether the scrollbar is horizontal or not * @return A Point, with x containing the top coordinate of the draggable part, and * y containing the bottom coordinate of the draggable part */ static Point HandleScrollbarHittest(const Scrollbar *sb, int top, int bottom, bool horizontal) { /* Base for reversion */ int rev_base = top + bottom; int button_size; if (horizontal) { button_size = NWidgetScrollbar::GetHorizontalDimension().width; } else { button_size = NWidgetScrollbar::GetVerticalDimension().height; } top += button_size; // top points to just below the up-button bottom -= button_size; // bottom points to top of the down-button int height = (bottom - top); int pos = sb->GetPosition(); int count = sb->GetCount(); int cap = sb->GetCapacity(); if (count != 0) top += height * pos / count; if (cap > count) cap = count; if (count != 0) bottom -= (count - pos - cap) * height / count; Point pt; if (horizontal && _current_text_dir == TD_RTL) { pt.x = rev_base - bottom; pt.y = rev_base - top; } else { pt.x = top; pt.y = bottom; } return pt; } /** * Compute new position of the scrollbar after a click and updates the window flags. * @param w Window on which a scroll was performed. * @param sb Scrollbar * @param mi Minimum coordinate of the scroll bar. * @param ma Maximum coordinate of the scroll bar. * @param x The X coordinate of the mouse click. * @param y The Y coordinate of the mouse click. */ static void ScrollbarClickPositioning(Window *w, NWidgetScrollbar *sb, int x, int y, int mi, int ma) { int pos; int button_size; bool rtl = false; if (sb->type == NWID_HSCROLLBAR) { pos = x; rtl = _current_text_dir == TD_RTL; button_size = NWidgetScrollbar::GetHorizontalDimension().width; } else { pos = y; button_size = NWidgetScrollbar::GetVerticalDimension().height; } if (pos < mi + button_size) { /* Pressing the upper button? */ SetBit(sb->disp_flags, NDB_SCROLLBAR_UP); if (_scroller_click_timeout <= 1) { _scroller_click_timeout = 3; sb->UpdatePosition(rtl ? 1 : -1); } w->scrolling_scrollbar = sb->index; } else if (pos >= ma - button_size) { /* Pressing the lower button? */ SetBit(sb->disp_flags, NDB_SCROLLBAR_DOWN); if (_scroller_click_timeout <= 1) { _scroller_click_timeout = 3; sb->UpdatePosition(rtl ? -1 : 1); } w->scrolling_scrollbar = sb->index; } else { Point pt = HandleScrollbarHittest(sb, mi, ma, sb->type == NWID_HSCROLLBAR); if (pos < pt.x) { sb->UpdatePosition(rtl ? 1 : -1, Scrollbar::SS_BIG); } else if (pos > pt.y) { sb->UpdatePosition(rtl ? -1 : 1, Scrollbar::SS_BIG); } else { _scrollbar_start_pos = pt.x - mi - button_size; _scrollbar_size = ma - mi - button_size * 2; w->scrolling_scrollbar = sb->index; _cursorpos_drag_start = _cursor.pos; } } w->SetDirty(); } /** * Special handling for the scrollbar widget type. * Handles the special scrolling buttons and other scrolling. * @param w Window on which a scroll was performed. * @param nw Pointer to the scrollbar widget. * @param x The X coordinate of the mouse click. * @param y The Y coordinate of the mouse click. */ void ScrollbarClickHandler(Window *w, NWidgetCore *nw, int x, int y) { int mi, ma; if (nw->type == NWID_HSCROLLBAR) { mi = nw->pos_x; ma = nw->pos_x + nw->current_x; } else { mi = nw->pos_y; ma = nw->pos_y + nw->current_y; } NWidgetScrollbar *scrollbar = dynamic_cast(nw); assert(scrollbar != NULL); ScrollbarClickPositioning(w, scrollbar, x, y, mi, ma); } /** * Returns the index for the widget located at the given position * relative to the window. It includes all widget-corner pixels as well. * @param *w Window to look inside * @param x The Window client X coordinate * @param y The Window client y coordinate * @return A widget index, or -1 if no widget was found. */ int GetWidgetFromPos(const Window *w, int x, int y) { NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); return (nw != NULL) ? nw->index : -1; } /** * Draw frame rectangle. * @param left Left edge of the frame * @param top Top edge of the frame * @param right Right edge of the frame * @param bottom Bottom edge of the frame * @param colour Colour table to use. @see _colour_gradient * @param flags Flags controlling how to draw the frame. @see FrameFlags */ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags) { assert(colour < COLOUR_END); uint dark = _colour_gradient[colour][3]; uint medium_dark = _colour_gradient[colour][5]; uint medium_light = _colour_gradient[colour][6]; uint light = _colour_gradient[colour][7]; if (flags & FR_TRANSPARENT) { GfxFillRect(left, top, right, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR); } else { uint interior; if (flags & FR_LOWERED) { GfxFillRect(left, top, left, bottom, dark); GfxFillRect(left + WD_BEVEL_LEFT, top, right, top, dark); GfxFillRect(right, top + WD_BEVEL_TOP, right, bottom - WD_BEVEL_BOTTOM, light); GfxFillRect(left + WD_BEVEL_LEFT, bottom, right, bottom, light); interior = (flags & FR_DARKENED ? medium_dark : medium_light); } else { GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, light); GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, light); GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, dark); GfxFillRect(left, bottom, right, bottom, dark); interior = medium_dark; } if (!(flags & FR_BORDERONLY)) { GfxFillRect(left + WD_BEVEL_LEFT, top + WD_BEVEL_TOP, right - WD_BEVEL_RIGHT, bottom - WD_BEVEL_BOTTOM, interior); } } } /** * Draw an image button. * @param r Rectangle of the button. * @param type Widget type (#WWT_IMGBTN or #WWT_IMGBTN_2). * @param colour Colour of the button. * @param clicked Button is lowered. * @param img Sprite to draw. */ static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img) { assert(img != 0); DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; // Show different image when clicked for #WWT_IMGBTN_2. DrawSprite(img, PAL_NONE, r.left + WD_IMGBTN_LEFT + clicked, r.top + WD_IMGBTN_TOP + clicked); } /** * Draw the label-part of a widget. * @param r Rectangle of the label background. * @param type Widget type (#WWT_TEXTBTN, #WWT_TEXTBTN_2, or #WWT_LABEL). * @param clicked Label is rendered lowered. * @param str Text to draw. */ static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, StringID str) { if (str == STR_NULL) return; if ((type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; Dimension d = GetStringBoundingBox(str); int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered DrawString(r.left + clicked, r.right + clicked, r.top + offset + clicked, str, TC_FROMSTRING, SA_HOR_CENTER); } /** * Draw text. * @param r Rectangle of the background. * @param colour Colour of the text. * @param str Text to draw. */ static inline void DrawText(const Rect &r, TextColour colour, StringID str) { Dimension d = GetStringBoundingBox(str); int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered if (str != STR_NULL) DrawString(r.left, r.right, r.top + offset, str, colour); } /** * Draw an inset widget. * @param r Rectangle of the background. * @param colour Colour of the inset. * @param str Text to draw. */ static inline void DrawInset(const Rect &r, Colours colour, StringID str) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_LOWERED | FR_DARKENED); if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str); } /** * Draw a matrix widget. * @param r Rectangle of the matrix background. * @param colour Colour of the background. * @param clicked Matrix is rendered lowered. * @param data Data of the widget, number of rows and columns of the widget. * @param resize_x Matrix resize unit size. * @param resize_y Matrix resize unit size. */ static inline void DrawMatrix(const Rect &r, Colours colour, bool clicked, uint16 data, uint resize_x, uint resize_y) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); int num_columns = GB(data, MAT_COL_START, MAT_COL_BITS); // Lower 8 bits of the widget data: Number of columns in the matrix. int column_width; // Width of a single column in the matrix. if (num_columns == 0) { column_width = resize_x; num_columns = (r.right - r.left + 1) / column_width; } else { column_width = (r.right - r.left + 1) / num_columns; } int num_rows = GB(data, MAT_ROW_START, MAT_ROW_BITS); // Upper 8 bits of the widget data: Number of rows in the matrix. int row_height; // Height of a single row in the matrix. if (num_rows == 0) { row_height = resize_y; num_rows = (r.bottom - r.top + 1) / row_height; } else { row_height = (r.bottom - r.top + 1) / num_rows; } int col = _colour_gradient[colour & 0xF][6]; int x = r.left; for (int ctr = num_columns; ctr > 1; ctr--) { x += column_width; GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); } x = r.top; for (int ctr = num_rows; ctr > 1; ctr--) { x += row_height; GfxFillRect(r.left + 1, x, r.right - 1, x, col); } col = _colour_gradient[colour & 0xF][4]; x = r.left - 1; for (int ctr = num_columns; ctr > 1; ctr--) { x += column_width; GfxFillRect(x, r.top + 1, x, r.bottom - 1, col); } x = r.top - 1; for (int ctr = num_rows; ctr > 1; ctr--) { x += row_height; GfxFillRect(r.left + 1, x, r.right - 1, x, col); } } /** * Draw a vertical scrollbar. * @param r Rectangle of the scrollbar widget. * @param colour Colour of the scrollbar widget. * @param up_clicked Up-arrow is clicked. * @param bar_dragged Bar is dragged. * @param down_clicked Down-arrow is clicked. * @param scrollbar Scrollbar size, offset, and capacity information. */ static inline void DrawVerticalScrollbar(const Rect &r, Colours colour, bool up_clicked, bool bar_dragged, bool down_clicked, const Scrollbar *scrollbar) { int centre = (r.right - r.left) / 2; int height = NWidgetScrollbar::GetVerticalDimension().height; /* draw up/down buttons */ DrawFrameRect(r.left, r.top, r.right, r.top + height - 1, colour, (up_clicked) ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_UP, PAL_NONE, r.left + 1 + up_clicked, r.top + 1 + up_clicked); DrawFrameRect(r.left, r.bottom - (height - 1), r.right, r.bottom, colour, (down_clicked) ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_DOWN, PAL_NONE, r.left + 1 + down_clicked, r.bottom - (height - 2) + down_clicked); int c1 = _colour_gradient[colour & 0xF][3]; int c2 = _colour_gradient[colour & 0xF][7]; /* draw "shaded" background */ GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c2); GfxFillRect(r.left, r.top + height, r.right, r.bottom - height, c1, FILLRECT_CHECKER); /* draw shaded lines */ GfxFillRect(r.left + centre - 3, r.top + height, r.left + centre - 3, r.bottom - height, c1); GfxFillRect(r.left + centre - 2, r.top + height, r.left + centre - 2, r.bottom - height, c2); GfxFillRect(r.left + centre + 2, r.top + height, r.left + centre + 2, r.bottom - height, c1); GfxFillRect(r.left + centre + 3, r.top + height, r.left + centre + 3, r.bottom - height, c2); Point pt = HandleScrollbarHittest(scrollbar, r.top, r.bottom, false); DrawFrameRect(r.left, pt.x, r.right, pt.y, colour, bar_dragged ? FR_LOWERED : FR_NONE); } /** * Draw a horizontal scrollbar. * @param r Rectangle of the scrollbar widget. * @param colour Colour of the scrollbar widget. * @param left_clicked Left-arrow is clicked. * @param bar_dragged Bar is dragged. * @param right_clicked Right-arrow is clicked. * @param scrollbar Scrollbar size, offset, and capacity information. */ static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool left_clicked, bool bar_dragged, bool right_clicked, const Scrollbar *scrollbar) { int centre = (r.bottom - r.top) / 2; int width = NWidgetScrollbar::GetHorizontalDimension().width; DrawFrameRect(r.left, r.top, r.left + width - 1, r.bottom, colour, left_clicked ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + left_clicked, r.top + 1 + left_clicked); DrawFrameRect(r.right - (width - 1), r.top, r.right, r.bottom, colour, right_clicked ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - (width - 2) + right_clicked, r.top + 1 + right_clicked); int c1 = _colour_gradient[colour & 0xF][3]; int c2 = _colour_gradient[colour & 0xF][7]; /* draw "shaded" background */ GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c2); GfxFillRect(r.left + width, r.top, r.right - width, r.bottom, c1, FILLRECT_CHECKER); /* draw shaded lines */ GfxFillRect(r.left + width, r.top + centre - 3, r.right - width, r.top + centre - 3, c1); GfxFillRect(r.left + width, r.top + centre - 2, r.right - width, r.top + centre - 2, c2); GfxFillRect(r.left + width, r.top + centre + 2, r.right - width, r.top + centre + 2, c1); GfxFillRect(r.left + width, r.top + centre + 3, r.right - width, r.top + centre + 3, c2); /* draw actual scrollbar */ Point pt = HandleScrollbarHittest(scrollbar, r.left, r.right, true); DrawFrameRect(pt.x, r.top, pt.y, r.bottom, colour, bar_dragged ? FR_LOWERED : FR_NONE); } /** * Draw a frame widget. * @param r Rectangle of the frame. * @param colour Colour of the frame. * @param str Text of the frame. */ static inline void DrawFrame(const Rect &r, Colours colour, StringID str) { int x2 = r.left; // by default the left side is the left side of the widget if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str); int c1 = _colour_gradient[colour][3]; int c2 = _colour_gradient[colour][7]; /* If the frame has text, adjust the top bar to fit half-way through */ int dy1 = 4; if (str != STR_NULL) dy1 = FONT_HEIGHT_NORMAL / 2 - 1; int dy2 = dy1 + 1; if (_current_text_dir == TD_LTR) { /* Line from upper left corner to start of text */ GfxFillRect(r.left, r.top + dy1, r.left + 4, r.top + dy1, c1); GfxFillRect(r.left + 1, r.top + dy2, r.left + 4, r.top + dy2, c2); /* Line from end of text to upper right corner */ GfxFillRect(x2, r.top + dy1, r.right - 1, r.top + dy1, c1); GfxFillRect(x2, r.top + dy2, r.right - 2, r.top + dy2, c2); } else { /* Line from upper left corner to start of text */ GfxFillRect(r.left, r.top + dy1, x2 - 2, r.top + dy1, c1); GfxFillRect(r.left + 1, r.top + dy2, x2 - 2, r.top + dy2, c2); /* Line from end of text to upper right corner */ GfxFillRect(r.right - 5, r.top + dy1, r.right - 1, r.top + dy1, c1); GfxFillRect(r.right - 5, r.top + dy2, r.right - 2, r.top + dy2, c2); } /* Line from upper left corner to bottom left corner */ GfxFillRect(r.left, r.top + dy2, r.left, r.bottom - 1, c1); GfxFillRect(r.left + 1, r.top + dy2 + 1, r.left + 1, r.bottom - 2, c2); /* Line from upper right corner to bottom right corner */ GfxFillRect(r.right - 1, r.top + dy2, r.right - 1, r.bottom - 2, c1); GfxFillRect(r.right, r.top + dy1, r.right, r.bottom - 1, c2); GfxFillRect(r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1, c1); GfxFillRect(r.left, r.bottom, r.right, r.bottom, c2); } /** * Draw a shade box. * @param r Rectangle of the box. * @param colour Colour of the shade box. * @param clicked Box is lowered. */ static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); DrawSprite((clicked) ? SPR_WINDOW_SHADE : SPR_WINDOW_UNSHADE, PAL_NONE, r.left + WD_SHADEBOX_LEFT + clicked, r.top + WD_SHADEBOX_TOP + clicked); } /** * Draw a sticky box. * @param r Rectangle of the box. * @param colour Colour of the sticky box. * @param clicked Box is lowered. */ static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + WD_STICKYBOX_LEFT + clicked, r.top + WD_STICKYBOX_TOP + clicked); } /** * Draw a defsize box. * @param r Rectangle of the box. * @param colour Colour of the defsize box. * @param clicked Box is lowered. */ static inline void DrawDefSizeBox(const Rect &r, Colours colour, bool clicked) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); DrawSprite(SPR_WINDOW_DEFSIZE, PAL_NONE, r.left + WD_DEFSIZEBOX_LEFT + clicked, r.top + WD_DEFSIZEBOX_TOP + clicked); } /** * Draw a NewGRF debug box. * @param r Rectangle of the box. * @param colour Colour of the debug box. * @param clicked Box is lowered. */ static inline void DrawDebugBox(const Rect &r, Colours colour, bool clicked) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); DrawSprite(SPR_WINDOW_DEBUG, PAL_NONE, r.left + WD_DEBUGBOX_LEFT + clicked, r.top + WD_DEBUGBOX_TOP + clicked); } /** * Draw a resize box. * @param r Rectangle of the box. * @param colour Colour of the resize box. * @param at_left Resize box is at left-side of the window, * @param clicked Box is lowered. */ static inline void DrawResizeBox(const Rect &r, Colours colour, bool at_left, bool clicked) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); if (at_left) { DrawSprite(SPR_WINDOW_RESIZE_LEFT, PAL_NONE, r.left + WD_RESIZEBOX_RIGHT + clicked, r.bottom - WD_RESIZEBOX_BOTTOM - GetSpriteSize(SPR_WINDOW_RESIZE_LEFT).height + clicked); } else { DrawSprite(SPR_WINDOW_RESIZE_RIGHT, PAL_NONE, r.left + WD_RESIZEBOX_LEFT + clicked, r.bottom - WD_RESIZEBOX_BOTTOM - GetSpriteSize(SPR_WINDOW_RESIZE_RIGHT).height + clicked); } } /** * Draw a close box. * @param r Rectangle of the box. * @param colour Colour of the close box. */ static inline void DrawCloseBox(const Rect &r, Colours colour) { if (colour != COLOUR_WHITE) DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_NONE); DrawSprite(SPR_CLOSEBOX, (colour != COLOUR_WHITE ? TC_BLACK : TC_SILVER) | (1 << PALETTE_TEXT_RECOLOUR), r.left + WD_CLOSEBOX_LEFT, r.top + WD_CLOSEBOX_TOP); } /** * Draw a caption bar. * @param r Rectangle of the bar. * @param colour Colour of the window. * @param owner 'Owner' of the window. * @param str Text to draw in the bar. */ void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str) { bool company_owned = owner < MAX_COMPANIES; DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_BORDERONLY); DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, colour, company_owned ? FR_LOWERED | FR_DARKENED | FR_BORDERONLY : FR_LOWERED | FR_DARKENED); if (company_owned) { GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_company_colours[owner]][4]); } if (str != STR_NULL) { Dimension d = GetStringBoundingBox(str); int offset = max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, r.top + offset, str, TC_FROMSTRING, SA_HOR_CENTER); } } /** * Draw a button with a dropdown (#WWT_DROPDOWN and #NWID_BUTTON_DROPDOWN). * @param r Rectangle containing the widget. * @param colour Background colour of the widget. * @param clicked_button The button-part is lowered. * @param clicked_dropdown The drop-down part is lowered. * @param str Text of the button. * * @note Magic constants are also used in #NWidgetLeaf::ButtonHit. */ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str) { int text_offset = max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered int dd_width = NWidgetLeaf::dropdown_dimension.width; int dd_height = NWidgetLeaf::dropdown_dimension.height; int image_offset = max(0, ((int)(r.bottom - r.top + 1) - dd_height) / 2); if (_current_text_dir == TD_LTR) { DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); DrawFrameRect(r.right + 1 - dd_width, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_DOWN, PAL_NONE, r.right - (dd_width - 2) + clicked_dropdown, r.top + image_offset + clicked_dropdown); if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); } else { DrawFrameRect(r.left + dd_width, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); DrawFrameRect(r.left, r.top, r.left + dd_width - 1, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_DOWN, PAL_NONE, r.left + 1 + clicked_dropdown, r.top + image_offset + clicked_dropdown); if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); } } /** * Draw a dropdown #WWT_DROPDOWN widget. * @param r Rectangle containing the widget. * @param colour Background colour of the widget. * @param clicked The widget is lowered. * @param str Text of the button. */ static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str) { DrawButtonDropdown(r, colour, false, clicked, str); } /** * Paint all widgets of a window. */ void Window::DrawWidgets() const { this->nested_root->Draw(this); if (this->flags & WF_WHITE_BORDER) { DrawFrameRect(0, 0, this->width - 1, this->height - 1, COLOUR_WHITE, FR_BORDERONLY); } if (this->flags & WF_HIGHLIGHTED) { extern bool _window_highlight_colour; for (uint i = 0; i < this->nested_array_size; i++) { const NWidgetBase *widget = this->GetWidget(i); if (widget == NULL || !widget->IsHighlighted()) continue; int left = widget->pos_x; int top = widget->pos_y; int right = left + widget->current_x - 1; int bottom = top + widget->current_y - 1; int colour = _string_colourmap[_window_highlight_colour ? widget->GetHighlightColour() : TC_WHITE]; GfxFillRect(left, top, left, bottom - WD_BEVEL_BOTTOM, colour); GfxFillRect(left + WD_BEVEL_LEFT, top, right - WD_BEVEL_RIGHT, top, colour); GfxFillRect(right, top, right, bottom - WD_BEVEL_BOTTOM, colour); GfxFillRect(left, bottom, right, bottom, colour); } } } /** * Draw a sort button's up or down arrow symbol. * @param widget Sort button widget * @param state State of sort button */ void Window::DrawSortButtonState(int widget, SortButtonState state) const { if (state == SBS_OFF) return; assert(this->nested_array != NULL); const NWidgetBase *nwid = this->GetWidget(widget); /* Sort button uses the same sprites as vertical scrollbar */ Dimension dim = NWidgetScrollbar::GetVerticalDimension(); int offset = this->IsWidgetLowered(widget) ? 1 : 0; int x = offset + nwid->pos_x + (_current_text_dir == TD_LTR ? nwid->current_x - dim.width : 0); int y = offset + nwid->pos_y + (nwid->current_y - dim.height) / 2; DrawSprite(state == SBS_DOWN ? SPR_ARROW_DOWN : SPR_ARROW_UP, PAL_NONE, x, y); } /** * Get width of up/down arrow of sort button state. * @return Width of space required by sort button arrow. */ int Window::SortButtonWidth() { return NWidgetScrollbar::GetVerticalDimension().width + 1; } /** * @defgroup NestedWidgets Hierarchical widgets * Hierarchical widgets, also known as nested widgets, are widgets stored in a tree. At the leafs of the tree are (mostly) the 'real' widgets * visible to the user. At higher levels, widgets get organized in container widgets, until all widgets of the window are merged. * * \section nestedwidgetkinds Hierarchical widget kinds * A leaf widget is one of *

* The purpose of a leaf widget is to provide interaction with the user by displaying settings, and/or allowing changing the settings. * * A container widget is one of *
    *
  • #NWidgetHorizontal for organizing child widgets in a (horizontal) row. The row switches order depending on the language setting (thus supporting * right-to-left languages), *
  • #NWidgetHorizontalLTR for organizing child widgets in a (horizontal) row, always in the same order. All children below this container will also * never swap order. *
  • #NWidgetVertical for organizing child widgets underneath each other. *
  • #NWidgetMatrix for organizing child widgets in a matrix form. *
  • #NWidgetBackground for adding a background behind its child widget. *
  • #NWidgetStacked for stacking child widgets on top of each other. *
* The purpose of a container widget is to structure its leafs and sub-containers to allow proper resizing. * * \section nestedwidgetscomputations Hierarchical widget computations * The first 'computation' is the creation of the nested widgets tree by calling the constructors of the widgets listed above and calling \c Add() for every child, * or by means of specifying the tree as a collection of nested widgets parts and instantiating the tree from the array. * * After the creation step, * - The leafs have their own minimal size (\e min_x, \e min_y), filling (\e fill_x, \e fill_y), and resize steps (\e resize_x, \e resize_y). * - Containers only know what their children are, \e fill_x, \e fill_y, \e resize_x, and \e resize_y are not initialized. * * Computations in the nested widgets take place as follows: *
    *
  1. A bottom-up sweep by recursively calling NWidgetBase::SetupSmallestSize() to initialize the smallest size (\e smallest_x, \e smallest_y) and * to propagate filling and resize steps upwards to the root of the tree. *
  2. A top-down sweep by recursively calling NWidgetBase::AssignSizePosition() with #ST_SMALLEST to make the smallest sizes consistent over * the entire tree, and to assign the top-left (\e pos_x, \e pos_y) position of each widget in the tree. This step uses \e fill_x and \e fill_y at each * node in the tree to decide how to fill each widget towards consistent sizes. Also the current size (\e current_x and \e current_y) is set. *
  3. After initializing the smallest size in the widget tree with #ST_SMALLEST, the tree can be resized (the current size modified) by calling * NWidgetBase::AssignSizePosition() at the root with #ST_RESIZE and the new size of the window. For proper functioning, the new size should be the smallest * size + a whole number of resize steps in both directions (ie you can only resize in steps of length resize_{x,y} from smallest_{x,y}). *
* After the second step, the current size of the widgets are set to the smallest size. * * To resize, perform the last step with the new window size. This can be done as often as desired. * When the smallest size of at least one widget changes, the whole procedure has to be redone from the start. * * @see NestedWidgetParts */ /** * Base class constructor. * @param tp Nested widget type. */ NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator() { this->type = tp; } /* ~NWidgetContainer() takes care of #next and #prev data members. */ /** * @fn void NWidgetBase::SetupSmallestSize(Window *w, bool init_array) * Compute smallest size needed by the widget. * * The smallest size of a widget is the smallest size that a widget needs to * display itself properly. In addition, filling and resizing of the widget are computed. * The function calls #Window::UpdateWidgetSize for each leaf widget and * background widget without child with a non-negative index. * * @param w Window owning the widget. * @param init_array Initialize the \c w->nested_array. * * @note After the computation, the results can be queried by accessing the #smallest_x and #smallest_y data members of the widget. */ /** * @fn void NWidgetBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) * Assign size and position to the widget. * @param sizing Type of resizing to perform. * @param x Horizontal offset of the widget relative to the left edge of the window. * @param y Vertical offset of the widget relative to the top edge of the window. * @param given_width Width allocated to the widget. * @param given_height Height allocated to the widget. * @param rtl Adapt for right-to-left languages (position contents of horizontal containers backwards). * * Afterwards, \e pos_x and \e pos_y contain the top-left position of the widget, \e smallest_x and \e smallest_y contain * the smallest size such that all widgets of the window are consistent, and \e current_x and \e current_y contain the current size. */ /** * @fn void FillNestedArray(NWidgetBase **array, uint length) * Fill the Window::nested_array array with pointers to nested widgets in the tree. * @param array Base pointer of the array. * @param length Length of the array. */ /** * @fn void NWidgetBase::Draw(const Window *w) * Draw the widgets of the tree. * The function calls #Window::DrawWidget for each widget with a non-negative index, after the widget itself is painted. * @param w Window that owns the tree. */ /** * Mark the widget as 'dirty' (in need of repaint). * @param w Window owning the widget. */ void NWidgetBase::SetDirty(const Window *w) const { int abs_left = w->left + this->pos_x; int abs_top = w->top + this->pos_y; SetDirtyBlocks(abs_left, abs_top, abs_left + this->current_x, abs_top + this->current_y); } /** * @fn NWidgetCore *NWidgetBase::GetWidgetFromPos(int x, int y) * Retrieve a widget by its position. * @param x Horizontal position relative to the left edge of the window. * @param y Vertical position relative to the top edge of the window. * @return Returns the deepest nested widget that covers the given position, or \c NULL if no widget can be found. */ /** * Retrieve a widget by its type. * @param tp Widget type to search for. * @return Returns the first widget of the specified type, or \c NULL if no widget can be found. */ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) { return (this->type == tp) ? this : NULL; } /** * Constructor for resizable nested widgets. * @param tp Nested widget type. * @param fill_x Horizontal fill step size, \c 0 means no filling is allowed. * @param fill_y Vertical fill step size, \c 0 means no filling is allowed. */ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : NWidgetBase(tp) { this->fill_x = fill_x; this->fill_y = fill_y; } /** * Set minimal size of the widget. * @param min_x Horizontal minimal size of the widget. * @param min_y Vertical minimal size of the widget. */ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) { this->min_x = max(this->min_x, min_x); this->min_y = max(this->min_y, min_y); } /** * Set minimal text lines for the widget. * @param min_lines Number of text lines of the widget. * @param spacing Extra spacing (eg WD_FRAMERECT_TOP + _BOTTOM) of the widget. * @param size Font size of text. */ void NWidgetResizeBase::SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size) { this->min_y = min_lines * GetCharacterHeight(size) + spacing; } /** * Set the filling of the widget from initial size. * @param fill_x Horizontal fill step size, \c 0 means no filling is allowed. * @param fill_y Vertical fill step size, \c 0 means no filling is allowed. */ void NWidgetResizeBase::SetFill(uint fill_x, uint fill_y) { this->fill_x = fill_x; this->fill_y = fill_y; } /** * Set resize step of the widget. * @param resize_x Resize step in horizontal direction, value \c 0 means no resize, otherwise the step size in pixels. * @param resize_y Resize step in vertical direction, value \c 0 means no resize, otherwise the step size in pixels. */ void NWidgetResizeBase::SetResize(uint resize_x, uint resize_y) { this->resize_x = resize_x; this->resize_y = resize_y; } void NWidgetResizeBase::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { this->StoreSizePosition(sizing, x, y, given_width, given_height); } /** * Initialization of a 'real' widget. * @param tp Type of the widget. * @param colour Colour of the widget. * @param fill_x Default horizontal filling. * @param fill_y Default vertical filling. * @param widget_data Data component of the widget. @see Widget::data * @param tool_tip Tool tip of the widget. @see Widget::tooltips */ NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip) : NWidgetResizeBase(tp, fill_x, fill_y) { this->colour = colour; this->index = -1; this->widget_data = widget_data; this->tool_tip = tool_tip; this->scrollbar_index = -1; } /** * Set index of the nested widget in the widget array. * @param index Index to use. */ void NWidgetCore::SetIndex(int index) { assert(index >= 0); this->index = index; } /** * Set data and tool tip of the nested widget. * @param widget_data Data to use. * @param tool_tip Tool tip string to use. */ void NWidgetCore::SetDataTip(uint32 widget_data, StringID tool_tip) { this->widget_data = widget_data; this->tool_tip = tool_tip; } void NWidgetCore::FillNestedArray(NWidgetBase **array, uint length) { if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; } NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y) { return (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) ? this : NULL; } /** * Constructor container baseclass. * @param tp Type of the container. */ NWidgetContainer::NWidgetContainer(WidgetType tp) : NWidgetBase(tp) { this->head = NULL; this->tail = NULL; } NWidgetContainer::~NWidgetContainer() { while (this->head != NULL) { NWidgetBase *wid = this->head->next; delete this->head; this->head = wid; } this->tail = NULL; } NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) { if (this->type == tp) return this; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { NWidgetBase *nwid = child_wid->GetWidgetOfType(tp); if (nwid != NULL) return nwid; } return NULL; } /** * Append widget \a wid to container. * @param wid Widget to append. */ void NWidgetContainer::Add(NWidgetBase *wid) { assert(wid->next == NULL && wid->prev == NULL); if (this->head == NULL) { this->head = wid; this->tail = wid; } else { assert(this->tail != NULL); assert(this->tail->next == NULL); this->tail->next = wid; wid->prev = this->tail; this->tail = wid; } } void NWidgetContainer::FillNestedArray(NWidgetBase **array, uint length) { for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->FillNestedArray(array, length); } } /** * Widgets stacked on top of each other. */ NWidgetStacked::NWidgetStacked() : NWidgetContainer(NWID_SELECTION) { this->index = -1; } void NWidgetStacked::SetIndex(int index) { this->index = index; } void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array) { if (this->index >= 0 && init_array) { // Fill w->nested_array[] assert(w->nested_array_size > (uint)this->index); w->nested_array[this->index] = this; } /* Zero size plane selected */ if (this->shown_plane >= SZSP_BEGIN) { Dimension size = {0, 0}; Dimension padding = {0, 0}; Dimension fill = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)}; Dimension resize = {(this->shown_plane == SZSP_HORIZONTAL), (this->shown_plane == SZSP_VERTICAL)}; /* Here we're primarily interested in the value of resize */ if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize); this->smallest_x = size.width; this->smallest_y = size.height; this->fill_x = fill.width; this->fill_y = fill.height; this->resize_x = resize.width; this->resize_y = resize.height; return; } /* First sweep, recurse down and compute minimal size and filling. */ this->smallest_x = 0; this->smallest_y = 0; this->fill_x = (this->head != NULL) ? 1 : 0; this->fill_y = (this->head != NULL) ? 1 : 0; this->resize_x = (this->head != NULL) ? 1 : 0; this->resize_y = (this->head != NULL) ? 1 : 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x); this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y); this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); } } void NWidgetStacked::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); this->StoreSizePosition(sizing, x, y, given_width, given_height); if (this->shown_plane >= SZSP_BEGIN) return; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); uint child_width = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step); uint child_pos_x = (rtl ? child_wid->padding_right : child_wid->padding_left); uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing); uint child_height = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step); uint child_pos_y = child_wid->padding_top; child_wid->AssignSizePosition(sizing, x + child_pos_x, y + child_pos_y, child_width, child_height, rtl); } } void NWidgetStacked::FillNestedArray(NWidgetBase **array, uint length) { if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; NWidgetContainer::FillNestedArray(array, length); } void NWidgetStacked::Draw(const Window *w) { if (this->shown_plane >= SZSP_BEGIN) return; int plane = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { if (plane == this->shown_plane) { child_wid->Draw(w); return; } } NOT_REACHED(); } NWidgetCore *NWidgetStacked::GetWidgetFromPos(int x, int y) { if (this->shown_plane >= SZSP_BEGIN) return NULL; if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; int plane = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; plane++, child_wid = child_wid->next) { if (plane == this->shown_plane) { return child_wid->GetWidgetFromPos(x, y); } } return NULL; } /** * Select which plane to show (for #NWID_SELECTION only). * @param plane Plane number to display. */ void NWidgetStacked::SetDisplayedPlane(int plane) { this->shown_plane = plane; } NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags) : NWidgetContainer(tp) { this->flags = flags; } /** * Set additional pre/inter/post space for the container. * * @param pip_pre Additional space in front of the first child widget (above * for the vertical container, at the left for the horizontal container). * @param pip_inter Additional space between two child widgets. * @param pip_post Additional space after the last child widget (below for the * vertical container, at the right for the horizontal container). */ void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) { this->pip_pre = pip_pre; this->pip_inter = pip_inter; this->pip_post = pip_post; } void NWidgetPIPContainer::Draw(const Window *w) { for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->Draw(w); } } NWidgetCore *NWidgetPIPContainer::GetWidgetFromPos(int x, int y) { if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); if (nwid != NULL) return nwid; } return NULL; } /** Horizontal container widget. */ NWidgetHorizontal::NWidgetHorizontal(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_HORIZONTAL, flags) { } void NWidgetHorizontal::SetupSmallestSize(Window *w, bool init_array) { this->smallest_x = 0; // Sum of minimal size of all children. this->smallest_y = 0; // Biggest child. this->fill_x = 0; // smallest non-zero child widget fill step. this->fill_y = 1; // smallest common child fill step. this->resize_x = 0; // smallest non-zero child widget resize step. this->resize_y = 1; // smallest common child resize step. /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ uint longest = 0; // Longest child found. uint max_vert_fill = 0; // Biggest vertical fill step. for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); longest = max(longest, child_wid->smallest_x); max_vert_fill = max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST)); this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); } /* 1b. Make the container higher if needed to accommodate all children nicely. */ uint max_smallest = this->smallest_y + 3 * max_vert_fill; // Upper limit to computing smallest height. uint cur_height = this->smallest_y; for (;;) { for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint step_size = child_wid->GetVerticalStepSize(ST_SMALLEST); uint child_height = child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; if (step_size > 1 && child_height < cur_height) { // Small step sizes or already fitting children are not interesting. uint remainder = (cur_height - child_height) % step_size; if (remainder > 0) { // Child did not fit entirely, widen the container. cur_height += step_size - remainder; assert(cur_height < max_smallest); // Safeguard against infinite height expansion. /* Remaining children will adapt to the new cur_height, thus speeding up the computation. */ } } } if (this->smallest_y == cur_height) break; this->smallest_y = cur_height; // Smallest height got changed, try again. } /* 2. For containers that must maintain equal width, extend child minimal size. */ if (this->flags & NC_EQUALSIZE) { for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (child_wid->fill_x == 1) child_wid->smallest_x = longest; } } /* 3. Move PIP space to the children, compute smallest, fill, and resize values of the container. */ if (this->head != NULL) this->head->padding_left += this->pip_pre; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (child_wid->next != NULL) { child_wid->padding_right += this->pip_inter; } else { child_wid->padding_right += this->pip_post; } this->smallest_x += child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right; if (child_wid->fill_x > 0) { if (this->fill_x == 0 || this->fill_x > child_wid->fill_x) this->fill_x = child_wid->fill_x; } this->fill_y = LeastCommonMultiple(this->fill_y, child_wid->fill_y); if (child_wid->resize_x > 0) { if (this->resize_x == 0 || this->resize_x > child_wid->resize_x) this->resize_x = child_wid->resize_x; } this->resize_y = LeastCommonMultiple(this->resize_y, child_wid->resize_y); } /* We need to zero the PIP settings so we can re-initialize the tree. */ this->pip_pre = this->pip_inter = this->pip_post = 0; } void NWidgetHorizontal::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); /* Compute additional width given to us. */ uint additional_length = given_width; if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { /* For EQUALSIZE containers this does not sum to smallest_x during initialisation */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { additional_length -= child_wid->smallest_x + child_wid->padding_right + child_wid->padding_left; } } else { additional_length -= this->smallest_x; } this->StoreSizePosition(sizing, x, y, given_width, given_height); /* In principle, the additional horizontal space is distributed evenly over the available resizable children. Due to step sizes, this may not always be feasible. * To make resizing work as good as possible, first children with biggest step sizes are done. These may get less due to rounding down. * This additional space is then given to children with smaller step sizes. This will give a good result when resize steps of each child is a multiple * of the child with the smallest non-zero stepsize. * * Since child sizes are computed out of order, positions cannot be calculated until all sizes are known. That means it is not possible to compute the child * size and position, and directly call child->AssignSizePosition() with the computed values. * Instead, computed child widths and heights are stored in child->current_x and child->current_y values. That is allowed, since this method overwrites those values * then we call the child. */ /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle vertical size for all children, * handle horizontal size for non-resizing children. */ int num_changing_childs = 0; // Number of children that can change size. uint biggest_stepsize = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step > 0) { num_changing_childs++; biggest_stepsize = max(biggest_stepsize, hor_step); } else { child_wid->current_x = child_wid->smallest_x; } uint vert_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetVerticalStepSize(sizing); child_wid->current_y = ComputeMaxSize(child_wid->smallest_y, given_height - child_wid->padding_top - child_wid->padding_bottom, vert_step); } /* Second loop: Allocate the additional horizontal space over the resizing children, starting with the biggest resize steps. */ while (biggest_stepsize > 0) { uint next_biggest_stepsize = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step > biggest_stepsize) continue; // Already done if (hor_step == biggest_stepsize) { uint increment = additional_length / num_changing_childs; num_changing_childs--; if (hor_step > 1) increment -= increment % hor_step; child_wid->current_x = child_wid->smallest_x + increment; additional_length -= increment; continue; } next_biggest_stepsize = max(next_biggest_stepsize, hor_step); } biggest_stepsize = next_biggest_stepsize; } assert(num_changing_childs == 0); /* Third loop: Compute position and call the child. */ uint position = rtl ? this->current_x : 0; // Place to put next child relative to origin of the container. NWidgetBase *child_wid = this->head; while (child_wid != NULL) { uint child_width = child_wid->current_x; uint child_x = x + (rtl ? position - child_width - child_wid->padding_left : position + child_wid->padding_left); uint child_y = y + child_wid->padding_top; child_wid->AssignSizePosition(sizing, child_x, child_y, child_width, child_wid->current_y, rtl); uint padded_child_width = child_width + child_wid->padding_right + child_wid->padding_left; position = rtl ? position - padded_child_width : position + padded_child_width; child_wid = child_wid->next; } } /** Horizontal left-to-right container widget. */ NWidgetHorizontalLTR::NWidgetHorizontalLTR(NWidContainerFlags flags) : NWidgetHorizontal(flags) { this->type = NWID_HORIZONTAL_LTR; } void NWidgetHorizontalLTR::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { NWidgetHorizontal::AssignSizePosition(sizing, x, y, given_width, given_height, false); } /** Vertical container widget. */ NWidgetVertical::NWidgetVertical(NWidContainerFlags flags) : NWidgetPIPContainer(NWID_VERTICAL, flags) { } void NWidgetVertical::SetupSmallestSize(Window *w, bool init_array) { this->smallest_x = 0; // Biggest child. this->smallest_y = 0; // Sum of minimal size of all children. this->fill_x = 1; // smallest common child fill step. this->fill_y = 0; // smallest non-zero child widget fill step. this->resize_x = 1; // smallest common child resize step. this->resize_y = 0; // smallest non-zero child widget resize step. /* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ uint highest = 0; // Highest child found. uint max_hor_fill = 0; // Biggest horizontal fill step. for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); highest = max(highest, child_wid->smallest_y); max_hor_fill = max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST)); this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); } /* 1b. Make the container wider if needed to accommodate all children nicely. */ uint max_smallest = this->smallest_x + 3 * max_hor_fill; // Upper limit to computing smallest height. uint cur_width = this->smallest_x; for (;;) { for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint step_size = child_wid->GetHorizontalStepSize(ST_SMALLEST); uint child_width = child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right; if (step_size > 1 && child_width < cur_width) { // Small step sizes or already fitting children are not interesting. uint remainder = (cur_width - child_width) % step_size; if (remainder > 0) { // Child did not fit entirely, widen the container. cur_width += step_size - remainder; assert(cur_width < max_smallest); // Safeguard against infinite width expansion. /* Remaining children will adapt to the new cur_width, thus speeding up the computation. */ } } } if (this->smallest_x == cur_width) break; this->smallest_x = cur_width; // Smallest width got changed, try again. } /* 2. For containers that must maintain equal width, extend children minimal size. */ if (this->flags & NC_EQUALSIZE) { for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (child_wid->fill_y == 1) child_wid->smallest_y = highest; } } /* 3. Move PIP space to the child, compute smallest, fill, and resize values of the container. */ if (this->head != NULL) this->head->padding_top += this->pip_pre; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (child_wid->next != NULL) { child_wid->padding_bottom += this->pip_inter; } else { child_wid->padding_bottom += this->pip_post; } this->smallest_y += child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; if (child_wid->fill_y > 0) { if (this->fill_y == 0 || this->fill_y > child_wid->fill_y) this->fill_y = child_wid->fill_y; } this->fill_x = LeastCommonMultiple(this->fill_x, child_wid->fill_x); if (child_wid->resize_y > 0) { if (this->resize_y == 0 || this->resize_y > child_wid->resize_y) this->resize_y = child_wid->resize_y; } this->resize_x = LeastCommonMultiple(this->resize_x, child_wid->resize_x); } /* We need to zero the PIP settings so we can re-initialize the tree. */ this->pip_pre = this->pip_inter = this->pip_post = 0; } void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); /* Compute additional height given to us. */ uint additional_length = given_height; if (sizing == ST_SMALLEST && (this->flags & NC_EQUALSIZE)) { /* For EQUALSIZE containers this does not sum to smallest_y during initialisation */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { additional_length -= child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom; } } else { additional_length -= this->smallest_y; } this->StoreSizePosition(sizing, x, y, given_width, given_height); /* Like the horizontal container, the vertical container also distributes additional height evenly, starting with the children with the biggest resize steps. * It also stores computed widths and heights into current_x and current_y values of the child. */ /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle horizontal size for all children, handle vertical size for non-resizing child. */ int num_changing_childs = 0; // Number of children that can change size. uint biggest_stepsize = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step > 0) { num_changing_childs++; biggest_stepsize = max(biggest_stepsize, vert_step); } else { child_wid->current_y = child_wid->smallest_y; } uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); child_wid->current_x = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding_left - child_wid->padding_right, hor_step); } /* Second loop: Allocate the additional vertical space over the resizing children, starting with the biggest resize steps. */ while (biggest_stepsize > 0) { uint next_biggest_stepsize = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step > biggest_stepsize) continue; // Already done if (vert_step == biggest_stepsize) { uint increment = additional_length / num_changing_childs; num_changing_childs--; if (vert_step > 1) increment -= increment % vert_step; child_wid->current_y = child_wid->smallest_y + increment; additional_length -= increment; continue; } next_biggest_stepsize = max(next_biggest_stepsize, vert_step); } biggest_stepsize = next_biggest_stepsize; } assert(num_changing_childs == 0); /* Third loop: Compute position and call the child. */ uint position = 0; // Place to put next child relative to origin of the container. for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { uint child_x = x + (rtl ? child_wid->padding_right : child_wid->padding_left); uint child_height = child_wid->current_y; child_wid->AssignSizePosition(sizing, child_x, y + position + child_wid->padding_top, child_wid->current_x, child_height, rtl); position += child_height + child_wid->padding_top + child_wid->padding_bottom; } } /** * Generic spacer widget. * @param length Horizontal size of the spacer widget. * @param height Vertical size of the spacer widget. */ NWidgetSpacer::NWidgetSpacer(int length, int height) : NWidgetResizeBase(NWID_SPACER, 0, 0) { this->SetMinimalSize(length, height); this->SetResize(0, 0); } void NWidgetSpacer::SetupSmallestSize(Window *w, bool init_array) { this->smallest_x = this->min_x; this->smallest_y = this->min_y; } void NWidgetSpacer::FillNestedArray(NWidgetBase **array, uint length) { } void NWidgetSpacer::Draw(const Window *w) { /* Spacer widget is never visible. */ } void NWidgetSpacer::SetDirty(const Window *w) const { /* Spacer widget never need repainting. */ } NWidgetCore *NWidgetSpacer::GetWidgetFromPos(int x, int y) { return NULL; } NWidgetMatrix::NWidgetMatrix() : NWidgetPIPContainer(NWID_MATRIX, NC_EQUALSIZE), index(-1), clicked(-1), count(-1) { } void NWidgetMatrix::SetIndex(int index) { this->index = index; } void NWidgetMatrix::SetColour(Colours colour) { this->colour = colour; } /** * Sets the clicked widget in the matrix. * @param clicked The clicked widget. */ void NWidgetMatrix::SetClicked(int clicked) { this->clicked = clicked; if (this->clicked >= 0 && this->sb != NULL && this->widgets_x != 0) { int vpos = (this->clicked / this->widgets_x) * this->widget_h; // Vertical position of the top. /* Need to scroll down -> Scroll to the bottom. * However, last entry has no 'this->pip_inter' underneath, and we must stay below this->sb->GetCount() */ if (this->sb->GetPosition() < vpos) vpos += this->widget_h - this->pip_inter - 1; this->sb->ScrollTowards(vpos); } } /** * Set the number of elements in this matrix. * @note Updates the number of elements/capacity of the real scrollbar. * @param count The number of elements. */ void NWidgetMatrix::SetCount(int count) { this->count = count; if (this->sb == NULL || this->widgets_x == 0) return; /* We need to get the number of pixels the matrix is high/wide. * So, determine the number of rows/columns based on the number of * columns/rows (one is constant/unscrollable). * Then multiply that by the height of a widget, and add the pre * and post spacing "offsets". */ count = CeilDiv(count, this->sb->IsVertical() ? this->widgets_x : this->widgets_y); count *= (this->sb->IsVertical() ? this->head->smallest_y : this->head->smallest_x) + this->pip_inter; if (count > 0) count -= this->pip_inter; // We counted an inter too much in the multiplication above count += this->pip_pre + this->pip_post; this->sb->SetCount(count); this->sb->SetCapacity(this->sb->IsVertical() ? this->current_y : this->current_x); this->sb->SetStepSize(this->sb->IsVertical() ? this->widget_h : this->widget_w); } /** * Assign a scrollbar to this matrix. * @param sb The scrollbar to assign to us. */ void NWidgetMatrix::SetScrollbar(Scrollbar *sb) { this->sb = sb; } void NWidgetMatrix::SetupSmallestSize(Window *w, bool init_array) { assert(this->head != NULL); assert(this->head->next == NULL); if (this->index >= 0 && init_array) { // Fill w->nested_array[] assert(w->nested_array_size > (uint)this->index); w->nested_array[this->index] = this; } /* Reset the widget number. */ NWidgetCore *nw = dynamic_cast(this->head); assert(nw != NULL); SB(nw->index, 16, 16, 0); this->head->SetupSmallestSize(w, init_array); Dimension padding = {this->pip_pre + this->pip_post, this->pip_pre + this->pip_post}; Dimension size = {this->head->smallest_x + padding.width, this->head->smallest_y + padding.height}; Dimension fill = {0, 0}; Dimension resize = {this->pip_inter + this->head->smallest_x, this->pip_inter + this->head->smallest_y}; if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize); this->smallest_x = size.width; this->smallest_y = size.height; this->fill_x = fill.width; this->fill_y = fill.height; this->resize_x = resize.width; this->resize_y = resize.height; } void NWidgetMatrix::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); this->pos_x = x; this->pos_y = y; this->current_x = given_width; this->current_y = given_height; /* Determine the size of the widgets, and the number of visible widgets on each of the axis. */ this->widget_w = this->head->smallest_x + this->pip_inter; this->widget_h = this->head->smallest_y + this->pip_inter; /* Account for the pip_inter is between widgets, so we need to account for that when * the division assumes pip_inter is used for all widgets. */ this->widgets_x = CeilDiv(this->current_x - this->pip_pre - this->pip_post + this->pip_inter, this->widget_w); this->widgets_y = CeilDiv(this->current_y - this->pip_pre - this->pip_post + this->pip_inter, this->widget_h); /* When resizing, update the scrollbar's count. E.g. with a vertical * scrollbar becoming wider or narrower means the amount of rows in * the scrollbar becomes respectively smaller or higher. */ this->SetCount(this->count); } void NWidgetMatrix::FillNestedArray(NWidgetBase **array, uint length) { if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; NWidgetContainer::FillNestedArray(array, length); } NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) { /* Falls outside of the matrix widget. */ if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; int start_x, start_y, base_offs_x, base_offs_y; this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); bool rtl = _current_text_dir == TD_RTL; int widget_col = (rtl ? -x + (int)this->pip_post + (int)this->pos_x + base_offs_x + (int)this->widget_w - 1 - (int)this->pip_inter : x - (int)this->pip_pre - (int)this->pos_x - base_offs_x ) / this->widget_w; int widget_row = (y - base_offs_y - (int)this->pip_pre - (int)this->pos_y) / this->widget_h; int sub_wid = (widget_row + start_y) * this->widgets_x + start_x + widget_col; if (sub_wid >= this->count) return NULL; NWidgetCore *child = dynamic_cast(this->head); assert(child != NULL); child->AssignSizePosition(ST_RESIZE, this->pos_x + (rtl ? this->pip_post - widget_col * this->widget_w : this->pip_pre + widget_col * this->widget_w) + base_offs_x, this->pos_y + this->pip_pre + widget_row * this->widget_h + base_offs_y, child->smallest_x, child->smallest_y, rtl); SB(child->index, 16, 16, sub_wid); return child->GetWidgetFromPos(x, y); } /* virtual */ void NWidgetMatrix::Draw(const Window *w) { /* Fill the background. */ GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, _colour_gradient[this->colour & 0xF][5]); /* Set up a clipping area for the previews. */ bool rtl = _current_text_dir == TD_RTL; DrawPixelInfo tmp_dpi; if (!FillDrawPixelInfo(&tmp_dpi, this->pos_x + (rtl ? this->pip_post : this->pip_pre), this->pos_y + this->pip_pre, this->current_x - this->pip_pre - this->pip_post, this->current_y - this->pip_pre - this->pip_post)) return; DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; /* Get the appropriate offsets so we can draw the right widgets. */ NWidgetCore *child = dynamic_cast(this->head); assert(child != NULL); int start_x, start_y, base_offs_x, base_offs_y; this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); int offs_y = base_offs_y; for (int y = start_y; y < start_y + this->widgets_y + 1; y++, offs_y += this->widget_h) { /* Are we within bounds? */ if (offs_y + child->smallest_y <= 0) continue; if (offs_y >= (int)this->current_y) break; /* We've passed our amount of widgets. */ if (y * this->widgets_x >= this->count) break; int offs_x = base_offs_x; for (int x = start_x; x < start_x + this->widgets_x + 1; x++, offs_x += rtl ? -this->widget_w : this->widget_w) { /* Are we within bounds? */ if (offs_x + child->smallest_x <= 0) continue; if (offs_x >= (int)this->current_x) continue; /* Do we have this many widgets? */ int sub_wid = y * this->widgets_x + x; if (sub_wid >= this->count) break; child->AssignSizePosition(ST_RESIZE, offs_x, offs_y, child->smallest_x, child->smallest_y, rtl); child->SetLowered(this->clicked == sub_wid); SB(child->index, 16, 16, sub_wid); child->Draw(w); } } /* Restore the clipping area. */ _cur_dpi = old_dpi; } /** * Get the different offsets that are influenced by scrolling. * @param [out] start_x The start position in columns (index of the left-most column, swapped in RTL). * @param [out] start_y The start position in rows. * @param [out] base_offs_x The base horizontal offset in pixels (X position of the column \a start_x). * @param [out] base_offs_y The base vertical offset in pixels (Y position of the column \a start_y). */ void NWidgetMatrix::GetScrollOffsets(int &start_x, int &start_y, int &base_offs_x, int &base_offs_y) { base_offs_x = _current_text_dir == TD_RTL ? this->widget_w * (this->widgets_x - 1) : 0; base_offs_y = 0; start_x = 0; start_y = 0; if (this->sb != NULL) { if (this->sb->IsVertical()) { start_y = this->sb->GetPosition() / this->widget_h; base_offs_y += -this->sb->GetPosition() + start_y * this->widget_h; } else { start_x = this->sb->GetPosition() / this->widget_w; int sub_x = this->sb->GetPosition() - start_x * this->widget_w; if (_current_text_dir == TD_RTL) { base_offs_x += sub_x; } else { base_offs_x -= sub_x; } } } } /** * Constructor parent nested widgets. * @param tp Type of parent widget. * @param colour Colour of the parent widget. * @param index Index in the widget array used by the window system. * @param child Child container widget (if supplied). If not supplied, a * vertical container will be inserted while adding the first * child widget. */ NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL) { assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME); if (index >= 0) this->SetIndex(index); this->child = child; } NWidgetBackground::~NWidgetBackground() { if (this->child != NULL) delete this->child; } /** * Add a child to the parent. * @param nwid Nested widget to add to the background widget. * * Unless a child container has been given in the constructor, a parent behaves as a vertical container. * You can add several children to it, and they are put underneath each other. */ void NWidgetBackground::Add(NWidgetBase *nwid) { if (this->child == NULL) { this->child = new NWidgetVertical(); } this->child->Add(nwid); } /** * Set additional pre/inter/post space for the background widget. * * @param pip_pre Additional space in front of the first child widget (above * for the vertical container, at the left for the horizontal container). * @param pip_inter Additional space between two child widgets. * @param pip_post Additional space after the last child widget (below for the * vertical container, at the right for the horizontal container). * @note Using this function implies that the widget has (or will have) child widgets. */ void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) { if (this->child == NULL) { this->child = new NWidgetVertical(); } this->child->SetPIP(pip_pre, pip_inter, pip_post); } void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) { if (init_array && this->index >= 0) { assert(w->nested_array_size > (uint)this->index); w->nested_array[this->index] = this; } if (this->child != NULL) { this->child->SetupSmallestSize(w, init_array); this->smallest_x = this->child->smallest_x; this->smallest_y = this->child->smallest_y; this->fill_x = this->child->fill_x; this->fill_y = this->child->fill_y; this->resize_x = this->child->resize_x; this->resize_y = this->child->resize_y; /* Account for the size of the frame's text if that exists */ if (w != NULL && this->type == WWT_FRAME) { this->child->padding_left = WD_FRAMETEXT_LEFT; this->child->padding_right = WD_FRAMETEXT_RIGHT; this->child->padding_top = max((int)WD_FRAMETEXT_TOP, this->widget_data != STR_NULL ? FONT_HEIGHT_NORMAL + WD_FRAMETEXT_TOP / 2 : 0); this->child->padding_bottom = WD_FRAMETEXT_BOTTOM; this->smallest_x += this->child->padding_left + this->child->padding_right; this->smallest_y += this->child->padding_top + this->child->padding_bottom; if (this->index >= 0) w->SetStringParameters(this->index); this->smallest_x = max(this->smallest_x, GetStringBoundingBox(this->widget_data).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); } } else { Dimension d = {this->min_x, this->min_y}; Dimension fill = {this->fill_x, this->fill_y}; Dimension resize = {this->resize_x, this->resize_y}; if (w != NULL) { // A non-NULL window pointer acts as switch to turn dynamic widget size on. if (this->type == WWT_FRAME || this->type == WWT_INSET) { if (this->index >= 0) w->SetStringParameters(this->index); Dimension background = GetStringBoundingBox(this->widget_data); background.width += (this->type == WWT_FRAME) ? (WD_FRAMETEXT_LEFT + WD_FRAMERECT_RIGHT) : (WD_INSET_LEFT + WD_INSET_RIGHT); d = maxdim(d, background); } if (this->index >= 0) { static const Dimension padding = {0, 0}; w->UpdateWidgetSize(this->index, &d, padding, &fill, &resize); } } this->smallest_x = d.width; this->smallest_y = d.height; this->fill_x = fill.width; this->fill_y = fill.height; this->resize_x = resize.width; this->resize_y = resize.height; } } void NWidgetBackground::AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { this->StoreSizePosition(sizing, x, y, given_width, given_height); if (this->child != NULL) { uint x_offset = (rtl ? this->child->padding_right : this->child->padding_left); uint width = given_width - this->child->padding_right - this->child->padding_left; uint height = given_height - this->child->padding_top - this->child->padding_bottom; this->child->AssignSizePosition(sizing, x + x_offset, y + this->child->padding_top, width, height, rtl); } } void NWidgetBackground::FillNestedArray(NWidgetBase **array, uint length) { if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; if (this->child != NULL) this->child->FillNestedArray(array, length); } void NWidgetBackground::Draw(const Window *w) { if (this->current_x == 0 || this->current_y == 0) return; Rect r; r.left = this->pos_x; r.right = this->pos_x + this->current_x - 1; r.top = this->pos_y; r.bottom = this->pos_y + this->current_y - 1; const DrawPixelInfo *dpi = _cur_dpi; if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; switch (this->type) { case WWT_PANEL: assert(this->widget_data == 0); DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, this->IsLowered() ? FR_LOWERED : FR_NONE); break; case WWT_FRAME: if (this->index >= 0) w->SetStringParameters(this->index); DrawFrame(r, this->colour, this->widget_data); break; case WWT_INSET: if (this->index >= 0) w->SetStringParameters(this->index); DrawInset(r, this->colour, this->widget_data); break; default: NOT_REACHED(); } if (this->index >= 0) w->DrawWidget(r, this->index); if (this->child != NULL) this->child->Draw(w); if (this->IsDisabled()) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); } } NWidgetCore *NWidgetBackground::GetWidgetFromPos(int x, int y) { NWidgetCore *nwid = NULL; if (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) { if (this->child != NULL) nwid = this->child->GetWidgetFromPos(x, y); if (nwid == NULL) nwid = this; } return nwid; } NWidgetBase *NWidgetBackground::GetWidgetOfType(WidgetType tp) { NWidgetBase *nwid = NULL; if (this->child != NULL) nwid = this->child->GetWidgetOfType(tp); if (nwid == NULL && this->type == tp) nwid = this; return nwid; } NWidgetViewport::NWidgetViewport(int index) : NWidgetCore(NWID_VIEWPORT, INVALID_COLOUR, 1, 1, 0x0, STR_NULL) { this->SetIndex(index); } void NWidgetViewport::SetupSmallestSize(Window *w, bool init_array) { if (init_array && this->index >= 0) { assert(w->nested_array_size > (uint)this->index); w->nested_array[this->index] = this; } this->smallest_x = this->min_x; this->smallest_y = this->min_y; } void NWidgetViewport::Draw(const Window *w) { if (this->disp_flags & ND_NO_TRANSPARENCY) { TransparencyOptionBits to_backup = _transparency_opt; _transparency_opt &= (1 << TO_SIGNS) | (1 << TO_LOADING); // Disable all transparency, except textual stuff w->DrawViewport(); _transparency_opt = to_backup; } else { w->DrawViewport(); } /* Optionally shade the viewport. */ if (this->disp_flags & (ND_SHADE_GREY | ND_SHADE_DIMMED)) { GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, (this->disp_flags & ND_SHADE_DIMMED) ? PALETTE_TO_TRANSPARENT : PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); } } /** * Initialize the viewport of the window. * @param w Window owning the viewport. * @param follow_flags Type of viewport, see #InitializeWindowViewport(). * @param zoom Zoom level. */ void NWidgetViewport::InitializeViewport(Window *w, uint32 follow_flags, ZoomLevel zoom) { InitializeWindowViewport(w, this->pos_x, this->pos_y, this->current_x, this->current_y, follow_flags, zoom); } /** * Update the position and size of the viewport (after eg a resize). * @param w Window owning the viewport. */ void NWidgetViewport::UpdateViewportCoordinates(Window *w) { ViewPort *vp = w->viewport; if (vp != NULL) { vp->left = w->left + this->pos_x; vp->top = w->top + this->pos_y; vp->width = this->current_x; vp->height = this->current_y; vp->virtual_width = ScaleByZoom(vp->width, vp->zoom); vp->virtual_height = ScaleByZoom(vp->height, vp->zoom); } } /** * Compute the row of a scrolled widget that a user clicked in. * @param clickpos Vertical position of the mouse click (without taking scrolling into account). * @param w The window the click was in. * @param widget Widget number of the widget clicked in. * @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0. * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. */ int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const { uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height); if (pos != INT_MAX) pos += this->GetPosition(); return (pos >= this->GetCount()) ? INT_MAX : pos; } /** * Set capacity of visible elements from the size and resize properties of a widget. * @param w Window. * @param widget Widget with size and resize properties. * @param padding Padding to subtract from the size. * @note Updates the position if needed. */ void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding) { NWidgetBase *nwid = w->GetWidget(widget); if (this->IsVertical()) { this->SetCapacity(((int)nwid->current_y - padding) / (int)nwid->resize_y); } else { this->SetCapacity(((int)nwid->current_x - padding) / (int)nwid->resize_x); } } /** * Scrollbar widget. * @param tp Scrollbar type. (horizontal/vertical) * @param colour Colour of the scrollbar. * @param index Index in the widget array used by the window system. */ NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR) { assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR); this->SetIndex(index); } void NWidgetScrollbar::SetupSmallestSize(Window *w, bool init_array) { if (init_array && this->index >= 0) { assert(w->nested_array_size > (uint)this->index); w->nested_array[this->index] = this; } this->min_x = 0; this->min_y = 0; switch (this->type) { case NWID_HSCROLLBAR: this->SetMinimalSize(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height); this->SetResize(1, 0); this->SetFill(1, 0); this->SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST); break; case NWID_VSCROLLBAR: this->SetMinimalSize(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3); this->SetResize(0, 1); this->SetFill(0, 1); this->SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST); break; default: NOT_REACHED(); } this->smallest_x = this->min_x; this->smallest_y = this->min_y; } void NWidgetScrollbar::Draw(const Window *w) { if (this->current_x == 0 || this->current_y == 0) return; Rect r; r.left = this->pos_x; r.right = this->pos_x + this->current_x - 1; r.top = this->pos_y; r.bottom = this->pos_y + this->current_y - 1; const DrawPixelInfo *dpi = _cur_dpi; if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; bool up_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_UP); bool down_lowered = HasBit(this->disp_flags, NDB_SCROLLBAR_DOWN); bool middle_lowered = !(this->disp_flags & ND_SCROLLBAR_BTN) && w->scrolling_scrollbar == this->index; if (this->type == NWID_HSCROLLBAR) { DrawHorizontalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this); } else { DrawVerticalScrollbar(r, this->colour, up_lowered, middle_lowered, down_lowered, this); } if (this->IsDisabled()) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); } } /* static */ void NWidgetScrollbar::InvalidateDimensionCache() { vertical_dimension.width = vertical_dimension.height = 0; horizontal_dimension.width = horizontal_dimension.height = 0; } /* static */ Dimension NWidgetScrollbar::GetVerticalDimension() { static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM}; if (vertical_dimension.width == 0) { vertical_dimension = maxdim(GetSpriteSize(SPR_ARROW_UP), GetSpriteSize(SPR_ARROW_DOWN)); vertical_dimension.width += extra.width; vertical_dimension.height += extra.height; } return vertical_dimension; } /* static */ Dimension NWidgetScrollbar::GetHorizontalDimension() { static const Dimension extra = {WD_SCROLLBAR_LEFT + WD_SCROLLBAR_RIGHT, WD_SCROLLBAR_TOP + WD_SCROLLBAR_BOTTOM}; if (horizontal_dimension.width == 0) { horizontal_dimension = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); horizontal_dimension.width += extra.width; horizontal_dimension.height += extra.height; } return horizontal_dimension; } Dimension NWidgetScrollbar::vertical_dimension = {0, 0}; Dimension NWidgetScrollbar::horizontal_dimension = {0, 0}; /** Reset the cached dimensions. */ /* static */ void NWidgetLeaf::InvalidateDimensionCache() { shadebox_dimension.width = shadebox_dimension.height = 0; debugbox_dimension.width = debugbox_dimension.height = 0; defsizebox_dimension.width = defsizebox_dimension.height = 0; stickybox_dimension.width = stickybox_dimension.height = 0; resizebox_dimension.width = resizebox_dimension.height = 0; closebox_dimension.width = closebox_dimension.height = 0; dropdown_dimension.width = dropdown_dimension.height = 0; } Dimension NWidgetLeaf::shadebox_dimension = {0, 0}; Dimension NWidgetLeaf::debugbox_dimension = {0, 0}; Dimension NWidgetLeaf::defsizebox_dimension = {0, 0}; Dimension NWidgetLeaf::stickybox_dimension = {0, 0}; Dimension NWidgetLeaf::resizebox_dimension = {0, 0}; Dimension NWidgetLeaf::closebox_dimension = {0, 0}; Dimension NWidgetLeaf::dropdown_dimension = {0, 0}; /** * Nested leaf widget. * @param tp Type of leaf widget. * @param colour Colour of the leaf widget. * @param index Index in the widget array used by the window system. * @param data Data of the widget. * @param tip Tooltip of the widget. */ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, StringID tip) : NWidgetCore(tp, colour, 1, 1, data, tip) { assert(index >= 0 || tp == WWT_LABEL || tp == WWT_TEXT || tp == WWT_CAPTION || tp == WWT_RESIZEBOX || tp == WWT_SHADEBOX || tp == WWT_DEFSIZEBOX || tp == WWT_DEBUGBOX || tp == WWT_STICKYBOX || tp == WWT_CLOSEBOX); if (index >= 0) this->SetIndex(index); this->min_x = 0; this->min_y = 0; this->SetResize(0, 0); switch (tp) { case WWT_EMPTY: break; case WWT_PUSHBTN: case WWT_IMGBTN: case WWT_PUSHIMGBTN: case WWT_IMGBTN_2: case WWT_TEXTBTN: case WWT_PUSHTXTBTN: case WWT_TEXTBTN_2: case WWT_LABEL: case WWT_TEXT: case WWT_MATRIX: case NWID_BUTTON_DROPDOWN: case NWID_PUSHBUTTON_DROPDOWN: case WWT_ARROWBTN: case WWT_PUSHARROWBTN: this->SetFill(0, 0); break; case WWT_EDITBOX: this->SetFill(0, 0); break; case WWT_CAPTION: this->SetFill(1, 0); this->SetResize(1, 0); this->min_y = WD_CAPTION_HEIGHT; this->SetDataTip(data, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); break; case WWT_STICKYBOX: this->SetFill(0, 0); this->SetMinimalSize(WD_STICKYBOX_WIDTH, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_STICKY); break; case WWT_SHADEBOX: this->SetFill(0, 0); this->SetMinimalSize(WD_SHADEBOX_TOP, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_SHADE); break; case WWT_DEBUGBOX: this->SetFill(0, 0); this->SetMinimalSize(WD_DEBUGBOX_TOP, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_DEBUG); break; case WWT_DEFSIZEBOX: this->SetFill(0, 0); this->SetMinimalSize(WD_DEFSIZEBOX_TOP, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_DEFSIZE); break; case WWT_RESIZEBOX: this->SetFill(0, 0); this->SetMinimalSize(WD_RESIZEBOX_WIDTH, 12); this->SetDataTip(STR_NULL, STR_TOOLTIP_RESIZE); break; case WWT_CLOSEBOX: this->SetFill(0, 0); this->SetMinimalSize(WD_CLOSEBOX_WIDTH, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_CLOSE_WINDOW); break; case WWT_DROPDOWN: this->SetFill(0, 0); this->min_y = WD_DROPDOWN_HEIGHT; break; default: NOT_REACHED(); } } void NWidgetLeaf::SetupSmallestSize(Window *w, bool init_array) { if (this->index >= 0 && init_array) { // Fill w->nested_array[] assert(w->nested_array_size > (uint)this->index); w->nested_array[this->index] = this; } Dimension size = {this->min_x, this->min_y}; Dimension fill = {this->fill_x, this->fill_y}; Dimension resize = {this->resize_x, this->resize_y}; /* Get padding, and update size with the real content size if appropriate. */ const Dimension *padding = NULL; switch (this->type) { case WWT_EMPTY: { static const Dimension extra = {0, 0}; padding = &extra; break; } case WWT_MATRIX: { static const Dimension extra = {WD_MATRIX_LEFT + WD_MATRIX_RIGHT, WD_MATRIX_TOP + WD_MATRIX_BOTTOM}; padding = &extra; break; } case WWT_SHADEBOX: { static const Dimension extra = {WD_SHADEBOX_LEFT + WD_SHADEBOX_RIGHT, WD_SHADEBOX_TOP + WD_SHADEBOX_BOTTOM}; padding = &extra; if (NWidgetLeaf::shadebox_dimension.width == 0) { NWidgetLeaf::shadebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_SHADE), GetSpriteSize(SPR_WINDOW_UNSHADE)); NWidgetLeaf::shadebox_dimension.width += extra.width; NWidgetLeaf::shadebox_dimension.height += extra.height; } size = maxdim(size, NWidgetLeaf::shadebox_dimension); break; } case WWT_DEBUGBOX: if (_settings_client.gui.newgrf_developer_tools && w->IsNewGRFInspectable()) { static const Dimension extra = {WD_DEBUGBOX_LEFT + WD_DEBUGBOX_RIGHT, WD_DEBUGBOX_TOP + WD_DEBUGBOX_BOTTOM}; padding = &extra; if (NWidgetLeaf::debugbox_dimension.width == 0) { NWidgetLeaf::debugbox_dimension = GetSpriteSize(SPR_WINDOW_DEBUG); NWidgetLeaf::debugbox_dimension.width += extra.width; NWidgetLeaf::debugbox_dimension.height += extra.height; } size = maxdim(size, NWidgetLeaf::debugbox_dimension); } else { /* If the setting is disabled we don't want to see it! */ size.width = 0; fill.width = 0; resize.width = 0; } break; case WWT_STICKYBOX: { static const Dimension extra = {WD_STICKYBOX_LEFT + WD_STICKYBOX_RIGHT, WD_STICKYBOX_TOP + WD_STICKYBOX_BOTTOM}; padding = &extra; if (NWidgetLeaf::stickybox_dimension.width == 0) { NWidgetLeaf::stickybox_dimension = maxdim(GetSpriteSize(SPR_PIN_UP), GetSpriteSize(SPR_PIN_DOWN)); NWidgetLeaf::stickybox_dimension.width += extra.width; NWidgetLeaf::stickybox_dimension.height += extra.height; } size = maxdim(size, NWidgetLeaf::stickybox_dimension); break; } case WWT_DEFSIZEBOX: { static const Dimension extra = {WD_DEFSIZEBOX_LEFT + WD_DEFSIZEBOX_RIGHT, WD_DEFSIZEBOX_TOP + WD_DEFSIZEBOX_BOTTOM}; padding = &extra; if (NWidgetLeaf::defsizebox_dimension.width == 0) { NWidgetLeaf::defsizebox_dimension = GetSpriteSize(SPR_WINDOW_DEFSIZE); NWidgetLeaf::defsizebox_dimension.width += extra.width; NWidgetLeaf::defsizebox_dimension.height += extra.height; } size = maxdim(size, NWidgetLeaf::defsizebox_dimension); break; } case WWT_RESIZEBOX: { static const Dimension extra = {WD_RESIZEBOX_LEFT + WD_RESIZEBOX_RIGHT, WD_RESIZEBOX_TOP + WD_RESIZEBOX_BOTTOM}; padding = &extra; if (NWidgetLeaf::resizebox_dimension.width == 0) { NWidgetLeaf::resizebox_dimension = maxdim(GetSpriteSize(SPR_WINDOW_RESIZE_LEFT), GetSpriteSize(SPR_WINDOW_RESIZE_RIGHT)); NWidgetLeaf::resizebox_dimension.width += extra.width; NWidgetLeaf::resizebox_dimension.height += extra.height; } size = maxdim(size, NWidgetLeaf::resizebox_dimension); break; } case WWT_EDITBOX: { Dimension sprite_size = GetSpriteSize(_current_text_dir == TD_RTL ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); size.width = max(size.width, 30 + sprite_size.width); size.height = max(sprite_size.height, GetStringBoundingBox("_").height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); /* FALL THROUGH */ } case WWT_PUSHBTN: { static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM}; padding = &extra; break; } case WWT_IMGBTN: case WWT_IMGBTN_2: case WWT_PUSHIMGBTN: { static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM}; padding = &extra; Dimension d2 = GetSpriteSize(this->widget_data); if (this->type == WWT_IMGBTN_2) d2 = maxdim(d2, GetSpriteSize(this->widget_data + 1)); d2.width += extra.width; d2.height += extra.height; size = maxdim(size, d2); break; } case WWT_ARROWBTN: case WWT_PUSHARROWBTN: { static const Dimension extra = {WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM}; padding = &extra; Dimension d2 = maxdim(GetSpriteSize(SPR_ARROW_LEFT), GetSpriteSize(SPR_ARROW_RIGHT)); d2.width += extra.width; d2.height += extra.height; size = maxdim(size, d2); break; } case WWT_CLOSEBOX: { static const Dimension extra = {WD_CLOSEBOX_LEFT + WD_CLOSEBOX_RIGHT, WD_CLOSEBOX_TOP + WD_CLOSEBOX_BOTTOM}; padding = &extra; if (NWidgetLeaf::closebox_dimension.width == 0) { NWidgetLeaf::closebox_dimension = GetSpriteSize(SPR_CLOSEBOX); NWidgetLeaf::closebox_dimension.width += extra.width; NWidgetLeaf::closebox_dimension.height += extra.height; } size = maxdim(size, NWidgetLeaf::closebox_dimension); break; } case WWT_TEXTBTN: case WWT_PUSHTXTBTN: case WWT_TEXTBTN_2: { static const Dimension extra = {WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM}; padding = &extra; if (this->index >= 0) w->SetStringParameters(this->index); Dimension d2 = GetStringBoundingBox(this->widget_data); d2.width += extra.width; d2.height += extra.height; size = maxdim(size, d2); break; } case WWT_LABEL: case WWT_TEXT: { static const Dimension extra = {0, 0}; padding = &extra; if (this->index >= 0) w->SetStringParameters(this->index); size = maxdim(size, GetStringBoundingBox(this->widget_data)); break; } case WWT_CAPTION: { static const Dimension extra = {WD_CAPTIONTEXT_LEFT + WD_CAPTIONTEXT_RIGHT, WD_CAPTIONTEXT_TOP + WD_CAPTIONTEXT_BOTTOM}; padding = &extra; if (this->index >= 0) w->SetStringParameters(this->index); Dimension d2 = GetStringBoundingBox(this->widget_data); d2.width += extra.width; d2.height += extra.height; size = maxdim(size, d2); break; } case WWT_DROPDOWN: case NWID_BUTTON_DROPDOWN: case NWID_PUSHBUTTON_DROPDOWN: { static Dimension extra = {WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM}; padding = &extra; if (NWidgetLeaf::dropdown_dimension.width == 0) { NWidgetLeaf::dropdown_dimension = GetSpriteSize(SPR_ARROW_DOWN); NWidgetLeaf::dropdown_dimension.width += WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT; NWidgetLeaf::dropdown_dimension.height += WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; extra.width = WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT + NWidgetLeaf::dropdown_dimension.width; } if (this->index >= 0) w->SetStringParameters(this->index); Dimension d2 = GetStringBoundingBox(this->widget_data); d2.width += extra.width; d2.height = max(d2.height, NWidgetLeaf::dropdown_dimension.height) + extra.height; size = maxdim(size, d2); break; } default: NOT_REACHED(); } if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, *padding, &fill, &resize); this->smallest_x = size.width; this->smallest_y = size.height; this->fill_x = fill.width; this->fill_y = fill.height; this->resize_x = resize.width; this->resize_y = resize.height; } void NWidgetLeaf::Draw(const Window *w) { if (this->current_x == 0 || this->current_y == 0) return; Rect r; r.left = this->pos_x; r.right = this->pos_x + this->current_x - 1; r.top = this->pos_y; r.bottom = this->pos_y + this->current_y - 1; const DrawPixelInfo *dpi = _cur_dpi; if (dpi->left > r.right || dpi->left + dpi->width <= r.left || dpi->top > r.bottom || dpi->top + dpi->height <= r.top) return; bool clicked = this->IsLowered(); switch (this->type) { case WWT_EMPTY: break; case WWT_PUSHBTN: assert(this->widget_data == 0); DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE); break; case WWT_IMGBTN: case WWT_PUSHIMGBTN: case WWT_IMGBTN_2: DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data); break; case WWT_TEXTBTN: case WWT_PUSHTXTBTN: case WWT_TEXTBTN_2: if (this->index >= 0) w->SetStringParameters(this->index); DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE); DrawLabel(r, this->type, clicked, this->widget_data); break; case WWT_ARROWBTN: case WWT_PUSHARROWBTN: { SpriteID sprite; switch (this->widget_data) { case AWV_DECREASE: sprite = _current_text_dir != TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break; case AWV_INCREASE: sprite = _current_text_dir == TD_RTL ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; break; case AWV_LEFT: sprite = SPR_ARROW_LEFT; break; case AWV_RIGHT: sprite = SPR_ARROW_RIGHT; break; default: NOT_REACHED(); } DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite); break; } case WWT_LABEL: if (this->index >= 0) w->SetStringParameters(this->index); DrawLabel(r, this->type, clicked, this->widget_data); break; case WWT_TEXT: if (this->index >= 0) w->SetStringParameters(this->index); DrawText(r, (TextColour)this->colour, this->widget_data); break; case WWT_MATRIX: DrawMatrix(r, this->colour, clicked, this->widget_data, this->resize_x, this->resize_y); break; case WWT_EDITBOX: { const QueryString *query = w->GetQueryString(this->index); if (query != NULL) query->DrawEditBox(w, this->index); break; } case WWT_CAPTION: if (this->index >= 0) w->SetStringParameters(this->index); DrawCaption(r, this->colour, w->owner, this->widget_data); break; case WWT_SHADEBOX: assert(this->widget_data == 0); DrawShadeBox(r, this->colour, w->IsShaded()); break; case WWT_DEBUGBOX: DrawDebugBox(r, this->colour, clicked); break; case WWT_STICKYBOX: assert(this->widget_data == 0); DrawStickyBox(r, this->colour, !!(w->flags & WF_STICKY)); break; case WWT_DEFSIZEBOX: assert(this->widget_data == 0); DrawDefSizeBox(r, this->colour, clicked); break; case WWT_RESIZEBOX: assert(this->widget_data == 0); DrawResizeBox(r, this->colour, this->pos_x < (uint)(w->width / 2), !!(w->flags & WF_SIZING)); break; case WWT_CLOSEBOX: DrawCloseBox(r, this->colour); break; case WWT_DROPDOWN: if (this->index >= 0) w->SetStringParameters(this->index); DrawDropdown(r, this->colour, clicked, this->widget_data); break; case NWID_BUTTON_DROPDOWN: case NWID_PUSHBUTTON_DROPDOWN: if (this->index >= 0) w->SetStringParameters(this->index); DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data); break; default: NOT_REACHED(); } if (this->index >= 0) w->DrawWidget(r, this->index); if (this->IsDisabled()) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[this->colour & 0xF][2], FILLRECT_CHECKER); } } /** * For a #NWID_BUTTON_DROPDOWN, test whether \a pt refers to the button or to the drop-down. * @param pt Point in the widget. * @return The point refers to the button. * * @note The magic constants are also used at #DrawButtonDropdown. */ bool NWidgetLeaf::ButtonHit(const Point &pt) { if (_current_text_dir == TD_LTR) { int button_width = this->pos_x + this->current_x - NWidgetLeaf::dropdown_dimension.width; return pt.x < button_width; } else { int button_left = this->pos_x + NWidgetLeaf::dropdown_dimension.width; return pt.x >= button_left; } } /* == Conversion code from NWidgetPart array to NWidgetBase* tree == */ /** * Construct a single nested widget in \a *dest from its parts. * * Construct a NWidgetBase object from a #NWidget function, and apply all * settings that follow it, until encountering a #EndContainer, another * #NWidget, or the end of the parts array. * * @param parts Array with parts of the nested widget. * @param count Length of the \a parts array. * @param dest Address of pointer to use for returning the composed widget. * @param fill_dest Fill the composed widget with child widgets. * @param biggest_index Pointer to biggest nested widget index in the tree encountered so far. * @return Number of widget part elements used to compose the widget. * @pre \c biggest_index != NULL. */ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, bool *fill_dest, int *biggest_index) { int num_used = 0; *dest = NULL; *fill_dest = false; while (count > num_used) { switch (parts->type) { case NWID_SPACER: if (*dest != NULL) return num_used; *dest = new NWidgetSpacer(0, 0); break; case NWID_HORIZONTAL: if (*dest != NULL) return num_used; *dest = new NWidgetHorizontal(parts->u.cont_flags); *fill_dest = true; break; case NWID_HORIZONTAL_LTR: if (*dest != NULL) return num_used; *dest = new NWidgetHorizontalLTR(parts->u.cont_flags); *fill_dest = true; break; case WWT_PANEL: case WWT_INSET: case WWT_FRAME: if (*dest != NULL) return num_used; *dest = new NWidgetBackground(parts->type, parts->u.widget.colour, parts->u.widget.index); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); *fill_dest = true; break; case NWID_VERTICAL: if (*dest != NULL) return num_used; *dest = new NWidgetVertical(parts->u.cont_flags); *fill_dest = true; break; case NWID_MATRIX: { if (*dest != NULL) return num_used; NWidgetMatrix *nwm = new NWidgetMatrix(); *dest = nwm; *fill_dest = true; nwm->SetIndex(parts->u.widget.index); nwm->SetColour(parts->u.widget.colour); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); break; } case WPT_FUNCTION: { if (*dest != NULL) return num_used; /* Ensure proper functioning even when the called code simply writes its largest index. */ int biggest = -1; *dest = parts->u.func_ptr(&biggest); *biggest_index = max(*biggest_index, biggest); *fill_dest = false; break; } case WPT_RESIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != NULL) { assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); nwrb->SetResize(parts->u.xy.x, parts->u.xy.y); } break; } case WPT_MINSIZE: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != NULL) { assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); nwrb->SetMinimalSize(parts->u.xy.x, parts->u.xy.y); } break; } case WPT_MINTEXTLINES: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != NULL) { assert(parts->u.text_lines.size >= FS_BEGIN && parts->u.text_lines.size < FS_END); nwrb->SetMinimalTextLines(parts->u.text_lines.lines, parts->u.text_lines.spacing, parts->u.text_lines.size); } break; } case WPT_FILL: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != NULL) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y); break; } case WPT_DATATIP: { NWidgetCore *nwc = dynamic_cast(*dest); if (nwc != NULL) { nwc->widget_data = parts->u.data_tip.data; nwc->tool_tip = parts->u.data_tip.tooltip; } break; } case WPT_PADDING: if (*dest != NULL) (*dest)->SetPadding(parts->u.padding.top, parts->u.padding.right, parts->u.padding.bottom, parts->u.padding.left); break; case WPT_PIPSPACE: { NWidgetPIPContainer *nwc = dynamic_cast(*dest); if (nwc != NULL) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); NWidgetBackground *nwb = dynamic_cast(*dest); if (nwb != NULL) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); break; } case WPT_SCROLLBAR: { NWidgetCore *nwc = dynamic_cast(*dest); if (nwc != NULL) { nwc->scrollbar_index = parts->u.widget.index; } break; } case WPT_ENDCONTAINER: return num_used; case NWID_VIEWPORT: if (*dest != NULL) return num_used; *dest = new NWidgetViewport(parts->u.widget.index); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); break; case NWID_HSCROLLBAR: case NWID_VSCROLLBAR: if (*dest != NULL) return num_used; *dest = new NWidgetScrollbar(parts->type, parts->u.widget.colour, parts->u.widget.index); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); break; case NWID_SELECTION: { if (*dest != NULL) return num_used; NWidgetStacked *nws = new NWidgetStacked(); *dest = nws; *fill_dest = true; nws->SetIndex(parts->u.widget.index); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); break; } default: if (*dest != NULL) return num_used; assert((parts->type & WWT_MASK) < WWT_LAST || (parts->type & WWT_MASK) == NWID_BUTTON_DROPDOWN); *dest = new NWidgetLeaf(parts->type, parts->u.widget.colour, parts->u.widget.index, 0x0, STR_NULL); *biggest_index = max(*biggest_index, (int)parts->u.widget.index); break; } num_used++; parts++; } return num_used; } /** * Build a nested widget tree by recursively filling containers with nested widgets read from their parts. * @param parts Array with parts of the nested widgets. * @param count Length of the \a parts array. * @param parent Pointer or container to use for storing the child widgets (*parent == NULL or *parent == container or background widget). * @param biggest_index Pointer to biggest nested widget index in the tree. * @return Number of widget part elements used to fill the container. * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. */ static int MakeWidgetTree(const NWidgetPart *parts, int count, NWidgetBase **parent, int *biggest_index) { /* If *parent == NULL, only the first widget is read and returned. Otherwise, *parent must point to either * a #NWidgetContainer or a #NWidgetBackground object, and parts are added as much as possible. */ NWidgetContainer *nwid_cont = dynamic_cast(*parent); NWidgetBackground *nwid_parent = dynamic_cast(*parent); assert(*parent == NULL || (nwid_cont != NULL && nwid_parent == NULL) || (nwid_cont == NULL && nwid_parent != NULL)); int total_used = 0; for (;;) { NWidgetBase *sub_widget = NULL; bool fill_sub = false; int num_used = MakeNWidget(parts, count - total_used, &sub_widget, &fill_sub, biggest_index); parts += num_used; total_used += num_used; /* Break out of loop when end reached */ if (sub_widget == NULL) break; /* If sub-widget is a container, recursively fill that container. */ WidgetType tp = sub_widget->type; if (fill_sub && (tp == NWID_HORIZONTAL || tp == NWID_HORIZONTAL_LTR || tp == NWID_VERTICAL || tp == NWID_MATRIX || tp == WWT_PANEL || tp == WWT_FRAME || tp == WWT_INSET || tp == NWID_SELECTION)) { NWidgetBase *sub_ptr = sub_widget; int num_used = MakeWidgetTree(parts, count - total_used, &sub_ptr, biggest_index); parts += num_used; total_used += num_used; } /* Add sub_widget to parent container if available, otherwise return the widget to the caller. */ if (nwid_cont != NULL) nwid_cont->Add(sub_widget); if (nwid_parent != NULL) nwid_parent->Add(sub_widget); if (nwid_cont == NULL && nwid_parent == NULL) { *parent = sub_widget; return total_used; } } if (count == total_used) return total_used; // Reached the end of the array of parts? assert(total_used < count); assert(parts->type == WPT_ENDCONTAINER); return total_used + 1; // *parts is also 'used' } /** * Construct a nested widget tree from an array of parts. * @param parts Array with parts of the widgets. * @param count Length of the \a parts array. * @param biggest_index Pointer to biggest nested widget index collected in the tree. * @param container Container to add the nested widgets to. In case it is NULL a vertical container is used. * @return Root of the nested widget tree, a vertical container containing the entire GUI. * @ingroup NestedWidgetParts * @pre \c biggest_index != NULL * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. */ NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest_index, NWidgetContainer *container) { *biggest_index = -1; if (container == NULL) container = new NWidgetVertical(); NWidgetBase *cont_ptr = container; MakeWidgetTree(parts, count, &cont_ptr, biggest_index); return container; } /** * Make a nested widget tree for a window from a parts array. Besides loading, it inserts a shading selection widget * between the title bar and the window body if the first widget in the parts array looks like a title bar (it is a horizontal * container with a caption widget) and has a shade box widget. * @param parts Array with parts of the widgets. * @param count Length of the \a parts array. * @param biggest_index Pointer to biggest nested widget index collected in the tree. * @param [out] shade_select Pointer to the inserted shade selection widget (\c NULL if not unserted). * @return Root of the nested widget tree, a vertical container containing the entire GUI. * @ingroup NestedWidgetParts * @pre \c biggest_index != NULL * @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used. */ NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index, NWidgetStacked **shade_select) { *biggest_index = -1; /* Read the first widget recursively from the array. */ NWidgetBase *nwid = NULL; int num_used = MakeWidgetTree(parts, count, &nwid, biggest_index); assert(nwid != NULL); parts += num_used; count -= num_used; NWidgetContainer *root = new NWidgetVertical; root->Add(nwid); if (count == 0) { // There is no body at all. *shade_select = NULL; return root; } /* If the first widget looks like a titlebar, treat it as such. * If it has a shading box, silently add a shade selection widget in the tree. */ NWidgetHorizontal *hor_cont = dynamic_cast(nwid); NWidgetContainer *body; if (hor_cont != NULL && hor_cont->GetWidgetOfType(WWT_CAPTION) != NULL && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != NULL) { *shade_select = new NWidgetStacked; root->Add(*shade_select); body = new NWidgetVertical; (*shade_select)->Add(body); } else { *shade_select = NULL; body = root; } /* Load the remaining parts into 'body'. */ int biggest2 = -1; MakeNWidgets(parts, count, &biggest2, body); *biggest_index = max(*biggest_index, biggest2); return root; } /** * Make a number of rows with button-like graphics, for enabling/disabling each company. * @param biggest_index Storage for collecting the biggest index used in the returned tree. * @param widget_first The first widget index to use. * @param widget_last The last widget index to use. * @param max_length Maximal number of company buttons in one row. * @param button_tooltip The tooltip-string of every button. * @return Panel with rows of company buttons. * @post \c *biggest_index contains the largest used index in the tree. */ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, int max_length, StringID button_tooltip) { assert(max_length >= 1); NWidgetVertical *vert = NULL; // Storage for all rows. NWidgetHorizontal *hor = NULL; // Storage for buttons in one row. int hor_length = 0; Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); sprite_size.width += WD_MATRIX_LEFT + WD_MATRIX_RIGHT; sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1; // 1 for the 'offset' of being pressed for (int widnum = widget_first; widnum <= widget_last; widnum++) { /* Ensure there is room in 'hor' for another button. */ if (hor_length == max_length) { if (vert == NULL) vert = new NWidgetVertical(); vert->Add(hor); hor = NULL; hor_length = 0; } if (hor == NULL) { hor = new NWidgetHorizontal(); hor_length = 0; } NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); panel->SetMinimalSize(sprite_size.width, sprite_size.height); panel->SetFill(1, 1); panel->SetResize(1, 0); panel->SetDataTip(0x0, button_tooltip); hor->Add(panel); hor_length++; } *biggest_index = widget_last; if (vert == NULL) return hor; // All buttons fit in a single row. if (hor_length > 0 && hor_length < max_length) { /* Last row is partial, add a spacer at the end to force all buttons to the left. */ NWidgetSpacer *spc = new NWidgetSpacer(sprite_size.width, sprite_size.height); spc->SetFill(1, 1); spc->SetResize(1, 0); hor->Add(spc); } if (hor != NULL) vert->Add(hor); return vert; } openttd-1.5.3/src/highscore.cpp0000644000000000000000000001446512627373435015167 0ustar rootroot/* $Id: highscore.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 highscore.cpp Definition of functions used for highscore handling */ #include "stdafx.h" #include "highscore.h" #include "company_base.h" #include "company_func.h" #include "cheat_func.h" #include "string_func.h" #include "strings_func.h" #include "table/strings.h" #include "core/sort_func.hpp" #include "debug.h" #include "safeguards.h" HighScore _highscore_table[SP_HIGHSCORE_END][5]; ///< various difficulty-settings; top 5 char *_highscore_file; ///< The file to store the highscore data in. static const StringID _endgame_perf_titles[] = { STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN, STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN, STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN, STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN, STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN, STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR, STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR, STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST, STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST, STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST, STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST, STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE, STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE, STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL, STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL, STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY }; StringID EndGameGetPerformanceTitleFromValue(uint value) { value = minu(value / 64, lengthof(_endgame_perf_titles) - 1); return _endgame_perf_titles[value]; } /** Save the highscore for the company */ int8 SaveHighScoreValue(const Company *c) { HighScore *hs = _highscore_table[SP_CUSTOM]; uint i; uint16 score = c->old_economy[0].performance_history; /* Exclude cheaters from the honour of being in the highscore table */ if (CheatHasBeenUsed()) return -1; for (i = 0; i < lengthof(_highscore_table[0]); i++) { /* You are in the TOP5. Move all values one down and save us there */ if (hs[i].score <= score) { /* move all elements one down starting from the replaced one */ memmove(&hs[i + 1], &hs[i], sizeof(HighScore) * (lengthof(_highscore_table[0]) - i - 1)); SetDParam(0, c->index); SetDParam(1, c->index); GetString(hs[i].company, STR_HIGHSCORE_NAME, lastof(hs[i].company)); // get manager/company name string hs[i].score = score; hs[i].title = EndGameGetPerformanceTitleFromValue(score); return i; } } return -1; // too bad; we did not make it into the top5 } /** Sort all companies given their performance */ static int CDECL HighScoreSorter(const Company * const *a, const Company * const *b) { return (*b)->old_economy[0].performance_history - (*a)->old_economy[0].performance_history; } /** * Save the highscores in a network game when it has ended * @return Position of the local company in the highscore list. */ int8 SaveHighScoreValueNetwork() { const Company *c; const Company *cl[MAX_COMPANIES]; uint count = 0; int8 company = -1; /* Sort all active companies with the highest score first */ FOR_ALL_COMPANIES(c) cl[count++] = c; QSortT(cl, count, &HighScoreSorter); { uint i; memset(_highscore_table[SP_MULTIPLAYER], 0, sizeof(_highscore_table[SP_MULTIPLAYER])); /* Copy over Top5 companies */ for (i = 0; i < lengthof(_highscore_table[SP_MULTIPLAYER]) && i < count; i++) { HighScore *hs = &_highscore_table[SP_MULTIPLAYER][i]; SetDParam(0, cl[i]->index); SetDParam(1, cl[i]->index); GetString(hs->company, STR_HIGHSCORE_NAME, lastof(hs->company)); // get manager/company name string hs->score = cl[i]->old_economy[0].performance_history; hs->title = EndGameGetPerformanceTitleFromValue(hs->score); /* get the ranking of the local company */ if (cl[i]->index == _local_company) company = i; } } /* Add top5 companies to highscore table */ return company; } /** Save HighScore table to file */ void SaveToHighScore() { FILE *fp = fopen(_highscore_file, "wb"); if (fp != NULL) { uint i; HighScore *hs; for (i = 0; i < SP_SAVED_HIGHSCORE_END; i++) { for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) { /* First character is a command character, so strlen will fail on that */ byte length = min(sizeof(hs->company), StrEmpty(hs->company) ? 0 : (int)strlen(&hs->company[1]) + 1); if (fwrite(&length, sizeof(length), 1, fp) != 1 || // write away string length fwrite(hs->company, length, 1, fp) > 1 || // Yes... could be 0 bytes too fwrite(&hs->score, sizeof(hs->score), 1, fp) != 1 || fwrite(" ", 2, 1, fp) != 1) { // XXX - placeholder for hs->title, not saved anymore; compatibility DEBUG(misc, 1, "Could not save highscore."); i = SP_SAVED_HIGHSCORE_END; break; } } } fclose(fp); } } /** Initialize the highscore table to 0 and if any file exists, load in values */ void LoadFromHighScore() { FILE *fp = fopen(_highscore_file, "rb"); memset(_highscore_table, 0, sizeof(_highscore_table)); if (fp != NULL) { uint i; HighScore *hs; for (i = 0; i < SP_SAVED_HIGHSCORE_END; i++) { for (hs = _highscore_table[i]; hs != endof(_highscore_table[i]); hs++) { byte length; if (fread(&length, sizeof(length), 1, fp) != 1 || fread(hs->company, min(lengthof(hs->company), length), 1, fp) > 1 || // Yes... could be 0 bytes too fread(&hs->score, sizeof(hs->score), 1, fp) != 1 || fseek(fp, 2, SEEK_CUR) == -1) { // XXX - placeholder for hs->title, not saved anymore; compatibility DEBUG(misc, 1, "Highscore corrupted"); i = SP_SAVED_HIGHSCORE_END; break; } str_validate(hs->company, lastof(hs->company), SVS_NONE); hs->title = EndGameGetPerformanceTitleFromValue(hs->score); } } fclose(fp); } } openttd-1.5.3/src/highscore.h0000644000000000000000000000322212627373435014621 0ustar rootroot/* $Id: highscore.h 25512 2013-06-29 12:07:40Z rubidium $ */ /* * 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 highscore.h Declaration of functions and types defined in highscore.h and highscore_gui.h */ #ifndef HIGHSCORE_H #define HIGHSCORE_H #include "strings_type.h" #include "company_type.h" #include "settings_type.h" struct HighScore { /** * The name of the company and president. * The + 5 is for the comma and space or possibly other characters * that join the two names in this single string and the '\0'. */ char company[(MAX_LENGTH_COMPANY_NAME_CHARS + MAX_LENGTH_PRESIDENT_NAME_CHARS + 5) * MAX_CHAR_LENGTH]; StringID title; ///< NOSAVE, has troubles with changing string-numbers. uint16 score; ///< The score for this high score. Do NOT change type, will break hs.dat }; extern HighScore _highscore_table[SP_HIGHSCORE_END][5]; void SaveToHighScore(); void LoadFromHighScore(); int8 SaveHighScoreValue(const Company *c); int8 SaveHighScoreValueNetwork(); StringID EndGameGetPerformanceTitleFromValue(uint value); void ShowHighscoreTable(int difficulty = SP_CUSTOM, int8 rank = -1); #endif /* HIGHSCORE_H */ openttd-1.5.3/src/terraform_gui.cpp0000644000000000000000000006520512627373434016056 0ustar rootroot/* $Id: terraform_gui.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 terraform_gui.cpp GUI related to terraforming the map. */ #include "stdafx.h" #include "clear_map.h" #include "company_func.h" #include "company_base.h" #include "gui.h" #include "window_gui.h" #include "window_func.h" #include "viewport_func.h" #include "command_func.h" #include "signs_func.h" #include "sound_func.h" #include "base_station_base.h" #include "textbuf_gui.h" #include "genworld.h" #include "tree_map.h" #include "landscape_type.h" #include "tilehighlight_func.h" #include "strings_func.h" #include "newgrf_object.h" #include "object.h" #include "hotkeys.h" #include "engine_base.h" #include "terraform_gui.h" #include "zoom_func.h" #include "widgets/terraform_widget.h" #include "table/strings.h" #include "safeguards.h" void CcTerraform(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded()) { if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); } else { extern TileIndex _terraform_err_tile; SetRedErrorSquare(_terraform_err_tile); } } /** Scenario editor command that generates desert areas */ static void GenerateDesertArea(TileIndex end, TileIndex start) { if (_game_mode != GM_EDITOR) return; _generating_world = true; TileArea ta(start, end); TILE_AREA_LOOP(tile, ta) { SetTropicZone(tile, (_ctrl_pressed) ? TROPICZONE_NORMAL : TROPICZONE_DESERT); DoCommandP(tile, 0, 0, CMD_LANDSCAPE_CLEAR); MarkTileDirtyByTile(tile); } _generating_world = false; InvalidateWindowClassesData(WC_TOWN_VIEW, 0); } /** Scenario editor command that generates rocky areas */ static void GenerateRockyArea(TileIndex end, TileIndex start) { if (_game_mode != GM_EDITOR) return; bool success = false; TileArea ta(start, end); TILE_AREA_LOOP(tile, ta) { switch (GetTileType(tile)) { case MP_TREES: if (GetTreeGround(tile) == TREE_GROUND_SHORE) continue; /* FALL THROUGH */ case MP_CLEAR: MakeClear(tile, CLEAR_ROCKS, 3); break; default: continue; } MarkTileDirtyByTile(tile); success = true; } if (success && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, end); } /** * A central place to handle all X_AND_Y dragged GUI functions. * @param proc Procedure related to the dragging * @param start_tile Begin of the dragging * @param end_tile End of the dragging * @return Returns true if the action was found and handled, and false otherwise. This * allows for additional implements that are more local. For example X_Y drag * of convertrail which belongs in rail_gui.cpp and not terraform_gui.cpp */ bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile) { if (!_settings_game.construction.freeform_edges) { /* When end_tile is MP_VOID, the error tile will not be visible to the * user. This happens when terraforming at the southern border. */ if (TileX(end_tile) == MapMaxX()) end_tile += TileDiffXY(-1, 0); if (TileY(end_tile) == MapMaxY()) end_tile += TileDiffXY(0, -1); } switch (proc) { case DDSP_DEMOLISH_AREA: DoCommandP(end_tile, start_tile, _ctrl_pressed ? 1 : 0, CMD_CLEAR_AREA | CMD_MSG(STR_ERROR_CAN_T_CLEAR_THIS_AREA), CcPlaySound10); break; case DDSP_RAISE_AND_LEVEL_AREA: DoCommandP(end_tile, start_tile, LM_RAISE << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_RAISE_LAND_HERE), CcTerraform); break; case DDSP_LOWER_AND_LEVEL_AREA: DoCommandP(end_tile, start_tile, LM_LOWER << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LOWER_LAND_HERE), CcTerraform); break; case DDSP_LEVEL_AREA: DoCommandP(end_tile, start_tile, LM_LEVEL << 1 | (_ctrl_pressed ? 1 : 0), CMD_LEVEL_LAND | CMD_MSG(STR_ERROR_CAN_T_LEVEL_LAND_HERE), CcTerraform); break; case DDSP_CREATE_ROCKS: GenerateRockyArea(end_tile, start_tile); break; case DDSP_CREATE_DESERT: GenerateDesertArea(end_tile, start_tile); break; default: return false; } return true; } /** * Start a drag for demolishing an area. * @param tile Position of one corner. */ void PlaceProc_DemolishArea(TileIndex tile) { VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_DEMOLISH_AREA); } /** Terra form toolbar managing class. */ struct TerraformToolbarWindow : Window { int last_user_action; ///< Last started user action. TerraformToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { /* This is needed as we like to have the tree available on OnInit. */ this->CreateNestedTree(); this->FinishInitNested(window_number); this->last_user_action = WIDGET_LIST_END; } ~TerraformToolbarWindow() { } virtual void OnInit() { /* Don't show the place object button when there are no objects to place. */ NWidgetStacked *show_object = this->GetWidget(WID_TT_SHOW_PLACE_OBJECT); show_object->SetDisplayedPlane(ObjectClass::GetUIClassCount() != 0 ? 0 : SZSP_NONE); } virtual void OnClick(Point pt, int widget, int click_count) { if (widget < WID_TT_BUTTONS_START) return; switch (widget) { case WID_TT_LOWER_LAND: // Lower land button HandlePlacePushButton(this, WID_TT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT | HT_DIAGONAL); this->last_user_action = widget; break; case WID_TT_RAISE_LAND: // Raise land button HandlePlacePushButton(this, WID_TT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT | HT_DIAGONAL); this->last_user_action = widget; break; case WID_TT_LEVEL_LAND: // Level land button HandlePlacePushButton(this, WID_TT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL); this->last_user_action = widget; break; case WID_TT_DEMOLISH: // Demolish aka dynamite button HandlePlacePushButton(this, WID_TT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_user_action = widget; break; case WID_TT_BUY_LAND: // Buy land button HandlePlacePushButton(this, WID_TT_BUY_LAND, SPR_CURSOR_BUY_LAND, HT_RECT); this->last_user_action = widget; break; case WID_TT_PLANT_TREES: // Plant trees button ShowBuildTreesToolbar(); break; case WID_TT_PLACE_SIGN: // Place sign button HandlePlacePushButton(this, WID_TT_PLACE_SIGN, SPR_CURSOR_SIGN, HT_RECT); this->last_user_action = widget; break; case WID_TT_PLACE_OBJECT: // Place object button /* Don't show the place object button when there are no objects to place. */ if (ObjectClass::GetUIClassCount() == 0) return; if (HandlePlacePushButton(this, WID_TT_PLACE_OBJECT, SPR_CURSOR_TRANSMITTER, HT_RECT)) { ShowBuildObjectPicker(this); this->last_user_action = widget; } break; default: NOT_REACHED(); } } virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_user_action) { case WID_TT_LOWER_LAND: // Lower land button VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LOWER_AND_LEVEL_AREA); break; case WID_TT_RAISE_LAND: // Raise land button VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_RAISE_AND_LEVEL_AREA); break; case WID_TT_LEVEL_LAND: // Level land button VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA); break; case WID_TT_DEMOLISH: // Demolish aka dynamite button PlaceProc_DemolishArea(tile); break; case WID_TT_BUY_LAND: // Buy land button DoCommandP(tile, OBJECT_OWNED_LAND, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_PURCHASE_THIS_LAND), CcPlaySound1E); break; case WID_TT_PLACE_SIGN: // Place sign button PlaceProc_Sign(tile); break; case WID_TT_PLACE_OBJECT: // Place object button PlaceProc_Object(tile); break; default: NOT_REACHED(); } } virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { Point pt = GetToolbarAlignedWindowPosition(sm_width); pt.y += sm_height; return pt; } virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) { if (pt.x != -1) { switch (select_proc) { default: NOT_REACHED(); case DDSP_DEMOLISH_AREA: case DDSP_RAISE_AND_LEVEL_AREA: case DDSP_LOWER_AND_LEVEL_AREA: case DDSP_LEVEL_AREA: GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; } } } virtual void OnPlaceObjectAbort() { DeleteWindowById(WC_BUILD_OBJECT, 0); this->RaiseButtons(); } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the TerraformToolbarWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState TerraformToolbarGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; Window *w = ShowTerraformToolbar(NULL); if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } static Hotkey terraform_hotkeys[] = { Hotkey('Q' | WKC_GLOBAL_HOTKEY, "lower", WID_TT_LOWER_LAND), Hotkey('W' | WKC_GLOBAL_HOTKEY, "raise", WID_TT_RAISE_LAND), Hotkey('E' | WKC_GLOBAL_HOTKEY, "level", WID_TT_LEVEL_LAND), Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_TT_DEMOLISH), Hotkey('U', "buyland", WID_TT_BUY_LAND), Hotkey('I', "trees", WID_TT_PLANT_TREES), Hotkey('O', "placesign", WID_TT_PLACE_SIGN), Hotkey('P', "placeobject", WID_TT_PLACE_OBJECT), HOTKEY_LIST_END }; HotkeyList TerraformToolbarWindow::hotkeys("terraform", terraform_hotkeys, TerraformToolbarGlobalHotkeys); static const NWidgetPart _nested_terraform_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_LANDSCAPING_TOOLBAR, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LOWER_LAND), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_DOWN, STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_RAISE_LAND), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_UP, STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LEVEL_LAND), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_LEVEL_LAND, STR_LANDSCAPING_LEVEL_LAND_TOOLTIP), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_DEMOLISH), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_BUY_LAND), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BUY_LAND, STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND), NWidget(WWT_PUSHIMGBTN, COLOUR_DARK_GREEN, WID_TT_PLANT_TREES), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_SIGN), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TT_SHOW_PLACE_OBJECT), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_PLACE_OBJECT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT), EndContainer(), EndContainer(), }; static WindowDesc _terraform_desc( WDP_MANUAL, "toolbar_landscape", 0, 0, WC_SCEN_LAND_GEN, WC_NONE, WDF_CONSTRUCTION, _nested_terraform_widgets, lengthof(_nested_terraform_widgets), &TerraformToolbarWindow::hotkeys ); /** * Show the toolbar for terraforming in the game. * @param link The toolbar we might want to link to. * @return The allocated toolbar if the window was newly opened, else \c NULL. */ Window *ShowTerraformToolbar(Window *link) { if (!Company::IsValidID(_local_company)) return NULL; Window *w; if (link == NULL) { w = AllocateWindowDescFront(&_terraform_desc, 0); return w; } /* Delete the terraform toolbar to place it again. */ DeleteWindowById(WC_SCEN_LAND_GEN, 0, true); w = AllocateWindowDescFront(&_terraform_desc, 0); /* Align the terraform toolbar under the main toolbar. */ w->top -= w->height; w->SetDirty(); /* Put the linked toolbar to the left / right of it. */ link->left = w->left + (_current_text_dir == TD_RTL ? w->width : -link->width); link->top = w->top; link->SetDirty(); return w; } static byte _terraform_size = 1; /** * Raise/Lower a bigger chunk of land at the same time in the editor. When * raising get the lowest point, when lowering the highest point, and set all * tiles in the selection to that height. * @todo : Incorporate into game itself to allow for ingame raising/lowering of * larger chunks at the same time OR remove altogether, as we have 'level land' ? * @param tile The top-left tile where the terraforming will start * @param mode 1 for raising, 0 for lowering land */ static void CommonRaiseLowerBigLand(TileIndex tile, int mode) { if (_terraform_size == 1) { StringID msg = mode ? STR_ERROR_CAN_T_RAISE_LAND_HERE : STR_ERROR_CAN_T_LOWER_LAND_HERE; DoCommandP(tile, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND | CMD_MSG(msg), CcTerraform); } else { assert(_terraform_size != 0); TileArea ta(tile, _terraform_size, _terraform_size); ta.ClampToMap(); if (ta.w == 0 || ta.h == 0) return; if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); uint h; if (mode != 0) { /* Raise land */ h = MAX_TILE_HEIGHT; TILE_AREA_LOOP(tile2, ta) { h = min(h, TileHeight(tile2)); } } else { /* Lower land */ h = 0; TILE_AREA_LOOP(tile2, ta) { h = max(h, TileHeight(tile2)); } } TILE_AREA_LOOP(tile2, ta) { if (TileHeight(tile2) == h) { DoCommandP(tile2, SLOPE_N, (uint32)mode, CMD_TERRAFORM_LAND); } } } } static const int8 _multi_terraform_coords[][2] = { { 0, -2}, { 4, 0}, { -4, 0}, { 0, 2}, { -8, 2}, { -4, 4}, { 0, 6}, { 4, 4}, { 8, 2}, {-12, 0}, { -8, -2}, { -4, -4}, { 0, -6}, { 4, -4}, { 8, -2}, { 12, 0}, {-16, 2}, {-12, 4}, { -8, 6}, { -4, 8}, { 0, 10}, { 4, 8}, { 8, 6}, { 12, 4}, { 16, 2}, {-20, 0}, {-16, -2}, {-12, -4}, { -8, -6}, { -4, -8}, { 0,-10}, { 4, -8}, { 8, -6}, { 12, -4}, { 16, -2}, { 20, 0}, {-24, 2}, {-20, 4}, {-16, 6}, {-12, 8}, { -8, 10}, { -4, 12}, { 0, 14}, { 4, 12}, { 8, 10}, { 12, 8}, { 16, 6}, { 20, 4}, { 24, 2}, {-28, 0}, {-24, -2}, {-20, -4}, {-16, -6}, {-12, -8}, { -8,-10}, { -4,-12}, { 0,-14}, { 4,-12}, { 8,-10}, { 12, -8}, { 16, -6}, { 20, -4}, { 24, -2}, { 28, 0}, }; static const NWidgetPart _nested_scen_edit_land_gen_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_HORIZONTAL), SetPadding(2, 2, 7, 2), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_DEMOLISH), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_LOWER_LAND), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_DOWN, STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_RAISE_LAND), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TERRAFORM_UP, STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_LEVEL_LAND), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_LEVEL_LAND, STR_LANDSCAPING_LEVEL_LAND_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_ROCKS), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_ROCKS, STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_ETT_SHOW_PLACE_DESERT), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_DESERT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_DESERT, STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_PLACE_OBJECT), SetMinimalSize(23, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_SCENEDIT_TOOLBAR_PLACE_OBJECT), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ETT_DOTS), SetMinimalSize(59, 31), SetDataTip(STR_EMPTY, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_INCREASE_SIZE), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_UP, STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_ETT_DECREASE_SIZE), SetMinimalSize(12, 12), SetDataTip(SPR_ARROW_DOWN, STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_ETT_NEW_SCENARIO), SetMinimalSize(160, 12), SetFill(1, 0), SetDataTip(STR_TERRAFORM_SE_NEW_WORLD, STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND), SetPadding(0, 2, 0, 2), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_ETT_RESET_LANDSCAPE), SetMinimalSize(160, 12), SetFill(1, 0), SetDataTip(STR_TERRAFORM_RESET_LANDSCAPE, STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP), SetPadding(1, 2, 2, 2), EndContainer(), }; /** * Callback function for the scenario editor 'reset landscape' confirmation window * @param w Window unused * @param confirmed boolean value, true when yes was clicked, false otherwise */ static void ResetLandscapeConfirmationCallback(Window *w, bool confirmed) { if (confirmed) { /* Set generating_world to true to get instant-green grass after removing * company property. */ _generating_world = true; /* Delete all companies */ Company *c; FOR_ALL_COMPANIES(c) { ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER); delete c; } _generating_world = false; /* Delete all station signs */ BaseStation *st; FOR_ALL_BASE_STATIONS(st) { /* There can be buoys, remove them */ if (IsBuoyTile(st->xy)) DoCommand(st->xy, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); if (!st->IsInUse()) delete st; } /* Now that all vehicles are gone, we can reset the engine pool. Maybe it reduces some NewGRF changing-mess */ EngineOverrideManager::ResetToCurrentNewGRFConfig(); MarkWholeScreenDirty(); } } /** Landscape generation window handler in the scenario editor. */ struct ScenarioEditorLandscapeGenerationWindow : Window { int last_user_action; ///< Last started user action. ScenarioEditorLandscapeGenerationWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->CreateNestedTree(); NWidgetStacked *show_desert = this->GetWidget(WID_ETT_SHOW_PLACE_DESERT); show_desert->SetDisplayedPlane(_settings_game.game_creation.landscape == LT_TROPIC ? 0 : SZSP_NONE); this->FinishInitNested(window_number); this->last_user_action = WIDGET_LIST_END; } virtual void OnPaint() { this->DrawWidgets(); if (this->IsWidgetLowered(WID_ETT_LOWER_LAND) || this->IsWidgetLowered(WID_ETT_RAISE_LAND)) { // change area-size if raise/lower corner is selected SetTileSelectSize(_terraform_size, _terraform_size); } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_ETT_DOTS) return; size->width = max(size->width, ScaleGUITrad(59)); size->height = max(size->height, ScaleGUITrad(31)); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_ETT_DOTS) return; int center_x = RoundDivSU(r.left + r.right, 2); int center_y = RoundDivSU(r.top + r.bottom, 2); int n = _terraform_size * _terraform_size; const int8 *coords = &_multi_terraform_coords[0][0]; assert(n != 0); do { DrawSprite(SPR_WHITE_POINT, PAL_NONE, center_x + ScaleGUITrad(coords[0]), center_y + ScaleGUITrad(coords[1])); coords += 2; } while (--n); } virtual void OnClick(Point pt, int widget, int click_count) { if (widget < WID_ETT_BUTTONS_START) return; switch (widget) { case WID_ETT_DEMOLISH: // Demolish aka dynamite button HandlePlacePushButton(this, WID_ETT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_user_action = widget; break; case WID_ETT_LOWER_LAND: // Lower land button HandlePlacePushButton(this, WID_ETT_LOWER_LAND, ANIMCURSOR_LOWERLAND, HT_POINT); this->last_user_action = widget; break; case WID_ETT_RAISE_LAND: // Raise land button HandlePlacePushButton(this, WID_ETT_RAISE_LAND, ANIMCURSOR_RAISELAND, HT_POINT); this->last_user_action = widget; break; case WID_ETT_LEVEL_LAND: // Level land button HandlePlacePushButton(this, WID_ETT_LEVEL_LAND, SPR_CURSOR_LEVEL_LAND, HT_POINT | HT_DIAGONAL); this->last_user_action = widget; break; case WID_ETT_PLACE_ROCKS: // Place rocks button HandlePlacePushButton(this, WID_ETT_PLACE_ROCKS, SPR_CURSOR_ROCKY_AREA, HT_RECT); this->last_user_action = widget; break; case WID_ETT_PLACE_DESERT: // Place desert button (in tropical climate) HandlePlacePushButton(this, WID_ETT_PLACE_DESERT, SPR_CURSOR_DESERT, HT_RECT); this->last_user_action = widget; break; case WID_ETT_PLACE_OBJECT: // Place transmitter button if (HandlePlacePushButton(this, WID_ETT_PLACE_OBJECT, SPR_CURSOR_TRANSMITTER, HT_RECT)) { ShowBuildObjectPicker(this); this->last_user_action = widget; } break; case WID_ETT_INCREASE_SIZE: case WID_ETT_DECREASE_SIZE: { // Increase/Decrease terraform size int size = (widget == WID_ETT_INCREASE_SIZE) ? 1 : -1; this->HandleButtonClick(widget); size += _terraform_size; if (!IsInsideMM(size, 1, 8 + 1)) return; _terraform_size = size; if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); break; } case WID_ETT_NEW_SCENARIO: // gen random land this->HandleButtonClick(widget); ShowCreateScenario(); break; case WID_ETT_RESET_LANDSCAPE: // Reset landscape ShowQuery(STR_QUERY_RESET_LANDSCAPE_CAPTION, STR_RESET_LANDSCAPE_CONFIRMATION_TEXT, NULL, ResetLandscapeConfirmationCallback); break; default: NOT_REACHED(); } } virtual void OnTimeout() { for (uint i = WID_ETT_START; i < this->nested_array_size; i++) { if (i == WID_ETT_BUTTONS_START) i = WID_ETT_BUTTONS_END; // skip the buttons if (this->IsWidgetLowered(i)) { this->RaiseWidget(i); this->SetWidgetDirty(i); } } } virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_user_action) { case WID_ETT_DEMOLISH: // Demolish aka dynamite button PlaceProc_DemolishArea(tile); break; case WID_ETT_LOWER_LAND: // Lower land button CommonRaiseLowerBigLand(tile, 0); break; case WID_ETT_RAISE_LAND: // Raise land button CommonRaiseLowerBigLand(tile, 1); break; case WID_ETT_LEVEL_LAND: // Level land button VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_LEVEL_AREA); break; case WID_ETT_PLACE_ROCKS: // Place rocks button VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_ROCKS); break; case WID_ETT_PLACE_DESERT: // Place desert button (in tropical climate) VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_DESERT); break; case WID_ETT_PLACE_OBJECT: // Place transmitter button PlaceProc_Object(tile); break; default: NOT_REACHED(); } } 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) { default: NOT_REACHED(); case DDSP_CREATE_ROCKS: case DDSP_CREATE_DESERT: case DDSP_RAISE_AND_LEVEL_AREA: case DDSP_LOWER_AND_LEVEL_AREA: case DDSP_LEVEL_AREA: case DDSP_DEMOLISH_AREA: GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; } } } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); this->SetDirty(); DeleteWindowById(WC_BUILD_OBJECT, 0); } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the ScenarioEditorLandscapeGenerationWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState TerraformToolbarEditorGlobalHotkeys(int hotkey) { if (_game_mode != GM_EDITOR) return ES_NOT_HANDLED; Window *w = ShowEditorTerraformToolbar(); if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } static Hotkey terraform_editor_hotkeys[] = { Hotkey('D' | WKC_GLOBAL_HOTKEY, "dynamite", WID_ETT_DEMOLISH), Hotkey('Q' | WKC_GLOBAL_HOTKEY, "lower", WID_ETT_LOWER_LAND), Hotkey('W' | WKC_GLOBAL_HOTKEY, "raise", WID_ETT_RAISE_LAND), Hotkey('E' | WKC_GLOBAL_HOTKEY, "level", WID_ETT_LEVEL_LAND), Hotkey('R', "rocky", WID_ETT_PLACE_ROCKS), Hotkey('T', "desert", WID_ETT_PLACE_DESERT), Hotkey('O', "object", WID_ETT_PLACE_OBJECT), HOTKEY_LIST_END }; HotkeyList ScenarioEditorLandscapeGenerationWindow::hotkeys("terraform_editor", terraform_editor_hotkeys, TerraformToolbarEditorGlobalHotkeys); static WindowDesc _scen_edit_land_gen_desc( WDP_AUTO, "toolbar_landscape_scen", 0, 0, WC_SCEN_LAND_GEN, WC_NONE, WDF_CONSTRUCTION, _nested_scen_edit_land_gen_widgets, lengthof(_nested_scen_edit_land_gen_widgets), &ScenarioEditorLandscapeGenerationWindow::hotkeys ); /** * Show the toolbar for terraforming in the scenario editor. * @return The allocated toolbar if the window was newly opened, else \c NULL. */ Window *ShowEditorTerraformToolbar() { return AllocateWindowDescFront(&_scen_edit_land_gen_desc, 0); } openttd-1.5.3/src/stringfilter_type.h0000644000000000000000000000602012627373442016420 0ustar rootroot/* $Id: stringfilter_type.h 24632 2012-10-27 15:26:17Z frosch $ */ /* * 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 stringfilter_type.h Searching and filtering using a stringterm. */ #ifndef STRINGFILTER_TYPE_H #define STRINGFILTER_TYPE_H #include "core/smallvec_type.hpp" #include "strings_type.h" /** * String filter and state. * * The filter takes a stringterm and parses it into words separated by whitespace. * The whitespace-separation can be avoided by quoting words in the searchterm using " or '. * The quotation characters can be nested or concatenated in a unix-shell style. * * When filtering an item, all words are checked for matches, and the filter matches if every word * matched. So, effectively this is a AND search for all entered words. * * Once the filter is set up using SetFilterTerm, multiple items can be filtered consecutively. * 1. For every item first call ResetState() which resets the matching-state. * 2. Pass all lines of the item via AddLine() to the filter. * 3. Check the matching-result for the item via GetState(). */ struct StringFilter { private: /** State of a single filter word */ struct WordState { const char *start; ///< Word to filter for. bool match; ///< Already matched? }; const char *filter_buffer; ///< Parsed filter string. Words separated by 0. SmallVector word_index; ///< Word index and filter state. uint word_matches; ///< Summary of filter state: Number of words matched. const bool *case_sensitive; ///< Match case-sensitively (usually a static variable). public: /** * Constructor for filter. * @param case_sensitive Pointer to a (usually static) variable controlling the case-sensitivity. NULL means always case-insensitive. */ StringFilter(const bool *case_sensitive = NULL) : filter_buffer(NULL), word_matches(0), case_sensitive(case_sensitive) {} ~StringFilter() { free(this->filter_buffer); } void SetFilterTerm(const char *str); /** * Check whether any filter words were entered. * @return true if no words were entered. */ bool IsEmpty() const { return this->word_index.Length() == 0; } void ResetState(); void AddLine(const char *str); void AddLine(StringID str); /** * Get the matching state of the current item. * @return true if matched. */ bool GetState() const { return this->word_matches == this->word_index.Length(); } }; #endif /* STRINGFILTER_TYPE_H */ openttd-1.5.3/src/openttd.cpp0000644000000000000000000013067612627373441014671 0ustar rootroot/* $Id: openttd.cpp 26828 2014-09-16 17:14:07Z rubidium $ */ /* * 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 openttd.cpp Functions related to starting OpenTTD. */ #include "stdafx.h" #include "blitter/factory.hpp" #include "sound/sound_driver.hpp" #include "music/music_driver.hpp" #include "video/video_driver.hpp" #include "fontcache.h" #include "error.h" #include "gui.h" #include "base_media_base.h" #include "saveload/saveload.h" #include "company_func.h" #include "command_func.h" #include "news_func.h" #include "fios.h" #include "aircraft.h" #include "roadveh.h" #include "train.h" #include "ship.h" #include "console_func.h" #include "screenshot.h" #include "network/network.h" #include "network/network_func.h" #include "ai/ai.hpp" #include "ai/ai_config.hpp" #include "settings_func.h" #include "genworld.h" #include "progress.h" #include "strings_func.h" #include "date_func.h" #include "vehicle_func.h" #include "gamelog.h" #include "animated_tile_func.h" #include "roadstop_base.h" #include "elrail_func.h" #include "rev.h" #include "highscore.h" #include "station_base.h" #include "crashlog.h" #include "engine_func.h" #include "core/random_func.hpp" #include "rail_gui.h" #include "core/backup_type.hpp" #include "hotkeys.h" #include "newgrf.h" #include "misc/getoptdata.h" #include "game/game.hpp" #include "game/game_config.hpp" #include "town.h" #include "subsidy_func.h" #include "gfx_layout.h" #include "viewport_sprite_sorter.h" #include "linkgraph/linkgraphschedule.h" #include #include "safeguards.h" void CallLandscapeTick(); void IncreaseDate(); void DoPaletteAnimations(); void MusicLoop(); void ResetMusic(); void CallWindowTickEvent(); bool HandleBootstrap(); extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY); extern void ShowOSErrorBox(const char *buf, bool system); extern char *_config_file; /** * Error handling for fatal user errors. * @param s the string to print. * @note Does NEVER return. */ void CDECL usererror(const char *s, ...) { va_list va; char buf[512]; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); ShowOSErrorBox(buf, false); if (VideoDriver::GetInstance() != NULL) VideoDriver::GetInstance()->Stop(); exit(1); } /** * Error handling for fatal non-user errors. * @param s the string to print. * @note Does NEVER return. */ void CDECL error(const char *s, ...) { va_list va; char buf[512]; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); ShowOSErrorBox(buf, true); /* Set the error message for the crash log and then invoke it. */ CrashLog::SetErrorMessage(buf); abort(); } /** * Shows some information on the console/a popup box depending on the OS. * @param str the text to show. */ void CDECL ShowInfoF(const char *str, ...) { va_list va; char buf[1024]; va_start(va, str); vseprintf(buf, lastof(buf), str, va); va_end(va); ShowInfo(buf); } /** * Show the help message when someone passed a wrong parameter. */ static void ShowHelp() { char buf[8192]; char *p = buf; p += seprintf(p, lastof(buf), "OpenTTD %s\n", _openttd_revision); p = strecpy(p, "\n" "\n" "Command line options:\n" " -v drv = Set video driver (see below)\n" " -s drv = Set sound driver (see below) (param bufsize,hz)\n" " -m drv = Set music driver (see below)\n" " -b drv = Set the blitter to use (see below)\n" " -r res = Set resolution (for instance 800x600)\n" " -h = Display this help text\n" " -t year = Set starting year\n" " -d [[fac=]lvl[,...]]= Debug mode\n" " -e = Start Editor\n" " -g [savegame] = Start new/save game immediately\n" " -G seed = Set random seed\n" #if defined(ENABLE_NETWORK) " -n [ip:port#company]= Join network game\n" " -p password = Password to join server\n" " -P password = Password to join company\n" " -D [ip][:port] = Start dedicated server\n" " -l ip[:port] = Redirect DEBUG()\n" #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) " -f = Fork into the background (dedicated only)\n" #endif #endif /* ENABLE_NETWORK */ " -I graphics_set = Force the graphics set (see below)\n" " -S sounds_set = Force the sounds set (see below)\n" " -M music_set = Force the music set (see below)\n" " -c config_file = Use 'config_file' instead of 'openttd.cfg'\n" " -x = Do not automatically save to config file on exit\n" " -q savegame = Write some information about the savegame and exit\n" "\n", lastof(buf) ); /* List the graphics packs */ p = BaseGraphics::GetSetsList(p, lastof(buf)); /* List the sounds packs */ p = BaseSounds::GetSetsList(p, lastof(buf)); /* List the music packs */ p = BaseMusic::GetSetsList(p, lastof(buf)); /* List the drivers */ p = DriverFactoryBase::GetDriversInfo(p, lastof(buf)); /* List the blitters */ p = BlitterFactory::GetBlittersInfo(p, lastof(buf)); /* List the debug facilities. */ p = DumpDebugFacilityNames(p, lastof(buf)); /* We need to initialize the AI, so it finds the AIs */ AI::Initialize(); p = AI::GetConsoleList(p, lastof(buf), true); AI::Uninitialize(true); /* We need to initialize the GameScript, so it finds the GSs */ Game::Initialize(); p = Game::GetConsoleList(p, lastof(buf), true); Game::Uninitialize(true); /* ShowInfo put output to stderr, but version information should go * to stdout; this is the only exception */ #if !defined(WIN32) && !defined(WIN64) printf("%s\n", buf); #else ShowInfo(buf); #endif } static void WriteSavegameInfo(const char *name) { extern uint16 _sl_version; uint32 last_ottd_rev = 0; byte ever_modified = 0; bool removed_newgrfs = false; GamelogInfo(_load_check_data.gamelog_action, _load_check_data.gamelog_actions, &last_ottd_rev, &ever_modified, &removed_newgrfs); char buf[8192]; char *p = buf; p += seprintf(p, lastof(buf), "Name: %s\n", name); p += seprintf(p, lastof(buf), "Savegame ver: %d\n", _sl_version); p += seprintf(p, lastof(buf), "NewGRF ver: 0x%08X\n", last_ottd_rev); p += seprintf(p, lastof(buf), "Modified: %d\n", ever_modified); if (removed_newgrfs) { p += seprintf(p, lastof(buf), "NewGRFs have been removed\n"); } p = strecpy(p, "NewGRFs:\n", lastof(buf)); if (_load_check_data.HasNewGrfs()) { for (GRFConfig *c = _load_check_data.grfconfig; c != NULL; c = c->next) { char md5sum[33]; md5sumToString(md5sum, lastof(md5sum), HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum); p += seprintf(p, lastof(buf), "%08X %s %s\n", c->ident.grfid, md5sum, c->filename); } } /* ShowInfo put output to stderr, but version information should go * to stdout; this is the only exception */ #if !defined(WIN32) && !defined(WIN64) printf("%s\n", buf); #else ShowInfo(buf); #endif } /** * Extract the resolution from the given string and store * it in the 'res' parameter. * @param res variable to store the resolution in. * @param s the string to decompose. */ static void ParseResolution(Dimension *res, const char *s) { const char *t = strchr(s, 'x'); if (t == NULL) { ShowInfoF("Invalid resolution '%s'", s); return; } res->width = max(strtoul(s, NULL, 0), 64UL); res->height = max(strtoul(t + 1, NULL, 0), 64UL); } /** * Unitializes drivers, frees allocated memory, cleans pools, ... * Generally, prepares the game for shutting down */ static void ShutdownGame() { IConsoleFree(); if (_network_available) NetworkShutDown(); // Shut down the network and close any open connections DriverFactoryBase::ShutdownDrivers(); UnInitWindowSystem(); /* stop the scripts */ AI::Uninitialize(false); Game::Uninitialize(false); /* Uninitialize variables that are allocated dynamically */ GamelogReset(); #ifdef ENABLE_NETWORK free(_config_file); #endif LinkGraphSchedule::Clear(); PoolBase::Clean(PT_ALL); /* No NewGRFs were loaded when it was still bootstrapping. */ if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData(); /* Close all and any open filehandles */ FioCloseAll(); UninitFreeType(); } /** * Load the introduction game. * @param load_newgrfs Whether to load the NewGRFs or not. */ static void LoadIntroGame(bool load_newgrfs = true) { _game_mode = GM_MENU; if (load_newgrfs) ResetGRFConfig(false); /* Setup main window */ ResetWindowSystem(); SetupColoursAndInitialWindow(); /* Load the default opening screen savegame */ if (SaveOrLoad("opntitle.dat", SL_LOAD, BASESET_DIR) != SL_OK) { GenerateWorld(GWM_EMPTY, 64, 64); // if failed loading, make empty world. WaitTillGeneratedWorld(); SetLocalCompany(COMPANY_SPECTATOR); } else { SetLocalCompany(COMPANY_FIRST); } _pause_mode = PM_UNPAUSED; _cursor.fix_at = false; if (load_newgrfs) CheckForMissingSprites(); CheckForMissingGlyphs(); /* Play main theme */ if (MusicDriver::GetInstance()->IsSongPlaying()) ResetMusic(); } void MakeNewgameSettingsLive() { for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (_settings_game.ai_config[c] != NULL) { delete _settings_game.ai_config[c]; } } if (_settings_game.game_config != NULL) { delete _settings_game.game_config; } /* Copy newgame settings to active settings. * Also initialise old settings needed for savegame conversion. */ _settings_game = _settings_newgame; _old_vds = _settings_client.company.vehicle; for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { _settings_game.ai_config[c] = NULL; if (_settings_newgame.ai_config[c] != NULL) { _settings_game.ai_config[c] = new AIConfig(_settings_newgame.ai_config[c]); } } _settings_game.game_config = NULL; if (_settings_newgame.game_config != NULL) { _settings_game.game_config = new GameConfig(_settings_newgame.game_config); } } void OpenBrowser(const char *url) { /* Make sure we only accept urls that are sure to open a browser. */ if (strstr(url, "http://") != url && strstr(url, "https://") != url) return; extern void OSOpenBrowser(const char *url); OSOpenBrowser(url); } /** Callback structure of statements to be executed after the NewGRF scan. */ struct AfterNewGRFScan : NewGRFScanCallback { Year startyear; ///< The start year. uint generation_seed; ///< Seed for the new game. char *dedicated_host; ///< Hostname for the dedicated server. uint16 dedicated_port; ///< Port for the dedicated server. char *network_conn; ///< Information about the server to connect to, or NULL. const char *join_server_password; ///< The password to join the server with. const char *join_company_password; ///< The password to join the company with. bool *save_config_ptr; ///< The pointer to the save config setting. bool save_config; ///< The save config setting. /** * Create a new callback. * @param save_config_ptr Pointer to the save_config local variable which * decides whether to save of exit or not. */ AfterNewGRFScan(bool *save_config_ptr) : startyear(INVALID_YEAR), generation_seed(GENERATE_NEW_SEED), dedicated_host(NULL), dedicated_port(0), network_conn(NULL), join_server_password(NULL), join_company_password(NULL), save_config_ptr(save_config_ptr), save_config(true) { } virtual void OnNewGRFsScanned() { ResetGRFConfig(false); TarScanner::DoScan(TarScanner::SCENARIO); AI::Initialize(); Game::Initialize(); /* We want the new (correct) NewGRF count to survive the loading. */ uint last_newgrf_count = _settings_client.gui.last_newgrf_count; LoadFromConfig(); _settings_client.gui.last_newgrf_count = last_newgrf_count; /* Since the default for the palette might have changed due to * reading the configuration file, recalculate that now. */ UpdateNewGRFConfigPalette(); Game::Uninitialize(true); AI::Uninitialize(true); CheckConfig(); LoadFromHighScore(); LoadHotkeysFromConfig(); WindowDesc::LoadFromConfig(); /* We have loaded the config, so we may possibly save it. */ *save_config_ptr = save_config; /* restore saved music volume */ MusicDriver::GetInstance()->SetVolume(_settings_client.music.music_vol); if (startyear != INVALID_YEAR) _settings_newgame.game_creation.starting_year = startyear; if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed; #if defined(ENABLE_NETWORK) if (dedicated_host != NULL) { _network_bind_list.Clear(); *_network_bind_list.Append() = stredup(dedicated_host); } if (dedicated_port != 0) _settings_client.network.server_port = dedicated_port; #endif /* ENABLE_NETWORK */ /* initialize the ingame console */ IConsoleInit(); InitializeGUI(); IConsoleCmdExec("exec scripts/autoexec.scr 0"); /* Make sure _settings is filled with _settings_newgame if we switch to a game directly */ if (_switch_mode != SM_NONE) MakeNewgameSettingsLive(); #ifdef ENABLE_NETWORK if (_network_available && network_conn != NULL) { const char *port = NULL; const char *company = NULL; uint16 rport = NETWORK_DEFAULT_PORT; CompanyID join_as = COMPANY_NEW_COMPANY; ParseConnectionString(&company, &port, network_conn); if (company != NULL) { join_as = (CompanyID)atoi(company); if (join_as != COMPANY_SPECTATOR) { join_as--; if (join_as >= MAX_COMPANIES) { delete this; return; } } } if (port != NULL) rport = atoi(port); LoadIntroGame(); _switch_mode = SM_NONE; NetworkClientConnectGame(NetworkAddress(network_conn, rport), join_as, join_server_password, join_company_password); } #endif /* ENABLE_NETWORK */ /* After the scan we're not used anymore. */ delete this; } }; #if defined(UNIX) && !defined(__MORPHOS__) extern void DedicatedFork(); #endif /** Options of OpenTTD. */ static const OptionData _options[] = { GETOPT_SHORT_VALUE('I'), GETOPT_SHORT_VALUE('S'), GETOPT_SHORT_VALUE('M'), GETOPT_SHORT_VALUE('m'), GETOPT_SHORT_VALUE('s'), GETOPT_SHORT_VALUE('v'), GETOPT_SHORT_VALUE('b'), #if defined(ENABLE_NETWORK) GETOPT_SHORT_OPTVAL('D'), GETOPT_SHORT_OPTVAL('n'), GETOPT_SHORT_VALUE('l'), GETOPT_SHORT_VALUE('p'), GETOPT_SHORT_VALUE('P'), #if !defined(__MORPHOS__) && !defined(__AMIGA__) && !defined(WIN32) GETOPT_SHORT_NOVAL('f'), #endif #endif /* ENABLE_NETWORK */ GETOPT_SHORT_VALUE('r'), GETOPT_SHORT_VALUE('t'), GETOPT_SHORT_OPTVAL('d'), GETOPT_SHORT_NOVAL('e'), GETOPT_SHORT_OPTVAL('g'), GETOPT_SHORT_VALUE('G'), GETOPT_SHORT_VALUE('c'), GETOPT_SHORT_NOVAL('x'), GETOPT_SHORT_VALUE('q'), GETOPT_SHORT_NOVAL('h'), GETOPT_END() }; /** * Main entry point for this lovely game. * @param argc The number of arguments passed to this game. * @param argv The values of the arguments. * @return 0 when there is no error. */ int openttd_main(int argc, char *argv[]) { char *musicdriver = NULL; char *sounddriver = NULL; char *videodriver = NULL; char *blitter = NULL; char *graphics_set = NULL; char *sounds_set = NULL; char *music_set = NULL; Dimension resolution = {0, 0}; /* AfterNewGRFScan sets save_config to true after scanning completed. */ bool save_config = false; AfterNewGRFScan *scanner = new AfterNewGRFScan(&save_config); #if defined(ENABLE_NETWORK) bool dedicated = false; char *debuglog_conn = NULL; extern bool _dedicated_forks; _dedicated_forks = false; #endif /* ENABLE_NETWORK */ _game_mode = GM_MENU; _switch_mode = SM_MENU; _config_file = NULL; GetOptData mgo(argc - 1, argv + 1, _options); int ret = 0; int i; while ((i = mgo.GetOpt()) != -1) { switch (i) { case 'I': free(graphics_set); graphics_set = stredup(mgo.opt); break; case 'S': free(sounds_set); sounds_set = stredup(mgo.opt); break; case 'M': free(music_set); music_set = stredup(mgo.opt); break; case 'm': free(musicdriver); musicdriver = stredup(mgo.opt); break; case 's': free(sounddriver); sounddriver = stredup(mgo.opt); break; case 'v': free(videodriver); videodriver = stredup(mgo.opt); break; case 'b': free(blitter); blitter = stredup(mgo.opt); break; #if defined(ENABLE_NETWORK) case 'D': free(musicdriver); free(sounddriver); free(videodriver); free(blitter); musicdriver = stredup("null"); sounddriver = stredup("null"); videodriver = stredup("dedicated"); blitter = stredup("null"); dedicated = true; SetDebugString("net=6"); if (mgo.opt != NULL) { /* Use the existing method for parsing (openttd -n). * However, we do ignore the #company part. */ const char *temp = NULL; const char *port = NULL; ParseConnectionString(&temp, &port, mgo.opt); if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt; if (port != NULL) scanner->dedicated_port = atoi(port); } break; case 'f': _dedicated_forks = true; break; case 'n': scanner->network_conn = mgo.opt; // optional IP parameter, NULL if unset break; case 'l': debuglog_conn = mgo.opt; break; case 'p': scanner->join_server_password = mgo.opt; break; case 'P': scanner->join_company_password = mgo.opt; break; #endif /* ENABLE_NETWORK */ case 'r': ParseResolution(&resolution, mgo.opt); break; case 't': scanner->startyear = atoi(mgo.opt); break; case 'd': { #if defined(WIN32) CreateConsole(); #endif if (mgo.opt != NULL) SetDebugString(mgo.opt); break; } case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break; case 'g': if (mgo.opt != NULL) { strecpy(_file_to_saveload.name, mgo.opt, lastof(_file_to_saveload.name)); _switch_mode = (_switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_LOAD_GAME); _file_to_saveload.mode = SL_LOAD; /* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */ const char *t = strrchr(_file_to_saveload.name, '.'); if (t != NULL) { FiosType ft = FiosGetSavegameListCallback(SLD_LOAD_GAME, _file_to_saveload.name, t, NULL, NULL); if (ft != FIOS_TYPE_INVALID) SetFiosType(ft); } break; } _switch_mode = SM_NEWGAME; /* Give a random map if no seed has been given */ if (scanner->generation_seed == GENERATE_NEW_SEED) { scanner->generation_seed = InteractiveRandom(); } break; case 'q': { DeterminePaths(argv[0]); if (StrEmpty(mgo.opt)) { ret = 1; goto exit_noshutdown; } char title[80]; title[0] = '\0'; FiosGetSavegameListCallback(SLD_LOAD_GAME, mgo.opt, strrchr(mgo.opt, '.'), title, lastof(title)); _load_check_data.Clear(); SaveOrLoadResult res = SaveOrLoad(mgo.opt, SL_LOAD_CHECK, SAVE_DIR, false); if (res != SL_OK || _load_check_data.HasErrors()) { fprintf(stderr, "Failed to open savegame\n"); if (_load_check_data.HasErrors()) { char buf[256]; SetDParamStr(0, _load_check_data.error_data); GetString(buf, _load_check_data.error, lastof(buf)); fprintf(stderr, "%s\n", buf); } goto exit_noshutdown; } WriteSavegameInfo(title); goto exit_noshutdown; } case 'G': scanner->generation_seed = atoi(mgo.opt); break; case 'c': free(_config_file); _config_file = stredup(mgo.opt); break; case 'x': scanner->save_config = false; break; case 'h': i = -2; // Force printing of help. break; } if (i == -2) break; } if (i == -2 || mgo.numleft > 0) { /* Either the user typed '-h', he made an error, or he added unrecognized command line arguments. * In all cases, print the help, and exit. * * The next two functions are needed to list the graphics sets. We can't do them earlier * because then we cannot show it on the debug console as that hasn't been configured yet. */ DeterminePaths(argv[0]); TarScanner::DoScan(TarScanner::BASESET); BaseGraphics::FindSets(); BaseSounds::FindSets(); BaseMusic::FindSets(); ShowHelp(); goto exit_noshutdown; } #if defined(WINCE) && defined(_DEBUG) /* Switch on debug lvl 4 for WinCE if Debug release, as you can't give params, and you most likely do want this information */ SetDebugString("4"); #endif DeterminePaths(argv[0]); TarScanner::DoScan(TarScanner::BASESET); #if defined(ENABLE_NETWORK) if (dedicated) DEBUG(net, 0, "Starting dedicated version %s", _openttd_revision); if (_dedicated_forks && !dedicated) _dedicated_forks = false; #if defined(UNIX) && !defined(__MORPHOS__) /* We must fork here, or we'll end up without some resources we need (like sockets) */ if (_dedicated_forks) DedicatedFork(); #endif #endif LoadFromConfig(true); if (resolution.width != 0) _cur_resolution = resolution; /* * The width and height must be at least 1 pixel and width times * height times bytes per pixel must still fit within a 32 bits * integer, even for 32 bpp video modes. This way all internal * drawing routines work correctly. */ _cur_resolution.width = ClampU(_cur_resolution.width, 1, UINT16_MAX / 2); _cur_resolution.height = ClampU(_cur_resolution.height, 1, UINT16_MAX / 2); /* Assume the cursor starts within the game as not all video drivers * get an event that the cursor is within the window when it is opened. * Saying the cursor is there makes no visible difference as it would * just be out of the bounds of the window. */ _cursor.in_window = true; /* enumerate language files */ InitializeLanguagePacks(); /* Initialize the regular font for FreeType */ InitFreeType(false); /* This must be done early, since functions use the SetWindowDirty* calls */ InitWindowSystem(); BaseGraphics::FindSets(); if (graphics_set == NULL && BaseGraphics::ini_set != NULL) graphics_set = stredup(BaseGraphics::ini_set); if (!BaseGraphics::SetSet(graphics_set)) { if (!StrEmpty(graphics_set)) { BaseGraphics::SetSet(NULL); ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND); msg.SetDParamStr(0, graphics_set); ScheduleErrorMessage(msg); } } free(graphics_set); /* Initialize game palette */ GfxInitPalettes(); DEBUG(misc, 1, "Loading blitter..."); if (blitter == NULL && _ini_blitter != NULL) blitter = stredup(_ini_blitter); _blitter_autodetected = StrEmpty(blitter); /* Activate the initial blitter. * This is only some initial guess, after NewGRFs have been loaded SwitchNewGRFBlitter may switch to a different one. * - Never guess anything, if the user specified a blitter. (_blitter_autodetected) * - Use 32bpp blitter if baseset or 8bpp-support settings says so. * - Use 8bpp blitter otherwise. */ if (!_blitter_autodetected || (_support8bpp != S8BPP_NONE && (BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->blitter == BLT_8BPP)) || BlitterFactory::SelectBlitter("32bpp-anim") == NULL) { if (BlitterFactory::SelectBlitter(blitter) == NULL) { StrEmpty(blitter) ? usererror("Failed to autoprobe blitter") : usererror("Failed to select requested blitter '%s'; does it exist?", blitter); } } free(blitter); if (videodriver == NULL && _ini_videodriver != NULL) videodriver = stredup(_ini_videodriver); DriverFactoryBase::SelectDriver(videodriver, Driver::DT_VIDEO); free(videodriver); InitializeSpriteSorter(); /* Initialize the zoom level of the screen to normal */ _screen.zoom = ZOOM_LVL_NORMAL; NetworkStartUp(); // initialize network-core #if defined(ENABLE_NETWORK) if (debuglog_conn != NULL && _network_available) { const char *not_used = NULL; const char *port = NULL; uint16 rport; rport = NETWORK_DEFAULT_DEBUGLOG_PORT; ParseConnectionString(¬_used, &port, debuglog_conn); if (port != NULL) rport = atoi(port); NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport)); } #endif /* ENABLE_NETWORK */ if (!HandleBootstrap()) { ShutdownGame(); goto exit_bootstrap; } VideoDriver::GetInstance()->ClaimMousePointer(); /* initialize screenshot formats */ InitializeScreenshotFormats(); BaseSounds::FindSets(); if (sounds_set == NULL && BaseSounds::ini_set != NULL) sounds_set = stredup(BaseSounds::ini_set); if (!BaseSounds::SetSet(sounds_set)) { if (StrEmpty(sounds_set) || !BaseSounds::SetSet(NULL)) { usererror("Failed to find a sounds set. Please acquire a sounds set for OpenTTD. See section 4.1 of readme.txt."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND); msg.SetDParamStr(0, sounds_set); ScheduleErrorMessage(msg); } } free(sounds_set); BaseMusic::FindSets(); if (music_set == NULL && BaseMusic::ini_set != NULL) music_set = stredup(BaseMusic::ini_set); if (!BaseMusic::SetSet(music_set)) { if (StrEmpty(music_set) || !BaseMusic::SetSet(NULL)) { usererror("Failed to find a music set. Please acquire a music set for OpenTTD. See section 4.1 of readme.txt."); } else { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND); msg.SetDParamStr(0, music_set); ScheduleErrorMessage(msg); } } free(music_set); if (sounddriver == NULL && _ini_sounddriver != NULL) sounddriver = stredup(_ini_sounddriver); DriverFactoryBase::SelectDriver(sounddriver, Driver::DT_SOUND); free(sounddriver); if (musicdriver == NULL && _ini_musicdriver != NULL) musicdriver = stredup(_ini_musicdriver); DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC); free(musicdriver); /* Take our initial lock on whatever we might want to do! */ _modal_progress_paint_mutex->BeginCritical(); _modal_progress_work_mutex->BeginCritical(); GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy WaitTillGeneratedWorld(); LoadIntroGame(false); CheckForMissingGlyphs(); /* ScanNewGRFFiles now has control over the scanner. */ ScanNewGRFFiles(scanner); scanner = NULL; VideoDriver::GetInstance()->MainLoop(); WaitTillSaved(); /* only save config if we have to */ if (save_config) { SaveToConfig(); SaveHotkeysToConfig(); WindowDesc::SaveToConfig(); SaveToHighScore(); } /* Reset windowing system, stop drivers, free used memory, ... */ ShutdownGame(); goto exit_normal; exit_noshutdown: /* These three are normally freed before bootstrap. */ free(graphics_set); free(videodriver); free(blitter); exit_bootstrap: /* These are normally freed before exit, but after bootstrap. */ free(sounds_set); free(music_set); free(musicdriver); free(sounddriver); exit_normal: free(BaseGraphics::ini_set); free(BaseSounds::ini_set); free(BaseMusic::ini_set); free(_ini_musicdriver); free(_ini_sounddriver); free(_ini_videodriver); free(_ini_blitter); delete scanner; #ifdef ENABLE_NETWORK extern FILE *_log_fd; if (_log_fd != NULL) { fclose(_log_fd); } #endif /* ENABLE_NETWORK */ return ret; } void HandleExitGameRequest() { if (_game_mode == GM_MENU || _game_mode == GM_BOOTSTRAP) { // do not ask to quit on the main screen _exit_game = true; } else if (_settings_client.gui.autosave_on_exit) { DoExitSave(); _exit_game = true; } else { AskExitGame(); } } static void MakeNewGameDone() { SettingsDisableElrail(_settings_game.vehicle.disable_elrails); /* In a dedicated server, the server does not play */ if (!VideoDriver::GetInstance()->HasGUI()) { SetLocalCompany(COMPANY_SPECTATOR); if (_settings_client.gui.pause_on_newgame) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); IConsoleCmdExec("exec scripts/game_start.scr 0"); return; } /* Create a single company */ DoStartupNewCompany(false); Company *c = Company::Get(COMPANY_FIRST); c->settings = _settings_client.company; IConsoleCmdExec("exec scripts/game_start.scr 0"); SetLocalCompany(COMPANY_FIRST); InitializeRailGUI(); #ifdef ENABLE_NETWORK /* We are the server, we start a new company (not dedicated), * so set the default password *if* needed. */ if (_network_server && !StrEmpty(_settings_client.network.default_company_pass)) { NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass); } #endif /* ENABLE_NETWORK */ if (_settings_client.gui.pause_on_newgame) DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); CheckEngines(); CheckIndustries(); MarkWholeScreenDirty(); } static void MakeNewGame(bool from_heightmap, bool reset_settings) { _game_mode = GM_NORMAL; ResetGRFConfig(true); GenerateWorldSetCallback(&MakeNewGameDone); GenerateWorld(from_heightmap ? GWM_HEIGHTMAP : GWM_NEWGAME, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y, reset_settings); } static void MakeNewEditorWorldDone() { SetLocalCompany(OWNER_NONE); } static void MakeNewEditorWorld() { _game_mode = GM_EDITOR; ResetGRFConfig(true); GenerateWorldSetCallback(&MakeNewEditorWorldDone); GenerateWorld(GWM_EMPTY, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); } /** * Load the specified savegame but on error do different things. * If loading fails due to corrupt savegame, bad version, etc. go back to * a previous correct state. In the menu for example load the intro game again. * @param mode mode of loading, either SL_LOAD or SL_OLD_LOAD * @param newgm switch to this mode of loading fails due to some unknown error * @param filename file to be loaded * @param subdir default directory to look for filename, set to 0 if not needed * @param lf Load filter to use, if NULL: use filename + subdir. */ bool SafeLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL) { assert(mode == SL_LOAD || (lf == NULL && mode == SL_OLD_LOAD)); GameMode ogm = _game_mode; _game_mode = newgm; switch (lf == NULL ? SaveOrLoad(filename, mode, subdir) : LoadWithFilter(lf)) { case SL_OK: return true; case SL_REINIT: #ifdef ENABLE_NETWORK if (_network_dedicated) { /* * We need to reinit a network map... * We can't simply load the intro game here as that game has many * special cases which make clients desync immediately. So we fall * back to just generating a new game with the current settings. */ DEBUG(net, 0, "Loading game failed, so a new (random) game will be started!"); MakeNewGame(false, true); return false; } if (_network_server) { /* We can't load the intro game as server, so disconnect first. */ NetworkDisconnect(); } #endif /* ENABLE_NETWORK */ switch (ogm) { default: case GM_MENU: LoadIntroGame(); break; case GM_EDITOR: MakeNewEditorWorld(); break; } return false; default: _game_mode = ogm; return false; } } void SwitchToMode(SwitchMode new_mode) { #ifdef ENABLE_NETWORK /* If we are saving something, the network stays in his current state */ if (new_mode != SM_SAVE_GAME) { /* If the network is active, make it not-active */ if (_networking) { if (_network_server && (new_mode == SM_LOAD_GAME || new_mode == SM_NEWGAME || new_mode == SM_RESTARTGAME)) { NetworkReboot(); } else { NetworkDisconnect(); } } /* If we are a server, we restart the server */ if (_is_network_server) { /* But not if we are going to the menu */ if (new_mode != SM_MENU) { /* check if we should reload the config */ if (_settings_client.network.reload_cfg) { LoadFromConfig(); MakeNewgameSettingsLive(); ResetGRFConfig(false); } NetworkServerStart(); } else { /* This client no longer wants to be a network-server */ _is_network_server = false; } } } #endif /* ENABLE_NETWORK */ /* Make sure all AI controllers are gone at quitting game */ if (new_mode != SM_SAVE_GAME) AI::KillAll(); switch (new_mode) { case SM_EDITOR: // Switch to scenario editor MakeNewEditorWorld(); break; case SM_RESTARTGAME: // Restart --> 'Random game' with current settings case SM_NEWGAME: // New Game --> 'Random game' #ifdef ENABLE_NETWORK if (_network_server) { seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "Random Map"); } #endif /* ENABLE_NETWORK */ MakeNewGame(false, new_mode == SM_NEWGAME); break; case SM_LOAD_GAME: { // Load game, Play Scenario ResetGRFConfig(true); ResetWindowSystem(); if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, NO_DIRECTORY)) { SetDParamStr(0, GetSaveLoadErrorString()); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } else { if (_saveload_mode == SLD_LOAD_SCENARIO) { /* Reset engine pool to simplify changing engine NewGRFs in scenario editor. */ EngineOverrideManager::ResetToCurrentNewGRFConfig(); } /* Update the local company for a loaded game. It is either always * company #1 (eg 0) or in the case of a dedicated server a spectator */ SetLocalCompany(_network_dedicated ? COMPANY_SPECTATOR : COMPANY_FIRST); /* Execute the game-start script */ IConsoleCmdExec("exec scripts/game_start.scr 0"); /* Decrease pause counter (was increased from opening load dialog) */ DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE); #ifdef ENABLE_NETWORK if (_network_server) { seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title); } #endif /* ENABLE_NETWORK */ } break; } case SM_START_HEIGHTMAP: // Load a heightmap and start a new game from it #ifdef ENABLE_NETWORK if (_network_server) { seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title); } #endif /* ENABLE_NETWORK */ MakeNewGame(true, true); break; case SM_LOAD_HEIGHTMAP: // Load heightmap from scenario editor SetLocalCompany(OWNER_NONE); GenerateWorld(GWM_HEIGHTMAP, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); MarkWholeScreenDirty(); break; case SM_LOAD_SCENARIO: { // Load scenario from scenario editor if (SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_EDITOR, NO_DIRECTORY)) { SetLocalCompany(OWNER_NONE); _settings_newgame.game_creation.starting_year = _cur_year; /* Cancel the saveload pausing */ DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE); } else { SetDParamStr(0, GetSaveLoadErrorString()); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } break; } case SM_MENU: // Switch to game intro menu LoadIntroGame(); if (BaseSounds::ini_set == NULL && BaseSounds::GetUsedSet()->fallback) { ShowErrorMessage(STR_WARNING_FALLBACK_SOUNDSET, INVALID_STRING_ID, WL_CRITICAL); BaseSounds::ini_set = stredup(BaseSounds::GetUsedSet()->name); } break; case SM_SAVE_GAME: // Save game. /* Make network saved games on pause compatible to singleplayer */ if (SaveOrLoad(_file_to_saveload.name, SL_SAVE, NO_DIRECTORY) != SL_OK) { SetDParamStr(0, GetSaveLoadErrorString()); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } else { DeleteWindowById(WC_SAVELOAD, 0); } break; case SM_SAVE_HEIGHTMAP: // Save heightmap. MakeHeightmapScreenshot(_file_to_saveload.name); DeleteWindowById(WC_SAVELOAD, 0); break; case SM_GENRANDLAND: // Generate random land within scenario editor SetLocalCompany(OWNER_NONE); GenerateWorld(GWM_RANDOM, 1 << _settings_game.game_creation.map_x, 1 << _settings_game.game_creation.map_y); /* XXX: set date */ MarkWholeScreenDirty(); break; default: NOT_REACHED(); } } /** * Check the validity of some of the caches. * Especially in the sense of desyncs between * the cached value and what the value would * be when calculated from the 'base' data. */ static void CheckCaches() { /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ if (_debug_desync_level <= 1) return; /* Check the town caches. */ SmallVector old_town_caches; Town *t; FOR_ALL_TOWNS(t) { MemCpyT(old_town_caches.Append(), &t->cache); } extern void RebuildTownCaches(); RebuildTownCaches(); RebuildSubsidisedSourceAndDestinationCache(); uint i = 0; FOR_ALL_TOWNS(t) { if (MemCmpT(old_town_caches.Get(i), &t->cache) != 0) { DEBUG(desync, 2, "town cache mismatch: town %i", (int)t->index); } i++; } /* Check company infrastructure cache. */ SmallVector old_infrastructure; Company *c; FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure); extern void AfterLoadCompanyStats(); AfterLoadCompanyStats(); i = 0; FOR_ALL_COMPANIES(c) { if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) { DEBUG(desync, 2, "infrastructure cache mismatch: company %i", (int)c->index); } i++; } /* Strict checking of the road stop cache entries */ const RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { if (IsStandardRoadStopTile(rs->xy)) continue; assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); } Vehicle *v; FOR_ALL_VEHICLES(v) { extern void FillNewGRFVehicleCache(const Vehicle *v); if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; uint length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) length++; NewGRFCache *grf_cache = CallocT(length); VehicleCache *veh_cache = CallocT(length); GroundVehicleCache *gro_cache = CallocT(length); TrainCache *tra_cache = CallocT(length); length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); grf_cache[length] = u->grf_cache; veh_cache[length] = u->vcache; switch (u->type) { case VEH_TRAIN: gro_cache[length] = Train::From(u)->gcache; tra_cache[length] = Train::From(u)->tcache; break; case VEH_ROAD: gro_cache[length] = RoadVehicle::From(u)->gcache; break; default: break; } length++; } switch (v->type) { case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; case VEH_SHIP: Ship::From(v)->UpdateCache(); break; default: break; } length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { DEBUG(desync, 2, "newgrf cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) { DEBUG(desync, 2, "vehicle cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } switch (u->type) { case VEH_TRAIN: if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "train ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { DEBUG(desync, 2, "train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; case VEH_ROAD: if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; default: break; } length++; } free(grf_cache); free(veh_cache); free(gro_cache); free(tra_cache); } /* Check whether the caches are still valid */ FOR_ALL_VEHICLES(v) { byte buff[sizeof(VehicleCargoList)]; memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); v->cargo.InvalidateCache(); assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); } Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) { byte buff[sizeof(StationCargoList)]; memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); st->goods[c].cargo.InvalidateCache(); assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); } } } /** * State controlling game loop. * The state must not be changed from anywhere but here. * That check is enforced in DoCommand. */ void StateGameLoop() { /* don't execute the state loop during pause */ if (_pause_mode != PM_UNPAUSED) { UpdateLandscapingLimits(); #ifndef DEBUG_DUMP_COMMANDS Game::GameLoop(); #endif CallWindowTickEvent(); return; } if (HasModalProgress()) return; Layouter::ReduceLineCache(); if (_game_mode == GM_EDITOR) { BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP); RunTileLoop(); CallVehicleTicks(); CallLandscapeTick(); BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP); UpdateLandscapingLimits(); CallWindowTickEvent(); NewsLoop(); } else { if (_debug_desync_level > 2 && _date_fract == 0 && (_date & 0x1F) == 0) { /* Save the desync savegame if needed. */ char name[MAX_PATH]; seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date); SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR, false); } CheckCaches(); /* All these actions has to be done from OWNER_NONE * for multiplayer compatibility */ Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP); AnimateAnimatedTiles(); IncreaseDate(); RunTileLoop(); CallVehicleTicks(); CallLandscapeTick(); BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP); #ifndef DEBUG_DUMP_COMMANDS AI::GameLoop(); Game::GameLoop(); #endif UpdateLandscapingLimits(); CallWindowTickEvent(); NewsLoop(); cur_company.Restore(); } assert(IsLocalCompany()); } /** * Create an autosave. The default name is "autosave#.sav". However with * the setting 'keep_all_autosave' the name defaults to company-name + date */ static void DoAutosave() { char buf[MAX_PATH]; #if defined(PSP) /* Autosaving in networking is too time expensive for the PSP */ if (_networking) return; #endif /* PSP */ if (_settings_client.gui.keep_all_autosave) { GenerateDefaultSaveName(buf, lastof(buf)); strecat(buf, ".sav", lastof(buf)); } else { static int _autosave_ctr = 0; /* generate a savegame name and number according to _settings_client.gui.max_num_autosaves */ seprintf(buf, lastof(buf), "autosave%d.sav", _autosave_ctr); if (++_autosave_ctr >= _settings_client.gui.max_num_autosaves) _autosave_ctr = 0; } DEBUG(sl, 2, "Autosaving to '%s'", buf); if (SaveOrLoad(buf, SL_SAVE, AUTOSAVE_DIR) != SL_OK) { ShowErrorMessage(STR_ERROR_AUTOSAVE_FAILED, INVALID_STRING_ID, WL_ERROR); } } void GameLoop() { if (_game_mode == GM_BOOTSTRAP) { #ifdef ENABLE_NETWORK /* Check for UDP stuff */ if (_network_available) NetworkBackgroundLoop(); #endif InputLoop(); return; } ProcessAsyncSaveFinish(); /* autosave game? */ if (_do_autosave) { DoAutosave(); _do_autosave = false; SetWindowDirty(WC_STATUS_BAR, 0); } /* switch game mode? */ if (_switch_mode != SM_NONE && !HasModalProgress()) { SwitchToMode(_switch_mode); _switch_mode = SM_NONE; } IncreaseSpriteLRU(); InteractiveRandom(); extern int _caret_timer; _caret_timer += 3; CursorTick(); #ifdef ENABLE_NETWORK /* Check for UDP stuff */ if (_network_available) NetworkBackgroundLoop(); if (_networking && !HasModalProgress()) { /* Multiplayer */ NetworkGameLoop(); } else { if (_network_reconnect > 0 && --_network_reconnect == 0) { /* This means that we want to reconnect to the last host * We do this here, because it means that the network is really closed */ NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); } /* Singleplayer */ StateGameLoop(); } /* Check chat messages roughly once a second. */ static uint check_message = 0; if (++check_message > 1000 / MILLISECONDS_PER_TICK) { check_message = 0; NetworkChatMessageLoop(); } #else StateGameLoop(); #endif /* ENABLE_NETWORK */ if (!_pause_mode && HasBit(_display_opt, DO_FULL_ANIMATION)) DoPaletteAnimations(); if (!_pause_mode || _game_mode == GM_EDITOR || _settings_game.construction.command_pause_level > CMDPL_NO_CONSTRUCTION) MoveAllTextEffects(); InputLoop(); SoundDriver::GetInstance()->MainLoop(); MusicLoop(); } openttd-1.5.3/src/cargomonitor.h0000644000000000000000000001314012627373442015347 0ustar rootroot/* $Id: cargomonitor.h 26685 2014-07-12 17:04:14Z alberth $ */ /* * 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 cargomonitor.h Cargo transport monitoring declarations. */ #ifndef CARGOMONITOR_H #define CARGOMONITOR_H #include "cargo_type.h" #include "company_func.h" #include "industry.h" #include "town.h" #include "core/overflowsafe_type.hpp" #include struct Station; /** * Unique number for a company / cargo type / (town or industry). * Encoding is as follows: * - bits 0-15 town or industry number * - bit 16 is set if it is an industry number (else it is a town number). * - bits 19-23 Cargo type. * - bits 24-31 %Company number. */ typedef uint32 CargoMonitorID; ///< Type of the cargo monitor number. /** Map type for storing and updating active cargo monitor numbers and their amounts. */ typedef std::map CargoMonitorMap; extern CargoMonitorMap _cargo_pickups; extern CargoMonitorMap _cargo_deliveries; /** Constants for encoding and extracting cargo monitors. */ enum CargoCompanyBits { CCB_TOWN_IND_NUMBER_START = 0, ///< Start bit of the town or industry number. CCB_TOWN_IND_NUMBER_LENGTH = 16, ///< Number of bits of the town or industry number. CCB_IS_INDUSTRY_BIT = 16, ///< Bit indicating the town/industry number is an industry. CCB_IS_INDUSTRY_BIT_VALUE = 1ul << CCB_IS_INDUSTRY_BIT, ///< Value of the #CCB_IS_INDUSTRY_BIT bit. CCB_CARGO_TYPE_START = 19, ///< Start bit of the cargo type field. CCB_CARGO_TYPE_LENGTH = 5, ///< Number of bits of the cargo type field. CCB_COMPANY_START = 24, ///< Start bit of the company field. CCB_COMPANY_LENGTH = 8, ///< Number of bits of the company field. }; /** * Encode a cargo monitor for pickup or delivery at an industry. * @param company Company performing the transport. * @param ctype Cargo type being transported. * @param ind %Industry providing or accepting the cargo. * @return The encoded cargo/company/industry number. */ static inline CargoMonitorID EncodeCargoIndustryMonitor(CompanyID company, CargoID ctype, IndustryID ind) { assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH)); uint32 ret = 0; SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, ind); SetBit(ret, CCB_IS_INDUSTRY_BIT); SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company); return ret; } /** * Encode a cargo monitoring number for pickup or delivery at a town. * @param company %Company performing the transport. * @param ctype Cargo type being transported. * @param town %Town providing or accepting the cargo. * @return The encoded cargo/company/town number. */ static inline CargoMonitorID EncodeCargoTownMonitor(CompanyID company, CargoID ctype, TownID town) { assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH)); uint32 ret = 0; SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, town); SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company); return ret; } /** * Extract the company from the cargo monitor. * @param num Cargo monitoring number to decode. * @return The extracted company id. */ static inline CompanyID DecodeMonitorCompany(CargoMonitorID num) { return static_cast(GB(num, CCB_COMPANY_START, CCB_COMPANY_LENGTH)); } /** * Extract the cargo type from the cargo monitor. * @param num Cargo monitoring number to decode. * @return The extracted cargo type. */ static inline CargoID DecodeMonitorCargoType(CargoMonitorID num) { return GB(num, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH); } /** * Does the cargo number monitor an industry or a town? * @param num Cargo monitoring number to decode. * @return true if monitoring an industry, false if monitoring a town. */ static inline bool MonitorMonitorsIndustry(CargoMonitorID num) { return HasBit(num, CCB_IS_INDUSTRY_BIT); } /** * Extract the industry number from the cargo monitor. * @param num Cargo monitoring number to decode. * @return The extracted industry id, or #INVALID_INDUSTRY if the number does not monitor an industry. */ static inline IndustryID DecodeMonitorIndustry(CargoMonitorID num) { if (!MonitorMonitorsIndustry(num)) return INVALID_INDUSTRY; return GB(num, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH); } /** * Extract the town number from the cargo monitor. * @param num Cargo monitoring number to decode. * @return The extracted town id, or #INVALID_TOWN if the number does not monitor a town. */ static inline TownID DecodeMonitorTown(CargoMonitorID num) { if (MonitorMonitorsIndustry(num)) return INVALID_TOWN; return GB(num, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH); } void ClearCargoPickupMonitoring(CompanyID company = INVALID_OWNER); void ClearCargoDeliveryMonitoring(CompanyID company = INVALID_OWNER); int32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring); int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring); void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st); #endif /* CARGOMONITOR_H */ openttd-1.5.3/src/station.cpp0000644000000000000000000004225512627373442014671 0ustar rootroot/* $Id: station.cpp 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 station.cpp Implementation of the station base class. */ #include "stdafx.h" #include "company_func.h" #include "company_base.h" #include "roadveh.h" #include "viewport_func.h" #include "date_func.h" #include "command_func.h" #include "news_func.h" #include "aircraft.h" #include "vehiclelist.h" #include "core/pool_func.hpp" #include "station_base.h" #include "roadstop_base.h" #include "industry.h" #include "core/random_func.hpp" #include "linkgraph/linkgraph.h" #include "linkgraph/linkgraphschedule.h" #include "table/strings.h" #include "safeguards.h" /** The pool of stations. */ StationPool _station_pool("Station"); INSTANTIATE_POOL_METHODS(Station) typedef StationIDStack::SmallStackPool StationIDStackPool; template<> StationIDStackPool StationIDStack::_pool = StationIDStackPool(); BaseStation::~BaseStation() { free(this->name); free(this->speclist); if (CleaningPool()) return; DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->index).Pack()); DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->index).Pack()); DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->index).Pack()); DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->index).Pack()); this->sign.MarkDirty(); } Station::Station(TileIndex tile) : SpecializedStation(tile), bus_station(INVALID_TILE, 0, 0), truck_station(INVALID_TILE, 0, 0), dock_tile(INVALID_TILE), indtype(IT_INVALID), time_since_load(255), time_since_unload(255), last_vehicle_type(VEH_INVALID) { /* this->random_bits is set in Station::AddFacility() */ } /** * Clean up a station by clearing vehicle orders, invalidating windows and * removing link stats. * Aircraft-Hangar orders need special treatment here, as the hangars are * actually part of a station (tiletype is STATION), but the order type * is OT_GOTO_DEPOT. */ Station::~Station() { if (CleaningPool()) { for (CargoID c = 0; c < NUM_CARGO; c++) { this->goods[c].cargo.OnCleanPool(); } return; } while (!this->loading_vehicles.empty()) { this->loading_vehicles.front()->LeaveStation(); } Aircraft *a; FOR_ALL_AIRCRAFT(a) { if (!a->IsNormalAircraft()) continue; if (a->targetairport == this->index) a->targetairport = INVALID_STATION; } for (CargoID c = 0; c < NUM_CARGO; ++c) { LinkGraph *lg = LinkGraph::GetIfValid(this->goods[c].link_graph); if (lg == NULL) continue; for (NodeID node = 0; node < lg->Size(); ++node) { Station *st = Station::Get((*lg)[node].Station()); st->goods[c].flows.erase(this->index); if ((*lg)[node][this->goods[c].node].LastUpdate() != INVALID_DATE) { st->goods[c].flows.DeleteFlows(this->index); RerouteCargo(st, c, this->index, st->index); } } lg->RemoveNode(this->goods[c].node); if (lg->Size() == 0) { LinkGraphSchedule::instance.Unqueue(lg); delete lg; } } Vehicle *v; FOR_ALL_VEHICLES(v) { /* Forget about this station if this station is removed */ if (v->last_station_visited == this->index) { v->last_station_visited = INVALID_STATION; } if (v->last_loading_station == this->index) { v->last_loading_station = INVALID_STATION; } } /* Clear the persistent storage. */ delete this->airport.psa; if (this->owner == OWNER_NONE) { /* Invalidate all in case of oil rigs. */ InvalidateWindowClassesData(WC_STATION_LIST, 0); } else { InvalidateWindowData(WC_STATION_LIST, this->owner, 0); } DeleteWindowById(WC_STATION_VIEW, index); /* Now delete all orders that go to the station */ RemoveOrderFromAllVehicles(OT_GOTO_STATION, this->index); /* Remove all news items */ DeleteStationNews(this->index); for (CargoID c = 0; c < NUM_CARGO; c++) { this->goods[c].cargo.Truncate(); } CargoPacket::InvalidateAllFrom(this->index); } /** * Invalidating of the JoinStation window has to be done * after removing item from the pool. * @param index index of deleted item */ void BaseStation::PostDestructor(size_t index) { InvalidateWindowData(WC_SELECT_STATION, 0, 0); } /** * Get the primary road stop (the first road stop) that the given vehicle can load/unload. * @param v the vehicle to get the first road stop for * @return the first roadstop that this vehicle can load at */ RoadStop *Station::GetPrimaryRoadStop(const RoadVehicle *v) const { RoadStop *rs = this->GetPrimaryRoadStop(v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK); for (; rs != NULL; rs = rs->next) { /* The vehicle cannot go to this roadstop (different roadtype) */ if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue; /* The vehicle is articulated and can therefore not go to a standard road stop. */ if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue; /* The vehicle can actually go to this road stop. So, return it! */ break; } return rs; } /** * Called when new facility is built on the station. If it is the first facility * it initializes also 'xy' and 'random_bits' members */ void Station::AddFacility(StationFacility new_facility_bit, TileIndex facil_xy) { if (this->facilities == FACIL_NONE) { this->xy = facil_xy; this->random_bits = Random(); } this->facilities |= new_facility_bit; this->owner = _current_company; this->build_date = _date; } /** * Marks the tiles of the station as dirty. * * @ingroup dirty */ void Station::MarkTilesDirty(bool cargo_change) const { TileIndex tile = this->train_station.tile; int w, h; if (tile == INVALID_TILE) return; /* cargo_change is set if we're refreshing the tiles due to cargo moving * around. */ if (cargo_change) { /* Don't waste time updating if there are no custom station graphics * that might change. Even if there are custom graphics, they might * not change. Unfortunately we have no way of telling. */ if (this->num_specs == 0) return; } for (h = 0; h < train_station.h; h++) { for (w = 0; w < train_station.w; w++) { if (this->TileBelongsToRailStation(tile)) { MarkTileDirtyByTile(tile); } tile += TileDiffXY(1, 0); } tile += TileDiffXY(-w, 1); } } /* virtual */ uint Station::GetPlatformLength(TileIndex tile) const { assert(this->TileBelongsToRailStation(tile)); TileIndexDiff delta = (GetRailStationAxis(tile) == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); TileIndex t = tile; uint len = 0; do { t -= delta; len++; } while (IsCompatibleTrainStationTile(t, tile)); t = tile; do { t += delta; len++; } while (IsCompatibleTrainStationTile(t, tile)); return len - 1; } /* virtual */ uint Station::GetPlatformLength(TileIndex tile, DiagDirection dir) const { TileIndex start_tile = tile; uint length = 0; assert(IsRailStationTile(tile)); assert(dir < DIAGDIR_END); do { length++; tile += TileOffsByDiagDir(dir); } while (IsCompatibleTrainStationTile(tile, start_tile)); return length; } /** * Determines the catchment radius of the station * @return The radius */ uint Station::GetCatchmentRadius() const { uint ret = CA_NONE; if (_settings_game.station.modified_catchment) { if (this->bus_stops != NULL) ret = max(ret, CA_BUS); if (this->truck_stops != NULL) ret = max(ret, CA_TRUCK); if (this->train_station.tile != INVALID_TILE) ret = max(ret, CA_TRAIN); if (this->dock_tile != INVALID_TILE) ret = max(ret, CA_DOCK); if (this->airport.tile != INVALID_TILE) ret = max(ret, this->airport.GetSpec()->catchment); } else { if (this->bus_stops != NULL || this->truck_stops != NULL || this->train_station.tile != INVALID_TILE || this->dock_tile != INVALID_TILE || this->airport.tile != INVALID_TILE) { ret = CA_UNMODIFIED; } } return ret; } /** * Determines catchment rectangle of this station * @return clamped catchment rectangle */ Rect Station::GetCatchmentRect() const { assert(!this->rect.IsEmpty()); /* Compute acceptance rectangle */ int catchment_radius = this->GetCatchmentRadius(); Rect ret = { max(this->rect.left - catchment_radius, 0), max(this->rect.top - catchment_radius, 0), min(this->rect.right + catchment_radius, MapMaxX()), min(this->rect.bottom + catchment_radius, MapMaxY()) }; return ret; } /** Rect and pointer to IndustryVector */ struct RectAndIndustryVector { Rect rect; ///< The rectangle to search the industries in. IndustryVector *industries_near; ///< The nearby industries. }; /** * Callback function for Station::RecomputeIndustriesNear() * Tests whether tile is an industry and possibly adds * the industry to station's industries_near list. * @param ind_tile tile to check * @param user_data pointer to RectAndIndustryVector * @return always false, we want to search all tiles */ static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data) { /* Only process industry tiles */ if (!IsTileType(ind_tile, MP_INDUSTRY)) return false; RectAndIndustryVector *riv = (RectAndIndustryVector *)user_data; Industry *ind = Industry::GetByTile(ind_tile); /* Don't check further if this industry is already in the list */ if (riv->industries_near->Contains(ind)) return false; /* Only process tiles in the station acceptance rectangle */ int x = TileX(ind_tile); int y = TileY(ind_tile); if (x < riv->rect.left || x > riv->rect.right || y < riv->rect.top || y > riv->rect.bottom) return false; /* Include only industries that can accept cargo */ uint cargo_index; for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) { if (ind->accepts_cargo[cargo_index] != CT_INVALID) break; } if (cargo_index >= lengthof(ind->accepts_cargo)) return false; *riv->industries_near->Append() = ind; return false; } /** * Recomputes Station::industries_near, list of industries possibly * accepting cargo in station's catchment radius */ void Station::RecomputeIndustriesNear() { this->industries_near.Clear(); if (this->rect.IsEmpty()) return; RectAndIndustryVector riv = { this->GetCatchmentRect(), &this->industries_near }; /* Compute maximum extent of acceptance rectangle wrt. station sign */ TileIndex start_tile = this->xy; uint max_radius = max( max(DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.left, riv.rect.bottom))), max(DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.top)), DistanceManhattan(start_tile, TileXY(riv.rect.right, riv.rect.bottom))) ); CircularTileSearch(&start_tile, 2 * max_radius + 1, &FindIndustryToDeliver, &riv); } /** * Recomputes Station::industries_near for all stations */ /* static */ void Station::RecomputeIndustriesNearForAll() { Station *st; FOR_ALL_STATIONS(st) st->RecomputeIndustriesNear(); } /************************************************************************/ /* StationRect implementation */ /************************************************************************/ StationRect::StationRect() { this->MakeEmpty(); } void StationRect::MakeEmpty() { this->left = this->top = this->right = this->bottom = 0; } /** * Determines whether a given point (x, y) is within a certain distance of * the station rectangle. * @note x and y are in Tile coordinates * @param x X coordinate * @param y Y coordinate * @param distance The maximum distance a point may have (L1 norm) * @return true if the point is within distance tiles of the station rectangle */ bool StationRect::PtInExtendedRect(int x, int y, int distance) const { return this->left - distance <= x && x <= this->right + distance && this->top - distance <= y && y <= this->bottom + distance; } bool StationRect::IsEmpty() const { return this->left == 0 || this->left > this->right || this->top > this->bottom; } CommandCost StationRect::BeforeAddTile(TileIndex tile, StationRectMode mode) { int x = TileX(tile); int y = TileY(tile); if (this->IsEmpty()) { /* we are adding the first station tile */ if (mode != ADD_TEST) { this->left = this->right = x; this->top = this->bottom = y; } } else if (!this->PtInExtendedRect(x, y)) { /* current rect is not empty and new point is outside this rect * make new spread-out rectangle */ Rect new_rect = {min(x, this->left), min(y, this->top), max(x, this->right), max(y, this->bottom)}; /* check new rect dimensions against preset max */ int w = new_rect.right - new_rect.left + 1; int h = new_rect.bottom - new_rect.top + 1; if (mode != ADD_FORCE && (w > _settings_game.station.station_spread || h > _settings_game.station.station_spread)) { assert(mode != ADD_TRY); return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT); } /* spread-out ok, return true */ if (mode != ADD_TEST) { /* we should update the station rect */ *this = new_rect; } } else { ; // new point is inside the rect, we don't need to do anything } return CommandCost(); } CommandCost StationRect::BeforeAddRect(TileIndex tile, int w, int h, StationRectMode mode) { if (mode == ADD_FORCE || (w <= _settings_game.station.station_spread && h <= _settings_game.station.station_spread)) { /* Important when the old rect is completely inside the new rect, resp. the old one was empty. */ CommandCost ret = this->BeforeAddTile(tile, mode); if (ret.Succeeded()) ret = this->BeforeAddTile(TILE_ADDXY(tile, w - 1, h - 1), mode); return ret; } return CommandCost(); } /** * Check whether station tiles of the given station id exist in the given rectangle * @param st_id Station ID to look for in the rectangle * @param left_a Minimal tile X edge of the rectangle * @param top_a Minimal tile Y edge of the rectangle * @param right_a Maximal tile X edge of the rectangle (inclusive) * @param bottom_a Maximal tile Y edge of the rectangle (inclusive) * @return \c true if a station tile with the given \a st_id exists in the rectangle, \c false otherwise */ /* static */ bool StationRect::ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a) { TileArea ta(TileXY(left_a, top_a), TileXY(right_a, bottom_a)); TILE_AREA_LOOP(tile, ta) { if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true; } return false; } bool StationRect::AfterRemoveTile(BaseStation *st, TileIndex tile) { int x = TileX(tile); int y = TileY(tile); /* look if removed tile was on the bounding rect edge * and try to reduce the rect by this edge * do it until we have empty rect or nothing to do */ for (;;) { /* check if removed tile is on rect edge */ bool left_edge = (x == this->left); bool right_edge = (x == this->right); bool top_edge = (y == this->top); bool bottom_edge = (y == this->bottom); /* can we reduce the rect in either direction? */ bool reduce_x = ((left_edge || right_edge) && !ScanForStationTiles(st->index, x, this->top, x, this->bottom)); bool reduce_y = ((top_edge || bottom_edge) && !ScanForStationTiles(st->index, this->left, y, this->right, y)); if (!(reduce_x || reduce_y)) break; // nothing to do (can't reduce) if (reduce_x) { /* reduce horizontally */ if (left_edge) { /* move left edge right */ this->left = x = x + 1; } else { /* move right edge left */ this->right = x = x - 1; } } if (reduce_y) { /* reduce vertically */ if (top_edge) { /* move top edge down */ this->top = y = y + 1; } else { /* move bottom edge up */ this->bottom = y = y - 1; } } if (left > right || top > bottom) { /* can't continue, if the remaining rectangle is empty */ this->MakeEmpty(); return true; // empty remaining rect } } return false; // non-empty remaining rect } bool StationRect::AfterRemoveRect(BaseStation *st, TileArea ta) { assert(this->PtInExtendedRect(TileX(ta.tile), TileY(ta.tile))); assert(this->PtInExtendedRect(TileX(ta.tile) + ta.w - 1, TileY(ta.tile) + ta.h - 1)); bool empty = this->AfterRemoveTile(st, ta.tile); if (ta.w != 1 || ta.h != 1) empty = empty || this->AfterRemoveTile(st, TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1)); return empty; } StationRect& StationRect::operator = (const Rect &src) { this->left = src.left; this->top = src.top; this->right = src.right; this->bottom = src.bottom; return *this; } /** * Calculates the maintenance cost of all airports of a company. * @param owner Company. * @return Total cost. */ Money AirportMaintenanceCost(Owner owner) { Money total_cost = 0; const Station *st; FOR_ALL_STATIONS(st) { if (st->owner == owner && (st->facilities & FACIL_AIRPORT)) { total_cost += _price[PR_INFRASTRUCTURE_AIRPORT] * st->airport.GetSpec()->maintenance_cost; } } /* 3 bits fraction for the maintenance cost factor. */ return total_cost >> 3; } openttd-1.5.3/src/industry_cmd.cpp0000644000000000000000000030173012627373435015712 0ustar rootroot/* $Id: industry_cmd.cpp 26879 2014-09-21 11:24:51Z rubidium $ */ /* * 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 industry_cmd.cpp Handling of industry tiles. */ #include "stdafx.h" #include "clear_map.h" #include "industry.h" #include "station_base.h" #include "landscape.h" #include "viewport_func.h" #include "command_func.h" #include "town.h" #include "news_func.h" #include "cheat_type.h" #include "genworld.h" #include "tree_map.h" #include "newgrf_cargo.h" #include "newgrf_debug.h" #include "newgrf_industrytiles.h" #include "autoslope.h" #include "water.h" #include "strings_func.h" #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "animated_tile_func.h" #include "effectvehicle_func.h" #include "effectvehicle_base.h" #include "ai/ai.hpp" #include "core/pool_func.hpp" #include "subsidy_func.h" #include "core/backup_type.hpp" #include "object_base.h" #include "game/game.hpp" #include "error.h" #include "table/strings.h" #include "table/industry_land.h" #include "table/build_industry.h" #include "safeguards.h" IndustryPool _industry_pool("Industry"); INSTANTIATE_POOL_METHODS(Industry) void ShowIndustryViewWindow(int industry); void BuildOilRig(TileIndex tile); static byte _industry_sound_ctr; static TileIndex _industry_sound_tile; uint16 Industry::counts[NUM_INDUSTRYTYPES]; IndustrySpec _industry_specs[NUM_INDUSTRYTYPES]; IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES]; IndustryBuildData _industry_builder; ///< In-game manager of industries. /** * This function initialize the spec arrays of both * industry and industry tiles. * It adjusts the enabling of the industry too, based on climate availability. * This will allow for clearer testings */ void ResetIndustries() { memset(&_industry_specs, 0, sizeof(_industry_specs)); memcpy(&_industry_specs, &_origin_industry_specs, sizeof(_origin_industry_specs)); /* once performed, enable only the current climate industries */ for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) { _industry_specs[i].enabled = i < NEW_INDUSTRYOFFSET && HasBit(_origin_industry_specs[i].climate_availability, _settings_game.game_creation.landscape); } memset(&_industry_tile_specs, 0, sizeof(_industry_tile_specs)); memcpy(&_industry_tile_specs, &_origin_industry_tile_specs, sizeof(_origin_industry_tile_specs)); /* Reset any overrides that have been set. */ _industile_mngr.ResetOverride(); _industry_mngr.ResetOverride(); } /** * Retrieve the type for this industry. Although it is accessed by a tile, * it will return the general type of industry, and not the sprite index * as would do GetIndustryGfx. * @param tile that is queried * @pre IsTileType(tile, MP_INDUSTRY) * @return general type for this industry, as defined in industry.h */ IndustryType GetIndustryType(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); const Industry *ind = Industry::GetByTile(tile); assert(ind != NULL); return ind->type; } /** * Accessor for array _industry_specs. * This will ensure at once : proper access and * not allowing modifications of it. * @param thistype of industry (which is the index in _industry_specs) * @pre thistype < NUM_INDUSTRYTYPES * @return a pointer to the corresponding industry spec */ const IndustrySpec *GetIndustrySpec(IndustryType thistype) { assert(thistype < NUM_INDUSTRYTYPES); return &_industry_specs[thistype]; } /** * Accessor for array _industry_tile_specs. * This will ensure at once : proper access and * not allowing modifications of it. * @param gfx of industrytile (which is the index in _industry_tile_specs) * @pre gfx < INVALID_INDUSTRYTILE * @return a pointer to the corresponding industrytile spec */ const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx) { assert(gfx < INVALID_INDUSTRYTILE); return &_industry_tile_specs[gfx]; } Industry::~Industry() { if (CleaningPool()) return; /* Industry can also be destroyed when not fully initialized. * This means that we do not have to clear tiles either. * Also we must not decrement industry counts in that case. */ if (this->location.w == 0) return; TILE_AREA_LOOP(tile_cur, this->location) { if (IsTileType(tile_cur, MP_INDUSTRY)) { if (GetIndustryIndex(tile_cur) == this->index) { DeleteNewGRFInspectWindow(GSF_INDUSTRYTILES, tile_cur); /* MakeWaterKeepingClass() can also handle 'land' */ MakeWaterKeepingClass(tile_cur, OWNER_NONE); } } else if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) { DeleteOilRig(tile_cur); } } if (GetIndustrySpec(this->type)->behaviour & INDUSTRYBEH_PLANT_FIELDS) { TileArea ta(this->location.tile - TileDiffXY(min(TileX(this->location.tile), 21), min(TileY(this->location.tile), 21)), 42, 42); ta.ClampToMap(); /* Remove the farmland and convert it to regular tiles over time. */ TILE_AREA_LOOP(tile_cur, ta) { if (IsTileType(tile_cur, MP_CLEAR) && IsClearGround(tile_cur, CLEAR_FIELDS) && GetIndustryIndexOfField(tile_cur) == this->index) { SetIndustryIndexOfField(tile_cur, INVALID_INDUSTRY); } } } /* don't let any disaster vehicle target invalid industry */ ReleaseDisastersTargetingIndustry(this->index); /* Clear the persistent storage. */ delete this->psa; DecIndustryTypeCount(this->type); DeleteIndustryNews(this->index); DeleteWindowById(WC_INDUSTRY_VIEW, this->index); DeleteNewGRFInspectWindow(GSF_INDUSTRIES, this->index); DeleteSubsidyWith(ST_INDUSTRY, this->index); CargoPacket::InvalidateAllFrom(ST_INDUSTRY, this->index); } /** * Invalidating some stuff after removing item from the pool. * @param index index of deleted item */ void Industry::PostDestructor(size_t index) { InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0); Station::RecomputeIndustriesNearForAll(); } /** * Return a random valid industry. * @return random industry, NULL if there are no industries */ /* static */ Industry *Industry::GetRandom() { if (Industry::GetNumItems() == 0) return NULL; int num = RandomRange((uint16)Industry::GetNumItems()); size_t index = MAX_UVALUE(size_t); while (num >= 0) { num--; index++; /* Make sure we have a valid industry */ while (!Industry::IsValidID(index)) { index++; assert(index < Industry::GetPoolSize()); } } return Industry::Get(index); } static void IndustryDrawSugarMine(const TileInfo *ti) { if (!IsIndustryCompleted(ti->tile)) return; const DrawIndustryAnimationStruct *d = &_draw_industry_spec1[GetAnimationFrame(ti->tile)]; AddChildSpriteScreen(SPR_IT_SUGAR_MINE_SIEVE + d->image_1, PAL_NONE, d->x, 0); if (d->image_2 != 0) { AddChildSpriteScreen(SPR_IT_SUGAR_MINE_CLOUDS + d->image_2 - 1, PAL_NONE, 8, 41); } if (d->image_3 != 0) { AddChildSpriteScreen(SPR_IT_SUGAR_MINE_PILE + d->image_3 - 1, PAL_NONE, _drawtile_proc1[d->image_3 - 1].x, _drawtile_proc1[d->image_3 - 1].y); } } static void IndustryDrawToffeeQuarry(const TileInfo *ti) { uint8 x = 0; if (IsIndustryCompleted(ti->tile)) { x = _industry_anim_offs_toffee[GetAnimationFrame(ti->tile)]; if (x == 0xFF) { x = 0; } } AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_SHOVEL, PAL_NONE, 22 - x, 24 + x); AddChildSpriteScreen(SPR_IT_TOFFEE_QUARRY_TOFFEE, PAL_NONE, 6, 14); } static void IndustryDrawBubbleGenerator( const TileInfo *ti) { if (IsIndustryCompleted(ti->tile)) { AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_BUBBLE, PAL_NONE, 5, _industry_anim_offs_bubbles[GetAnimationFrame(ti->tile)]); } AddChildSpriteScreen(SPR_IT_BUBBLE_GENERATOR_SPRING, PAL_NONE, 3, 67); } static void IndustryDrawToyFactory(const TileInfo *ti) { const DrawIndustryAnimationStruct *d = &_industry_anim_offs_toys[GetAnimationFrame(ti->tile)]; if (d->image_1 != 0xFF) { AddChildSpriteScreen(SPR_IT_TOY_FACTORY_CLAY, PAL_NONE, d->x, 96 + d->image_1); } if (d->image_2 != 0xFF) { AddChildSpriteScreen(SPR_IT_TOY_FACTORY_ROBOT, PAL_NONE, 16 - d->image_2 * 2, 100 + d->image_2); } AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP, PAL_NONE, 7, d->image_3); AddChildSpriteScreen(SPR_IT_TOY_FACTORY_STAMP_HOLDER, PAL_NONE, 0, 42); } static void IndustryDrawCoalPlantSparks(const TileInfo *ti) { if (IsIndustryCompleted(ti->tile)) { uint8 image = GetAnimationFrame(ti->tile); if (image != 0 && image < 7) { AddChildSpriteScreen(image + SPR_IT_POWER_PLANT_TRANSFORMERS, PAL_NONE, _coal_plant_sparks[image - 1].x, _coal_plant_sparks[image - 1].y ); } } } typedef void IndustryDrawTileProc(const TileInfo *ti); static IndustryDrawTileProc * const _industry_draw_tile_procs[5] = { IndustryDrawSugarMine, IndustryDrawToffeeQuarry, IndustryDrawBubbleGenerator, IndustryDrawToyFactory, IndustryDrawCoalPlantSparks, }; static void DrawTile_Industry(TileInfo *ti) { IndustryGfx gfx = GetIndustryGfx(ti->tile); Industry *ind = Industry::GetByTile(ti->tile); const IndustryTileSpec *indts = GetIndustryTileSpec(gfx); /* Retrieve pointer to the draw industry tile struct */ if (gfx >= NEW_INDUSTRYTILEOFFSET) { /* Draw the tile using the specialized method of newgrf industrytile. * DrawNewIndustry will return false if ever the resolver could not * find any sprite to display. So in this case, we will jump on the * substitute gfx instead. */ if (indts->grf_prop.spritegroup[0] != NULL && DrawNewIndustryTile(ti, ind, gfx, indts)) { return; } else { /* No sprite group (or no valid one) found, meaning no graphics associated. * Use the substitute one instead */ if (indts->grf_prop.subst_id != INVALID_INDUSTRYTILE) { gfx = indts->grf_prop.subst_id; /* And point the industrytile spec accordingly */ indts = GetIndustryTileSpec(gfx); } } } const DrawBuildingsTileStruct *dits = &_industry_draw_tile_data[gfx << 2 | (indts->anim_state ? GetAnimationFrame(ti->tile) & INDUSTRY_COMPLETED : GetIndustryConstructionStage(ti->tile))]; SpriteID image = dits->ground.sprite; /* DrawFoundation() modifies ti->z and ti->tileh */ if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); /* If the ground sprite is the default flat water sprite, draw also canal/river borders. * Do not do this if the tile's WaterClass is 'land'. */ if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) { DrawWaterClassGround(ti); } else { DrawGroundSprite(image, GroundSpritePaletteTransform(image, dits->ground.pal, GENERAL_SPRITE_COLOUR(ind->random_colour))); } /* If industries are transparent and invisible, do not draw the upper part */ if (IsInvisibilitySet(TO_INDUSTRIES)) return; /* Add industry on top of the ground? */ image = dits->building.sprite; if (image != 0) { AddSortableSpriteToDraw(image, SpriteLayoutPaletteTransform(image, dits->building.pal, GENERAL_SPRITE_COLOUR(ind->random_colour)), ti->x + dits->subtile_x, ti->y + dits->subtile_y, dits->width, dits->height, dits->dz, ti->z, IsTransparencySet(TO_INDUSTRIES)); if (IsTransparencySet(TO_INDUSTRIES)) return; } { int proc = dits->draw_proc - 1; if (proc >= 0) _industry_draw_tile_procs[proc](ti); } } static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y) { return GetTileMaxPixelZ(tile); } static Foundation GetFoundation_Industry(TileIndex tile, Slope tileh) { IndustryGfx gfx = GetIndustryGfx(tile); /* For NewGRF industry tiles we might not be drawing a foundation. We need to * account for this, as other structures should * draw the wall of the foundation in this case. */ if (gfx >= NEW_INDUSTRYTILEOFFSET) { const IndustryTileSpec *indts = GetIndustryTileSpec(gfx); if (indts->grf_prop.spritegroup[0] != NULL && HasBit(indts->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) { uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, Industry::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(indts->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE; } } return FlatteningFoundation(tileh); } static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted) { IndustryGfx gfx = GetIndustryGfx(tile); const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); /* When we have to use a callback, we put our data in the next two variables */ CargoID raw_accepts_cargo[lengthof(itspec->accepts_cargo)]; uint8 raw_cargo_acceptance[lengthof(itspec->acceptance)]; /* And then these will always point to a same sized array with the required data */ const CargoID *accepts_cargo = itspec->accepts_cargo; const uint8 *cargo_acceptance = itspec->acceptance; if (HasBit(itspec->callback_mask, CBM_INDT_ACCEPT_CARGO)) { uint16 res = GetIndustryTileCallback(CBID_INDTILE_ACCEPT_CARGO, 0, 0, gfx, Industry::GetByTile(tile), tile); if (res != CALLBACK_FAILED) { accepts_cargo = raw_accepts_cargo; for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_accepts_cargo[i] = GetCargoTranslation(GB(res, i * 5, 5), itspec->grf_prop.grffile); } } if (HasBit(itspec->callback_mask, CBM_INDT_CARGO_ACCEPTANCE)) { uint16 res = GetIndustryTileCallback(CBID_INDTILE_CARGO_ACCEPTANCE, 0, 0, gfx, Industry::GetByTile(tile), tile); if (res != CALLBACK_FAILED) { cargo_acceptance = raw_cargo_acceptance; for (uint i = 0; i < lengthof(itspec->accepts_cargo); i++) raw_cargo_acceptance[i] = GB(res, i * 4, 4); } } const Industry *ind = Industry::GetByTile(tile); for (byte i = 0; i < lengthof(itspec->accepts_cargo); i++) { CargoID a = accepts_cargo[i]; if (a == CT_INVALID || cargo_acceptance[i] == 0) continue; // work only with valid cargoes /* Add accepted cargo */ acceptance[a] += cargo_acceptance[i]; /* Maybe set 'always accepted' bit (if it's not set already) */ if (HasBit(*always_accepted, a)) continue; bool accepts = false; for (uint cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) { /* Test whether the industry itself accepts the cargo type */ if (ind->accepts_cargo[cargo_index] == a) { accepts = true; break; } } if (accepts) continue; /* If the industry itself doesn't accept this cargo, set 'always accepted' bit */ SetBit(*always_accepted, a); } } static void GetTileDesc_Industry(TileIndex tile, TileDesc *td) { const Industry *i = Industry::GetByTile(tile); const IndustrySpec *is = GetIndustrySpec(i->type); td->owner[0] = i->owner; td->str = is->name; if (!IsIndustryCompleted(tile)) { SetDParamX(td->dparam, 0, td->str); td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION; } if (is->grf_prop.grffile != NULL) { td->grf = GetGRFConfig(is->grf_prop.grffile->grfid)->GetName(); } } static CommandCost ClearTile_Industry(TileIndex tile, DoCommandFlag flags) { Industry *i = Industry::GetByTile(tile); const IndustrySpec *indspec = GetIndustrySpec(i->type); /* water can destroy industries * in editor you can bulldoze industries * with magic_bulldozer cheat you can destroy industries * (area around OILRIG is water, so water shouldn't flood it */ if ((_current_company != OWNER_WATER && _game_mode != GM_EDITOR && !_cheats.magic_bulldozer.value) || ((flags & DC_AUTO) != 0) || (_current_company == OWNER_WATER && ((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) || HasBit(GetIndustryTileSpec(GetIndustryGfx(tile))->slopes_refused, 5)))) { SetDParam(1, indspec->name); return_cmd_error(flags & DC_AUTO ? STR_ERROR_GENERIC_OBJECT_IN_THE_WAY : INVALID_STRING_ID); } if (flags & DC_EXEC) { AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index)); Game::NewEvent(new ScriptEventIndustryClose(i->index)); delete i; } return CommandCost(EXPENSES_CONSTRUCTION, indspec->GetRemovalCost()); } static void TransportIndustryGoods(TileIndex tile) { Industry *i = Industry::GetByTile(tile); const IndustrySpec *indspec = GetIndustrySpec(i->type); bool moved_cargo = false; StationFinder stations(i->location); for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) { uint cw = min(i->produced_cargo_waiting[j], 255); if (cw > indspec->minimal_cargo && i->produced_cargo[j] != CT_INVALID) { i->produced_cargo_waiting[j] -= cw; /* fluctuating economy? */ if (EconomyIsInRecession()) cw = (cw + 1) / 2; i->this_month_production[j] += cw; uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, stations.GetStations()); i->this_month_transported[j] += am; moved_cargo |= (am != 0); } } if (moved_cargo && !StartStopIndustryTileAnimation(i, IAT_INDUSTRY_DISTRIBUTES_CARGO)) { uint newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_production; if (newgfx != INDUSTRYTILE_NOANIM) { ResetIndustryConstructionStage(tile); SetIndustryCompleted(tile); SetIndustryGfx(tile, newgfx); MarkTileDirtyByTile(tile); } } } static void AnimateTile_Industry(TileIndex tile) { IndustryGfx gfx = GetIndustryGfx(tile); if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) { AnimateNewIndustryTile(tile); return; } switch (gfx) { case GFX_SUGAR_MINE_SIEVE: if ((_tick_counter & 1) == 0) { byte m = GetAnimationFrame(tile) + 1; if (_settings_client.sound.ambient) { switch (m & 7) { case 2: SndPlayTileFx(SND_2D_RIP_2, tile); break; case 6: SndPlayTileFx(SND_29_RIP, tile); break; } } if (m >= 96) { m = 0; DeleteAnimatedTile(tile); } SetAnimationFrame(tile, m); MarkTileDirtyByTile(tile); } break; case GFX_TOFFEE_QUARY: if ((_tick_counter & 3) == 0) { byte m = GetAnimationFrame(tile); if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) { SndPlayTileFx(SND_30_CARTOON_SOUND, tile); } if (++m >= 70) { m = 0; DeleteAnimatedTile(tile); } SetAnimationFrame(tile, m); MarkTileDirtyByTile(tile); } break; case GFX_BUBBLE_CATCHER: if ((_tick_counter & 1) == 0) { byte m = GetAnimationFrame(tile); if (++m >= 40) { m = 0; DeleteAnimatedTile(tile); } SetAnimationFrame(tile, m); MarkTileDirtyByTile(tile); } break; /* Sparks on a coal plant */ case GFX_POWERPLANT_SPARKS: if ((_tick_counter & 3) == 0) { byte m = GetAnimationFrame(tile); if (m == 6) { SetAnimationFrame(tile, 0); DeleteAnimatedTile(tile); } else { SetAnimationFrame(tile, m + 1); MarkTileDirtyByTile(tile); } } break; case GFX_TOY_FACTORY: if ((_tick_counter & 1) == 0) { byte m = GetAnimationFrame(tile) + 1; switch (m) { case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_MACHINERY, tile); break; case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_COMEDY_HIT, tile); break; case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_EXTRACT_AND_POP, tile); break; default: if (m >= 50) { int n = GetIndustryAnimationLoop(tile) + 1; m = 0; if (n >= 8) { n = 0; DeleteAnimatedTile(tile); } SetIndustryAnimationLoop(tile, n); } } SetAnimationFrame(tile, m); MarkTileDirtyByTile(tile); } break; case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2: case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4: case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6: case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8: if ((_tick_counter & 3) == 0) { IndustryGfx gfx = GetIndustryGfx(tile); gfx = (gfx < 155) ? gfx + 1 : 148; SetIndustryGfx(tile, gfx); MarkTileDirtyByTile(tile); } break; case GFX_OILWELL_ANIMATED_1: case GFX_OILWELL_ANIMATED_2: case GFX_OILWELL_ANIMATED_3: if ((_tick_counter & 7) == 0) { bool b = Chance16(1, 7); IndustryGfx gfx = GetIndustryGfx(tile); byte m = GetAnimationFrame(tile) + 1; if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) { SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED); SetIndustryConstructionStage(tile, 3); DeleteAnimatedTile(tile); } else { SetAnimationFrame(tile, m); SetIndustryGfx(tile, gfx); MarkTileDirtyByTile(tile); } } break; case GFX_COAL_MINE_TOWER_ANIMATED: case GFX_COPPER_MINE_TOWER_ANIMATED: case GFX_GOLD_MINE_TOWER_ANIMATED: { int state = _tick_counter & 0x7FF; if ((state -= 0x400) < 0) return; if (state < 0x1A0) { if (state < 0x20 || state >= 0x180) { byte m = GetAnimationFrame(tile); if (!(m & 0x40)) { SetAnimationFrame(tile, m | 0x40); if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINING_MACHINERY, tile); } if (state & 7) return; } else { if (state & 3) return; } byte m = (GetAnimationFrame(tile) + 1) | 0x40; if (m > 0xC2) m = 0xC0; SetAnimationFrame(tile, m); MarkTileDirtyByTile(tile); } else if (state >= 0x200 && state < 0x3A0) { int i = (state < 0x220 || state >= 0x380) ? 7 : 3; if (state & i) return; byte m = (GetAnimationFrame(tile) & 0xBF) - 1; if (m < 0x80) m = 0x82; SetAnimationFrame(tile, m); MarkTileDirtyByTile(tile); } break; } } } static void CreateChimneySmoke(TileIndex tile) { uint x = TileX(tile) * TILE_SIZE; uint y = TileY(tile) * TILE_SIZE; int z = GetTileMaxPixelZ(tile); CreateEffectVehicle(x + 15, y + 14, z + 59, EV_CHIMNEY_SMOKE); } static void MakeIndustryTileBigger(TileIndex tile) { byte cnt = GetIndustryConstructionCounter(tile) + 1; if (cnt != 4) { SetIndustryConstructionCounter(tile, cnt); return; } byte stage = GetIndustryConstructionStage(tile) + 1; SetIndustryConstructionCounter(tile, 0); SetIndustryConstructionStage(tile, stage); StartStopIndustryTileAnimation(tile, IAT_CONSTRUCTION_STATE_CHANGE); if (stage == INDUSTRY_COMPLETED) SetIndustryCompleted(tile); MarkTileDirtyByTile(tile); if (!IsIndustryCompleted(tile)) return; IndustryGfx gfx = GetIndustryGfx(tile); if (gfx >= NEW_INDUSTRYTILEOFFSET) { /* New industries are already animated on construction. */ return; } switch (gfx) { case GFX_POWERPLANT_CHIMNEY: CreateChimneySmoke(tile); break; case GFX_OILRIG_1: { /* Do not require an industry tile to be after the first two GFX_OILRIG_1 * tiles (like the default oil rig). Do a proper check to ensure the * tiles belong to the same industry and based on that build the oil rig's * station. */ TileIndex other = tile + TileDiffXY(0, 1); if (IsTileType(other, MP_INDUSTRY) && GetIndustryGfx(other) == GFX_OILRIG_1 && GetIndustryIndex(tile) == GetIndustryIndex(other)) { BuildOilRig(tile); } break; } case GFX_TOY_FACTORY: case GFX_BUBBLE_CATCHER: case GFX_TOFFEE_QUARY: SetAnimationFrame(tile, 0); SetIndustryAnimationLoop(tile, 0); break; case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2: case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4: case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6: case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8: AddAnimatedTile(tile); break; } } static void TileLoopIndustry_BubbleGenerator(TileIndex tile) { static const int8 _bubble_spawn_location[3][4] = { { 11, 0, -4, -14 }, { -4, -10, -4, 1 }, { 49, 59, 60, 65 }, }; if (_settings_client.sound.ambient) SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile); int dir = Random() & 3; EffectVehicle *v = CreateEffectVehicleAbove( TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir], TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir], _bubble_spawn_location[2][dir], EV_BUBBLE ); if (v != NULL) v->animation_substate = dir; } static void TileLoop_Industry(TileIndex tile) { if (IsTileOnWater(tile)) TileLoop_Water(tile); /* Normally this doesn't happen, but if an industry NewGRF is removed * an industry that was previously build on water can now be flooded. * If this happens the tile is no longer an industry tile after * returning from TileLoop_Water. */ if (!IsTileType(tile, MP_INDUSTRY)) return; TriggerIndustryTile(tile, INDTILE_TRIGGER_TILE_LOOP); if (!IsIndustryCompleted(tile)) { MakeIndustryTileBigger(tile); return; } if (_game_mode == GM_EDITOR) return; TransportIndustryGoods(tile); if (StartStopIndustryTileAnimation(tile, IAT_TILELOOP)) return; IndustryGfx newgfx = GetIndustryTileSpec(GetIndustryGfx(tile))->anim_next; if (newgfx != INDUSTRYTILE_NOANIM) { ResetIndustryConstructionStage(tile); SetIndustryGfx(tile, newgfx); MarkTileDirtyByTile(tile); return; } IndustryGfx gfx = GetIndustryGfx(tile); switch (gfx) { case GFX_COAL_MINE_TOWER_NOT_ANIMATED: case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: if (!(_tick_counter & 0x400) && Chance16(1, 2)) { switch (gfx) { case GFX_COAL_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COAL_MINE_TOWER_ANIMATED; break; case GFX_COPPER_MINE_TOWER_NOT_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_ANIMATED; break; case GFX_GOLD_MINE_TOWER_NOT_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_ANIMATED; break; } SetIndustryGfx(tile, gfx); SetAnimationFrame(tile, 0x80); AddAnimatedTile(tile); } break; case GFX_OILWELL_NOT_ANIMATED: if (Chance16(1, 6)) { SetIndustryGfx(tile, GFX_OILWELL_ANIMATED_1); SetAnimationFrame(tile, 0); AddAnimatedTile(tile); } break; case GFX_COAL_MINE_TOWER_ANIMATED: case GFX_COPPER_MINE_TOWER_ANIMATED: case GFX_GOLD_MINE_TOWER_ANIMATED: if (!(_tick_counter & 0x400)) { switch (gfx) { case GFX_COAL_MINE_TOWER_ANIMATED: gfx = GFX_COAL_MINE_TOWER_NOT_ANIMATED; break; case GFX_COPPER_MINE_TOWER_ANIMATED: gfx = GFX_COPPER_MINE_TOWER_NOT_ANIMATED; break; case GFX_GOLD_MINE_TOWER_ANIMATED: gfx = GFX_GOLD_MINE_TOWER_NOT_ANIMATED; break; } SetIndustryGfx(tile, gfx); SetIndustryCompleted(tile); SetIndustryConstructionStage(tile, 3); DeleteAnimatedTile(tile); } break; case GFX_POWERPLANT_SPARKS: if (Chance16(1, 3)) { if (_settings_client.sound.ambient) SndPlayTileFx(SND_0C_ELECTRIC_SPARK, tile); AddAnimatedTile(tile); } break; case GFX_COPPER_MINE_CHIMNEY: CreateEffectVehicleAbove(TileX(tile) * TILE_SIZE + 6, TileY(tile) * TILE_SIZE + 6, 43, EV_COPPER_MINE_SMOKE); break; case GFX_TOY_FACTORY: { Industry *i = Industry::GetByTile(tile); if (i->was_cargo_delivered) { i->was_cargo_delivered = false; SetIndustryAnimationLoop(tile, 0); AddAnimatedTile(tile); } } break; case GFX_BUBBLE_GENERATOR: TileLoopIndustry_BubbleGenerator(tile); break; case GFX_TOFFEE_QUARY: AddAnimatedTile(tile); break; case GFX_SUGAR_MINE_SIEVE: if (Chance16(1, 3)) AddAnimatedTile(tile); break; } } static bool ClickTile_Industry(TileIndex tile) { ShowIndustryViewWindow(GetIndustryIndex(tile)); return true; } static TrackStatus GetTileTrackStatus_Industry(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { return 0; } static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_owner) { /* If the founder merges, the industry was created by the merged company */ Industry *i = Industry::GetByTile(tile); if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner; } /** * Check whether the tile is a forest. * @param tile the tile to investigate. * @return true if and only if the tile is a forest */ bool IsTileForestIndustry(TileIndex tile) { /* Check for industry tile */ if (!IsTileType(tile, MP_INDUSTRY)) return false; const Industry *ind = Industry::GetByTile(tile); /* Check for organic industry (i.e. not processing or extractive) */ if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false; /* Check for wood production */ for (uint i = 0; i < lengthof(ind->produced_cargo); i++) { /* The industry produces wood. */ if (ind->produced_cargo[i] != CT_INVALID && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true; } return false; } static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6}; /** * Check whether the tile can be replaced by a farm field. * @param tile the tile to investigate. * @param allow_fields if true, the method will return true even if * the tile is a farm tile, otherwise the tile may not be a farm tile * @return true if the tile can become a farm field */ static bool IsSuitableForFarmField(TileIndex tile, bool allow_fields) { switch (GetTileType(tile)) { case MP_CLEAR: return !IsClearGround(tile, CLEAR_SNOW) && !IsClearGround(tile, CLEAR_DESERT) && (allow_fields || !IsClearGround(tile, CLEAR_FIELDS)); case MP_TREES: return GetTreeGround(tile) != TREE_GROUND_SHORE; default: return false; } } /** * Build farm field fence * @param tile the tile to position the fence on * @param size the size of the field being planted in tiles * @param type type of fence to set * @param side the side of the tile to attempt placement */ static void SetupFarmFieldFence(TileIndex tile, int size, byte type, DiagDirection side) { TileIndexDiff diff = (DiagDirToAxis(side) == AXIS_Y ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); do { tile = TILE_MASK(tile); if (IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)) { byte or_ = type; if (or_ == 1 && Chance16(1, 7)) or_ = 2; SetFence(tile, side, or_); } tile += diff; } while (--size); } static void PlantFarmField(TileIndex tile, IndustryID industry) { if (_settings_game.game_creation.landscape == LT_ARCTIC) { if (GetTileZ(tile) + 2 >= GetSnowLine()) return; } /* determine field size */ uint32 r = (Random() & 0x303) + 0x404; if (_settings_game.game_creation.landscape == LT_ARCTIC) r += 0x404; uint size_x = GB(r, 0, 8); uint size_y = GB(r, 8, 8); TileArea ta(tile - TileDiffXY(min(TileX(tile), size_x / 2), min(TileY(tile), size_y / 2)), size_x, size_y); ta.ClampToMap(); if (ta.w == 0 || ta.h == 0) return; /* check the amount of bad tiles */ int count = 0; TILE_AREA_LOOP(cur_tile, ta) { assert(cur_tile < MapSize()); count += IsSuitableForFarmField(cur_tile, false); } if (count * 2 < ta.w * ta.h) return; /* determine type of field */ r = Random(); uint counter = GB(r, 5, 3); uint field_type = GB(r, 8, 8) * 9 >> 8; /* make field */ TILE_AREA_LOOP(cur_tile, ta) { assert(cur_tile < MapSize()); if (IsSuitableForFarmField(cur_tile, true)) { MakeField(cur_tile, field_type, industry); SetClearCounter(cur_tile, counter); MarkTileDirtyByTile(cur_tile); } } int type = 3; if (_settings_game.game_creation.landscape != LT_ARCTIC && _settings_game.game_creation.landscape != LT_TROPIC) { type = _plantfarmfield_type[Random() & 0xF]; } SetupFarmFieldFence(ta.tile, ta.h, type, DIAGDIR_NE); SetupFarmFieldFence(ta.tile, ta.w, type, DIAGDIR_NW); SetupFarmFieldFence(ta.tile + TileDiffXY(ta.w - 1, 0), ta.h, type, DIAGDIR_SW); SetupFarmFieldFence(ta.tile + TileDiffXY(0, ta.h - 1), ta.w, type, DIAGDIR_SE); } void PlantRandomFarmField(const Industry *i) { int x = i->location.w / 2 + Random() % 31 - 16; int y = i->location.h / 2 + Random() % 31 - 16; TileIndex tile = TileAddWrap(i->location.tile, x, y); if (tile != INVALID_TILE) PlantFarmField(tile, i->index); } /** * Search callback function for ChopLumberMillTrees * @param tile to test * @param user_data that is passed by the caller. In this case, nothing * @return the result of the test */ static bool SearchLumberMillTrees(TileIndex tile, void *user_data) { if (IsTileType(tile, MP_TREES) && GetTreeGrowth(tile) > 2) { ///< 3 and up means all fully grown trees /* found a tree */ Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); _industry_sound_ctr = 1; _industry_sound_tile = tile; if (_settings_client.sound.ambient) SndPlayTileFx(SND_38_CHAINSAW, tile); DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); return true; } return false; } /** * Perform a circular search around the Lumber Mill in order to find trees to cut * @param i industry */ static void ChopLumberMillTrees(Industry *i) { /* We only want to cut trees if all tiles are completed. */ TILE_AREA_LOOP(tile_cur, i->location) { if (i->TileBelongsToIndustry(tile_cur)) { if (!IsIndustryCompleted(tile_cur)) return; } } TileIndex tile = i->location.tile; if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, NULL)) { // 40x40 tiles to search. i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo. } } static void ProduceIndustryGoods(Industry *i) { const IndustrySpec *indsp = GetIndustrySpec(i->type); /* play a sound? */ if ((i->counter & 0x3F) == 0) { uint32 r; uint num; if (Chance16R(1, 14, r) && (num = indsp->number_of_sounds) != 0 && _settings_client.sound.ambient) { SndPlayTileFx( (SoundFx)(indsp->random_sounds[((r >> 16) * num) >> 16]), i->location.tile); } } i->counter--; /* produce some cargo */ if ((i->counter % INDUSTRY_PRODUCE_TICKS) == 0) { if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1); IndustryBehaviour indbehav = indsp->behaviour; i->produced_cargo_waiting[0] = min(0xffff, i->produced_cargo_waiting[0] + i->production_rate[0]); i->produced_cargo_waiting[1] = min(0xffff, i->produced_cargo_waiting[1] + i->production_rate[1]); if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) { uint16 cb_res = CALLBACK_FAILED; if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) { cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 0, i, i->type, i->location.tile); } bool plant; if (cb_res != CALLBACK_FAILED) { plant = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res); } else { plant = Chance16(1, 8); } if (plant) PlantRandomFarmField(i); } if ((indbehav & INDUSTRYBEH_CUT_TREES) != 0) { uint16 cb_res = CALLBACK_FAILED; if (HasBit(indsp->callback_mask, CBM_IND_SPECIAL_EFFECT)) { cb_res = GetIndustryCallback(CBID_INDUSTRY_SPECIAL_EFFECT, Random(), 1, i, i->type, i->location.tile); } bool cut; if (cb_res != CALLBACK_FAILED) { cut = ConvertBooleanCallback(indsp->grf_prop.grffile, CBID_INDUSTRY_SPECIAL_EFFECT, cb_res); } else { cut = ((i->counter % INDUSTRY_CUT_TREE_TICKS) == 0); } if (cut) ChopLumberMillTrees(i); } TriggerIndustry(i, INDUSTRY_TRIGGER_INDUSTRY_TICK); StartStopIndustryTileAnimation(i, IAT_INDUSTRY_TICK); } } void OnTick_Industry() { if (_industry_sound_ctr != 0) { _industry_sound_ctr++; if (_industry_sound_ctr == 75) { if (_settings_client.sound.ambient) SndPlayTileFx(SND_37_BALLOON_SQUEAK, _industry_sound_tile); } else if (_industry_sound_ctr == 160) { _industry_sound_ctr = 0; if (_settings_client.sound.ambient) SndPlayTileFx(SND_36_CARTOON_CRASH, _industry_sound_tile); } } if (_game_mode == GM_EDITOR) return; Industry *i; FOR_ALL_INDUSTRIES(i) { ProduceIndustryGoods(i); } } /** * Check the conditions of #CHECK_NOTHING (Always succeeds). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_NULL(TileIndex tile) { return CommandCost(); } /** * Check the conditions of #CHECK_FOREST (Industry should be build above snow-line in arctic climate). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_Forest(TileIndex tile) { if (_settings_game.game_creation.landscape == LT_ARCTIC) { if (GetTileZ(tile) < HighestSnowLine() + 2) { return_cmd_error(STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED); } } return CommandCost(); } /** * Check the conditions of #CHECK_REFINERY (Industry should be positioned near edge of the map). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile) { if (_game_mode == GM_EDITOR) return CommandCost(); if (DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost(); return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED); } extern bool _ignore_restrictions; /** * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_OilRig(TileIndex tile) { if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost(); if (TileHeight(tile) == 0 && DistanceFromEdge(TILE_ADDXY(tile, 1, 1)) < _settings_game.game_creation.oil_refinery_limit) return CommandCost(); return_cmd_error(STR_ERROR_CAN_ONLY_BE_POSITIONED); } /** * Check the conditions of #CHECK_FARM (Industry should be below snow-line in arctic). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_Farm(TileIndex tile) { if (_settings_game.game_creation.landscape == LT_ARCTIC) { if (GetTileZ(tile) + 2 >= HighestSnowLine()) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } } return CommandCost(); } /** * Check the conditions of #CHECK_PLANTATION (Industry should NOT be in the desert). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_Plantation(TileIndex tile) { if (GetTropicZone(tile) == TROPICZONE_DESERT) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } return CommandCost(); } /** * Check the conditions of #CHECK_WATER (Industry should be in the desert). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_Water(TileIndex tile) { if (GetTropicZone(tile) != TROPICZONE_DESERT) { return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT); } return CommandCost(); } /** * Check the conditions of #CHECK_LUMBERMILL (Industry should be in the rain forest). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_Lumbermill(TileIndex tile) { if (GetTropicZone(tile) != TROPICZONE_RAINFOREST) { return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST); } return CommandCost(); } /** * Check the conditions of #CHECK_BUBBLEGEN (Industry should be in low land). * @param tile %Tile to perform the checking. * @return Succeeded or failed command. */ static CommandCost CheckNewIndustry_BubbleGen(TileIndex tile) { if (GetTileZ(tile) > 4) { return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS); } return CommandCost(); } /** * Industrytype check function signature. * @param tile %Tile to check. * @return Succeeded or failed command. */ typedef CommandCost CheckNewIndustryProc(TileIndex tile); /** Check functions for different types of industry. */ static CheckNewIndustryProc * const _check_new_industry_procs[CHECK_END] = { CheckNewIndustry_NULL, ///< CHECK_NOTHING CheckNewIndustry_Forest, ///< CHECK_FOREST CheckNewIndustry_OilRefinery, ///< CHECK_REFINERY CheckNewIndustry_Farm, ///< CHECK_FARM CheckNewIndustry_Plantation, ///< CHECK_PLANTATION CheckNewIndustry_Water, ///< CHECK_WATER CheckNewIndustry_Lumbermill, ///< CHECK_LUMBERMILL CheckNewIndustry_BubbleGen, ///< CHECK_BUBBLEGEN CheckNewIndustry_OilRig, ///< CHECK_OIL_RIG }; /** * Find a town for the industry, while checking for multiple industries in the same town. * @param tile Position of the industry to build. * @param type Industry type. * @param [out] town Pointer to return town for the new industry, \c NULL is written if no good town can be found. * @return Succeeded or failed command. * * @pre \c *t != NULL * @post \c *t points to a town on success, and \c NULL on failure. */ static CommandCost FindTownForIndustry(TileIndex tile, int type, Town **t) { *t = ClosestTownFromTile(tile, UINT_MAX); if (_settings_game.economy.multiple_industry_per_town) return CommandCost(); const Industry *i; FOR_ALL_INDUSTRIES(i) { if (i->type == (byte)type && i->town == *t) { *t = NULL; return_cmd_error(STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN); } } return CommandCost(); } bool IsSlopeRefused(Slope current, Slope refused) { if (IsSteepSlope(current)) return true; if (current != SLOPE_FLAT) { if (IsSteepSlope(refused)) return true; Slope t = ComplementSlope(current); if ((refused & SLOPE_W) && (t & SLOPE_NW)) return true; if ((refused & SLOPE_S) && (t & SLOPE_NE)) return true; if ((refused & SLOPE_E) && (t & SLOPE_SW)) return true; if ((refused & SLOPE_N) && (t & SLOPE_SE)) return true; } return false; } /** * Are the tiles of the industry free? * @param tile Position to check. * @param it Industry tiles table. * @param itspec_index The index of the itsepc to build/fund * @param type Type of the industry. * @param initial_random_bits The random bits the industry is going to have after construction. * @param founder Industry founder * @param creation_type The circumstances the industry is created under. * @param [out] custom_shape_check Perform custom check for the site. * @return Failed or succeeded command. */ static CommandCost CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, uint itspec_index, int type, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type, bool *custom_shape_check = NULL) { bool refused_slope = false; bool custom_shape = false; do { IndustryGfx gfx = GetTranslatedIndustryTileID(it->gfx); TileIndex cur_tile = TileAddWrap(tile, it->ti.x, it->ti.y); if (!IsValidTile(cur_tile)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } if (gfx == GFX_WATERTILE_SPECIALCHECK) { if (!IsTileType(cur_tile, MP_WATER) || !IsTileFlat(cur_tile)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } } else { CommandCost ret = EnsureNoVehicleOnGround(cur_tile); if (ret.Failed()) return ret; if (IsBridgeAbove(cur_tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); const IndustryTileSpec *its = GetIndustryTileSpec(gfx); IndustryBehaviour ind_behav = GetIndustrySpec(type)->behaviour; /* Perform land/water check if not disabled */ if (!HasBit(its->slopes_refused, 5) && ((HasTileWaterClass(cur_tile) && IsTileOnWater(cur_tile)) == !(ind_behav & INDUSTRYBEH_BUILT_ONWATER))) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); if (HasBit(its->callback_mask, CBM_INDT_SHAPE_CHECK)) { custom_shape = true; CommandCost ret = PerformIndustryTileSlopeCheck(tile, cur_tile, its, type, gfx, itspec_index, initial_random_bits, founder, creation_type); if (ret.Failed()) return ret; } else { Slope tileh = GetTileSlope(cur_tile); refused_slope |= IsSlopeRefused(tileh, its->slopes_refused); } if ((ind_behav & (INDUSTRYBEH_ONLY_INTOWN | INDUSTRYBEH_TOWN1200_MORE)) || // Tile must be a house ((ind_behav & INDUSTRYBEH_ONLY_NEARTOWN) && IsTileType(cur_tile, MP_HOUSE))) { // Tile is allowed to be a house (and it is a house) if (!IsTileType(cur_tile, MP_HOUSE)) { return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS); } /* Clear the tiles as OWNER_TOWN to not affect town rating, and to not clear protected buildings */ Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); CommandCost ret = DoCommand(cur_tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); if (ret.Failed()) return ret; } else { /* Clear the tiles, but do not affect town ratings */ CommandCost ret = DoCommand(cur_tile, 0, 0, DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; } } } while ((++it)->ti.x != -0x80); if (custom_shape_check != NULL) *custom_shape_check = custom_shape; /* It is almost impossible to have a fully flat land in TG, so what we * do is that we check if we can make the land flat later on. See * CheckIfCanLevelIndustryPlatform(). */ if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) { return CommandCost(); } return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } /** * Is the industry allowed to be built at this place for the town? * @param tile Tile to construct the industry. * @param type Type of the industry. * @param t Town authority that the industry belongs to. * @return Succeeded or failed command. */ static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t) { if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_TOWN1200_MORE) && t->cache.population < 1200) { return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200); } if ((GetIndustrySpec(type)->behaviour & INDUSTRYBEH_ONLY_NEARTOWN) && DistanceMax(t->xy, tile) > 9) { return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER); } return CommandCost(); } static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal) { /* Check if we don't leave the map */ if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false; TileArea ta(tile - TileDiffXY(1, 1), 2, 2); TILE_AREA_LOOP(tile_walk, ta) { uint curh = TileHeight(tile_walk); /* Is the tile clear? */ if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) return false; /* Don't allow too big of a change if this is the sub-tile check */ if (internal != 0 && Delta(curh, height) > 1) return false; /* Different height, so the surrounding tiles of this tile * has to be correct too (in level, or almost in level) * else you get a chain-reaction of terraforming. */ if (internal == 0 && curh != height) { if (TileX(tile_walk) == 0 || TileY(tile_walk) == 0 || !CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) { return false; } } } return true; } /** * This function tries to flatten out the land below an industry, without * damaging the surroundings too much. */ static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, DoCommandFlag flags, const IndustryTileTable *it, int type) { const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h) int max_x = 0; int max_y = 0; /* Finds dimensions of largest variant of this industry */ do { if (it->gfx == 0xFF) continue; // FF been a marquer for a check on clear water, skip it if (it->ti.x > max_x) max_x = it->ti.x; if (it->ti.y > max_y) max_y = it->ti.y; } while ((++it)->ti.x != MKEND); /* Remember level height */ uint h = TileHeight(tile); if (TileX(tile) <= _settings_game.construction.industry_platform + 1U || TileY(tile) <= _settings_game.construction.industry_platform + 1U) return false; /* Check that all tiles in area and surrounding are clear * this determines that there are no obstructing items */ TileArea ta(tile + TileDiffXY(-_settings_game.construction.industry_platform, -_settings_game.construction.industry_platform), max_x + 2 + 2 * _settings_game.construction.industry_platform, max_y + 2 + 2 * _settings_game.construction.industry_platform); if (TileX(ta.tile) + ta.w >= MapMaxX() || TileY(ta.tile) + ta.h >= MapMaxY()) return false; /* _current_company is OWNER_NONE for randomly generated industries and in editor, or the company who funded or prospected the industry. * Perform terraforming as OWNER_TOWN to disable autoslope and town ratings. */ Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); TILE_AREA_LOOP(tile_walk, ta) { uint curh = TileHeight(tile_walk); if (curh != h) { /* This tile needs terraforming. Check if we can do that without * damaging the surroundings too much. */ if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) { cur_company.Restore(); return false; } /* This is not 100% correct check, but the best we can do without modifying the map. * What is missing, is if the difference in height is more than 1.. */ if (DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND).Failed()) { cur_company.Restore(); return false; } } } if (flags & DC_EXEC) { /* Terraform the land under the industry */ TILE_AREA_LOOP(tile_walk, ta) { uint curh = TileHeight(tile_walk); while (curh != h) { /* We give the terraforming for free here, because we can't calculate * exact cost in the test-round, and as we all know, that will cause * a nice assert if they don't match ;) */ DoCommand(tile_walk, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND); curh += (curh > h) ? -1 : 1; } } } cur_company.Restore(); return true; } /** * Check that the new industry is far enough from conflicting industries. * @param tile Tile to construct the industry. * @param type Type of the new industry. * @return Succeeded or failed command. */ static CommandCost CheckIfFarEnoughFromConflictingIndustry(TileIndex tile, int type) { const IndustrySpec *indspec = GetIndustrySpec(type); const Industry *i = NULL; /* On a large map with many industries, it may be faster to check an area. */ static const int dmax = 14; if (Industry::GetNumItems() > (size_t) (dmax * dmax * 2)) { const int tx = TileX(tile); const int ty = TileY(tile); TileArea tile_area = TileArea(TileXY(max(0, tx - dmax), max(0, ty - dmax)), TileXY(min(MapMaxX(), tx + dmax), min(MapMaxY(), ty + dmax))); TILE_AREA_LOOP(atile, tile_area) { if (GetTileType(atile) == MP_INDUSTRY) { const Industry *i2 = Industry::GetByTile(atile); if (i == i2) continue; i = i2; if (DistanceMax(tile, i->location.tile) > (uint)dmax) continue; if (i->type == indspec->conflicting[0] || i->type == indspec->conflicting[1] || i->type == indspec->conflicting[2]) { return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE); } } } return CommandCost(); } FOR_ALL_INDUSTRIES(i) { /* Within 14 tiles from another industry is considered close */ if (DistanceMax(tile, i->location.tile) > 14) continue; /* check if there are any conflicting industry types around */ if (i->type == indspec->conflicting[0] || i->type == indspec->conflicting[1] || i->type == indspec->conflicting[2]) { return_cmd_error(STR_ERROR_INDUSTRY_TOO_CLOSE); } } return CommandCost(); } /** * Advertise about a new industry opening. * @param ind Industry being opened. */ static void AdvertiseIndustryOpening(const Industry *ind) { const IndustrySpec *ind_spc = GetIndustrySpec(ind->type); SetDParam(0, ind_spc->name); if (ind_spc->new_industry_text > STR_LAST_STRINGID) { SetDParam(1, STR_TOWN_NAME); SetDParam(2, ind->town->index); } else { SetDParam(1, ind->town->index); } AddIndustryNewsItem(ind_spc->new_industry_text, NT_INDUSTRY_OPEN, ind->index); AI::BroadcastNewEvent(new ScriptEventIndustryOpen(ind->index)); Game::NewEvent(new ScriptEventIndustryOpen(ind->index)); } /** * Put an industry on the map. * @param i Just allocated poolitem, mostly empty. * @param tile North tile of the industry. * @param type Type of the industry. * @param it Industrylayout to build. * @param layout Number of the layout. * @param t Nearest town. * @param founder Founder of the industry; OWNER_NONE in case of random construction. * @param initial_random_bits Random bits for the industry. */ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, const IndustryTileTable *it, byte layout, Town *t, Owner founder, uint16 initial_random_bits) { const IndustrySpec *indspec = GetIndustrySpec(type); i->location = TileArea(tile, 1, 1); i->type = type; Industry::IncIndustryTypeCount(type); i->produced_cargo[0] = indspec->produced_cargo[0]; i->produced_cargo[1] = indspec->produced_cargo[1]; i->accepts_cargo[0] = indspec->accepts_cargo[0]; i->accepts_cargo[1] = indspec->accepts_cargo[1]; i->accepts_cargo[2] = indspec->accepts_cargo[2]; i->production_rate[0] = indspec->production_rate[0]; i->production_rate[1] = indspec->production_rate[1]; /* don't use smooth economy for industries using production related callbacks */ if (indspec->UsesSmoothEconomy()) { i->production_rate[0] = min((RandomRange(256) + 128) * i->production_rate[0] >> 8, 255); i->production_rate[1] = min((RandomRange(256) + 128) * i->production_rate[1] >> 8, 255); } i->town = t; i->owner = OWNER_NONE; uint16 r = Random(); i->random_colour = GB(r, 0, 4); i->counter = GB(r, 4, 12); i->random = initial_random_bits; i->produced_cargo_waiting[0] = 0; i->produced_cargo_waiting[1] = 0; i->incoming_cargo_waiting[0] = 0; i->incoming_cargo_waiting[1] = 0; i->incoming_cargo_waiting[2] = 0; i->this_month_production[0] = 0; i->this_month_production[1] = 0; i->this_month_transported[0] = 0; i->this_month_transported[1] = 0; i->last_month_pct_transported[0] = 0; i->last_month_pct_transported[1] = 0; i->last_month_transported[0] = 0; i->last_month_transported[1] = 0; i->was_cargo_delivered = false; i->last_prod_year = _cur_year; i->founder = founder; i->construction_date = _date; i->construction_type = (_game_mode == GM_EDITOR) ? ICT_SCENARIO_EDITOR : (_generating_world ? ICT_MAP_GENERATION : ICT_NORMAL_GAMEPLAY); /* Adding 1 here makes it conform to specs of var44 of varaction2 for industries * 0 = created prior of newindustries * else, chosen layout + 1 */ i->selected_layout = layout + 1; i->prod_level = PRODLEVEL_DEFAULT; /* Call callbacks after the regular fields got initialised. */ if (HasBit(indspec->callback_mask, CBM_IND_PROD_CHANGE_BUILD)) { uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROD_CHANGE_BUILD, 0, Random(), i, type, INVALID_TILE); if (res != CALLBACK_FAILED) { if (res < PRODLEVEL_MINIMUM || res > PRODLEVEL_MAXIMUM) { ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROD_CHANGE_BUILD, res); } else { i->prod_level = res; i->RecomputeProductionMultipliers(); } } } if (_generating_world) { i->last_month_production[0] = i->production_rate[0] * 8; i->last_month_production[1] = i->production_rate[1] * 8; } else { i->last_month_production[0] = i->last_month_production[1] = 0; } if (HasBit(indspec->callback_mask, CBM_IND_DECIDE_COLOUR)) { uint16 res = GetIndustryCallback(CBID_INDUSTRY_DECIDE_COLOUR, 0, 0, i, type, INVALID_TILE); if (res != CALLBACK_FAILED) { if (GB(res, 4, 11) != 0) ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_DECIDE_COLOUR, res); i->random_colour = GB(res, 0, 4); } } if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) { for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID; for (uint j = 0; j < lengthof(i->accepts_cargo); j++) { uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE); if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break; if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) { ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res); break; } i->accepts_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile); } } if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) { for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID; for (uint j = 0; j < lengthof(i->produced_cargo); j++) { uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE); if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break; if (indspec->grf_prop.grffile->grf_version >= 8 && res >= 0x100) { ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res); break; } i->produced_cargo[j] = GetCargoTranslation(GB(res, 0, 8), indspec->grf_prop.grffile); } } /* Plant the tiles */ do { TileIndex cur_tile = tile + ToTileIndexDiff(it->ti); if (it->gfx != GFX_WATERTILE_SPECIALCHECK) { i->location.Add(cur_tile); WaterClass wc = (IsWaterTile(cur_tile) ? GetWaterClass(cur_tile) : WATER_CLASS_INVALID); DoCommand(cur_tile, 0, 0, DC_EXEC | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR); MakeIndustry(cur_tile, i->index, it->gfx, Random(), wc); if (_generating_world) { SetIndustryConstructionCounter(cur_tile, 3); SetIndustryConstructionStage(cur_tile, 2); } /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */ IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it->gfx); const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx); if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile); } } while ((++it)->ti.x != -0x80); if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) { for (uint j = 0; j != 50; j++) PlantRandomFarmField(i); } InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0); Station::RecomputeIndustriesNearForAll(); } /** * Helper function for Build/Fund an industry * @param tile tile where industry is built * @param type of industry to build * @param flags of operations to conduct * @param indspec pointer to industry specifications * @param itspec_index the index of the itsepc to build/fund * @param seed random seed (possibly) used by industries * @param initial_random_bits The random bits the industry is going to have after construction. * @param founder Founder of the industry * @param creation_type The circumstances the industry is created under. * @param [out] ip Pointer to store newly created industry. * @return Succeeded or failed command. * * @post \c *ip contains the newly created industry if all checks are successful and the \a flags request actual creation, else it contains \c NULL afterwards. */ static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCommandFlag flags, const IndustrySpec *indspec, uint itspec_index, uint32 random_var8f, uint16 random_initial_bits, Owner founder, IndustryAvailabilityCallType creation_type, Industry **ip) { assert(itspec_index < indspec->num_table); const IndustryTileTable *it = indspec->table[itspec_index]; bool custom_shape_check = false; *ip = NULL; SmallVector object_areas(_cleared_object_areas); CommandCost ret = CheckIfIndustryTilesAreFree(tile, it, itspec_index, type, random_initial_bits, founder, creation_type, &custom_shape_check); _cleared_object_areas = object_areas; if (ret.Failed()) return ret; if (HasBit(GetIndustrySpec(type)->callback_mask, CBM_IND_LOCATION)) { ret = CheckIfCallBackAllowsCreation(tile, type, itspec_index, random_var8f, random_initial_bits, founder, creation_type); } else { ret = _check_new_industry_procs[indspec->check_proc](tile); } if (ret.Failed()) return ret; if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER, it, type)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } ret = CheckIfFarEnoughFromConflictingIndustry(tile, type); if (ret.Failed()) return ret; Town *t = NULL; ret = FindTownForIndustry(tile, type, &t); if (ret.Failed()) return ret; assert(t != NULL); ret = CheckIfIndustryIsAllowed(tile, type, t); if (ret.Failed()) return ret; if (!Industry::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_INDUSTRIES); if (flags & DC_EXEC) { *ip = new Industry(tile); if (!custom_shape_check) CheckIfCanLevelIndustryPlatform(tile, DC_NO_WATER | DC_EXEC, it, type); DoCreateNewIndustry(*ip, tile, type, it, itspec_index, t, founder, random_initial_bits); } return CommandCost(); } /** * Build/Fund an industry * @param tile tile where industry is built * @param flags of operations to conduct * @param p1 various bitstuffed elements * - p1 = (bit 0 - 7) - industry type see build_industry.h and see industry.h * - p1 = (bit 8 - 15) - first layout to try * - p1 = (bit 16 ) - 0 = prospect, 1 = fund (only valid if current company is DEITY) * @param p2 seed to use for desyncfree randomisations * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { IndustryType it = GB(p1, 0, 8); if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR; const IndustrySpec *indspec = GetIndustrySpec(it); /* Check if the to-be built/founded industry is available for this climate. */ if (!indspec->enabled || indspec->num_table == 0) return CMD_ERROR; /* If the setting for raw-material industries is not on, you cannot build raw-material industries. * Raw material industries are industries that do not accept cargo (at least for now) */ if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 0 && indspec->IsRawIndustry()) { return CMD_ERROR; } if (_game_mode != GM_EDITOR && GetIndustryProbabilityCallback(it, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) { return CMD_ERROR; } Randomizer randomizer; randomizer.SetSeed(p2); uint16 random_initial_bits = GB(p2, 0, 16); uint32 random_var8f = randomizer.Next(); int num_layouts = indspec->num_table; CommandCost ret = CommandCost(STR_ERROR_SITE_UNSUITABLE); const bool deity_prospect = _current_company == OWNER_DEITY && !HasBit(p1, 16); Industry *ind = NULL; if (deity_prospect || (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY && _settings_game.construction.raw_industry_construction == 2 && indspec->IsRawIndustry())) { if (flags & DC_EXEC) { /* Prospected industries are build as OWNER_TOWN to not e.g. be build on owned land of the founder */ Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); /* Prospecting has a chance to fail, however we cannot guarantee that something can * be built on the map, so the chance gets lower when the map is fuller, but there * is nothing we can really do about that. */ if (deity_prospect || Random() <= indspec->prospecting_chance) { for (int i = 0; i < 5000; i++) { /* We should not have more than one Random() in a function call * because parameter evaluation order is not guaranteed in the c++ standard */ tile = RandomTile(); /* Start with a random layout */ int layout = RandomRange(num_layouts); /* Check now each layout, starting with the random one */ for (int j = 0; j < num_layouts; j++) { layout = (layout + 1) % num_layouts; ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, cur_company.GetOriginalValue(), _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_PROSPECTCREATION, &ind); if (ret.Succeeded()) break; } if (ret.Succeeded()) break; } } cur_company.Restore(); } } else { int layout = GB(p1, 8, 8); if (layout >= num_layouts) return CMD_ERROR; /* Check subsequently each layout, starting with the given layout in p1 */ for (int i = 0; i < num_layouts; i++) { layout = (layout + 1) % num_layouts; ret = CreateNewIndustryHelper(tile, it, flags, indspec, layout, random_var8f, random_initial_bits, _current_company, _current_company == OWNER_DEITY ? IACT_RANDOMCREATION : IACT_USERCREATION, &ind); if (ret.Succeeded()) break; } /* If it still failed, there's no suitable layout to build here, return the error */ if (ret.Failed()) return ret; } if ((flags & DC_EXEC) && ind != NULL && _game_mode != GM_EDITOR) { AdvertiseIndustryOpening(ind); } return CommandCost(EXPENSES_OTHER, indspec->GetConstructionCost()); } /** * Create a new industry of random layout. * @param tile The location to build the industry. * @param type The industry type to build. * @param creation_type The circumstances the industry is created under. * @return the created industry or NULL if it failed. */ static Industry *CreateNewIndustry(TileIndex tile, IndustryType type, IndustryAvailabilityCallType creation_type) { const IndustrySpec *indspec = GetIndustrySpec(type); uint32 seed = Random(); uint32 seed2 = Random(); Industry *i = NULL; CommandCost ret = CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, RandomRange(indspec->num_table), seed, GB(seed2, 0, 16), OWNER_NONE, creation_type, &i); assert(i != NULL || ret.Failed()); return i; } /** * Compute the appearance probability for an industry during map creation. * @param it Industry type to compute. * @param [out] force_at_least_one Returns whether at least one instance should be forced on map creation. * @return Relative probability for the industry to appear. */ static uint32 GetScaledIndustryGenerationProbability(IndustryType it, bool *force_at_least_one) { const IndustrySpec *ind_spc = GetIndustrySpec(it); uint32 chance = ind_spc->appear_creation[_settings_game.game_creation.landscape] * 16; // * 16 to increase precision if (!ind_spc->enabled || ind_spc->num_table == 0 || (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) || (chance = GetIndustryProbabilityCallback(it, IACT_MAPGENERATION, chance)) == 0) { *force_at_least_one = false; return 0; } else { /* We want industries appearing at coast to appear less often on bigger maps, as length of coast increases slower than map area. * For simplicity we scale in both cases, though scaling the probabilities of all industries has no effect. */ chance = (ind_spc->check_proc == CHECK_REFINERY || ind_spc->check_proc == CHECK_OIL_RIG) ? ScaleByMapSize1D(chance) : ScaleByMapSize(chance); *force_at_least_one = (chance > 0) && !(ind_spc->behaviour & INDUSTRYBEH_NOBUILT_MAPCREATION) && (_game_mode != GM_EDITOR); return chance; } } /** * Compute the probability for constructing a new industry during game play. * @param it Industry type to compute. * @param [out] min_number Minimal number of industries that should exist at the map. * @return Relative probability for the industry to appear. */ static uint16 GetIndustryGamePlayProbability(IndustryType it, byte *min_number) { if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) { *min_number = 0; return 0; } const IndustrySpec *ind_spc = GetIndustrySpec(it); byte chance = ind_spc->appear_ingame[_settings_game.game_creation.landscape]; if (!ind_spc->enabled || ind_spc->num_table == 0 || ((ind_spc->behaviour & INDUSTRYBEH_BEFORE_1950) && _cur_year > 1950) || ((ind_spc->behaviour & INDUSTRYBEH_AFTER_1960) && _cur_year < 1960) || (chance = GetIndustryProbabilityCallback(it, IACT_RANDOMCREATION, chance)) == 0) { *min_number = 0; return 0; } *min_number = (ind_spc->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) ? 1 : 0; return chance; } /** * Get wanted number of industries on the map. * @return Wanted number of industries at the map. */ static uint GetNumberOfIndustries() { /* Number of industries on a 256x256 map. */ static const uint16 numof_industry_table[] = { 0, // none 0, // minimal 10, // very low 25, // low 55, // normal 80, // high }; assert(lengthof(numof_industry_table) == ID_END); uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.industry_density : (uint)ID_VERY_LOW; return min(IndustryPool::MAX_SIZE, ScaleByMapSize(numof_industry_table[difficulty])); } /** * Try to place the industry in the game. * Since there is no feedback why placement fails, there is no other option * than to try a few times before concluding it does not work. * @param type Industry type of the desired industry. * @param try_hard Try very hard to find a place. (Used to place at least one industry per type.) * @return Pointer to created industry, or \c NULL if creation failed. */ static Industry *PlaceIndustry(IndustryType type, IndustryAvailabilityCallType creation_type, bool try_hard) { uint tries = try_hard ? 10000u : 2000u; for (; tries > 0; tries--) { Industry *ind = CreateNewIndustry(RandomTile(), type, creation_type); if (ind != NULL) return ind; } return NULL; } /** * Try to build a industry on the map. * @param type IndustryType of the desired industry * @param try_hard Try very hard to find a place. (Used to place at least one industry per type) */ static void PlaceInitialIndustry(IndustryType type, bool try_hard) { Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); IncreaseGeneratingWorldProgress(GWP_INDUSTRY); PlaceIndustry(type, IACT_MAPGENERATION, try_hard); cur_company.Restore(); } /** * Get total number of industries existing in the game. * @return Number of industries currently in the game. */ static uint GetCurrentTotalNumberOfIndustries() { int total = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) total += Industry::GetIndustryTypeCount(it); return total; } /** Reset the entry. */ void IndustryTypeBuildData::Reset() { this->probability = 0; this->min_number = 0; this->target_count = 0; this->max_wait = 1; this->wait_count = 0; } /** Completely reset the industry build data. */ void IndustryBuildData::Reset() { this->wanted_inds = GetCurrentTotalNumberOfIndustries() << 16; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { this->builddata[it].Reset(); } } /** Monthly update of industry build data. */ void IndustryBuildData::MonthlyLoop() { static const int NEWINDS_PER_MONTH = 0x38000 / (10 * 12); // lower 16 bits is a float fraction, 3.5 industries per decade, divided by 10 * 12 months. if (_settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // 'no industries' setting. /* To prevent running out of unused industries for the player to connect, * add a fraction of new industries each month, but only if the manager can keep up. */ uint max_behind = 1 + min(99u, ScaleByMapSize(3)); // At most 2 industries for small maps, and 100 at the biggest map (about 6 months industry build attempts). if (GetCurrentTotalNumberOfIndustries() + max_behind >= (this->wanted_inds >> 16)) { this->wanted_inds += ScaleByMapSize(NEWINDS_PER_MONTH); } } /** * This function will create random industries during game creation. * It will scale the amount of industries by mapsize and difficulty level. */ void GenerateIndustries() { if (_game_mode != GM_EDITOR && _settings_game.difficulty.industry_density == ID_FUND_ONLY) return; // No industries in the game. uint32 industry_probs[NUM_INDUSTRYTYPES]; bool force_at_least_one[NUM_INDUSTRYTYPES]; uint32 total_prob = 0; uint num_forced = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { industry_probs[it] = GetScaledIndustryGenerationProbability(it, force_at_least_one + it); total_prob += industry_probs[it]; if (force_at_least_one[it]) num_forced++; } uint total_amount = GetNumberOfIndustries(); if (total_prob == 0 || total_amount < num_forced) { /* Only place the forced ones */ total_amount = num_forced; } SetGeneratingWorldProgress(GWP_INDUSTRY, total_amount); /* Try to build one industry per type independent of any probabilities */ for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { if (force_at_least_one[it]) { assert(total_amount > 0); total_amount--; PlaceInitialIndustry(it, true); } } /* Add the remaining industries according to their probabilities */ for (uint i = 0; i < total_amount; i++) { uint32 r = RandomRange(total_prob); IndustryType it = 0; while (r >= industry_probs[it]) { r -= industry_probs[it]; it++; assert(it < NUM_INDUSTRYTYPES); } assert(industry_probs[it] > 0); PlaceInitialIndustry(it, false); } _industry_builder.Reset(); } /** * Monthly update of industry statistics. * @param i Industry to update. */ static void UpdateIndustryStatistics(Industry *i) { for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] != CT_INVALID) { byte pct = 0; if (i->this_month_production[j] != 0) { i->last_prod_year = _cur_year; pct = min(i->this_month_transported[j] * 256 / i->this_month_production[j], 255); } i->last_month_pct_transported[j] = pct; i->last_month_production[j] = i->this_month_production[j]; i->this_month_production[j] = 0; i->last_month_transported[j] = i->this_month_transported[j]; i->this_month_transported[j] = 0; } } } /** * Recompute #production_rate for current #prod_level. * This function is only valid when not using smooth economy. */ void Industry::RecomputeProductionMultipliers() { const IndustrySpec *indspec = GetIndustrySpec(this->type); assert(!indspec->UsesSmoothEconomy()); /* Rates are rounded up, so e.g. oilrig always produces some passengers */ this->production_rate[0] = min(CeilDiv(indspec->production_rate[0] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF); this->production_rate[1] = min(CeilDiv(indspec->production_rate[1] * this->prod_level, PRODLEVEL_DEFAULT), 0xFF); } /** * Set the #probability and #min_number fields for the industry type \a it for a running game. * @param it Industry type. * @return At least one of the fields has changed value. */ bool IndustryTypeBuildData::GetIndustryTypeData(IndustryType it) { byte min_number; uint32 probability = GetIndustryGamePlayProbability(it, &min_number); bool changed = min_number != this->min_number || probability != this->probability; this->min_number = min_number; this->probability = probability; return changed; } /** Decide how many industries of each type are needed. */ void IndustryBuildData::SetupTargetCount() { bool changed = false; uint num_planned = 0; // Number of industries planned in the industry build data. for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { changed |= this->builddata[it].GetIndustryTypeData(it); num_planned += this->builddata[it].target_count; } uint total_amount = this->wanted_inds >> 16; // Desired total number of industries. changed |= num_planned != total_amount; if (!changed) return; // All industries are still the same, no need to re-randomize. /* Initialize the target counts. */ uint force_build = 0; // Number of industries that should always be available. uint32 total_prob = 0; // Sum of probabilities. for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { IndustryTypeBuildData *ibd = this->builddata + it; force_build += ibd->min_number; ibd->target_count = ibd->min_number; total_prob += ibd->probability; } if (total_prob == 0) return; // No buildable industries. /* Subtract forced industries from the number of industries available for construction. */ total_amount = (total_amount <= force_build) ? 0 : total_amount - force_build; /* Assign number of industries that should be aimed for, by using the probability as a weight. */ while (total_amount > 0) { uint32 r = RandomRange(total_prob); IndustryType it = 0; while (r >= this->builddata[it].probability) { r -= this->builddata[it].probability; it++; assert(it < NUM_INDUSTRYTYPES); } assert(this->builddata[it].probability > 0); this->builddata[it].target_count++; total_amount--; } } /** * Try to create a random industry, during gameplay */ void IndustryBuildData::TryBuildNewIndustry() { this->SetupTargetCount(); int missing = 0; // Number of industries that need to be build. uint count = 0; // Number of industry types eligible for build. uint32 total_prob = 0; // Sum of probabilities. IndustryType forced_build = NUM_INDUSTRYTYPES; // Industry type that should be forcibly build. for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it); missing += difference; if (this->builddata[it].wait_count > 0) continue; // This type may not be built now. if (difference > 0) { if (Industry::GetIndustryTypeCount(it) == 0 && this->builddata[it].min_number > 0) { /* An industry that should exist at least once, is not available. Force it, trying the most needed one first. */ if (forced_build == NUM_INDUSTRYTYPES || difference > this->builddata[forced_build].target_count - Industry::GetIndustryTypeCount(forced_build)) { forced_build = it; } } total_prob += difference; count++; } } if (EconomyIsInRecession() || (forced_build == NUM_INDUSTRYTYPES && (missing <= 0 || total_prob == 0))) count = 0; // Skip creation of an industry. if (count >= 1) { /* If not forced, pick a weighted random industry to build. * For the case that count == 1, there is no need to draw a random number. */ IndustryType it; if (forced_build != NUM_INDUSTRYTYPES) { it = forced_build; } else { /* Non-forced, select an industry type to build (weighted random). */ uint32 r = 0; // Initialized to silence the compiler. if (count > 1) r = RandomRange(total_prob); for (it = 0; it < NUM_INDUSTRYTYPES; it++) { if (this->builddata[it].wait_count > 0) continue; // Type may not be built now. int difference = this->builddata[it].target_count - Industry::GetIndustryTypeCount(it); if (difference <= 0) continue; // Too many of this kind. if (count == 1) break; if (r < (uint)difference) break; r -= difference; } assert(it < NUM_INDUSTRYTYPES && this->builddata[it].target_count > Industry::GetIndustryTypeCount(it)); } /* Try to create the industry. */ const Industry *ind = PlaceIndustry(it, IACT_RANDOMCREATION, false); if (ind == NULL) { this->builddata[it].wait_count = this->builddata[it].max_wait + 1; // Compensate for decrementing below. this->builddata[it].max_wait = min(1000, this->builddata[it].max_wait + 2); } else { AdvertiseIndustryOpening(ind); this->builddata[it].max_wait = max(this->builddata[it].max_wait / 2, 1); // Reduce waiting time of the industry type. } } /* Decrement wait counters. */ for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { if (this->builddata[it].wait_count > 0) this->builddata[it].wait_count--; } } /** * Protects an industry from closure if the appropriate flags and conditions are met * INDUSTRYBEH_CANCLOSE_LASTINSTANCE must be set (which, by default, it is not) and the * count of industries of this type must one (or lower) in order to be protected * against closure. * @param type IndustryType been queried * @result true if protection is on, false otherwise (except for oil wells) */ static bool CheckIndustryCloseDownProtection(IndustryType type) { const IndustrySpec *indspec = GetIndustrySpec(type); /* oil wells (or the industries with that flag set) are always allowed to closedown */ if ((indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE) return false; return (indspec->behaviour & INDUSTRYBEH_CANCLOSE_LASTINSTANCE) == 0 && Industry::GetIndustryTypeCount(type) <= 1; } /** * Can given cargo type be accepted or produced by the industry? * @param cargo: Cargo type * @param ind: Industry * @param *c_accepts: Pointer to boolean for acceptance of cargo * @param *c_produces: Pointer to boolean for production of cargo * @return: \c *c_accepts is set when industry accepts the cargo type, * \c *c_produces is set when the industry produces the cargo type */ static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accepts, bool *c_produces) { if (cargo == CT_INVALID) return; /* Check for acceptance of cargo */ for (byte j = 0; j < lengthof(ind->accepts_cargo); j++) { if (cargo == ind->accepts_cargo[j] && !IndustryTemporarilyRefusesCargo(ind, cargo)) { *c_accepts = true; break; } } /* Check for produced cargo */ for (byte j = 0; j < lengthof(ind->produced_cargo); j++) { if (cargo == ind->produced_cargo[j]) { *c_produces = true; break; } } } /** * Compute who can service the industry. * * Here, 'can service' means that he/she has trains and stations close enough * to the industry with the right cargo type and the right orders (ie has the * technical means). * * @param ind: Industry being investigated. * * @return: 0 if nobody can service the industry, 2 if the local company can * service the industry, and 1 otherwise (only competitors can service the * industry) */ static int WhoCanServiceIndustry(Industry *ind) { /* Find all stations within reach of the industry */ StationList stations; FindStationsAroundTiles(ind->location, &stations); if (stations.Length() == 0) return 0; // No stations found at all => nobody services const Vehicle *v; int result = 0; FOR_ALL_VEHICLES(v) { /* Is it worthwhile to try this vehicle? */ if (v->owner != _local_company && result != 0) continue; /* Check whether it accepts the right kind of cargo */ bool c_accepts = false; bool c_produces = false; if (v->type == VEH_TRAIN && v->IsFrontEngine()) { for (const Vehicle *u = v; u != NULL; u = u->Next()) { CanCargoServiceIndustry(u->cargo_type, ind, &c_accepts, &c_produces); } } else if (v->type == VEH_ROAD || v->type == VEH_SHIP || v->type == VEH_AIRCRAFT) { CanCargoServiceIndustry(v->cargo_type, ind, &c_accepts, &c_produces); } else { continue; } if (!c_accepts && !c_produces) continue; // Wrong cargo /* Check orders of the vehicle. * We cannot check the first of shared orders only, since the first vehicle in such a chain * may have a different cargo type. */ const Order *o; FOR_VEHICLE_ORDERS(v, o) { if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) { /* Vehicle visits a station to load or unload */ Station *st = Station::Get(o->GetDestination()); assert(st != NULL); /* Same cargo produced by industry is dropped here => not serviced by vehicle v */ if ((o->GetUnloadType() & OUFB_UNLOAD) && !c_accepts) break; if (stations.Contains(st)) { if (v->owner == _local_company) return 2; // Company services industry result = 1; // Competitor services industry } } } } return result; } /** * Report news that industry production has changed significantly * * @param ind: Industry with changed production * @param type: Cargo type that has changed * @param percent: Percentage of change (>0 means increase, <0 means decrease) */ static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent) { NewsType nt; switch (WhoCanServiceIndustry(ind)) { case 0: nt = NT_INDUSTRY_NOBODY; break; case 1: nt = NT_INDUSTRY_OTHER; break; case 2: nt = NT_INDUSTRY_COMPANY; break; default: NOT_REACHED(); } SetDParam(2, abs(percent)); SetDParam(0, CargoSpec::Get(type)->name); SetDParam(1, ind->index); AddIndustryNewsItem( percent >= 0 ? STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH : STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH, nt, ind->index ); } static const uint PERCENT_TRANSPORTED_60 = 153; static const uint PERCENT_TRANSPORTED_80 = 204; /** * Change industry production or do closure * @param i Industry for which changes are performed * @param monthly true if it's the monthly call, false if it's the random call */ static void ChangeIndustryProduction(Industry *i, bool monthly) { StringID str = STR_NULL; bool closeit = false; const IndustrySpec *indspec = GetIndustrySpec(i->type); bool standard = false; bool suppress_message = false; bool recalculate_multipliers = false; ///< reinitialize production_rate to match prod_level /* don't use smooth economy for industries using production related callbacks */ bool smooth_economy = indspec->UsesSmoothEconomy(); byte div = 0; byte mul = 0; int8 increment = 0; bool callback_enabled = HasBit(indspec->callback_mask, monthly ? CBM_IND_MONTHLYPROD_CHANGE : CBM_IND_PRODUCTION_CHANGE); if (callback_enabled) { uint16 res = GetIndustryCallback(monthly ? CBID_INDUSTRY_MONTHLYPROD_CHANGE : CBID_INDUSTRY_PRODUCTION_CHANGE, 0, Random(), i, i->type, i->location.tile); if (res != CALLBACK_FAILED) { // failed callback means "do nothing" suppress_message = HasBit(res, 7); /* Get the custom message if any */ if (HasBit(res, 8)) str = MapGRFStringID(indspec->grf_prop.grffile->grfid, GB(GetRegister(0x100), 0, 16)); res = GB(res, 0, 4); switch (res) { default: NOT_REACHED(); case 0x0: break; // Do nothing, but show the custom message if any case 0x1: div = 1; break; // Halve industry production. If production reaches the quarter of the default, the industry is closed instead. case 0x2: mul = 1; break; // Double industry production if it hasn't reached eight times of the original yet. case 0x3: closeit = true; break; // The industry announces imminent closure, and is physically removed from the map next month. case 0x4: standard = true; break; // Do the standard random production change as if this industry was a primary one. case 0x5: case 0x6: case 0x7: // Divide production by 4, 8, 16 case 0x8: div = res - 0x3; break; // Divide production by 32 case 0x9: case 0xA: case 0xB: // Multiply production by 4, 8, 16 case 0xC: mul = res - 0x7; break; // Multiply production by 32 case 0xD: // decrement production case 0xE: // increment production increment = res == 0x0D ? -1 : 1; break; case 0xF: // Set production to third byte of register 0x100 i->prod_level = Clamp(GB(GetRegister(0x100), 16, 8), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM); recalculate_multipliers = true; break; } } } else { if (monthly != smooth_economy) return; if (indspec->life_type == INDUSTRYLIFE_BLACK_HOLE) return; } if (standard || (!callback_enabled && (indspec->life_type & (INDUSTRYLIFE_ORGANIC | INDUSTRYLIFE_EXTRACTIVE)) != 0)) { /* decrease or increase */ bool only_decrease = (indspec->behaviour & INDUSTRYBEH_DONT_INCR_PROD) && _settings_game.game_creation.landscape == LT_TEMPERATE; if (smooth_economy) { closeit = true; for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == CT_INVALID) continue; uint32 r = Random(); int old_prod, new_prod, percent; /* If over 60% is transported, mult is 1, else mult is -1. */ int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1; new_prod = old_prod = i->production_rate[j]; /* For industries with only_decrease flags (temperate terrain Oil Wells), * the multiplier will always be -1 so they will only decrease. */ if (only_decrease) { mult = -1; /* For normal industries, if over 60% is transported, 33% chance for decrease. * Bonus for very high station ratings (over 80%): 16% chance for decrease. */ } else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) { mult *= -1; } /* 4.5% chance for 3-23% (or 1 unit for very low productions) production change, * determined by mult value. If mult = 1 prod. increases, else (-1) it decreases. */ if (Chance16I(1, 22, r >> 16)) { new_prod += mult * (max(((RandomRange(50) + 10) * old_prod) >> 8, 1U)); } /* Prevent production to overflow or Oil Rig passengers to be over-"produced" */ new_prod = Clamp(new_prod, 1, 255); if (((indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) && j == 1) { new_prod = Clamp(new_prod, 0, 16); } /* Do not stop closing the industry when it has the lowest possible production rate */ if (new_prod == old_prod && old_prod > 1) { closeit = false; continue; } percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100); i->production_rate[j] = new_prod; /* Close the industry when it has the lowest possible production rate */ if (new_prod > 1) closeit = false; if (abs(percent) >= 10) { ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent); } } } else { if (only_decrease || Chance16(1, 3)) { /* If more than 60% transported, 66% chance of increase, else 33% chance of increase */ if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) { mul = 1; // Increase production } else { div = 1; // Decrease production } } } } if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) { if ( (byte)(_cur_year - i->last_prod_year) >= 5 && Chance16(1, smooth_economy ? 180 : 2)) { closeit = true; } } /* Increase if needed */ while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) { i->prod_level = min(i->prod_level * 2, PRODLEVEL_MAXIMUM); recalculate_multipliers = true; if (str == STR_NULL) str = indspec->production_up_text; } /* Decrease if needed */ while (div-- != 0 && !closeit) { if (i->prod_level == PRODLEVEL_MINIMUM) { closeit = true; } else { i->prod_level = max(i->prod_level / 2, (int)PRODLEVEL_MINIMUM); // typecast to int required to please MSVC recalculate_multipliers = true; if (str == STR_NULL) str = indspec->production_down_text; } } /* Increase or Decreasing the production level if needed */ if (increment != 0) { if (increment < 0 && i->prod_level == PRODLEVEL_MINIMUM) { closeit = true; } else { i->prod_level = ClampU(i->prod_level + increment, PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM); recalculate_multipliers = true; } } /* Recalculate production_rate * For non-smooth economy these should always be synchronized with prod_level */ if (recalculate_multipliers) i->RecomputeProductionMultipliers(); /* Close if needed and allowed */ if (closeit && !CheckIndustryCloseDownProtection(i->type)) { i->prod_level = PRODLEVEL_CLOSURE; SetWindowDirty(WC_INDUSTRY_VIEW, i->index); str = indspec->closure_text; } if (!suppress_message && str != STR_NULL) { NewsType nt; /* Compute news category */ if (closeit) { nt = NT_INDUSTRY_CLOSE; AI::BroadcastNewEvent(new ScriptEventIndustryClose(i->index)); Game::NewEvent(new ScriptEventIndustryClose(i->index)); } else { switch (WhoCanServiceIndustry(i)) { case 0: nt = NT_INDUSTRY_NOBODY; break; case 1: nt = NT_INDUSTRY_OTHER; break; case 2: nt = NT_INDUSTRY_COMPANY; break; default: NOT_REACHED(); } } /* Set parameters of news string */ if (str > STR_LAST_STRINGID) { SetDParam(0, STR_TOWN_NAME); SetDParam(1, i->town->index); SetDParam(2, indspec->name); } else if (closeit) { SetDParam(0, STR_FORMAT_INDUSTRY_NAME); SetDParam(1, i->town->index); SetDParam(2, indspec->name); } else { SetDParam(0, i->index); } /* and report the news to the user */ if (closeit) { AddTileNewsItem(str, nt, i->location.tile + TileDiffXY(1, 1)); } else { AddIndustryNewsItem(str, nt, i->index); } } } /** * Daily handler for the industry changes * Taking the original map size of 256*256, the number of random changes was always of just one unit. * But it cannot be the same on smaller or bigger maps. That number has to be scaled up or down. * For small maps, it implies that less than one change per month is required, while on bigger maps, * it would be way more. The daily loop handles those changes. */ void IndustryDailyLoop() { _economy.industry_daily_change_counter += _economy.industry_daily_increment; /* Bits 16-31 of industry_construction_counter contain the number of industries to change/create today, * the lower 16 bit are a fractional part that might accumulate over several days until it * is sufficient for an industry. */ uint16 change_loop = _economy.industry_daily_change_counter >> 16; /* Reset the active part of the counter, just keeping the "fractional part" */ _economy.industry_daily_change_counter &= 0xFFFF; if (change_loop == 0) { return; // Nothing to do? get out } Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); /* perform the required industry changes for the day */ uint perc = 3; // Between 3% and 9% chance of creating a new industry. if ((_industry_builder.wanted_inds >> 16) > GetCurrentTotalNumberOfIndustries()) { perc = min(9u, perc + (_industry_builder.wanted_inds >> 16) - GetCurrentTotalNumberOfIndustries()); } for (uint16 j = 0; j < change_loop; j++) { if (Chance16(perc, 100)) { _industry_builder.TryBuildNewIndustry(); } else { Industry *i = Industry::GetRandom(); if (i != NULL) { ChangeIndustryProduction(i, false); SetWindowDirty(WC_INDUSTRY_VIEW, i->index); } } } cur_company.Restore(); /* production-change */ InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1); } void IndustryMonthlyLoop() { Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); _industry_builder.MonthlyLoop(); Industry *i; FOR_ALL_INDUSTRIES(i) { UpdateIndustryStatistics(i); if (i->prod_level == PRODLEVEL_CLOSURE) { delete i; } else { ChangeIndustryProduction(i, true); SetWindowDirty(WC_INDUSTRY_VIEW, i->index); } } cur_company.Restore(); /* production-change */ InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1); } void InitializeIndustries() { Industry::ResetIndustryCounts(); _industry_sound_tile = 0; _industry_builder.Reset(); } /** Verify whether the generated industries are complete, and warn the user if not. */ void CheckIndustries() { int count = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { if (Industry::GetIndustryTypeCount(it) > 0) continue; // Types of existing industries can be skipped. bool force_at_least_one; uint32 chance = GetScaledIndustryGenerationProbability(it, &force_at_least_one); if (chance == 0 || !force_at_least_one) continue; // Types that are not available can be skipped. const IndustrySpec *is = GetIndustrySpec(it); SetDParam(0, is->name); ShowErrorMessage(STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES, STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION, WL_WARNING); count++; if (count >= 3) break; // Don't swamp the user with errors. } } /** * Is an industry with the spec a raw industry? * @return true if it should be handled as a raw industry */ bool IndustrySpec::IsRawIndustry() const { return (this->life_type & (INDUSTRYLIFE_EXTRACTIVE | INDUSTRYLIFE_ORGANIC)) != 0; } /** * Is an industry with the spec a processing industry? * @return true if it should be handled as a processing industry */ bool IndustrySpec::IsProcessingIndustry() const { /* Lumber mills are neither raw nor processing */ return (this->life_type & INDUSTRYLIFE_PROCESSING) != 0 && (this->behaviour & INDUSTRYBEH_CUT_TREES) == 0; } /** * Get the cost for constructing this industry * @return the cost (inflation corrected etc) */ Money IndustrySpec::GetConstructionCost() const { /* Building raw industries like secondary uses different price base */ return (_price[(_settings_game.construction.raw_industry_construction == 1 && this->IsRawIndustry()) ? PR_BUILD_INDUSTRY_RAW : PR_BUILD_INDUSTRY] * this->cost_multiplier) >> 8; } /** * Get the cost for removing this industry * Take note that the cost will always be zero for non-grf industries. * Only if the grf author did specified a cost will it be applicable. * @return the cost (inflation corrected etc) */ Money IndustrySpec::GetRemovalCost() const { return (_price[PR_CLEAR_INDUSTRY] * this->removal_cost_multiplier) >> 8; } /** * Determines whether this industrytype uses smooth economy or whether it uses standard/newgrf production changes. * @return true if smooth economy is used. */ bool IndustrySpec::UsesSmoothEconomy() const { return _settings_game.economy.smooth_economy && !(HasBit(this->callback_mask, CBM_IND_PRODUCTION_256_TICKS) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) && // production callbacks !(HasBit(this->callback_mask, CBM_IND_MONTHLYPROD_CHANGE) || HasBit(this->callback_mask, CBM_IND_PRODUCTION_CHANGE) || HasBit(this->callback_mask, CBM_IND_PROD_CHANGE_BUILD)); // production change callbacks } static CommandCost TerraformTile_Industry(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { if (AutoslopeEnabled()) { /* We imitate here TTDP's behaviour: * - Both new and old slope must not be steep. * - TileMaxZ must not be changed. * - Allow autoslope by default. * - Disallow autoslope if callback succeeds and returns non-zero. */ Slope tileh_old = GetTileSlope(tile); /* TileMaxZ must not be changed. Slopes must not be steep. */ if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) { const IndustryGfx gfx = GetIndustryGfx(tile); const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); /* Call callback 3C 'disable autosloping for industry tiles'. */ if (HasBit(itspec->callback_mask, CBM_INDT_AUTOSLOPE)) { /* If the callback fails, allow autoslope. */ uint16 res = GetIndustryTileCallback(CBID_INDTILE_AUTOSLOPE, 0, 0, gfx, Industry::GetByTile(tile), tile); if (res == CALLBACK_FAILED || !ConvertBooleanCallback(itspec->grf_prop.grffile, CBID_INDTILE_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } else { /* allow autoslope */ return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } } } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } extern const TileTypeProcs _tile_type_industry_procs = { DrawTile_Industry, // draw_tile_proc GetSlopePixelZ_Industry, // get_slope_z_proc ClearTile_Industry, // clear_tile_proc AddAcceptedCargo_Industry, // add_accepted_cargo_proc GetTileDesc_Industry, // get_tile_desc_proc GetTileTrackStatus_Industry, // get_tile_track_status_proc ClickTile_Industry, // click_tile_proc AnimateTile_Industry, // animate_tile_proc TileLoop_Industry, // tile_loop_proc ChangeTileOwner_Industry, // change_tile_owner_proc NULL, // add_produced_cargo_proc NULL, // vehicle_enter_tile_proc GetFoundation_Industry, // get_foundation_proc TerraformTile_Industry, // terraform_tile_proc }; openttd-1.5.3/src/widgets/0000755000000000000000000000000012627373434014143 5ustar rootrootopenttd-1.5.3/src/widgets/news_widget.h0000644000000000000000000000406012627373434016633 0ustar rootroot/* $Id: news_widget.h 24842 2012-12-23 21:06:37Z frosch $ */ /* * 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 news_widget.h Types related to the news widgets. */ #ifndef WIDGETS_NEWS_WIDGET_H #define WIDGETS_NEWS_WIDGET_H #include "../news_type.h" /** Widgets of the #NewsWindow class. */ enum NewsWidgets { WID_N_PANEL, ///< Panel of the window. WID_N_TITLE, ///< Title of the company news. WID_N_HEADLINE, ///< The news headline. WID_N_CLOSEBOX, ///< Close the window. WID_N_DATE, ///< Date of the news item. WID_N_CAPTION, ///< Title bar of the window. Only used in small news items. WID_N_INSET, ///< Inset around the viewport in the window. Only used in small news items. WID_N_VIEWPORT, ///< Viewport in the window. WID_N_COMPANY_MSG, ///< Message in company news items. WID_N_MESSAGE, ///< Space for displaying the message. Only used in small news items. WID_N_MGR_FACE, ///< Face of the manager. WID_N_MGR_NAME, ///< Name of the manager. WID_N_VEH_TITLE, ///< Vehicle new title. WID_N_VEH_BKGND, ///< Dark background of new vehicle news. WID_N_VEH_NAME, ///< Name of the new vehicle. WID_N_VEH_SPR, ///< Graphical display of the new vehicle. WID_N_VEH_INFO, ///< Some technical data of the new vehicle. }; /** Widgets of the #MessageHistoryWindow class. */ enum MessageHistoryWidgets { WID_MH_STICKYBOX, ///< Stickybox. WID_MH_BACKGROUND, ///< Background of the window. WID_MH_SCROLLBAR, ///< Scrollbar for the list. }; #endif /* WIDGETS_NEWS_WIDGET_H */ openttd-1.5.3/src/widgets/osk_widget.h0000644000000000000000000000411212627373434016451 0ustar rootroot/* $Id: osk_widget.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 osk_widget.h Types related to the osk widgets. */ #ifndef WIDGETS_OSK_WIDGET_H #define WIDGETS_OSK_WIDGET_H /** Widgets of the #OskWindow class. */ enum OnScreenKeyboardWidgets { WID_OSK_CAPTION, ///< Caption of window. WID_OSK_TEXT, ///< Edit box. WID_OSK_CANCEL, ///< Cancel key. WID_OSK_OK, ///< Ok key. WID_OSK_BACKSPACE, ///< Backspace key. WID_OSK_SPECIAL, ///< Special key (at keyboards often used for tab key). WID_OSK_CAPS, ///< Capslock key. WID_OSK_SHIFT, ///< Shift(lock) key. WID_OSK_SPACE, ///< Space bar. WID_OSK_LEFT, ///< Cursor left key. WID_OSK_RIGHT, ///< Cursor right key. WID_OSK_LETTERS, ///< First widget of the 'normal' keys. WID_OSK_NUMBERS_FIRST = WID_OSK_LETTERS, ///< First widget of the numbers row. WID_OSK_NUMBERS_LAST = WID_OSK_NUMBERS_FIRST + 13, ///< Last widget of the numbers row. WID_OSK_QWERTY_FIRST, ///< First widget of the qwerty row. WID_OSK_QWERTY_LAST = WID_OSK_QWERTY_FIRST + 11, ///< Last widget of the qwerty row. WID_OSK_ASDFG_FIRST, ///< First widget of the asdfg row. WID_OSK_ASDFG_LAST = WID_OSK_ASDFG_FIRST + 11, ///< Last widget of the asdfg row. WID_OSK_ZXCVB_FIRST, ///< First widget of the zxcvb row. WID_OSK_ZXCVB_LAST = WID_OSK_ZXCVB_FIRST + 11, ///< Last widget of the zxcvb row. }; #endif /* WIDGETS_OSK_WIDGET_H */ openttd-1.5.3/src/widgets/newgrf_debug_widget.h0000644000000000000000000000415412627373434020321 0ustar rootroot/* $Id: newgrf_debug_widget.h 27174 2015-03-01 08:17:14Z alberth $ */ /* * 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 newgrf_debug_widget.h Types related to the newgrf debug widgets. */ #ifndef WIDGETS_NEWGRF_DEBUG_WIDGET_H #define WIDGETS_NEWGRF_DEBUG_WIDGET_H /** Widgets of the #NewGRFInspectWindow class. */ enum NewGRFInspectWidgets { WID_NGRFI_CAPTION, ///< The caption bar of course. WID_NGRFI_PARENT, ///< Inspect the parent. WID_NGRFI_VEH_PREV, ///< Go to previous vehicle in chain. WID_NGRFI_VEH_NEXT, ///< Go to next vehicle in chain. WID_NGRFI_VEH_CHAIN, ///< Display for vehicle chain. WID_NGRFI_MAINPANEL, ///< Panel widget containing the actual data. WID_NGRFI_SCROLLBAR, ///< Scrollbar. }; /** Widgets of the #SpriteAlignerWindow class. */ enum SpriteAlignerWidgets { WID_SA_CAPTION, ///< Caption of the window. WID_SA_PREVIOUS, ///< Skip to the previous sprite. WID_SA_GOTO, ///< Go to a given sprite. WID_SA_NEXT, ///< Skip to the next sprite. WID_SA_UP, ///< Move the sprite up. WID_SA_LEFT, ///< Move the sprite to the left. WID_SA_RIGHT, ///< Move the sprite to the right. WID_SA_DOWN, ///< Move the sprite down. WID_SA_SPRITE, ///< The actual sprite. WID_SA_OFFSETS_ABS, ///< The sprite offsets (absolute). WID_SA_OFFSETS_REL, ///< The sprite offsets (relative). WID_SA_PICKER, ///< Sprite picker. WID_SA_LIST, ///< Queried sprite list. WID_SA_SCROLLBAR, ///< Scrollbar for sprite list. WID_SA_RESET_REL, ///< Reset relative sprite offset }; #endif /* WIDGETS_NEWGRF_DEBUG_WIDGET_H */ openttd-1.5.3/src/widgets/tree_widget.h0000644000000000000000000000321212627373434016614 0ustar rootroot/* $Id: tree_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 tree_widget.h Types related to the tree widgets. */ #ifndef WIDGETS_TREE_WIDGET_H #define WIDGETS_TREE_WIDGET_H /** Widgets of the #BuildTreesWindow class. */ enum BuildTreesWidgets { WID_BT_TYPE_11, ///< Tree 1st column 1st row. WID_BT_TYPE_12, ///< Tree 1st column 2nd row. WID_BT_TYPE_13, ///< Tree 1st column 3rd row. WID_BT_TYPE_14, ///< Tree 1st column 4th row. WID_BT_TYPE_21, ///< Tree 2st column 1st row. WID_BT_TYPE_22, ///< Tree 2st column 2nd row. WID_BT_TYPE_23, ///< Tree 2st column 3rd row. WID_BT_TYPE_24, ///< Tree 2st column 4th row. WID_BT_TYPE_31, ///< Tree 3st column 1st row. WID_BT_TYPE_32, ///< Tree 3st column 2nd row. WID_BT_TYPE_33, ///< Tree 3st column 3rd row. WID_BT_TYPE_34, ///< Tree 3st column 4th row. WID_BT_TYPE_RANDOM, ///< Button to build random type of tree. WID_BT_MANY_RANDOM, ///< Button to build many random trees. }; #endif /* WIDGETS_TREE_WIDGET_H */ openttd-1.5.3/src/widgets/timetable_widget.h0000644000000000000000000000403712627373434017631 0ustar rootroot/* $Id: timetable_widget.h 23947 2012-02-14 17:04:06Z michi_cc $ */ /* * 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 timetable_widget.h Types related to the timetable widgets. */ #ifndef WIDGETS_TIMETABLE_WIDGET_H #define WIDGETS_TIMETABLE_WIDGET_H /** Widgets of the #TimetableWindow class. */ enum VehicleTimetableWidgets { WID_VT_CAPTION, ///< Caption of the window. WID_VT_ORDER_VIEW, ///< Order view. WID_VT_TIMETABLE_PANEL, ///< Timetable panel. WID_VT_ARRIVAL_DEPARTURE_PANEL, ///< Panel with the expected/scheduled arrivals. WID_VT_SCROLLBAR, ///< Scrollbar for the panel. WID_VT_SUMMARY_PANEL, ///< Summary panel. WID_VT_START_DATE, ///< Start date button. WID_VT_CHANGE_TIME, ///< Change time button. WID_VT_CLEAR_TIME, ///< Clear time button. WID_VT_RESET_LATENESS, ///< Reset lateness button. WID_VT_AUTOFILL, ///< Autofill button. WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals. WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list. WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel. WID_VT_EXPECTED_SELECTION, ///< Disable/hide the expected selection button. WID_VT_CHANGE_SPEED, ///< Change speed limit button. WID_VT_CLEAR_SPEED, ///< Clear speed limit button. }; #endif /* WIDGETS_TIMETABLE_WIDGET_H */ openttd-1.5.3/src/widgets/ai_widget.h0000644000000000000000000000666312627373434016263 0ustar rootroot/* $Id: ai_widget.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 ai_widget.h Types related to the ai widgets. */ #ifndef WIDGETS_AI_WIDGET_H #define WIDGETS_AI_WIDGET_H #include "../company_type.h" #include "../textfile_type.h" /** Widgets of the #AIListWindow class. */ enum AIListWidgets { WID_AIL_CAPTION, ///< Caption of the window. WID_AIL_LIST, ///< The matrix with all available AIs. WID_AIL_SCROLLBAR, ///< Scrollbar next to the AI list. WID_AIL_INFO_BG, ///< Panel to draw some AI information on. WID_AIL_ACCEPT, ///< Accept button. WID_AIL_CANCEL, ///< Cancel button. }; /** Widgets of the #AISettingsWindow class. */ enum AISettingsWidgets { WID_AIS_CAPTION, ///< Caption of the window. WID_AIS_BACKGROUND, ///< Panel to draw the settings on. WID_AIS_SCROLLBAR, ///< Scrollbar to scroll through all settings. WID_AIS_ACCEPT, ///< Accept button. WID_AIS_RESET, ///< Reset button. }; /** Widgets of the #AIConfigWindow class. */ enum AIConfigWidgets { WID_AIC_BACKGROUND, ///< Window background. WID_AIC_DECREASE, ///< Decrease the number of AIs. WID_AIC_INCREASE, ///< Increase the number of AIs. WID_AIC_NUMBER, ///< Number of AIs. WID_AIC_GAMELIST, ///< List with current selected GameScript. WID_AIC_LIST, ///< List with currently selected AIs. WID_AIC_SCROLLBAR, ///< Scrollbar to scroll through the selected AIs. WID_AIC_MOVE_UP, ///< Move up button. WID_AIC_MOVE_DOWN, ///< Move down button. WID_AIC_CHANGE, ///< Select another AI button. WID_AIC_CONFIGURE, ///< Change AI settings button. WID_AIC_CLOSE, ///< Close window button. WID_AIC_TEXTFILE, ///< Open AI readme, changelog (+1) or license (+2). WID_AIC_CONTENT_DOWNLOAD = WID_AIC_TEXTFILE + TFT_END, ///< Download content button. }; /** Widgets of the #AIDebugWindow class. */ enum AIDebugWidgets { WID_AID_VIEW, ///< The row of company buttons. WID_AID_NAME_TEXT, ///< Name of the current selected. WID_AID_SETTINGS, ///< Settings button. WID_AID_SCRIPT_GAME, ///< Game Script button. WID_AID_RELOAD_TOGGLE, ///< Reload button. WID_AID_LOG_PANEL, ///< Panel where the log is in. WID_AID_SCROLLBAR, ///< Scrollbar of the log panel. WID_AID_COMPANY_BUTTON_START, ///< Buttons in the VIEW. WID_AID_COMPANY_BUTTON_END = WID_AID_COMPANY_BUTTON_START + MAX_COMPANIES - 1, ///< Last possible button in the VIEW. WID_AID_BREAK_STRING_WIDGETS, ///< The panel to handle the breaking on string. WID_AID_BREAK_STR_ON_OFF_BTN, ///< Enable breaking on string. WID_AID_BREAK_STR_EDIT_BOX, ///< Edit box for the string to break on. WID_AID_MATCH_CASE_BTN, ///< Checkbox to use match caching or not. WID_AID_CONTINUE_BTN, ///< Continue button. }; #endif /* WIDGETS_AI_WIDGET_H */ openttd-1.5.3/src/widgets/company_widget.h0000644000000000000000000002270412627373434017332 0ustar rootroot/* $Id: company_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 company_widget.h Types related to the company widgets. */ #ifndef WIDGETS_COMPANY_WIDGET_H #define WIDGETS_COMPANY_WIDGET_H /** Widgets of the #CompanyWindow class. */ enum CompanyWidgets { WID_C_CAPTION, ///< Caption of the window. WID_C_FACE, ///< View of the face. WID_C_FACE_TITLE, ///< Title for the face. WID_C_DESC_INAUGURATION, ///< Inauguration. WID_C_DESC_COLOUR_SCHEME, ///< Colour scheme. WID_C_DESC_COLOUR_SCHEME_EXAMPLE, ///< Colour scheme example. WID_C_DESC_VEHICLE, ///< Vehicles. WID_C_DESC_VEHICLE_COUNTS, ///< Vehicle count. WID_C_DESC_COMPANY_VALUE, ///< Company value. WID_C_DESC_INFRASTRUCTURE, ///< Infrastructure. WID_C_DESC_INFRASTRUCTURE_COUNTS, ///< Infrastructure count. WID_C_SELECT_DESC_OWNERS, ///< Owners. WID_C_DESC_OWNERS, ///< Owner in Owners. WID_C_SELECT_BUTTONS, ///< Selection widget for the button bar. WID_C_NEW_FACE, ///< Button to make new face. WID_C_COLOUR_SCHEME, ///< Button to change colour scheme. WID_C_PRESIDENT_NAME, ///< Button to change president name. WID_C_COMPANY_NAME, ///< Button to change company name. WID_C_BUY_SHARE, ///< Button to buy a share. WID_C_SELL_SHARE, ///< Button to sell a share. WID_C_SELECT_VIEW_BUILD_HQ, ///< Panel about HQ. WID_C_VIEW_HQ, ///< Button to view the HQ. WID_C_BUILD_HQ, ///< Button to build the HQ. WID_C_SELECT_RELOCATE, ///< Panel about 'Relocate HQ'. WID_C_RELOCATE_HQ, ///< Button to relocate the HQ. WID_C_VIEW_INFRASTRUCTURE, ///< Panel about infrastructure. WID_C_HAS_PASSWORD, ///< Has company password lock. WID_C_SELECT_MULTIPLAYER, ///< Multiplayer selection panel. WID_C_COMPANY_PASSWORD, ///< Button to set company password. WID_C_COMPANY_JOIN, ///< Button to join company. }; /** Widgets of the #CompanyFinancesWindow class. */ enum CompanyFinancesWidgets { WID_CF_CAPTION, ///< Caption of the window. WID_CF_TOGGLE_SIZE, ///< Toggle windows size. WID_CF_SEL_PANEL, ///< Select panel or nothing. WID_CF_EXPS_CATEGORY, ///< Column for expenses category strings. WID_CF_EXPS_PRICE1, ///< Column for year Y-2 expenses. WID_CF_EXPS_PRICE2, ///< Column for year Y-1 expenses. WID_CF_EXPS_PRICE3, ///< Column for year Y expenses. WID_CF_TOTAL_PANEL, ///< Panel for totals. WID_CF_SEL_MAXLOAN, ///< Selection of maxloan column. WID_CF_BALANCE_VALUE, ///< Bank balance value. WID_CF_LOAN_VALUE, ///< Loan. WID_CF_LOAN_LINE, ///< Line for summing bank balance and loan. WID_CF_TOTAL_VALUE, ///< Total. WID_CF_MAXLOAN_GAP, ///< Gap above max loan widget. WID_CF_MAXLOAN_VALUE, ///< Max loan widget. WID_CF_SEL_BUTTONS, ///< Selection of buttons. WID_CF_INCREASE_LOAN, ///< Increase loan. WID_CF_REPAY_LOAN, ///< Decrease loan.. WID_CF_INFRASTRUCTURE, ///< View company infrastructure. }; /** Widgets of the #SelectCompanyLiveryWindow class. */ enum SelectCompanyLiveryWidgets { WID_SCL_CAPTION, ///< Caption of window. WID_SCL_CLASS_GENERAL, ///< Class general. WID_SCL_CLASS_RAIL, ///< Class rail. WID_SCL_CLASS_ROAD, ///< Class road. WID_SCL_CLASS_SHIP, ///< Class ship. WID_SCL_CLASS_AIRCRAFT, ///< Class aircraft. WID_SCL_SPACER_DROPDOWN, ///< Spacer for dropdown. WID_SCL_PRI_COL_DROPDOWN, ///< Dropdown for primary colour. WID_SCL_SEC_COL_DROPDOWN, ///< Dropdown for secondary colour. WID_SCL_MATRIX, ///< Matrix. }; /** * Widgets of the #SelectCompanyManagerFaceWindow class. * Do not change the order of the widgets from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R, * this order is needed for the WE_CLICK event of DrawFaceStringLabel(). */ enum SelectCompanyManagerFaceWidgets { WID_SCMF_CAPTION, ///< Caption of window. WID_SCMF_TOGGLE_LARGE_SMALL, ///< Toggle for large or small. WID_SCMF_SELECT_FACE, ///< Select face. WID_SCMF_CANCEL, ///< Cancel. WID_SCMF_ACCEPT, ///< Accept. WID_SCMF_MALE, ///< Male button in the simple view. WID_SCMF_FEMALE, ///< Female button in the simple view. WID_SCMF_MALE2, ///< Male button in the advanced view. WID_SCMF_FEMALE2, ///< Female button in the advanced view. WID_SCMF_SEL_LOADSAVE, ///< Selection to display the load/save/number buttons in the advanced view. WID_SCMF_SEL_MALEFEMALE, ///< Selection to display the male/female buttons in the simple view. WID_SCMF_SEL_PARTS, ///< Selection to display the buttons for setting each part of the face in the advanced view. WID_SCMF_RANDOM_NEW_FACE, ///< Create random new face. WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, ///< Toggle for large or small. WID_SCMF_FACE, ///< Current face. WID_SCMF_LOAD, ///< Load face. WID_SCMF_FACECODE, ///< Get the face code. WID_SCMF_SAVE, ///< Save face. WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, ///< Text about moustache and earring. WID_SCMF_TIE_EARRING_TEXT, ///< Text about tie and earring. WID_SCMF_LIPS_MOUSTACHE_TEXT, ///< Text about lips and moustache. WID_SCMF_HAS_GLASSES_TEXT, ///< Text about glasses. WID_SCMF_HAIR_TEXT, ///< Text about hair. WID_SCMF_EYEBROWS_TEXT, ///< Text about eyebrows. WID_SCMF_EYECOLOUR_TEXT, ///< Text about eyecolour. WID_SCMF_GLASSES_TEXT, ///< Text about glasses. WID_SCMF_NOSE_TEXT, ///< Text about nose. WID_SCMF_CHIN_TEXT, ///< Text about chin. WID_SCMF_JACKET_TEXT, ///< Text about jacket. WID_SCMF_COLLAR_TEXT, ///< Text about collar. WID_SCMF_ETHNICITY_EUR, ///< Text about ethnicity european. WID_SCMF_ETHNICITY_AFR, ///< Text about ethnicity african. WID_SCMF_HAS_MOUSTACHE_EARRING, ///< Has moustache or earring. WID_SCMF_HAS_GLASSES, ///< Has glasses. WID_SCMF_EYECOLOUR_L, ///< Eyecolour left. WID_SCMF_EYECOLOUR, ///< Eyecolour. WID_SCMF_EYECOLOUR_R, ///< Eyecolour right. WID_SCMF_CHIN_L, ///< Chin left. WID_SCMF_CHIN, ///< Chin. WID_SCMF_CHIN_R, ///< Chin right. WID_SCMF_EYEBROWS_L, ///< Eyebrows left. WID_SCMF_EYEBROWS, ///< Eyebrows. WID_SCMF_EYEBROWS_R, ///< Eyebrows right. WID_SCMF_LIPS_MOUSTACHE_L, ///< Lips / Moustache left. WID_SCMF_LIPS_MOUSTACHE, ///< Lips / Moustache. WID_SCMF_LIPS_MOUSTACHE_R, ///< Lips / Moustache right. WID_SCMF_NOSE_L, ///< Nose left. WID_SCMF_NOSE, ///< Nose. WID_SCMF_NOSE_R, ///< Nose right. WID_SCMF_HAIR_L, ///< Hair left. WID_SCMF_HAIR, ///< Hair. WID_SCMF_HAIR_R, ///< Hair right. WID_SCMF_JACKET_L, ///< Jacket left. WID_SCMF_JACKET, ///< Jacket. WID_SCMF_JACKET_R, ///< Jacket right. WID_SCMF_COLLAR_L, ///< Collar left. WID_SCMF_COLLAR, ///< Collar. WID_SCMF_COLLAR_R, ///< Collar right. WID_SCMF_TIE_EARRING_L, ///< Tie / Earring left. WID_SCMF_TIE_EARRING, ///< Tie / Earring. WID_SCMF_TIE_EARRING_R, ///< Tie / Earring right. WID_SCMF_GLASSES_L, ///< Glasses left. WID_SCMF_GLASSES, ///< Glasses. WID_SCMF_GLASSES_R, ///< Glasses right. }; /** Widgets of the #CompanyInfrastructureWindow class. */ enum CompanyInfrastructureWidgets { WID_CI_CAPTION, ///< Caption of window. WID_CI_RAIL_DESC, ///< Description of rail. WID_CI_RAIL_COUNT, ///< Count of rail. WID_CI_ROAD_DESC, ///< Description of road. WID_CI_ROAD_COUNT, ///< Count of road. WID_CI_WATER_DESC, ///< Description of water. WID_CI_WATER_COUNT, ///< Count of water. WID_CI_STATION_DESC, ///< Description of station. WID_CI_STATION_COUNT, ///< Count of station. WID_CI_TOTAL_DESC, ///< Description of total. WID_CI_TOTAL, ///< Count of total. }; /** Widgets of the #BuyCompanyWindow class. */ enum BuyCompanyWidgets { WID_BC_CAPTION, ///< Caption of window. WID_BC_FACE, ///< Face button. WID_BC_QUESTION, ///< Question text. WID_BC_NO, ///< No button. WID_BC_YES, ///< Yes button. }; #endif /* WIDGETS_COMPANY_WIDGET_H */ openttd-1.5.3/src/widgets/viewport_widget.h0000644000000000000000000000231412627373434017536 0ustar rootroot/* $Id: viewport_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 viewport_widget.h Types related to the viewport widgets. */ #ifndef WIDGETS_VIEWPORT_WIDGET_H #define WIDGETS_VIEWPORT_WIDGET_H /** Widgets of the #ExtraViewportWindow class. */ enum ExtraViewportWidgets { WID_EV_CAPTION, ///< Caption of window. WID_EV_VIEWPORT, ///< The viewport. WID_EV_ZOOM_IN, ///< Zoom in. WID_EV_ZOOM_OUT, ///< Zoom out. WID_EV_MAIN_TO_VIEW, ///< Center the view of this viewport on the main view. WID_EV_VIEW_TO_MAIN, ///< Center the main view on the view of this viewport. }; #endif /* WIDGETS_VIEWPORT_WIDGET_H */ openttd-1.5.3/src/widgets/network_widget.h0000644000000000000000000001353712627373434017361 0ustar rootroot/* $Id: network_widget.h 24769 2012-11-27 21:35:52Z frosch $ */ /* * 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 network_widget.h Types related to the network widgets. */ #ifndef WIDGETS_NETWORK_WIDGET_H #define WIDGETS_NETWORK_WIDGET_H /** Widgets of the #NetworkGameWindow class. */ enum NetworkGameWidgets { WID_NG_MAIN, ///< Main panel. WID_NG_CONNECTION, ///< Label in front of connection droplist. WID_NG_CONN_BTN, ///< 'Connection' droplist button. WID_NG_CLIENT_LABEL, ///< Label in front of client name edit box. WID_NG_CLIENT, ///< Panel with editbox to set client name. WID_NG_FILTER_LABEL, ///< Label in front of the filter/search edit box. WID_NG_FILTER, ///< Panel with the edit box to enter the search text. WID_NG_HEADER, ///< Header container of the matrix. WID_NG_NAME, ///< 'Name' button. WID_NG_CLIENTS, ///< 'Clients' button. WID_NG_MAPSIZE, ///< 'Map size' button. WID_NG_DATE, ///< 'Date' button. WID_NG_YEARS, ///< 'Years' button. WID_NG_INFO, ///< Third button in the game list panel. WID_NG_MATRIX, ///< Panel with list of games. WID_NG_SCROLLBAR, ///< Scrollbar of matrix. WID_NG_LASTJOINED_LABEL, ///< Label "Last joined server:". WID_NG_LASTJOINED, ///< Info about the last joined server. WID_NG_LASTJOINED_SPACER, ///< Spacer after last joined server panel. WID_NG_DETAILS, ///< Panel with game details. WID_NG_DETAILS_SPACER, ///< Spacer for game actual details. WID_NG_JOIN, ///< 'Join game' button. WID_NG_REFRESH, ///< 'Refresh server' button. WID_NG_NEWGRF, ///< 'NewGRF Settings' button. WID_NG_NEWGRF_SEL, ///< Selection 'widget' to hide the NewGRF settings. WID_NG_NEWGRF_MISSING, ///< 'Find missing NewGRF online' button. WID_NG_NEWGRF_MISSING_SEL, ///< Selection widget for the above button. WID_NG_FIND, ///< 'Find server' button. WID_NG_ADD, ///< 'Add server' button. WID_NG_START, ///< 'Start server' button. WID_NG_CANCEL, ///< 'Cancel' button. }; /** Widgets of the #NetworkStartServerWindow class. */ enum NetworkStartServerWidgets { WID_NSS_BACKGROUND, ///< Background of the window. WID_NSS_GAMENAME_LABEL, ///< Label for the game name. WID_NSS_GAMENAME, ///< Background for editbox to set game name. WID_NSS_SETPWD, ///< 'Set password' button. WID_NSS_CONNTYPE_LABEL, ///< Label for 'connection type'. WID_NSS_CONNTYPE_BTN, ///< 'Connection type' droplist button. WID_NSS_CLIENTS_LABEL, ///< Label for 'max clients'. WID_NSS_CLIENTS_BTND, ///< 'Max clients' downarrow. WID_NSS_CLIENTS_TXT, ///< 'Max clients' text. WID_NSS_CLIENTS_BTNU, ///< 'Max clients' uparrow. WID_NSS_COMPANIES_LABEL, ///< Label for 'max companies'. WID_NSS_COMPANIES_BTND, ///< 'Max companies' downarrow. WID_NSS_COMPANIES_TXT, ///< 'Max companies' text. WID_NSS_COMPANIES_BTNU, ///< 'Max companies' uparrow. WID_NSS_SPECTATORS_LABEL, ///< Label for 'max spectators'. WID_NSS_SPECTATORS_BTND, ///< 'Max spectators' downarrow. WID_NSS_SPECTATORS_TXT, ///< 'Max spectators' text. WID_NSS_SPECTATORS_BTNU, ///< 'Max spectators' uparrow. WID_NSS_LANGUAGE_LABEL, ///< Label for 'language spoken'. WID_NSS_LANGUAGE_BTN, ///< 'Language spoken' droplist button. WID_NSS_GENERATE_GAME, ///< New game button. WID_NSS_LOAD_GAME, ///< Load game button. WID_NSS_PLAY_SCENARIO, ///< Play scenario button. WID_NSS_PLAY_HEIGHTMAP, ///< Play heightmap button. WID_NSS_CANCEL, ///< 'Cancel' button. }; /** Widgets of the #NetworkLobbyWindow class. */ enum NetworkLobbyWidgets { WID_NL_BACKGROUND, ///< Background of the window. WID_NL_TEXT, ///< Heading text. WID_NL_HEADER, ///< Header above list of companies. WID_NL_MATRIX, ///< List of companies. WID_NL_SCROLLBAR, ///< Scroll bar. WID_NL_DETAILS, ///< Company details. WID_NL_JOIN, ///< 'Join company' button. WID_NL_NEW, ///< 'New company' button. WID_NL_SPECTATE, ///< 'Spectate game' button. WID_NL_REFRESH, ///< 'Refresh server' button. WID_NL_CANCEL, ///< 'Cancel' button. }; /** Widgets of the #NetworkClientListWindow class. */ enum ClientListWidgets { WID_CL_PANEL, ///< Panel of the window. }; /** Widgets of the #NetworkClientListPopupWindow class. */ enum ClientListPopupWidgets { WID_CLP_PANEL, ///< Panel of the window. }; /** Widgets of the #NetworkJoinStatusWindow class. */ enum NetworkJoinStatusWidgets { WID_NJS_BACKGROUND, ///< Background of the window. WID_NJS_CANCELOK, ///< Cancel / OK button. }; /** Widgets of the #NetworkCompanyPasswordWindow class. */ enum NetworkCompanyPasswordWidgets { WID_NCP_BACKGROUND, ///< Background of the window. WID_NCP_LABEL, ///< Label in front of the password field. WID_NCP_PASSWORD, ///< Input field for the password. WID_NCP_SAVE_AS_DEFAULT_PASSWORD, ///< Toggle 'button' for saving the current password as default password. WID_NCP_CANCEL, ///< Close the window without changing anything. WID_NCP_OK, ///< Safe the password etc. }; #endif /* WIDGETS_NETWORK_WIDGET_H */ openttd-1.5.3/src/widgets/story_widget.h0000644000000000000000000000215712627373434017044 0ustar rootroot /* $Id: story_widget.h 26442 2014-04-03 10:54:37Z planetmaker $ */ /* * 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 story_widget.h Types related to the story widgets. */ #ifndef WIDGETS_STORY_WIDGET_H #define WIDGETS_STORY_WIDGET_H /** Widgets of the #GoalListWindow class. */ enum StoryBookWidgets { WID_SB_CAPTION, ///< Caption of the window. WID_SB_SEL_PAGE, ///< Page selector. WID_SB_PAGE_PANEL,///< Page body. WID_SB_SCROLLBAR, ///< Scrollbar of the goal list. WID_SB_PREV_PAGE, ///< Prev button. WID_SB_NEXT_PAGE, ///< Next button. }; #endif /* WIDGETS_STORY_WIDGET_H */ openttd-1.5.3/src/widgets/airport_widget.h0000644000000000000000000000340412627373434017340 0ustar rootroot/* $Id: airport_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 airport_widget.h Types related to the airport widgets. */ #ifndef WIDGETS_AIRPORT_WIDGET_H #define WIDGETS_AIRPORT_WIDGET_H /** Widgets of the #BuildAirToolbarWindow class. */ enum AirportToolbarWidgets { WID_AT_AIRPORT, ///< Build airport button. WID_AT_DEMOLISH, ///< Demolish button. }; /** Widgets of the #BuildAirportWindow class. */ enum AirportPickerWidgets { WID_AP_CLASS_DROPDOWN, ///< Dropdown of airport classes. WID_AP_AIRPORT_LIST, ///< List of airports. WID_AP_SCROLLBAR, ///< Scrollbar of the list. WID_AP_LAYOUT_NUM, ///< Current number of the layout. WID_AP_LAYOUT_DECREASE, ///< Decrease the layout number. WID_AP_LAYOUT_INCREASE, ///< Increase the layout number. WID_AP_AIRPORT_SPRITE, ///< A visual display of the airport currently selected. WID_AP_EXTRA_TEXT, ///< Additional text about the airport. WID_AP_BOTTOMPANEL, ///< Panel at the bottom. WID_AP_COVERAGE_LABEL, ///< Label if you want to see the coverage. WID_AP_BTN_DONTHILIGHT, ///< Don't show the coverage button. WID_AP_BTN_DOHILIGHT, ///< Show the coverage button. }; #endif /* WIDGETS_AIRPORT_WIDGET_H */ openttd-1.5.3/src/widgets/date_widget.h0000644000000000000000000000204412627373434016574 0ustar rootroot/* $Id: date_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 date_widget.h Types related to the date widgets. */ #ifndef WIDGETS_DATE_WIDGET_H #define WIDGETS_DATE_WIDGET_H /** Widgets of the #SetDateWindow class. */ enum SetDateWidgets { WID_SD_DAY, ///< Dropdown for the day. WID_SD_MONTH, ///< Dropdown for the month. WID_SD_YEAR, ///< Dropdown for the year. WID_SD_SET_DATE, ///< Actually set the date. }; #endif /* WIDGETS_DATE_WIDGET_H */ openttd-1.5.3/src/widgets/depot_widget.h0000644000000000000000000000331212627373434016771 0ustar rootroot/* $Id: depot_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 depot_widget.h Types related to the depot widgets. */ #ifndef WIDGETS_DEPOT_WIDGET_H #define WIDGETS_DEPOT_WIDGET_H /** Widgets of the #DepotWindow class. */ enum DepotWidgets { WID_D_CAPTION, ///< Caption of window. WID_D_SELL, ///< Sell button. WID_D_SHOW_SELL_CHAIN, ///< Show sell chain panel. WID_D_SELL_CHAIN, ///< Sell chain button. WID_D_SELL_ALL, ///< Sell all button. WID_D_AUTOREPLACE, ///< Autoreplace button. WID_D_MATRIX, ///< Matrix of vehicles. WID_D_V_SCROLL, ///< Vertical scrollbar. WID_D_SHOW_H_SCROLL, ///< Show horizontal scrollbar panel. WID_D_H_SCROLL, ///< Horizontal scrollbar. WID_D_BUILD, ///< Build button. WID_D_CLONE, ///< Clone button. WID_D_LOCATION, ///< Location button. WID_D_SHOW_RENAME, ///< Show rename panel. WID_D_RENAME, ///< Rename button. WID_D_VEHICLE_LIST, ///< List of vehicles. WID_D_STOP_ALL, ///< Stop all button. WID_D_START_ALL, ///< Start all button. }; #endif /* WIDGETS_DEPOT_WIDGET_H */ openttd-1.5.3/src/widgets/link_graph_legend_widget.h0000644000000000000000000000301412627373434021311 0ustar rootroot/* $Id: link_graph_legend_widget.h 25331 2013-06-08 12:37:36Z zuu $ */ /* * 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 link_graph_legend_widget.h Types related to the linkgraph_legend widgets. */ #ifndef WIDGETS_LINKGRAPH_LEGEND_WIDGET_H #define WIDGETS_LINKGRAPH_LEGEND_WIDGET_H #include "../cargo_type.h" /** Widgets of the WC_LINKGRAPH_LEGEND. */ enum LinkGraphLegendWidgets { WID_LGL_CAPTION, ///< Caption widget. WID_LGL_SATURATION, ///< Saturation legend. WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST = WID_LGL_SATURATION_FIRST + 11, WID_LGL_COMPANIES, ///< Company selection widget. WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST = WID_LGL_COMPANY_FIRST + MAX_COMPANIES - 1, WID_LGL_COMPANIES_ALL, WID_LGL_COMPANIES_NONE, WID_LGL_CARGOES, ///< Cargo selection widget. WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST = WID_LGL_CARGO_FIRST + NUM_CARGO - 1, WID_LGL_CARGOES_ALL, WID_LGL_CARGOES_NONE, }; #endif /* WIDGETS_LINKGRAPH_LEGEND_WIDGET_H */ openttd-1.5.3/src/widgets/road_widget.h0000644000000000000000000000526712627373434016616 0ustar rootroot/* $Id: road_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 road_widget.h Types related to the road widgets. */ #ifndef WIDGETS_ROAD_WIDGET_H #define WIDGETS_ROAD_WIDGET_H /** Widgets of the #BuildRoadToolbarWindow class. */ enum RoadToolbarWidgets { /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ WID_ROT_ROAD_X, ///< Build road in x-direction. WID_ROT_ROAD_Y, ///< Build road in y-direction. WID_ROT_AUTOROAD, ///< Autorail. WID_ROT_DEMOLISH, ///< Demolish. WID_ROT_DEPOT, ///< Build depot. WID_ROT_BUS_STATION, ///< Build bus station. WID_ROT_TRUCK_STATION, ///< Build truck station. WID_ROT_ONE_WAY, ///< Build one-way road. WID_ROT_BUILD_BRIDGE, ///< Build bridge. WID_ROT_BUILD_TUNNEL, ///< Build tunnel. WID_ROT_REMOVE, ///< Remove road. }; /** Widgets of the #BuildRoadDepotWindow class. */ enum BuildRoadDepotWidgets { /* Name starts with BRO instead of BR, because of collision with BuildRailDepotWidgets */ WID_BROD_CAPTION, ///< Caption of the window. WID_BROD_DEPOT_NE, ///< Depot with NE entry. WID_BROD_DEPOT_SE, ///< Depot with SE entry. WID_BROD_DEPOT_SW, ///< Depot with SW entry. WID_BROD_DEPOT_NW, ///< Depot with NW entry. }; /** Widgets of the #BuildRoadStationWindow class. */ enum BuildRoadStationWidgets { /* Name starts with BRO instead of BR, because of collision with BuildRailStationWidgets */ WID_BROS_CAPTION, ///< Caption of the window. WID_BROS_BACKGROUND, ///< Background of the window. WID_BROS_STATION_NE, ///< Terminal station with NE entry. WID_BROS_STATION_SE, ///< Terminal station with SE entry. WID_BROS_STATION_SW, ///< Terminal station with SW entry. WID_BROS_STATION_NW, ///< Terminal station with NW entry. WID_BROS_STATION_X, ///< Drive-through station in x-direction. WID_BROS_STATION_Y, ///< Drive-through station in y-direction. WID_BROS_LT_OFF, ///< Turn off area highlight. WID_BROS_LT_ON, ///< Turn on area highlight. WID_BROS_INFO, ///< Station acceptance info. }; #endif /* WIDGETS_ROAD_WIDGET_H */ openttd-1.5.3/src/widgets/rail_widget.h0000644000000000000000000001467412627373434016622 0ustar rootroot/* $Id: rail_widget.h 25464 2013-06-25 20:22:08Z frosch $ */ /* * 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 rail_widget.h Types related to the rail widgets. */ #ifndef WIDGETS_RAIL_WIDGET_H #define WIDGETS_RAIL_WIDGET_H /** Widgets of the #BuildRailToolbarWindow class. */ enum RailToolbarWidgets { /* Name starts with RA instead of R, because of collision with RoadToolbarWidgets */ WID_RAT_CAPTION, ///< Caption of the window. WID_RAT_BUILD_NS, ///< Build rail along the game view Y axis. WID_RAT_BUILD_X, ///< Build rail along the game grid X axis. WID_RAT_BUILD_EW, ///< Build rail along the game view X axis. WID_RAT_BUILD_Y, ///< Build rail along the game grid Y axis. WID_RAT_AUTORAIL, ///< Autorail tool. WID_RAT_DEMOLISH, ///< Destroy something with dynamite! WID_RAT_BUILD_DEPOT, ///< Build a depot. WID_RAT_BUILD_WAYPOINT, ///< Build a waypoint. WID_RAT_BUILD_STATION, ///< Build a station. WID_RAT_BUILD_SIGNALS, ///< Build signals. WID_RAT_BUILD_BRIDGE, ///< Build a bridge. WID_RAT_BUILD_TUNNEL, ///< Build a tunnel. WID_RAT_REMOVE, ///< Bulldozer to remove rail. WID_RAT_CONVERT_RAIL, ///< Convert other rail to this type. }; /** Widgets of the #BuildRailStationWindow class. */ enum BuildRailStationWidgets { /* Name starts with BRA instead of BR, because of collision with BuildRoadStationWidgets */ WID_BRAS_PLATFORM_DIR_X, ///< Button to select '/' view. WID_BRAS_PLATFORM_DIR_Y, ///< Button to select '\' view. WID_BRAS_PLATFORM_NUM_1, ///< Button to select stations with a single platform. WID_BRAS_PLATFORM_NUM_2, ///< Button to select stations with 2 platforms. WID_BRAS_PLATFORM_NUM_3, ///< Button to select stations with 3 platforms. WID_BRAS_PLATFORM_NUM_4, ///< Button to select stations with 4 platforms. WID_BRAS_PLATFORM_NUM_5, ///< Button to select stations with 5 platforms. WID_BRAS_PLATFORM_NUM_6, ///< Button to select stations with 6 platforms. WID_BRAS_PLATFORM_NUM_7, ///< Button to select stations with 7 platforms. WID_BRAS_PLATFORM_LEN_1, ///< Button to select single tile length station platforms. WID_BRAS_PLATFORM_LEN_2, ///< Button to select 2 tiles length station platforms. WID_BRAS_PLATFORM_LEN_3, ///< Button to select 3 tiles length station platforms. WID_BRAS_PLATFORM_LEN_4, ///< Button to select 4 tiles length station platforms. WID_BRAS_PLATFORM_LEN_5, ///< Button to select 5 tiles length station platforms. WID_BRAS_PLATFORM_LEN_6, ///< Button to select 6 tiles length station platforms. WID_BRAS_PLATFORM_LEN_7, ///< Button to select 7 tiles length station platforms. WID_BRAS_PLATFORM_DRAG_N_DROP, ///< Button to enable drag and drop type station placement. WID_BRAS_HIGHLIGHT_OFF, ///< Button for turning coverage highlighting off. WID_BRAS_HIGHLIGHT_ON, ///< Button for turning coverage highlighting on. WID_BRAS_COVERAGE_TEXTS, ///< Empty space for the coverage texts. WID_BRAS_MATRIX, ///< Matrix widget displaying the available stations. WID_BRAS_IMAGE, ///< Panel used at each cell of the matrix. WID_BRAS_MATRIX_SCROLL, ///< Scrollbar of the matrix widget. WID_BRAS_SHOW_NEWST_DEFSIZE, ///< Selection for default-size button for newstation. WID_BRAS_SHOW_NEWST_ADDITIONS, ///< Selection for newstation class selection list. WID_BRAS_SHOW_NEWST_MATRIX, ///< Selection for newstation image matrix. WID_BRAS_SHOW_NEWST_RESIZE, ///< Selection for panel and resize at bottom right for newstation. WID_BRAS_SHOW_NEWST_TYPE, ///< Display of selected station type. WID_BRAS_NEWST_LIST, ///< List with available newstation classes. WID_BRAS_NEWST_SCROLL, ///< Scrollbar of the #WID_BRAS_NEWST_LIST. WID_BRAS_PLATFORM_NUM_BEGIN = WID_BRAS_PLATFORM_NUM_1 - 1, ///< Helper for determining the chosen platform width. WID_BRAS_PLATFORM_LEN_BEGIN = WID_BRAS_PLATFORM_LEN_1 - 1, ///< Helper for determining the chosen platform length. }; /** Widgets of the #BuildSignalWindow class. */ enum BuildSignalWidgets { WID_BS_SEMAPHORE_NORM, ///< Build a semaphore normal block signal WID_BS_SEMAPHORE_ENTRY, ///< Build a semaphore entry block signal WID_BS_SEMAPHORE_EXIT, ///< Build a semaphore exit block signal WID_BS_SEMAPHORE_COMBO, ///< Build a semaphore combo block signal WID_BS_SEMAPHORE_PBS, ///< Build a semaphore path signal. WID_BS_SEMAPHORE_PBS_OWAY, ///< Build a semaphore one way path signal. WID_BS_ELECTRIC_NORM, ///< Build an electric normal block signal WID_BS_ELECTRIC_ENTRY, ///< Build an electric entry block signal WID_BS_ELECTRIC_EXIT, ///< Build an electric exit block signal WID_BS_ELECTRIC_COMBO, ///< Build an electric combo block signal WID_BS_ELECTRIC_PBS, ///< Build an electric path signal. WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal. WID_BS_CONVERT, ///< Convert the signal. WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density. WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density. WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density. }; /** Widgets of the #BuildRailDepotWindow class. */ enum BuildRailDepotWidgets { /* Name starts with BRA instead of BR, because of collision with BuildRoadDepotWidgets */ WID_BRAD_DEPOT_NE, ///< Build a depot with the entrance in the north east. WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east. WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west. WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west. }; /** Widgets of the #BuildRailWaypointWindow class. */ enum BuildRailWaypointWidgets { WID_BRW_WAYPOINT_MATRIX, ///< Matrix with waypoints. WID_BRW_WAYPOINT, ///< A single waypoint. WID_BRW_SCROLL, ///< Scrollbar for the matrix. }; #endif /* WIDGETS_RAIL_WIDGET_H */ openttd-1.5.3/src/widgets/network_chat_widget.h0000644000000000000000000000216112627373434020347 0ustar rootroot/* $Id: network_chat_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 network_chat_widget.h Types related to the network chat widgets. */ #ifndef WIDGETS_NETWORK_CHAT_WIDGET_H #define WIDGETS_NETWORK_CHAT_WIDGET_H /** Widgets of the #NetworkChatWindow class. */ enum NetWorkChatWidgets { WID_NC_CLOSE, ///< Close button. WID_NC_BACKGROUND, ///< Background of the window. WID_NC_DESTINATION, ///< Destination. WID_NC_TEXTBOX, ///< Textbox. WID_NC_SENDBUTTON, ///< Send button. }; #endif /* WIDGETS_NETWORK_CHAT_WIDGET_H */ openttd-1.5.3/src/widgets/dropdown_func.h0000644000000000000000000000216012627373434017162 0ustar rootroot/* $Id: dropdown_func.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 dropdown_func.h Functions related to the drop down widget. */ #ifndef WIDGETS_DROPDOWN_FUNC_H #define WIDGETS_DROPDOWN_FUNC_H #include "../window_gui.h" /* Show drop down menu containing a fixed list of strings */ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask, uint width = 0); /* Hide drop down menu of a parent window */ int HideDropDownMenu(Window *pw); #endif /* WIDGETS_DROPDOWN_FUNC_H */ openttd-1.5.3/src/widgets/main_widget.h0000644000000000000000000000162212627373434016604 0ustar rootroot/* $Id: main_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 main_widget.h Types related to the main widgets. */ #ifndef WIDGETS_MAIN_WIDGET_H #define WIDGETS_MAIN_WIDGET_H /** Widgets of the #MainWindow class. */ enum MainWidgets { WID_M_VIEWPORT, ///< Main window viewport. }; #endif /* WIDGETS_MAIN_WIDGET_H */ openttd-1.5.3/src/widgets/sign_widget.h0000644000000000000000000000325112627373434016620 0ustar rootroot/* $Id: sign_widget.h 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 sign_widget.h Types related to the sign widgets. */ #ifndef WIDGETS_SIGN_WIDGET_H #define WIDGETS_SIGN_WIDGET_H /** Widgets of the #SignListWindow class. */ enum SignListWidgets { /* Name starts with SI instead of S, because of collision with SaveLoadWidgets */ WID_SIL_CAPTION, ///< Caption of the window. WID_SIL_LIST, ///< List of signs. WID_SIL_SCROLLBAR, ///< Scrollbar of list. WID_SIL_FILTER_TEXT, ///< Text box for typing a filter string. WID_SIL_FILTER_MATCH_CASE_BTN, ///< Button to toggle if case sensitive filtering should be used. WID_SIL_FILTER_ENTER_BTN, ///< Scroll to first sign. }; /** Widgets of the #SignWindow class. */ enum QueryEditSignWidgets { WID_QES_CAPTION, ///< Caption of the window. WID_QES_TEXT, ///< Text of the query. WID_QES_OK, ///< OK button. WID_QES_CANCEL, ///< Cancel button. WID_QES_DELETE, ///< Delete button. WID_QES_PREVIOUS, ///< Previous button. WID_QES_NEXT, ///< Next button. }; #endif /* SIGN_WIDGET_H */ openttd-1.5.3/src/widgets/waypoint_widget.h0000644000000000000000000000224612627373434017535 0ustar rootroot/* $Id: waypoint_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 waypoint_widget.h Types related to the waypoint widgets. */ #ifndef WIDGETS_WAYPOINT_WIDGET_H #define WIDGETS_WAYPOINT_WIDGET_H /** Widgets of the #WaypointWindow class. */ enum WaypointWidgets { WID_W_CAPTION, ///< Caption of window. WID_W_VIEWPORT, ///< The viewport on this waypoint. WID_W_CENTER_VIEW, ///< Center the main view on this waypoint. WID_W_RENAME, ///< Rename this waypoint. WID_W_SHOW_VEHICLES, ///< Show the vehicles visiting this waypoint. }; #endif /* WIDGETS_WAYPOINT_WIDGET_H */ openttd-1.5.3/src/widgets/subsidy_widget.h0000644000000000000000000000206612627373434017345 0ustar rootroot/* $Id: subsidy_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 subsidy_widget.h Types related to the subsidy widgets. */ #ifndef WIDGETS_SUBSIDY_WIDGET_H #define WIDGETS_SUBSIDY_WIDGET_H /** Widgets of the #SubsidyListWindow class. */ enum SubsidyListWidgets { /* Name starts with SU instead of S, because of collision with SaveLoadWidgets. */ WID_SUL_PANEL, ///< Main panel of window. WID_SUL_SCROLLBAR, ///< Scrollbar of panel. }; #endif /* WIDGETS_SUBSIDY_WIDGET_H */ openttd-1.5.3/src/widgets/toolbar_widget.h0000644000000000000000000000752612627373434017333 0ustar rootroot/* $Id: toolbar_widget.h 25376 2013-06-09 13:37:04Z zuu $ */ /* * 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 toolbar_widget.h Types related to the toolbar widgets. */ #ifndef WIDGETS_TOOLBAR_WIDGET_H #define WIDGETS_TOOLBAR_WIDGET_H /** Widgets of the #MainToolbarWindow class. */ enum ToolbarNormalWidgets { WID_TN_PAUSE, ///< Pause the game. WID_TN_FAST_FORWARD, ///< Fast forward the game. WID_TN_SETTINGS, ///< Settings menu. WID_TN_SAVE, ///< Save menu. WID_TN_SMALL_MAP, ///< Small map menu. WID_TN_TOWNS, ///< Town menu. WID_TN_SUBSIDIES, ///< Subsidy menu. WID_TN_STATIONS, ///< Station menu. WID_TN_FINANCES, ///< Finance menu. WID_TN_COMPANIES, ///< Company menu. WID_TN_STORY, ///< Story menu. WID_TN_GOAL, ///< Goal menu. WID_TN_GRAPHS, ///< Graph menu. WID_TN_LEAGUE, ///< Company league menu. WID_TN_INDUSTRIES, ///< Industry menu. WID_TN_VEHICLE_START, ///< Helper for the offset of the vehicle menus. WID_TN_TRAINS = WID_TN_VEHICLE_START, ///< Train menu. WID_TN_ROADVEHS, ///< Road vehicle menu. WID_TN_SHIPS, ///< Ship menu. WID_TN_AIRCRAFTS, ///< Aircraft menu. WID_TN_ZOOM_IN, ///< Zoom in the main viewport. WID_TN_ZOOM_OUT, ///< Zoom out the main viewport. WID_TN_RAILS, ///< Rail building menu. WID_TN_ROADS, ///< Road building menu. WID_TN_WATER, ///< Water building toolbar. WID_TN_AIR, ///< Airport building toolbar. WID_TN_LANDSCAPE, ///< Landscaping toolbar. WID_TN_MUSIC_SOUND, ///< Music/sound configuration menu. WID_TN_MESSAGES, ///< Messages menu. WID_TN_HELP, ///< Help menu. WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. WID_TN_END, ///< Helper for knowing the amount of widgets. }; /** Widgets of the #ScenarioEditorToolbarWindow class. */ enum ToolbarEditorWidgets { WID_TE_PAUSE, ///< Pause the game. WID_TE_FAST_FORWARD, ///< Fast forward the game. WID_TE_SETTINGS, ///< Settings menu. WID_TE_SAVE, ///< Save menu. WID_TE_SPACER, ///< Spacer with "scenario editor" text. WID_TE_DATE, ///< The date of the scenario. WID_TE_DATE_BACKWARD, ///< Reduce the date of the scenario. WID_TE_DATE_FORWARD, ///< Increase the date of the scenario. WID_TE_SMALL_MAP, ///< Small map menu. WID_TE_ZOOM_IN, ///< Zoom in the main viewport. WID_TE_ZOOM_OUT, ///< Zoom out the main viewport. WID_TE_LAND_GENERATE, ///< Land generation. WID_TE_TOWN_GENERATE, ///< Town building window. WID_TE_INDUSTRY, ///< Industry building window. WID_TE_ROADS, ///< Road building menu. WID_TE_WATER, ///< Water building toolbar. WID_TE_TREES, ///< Tree building toolbar. WID_TE_SIGNS, ///< Sign building. WID_TE_DATE_PANEL, ///< Container for the date widgets. /* The following three need to have the same actual widget number as the normal toolbar due to shared code. */ WID_TE_MUSIC_SOUND = WID_TN_MUSIC_SOUND, ///< Music/sound configuration menu. WID_TE_HELP = WID_TN_HELP, ///< Help menu. WID_TE_SWITCH_BAR = WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. }; #endif /* WIDGETS_TOOLBAR_WIDGET_H */ openttd-1.5.3/src/widgets/music_widget.h0000644000000000000000000000414512627373434017003 0ustar rootroot/* $Id: music_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 music_widget.h Types related to the music widgets. */ #ifndef WIDGETS_MUSIC_WIDGET_H #define WIDGETS_MUSIC_WIDGET_H /** Widgets of the #MusicTrackSelectionWindow class. */ enum MusicTrackSelectionWidgets { WID_MTS_LIST_LEFT, ///< Left button. WID_MTS_PLAYLIST, ///< Playlist. WID_MTS_LIST_RIGHT, ///< Right button. WID_MTS_ALL, ///< All button. WID_MTS_OLD, ///< Old button. WID_MTS_NEW, ///< New button. WID_MTS_EZY, ///< Ezy button. WID_MTS_CUSTOM1, ///< Custom1 button. WID_MTS_CUSTOM2, ///< Custom2 button. WID_MTS_CLEAR, ///< Clear button. }; /** Widgets of the #MusicWindow class. */ enum MusicWidgets { WID_M_PREV, ///< Previous button. WID_M_NEXT, ///< Next button. WID_M_STOP, ///< Stop button. WID_M_PLAY, ///< Play button. WID_M_SLIDERS, ///< Sliders. WID_M_MUSIC_VOL, ///< Music volume. WID_M_EFFECT_VOL, ///< Effect volume. WID_M_BACKGROUND, ///< Background of the window. WID_M_TRACK, ///< Track playing. WID_M_TRACK_NR, ///< Track number. WID_M_TRACK_TITLE, ///< Track title. WID_M_TRACK_NAME, ///< Track name. WID_M_SHUFFLE, ///< Shuffle button. WID_M_PROGRAMME, ///< Program button. WID_M_ALL, ///< All button. WID_M_OLD, ///< Old button. WID_M_NEW, ///< New button. WID_M_EZY, ///< Ezy button. WID_M_CUSTOM1, ///< Custom1 button. WID_M_CUSTOM2, ///< Custom2 button. }; #endif /* WIDGETS_MUSIC_WIDGET_H */ openttd-1.5.3/src/widgets/group_widget.h0000644000000000000000000000360112627373434017013 0ustar rootroot/* $Id: group_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 group_widget.h Types related to the group widgets. */ #ifndef WIDGETS_GROUP_WIDGET_H #define WIDGETS_GROUP_WIDGET_H /** Widgets of the #VehicleGroupWindow class. */ enum GroupListWidgets { WID_GL_CAPTION, ///< Caption of the window. WID_GL_SORT_BY_ORDER, ///< Sort order. WID_GL_SORT_BY_DROPDOWN, ///< Sort by dropdown list. WID_GL_LIST_VEHICLE, ///< List of the vehicles. WID_GL_LIST_VEHICLE_SCROLLBAR, ///< Scrollbar for the list. WID_GL_AVAILABLE_VEHICLES, ///< Available vehicles. WID_GL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. WID_GL_STOP_ALL, ///< Stop all button. WID_GL_START_ALL, ///< Start all button. WID_GL_ALL_VEHICLES, ///< All vehicles entry. WID_GL_DEFAULT_VEHICLES, ///< Default vehicles entry. WID_GL_LIST_GROUP, ///< List of the groups. WID_GL_LIST_GROUP_SCROLLBAR, ///< Scrollbar for the list. WID_GL_CREATE_GROUP, ///< Create group button. WID_GL_DELETE_GROUP, ///< Delete group button. WID_GL_RENAME_GROUP, ///< Rename group button. WID_GL_REPLACE_PROTECTION, ///< Replace protection button. }; #endif /* WIDGETS_GROUP_WIDGET_H */ openttd-1.5.3/src/widgets/dropdown_type.h0000644000000000000000000000676712627373434017231 0ustar rootroot/* $Id: dropdown_type.h 26088 2013-11-24 15:17:53Z rubidium $ */ /* * 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 dropdown_type.h Types related to the drop down widget. */ #ifndef WIDGETS_DROPDOWN_TYPE_H #define WIDGETS_DROPDOWN_TYPE_H #include "../window_type.h" #include "../gfx_func.h" #include "../core/smallvec_type.hpp" #include "table/strings.h" /** * Base list item class from which others are derived. If placed in a list it * will appear as a horizontal line in the menu. */ class DropDownListItem { public: int result; ///< Result code to return to window on selection bool masked; ///< Masked and unselectable item DropDownListItem(int result, bool masked) : result(result), masked(masked) {} virtual ~DropDownListItem() {} virtual bool Selectable() const { return false; } virtual uint Height(uint width) const { return FONT_HEIGHT_NORMAL; } virtual uint Width() const { return 0; } virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const; }; /** * Common string list item. */ class DropDownListStringItem : public DropDownListItem { public: StringID string; ///< String ID of item DropDownListStringItem(StringID string, int result, bool masked) : DropDownListItem(result, masked), string(string) {} virtual ~DropDownListStringItem() {} virtual bool Selectable() const { return true; } virtual uint Width() const; virtual void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const; virtual StringID String() const { return this->string; } static int CDECL NatSortFunc(const DropDownListItem * const *first, const DropDownListItem * const *second); }; /** * String list item with parameters. */ class DropDownListParamStringItem : public DropDownListStringItem { public: uint64 decode_params[10]; ///< Parameters of the string DropDownListParamStringItem(StringID string, int result, bool masked) : DropDownListStringItem(string, result, masked) {} virtual ~DropDownListParamStringItem() {} virtual StringID String() const; virtual void SetParam(uint index, uint64 value) { decode_params[index] = value; } }; /** * List item containing a C char string. */ class DropDownListCharStringItem : public DropDownListStringItem { public: const char *raw_string; DropDownListCharStringItem(const char *raw_string, int result, bool masked) : DropDownListStringItem(STR_JUST_RAW_STRING, result, masked), raw_string(raw_string) {} virtual ~DropDownListCharStringItem() {} virtual StringID String() const; }; /** * A drop down list is a collection of drop down list items. */ typedef AutoDeleteSmallVector DropDownList; void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width = false, bool instant_close = false); void ShowDropDownList(Window *w, const DropDownList *list, int selected, int button, uint width = 0, bool auto_width = false, bool instant_close = false); #endif /* WIDGETS_DROPDOWN_TYPE_H */ openttd-1.5.3/src/widgets/console_widget.h0000644000000000000000000000166212627373434017326 0ustar rootroot/* $Id: console_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 console_widget.h Types related to the console widgets. */ #ifndef WIDGETS_CONSOLE_WIDGET_H #define WIDGETS_CONSOLE_WIDGET_H /** Widgets of the #IConsoleWindow class. */ enum ConsoleWidgets { WID_C_BACKGROUND, ///< Background of the console. }; #endif /* WIDGETS_CONSOLE_WIDGET_H */ openttd-1.5.3/src/widgets/town_widget.h0000644000000000000000000000620312627373434016647 0ustar rootroot/* $Id: town_widget.h 25094 2013-03-17 15:41:40Z alberth $ */ /* * 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 town_widget.h Types related to the town widgets. */ #ifndef WIDGETS_TOWN_WIDGET_H #define WIDGETS_TOWN_WIDGET_H /** Widgets of the #TownDirectoryWindow class. */ enum TownDirectoryWidgets { WID_TD_SORT_ORDER, ///< Direction of sort dropdown. WID_TD_SORT_CRITERIA, ///< Criteria of sort dropdown. WID_TD_LIST, ///< List of towns. WID_TD_SCROLLBAR, ///< Scrollbar for the town list. WID_TD_WORLD_POPULATION, ///< The world's population. }; /** Widgets of the #TownAuthorityWindow class. */ enum TownAuthorityWidgets { WID_TA_CAPTION, ///< Caption of window. WID_TA_RATING_INFO, ///< Overview with ratings for each company. WID_TA_COMMAND_LIST, ///< List of commands for the player. WID_TA_SCROLLBAR, ///< Scrollbar of the list of commands. WID_TA_ACTION_INFO, ///< Additional information about the action. WID_TA_EXECUTE, ///< Do-it button. }; /** Widgets of the #TownViewWindow class. */ enum TownViewWidgets { WID_TV_CAPTION, ///< Caption of window. WID_TV_VIEWPORT, ///< View of the center of the town. WID_TV_INFO, ///< General information about the town. WID_TV_CENTER_VIEW, ///< Center the main view on this town. WID_TV_SHOW_AUTHORITY, ///< Show the town authority window. WID_TV_CHANGE_NAME, ///< Change the name of this town. WID_TV_EXPAND, ///< Expand this town (scenario editor only). WID_TV_DELETE, ///< Delete this town (scenario editor only). }; /** Widgets of the #FoundTownWindow class. */ enum TownFoundingWidgets { WID_TF_NEW_TOWN, ///< Create a new town. WID_TF_RANDOM_TOWN, ///< Randomly place a town. WID_TF_MANY_RANDOM_TOWNS, ///< Randomly place many towns. WID_TF_TOWN_NAME_EDITBOX, ///< Editor for the town name. WID_TF_TOWN_NAME_RANDOM, ///< Generate a random town name. WID_TF_SIZE_SMALL, ///< Selection for a small town. WID_TF_SIZE_MEDIUM, ///< Selection for a medium town. WID_TF_SIZE_LARGE, ///< Selection for a large town. WID_TF_SIZE_RANDOM, ///< Selection for a randomly sized town. WID_TF_CITY, ///< Selection for the town's city state. WID_TF_LAYOUT_ORIGINAL, ///< Selection for the original town layout. WID_TF_LAYOUT_BETTER, ///< Selection for the better town layout. WID_TF_LAYOUT_GRID2, ///< Selection for the 2x2 grid town layout. WID_TF_LAYOUT_GRID3, ///< Selection for the 3x3 grid town layout. WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout. }; #endif /* WIDGETS_TOWN_WIDGET_H */ openttd-1.5.3/src/widgets/fios_widget.h0000644000000000000000000000406112627373434016620 0ustar rootroot/* $Id: fios_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 fios_widget.h Types related to the fios widgets. */ #ifndef WIDGETS_FIOS_WIDGET_H #define WIDGETS_FIOS_WIDGET_H /** Widgets of the #SaveLoadWindow class. */ enum SaveLoadWidgets { WID_SL_CAPTION, ///< Caption of the window. WID_SL_SORT_BYNAME, ///< Sort by name button. WID_SL_SORT_BYDATE, ///< Sort by date button. WID_SL_BACKGROUND, ///< Background of window. WID_SL_FILE_BACKGROUND, ///< Background of file selection. WID_SL_HOME_BUTTON, ///< Home button. WID_SL_DRIVES_DIRECTORIES_LIST, ///< Drives list. WID_SL_SCROLLBAR, ///< Scrollbar of the file list. WID_SL_CONTENT_DOWNLOAD, ///< Content download button, only available for play scenario/heightmap. WID_SL_SAVE_OSK_TITLE, ///< Title textbox, only available for save operations. WID_SL_DELETE_SELECTION, ///< Delete button, only available for save operations. WID_SL_SAVE_GAME, ///< Save button, only available for save operations. WID_SL_CONTENT_DOWNLOAD_SEL, ///< Selection 'stack' to 'hide' the content download. WID_SL_DETAILS, ///< Panel with game details. WID_SL_NEWGRF_INFO, ///< Button to open NewGgrf configuration. WID_SL_LOAD_BUTTON, ///< Button to load game/scenario. WID_SL_MISSING_NEWGRFS, ///< Button to find missing NewGRFs online. }; #endif /* WIDGETS_FIOS_WIDGET_H */ openttd-1.5.3/src/widgets/genworld_widget.h0000644000000000000000000001041012627373434017474 0ustar rootroot/* $Id: genworld_widget.h 26885 2014-09-21 12:25:04Z rubidium $ */ /* * 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 genworld_widget.h Types related to the genworld widgets. */ #ifndef WIDGETS_GENWORLD_WIDGET_H #define WIDGETS_GENWORLD_WIDGET_H /** Widgets of the #GenerateLandscapeWindow class. */ enum GenerateLandscapeWidgets { WID_GL_TEMPERATE, ///< Button with icon "Temperate". WID_GL_ARCTIC, ///< Button with icon "Arctic". WID_GL_TROPICAL, ///< Button with icon "Tropical". WID_GL_TOYLAND, ///< Button with icon "Toyland". WID_GL_MAPSIZE_X_PULLDOWN, ///< Dropdown 'map X size'. WID_GL_MAPSIZE_Y_PULLDOWN, ///< Dropdown 'map Y size'. WID_GL_TOWN_PULLDOWN, ///< Dropdown 'No. of towns'. WID_GL_INDUSTRY_PULLDOWN, ///< Dropdown 'No. of industries'. WID_GL_GENERATE_BUTTON, ///< 'Generate' button. WID_GL_MAX_HEIGHTLEVEL_DOWN, ///< Decrease max. heightlevel WID_GL_MAX_HEIGHTLEVEL_TEXT, ///< Max. heightlevel WID_GL_MAX_HEIGHTLEVEL_UP, ///< Increase max. heightlevel WID_GL_START_DATE_DOWN, ///< Decrease start year. WID_GL_START_DATE_TEXT, ///< Start year. WID_GL_START_DATE_UP, ///< Increase start year. WID_GL_SNOW_LEVEL_DOWN, ///< Decrease snow level. WID_GL_SNOW_LEVEL_TEXT, ///< Snow level. WID_GL_SNOW_LEVEL_UP, ///< Increase snow level. WID_GL_TREE_PULLDOWN, ///< Dropdown 'Tree algorithm'. WID_GL_LANDSCAPE_PULLDOWN, ///< Dropdown 'Land generator'. WID_GL_HEIGHTMAP_NAME_TEXT, ///< Heightmap name. WID_GL_HEIGHTMAP_SIZE_TEXT, ///< Size of heightmap. WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, ///< Dropdown 'Heightmap rotation'. WID_GL_TERRAIN_PULLDOWN, ///< Dropdown 'Terrain type'. WID_GL_WATER_PULLDOWN, ///< Dropdown 'Sea level'. WID_GL_RIVER_PULLDOWN, ///< Dropdown 'Rivers'. WID_GL_SMOOTHNESS_PULLDOWN, ///< Dropdown 'Smoothness'. WID_GL_VARIETY_PULLDOWN, ///< Dropdown 'Variety distribution'. WID_GL_BORDERS_RANDOM, ///< 'Random'/'Manual' borders. WID_GL_WATER_NW, ///< NW 'Water'/'Freeform'. WID_GL_WATER_NE, ///< NE 'Water'/'Freeform'. WID_GL_WATER_SE, ///< SE 'Water'/'Freeform'. WID_GL_WATER_SW, ///< SW 'Water'/'Freeform'. }; /** Widgets of the #CreateScenarioWindow class. */ enum CreateScenarioWidgets { WID_CS_TEMPERATE, ///< Select temperate landscape style. WID_CS_ARCTIC, ///< Select arctic landscape style. WID_CS_TROPICAL, ///< Select tropical landscape style. WID_CS_TOYLAND, ///< Select toy-land landscape style. WID_CS_EMPTY_WORLD, ///< Generate an empty flat world. WID_CS_RANDOM_WORLD, ///< Generate random land button WID_CS_MAPSIZE_X_PULLDOWN, ///< Pull-down arrow for x map size. WID_CS_MAPSIZE_Y_PULLDOWN, ///< Pull-down arrow for y map size. WID_CS_START_DATE_DOWN, ///< Decrease start year (start earlier). WID_CS_START_DATE_TEXT, ///< Clickable start date value. WID_CS_START_DATE_UP, ///< Increase start year (start later). WID_CS_FLAT_LAND_HEIGHT_DOWN, ///< Decrease flat land height. WID_CS_FLAT_LAND_HEIGHT_TEXT, ///< Clickable flat land height value. WID_CS_FLAT_LAND_HEIGHT_UP, ///< Increase flat land height. }; /** Widgets of the #GenerateProgressWindow class. */ enum GenerationProgressWidgets { WID_GP_PROGRESS_BAR, ///< Progress bar. WID_GP_PROGRESS_TEXT, ///< Text with the progress bar. WID_GP_ABORT, ///< Abort button. }; #endif /* WIDGETS_GENWORLD_WIDGET_H */ openttd-1.5.3/src/widgets/build_vehicle_widget.h0000644000000000000000000000323212627373434020455 0ustar rootroot/* $Id: build_vehicle_widget.h 26811 2014-09-11 17:10:38Z alberth $ */ /* * 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 build_vehicle_widget.h Types related to the build_vehicle widgets. */ #ifndef WIDGETS_BUILD_VEHICLE_WIDGET_H #define WIDGETS_BUILD_VEHICLE_WIDGET_H /** Widgets of the #BuildVehicleWindow class. */ enum BuildVehicleWidgets { WID_BV_CAPTION, ///< Caption of window. WID_BV_SORT_ASCENDING_DESCENDING, ///< Sort direction. WID_BV_SORT_DROPDOWN, ///< Criteria of sorting dropdown. WID_BV_CARGO_FILTER_DROPDOWN, ///< Cargo filter dropdown. WID_BV_SHOW_HIDDEN_ENGINES, ///< Toggle whether to display the hidden vehicles. WID_BV_LIST, ///< List of vehicles. WID_BV_SCROLLBAR, ///< Scrollbar of list. WID_BV_PANEL, ///< Button panel. WID_BV_BUILD, ///< Build panel. WID_BV_SHOW_HIDE, ///< Button to hide or show the selected engine. WID_BV_BUILD_SEL, ///< Build button. WID_BV_RENAME, ///< Rename button. }; #endif /* WIDGETS_BUILD_VEHICLE_WIDGET_H */ openttd-1.5.3/src/widgets/highscore_widget.h0000644000000000000000000000174612627373434017642 0ustar rootroot/* $Id: highscore_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 highscore_widget.h Types related to the highscore widgets. */ #ifndef WIDGETS_HIGHSCORE_WIDGET_H #define WIDGETS_HIGHSCORE_WIDGET_H /** Widgets of the #EndGameHighScoreBaseWindow class and #HighScoreWindow class. */ enum HighscoreWidgets { WID_H_BACKGROUND, ///< Background of the window. }; #endif /* WIDGETS_HIGHSCORE_WIDGET_H */ openttd-1.5.3/src/widgets/industry_widget.h0000644000000000000000000000426712627373434017551 0ustar rootroot/* $Id: industry_widget.h 24763 2012-11-25 15:24:02Z alberth $ */ /* * 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 industry_widget.h Types related to the industry widgets. */ #ifndef WIDGETS_INDUSTRY_WIDGET_H #define WIDGETS_INDUSTRY_WIDGET_H /** Widgets of the #BuildIndustryWindow class. */ enum DynamicPlaceIndustriesWidgets { WID_DPI_MATRIX_WIDGET, ///< Matrix of the industries. WID_DPI_SCROLLBAR, ///< Scrollbar of the matrix. WID_DPI_INFOPANEL, ///< Info panel about the industry. WID_DPI_DISPLAY_WIDGET, ///< Display chain button. WID_DPI_FUND_WIDGET, ///< Fund button. }; /** Widgets of the #IndustryViewWindow class. */ enum IndustryViewWidgets { WID_IV_CAPTION, ///< Caption of the window. WID_IV_VIEWPORT, ///< Viewport of the industry. WID_IV_INFO, ///< Info of the industry. WID_IV_GOTO, ///< Goto button. WID_IV_DISPLAY, ///< Display chain button. }; /** Widgets of the #IndustryDirectoryWindow class. */ enum IndustryDirectoryWidgets { WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort. WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort. WID_ID_INDUSTRY_LIST, ///< Industry list. WID_ID_SCROLLBAR, ///< Scrollbar of the list. }; /** Widgets of the #IndustryCargoesWindow class */ enum IndustryCargoesWidgets { WID_IC_CAPTION, ///< Caption of the window. WID_IC_NOTIFY, ///< Row of buttons at the bottom. WID_IC_PANEL, ///< Panel that shows the chain. WID_IC_SCROLLBAR, ///< Scrollbar of the panel. WID_IC_CARGO_DROPDOWN, ///< Select cargo dropdown. WID_IC_IND_DROPDOWN, ///< Select industry dropdown. }; #endif /* WIDGETS_INDUSTRY_WIDGET_H */ openttd-1.5.3/src/widgets/goal_widget.h0000644000000000000000000000250712627373434016605 0ustar rootroot /* $Id: goal_widget.h 25623 2013-07-21 15:59:07Z zuu $ */ /* * 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 goal_widget.h Types related to the goal widgets. */ #ifndef WIDGETS_GOAL_WIDGET_H #define WIDGETS_GOAL_WIDGET_H /** Widgets of the #GoalListWindow class. */ enum GoalListWidgets { WID_GOAL_CAPTION, ///< Caption of the window. WID_GOAL_LIST, ///< Goal list. WID_GOAL_SCROLLBAR, ///< Scrollbar of the goal list. }; /** Widgets of the #GoalQuestionWindow class. */ enum GoalQuestionWidgets { WID_GQ_CAPTION, ///< Caption of the window. WID_GQ_QUESTION, ///< Question text. WID_GQ_BUTTONS, ///< Buttons selection (between 1, 2 or 3). WID_GQ_BUTTON_1, ///< First button. WID_GQ_BUTTON_2, ///< Second button. WID_GQ_BUTTON_3, ///< Third button. }; #endif /* WIDGETS_GOAL_WIDGET_H */ openttd-1.5.3/src/widgets/terraform_widget.h0000644000000000000000000000612112627373434017660 0ustar rootroot/* $Id: terraform_widget.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 terraform_widget.h Types related to the terraform widgets. */ #ifndef WIDGETS_TERRAFORM_WIDGET_H #define WIDGETS_TERRAFORM_WIDGET_H /** Widgets of the #TerraformToolbarWindow class. */ enum TerraformToolbarWidgets { WID_TT_SHOW_PLACE_OBJECT, ///< Should the place object button be shown? WID_TT_BUTTONS_START, ///< Start of pushable buttons. WID_TT_LOWER_LAND = WID_TT_BUTTONS_START, ///< Lower land button. WID_TT_RAISE_LAND, ///< Raise land button. WID_TT_LEVEL_LAND, ///< Level land button. WID_TT_DEMOLISH, ///< Demolish aka dynamite button. WID_TT_BUY_LAND, ///< Buy land button. WID_TT_PLANT_TREES, ///< Plant trees button (note: opens separate window, no place-push-button). WID_TT_PLACE_SIGN, ///< Place sign button. WID_TT_PLACE_OBJECT, ///< Place object button. }; /** Widgets of the #ScenarioEditorLandscapeGenerationWindow class. */ enum EditorTerraformToolbarWidgets { WID_ETT_SHOW_PLACE_DESERT, ///< Should the place desert button be shown? WID_ETT_START, ///< Used for iterations. WID_ETT_DOTS = WID_ETT_START, ///< Invisible widget for rendering the terraform size on. WID_ETT_BUTTONS_START, ///< Start of pushable buttons. WID_ETT_DEMOLISH = WID_ETT_BUTTONS_START, ///< Demolish aka dynamite button. WID_ETT_LOWER_LAND, ///< Lower land button. WID_ETT_RAISE_LAND, ///< Raise land button. WID_ETT_LEVEL_LAND, ///< Level land button. WID_ETT_PLACE_ROCKS, ///< Place rocks button. WID_ETT_PLACE_DESERT, ///< Place desert button (in tropical climate). WID_ETT_PLACE_OBJECT, ///< Place transmitter button. WID_ETT_BUTTONS_END, ///< End of pushable buttons. WID_ETT_INCREASE_SIZE = WID_ETT_BUTTONS_END, ///< Upwards arrow button to increase terraforming size. WID_ETT_DECREASE_SIZE, ///< Downwards arrow button to decrease terraforming size. WID_ETT_NEW_SCENARIO, ///< Button for generating a new scenario. WID_ETT_RESET_LANDSCAPE, ///< Button for removing all company-owned property. }; #endif /* WIDGETS_TERRAFORM_WIDGET_H */ openttd-1.5.3/src/widgets/graph_widget.h0000644000000000000000000000551512627373434016766 0ustar rootroot/* $Id: graph_widget.h 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 graph_widget.h Types related to the graph widgets. */ #ifndef WIDGETS_GRAPH_WIDGET_H #define WIDGETS_GRAPH_WIDGET_H #include "../economy_type.h" #include "../company_type.h" /** Widgets of the #GraphLegendWindow class. */ enum GraphLegendWidgets { WID_GL_BACKGROUND, ///< Background of the window. WID_GL_FIRST_COMPANY, ///< First company in the legend. WID_GL_LAST_COMPANY = WID_GL_FIRST_COMPANY + MAX_COMPANIES - 1, ///< Last company in the legend. }; /** Widgets of the #OperatingProfitGraphWindow class, #IncomeGraphWindow class, #DeliveredCargoGraphWindow class, and #CompanyValueGraphWindow class. */ enum CompanyValueWidgets { WID_CV_KEY_BUTTON, ///< Key button. WID_CV_BACKGROUND, ///< Background of the window. WID_CV_GRAPH, ///< Graph itself. WID_CV_RESIZE, ///< Resize button. }; /** Widget of the #PerformanceHistoryGraphWindow class. */ enum PerformanceHistoryGraphWidgets { WID_PHG_KEY, ///< Key button. WID_PHG_DETAILED_PERFORMANCE, ///< Detailed performance. WID_PHG_BACKGROUND, ///< Background of the window. WID_PHG_GRAPH, ///< Graph itself. WID_PHG_RESIZE, ///< Resize button. }; /** Widget of the #PaymentRatesGraphWindow class. */ enum CargoPaymentRatesWidgets { WID_CPR_BACKGROUND, ///< Background of the window. WID_CPR_HEADER, ///< Header. WID_CPR_GRAPH, ///< Graph itself. WID_CPR_RESIZE, ///< Resize button. WID_CPR_FOOTER, ///< Footer. WID_CPR_ENABLE_CARGOES, ///< Enable cargoes button. WID_CPR_DISABLE_CARGOES, ///< Disable cargoes button. WID_CPR_CARGO_FIRST, ///< First cargo in the list. }; /** Widget of the #CompanyLeagueWindow class. */ enum CompanyLeagueWidgets { WID_CL_BACKGROUND, ///< Background of the window. }; /** Widget of the #PerformanceRatingDetailWindow class. */ enum PerformanceRatingDetailsWidgets { WID_PRD_SCORE_FIRST, ///< First entry in the score list. WID_PRD_SCORE_LAST = WID_PRD_SCORE_FIRST + (SCORE_END - SCORE_BEGIN) - 1, ///< Last entry in the score list. WID_PRD_COMPANY_FIRST, ///< First company. WID_PRD_COMPANY_LAST = WID_PRD_COMPANY_FIRST + MAX_COMPANIES - 1, ///< Last company. }; #endif /* WIDGETS_GRAPH_WIDGET_H */ openttd-1.5.3/src/widgets/vehicle_widget.h0000644000000000000000000001053512627373434017302 0ustar rootroot/* $Id: vehicle_widget.h 24997 2013-02-14 17:11:42Z rubidium $ */ /* * 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 vehicle_widget.h Types related to the vehicle widgets. */ #ifndef WIDGETS_VEHICLE_WIDGET_H #define WIDGETS_VEHICLE_WIDGET_H /** Widgets of the #VehicleViewWindow class. */ enum VehicleViewWidgets { WID_VV_CAPTION, ///< Caption of window. WID_VV_VIEWPORT, ///< Viewport widget. WID_VV_START_STOP, ///< Start or stop this vehicle, and show information about the current state. WID_VV_CENTER_MAIN_VIEW, ///< Center the main view on this vehicle. WID_VV_GOTO_DEPOT, ///< Order this vehicle to go to the depot. WID_VV_REFIT, ///< Open the refit window. WID_VV_SHOW_ORDERS, ///< Show the orders of this vehicle. WID_VV_SHOW_DETAILS, ///< Show details of this vehicle. WID_VV_CLONE, ///< Clone this vehicle. WID_VV_SELECT_DEPOT_CLONE, ///< Selection widget between 'goto depot', and 'clone vehicle' buttons. WID_VV_SELECT_REFIT_TURN, ///< Selection widget between 'refit' and 'turn around' buttons. WID_VV_TURN_AROUND, ///< Turn this vehicle around. WID_VV_FORCE_PROCEED, ///< Force this vehicle to pass a signal at danger. }; /** Widgets of the #RefitWindow class. */ enum VehicleRefitWidgets { WID_VR_CAPTION, ///< Caption of window. WID_VR_VEHICLE_PANEL_DISPLAY, ///< Display with a representation of the vehicle to refit. WID_VR_SHOW_HSCROLLBAR, ///< Selection widget for the horizontal scrollbar. WID_VR_HSCROLLBAR, ///< Horizontal scrollbar or the vehicle display. WID_VR_SELECT_HEADER, ///< Header with question about the cargo to carry. WID_VR_MATRIX, ///< Options to refit to. WID_VR_SCROLLBAR, ///< Scrollbar for the refit options. WID_VR_INFO, ///< Information about the currently selected refit option. WID_VR_REFIT, ///< Perform the refit. }; /** Widgets of the #VehicleDetailsWindow class. */ enum VehicleDetailsWidgets { WID_VD_CAPTION, ///< Caption of window. WID_VD_RENAME_VEHICLE, ///< Rename this vehicle. WID_VD_TOP_DETAILS, ///< Panel with generic details. WID_VD_INCREASE_SERVICING_INTERVAL, ///< Increase the servicing interval. WID_VD_DECREASE_SERVICING_INTERVAL, ///< Decrease the servicing interval. WID_VD_SERVICE_INTERVAL_DROPDOWN, ///< Dropdown to select default/days/percent service interval. WID_VD_SERVICING_INTERVAL, ///< Information about the servicing interval. WID_VD_MIDDLE_DETAILS, ///< Details for non-trains. WID_VD_MATRIX, ///< List of details for trains. WID_VD_SCROLLBAR, ///< Scrollbar for train details. WID_VD_DETAILS_CARGO_CARRIED, ///< Show carried cargo per part of the train. WID_VD_DETAILS_TRAIN_VEHICLES, ///< Show all parts of the train with their description. WID_VD_DETAILS_CAPACITY_OF_EACH, ///< Show the capacity of all train parts. WID_VD_DETAILS_TOTAL_CARGO, ///< Show the capacity and carried cargo amounts aggregated per cargo of the train. }; /** Widgets of the #VehicleListWindow class. */ enum VehicleListWidgets { WID_VL_CAPTION, ///< Caption of window. WID_VL_SORT_ORDER, ///< Sort order. WID_VL_SORT_BY_PULLDOWN, ///< Sort by dropdown list. WID_VL_LIST, ///< List of the vehicles. WID_VL_SCROLLBAR, ///< Scrollbar for the list. WID_VL_HIDE_BUTTONS, ///< Selection to hide the buttons. WID_VL_AVAILABLE_VEHICLES, ///< Available vehicles. WID_VL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. WID_VL_STOP_ALL, ///< Stop all button. WID_VL_START_ALL, ///< Start all button. }; #endif /* WIDGETS_VEHICLE_WIDGET_H */ openttd-1.5.3/src/widgets/dock_widget.h0000644000000000000000000000310612627373434016577 0ustar rootroot/* $Id: dock_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 dock_widget.h Types related to the dock widgets. */ #ifndef WIDGETS_DOCK_WIDGET_H #define WIDGETS_DOCK_WIDGET_H /** Widgets of the #BuildDocksDepotWindow class. */ enum BuildDockDepotWidgets { WID_BDD_BACKGROUND, ///< Background of the window. WID_BDD_X, ///< X-direction button. WID_BDD_Y, ///< Y-direction button. }; /** Widgets of the #BuildDocksToolbarWindow class. */ enum DockToolbarWidgets { WID_DT_CANAL, ///< Build canal button. WID_DT_LOCK, ///< Build lock button. WID_DT_DEMOLISH, ///< Demolish aka dynamite button. WID_DT_DEPOT, ///< Build depot button. WID_DT_STATION, ///< Build station button. WID_DT_BUOY, ///< Build buoy button. WID_DT_RIVER, ///< Build river button (in scenario editor). WID_DT_BUILD_AQUEDUCT, ///< Build aqueduct button. WID_DT_INVALID, ///< Used to initialize a variable. }; #endif /* WIDGETS_DOCK_WIDGET_H */ openttd-1.5.3/src/widgets/object_widget.h0000644000000000000000000000304712627373434017131 0ustar rootroot/* $Id: object_widget.h 24178 2012-04-24 20:01:34Z frosch $ */ /* * 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 object_widget.h Types related to the object widgets. */ #ifndef WIDGETS_OBJECT_WIDGET_H #define WIDGETS_OBJECT_WIDGET_H /** Widgets of the #BuildObjectWindow class. */ enum BuildObjectWidgets { WID_BO_CLASS_LIST, ///< The list with classes. WID_BO_SCROLLBAR, ///< The scrollbar associated with the list. WID_BO_OBJECT_MATRIX, ///< The matrix with preview sprites. WID_BO_OBJECT_SPRITE, ///< A preview sprite of the object. WID_BO_OBJECT_NAME, ///< The name of the selected object. WID_BO_OBJECT_SIZE, ///< The size of the selected object. WID_BO_INFO, ///< Other information about the object (from the NewGRF). WID_BO_SELECT_MATRIX, ///< Selection preview matrix of objects of a given class. WID_BO_SELECT_IMAGE, ///< Preview image in the #WID_BO_SELECT_MATRIX. WID_BO_SELECT_SCROLL, ///< Scrollbar next to the #WID_BO_SELECT_MATRIX. }; #endif /* WIDGETS_OBJECT_WIDGET_H */ openttd-1.5.3/src/widgets/bridge_widget.h0000644000000000000000000000224412627373434017115 0ustar rootroot/* $Id: bridge_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 bridge_widget.h Types related to the bridge widgets. */ #ifndef WIDGETS_BRIDGE_WIDGET_H #define WIDGETS_BRIDGE_WIDGET_H /** Widgets of the #BuildBridgeWindow class. */ enum BuildBridgeSelectionWidgets { WID_BBS_CAPTION, ///< Caption of the window. WID_BBS_DROPDOWN_ORDER, ///< Direction of sort dropdown. WID_BBS_DROPDOWN_CRITERIA, ///< Criteria of sort dropdown. WID_BBS_BRIDGE_LIST, ///< List of bridges. WID_BBS_SCROLLBAR, ///< Scrollbar of the list. }; #endif /* WIDGETS_BRIDGE_WIDGET_H */ openttd-1.5.3/src/widgets/error_widget.h0000644000000000000000000000175312627373434017016 0ustar rootroot/* $Id: error_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 error_widget.h Types related to the error widgets. */ #ifndef WIDGETS_ERROR_WIDGET_H #define WIDGETS_ERROR_WIDGET_H /** Widgets of the #ErrmsgWindow class. */ enum ErrorMessageWidgets { WID_EM_CAPTION, ///< Caption of the window. WID_EM_FACE, ///< Error title. WID_EM_MESSAGE, ///< Error message. }; #endif /* WIDGETS_ERROR_WIDGET_H */ openttd-1.5.3/src/widgets/statusbar_widget.h0000644000000000000000000000214112627373434017665 0ustar rootroot/* $Id: statusbar_widget.h 24663 2012-11-05 19:45:45Z frosch $ */ /* * 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 statusbar_widget.h Types related to the statusbar widgets. */ #ifndef WIDGETS_STATUSBAR_WIDGET_H #define WIDGETS_STATUSBAR_WIDGET_H /** Widgets of the #StatusBarWindow class. */ enum StatusbarWidgets { WID_S_LEFT, ///< Left part of the statusbar; date is shown there. WID_S_MIDDLE, ///< Middle part; current news or company name or *** SAVING *** or *** PAUSED ***. WID_S_RIGHT, ///< Right part; bank balance. }; #endif /* WIDGETS_STATUSBAR_WIDGET_H */ openttd-1.5.3/src/widgets/cheat_widget.h0000644000000000000000000000164712627373434016753 0ustar rootroot/* $Id: cheat_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 cheat_widget.h Types related to the cheat widgets. */ #ifndef WIDGETS_CHEAT_WIDGET_H #define WIDGETS_CHEAT_WIDGET_H /** Widgets of the #CheatWindow class.. */ enum CheatWidgets { WID_C_PANEL, ///< Panel where all cheats are shown in. }; #endif /* WIDGETS_CHEAT_WIDGET_H */ openttd-1.5.3/src/widgets/dropdown_widget.h0000644000000000000000000000205112627373434017511 0ustar rootroot/* $Id: dropdown_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 dropdown_widget.h Types related to the dropdown widgets. */ #ifndef WIDGETS_DROPDOWN_WIDGET_H #define WIDGETS_DROPDOWN_WIDGET_H /** Widgets of the #DropdownWindow class. */ enum DropdownMenuWidgets { WID_DM_ITEMS, ///< Panel showing the dropdown items. WID_DM_SHOW_SCROLL, ///< Hide scrollbar if too few items. WID_DM_SCROLL, ///< Scrollbar. }; #endif /* WIDGETS_DROPDOWN_WIDGET_H */ openttd-1.5.3/src/widgets/engine_widget.h0000644000000000000000000000200012627373434017114 0ustar rootroot/* $Id: engine_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 engine_widget.h Types related to the engine widgets. */ #ifndef WIDGETS_ENGINE_WIDGET_H #define WIDGETS_ENGINE_WIDGET_H /** Widgets of the #EnginePreviewWindow class. */ enum EnginePreviewWidgets { WID_EP_QUESTION, ///< The container for the question. WID_EP_NO, ///< No button. WID_EP_YES, ///< Yes button. }; #endif /* WIDGETS_ENGINE_WIDGET_H */ openttd-1.5.3/src/widgets/dropdown.cpp0000644000000000000000000004061712627373434016513 0ustar rootroot/* $Id: dropdown.cpp 27131 2015-02-01 12:23:39Z frosch $ */ /* * 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 dropdown.cpp Implementation of the dropdown widget. */ #include "../stdafx.h" #include "../window_gui.h" #include "../string_func.h" #include "../strings_func.h" #include "../window_func.h" #include "dropdown_type.h" #include "dropdown_widget.h" #include "../safeguards.h" void DropDownListItem::Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const { int c1 = _colour_gradient[bg_colour][3]; int c2 = _colour_gradient[bg_colour][7]; int mid = top + this->Height(0) / 2; GfxFillRect(left + 1, mid - 2, right - 1, mid - 2, c1); GfxFillRect(left + 1, mid - 1, right - 1, mid - 1, c2); } uint DropDownListStringItem::Width() const { char buffer[512]; GetString(buffer, this->String(), lastof(buffer)); return GetStringBoundingBox(buffer).width; } void DropDownListStringItem::Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const { DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, this->String(), sel ? TC_WHITE : TC_BLACK); } /** * Natural sorting comparator function for DropDownList::sort(). * @param first Left side of comparison. * @param second Right side of comparison. * @return true if \a first precedes \a second. * @warning All items in the list need to be derivates of DropDownListStringItem. */ /* static */ int DropDownListStringItem::NatSortFunc(const DropDownListItem * const *first, const DropDownListItem * const * second) { char buffer1[512], buffer2[512]; GetString(buffer1, static_cast(*first)->String(), lastof(buffer1)); GetString(buffer2, static_cast(*second)->String(), lastof(buffer2)); return strnatcmp(buffer1, buffer2); } StringID DropDownListParamStringItem::String() const { for (uint i = 0; i < lengthof(this->decode_params); i++) SetDParam(i, this->decode_params[i]); return this->string; } StringID DropDownListCharStringItem::String() const { SetDParamStr(0, this->raw_string); return this->string; } static const NWidgetPart _nested_dropdown_menu_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_END, WID_DM_ITEMS), SetMinimalSize(1, 1), SetScrollbar(WID_DM_SCROLL), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_DM_SHOW_SCROLL), NWidget(NWID_VSCROLLBAR, COLOUR_END, WID_DM_SCROLL), EndContainer(), EndContainer(), }; static WindowDesc _dropdown_desc( WDP_MANUAL, NULL, 0, 0, WC_DROPDOWN_MENU, WC_NONE, WDF_NO_FOCUS, _nested_dropdown_menu_widgets, lengthof(_nested_dropdown_menu_widgets) ); /** Drop-down menu window */ struct DropdownWindow : Window { WindowClass parent_wnd_class; ///< Parent window class. WindowNumber parent_wnd_num; ///< Parent window number. int parent_button; ///< Parent widget number where the window is dropped from. const DropDownList *list; ///< List with dropdown menu items. int selected_index; ///< Index of the selected item in the list. byte click_delay; ///< Timer to delay selection. bool drag_mode; bool instant_close; ///< Close the window when the mouse button is raised. int scrolling; ///< If non-zero, auto-scroll the item list (one time). Point position; ///< Position of the topleft corner of the window. Scrollbar *vscroll; /** * Create a dropdown menu. * @param parent Parent window. * @param list Dropdown item list. * @param selected Index of the selected item in the list. * @param button Widget of the parent window doing the dropdown. * @param instant_close Close the window when the mouse button is raised. * @param position Topleft position of the dropdown menu window. * @param size Size of the dropdown menu window. * @param wi_colour Colour of the parent widget. * @param scroll Dropdown menu has a scrollbar. * @param widget Widgets of the dropdown menu window. */ DropdownWindow(Window *parent, const DropDownList *list, int selected, int button, bool instant_close, const Point &position, const Dimension &size, Colours wi_colour, bool scroll) : Window(&_dropdown_desc) { assert(list->Length() > 0); this->position = position; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_DM_SCROLL); uint items_width = size.width - (scroll ? NWidgetScrollbar::GetVerticalDimension().width : 0); NWidgetCore *nwi = this->GetWidget(WID_DM_ITEMS); nwi->SetMinimalSize(items_width, size.height + 4); nwi->colour = wi_colour; nwi = this->GetWidget(WID_DM_SCROLL); nwi->colour = wi_colour; this->GetWidget(WID_DM_SHOW_SCROLL)->SetDisplayedPlane(scroll ? 0 : SZSP_NONE); this->FinishInitNested(0); CLRBITS(this->flags, WF_WHITE_BORDER); /* Total length of list */ int list_height = 0; for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { const DropDownListItem *item = *it; list_height += item->Height(items_width); } /* Capacity is the average number of items visible */ this->vscroll->SetCapacity(size.height * (uint16)list->Length() / list_height); this->vscroll->SetCount((uint16)list->Length()); this->parent_wnd_class = parent->window_class; this->parent_wnd_num = parent->window_number; this->parent_button = button; this->list = list; this->selected_index = selected; this->click_delay = 0; this->drag_mode = true; this->instant_close = instant_close; } ~DropdownWindow() { /* Make the dropdown "invisible", so it doesn't affect new window placement. * Also mark it dirty in case the callback deals with the screen. (e.g. screenshots). */ this->window_class = WC_INVALID; this->SetDirty(); Window *w2 = FindWindowById(this->parent_wnd_class, this->parent_wnd_num); if (w2 != NULL) { Point pt = _cursor.pos; pt.x -= w2->left; pt.y -= w2->top; w2->OnDropdownClose(pt, this->parent_button, this->selected_index, this->instant_close); } delete this->list; } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { return this->position; } /** * Find the dropdown item under the cursor. * @param value [out] Selected item, if function returns \c true. * @return Cursor points to a dropdown item. */ bool GetDropDownItem(int &value) { if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false; NWidgetBase *nwi = this->GetWidget(WID_DM_ITEMS); int y = _cursor.pos.y - this->top - nwi->pos_y - 2; int width = nwi->current_x - 4; int pos = this->vscroll->GetPosition(); const DropDownList *list = this->list; for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { /* Skip items that are scrolled up */ if (--pos >= 0) continue; const DropDownListItem *item = *it; int item_height = item->Height(width); if (y < item_height) { if (item->masked || !item->Selectable()) return false; value = item->result; return true; } y -= item_height; } return false; } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_DM_ITEMS) return; Colours colour = this->GetWidget(widget)->colour; int y = r.top + 2; int pos = this->vscroll->GetPosition(); for (const DropDownListItem * const *it = this->list->Begin(); it != this->list->End(); ++it) { const DropDownListItem *item = *it; int item_height = item->Height(r.right - r.left + 1); /* Skip items that are scrolled up */ if (--pos >= 0) continue; if (y + item_height < r.bottom) { bool selected = (this->selected_index == item->result); if (selected) GfxFillRect(r.left + 2, y, r.right - 1, y + item_height - 1, PC_BLACK); item->Draw(r.left, r.right, y, y + item_height, selected, colour); if (item->masked) { GfxFillRect(r.left + 1, y, r.right - 1, y + item_height - 1, _colour_gradient[colour][5], FILLRECT_CHECKER); } } y += item_height; } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget != WID_DM_ITEMS) return; int item; if (this->GetDropDownItem(item)) { this->click_delay = 4; this->selected_index = item; this->SetDirty(); } } virtual void OnTick() { if (this->scrolling != 0) { int pos = this->vscroll->GetPosition(); this->vscroll->UpdatePosition(this->scrolling); this->scrolling = 0; if (pos != this->vscroll->GetPosition()) { this->SetDirty(); } } } virtual void OnMouseLoop() { Window *w2 = FindWindowById(this->parent_wnd_class, this->parent_wnd_num); if (w2 == NULL) { delete this; return; } if (this->click_delay != 0 && --this->click_delay == 0) { /* Make the dropdown "invisible", so it doesn't affect new window placement. * Also mark it dirty in case the callback deals with the screen. (e.g. screenshots). */ this->window_class = WC_INVALID; this->SetDirty(); w2->OnDropdownSelect(this->parent_button, this->selected_index); delete this; return; } if (this->drag_mode) { int item; if (!_left_button_clicked) { this->drag_mode = false; if (!this->GetDropDownItem(item)) { if (this->instant_close) delete this; return; } this->click_delay = 2; } else { if (_cursor.pos.y <= this->top + 2) { /* Cursor is above the list, set scroll up */ this->scrolling = -1; return; } else if (_cursor.pos.y >= this->top + this->height - 2) { /* Cursor is below list, set scroll down */ this->scrolling = 1; return; } if (!this->GetDropDownItem(item)) return; } if (this->selected_index != item) { this->selected_index = item; this->SetDirty(); } } } }; /** * Show a drop down list. * @param w Parent window for the list. * @param list Prepopulated DropDownList. Will be deleted when the list is * closed. * @param selected The initially selected list item. * @param button The widget which is passed to Window::OnDropdownSelect and OnDropdownClose. * Unless you override those functions, this should be then widget index of the dropdown button. * @param wi_rect Coord of the parent drop down button, used to position the dropdown menu. * @param auto_width The width is determined by the widest item in the list, * in this case only one of \a left or \a right is used (depending on text direction). * @param instant_close Set to true if releasing mouse button should close the * list regardless of where the cursor is. */ void ShowDropDownListAt(Window *w, const DropDownList *list, int selected, int button, Rect wi_rect, Colours wi_colour, bool auto_width, bool instant_close) { DeleteWindowById(WC_DROPDOWN_MENU, 0); /* The preferred position is just below the dropdown calling widget */ int top = w->top + wi_rect.bottom + 1; /* The preferred width equals the calling widget */ uint width = wi_rect.right - wi_rect.left + 1; /* Longest item in the list, if auto_width is enabled */ uint max_item_width = 0; /* Total length of list */ int height = 0; for (const DropDownListItem * const *it = list->Begin(); it != list->End(); ++it) { const DropDownListItem *item = *it; height += item->Height(width); if (auto_width) max_item_width = max(max_item_width, item->Width() + 5); } /* Check if the status bar is visible, as we don't want to draw over it */ int screen_bottom = GetMainViewBottom(); bool scroll = false; /* Check if the dropdown will fully fit below the widget */ if (top + height + 4 >= screen_bottom) { /* If not, check if it will fit above the widget */ if (w->top + wi_rect.top - height > GetMainViewTop()) { top = w->top + wi_rect.top - height - 4; } else { /* ... and lastly if it won't, enable the scroll bar and fit the * list in below the widget */ int avg_height = height / (int)list->Length(); int rows = (screen_bottom - 4 - top) / avg_height; height = rows * avg_height; scroll = true; /* Add space for the scroll bar if we automatically determined * the width of the list. */ max_item_width += NWidgetScrollbar::GetVerticalDimension().width; } } if (auto_width) width = max(width, max_item_width); Point dw_pos = { w->left + (_current_text_dir == TD_RTL ? wi_rect.right + 1 - width : wi_rect.left), top}; Dimension dw_size = {width, height}; new DropdownWindow(w, list, selected, button, instant_close, dw_pos, dw_size, wi_colour, scroll); } /** * Show a drop down list. * @param w Parent window for the list. * @param list Prepopulated DropDownList. Will be deleted when the list is * closed. * @param selected The initially selected list item. * @param button The widget within the parent window that is used to determine * the list's location. * @param width Override the width determined by the selected widget. * @param auto_width Maximum width is determined by the widest item in the list. * @param instant_close Set to true if releasing mouse button should close the * list regardless of where the cursor is. */ void ShowDropDownList(Window *w, const DropDownList *list, int selected, int button, uint width, bool auto_width, bool instant_close) { /* Our parent's button widget is used to determine where to place the drop * down list window. */ Rect wi_rect; NWidgetCore *nwi = w->GetWidget(button); wi_rect.left = nwi->pos_x; wi_rect.right = nwi->pos_x + nwi->current_x - 1; wi_rect.top = nwi->pos_y; wi_rect.bottom = nwi->pos_y + nwi->current_y - 1; Colours wi_colour = nwi->colour; if ((nwi->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) { nwi->disp_flags |= ND_DROPDOWN_ACTIVE; } else { w->LowerWidget(button); } w->SetWidgetDirty(button); if (width != 0) { if (_current_text_dir == TD_RTL) { wi_rect.left = wi_rect.right + 1 - width; } else { wi_rect.right = wi_rect.left + width - 1; } } ShowDropDownListAt(w, list, selected, button, wi_rect, wi_colour, auto_width, instant_close); } /** * Show a dropdown menu window near a widget of the parent window. * The result code of the items is their index in the \a strings list. * @param w Parent window that wants the dropdown menu. * @param strings Menu list, end with #INVALID_STRING_ID * @param selected Index of initial selected item. * @param button Button widget number of the parent window \a w that wants the dropdown menu. * @param disabled_mask Bitmask for disabled items (items with their bit set are displayed, but not selectable in the dropdown list). * @param hidden_mask Bitmask for hidden items (items with their bit set are not copied to the dropdown list). * @param width Width of the dropdown menu. If \c 0, use the width of parent widget \a button. */ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask, uint32 hidden_mask, uint width) { DropDownList *list = new DropDownList(); for (uint i = 0; strings[i] != INVALID_STRING_ID; i++) { if (!HasBit(hidden_mask, i)) { *list->Append() = new DropDownListStringItem(strings[i], i, HasBit(disabled_mask, i)); } } /* No entries in the list? */ if (list->Length() == 0) { delete list; return; } ShowDropDownList(w, list, selected, button, width); } /** * Delete the drop-down menu from window \a pw * @param pw Parent window of the drop-down menu window * @return Parent widget number if the drop-down was found and closed, \c -1 if the window was not found. */ int HideDropDownMenu(Window *pw) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class != WC_DROPDOWN_MENU) continue; DropdownWindow *dw = dynamic_cast(w); assert(dw != NULL); if (pw->window_class == dw->parent_wnd_class && pw->window_number == dw->parent_wnd_num) { int parent_button = dw->parent_button; delete dw; return parent_button; } } return -1; } openttd-1.5.3/src/widgets/network_content_widget.h0000644000000000000000000000434612627373434021111 0ustar rootroot/* $Id: network_content_widget.h 25024 2013-02-18 19:30:24Z frosch $ */ /* * 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 network_content_widget.h Types related to the network content widgets. */ #ifndef WIDGETS_NETWORK_CONTENT_WIDGET_H #define WIDGETS_NETWORK_CONTENT_WIDGET_H #include "../textfile_type.h" /** Widgets of the #NetworkContentDownloadStatusWindow class. */ enum NetworkContentDownloadStatusWidgets { WID_NCDS_BACKGROUND, ///< Background of the window. WID_NCDS_CANCELOK, ///< (Optional) Cancel/OK button. }; /** Widgets of the #NetworkContentListWindow class. */ enum NetworkContentListWidgets { WID_NCL_BACKGROUND, ///< Resize button. WID_NCL_FILTER_CAPT, ///< Caption for the filter editbox. WID_NCL_FILTER, ///< Filter editbox. WID_NCL_CHECKBOX, ///< Button above checkboxes. WID_NCL_TYPE, ///< 'Type' button. WID_NCL_NAME, ///< 'Name' button. WID_NCL_MATRIX, ///< Panel with list of content. WID_NCL_SCROLLBAR, ///< Scrollbar of matrix. WID_NCL_DETAILS, ///< Panel with content details. WID_NCL_TEXTFILE, ///< Open readme, changelog (+1) or license (+2) of a file in the content window. WID_NCL_SELECT_ALL = WID_NCL_TEXTFILE + TFT_END, ///< 'Select all' button. WID_NCL_SELECT_UPDATE, ///< 'Select updates' button. WID_NCL_UNSELECT, ///< 'Unselect all' button. WID_NCL_OPEN_URL, ///< 'Open url' button. WID_NCL_CANCEL, ///< 'Cancel' button. WID_NCL_DOWNLOAD, ///< 'Download' button. WID_NCL_SEL_ALL_UPDATE, ///< #NWID_SELECTION widget for select all/update buttons.. WID_NCL_SEARCH_EXTERNAL, ///< Search external sites for missing NewGRF. }; #endif /* WIDGETS_NETWORK_CONTENT_WIDGET_H */ openttd-1.5.3/src/widgets/autoreplace_widget.h0000644000000000000000000000441512627373434020167 0ustar rootroot/* $Id: autoreplace_widget.h 26811 2014-09-11 17:10:38Z alberth $ */ /* * 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 autoreplace_widget.h Types related to the autoreplace widgets. */ #ifndef WIDGETS_AUTOREPLACE_WIDGET_H #define WIDGETS_AUTOREPLACE_WIDGET_H /** Widgets of the #ReplaceVehicleWindow class. */ enum ReplaceVehicleWidgets { WID_RV_CAPTION, ///< Caption of the window. /* Sort dropdown at the right. */ WID_RV_SORT_ASCENDING_DESCENDING, ///< Ascending/descending sort order button. WID_RV_SHOW_HIDDEN_ENGINES, ///< Toggle whether to display the hidden vehicles. WID_RV_SORT_DROPDOWN, ///< Dropdown for the sort criteria. /* Left and right matrix + details. */ WID_RV_LEFT_MATRIX, ///< The matrix on the left. WID_RV_LEFT_SCROLLBAR, ///< The scrollbar for the matrix on the left. WID_RV_RIGHT_MATRIX, ///< The matrix on the right. WID_RV_RIGHT_SCROLLBAR, ///< The scrollbar for the matrix on the right. WID_RV_LEFT_DETAILS, ///< Details of the entry on the left. WID_RV_RIGHT_DETAILS, ///< Details of the entry on the right. /* Button row. */ WID_RV_START_REPLACE, ///< Start Replacing button. WID_RV_INFO_TAB, ///< Info tab. WID_RV_STOP_REPLACE, ///< Stop Replacing button. /* Train only widgets. */ WID_RV_TRAIN_ENGINEWAGON_TOGGLE, ///< Button to toggle engines and/or wagons. WID_RV_TRAIN_FLUFF_LEFT, ///< The fluff on the left. WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. WID_RV_TRAIN_FLUFF_RIGHT, ///< The fluff on the right. WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. }; #endif /* WIDGETS_AUTOREPLACE_WIDGET_H */ openttd-1.5.3/src/widgets/station_widget.h0000644000000000000000000000645112627373434017346 0ustar rootroot/* $Id: station_widget.h 25365 2013-06-09 13:08:52Z fonsinchen $ */ /* * 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 station_widget.h Types related to the station widgets. */ #ifndef WIDGETS_STATION_WIDGET_H #define WIDGETS_STATION_WIDGET_H /** Widgets of the #StationViewWindow class. */ enum StationViewWidgets { WID_SV_CAPTION, ///< Caption of the window. WID_SV_SORT_ORDER, ///< 'Sort order' button WID_SV_SORT_BY, ///< 'Sort by' button WID_SV_GROUP, ///< label for "group by" WID_SV_GROUP_BY, ///< 'Group by' button WID_SV_WAITING, ///< List of waiting cargo. WID_SV_SCROLLBAR, ///< Scrollbar. WID_SV_ACCEPT_RATING_LIST, ///< List of accepted cargoes / rating of cargoes. WID_SV_LOCATION, ///< 'Location' button. WID_SV_ACCEPTS_RATINGS, ///< 'Accepts' / 'Ratings' button. WID_SV_RENAME, ///< 'Rename' button. WID_SV_CLOSE_AIRPORT, ///< 'Close airport' button. WID_SV_TRAINS, ///< List of scheduled trains button. WID_SV_ROADVEHS, ///< List of scheduled road vehs button. WID_SV_SHIPS, ///< List of scheduled ships button. WID_SV_PLANES, ///< List of scheduled planes button. }; /** Widgets of the #CompanyStationsWindow class. */ enum StationListWidgets { /* Name starts with ST instead of S, because of collision with SaveLoadWidgets */ WID_STL_CAPTION, ///< Caption of the window. WID_STL_LIST, ///< The main panel, list of stations. WID_STL_SCROLLBAR, ///< Scrollbar next to the main panel. /* Vehicletypes need to be in order of StationFacility due to bit magic */ WID_STL_TRAIN, ///< 'TRAIN' button - list only facilities where is a railroad station. WID_STL_TRUCK, ///< 'TRUCK' button - list only facilities where is a truck stop. WID_STL_BUS, ///< 'BUS' button - list only facilities where is a bus stop. WID_STL_AIRPLANE, ///< 'AIRPLANE' button - list only facilities where is an airport. WID_STL_SHIP, ///< 'SHIP' button - list only facilities where is a dock. WID_STL_FACILALL, ///< 'ALL' button - list all facilities. WID_STL_NOCARGOWAITING, ///< 'NO' button - list stations where no cargo is waiting. WID_STL_CARGOALL, ///< 'ALL' button - list all stations. WID_STL_SORTBY, ///< 'Sort by' button - reverse sort direction. WID_STL_SORTDROPBTN, ///< Dropdown button. WID_STL_CARGOSTART, ///< Widget numbers used for list of cargo types (not present in _company_stations_widgets). }; /** Widgets of the #SelectStationWindow class. */ enum JoinStationWidgets { WID_JS_CAPTION, // Caption of the window. WID_JS_PANEL, // Main panel. WID_JS_SCROLLBAR, // Scrollbar of the panel. }; #endif /* WIDGETS_STATION_WIDGET_H */ openttd-1.5.3/src/widgets/intro_widget.h0000644000000000000000000000372412627373434017020 0ustar rootroot/* $Id: intro_widget.h 24791 2012-12-05 19:37:15Z frosch $ */ /* * 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 intro_widget.h Types related to the intro widgets. */ #ifndef WIDGETS_INTRO_WIDGET_H #define WIDGETS_INTRO_WIDGET_H /** Widgets of the #SelectGameWindow class. */ enum SelectGameIntroWidgets { WID_SGI_GENERATE_GAME, ///< Generate game button. WID_SGI_LOAD_GAME, ///< Load game button. WID_SGI_PLAY_SCENARIO, ///< Play scenario button. WID_SGI_PLAY_HEIGHTMAP, ///< Play heightmap button. WID_SGI_EDIT_SCENARIO, ///< Edit scenario button. WID_SGI_PLAY_NETWORK, ///< Play network button. WID_SGI_TEMPERATE_LANDSCAPE, ///< Select temperate landscape button. WID_SGI_ARCTIC_LANDSCAPE, ///< Select arctic landscape button. WID_SGI_TROPIC_LANDSCAPE, ///< Select tropic landscape button. WID_SGI_TOYLAND_LANDSCAPE, ///< Select toyland landscape button. WID_SGI_TRANSLATION_SELECTION, ///< Translation selection. WID_SGI_TRANSLATION, ///< Translation. WID_SGI_OPTIONS, ///< Options button. WID_SGI_HIGHSCORE, ///< Highscore button. WID_SGI_SETTINGS_OPTIONS, ///< Settings button. WID_SGI_GRF_SETTINGS, ///< NewGRF button. WID_SGI_CONTENT_DOWNLOAD, ///< Content Download button. WID_SGI_AI_SETTINGS, ///< AI button. WID_SGI_EXIT, ///< Exit button. }; #endif /* WIDGETS_INTRO_WIDGET_H */ openttd-1.5.3/src/widgets/transparency_widget.h0000644000000000000000000000361412627373434020374 0ustar rootroot/* $Id: transparency_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 transparency_widget.h Types related to the transparency widgets. */ #ifndef WIDGETS_TRANSPARENCY_WIDGET_H #define WIDGETS_TRANSPARENCY_WIDGET_H /** Widgets of the #TransparenciesWindow class. */ enum TransparencyToolbarWidgets { /* Button row. */ WID_TT_BEGIN, ///< First toggle button. WID_TT_SIGNS = WID_TT_BEGIN, ///< Signs background transparency toggle button. WID_TT_TREES, ///< Trees transparency toggle button. WID_TT_HOUSES, ///< Houses transparency toggle button. WID_TT_INDUSTRIES, ///< industries transparency toggle button. WID_TT_BUILDINGS, ///< Company buildings and structures transparency toggle button. WID_TT_BRIDGES, ///< Bridges transparency toggle button. WID_TT_STRUCTURES, ///< Object structure transparency toggle button. WID_TT_CATENARY, ///< Catenary transparency toggle button. WID_TT_LOADING, ///< Loading indicators transparency toggle button. WID_TT_END, ///< End of toggle buttons. /* Panel with buttons for invisibility */ WID_TT_BUTTONS, ///< Panel with 'invisibility' buttons. }; #endif /* WIDGETS_TRANSPARENCY_WIDGET_H */ openttd-1.5.3/src/widgets/bootstrap_widget.h0000644000000000000000000000236412627373434017701 0ustar rootroot/* $Id: bootstrap_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 bootstrap_widget.h Types related to the bootstrap widgets. */ #ifndef WIDGETS_BOOTSTRAP_WIDGET_H #define WIDGETS_BOOTSTRAP_WIDGET_H /** Widgets of the #BootstrapBackground class. */ enum BootstrapBackgroundWidgets { WID_BB_BACKGROUND, ///< Background of the window. }; /** Widgets of the #BootstrapContentDownloadStatusWindow class. */ enum BootstrapAskForDownloadWidgets { WID_BAFD_QUESTION, ///< The question whether to download. WID_BAFD_YES, ///< An affirmative answer to the question. WID_BAFD_NO, ///< An negative answer to the question. }; #endif /* WIDGETS_BOOTSTRAP_WIDGET_H */ openttd-1.5.3/src/widgets/smallmap_widget.h0000644000000000000000000000430012627373434017462 0ustar rootroot/* $Id: smallmap_widget.h 25262 2013-05-19 14:36:35Z rubidium $ */ /* * 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 smallmap_widget.h Types related to the smallmap widgets. */ #ifndef WIDGETS_SMALLMAP_WIDGET_H #define WIDGETS_SMALLMAP_WIDGET_H /** Widgets of the #SmallMapWindow class. */ enum SmallMapWidgets { WID_SM_CAPTION, ///< Caption of the window. WID_SM_MAP_BORDER, ///< Border around the smallmap. WID_SM_MAP, ///< Panel containing the smallmap. WID_SM_LEGEND, ///< Bottom panel to display smallmap legends. WID_SM_BLANK, ///< Empty button as placeholder. WID_SM_ZOOM_IN, ///< Button to zoom in one step. WID_SM_ZOOM_OUT, ///< Button to zoom out one step. WID_SM_CONTOUR, ///< Button to select the contour view (height map). WID_SM_VEHICLES, ///< Button to select the vehicles view. WID_SM_INDUSTRIES, ///< Button to select the industries view. WID_SM_LINKSTATS, ///< Button to select the link stats view. WID_SM_ROUTES, ///< Button to select the routes view. WID_SM_VEGETATION, ///< Button to select the vegetation view. WID_SM_OWNERS, ///< Button to select the owners view. WID_SM_CENTERMAP, ///< Button to move smallmap center to main window center. WID_SM_TOGGLETOWNNAME, ///< Toggle button to display town names. WID_SM_SELECT_BUTTONS, ///< Selection widget for the buttons present in some smallmap modes. WID_SM_ENABLE_ALL, ///< Button to enable display of all legend entries. WID_SM_DISABLE_ALL, ///< Button to disable display of all legend entries. WID_SM_SHOW_HEIGHT, ///< Show heightmap toggle button. }; #endif /* WIDGETS_SMALLMAP_WIDGET_H */ openttd-1.5.3/src/widgets/misc_widget.h0000644000000000000000000000412112627373434016610 0ustar rootroot/* $Id: misc_widget.h 25816 2013-10-06 11:29:14Z frosch $ */ /* * 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 misc_widget.h Types related to the misc widgets. */ #ifndef WIDGETS_MISC_WIDGET_H #define WIDGETS_MISC_WIDGET_H /** Widgets of the #LandInfoWindow class. */ enum LandInfoWidgets { WID_LI_BACKGROUND, ///< Background of the window. }; /** Widgets of the #TooltipsWindow class. */ enum ToolTipsWidgets { WID_TT_BACKGROUND, ///< Background of the window. }; /** Widgets of the #AboutWindow class. */ enum AboutWidgets { WID_A_SCROLLING_TEXT, ///< The actually scrolling text. WID_A_WEBSITE, ///< URL of OpenTTD website. }; /** Widgets of the #QueryStringWindow class. */ enum QueryStringWidgets { WID_QS_CAPTION, ///< Caption of the window. WID_QS_TEXT, ///< Text of the query. WID_QS_DEFAULT, ///< Default button. WID_QS_CANCEL, ///< Cancel button. WID_QS_OK, ///< OK button. }; /** Widgets of the #QueryWindow class. */ enum QueryWidgets { WID_Q_CAPTION, ///< Caption of the window. WID_Q_TEXT, ///< Text of the query. WID_Q_NO, ///< Yes button. WID_Q_YES, ///< No button. }; /** Widgets of the #TextfileWindow class. */ enum TextfileWidgets { WID_TF_CAPTION, ///< The caption of the window. WID_TF_WRAPTEXT, ///< Whether or not to wrap the text. WID_TF_BACKGROUND, ///< Panel to draw the textfile on. WID_TF_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. }; #endif /* WIDGETS_MISC_WIDGET_H */ openttd-1.5.3/src/widgets/order_widget.h0000644000000000000000000000536412627373434017002 0ustar rootroot/* $Id: order_widget.h 23600 2011-12-19 20:46:17Z truebrain $ */ /* * 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 order_widget.h Types related to the order widgets. */ #ifndef WIDGETS_ORDER_WIDGET_H #define WIDGETS_ORDER_WIDGET_H /** Widgets of the #OrdersWindow class. */ enum OrderWidgets { WID_O_CAPTION, ///< Caption of the window. WID_O_TIMETABLE_VIEW, ///< Toggle timetable view. WID_O_ORDER_LIST, ///< Order list panel. WID_O_SCROLLBAR, ///< Order list scrollbar. WID_O_SKIP, ///< Skip current order. WID_O_DELETE, ///< Delete selected order. WID_O_STOP_SHARING, ///< Stop sharing orders. WID_O_NON_STOP, ///< Goto non-stop to destination. WID_O_GOTO, ///< Goto destination. WID_O_FULL_LOAD, ///< Select full load. WID_O_UNLOAD, ///< Select unload. WID_O_REFIT, ///< Select refit. WID_O_SERVICE, ///< Select service (at depot). WID_O_EMPTY, ///< Placeholder for refit dropdown when not owner. WID_O_REFIT_DROPDOWN, ///< Open refit options. WID_O_COND_VARIABLE, ///< Choose condition variable. WID_O_COND_COMPARATOR, ///< Choose condition type. WID_O_COND_VALUE, ///< Choose condition value. WID_O_SEL_TOP_LEFT, ///< #NWID_SELECTION widget for left part of the top row of the 'your train' order window. WID_O_SEL_TOP_MIDDLE, ///< #NWID_SELECTION widget for middle part of the top row of the 'your train' order window. WID_O_SEL_TOP_RIGHT, ///< #NWID_SELECTION widget for right part of the top row of the 'your train' order window. WID_O_SEL_TOP_ROW_GROUNDVEHICLE, ///< #NWID_SELECTION widget for the top row of the 'your train' order window. WID_O_SEL_TOP_ROW, ///< #NWID_SELECTION widget for the top row of the 'your non-trains' order window. WID_O_SEL_BOTTOM_MIDDLE, ///< #NWID_SELECTION widget for the middle part of the bottom row of the 'your train' order window. WID_O_SHARED_ORDER_LIST, ///< Open list of shared vehicles. }; #endif /* WIDGETS_ORDER_WIDGET_H */ openttd-1.5.3/src/widgets/settings_widget.h0000644000000000000000000000770612627373434017531 0ustar rootroot/* $Id: settings_widget.h 26990 2014-10-11 13:22:37Z peter1138 $ */ /* * 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 settings_widget.h Types related to the settings widgets. */ #ifndef WIDGETS_SETTINGS_WIDGET_H #define WIDGETS_SETTINGS_WIDGET_H /** Widgets of the #GameOptionsWindow class. */ enum GameOptionsWidgets { WID_GO_BACKGROUND, ///< Background of the window. WID_GO_CURRENCY_DROPDOWN, ///< Currency dropdown. WID_GO_DISTANCE_DROPDOWN, ///< Measuring unit dropdown. WID_GO_ROADSIDE_DROPDOWN, ///< Dropdown to select the road side (to set the right side ;)). WID_GO_TOWNNAME_DROPDOWN, ///< Town name dropdown. WID_GO_AUTOSAVE_DROPDOWN, ///< Dropdown to say how often to autosave. WID_GO_LANG_DROPDOWN, ///< Language dropdown. WID_GO_RESOLUTION_DROPDOWN, ///< Dropdown for the resolution. WID_GO_FULLSCREEN_BUTTON, ///< Toggle fullscreen. WID_GO_GUI_ZOOM_DROPDOWN, ///< Dropdown for the GUI zoom level. WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). WID_GO_BASE_GRF_DESCRIPTION = WID_GO_BASE_GRF_TEXTFILE + TFT_END, ///< Description of selected base GRF. WID_GO_BASE_SFX_DROPDOWN, ///< Use to select a base SFX. WID_GO_BASE_SFX_TEXTFILE, ///< Open base SFX readme, changelog (+1) or license (+2). WID_GO_BASE_SFX_DESCRIPTION = WID_GO_BASE_SFX_TEXTFILE + TFT_END, ///< Description of selected base SFX. WID_GO_BASE_MUSIC_DROPDOWN, ///< Use to select a base music set. WID_GO_BASE_MUSIC_STATUS, ///< Info about corrupted files etc. WID_GO_BASE_MUSIC_TEXTFILE, ///< Open base music readme, changelog (+1) or license (+2). WID_GO_BASE_MUSIC_DESCRIPTION = WID_GO_BASE_MUSIC_TEXTFILE + TFT_END, ///< Description of selected base music set. }; /** Widgets of the #GameSettingsWindow class. */ enum GameSettingsWidgets { WID_GS_FILTER, ///< Text filter. WID_GS_OPTIONSPANEL, ///< Panel widget containing the option lists. WID_GS_SCROLLBAR, ///< Scrollbar. WID_GS_HELP_TEXT, ///< Information area to display help text of the selected option. WID_GS_EXPAND_ALL, ///< Expand all button. WID_GS_COLLAPSE_ALL, ///< Collapse all button. WID_GS_RESTRICT_CATEGORY, ///< Label upfront to the category drop-down box to restrict the list of settings to show WID_GS_RESTRICT_TYPE, ///< Label upfront to the type drop-down box to restrict the list of settings to show WID_GS_RESTRICT_DROPDOWN, ///< The drop down box to restrict the list of settings WID_GS_TYPE_DROPDOWN, ///< The drop down box to choose client/game/company/all settings }; /** Widgets of the #CustomCurrencyWindow class. */ enum CustomCurrencyWidgets { WID_CC_RATE_DOWN, ///< Down button. WID_CC_RATE_UP, ///< Up button. WID_CC_RATE, ///< Rate of currency. WID_CC_SEPARATOR_EDIT, ///< Separator edit button. WID_CC_SEPARATOR, ///< Current separator. WID_CC_PREFIX_EDIT, ///< Prefix edit button. WID_CC_PREFIX, ///< Current prefix. WID_CC_SUFFIX_EDIT, ///< Suffix edit button. WID_CC_SUFFIX, ///< Current suffix. WID_CC_YEAR_DOWN, ///< Down button. WID_CC_YEAR_UP, ///< Up button. WID_CC_YEAR, ///< Year of introduction. WID_CC_PREVIEW, ///< Preview. }; #endif /* WIDGETS_SETTINGS_WIDGET_H */ openttd-1.5.3/src/widgets/newgrf_widget.h0000644000000000000000000001030312627373434017144 0ustar rootroot/* $Id: newgrf_widget.h 26613 2014-05-24 19:15:57Z alberth $ */ /* * 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 newgrf_widget.h Types related to the newgrf widgets. */ #ifndef WIDGETS_NEWGRF_WIDGET_H #define WIDGETS_NEWGRF_WIDGET_H #include "../newgrf_config.h" #include "../textfile_type.h" /** Widgets of the #NewGRFParametersWindow class. */ enum NewGRFParametersWidgets { WID_NP_SHOW_NUMPAR, ///< #NWID_SELECTION to optionally display #WID_NP_NUMPAR. WID_NP_NUMPAR_DEC, ///< Button to decrease number of parameters. WID_NP_NUMPAR_INC, ///< Button to increase number of parameters. WID_NP_NUMPAR, ///< Optional number of parameters. WID_NP_NUMPAR_TEXT, ///< Text description. WID_NP_BACKGROUND, ///< Panel to draw the settings on. WID_NP_SCROLLBAR, ///< Scrollbar to scroll through all settings. WID_NP_ACCEPT, ///< Accept button. WID_NP_RESET, ///< Reset button. WID_NP_SHOW_DESCRIPTION, ///< #NWID_SELECTION to optionally display parameter descriptions. WID_NP_DESCRIPTION, ///< Multi-line description of a parameter. }; /** Widgets of the #NewGRFWindow class. */ enum NewGRFStateWidgets { WID_NS_PRESET_LIST, ///< Active NewGRF preset. WID_NS_PRESET_SAVE, ///< Save list of active NewGRFs as presets. WID_NS_PRESET_DELETE, ///< Delete active preset. WID_NS_ADD, ///< Add NewGRF to active list. WID_NS_REMOVE, ///< Remove NewGRF from active list. WID_NS_MOVE_UP, ///< Move NewGRF up in active list. WID_NS_MOVE_DOWN, ///< Move NewGRF down in active list. WID_NS_UPGRADE, ///< Upgrade NewGRFs that have a newer version available. WID_NS_FILTER, ///< Filter list of available NewGRFs. WID_NS_FILE_LIST, ///< List window of active NewGRFs. WID_NS_SCROLLBAR, ///< Scrollbar for active NewGRF list. WID_NS_AVAIL_LIST, ///< List window of available NewGRFs. WID_NS_SCROLL2BAR, ///< Scrollbar for available NewGRF list. WID_NS_NEWGRF_INFO_TITLE, ///< Title for Info on selected NewGRF. WID_NS_NEWGRF_INFO, ///< Panel for Info on selected NewGRF. WID_NS_OPEN_URL, ///< Open URL of NewGRF. WID_NS_NEWGRF_TEXTFILE, ///< Open NewGRF readme, changelog (+1) or license (+2). WID_NS_SET_PARAMETERS = WID_NS_NEWGRF_TEXTFILE + TFT_END, ///< Open Parameters Window for selected NewGRF for editing parameters. WID_NS_VIEW_PARAMETERS, ///< Open Parameters Window for selected NewGRF for viewing parameters. WID_NS_TOGGLE_PALETTE, ///< Toggle Palette of selected, active NewGRF. WID_NS_APPLY_CHANGES, ///< Apply changes to NewGRF config. WID_NS_RESCAN_FILES, ///< Rescan files (available NewGRFs). WID_NS_RESCAN_FILES2, ///< Rescan files (active NewGRFs). WID_NS_CONTENT_DOWNLOAD, ///< Open content download (available NewGRFs). WID_NS_CONTENT_DOWNLOAD2, ///< Open content download (active NewGRFs). WID_NS_SHOW_REMOVE, ///< Select active list buttons (0 = normal, 1 = simple layout). WID_NS_SHOW_APPLY, ///< Select display of the buttons below the 'details'. }; /** Widgets of the #SavePresetWindow class. */ enum SavePresetWidgets { WID_SVP_PRESET_LIST, ///< List with available preset names. WID_SVP_SCROLLBAR, ///< Scrollbar for the list available preset names. WID_SVP_EDITBOX, ///< Edit box for changing the preset name. WID_SVP_CANCEL, ///< Button to cancel saving the preset. WID_SVP_SAVE, ///< Button to save the preset. }; /** Widgets of the #ScanProgressWindow class. */ enum ScanProgressWidgets { WID_SP_PROGRESS_BAR, ///< Simple progress bar. WID_SP_PROGRESS_TEXT, ///< Text explaining what is happening. }; #endif /* WIDGETS_NEWGRF_WIDGET_H */ openttd-1.5.3/src/roadstop.cpp0000644000000000000000000003223112627373434015035 0ustar rootroot/* $Id: roadstop.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 roadstop.cpp Implementation of the roadstop base class. */ #include "stdafx.h" #include "roadveh.h" #include "core/pool_func.hpp" #include "roadstop_base.h" #include "station_base.h" #include "vehicle_func.h" #include "safeguards.h" /** The pool of roadstops. */ RoadStopPool _roadstop_pool("RoadStop"); INSTANTIATE_POOL_METHODS(RoadStop) /** * De-Initializes RoadStops. */ RoadStop::~RoadStop() { /* When we are the head we need to free the entries */ if (HasBit(this->status, RSSFB_BASE_ENTRY)) { delete this->east; delete this->west; } if (CleaningPool()) return; } /** * Get the next road stop accessible by this vehicle. * @param v the vehicle to get the next road stop for. * @return the next road stop accessible. */ RoadStop *RoadStop::GetNextRoadStop(const RoadVehicle *v) const { for (RoadStop *rs = this->next; rs != NULL; rs = rs->next) { /* The vehicle cannot go to this roadstop (different roadtype) */ if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue; /* The vehicle is articulated and can therefore not go to a standard road stop. */ if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue; /* The vehicle can actually go to this road stop. So, return it! */ return rs; } return NULL; } /** * Join this road stop to another 'base' road stop if possible; * fill all necessary data to become an actual drive through road stop. * Also update the length etc. */ void RoadStop::MakeDriveThrough() { assert(this->east == NULL && this->west == NULL); RoadStopType rst = GetRoadStopType(this->xy); DiagDirection dir = GetRoadStopDir(this->xy); /* Use absolute so we always go towards the northern tile */ TileIndexDiff offset = abs(TileOffsByDiagDir(dir)); /* Information about the tile north of us */ TileIndex north_tile = this->xy - offset; bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile); RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL; /* Information about the tile south of us */ TileIndex south_tile = this->xy + offset; bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile); RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL; /* Amount of road stops that will be added to the 'northern' head */ int added = 1; if (north && rs_north->east != NULL) { // (east != NULL) == (west != NULL) /* There is a more northern one, so this can join them */ this->east = rs_north->east; this->west = rs_north->west; if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL) /* There more southern tiles too, they must 'join' us too */ ClrBit(rs_south->status, RSSFB_BASE_ENTRY); this->east->occupied += rs_south->east->occupied; this->west->occupied += rs_south->west->occupied; /* Free the now unneeded entry structs */ delete rs_south->east; delete rs_south->west; /* Make all 'children' of the southern tile take the new master */ for (; IsDriveThroughRoadStopContinuation(this->xy, south_tile); south_tile += offset) { rs_south = RoadStop::GetByTile(south_tile, rst); if (rs_south->east == NULL) break; rs_south->east = rs_north->east; rs_south->west = rs_north->west; added++; } } } else if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL) /* There is one to the south, but not to the north... so we become 'parent' */ this->east = rs_south->east; this->west = rs_south->west; SetBit(this->status, RSSFB_BASE_ENTRY); ClrBit(rs_south->status, RSSFB_BASE_ENTRY); } else { /* We are the only... so we are automatically the master */ this->east = new Entry(); this->west = new Entry(); SetBit(this->status, RSSFB_BASE_ENTRY); } /* Now update the lengths */ added *= TILE_SIZE; this->east->length += added; this->west->length += added; } /** * Prepare for removal of this stop; update other neighbouring stops * if needed. Also update the length etc. */ void RoadStop::ClearDriveThrough() { assert(this->east != NULL && this->west != NULL); RoadStopType rst = GetRoadStopType(this->xy); DiagDirection dir = GetRoadStopDir(this->xy); /* Use absolute so we always go towards the northern tile */ TileIndexDiff offset = abs(TileOffsByDiagDir(dir)); /* Information about the tile north of us */ TileIndex north_tile = this->xy - offset; bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile); RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL; /* Information about the tile south of us */ TileIndex south_tile = this->xy + offset; bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile); RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL; /* Must only be cleared after we determined which neighbours are * part of our little entry 'queue' */ DoClearSquare(this->xy); if (north) { /* There is a tile to the north, so we can't clear ourselves. */ if (south) { /* There are more southern tiles too, they must be split; * first make the new southern 'base' */ SetBit(rs_south->status, RSSFB_BASE_ENTRY); rs_south->east = new Entry(); rs_south->west = new Entry(); /* Keep track of the base because we need it later on */ RoadStop *rs_south_base = rs_south; TileIndex base_tile = south_tile; /* Make all (even more) southern stops part of the new entry queue */ for (south_tile += offset; IsDriveThroughRoadStopContinuation(base_tile, south_tile); south_tile += offset) { rs_south = RoadStop::GetByTile(south_tile, rst); rs_south->east = rs_south_base->east; rs_south->west = rs_south_base->west; } /* Find the other end; the northern most tile */ for (; IsDriveThroughRoadStopContinuation(base_tile, north_tile); north_tile -= offset) { rs_north = RoadStop::GetByTile(north_tile, rst); } /* We have to rebuild the entries because we cannot easily determine * how full each part is. So instead of keeping and maintaining a list * of vehicles and using that to 'rebuild' the occupied state we just * rebuild it from scratch as that removes lots of maintenance code * for the vehicle list and it's faster in real games as long as you * do not keep split and merge road stop every tick by the millions. */ rs_south_base->east->Rebuild(rs_south_base); rs_south_base->west->Rebuild(rs_south_base); assert(HasBit(rs_north->status, RSSFB_BASE_ENTRY)); rs_north->east->Rebuild(rs_north); rs_north->west->Rebuild(rs_north); } else { /* Only we left, so simple update the length. */ rs_north->east->length -= TILE_SIZE; rs_north->west->length -= TILE_SIZE; } } else if (south) { /* There is only something to the south. Hand over the base entry */ SetBit(rs_south->status, RSSFB_BASE_ENTRY); rs_south->east->length -= TILE_SIZE; rs_south->west->length -= TILE_SIZE; } else { /* We were the last */ delete this->east; delete this->west; } /* Make sure we don't get used for something 'incorrect' */ ClrBit(this->status, RSSFB_BASE_ENTRY); this->east = NULL; this->west = NULL; } /** * Leave the road stop * @param rv the vehicle that leaves the stop */ void RoadStop::Leave(RoadVehicle *rv) { if (IsStandardRoadStopTile(rv->tile)) { /* Vehicle is leaving a road stop tile, mark bay as free */ this->FreeBay(HasBit(rv->state, RVS_USING_SECOND_BAY)); this->SetEntranceBusy(false); } else { /* Otherwise just leave the drive through's entry cache. */ this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv); } } /** * Enter the road stop * @param rv the vehicle that enters the stop * @return whether the road stop could actually be entered */ bool RoadStop::Enter(RoadVehicle *rv) { if (IsStandardRoadStopTile(this->xy)) { /* For normal (non drive-through) road stops * Check if station is busy or if there are no free bays or whether it is a articulated vehicle. */ if (this->IsEntranceBusy() || !this->HasFreeBay() || rv->HasArticulatedPart()) return false; SetBit(rv->state, RVS_IN_ROAD_STOP); /* Allocate a bay and update the road state */ uint bay_nr = this->AllocateBay(); SB(rv->state, RVS_USING_SECOND_BAY, 1, bay_nr); /* Mark the station entrance as busy */ this->SetEntranceBusy(true); return true; } /* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */ this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv); /* Indicate a drive-through stop */ SetBit(rv->state, RVS_IN_DT_ROAD_STOP); return true; } /** * Find a roadstop at given tile * @param tile tile with roadstop * @param type roadstop type * @return pointer to RoadStop * @pre there has to be roadstop of given type there! */ /* static */ RoadStop *RoadStop::GetByTile(TileIndex tile, RoadStopType type) { const Station *st = Station::GetByTile(tile); for (RoadStop *rs = st->GetPrimaryRoadStop(type);; rs = rs->next) { if (rs->xy == tile) return rs; assert(rs->next != NULL); } } /** * Leave the road stop * @param rv the vehicle that leaves the stop */ void RoadStop::Entry::Leave(const RoadVehicle *rv) { this->occupied -= rv->gcache.cached_total_length; assert(this->occupied >= 0); } /** * Enter the road stop * @param rv the vehicle that enters the stop */ void RoadStop::Entry::Enter(const RoadVehicle *rv) { /* we cannot assert on this->occupied < this->length because of the * remote possibility that RVs are running through each other when * trying to prevention an infinite jam. */ this->occupied += rv->gcache.cached_total_length; } /** * Checks whether the 'next' tile is still part of the road same drive through * stop 'rs' in the same direction for the same vehicle. * @param rs the road stop tile to check against * @param next the 'next' tile to check * @return true if the 'next' tile is part of the road stop at 'next'. */ /* static */ bool RoadStop::IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next) { return IsTileType(next, MP_STATION) && GetStationIndex(next) == GetStationIndex(rs) && GetStationType(next) == GetStationType(rs) && GetRoadStopDir(next) == GetRoadStopDir(rs) && IsDriveThroughStopTile(next); } typedef std::list RVList; ///< A list of road vehicles /** Helper for finding RVs in a road stop. */ struct RoadStopEntryRebuilderHelper { RVList vehicles; ///< The list of vehicles to possibly add to. DiagDirection dir; ///< The direction the vehicle has to face to be added. }; /** * Add road vehicles to the station's list if needed. * @param v the found vehicle * @param data the extra data used to make our decision * @return always NULL */ Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data) { RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data; /* Not a RV or not in the right direction or crashed :( */ if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return NULL; RoadVehicle *rv = RoadVehicle::From(v); /* Don't add ones not in a road stop */ if (rv->state < RVSB_IN_ROAD_STOP) return NULL; /* Do not add duplicates! */ for (RVList::iterator it = rserh->vehicles.begin(); it != rserh->vehicles.end(); it++) { if (rv == *it) return NULL; } rserh->vehicles.push_back(rv); return NULL; } /** * Rebuild, from scratch, the vehicles and other metadata on this stop. * @param rs the roadstop this entry is part of * @param side the side of the road stop to look at */ void RoadStop::Entry::Rebuild(const RoadStop *rs, int side) { assert(HasBit(rs->status, RSSFB_BASE_ENTRY)); DiagDirection dir = GetRoadStopDir(rs->xy); if (side == -1) side = (rs->east == this); RoadStopEntryRebuilderHelper rserh; rserh.dir = side ? dir : ReverseDiagDir(dir); this->length = 0; TileIndexDiff offset = abs(TileOffsByDiagDir(dir)); for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) { this->length += TILE_SIZE; FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop); } this->occupied = 0; for (RVList::iterator it = rserh.vehicles.begin(); it != rserh.vehicles.end(); it++) { this->occupied += (*it)->gcache.cached_total_length; } } /** * Check the integrity of the data in this struct. * @param rs the roadstop this entry is part of */ void RoadStop::Entry::CheckIntegrity(const RoadStop *rs) const { if (!HasBit(rs->status, RSSFB_BASE_ENTRY)) return; /* The tile 'before' the road stop must not be part of this 'line' */ assert(!IsDriveThroughRoadStopContinuation(rs->xy, rs->xy - abs(TileOffsByDiagDir(GetRoadStopDir(rs->xy))))); Entry temp; temp.Rebuild(rs, rs->east == this); if (temp.length != this->length || temp.occupied != this->occupied) NOT_REACHED(); } openttd-1.5.3/src/date_gui.cpp0000644000000000000000000001613612627373435014772 0ustar rootroot/* $Id: date_gui.cpp 26657 2014-06-20 20:57:32Z planetmaker $ */ /* * 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 date_gui.cpp Graphical selection of a date. */ #include "stdafx.h" #include "strings_func.h" #include "date_func.h" #include "window_func.h" #include "window_gui.h" #include "date_gui.h" #include "core/geometry_func.hpp" #include "widgets/dropdown_type.h" #include "widgets/date_widget.h" #include "safeguards.h" /** Window to select a date graphically by using dropdowns */ struct SetDateWindow : Window { SetDateCallback *callback; ///< Callback to call when a date has been selected YearMonthDay date; ///< The currently selected date Year min_year; ///< The minimum year in the year dropdown Year max_year; ///< The maximum year (inclusive) in the year dropdown /** * Create the new 'set date' window * @param desc the window description * @param window_number number of the window * @param parent the parent window, i.e. if this closes we should close too * @param initial_date the initial date to show * @param min_year the minimum year to show in the year dropdown * @param max_year the maximum year (inclusive) to show in the year dropdown * @param callback the callback to call once a date has been selected */ SetDateWindow(WindowDesc *desc, WindowNumber window_number, Window *parent, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback) : Window(desc), callback(callback), min_year(max(MIN_YEAR, min_year)), max_year(min(MAX_YEAR, max_year)) { assert(this->min_year <= this->max_year); this->parent = parent; this->InitNested(window_number); if (initial_date == 0) initial_date = _date; ConvertDateToYMD(initial_date, &this->date); this->date.year = Clamp(this->date.year, min_year, max_year); } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { Point pt = { this->parent->left + this->parent->width / 2 - sm_width / 2, this->parent->top + this->parent->height / 2 - sm_height / 2 }; return pt; } /** * Helper function to construct the dropdown. * @param widget the dropdown widget to create the dropdown for */ void ShowDateDropDown(int widget) { int selected; DropDownList *list = new DropDownList(); switch (widget) { default: NOT_REACHED(); case WID_SD_DAY: for (uint i = 0; i < 31; i++) { *list->Append() = new DropDownListStringItem(STR_DAY_NUMBER_1ST + i, i + 1, false); } selected = this->date.day; break; case WID_SD_MONTH: for (uint i = 0; i < 12; i++) { *list->Append() = new DropDownListStringItem(STR_MONTH_JAN + i, i, false); } selected = this->date.month; break; case WID_SD_YEAR: for (Year i = this->min_year; i <= this->max_year; i++) { DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false); item->SetParam(0, i); *list->Append() = item; } selected = this->date.year; break; } ShowDropDownList(this, list, selected, widget); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { Dimension d = {0, 0}; switch (widget) { default: return; case WID_SD_DAY: for (uint i = 0; i < 31; i++) { d = maxdim(d, GetStringBoundingBox(STR_DAY_NUMBER_1ST + i)); } break; case WID_SD_MONTH: for (uint i = 0; i < 12; i++) { d = maxdim(d, GetStringBoundingBox(STR_MONTH_JAN + i)); } break; case WID_SD_YEAR: SetDParamMaxValue(0, this->max_year); d = maxdim(d, GetStringBoundingBox(STR_JUST_INT)); break; } d.width += padding.width; d.height += padding.height; *size = d; } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_SD_DAY: SetDParam(0, this->date.day - 1 + STR_DAY_NUMBER_1ST); break; case WID_SD_MONTH: SetDParam(0, this->date.month + STR_MONTH_JAN); break; case WID_SD_YEAR: SetDParam(0, this->date.year); break; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_SD_DAY: case WID_SD_MONTH: case WID_SD_YEAR: ShowDateDropDown(widget); break; case WID_SD_SET_DATE: if (this->callback != NULL) this->callback(this, ConvertYMDToDate(this->date.year, this->date.month, this->date.day)); delete this; break; } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_SD_DAY: this->date.day = index; break; case WID_SD_MONTH: this->date.month = index; break; case WID_SD_YEAR: this->date.year = index; break; } this->SetDirty(); } }; /** Widgets for the date setting window. */ static const NWidgetPart _nested_set_date_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_DATE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_VERTICAL), SetPIP(6, 6, 6), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(6, 6, 6), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SD_DAY), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_DATE_DAY_TOOLTIP), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SD_MONTH), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_DATE_MONTH_TOOLTIP), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_SD_YEAR), SetFill(1, 0), SetDataTip(STR_JUST_INT, STR_DATE_YEAR_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SD_SET_DATE), SetMinimalSize(100, 12), SetDataTip(STR_DATE_SET_DATE, STR_DATE_SET_DATE_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), EndContainer(), EndContainer() }; /** Description of the date setting window. */ static WindowDesc _set_date_desc( WDP_CENTER, NULL, 0, 0, WC_SET_DATE, WC_NONE, 0, _nested_set_date_widgets, lengthof(_nested_set_date_widgets) ); /** * Create the new 'set date' window * @param window_number number for the window * @param parent the parent window, i.e. if this closes we should close too * @param initial_date the initial date to show * @param min_year the minimum year to show in the year dropdown * @param max_year the maximum year (inclusive) to show in the year dropdown * @param callback the callback to call once a date has been selected */ void ShowSetDateWindow(Window *parent, int window_number, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback) { DeleteWindowByClass(WC_SET_DATE); new SetDateWindow(&_set_date_desc, window_number, parent, initial_date, min_year, max_year, callback); } openttd-1.5.3/src/station_cmd.cpp0000644000000000000000000045716212627373435015525 0ustar rootroot/* $Id: station_cmd.cpp 27350 2015-07-30 18:50:39Z frosch $ */ /* * 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 station_cmd.cpp Handling of station tiles. */ #include "stdafx.h" #include "aircraft.h" #include "bridge_map.h" #include "cmd_helper.h" #include "viewport_func.h" #include "command_func.h" #include "town.h" #include "news_func.h" #include "train.h" #include "ship.h" #include "roadveh.h" #include "industry.h" #include "newgrf_cargo.h" #include "newgrf_debug.h" #include "newgrf_station.h" #include "newgrf_canal.h" /* For the buoy */ #include "pathfinder/yapf/yapf_cache.h" #include "road_internal.h" /* For drawing catenary/checking road removal */ #include "autoslope.h" #include "water.h" #include "strings_func.h" #include "clear_func.h" #include "date_func.h" #include "vehicle_func.h" #include "string_func.h" #include "animated_tile_func.h" #include "elrail_func.h" #include "station_base.h" #include "roadstop_base.h" #include "newgrf_railtype.h" #include "waypoint_base.h" #include "waypoint_func.h" #include "pbs.h" #include "debug.h" #include "core/random_func.hpp" #include "company_base.h" #include "table/airporttile_ids.h" #include "newgrf_airporttiles.h" #include "order_backup.h" #include "newgrf_house.h" #include "company_gui.h" #include "linkgraph/linkgraph_base.h" #include "linkgraph/refresh.h" #include "widgets/station_widget.h" #include "table/strings.h" #include "safeguards.h" /** * Static instance of FlowStat::SharesMap. * Note: This instance is created on task start. * Lazy creation on first usage results in a data race between the CDist threads. */ /* static */ const FlowStat::SharesMap FlowStat::empty_sharesmap; /** * Check whether the given tile is a hangar. * @param t the tile to of whether it is a hangar. * @pre IsTileType(t, MP_STATION) * @return true if and only if the tile is a hangar. */ bool IsHangar(TileIndex t) { assert(IsTileType(t, MP_STATION)); /* If the tile isn't an airport there's no chance it's a hangar. */ if (!IsAirport(t)) return false; const Station *st = Station::GetByTile(t); const AirportSpec *as = st->airport.GetSpec(); for (uint i = 0; i < as->nof_depots; i++) { if (st->airport.GetHangarTile(i) == t) return true; } return false; } /** * Look for a station around the given tile area. * @param ta the area to search over * @param closest_station the closest station found so far * @param st to 'return' the found station * @return Succeeded command (if zero or one station found) or failed command (for two or more stations found). */ template CommandCost GetStationAround(TileArea ta, StationID closest_station, T **st) { ta.tile -= TileDiffXY(1, 1); ta.w += 2; ta.h += 2; /* check around to see if there's any stations there */ TILE_AREA_LOOP(tile_cur, ta) { if (IsTileType(tile_cur, MP_STATION)) { StationID t = GetStationIndex(tile_cur); if (!T::IsValidID(t)) continue; if (closest_station == INVALID_STATION) { closest_station = t; } else if (closest_station != t) { return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING); } } } *st = (closest_station == INVALID_STATION) ? NULL : T::Get(closest_station); return CommandCost(); } /** * Function to check whether the given tile matches some criterion. * @param tile the tile to check * @return true if it matches, false otherwise */ typedef bool (*CMSAMatcher)(TileIndex tile); /** * Counts the numbers of tiles matching a specific type in the area around * @param tile the center tile of the 'count area' * @param cmp the comparator/matcher (@see CMSAMatcher) * @return the number of matching tiles around */ static int CountMapSquareAround(TileIndex tile, CMSAMatcher cmp) { int num = 0; for (int dx = -3; dx <= 3; dx++) { for (int dy = -3; dy <= 3; dy++) { TileIndex t = TileAddWrap(tile, dx, dy); if (t != INVALID_TILE && cmp(t)) num++; } } return num; } /** * Check whether the tile is a mine. * @param tile the tile to investigate. * @return true if and only if the tile is a mine */ static bool CMSAMine(TileIndex tile) { /* No industry */ if (!IsTileType(tile, MP_INDUSTRY)) return false; const Industry *ind = Industry::GetByTile(tile); /* No extractive industry */ if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_EXTRACTIVE) == 0) return false; for (uint i = 0; i < lengthof(ind->produced_cargo); i++) { /* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine. * Also the production of passengers and mail is ignored. */ if (ind->produced_cargo[i] != CT_INVALID && (CargoSpec::Get(ind->produced_cargo[i])->classes & (CC_LIQUID | CC_PASSENGERS | CC_MAIL)) == 0) { return true; } } return false; } /** * Check whether the tile is water. * @param tile the tile to investigate. * @return true if and only if the tile is a water tile */ static bool CMSAWater(TileIndex tile) { return IsTileType(tile, MP_WATER) && IsWater(tile); } /** * Check whether the tile is a tree. * @param tile the tile to investigate. * @return true if and only if the tile is a tree tile */ static bool CMSATree(TileIndex tile) { return IsTileType(tile, MP_TREES); } #define M(x) ((x) - STR_SV_STNAME) enum StationNaming { STATIONNAMING_RAIL, STATIONNAMING_ROAD, STATIONNAMING_AIRPORT, STATIONNAMING_OILRIG, STATIONNAMING_DOCK, STATIONNAMING_HELIPORT, }; /** Information to handle station action 0 property 24 correctly */ struct StationNameInformation { uint32 free_names; ///< Current bitset of free names (we can remove names). bool *indtypes; ///< Array of bools telling whether an industry type has been found. }; /** * Find a station action 0 property 24 station name, or reduce the * free_names if needed. * @param tile the tile to search * @param user_data the StationNameInformation to base the search on * @return true if the tile contains an industry that has not given * its name to one of the other stations in town. */ static bool FindNearIndustryName(TileIndex tile, void *user_data) { /* All already found industry types */ StationNameInformation *sni = (StationNameInformation*)user_data; if (!IsTileType(tile, MP_INDUSTRY)) return false; /* If the station name is undefined it means that it doesn't name a station */ IndustryType indtype = GetIndustryType(tile); if (GetIndustrySpec(indtype)->station_name == STR_UNDEFINED) return false; /* In all cases if an industry that provides a name is found two of * the standard names will be disabled. */ sni->free_names &= ~(1 << M(STR_SV_STNAME_OILFIELD) | 1 << M(STR_SV_STNAME_MINES)); return !sni->indtypes[indtype]; } static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class) { static const uint32 _gen_station_name_bits[] = { 0, // STATIONNAMING_RAIL 0, // STATIONNAMING_ROAD 1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT 1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG 1U << M(STR_SV_STNAME_DOCKS), // STATIONNAMING_DOCK 1U << M(STR_SV_STNAME_HELIPORT), // STATIONNAMING_HELIPORT }; const Town *t = st->town; uint32 free_names = UINT32_MAX; bool indtypes[NUM_INDUSTRYTYPES]; memset(indtypes, 0, sizeof(indtypes)); const Station *s; FOR_ALL_STATIONS(s) { if (s != st && s->town == t) { if (s->indtype != IT_INVALID) { indtypes[s->indtype] = true; StringID name = GetIndustrySpec(s->indtype)->station_name; if (name != STR_UNDEFINED) { /* Filter for other industrytypes with the same name */ for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { const IndustrySpec *indsp = GetIndustrySpec(it); if (indsp->enabled && indsp->station_name == name) indtypes[it] = true; } } continue; } uint str = M(s->string_id); if (str <= 0x20) { if (str == M(STR_SV_STNAME_FOREST)) { str = M(STR_SV_STNAME_WOODS); } ClrBit(free_names, str); } } } TileIndex indtile = tile; StationNameInformation sni = { free_names, indtypes }; if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) { /* An industry has been found nearby */ IndustryType indtype = GetIndustryType(indtile); const IndustrySpec *indsp = GetIndustrySpec(indtype); /* STR_NULL means it only disables oil rig/mines */ if (indsp->station_name != STR_NULL) { st->indtype = indtype; return STR_SV_STNAME_FALLBACK; } } /* Oil rigs/mines name could be marked not free by looking for a near by industry. */ free_names = sni.free_names; /* check default names */ uint32 tmp = free_names & _gen_station_name_bits[name_class]; if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp); /* check mine? */ if (HasBit(free_names, M(STR_SV_STNAME_MINES))) { if (CountMapSquareAround(tile, CMSAMine) >= 2) { return STR_SV_STNAME_MINES; } } /* check close enough to town to get central as name? */ if (DistanceMax(tile, t->xy) < 8) { if (HasBit(free_names, M(STR_SV_STNAME))) return STR_SV_STNAME; if (HasBit(free_names, M(STR_SV_STNAME_CENTRAL))) return STR_SV_STNAME_CENTRAL; } /* Check lakeside */ if (HasBit(free_names, M(STR_SV_STNAME_LAKESIDE)) && DistanceFromEdge(tile) < 20 && CountMapSquareAround(tile, CMSAWater) >= 5) { return STR_SV_STNAME_LAKESIDE; } /* Check woods */ if (HasBit(free_names, M(STR_SV_STNAME_WOODS)) && ( CountMapSquareAround(tile, CMSATree) >= 8 || CountMapSquareAround(tile, IsTileForestIndustry) >= 2) ) { return _settings_game.game_creation.landscape == LT_TROPIC ? STR_SV_STNAME_FOREST : STR_SV_STNAME_WOODS; } /* check elevation compared to town */ int z = GetTileZ(tile); int z2 = GetTileZ(t->xy); if (z < z2) { if (HasBit(free_names, M(STR_SV_STNAME_VALLEY))) return STR_SV_STNAME_VALLEY; } else if (z > z2) { if (HasBit(free_names, M(STR_SV_STNAME_HEIGHTS))) return STR_SV_STNAME_HEIGHTS; } /* check direction compared to town */ static const int8 _direction_and_table[] = { ~( (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ), ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_NORTH)) ), ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ), ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) ), }; free_names &= _direction_and_table[ (TileX(tile) < TileX(t->xy)) + (TileY(tile) < TileY(t->xy)) * 2]; tmp = free_names & ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 6) | (1 << 7) | (1 << 12) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30)); return (tmp == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(tmp)); } #undef M /** * Find the closest deleted station of the current company * @param tile the tile to search from. * @return the closest station or NULL if too far. */ static Station *GetClosestDeletedStation(TileIndex tile) { uint threshold = 8; Station *best_station = NULL; Station *st; FOR_ALL_STATIONS(st) { if (!st->IsInUse() && st->owner == _current_company) { uint cur_dist = DistanceManhattan(tile, st->xy); if (cur_dist < threshold) { threshold = cur_dist; best_station = st; } } } return best_station; } void Station::GetTileArea(TileArea *ta, StationType type) const { switch (type) { case STATION_RAIL: *ta = this->train_station; return; case STATION_AIRPORT: *ta = this->airport; return; case STATION_TRUCK: *ta = this->truck_station; return; case STATION_BUS: *ta = this->bus_station; return; case STATION_DOCK: case STATION_OILRIG: ta->tile = this->dock_tile; break; default: NOT_REACHED(); } ta->w = 1; ta->h = 1; } /** * Update the virtual coords needed to draw the station sign. */ void Station::UpdateVirtCoord() { Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE); pt.y -= 32 * ZOOM_LVL_BASE; if ((this->facilities & FACIL_AIRPORT) && this->airport.type == AT_OILRIG) pt.y -= 16 * ZOOM_LVL_BASE; SetDParam(0, this->index); SetDParam(1, this->facilities); this->sign.UpdatePosition(pt.x, pt.y, STR_VIEWPORT_STATION); SetWindowDirty(WC_STATION_VIEW, this->index); } /** Update the virtual coords needed to draw the station sign for all stations. */ void UpdateAllStationVirtCoords() { BaseStation *st; FOR_ALL_BASE_STATIONS(st) { st->UpdateVirtCoord(); } } /** * Get a mask of the cargo types that the station accepts. * @param st Station to query * @return the expected mask */ static uint GetAcceptanceMask(const Station *st) { uint mask = 0; for (CargoID i = 0; i < NUM_CARGO; i++) { if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) mask |= 1 << i; } return mask; } /** * Items contains the two cargo names that are to be accepted or rejected. * msg is the string id of the message to display. */ static void ShowRejectOrAcceptNews(const Station *st, uint num_items, CargoID *cargo, StringID msg) { for (uint i = 0; i < num_items; i++) { SetDParam(i + 1, CargoSpec::Get(cargo[i])->name); } SetDParam(0, st->index); AddNewsItem(msg, NT_ACCEPTANCE, NF_INCOLOUR | NF_SMALL, NR_STATION, st->index); } /** * Get the cargo types being produced around the tile (in a rectangle). * @param tile Northtile of area * @param w X extent of the area * @param h Y extent of the area * @param rad Search radius in addition to the given area */ CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad) { CargoArray produced; int x = TileX(tile); int y = TileY(tile); /* expand the region by rad tiles on each side * while making sure that we remain inside the board. */ int x2 = min(x + w + rad, MapSizeX()); int x1 = max(x - rad, 0); int y2 = min(y + h + rad, MapSizeY()); int y1 = max(y - rad, 0); assert(x1 < x2); assert(y1 < y2); assert(w > 0); assert(h > 0); TileArea ta(TileXY(x1, y1), TileXY(x2 - 1, y2 - 1)); /* Loop over all tiles to get the produced cargo of * everything except industries */ TILE_AREA_LOOP(tile, ta) AddProducedCargo(tile, produced); /* Loop over the industries. They produce cargo for * anything that is within 'rad' from their bounding * box. As such if you have e.g. a oil well the tile * area loop might not hit an industry tile while * the industry would produce cargo for the station. */ const Industry *i; FOR_ALL_INDUSTRIES(i) { if (!ta.Intersects(i->location)) continue; for (uint j = 0; j < lengthof(i->produced_cargo); j++) { CargoID cargo = i->produced_cargo[j]; if (cargo != CT_INVALID) produced[cargo]++; } } return produced; } /** * Get the acceptance of cargoes around the tile in 1/8. * @param tile Center of the search area * @param w X extent of area * @param h Y extent of area * @param rad Search radius in addition to given area * @param always_accepted bitmask of cargo accepted by houses and headquarters; can be NULL */ CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, uint32 *always_accepted) { CargoArray acceptance; if (always_accepted != NULL) *always_accepted = 0; int x = TileX(tile); int y = TileY(tile); /* expand the region by rad tiles on each side * while making sure that we remain inside the board. */ int x2 = min(x + w + rad, MapSizeX()); int y2 = min(y + h + rad, MapSizeY()); int x1 = max(x - rad, 0); int y1 = max(y - rad, 0); assert(x1 < x2); assert(y1 < y2); assert(w > 0); assert(h > 0); for (int yc = y1; yc != y2; yc++) { for (int xc = x1; xc != x2; xc++) { TileIndex tile = TileXY(xc, yc); AddAcceptedCargo(tile, acceptance, always_accepted); } } return acceptance; } /** * Update the acceptance for a station. * @param st Station to update * @param show_msg controls whether to display a message that acceptance was changed. */ void UpdateStationAcceptance(Station *st, bool show_msg) { /* old accepted goods types */ uint old_acc = GetAcceptanceMask(st); /* And retrieve the acceptance. */ CargoArray acceptance; if (!st->rect.IsEmpty()) { acceptance = GetAcceptanceAroundTiles( TileXY(st->rect.left, st->rect.top), st->rect.right - st->rect.left + 1, st->rect.bottom - st->rect.top + 1, st->GetCatchmentRadius(), &st->always_accepted ); } /* Adjust in case our station only accepts fewer kinds of goods */ for (CargoID i = 0; i < NUM_CARGO; i++) { uint amt = acceptance[i]; /* Make sure the station can accept the goods type. */ bool is_passengers = IsCargoInClass(i, CC_PASSENGERS); if ((!is_passengers && !(st->facilities & ~FACIL_BUS_STOP)) || (is_passengers && !(st->facilities & ~FACIL_TRUCK_STOP))) { amt = 0; } GoodsEntry &ge = st->goods[i]; SB(ge.status, GoodsEntry::GES_ACCEPTANCE, 1, amt >= 8); if (LinkGraph::IsValidID(ge.link_graph)) { (*LinkGraph::Get(ge.link_graph))[ge.node].SetDemand(amt / 8); } } /* Only show a message in case the acceptance was actually changed. */ uint new_acc = GetAcceptanceMask(st); if (old_acc == new_acc) return; /* show a message to report that the acceptance was changed? */ if (show_msg && st->owner == _local_company && st->IsInUse()) { /* List of accept and reject strings for different number of * cargo types */ static const StringID accept_msg[] = { STR_NEWS_STATION_NOW_ACCEPTS_CARGO, STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO, }; static const StringID reject_msg[] = { STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO, STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO, }; /* Array of accepted and rejected cargo types */ CargoID accepts[2] = { CT_INVALID, CT_INVALID }; CargoID rejects[2] = { CT_INVALID, CT_INVALID }; uint num_acc = 0; uint num_rej = 0; /* Test each cargo type to see if its acceptance has changed */ for (CargoID i = 0; i < NUM_CARGO; i++) { if (HasBit(new_acc, i)) { if (!HasBit(old_acc, i) && num_acc < lengthof(accepts)) { /* New cargo is accepted */ accepts[num_acc++] = i; } } else { if (HasBit(old_acc, i) && num_rej < lengthof(rejects)) { /* Old cargo is no longer accepted */ rejects[num_rej++] = i; } } } /* Show news message if there are any changes */ if (num_acc > 0) ShowRejectOrAcceptNews(st, num_acc, accepts, accept_msg[num_acc - 1]); if (num_rej > 0) ShowRejectOrAcceptNews(st, num_rej, rejects, reject_msg[num_rej - 1]); } /* redraw the station view since acceptance changed */ SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_ACCEPT_RATING_LIST); } static void UpdateStationSignCoord(BaseStation *st) { const StationRect *r = &st->rect; if (r->IsEmpty()) return; // no tiles belong to this station /* clamp sign coord to be inside the station rect */ st->xy = TileXY(ClampU(TileX(st->xy), r->left, r->right), ClampU(TileY(st->xy), r->top, r->bottom)); st->UpdateVirtCoord(); if (!Station::IsExpected(st)) return; Station *full_station = Station::From(st); for (CargoID c = 0; c < NUM_CARGO; ++c) { LinkGraphID lg = full_station->goods[c].link_graph; if (!LinkGraph::IsValidID(lg)) continue; (*LinkGraph::Get(lg))[full_station->goods[c].node].UpdateLocation(st->xy); } } /** * Common part of building various station parts and possibly attaching them to an existing one. * @param [in,out] st Station to attach to * @param flags Command flags * @param reuse Whether to try to reuse a deleted station (gray sign) if possible * @param area Area occupied by the new part * @param name_class Station naming class to use to generate the new station's name * @return Command error that occurred, if any */ static CommandCost BuildStationPart(Station **st, DoCommandFlag flags, bool reuse, TileArea area, StationNaming name_class) { /* Find a deleted station close to us */ if (*st == NULL && reuse) *st = GetClosestDeletedStation(area.tile); if (*st != NULL) { if ((*st)->owner != _current_company) { return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION); } CommandCost ret = (*st)->rect.BeforeAddRect(area.tile, area.w, area.h, StationRect::ADD_TEST); if (ret.Failed()) return ret; } else { /* allocate and initialize new station */ if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING); if (flags & DC_EXEC) { *st = new Station(area.tile); (*st)->town = ClosestTownFromTile(area.tile, UINT_MAX); (*st)->string_id = GenerateStationName(*st, area.tile, name_class); if (Company::IsValidID(_current_company)) { SetBit((*st)->town->have_ratings, _current_company); } } } return CommandCost(); } /** * This is called right after a station was deleted. * It checks if the whole station is free of substations, and if so, the station will be * deleted after a little while. * @param st Station */ static void DeleteStationIfEmpty(BaseStation *st) { if (!st->IsInUse()) { st->delete_ctr = 0; InvalidateWindowData(WC_STATION_LIST, st->owner, 0); } /* station remains but it probably lost some parts - station sign should stay in the station boundaries */ UpdateStationSignCoord(st); } CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags); /** * Checks if the given tile is buildable, flat and has a certain height. * @param tile TileIndex to check. * @param invalid_dirs Prohibited directions for slopes (set of #DiagDirection). * @param allowed_z Height allowed for the tile. If allowed_z is negative, it will be set to the height of this tile. * @param allow_steep Whether steep slopes are allowed. * @param check_bridge Check for the existence of a bridge. * @return The cost in case of success, or an error code if it failed. */ CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool allow_steep, bool check_bridge = true) { if (check_bridge && IsBridgeAbove(tile)) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; int z; Slope tileh = GetTileSlope(tile, &z); /* Prohibit building if * 1) The tile is "steep" (i.e. stretches two height levels). * 2) The tile is non-flat and the build_on_slopes switch is disabled. */ if ((!allow_steep && IsSteepSlope(tileh)) || ((!_settings_game.construction.build_on_slopes) && tileh != SLOPE_FLAT)) { return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); } CommandCost cost(EXPENSES_CONSTRUCTION); int flat_z = z + GetSlopeMaxZ(tileh); if (tileh != SLOPE_FLAT) { /* Forbid building if the tile faces a slope in a invalid direction. */ for (DiagDirection dir = DIAGDIR_BEGIN; dir != DIAGDIR_END; dir++) { if (HasBit(invalid_dirs, dir) && !CanBuildDepotByTileh(dir, tileh)) { return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); } } cost.AddCost(_price[PR_BUILD_FOUNDATION]); } /* The level of this tile must be equal to allowed_z. */ if (allowed_z < 0) { /* First tile. */ allowed_z = flat_z; } else if (allowed_z != flat_z) { return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); } return cost; } /** * Tries to clear the given area. * @param tile_area Area to check. * @param flags Operation to perform. * @return The cost in case of success, or an error code if it failed. */ CommandCost CheckFlatLand(TileArea tile_area, DoCommandFlag flags) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; TILE_AREA_LOOP(tile_cur, tile_area) { CommandCost ret = CheckBuildableTile(tile_cur, 0, allowed_z, true); if (ret.Failed()) return ret; cost.AddCost(ret); ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); } return cost; } /** * Checks if a rail station can be built at the given area. * @param tile_area Area to check. * @param flags Operation to perform. * @param axis Rail station axis. * @param station StationID to be queried and returned if available. * @param rt The rail type to check for (overbuilding rail stations over rail). * @param affected_vehicles List of trains with PBS reservations on the tiles * @param spec_class Station class. * @param spec_index Index into the station class. * @param plat_len Platform length. * @param numtracks Number of platforms. * @return The cost in case of success, or an error code if it failed. */ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag flags, Axis axis, StationID *station, RailType rt, SmallVector &affected_vehicles, StationClassID spec_class, byte spec_index, byte plat_len, byte numtracks) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; uint invalid_dirs = 5 << axis; const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index); bool slope_cb = statspec != NULL && HasBit(statspec->callback_mask, CBM_STATION_SLOPE_CHECK); TILE_AREA_LOOP(tile_cur, tile_area) { CommandCost ret = CheckBuildableTile(tile_cur, invalid_dirs, allowed_z, false); if (ret.Failed()) return ret; cost.AddCost(ret); if (slope_cb) { /* Do slope check if requested. */ ret = PerformStationTileSlopeCheck(tile_area.tile, tile_cur, statspec, axis, plat_len, numtracks); if (ret.Failed()) return ret; } /* if station is set, then we have special handling to allow building on top of already existing stations. * so station points to INVALID_STATION if we can build on any station. * Or it points to a station if we're only allowed to build on exactly that station. */ if (station != NULL && IsTileType(tile_cur, MP_STATION)) { if (!IsRailStation(tile_cur)) { return ClearTile_Station(tile_cur, DC_AUTO); // get error message } else { StationID st = GetStationIndex(tile_cur); if (*station == INVALID_STATION) { *station = st; } else if (*station != st) { return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING); } } } else { /* Rail type is only valid when building a railway station; if station to * build isn't a rail station it's INVALID_RAILTYPE. */ if (rt != INVALID_RAILTYPE && IsPlainRailTile(tile_cur) && !HasSignals(tile_cur) && HasPowerOnRail(GetRailType(tile_cur), rt)) { /* Allow overbuilding if the tile: * - has rail, but no signals * - it has exactly one track * - the track is in line with the station * - the current rail type has power on the to-be-built type (e.g. convert normal rail to el rail) */ TrackBits tracks = GetTrackBits(tile_cur); Track track = RemoveFirstTrack(&tracks); Track expected_track = HasBit(invalid_dirs, DIAGDIR_NE) ? TRACK_X : TRACK_Y; if (tracks == TRACK_BIT_NONE && track == expected_track) { /* Check for trains having a reservation for this tile. */ if (HasBit(GetRailReservationTrackBits(tile_cur), track)) { Train *v = GetTrainForReservation(tile_cur, track); if (v != NULL) { *affected_vehicles.Append() = v; } } CommandCost ret = DoCommand(tile_cur, 0, track, flags, CMD_REMOVE_SINGLE_RAIL); if (ret.Failed()) return ret; cost.AddCost(ret); /* With flags & ~DC_EXEC CmdLandscapeClear would fail since the rail still exists */ continue; } } ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); } } return cost; } /** * Checks if a road stop can be built at the given tile. * @param tile_area Area to check. * @param flags Operation to perform. * @param invalid_dirs Prohibited directions (set of DiagDirections). * @param is_drive_through True if trying to build a drive-through station. * @param is_truck_stop True when building a truck stop, false otherwise. * @param axis Axis of a drive-through road stop. * @param station StationID to be queried and returned if available. * @param rts Road types to build. * @return The cost in case of success, or an error code if it failed. */ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadTypes rts) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; TILE_AREA_LOOP(cur_tile, tile_area) { CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through); if (ret.Failed()) return ret; cost.AddCost(ret); /* If station is set, then we have special handling to allow building on top of already existing stations. * Station points to INVALID_STATION if we can build on any station. * Or it points to a station if we're only allowed to build on exactly that station. */ if (station != NULL && IsTileType(cur_tile, MP_STATION)) { if (!IsRoadStop(cur_tile)) { return ClearTile_Station(cur_tile, DC_AUTO); // Get error message. } else { if (is_truck_stop != IsTruckStop(cur_tile) || is_drive_through != IsDriveThroughStopTile(cur_tile)) { return ClearTile_Station(cur_tile, DC_AUTO); // Get error message. } /* Drive-through station in the wrong direction. */ if (is_drive_through && IsDriveThroughStopTile(cur_tile) && DiagDirToAxis(GetRoadStopDir(cur_tile)) != axis){ return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION); } StationID st = GetStationIndex(cur_tile); if (*station == INVALID_STATION) { *station = st; } else if (*station != st) { return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING); } } } else { bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile); /* Road bits in the wrong direction. */ RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE; if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) { /* Someone was pedantic and *NEEDED* three fracking different error messages. */ switch (CountBits(rb)) { case 1: return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION); case 2: if (rb == ROAD_X || rb == ROAD_Y) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION); return_cmd_error(STR_ERROR_DRIVE_THROUGH_CORNER); default: // 3 or 4 return_cmd_error(STR_ERROR_DRIVE_THROUGH_JUNCTION); } } RoadTypes cur_rts = IsNormalRoadTile(cur_tile) ? GetRoadTypes(cur_tile) : ROADTYPES_NONE; uint num_roadbits = 0; if (build_over_road) { /* There is a road, check if we can build road+tram stop over it. */ if (HasBit(cur_rts, ROADTYPE_ROAD)) { Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD); if (road_owner == OWNER_TOWN) { if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD); } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) { CommandCost ret = CheckOwnership(road_owner); if (ret.Failed()) return ret; } num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD)); } /* There is a tram, check if we can build road+tram stop over it. */ if (HasBit(cur_rts, ROADTYPE_TRAM)) { Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM); if (Company::IsValidID(tram_owner) && (!_settings_game.construction.road_stop_on_competitor_road || /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ HasExactlyOneBit(GetRoadBits(cur_tile, ROADTYPE_TRAM)))) { CommandCost ret = CheckOwnership(tram_owner); if (ret.Failed()) return ret; } num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM)); } /* Take into account existing roadbits. */ rts |= cur_rts; } else { ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); } uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits; cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build); } } return cost; } /** * Check whether we can expand the rail part of the given station. * @param st the station to expand * @param new_ta the current (and if all is fine new) tile area of the rail part of the station * @param axis the axis of the newly build rail * @return Succeeded or failed command. */ CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis axis) { TileArea cur_ta = st->train_station; /* determine new size of train station region.. */ int x = min(TileX(cur_ta.tile), TileX(new_ta.tile)); int y = min(TileY(cur_ta.tile), TileY(new_ta.tile)); new_ta.w = max(TileX(cur_ta.tile) + cur_ta.w, TileX(new_ta.tile) + new_ta.w) - x; new_ta.h = max(TileY(cur_ta.tile) + cur_ta.h, TileY(new_ta.tile) + new_ta.h) - y; new_ta.tile = TileXY(x, y); /* make sure the final size is not too big. */ if (new_ta.w > _settings_game.station.station_spread || new_ta.h > _settings_game.station.station_spread) { return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT); } return CommandCost(); } static inline byte *CreateSingle(byte *layout, int n) { int i = n; do *layout++ = 0; while (--i); layout[((n - 1) >> 1) - n] = 2; return layout; } static inline byte *CreateMulti(byte *layout, int n, byte b) { int i = n; do *layout++ = b; while (--i); if (n > 4) { layout[0 - n] = 0; layout[n - 1 - n] = 0; } return layout; } /** * Create the station layout for the given number of tracks and platform length. * @param layout The layout to write to. * @param numtracks The number of tracks to write. * @param plat_len The length of the platforms. * @param statspec The specification of the station to (possibly) get the layout from. */ void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec) { if (statspec != NULL && statspec->lengths >= plat_len && statspec->platforms[plat_len - 1] >= numtracks && statspec->layouts[plat_len - 1][numtracks - 1]) { /* Custom layout defined, follow it. */ memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1], plat_len * numtracks); return; } if (plat_len == 1) { CreateSingle(layout, numtracks); } else { if (numtracks & 1) layout = CreateSingle(layout, plat_len); numtracks >>= 1; while (--numtracks >= 0) { layout = CreateMulti(layout, plat_len, 4); layout = CreateMulti(layout, plat_len, 6); } } } /** * Find a nearby station that joins this station. * @tparam T the class to find a station for * @tparam error_message the error message when building a station on top of others * @param existing_station an existing station we build over * @param station_to_join the station to join to * @param adjacent whether adjacent stations are allowed * @param ta the area of the newly build station * @param st 'return' pointer for the found station * @return command cost with the error or 'okay' */ template CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st) { assert(*st == NULL); bool check_surrounding = true; if (_settings_game.station.adjacent_stations) { if (existing_station != INVALID_STATION) { if (adjacent && existing_station != station_to_join) { /* You can't build an adjacent station over the top of one that * already exists. */ return_cmd_error(error_message); } else { /* Extend the current station, and don't check whether it will * be near any other stations. */ *st = T::GetIfValid(existing_station); check_surrounding = (*st == NULL); } } else { /* There's no station here. Don't check the tiles surrounding this * one if the company wanted to build an adjacent station. */ if (adjacent) check_surrounding = false; } } if (check_surrounding) { /* Make sure there are no similar stations around us. */ CommandCost ret = GetStationAround(ta, existing_station, st); if (ret.Failed()) return ret; } /* Distant join */ if (*st == NULL && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join); return CommandCost(); } /** * Find a nearby station that joins this station. * @param existing_station an existing station we build over * @param station_to_join the station to join to * @param adjacent whether adjacent stations are allowed * @param ta the area of the newly build station * @param st 'return' pointer for the found station * @return command cost with the error or 'okay' */ static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st) { return FindJoiningBaseStation(existing_station, station_to_join, adjacent, ta, st); } /** * Find a nearby waypoint that joins this waypoint. * @param existing_waypoint an existing waypoint we build over * @param waypoint_to_join the waypoint to join to * @param adjacent whether adjacent waypoints are allowed * @param ta the area of the newly build waypoint * @param wp 'return' pointer for the found waypoint * @return command cost with the error or 'okay' */ CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp) { return FindJoiningBaseStation(existing_waypoint, waypoint_to_join, adjacent, ta, wp); } /** * Build rail station * @param tile_org northern most position of station dragging/placement * @param flags operation to perform * @param p1 various bitstuffed elements * - p1 = (bit 0- 3) - railtype * - p1 = (bit 4) - orientation (Axis) * - p1 = (bit 8-15) - number of tracks * - p1 = (bit 16-23) - platform length * - p1 = (bit 24) - allow stations directly adjacent to other stations. * @param p2 various bitstuffed elements * - p2 = (bit 0- 7) - custom station class * - p2 = (bit 8-15) - custom station id * - p2 = (bit 16-31) - station ID to join (NEW_STATION if build new one) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildRailStation(TileIndex tile_org, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* Unpack parameters */ RailType rt = Extract(p1); Axis axis = Extract(p1); byte numtracks = GB(p1, 8, 8); byte plat_len = GB(p1, 16, 8); bool adjacent = HasBit(p1, 24); StationClassID spec_class = Extract(p2); byte spec_index = GB(p2, 8, 8); StationID station_to_join = GB(p2, 16, 16); /* Does the authority allow this? */ CommandCost ret = CheckIfAuthorityAllowsNewStation(tile_org, flags); if (ret.Failed()) return ret; if (!ValParamRailtype(rt)) return CMD_ERROR; /* Check if the given station class is valid */ if ((uint)spec_class >= StationClass::GetClassCount() || spec_class == STAT_CLASS_WAYP) return CMD_ERROR; if (spec_index >= StationClass::Get(spec_class)->GetSpecCount()) return CMD_ERROR; if (plat_len == 0 || numtracks == 0) return CMD_ERROR; int w_org, h_org; if (axis == AXIS_X) { w_org = plat_len; h_org = numtracks; } else { h_org = plat_len; w_org = numtracks; } bool reuse = (station_to_join != NEW_STATION); if (!reuse) station_to_join = INVALID_STATION; bool distant_join = (station_to_join != INVALID_STATION); if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR; if (h_org > _settings_game.station.station_spread || w_org > _settings_game.station.station_spread) return CMD_ERROR; /* these values are those that will be stored in train_tile and station_platforms */ TileArea new_location(tile_org, w_org, h_org); /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */ StationID est = INVALID_STATION; SmallVector affected_vehicles; /* Clear the land below the station. */ CommandCost cost = CheckFlatLandRailStation(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks); if (cost.Failed()) return cost; /* Add construction expenses. */ cost.AddCost((numtracks * _price[PR_BUILD_STATION_RAIL] + _price[PR_BUILD_STATION_RAIL_LENGTH]) * plat_len); cost.AddCost(numtracks * plat_len * RailBuildCost(rt)); Station *st = NULL; ret = FindJoiningStation(est, station_to_join, adjacent, new_location, &st); if (ret.Failed()) return ret; ret = BuildStationPart(&st, flags, reuse, new_location, STATIONNAMING_RAIL); if (ret.Failed()) return ret; if (st != NULL && st->train_station.tile != INVALID_TILE) { CommandCost ret = CanExpandRailStation(st, new_location, axis); if (ret.Failed()) return ret; } /* Check if we can allocate a custom stationspec to this station */ const StationSpec *statspec = StationClass::Get(spec_class)->GetSpec(spec_index); int specindex = AllocateSpecToStation(statspec, st, (flags & DC_EXEC) != 0); if (specindex == -1) return_cmd_error(STR_ERROR_TOO_MANY_STATION_SPECS); if (statspec != NULL) { /* Perform NewStation checks */ /* Check if the station size is permitted */ if (HasBit(statspec->disallowed_platforms, min(numtracks - 1, 7)) || HasBit(statspec->disallowed_lengths, min(plat_len - 1, 7))) { return CMD_ERROR; } /* Check if the station is buildable */ if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) { uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE); if (cb_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res)) return CMD_ERROR; } } if (flags & DC_EXEC) { TileIndexDiff tile_delta; byte *layout_ptr; byte numtracks_orig; Track track; st->train_station = new_location; st->AddFacility(FACIL_TRAIN, new_location.tile); st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY); if (statspec != NULL) { /* Include this station spec's animation trigger bitmask * in the station's cached copy. */ st->cached_anim_triggers |= statspec->animation.triggers; } tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); track = AxisToTrack(axis); layout_ptr = AllocaM(byte, numtracks * plat_len); GetStationLayout(layout_ptr, numtracks, plat_len, statspec); numtracks_orig = numtracks; Company *c = Company::Get(st->owner); TileIndex tile_track = tile_org; do { TileIndex tile = tile_track; int w = plat_len; do { byte layout = *layout_ptr++; if (IsRailStationTile(tile) && HasStationReservation(tile)) { /* Check for trains having a reservation for this tile. */ Train *v = GetTrainForReservation(tile, AxisToTrack(GetRailStationAxis(tile))); if (v != NULL) { FreeTrainTrackReservation(v); *affected_vehicles.Append() = v; if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), false); for (; v->Next() != NULL; v = v->Next()) { } if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), false); } } /* Railtype can change when overbuilding. */ if (IsRailStationTile(tile)) { if (!IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]--; c->infrastructure.station--; } /* Remove animation if overbuilding */ DeleteAnimatedTile(tile); byte old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0; MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, rt); /* Free the spec if we overbuild something */ DeallocateSpecFromStation(st, old_specindex); SetCustomStationSpecIndex(tile, specindex); SetStationTileRandomBits(tile, GB(Random(), 0, 4)); SetAnimationFrame(tile, 0); if (!IsStationTileBlocked(tile)) c->infrastructure.rail[rt]++; c->infrastructure.station++; if (statspec != NULL) { /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */ uint32 platinfo = GetPlatformInfo(AXIS_X, GetStationGfx(tile), plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false); /* As the station is not yet completely finished, the station does not yet exist. */ uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, NULL, tile); if (callback != CALLBACK_FAILED) { if (callback < 8) { SetStationGfx(tile, (callback & ~1) + axis); } else { ErrorUnknownCallbackResult(statspec->grf_prop.grffile->grfid, CBID_STATION_TILE_LAYOUT, callback); } } /* Trigger station animation -- after building? */ TriggerStationAnimation(st, tile, SAT_BUILT); } tile += tile_delta; } while (--w); AddTrackToSignalBuffer(tile_track, track, _current_company); YapfNotifyTrackLayoutChange(tile_track, track); tile_track += tile_delta ^ TileDiffXY(1, 1); // perpendicular to tile_delta } while (--numtracks); for (uint i = 0; i < affected_vehicles.Length(); ++i) { /* Restore reservations of trains. */ Train *v = affected_vehicles[i]; if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true); TryPathReserve(v, true, true); for (; v->Next() != NULL; v = v->Next()) { } if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), true); } /* Check whether we need to expand the reservation of trains already on the station. */ TileArea update_reservation_area; if (axis == AXIS_X) { update_reservation_area = TileArea(tile_org, 1, numtracks_orig); } else { update_reservation_area = TileArea(tile_org, numtracks_orig, 1); } TILE_AREA_LOOP(tile, update_reservation_area) { /* Don't even try to make eye candy parts reserved. */ if (IsStationTileBlocked(tile)) continue; DiagDirection dir = AxisToDiagDir(axis); TileIndexDiff tile_offset = TileOffsByDiagDir(dir); TileIndex platform_begin = tile; TileIndex platform_end = tile; /* We can only account for tiles that are reachable from this tile, so ignore primarily blocked tiles while finding the platform begin and end. */ for (TileIndex next_tile = platform_begin - tile_offset; IsCompatibleTrainStationTile(next_tile, platform_begin); next_tile -= tile_offset) { platform_begin = next_tile; } for (TileIndex next_tile = platform_end + tile_offset; IsCompatibleTrainStationTile(next_tile, platform_end); next_tile += tile_offset) { platform_end = next_tile; } /* If there is at least on reservation on the platform, we reserve the whole platform. */ bool reservation = false; for (TileIndex t = platform_begin; !reservation && t <= platform_end; t += tile_offset) { reservation = HasStationReservation(t); } if (reservation) { SetRailStationPlatformReservation(platform_begin, dir, true); } } st->MarkTilesDirty(false); st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_TRAINS); DirtyCompanyInfrastructureWindows(st->owner); } return cost; } static void MakeRailStationAreaSmaller(BaseStation *st) { TileArea ta = st->train_station; restart: /* too small? */ if (ta.w != 0 && ta.h != 0) { /* check the left side, x = constant, y changes */ for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(0, i));) { /* the left side is unused? */ if (++i == ta.h) { ta.tile += TileDiffXY(1, 0); ta.w--; goto restart; } } /* check the right side, x = constant, y changes */ for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(ta.w - 1, i));) { /* the right side is unused? */ if (++i == ta.h) { ta.w--; goto restart; } } /* check the upper side, y = constant, x changes */ for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, 0));) { /* the left side is unused? */ if (++i == ta.w) { ta.tile += TileDiffXY(0, 1); ta.h--; goto restart; } } /* check the lower side, y = constant, x changes */ for (uint i = 0; !st->TileBelongsToRailStation(ta.tile + TileDiffXY(i, ta.h - 1));) { /* the left side is unused? */ if (++i == ta.w) { ta.h--; goto restart; } } } else { ta.Clear(); } st->train_station = ta; } /** * Remove a number of tiles from any rail station within the area. * @param ta the area to clear station tile from. * @param affected_stations the stations affected. * @param flags the command flags. * @param removal_cost the cost for removing the tile, including the rail. * @param keep_rail whether to keep the rail of the station. * @tparam T the type of station to remove. * @return the number of cleared tiles or an error. */ template CommandCost RemoveFromRailBaseStation(TileArea ta, SmallVector &affected_stations, DoCommandFlag flags, Money removal_cost, bool keep_rail) { /* Count of the number of tiles removed */ int quantity = 0; CommandCost total_cost(EXPENSES_CONSTRUCTION); /* Accumulator for the errors seen during clearing. If no errors happen, * and the quantity is 0 there is no station. Otherwise it will be one * of the other error that got accumulated. */ CommandCost error; /* Do the action for every tile into the area */ TILE_AREA_LOOP(tile, ta) { /* Make sure the specified tile is a rail station */ if (!HasStationTileRail(tile)) continue; /* If there is a vehicle on ground, do not allow to remove (flood) the tile */ CommandCost ret = EnsureNoVehicleOnGround(tile); error.AddCost(ret); if (ret.Failed()) continue; /* Check ownership of station */ T *st = T::GetByTile(tile); if (st == NULL) continue; if (_current_company != OWNER_WATER) { CommandCost ret = CheckOwnership(st->owner); error.AddCost(ret); if (ret.Failed()) continue; } /* If we reached here, the tile is valid so increase the quantity of tiles we will remove */ quantity++; if (keep_rail || IsStationTileBlocked(tile)) { /* Don't refund the 'steel' of the track when we keep the * rail, or when the tile didn't have any rail at all. */ total_cost.AddCost(-_price[PR_CLEAR_RAIL]); } if (flags & DC_EXEC) { /* read variables before the station tile is removed */ uint specindex = GetCustomStationSpecIndex(tile); Track track = GetRailStationTrack(tile); Owner owner = GetTileOwner(tile); RailType rt = GetRailType(tile); Train *v = NULL; if (HasStationReservation(tile)) { v = GetTrainForReservation(tile, track); if (v != NULL) { /* Free train reservation. */ FreeTrainTrackReservation(v); if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), false); Vehicle *temp = v; for (; temp->Next() != NULL; temp = temp->Next()) { } if (IsRailStationTile(temp->tile)) SetRailStationPlatformReservation(temp->tile, TrackdirToExitdir(ReverseTrackdir(temp->GetVehicleTrackdir())), false); } } bool build_rail = keep_rail && !IsStationTileBlocked(tile); if (!build_rail && !IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[rt]--; DoClearSquare(tile); DeleteNewGRFInspectWindow(GSF_STATIONS, tile); if (build_rail) MakeRailNormal(tile, owner, TrackToTrackBits(track), rt); Company::Get(owner)->infrastructure.station--; DirtyCompanyInfrastructureWindows(owner); st->rect.AfterRemoveTile(st, tile); AddTrackToSignalBuffer(tile, track, owner); YapfNotifyTrackLayoutChange(tile, track); DeallocateSpecFromStation(st, specindex); affected_stations.Include(st); if (v != NULL) { /* Restore station reservation. */ if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true); TryPathReserve(v, true, true); for (; v->Next() != NULL; v = v->Next()) { } if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(ReverseTrackdir(v->GetVehicleTrackdir())), true); } } } if (quantity == 0) return error.Failed() ? error : CommandCost(STR_ERROR_THERE_IS_NO_STATION); for (T **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) { T *st = *stp; /* now we need to make the "spanned" area of the railway station smaller * if we deleted something at the edges. * we also need to adjust train_tile. */ MakeRailStationAreaSmaller(st); UpdateStationSignCoord(st); /* if we deleted the whole station, delete the train facility. */ if (st->train_station.tile == INVALID_TILE) { st->facilities &= ~FACIL_TRAIN; SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_TRAINS); st->UpdateVirtCoord(); DeleteStationIfEmpty(st); } } total_cost.AddCost(quantity * removal_cost); return total_cost; } /** * Remove a single tile from a rail station. * This allows for custom-built station with holes and weird layouts * @param start tile of station piece to remove * @param flags operation to perform * @param p1 start_tile * @param p2 various bitstuffed elements * - p2 = bit 0 - if set keep the rail * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRemoveFromRailStation(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { TileIndex end = p1 == 0 ? start : p1; if (start >= MapSize() || end >= MapSize()) return CMD_ERROR; TileArea ta(start, end); SmallVector affected_stations; CommandCost ret = RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_STATION_RAIL], HasBit(p2, 0)); if (ret.Failed()) return ret; /* Do all station specific functions here. */ for (Station **stp = affected_stations.Begin(); stp != affected_stations.End(); stp++) { Station *st = *stp; if (st->train_station.tile == INVALID_TILE) SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_TRAINS); st->MarkTilesDirty(false); st->RecomputeIndustriesNear(); } /* Now apply the rail cost to the number that we deleted */ return ret; } /** * Remove a single tile from a waypoint. * This allows for custom-built waypoint with holes and weird layouts * @param start tile of waypoint piece to remove * @param flags operation to perform * @param p1 start_tile * @param p2 various bitstuffed elements * - p2 = bit 0 - if set keep the rail * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRemoveFromRailWaypoint(TileIndex start, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { TileIndex end = p1 == 0 ? start : p1; if (start >= MapSize() || end >= MapSize()) return CMD_ERROR; TileArea ta(start, end); SmallVector affected_stations; return RemoveFromRailBaseStation(ta, affected_stations, flags, _price[PR_CLEAR_WAYPOINT_RAIL], HasBit(p2, 0)); } /** * Remove a rail station/waypoint * @param st The station/waypoint to remove the rail part from * @param flags operation to perform * @param removal_cost the cost for removing a tile * @tparam T the type of station to remove * @return cost or failure of operation */ template CommandCost RemoveRailStation(T *st, DoCommandFlag flags, Money removal_cost) { /* Current company owns the station? */ if (_current_company != OWNER_WATER) { CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; } /* determine width and height of platforms */ TileArea ta = st->train_station; assert(ta.w != 0 && ta.h != 0); CommandCost cost(EXPENSES_CONSTRUCTION); /* clear all areas of the station */ TILE_AREA_LOOP(tile, ta) { /* only remove tiles that are actually train station tiles */ if (!st->TileBelongsToRailStation(tile)) continue; CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; cost.AddCost(removal_cost); if (flags & DC_EXEC) { /* read variables before the station tile is removed */ Track track = GetRailStationTrack(tile); Owner owner = GetTileOwner(tile); // _current_company can be OWNER_WATER Train *v = NULL; if (HasStationReservation(tile)) { v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } if (!IsStationTileBlocked(tile)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--; Company::Get(owner)->infrastructure.station--; DoClearSquare(tile); DeleteNewGRFInspectWindow(GSF_STATIONS, tile); AddTrackToSignalBuffer(tile, track, owner); YapfNotifyTrackLayoutChange(tile, track); if (v != NULL) TryPathReserve(v, true); } } if (flags & DC_EXEC) { st->rect.AfterRemoveRect(st, st->train_station); st->train_station.Clear(); st->facilities &= ~FACIL_TRAIN; free(st->speclist); st->num_specs = 0; st->speclist = NULL; st->cached_anim_triggers = 0; DirtyCompanyInfrastructureWindows(st->owner); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_TRAINS); st->UpdateVirtCoord(); DeleteStationIfEmpty(st); } return cost; } /** * Remove a rail station * @param tile Tile of the station. * @param flags operation to perform * @return cost or failure of operation */ static CommandCost RemoveRailStation(TileIndex tile, DoCommandFlag flags) { /* if there is flooding, remove platforms tile by tile */ if (_current_company == OWNER_WATER) { return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_STATION); } Station *st = Station::GetByTile(tile); CommandCost cost = RemoveRailStation(st, flags, _price[PR_CLEAR_STATION_RAIL]); if (flags & DC_EXEC) st->RecomputeIndustriesNear(); return cost; } /** * Remove a rail waypoint * @param tile Tile of the waypoint. * @param flags operation to perform * @return cost or failure of operation */ static CommandCost RemoveRailWaypoint(TileIndex tile, DoCommandFlag flags) { /* if there is flooding, remove waypoints tile by tile */ if (_current_company == OWNER_WATER) { return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAIL_WAYPOINT); } return RemoveRailStation(Waypoint::GetByTile(tile), flags, _price[PR_CLEAR_WAYPOINT_RAIL]); } /** * @param truck_station Determines whether a stop is #ROADSTOP_BUS or #ROADSTOP_TRUCK * @param st The Station to do the whole procedure for * @return a pointer to where to link a new RoadStop* */ static RoadStop **FindRoadStopSpot(bool truck_station, Station *st) { RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops; if (*primary_stop == NULL) { /* we have no roadstop of the type yet, so write a "primary stop" */ return primary_stop; } else { /* there are stops already, so append to the end of the list */ RoadStop *stop = *primary_stop; while (stop->next != NULL) stop = stop->next; return &stop->next; } } static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags); /** * Find a nearby station that joins this road stop. * @param existing_stop an existing road stop we build over * @param station_to_join the station to join to * @param adjacent whether adjacent stations are allowed * @param ta the area of the newly build station * @param st 'return' pointer for the found station * @return command cost with the error or 'okay' */ static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st) { return FindJoiningBaseStation(existing_stop, station_to_join, adjacent, ta, st); } /** * Build a bus or truck stop. * @param tile Northernmost tile of the stop. * @param flags Operation to perform. * @param p1 bit 0..7: Width of the road stop. * bit 8..15: Length of the road stop. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * bit 1: 0 For normal stops, 1 for drive-through. * bit 2..3: The roadtypes. * bit 5: Allow stations directly adjacent to other stations. * bit 6..7: Entrance direction (#DiagDirection) for normal stops. * bit 6: #Axis of the road for drive-through stops. * bit 16..31: Station ID to join (NEW_STATION if build new one). * @param text Unused. * @return The cost of this operation or an error. */ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { bool type = HasBit(p2, 0); bool is_drive_through = HasBit(p2, 1); RoadTypes rts = Extract(p2); StationID station_to_join = GB(p2, 16, 16); bool reuse = (station_to_join != NEW_STATION); if (!reuse) station_to_join = INVALID_STATION; bool distant_join = (station_to_join != INVALID_STATION); uint8 width = (uint8)GB(p1, 0, 8); uint8 lenght = (uint8)GB(p1, 8, 8); /* Check if the requested road stop is too big */ if (width > _settings_game.station.station_spread || lenght > _settings_game.station.station_spread) return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT); /* Check for incorrect width / length. */ if (width == 0 || lenght == 0) return CMD_ERROR; /* Check if the first tile and the last tile are valid */ if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, lenght - 1) == INVALID_TILE) return CMD_ERROR; TileArea roadstop_area(tile, width, lenght); if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR; if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(_current_company, rts)) return CMD_ERROR; /* Trams only have drive through stops */ if (!is_drive_through && HasBit(rts, ROADTYPE_TRAM)) return CMD_ERROR; DiagDirection ddir; Axis axis; if (is_drive_through) { /* By definition axis is valid, due to there being 2 axes and reading 1 bit. */ axis = Extract(p2); ddir = AxisToDiagDir(axis); } else { /* By definition ddir is valid, due to there being 4 diagonal directions and reading 2 bits. */ ddir = Extract(p2); axis = DiagDirToAxis(ddir); } CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags); if (ret.Failed()) return ret; /* Total road stop cost. */ CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]); StationID est = INVALID_STATION; ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rts); if (ret.Failed()) return ret; cost.AddCost(ret); Station *st = NULL; ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 5), roadstop_area, &st); if (ret.Failed()) return ret; /* Check if this number of road stops can be allocated. */ if (!RoadStop::CanAllocateItem(roadstop_area.w * roadstop_area.h)) return_cmd_error(type ? STR_ERROR_TOO_MANY_TRUCK_STOPS : STR_ERROR_TOO_MANY_BUS_STOPS); ret = BuildStationPart(&st, flags, reuse, roadstop_area, STATIONNAMING_ROAD); if (ret.Failed()) return ret; if (flags & DC_EXEC) { /* Check every tile in the area. */ TILE_AREA_LOOP(cur_tile, roadstop_area) { RoadTypes cur_rts = GetRoadTypes(cur_tile); Owner road_owner = HasBit(cur_rts, ROADTYPE_ROAD) ? GetRoadOwner(cur_tile, ROADTYPE_ROAD) : _current_company; Owner tram_owner = HasBit(cur_rts, ROADTYPE_TRAM) ? GetRoadOwner(cur_tile, ROADTYPE_TRAM) : _current_company; if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) { RemoveRoadStop(cur_tile, flags); } RoadStop *road_stop = new RoadStop(cur_tile); /* Insert into linked list of RoadStops. */ RoadStop **currstop = FindRoadStopSpot(type, st); *currstop = road_stop; if (type) { st->truck_station.Add(cur_tile); } else { st->bus_station.Add(cur_tile); } /* Initialize an empty station. */ st->AddFacility((type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, cur_tile); st->rect.BeforeAddTile(cur_tile, StationRect::ADD_TRY); RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS; if (is_drive_through) { /* Update company infrastructure counts. If the current tile is a normal * road tile, count only the new road bits needed to get a full diagonal road. */ RoadType rt; FOR_EACH_SET_ROADTYPE(rt, cur_rts | rts) { Company *c = Company::GetIfValid(rt == ROADTYPE_ROAD ? road_owner : tram_owner); if (c != NULL) { c->infrastructure.road[rt] += 2 - (IsNormalRoadTile(cur_tile) && HasBit(cur_rts, rt) ? CountBits(GetRoadBits(cur_tile, rt)) : 0); DirtyCompanyInfrastructureWindows(c->index); } } MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, rts | cur_rts, axis); road_stop->MakeDriveThrough(); } else { /* Non-drive-through stop never overbuild and always count as two road bits. */ Company::Get(st->owner)->infrastructure.road[FIND_FIRST_BIT(rts)] += 2; MakeRoadStop(cur_tile, st->owner, st->index, rs_type, rts, ddir); } Company::Get(st->owner)->infrastructure.station++; DirtyCompanyInfrastructureWindows(st->owner); MarkTileDirtyByTile(cur_tile); } } if (st != NULL) { st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_ROADVEHS); } return cost; } static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *) { if (v->type == VEH_ROAD) { /* Okay... we are a road vehicle on a drive through road stop. * But that road stop has just been removed, so we need to make * sure we are in a valid state... however, vehicles can also * turn on road stop tiles, so only clear the 'road stop' state * bits and only when the state was 'in road stop', otherwise * we'll end up clearing the turn around bits. */ RoadVehicle *rv = RoadVehicle::From(v); if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) rv->state &= RVSB_ROAD_STOP_TRACKDIR_MASK; } return NULL; } /** * Remove a bus station/truck stop * @param tile TileIndex been queried * @param flags operation to perform * @return cost or failure of operation */ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags) { Station *st = Station::GetByTile(tile); if (_current_company != OWNER_WATER) { CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; } bool is_truck = IsTruckStop(tile); RoadStop **primary_stop; RoadStop *cur_stop; if (is_truck) { // truck stop primary_stop = &st->truck_stops; cur_stop = RoadStop::GetByTile(tile, ROADSTOP_TRUCK); } else { primary_stop = &st->bus_stops; cur_stop = RoadStop::GetByTile(tile, ROADSTOP_BUS); } assert(cur_stop != NULL); /* don't do the check for drive-through road stops when company bankrupts */ if (IsDriveThroughStopTile(tile) && (flags & DC_BANKRUPT)) { /* remove the 'going through road stop' status from all vehicles on that tile */ if (flags & DC_EXEC) FindVehicleOnPos(tile, NULL, &ClearRoadStopStatusEnum); } else { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; } if (flags & DC_EXEC) { if (*primary_stop == cur_stop) { /* removed the first stop in the list */ *primary_stop = cur_stop->next; /* removed the only stop? */ if (*primary_stop == NULL) { st->facilities &= (is_truck ? ~FACIL_TRUCK_STOP : ~FACIL_BUS_STOP); } } else { /* tell the predecessor in the list to skip this stop */ RoadStop *pred = *primary_stop; while (pred->next != cur_stop) pred = pred->next; pred->next = cur_stop->next; } /* Update company infrastructure counts. */ RoadType rt; FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { c->infrastructure.road[rt] -= 2; DirtyCompanyInfrastructureWindows(c->index); } } Company::Get(st->owner)->infrastructure.station--; DirtyCompanyInfrastructureWindows(st->owner); if (IsDriveThroughStopTile(tile)) { /* Clears the tile for us */ cur_stop->ClearDriveThrough(); } else { DoClearSquare(tile); } SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_ROADVEHS); delete cur_stop; /* Make sure no vehicle is going to the old roadstop */ RoadVehicle *v; FOR_ALL_ROADVEHICLES(v) { if (v->First() == v && v->current_order.IsType(OT_GOTO_STATION) && v->dest_tile == tile) { v->dest_tile = v->GetOrderStationLocation(st->index); } } st->rect.AfterRemoveTile(st, tile); st->UpdateVirtCoord(); st->RecomputeIndustriesNear(); DeleteStationIfEmpty(st); /* Update the tile area of the truck/bus stop */ if (is_truck) { st->truck_station.Clear(); for (const RoadStop *rs = st->truck_stops; rs != NULL; rs = rs->next) st->truck_station.Add(rs->xy); } else { st->bus_station.Clear(); for (const RoadStop *rs = st->bus_stops; rs != NULL; rs = rs->next) st->bus_station.Add(rs->xy); } } return CommandCost(EXPENSES_CONSTRUCTION, _price[is_truck ? PR_CLEAR_STATION_TRUCK : PR_CLEAR_STATION_BUS]); } /** * Remove bus or truck stops. * @param tile Northernmost tile of the removal area. * @param flags Operation to perform. * @param p1 bit 0..7: Width of the removal area. * bit 8..15: Height of the removal area. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * @param text Unused. * @return The cost of this operation or an error. */ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { uint8 width = (uint8)GB(p1, 0, 8); uint8 height = (uint8)GB(p1, 8, 8); /* Check for incorrect width / height. */ if (width == 0 || height == 0) return CMD_ERROR; /* Check if the first tile and the last tile are valid */ if (!IsValidTile(tile) || TileAddWrap(tile, width - 1, height - 1) == INVALID_TILE) return CMD_ERROR; TileArea roadstop_area(tile, width, height); int quantity = 0; CommandCost cost(EXPENSES_CONSTRUCTION); TILE_AREA_LOOP(cur_tile, roadstop_area) { /* Make sure the specified tile is a road stop of the correct type */ if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue; /* Save the stop info before it is removed */ bool is_drive_through = IsDriveThroughStopTile(cur_tile); RoadTypes rts = GetRoadTypes(cur_tile); RoadBits road_bits = IsDriveThroughStopTile(cur_tile) ? ((GetRoadStopDir(cur_tile) == DIAGDIR_NE) ? ROAD_X : ROAD_Y) : DiagDirToRoadBits(GetRoadStopDir(cur_tile)); Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD); Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM); CommandCost ret = RemoveRoadStop(cur_tile, flags); if (ret.Failed()) return ret; cost.AddCost(ret); quantity++; /* If the stop was a drive-through stop replace the road */ if ((flags & DC_EXEC) && is_drive_through) { MakeRoadNormal(cur_tile, road_bits, rts, ClosestTownFromTile(cur_tile, UINT_MAX)->index, road_owner, tram_owner); /* Update company infrastructure counts. */ RoadType rt; FOR_EACH_SET_ROADTYPE(rt, rts) { Company *c = Company::GetIfValid(GetRoadOwner(cur_tile, rt)); if (c != NULL) { c->infrastructure.road[rt] += CountBits(road_bits); DirtyCompanyInfrastructureWindows(c->index); } } } } if (quantity == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_STATION); return cost; } /** * Computes the minimal distance from town's xy to any airport's tile. * @param it An iterator over all airport tiles. * @param town_tile town's tile (t->xy) * @return minimal manhattan distance from town_tile to any airport's tile */ static uint GetMinimalAirportDistanceToTile(TileIterator &it, TileIndex town_tile) { uint mindist = UINT_MAX; for (TileIndex cur_tile = it; cur_tile != INVALID_TILE; cur_tile = ++it) { mindist = min(mindist, DistanceManhattan(town_tile, cur_tile)); } return mindist; } /** * Get a possible noise reduction factor based on distance from town center. * The further you get, the less noise you generate. * So all those folks at city council can now happily slee... work in their offices * @param as airport information * @param it An iterator over all airport tiles. * @param town_tile TileIndex of town's center, the one who will receive the airport's candidature * @return the noise that will be generated, according to distance */ uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileIndex town_tile) { /* 0 cannot be accounted, and 1 is the lowest that can be reduced from town. * So no need to go any further*/ if (as->noise_level < 2) return as->noise_level; uint distance = GetMinimalAirportDistanceToTile(it, town_tile); /* The steps for measuring noise reduction are based on the "magical" (and arbitrary) 8 base distance * adding the town_council_tolerance 4 times, as a way to graduate, depending of the tolerance. * Basically, it says that the less tolerant a town is, the bigger the distance before * an actual decrease can be granted */ uint8 town_tolerance_distance = 8 + (_settings_game.difficulty.town_council_tolerance * 4); /* now, we want to have the distance segmented using the distance judged bareable by town * This will give us the coefficient of reduction the distance provides. */ uint noise_reduction = distance / town_tolerance_distance; /* If the noise reduction equals the airport noise itself, don't give it for free. * Otherwise, simply reduce the airport's level. */ return noise_reduction >= as->noise_level ? 1 : as->noise_level - noise_reduction; } /** * Finds the town nearest to given airport. Based on minimal manhattan distance to any airport's tile. * If two towns have the same distance, town with lower index is returned. * @param as airport's description * @param it An iterator over all airport tiles * @return nearest town to airport */ Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it) { Town *t, *nearest = NULL; uint add = as->size_x + as->size_y - 2; // GetMinimalAirportDistanceToTile can differ from DistanceManhattan by this much uint mindist = UINT_MAX - add; // prevent overflow FOR_ALL_TOWNS(t) { if (DistanceManhattan(t->xy, it) < mindist + add) { // avoid calling GetMinimalAirportDistanceToTile too often TileIterator *copy = it.Clone(); uint dist = GetMinimalAirportDistanceToTile(*copy, t->xy); delete copy; if (dist < mindist) { nearest = t; mindist = dist; } } } return nearest; } /** Recalculate the noise generated by the airports of each town */ void UpdateAirportsNoise() { Town *t; const Station *st; FOR_ALL_TOWNS(t) t->noise_reached = 0; FOR_ALL_STATIONS(st) { if (st->airport.tile != INVALID_TILE && st->airport.type != AT_OILRIG) { const AirportSpec *as = st->airport.GetSpec(); AirportTileIterator it(st); Town *nearest = AirportGetNearestTown(as, it); nearest->noise_reached += GetAirportNoiseLevelForTown(as, it, nearest->xy); } } } /** * Place an Airport. * @param tile tile where airport will be built * @param flags operation to perform * @param p1 * - p1 = (bit 0- 7) - airport type, @see airport.h * - p1 = (bit 8-15) - airport layout * @param p2 various bitstuffed elements * - p2 = (bit 0) - allow airports directly adjacent to other airports. * - p2 = (bit 16-31) - station ID to join (NEW_STATION if build new one) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { StationID station_to_join = GB(p2, 16, 16); bool reuse = (station_to_join != NEW_STATION); if (!reuse) station_to_join = INVALID_STATION; bool distant_join = (station_to_join != INVALID_STATION); byte airport_type = GB(p1, 0, 8); byte layout = GB(p1, 8, 8); if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR; if (airport_type >= NUM_AIRPORTS) return CMD_ERROR; CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags); if (ret.Failed()) return ret; /* Check if a valid, buildable airport was chosen for construction */ const AirportSpec *as = AirportSpec::Get(airport_type); if (!as->IsAvailable() || layout >= as->num_table) return CMD_ERROR; Direction rotation = as->rotation[layout]; int w = as->size_x; int h = as->size_y; if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); TileArea airport_area = TileArea(tile, w, h); if (w > _settings_game.station.station_spread || h > _settings_game.station.station_spread) { return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT); } CommandCost cost = CheckFlatLand(airport_area, flags); if (cost.Failed()) return cost; /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. */ AirportTileTableIterator iter(as->table[layout], tile); Town *nearest = AirportGetNearestTown(as, iter); uint newnoise_level = GetAirportNoiseLevelForTown(as, iter, nearest->xy); /* Check if local auth would allow a new airport */ StringID authority_refuse_message = STR_NULL; Town *authority_refuse_town = NULL; if (_settings_game.economy.station_noise_level) { /* do not allow to build a new airport if this raise the town noise over the maximum allowed by town */ if ((nearest->noise_reached + newnoise_level) > nearest->MaxTownNoise()) { authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE; authority_refuse_town = nearest; } } else { Town *t = ClosestTownFromTile(tile, UINT_MAX); uint num = 0; const Station *st; FOR_ALL_STATIONS(st) { if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++; } if (num >= 2) { authority_refuse_message = STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT; authority_refuse_town = t; } } if (authority_refuse_message != STR_NULL) { SetDParam(0, authority_refuse_town->index); return_cmd_error(authority_refuse_message); } Station *st = NULL; ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 0), airport_area, &st); if (ret.Failed()) return ret; /* Distant join */ if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join); ret = BuildStationPart(&st, flags, reuse, airport_area, (GetAirport(airport_type)->flags & AirportFTAClass::AIRPLANES) ? STATIONNAMING_AIRPORT : STATIONNAMING_HELIPORT); if (ret.Failed()) return ret; if (st != NULL && st->airport.tile != INVALID_TILE) { return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT); } for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) { cost.AddCost(_price[PR_BUILD_STATION_AIRPORT]); } if (flags & DC_EXEC) { /* Always add the noise, so there will be no need to recalculate when option toggles */ nearest->noise_reached += newnoise_level; st->AddFacility(FACIL_AIRPORT, tile); st->airport.type = airport_type; st->airport.layout = layout; st->airport.flags = 0; st->airport.rotation = rotation; st->rect.BeforeAddRect(tile, w, h, StationRect::ADD_TRY); for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) { MakeAirport(iter, st->owner, st->index, iter.GetStationGfx(), WATER_CLASS_INVALID); SetStationTileRandomBits(iter, GB(Random(), 0, 4)); st->airport.Add(iter); if (AirportTileSpec::Get(GetTranslatedAirportTileID(iter.GetStationGfx()))->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(iter); } /* Only call the animation trigger after all tiles have been built */ for (AirportTileTableIterator iter(as->table[layout], tile); iter != INVALID_TILE; ++iter) { AirportTileAnimationTrigger(st, iter, AAT_BUILT); } UpdateAirplanesOnNewStation(st); Company::Get(st->owner)->infrastructure.airport++; DirtyCompanyInfrastructureWindows(st->owner); st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); InvalidateWindowData(WC_STATION_VIEW, st->index, -1); if (_settings_game.economy.station_noise_level) { SetWindowDirty(WC_TOWN_VIEW, st->town->index); } } return cost; } /** * Remove an airport * @param tile TileIndex been queried * @param flags operation to perform * @return cost or failure of operation */ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) { Station *st = Station::GetByTile(tile); if (_current_company != OWNER_WATER) { CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; } tile = st->airport.tile; CommandCost cost(EXPENSES_CONSTRUCTION); const Aircraft *a; FOR_ALL_AIRCRAFT(a) { if (!a->IsNormalAircraft()) continue; if (a->targetairport == st->index && a->state != FLYING) return CMD_ERROR; } if (flags & DC_EXEC) { const AirportSpec *as = st->airport.GetSpec(); /* The noise level is the noise from the airport and reduce it to account for the distance to the town center. * And as for construction, always remove it, even if the setting is not set, in order to avoid the * need of recalculation */ AirportTileIterator it(st); Town *nearest = AirportGetNearestTown(as, it); nearest->noise_reached -= GetAirportNoiseLevelForTown(as, it, nearest->xy); } TILE_AREA_LOOP(tile_cur, st->airport) { if (!st->TileBelongsToAirport(tile_cur)) continue; CommandCost ret = EnsureNoVehicleOnGround(tile_cur); if (ret.Failed()) return ret; cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]); if (flags & DC_EXEC) { if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false); DeleteAnimatedTile(tile_cur); DoClearSquare(tile_cur); DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur); } } if (flags & DC_EXEC) { /* Clear the persistent storage. */ delete st->airport.psa; for (uint i = 0; i < st->airport.GetNumHangars(); ++i) { DeleteWindowById( WC_VEHICLE_DEPOT, st->airport.GetHangarTile(i) ); } st->rect.AfterRemoveRect(st, st->airport); st->airport.Clear(); st->facilities &= ~FACIL_AIRPORT; InvalidateWindowData(WC_STATION_VIEW, st->index, -1); if (_settings_game.economy.station_noise_level) { SetWindowDirty(WC_TOWN_VIEW, st->town->index); } Company::Get(st->owner)->infrastructure.airport--; DirtyCompanyInfrastructureWindows(st->owner); st->UpdateVirtCoord(); st->RecomputeIndustriesNear(); DeleteStationIfEmpty(st); DeleteNewGRFInspectWindow(GSF_AIRPORTS, st->index); } return cost; } /** * Open/close an airport to incoming aircraft. * @param tile Unused. * @param flags Operation to perform. * @param p1 Station ID of the airport. * @param p2 Unused. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdOpenCloseAirport(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (!Station::IsValidID(p1)) return CMD_ERROR; Station *st = Station::Get(p1); if (!(st->facilities & FACIL_AIRPORT) || st->owner == OWNER_NONE) return CMD_ERROR; CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; if (flags & DC_EXEC) { st->airport.flags ^= AIRPORT_CLOSED_block; SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_CLOSE_AIRPORT); } return CommandCost(); } /** * Tests whether the company's vehicles have this station in orders * @param station station ID * @param include_company If true only check vehicles of \a company, if false only check vehicles of other companies * @param company company ID */ bool HasStationInUse(StationID station, bool include_company, CompanyID company) { const Vehicle *v; FOR_ALL_VEHICLES(v) { if ((v->owner == company) == include_company) { const Order *order; FOR_VEHICLE_ORDERS(v, order) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) { return true; } } } } return false; } static const TileIndexDiffC _dock_tileoffs_chkaround[] = { {-1, 0}, { 0, 0}, { 0, 0}, { 0, -1} }; static const byte _dock_w_chk[4] = { 2, 1, 2, 1 }; static const byte _dock_h_chk[4] = { 1, 2, 1, 2 }; /** * Build a dock/haven. * @param tile tile where dock will be built * @param flags operation to perform * @param p1 (bit 0) - allow docks directly adjacent to other docks. * @param p2 bit 16-31: station ID to join (NEW_STATION if build new one) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildDock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { StationID station_to_join = GB(p2, 16, 16); bool reuse = (station_to_join != NEW_STATION); if (!reuse) station_to_join = INVALID_STATION; bool distant_join = (station_to_join != INVALID_STATION); if (distant_join && (!_settings_game.station.distant_join_stations || !Station::IsValidID(station_to_join))) return CMD_ERROR; DiagDirection direction = GetInclinedSlopeDirection(GetTileSlope(tile)); if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); direction = ReverseDiagDir(direction); /* Docks cannot be placed on rapids */ if (HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); CommandCost ret = CheckIfAuthorityAllowsNewStation(tile, flags); if (ret.Failed()) return ret; if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; TileIndex tile_cur = tile + TileOffsByDiagDir(direction); if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } if (IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); /* Get the water class of the water tile before it is cleared.*/ WaterClass wc = GetWaterClass(tile_cur); ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; tile_cur += TileOffsByDiagDir(direction); if (!IsTileType(tile_cur, MP_WATER) || !IsTileFlat(tile_cur)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } TileArea dock_area = TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]), _dock_w_chk[direction], _dock_h_chk[direction]); /* middle */ Station *st = NULL; ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p1, 0), dock_area, &st); if (ret.Failed()) return ret; /* Distant join */ if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join); ret = BuildStationPart(&st, flags, reuse, dock_area, STATIONNAMING_DOCK); if (ret.Failed()) return ret; if (st != NULL && st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK); if (flags & DC_EXEC) { st->dock_tile = tile; st->AddFacility(FACIL_DOCK, tile); st->rect.BeforeAddRect(dock_area.tile, dock_area.w, dock_area.h, StationRect::ADD_TRY); /* If the water part of the dock is on a canal, update infrastructure counts. * This is needed as we've unconditionally cleared that tile before. */ if (wc == WATER_CLASS_CANAL) { Company::Get(st->owner)->infrastructure.water++; } Company::Get(st->owner)->infrastructure.station += 2; DirtyCompanyInfrastructureWindows(st->owner); MakeDock(tile, st->owner, st->index, direction, wc); st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); InvalidateWindowData(WC_SELECT_STATION, 0, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_SHIPS); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]); } /** * Remove a dock * @param tile TileIndex been queried * @param flags operation to perform * @return cost or failure of operation */ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) { Station *st = Station::GetByTile(tile); CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; TileIndex docking_location = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); TileIndex tile1 = st->dock_tile; TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1)); ret = EnsureNoVehicleOnGround(tile1); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2); if (ret.Failed()) return ret; if (flags & DC_EXEC) { DoClearSquare(tile1); MarkTileDirtyByTile(tile1); MakeWaterKeepingClass(tile2, st->owner); st->rect.AfterRemoveTile(st, tile1); st->rect.AfterRemoveTile(st, tile2); st->dock_tile = INVALID_TILE; st->facilities &= ~FACIL_DOCK; Company::Get(st->owner)->infrastructure.station -= 2; DirtyCompanyInfrastructureWindows(st->owner); SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_SHIPS); st->UpdateVirtCoord(); st->RecomputeIndustriesNear(); DeleteStationIfEmpty(st); /* All ships that were going to our station, can't go to it anymore. * Just clear the order, then automatically the next appropriate order * will be selected and in case of no appropriate order it will just * wander around the world. */ Ship *s; FOR_ALL_SHIPS(s) { if (s->current_order.IsType(OT_LOADING) && s->tile == docking_location) { s->LeaveStation(); } if (s->dest_tile == docking_location) { s->dest_tile = 0; s->current_order.Free(); } } } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]); } #include "table/station_land.h" const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx) { return &_station_display_datas[st][gfx]; } /** * Check whether a sprite is a track sprite, which can be replaced by a non-track ground sprite and a rail overlay. * If the ground sprite is suitable, \a ground is replaced with the new non-track ground sprite, and \a overlay_offset * is set to the overlay to draw. * @param ti Positional info for the tile to decide snowyness etc. May be NULL. * @param [in,out] ground Groundsprite to draw. * @param [out] overlay_offset Overlay to draw. * @return true if overlay can be drawn. */ bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset) { bool snow_desert; switch (*ground) { case SPR_RAIL_TRACK_X: snow_desert = false; *overlay_offset = RTO_X; break; case SPR_RAIL_TRACK_Y: snow_desert = false; *overlay_offset = RTO_Y; break; case SPR_RAIL_TRACK_X_SNOW: snow_desert = true; *overlay_offset = RTO_X; break; case SPR_RAIL_TRACK_Y_SNOW: snow_desert = true; *overlay_offset = RTO_Y; break; default: return false; } if (ti != NULL) { /* Decide snow/desert from tile */ switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: snow_desert = (uint)ti->z > GetSnowLine() * TILE_HEIGHT; break; case LT_TROPIC: snow_desert = GetTropicZone(ti->tile) == TROPICZONE_DESERT; break; default: break; } } *ground = snow_desert ? SPR_FLAT_SNOW_DESERT_TILE : SPR_FLAT_GRASS_TILE; return true; } static void DrawTile_Station(TileInfo *ti) { const NewGRFSpriteLayout *layout = NULL; DrawTileSprites tmp_rail_layout; const DrawTileSprites *t = NULL; RoadTypes roadtypes; int32 total_offset; const RailtypeInfo *rti = NULL; uint32 relocation = 0; uint32 ground_relocation = 0; BaseStation *st = NULL; const StationSpec *statspec = NULL; uint tile_layout = 0; if (HasStationRail(ti->tile)) { rti = GetRailTypeInfo(GetRailType(ti->tile)); roadtypes = ROADTYPES_NONE; total_offset = rti->GetRailtypeSpriteOffset(); if (IsCustomStationSpecIndex(ti->tile)) { /* look for customization */ st = BaseStation::GetByTile(ti->tile); statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec; if (statspec != NULL) { tile_layout = GetStationGfx(ti->tile); if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) { uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile); if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile); } /* Ensure the chosen tile layout is valid for this custom station */ if (statspec->renderdata != NULL) { layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)]; if (!layout->NeedsPreprocessing()) { t = layout; layout = NULL; } } } } } else { roadtypes = IsRoadStop(ti->tile) ? GetRoadTypes(ti->tile) : ROADTYPES_NONE; total_offset = 0; } StationGfx gfx = GetStationGfx(ti->tile); if (IsAirport(ti->tile)) { gfx = GetAirportGfx(ti->tile); if (gfx >= NEW_AIRPORTTILE_OFFSET) { const AirportTileSpec *ats = AirportTileSpec::Get(gfx); if (ats->grf_prop.spritegroup[0] != NULL && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) { return; } /* No sprite group (or no valid one) found, meaning no graphics associated. * Use the substitute one instead */ assert(ats->grf_prop.subst_id != INVALID_AIRPORTTILE); gfx = ats->grf_prop.subst_id; } switch (gfx) { case APT_RADAR_GRASS_FENCE_SW: t = &_station_display_datas_airport_radar_grass_fence_sw[GetAnimationFrame(ti->tile)]; break; case APT_GRASS_FENCE_NE_FLAG: t = &_station_display_datas_airport_flag_grass_fence_ne[GetAnimationFrame(ti->tile)]; break; case APT_RADAR_FENCE_SW: t = &_station_display_datas_airport_radar_fence_sw[GetAnimationFrame(ti->tile)]; break; case APT_RADAR_FENCE_NE: t = &_station_display_datas_airport_radar_fence_ne[GetAnimationFrame(ti->tile)]; break; case APT_GRASS_FENCE_NE_FLAG_2: t = &_station_display_datas_airport_flag_grass_fence_ne_2[GetAnimationFrame(ti->tile)]; break; } } Owner owner = GetTileOwner(ti->tile); PaletteID palette; if (Company::IsValidID(owner)) { palette = COMPANY_SPRITE_COLOUR(owner); } else { /* Some stations are not owner by a company, namely oil rigs */ palette = PALETTE_TO_GREY; } if (layout == NULL && (t == NULL || t->seq == NULL)) t = GetStationTileLayout(GetStationType(ti->tile), gfx); /* don't show foundation for docks */ if (ti->tileh != SLOPE_FLAT && !IsDock(ti->tile)) { if (statspec != NULL && HasBit(statspec->flags, SSF_CUSTOM_FOUNDATIONS)) { /* Station has custom foundations. * Check whether the foundation continues beyond the tile's upper sides. */ uint edge_info = 0; int z; Slope slope = GetFoundationPixelSlope(ti->tile, &z); if (!HasFoundationNW(ti->tile, slope, z)) SetBit(edge_info, 0); if (!HasFoundationNE(ti->tile, slope, z)) SetBit(edge_info, 1); SpriteID image = GetCustomStationFoundationRelocation(statspec, st, ti->tile, tile_layout, edge_info); if (image == 0) goto draw_default_foundation; if (HasBit(statspec->flags, SSF_EXTENDED_FOUNDATIONS)) { /* Station provides extended foundations. */ static const uint8 foundation_parts[] = { 0, 0, 0, 0, // Invalid, Invalid, Invalid, SLOPE_SW 0, 1, 2, 3, // Invalid, SLOPE_EW, SLOPE_SE, SLOPE_WSE 0, 4, 5, 6, // Invalid, SLOPE_NW, SLOPE_NS, SLOPE_NWS 7, 8, 9 // SLOPE_NE, SLOPE_ENW, SLOPE_SEN }; AddSortableSpriteToDraw(image + foundation_parts[ti->tileh], PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z); } else { /* Draw simple foundations, built up from 8 possible foundation sprites. */ /* Each set bit represents one of the eight composite sprites to be drawn. * 'Invalid' entries will not drawn but are included for completeness. */ static const uint8 composite_foundation_parts[] = { /* Invalid (00000000), Invalid (11010001), Invalid (11100100), SLOPE_SW (11100000) */ 0x00, 0xD1, 0xE4, 0xE0, /* Invalid (11001010), SLOPE_EW (11001001), SLOPE_SE (11000100), SLOPE_WSE (11000000) */ 0xCA, 0xC9, 0xC4, 0xC0, /* Invalid (11010010), SLOPE_NW (10010001), SLOPE_NS (11100100), SLOPE_NWS (10100000) */ 0xD2, 0x91, 0xE4, 0xA0, /* SLOPE_NE (01001010), SLOPE_ENW (00001001), SLOPE_SEN (01000100) */ 0x4A, 0x09, 0x44 }; uint8 parts = composite_foundation_parts[ti->tileh]; /* If foundations continue beyond the tile's upper sides then * mask out the last two pieces. */ if (HasBit(edge_info, 0)) ClrBit(parts, 6); if (HasBit(edge_info, 1)) ClrBit(parts, 7); if (parts == 0) { /* We always have to draw at least one sprite to make sure there is a boundingbox and a sprite with the * correct offset for the childsprites. * So, draw the (completely empty) sprite of the default foundations. */ goto draw_default_foundation; } StartSpriteCombine(); for (int i = 0; i < 8; i++) { if (HasBit(parts, i)) { AddSortableSpriteToDraw(image + i, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z); } } EndSpriteCombine(); } OffsetGroundSprite(31, 1); ti->z += ApplyPixelFoundationToSlope(FOUNDATION_LEVELED, &ti->tileh); } else { draw_default_foundation: DrawFoundation(ti, FOUNDATION_LEVELED); } } if (IsBuoy(ti->tile)) { DrawWaterClassGround(ti); SpriteID sprite = GetCanalSprite(CF_BUOY, ti->tile); if (sprite != 0) total_offset = sprite - SPR_IMG_BUOY; } else if (IsDock(ti->tile) || (IsOilRig(ti->tile) && IsTileOnWater(ti->tile))) { if (ti->tileh == SLOPE_FLAT) { DrawWaterClassGround(ti); } else { assert(IsDock(ti->tile)); TileIndex water_tile = ti->tile + TileOffsByDiagDir(GetDockDirection(ti->tile)); WaterClass wc = GetWaterClass(water_tile); if (wc == WATER_CLASS_SEA) { DrawShoreTile(ti->tileh); } else { DrawClearLandTile(ti, 3); } } } else { if (layout != NULL) { /* Sprite layout which needs preprocessing */ bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND); uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground); uint8 var10; FOR_EACH_SET_BIT(var10, var10_values) { uint32 var10_relocation = GetCustomStationRelocation(statspec, st, ti->tile, var10); layout->ProcessRegisters(var10, var10_relocation, separate_ground); } tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground); t = &tmp_rail_layout; total_offset = 0; } else if (statspec != NULL) { /* Simple sprite layout */ ground_relocation = relocation = GetCustomStationRelocation(statspec, st, ti->tile, 0); if (HasBit(statspec->flags, SSF_SEPARATE_GROUND)) { ground_relocation = GetCustomStationRelocation(statspec, st, ti->tile, 1); } ground_relocation += rti->fallback_railtype; } SpriteID image = t->ground.sprite; PaletteID pal = t->ground.pal; RailTrackOffset overlay_offset; if (rti != NULL && rti->UsesOverlay() && SplitGroundSpriteForOverlay(ti, &image, &overlay_offset)) { SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND); DrawGroundSprite(image, PAL_NONE); DrawGroundSprite(ground + overlay_offset, PAL_NONE); if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationReservation(ti->tile)) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); DrawGroundSprite(overlay + overlay_offset, PALETTE_CRASH); } } else { image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset; if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation; DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette)); /* PBS debugging, draw reserved tracks darker */ if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasStationRail(ti->tile) && HasStationReservation(ti->tile)) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); DrawGroundSprite(GetRailStationAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH); } } } if (HasStationRail(ti->tile) && HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti); if (HasBit(roadtypes, ROADTYPE_TRAM)) { Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; DrawGroundSprite((HasBit(roadtypes, ROADTYPE_ROAD) ? SPR_TRAMWAY_OVERLAY : SPR_TRAMWAY_TRAM) + (axis ^ 1), PAL_NONE); DrawTramCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y); } if (IsRailWaypoint(ti->tile)) { /* Don't offset the waypoint graphics; they're always the same. */ total_offset = 0; } DrawRailTileSeq(ti, t, TO_BUILDINGS, total_offset, relocation, palette); } void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image) { int32 total_offset = 0; PaletteID pal = COMPANY_SPRITE_COLOUR(_local_company); const DrawTileSprites *t = GetStationTileLayout(st, image); const RailtypeInfo *rti = NULL; if (railtype != INVALID_RAILTYPE) { rti = GetRailTypeInfo(railtype); total_offset = rti->GetRailtypeSpriteOffset(); } SpriteID img = t->ground.sprite; RailTrackOffset overlay_offset; if (rti != NULL && rti->UsesOverlay() && SplitGroundSpriteForOverlay(NULL, &img, &overlay_offset)) { SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND); DrawSprite(img, PAL_NONE, x, y); DrawSprite(ground + overlay_offset, PAL_NONE, x, y); } else { DrawSprite(img + total_offset, HasBit(img, PALETTE_MODIFIER_COLOUR) ? pal : PAL_NONE, x, y); } if (roadtype == ROADTYPE_TRAM) { DrawSprite(SPR_TRAMWAY_TRAM + (t->ground.sprite == SPR_ROAD_PAVED_STRAIGHT_X ? 1 : 0), PAL_NONE, x, y); } /* Default waypoint has no railtype specific sprites */ DrawRailTileSeqInGUI(x, y, t, st == STATION_WAYPOINT ? 0 : total_offset, 0, pal); } static int GetSlopePixelZ_Station(TileIndex tile, uint x, uint y) { return GetTileMaxPixelZ(tile); } static Foundation GetFoundation_Station(TileIndex tile, Slope tileh) { return FlatteningFoundation(tileh); } static void GetTileDesc_Station(TileIndex tile, TileDesc *td) { td->owner[0] = GetTileOwner(tile); if (IsDriveThroughStopTile(tile)) { Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; RoadTypes rts = GetRoadTypes(tile); if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); /* Is there a mix of owners? */ if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { uint i = 1; if (road_owner != INVALID_OWNER) { td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; td->owner[i] = road_owner; i++; } if (tram_owner != INVALID_OWNER) { td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; td->owner[i] = tram_owner; } } } td->build_date = BaseStation::GetByTile(tile)->build_date; if (HasStationTileRail(tile)) { const StationSpec *spec = GetStationSpec(tile); if (spec != NULL) { td->station_class = StationClass::Get(spec->cls_id)->name; td->station_name = spec->name; if (spec->grf_prop.grffile != NULL) { const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid); td->grf = gc->GetName(); } } const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); td->rail_speed = rti->max_speed; } if (IsAirport(tile)) { const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec(); td->airport_class = AirportClass::Get(as->cls_id)->name; td->airport_name = as->name; const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); td->airport_tile_name = ats->name; if (as->grf_prop.grffile != NULL) { const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid); td->grf = gc->GetName(); } else if (ats->grf_prop.grffile != NULL) { const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid); td->grf = gc->GetName(); } } StringID str; switch (GetStationType(tile)) { default: NOT_REACHED(); case STATION_RAIL: str = STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION; break; case STATION_AIRPORT: str = (IsHangar(tile) ? STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_LAI_STATION_DESCRIPTION_AIRPORT); break; case STATION_TRUCK: str = STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break; case STATION_BUS: str = STR_LAI_STATION_DESCRIPTION_BUS_STATION; break; case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break; case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break; case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break; case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break; } td->str = str; } static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { TrackBits trackbits = TRACK_BIT_NONE; switch (mode) { case TRANSPORT_RAIL: if (HasStationRail(tile) && !IsStationTileBlocked(tile)) { trackbits = TrackToTrackBits(GetRailStationTrack(tile)); } break; case TRANSPORT_WATER: /* buoy is coded as a station, it is always on open water */ if (IsBuoy(tile)) { trackbits = TRACK_BIT_ALL; /* remove tracks that connect NE map edge */ if (TileX(tile) == 0) trackbits &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT); /* remove tracks that connect NW map edge */ if (TileY(tile) == 0) trackbits &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER); } break; case TRANSPORT_ROAD: if ((GetRoadTypes(tile) & sub_mode) != 0 && IsRoadStop(tile)) { DiagDirection dir = GetRoadStopDir(tile); Axis axis = DiagDirToAxis(dir); if (side != INVALID_DIAGDIR) { if (axis != DiagDirToAxis(side) || (IsStandardRoadStopTile(tile) && dir != side)) break; } trackbits = AxisToTrackBits(axis); } break; default: break; } return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), TRACKDIR_BIT_NONE); } static void TileLoop_Station(TileIndex tile) { /* FIXME -- GetTileTrackStatus_Station -> animated stationtiles * hardcoded.....not good */ switch (GetStationType(tile)) { case STATION_AIRPORT: AirportTileAnimationTrigger(Station::GetByTile(tile), tile, AAT_TILELOOP); break; case STATION_DOCK: if (!IsTileFlat(tile)) break; // only handle water part /* FALL THROUGH */ case STATION_OILRIG: //(station part) case STATION_BUOY: TileLoop_Water(tile); break; default: break; } } static void AnimateTile_Station(TileIndex tile) { if (HasStationRail(tile)) { AnimateStationTile(tile); return; } if (IsAirport(tile)) { AnimateAirportTile(tile); } } static bool ClickTile_Station(TileIndex tile) { const BaseStation *bst = BaseStation::GetByTile(tile); if (bst->facilities & FACIL_WAYPOINT) { ShowWaypointWindow(Waypoint::From(bst)); } else if (IsHangar(tile)) { const Station *st = Station::From(bst); ShowDepotWindow(st->airport.GetHangarTile(st->airport.GetHangarNum(tile)), VEH_AIRCRAFT); } else { ShowStationViewWindow(bst->index); } return true; } static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, int x, int y) { if (v->type == VEH_TRAIN) { StationID station_id = GetStationIndex(tile); if (!v->current_order.ShouldStopAtStation(v, station_id)) return VETSB_CONTINUE; if (!IsRailStation(tile) || !v->IsFrontEngine()) return VETSB_CONTINUE; int station_ahead; int station_length; int stop = GetTrainStopLocation(station_id, tile, Train::From(v), &station_ahead, &station_length); /* Stop whenever that amount of station ahead + the distance from the * begin of the platform to the stop location is longer than the length * of the platform. Station ahead 'includes' the current tile where the * vehicle is on, so we need to subtract that. */ if (stop + station_ahead - (int)TILE_SIZE >= station_length) return VETSB_CONTINUE; DiagDirection dir = DirToDiagDir(v->direction); x &= 0xF; y &= 0xF; if (DiagDirToAxis(dir) != AXIS_X) Swap(x, y); if (y == TILE_SIZE / 2) { if (dir != DIAGDIR_SE && dir != DIAGDIR_SW) x = TILE_SIZE - 1 - x; stop &= TILE_SIZE - 1; if (x == stop) { return VETSB_ENTERED_STATION | (VehicleEnterTileStatus)(station_id << VETS_STATION_ID_OFFSET); // enter station } else if (x < stop) { v->vehstatus |= VS_TRAIN_SLOWING; uint16 spd = max(0, (stop - x) * 20 - 15); if (spd < v->cur_speed) v->cur_speed = spd; } } } else if (v->type == VEH_ROAD) { RoadVehicle *rv = RoadVehicle::From(v); if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) { if (IsRoadStop(tile) && rv->IsFrontEngine()) { /* Attempt to allocate a parking bay in a road stop */ return RoadStop::GetByTile(tile, GetRoadStopType(tile))->Enter(rv) ? VETSB_CONTINUE : VETSB_CANNOT_ENTER; } } } return VETSB_CONTINUE; } /** * Run the watched cargo callback for all houses in the catchment area. * @param st Station. */ void TriggerWatchedCargoCallbacks(Station *st) { /* Collect cargoes accepted since the last big tick. */ uint cargoes = 0; for (CargoID cid = 0; cid < NUM_CARGO; cid++) { if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(cargoes, cid); } /* Anything to do? */ if (cargoes == 0) return; /* Loop over all houses in the catchment. */ Rect r = st->GetCatchmentRect(); TileArea ta(TileXY(r.left, r.top), TileXY(r.right, r.bottom)); TILE_AREA_LOOP(tile, ta) { if (IsTileType(tile, MP_HOUSE)) { WatchedCargoCallback(tile, cargoes); } } } /** * This function is called for each station once every 250 ticks. * Not all stations will get the tick at the same time. * @param st the station receiving the tick. * @return true if the station is still valid (wasn't deleted) */ static bool StationHandleBigTick(BaseStation *st) { if (!st->IsInUse()) { if (++st->delete_ctr >= 8) delete st; return false; } if (Station::IsExpected(st)) { TriggerWatchedCargoCallbacks(Station::From(st)); for (CargoID i = 0; i < NUM_CARGO; i++) { ClrBit(Station::From(st)->goods[i].status, GoodsEntry::GES_ACCEPTED_BIGTICK); } } if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true); return true; } static inline void byte_inc_sat(byte *p) { byte b = *p + 1; if (b != 0) *p = b; } /** * Truncate the cargo by a specific amount. * @param cs The type of cargo to perform the truncation for. * @param ge The goods entry, of the station, to truncate. * @param amount The amount to truncate the cargo by. */ static void TruncateCargo(const CargoSpec *cs, GoodsEntry *ge, uint amount = UINT_MAX) { /* If truncating also punish the source stations' ratings to * decrease the flow of incoming cargo. */ StationCargoAmountMap waiting_per_source; ge->cargo.Truncate(amount, &waiting_per_source); for (StationCargoAmountMap::iterator i(waiting_per_source.begin()); i != waiting_per_source.end(); ++i) { Station *source_station = Station::GetIfValid(i->first); if (source_station == NULL) continue; GoodsEntry &source_ge = source_station->goods[cs->Index()]; source_ge.max_waiting_cargo = max(source_ge.max_waiting_cargo, i->second); } } static void UpdateStationRating(Station *st) { bool waiting_changed = false; byte_inc_sat(&st->time_since_load); byte_inc_sat(&st->time_since_unload); const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { GoodsEntry *ge = &st->goods[cs->Index()]; /* Slowly increase the rating back to his original level in the case we * didn't deliver cargo yet to this station. This happens when a bribe * failed while you didn't moved that cargo yet to a station. */ if (!ge->HasRating() && ge->rating < INITIAL_STATION_RATING) { ge->rating++; } /* Only change the rating if we are moving this cargo */ if (ge->HasRating()) { byte_inc_sat(&ge->time_since_pickup); if (ge->time_since_pickup == 255 && _settings_game.order.selectgoods) { ClrBit(ge->status, GoodsEntry::GES_RATING); ge->last_speed = 0; TruncateCargo(cs, ge); waiting_changed = true; continue; } bool skip = false; int rating = 0; uint waiting = ge->cargo.TotalCount(); /* num_dests is at least 1 if there is any cargo as * INVALID_STATION is also a destination. */ uint num_dests = (uint)ge->cargo.Packets()->MapSize(); /* Average amount of cargo per next hop, but prefer solitary stations * with only one or two next hops. They are allowed to have more * cargo waiting per next hop. * With manual cargo distribution waiting_avg = waiting / 2 as then * INVALID_STATION is the only destination. */ uint waiting_avg = waiting / (num_dests + 1); if (HasBit(cs->callback_mask, CBM_CARGO_STATION_RATING_CALC)) { /* Perform custom station rating. If it succeeds the speed, days in transit and * waiting cargo ratings must not be executed. */ /* NewGRFs expect last speed to be 0xFF when no vehicle has arrived yet. */ uint last_speed = ge->HasVehicleEverTriedLoading() ? ge->last_speed : 0xFF; uint32 var18 = min(ge->time_since_pickup, 0xFF) | (min(ge->max_waiting_cargo, 0xFFFF) << 8) | (min(last_speed, 0xFF) << 24); /* Convert to the 'old' vehicle types */ uint32 var10 = (st->last_vehicle_type == VEH_INVALID) ? 0x0 : (st->last_vehicle_type + 0x10); uint16 callback = GetCargoCallback(CBID_CARGO_STATION_RATING_CALC, var10, var18, cs); if (callback != CALLBACK_FAILED) { skip = true; rating = GB(callback, 0, 14); /* Simulate a 15 bit signed value */ if (HasBit(callback, 14)) rating -= 0x4000; } } if (!skip) { int b = ge->last_speed - 85; if (b >= 0) rating += b >> 2; byte waittime = ge->time_since_pickup; if (st->last_vehicle_type == VEH_SHIP) waittime >>= 2; (waittime > 21) || (rating += 25, waittime > 12) || (rating += 25, waittime > 6) || (rating += 45, waittime > 3) || (rating += 35, true); (rating -= 90, ge->max_waiting_cargo > 1500) || (rating += 55, ge->max_waiting_cargo > 1000) || (rating += 35, ge->max_waiting_cargo > 600) || (rating += 10, ge->max_waiting_cargo > 300) || (rating += 20, ge->max_waiting_cargo > 100) || (rating += 10, true); } if (Company::IsValidID(st->owner) && HasBit(st->town->statues, st->owner)) rating += 26; byte age = ge->last_age; (age >= 3) || (rating += 10, age >= 2) || (rating += 10, age >= 1) || (rating += 13, true); { int or_ = ge->rating; // old rating /* only modify rating in steps of -2, -1, 0, 1 or 2 */ ge->rating = rating = or_ + Clamp(Clamp(rating, 0, 255) - or_, -2, 2); /* if rating is <= 64 and more than 100 items waiting on average per destination, * remove some random amount of goods from the station */ if (rating <= 64 && waiting_avg >= 100) { int dec = Random() & 0x1F; if (waiting_avg < 200) dec &= 7; waiting -= (dec + 1) * num_dests; waiting_changed = true; } /* if rating is <= 127 and there are any items waiting, maybe remove some goods. */ if (rating <= 127 && waiting != 0) { uint32 r = Random(); if (rating <= (int)GB(r, 0, 7)) { /* Need to have int, otherwise it will just overflow etc. */ waiting = max((int)waiting - (int)((GB(r, 8, 2) - 1) * num_dests), 0); waiting_changed = true; } } /* At some point we really must cap the cargo. Previously this * was a strict 4095, but now we'll have a less strict, but * increasingly aggressive truncation of the amount of cargo. */ static const uint WAITING_CARGO_THRESHOLD = 1 << 12; static const uint WAITING_CARGO_CUT_FACTOR = 1 << 6; static const uint MAX_WAITING_CARGO = 1 << 15; if (waiting > WAITING_CARGO_THRESHOLD) { uint difference = waiting - WAITING_CARGO_THRESHOLD; waiting -= (difference / WAITING_CARGO_CUT_FACTOR); waiting = min(waiting, MAX_WAITING_CARGO); waiting_changed = true; } /* We can't truncate cargo that's already reserved for loading. * Thus StoredCount() here. */ if (waiting_changed && waiting < ge->cargo.AvailableCount()) { /* Feed back the exact own waiting cargo at this station for the * next rating calculation. */ ge->max_waiting_cargo = 0; TruncateCargo(cs, ge, ge->cargo.AvailableCount() - waiting); } else { /* If the average number per next hop is low, be more forgiving. */ ge->max_waiting_cargo = waiting_avg; } } } } StationID index = st->index; if (waiting_changed) { SetWindowDirty(WC_STATION_VIEW, index); // update whole window } else { SetWindowWidgetDirty(WC_STATION_VIEW, index, WID_SV_ACCEPT_RATING_LIST); // update only ratings list } } /** * Reroute cargo of type c at station st or in any vehicles unloading there. * Make sure the cargo's new next hop is neither "avoid" nor "avoid2". * @param st Station to be rerouted at. * @param c Type of cargo. * @param avoid Original next hop of cargo, avoid this. * @param avoid2 Another station to be avoided when rerouting. */ void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2) { GoodsEntry &ge = st->goods[c]; /* Reroute cargo in station. */ ge.cargo.Reroute(UINT_MAX, &ge.cargo, avoid, avoid2, &ge); /* Reroute cargo staged to be transfered. */ for (std::list::iterator it(st->loading_vehicles.begin()); it != st->loading_vehicles.end(); ++it) { for (Vehicle *v = *it; v != NULL; v = v->Next()) { if (v->cargo_type != c) continue; v->cargo.Reroute(UINT_MAX, &v->cargo, avoid, avoid2, &ge); } } } /** * Check all next hops of cargo packets in this station for existance of a * a valid link they may use to travel on. Reroute any cargo not having a valid * link and remove timed out links found like this from the linkgraph. We're * not all links here as that is expensive and useless. A link no one is using * doesn't hurt either. * @param from Station to check. */ void DeleteStaleLinks(Station *from) { for (CargoID c = 0; c < NUM_CARGO; ++c) { GoodsEntry &ge = from->goods[c]; LinkGraph *lg = LinkGraph::GetIfValid(ge.link_graph); if (lg == NULL) continue; Node node = (*lg)[ge.node]; for (EdgeIterator it(node.Begin()); it != node.End();) { Edge edge = it->second; Station *to = Station::Get((*lg)[it->first].Station()); assert(to->goods[c].node == it->first); ++it; // Do that before removing the edge. Anything else may crash. assert(_date >= edge.LastUpdate()); uint timeout = LinkGraph::MIN_TIMEOUT_DISTANCE + (DistanceManhattan(from->xy, to->xy) >> 3); if ((uint)(_date - edge.LastUpdate()) > timeout) { /* Have all vehicles refresh their next hops before deciding to * remove the node. */ bool updated = false; OrderList *l; FOR_ALL_ORDER_LISTS(l) { bool found_from = false; bool found_to = false; for (Order *order = l->GetFirstOrder(); order != NULL; order = order->next) { if (!order->IsType(OT_GOTO_STATION) && !order->IsType(OT_IMPLICIT)) continue; if (order->GetDestination() == from->index) { found_from = true; if (found_to) break; } else if (order->GetDestination() == to->index) { found_to = true; if (found_from) break; } } if (!found_to || !found_from) continue; for (Vehicle *v = l->GetFirstSharedVehicle(); !updated && v != NULL; v = v->NextShared()) { /* There is potential for optimization here: * - Usually consists of the same order list are the same. It's probably better to * first check the first of each list, then the second of each list and so on. * - We could try to figure out if we've seen a consist with the same cargo on the * same list already and if the consist can actually carry the cargo we're looking * for. With conditional and refit orders this is not quite trivial, though. */ LinkRefresher::Run(v, false); // Don't allow merging. Otherwise lg might get deleted. if (edge.LastUpdate() == _date) updated = true; } if (updated) break; } if (!updated) { /* If it's still considered dead remove it. */ node.RemoveEdge(to->goods[c].node); ge.flows.DeleteFlows(to->index); RerouteCargo(from, c, to->index, from->index); } } else if (edge.LastUnrestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastUnrestrictedUpdate()) > timeout) { edge.Restrict(); ge.flows.RestrictFlows(to->index); RerouteCargo(from, c, to->index, from->index); } else if (edge.LastRestrictedUpdate() != INVALID_DATE && (uint)(_date - edge.LastRestrictedUpdate()) > timeout) { edge.Release(); } } assert(_date >= lg->LastCompression()); if ((uint)(_date - lg->LastCompression()) > LinkGraph::COMPRESSION_INTERVAL) { lg->Compress(); } } } /** * Increase capacity for a link stat given by station cargo and next hop. * @param st Station to get the link stats from. * @param cargo Cargo to increase stat for. * @param next_station_id Station the consist will be travelling to next. * @param capacity Capacity to add to link stat. * @param usage Usage to add to link stat. * @param mode Update mode to be applied. */ void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode) { GoodsEntry &ge1 = st->goods[cargo]; Station *st2 = Station::Get(next_station_id); GoodsEntry &ge2 = st2->goods[cargo]; LinkGraph *lg = NULL; if (ge1.link_graph == INVALID_LINK_GRAPH) { if (ge2.link_graph == INVALID_LINK_GRAPH) { if (LinkGraph::CanAllocateItem()) { lg = new LinkGraph(cargo); LinkGraphSchedule::instance.Queue(lg); ge2.link_graph = lg->index; ge2.node = lg->AddNode(st2); } else { DEBUG(misc, 0, "Can't allocate link graph"); } } else { lg = LinkGraph::Get(ge2.link_graph); } if (lg) { ge1.link_graph = lg->index; ge1.node = lg->AddNode(st); } } else if (ge2.link_graph == INVALID_LINK_GRAPH) { lg = LinkGraph::Get(ge1.link_graph); ge2.link_graph = lg->index; ge2.node = lg->AddNode(st2); } else { lg = LinkGraph::Get(ge1.link_graph); if (ge1.link_graph != ge2.link_graph) { LinkGraph *lg2 = LinkGraph::Get(ge2.link_graph); if (lg->Size() < lg2->Size()) { LinkGraphSchedule::instance.Unqueue(lg); lg2->Merge(lg); // Updates GoodsEntries of lg lg = lg2; } else { LinkGraphSchedule::instance.Unqueue(lg2); lg->Merge(lg2); // Updates GoodsEntries of lg2 } } } if (lg != NULL) { (*lg)[ge1.node].UpdateEdge(ge2.node, capacity, usage, mode); } } /** * Increase capacity for all link stats associated with vehicles in the given consist. * @param st Station to get the link stats from. * @param front First vehicle in the consist. * @param next_station_id Station the consist will be travelling to next. */ void IncreaseStats(Station *st, const Vehicle *front, StationID next_station_id) { for (const Vehicle *v = front; v != NULL; v = v->Next()) { if (v->refit_cap > 0) { /* The cargo count can indeed be higher than the refit_cap if * wagons have been auto-replaced and subsequently auto- * refitted to a higher capacity. The cargo gets redistributed * among the wagons in that case. * As usage is not such an important figure anyway we just * ignore the additional cargo then.*/ IncreaseStats(st, v->cargo_type, next_station_id, v->refit_cap, min(v->refit_cap, v->cargo.StoredCount()), EUM_INCREASE); } } } /* called for every station each tick */ static void StationHandleSmallTick(BaseStation *st) { if ((st->facilities & FACIL_WAYPOINT) != 0 || !st->IsInUse()) return; byte b = st->delete_ctr + 1; if (b >= STATION_RATING_TICKS) b = 0; st->delete_ctr = b; if (b == 0) UpdateStationRating(Station::From(st)); } void OnTick_Station() { if (_game_mode == GM_EDITOR) return; BaseStation *st; FOR_ALL_BASE_STATIONS(st) { StationHandleSmallTick(st); /* Clean up the link graph about once a week. */ if (Station::IsExpected(st) && (_tick_counter + st->index) % STATION_LINKGRAPH_TICKS == 0) { DeleteStaleLinks(Station::From(st)); }; /* Run STATION_ACCEPTANCE_TICKS = 250 tick interval trigger for station animation. * Station index is included so that triggers are not all done * at the same time. */ if ((_tick_counter + st->index) % STATION_ACCEPTANCE_TICKS == 0) { /* Stop processing this station if it was deleted */ if (!StationHandleBigTick(st)) continue; TriggerStationAnimation(st, st->xy, SAT_250_TICKS); if (Station::IsExpected(st)) AirportAnimationTrigger(Station::From(st), AAT_STATION_250_TICKS); } } } /** Monthly loop for stations. */ void StationMonthlyLoop() { Station *st; FOR_ALL_STATIONS(st) { for (CargoID i = 0; i < NUM_CARGO; i++) { GoodsEntry *ge = &st->goods[i]; SB(ge->status, GoodsEntry::GES_LAST_MONTH, 1, GB(ge->status, GoodsEntry::GES_CURRENT_MONTH, 1)); ClrBit(ge->status, GoodsEntry::GES_CURRENT_MONTH); } } } void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius) { Station *st; FOR_ALL_STATIONS(st) { if (st->owner == owner && DistanceManhattan(tile, st->xy) <= radius) { for (CargoID i = 0; i < NUM_CARGO; i++) { GoodsEntry *ge = &st->goods[i]; if (ge->status != 0) { ge->rating = Clamp(ge->rating + amount, 0, 255); } } } } } static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceType source_type, SourceID source_id) { /* We can't allocate a CargoPacket? Then don't do anything * at all; i.e. just discard the incoming cargo. */ if (!CargoPacket::CanAllocateItem()) return 0; GoodsEntry &ge = st->goods[type]; amount += ge.amount_fract; ge.amount_fract = GB(amount, 0, 8); amount >>= 8; /* No new "real" cargo item yet. */ if (amount == 0) return 0; StationID next = ge.GetVia(st->index); ge.cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next); LinkGraph *lg = NULL; if (ge.link_graph == INVALID_LINK_GRAPH) { if (LinkGraph::CanAllocateItem()) { lg = new LinkGraph(type); LinkGraphSchedule::instance.Queue(lg); ge.link_graph = lg->index; ge.node = lg->AddNode(st); } else { DEBUG(misc, 0, "Can't allocate link graph"); } } else { lg = LinkGraph::Get(ge.link_graph); } if (lg != NULL) (*lg)[ge.node].UpdateSupply(amount); if (!ge.HasRating()) { InvalidateWindowData(WC_STATION_LIST, st->index); SetBit(ge.status, GoodsEntry::GES_RATING); } TriggerStationRandomisation(st, st->xy, SRT_NEW_CARGO, type); TriggerStationAnimation(st, st->xy, SAT_NEW_CARGO, type); AirportAnimationTrigger(st, AAT_STATION_NEW_CARGO, type); SetWindowDirty(WC_STATION_VIEW, st->index); st->MarkTilesDirty(true); return amount; } static bool IsUniqueStationName(const char *name) { const Station *st; FOR_ALL_STATIONS(st) { if (st->name != NULL && strcmp(st->name, name) == 0) return false; } return true; } /** * Rename a station * @param tile unused * @param flags operation to perform * @param p1 station ID that is to be renamed * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Station *st = Station::GetIfValid(p1); if (st == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_STATION_NAME_CHARS) return CMD_ERROR; if (!IsUniqueStationName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { free(st->name); st->name = reset ? NULL : stredup(text); st->UpdateVirtCoord(); InvalidateWindowData(WC_STATION_LIST, st->owner, 1); } return CommandCost(); } /** * Find all stations around a rectangular producer (industry, house, headquarter, ...) * * @param location The location/area of the producer * @param stations The list to store the stations in */ void FindStationsAroundTiles(const TileArea &location, StationList *stations) { /* area to search = producer plus station catchment radius */ uint max_rad = (_settings_game.station.modified_catchment ? MAX_CATCHMENT : CA_UNMODIFIED); uint x = TileX(location.tile); uint y = TileY(location.tile); uint min_x = (x > max_rad) ? x - max_rad : 0; uint max_x = x + location.w + max_rad; uint min_y = (y > max_rad) ? y - max_rad : 0; uint max_y = y + location.h + max_rad; if (min_x == 0 && _settings_game.construction.freeform_edges) min_x = 1; if (min_y == 0 && _settings_game.construction.freeform_edges) min_y = 1; if (max_x >= MapSizeX()) max_x = MapSizeX() - 1; if (max_y >= MapSizeY()) max_y = MapSizeY() - 1; for (uint cy = min_y; cy < max_y; cy++) { for (uint cx = min_x; cx < max_x; cx++) { TileIndex cur_tile = TileXY(cx, cy); if (!IsTileType(cur_tile, MP_STATION)) continue; Station *st = Station::GetByTile(cur_tile); /* st can be NULL in case of waypoints */ if (st == NULL) continue; if (_settings_game.station.modified_catchment) { int rad = st->GetCatchmentRadius(); int rad_x = cx - x; int rad_y = cy - y; if (rad_x < -rad || rad_x >= rad + location.w) continue; if (rad_y < -rad || rad_y >= rad + location.h) continue; } /* Insert the station in the set. This will fail if it has * already been added. */ stations->Include(st); } } } /** * Run a tile loop to find stations around a tile, on demand. Cache the result for further requests * @return pointer to a StationList containing all stations found */ const StationList *StationFinder::GetStations() { if (this->tile != INVALID_TILE) { FindStationsAroundTiles(*this, &this->stations); this->tile = INVALID_TILE; } return &this->stations; } uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations) { /* Return if nothing to do. Also the rounding below fails for 0. */ if (amount == 0) return 0; Station *st1 = NULL; // Station with best rating Station *st2 = NULL; // Second best station uint best_rating1 = 0; // rating of st1 uint best_rating2 = 0; // rating of st2 for (Station * const *st_iter = all_stations->Begin(); st_iter != all_stations->End(); ++st_iter) { Station *st = *st_iter; /* Is the station reserved exclusively for somebody else? */ if (st->town->exclusive_counter > 0 && st->town->exclusivity != st->owner) continue; if (st->goods[type].rating == 0) continue; // Lowest possible rating, better not to give cargo anymore if (_settings_game.order.selectgoods && !st->goods[type].HasVehicleEverTriedLoading()) continue; // Selectively servicing stations, and not this one if (IsCargoInClass(type, CC_PASSENGERS)) { if (st->facilities == FACIL_TRUCK_STOP) continue; // passengers are never served by just a truck stop } else { if (st->facilities == FACIL_BUS_STOP) continue; // non-passengers are never served by just a bus stop } /* This station can be used, add it to st1/st2 */ if (st1 == NULL || st->goods[type].rating >= best_rating1) { st2 = st1; best_rating2 = best_rating1; st1 = st; best_rating1 = st->goods[type].rating; } else if (st2 == NULL || st->goods[type].rating >= best_rating2) { st2 = st; best_rating2 = st->goods[type].rating; } } /* no stations around at all? */ if (st1 == NULL) return 0; /* From now we'll calculate with fractal cargo amounts. * First determine how much cargo we really have. */ amount *= best_rating1 + 1; if (st2 == NULL) { /* only one station around */ return UpdateStationWaiting(st1, type, amount, source_type, source_id); } /* several stations around, the best two (highest rating) are in st1 and st2 */ assert(st1 != NULL); assert(st2 != NULL); assert(best_rating1 != 0 || best_rating2 != 0); /* Then determine the amount the worst station gets. We do it this way as the * best should get a bonus, which in this case is the rounding difference from * this calculation. In reality that will mean the bonus will be pretty low. * Nevertheless, the best station should always get the most cargo regardless * of rounding issues. */ uint worst_cargo = amount * best_rating2 / (best_rating1 + best_rating2); assert(worst_cargo <= (amount - worst_cargo)); /* And then send the cargo to the stations! */ uint moved = UpdateStationWaiting(st1, type, amount - worst_cargo, source_type, source_id); /* These two UpdateStationWaiting's can't be in the statement as then the order * of execution would be undefined and that could cause desyncs with callbacks. */ return moved + UpdateStationWaiting(st2, type, worst_cargo, source_type, source_id); } void BuildOilRig(TileIndex tile) { if (!Station::CanAllocateItem()) { DEBUG(misc, 0, "Can't allocate station for oilrig at 0x%X, reverting to oilrig only", tile); return; } Station *st = new Station(tile); st->town = ClosestTownFromTile(tile, UINT_MAX); st->string_id = GenerateStationName(st, tile, STATIONNAMING_OILRIG); assert(IsTileType(tile, MP_INDUSTRY)); DeleteAnimatedTile(tile); MakeOilrig(tile, st->index, GetWaterClass(tile)); st->owner = OWNER_NONE; st->airport.type = AT_OILRIG; st->airport.Add(tile); st->dock_tile = tile; st->facilities = FACIL_AIRPORT | FACIL_DOCK; st->build_date = _date; st->rect.BeforeAddTile(tile, StationRect::ADD_FORCE); st->UpdateVirtCoord(); UpdateStationAcceptance(st, false); st->RecomputeIndustriesNear(); } void DeleteOilRig(TileIndex tile) { Station *st = Station::GetByTile(tile); MakeWaterKeepingClass(tile, OWNER_NONE); st->dock_tile = INVALID_TILE; st->airport.Clear(); st->facilities &= ~(FACIL_AIRPORT | FACIL_DOCK); st->airport.flags = 0; st->rect.AfterRemoveTile(st, tile); st->UpdateVirtCoord(); st->RecomputeIndustriesNear(); if (!st->IsInUse()) delete st; } static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner) { if (IsRoadStopTile(tile)) { for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { /* Update all roadtypes, no matter if they are present */ if (GetRoadOwner(tile, rt) == old_owner) { if (HasTileRoadType(tile, rt)) { /* A drive-through road-stop has always two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ Company::Get(old_owner)->infrastructure.road[rt] -= 2; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += 2; } SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } } if (!IsTileOwner(tile, old_owner)) return; if (new_owner != INVALID_OWNER) { /* Update company infrastructure counts. Only do it here * if the new owner is valid as otherwise the clear * command will do it for us. No need to dirty windows * here, we'll redraw the whole screen anyway.*/ Company *old_company = Company::Get(old_owner); Company *new_company = Company::Get(new_owner); /* Update counts for underlying infrastructure. */ switch (GetStationType(tile)) { case STATION_RAIL: case STATION_WAYPOINT: if (!IsStationTileBlocked(tile)) { old_company->infrastructure.rail[GetRailType(tile)]--; new_company->infrastructure.rail[GetRailType(tile)]++; } break; case STATION_BUS: case STATION_TRUCK: /* Road stops were already handled above. */ break; case STATION_BUOY: case STATION_DOCK: if (GetWaterClass(tile) == WATER_CLASS_CANAL) { old_company->infrastructure.water--; new_company->infrastructure.water++; } break; default: break; } /* Update station tile count. */ if (!IsBuoy(tile) && !IsAirport(tile)) { old_company->infrastructure.station--; new_company->infrastructure.station++; } /* for buoys, owner of tile is owner of water, st->owner == OWNER_NONE */ SetTileOwner(tile, new_owner); InvalidateWindowClassesData(WC_STATION_LIST, 0); } else { if (IsDriveThroughStopTile(tile)) { /* Remove the drive-through road stop */ DoCommand(tile, 1 | 1 << 8, (GetStationType(tile) == STATION_TRUCK) ? ROADSTOP_TRUCK : ROADSTOP_BUS, DC_EXEC | DC_BANKRUPT, CMD_REMOVE_ROAD_STOP); assert(IsTileType(tile, MP_ROAD)); /* Change owner of tile and all roadtypes */ ChangeTileOwner(tile, old_owner, new_owner); } else { DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); /* Set tile owner of water under (now removed) buoy and dock to OWNER_NONE. * Update owner of buoy if it was not removed (was in orders). * Do not update when owned by OWNER_WATER (sea and rivers). */ if ((IsTileType(tile, MP_WATER) || IsBuoyTile(tile)) && IsTileOwner(tile, old_owner)) SetTileOwner(tile, OWNER_NONE); } } } /** * Check if a drive-through road stop tile can be cleared. * Road stops built on town-owned roads check the conditions * that would allow clearing of the original road. * @param tile road stop tile to check * @param flags command flags * @return true if the road can be cleared */ static bool CanRemoveRoadWithStop(TileIndex tile, DoCommandFlag flags) { /* Yeah... water can always remove stops, right? */ if (_current_company == OWNER_WATER) return true; RoadTypes rts = GetRoadTypes(tile); if (HasBit(rts, ROADTYPE_TRAM)) { Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); if (tram_owner != OWNER_NONE && CheckOwnership(tram_owner).Failed()) return false; } if (HasBit(rts, ROADTYPE_ROAD)) { Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); if (road_owner != OWNER_TOWN) { if (road_owner != OWNER_NONE && CheckOwnership(road_owner).Failed()) return false; } else { if (CheckAllowRemoveRoad(tile, GetAnyRoadBits(tile, ROADTYPE_ROAD), OWNER_TOWN, ROADTYPE_ROAD, flags).Failed()) return false; } } return true; } /** * Clear a single tile of a station. * @param tile The tile to clear. * @param flags The DoCommand flags related to the "command". * @return The cost, or error of clearing. */ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags) { if (flags & DC_AUTO) { switch (GetStationType(tile)) { default: break; case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD); case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST); case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); case STATION_BUS: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY); case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST); case STATION_OILRIG: SetDParam(1, STR_INDUSTRY_NAME_OIL_RIG); return_cmd_error(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY); } } switch (GetStationType(tile)) { case STATION_RAIL: return RemoveRailStation(tile, flags); case STATION_WAYPOINT: return RemoveRailWaypoint(tile, flags); case STATION_AIRPORT: return RemoveAirport(tile, flags); case STATION_TRUCK: if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); } return RemoveRoadStop(tile, flags); case STATION_BUS: if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); } return RemoveRoadStop(tile, flags); case STATION_BUOY: return RemoveBuoy(tile, flags); case STATION_DOCK: return RemoveDock(tile, flags); default: break; } return CMD_ERROR; } static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) { /* TODO: If you implement newgrf callback 149 'land slope check', you have to decide what to do with it here. * TTDP does not call it. */ if (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) { switch (GetStationType(tile)) { case STATION_WAYPOINT: case STATION_RAIL: { DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile)); if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break; if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break; return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } case STATION_AIRPORT: return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); case STATION_TRUCK: case STATION_BUS: { DiagDirection direction = GetRoadStopDir(tile); if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break; if (IsDriveThroughStopTile(tile)) { if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, ReverseDiagDir(direction))) break; } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } default: break; } } } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } /** * Get flow for a station. * @param st Station to get flow for. * @return Flow for st. */ uint FlowStat::GetShare(StationID st) const { uint32 prev = 0; for (SharesMap::const_iterator it = this->shares.begin(); it != this->shares.end(); ++it) { if (it->second == st) { return it->first - prev; } else { prev = it->first; } } return 0; } /** * Get a station a package can be routed to, but exclude the given ones. * @param excluded StationID not to be selected. * @param excluded2 Another StationID not to be selected. * @return A station ID from the shares map. */ StationID FlowStat::GetVia(StationID excluded, StationID excluded2) const { if (this->unrestricted == 0) return INVALID_STATION; assert(!this->shares.empty()); SharesMap::const_iterator it = this->shares.upper_bound(RandomRange(this->unrestricted)); assert(it != this->shares.end() && it->first <= this->unrestricted); if (it->second != excluded && it->second != excluded2) return it->second; /* We've hit one of the excluded stations. * Draw another share, from outside its range. */ uint end = it->first; uint begin = (it == this->shares.begin() ? 0 : (--it)->first); uint interval = end - begin; if (interval >= this->unrestricted) return INVALID_STATION; // Only one station in the map. uint new_max = this->unrestricted - interval; uint rand = RandomRange(new_max); SharesMap::const_iterator it2 = (rand < begin) ? this->shares.upper_bound(rand) : this->shares.upper_bound(rand + interval); assert(it2 != this->shares.end() && it2->first <= this->unrestricted); if (it2->second != excluded && it2->second != excluded2) return it2->second; /* We've hit the second excluded station. * Same as before, only a bit more complicated. */ uint end2 = it2->first; uint begin2 = (it2 == this->shares.begin() ? 0 : (--it2)->first); uint interval2 = end2 - begin2; if (interval2 >= new_max) return INVALID_STATION; // Only the two excluded stations in the map. new_max -= interval2; if (begin > begin2) { Swap(begin, begin2); Swap(end, end2); Swap(interval, interval2); } rand = RandomRange(new_max); SharesMap::const_iterator it3 = this->shares.upper_bound(this->unrestricted); if (rand < begin) { it3 = this->shares.upper_bound(rand); } else if (rand < begin2 - interval) { it3 = this->shares.upper_bound(rand + interval); } else { it3 = this->shares.upper_bound(rand + interval + interval2); } assert(it3 != this->shares.end() && it3->first <= this->unrestricted); return it3->second; } /** * Reduce all flows to minimum capacity so that they don't get in the way of * link usage statistics too much. Keep them around, though, to continue * routing any remaining cargo. */ void FlowStat::Invalidate() { assert(!this->shares.empty()); SharesMap new_shares; uint i = 0; for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) { new_shares[++i] = it->second; if (it->first == this->unrestricted) this->unrestricted = i; } this->shares.swap(new_shares); assert(!this->shares.empty() && this->unrestricted <= (--this->shares.end())->first); } /** * Change share for specified station. By specifing INT_MIN as parameter you * can erase a share. Newly added flows will be unrestricted. * @param st Next Hop to be removed. * @param flow Share to be added or removed. */ void FlowStat::ChangeShare(StationID st, int flow) { /* We assert only before changing as afterwards the shares can actually * be empty. In that case the whole flow stat must be deleted then. */ assert(!this->shares.empty()); uint removed_shares = 0; uint added_shares = 0; uint last_share = 0; SharesMap new_shares; for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) { if (it->second == st) { if (flow < 0) { uint share = it->first - last_share; if (flow == INT_MIN || (uint)(-flow) >= share) { removed_shares += share; if (it->first <= this->unrestricted) this->unrestricted -= share; if (flow != INT_MIN) flow += share; last_share = it->first; continue; // remove the whole share } removed_shares += (uint)(-flow); } else { added_shares += (uint)(flow); } if (it->first <= this->unrestricted) this->unrestricted += flow; /* If we don't continue above the whole flow has been added or * removed. */ flow = 0; } new_shares[it->first + added_shares - removed_shares] = it->second; last_share = it->first; } if (flow > 0) { new_shares[last_share + (uint)flow] = st; if (this->unrestricted < last_share) { this->ReleaseShare(st); } else { this->unrestricted += flow; } } this->shares.swap(new_shares); } /** * Restrict a flow by moving it to the end of the map and decreasing the amount * of unrestricted flow. * @param st Station of flow to be restricted. */ void FlowStat::RestrictShare(StationID st) { assert(!this->shares.empty()); uint flow = 0; uint last_share = 0; SharesMap new_shares; for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) { if (flow == 0) { if (it->first > this->unrestricted) return; // Not present or already restricted. if (it->second == st) { flow = it->first - last_share; this->unrestricted -= flow; } else { new_shares[it->first] = it->second; } } else { new_shares[it->first - flow] = it->second; } last_share = it->first; } if (flow == 0) return; new_shares[last_share + flow] = st; this->shares.swap(new_shares); assert(!this->shares.empty()); } /** * Release ("unrestrict") a flow by moving it to the begin of the map and * increasing the amount of unrestricted flow. * @param st Station of flow to be released. */ void FlowStat::ReleaseShare(StationID st) { assert(!this->shares.empty()); uint flow = 0; uint next_share = 0; bool found = false; for (SharesMap::reverse_iterator it(this->shares.rbegin()); it != this->shares.rend(); ++it) { if (it->first < this->unrestricted) return; // Note: not <= as the share may hit the limit. if (found) { flow = next_share - it->first; this->unrestricted += flow; break; } else { if (it->first == this->unrestricted) return; // !found -> Limit not hit. if (it->second == st) found = true; } next_share = it->first; } if (flow == 0) return; SharesMap new_shares; new_shares[flow] = st; for (SharesMap::iterator it(this->shares.begin()); it != this->shares.end(); ++it) { if (it->second != st) { new_shares[flow + it->first] = it->second; } else { flow = 0; } } this->shares.swap(new_shares); assert(!this->shares.empty()); } /** * Scale all shares from link graph's runtime to monthly values. * @param runtime Time the link graph has been running without compression. * @pre runtime must be greater than 0 as we don't want infinite flow values. */ void FlowStat::ScaleToMonthly(uint runtime) { assert(runtime > 0); SharesMap new_shares; uint share = 0; for (SharesMap::iterator i = this->shares.begin(); i != this->shares.end(); ++i) { share = max(share + 1, i->first * 30 / runtime); new_shares[share] = i->second; if (this->unrestricted == i->first) this->unrestricted = share; } this->shares.swap(new_shares); } /** * Add some flow from "origin", going via "via". * @param origin Origin of the flow. * @param via Next hop. * @param flow Amount of flow to be added. */ void FlowStatMap::AddFlow(StationID origin, StationID via, uint flow) { FlowStatMap::iterator origin_it = this->find(origin); if (origin_it == this->end()) { this->insert(std::make_pair(origin, FlowStat(via, flow))); } else { origin_it->second.ChangeShare(via, flow); assert(!origin_it->second.GetShares()->empty()); } } /** * Pass on some flow, remembering it as invalid, for later subtraction from * locally consumed flow. This is necessary because we can't have negative * flows and we don't want to sort the flows before adding them up. * @param origin Origin of the flow. * @param via Next hop. * @param flow Amount of flow to be passed. */ void FlowStatMap::PassOnFlow(StationID origin, StationID via, uint flow) { FlowStatMap::iterator prev_it = this->find(origin); if (prev_it == this->end()) { FlowStat fs(via, flow); fs.AppendShare(INVALID_STATION, flow); this->insert(std::make_pair(origin, fs)); } else { prev_it->second.ChangeShare(via, flow); prev_it->second.ChangeShare(INVALID_STATION, flow); assert(!prev_it->second.GetShares()->empty()); } } /** * Subtract invalid flows from locally consumed flow. * @param self ID of own station. */ void FlowStatMap::FinalizeLocalConsumption(StationID self) { for (FlowStatMap::iterator i = this->begin(); i != this->end(); ++i) { FlowStat &fs = i->second; uint local = fs.GetShare(INVALID_STATION); if (local > INT_MAX) { // make sure it fits in an int fs.ChangeShare(self, -INT_MAX); fs.ChangeShare(INVALID_STATION, -INT_MAX); local -= INT_MAX; } fs.ChangeShare(self, -(int)local); fs.ChangeShare(INVALID_STATION, -(int)local); /* If the local share is used up there must be a share for some * remote station. */ assert(!fs.GetShares()->empty()); } } /** * Delete all flows at a station for specific cargo and destination. * @param via Remote station of flows to be deleted. * @return IDs of source stations for which the complete FlowStat, not only a * share, has been erased. */ StationIDStack FlowStatMap::DeleteFlows(StationID via) { StationIDStack ret; for (FlowStatMap::iterator f_it = this->begin(); f_it != this->end();) { FlowStat &s_flows = f_it->second; s_flows.ChangeShare(via, INT_MIN); if (s_flows.GetShares()->empty()) { ret.Push(f_it->first); this->erase(f_it++); } else { ++f_it; } } return ret; } /** * Restrict all flows at a station for specific cargo and destination. * @param via Remote station of flows to be restricted. */ void FlowStatMap::RestrictFlows(StationID via) { for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) { it->second.RestrictShare(via); } } /** * Release all flows at a station for specific cargo and destination. * @param via Remote station of flows to be released. */ void FlowStatMap::ReleaseFlows(StationID via) { for (FlowStatMap::iterator it = this->begin(); it != this->end(); ++it) { it->second.ReleaseShare(via); } } /** * Get the sum of all flows from this FlowStatMap. * @return sum of all flows. */ uint FlowStatMap::GetFlow() const { uint ret = 0; for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) { ret += (--(i->second.GetShares()->end()))->first; } return ret; } /** * Get the sum of flows via a specific station from this FlowStatMap. * @param via Remote station to look for. * @return all flows for 'via' added up. */ uint FlowStatMap::GetFlowVia(StationID via) const { uint ret = 0; for (FlowStatMap::const_iterator i = this->begin(); i != this->end(); ++i) { ret += i->second.GetShare(via); } return ret; } /** * Get the sum of flows from a specific station from this FlowStatMap. * @param from Origin station to look for. * @return all flows from 'from' added up. */ uint FlowStatMap::GetFlowFrom(StationID from) const { FlowStatMap::const_iterator i = this->find(from); if (i == this->end()) return 0; return (--(i->second.GetShares()->end()))->first; } /** * Get the flow from a specific station via a specific other station. * @param from Origin station to look for. * @param via Remote station to look for. * @return flow share originating at 'from' and going to 'via'. */ uint FlowStatMap::GetFlowFromVia(StationID from, StationID via) const { FlowStatMap::const_iterator i = this->find(from); if (i == this->end()) return 0; return i->second.GetShare(via); } extern const TileTypeProcs _tile_type_station_procs = { DrawTile_Station, // draw_tile_proc GetSlopePixelZ_Station, // get_slope_z_proc ClearTile_Station, // clear_tile_proc NULL, // add_accepted_cargo_proc GetTileDesc_Station, // get_tile_desc_proc GetTileTrackStatus_Station, // get_tile_track_status_proc ClickTile_Station, // click_tile_proc AnimateTile_Station, // animate_tile_proc TileLoop_Station, // tile_loop_proc ChangeTileOwner_Station, // change_tile_owner_proc NULL, // add_produced_cargo_proc VehicleEnter_Station, // vehicle_enter_tile_proc GetFoundation_Station, // get_foundation_proc TerraformTile_Station, // terraform_tile_proc }; openttd-1.5.3/src/console_internal.h0000644000000000000000000000706112627373433016207 0ustar rootroot/* $Id: console_internal.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 console_internal.h Internally used functions for the console. */ #ifndef CONSOLE_INTERNAL_H #define CONSOLE_INTERNAL_H #include "gfx_type.h" static const uint ICON_CMDLN_SIZE = 1024; ///< maximum length of a typed in command static const uint ICON_MAX_STREAMSIZE = 2048; ///< maximum length of a totally expanded command /** Return values of console hooks (#IConsoleHook). */ enum ConsoleHookResult { CHR_ALLOW, ///< Allow command execution. CHR_DISALLOW, ///< Disallow command execution. CHR_HIDE, ///< Hide the existence of the command. }; /** * --Commands-- * Commands are commands, or functions. They get executed once and any * effect they produce are carried out. The arguments to the commands * are given to them, each input word separated by a double-quote (") is an argument * If you want to handle multiple words as one, enclose them in double-quotes * eg. 'say "hello sexy boy"' */ typedef bool IConsoleCmdProc(byte argc, char *argv[]); typedef ConsoleHookResult IConsoleHook(bool echo); struct IConsoleCmd { char *name; ///< name of command IConsoleCmd *next; ///< next command in list IConsoleCmdProc *proc; ///< process executed when command is typed IConsoleHook *hook; ///< any special trigger action that needs executing }; /** * --Aliases-- * Aliases are like shortcuts for complex functions, variable assignments, * etc. You can use a simple alias to rename a longer command (eg 'set' for * 'setting' for example), or concatenate more commands into one * (eg. 'ng' for 'load %A; unpause; debug_level 5'). Aliases can parse the arguments * given to them in the command line. * - "%A - %Z" substitute arguments 1 t/m 26 * - "%+" lists all parameters keeping them separated * - "%!" also lists all parameters but presenting them to the aliased command as one argument * - ";" allows for combining commands (see example 'ng') */ struct IConsoleAlias { char *name; ///< name of the alias IConsoleAlias *next; ///< next alias in list char *cmdline; ///< command(s) that is/are being aliased }; /* console parser */ extern IConsoleCmd *_iconsole_cmds; ///< List of registered commands. extern IConsoleAlias *_iconsole_aliases; ///< List of registered aliases. /* console functions */ void IConsoleClearBuffer(); /* Commands */ void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook = NULL); void IConsoleAliasRegister(const char *name, const char *cmd); IConsoleCmd *IConsoleCmdGet(const char *name); IConsoleAlias *IConsoleAliasGet(const char *name); /* console std lib (register ingame commands/aliases) */ void IConsoleStdLibRegister(); /* Supporting functions */ bool GetArgumentInteger(uint32 *value, const char *arg); void IConsoleGUIInit(); void IConsoleGUIFree(); void IConsoleGUIPrint(TextColour colour_code, char *string); char *RemoveUnderscores(char *name); #endif /* CONSOLE_INTERNAL_H */ openttd-1.5.3/src/town_gui.cpp0000644000000000000000000013202512627373435015040 0ustar rootroot/* $Id: town_gui.cpp 27351 2015-07-30 18:53:31Z frosch $ */ /* * 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 town_gui.cpp GUI for towns. */ #include "stdafx.h" #include "town.h" #include "viewport_func.h" #include "error.h" #include "gui.h" #include "command_func.h" #include "company_func.h" #include "company_base.h" #include "company_gui.h" #include "network/network.h" #include "string_func.h" #include "strings_func.h" #include "sound_func.h" #include "tilehighlight_func.h" #include "sortlist_type.h" #include "road_cmd.h" #include "landscape.h" #include "querystring_gui.h" #include "window_func.h" #include "townname_func.h" #include "core/geometry_func.hpp" #include "genworld.h" #include "widgets/dropdown_func.h" #include "widgets/town_widget.h" #include "table/strings.h" #include "safeguards.h" typedef GUIList GUITownList; static const NWidgetPart _nested_town_authority_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION), SetDataTip(STR_LOCAL_AUTHORITY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(305, 52), SetResize(1, 0), SetDataTip(0x0, STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), SetScrollbar(WID_TA_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TA_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer() }; /** Town authority window. */ struct TownAuthorityWindow : Window { private: Town *town; ///< Town being displayed. int sel_index; ///< Currently selected town action, \c 0 to \c TACT_COUNT-1, \c -1 means no action selected. Scrollbar *vscroll; uint displayed_actions_on_previous_painting; ///< Actions that were available on the previous call to OnPaint() /** * Get the position of the Nth set bit. * * If there is no Nth bit set return -1 * * @param bits The value to search in * @param n The Nth set bit from which we want to know the position * @return The position of the Nth set bit */ static int GetNthSetBit(uint32 bits, int n) { if (n >= 0) { uint i; FOR_EACH_SET_BIT(i, bits) { n--; if (n < 0) return i; } } return -1; } public: TownAuthorityWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), sel_index(-1), displayed_actions_on_previous_painting(0) { this->town = Town::Get(window_number); this->InitNested(window_number); this->vscroll = this->GetScrollbar(WID_TA_SCROLLBAR); this->vscroll->SetCapacity((this->GetWidget(WID_TA_COMMAND_LIST)->current_y - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM) / FONT_HEIGHT_NORMAL); } virtual void OnPaint() { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); if (buttons != displayed_actions_on_previous_painting) this->SetDirty(); displayed_actions_on_previous_painting = buttons; this->vscroll->SetCount(numact + 1); if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) { this->sel_index = -1; } this->SetWidgetDisabledState(WID_TA_EXECUTE, this->sel_index == -1); this->DrawWidgets(); if (!this->IsShaded()) this->DrawRatings(); } /** Draw the contents of the ratings panel. May request a resize of the window if the contents does not fit. */ void DrawRatings() { NWidgetBase *nwid = this->GetWidget(WID_TA_RATING_INFO); uint left = nwid->pos_x + WD_FRAMERECT_LEFT; uint right = nwid->pos_x + nwid->current_x - 1 - WD_FRAMERECT_RIGHT; uint y = nwid->pos_y + WD_FRAMERECT_TOP; DrawString(left, right, y, STR_LOCAL_AUTHORITY_COMPANY_RATINGS); y += FONT_HEIGHT_NORMAL; Dimension icon_size = GetSpriteSize(SPR_COMPANY_ICON); int icon_width = icon_size.width; int icon_y_offset = (FONT_HEIGHT_NORMAL - icon_size.height) / 2; Dimension exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT); int exclusive_width = exclusive_size.width; int exclusive_y_offset = (FONT_HEIGHT_NORMAL - exclusive_size.height) / 2; bool rtl = _current_text_dir == TD_RTL; uint text_left = left + (rtl ? 0 : icon_width + exclusive_width + 4); uint text_right = right - (rtl ? icon_width + exclusive_width + 4 : 0); uint icon_left = rtl ? right - icon_width : left; uint exclusive_left = rtl ? right - icon_width - exclusive_width - 2 : left + icon_width + 2; /* Draw list of companies */ const Company *c; FOR_ALL_COMPANIES(c) { if ((HasBit(this->town->have_ratings, c->index) || this->town->exclusivity == c->index)) { DrawCompanyIcon(c->index, icon_left, y + icon_y_offset); SetDParam(0, c->index); SetDParam(1, c->index); int r = this->town->ratings[c->index]; StringID str; (str = STR_CARGO_RATING_APPALLING, r <= RATING_APPALLING) || // Apalling (str++, r <= RATING_VERYPOOR) || // Very Poor (str++, r <= RATING_POOR) || // Poor (str++, r <= RATING_MEDIOCRE) || // Mediocore (str++, r <= RATING_GOOD) || // Good (str++, r <= RATING_VERYGOOD) || // Very Good (str++, r <= RATING_EXCELLENT) || // Excellent (str++, true); // Outstanding SetDParam(2, str); if (this->town->exclusivity == c->index) { DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive_left, y + exclusive_y_offset); } DrawString(text_left, text_right, y, STR_LOCAL_AUTHORITY_COMPANY_RATING); y += FONT_HEIGHT_NORMAL; } } y = y + WD_FRAMERECT_BOTTOM - nwid->pos_y; // Compute needed size of the widget. if (y > nwid->current_y) { /* If the company list is too big to fit, mark ourself dirty and draw again. */ ResizeWindow(this, 0, y - nwid->current_y); } } virtual void SetStringParameters(int widget) const { if (widget == WID_TA_CAPTION) SetDParam(0, this->window_number); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_TA_ACTION_INFO: if (this->sel_index != -1) { SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[this->sel_index] >> 8); DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + this->sel_index); } break; case WID_TA_COMMAND_LIST: { int numact; uint buttons = GetMaskOfTownActions(&numact, _local_company, this->town); int y = r.top + WD_FRAMERECT_TOP; int pos = this->vscroll->GetPosition(); if (--pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTIONS_TITLE); y += FONT_HEIGHT_NORMAL; } for (int i = 0; buttons; i++, buttons >>= 1) { if (pos <= -5) break; ///< Draw only the 5 fitting lines if ((buttons & 1) && --pos < 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i, this->sel_index == i ? TC_WHITE : TC_ORANGE); y += FONT_HEIGHT_NORMAL; } } break; } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_TA_ACTION_INFO: { assert(size->width > padding.width && size->height > padding.height); size->width -= WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; size->height -= WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; Dimension d = {0, 0}; for (int i = 0; i < TACT_COUNT; i++) { SetDParam(0, _price[PR_TOWN_ACTION] * _town_action_costs[i] >> 8); d = maxdim(d, GetStringMultiLineBoundingBox(STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING + i, *size)); } *size = maxdim(*size, d); size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; } case WID_TA_COMMAND_LIST: size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; size->width = GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTIONS_TITLE).width; for (uint i = 0; i < TACT_COUNT; i++ ) { size->width = max(size->width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + i).width); } size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; break; case WID_TA_RATING_INFO: resize->height = FONT_HEIGHT_NORMAL; size->height = WD_FRAMERECT_TOP + 9 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; break; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_TA_COMMAND_LIST: { int y = this->GetRowFromWidget(pt.y, WID_TA_COMMAND_LIST, 1, FONT_HEIGHT_NORMAL); if (!IsInsideMM(y, 0, 5)) return; y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_company, this->town), y + this->vscroll->GetPosition() - 1); if (y >= 0) { this->sel_index = y; this->SetDirty(); } /* FALL THROUGH, when double-clicking. */ if (click_count == 1 || y < 0) break; } case WID_TA_EXECUTE: DoCommandP(this->town->xy, this->window_number, this->sel_index, CMD_DO_TOWN_ACTION | CMD_MSG(STR_ERROR_CAN_T_DO_THIS)); break; } } virtual void OnHundredthTick() { this->SetDirty(); } }; static WindowDesc _town_authority_desc( WDP_AUTO, "view_town_authority", 317, 222, WC_TOWN_AUTHORITY, WC_NONE, 0, _nested_town_authority_widgets, lengthof(_nested_town_authority_widgets) ); static void ShowTownAuthorityWindow(uint town) { AllocateWindowDescFront(&_town_authority_desc, town); } /* Town view window. */ struct TownViewWindow : Window { private: Town *town; ///< Town displayed by the window. public: static const int WID_TV_HEIGHT_NORMAL = 150; TownViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->CreateNestedTree(); this->town = Town::Get(window_number); if (this->town->larger_town) this->GetWidget(WID_TV_CAPTION)->widget_data = STR_TOWN_VIEW_CITY_CAPTION; this->FinishInitNested(window_number); this->flags |= WF_DISABLE_VP_SCROLL; NWidgetViewport *nvp = this->GetWidget(WID_TV_VIEWPORT); nvp->InitializeViewport(this, this->town->xy, ZOOM_LVL_NEWS); /* disable renaming town in network games if you are not the server */ this->SetWidgetDisabledState(WID_TV_CHANGE_NAME, _networking && !_network_server); } virtual void SetStringParameters(int widget) const { if (widget == WID_TV_CAPTION) SetDParam(0, this->town->index); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_TV_INFO) return; uint y = r.top + WD_FRAMERECT_TOP; SetDParam(0, this->town->cache.population); SetDParam(1, this->town->cache.num_houses); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y, STR_TOWN_VIEW_POPULATION_HOUSES); SetDParam(0, this->town->supplied[CT_PASSENGERS].old_act); SetDParam(1, this->town->supplied[CT_PASSENGERS].old_max); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX); SetDParam(0, this->town->supplied[CT_MAIL].old_act); SetDParam(1, this->town->supplied[CT_MAIL].old_max); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX); bool first = true; for (int i = TE_BEGIN; i < TE_END; i++) { if (this->town->goal[i] == 0) continue; if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; if (first) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH); first = false; } bool rtl = _current_text_dir == TD_RTL; uint cargo_text_left = r.left + WD_FRAMERECT_LEFT + (rtl ? 0 : 20); uint cargo_text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? 20 : 0); const CargoSpec *cargo = FindFirstCargoWithTownEffect((TownEffect)i); assert(cargo != NULL); StringID string; if (this->town->goal[i] == TOWN_GROWTH_DESERT || this->town->goal[i] == TOWN_GROWTH_WINTER) { /* For 'original' gameplay, don't show the amount required (you need 1 or more ..) */ string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL; if (this->town->received[i].old_act == 0) { string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL; if (this->town->goal[i] == TOWN_GROWTH_WINTER && TileHeight(this->town->xy) < GetSnowLine()) { string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER; } } SetDParam(0, cargo->name); } else { string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED; if (this->town->received[i].old_act < this->town->goal[i]) { string = STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED; } SetDParam(0, cargo->Index()); SetDParam(1, this->town->received[i].old_act); SetDParam(2, cargo->Index()); SetDParam(3, this->town->goal[i]); } DrawString(cargo_text_left, cargo_text_right, y += FONT_HEIGHT_NORMAL, string); } if (HasBit(this->town->flags, TOWN_IS_GROWING)) { SetDParam(0, ((this->town->growth_rate & (~TOWN_GROW_RATE_CUSTOM)) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, this->town->fund_buildings_months == 0 ? STR_TOWN_VIEW_TOWN_GROWS_EVERY : STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED); } else { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_TOWN_GROW_STOPPED); } /* only show the town noise, if the noise option is activated. */ if (_settings_game.economy.station_noise_level) { SetDParam(0, this->town->noise_reached); SetDParam(1, this->town->MaxTownNoise()); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, y += FONT_HEIGHT_NORMAL, STR_TOWN_VIEW_NOISE_IN_TOWN); } if (this->town->text != NULL) { SetDParamStr(0, this->town->text); DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y += FONT_HEIGHT_NORMAL, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_TV_CENTER_VIEW: // scroll to location if (_ctrl_pressed) { ShowExtraViewPortWindow(this->town->xy); } else { ScrollMainWindowToTile(this->town->xy); } break; case WID_TV_SHOW_AUTHORITY: // town authority ShowTownAuthorityWindow(this->window_number); break; case WID_TV_CHANGE_NAME: // rename SetDParam(0, this->window_number); ShowQueryString(STR_TOWN_NAME, STR_TOWN_VIEW_RENAME_TOWN_BUTTON, MAX_LENGTH_TOWN_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); break; case WID_TV_EXPAND: { // expand town - only available on Scenario editor /* Warn the user if towns are not allowed to build roads, but do this only once per OpenTTD run. */ static bool _warn_town_no_roads = false; if (!_settings_game.economy.allow_town_roads && !_warn_town_no_roads) { ShowErrorMessage(STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS, INVALID_STRING_ID, WL_WARNING); _warn_town_no_roads = true; } DoCommandP(0, this->window_number, 0, CMD_EXPAND_TOWN | CMD_MSG(STR_ERROR_CAN_T_EXPAND_TOWN)); break; } case WID_TV_DELETE: // delete town - only available on Scenario editor DoCommandP(0, this->window_number, 0, CMD_DELETE_TOWN | CMD_MSG(STR_ERROR_TOWN_CAN_T_DELETE)); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_TV_INFO: size->height = GetDesiredInfoHeight(size->width); break; } } /** * Gets the desired height for the information panel. * @return the desired height in pixels. */ uint GetDesiredInfoHeight(int width) const { uint aimed_height = 3 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; bool first = true; for (int i = TE_BEGIN; i < TE_END; i++) { if (this->town->goal[i] == 0) continue; if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue; if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue; if (first) { aimed_height += FONT_HEIGHT_NORMAL; first = false; } aimed_height += FONT_HEIGHT_NORMAL; } aimed_height += FONT_HEIGHT_NORMAL; if (_settings_game.economy.station_noise_level) aimed_height += FONT_HEIGHT_NORMAL; if (this->town->text != NULL) { SetDParamStr(0, this->town->text); aimed_height += GetStringHeight(STR_JUST_RAW_STRING, width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT); } return aimed_height; } void ResizeWindowAsNeeded() { const NWidgetBase *nwid_info = this->GetWidget(WID_TV_INFO); uint aimed_height = GetDesiredInfoHeight(nwid_info->current_x); if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) { this->ReInit(); } } virtual void OnResize() { if (this->viewport != NULL) { NWidgetViewport *nvp = this->GetWidget(WID_TV_VIEWPORT); nvp->UpdateViewportCoordinates(this); ScrollWindowToTile(this->town->xy, this, true); // Re-center viewport. } } /** * 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; /* Called when setting station noise or required cargoes have changed, in order to resize the window */ this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading this->ResizeWindowAsNeeded(); } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; DoCommandP(0, this->window_number, 0, CMD_RENAME_TOWN | CMD_MSG(STR_ERROR_CAN_T_RENAME_TOWN), NULL, str); } }; static const NWidgetPart _nested_town_game_view_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1), SetPadding(1, 1, 1, 1), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), }; static WindowDesc _town_game_view_desc( WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, WC_TOWN_VIEW, WC_NONE, 0, _nested_town_game_view_widgets, lengthof(_nested_town_game_view_widgets) ); static const NWidgetPart _nested_town_editor_view_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetDataTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetMinimalSize(76, 14), SetDataTip(STR_BUTTON_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1), SetPadding(1, 1, 1, 1), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), }; static WindowDesc _town_editor_view_desc( WDP_AUTO, "view_town_scen", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL, WC_TOWN_VIEW, WC_NONE, 0, _nested_town_editor_view_widgets, lengthof(_nested_town_editor_view_widgets) ); void ShowTownViewWindow(TownID town) { if (_game_mode == GM_EDITOR) { AllocateWindowDescFront(&_town_editor_view_desc, town); } else { AllocateWindowDescFront(&_town_game_view_desc, town); } } static const NWidgetPart _nested_town_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_TOWN_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetMinimalSize(196, 0), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP), SetFill(1, 0), SetResize(0, 10), SetScrollbar(WID_TD_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(WWT_TEXT, COLOUR_BROWN, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 0, 2), SetMinimalSize(196, 12), SetFill(1, 0), SetDataTip(STR_TOWN_POPULATION, STR_NULL), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_TD_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), }; /** Town directory window class. */ struct TownDirectoryWindow : public Window { private: /* Runtime saved values */ static Listing last_sorting; static const Town *last_town; /* Constants for sorting towns */ static const StringID sorter_names[]; static GUITownList::SortFunction * const sorter_funcs[]; GUITownList towns; Scrollbar *vscroll; void BuildSortTownList() { if (this->towns.NeedRebuild()) { this->towns.Clear(); const Town *t; FOR_ALL_TOWNS(t) { *this->towns.Append() = t; } this->towns.Compact(); this->towns.RebuildDone(); this->vscroll->SetCount(this->towns.Length()); // Update scrollbar as well. } /* Always sort the towns. */ this->last_town = NULL; this->towns.Sort(); this->SetWidgetDirty(WID_TD_LIST); // Force repaint of the displayed towns. } /** Sort by town name */ static int CDECL TownNameSorter(const Town * const *a, const Town * const *b) { static char buf_cache[64]; const Town *ta = *a; const Town *tb = *b; char buf[64]; SetDParam(0, ta->index); GetString(buf, STR_TOWN_NAME, lastof(buf)); /* If 'b' is the same town as in the last round, use the cached value * We do this to speed stuff up ('b' is called with the same value a lot of * times after each other) */ if (tb != last_town) { last_town = tb; SetDParam(0, tb->index); GetString(buf_cache, STR_TOWN_NAME, lastof(buf_cache)); } return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). } /** Sort by population (default descending, as big towns are of the most interest). */ static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b) { uint32 a_population = (*a)->cache.population; uint32 b_population = (*b)->cache.population; if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b); return (a_population < b_population) ? -1 : 1; } /** Sort by town rating */ static int CDECL TownRatingSorter(const Town * const *a, const Town * const *b) { int before = TownDirectoryWindow::last_sorting.order ? 1 : -1; // Value to get 'a' before 'b'. /* Towns without rating are always after towns with rating. */ if (HasBit((*a)->have_ratings, _local_company)) { if (HasBit((*b)->have_ratings, _local_company)) { int16 a_rating = (*a)->ratings[_local_company]; int16 b_rating = (*b)->ratings[_local_company]; if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b); return (a_rating < b_rating) ? -1 : 1; } return before; } if (HasBit((*b)->have_ratings, _local_company)) return -before; return -before * TownDirectoryWindow::TownNameSorter(a, b); // Sort unrated towns always on ascending town name. } public: TownDirectoryWindow(WindowDesc *desc) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_TD_SCROLLBAR); this->towns.SetListing(this->last_sorting); this->towns.SetSortFuncs(TownDirectoryWindow::sorter_funcs); this->towns.ForceRebuild(); this->BuildSortTownList(); this->FinishInitNested(0); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_TD_WORLD_POPULATION: SetDParam(0, GetWorldPopulation()); break; case WID_TD_SORT_CRITERIA: SetDParam(0, TownDirectoryWindow::sorter_names[this->towns.SortType()]); break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_TD_SORT_ORDER: this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; case WID_TD_LIST: { int n = 0; int y = r.top + WD_FRAMERECT_TOP; if (this->towns.Length() == 0) { // No towns available. DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y, STR_TOWN_DIRECTORY_NONE); break; } /* At least one town available. */ bool rtl = _current_text_dir == TD_RTL; Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); int text_left = r.left + WD_FRAMERECT_LEFT + (rtl ? 0 : icon_size.width + 2); int text_right = r.right - WD_FRAMERECT_RIGHT - (rtl ? icon_size.width + 2 : 0); int icon_x = rtl ? r.right - WD_FRAMERECT_RIGHT - icon_size.width : r.left + WD_FRAMERECT_LEFT; for (uint i = this->vscroll->GetPosition(); i < this->towns.Length(); i++) { const Town *t = this->towns[i]; assert(t->xy != INVALID_TILE); /* Draw rating icon. */ if (_game_mode == GM_EDITOR || !HasBit(t->have_ratings, _local_company)) { DrawSprite(SPR_TOWN_RATING_NA, PAL_NONE, icon_x, y + (this->resize.step_height - icon_size.height) / 2); } else { SpriteID icon = SPR_TOWN_RATING_APALLING; if (t->ratings[_local_company] > RATING_VERYPOOR) icon = SPR_TOWN_RATING_MEDIOCRE; if (t->ratings[_local_company] > RATING_GOOD) icon = SPR_TOWN_RATING_GOOD; DrawSprite(icon, PAL_NONE, icon_x, y + (this->resize.step_height - icon_size.height) / 2); } SetDParam(0, t->index); SetDParam(1, t->cache.population); DrawString(text_left, text_right, y + (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2, STR_TOWN_DIRECTORY_TOWN); y += this->resize.step_height; if (++n == this->vscroll->GetCapacity()) break; // max number of towns in 1 window } break; } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_TD_SORT_ORDER: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_TD_SORT_CRITERIA: { Dimension d = {0, 0}; for (uint i = 0; TownDirectoryWindow::sorter_names[i] != INVALID_STRING_ID; i++) { d = maxdim(d, GetStringBoundingBox(TownDirectoryWindow::sorter_names[i])); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_TD_LIST: { Dimension d = GetStringBoundingBox(STR_TOWN_DIRECTORY_NONE); for (uint i = 0; i < this->towns.Length(); i++) { const Town *t = this->towns[i]; assert(t != NULL); SetDParam(0, t->index); SetDParamMaxDigits(1, 8); d = maxdim(d, GetStringBoundingBox(STR_TOWN_DIRECTORY_TOWN)); } Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD); d.width += icon_size.width + 2; d.height = max(d.height, icon_size.height); resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } case WID_TD_WORLD_POPULATION: { SetDParamMaxDigits(0, 10); Dimension d = GetStringBoundingBox(STR_TOWN_POPULATION); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_TD_SORT_ORDER: // Click on sort order button if (this->towns.SortType() != 2) { // A different sort than by rating. this->towns.ToggleSortOrder(); this->last_sorting = this->towns.GetListing(); // Store new sorting order. } else { /* Some parts are always sorted ascending on name. */ this->last_sorting.order = !this->last_sorting.order; this->towns.SetListing(this->last_sorting); this->towns.ForceResort(); this->towns.Sort(); } this->SetDirty(); break; case WID_TD_SORT_CRITERIA: // Click on sort criteria dropdown ShowDropDownMenu(this, TownDirectoryWindow::sorter_names, this->towns.SortType(), WID_TD_SORT_CRITERIA, 0, 0); break; case WID_TD_LIST: { // Click on Town Matrix uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_TD_LIST, WD_FRAMERECT_TOP); if (id_v >= this->towns.Length()) return; // click out of town bounds const Town *t = this->towns[id_v]; assert(t != NULL); if (_ctrl_pressed) { ShowExtraViewPortWindow(t->xy); } else { ScrollMainWindowToTile(t->xy); } break; } } } virtual void OnDropdownSelect(int widget, int index) { if (widget != WID_TD_SORT_CRITERIA) return; if (this->towns.SortType() != index) { this->towns.SetSortType(index); this->last_sorting = this->towns.GetListing(); // Store new sorting order. this->BuildSortTownList(); } } virtual void OnPaint() { if (this->towns.NeedRebuild()) this->BuildSortTownList(); this->DrawWidgets(); } virtual void OnHundredthTick() { this->BuildSortTownList(); this->SetDirty(); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_TD_LIST); } /** * 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 (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->towns.ForceRebuild(); } else { this->towns.ForceResort(); } } }; Listing TownDirectoryWindow::last_sorting = {false, 0}; const Town *TownDirectoryWindow::last_town = NULL; /** Names of the sorting functions. */ const StringID TownDirectoryWindow::sorter_names[] = { STR_SORT_BY_NAME, STR_SORT_BY_POPULATION, STR_SORT_BY_RATING, INVALID_STRING_ID }; /** Available town directory sorting functions. */ GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = { &TownNameSorter, &TownPopulationSorter, &TownRatingSorter, }; static WindowDesc _town_directory_desc( WDP_AUTO, "list_towns", 208, 202, WC_TOWN_DIRECTORY, WC_NONE, 0, _nested_town_directory_widgets, lengthof(_nested_town_directory_widgets) ); void ShowTownDirectory() { if (BringWindowToFrontById(WC_TOWN_DIRECTORY, 0)) return; new TownDirectoryWindow(&_town_directory_desc); } void CcFoundTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } void CcFoundRandomTown(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(_new_town_id)->xy); } static const NWidgetPart _nested_found_town_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), /* Construct new town(s) buttons. */ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetMinimalSize(156, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetPadding(0, 2, 1, 2), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetMinimalSize(156, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetPadding(0, 2, 0, 2), /* Town name selection. */ NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(156, 14), SetPadding(0, 2, 0, 2), SetDataTip(STR_FOUND_TOWN_NAME_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetMinimalSize(156, 12), SetPadding(0, 2, 3, 2), SetDataTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_HELP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetMinimalSize(78, 12), SetPadding(0, 2, 0, 2), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), /* Town size selection. */ NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetPadding(0, 2, 0, 2), SetMinimalSize(156, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0), /* Town roads selection. */ NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(148, 14), SetDataTip(STR_FOUND_TOWN_ROAD_LAYOUT, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(2, 0, 2), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetMinimalSize(78, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetPadding(0, 2, 0, 2), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT), SetFill(1, 0), NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), }; /** Found a town window class. */ struct FoundTownWindow : Window { private: TownSize town_size; ///< Selected town size TownLayout town_layout; ///< Selected town layout bool city; ///< Are we building a city? QueryString townname_editbox; ///< Townname editbox bool townnamevalid; ///< Is generated town name valid? uint32 townnameparts; ///< Generated town name TownNameParams params; ///< Town name parameters public: FoundTownWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), town_size(TSZ_MEDIUM), town_layout(_settings_game.economy.town_layout), townname_editbox(MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_TOWN_NAME_CHARS), params(_settings_game.game_creation.town_name) { this->InitNested(window_number); this->querystrings[WID_TF_TOWN_NAME_EDITBOX] = &this->townname_editbox; this->RandomTownName(); this->UpdateButtons(true); } void RandomTownName() { this->townnamevalid = GenerateTownName(&this->townnameparts); if (!this->townnamevalid) { this->townname_editbox.text.DeleteAll(); } else { GetTownName(this->townname_editbox.text.buf, &this->params, this->townnameparts, &this->townname_editbox.text.buf[this->townname_editbox.text.max_bytes - 1]); this->townname_editbox.text.UpdateSize(); } UpdateOSKOriginalText(this, WID_TF_TOWN_NAME_EDITBOX); this->SetWidgetDirty(WID_TF_TOWN_NAME_EDITBOX); } void UpdateButtons(bool check_availability) { if (check_availability && _game_mode != GM_EDITOR) { this->SetWidgetsDisabledState(true, WID_TF_RANDOM_TOWN, WID_TF_MANY_RANDOM_TOWNS, WID_TF_SIZE_LARGE, WIDGET_LIST_END); this->SetWidgetsDisabledState(_settings_game.economy.found_town != TF_CUSTOM_LAYOUT, WID_TF_LAYOUT_ORIGINAL, WID_TF_LAYOUT_BETTER, WID_TF_LAYOUT_GRID2, WID_TF_LAYOUT_GRID3, WID_TF_LAYOUT_RANDOM, WIDGET_LIST_END); if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT) town_layout = _settings_game.economy.town_layout; } for (int i = WID_TF_SIZE_SMALL; i <= WID_TF_SIZE_RANDOM; i++) { this->SetWidgetLoweredState(i, i == WID_TF_SIZE_SMALL + this->town_size); } this->SetWidgetLoweredState(WID_TF_CITY, this->city); for (int i = WID_TF_LAYOUT_ORIGINAL; i <= WID_TF_LAYOUT_RANDOM; i++) { this->SetWidgetLoweredState(i, i == WID_TF_LAYOUT_ORIGINAL + this->town_layout); } this->SetDirty(); } void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, CommandCallback cc) { const char *name = NULL; if (!this->townnamevalid) { name = this->townname_editbox.text.buf; } else { /* If user changed the name, send it */ char buf[MAX_LENGTH_TOWN_NAME_CHARS * MAX_CHAR_LENGTH]; GetTownName(buf, &this->params, this->townnameparts, lastof(buf)); if (strcmp(buf, this->townname_editbox.text.buf) != 0) name = this->townname_editbox.text.buf; } bool success = DoCommandP(tile, this->town_size | this->city << 2 | this->town_layout << 3 | random << 6, townnameparts, CMD_FOUND_TOWN | CMD_MSG(errstr), cc, name); /* Rerandomise name, if success and no cost-estimation. */ if (success && !_shift_pressed) this->RandomTownName(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_TF_NEW_TOWN: HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT); break; case WID_TF_RANDOM_TOWN: this->ExecuteFoundTownCommand(0, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown); break; case WID_TF_TOWN_NAME_RANDOM: this->RandomTownName(); this->SetFocusedWidget(WID_TF_TOWN_NAME_EDITBOX); break; case WID_TF_MANY_RANDOM_TOWNS: _generating_world = true; UpdateNearestTownForRoadTiles(true); if (!GenerateTowns(this->town_layout)) { ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_TOWN, STR_ERROR_NO_SPACE_FOR_TOWN, WL_INFO); } UpdateNearestTownForRoadTiles(false); _generating_world = false; break; case WID_TF_SIZE_SMALL: case WID_TF_SIZE_MEDIUM: case WID_TF_SIZE_LARGE: case WID_TF_SIZE_RANDOM: this->town_size = (TownSize)(widget - WID_TF_SIZE_SMALL); this->UpdateButtons(false); break; case WID_TF_CITY: this->city ^= true; this->SetWidgetLoweredState(WID_TF_CITY, this->city); this->SetDirty(); break; case WID_TF_LAYOUT_ORIGINAL: case WID_TF_LAYOUT_BETTER: case WID_TF_LAYOUT_GRID2: case WID_TF_LAYOUT_GRID3: case WID_TF_LAYOUT_RANDOM: this->town_layout = (TownLayout)(widget - WID_TF_LAYOUT_ORIGINAL); this->UpdateButtons(false); break; } } virtual void OnPlaceObject(Point pt, TileIndex tile) { this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown); } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); this->UpdateButtons(false); } /** * 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->UpdateButtons(true); } }; static WindowDesc _found_town_desc( WDP_AUTO, "build_town", 160, 162, WC_FOUND_TOWN, WC_NONE, WDF_CONSTRUCTION, _nested_found_town_widgets, lengthof(_nested_found_town_widgets) ); void ShowFoundTownWindow() { if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; AllocateWindowDescFront(&_found_town_desc, 0); } openttd-1.5.3/src/bootstrap_gui.cpp0000644000000000000000000002230512627373441016062 0ustar rootroot/* $Id: bootstrap_gui.cpp 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 bootstrap_gui.cpp Barely used user interface for bootstrapping OpenTTD, i.e. downloading the required content. */ #include "stdafx.h" #include "base_media_base.h" #include "blitter/factory.hpp" #if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) #include "core/geometry_func.hpp" #include "fontcache.h" #include "gfx_func.h" #include "network/network.h" #include "network/network_content_gui.h" #include "openttd.h" #include "strings_func.h" #include "video/video_driver.hpp" #include "window_func.h" #include "widgets/bootstrap_widget.h" #include "table/strings.h" #include "safeguards.h" /** Widgets for the background window to prevent smearing. */ static const struct NWidgetPart _background_widgets[] = { NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1), }; /** * Window description for the background window to prevent smearing. */ static WindowDesc _background_desc( WDP_MANUAL, NULL, 0, 0, WC_BOOTSTRAP, WC_NONE, 0, _background_widgets, lengthof(_background_widgets) ); /** The background for the game. */ class BootstrapBackground : public Window { public: BootstrapBackground() : Window(&_background_desc) { this->InitNested(0); CLRBITS(this->flags, WF_WHITE_BORDER); ResizeWindow(this, _screen.width, _screen.height); } virtual void DrawWidget(const Rect &r, int widget) const { GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE); GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER); } }; /** Nested widgets for the download window. */ static const NWidgetPart _nested_boostrap_download_status_window_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PANEL, COLOUR_GREY, WID_NCDS_BACKGROUND), NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30), EndContainer(), }; /** Window description for the download window */ static WindowDesc _bootstrap_download_status_window_desc( WDP_CENTER, NULL, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, _nested_boostrap_download_status_window_widgets, lengthof(_nested_boostrap_download_status_window_widgets) ); /** Window for showing the download status of content */ struct BootstrapContentDownloadStatusWindow : public BaseNetworkContentDownloadStatusWindow { public: /** Simple call the constructor of the superclass. */ BootstrapContentDownloadStatusWindow() : BaseNetworkContentDownloadStatusWindow(&_bootstrap_download_status_window_desc) { } virtual void OnDownloadComplete(ContentID cid) { /* We have completed downloading. We can trigger finding the right set now. */ BaseGraphics::FindSets(); /* And continue going into the menu. */ _game_mode = GM_MENU; /* _exit_game is used to break out of the outer video driver's MainLoop. */ _exit_game = true; delete this; } }; /** The widgets for the query. It has no close box as that sprite does not exist yet. */ static const NWidgetPart _bootstrap_query_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_PANEL, COLOUR_GREY, WID_BAFD_QUESTION), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_YES), SetDataTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_NO), SetDataTip(STR_MISSING_GRAPHICS_NO_QUIT, STR_NULL), EndContainer(), EndContainer(), }; /** The window description for the query. */ static WindowDesc _bootstrap_query_desc( WDP_CENTER, NULL, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, 0, _bootstrap_query_widgets, lengthof(_bootstrap_query_widgets) ); /** The window for the query. It can't use the generic query window as that uses sprites that don't exist yet. */ class BootstrapAskForDownloadWindow : public Window, ContentCallback { Dimension button_size; ///< The dimension of the button public: /** Start listening to the content client events. */ BootstrapAskForDownloadWindow() : Window(&_bootstrap_query_desc) { this->InitNested(WN_CONFIRM_POPUP_QUERY_BOOTSTRAP); _network_content_client.AddCallback(this); } /** Stop listening to the content client events. */ ~BootstrapAskForDownloadWindow() { _network_content_client.RemoveCallback(this); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { /* We cache the button size. This is safe as no reinit can happen here. */ if (this->button_size.width == 0) { this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT)); this->button_size.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; this->button_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; } switch (widget) { case WID_BAFD_QUESTION: /* The question is twice as wide as the buttons, and determine the height based on the width. */ size->width = this->button_size.width * 2; size->height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT) + WD_FRAMETEXT_BOTTOM + WD_FRAMETEXT_TOP; break; case WID_BAFD_YES: case WID_BAFD_NO: *size = this->button_size; break; } } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != 0) return; DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMETEXT_TOP, r.bottom - WD_FRAMETEXT_BOTTOM, STR_MISSING_GRAPHICS_SET_MESSAGE, TC_FROMSTRING, SA_CENTER); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BAFD_YES: /* We got permission to connect! Yay! */ _network_content_client.Connect(); break; case WID_BAFD_NO: _exit_game = true; break; default: break; } } virtual void OnConnect(bool success) { /* Once connected, request the metadata. */ _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS); } virtual void OnReceiveContentInfo(const ContentInfo *ci) { /* And once the meta data is received, start downloading it. */ _network_content_client.Select(ci->id); new BootstrapContentDownloadStatusWindow(); delete this; } }; #endif /* defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) */ /** * Handle all procedures for bootstrapping OpenTTD without a base graphics set. * This requires all kinds of trickery that is needed to avoid the use of * sprites from the base graphics set which are pretty interwoven. * @return True if a base set exists, otherwise false. */ bool HandleBootstrap() { if (BaseGraphics::GetUsedSet() != NULL) return true; /* No user interface, bail out with an error. */ if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure; /* If there is no network or no freetype, then there is nothing we can do. Go straight to failure. */ #if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(WIN32) || defined(__APPLE__)) if (!_network_available) goto failure; /* First tell the game we're bootstrapping. */ _game_mode = GM_BOOTSTRAP; /* Initialise the freetype font code. */ InitializeUnicodeGlyphMap(); /* Next "force" finding a suitable freetype font as the local font is missing. */ CheckForMissingGlyphs(false); /* Initialise the palette. The biggest step is 'faking' some recolour sprites. * This way the mauve and gray colours work and we can show the user interface. */ GfxInitPalettes(); static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 }; for (uint i = 0; i != 16; i++) { for (int j = 0; j < 8; j++) { _colour_gradient[i][j] = offsets[i] + j; } } /* Finally ask the question. */ new BootstrapBackground(); new BootstrapAskForDownloadWindow(); /* Process the user events. */ VideoDriver::GetInstance()->MainLoop(); /* _exit_game is used to get out of the video driver's main loop. * In case GM_BOOTSTRAP is still set we did not exit it via the * "download complete" event, so it was a manual exit. Obey it. */ _exit_game = _game_mode == GM_BOOTSTRAP; if (_exit_game) return false; /* Try to probe the graphics. Should work this time. */ if (!BaseGraphics::SetSet(NULL)) goto failure; /* Finally we can continue heading for the menu. */ _game_mode = GM_MENU; return true; #endif /* Failure to get enough working to get a graphics set. */ failure: usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 4.1 of readme.txt."); return false; } openttd-1.5.3/src/newgrf_engine.cpp0000644000000000000000000013103412627373441016016 0ustar rootroot/* $Id: newgrf_engine.cpp 27075 2014-12-07 14:13:21Z frosch $ */ /* * 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 newgrf_engine.cpp NewGRF handling of engines. */ #include "stdafx.h" #include "debug.h" #include "train.h" #include "roadveh.h" #include "company_func.h" #include "newgrf_cargo.h" #include "newgrf_spritegroup.h" #include "date_func.h" #include "vehicle_func.h" #include "core/random_func.hpp" #include "aircraft.h" #include "station_base.h" #include "company_base.h" #include "newgrf_railtype.h" #include "ship.h" #include "safeguards.h" struct WagonOverride { EngineID *train_id; uint trains; CargoID cargo; const SpriteGroup *group; }; void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const SpriteGroup *group, EngineID *train_id, uint trains) { Engine *e = Engine::Get(engine); WagonOverride *wo; assert(cargo < NUM_CARGO + 2); // Include CT_DEFAULT and CT_PURCHASE pseudo cargoes. e->overrides_count++; e->overrides = ReallocT(e->overrides, e->overrides_count); wo = &e->overrides[e->overrides_count - 1]; wo->group = group; wo->cargo = cargo; wo->trains = trains; wo->train_id = MallocT(trains); memcpy(wo->train_id, train_id, trains * sizeof *train_id); } const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, EngineID overriding_engine) { const Engine *e = Engine::Get(engine); for (uint i = 0; i < e->overrides_count; i++) { const WagonOverride *wo = &e->overrides[i]; if (wo->cargo != cargo && wo->cargo != CT_DEFAULT) continue; for (uint j = 0; j < wo->trains; j++) { if (wo->train_id[j] == overriding_engine) return wo->group; } } return NULL; } /** * Unload all wagon override sprite groups. */ void UnloadWagonOverrides(Engine *e) { for (uint i = 0; i < e->overrides_count; i++) { WagonOverride *wo = &e->overrides[i]; free(wo->train_id); } free(e->overrides); e->overrides_count = 0; e->overrides = NULL; } void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *group) { Engine *e = Engine::Get(engine); assert(cargo < lengthof(e->grf_prop.spritegroup)); if (e->grf_prop.spritegroup[cargo] != NULL) { grfmsg(6, "SetCustomEngineSprites: engine %d cargo %d already has group -- replacing", engine, cargo); } e->grf_prop.spritegroup[cargo] = group; } /** * Tie a GRFFile entry to an engine, to allow us to retrieve GRF parameters * etc during a game. * @param engine Engine ID to tie the GRFFile to. * @param file Pointer of GRFFile to tie. */ void SetEngineGRF(EngineID engine, const GRFFile *file) { Engine *e = Engine::Get(engine); e->grf_prop.grffile = file; } static int MapOldSubType(const Vehicle *v) { switch (v->type) { case VEH_TRAIN: if (Train::From(v)->IsEngine()) return 0; if (Train::From(v)->IsFreeWagon()) return 4; return 2; case VEH_ROAD: case VEH_SHIP: return 0; case VEH_AIRCRAFT: case VEH_DISASTER: return v->subtype; case VEH_EFFECT: return v->subtype << 1; default: NOT_REACHED(); } } /* TTDP style aircraft movement states for GRF Action 2 Var 0xE2 */ enum TTDPAircraftMovementStates { AMS_TTDP_HANGAR, AMS_TTDP_TO_HANGAR, AMS_TTDP_TO_PAD1, AMS_TTDP_TO_PAD2, AMS_TTDP_TO_PAD3, AMS_TTDP_TO_ENTRY_2_AND_3, AMS_TTDP_TO_ENTRY_2_AND_3_AND_H, AMS_TTDP_TO_JUNCTION, AMS_TTDP_LEAVE_RUNWAY, AMS_TTDP_TO_INWAY, AMS_TTDP_TO_RUNWAY, AMS_TTDP_TO_OUTWAY, AMS_TTDP_WAITING, AMS_TTDP_TAKEOFF, AMS_TTDP_TO_TAKEOFF, AMS_TTDP_CLIMBING, AMS_TTDP_FLIGHT_APPROACH, AMS_TTDP_UNUSED_0x11, AMS_TTDP_FLIGHT_TO_TOWER, AMS_TTDP_UNUSED_0x13, AMS_TTDP_FLIGHT_FINAL, AMS_TTDP_FLIGHT_DESCENT, AMS_TTDP_BRAKING, AMS_TTDP_HELI_TAKEOFF_AIRPORT, AMS_TTDP_HELI_TO_TAKEOFF_AIRPORT, AMS_TTDP_HELI_LAND_AIRPORT, AMS_TTDP_HELI_TAKEOFF_HELIPORT, AMS_TTDP_HELI_TO_TAKEOFF_HELIPORT, AMS_TTDP_HELI_LAND_HELIPORT, }; /** * Map OTTD aircraft movement states to TTDPatch style movement states * (VarAction 2 Variable 0xE2) */ static byte MapAircraftMovementState(const Aircraft *v) { const Station *st = GetTargetAirportIfValid(v); if (st == NULL) return AMS_TTDP_FLIGHT_TO_TOWER; const AirportFTAClass *afc = st->airport.GetFTA(); uint16 amdflag = afc->MovingData(v->pos)->flag; switch (v->state) { case HANGAR: /* The international airport is a special case as helicopters can land in * front of the hangar. Helicopters also change their air.state to * AMED_HELI_LOWER some time before actually descending. */ /* This condition only occurs for helicopters, during descent, * to a landing by the hangar of an international airport. */ if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT; /* This condition only occurs for helicopters, before starting descent, * to a landing by the hangar of an international airport. */ if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER; /* The final two conditions apply to helicopters or aircraft. * Has reached hangar? */ if (amdflag & AMED_EXACTPOS) return AMS_TTDP_HANGAR; /* Still moving towards hangar. */ return AMS_TTDP_TO_HANGAR; case TERM1: if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD1; return AMS_TTDP_TO_JUNCTION; case TERM2: if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD2; return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H; case TERM3: case TERM4: case TERM5: case TERM6: case TERM7: case TERM8: /* TTDPatch only has 3 terminals, so treat these states the same */ if (amdflag & AMED_EXACTPOS) return AMS_TTDP_TO_PAD3; return AMS_TTDP_TO_ENTRY_2_AND_3_AND_H; case HELIPAD1: case HELIPAD2: case HELIPAD3: /* Will only occur for helicopters.*/ if (amdflag & AMED_HELI_LOWER) return AMS_TTDP_HELI_LAND_AIRPORT; // Descending. if (amdflag & AMED_SLOWTURN) return AMS_TTDP_FLIGHT_TO_TOWER; // Still hasn't started descent. return AMS_TTDP_TO_JUNCTION; // On the ground. case TAKEOFF: // Moving to takeoff position. return AMS_TTDP_TO_OUTWAY; case STARTTAKEOFF: // Accelerating down runway. return AMS_TTDP_TAKEOFF; case ENDTAKEOFF: // Ascent return AMS_TTDP_CLIMBING; case HELITAKEOFF: // Helicopter is moving to take off position. if (afc->delta_z == 0) { return amdflag & AMED_HELI_RAISE ? AMS_TTDP_HELI_TAKEOFF_AIRPORT : AMS_TTDP_TO_JUNCTION; } else { return AMS_TTDP_HELI_TAKEOFF_HELIPORT; } case FLYING: return amdflag & AMED_HOLD ? AMS_TTDP_FLIGHT_APPROACH : AMS_TTDP_FLIGHT_TO_TOWER; case LANDING: // Descent return AMS_TTDP_FLIGHT_DESCENT; case ENDLANDING: // On the runway braking if (amdflag & AMED_BRAKE) return AMS_TTDP_BRAKING; /* Landed - moving off runway */ return AMS_TTDP_TO_INWAY; case HELILANDING: case HELIENDLANDING: // Helicoptor is decending. if (amdflag & AMED_HELI_LOWER) { return afc->delta_z == 0 ? AMS_TTDP_HELI_LAND_AIRPORT : AMS_TTDP_HELI_LAND_HELIPORT; } else { return AMS_TTDP_FLIGHT_TO_TOWER; } default: return AMS_TTDP_HANGAR; } } /* TTDP style aircraft movement action for GRF Action 2 Var 0xE6 */ enum TTDPAircraftMovementActions { AMA_TTDP_IN_HANGAR, AMA_TTDP_ON_PAD1, AMA_TTDP_ON_PAD2, AMA_TTDP_ON_PAD3, AMA_TTDP_HANGAR_TO_PAD1, AMA_TTDP_HANGAR_TO_PAD2, AMA_TTDP_HANGAR_TO_PAD3, AMA_TTDP_LANDING_TO_PAD1, AMA_TTDP_LANDING_TO_PAD2, AMA_TTDP_LANDING_TO_PAD3, AMA_TTDP_PAD1_TO_HANGAR, AMA_TTDP_PAD2_TO_HANGAR, AMA_TTDP_PAD3_TO_HANGAR, AMA_TTDP_PAD1_TO_TAKEOFF, AMA_TTDP_PAD2_TO_TAKEOFF, AMA_TTDP_PAD3_TO_TAKEOFF, AMA_TTDP_HANGAR_TO_TAKOFF, AMA_TTDP_LANDING_TO_HANGAR, AMA_TTDP_IN_FLIGHT, }; /** * Map OTTD aircraft movement states to TTDPatch style movement actions * (VarAction 2 Variable 0xE6) * This is not fully supported yet but it's enough for Planeset. */ static byte MapAircraftMovementAction(const Aircraft *v) { switch (v->state) { case HANGAR: return (v->cur_speed > 0) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_IN_HANGAR; case TERM1: case HELIPAD1: return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD1 : AMA_TTDP_LANDING_TO_PAD1; case TERM2: case HELIPAD2: return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD2 : AMA_TTDP_LANDING_TO_PAD2; case TERM3: case TERM4: case TERM5: case TERM6: case TERM7: case TERM8: case HELIPAD3: return (v->current_order.IsType(OT_LOADING)) ? AMA_TTDP_ON_PAD3 : AMA_TTDP_LANDING_TO_PAD3; case TAKEOFF: // Moving to takeoff position case STARTTAKEOFF: // Accelerating down runway case ENDTAKEOFF: // Ascent case HELITAKEOFF: /* @todo Need to find which terminal (or hangar) we've come from. How? */ return AMA_TTDP_PAD1_TO_TAKEOFF; case FLYING: return AMA_TTDP_IN_FLIGHT; case LANDING: // Descent case ENDLANDING: // On the runway braking case HELILANDING: case HELIENDLANDING: /* @todo Need to check terminal we're landing to. Is it known yet? */ return (v->current_order.IsType(OT_GOTO_DEPOT)) ? AMA_TTDP_LANDING_TO_HANGAR : AMA_TTDP_LANDING_TO_PAD1; default: return AMA_TTDP_IN_HANGAR; } } /* virtual */ uint32 VehicleScopeResolver::GetRandomBits() const { return this->v == NULL ? 0 : this->v->random_bits; } /* virtual */ uint32 VehicleScopeResolver::GetTriggers() const { return this->v == NULL ? 0 : this->v->waiting_triggers; } /* virtual */ void VehicleScopeResolver::SetTriggers(int triggers) const { /* Evil cast to get around const-ness. This used to be achieved by an * innocent looking function pointer cast... Currently I cannot see a * way of avoiding this without removing consts deep within gui code. */ Vehicle *v = const_cast(this->v); /* This function must only be called when processing triggers -- any * other time is an error. */ assert(this->ro.trigger != 0); if (v != NULL) v->waiting_triggers = triggers; } /* virtual */ ScopeResolver *VehicleResolverObject::GetScope(VarSpriteGroupScope scope, byte relative) { switch (scope) { case VSG_SCOPE_SELF: return &this->self_scope; case VSG_SCOPE_PARENT: return &this->parent_scope; case VSG_SCOPE_RELATIVE: { int32 count = GB(relative, 0, 4); if (this->self_scope.v != NULL && (relative != this->cached_relative_count || count == 0)) { /* Note: This caching only works as long as the VSG_SCOPE_RELATIVE cannot be used in * VarAct2 with procedure calls. */ if (count == 0) count = GetRegister(0x100); const Vehicle *v = NULL; switch (GB(relative, 6, 2)) { default: NOT_REACHED(); case 0x00: // count back (away from the engine), starting at this vehicle v = this->self_scope.v; break; case 0x01: // count forward (toward the engine), starting at this vehicle v = this->self_scope.v; count = -count; break; case 0x02: // count back, starting at the engine v = this->parent_scope.v; break; case 0x03: { // count back, starting at the first vehicle in this chain of vehicles with the same ID, as for vehicle variable 41 const Vehicle *self = this->self_scope.v; for (const Vehicle *u = self->First(); u != self; u = u->Next()) { if (u->engine_type != self->engine_type) { v = NULL; } else { if (v == NULL) v = u; } } if (v == NULL) v = self; break; } } this->relative_scope.SetVehicle(v->Move(count)); } return &this->relative_scope; } default: return ResolverObject::GetScope(scope, relative); } } /** * Determines the livery of an engine. * * This always uses dual company colours independent of GUI settings. So it is desync-safe. * * @param engine Engine type * @param v Vehicle, NULL in purchase list. * @return Livery to use */ static const Livery *LiveryHelper(EngineID engine, const Vehicle *v) { const Livery *l; if (v == NULL) { if (!Company::IsValidID(_current_company)) return NULL; l = GetEngineLivery(engine, _current_company, INVALID_ENGINE, NULL, LIT_ALL); } else if (v->IsGroundVehicle()) { l = GetEngineLivery(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v, LIT_ALL); } else { l = GetEngineLivery(v->engine_type, v->owner, INVALID_ENGINE, v, LIT_ALL); } return l; } /** * Helper to get the position of a vehicle within a chain of vehicles. * @param v the vehicle to get the position of. * @param consecutive whether to look at the whole chain or the vehicles * with the same 'engine type'. * @return the position in the chain from front and tail and chain length. */ static uint32 PositionHelper(const Vehicle *v, bool consecutive) { const Vehicle *u; byte chain_before = 0; byte chain_after = 0; for (u = v->First(); u != v; u = u->Next()) { chain_before++; if (consecutive && u->engine_type != v->engine_type) chain_before = 0; } while (u->Next() != NULL && (!consecutive || u->Next()->engine_type == v->engine_type)) { chain_after++; u = u->Next(); } return chain_before | chain_after << 8 | (chain_before + chain_after + consecutive) << 16; } static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, byte variable, uint32 parameter, bool *available) { /* Calculated vehicle parameters */ switch (variable) { case 0x25: // Get engine GRF ID return v->GetGRFID(); case 0x40: // Get length of consist if (!HasBit(v->grf_cache.cache_valid, NCVV_POSITION_CONSIST_LENGTH)) { v->grf_cache.position_consist_length = PositionHelper(v, false); SetBit(v->grf_cache.cache_valid, NCVV_POSITION_CONSIST_LENGTH); } return v->grf_cache.position_consist_length; case 0x41: // Get length of same consecutive wagons if (!HasBit(v->grf_cache.cache_valid, NCVV_POSITION_SAME_ID_LENGTH)) { v->grf_cache.position_same_id_length = PositionHelper(v, true); SetBit(v->grf_cache.cache_valid, NCVV_POSITION_SAME_ID_LENGTH); } return v->grf_cache.position_same_id_length; case 0x42: { // Consist cargo information if (!HasBit(v->grf_cache.cache_valid, NCVV_CONSIST_CARGO_INFORMATION)) { const Vehicle *u; byte cargo_classes = 0; uint8 common_cargoes[NUM_CARGO]; uint8 common_subtypes[256]; byte user_def_data = 0; CargoID common_cargo_type = CT_INVALID; uint8 common_subtype = 0xFF; // Return 0xFF if nothing is carried /* Reset our arrays */ memset(common_cargoes, 0, sizeof(common_cargoes)); memset(common_subtypes, 0, sizeof(common_subtypes)); for (u = v; u != NULL; u = u->Next()) { if (v->type == VEH_TRAIN) user_def_data |= Train::From(u)->tcache.user_def_data; /* Skip empty engines */ if (!u->GetEngine()->CanCarryCargo()) continue; cargo_classes |= CargoSpec::Get(u->cargo_type)->classes; common_cargoes[u->cargo_type]++; } /* Pick the most common cargo type */ uint common_cargo_best_amount = 0; for (CargoID cargo = 0; cargo < NUM_CARGO; cargo++) { if (common_cargoes[cargo] > common_cargo_best_amount) { common_cargo_best_amount = common_cargoes[cargo]; common_cargo_type = cargo; } } /* Count subcargo types of common_cargo_type */ for (u = v; u != NULL; u = u->Next()) { /* Skip empty engines and engines not carrying common_cargo_type */ if (u->cargo_type != common_cargo_type || !u->GetEngine()->CanCarryCargo()) continue; common_subtypes[u->cargo_subtype]++; } /* Pick the most common subcargo type*/ uint common_subtype_best_amount = 0; for (uint i = 0; i < lengthof(common_subtypes); i++) { if (common_subtypes[i] > common_subtype_best_amount) { common_subtype_best_amount = common_subtypes[i]; common_subtype = i; } } /* Note: We have to store the untranslated cargotype in the cache as the cache can be read by different NewGRFs, * which will need different translations */ v->grf_cache.consist_cargo_information = cargo_classes | (common_cargo_type << 8) | (common_subtype << 16) | (user_def_data << 24); SetBit(v->grf_cache.cache_valid, NCVV_CONSIST_CARGO_INFORMATION); } /* The cargo translation is specific to the accessing GRF, and thus cannot be cached. */ CargoID common_cargo_type = (v->grf_cache.consist_cargo_information >> 8) & 0xFF; /* Note: * - Unlike everywhere else the cargo translation table is only used since grf version 8, not 7. * - For translating the cargo type we need to use the GRF which is resolving the variable, which * is object->ro.grffile. * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF(). * - The grffile == NULL case only happens if this function is called for default vehicles. * And this is only done by CheckCaches(). */ const GRFFile *grffile = object->ro.grffile; uint8 common_bitnum = (common_cargo_type == CT_INVALID) ? 0xFF : (grffile == NULL || grffile->grf_version < 8) ? CargoSpec::Get(common_cargo_type)->bitnum : grffile->cargo_map[common_cargo_type]; return (v->grf_cache.consist_cargo_information & 0xFFFF00FF) | common_bitnum << 8; } case 0x43: // Company information if (!HasBit(v->grf_cache.cache_valid, NCVV_COMPANY_INFORMATION)) { v->grf_cache.company_information = GetCompanyInfo(v->owner, LiveryHelper(v->engine_type, v)); SetBit(v->grf_cache.cache_valid, NCVV_COMPANY_INFORMATION); } return v->grf_cache.company_information; case 0x44: // Aircraft information if (v->type != VEH_AIRCRAFT || !Aircraft::From(v)->IsNormalAircraft()) return UINT_MAX; { const Vehicle *w = v->Next(); uint16 altitude = ClampToU16(v->z_pos - w->z_pos); // Aircraft height - shadow height byte airporttype = ATP_TTDP_LARGE; const Station *st = GetTargetAirportIfValid(Aircraft::From(v)); if (st != NULL && st->airport.tile != INVALID_TILE) { airporttype = st->airport.GetSpec()->ttd_airport_type; } return (Clamp(altitude, 0, 0xFF) << 8) | airporttype; } case 0x45: { // Curvature info /* Format: xxxTxBxF * F - previous wagon to current wagon, 0 if vehicle is first * B - current wagon to next wagon, 0 if wagon is last * T - previous wagon to next wagon, 0 in an S-bend */ if (!v->IsGroundVehicle()) return 0; const Vehicle *u_p = v->Previous(); const Vehicle *u_n = v->Next(); DirDiff f = (u_p == NULL) ? DIRDIFF_SAME : DirDifference(u_p->direction, v->direction); DirDiff b = (u_n == NULL) ? DIRDIFF_SAME : DirDifference(v->direction, u_n->direction); DirDiff t = ChangeDirDiff(f, b); return ((t > DIRDIFF_REVERSE ? t | 8 : t) << 16) | ((b > DIRDIFF_REVERSE ? b | 8 : b) << 8) | ( f > DIRDIFF_REVERSE ? f | 8 : f); } case 0x46: // Motion counter return v->motion_counter; case 0x47: { // Vehicle cargo info /* Format: ccccwwtt * tt - the cargo type transported by the vehicle, * translated if a translation table has been installed. * ww - cargo unit weight in 1/16 tons, same as cargo prop. 0F. * cccc - the cargo class value of the cargo transported by the vehicle. */ const CargoSpec *cs = CargoSpec::Get(v->cargo_type); /* Note: * For translating the cargo type we need to use the GRF which is resolving the variable, which * is object->ro.grffile. * In case of CBID_TRAIN_ALLOW_WAGON_ATTACH this is not the same as v->GetGRF(). */ return (cs->classes << 16) | (cs->weight << 8) | object->ro.grffile->cargo_map[v->cargo_type]; } case 0x48: return v->GetEngine()->flags; // Vehicle Type Info case 0x49: return v->build_year; case 0x4A: { if (v->type != VEH_TRAIN) return 0; RailType rt = GetTileRailType(v->tile); return (HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) | GetReverseRailTypeTranslation(rt, object->ro.grffile); } case 0x4B: // Long date of last service return v->date_of_last_service; case 0x4C: // Current maximum speed in NewGRF units if (!v->IsPrimaryVehicle()) return 0; return v->GetCurrentMaxSpeed(); case 0x4D: // Position within articulated vehicle if (!HasBit(v->grf_cache.cache_valid, NCVV_POSITION_IN_VEHICLE)) { byte artic_before = 0; for (const Vehicle *u = v; u->IsArticulatedPart(); u = u->Previous()) artic_before++; byte artic_after = 0; for (const Vehicle *u = v; u->HasArticulatedPart(); u = u->Next()) artic_after++; v->grf_cache.position_in_vehicle = artic_before | artic_after << 8; SetBit(v->grf_cache.cache_valid, NCVV_POSITION_IN_VEHICLE); } return v->grf_cache.position_in_vehicle; /* Variables which use the parameter */ case 0x60: // Count consist's engine ID occurrence if (v->type != VEH_TRAIN) return v->GetEngine()->grf_prop.local_id == parameter ? 1 : 0; { uint count = 0; for (; v != NULL; v = v->Next()) { if (v->GetEngine()->grf_prop.local_id == parameter) count++; } return count; } case 0x61: // Get variable of n-th vehicle in chain [signed number relative to vehicle] if (!v->IsGroundVehicle() || parameter == 0x61) { /* Not available */ break; } /* Only allow callbacks that don't change properties to avoid circular dependencies. */ if (object->ro.callback == CBID_NO_CALLBACK || object->ro.callback == CBID_RANDOM_TRIGGER || object->ro.callback == CBID_TRAIN_ALLOW_WAGON_ATTACH || object->ro.callback == CBID_VEHICLE_START_STOP_CHECK || object->ro.callback == CBID_VEHICLE_32DAY_CALLBACK || object->ro.callback == CBID_VEHICLE_COLOUR_MAPPING || object->ro.callback == CBID_VEHICLE_SPAWN_VISUAL_EFFECT) { Vehicle *u = v->Move((int32)GetRegister(0x10F)); if (u == NULL) return 0; // available, but zero if (parameter == 0x5F) { /* This seems to be the only variable that makes sense to access via var 61, but is not handled by VehicleGetVariable */ return (u->random_bits << 8) | u->waiting_triggers; } else { return VehicleGetVariable(u, object, parameter, GetRegister(0x10E), available); } } /* Not available */ break; case 0x62: { // Curvature/position difference for n-th vehicle in chain [signed number relative to vehicle] /* Format: zzyyxxFD * zz - Signed difference of z position between the selected and this vehicle. * yy - Signed difference of y position between the selected and this vehicle. * xx - Signed difference of x position between the selected and this vehicle. * F - Flags, bit 7 corresponds to VS_HIDDEN. * D - Dir difference, like in 0x45. */ if (!v->IsGroundVehicle()) return 0; const Vehicle *u = v->Move((int8)parameter); if (u == NULL) return 0; /* Get direction difference. */ bool prev = (int8)parameter < 0; uint32 ret = prev ? DirDifference(u->direction, v->direction) : DirDifference(v->direction, u->direction); if (ret > DIRDIFF_REVERSE) ret |= 0x08; if (u->vehstatus & VS_HIDDEN) ret |= 0x80; /* Get position difference. */ ret |= ((prev ? u->x_pos - v->x_pos : v->x_pos - u->x_pos) & 0xFF) << 8; ret |= ((prev ? u->y_pos - v->y_pos : v->y_pos - u->y_pos) & 0xFF) << 16; ret |= ((prev ? u->z_pos - v->z_pos : v->z_pos - u->z_pos) & 0xFF) << 24; return ret; } case 0xFE: case 0xFF: { uint16 modflags = 0; if (v->type == VEH_TRAIN) { const Train *t = Train::From(v); bool is_powered_wagon = HasBit(t->flags, VRF_POWEREDWAGON); const Train *u = is_powered_wagon ? t->First() : t; // for powered wagons the engine defines the type of engine (i.e. railtype) RailType railtype = GetRailType(v->tile); bool powered = t->IsEngine() || is_powered_wagon; bool has_power = HasPowerOnRail(u->railtype, railtype); if (powered && has_power) SetBit(modflags, 5); if (powered && !has_power) SetBit(modflags, 6); if (HasBit(t->flags, VRF_TOGGLE_REVERSE)) SetBit(modflags, 8); } if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING)) SetBit(modflags, 1); if (HasBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE)) SetBit(modflags, 10); return variable == 0xFE ? modflags : GB(modflags, 8, 8); } } /* General vehicle properties */ switch (variable - 0x80) { case 0x00: return v->type + 0x10; case 0x01: return MapOldSubType(v); case 0x04: return v->index; case 0x05: return GB(v->index, 8, 8); case 0x0A: return v->current_order.MapOldOrder(); case 0x0B: return v->current_order.GetDestination(); case 0x0C: return v->GetNumOrders(); case 0x0D: return v->cur_real_order_index; case 0x10: case 0x11: { uint ticks; if (v->current_order.IsType(OT_LOADING)) { ticks = v->load_unload_ticks; } else { switch (v->type) { case VEH_TRAIN: ticks = Train::From(v)->wait_counter; break; case VEH_AIRCRAFT: ticks = Aircraft::From(v)->turn_counter; break; default: ticks = 0; break; } } return (variable - 0x80) == 0x10 ? ticks : GB(ticks, 8, 8); } case 0x12: return Clamp(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF); case 0x13: return GB(Clamp(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF), 8, 8); case 0x14: return v->GetServiceInterval(); case 0x15: return GB(v->GetServiceInterval(), 8, 8); case 0x16: return v->last_station_visited; case 0x17: return v->tick_counter; case 0x18: case 0x19: { uint max_speed; switch (v->type) { case VEH_AIRCRAFT: max_speed = Aircraft::From(v)->GetSpeedOldUnits(); // Convert to old units. break; default: max_speed = v->vcache.cached_max_speed; break; } return (variable - 0x80) == 0x18 ? max_speed : GB(max_speed, 8, 8); } case 0x1A: return v->x_pos; case 0x1B: return GB(v->x_pos, 8, 8); case 0x1C: return v->y_pos; case 0x1D: return GB(v->y_pos, 8, 8); case 0x1E: return v->z_pos; case 0x1F: return object->info_view ? DIR_W : v->direction; case 0x28: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs. case 0x29: return 0; // cur_image is a potential desyncer due to Action1 in static NewGRFs. case 0x32: return v->vehstatus; case 0x33: return 0; // non-existent high byte of vehstatus case 0x34: return v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed; case 0x35: return GB(v->type == VEH_AIRCRAFT ? (v->cur_speed * 10) / 128 : v->cur_speed, 8, 8); case 0x36: return v->subspeed; case 0x37: return v->acceleration; case 0x39: return v->cargo_type; case 0x3A: return v->cargo_cap; case 0x3B: return GB(v->cargo_cap, 8, 8); case 0x3C: return ClampToU16(v->cargo.StoredCount()); case 0x3D: return GB(ClampToU16(v->cargo.StoredCount()), 8, 8); case 0x3E: return v->cargo.Source(); case 0x3F: return ClampU(v->cargo.DaysInTransit(), 0, 0xFF); case 0x40: return ClampToU16(v->age); case 0x41: return GB(ClampToU16(v->age), 8, 8); case 0x42: return ClampToU16(v->max_age); case 0x43: return GB(ClampToU16(v->max_age), 8, 8); case 0x44: return Clamp(v->build_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; case 0x45: return v->unitnumber; case 0x46: return v->GetEngine()->grf_prop.local_id; case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8); case 0x48: if (v->type != VEH_TRAIN || v->spritenum != 0xFD) return v->spritenum; return HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION) ? 0xFE : 0xFD; case 0x49: return v->day_counter; case 0x4A: return v->breakdowns_since_last_service; case 0x4B: return v->breakdown_ctr; case 0x4C: return v->breakdown_delay; case 0x4D: return v->breakdown_chance; case 0x4E: return v->reliability; case 0x4F: return GB(v->reliability, 8, 8); case 0x50: return v->reliability_spd_dec; case 0x51: return GB(v->reliability_spd_dec, 8, 8); case 0x52: return ClampToI32(v->GetDisplayProfitThisYear()); case 0x53: return GB(ClampToI32(v->GetDisplayProfitThisYear()), 8, 24); case 0x54: return GB(ClampToI32(v->GetDisplayProfitThisYear()), 16, 16); case 0x55: return GB(ClampToI32(v->GetDisplayProfitThisYear()), 24, 8); case 0x56: return ClampToI32(v->GetDisplayProfitLastYear()); case 0x57: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 8, 24); case 0x58: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 16, 16); case 0x59: return GB(ClampToI32(v->GetDisplayProfitLastYear()), 24, 8); case 0x5A: return v->Next() == NULL ? INVALID_VEHICLE : v->Next()->index; case 0x5C: return ClampToI32(v->value); case 0x5D: return GB(ClampToI32(v->value), 8, 24); case 0x5E: return GB(ClampToI32(v->value), 16, 16); case 0x5F: return GB(ClampToI32(v->value), 24, 8); case 0x72: return v->cargo_subtype; case 0x7A: return v->random_bits; case 0x7B: return v->waiting_triggers; } /* Vehicle specific properties */ switch (v->type) { case VEH_TRAIN: { Train *t = Train::From(v); switch (variable - 0x80) { case 0x62: return t->track; case 0x66: return t->railtype; case 0x73: return 0x80 + VEHICLE_LENGTH - t->gcache.cached_veh_length; case 0x74: return t->gcache.cached_power; case 0x75: return GB(t->gcache.cached_power, 8, 24); case 0x76: return GB(t->gcache.cached_power, 16, 16); case 0x77: return GB(t->gcache.cached_power, 24, 8); case 0x7C: return t->First()->index; case 0x7D: return GB(t->First()->index, 8, 8); case 0x7F: return 0; // Used for vehicle reversing hack in TTDP } break; } case VEH_ROAD: { RoadVehicle *rv = RoadVehicle::From(v); switch (variable - 0x80) { case 0x62: return rv->state; case 0x64: return rv->blocked_ctr; case 0x65: return GB(rv->blocked_ctr, 8, 8); case 0x66: return rv->overtaking; case 0x67: return rv->overtaking_ctr; case 0x68: return rv->crashed_ctr; case 0x69: return GB(rv->crashed_ctr, 8, 8); } break; } case VEH_SHIP: { Ship *s = Ship::From(v); switch (variable - 0x80) { case 0x62: return s->state; } break; } case VEH_AIRCRAFT: { Aircraft *a = Aircraft::From(v); switch (variable - 0x80) { case 0x62: return MapAircraftMovementState(a); // Current movement state case 0x63: return a->targetairport; // Airport to which the action refers case 0x66: return MapAircraftMovementAction(a); // Current movement action } break; } default: break; } DEBUG(grf, 1, "Unhandled vehicle variable 0x%X, type 0x%X", variable, (uint)v->type); *available = false; return UINT_MAX; } /* virtual */ uint32 VehicleScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { if (this->v == NULL) { /* Vehicle does not exist, so we're in a purchase list */ switch (variable) { case 0x43: return GetCompanyInfo(_current_company, LiveryHelper(this->self_type, NULL)); // Owner information case 0x46: return 0; // Motion counter case 0x47: { // Vehicle cargo info const Engine *e = Engine::Get(this->self_type); CargoID cargo_type = e->GetDefaultCargoType(); if (cargo_type != CT_INVALID) { const CargoSpec *cs = CargoSpec::Get(cargo_type); return (cs->classes << 16) | (cs->weight << 8) | this->ro.grffile->cargo_map[cargo_type]; } else { return 0x000000FF; } } case 0x48: return Engine::Get(this->self_type)->flags; // Vehicle Type Info case 0x49: return _cur_year; // 'Long' format build year case 0x4B: return _date; // Long date of last service case 0x92: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF); // Date of last service case 0x93: return GB(Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 0xFFFF), 8, 8); case 0xC4: return Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; // Build year case 0xDA: return INVALID_VEHICLE; // Next vehicle case 0xF2: return 0; // Cargo subtype } *available = false; return UINT_MAX; } return VehicleGetVariable(const_cast(this->v), this, variable, parameter, available); } /* virtual */ const SpriteGroup *VehicleResolverObject::ResolveReal(const RealSpriteGroup *group) const { const Vehicle *v = this->self_scope.v; if (v == NULL) { if (group->num_loading > 0) return group->loading[0]; if (group->num_loaded > 0) return group->loaded[0]; return NULL; } bool in_motion = !v->First()->current_order.IsType(OT_LOADING); uint totalsets = in_motion ? group->num_loaded : group->num_loading; if (totalsets == 0) return NULL; uint set = (v->cargo.StoredCount() * totalsets) / max((uint16)1, v->cargo_cap); set = min(set, totalsets - 1); return in_motion ? group->loaded[set] : group->loading[set]; } /** * Scope resolver of a single vehicle. * @param ro Surrounding resolver. * @param engine_type Engine type * @param v %Vehicle being resolved. * @param info_view Indicates if the item is being drawn in an info window. */ VehicleScopeResolver::VehicleScopeResolver(ResolverObject &ro, EngineID engine_type, const Vehicle *v, bool info_view) : ScopeResolver(ro) { this->v = v; this->self_type = engine_type; this->info_view = info_view; } /** * Get the grf file associated with an engine type. * @param engine_type Engine to query. * @return grf file associated with the engine. */ static const GRFFile *GetEngineGrfFile(EngineID engine_type) { const Engine *e = Engine::Get(engine_type); return (e != NULL) ? e->GetGRF() : NULL; } /** * Resolver of a vehicle (chain). * @param engine_type Engine type * @param v %Vehicle being resolved. * @param wagon_override Application of wagon overrides. * @param info_view Indicates if the item is being drawn in an info window. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool info_view, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(GetEngineGrfFile(engine_type), callback, callback_param1, callback_param2), self_scope(*this, engine_type, v, info_view), parent_scope(*this, engine_type, ((v != NULL) ? v->First() : v), info_view), relative_scope(*this, engine_type, v, info_view), cached_relative_count(0) { if (wagon_override == WO_SELF) { this->root_spritegroup = GetWagonOverrideSpriteSet(engine_type, CT_DEFAULT, engine_type); } else { if (wagon_override != WO_NONE && v != NULL && v->IsGroundVehicle()) { assert(v->engine_type == engine_type); // overrides make little sense with fake scopes /* For trains we always use cached value, except for callbacks because the override spriteset * to use may be different than the one cached. It happens for callback 0x15 (refit engine), * as v->cargo_type is temporary changed to the new type */ if (wagon_override == WO_CACHED && v->type == VEH_TRAIN) { this->root_spritegroup = Train::From(v)->tcache.cached_override; } else { this->root_spritegroup = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->GetGroundVehicleCache()->first_engine); } } if (this->root_spritegroup == NULL) { const Engine *e = Engine::Get(engine_type); CargoID cargo = v != NULL ? v->cargo_type : CT_PURCHASE; assert(cargo < lengthof(e->grf_prop.spritegroup)); this->root_spritegroup = e->grf_prop.spritegroup[cargo] != NULL ? e->grf_prop.spritegroup[cargo] : e->grf_prop.spritegroup[CT_DEFAULT]; } } } SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type) { VehicleResolverObject object(engine, v, VehicleResolverObject::WO_CACHED, false, CBID_NO_CALLBACK, image_type); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->GetNumResults() == 0) return 0; return group->GetResult() + (direction % group->GetNumResults()); } SpriteID GetRotorOverrideSprite(EngineID engine, const Aircraft *v, bool info_view, EngineImageType image_type) { const Engine *e = Engine::Get(engine); /* Only valid for helicopters */ assert(e->type == VEH_AIRCRAFT); assert(!(e->u.air.subtype & AIR_CTOL)); VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK, image_type); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->GetNumResults() == 0) return 0; if (v == NULL || info_view) return group->GetResult(); return group->GetResult() + (v->Next()->Next()->state % group->GetNumResults()); } /** * Check if a wagon is currently using a wagon override * @param v The wagon to check * @return true if it is using an override, false otherwise */ bool UsesWagonOverride(const Vehicle *v) { assert(v->type == VEH_TRAIN); return Train::From(v)->tcache.cached_override != NULL; } /** * Evaluate a newgrf callback for vehicles * @param callback The callback to evaluate * @param param1 First parameter of the callback * @param param2 Second parameter of the callback * @param engine Engine type of the vehicle to evaluate the callback for * @param v The vehicle to evaluate the callback for, or NULL if it doesnt exist yet * @return The value the callback returned, or CALLBACK_FAILED if it failed */ uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v) { VehicleResolverObject object(engine, v, VehicleResolverObject::WO_UNCACHED, false, callback, param1, param2); return object.ResolveCallback(); } /** * Evaluate a newgrf callback for vehicles with a different vehicle for parent scope. * @param callback The callback to evaluate * @param param1 First parameter of the callback * @param param2 Second parameter of the callback * @param engine Engine type of the vehicle to evaluate the callback for * @param v The vehicle to evaluate the callback for, or NULL if it doesn't exist yet * @param parent The vehicle to use for parent scope * @return The value the callback returned, or CALLBACK_FAILED if it failed */ uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent) { VehicleResolverObject object(engine, v, VehicleResolverObject::WO_NONE, false, callback, param1, param2); object.parent_scope.SetVehicle(parent); return object.ResolveCallback(); } /* Callback 36 handlers */ uint GetVehicleProperty(const Vehicle *v, PropertyID property, uint orig_value) { return GetEngineProperty(v->engine_type, property, orig_value, v); } uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, const Vehicle *v) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_MODIFY_PROPERTY, property, 0, engine, v); if (callback != CALLBACK_FAILED) return callback; return orig_value; } static void DoTriggerVehicle(Vehicle *v, VehicleTrigger trigger, byte base_random_bits, bool first) { /* We can't trigger a non-existent vehicle... */ assert(v != NULL); VehicleResolverObject object(v->engine_type, v, VehicleResolverObject::WO_CACHED, false, CBID_RANDOM_TRIGGER); object.trigger = trigger; const SpriteGroup *group = object.Resolve(); if (group == NULL) return; byte new_random_bits = Random(); uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding v->random_bits &= ~reseed; v->random_bits |= (first ? new_random_bits : base_random_bits) & reseed; switch (trigger) { case VEHICLE_TRIGGER_NEW_CARGO: /* All vehicles in chain get ANY_NEW_CARGO trigger now. * So we call it for the first one and they will recurse. * Indexing part of vehicle random bits needs to be * same for all triggered vehicles in the chain (to get * all the random-cargo wagons carry the same cargo, * i.e.), so we give them all the NEW_CARGO triggered * vehicle's portion of random bits. */ assert(first); DoTriggerVehicle(v->First(), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false); break; case VEHICLE_TRIGGER_DEPOT: /* We now trigger the next vehicle in chain recursively. * The random bits portions may be different for each * vehicle in chain. */ if (v->Next() != NULL) DoTriggerVehicle(v->Next(), trigger, 0, true); break; case VEHICLE_TRIGGER_EMPTY: /* We now trigger the next vehicle in chain * recursively. The random bits portions must be same * for each vehicle in chain, so we give them all * first chained vehicle's portion of random bits. */ if (v->Next() != NULL) DoTriggerVehicle(v->Next(), trigger, first ? new_random_bits : base_random_bits, false); break; case VEHICLE_TRIGGER_ANY_NEW_CARGO: /* Now pass the trigger recursively to the next vehicle * in chain. */ assert(!first); if (v->Next() != NULL) DoTriggerVehicle(v->Next(), VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false); break; case VEHICLE_TRIGGER_CALLBACK_32: /* Do not do any recursion */ break; } } void TriggerVehicle(Vehicle *v, VehicleTrigger trigger) { if (trigger == VEHICLE_TRIGGER_DEPOT) { /* store that the vehicle entered a depot this tick */ VehicleEnteredDepotThisTick(v); } v->InvalidateNewGRFCacheOfChain(); DoTriggerVehicle(v, trigger, 0, true); v->InvalidateNewGRFCacheOfChain(); } /* Functions for changing the order of vehicle purchase lists */ struct ListOrderChange { EngineID engine; uint target; ///< local ID }; static SmallVector _list_order_changes; /** * Record a vehicle ListOrderChange. * @param engine Engine to move * @param target Local engine ID to move \a engine in front of * @note All sorting is done later in CommitVehicleListOrderChanges */ void AlterVehicleListOrder(EngineID engine, uint target) { /* Add the list order change to a queue */ ListOrderChange *loc = _list_order_changes.Append(); loc->engine = engine; loc->target = target; } /** * Comparator function to sort engines via scope-GRFID and local ID. * @param a left side * @param b right side * @return comparison result */ static int CDECL EnginePreSort(const EngineID *a, const EngineID *b) { const EngineIDMapping *id_a = _engine_mngr.Get(*a); const EngineIDMapping *id_b = _engine_mngr.Get(*b); /* 1. Sort by engine type */ if (id_a->type != id_b->type) return (int)id_a->type - (int)id_b->type; /* 2. Sort by scope-GRFID */ if (id_a->grfid != id_b->grfid) return id_a->grfid < id_b->grfid ? -1 : 1; /* 3. Sort by local ID */ return (int)id_a->internal_id - (int)id_b->internal_id; } /** * Deternine default engine sorting and execute recorded ListOrderChanges from AlterVehicleListOrder. */ void CommitVehicleListOrderChanges() { /* Pre-sort engines by scope-grfid and local index */ SmallVector ordering; Engine *e; FOR_ALL_ENGINES(e) { *ordering.Append() = e->index; } QSortT(ordering.Begin(), ordering.Length(), EnginePreSort); /* Apply Insertion-Sort operations */ const ListOrderChange *end = _list_order_changes.End(); for (const ListOrderChange *it = _list_order_changes.Begin(); it != end; ++it) { EngineID source = it->engine; uint local_target = it->target; const EngineIDMapping *id_source = _engine_mngr.Get(source); if (id_source->internal_id == local_target) continue; EngineID target = _engine_mngr.GetID(id_source->type, local_target, id_source->grfid); if (target == INVALID_ENGINE) continue; int source_index = ordering.FindIndex(source); int target_index = ordering.FindIndex(target); assert(source_index >= 0 && target_index >= 0); assert(source_index != target_index); EngineID *list = ordering.Begin(); if (source_index < target_index) { --target_index; for (int i = source_index; i < target_index; ++i) list[i] = list[i + 1]; list[target_index] = source; } else { for (int i = source_index; i > target_index; --i) list[i] = list[i - 1]; list[target_index] = source; } } /* Store final sort-order */ const EngineID *idend = ordering.End(); uint index = 0; for (const EngineID *it = ordering.Begin(); it != idend; ++it, ++index) { Engine::Get(*it)->list_position = index; } /* Clear out the queue */ _list_order_changes.Reset(); } /** * Fill the grf_cache of the given vehicle. * @param v The vehicle to fill the cache for. */ void FillNewGRFVehicleCache(const Vehicle *v) { VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_NONE); /* These variables we have to check; these are the ones with a cache. */ static const int cache_entries[][2] = { { 0x40, NCVV_POSITION_CONSIST_LENGTH }, { 0x41, NCVV_POSITION_SAME_ID_LENGTH }, { 0x42, NCVV_CONSIST_CARGO_INFORMATION }, { 0x43, NCVV_COMPANY_INFORMATION }, { 0x4D, NCVV_POSITION_IN_VEHICLE }, }; assert_compile(NCVV_END == lengthof(cache_entries)); /* Resolve all the variables, so their caches are set. */ for (size_t i = 0; i < lengthof(cache_entries); i++) { /* Only resolve when the cache isn't valid. */ if (HasBit(v->grf_cache.cache_valid, cache_entries[i][1])) continue; bool stub; ro.GetScope(VSG_SCOPE_SELF)->GetVariable(cache_entries[i][0], 0, &stub); } /* Make sure really all bits are set. */ assert(v->grf_cache.cache_valid == (1 << NCVV_END) - 1); } openttd-1.5.3/src/industry.h0000644000000000000000000001570012627373434014532 0ustar rootroot/* $Id: industry.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 industry.h Base of all industries. */ #ifndef INDUSTRY_H #define INDUSTRY_H #include "newgrf_storage.h" #include "subsidy_type.h" #include "industry_map.h" #include "tilearea_type.h" typedef Pool IndustryPool; extern IndustryPool _industry_pool; /** * Production level maximum, minimum and default values. * It is not a value been really used in order to change, but rather an indicator * of how the industry is behaving. */ enum ProductionLevels { PRODLEVEL_CLOSURE = 0x00, ///< signal set to actually close the industry PRODLEVEL_MINIMUM = 0x04, ///< below this level, the industry is set to be closing PRODLEVEL_DEFAULT = 0x10, ///< default level set when the industry is created PRODLEVEL_MAXIMUM = 0x80, ///< the industry is running at full speed }; /** * Defines the internal data of a functional industry. */ struct Industry : IndustryPool::PoolItem<&_industry_pool> { TileArea location; ///< Location of the industry Town *town; ///< Nearest town CargoID produced_cargo[2]; ///< 2 production cargo slots uint16 produced_cargo_waiting[2]; ///< amount of cargo produced per cargo uint16 incoming_cargo_waiting[3]; ///< incoming cargo waiting to be processed byte production_rate[2]; ///< production rate for each cargo byte prod_level; ///< general production level CargoID accepts_cargo[3]; ///< 3 input cargo slots uint16 this_month_production[2]; ///< stats of this month's production per cargo uint16 this_month_transported[2]; ///< stats of this month's transport per cargo byte last_month_pct_transported[2]; ///< percentage transported per cargo in the last full month uint16 last_month_production[2]; ///< total units produced per cargo in the last full month uint16 last_month_transported[2]; ///< total units transported per cargo in the last full month uint16 counter; ///< used for animation and/or production (if available cargo) IndustryType type; ///< type of industry. OwnerByte owner; ///< owner of the industry. Which SHOULD always be (imho) OWNER_NONE byte random_colour; ///< randomized colour of the industry, for display purpose Year last_prod_year; ///< last year of production byte was_cargo_delivered; ///< flag that indicate this has been the closest industry chosen for cargo delivery by a station. see DeliverGoodsToIndustry PartOfSubsidyByte part_of_subsidy; ///< NOSAVE: is this industry a source/destination of a subsidy? OwnerByte founder; ///< Founder of the industry Date construction_date; ///< Date of the construction of the industry uint8 construction_type; ///< Way the industry was constructed (@see IndustryConstructionType) Date last_cargo_accepted_at; ///< Last day cargo was accepted by this industry byte selected_layout; ///< Which tile layout was used when creating the industry byte random_triggers; ///< Triggers for the random uint16 random; ///< Random value used for randomisation of all kinds of things PersistentStorage *psa; ///< Persistent storage for NewGRF industries. Industry(TileIndex tile = INVALID_TILE) : location(tile, 0, 0) {} ~Industry(); void RecomputeProductionMultipliers(); /** * Check if a given tile belongs to this industry. * @param tile The tile to check. * @return True if the tile is part of this industry. */ inline bool TileBelongsToIndustry(TileIndex tile) const { return IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->index; } /** * Get the industry of the given tile * @param tile the tile to get the industry from * @pre IsTileType(t, MP_INDUSTRY) * @return the industry */ static inline Industry *GetByTile(TileIndex tile) { return Industry::Get(GetIndustryIndex(tile)); } static Industry *GetRandom(); static void PostDestructor(size_t index); /** * Increment the count of industries for this type. * @param type IndustryType to increment * @pre type < NUM_INDUSTRYTYPES */ static inline void IncIndustryTypeCount(IndustryType type) { assert(type < NUM_INDUSTRYTYPES); counts[type]++; } /** * Decrement the count of industries for this type. * @param type IndustryType to decrement * @pre type < NUM_INDUSTRYTYPES */ static inline void DecIndustryTypeCount(IndustryType type) { assert(type < NUM_INDUSTRYTYPES); counts[type]--; } /** * Get the count of industries for this type. * @param type IndustryType to query * @pre type < NUM_INDUSTRYTYPES */ static inline uint16 GetIndustryTypeCount(IndustryType type) { assert(type < NUM_INDUSTRYTYPES); return counts[type]; } /** Resets industry counts. */ static inline void ResetIndustryCounts() { memset(&counts, 0, sizeof(counts)); } protected: static uint16 counts[NUM_INDUSTRYTYPES]; ///< Number of industries per type ingame }; void PlantRandomFarmField(const Industry *i); void ReleaseDisastersTargetingIndustry(IndustryID); bool IsTileForestIndustry(TileIndex tile); #define FOR_ALL_INDUSTRIES_FROM(var, start) FOR_ALL_ITEMS_FROM(Industry, industry_index, var, start) #define FOR_ALL_INDUSTRIES(var) FOR_ALL_INDUSTRIES_FROM(var, 0) /** Data for managing the number of industries of a single industry type. */ struct IndustryTypeBuildData { uint32 probability; ///< Relative probability of building this industry. byte min_number; ///< Smallest number of industries that should exist (either \c 0 or \c 1). uint16 target_count; ///< Desired number of industries of this type. uint16 max_wait; ///< Starting number of turns to wait (copied to #wait_count). uint16 wait_count; ///< Number of turns to wait before trying to build again. void Reset(); bool GetIndustryTypeData(IndustryType it); }; /** * Data for managing the number and type of industries in the game. */ struct IndustryBuildData { IndustryTypeBuildData builddata[NUM_INDUSTRYTYPES]; ///< Industry build data for every industry type. uint32 wanted_inds; ///< Number of wanted industries (bits 31-16), and a fraction (bits 15-0). void Reset(); void SetupTargetCount(); void TryBuildNewIndustry(); void MonthlyLoop(); }; extern IndustryBuildData _industry_builder; #endif /* INDUSTRY_H */ openttd-1.5.3/src/train_cmd.cpp0000644000000000000000000042124512627373441015147 0ustar rootroot/* $Id: train_cmd.cpp 27431 2015-11-01 11:59:17Z frosch $ */ /* * 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 train_cmd.cpp Handling of trains. */ #include "stdafx.h" #include "error.h" #include "articulated_vehicles.h" #include "command_func.h" #include "pathfinder/npf/npf_func.h" #include "pathfinder/yapf/yapf.hpp" #include "news_func.h" #include "company_func.h" #include "newgrf_sound.h" #include "newgrf_text.h" #include "strings_func.h" #include "viewport_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "ai/ai.hpp" #include "game/game.hpp" #include "newgrf_station.h" #include "effectvehicle_func.h" #include "network/network.h" #include "spritecache.h" #include "core/random_func.hpp" #include "company_base.h" #include "newgrf.h" #include "order_backup.h" #include "zoom_func.h" #include "newgrf_debug.h" #include "table/strings.h" #include "table/train_cmd.h" #include "safeguards.h" static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck); static bool TrainCheckIfLineEnds(Train *v, bool reverse = true); bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp. static TileIndex TrainApproachingCrossingTile(const Train *v); static void CheckIfTrainNeedsService(Train *v); static void CheckNextTrainTile(Train *v); static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8}; static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10}; template <> bool IsValidImageIndex(uint8 image_index) { return image_index < lengthof(_engine_sprite_base); } /** * Determine the side in which the train will leave the tile * * @param direction vehicle direction * @param track vehicle track bits * @return side of tile the train will leave */ static inline DiagDirection TrainExitDir(Direction direction, TrackBits track) { static const TrackBits state_dir_table[DIAGDIR_END] = { TRACK_BIT_RIGHT, TRACK_BIT_LOWER, TRACK_BIT_LEFT, TRACK_BIT_UPPER }; DiagDirection diagdir = DirToDiagDir(direction); /* Determine the diagonal direction in which we will exit this tile */ if (!HasBit(direction, 0) && track != state_dir_table[diagdir]) { diagdir = ChangeDiagDir(diagdir, DIAGDIRDIFF_90LEFT); } return diagdir; } /** * Return the cargo weight multiplier to use for a rail vehicle * @param cargo Cargo type to get multiplier for * @return Cargo weight multiplier */ byte FreightWagonMult(CargoID cargo) { if (!CargoSpec::Get(cargo)->is_freight) return 1; return _settings_game.vehicle.freight_trains; } /** Checks if lengths of all rail vehicles are valid. If not, shows an error message. */ void CheckTrainsLengths() { const Train *v; bool first = true; FOR_ALL_TRAINS(v) { if (v->First() == v && !(v->vehstatus & VS_CRASHED)) { for (const Train *u = v, *w = v->Next(); w != NULL; u = w, w = w->Next()) { if (u->track != TRACK_BIT_DEPOT) { if ((w->track != TRACK_BIT_DEPOT && max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->CalcNextVehicleOffset()) || (w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) { SetDParam(0, v->index); SetDParam(1, v->owner); ShowErrorMessage(STR_BROKEN_VEHICLE_LENGTH, INVALID_STRING_ID, WL_CRITICAL); if (!_networking && first) { first = false; DoCommandP(0, PM_PAUSED_ERROR, 1, CMD_PAUSE); } /* Break so we warn only once for each train. */ break; } } } } } } /** * Recalculates the cached stuff of a train. Should be called each time a vehicle is added * to/removed from the chain, and when the game is loaded. * Note: this needs to be called too for 'wagon chains' (in the depot, without an engine) * @param allowed_changes Stuff that is allowed to change. */ void Train::ConsistChanged(ConsistChangeFlags allowed_changes) { uint16 max_speed = UINT16_MAX; assert(this->IsFrontEngine() || this->IsFreeWagon()); const RailVehicleInfo *rvi_v = RailVehInfo(this->engine_type); EngineID first_engine = this->IsFrontEngine() ? this->engine_type : INVALID_ENGINE; this->gcache.cached_total_length = 0; this->compatible_railtypes = RAILTYPES_NONE; bool train_can_tilt = true; for (Train *u = this; u != NULL; u = u->Next()) { const RailVehicleInfo *rvi_u = RailVehInfo(u->engine_type); /* Check the this->first cache. */ assert(u->First() == this); /* update the 'first engine' */ u->gcache.first_engine = this == u ? INVALID_ENGINE : first_engine; u->railtype = rvi_u->railtype; if (u->IsEngine()) first_engine = u->engine_type; /* Set user defined data to its default value */ u->tcache.user_def_data = rvi_u->user_def_data; this->InvalidateNewGRFCache(); u->InvalidateNewGRFCache(); } for (Train *u = this; u != NULL; u = u->Next()) { /* Update user defined data (must be done before other properties) */ u->tcache.user_def_data = GetVehicleProperty(u, PROP_TRAIN_USER_DATA, u->tcache.user_def_data); this->InvalidateNewGRFCache(); u->InvalidateNewGRFCache(); } for (Train *u = this; u != NULL; u = u->Next()) { const Engine *e_u = u->GetEngine(); const RailVehicleInfo *rvi_u = &e_u->u.rail; if (!HasBit(e_u->info.misc_flags, EF_RAIL_TILTS)) train_can_tilt = false; /* Cache wagon override sprite group. NULL is returned if there is none */ u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->gcache.first_engine); /* Reset colour map */ u->colourmap = PAL_NONE; /* Update powered-wagon-status and visual effect */ u->UpdateVisualEffect(true); if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON && UsesWagonOverride(u) && !HasBit(u->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) { /* wagon is powered */ SetBit(u->flags, VRF_POWEREDWAGON); // cache 'powered' status } else { ClrBit(u->flags, VRF_POWEREDWAGON); } if (!u->IsArticulatedPart()) { /* Do not count powered wagons for the compatible railtypes, as wagons always have railtype normal */ if (rvi_u->power > 0) { this->compatible_railtypes |= GetRailTypeInfo(u->railtype)->powered_railtypes; } /* Some electric engines can be allowed to run on normal rail. It happens to all * existing electric engines when elrails are disabled and then re-enabled */ if (HasBit(u->flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) { u->railtype = RAILTYPE_RAIL; u->compatible_railtypes |= RAILTYPES_RAIL; } /* max speed is the minimum of the speed limits of all vehicles in the consist */ if ((rvi_u->railveh_type != RAILVEH_WAGON || _settings_game.vehicle.wagon_speed_limits) && !UsesWagonOverride(u)) { uint16 speed = GetVehicleProperty(u, PROP_TRAIN_SPEED, rvi_u->max_speed); if (speed != 0) max_speed = min(speed, max_speed); } } uint16 new_cap = e_u->DetermineCapacity(u); if (allowed_changes & CCF_CAPACITY) { /* Update vehicle capacity. */ if (u->cargo_cap > new_cap) u->cargo.Truncate(new_cap); u->refit_cap = min(new_cap, u->refit_cap); u->cargo_cap = new_cap; } else { /* Verify capacity hasn't changed. */ if (new_cap != u->cargo_cap) ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_CAPACITY, GBUG_VEH_CAPACITY, true); } u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_TRAIN_CARGO_AGE_PERIOD, e_u->info.cargo_age_period); /* check the vehicle length (callback) */ uint16 veh_len = CALLBACK_FAILED; if (e_u->GetGRF() != NULL && e_u->GetGRF()->grf_version >= 8) { /* Use callback 36 */ veh_len = GetVehicleProperty(u, PROP_TRAIN_SHORTEN_FACTOR, CALLBACK_FAILED); if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) { ErrorUnknownCallbackResult(e_u->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len); } } else if (HasBit(e_u->info.callback_mask, CBM_VEHICLE_LENGTH)) { /* Use callback 11 */ veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u); } if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor; veh_len = VEHICLE_LENGTH - Clamp(veh_len, 0, VEHICLE_LENGTH - 1); if (allowed_changes & CCF_LENGTH) { /* Update vehicle length. */ u->gcache.cached_veh_length = veh_len; } else { /* Verify length hasn't changed. */ if (veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u); } this->gcache.cached_total_length += u->gcache.cached_veh_length; this->InvalidateNewGRFCache(); u->InvalidateNewGRFCache(); } /* store consist weight/max speed in cache */ this->vcache.cached_max_speed = max_speed; this->tcache.cached_tilt = train_can_tilt; this->tcache.cached_max_curve_speed = this->GetCurveSpeedLimit(); /* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */ this->CargoChanged(); if (this->IsFrontEngine()) { this->UpdateAcceleration(); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); InvalidateWindowData(WC_VEHICLE_REFIT, this->index, VIWD_CONSIST_CHANGED); InvalidateWindowData(WC_VEHICLE_ORDERS, this->index, VIWD_CONSIST_CHANGED); InvalidateNewGRFInspectWindow(GSF_TRAINS, this->index); } } /** * Get the stop location of (the center) of the front vehicle of a train at * a platform of a station. * @param station_id the ID of the station where we're stopping * @param tile the tile where the vehicle currently is * @param v the vehicle to get the stop location of * @param station_ahead 'return' the amount of 1/16th tiles in front of the train * @param station_length 'return' the station length in 1/16th tiles * @return the location, calculated from the begin of the station to stop at. */ int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length) { const Station *st = Station::Get(station_id); *station_ahead = st->GetPlatformLength(tile, DirToDiagDir(v->direction)) * TILE_SIZE; *station_length = st->GetPlatformLength(tile) * TILE_SIZE; /* Default to the middle of the station for stations stops that are not in * the order list like intermediate stations when non-stop is disabled */ OrderStopLocation osl = OSL_PLATFORM_MIDDLE; if (v->gcache.cached_total_length >= *station_length) { /* The train is longer than the station, make it stop at the far end of the platform */ osl = OSL_PLATFORM_FAR_END; } else if (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == station_id) { osl = v->current_order.GetStopLocation(); } /* The stop location of the FRONT! of the train */ int stop; switch (osl) { default: NOT_REACHED(); case OSL_PLATFORM_NEAR_END: stop = v->gcache.cached_total_length; break; case OSL_PLATFORM_MIDDLE: stop = *station_length - (*station_length - v->gcache.cached_total_length) / 2; break; case OSL_PLATFORM_FAR_END: stop = *station_length; break; } /* Subtract half the front vehicle length of the train so we get the real * stop location of the train. */ return stop - (v->gcache.cached_veh_length + 1) / 2; } /** * Computes train speed limit caused by curves * @return imposed speed limit */ int Train::GetCurveSpeedLimit() const { assert(this->First() == this); static const int absolute_max_speed = UINT16_MAX; int max_speed = absolute_max_speed; if (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) return max_speed; int curvecount[2] = {0, 0}; /* first find the curve speed limit */ int numcurve = 0; int sum = 0; int pos = 0; int lastpos = -1; for (const Vehicle *u = this; u->Next() != NULL; u = u->Next(), pos++) { Direction this_dir = u->direction; Direction next_dir = u->Next()->direction; DirDiff dirdiff = DirDifference(this_dir, next_dir); if (dirdiff == DIRDIFF_SAME) continue; if (dirdiff == DIRDIFF_45LEFT) curvecount[0]++; if (dirdiff == DIRDIFF_45RIGHT) curvecount[1]++; if (dirdiff == DIRDIFF_45LEFT || dirdiff == DIRDIFF_45RIGHT) { if (lastpos != -1) { numcurve++; sum += pos - lastpos; if (pos - lastpos == 1 && max_speed > 88) { max_speed = 88; } } lastpos = pos; } /* if we have a 90 degree turn, fix the speed limit to 60 */ if (dirdiff == DIRDIFF_90LEFT || dirdiff == DIRDIFF_90RIGHT) { max_speed = 61; } } if (numcurve > 0 && max_speed > 88) { if (curvecount[0] == 1 && curvecount[1] == 1) { max_speed = absolute_max_speed; } else { sum /= numcurve; max_speed = 232 - (13 - Clamp(sum, 1, 12)) * (13 - Clamp(sum, 1, 12)); } } if (max_speed != absolute_max_speed) { /* Apply the engine's rail type curve speed advantage, if it slowed by curves */ const RailtypeInfo *rti = GetRailTypeInfo(this->railtype); max_speed += (max_speed / 2) * rti->curve_speed; if (this->tcache.cached_tilt) { /* Apply max_speed bonus of 20% for a tilting train */ max_speed += max_speed / 5; } } return max_speed; } /** * Calculates the maximum speed of the vehicle under its current conditions. * @return Maximum speed of the vehicle. */ int Train::GetCurrentMaxSpeed() const { int max_speed = _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ? this->gcache.cached_max_track_speed : this->tcache.cached_max_curve_speed; if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && IsRailStationTile(this->tile)) { StationID sid = GetStationIndex(this->tile); if (this->current_order.ShouldStopAtStation(this, sid)) { int station_ahead; int station_length; int stop_at = GetTrainStopLocation(sid, this->tile, this, &station_ahead, &station_length); /* The distance to go is whatever is still ahead of the train minus the * distance from the train's stop location to the end of the platform */ int distance_to_go = station_ahead / TILE_SIZE - (station_length - stop_at) / TILE_SIZE; if (distance_to_go > 0) { int st_max_speed = 120; int delta_v = this->cur_speed / (distance_to_go + 1); if (max_speed > (this->cur_speed - delta_v)) { st_max_speed = this->cur_speed - (delta_v / 10); } st_max_speed = max(st_max_speed, 25 * distance_to_go); max_speed = min(max_speed, st_max_speed); } } } for (const Train *u = this; u != NULL; u = u->Next()) { if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && u->track == TRACK_BIT_DEPOT) { max_speed = min(max_speed, 61); break; } /* Vehicle is on the middle part of a bridge. */ if (u->track == TRACK_BIT_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) { max_speed = min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed); } } max_speed = min(max_speed, this->current_order.GetMaxSpeed()); return min(max_speed, this->gcache.cached_max_track_speed); } /** Update acceleration of the train from the cached power and weight. */ void Train::UpdateAcceleration() { assert(this->IsFrontEngine() || this->IsFreeWagon()); uint power = this->gcache.cached_power; uint weight = this->gcache.cached_weight; assert(weight != 0); this->acceleration = Clamp(power / weight * 4, 1, 255); } /** * Get the width of a train vehicle image in the GUI. * @param offset Additional offset for positioning the sprite; set to NULL if not needed * @return Width in pixels */ int Train::GetDisplayImageWidth(Point *offset) const { int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH; int vehicle_pitch = 0; const Engine *e = this->GetEngine(); if (e->GetGRF() != NULL && is_custom_sprite(e->u.rail.image_index)) { reference_width = e->GetGRF()->traininfo_vehicle_width; vehicle_pitch = e->GetGRF()->traininfo_vehicle_pitch; } if (offset != NULL) { offset->x = ScaleGUITrad(reference_width) / 2; offset->y = ScaleGUITrad(vehicle_pitch); } return ScaleGUITrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH); } static SpriteID GetDefaultTrainSprite(uint8 spritenum, Direction direction) { assert(IsValidImageIndex(spritenum)); return ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum]; } /** * Get the sprite to display the train. * @param direction Direction of view/travel. * @param image_type Visualisation context. * @return Sprite to display. */ SpriteID Train::GetImage(Direction direction, EngineImageType image_type) const { uint8 spritenum = this->spritenum; SpriteID sprite; if (HasBit(this->flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction); if (is_custom_sprite(spritenum)) { sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type); if (sprite != 0) return sprite; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); sprite = GetDefaultTrainSprite(spritenum, direction); if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum]; return sprite; } static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type) { const Engine *e = Engine::Get(engine); Direction dir = rear_head ? DIR_E : DIR_W; uint8 spritenum = e->u.rail.image_index; if (is_custom_sprite(spritenum)) { SpriteID sprite = GetCustomVehicleIcon(engine, dir, image_type); if (sprite != 0) { if (e->GetGRF() != NULL) { y += ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch); } return sprite; } spritenum = Engine::Get(engine)->original_image_index; } if (rear_head) spritenum++; return GetDefaultTrainSprite(spritenum, DIR_W); } void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) { int yf = y; int yr = y; SpriteID spritef = GetRailIcon(engine, false, yf, image_type); SpriteID spriter = GetRailIcon(engine, true, yr, image_type); const Sprite *real_spritef = GetSprite(spritef, ST_NORMAL); const Sprite *real_spriter = GetSprite(spriter, ST_NORMAL); preferred_x = Clamp(preferred_x, left - UnScaleGUI(real_spritef->x_offs) + ScaleGUITrad(14), right - UnScaleGUI(real_spriter->width) - UnScaleGUI(real_spriter->x_offs) - ScaleGUITrad(15)); DrawSprite(spritef, pal, preferred_x - ScaleGUITrad(14), yf); DrawSprite(spriter, pal, preferred_x + ScaleGUITrad(15), yr); } else { SpriteID sprite = GetRailIcon(engine, false, y, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); preferred_x = Clamp(preferred_x, left - UnScaleGUI(real_sprite->x_offs), right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); DrawSprite(sprite, pal, preferred_x, y); } } /** * Get the size of the sprite of a train sprite heading west, or both heads (used for lists). * @param engine The engine to get the sprite from. * @param[out] width The width of the sprite. * @param[out] height The height of the sprite. * @param[out] xoffs Number of pixels to shift the sprite to the right. * @param[out] yoffs Number of pixels to shift the sprite downwards. * @param image_type Context the sprite is used in. */ void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) { int y = 0; SpriteID sprite = GetRailIcon(engine, false, y, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); width = UnScaleGUI(real_sprite->width); height = UnScaleGUI(real_sprite->height); xoffs = UnScaleGUI(real_sprite->x_offs); yoffs = UnScaleGUI(real_sprite->y_offs); if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) { sprite = GetRailIcon(engine, true, y, image_type); real_sprite = GetSprite(sprite, ST_NORMAL); /* Calculate values relative to an imaginary center between the two sprites. */ width = ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(real_sprite->width) + UnScaleGUI(real_sprite->x_offs) - xoffs; height = max(height, UnScaleGUI(real_sprite->height)); xoffs = xoffs - ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) / 2; yoffs = min(yoffs, UnScaleGUI(real_sprite->y_offs)); } } /** * Build a railroad wagon. * @param tile tile of the depot where rail-vehicle is built. * @param flags type of operation. * @param e the engine to build. * @param ret[out] the vehicle that has been built. * @return the cost of this operation or an error. */ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const Engine *e, Vehicle **ret) { const RailVehicleInfo *rvi = &e->u.rail; /* Check that the wagon can drive on the track in question */ if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; if (flags & DC_EXEC) { Train *v = new Train(); *ret = v; v->spritenum = rvi->image_index; v->engine_type = e->index; v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback DiagDirection dir = GetRailDepotDirection(tile); v->direction = DiagDirToDir(dir); v->tile = tile; int x = TileX(tile) * TILE_SIZE | _vehicle_initial_x_fract[dir]; int y = TileY(tile) * TILE_SIZE | _vehicle_initial_y_fract[dir]; v->x_pos = x; v->y_pos = y; v->z_pos = GetSlopePixelZ(x, y); v->owner = _current_company; v->track = TRACK_BIT_DEPOT; v->vehstatus = VS_HIDDEN | VS_DEFPAL; v->SetWagon(); v->SetFreeWagon(); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); v->cargo_type = e->GetDefaultCargoType(); v->cargo_cap = rvi->capacity; v->refit_cap = 0; v->railtype = rvi->railtype; v->build_year = _cur_year; v->cur_image = SPR_IMG_QUERY; v->random_bits = VehicleRandomBits(); v->group_id = DEFAULT_GROUP; AddArticulatedParts(v); _new_vehicle_id = v->index; v->UpdatePosition(); v->First()->ConsistChanged(CCF_ARRANGE); UpdateTrainGroupID(v->First()); CheckConsistencyOfArticulatedVehicle(v); /* Try to connect the vehicle to one of free chains of wagons. */ Train *w; FOR_ALL_TRAINS(w) { if (w->tile == tile && ///< Same depot w->IsFreeWagon() && ///< A free wagon chain w->engine_type == e->index && ///< Same type w->First() != v && ///< Don't connect to ourself !(w->vehstatus & VS_CRASHED)) { ///< Not crashed/flooded DoCommand(0, v->index | 1 << 20, w->Last()->index, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); break; } } } return CommandCost(); } /** Move all free vehicles in the depot to the train */ static void NormalizeTrainVehInDepot(const Train *u) { const Train *v; FOR_ALL_TRAINS(v) { if (v->IsFreeWagon() && v->tile == u->tile && v->track == TRACK_BIT_DEPOT) { if (DoCommand(0, v->index | 1 << 20, u->index, DC_EXEC, CMD_MOVE_RAIL_VEHICLE).Failed()) break; } } } static void AddRearEngineToMultiheadedTrain(Train *v) { Train *u = new Train(); v->value >>= 1; u->value = v->value; u->direction = v->direction; u->owner = v->owner; u->tile = v->tile; u->x_pos = v->x_pos; u->y_pos = v->y_pos; u->z_pos = v->z_pos; u->track = TRACK_BIT_DEPOT; u->vehstatus = v->vehstatus & ~VS_STOPPED; u->spritenum = v->spritenum + 1; u->cargo_type = v->cargo_type; u->cargo_subtype = v->cargo_subtype; u->cargo_cap = v->cargo_cap; u->refit_cap = v->refit_cap; u->railtype = v->railtype; u->engine_type = v->engine_type; u->build_year = v->build_year; u->cur_image = SPR_IMG_QUERY; u->random_bits = VehicleRandomBits(); v->SetMultiheaded(); u->SetMultiheaded(); v->SetNext(u); u->UpdatePosition(); /* Now we need to link the front and rear engines together */ v->other_multiheaded_part = u; u->other_multiheaded_part = v; } /** * Build a railroad vehicle. * @param tile tile of the depot where rail-vehicle is built. * @param flags type of operation. * @param e the engine to build. * @param data bit 0 prevents any free cars from being added to the train. * @param ret[out] the vehicle that has been built. * @return the cost of this operation or an error. */ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret) { const RailVehicleInfo *rvi = &e->u.rail; if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(tile, flags, e, ret); /* Check if depot and new engine uses the same kind of tracks * * We need to see if the engine got power on the tile to avoid electric engines in non-electric depots */ if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR; if (flags & DC_EXEC) { DiagDirection dir = GetRailDepotDirection(tile); int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir]; int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir]; Train *v = new Train(); *ret = v; v->direction = DiagDirToDir(dir); v->tile = tile; v->owner = _current_company; v->x_pos = x; v->y_pos = y; v->z_pos = GetSlopePixelZ(x, y); v->track = TRACK_BIT_DEPOT; v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; v->spritenum = rvi->image_index; v->cargo_type = e->GetDefaultCargoType(); v->cargo_cap = rvi->capacity; v->refit_cap = 0; v->last_station_visited = INVALID_STATION; v->last_loading_station = INVALID_STATION; v->engine_type = e->index; v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback v->reliability = e->reliability; v->reliability_spd_dec = e->reliability_spd_dec; v->max_age = e->GetLifeLengthInDays(); v->railtype = rvi->railtype; _new_vehicle_id = v->index; v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains); v->date_of_last_service = _date; v->build_year = _cur_year; v->cur_image = SPR_IMG_QUERY; v->random_bits = VehicleRandomBits(); if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); v->group_id = DEFAULT_GROUP; v->SetFrontEngine(); v->SetEngine(); v->UpdatePosition(); if (rvi->railveh_type == RAILVEH_MULTIHEAD) { AddRearEngineToMultiheadedTrain(v); } else { AddArticulatedParts(v); } v->ConsistChanged(CCF_ARRANGE); UpdateTrainGroupID(v); if (!HasBit(data, 0) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle NormalizeTrainVehInDepot(v); } CheckConsistencyOfArticulatedVehicle(v); } return CommandCost(); } static Train *FindGoodVehiclePos(const Train *src) { EngineID eng = src->engine_type; TileIndex tile = src->tile; Train *dst; FOR_ALL_TRAINS(dst) { if (dst->IsFreeWagon() && dst->tile == tile && !(dst->vehstatus & VS_CRASHED)) { /* check so all vehicles in the line have the same engine. */ Train *t = dst; while (t->engine_type == eng) { t = t->Next(); if (t == NULL) return dst; } } } return NULL; } /** Helper type for lists/vectors of trains */ typedef SmallVector TrainList; /** * Make a backup of a train into a train list. * @param list to make the backup in * @param t the train to make the backup of */ static void MakeTrainBackup(TrainList &list, Train *t) { for (; t != NULL; t = t->Next()) *list.Append() = t; } /** * Restore the train from the backup list. * @param list the train to restore. */ static void RestoreTrainBackup(TrainList &list) { /* No train, nothing to do. */ if (list.Length() == 0) return; Train *prev = NULL; /* Iterate over the list and rebuild it. */ for (Train **iter = list.Begin(); iter != list.End(); iter++) { Train *t = *iter; if (prev != NULL) { prev->SetNext(t); } else if (t->Previous() != NULL) { /* Make sure the head of the train is always the first in the chain. */ t->Previous()->SetNext(NULL); } prev = t; } } /** * Remove the given wagon from its consist. * @param part the part of the train to remove. * @param chain whether to remove the whole chain. */ static void RemoveFromConsist(Train *part, bool chain = false) { Train *tail = chain ? part->Last() : part->GetLastEnginePart(); /* Unlink at the front, but make it point to the next * vehicle after the to be remove part. */ if (part->Previous() != NULL) part->Previous()->SetNext(tail->Next()); /* Unlink at the back */ tail->SetNext(NULL); } /** * Inserts a chain into the train at dst. * @param dst the place where to append after. * @param chain the chain to actually add. */ static void InsertInConsist(Train *dst, Train *chain) { /* We do not want to add something in the middle of an articulated part. */ assert(dst->Next() == NULL || !dst->Next()->IsArticulatedPart()); chain->Last()->SetNext(dst->Next()); dst->SetNext(chain); } /** * Normalise the dual heads in the train, i.e. if one is * missing move that one to this train. * @param t the train to normalise. */ static void NormaliseDualHeads(Train *t) { for (; t != NULL; t = t->GetNextVehicle()) { if (!t->IsMultiheaded() || !t->IsEngine()) continue; /* Make sure that there are no free cars before next engine */ Train *u; for (u = t; u->Next() != NULL && !u->Next()->IsEngine(); u = u->Next()) {} if (u == t->other_multiheaded_part) continue; /* Remove the part from the 'wrong' train */ RemoveFromConsist(t->other_multiheaded_part); /* And add it to the 'right' train */ InsertInConsist(u, t->other_multiheaded_part); } } /** * Normalise the sub types of the parts in this chain. * @param chain the chain to normalise. */ static void NormaliseSubtypes(Train *chain) { /* Nothing to do */ if (chain == NULL) return; /* We must be the first in the chain. */ assert(chain->Previous() == NULL); /* Set the appropriate bits for the first in the chain. */ if (chain->IsWagon()) { chain->SetFreeWagon(); } else { assert(chain->IsEngine()); chain->SetFrontEngine(); } /* Now clear the bits for the rest of the chain */ for (Train *t = chain->Next(); t != NULL; t = t->Next()) { t->ClearFreeWagon(); t->ClearFrontEngine(); } } /** * Check/validate whether we may actually build a new train. * @note All vehicles are/were 'heads' of their chains. * @param original_dst The original destination chain. * @param dst The destination chain after constructing the train. * @param original_dst The original source chain. * @param dst The source chain after constructing the train. * @return possible error of this command. */ static CommandCost CheckNewTrain(Train *original_dst, Train *dst, Train *original_src, Train *src) { /* Just add 'new' engines and subtract the original ones. * If that's less than or equal to 0 we can be sure we did * not add any engines (read: trains) along the way. */ if ((src != NULL && src->IsEngine() ? 1 : 0) + (dst != NULL && dst->IsEngine() ? 1 : 0) - (original_src != NULL && original_src->IsEngine() ? 1 : 0) - (original_dst != NULL && original_dst->IsEngine() ? 1 : 0) <= 0) { return CommandCost(); } /* Get a free unit number and check whether it's within the bounds. * There will always be a maximum of one new train. */ if (GetFreeUnitNumber(VEH_TRAIN) <= _settings_game.vehicle.max_trains) return CommandCost(); return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); } /** * Check whether the train parts can be attached. * @param t the train to check * @return possible error of this command. */ static CommandCost CheckTrainAttachment(Train *t) { /* No multi-part train, no need to check. */ if (t == NULL || t->Next() == NULL || !t->IsEngine()) return CommandCost(); /* The maximum length for a train. For each part we decrease this by one * and if the result is negative the train is simply too long. */ int allowed_len = _settings_game.vehicle.max_train_length * TILE_SIZE - t->gcache.cached_veh_length; Train *head = t; Train *prev = t; /* Break the prev -> t link so it always holds within the loop. */ t = t->Next(); prev->SetNext(NULL); /* Make sure the cache is cleared. */ head->InvalidateNewGRFCache(); while (t != NULL) { allowed_len -= t->gcache.cached_veh_length; Train *next = t->Next(); /* Unlink the to-be-added piece; it is already unlinked from the previous * part due to the fact that the prev -> t link is broken. */ t->SetNext(NULL); /* Don't check callback for articulated or rear dual headed parts */ if (!t->IsArticulatedPart() && !t->IsRearDualheaded()) { /* Back up and clear the first_engine data to avoid using wagon override group */ EngineID first_engine = t->gcache.first_engine; t->gcache.first_engine = INVALID_ENGINE; /* We don't want the cache to interfere. head's cache is cleared before * the loop and after each callback does not need to be cleared here. */ t->InvalidateNewGRFCache(); uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, head->engine_type, t, head); /* Restore original first_engine data */ t->gcache.first_engine = first_engine; /* We do not want to remember any cached variables from the test run */ t->InvalidateNewGRFCache(); head->InvalidateNewGRFCache(); if (callback != CALLBACK_FAILED) { /* A failing callback means everything is okay */ StringID error = STR_NULL; if (head->GetGRF()->grf_version < 8) { if (callback == 0xFD) error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES; if (callback < 0xFD) error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback); if (callback >= 0x100) ErrorUnknownCallbackResult(head->GetGRFID(), CBID_TRAIN_ALLOW_WAGON_ATTACH, callback); } else { if (callback < 0x400) { error = GetGRFStringID(head->GetGRFID(), 0xD000 + callback); } else { switch (callback) { case 0x400: // allow if railtypes match (always the case for OpenTTD) case 0x401: // allow break; default: // unknown reason -> disallow case 0x402: // disallow attaching error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES; break; } } } if (error != STR_NULL) return_cmd_error(error); } } /* And link it to the new part. */ prev->SetNext(t); prev = t; t = next; } if (allowed_len < 0) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG); return CommandCost(); } /** * Validate whether we are going to create valid trains. * @note All vehicles are/were 'heads' of their chains. * @param original_dst The original destination chain. * @param dst The destination chain after constructing the train. * @param original_dst The original source chain. * @param dst The source chain after constructing the train. * @param check_limit Whether to check the vehicle limit. * @return possible error of this command. */ static CommandCost ValidateTrains(Train *original_dst, Train *dst, Train *original_src, Train *src, bool check_limit) { /* Check whether we may actually construct the trains. */ CommandCost ret = CheckTrainAttachment(src); if (ret.Failed()) return ret; ret = CheckTrainAttachment(dst); if (ret.Failed()) return ret; /* Check whether we need to build a new train. */ return check_limit ? CheckNewTrain(original_dst, dst, original_src, src) : CommandCost(); } /** * Arrange the trains in the wanted way. * @param dst_head The destination chain of the to be moved vehicle. * @param dst The destination for the to be moved vehicle. * @param src_head The source chain of the to be moved vehicle. * @param src The to be moved vehicle. * @param move_chain Whether to move all vehicles after src or not. */ static void ArrangeTrains(Train **dst_head, Train *dst, Train **src_head, Train *src, bool move_chain) { /* First determine the front of the two resulting trains */ if (*src_head == *dst_head) { /* If we aren't moving part(s) to a new train, we are just moving the * front back and there is not destination head. */ *dst_head = NULL; } else if (*dst_head == NULL) { /* If we are moving to a new train the head of the move train would become * the head of the new vehicle. */ *dst_head = src; } if (src == *src_head) { /* If we are moving the front of a train then we are, in effect, creating * a new head for the train. Point to that. Unless we are moving the whole * train in which case there is not 'source' train anymore. * In case we are a multiheaded part we want the complete thing to come * with us, so src->GetNextUnit(), however... when we are e.g. a wagon * that is followed by a rear multihead we do not want to include that. */ *src_head = move_chain ? NULL : (src->IsMultiheaded() ? src->GetNextUnit() : src->GetNextVehicle()); } /* Now it's just simply removing the part that we are going to move from the * source train and *if* the destination is a not a new train add the chain * at the destination location. */ RemoveFromConsist(src, move_chain); if (*dst_head != src) InsertInConsist(dst, src); /* Now normalise the dual heads, that is move the dual heads around in such * a way that the head and rear of a dual head are in the same train */ NormaliseDualHeads(*src_head); NormaliseDualHeads(*dst_head); } /** * Normalise the head of the train again, i.e. that is tell the world that * we have changed and update all kinds of variables. * @param head the train to update. */ static void NormaliseTrainHead(Train *head) { /* Not much to do! */ if (head == NULL) return; /* Tell the 'world' the train changed. */ head->ConsistChanged(CCF_ARRANGE); UpdateTrainGroupID(head); /* Not a front engine, i.e. a free wagon chain. No need to do more. */ if (!head->IsFrontEngine()) return; /* Update the refit button and window */ InvalidateWindowData(WC_VEHICLE_REFIT, head->index, VIWD_CONSIST_CHANGED); SetWindowWidgetDirty(WC_VEHICLE_VIEW, head->index, WID_VV_REFIT); /* If we don't have a unit number yet, set one. */ if (head->unitnumber != 0) return; head->unitnumber = GetFreeUnitNumber(VEH_TRAIN); } /** * Move a rail vehicle around inside the depot. * @param tile unused * @param flags type of operation * Note: DC_AUTOREPLACE is set when autoreplace tries to undo its modifications or moves vehicles to temporary locations inside the depot. * @param p1 various bitstuffed elements * - p1 (bit 0 - 19) source vehicle index * - p1 (bit 20) move all vehicles following the source vehicle * @param p2 what wagon to put the source wagon AFTER, XXX - INVALID_VEHICLE to make a new line * @param text unused * @return the cost of this operation or an error */ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID s = GB(p1, 0, 20); VehicleID d = GB(p2, 0, 20); bool move_chain = HasBit(p1, 20); Train *src = Train::GetIfValid(s); if (src == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(src->owner); if (ret.Failed()) return ret; /* Do not allow moving crashed vehicles inside the depot, it is likely to cause asserts later */ if (src->vehstatus & VS_CRASHED) return CMD_ERROR; /* if nothing is selected as destination, try and find a matching vehicle to drag to. */ Train *dst; if (d == INVALID_VEHICLE) { dst = src->IsEngine() ? NULL : FindGoodVehiclePos(src); } else { dst = Train::GetIfValid(d); if (dst == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(dst->owner); if (ret.Failed()) return ret; /* Do not allow appending to crashed vehicles, too */ if (dst->vehstatus & VS_CRASHED) return CMD_ERROR; } /* if an articulated part is being handled, deal with its parent vehicle */ src = src->GetFirstEnginePart(); if (dst != NULL) { dst = dst->GetFirstEnginePart(); } /* don't move the same vehicle.. */ if (src == dst) return CommandCost(); /* locate the head of the two chains */ Train *src_head = src->First(); Train *dst_head; if (dst != NULL) { dst_head = dst->First(); if (dst_head->tile != src_head->tile) return CMD_ERROR; /* Now deal with articulated part of destination wagon */ dst = dst->GetLastEnginePart(); } else { dst_head = NULL; } if (src->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT); /* When moving all wagons, we can't have the same src_head and dst_head */ if (move_chain && src_head == dst_head) return CommandCost(); /* When moving a multiheaded part to be place after itself, bail out. */ if (!move_chain && dst != NULL && dst->IsRearDualheaded() && src == dst->other_multiheaded_part) return CommandCost(); /* Check if all vehicles in the source train are stopped inside a depot. */ if (!src_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); /* Check if all vehicles in the destination train are stopped inside a depot. */ if (dst_head != NULL && !dst_head->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); /* First make a backup of the order of the trains. That way we can do * whatever we want with the order and later on easily revert. */ TrainList original_src; TrainList original_dst; MakeTrainBackup(original_src, src_head); MakeTrainBackup(original_dst, dst_head); /* Also make backup of the original heads as ArrangeTrains can change them. * For the destination head we do not care if it is the same as the source * head because in that case it's just a copy. */ Train *original_src_head = src_head; Train *original_dst_head = (dst_head == src_head ? NULL : dst_head); /* We want this information from before the rearrangement, but execute this after the validation. * original_src_head can't be NULL; src is by definition != NULL, so src_head can't be NULL as * src->GetFirst() always yields non-NULL, so eventually original_src_head != NULL as well. */ bool original_src_head_front_engine = original_src_head->IsFrontEngine(); bool original_dst_head_front_engine = original_dst_head != NULL && original_dst_head->IsFrontEngine(); /* (Re)arrange the trains in the wanted arrangement. */ ArrangeTrains(&dst_head, dst, &src_head, src, move_chain); if ((flags & DC_AUTOREPLACE) == 0) { /* If the autoreplace flag is set we do not need to test for the validity * because we are going to revert the train to its original state. As we * assume the original state was correct autoreplace can skip this. */ CommandCost ret = ValidateTrains(original_dst_head, dst_head, original_src_head, src_head, true); if (ret.Failed()) { /* Restore the train we had. */ RestoreTrainBackup(original_src); RestoreTrainBackup(original_dst); return ret; } } /* do it? */ if (flags & DC_EXEC) { /* Remove old heads from the statistics */ if (original_src_head_front_engine) GroupStatistics::CountVehicle(original_src_head, -1); if (original_dst_head_front_engine) GroupStatistics::CountVehicle(original_dst_head, -1); /* First normalise the sub types of the chains. */ NormaliseSubtypes(src_head); NormaliseSubtypes(dst_head); /* There are 14 different cases: * 1) front engine gets moved to a new train, it stays a front engine. * a) the 'next' part is a wagon that becomes a free wagon chain. * b) the 'next' part is an engine that becomes a front engine. * c) there is no 'next' part, nothing else happens * 2) front engine gets moved to another train, it is not a front engine anymore * a) the 'next' part is a wagon that becomes a free wagon chain. * b) the 'next' part is an engine that becomes a front engine. * c) there is no 'next' part, nothing else happens * 3) front engine gets moved to later in the current train, it is not a front engine anymore. * a) the 'next' part is a wagon that becomes a free wagon chain. * b) the 'next' part is an engine that becomes a front engine. * 4) free wagon gets moved * a) the 'next' part is a wagon that becomes a free wagon chain. * b) the 'next' part is an engine that becomes a front engine. * c) there is no 'next' part, nothing else happens * 5) non front engine gets moved and becomes a new train, nothing else happens * 6) non front engine gets moved within a train / to another train, nothing hapens * 7) wagon gets moved, nothing happens */ if (src == original_src_head && src->IsEngine() && !src->IsFrontEngine()) { /* Cases #2 and #3: the front engine gets trashed. */ DeleteWindowById(WC_VEHICLE_VIEW, src->index); DeleteWindowById(WC_VEHICLE_ORDERS, src->index); DeleteWindowById(WC_VEHICLE_REFIT, src->index); DeleteWindowById(WC_VEHICLE_DETAILS, src->index); DeleteWindowById(WC_VEHICLE_TIMETABLE, src->index); DeleteNewGRFInspectWindow(GSF_TRAINS, src->index); SetWindowDirty(WC_COMPANY, _current_company); /* Delete orders, group stuff and the unit number as we're not the * front of any vehicle anymore. */ DeleteVehicleOrders(src); RemoveVehicleFromGroup(src); src->unitnumber = 0; } /* We weren't a front engine but are becoming one. So * we should be put in the default group. */ if (original_src_head != src && dst_head == src) { SetTrainGroupID(src, DEFAULT_GROUP); SetWindowDirty(WC_COMPANY, _current_company); } /* Add new heads to statistics */ if (src_head != NULL && src_head->IsFrontEngine()) GroupStatistics::CountVehicle(src_head, 1); if (dst_head != NULL && dst_head->IsFrontEngine()) GroupStatistics::CountVehicle(dst_head, 1); /* Handle 'new engine' part of cases #1b, #2b, #3b, #4b and #5 in NormaliseTrainHead. */ NormaliseTrainHead(src_head); NormaliseTrainHead(dst_head); if ((flags & DC_NO_CARGO_CAP_CHECK) == 0) { CheckCargoCapacity(src_head); CheckCargoCapacity(dst_head); } if (src_head != NULL) src_head->First()->MarkDirty(); if (dst_head != NULL) dst_head->First()->MarkDirty(); /* We are undoubtedly changing something in the depot and train list. */ InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile); InvalidateWindowClassesData(WC_TRAINS_LIST, 0); } else { /* We don't want to execute what we're just tried. */ RestoreTrainBackup(original_src); RestoreTrainBackup(original_dst); } return CommandCost(); } /** * Sell a (single) train wagon/engine. * @param flags type of operation * @param t the train wagon to sell * @param data the selling mode * - data = 0: only sell the single dragged wagon/engine (and any belonging rear-engines) * - data = 1: sell the vehicle and all vehicles following it in the chain * if the wagon is dragged, don't delete the possibly belonging rear-engine to some front * @param user the user for the order backup. * @return the cost of this operation or an error */ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user) { /* Sell a chain of vehicles or not? */ bool sell_chain = HasBit(data, 0); Train *v = Train::From(t)->GetFirstEnginePart(); Train *first = v->First(); if (v->IsRearDualheaded()) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT); /* First make a backup of the order of the train. That way we can do * whatever we want with the order and later on easily revert. */ TrainList original; MakeTrainBackup(original, first); /* We need to keep track of the new head and the head of what we're going to sell. */ Train *new_head = first; Train *sell_head = NULL; /* Split the train in the wanted way. */ ArrangeTrains(&sell_head, NULL, &new_head, v, sell_chain); /* We don't need to validate the second train; it's going to be sold. */ CommandCost ret = ValidateTrains(NULL, NULL, first, new_head, (flags & DC_AUTOREPLACE) == 0); if (ret.Failed()) { /* Restore the train we had. */ RestoreTrainBackup(original); return ret; } if (first->orders.list == NULL && !OrderList::CanAllocateItem()) { /* Restore the train we had. */ RestoreTrainBackup(original); return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); } CommandCost cost(EXPENSES_NEW_VEHICLES); for (Train *t = sell_head; t != NULL; t = t->Next()) cost.AddCost(-t->value); /* do it? */ if (flags & DC_EXEC) { /* First normalise the sub types of the chain. */ NormaliseSubtypes(new_head); if (v == first && v->IsEngine() && !sell_chain && new_head != NULL && new_head->IsFrontEngine()) { /* We are selling the front engine. In this case we want to * 'give' the order, unit number and such to the new head. */ new_head->orders.list = first->orders.list; new_head->AddToShared(first); DeleteVehicleOrders(first); /* Copy other important data from the front engine */ new_head->CopyVehicleConfigAndStatistics(first); GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit } else if (v->IsPrimaryVehicle() && data & (MAKE_ORDER_BACKUP_FLAG >> 20)) { OrderBackup::Backup(v, user); } /* We need to update the information about the train. */ NormaliseTrainHead(new_head); /* We are undoubtedly changing something in the depot and train list. */ InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); InvalidateWindowClassesData(WC_TRAINS_LIST, 0); /* Actually delete the sold 'goods' */ delete sell_head; } else { /* We don't want to execute what we're just tried. */ RestoreTrainBackup(original); } return cost; } void Train::UpdateDeltaXY(Direction direction) { /* Set common defaults. */ this->x_offs = -1; this->y_offs = -1; this->x_extent = 3; this->y_extent = 3; this->z_extent = 6; this->x_bb_offs = 0; this->y_bb_offs = 0; if (!IsDiagonalDirection(direction)) { static const int _sign_table[] = { /* x, y */ -1, -1, // DIR_N -1, 1, // DIR_E 1, 1, // DIR_S 1, -1, // DIR_W }; int half_shorten = (VEHICLE_LENGTH - this->gcache.cached_veh_length) / 2; /* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */ this->x_offs -= half_shorten * _sign_table[direction]; this->y_offs -= half_shorten * _sign_table[direction + 1]; this->x_extent += this->x_bb_offs = half_shorten * _sign_table[direction]; this->y_extent += this->y_bb_offs = half_shorten * _sign_table[direction + 1]; } else { switch (direction) { /* Shorten southern corner of the bounding box according the vehicle length * and center the bounding box on the vehicle. */ case DIR_NE: this->x_offs = 1 - (this->gcache.cached_veh_length + 1) / 2; this->x_extent = this->gcache.cached_veh_length - 1; this->x_bb_offs = -1; break; case DIR_NW: this->y_offs = 1 - (this->gcache.cached_veh_length + 1) / 2; this->y_extent = this->gcache.cached_veh_length - 1; this->y_bb_offs = -1; break; /* Move northern corner of the bounding box down according to vehicle length * and center the bounding box on the vehicle. */ case DIR_SW: this->x_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH; this->x_extent = VEHICLE_LENGTH - 1; this->x_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1; break; case DIR_SE: this->y_offs = 1 + (this->gcache.cached_veh_length + 1) / 2 - VEHICLE_LENGTH; this->y_extent = VEHICLE_LENGTH - 1; this->y_bb_offs = VEHICLE_LENGTH - this->gcache.cached_veh_length - 1; break; default: NOT_REACHED(); } } } /** * Mark a train as stuck and stop it if it isn't stopped right now. * @param v %Train to mark as being stuck. */ static void MarkTrainAsStuck(Train *v) { if (!HasBit(v->flags, VRF_TRAIN_STUCK)) { /* It is the first time the problem occurred, set the "train stuck" flag. */ SetBit(v->flags, VRF_TRAIN_STUCK); v->wait_counter = 0; /* Stop train */ v->cur_speed = 0; v->subspeed = 0; v->SetLastSpeed(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } } /** * Swap the two up/down flags in two ways: * - Swap values of \a swap_flag1 and \a swap_flag2, and * - If going up previously (#GVF_GOINGUP_BIT set), the #GVF_GOINGDOWN_BIT is set, and vice versa. * @param swap_flag1 [inout] First train flag. * @param swap_flag2 [inout] Second train flag. */ static void SwapTrainFlags(uint16 *swap_flag1, uint16 *swap_flag2) { uint16 flag1 = *swap_flag1; uint16 flag2 = *swap_flag2; /* Clear the flags */ ClrBit(*swap_flag1, GVF_GOINGUP_BIT); ClrBit(*swap_flag1, GVF_GOINGDOWN_BIT); ClrBit(*swap_flag2, GVF_GOINGUP_BIT); ClrBit(*swap_flag2, GVF_GOINGDOWN_BIT); /* Reverse the rail-flags (if needed) */ if (HasBit(flag1, GVF_GOINGUP_BIT)) { SetBit(*swap_flag2, GVF_GOINGDOWN_BIT); } else if (HasBit(flag1, GVF_GOINGDOWN_BIT)) { SetBit(*swap_flag2, GVF_GOINGUP_BIT); } if (HasBit(flag2, GVF_GOINGUP_BIT)) { SetBit(*swap_flag1, GVF_GOINGDOWN_BIT); } else if (HasBit(flag2, GVF_GOINGDOWN_BIT)) { SetBit(*swap_flag1, GVF_GOINGUP_BIT); } } /** * Updates some variables after swapping the vehicle. * @param v swapped vehicle */ static void UpdateStatusAfterSwap(Train *v) { /* Reverse the direction. */ if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction); /* Call the proper EnterTile function unless we are in a wormhole. */ if (v->track != TRACK_BIT_WORMHOLE) { VehicleEnterTile(v, v->tile, v->x_pos, v->y_pos); } else { /* VehicleEnter_TunnelBridge() sets TRACK_BIT_WORMHOLE when the vehicle * is on the last bit of the bridge head (frame == TILE_SIZE - 1). * If we were swapped with such a vehicle, we have set TRACK_BIT_WORMHOLE, * when we shouldn't have. Check if this is the case. */ TileIndex vt = TileVirtXY(v->x_pos, v->y_pos); if (IsTileType(vt, MP_TUNNELBRIDGE)) { VehicleEnterTile(v, vt, v->x_pos, v->y_pos); if (v->track != TRACK_BIT_WORMHOLE && IsBridgeTile(v->tile)) { /* We have just left the wormhole, possibly set the * "goingdown" bit. UpdateInclination() can be used * because we are at the border of the tile. */ v->UpdatePosition(); v->UpdateInclination(true, true); return; } } } v->UpdatePosition(); v->UpdateViewport(true, true); } /** * Swap vehicles \a l and \a r in consist \a v, and reverse their direction. * @param v Consist to change. * @param l %Vehicle index in the consist of the first vehicle. * @param r %Vehicle index in the consist of the second vehicle. */ void ReverseTrainSwapVeh(Train *v, int l, int r) { Train *a, *b; /* locate vehicles to swap */ for (a = v; l != 0; l--) a = a->Next(); for (b = v; r != 0; r--) b = b->Next(); if (a != b) { /* swap the hidden bits */ { uint16 tmp = (a->vehstatus & ~VS_HIDDEN) | (b->vehstatus & VS_HIDDEN); b->vehstatus = (b->vehstatus & ~VS_HIDDEN) | (a->vehstatus & VS_HIDDEN); a->vehstatus = tmp; } Swap(a->track, b->track); Swap(a->direction, b->direction); Swap(a->x_pos, b->x_pos); Swap(a->y_pos, b->y_pos); Swap(a->tile, b->tile); Swap(a->z_pos, b->z_pos); SwapTrainFlags(&a->gv_flags, &b->gv_flags); UpdateStatusAfterSwap(a); UpdateStatusAfterSwap(b); } else { /* Swap GVF_GOINGUP_BIT/GVF_GOINGDOWN_BIT. * This is a little bit redundant way, a->gv_flags will * be (re)set twice, but it reduces code duplication */ SwapTrainFlags(&a->gv_flags, &a->gv_flags); UpdateStatusAfterSwap(a); } } /** * Check if the vehicle is a train * @param v vehicle on tile * @return v if it is a train, NULL otherwise */ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) { return (v->type == VEH_TRAIN) ? v : NULL; } /** * Checks if a train is approaching a rail-road crossing * @param v vehicle on tile * @param data tile with crossing we are testing * @return v if it is approaching a crossing, NULL otherwise */ static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data) { if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL; Train *t = Train::From(v); if (!t->IsFrontEngine()) return NULL; TileIndex tile = *(TileIndex *)data; if (TrainApproachingCrossingTile(t) != tile) return NULL; return t; } /** * Finds a vehicle approaching rail-road crossing * @param tile tile to test * @return true if a vehicle is approaching the crossing * @pre tile is a rail-road crossing */ static bool TrainApproachingCrossing(TileIndex tile) { assert(IsLevelCrossingTile(tile)); DiagDirection dir = AxisToDiagDir(GetCrossingRailAxis(tile)); TileIndex tile_from = tile + TileOffsByDiagDir(dir); if (HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum)) return true; dir = ReverseDiagDir(dir); tile_from = tile + TileOffsByDiagDir(dir); return HasVehicleOnPos(tile_from, &tile, &TrainApproachingCrossingEnum); } /** * Sets correct crossing state * @param tile tile to update * @param sound should we play sound? * @pre tile is a rail-road crossing */ void UpdateLevelCrossing(TileIndex tile, bool sound) { assert(IsLevelCrossingTile(tile)); /* train on crossing || train approaching crossing || reserved */ bool new_state = HasVehicleOnPos(tile, NULL, &TrainOnTileEnum) || TrainApproachingCrossing(tile) || HasCrossingReservation(tile); if (new_state != IsCrossingBarred(tile)) { if (new_state && sound) { if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile); } SetCrossingBarred(tile, new_state); MarkTileDirtyByTile(tile); } } /** * Bars crossing and plays ding-ding sound if not barred already * @param tile tile with crossing * @pre tile is a rail-road crossing */ static inline void MaybeBarCrossingWithSound(TileIndex tile) { if (!IsCrossingBarred(tile)) { BarCrossing(tile); if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile); MarkTileDirtyByTile(tile); } } /** * Advances wagons for train reversing, needed for variable length wagons. * This one is called before the train is reversed. * @param v First vehicle in chain */ static void AdvanceWagonsBeforeSwap(Train *v) { Train *base = v; Train *first = base; // first vehicle to move Train *last = v->Last(); // last vehicle to move uint length = CountVehiclesInChain(v); while (length > 2) { last = last->Previous(); first = first->Next(); int differential = base->CalcNextVehicleOffset() - last->CalcNextVehicleOffset(); /* do not update images now * negative differential will be handled in AdvanceWagonsAfterSwap() */ for (int i = 0; i < differential; i++) TrainController(first, last->Next()); base = first; // == base->Next() length -= 2; } } /** * Advances wagons for train reversing, needed for variable length wagons. * This one is called after the train is reversed. * @param v First vehicle in chain */ static void AdvanceWagonsAfterSwap(Train *v) { /* first of all, fix the situation when the train was entering a depot */ Train *dep = v; // last vehicle in front of just left depot while (dep->Next() != NULL && (dep->track == TRACK_BIT_DEPOT || dep->Next()->track != TRACK_BIT_DEPOT)) { dep = dep->Next(); // find first vehicle outside of a depot, with next vehicle inside a depot } Train *leave = dep->Next(); // first vehicle in a depot we are leaving now if (leave != NULL) { /* 'pull' next wagon out of the depot, so we won't miss it (it could stay in depot forever) */ int d = TicksToLeaveDepot(dep); if (d <= 0) { leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot leave->track = TrackToTrackBits(GetRailDepotTrack(leave->tile)); for (int i = 0; i >= d; i--) TrainController(leave, NULL); // maybe move it, and maybe let another wagon leave } } else { dep = NULL; // no vehicle in a depot, so no vehicle leaving a depot } Train *base = v; Train *first = base; // first vehicle to move Train *last = v->Last(); // last vehicle to move uint length = CountVehiclesInChain(v); /* We have to make sure all wagons that leave a depot because of train reversing are moved correctly * they have already correct spacing, so we have to make sure they are moved how they should */ bool nomove = (dep == NULL); // If there is no vehicle leaving a depot, limit the number of wagons moved immediately. while (length > 2) { /* we reached vehicle (originally) in front of a depot, stop now * (we would move wagons that are already moved with new wagon length). */ if (base == dep) break; /* the last wagon was that one leaving a depot, so do not move it anymore */ if (last == dep) nomove = true; last = last->Previous(); first = first->Next(); int differential = last->CalcNextVehicleOffset() - base->CalcNextVehicleOffset(); /* do not update images now */ for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL)); base = first; // == base->Next() length -= 2; } } /** * Turn a train around. * @param v %Train to turn around. */ void ReverseTrainDirection(Train *v) { if (IsRailDepotTile(v->tile)) { InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); } /* Clear path reservation in front if train is not stuck. */ if (!HasBit(v->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(v); /* Check if we were approaching a rail/road-crossing */ TileIndex crossing = TrainApproachingCrossingTile(v); /* count number of vehicles */ int r = CountVehiclesInChain(v) - 1; // number of vehicles - 1 AdvanceWagonsBeforeSwap(v); /* swap start<>end, start+1<>end-1, ... */ int l = 0; do { ReverseTrainSwapVeh(v, l++, r--); } while (l <= r); AdvanceWagonsAfterSwap(v); if (IsRailDepotTile(v->tile)) { InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); } ToggleBit(v->flags, VRF_TOGGLE_REVERSE); ClrBit(v->flags, VRF_REVERSING); /* recalculate cached data */ v->ConsistChanged(CCF_TRACK); /* update all images */ for (Train *u = v; u != NULL; u = u->Next()) u->UpdateViewport(false, false); /* update crossing we were approaching */ if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); /* maybe we are approaching crossing now, after reversal */ crossing = TrainApproachingCrossingTile(v); if (crossing != INVALID_TILE) MaybeBarCrossingWithSound(crossing); /* If we are inside a depot after reversing, don't bother with path reserving. */ if (v->track == TRACK_BIT_DEPOT) { /* Can't be stuck here as inside a depot is always a safe tile. */ if (HasBit(v->flags, VRF_TRAIN_STUCK)) SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); ClrBit(v->flags, VRF_TRAIN_STUCK); return; } /* TrainExitDir does not always produce the desired dir for depots and * tunnels/bridges that is needed for UpdateSignalsOnSegment. */ DiagDirection dir = TrainExitDir(v->direction, v->track); if (IsRailDepotTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE)) dir = INVALID_DIAGDIR; if (UpdateSignalsOnSegment(v->tile, dir, v->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) { /* If we are currently on a tile with conventional signals, we can't treat the * current tile as a safe tile or we would enter a PBS block without a reservation. */ bool first_tile_okay = !(IsTileType(v->tile, MP_RAILWAY) && HasSignalOnTrackdir(v->tile, v->GetVehicleTrackdir()) && !IsPbsSignal(GetSignalType(v->tile, FindFirstTrack(v->track)))); /* If we are on a depot tile facing outwards, do not treat the current tile as safe. */ if (IsRailDepotTile(v->tile) && TrackdirToExitdir(v->GetVehicleTrackdir()) == GetRailDepotDirection(v->tile)) first_tile_okay = false; if (IsRailStationTile(v->tile)) SetRailStationPlatformReservation(v->tile, TrackdirToExitdir(v->GetVehicleTrackdir()), true); if (TryPathReserve(v, false, first_tile_okay)) { /* Do a look-ahead now in case our current tile was already a safe tile. */ CheckNextTrainTile(v); } else if (v->current_order.GetType() != OT_LOADING) { /* Do not wait for a way out when we're still loading */ MarkTrainAsStuck(v); } } else if (HasBit(v->flags, VRF_TRAIN_STUCK)) { /* A train not inside a PBS block can't be stuck. */ ClrBit(v->flags, VRF_TRAIN_STUCK); v->wait_counter = 0; } } /** * Reverse train. * @param tile unused * @param flags type of operation * @param p1 train to reverse * @param p2 if true, reverse a unit in a train (needs to be in a depot) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Train *v = Train::GetIfValid(p1); if (v == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (p2 != 0) { /* turn a single unit around */ if (v->IsMultiheaded() || HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) { return_cmd_error(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS); } if (!HasBit(EngInfo(v->engine_type)->misc_flags, EF_RAIL_FLIPS)) return CMD_ERROR; Train *front = v->First(); /* make sure the vehicle is stopped in the depot */ if (!front->IsStoppedInDepot()) { return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT); } if (flags & DC_EXEC) { ToggleBit(v->flags, VRF_REVERSE_DIRECTION); front->ConsistChanged(CCF_ARRANGE); SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); SetWindowDirty(WC_VEHICLE_DETAILS, front->index); SetWindowDirty(WC_VEHICLE_VIEW, front->index); SetWindowClassesDirty(WC_TRAINS_LIST); } } else { /* turn the whole train around */ if ((v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0) return CMD_ERROR; if (flags & DC_EXEC) { /* Properly leave the station if we are loading and won't be loading anymore */ if (v->current_order.IsType(OT_LOADING)) { const Vehicle *last = v; while (last->Next() != NULL) last = last->Next(); /* not a station || different station --> leave the station */ if (!IsTileType(last->tile, MP_STATION) || GetStationIndex(last->tile) != GetStationIndex(v->tile)) { v->LeaveStation(); } } /* We cancel any 'skip signal at dangers' here */ v->force_proceed = TFP_NONE; SetWindowDirty(WC_VEHICLE_VIEW, v->index); if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && v->cur_speed != 0) { ToggleBit(v->flags, VRF_REVERSING); } else { v->cur_speed = 0; v->SetLastSpeed(); HideFillingPercent(&v->fill_percent_te_id); ReverseTrainDirection(v); } } } return CommandCost(); } /** * Force a train through a red signal * @param tile unused * @param flags type of operation * @param p1 train to ignore the red signal * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Train *t = Train::GetIfValid(p1); if (t == NULL) return CMD_ERROR; if (!t->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(t->owner); if (ret.Failed()) return ret; if (flags & DC_EXEC) { /* If we are forced to proceed, cancel that order. * If we are marked stuck we would want to force the train * to proceed to the next signal. In the other cases we * would like to pass the signal at danger and run till the * next signal we encounter. */ t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsChainInDepot() ? TFP_STUCK : TFP_SIGNAL; SetWindowDirty(WC_VEHICLE_VIEW, t->index); } return CommandCost(); } /** * Try to find a depot nearby. * @param v %Train that wants a depot. * @param max_distance Maximal search distance. * @return Information where the closest train depot is located. * @pre The given vehicle must not be crashed! */ static FindDepotData FindClosestTrainDepot(Train *v, int max_distance) { assert(!(v->vehstatus & VS_CRASHED)); if (IsRailDepotTile(v->tile)) return FindDepotData(v->tile, 0); PBSTileInfo origin = FollowTrainReservation(v); if (IsRailDepotTile(origin.tile)) return FindDepotData(origin.tile, 0); switch (_settings_game.pf.pathfinder_for_trains) { case VPF_NPF: return NPFTrainFindNearestDepot(v, max_distance); case VPF_YAPF: return YapfTrainFindNearestDepot(v, max_distance); default: NOT_REACHED(); } } /** * Locate the closest depot for this consist, and return the information to the caller. * @param location [out] If not \c NULL and a depot is found, store its location in the given address. * @param destination [out] If not \c NULL and a depot is found, store its index in the given address. * @param reverse [out] If not \c NULL and a depot is found, store reversal information in the given address. * @return A depot has been found. */ bool Train::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { FindDepotData tfdd = FindClosestTrainDepot(this, 0); if (tfdd.best_length == UINT_MAX) return false; if (location != NULL) *location = tfdd.tile; if (destination != NULL) *destination = GetDepotIndex(tfdd.tile); if (reverse != NULL) *reverse = tfdd.reverse; return true; } /** Play a sound for a train leaving the station. */ void Train::PlayLeaveStationSound() const { static const SoundFx sfx[] = { SND_04_TRAIN, SND_0A_TRAIN_HORN, SND_0A_TRAIN_HORN, SND_47_MAGLEV_2, SND_41_MAGLEV }; if (PlayVehicleSound(this, VSE_START)) return; EngineID engtype = this->engine_type; SndPlayVehicleFx(sfx[RailVehInfo(engtype)->engclass], this); } /** * Check if the train is on the last reserved tile and try to extend the path then. * @param v %Train that needs its path extended. */ static void CheckNextTrainTile(Train *v) { /* Don't do any look-ahead if path_backoff_interval is 255. */ if (_settings_game.pf.path_backoff_interval == 255) return; /* Exit if we are inside a depot. */ if (v->track == TRACK_BIT_DEPOT) return; switch (v->current_order.GetType()) { /* Exit if we reached our destination depot. */ case OT_GOTO_DEPOT: if (v->tile == v->dest_tile) return; break; case OT_GOTO_WAYPOINT: /* If we reached our waypoint, make sure we see that. */ if (IsRailWaypointTile(v->tile) && GetStationIndex(v->tile) == v->current_order.GetDestination()) ProcessOrders(v); break; case OT_NOTHING: case OT_LEAVESTATION: case OT_LOADING: /* Exit if the current order doesn't have a destination, but the train has orders. */ if (v->GetNumOrders() > 0) return; break; default: break; } /* Exit if we are on a station tile and are going to stop. */ if (IsRailStationTile(v->tile) && v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile))) return; Trackdir td = v->GetVehicleTrackdir(); /* On a tile with a red non-pbs signal, don't look ahead. */ if (IsTileType(v->tile, MP_RAILWAY) && HasSignalOnTrackdir(v->tile, td) && !IsPbsSignal(GetSignalType(v->tile, TrackdirToTrack(td))) && GetSignalStateByTrackdir(v->tile, td) == SIGNAL_STATE_RED) return; CFollowTrackRail ft(v); if (!ft.Follow(v->tile, td)) return; if (!HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits))) { /* Next tile is not reserved. */ if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { if (HasPbsSignalOnTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) { /* If the next tile is a PBS signal, try to make a reservation. */ TrackBits tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); if (_settings_game.pf.forbid_90_deg) { tracks &= ~TrackCrossesTracks(TrackdirToTrack(ft.m_old_td)); } ChooseTrainTrack(v, ft.m_new_tile, ft.m_exitdir, tracks, false, NULL, false); } } } } /** * Will the train stay in the depot the next tick? * @param v %Train to check. * @return True if it stays in the depot, false otherwise. */ static bool CheckTrainStayInDepot(Train *v) { /* bail out if not all wagons are in the same depot or not in a depot at all */ for (const Train *u = v; u != NULL; u = u->Next()) { if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return false; } /* if the train got no power, then keep it in the depot */ if (v->gcache.cached_power == 0) { v->vehstatus |= VS_STOPPED; SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); return true; } SigSegState seg_state; if (v->force_proceed == TFP_NONE) { /* force proceed was not pressed */ if (++v->wait_counter < 37) { SetWindowClassesDirty(WC_TRAINS_LIST); return true; } v->wait_counter = 0; seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner); if (seg_state == SIGSEG_FULL || HasDepotReservation(v->tile)) { /* Full and no PBS signal in block or depot reserved, can't exit. */ SetWindowClassesDirty(WC_TRAINS_LIST); return true; } } else { seg_state = _settings_game.pf.reserve_paths ? SIGSEG_PBS : UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner); } /* We are leaving a depot, but have to go to the exact same one; re-enter */ if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) { /* We need to have a reservation for this to work. */ if (HasDepotReservation(v->tile)) return true; SetDepotReservation(v->tile, true); VehicleEnterDepot(v); return true; } /* Only leave when we can reserve a path to our destination. */ if (seg_state == SIGSEG_PBS && !TryPathReserve(v) && v->force_proceed == TFP_NONE) { /* No path and no force proceed. */ SetWindowClassesDirty(WC_TRAINS_LIST); MarkTrainAsStuck(v); return true; } SetDepotReservation(v->tile, true); if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile); VehicleServiceInDepot(v); SetWindowClassesDirty(WC_TRAINS_LIST); v->PlayLeaveStationSound(); v->track = TRACK_BIT_X; if (v->direction & 2) v->track = TRACK_BIT_Y; v->vehstatus &= ~VS_HIDDEN; v->cur_speed = 0; v->UpdateViewport(true, true); v->UpdatePosition(); UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner); v->UpdateAcceleration(); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); return false; } /** * Clear the reservation of \a tile that was just left by a wagon on \a track_dir. * @param v %Train owning the reservation. * @param tile Tile with reservation to clear. * @param track_dir Track direction to clear. */ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir) { DiagDirection dir = TrackdirToExitdir(track_dir); if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* Are we just leaving a tunnel/bridge? */ if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) { TileIndex end = GetOtherTunnelBridgeEnd(tile); if (TunnelBridgeIsFree(tile, end, v).Succeeded()) { /* Free the reservation only if no other train is on the tiles. */ SetTunnelBridgeReservation(tile, false); SetTunnelBridgeReservation(end, false); if (_settings_client.gui.show_track_reservation) { if (IsBridge(tile)) { MarkBridgeDirty(tile); } else { MarkTileDirtyByTile(tile); MarkTileDirtyByTile(end); } } } } } else if (IsRailStationTile(tile)) { TileIndex new_tile = TileAddByDiagDir(tile, dir); /* If the new tile is not a further tile of the same station, we * clear the reservation for the whole platform. */ if (!IsCompatibleTrainStationTile(new_tile, tile)) { SetRailStationPlatformReservation(tile, ReverseDiagDir(dir), false); } } else { /* Any other tile */ UnreserveRailTrack(tile, TrackdirToTrack(track_dir)); } } /** * Free the reserved path in front of a vehicle. * @param v %Train owning the reserved path. * @param origin %Tile to start clearing (if #INVALID_TILE, use the current tile of \a v). * @param orig_td Track direction (if #INVALID_TRACKDIR, use the track direction of \a v). */ void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_td) { assert(v->IsFrontEngine()); TileIndex tile = origin != INVALID_TILE ? origin : v->tile; Trackdir td = orig_td != INVALID_TRACKDIR ? orig_td : v->GetVehicleTrackdir(); bool free_tile = tile != v->tile || !(IsRailStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE)); StationID station_id = IsRailStationTile(v->tile) ? GetStationIndex(v->tile) : INVALID_STATION; /* Can't be holding a reservation if we enter a depot. */ if (IsRailDepotTile(tile) && TrackdirToExitdir(td) != GetRailDepotDirection(tile)) return; if (v->track == TRACK_BIT_DEPOT) { /* Front engine is in a depot. We enter if some part is not in the depot. */ for (const Train *u = v; u != NULL; u = u->Next()) { if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return; } } /* Don't free reservation if it's not ours. */ if (TracksOverlap(GetReservedTrackbits(tile) | TrackToTrackBits(TrackdirToTrack(td)))) return; CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); while (ft.Follow(tile, td)) { tile = ft.m_new_tile; TrackdirBits bits = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(tile)); td = RemoveFirstTrackdir(&bits); assert(bits == TRACKDIR_BIT_NONE); if (!IsValidTrackdir(td)) break; if (IsTileType(tile, MP_RAILWAY)) { if (HasSignalOnTrackdir(tile, td) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td)))) { /* Conventional signal along trackdir: remove reservation and stop. */ UnreserveRailTrack(tile, TrackdirToTrack(td)); break; } if (HasPbsSignalOnTrackdir(tile, td)) { if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) { /* Red PBS signal? Can't be our reservation, would be green then. */ break; } else { /* Turn the signal back to red. */ SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_RED); MarkTileDirtyByTile(tile); } } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) { break; } } /* Don't free first station/bridge/tunnel if we are on it. */ if (free_tile || (!(ft.m_is_station && GetStationIndex(ft.m_new_tile) == station_id) && !ft.m_is_tunnel && !ft.m_is_bridge)) ClearPathReservation(v, tile, td); free_tile = true; } } static const byte _initial_tile_subcoord[6][4][3] = { {{ 15, 8, 1 }, { 0, 0, 0 }, { 0, 8, 5 }, { 0, 0, 0 }}, {{ 0, 0, 0 }, { 8, 0, 3 }, { 0, 0, 0 }, { 8, 15, 7 }}, {{ 0, 0, 0 }, { 7, 0, 2 }, { 0, 7, 6 }, { 0, 0, 0 }}, {{ 15, 8, 2 }, { 0, 0, 0 }, { 0, 0, 0 }, { 8, 15, 6 }}, {{ 15, 7, 0 }, { 8, 0, 4 }, { 0, 0, 0 }, { 0, 0, 0 }}, {{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 8, 4 }, { 7, 15, 0 }}, }; /** * Perform pathfinding for a train. * * @param v The train * @param tile The tile the train is about to enter * @param enterdir Diagonal direction the train is coming from * @param tracks Usable tracks on the new tile * @param path_found [out] Whether a path has been found or not. * @param do_track_reservation Path reservation is requested * @param dest [out] State and destination of the requested path * @return The best track the train should follow */ static Track DoTrainPathfind(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool do_track_reservation, PBSTileInfo *dest) { switch (_settings_game.pf.pathfinder_for_trains) { case VPF_NPF: return NPFTrainChooseTrack(v, tile, enterdir, tracks, path_found, do_track_reservation, dest); case VPF_YAPF: return YapfTrainChooseTrack(v, tile, enterdir, tracks, path_found, do_track_reservation, dest); default: NOT_REACHED(); } } /** * Extend a train path as far as possible. Stops on encountering a safe tile, * another reservation or a track choice. * @return INVALID_TILE indicates that the reservation failed. */ static PBSTileInfo ExtendTrainReservation(const Train *v, TrackBits *new_tracks, DiagDirection *enterdir) { PBSTileInfo origin = FollowTrainReservation(v); CFollowTrackRail ft(v); TileIndex tile = origin.tile; Trackdir cur_td = origin.trackdir; while (ft.Follow(tile, cur_td)) { if (KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { /* Possible signal tile. */ if (HasOnewaySignalBlockingTrackdir(ft.m_new_tile, FindFirstTrackdir(ft.m_new_td_bits))) break; } if (_settings_game.pf.forbid_90_deg) { ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td); if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) break; } /* Station, depot or waypoint are a possible target. */ bool target_seen = ft.m_is_station || (IsTileType(ft.m_new_tile, MP_RAILWAY) && !IsPlainRail(ft.m_new_tile)); if (target_seen || KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { /* Choice found or possible target encountered. * On finding a possible target, we need to stop and let the pathfinder handle the * remaining path. This is because we don't know if this target is in one of our * orders, so we might cause pathfinding to fail later on if we find a choice. * This failure would cause a bogous call to TryReserveSafePath which might reserve * a wrong path not leading to our next destination. */ if (HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(ft.m_old_td)))) break; /* If we did skip some tiles, backtrack to the first skipped tile so the pathfinder * actually starts its search at the first unreserved tile. */ if (ft.m_tiles_skipped != 0) ft.m_new_tile -= TileOffsByDiagDir(ft.m_exitdir) * ft.m_tiles_skipped; /* Choice found, path valid but not okay. Save info about the choice tile as well. */ if (new_tracks != NULL) *new_tracks = TrackdirBitsToTrackBits(ft.m_new_td_bits); if (enterdir != NULL) *enterdir = ft.m_exitdir; return PBSTileInfo(ft.m_new_tile, ft.m_old_td, false); } tile = ft.m_new_tile; cur_td = FindFirstTrackdir(ft.m_new_td_bits); if (IsSafeWaitingPosition(v, tile, cur_td, true, _settings_game.pf.forbid_90_deg)) { bool wp_free = IsWaitingPositionFree(v, tile, cur_td, _settings_game.pf.forbid_90_deg); if (!(wp_free && TryReserveRailTrack(tile, TrackdirToTrack(cur_td)))) break; /* Safe position is all good, path valid and okay. */ return PBSTileInfo(tile, cur_td, true); } if (!TryReserveRailTrack(tile, TrackdirToTrack(cur_td))) break; } if (ft.m_err == CFollowTrackRail::EC_OWNER || ft.m_err == CFollowTrackRail::EC_NO_WAY) { /* End of line, path valid and okay. */ return PBSTileInfo(ft.m_old_tile, ft.m_old_td, true); } /* Sorry, can't reserve path, back out. */ tile = origin.tile; cur_td = origin.trackdir; TileIndex stopped = ft.m_old_tile; Trackdir stopped_td = ft.m_old_td; while (tile != stopped || cur_td != stopped_td) { if (!ft.Follow(tile, cur_td)) break; if (_settings_game.pf.forbid_90_deg) { ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(ft.m_old_td); assert(ft.m_new_td_bits != TRACKDIR_BIT_NONE); } assert(KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE); tile = ft.m_new_tile; cur_td = FindFirstTrackdir(ft.m_new_td_bits); UnreserveRailTrack(tile, TrackdirToTrack(cur_td)); } /* Path invalid. */ return PBSTileInfo(); } /** * Try to reserve any path to a safe tile, ignoring the vehicle's destination. * Safe tiles are tiles in front of a signal, depots and station tiles at end of line. * * @param v The vehicle. * @param tile The tile the search should start from. * @param td The trackdir the search should start from. * @param override_railtype Whether all physically compatible railtypes should be followed. * @return True if a path to a safe stopping tile could be reserved. */ static bool TryReserveSafeTrack(const Train *v, TileIndex tile, Trackdir td, bool override_tailtype) { switch (_settings_game.pf.pathfinder_for_trains) { case VPF_NPF: return NPFTrainFindNearestSafeTile(v, tile, td, override_tailtype); case VPF_YAPF: return YapfTrainFindNearestSafeTile(v, tile, td, override_tailtype); default: NOT_REACHED(); } } /** This class will save the current order of a vehicle and restore it on destruction. */ class VehicleOrderSaver { private: Train *v; Order old_order; TileIndex old_dest_tile; StationID old_last_station_visited; VehicleOrderID index; bool suppress_implicit_orders; public: VehicleOrderSaver(Train *_v) : v(_v), old_order(_v->current_order), old_dest_tile(_v->dest_tile), old_last_station_visited(_v->last_station_visited), index(_v->cur_real_order_index), suppress_implicit_orders(HasBit(_v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) { } ~VehicleOrderSaver() { this->v->current_order = this->old_order; this->v->dest_tile = this->old_dest_tile; this->v->last_station_visited = this->old_last_station_visited; SB(this->v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS, 1, suppress_implicit_orders ? 1: 0); } /** * Set the current vehicle order to the next order in the order list. * @param skip_first Shall the first (i.e. active) order be skipped? * @return True if a suitable next order could be found. */ bool SwitchToNextOrder(bool skip_first) { if (this->v->GetNumOrders() == 0) return false; if (skip_first) ++this->index; int depth = 0; do { /* Wrap around. */ if (this->index >= this->v->GetNumOrders()) this->index = 0; Order *order = this->v->GetOrder(this->index); assert(order != NULL); switch (order->GetType()) { case OT_GOTO_DEPOT: /* Skip service in depot orders when the train doesn't need service. */ if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !this->v->NeedsServicing()) break; case OT_GOTO_STATION: case OT_GOTO_WAYPOINT: this->v->current_order = *order; return UpdateOrderDest(this->v, order, 0, true); case OT_CONDITIONAL: { VehicleOrderID next = ProcessConditionalOrder(order, this->v); if (next != INVALID_VEH_ORDER_ID) { depth++; this->index = next; /* Don't increment next, so no break here. */ continue; } break; } default: break; } /* Don't increment inside the while because otherwise conditional * orders can lead to an infinite loop. */ ++this->index; depth++; } while (this->index != this->v->cur_real_order_index && depth < this->v->GetNumOrders()); return false; } }; /* choose a track */ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck) { Track best_track = INVALID_TRACK; bool do_track_reservation = _settings_game.pf.reserve_paths || force_res; bool changed_signal = false; assert((tracks & ~TRACK_BIT_MASK) == 0); if (got_reservation != NULL) *got_reservation = false; /* Don't use tracks here as the setting to forbid 90 deg turns might have been switched between reservation and now. */ TrackBits res_tracks = (TrackBits)(GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir)); /* Do we have a suitable reserved track? */ if (res_tracks != TRACK_BIT_NONE) return FindFirstTrack(res_tracks); /* Quick return in case only one possible track is available */ if (KillFirstBit(tracks) == TRACK_BIT_NONE) { Track track = FindFirstTrack(tracks); /* We need to check for signals only here, as a junction tile can't have signals. */ if (track != INVALID_TRACK && HasPbsSignalOnTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir))) { do_track_reservation = true; changed_signal = true; SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(track, enterdir), SIGNAL_STATE_GREEN); } else if (!do_track_reservation) { return track; } best_track = track; } PBSTileInfo res_dest(tile, INVALID_TRACKDIR, false); DiagDirection dest_enterdir = enterdir; if (do_track_reservation) { res_dest = ExtendTrainReservation(v, &tracks, &dest_enterdir); if (res_dest.tile == INVALID_TILE) { /* Reservation failed? */ if (mark_stuck) MarkTrainAsStuck(v); if (changed_signal) SetSignalStateByTrackdir(tile, TrackEnterdirToTrackdir(best_track, enterdir), SIGNAL_STATE_RED); return FindFirstTrack(tracks); } if (res_dest.okay) { /* Got a valid reservation that ends at a safe target, quick exit. */ if (got_reservation != NULL) *got_reservation = true; if (changed_signal) MarkTileDirtyByTile(tile); TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); return best_track; } /* Check if the train needs service here, so it has a chance to always find a depot. * Also check if the current order is a service order so we don't reserve a path to * the destination but instead to the next one if service isn't needed. */ CheckIfTrainNeedsService(v); if (v->current_order.IsType(OT_DUMMY) || v->current_order.IsType(OT_CONDITIONAL) || v->current_order.IsType(OT_GOTO_DEPOT)) ProcessOrders(v); } /* Save the current train order. The destructor will restore the old order on function exit. */ VehicleOrderSaver orders(v); /* If the current tile is the destination of the current order and * a reservation was requested, advance to the next order. * Don't advance on a depot order as depots are always safe end points * for a path and no look-ahead is necessary. This also avoids a * problem with depot orders not part of the order list when the * order list itself is empty. */ if (v->current_order.IsType(OT_LEAVESTATION)) { orders.SwitchToNextOrder(false); } else if (v->current_order.IsType(OT_LOADING) || (!v->current_order.IsType(OT_GOTO_DEPOT) && ( v->current_order.IsType(OT_GOTO_STATION) ? IsRailStationTile(v->tile) && v->current_order.GetDestination() == GetStationIndex(v->tile) : v->tile == v->dest_tile))) { orders.SwitchToNextOrder(true); } if (res_dest.tile != INVALID_TILE && !res_dest.okay) { /* Pathfinders are able to tell that route was only 'guessed'. */ bool path_found = true; TileIndex new_tile = res_dest.tile; Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, path_found, do_track_reservation, &res_dest); if (new_tile == tile) best_track = next_track; v->HandlePathfindingResult(path_found); } /* No track reservation requested -> finished. */ if (!do_track_reservation) return best_track; /* A path was found, but could not be reserved. */ if (res_dest.tile != INVALID_TILE && !res_dest.okay) { if (mark_stuck) MarkTrainAsStuck(v); FreeTrainTrackReservation(v); return best_track; } /* No possible reservation target found, we are probably lost. */ if (res_dest.tile == INVALID_TILE) { /* Try to find any safe destination. */ PBSTileInfo origin = FollowTrainReservation(v); if (TryReserveSafeTrack(v, origin.tile, origin.trackdir, false)) { TrackBits res = GetReservedTrackbits(tile) & DiagdirReachesTracks(enterdir); best_track = FindFirstTrack(res); TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); if (got_reservation != NULL) *got_reservation = true; if (changed_signal) MarkTileDirtyByTile(tile); } else { FreeTrainTrackReservation(v); if (mark_stuck) MarkTrainAsStuck(v); } return best_track; } if (got_reservation != NULL) *got_reservation = true; /* Reservation target found and free, check if it is safe. */ while (!IsSafeWaitingPosition(v, res_dest.tile, res_dest.trackdir, true, _settings_game.pf.forbid_90_deg)) { /* Extend reservation until we have found a safe position. */ DiagDirection exitdir = TrackdirToExitdir(res_dest.trackdir); TileIndex next_tile = TileAddByDiagDir(res_dest.tile, exitdir); TrackBits reachable = TrackdirBitsToTrackBits((TrackdirBits)(GetTileTrackStatus(next_tile, TRANSPORT_RAIL, 0))) & DiagdirReachesTracks(exitdir); if (_settings_game.pf.forbid_90_deg) { reachable &= ~TrackCrossesTracks(TrackdirToTrack(res_dest.trackdir)); } /* Get next order with destination. */ if (orders.SwitchToNextOrder(true)) { PBSTileInfo cur_dest; bool path_found; DoTrainPathfind(v, next_tile, exitdir, reachable, path_found, true, &cur_dest); if (cur_dest.tile != INVALID_TILE) { res_dest = cur_dest; if (res_dest.okay) continue; /* Path found, but could not be reserved. */ FreeTrainTrackReservation(v); if (mark_stuck) MarkTrainAsStuck(v); if (got_reservation != NULL) *got_reservation = false; changed_signal = false; break; } } /* No order or no safe position found, try any position. */ if (!TryReserveSafeTrack(v, res_dest.tile, res_dest.trackdir, true)) { FreeTrainTrackReservation(v); if (mark_stuck) MarkTrainAsStuck(v); if (got_reservation != NULL) *got_reservation = false; changed_signal = false; } break; } TryReserveRailTrack(v->tile, TrackdirToTrack(v->GetVehicleTrackdir())); if (changed_signal) MarkTileDirtyByTile(tile); return best_track; } /** * Try to reserve a path to a safe position. * * @param v The vehicle * @param mark_as_stuck Should the train be marked as stuck on a failed reservation? * @param first_tile_okay True if no path should be reserved if the current tile is a safe position. * @return True if a path could be reserved. */ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay) { assert(v->IsFrontEngine()); /* We have to handle depots specially as the track follower won't look * at the depot tile itself but starts from the next tile. If we are still * inside the depot, a depot reservation can never be ours. */ if (v->track == TRACK_BIT_DEPOT) { if (HasDepotReservation(v->tile)) { if (mark_as_stuck) MarkTrainAsStuck(v); return false; } else { /* Depot not reserved, but the next tile might be. */ TileIndex next_tile = TileAddByDiagDir(v->tile, GetRailDepotDirection(v->tile)); if (HasReservedTracks(next_tile, DiagdirReachesTracks(GetRailDepotDirection(v->tile)))) return false; } } Vehicle *other_train = NULL; PBSTileInfo origin = FollowTrainReservation(v, &other_train); /* The path we are driving on is already blocked by some other train. * This can only happen in certain situations when mixing path and * block signals or when changing tracks and/or signals. * Exit here as doing any further reservations will probably just * make matters worse. */ if (other_train != NULL && other_train->index != v->index) { if (mark_as_stuck) MarkTrainAsStuck(v); return false; } /* If we have a reserved path and the path ends at a safe tile, we are finished already. */ if (origin.okay && (v->tile != origin.tile || first_tile_okay)) { /* Can't be stuck then. */ if (HasBit(v->flags, VRF_TRAIN_STUCK)) SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); ClrBit(v->flags, VRF_TRAIN_STUCK); return true; } /* If we are in a depot, tentatively reserve the depot. */ if (v->track == TRACK_BIT_DEPOT) { SetDepotReservation(v->tile, true); if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(v->tile); } DiagDirection exitdir = TrackdirToExitdir(origin.trackdir); TileIndex new_tile = TileAddByDiagDir(origin.tile, exitdir); TrackBits reachable = TrackdirBitsToTrackBits(TrackStatusToTrackdirBits(GetTileTrackStatus(new_tile, TRANSPORT_RAIL, 0)) & DiagdirReachesTrackdirs(exitdir)); if (_settings_game.pf.forbid_90_deg) reachable &= ~TrackCrossesTracks(TrackdirToTrack(origin.trackdir)); bool res_made = false; ChooseTrainTrack(v, new_tile, exitdir, reachable, true, &res_made, mark_as_stuck); if (!res_made) { /* Free the depot reservation as well. */ if (v->track == TRACK_BIT_DEPOT) SetDepotReservation(v->tile, false); return false; } if (HasBit(v->flags, VRF_TRAIN_STUCK)) { v->wait_counter = 0; SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } ClrBit(v->flags, VRF_TRAIN_STUCK); return true; } static bool CheckReverseTrain(const Train *v) { if (_settings_game.difficulty.line_reverse_mode != 0 || v->track == TRACK_BIT_DEPOT || v->track == TRACK_BIT_WORMHOLE || !(v->direction & 1)) { return false; } assert(v->track != TRACK_BIT_NONE); switch (_settings_game.pf.pathfinder_for_trains) { case VPF_NPF: return NPFTrainCheckReverse(v); case VPF_YAPF: return YapfTrainCheckReverse(v); default: NOT_REACHED(); } } /** * Get the location of the next station to visit. * @param station Next station to visit. * @return Location of the new station. */ TileIndex Train::GetOrderStationLocation(StationID station) { if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION; const Station *st = Station::Get(station); if (!(st->facilities & FACIL_TRAIN)) { /* The destination station has no trainstation tiles. */ this->IncrementRealOrderIndex(); return 0; } return st->xy; } /** Goods at the consist have changed, update the graphics, cargo, and acceleration. */ void Train::MarkDirty() { Train *v = this; do { v->colourmap = PAL_NONE; v->UpdateViewport(true, false); } while ((v = v->Next()) != NULL); /* need to update acceleration and cached values since the goods on the train changed. */ this->CargoChanged(); this->UpdateAcceleration(); } /** * This function looks at the vehicle and updates its speed (cur_speed * and subspeed) variables. Furthermore, it returns the distance that * the train can drive this tick. #Vehicle::GetAdvanceDistance() determines * the distance to drive before moving a step on the map. * @return distance to drive. */ int Train::UpdateSpeed() { switch (_settings_game.vehicle.train_acceleration_model) { default: NOT_REACHED(); case AM_ORIGINAL: return this->DoUpdateSpeed(this->acceleration * (this->GetAccelerationStatus() == AS_BRAKE ? -4 : 2), 0, this->GetCurrentMaxSpeed()); case AM_REALISTIC: return this->DoUpdateSpeed(this->GetAcceleration(), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 2, this->GetCurrentMaxSpeed()); } } /** * Trains enters a station, send out a news item if it is the first train, and start loading. * @param v Train that entered the station. * @param station Station visited. */ static void TrainEnterStation(Train *v, StationID station) { v->last_station_visited = station; /* check if a train ever visited this station before */ Station *st = Station::Get(station); if (!(st->had_vehicle_of_type & HVOT_TRAIN)) { st->had_vehicle_of_type |= HVOT_TRAIN; SetDParam(0, st->index); AddVehicleNewsItem( STR_NEWS_FIRST_TRAIN_ARRIVAL, v->owner == _local_company ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index ); AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index)); Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index)); } v->force_proceed = TFP_NONE; SetWindowDirty(WC_VEHICLE_VIEW, v->index); v->BeginLoading(); TriggerStationRandomisation(st, v->tile, SRT_TRAIN_ARRIVES); TriggerStationAnimation(st, v->tile, SAT_TRAIN_ARRIVES); } /* Check if the vehicle is compatible with the specified tile */ static inline bool CheckCompatibleRail(const Train *v, TileIndex tile) { return IsTileOwner(tile, v->owner) && (!v->IsFrontEngine() || HasBit(v->compatible_railtypes, GetRailType(tile))); } /** Data structure for storing engine speed changes of an acceleration type. */ struct AccelerationSlowdownParams { byte small_turn; ///< Speed change due to a small turn. byte large_turn; ///< Speed change due to a large turn. byte z_up; ///< Fraction to remove when moving up. byte z_down; ///< Fraction to add when moving down. }; /** Speed update fractions for each acceleration type. */ static const AccelerationSlowdownParams _accel_slowdown[] = { /* normal accel */ {256 / 4, 256 / 2, 256 / 4, 2}, ///< normal {256 / 4, 256 / 2, 256 / 4, 2}, ///< monorail {0, 256 / 2, 256 / 4, 2}, ///< maglev }; /** * Modify the speed of the vehicle due to a change in altitude. * @param v %Train to update. * @param old_z Previous height. */ static inline void AffectSpeedByZChange(Train *v, int old_z) { if (old_z == v->z_pos || _settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) return; const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type]; if (old_z < v->z_pos) { v->cur_speed -= (v->cur_speed * asp->z_up >> 8); } else { uint16 spd = v->cur_speed + asp->z_down; if (spd <= v->gcache.cached_max_track_speed) v->cur_speed = spd; } } static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir) { if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_SIGNALS) { TrackdirBits tracks = TrackBitsToTrackdirBits(GetTrackBits(tile)) & DiagdirReachesTrackdirs(dir); Trackdir trackdir = FindFirstTrackdir(tracks); if (UpdateSignalsOnSegment(tile, TrackdirToExitdir(trackdir), GetTileOwner(tile)) == SIGSEG_PBS && HasSignalOnTrackdir(tile, trackdir)) { /* A PBS block with a non-PBS signal facing us? */ if (!IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true; } } return false; } /** Tries to reserve track under whole train consist. */ void Train::ReserveTrackUnderConsist() const { for (const Train *u = this; u != NULL; u = u->Next()) { switch (u->track) { case TRACK_BIT_WORMHOLE: TryReserveRailTrack(u->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(u->tile))); break; case TRACK_BIT_DEPOT: break; default: TryReserveRailTrack(u->tile, TrackBitsToTrack(u->track)); break; } } } /** * The train vehicle crashed! * Update its status and other parts around it. * @param flooded Crash was caused by flooding. * @return Number of people killed. */ uint Train::Crash(bool flooded) { uint pass = 0; if (this->IsFrontEngine()) { pass += 2; // driver /* Remove the reserved path in front of the train if it is not stuck. * Also clear all reserved tracks the train is currently on. */ if (!HasBit(this->flags, VRF_TRAIN_STUCK)) FreeTrainTrackReservation(this); for (const Train *v = this; v != NULL; v = v->Next()) { ClearPathReservation(v, v->tile, v->GetVehicleTrackdir()); if (IsTileType(v->tile, MP_TUNNELBRIDGE)) { /* ClearPathReservation will not free the wormhole exit * if the train has just entered the wormhole. */ SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(v->tile), false); } } /* we may need to update crossing we were approaching, * but must be updated after the train has been marked crashed */ TileIndex crossing = TrainApproachingCrossingTile(this); if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing); /* Remove the loading indicators (if any) */ HideFillingPercent(&this->fill_percent_te_id); } pass += this->GroundVehicleBase::Crash(flooded); this->crash_anim_pos = flooded ? 4000 : 1; // max 4440, disappear pretty fast when flooded return pass; } /** * Marks train as crashed and creates an AI event. * Doesn't do anything if the train is crashed already. * @param v first vehicle of chain * @return number of victims (including 2 drivers; zero if train was already crashed) */ static uint TrainCrashed(Train *v) { uint num = 0; /* do not crash train twice */ if (!(v->vehstatus & VS_CRASHED)) { num = v->Crash(); AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN)); Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_TRAIN)); } /* Try to re-reserve track under already crashed train too. * Crash() clears the reservation! */ v->ReserveTrackUnderConsist(); return num; } /** Temporary data storage for testing collisions. */ struct TrainCollideChecker { Train *v; ///< %Vehicle we are testing for collision. uint num; ///< Total number of victims if train collided. }; /** * Collision test function. * @param v %Train vehicle to test collision with. * @param data %Train being examined. * @return \c NULL (always continue search) */ static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data) { TrainCollideChecker *tcc = (TrainCollideChecker*)data; /* not a train or in depot */ if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return NULL; /* do not crash into trains of another company. */ if (v->owner != tcc->v->owner) return NULL; /* get first vehicle now to make most usual checks faster */ Train *coll = Train::From(v)->First(); /* can't collide with own wagons */ if (coll == tcc->v) return NULL; int x_diff = v->x_pos - tcc->v->x_pos; int y_diff = v->y_pos - tcc->v->y_pos; /* Do fast calculation to check whether trains are not in close vicinity * and quickly reject trains distant enough for any collision. * Differences are shifted by 7, mapping range [-7 .. 8] into [0 .. 15] * Differences are then ORed and then we check for any higher bits */ uint hash = (y_diff + 7) | (x_diff + 7); if (hash & ~15) return NULL; /* Slower check using multiplication */ int min_diff = (Train::From(v)->gcache.cached_veh_length + 1) / 2 + (tcc->v->gcache.cached_veh_length + 1) / 2 - 1; if (x_diff * x_diff + y_diff * y_diff > min_diff * min_diff) return NULL; /* Happens when there is a train under bridge next to bridge head */ if (abs(v->z_pos - tcc->v->z_pos) > 5) return NULL; /* crash both trains */ tcc->num += TrainCrashed(tcc->v); tcc->num += TrainCrashed(coll); return NULL; // continue searching } /** * Checks whether the specified train has a collision with another vehicle. If * so, destroys this vehicle, and the other vehicle if its subtype has TS_Front. * Reports the incident in a flashy news item, modifies station ratings and * plays a sound. * @param v %Train to test. */ static bool CheckTrainCollision(Train *v) { /* can't collide in depot */ if (v->track == TRACK_BIT_DEPOT) return false; assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile); TrainCollideChecker tcc; tcc.v = v; tcc.num = 0; /* find colliding vehicles */ if (v->track == TRACK_BIT_WORMHOLE) { FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum); FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum); } else { FindVehicleOnPosXY(v->x_pos, v->y_pos, &tcc, FindTrainCollideEnum); } /* any dead -> no crash */ if (tcc.num == 0) return false; SetDParam(0, tcc.num); AddVehicleNewsItem(STR_NEWS_TRAIN_CRASH, NT_ACCIDENT, v->index); ModifyStationRatingAround(v->tile, v->owner, -160, 30); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_BIG_CRASH, v); return true; } static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data) { if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL; Train *t = Train::From(v); DiagDirection exitdir = *(DiagDirection *)data; /* not front engine of a train, inside wormhole or depot, crashed */ if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return NULL; if (t->cur_speed > 5 || TrainExitDir(t->direction, t->track) != exitdir) return NULL; return t; } /** * Move a vehicle chain one movement stop forwards. * @param v First vehicle to move. * @param nomove Stop moving this and all following vehicles. * @param reverse Set to false to not execute the vehicle reversing. This does not change any other logic. * @return True if the vehicle could be moved forward, false otherwise. */ bool TrainController(Train *v, Vehicle *nomove, bool reverse) { Train *first = v->First(); Train *prev; bool direction_changed = false; // has direction of any part changed? /* For every vehicle after and including the given vehicle */ for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) { DiagDirection enterdir = DIAGDIR_BEGIN; bool update_signals_crossing = false; // will we update signals or crossing state? GetNewVehiclePosResult gp = GetNewVehiclePos(v); if (v->track != TRACK_BIT_WORMHOLE) { /* Not inside tunnel */ if (gp.old_tile == gp.new_tile) { /* Staying in the old tile */ if (v->track == TRACK_BIT_DEPOT) { /* Inside depot */ gp.x = v->x_pos; gp.y = v->y_pos; } else { /* Not inside depot */ /* Reverse when we are at the end of the track already, do not move to the new position */ if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v, reverse)) return false; uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) { goto invalid_rail; } if (HasBit(r, VETS_ENTERED_STATION)) { /* The new position is the end of the platform */ TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); } } } else { /* A new tile is about to be entered. */ /* Determine what direction we're entering the new tile from */ enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile); assert(IsValidDiagDirection(enterdir)); /* Get the status of the tracks in the new tile and mask * away the bits that aren't reachable. */ TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir)); TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir); TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs; TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs); TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); if (_settings_game.pf.forbid_90_deg && prev == NULL) { /* We allow wagons to make 90 deg turns, because forbid_90_deg * can be switched on halfway a turn */ bits &= ~TrackCrossesTracks(FindFirstTrack(v->track)); } if (bits == TRACK_BIT_NONE) goto invalid_rail; /* Check if the new tile constrains tracks that are compatible * with the current train, if not, bail out. */ if (!CheckCompatibleRail(v, gp.new_tile)) goto invalid_rail; TrackBits chosen_track; if (prev == NULL) { /* Currently the locomotive is active. Determine which one of the * available tracks to choose */ chosen_track = TrackToTrackBits(ChooseTrainTrack(v, gp.new_tile, enterdir, bits, false, NULL, true)); assert(chosen_track & (bits | GetReservedTrackbits(gp.new_tile))); if (v->force_proceed != TFP_NONE && IsPlainRailTile(gp.new_tile) && HasSignals(gp.new_tile)) { /* For each signal we find decrease the counter by one. * We start at two, so the first signal we pass decreases * this to one, then if we reach the next signal it is * decreased to zero and we won't pass that new signal. */ Trackdir dir = FindFirstTrackdir(trackdirbits); if (HasSignalOnTrackdir(gp.new_tile, dir) || (HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(dir)) && GetSignalType(gp.new_tile, TrackdirToTrack(dir)) != SIGTYPE_PBS)) { /* However, we do not want to be stopped by PBS signals * entered via the back. */ v->force_proceed = (v->force_proceed == TFP_SIGNAL) ? TFP_STUCK : TFP_NONE; SetWindowDirty(WC_VEHICLE_VIEW, v->index); } } /* Check if it's a red signal and that force proceed is not clicked. */ if ((red_signals & chosen_track) && v->force_proceed == TFP_NONE) { /* In front of a red signal */ Trackdir i = FindFirstTrackdir(trackdirbits); /* Don't handle stuck trains here. */ if (HasBit(v->flags, VRF_TRAIN_STUCK)) return false; if (!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(i))) { v->cur_speed = 0; v->subspeed = 0; v->progress = 255 - 100; if (!_settings_game.pf.reverse_at_signals || ++v->wait_counter < _settings_game.pf.wait_oneway_signal * 20) return false; } else if (HasSignalOnTrackdir(gp.new_tile, i)) { v->cur_speed = 0; v->subspeed = 0; v->progress = 255 - 10; if (!_settings_game.pf.reverse_at_signals || ++v->wait_counter < _settings_game.pf.wait_twoway_signal * 73) { DiagDirection exitdir = TrackdirToExitdir(i); TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir); exitdir = ReverseDiagDir(exitdir); /* check if a train is waiting on the other side */ if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return false; } } /* If we would reverse but are currently in a PBS block and * reversing of stuck trains is disabled, don't reverse. * This does not apply if the reason for reversing is a one-way * signal blocking us, because a train would then be stuck forever. */ if (!_settings_game.pf.reverse_at_signals && !HasOnewaySignalBlockingTrackdir(gp.new_tile, i) && UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) { v->wait_counter = 0; return false; } goto reverse_train_direction; } else { TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track), false); } } else { /* The wagon is active, simply follow the prev vehicle. */ if (prev->tile == gp.new_tile) { /* Choose the same track as prev */ if (prev->track == TRACK_BIT_WORMHOLE) { /* Vehicles entering tunnels enter the wormhole earlier than for bridges. * However, just choose the track into the wormhole. */ assert(IsTunnel(prev->tile)); chosen_track = bits; } else { chosen_track = prev->track; } } else { /* Choose the track that leads to the tile where prev is. * This case is active if 'prev' is already on the second next tile, when 'v' just enters the next tile. * I.e. when the tile between them has only space for a single vehicle like * 1) horizontal/vertical track tiles and * 2) some orientations of tunnel entries, where the vehicle is already inside the wormhole at 8/16 from the tile edge. * Is also the train just reversing, the wagon inside the tunnel is 'on' the tile of the opposite tunnel entry. */ static const TrackBits _connecting_track[DIAGDIR_END][DIAGDIR_END] = { {TRACK_BIT_X, TRACK_BIT_LOWER, TRACK_BIT_NONE, TRACK_BIT_LEFT }, {TRACK_BIT_UPPER, TRACK_BIT_Y, TRACK_BIT_LEFT, TRACK_BIT_NONE }, {TRACK_BIT_NONE, TRACK_BIT_RIGHT, TRACK_BIT_X, TRACK_BIT_UPPER}, {TRACK_BIT_RIGHT, TRACK_BIT_NONE, TRACK_BIT_LOWER, TRACK_BIT_Y } }; DiagDirection exitdir = DiagdirBetweenTiles(gp.new_tile, prev->tile); assert(IsValidDiagDirection(exitdir)); chosen_track = _connecting_track[enterdir][exitdir]; } chosen_track &= bits; } /* Make sure chosen track is a valid track */ assert( chosen_track == TRACK_BIT_X || chosen_track == TRACK_BIT_Y || chosen_track == TRACK_BIT_UPPER || chosen_track == TRACK_BIT_LOWER || chosen_track == TRACK_BIT_LEFT || chosen_track == TRACK_BIT_RIGHT); /* Update XY to reflect the entrance to the new tile, and select the direction to use */ const byte *b = _initial_tile_subcoord[FIND_FIRST_BIT(chosen_track)][enterdir]; gp.x = (gp.x & ~0xF) | b[0]; gp.y = (gp.y & ~0xF) | b[1]; Direction chosen_dir = (Direction)b[2]; /* Call the landscape function and tell it that the vehicle entered the tile */ uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) { goto invalid_rail; } if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { Track track = FindFirstTrack(chosen_track); Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir); if (v->IsFrontEngine() && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) { SetSignalStateByTrackdir(gp.new_tile, tdir, SIGNAL_STATE_RED); MarkTileDirtyByTile(gp.new_tile); } /* Clear any track reservation when the last vehicle leaves the tile */ if (v->Next() == NULL) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir()); v->tile = gp.new_tile; if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) { v->First()->ConsistChanged(CCF_TRACK); } v->track = chosen_track; assert(v->track); } /* We need to update signal status, but after the vehicle position hash * has been updated by UpdateInclination() */ update_signals_crossing = true; if (chosen_dir != v->direction) { if (prev == NULL && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type]; DirDiff diff = DirDifference(v->direction, chosen_dir); v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8; } direction_changed = true; v->direction = chosen_dir; } if (v->IsFrontEngine()) { v->wait_counter = 0; /* If we are approaching a crossing that is reserved, play the sound now. */ TileIndex crossing = TrainApproachingCrossingTile(v); if (crossing != INVALID_TILE && HasCrossingReservation(crossing) && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing); /* Always try to extend the reservation when entering a tile. */ CheckNextTrainTile(v); } if (HasBit(r, VETS_ENTERED_STATION)) { /* The new position is the location where we want to stop */ TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET); } } } else { if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { /* Perform look-ahead on tunnel exit. */ if (v->IsFrontEngine()) { TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile))); CheckNextTrainTile(v); } /* Prevent v->UpdateInclination() being called with wrong parameters. * This could happen if the train was reversed inside the tunnel/bridge. */ if (gp.old_tile == gp.new_tile) { gp.old_tile = GetOtherTunnelBridgeEnd(gp.old_tile); } } else { v->x_pos = gp.x; v->y_pos = gp.y; v->UpdatePosition(); if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true); continue; } } /* update image of train, as well as delta XY */ v->UpdateDeltaXY(v->direction); v->x_pos = gp.x; v->y_pos = gp.y; v->UpdatePosition(); /* update the Z position of the vehicle */ int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false); if (prev == NULL) { /* This is the first vehicle in the train */ AffectSpeedByZChange(v, old_z); } if (update_signals_crossing) { if (v->IsFrontEngine()) { if (TrainMovedChangeSignals(gp.new_tile, enterdir)) { /* We are entering a block with PBS signals right now, but * not through a PBS signal. This means we don't have a * reservation right now. As a conventional signal will only * ever be green if no other train is in the block, getting * a path should always be possible. If the player built * such a strange network that it is not possible, the train * will be marked as stuck and the player has to deal with * the problem. */ if ((!HasReservedTracks(gp.new_tile, v->track) && !TryReserveRailTrack(gp.new_tile, FindFirstTrack(v->track))) || !TryPathReserve(v)) { MarkTrainAsStuck(v); } } } /* Signals can only change when the first * (above) or the last vehicle moves. */ if (v->Next() == NULL) { TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir)); if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile); } } /* Do not check on every tick to save some computing time. */ if (v->IsFrontEngine() && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v); } if (direction_changed) first->tcache.cached_max_curve_speed = first->GetCurveSpeedLimit(); return true; invalid_rail: /* We've reached end of line?? */ if (prev != NULL) error("Disconnecting train"); reverse_train_direction: if (reverse) { v->wait_counter = 0; v->cur_speed = 0; v->subspeed = 0; ReverseTrainDirection(v); } return false; } /** * Collect trackbits of all crashed train vehicles on a tile * @param v Vehicle passed from Find/HasVehicleOnPos() * @param data trackdirbits for the result * @return NULL to iterate over all vehicles on the tile. */ static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data) { TrackBits *trackbits = (TrackBits *)data; if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) { TrackBits train_tbits = Train::From(v)->track; if (train_tbits == TRACK_BIT_WORMHOLE) { /* Vehicle is inside a wormhole, v->track contains no useful value then. */ *trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile)); } else if (train_tbits != TRACK_BIT_DEPOT) { *trackbits |= train_tbits; } } return NULL; } /** * Deletes/Clears the last wagon of a crashed train. It takes the engine of the * train, then goes to the last wagon and deletes that. Each call to this function * will remove the last wagon of a crashed train. If this wagon was on a crossing, * or inside a tunnel/bridge, recalculate the signals as they might need updating * @param v the Vehicle of which last wagon is to be removed */ static void DeleteLastWagon(Train *v) { Train *first = v->First(); /* Go to the last wagon and delete the link pointing there * *u is then the one-before-last wagon, and *v the last * one which will physically be removed */ Train *u = v; for (; v->Next() != NULL; v = v->Next()) u = v; u->SetNext(NULL); if (first != v) { /* Recalculate cached train properties */ first->ConsistChanged(CCF_ARRANGE); /* Update the depot window if the first vehicle is in depot - * if v == first, then it is updated in PreDestructor() */ if (first->track == TRACK_BIT_DEPOT) { SetWindowDirty(WC_VEHICLE_DEPOT, first->tile); } v->last_station_visited = first->last_station_visited; // for PreDestructor } /* 'v' shouldn't be accessed after it has been deleted */ TrackBits trackbits = v->track; TileIndex tile = v->tile; Owner owner = v->owner; delete v; v = NULL; // make sure nobody will try to read 'v' anymore if (trackbits == TRACK_BIT_WORMHOLE) { /* Vehicle is inside a wormhole, v->track contains no useful value then. */ trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(tile)); } Track track = TrackBitsToTrack(trackbits); if (HasReservedTracks(tile, trackbits)) { UnreserveRailTrack(tile, track); /* If there are still crashed vehicles on the tile, give the track reservation to them */ TrackBits remaining_trackbits = TRACK_BIT_NONE; FindVehicleOnPos(tile, &remaining_trackbits, CollectTrackbitsFromCrashedVehiclesEnum); /* It is important that these two are the first in the loop, as reservation cannot deal with every trackbit combination */ assert(TRACK_BEGIN == TRACK_X && TRACK_Y == TRACK_BEGIN + 1); Track t; FOR_EACH_SET_TRACK(t, remaining_trackbits) TryReserveRailTrack(tile, t); } /* check if the wagon was on a road/rail-crossing */ if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile); /* Update signals */ if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) { UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner); } else { SetSignalsOnBothDir(tile, track, owner); } } /** * Rotate all vehicles of a (crashed) train chain randomly to animate the crash. * @param v First crashed vehicle. */ static void ChangeTrainDirRandomly(Train *v) { static const DirDiff delta[] = { DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT }; do { /* We don't need to twist around vehicles if they're not visible */ if (!(v->vehstatus & VS_HIDDEN)) { v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]); v->UpdateDeltaXY(v->direction); v->cur_image = v->GetImage(v->direction, EIT_ON_MAP); /* Refrain from updating the z position of the vehicle when on * a bridge, because UpdateInclination() will put the vehicle under * the bridge in that case */ if (v->track != TRACK_BIT_WORMHOLE) { v->UpdatePosition(); v->UpdateInclination(false, false); } } } while ((v = v->Next()) != NULL); } /** * Handle a crashed train. * @param v First train vehicle. * @return %Vehicle chain still exists. */ static bool HandleCrashedTrain(Train *v) { int state = ++v->crash_anim_pos; if (state == 4 && !(v->vehstatus & VS_HIDDEN)) { CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); } uint32 r; if (state <= 200 && Chance16R(1, 7, r)) { int index = (r * 10 >> 16); Vehicle *u = v; do { if (--index < 0) { r = Random(); CreateEffectVehicleRel(u, GB(r, 8, 3) + 2, GB(r, 16, 3) + 2, GB(r, 0, 3) + 5, EV_EXPLOSION_SMALL); break; } } while ((u = u->Next()) != NULL); } if (state <= 240 && !(v->tick_counter & 3)) ChangeTrainDirRandomly(v); if (state >= 4440 && !(v->tick_counter & 0x1F)) { bool ret = v->Next() != NULL; DeleteLastWagon(v); return ret; } return true; } /** Maximum speeds for train that is broken down or approaching line end */ static const uint16 _breakdown_speeds[16] = { 225, 210, 195, 180, 165, 150, 135, 120, 105, 90, 75, 60, 45, 30, 15, 15 }; /** * Train is approaching line end, slow down and possibly reverse * * @param v front train engine * @param signal not line end, just a red signal * @param reverse Set to false to not execute the vehicle reversing. This does not change any other logic. * @return true iff we did NOT have to reverse */ static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse) { /* Calc position within the current tile */ uint x = v->x_pos & 0xF; uint y = v->y_pos & 0xF; /* for diagonal directions, 'x' will be 0..15 - * for other directions, it will be 1, 3, 5, ..., 15 */ switch (v->direction) { case DIR_N : x = ~x + ~y + 25; break; case DIR_NW: x = y; // FALL THROUGH case DIR_NE: x = ~x + 16; break; case DIR_E : x = ~x + y + 9; break; case DIR_SE: x = y; break; case DIR_S : x = x + y - 7; break; case DIR_W : x = ~y + x + 9; break; default: break; } /* Do not reverse when approaching red signal. Make sure the vehicle's front * does not cross the tile boundary when we do reverse, but as the vehicle's * location is based on their center, use half a vehicle's length as offset. * Multiply the half-length by two for straight directions to compensate that * we only get odd x offsets there. */ if (!signal && x + (v->gcache.cached_veh_length + 1) / 2 * (IsDiagonalDirection(v->direction) ? 1 : 2) >= TILE_SIZE) { /* we are too near the tile end, reverse now */ v->cur_speed = 0; if (reverse) ReverseTrainDirection(v); return false; } /* slow down */ v->vehstatus |= VS_TRAIN_SLOWING; uint16 break_speed = _breakdown_speeds[x & 0xF]; if (break_speed < v->cur_speed) v->cur_speed = break_speed; return true; } /** * Determines whether train would like to leave the tile * @param v train to test * @return true iff vehicle is NOT entering or inside a depot or tunnel/bridge */ static bool TrainCanLeaveTile(const Train *v) { /* Exit if inside a tunnel/bridge or a depot */ if (v->track == TRACK_BIT_WORMHOLE || v->track == TRACK_BIT_DEPOT) return false; TileIndex tile = v->tile; /* entering a tunnel/bridge? */ if (IsTileType(tile, MP_TUNNELBRIDGE)) { DiagDirection dir = GetTunnelBridgeDirection(tile); if (DiagDirToDir(dir) == v->direction) return false; } /* entering a depot? */ if (IsRailDepotTile(tile)) { DiagDirection dir = ReverseDiagDir(GetRailDepotDirection(tile)); if (DiagDirToDir(dir) == v->direction) return false; } return true; } /** * Determines whether train is approaching a rail-road crossing * (thus making it barred) * @param v front engine of train * @return TileIndex of crossing the train is approaching, else INVALID_TILE * @pre v in non-crashed front engine */ static TileIndex TrainApproachingCrossingTile(const Train *v) { assert(v->IsFrontEngine()); assert(!(v->vehstatus & VS_CRASHED)); if (!TrainCanLeaveTile(v)) return INVALID_TILE; DiagDirection dir = TrainExitDir(v->direction, v->track); TileIndex tile = v->tile + TileOffsByDiagDir(dir); /* not a crossing || wrong axis || unusable rail (wrong type or owner) */ if (!IsLevelCrossingTile(tile) || DiagDirToAxis(dir) == GetCrossingRoadAxis(tile) || !CheckCompatibleRail(v, tile)) { return INVALID_TILE; } return tile; } /** * Checks for line end. Also, bars crossing at next tile if needed * * @param v vehicle we are checking * @param reverse Set to false to not execute the vehicle reversing. This does not change any other logic. * @return true iff we did NOT have to reverse */ static bool TrainCheckIfLineEnds(Train *v, bool reverse) { /* First, handle broken down train */ int t = v->breakdown_ctr; if (t > 1) { v->vehstatus |= VS_TRAIN_SLOWING; uint16 break_speed = _breakdown_speeds[GB(~t, 4, 4)]; if (break_speed < v->cur_speed) v->cur_speed = break_speed; } else { v->vehstatus &= ~VS_TRAIN_SLOWING; } if (!TrainCanLeaveTile(v)) return true; /* Determine the non-diagonal direction in which we will exit this tile */ DiagDirection dir = TrainExitDir(v->direction, v->track); /* Calculate next tile */ TileIndex tile = v->tile + TileOffsByDiagDir(dir); /* Determine the track status on the next tile */ TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0, ReverseDiagDir(dir)); TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(dir); TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs; TrackdirBits red_signals = TrackStatusToRedSignals(ts) & reachable_trackdirs; /* We are sure the train is not entering a depot, it is detected above */ /* mask unreachable track bits if we are forbidden to do 90deg turns */ TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); if (_settings_game.pf.forbid_90_deg) { bits &= ~TrackCrossesTracks(FindFirstTrack(v->track)); } /* no suitable trackbits at all || unusable rail (wrong type or owner) */ if (bits == TRACK_BIT_NONE || !CheckCompatibleRail(v, tile)) { return TrainApproachingLineEnd(v, false, reverse); } /* approaching red signal */ if ((trackdirbits & red_signals) != 0) return TrainApproachingLineEnd(v, true, reverse); /* approaching a rail/road crossing? then make it red */ if (IsLevelCrossingTile(tile)) MaybeBarCrossingWithSound(tile); return true; } static bool TrainLocoHandler(Train *v, bool mode) { /* train has crashed? */ if (v->vehstatus & VS_CRASHED) { return mode ? true : HandleCrashedTrain(v); // 'this' can be deleted here } if (v->force_proceed != TFP_NONE) { ClrBit(v->flags, VRF_TRAIN_STUCK); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } /* train is broken down? */ if (v->HandleBreakdown()) return true; if (HasBit(v->flags, VRF_REVERSING) && v->cur_speed == 0) { ReverseTrainDirection(v); } /* exit if train is stopped */ if ((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) return true; bool valid_order = !v->current_order.IsType(OT_NOTHING) && v->current_order.GetType() != OT_CONDITIONAL; if (ProcessOrders(v) && CheckReverseTrain(v)) { v->wait_counter = 0; v->cur_speed = 0; v->subspeed = 0; ClrBit(v->flags, VRF_LEAVING_STATION); ReverseTrainDirection(v); return true; } else if (HasBit(v->flags, VRF_LEAVING_STATION)) { /* Try to reserve a path when leaving the station as we * might not be marked as wanting a reservation, e.g. * when an overlength train gets turned around in a station. */ DiagDirection dir = TrainExitDir(v->direction, v->track); if (IsRailDepotTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE)) dir = INVALID_DIAGDIR; if (UpdateSignalsOnSegment(v->tile, dir, v->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) { TryPathReserve(v, true, true); } ClrBit(v->flags, VRF_LEAVING_STATION); } v->HandleLoading(mode); if (v->current_order.IsType(OT_LOADING)) return true; if (CheckTrainStayInDepot(v)) return true; if (!mode) v->ShowVisualEffect(); /* We had no order but have an order now, do look ahead. */ if (!valid_order && !v->current_order.IsType(OT_NOTHING)) { CheckNextTrainTile(v); } /* Handle stuck trains. */ if (!mode && HasBit(v->flags, VRF_TRAIN_STUCK)) { ++v->wait_counter; /* Should we try reversing this tick if still stuck? */ bool turn_around = v->wait_counter % (_settings_game.pf.wait_for_pbs_path * DAY_TICKS) == 0 && _settings_game.pf.reverse_at_signals; if (!turn_around && v->wait_counter % _settings_game.pf.path_backoff_interval != 0 && v->force_proceed == TFP_NONE) return true; if (!TryPathReserve(v)) { /* Still stuck. */ if (turn_around) ReverseTrainDirection(v); if (HasBit(v->flags, VRF_TRAIN_STUCK) && v->wait_counter > 2 * _settings_game.pf.wait_for_pbs_path * DAY_TICKS) { /* Show message to player. */ if (_settings_client.gui.lost_vehicle_warn && v->owner == _local_company) { SetDParam(0, v->index); AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_STUCK, v->index); } v->wait_counter = 0; } /* Exit if force proceed not pressed, else reset stuck flag anyway. */ if (v->force_proceed == TFP_NONE) return true; ClrBit(v->flags, VRF_TRAIN_STUCK); v->wait_counter = 0; SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } } if (v->current_order.IsType(OT_LEAVESTATION)) { v->current_order.Free(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); return true; } int j = v->UpdateSpeed(); /* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */ if (v->cur_speed == 0 && (v->vehstatus & VS_STOPPED)) { /* If we manually stopped, we're not force-proceeding anymore. */ v->force_proceed = TFP_NONE; SetWindowDirty(WC_VEHICLE_VIEW, v->index); } int adv_spd = v->GetAdvanceDistance(); if (j < adv_spd) { /* if the vehicle has speed 0, update the last_speed field. */ if (v->cur_speed == 0) v->SetLastSpeed(); } else { TrainCheckIfLineEnds(v); /* Loop until the train has finished moving. */ for (;;) { j -= adv_spd; TrainController(v, NULL); /* Don't continue to move if the train crashed. */ if (CheckTrainCollision(v)) break; /* Determine distance to next map position */ adv_spd = v->GetAdvanceDistance(); /* No more moving this tick */ if (j < adv_spd || v->cur_speed == 0) break; OrderType order_type = v->current_order.GetType(); /* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */ if ((order_type == OT_GOTO_WAYPOINT || order_type == OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) && IsTileType(v->tile, MP_STATION) && v->current_order.GetDestination() == GetStationIndex(v->tile)) { ProcessOrders(v); } } v->SetLastSpeed(); } for (Train *u = v; u != NULL; u = u->Next()) { if ((u->vehstatus & VS_HIDDEN) != 0) continue; u->UpdateViewport(false, false); } if (v->progress == 0) v->progress = j; // Save unused spd for next time, if TrainController didn't set progress return true; } /** * Get running cost for the train consist. * @return Yearly running costs. */ Money Train::GetRunningCost() const { Money cost = 0; const Train *v = this; do { const Engine *e = v->GetEngine(); if (e->u.rail.running_cost_class == INVALID_PRICE) continue; uint cost_factor = GetVehicleProperty(v, PROP_TRAIN_RUNNING_COST_FACTOR, e->u.rail.running_cost); if (cost_factor == 0) continue; /* Halve running cost for multiheaded parts */ if (v->IsMultiheaded()) cost_factor /= 2; cost += GetPrice(e->u.rail.running_cost_class, cost_factor, e->GetGRF()); } while ((v = v->GetNextVehicle()) != NULL); return cost; } /** * Update train vehicle data for a tick. * @return True if the vehicle still exists, false if it has ceased to exist (front of consists only). */ bool Train::Tick() { this->tick_counter++; if (this->IsFrontEngine()) { if (!(this->vehstatus & VS_STOPPED) || this->cur_speed > 0) this->running_ticks++; this->current_order_time++; if (!TrainLocoHandler(this, false)) return false; return TrainLocoHandler(this, true); } else if (this->IsFreeWagon() && (this->vehstatus & VS_CRASHED)) { /* Delete flooded standalone wagon chain */ if (++this->crash_anim_pos >= 4400) { delete this; return false; } } return true; } /** * Check whether a train needs service, and if so, find a depot or service it. * @return v %Train to check. */ static void CheckIfTrainNeedsService(Train *v) { if (Company::Get(v->owner)->settings.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return; if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } uint max_penalty; switch (_settings_game.pf.pathfinder_for_trains) { case VPF_NPF: max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty; break; case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break; default: NOT_REACHED(); } FindDepotData tfdd = FindClosestTrainDepot(v, max_penalty); /* Only go to the depot if it is not too far out of our way. */ if (tfdd.best_length == UINT_MAX || tfdd.best_length > max_penalty) { if (v->current_order.IsType(OT_GOTO_DEPOT)) { /* If we were already heading for a depot but it has * suddenly moved farther away, we continue our normal * schedule? */ v->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } return; } DepotID depot = GetDepotIndex(tfdd.tile); if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetDestination() != depot && !Chance16(3, 16)) { return; } SetBit(v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE); v->dest_tile = tfdd.tile; SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } /** Update day counters of the train vehicle. */ void Train::OnNewDay() { AgeVehicle(this); if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this); if (this->IsFrontEngine()) { CheckVehicleBreakdown(this); CheckIfTrainNeedsService(this); CheckOrders(this); /* update destination */ if (this->current_order.IsType(OT_GOTO_STATION)) { TileIndex tile = Station::Get(this->current_order.GetDestination())->train_station.tile; if (tile != INVALID_TILE) this->dest_tile = tile; } if (this->running_ticks != 0) { /* running costs */ CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS)); this->profit_this_year -= cost.GetCost(); this->running_ticks = 0; SubtractMoneyFromCompanyFract(this->owner, cost); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); SetWindowClassesDirty(WC_TRAINS_LIST); } } } /** * Get the tracks of the train vehicle. * @return Current tracks of the vehicle. */ Trackdir Train::GetVehicleTrackdir() const { if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR; if (this->track == TRACK_BIT_DEPOT) { /* We'll assume the train is facing outwards */ return DiagDirToDiagTrackdir(GetRailDepotDirection(this->tile)); // Train in depot } if (this->track == TRACK_BIT_WORMHOLE) { /* train in tunnel or on bridge, so just use his direction and assume a diagonal track */ return DiagDirToDiagTrackdir(DirToDiagDir(this->direction)); } return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction); } openttd-1.5.3/src/3rdparty/0000755000000000000000000000000012627373445014247 5ustar rootrootopenttd-1.5.3/src/3rdparty/md5/0000755000000000000000000000000012627373445014734 5ustar rootrootopenttd-1.5.3/src/3rdparty/md5/md5.h0000644000000000000000000000505312627373445015575 0ustar rootroot/* $Id: md5.h 17883 2009-10-26 23:03:03Z smatz $ */ /** @file md5.h Functions to create MD5 checksums. */ /* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2007-12-24 Changed to C++ and adapted to OpenTTD source 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef MD5_INCLUDED #define MD5_INCLUDED struct Md5 { private: uint32 count[2]; ///< message length in bits, lsw first uint32 abcd[4]; ///< digest buffer uint8 buf[64]; ///< accumulate block void Process(const uint8 *data); public: Md5(); void Append(const void *data, const size_t nbytes); void Finish(uint8 digest[16]); }; #endif /* MD5_INCLUDED */ openttd-1.5.3/src/3rdparty/md5/md5.cpp0000644000000000000000000002604512627373445016134 0ustar rootroot/* $Id: md5.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /** @file md5.cpp Creating MD5 checksums of files. */ /* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2007-12-24 Changed to C++ and adapted to OpenTTD source 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "../../stdafx.h" #include "../../core/endian_func.hpp" #include "md5.h" #include "../../safeguards.h" #define T_MASK ((uint32)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static inline void Md5Set1(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) { uint32 t = (*b & *c) | (~*b & *d); t += *a + X[k] + Ti; *a = ROL(t, s) + *b; } static inline void Md5Set2(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) { uint32 t = (*b & *d) | (*c & ~*d); t += *a + X[k] + Ti; *a = ROL(t, s) + *b; } static inline void Md5Set3(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) { uint32 t = *b ^ *c ^ *d; t += *a + X[k] + Ti; *a = ROL(t, s) + *b; } static inline void Md5Set4(const uint32 *X, uint32 *a, const uint32 *b, const uint32 *c, const uint32 *d, const uint8 k, const uint8 s, const uint32 Ti) { uint32 t = *c ^ (*b | ~*d); t += *a + X[k] + Ti; *a = ROL(t, s) + *b; } Md5::Md5() { count[0] = 0; count[1] = 0; abcd[0] = 0x67452301; abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; abcd[3] = 0x10325476; } void Md5::Process(const uint8 *data /*[64]*/) { uint32 a = this->abcd[0]; uint32 b = this->abcd[1]; uint32 c = this->abcd[2]; uint32 d = this->abcd[3]; uint32 X[16]; /* Convert the uint8 data to uint32 LE */ const uint32 *px = (const uint32 *)data; for (uint i = 0; i < 16; i++) { X[i] = TO_LE32(*px); px++; } /* Round 1. */ Md5Set1(X, &a, &b, &c, &d, 0, 7, T1); Md5Set1(X, &d, &a, &b, &c, 1, 12, T2); Md5Set1(X, &c, &d, &a, &b, 2, 17, T3); Md5Set1(X, &b, &c, &d, &a, 3, 22, T4); Md5Set1(X, &a, &b, &c, &d, 4, 7, T5); Md5Set1(X, &d, &a, &b, &c, 5, 12, T6); Md5Set1(X, &c, &d, &a, &b, 6, 17, T7); Md5Set1(X, &b, &c, &d, &a, 7, 22, T8); Md5Set1(X, &a, &b, &c, &d, 8, 7, T9); Md5Set1(X, &d, &a, &b, &c, 9, 12, T10); Md5Set1(X, &c, &d, &a, &b, 10, 17, T11); Md5Set1(X, &b, &c, &d, &a, 11, 22, T12); Md5Set1(X, &a, &b, &c, &d, 12, 7, T13); Md5Set1(X, &d, &a, &b, &c, 13, 12, T14); Md5Set1(X, &c, &d, &a, &b, 14, 17, T15); Md5Set1(X, &b, &c, &d, &a, 15, 22, T16); /* Round 2. */ Md5Set2(X, &a, &b, &c, &d, 1, 5, T17); Md5Set2(X, &d, &a, &b, &c, 6, 9, T18); Md5Set2(X, &c, &d, &a, &b, 11, 14, T19); Md5Set2(X, &b, &c, &d, &a, 0, 20, T20); Md5Set2(X, &a, &b, &c, &d, 5, 5, T21); Md5Set2(X, &d, &a, &b, &c, 10, 9, T22); Md5Set2(X, &c, &d, &a, &b, 15, 14, T23); Md5Set2(X, &b, &c, &d, &a, 4, 20, T24); Md5Set2(X, &a, &b, &c, &d, 9, 5, T25); Md5Set2(X, &d, &a, &b, &c, 14, 9, T26); Md5Set2(X, &c, &d, &a, &b, 3, 14, T27); Md5Set2(X, &b, &c, &d, &a, 8, 20, T28); Md5Set2(X, &a, &b, &c, &d, 13, 5, T29); Md5Set2(X, &d, &a, &b, &c, 2, 9, T30); Md5Set2(X, &c, &d, &a, &b, 7, 14, T31); Md5Set2(X, &b, &c, &d, &a, 12, 20, T32); /* Round 3. */ Md5Set3(X, &a, &b, &c, &d, 5, 4, T33); Md5Set3(X, &d, &a, &b, &c, 8, 11, T34); Md5Set3(X, &c, &d, &a, &b, 11, 16, T35); Md5Set3(X, &b, &c, &d, &a, 14, 23, T36); Md5Set3(X, &a, &b, &c, &d, 1, 4, T37); Md5Set3(X, &d, &a, &b, &c, 4, 11, T38); Md5Set3(X, &c, &d, &a, &b, 7, 16, T39); Md5Set3(X, &b, &c, &d, &a, 10, 23, T40); Md5Set3(X, &a, &b, &c, &d, 13, 4, T41); Md5Set3(X, &d, &a, &b, &c, 0, 11, T42); Md5Set3(X, &c, &d, &a, &b, 3, 16, T43); Md5Set3(X, &b, &c, &d, &a, 6, 23, T44); Md5Set3(X, &a, &b, &c, &d, 9, 4, T45); Md5Set3(X, &d, &a, &b, &c, 12, 11, T46); Md5Set3(X, &c, &d, &a, &b, 15, 16, T47); Md5Set3(X, &b, &c, &d, &a, 2, 23, T48); /* Round 4. */ Md5Set4(X, &a, &b, &c, &d, 0, 6, T49); Md5Set4(X, &d, &a, &b, &c, 7, 10, T50); Md5Set4(X, &c, &d, &a, &b, 14, 15, T51); Md5Set4(X, &b, &c, &d, &a, 5, 21, T52); Md5Set4(X, &a, &b, &c, &d, 12, 6, T53); Md5Set4(X, &d, &a, &b, &c, 3, 10, T54); Md5Set4(X, &c, &d, &a, &b, 10, 15, T55); Md5Set4(X, &b, &c, &d, &a, 1, 21, T56); Md5Set4(X, &a, &b, &c, &d, 8, 6, T57); Md5Set4(X, &d, &a, &b, &c, 15, 10, T58); Md5Set4(X, &c, &d, &a, &b, 6, 15, T59); Md5Set4(X, &b, &c, &d, &a, 13, 21, T60); Md5Set4(X, &a, &b, &c, &d, 4, 6, T61); Md5Set4(X, &d, &a, &b, &c, 11, 10, T62); Md5Set4(X, &c, &d, &a, &b, 2, 15, T63); Md5Set4(X, &b, &c, &d, &a, 9, 21, T64); /* Then perform the following additions. (That is increment each * of the four registers by the value it had before this block * was started.) */ this->abcd[0] += a; this->abcd[1] += b; this->abcd[2] += c; this->abcd[3] += d; } void Md5::Append(const void *data, const size_t nbytes) { const uint8 *p = (const uint8 *)data; size_t left = nbytes; const size_t offset = (this->count[0] >> 3) & 63; const uint32 nbits = (uint32)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ this->count[1] += (uint32)(nbytes >> 29); this->count[0] += nbits; if (this->count[0] < nbits) this->count[1]++; /* Process an initial partial block. */ if (offset) { size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(this->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; this->Process(this->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) this->Process(p); /* Process a final partial block. */ if (left) memcpy(this->buf, p, left); } void Md5::Finish(uint8 digest[16]) { static const uint8 pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; uint8 data[8]; /* Save the length before padding. */ for (uint i = 0; i < 8; ++i) { data[i] = (uint8)(this->count[i >> 2] >> ((i & 3) << 3)); } /* Pad to 56 bytes mod 64. */ this->Append(pad, ((55 - (this->count[0] >> 3)) & 63) + 1); /* Append the length. */ this->Append(data, 8); for (uint i = 0; i < 16; ++i) { digest[i] = (uint8)(this->abcd[i >> 2] >> ((i & 3) << 3)); } } openttd-1.5.3/src/3rdparty/squirrel/0000755000000000000000000000000012627373445016115 5ustar rootrootopenttd-1.5.3/src/3rdparty/squirrel/squirrel/0000755000000000000000000000000012627373445017763 5ustar rootrootopenttd-1.5.3/src/3rdparty/squirrel/squirrel/squserdata.h0000644000000000000000000000164712627373445022320 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQUSERDATA_H_ #define _SQUSERDATA_H_ struct SQUserData : SQDelegable { SQUserData(SQSharedState *ss, SQInteger size){ _delegate = 0; _hook = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_ss(this)->_gc_chain, this); _size = size; _typetag = 0; } ~SQUserData() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain, this); SetDelegate(NULL); } static SQUserData* Create(SQSharedState *ss, SQInteger size) { SQUserData* ud = (SQUserData*)SQ_MALLOC(sizeof(SQUserData)+(size-1)); new (ud) SQUserData(ss, size); return ud; } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){SetDelegate(NULL);} #endif void Release() { if (_hook) _hook(_val,_size); SQInteger tsize = _size - 1; this->~SQUserData(); SQ_FREE(this, sizeof(SQUserData) + tsize); } SQInteger _size; SQRELEASEHOOK _hook; SQUserPointer _typetag; SQChar _val[1]; }; #endif //_SQUSERDATA_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqobject.h0000644000000000000000000002131712627373445021752 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQOBJECT_H_ #define _SQOBJECT_H_ #include "squtils.h" #define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) #define SQ_CLOSURESTREAM_PART (('P'<<24)|('A'<<16)|('R'<<8)|('T')) #define SQ_CLOSURESTREAM_TAIL (('T'<<24)|('A'<<16)|('I'<<8)|('L')) struct SQSharedState; enum SQMetaMethod{ MT_ADD=0, MT_SUB=1, MT_MUL=2, MT_DIV=3, MT_UNM=4, MT_MODULO=5, MT_SET=6, MT_GET=7, MT_TYPEOF=8, MT_NEXTI=9, MT_CMP=10, MT_CALL=11, MT_CLONED=12, MT_NEWSLOT=13, MT_DELSLOT=14, MT_TOSTRING=15, MT_NEWMEMBER=16, MT_INHERITED=17, MT_LAST = 18 }; #define MM_ADD "_add" #define MM_SUB "_sub" #define MM_MUL "_mul" #define MM_DIV "_div" #define MM_UNM "_unm" #define MM_MODULO "_modulo" #define MM_SET "_set" #define MM_GET "_get" #define MM_TYPEOF "_typeof" #define MM_NEXTI "_nexti" #define MM_CMP "_cmp" #define MM_CALL "_call" #define MM_CLONED "_cloned" #define MM_NEWSLOT "_newslot" #define MM_DELSLOT "_delslot" #define MM_TOSTRING "_tostring" #define MM_NEWMEMBER "_newmember" #define MM_INHERITED "_inherited" #define MINPOWER2 4 struct SQRefCounted { SQRefCounted() { _uiRef = 0; _weakref = NULL; } virtual ~SQRefCounted(); SQWeakRef *GetWeakRef(SQObjectType type); SQUnsignedInteger _uiRef; struct SQWeakRef *_weakref; virtual void Release()=0; }; struct SQWeakRef : SQRefCounted { void Release(); SQObject _obj; }; #define _realval(o) (type((o)) != OT_WEAKREF?(SQObject)o:_weakref(o)->_obj) struct SQObjectPtr; #define __AddRef(type,unval) if(ISREFCOUNTED(type)) \ { \ unval.pRefCounted->_uiRef++; \ } #define __Release(type,unval) if(ISREFCOUNTED(type) && ((--unval.pRefCounted->_uiRef)<=0)) \ { \ unval.pRefCounted->Release(); \ } #define __ObjRelease(obj) { \ if((obj)) { \ (obj)->_uiRef--; \ if((obj)->_uiRef == 0) \ (obj)->Release(); \ (obj) = NULL; \ } \ } #define __ObjAddRef(obj) { \ (obj)->_uiRef++; \ } #define type(obj) ((obj)._type) #define is_delegable(t) (type(t)&SQOBJECT_DELEGABLE) #define raw_type(obj) _RAW_TYPE((obj)._type) #define _integer(obj) ((obj)._unVal.nInteger) #define _float(obj) ((obj)._unVal.fFloat) #define _string(obj) ((obj)._unVal.pString) #define _table(obj) ((obj)._unVal.pTable) #define _array(obj) ((obj)._unVal.pArray) #define _closure(obj) ((obj)._unVal.pClosure) #define _generator(obj) ((obj)._unVal.pGenerator) #define _nativeclosure(obj) ((obj)._unVal.pNativeClosure) #define _userdata(obj) ((obj)._unVal.pUserData) #define _userpointer(obj) ((obj)._unVal.pUserPointer) #define _thread(obj) ((obj)._unVal.pThread) #define _funcproto(obj) ((obj)._unVal.pFunctionProto) #define _class(obj) ((obj)._unVal.pClass) #define _instance(obj) ((obj)._unVal.pInstance) #define _delegable(obj) ((SQDelegable *)(obj)._unVal.pDelegable) #define _weakref(obj) ((obj)._unVal.pWeakRef) #define _refcounted(obj) ((obj)._unVal.pRefCounted) #define _rawval(obj) ((obj)._unVal.raw) #define _stringval(obj) (obj)._unVal.pString->_val #define _userdataval(obj) (obj)._unVal.pUserData->_val #define tofloat(num) ((type(num)==OT_INTEGER)?(SQFloat)_integer(num):_float(num)) #define tointeger(num) ( (type(num)==OT_FLOAT)?(SQInteger)_float(num):_integer(num)) ///////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// struct SQObjectPtr : public SQObject { SQObjectPtr() { SQ_OBJECT_RAWINIT() _type=OT_NULL; _unVal.pUserPointer=NULL; } SQObjectPtr(const SQObjectPtr &o) { SQ_OBJECT_RAWINIT() _type=o._type; _unVal=o._unVal; __AddRef(_type,_unVal); } SQObjectPtr(const SQObject &o) { SQ_OBJECT_RAWINIT() _type=o._type; _unVal=o._unVal; __AddRef(_type,_unVal); } SQObjectPtr(SQTable *pTable) { SQ_OBJECT_RAWINIT() _type=OT_TABLE; _unVal.pTable=pTable; assert(_unVal.pTable); __AddRef(_type,_unVal); } SQObjectPtr(SQClass *pClass) { SQ_OBJECT_RAWINIT() _type=OT_CLASS; _unVal.pClass=pClass; assert(_unVal.pClass); __AddRef(_type,_unVal); } SQObjectPtr(SQInstance *pInstance) { SQ_OBJECT_RAWINIT() _type=OT_INSTANCE; _unVal.pInstance=pInstance; assert(_unVal.pInstance); __AddRef(_type,_unVal); } SQObjectPtr(SQArray *pArray) { SQ_OBJECT_RAWINIT() _type=OT_ARRAY; _unVal.pArray=pArray; assert(_unVal.pArray); __AddRef(_type,_unVal); } SQObjectPtr(SQClosure *pClosure) { SQ_OBJECT_RAWINIT() _type=OT_CLOSURE; _unVal.pClosure=pClosure; assert(_unVal.pClosure); __AddRef(_type,_unVal); } SQObjectPtr(SQGenerator *pGenerator) { SQ_OBJECT_RAWINIT() _type=OT_GENERATOR; _unVal.pGenerator=pGenerator; assert(_unVal.pGenerator); __AddRef(_type,_unVal); } SQObjectPtr(SQNativeClosure *pNativeClosure) { SQ_OBJECT_RAWINIT() _type=OT_NATIVECLOSURE; _unVal.pNativeClosure=pNativeClosure; assert(_unVal.pNativeClosure); __AddRef(_type,_unVal); } SQObjectPtr(SQString *pString) { SQ_OBJECT_RAWINIT() _type=OT_STRING; _unVal.pString=pString; assert(_unVal.pString); __AddRef(_type,_unVal); } SQObjectPtr(SQUserData *pUserData) { SQ_OBJECT_RAWINIT() _type=OT_USERDATA; _unVal.pUserData=pUserData; assert(_unVal.pUserData); __AddRef(_type,_unVal); } SQObjectPtr(SQVM *pThread) { SQ_OBJECT_RAWINIT() _type=OT_THREAD; _unVal.pThread=pThread; assert(_unVal.pThread); __AddRef(_type,_unVal); } SQObjectPtr(SQWeakRef *pWeakRef) { SQ_OBJECT_RAWINIT() _type=OT_WEAKREF; _unVal.pWeakRef=pWeakRef; assert(_unVal.pWeakRef); __AddRef(_type,_unVal); } SQObjectPtr(SQFunctionProto *pFunctionProto) { SQ_OBJECT_RAWINIT() _type=OT_FUNCPROTO; _unVal.pFunctionProto=pFunctionProto; assert(_unVal.pFunctionProto); __AddRef(_type,_unVal); } SQObjectPtr(SQInteger nInteger) { SQ_OBJECT_RAWINIT() _type=OT_INTEGER; _unVal.nInteger=nInteger; } SQObjectPtr(SQFloat fFloat) { SQ_OBJECT_RAWINIT() _type=OT_FLOAT; _unVal.fFloat=fFloat; } SQObjectPtr(bool bBool) { SQ_OBJECT_RAWINIT() _type = OT_BOOL; _unVal.nInteger = bBool?1:0; } SQObjectPtr(SQUserPointer pUserPointer) { SQ_OBJECT_RAWINIT() _type=OT_USERPOINTER; _unVal.pUserPointer=pUserPointer; } ~SQObjectPtr() { __Release(_type,_unVal); } inline void Null() { SQObjectType tOldType; SQObjectValue unOldVal; tOldType = _type; unOldVal = _unVal; _type = OT_NULL; _unVal.pUserPointer = NULL; __Release(tOldType,unOldVal); } inline SQObjectPtr& operator=(SQInteger i) { __Release(_type,_unVal); SQ_OBJECT_RAWINIT() _unVal.nInteger = i; _type = OT_INTEGER; return *this; } inline SQObjectPtr& operator=(SQFloat f) { __Release(_type,_unVal); SQ_OBJECT_RAWINIT() _unVal.fFloat = f; _type = OT_FLOAT; return *this; } inline SQObjectPtr& operator=(const SQObjectPtr& obj) { SQObjectType tOldType; SQObjectValue unOldVal; tOldType=_type; unOldVal=_unVal; _unVal = obj._unVal; _type = obj._type; __AddRef(_type,_unVal); __Release(tOldType,unOldVal); return *this; } inline SQObjectPtr& operator=(const SQObject& obj) { SQObjectType tOldType; SQObjectValue unOldVal; tOldType=_type; unOldVal=_unVal; _unVal = obj._unVal; _type = obj._type; __AddRef(_type,_unVal); __Release(tOldType,unOldVal); return *this; } private: SQObjectPtr(const SQChar *){} //safety }; inline void _Swap(SQObject &a,SQObject &b) { SQObjectType tOldType = a._type; SQObjectValue unOldVal = a._unVal; a._type = b._type; a._unVal = b._unVal; b._type = tOldType; b._unVal = unOldVal; } ///////////////////////////////////////////////////////////////////////////////////// #ifndef NO_GARBAGE_COLLECTOR #define MARK_FLAG 0x80000000 struct SQCollectable : public SQRefCounted { SQCollectable *_next; SQCollectable *_prev; SQSharedState *_sharedstate; virtual void Release()=0; virtual void Mark(SQCollectable **chain)=0; void UnMark(); virtual void Finalize()=0; static void AddToChain(SQCollectable **chain,SQCollectable *c); static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); }; #define ADD_TO_CHAIN(chain,obj) AddToChain(chain,obj) #define REMOVE_FROM_CHAIN(chain,obj) {if(!(_uiRef&MARK_FLAG))RemoveFromChain(chain,obj);} #define CHAINABLE_OBJ SQCollectable #define INIT_CHAIN() {_next=NULL;_prev=NULL;_sharedstate=ss;} #else #define ADD_TO_CHAIN(chain,obj) ((void)0) #define REMOVE_FROM_CHAIN(chain,obj) ((void)0) #define CHAINABLE_OBJ SQRefCounted #define INIT_CHAIN() ((void)0) #endif struct SQDelegable : public CHAINABLE_OBJ { bool SetDelegate(SQTable *m); virtual bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); SQTable *_delegate; }; SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx); typedef sqvector SQObjectPtrVec; typedef sqvector SQIntVec; const SQChar *GetTypeName(const SQObjectPtr &obj1); const SQChar *IdType2Name(SQObjectType type); #endif //_SQOBJECT_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqopcodes.h0000644000000000000000000000433612627373445022142 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQOPCODES_H_ #define _SQOPCODES_H_ #define MAX_FUNC_STACKSIZE 0xFF #define MAX_LITERALS ((SQInteger)0x7FFFFFFF) enum BitWiseOP { BW_AND = 0, BW_OR = 2, BW_XOR = 3, BW_SHIFTL = 4, BW_SHIFTR = 5, BW_USHIFTR = 6 }; enum CmpOP { CMP_G = 0, CMP_GE = 2, CMP_L = 3, CMP_LE = 4 }; enum SQOpcode { _OP_LINE= 0x00, _OP_LOAD= 0x01, _OP_LOADINT= 0x02, _OP_LOADFLOAT= 0x03, _OP_DLOAD= 0x04, _OP_TAILCALL= 0x05, _OP_CALL= 0x06, _OP_PREPCALL= 0x07, _OP_PREPCALLK= 0x08, _OP_GETK= 0x09, _OP_MOVE= 0x0A, _OP_NEWSLOT= 0x0B, _OP_DELETE= 0x0C, _OP_SET= 0x0D, _OP_GET= 0x0E, _OP_EQ= 0x0F, _OP_NE= 0x10, _OP_ARITH= 0x11, _OP_BITW= 0x12, _OP_RETURN= 0x13, _OP_LOADNULLS= 0x14, _OP_LOADROOTTABLE= 0x15, _OP_LOADBOOL= 0x16, _OP_DMOVE= 0x17, _OP_JMP= 0x18, _OP_JNZ= 0x19, _OP_JZ= 0x1A, _OP_LOADFREEVAR= 0x1B, _OP_VARGC= 0x1C, _OP_GETVARGV= 0x1D, _OP_NEWTABLE= 0x1E, _OP_NEWARRAY= 0x1F, _OP_APPENDARRAY= 0x20, _OP_GETPARENT= 0x21, _OP_COMPARITH= 0x22, _OP_COMPARITHL= 0x23, _OP_INC= 0x24, _OP_INCL= 0x25, _OP_PINC= 0x26, _OP_PINCL= 0x27, _OP_CMP= 0x28, _OP_EXISTS= 0x29, _OP_INSTANCEOF= 0x2A, _OP_AND= 0x2B, _OP_OR= 0x2C, _OP_NEG= 0x2D, _OP_NOT= 0x2E, _OP_BWNOT= 0x2F, _OP_CLOSURE= 0x30, _OP_YIELD= 0x31, _OP_RESUME= 0x32, _OP_FOREACH= 0x33, _OP_POSTFOREACH= 0x34, _OP_DELEGATE= 0x35, _OP_CLONE= 0x36, _OP_TYPEOF= 0x37, _OP_PUSHTRAP= 0x38, _OP_POPTRAP= 0x39, _OP_THROW= 0x3A, _OP_CLASS= 0x3B, _OP_NEWSLOTA= 0x3C, _OP_SCOPE_END= 0x3D, }; struct SQInstructionDesc { const SQChar *name; }; struct SQInstruction { SQInstruction(SQOpcode _op=_OP_SCOPE_END,SQInteger a0=0,SQInteger a1=0,SQInteger a2=0,SQInteger a3=0) { op = _op; _arg0 = (unsigned char)a0;_arg1 = (SQInt32)a1; _arg2 = (unsigned char)a2;_arg3 = (unsigned char)a3; } SQInt32 _arg1; unsigned char op; unsigned char _arg0; unsigned char _arg2; unsigned char _arg3; }; #include "squtils.h" typedef sqvector SQInstructionVec; #define NEW_SLOT_ATTRIBUTES_FLAG 0x01 #define NEW_SLOT_STATIC_FLAG 0x02 #endif // _SQOPCODES_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqstate.cpp0000644000000000000000000003423012627373445022155 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include "sqpcheader.h" #include "sqopcodes.h" #include "sqvm.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "sqstring.h" #include "sqtable.h" #include "sqarray.h" #include "squserdata.h" #include "sqclass.h" #include "../../../safeguards.h" SQObjectPtr _null_; SQObjectPtr _true_(true); SQObjectPtr _false_(false); SQObjectPtr _one_((SQInteger)1); SQObjectPtr _minusone_((SQInteger)-1); #define newsysstring(s) { \ _systemstrings->push_back(SQString::Create(this,s)); \ } #define newmetamethod(s) { \ _metamethods->push_back(SQString::Create(this,s)); \ _table(_metamethodsmap)->NewSlot(_metamethods->back(),(SQInteger)(_metamethods->size()-1)); \ } bool CompileTypemask(SQIntVec &res,const SQChar *typemask) { SQInteger i = 0; SQInteger mask = 0; while(typemask[i] != 0) { switch(typemask[i]){ case 'o': mask |= _RT_NULL; break; case 'i': mask |= _RT_INTEGER; break; case 'f': mask |= _RT_FLOAT; break; case 'n': mask |= (_RT_FLOAT | _RT_INTEGER); break; case 's': mask |= _RT_STRING; break; case 't': mask |= _RT_TABLE; break; case 'a': mask |= _RT_ARRAY; break; case 'u': mask |= _RT_USERDATA; break; case 'c': mask |= (_RT_CLOSURE | _RT_NATIVECLOSURE); break; case 'b': mask |= _RT_BOOL; break; case 'g': mask |= _RT_GENERATOR; break; case 'p': mask |= _RT_USERPOINTER; break; case 'v': mask |= _RT_THREAD; break; case 'x': mask |= _RT_INSTANCE; break; case 'y': mask |= _RT_CLASS; break; case 'r': mask |= _RT_WEAKREF; break; case '.': mask = -1; res.push_back(mask); i++; mask = 0; continue; case ' ': i++; continue; //ignores spaces default: return false; } i++; if(typemask[i] == '|') { i++; if(typemask[i] == 0) return false; continue; } res.push_back(mask); mask = 0; } return true; } SQTable *CreateDefaultDelegate(SQSharedState *ss,SQRegFunction *funcz) { SQInteger i=0; SQTable *t=SQTable::Create(ss,0); while(funcz[i].name!=0){ SQNativeClosure *nc = SQNativeClosure::Create(ss,funcz[i].f); nc->_nparamscheck = funcz[i].nparamscheck; nc->_name = SQString::Create(ss,funcz[i].name); if(funcz[i].typemask && !CompileTypemask(nc->_typecheck,funcz[i].typemask)) return NULL; t->NewSlot(SQString::Create(ss,funcz[i].name),nc); i++; } return t; } SQSharedState::SQSharedState() { _compilererrorhandler = NULL; _printfunc = NULL; _debuginfo = false; _notifyallexceptions = false; _scratchpad=NULL; _scratchpadsize=0; #ifndef NO_GARBAGE_COLLECTOR _gc_chain=NULL; #endif sq_new(_stringtable,SQStringTable); sq_new(_metamethods,SQObjectPtrVec); sq_new(_systemstrings,SQObjectPtrVec); sq_new(_types,SQObjectPtrVec); _metamethodsmap = SQTable::Create(this,MT_LAST-1); //adding type strings to avoid memory trashing //types names newsysstring("null"); newsysstring("table"); newsysstring("array"); newsysstring("closure"); newsysstring("string"); newsysstring("userdata"); newsysstring("integer"); newsysstring("float"); newsysstring("userpointer"); newsysstring("function"); newsysstring("generator"); newsysstring("thread"); newsysstring("class"); newsysstring("instance"); newsysstring("bool"); //meta methods newmetamethod(MM_ADD); newmetamethod(MM_SUB); newmetamethod(MM_MUL); newmetamethod(MM_DIV); newmetamethod(MM_UNM); newmetamethod(MM_MODULO); newmetamethod(MM_SET); newmetamethod(MM_GET); newmetamethod(MM_TYPEOF); newmetamethod(MM_NEXTI); newmetamethod(MM_CMP); newmetamethod(MM_CALL); newmetamethod(MM_CLONED); newmetamethod(MM_NEWSLOT); newmetamethod(MM_DELSLOT); newmetamethod(MM_TOSTRING); newmetamethod(MM_NEWMEMBER); newmetamethod(MM_INHERITED); _constructoridx = SQString::Create(this,"constructor"); _registry = SQTable::Create(this,0); _consts = SQTable::Create(this,0); _table_default_delegate = CreateDefaultDelegate(this,_table_default_delegate_funcz); _array_default_delegate = CreateDefaultDelegate(this,_array_default_delegate_funcz); _string_default_delegate = CreateDefaultDelegate(this,_string_default_delegate_funcz); _number_default_delegate = CreateDefaultDelegate(this,_number_default_delegate_funcz); _closure_default_delegate = CreateDefaultDelegate(this,_closure_default_delegate_funcz); _generator_default_delegate = CreateDefaultDelegate(this,_generator_default_delegate_funcz); _thread_default_delegate = CreateDefaultDelegate(this,_thread_default_delegate_funcz); _class_default_delegate = CreateDefaultDelegate(this,_class_default_delegate_funcz); _instance_default_delegate = CreateDefaultDelegate(this,_instance_default_delegate_funcz); _weakref_default_delegate = CreateDefaultDelegate(this,_weakref_default_delegate_funcz); } SQSharedState::~SQSharedState() { _constructoridx = _null_; _table(_registry)->Finalize(); _table(_consts)->Finalize(); _table(_metamethodsmap)->Finalize(); _registry = _null_; _consts = _null_; _metamethodsmap = _null_; while(!_systemstrings->empty()) { _systemstrings->back()=_null_; _systemstrings->pop_back(); } _thread(_root_vm)->Finalize(); _root_vm = _null_; _table_default_delegate = _null_; _array_default_delegate = _null_; _string_default_delegate = _null_; _number_default_delegate = _null_; _closure_default_delegate = _null_; _generator_default_delegate = _null_; _thread_default_delegate = _null_; _class_default_delegate = _null_; _instance_default_delegate = _null_; _weakref_default_delegate = _null_; _refs_table.Finalize(); #ifndef NO_GARBAGE_COLLECTOR SQCollectable *t = _gc_chain; SQCollectable *nx = NULL; if(t) { t->_uiRef++; while(t) { t->Finalize(); nx = t->_next; if(nx) nx->_uiRef++; if(--t->_uiRef == 0) t->Release(); t = nx; } } // assert(_gc_chain==NULL); //just to proove a theory while(_gc_chain){ _gc_chain->_uiRef--; _gc_chain->Release(); } #endif sq_delete(_types,SQObjectPtrVec); sq_delete(_systemstrings,SQObjectPtrVec); sq_delete(_metamethods,SQObjectPtrVec); sq_delete(_stringtable,SQStringTable); if(_scratchpad)SQ_FREE(_scratchpad,_scratchpadsize); } SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) { if(type(name) != OT_STRING) return -1; SQObjectPtr ret; if(_table(_metamethodsmap)->Get(name,ret)) { return _integer(ret); } return -1; } #ifndef NO_GARBAGE_COLLECTOR void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) { switch(type(o)){ case OT_TABLE:_table(o)->Mark(chain);break; case OT_ARRAY:_array(o)->Mark(chain);break; case OT_USERDATA:_userdata(o)->Mark(chain);break; case OT_CLOSURE:_closure(o)->Mark(chain);break; case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; case OT_GENERATOR:_generator(o)->Mark(chain);break; case OT_THREAD:_thread(o)->Mark(chain);break; case OT_CLASS:_class(o)->Mark(chain);break; case OT_INSTANCE:_instance(o)->Mark(chain);break; default: break; //shutup compiler } } SQInteger SQSharedState::CollectGarbage(SQVM *vm) { SQInteger n=0; SQCollectable *tchain=NULL; SQVM *vms = _thread(_root_vm); vms->Mark(&tchain); SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); _refs_table.Mark(&tchain); MarkObject(_registry,&tchain); MarkObject(_consts,&tchain); MarkObject(_metamethodsmap,&tchain); MarkObject(_table_default_delegate,&tchain); MarkObject(_array_default_delegate,&tchain); MarkObject(_string_default_delegate,&tchain); MarkObject(_number_default_delegate,&tchain); MarkObject(_generator_default_delegate,&tchain); MarkObject(_thread_default_delegate,&tchain); MarkObject(_closure_default_delegate,&tchain); MarkObject(_class_default_delegate,&tchain); MarkObject(_instance_default_delegate,&tchain); MarkObject(_weakref_default_delegate,&tchain); SQCollectable *t = _gc_chain; SQCollectable *nx = NULL; if(t) { t->_uiRef++; while(t) { t->Finalize(); nx = t->_next; if(nx) nx->_uiRef++; if(--t->_uiRef == 0) t->Release(); t = nx; n++; } } t = tchain; while(t) { t->UnMark(); t = t->_next; } _gc_chain = tchain; SQInteger z = _table(_thread(_root_vm)->_roottable)->CountUsed(); assert(z == x); return n; } #endif #ifndef NO_GARBAGE_COLLECTOR void SQCollectable::AddToChain(SQCollectable **chain,SQCollectable *c) { c->_prev = NULL; c->_next = *chain; if(*chain) (*chain)->_prev = c; *chain = c; } void SQCollectable::RemoveFromChain(SQCollectable **chain,SQCollectable *c) { if(c->_prev) c->_prev->_next = c->_next; else *chain = c->_next; if(c->_next) c->_next->_prev = c->_prev; c->_next = NULL; c->_prev = NULL; } #endif SQChar* SQSharedState::GetScratchPad(SQInteger size) { SQInteger newsize; if(size>0) { if(_scratchpadsize < size) { newsize = size + (size>>1); _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); _scratchpadsize = newsize; }else if(_scratchpadsize >= (size<<5)) { newsize = _scratchpadsize >> 1; _scratchpad = (SQChar *)SQ_REALLOC(_scratchpad,_scratchpadsize,newsize); _scratchpadsize = newsize; } } return _scratchpad; } RefTable::RefTable() { AllocNodes(4); } void RefTable::Finalize() { RefNode *nodes = _nodes; for(SQUnsignedInteger n = 0; n < _numofslots; n++) { nodes->obj = _null_; nodes++; } } RefTable::~RefTable() { SQ_FREE(_buckets,(_numofslots * sizeof(RefNode *)) + (_numofslots * sizeof(RefNode))); } #ifndef NO_GARBAGE_COLLECTOR void RefTable::Mark(SQCollectable **chain) { RefNode *nodes = (RefNode *)_nodes; for(SQUnsignedInteger n = 0; n < _numofslots; n++) { if(type(nodes->obj) != OT_NULL) { SQSharedState::MarkObject(nodes->obj,chain); } nodes++; } } #endif void RefTable::AddRef(SQObject &obj) { SQHash mainpos; RefNode *prev; RefNode *ref = Get(obj,mainpos,&prev,true); ref->refs++; } SQBool RefTable::Release(SQObject &obj) { SQHash mainpos; RefNode *prev; RefNode *ref = Get(obj,mainpos,&prev,false); if(ref) { if(--ref->refs == 0) { SQObjectPtr o = ref->obj; if(prev) { prev->next = ref->next; } else { _buckets[mainpos] = ref->next; } ref->next = _freelist; _freelist = ref; _slotused--; ref->obj = _null_; //<>test for shrink? return SQTrue; } } else { assert(0); } return SQFalse; } void RefTable::Resize(SQUnsignedInteger size) { RefNode **oldbucks = _buckets; RefNode *t = _nodes; SQUnsignedInteger oldnumofslots = _numofslots; AllocNodes(size); //rehash SQUnsignedInteger nfound = 0; for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) { if(type(t->obj) != OT_NULL) { //add back; assert(t->refs != 0); RefNode *nn = Add(::HashObj(t->obj)&(_numofslots-1),t->obj); nn->refs = t->refs; t->obj = _null_; nfound++; } t++; } assert(nfound == oldnumofslots); SQ_FREE(oldbucks,(oldnumofslots * sizeof(RefNode *)) + (oldnumofslots * sizeof(RefNode))); } RefTable::RefNode *RefTable::Add(SQHash mainpos,SQObject &obj) { RefNode *t = _buckets[mainpos]; RefNode *newnode = _freelist; newnode->obj = obj; _buckets[mainpos] = newnode; _freelist = _freelist->next; newnode->next = t; assert(newnode->refs == 0); _slotused++; return newnode; } RefTable::RefNode *RefTable::Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add) { RefNode *ref; mainpos = ::HashObj(obj)&(_numofslots-1); *prev = NULL; for (ref = _buckets[mainpos]; ref; ) { if(_rawval(ref->obj) == _rawval(obj) && type(ref->obj) == type(obj)) break; *prev = ref; ref = ref->next; } if(ref == NULL && add) { if(_numofslots == _slotused) { assert(_freelist == 0); Resize(_numofslots*2); mainpos = ::HashObj(obj)&(_numofslots-1); } ref = Add(mainpos,obj); } return ref; } void RefTable::AllocNodes(SQUnsignedInteger size) { RefNode **bucks; RefNode *nodes; bucks = (RefNode **)SQ_MALLOC((size * sizeof(RefNode *)) + (size * sizeof(RefNode))); nodes = (RefNode *)&bucks[size]; RefNode *temp = nodes; SQUnsignedInteger n; for(n = 0; n < size - 1; n++) { bucks[n] = NULL; temp->refs = 0; new (&temp->obj) SQObjectPtr; temp->next = temp+1; temp++; } bucks[n] = NULL; temp->refs = 0; new (&temp->obj) SQObjectPtr; temp->next = NULL; _freelist = nodes; _nodes = nodes; _buckets = bucks; _slotused = 0; _numofslots = size; } ////////////////////////////////////////////////////////////////////////// //SQStringTable /* * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) * http://www.lua.org/copyright.html#4 * http://www.lua.org/source/4.0.1/src_lstring.c.html */ SQStringTable::SQStringTable() { AllocNodes(4); _slotused = 0; } SQStringTable::~SQStringTable() { SQ_FREE(_strings,sizeof(SQString*)*_numofslots); _strings = NULL; } void SQStringTable::AllocNodes(SQInteger size) { _numofslots = size; _strings = (SQString**)SQ_MALLOC(sizeof(SQString*)*_numofslots); memset(_strings,0,sizeof(SQString*)*(size_t)_numofslots); } SQString *SQStringTable::Add(const SQChar *news,SQInteger len) { if(len<0) len = (SQInteger)strlen(news); SQHash h = ::_hashstr(news,(size_t)len)&(_numofslots-1); SQString *s; for (s = _strings[h]; s; s = s->_next){ if(s->_len == len && (!memcmp(news,s->_val,(size_t)len))) return s; //found } SQString *t=(SQString *)SQ_MALLOC(len+sizeof(SQString)); new (t) SQString(news, len); t->_next = _strings[h]; _strings[h] = t; _slotused++; if (_slotused > _numofslots) /* too crowded? */ Resize(_numofslots*2); return t; } SQString::SQString(const SQChar *news, SQInteger len) { memcpy(_val,news,(size_t)len); _val[len] = '\0'; _len = len; _hash = ::_hashstr(news,(size_t)len); _next = NULL; _sharedstate = NULL; } void SQStringTable::Resize(SQInteger size) { SQInteger oldsize=_numofslots; SQString **oldtable=_strings; AllocNodes(size); for (SQInteger i=0; i_next; SQHash h = p->_hash&(_numofslots-1); p->_next = _strings[h]; _strings[h] = p; p = next; } } SQ_FREE(oldtable,oldsize*sizeof(SQString*)); } void SQStringTable::Remove(SQString *bs) { SQString *s; SQString *prev=NULL; SQHash h = bs->_hash&(_numofslots - 1); for (s = _strings[h]; s; ){ if(s == bs){ if(prev) prev->_next = s->_next; else _strings[h] = s->_next; _slotused--; SQInteger slen = s->_len; s->~SQString(); SQ_FREE(s,sizeof(SQString) + slen); return; } prev = s; s = s->_next; } assert(0);//if this fail something is wrong } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqlexer.h0000644000000000000000000000176212627373445021625 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQLEXER_H_ #define _SQLEXER_H_ struct SQLexer { ~SQLexer(); SQLexer(SQSharedState *ss,SQLEXREADFUNC rg,SQUserPointer up,CompilerErrorFunc efunc,void *ed); NORETURN void Error(const SQChar *err); SQInteger Lex(); const SQChar *Tok2Str(SQInteger tok); private: SQInteger GetIDType(SQChar *s); SQInteger ReadString(WChar ndelim,bool verbatim); SQInteger ReadNumber(); void LexBlockComment(); SQInteger ReadID(); void Next(); SQInteger _curtoken; SQTable *_keywords; void INIT_TEMP_STRING() { _longstr.resize(0); } void APPEND_CHAR(WChar c); void TERMINATE_BUFFER() { _longstr.push_back('\0'); } public: SQInteger _prevtoken; SQInteger _currentline; SQInteger _lasttokenline; SQInteger _currentcolumn; const SQChar *_svalue; SQInteger _nvalue; SQFloat _fvalue; SQLEXREADFUNC _readf; SQUserPointer _up; WChar _currdata; SQSharedState *_sharedstate; sqvector _longstr; CompilerErrorFunc _errfunc; void *_errtarget; }; #endif openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqclosure.h0000644000000000000000000000633612627373445022164 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQCLOSURE_H_ #define _SQCLOSURE_H_ struct SQFunctionProto; struct SQClosure : public CHAINABLE_OBJ { private: SQClosure(SQSharedState *ss,SQFunctionProto *func){_function=func; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} public: static SQClosure *Create(SQSharedState *ss,SQFunctionProto *func){ SQClosure *nc=(SQClosure*)SQ_MALLOC(sizeof(SQClosure)); new (nc) SQClosure(ss,func); return nc; } void Release(){ sq_delete(this,SQClosure); } SQClosure *Clone() { SQClosure * ret = SQClosure::Create(_opt_ss(this),_funcproto(_function)); ret->_env = _env; ret->_outervalues.copy(_outervalues); ret->_defaultparams.copy(_defaultparams); return ret; } ~SQClosure() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){_outervalues.resize(0); } #endif SQObjectPtr _env; SQObjectPtr _function; SQObjectPtrVec _outervalues; SQObjectPtrVec _defaultparams; }; ////////////////////////////////////////////// struct SQGenerator : public CHAINABLE_OBJ { enum SQGeneratorState{eRunning,eSuspended,eDead}; private: SQGenerator(SQSharedState *ss,SQClosure *closure){_closure=closure;_state=eRunning;_ci._generator=NULL;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} public: static SQGenerator *Create(SQSharedState *ss,SQClosure *closure){ SQGenerator *nc=(SQGenerator*)SQ_MALLOC(sizeof(SQGenerator)); new (nc) SQGenerator(ss,closure); return nc; } ~SQGenerator() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } void Kill(){ _state=eDead; _stack.resize(0); _closure=_null_;} void Release(){ sq_delete(this,SQGenerator); } bool Yield(SQVM *v); bool Resume(SQVM *v,SQInteger target); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){_stack.resize(0);_closure=_null_;} #endif SQObjectPtr _closure; SQObjectPtrVec _stack; SQObjectPtrVec _vargsstack; SQVM::CallInfo _ci; ExceptionsTraps _etraps; SQGeneratorState _state; }; struct SQNativeClosure : public CHAINABLE_OBJ { private: SQNativeClosure(SQSharedState *ss,SQFUNCTION func) : _nparamscheck(0) {_function=func;INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } public: static SQNativeClosure *Create(SQSharedState *ss,SQFUNCTION func) { SQNativeClosure *nc=(SQNativeClosure*)SQ_MALLOC(sizeof(SQNativeClosure)); new (nc) SQNativeClosure(ss,func); return nc; } SQNativeClosure *Clone() { SQNativeClosure * ret = SQNativeClosure::Create(_opt_ss(this),_function); ret->_env = _env; ret->_name = _name; ret->_outervalues.copy(_outervalues); ret->_typecheck.copy(_typecheck); ret->_nparamscheck = _nparamscheck; return ret; } ~SQNativeClosure() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } void Release(){ sq_delete(this,SQNativeClosure); } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); void Finalize(){_outervalues.resize(0);} #endif SQInteger _nparamscheck; SQIntVec _typecheck; SQObjectPtrVec _outervalues; SQObjectPtr _env; SQFUNCTION _function; SQObjectPtr _name; }; #endif //_SQCLOSURE_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqtable.h0000644000000000000000000000451512627373445021574 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQTABLE_H_ #define _SQTABLE_H_ /* * The following code is based on Lua 4.0 (Copyright 1994-2002 Tecgraf, PUC-Rio.) * http://www.lua.org/copyright.html#4 * http://www.lua.org/source/4.0.1/src_ltable.c.html */ #include "sqstring.h" #define hashptr(p) ((SQHash)(((SQInteger)p) >> 3)) inline SQHash HashObj(const SQObjectPtr &key) { switch(type(key)) { case OT_STRING: return _string(key)->_hash; case OT_FLOAT: return (SQHash)((SQInteger)_float(key)); case OT_BOOL: case OT_INTEGER: return (SQHash)((SQInteger)_integer(key)); default: return hashptr(key._unVal.pRefCounted); } } struct SQTable : public SQDelegable { private: struct _HashNode { _HashNode() { next = NULL; } SQObjectPtr val; SQObjectPtr key; _HashNode *next; }; _HashNode *_firstfree; _HashNode *_nodes; SQInteger _numofnodes; SQInteger _usednodes; /////////////////////////// void AllocNodes(SQInteger nSize); void Rehash(bool force); SQTable(SQSharedState *ss, SQInteger nInitialSize); void _ClearNodes(); public: static SQTable* Create(SQSharedState *ss,SQInteger nInitialSize) { SQTable *newtable = (SQTable*)SQ_MALLOC(sizeof(SQTable)); new (newtable) SQTable(ss, nInitialSize); newtable->_delegate = NULL; return newtable; } void Finalize(); SQTable *Clone(); ~SQTable() { SetDelegate(NULL); REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); for (SQInteger i = 0; i < _numofnodes; i++) _nodes[i].~_HashNode(); SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); #endif inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) { _HashNode *n = &_nodes[hash]; do{ if(_rawval(n->key) == _rawval(key) && type(n->key) == type(key)){ return n; } }while((n = n->next)); return NULL; } bool Get(const SQObjectPtr &key,SQObjectPtr &val); void Remove(const SQObjectPtr &key); bool Set(const SQObjectPtr &key, const SQObjectPtr &val); //returns true if a new slot has been created false if it was already present bool NewSlot(const SQObjectPtr &key,const SQObjectPtr &val); SQInteger Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); SQInteger CountUsed(){ return _usednodes;} void Clear(); void Release() { sq_delete(this, SQTable); } }; #endif //_SQTABLE_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqcompiler.cpp0000644000000000000000000011501312627373445022646 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include #include "sqpcheader.h" #include #include "sqopcodes.h" #include "sqstring.h" #include "sqfuncproto.h" #include "sqcompiler.h" #include "sqfuncstate.h" #include "sqlexer.h" #include "sqvm.h" #include "sqtable.h" #include "../../../string_func.h" #include "../../../safeguards.h" #define DEREF_NO_DEREF -1 #define DEREF_FIELD -2 SQInteger _last_stacksize; struct ExpState { ExpState() { _deref = DEREF_NO_DEREF; _freevar = false; _class_or_delete = false; _funcarg = false; } bool _class_or_delete; bool _funcarg; bool _freevar; SQInteger _deref; }; typedef sqvector ExpStateVec; #define _exst (_expstates.top()) #define BEGIN_BREAKBLE_BLOCK() SQInteger __nbreaks__=_fs->_unresolvedbreaks.size(); \ SQInteger __ncontinues__=_fs->_unresolvedcontinues.size(); \ _fs->_breaktargets.push_back(0);_fs->_continuetargets.push_back(0); #define END_BREAKBLE_BLOCK(continue_target) {__nbreaks__=_fs->_unresolvedbreaks.size()-__nbreaks__; \ __ncontinues__=_fs->_unresolvedcontinues.size()-__ncontinues__; \ if(__ncontinues__>0)ResolveContinues(_fs,__ncontinues__,continue_target); \ if(__nbreaks__>0)ResolveBreaks(_fs,__nbreaks__); \ _fs->_breaktargets.pop_back();_fs->_continuetargets.pop_back();} class SQCompiler { public: SQCompiler(SQVM *v, SQLEXREADFUNC rg, SQUserPointer up, const SQChar* sourcename, bool raiseerror, bool lineinfo) : _lex(_ss(v), rg, up,ThrowError,this) { _vm=v; _sourcename = SQString::Create(_ss(v), sourcename); _lineinfo = lineinfo;_raiseerror = raiseerror; } NORETURN static void ThrowError(void *ud, const SQChar *s) { SQCompiler *c = (SQCompiler *)ud; c->Error(s); } NORETURN void Error(const SQChar *s, ...) { static SQChar temp[256]; va_list vl; va_start(vl, s); vseprintf(temp, lastof(temp), s, vl); va_end(vl); throw temp; } void Lex(){ _token = _lex.Lex();} void PushExpState(){ _expstates.push_back(ExpState()); } bool IsDerefToken(SQInteger tok) { switch(tok){ case '=': case '(': case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: return true; } return false; } ExpState PopExpState() { ExpState ret = _expstates.top(); _expstates.pop_back(); return ret; } SQObject Expect(SQInteger tok) { if(_token != tok) { if(_token == TK_CONSTRUCTOR && tok == TK_IDENTIFIER) { //ret = SQString::Create(_ss(_vm),"constructor"); //do nothing } else { const SQChar *etypename; if(tok > 255) { switch(tok) { case TK_IDENTIFIER: etypename = "IDENTIFIER"; break; case TK_STRING_LITERAL: etypename = "STRING_LITERAL"; break; case TK_INTEGER: etypename = "INTEGER"; break; case TK_FLOAT: etypename = "FLOAT"; break; default: etypename = _lex.Tok2Str(tok); } Error("expected '%s'", etypename); } Error("expected '%c'", tok); } } SQObjectPtr ret; switch(tok) { case TK_IDENTIFIER: ret = _fs->CreateString(_lex._svalue); break; case TK_STRING_LITERAL: ret = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); break; case TK_INTEGER: ret = SQObjectPtr(_lex._nvalue); break; case TK_FLOAT: ret = SQObjectPtr(_lex._fvalue); break; } Lex(); return ret; } bool IsEndOfStatement() { return ((_lex._prevtoken == '\n') || (_token == SQUIRREL_EOB) || (_token == '}') || (_token == ';')); } void OptionalSemicolon() { if(_token == ';') { Lex(); return; } if(!IsEndOfStatement()) { Error("end of statement expected (; or lf)"); } } void MoveIfCurrentTargetIsLocal() { SQInteger trg = _fs->TopTarget(); if(_fs->IsLocal(trg)) { trg = _fs->PopTarget(); //no pops the target and move it _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); } } bool Compile(SQObjectPtr &o) { _debugline = 1; _debugop = 0; SQFuncState funcstate(_ss(_vm), NULL,ThrowError,this); funcstate._name = SQString::Create(_ss(_vm), "main"); _fs = &funcstate; _fs->AddParameter(_fs->CreateString("this")); _fs->_sourcename = _sourcename; SQInteger stacksize = _fs->GetStackSize(); try { Lex(); while(_token > 0){ Statement(); if(_lex._prevtoken != '}') OptionalSemicolon(); } CleanStack(stacksize); _fs->AddLineInfos(_lex._currentline, _lineinfo, true); _fs->AddInstruction(_OP_RETURN, 0xFF); _fs->SetStackSize(0); o =_fs->BuildProto(); #ifdef _DEBUG_DUMP _fs->Dump(_funcproto(o)); #endif return true; } catch (SQChar *compilererror) { if(_raiseerror && _ss(_vm)->_compilererrorhandler) { _ss(_vm)->_compilererrorhandler(_vm, compilererror, type(_sourcename) == OT_STRING?_stringval(_sourcename):"unknown", _lex._currentline, _lex._currentcolumn); } _vm->_lasterror = SQString::Create(_ss(_vm), compilererror, -1); return false; } } void Statements() { while(_token != '}' && _token != TK_DEFAULT && _token != TK_CASE) { Statement(); if(_lex._prevtoken != '}' && _lex._prevtoken != ';') OptionalSemicolon(); } } void Statement() { _fs->AddLineInfos(_lex._currentline, _lineinfo); switch(_token){ case ';': Lex(); break; case TK_IF: IfStatement(); break; case TK_WHILE: WhileStatement(); break; case TK_DO: DoWhileStatement(); break; case TK_FOR: ForStatement(); break; case TK_FOREACH: ForEachStatement(); break; case TK_SWITCH: SwitchStatement(); break; case TK_LOCAL: LocalDeclStatement(); break; case TK_RETURN: case TK_YIELD: { SQOpcode op; if(_token == TK_RETURN) { op = _OP_RETURN; } else { op = _OP_YIELD; _fs->_bgenerator = true; } Lex(); if(!IsEndOfStatement()) { SQInteger retexp = _fs->GetCurrentPos()+1; CommaExpr(); if(op == _OP_RETURN && _fs->_traps > 0) _fs->AddInstruction(_OP_POPTRAP, _fs->_traps, 0); _fs->_returnexp = retexp; _fs->AddInstruction(op, 1, _fs->PopTarget()); } else{ if(op == _OP_RETURN && _fs->_traps > 0) _fs->AddInstruction(_OP_POPTRAP, _fs->_traps ,0); _fs->_returnexp = -1; _fs->AddInstruction(op, 0xFF); } break;} case TK_BREAK: if(_fs->_breaktargets.size() <= 0)Error("'break' has to be in a loop block"); if(_fs->_breaktargets.top() > 0){ _fs->AddInstruction(_OP_POPTRAP, _fs->_breaktargets.top(), 0); } _fs->AddInstruction(_OP_SCOPE_END, _last_stacksize, _fs->GetStackSize()); _fs->AddInstruction(_OP_JMP, 0, -1234); _fs->_unresolvedbreaks.push_back(_fs->GetCurrentPos()); Lex(); break; case TK_CONTINUE: if(_fs->_continuetargets.size() <= 0)Error("'continue' has to be in a loop block"); if(_fs->_continuetargets.top() > 0) { _fs->AddInstruction(_OP_POPTRAP, _fs->_continuetargets.top(), 0); } _fs->AddInstruction(_OP_SCOPE_END, _last_stacksize, _fs->GetStackSize()); _fs->AddInstruction(_OP_JMP, 0, -1234); _fs->_unresolvedcontinues.push_back(_fs->GetCurrentPos()); Lex(); break; case TK_FUNCTION: FunctionStatement(); break; case TK_CLASS: ClassStatement(); break; case TK_ENUM: EnumStatement(); break; case '{':{ SQInteger stacksize = _fs->GetStackSize(); Lex(); Statements(); Expect('}'); _fs->AddInstruction(_OP_SCOPE_END, stacksize, _fs->GetStackSize()); _fs->SetStackSize(stacksize); } break; case TK_TRY: TryCatchStatement(); break; case TK_THROW: Lex(); CommaExpr(); _fs->AddInstruction(_OP_THROW, _fs->PopTarget()); break; case TK_CONST: { Lex(); SQObject id = Expect(TK_IDENTIFIER); Expect('='); SQObject val = ExpectScalar(); OptionalSemicolon(); SQTable *enums = _table(_ss(_vm)->_consts); SQObjectPtr strongid = id; enums->NewSlot(strongid,SQObjectPtr(val)); strongid.Null(); } break; default: CommaExpr(); _fs->PopTarget(); break; } _fs->SnoozeOpt(); } void EmitDerefOp(SQOpcode op) { SQInteger val = _fs->PopTarget(); SQInteger key = _fs->PopTarget(); SQInteger src = _fs->PopTarget(); _fs->AddInstruction(op,_fs->PushTarget(),src,key,val); } void Emit2ArgsOP(SQOpcode op, SQInteger p3 = 0) { SQInteger p2 = _fs->PopTarget(); //src in OP_GET SQInteger p1 = _fs->PopTarget(); //key in OP_GET _fs->AddInstruction(op,_fs->PushTarget(), p1, p2, p3); } void EmitCompoundArith(SQInteger tok,bool deref) { SQInteger oper; switch(tok){ case TK_MINUSEQ: oper = '-'; break; case TK_PLUSEQ: oper = '+'; break; case TK_MULEQ: oper = '*'; break; case TK_DIVEQ: oper = '/'; break; case TK_MODEQ: oper = '%'; break; default: oper = 0; //shut up compiler assert(0); break; }; if(deref) { SQInteger val = _fs->PopTarget(); SQInteger key = _fs->PopTarget(); SQInteger src = _fs->PopTarget(); //mixes dest obj and source val in the arg1(hack?) _fs->AddInstruction(_OP_COMPARITH,_fs->PushTarget(),(src<<16)|val,key,oper); } else { Emit2ArgsOP(_OP_COMPARITHL, oper); } } void CommaExpr() { for(Expression();_token == ',';_fs->PopTarget(), Lex(), CommaExpr()) {} } ExpState Expression(bool funcarg = false) { PushExpState(); _exst._class_or_delete = false; _exst._funcarg = funcarg; LogicalOrExp(); switch(_token) { case '=': case TK_NEWSLOT: case TK_MINUSEQ: case TK_PLUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: { SQInteger op = _token; SQInteger ds = _exst._deref; bool freevar = _exst._freevar; if(ds == DEREF_NO_DEREF) Error("can't assign expression"); Lex(); Expression(); switch(op){ case TK_NEWSLOT: if(freevar) Error("free variables cannot be modified"); if(ds == DEREF_FIELD) EmitDerefOp(_OP_NEWSLOT); else //if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local Error("can't 'create' a local slot"); break; case '=': //ASSIGN if(freevar) Error("free variables cannot be modified"); if(ds == DEREF_FIELD) EmitDerefOp(_OP_SET); else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local SQInteger p2 = _fs->PopTarget(); //src in OP_GET SQInteger p1 = _fs->TopTarget(); //key in OP_GET _fs->AddInstruction(_OP_MOVE, p1, p2); } break; case TK_MINUSEQ: case TK_PLUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: EmitCompoundArith(op,ds == DEREF_FIELD); break; } } break; case '?': { Lex(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); SQInteger jzpos = _fs->GetCurrentPos(); SQInteger trg = _fs->PushTarget(); Expression(); SQInteger first_exp = _fs->PopTarget(); if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); SQInteger endfirstexp = _fs->GetCurrentPos(); _fs->AddInstruction(_OP_JMP, 0, 0); Expect(':'); SQInteger jmppos = _fs->GetCurrentPos(); Expression(); SQInteger second_exp = _fs->PopTarget(); if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); _fs->SetIntructionParam(jzpos, 1, endfirstexp - jzpos + 1); _fs->SnoozeOpt(); } break; } return PopExpState(); } void BIN_EXP(SQOpcode op, void (SQCompiler::*f)(void),SQInteger op3 = 0) { Lex(); (this->*f)(); SQInteger op1 = _fs->PopTarget();SQInteger op2 = _fs->PopTarget(); _fs->AddInstruction(op, _fs->PushTarget(), op1, op2, op3); } void LogicalOrExp() { LogicalAndExp(); if(_token == TK_OR) { SQInteger first_exp = _fs->PopTarget(); SQInteger trg = _fs->PushTarget(); _fs->AddInstruction(_OP_OR, trg, 0, first_exp, 0); SQInteger jpos = _fs->GetCurrentPos(); if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); Lex(); LogicalOrExp(); _fs->SnoozeOpt(); SQInteger second_exp = _fs->PopTarget(); if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); _fs->SnoozeOpt(); _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); } } void LogicalAndExp() { BitwiseOrExp(); for(;;) switch(_token) { case TK_AND: { SQInteger first_exp = _fs->PopTarget(); SQInteger trg = _fs->PushTarget(); _fs->AddInstruction(_OP_AND, trg, 0, first_exp, 0); SQInteger jpos = _fs->GetCurrentPos(); if(trg != first_exp) _fs->AddInstruction(_OP_MOVE, trg, first_exp); Lex(); LogicalAndExp(); _fs->SnoozeOpt(); SQInteger second_exp = _fs->PopTarget(); if(trg != second_exp) _fs->AddInstruction(_OP_MOVE, trg, second_exp); _fs->SnoozeOpt(); _fs->SetIntructionParam(jpos, 1, (_fs->GetCurrentPos() - jpos)); break; } case TK_IN: BIN_EXP(_OP_EXISTS, &SQCompiler::BitwiseOrExp); break; case TK_INSTANCEOF: BIN_EXP(_OP_INSTANCEOF, &SQCompiler::BitwiseOrExp); break; default: return; } } void BitwiseOrExp() { BitwiseXorExp(); for(;;) if(_token == '|') {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseXorExp,BW_OR); }else return; } void BitwiseXorExp() { BitwiseAndExp(); for(;;) if(_token == '^') {BIN_EXP(_OP_BITW, &SQCompiler::BitwiseAndExp,BW_XOR); }else return; } void BitwiseAndExp() { CompExp(); for(;;) if(_token == '&') {BIN_EXP(_OP_BITW, &SQCompiler::CompExp,BW_AND); }else return; } void CompExp() { ShiftExp(); for(;;) switch(_token) { case TK_EQ: BIN_EXP(_OP_EQ, &SQCompiler::ShiftExp); break; case '>': BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_G); break; case '<': BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_L); break; case TK_GE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_GE); break; case TK_LE: BIN_EXP(_OP_CMP, &SQCompiler::ShiftExp,CMP_LE); break; case TK_NE: BIN_EXP(_OP_NE, &SQCompiler::ShiftExp); break; default: return; } } void ShiftExp() { PlusExp(); for(;;) switch(_token) { case TK_USHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_USHIFTR); break; case TK_SHIFTL: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTL); break; case TK_SHIFTR: BIN_EXP(_OP_BITW, &SQCompiler::PlusExp,BW_SHIFTR); break; default: return; } } void PlusExp() { MultExp(); for(;;) switch(_token) { case '+': case '-': BIN_EXP(_OP_ARITH, &SQCompiler::MultExp,_token); break; default: return; } } void MultExp() { PrefixedExpr(); for(;;) switch(_token) { case '*': case '/': case '%': BIN_EXP(_OP_ARITH, &SQCompiler::PrefixedExpr,_token); break; default: return; } } //if 'pos' != -1 the previous variable is a local variable void PrefixedExpr() { SQInteger pos = Factor(); for(;;) { switch(_token) { case '.': { pos = -1; Lex(); if(_token == TK_PARENT) { Lex(); if(!NeedGet()) Error("parent cannot be set"); SQInteger src = _fs->PopTarget(); _fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), src); } else { _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); if(NeedGet()) Emit2ArgsOP(_OP_GET); } _exst._deref = DEREF_FIELD; _exst._freevar = false; } break; case '[': if(_lex._prevtoken == '\n') Error("cannot brake deref/or comma needed after [exp]=exp slot declaration"); Lex(); Expression(); Expect(']'); pos = -1; if(NeedGet()) Emit2ArgsOP(_OP_GET); _exst._deref = DEREF_FIELD; _exst._freevar = false; break; case TK_MINUSMINUS: case TK_PLUSPLUS: if(_exst._deref != DEREF_NO_DEREF && !IsEndOfStatement()) { SQInteger tok = _token; Lex(); if(pos < 0) Emit2ArgsOP(_OP_PINC,tok == TK_MINUSMINUS?-1:1); else {//if _derefstate != DEREF_NO_DEREF && DEREF_FIELD so is the index of a local SQInteger src = _fs->PopTarget(); _fs->AddInstruction(_OP_PINCL, _fs->PushTarget(), src, 0, tok == TK_MINUSMINUS?-1:1); } } return; break; case '(': { if(_exst._deref != DEREF_NO_DEREF) { if(pos<0) { SQInteger key = _fs->PopTarget(); //key SQInteger table = _fs->PopTarget(); //table etc... SQInteger closure = _fs->PushTarget(); SQInteger ttarget = _fs->PushTarget(); _fs->AddInstruction(_OP_PREPCALL, closure, key, table, ttarget); } else{ _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); } } else _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), 0); _exst._deref = DEREF_NO_DEREF; Lex(); FunctionCallArgs(); } break; default: return; } } } SQInteger Factor() { _exst._deref = DEREF_NO_DEREF; switch(_token) { case TK_STRING_LITERAL: { //SQObjectPtr id(SQString::Create(_ss(_vm), _lex._svalue,_lex._longstr.size()-1)); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_fs->CreateString(_lex._svalue,_lex._longstr.size()-1))); Lex(); } break; case TK_VARGC: Lex(); _fs->AddInstruction(_OP_VARGC, _fs->PushTarget()); break; case TK_VARGV: { Lex(); Expect('['); Expression(); Expect(']'); SQInteger src = _fs->PopTarget(); _fs->AddInstruction(_OP_GETVARGV, _fs->PushTarget(), src); } break; case TK_IDENTIFIER: case TK_CONSTRUCTOR: case TK_THIS:{ _exst._freevar = false; SQObject id; SQObject constant; switch(_token) { case TK_IDENTIFIER: id = _fs->CreateString(_lex._svalue); break; case TK_THIS: id = _fs->CreateString("this"); break; case TK_CONSTRUCTOR: id = _fs->CreateString("constructor"); break; } SQInteger pos = -1; Lex(); if((pos = _fs->GetLocalVariable(id)) == -1) { //checks if is a free variable if((pos = _fs->GetOuterVariable(id)) != -1) { _exst._deref = _fs->PushTarget(); _fs->AddInstruction(_OP_LOADFREEVAR, _exst._deref ,pos); _exst._freevar = true; } else if(_fs->IsConstant(id,constant)) { //line 634 SQObjectPtr constval; SQObject constid; if(type(constant) == OT_TABLE) { Expect('.'); constid = Expect(TK_IDENTIFIER); if(!_table(constant)->Get(constid,constval)) { constval.Null(); Error("invalid constant [%s.%s]", _stringval(id),_stringval(constid)); } } else { constval = constant; } _exst._deref = _fs->PushTarget(); SQObjectType ctype = type(constval); if(ctype == OT_INTEGER && (_integer(constval) & (~0x7FFFFFFF)) == 0) { _fs->AddInstruction(_OP_LOADINT, _exst._deref,_integer(constval)); } else if(ctype == OT_FLOAT && sizeof(SQFloat) == sizeof(SQInt32)) { SQFloat f = _float(constval); _fs->AddInstruction(_OP_LOADFLOAT, _exst._deref,*((SQInt32 *)&f)); } else { _fs->AddInstruction(_OP_LOAD, _exst._deref, _fs->GetConstant(constval)); } _exst._freevar = true; } else { _fs->PushTarget(0); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); if(NeedGet()) Emit2ArgsOP(_OP_GET); _exst._deref = DEREF_FIELD; } } else{ _fs->PushTarget(pos); _exst._deref = pos; } return _exst._deref; } break; case TK_PARENT: Lex();_fs->AddInstruction(_OP_GETPARENT, _fs->PushTarget(), 0); break; case TK_DOUBLE_COLON: // "::" _fs->AddInstruction(_OP_LOADROOTTABLE, _fs->PushTarget()); _exst._deref = DEREF_FIELD; _token = '.'; //hack return -1; break; case TK_NULL: _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); Lex(); break; case TK_INTEGER: { if((_lex._nvalue & (~0x7FFFFFFF)) == 0) { //does it fit in 32 bits? _fs->AddInstruction(_OP_LOADINT, _fs->PushTarget(),_lex._nvalue); } else { _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._nvalue)); } Lex(); } break; case TK_FLOAT: if(sizeof(SQFloat) == sizeof(SQInt32)) { _fs->AddInstruction(_OP_LOADFLOAT, _fs->PushTarget(),*((SQInt32 *)&_lex._fvalue)); } else { _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetNumericConstant(_lex._fvalue)); } Lex(); break; case TK_TRUE: case TK_FALSE: _fs->AddInstruction(_OP_LOADBOOL, _fs->PushTarget(),_token == TK_TRUE?1:0); Lex(); break; case '[': { _fs->AddInstruction(_OP_NEWARRAY, _fs->PushTarget()); SQInteger apos = _fs->GetCurrentPos(),key = 0; Lex(); while(_token != ']') { Expression(); if(_token == ',') Lex(); SQInteger val = _fs->PopTarget(); SQInteger array = _fs->TopTarget(); _fs->AddInstruction(_OP_APPENDARRAY, array, val); key++; } _fs->SetIntructionParam(apos, 1, key); Lex(); } break; case '{':{ _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex();ParseTableOrClass(','); } break; case TK_FUNCTION: FunctionExp(_token);break; case TK_CLASS: Lex(); ClassExp();break; case '-': UnaryOP(_OP_NEG); break; case '!': UnaryOP(_OP_NOT); break; case '~': UnaryOP(_OP_BWNOT); break; case TK_TYPEOF : UnaryOP(_OP_TYPEOF); break; case TK_RESUME : UnaryOP(_OP_RESUME); break; case TK_CLONE : UnaryOP(_OP_CLONE); break; case TK_MINUSMINUS : case TK_PLUSPLUS :PrefixIncDec(_token); break; case TK_DELETE : DeleteExpr(); break; case TK_DELEGATE : DelegateExpr(); break; case '(': Lex(); CommaExpr(); Expect(')'); break; default: Error("expression expected"); } return -1; } void UnaryOP(SQOpcode op) { Lex(); PrefixedExpr(); SQInteger src = _fs->PopTarget(); _fs->AddInstruction(op, _fs->PushTarget(), src); } bool NeedGet() { switch(_token) { case '=': case '(': case TK_NEWSLOT: case TK_PLUSPLUS: case TK_MINUSMINUS: case TK_PLUSEQ: case TK_MINUSEQ: case TK_MULEQ: case TK_DIVEQ: case TK_MODEQ: return false; } return (!_exst._class_or_delete) || (_exst._class_or_delete && (_token == '.' || _token == '[')); } void FunctionCallArgs() { SQInteger nargs = 1;//this while(_token != ')') { Expression(true); MoveIfCurrentTargetIsLocal(); nargs++; if(_token == ','){ Lex(); if(_token == ')') Error("expression expected, found ')'"); } } Lex(); for(SQInteger i = 0; i < (nargs - 1); i++) _fs->PopTarget(); SQInteger stackbase = _fs->PopTarget(); SQInteger closure = _fs->PopTarget(); _fs->AddInstruction(_OP_CALL, _fs->PushTarget(), closure, stackbase, nargs); } void ParseTableOrClass(SQInteger separator,SQInteger terminator = '}') { SQInteger tpos = _fs->GetCurrentPos(),nkeys = 0; while(_token != terminator) { bool hasattrs = false; bool isstatic = false; //check if is an attribute if(separator == ';') { if(_token == TK_ATTR_OPEN) { _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); Lex(); ParseTableOrClass(',',TK_ATTR_CLOSE); hasattrs = true; } if(_token == TK_STATIC) { isstatic = true; Lex(); } } switch(_token) { case TK_FUNCTION: case TK_CONSTRUCTOR:{ SQInteger tk = _token; Lex(); SQObject id = tk == TK_FUNCTION ? Expect(TK_IDENTIFIER) : _fs->CreateString("constructor"); Expect('('); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); CreateFunction(id); _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); } break; case '[': Lex(); CommaExpr(); Expect(']'); Expect('='); Expression(); break; default : _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(Expect(TK_IDENTIFIER))); Expect('='); Expression(); } if(_token == separator) Lex();//optional comma/semicolon nkeys++; SQInteger val = _fs->PopTarget(); SQInteger key = _fs->PopTarget(); SQInteger attrs = hasattrs ? _fs->PopTarget():-1; assert((hasattrs && attrs == key-1) || !hasattrs); unsigned char flags = (hasattrs?NEW_SLOT_ATTRIBUTES_FLAG:0)|(isstatic?NEW_SLOT_STATIC_FLAG:0); SQInteger table = _fs->TopTarget(); //<AddInstruction(_OP_NEWSLOTA, flags, table, key, val); //_fs->PopTarget(); } if(separator == ',') //hack recognizes a table from the separator _fs->SetIntructionParam(tpos, 1, nkeys); Lex(); } void LocalDeclStatement() { SQObject varname; do { Lex(); varname = Expect(TK_IDENTIFIER); if(_token == '=') { Lex(); Expression(); SQInteger src = _fs->PopTarget(); SQInteger dest = _fs->PushTarget(); if(dest != src) _fs->AddInstruction(_OP_MOVE, dest, src); } else{ _fs->AddInstruction(_OP_LOADNULLS, _fs->PushTarget(),1); } _fs->PopTarget(); _fs->PushLocalVariable(varname); } while(_token == ','); } void IfStatement() { SQInteger jmppos; bool haselse = false; Lex(); Expect('('); CommaExpr(); Expect(')'); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); SQInteger jnepos = _fs->GetCurrentPos(); SQInteger stacksize = _fs->GetStackSize(); Statement(); // if(_token != '}' && _token != TK_ELSE) OptionalSemicolon(); CleanStack(stacksize); SQInteger endifblock = _fs->GetCurrentPos(); if(_token == TK_ELSE){ haselse = true; stacksize = _fs->GetStackSize(); _fs->AddInstruction(_OP_JMP); jmppos = _fs->GetCurrentPos(); Lex(); Statement(); OptionalSemicolon(); CleanStack(stacksize); _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); } _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); } void WhileStatement() { SQInteger jzpos, jmppos; SQInteger stacksize = _fs->GetStackSize(); jmppos = _fs->GetCurrentPos(); Lex(); Expect('('); CommaExpr(); Expect(')'); BEGIN_BREAKBLE_BLOCK(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); stacksize = _fs->GetStackSize(); _last_stacksize = _fs->GetStackSize(); Statement(); CleanStack(stacksize); _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); END_BREAKBLE_BLOCK(jmppos); } void DoWhileStatement() { Lex(); SQInteger jzpos = _fs->GetCurrentPos(); SQInteger stacksize = _fs->GetStackSize(); BEGIN_BREAKBLE_BLOCK() _last_stacksize = _fs->GetStackSize(); Statement(); CleanStack(stacksize); _fs->AddLineInfos(_lex._currentline, _lineinfo, true); Expect(TK_WHILE); SQInteger continuetrg = _fs->GetCurrentPos(); Expect('('); CommaExpr(); Expect(')'); _fs->AddInstruction(_OP_JNZ, _fs->PopTarget(), jzpos - _fs->GetCurrentPos() - 1); END_BREAKBLE_BLOCK(continuetrg); } void ForStatement() { Lex(); SQInteger stacksize = _fs->GetStackSize(); Expect('('); if(_token == TK_LOCAL) LocalDeclStatement(); else if(_token != ';'){ CommaExpr(); _fs->PopTarget(); } Expect(';'); _fs->SnoozeOpt(); SQInteger jmppos = _fs->GetCurrentPos(); SQInteger jzpos = -1; if(_token != ';') { CommaExpr(); _fs->AddInstruction(_OP_JZ, _fs->PopTarget()); jzpos = _fs->GetCurrentPos(); } Expect(';'); _fs->SnoozeOpt(); SQInteger expstart = _fs->GetCurrentPos() + 1; if(_token != ')') { CommaExpr(); _fs->PopTarget(); } Expect(')'); _fs->SnoozeOpt(); SQInteger expend = _fs->GetCurrentPos(); SQInteger expsize = (expend - expstart) + 1; SQInstructionVec exp; if(expsize > 0) { for(SQInteger i = 0; i < expsize; i++) exp.push_back(_fs->GetInstruction(expstart + i)); _fs->PopInstructions(expsize); } BEGIN_BREAKBLE_BLOCK() _last_stacksize = _fs->GetStackSize(); Statement(); SQInteger continuetrg = _fs->GetCurrentPos(); if(expsize > 0) { for(SQInteger i = 0; i < expsize; i++) _fs->AddInstruction(exp[i]); } _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1, 0); if(jzpos> 0) _fs->SetIntructionParam(jzpos, 1, _fs->GetCurrentPos() - jzpos); CleanStack(stacksize); END_BREAKBLE_BLOCK(continuetrg); } void ForEachStatement() { SQObject idxname, valname; Lex(); Expect('('); valname = Expect(TK_IDENTIFIER); if(_token == ',') { idxname = valname; Lex(); valname = Expect(TK_IDENTIFIER); } else{ idxname = _fs->CreateString("@INDEX@"); } Expect(TK_IN); //save the stack size SQInteger stacksize = _fs->GetStackSize(); //put the table in the stack(evaluate the table expression) Expression(); Expect(')'); SQInteger container = _fs->TopTarget(); //push the index local var SQInteger indexpos = _fs->PushLocalVariable(idxname); _fs->AddInstruction(_OP_LOADNULLS, indexpos,1); //push the value local var SQInteger valuepos = _fs->PushLocalVariable(valname); _fs->AddInstruction(_OP_LOADNULLS, valuepos,1); //push reference index SQInteger itrpos = _fs->PushLocalVariable(_fs->CreateString("@ITERATOR@")); //use invalid id to make it inaccessible _fs->AddInstruction(_OP_LOADNULLS, itrpos,1); SQInteger jmppos = _fs->GetCurrentPos(); _fs->AddInstruction(_OP_FOREACH, container, 0, indexpos); SQInteger foreachpos = _fs->GetCurrentPos(); _fs->AddInstruction(_OP_POSTFOREACH, container, 0, indexpos); //generate the statement code BEGIN_BREAKBLE_BLOCK() _last_stacksize = _fs->GetStackSize(); Statement(); _fs->AddInstruction(_OP_JMP, 0, jmppos - _fs->GetCurrentPos() - 1); _fs->SetIntructionParam(foreachpos, 1, _fs->GetCurrentPos() - foreachpos); _fs->SetIntructionParam(foreachpos + 1, 1, _fs->GetCurrentPos() - foreachpos); //restore the local variable stack(remove index,val and ref idx) CleanStack(stacksize); END_BREAKBLE_BLOCK(foreachpos - 1); } void SwitchStatement() { Lex(); Expect('('); CommaExpr(); Expect(')'); Expect('{'); SQInteger expr = _fs->TopTarget(); bool bfirst = true; SQInteger tonextcondjmp = -1; SQInteger skipcondjmp = -1; SQInteger __nbreaks__ = _fs->_unresolvedbreaks.size(); _fs->_breaktargets.push_back(0); while(_token == TK_CASE) { //_fs->AddLineInfos(_lex._currentline, _lineinfo); think about this one if(!bfirst) { _fs->AddInstruction(_OP_JMP, 0, 0); skipcondjmp = _fs->GetCurrentPos(); _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); } //condition Lex(); Expression(); Expect(':'); SQInteger trg = _fs->PopTarget(); _fs->AddInstruction(_OP_EQ, trg, trg, expr); _fs->AddInstruction(_OP_JZ, trg, 0); //end condition if(skipcondjmp != -1) { _fs->SetIntructionParam(skipcondjmp, 1, (_fs->GetCurrentPos() - skipcondjmp)); } tonextcondjmp = _fs->GetCurrentPos(); SQInteger stacksize = _fs->GetStackSize(); _last_stacksize = _fs->GetStackSize(); Statements(); _fs->SetStackSize(stacksize); bfirst = false; } if(tonextcondjmp != -1) _fs->SetIntructionParam(tonextcondjmp, 1, _fs->GetCurrentPos() - tonextcondjmp); if(_token == TK_DEFAULT) { // _fs->AddLineInfos(_lex._currentline, _lineinfo); Lex(); Expect(':'); SQInteger stacksize = _fs->GetStackSize(); _last_stacksize = _fs->GetStackSize(); Statements(); _fs->SetStackSize(stacksize); } Expect('}'); _fs->PopTarget(); __nbreaks__ = _fs->_unresolvedbreaks.size() - __nbreaks__; if(__nbreaks__ > 0)ResolveBreaks(_fs, __nbreaks__); _fs->_breaktargets.pop_back(); } void FunctionStatement() { SQObject id; Lex(); id = Expect(TK_IDENTIFIER); _fs->PushTarget(0); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); while(_token == TK_DOUBLE_COLON) { Lex(); id = Expect(TK_IDENTIFIER); _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(id)); if(_token == TK_DOUBLE_COLON) Emit2ArgsOP(_OP_GET); } Expect('('); CreateFunction(id); _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, 0); EmitDerefOp(_OP_NEWSLOT); _fs->PopTarget(); } void ClassStatement() { ExpState es; Lex(); PushExpState(); _exst._class_or_delete = true; _exst._funcarg = false; PrefixedExpr(); es = PopExpState(); if(es._deref == DEREF_NO_DEREF) Error("invalid class name"); if(es._deref == DEREF_FIELD) { ClassExp(); EmitDerefOp(_OP_NEWSLOT); _fs->PopTarget(); } else Error("cannot create a class in a local with the syntax(class )"); } SQObject ExpectScalar() { SQObject val; switch(_token) { case TK_INTEGER: val._type = OT_INTEGER; val._unVal.nInteger = _lex._nvalue; break; case TK_FLOAT: val._type = OT_FLOAT; val._unVal.fFloat = _lex._fvalue; break; case TK_STRING_LITERAL: val = _fs->CreateString(_lex._svalue,_lex._longstr.size()-1); break; case '-': Lex(); switch(_token) { case TK_INTEGER: val._type = OT_INTEGER; val._unVal.nInteger = -_lex._nvalue; break; case TK_FLOAT: val._type = OT_FLOAT; val._unVal.fFloat = -_lex._fvalue; break; default: Error("scalar expected : integer,float"); val._type = OT_NULL; // Silent compile-warning } break; default: Error("scalar expected : integer,float or string"); val._type = OT_NULL; // Silent compile-warning } Lex(); return val; } void EnumStatement() { Lex(); SQObject id = Expect(TK_IDENTIFIER); Expect('{'); SQObject table = _fs->CreateTable(); SQInteger nval = 0; while(_token != '}') { SQObject key = Expect(TK_IDENTIFIER); SQObject val; if(_token == '=') { Lex(); val = ExpectScalar(); } else { val._type = OT_INTEGER; val._unVal.nInteger = nval++; } _table(table)->NewSlot(SQObjectPtr(key),SQObjectPtr(val)); if(_token == ',') Lex(); } SQTable *enums = _table(_ss(_vm)->_consts); SQObjectPtr strongid = id; /*SQObjectPtr dummy; if(enums->Get(strongid,dummy)) { dummy.Null(); strongid.Null(); Error("enumeration already exists"); }*/ enums->NewSlot(SQObjectPtr(strongid),SQObjectPtr(table)); strongid.Null(); Lex(); } void TryCatchStatement() { SQObject exid; Lex(); _fs->AddInstruction(_OP_PUSHTRAP,0,0); _fs->_traps++; if(_fs->_breaktargets.size()) _fs->_breaktargets.top()++; if(_fs->_continuetargets.size()) _fs->_continuetargets.top()++; SQInteger trappos = _fs->GetCurrentPos(); Statement(); _fs->_traps--; _fs->AddInstruction(_OP_POPTRAP, 1, 0); if(_fs->_breaktargets.size()) _fs->_breaktargets.top()--; if(_fs->_continuetargets.size()) _fs->_continuetargets.top()--; _fs->AddInstruction(_OP_JMP, 0, 0); SQInteger jmppos = _fs->GetCurrentPos(); _fs->SetIntructionParam(trappos, 1, (_fs->GetCurrentPos() - trappos)); Expect(TK_CATCH); Expect('('); exid = Expect(TK_IDENTIFIER); Expect(')'); SQInteger stacksize = _fs->GetStackSize(); SQInteger ex_target = _fs->PushLocalVariable(exid); _fs->SetIntructionParam(trappos, 0, ex_target); Statement(); _fs->SetIntructionParams(jmppos, 0, (_fs->GetCurrentPos() - jmppos), 0); CleanStack(stacksize); } void FunctionExp(SQInteger ftype) { Lex(); Expect('('); CreateFunction(_null_); _fs->AddInstruction(_OP_CLOSURE, _fs->PushTarget(), _fs->_functions.size() - 1, ftype == TK_FUNCTION?0:1); } void ClassExp() { SQInteger base = -1; SQInteger attrs = -1; if(_token == TK_EXTENDS) { Lex(); Expression(); base = _fs->TopTarget(); } if(_token == TK_ATTR_OPEN) { Lex(); _fs->AddInstruction(_OP_NEWTABLE, _fs->PushTarget()); ParseTableOrClass(',',TK_ATTR_CLOSE); attrs = _fs->TopTarget(); } Expect('{'); if(attrs != -1) _fs->PopTarget(); if(base != -1) _fs->PopTarget(); _fs->AddInstruction(_OP_CLASS, _fs->PushTarget(), base, attrs); ParseTableOrClass(';'); } void DelegateExpr() { Lex(); CommaExpr(); Expect(':'); CommaExpr(); SQInteger table = _fs->PopTarget(), delegate = _fs->PopTarget(); _fs->AddInstruction(_OP_DELEGATE, _fs->PushTarget(), table, delegate); } void DeleteExpr() { ExpState es; Lex(); PushExpState(); _exst._class_or_delete = true; _exst._funcarg = false; PrefixedExpr(); es = PopExpState(); if(es._deref == DEREF_NO_DEREF) Error("can't delete an expression"); if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_DELETE); else Error("cannot delete a local"); } void PrefixIncDec(SQInteger token) { ExpState es; Lex(); PushExpState(); _exst._class_or_delete = true; _exst._funcarg = false; PrefixedExpr(); es = PopExpState(); if(es._deref == DEREF_FIELD) Emit2ArgsOP(_OP_INC,token == TK_MINUSMINUS?-1:1); else { SQInteger src = _fs->PopTarget(); _fs->AddInstruction(_OP_INCL, _fs->PushTarget(), src, 0, token == TK_MINUSMINUS?-1:1); } } void CreateFunction(SQObject &name) { SQFuncState *funcstate = _fs->PushChildState(_ss(_vm)); funcstate->_name = name; SQObject paramname; funcstate->AddParameter(_fs->CreateString("this")); funcstate->_sourcename = _sourcename; SQInteger defparams = 0; while(_token!=')') { if(_token == TK_VARPARAMS) { if(defparams > 0) Error("function with default parameters cannot have variable number of parameters"); funcstate->_varparams = true; Lex(); if(_token != ')') Error("expected ')'"); break; } else { paramname = Expect(TK_IDENTIFIER); funcstate->AddParameter(paramname); if(_token == '=') { Lex(); Expression(); funcstate->AddDefaultParam(_fs->TopTarget()); defparams++; } else { if(defparams > 0) Error("expected '='"); } if(_token == ',') Lex(); else if(_token != ')') Error("expected ')' or ','"); } } Expect(')'); for(SQInteger n = 0; n < defparams; n++) { _fs->PopTarget(); } //outer values if(_token == ':') { Lex(); Expect('('); while(_token != ')') { paramname = Expect(TK_IDENTIFIER); //outers are treated as implicit local variables funcstate->AddOuterValue(paramname); if(_token == ',') Lex(); else if(_token != ')') Error("expected ')' or ','"); } Lex(); } SQFuncState *currchunk = _fs; _fs = funcstate; Statement(); funcstate->AddLineInfos(_lex._prevtoken == '\n'?_lex._lasttokenline:_lex._currentline, _lineinfo, true); funcstate->AddInstruction(_OP_RETURN, -1); funcstate->SetStackSize(0); //_fs->->_stacksize = _fs->_stacksize; SQFunctionProto *func = funcstate->BuildProto(); #ifdef _DEBUG_DUMP funcstate->Dump(func); #endif _fs = currchunk; _fs->_functions.push_back(func); _fs->PopChildState(); } void CleanStack(SQInteger stacksize) { if(_fs->GetStackSize() != stacksize) _fs->SetStackSize(stacksize); } void ResolveBreaks(SQFuncState *funcstate, SQInteger ntoresolve) { while(ntoresolve > 0) { SQInteger pos = funcstate->_unresolvedbreaks.back(); funcstate->_unresolvedbreaks.pop_back(); //set the jmp instruction funcstate->SetIntructionParams(pos, 0, funcstate->GetCurrentPos() - pos, 0); ntoresolve--; } } void ResolveContinues(SQFuncState *funcstate, SQInteger ntoresolve, SQInteger targetpos) { while(ntoresolve > 0) { SQInteger pos = funcstate->_unresolvedcontinues.back(); funcstate->_unresolvedcontinues.pop_back(); //set the jmp instruction funcstate->SetIntructionParams(pos, 0, targetpos - pos, 0); ntoresolve--; } } private: SQInteger _token; SQFuncState *_fs; SQObjectPtr _sourcename; SQLexer _lex; bool _lineinfo; bool _raiseerror; SQInteger _debugline; SQInteger _debugop; ExpStateVec _expstates; SQVM *_vm; }; bool Compile(SQVM *vm,SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo) { SQCompiler p(vm, rg, up, sourcename, raiseerror, lineinfo); return p.Compile(out); } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqvm.h0000644000000000000000000001711612627373445021130 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQVM_H_ #define _SQVM_H_ #include "sqopcodes.h" #include "sqobject.h" #define MAX_NATIVE_CALLS 100 #define MIN_STACK_OVERHEAD 10 #define SQ_SUSPEND_FLAG -666 //base lib void sq_base_register(HSQUIRRELVM v); struct SQExceptionTrap{ SQExceptionTrap() {} SQExceptionTrap(SQInteger ss, SQInteger stackbase,SQInstruction *ip, SQInteger ex_target){ _stacksize = ss; _stackbase = stackbase; _ip = ip; _extarget = ex_target;} SQExceptionTrap(const SQExceptionTrap &et) { (*this) = et; } SQInteger _stackbase; SQInteger _stacksize; SQInstruction *_ip; SQInteger _extarget; }; #define _INLINE #define STK(a) _stack._vals[_stackbase+(a)] #define TARGET _stack._vals[_stackbase+arg0] typedef sqvector ExceptionsTraps; struct SQVM : public CHAINABLE_OBJ { struct VarArgs { VarArgs() { size = 0; base = 0; } unsigned short size; unsigned short base; }; struct CallInfo{ //CallInfo() { _generator._type = OT_NULL;} SQInstruction *_ip; SQObjectPtr *_literals; SQObjectPtr _closure; SQGenerator *_generator; SQInt32 _etraps; SQInt32 _prevstkbase; SQInt32 _prevtop; SQInt32 _target; SQInt32 _ncalls; SQBool _root; VarArgs _vargs; }; typedef sqvector CallInfoVec; public: enum ExecutionType { ET_CALL, ET_RESUME_GENERATOR, ET_RESUME_VM, ET_RESUME_THROW_VM, ET_RESUME_OPENTTD }; SQVM(SQSharedState *ss); ~SQVM(); bool Init(SQVM *friendvm, SQInteger stacksize); bool Execute(SQObjectPtr &func, SQInteger target, SQInteger nargs, SQInteger stackbase, SQObjectPtr &outres, SQBool raiseerror, ExecutionType et = ET_CALL); //starts a native call return when the NATIVE closure returns bool CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger stackbase, SQObjectPtr &retval,bool &suspend); //starts a SQUIRREL call in the same "Execution loop" bool StartCall(SQClosure *closure, SQInteger target, SQInteger nargs, SQInteger stackbase, bool tailcall); bool CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor); //call a generic closure pure SQUIRREL or NATIVE bool Call(SQObjectPtr &closure, SQInteger nparams, SQInteger stackbase, SQObjectPtr &outres,SQBool raiseerror,SQBool can_suspend); SQRESULT Suspend(); void CallDebugHook(SQInteger type,SQInteger forcedline=0); void CallErrorHandler(SQObjectPtr &e); bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, bool fetchroot); bool FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw); bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, bool fetchroot); bool NewSlot(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val,bool bstatic); bool DeleteSlot(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &res); bool Clone(const SQObjectPtr &self, SQObjectPtr &target); bool ObjCmp(const SQObjectPtr &o1, const SQObjectPtr &o2,SQInteger &res); bool StringCat(const SQObjectPtr &str, const SQObjectPtr &obj, SQObjectPtr &dest); bool IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res); void ToString(const SQObjectPtr &o,SQObjectPtr &res); SQString *PrintObjVal(const SQObject &o); void Raise_Error(const SQChar *s, ...); void Raise_Error(SQObjectPtr &desc); void Raise_IdxError(const SQObject &o); void Raise_CompareError(const SQObject &o1, const SQObject &o2); void Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type); void TypeOf(const SQObjectPtr &obj1, SQObjectPtr &dest); bool CallMetaMethod(SQDelegable *del, SQMetaMethod mm, SQInteger nparams, SQObjectPtr &outres); bool ArithMetaMethod(SQInteger op, const SQObjectPtr &o1, const SQObjectPtr &o2, SQObjectPtr &dest); bool Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval); //new stuff _INLINE bool ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); _INLINE bool BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2); _INLINE bool NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o1); _INLINE bool CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res); bool CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func); bool GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &idx,CallInfo *ci); bool CLASS_OP(SQObjectPtr &target,SQInteger base,SQInteger attrs); bool GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target); //return true if the loop is finished bool FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump); bool DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2); _INLINE bool LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); _INLINE bool PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr); _INLINE bool DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix); void PopVarArgs(VarArgs &vargs); void ClearStack(SQInteger last_top); #ifdef _DEBUG_DUMP void dumpstack(SQInteger stackbase=-1, bool dumpall = false); #endif #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); #endif void Finalize(); void GrowCallStack() { SQInteger newsize = _alloccallsstacksize*2; _callstackdata.resize(newsize); _callsstack = &_callstackdata[0]; _alloccallsstacksize = newsize; } void Release(){ sq_delete(this,SQVM); } //does nothing //////////////////////////////////////////////////////////////////////////// //stack functions for the api void Remove(SQInteger n); bool IsFalse(SQObjectPtr &o); void Pop(); void Pop(SQInteger n); void Push(const SQObjectPtr &o); SQObjectPtr &Top(); SQObjectPtr &PopGet(); SQObjectPtr &GetUp(SQInteger n); SQObjectPtr &GetAt(SQInteger n); SQObjectPtrVec _stack; SQObjectPtrVec _vargsstack; SQInteger _top; SQInteger _stackbase; SQObjectPtr _roottable; SQObjectPtr _lasterror; SQObjectPtr _errorhandler; SQObjectPtr _debughook; SQObjectPtr temp_reg; CallInfo* _callsstack; SQInteger _callsstacksize; SQInteger _alloccallsstacksize; sqvector _callstackdata; ExceptionsTraps _etraps; CallInfo *ci; void *_foreignptr; //VMs sharing the same state SQSharedState *_sharedstate; SQInteger _nnativecalls; //suspend infos SQBool _suspended; SQBool _suspended_root; SQInteger _suspended_target; SQInteger _suspended_traps; VarArgs _suspend_varargs; SQBool _can_suspend; SQInteger _ops_till_suspend; SQBool _in_stackoverflow; bool ShouldSuspend() { return _can_suspend && _ops_till_suspend <= 0; } void DecreaseOps(SQInteger amount) { if (_ops_till_suspend - amount < _ops_till_suspend) _ops_till_suspend -= amount; } }; struct AutoDec{ AutoDec(SQInteger *n) { _n = n; } ~AutoDec() { (*_n)--; } SQInteger *_n; }; inline SQObjectPtr &stack_get(HSQUIRRELVM v,SQInteger idx){return ((idx>=0)?(v->GetAt(idx+v->_stackbase-1)):(v->GetUp(idx)));} #define _ss(_vm_) (_vm_)->_sharedstate #ifndef NO_GARBAGE_COLLECTOR #define _opt_ss(_vm_) (_vm_)->_sharedstate #else #define _opt_ss(_vm_) NULL #endif #define PUSH_CALLINFO(v,nci){ \ if(v->_callsstacksize == v->_alloccallsstacksize) { \ if (v->_callsstacksize > 65535 && !v->_in_stackoverflow) {\ v->_in_stackoverflow = true; \ v->Raise_Error("stack overflow");\ v->CallErrorHandler(v->_lasterror);\ return false;\ }\ v->GrowCallStack(); \ } \ v->ci = &v->_callsstack[v->_callsstacksize]; \ *(v->ci) = nci; \ v->_callsstacksize++; \ } #define POP_CALLINFO(v){ \ v->_callsstacksize--; \ v->ci->_closure.Null(); \ if(v->_callsstacksize) \ v->ci = &v->_callsstack[v->_callsstacksize-1] ; \ else \ v->ci = NULL; \ } #endif //_SQVM_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqarray.h0000644000000000000000000000455412627373445021626 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQARRAY_H_ #define _SQARRAY_H_ struct SQArray : public CHAINABLE_OBJ { private: SQArray(SQSharedState *ss,SQInteger nsize){_values.resize(nsize); INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this);} ~SQArray() { REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } public: static SQArray* Create(SQSharedState *ss,SQInteger nInitialSize){ SQArray *newarray=(SQArray*)SQ_MALLOC(sizeof(SQArray)); new (newarray) SQArray(ss,nInitialSize); return newarray; } #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); #endif void Finalize(){ _values.resize(0); } bool Get(const SQInteger nidx,SQObjectPtr &val) { if(nidx>=0 && nidx<(SQInteger)_values.size()){ SQObjectPtr &o = _values[nidx]; val = _realval(o); return true; } else return false; } bool Set(const SQInteger nidx,const SQObjectPtr &val) { if(nidx>=0 && nidx<(SQInteger)_values.size()){ _values[nidx]=val; return true; } else return false; } SQInteger Next(const SQObjectPtr &refpos,SQObjectPtr &outkey,SQObjectPtr &outval) { SQUnsignedInteger idx=TranslateIndex(refpos); while(idx<_values.size()){ //first found outkey=(SQInteger)idx; SQObjectPtr &o = _values[idx]; outval = _realval(o); //return idx for the next iteration return ++idx; } //nothing to iterate anymore return -1; } SQArray *Clone(){SQArray *anew=Create(_opt_ss(this),Size()); anew->_values.copy(_values); return anew; } SQInteger Size() const {return _values.size();} void Resize(SQInteger size,SQObjectPtr &fill = _null_) { _values.resize(size,fill); ShrinkIfNeeded(); } void Reserve(SQInteger size) { _values.reserve(size); } void Append(const SQObject &o){_values.push_back(o);} void Extend(const SQArray *a); SQObjectPtr &Top(){return _values.top();} void Pop(){_values.pop_back(); ShrinkIfNeeded(); } bool Insert(SQInteger idx,const SQObject &val){ if(idx < 0 || idx > (SQInteger)_values.size()) return false; _values.insert(idx,val); return true; } void ShrinkIfNeeded() { if(_values.size() <= _values.capacity()>>2) //shrink the array _values.shrinktofit(); } bool Remove(SQInteger idx){ if(idx < 0 || idx >= (SQInteger)_values.size()) return false; _values.remove(idx); ShrinkIfNeeded(); return true; } void Release() { sq_delete(this,SQArray); } SQObjectPtrVec _values; }; #endif //_SQARRAY_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqfuncstate.h0000644000000000000000000000571012627373445022477 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQFUNCSTATE_H_ #define _SQFUNCSTATE_H_ /////////////////////////////////// #include "squtils.h" struct SQFuncState { SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed); ~SQFuncState(); #ifdef _DEBUG_DUMP void Dump(SQFunctionProto *func); #endif void Error(const SQChar *err); SQFuncState *PushChildState(SQSharedState *ss); void PopChildState(); void AddInstruction(SQOpcode _op,SQInteger arg0=0,SQInteger arg1=0,SQInteger arg2=0,SQInteger arg3=0){SQInstruction i(_op,arg0,arg1,arg2,arg3);AddInstruction(i);} void AddInstruction(SQInstruction &i); void SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2=0,SQInteger arg3=0); void SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val); SQInstruction &GetInstruction(SQInteger pos){return _instructions[pos];} void PopInstructions(SQInteger size){for(SQInteger i=0;i _childstates; SQInteger GetConstant(const SQObject &cons); private: CompilerErrorFunc _errfunc; void *_errtarget; }; #endif //_SQFUNCSTATE_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqclass.h0000644000000000000000000001041112627373445021602 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQCLASS_H_ #define _SQCLASS_H_ struct SQInstance; struct SQClassMember { SQClassMember(){} SQClassMember(const SQClassMember &o) { val = o.val; attrs = o.attrs; } SQObjectPtr val; SQObjectPtr attrs; }; typedef sqvector SQClassMemberVec; #define MEMBER_TYPE_METHOD 0x01000000 #define MEMBER_TYPE_FIELD 0x02000000 #define _ismethod(o) (_integer(o)&MEMBER_TYPE_METHOD) #define _isfield(o) (_integer(o)&MEMBER_TYPE_FIELD) #define _make_method_idx(i) ((SQInteger)(MEMBER_TYPE_METHOD|i)) #define _make_field_idx(i) ((SQInteger)(MEMBER_TYPE_FIELD|i)) #define _member_type(o) (_integer(o)&0xFF000000) #define _member_idx(o) (_integer(o)&0x00FFFFFF) struct SQClass : public CHAINABLE_OBJ { SQClass(SQSharedState *ss,SQClass *base); public: static SQClass* Create(SQSharedState *ss,SQClass *base) { SQClass *newclass = (SQClass *)SQ_MALLOC(sizeof(SQClass)); new (newclass) SQClass(ss, base); return newclass; } ~SQClass(); bool NewSlot(SQSharedState *ss, const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic); bool Get(const SQObjectPtr &key,SQObjectPtr &val) { if(_members->Get(key,val)) { if(_isfield(val)) { SQObjectPtr &o = _defaultvalues[_member_idx(val)].val; val = _realval(o); } else { val = _methods[_member_idx(val)].val; } return true; } return false; } bool SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val); bool GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval); void Lock() { _locked = true; if(_base) _base->Lock(); } void Release() { if (_hook) { _hook(_typetag,0);} sq_delete(this, SQClass); } void Finalize(); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable ** ); #endif SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); SQInstance *CreateInstance(); SQTable *_members; SQClass *_base; SQClassMemberVec _defaultvalues; SQClassMemberVec _methods; SQObjectPtrVec _metamethods; SQObjectPtr _attributes; SQUserPointer _typetag; SQRELEASEHOOK _hook; bool _locked; SQInteger _udsize; }; #define calcinstancesize(_theclass_) \ (_theclass_->_udsize + sizeof(SQInstance) + (sizeof(SQObjectPtr)*(_theclass_->_defaultvalues.size()>0?_theclass_->_defaultvalues.size()-1:0))) struct SQInstance : public SQDelegable { void Init(SQSharedState *ss); SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize); SQInstance(SQSharedState *ss, SQInstance *c, SQInteger memsize); public: static SQInstance* Create(SQSharedState *ss,SQClass *theclass) { SQInteger size = calcinstancesize(theclass); SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); new (newinst) SQInstance(ss, theclass,size); if(theclass->_udsize) { newinst->_userpointer = ((unsigned char *)newinst) + (size - theclass->_udsize); } return newinst; } SQInstance *Clone(SQSharedState *ss) { SQInteger size = calcinstancesize(_class); SQInstance *newinst = (SQInstance *)SQ_MALLOC(size); new (newinst) SQInstance(ss, this,size); if(_class->_udsize) { newinst->_userpointer = ((unsigned char *)newinst) + (size - _class->_udsize); } return newinst; } ~SQInstance(); bool Get(const SQObjectPtr &key,SQObjectPtr &val) { if(_class->_members->Get(key,val)) { if(_isfield(val)) { SQObjectPtr &o = _values[_member_idx(val)]; val = _realval(o); } else { val = _class->_methods[_member_idx(val)].val; } return true; } return false; } bool Set(const SQObjectPtr &key,const SQObjectPtr &val) { SQObjectPtr idx; if(_class->_members->Get(key,idx) && _isfield(idx)) { _values[_member_idx(idx)] = val; return true; } return false; } void Release() { _uiRef++; try { if (_hook) { _hook(_userpointer,0);} } catch (...) { _uiRef--; if (_uiRef == 0) { SQInteger size = _memsize; this->~SQInstance(); SQ_FREE(this, size); } throw; } _uiRef--; if(_uiRef > 0) return; SQInteger size = _memsize; this->~SQInstance(); SQ_FREE(this, size); } void Finalize(); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable ** ); #endif bool InstanceOf(SQClass *trg); bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); SQClass *_class; SQUserPointer _userpointer; SQRELEASEHOOK _hook; SQInteger _memsize; SQObjectPtr _values[1]; }; #endif //_SQCLASS_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqlexer.cpp0000644000000000000000000002652412627373445022163 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include "sqpcheader.h" #include #include "sqtable.h" #include "sqstring.h" #include "sqcompiler.h" #include "sqlexer.h" #include "../../../string_func.h" #include "../../../safeguards.h" #define CUR_CHAR (_currdata) #define RETURN_TOKEN(t) { _prevtoken = _curtoken; _curtoken = t; return t;} #define IS_EOB() (CUR_CHAR <= SQUIRREL_EOB) #define NEXT() {Next();_currentcolumn++;} #define ADD_KEYWORD(key,id) _keywords->NewSlot( SQString::Create(ss, #key) ,SQInteger(id)) SQLexer::~SQLexer() { _keywords->Release(); } void SQLexer::APPEND_CHAR(WChar c) { char buf[4]; size_t chars = Utf8Encode(buf, c); for (size_t i = 0; i < chars; i++) { _longstr.push_back(buf[i]); } } SQLexer::SQLexer(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,CompilerErrorFunc efunc,void *ed) { _errfunc = efunc; _errtarget = ed; _sharedstate = ss; _keywords = SQTable::Create(ss, 26); ADD_KEYWORD(while, TK_WHILE); ADD_KEYWORD(do, TK_DO); ADD_KEYWORD(if, TK_IF); ADD_KEYWORD(else, TK_ELSE); ADD_KEYWORD(break, TK_BREAK); ADD_KEYWORD(continue, TK_CONTINUE); ADD_KEYWORD(return, TK_RETURN); ADD_KEYWORD(null, TK_NULL); ADD_KEYWORD(function, TK_FUNCTION); ADD_KEYWORD(local, TK_LOCAL); ADD_KEYWORD(for, TK_FOR); ADD_KEYWORD(foreach, TK_FOREACH); ADD_KEYWORD(in, TK_IN); ADD_KEYWORD(typeof, TK_TYPEOF); ADD_KEYWORD(delegate, TK_DELEGATE); ADD_KEYWORD(delete, TK_DELETE); ADD_KEYWORD(try, TK_TRY); ADD_KEYWORD(catch, TK_CATCH); ADD_KEYWORD(throw, TK_THROW); ADD_KEYWORD(clone, TK_CLONE); ADD_KEYWORD(yield, TK_YIELD); ADD_KEYWORD(resume, TK_RESUME); ADD_KEYWORD(switch, TK_SWITCH); ADD_KEYWORD(case, TK_CASE); ADD_KEYWORD(default, TK_DEFAULT); ADD_KEYWORD(this, TK_THIS); ADD_KEYWORD(parent,TK_PARENT); ADD_KEYWORD(class,TK_CLASS); ADD_KEYWORD(extends,TK_EXTENDS); ADD_KEYWORD(constructor,TK_CONSTRUCTOR); ADD_KEYWORD(instanceof,TK_INSTANCEOF); ADD_KEYWORD(vargc,TK_VARGC); ADD_KEYWORD(vargv,TK_VARGV); ADD_KEYWORD(true,TK_TRUE); ADD_KEYWORD(false,TK_FALSE); ADD_KEYWORD(static,TK_STATIC); ADD_KEYWORD(enum,TK_ENUM); ADD_KEYWORD(const,TK_CONST); _readf = rg; _up = up; _lasttokenline = _currentline = 1; _currentcolumn = 0; _prevtoken = -1; _curtoken = -1; _svalue = NULL; _nvalue = 0; _fvalue = 0; Next(); } NORETURN void SQLexer::Error(const SQChar *err) { _errfunc(_errtarget,err); } void SQLexer::Next() { WChar t = _readf(_up); if(t > MAX_CHAR) Error("Invalid character"); if(t != 0) { _currdata = t; return; } _currdata = SQUIRREL_EOB; } const SQChar *SQLexer::Tok2Str(SQInteger tok) { SQObjectPtr itr, key, val; SQInteger nitr; while((nitr = _keywords->Next(false,itr, key, val)) != -1) { itr = (SQInteger)nitr; if(((SQInteger)_integer(val)) == tok) return _stringval(key); } return NULL; } void SQLexer::LexBlockComment() { bool done = false; while(!done) { switch(CUR_CHAR) { case '*': { NEXT(); if(CUR_CHAR == '/') { done = true; NEXT(); }}; continue; case '\n': _currentline++; NEXT(); continue; case SQUIRREL_EOB: Error("missing \"*/\" in comment"); default: NEXT(); } } } SQInteger SQLexer::Lex() { _lasttokenline = _currentline; while(CUR_CHAR != SQUIRREL_EOB) { switch(CUR_CHAR){ case '\t': case '\r': case ' ': NEXT(); continue; case '\n': _currentline++; _prevtoken=_curtoken; _curtoken='\n'; NEXT(); _currentcolumn=1; continue; case '/': NEXT(); switch(CUR_CHAR){ case '*': NEXT(); LexBlockComment(); continue; case '/': do { NEXT(); } while (CUR_CHAR != '\n' && (!IS_EOB())); continue; case '=': NEXT(); RETURN_TOKEN(TK_DIVEQ); case '>': NEXT(); RETURN_TOKEN(TK_ATTR_CLOSE); default: RETURN_TOKEN('/'); } case '=': NEXT(); if (CUR_CHAR != '='){ RETURN_TOKEN('=') } else { NEXT(); RETURN_TOKEN(TK_EQ); } case '<': NEXT(); if ( CUR_CHAR == '=' ) { NEXT(); RETURN_TOKEN(TK_LE) } else if ( CUR_CHAR == '-' ) { NEXT(); RETURN_TOKEN(TK_NEWSLOT); } else if ( CUR_CHAR == '<' ) { NEXT(); RETURN_TOKEN(TK_SHIFTL); } else if ( CUR_CHAR == '/' ) { NEXT(); RETURN_TOKEN(TK_ATTR_OPEN); } //else if ( CUR_CHAR == '[' ) { NEXT(); ReadMultilineString(); RETURN_TOKEN(TK_STRING_LITERAL); } else { RETURN_TOKEN('<') } case '>': NEXT(); if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_GE);} else if(CUR_CHAR == '>'){ NEXT(); if(CUR_CHAR == '>'){ NEXT(); RETURN_TOKEN(TK_USHIFTR); } RETURN_TOKEN(TK_SHIFTR); } else { RETURN_TOKEN('>') } case '!': NEXT(); if (CUR_CHAR != '='){ RETURN_TOKEN('!')} else { NEXT(); RETURN_TOKEN(TK_NE); } case '@': { SQInteger stype; NEXT(); if(CUR_CHAR != '"') Error("string expected"); if((stype=ReadString('"',true))!=-1) { RETURN_TOKEN(stype); } Error("error parsing the string"); } case '"': case '\'': { SQInteger stype; if((stype=ReadString(CUR_CHAR,false))!=-1){ RETURN_TOKEN(stype); } Error("error parsing the string"); } case '{': case '}': case '(': case ')': case '[': case ']': case ';': case ',': case '?': case '^': case '~': {SQInteger ret = CUR_CHAR; NEXT(); RETURN_TOKEN(ret); } case '.': NEXT(); if (CUR_CHAR != '.'){ RETURN_TOKEN('.') } NEXT(); if (CUR_CHAR != '.'){ Error("invalid token '..'"); } NEXT(); RETURN_TOKEN(TK_VARPARAMS); case '&': NEXT(); if (CUR_CHAR != '&'){ RETURN_TOKEN('&') } else { NEXT(); RETURN_TOKEN(TK_AND); } case '|': NEXT(); if (CUR_CHAR != '|'){ RETURN_TOKEN('|') } else { NEXT(); RETURN_TOKEN(TK_OR); } case ':': NEXT(); if (CUR_CHAR != ':'){ RETURN_TOKEN(':') } else { NEXT(); RETURN_TOKEN(TK_DOUBLE_COLON); } case '*': NEXT(); if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MULEQ);} else RETURN_TOKEN('*'); case '%': NEXT(); if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MODEQ);} else RETURN_TOKEN('%'); case '-': NEXT(); if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_MINUSEQ);} else if (CUR_CHAR == '-'){ NEXT(); RETURN_TOKEN(TK_MINUSMINUS);} else RETURN_TOKEN('-'); case '+': NEXT(); if (CUR_CHAR == '='){ NEXT(); RETURN_TOKEN(TK_PLUSEQ);} else if (CUR_CHAR == '+'){ NEXT(); RETURN_TOKEN(TK_PLUSPLUS);} else RETURN_TOKEN('+'); case SQUIRREL_EOB: return 0; default:{ if (isdigit(CUR_CHAR)) { SQInteger ret = ReadNumber(); RETURN_TOKEN(ret); } else if (isalpha(CUR_CHAR) || CUR_CHAR == '_') { SQInteger t = ReadID(); RETURN_TOKEN(t); } else { SQInteger c = CUR_CHAR; if (iscntrl((int)c)) Error("unexpected character(control)"); NEXT(); RETURN_TOKEN(c); } RETURN_TOKEN(0); } } } return 0; } SQInteger SQLexer::GetIDType(SQChar *s) { SQObjectPtr t; if(_keywords->Get(SQString::Create(_sharedstate, s), t)) { return SQInteger(_integer(t)); } return TK_IDENTIFIER; } SQInteger SQLexer::ReadString(WChar ndelim,bool verbatim) { INIT_TEMP_STRING(); NEXT(); if(IS_EOB()) return -1; for(;;) { while(CUR_CHAR != ndelim) { switch(CUR_CHAR) { case SQUIRREL_EOB: Error("unfinished string"); return -1; case '\n': if(!verbatim) Error("newline in a constant"); APPEND_CHAR(CUR_CHAR); NEXT(); _currentline++; break; case '\\': if(verbatim) { APPEND_CHAR('\\'); NEXT(); } else { NEXT(); switch(CUR_CHAR) { case 'x': NEXT(); { if(!isxdigit(CUR_CHAR)) Error("hexadecimal number expected"); const SQInteger maxdigits = 4; SQChar temp[maxdigits+1]; SQInteger n = 0; while(isxdigit(CUR_CHAR) && n < maxdigits) { temp[n] = CUR_CHAR; n++; NEXT(); } temp[n] = 0; SQChar *sTemp; APPEND_CHAR((SQChar)strtoul(temp,&sTemp,16)); } break; case 't': APPEND_CHAR('\t'); NEXT(); break; case 'a': APPEND_CHAR('\a'); NEXT(); break; case 'b': APPEND_CHAR('\b'); NEXT(); break; case 'n': APPEND_CHAR('\n'); NEXT(); break; case 'r': APPEND_CHAR('\r'); NEXT(); break; case 'v': APPEND_CHAR('\v'); NEXT(); break; case 'f': APPEND_CHAR('\f'); NEXT(); break; case '0': APPEND_CHAR('\0'); NEXT(); break; case '\\': APPEND_CHAR('\\'); NEXT(); break; case '"': APPEND_CHAR('"'); NEXT(); break; case '\'': APPEND_CHAR('\''); NEXT(); break; default: Error("unrecognised escaper char"); break; } } break; default: APPEND_CHAR(CUR_CHAR); NEXT(); } } NEXT(); if(verbatim && CUR_CHAR == '"') { //double quotation APPEND_CHAR(CUR_CHAR); NEXT(); } else { break; } } TERMINATE_BUFFER(); SQInteger len = _longstr.size()-1; if(ndelim == '\'') { if(len == 0) Error("empty constant"); if(len > 1) Error("constant too long"); _nvalue = _longstr[0]; return TK_INTEGER; } _svalue = &_longstr[0]; return TK_STRING_LITERAL; } void LexHexadecimal(const SQChar *s,SQUnsignedInteger *res) { *res = 0; while(*s != 0) { if(isdigit(*s)) *res = (*res)*16+((*s++)-'0'); else if(isxdigit(*s)) *res = (*res)*16+(toupper(*s++)-'A'+10); else { assert(0); } } } void LexInteger(const SQChar *s,SQUnsignedInteger *res) { *res = 0; while(*s != 0) { *res = (*res)*10+((*s++)-'0'); } } SQInteger scisodigit(SQChar c) { return c >= '0' && c <= '7'; } void LexOctal(const SQChar *s,SQUnsignedInteger *res) { *res = 0; while(*s != 0) { if(scisodigit(*s)) *res = (*res)*8+((*s++)-'0'); else { assert(0); } } } SQInteger isexponent(SQInteger c) { return c == 'e' || c=='E'; } #define MAX_HEX_DIGITS (sizeof(SQInteger)*2) SQInteger SQLexer::ReadNumber() { #define TINT 1 #define TFLOAT 2 #define THEX 3 #define TSCIENTIFIC 4 #define TOCTAL 5 SQInteger type = TINT, firstchar = CUR_CHAR; SQChar *sTemp; INIT_TEMP_STRING(); NEXT(); if(firstchar == '0' && (toupper(CUR_CHAR) == 'X' || scisodigit(CUR_CHAR)) ) { if(scisodigit(CUR_CHAR)) { type = TOCTAL; while(scisodigit(CUR_CHAR)) { APPEND_CHAR(CUR_CHAR); NEXT(); } if(isdigit(CUR_CHAR)) Error("invalid octal number"); } else { NEXT(); type = THEX; while(isxdigit(CUR_CHAR)) { APPEND_CHAR(CUR_CHAR); NEXT(); } if(_longstr.size() > MAX_HEX_DIGITS) Error("too many digits for an Hex number"); } } else { APPEND_CHAR((int)firstchar); while (CUR_CHAR == '.' || isdigit(CUR_CHAR) || isexponent(CUR_CHAR)) { if(CUR_CHAR == '.' || isexponent(CUR_CHAR)) type = TFLOAT; if(isexponent(CUR_CHAR)) { if(type != TFLOAT) Error("invalid numeric format"); type = TSCIENTIFIC; APPEND_CHAR(CUR_CHAR); NEXT(); if(CUR_CHAR == '+' || CUR_CHAR == '-'){ APPEND_CHAR(CUR_CHAR); NEXT(); } if(!isdigit(CUR_CHAR)) Error("exponent expected"); } APPEND_CHAR(CUR_CHAR); NEXT(); } } TERMINATE_BUFFER(); switch(type) { case TSCIENTIFIC: case TFLOAT: _fvalue = (SQFloat)strtod(&_longstr[0],&sTemp); return TK_FLOAT; case TINT: LexInteger(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; case THEX: LexHexadecimal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; case TOCTAL: LexOctal(&_longstr[0],(SQUnsignedInteger *)&_nvalue); return TK_INTEGER; } return 0; } SQInteger SQLexer::ReadID() { SQInteger res; INIT_TEMP_STRING(); do { APPEND_CHAR(CUR_CHAR); NEXT(); } while(isalnum(CUR_CHAR) || CUR_CHAR == '_'); TERMINATE_BUFFER(); res = GetIDType(&_longstr[0]); if(res == TK_IDENTIFIER || res == TK_CONSTRUCTOR) { _svalue = &_longstr[0]; } return res; } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqdebug.cpp0000644000000000000000000000702612627373445022126 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include #include "sqpcheader.h" #include "sqvm.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "sqstring.h" #include "../../../core/alloc_func.hpp" #include "../../../string_func.h" #include "../../../safeguards.h" SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger level,SQFunctionInfo *fi) { SQInteger cssize = v->_callsstacksize; if (cssize > level) { SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; if(sq_isclosure(ci._closure)) { SQClosure *c = _closure(ci._closure); SQFunctionProto *proto = _funcproto(c->_function); fi->funcid = proto; fi->name = type(proto->_name) == OT_STRING?_stringval(proto->_name):"unknown"; fi->source = type(proto->_name) == OT_STRING?_stringval(proto->_sourcename):"unknown"; return SQ_OK; } } return sq_throwerror(v,"the object is not a closure"); } SQRESULT sq_stackinfos(HSQUIRRELVM v, SQInteger level, SQStackInfos *si) { SQInteger cssize = v->_callsstacksize; if (cssize > level) { memset(si, 0, sizeof(SQStackInfos)); SQVM::CallInfo &ci = v->_callsstack[cssize-level-1]; switch (type(ci._closure)) { case OT_CLOSURE:{ SQFunctionProto *func = _funcproto(_closure(ci._closure)->_function); if (type(func->_name) == OT_STRING) si->funcname = _stringval(func->_name); if (type(func->_sourcename) == OT_STRING) si->source = _stringval(func->_sourcename); si->line = func->GetLine(ci._ip); } break; case OT_NATIVECLOSURE: si->source = "NATIVE"; si->funcname = "unknown"; if(type(_nativeclosure(ci._closure)->_name) == OT_STRING) si->funcname = _stringval(_nativeclosure(ci._closure)->_name); si->line = -1; break; default: break; //shutup compiler } return SQ_OK; } return SQ_ERROR; } void SQVM::Raise_Error(const SQChar *s, ...) { va_list vl; va_start(vl, s); size_t len = strlen(s)+(NUMBER_MAX_CHAR*2); char *buffer = MallocT(len + 1); vseprintf(buffer, buffer + len, s, vl); va_end(vl); _lasterror = SQString::Create(_ss(this),buffer,-1); free(buffer); } void SQVM::Raise_Error(SQObjectPtr &desc) { _lasterror = desc; } SQString *SQVM::PrintObjVal(const SQObject &o) { char buf[NUMBER_MAX_CHAR+1]; switch(type(o)) { case OT_STRING: return _string(o); case OT_INTEGER: seprintf(buf, lastof(buf), OTTD_PRINTF64, _integer(o)); return SQString::Create(_ss(this), buf); case OT_FLOAT: seprintf(buf, lastof(buf), "%.14g", _float(o)); return SQString::Create(_ss(this), buf); default: return SQString::Create(_ss(this), GetTypeName(o)); } } void SQVM::Raise_IdxError(const SQObject &o) { SQObjectPtr oval = PrintObjVal(o); Raise_Error("the index '%.50s' does not exist", _stringval(oval)); } void SQVM::Raise_CompareError(const SQObject &o1, const SQObject &o2) { SQObjectPtr oval1 = PrintObjVal(o1), oval2 = PrintObjVal(o2); Raise_Error("comparsion between '%.50s' and '%.50s'", _stringval(oval1), _stringval(oval2)); } void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger type) { SQObjectPtr exptypes = SQString::Create(_ss(this), "", -1); SQInteger found = 0; for(SQInteger i=0; i<16; i++) { SQInteger mask = 0x00000001 << i; if(typemask & (mask)) { if(found>0) StringCat(exptypes,SQString::Create(_ss(this), "|", -1), exptypes); found ++; StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); } } Raise_Error("parameter %d has an invalid type '%s' ; expected: '%s'", nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqvm.cpp0000644000000000000000000013341412627373445021463 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include #include "sqpcheader.h" #include #include "sqopcodes.h" #include "sqfuncproto.h" #include "sqvm.h" #include "sqclosure.h" #include "sqstring.h" #include "sqtable.h" #include "squserdata.h" #include "sqarray.h" #include "sqclass.h" #include "../../../string_func.h" #include "../../../safeguards.h" #define TOP() (_stack._vals[_top-1]) #define CLEARSTACK(_last_top) { if((_last_top) >= _top) ClearStack(_last_top); } void SQVM::ClearStack(SQInteger last_top) { SQObjectType tOldType; SQObjectValue unOldVal; while (last_top >= _top) { SQObjectPtr &o = _stack._vals[last_top--]; tOldType = o._type; unOldVal = o._unVal; o._type = OT_NULL; o._unVal.pUserPointer = NULL; __Release(tOldType,unOldVal); } } bool SQVM::BW_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) { SQInteger res; SQInteger i1 = _integer(o1), i2 = _integer(o2); if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) { switch(op) { case BW_AND: res = i1 & i2; break; case BW_OR: res = i1 | i2; break; case BW_XOR: res = i1 ^ i2; break; case BW_SHIFTL: res = i1 << i2; break; case BW_SHIFTR: res = i1 >> i2; break; case BW_USHIFTR:res = (SQInteger)(*((SQUnsignedInteger*)&i1) >> i2); break; default: { Raise_Error("internal vm error bitwise op failed"); return false; } } } else { Raise_Error("bitwise op between '%s' and '%s'",GetTypeName(o1),GetTypeName(o2)); return false;} trg = res; return true; } bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,const SQObjectPtr &o2) { if(sq_isnumeric(o1) && sq_isnumeric(o2)) { if((type(o1)==OT_INTEGER) && (type(o2)==OT_INTEGER)) { SQInteger res, i1 = _integer(o1), i2 = _integer(o2); switch(op) { case '+': res = i1 + i2; break; case '-': res = i1 - i2; break; case '/': if(i2 == 0) { Raise_Error("division by zero"); return false; } res = i1 / i2; break; case '*': res = i1 * i2; break; case '%': if(i2 == 0) { Raise_Error("modulo by zero"); return false; } res = i1 % i2; break; default: res = 0xDEADBEEF; } trg = res; }else{ SQFloat res, f1 = tofloat(o1), f2 = tofloat(o2); switch(op) { case '+': res = f1 + f2; break; case '-': res = f1 - f2; break; case '/': res = f1 / f2; break; case '*': res = f1 * f2; break; case '%': res = SQFloat(fmod((double)f1,(double)f2)); break; default: res = 0x0f; } trg = res; } } else { if(op == '+' && (type(o1) == OT_STRING || type(o2) == OT_STRING)){ if(!StringCat(o1, o2, trg)) return false; } else if(!ArithMetaMethod(op,o1,o2,trg)) { Raise_Error("arith op %c on between '%s' and '%s'",op,GetTypeName(o1),GetTypeName(o2)); return false; } } return true; } SQVM::SQVM(SQSharedState *ss) { _sharedstate=ss; _suspended = SQFalse; _suspended_target=-1; _suspended_root = SQFalse; _suspended_traps=0; _foreignptr=NULL; _nnativecalls=0; _lasterror = _null_; _errorhandler = _null_; _debughook = _null_; _can_suspend = false; _in_stackoverflow = false; _ops_till_suspend = 0; _callsstack = NULL; _callsstacksize = 0; _alloccallsstacksize = 0; _top = 0; _stackbase = 0; ci = NULL; INIT_CHAIN();ADD_TO_CHAIN(&_ss(this)->_gc_chain,this); } void SQVM::Finalize() { _roottable = _null_; _lasterror = _null_; _errorhandler = _null_; _debughook = _null_; temp_reg = _null_; _callstackdata.resize(0); SQInteger size=_stack.size(); for(SQInteger i=size - 1;i>=0;i--) _stack[i]=_null_; } SQVM::~SQVM() { Finalize(); //sq_free(_callsstack,_alloccallsstacksize*sizeof(CallInfo)); REMOVE_FROM_CHAIN(&_ss(this)->_gc_chain,this); } bool SQVM::ArithMetaMethod(SQInteger op,const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &dest) { SQMetaMethod mm; switch(op){ case '+': mm=MT_ADD; break; case '-': mm=MT_SUB; break; case '/': mm=MT_DIV; break; case '*': mm=MT_MUL; break; case '%': mm=MT_MODULO; break; default: mm = MT_ADD; assert(0); break; //shutup compiler } if(is_delegable(o1) && _delegable(o1)->_delegate) { Push(o1);Push(o2); return CallMetaMethod(_delegable(o1),mm,2,dest); } return false; } bool SQVM::NEG_OP(SQObjectPtr &trg,const SQObjectPtr &o) { switch(type(o)) { case OT_INTEGER: trg = -_integer(o); return true; case OT_FLOAT: trg = -_float(o); return true; case OT_TABLE: case OT_USERDATA: case OT_INSTANCE: if(_delegable(o)->_delegate) { Push(o); if(CallMetaMethod(_delegable(o), MT_UNM, 1, temp_reg)) { trg = temp_reg; return true; } } default:break; //shutup compiler } Raise_Error("attempt to negate a %s", GetTypeName(o)); return false; } #define _RET_SUCCEED(exp) { result = (exp); return true; } bool SQVM::ObjCmp(const SQObjectPtr &o1,const SQObjectPtr &o2,SQInteger &result) { if(type(o1)==type(o2)){ if(_rawval(o1)==_rawval(o2))_RET_SUCCEED(0); SQObjectPtr res; switch(type(o1)){ case OT_STRING: _RET_SUCCEED(strcmp(_stringval(o1),_stringval(o2))); case OT_INTEGER: /* FS#3954: wrong integer comparison */ _RET_SUCCEED((_integer(o1)<_integer(o2))?-1:(_integer(o1)==_integer(o2))?0:1); case OT_FLOAT: _RET_SUCCEED((_float(o1)<_float(o2))?-1:1); case OT_TABLE: case OT_USERDATA: case OT_INSTANCE: if(_delegable(o1)->_delegate) { Push(o1);Push(o2); if(CallMetaMethod(_delegable(o1),MT_CMP,2,res)) { if(type(res) != OT_INTEGER) { Raise_Error("_cmp must return an integer"); return false; } _RET_SUCCEED(_integer(res)) } } //continues through (no break needed) default: _RET_SUCCEED( _userpointer(o1) < _userpointer(o2)?-1:1 ); } assert(0); } else{ if(sq_isnumeric(o1) && sq_isnumeric(o2)){ if((type(o1)==OT_INTEGER) && (type(o2)==OT_FLOAT)) { if( _integer(o1)==_float(o2) ) { _RET_SUCCEED(0); } else if( _integer(o1)<_float(o2) ) { _RET_SUCCEED(-1); } _RET_SUCCEED(1); } else{ if( _float(o1)==_integer(o2) ) { _RET_SUCCEED(0); } else if( _float(o1)<_integer(o2) ) { _RET_SUCCEED(-1); } _RET_SUCCEED(1); } } else if(type(o1)==OT_NULL) {_RET_SUCCEED(-1);} else if(type(o2)==OT_NULL) {_RET_SUCCEED(1);} else { Raise_CompareError(o1,o2); return false; } } assert(0); _RET_SUCCEED(0); //cannot happen } bool SQVM::CMP_OP(CmpOP op, const SQObjectPtr &o1,const SQObjectPtr &o2,SQObjectPtr &res) { SQInteger r; if(ObjCmp(o1,o2,r)) { switch(op) { case CMP_G: res = (r > 0)?_true_:_false_; return true; case CMP_GE: res = (r >= 0)?_true_:_false_; return true; case CMP_L: res = (r < 0)?_true_:_false_; return true; case CMP_LE: res = (r <= 0)?_true_:_false_; return true; } assert(0); } return false; } void SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res) { char buf[64]; switch(type(o)) { case OT_STRING: res = o; return; case OT_FLOAT: seprintf(buf, lastof(buf),"%g",_float(o)); break; case OT_INTEGER: seprintf(buf, lastof(buf),OTTD_PRINTF64,_integer(o)); break; case OT_BOOL: seprintf(buf, lastof(buf),_integer(o)?"true":"false"); break; case OT_TABLE: case OT_USERDATA: case OT_INSTANCE: if(_delegable(o)->_delegate) { Push(o); if(CallMetaMethod(_delegable(o),MT_TOSTRING,1,res)) { if(type(res) == OT_STRING) return; //else keeps going to the default } } default: seprintf(buf, lastof(buf),"(%s : 0x%p)",GetTypeName(o),(void*)_rawval(o)); } res = SQString::Create(_ss(this),buf); } bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &dest) { SQObjectPtr a, b; ToString(str, a); ToString(obj, b); SQInteger l = _string(a)->_len , ol = _string(b)->_len; SQChar *s = _sp(l + ol + 1); memcpy(s, _stringval(a), (size_t)l); memcpy(s + l, _stringval(b), (size_t)ol); dest = SQString::Create(_ss(this), _spval, l + ol); return true; } void SQVM::TypeOf(const SQObjectPtr &obj1,SQObjectPtr &dest) { if(is_delegable(obj1) && _delegable(obj1)->_delegate) { Push(obj1); if(CallMetaMethod(_delegable(obj1),MT_TYPEOF,1,dest)) return; } dest = SQString::Create(_ss(this),GetTypeName(obj1)); } bool SQVM::Init(SQVM *friendvm, SQInteger stacksize) { _stack.resize(stacksize); _alloccallsstacksize = 4; _callstackdata.resize(_alloccallsstacksize); _callsstacksize = 0; _callsstack = &_callstackdata[0]; _stackbase = 0; _top = 0; if(!friendvm) _roottable = SQTable::Create(_ss(this), 0); else { _roottable = friendvm->_roottable; _errorhandler = friendvm->_errorhandler; _debughook = friendvm->_debughook; } sq_base_register(this); return true; } extern SQInstructionDesc g_InstrDesc[]; bool SQVM::StartCall(SQClosure *closure,SQInteger target,SQInteger args,SQInteger stackbase,bool tailcall) { SQFunctionProto *func = _funcproto(closure->_function); const SQInteger paramssize = func->_nparameters; const SQInteger newtop = stackbase + func->_stacksize; SQInteger nargs = args; if (paramssize != nargs) { SQInteger ndef = func->_ndefaultparams; SQInteger diff; if(ndef && nargs < paramssize && (diff = paramssize - nargs) <= ndef) { for(SQInteger n = ndef - diff; n < ndef; n++) { _stack._vals[stackbase + (nargs++)] = closure->_defaultparams[n]; } } else if(func->_varparams) { if (nargs < paramssize) { Raise_Error("wrong number of parameters"); return false; } for(SQInteger n = 0; n < nargs - paramssize; n++) { _vargsstack.push_back(_stack._vals[stackbase+paramssize+n]); _stack._vals[stackbase+paramssize+n] = _null_; } } else { Raise_Error("wrong number of parameters"); return false; } } if(type(closure->_env) == OT_WEAKREF) { _stack._vals[stackbase] = _weakref(closure->_env)->_obj; } if (!tailcall) { CallInfo lc; memset(&lc, 0, sizeof(lc)); lc._generator = NULL; lc._etraps = 0; lc._prevstkbase = (SQInt32) ( stackbase - _stackbase ); lc._target = (SQInt32) target; lc._prevtop = (SQInt32) (_top - _stackbase); lc._ncalls = 1; lc._root = SQFalse; PUSH_CALLINFO(this, lc); } else { ci->_ncalls++; } ci->_vargs.size = (SQInt32)(nargs - paramssize); ci->_vargs.base = (SQInt32)(_vargsstack.size()-(ci->_vargs.size)); ci->_closure = closure; ci->_literals = func->_literals; ci->_ip = func->_instructions; //grows the stack if needed if (((SQUnsignedInteger)newtop + (func->_stacksize<<1)) > _stack.size()) { _stack.resize(_stack.size() + (func->_stacksize<<1)); } _top = newtop; _stackbase = stackbase; if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) CallDebugHook('c'); return true; } bool SQVM::Return(SQInteger _arg0, SQInteger _arg1, SQObjectPtr &retval) { if (type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) for(SQInteger i=0;i_ncalls;i++) CallDebugHook('r'); SQBool broot = ci->_root; SQInteger last_top = _top; SQInteger target = ci->_target; SQInteger oldstackbase = _stackbase; _stackbase -= ci->_prevstkbase; _top = _stackbase + ci->_prevtop; if(ci->_vargs.size) PopVarArgs(ci->_vargs); POP_CALLINFO(this); if (broot) { if (_arg0 != MAX_FUNC_STACKSIZE) retval = _stack._vals[oldstackbase+_arg1]; else retval = _null_; } else { if(target != -1) { //-1 is when a class contructor ret value has to be ignored if (_arg0 != MAX_FUNC_STACKSIZE) STK(target) = _stack._vals[oldstackbase+_arg1]; else STK(target) = _null_; } } while (last_top > oldstackbase) _stack._vals[last_top--].Null(); assert(oldstackbase >= _stackbase); return broot?true:false; } #define _RET_ON_FAIL(exp) { if(!exp) return false; } bool SQVM::LOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) { _RET_ON_FAIL(ARITH_OP( op , target, a, incr)); a = target; return true; } bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObjectPtr &incr) { SQObjectPtr trg; _RET_ON_FAIL(ARITH_OP( op , trg, a, incr)); target = a; a = trg; return true; } bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix) { SQObjectPtr tmp, tself = self, tkey = key; if (!Get(tself, tkey, tmp, false, true)) { Raise_IdxError(tkey); return false; } _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) Set(tself, tkey, target,true); if (postfix) target = tmp; return true; } #define arg0 (_i_._arg0) #define arg1 (_i_._arg1) #define sarg1 (*(const_cast(&_i_._arg1))) #define arg2 (_i_._arg2) #define arg3 (_i_._arg3) #define sarg3 ((SQInteger)*((const signed char *)&_i_._arg3)) SQRESULT SQVM::Suspend() { if (_suspended) return sq_throwerror(this, "cannot suspend an already suspended vm"); if (_nnativecalls!=2) return sq_throwerror(this, "cannot suspend through native calls/metamethods"); return SQ_SUSPEND_FLAG; } void SQVM::PopVarArgs(VarArgs &vargs) { for(SQInteger n = 0; n< vargs.size; n++) _vargsstack.pop_back(); } #define _FINISH(howmuchtojump) {jump = howmuchtojump; return true; } bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr &o3,SQObjectPtr &o4,SQInteger arg_2,int exitpos,int &jump) { SQInteger nrefidx; switch(type(o1)) { case OT_TABLE: if((nrefidx = _table(o1)->Next(false,o4, o2, o3)) == -1) _FINISH(exitpos); o4 = (SQInteger)nrefidx; _FINISH(1); case OT_ARRAY: if((nrefidx = _array(o1)->Next(o4, o2, o3)) == -1) _FINISH(exitpos); o4 = (SQInteger) nrefidx; _FINISH(1); case OT_STRING: if((nrefidx = _string(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); o4 = (SQInteger)nrefidx; _FINISH(1); case OT_CLASS: if((nrefidx = _class(o1)->Next(o4, o2, o3)) == -1)_FINISH(exitpos); o4 = (SQInteger)nrefidx; _FINISH(1); case OT_USERDATA: case OT_INSTANCE: if(_delegable(o1)->_delegate) { SQObjectPtr itr; Push(o1); Push(o4); if(CallMetaMethod(_delegable(o1), MT_NEXTI, 2, itr)){ o4 = o2 = itr; if(type(itr) == OT_NULL) _FINISH(exitpos); if(!Get(o1, itr, o3, false,false)) { Raise_Error("_nexti returned an invalid idx"); return false; } _FINISH(1); } Raise_Error("_nexti failed"); return false; } break; case OT_GENERATOR: if(_generator(o1)->_state == SQGenerator::eDead) _FINISH(exitpos); if(_generator(o1)->_state == SQGenerator::eSuspended) { SQInteger idx = 0; if(type(o4) == OT_INTEGER) { idx = _integer(o4) + 1; } o2 = idx; o4 = idx; _generator(o1)->Resume(this, arg_2+1); _FINISH(0); } /* FALL THROUGH */ default: Raise_Error("cannot iterate %s", GetTypeName(o1)); } return false; //cannot be hit(just to avoid warnings) } bool SQVM::DELEGATE_OP(SQObjectPtr &trg,SQObjectPtr &o1,SQObjectPtr &o2) { if(type(o1) != OT_TABLE) { Raise_Error("delegating a '%s'", GetTypeName(o1)); return false; } switch(type(o2)) { case OT_TABLE: if(!_table(o1)->SetDelegate(_table(o2))){ Raise_Error("delegate cycle detected"); return false; } break; case OT_NULL: _table(o1)->SetDelegate(NULL); break; default: Raise_Error("using '%s' as delegate", GetTypeName(o2)); return false; break; } trg = o1; return true; } #define COND_LITERAL (arg3!=0?ci->_literals[arg1]:STK(arg1)) #define _GUARD(exp) { if(!exp) { Raise_Error(_lasterror); SQ_THROW();} } #define SQ_THROW() { goto exception_trap; } bool SQVM::CLOSURE_OP(SQObjectPtr &target, SQFunctionProto *func) { SQInteger nouters; SQClosure *closure = SQClosure::Create(_ss(this), func); if((nouters = func->_noutervalues)) { closure->_outervalues.reserve(nouters); for(SQInteger i = 0; i_outervalues[i]; switch(v._type){ case otSYMBOL: closure->_outervalues.push_back(_null_); if(!Get(_stack._vals[_stackbase]/*STK(0)*/, v._src, closure->_outervalues.top(), false,true)) {Raise_IdxError(v._src); return false; } break; case otLOCAL: closure->_outervalues.push_back(_stack._vals[_stackbase+_integer(v._src)]); break; case otOUTER: closure->_outervalues.push_back(_closure(ci->_closure)->_outervalues[_integer(v._src)]); break; } } } SQInteger ndefparams; if((ndefparams = func->_ndefaultparams)) { closure->_defaultparams.reserve(ndefparams); for(SQInteger i = 0; i < ndefparams; i++) { SQInteger spos = func->_defaultparams[i]; closure->_defaultparams.push_back(_stack._vals[_stackbase + spos]); } } target = closure; return true; } bool SQVM::GETVARGV_OP(SQObjectPtr &target,SQObjectPtr &index,CallInfo *ci) { if(ci->_vargs.size == 0) { Raise_Error("the function doesn't have var args"); return false; } if(!sq_isnumeric(index)){ Raise_Error("indexing 'vargv' with %s",GetTypeName(index)); return false; } SQInteger idx = tointeger(index); if(idx < 0 || idx >= ci->_vargs.size){ Raise_Error("vargv index out of range"); return false; } target = _vargsstack[ci->_vargs.base+idx]; return true; } bool SQVM::CLASS_OP(SQObjectPtr &target,SQInteger baseclass,SQInteger attributes) { SQClass *base = NULL; SQObjectPtr attrs; if(baseclass != -1) { if(type(_stack._vals[_stackbase+baseclass]) != OT_CLASS) { Raise_Error("trying to inherit from a %s",GetTypeName(_stack._vals[_stackbase+baseclass])); return false; } base = _class(_stack._vals[_stackbase + baseclass]); } if(attributes != MAX_FUNC_STACKSIZE) { attrs = _stack._vals[_stackbase+attributes]; } target = SQClass::Create(_ss(this),base); if(type(_class(target)->_metamethods[MT_INHERITED]) != OT_NULL) { int nparams = 2; SQObjectPtr ret; Push(target); Push(attrs); Call(_class(target)->_metamethods[MT_INHERITED],nparams,_top - nparams, ret, false, false); Pop(nparams); } _class(target)->_attributes = attrs; return true; } bool SQVM::IsEqual(SQObjectPtr &o1,SQObjectPtr &o2,bool &res) { if(type(o1) == type(o2)) { res = ((_rawval(o1) == _rawval(o2)?true:false)); } else { if(sq_isnumeric(o1) && sq_isnumeric(o2)) { SQInteger cmpres; if(!ObjCmp(o1, o2,cmpres)) return false; res = (cmpres == 0); } else { res = false; } } return true; } bool SQVM::IsFalse(SQObjectPtr &o) { if(((type(o) & SQOBJECT_CANBEFALSE) && ( (type(o) == OT_FLOAT) && (_float(o) == SQFloat(0.0)) )) || (_integer(o) == 0) ) { //OT_NULL|OT_INTEGER|OT_BOOL return true; } return false; } bool SQVM::GETPARENT_OP(SQObjectPtr &o,SQObjectPtr &target) { switch(type(o)) { case OT_TABLE: target = _table(o)->_delegate?SQObjectPtr(_table(o)->_delegate):_null_; break; case OT_CLASS: target = _class(o)->_base?_class(o)->_base:_null_; break; default: Raise_Error("the %s type doesn't have a parent slot", GetTypeName(o)); return false; } return true; } bool SQVM::Execute(SQObjectPtr &closure, SQInteger target, SQInteger nargs, SQInteger stackbase,SQObjectPtr &outres, SQBool raiseerror,ExecutionType et) { if ((_nnativecalls + 1) > MAX_NATIVE_CALLS) { Raise_Error("Native stack overflow"); return false; } _nnativecalls++; AutoDec ad(&_nnativecalls); SQInteger traps = 0; //temp_reg vars for OP_CALL SQInteger ct_target; SQInteger ct_stackbase; bool ct_tailcall; switch(et) { case ET_CALL: { SQInteger last_top = _top; temp_reg = closure; if(!StartCall(_closure(temp_reg), _top - nargs, nargs, stackbase, false)) { //call the handler if there are no calls in the stack, if not relies on the previous node if(ci == NULL) CallErrorHandler(_lasterror); return false; } if (_funcproto(_closure(temp_reg)->_function)->_bgenerator) { //SQFunctionProto *f = _funcproto(_closure(temp_reg)->_function); SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(temp_reg)); _GUARD(gen->Yield(this)); Return(1, ci->_target, temp_reg); outres = gen; CLEARSTACK(last_top); return true; } ci->_root = SQTrue; } break; case ET_RESUME_GENERATOR: _generator(closure)->Resume(this, target); ci->_root = SQTrue; traps += ci->_etraps; break; case ET_RESUME_VM: case ET_RESUME_THROW_VM: traps = _suspended_traps; ci->_root = _suspended_root; ci->_vargs = _suspend_varargs; _suspended = SQFalse; if(et == ET_RESUME_THROW_VM) { SQ_THROW(); } break; case ET_RESUME_OPENTTD: traps = _suspended_traps; _suspended = SQFalse; break; } exception_restore: // { for(;;) { DecreaseOps(1); if (ShouldSuspend()) { _suspended = SQTrue; _suspended_traps = traps; return true; } const SQInstruction &_i_ = *ci->_ip++; //dumpstack(_stackbase); //printf("%s %d %d %d %d\n",g_InstrDesc[_i_.op].name,arg0,arg1,arg2,arg3); switch(_i_.op) { case _OP_LINE: if(type(_debughook) != OT_NULL && _rawval(_debughook) != _rawval(ci->_closure)) CallDebugHook('l',arg1); continue; case _OP_LOAD: TARGET = ci->_literals[arg1]; continue; case _OP_LOADINT: TARGET = (SQInteger)arg1; continue; case _OP_LOADFLOAT: TARGET = *((const SQFloat *)&arg1); continue; case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue; case _OP_TAILCALL: temp_reg = STK(arg1); if (type(temp_reg) == OT_CLOSURE && !_funcproto(_closure(temp_reg)->_function)->_bgenerator){ ct_tailcall = true; if(ci->_vargs.size) PopVarArgs(ci->_vargs); for (SQInteger i = 0; i < arg3; i++) STK(i) = STK(arg2 + i); ct_target = ci->_target; ct_stackbase = _stackbase; goto common_call; } /* FALL THROUGH */ case _OP_CALL: { ct_tailcall = false; ct_target = arg0; temp_reg = STK(arg1); ct_stackbase = _stackbase+arg2; common_call: SQObjectPtr clo = temp_reg; SQInteger last_top = _top; switch (type(clo)) { case OT_CLOSURE:{ _GUARD(StartCall(_closure(clo), ct_target, arg3, ct_stackbase, ct_tailcall)); if (_funcproto(_closure(clo)->_function)->_bgenerator) { SQGenerator *gen = SQGenerator::Create(_ss(this), _closure(clo)); _GUARD(gen->Yield(this)); Return(1, ct_target, clo); STK(ct_target) = gen; } CLEARSTACK(last_top); } continue; case OT_NATIVECLOSURE: { bool suspend; _suspended_target = ct_target; try { _GUARD(CallNative(_nativeclosure(clo), arg3, ct_stackbase, clo,suspend)); } catch (...) { _suspended = SQTrue; _suspended_target = ct_target; _suspended_root = ci->_root; _suspended_traps = traps; _suspend_varargs = ci->_vargs; throw; } if(suspend){ _suspended = SQTrue; _suspended_target = ct_target; _suspended_root = ci->_root; _suspended_traps = traps; _suspend_varargs = ci->_vargs; outres = clo; return true; } if(ct_target != -1) { //skip return value for constructors STK(ct_target) = clo; } } continue; case OT_CLASS:{ SQObjectPtr inst; _GUARD(CreateClassInstance(_class(clo),inst,temp_reg)); STK(ct_target) = inst; ct_target = -1; //fakes return value target so that is not overwritten by the constructor if(type(temp_reg) != OT_NULL) { _stack._vals[ct_stackbase] = inst; goto common_call; //hard core spaghetti code(reissues the OP_CALL to invoke the constructor) } } break; case OT_TABLE: case OT_USERDATA: case OT_INSTANCE: { Push(clo); for (SQInteger i = 0; i < arg3; i++) Push(STK(arg2 + i)); if (_delegable(clo) && CallMetaMethod(_delegable(clo), MT_CALL, arg3+1, clo)){ STK(ct_target) = clo; break; } Raise_Error("attempt to call '%s'", GetTypeName(clo)); SQ_THROW(); } default: Raise_Error("attempt to call '%s'", GetTypeName(clo)); SQ_THROW(); } } continue; case _OP_PREPCALL: case _OP_PREPCALLK: { SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1); SQObjectPtr &o = STK(arg2); if (!Get(o, key, temp_reg,false,true)) { if(type(o) == OT_CLASS) { //hack? if(_class_ddel->Get(key,temp_reg)) { STK(arg3) = o; TARGET = temp_reg; continue; } } { Raise_IdxError(key); SQ_THROW();} } STK(arg3) = type(o) == OT_CLASS?STK(0):o; TARGET = temp_reg; } continue; case _OP_SCOPE_END: { SQInteger from = arg0; SQInteger count = arg1 - arg0 + 2; /* When 'return' is executed, it happens that the stack is already cleaned * (by Return()), but this OP-code is still executed. So check for this * situation, and ignore the cleanup */ if (_stackbase + count + from <= _top) { while (--count >= 0) _stack._vals[_stackbase + count + from].Null(); } } continue; case _OP_GETK: if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,true)) { Raise_IdxError(ci->_literals[arg1]); SQ_THROW();} TARGET = temp_reg; continue; case _OP_MOVE: TARGET = STK(arg1); continue; case _OP_NEWSLOT: _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),false)); if(arg0 != arg3) TARGET = STK(arg3); continue; case _OP_DELETE: _GUARD(DeleteSlot(STK(arg1), STK(arg2), TARGET)); continue; case _OP_SET: if (!Set(STK(arg1), STK(arg2), STK(arg3),true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } if (arg0 != arg3) TARGET = STK(arg3); continue; case _OP_GET: if (!Get(STK(arg1), STK(arg2), temp_reg, false,true)) { Raise_IdxError(STK(arg2)); SQ_THROW(); } TARGET = temp_reg; continue; case _OP_EQ:{ bool res; if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } TARGET = res?_true_:_false_; }continue; case _OP_NE:{ bool res; if(!IsEqual(STK(arg2),COND_LITERAL,res)) { SQ_THROW(); } TARGET = (!res)?_true_:_false_; } continue; case _OP_ARITH: _GUARD(ARITH_OP( arg3 , temp_reg, STK(arg2), STK(arg1))); TARGET = temp_reg; continue; case _OP_BITW: _GUARD(BW_OP( arg3,TARGET,STK(arg2),STK(arg1))); continue; case _OP_RETURN: if(ci->_generator) { ci->_generator->Kill(); } if(Return(arg0, arg1, temp_reg)){ assert(traps==0); outres = temp_reg; return true; } continue; case _OP_LOADNULLS:{ for(SQInt32 n=0; n < arg1; n++) STK(arg0+n) = _null_; }continue; case _OP_LOADROOTTABLE: TARGET = _roottable; continue; case _OP_LOADBOOL: TARGET = arg1?_true_:_false_; continue; case _OP_DMOVE: STK(arg0) = STK(arg1); STK(arg2) = STK(arg3); continue; case _OP_JMP: ci->_ip += (sarg1); continue; case _OP_JNZ: if(!IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; case _OP_JZ: if(IsFalse(STK(arg0))) ci->_ip+=(sarg1); continue; case _OP_LOADFREEVAR: TARGET = _closure(ci->_closure)->_outervalues[arg1]; continue; case _OP_VARGC: TARGET = SQInteger(ci->_vargs.size); continue; case _OP_GETVARGV: if(!GETVARGV_OP(TARGET,STK(arg1),ci)) { SQ_THROW(); } continue; case _OP_NEWTABLE: TARGET = SQTable::Create(_ss(this), arg1); continue; case _OP_NEWARRAY: TARGET = SQArray::Create(_ss(this), 0); _array(TARGET)->Reserve(arg1); continue; case _OP_APPENDARRAY: _array(STK(arg0))->Append(COND_LITERAL); continue; case _OP_GETPARENT: _GUARD(GETPARENT_OP(STK(arg1),TARGET)); continue; case _OP_COMPARITH: _GUARD(DerefInc(arg3, TARGET, STK((((SQUnsignedInteger)arg1&0xFFFF0000)>>16)), STK(arg2), STK(arg1&0x0000FFFF), false)); continue; case _OP_COMPARITHL: _GUARD(LOCAL_INC(arg3, TARGET, STK(arg1), STK(arg2))); continue; case _OP_INC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, false));} continue; case _OP_INCL: {SQObjectPtr o(sarg3); _GUARD(LOCAL_INC('+',TARGET, STK(arg1), o));} continue; case _OP_PINC: {SQObjectPtr o(sarg3); _GUARD(DerefInc('+',TARGET, STK(arg1), STK(arg2), o, true));} continue; case _OP_PINCL: {SQObjectPtr o(sarg3); _GUARD(PLOCAL_INC('+',TARGET, STK(arg1), o));} continue; case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true,false)?_true_:_false_;continue; case _OP_INSTANCEOF: if(type(STK(arg1)) != OT_CLASS || type(STK(arg2)) != OT_INSTANCE) {Raise_Error("cannot apply instanceof between a %s and a %s",GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} TARGET = _instance(STK(arg2))->InstanceOf(_class(STK(arg1)))?_true_:_false_; continue; case _OP_AND: if(IsFalse(STK(arg2))) { TARGET = STK(arg2); ci->_ip += (sarg1); } continue; case _OP_OR: if(!IsFalse(STK(arg2))) { TARGET = STK(arg2); ci->_ip += (sarg1); } continue; case _OP_NEG: _GUARD(NEG_OP(TARGET,STK(arg1))); continue; case _OP_NOT: TARGET = (IsFalse(STK(arg1))?_true_:_false_); continue; case _OP_BWNOT: if(type(STK(arg1)) == OT_INTEGER) { SQInteger t = _integer(STK(arg1)); TARGET = SQInteger(~t); continue; } Raise_Error("attempt to perform a bitwise op on a %s", GetTypeName(STK(arg1))); SQ_THROW(); case _OP_CLOSURE: { SQClosure *c = ci->_closure._unVal.pClosure; SQFunctionProto *fp = c->_function._unVal.pFunctionProto; if(!CLOSURE_OP(TARGET,fp->_functions[arg1]._unVal.pFunctionProto)) { SQ_THROW(); } continue; } case _OP_YIELD:{ if(ci->_generator) { if(sarg1 != MAX_FUNC_STACKSIZE) temp_reg = STK(arg1); _GUARD(ci->_generator->Yield(this)); traps -= ci->_etraps; if(sarg1 != MAX_FUNC_STACKSIZE) STK(arg1) = temp_reg; } else { Raise_Error("trying to yield a '%s',only genenerator can be yielded", GetTypeName(ci->_closure)); SQ_THROW();} if(Return(arg0, arg1, temp_reg)){ assert(traps == 0); outres = temp_reg; return true; } } continue; case _OP_RESUME: if(type(STK(arg1)) != OT_GENERATOR){ Raise_Error("trying to resume a '%s',only genenerator can be resumed", GetTypeName(STK(arg1))); SQ_THROW();} _GUARD(_generator(STK(arg1))->Resume(this, arg0)); traps += ci->_etraps; continue; case _OP_FOREACH:{ int tojump; _GUARD(FOREACH_OP(STK(arg0),STK(arg2),STK(arg2+1),STK(arg2+2),arg2,sarg1,tojump)); ci->_ip += tojump; } continue; case _OP_POSTFOREACH: assert(type(STK(arg0)) == OT_GENERATOR); if(_generator(STK(arg0))->_state == SQGenerator::eDead) ci->_ip += (sarg1 - 1); continue; case _OP_DELEGATE: _GUARD(DELEGATE_OP(TARGET,STK(arg1),STK(arg2))); continue; case _OP_CLONE: if(!Clone(STK(arg1), TARGET)) { Raise_Error("cloning a %s", GetTypeName(STK(arg1))); SQ_THROW();} continue; case _OP_TYPEOF: TypeOf(STK(arg1), TARGET); continue; case _OP_PUSHTRAP:{ SQInstruction *_iv = _funcproto(_closure(ci->_closure)->_function)->_instructions; _etraps.push_back(SQExceptionTrap(_top,_stackbase, &_iv[(ci->_ip-_iv)+arg1], arg0)); traps++; ci->_etraps++; } continue; case _OP_POPTRAP: { for(SQInteger i = 0; i < arg0; i++) { _etraps.pop_back(); traps--; ci->_etraps--; } } continue; case _OP_THROW: Raise_Error(TARGET); SQ_THROW(); case _OP_CLASS: _GUARD(CLASS_OP(TARGET,arg1,arg2)); continue; case _OP_NEWSLOTA: bool bstatic = (arg0&NEW_SLOT_STATIC_FLAG)?true:false; if(type(STK(arg1)) == OT_CLASS) { if(type(_class(STK(arg1))->_metamethods[MT_NEWMEMBER]) != OT_NULL ) { Push(STK(arg1)); Push(STK(arg2)); Push(STK(arg3)); Push((arg0&NEW_SLOT_ATTRIBUTES_FLAG) ? STK(arg2-1) : _null_); Push(bstatic); int nparams = 5; if(Call(_class(STK(arg1))->_metamethods[MT_NEWMEMBER], nparams, _top - nparams, temp_reg,SQFalse,SQFalse)) { Pop(nparams); continue; } } } _GUARD(NewSlot(STK(arg1), STK(arg2), STK(arg3),bstatic)); if((arg0&NEW_SLOT_ATTRIBUTES_FLAG)) { _class(STK(arg1))->SetAttributes(STK(arg2),STK(arg2-1)); } continue; } } } exception_trap: { SQObjectPtr currerror = _lasterror; // dumpstack(_stackbase); SQInteger n = 0; SQInteger last_top = _top; if(ci) { if(_ss(this)->_notifyallexceptions) CallErrorHandler(currerror); if(traps) { do { if(ci->_etraps > 0) { SQExceptionTrap &et = _etraps.top(); ci->_ip = et._ip; _top = et._stacksize; _stackbase = et._stackbase; _stack._vals[_stackbase+et._extarget] = currerror; _etraps.pop_back(); traps--; ci->_etraps--; CLEARSTACK(last_top); goto exception_restore; } //if is a native closure if(type(ci->_closure) != OT_CLOSURE && n) break; if(ci->_generator) ci->_generator->Kill(); PopVarArgs(ci->_vargs); POP_CALLINFO(this); n++; } while(_callsstacksize); } else { //call the hook if(raiseerror && !_ss(this)->_notifyallexceptions) CallErrorHandler(currerror); } //remove call stack until a C function is found or the cstack is empty if(ci) do { SQBool exitafterthisone = ci->_root; if(ci->_generator) ci->_generator->Kill(); _stackbase -= ci->_prevstkbase; _top = _stackbase + ci->_prevtop; PopVarArgs(ci->_vargs); POP_CALLINFO(this); if( (ci && type(ci->_closure) != OT_CLOSURE) || exitafterthisone) break; } while(_callsstacksize); CLEARSTACK(last_top); } _lasterror = currerror; return false; } assert(0); } bool SQVM::CreateClassInstance(SQClass *theclass, SQObjectPtr &inst, SQObjectPtr &constructor) { inst = theclass->CreateInstance(); if(!theclass->Get(_ss(this)->_constructoridx,constructor)) { constructor = _null_; } return true; } void SQVM::CallErrorHandler(SQObjectPtr &error) { if(type(_errorhandler) != OT_NULL) { SQObjectPtr out; Push(_roottable); Push(error); Call(_errorhandler, 2, _top-2, out,SQFalse,SQFalse); Pop(2); } } void SQVM::CallDebugHook(SQInteger type,SQInteger forcedline) { SQObjectPtr temp_reg; SQInteger nparams=5; SQFunctionProto *func=_funcproto(_closure(ci->_closure)->_function); Push(_roottable); Push(type); Push(func->_sourcename); Push(forcedline?forcedline:func->GetLine(ci->_ip)); Push(func->_name); Call(_debughook,nparams,_top-nparams,temp_reg,SQFalse,SQFalse); Pop(nparams); } bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackbase,SQObjectPtr &retval,bool &suspend) { if (_nnativecalls + 1 > MAX_NATIVE_CALLS) { Raise_Error("Native stack overflow"); return false; } SQInteger nparamscheck = nclosure->_nparamscheck; if(((nparamscheck > 0) && (nparamscheck != nargs)) || ((nparamscheck < 0) && (nargs < (-nparamscheck)))) { Raise_Error("wrong number of parameters"); return false; } SQInteger tcs; if((tcs = nclosure->_typecheck.size())) { for(SQInteger i = 0; i < nargs && i < tcs; i++) if((nclosure->_typecheck._vals[i] != -1) && !(type(_stack._vals[stackbase+i]) & nclosure->_typecheck[i])) { Raise_ParamTypeError(i,nclosure->_typecheck._vals[i],type(_stack._vals[stackbase+i])); return false; } } _nnativecalls++; if ((_top + MIN_STACK_OVERHEAD) > (SQInteger)_stack.size()) { _stack.resize(_stack.size() + (MIN_STACK_OVERHEAD<<1)); } SQInteger oldtop = _top; SQInteger oldstackbase = _stackbase; _top = stackbase + nargs; CallInfo lci; memset(&lci, 0, sizeof(lci)); lci._closure = nclosure; lci._generator = NULL; lci._etraps = 0; lci._prevstkbase = (SQInt32) (stackbase - _stackbase); lci._ncalls = 1; lci._prevtop = (SQInt32) (oldtop - oldstackbase); PUSH_CALLINFO(this, lci); _stackbase = stackbase; //push free variables SQInteger outers = nclosure->_outervalues.size(); for (SQInteger i = 0; i < outers; i++) { Push(nclosure->_outervalues[i]); } if(type(nclosure->_env) == OT_WEAKREF) { _stack[stackbase] = _weakref(nclosure->_env)->_obj; } /* Store the call stack size, so we can restore that */ SQInteger cstksize = _callsstacksize; SQInteger ret; try { SQBool can_suspend = this->_can_suspend; this->_can_suspend = false; ret = (nclosure->_function)(this); this->_can_suspend = can_suspend; } catch (...) { _nnativecalls--; suspend = false; _callsstacksize = cstksize; _stackbase = oldstackbase; _top = oldtop; POP_CALLINFO(this); while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null(); throw; } _callsstacksize = cstksize; _nnativecalls--; suspend = false; if( ret == SQ_SUSPEND_FLAG) suspend = true; else if (ret < 0) { _stackbase = oldstackbase; _top = oldtop; POP_CALLINFO(this); while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null(); Raise_Error(_lasterror); return false; } if (ret != 0){ retval = TOP(); TOP().Null(); } else { retval = _null_; } _stackbase = oldstackbase; _top = oldtop; POP_CALLINFO(this); while(oldtop > _stackbase + stackbase) _stack._vals[oldtop--].Null(); return true; } bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, bool fetchroot) { switch(type(self)){ case OT_TABLE: if(_table(self)->Get(key,dest))return true; break; case OT_ARRAY: if(sq_isnumeric(key)){ return _array(self)->Get(tointeger(key),dest); } break; case OT_INSTANCE: if(_instance(self)->Get(key,dest)) return true; break; default:break; //shut up compiler } if(FallBackGet(self,key,dest,raw)) return true; if(fetchroot) { if(_rawval(STK(0)) == _rawval(self) && type(STK(0)) == type(self)) { return _table(_roottable)->Get(key,dest); } } return false; } bool SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw) { switch(type(self)){ case OT_CLASS: return _class(self)->Get(key,dest); break; case OT_TABLE: case OT_USERDATA: //delegation if(_delegable(self)->_delegate) { if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,raw,false)) return true; if(raw)return false; Push(self);Push(key); if(CallMetaMethod(_delegable(self),MT_GET,2,dest)) return true; } if(type(self) == OT_TABLE) { if(raw) return false; return _table_ddel->Get(key,dest); } return false; break; case OT_ARRAY: if(raw)return false; return _array_ddel->Get(key,dest); case OT_STRING: if(sq_isnumeric(key)){ SQInteger n=tointeger(key); if(abs((int)n)<_string(self)->_len){ if(n<0)n=_string(self)->_len-n; dest=SQInteger(_stringval(self)[n]); return true; } return false; } else { if(raw)return false; return _string_ddel->Get(key,dest); } break; case OT_INSTANCE: if(raw)return false; Push(self);Push(key); if(!CallMetaMethod(_delegable(self),MT_GET,2,dest)) { return _instance_ddel->Get(key,dest); } return true; case OT_INTEGER:case OT_FLOAT:case OT_BOOL: if(raw)return false; return _number_ddel->Get(key,dest); case OT_GENERATOR: if(raw)return false; return _generator_ddel->Get(key,dest); case OT_CLOSURE: case OT_NATIVECLOSURE: if(raw)return false; return _closure_ddel->Get(key,dest); case OT_THREAD: if(raw)return false; return _thread_ddel->Get(key,dest); case OT_WEAKREF: if(raw)return false; return _weakref_ddel->Get(key,dest); default:return false; } return false; } bool SQVM::Set(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool fetchroot) { switch(type(self)){ case OT_TABLE: if(_table(self)->Set(key,val)) return true; if(_table(self)->_delegate) { if(Set(_table(self)->_delegate,key,val,false)) { return true; } } //keeps going case OT_USERDATA: if(_delegable(self)->_delegate) { SQObjectPtr t; Push(self);Push(key);Push(val); if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; } break; case OT_INSTANCE:{ if(_instance(self)->Set(key,val)) return true; SQObjectPtr t; Push(self);Push(key);Push(val); if(CallMetaMethod(_delegable(self),MT_SET,3,t)) return true; } break; case OT_ARRAY: if(!sq_isnumeric(key)) {Raise_Error("indexing %s with %s",GetTypeName(self),GetTypeName(key)); return false; } return _array(self)->Set(tointeger(key),val); default: Raise_Error("trying to set '%s'",GetTypeName(self)); return false; } if(fetchroot) { if(_rawval(STK(0)) == _rawval(self) && type(STK(0)) == type(self)) { return _table(_roottable)->Set(key,val); } } return false; } bool SQVM::Clone(const SQObjectPtr &self,SQObjectPtr &target) { SQObjectPtr temp_reg; SQObjectPtr newobj; switch(type(self)){ case OT_TABLE: newobj = _table(self)->Clone(); goto cloned_mt; case OT_INSTANCE: newobj = _instance(self)->Clone(_ss(this)); cloned_mt: if(_delegable(newobj)->_delegate){ Push(newobj); Push(self); CallMetaMethod(_delegable(newobj),MT_CLONED,2,temp_reg); } target = newobj; return true; case OT_ARRAY: target = _array(self)->Clone(); return true; default: return false; } } bool SQVM::NewSlot(const SQObjectPtr &self,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { if(type(key) == OT_NULL) { Raise_Error("null cannot be used as index"); return false; } switch(type(self)) { case OT_TABLE: { bool rawcall = true; if(_table(self)->_delegate) { SQObjectPtr res; if(!_table(self)->Get(key,res)) { Push(self);Push(key);Push(val); rawcall = !CallMetaMethod(_table(self),MT_NEWSLOT,3,res); } } if(rawcall) _table(self)->NewSlot(key,val); //cannot fail break;} case OT_INSTANCE: { SQObjectPtr res; Push(self);Push(key);Push(val); if(!CallMetaMethod(_instance(self),MT_NEWSLOT,3,res)) { Raise_Error("class instances do not support the new slot operator"); return false; } break;} case OT_CLASS: if(!_class(self)->NewSlot(_ss(this),key,val,bstatic)) { if(_class(self)->_locked) { Raise_Error("trying to modify a class that has already been instantiated"); return false; } else { SQObjectPtr oval = PrintObjVal(key); Raise_Error("the property '%s' already exists",_stringval(oval)); return false; } } break; default: Raise_Error("indexing %s with %s",GetTypeName(self),GetTypeName(key)); return false; break; } return true; } bool SQVM::DeleteSlot(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &res) { switch(type(self)) { case OT_TABLE: case OT_INSTANCE: case OT_USERDATA: { SQObjectPtr t; bool handled = false; if(_delegable(self)->_delegate) { Push(self);Push(key); handled = CallMetaMethod(_delegable(self),MT_DELSLOT,2,t); } if(!handled) { if(type(self) == OT_TABLE) { if(_table(self)->Get(key,t)) { _table(self)->Remove(key); } else { Raise_IdxError((const SQObject &)key); return false; } } else { Raise_Error("cannot delete a slot from %s",GetTypeName(self)); return false; } } res = t; } break; default: Raise_Error("attempt to delete a slot from a %s",GetTypeName(self)); return false; } return true; } bool SQVM::Call(SQObjectPtr &closure,SQInteger nparams,SQInteger stackbase,SQObjectPtr &outres,SQBool raiseerror,SQBool can_suspend) { #ifdef _DEBUG SQInteger prevstackbase = _stackbase; #endif switch(type(closure)) { case OT_CLOSURE: { assert(!can_suspend || this->_can_suspend); SQBool backup_suspend = this->_can_suspend; this->_can_suspend = can_suspend; bool ret = Execute(closure, _top - nparams, nparams, stackbase,outres,raiseerror); this->_can_suspend = backup_suspend; return ret; } break; case OT_NATIVECLOSURE:{ bool suspend; return CallNative(_nativeclosure(closure), nparams, stackbase, outres,suspend); } break; case OT_CLASS: { SQObjectPtr constr; SQObjectPtr temp; CreateClassInstance(_class(closure),outres,constr); if(type(constr) != OT_NULL) { _stack[stackbase] = outres; return Call(constr,nparams,stackbase,temp,raiseerror,false); } return true; } break; default: return false; } #ifdef _DEBUG if(!_suspended) { assert(_stackbase == prevstackbase); } #endif return true; } bool SQVM::CallMetaMethod(SQDelegable *del,SQMetaMethod mm,SQInteger nparams,SQObjectPtr &outres) { SQObjectPtr closure; if(del->GetMetaMethod(this, mm, closure)) { if(Call(closure, nparams, _top - nparams, outres, SQFalse, SQFalse)) { Pop(nparams); return true; } } Pop(nparams); return false; } void SQVM::Remove(SQInteger n) { n = (n >= 0)?n + _stackbase - 1:_top + n; for(SQInteger i = n; i < _top; i++){ _stack[i] = _stack[i+1]; } _stack[_top] = _null_; _top--; } void SQVM::Pop() { _stack[--_top] = _null_; } void SQVM::Pop(SQInteger n) { for(SQInteger i = 0; i < n; i++){ _stack[--_top] = _null_; } } void SQVM::Push(const SQObjectPtr &o) { /* Normally the stack shouldn't get this full, sometimes it might. As of now * all cases have been bugs in "our" (OpenTTD) code. Trigger an assert for * all debug builds and for the release builds just increase the stack size. * This way getting a false positive isn't that bad (releases work fine) and * if there is something fishy it can be caught in RCs/nightlies. */ #ifdef NDEBUG if (_top >= (int)_stack.capacity()) _stack.resize(2 * _stack.capacity()); #else assert(_top < (int)_stack.capacity()); #endif _stack[_top++] = o; } SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; } SQObjectPtr &SQVM::GetAt(SQInteger n) { return _stack[n]; } #ifdef _DEBUG_DUMP void SQVM::dumpstack(SQInteger stackbase,bool dumpall) { SQInteger size=dumpall?_stack.size():_top; SQInteger n=0; printf("\n>>>>stack dump<<<<\n"); CallInfo &ci=_callsstack[_callsstacksize-1]; printf("IP: %p\n",ci._ip); printf("prev stack base: %d\n",ci._prevstkbase); printf("prev top: %d\n",ci._prevtop); for(SQInteger i=0;i");else printf(" "); printf("[%d]:",n); switch(type(obj)){ case OT_FLOAT: printf("FLOAT %.3f",_float(obj));break; case OT_INTEGER: printf("INTEGER %d",_integer(obj));break; case OT_BOOL: printf("BOOL %s",_integer(obj)?"true":"false");break; case OT_STRING: printf("STRING %s",_stringval(obj));break; case OT_NULL: printf("NULL"); break; case OT_TABLE: printf("TABLE %p[%p]",_table(obj),_table(obj)->_delegate);break; case OT_ARRAY: printf("ARRAY %p",_array(obj));break; case OT_CLOSURE: printf("CLOSURE [%p]",_closure(obj));break; case OT_NATIVECLOSURE: printf("NATIVECLOSURE");break; case OT_USERDATA: printf("USERDATA %p[%p]",_userdataval(obj),_userdata(obj)->_delegate);break; case OT_GENERATOR: printf("GENERATOR %p",_generator(obj));break; case OT_THREAD: printf("THREAD [%p]",_thread(obj));break; case OT_USERPOINTER: printf("USERPOINTER %p",_userpointer(obj));break; case OT_CLASS: printf("CLASS %p",_class(obj));break; case OT_INSTANCE: printf("INSTANCE %p",_instance(obj));break; case OT_WEAKREF: printf("WEAKERF %p",_weakref(obj));break; default: assert(0); break; }; printf("\n"); ++n; } } #endif openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqbaselib.cpp0000644000000000000000000005537212627373445022450 0ustar rootroot/* * see copyright notice in squirrel.h */ /* * Needs to be first due to a squirrel header defining type() and type() * being used in some versions of the headers included by algorithm. */ #include "../../../stdafx.h" #include #include "sqpcheader.h" #include "sqvm.h" #include "sqstring.h" #include "sqtable.h" #include "sqarray.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "sqclass.h" #include #include #include "../../../safeguards.h" bool str2num(const SQChar *s,SQObjectPtr &res) { SQChar *end; if(strstr(s,".")){ SQFloat r = SQFloat(strtod(s,&end)); if(s == end) return false; res = r; return true; } else{ SQInteger r = SQInteger(strtol(s,&end,10)); if(s == end) return false; res = r; return true; } } #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS static SQInteger base_dummy(HSQUIRRELVM v) { return 0; } #ifndef NO_GARBAGE_COLLECTOR static SQInteger base_collectgarbage(HSQUIRRELVM v) { sq_pushinteger(v, sq_collectgarbage(v)); return 1; } #endif static SQInteger base_getroottable(HSQUIRRELVM v) { v->Push(v->_roottable); return 1; } static SQInteger base_getconsttable(HSQUIRRELVM v) { v->Push(_ss(v)->_consts); return 1; } static SQInteger base_setroottable(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,2); if(SQ_FAILED(sq_setroottable(v))) return SQ_ERROR; v->Push(o); return 1; } static SQInteger base_setconsttable(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,2); if(SQ_FAILED(sq_setconsttable(v))) return SQ_ERROR; v->Push(o); return 1; } static SQInteger base_seterrorhandler(HSQUIRRELVM v) { sq_seterrorhandler(v); return 0; } static SQInteger base_setdebughook(HSQUIRRELVM v) { sq_setdebughook(v); return 0; } static SQInteger base_enabledebuginfo(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,2); sq_enabledebuginfo(v,(type(o) != OT_NULL)?1:0); return 0; } static SQInteger base_getstackinfos(HSQUIRRELVM v) { SQInteger level; SQStackInfos si; SQInteger seq = 0; const SQChar *name = NULL; sq_getinteger(v, -1, &level); if (SQ_SUCCEEDED(sq_stackinfos(v, level, &si))) { const SQChar *fn = "unknown"; const SQChar *src = "unknown"; if(si.funcname)fn = si.funcname; if(si.source)src = si.source; sq_newtable(v); sq_pushstring(v, "func", -1); sq_pushstring(v, fn, -1); sq_createslot(v, -3); sq_pushstring(v, "src", -1); sq_pushstring(v, src, -1); sq_createslot(v, -3); sq_pushstring(v, "line", -1); sq_pushinteger(v, si.line); sq_createslot(v, -3); sq_pushstring(v, "locals", -1); sq_newtable(v); seq=0; while ((name = sq_getlocal(v, level, seq))) { sq_pushstring(v, name, -1); sq_push(v, -2); sq_createslot(v, -4); sq_pop(v, 1); seq++; } sq_createslot(v, -3); return 1; } return 0; } #endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ static SQInteger base_assert(HSQUIRRELVM v) { if(v->IsFalse(stack_get(v,2))){ return sq_throwerror(v,"assertion failed"); } return 0; } static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,SQObjectPtr &o) { SQInteger top = sq_gettop(v); sidx=0; eidx=0; o=stack_get(v,1); SQObjectPtr &start=stack_get(v,2); if(type(start)!=OT_NULL && sq_isnumeric(start)){ sidx=tointeger(start); } if(top>2){ SQObjectPtr &end=stack_get(v,3); if(sq_isnumeric(end)){ eidx=tointeger(end); } } else { eidx = sq_getsize(v,1); } return 1; } static SQInteger base_print(HSQUIRRELVM v) { const SQChar *str; sq_tostring(v,2); sq_getstring(v,-1,&str); if(_ss(v)->_printfunc) _ss(v)->_printfunc(v,"%s",str); return 0; } #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS static SQInteger base_compilestring(HSQUIRRELVM v) { SQInteger nargs=sq_gettop(v); const SQChar *src=NULL,*name="unnamedbuffer"; SQInteger size; sq_getstring(v,2,&src); size=sq_getsize(v,2); if(nargs>2){ sq_getstring(v,3,&name); } if(SQ_SUCCEEDED(sq_compilebuffer(v,src,size,name,SQFalse))) return 1; else return SQ_ERROR; } static SQInteger base_newthread(HSQUIRRELVM v) { SQObjectPtr &func = stack_get(v,2); SQInteger stksize = (_funcproto(_closure(func)->_function)->_stacksize << 1) +2; HSQUIRRELVM newv = sq_newthread(v, (stksize < MIN_STACK_OVERHEAD + 2)? MIN_STACK_OVERHEAD + 2 : stksize); sq_move(newv,v,-2); return 1; } static SQInteger base_suspend(HSQUIRRELVM v) { return sq_suspendvm(v); } #endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ static SQInteger base_array(HSQUIRRELVM v) { SQArray *a; SQInteger nInitialSize = tointeger(stack_get(v,2)); SQInteger ret = 1; if (nInitialSize < 0) { v->Raise_Error("can't create/resize array with/to size %d", nInitialSize); nInitialSize = 0; ret = -1; } if(sq_gettop(v) > 2) { a = SQArray::Create(_ss(v),0); a->Resize(nInitialSize,stack_get(v,3)); } else { a = SQArray::Create(_ss(v),nInitialSize); } v->Push(a); return ret; } static SQInteger base_type(HSQUIRRELVM v) { SQObjectPtr &o = stack_get(v,2); v->Push(SQString::Create(_ss(v),GetTypeName(o),-1)); return 1; } static SQRegFunction base_funcs[]={ //generic #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS {"seterrorhandler",base_seterrorhandler,2, NULL}, {"setdebughook",base_setdebughook,2, NULL}, {"enabledebuginfo",base_enabledebuginfo,2, NULL}, {"getstackinfos",base_getstackinfos,2, ".n"}, {"getroottable",base_getroottable,1, NULL}, {"setroottable",base_setroottable,2, NULL}, {"getconsttable",base_getconsttable,1, NULL}, {"setconsttable",base_setconsttable,2, NULL}, #endif {"assert",base_assert,2, NULL}, {"print",base_print,2, NULL}, #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS {"compilestring",base_compilestring,-2, ".ss"}, {"newthread",base_newthread,2, ".c"}, {"suspend",base_suspend,-1, NULL}, #endif {"array",base_array,-2, ".n"}, {"type",base_type,2, NULL}, #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS {"dummy",base_dummy,0,NULL}, #ifndef NO_GARBAGE_COLLECTOR {"collectgarbage",base_collectgarbage,1, "t"}, #endif #endif {0,0,0,0} }; void sq_base_register(HSQUIRRELVM v) { SQInteger i=0; sq_pushroottable(v); while(base_funcs[i].name!=0) { sq_pushstring(v,base_funcs[i].name,-1); sq_newclosure(v,base_funcs[i].f,0); sq_setnativeclosurename(v,-1,base_funcs[i].name); sq_setparamscheck(v,base_funcs[i].nparamscheck,base_funcs[i].typemask); sq_createslot(v,-3); i++; } sq_pushstring(v,"_version_",-1); sq_pushstring(v,SQUIRREL_VERSION,-1); sq_createslot(v,-3); sq_pushstring(v,"_charsize_",-1); sq_pushinteger(v,sizeof(SQChar)); sq_createslot(v,-3); sq_pushstring(v,"_intsize_",-1); sq_pushinteger(v,sizeof(SQInteger)); sq_createslot(v,-3); sq_pushstring(v,"_floatsize_",-1); sq_pushinteger(v,sizeof(SQFloat)); sq_createslot(v,-3); sq_pop(v,1); } static SQInteger default_delegate_len(HSQUIRRELVM v) { v->Push(SQInteger(sq_getsize(v,1))); return 1; } static SQInteger default_delegate_tofloat(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,1); switch(type(o)){ case OT_STRING:{ SQObjectPtr res; if(str2num(_stringval(o),res)){ v->Push(SQObjectPtr(tofloat(res))); break; }} return sq_throwerror(v, "cannot convert the string"); break; case OT_INTEGER:case OT_FLOAT: v->Push(SQObjectPtr(tofloat(o))); break; case OT_BOOL: v->Push(SQObjectPtr((SQFloat)(_integer(o)?1:0))); break; default: v->Push(_null_); break; } return 1; } static SQInteger default_delegate_tointeger(HSQUIRRELVM v) { SQObjectPtr &o=stack_get(v,1); switch(type(o)){ case OT_STRING:{ SQObjectPtr res; if(str2num(_stringval(o),res)){ v->Push(SQObjectPtr(tointeger(res))); break; }} return sq_throwerror(v, "cannot convert the string"); break; case OT_INTEGER:case OT_FLOAT: v->Push(SQObjectPtr(tointeger(o))); break; case OT_BOOL: v->Push(SQObjectPtr(_integer(o)?(SQInteger)1:(SQInteger)0)); break; default: v->Push(_null_); break; } return 1; } static SQInteger default_delegate_tostring(HSQUIRRELVM v) { sq_tostring(v,1); return 1; } static SQInteger obj_delegate_weakref(HSQUIRRELVM v) { sq_weakref(v,1); return 1; } static SQInteger obj_clear(HSQUIRRELVM v) { return sq_clear(v,-1); } static SQInteger number_delegate_tochar(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); SQChar c = (SQChar)tointeger(o); v->Push(SQString::Create(_ss(v),(const SQChar *)&c,1)); return 1; } ///////////////////////////////////////////////////////////////// //TABLE DEFAULT DELEGATE static SQInteger table_rawdelete(HSQUIRRELVM v) { if(SQ_FAILED(sq_rawdeleteslot(v,1,SQTrue))) return SQ_ERROR; return 1; } static SQInteger container_rawexists(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_rawget(v,-2))) { sq_pushbool(v,SQTrue); return 1; } sq_pushbool(v,SQFalse); return 1; } static SQInteger table_rawset(HSQUIRRELVM v) { return sq_rawset(v,-3); } static SQInteger table_rawget(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_rawget(v,-2))?1:SQ_ERROR; } SQRegFunction SQSharedState::_table_default_delegate_funcz[]={ {"len",default_delegate_len,1, "t"}, {"rawget",table_rawget,2, "t"}, {"rawset",table_rawset,3, "t"}, {"rawdelete",table_rawdelete,2, "t"}, {"rawin",container_rawexists,2, "t"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {"clear",obj_clear,1, "."}, {0,0,0,0} }; //ARRAY DEFAULT DELEGATE/////////////////////////////////////// static SQInteger array_append(HSQUIRRELVM v) { return sq_arrayappend(v,-2); } static SQInteger array_extend(HSQUIRRELVM v) { _array(stack_get(v,1))->Extend(_array(stack_get(v,2))); return 0; } static SQInteger array_reverse(HSQUIRRELVM v) { return sq_arrayreverse(v,-1); } static SQInteger array_pop(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_arraypop(v,1,SQTrue))?1:SQ_ERROR; } static SQInteger array_top(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); if(_array(o)->Size()>0){ v->Push(_array(o)->Top()); return 1; } else return sq_throwerror(v,"top() on a empty array"); } static SQInteger array_insert(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); SQObject &idx=stack_get(v,2); SQObject &val=stack_get(v,3); if(!_array(o)->Insert(tointeger(idx),val)) return sq_throwerror(v,"index out of range"); return 0; } static SQInteger array_remove(HSQUIRRELVM v) { SQObject &o = stack_get(v, 1); SQObject &idx = stack_get(v, 2); if(!sq_isnumeric(idx)) return sq_throwerror(v, "wrong type"); SQObjectPtr val; if(_array(o)->Get(tointeger(idx), val)) { _array(o)->Remove(tointeger(idx)); v->Push(val); return 1; } return sq_throwerror(v, "idx out of range"); } static SQInteger array_resize(HSQUIRRELVM v) { SQObject &o = stack_get(v, 1); SQObject &nsize = stack_get(v, 2); SQObjectPtr fill; if(sq_isnumeric(nsize)) { if(sq_gettop(v) > 2) fill = stack_get(v, 3); _array(o)->Resize(tointeger(nsize),fill); return 0; } return sq_throwerror(v, "size must be a number"); } bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) { if(func < 0) { if(!v->ObjCmp(a,b,ret)) return false; } else { SQInteger top = sq_gettop(v); sq_push(v, func); sq_pushroottable(v); v->Push(a); v->Push(b); if(SQ_FAILED(sq_call(v, 3, SQTrue, SQFalse))) { if(!sq_isstring( v->_lasterror)) v->Raise_Error("compare func failed"); return false; } if(SQ_FAILED(sq_getinteger(v, -1, &ret))) { v->Raise_Error("numeric value expected as return value of the compare function"); return false; } sq_settop(v, top); return true; } return true; } bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func) { SQInteger maxChild; SQInteger done = 0; SQInteger ret; SQInteger root2; while (((root2 = root * 2) <= bottom) && (!done)) { if (root2 == bottom) { maxChild = root2; } else { if(!_sort_compare(v,arr->_values[root2],arr->_values[root2 + 1],func,ret)) return false; if (ret > 0) { maxChild = root2; } else { maxChild = root2 + 1; } } if(!_sort_compare(v,arr->_values[root],arr->_values[maxChild],func,ret)) return false; if (ret < 0) { if (root == maxChild) { v->Raise_Error("inconsistent compare function"); return false; // We'd be swapping ourselve. The compare function is incorrect } _Swap(arr->_values[root],arr->_values[maxChild]); root = maxChild; } else { done = 1; } } return true; } bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func) { SQArray *a = _array(arr); SQInteger i; SQInteger array_size = a->Size(); for (i = (array_size / 2); i >= 0; i--) { if(!_hsort_sift_down(v,a, i, array_size - 1,func)) return false; } for (i = array_size-1; i >= 1; i--) { _Swap(a->_values[0],a->_values[i]); if(!_hsort_sift_down(v,a, 0, i-1,func)) return false; } return true; } static SQInteger array_sort(HSQUIRRELVM v) { SQInteger func = -1; SQObjectPtr &o = stack_get(v,1); if(_array(o)->Size() > 1) { if(sq_gettop(v) == 2) func = 2; if(!_hsort(v, o, 0, _array(o)->Size()-1, func)) return SQ_ERROR; } return 0; } static SQInteger array_slice(HSQUIRRELVM v) { SQInteger sidx,eidx; SQObjectPtr o; if(get_slice_params(v,sidx,eidx,o)==-1)return -1; SQInteger alen = _array(o)->Size(); if(sidx < 0)sidx = alen + sidx; if(eidx < 0)eidx = alen + eidx; if(eidx < sidx)return sq_throwerror(v,"wrong indexes"); if(eidx > alen)return sq_throwerror(v,"slice out of range"); SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); SQObjectPtr t; SQInteger count=0; for(SQInteger i=sidx;iGet(i,t); arr->Set(count++,t); } v->Push(arr); return 1; } SQRegFunction SQSharedState::_array_default_delegate_funcz[]={ {"len",default_delegate_len,1, "a"}, {"append",array_append,2, "a"}, {"extend",array_extend,2, "aa"}, {"push",array_append,2, "a"}, {"pop",array_pop,1, "a"}, {"top",array_top,1, "a"}, {"insert",array_insert,3, "an"}, {"remove",array_remove,2, "an"}, {"resize",array_resize,-2, "an"}, {"reverse",array_reverse,1, "a"}, {"sort",array_sort,-1, "ac"}, {"slice",array_slice,-1, "ann"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {"clear",obj_clear,1, "."}, {0,0,0,0} }; //STRING DEFAULT DELEGATE////////////////////////// static SQInteger string_slice(HSQUIRRELVM v) { SQInteger sidx,eidx; SQObjectPtr o; if(SQ_FAILED(get_slice_params(v,sidx,eidx,o)))return -1; SQInteger slen = _string(o)->_len; if(sidx < 0)sidx = slen + sidx; if(eidx < 0)eidx = slen + eidx; if(eidx < sidx) return sq_throwerror(v,"wrong indexes"); if(eidx > slen) return sq_throwerror(v,"slice out of range"); v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); return 1; } static SQInteger string_find(HSQUIRRELVM v) { SQInteger top,start_idx=0; const SQChar *str,*substr,*ret; if(((top=sq_gettop(v))>1) && SQ_SUCCEEDED(sq_getstring(v,1,&str)) && SQ_SUCCEEDED(sq_getstring(v,2,&substr))){ if(top>2)sq_getinteger(v,3,&start_idx); if((sq_getsize(v,1)>start_idx) && (start_idx>=0)){ ret=strstr(&str[start_idx],substr); if(ret){ sq_pushinteger(v,(SQInteger)(ret-str)); return 1; } } return 0; } return sq_throwerror(v,"invalid param"); } #define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \ { \ SQObject str=stack_get(v,1); \ SQInteger len=_string(str)->_len; \ const SQChar *sThis=_stringval(str); \ SQChar *sNew=(_ss(v)->GetScratchPad(len)); \ for(SQInteger i=0;iPush(SQString::Create(_ss(v),sNew,len)); \ return 1; \ } STRING_TOFUNCZ(tolower) STRING_TOFUNCZ(toupper) SQRegFunction SQSharedState::_string_default_delegate_funcz[]={ {"len",default_delegate_len,1, "s"}, {"tointeger",default_delegate_tointeger,1, "s"}, {"tofloat",default_delegate_tofloat,1, "s"}, {"tostring",default_delegate_tostring,1, "."}, {"slice",string_slice,-1, " s n n"}, {"find",string_find,-2, "s s n "}, {"tolower",string_tolower,1, "s"}, {"toupper",string_toupper,1, "s"}, {"weakref",obj_delegate_weakref,1, NULL }, {0,0,0,0} }; //INTEGER DEFAULT DELEGATE////////////////////////// SQRegFunction SQSharedState::_number_default_delegate_funcz[]={ {"tointeger",default_delegate_tointeger,1, "n|b"}, {"tofloat",default_delegate_tofloat,1, "n|b"}, {"tostring",default_delegate_tostring,1, "."}, {"tochar",number_delegate_tochar,1, "n|b"}, {"weakref",obj_delegate_weakref,1, NULL }, {0,0,0,0} }; //CLOSURE DEFAULT DELEGATE////////////////////////// static SQInteger closure_pcall(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQFalse))?1:SQ_ERROR; } static SQInteger closure_call(HSQUIRRELVM v) { return SQ_SUCCEEDED(sq_call(v,sq_gettop(v)-1,SQTrue,SQTrue))?1:SQ_ERROR; } static SQInteger _closure_acall(HSQUIRRELVM v,SQBool raiseerror) { SQArray *aparams=_array(stack_get(v,2)); SQInteger nparams=aparams->Size(); v->Push(stack_get(v,1)); for(SQInteger i=0;iPush(aparams->_values[i]); return SQ_SUCCEEDED(sq_call(v,nparams,SQTrue,raiseerror))?1:SQ_ERROR; } static SQInteger closure_acall(HSQUIRRELVM v) { return _closure_acall(v,SQTrue); } static SQInteger closure_pacall(HSQUIRRELVM v) { return _closure_acall(v,SQFalse); } static SQInteger closure_bindenv(HSQUIRRELVM v) { if(SQ_FAILED(sq_bindenv(v,1))) return SQ_ERROR; return 1; } static SQInteger closure_getinfos(HSQUIRRELVM v) { SQObject o = stack_get(v,1); SQTable *res = SQTable::Create(_ss(v),4); if(type(o) == OT_CLOSURE) { SQFunctionProto *f = _funcproto(_closure(o)->_function); SQInteger nparams = f->_nparameters + (f->_varparams?1:0); SQObjectPtr params = SQArray::Create(_ss(v),nparams); for(SQInteger n = 0; n_nparameters; n++) { _array(params)->Set((SQInteger)n,f->_parameters[n]); } if(f->_varparams) { _array(params)->Set(nparams-1,SQString::Create(_ss(v),"...",-1)); } res->NewSlot(SQString::Create(_ss(v),"native",-1),false); res->NewSlot(SQString::Create(_ss(v),"name",-1),f->_name); res->NewSlot(SQString::Create(_ss(v),"src",-1),f->_sourcename); res->NewSlot(SQString::Create(_ss(v),"parameters",-1),params); res->NewSlot(SQString::Create(_ss(v),"varargs",-1),f->_varparams); } else { //OT_NATIVECLOSURE SQNativeClosure *nc = _nativeclosure(o); res->NewSlot(SQString::Create(_ss(v),"native",-1),true); res->NewSlot(SQString::Create(_ss(v),"name",-1),nc->_name); res->NewSlot(SQString::Create(_ss(v),"paramscheck",-1),nc->_nparamscheck); SQObjectPtr typecheck; if(nc->_typecheck.size() > 0) { typecheck = SQArray::Create(_ss(v), nc->_typecheck.size()); for(SQUnsignedInteger n = 0; n_typecheck.size(); n++) { _array(typecheck)->Set((SQInteger)n,nc->_typecheck[n]); } } res->NewSlot(SQString::Create(_ss(v),"typecheck",-1),typecheck); } v->Push(res); return 1; } SQRegFunction SQSharedState::_closure_default_delegate_funcz[]={ {"call",closure_call,-1, "c"}, {"pcall",closure_pcall,-1, "c"}, {"acall",closure_acall,2, "ca"}, {"pacall",closure_pacall,2, "ca"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {"bindenv",closure_bindenv,2, "c x|y|t"}, {"getinfos",closure_getinfos,1, "c"}, {0,0,0,0} }; //GENERATOR DEFAULT DELEGATE static SQInteger generator_getstatus(HSQUIRRELVM v) { SQObject &o=stack_get(v,1); switch(_generator(o)->_state){ case SQGenerator::eSuspended:v->Push(SQString::Create(_ss(v),"suspended"));break; case SQGenerator::eRunning:v->Push(SQString::Create(_ss(v),"running"));break; case SQGenerator::eDead:v->Push(SQString::Create(_ss(v),"dead"));break; } return 1; } SQRegFunction SQSharedState::_generator_default_delegate_funcz[]={ {"getstatus",generator_getstatus,1, "g"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {0,0,0,0} }; //THREAD DEFAULT DELEGATE static SQInteger thread_call(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(type(o) == OT_THREAD) { SQInteger nparams = sq_gettop(v); _thread(o)->Push(_thread(o)->_roottable); for(SQInteger i = 2; i<(nparams+1); i++) sq_move(_thread(o),v,i); if(SQ_SUCCEEDED(sq_call(_thread(o),nparams,SQTrue,SQFalse))) { sq_move(v,_thread(o),-1); sq_pop(_thread(o),1); return 1; } v->_lasterror = _thread(o)->_lasterror; return SQ_ERROR; } return sq_throwerror(v,"wrong parameter"); } static SQInteger thread_wakeup(HSQUIRRELVM v) { SQObjectPtr o = stack_get(v,1); if(type(o) == OT_THREAD) { SQVM *thread = _thread(o); SQInteger state = sq_getvmstate(thread); if(state != SQ_VMSTATE_SUSPENDED) { switch(state) { case SQ_VMSTATE_IDLE: return sq_throwerror(v,"cannot wakeup a idle thread"); break; case SQ_VMSTATE_RUNNING: return sq_throwerror(v,"cannot wakeup a running thread"); break; } } SQInteger wakeupret = sq_gettop(v)>1?1:0; if(wakeupret) { sq_move(thread,v,2); } if(SQ_SUCCEEDED(sq_wakeupvm(thread,wakeupret,SQTrue,SQTrue,SQFalse))) { sq_move(v,thread,-1); sq_pop(thread,1); //pop retval if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) { sq_settop(thread,1); //pop roottable } return 1; } sq_settop(thread,1); v->_lasterror = thread->_lasterror; return SQ_ERROR; } return sq_throwerror(v,"wrong parameter"); } static SQInteger thread_getstatus(HSQUIRRELVM v) { SQObjectPtr &o = stack_get(v,1); switch(sq_getvmstate(_thread(o))) { case SQ_VMSTATE_IDLE: sq_pushstring(v,"idle",-1); break; case SQ_VMSTATE_RUNNING: sq_pushstring(v,"running",-1); break; case SQ_VMSTATE_SUSPENDED: sq_pushstring(v,"suspended",-1); break; default: return sq_throwerror(v,"internal VM error"); } return 1; } SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { {"call", thread_call, -1, "v"}, {"wakeup", thread_wakeup, -1, "v"}, {"getstatus", thread_getstatus, 1, "v"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {0,0,0,0}, }; static SQInteger class_getattributes(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_getattributes(v,-2))) return 1; return SQ_ERROR; } static SQInteger class_setattributes(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_setattributes(v,-3))) return 1; return SQ_ERROR; } static SQInteger class_instance(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_createinstance(v,-1))) return 1; return SQ_ERROR; } SQRegFunction SQSharedState::_class_default_delegate_funcz[] = { {"getattributes", class_getattributes, 2, "y."}, {"setattributes", class_setattributes, 3, "y.."}, {"rawin",container_rawexists,2, "y"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {"instance",class_instance,1, "y"}, {0,0,0,0} }; static SQInteger instance_getclass(HSQUIRRELVM v) { if(SQ_SUCCEEDED(sq_getclass(v,1))) return 1; return SQ_ERROR; } SQRegFunction SQSharedState::_instance_default_delegate_funcz[] = { {"getclass", instance_getclass, 1, "x"}, {"rawin",container_rawexists,2, "x"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {0,0,0,0} }; static SQInteger weakref_ref(HSQUIRRELVM v) { if(SQ_FAILED(sq_getweakrefval(v,1))) return SQ_ERROR; return 1; } SQRegFunction SQSharedState::_weakref_default_delegate_funcz[] = { {"ref",weakref_ref,1, "r"}, {"weakref",obj_delegate_weakref,1, NULL }, {"tostring",default_delegate_tostring,1, "."}, {0,0,0,0} }; openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqclass.cpp0000644000000000000000000001103712627373445022142 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include "sqpcheader.h" #include "sqvm.h" #include "sqtable.h" #include "sqclass.h" #include "sqclosure.h" #include "../../../safeguards.h" SQClass::SQClass(SQSharedState *ss,SQClass *base) { _base = base; _typetag = 0; _hook = NULL; _udsize = 0; _metamethods.resize(MT_LAST); //size it to max size if(_base) { _defaultvalues.copy(base->_defaultvalues); _methods.copy(base->_methods); _metamethods.copy(base->_metamethods); __ObjAddRef(_base); } _members = base?base->_members->Clone() : SQTable::Create(ss,0); __ObjAddRef(_members); _locked = false; INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); } void SQClass::Finalize() { _attributes = _null_; _defaultvalues.resize(0); _methods.resize(0); _metamethods.resize(0); __ObjRelease(_members); if(_base) { __ObjRelease(_base); } } SQClass::~SQClass() { REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); Finalize(); } bool SQClass::NewSlot(SQSharedState *ss,const SQObjectPtr &key,const SQObjectPtr &val,bool bstatic) { SQObjectPtr temp; if(_locked) return false; //the class already has an instance so cannot be modified if(_members->Get(key,temp) && _isfield(temp)) //overrides the default value { _defaultvalues[_member_idx(temp)].val = val; return true; } if(type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE || bstatic) { SQInteger mmidx; if((type(val) == OT_CLOSURE || type(val) == OT_NATIVECLOSURE) && (mmidx = ss->GetMetaMethodIdxByName(key)) != -1) { _metamethods[mmidx] = val; } else { if(type(temp) == OT_NULL) { SQClassMember m; m.val = val; _members->NewSlot(key,SQObjectPtr(_make_method_idx(_methods.size()))); _methods.push_back(m); } else { _methods[_member_idx(temp)].val = val; } } return true; } SQClassMember m; m.val = val; _members->NewSlot(key,SQObjectPtr(_make_field_idx(_defaultvalues.size()))); _defaultvalues.push_back(m); return true; } SQInstance *SQClass::CreateInstance() { if(!_locked) Lock(); return SQInstance::Create(_opt_ss(this),this); } SQInteger SQClass::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQObjectPtr oval; SQInteger idx = _members->Next(false,refpos,outkey,oval); if(idx != -1) { if(_ismethod(oval)) { outval = _methods[_member_idx(oval)].val; } else { SQObjectPtr &o = _defaultvalues[_member_idx(oval)].val; outval = _realval(o); } } return idx; } bool SQClass::SetAttributes(const SQObjectPtr &key,const SQObjectPtr &val) { SQObjectPtr idx; if(_members->Get(key,idx)) { if(_isfield(idx)) _defaultvalues[_member_idx(idx)].attrs = val; else _methods[_member_idx(idx)].attrs = val; return true; } return false; } bool SQClass::GetAttributes(const SQObjectPtr &key,SQObjectPtr &outval) { SQObjectPtr idx; if(_members->Get(key,idx)) { outval = (_isfield(idx)?_defaultvalues[_member_idx(idx)].attrs:_methods[_member_idx(idx)].attrs); return true; } return false; } /////////////////////////////////////////////////////////////////////// void SQInstance::Init(SQSharedState *ss) { _userpointer = NULL; _hook = NULL; __ObjAddRef(_class); _delegate = _class->_members; INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain, this); } SQInstance::SQInstance(SQSharedState *ss, SQClass *c, SQInteger memsize) { _memsize = memsize; _class = c; SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger n = 0; n < nvalues; n++) { new (&_values[n]) SQObjectPtr(_class->_defaultvalues[n].val); } Init(ss); } SQInstance::SQInstance(SQSharedState *ss, SQInstance *i, SQInteger memsize) { _memsize = memsize; _class = i->_class; SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger n = 0; n < nvalues; n++) { new (&_values[n]) SQObjectPtr(i->_values[n]); } Init(ss); } void SQInstance::Finalize() { SQUnsignedInteger nvalues = _class->_defaultvalues.size(); __ObjRelease(_class); for(SQUnsignedInteger i = 0; i < nvalues; i++) { _values[i] = _null_; } } SQInstance::~SQInstance() { REMOVE_FROM_CHAIN(&_sharedstate->_gc_chain, this); if(_class){ Finalize(); } //if _class is null it was already finalized by the GC } bool SQInstance::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { if(type(_class->_metamethods[mm]) != OT_NULL) { res = _class->_metamethods[mm]; return true; } return false; } bool SQInstance::InstanceOf(SQClass *trg) { SQClass *parent = _class; while(parent != NULL) { if(parent == trg) return true; parent = parent->_base; } return false; } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqmem.cpp0000644000000000000000000000071712627373445021616 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include "sqpcheader.h" #include "../../../core/alloc_func.hpp" #include "../../../safeguards.h" void *sq_vm_malloc(SQUnsignedInteger size){ return MallocT((size_t)size); } void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return ReallocT(static_cast(p), (size_t)size); } void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqapi.cpp0000644000000000000000000007410712627373445021615 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include #include "sqpcheader.h" #include "sqvm.h" #include "sqstring.h" #include "sqtable.h" #include "sqarray.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "squserdata.h" #include "sqcompiler.h" #include "sqfuncstate.h" #include "sqclass.h" #include "../../../string_func.h" #include "../../../safeguards.h" bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o) { *o = &stack_get(v,idx); if(type(**o) != type){ SQObjectPtr oval = v->PrintObjVal(**o); v->Raise_Error("wrong argument type, expected '%s' got '%.50s'",IdType2Name(type),_stringval(oval)); return false; } return true; } #define _GETSAFE_OBJ(v,idx,type,o) { if(!sq_aux_gettypedarg(v,idx,type,&o)) return SQ_ERROR; } #define sq_aux_paramscheck(v,count) \ { \ if(sq_gettop(v) < count){ v->Raise_Error("not enough params in the stack"); return SQ_ERROR; }\ } SQInteger sq_aux_throwobject(HSQUIRRELVM v,SQObjectPtr &e) { v->_lasterror = e; return SQ_ERROR; } SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) { char buf[100]; seprintf(buf, lastof(buf), "unexpected type %s", IdType2Name(type)); return sq_throwerror(v, buf); } HSQUIRRELVM sq_open(SQInteger initialstacksize) { SQSharedState *ss; SQVM *v; sq_new(ss, SQSharedState); v = (SQVM *)SQ_MALLOC(sizeof(SQVM)); new (v) SQVM(ss); ss->_root_vm = v; if(v->Init(NULL, initialstacksize)) { return v; } else { sq_delete(v, SQVM); return NULL; } return v; } HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize) { SQSharedState *ss; SQVM *v; ss=_ss(friendvm); v= (SQVM *)SQ_MALLOC(sizeof(SQVM)); new (v) SQVM(ss); if(v->Init(friendvm, initialstacksize)) { friendvm->Push(v); return v; } else { sq_delete(v, SQVM); return NULL; } } SQInteger sq_getvmstate(HSQUIRRELVM v) { if(v->_suspended) return SQ_VMSTATE_SUSPENDED; else { if(v->_callsstacksize != 0) return SQ_VMSTATE_RUNNING; else return SQ_VMSTATE_IDLE; } } void sq_decreaseops(HSQUIRRELVM v, int amount) { v->DecreaseOps(amount); } bool sq_can_suspend(HSQUIRRELVM v) { return v->_nnativecalls <= 2; } void sq_seterrorhandler(HSQUIRRELVM v) { SQObject o = stack_get(v, -1); if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { v->_errorhandler = o; v->Pop(); } } void sq_setdebughook(HSQUIRRELVM v) { SQObject o = stack_get(v,-1); if(sq_isclosure(o) || sq_isnativeclosure(o) || sq_isnull(o)) { v->_debughook = o; v->Pop(); } } void sq_close(HSQUIRRELVM v) { SQSharedState *ss = _ss(v); _thread(ss->_root_vm)->Finalize(); sq_delete(ss, SQSharedState); } SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror) { SQObjectPtr o; if(Compile(v, read, p, sourcename, o, raiseerror?true:false, _ss(v)->_debuginfo)) { v->Push(SQClosure::Create(_ss(v), _funcproto(o))); return SQ_OK; } return SQ_ERROR; } void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable) { _ss(v)->_debuginfo = enable?true:false; } void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable) { _ss(v)->_notifyallexceptions = enable?true:false; } void sq_addref(HSQUIRRELVM v,HSQOBJECT *po) { if(!ISREFCOUNTED(type(*po))) return; #ifdef NO_GARBAGE_COLLECTOR __AddRef(po->_type,po->_unVal); #else _ss(v)->_refs_table.AddRef(*po); #endif } SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po) { if(!ISREFCOUNTED(type(*po))) return SQTrue; #ifdef NO_GARBAGE_COLLECTOR __Release(po->_type,po->_unVal); return SQFalse; //the ret val doesn't work(and cannot be fixed) #else return _ss(v)->_refs_table.Release(*po); #endif } const SQChar *sq_objtostring(HSQOBJECT *o) { if(sq_type(*o) == OT_STRING) { return _stringval(*o); } return NULL; } SQInteger sq_objtointeger(HSQOBJECT *o) { if(sq_isnumeric(*o)) { return tointeger(*o); } return 0; } SQFloat sq_objtofloat(HSQOBJECT *o) { if(sq_isnumeric(*o)) { return tofloat(*o); } return 0; } SQBool sq_objtobool(HSQOBJECT *o) { if(sq_isbool(*o)) { return _integer(*o); } return SQFalse; } void sq_pushnull(HSQUIRRELVM v) { v->Push(_null_); } void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len) { if(s) v->Push(SQObjectPtr(SQString::Create(_ss(v), s, len))); else v->Push(_null_); } void sq_pushinteger(HSQUIRRELVM v,SQInteger n) { v->Push(n); } void sq_pushbool(HSQUIRRELVM v,SQBool b) { v->Push(b?true:false); } void sq_pushfloat(HSQUIRRELVM v,SQFloat n) { v->Push(n); } void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p) { v->Push(p); } SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size) { SQUserData *ud = SQUserData::Create(_ss(v), size); v->Push(ud); return ud->_val; } void sq_newtable(HSQUIRRELVM v) { v->Push(SQTable::Create(_ss(v), 0)); } void sq_newarray(HSQUIRRELVM v,SQInteger size) { v->Push(SQArray::Create(_ss(v), size)); } SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase) { SQClass *baseclass = NULL; if(hasbase) { SQObjectPtr &base = stack_get(v,-1); if(type(base) != OT_CLASS) return sq_throwerror(v,"invalid base type"); baseclass = _class(base); } SQClass *newclass = SQClass::Create(_ss(v), baseclass); if(baseclass) v->Pop(); v->Push(newclass); return SQ_OK; } SQBool sq_instanceof(HSQUIRRELVM v) { SQObjectPtr &inst = stack_get(v,-1); SQObjectPtr &cl = stack_get(v,-2); if(type(inst) != OT_INSTANCE || type(cl) != OT_CLASS) return sq_throwerror(v,"invalid param type"); return _instance(inst)->InstanceOf(_class(cl))?SQTrue:SQFalse; } SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx) { sq_aux_paramscheck(v,2); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); _array(*arr)->Append(v->GetUp(-1)); v->Pop(1); return SQ_OK; } SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval) { sq_aux_paramscheck(v, 1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); if(_array(*arr)->Size() > 0) { if(pushval != 0){ v->Push(_array(*arr)->Top()); } _array(*arr)->Pop(); return SQ_OK; } return sq_throwerror(v, "empty array"); } SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize) { sq_aux_paramscheck(v,1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); if(newsize >= 0) { _array(*arr)->Resize(newsize); return SQ_OK; } return sq_throwerror(v,"negative size"); } SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx) { sq_aux_paramscheck(v, 1); SQObjectPtr *o; _GETSAFE_OBJ(v, idx, OT_ARRAY,o); SQArray *arr = _array(*o); if(arr->Size() > 0) { SQObjectPtr t; SQInteger size = arr->Size(); SQInteger n = size >> 1; size -= 1; for(SQInteger i = 0; i < n; i++) { t = arr->_values[i]; arr->_values[i] = arr->_values[size-i]; arr->_values[size-i] = t; } return SQ_OK; } return SQ_OK; } SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx) { sq_aux_paramscheck(v, 1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); return _array(*arr)->Remove(itemidx) ? SQ_OK : sq_throwerror(v,"index out of range"); } SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos) { sq_aux_paramscheck(v, 1); SQObjectPtr *arr; _GETSAFE_OBJ(v, idx, OT_ARRAY,arr); SQRESULT ret = _array(*arr)->Insert(destpos, v->GetUp(-1)) ? SQ_OK : sq_throwerror(v,"index out of range"); v->Pop(); return ret; } void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars) { SQNativeClosure *nc = SQNativeClosure::Create(_ss(v), func); for(SQUnsignedInteger i = 0; i < nfreevars; i++) { nc->_outervalues.push_back(v->Top()); v->Pop(); } v->Push(SQObjectPtr(nc)); } SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars) { SQObject o = stack_get(v, idx); if(sq_isclosure(o)) { SQClosure *c = _closure(o); SQFunctionProto *proto = _funcproto(c->_function); *nparams = (SQUnsignedInteger)proto->_nparameters; *nfreevars = (SQUnsignedInteger)c->_outervalues.size(); return SQ_OK; } return sq_throwerror(v,"the object is not a closure"); } SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name) { SQObject o = stack_get(v, idx); if(sq_isnativeclosure(o)) { SQNativeClosure *nc = _nativeclosure(o); nc->_name = SQString::Create(_ss(v),name); return SQ_OK; } return sq_throwerror(v,"the object is not a nativeclosure"); } SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask) { SQObject o = stack_get(v, -1); if(!sq_isnativeclosure(o)) return sq_throwerror(v, "native closure expected"); SQNativeClosure *nc = _nativeclosure(o); nc->_nparamscheck = nparamscheck; if(typemask) { SQIntVec res; if(!CompileTypemask(res, typemask)) return sq_throwerror(v, "invalid typemask"); nc->_typecheck.copy(res); } else { nc->_typecheck.resize(0); } if(nparamscheck == SQ_MATCHTYPEMASKSTRING) { nc->_nparamscheck = nc->_typecheck.size(); } return SQ_OK; } SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v,idx); if(!sq_isnativeclosure(o) && !sq_isclosure(o)) return sq_throwerror(v,"the target is not a closure"); SQObjectPtr &env = stack_get(v,-1); if(!sq_istable(env) && !sq_isclass(env) && !sq_isinstance(env)) return sq_throwerror(v,"invalid environment"); SQObjectPtr w = _refcounted(env)->GetWeakRef(type(env)); SQObjectPtr ret; if(sq_isclosure(o)) { SQClosure *c = _closure(o)->Clone(); c->_env = w; ret = c; } else { //then must be a native closure SQNativeClosure *c = _nativeclosure(o)->Clone(); c->_env = w; ret = c; } v->Pop(); v->Push(ret); return SQ_OK; } SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx) { SQObject &o=stack_get(v,idx); switch(type(o)) { case OT_TABLE: _table(o)->Clear(); break; case OT_ARRAY: _array(o)->Resize(0); break; default: return sq_throwerror(v, "clear only works on table and array"); break; } return SQ_OK; } void sq_pushroottable(HSQUIRRELVM v) { v->Push(v->_roottable); } void sq_pushregistrytable(HSQUIRRELVM v) { v->Push(_ss(v)->_registry); } void sq_pushconsttable(HSQUIRRELVM v) { v->Push(_ss(v)->_consts); } SQRESULT sq_setroottable(HSQUIRRELVM v) { SQObject o = stack_get(v, -1); if(sq_istable(o) || sq_isnull(o)) { v->_roottable = o; v->Pop(); return SQ_OK; } return sq_throwerror(v, "ivalid type"); } SQRESULT sq_setconsttable(HSQUIRRELVM v) { SQObject o = stack_get(v, -1); if(sq_istable(o)) { _ss(v)->_consts = o; v->Pop(); return SQ_OK; } return sq_throwerror(v, "ivalid type, expected table"); } void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p) { v->_foreignptr = p; } SQUserPointer sq_getforeignptr(HSQUIRRELVM v) { return v->_foreignptr; } void sq_push(HSQUIRRELVM v,SQInteger idx) { v->Push(stack_get(v, idx)); } SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx) { return type(stack_get(v, idx)); } void sq_tostring(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v, idx); SQObjectPtr res; v->ToString(o,res); v->Push(res); } void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b) { SQObjectPtr &o = stack_get(v, idx); *b = v->IsFalse(o)?SQFalse:SQTrue; } SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i) { SQObjectPtr &o = stack_get(v, idx); if(sq_isnumeric(o)) { *i = tointeger(o); return SQ_OK; } return SQ_ERROR; } SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f) { SQObjectPtr &o = stack_get(v, idx); if(sq_isnumeric(o)) { *f = tofloat(o); return SQ_OK; } return SQ_ERROR; } SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b) { SQObjectPtr &o = stack_get(v, idx); if(sq_isbool(o)) { *b = _integer(o); return SQ_OK; } return SQ_ERROR; } SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_STRING,o); *c = _stringval(*o); return SQ_OK; } SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_THREAD,o); *thread = _thread(*o); return SQ_OK; } SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v,idx); v->Push(_null_); if(!v->Clone(o, stack_get(v, -1))){ v->Pop(); return sq_aux_invalidtype(v, type(o)); } return SQ_OK; } SQInteger sq_getsize(HSQUIRRELVM v, SQInteger idx) { SQObjectPtr &o = stack_get(v, idx); SQObjectType type = type(o); switch(type) { case OT_STRING: return _string(o)->_len; case OT_TABLE: return _table(o)->CountUsed(); case OT_ARRAY: return _array(o)->Size(); case OT_USERDATA: return _userdata(o)->_size; case OT_INSTANCE: return _instance(o)->_class->_udsize; case OT_CLASS: return _class(o)->_udsize; default: return sq_aux_invalidtype(v, type); } } SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_USERDATA,o); (*p) = _userdataval(*o); if(typetag) *typetag = _userdata(*o)->_typetag; return SQ_OK; } SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag) { SQObjectPtr &o = stack_get(v,idx); switch(type(o)) { case OT_USERDATA: _userdata(o)->_typetag = typetag; break; case OT_CLASS: _class(o)->_typetag = typetag; break; default: return sq_throwerror(v,"invalid object type"); } return SQ_OK; } SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag) { switch(type(*o)) { case OT_INSTANCE: *typetag = _instance(*o)->_class->_typetag; break; case OT_USERDATA: *typetag = _userdata(*o)->_typetag; break; case OT_CLASS: *typetag = _class(*o)->_typetag; break; default: return SQ_ERROR; } return SQ_OK; } SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag) { SQObjectPtr &o = stack_get(v,idx); if(SQ_FAILED(sq_getobjtypetag(&o,typetag))) return sq_throwerror(v,"invalid object type"); return SQ_OK; } SQRESULT sq_getuserpointer(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_USERPOINTER,o); (*p) = _userpointer(*o); return SQ_OK; } SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p) { SQObjectPtr &o = stack_get(v,idx); if(type(o) != OT_INSTANCE) return sq_throwerror(v,"the object is not a class instance"); _instance(o)->_userpointer = p; return SQ_OK; } SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize) { SQObjectPtr &o = stack_get(v,idx); if(type(o) != OT_CLASS) return sq_throwerror(v,"the object is not a class"); if(_class(o)->_locked) return sq_throwerror(v,"the class is locked"); _class(o)->_udsize = udsize; return SQ_OK; } SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag) { SQObjectPtr &o = stack_get(v,idx); if(type(o) != OT_INSTANCE) return sq_throwerror(v,"the object is not a class instance"); (*p) = _instance(o)->_userpointer; if(typetag != 0) { SQClass *cl = _instance(o)->_class; do{ if(cl->_typetag == typetag) return SQ_OK; cl = cl->_base; }while(cl != NULL); return sq_throwerror(v,"invalid type tag"); } return SQ_OK; } SQInteger sq_gettop(HSQUIRRELVM v) { return (v->_top) - v->_stackbase; } void sq_settop(HSQUIRRELVM v, SQInteger newtop) { SQInteger top = sq_gettop(v); if(top > newtop) sq_pop(v, top - newtop); else while(top++ < newtop) sq_pushnull(v); } void sq_pop(HSQUIRRELVM v, SQInteger nelemstopop) { assert(v->_top >= nelemstopop); v->Pop(nelemstopop); } void sq_poptop(HSQUIRRELVM v) { assert(v->_top >= 1); v->Pop(); } void sq_remove(HSQUIRRELVM v, SQInteger idx) { v->Remove(idx); } SQInteger sq_cmp(HSQUIRRELVM v) { SQInteger res; v->ObjCmp(stack_get(v, -1), stack_get(v, -2),res); return res; } SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic) { sq_aux_paramscheck(v, 3); SQObjectPtr &self = stack_get(v, idx); if(type(self) == OT_TABLE || type(self) == OT_CLASS) { SQObjectPtr &key = v->GetUp(-2); if(type(key) == OT_NULL) return sq_throwerror(v, "null is not a valid key"); v->NewSlot(self, key, v->GetUp(-1),bstatic?true:false); v->Pop(2); } return SQ_OK; } SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) { sq_aux_paramscheck(v, 2); SQObjectPtr *self; _GETSAFE_OBJ(v, idx, OT_TABLE,self); SQObjectPtr &key = v->GetUp(-1); if(type(key) == OT_NULL) return sq_throwerror(v, "null is not a valid key"); SQObjectPtr res; if(!v->DeleteSlot(*self, key, res)){ return SQ_ERROR; } if(pushval) v->GetUp(-1) = res; else v->Pop(1); return SQ_OK; } SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self = stack_get(v, idx); if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { v->Pop(2); return SQ_OK; } v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; } SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self = stack_get(v, idx); if(type(v->GetUp(-2)) == OT_NULL) return sq_throwerror(v, "null key"); switch(type(self)) { case OT_TABLE: _table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); v->Pop(2); return SQ_OK; break; case OT_CLASS: _class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false); v->Pop(2); return SQ_OK; break; case OT_INSTANCE: if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) { v->Pop(2); return SQ_OK; } break; case OT_ARRAY: if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { v->Pop(2); return SQ_OK; } break; default: v->Pop(2); return sq_throwerror(v, "rawset works only on array/table/class and instance"); } v->Raise_IdxError(v->GetUp(-2));return SQ_ERROR; } SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self = stack_get(v, idx); SQObjectPtr &mt = v->GetUp(-1); SQObjectType type = type(self); switch(type) { case OT_TABLE: if(type(mt) == OT_TABLE) { if(!_table(self)->SetDelegate(_table(mt))) return sq_throwerror(v, "delagate cycle"); v->Pop();} else if(type(mt)==OT_NULL) { _table(self)->SetDelegate(NULL); v->Pop(); } else return sq_aux_invalidtype(v,type); break; case OT_USERDATA: if(type(mt)==OT_TABLE) { _userdata(self)->SetDelegate(_table(mt)); v->Pop(); } else if(type(mt)==OT_NULL) { _userdata(self)->SetDelegate(NULL); v->Pop(); } else return sq_aux_invalidtype(v, type); break; default: return sq_aux_invalidtype(v, type); break; } return SQ_OK; } SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval) { sq_aux_paramscheck(v, 2); SQObjectPtr *self; _GETSAFE_OBJ(v, idx, OT_TABLE,self); SQObjectPtr &key = v->GetUp(-1); SQObjectPtr t; if(_table(*self)->Get(key,t)) { _table(*self)->Remove(key); } if(pushval != 0) { if(pushval) v->GetUp(-1) = t; } else { v->Pop(1); } return SQ_OK; } SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self=stack_get(v,idx); switch(type(self)){ case OT_TABLE: case OT_USERDATA: if(!_delegable(self)->_delegate){ v->Push(_null_); break; } v->Push(SQObjectPtr(_delegable(self)->_delegate)); break; default: return sq_throwerror(v,"wrong type"); break; } return SQ_OK; } SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self=stack_get(v,idx); if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) return SQ_OK; v->Pop(1); return sq_throwerror(v,"the index doesn't exist"); } SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &self=stack_get(v,idx); switch(type(self)) { case OT_TABLE: if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1))) return SQ_OK; break; case OT_CLASS: if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1))) return SQ_OK; break; case OT_INSTANCE: if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1))) return SQ_OK; break; case OT_ARRAY: if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,false)) return SQ_OK; break; default: v->Pop(1); return sq_throwerror(v,"rawget works only on array/table/instance and class"); } v->Pop(1); return sq_throwerror(v,"the index doesn't exist"); } SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po) { *po=stack_get(v,idx); return SQ_OK; } const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx) { SQUnsignedInteger cstksize=v->_callsstacksize; SQUnsignedInteger lvl=(cstksize-level)-1; SQInteger stackbase=v->_stackbase; if(lvl_callsstack[(cstksize-i)-1]; stackbase-=ci._prevstkbase; } SQVM::CallInfo &ci=v->_callsstack[lvl]; if(type(ci._closure)!=OT_CLOSURE) return NULL; SQClosure *c=_closure(ci._closure); SQFunctionProto *func=_funcproto(c->_function); if(func->_noutervalues > (SQInteger)idx) { v->Push(c->_outervalues[idx]); return _stringval(func->_outervalues[idx]._name); } idx -= func->_noutervalues; return func->GetLocal(v,stackbase,idx,(SQInteger)(ci._ip-func->_instructions)-1); } return NULL; } void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj) { v->Push(SQObjectPtr(obj)); } void sq_resetobject(HSQOBJECT *po) { po->_unVal.pUserPointer=NULL;po->_type=OT_NULL; } SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err) { v->_lasterror=SQString::Create(_ss(v),err); return -1; } void sq_reseterror(HSQUIRRELVM v) { v->_lasterror = _null_; } void sq_getlasterror(HSQUIRRELVM v) { v->Push(v->_lasterror); } void sq_reservestack(HSQUIRRELVM v,SQInteger nsize) { if (((SQUnsignedInteger)v->_top + nsize) > v->_stack.size()) { v->_stack.resize(v->_stack.size() + ((v->_top + nsize) - v->_stack.size())); } } SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) { if(type(v->GetUp(-1))==OT_GENERATOR){ v->Push(_null_); //retval v->_can_suspend = false; if(!v->Execute(v->GetUp(-2),v->_top,0,v->_top,v->GetUp(-1),raiseerror,SQVM::ET_RESUME_GENERATOR)) {v->Raise_Error(v->_lasterror); return SQ_ERROR;} if(!retval) v->Pop(); return SQ_OK; } return sq_throwerror(v,"only generators can be resumed"); } SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror, int suspend) { SQObjectPtr res; v->_can_suspend = suspend >= 0; if (v->_can_suspend) v->_ops_till_suspend = suspend; if(v->Call(v->GetUp(-(params+1)),params,v->_top-params,res,raiseerror?true:false,v->_can_suspend)){ if(!v->_suspended) { v->Pop(params);//pop closure and args } if(retval){ v->Push(res); return SQ_OK; } return SQ_OK; } else { v->Pop(params); return SQ_ERROR; } } SQRESULT sq_suspendvm(HSQUIRRELVM v) { return v->Suspend(); } SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool wakeupret,SQBool retval,SQBool raiseerror,SQBool throwerror) { SQObjectPtr ret; if(!v->_suspended) return sq_throwerror(v,"cannot resume a vm that is not running any code"); if(wakeupret) { v->GetAt(v->_stackbase+v->_suspended_target)=v->GetUp(-1); //retval v->Pop(); } else v->GetAt(v->_stackbase+v->_suspended_target)=_null_; v->_can_suspend = false; if(!v->Execute(_null_,v->_top,-1,-1,ret,raiseerror,throwerror?SQVM::ET_RESUME_THROW_VM : SQVM::ET_RESUME_VM)) return SQ_ERROR; if(sq_getvmstate(v) == SQ_VMSTATE_IDLE) { while (v->_top > 1) v->_stack[--v->_top] = _null_; } if(retval) v->Push(ret); return SQ_OK; } bool sq_resumecatch(HSQUIRRELVM v, int suspend) { SQObjectPtr ret; v->_can_suspend = suspend >= 0; if (v->_can_suspend) v->_ops_till_suspend = suspend; return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_OPENTTD); } bool sq_resumeerror(HSQUIRRELVM v) { SQObjectPtr ret; v->_can_suspend = true; v->_ops_till_suspend = 1; return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_THROW_VM); } void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook) { if(sq_gettop(v) >= 1){ SQObjectPtr &ud=stack_get(v,idx); switch( type(ud) ) { case OT_USERDATA: _userdata(ud)->_hook = hook; break; case OT_INSTANCE: _instance(ud)->_hook = hook; break; case OT_CLASS: _class(ud)->_hook = hook; break; default: break; //shutup compiler } } } void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) { _ss(v)->_compilererrorhandler = f; } SQRESULT sq_writeclosure(HSQUIRRELVM v,SQWRITEFUNC w,SQUserPointer up) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, -1, OT_CLOSURE,o); unsigned short tag = SQ_BYTECODE_STREAM_TAG; if(w(up,&tag,2) != 2) return sq_throwerror(v,"io error"); if(!_closure(*o)->Save(v,up,w)) return SQ_ERROR; return SQ_OK; } SQRESULT sq_readclosure(HSQUIRRELVM v,SQREADFUNC r,SQUserPointer up) { SQObjectPtr closure; unsigned short tag; if(r(up,&tag,2) != 2) return sq_throwerror(v,"io error"); if(tag != SQ_BYTECODE_STREAM_TAG) return sq_throwerror(v,"invalid stream"); if(!SQClosure::Load(v,up,r,closure)) return SQ_ERROR; v->Push(closure); return SQ_OK; } SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize) { return _ss(v)->GetScratchPad(minsize); } SQInteger sq_collectgarbage(HSQUIRRELVM v) { #ifndef NO_GARBAGE_COLLECTOR return _ss(v)->CollectGarbage(v); #else return -1; #endif } const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) { SQObjectPtr &self = stack_get(v,idx); const SQChar *name = NULL; if(type(self) == OT_CLOSURE) { if(_closure(self)->_outervalues.size()>nval) { v->Push(_closure(self)->_outervalues[nval]); SQFunctionProto *fp = _funcproto(_closure(self)->_function); SQOuterVar &ov = fp->_outervalues[nval]; name = _stringval(ov._name); } } return name; } SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval) { SQObjectPtr &self=stack_get(v,idx); switch(type(self)) { case OT_CLOSURE: if(_closure(self)->_outervalues.size()>nval){ _closure(self)->_outervalues[nval]=stack_get(v,-1); } else return sq_throwerror(v,"invalid free var index"); break; case OT_NATIVECLOSURE: if(_nativeclosure(self)->_outervalues.size()>nval){ _nativeclosure(self)->_outervalues[nval]=stack_get(v,-1); } else return sq_throwerror(v,"invalid free var index"); break; default: return sq_aux_invalidtype(v,type(self)); } v->Pop(1); return SQ_OK; } SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); SQObjectPtr &key = stack_get(v,-2); SQObjectPtr &val = stack_get(v,-1); SQObjectPtr attrs; if(type(key) == OT_NULL) { attrs = _class(*o)->_attributes; _class(*o)->_attributes = val; v->Pop(2); v->Push(attrs); return SQ_OK; }else if(_class(*o)->GetAttributes(key,attrs)) { _class(*o)->SetAttributes(key,val); v->Pop(2); v->Push(attrs); return SQ_OK; } return sq_throwerror(v,"wrong index"); } SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); SQObjectPtr &key = stack_get(v,-1); SQObjectPtr attrs; if(type(key) == OT_NULL) { attrs = _class(*o)->_attributes; v->Pop(); v->Push(attrs); return SQ_OK; } else if(_class(*o)->GetAttributes(key,attrs)) { v->Pop(); v->Push(attrs); return SQ_OK; } return sq_throwerror(v,"wrong index"); } SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); if(_class(*o)->_base) v->Push(SQObjectPtr(_class(*o)->_base)); else v->Push(_null_); return SQ_OK; } SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_INSTANCE,o); v->Push(SQObjectPtr(_instance(*o)->_class)); return SQ_OK; } SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr *o = NULL; _GETSAFE_OBJ(v, idx, OT_CLASS,o); v->Push(_class(*o)->CreateInstance()); return SQ_OK; } void sq_weakref(HSQUIRRELVM v,SQInteger idx) { SQObject &o=stack_get(v,idx); if(ISREFCOUNTED(type(o))) { v->Push(_refcounted(o)->GetWeakRef(type(o))); return; } v->Push(o); } SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr &o = stack_get(v,idx); if(type(o) != OT_WEAKREF) { return sq_throwerror(v,"the object must be a weakref"); } v->Push(_weakref(o)->_obj); return SQ_OK; } SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t) { SQSharedState *ss = _ss(v); switch(t) { case OT_TABLE: v->Push(ss->_table_default_delegate); break; case OT_ARRAY: v->Push(ss->_array_default_delegate); break; case OT_STRING: v->Push(ss->_string_default_delegate); break; case OT_INTEGER: case OT_FLOAT: v->Push(ss->_number_default_delegate); break; case OT_GENERATOR: v->Push(ss->_generator_default_delegate); break; case OT_CLOSURE: case OT_NATIVECLOSURE: v->Push(ss->_closure_default_delegate); break; case OT_THREAD: v->Push(ss->_thread_default_delegate); break; case OT_CLASS: v->Push(ss->_class_default_delegate); break; case OT_INSTANCE: v->Push(ss->_instance_default_delegate); break; case OT_WEAKREF: v->Push(ss->_weakref_default_delegate); break; default: return sq_throwerror(v,"the type doesn't have a default delegate"); } return SQ_OK; } SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx) { SQObjectPtr o=stack_get(v,idx),&refpos = stack_get(v,-1),realkey,val; if(type(o) == OT_GENERATOR) { return sq_throwerror(v,"cannot iterate a generator"); } int faketojump; if(!v->FOREACH_OP(o,realkey,val,refpos,0,666,faketojump)) return SQ_ERROR; if(faketojump != 666) { v->Push(realkey); v->Push(val); return SQ_OK; } return SQ_ERROR; } struct BufState{ const SQChar *buf; SQInteger ptr; SQInteger size; }; WChar buf_lexfeed(SQUserPointer file) { /* Convert an UTF-8 character into a WChar */ BufState *buf = (BufState *)file; const char *p = &buf->buf[buf->ptr]; if (buf->size < buf->ptr + 1) return 0; /* Read the first character, and get the length based on UTF-8 specs. If invalid, bail out. */ uint len = Utf8EncodedCharLen(*p); if (len == 0) { buf->ptr++; return -1; } /* Read the remaining bits. */ if (buf->size < buf->ptr + len) return 0; buf->ptr += len; /* Convert the character, and when definitely invalid, bail out as well. */ WChar c; if (Utf8Decode(&c, p) != len) return -1; return c; } SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) { BufState buf; buf.buf = s; buf.size = size; buf.ptr = 0; return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); } void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx) { dest->Push(stack_get(src,idx)); } void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc) { _ss(v)->_printfunc = printfunc; } SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v) { return _ss(v)->_printfunc; } void *sq_malloc(SQUnsignedInteger size) { return SQ_MALLOC(size); } void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize) { return SQ_REALLOC(p,oldsize,newsize); } void sq_free(void *p,SQUnsignedInteger size) { SQ_FREE(p,size); } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqstring.h0000644000000000000000000000143312627373445022007 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQSTRING_H_ #define _SQSTRING_H_ inline SQHash _hashstr (const SQChar *s, size_t l) { SQHash h = (SQHash)l; /* seed */ size_t step = (l>>5)|1; /* if string is too long, don't hash all its chars */ for (; l>=step; l-=step) h = h ^ ((h<<5)+(h>>2)+(unsigned short)*(s++)); return h; } struct SQString : public SQRefCounted { SQString(const SQChar *news, SQInteger len); ~SQString(){} public: static SQString *Create(SQSharedState *ss, const SQChar *, SQInteger len = -1 ); SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); void Release(); SQSharedState *_sharedstate; SQString *_next; //chain for the string table SQInteger _len; SQHash _hash; SQChar _val[1]; }; #endif //_SQSTRING_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqpcheader.h0000644000000000000000000000042712627373445022256 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQPCHEADER_H_ #define _SQPCHEADER_H_ #if defined(_MSC_VER) && defined(_DEBUG) #include #endif #include //squirrel stuff #include #include "sqobject.h" #include "sqstate.h" #endif //_SQPCHEADER_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqtable.cpp0000644000000000000000000001071312627373445022124 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include "sqpcheader.h" #include "sqvm.h" #include "sqtable.h" #include "sqfuncproto.h" #include "sqclosure.h" #include "../../../safeguards.h" SQTable::SQTable(SQSharedState *ss,SQInteger nInitialSize) { SQInteger pow2size=MINPOWER2; while(nInitialSize>pow2size)pow2size=pow2size<<1; AllocNodes(pow2size); _usednodes = 0; _delegate = NULL; INIT_CHAIN(); ADD_TO_CHAIN(&_sharedstate->_gc_chain,this); } void SQTable::Remove(const SQObjectPtr &key) { _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { n->val = n->key = _null_; _usednodes--; Rehash(false); } } void SQTable::AllocNodes(SQInteger nSize) { _HashNode *nodes=(_HashNode *)SQ_MALLOC(sizeof(_HashNode)*nSize); for(SQInteger i=0;i= oldsize-oldsize/4) /* using more than 3/4? */ AllocNodes(oldsize*2); else if (nelems <= oldsize/4 && /* less than 1/4? */ oldsize > MINPOWER2) AllocNodes(oldsize/2); else if(force) AllocNodes(oldsize); else return; _usednodes = 0; for (SQInteger i=0; ikey) != OT_NULL) NewSlot(old->key,old->val); } for(SQInteger k=0;kNewSlot(key,val); } nt->SetDelegate(_delegate); return nt; } bool SQTable::Get(const SQObjectPtr &key,SQObjectPtr &val) { if(type(key) == OT_NULL) return false; _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { val = _realval(n->val); return true; } return false; } bool SQTable::NewSlot(const SQObjectPtr &key,const SQObjectPtr &val) { assert(type(key) != OT_NULL); SQHash h = HashObj(key) & (_numofnodes - 1); _HashNode *n = _Get(key, h); if (n) { n->val = val; return false; } _HashNode *mp = &_nodes[h]; n = mp; //key not found I'll insert it //main pos is not free if(type(mp->key) != OT_NULL) { n = _firstfree; /* get a free place */ SQHash mph = HashObj(mp->key) & (_numofnodes - 1); _HashNode *othern; /* main position of colliding node */ if (mp > n && (othern = &_nodes[mph]) != mp){ /* yes; move colliding node into free position */ while (othern->next != mp){ assert(othern->next != NULL); othern = othern->next; /* find previous */ } othern->next = n; /* redo the chain with `n' in place of `mp' */ n->key = mp->key; n->val = mp->val;/* copy colliding node into free pos. (mp->next also goes) */ n->next = mp->next; mp->key = _null_; mp->val = _null_; mp->next = NULL; /* now `mp' is free */ } else{ /* new node will go into free position */ n->next = mp->next; /* chain new position */ mp->next = n; mp = n; } } mp->key = key; for (;;) { /* correct `firstfree' */ if (type(_firstfree->key) == OT_NULL && _firstfree->next == NULL) { mp->val = val; _usednodes++; return true; /* OK; table still has a free place */ } else if (_firstfree == _nodes) break; /* cannot decrement from here */ else (_firstfree)--; } Rehash(true); return NewSlot(key, val); } SQInteger SQTable::Next(bool getweakrefs,const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQInteger idx = (SQInteger)TranslateIndex(refpos); while (idx < _numofnodes) { if(type(_nodes[idx].key) != OT_NULL) { //first found _HashNode &n = _nodes[idx]; outkey = n.key; outval = getweakrefs?(SQObject)n.val:_realval(n.val); //return idx for the next iteration return ++idx; } ++idx; } //nothing to iterate anymore return -1; } bool SQTable::Set(const SQObjectPtr &key, const SQObjectPtr &val) { _HashNode *n = _Get(key, HashObj(key) & (_numofnodes - 1)); if (n) { n->val = val; return true; } return false; } void SQTable::_ClearNodes() { for(SQInteger i = 0;i < _numofnodes; i++) { _nodes[i].key = _null_; _nodes[i].val = _null_; } } void SQTable::Finalize() { _ClearNodes(); SetDelegate(NULL); } void SQTable::Clear() { _ClearNodes(); _usednodes = 0; Rehash(true); } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqcompiler.h0000644000000000000000000000364412627373445022321 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQCOMPILER_H_ #define _SQCOMPILER_H_ struct SQVM; #define TK_IDENTIFIER 258 #define TK_STRING_LITERAL 259 #define TK_INTEGER 260 #define TK_FLOAT 261 #define TK_DELEGATE 262 #define TK_DELETE 263 #define TK_EQ 264 #define TK_NE 265 #define TK_LE 266 #define TK_GE 267 #define TK_SWITCH 268 #define TK_ARROW 269 #define TK_AND 270 #define TK_OR 271 #define TK_IF 272 #define TK_ELSE 273 #define TK_WHILE 274 #define TK_BREAK 275 #define TK_FOR 276 #define TK_DO 277 #define TK_NULL 278 #define TK_FOREACH 279 #define TK_IN 280 #define TK_NEWSLOT 281 #define TK_MODULO 282 #define TK_LOCAL 283 #define TK_CLONE 284 #define TK_FUNCTION 285 #define TK_RETURN 286 #define TK_TYPEOF 287 #define TK_UMINUS 288 #define TK_PLUSEQ 289 #define TK_MINUSEQ 290 #define TK_CONTINUE 291 #define TK_YIELD 292 #define TK_TRY 293 #define TK_CATCH 294 #define TK_THROW 295 #define TK_SHIFTL 296 #define TK_SHIFTR 297 #define TK_RESUME 298 #define TK_DOUBLE_COLON 299 #define TK_CASE 300 #define TK_DEFAULT 301 #define TK_THIS 302 #define TK_PLUSPLUS 303 #define TK_MINUSMINUS 304 #define TK_PARENT 305 #define TK_USHIFTR 306 #define TK_CLASS 307 #define TK_EXTENDS 308 #define TK_CONSTRUCTOR 310 #define TK_INSTANCEOF 311 #define TK_VARPARAMS 312 #define TK_VARGC 313 #define TK_VARGV 314 #define TK_TRUE 315 #define TK_FALSE 316 #define TK_MULEQ 317 #define TK_DIVEQ 318 #define TK_MODEQ 319 #define TK_ATTR_OPEN 320 #define TK_ATTR_CLOSE 321 #define TK_STATIC 322 #define TK_ENUM 323 #define TK_CONST 324 /* MSVC doesn't like NORETURN for function prototypes, but we kinda need it for GCC. */ #if defined(_MSC_VER) typedef void(*CompilerErrorFunc)(void *ud, const SQChar *s); #else typedef NORETURN void(*CompilerErrorFunc)(void *ud, const SQChar *s); #endif bool Compile(SQVM *vm, SQLEXREADFUNC rg, SQUserPointer up, const SQChar *sourcename, SQObjectPtr &out, bool raiseerror, bool lineinfo); #endif //_SQCOMPILER_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqfuncproto.h0000644000000000000000000001173212627373445022523 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQFUNCTION_H_ #define _SQFUNCTION_H_ #include "sqopcodes.h" enum SQOuterType { otLOCAL = 0, otSYMBOL = 1, otOUTER = 2, }; struct SQOuterVar { SQOuterVar() : _type(otLOCAL) {} SQOuterVar(const SQObjectPtr &name,const SQObjectPtr &src,SQOuterType t) { _name = name; _src=src; _type=t; } SQOuterVar(const SQOuterVar &ov) { _type=ov._type; _src=ov._src; _name=ov._name; } SQOuterType _type; SQObjectPtr _name; SQObjectPtr _src; }; struct SQLocalVarInfo { SQLocalVarInfo():_start_op(0),_end_op(0), _pos(0){} SQLocalVarInfo(const SQLocalVarInfo &lvi) { _name=lvi._name; _start_op=lvi._start_op; _end_op=lvi._end_op; _pos=lvi._pos; } SQObjectPtr _name; SQUnsignedInteger _start_op; SQUnsignedInteger _end_op; SQUnsignedInteger _pos; }; struct SQLineInfo { SQInteger _line;SQInteger _op; }; typedef sqvector SQOuterVarVec; typedef sqvector SQLocalVarInfoVec; typedef sqvector SQLineInfoVec; #define _FUNC_SIZE(ni,nl,nparams,nfuncs,nouters,nlineinf,localinf,defparams) (sizeof(SQFunctionProto) \ +((ni-1)*sizeof(SQInstruction))+(nl*sizeof(SQObjectPtr)) \ +(nparams*sizeof(SQObjectPtr))+(nfuncs*sizeof(SQObjectPtr)) \ +(nouters*sizeof(SQOuterVar))+(nlineinf*sizeof(SQLineInfo)) \ +(localinf*sizeof(SQLocalVarInfo))+(defparams*sizeof(SQInteger))) #define _CONSTRUCT_VECTOR(type,size,ptr) { \ for(SQInteger n = 0; n < size; n++) { \ new (&ptr[n]) type(); \ } \ } #define _DESTRUCT_VECTOR(type,size,ptr) { \ for(SQInteger nl = 0; nl < size; nl++) { \ ptr[nl].~type(); \ } \ } struct SQFunctionProto : public SQRefCounted { private: SQFunctionProto(SQInteger ninstructions, SQInteger nliterals,SQInteger nparameters, SQInteger nfunctions,SQInteger noutervalues, SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams) { _stacksize=0; _bgenerator=false; _varparams = false; _ninstructions = ninstructions; _literals = (SQObjectPtr*)&_instructions[ninstructions]; _nliterals = nliterals; _parameters = (SQObjectPtr*)&_literals[nliterals]; _nparameters = nparameters; _functions = (SQObjectPtr*)&_parameters[nparameters]; _nfunctions = nfunctions; _outervalues = (SQOuterVar*)&_functions[nfunctions]; _noutervalues = noutervalues; _lineinfos = (SQLineInfo *)&_outervalues[noutervalues]; _nlineinfos = nlineinfos; _localvarinfos = (SQLocalVarInfo *)&_lineinfos[nlineinfos]; _nlocalvarinfos = nlocalvarinfos; _defaultparams = (SQInteger *)&_localvarinfos[nlocalvarinfos]; _ndefaultparams = ndefaultparams; _CONSTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals); _CONSTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters); _CONSTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions); _CONSTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues); //_CONSTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers _CONSTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos); } public: static SQFunctionProto *Create(SQInteger ninstructions, SQInteger nliterals,SQInteger nparameters, SQInteger nfunctions,SQInteger noutervalues, SQInteger nlineinfos,SQInteger nlocalvarinfos,SQInteger ndefaultparams) { SQFunctionProto *f; //I compact the whole class and members in a single memory allocation f = (SQFunctionProto *)sq_vm_malloc(_FUNC_SIZE(ninstructions,nliterals,nparameters,nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams)); new (f) SQFunctionProto(ninstructions, nliterals, nparameters, nfunctions, noutervalues, nlineinfos, nlocalvarinfos, ndefaultparams); return f; } void Release(){ _DESTRUCT_VECTOR(SQObjectPtr,_nliterals,_literals); _DESTRUCT_VECTOR(SQObjectPtr,_nparameters,_parameters); _DESTRUCT_VECTOR(SQObjectPtr,_nfunctions,_functions); _DESTRUCT_VECTOR(SQOuterVar,_noutervalues,_outervalues); //_DESTRUCT_VECTOR(SQLineInfo,_nlineinfos,_lineinfos); //not required are 2 integers _DESTRUCT_VECTOR(SQLocalVarInfo,_nlocalvarinfos,_localvarinfos); SQInteger size = _FUNC_SIZE(_ninstructions,_nliterals,_nparameters,_nfunctions,_noutervalues,_nlineinfos,_nlocalvarinfos,_ndefaultparams); this->~SQFunctionProto(); sq_vm_free(this,size); } const SQChar* GetLocal(SQVM *v,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop); SQInteger GetLine(SQInstruction *curr); bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); SQObjectPtr _sourcename; SQObjectPtr _name; SQInteger _stacksize; bool _bgenerator; bool _varparams; SQInteger _nlocalvarinfos; SQLocalVarInfo *_localvarinfos; SQInteger _nlineinfos; SQLineInfo *_lineinfos; SQInteger _nliterals; SQObjectPtr *_literals; SQInteger _nparameters; SQObjectPtr *_parameters; SQInteger _nfunctions; SQObjectPtr *_functions; SQInteger _noutervalues; SQOuterVar *_outervalues; SQInteger _ndefaultparams; SQInteger *_defaultparams; SQInteger _ninstructions; SQInstruction _instructions[1]; }; #endif //_SQFUNCTION_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqfuncstate.cpp0000644000000000000000000003340612627373445023035 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include "sqpcheader.h" #include "sqcompiler.h" #include "sqfuncproto.h" #include "sqstring.h" #include "sqtable.h" #include "sqopcodes.h" #include "sqfuncstate.h" #include "../../../safeguards.h" #ifdef _DEBUG_DUMP SQInstructionDesc g_InstrDesc[]={ {"_OP_LINE"}, {"_OP_LOAD"}, {"_OP_LOADINT"}, {"_OP_LOADFLOAT"}, {"_OP_DLOAD"}, {"_OP_TAILCALL"}, {"_OP_CALL"}, {"_OP_PREPCALL"}, {"_OP_PREPCALLK"}, {"_OP_GETK"}, {"_OP_MOVE"}, {"_OP_NEWSLOT"}, {"_OP_DELETE"}, {"_OP_SET"}, {"_OP_GET"}, {"_OP_EQ"}, {"_OP_NE"}, {"_OP_ARITH"}, {"_OP_BITW"}, {"_OP_RETURN"}, {"_OP_LOADNULLS"}, {"_OP_LOADROOTTABLE"}, {"_OP_LOADBOOL"}, {"_OP_DMOVE"}, {"_OP_JMP"}, {"_OP_JNZ"}, {"_OP_JZ"}, {"_OP_LOADFREEVAR"}, {"_OP_VARGC"}, {"_OP_GETVARGV"}, {"_OP_NEWTABLE"}, {"_OP_NEWARRAY"}, {"_OP_APPENDARRAY"}, {"_OP_GETPARENT"}, {"_OP_COMPARITH"}, {"_OP_COMPARITHL"}, {"_OP_INC"}, {"_OP_INCL"}, {"_OP_PINC"}, {"_OP_PINCL"}, {"_OP_CMP"}, {"_OP_EXISTS"}, {"_OP_INSTANCEOF"}, {"_OP_AND"}, {"_OP_OR"}, {"_OP_NEG"}, {"_OP_NOT"}, {"_OP_BWNOT"}, {"_OP_CLOSURE"}, {"_OP_YIELD"}, {"_OP_RESUME"}, {"_OP_FOREACH"}, {"_OP_POSTFOREACH"}, {"_OP_DELEGATE"}, {"_OP_CLONE"}, {"_OP_TYPEOF"}, {"_OP_PUSHTRAP"}, {"_OP_POPTRAP"}, {"_OP_THROW"}, {"_OP_CLASS"}, {"_OP_NEWSLOTA"}, {"_OP_SCOPE_END"} }; #endif void DumpLiteral(SQObjectPtr &o) { switch(type(o)){ case OT_STRING: printf("\"%s\"",_stringval(o));break; case OT_FLOAT: printf("{%f}",_float(o));break; case OT_INTEGER: printf("{" OTTD_PRINTF64 "}",_integer(o));break; case OT_BOOL: printf("%s",_integer(o)?"true":"false");break; default: printf("(%s %p)",GetTypeName(o),(void*)_rawval(o));break; break; //shut up compiler } } SQFuncState::SQFuncState(SQSharedState *ss,SQFuncState *parent,CompilerErrorFunc efunc,void *ed) { _nliterals = 0; _literals = SQTable::Create(ss,0); _strings = SQTable::Create(ss,0); _sharedstate = ss; _lastline = 0; _optimization = true; _parent = parent; _stacksize = 0; _traps = 0; _returnexp = 0; _varparams = false; _errfunc = efunc; _errtarget = ed; _bgenerator = false; } void SQFuncState::Error(const SQChar *err) { _errfunc(_errtarget,err); } #ifdef _DEBUG_DUMP void SQFuncState::Dump(SQFunctionProto *func) { SQUnsignedInteger n=0,i; SQInteger si; printf("SQInstruction sizeof %d\n",sizeof(SQInstruction)); printf("SQObject sizeof %d\n",sizeof(SQObject)); printf("--------------------------------------------------------------------\n"); printf("*****FUNCTION [%s]\n",type(func->_name)==OT_STRING?_stringval(func->_name):"unknown"); printf("-----LITERALS\n"); SQObjectPtr refidx,key,val; SQInteger idx; SQObjectPtrVec templiterals; templiterals.resize(_nliterals); while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { refidx=idx; templiterals[_integer(val)]=key; } for(i=0;i>\n"); n=0; for(i=0;i<_parameters.size();i++){ printf("[%d] ",n); DumpLiteral(_parameters[i]); printf("\n"); n++; } printf("-----LOCALS\n"); for(si=0;si_nlocalvarinfos;si++){ SQLocalVarInfo lvi=func->_localvarinfos[si]; printf("[%d] %s \t%d %d\n",lvi._pos,_stringval(lvi._name),lvi._start_op,lvi._end_op); n++; } printf("-----LINE INFO\n"); for(i=0;i<_lineinfos.size();i++){ SQLineInfo li=_lineinfos[i]; printf("op [%d] line [%d] \n",li._op,li._line); n++; } printf("-----dump\n"); n=0; for(i=0;i<_instructions.size();i++){ SQInstruction &inst=_instructions[i]; if(inst.op==_OP_LOAD || inst.op==_OP_DLOAD || inst.op==_OP_PREPCALLK || inst.op==_OP_GETK ){ SQInteger lidx = inst._arg1; printf("[%03d] %15s %d ",n,g_InstrDesc[inst.op].name,inst._arg0); if(lidx >= 0xFFFFFFFF) printf("null"); else { SQInteger refidx; SQObjectPtr val,key,refo; while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { refo = refidx; } DumpLiteral(key); } if(inst.op != _OP_DLOAD) { printf(" %d %d \n",inst._arg2,inst._arg3); } else { printf(" %d ",inst._arg2); lidx = inst._arg3; if(lidx >= 0xFFFFFFFF) printf("null"); else { SQInteger refidx; SQObjectPtr val,key,refo; while(((refidx=_table(_literals)->Next(false,refo,key,val))!= -1) && (_integer(val) != lidx)) { refo = refidx; } DumpLiteral(key); printf("\n"); } } } else if(inst.op==_OP_LOADFLOAT) { printf("[%03d] %15s %d %f %d %d\n",n,g_InstrDesc[inst.op].name,inst._arg0,*((SQFloat*)&inst._arg1),inst._arg2,inst._arg3); } else if(inst.op==_OP_ARITH){ printf("[%03d] %15s %d %d %d %c\n",n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); } else printf("[%03d] %15s %d %d %d %d\n",n,g_InstrDesc[inst.op].name,inst._arg0,inst._arg1,inst._arg2,inst._arg3); n++; } printf("-----\n"); printf("stack size[%d]\n",func->_stacksize); printf("--------------------------------------------------------------------\n\n"); } #endif SQInteger SQFuncState::GetNumericConstant(const SQInteger cons) { return GetConstant(SQObjectPtr(cons)); } SQInteger SQFuncState::GetNumericConstant(const SQFloat cons) { return GetConstant(SQObjectPtr(cons)); } SQInteger SQFuncState::GetConstant(const SQObject &cons) { SQObjectPtr val; if(!_table(_literals)->Get(cons,val)) { val = _nliterals; _table(_literals)->NewSlot(cons,val); _nliterals++; if(_nliterals > MAX_LITERALS) { val.Null(); Error("internal compiler error: too many literals"); } } return _integer(val); } void SQFuncState::SetIntructionParams(SQInteger pos,SQInteger arg0,SQInteger arg1,SQInteger arg2,SQInteger arg3) { _instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&arg0); _instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&arg1); _instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&arg2); _instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&arg3); } void SQFuncState::SetIntructionParam(SQInteger pos,SQInteger arg,SQInteger val) { switch(arg){ case 0:_instructions[pos]._arg0=(unsigned char)*((SQUnsignedInteger *)&val);break; case 1:case 4:_instructions[pos]._arg1=(SQInt32)*((SQUnsignedInteger *)&val);break; case 2:_instructions[pos]._arg2=(unsigned char)*((SQUnsignedInteger *)&val);break; case 3:_instructions[pos]._arg3=(unsigned char)*((SQUnsignedInteger *)&val);break; }; } SQInteger SQFuncState::AllocStackPos() { SQInteger npos=_vlocals.size(); _vlocals.push_back(SQLocalVarInfo()); if(_vlocals.size()>((SQUnsignedInteger)_stacksize)) { if(_stacksize>MAX_FUNC_STACKSIZE) Error("internal compiler error: too many locals"); _stacksize=_vlocals.size(); } return npos; } SQInteger SQFuncState::PushTarget(SQInteger n) { if(n!=-1){ _targetstack.push_back(n); return n; } n=AllocStackPos(); _targetstack.push_back(n); return n; } SQInteger SQFuncState::GetUpTarget(SQInteger n){ return _targetstack[((_targetstack.size()-1)-n)]; } SQInteger SQFuncState::TopTarget(){ return _targetstack.back(); } SQInteger SQFuncState::PopTarget() { SQInteger npos=_targetstack.back(); SQLocalVarInfo t=_vlocals[_targetstack.back()]; if(type(t._name)==OT_NULL){ _vlocals.pop_back(); } _targetstack.pop_back(); return npos; } SQInteger SQFuncState::GetStackSize() { return _vlocals.size(); } void SQFuncState::SetStackSize(SQInteger n) { SQInteger size=_vlocals.size(); while(size>n){ size--; SQLocalVarInfo lvi=_vlocals.back(); if(type(lvi._name)!=OT_NULL){ lvi._end_op=GetCurrentPos(); _localvarinfos.push_back(lvi); } _vlocals.pop_back(); } } bool SQFuncState::IsConstant(const SQObject &name,SQObject &e) { SQObjectPtr val; if(_table(_sharedstate->_consts)->Get(name,val)) { e = val; return true; } return false; } bool SQFuncState::IsLocal(SQUnsignedInteger stkpos) { if(stkpos>=_vlocals.size())return false; else if(type(_vlocals[stkpos]._name)!=OT_NULL)return true; return false; } SQInteger SQFuncState::PushLocalVariable(const SQObject &name) { SQInteger pos=_vlocals.size(); SQLocalVarInfo lvi; lvi._name=name; lvi._start_op=GetCurrentPos()+1; lvi._pos=_vlocals.size(); _vlocals.push_back(lvi); if(_vlocals.size()>((SQUnsignedInteger)_stacksize))_stacksize=_vlocals.size(); return pos; } SQInteger SQFuncState::GetLocalVariable(const SQObject &name) { SQInteger locals=_vlocals.size(); while(locals>=1){ if(type(_vlocals[locals-1]._name)==OT_STRING && _string(_vlocals[locals-1]._name)==_string(name)){ return locals-1; } locals--; } return -1; } SQInteger SQFuncState::GetOuterVariable(const SQObject &name) { SQInteger outers = _outervalues.size(); for(SQInteger i = 0; iGetLocalVariable(name); if(pos == -1) { pos = _parent->GetOuterVariable(name); if(pos != -1) { _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otOUTER)); //local return; } } else { _outervalues.push_back(SQOuterVar(name,SQObjectPtr(SQInteger(pos)),otLOCAL)); //local return; } } _outervalues.push_back(SQOuterVar(name,name,otSYMBOL)); //global } void SQFuncState::AddParameter(const SQObject &name) { PushLocalVariable(name); _parameters.push_back(name); } void SQFuncState::AddLineInfos(SQInteger line,bool lineop,bool force) { if(_lastline!=line || force){ SQLineInfo li; li._line=line;li._op=(GetCurrentPos()+1); if(lineop)AddInstruction(_OP_LINE,0,line); _lineinfos.push_back(li); _lastline=line; } } void SQFuncState::AddInstruction(SQInstruction &i) { SQInteger size = _instructions.size(); if(size > 0 && _optimization){ //simple optimizer SQInstruction &pi = _instructions[size-1];//previous instruction switch(i.op) { case _OP_RETURN: if( _parent && i._arg0 != MAX_FUNC_STACKSIZE && pi.op == _OP_CALL && _returnexp < size-1) { pi.op = _OP_TAILCALL; } break; case _OP_GET: if( pi.op == _OP_LOAD && pi._arg0 == i._arg2 && (!IsLocal(pi._arg0))){ pi._arg2 = (unsigned char)i._arg1; pi.op = _OP_GETK; pi._arg0 = i._arg0; return; } break; case _OP_PREPCALL: if( pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ pi.op = _OP_PREPCALLK; pi._arg0 = i._arg0; pi._arg2 = i._arg2; pi._arg3 = i._arg3; return; } break; case _OP_APPENDARRAY: if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0))){ pi.op = _OP_APPENDARRAY; pi._arg0 = i._arg0; pi._arg2 = MAX_FUNC_STACKSIZE; pi._arg3 = MAX_FUNC_STACKSIZE; return; } break; case _OP_MOVE: if((pi.op == _OP_GET || pi.op == _OP_ARITH || pi.op == _OP_BITW) && (pi._arg0 == i._arg1)) { pi._arg0 = i._arg0; _optimization = false; return; } if(pi.op == _OP_MOVE) { pi.op = _OP_DMOVE; pi._arg2 = i._arg0; pi._arg3 = (unsigned char)i._arg1; return; } break; case _OP_LOAD: if(pi.op == _OP_LOAD && i._arg1 < 256) { pi.op = _OP_DLOAD; pi._arg2 = i._arg0; pi._arg3 = (unsigned char)i._arg1; return; } break; case _OP_EQ:case _OP_NE: if(pi.op == _OP_LOAD && pi._arg0 == i._arg1 && (!IsLocal(pi._arg0) )) { pi.op = i.op; pi._arg0 = i._arg0; pi._arg2 = i._arg2; pi._arg3 = MAX_FUNC_STACKSIZE; return; } break; case _OP_LOADNULLS: if((pi.op == _OP_LOADNULLS && pi._arg0+pi._arg1 == i._arg0)) { pi._arg1 = pi._arg1 + 1; pi.op = _OP_LOADNULLS; return; } break; case _OP_LINE: if(pi.op == _OP_LINE) { _instructions.pop_back(); _lineinfos.pop_back(); } break; } } _optimization = true; _instructions.push_back(i); } SQObject SQFuncState::CreateString(const SQChar *s,SQInteger len) { SQObjectPtr ns(SQString::Create(_sharedstate,s,len)); _table(_strings)->NewSlot(ns,(SQInteger)1); return ns; } SQObject SQFuncState::CreateTable() { SQObjectPtr nt(SQTable::Create(_sharedstate,0)); _table(_strings)->NewSlot(nt,(SQInteger)1); return nt; } SQFunctionProto *SQFuncState::BuildProto() { SQFunctionProto *f=SQFunctionProto::Create(_instructions.size(), _nliterals,_parameters.size(),_functions.size(),_outervalues.size(), _lineinfos.size(),_localvarinfos.size(),_defaultparams.size()); SQObjectPtr refidx,key,val; SQInteger idx; f->_stacksize = _stacksize; f->_sourcename = _sourcename; f->_bgenerator = _bgenerator; f->_name = _name; while((idx=_table(_literals)->Next(false,refidx,key,val))!=-1) { f->_literals[_integer(val)]=key; refidx=idx; } for(SQUnsignedInteger nf = 0; nf < _functions.size(); nf++) f->_functions[nf] = _functions[nf]; for(SQUnsignedInteger np = 0; np < _parameters.size(); np++) f->_parameters[np] = _parameters[np]; for(SQUnsignedInteger no = 0; no < _outervalues.size(); no++) f->_outervalues[no] = _outervalues[no]; for(SQUnsignedInteger no = 0; no < _localvarinfos.size(); no++) f->_localvarinfos[no] = _localvarinfos[no]; for(SQUnsignedInteger no = 0; no < _lineinfos.size(); no++) f->_lineinfos[no] = _lineinfos[no]; for(SQUnsignedInteger no = 0; no < _defaultparams.size(); no++) f->_defaultparams[no] = _defaultparams[no]; memcpy(f->_instructions,&_instructions[0],(size_t)_instructions.size()*sizeof(SQInstruction)); f->_varparams = _varparams; return f; } SQFuncState *SQFuncState::PushChildState(SQSharedState *ss) { SQFuncState *child = (SQFuncState *)sq_malloc(sizeof(SQFuncState)); new (child) SQFuncState(ss,this,_errfunc,_errtarget); _childstates.push_back(child); return child; } void SQFuncState::PopChildState() { SQFuncState *child = _childstates.back(); sq_delete(child,SQFuncState); _childstates.pop_back(); } SQFuncState::~SQFuncState() { while(_childstates.size() > 0) { PopChildState(); } } openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqstate.h0000644000000000000000000000775312627373445021634 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQSTATE_H_ #define _SQSTATE_H_ #include "squtils.h" #include "sqobject.h" struct SQString; struct SQTable; //max number of character for a printed number #define NUMBER_MAX_CHAR 50 struct SQStringTable { SQStringTable(); ~SQStringTable(); SQString *Add(const SQChar *,SQInteger len); void Remove(SQString *); private: void Resize(SQInteger size); void AllocNodes(SQInteger size); SQString **_strings; SQUnsignedInteger _numofslots; SQUnsignedInteger _slotused; }; struct RefTable { struct RefNode { SQObjectPtr obj; SQUnsignedInteger refs; struct RefNode *next; }; RefTable(); ~RefTable(); void AddRef(SQObject &obj); SQBool Release(SQObject &obj); #ifndef NO_GARBAGE_COLLECTOR void Mark(SQCollectable **chain); #endif void Finalize(); private: RefNode *Get(SQObject &obj,SQHash &mainpos,RefNode **prev,bool add); RefNode *Add(SQHash mainpos,SQObject &obj); void Resize(SQUnsignedInteger size); void AllocNodes(SQUnsignedInteger size); SQUnsignedInteger _numofslots; SQUnsignedInteger _slotused; RefNode *_nodes; RefNode *_freelist; RefNode **_buckets; }; #define ADD_STRING(ss,str,len) ss->_stringtable->Add(str,len) #define REMOVE_STRING(ss,bstr) ss->_stringtable->Remove(bstr) struct SQObjectPtr; struct SQSharedState { SQSharedState(); ~SQSharedState(); public: SQChar* GetScratchPad(SQInteger size); SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); #ifndef NO_GARBAGE_COLLECTOR SQInteger CollectGarbage(SQVM *vm); static void MarkObject(SQObjectPtr &o,SQCollectable **chain); #endif SQObjectPtrVec *_metamethods; SQObjectPtr _metamethodsmap; SQObjectPtrVec *_systemstrings; SQObjectPtrVec *_types; SQStringTable *_stringtable; RefTable _refs_table; SQObjectPtr _registry; SQObjectPtr _consts; SQObjectPtr _constructoridx; #ifndef NO_GARBAGE_COLLECTOR SQCollectable *_gc_chain; #endif SQObjectPtr _root_vm; SQObjectPtr _table_default_delegate; static SQRegFunction _table_default_delegate_funcz[]; SQObjectPtr _array_default_delegate; static SQRegFunction _array_default_delegate_funcz[]; SQObjectPtr _string_default_delegate; static SQRegFunction _string_default_delegate_funcz[]; SQObjectPtr _number_default_delegate; static SQRegFunction _number_default_delegate_funcz[]; SQObjectPtr _generator_default_delegate; static SQRegFunction _generator_default_delegate_funcz[]; SQObjectPtr _closure_default_delegate; static SQRegFunction _closure_default_delegate_funcz[]; SQObjectPtr _thread_default_delegate; static SQRegFunction _thread_default_delegate_funcz[]; SQObjectPtr _class_default_delegate; static SQRegFunction _class_default_delegate_funcz[]; SQObjectPtr _instance_default_delegate; static SQRegFunction _instance_default_delegate_funcz[]; SQObjectPtr _weakref_default_delegate; static SQRegFunction _weakref_default_delegate_funcz[]; SQCOMPILERERROR _compilererrorhandler; SQPRINTFUNCTION _printfunc; bool _debuginfo; bool _notifyallexceptions; private: SQChar *_scratchpad; SQInteger _scratchpadsize; }; #define _sp(s) (_sharedstate->GetScratchPad(s)) #define _spval (_sharedstate->GetScratchPad(-1)) #define _table_ddel _table(_sharedstate->_table_default_delegate) #define _array_ddel _table(_sharedstate->_array_default_delegate) #define _string_ddel _table(_sharedstate->_string_default_delegate) #define _number_ddel _table(_sharedstate->_number_default_delegate) #define _generator_ddel _table(_sharedstate->_generator_default_delegate) #define _closure_ddel _table(_sharedstate->_closure_default_delegate) #define _thread_ddel _table(_sharedstate->_thread_default_delegate) #define _class_ddel _table(_sharedstate->_class_default_delegate) #define _instance_ddel _table(_sharedstate->_instance_default_delegate) #define _weakref_ddel _table(_sharedstate->_weakref_default_delegate) extern SQObjectPtr _null_; extern SQObjectPtr _true_; extern SQObjectPtr _false_; extern SQObjectPtr _one_; extern SQObjectPtr _minusone_; bool CompileTypemask(SQIntVec &res,const SQChar *typemask); #endif //_SQSTATE_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/squtils.h0000644000000000000000000000567112627373445021651 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQUTILS_H_ #define _SQUTILS_H_ void *sq_vm_malloc(SQUnsignedInteger size); void *sq_vm_realloc(void *p,SQUnsignedInteger oldsize,SQUnsignedInteger size); void sq_vm_free(void *p,SQUnsignedInteger size); #define sq_new(__ptr,__type) {__ptr=(__type *)sq_vm_malloc(sizeof(__type));new (__ptr) __type;} #define sq_delete(__ptr,__type) {__ptr->~__type();sq_vm_free(__ptr,sizeof(__type));} #define SQ_MALLOC(__size) sq_vm_malloc((__size)); #define SQ_FREE(__ptr,__size) sq_vm_free((__ptr),(__size)); #define SQ_REALLOC(__ptr,__oldsize,__size) sq_vm_realloc((__ptr),(__oldsize),(__size)); //sqvector mini vector class, supports objects by value template class sqvector { public: sqvector() { _vals = NULL; _size = 0; _allocated = 0; } sqvector(const sqvector& v) { copy(v); } void copy(const sqvector& v) { resize(v._size); for(SQUnsignedInteger i = 0; i < v._size; i++) { new ((void *)&_vals[i]) T(v._vals[i]); } _size = v._size; } ~sqvector() { if(_allocated) { /* Break freeing loops, if this vector (indirectly) links to itself. */ size_t allocated_size = _allocated * sizeof(T); _allocated = 0; for(size_t i = 0; i < _size; i++) _vals[i].~T(); SQ_FREE(_vals, allocated_size); } } void reserve(SQUnsignedInteger newsize) { _realloc(newsize); } void resize(SQUnsignedInteger newsize, const T& fill = T()) { if(newsize > _allocated) _realloc(newsize); if(newsize > _size) { while(_size < newsize) { new ((void *)&_vals[_size]) T(fill); _size++; } } else{ for(SQUnsignedInteger i = newsize; i < _size; i++) { _vals[i].~T(); } _size = (size_t)newsize; } } void shrinktofit() { if(_size > 4) { _realloc(_size); } } T& top() const { return _vals[_size - 1]; } inline SQUnsignedInteger size() const { return _size; } bool empty() const { return (_size <= 0); } inline T &push_back(const T& val = T()) { if(_allocated <= _size) _realloc(_size * 2); return *(new ((void *)&_vals[_size++]) T(val)); } inline void pop_back() { _size--; _vals[_size].~T(); } void insert(SQUnsignedInteger idx, const T& val) { resize(_size + 1); for(SQUnsignedInteger i = _size - 1; i > idx; i--) { _vals[i] = _vals[i - 1]; } _vals[idx] = val; } void remove(SQUnsignedInteger idx) { _vals[idx].~T(); if(idx < (_size - 1)) { memmove(&_vals[idx], &_vals[idx+1], sizeof(T) * (_size - (size_t)idx - 1)); } _size--; } SQUnsignedInteger capacity() { return _allocated; } inline T &back() const { return _vals[_size - 1]; } inline T& operator[](SQUnsignedInteger pos) const{ assert(pos < _allocated); return _vals[pos]; } T* _vals; private: void _realloc(SQUnsignedInteger newsize) { newsize = (newsize > 0)?newsize:4; _vals = (T*)SQ_REALLOC(_vals, _allocated * sizeof(T), newsize * sizeof(T)); _allocated = (size_t)newsize; } size_t _size; size_t _allocated; }; #endif //_SQUTILS_H_ openttd-1.5.3/src/3rdparty/squirrel/squirrel/sqobject.cpp0000644000000000000000000004313312627373445022305 0ustar rootroot/* * see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include "sqpcheader.h" #include "sqvm.h" #include "sqstring.h" #include "sqarray.h" #include "sqtable.h" #include "squserdata.h" #include "sqfuncproto.h" #include "sqclass.h" #include "sqclosure.h" #include "../../../safeguards.h" const SQChar *IdType2Name(SQObjectType type) { switch(_RAW_TYPE(type)) { case _RT_NULL:return "null"; case _RT_INTEGER:return "integer"; case _RT_FLOAT:return "float"; case _RT_BOOL:return "bool"; case _RT_STRING:return "string"; case _RT_TABLE:return "table"; case _RT_ARRAY:return "array"; case _RT_GENERATOR:return "generator"; case _RT_CLOSURE: case _RT_NATIVECLOSURE: return "function"; case _RT_USERDATA: case _RT_USERPOINTER: return "userdata"; case _RT_THREAD: return "thread"; case _RT_FUNCPROTO: return "function"; case _RT_CLASS: return "class"; case _RT_INSTANCE: return "instance"; case _RT_WEAKREF: return "weakref"; default: return NULL; } } const SQChar *GetTypeName(const SQObjectPtr &obj1) { return IdType2Name(type(obj1)); } SQString *SQString::Create(SQSharedState *ss,const SQChar *s,SQInteger len) { SQString *str=ADD_STRING(ss,s,len); str->_sharedstate=ss; return str; } void SQString::Release() { REMOVE_STRING(_sharedstate,this); } SQInteger SQString::Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval) { SQInteger idx = (SQInteger)TranslateIndex(refpos); while(idx < _len){ outkey = (SQInteger)idx; outval = SQInteger(_val[idx]); //return idx for the next iteration return ++idx; } //nothing to iterate anymore return -1; } SQUnsignedInteger TranslateIndex(const SQObjectPtr &idx) { switch(type(idx)){ case OT_NULL: return 0; case OT_INTEGER: return (SQUnsignedInteger)_integer(idx); default: assert(0); break; } return 0; } SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type) { if(!_weakref) { sq_new(_weakref,SQWeakRef); _weakref->_obj._type = type; _weakref->_obj._unVal.pRefCounted = this; } return _weakref; } SQRefCounted::~SQRefCounted() { if(_weakref) { _weakref->_obj._type = OT_NULL; _weakref->_obj._unVal.pRefCounted = NULL; } } void SQWeakRef::Release() { if(ISREFCOUNTED(_obj._type)) { _obj._unVal.pRefCounted->_weakref = NULL; } sq_delete(this,SQWeakRef); } bool SQDelegable::GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) { if(_delegate) { return _delegate->Get((*_ss(v)->_metamethods)[mm],res); } return false; } bool SQDelegable::SetDelegate(SQTable *mt) { SQTable *temp = mt; if(temp == this) return false; while (temp) { if (temp->_delegate == this) return false; //cycle detected temp = temp->_delegate; } if (mt) __ObjAddRef(mt); __ObjRelease(_delegate); _delegate = mt; return true; } bool SQGenerator::Yield(SQVM *v) { if(_state==eSuspended) { v->Raise_Error("internal vm error, yielding dead generator"); return false;} if(_state==eDead) { v->Raise_Error("internal vm error, yielding a dead generator"); return false; } SQInteger size = v->_top-v->_stackbase; _ci=*v->ci; _stack.resize(size); for(SQInteger n =0; n_stack[v->_stackbase+n]; v->_stack[v->_stackbase+n] = _null_; } SQInteger nvargs = v->ci->_vargs.size; SQInteger vargsbase = v->ci->_vargs.base; for(SQInteger j = nvargs - 1; j >= 0; j--) { _vargsstack.push_back(v->_vargsstack[vargsbase+j]); } _ci._generator=NULL; for(SQInteger i=0;i<_ci._etraps;i++) { _etraps.push_back(v->_etraps.top()); v->_etraps.pop_back(); } _state=eSuspended; return true; } bool SQGenerator::Resume(SQVM *v,SQInteger target) { SQInteger size=_stack.size(); if(_state==eDead){ v->Raise_Error("resuming dead generator"); return false; } if(_state==eRunning){ v->Raise_Error("resuming active generator"); return false; } SQInteger prevtop=v->_top-v->_stackbase; PUSH_CALLINFO(v,_ci); SQInteger oldstackbase=v->_stackbase; v->_stackbase = v->_top; v->ci->_target = (SQInt32)target; v->ci->_generator = this; v->ci->_vargs.size = (unsigned short)_vargsstack.size(); for(SQInteger i=0;i<_ci._etraps;i++) { v->_etraps.push_back(_etraps.top()); _etraps.pop_back(); } for(SQInteger n =0; n_stack[v->_stackbase+n] = _stack._vals[n]; _stack._vals[0] = _null_; } while(_vargsstack.size()) { v->_vargsstack.push_back(_vargsstack.back()); _vargsstack.pop_back(); } v->ci->_vargs.base = (unsigned short)(v->_vargsstack.size() - v->ci->_vargs.size); v->_top=v->_stackbase+size; v->ci->_prevtop = (SQInt32)prevtop; v->ci->_prevstkbase = (SQInt32)(v->_stackbase - oldstackbase); _state=eRunning; if (type(v->_debughook) != OT_NULL && _rawval(v->_debughook) != _rawval(v->ci->_closure)) v->CallDebugHook('c'); return true; } void SQArray::Extend(const SQArray *a){ SQInteger xlen; if((xlen=a->Size())) for(SQInteger i=0;i_values[i]); } const SQChar* SQFunctionProto::GetLocal(SQVM *vm,SQUnsignedInteger stackbase,SQUnsignedInteger nseq,SQUnsignedInteger nop) { SQUnsignedInteger nvars=_nlocalvarinfos; const SQChar *res=NULL; if(nvars>=nseq){ for(SQUnsignedInteger i=0;i=nop) { if(nseq==0){ vm->Push(vm->_stack[stackbase+_localvarinfos[i]._pos]); res=_stringval(_localvarinfos[i]._name); break; } nseq--; } } } return res; } SQInteger SQFunctionProto::GetLine(SQInstruction *curr) { SQInteger op = (SQInteger)(curr-_instructions); SQInteger line=_lineinfos[0]._line; for(SQInteger i=1;i<_nlineinfos;i++){ if(_lineinfos[i]._op>=op) return line; line=_lineinfos[i]._line; } return line; } #define _CHECK_IO(exp) { if(!exp)return false; } bool SafeWrite(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQUserPointer dest,SQInteger size) { if(write(up,dest,size) != size) { v->Raise_Error("io error (write function failure)"); return false; } return true; } bool SafeRead(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQUserPointer dest,SQInteger size) { if(size && read(up,dest,size) != size) { v->Raise_Error("io error, read function failure, the origin stream could be corrupted/trucated"); return false; } return true; } bool WriteTag(HSQUIRRELVM v,SQWRITEFUNC write,SQUserPointer up,SQInteger tag) { return SafeWrite(v,write,up,&tag,sizeof(tag)); } bool CheckTag(HSQUIRRELVM v,SQWRITEFUNC read,SQUserPointer up,SQInteger tag) { SQInteger t; _CHECK_IO(SafeRead(v,read,up,&t,sizeof(t))); if(t != tag){ v->Raise_Error("invalid or corrupted closure stream"); return false; } return true; } bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o) { _CHECK_IO(SafeWrite(v,write,up,&type(o),sizeof(SQObjectType))); switch(type(o)){ case OT_STRING: _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); _CHECK_IO(SafeWrite(v,write,up,_stringval(o),_string(o)->_len)); break; case OT_INTEGER: _CHECK_IO(SafeWrite(v,write,up,&_integer(o),sizeof(SQInteger)));break; case OT_FLOAT: _CHECK_IO(SafeWrite(v,write,up,&_float(o),sizeof(SQFloat)));break; case OT_NULL: break; default: v->Raise_Error("cannot serialize a %s",GetTypeName(o)); return false; } return true; } bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o) { SQObjectType t; _CHECK_IO(SafeRead(v,read,up,&t,sizeof(SQObjectType))); switch(t){ case OT_STRING:{ SQInteger len; _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(len),len)); o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); } break; case OT_INTEGER:{ SQInteger i; _CHECK_IO(SafeRead(v,read,up,&i,sizeof(SQInteger))); o = i; break; } case OT_FLOAT:{ SQFloat f; _CHECK_IO(SafeRead(v,read,up,&f,sizeof(SQFloat))); o = f; break; } case OT_NULL: o=_null_; break; default: v->Raise_Error("cannot serialize a %s",IdType2Name(t)); return false; } return true; } bool SQClosure::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) { _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_HEAD)); _CHECK_IO(WriteTag(v,write,up,sizeof(SQChar))); _CHECK_IO(_funcproto(_function)->Save(v,up,write)); _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_TAIL)); return true; } bool SQClosure::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) { _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_HEAD)); _CHECK_IO(CheckTag(v,read,up,sizeof(SQChar))); SQObjectPtr func; _CHECK_IO(SQFunctionProto::Load(v,up,read,func)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_TAIL)); ret = SQClosure::Create(_ss(v),_funcproto(func)); return true; } bool SQFunctionProto::Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write) { SQInteger i,nliterals = _nliterals,nparameters = _nparameters; SQInteger noutervalues = _noutervalues,nlocalvarinfos = _nlocalvarinfos; SQInteger nlineinfos=_nlineinfos,ninstructions = _ninstructions,nfunctions=_nfunctions; SQInteger ndefaultparams = _ndefaultparams; _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(WriteObject(v,up,write,_sourcename)); _CHECK_IO(WriteObject(v,up,write,_name)); _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeWrite(v,write,up,&nliterals,sizeof(nliterals))); _CHECK_IO(SafeWrite(v,write,up,&nparameters,sizeof(nparameters))); _CHECK_IO(SafeWrite(v,write,up,&noutervalues,sizeof(noutervalues))); _CHECK_IO(SafeWrite(v,write,up,&nlocalvarinfos,sizeof(nlocalvarinfos))); _CHECK_IO(SafeWrite(v,write,up,&nlineinfos,sizeof(nlineinfos))); _CHECK_IO(SafeWrite(v,write,up,&ndefaultparams,sizeof(ndefaultparams))); _CHECK_IO(SafeWrite(v,write,up,&ninstructions,sizeof(ninstructions))); _CHECK_IO(SafeWrite(v,write,up,&nfunctions,sizeof(nfunctions))); _CHECK_IO(WriteTag(v,write,up,SQ_CLOSURESTREAM_PART)); for(i=0;iSave(v,up,write)); } _CHECK_IO(SafeWrite(v,write,up,&_stacksize,sizeof(_stacksize))); _CHECK_IO(SafeWrite(v,write,up,&_bgenerator,sizeof(_bgenerator))); _CHECK_IO(SafeWrite(v,write,up,&_varparams,sizeof(_varparams))); return true; } bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret) { SQInteger i, nliterals,nparameters; SQInteger noutervalues ,nlocalvarinfos ; SQInteger nlineinfos,ninstructions ,nfunctions,ndefaultparams ; SQObjectPtr sourcename, name; SQObjectPtr o; _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(ReadObject(v, up, read, sourcename)); _CHECK_IO(ReadObject(v, up, read, name)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, &nliterals, sizeof(nliterals))); _CHECK_IO(SafeRead(v,read,up, &nparameters, sizeof(nparameters))); _CHECK_IO(SafeRead(v,read,up, &noutervalues, sizeof(noutervalues))); _CHECK_IO(SafeRead(v,read,up, &nlocalvarinfos, sizeof(nlocalvarinfos))); _CHECK_IO(SafeRead(v,read,up, &nlineinfos, sizeof(nlineinfos))); _CHECK_IO(SafeRead(v,read,up, &ndefaultparams, sizeof(ndefaultparams))); _CHECK_IO(SafeRead(v,read,up, &ninstructions, sizeof(ninstructions))); _CHECK_IO(SafeRead(v,read,up, &nfunctions, sizeof(nfunctions))); SQFunctionProto *f = SQFunctionProto::Create(ninstructions,nliterals,nparameters, nfunctions,noutervalues,nlineinfos,nlocalvarinfos,ndefaultparams); SQObjectPtr proto = f; //gets a ref in case of failure f->_sourcename = sourcename; f->_name = name; _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0;i < nliterals; i++){ _CHECK_IO(ReadObject(v, up, read, o)); f->_literals[i] = o; } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < nparameters; i++){ _CHECK_IO(ReadObject(v, up, read, o)); f->_parameters[i] = o; } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < noutervalues; i++){ SQUnsignedInteger type; SQObjectPtr name; _CHECK_IO(SafeRead(v,read,up, &type, sizeof(SQUnsignedInteger))); _CHECK_IO(ReadObject(v, up, read, o)); _CHECK_IO(ReadObject(v, up, read, name)); f->_outervalues[i] = SQOuterVar(name,o, (SQOuterType)type); } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < nlocalvarinfos; i++){ SQLocalVarInfo lvi; _CHECK_IO(ReadObject(v, up, read, lvi._name)); _CHECK_IO(SafeRead(v,read,up, &lvi._pos, sizeof(SQUnsignedInteger))); _CHECK_IO(SafeRead(v,read,up, &lvi._start_op, sizeof(SQUnsignedInteger))); _CHECK_IO(SafeRead(v,read,up, &lvi._end_op, sizeof(SQUnsignedInteger))); f->_localvarinfos[i] = lvi; } _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, f->_lineinfos, sizeof(SQLineInfo)*nlineinfos)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, f->_defaultparams, sizeof(SQInteger)*ndefaultparams)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); _CHECK_IO(SafeRead(v,read,up, f->_instructions, sizeof(SQInstruction)*ninstructions)); _CHECK_IO(CheckTag(v,read,up,SQ_CLOSURESTREAM_PART)); for(i = 0; i < nfunctions; i++){ _CHECK_IO(_funcproto(o)->Load(v, up, read, o)); f->_functions[i] = o; } _CHECK_IO(SafeRead(v,read,up, &f->_stacksize, sizeof(f->_stacksize))); _CHECK_IO(SafeRead(v,read,up, &f->_bgenerator, sizeof(f->_bgenerator))); _CHECK_IO(SafeRead(v,read,up, &f->_varparams, sizeof(f->_varparams))); ret = f; return true; } #ifndef NO_GARBAGE_COLLECTOR #define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ _uiRef|=MARK_FLAG; #define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ AddToChain(chain, this); } void SQVM::Mark(SQCollectable **chain) { START_MARK() SQSharedState::MarkObject(_lasterror,chain); SQSharedState::MarkObject(_errorhandler,chain); SQSharedState::MarkObject(_debughook,chain); SQSharedState::MarkObject(_roottable, chain); SQSharedState::MarkObject(temp_reg, chain); for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain); END_MARK() } void SQArray::Mark(SQCollectable **chain) { START_MARK() SQInteger len = _values.size(); for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); END_MARK() } void SQTable::Mark(SQCollectable **chain) { START_MARK() if(_delegate) _delegate->Mark(chain); SQInteger len = _numofnodes; for(SQInteger i = 0; i < len; i++){ SQSharedState::MarkObject(_nodes[i].key, chain); SQSharedState::MarkObject(_nodes[i].val, chain); } END_MARK() } void SQClass::Mark(SQCollectable **chain) { START_MARK() _members->Mark(chain); if(_base) _base->Mark(chain); SQSharedState::MarkObject(_attributes, chain); for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { SQSharedState::MarkObject(_defaultvalues[i].val, chain); SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); } for(SQUnsignedInteger j =0; j< _methods.size(); j++) { SQSharedState::MarkObject(_methods[j].val, chain); SQSharedState::MarkObject(_methods[j].attrs, chain); } for(SQUnsignedInteger k =0; k< _metamethods.size(); k++) { SQSharedState::MarkObject(_metamethods[k], chain); } END_MARK() } void SQInstance::Mark(SQCollectable **chain) { START_MARK() _class->Mark(chain); SQUnsignedInteger nvalues = _class->_defaultvalues.size(); for(SQUnsignedInteger i =0; i< nvalues; i++) { SQSharedState::MarkObject(_values[i], chain); } END_MARK() } void SQGenerator::Mark(SQCollectable **chain) { START_MARK() for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); SQSharedState::MarkObject(_closure, chain); END_MARK() } void SQClosure::Mark(SQCollectable **chain) { START_MARK() for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); for(SQUnsignedInteger i = 0; i < _defaultparams.size(); i++) SQSharedState::MarkObject(_defaultparams[i], chain); END_MARK() } void SQNativeClosure::Mark(SQCollectable **chain) { START_MARK() for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); END_MARK() } void SQUserData::Mark(SQCollectable **chain){ START_MARK() if(_delegate) _delegate->Mark(chain); END_MARK() } void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } #endif openttd-1.5.3/src/3rdparty/squirrel/include/0000755000000000000000000000000012627373445017540 5ustar rootrootopenttd-1.5.3/src/3rdparty/squirrel/include/sqstdstring.h0000644000000000000000000000163712627373445022305 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQSTD_STRING_H_ #define _SQSTD_STRING_H_ typedef unsigned int SQRexBool; typedef struct SQRex SQRex; typedef struct { const SQChar *begin; SQInteger len; } SQRexMatch; SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error); void sqstd_rex_free(SQRex *exp); SQBool sqstd_rex_match(SQRex* exp,const SQChar* text); SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end); SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end); SQInteger sqstd_rex_getsubexpcount(SQRex* exp); SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp); SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output); SQRESULT sqstd_register_stringlib(HSQUIRRELVM v); #endif /*_SQSTD_STRING_H_*/ openttd-1.5.3/src/3rdparty/squirrel/include/sqstdaux.h0000644000000000000000000000032112627373445021561 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQSTD_AUXLIB_H_ #define _SQSTD_AUXLIB_H_ void sqstd_seterrorhandlers(HSQUIRRELVM v); void sqstd_printcallstack(HSQUIRRELVM v); #endif /* _SQSTD_AUXLIB_H_ */ openttd-1.5.3/src/3rdparty/squirrel/include/sqstdmath.h0000644000000000000000000000024312627373445021720 0ustar rootroot/* see copyright notice in squirrel.h */ #ifndef _SQSTD_MATH_H_ #define _SQSTD_MATH_H_ SQRESULT sqstd_register_mathlib(HSQUIRRELVM v); #endif /*_SQSTD_MATH_H_*/ openttd-1.5.3/src/3rdparty/squirrel/include/squirrel.h0000644000000000000000000003322612627373445021565 0ustar rootroot/* * Copyright (c) 2003-2011 Alberto Demichelis * * This software is provided 'as-is', without any * express or implied warranty. In no event will the * authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software * for any purpose, including commercial applications, * and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. The origin of this software must not be * misrepresented; you must not claim that * you wrote the original software. If you * use this software in a product, an * acknowledgment in the product * documentation would be appreciated but is * not required. * * 2. Altered source versions must be plainly * marked as such, and must not be * misrepresented as being the original * software. * * 3. This notice may not be removed or * altered from any source distribution. */ #ifndef _SQUIRREL_H_ #define _SQUIRREL_H_ #include "../../../string_type.h" typedef __int64 SQInteger; typedef unsigned __int64 SQUnsignedInteger; typedef unsigned __int64 SQHash; /*should be the same size of a pointer*/ typedef int SQInt32; #ifdef SQUSEDOUBLE typedef double SQFloat; #else typedef float SQFloat; #endif typedef __int64 SQRawObjectVal; //must be 64bits #define SQ_OBJECT_RAWINIT() { _unVal.raw = 0; } typedef void* SQUserPointer; typedef SQUnsignedInteger SQBool; typedef SQInteger SQRESULT; #define SQTrue (1) #define SQFalse (0) struct SQVM; struct SQTable; struct SQArray; struct SQString; struct SQClosure; struct SQGenerator; struct SQNativeClosure; struct SQUserData; struct SQFunctionProto; struct SQRefCounted; struct SQClass; struct SQInstance; struct SQDelegable; typedef char SQChar; #define MAX_CHAR 0xFFFF #define SQUIRREL_VERSION "Squirrel 2.2.5 stable - With custom OpenTTD modifications" #define SQUIRREL_COPYRIGHT "Copyright (C) 2003-2010 Alberto Demichelis" #define SQUIRREL_AUTHOR "Alberto Demichelis" #define SQUIRREL_VERSION_NUMBER 225 #define SQ_VMSTATE_IDLE 0 #define SQ_VMSTATE_RUNNING 1 #define SQ_VMSTATE_SUSPENDED 2 #define SQUIRREL_EOB 0 #define SQ_BYTECODE_STREAM_TAG 0xFAFA #define SQOBJECT_REF_COUNTED 0x08000000 #define SQOBJECT_NUMERIC 0x04000000 #define SQOBJECT_DELEGABLE 0x02000000 #define SQOBJECT_CANBEFALSE 0x01000000 #define SQ_MATCHTYPEMASKSTRING (-99999) #define _RT_MASK 0x00FFFFFF #define _RAW_TYPE(type) (type&_RT_MASK) #define _RT_NULL 0x00000001 #define _RT_INTEGER 0x00000002 #define _RT_FLOAT 0x00000004 #define _RT_BOOL 0x00000008 #define _RT_STRING 0x00000010 #define _RT_TABLE 0x00000020 #define _RT_ARRAY 0x00000040 #define _RT_USERDATA 0x00000080 #define _RT_CLOSURE 0x00000100 #define _RT_NATIVECLOSURE 0x00000200 #define _RT_GENERATOR 0x00000400 #define _RT_USERPOINTER 0x00000800 #define _RT_THREAD 0x00001000 #define _RT_FUNCPROTO 0x00002000 #define _RT_CLASS 0x00004000 #define _RT_INSTANCE 0x00008000 #define _RT_WEAKREF 0x00010000 typedef enum tagSQObjectType{ OT_NULL = (_RT_NULL|SQOBJECT_CANBEFALSE), OT_INTEGER = (_RT_INTEGER|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), OT_FLOAT = (_RT_FLOAT|SQOBJECT_NUMERIC|SQOBJECT_CANBEFALSE), OT_BOOL = (_RT_BOOL|SQOBJECT_CANBEFALSE), OT_STRING = (_RT_STRING|SQOBJECT_REF_COUNTED), OT_TABLE = (_RT_TABLE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), OT_ARRAY = (_RT_ARRAY|SQOBJECT_REF_COUNTED), OT_USERDATA = (_RT_USERDATA|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), OT_CLOSURE = (_RT_CLOSURE|SQOBJECT_REF_COUNTED), OT_NATIVECLOSURE = (_RT_NATIVECLOSURE|SQOBJECT_REF_COUNTED), OT_GENERATOR = (_RT_GENERATOR|SQOBJECT_REF_COUNTED), OT_USERPOINTER = _RT_USERPOINTER, OT_THREAD = (_RT_THREAD|SQOBJECT_REF_COUNTED) , OT_FUNCPROTO = (_RT_FUNCPROTO|SQOBJECT_REF_COUNTED), //internal usage only OT_CLASS = (_RT_CLASS|SQOBJECT_REF_COUNTED), OT_INSTANCE = (_RT_INSTANCE|SQOBJECT_REF_COUNTED|SQOBJECT_DELEGABLE), OT_WEAKREF = (_RT_WEAKREF|SQOBJECT_REF_COUNTED) }SQObjectType; #define ISREFCOUNTED(t) (t&SQOBJECT_REF_COUNTED) typedef union tagSQObjectValue { struct SQTable *pTable; struct SQArray *pArray; struct SQClosure *pClosure; struct SQGenerator *pGenerator; struct SQNativeClosure *pNativeClosure; struct SQString *pString; struct SQUserData *pUserData; SQInteger nInteger; SQFloat fFloat; SQUserPointer pUserPointer; struct SQFunctionProto *pFunctionProto; struct SQRefCounted *pRefCounted; struct SQDelegable *pDelegable; struct SQVM *pThread; struct SQClass *pClass; struct SQInstance *pInstance; struct SQWeakRef *pWeakRef; SQRawObjectVal raw; }SQObjectValue; typedef struct tagSQObject { SQObjectType _type; SQObjectValue _unVal; }SQObject; typedef struct tagSQStackInfos{ const SQChar* funcname; const SQChar* source; SQInteger line; }SQStackInfos; typedef struct SQVM* HSQUIRRELVM; typedef SQObject HSQOBJECT; typedef SQInteger (*SQFUNCTION)(HSQUIRRELVM); typedef SQInteger (*SQRELEASEHOOK)(SQUserPointer,SQInteger size); typedef void (*SQCOMPILERERROR)(HSQUIRRELVM,const SQChar * /*desc*/,const SQChar * /*source*/,SQInteger /*line*/,SQInteger /*column*/); typedef void (*SQPRINTFUNCTION)(HSQUIRRELVM,const SQChar * ,...); typedef SQInteger (*SQWRITEFUNC)(SQUserPointer,SQUserPointer,SQInteger); typedef SQInteger (*SQREADFUNC)(SQUserPointer,SQUserPointer,SQInteger); typedef WChar (*SQLEXREADFUNC)(SQUserPointer); typedef struct tagSQRegFunction{ const SQChar *name; SQFUNCTION f; SQInteger nparamscheck; const SQChar *typemask; }SQRegFunction; typedef struct tagSQFunctionInfo { SQUserPointer funcid; const SQChar *name; const SQChar *source; }SQFunctionInfo; /*vm*/ bool sq_can_suspend(HSQUIRRELVM v); HSQUIRRELVM sq_open(SQInteger initialstacksize); HSQUIRRELVM sq_newthread(HSQUIRRELVM friendvm, SQInteger initialstacksize); void sq_seterrorhandler(HSQUIRRELVM v); void sq_close(HSQUIRRELVM v); void sq_setforeignptr(HSQUIRRELVM v,SQUserPointer p); SQUserPointer sq_getforeignptr(HSQUIRRELVM v); void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc); SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); SQRESULT sq_suspendvm(HSQUIRRELVM v); bool sq_resumecatch(HSQUIRRELVM v, int suspend = -1); bool sq_resumeerror(HSQUIRRELVM v); SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror,SQBool throwerror); SQInteger sq_getvmstate(HSQUIRRELVM v); void sq_decreaseops(HSQUIRRELVM v, int amount); /*compiler*/ SQRESULT sq_compile(HSQUIRRELVM v,SQLEXREADFUNC read,SQUserPointer p,const SQChar *sourcename,SQBool raiseerror); SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror); void sq_enabledebuginfo(HSQUIRRELVM v, SQBool enable); void sq_notifyallexceptions(HSQUIRRELVM v, SQBool enable); void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f); /*stack operations*/ void sq_push(HSQUIRRELVM v,SQInteger idx); void sq_pop(HSQUIRRELVM v,SQInteger nelemstopop); void sq_poptop(HSQUIRRELVM v); void sq_remove(HSQUIRRELVM v,SQInteger idx); SQInteger sq_gettop(HSQUIRRELVM v); void sq_settop(HSQUIRRELVM v,SQInteger newtop); void sq_reservestack(HSQUIRRELVM v,SQInteger nsize); SQInteger sq_cmp(HSQUIRRELVM v); void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx); /*object creation handling*/ SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size); void sq_newtable(HSQUIRRELVM v); void sq_newarray(HSQUIRRELVM v,SQInteger size); void sq_newclosure(HSQUIRRELVM v,SQFUNCTION func,SQUnsignedInteger nfreevars); SQRESULT sq_setparamscheck(HSQUIRRELVM v,SQInteger nparamscheck,const SQChar *typemask); SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx); void sq_pushstring(HSQUIRRELVM v,const SQChar *s,SQInteger len); void sq_pushfloat(HSQUIRRELVM v,SQFloat f); void sq_pushinteger(HSQUIRRELVM v,SQInteger n); void sq_pushbool(HSQUIRRELVM v,SQBool b); void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p); void sq_pushnull(HSQUIRRELVM v); SQObjectType sq_gettype(HSQUIRRELVM v,SQInteger idx); SQInteger sq_getsize(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_getbase(HSQUIRRELVM v,SQInteger idx); SQBool sq_instanceof(HSQUIRRELVM v); void sq_tostring(HSQUIRRELVM v,SQInteger idx); void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b); SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c); SQRESULT sq_getinteger(HSQUIRRELVM v,SQInteger idx,SQInteger *i); SQRESULT sq_getfloat(HSQUIRRELVM v,SQInteger idx,SQFloat *f); SQRESULT sq_getbool(HSQUIRRELVM v,SQInteger idx,SQBool *b); SQRESULT sq_getthread(HSQUIRRELVM v,SQInteger idx,HSQUIRRELVM *thread); SQRESULT sq_getuserpointer(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p); SQRESULT sq_getuserdata(HSQUIRRELVM v,SQInteger idx,SQUserPointer *p,SQUserPointer *typetag); SQRESULT sq_settypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer typetag); SQRESULT sq_gettypetag(HSQUIRRELVM v,SQInteger idx,SQUserPointer *typetag); void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook); SQChar *sq_getscratchpad(HSQUIRRELVM v,SQInteger minsize); SQRESULT sq_getfunctioninfo(HSQUIRRELVM v,SQInteger idx,SQFunctionInfo *fi); SQRESULT sq_getclosureinfo(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger *nparams,SQUnsignedInteger *nfreevars); SQRESULT sq_setnativeclosurename(HSQUIRRELVM v,SQInteger idx,const SQChar *name); SQRESULT sq_setinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer p); SQRESULT sq_getinstanceup(HSQUIRRELVM v, SQInteger idx, SQUserPointer *p,SQUserPointer typetag); SQRESULT sq_setclassudsize(HSQUIRRELVM v, SQInteger idx, SQInteger udsize); SQRESULT sq_newclass(HSQUIRRELVM v,SQBool hasbase); SQRESULT sq_createinstance(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_setattributes(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_getattributes(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_getclass(HSQUIRRELVM v,SQInteger idx); void sq_weakref(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_getdefaultdelegate(HSQUIRRELVM v,SQObjectType t); /*object manipulation*/ void sq_pushroottable(HSQUIRRELVM v); void sq_pushregistrytable(HSQUIRRELVM v); void sq_pushconsttable(HSQUIRRELVM v); SQRESULT sq_setroottable(HSQUIRRELVM v); SQRESULT sq_setconsttable(HSQUIRRELVM v); SQRESULT sq_newslot(HSQUIRRELVM v, SQInteger idx, SQBool bstatic); SQRESULT sq_deleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_rawdeleteslot(HSQUIRRELVM v,SQInteger idx,SQBool pushval); SQRESULT sq_arrayappend(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_arraypop(HSQUIRRELVM v,SQInteger idx,SQBool pushval); SQRESULT sq_arrayresize(HSQUIRRELVM v,SQInteger idx,SQInteger newsize); SQRESULT sq_arrayreverse(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_arrayremove(HSQUIRRELVM v,SQInteger idx,SQInteger itemidx); SQRESULT sq_arrayinsert(HSQUIRRELVM v,SQInteger idx,SQInteger destpos); SQRESULT sq_setdelegate(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_clone(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_setfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_getweakrefval(HSQUIRRELVM v,SQInteger idx); SQRESULT sq_clear(HSQUIRRELVM v,SQInteger idx); /*calls*/ SQRESULT sq_call(HSQUIRRELVM v,SQInteger params,SQBool retval,SQBool raiseerror, int suspend = -1); SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror); const SQChar *sq_getlocal(HSQUIRRELVM v,SQUnsignedInteger level,SQUnsignedInteger idx); const SQChar *sq_getfreevariable(HSQUIRRELVM v,SQInteger idx,SQUnsignedInteger nval); SQRESULT sq_throwerror(HSQUIRRELVM v,const SQChar *err); void sq_reseterror(HSQUIRRELVM v); void sq_getlasterror(HSQUIRRELVM v); /*raw object handling*/ SQRESULT sq_getstackobj(HSQUIRRELVM v,SQInteger idx,HSQOBJECT *po); void sq_pushobject(HSQUIRRELVM v,HSQOBJECT obj); void sq_addref(HSQUIRRELVM v,HSQOBJECT *po); SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po); void sq_resetobject(HSQOBJECT *po); const SQChar *sq_objtostring(HSQOBJECT *o); SQBool sq_objtobool(HSQOBJECT *o); SQInteger sq_objtointeger(HSQOBJECT *o); SQFloat sq_objtofloat(HSQOBJECT *o); SQRESULT sq_getobjtypetag(HSQOBJECT *o,SQUserPointer * typetag); /*GC*/ SQInteger sq_collectgarbage(HSQUIRRELVM v); /*serialization*/ SQRESULT sq_writeclosure(HSQUIRRELVM vm,SQWRITEFUNC writef,SQUserPointer up); SQRESULT sq_readclosure(HSQUIRRELVM vm,SQREADFUNC readf,SQUserPointer up); /*mem allocation*/ void *sq_malloc(SQUnsignedInteger size); void *sq_realloc(void* p,SQUnsignedInteger oldsize,SQUnsignedInteger newsize); void sq_free(void *p,SQUnsignedInteger size); /*debug*/ SQRESULT sq_stackinfos(HSQUIRRELVM v,SQInteger level,SQStackInfos *si); void sq_setdebughook(HSQUIRRELVM v); /*UTILITY MACRO*/ #define sq_isnumeric(o) ((o)._type&SQOBJECT_NUMERIC) #define sq_istable(o) ((o)._type==OT_TABLE) #define sq_isarray(o) ((o)._type==OT_ARRAY) #define sq_isfunction(o) ((o)._type==OT_FUNCPROTO) #define sq_isclosure(o) ((o)._type==OT_CLOSURE) #define sq_isgenerator(o) ((o)._type==OT_GENERATOR) #define sq_isnativeclosure(o) ((o)._type==OT_NATIVECLOSURE) #define sq_isstring(o) ((o)._type==OT_STRING) #define sq_isinteger(o) ((o)._type==OT_INTEGER) #define sq_isfloat(o) ((o)._type==OT_FLOAT) #define sq_isuserpointer(o) ((o)._type==OT_USERPOINTER) #define sq_isuserdata(o) ((o)._type==OT_USERDATA) #define sq_isthread(o) ((o)._type==OT_THREAD) #define sq_isnull(o) ((o)._type==OT_NULL) #define sq_isclass(o) ((o)._type==OT_CLASS) #define sq_isinstance(o) ((o)._type==OT_INSTANCE) #define sq_isbool(o) ((o)._type==OT_BOOL) #define sq_isweakref(o) ((o)._type==OT_WEAKREF) #define sq_type(o) ((o)._type) /* deprecated */ #define sq_createslot(v,n) sq_newslot(v,n,SQFalse) #define SQ_OK (0) #define SQ_ERROR (-1) #define SQ_FAILED(res) (res<0) #define SQ_SUCCEEDED(res) (res>=0) #endif /*_SQUIRREL_H_*/ openttd-1.5.3/src/3rdparty/squirrel/README.OpenTTD0000644000000000000000000000026612627373445020255 0ustar rootrootThis folder contains a modified version of Squirrel that is tailored to meet the needs of OpenTTD. We have based this modification on the version as described in: include/squirrel.h openttd-1.5.3/src/3rdparty/squirrel/COPYRIGHT0000644000000000000000000000166512627373445017420 0ustar rootrootCopyright (c) 2003-2011 Alberto Demichelis This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. ----------------------------------------------------- END OF COPYRIGHT openttd-1.5.3/src/3rdparty/squirrel/sqstdlib/0000755000000000000000000000000012627373445017742 5ustar rootrootopenttd-1.5.3/src/3rdparty/squirrel/sqstdlib/sqstdrex.cpp0000644000000000000000000004053212627373445022327 0ustar rootroot/* see copyright notice in squirrel.h */ #include #include #include "sqstdstring.h" #ifdef _UNICODE #define scisprint iswprint #else #define scisprint isprint #endif #ifdef _DEBUG static const SQChar *g_nnames[] = { "NONE","OP_GREEDY", "OP_OR", "OP_EXPR","OP_NOCAPEXPR","OP_DOT", "OP_CLASS", "OP_CCLASS","OP_NCLASS","OP_RANGE","OP_CHAR", "OP_EOL","OP_BOL","OP_WB" }; #endif #define OP_GREEDY (MAX_CHAR+1) // * + ? {n} #define OP_OR (MAX_CHAR+2) #define OP_EXPR (MAX_CHAR+3) //parentesis () #define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:) #define OP_DOT (MAX_CHAR+5) #define OP_CLASS (MAX_CHAR+6) #define OP_CCLASS (MAX_CHAR+7) #define OP_NCLASS (MAX_CHAR+8) //negates class the [^ #define OP_RANGE (MAX_CHAR+9) #define OP_CHAR (MAX_CHAR+10) #define OP_EOL (MAX_CHAR+11) #define OP_BOL (MAX_CHAR+12) #define OP_WB (MAX_CHAR+13) #define SQREX_SYMBOL_ANY_CHAR ('.') #define SQREX_SYMBOL_GREEDY_ONE_OR_MORE ('+') #define SQREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*') #define SQREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?') #define SQREX_SYMBOL_BRANCH ('|') #define SQREX_SYMBOL_END_OF_STRING ('$') #define SQREX_SYMBOL_BEGINNING_OF_STRING ('^') #define SQREX_SYMBOL_ESCAPE_CHAR ('\\') typedef int SQRexNodeType; typedef struct tagSQRexNode{ SQRexNodeType type; SQInteger left; SQInteger right; SQInteger next; }SQRexNode; struct SQRex{ const SQChar *_eol; const SQChar *_bol; const SQChar *_p; SQInteger _first; SQInteger _op; SQRexNode *_nodes; SQInteger _nallocated; SQInteger _nsize; SQInteger _nsubexpr; SQRexMatch *_matches; SQInteger _currsubexp; const SQChar **_error; }; static SQInteger sqstd_rex_list(SQRex *exp); static SQInteger sqstd_rex_newnode(SQRex *exp, SQRexNodeType type) { SQRexNode n; n.type = type; n.next = n.right = n.left = -1; if(type == OP_EXPR) n.right = exp->_nsubexpr++; if(exp->_nallocated < (exp->_nsize + 1)) { SQInteger oldsize = exp->_nallocated; exp->_nallocated *= 2; exp->_nodes = (SQRexNode *)sq_realloc(exp->_nodes, oldsize * sizeof(SQRexNode) ,exp->_nallocated * sizeof(SQRexNode)); } exp->_nodes[exp->_nsize++] = n; SQInteger newid = exp->_nsize - 1; return (SQInteger)newid; } static void sqstd_rex_error(SQRex *exp,const SQChar *error) { if(exp->_error) *exp->_error = error; throw std::exception(); } static void sqstd_rex_expect(SQRex *exp, SQChar n){ if((*exp->_p) != n) sqstd_rex_error(exp, "expected paren"); exp->_p++; } static SQChar sqstd_rex_escapechar(SQRex *exp) { if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR){ exp->_p++; switch(*exp->_p) { case 'v': exp->_p++; return '\v'; case 'n': exp->_p++; return '\n'; case 't': exp->_p++; return '\t'; case 'r': exp->_p++; return '\r'; case 'f': exp->_p++; return '\f'; default: return (*exp->_p++); } } else if(!scisprint(*exp->_p)) sqstd_rex_error(exp,"letter expected"); return (*exp->_p++); } static SQInteger sqstd_rex_charclass(SQRex *exp,SQInteger classid) { SQInteger n = sqstd_rex_newnode(exp,OP_CCLASS); exp->_nodes[n].left = classid; return n; } static SQInteger sqstd_rex_charnode(SQRex *exp,SQBool isclass) { SQChar t; if(*exp->_p == SQREX_SYMBOL_ESCAPE_CHAR) { exp->_p++; switch(*exp->_p) { case 'n': exp->_p++; return sqstd_rex_newnode(exp,'\n'); case 't': exp->_p++; return sqstd_rex_newnode(exp,'\t'); case 'r': exp->_p++; return sqstd_rex_newnode(exp,'\r'); case 'f': exp->_p++; return sqstd_rex_newnode(exp,'\f'); case 'v': exp->_p++; return sqstd_rex_newnode(exp,'\v'); case 'a': case 'A': case 'w': case 'W': case 's': case 'S': case 'd': case 'D': case 'x': case 'X': case 'c': case 'C': case 'p': case 'P': case 'l': case 'u': { t = *exp->_p; exp->_p++; return sqstd_rex_charclass(exp,t); } case 'b': case 'B': if(!isclass) { SQInteger node = sqstd_rex_newnode(exp,OP_WB); exp->_nodes[node].left = *exp->_p; exp->_p++; return node; } //else default default: t = *exp->_p; exp->_p++; return sqstd_rex_newnode(exp,t); } } else if(!scisprint(*exp->_p)) { sqstd_rex_error(exp,"letter expected"); } t = *exp->_p; exp->_p++; return sqstd_rex_newnode(exp,t); } static SQInteger sqstd_rex_class(SQRex *exp) { SQInteger ret = -1; SQInteger first = -1,chain; if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING){ ret = sqstd_rex_newnode(exp,OP_NCLASS); exp->_p++; }else ret = sqstd_rex_newnode(exp,OP_CLASS); if(*exp->_p == ']') sqstd_rex_error(exp,"empty class"); chain = ret; while(*exp->_p != ']' && exp->_p != exp->_eol) { if(*exp->_p == '-' && first != -1){ SQInteger r; if(*exp->_p++ == ']') sqstd_rex_error(exp,"unfinished range"); r = sqstd_rex_newnode(exp,OP_RANGE); if(exp->_nodes[first].type>*exp->_p) sqstd_rex_error(exp,"invalid range"); if(exp->_nodes[first].type == OP_CCLASS) sqstd_rex_error(exp,"cannot use character classes in ranges"); exp->_nodes[r].left = exp->_nodes[first].type; SQInteger t = sqstd_rex_escapechar(exp); exp->_nodes[r].right = t; exp->_nodes[chain].next = r; chain = r; first = -1; } else{ if(first!=-1){ SQInteger c = first; exp->_nodes[chain].next = c; chain = c; first = sqstd_rex_charnode(exp,SQTrue); } else{ first = sqstd_rex_charnode(exp,SQTrue); } } } if(first!=-1){ SQInteger c = first; exp->_nodes[chain].next = c; chain = c; first = -1; } /* hack? */ exp->_nodes[ret].left = exp->_nodes[ret].next; exp->_nodes[ret].next = -1; return ret; } static SQInteger sqstd_rex_parsenumber(SQRex *exp) { SQInteger ret = *exp->_p-'0'; SQInteger positions = 10; exp->_p++; while(isdigit(*exp->_p)) { ret = ret*10+(*exp->_p++-'0'); if(positions==1000000000) sqstd_rex_error(exp,"overflow in numeric constant"); positions *= 10; }; return ret; } static SQInteger sqstd_rex_element(SQRex *exp) { SQInteger ret = -1; switch(*exp->_p) { case '(': { SQInteger expr; exp->_p++; if(*exp->_p =='?') { exp->_p++; sqstd_rex_expect(exp,':'); expr = sqstd_rex_newnode(exp,OP_NOCAPEXPR); } else expr = sqstd_rex_newnode(exp,OP_EXPR); SQInteger newn = sqstd_rex_list(exp); exp->_nodes[expr].left = newn; ret = expr; sqstd_rex_expect(exp,')'); } break; case '[': exp->_p++; ret = sqstd_rex_class(exp); sqstd_rex_expect(exp,']'); break; case SQREX_SYMBOL_END_OF_STRING: exp->_p++; ret = sqstd_rex_newnode(exp,OP_EOL);break; case SQREX_SYMBOL_ANY_CHAR: exp->_p++; ret = sqstd_rex_newnode(exp,OP_DOT);break; default: ret = sqstd_rex_charnode(exp,SQFalse); break; } SQInteger op; SQBool isgreedy = SQFalse; unsigned short p0 = 0, p1 = 0; switch(*exp->_p){ case SQREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; case SQREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = SQTrue; break; case SQREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = SQTrue; break; case '{': exp->_p++; if(!isdigit(*exp->_p)) sqstd_rex_error(exp,"number expected"); p0 = (unsigned short)sqstd_rex_parsenumber(exp); /*******************************/ switch(*exp->_p) { case '}': p1 = p0; exp->_p++; break; case ',': exp->_p++; p1 = 0xFFFF; if(isdigit(*exp->_p)){ p1 = (unsigned short)sqstd_rex_parsenumber(exp); } sqstd_rex_expect(exp,'}'); break; default: sqstd_rex_error(exp,", or } expected"); } /*******************************/ isgreedy = SQTrue; break; } if(isgreedy) { SQInteger nnode = sqstd_rex_newnode(exp,OP_GREEDY); op = OP_GREEDY; exp->_nodes[nnode].left = ret; exp->_nodes[nnode].right = ((p0)<<16)|p1; ret = nnode; } if((*exp->_p != SQREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != SQREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != SQREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) { SQInteger nnode = sqstd_rex_element(exp); exp->_nodes[ret].next = nnode; } return ret; } static SQInteger sqstd_rex_list(SQRex *exp) { SQInteger ret=-1,e; if(*exp->_p == SQREX_SYMBOL_BEGINNING_OF_STRING) { exp->_p++; ret = sqstd_rex_newnode(exp,OP_BOL); } e = sqstd_rex_element(exp); if(ret != -1) { exp->_nodes[ret].next = e; } else ret = e; if(*exp->_p == SQREX_SYMBOL_BRANCH) { SQInteger temp,tright; exp->_p++; temp = sqstd_rex_newnode(exp,OP_OR); exp->_nodes[temp].left = ret; tright = sqstd_rex_list(exp); exp->_nodes[temp].right = tright; ret = temp; } return ret; } static SQBool sqstd_rex_matchcclass(SQInteger cclass,SQChar c) { switch(cclass) { case 'a': return isalpha(c)?SQTrue:SQFalse; case 'A': return !isalpha(c)?SQTrue:SQFalse; case 'w': return (isalnum(c) || c == '_')?SQTrue:SQFalse; case 'W': return (!isalnum(c) && c != '_')?SQTrue:SQFalse; case 's': return isspace(c)?SQTrue:SQFalse; case 'S': return !isspace(c)?SQTrue:SQFalse; case 'd': return isdigit(c)?SQTrue:SQFalse; case 'D': return !isdigit(c)?SQTrue:SQFalse; case 'x': return isxdigit(c)?SQTrue:SQFalse; case 'X': return !isxdigit(c)?SQTrue:SQFalse; case 'c': return iscntrl(c)?SQTrue:SQFalse; case 'C': return !iscntrl(c)?SQTrue:SQFalse; case 'p': return ispunct(c)?SQTrue:SQFalse; case 'P': return !ispunct(c)?SQTrue:SQFalse; case 'l': return islower(c)?SQTrue:SQFalse; case 'u': return isupper(c)?SQTrue:SQFalse; } return SQFalse; /*cannot happen*/ } static SQBool sqstd_rex_matchclass(SQRex* exp,SQRexNode *node,SQInteger c) { do { switch(node->type) { case OP_RANGE: if(c >= node->left && c <= node->right) return SQTrue; break; case OP_CCLASS: if(sqstd_rex_matchcclass(node->left,c)) return SQTrue; break; default: if(c == node->type)return SQTrue; } } while((node->next != -1) && (node = &exp->_nodes[node->next])); return SQFalse; } static const SQChar *sqstd_rex_matchnode(SQRex* exp,SQRexNode *node,const SQChar *str,SQRexNode *next) { SQRexNodeType type = node->type; switch(type) { case OP_GREEDY: { //SQRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL; SQRexNode *greedystop = NULL; SQInteger p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0; const SQChar *s=str, *good = str; if(node->next != -1) { greedystop = &exp->_nodes[node->next]; } else { greedystop = next; } while((nmaches == 0xFFFF || nmaches < p1)) { const SQChar *stop; if(!(s = sqstd_rex_matchnode(exp,&exp->_nodes[node->left],s,greedystop))) break; nmaches++; good=s; if(greedystop) { //checks that 0 matches satisfy the expression(if so skips) //if not would always stop(for instance if is a '?') if(greedystop->type != OP_GREEDY || (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0)) { SQRexNode *gnext = NULL; if(greedystop->next != -1) { gnext = &exp->_nodes[greedystop->next]; }else if(next && next->next != -1){ gnext = &exp->_nodes[next->next]; } stop = sqstd_rex_matchnode(exp,greedystop,s,gnext); if(stop) { //if satisfied stop it if(p0 == p1 && p0 == nmaches) break; else if(nmaches >= p0 && p1 == 0xFFFF) break; else if(nmaches >= p0 && nmaches <= p1) break; } } } if(s >= exp->_eol) break; } if(p0 == p1 && p0 == nmaches) return good; else if(nmaches >= p0 && p1 == 0xFFFF) return good; else if(nmaches >= p0 && nmaches <= p1) return good; return NULL; } case OP_OR: { const SQChar *asd = str; SQRexNode *temp=&exp->_nodes[node->left]; while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { if(temp->next != -1) temp = &exp->_nodes[temp->next]; else return asd; } asd = str; temp = &exp->_nodes[node->right]; while( (asd = sqstd_rex_matchnode(exp,temp,asd,NULL)) ) { if(temp->next != -1) temp = &exp->_nodes[temp->next]; else return asd; } return NULL; break; } case OP_EXPR: case OP_NOCAPEXPR:{ SQRexNode *n = &exp->_nodes[node->left]; const SQChar *cur = str; SQInteger capture = -1; if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) { capture = exp->_currsubexp; exp->_matches[capture].begin = cur; exp->_currsubexp++; } do { SQRexNode *subnext = NULL; if(n->next != -1) { subnext = &exp->_nodes[n->next]; }else { subnext = next; } if(!(cur = sqstd_rex_matchnode(exp,n,cur,subnext))) { if(capture != -1){ exp->_matches[capture].begin = 0; exp->_matches[capture].len = 0; } return NULL; } } while((n->next != -1) && (n = &exp->_nodes[n->next])); if(capture != -1) exp->_matches[capture].len = cur - exp->_matches[capture].begin; return cur; } case OP_WB: if((str == exp->_bol && !isspace(*str)) || (str == exp->_eol && !isspace(*(str-1))) || (!isspace(*str) && isspace(*(str+1))) || (isspace(*str) && !isspace(*(str+1))) ) { return (node->left == 'b')?str:NULL; } return (node->left == 'b')?NULL:str; case OP_BOL: if(str == exp->_bol) return str; return NULL; case OP_EOL: if(str == exp->_eol) return str; return NULL; case OP_DOT:{ *str++; } return str; case OP_NCLASS: case OP_CLASS: if(sqstd_rex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?SQTrue:SQFalse):(type == OP_NCLASS?SQTrue:SQFalse)) { *str++; return str; } return NULL; case OP_CCLASS: if(sqstd_rex_matchcclass(node->left,*str)) { *str++; return str; } return NULL; default: /* char */ if(*str != (SQChar)node->type) return NULL; *str++; return str; } return NULL; } /* public api */ SQRex *sqstd_rex_compile(const SQChar *pattern,const SQChar **error) { SQRex *exp = (SQRex *)sq_malloc(sizeof(SQRex)); exp->_eol = exp->_bol = NULL; exp->_p = pattern; exp->_nallocated = (SQInteger)strlen(pattern) * sizeof(SQChar); exp->_nodes = (SQRexNode *)sq_malloc(exp->_nallocated * sizeof(SQRexNode)); exp->_nsize = 0; exp->_matches = 0; exp->_nsubexpr = 0; exp->_first = sqstd_rex_newnode(exp,OP_EXPR); exp->_error = error; try { SQInteger res = sqstd_rex_list(exp); exp->_nodes[exp->_first].left = res; if(*exp->_p!='\0') sqstd_rex_error(exp,"unexpected character"); #ifdef _DEBUG { SQInteger nsize,i; SQRexNode *t; nsize = exp->_nsize; t = &exp->_nodes[0]; printf("\n"); /* XXX -- The (int) casts are needed to silent warnings on 64bit systems (SQInteger is 64bit, %d assumes 32bit, (int) is 32bit) */ for(i = 0;i < nsize; i++) { if(exp->_nodes[i].type>MAX_CHAR) printf("[%02d] %10s ",(int)i,g_nnames[exp->_nodes[i].type-MAX_CHAR]); else printf("[%02d] %10c ",(int)i,exp->_nodes[i].type); printf("left %02d right %02d next %02d\n",(int)exp->_nodes[i].left,(int)exp->_nodes[i].right,(int)exp->_nodes[i].next); } printf("\n"); } #endif exp->_matches = (SQRexMatch *) sq_malloc(exp->_nsubexpr * sizeof(SQRexMatch)); memset(exp->_matches,0,exp->_nsubexpr * sizeof(SQRexMatch)); } catch (...) { sqstd_rex_free(exp); return NULL; } return exp; } void sqstd_rex_free(SQRex *exp) { if(exp) { if(exp->_nodes) sq_free(exp->_nodes,exp->_nallocated * sizeof(SQRexNode)); if(exp->_matches) sq_free(exp->_matches,exp->_nsubexpr * sizeof(SQRexMatch)); sq_free(exp,sizeof(SQRex)); } } SQBool sqstd_rex_match(SQRex* exp,const SQChar* text) { const SQChar* res = NULL; exp->_bol = text; exp->_eol = text + strlen(text); exp->_currsubexp = 0; res = sqstd_rex_matchnode(exp,exp->_nodes,text,NULL); if(res == NULL || res != exp->_eol) return SQFalse; return SQTrue; } SQBool sqstd_rex_searchrange(SQRex* exp,const SQChar* text_begin,const SQChar* text_end,const SQChar** out_begin, const SQChar** out_end) { const SQChar *cur = NULL; SQInteger node = exp->_first; if(text_begin >= text_end) return SQFalse; exp->_bol = text_begin; exp->_eol = text_end; do { cur = text_begin; while(node != -1) { exp->_currsubexp = 0; cur = sqstd_rex_matchnode(exp,&exp->_nodes[node],cur,NULL); if(!cur) break; node = exp->_nodes[node].next; } *text_begin++; } while(cur == NULL && text_begin != text_end); if(cur == NULL) return SQFalse; --text_begin; if(out_begin) *out_begin = text_begin; if(out_end) *out_end = cur; return SQTrue; } SQBool sqstd_rex_search(SQRex* exp,const SQChar* text, const SQChar** out_begin, const SQChar** out_end) { return sqstd_rex_searchrange(exp,text,text + strlen(text),out_begin,out_end); } SQInteger sqstd_rex_getsubexpcount(SQRex* exp) { return exp->_nsubexpr; } SQBool sqstd_rex_getsubexp(SQRex* exp, SQInteger n, SQRexMatch *subexp) { if( n<0 || n >= exp->_nsubexpr) return SQFalse; *subexp = exp->_matches[n]; return SQTrue; } openttd-1.5.3/src/3rdparty/squirrel/sqstdlib/sqstdaux.cpp0000644000000000000000000000644512627373445022333 0ustar rootroot/* see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include #include #include "../../../safeguards.h" void sqstd_printcallstack(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_getprintfunc(v); if(pf) { SQStackInfos si; SQInteger i; SQBool b; SQFloat f; const SQChar *s; SQInteger level=1; //1 is to skip this function that is level 0 const SQChar *name=0; SQInteger seq=0; pf(v,"\nCALLSTACK\n"); while(SQ_SUCCEEDED(sq_stackinfos(v,level,&si))) { const SQChar *fn="unknown"; const SQChar *src="unknown"; if(si.funcname)fn=si.funcname; if(si.source) { /* We don't want to bother users with absolute paths to all AI files. * Since the path only reaches NoAI code in a formatted string we have * to strip it here. Let's hope nobody installs openttd in a subdirectory * of a directory named /ai/. */ src = strstr(si.source, "\\ai\\"); if (!src) src = strstr(si.source, "/ai/"); if (src) { src += 4; } else { src = si.source; } } pf(v,"*FUNCTION [%s()] %s line [%d]\n",fn,src,si.line); level++; } level=0; pf(v,"\nLOCALS\n"); for(level=0;level<10;level++){ seq=0; while((name = sq_getlocal(v,level,seq))) { seq++; switch(sq_gettype(v,-1)) { case OT_NULL: pf(v,"[%s] NULL\n",name); break; case OT_INTEGER: sq_getinteger(v,-1,&i); pf(v,"[%s] %d\n",name,i); break; case OT_FLOAT: sq_getfloat(v,-1,&f); pf(v,"[%s] %.14g\n",name,f); break; case OT_USERPOINTER: pf(v,"[%s] USERPOINTER\n",name); break; case OT_STRING: sq_getstring(v,-1,&s); pf(v,"[%s] \"%s\"\n",name,s); break; case OT_TABLE: pf(v,"[%s] TABLE\n",name); break; case OT_ARRAY: pf(v,"[%s] ARRAY\n",name); break; case OT_CLOSURE: pf(v,"[%s] CLOSURE\n",name); break; case OT_NATIVECLOSURE: pf(v,"[%s] NATIVECLOSURE\n",name); break; case OT_GENERATOR: pf(v,"[%s] GENERATOR\n",name); break; case OT_USERDATA: pf(v,"[%s] USERDATA\n",name); break; case OT_THREAD: pf(v,"[%s] THREAD\n",name); break; case OT_CLASS: pf(v,"[%s] CLASS\n",name); break; case OT_INSTANCE: pf(v,"[%s] INSTANCE\n",name); break; case OT_WEAKREF: pf(v,"[%s] WEAKREF\n",name); break; case OT_BOOL:{ sq_getbool(v,-1,&b); pf(v,"[%s] %s\n",name,b?"true":"false"); } break; default: assert(0); break; } sq_pop(v,1); } } } } static SQInteger _sqstd_aux_printerror(HSQUIRRELVM v) { SQPRINTFUNCTION pf = sq_getprintfunc(v); if(pf) { const SQChar *sErr = 0; if(sq_gettop(v)>=1) { if(SQ_SUCCEEDED(sq_getstring(v,2,&sErr))) { pf(v,"\nAN ERROR HAS OCCURED [%s]\n",sErr); } else{ pf(v,"\nAN ERROR HAS OCCURED [unknown]\n"); } sqstd_printcallstack(v); } } return 0; } void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSource,SQInteger line,SQInteger column) { SQPRINTFUNCTION pf = sq_getprintfunc(v); if(pf) { pf(v,"%s line = (%d) column = (%d) : error %s\n",sSource,line,column,sErr); } } void sqstd_seterrorhandlers(HSQUIRRELVM v) { sq_setcompilererrorhandler(v,_sqstd_compiler_error); sq_newclosure(v,_sqstd_aux_printerror,0); sq_seterrorhandler(v); } openttd-1.5.3/src/3rdparty/squirrel/sqstdlib/sqstdstring.cpp0000644000000000000000000002171612627373445023042 0ustar rootroot/* see copyright notice in squirrel.h */ #include #include #include #define scstrchr strchr #define scatoi atoi #define scstrtok strtok #define MAX_FORMAT_LEN 20 #define MAX_WFORMAT_LEN 3 #define ADDITIONAL_FORMAT_SPACE (100*sizeof(SQChar)) static SQInteger validate_format(HSQUIRRELVM v, SQChar *fmt, const SQChar *src, SQInteger n,SQInteger &width) { SQChar swidth[MAX_WFORMAT_LEN]; SQInteger wc = 0; SQInteger start = n; fmt[0] = '%'; while (scstrchr("-+ #0", src[n])) n++; while (isdigit(src[n])) { swidth[wc] = src[n]; n++; wc++; if(wc>=MAX_WFORMAT_LEN) return sq_throwerror(v,"width format too long"); } swidth[wc] = '\0'; if(wc > 0) { width = atoi(swidth); } else width = 0; if (src[n] == '.') { n++; wc = 0; while (isdigit(src[n])) { swidth[wc] = src[n]; n++; wc++; if(wc>=MAX_WFORMAT_LEN) return sq_throwerror(v,"precision format too long"); } swidth[wc] = '\0'; if(wc > 0) { width += atoi(swidth); } } if (n-start > MAX_FORMAT_LEN ) return sq_throwerror(v,"format too long"); memcpy(&fmt[1],&src[start],((n-start)+1)*sizeof(SQChar)); fmt[(n-start)+2] = '\0'; return n; } /* * Little hack to remove the "format not a string literal, argument types not checked" warning. * This check has been added to OpenTTD to make sure that nobody passes wrong string literals, * but three lines in Squirrel have a little problem with those. Therefor we use this hack * which basically uses vsnprintf instead of sprintf as vsnprintf is not testing for the right * string literal at compile time. */ static void _append_string(SQInteger &i, SQChar *dest, SQInteger allocated, const SQChar *fmt, ...) { va_list va; va_start(va, fmt); i += vsnprintf(&dest[i],allocated-i,fmt,va); va_end(va); } SQRESULT sqstd_format(HSQUIRRELVM v,SQInteger nformatstringidx,SQInteger *outlen,SQChar **output) { const SQChar *format; SQChar *dest; SQChar fmt[MAX_FORMAT_LEN]; sq_getstring(v,nformatstringidx,&format); SQInteger allocated = (sq_getsize(v,nformatstringidx)+2)*sizeof(SQChar); dest = sq_getscratchpad(v,allocated); SQInteger n = 0,i = 0, nparam = nformatstringidx+1, w = 0; while(format[n] != '\0') { if(format[n] != '%') { assert(i < allocated); dest[i++] = format[n]; n++; } else if(format[n+1] == '%') { //handles %% dest[i++] = '%'; n += 2; } else { n++; if( nparam > sq_gettop(v) ) return sq_throwerror(v,"not enough paramters for the given format string"); n = validate_format(v,fmt,format,n,w); if(n < 0) return -1; SQInteger addlen = 0; SQInteger valtype = 0; const SQChar *ts; SQInteger ti; SQFloat tf; switch(format[n]) { case 's': if(SQ_FAILED(sq_getstring(v,nparam,&ts))) return sq_throwerror(v,"string expected for the specified format"); addlen = (sq_getsize(v,nparam)*sizeof(SQChar))+((w+1)*sizeof(SQChar)); valtype = 's'; break; case 'i': case 'd': case 'c':case 'o': case 'u': case 'x': case 'X': if(SQ_FAILED(sq_getinteger(v,nparam,&ti))) return sq_throwerror(v,"integer expected for the specified format"); addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); valtype = 'i'; break; case 'f': case 'g': case 'G': case 'e': case 'E': if(SQ_FAILED(sq_getfloat(v,nparam,&tf))) return sq_throwerror(v,"float expected for the specified format"); addlen = (ADDITIONAL_FORMAT_SPACE)+((w+1)*sizeof(SQChar)); valtype = 'f'; break; default: return sq_throwerror(v,"invalid format"); } n++; allocated += addlen + sizeof(SQChar); dest = sq_getscratchpad(v,allocated); switch(valtype) { case 's': _append_string(i,dest,allocated,fmt,ts); break; case 'i': _append_string(i,dest,allocated,fmt,ti); break; case 'f': _append_string(i,dest,allocated,fmt,tf); break; }; nparam ++; } } *outlen = i; dest[i] = '\0'; *output = dest; return SQ_OK; } static SQInteger _string_format(HSQUIRRELVM v) { SQChar *dest = NULL; SQInteger length = 0; if(SQ_FAILED(sqstd_format(v,2,&length,&dest))) return -1; sq_pushstring(v,dest,length); return 1; } static void __strip_l(const SQChar *str,const SQChar **start) { const SQChar *t = str; while(((*t) != '\0') && isspace(*t)){ t++; } *start = t; } static void __strip_r(const SQChar *str,SQInteger len,const SQChar **end) { if(len == 0) { *end = str; return; } const SQChar *t = &str[len-1]; while(t != str && isspace(*t)) { t--; } *end = t+1; } static SQInteger _string_strip(HSQUIRRELVM v) { const SQChar *str,*start,*end; sq_getstring(v,2,&str); SQInteger len = sq_getsize(v,2); __strip_l(str,&start); __strip_r(str,len,&end); sq_pushstring(v,start,end - start); return 1; } static SQInteger _string_lstrip(HSQUIRRELVM v) { const SQChar *str,*start; sq_getstring(v,2,&str); __strip_l(str,&start); sq_pushstring(v,start,-1); return 1; } static SQInteger _string_rstrip(HSQUIRRELVM v) { const SQChar *str,*end; sq_getstring(v,2,&str); SQInteger len = sq_getsize(v,2); __strip_r(str,len,&end); sq_pushstring(v,str,end - str); return 1; } static SQInteger _string_split(HSQUIRRELVM v) { const SQChar *str,*seps; SQChar *stemp,*tok; sq_getstring(v,2,&str); sq_getstring(v,3,&seps); if(sq_getsize(v,3) == 0) return sq_throwerror(v,"empty separators string"); SQInteger memsize = (sq_getsize(v,2)+1)*sizeof(SQChar); stemp = sq_getscratchpad(v,memsize); memcpy(stemp,str,memsize); tok = scstrtok(stemp,seps); sq_newarray(v,0); while( tok != NULL ) { sq_pushstring(v,tok,-1); sq_arrayappend(v,-2); tok = scstrtok( NULL, seps ); } return 1; } #define SETUP_REX(v) \ SQRex *self = NULL; \ sq_getinstanceup(v,1,(SQUserPointer *)&self,0); static SQInteger _rexobj_releasehook(SQUserPointer p, SQInteger size) { SQRex *self = ((SQRex *)p); sqstd_rex_free(self); return 1; } static SQInteger _regexp_match(HSQUIRRELVM v) { SETUP_REX(v); const SQChar *str; sq_getstring(v,2,&str); if(sqstd_rex_match(self,str) == SQTrue) { sq_pushbool(v,SQTrue); return 1; } sq_pushbool(v,SQFalse); return 1; } static void _addrexmatch(HSQUIRRELVM v,const SQChar *str,const SQChar *begin,const SQChar *end) { sq_newtable(v); sq_pushstring(v,"begin",-1); sq_pushinteger(v,begin - str); sq_rawset(v,-3); sq_pushstring(v,"end",-1); sq_pushinteger(v,end - str); sq_rawset(v,-3); } static SQInteger _regexp_search(HSQUIRRELVM v) { SETUP_REX(v); const SQChar *str,*begin,*end; SQInteger start = 0; sq_getstring(v,2,&str); if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { _addrexmatch(v,str,begin,end); return 1; } return 0; } static SQInteger _regexp_capture(HSQUIRRELVM v) { SETUP_REX(v); const SQChar *str,*begin,*end; SQInteger start = 0; sq_getstring(v,2,&str); if(sq_gettop(v) > 2) sq_getinteger(v,3,&start); if(sqstd_rex_search(self,str+start,&begin,&end) == SQTrue) { SQInteger n = sqstd_rex_getsubexpcount(self); SQRexMatch match; sq_newarray(v,0); for(SQInteger i = 0;i < n; i++) { sqstd_rex_getsubexp(self,i,&match); if(match.len > 0) _addrexmatch(v,str,match.begin,match.begin+match.len); else _addrexmatch(v,str,str,str); //empty match sq_arrayappend(v,-2); } return 1; } return 0; } static SQInteger _regexp_subexpcount(HSQUIRRELVM v) { SETUP_REX(v); sq_pushinteger(v,sqstd_rex_getsubexpcount(self)); return 1; } static SQInteger _regexp_constructor(HSQUIRRELVM v) { const SQChar *error,*pattern; sq_getstring(v,2,&pattern); SQRex *rex = sqstd_rex_compile(pattern,&error); if(!rex) return sq_throwerror(v,error); sq_setinstanceup(v,1,rex); sq_setreleasehook(v,1,_rexobj_releasehook); return 0; } static SQInteger _regexp__typeof(HSQUIRRELVM v) { sq_pushstring(v,"regexp",-1); return 1; } #define _DECL_REX_FUNC(name,nparams,pmask) {#name,_regexp_##name,nparams,pmask} static SQRegFunction rexobj_funcs[]={ _DECL_REX_FUNC(constructor,2,".s"), _DECL_REX_FUNC(search,-2,"xsn"), _DECL_REX_FUNC(match,2,"xs"), _DECL_REX_FUNC(capture,-2,"xsn"), _DECL_REX_FUNC(subexpcount,1,"x"), _DECL_REX_FUNC(_typeof,1,"x"), {0,0,0,0} }; #define _DECL_FUNC(name,nparams,pmask) {#name,_string_##name,nparams,pmask} static SQRegFunction stringlib_funcs[]={ _DECL_FUNC(format,-2,".s"), _DECL_FUNC(strip,2,".s"), _DECL_FUNC(lstrip,2,".s"), _DECL_FUNC(rstrip,2,".s"), _DECL_FUNC(split,3,".ss"), {0,0,0,0} }; SQInteger sqstd_register_stringlib(HSQUIRRELVM v) { sq_pushstring(v,"regexp",-1); sq_newclass(v,SQFalse); SQInteger i = 0; while(rexobj_funcs[i].name != 0) { SQRegFunction &f = rexobj_funcs[i]; sq_pushstring(v,f.name,-1); sq_newclosure(v,f.f,0); sq_setparamscheck(v,f.nparamscheck,f.typemask); sq_setnativeclosurename(v,-1,f.name); sq_createslot(v,-3); i++; } sq_createslot(v,-3); i = 0; while(stringlib_funcs[i].name!=0) { sq_pushstring(v,stringlib_funcs[i].name,-1); sq_newclosure(v,stringlib_funcs[i].f,0); sq_setparamscheck(v,stringlib_funcs[i].nparamscheck,stringlib_funcs[i].typemask); sq_setnativeclosurename(v,-1,stringlib_funcs[i].name); sq_createslot(v,-3); i++; } return 1; } openttd-1.5.3/src/3rdparty/squirrel/sqstdlib/sqstdmath.cpp0000644000000000000000000000552512627373445022465 0ustar rootroot/* see copyright notice in squirrel.h */ #include "../../../stdafx.h" #include #include #include #include "../../../safeguards.h" #define SINGLE_ARG_FUNC(_funcname, num_ops) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ SQFloat f; \ sq_decreaseops(v,num_ops); \ sq_getfloat(v,2,&f); \ sq_pushfloat(v,(SQFloat)_funcname(f)); \ return 1; \ } #define TWO_ARGS_FUNC(_funcname, num_ops) static SQInteger math_##_funcname(HSQUIRRELVM v){ \ SQFloat p1,p2; \ sq_decreaseops(v,num_ops); \ sq_getfloat(v,2,&p1); \ sq_getfloat(v,3,&p2); \ sq_pushfloat(v,(SQFloat)_funcname(p1,p2)); \ return 1; \ } #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS static SQInteger math_srand(HSQUIRRELVM v) { SQInteger i; if(SQ_FAILED(sq_getinteger(v,2,&i))) return sq_throwerror(v,"invalid param"); srand((unsigned int)i); return 0; } static SQInteger math_rand(HSQUIRRELVM v) { sq_pushinteger(v,rand()); return 1; } #endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ static SQInteger math_abs(HSQUIRRELVM v) { SQInteger n; sq_getinteger(v,2,&n); sq_pushinteger(v,(SQInteger)abs((int)n)); return 1; } SINGLE_ARG_FUNC(sqrt, 100) SINGLE_ARG_FUNC(fabs, 1) SINGLE_ARG_FUNC(sin, 100) SINGLE_ARG_FUNC(cos, 100) SINGLE_ARG_FUNC(asin, 100) SINGLE_ARG_FUNC(acos, 100) SINGLE_ARG_FUNC(log, 100) SINGLE_ARG_FUNC(log10, 100) SINGLE_ARG_FUNC(tan, 100) SINGLE_ARG_FUNC(atan, 100) TWO_ARGS_FUNC(atan2, 100) TWO_ARGS_FUNC(pow, 100) SINGLE_ARG_FUNC(floor, 1) SINGLE_ARG_FUNC(ceil, 1) SINGLE_ARG_FUNC(exp, 100) #define _DECL_FUNC(name,nparams,tycheck) {#name,math_##name,nparams,tycheck} static SQRegFunction mathlib_funcs[] = { _DECL_FUNC(sqrt,2,".n"), _DECL_FUNC(sin,2,".n"), _DECL_FUNC(cos,2,".n"), _DECL_FUNC(asin,2,".n"), _DECL_FUNC(acos,2,".n"), _DECL_FUNC(log,2,".n"), _DECL_FUNC(log10,2,".n"), _DECL_FUNC(tan,2,".n"), _DECL_FUNC(atan,2,".n"), _DECL_FUNC(atan2,3,".nn"), _DECL_FUNC(pow,3,".nn"), _DECL_FUNC(floor,2,".n"), _DECL_FUNC(ceil,2,".n"), _DECL_FUNC(exp,2,".n"), #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS _DECL_FUNC(srand,2,".n"), _DECL_FUNC(rand,1,NULL), #endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ _DECL_FUNC(fabs,2,".n"), _DECL_FUNC(abs,2,".n"), {0,0,0,0}, }; #ifndef M_PI #define M_PI (3.14159265358979323846) #endif SQRESULT sqstd_register_mathlib(HSQUIRRELVM v) { SQInteger i=0; while(mathlib_funcs[i].name!=0) { sq_pushstring(v,mathlib_funcs[i].name,-1); sq_newclosure(v,mathlib_funcs[i].f,0); sq_setparamscheck(v,mathlib_funcs[i].nparamscheck,mathlib_funcs[i].typemask); sq_setnativeclosurename(v,-1,mathlib_funcs[i].name); sq_createslot(v,-3); i++; } #ifdef EXPORT_DEFAULT_SQUIRREL_FUNCTIONS sq_pushstring(v,"RAND_MAX",-1); sq_pushinteger(v,RAND_MAX); sq_createslot(v,-3); #endif /* EXPORT_DEFAULT_SQUIRREL_FUNCTIONS */ sq_pushstring(v,"PI",-1); sq_pushfloat(v,(SQFloat)M_PI); sq_createslot(v,-3); return SQ_OK; } openttd-1.5.3/src/3rdparty/os2/0000755000000000000000000000000012627373445014752 5ustar rootrootopenttd-1.5.3/src/3rdparty/os2/getaddrinfo.c0000644000000000000000000002141612627373445017410 0ustar rootroot/* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* An emulation of the RFC 2553 / Posix getaddrinfo resolver interface. */ #if !HAVE_GETADDRINFO /* Need to turn off Posix features in glibc to build this */ #undef _POSIX_C_SOURCE #undef _XOPEN_SOURCE #include "getaddrinfo.h" //#include "compat/inet_pton.h" #include #include #include #include #include #include #include static struct addrinfo * dup_addrinfo (struct addrinfo *info, void *addr, size_t addrlen) { struct addrinfo *ret; ret = malloc (sizeof (struct addrinfo)); if (ret == NULL) return NULL; memcpy (ret, info, sizeof (struct addrinfo)); ret->ai_addr = malloc (addrlen); if (ret->ai_addr == NULL) { free (ret); return NULL; } memcpy (ret->ai_addr, addr, addrlen); ret->ai_addrlen = addrlen; return ret; } int getaddrinfo (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { struct hostent *hp; struct servent *servent; const char *socktype; int port; struct addrinfo hint, result; struct addrinfo *ai, *sai, *eai; char **addrs; if (servname == NULL && nodename == NULL) return EAI_NONAME; memset (&result, 0, sizeof result); /* default for hints */ if (hints == NULL) { memset (&hint, 0, sizeof hint); hint.ai_family = PF_UNSPEC; hints = &hint; } if (servname == NULL) port = 0; else { /* check for tcp or udp sockets only */ if (hints->ai_socktype == SOCK_STREAM) socktype = "tcp"; else if (hints->ai_socktype == SOCK_DGRAM) socktype = "udp"; else return EAI_SERVICE; result.ai_socktype = hints->ai_socktype; /* Note: maintain port in host byte order to make debugging easier */ if (isdigit (*servname)) port = strtol (servname, NULL, 10); else if ((servent = getservbyname (servname, socktype)) != NULL) port = ntohs (servent->s_port); else return EAI_NONAME; } /* if nodename == NULL refer to the local host for a client or any for a server */ if (nodename == NULL) { struct sockaddr_in sin; /* check protocol family is PF_UNSPEC or PF_INET - could try harder for IPv6 but that's more code than I'm prepared to write */ if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET) result.ai_family = AF_INET; else return EAI_FAMILY; sin.sin_family = result.ai_family; sin.sin_port = htons (port); if (hints->ai_flags & AI_PASSIVE) sin.sin_addr.s_addr = htonl (INADDR_ANY); else sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); /* Duplicate result and addr and return */ *res = dup_addrinfo (&result, &sin, sizeof sin); return (*res == NULL) ? EAI_MEMORY : 0; } /* If AI_NUMERIC is specified, use inet_pton to translate numbers and dots notation. */ if (hints->ai_flags & AI_NUMERICHOST) { struct sockaddr_in sin; /* check protocol family is PF_UNSPEC or PF_INET */ if (hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET) result.ai_family = AF_INET; else return EAI_FAMILY; sin.sin_family = result.ai_family; sin.sin_port = htons (port); if (inet_pton(result.ai_family, nodename, &sin.sin_addr)==0) return EAI_NONAME; sin.sin_addr.s_addr = inet_addr (nodename); /* Duplicate result and addr and return */ *res = dup_addrinfo (&result, &sin, sizeof sin); return (*res == NULL) ? EAI_MEMORY : 0; } #if HAVE_H_ERRNO h_errno = 0; #endif errno = 0; hp = gethostbyname(nodename); if (hp == NULL) { #ifdef EAI_SYSTEM if (errno != 0) { return EAI_SYSTEM; } #endif switch (h_errno) { case HOST_NOT_FOUND: return EAI_NODATA; case NO_DATA: return EAI_NODATA; #if defined(NO_ADDRESS) && NO_ADDRESS != NO_DATA case NO_ADDRESS: return EAI_NODATA; #endif case NO_RECOVERY: return EAI_FAIL; case TRY_AGAIN: return EAI_AGAIN; default: return EAI_FAIL; } return EAI_FAIL; } /* Check that the address family is acceptable. */ switch (hp->h_addrtype) { case AF_INET: if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET)) return EAI_FAMILY; break; #ifndef __OS2__ case AF_INET6: if (!(hints->ai_family == PF_UNSPEC || hints->ai_family == PF_INET6)) return EAI_FAMILY; break; #endif default: return EAI_FAMILY; } /* For each element pointed to by hp, create an element in the result linked list. */ sai = eai = NULL; for (addrs = hp->h_addr_list; *addrs != NULL; addrs++) { struct sockaddr sa; size_t addrlen; if (hp->h_length < 1) continue; sa.sa_family = hp->h_addrtype; switch (hp->h_addrtype) { case AF_INET: ((struct sockaddr_in *) &sa)->sin_port = htons (port); memcpy (&((struct sockaddr_in *) &sa)->sin_addr, *addrs, hp->h_length); addrlen = sizeof (struct sockaddr_in); break; #ifndef __OS2__ case AF_INET6: #if SIN6_LEN ((struct sockaddr_in6 *) &sa)->sin6_len = hp->h_length; #endif ((struct sockaddr_in6 *) &sa)->sin6_port = htons (port); memcpy (&((struct sockaddr_in6 *) &sa)->sin6_addr, *addrs, hp->h_length); addrlen = sizeof (struct sockaddr_in6); break; #endif default: continue; } result.ai_family = hp->h_addrtype; ai = dup_addrinfo (&result, &sa, addrlen); if (ai == NULL) { freeaddrinfo (sai); return EAI_MEMORY; } if (sai == NULL) sai = ai; else eai->ai_next = ai; eai = ai; } if (sai == NULL) { return EAI_NODATA; } if (hints->ai_flags & AI_CANONNAME) { sai->ai_canonname = malloc (strlen (hp->h_name) + 1); if (sai->ai_canonname == NULL) { freeaddrinfo (sai); return EAI_MEMORY; } strcpy (sai->ai_canonname, hp->h_name); } *res = sai; return 0; } void freeaddrinfo (struct addrinfo *ai) { struct addrinfo *next; while (ai != NULL) { next = ai->ai_next; if (ai->ai_canonname != NULL) free (ai->ai_canonname); if (ai->ai_addr != NULL) free (ai->ai_addr); free (ai); ai = next; } } const char * gai_strerror (int ecode) { static const char *eai_descr[] = { "no error", "address family for nodename not supported", /* EAI_ADDRFAMILY */ "temporary failure in name resolution", /* EAI_AGAIN */ "invalid value for ai_flags", /* EAI_BADFLAGS */ "non-recoverable failure in name resolution", /* EAI_FAIL */ "ai_family not supported", /* EAI_FAMILY */ "memory allocation failure", /* EAI_MEMORY */ "no address associated with nodename", /* EAI_NODATA */ "nodename nor servname provided, or not known", /* EAI_NONAME */ "servname not supported for ai_socktype", /* EAI_SERVICE */ "ai_socktype not supported", /* EAI_SOCKTYPE */ "system error returned in errno", /* EAI_SYSTEM */ "argument buffer overflow", /* EAI_OVERFLOW */ }; if (ecode < 0 || ecode > (int) (sizeof eai_descr/ sizeof eai_descr[0])) return "unknown error"; return eai_descr[ecode]; } #endif /* HAVE_GETADDRINFO */ openttd-1.5.3/src/3rdparty/os2/getaddrinfo.h0000644000000000000000000000736512627373445017424 0ustar rootroot#ifndef _getaddrinfo_h #define _getaddrinfo_h /* * Shamelessly duplicated from the fetchmail public sources * for use by the Squid Project under GNU Public License. * * Update/Maintenance History: * * 15-Aug-2007 : Copied from fetchmail 6.3.8 * - added protection around libray headers * * 16-Aug-2007 : Altered configure checks * Un-hacked slightly to use system gethostbyname() * * Original License and code follows. */ /* * This file is part of libESMTP, a library for submission of RFC 2822 * formatted electronic mail messages using the SMTP protocol described * in RFC 2821. * * Copyright (C) 2001,2002 Brian Stafford * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Structure and prototypes taken from RFC 2553 */ /* SG 23/09/2007: On Windows the following definitions are already available, may be that this could be needed on some other platform */ typedef int socklen_t; struct addrinfo { int ai_flags; /* AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST */ int ai_family; /* PF_xxx */ int ai_socktype; /* SOCK_xxx */ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ socklen_t ai_addrlen; /* length of ai_addr */ char *ai_canonname; /* canonical name for nodename */ struct sockaddr *ai_addr; /* binary address */ struct addrinfo *ai_next; /* next structure in linked list */ }; /* Supposed to be defined in */ #define AI_ADDRCONFIG 0 #define AI_PASSIVE 1 /* Socket address is intended for `bind'. */ #define AI_CANONNAME 2 /* Request for canonical name. */ #define AI_NUMERICHOST 4 /* Don't use name resolution. */ /* Supposed to be defined in */ #define EAI_ADDRFAMILY 1 /* address family for nodename not supported */ #define EAI_AGAIN 2 /* temporary failure in name resolution */ #define EAI_BADFLAGS 3 /* invalid value for ai_flags */ #define EAI_FAIL 4 /* non-recoverable failure in name resolution */ #define EAI_FAMILY 5 /* ai_family not supported */ #define EAI_MEMORY 6 /* memory allocation failure */ #define EAI_NODATA 7 /* no address associated with nodename */ #define EAI_NONAME 8 /* nodename nor servname provided, or not known */ #define EAI_SERVICE 9 /* servname not supported for ai_socktype */ #define EAI_SOCKTYPE 10 /* ai_socktype not supported */ #ifndef EAI_SYSTEM /* Not defined on mingw32. */ #define EAI_SYSTEM 11 /* System error returned in `errno'. */ #endif #ifndef EAI_OVERFLOW /* Not defined on mingw32. */ #define EAI_OVERFLOW 12 /* Argument buffer overflow. */ #endif #ifdef __cplusplus extern "C" { #endif /* RFC 2553 / Posix resolver */ int getaddrinfo (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res); /* Free addrinfo structure and associated storage */ void freeaddrinfo (struct addrinfo *ai); /* Convert error return from getaddrinfo() to string */ const char *gai_strerror (int code); #ifdef __cplusplus } #endif #endif /* _getaddrinfo_h */ openttd-1.5.3/src/3rdparty/os2/getnameinfo.h0000644000000000000000000000137712627373445017427 0ustar rootroot#ifndef _getnameinfo_h #define _getnameinfo_h /* * Reconstructed from KAME getnameinfo.c (in lib/) */ /* getnameinfo flags */ #define NI_NOFQDN 0x0001 #define NI_NUMERICHOST 0x0002 /* return numeric form of address */ #define NI_NAMEREQD 0x0004 /* request DNS name */ #define NI_NUMERICSERV 0x0008 #define NI_DGRAM 0x0010 #ifdef __cplusplus extern "C" { #endif /* RFC 2553 / Posix resolver */ int getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags ); #ifdef __cplusplus } #endif #endif /* _getnameinfo_h */ openttd-1.5.3/src/3rdparty/os2/getnameinfo.c0000644000000000000000000002614212627373445017417 0ustar rootroot/* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Issues to be discussed: * - RFC2553 says that we should raise error on short buffer. X/Open says * we need to truncate the result. We obey RFC2553 (and X/Open should be * modified). ipngwg rough consensus seems to follow RFC2553. RFC3493 says * nothing about it, but defines a new error code EAI_OVERFLOW which seems * to be intended the code for this case. * - What is "local" in NI_NOFQDN? (see comments in the code) * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if * sin6_scope_id is filled - standardization status? * - what should we do if we should do getservbyport("sctp")? */ /* * Considerations about thread-safeness * The code in this file is thread-safe, and so the thread-safeness of * getnameinfo() depends on the property of backend functions. * - getservbyport() is not thread safe for most systems we are targeting. * - getipnodebyaddr() is thread safe. However, many resolver libraries * used in the function are not thread safe. * - gethostbyaddr() is usually not thread safe. */ #if !HAVE_GETNAMEINFO #include #include #include #include #include #include #include #include #include #include #include #include "getaddrinfo.h" #include "getnameinfo.h" static const struct afd { int a_af; int a_addrlen; int a_socklen; int a_off; int a_portoff; } afdl [] = { #if INET6 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), offsetof(struct sockaddr_in6, sin6_port)}, #endif {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), offsetof(struct sockaddr_in, sin_port)}, {0, 0, 0, 0, 0}, }; #if INET6 static int ip6_parsenumeric __P((const struct sockaddr *, const char *, char *, size_t, int)); static int ip6_sa2str __P((const struct sockaddr_in6 *, char *, size_t, int)); #endif int getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) const struct sockaddr *sa; socklen_t salen; char *host; size_t hostlen; char *serv; size_t servlen; int flags; { const struct afd *afd; struct servent *sp; struct hostent *hp; unsigned short port; int family, i; const char *addr; uint32_t v4a; char numserv[512]; if (sa == NULL) return EAI_FAIL; #if HAVE_SA_LEN /*XXX*/ if (sa->sa_len != salen) return EAI_FAIL; #endif family = sa->sa_family; for (i = 0; afdl[i].a_af; i++) if (afdl[i].a_af == family) { afd = &afdl[i]; goto found; } return EAI_FAMILY; found: if (salen != afd->a_socklen) return EAI_FAIL; /* network byte order */ memcpy(&port, (const char *)sa + afd->a_portoff, sizeof(port)); addr = (const char *)sa + afd->a_off; if (serv == NULL || servlen == 0) { /* * do nothing in this case. * in case you are wondering if "&&" is more correct than * "||" here: RFC3493 says that serv == NULL OR servlen == 0 * means that the caller does not want the result. */ } else { if (flags & NI_NUMERICSERV) sp = NULL; else { sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); } if (sp) { if (strlen(sp->s_name) + 1 > servlen) return EAI_OVERFLOW; strncpy(serv, sp->s_name, servlen); } else { snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); if (strlen(numserv) + 1 > servlen) return EAI_OVERFLOW; strncpy(serv, numserv, servlen); } } switch (sa->sa_family) { case AF_INET: v4a = (uint32_t) ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr); if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) flags |= NI_NUMERICHOST; v4a >>= IN_CLASSA_NSHIFT; if (v4a == 0) flags |= NI_NUMERICHOST; break; #if INET6 case AF_INET6: { const struct sockaddr_in6 *sin6; sin6 = (const struct sockaddr_in6 *)sa; switch (sin6->sin6_addr.s6_addr[0]) { case 0x00: if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) ; else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) ; else flags |= NI_NUMERICHOST; break; default: if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) flags |= NI_NUMERICHOST; else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) flags |= NI_NUMERICHOST; break; } } break; #endif } if (host == NULL || hostlen == 0) { /* * do nothing in this case. * in case you are wondering if "&&" is more correct than * "||" here: RFC3493 says that host == NULL or hostlen == 0 * means that the caller does not want the result. */ } else if (flags & NI_NUMERICHOST) { /* NUMERICHOST and NAMEREQD conflicts with each other */ if (flags & NI_NAMEREQD) return EAI_NONAME; goto numeric; } else { #if USE_GETIPNODEBY int h_error = 0; hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error); #else hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af); #if 0 // getnameinfo.c:161:9: error: variable 'h_error' set but not used #if HAVE_H_ERRNO h_error = h_errno; #else h_error = EINVAL; #endif #endif /* 0 */ #endif if (hp) { #if 0 if (flags & NI_NOFQDN) { /* * According to RFC3493 section 6.2, NI_NOFQDN * means "node name portion of the FQDN shall * be returned for local hosts." The following * code tries to implement it by returning the * first label (the part before the first * period) of the FQDN. However, it is not * clear if this always makes sense, since the * given address may be outside of "local * hosts." Due to the unclear description, we * disable the code in this implementation. */ char *p; p = strchr(hp->h_name, '.'); if (p) *p = '\0'; } #endif if (strlen(hp->h_name) + 1 > hostlen) { #if USE_GETIPNODEBY freehostent(hp); #endif return EAI_OVERFLOW; } strncpy(host, hp->h_name, hostlen); #if USE_GETIPNODEBY freehostent(hp); #endif } else { if (flags & NI_NAMEREQD) return EAI_NONAME; numeric: switch (afd->a_af) { #if INET6 case AF_INET6: { int error; if ((error = ip6_parsenumeric(sa, addr, host, hostlen, flags)) != 0) return(error); break; } #endif default: if (inet_ntop(afd->a_af, addr, host, hostlen) == NULL) return EAI_SYSTEM; break; } } } return(0); } #if INET6 static int ip6_parsenumeric(sa, addr, host, hostlen, flags) const struct sockaddr *sa; const char *addr; char *host; size_t hostlen; int flags; { int numaddrlen; char numaddr[512]; if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL) return EAI_SYSTEM; numaddrlen = strlen(numaddr); if (numaddrlen + 1 > hostlen) /* don't forget terminator */ return EAI_OVERFLOW; strncpy(host, numaddr, hostlen); if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) { char zonebuf[SQUIDHOSTNAMELEN]; int zonelen; zonelen = ip6_sa2str( (const struct sockaddr_in6 *)(const void *)sa, zonebuf, sizeof(zonebuf), flags); if (zonelen < 0) return EAI_OVERFLOW; if (zonelen + 1 + numaddrlen + 1 > hostlen) return EAI_OVERFLOW; /* construct */ memcpy(host + numaddrlen + 1, zonebuf, (size_t)zonelen); host[numaddrlen] = SCOPE_DELIMITER; host[numaddrlen + 1 + zonelen] = '\0'; } return 0; } /* ARGSUSED */ static int ip6_sa2str(sa6, buf, bufsiz, flags) const struct sockaddr_in6 *sa6; char *buf; size_t bufsiz; int flags; { unsigned int ifindex; const struct in6_addr *a6; int n; ifindex = (unsigned int)sa6->sin6_scope_id; a6 = &sa6->sin6_addr; #if NI_NUMERICSCOPE if ((flags & NI_NUMERICSCOPE) != 0) { n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); if (n < 0 || n >= bufsiz) return -1; else return n; } #endif /* if_indextoname() does not take buffer size. not a good api... */ if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) || IN6_IS_ADDR_MC_NODELOCAL(a6)) && bufsiz >= IF_NAMESIZE) { char *p = if_indextoname(ifindex, buf); if (p) return (strlen(p)); } /* last resort */ n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id); if (n < 0 || n >= bufsiz) return -1; else return n; } #endif /* INET6 */ #endif openttd-1.5.3/src/3rdparty/README.licensing0000644000000000000000000000030212627373445017074 0ustar rootrootThe files in this directory are not licensed under the same terms as the rest of OpenTTD. Licensing details can be found in OpenTTD's readme.txt and in this directory or subdirectories as well. openttd-1.5.3/src/transparency.h0000644000000000000000000000772612627373434015373 0ustar rootroot/* $Id: transparency.h 22506 2011-05-28 09:46:37Z frosch $ */ /* * 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 transparency.h Functions related to transparency. */ #ifndef TRANSPARENCY_H #define TRANSPARENCY_H #include "gfx_func.h" #include "openttd.h" #include "core/bitmath_func.hpp" /** * Transparency option bits: which position in _transparency_opt stands for which transparency. * If you change the order, change the order of the ShowTransparencyToolbar() stuff in transparency_gui.cpp too. * If you add or remove an option don't forget to change the transparency 'hot keys' in main_gui.cpp. */ enum TransparencyOption { TO_SIGNS = 0, ///< signs TO_TREES, ///< trees TO_HOUSES, ///< town buildings TO_INDUSTRIES, ///< industries TO_BUILDINGS, ///< company buildings - depots, stations, HQ, ... TO_BRIDGES, ///< bridges TO_STRUCTURES, ///< other objects such as transmitters and lighthouses TO_CATENARY, ///< catenary TO_LOADING, ///< loading indicators TO_END, TO_INVALID, ///< Invalid transparency option }; typedef uint TransparencyOptionBits; ///< transparency option bits extern TransparencyOptionBits _transparency_opt; extern TransparencyOptionBits _transparency_lock; extern TransparencyOptionBits _invisibility_opt; extern byte _display_opt; /** * Check if the transparency option bit is set * and if we aren't in the game menu (there's never transparency) * * @param to the structure which transparency option is ask for */ static inline bool IsTransparencySet(TransparencyOption to) { return (HasBit(_transparency_opt, to) && _game_mode != GM_MENU); } /** * Check if the invisibility option bit is set * and if we aren't in the game menu (there's never transparency) * * @param to the structure which invisibility option is ask for */ static inline bool IsInvisibilitySet(TransparencyOption to) { return (HasBit(_transparency_opt & _invisibility_opt, to) && _game_mode != GM_MENU); } /** * Toggle the transparency option bit * * @param to the transparency option to be toggled */ static inline void ToggleTransparency(TransparencyOption to) { ToggleBit(_transparency_opt, to); } /** * Toggle the invisibility option bit * * @param to the structure which invisibility option is toggle */ static inline void ToggleInvisibility(TransparencyOption to) { ToggleBit(_invisibility_opt, to); } /** * Toggles between invisible and solid state. * If object is transparent, then it is made invisible. * Used by the keyboard shortcuts. * * @param to the object type which invisibility option to toggle */ static inline void ToggleInvisibilityWithTransparency(TransparencyOption to) { if (IsInvisibilitySet(to)) { ClrBit(_invisibility_opt, to); ClrBit(_transparency_opt, to); } else { SetBit(_invisibility_opt, to); SetBit(_transparency_opt, to); } } /** * Toggle the transparency lock bit * * @param to the transparency option to be locked or unlocked */ static inline void ToggleTransparencyLock(TransparencyOption to) { ToggleBit(_transparency_lock, to); } /** Set or clear all non-locked transparency options */ static inline void ResetRestoreAllTransparency() { /* if none of the non-locked options are set */ if ((_transparency_opt & ~_transparency_lock) == 0) { /* set all non-locked options */ _transparency_opt |= GB(~_transparency_lock, 0, TO_END); } else { /* clear all non-locked options */ _transparency_opt &= _transparency_lock; } MarkWholeScreenDirty(); } #endif /* TRANSPARENCY_H */ openttd-1.5.3/src/main_gui.cpp0000644000000000000000000004502012627373442014771 0ustar rootroot/* $Id: main_gui.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 main_gui.cpp Handling of the main viewport. */ #include "stdafx.h" #include "currency.h" #include "spritecache.h" #include "window_gui.h" #include "window_func.h" #include "textbuf_gui.h" #include "viewport_func.h" #include "command_func.h" #include "console_gui.h" #include "progress.h" #include "transparency_gui.h" #include "map_func.h" #include "sound_func.h" #include "transparency.h" #include "strings_func.h" #include "zoom_func.h" #include "company_base.h" #include "company_func.h" #include "toolbar_gui.h" #include "statusbar_gui.h" #include "linkgraph/linkgraph_gui.h" #include "tilehighlight_func.h" #include "hotkeys.h" #include "saveload/saveload.h" #include "widgets/main_widget.h" #include "network/network.h" #include "network/network_func.h" #include "network/network_gui.h" #include "network/network_base.h" #include "table/sprites.h" #include "table/strings.h" #include "safeguards.h" static int _rename_id = 1; static int _rename_what = -1; void CcGiveMoney(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { #ifdef ENABLE_NETWORK if (result.Failed() || !_settings_game.economy.give_money) return; /* Inform the company of the action of one of its clients (controllers). */ char msg[64]; SetDParam(0, p2); GetString(msg, STR_COMPANY_NAME, lastof(msg)); if (!_network_server) { NetworkClientSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, p1); } else { NetworkServerSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, CLIENT_ID_SERVER, p1); } #endif /* ENABLE_NETWORK */ } void HandleOnEditText(const char *str) { switch (_rename_what) { #ifdef ENABLE_NETWORK case 3: { // Give money, you can only give money in excess of loan const Company *c = Company::GetIfValid(_local_company); if (c == NULL) break; Money money = min(c->money - c->current_loan, (Money)(atoi(str) / _currency->rate)); uint32 money_c = Clamp(ClampToI32(money), 0, 20000000); // Clamp between 20 million and 0 /* Give 'id' the money, and subtract it from ourself */ DoCommandP(0, money_c, _rename_id, CMD_GIVE_MONEY | CMD_MSG(STR_ERROR_INSUFFICIENT_FUNDS), CcGiveMoney, str); break; } #endif /* ENABLE_NETWORK */ default: NOT_REACHED(); } _rename_id = _rename_what = -1; } /** * This code is shared for the majority of the pushbuttons. * Handles e.g. the pressing of a button (to build things), playing of click sound and sets certain parameters * * @param w Window which called the function * @param widget ID of the widget (=button) that called this function * @param cursor How should the cursor image change? E.g. cursor with depot image in it * @param mode Tile highlighting mode, e.g. drawing a rectangle or a dot on the ground * @return true if the button is clicked, false if it's unclicked */ bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyle mode) { if (w->IsWidgetDisabled(widget)) return false; if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); w->SetDirty(); if (w->IsWidgetLowered(widget)) { ResetObjectToPlace(); return false; } SetObjectToPlace(cursor, PAL_NONE, mode, w->window_class, w->window_number); w->LowerWidget(widget); return true; } void CcPlaySound10(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_12_EXPLOSION, tile); } #ifdef ENABLE_NETWORK void ShowNetworkGiveMoneyWindow(CompanyID company) { _rename_id = company; _rename_what = 3; ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, NULL, CS_NUMERAL, QSF_NONE); } #endif /* ENABLE_NETWORK */ /** * Zooms a viewport in a window in or out. * @param how Zooming direction. * @param w Window owning the viewport. * @return Returns \c true if zooming step could be done, \c false if further zooming is not possible. * @note No button handling or what so ever is done. */ bool DoZoomInOutWindow(ZoomStateChange how, Window *w) { ViewPort *vp; assert(w != NULL); vp = w->viewport; switch (how) { case ZOOM_NONE: /* On initialisation of the viewport we don't do anything. */ break; case ZOOM_IN: if (vp->zoom <= _settings_client.gui.zoom_min) return false; vp->zoom = (ZoomLevel)((int)vp->zoom - 1); vp->virtual_width >>= 1; vp->virtual_height >>= 1; w->viewport->scrollpos_x += vp->virtual_width >> 1; w->viewport->scrollpos_y += vp->virtual_height >> 1; w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x; w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y; w->viewport->follow_vehicle = INVALID_VEHICLE; break; case ZOOM_OUT: if (vp->zoom >= _settings_client.gui.zoom_max) return false; vp->zoom = (ZoomLevel)((int)vp->zoom + 1); w->viewport->scrollpos_x -= vp->virtual_width >> 1; w->viewport->scrollpos_y -= vp->virtual_height >> 1; w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x; w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y; vp->virtual_width <<= 1; vp->virtual_height <<= 1; w->viewport->follow_vehicle = INVALID_VEHICLE; break; } if (vp != NULL) { // the vp can be null when how == ZOOM_NONE vp->virtual_left = w->viewport->scrollpos_x; vp->virtual_top = w->viewport->scrollpos_y; } /* Update the windows that have zoom-buttons to perhaps disable their buttons */ w->InvalidateData(); return true; } void ZoomInOrOutToCursorWindow(bool in, Window *w) { assert(w != NULL); if (_game_mode != GM_MENU) { ViewPort *vp = w->viewport; if ((in && vp->zoom <= _settings_client.gui.zoom_min) || (!in && vp->zoom >= _settings_client.gui.zoom_max)) return; Point pt = GetTileZoomCenterWindow(in, w); if (pt.x != -1) { ScrollWindowTo(pt.x, pt.y, -1, w, true); DoZoomInOutWindow(in ? ZOOM_IN : ZOOM_OUT, w); } } } static const struct NWidgetPart _nested_main_window_widgets[] = { NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_M_VIEWPORT), SetResize(1, 1), }; enum { GHK_QUIT, GHK_ABANDON, GHK_CONSOLE, GHK_BOUNDING_BOXES, GHK_DIRTY_BLOCKS, GHK_CENTER, GHK_CENTER_ZOOM, GHK_RESET_OBJECT_TO_PLACE, GHK_DELETE_WINDOWS, GHK_DELETE_NONVITAL_WINDOWS, GHK_REFRESH_SCREEN, GHK_CRASH, GHK_MONEY, GHK_UPDATE_COORDS, GHK_TOGGLE_TRANSPARENCY, GHK_TOGGLE_INVISIBILITY = GHK_TOGGLE_TRANSPARENCY + 9, GHK_TRANSPARENCY_TOOLBAR = GHK_TOGGLE_INVISIBILITY + 8, GHK_TRANSPARANCY, GHK_CHAT, GHK_CHAT_ALL, GHK_CHAT_COMPANY, GHK_CHAT_SERVER, }; struct MainWindow : Window { uint refresh; static const uint LINKGRAPH_REFRESH_PERIOD = 0xff; static const uint LINKGRAPH_DELAY = 0xf; MainWindow(WindowDesc *desc) : Window(desc) { this->InitNested(0); CLRBITS(this->flags, WF_WHITE_BORDER); ResizeWindow(this, _screen.width, _screen.height); NWidgetViewport *nvp = this->GetWidget(WID_M_VIEWPORT); nvp->InitializeViewport(this, TileXY(32, 32), ZOOM_LVL_VIEWPORT); this->viewport->overlay = new LinkGraphOverlay(this, WID_M_VIEWPORT, 0, 0, 3); this->refresh = LINKGRAPH_DELAY; } virtual void OnTick() { if (--this->refresh > 0) return; this->refresh = LINKGRAPH_REFRESH_PERIOD; if (this->viewport->overlay->GetCargoMask() == 0 || this->viewport->overlay->GetCompanyMask() == 0) { return; } this->viewport->overlay->RebuildCache(); this->GetWidget(WID_M_VIEWPORT)->SetDirty(this); } virtual void OnPaint() { this->DrawWidgets(); if (_game_mode == GM_MENU) { static const SpriteID title_sprites[] = {SPR_OTTD_O, SPR_OTTD_P, SPR_OTTD_E, SPR_OTTD_N, SPR_OTTD_T, SPR_OTTD_T, SPR_OTTD_D}; static const uint LETTER_SPACING = 10; int name_width = (lengthof(title_sprites) - 1) * LETTER_SPACING; for (uint i = 0; i < lengthof(title_sprites); i++) { name_width += GetSpriteSize(title_sprites[i]).width; } int off_x = (this->width - name_width) / 2; for (uint i = 0; i < lengthof(title_sprites); i++) { DrawSprite(title_sprites[i], PAL_NONE, off_x, 50); off_x += GetSpriteSize(title_sprites[i]).width + LETTER_SPACING; } } } virtual EventState OnHotkey(int hotkey) { if (hotkey == GHK_QUIT) { HandleExitGameRequest(); return ES_HANDLED; } /* Disable all key shortcuts, except quit shortcuts when * generating the world, otherwise they create threading * problem during the generating, resulting in random * assertions that are hard to trigger and debug */ if (HasModalProgress()) return ES_NOT_HANDLED; switch (hotkey) { case GHK_ABANDON: /* No point returning from the main menu to itself */ if (_game_mode == GM_MENU) return ES_HANDLED; if (_settings_client.gui.autosave_on_exit) { DoExitSave(); _switch_mode = SM_MENU; } else { AskExitToGameMenu(); } return ES_HANDLED; case GHK_CONSOLE: IConsoleSwitch(); return ES_HANDLED; case GHK_BOUNDING_BOXES: ToggleBoundingBoxes(); return ES_HANDLED; case GHK_DIRTY_BLOCKS: ToggleDirtyBlocks(); return ES_HANDLED; } if (_game_mode == GM_MENU) return ES_NOT_HANDLED; switch (hotkey) { case GHK_CENTER: case GHK_CENTER_ZOOM: { Point pt = GetTileBelowCursor(); if (pt.x != -1) { bool instant = (hotkey == GHK_CENTER_ZOOM && this->viewport->zoom != _settings_client.gui.zoom_min); if (hotkey == GHK_CENTER_ZOOM) MaxZoomInOut(ZOOM_IN, this); ScrollMainWindowTo(pt.x, pt.y, -1, instant); } break; } case GHK_RESET_OBJECT_TO_PLACE: ResetObjectToPlace(); break; case GHK_DELETE_WINDOWS: DeleteNonVitalWindows(); break; case GHK_DELETE_NONVITAL_WINDOWS: DeleteAllNonVitalWindows(); break; case GHK_REFRESH_SCREEN: MarkWholeScreenDirty(); break; case GHK_CRASH: // Crash the game *(volatile byte *)0 = 0; break; case GHK_MONEY: // Gimme money /* You can only cheat for money in single player. */ if (!_networking) DoCommandP(0, 10000000, 0, CMD_MONEY_CHEAT); break; case GHK_UPDATE_COORDS: // Update the coordinates of all station signs UpdateAllVirtCoords(); break; case GHK_TOGGLE_TRANSPARENCY: case GHK_TOGGLE_TRANSPARENCY + 1: case GHK_TOGGLE_TRANSPARENCY + 2: case GHK_TOGGLE_TRANSPARENCY + 3: case GHK_TOGGLE_TRANSPARENCY + 4: case GHK_TOGGLE_TRANSPARENCY + 5: case GHK_TOGGLE_TRANSPARENCY + 6: case GHK_TOGGLE_TRANSPARENCY + 7: case GHK_TOGGLE_TRANSPARENCY + 8: /* Transparency toggle hot keys */ ToggleTransparency((TransparencyOption)(hotkey - GHK_TOGGLE_TRANSPARENCY)); MarkWholeScreenDirty(); break; case GHK_TOGGLE_INVISIBILITY: case GHK_TOGGLE_INVISIBILITY + 1: case GHK_TOGGLE_INVISIBILITY + 2: case GHK_TOGGLE_INVISIBILITY + 3: case GHK_TOGGLE_INVISIBILITY + 4: case GHK_TOGGLE_INVISIBILITY + 5: case GHK_TOGGLE_INVISIBILITY + 6: case GHK_TOGGLE_INVISIBILITY + 7: /* Invisibility toggle hot keys */ ToggleInvisibilityWithTransparency((TransparencyOption)(hotkey - GHK_TOGGLE_INVISIBILITY)); MarkWholeScreenDirty(); break; case GHK_TRANSPARENCY_TOOLBAR: ShowTransparencyToolbar(); break; case GHK_TRANSPARANCY: ResetRestoreAllTransparency(); break; #ifdef ENABLE_NETWORK case GHK_CHAT: // smart chat; send to team if any, otherwise to all if (_networking) { const NetworkClientInfo *cio = NetworkClientInfo::GetByClientID(_network_own_client_id); if (cio == NULL) break; ShowNetworkChatQueryWindow(NetworkClientPreferTeamChat(cio) ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas); } break; case GHK_CHAT_ALL: // send text message to all clients if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0); break; case GHK_CHAT_COMPANY: // send text to all team mates if (_networking) { const NetworkClientInfo *cio = NetworkClientInfo::GetByClientID(_network_own_client_id); if (cio == NULL) break; ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas); } break; case GHK_CHAT_SERVER: // send text to the server if (_networking && !_network_server) { ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, CLIENT_ID_SERVER); } break; #endif default: return ES_NOT_HANDLED; } return ES_HANDLED; } virtual void OnScroll(Point delta) { this->viewport->scrollpos_x += ScaleByZoom(delta.x, this->viewport->zoom); this->viewport->scrollpos_y += ScaleByZoom(delta.y, this->viewport->zoom); this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x; this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; this->refresh = LINKGRAPH_DELAY; } virtual void OnMouseWheel(int wheel) { if (_settings_client.gui.scrollwheel_scrolling == 0) { ZoomInOrOutToCursorWindow(wheel < 0, this); } } virtual void OnResize() { if (this->viewport != NULL) { NWidgetViewport *nvp = this->GetWidget(WID_M_VIEWPORT); nvp->UpdateViewportCoordinates(this); this->refresh = LINKGRAPH_DELAY; } } /** * 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; /* Forward the message to the appropriate toolbar (ingame or scenario editor) */ InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data, true); } static HotkeyList hotkeys; }; const uint16 _ghk_quit_keys[] = {'Q' | WKC_CTRL, 'Q' | WKC_META, 0}; const uint16 _ghk_abandon_keys[] = {'W' | WKC_CTRL, 'W' | WKC_META, 0}; const uint16 _ghk_chat_keys[] = {WKC_RETURN, 'T', 0}; const uint16 _ghk_chat_all_keys[] = {WKC_SHIFT | WKC_RETURN, WKC_SHIFT | 'T', 0}; const uint16 _ghk_chat_company_keys[] = {WKC_CTRL | WKC_RETURN, WKC_CTRL | 'T', 0}; const uint16 _ghk_chat_server_keys[] = {WKC_CTRL | WKC_SHIFT | WKC_RETURN, WKC_CTRL | WKC_SHIFT | 'T', 0}; static Hotkey global_hotkeys[] = { Hotkey(_ghk_quit_keys, "quit", GHK_QUIT), Hotkey(_ghk_abandon_keys, "abandon", GHK_ABANDON), Hotkey(WKC_BACKQUOTE, "console", GHK_CONSOLE), Hotkey('B' | WKC_CTRL, "bounding_boxes", GHK_BOUNDING_BOXES), Hotkey('I' | WKC_CTRL, "dirty_blocks", GHK_DIRTY_BLOCKS), Hotkey('C', "center", GHK_CENTER), Hotkey('Z', "center_zoom", GHK_CENTER_ZOOM), Hotkey(WKC_ESC, "reset_object_to_place", GHK_RESET_OBJECT_TO_PLACE), Hotkey(WKC_DELETE, "delete_windows", GHK_DELETE_WINDOWS), Hotkey(WKC_DELETE | WKC_SHIFT, "delete_all_windows", GHK_DELETE_NONVITAL_WINDOWS), Hotkey('R' | WKC_CTRL, "refresh_screen", GHK_REFRESH_SCREEN), #if defined(_DEBUG) Hotkey('0' | WKC_ALT, "crash_game", GHK_CRASH), Hotkey('1' | WKC_ALT, "money", GHK_MONEY), Hotkey('2' | WKC_ALT, "update_coordinates", GHK_UPDATE_COORDS), #endif Hotkey('1' | WKC_CTRL, "transparency_signs", GHK_TOGGLE_TRANSPARENCY), Hotkey('2' | WKC_CTRL, "transparency_trees", GHK_TOGGLE_TRANSPARENCY + 1), Hotkey('3' | WKC_CTRL, "transparency_houses", GHK_TOGGLE_TRANSPARENCY + 2), Hotkey('4' | WKC_CTRL, "transparency_industries", GHK_TOGGLE_TRANSPARENCY + 3), Hotkey('5' | WKC_CTRL, "transparency_buildings", GHK_TOGGLE_TRANSPARENCY + 4), Hotkey('6' | WKC_CTRL, "transparency_bridges", GHK_TOGGLE_TRANSPARENCY + 5), Hotkey('7' | WKC_CTRL, "transparency_structures", GHK_TOGGLE_TRANSPARENCY + 6), Hotkey('8' | WKC_CTRL, "transparency_catenary", GHK_TOGGLE_TRANSPARENCY + 7), Hotkey('9' | WKC_CTRL, "transparency_loading", GHK_TOGGLE_TRANSPARENCY + 8), Hotkey('1' | WKC_CTRL | WKC_SHIFT, "invisibility_signs", GHK_TOGGLE_INVISIBILITY), Hotkey('2' | WKC_CTRL | WKC_SHIFT, "invisibility_trees", GHK_TOGGLE_INVISIBILITY + 1), Hotkey('3' | WKC_CTRL | WKC_SHIFT, "invisibility_houses", GHK_TOGGLE_INVISIBILITY + 2), Hotkey('4' | WKC_CTRL | WKC_SHIFT, "invisibility_industries", GHK_TOGGLE_INVISIBILITY + 3), Hotkey('5' | WKC_CTRL | WKC_SHIFT, "invisibility_buildings", GHK_TOGGLE_INVISIBILITY + 4), Hotkey('6' | WKC_CTRL | WKC_SHIFT, "invisibility_bridges", GHK_TOGGLE_INVISIBILITY + 5), Hotkey('7' | WKC_CTRL | WKC_SHIFT, "invisibility_structures", GHK_TOGGLE_INVISIBILITY + 6), Hotkey('8' | WKC_CTRL | WKC_SHIFT, "invisibility_catenary", GHK_TOGGLE_INVISIBILITY + 7), Hotkey('X' | WKC_CTRL, "transparency_toolbar", GHK_TRANSPARENCY_TOOLBAR), Hotkey('X', "toggle_transparency", GHK_TRANSPARANCY), #ifdef ENABLE_NETWORK Hotkey(_ghk_chat_keys, "chat", GHK_CHAT), Hotkey(_ghk_chat_all_keys, "chat_all", GHK_CHAT_ALL), Hotkey(_ghk_chat_company_keys, "chat_company", GHK_CHAT_COMPANY), Hotkey(_ghk_chat_server_keys, "chat_server", GHK_CHAT_SERVER), #endif HOTKEY_LIST_END }; HotkeyList MainWindow::hotkeys("global", global_hotkeys); static WindowDesc _main_window_desc( WDP_MANUAL, NULL, 0, 0, WC_MAIN_WINDOW, WC_NONE, 0, _nested_main_window_widgets, lengthof(_nested_main_window_widgets), &MainWindow::hotkeys ); /** * Does the given keycode match one of the keycodes bound to 'quit game'? * @param keycode The keycode that was pressed by the user. * @return True iff the keycode matches one of the hotkeys for 'quit'. */ bool IsQuitKey(uint16 keycode) { int num = MainWindow::hotkeys.CheckMatch(keycode); return num == GHK_QUIT; } void ShowSelectGameWindow(); /** * Initialise the default colours (remaps and the likes), and load the main windows. */ void SetupColoursAndInitialWindow() { for (uint i = 0; i != 16; i++) { const byte *b = GetNonSprite(PALETTE_RECOLOUR_START + i, ST_RECOLOUR); assert(b); memcpy(_colour_gradient[i], b + 0xC6, sizeof(_colour_gradient[i])); } new MainWindow(&_main_window_desc); /* XXX: these are not done */ switch (_game_mode) { default: NOT_REACHED(); case GM_MENU: ShowSelectGameWindow(); break; case GM_NORMAL: case GM_EDITOR: ShowVitalWindows(); break; } } /** * Show the vital in-game windows. */ void ShowVitalWindows() { AllocateToolbar(); /* Status bad only for normal games */ if (_game_mode == GM_EDITOR) return; ShowStatusBar(); } /** * Size of the application screen changed. * Adapt the game screen-size, re-allocate the open windows, and repaint everything */ void GameSizeChanged() { _cur_resolution.width = _screen.width; _cur_resolution.height = _screen.height; ScreenSizeChanged(); RelocateAllWindows(_screen.width, _screen.height); MarkWholeScreenDirty(); } openttd-1.5.3/src/signal_func.h0000644000000000000000000000433412627373442015141 0ustar rootroot/* $Id: signal_func.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 signal_func.h Functions related to signals. */ #ifndef SIGNAL_FUNC_H #define SIGNAL_FUNC_H #include "track_type.h" #include "tile_type.h" #include "direction_type.h" #include "company_type.h" /** * Maps a trackdir to the bit that stores its status in the map arrays, in the * direction along with the trackdir. */ static inline byte SignalAlongTrackdir(Trackdir trackdir) { extern const byte _signal_along_trackdir[TRACKDIR_END]; return _signal_along_trackdir[trackdir]; } /** * Maps a trackdir to the bit that stores its status in the map arrays, in the * direction against the trackdir. */ static inline byte SignalAgainstTrackdir(Trackdir trackdir) { extern const byte _signal_against_trackdir[TRACKDIR_END]; return _signal_against_trackdir[trackdir]; } /** * Maps a Track to the bits that store the status of the two signals that can * be present on the given track. */ static inline byte SignalOnTrack(Track track) { extern const byte _signal_on_track[TRACK_END]; return _signal_on_track[track]; } /** State of the signal segment */ enum SigSegState { SIGSEG_FREE, ///< Free and has no pre-signal exits or at least one green exit SIGSEG_FULL, ///< Occupied by a train SIGSEG_PBS, ///< Segment is a PBS segment }; SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner); void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner); void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner); void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner); void UpdateSignalsInBuffer(); #endif /* SIGNAL_FUNC_H */ openttd-1.5.3/src/cargopacket.h0000644000000000000000000004256612627373442015145 0ustar rootroot/* $Id: cargopacket.h 26660 2014-06-21 19:52:52Z fonsinchen $ */ /* * 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 cargopacket.h Base class for cargo packets. */ #ifndef CARGOPACKET_H #define CARGOPACKET_H #include "core/pool_type.hpp" #include "economy_type.h" #include "station_type.h" #include "order_type.h" #include "cargo_type.h" #include "vehicle_type.h" #include "core/multimap.hpp" #include /** Unique identifier for a single cargo packet. */ typedef uint32 CargoPacketID; struct CargoPacket; /** Type of the pool for cargo packets for a little over 16 million packets. */ typedef Pool CargoPacketPool; /** The actual pool with cargo packets. */ extern CargoPacketPool _cargopacket_pool; struct GoodsEntry; // forward-declare for Stage() and RerouteStalePackets() template class CargoList; class StationCargoList; // forward-declare, so we can use it in VehicleCargoList. extern const struct SaveLoad *GetCargoPacketDesc(); typedef uint32 TileOrStationID; /** * Container for cargo from the same location and time. */ struct CargoPacket : CargoPacketPool::PoolItem<&_cargopacket_pool> { private: Money feeder_share; ///< Value of feeder pickup to be paid for on delivery of cargo. uint16 count; ///< The amount of cargo in this packet. byte days_in_transit; ///< Amount of days this packet has been in transit. SourceTypeByte source_type; ///< Type of \c source_id. SourceID source_id; ///< Index of source, INVALID_SOURCE if unknown/invalid. StationID source; ///< The station where the cargo came from first. TileIndex source_xy; ///< The origin of the cargo (first station in feeder chain). union { TileOrStationID loaded_at_xy; ///< Location where this cargo has been loaded into the vehicle. TileOrStationID next_station; ///< Station where the cargo wants to go next. }; /** The CargoList caches, thus needs to know about it. */ template friend class CargoList; friend class VehicleCargoList; friend class StationCargoList; /** We want this to be saved, right? */ friend const struct SaveLoad *GetCargoPacketDesc(); public: /** Maximum number of items in a single cargo packet. */ static const uint16 MAX_COUNT = UINT16_MAX; CargoPacket(); CargoPacket(StationID source, TileIndex source_xy, uint16 count, SourceType source_type, SourceID source_id); CargoPacket(uint16 count, byte days_in_transit, StationID source, TileIndex source_xy, TileIndex loaded_at_xy, Money feeder_share = 0, SourceType source_type = ST_INDUSTRY, SourceID source_id = INVALID_SOURCE); /** Destroy the packet. */ ~CargoPacket() { } CargoPacket *Split(uint new_size); void Merge(CargoPacket *cp); void Reduce(uint count); /** * Sets the tile where the packet was loaded last. * @param load_place Tile where the packet was loaded last. */ void SetLoadPlace(TileIndex load_place) { this->loaded_at_xy = load_place; } /** * Sets the station where the packet is supposed to go next. * @param next_station Next station the packet should go to. */ void SetNextStation(StationID next_station) { this->next_station = next_station; } /** * Adds some feeder share to the packet. * @param new_share Feeder share to be added. */ void AddFeederShare(Money new_share) { this->feeder_share += new_share; } /** * Gets the number of 'items' in this packet. * @return Item count. */ inline uint16 Count() const { return this->count; } /** * Gets the amount of money already paid to earlier vehicles in * the feeder chain. * @return Feeder share. */ inline Money FeederShare() const { return this->feeder_share; } /** * Gets part of the amount of money already paid to earlier vehicles in * the feeder chain. * @param part Amount of cargo to get the share for. * @return Feeder share for the given amount of cargo. */ inline Money FeederShare(uint part) const { return this->feeder_share * part / static_cast(this->count); } /** * Gets the number of days this cargo has been in transit. * This number isn't really in days, but in 2.5 days (CARGO_AGING_TICKS = 185 ticks) and * it is capped at 255. * @return Length this cargo has been in transit. */ inline byte DaysInTransit() const { return this->days_in_transit; } /** * Gets the type of the cargo's source. industry, town or head quarter. * @return Source type. */ inline SourceType SourceSubsidyType() const { return this->source_type; } /** * Gets the ID of the cargo's source. An IndustryID, TownID or CompanyID. * @return Source ID. */ inline SourceID SourceSubsidyID() const { return this->source_id; } /** * Gets the ID of the station where the cargo was loaded for the first time. * @return StationID. */ inline StationID SourceStation() const { return this->source; } /** * Gets the coordinates of the cargo's source station. * @return Source station's coordinates. */ inline TileIndex SourceStationXY() const { return this->source_xy; } /** * Gets the coordinates of the cargo's last loading station. * @return Last loading station's coordinates. */ inline TileIndex LoadedAtXY() const { return this->loaded_at_xy; } /** * Gets the ID of station the cargo wants to go next. * @return Next station for this packets. */ inline StationID NextStation() const { return this->next_station; } static void InvalidateAllFrom(SourceType src_type, SourceID src); static void InvalidateAllFrom(StationID sid); static void AfterLoad(); }; /** * Iterate over all _valid_ cargo packets from the given start. * @param var Variable used as "iterator". * @param start Cargo packet ID of the first packet to iterate over. */ #define FOR_ALL_CARGOPACKETS_FROM(var, start) FOR_ALL_ITEMS_FROM(CargoPacket, cargopacket_index, var, start) /** * Iterate over all _valid_ cargo packets from the begin of the pool. * @param var Variable used as "iterator". */ #define FOR_ALL_CARGOPACKETS(var) FOR_ALL_CARGOPACKETS_FROM(var, 0) /** * Simple collection class for a list of cargo packets. * @tparam Tinst Actual instantiation of this cargo list. */ template class CargoList { public: /** The iterator for our container. */ typedef typename Tcont::iterator Iterator; /** The reverse iterator for our container. */ typedef typename Tcont::reverse_iterator ReverseIterator; /** The const iterator for our container. */ typedef typename Tcont::const_iterator ConstIterator; /** The const reverse iterator for our container. */ typedef typename Tcont::const_reverse_iterator ConstReverseIterator; /** Kind of actions that could be done with packets on move. */ enum MoveToAction { MTA_BEGIN = 0, MTA_TRANSFER = 0, ///< Transfer the cargo to the station. MTA_DELIVER, ///< Deliver the cargo to some town or industry. MTA_KEEP, ///< Keep the cargo in the vehicle. MTA_LOAD, ///< Load the cargo from the station. MTA_END, NUM_MOVE_TO_ACTION = MTA_END }; protected: 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. Tcont packets; ///< The cargo packets in this list. void AddToCache(const CargoPacket *cp); void RemoveFromCache(const CargoPacket *cp, uint count); static bool TryMerge(CargoPacket *cp, CargoPacket *icp); public: /** Create the cargo list. */ CargoList() {} ~CargoList(); void OnCleanPool(); /** * Returns a pointer to the cargo packet list (so you can iterate over it etc). * @return Pointer to the packet list. */ inline const Tcont *Packets() const { return &this->packets; } /** * Returns average number of days in transit for a cargo entity. * @return The before mentioned number. */ inline uint DaysInTransit() const { return this->count == 0 ? 0 : this->cargo_days_in_transit / this->count; } void InvalidateCache(); }; typedef std::list CargoPacketList; /** * CargoList that is used for vehicles. */ class VehicleCargoList : public CargoList { protected: /** The (direct) parent of this class. */ typedef CargoList Parent; Money feeder_share; ///< Cache for the feeder share. uint action_counts[NUM_MOVE_TO_ACTION]; ///< Counts of cargo to be transfered, delivered, kept and loaded. template void ShiftCargo(Taction action); template void PopCargo(Taction action); /** * Assert that the designation counts add up. */ inline void AssertCountConsistency() const { assert(this->action_counts[MTA_KEEP] + this->action_counts[MTA_DELIVER] + this->action_counts[MTA_TRANSFER] + this->action_counts[MTA_LOAD] == this->count); } void AddToCache(const CargoPacket *cp); void RemoveFromCache(const CargoPacket *cp, uint count); void AddToMeta(const CargoPacket *cp, MoveToAction action); void RemoveFromMeta(const CargoPacket *cp, MoveToAction action, uint count); static MoveToAction ChooseAction(const CargoPacket *cp, StationID cargo_next, StationID current_station, bool accepted, StationIDStack next_station); public: /** 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); friend class CargoShift; friend class CargoTransfer; friend class CargoDelivery; template friend class CargoRemoval; friend class CargoReturn; friend class VehicleCargoReroute; /** * Returns source of the first cargo packet in this list. * @return The before mentioned source. */ inline StationID Source() const { return this->count == 0 ? INVALID_STATION : this->packets.front()->source; } /** * Returns total sum of the feeder share for all packets. * @return The before mentioned number. */ inline Money FeederShare() const { return this->feeder_share; } /** * Returns the amount of cargo designated for a given purpose. * @param action Action the cargo is designated for. * @return Amount of cargo designated for the given action. */ inline uint ActionCount(MoveToAction action) const { return this->action_counts[action]; } /** * Returns sum of cargo on board the vehicle (ie not only * reserved). * @return Cargo on board the vehicle. */ inline uint StoredCount() const { return this->count - this->action_counts[MTA_LOAD]; } /** * Returns sum of cargo, including reserved cargo. * @return Sum of cargo. */ inline uint TotalCount() const { return this->count; } /** * Returns sum of reserved cargo. * @return Sum of reserved cargo. */ inline uint ReservedCount() const { return this->action_counts[MTA_LOAD]; } /** * Returns sum of cargo to be moved out of the vehicle at the current station. * @return Cargo to be moved. */ inline uint UnloadCount() const { return this->action_counts[MTA_TRANSFER] + this->action_counts[MTA_DELIVER]; } /** * Returns the sum of cargo to be kept in the vehicle at the current station. * @return Cargo to be kept or loaded. */ inline uint RemainingCount() const { return this->action_counts[MTA_KEEP] + this->action_counts[MTA_LOAD]; } void Append(CargoPacket *cp, MoveToAction action = MTA_KEEP); void AgeCargo(); void InvalidateCache(); void SetTransferLoadPlace(TileIndex xy); bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment); /** * Marks all cargo in the vehicle as to be kept. This is mostly useful for * loading old savegames. When loading is aborted the reserved cargo has * to be returned first. */ inline void KeepAll() { this->action_counts[MTA_DELIVER] = this->action_counts[MTA_TRANSFER] = this->action_counts[MTA_LOAD] = 0; this->action_counts[MTA_KEEP] = this->count; } /* Methods for moving cargo around. First parameter is always maximum * amount of cargo to be moved. Second parameter is destination (if * applicable), return value is amount of cargo actually moved. */ template uint Reassign(uint max_move, TileOrStationID update = INVALID_TILE); uint Return(uint max_move, StationCargoList *dest, StationID next_station); uint Unload(uint max_move, StationCargoList *dest, CargoPayment *payment); uint Shift(uint max_move, VehicleCargoList *dest); uint Truncate(uint max_move = UINT_MAX); uint Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); /** * Are two the two CargoPackets mergeable in the context of * a list of CargoPackets for a Vehicle? * @param cp1 First CargoPacket. * @param cp2 Second CargoPacket. * @return True if they are mergeable. */ static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2) { return cp1->source_xy == cp2->source_xy && cp1->days_in_transit == cp2->days_in_transit && cp1->source_type == cp2->source_type && cp1->source_id == cp2->source_id && cp1->loaded_at_xy == cp2->loaded_at_xy; } }; typedef MultiMap StationCargoPacketMap; typedef std::map StationCargoAmountMap; /** * CargoList that is used for stations. */ class StationCargoList : public CargoList { protected: /** The (direct) parent of this class. */ typedef CargoList Parent; uint reserved_count; ///< Amount of cargo being reserved for loading. public: /** The super class ought to know what it's doing. */ friend class CargoList; /** The stations, via GoodsEntry, have a CargoList. */ friend const struct SaveLoad *GetGoodsDesc(); friend class CargoLoad; friend class CargoTransfer; template friend class CargoRemoval; friend class CargoReservation; friend class CargoReturn; friend class StationCargoReroute; static void InvalidateAllFrom(SourceType src_type, SourceID src); template bool ShiftCargo(Taction &action, StationID next); template uint ShiftCargo(Taction action, StationIDStack next, bool include_invalid); void Append(CargoPacket *cp, StationID next); /** * Check for cargo headed for a specific station. * @param next Station the cargo is headed for. * @return If there is any cargo for that station. */ inline bool HasCargoFor(StationIDStack next) const { while (!next.IsEmpty()) { if (this->packets.find(next.Pop()) != this->packets.end()) return true; } /* Packets for INVALID_STTION can go anywhere. */ return this->packets.find(INVALID_STATION) != this->packets.end(); } /** * Returns source of the first cargo packet in this list. * @return The before mentioned source. */ inline StationID Source() const { return this->count == 0 ? INVALID_STATION : this->packets.begin()->second.front()->source; } /** * Returns sum of cargo still available for loading at the sation. * (i.e. not counting cargo which is already reserved for loading) * @return Cargo on board the vehicle. */ inline uint AvailableCount() const { return this->count; } /** * Returns sum of cargo reserved for loading onto vehicles. * @return Cargo reserved for loading. */ inline uint ReservedCount() const { return this->reserved_count; } /** * Returns total count of cargo at the station, including * cargo which is already reserved for loading. * @return Total cargo count. */ inline uint TotalCount() const { return this->count + this->reserved_count; } /* Methods for moving cargo around. First parameter is always maximum * amount of cargo to be moved. Second parameter is destination (if * applicable), return value is amount of cargo actually moved. */ uint Reserve(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next); uint Load(uint max_move, VehicleCargoList *dest, TileIndex load_place, StationIDStack next); uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = NULL); uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); /** * Are two the two CargoPackets mergeable in the context of * a list of CargoPackets for a Vehicle? * @param cp1 First CargoPacket. * @param cp2 Second CargoPacket. * @return True if they are mergeable. */ static bool AreMergable(const CargoPacket *cp1, const CargoPacket *cp2) { return cp1->source_xy == cp2->source_xy && cp1->days_in_transit == cp2->days_in_transit && cp1->source_type == cp2->source_type && cp1->source_id == cp2->source_id; } }; #endif /* CARGOPACKET_H */ openttd-1.5.3/src/smallmap_gui.cpp0000644000000000000000000020374412627373441015663 0ustar rootroot/* $Id: smallmap_gui.cpp 27160 2015-02-22 14:14:30Z frosch $ */ /* * 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 smallmap_gui.cpp GUI that shows a small map of the world with metadata like owner or height. */ #include "stdafx.h" #include "clear_map.h" #include "industry.h" #include "station_map.h" #include "landscape.h" #include "tree_map.h" #include "viewport_func.h" #include "town.h" #include "tunnelbridge_map.h" #include "core/endian_func.hpp" #include "vehicle_base.h" #include "sound_func.h" #include "window_func.h" #include "company_base.h" #include "smallmap_gui.h" #include "table/strings.h" #include "safeguards.h" static int _smallmap_industry_count; ///< Number of used industries static int _smallmap_company_count; ///< Number of entries in the owner legend. static int _smallmap_cargo_count; ///< Number of cargos in the link stats legend. /** Link stat colours shown in legenda. */ static uint8 _linkstat_colours_in_legenda[] = {0, 1, 3, 5, 7, 9, 11}; static const int NUM_NO_COMPANY_ENTRIES = 4; ///< Number of entries in the owner legend that are not companies. static const uint8 PC_ROUGH_LAND = 0x52; ///< Dark green palette colour for rough land. static const uint8 PC_GRASS_LAND = 0x54; ///< Dark green palette colour for grass land. static const uint8 PC_BARE_LAND = 0x37; ///< Brown palette colour for bare land. static const uint8 PC_FIELDS = 0x25; ///< Light brown palette colour for fields. static const uint8 PC_TREES = 0x57; ///< Green palette colour for trees. static const uint8 PC_WATER = 0xCA; ///< Dark blue palette colour for water. /** Macro for ordinary entry of LegendAndColour */ #define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false} /** Macro for a height legend entry with configurable colour. */ #define MC(col_break) {0, STR_TINY_BLACK_HEIGHT, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, col_break} /** Macro for non-company owned property entry of LegendAndColour */ #define MO(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false} /** Macro used for forcing a rebuild of the owner legend the first time it is used. */ #define MOEND() {0, 0, INVALID_INDUSTRYTYPE, 0, OWNER_NONE, true, true, false} /** Macro for end of list marker in arrays of LegendAndColour */ #define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, true, false} /** * Macro for break marker in arrays of LegendAndColour. * It will have valid data, though */ #define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, true} /** Legend text giving the colours to look for on the minimap */ static LegendAndColour _legend_land_contours[] = { MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS), MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS), MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS), MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), MK(PC_WHITE, STR_SMALLMAP_LEGENDA_VEHICLES), /* Placeholders for the colours and heights of the legend. * The following values are set at BuildLandLegend() based * on each colour scheme and the maximum map height. */ MC(true), MC(false), MC(false), MC(false), MC(false), MC(false), MC(true), MC(false), MC(false), MC(false), MC(false), MC(false), MKEND() }; static const LegendAndColour _legend_vehicles[] = { MK(PC_RED, STR_SMALLMAP_LEGENDA_TRAINS), MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_ROAD_VEHICLES), MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SHIPS), MK(PC_WHITE, STR_SMALLMAP_LEGENDA_AIRCRAFT), MS(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), MKEND() }; static const LegendAndColour _legend_routes[] = { MK(PC_BLACK, STR_SMALLMAP_LEGENDA_ROADS), MK(PC_GREY, STR_SMALLMAP_LEGENDA_RAILROADS), MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), MS(PC_VERY_DARK_BROWN, STR_SMALLMAP_LEGENDA_RAILROAD_STATION), MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY), MK(PC_YELLOW, STR_SMALLMAP_LEGENDA_BUS_STATION), MK(PC_RED, STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT), MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_DOCK), MKEND() }; static const LegendAndColour _legend_vegetation[] = { MK(PC_ROUGH_LAND, STR_SMALLMAP_LEGENDA_ROUGH_LAND), MK(PC_GRASS_LAND, STR_SMALLMAP_LEGENDA_GRASS_LAND), MK(PC_BARE_LAND, STR_SMALLMAP_LEGENDA_BARE_LAND), MK(PC_FIELDS, STR_SMALLMAP_LEGENDA_FIELDS), MK(PC_TREES, STR_SMALLMAP_LEGENDA_TREES), MK(PC_GREEN, STR_SMALLMAP_LEGENDA_FOREST), MS(PC_GREY, STR_SMALLMAP_LEGENDA_ROCKS), MK(PC_ORANGE, STR_SMALLMAP_LEGENDA_DESERT), MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_SNOW), MK(PC_BLACK, STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES), MK(PC_DARK_RED, STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES), MKEND() }; static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = { MO(PC_WATER, STR_SMALLMAP_LEGENDA_WATER), MO(0x00, STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings. MO(PC_DARK_RED, STR_SMALLMAP_LEGENDA_TOWNS), MO(PC_DARK_GREY, STR_SMALLMAP_LEGENDA_INDUSTRIES), /* The legend will be terminated the first time it is used. */ MOEND(), }; #undef MK #undef MC #undef MS #undef MO #undef MOEND #undef MKEND /** Legend entries for the link stats view. */ static LegendAndColour _legend_linkstats[NUM_CARGO + lengthof(_linkstat_colours_in_legenda) + 1]; /** * Allow room for all industries, plus a terminator entry * This is required in order to have the industry slots all filled up */ static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1]; /** For connecting industry type to position in industries list(small map legend) */ static uint _industry_to_list_pos[NUM_INDUSTRYTYPES]; /** Show heightmap in industry and owner mode of smallmap window. */ static bool _smallmap_show_heightmap = false; /** Highlight a specific industry type */ static IndustryType _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; /** State of highlight blinking */ static bool _smallmap_industry_highlight_state; /** For connecting company ID to position in owner list (small map legend) */ static uint _company_to_list_pos[MAX_COMPANIES]; /** * Fills an array for the industries legends. */ void BuildIndustriesLegend() { uint j = 0; /* Add each name */ for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { IndustryType ind = _sorted_industry_types[i]; const IndustrySpec *indsp = GetIndustrySpec(ind); if (indsp->enabled) { _legend_from_industries[j].legend = indsp->name; _legend_from_industries[j].colour = indsp->map_colour; _legend_from_industries[j].type = ind; _legend_from_industries[j].show_on_map = true; _legend_from_industries[j].col_break = false; _legend_from_industries[j].end = false; /* Store widget number for this industry type. */ _industry_to_list_pos[ind] = j; j++; } } /* Terminate the list */ _legend_from_industries[j].end = true; /* Store number of enabled industries */ _smallmap_industry_count = j; } /** * Populate legend table for the link stat view. */ void BuildLinkStatsLegend() { /* Clear the legend */ memset(_legend_linkstats, 0, sizeof(_legend_linkstats)); uint i = 0; for (; i < _sorted_cargo_specs_size; ++i) { const CargoSpec *cs = _sorted_cargo_specs[i]; _legend_linkstats[i].legend = cs->name; _legend_linkstats[i].colour = cs->legend_colour; _legend_linkstats[i].type = cs->Index(); _legend_linkstats[i].show_on_map = true; } _legend_linkstats[i].col_break = true; _smallmap_cargo_count = i; for (; i < _smallmap_cargo_count + lengthof(_linkstat_colours_in_legenda); ++i) { _legend_linkstats[i].legend = STR_EMPTY; _legend_linkstats[i].colour = LinkGraphOverlay::LINK_COLOURS[_linkstat_colours_in_legenda[i - _smallmap_cargo_count]]; _legend_linkstats[i].show_on_map = true; } _legend_linkstats[_smallmap_cargo_count].legend = STR_LINKGRAPH_LEGEND_UNUSED; _legend_linkstats[i - 1].legend = STR_LINKGRAPH_LEGEND_OVERLOADED; _legend_linkstats[(_smallmap_cargo_count + i - 1) / 2].legend = STR_LINKGRAPH_LEGEND_SATURATED; _legend_linkstats[i].end = true; } static const LegendAndColour * const _legend_table[] = { _legend_land_contours, _legend_vehicles, _legend_from_industries, _legend_linkstats, _legend_routes, _legend_vegetation, _legend_land_owners, }; #define MKCOLOUR(x) TO_LE32X(x) #define MKCOLOUR_XXXX(x) (MKCOLOUR(0x01010101) * (uint)(x)) #define MKCOLOUR_X0X0(x) (MKCOLOUR(0x01000100) * (uint)(x)) #define MKCOLOUR_0X0X(x) (MKCOLOUR(0x00010001) * (uint)(x)) #define MKCOLOUR_0XX0(x) (MKCOLOUR(0x00010100) * (uint)(x)) #define MKCOLOUR_X00X(x) (MKCOLOUR(0x01000001) * (uint)(x)) #define MKCOLOUR_XYXY(x, y) (MKCOLOUR_X0X0(x) | MKCOLOUR_0X0X(y)) #define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y)) #define MKCOLOUR_0000 MKCOLOUR_XXXX(0x00) #define MKCOLOUR_0FF0 MKCOLOUR_0XX0(0xFF) #define MKCOLOUR_F00F MKCOLOUR_X00X(0xFF) #define MKCOLOUR_FFFF MKCOLOUR_XXXX(0xFF) #include "table/heightmap_colours.h" /** Colour scheme of the smallmap. */ struct SmallMapColourScheme { uint32 *height_colours; ///< Cached colours for each level in a map. const uint32 *height_colours_base; ///< Base table for determining the colours size_t colour_count; ///< The number of colours. uint32 default_colour; ///< Default colour of the land. }; /** Available colour schemes for height maps. */ static SmallMapColourScheme _heightmap_schemes[] = { {NULL, _green_map_heights, lengthof(_green_map_heights), MKCOLOUR_XXXX(0x54)}, ///< Green colour scheme. {NULL, _dark_green_map_heights, lengthof(_dark_green_map_heights), MKCOLOUR_XXXX(0x62)}, ///< Dark green colour scheme. {NULL, _violet_map_heights, lengthof(_violet_map_heights), MKCOLOUR_XXXX(0x82)}, ///< Violet colour scheme. }; /** * (Re)build the colour tables for the legends. */ void BuildLandLegend() { /* The smallmap window has never been initialized, so no need to change the legend. */ if (_heightmap_schemes[0].height_colours == NULL) return; /* * The general idea of this function is to fill the legend with an appropriate evenly spaced * selection of height levels. All entries with STR_TINY_BLACK_HEIGHT are reserved for this. * At the moment there are twelve of these. * * The table below defines up to which height level a particular delta in the legend should be * used. One could opt for just dividing the maximum height and use that as delta, but that * creates many "ugly" legend labels, e.g. once every 950 meter. As a result, this table will * reduce the number of deltas to 7: every 100m, 200m, 300m, 500m, 750m, 1000m and 1250m. The * deltas are closer together at the lower numbers because going from 12 entries to just 4, as * would happen when replacing 200m and 300m by 250m, would mean the legend would be short and * that might not be considered appropriate. * * The current method yields at least 7 legend entries and at most 12. It can be increased to * 8 by adding a 150m and 400m option, but especially 150m creates ugly heights. * * It tries to evenly space the legend items over the two columns that are there for the legend. */ /* Table for delta; if max_height is less than the first column, use the second column as value. */ uint deltas[][2] = { { 24, 2 }, { 48, 4 }, { 72, 6 }, { 120, 10 }, { 180, 15 }, { 240, 20 }, { MAX_TILE_HEIGHT + 1, 25 }}; uint i = 0; for (; _settings_game.construction.max_heightlevel >= deltas[i][0]; i++) { /* Nothing to do here. */ } uint delta = deltas[i][1]; int total_entries = (_settings_game.construction.max_heightlevel / delta) + 1; int rows = CeilDiv(total_entries, 2); int j = 0; for (i = 0; i < lengthof(_legend_land_contours) - 1 && j < total_entries; i++) { if (_legend_land_contours[i].legend != STR_TINY_BLACK_HEIGHT) continue; _legend_land_contours[i].col_break = j % rows == 0; _legend_land_contours[i].end = false; _legend_land_contours[i].height = j * delta; _legend_land_contours[i].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].height_colours[j * delta]; j++; } _legend_land_contours[i].end = true; } /** * Completes the array for the owned property legend. */ void BuildOwnerLegend() { _legend_land_owners[1].colour = _heightmap_schemes[_settings_client.gui.smallmap_land_colour].default_colour; int i = NUM_NO_COMPANY_ENTRIES; const Company *c; FOR_ALL_COMPANIES(c) { _legend_land_owners[i].colour = _colour_gradient[c->colour][5]; _legend_land_owners[i].company = c->index; _legend_land_owners[i].show_on_map = true; _legend_land_owners[i].col_break = false; _legend_land_owners[i].end = false; _company_to_list_pos[c->index] = i; i++; } /* Terminate the list */ _legend_land_owners[i].end = true; /* Store maximum amount of owner legend entries. */ _smallmap_company_count = i; } struct AndOr { uint32 mor; uint32 mand; }; static inline uint32 ApplyMask(uint32 colour, const AndOr *mask) { return (colour & mask->mand) | mask->mor; } /** Colour masks for "Contour" and "Routes" modes. */ static const AndOr _smallmap_contours_andor[] = { {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, // MP_RAILWAY {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000}, // MP_STATION {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT {MKCOLOUR_0XX0(PC_GREY ), MKCOLOUR_F00F}, }; /** Colour masks for "Vehicles", "Industry", and "Vegetation" modes. */ static const AndOr _smallmap_vehicles_andor[] = { {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_CLEAR {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_RAILWAY {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_ROAD {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_HOUSE {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TREES {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, // MP_STATION {MKCOLOUR_XXXX(PC_WATER ), MKCOLOUR_0000}, // MP_WATER {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_VOID {MKCOLOUR_XXXX(PC_DARK_RED ), MKCOLOUR_0000}, // MP_INDUSTRY {MKCOLOUR_0000 , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE {MKCOLOUR_0XX0(PC_DARK_RED ), MKCOLOUR_F00F}, // MP_OBJECT {MKCOLOUR_0XX0(PC_BLACK ), MKCOLOUR_F00F}, }; /** Mapping of tile type to importance of the tile (higher number means more interesting to show). */ static const byte _tiletype_importance[] = { 2, // MP_CLEAR 8, // MP_RAILWAY 7, // MP_ROAD 5, // MP_HOUSE 2, // MP_TREES 9, // MP_STATION 2, // MP_WATER 1, // MP_VOID 6, // MP_INDUSTRY 8, // MP_TUNNELBRIDGE 2, // MP_OBJECT 0, }; static inline TileType GetEffectiveTileType(TileIndex tile) { TileType t = GetTileType(tile); if (t == MP_TUNNELBRIDGE) { TransportType tt = GetTunnelBridgeTransportType(tile); switch (tt) { case TRANSPORT_RAIL: t = MP_RAILWAY; break; case TRANSPORT_ROAD: t = MP_ROAD; break; default: t = MP_WATER; break; } } return t; } /** * Return the colour a tile would be displayed with in the small map in mode "Contour". * @param tile The tile of which we would like to get the colour. * @param t Effective tile type of the tile (see #GetEffectiveTileType). * @return The colour of tile in the small map in mode "Contour" */ static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t) { const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; return ApplyMask(cs->height_colours[TileHeight(tile)], &_smallmap_contours_andor[t]); } /** * Return the colour a tile would be displayed with in the small map in mode "Vehicles". * * @param tile The tile of which we would like to get the colour. * @param t Effective tile type of the tile (see #GetEffectiveTileType). * @return The colour of tile in the small map in mode "Vehicles" */ static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t) { const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]); } /** * Return the colour a tile would be displayed with in the small map in mode "Industries". * * @param tile The tile of which we would like to get the colour. * @param t Effective tile type of the tile (see #GetEffectiveTileType). * @return The colour of tile in the small map in mode "Industries" */ static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t) { if (t == MP_INDUSTRY) { /* If industry is allowed to be seen, use its colour on the map */ IndustryType type = Industry::GetByTile(tile)->type; if (_legend_from_industries[_industry_to_list_pos[type]].show_on_map && (_smallmap_industry_highlight_state || type != _smallmap_industry_highlight)) { return (type == _smallmap_industry_highlight ? PC_WHITE : GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour) * 0x01010101; } else { /* Otherwise, return the colour which will make it disappear */ t = (IsTileOnWater(tile) ? MP_WATER : MP_CLEAR); } } const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; return ApplyMask(_smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour, &_smallmap_vehicles_andor[t]); } /** * Return the colour a tile would be displayed with in the small map in mode "Routes". * * @param tile The tile of which we would like to get the colour. * @param t Effective tile type of the tile (see #GetEffectiveTileType). * @return The colour of tile in the small map in mode "Routes" */ static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t) { if (t == MP_STATION) { switch (GetStationType(tile)) { case STATION_RAIL: return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN); case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED); case STATION_TRUCK: return MKCOLOUR_XXXX(PC_ORANGE); case STATION_BUS: return MKCOLOUR_XXXX(PC_YELLOW); case STATION_DOCK: return MKCOLOUR_XXXX(PC_LIGHT_BLUE); default: return MKCOLOUR_FFFF; } } else if (t == MP_RAILWAY) { AndOr andor = { MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour), _smallmap_contours_andor[t].mand }; const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; return ApplyMask(cs->default_colour, &andor); } /* Ground colour */ const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]); } /** * Return the colour a tile would be displayed with in the small map in mode "link stats". * * @param tile The tile of which we would like to get the colour. * @param t Effective tile type of the tile (see #GetEffectiveTileType). * @return The colour of tile in the small map in mode "link stats" */ static inline uint32 GetSmallMapLinkStatsPixels(TileIndex tile, TileType t) { return _smallmap_show_heightmap ? GetSmallMapContoursPixels(tile, t) : GetSmallMapRoutesPixels(tile, t); } static const uint32 _vegetation_clear_bits[] = { MKCOLOUR_XXXX(PC_GRASS_LAND), ///< full grass MKCOLOUR_XXXX(PC_ROUGH_LAND), ///< rough land MKCOLOUR_XXXX(PC_GREY), ///< rocks MKCOLOUR_XXXX(PC_FIELDS), ///< fields MKCOLOUR_XXXX(PC_LIGHT_BLUE), ///< snow MKCOLOUR_XXXX(PC_ORANGE), ///< desert MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused MKCOLOUR_XXXX(PC_GRASS_LAND), ///< unused }; /** * Return the colour a tile would be displayed with in the smallmap in mode "Vegetation". * * @param tile The tile of which we would like to get the colour. * @param t Effective tile type of the tile (see #GetEffectiveTileType). * @return The colour of tile in the smallmap in mode "Vegetation" */ static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t) { switch (t) { case MP_CLEAR: return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR_XXXX(PC_BARE_LAND) : _vegetation_clear_bits[GetClearGround(tile)]; case MP_INDUSTRY: return IsTileForestIndustry(tile) ? MKCOLOUR_XXXX(PC_GREEN) : MKCOLOUR_XXXX(PC_DARK_RED); case MP_TREES: if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) { return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES); } return MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES); default: return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]); } } /** * Return the colour a tile would be displayed with in the small map in mode "Owner". * * @param tile The tile of which we would like to get the colour. * @param t Effective tile type of the tile (see #GetEffectiveTileType). * @return The colour of tile in the small map in mode "Owner" */ static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t) { Owner o; switch (t) { case MP_INDUSTRY: return MKCOLOUR_XXXX(PC_DARK_GREY); case MP_HOUSE: return MKCOLOUR_XXXX(PC_DARK_RED); default: o = GetTileOwner(tile); break; /* FIXME: For MP_ROAD there are multiple owners. * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road), * even if there are no ROADTYPE_ROAD bits on the tile. */ } if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE || o == OWNER_WATER) { if (t == MP_WATER) return MKCOLOUR_XXXX(PC_WATER); const SmallMapColourScheme *cs = &_heightmap_schemes[_settings_client.gui.smallmap_land_colour]; return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour; } else if (o == OWNER_TOWN) { return MKCOLOUR_XXXX(PC_DARK_RED); } return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour); } /** Vehicle colours in #SMT_VEHICLES mode. Indexed by #VehicleTypeByte. */ static const byte _vehicle_type_colours[6] = { PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED }; inline Point SmallMapWindow::SmallmapRemapCoords(int x, int y) const { Point pt; pt.x = (y - x) * 2; pt.y = y + x; return pt; } /** * Remap tile to location on this smallmap. * @param tile_x X coordinate of the tile. * @param tile_y Y coordinate of the tile. * @return Position to draw on. */ inline Point SmallMapWindow::RemapTile(int tile_x, int tile_y) const { int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE; int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE; if (this->zoom == 1) return SmallmapRemapCoords(x_offset, y_offset); /* For negative offsets, round towards -inf. */ if (x_offset < 0) x_offset -= this->zoom - 1; if (y_offset < 0) y_offset -= this->zoom - 1; return SmallmapRemapCoords(x_offset / this->zoom, y_offset / this->zoom); } /** * Determine the tile relative to the base tile of the smallmap, and the pixel position at * that tile for a point in the smallmap. * @param px Horizontal coordinate of the pixel. * @param py Vertical coordinate of the pixel. * @param sub[out] Pixel position at the tile (0..3). * @param add_sub Add current #subscroll to the position. * @return Tile being displayed at the given position relative to #scroll_x and #scroll_y. * @note The #subscroll offset is already accounted for. */ inline Point SmallMapWindow::PixelToTile(int px, int py, int *sub, bool add_sub) const { if (add_sub) px += this->subscroll; // Total horizontal offset. /* For each two rows down, add a x and a y tile, and * For each four pixels to the right, move a tile to the right. */ Point pt = {((py >> 1) - (px >> 2)) * this->zoom, ((py >> 1) + (px >> 2)) * this->zoom}; px &= 3; if (py & 1) { // Odd number of rows, handle the 2 pixel shift. if (px < 2) { pt.x += this->zoom; px += 2; } else { pt.y += this->zoom; px -= 2; } } *sub = px; return pt; } /** * Compute base parameters of the smallmap such that tile (\a tx, \a ty) starts at pixel (\a x, \a y). * @param tx Tile x coordinate. * @param ty Tile y coordinate. * @param x Non-negative horizontal position in the display where the tile starts. * @param y Non-negative vertical position in the display where the tile starts. * @param sub [out] Value of #subscroll needed. * @return #scroll_x, #scroll_y values. */ Point SmallMapWindow::ComputeScroll(int tx, int ty, int x, int y, int *sub) { assert(x >= 0 && y >= 0); int new_sub; Point tile_xy = PixelToTile(x, y, &new_sub, false); tx -= tile_xy.x; ty -= tile_xy.y; Point scroll; if (new_sub == 0) { *sub = 0; scroll.x = (tx + this->zoom) * TILE_SIZE; scroll.y = (ty - this->zoom) * TILE_SIZE; } else { *sub = 4 - new_sub; scroll.x = (tx + 2 * this->zoom) * TILE_SIZE; scroll.y = (ty - 2 * this->zoom) * TILE_SIZE; } return scroll; } /** * Initialize or change the zoom level. * @param change Way to change the zoom level. * @param zoom_pt Position to keep fixed while zooming. * @pre \c *zoom_pt should contain a point in the smallmap display when zooming in or out. */ void SmallMapWindow::SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt) { static const int zoomlevels[] = {1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away). static const int MIN_ZOOM_INDEX = 0; static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1; int new_index, cur_index, sub; Point tile; switch (change) { case ZLC_INITIALIZE: cur_index = - 1; // Definitely different from new_index. new_index = MIN_ZOOM_INDEX; tile.x = tile.y = 0; break; case ZLC_ZOOM_IN: case ZLC_ZOOM_OUT: for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) { if (this->zoom == zoomlevels[cur_index]) break; } assert(cur_index <= MAX_ZOOM_INDEX); tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX); break; default: NOT_REACHED(); } if (new_index != cur_index) { this->zoom = zoomlevels[new_index]; if (cur_index >= 0) { Point new_tile = this->PixelToTile(zoom_pt->x, zoom_pt->y, &sub); this->SetNewScroll(this->scroll_x + (tile.x - new_tile.x) * TILE_SIZE, this->scroll_y + (tile.y - new_tile.y) * TILE_SIZE, sub); } else if (this->map_type == SMT_LINKSTATS) { this->overlay->RebuildCache(); } this->SetWidgetDisabledState(WID_SM_ZOOM_IN, this->zoom == zoomlevels[MIN_ZOOM_INDEX]); this->SetWidgetDisabledState(WID_SM_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]); this->SetDirty(); } } /** * Decide which colours to show to the user for a group of tiles. * @param ta Tile area to investigate. * @return Colours to display. */ inline uint32 SmallMapWindow::GetTileColours(const TileArea &ta) const { int importance = 0; TileIndex tile = INVALID_TILE; // Position of the most important tile. TileType et = MP_VOID; // Effective tile type at that position. TILE_AREA_LOOP(ti, ta) { TileType ttype = GetEffectiveTileType(ti); if (_tiletype_importance[ttype] > importance) { importance = _tiletype_importance[ttype]; tile = ti; et = ttype; } } switch (this->map_type) { case SMT_CONTOUR: return GetSmallMapContoursPixels(tile, et); case SMT_VEHICLES: return GetSmallMapVehiclesPixels(tile, et); case SMT_INDUSTRY: return GetSmallMapIndustriesPixels(tile, et); case SMT_LINKSTATS: return GetSmallMapLinkStatsPixels(tile, et); case SMT_ROUTES: return GetSmallMapRoutesPixels(tile, et); case SMT_VEGETATION: return GetSmallMapVegetationPixels(tile, et); case SMT_OWNER: return GetSmallMapOwnerPixels(tile, et); default: NOT_REACHED(); } } /** * Draws one column of tiles of the small map in a certain mode onto the screen buffer, skipping the shifted rows in between. * * @param dst Pointer to a part of the screen buffer to write to. * @param xc The X coordinate of the first tile in the column. * @param yc The Y coordinate of the first tile in the column * @param pitch Number of pixels to advance in the screen buffer each time a pixel is written. * @param reps Number of lines to draw * @param start_pos Position of first pixel to draw. * @param end_pos Position of last pixel to draw (exclusive). * @param blitter current blitter * @note If pixel position is below \c 0, skip drawing. */ void SmallMapWindow::DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const { void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height); uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0; do { /* Check if the tile (xc,yc) is within the map range */ if (xc >= MapMaxX() || yc >= MapMaxY()) continue; /* Check if the dst pointer points to a pixel inside the screen buffer */ if (dst < _screen.dst_ptr) continue; if (dst >= dst_ptr_abs_end) continue; /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */ TileArea ta; if (min_xy == 1 && (xc == 0 || yc == 0)) { if (this->zoom == 1) continue; // The tile area is empty, don't draw anything. ta = TileArea(TileXY(max(min_xy, xc), max(min_xy, yc)), this->zoom - (xc == 0), this->zoom - (yc == 0)); } else { ta = TileArea(TileXY(xc, yc), this->zoom, this->zoom); } ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!). uint32 val = this->GetTileColours(ta); uint8 *val8 = (uint8 *)&val; int idx = max(0, -start_pos); for (int pos = max(0, start_pos); pos < end_pos; pos++) { blitter->SetPixel(dst, idx, 0, val8[idx]); idx++; } /* Switch to next tile in the column */ } while (xc += this->zoom, yc += this->zoom, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0); } /** * Adds vehicles to the smallmap. * @param dpi the part of the smallmap to be drawn into * @param blitter current blitter */ void SmallMapWindow::DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const { const Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->type == VEH_EFFECT) continue; if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue; /* Remap into flat coordinates. */ Point pt = this->RemapTile(v->x_pos / (int)TILE_SIZE, v->y_pos / (int)TILE_SIZE); int y = pt.y - dpi->top; if (!IsInsideMM(y, 0, dpi->height)) continue; // y is out of bounds. bool skip = false; // Default is to draw both pixels. int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate. if (x < 0) { /* if x+1 is 0, that means we're on the very left edge, * and should thus only draw a single pixel */ if (++x != 0) continue; skip = true; } else if (x >= dpi->width - 1) { /* Check if we're at the very right edge, and if so draw only a single pixel */ if (x != dpi->width - 1) continue; skip = true; } /* Calculate pointer to pixel and the colour */ byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE; /* And draw either one or two pixels depending on clipping */ blitter->SetPixel(dpi->dst_ptr, x, y, colour); if (!skip) blitter->SetPixel(dpi->dst_ptr, x + 1, y, colour); } } /** * Adds town names to the smallmap. * @param dpi the part of the smallmap to be drawn into */ void SmallMapWindow::DrawTowns(const DrawPixelInfo *dpi) const { const Town *t; FOR_ALL_TOWNS(t) { /* Remap the town coordinate */ Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy)); int x = pt.x - this->subscroll - (t->cache.sign.width_small >> 1); int y = pt.y; /* Check if the town sign is within bounds */ if (x + t->cache.sign.width_small > dpi->left && x < dpi->left + dpi->width && y + FONT_HEIGHT_SMALL > dpi->top && y < dpi->top + dpi->height) { /* And draw it. */ SetDParam(0, t->index); DrawString(x, x + t->cache.sign.width_small, y, STR_SMALLMAP_TOWN); } } } /** * Adds map indicators to the smallmap. */ void SmallMapWindow::DrawMapIndicators() const { /* Find main viewport. */ const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; Point upper_left_smallmap_coord = TranslateXYToTileCoord(vp, vp->left, vp->top, false); Point lower_right_smallmap_coord = TranslateXYToTileCoord(vp, vp->left + vp->width - 1, vp->top + vp->height - 1, false); Point upper_left = this->RemapTile(upper_left_smallmap_coord.x / (int)TILE_SIZE, upper_left_smallmap_coord.y / (int)TILE_SIZE); upper_left.x -= this->subscroll; Point lower_right = this->RemapTile(lower_right_smallmap_coord.x / (int)TILE_SIZE, lower_right_smallmap_coord.y / (int)TILE_SIZE); lower_right.x -= this->subscroll; SmallMapWindow::DrawVertMapIndicator(upper_left.x, upper_left.y, lower_right.y); SmallMapWindow::DrawVertMapIndicator(lower_right.x, upper_left.y, lower_right.y); SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, upper_left.y); SmallMapWindow::DrawHorizMapIndicator(upper_left.x, lower_right.x, lower_right.y); } /** * Draws the small map. * * Basically, the small map is draw column of pixels by column of pixels. The pixels * are drawn directly into the screen buffer. The final map is drawn in multiple passes. * The passes are: *
  1. The colours of tiles in the different modes.
  2. *
  3. Town names (optional)
* * @param dpi pointer to pixel to write onto */ void SmallMapWindow::DrawSmallMap(DrawPixelInfo *dpi) const { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); DrawPixelInfo *old_dpi; old_dpi = _cur_dpi; _cur_dpi = dpi; /* Clear it */ GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK); /* Which tile is displayed at (dpi->left, dpi->top)? */ int dx; Point tile = this->PixelToTile(dpi->left, dpi->top, &dx); int tile_x = this->scroll_x / (int)TILE_SIZE + tile.x; int tile_y = this->scroll_y / (int)TILE_SIZE + tile.y; void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0); int x = - dx - 4; int y = 0; for (;;) { /* Distance from left edge */ if (x >= -3) { if (x >= dpi->width) break; // Exit the loop. int end_pos = min(dpi->width, x + 4); int reps = (dpi->height - y + 1) / 2; // Number of lines. if (reps > 0) { this->DrawSmallMapColumn(ptr, tile_x, tile_y, dpi->pitch * 2, reps, x, end_pos, blitter); } } if (y == 0) { tile_y += this->zoom; y++; ptr = blitter->MoveTo(ptr, 0, 1); } else { tile_x -= this->zoom; y--; ptr = blitter->MoveTo(ptr, 0, -1); } ptr = blitter->MoveTo(ptr, 2, 0); x += 2; } /* Draw vehicles */ if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter); /* Draw link stat overlay */ if (this->map_type == SMT_LINKSTATS) this->overlay->Draw(dpi); /* Draw town names */ if (this->show_towns) this->DrawTowns(dpi); /* Draw map indicators */ this->DrawMapIndicators(); _cur_dpi = old_dpi; } /** * Function to set up widgets depending on the information being shown on the smallmap. */ void SmallMapWindow::SetupWidgetData() { StringID legend_tooltip; StringID enable_all_tooltip; StringID disable_all_tooltip; int plane; switch (this->map_type) { case SMT_INDUSTRY: legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION; enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES; disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES; plane = 0; break; case SMT_OWNER: legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION; enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES; disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES; plane = 0; break; case SMT_LINKSTATS: legend_tooltip = STR_SMALLMAP_TOOLTIP_CARGO_SELECTION; enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS; disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS; plane = 0; break; default: legend_tooltip = STR_NULL; enable_all_tooltip = STR_NULL; disable_all_tooltip = STR_NULL; plane = 1; break; } this->GetWidget(WID_SM_LEGEND)->SetDataTip(STR_NULL, legend_tooltip); this->GetWidget(WID_SM_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip); this->GetWidget(WID_SM_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip); this->GetWidget(WID_SM_SELECT_BUTTONS)->SetDisplayedPlane(plane); } SmallMapWindow::SmallMapWindow(WindowDesc *desc, int window_number) : Window(desc), refresh(FORCE_REFRESH_PERIOD) { _smallmap_industry_highlight = INVALID_INDUSTRYTYPE; this->overlay = new LinkGraphOverlay(this, WID_SM_MAP, 0, this->GetOverlayCompanyMask(), 1); this->InitNested(window_number); this->LowerWidget(this->map_type + WID_SM_CONTOUR); this->RebuildColourIndexIfNecessary(); this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); this->SetupWidgetData(); this->SetZoomLevel(ZLC_INITIALIZE, NULL); this->SmallMapCenterOnCurrentPos(); this->SetOverlayCargoMask(); } /** * Rebuilds the colour indices used for fast access to the smallmap contour colours based on the heightlevel. */ void SmallMapWindow::RebuildColourIndexIfNecessary() { /* Rebuild colour indices if necessary. */ if (SmallMapWindow::max_heightlevel == _settings_game.construction.max_heightlevel) return; for (uint n = 0; n < lengthof(_heightmap_schemes); n++) { /* The heights go from 0 up to and including maximum. */ int heights = _settings_game.construction.max_heightlevel + 1; _heightmap_schemes[n].height_colours = ReallocT(_heightmap_schemes[n].height_colours, heights); for (int z = 0; z < heights; z++) { uint access_index = (_heightmap_schemes[n].colour_count * z) / heights; /* Choose colour by mapping the range (0..max heightlevel) on the complete colour table. */ _heightmap_schemes[n].height_colours[z] = _heightmap_schemes[n].height_colours_base[access_index]; } } SmallMapWindow::max_heightlevel = _settings_game.construction.max_heightlevel; BuildLandLegend(); } /* virtual */ void SmallMapWindow::SetStringParameters(int widget) const { switch (widget) { case WID_SM_CAPTION: SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type); break; } } /* virtual */ void SmallMapWindow::OnInit() { uint min_width = 0; this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS; this->min_number_of_fixed_rows = lengthof(_linkstat_colours_in_legenda); for (uint i = 0; i < lengthof(_legend_table); i++) { uint height = 0; uint num_columns = 1; for (const LegendAndColour *tbl = _legend_table[i]; !tbl->end; ++tbl) { StringID str; if (i == SMT_INDUSTRY) { SetDParam(0, tbl->legend); SetDParam(1, IndustryPool::MAX_SIZE); str = STR_SMALLMAP_INDUSTRY; } else if (i == SMT_LINKSTATS) { SetDParam(0, tbl->legend); str = STR_SMALLMAP_LINKSTATS; } else if (i == SMT_OWNER) { if (tbl->company != INVALID_COMPANY) { if (!Company::IsValidID(tbl->company)) { /* Rebuild the owner legend. */ BuildOwnerLegend(); this->OnInit(); return; } /* Non-fixed legend entries for the owner view. */ SetDParam(0, tbl->company); str = STR_SMALLMAP_COMPANY; } else { str = tbl->legend; } } else { if (tbl->col_break) { this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height); height = 0; num_columns++; } height++; str = tbl->legend; } min_width = max(GetStringBoundingBox(str).width, min_width); } this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height); this->min_number_of_columns = max(this->min_number_of_columns, num_columns); } /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */ this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; } /* virtual */ void SmallMapWindow::OnPaint() { if (this->map_type == SMT_OWNER) { for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) { /* Rebuild the owner legend. */ BuildOwnerLegend(); this->InvalidateData(1); break; } } } this->DrawWidgets(); } /* virtual */ void SmallMapWindow::DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_SM_MAP: { DrawPixelInfo new_dpi; if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return; this->DrawSmallMap(&new_dpi); break; } case WID_SM_LEGEND: { uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1); uint number_of_rows = this->GetNumberRowsLegend(columns); bool rtl = _current_text_dir == TD_RTL; uint y_org = r.top + WD_FRAMERECT_TOP; uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT; uint y = y_org; uint i = 0; // Row counter for industry legend. uint row_height = FONT_HEIGHT_SMALL; uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT; uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0); uint blob_left = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0; uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH; StringID string = STR_NULL; switch (this->map_type) { case SMT_INDUSTRY: string = STR_SMALLMAP_INDUSTRY; break; case SMT_LINKSTATS: string = STR_SMALLMAP_LINKSTATS; break; case SMT_OWNER: string = STR_SMALLMAP_COMPANY; break; default: break; } for (const LegendAndColour *tbl = _legend_table[this->map_type]; !tbl->end; ++tbl) { if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_OWNER || this->map_type == SMT_LINKSTATS) && i++ >= number_of_rows)) { /* Column break needed, continue at top, COLUMN_WIDTH pixels * (one "row") to the right. */ x += rtl ? -(int)this->column_width : this->column_width; y = y_org; i = 1; } uint8 legend_colour = tbl->colour; switch (this->map_type) { case SMT_INDUSTRY: /* Industry name must be formatted, since it's not in tiny font in the specs. * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font */ SetDParam(0, tbl->legend); SetDParam(1, Industry::GetIndustryTypeCount(tbl->type)); if (tbl->show_on_map && tbl->type == _smallmap_industry_highlight) { legend_colour = _smallmap_industry_highlight_state ? PC_WHITE : PC_BLACK; } /* FALL THROUGH */ case SMT_LINKSTATS: SetDParam(0, tbl->legend); /* FALL_THROUGH */ case SMT_OWNER: if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) { if (this->map_type == SMT_OWNER) SetDParam(0, tbl->company); if (!tbl->show_on_map) { /* Simply draw the string, not the black border of the legend colour. * This will enforce the idea of the disabled item */ DrawString(x + text_left, x + text_right, y, string, TC_GREY); } else { DrawString(x + text_left, x + text_right, y, string, TC_BLACK); GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); // Outer border of the legend colour } break; } /* FALL_THROUGH */ default: if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); /* Anything that is not an industry or a company is using normal process */ GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); DrawString(x + text_left, x + text_right, y, tbl->legend); break; } GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, legend_colour); // Legend colour y += row_height; } } } } /** * Select a new map type. * @param map_type New map type. */ void SmallMapWindow::SwitchMapType(SmallMapType map_type) { this->RaiseWidget(this->map_type + WID_SM_CONTOUR); this->map_type = map_type; this->LowerWidget(this->map_type + WID_SM_CONTOUR); this->SetupWidgetData(); if (map_type == SMT_LINKSTATS) this->overlay->RebuildCache(); this->SetDirty(); } /** * Get the number of rows in the legend from the number of columns. Those * are at least min_number_of_fixed_rows and possibly more if there are so * many cargoes, industry types or companies that they won't fit in the * available space. * @param columns Number of columns in the legend. * @return Number of rows needed for everything to fit in. */ inline uint SmallMapWindow::GetNumberRowsLegend(uint columns) const { /* Reserve one column for link colours */ uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1); uint num_rows_others = CeilDiv(max(_smallmap_industry_count, _smallmap_company_count), columns); return max(this->min_number_of_fixed_rows, max(num_rows_linkstats, num_rows_others)); } /** * Select and toggle a legend item. When CTRL is pressed, disable all other * items in the group defined by begin_legend_item and end_legend_item and * keep the clicked one enabled even if it was already enabled before. If * the other items in the group are all disabled already and CTRL is pressed * enable them instead. * @param click_pos the index of the item being selected * @param legend the legend from which we select * @param end_legend_item index one past the last item in the group to be inverted * @param begin_legend_item index of the first item in the group to be inverted */ void SmallMapWindow::SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item) { if (_ctrl_pressed) { /* Disable all, except the clicked one */ bool changes = false; for (int i = begin_legend_item; i != end_legend_item; i++) { bool new_state = (i == click_pos); if (legend[i].show_on_map != new_state) { changes = true; legend[i].show_on_map = new_state; } } if (!changes) { /* Nothing changed? Then show all (again). */ for (int i = begin_legend_item; i != end_legend_item; i++) { legend[i].show_on_map = true; } } } else { legend[click_pos].show_on_map = !legend[click_pos].show_on_map; } } /** * Set the link graph overlay cargo mask from the legend. */ void SmallMapWindow::SetOverlayCargoMask() { uint32 cargo_mask = 0; for (int i = 0; i != _smallmap_cargo_count; ++i) { if (_legend_linkstats[i].show_on_map) SetBit(cargo_mask, _legend_linkstats[i].type); } this->overlay->SetCargoMask(cargo_mask); } /** * Determines the mouse position on the legend. * @param pt Mouse position. * @return Legend item under the mouse. */ int SmallMapWindow::GetPositionOnLegend(Point pt) { const NWidgetBase *wi = this->GetWidget(WID_SM_LEGEND); uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL; uint columns = this->GetNumberColumnsLegend(wi->current_x); uint number_of_rows = this->GetNumberRowsLegend(columns); if (line >= number_of_rows) return -1; bool rtl = _current_text_dir == TD_RTL; int x = pt.x - wi->pos_x; if (rtl) x = wi->current_x - x; uint column = (x - WD_FRAMERECT_LEFT) / this->column_width; return (column * number_of_rows) + line; } /* virtual */ void SmallMapWindow::OnMouseOver(Point pt, int widget) { IndustryType new_highlight = INVALID_INDUSTRYTYPE; if (widget == WID_SM_LEGEND && this->map_type == SMT_INDUSTRY) { int industry_pos = GetPositionOnLegend(pt); if (industry_pos >= 0 && industry_pos < _smallmap_industry_count) { new_highlight = _legend_from_industries[industry_pos].type; } } if (new_highlight != _smallmap_industry_highlight) { _smallmap_industry_highlight = new_highlight; this->refresh = _smallmap_industry_highlight != INVALID_INDUSTRYTYPE ? BLINK_PERIOD : FORCE_REFRESH_PERIOD; _smallmap_industry_highlight_state = true; this->SetDirty(); } } /* virtual */ void SmallMapWindow::OnClick(Point pt, int widget, int click_count) { /* User clicked something, notify the industry chain window to stop sending newly selected industries. */ InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES); switch (widget) { case WID_SM_MAP: { // Map window /* * XXX: scrolling with the left mouse button is done by subsequently * clicking with the left mouse button; clicking once centers the * large map at the selected point. So by unclicking the left mouse * button here, it gets reclicked during the next inputloop, which * would make it look like the mouse is being dragged, while it is * actually being (virtually) clicked every inputloop. */ _left_button_clicked = false; const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); Window *w = FindWindowById(WC_MAIN_WINDOW, 0); int sub; pt = this->PixelToTile(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub); ScrollWindowTo(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, -1, w); this->SetDirty(); break; } case WID_SM_ZOOM_IN: case WID_SM_ZOOM_OUT: { const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); Point pt = {wid->current_x / 2, wid->current_y / 2}; this->SetZoomLevel((widget == WID_SM_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; } case WID_SM_CONTOUR: // Show land contours case WID_SM_VEHICLES: // Show vehicles case WID_SM_INDUSTRIES: // Show industries case WID_SM_LINKSTATS: // Show route map case WID_SM_ROUTES: // Show transport routes case WID_SM_VEGETATION: // Show vegetation case WID_SM_OWNERS: // Show land owners this->SwitchMapType((SmallMapType)(widget - WID_SM_CONTOUR)); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; case WID_SM_CENTERMAP: // Center the smallmap again this->SmallMapCenterOnCurrentPos(); this->HandleButtonClick(WID_SM_CENTERMAP); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; case WID_SM_TOGGLETOWNNAME: // Toggle town names this->show_towns = !this->show_towns; this->SetWidgetLoweredState(WID_SM_TOGGLETOWNNAME, this->show_towns); this->SetDirty(); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; case WID_SM_LEGEND: // Legend if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) { int click_pos = this->GetPositionOnLegend(pt); if (click_pos < 0) break; /* If industry type small map*/ if (this->map_type == SMT_INDUSTRY) { /* If click on industries label, find right industry type and enable/disable it. */ if (click_pos < _smallmap_industry_count) { this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count); } } else if (this->map_type == SMT_LINKSTATS) { if (click_pos < _smallmap_cargo_count) { this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count); this->SetOverlayCargoMask(); } } else if (this->map_type == SMT_OWNER) { if (click_pos < _smallmap_company_count) { this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES); } } this->SetDirty(); } break; case WID_SM_ENABLE_ALL: /* FALL THROUGH */ case WID_SM_DISABLE_ALL: { LegendAndColour *tbl = NULL; switch (this->map_type) { case SMT_INDUSTRY: tbl = _legend_from_industries; break; case SMT_OWNER: tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]); break; case SMT_LINKSTATS: tbl = _legend_linkstats; break; default: NOT_REACHED(); } for (;!tbl->end && tbl->legend != STR_LINKGRAPH_LEGEND_UNUSED; ++tbl) { tbl->show_on_map = (widget == WID_SM_ENABLE_ALL); } if (this->map_type == SMT_LINKSTATS) this->SetOverlayCargoMask(); this->SetDirty(); break; } case WID_SM_SHOW_HEIGHT: // Enable/disable showing of heightmap. _smallmap_show_heightmap = !_smallmap_show_heightmap; this->SetWidgetLoweredState(WID_SM_SHOW_HEIGHT, _smallmap_show_heightmap); this->SetDirty(); break; } } /** * Some data on this window has become invalid. * @param data Information about the changed data. * - data = 0: Displayed industries at the industry chain window have changed. * - data = 1: Companies have changed. * - data = 2: Cheat changing the maximum heightlevel has been used, rebuild our heightlevel-to-colour index * @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 SmallMapWindow::OnInvalidateData(int data, bool gui_scope) { if (!gui_scope) return; switch (data) { case 1: /* The owner legend has already been rebuilt. */ this->ReInit(); break; case 0: { extern uint64 _displayed_industries; if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY); for (int i = 0; i != _smallmap_industry_count; i++) { _legend_from_industries[i].show_on_map = HasBit(_displayed_industries, _legend_from_industries[i].type); } break; } case 2: this->RebuildColourIndexIfNecessary(); break; default: NOT_REACHED(); } this->SetDirty(); } /* virtual */ bool SmallMapWindow::OnRightClick(Point pt, int widget) { if (widget != WID_SM_MAP || _scrolling_viewport) return false; _scrolling_viewport = true; return true; } /* virtual */ void SmallMapWindow::OnMouseWheel(int wheel) { if (_settings_client.gui.scrollwheel_scrolling == 0) { const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); int cursor_x = _cursor.pos.x - this->left - wid->pos_x; int cursor_y = _cursor.pos.y - this->top - wid->pos_y; if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) { Point pt = {cursor_x, cursor_y}; this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt); } } } /* virtual */ void SmallMapWindow::OnTick() { /* Update the window every now and then */ if (--this->refresh != 0) return; if (this->map_type == SMT_LINKSTATS) { uint32 company_mask = this->GetOverlayCompanyMask(); if (this->overlay->GetCompanyMask() != company_mask) { this->overlay->SetCompanyMask(company_mask); } else { this->overlay->RebuildCache(); } } _smallmap_industry_highlight_state = !_smallmap_industry_highlight_state; this->refresh = _smallmap_industry_highlight != INVALID_INDUSTRYTYPE ? BLINK_PERIOD : FORCE_REFRESH_PERIOD; this->SetDirty(); } /** * Set new #scroll_x, #scroll_y, and #subscroll values after limiting them such that the center * of the smallmap always contains a part of the map. * @param sx Proposed new #scroll_x * @param sy Proposed new #scroll_y * @param sub Proposed new #subscroll */ void SmallMapWindow::SetNewScroll(int sx, int sy, int sub) { const NWidgetBase *wi = this->GetWidget(WID_SM_MAP); Point hv = InverseRemapCoords(wi->current_x * ZOOM_LVL_BASE * TILE_SIZE / 2, wi->current_y * ZOOM_LVL_BASE * TILE_SIZE / 2); hv.x *= this->zoom; hv.y *= this->zoom; if (sx < -hv.x) { sx = -hv.x; sub = 0; } if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) { sx = MapMaxX() * TILE_SIZE - hv.x; sub = 0; } if (sy < -hv.y) { sy = -hv.y; sub = 0; } if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) { sy = MapMaxY() * TILE_SIZE - hv.y; sub = 0; } this->scroll_x = sx; this->scroll_y = sy; this->subscroll = sub; if (this->map_type == SMT_LINKSTATS) this->overlay->RebuildCache(); } /* virtual */ void SmallMapWindow::OnScroll(Point delta) { _cursor.fix_at = true; /* While tile is at (delta.x, delta.y)? */ int sub; Point pt = this->PixelToTile(delta.x, delta.y, &sub); this->SetNewScroll(this->scroll_x + pt.x * TILE_SIZE, this->scroll_y + pt.y * TILE_SIZE, sub); this->SetDirty(); } /** * Center the small map on the current center of the viewport. */ void SmallMapWindow::SmallMapCenterOnCurrentPos() { const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; Point viewport_center = TranslateXYToTileCoord(vp, vp->left + vp->width / 2, vp->top + vp->height / 2); int sub; const NWidgetBase *wid = this->GetWidget(WID_SM_MAP); Point sxy = this->ComputeScroll(viewport_center.x / (int)TILE_SIZE, viewport_center.y / (int)TILE_SIZE, max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub); this->SetNewScroll(sxy.x, sxy.y, sub); this->SetDirty(); } /** * Get the center of the given station as point on the screen in the smallmap window. * @param st Station to find in the smallmap. * @return Point with coordinates of the station. */ Point SmallMapWindow::GetStationMiddle(const Station *st) const { int x = (st->rect.right + st->rect.left + 1) / 2; int y = (st->rect.bottom + st->rect.top + 1) / 2; Point ret = this->RemapTile(x, y); /* Same magic 3 as in DrawVehicles; that's where I got it from. * No idea what it is, but without it the result looks bad. */ ret.x -= 3 + this->subscroll; return ret; } SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR; bool SmallMapWindow::show_towns = true; int SmallMapWindow::max_heightlevel = -1; /** * Custom container class for displaying smallmap with a vertically resizing legend panel. * The legend panel has a smallest height that depends on its width. Standard containers cannot handle this case. * * @note The container assumes it has two children, the first is the display, the second is the bar with legends and selection image buttons. * Both children should be both horizontally and vertically resizable and horizontally fillable. * The bar should have a minimal size with a zero-size legends display. Child padding is not supported. */ class NWidgetSmallmapDisplay : public NWidgetContainer { const SmallMapWindow *smallmap_window; ///< Window manager instance. public: NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL) { this->smallmap_window = NULL; } virtual void SetupSmallestSize(Window *w, bool init_array) { NWidgetBase *display = this->head; NWidgetBase *bar = display->next; display->SetupSmallestSize(w, init_array); bar->SetupSmallestSize(w, init_array); this->smallmap_window = dynamic_cast(w); assert(this->smallmap_window != NULL); this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth()); this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns)); this->fill_x = max(display->fill_x, bar->fill_x); this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y); this->resize_x = max(display->resize_x, bar->resize_x); this->resize_y = min(display->resize_y, bar->resize_y); } virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { this->pos_x = x; this->pos_y = y; this->current_x = given_width; this->current_y = given_height; NWidgetBase *display = this->head; NWidgetBase *bar = display->next; if (sizing == ST_SMALLEST) { this->smallest_x = given_width; this->smallest_y = given_height; /* Make display and bar exactly equal to their minimal size. */ display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl); bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl); } uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x))); uint display_height = given_height - bar_height; display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl); bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl); } virtual NWidgetCore *GetWidgetFromPos(int x, int y) { if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y); if (widget != NULL) return widget; } return NULL; } virtual void Draw(const Window *w) { for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w); } }; /** Widget parts of the smallmap display. */ static const NWidgetPart _nested_smallmap_display[] = { NWidget(WWT_PANEL, COLOUR_BROWN, WID_SM_MAP_BORDER), NWidget(WWT_INSET, COLOUR_BROWN, WID_SM_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(), EndContainer(), }; /** Widget parts of the smallmap legend bar + image buttons. */ static const NWidgetPart _nested_smallmap_bar[] = { NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SM_LEGEND), SetResize(1, 1), NWidget(NWID_VERTICAL), /* Top button row. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_CENTERMAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_BLANK), SetDataTip(SPR_DOT_SMALL, STR_NULL), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_CONTOUR), SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEHICLES), SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_INDUSTRIES), SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1), EndContainer(), /* Bottom button row. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_SM_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_TOGGLETOWNNAME), SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_LINKSTATS), SetDataTip(SPR_IMG_CARGOFLOW, STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_ROUTES), SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_VEGETATION), SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_BROWN, WID_SM_OWNERS), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1), EndContainer(), NWidget(NWID_SPACER), SetResize(0, 1), EndContainer(), EndContainer(), EndContainer(), }; static NWidgetBase *SmallMapDisplay(int *biggest_index) { NWidgetContainer *map_display = new NWidgetSmallmapDisplay; MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display); MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display); return map_display; } static const NWidgetPart _nested_smallmap_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SM_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons. /* Bottom button row and resize box. */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SM_SELECT_BUTTONS), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_SM_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SM_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT), NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), }; static WindowDesc _smallmap_desc( WDP_AUTO, "smallmap", 484, 314, WC_SMALLMAP, WC_NONE, 0, _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets) ); /** * Show the smallmap window. */ void ShowSmallMap() { AllocateWindowDescFront(&_smallmap_desc, 0); } /** * Scrolls the main window to given coordinates. * @param x x coordinate * @param y y coordinate * @param z z coordinate; -1 to scroll to terrain height * @param instant scroll instantly (meaningful only when smooth_scrolling is active) * @return did the viewport position change? */ bool ScrollMainWindowTo(int x, int y, int z, bool instant) { bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant); /* If a user scrolls to a tile (via what way what so ever) and already is on * that tile (e.g.: pressed twice), move the smallmap to that location, * so you directly see where you are on the smallmap. */ if (res) return res; SmallMapWindow *w = dynamic_cast(FindWindowById(WC_SMALLMAP, 0)); if (w != NULL) w->SmallMapCenterOnCurrentPos(); return res; } openttd-1.5.3/src/object_base.h0000644000000000000000000000572712627373435015122 0ustar rootroot/* $Id: object_base.h 25844 2013-10-12 16:35:50Z frosch $ */ /* * 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 object_base.h Base for all objects. */ #ifndef OBJECT_BASE_H #define OBJECT_BASE_H #include "core/pool_type.hpp" #include "object_type.h" #include "tilearea_type.h" #include "town_type.h" #include "date_type.h" typedef Pool ObjectPool; extern ObjectPool _object_pool; /** An object, such as transmitter, on the map. */ struct Object : ObjectPool::PoolItem<&_object_pool> { ObjectType type; ///< Type of the object Town *town; ///< Town the object is built in TileArea location; ///< Location of the object Date build_date; ///< Date of construction byte colour; ///< Colour of the object, for display purpose byte view; ///< The view setting for this object /** Make sure the object isn't zeroed. */ Object() {} /** Make sure the right destructor is called as well! */ ~Object() {} static Object *GetByTile(TileIndex tile); /** * Increment the count of objects for this type. * @param type ObjectType to increment * @pre type < NUM_OBJECTS */ static inline void IncTypeCount(ObjectType type) { assert(type < NUM_OBJECTS); counts[type]++; } /** * Decrement the count of objects for this type. * @param type ObjectType to decrement * @pre type < NUM_OBJECTS */ static inline void DecTypeCount(ObjectType type) { assert(type < NUM_OBJECTS); counts[type]--; } /** * Get the count of objects for this type. * @param type ObjectType to query * @pre type < NUM_OBJECTS */ static inline uint16 GetTypeCount(ObjectType type) { assert(type < NUM_OBJECTS); return counts[type]; } /** Resets object counts. */ static inline void ResetTypeCounts() { memset(&counts, 0, sizeof(counts)); } protected: static uint16 counts[NUM_OBJECTS]; ///< Number of objects per type ingame }; #define FOR_ALL_OBJECTS_FROM(var, start) FOR_ALL_ITEMS_FROM(Object, object_index, var, start) #define FOR_ALL_OBJECTS(var) FOR_ALL_OBJECTS_FROM(var, 0) /** * Keeps track of removed objects during execution/testruns of commands. */ struct ClearedObjectArea { TileIndex first_tile; ///< The first tile being cleared, which then causes the whole object to be cleared. TileArea area; ///< The area of the object. }; ClearedObjectArea *FindClearedObject(TileIndex tile); extern SmallVector _cleared_object_areas; #endif /* OBJECT_BASE_H */ openttd-1.5.3/src/fontcache.cpp0000644000000000000000000005200012627373435015131 0ustar rootroot/* $Id: fontcache.cpp 27187 2015-03-15 12:19:58Z frosch $ */ /* * 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 fontcache.cpp Cache for characters from fonts. */ #include "stdafx.h" #include "fontcache.h" #include "fontdetection.h" #include "blitter/factory.hpp" #include "core/math_func.hpp" #include "core/smallmap_type.hpp" #include "strings_func.h" #include "zoom_type.h" #include "gfx_layout.h" #include "zoom_func.h" #include "table/sprites.h" #include "table/control_codes.h" #include "table/unicode.h" #include "safeguards.h" static const int ASCII_LETTERSTART = 32; ///< First printable ASCII letter. static const int MAX_FONT_SIZE = 72; ///< Maximum font size. /** Default heights for the different sizes of fonts. */ static const int _default_font_height[FS_END] = {10, 6, 18, 10}; static const int _default_font_ascender[FS_END] = { 8, 5, 15, 8}; /** * Create a new font cache. * @param fs The size of the font. */ FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs), height(_default_font_height[fs]), ascender(_default_font_ascender[fs]), descender(_default_font_ascender[fs] - _default_font_height[fs]), units_per_em(1) { assert(parent == NULL || this->fs == parent->fs); FontCache::caches[this->fs] = this; Layouter::ResetFontCache(this->fs); } /** Clean everything up. */ FontCache::~FontCache() { assert(this->fs == parent->fs); FontCache::caches[this->fs] = this->parent; Layouter::ResetFontCache(this->fs); } /** * Get height of a character for a given font size. * @param size Font size to get height of * @return Height of characters in the given font (pixels) */ int GetCharacterHeight(FontSize size) { return FontCache::Get(size)->GetHeight(); } /** Font cache for fonts that are based on a freetype font. */ class SpriteFontCache : public FontCache { private: SpriteID **glyph_to_spriteid_map; ///< Mapping of glyphs to sprite IDs. void ClearGlyphToSpriteMap(); public: SpriteFontCache(FontSize fs); ~SpriteFontCache(); virtual SpriteID GetUnicodeGlyph(WChar key); virtual void SetUnicodeGlyph(WChar key, SpriteID sprite); virtual void InitializeUnicodeGlyphMap(); virtual void ClearFontCache(); virtual const Sprite *GetGlyph(GlyphID key); virtual uint GetGlyphWidth(GlyphID key); virtual int GetHeight() const; virtual bool GetDrawGlyphShadow(); virtual GlyphID MapCharToGlyph(WChar key) { assert(IsPrintable(key)); return SPRITE_GLYPH | key; } virtual const void *GetFontTable(uint32 tag, size_t &length) { length = 0; return NULL; } virtual const char *GetFontName() { return "sprite"; } }; /** * Create a new sprite font cache. * @param fs The font size to create the cache for. */ SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(NULL) { this->InitializeUnicodeGlyphMap(); } /** * Free everything we allocated. */ SpriteFontCache::~SpriteFontCache() { this->ClearGlyphToSpriteMap(); } SpriteID SpriteFontCache::GetUnicodeGlyph(GlyphID key) { if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) return 0; return this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)]; } void SpriteFontCache::SetUnicodeGlyph(GlyphID key, SpriteID sprite) { if (this->glyph_to_spriteid_map == NULL) this->glyph_to_spriteid_map = CallocT(256); if (this->glyph_to_spriteid_map[GB(key, 8, 8)] == NULL) this->glyph_to_spriteid_map[GB(key, 8, 8)] = CallocT(256); this->glyph_to_spriteid_map[GB(key, 8, 8)][GB(key, 0, 8)] = sprite; } void SpriteFontCache::InitializeUnicodeGlyphMap() { /* Clear out existing glyph map if it exists */ this->ClearGlyphToSpriteMap(); SpriteID base; switch (this->fs) { default: NOT_REACHED(); case FS_MONO: // Use normal as default for mono spaced font, i.e. FALL THROUGH case FS_NORMAL: base = SPR_ASCII_SPACE; break; case FS_SMALL: base = SPR_ASCII_SPACE_SMALL; break; case FS_LARGE: base = SPR_ASCII_SPACE_BIG; break; } for (uint i = ASCII_LETTERSTART; i < 256; i++) { SpriteID sprite = base + i - ASCII_LETTERSTART; if (!SpriteExists(sprite)) continue; this->SetUnicodeGlyph(i, sprite); this->SetUnicodeGlyph(i + SCC_SPRITE_START, sprite); } for (uint i = 0; i < lengthof(_default_unicode_map); i++) { byte key = _default_unicode_map[i].key; if (key == CLRA) { /* Clear the glyph. This happens if the glyph at this code point * is non-standard and should be accessed by an SCC_xxx enum * entry only. */ this->SetUnicodeGlyph(_default_unicode_map[i].code, 0); } else { SpriteID sprite = base + key - ASCII_LETTERSTART; this->SetUnicodeGlyph(_default_unicode_map[i].code, sprite); } } } /** * Clear the glyph to sprite mapping. */ void SpriteFontCache::ClearGlyphToSpriteMap() { if (this->glyph_to_spriteid_map == NULL) return; for (uint i = 0; i < 256; i++) { free(this->glyph_to_spriteid_map[i]); } free(this->glyph_to_spriteid_map); this->glyph_to_spriteid_map = NULL; } void SpriteFontCache::ClearFontCache() { Layouter::ResetFontCache(this->fs); } const Sprite *SpriteFontCache::GetGlyph(GlyphID key) { SpriteID sprite = this->GetUnicodeGlyph(key); if (sprite == 0) sprite = this->GetUnicodeGlyph('?'); return GetSprite(sprite, ST_FONT); } uint SpriteFontCache::GetGlyphWidth(GlyphID key) { SpriteID sprite = this->GetUnicodeGlyph(key); if (sprite == 0) sprite = this->GetUnicodeGlyph('?'); return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + ScaleGUITrad(this->fs != FS_NORMAL ? 1 : 0) : 0; } int SpriteFontCache::GetHeight() const { return ScaleGUITrad(this->height); } bool SpriteFontCache::GetDrawGlyphShadow() { return false; } /* static */ FontCache *FontCache::caches[FS_END] = { new SpriteFontCache(FS_NORMAL), new SpriteFontCache(FS_SMALL), new SpriteFontCache(FS_LARGE), new SpriteFontCache(FS_MONO) }; #ifdef WITH_FREETYPE #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_TRUETYPE_TABLES_H /** Font cache for fonts that are based on a freetype font. */ class FreeTypeFontCache : public FontCache { private: FT_Face face; ///< The font face associated with this font. typedef SmallMap > FontTable; ///< Table with font table cache FontTable font_tables; ///< Cached font tables. /** Container for information about a glyph. */ struct GlyphEntry { Sprite *sprite; ///< The loaded sprite. byte width; ///< The width of the glyph. bool duplicate; ///< Whether this glyph entry is a duplicate, i.e. may this be freed? }; /** * The glyph cache. This is structured to reduce memory consumption. * 1) There is a 'segment' table for each font size. * 2) Each segment table is a discrete block of characters. * 3) Each block contains 256 (aligned) characters sequential characters. * * The cache is accessed in the following way: * For character 0x0041 ('A'): glyph_to_sprite[0x00][0x41] * For character 0x20AC (Euro): glyph_to_sprite[0x20][0xAC] * * Currently only 256 segments are allocated, "limiting" us to 65536 characters. * This can be simply changed in the two functions Get & SetGlyphPtr. */ GlyphEntry **glyph_to_sprite; GlyphEntry *GetGlyphPtr(GlyphID key); void SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate = false); public: FreeTypeFontCache(FontSize fs, FT_Face face, int pixels); ~FreeTypeFontCache(); virtual SpriteID GetUnicodeGlyph(WChar key) { return this->parent->GetUnicodeGlyph(key); } virtual void SetUnicodeGlyph(WChar key, SpriteID sprite) { this->parent->SetUnicodeGlyph(key, sprite); } virtual void InitializeUnicodeGlyphMap() { this->parent->InitializeUnicodeGlyphMap(); } virtual void ClearFontCache(); virtual const Sprite *GetGlyph(GlyphID key); virtual uint GetGlyphWidth(GlyphID key); virtual bool GetDrawGlyphShadow(); virtual GlyphID MapCharToGlyph(WChar key); virtual const void *GetFontTable(uint32 tag, size_t &length); virtual const char *GetFontName() { return face->family_name; } }; FT_Library _library = NULL; FreeTypeSettings _freetype; static const byte FACE_COLOUR = 1; static const byte SHADOW_COLOUR = 2; /** * Create a new FreeTypeFontCache. * @param fs The font size that is going to be cached. * @param face The font that has to be loaded. * @param pixels The number of pixels this font should be high. */ FreeTypeFontCache::FreeTypeFontCache(FontSize fs, FT_Face face, int pixels) : FontCache(fs), face(face), glyph_to_sprite(NULL) { assert(face != NULL); if (pixels == 0) { /* Try to determine a good height based on the minimal height recommended by the font. */ pixels = _default_font_height[this->fs]; TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head); if (head != NULL) { /* Font height is minimum height plus the difference between the default * height for this font size and the small size. */ int diff = _default_font_height[this->fs] - _default_font_height[FS_SMALL]; pixels = Clamp(min(head->Lowest_Rec_PPEM, 20) + diff, _default_font_height[this->fs], MAX_FONT_SIZE); } } FT_Error err = FT_Set_Pixel_Sizes(this->face, 0, pixels); if (err != FT_Err_Ok) { /* Find nearest size to that requested */ FT_Bitmap_Size *bs = this->face->available_sizes; int i = this->face->num_fixed_sizes; if (i > 0) { // In pathetic cases one might get no fixed sizes at all. int n = bs->height; FT_Int chosen = 0; for (; --i; bs++) { if (abs(pixels - bs->height) >= abs(pixels - n)) continue; n = bs->height; chosen = this->face->num_fixed_sizes - i; } /* Don't use FT_Set_Pixel_Sizes here - it might give us another * error, even though the size is available (FS#5885). */ err = FT_Select_Size(this->face, chosen); } } if (err == FT_Err_Ok) { this->units_per_em = this->face->units_per_EM; this->ascender = this->face->size->metrics.ascender >> 6; this->descender = this->face->size->metrics.descender >> 6; this->height = this->ascender - this->descender; } else { /* Both FT_Set_Pixel_Sizes and FT_Select_Size failed. */ DEBUG(freetype, 0, "Font size selection failed. Using FontCache defaults."); } } /** * Loads the freetype font. * First type to load the fontname as if it were a path. If that fails, * try to resolve the filename of the font using fontconfig, where the * format is 'font family name' or 'font family name, font style'. * @param fs The font size to load. */ static void LoadFreeTypeFont(FontSize fs) { FreeTypeSubSetting *settings = NULL; switch (fs) { default: NOT_REACHED(); case FS_SMALL: settings = &_freetype.small; break; case FS_NORMAL: settings = &_freetype.medium; break; case FS_LARGE: settings = &_freetype.large; break; case FS_MONO: settings = &_freetype.mono; break; } if (StrEmpty(settings->font)) return; if (_library == NULL) { if (FT_Init_FreeType(&_library) != FT_Err_Ok) { ShowInfoF("Unable to initialize FreeType, using sprite fonts instead"); return; } DEBUG(freetype, 2, "Initialized"); } FT_Face face = NULL; FT_Error error = FT_New_Face(_library, settings->font, 0, &face); if (error != FT_Err_Ok) error = GetFontByFaceName(settings->font, &face); if (error == FT_Err_Ok) { DEBUG(freetype, 2, "Requested '%s', using '%s %s'", settings->font, face->family_name, face->style_name); /* Attempt to select the unicode character map */ error = FT_Select_Charmap(face, ft_encoding_unicode); if (error == FT_Err_Ok) goto found_face; // Success if (error == FT_Err_Invalid_CharMap_Handle) { /* Try to pick a different character map instead. We default to * the first map, but platform_id 0 encoding_id 0 should also * be unicode (strange system...) */ FT_CharMap found = face->charmaps[0]; int i; for (i = 0; i < face->num_charmaps; i++) { FT_CharMap charmap = face->charmaps[i]; if (charmap->platform_id == 0 && charmap->encoding_id == 0) { found = charmap; } } if (found != NULL) { error = FT_Set_Charmap(face, found); if (error == FT_Err_Ok) goto found_face; } } } FT_Done_Face(face); static const char *SIZE_TO_NAME[] = { "medium", "small", "large", "mono" }; ShowInfoF("Unable to use '%s' for %s font, FreeType reported error 0x%X, using sprite font instead", settings->font, SIZE_TO_NAME[fs], error); return; found_face: new FreeTypeFontCache(fs, face, settings->size); } /** * Free everything that was allocated for this font cache. */ FreeTypeFontCache::~FreeTypeFontCache() { FT_Done_Face(this->face); this->ClearFontCache(); for (FontTable::iterator iter = this->font_tables.Begin(); iter != this->font_tables.End(); iter++) { free(iter->second.second); } } /** * Reset cached glyphs. */ void FreeTypeFontCache::ClearFontCache() { if (this->glyph_to_sprite == NULL) return; for (int i = 0; i < 256; i++) { if (this->glyph_to_sprite[i] == NULL) continue; for (int j = 0; j < 256; j++) { if (this->glyph_to_sprite[i][j].duplicate) continue; free(this->glyph_to_sprite[i][j].sprite); } free(this->glyph_to_sprite[i]); } free(this->glyph_to_sprite); this->glyph_to_sprite = NULL; Layouter::ResetFontCache(this->fs); } FreeTypeFontCache::GlyphEntry *FreeTypeFontCache::GetGlyphPtr(GlyphID key) { if (this->glyph_to_sprite == NULL) return NULL; if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) return NULL; return &this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)]; } void FreeTypeFontCache::SetGlyphPtr(GlyphID key, const GlyphEntry *glyph, bool duplicate) { if (this->glyph_to_sprite == NULL) { DEBUG(freetype, 3, "Allocating root glyph cache for size %u", this->fs); this->glyph_to_sprite = CallocT(256); } if (this->glyph_to_sprite[GB(key, 8, 8)] == NULL) { DEBUG(freetype, 3, "Allocating glyph cache for range 0x%02X00, size %u", GB(key, 8, 8), this->fs); this->glyph_to_sprite[GB(key, 8, 8)] = CallocT(256); } DEBUG(freetype, 4, "Set glyph for unicode character 0x%04X, size %u", key, this->fs); this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].sprite = glyph->sprite; this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].width = glyph->width; this->glyph_to_sprite[GB(key, 8, 8)][GB(key, 0, 8)].duplicate = duplicate; } static void *AllocateFont(size_t size) { return MallocT(size); } /* Check if a glyph should be rendered with antialiasing */ static bool GetFontAAState(FontSize size) { /* AA is only supported for 32 bpp */ if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() != 32) return false; switch (size) { default: NOT_REACHED(); case FS_NORMAL: return _freetype.medium.aa; case FS_SMALL: return _freetype.small.aa; case FS_LARGE: return _freetype.large.aa; case FS_MONO: return _freetype.mono.aa; } } const Sprite *FreeTypeFontCache::GetGlyph(GlyphID key) { if ((key & SPRITE_GLYPH) != 0) return parent->GetGlyph(key); /* Check for the glyph in our cache */ GlyphEntry *glyph = this->GetGlyphPtr(key); if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite; FT_GlyphSlot slot = this->face->glyph; bool aa = GetFontAAState(this->fs); GlyphEntry new_glyph; if (key == 0) { GlyphID question_glyph = this->MapCharToGlyph('?'); if (question_glyph == 0) { /* The font misses the '?' character. Use built-in sprite. * Note: We cannot use the baseset as this also has to work in the bootstrap GUI. */ #define CPSET { 0, 0, 0, 0, 1 } #define CP___ { 0, 0, 0, 0, 0 } static SpriteLoader::CommonPixel builtin_questionmark_data[10 * 8] = { CP___, CP___, CPSET, CPSET, CPSET, CPSET, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, CP___, CP___, CP___, CPSET, CPSET, CP___, CP___, CP___, }; #undef CPSET #undef CP___ static const SpriteLoader::Sprite builtin_questionmark = { 10, // height 8, // width 0, // x_offs 0, // y_offs ST_FONT, builtin_questionmark_data }; Sprite *spr = BlitterFactory::GetCurrentBlitter()->Encode(&builtin_questionmark, AllocateFont); assert(spr != NULL); new_glyph.sprite = spr; new_glyph.width = spr->width + (this->fs != FS_NORMAL); this->SetGlyphPtr(key, &new_glyph, false); return new_glyph.sprite; } else { /* Use '?' for missing characters. */ this->GetGlyph(question_glyph); glyph = this->GetGlyphPtr(question_glyph); this->SetGlyphPtr(key, glyph, true); return glyph->sprite; } } FT_Load_Glyph(this->face, key, FT_LOAD_DEFAULT); FT_Render_Glyph(this->face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); /* Despite requesting a normal glyph, FreeType may have returned a bitmap */ aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */ uint width = max(1U, (uint)slot->bitmap.width + (this->fs == FS_NORMAL)); uint height = max(1U, (uint)slot->bitmap.rows + (this->fs == FS_NORMAL)); /* Limit glyph size to prevent overflows later on. */ if (width > 256 || height > 256) usererror("Font glyph is too large"); /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */ SpriteLoader::Sprite sprite; sprite.AllocateData(ZOOM_LVL_NORMAL, width * height); sprite.type = ST_FONT; sprite.width = width; sprite.height = height; sprite.x_offs = slot->bitmap_left; sprite.y_offs = this->ascender - slot->bitmap_top; /* Draw shadow for medium size */ if (this->fs == FS_NORMAL && !aa) { for (uint y = 0; y < (uint)slot->bitmap.rows; y++) { for (uint x = 0; x < (uint)slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR; sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } } for (uint y = 0; y < (uint)slot->bitmap.rows; y++) { for (uint x = 0; x < (uint)slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[x + y * sprite.width].m = FACE_COLOUR; sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont); new_glyph.width = slot->advance.x >> 6; this->SetGlyphPtr(key, &new_glyph); return new_glyph.sprite; } bool FreeTypeFontCache::GetDrawGlyphShadow() { return this->fs == FS_NORMAL && GetFontAAState(FS_NORMAL); } uint FreeTypeFontCache::GetGlyphWidth(GlyphID key) { if ((key & SPRITE_GLYPH) != 0) return this->parent->GetGlyphWidth(key); GlyphEntry *glyph = this->GetGlyphPtr(key); if (glyph == NULL || glyph->sprite == NULL) { this->GetGlyph(key); glyph = this->GetGlyphPtr(key); } return glyph->width; } GlyphID FreeTypeFontCache::MapCharToGlyph(WChar key) { assert(IsPrintable(key)); if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { return this->parent->MapCharToGlyph(key); } return FT_Get_Char_Index(this->face, key); } const void *FreeTypeFontCache::GetFontTable(uint32 tag, size_t &length) { const FontTable::iterator iter = this->font_tables.Find(tag); if (iter != this->font_tables.End()) { length = iter->second.first; return iter->second.second; } FT_ULong len = 0; FT_Byte *result = NULL; FT_Load_Sfnt_Table(this->face, tag, 0, NULL, &len); if (len > 0) { result = MallocT(len); FT_Load_Sfnt_Table(this->face, tag, 0, result, &len); } length = len; this->font_tables.Insert(tag, SmallPair(length, result)); return result; } #endif /* WITH_FREETYPE */ /** * (Re)initialize the freetype related things, i.e. load the non-sprite fonts. * @param monospace Whether to initialise the monospace or regular fonts. */ void InitFreeType(bool monospace) { for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) { if (monospace != (fs == FS_MONO)) continue; FontCache *fc = FontCache::Get(fs); if (fc->HasParent()) delete fc; #ifdef WITH_FREETYPE LoadFreeTypeFont(fs); #endif } } /** * Free everything allocated w.r.t. fonts. */ void UninitFreeType() { for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) { FontCache *fc = FontCache::Get(fs); if (fc->HasParent()) delete fc; } #ifdef WITH_FREETYPE FT_Done_FreeType(_library); _library = NULL; #endif /* WITH_FREETYPE */ } openttd-1.5.3/src/blitter/0000755000000000000000000000000012627373442014141 5ustar rootrootopenttd-1.5.3/src/blitter/32bpp_anim.hpp0000644000000000000000000000544412627373442016613 0ustar rootroot/* $Id: 32bpp_anim.hpp 26214 2014-01-02 23:52:13Z rubidium $ */ /* * 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 32bpp_anim.hpp A 32 bpp blitter with animation support. */ #ifndef BLITTER_32BPP_ANIM_HPP #define BLITTER_32BPP_ANIM_HPP #include "32bpp_optimized.hpp" /** The optimised 32 bpp blitter with palette animation. */ class Blitter_32bppAnim : public Blitter_32bppOptimized { protected: uint16 *anim_buf; ///< In this buffer we keep track of the 8bpp indexes so we can do palette animation int anim_buf_width; ///< The width of the animation buffer. int anim_buf_height; ///< The height of the animation buffer. Palette palette; ///< The current palette. public: Blitter_32bppAnim() : anim_buf(NULL), anim_buf_width(0), anim_buf_height(0) {} /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y); /* virtual */ int BufferSize(int width, int height); /* virtual */ void PaletteAnimate(const Palette &palette); /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); /* virtual */ const char *GetName() { return "32bpp-anim"; } /* virtual */ int GetBytesPerPixel() { return 6; } /* virtual */ void PostResize(); /** * Look up the colour in the current palette. */ inline Colour LookupColourInPalette(uint index) { return this->palette.palette[index]; } template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); }; /** Factory for the 32bpp blitter with animation. */ class FBlitter_32bppAnim : public BlitterFactory { public: FBlitter_32bppAnim() : BlitterFactory("32bpp-anim", "32bpp Animation Blitter (palette animation)") {} /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppAnim(); } }; #endif /* BLITTER_32BPP_ANIM_HPP */ openttd-1.5.3/src/blitter/factory.hpp0000644000000000000000000001312612627373442016324 0ustar rootroot/* $Id: factory.hpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 factory.hpp Factory to 'query' all available blitters. */ #ifndef BLITTER_FACTORY_HPP #define BLITTER_FACTORY_HPP #include "base.hpp" #include "../debug.h" #include "../string_func.h" #include "../core/string_compare_type.hpp" #include #if defined(WITH_COCOA) bool QZ_CanDisplay8bpp(); #endif /* defined(WITH_COCOA) */ /** * The base factory, keeping track of all blitters. */ class BlitterFactory { private: const char *name; ///< The name of the blitter factory. const char *description; ///< The description of the blitter. typedef std::map Blitters; ///< Map of blitter factories. /** * Get the map with currently known blitters. * @return The known blitters. */ static Blitters &GetBlitters() { static Blitters &s_blitters = *new Blitters(); return s_blitters; } /** * Get the currently active blitter. * @return The currently active blitter. */ static Blitter **GetActiveBlitter() { static Blitter *s_blitter = NULL; return &s_blitter; } protected: /** * Construct the blitter, and register it. * @param name The name of the blitter. * @param description A longer description for the blitter. * @param usable Whether the blitter is usable (on the current computer). For example for disabling SSE blitters when the CPU can't handle them. * @pre name != NULL. * @pre description != NULL. * @pre There is no blitter registered with this name. */ BlitterFactory(const char *name, const char *description, bool usable = true) : name(stredup(name)), description(stredup(description)) { if (usable) { /* * Only add when the blitter is usable. Do not bail out or * do more special things since the blitters are always * instantiated upon start anyhow and freed upon shutdown. */ std::pair P = GetBlitters().insert(Blitters::value_type(this->name, this)); assert(P.second); } else { DEBUG(driver, 1, "Not registering blitter %s as it is not usable", name); } } public: virtual ~BlitterFactory() { GetBlitters().erase(this->name); if (GetBlitters().empty()) delete &GetBlitters(); free(this->name); free(this->description); } /** * Find the requested blitter and return his class. * @param name the blitter to select. * @post Sets the blitter so GetCurrentBlitter() returns it too. */ static Blitter *SelectBlitter(const char *name) { BlitterFactory *b = GetBlitterFactory(name); if (b == NULL) return NULL; Blitter *newb = b->CreateInstance(); delete *GetActiveBlitter(); *GetActiveBlitter() = newb; DEBUG(driver, 1, "Successfully %s blitter '%s'", StrEmpty(name) ? "probed" : "loaded", newb->GetName()); return newb; } /** * Get the blitter factory with the given name. * @param name the blitter factory to select. * @return The blitter factory, or NULL when there isn't one with the wanted name. */ static BlitterFactory *GetBlitterFactory(const char *name) { #if defined(DEDICATED) const char *default_blitter = "null"; #else const char *default_blitter = "8bpp-optimized"; #if defined(WITH_COCOA) /* Some people reported lack of fullscreen support in 8 bpp mode. * While we prefer 8 bpp since it's faster, we will still have to test for support. */ if (!QZ_CanDisplay8bpp()) { /* The main display can't go to 8 bpp fullscreen mode. * We will have to switch to 32 bpp by default. */ default_blitter = "32bpp-anim"; } #endif /* defined(WITH_COCOA) */ #endif /* defined(DEDICATED) */ if (GetBlitters().size() == 0) return NULL; const char *bname = (StrEmpty(name)) ? default_blitter : name; Blitters::iterator it = GetBlitters().begin(); for (; it != GetBlitters().end(); it++) { BlitterFactory *b = (*it).second; if (strcasecmp(bname, b->name) == 0) { return b; } } return NULL; } /** * Get the current active blitter (always set by calling SelectBlitter). */ static Blitter *GetCurrentBlitter() { return *GetActiveBlitter(); } /** * Fill a buffer with information about the blitters. * @param p The buffer to fill. * @param last The last element of the buffer. * @return p The location till where we filled the buffer. */ static char *GetBlittersInfo(char *p, const char *last) { p += seprintf(p, last, "List of blitters:\n"); Blitters::iterator it = GetBlitters().begin(); for (; it != GetBlitters().end(); it++) { BlitterFactory *b = (*it).second; p += seprintf(p, last, "%18s: %s\n", b->name, b->GetDescription()); } p += seprintf(p, last, "\n"); return p; } /** * Get the long, human readable, name for the Blitter-class. */ const char *GetName() const { return this->name; } /** * Get a nice description of the blitter-class. */ const char *GetDescription() const { return this->description; } /** * Create an instance of this Blitter-class. */ virtual Blitter *CreateInstance() = 0; }; extern char *_ini_blitter; extern bool _blitter_autodetected; #endif /* BLITTER_FACTORY_HPP */ openttd-1.5.3/src/blitter/8bpp_base.cpp0000644000000000000000000001007112627373442016507 0ustar rootroot/* $Id: 8bpp_base.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 8bpp_base.cpp Implementation of the base for all 8 bpp blitters. */ #include "../stdafx.h" #include "../gfx_func.h" #include "8bpp_base.hpp" #include "../safeguards.h" void Blitter_8bppBase::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) { const uint8 *ctab = GetNonSprite(pal, ST_RECOLOUR) + 1; do { for (int i = 0; i != width; i++) *((uint8 *)dst + i) = ctab[((uint8 *)dst)[i]]; dst = (uint8 *)dst + _screen.pitch; } while (--height); } void *Blitter_8bppBase::MoveTo(void *video, int x, int y) { return (uint8 *)video + x + y * _screen.pitch; } void Blitter_8bppBase::SetPixel(void *video, int x, int y, uint8 colour) { *((uint8 *)video + x + y * _screen.pitch) = colour; } void Blitter_8bppBase::DrawRect(void *video, int width, int height, uint8 colour) { do { memset(video, colour, width); video = (uint8 *)video + _screen.pitch; } while (--height); } void Blitter_8bppBase::CopyFromBuffer(void *video, const void *src, int width, int height) { uint8 *dst = (uint8 *)video; const uint8 *usrc = (const uint8 *)src; for (; height > 0; height--) { memcpy(dst, usrc, width * sizeof(uint8)); usrc += width; dst += _screen.pitch; } } void Blitter_8bppBase::CopyToBuffer(const void *video, void *dst, int width, int height) { uint8 *udst = (uint8 *)dst; const uint8 *src = (const uint8 *)video; for (; height > 0; height--) { memcpy(udst, src, width * sizeof(uint8)); src += _screen.pitch; udst += width; } } void Blitter_8bppBase::CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) { uint8 *udst = (uint8 *)dst; const uint8 *src = (const uint8 *)video; for (; height > 0; height--) { memcpy(udst, src, width * sizeof(uint8)); src += _screen.pitch; udst += dst_pitch; } } void Blitter_8bppBase::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) { const uint8 *src; uint8 *dst; if (scroll_y > 0) { /* Calculate pointers */ dst = (uint8 *)video + left + (top + height - 1) * _screen.pitch; src = dst - scroll_y * _screen.pitch; /* Decrease height and increase top */ top += scroll_y; height -= scroll_y; assert(height > 0); /* Adjust left & width */ if (scroll_x >= 0) { dst += scroll_x; left += scroll_x; width -= scroll_x; } else { src -= scroll_x; width += scroll_x; } for (int h = height; h > 0; h--) { memcpy(dst, src, width * sizeof(uint8)); src -= _screen.pitch; dst -= _screen.pitch; } } else { /* Calculate pointers */ dst = (uint8 *)video + left + top * _screen.pitch; src = dst - scroll_y * _screen.pitch; /* Decrease height. (scroll_y is <=0). */ height += scroll_y; assert(height > 0); /* Adjust left & width */ if (scroll_x >= 0) { dst += scroll_x; left += scroll_x; width -= scroll_x; } else { src -= scroll_x; width += scroll_x; } /* the y-displacement may be 0 therefore we have to use memmove, * because source and destination may overlap */ for (int h = height; h > 0; h--) { memmove(dst, src, width * sizeof(uint8)); src += _screen.pitch; dst += _screen.pitch; } } } int Blitter_8bppBase::BufferSize(int width, int height) { return width * height; } void Blitter_8bppBase::PaletteAnimate(const Palette &palette) { /* Video backend takes care of the palette animation */ } Blitter::PaletteAnimation Blitter_8bppBase::UsePaletteAnimation() { return Blitter::PALETTE_ANIMATION_VIDEO_BACKEND; } openttd-1.5.3/src/blitter/32bpp_base.hpp0000644000000000000000000001347512627373442016604 0ustar rootroot/* $Id: 32bpp_base.hpp 26463 2014-04-13 19:22:23Z peter1138 $ */ /* * 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 32bpp_base.hpp Base for all 32 bits blitters. */ #ifndef BLITTER_32BPP_BASE_HPP #define BLITTER_32BPP_BASE_HPP #include "base.hpp" #include "../core/bitmath_func.hpp" #include "../core/math_func.hpp" #include "../gfx_func.h" /** Base for all 32bpp blitters. */ class Blitter_32bppBase : public Blitter { public: /* virtual */ uint8 GetScreenDepth() { return 32; } /* virtual */ void *MoveTo(void *video, int x, int y); /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); /* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch); /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y); /* virtual */ int BufferSize(int width, int height); /* virtual */ void PaletteAnimate(const Palette &palette); /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); /* virtual */ int GetBytesPerPixel() { return 4; } /** * Look up the colour in the current palette. */ static inline Colour LookupColourInPalette(uint index) { return _cur_palette.palette[index]; } /** * Compose a colour based on RGBA values and the current pixel value. */ static inline Colour ComposeColourRGBANoCheck(uint r, uint g, uint b, uint a, Colour current) { uint cr = current.r; uint cg = current.g; uint cb = current.b; /* The 256 is wrong, it should be 255, but 256 is much faster... */ return Colour( ((int)(r - cr) * a) / 256 + cr, ((int)(g - cg) * a) / 256 + cg, ((int)(b - cb) * a) / 256 + cb); } /** * Compose a colour based on RGBA values and the current pixel value. * Handles fully transparent and solid pixels in a special (faster) way. */ static inline Colour ComposeColourRGBA(uint r, uint g, uint b, uint a, Colour current) { if (a == 0) return current; if (a >= 255) return Colour(r, g, b); return ComposeColourRGBANoCheck(r, g, b, a, current); } /** * Compose a colour based on Pixel value, alpha value, and the current pixel value. */ static inline Colour ComposeColourPANoCheck(Colour colour, uint a, Colour current) { uint r = colour.r; uint g = colour.g; uint b = colour.b; return ComposeColourRGBANoCheck(r, g, b, a, current); } /** * Compose a colour based on Pixel value, alpha value, and the current pixel value. * Handles fully transparent and solid pixels in a special (faster) way. */ static inline Colour ComposeColourPA(Colour colour, uint a, Colour current) { if (a == 0) return current; if (a >= 255) { colour.a = 255; return colour; } return ComposeColourPANoCheck(colour, a, current); } /** * Make a pixel looks like it is transparent. * @param colour the colour already on the screen. * @param nom the amount of transparency, nominator, makes colour lighter. * @param denom denominator, makes colour darker. * @return the new colour for the screen. */ static inline Colour MakeTransparent(Colour colour, uint nom, uint denom = 256) { uint r = colour.r; uint g = colour.g; uint b = colour.b; return Colour(r * nom / denom, g * nom / denom, b * nom / denom); } /** * Make a colour dark grey, for specialized 32bpp remapping. * @param r red component * @param g green component * @param b blue component * @return the brightness value of the new colour, now dark grey. */ static inline uint8 MakeDark(uint8 r, uint8 g, uint8 b) { /* Magic-numbers are ~66% of those used in MakeGrey() */ return ((r * 13063) + (g * 25647) + (b * 4981)) / 65536; } /** * Make a colour grey - based. * @param colour the colour to make grey. * @return the new colour, now grey. */ static inline Colour MakeGrey(Colour colour) { uint r = colour.r; uint g = colour.g; uint b = colour.b; /* To avoid doubles and stuff, multiple it with a total of 65536 (16bits), then * divide by it to normalize the value to a byte again. See heightmap.cpp for * information about the formula. */ uint grey = ((r * 19595) + (g * 38470) + (b * 7471)) / 65536; return Colour(grey, grey, grey); } static const int DEFAULT_BRIGHTNESS = 128; static inline Colour AdjustBrightness(Colour colour, uint8 brightness) { /* Shortcut for normal brightness */ if (brightness == DEFAULT_BRIGHTNESS) return colour; uint16 ob = 0; uint16 r = colour.r * brightness / DEFAULT_BRIGHTNESS; uint16 g = colour.g * brightness / DEFAULT_BRIGHTNESS; uint16 b = colour.b * brightness / DEFAULT_BRIGHTNESS; /* Sum overbright */ if (r > 255) ob += r - 255; if (g > 255) ob += g - 255; if (b > 255) ob += b - 255; if (ob == 0) return Colour(r, g, b, colour.a); /* Reduce overbright strength */ ob /= 2; return Colour( r >= 255 ? 255 : min(r + ob * (255 - r) / 256, 255), g >= 255 ? 255 : min(g + ob * (255 - g) / 256, 255), b >= 255 ? 255 : min(b + ob * (255 - b) / 256, 255), colour.a); } }; #endif /* BLITTER_32BPP_BASE_HPP */ openttd-1.5.3/src/blitter/32bpp_optimized.hpp0000644000000000000000000000364112627373442017670 0ustar rootroot/* $Id: 32bpp_optimized.hpp 26209 2014-01-02 22:41:58Z rubidium $ */ /* * 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 32bpp_optimized.hpp Optimized 32 bpp blitter. */ #ifndef BLITTER_32BPP_OPTIMIZED_HPP #define BLITTER_32BPP_OPTIMIZED_HPP #include "32bpp_simple.hpp" /** The optimised 32 bpp blitter (without palette animation). */ class Blitter_32bppOptimized : public Blitter_32bppSimple { public: /** Data stored about a (single) sprite. */ struct SpriteData { uint32 offset[ZOOM_LVL_COUNT][2]; ///< Offsets (from .data) to streams for different zoom levels, and the normal and remap image information. byte data[]; ///< Data, all zoomlevels. }; /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); /* virtual */ const char *GetName() { return "32bpp-optimized"; } template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); }; /** Factory for the optimised 32 bpp blitter (without palette animation). */ class FBlitter_32bppOptimized : public BlitterFactory { public: FBlitter_32bppOptimized() : BlitterFactory("32bpp-optimized", "32bpp Optimized Blitter (no palette animation)") {} /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppOptimized(); } }; #endif /* BLITTER_32BPP_OPTIMIZED_HPP */ openttd-1.5.3/src/blitter/base.cpp0000644000000000000000000000672612627373442015572 0ustar rootroot/* $Id: base.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 base.cpp Implementation of the base for all blitters. */ #include "../stdafx.h" #include "base.hpp" #include "../core/math_func.hpp" #include "../safeguards.h" void Blitter::DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) { int dy; int dx; int stepx; int stepy; dy = (y2 - y) * 2; if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } dx = (x2 - x) * 2; if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } if (dx == 0 && dy == 0) { /* The algorithm below cannot handle this special case; make it work at least for line width 1 */ if (x >= 0 && x < screen_width && y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour); return; } int frac_diff = width * max(dx, dy); if (width > 1) { /* compute frac_diff = width * sqrt(dx*dx + dy*dy) * Start interval: * max(dx, dy) <= sqrt(dx*dx + dy*dy) <= sqrt(2) * max(dx, dy) <= 3/2 * max(dx, dy) */ int frac_sq = width * width * (dx * dx + dy * dy); int frac_max = 3 * frac_diff / 2; while (frac_diff < frac_max) { int frac_test = (frac_diff + frac_max) / 2; if (frac_test * frac_test < frac_sq) { frac_diff = frac_test + 1; } else { frac_max = frac_test - 1; } } } int gap = dash; if (dash == 0) dash = 1; int dash_count = 0; if (dx > dy) { int y_low = y; int y_high = y; int frac_low = dy - frac_diff / 2; int frac_high = dy + frac_diff / 2; while (frac_low + dx / 2 < 0) { frac_low += dx; y_low -= stepy; } while (frac_high - dx / 2 >= 0) { frac_high -= dx; y_high += stepy; } x2 += stepx; while (x != x2) { if (dash_count < dash && x >= 0 && x < screen_width) { for (int y = y_low; y != y_high; y += stepy) { if (y >= 0 && y < screen_height) this->SetPixel(video, x, y, colour); } } if (frac_low >= 0) { y_low += stepy; frac_low -= dx; } if (frac_high >= 0) { y_high += stepy; frac_high -= dx; } x += stepx; frac_low += dy; frac_high += dy; if (++dash_count >= dash + gap) dash_count = 0; } } else { int x_low = x; int x_high = x; int frac_low = dx - frac_diff / 2; int frac_high = dx + frac_diff / 2; while (frac_low + dy / 2 < 0) { frac_low += dy; x_low -= stepx; } while (frac_high - dy / 2 >= 0) { frac_high -= dy; x_high += stepx; } y2 += stepy; while (y != y2) { if (dash_count < dash && y >= 0 && y < screen_height) { for (int x = x_low; x != x_high; x += stepx) { if (x >= 0 && x < screen_width) this->SetPixel(video, x, y, colour); } } if (frac_low >= 0) { x_low += stepx; frac_low -= dy; } if (frac_high >= 0) { x_high += stepx; frac_high -= dy; } y += stepy; frac_low += dx; frac_high += dx; if (++dash_count >= dash + gap) dash_count = 0; } } } openttd-1.5.3/src/blitter/32bpp_ssse3.cpp0000644000000000000000000000201112627373442016705 0ustar rootroot/* $Id: 32bpp_ssse3.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 32bpp_ssse3.cpp Implementation of the SSSE3 32 bpp blitter. */ #ifdef WITH_SSE #include "../stdafx.h" #include "../zoom_func.h" #include "../settings_type.h" #include "32bpp_ssse3.hpp" #include "32bpp_sse_func.hpp" #include "../safeguards.h" /** Instantiation of the SSSE3 32bpp blitter factory. */ static FBlitter_32bppSSSE3 iFBlitter_32bppSSSE3; #endif /* WITH_SSE */ openttd-1.5.3/src/blitter/8bpp_optimized.cpp0000644000000000000000000001410312627373442017601 0ustar rootroot/* $Id: 8bpp_optimized.cpp 26969 2014-10-06 18:45:51Z rubidium $ */ /* * 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 8bpp_optimized.cpp Implementation of the optimized 8 bpp blitter. */ #include "../stdafx.h" #include "../zoom_func.h" #include "../settings_type.h" #include "../core/math_func.hpp" #include "../core/mem_func.hpp" #include "8bpp_optimized.hpp" #include "../safeguards.h" /** Instantiation of the 8bpp optimised blitter factory. */ static FBlitter_8bppOptimized iFBlitter_8bppOptimized; void Blitter_8bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { /* Find the offset of this zoom-level */ const SpriteData *sprite_src = (const SpriteData *)bp->sprite; uint offset = sprite_src->offset[zoom]; /* Find where to start reading in the source sprite */ const uint8 *src = sprite_src->data + offset; uint8 *dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; /* Skip over the top lines in the source image */ for (int y = 0; y < bp->skip_top; y++) { for (;;) { uint trans = *src++; uint pixels = *src++; if (trans == 0 && pixels == 0) break; src += pixels; } } const uint8 *src_next = src; for (int y = 0; y < bp->height; y++) { uint8 *dst = dst_line; dst_line += bp->pitch; uint skip_left = bp->skip_left; int width = bp->width; for (;;) { src = src_next; uint trans = *src++; uint pixels = *src++; src_next = src + pixels; if (trans == 0 && pixels == 0) break; if (width <= 0) continue; if (skip_left != 0) { if (skip_left < trans) { trans -= skip_left; skip_left = 0; } else { skip_left -= trans; trans = 0; } if (skip_left < pixels) { src += skip_left; pixels -= skip_left; skip_left = 0; } else { src += pixels; skip_left -= pixels; pixels = 0; } } if (skip_left != 0) continue; /* Skip transparent pixels */ dst += trans; width -= trans; if (width <= 0 || pixels == 0) continue; pixels = min(pixels, (uint)width); width -= pixels; switch (mode) { case BM_COLOUR_REMAP: case BM_CRASH_REMAP: { const uint8 *remap = bp->remap; do { uint m = remap[*src]; if (m != 0) *dst = m; dst++; src++; } while (--pixels != 0); break; } case BM_BLACK_REMAP: MemSetT(dst, 0, pixels); dst += pixels; break; case BM_TRANSPARENT: { const uint8 *remap = bp->remap; src += pixels; do { *dst = remap[*dst]; dst++; } while (--pixels != 0); break; } default: MemCpyT(dst, src, pixels); dst += pixels; src += pixels; break; } } } } Sprite *Blitter_8bppOptimized::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { /* Make memory for all zoom-levels */ uint memory = sizeof(SpriteData); ZoomLevel zoom_min; ZoomLevel zoom_max; if (sprite->type == ST_FONT) { zoom_min = ZOOM_LVL_NORMAL; zoom_max = ZOOM_LVL_NORMAL; } else { zoom_min = _settings_client.gui.zoom_min; zoom_max = _settings_client.gui.zoom_max; if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX; } for (ZoomLevel i = zoom_min; i <= zoom_max; i++) { memory += sprite[i].width * sprite[i].height; } /* We have no idea how much memory we really need, so just guess something */ memory *= 5; /* Don't allocate memory each time, but just keep some * memory around as this function is called quite often * and the memory usage is quite low. */ static ReusableBuffer temp_buffer; SpriteData *temp_dst = (SpriteData *)temp_buffer.Allocate(memory); memset(temp_dst, 0, sizeof(*temp_dst)); byte *dst = temp_dst->data; /* Make the sprites per zoom-level */ for (ZoomLevel i = zoom_min; i <= zoom_max; i++) { /* Store the index table */ uint offset = dst - temp_dst->data; temp_dst->offset[i] = offset; /* cache values, because compiler can't cache it */ int scaled_height = sprite[i].height; int scaled_width = sprite[i].width; for (int y = 0; y < scaled_height; y++) { uint trans = 0; uint pixels = 0; uint last_colour = 0; byte *count_dst = NULL; /* Store the scaled image */ const SpriteLoader::CommonPixel *src = &sprite[i].data[y * sprite[i].width]; for (int x = 0; x < scaled_width; x++) { uint colour = src++->m; if (last_colour == 0 || colour == 0 || pixels == 255) { if (count_dst != NULL) { /* Write how many non-transparent bytes we get */ *count_dst = pixels; pixels = 0; count_dst = NULL; } /* As long as we find transparency bytes, keep counting */ if (colour == 0 && trans != 255) { last_colour = 0; trans++; continue; } /* No longer transparency, so write the amount of transparent bytes */ *dst = trans; dst++; trans = 0; /* Reserve a byte for the pixel counter */ count_dst = dst; dst++; } last_colour = colour; if (colour == 0) { trans++; } else { pixels++; *dst = colour; dst++; } } if (count_dst != NULL) *count_dst = pixels; /* Write line-ending */ *dst = 0; dst++; *dst = 0; dst++; } } uint size = dst - (byte *)temp_dst; /* Safety check, to make sure we guessed the size correctly */ assert(size < memory); /* Allocate the exact amount of memory we need */ Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + size); dest_sprite->height = sprite->height; dest_sprite->width = sprite->width; dest_sprite->x_offs = sprite->x_offs; dest_sprite->y_offs = sprite->y_offs; memcpy(dest_sprite->data, temp_dst, size); return dest_sprite; } openttd-1.5.3/src/blitter/8bpp_simple.cpp0000644000000000000000000000473312627373442017076 0ustar rootroot/* $Id: 8bpp_simple.cpp 26969 2014-10-06 18:45:51Z rubidium $ */ /* * 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 8bpp_simple.cpp Implementation of the simple 8 bpp blitter. */ #include "../stdafx.h" #include "../zoom_func.h" #include "8bpp_simple.hpp" #include "../safeguards.h" /** Instantiation of the simple 8bpp blitter factory. */ static FBlitter_8bppSimple iFBlitter_8bppSimple; void Blitter_8bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { const uint8 *src, *src_line; uint8 *dst, *dst_line; /* Find where to start reading in the source sprite */ src_line = (const uint8 *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); dst_line = (uint8 *)bp->dst + bp->top * bp->pitch + bp->left; for (int y = 0; y < bp->height; y++) { dst = dst_line; dst_line += bp->pitch; src = src_line; src_line += bp->sprite_width * ScaleByZoom(1, zoom); for (int x = 0; x < bp->width; x++) { uint colour = 0; switch (mode) { case BM_COLOUR_REMAP: case BM_CRASH_REMAP: colour = bp->remap[*src]; break; case BM_TRANSPARENT: if (*src != 0) colour = bp->remap[*dst]; break; case BM_BLACK_REMAP: colour = 0; break; default: colour = *src; break; } if (colour != 0) *dst = colour; dst++; src += ScaleByZoom(1, zoom); } } } Sprite *Blitter_8bppSimple::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { Sprite *dest_sprite; dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + (size_t)sprite->height * (size_t)sprite->width); dest_sprite->height = sprite->height; dest_sprite->width = sprite->width; dest_sprite->x_offs = sprite->x_offs; dest_sprite->y_offs = sprite->y_offs; /* Copy over only the 'remap' channel, as that is what we care about in 8bpp */ for (int i = 0; i < sprite->height * sprite->width; i++) { dest_sprite->data[i] = sprite->data[i].m; } return dest_sprite; } openttd-1.5.3/src/blitter/32bpp_sse4.hpp0000644000000000000000000000335712627373442016546 0ustar rootroot/* $Id: 32bpp_sse4.hpp 26260 2014-01-13 18:20:23Z rubidium $ */ /* * 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 32bpp_sse4.hpp SSE4 32 bpp blitter. */ #ifndef BLITTER_32BPP_SSE4_HPP #define BLITTER_32BPP_SSE4_HPP #ifdef WITH_SSE #ifndef SSE_VERSION #define SSE_VERSION 4 #endif #ifndef FULL_ANIMATION #define FULL_ANIMATION 0 #endif #include "32bpp_ssse3.hpp" /** The SSE4 32 bpp blitter (without palette animation). */ class Blitter_32bppSSE4 : public Blitter_32bppSSSE3 { public: /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); /* virtual */ const char *GetName() { return "32bpp-sse4"; } }; /** Factory for the SSE4 32 bpp blitter (without palette animation). */ class FBlitter_32bppSSE4: public BlitterFactory { public: FBlitter_32bppSSE4() : BlitterFactory("32bpp-sse4", "32bpp SSE4 Blitter (no palette animation)", HasCPUIDFlag(1, 2, 19)) {} /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE4(); } }; #endif /* WITH_SSE */ #endif /* BLITTER_32BPP_SSE4_HPP */ openttd-1.5.3/src/blitter/32bpp_anim.cpp0000644000000000000000000003631012627373442016602 0ustar rootroot/* $Id: 32bpp_anim.cpp 26970 2014-10-06 19:15:00Z rubidium $ */ /* * 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 32bpp_anim.cpp Implementation of the optimized 32 bpp blitter with animation support. */ #include "../stdafx.h" #include "../video/video_driver.hpp" #include "32bpp_anim.hpp" #include "../table/sprites.h" #include "../safeguards.h" /** Instantiation of the 32bpp with animation blitter factory. */ static FBlitter_32bppAnim iFBlitter_32bppAnim; template inline void Blitter_32bppAnim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) { const SpriteData *src = (const SpriteData *)bp->sprite; const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); const uint16 *src_n = (const uint16 *)(src->data + src->offset[zoom][1]); for (uint i = bp->skip_top; i != 0; i--) { src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); src_n = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); } Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; uint16 *anim = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left; const byte *remap = bp->remap; // store so we don't have to access it via bp everytime for (int y = 0; y < bp->height; y++) { Colour *dst_ln = dst + bp->pitch; uint16 *anim_ln = anim + this->anim_buf_width; const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); src_px++; const uint16 *src_n_ln = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); src_n += 2; Colour *dst_end = dst + bp->skip_left; uint n; while (dst < dst_end) { n = *src_n++; if (src_px->a == 0) { dst += n; src_px ++; src_n++; if (dst > dst_end) anim += dst - dst_end; } else { if (dst + n > dst_end) { uint d = dst_end - dst; src_px += d; src_n += d; dst = dst_end - bp->skip_left; dst_end = dst + bp->width; n = min(n - d, (uint)bp->width); goto draw; } dst += n; src_px += n; src_n += n; } } dst -= bp->skip_left; dst_end -= bp->skip_left; dst_end += bp->width; while (dst < dst_end) { n = min(*src_n++, (uint)(dst_end - dst)); if (src_px->a == 0) { anim += n; dst += n; src_px++; src_n++; continue; } draw:; switch (mode) { case BM_COLOUR_REMAP: if (src_px->a == 255) { do { uint m = *src_n; /* In case the m-channel is zero, do not remap this pixel in any way */ if (m == 0) { *dst = src_px->data; *anim = 0; } else { uint r = remap[GB(m, 0, 8)]; *anim = r | (m & 0xFF00); if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); } anim++; dst++; src_px++; src_n++; } while (--n != 0); } else { do { uint m = *src_n; if (m == 0) { *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); *anim = 0; } else { uint r = remap[GB(m, 0, 8)]; *anim = 0; if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); } anim++; dst++; src_px++; src_n++; } while (--n != 0); } break; case BM_CRASH_REMAP: if (src_px->a == 255) { do { uint m = *src_n; if (m == 0) { uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); *anim = 0; } else { uint r = remap[GB(m, 0, 8)]; *anim = r | (m & 0xFF00); if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); } anim++; dst++; src_px++; src_n++; } while (--n != 0); } else { do { uint m = *src_n; if (m == 0) { if (src_px->a != 0) { uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); *anim = 0; } } else { uint r = remap[GB(m, 0, 8)]; *anim = 0; if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); } anim++; dst++; src_px++; src_n++; } while (--n != 0); } break; case BM_BLACK_REMAP: do { *dst++ = Colour(0, 0, 0); *anim++ = 0; src_px++; src_n++; } while (--n != 0); break; case BM_TRANSPARENT: /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: * we produce a result the newgrf maker didn't expect ;) */ /* Make the current colour a bit more black, so it looks like this image is transparent */ src_n += n; if (src_px->a == 255) { src_px += n; do { *dst = MakeTransparent(*dst, 3, 4); *anim = 0; anim++; dst++; } while (--n != 0); } else { do { *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4); *anim = 0; anim++; dst++; src_px++; } while (--n != 0); } break; default: if (src_px->a == 255) { do { /* Compiler assumes pointer aliasing, can't optimise this on its own */ uint m = GB(*src_n, 0, 8); /* Above PALETTE_ANIM_START is palette animation */ *anim++ = *src_n; *dst++ = (m >= PALETTE_ANIM_START) ? this->AdjustBrightness(this->LookupColourInPalette(m), GB(*src_n, 8, 8)) : src_px->data; src_px++; src_n++; } while (--n != 0); } else { do { uint m = GB(*src_n, 0, 8); *anim++ = 0; if (m >= PALETTE_ANIM_START) { *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(m), GB(*src_n, 8, 8)), src_px->a, *dst); } else { *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); } dst++; src_px++; src_n++; } while (--n != 0); } break; } } anim = anim_ln; dst = dst_ln; src_px = src_px_ln; src_n = src_n_ln; } } void Blitter_32bppAnim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { if (_screen_disable_anim) { /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent Draw() */ Blitter_32bppOptimized::Draw(bp, mode, zoom); return; } switch (mode) { default: NOT_REACHED(); case BM_NORMAL: Draw (bp, zoom); return; case BM_COLOUR_REMAP: Draw(bp, zoom); return; case BM_TRANSPARENT: Draw (bp, zoom); return; case BM_CRASH_REMAP: Draw (bp, zoom); return; case BM_BLACK_REMAP: Draw (bp, zoom); return; } } void Blitter_32bppAnim::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) { if (_screen_disable_anim) { /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawColourMappingRect() */ Blitter_32bppOptimized::DrawColourMappingRect(dst, width, height, pal); return; } Colour *udst = (Colour *)dst; uint16 *anim; anim = this->anim_buf + ((uint32 *)dst - (uint32 *)_screen.dst_ptr); if (pal == PALETTE_TO_TRANSPARENT) { do { for (int i = 0; i != width; i++) { *udst = MakeTransparent(*udst, 154); *anim = 0; udst++; anim++; } udst = udst - width + _screen.pitch; anim = anim - width + this->anim_buf_width; } while (--height); return; } if (pal == PALETTE_NEWSPAPER) { do { for (int i = 0; i != width; i++) { *udst = MakeGrey(*udst); *anim = 0; udst++; anim++; } udst = udst - width + _screen.pitch; anim = anim - width + this->anim_buf_width; } while (--height); return; } DEBUG(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('%d')", pal); } void Blitter_32bppAnim::SetPixel(void *video, int x, int y, uint8 colour) { *((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); /* Set the colour in the anim-buffer too, if we are rendering to the screen */ if (_screen_disable_anim) return; this->anim_buf[((uint32 *)video - (uint32 *)_screen.dst_ptr) + x + y * this->anim_buf_width] = colour | (DEFAULT_BRIGHTNESS << 8); } void Blitter_32bppAnim::DrawRect(void *video, int width, int height, uint8 colour) { if (_screen_disable_anim) { /* This means our output is not to the screen, so we can't be doing any animation stuff, so use our parent DrawRect() */ Blitter_32bppOptimized::DrawRect(video, width, height, colour); return; } Colour colour32 = LookupColourInPalette(colour); uint16 *anim_line; anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf; do { Colour *dst = (Colour *)video; uint16 *anim = anim_line; for (int i = width; i > 0; i--) { *dst = colour32; /* Set the colour in the anim-buffer too */ *anim = colour | (DEFAULT_BRIGHTNESS << 8); dst++; anim++; } video = (uint32 *)video + _screen.pitch; anim_line += this->anim_buf_width; } while (--height); } void Blitter_32bppAnim::CopyFromBuffer(void *video, const void *src, int width, int height) { assert(!_screen_disable_anim); assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); Colour *dst = (Colour *)video; const uint32 *usrc = (const uint32 *)src; uint16 *anim_line = ((uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf; for (; height > 0; height--) { /* We need to keep those for palette animation. */ Colour *dst_pal = dst; uint16 *anim_pal = anim_line; memcpy(dst, usrc, width * sizeof(uint32)); usrc += width; dst += _screen.pitch; /* Copy back the anim-buffer */ memcpy(anim_line, usrc, width * sizeof(uint16)); usrc = (const uint32 *)((const uint16 *)usrc + width); anim_line += this->anim_buf_width; /* Okay, it is *very* likely that the image we stored is using * the wrong palette animated colours. There are two things we * can do to fix this. The first is simply reviewing the whole * screen after we copied the buffer, i.e. run PaletteAnimate, * however that forces a full screen redraw which is expensive * for just the cursor. This just copies the implementation of * palette animation, much cheaper though slightly nastier. */ for (int i = 0; i < width; i++) { uint colour = GB(*anim_pal, 0, 8); if (colour >= PALETTE_ANIM_START) { /* Update this pixel */ *dst_pal = this->AdjustBrightness(LookupColourInPalette(colour), GB(*anim_pal, 8, 8)); } dst_pal++; anim_pal++; } } } void Blitter_32bppAnim::CopyToBuffer(const void *video, void *dst, int width, int height) { assert(!_screen_disable_anim); assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); uint32 *udst = (uint32 *)dst; const uint32 *src = (const uint32 *)video; const uint16 *anim_line; if (this->anim_buf == NULL) return; anim_line = ((const uint32 *)video - (uint32 *)_screen.dst_ptr) + this->anim_buf; for (; height > 0; height--) { memcpy(udst, src, width * sizeof(uint32)); src += _screen.pitch; udst += width; /* Copy the anim-buffer */ memcpy(udst, anim_line, width * sizeof(uint16)); udst = (uint32 *)((uint16 *)udst + width); anim_line += this->anim_buf_width; } } void Blitter_32bppAnim::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) { assert(!_screen_disable_anim); assert(video >= _screen.dst_ptr && video <= (uint32 *)_screen.dst_ptr + _screen.width + _screen.height * _screen.pitch); uint16 *dst, *src; /* We need to scroll the anim-buffer too */ if (scroll_y > 0) { dst = this->anim_buf + left + (top + height - 1) * this->anim_buf_width; src = dst - scroll_y * this->anim_buf_width; /* Adjust left & width */ if (scroll_x >= 0) { dst += scroll_x; } else { src -= scroll_x; } uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x); uint th = height - scroll_y; for (; th > 0; th--) { memcpy(dst, src, tw * sizeof(uint16)); src -= this->anim_buf_width; dst -= this->anim_buf_width; } } else { /* Calculate pointers */ dst = this->anim_buf + left + top * this->anim_buf_width; src = dst - scroll_y * this->anim_buf_width; /* Adjust left & width */ if (scroll_x >= 0) { dst += scroll_x; } else { src -= scroll_x; } /* the y-displacement may be 0 therefore we have to use memmove, * because source and destination may overlap */ uint tw = width + (scroll_x >= 0 ? -scroll_x : scroll_x); uint th = height + scroll_y; for (; th > 0; th--) { memmove(dst, src, tw * sizeof(uint16)); src += this->anim_buf_width; dst += this->anim_buf_width; } } Blitter_32bppBase::ScrollBuffer(video, left, top, width, height, scroll_x, scroll_y); } int Blitter_32bppAnim::BufferSize(int width, int height) { return width * height * (sizeof(uint32) + sizeof(uint16)); } void Blitter_32bppAnim::PaletteAnimate(const Palette &palette) { assert(!_screen_disable_anim); this->palette = palette; /* If first_dirty is 0, it is for 8bpp indication to send the new * palette. However, only the animation colours might possibly change. * Especially when going between toyland and non-toyland. */ assert(this->palette.first_dirty == PALETTE_ANIM_START || this->palette.first_dirty == 0); const uint16 *anim = this->anim_buf; Colour *dst = (Colour *)_screen.dst_ptr; /* Let's walk the anim buffer and try to find the pixels */ for (int y = this->anim_buf_height; y != 0 ; y--) { for (int x = this->anim_buf_width; x != 0 ; x--) { uint colour = GB(*anim, 0, 8); if (colour >= PALETTE_ANIM_START) { /* Update this pixel */ *dst = this->AdjustBrightness(LookupColourInPalette(colour), GB(*anim, 8, 8)); } dst++; anim++; } dst += _screen.pitch - this->anim_buf_width; } /* Make sure the backend redraws the whole screen */ VideoDriver::GetInstance()->MakeDirty(0, 0, _screen.width, _screen.height); } Blitter::PaletteAnimation Blitter_32bppAnim::UsePaletteAnimation() { return Blitter::PALETTE_ANIMATION_BLITTER; } void Blitter_32bppAnim::PostResize() { if (_screen.width != this->anim_buf_width || _screen.height != this->anim_buf_height) { /* The size of the screen changed; we can assume we can wipe all data from our buffer */ free(this->anim_buf); this->anim_buf = CallocT(_screen.width * _screen.height); this->anim_buf_width = _screen.width; this->anim_buf_height = _screen.height; } } openttd-1.5.3/src/blitter/base.hpp0000644000000000000000000002034312627373442015566 0ustar rootroot/* $Id: base.hpp 26969 2014-10-06 18:45:51Z rubidium $ */ /* * 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 base.hpp Base for all blitters. */ #ifndef BLITTER_BASE_HPP #define BLITTER_BASE_HPP #include "../spritecache.h" #include "../spriteloader/spriteloader.hpp" /** The modes of blitting we can do. */ enum BlitterMode { BM_NORMAL, ///< Perform the simple blitting. BM_COLOUR_REMAP, ///< Perform a colour remapping. BM_TRANSPARENT, ///< Perform transparency colour remapping. BM_CRASH_REMAP, ///< Perform a crash remapping. BM_BLACK_REMAP, ///< Perform remapping to a completely blackened sprite }; /** * How all blitters should look like. Extend this class to make your own. */ class Blitter { public: /** Parameters related to blitting. */ struct BlitterParams { const void *sprite; ///< Pointer to the sprite how ever the encoder stored it const byte *remap; ///< XXX -- Temporary storage for remap array int skip_left; ///< How much pixels of the source to skip on the left (based on zoom of dst) int skip_top; ///< How much pixels of the source to skip on the top (based on zoom of dst) int width; ///< The width in pixels that needs to be drawn to dst int height; ///< The height in pixels that needs to be drawn to dst int sprite_width; ///< Real width of the sprite int sprite_height; ///< Real height of the sprite int left; ///< The left offset in the 'dst' in pixels to start drawing int top; ///< The top offset in the 'dst' in pixels to start drawing void *dst; ///< Destination buffer int pitch; ///< The pitch of the destination buffer }; /** Types of palette animation. */ enum PaletteAnimation { PALETTE_ANIMATION_NONE, ///< No palette animation PALETTE_ANIMATION_VIDEO_BACKEND, ///< Palette animation should be done by video backend (8bpp only!) PALETTE_ANIMATION_BLITTER, ///< The blitter takes care of the palette animation }; /** * Get the screen depth this blitter works for. * This is either: 8, 16, 24 or 32. */ virtual uint8 GetScreenDepth() = 0; /** * Draw an image to the screen, given an amount of params defined above. */ virtual void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) = 0; /** * Draw a colourtable to the screen. This is: the colour of the screen is read * and is looked-up in the palette to match a new colour, which then is put * on the screen again. * @param dst the destination pointer (video-buffer). * @param width the width of the buffer. * @param height the height of the buffer. * @param pal the palette to use. */ virtual void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) = 0; /** * Convert a sprite from the loader to our own format. */ virtual Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) = 0; /** * Move the destination pointer the requested amount x and y, keeping in mind * any pitch and bpp of the renderer. * @param video The destination pointer (video-buffer) to scroll. * @param x How much you want to scroll to the right. * @param y How much you want to scroll to the bottom. * @return A new destination pointer moved the the requested place. */ virtual void *MoveTo(void *video, int x, int y) = 0; /** * Draw a pixel with a given colour on the video-buffer. * @param video The destination pointer (video-buffer). * @param x The x position within video-buffer. * @param y The y position within video-buffer. * @param colour A 8bpp mapping colour. */ virtual void SetPixel(void *video, int x, int y, uint8 colour) = 0; /** * Make a single horizontal line in a single colour on the video-buffer. * @param video The destination pointer (video-buffer). * @param width The length of the line. * @param height The height of the line. * @param colour A 8bpp mapping colour. */ virtual void DrawRect(void *video, int width, int height, uint8 colour) = 0; /** * Draw a line with a given colour. * @param video The destination pointer (video-buffer). * @param x The x coordinate from where the line starts. * @param y The y coordinate from where the line starts. * @param x2 The x coordinate to where the line goes. * @param y2 The y coordinate to where the lines goes. * @param screen_width The width of the screen you are drawing in (to avoid buffer-overflows). * @param screen_height The height of the screen you are drawing in (to avoid buffer-overflows). * @param colour A 8bpp mapping colour. * @param width Line width. * @param dash Length of dashes for dashed lines. 0 means solid line. */ virtual void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0); /** * Copy from a buffer to the screen. * @param video The destination pointer (video-buffer). * @param src The buffer from which the data will be read. * @param width The width of the buffer. * @param height The height of the buffer. * @note You can not do anything with the content of the buffer, as the blitter can store non-pixel data in it too! */ virtual void CopyFromBuffer(void *video, const void *src, int width, int height) = 0; /** * Copy from the screen to a buffer. * @param video The destination pointer (video-buffer). * @param dst The buffer in which the data will be stored. * @param width The width of the buffer. * @param height The height of the buffer. * @note You can not do anything with the content of the buffer, as the blitter can store non-pixel data in it too! */ virtual void CopyToBuffer(const void *video, void *dst, int width, int height) = 0; /** * Copy from the screen to a buffer in a palette format for 8bpp and RGBA format for 32bpp. * @param video The destination pointer (video-buffer). * @param dst The buffer in which the data will be stored. * @param width The width of the buffer. * @param height The height of the buffer. * @param dst_pitch The pitch (byte per line) of the destination buffer. */ virtual void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) = 0; /** * Scroll the videobuffer some 'x' and 'y' value. * @param video The buffer to scroll into. * @param left The left value of the screen to scroll. * @param top The top value of the screen to scroll. * @param width The width of the screen to scroll. * @param height The height of the screen to scroll. * @param scroll_x How much to scroll in X. * @param scroll_y How much to scroll in Y. */ virtual void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) = 0; /** * Calculate how much memory there is needed for an image of this size in the video-buffer. * @param width The width of the buffer-to-be. * @param height The height of the buffer-to-be. * @return The size needed for the buffer. */ virtual int BufferSize(int width, int height) = 0; /** * Called when the 8bpp palette is changed; you should redraw all pixels on the screen that * are equal to the 8bpp palette indexes 'first_dirty' to 'first_dirty + count_dirty'. * @param palette The new palette. */ virtual void PaletteAnimate(const Palette &palette) = 0; /** * Check if the blitter uses palette animation at all. * @return True if it uses palette animation. */ virtual Blitter::PaletteAnimation UsePaletteAnimation() = 0; /** * Get the name of the blitter, the same as the Factory-instance returns. */ virtual const char *GetName() = 0; /** * Get how many bytes are needed to store a pixel. */ virtual int GetBytesPerPixel() = 0; /** * Post resize event */ virtual void PostResize() { }; virtual ~Blitter() { } }; #endif /* BLITTER_BASE_HPP */ openttd-1.5.3/src/blitter/32bpp_anim_sse4.cpp0000644000000000000000000003520412627373442017541 0ustar rootroot/* $Id: 32bpp_anim_sse4.cpp 26969 2014-10-06 18:45:51Z rubidium $ */ /* * 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 32bpp_sse4_anim.cpp Implementation of the SSE4 32 bpp blitter with animation support. */ #ifdef WITH_SSE #include "../stdafx.h" #include "../video/video_driver.hpp" #include "../table/sprites.h" #include "32bpp_anim_sse4.hpp" #include "32bpp_sse_func.hpp" #include "../safeguards.h" /** Instantiation of the SSE4 32bpp blitter factory. */ static FBlitter_32bppSSE4_Anim iFBlitter_32bppSSE4_Anim; /** * Draws a sprite to a (screen) buffer. It is templated to allow faster operation. * * @tparam mode blitter mode * @param bp further blitting parameters * @param zoom zoom level at which we are drawing */ IGNORE_UNINITIALIZED_WARNING_START template inline void Blitter_32bppSSE4_Anim::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) { const byte * const remap = bp->remap; Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left; uint16 *anim_line = this->anim_buf + ((uint32 *)bp->dst - (uint32 *)_screen.dst_ptr) + bp->top * this->anim_buf_width + bp->left; int effective_width = bp->width; /* Find where to start reading in the source sprite. */ const Blitter_32bppSSE_Base::SpriteData * const sd = (const Blitter_32bppSSE_Base::SpriteData *) bp->sprite; const SpriteInfo * const si = &sd->infos[zoom]; const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width; const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size); if (read_mode != RM_WITH_MARGIN) { src_rgba_line += bp->skip_left; src_mv_line += bp->skip_left; } const MapValue *src_mv = src_mv_line; /* Load these variables into register before loop. */ const __m128i a_cm = ALPHA_CONTROL_MASK; const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK; const __m128i tr_nom_base = TRANSPARENT_NOM_BASE; for (int y = bp->height; y != 0; y--) { Colour *dst = dst_line; const Colour *src = src_rgba_line + META_LENGTH; if (mode != BM_TRANSPARENT) src_mv = src_mv_line; uint16 *anim = anim_line; if (read_mode == RM_WITH_MARGIN) { assert(bt_last == BT_NONE); // or you must ensure block type is preserved anim += src_rgba_line[0].data; src += src_rgba_line[0].data; dst += src_rgba_line[0].data; if (mode != BM_TRANSPARENT) src_mv += src_rgba_line[0].data; const int width_diff = si->sprite_width - bp->width; effective_width = bp->width - (int) src_rgba_line[0].data; const int delta_diff = (int) src_rgba_line[1].data - width_diff; const int new_width = effective_width - delta_diff; effective_width = delta_diff > 0 ? new_width : effective_width; if (effective_width <= 0) goto next_line; } switch (mode) { default: if (!translucent) { for (uint x = (uint) effective_width; x > 0; x--) { if (src->a) { if (animated) { *anim = *(const uint16*) src_mv; *dst = (src_mv->m >= PALETTE_ANIM_START) ? AdjustBrightneSSE(this->LookupColourInPalette(src_mv->m), src_mv->v) : src->data; } else { *anim = 0; *dst = *src; } } if (animated) src_mv++; anim++; src++; dst++; } break; } for (uint x = (uint) effective_width/2; x != 0; x--) { uint32 mvX2 = *((uint32 *) const_cast(src_mv)); __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); if (animated) { /* Remap colours. */ const byte m0 = mvX2; if (m0 >= PALETTE_ANIM_START) { const Colour c0 = (this->LookupColourInPalette(m0).data & 0x00FFFFFF) | (src[0].data & 0xFF000000); InsertFirstUint32(AdjustBrightneSSE(c0, (byte) (mvX2 >> 8)).data, srcABCD); } const byte m1 = mvX2 >> 16; if (m1 >= PALETTE_ANIM_START) { const Colour c1 = (this->LookupColourInPalette(m1).data & 0x00FFFFFF) | (src[1].data & 0xFF000000); InsertSecondUint32(AdjustBrightneSSE(c1, (byte) (mvX2 >> 24)).data, srcABCD); } /* Update anim buffer. */ const byte a0 = src[0].a; const byte a1 = src[1].a; uint32 anim01 = 0; if (a0 == 255) { if (a1 == 255) { *(uint32*) anim = mvX2; goto bmno_full_opacity; } anim01 = (uint16) mvX2; } else if (a0 == 0) { if (a1 == 0) { goto bmno_full_transparency; } else { if (a1 == 255) anim[1] = (uint16) (mvX2 >> 16); goto bmno_alpha_blend; } } if (a1 > 0) { if (a1 == 255) anim01 |= mvX2 & 0xFFFF0000; *(uint32*) anim = anim01; } else { anim[0] = (uint16) anim01; } } else { if (src[0].a) anim[0] = 0; if (src[1].a) anim[1] = 0; } /* Blend colours. */ bmno_alpha_blend: srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm); bmno_full_opacity: _mm_storel_epi64((__m128i *) dst, srcABCD); bmno_full_transparency: src_mv += 2; src += 2; anim += 2; dst += 2; } if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { if (src->a == 0) { } else if (src->a == 255) { *anim = *(const uint16*) src_mv; *dst = (src_mv->m >= PALETTE_ANIM_START) ? AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v) : *src; } else { *anim = 0; __m128i srcABCD; __m128i dstABCD = _mm_cvtsi32_si128(dst->data); if (src_mv->m >= PALETTE_ANIM_START) { Colour colour = AdjustBrightneSSE(LookupColourInPalette(src_mv->m), src_mv->v); colour.a = src->a; srcABCD = _mm_cvtsi32_si128(colour.data); } else { srcABCD = _mm_cvtsi32_si128(src->data); } dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm)); } } break; case BM_COLOUR_REMAP: for (uint x = (uint) effective_width / 2; x != 0; x--) { uint32 mvX2 = *((uint32 *) const_cast(src_mv)); __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); /* Remap colours. */ const uint m0 = (byte) mvX2; const uint r0 = remap[m0]; const uint m1 = (byte) (mvX2 >> 16); const uint r1 = remap[m1]; if (mvX2 & 0x00FF00FF) { #define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \ /* Written so the compiler uses CMOV. */ \ Colour m_colour = m_colour_init; \ { \ const Colour srcm = (Colour) (m_src); \ const uint m = (byte) (m_m); \ const uint r = remap[m]; \ const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \ m_colour = r == 0 ? m_colour : cmap; \ m_colour = m != 0 ? m_colour : srcm; \ } #ifdef _SQ64 uint64 srcs = _mm_cvtsi128_si64(srcABCD); uint64 dsts; if (animated) dsts = _mm_cvtsi128_si64(dstABCD); uint64 remapped_src = 0; CMOV_REMAP(c0, animated ? dsts : 0, srcs, mvX2); remapped_src = c0.data; CMOV_REMAP(c1, animated ? dsts >> 32 : 0, srcs >> 32, mvX2 >> 16); remapped_src |= (uint64) c1.data << 32; srcABCD = _mm_cvtsi64_si128(remapped_src); #else Colour remapped_src[2]; CMOV_REMAP(c0, animated ? _mm_cvtsi128_si32(dstABCD) : 0, _mm_cvtsi128_si32(srcABCD), mvX2); remapped_src[0] = c0.data; CMOV_REMAP(c1, animated ? dst[1] : 0, src[1], mvX2 >> 16); remapped_src[1] = c1.data; srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src); #endif if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2); } /* Update anim buffer. */ if (animated) { const byte a0 = src[0].a; const byte a1 = src[1].a; uint32 anim01 = mvX2 & 0xFF00FF00; if (a0 == 255) { anim01 |= r0; if (a1 == 255) { *(uint32*) anim = anim01 | (r1 << 16); goto bmcr_full_opacity; } } else if (a0 == 0) { if (a1 == 0) { goto bmcr_full_transparency; } else { if (a1 == 255) { anim[1] = r1 | (anim01 >> 16); } goto bmcr_alpha_blend; } } if (a1 > 0) { if (a1 == 255) anim01 |= r1 << 16; *(uint32*) anim = anim01; } else { anim[0] = (uint16) anim01; } } else { if (src[0].a) anim[0] = 0; if (src[1].a) anim[1] = 0; } /* Blend colours. */ bmcr_alpha_blend: srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm); bmcr_full_opacity: _mm_storel_epi64((__m128i *) dst, srcABCD); bmcr_full_transparency: src_mv += 2; dst += 2; src += 2; anim += 2; } if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { /* In case the m-channel is zero, do not remap this pixel in any way. */ __m128i srcABCD; if (src->a == 0) break; if (src_mv->m) { const uint r = remap[src_mv->m]; *anim = (animated && src->a == 255) ? r | ((uint16) src_mv->v << 8 ) : 0; if (r != 0) { Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v); if (src->a == 255) { *dst = remapped_colour; } else { remapped_colour.a = src->a; srcABCD = _mm_cvtsi32_si128(remapped_colour.data); goto bmcr_alpha_blend_single; } } } else { *anim = 0; srcABCD = _mm_cvtsi32_si128(src->data); if (src->a < 255) { bmcr_alpha_blend_single: __m128i dstABCD = _mm_cvtsi32_si128(dst->data); srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, a_cm, pack_low_cm); } dst->data = _mm_cvtsi128_si32(srcABCD); } } break; case BM_TRANSPARENT: /* Make the current colour a bit more black, so it looks like this image is transparent. */ for (uint x = (uint) bp->width / 2; x > 0; x--) { __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); _mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base)); src += 2; dst += 2; anim += 2; if (src[-2].a) anim[-2] = 0; if (src[-1].a) anim[-1] = 0; } if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) { __m128i srcABCD = _mm_cvtsi32_si128(src->data); __m128i dstABCD = _mm_cvtsi32_si128(dst->data); dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, a_cm, tr_nom_base)); if (src[0].a) anim[0] = 0; } break; case BM_CRASH_REMAP: for (uint x = (uint) bp->width; x > 0; x--) { if (src_mv->m == 0) { if (src->a != 0) { uint8 g = MakeDark(src->r, src->g, src->b); *dst = ComposeColourRGBA(g, g, g, src->a, *dst); *anim = 0; } } else { uint r = remap[src_mv->m]; if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), src_mv->v), src->a, *dst); } src_mv++; dst++; src++; anim++; } break; case BM_BLACK_REMAP: for (uint x = (uint) bp->width; x > 0; x--) { if (src->a != 0) { *dst = Colour(0, 0, 0); *anim = 0; } src_mv++; dst++; src++; anim++; } break; } next_line: if (mode != BM_TRANSPARENT) src_mv_line += si->sprite_width; src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size); dst_line += bp->pitch; anim_line += this->anim_buf_width; } } IGNORE_UNINITIALIZED_WARNING_STOP /** * Draws a sprite to a (screen) buffer. Calls adequate templated function. * * @param bp further blitting parameters * @param mode blitter mode * @param zoom zoom level at which we are drawing */ void Blitter_32bppSSE4_Anim::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { const Blitter_32bppSSE_Base::SpriteFlags sprite_flags = ((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags; switch (mode) { default: { bm_normal: if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) { const BlockType bt_last = (BlockType) (bp->width & 1); if (bt_last == BT_EVEN) { if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); else Draw(bp, zoom); } else { if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); else Draw(bp, zoom); } } else { #ifdef _SQ64 if (sprite_flags & SF_TRANSLUCENT) { if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); else Draw(bp, zoom); } else { if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); else Draw(bp, zoom); } #else if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); else Draw(bp, zoom); #endif } break; } case BM_COLOUR_REMAP: if (sprite_flags & SF_NO_REMAP) goto bm_normal; if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) { if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); else Draw(bp, zoom); } else { if (sprite_flags & SF_NO_ANIM) Draw(bp, zoom); else Draw(bp, zoom); } break; case BM_TRANSPARENT: Draw(bp, zoom); return; case BM_CRASH_REMAP: Draw(bp, zoom); return; case BM_BLACK_REMAP: Draw(bp, zoom); return; } } #endif /* WITH_SSE */ openttd-1.5.3/src/blitter/32bpp_optimized.cpp0000644000000000000000000002654412627373442017672 0ustar rootroot/* $Id: 32bpp_optimized.cpp 26969 2014-10-06 18:45:51Z rubidium $ */ /* * 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 32bpp_optimized.cpp Implementation of the optimized 32 bpp blitter. */ #include "../stdafx.h" #include "../zoom_func.h" #include "../settings_type.h" #include "32bpp_optimized.hpp" #include "../safeguards.h" /** Instantiation of the optimized 32bpp blitter factory. */ static FBlitter_32bppOptimized iFBlitter_32bppOptimized; /** * Draws a sprite to a (screen) buffer. It is templated to allow faster operation. * * @tparam mode blitter mode * @param bp further blitting parameters * @param zoom zoom level at which we are drawing */ template inline void Blitter_32bppOptimized::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) { const SpriteData *src = (const SpriteData *)bp->sprite; /* src_px : each line begins with uint32 n = 'number of bytes in this line', * then n times is the Colour struct for this line */ const Colour *src_px = (const Colour *)(src->data + src->offset[zoom][0]); /* src_n : each line begins with uint32 n = 'number of bytes in this line', * then interleaved stream of 'm' and 'n' channels. 'm' is remap, * 'n' is number of bytes with the same alpha channel class */ const uint16 *src_n = (const uint16 *)(src->data + src->offset[zoom][1]); /* skip upper lines in src_px and src_n */ for (uint i = bp->skip_top; i != 0; i--) { src_px = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); src_n = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); } /* skip lines in dst */ Colour *dst = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; /* store so we don't have to access it via bp everytime (compiler assumes pointer aliasing) */ const byte *remap = bp->remap; for (int y = 0; y < bp->height; y++) { /* next dst line begins here */ Colour *dst_ln = dst + bp->pitch; /* next src line begins here */ const Colour *src_px_ln = (const Colour *)((const byte *)src_px + *(const uint32 *)src_px); src_px++; /* next src_n line begins here */ const uint16 *src_n_ln = (const uint16 *)((const byte *)src_n + *(const uint32 *)src_n); src_n += 2; /* we will end this line when we reach this point */ Colour *dst_end = dst + bp->skip_left; /* number of pixels with the same aplha channel class */ uint n; while (dst < dst_end) { n = *src_n++; if (src_px->a == 0) { dst += n; src_px ++; src_n++; } else { if (dst + n > dst_end) { uint d = dst_end - dst; src_px += d; src_n += d; dst = dst_end - bp->skip_left; dst_end = dst + bp->width; n = min(n - d, (uint)bp->width); goto draw; } dst += n; src_px += n; src_n += n; } } dst -= bp->skip_left; dst_end -= bp->skip_left; dst_end += bp->width; while (dst < dst_end) { n = min(*src_n++, (uint)(dst_end - dst)); if (src_px->a == 0) { dst += n; src_px++; src_n++; continue; } draw:; switch (mode) { case BM_COLOUR_REMAP: if (src_px->a == 255) { do { uint m = *src_n; /* In case the m-channel is zero, do not remap this pixel in any way */ if (m == 0) { *dst = src_px->data; } else { uint r = remap[GB(m, 0, 8)]; if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); } dst++; src_px++; src_n++; } while (--n != 0); } else { do { uint m = *src_n; if (m == 0) { *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); } else { uint r = remap[GB(m, 0, 8)]; if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); } dst++; src_px++; src_n++; } while (--n != 0); } break; case BM_CRASH_REMAP: if (src_px->a == 255) { do { uint m = *src_n; if (m == 0) { uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); } else { uint r = remap[GB(m, 0, 8)]; if (r != 0) *dst = this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)); } dst++; src_px++; src_n++; } while (--n != 0); } else { do { uint m = *src_n; if (m == 0) { if (src_px->a != 0) { uint8 g = MakeDark(src_px->r, src_px->g, src_px->b); *dst = ComposeColourRGBA(g, g, g, src_px->a, *dst); } } else { uint r = remap[GB(m, 0, 8)]; if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), GB(m, 8, 8)), src_px->a, *dst); } dst++; src_px++; src_n++; } while (--n != 0); } break; case BM_BLACK_REMAP: do { *dst = Colour(0, 0, 0); dst++; src_px++; src_n++; } while (--n != 0); break; case BM_TRANSPARENT: /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: * we produce a result the newgrf maker didn't expect ;) */ /* Make the current colour a bit more black, so it looks like this image is transparent */ src_n += n; if (src_px->a == 255) { src_px += n; do { *dst = MakeTransparent(*dst, 3, 4); dst++; } while (--n != 0); } else { do { *dst = MakeTransparent(*dst, (256 * 4 - src_px->a), 256 * 4); dst++; src_px++; } while (--n != 0); } break; default: if (src_px->a == 255) { /* faster than memcpy(), n is usually low */ src_n += n; do { *dst = src_px->data; dst++; src_px++; } while (--n != 0); } else { src_n += n; do { *dst = ComposeColourRGBANoCheck(src_px->r, src_px->g, src_px->b, src_px->a, *dst); dst++; src_px++; } while (--n != 0); } break; } } dst = dst_ln; src_px = src_px_ln; src_n = src_n_ln; } } /** * Draws a sprite to a (screen) buffer. Calls adequate templated function. * * @param bp further blitting parameters * @param mode blitter mode * @param zoom zoom level at which we are drawing */ void Blitter_32bppOptimized::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { switch (mode) { default: NOT_REACHED(); case BM_NORMAL: Draw (bp, zoom); return; case BM_COLOUR_REMAP: Draw(bp, zoom); return; case BM_TRANSPARENT: Draw (bp, zoom); return; case BM_CRASH_REMAP: Draw (bp, zoom); return; case BM_BLACK_REMAP: Draw (bp, zoom); return; } } Sprite *Blitter_32bppOptimized::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { /* streams of pixels (a, r, g, b channels) * * stored in separated stream so data are always aligned on 4B boundary */ Colour *dst_px_orig[ZOOM_LVL_COUNT]; /* interleaved stream of 'm' channel and 'n' channel * 'n' is number of following pixels with the same alpha channel class * there are 3 classes: 0, 255, others * * it has to be stored in one stream so fewer registers are used - * x86 has problems with register allocation even with this solution */ uint16 *dst_n_orig[ZOOM_LVL_COUNT]; /* lengths of streams */ uint32 lengths[ZOOM_LVL_COUNT][2]; ZoomLevel zoom_min; ZoomLevel zoom_max; if (sprite->type == ST_FONT) { zoom_min = ZOOM_LVL_NORMAL; zoom_max = ZOOM_LVL_NORMAL; } else { zoom_min = _settings_client.gui.zoom_min; zoom_max = _settings_client.gui.zoom_max; if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX; } for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { const SpriteLoader::Sprite *src_orig = &sprite[z]; uint size = src_orig->height * src_orig->width; dst_px_orig[z] = CallocT(size + src_orig->height * 2); dst_n_orig[z] = CallocT(size * 2 + src_orig->height * 4 * 2); uint32 *dst_px_ln = (uint32 *)dst_px_orig[z]; uint32 *dst_n_ln = (uint32 *)dst_n_orig[z]; const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *)src_orig->data; for (uint y = src_orig->height; y > 0; y--) { Colour *dst_px = (Colour *)(dst_px_ln + 1); uint16 *dst_n = (uint16 *)(dst_n_ln + 1); uint16 *dst_len = dst_n++; uint last = 3; int len = 0; for (uint x = src_orig->width; x > 0; x--) { uint8 a = src->a; uint t = a > 0 && a < 255 ? 1 : a; if (last != t || len == 65535) { if (last != 3) { *dst_len = len; dst_len = dst_n++; } len = 0; } last = t; len++; if (a != 0) { dst_px->a = a; *dst_n = src->m; if (src->m != 0) { /* Get brightest value */ uint8 rgb_max = max(src->r, max(src->g, src->b)); /* Black pixel (8bpp or old 32bpp image), so use default value */ if (rgb_max == 0) rgb_max = DEFAULT_BRIGHTNESS; *dst_n |= rgb_max << 8; /* Pre-convert the mapping channel to a RGB value */ Colour colour = this->AdjustBrightness(this->LookupColourInPalette(src->m), rgb_max); dst_px->r = colour.r; dst_px->g = colour.g; dst_px->b = colour.b; } else { dst_px->r = src->r; dst_px->g = src->g; dst_px->b = src->b; } dst_px++; dst_n++; } else if (len == 1) { dst_px++; *dst_n = src->m; dst_n++; } src++; } if (last != 3) { *dst_len = len; } dst_px = (Colour *)AlignPtr(dst_px, 4); dst_n = (uint16 *)AlignPtr(dst_n, 4); *dst_px_ln = (uint8 *)dst_px - (uint8 *)dst_px_ln; *dst_n_ln = (uint8 *)dst_n - (uint8 *)dst_n_ln; dst_px_ln = (uint32 *)dst_px; dst_n_ln = (uint32 *)dst_n; } lengths[z][0] = (byte *)dst_px_ln - (byte *)dst_px_orig[z]; // all are aligned to 4B boundary lengths[z][1] = (byte *)dst_n_ln - (byte *)dst_n_orig[z]; } uint len = 0; // total length of data for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { len += lengths[z][0] + lengths[z][1]; } Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + sizeof(SpriteData) + len); dest_sprite->height = sprite->height; dest_sprite->width = sprite->width; dest_sprite->x_offs = sprite->x_offs; dest_sprite->y_offs = sprite->y_offs; SpriteData *dst = (SpriteData *)dest_sprite->data; memset(dst, 0, sizeof(*dst)); for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { dst->offset[z][0] = z == zoom_min ? 0 : lengths[z - 1][1] + dst->offset[z - 1][1]; dst->offset[z][1] = lengths[z][0] + dst->offset[z][0]; memcpy(dst->data + dst->offset[z][0], dst_px_orig[z], lengths[z][0]); memcpy(dst->data + dst->offset[z][1], dst_n_orig[z], lengths[z][1]); free(dst_px_orig[z]); free(dst_n_orig[z]); } return dest_sprite; } openttd-1.5.3/src/blitter/null.cpp0000644000000000000000000000226612627373442015625 0ustar rootroot/* $Id: null.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 null.cpp A blitter that doesn't blit. */ #include "../stdafx.h" #include "null.hpp" #include "../safeguards.h" /** Instantiation of the null blitter factory. */ static FBlitter_Null iFBlitter_Null; Sprite *Blitter_Null::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { Sprite *dest_sprite; dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite)); dest_sprite->height = sprite->height; dest_sprite->width = sprite->width; dest_sprite->x_offs = sprite->x_offs; dest_sprite->y_offs = sprite->y_offs; return dest_sprite; } openttd-1.5.3/src/blitter/8bpp_base.hpp0000644000000000000000000000354612627373442016525 0ustar rootroot/* $Id: 8bpp_base.hpp 23448 2011-12-08 19:37:33Z rubidium $ */ /* * 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 8bpp_base.hpp Base for all 8 bpp blitters. */ #ifndef BLITTER_8BPP_BASE_HPP #define BLITTER_8BPP_BASE_HPP #include "base.hpp" /** Base for all 8bpp blitters. */ class Blitter_8bppBase : public Blitter { public: /* virtual */ uint8 GetScreenDepth() { return 8; } /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); /* virtual */ void *MoveTo(void *video, int x, int y); /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour); /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour); /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height); /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height); /* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch); /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y); /* virtual */ int BufferSize(int width, int height); /* virtual */ void PaletteAnimate(const Palette &palette); /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation(); /* virtual */ int GetBytesPerPixel() { return 1; } }; #endif /* BLITTER_8BPP_BASE_HPP */ openttd-1.5.3/src/blitter/32bpp_simple.cpp0000644000000000000000000001170212627373442017145 0ustar rootroot/* $Id: 32bpp_simple.cpp 26969 2014-10-06 18:45:51Z rubidium $ */ /* * 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 32bpp_simple.cpp Implementation of the simple 32 bpp blitter. */ #include "../stdafx.h" #include "../zoom_func.h" #include "32bpp_simple.hpp" #include "../table/sprites.h" #include "../safeguards.h" /** Instantiation of the simple 32bpp blitter factory. */ static FBlitter_32bppSimple iFBlitter_32bppSimple; void Blitter_32bppSimple::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) { const Blitter_32bppSimple::Pixel *src, *src_line; Colour *dst, *dst_line; /* Find where to start reading in the source sprite */ src_line = (const Blitter_32bppSimple::Pixel *)bp->sprite + (bp->skip_top * bp->sprite_width + bp->skip_left) * ScaleByZoom(1, zoom); dst_line = (Colour *)bp->dst + bp->top * bp->pitch + bp->left; for (int y = 0; y < bp->height; y++) { dst = dst_line; dst_line += bp->pitch; src = src_line; src_line += bp->sprite_width * ScaleByZoom(1, zoom); for (int x = 0; x < bp->width; x++) { switch (mode) { case BM_COLOUR_REMAP: /* In case the m-channel is zero, do not remap this pixel in any way */ if (src->m == 0) { if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst); } else { if (bp->remap[src->m] != 0) *dst = ComposeColourPA(this->AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst); } break; case BM_CRASH_REMAP: if (src->m == 0) { if (src->a != 0) { uint8 g = MakeDark(src->r, src->g, src->b); *dst = ComposeColourRGBA(g, g, g, src->a, *dst); } } else { if (bp->remap[src->m] != 0) *dst = ComposeColourPA(this->AdjustBrightness(this->LookupColourInPalette(bp->remap[src->m]), src->v), src->a, *dst); } break; case BM_BLACK_REMAP: if (src->a != 0) { *dst = Colour(0, 0, 0); } break; case BM_TRANSPARENT: /* TODO -- We make an assumption here that the remap in fact is transparency, not some colour. * This is never a problem with the code we produce, but newgrfs can make it fail... or at least: * we produce a result the newgrf maker didn't expect ;) */ /* Make the current colour a bit more black, so it looks like this image is transparent */ if (src->a != 0) *dst = MakeTransparent(*dst, 192); break; default: if (src->a != 0) *dst = ComposeColourRGBA(src->r, src->g, src->b, src->a, *dst); break; } dst++; src += ScaleByZoom(1, zoom); } } } void Blitter_32bppSimple::DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) { Colour *udst = (Colour *)dst; if (pal == PALETTE_TO_TRANSPARENT) { do { for (int i = 0; i != width; i++) { *udst = MakeTransparent(*udst, 154); udst++; } udst = udst - width + _screen.pitch; } while (--height); return; } if (pal == PALETTE_NEWSPAPER) { do { for (int i = 0; i != width; i++) { *udst = MakeGrey(*udst); udst++; } udst = udst - width + _screen.pitch; } while (--height); return; } DEBUG(misc, 0, "32bpp blitter doesn't know how to draw this colour table ('%d')", pal); } Sprite *Blitter_32bppSimple::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { Blitter_32bppSimple::Pixel *dst; Sprite *dest_sprite = (Sprite *)allocator(sizeof(*dest_sprite) + (size_t)sprite->height * (size_t)sprite->width * sizeof(*dst)); dest_sprite->height = sprite->height; dest_sprite->width = sprite->width; dest_sprite->x_offs = sprite->x_offs; dest_sprite->y_offs = sprite->y_offs; dst = (Blitter_32bppSimple::Pixel *)dest_sprite->data; SpriteLoader::CommonPixel *src = (SpriteLoader::CommonPixel *)sprite->data; for (int i = 0; i < sprite->height * sprite->width; i++) { if (src->m == 0) { dst[i].r = src->r; dst[i].g = src->g; dst[i].b = src->b; dst[i].a = src->a; dst[i].m = 0; dst[i].v = 0; } else { /* Get brightest value */ uint8 rgb_max = max(src->r, max(src->g, src->b)); /* Black pixel (8bpp or old 32bpp image), so use default value */ if (rgb_max == 0) rgb_max = DEFAULT_BRIGHTNESS; dst[i].v = rgb_max; /* Pre-convert the mapping channel to a RGB value */ Colour colour = this->AdjustBrightness(this->LookupColourInPalette(src->m), dst[i].v); dst[i].r = colour.r; dst[i].g = colour.g; dst[i].b = colour.b; dst[i].a = src->a; dst[i].m = src->m; } src++; } return dest_sprite; } openttd-1.5.3/src/blitter/32bpp_anim_sse4.hpp0000644000000000000000000000415712627373442017551 0ustar rootroot/* $Id: 32bpp_anim_sse4.hpp 26260 2014-01-13 18:20:23Z rubidium $ */ /* * 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 32bpp_sse4_anim.hpp A SSE4 32 bpp blitter with animation support. */ #ifndef BLITTER_32BPP_SSE4_ANIM_HPP #define BLITTER_32BPP_SSE4_ANIM_HPP #ifdef WITH_SSE #ifndef SSE_VERSION #define SSE_VERSION 4 #endif #ifndef FULL_ANIMATION #define FULL_ANIMATION 1 #endif #include "32bpp_anim.hpp" #include "32bpp_sse4.hpp" #undef MARGIN_NORMAL_THRESHOLD #define MARGIN_NORMAL_THRESHOLD 4 /** The SSE4 32 bpp blitter with palette animation. */ class Blitter_32bppSSE4_Anim FINAL : public Blitter_32bppAnim, public Blitter_32bppSSE_Base { private: public: template /* virtual */ void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { return Blitter_32bppSSE_Base::Encode(sprite, allocator); } /* virtual */ const char *GetName() { return "32bpp-sse4-anim"; } }; /** Factory for the SSE4 32 bpp blitter (with palette animation). */ class FBlitter_32bppSSE4_Anim: public BlitterFactory { public: FBlitter_32bppSSE4_Anim() : BlitterFactory("32bpp-sse4-anim", "SSE4 Blitter (palette animation)", HasCPUIDFlag(1, 2, 19)) {} /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE4_Anim(); } }; #endif /* WITH_SSE */ #endif /* BLITTER_32BPP_SSE4_ANIM_HPP */ openttd-1.5.3/src/blitter/null.hpp0000644000000000000000000000506612627373442015633 0ustar rootroot/* $Id: null.hpp 26209 2014-01-02 22:41:58Z rubidium $ */ /* * 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 null.hpp The blitter that doesn't blit. */ #ifndef BLITTER_NULL_HPP #define BLITTER_NULL_HPP #include "factory.hpp" /** Blitter that does nothing. */ class Blitter_Null : public Blitter { public: /* virtual */ uint8 GetScreenDepth() { return 0; } /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) {}; /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal) {}; /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); /* virtual */ void *MoveTo(void *video, int x, int y) { return NULL; }; /* virtual */ void SetPixel(void *video, int x, int y, uint8 colour) {}; /* virtual */ void DrawRect(void *video, int width, int height, uint8 colour) {}; /* virtual */ void DrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash) {}; /* virtual */ void CopyFromBuffer(void *video, const void *src, int width, int height) {}; /* virtual */ void CopyToBuffer(const void *video, void *dst, int width, int height) {}; /* virtual */ void CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) {}; /* virtual */ void ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) {}; /* virtual */ int BufferSize(int width, int height) { return 0; }; /* virtual */ void PaletteAnimate(const Palette &palette) { }; /* virtual */ Blitter::PaletteAnimation UsePaletteAnimation() { return Blitter::PALETTE_ANIMATION_NONE; }; /* virtual */ const char *GetName() { return "null"; } /* virtual */ int GetBytesPerPixel() { return 0; } }; /** Factory for the blitter that does nothing. */ class FBlitter_Null : public BlitterFactory { public: FBlitter_Null() : BlitterFactory("null", "Null Blitter (does nothing)") {} /* virtual */ Blitter *CreateInstance() { return new Blitter_Null(); } }; #endif /* BLITTER_NULL_HPP */ openttd-1.5.3/src/blitter/32bpp_sse_func.hpp0000644000000000000000000004173312627373442017475 0ustar rootroot/* $Id: 32bpp_sse_func.hpp 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 32bpp_sse_func.hpp Functions related to SSE 32 bpp blitter. */ #ifndef BLITTER_32BPP_SSE_FUNC_HPP #define BLITTER_32BPP_SSE_FUNC_HPP #ifdef WITH_SSE static inline void InsertFirstUint32(const uint32 value, __m128i &into) { #if (SSE_VERSION >= 4) into = _mm_insert_epi32(into, value, 0); #else into = _mm_insert_epi16(into, value, 0); into = _mm_insert_epi16(into, value >> 16, 1); #endif } static inline void InsertSecondUint32(const uint32 value, __m128i &into) { #if (SSE_VERSION >= 4) into = _mm_insert_epi32(into, value, 1); #else into = _mm_insert_epi16(into, value, 2); into = _mm_insert_epi16(into, value >> 16, 3); #endif } static inline void LoadUint64(const uint64 value, __m128i &into) { #ifdef _SQ64 into = _mm_cvtsi64_si128(value); #else #if (SSE_VERSION >= 4) into = _mm_cvtsi32_si128(value); InsertSecondUint32(value >> 32, into); #else (*(um128i*) &into).m128i_u64[0] = value; #endif #endif } static inline __m128i PackUnsaturated(__m128i from, const __m128i &mask) { #if (SSE_VERSION == 2) from = _mm_and_si128(from, mask); // PAND, wipe high bytes to keep low bytes when packing return _mm_packus_epi16(from, from); // PACKUSWB, pack 2 colours (with saturation) #else return _mm_shuffle_epi8(from, mask); #endif } static inline __m128i DistributeAlpha(const __m128i from, const __m128i &mask) { #if (SSE_VERSION == 2) __m128i alphaAB = _mm_shufflelo_epi16(from, 0x3F); // PSHUFLW, put alpha1 in front of each rgb1 return _mm_shufflehi_epi16(alphaAB, 0x3F); // PSHUFHW, put alpha2 in front of each rgb2 #else return _mm_shuffle_epi8(from, mask); #endif } static inline __m128i AlphaBlendTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &pack_mask) { __m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128()); // PUNPCKLBW, expand each uint8 into uint16 __m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128()); __m128i alphaAB = _mm_cmpgt_epi16(srcAB, _mm_setzero_si128()); // PCMPGTW, if (alpha > 0) a++; alphaAB = _mm_srli_epi16(alphaAB, 15); alphaAB = _mm_add_epi16(alphaAB, srcAB); alphaAB = DistributeAlpha(alphaAB, distribution_mask); srcAB = _mm_sub_epi16(srcAB, dstAB); // PSUBW, (r - Cr) srcAB = _mm_mullo_epi16(srcAB, alphaAB); // PMULLW, a*(r - Cr) srcAB = _mm_srli_epi16(srcAB, 8); // PSRLW, a*(r - Cr)/256 srcAB = _mm_add_epi16(srcAB, dstAB); // PADDW, a*(r - Cr)/256 + Cr return PackUnsaturated(srcAB, pack_mask); } /* Darken 2 pixels. * rgb = rgb * ((256/4) * 4 - (alpha/4)) / ((256/4) * 4) */ static inline __m128i DarkenTwoPixels(__m128i src, __m128i dst, const __m128i &distribution_mask, const __m128i &tr_nom_base) { __m128i srcAB = _mm_unpacklo_epi8(src, _mm_setzero_si128()); __m128i dstAB = _mm_unpacklo_epi8(dst, _mm_setzero_si128()); __m128i alphaAB = DistributeAlpha(srcAB, distribution_mask); alphaAB = _mm_srli_epi16(alphaAB, 2); // Reduce to 64 levels of shades so the max value fits in 16 bits. __m128i nom = _mm_sub_epi16(tr_nom_base, alphaAB); dstAB = _mm_mullo_epi16(dstAB, nom); dstAB = _mm_srli_epi16(dstAB, 8); return _mm_packus_epi16(dstAB, dstAB); } IGNORE_UNINITIALIZED_WARNING_START static Colour ReallyAdjustBrightness(Colour colour, uint8 brightness) { uint64 c16 = colour.b | (uint64) colour.g << 16 | (uint64) colour.r << 32; c16 *= brightness; uint64 c16_ob = c16; // Helps out of order execution. c16 /= Blitter_32bppBase::DEFAULT_BRIGHTNESS; c16 &= 0x01FF01FF01FFULL; /* Sum overbright (maximum for each rgb is 508, 9 bits, -255 is changed in -256 so we just have to take the 8 lower bits into account). */ c16_ob = (((c16_ob >> (8 + 7)) & 0x0100010001ULL) * 0xFF) & c16; const uint ob = ((uint16) c16_ob + (uint16) (c16_ob >> 16) + (uint16) (c16_ob >> 32)) / 2; const uint32 alpha32 = colour.data & 0xFF000000; __m128i ret; LoadUint64(c16, ret); if (ob != 0) { __m128i ob128 = _mm_cvtsi32_si128(ob); ob128 = _mm_shufflelo_epi16(ob128, 0xC0); __m128i white = OVERBRIGHT_VALUE_MASK; __m128i c128 = ret; ret = _mm_subs_epu16(white, c128); // PSUBUSW, (255 - rgb) ret = _mm_mullo_epi16(ret, ob128); // PMULLW, ob*(255 - rgb) ret = _mm_srli_epi16(ret, 8); // PSRLW, ob*(255 - rgb)/256 ret = _mm_add_epi16(ret, c128); // PADDW, ob*(255 - rgb)/256 + rgb } ret = _mm_packus_epi16(ret, ret); // PACKUSWB, saturate and pack. return alpha32 | _mm_cvtsi128_si32(ret); } IGNORE_UNINITIALIZED_WARNING_STOP /** ReallyAdjustBrightness() is not called that often. * Inlining this function implies a far jump, which has a huge latency. */ static inline Colour AdjustBrightneSSE(Colour colour, uint8 brightness) { /* Shortcut for normal brightness. */ if (brightness == Blitter_32bppBase::DEFAULT_BRIGHTNESS) return colour; return ReallyAdjustBrightness(colour, brightness); } static inline __m128i AdjustBrightnessOfTwoPixels(__m128i from, uint32 brightness) { #if (SSE_VERSION < 3) NOT_REACHED(); #else /* The following dataflow differs from the one of AdjustBrightness() only for alpha. * In order to keep alpha in colAB, insert a 1 in a unused brightness byte (a*1->a). * OK, not a 1 but DEFAULT_BRIGHTNESS to compensate the div. */ brightness &= 0xFF00FF00; brightness += Blitter_32bppBase::DEFAULT_BRIGHTNESS; __m128i colAB = _mm_unpacklo_epi8(from, _mm_setzero_si128()); __m128i briAB = _mm_cvtsi32_si128(brightness); briAB = _mm_shuffle_epi8(briAB, BRIGHTNESS_LOW_CONTROL_MASK); // DEFAULT_BRIGHTNESS in 0, 0x00 in 2. colAB = _mm_mullo_epi16(colAB, briAB); __m128i colAB_ob = _mm_srli_epi16(colAB, 8 + 7); colAB = _mm_srli_epi16(colAB, 7); /* Sum overbright. * Maximum for each rgb is 508 => 9 bits. The highest bit tells if there is overbright. * -255 is changed in -256 so we just have to take the 8 lower bits into account. */ colAB = _mm_and_si128(colAB, BRIGHTNESS_DIV_CLEANER); colAB_ob = _mm_and_si128(colAB_ob, OVERBRIGHT_PRESENCE_MASK); colAB_ob = _mm_mullo_epi16(colAB_ob, OVERBRIGHT_VALUE_MASK); colAB_ob = _mm_and_si128(colAB_ob, colAB); __m128i obAB = _mm_hadd_epi16(_mm_hadd_epi16(colAB_ob, _mm_setzero_si128()), _mm_setzero_si128()); obAB = _mm_srli_epi16(obAB, 1); // Reduce overbright strength. obAB = _mm_shuffle_epi8(obAB, OVERBRIGHT_CONTROL_MASK); __m128i retAB = OVERBRIGHT_VALUE_MASK; // ob_mask is equal to white. retAB = _mm_subs_epu16(retAB, colAB); // (255 - rgb) retAB = _mm_mullo_epi16(retAB, obAB); // ob*(255 - rgb) retAB = _mm_srli_epi16(retAB, 8); // ob*(255 - rgb)/256 retAB = _mm_add_epi16(retAB, colAB); // ob*(255 - rgb)/256 + rgb return _mm_packus_epi16(retAB, retAB); #endif } #if FULL_ANIMATION == 0 /** * Draws a sprite to a (screen) buffer. It is templated to allow faster operation. * * @tparam mode blitter mode * @param bp further blitting parameters * @param zoom zoom level at which we are drawing */ IGNORE_UNINITIALIZED_WARNING_START template #if (SSE_VERSION == 2) inline void Blitter_32bppSSE2::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) #elif (SSE_VERSION == 3) inline void Blitter_32bppSSSE3::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) #elif (SSE_VERSION == 4) inline void Blitter_32bppSSE4::Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom) #endif { const byte * const remap = bp->remap; Colour *dst_line = (Colour *) bp->dst + bp->top * bp->pitch + bp->left; int effective_width = bp->width; /* Find where to start reading in the source sprite. */ const SpriteData * const sd = (const SpriteData *) bp->sprite; const SpriteInfo * const si = &sd->infos[zoom]; const MapValue *src_mv_line = (const MapValue *) &sd->data[si->mv_offset] + bp->skip_top * si->sprite_width; const Colour *src_rgba_line = (const Colour *) ((const byte *) &sd->data[si->sprite_offset] + bp->skip_top * si->sprite_line_size); if (read_mode != RM_WITH_MARGIN) { src_rgba_line += bp->skip_left; src_mv_line += bp->skip_left; } const MapValue *src_mv = src_mv_line; /* Load these variables into register before loop. */ #if (SSE_VERSION == 2) const __m128i clear_hi = CLEAR_HIGH_BYTE_MASK; #define ALPHA_BLEND_PARAM_1 clear_hi #define ALPHA_BLEND_PARAM_2 clear_hi #define DARKEN_PARAM_1 tr_nom_base #define DARKEN_PARAM_2 tr_nom_base #else const __m128i a_cm = ALPHA_CONTROL_MASK; const __m128i pack_low_cm = PACK_LOW_CONTROL_MASK; #define ALPHA_BLEND_PARAM_1 a_cm #define ALPHA_BLEND_PARAM_2 pack_low_cm #define DARKEN_PARAM_1 a_cm #define DARKEN_PARAM_2 tr_nom_base #endif const __m128i tr_nom_base = TRANSPARENT_NOM_BASE; for (int y = bp->height; y != 0; y--) { Colour *dst = dst_line; const Colour *src = src_rgba_line + META_LENGTH; if (mode == BM_COLOUR_REMAP || mode == BM_CRASH_REMAP) src_mv = src_mv_line; if (read_mode == RM_WITH_MARGIN) { assert(bt_last == BT_NONE); // or you must ensure block type is preserved src += src_rgba_line[0].data; dst += src_rgba_line[0].data; if (mode == BM_COLOUR_REMAP || mode == BM_CRASH_REMAP) src_mv += src_rgba_line[0].data; const int width_diff = si->sprite_width - bp->width; effective_width = bp->width - (int) src_rgba_line[0].data; const int delta_diff = (int) src_rgba_line[1].data - width_diff; const int new_width = effective_width - delta_diff; effective_width = delta_diff > 0 ? new_width : effective_width; if (effective_width <= 0) goto next_line; } switch (mode) { default: if (!translucent) { for (uint x = (uint) effective_width; x > 0; x--) { if (src->a) *dst = *src; src++; dst++; } break; } for (uint x = (uint) effective_width / 2; x > 0; x--) { __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); _mm_storel_epi64((__m128i*) dst, AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2)); src += 2; dst += 2; } if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { __m128i srcABCD = _mm_cvtsi32_si128(src->data); __m128i dstABCD = _mm_cvtsi32_si128(dst->data); dst->data = _mm_cvtsi128_si32(AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2)); } break; case BM_COLOUR_REMAP: #if (SSE_VERSION >= 3) for (uint x = (uint) effective_width / 2; x > 0; x--) { __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); uint32 mvX2 = *((uint32 *) const_cast(src_mv)); /* Remap colours. */ if (mvX2 & 0x00FF00FF) { #define CMOV_REMAP(m_colour, m_colour_init, m_src, m_m) \ /* Written so the compiler uses CMOV. */ \ Colour m_colour = m_colour_init; \ { \ const Colour srcm = (Colour) (m_src); \ const uint m = (byte) (m_m); \ const uint r = remap[m]; \ const Colour cmap = (this->LookupColourInPalette(r).data & 0x00FFFFFF) | (srcm.data & 0xFF000000); \ m_colour = r == 0 ? m_colour : cmap; \ m_colour = m != 0 ? m_colour : srcm; \ } #ifdef _SQ64 uint64 srcs = _mm_cvtsi128_si64(srcABCD); uint64 remapped_src = 0; CMOV_REMAP(c0, 0, srcs, mvX2); remapped_src = c0.data; CMOV_REMAP(c1, 0, srcs >> 32, mvX2 >> 16); remapped_src |= (uint64) c1.data << 32; srcABCD = _mm_cvtsi64_si128(remapped_src); #else Colour remapped_src[2]; CMOV_REMAP(c0, 0, _mm_cvtsi128_si32(srcABCD), mvX2); remapped_src[0] = c0.data; CMOV_REMAP(c1, 0, src[1], mvX2 >> 16); remapped_src[1] = c1.data; srcABCD = _mm_loadl_epi64((__m128i*) &remapped_src); #endif if ((mvX2 & 0xFF00FF00) != 0x80008000) srcABCD = AdjustBrightnessOfTwoPixels(srcABCD, mvX2); } /* Blend colours. */ _mm_storel_epi64((__m128i *) dst, AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2)); dst += 2; src += 2; src_mv += 2; } if ((bt_last == BT_NONE && effective_width & 1) || bt_last == BT_ODD) { #else for (uint x = (uint) effective_width; x > 0; x--) { #endif /* In case the m-channel is zero, do not remap this pixel in any way. */ __m128i srcABCD; if (src_mv->m) { const uint r = remap[src_mv->m]; if (r != 0) { Colour remapped_colour = AdjustBrightneSSE(this->LookupColourInPalette(r), src_mv->v); if (src->a == 255) { *dst = remapped_colour; } else { remapped_colour.a = src->a; srcABCD = _mm_cvtsi32_si128(remapped_colour.data); goto bmcr_alpha_blend_single; } } } else { srcABCD = _mm_cvtsi32_si128(src->data); if (src->a < 255) { bmcr_alpha_blend_single: __m128i dstABCD = _mm_cvtsi32_si128(dst->data); srcABCD = AlphaBlendTwoPixels(srcABCD, dstABCD, ALPHA_BLEND_PARAM_1, ALPHA_BLEND_PARAM_2); } dst->data = _mm_cvtsi128_si32(srcABCD); } #if (SSE_VERSION == 2) src_mv++; dst++; src++; #endif } break; case BM_TRANSPARENT: /* Make the current colour a bit more black, so it looks like this image is transparent. */ for (uint x = (uint) bp->width / 2; x > 0; x--) { __m128i srcABCD = _mm_loadl_epi64((const __m128i*) src); __m128i dstABCD = _mm_loadl_epi64((__m128i*) dst); _mm_storel_epi64((__m128i *) dst, DarkenTwoPixels(srcABCD, dstABCD, DARKEN_PARAM_1, DARKEN_PARAM_2)); src += 2; dst += 2; } if ((bt_last == BT_NONE && bp->width & 1) || bt_last == BT_ODD) { __m128i srcABCD = _mm_cvtsi32_si128(src->data); __m128i dstABCD = _mm_cvtsi32_si128(dst->data); dst->data = _mm_cvtsi128_si32(DarkenTwoPixels(srcABCD, dstABCD, DARKEN_PARAM_1, DARKEN_PARAM_2)); } break; case BM_CRASH_REMAP: for (uint x = (uint) bp->width; x > 0; x--) { if (src_mv->m == 0) { if (src->a != 0) { uint8 g = MakeDark(src->r, src->g, src->b); *dst = ComposeColourRGBA(g, g, g, src->a, *dst); } } else { uint r = remap[src_mv->m]; if (r != 0) *dst = ComposeColourPANoCheck(this->AdjustBrightness(this->LookupColourInPalette(r), src_mv->v), src->a, *dst); } src_mv++; dst++; src++; } break; case BM_BLACK_REMAP: for (uint x = (uint) bp->width; x > 0; x--) { if (src->a != 0) { *dst = Colour(0, 0, 0); } src_mv++; dst++; src++; } break; } next_line: if (mode == BM_COLOUR_REMAP || mode == BM_CRASH_REMAP) src_mv_line += si->sprite_width; src_rgba_line = (const Colour*) ((const byte*) src_rgba_line + si->sprite_line_size); dst_line += bp->pitch; } } IGNORE_UNINITIALIZED_WARNING_STOP /** * Draws a sprite to a (screen) buffer. Calls adequate templated function. * * @param bp further blitting parameters * @param mode blitter mode * @param zoom zoom level at which we are drawing */ #if (SSE_VERSION == 2) void Blitter_32bppSSE2::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) #elif (SSE_VERSION == 3) void Blitter_32bppSSSE3::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) #elif (SSE_VERSION == 4) void Blitter_32bppSSE4::Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom) #endif { switch (mode) { default: { if (bp->skip_left != 0 || bp->width <= MARGIN_NORMAL_THRESHOLD) { bm_normal: const BlockType bt_last = (BlockType) (bp->width & 1); switch (bt_last) { default: Draw(bp, zoom); return; case BT_ODD: Draw(bp, zoom); return; } } else { if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags & SF_TRANSLUCENT) { Draw(bp, zoom); } else { Draw(bp, zoom); } return; } break; } case BM_COLOUR_REMAP: if (((const Blitter_32bppSSE_Base::SpriteData *) bp->sprite)->flags & SF_NO_REMAP) goto bm_normal; if (bp->skip_left != 0 || bp->width <= MARGIN_REMAP_THRESHOLD) { Draw(bp, zoom); return; } else { Draw(bp, zoom); return; } case BM_TRANSPARENT: Draw(bp, zoom); return; case BM_CRASH_REMAP: Draw(bp, zoom); return; case BM_BLACK_REMAP: Draw(bp, zoom); return; } } #endif /* FULL_ANIMATION */ #endif /* WITH_SSE */ #endif /* BLITTER_32BPP_SSE_FUNC_HPP */ openttd-1.5.3/src/blitter/8bpp_simple.hpp0000644000000000000000000000275612627373442017106 0ustar rootroot/* $Id: 8bpp_simple.hpp 26209 2014-01-02 22:41:58Z rubidium $ */ /* * 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 8bpp_simple.hpp Simple (and slow) 8 bpp blitter. */ #ifndef BLITTER_8BPP_SIMPLE_HPP #define BLITTER_8BPP_SIMPLE_HPP #include "8bpp_base.hpp" #include "factory.hpp" /** Most trivial 8bpp blitter. */ class Blitter_8bppSimple FINAL : public Blitter_8bppBase { public: /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); /* virtual */ const char *GetName() { return "8bpp-simple"; } }; /** Factory for the most trivial 8bpp blitter. */ class FBlitter_8bppSimple : public BlitterFactory { public: FBlitter_8bppSimple() : BlitterFactory("8bpp-simple", "8bpp Simple Blitter (relative slow, but never wrong)") {} /* virtual */ Blitter *CreateInstance() { return new Blitter_8bppSimple(); } }; #endif /* BLITTER_8BPP_SIMPLE_HPP */ openttd-1.5.3/src/blitter/32bpp_base.cpp0000644000000000000000000000764612627373442016602 0ustar rootroot/* $Id: 32bpp_base.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 32bpp_base.cpp Implementation of base for 32 bpp blitters. */ #include "../stdafx.h" #include "32bpp_base.hpp" #include "../safeguards.h" void *Blitter_32bppBase::MoveTo(void *video, int x, int y) { return (uint32 *)video + x + y * _screen.pitch; } void Blitter_32bppBase::SetPixel(void *video, int x, int y, uint8 colour) { *((Colour *)video + x + y * _screen.pitch) = LookupColourInPalette(colour); } void Blitter_32bppBase::DrawRect(void *video, int width, int height, uint8 colour) { Colour colour32 = LookupColourInPalette(colour); do { Colour *dst = (Colour *)video; for (int i = width; i > 0; i--) { *dst = colour32; dst++; } video = (uint32 *)video + _screen.pitch; } while (--height); } void Blitter_32bppBase::CopyFromBuffer(void *video, const void *src, int width, int height) { uint32 *dst = (uint32 *)video; const uint32 *usrc = (const uint32 *)src; for (; height > 0; height--) { memcpy(dst, usrc, width * sizeof(uint32)); usrc += width; dst += _screen.pitch; } } void Blitter_32bppBase::CopyToBuffer(const void *video, void *dst, int width, int height) { uint32 *udst = (uint32 *)dst; const uint32 *src = (const uint32 *)video; for (; height > 0; height--) { memcpy(udst, src, width * sizeof(uint32)); src += _screen.pitch; udst += width; } } void Blitter_32bppBase::CopyImageToBuffer(const void *video, void *dst, int width, int height, int dst_pitch) { uint32 *udst = (uint32 *)dst; const uint32 *src = (const uint32 *)video; for (; height > 0; height--) { memcpy(udst, src, width * sizeof(uint32)); src += _screen.pitch; udst += dst_pitch; } } void Blitter_32bppBase::ScrollBuffer(void *video, int &left, int &top, int &width, int &height, int scroll_x, int scroll_y) { const uint32 *src; uint32 *dst; if (scroll_y > 0) { /* Calculate pointers */ dst = (uint32 *)video + left + (top + height - 1) * _screen.pitch; src = dst - scroll_y * _screen.pitch; /* Decrease height and increase top */ top += scroll_y; height -= scroll_y; assert(height > 0); /* Adjust left & width */ if (scroll_x >= 0) { dst += scroll_x; left += scroll_x; width -= scroll_x; } else { src -= scroll_x; width += scroll_x; } for (int h = height; h > 0; h--) { memcpy(dst, src, width * sizeof(uint32)); src -= _screen.pitch; dst -= _screen.pitch; } } else { /* Calculate pointers */ dst = (uint32 *)video + left + top * _screen.pitch; src = dst - scroll_y * _screen.pitch; /* Decrease height. (scroll_y is <=0). */ height += scroll_y; assert(height > 0); /* Adjust left & width */ if (scroll_x >= 0) { dst += scroll_x; left += scroll_x; width -= scroll_x; } else { src -= scroll_x; width += scroll_x; } /* the y-displacement may be 0 therefore we have to use memmove, * because source and destination may overlap */ for (int h = height; h > 0; h--) { memmove(dst, src, width * sizeof(uint32)); src += _screen.pitch; dst += _screen.pitch; } } } int Blitter_32bppBase::BufferSize(int width, int height) { return width * height * sizeof(uint32); } void Blitter_32bppBase::PaletteAnimate(const Palette &palette) { /* By default, 32bpp doesn't have palette animation */ } Blitter::PaletteAnimation Blitter_32bppBase::UsePaletteAnimation() { return Blitter::PALETTE_ANIMATION_NONE; } openttd-1.5.3/src/blitter/32bpp_sse2.hpp0000644000000000000000000000756412627373442016550 0ustar rootroot/* $Id: 32bpp_sse2.hpp 26260 2014-01-13 18:20:23Z rubidium $ */ /* * 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 32bpp_sse2.hpp SSE2 32 bpp blitter. */ #ifndef BLITTER_32BPP_SSE2_HPP #define BLITTER_32BPP_SSE2_HPP #ifdef WITH_SSE #ifndef SSE_VERSION #define SSE_VERSION 2 #endif #ifndef FULL_ANIMATION #define FULL_ANIMATION 0 #endif #include "32bpp_sse_type.h" /** Base methods for 32bpp SSE blitters. */ class Blitter_32bppSSE_Base { public: virtual ~Blitter_32bppSSE_Base() {} struct MapValue { uint8 m; uint8 v; }; assert_compile(sizeof(MapValue) == 2); /** Helper for creating specialised functions for specific optimisations. */ enum ReadMode { RM_WITH_SKIP, ///< Use normal code for skipping empty pixels. RM_WITH_MARGIN, ///< Use cached number of empty pixels at begin and end of line to reduce work. RM_NONE, ///< No specialisation. }; /** Helper for creating specialised functions for the case where the sprite width is odd or even. */ enum BlockType { BT_EVEN, ///< An even number of pixels in the width; no need for a special case for the last pixel. BT_ODD, ///< An odd number of pixels in the width; special case for the last pixel. BT_NONE, ///< No specialisation for either case. }; /** Helper for using specialised functions designed to prevent whenever it's possible things like: * - IO (reading video buffer), * - calculations (alpha blending), * - heavy branching (remap lookups and animation buffer handling). */ enum SpriteFlags { SF_NONE = 0, SF_TRANSLUCENT = 1 << 1, ///< The sprite has at least 1 translucent pixel. SF_NO_REMAP = 1 << 2, ///< The sprite has no remappable colour pixel. SF_NO_ANIM = 1 << 3, ///< The sprite has no palette animated pixel. }; /** Data stored about a (single) sprite. */ struct SpriteInfo { uint32 sprite_offset; ///< The offset to the sprite data. uint32 mv_offset; ///< The offset to the map value data. uint16 sprite_line_size; ///< The size of a single line (pitch). uint16 sprite_width; ///< The width of the sprite. }; struct SpriteData { SpriteFlags flags; SpriteInfo infos[ZOOM_LVL_COUNT]; byte data[]; ///< Data, all zoomlevels. }; Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); }; DECLARE_ENUM_AS_BIT_SET(Blitter_32bppSSE_Base::SpriteFlags); /** The SSE2 32 bpp blitter (without palette animation). */ class Blitter_32bppSSE2 : public Blitter_32bppSimple, public Blitter_32bppSSE_Base { public: /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { return Blitter_32bppSSE_Base::Encode(sprite, allocator); } /* virtual */ const char *GetName() { return "32bpp-sse2"; } }; /** Factory for the SSE2 32 bpp blitter (without palette animation). */ class FBlitter_32bppSSE2 : public BlitterFactory { public: FBlitter_32bppSSE2() : BlitterFactory("32bpp-sse2", "32bpp SSE2 Blitter (no palette animation)", HasCPUIDFlag(1, 3, 26)) {} /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSE2(); } }; #endif /* WITH_SSE */ #endif /* BLITTER_32BPP_SSE2_HPP */ openttd-1.5.3/src/blitter/32bpp_simple.hpp0000644000000000000000000000345412627373442017157 0ustar rootroot/* $Id: 32bpp_simple.hpp 26209 2014-01-02 22:41:58Z rubidium $ */ /* * 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 32bpp_simple.hpp Simple 32 bpp blitter. */ #ifndef BLITTER_32BPP_SIMPLE_HPP #define BLITTER_32BPP_SIMPLE_HPP #include "32bpp_base.hpp" #include "factory.hpp" /** The most trivial 32 bpp blitter (without palette animation). */ class Blitter_32bppSimple : public Blitter_32bppBase { struct Pixel { uint8 r; ///< Red-channel uint8 g; ///< Green-channel uint8 b; ///< Blue-channel uint8 a; ///< Alpha-channel uint8 m; ///< Remap-channel uint8 v; ///< Brightness-channel }; public: /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); /* virtual */ void DrawColourMappingRect(void *dst, int width, int height, PaletteID pal); /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); /* virtual */ const char *GetName() { return "32bpp-simple"; } }; /** Factory for the simple 32 bpp blitter. */ class FBlitter_32bppSimple : public BlitterFactory { public: FBlitter_32bppSimple() : BlitterFactory("32bpp-simple", "32bpp Simple Blitter (no palette animation)") {} /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSimple(); } }; #endif /* BLITTER_32BPP_SIMPLE_HPP */ openttd-1.5.3/src/blitter/32bpp_sse4.cpp0000644000000000000000000000200212627373442016523 0ustar rootroot/* $Id: 32bpp_sse4.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 32bpp_sse4.cpp Implementation of the SSE4 32 bpp blitter. */ #ifdef WITH_SSE #include "../stdafx.h" #include "../zoom_func.h" #include "../settings_type.h" #include "32bpp_sse4.hpp" #include "32bpp_sse_func.hpp" #include "../safeguards.h" /** Instantiation of the SSE4 32bpp blitter factory. */ static FBlitter_32bppSSE4 iFBlitter_32bppSSE4; #endif /* WITH_SSE */ openttd-1.5.3/src/blitter/8bpp_optimized.hpp0000644000000000000000000000340212627373442017606 0ustar rootroot/* $Id: 8bpp_optimized.hpp 26209 2014-01-02 22:41:58Z rubidium $ */ /* * 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 8bpp_optimized.hpp An optimized 8 bpp blitter. */ #ifndef BLITTER_8BPP_OPTIMIZED_HPP #define BLITTER_8BPP_OPTIMIZED_HPP #include "8bpp_base.hpp" #include "factory.hpp" /** 8bpp blitter optimised for speed. */ class Blitter_8bppOptimized FINAL : public Blitter_8bppBase { public: /** Data stored about a (single) sprite. */ struct SpriteData { uint32 offset[ZOOM_LVL_COUNT]; ///< Offsets (from .data) to streams for different zoom levels. byte data[]; ///< Data, all zoomlevels. }; /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); /* virtual */ Sprite *Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator); /* virtual */ const char *GetName() { return "8bpp-optimized"; } }; /** Factory for the 8bpp blitter optimised for speed. */ class FBlitter_8bppOptimized : public BlitterFactory { public: FBlitter_8bppOptimized() : BlitterFactory("8bpp-optimized", "8bpp Optimized Blitter (compression + all-ZoomLevel cache)") {} /* virtual */ Blitter *CreateInstance() { return new Blitter_8bppOptimized(); } }; #endif /* BLITTER_8BPP_OPTIMIZED_HPP */ openttd-1.5.3/src/blitter/32bpp_ssse3.hpp0000644000000000000000000000337312627373442016726 0ustar rootroot/* $Id: 32bpp_ssse3.hpp 26260 2014-01-13 18:20:23Z rubidium $ */ /* * 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 32bpp_ssse3.hpp SSSE3 32 bpp blitter. */ #ifndef BLITTER_32BPP_SSSE3_HPP #define BLITTER_32BPP_SSSE3_HPP #ifdef WITH_SSE #ifndef SSE_VERSION #define SSE_VERSION 3 #endif #ifndef FULL_ANIMATION #define FULL_ANIMATION 0 #endif #include "32bpp_sse2.hpp" /** The SSSE3 32 bpp blitter (without palette animation). */ class Blitter_32bppSSSE3 : public Blitter_32bppSSE2 { public: /* virtual */ void Draw(Blitter::BlitterParams *bp, BlitterMode mode, ZoomLevel zoom); template void Draw(const Blitter::BlitterParams *bp, ZoomLevel zoom); /* virtual */ const char *GetName() { return "32bpp-ssse3"; } }; /** Factory for the SSSE3 32 bpp blitter (without palette animation). */ class FBlitter_32bppSSSE3: public BlitterFactory { public: FBlitter_32bppSSSE3() : BlitterFactory("32bpp-ssse3", "32bpp SSSE3 Blitter (no palette animation)", HasCPUIDFlag(1, 2, 9)) {} /* virtual */ Blitter *CreateInstance() { return new Blitter_32bppSSSE3(); } }; #endif /* WITH_SSE */ #endif /* BLITTER_32BPP_SSSE3_HPP */ openttd-1.5.3/src/blitter/32bpp_sse_type.h0000644000000000000000000000525112627373442017156 0ustar rootroot/* $Id: 32bpp_sse_type.h 26258 2014-01-13 18:12:33Z rubidium $ */ /* * 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 32bpp_sse_type.hpp Types related to SSE 32 bpp blitter. */ #ifndef BLITTER_32BPP_SSE_TYPE_HPP #define BLITTER_32BPP_SSE_TYPE_HPP #ifdef WITH_SSE #include "32bpp_simple.hpp" #if (SSE_VERSION == 2) #include #elif (SSE_VERSION == 3) #include #elif (SSE_VERSION == 4) #include #endif #define META_LENGTH 2 ///< Number of uint32 inserted before each line of pixels in a sprite. #define MARGIN_NORMAL_THRESHOLD (zoom == ZOOM_LVL_OUT_32X ? 8 : 4) ///< Minimum width to use margins with BM_NORMAL. #define MARGIN_REMAP_THRESHOLD 4 ///< Minimum width to use margins with BM_COLOUR_REMAP. #ifdef _MSC_VER #define ALIGN(n) __declspec(align(n)) #else #define ALIGN(n) __attribute__ ((aligned (n))) #endif typedef union ALIGN(16) um128i { __m128i m128i; uint8 m128i_u8[16]; uint16 m128i_u16[8]; uint32 m128i_u32[4]; uint64 m128i_u64[2]; } um128i; #define CLEAR_HIGH_BYTE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0) #define ALPHA_CONTROL_MASK _mm_setr_epi8( 6, 7, 6, 7, 6, 7, -1, -1, 14, 15, 14, 15, 14, 15, -1, -1) #define PACK_LOW_CONTROL_MASK _mm_setr_epi8( 0, 2, 4, -1, 8, 10, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1) #define PACK_HIGH_CONTROL_MASK _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, 0, 2, 4, -1, 8, 10, 12, -1) #define BRIGHTNESS_LOW_CONTROL_MASK _mm_setr_epi8( 1, 2, 1, 2, 1, 2, 0, 2, 3, 2, 3, 2, 3, 2, 0, 2) #define BRIGHTNESS_DIV_CLEANER _mm_setr_epi8(-1, 1, -1, 1, -1, 1, -1, 0, -1, 1, -1, 1, -1, 1, -1, 0) #define OVERBRIGHT_PRESENCE_MASK _mm_setr_epi8( 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0) #define OVERBRIGHT_VALUE_MASK _mm_setr_epi8(-1, 0, -1, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, 0, 0) #define OVERBRIGHT_CONTROL_MASK _mm_setr_epi8( 0, 1, 0, 1, 0, 1, 7, 7, 2, 3, 2, 3, 2, 3, 7, 7) #define TRANSPARENT_NOM_BASE _mm_setr_epi16(256, 256, 256, 256, 256, 256, 256, 256) #endif /* WITH_SSE */ #endif /* BLITTER_32BPP_SSE_TYPE_HPP */ openttd-1.5.3/src/blitter/32bpp_sse2.cpp0000644000000000000000000001223112627373442016526 0ustar rootroot/* $Id: 32bpp_sse2.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 32bpp_sse2.cpp Implementation of the SSE2 32 bpp blitter. */ #ifdef WITH_SSE #include "../stdafx.h" #include "../zoom_func.h" #include "../settings_type.h" #include "32bpp_sse2.hpp" #include "32bpp_sse_func.hpp" #include "../safeguards.h" /** Instantiation of the SSE2 32bpp blitter factory. */ static FBlitter_32bppSSE2 iFBlitter_32bppSSE2; Sprite *Blitter_32bppSSE_Base::Encode(const SpriteLoader::Sprite *sprite, AllocatorProc *allocator) { /* First uint32 of a line = the number of transparent pixels from the left. * Second uint32 of a line = the number of transparent pixels from the right. * Then all RGBA then all MV. */ ZoomLevel zoom_min = ZOOM_LVL_NORMAL; ZoomLevel zoom_max = ZOOM_LVL_NORMAL; if (sprite->type != ST_FONT) { zoom_min = _settings_client.gui.zoom_min; zoom_max = _settings_client.gui.zoom_max; if (zoom_max == zoom_min) zoom_max = ZOOM_LVL_MAX; } /* Calculate sizes and allocate. */ SpriteData sd; memset(&sd, 0, sizeof(sd)); uint all_sprites_size = 0; for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { const SpriteLoader::Sprite *src_sprite = &sprite[z]; sd.infos[z].sprite_width = src_sprite->width; sd.infos[z].sprite_offset = all_sprites_size; sd.infos[z].sprite_line_size = sizeof(Colour) * src_sprite->width + sizeof(uint32) * META_LENGTH; const uint rgba_size = sd.infos[z].sprite_line_size * src_sprite->height; sd.infos[z].mv_offset = all_sprites_size + rgba_size; const uint mv_size = sizeof(MapValue) * src_sprite->width * src_sprite->height; all_sprites_size += rgba_size + mv_size; } Sprite *dst_sprite = (Sprite *) allocator(sizeof(Sprite) + sizeof(SpriteData) + all_sprites_size); dst_sprite->height = sprite->height; dst_sprite->width = sprite->width; dst_sprite->x_offs = sprite->x_offs; dst_sprite->y_offs = sprite->y_offs; memcpy(dst_sprite->data, &sd, sizeof(SpriteData)); /* Copy colours and determine flags. */ bool has_remap = false; bool has_anim = false; bool has_translucency = false; for (ZoomLevel z = zoom_min; z <= zoom_max; z++) { const SpriteLoader::Sprite *src_sprite = &sprite[z]; const SpriteLoader::CommonPixel *src = (const SpriteLoader::CommonPixel *) src_sprite->data; Colour *dst_rgba_line = (Colour *) &dst_sprite->data[sizeof(SpriteData) + sd.infos[z].sprite_offset]; MapValue *dst_mv = (MapValue *) &dst_sprite->data[sizeof(SpriteData) + sd.infos[z].mv_offset]; for (uint y = src_sprite->height; y != 0; y--) { Colour *dst_rgba = dst_rgba_line + META_LENGTH; for (uint x = src_sprite->width; x != 0; x--) { if (src->a != 0) { dst_rgba->a = src->a; if (src->a != 0 && src->a != 255) has_translucency = true; dst_mv->m = src->m; if (src->m != 0) { /* Do some accounting for flags. */ has_remap = true; if (src->m >= PALETTE_ANIM_START) has_anim = true; /* Get brightest value (or default brightness if it's a black pixel). */ const uint8 rgb_max = max(src->r, max(src->g, src->b)); dst_mv->v = (rgb_max == 0) ? Blitter_32bppBase::DEFAULT_BRIGHTNESS : rgb_max; /* Pre-convert the mapping channel to a RGB value. */ const Colour colour = AdjustBrightneSSE(Blitter_32bppBase::LookupColourInPalette(src->m), dst_mv->v); dst_rgba->r = colour.r; dst_rgba->g = colour.g; dst_rgba->b = colour.b; } else { dst_rgba->r = src->r; dst_rgba->g = src->g; dst_rgba->b = src->b; dst_mv->v = Blitter_32bppBase::DEFAULT_BRIGHTNESS; } } else { dst_rgba->data = 0; *(uint16*) dst_mv = 0; } dst_rgba++; dst_mv++; src++; } /* Count the number of transparent pixels from the left. */ dst_rgba = dst_rgba_line + META_LENGTH; uint32 nb_pix_transp = 0; for (uint x = src_sprite->width; x != 0; x--) { if (dst_rgba->a == 0) nb_pix_transp++; else break; dst_rgba++; } (*dst_rgba_line).data = nb_pix_transp; Colour *nb_right = dst_rgba_line + 1; dst_rgba_line = (Colour*) ((byte*) dst_rgba_line + sd.infos[z].sprite_line_size); /* Count the number of transparent pixels from the right. */ dst_rgba = dst_rgba_line - 1; nb_pix_transp = 0; for (uint x = src_sprite->width; x != 0; x--) { if (dst_rgba->a == 0) nb_pix_transp++; else break; dst_rgba--; } (*nb_right).data = nb_pix_transp; } } /* Store sprite flags. */ sd.flags = SF_NONE; if (has_translucency) sd.flags |= SF_TRANSLUCENT; if (!has_remap) sd.flags |= SF_NO_REMAP; if (!has_anim) sd.flags |= SF_NO_ANIM; memcpy(dst_sprite->data, &sd, sizeof(SpriteData)); return dst_sprite; } #endif /* WITH_SSE */ openttd-1.5.3/src/slope_type.h0000644000000000000000000001456312627373434015042 0ustar rootroot/* $Id: slope_type.h 23595 2011-12-19 17:48:04Z rubidium $ */ /* * 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 slope_type.h Definitions of a slope. * This file defines the enumeration and helper functions for handling * the slope info of a tile. */ #ifndef SLOPE_TYPE_H #define SLOPE_TYPE_H #include "core/enum_type.hpp" /** * Enumeration of tile corners */ enum Corner { CORNER_W = 0, CORNER_S = 1, CORNER_E = 2, CORNER_N = 3, CORNER_END, CORNER_INVALID = 0xFF }; /** * Enumeration for the slope-type. * * This enumeration use the chars N,E,S,W corresponding the * direction north, east, south and west. The top corner of a tile * is the north-part of the tile. The whole slope is encoded with * 5 bits, 4 bits for each corner and 1 bit for a steep-flag. * * For halftile slopes an extra 3 bits are used to represent this * properly; 1 bit for a halftile-flag and 2 bits to encode which * extra side (corner) is leveled when the slope of the first 5 * bits is applied. This means that there can only be one leveled * slope for steep slopes, which is logical because two leveled * slopes would mean that it is not a steep slope as halftile * slopes only span one height level. */ enum Slope { SLOPE_FLAT = 0x00, ///< a flat tile SLOPE_W = 0x01, ///< the west corner of the tile is raised SLOPE_S = 0x02, ///< the south corner of the tile is raised SLOPE_E = 0x04, ///< the east corner of the tile is raised SLOPE_N = 0x08, ///< the north corner of the tile is raised SLOPE_STEEP = 0x10, ///< indicates the slope is steep SLOPE_NW = SLOPE_N | SLOPE_W, ///< north and west corner are raised SLOPE_SW = SLOPE_S | SLOPE_W, ///< south and west corner are raised SLOPE_SE = SLOPE_S | SLOPE_E, ///< south and east corner are raised SLOPE_NE = SLOPE_N | SLOPE_E, ///< north and east corner are raised SLOPE_EW = SLOPE_E | SLOPE_W, ///< east and west corner are raised SLOPE_NS = SLOPE_N | SLOPE_S, ///< north and south corner are raised SLOPE_ELEVATED = SLOPE_N | SLOPE_E | SLOPE_S | SLOPE_W, ///< bit mask containing all 'simple' slopes SLOPE_NWS = SLOPE_N | SLOPE_W | SLOPE_S, ///< north, west and south corner are raised SLOPE_WSE = SLOPE_W | SLOPE_S | SLOPE_E, ///< west, south and east corner are raised SLOPE_SEN = SLOPE_S | SLOPE_E | SLOPE_N, ///< south, east and north corner are raised SLOPE_ENW = SLOPE_E | SLOPE_N | SLOPE_W, ///< east, north and west corner are raised SLOPE_STEEP_W = SLOPE_STEEP | SLOPE_NWS, ///< a steep slope falling to east (from west) SLOPE_STEEP_S = SLOPE_STEEP | SLOPE_WSE, ///< a steep slope falling to north (from south) SLOPE_STEEP_E = SLOPE_STEEP | SLOPE_SEN, ///< a steep slope falling to west (from east) SLOPE_STEEP_N = SLOPE_STEEP | SLOPE_ENW, ///< a steep slope falling to south (from north) SLOPE_HALFTILE = 0x20, ///< one halftile is leveled (non continuous slope) SLOPE_HALFTILE_MASK = 0xE0, ///< three bits used for halftile slopes SLOPE_HALFTILE_W = SLOPE_HALFTILE | (CORNER_W << 6), ///< the west halftile is leveled (non continuous slope) SLOPE_HALFTILE_S = SLOPE_HALFTILE | (CORNER_S << 6), ///< the south halftile is leveled (non continuous slope) SLOPE_HALFTILE_E = SLOPE_HALFTILE | (CORNER_E << 6), ///< the east halftile is leveled (non continuous slope) SLOPE_HALFTILE_N = SLOPE_HALFTILE | (CORNER_N << 6), ///< the north halftile is leveled (non continuous slope) }; DECLARE_ENUM_AS_BIT_SET(Slope) /** * Helper for creating a bitset of slopes. * @param x The slope to convert into a bitset. */ #define M(x) (1 << (x)) /** Constant bitset with safe slopes for building a level crossing. */ static const uint32 VALID_LEVEL_CROSSING_SLOPES = M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT); #undef M /** * Enumeration for Foundations. */ enum Foundation { FOUNDATION_NONE, ///< The tile has no foundation, the slope remains unchanged. FOUNDATION_LEVELED, ///< The tile is leveled up to a flat slope. FOUNDATION_INCLINED_X, ///< The tile has an along X-axis inclined foundation. FOUNDATION_INCLINED_Y, ///< The tile has an along Y-axis inclined foundation. FOUNDATION_STEEP_LOWER, ///< The tile has a steep slope. The lowest corner is raised by a foundation to allow building railroad on the lower halftile. /* Halftile foundations */ FOUNDATION_STEEP_BOTH, ///< The tile has a steep slope. The lowest corner is raised by a foundation and the upper halftile is leveled. FOUNDATION_HALFTILE_W, ///< Level west halftile non-continuously. FOUNDATION_HALFTILE_S, ///< Level south halftile non-continuously. FOUNDATION_HALFTILE_E, ///< Level east halftile non-continuously. FOUNDATION_HALFTILE_N, ///< Level north halftile non-continuously. /* Special anti-zig-zag foundations for single horizontal/vertical track */ FOUNDATION_RAIL_W, ///< Foundation for TRACK_BIT_LEFT, but not a leveled foundation. FOUNDATION_RAIL_S, ///< Foundation for TRACK_BIT_LOWER, but not a leveled foundation. FOUNDATION_RAIL_E, ///< Foundation for TRACK_BIT_RIGHT, but not a leveled foundation. FOUNDATION_RAIL_N, ///< Foundation for TRACK_BIT_UPPER, but not a leveled foundation. FOUNDATION_INVALID = 0xFF, ///< Used inside "rail_cmd.cpp" to indicate invalid slope/track combination. }; #endif /* SLOPE_TYPE_H */ openttd-1.5.3/src/cargoaction.cpp0000644000000000000000000001767112627373441015504 0ustar rootroot/* $Id: cargoaction.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cargoaction.cpp Implementation of cargo actions. */ #include "stdafx.h" #include "economy_base.h" #include "cargoaction.h" #include "station_base.h" #include "safeguards.h" /** * Decides if a packet needs to be split. * @param cp Packet to be either split or moved in one piece. * @return Either new packet if splitting was necessary or the given one * otherwise. */ template CargoPacket *CargoMovement::Preprocess(CargoPacket *cp) { if (this->max_move < cp->Count()) { cp = cp->Split(this->max_move); this->max_move = 0; } else { this->max_move -= cp->Count(); } return cp; } /** * Determines the amount of cargo to be removed from a packet and removes that * from the metadata of the list. * @param cp Packet to be removed completely or partially. * @return Amount of cargo to be removed. */ template uint CargoRemoval::Preprocess(CargoPacket *cp) { if (this->max_move >= cp->Count()) { this->max_move -= cp->Count(); return cp->Count(); } else { uint ret = this->max_move; this->max_move = 0; return ret; } } /** * Finalize cargo removal. Either delete the packet or reduce it. * @param cp Packet to be removed or reduced. * @param remove Amount of cargo to be removed. * @return True if the packet was deleted, False if it was reduced. */ template bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove) { if (remove == cp->Count()) { delete cp; return true; } else { cp->Reduce(remove); return false; } } /** * Removes some cargo from a StationCargoList. * @param cp Packet to be removed. * @return True if the packet was completely delivered, false if only part of * it was. */ template<> bool CargoRemoval::operator()(CargoPacket *cp) { uint remove = this->Preprocess(cp); this->source->RemoveFromCache(cp, remove); return this->Postprocess(cp, remove); } /** * Removes some cargo from a VehicleCargoList. * @param cp Packet to be removed. * @return True if the packet was completely delivered, false if only part of * it was. */ template<> bool CargoRemoval::operator()(CargoPacket *cp) { uint remove = this->Preprocess(cp); this->source->RemoveFromMeta(cp, VehicleCargoList::MTA_KEEP, remove); return this->Postprocess(cp, remove); } /** * Delivers some cargo. * @param cp Packet to be delivered. * @return True if the packet was completely delivered, false if only part of * it was. */ bool CargoDelivery::operator()(CargoPacket *cp) { uint remove = this->Preprocess(cp); this->source->RemoveFromMeta(cp, VehicleCargoList::MTA_DELIVER, remove); this->payment->PayFinalDelivery(cp, remove); return this->Postprocess(cp, remove); } /** * Loads some cargo onto a vehicle. * @param cp Packet to be loaded. * @return True if the packet was completely loaded, false if part of it was. */ bool CargoLoad::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == NULL) return false; cp_new->SetLoadPlace(this->load_place); this->source->RemoveFromCache(cp_new, cp_new->Count()); this->destination->Append(cp_new, VehicleCargoList::MTA_KEEP); return cp_new == cp; } /** * Reserves some cargo for loading. * @param cp Packet to be reserved. * @return True if the packet was completely reserved, false if part of it was. */ bool CargoReservation::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == NULL) return false; cp_new->SetLoadPlace(this->load_place); this->source->reserved_count += cp_new->Count(); this->source->RemoveFromCache(cp_new, cp_new->Count()); this->destination->Append(cp_new, VehicleCargoList::MTA_LOAD); return cp_new == cp; } /** * Returns some reserved cargo. * @param cp Packet to be returned. * @return True if the packet was completely returned, false if part of it was. */ bool CargoReturn::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == NULL) cp_new = cp; assert(cp_new->Count() <= this->destination->reserved_count); this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_LOAD, cp_new->Count()); this->destination->reserved_count -= cp_new->Count(); this->destination->Append(cp_new, this->next); return cp_new == cp; } /** * Transfers some cargo from a vehicle to a station. * @param cp Packet to be transfered. * @return True if the packet was completely reserved, false if part of it was. */ bool CargoTransfer::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == NULL) return false; this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_TRANSFER, cp_new->Count()); /* No transfer credits here as they were already granted during Stage(). */ this->destination->Append(cp_new, cp_new->NextStation()); return cp_new == cp; } /** * Shifts some cargo from a vehicle to another one. * @param cp Packet to be shifted. * @return True if the packet was completely shifted, false if part of it was. */ bool CargoShift::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == NULL) cp_new = cp; this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_KEEP, cp_new->Count()); this->destination->Append(cp_new, VehicleCargoList::MTA_KEEP); return cp_new == cp; } /** * Reroutes some cargo from one Station sublist to another. * @param cp Packet to be rerouted. * @return True if the packet was completely rerouted, false if part of it was. */ bool StationCargoReroute::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == NULL) cp_new = cp; StationID next = this->ge->GetVia(cp_new->SourceStation(), this->avoid, this->avoid2); assert(next != this->avoid && next != this->avoid2); if (this->source != this->destination) { this->source->RemoveFromCache(cp_new, cp_new->Count()); this->destination->AddToCache(cp_new); } /* 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->destination->packets.Insert(next, cp_new); return cp_new == cp; } /** * Reroutes some cargo in a VehicleCargoList. * @param cp Packet to be rerouted. * @return True if the packet was completely rerouted, false if part of it was. */ bool VehicleCargoReroute::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == NULL) cp_new = cp; if (cp_new->NextStation() == this->avoid || cp_new->NextStation() == this->avoid2) { cp->SetNextStation(this->ge->GetVia(cp_new->SourceStation(), this->avoid, this->avoid2)); } if (this->source != this->destination) { this->source->RemoveFromMeta(cp_new, VehicleCargoList::MTA_TRANSFER, cp_new->Count()); this->destination->AddToMeta(cp_new, VehicleCargoList::MTA_TRANSFER); } /* Legal, as front pushing doesn't invalidate iterators in std::list. */ this->destination->packets.push_front(cp_new); return cp_new == cp; } template uint CargoRemoval::Preprocess(CargoPacket *cp); template uint CargoRemoval::Preprocess(CargoPacket *cp); template bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove); template bool CargoRemoval::Postprocess(CargoPacket *cp, uint remove); openttd-1.5.3/src/newgrf_industries.h0000644000000000000000000001005012627373436016405 0ustar rootroot/* $Id: newgrf_industries.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 newgrf_industries.h Functions for NewGRF industries. */ #ifndef NEWGRF_INDUSTRIES_H #define NEWGRF_INDUSTRIES_H #include "newgrf_town.h" /** Resolver for industry scopes. */ struct IndustriesScopeResolver : public ScopeResolver { TileIndex tile; ///< Tile owned by the industry. Industry *industry; ///< %Industry being resolved. IndustryType type; ///< Type of the industry. uint32 random_bits; ///< Random bits of the new industry. IndustriesScopeResolver(ResolverObject &ro, TileIndex tile, Industry *industry, IndustryType type, uint32 random_bits = 0); /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; /* virtual */ uint32 GetTriggers() const; /* virtual */ void SetTriggers(int triggers) const; /* virtual */ void StorePSA(uint pos, int32 value); }; /** Resolver for industries. */ struct IndustriesResolverObject : public ResolverObject { IndustriesScopeResolver industries_scope; ///< Scope resolver for the industry. TownScopeResolver *town_scope; ///< Scope resolver for the associated town (if needed and available, else \c NULL). IndustriesResolverObject(TileIndex tile, Industry *indus, IndustryType type, uint32 random_bits = 0, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); ~IndustriesResolverObject(); TownScopeResolver *GetTown(); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &industries_scope; case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); if (tsr != NULL) return tsr; /* FALL-THROUGH */ } default: return ResolverObject::GetScope(scope, relative); } } }; /** When should the industry(tile) be triggered for random bits? */ enum IndustryTrigger { /** Triggered each tile loop */ INDUSTRY_TRIGGER_TILELOOP_PROCESS = 1, /** Triggered (whole industry) each 256 ticks */ INDUSTRY_TRIGGER_256_TICKS = 2, /** Triggered on cargo delivery */ INDUSTRY_TRIGGER_CARGO_DELIVERY = 4, }; /** From where has callback #CBID_INDUSTRY_PROBABILITY been called */ enum IndustryAvailabilityCallType { IACT_MAPGENERATION, ///< during random map generation IACT_RANDOMCREATION, ///< during creation of random ingame industry IACT_USERCREATION, ///< from the Fund/build window IACT_PROSPECTCREATION, ///< from the Fund/build using prospecting }; /* in newgrf_industry.cpp */ uint16 GetIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, Industry *industry, IndustryType type, TileIndex tile); uint32 GetIndustryIDAtOffset(TileIndex new_tile, const Industry *i, uint32 cur_grfid); void IndustryProductionCallback(Industry *ind, int reason); CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type); uint32 GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCallType creation_type, uint32 default_prob); bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoID cargo_type); IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32 grf_id); /* in newgrf_industrytiles.cpp*/ uint32 GetNearbyIndustryTileInformation(byte parameter, TileIndex tile, IndustryID index, bool signed_offsets, bool grf_version8); #endif /* NEWGRF_INDUSTRIES_H */ openttd-1.5.3/src/depot_func.h0000644000000000000000000000314312627373445014777 0ustar rootroot/* $Id: depot_func.h 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 depot_func.h Functions related to depots. */ #ifndef DEPOT_FUNC_H #define DEPOT_FUNC_H #include "vehicle_type.h" #include "slope_func.h" void ShowDepotWindow(TileIndex tile, VehicleType type); void DeleteDepotHighlightOfVehicle(const Vehicle *v); /** * Find out if the slope of the tile is suitable to build a depot of given direction * @param direction The direction in which the depot's exit points * @param tileh The slope of the tile in question * @return true if the construction is possible */ static inline bool CanBuildDepotByTileh(DiagDirection direction, Slope tileh) { assert(tileh != SLOPE_FLAT); Slope entrance_corners = InclinedSlope(direction); /* For steep slopes both entrance corners must be raised (i.e. neither of them is the lowest corner), * For non-steep slopes at least one corner must be raised. */ return IsSteepSlope(tileh) ? (tileh & entrance_corners) == entrance_corners : (tileh & entrance_corners) != 0; } #endif /* DEPOT_FUNC_H */ openttd-1.5.3/src/vehicle_cmd.cpp0000644000000000000000000011442312627373435015451 0ustar rootroot/* $Id: vehicle_cmd.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 vehicle_cmd.cpp Commands for vehicles. */ #include "stdafx.h" #include "roadveh.h" #include "news_func.h" #include "airport.h" #include "cmd_helper.h" #include "command_func.h" #include "company_func.h" #include "train.h" #include "aircraft.h" #include "newgrf_text.h" #include "vehicle_func.h" #include "string_func.h" #include "depot_map.h" #include "vehiclelist.h" #include "engine_func.h" #include "articulated_vehicles.h" #include "autoreplace_gui.h" #include "group.h" #include "order_backup.h" #include "ship.h" #include "newgrf.h" #include "company_base.h" #include "table/strings.h" #include "safeguards.h" /* Tables used in vehicle.h to find the right command for a certain vehicle type */ const uint32 _veh_build_proc_table[] = { CMD_BUILD_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN), CMD_BUILD_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_ROAD_VEHICLE), CMD_BUILD_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_SHIP), CMD_BUILD_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_AIRCRAFT), }; const uint32 _veh_sell_proc_table[] = { CMD_SELL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_SELL_TRAIN), CMD_SELL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_SELL_ROAD_VEHICLE), CMD_SELL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_SELL_SHIP), CMD_SELL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_SELL_AIRCRAFT), }; const uint32 _veh_refit_proc_table[] = { CMD_REFIT_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_REFIT_TRAIN), CMD_REFIT_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE), CMD_REFIT_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_REFIT_SHIP), CMD_REFIT_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_REFIT_AIRCRAFT), }; const uint32 _send_to_depot_proc_table[] = { CMD_SEND_VEHICLE_TO_DEPOT | CMD_MSG(STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT), CMD_SEND_VEHICLE_TO_DEPOT | CMD_MSG(STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT), CMD_SEND_VEHICLE_TO_DEPOT | CMD_MSG(STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT), CMD_SEND_VEHICLE_TO_DEPOT | CMD_MSG(STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR), }; CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v); CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v); CommandCost CmdBuildShip (TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v); CommandCost CmdBuildAircraft (TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **v); /** * Build a vehicle. * @param tile tile of depot where the vehicle is built * @param flags for command * @param p1 various bitstuffed data * bits 0-15: vehicle type being built. * bits 16-31: vehicle type specific bits passed on to the vehicle build functions. * @param p2 User * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* Elementary check for valid location. */ if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR; VehicleType type = GetDepotVehicleType(tile); /* Validate the engine type. */ EngineID eid = GB(p1, 0, 16); if (!IsEngineBuildable(eid, type, _current_company)) return_cmd_error(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + type); const Engine *e = Engine::Get(eid); CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost()); /* Engines without valid cargo should not be available */ if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR; /* Check whether the number of vehicles we need to build can be built according to pool space. */ uint num_vehicles; switch (type) { case VEH_TRAIN: num_vehicles = (e->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) + CountArticulatedParts(eid, false); break; case VEH_ROAD: num_vehicles = 1 + CountArticulatedParts(eid, false); break; case VEH_SHIP: num_vehicles = 1; break; case VEH_AIRCRAFT: num_vehicles = e->u.air.subtype & AIR_CTOL ? 2 : 3; break; default: NOT_REACHED(); // Safe due to IsDepotTile() } if (!Vehicle::CanAllocateItem(num_vehicles)) return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); /* Check whether we can allocate a unit number. Autoreplace does not allocate * an unit number as it will (always) reuse the one of the replaced vehicle * and (train) wagons don't have an unit number in any scenario. */ UnitID unit_num = (flags & DC_AUTOREPLACE || (type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON)) ? 0 : GetFreeUnitNumber(type); if (unit_num == UINT16_MAX) return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); Vehicle *v; switch (type) { case VEH_TRAIN: value.AddCost(CmdBuildRailVehicle(tile, flags, e, GB(p1, 16, 16), &v)); break; case VEH_ROAD: value.AddCost(CmdBuildRoadVehicle(tile, flags, e, GB(p1, 16, 16), &v)); break; case VEH_SHIP: value.AddCost(CmdBuildShip (tile, flags, e, GB(p1, 16, 16), &v)); break; case VEH_AIRCRAFT: value.AddCost(CmdBuildAircraft (tile, flags, e, GB(p1, 16, 16), &v)); break; default: NOT_REACHED(); // Safe due to IsDepotTile() } if (value.Succeeded() && flags & DC_EXEC) { v->unitnumber = unit_num; v->value = value.GetCost(); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); InvalidateWindowClassesData(GetWindowClassForVehicleType(type), 0); SetWindowDirty(WC_COMPANY, _current_company); if (IsLocalCompany()) { InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the auto replace window (must be called before incrementing num_engines) } GroupStatistics::CountEngine(v, 1); GroupStatistics::UpdateAutoreplace(_current_company); if (v->IsPrimaryVehicle()) { GroupStatistics::CountVehicle(v, 1); OrderBackup::Restore(v, p2); } } return value; } CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *v, uint16 data, uint32 user); /** * Sell a vehicle. * @param tile unused. * @param flags for command. * @param p1 various bitstuffed data. * bits 0-19: vehicle ID being sold. * bits 20-30: vehicle type specific bits passed on to the vehicle build functions. * bit 31: make a backup of the vehicle's order (if an engine). * @param p2 User. * @param text unused. * @return the cost of this operation or an error. */ CommandCost CmdSellVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); if (v == NULL) return CMD_ERROR; Vehicle *front = v->First(); CommandCost ret = CheckOwnership(front->owner); if (ret.Failed()) return ret; if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); if (!front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); /* Can we actually make the order backup, i.e. are there enough orders? */ if (p1 & MAKE_ORDER_BACKUP_FLAG && front->orders.list != NULL && !front->orders.list->IsShared() && !Order::CanAllocateItem(front->orders.list->GetNumOrders())) { /* Only happens in exceptional cases when there aren't enough orders anyhow. * Thus it should be safe to just drop the orders in that case. */ p1 &= ~MAKE_ORDER_BACKUP_FLAG; } if (v->type == VEH_TRAIN) { ret = CmdSellRailWagon(flags, v, GB(p1, 20, 12), p2); } else { ret = CommandCost(EXPENSES_NEW_VEHICLES, -front->value); if (flags & DC_EXEC) { if (front->IsPrimaryVehicle() && p1 & MAKE_ORDER_BACKUP_FLAG) OrderBackup::Backup(front, p2); delete front; } } return ret; } /** * Helper to run the refit cost callback. * @param v The vehicle we are refitting, can be NULL. * @param engine_type Which engine to refit * @param new_cid Cargo type we are refitting to. * @param new_subtype New cargo subtype. * @param [out] auto_refit_allowed The refit is allowed as an auto-refit. * @return Price for refitting */ static int GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID new_cid, byte new_subtype, bool *auto_refit_allowed) { /* Prepare callback param with info about the new cargo type. */ const Engine *e = Engine::Get(engine_type); /* Is this vehicle a NewGRF vehicle? */ if (e->GetGRF() != NULL) { const CargoSpec *cs = CargoSpec::Get(new_cid); uint32 param1 = (cs->classes << 16) | (new_subtype << 8) | e->GetGRF()->cargo_map[new_cid]; uint16 cb_res = GetVehicleCallback(CBID_VEHICLE_REFIT_COST, param1, 0, engine_type, v); if (cb_res != CALLBACK_FAILED) { *auto_refit_allowed = HasBit(cb_res, 14); int factor = GB(cb_res, 0, 14); if (factor >= 0x2000) factor -= 0x4000; // Treat as signed integer. return factor; } } *auto_refit_allowed = e->info.refit_cost == 0; return (v == NULL || v->cargo_type != new_cid) ? e->info.refit_cost : 0; } /** * Learn the price of refitting a certain engine * @param v The vehicle we are refitting, can be NULL. * @param engine_type Which engine to refit * @param new_cid Cargo type we are refitting to. * @param new_subtype New cargo subtype. * @param [out] auto_refit_allowed The refit is allowed as an auto-refit. * @return Price for refitting */ static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoID new_cid, byte new_subtype, bool *auto_refit_allowed) { ExpensesType expense_type; const Engine *e = Engine::Get(engine_type); Price base_price; int cost_factor = GetRefitCostFactor(v, engine_type, new_cid, new_subtype, auto_refit_allowed); switch (e->type) { case VEH_SHIP: base_price = PR_BUILD_VEHICLE_SHIP; expense_type = EXPENSES_SHIP_RUN; break; case VEH_ROAD: base_price = PR_BUILD_VEHICLE_ROAD; expense_type = EXPENSES_ROADVEH_RUN; break; case VEH_AIRCRAFT: base_price = PR_BUILD_VEHICLE_AIRCRAFT; expense_type = EXPENSES_AIRCRAFT_RUN; break; case VEH_TRAIN: base_price = (e->u.rail.railveh_type == RAILVEH_WAGON) ? PR_BUILD_VEHICLE_WAGON : PR_BUILD_VEHICLE_TRAIN; cost_factor <<= 1; expense_type = EXPENSES_TRAIN_RUN; break; default: NOT_REACHED(); } if (cost_factor < 0) { return CommandCost(expense_type, -GetPrice(base_price, -cost_factor, e->GetGRF(), -10)); } else { return CommandCost(expense_type, GetPrice(base_price, cost_factor, e->GetGRF(), -10)); } } /** Helper structure for RefitVehicle() */ struct RefitResult { Vehicle *v; ///< Vehicle to refit uint capacity; ///< New capacity of vehicle uint mail_capacity; ///< New mail capacity of aircraft byte subtype; ///< cargo subtype to refit to }; /** * Refits a vehicle (chain). * This is the vehicle-type independent part of the CmdRefitXXX functions. * @param v The vehicle to refit. * @param only_this Whether to only refit this vehicle, or to check the rest of them. * @param num_vehicles Number of vehicles to refit (not counting articulated parts). Zero means the whole chain. * @param new_cid Cargotype to refit to * @param new_subtype Cargo subtype to refit to. 0xFF means to try keeping the same subtype according to GetBestFittingSubType(). * @param flags Command flags * @param auto_refit Refitting is done as automatic refitting outside a depot. * @return Refit cost. */ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, CargoID new_cid, byte new_subtype, DoCommandFlag flags, bool auto_refit) { CommandCost cost(v->GetExpenseType(false)); uint total_capacity = 0; uint total_mail_capacity = 0; num_vehicles = num_vehicles == 0 ? UINT8_MAX : num_vehicles; VehicleSet vehicles_to_refit; if (!only_this) { GetVehicleSet(vehicles_to_refit, v, num_vehicles); /* In this case, we need to check the whole chain. */ v = v->First(); } static SmallVector refit_result; refit_result.Clear(); v->InvalidateNewGRFCacheOfChain(); byte actual_subtype = new_subtype; for (; v != NULL; v = (only_this ? NULL : v->Next())) { /* Reset actual_subtype for every new vehicle */ if (!v->IsArticulatedPart()) actual_subtype = new_subtype; if (v->type == VEH_TRAIN && !vehicles_to_refit.Contains(v->index) && !only_this) continue; const Engine *e = v->GetEngine(); if (!e->CanCarryCargo()) continue; /* If the vehicle is not refittable, or does not allow automatic refitting, * count its capacity nevertheless if the cargo matches */ bool refittable = HasBit(e->info.refit_mask, new_cid) && (!auto_refit || HasBit(e->info.misc_flags, EF_AUTO_REFIT)); if (!refittable && v->cargo_type != new_cid) continue; /* Determine best fitting subtype if requested */ if (actual_subtype == 0xFF) { actual_subtype = GetBestFittingSubType(v, v, new_cid); } /* Back up the vehicle's cargo type */ CargoID temp_cid = v->cargo_type; byte temp_subtype = v->cargo_subtype; if (refittable) { v->cargo_type = new_cid; v->cargo_subtype = actual_subtype; } uint16 mail_capacity = 0; uint amount = e->DetermineCapacity(v, &mail_capacity); total_capacity += amount; /* mail_capacity will always be zero if the vehicle is not an aircraft. */ total_mail_capacity += mail_capacity; if (!refittable) continue; /* Restore the original cargo type */ v->cargo_type = temp_cid; v->cargo_subtype = temp_subtype; bool auto_refit_allowed; CommandCost refit_cost = GetRefitCost(v, v->engine_type, new_cid, actual_subtype, &auto_refit_allowed); if (auto_refit && (flags & DC_QUERY_COST) == 0 && !auto_refit_allowed) { /* Sorry, auto-refitting not allowed, subtract the cargo amount again from the total. * When querrying cost/capacity (for example in order refit GUI), we always assume 'allowed'. * It is not predictable. */ total_capacity -= amount; total_mail_capacity -= mail_capacity; if (v->cargo_type == new_cid) { /* Add the old capacity nevertheless, if the cargo matches */ total_capacity += v->cargo_cap; if (v->type == VEH_AIRCRAFT) total_mail_capacity += v->Next()->cargo_cap; } continue; } cost.AddCost(refit_cost); /* Record the refitting. * Do not execute the refitting immediately, so DetermineCapacity and GetRefitCost do the same in test and exec run. * (weird NewGRFs) * Note: * - If the capacity of vehicles depends on other vehicles in the chain, the actual capacity is * set after RefitVehicle() via ConsistChanged() and friends. The estimation via _returned_refit_capacity will be wrong. * - We have to call the refit cost callback with the pre-refit configuration of the chain because we want refit and * autorefit to behave the same, and we need its result for auto_refit_allowed. */ RefitResult *result = refit_result.Append(); result->v = v; result->capacity = amount; result->mail_capacity = mail_capacity; result->subtype = actual_subtype; } if (flags & DC_EXEC) { /* Store the result */ for (RefitResult *result = refit_result.Begin(); result != refit_result.End(); result++) { Vehicle *u = result->v; u->refit_cap = (u->cargo_type == new_cid) ? min(result->capacity, u->refit_cap) : 0; if (u->cargo.TotalCount() > u->refit_cap) u->cargo.Truncate(u->cargo.TotalCount() - u->refit_cap); u->cargo_type = new_cid; u->cargo_cap = result->capacity; u->cargo_subtype = result->subtype; if (u->type == VEH_AIRCRAFT) { Vehicle *w = u->Next(); w->refit_cap = min(w->refit_cap, result->mail_capacity); w->cargo_cap = result->mail_capacity; if (w->cargo.TotalCount() > w->refit_cap) w->cargo.Truncate(w->cargo.TotalCount() - w->refit_cap); } } } refit_result.Clear(); _returned_refit_capacity = total_capacity; _returned_mail_refit_capacity = total_mail_capacity; return cost; } /** * Refits a vehicle to the specified cargo type. * @param tile unused * @param flags type of operation * @param p1 vehicle ID to refit * @param p2 various bitstuffed elements * - p2 = (bit 0-4) - New cargo type to refit to. * - p2 = (bit 6) - Automatic refitting. * - p2 = (bit 7) - Refit only this vehicle. Used only for cloning vehicles. * - p2 = (bit 8-15) - New cargo subtype to refit to. 0xFF means to try keeping the same subtype according to GetBestFittingSubType(). * - p2 = (bit 16-23) - Number of vehicles to refit (not counting articulated parts). Zero means all vehicles. * Only used if "refit only this vehicle" is false. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL) return CMD_ERROR; /* Don't allow disasters and sparks and such to be refitted. * We cannot check for IsPrimaryVehicle as autoreplace also refits in free wagon chains. */ if (!IsCompanyBuildableVehicleType(v->type)) return CMD_ERROR; Vehicle *front = v->First(); CommandCost ret = CheckOwnership(front->owner); if (ret.Failed()) return ret; bool auto_refit = HasBit(p2, 6); bool free_wagon = v->type == VEH_TRAIN && Train::From(front)->IsFreeWagon(); // used by autoreplace/renew /* Don't allow shadows and such to be refitted. */ if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return CMD_ERROR; /* Allow auto-refitting only during loading and normal refitting only in a depot. */ if ((flags & DC_QUERY_COST) == 0 && // used by the refit GUI, including the order refit GUI. !free_wagon && // used by autoreplace/renew (!auto_refit || !front->current_order.IsType(OT_LOADING)) && // refit inside stations !front->IsStoppedInDepot()) { // refit inside depots return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); } if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); /* Check cargo */ CargoID new_cid = GB(p2, 0, 5); byte new_subtype = GB(p2, 8, 8); if (new_cid >= NUM_CARGO) return CMD_ERROR; /* For ships and aircrafts there is always only one. */ bool only_this = HasBit(p2, 7) || front->type == VEH_SHIP || front->type == VEH_AIRCRAFT; uint8 num_vehicles = GB(p2, 16, 8); CommandCost cost = RefitVehicle(v, only_this, num_vehicles, new_cid, new_subtype, flags, auto_refit); if (flags & DC_EXEC) { /* Update the cached variables */ switch (v->type) { case VEH_TRAIN: Train::From(front)->ConsistChanged(auto_refit ? CCF_AUTOREFIT : CCF_REFIT); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(front), auto_refit); if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) RoadVehicle::From(front)->CargoChanged(); break; case VEH_SHIP: v->InvalidateNewGRFCacheOfChain(); Ship::From(v)->UpdateCache(); break; case VEH_AIRCRAFT: v->InvalidateNewGRFCacheOfChain(); UpdateAircraftCache(Aircraft::From(v), true); break; default: NOT_REACHED(); } front->MarkDirty(); if (!free_wagon) { InvalidateWindowData(WC_VEHICLE_DETAILS, front->index); InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0); } SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); } else { /* Always invalidate the cache; querycost might have filled it. */ v->InvalidateNewGRFCacheOfChain(); } return cost; } /** * Start/Stop a vehicle * @param tile unused * @param flags type of operation * @param p1 vehicle to start/stop, don't forget to change CcStartStopVehicle if you modify this! * @param p2 bit 0: Shall the start/stop newgrf callback be evaluated (only valid with DC_AUTOREPLACE for network safety) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* Disable the effect of p2 bit 0, when DC_AUTOREPLACE is not set */ if ((flags & DC_AUTOREPLACE) == 0) SetBit(p2, 0); Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); switch (v->type) { case VEH_TRAIN: if ((v->vehstatus & VS_STOPPED) && Train::From(v)->gcache.cached_power == 0) return_cmd_error(STR_ERROR_TRAIN_START_NO_POWER); break; case VEH_SHIP: case VEH_ROAD: break; case VEH_AIRCRAFT: { Aircraft *a = Aircraft::From(v); /* cannot stop airplane when in flight, or when taking off / landing */ if (!(v->vehstatus & VS_CRASHED) && a->state >= STARTTAKEOFF && a->state < TERM7) return_cmd_error(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT); break; } default: return CMD_ERROR; } if (HasBit(p2, 0)) { /* Check if this vehicle can be started/stopped. Failure means 'allow'. */ uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); StringID error = STR_NULL; if (callback != CALLBACK_FAILED) { if (v->GetGRF()->grf_version < 8) { /* 8 bit result 0xFF means 'allow' */ if (callback < 0x400 && GB(callback, 0, 8) != 0xFF) error = GetGRFStringID(v->GetGRFID(), 0xD000 + callback); } else { if (callback < 0x400) { error = GetGRFStringID(v->GetGRFID(), 0xD000 + callback); } else { switch (callback) { case 0x400: // allow break; default: // unknown reason -> disallow error = STR_ERROR_INCOMPATIBLE_RAIL_TYPES; break; } } } } if (error != STR_NULL) return_cmd_error(error); } if (flags & DC_EXEC) { if (v->IsStoppedInDepot() && (flags & DC_AUTOREPLACE) == 0) DeleteVehicleNews(p1, STR_NEWS_TRAIN_IS_WAITING + v->type); v->vehstatus ^= VS_STOPPED; if (v->type != VEH_TRAIN) v->cur_speed = 0; // trains can stop 'slowly' v->MarkDirty(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); SetWindowClassesDirty(GetWindowClassForVehicleType(v->type)); } return CommandCost(); } /** * Starts or stops a lot of vehicles * @param tile Tile of the depot where the vehicles are started/stopped (only used for depots) * @param flags type of operation * @param p1 bitmask * - bit 0 set = start vehicles, unset = stop vehicles * - bit 1 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case * @param p2 packed VehicleListIdentifier * @param text unused * @return the cost of this operation or an error */ CommandCost CmdMassStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleList list; bool do_start = HasBit(p1, 0); bool vehicle_list_window = HasBit(p1, 1); VehicleListIdentifier vli; if (!vli.Unpack(p2)) return CMD_ERROR; if (!IsCompanyBuildableVehicleType(vli.vtype)) return CMD_ERROR; if (vehicle_list_window) { if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR; } else { /* Get the list of vehicles in the depot */ BuildDepotVehicleList(vli.vtype, tile, &list, NULL); } for (uint i = 0; i < list.Length(); i++) { const Vehicle *v = list[i]; if (!!(v->vehstatus & VS_STOPPED) != do_start) continue; if (!vehicle_list_window && !v->IsChainInDepot()) continue; /* Just try and don't care if some vehicle's can't be stopped. */ DoCommand(tile, v->index, 0, flags, CMD_START_STOP_VEHICLE); } return CommandCost(); } /** * Sells all vehicles in a depot * @param tile Tile of the depot where the depot is * @param flags type of operation * @param p1 Vehicle type * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdDepotSellAllVehicles(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleList list; CommandCost cost(EXPENSES_NEW_VEHICLES); VehicleType vehicle_type = Extract(p1); if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR; uint sell_command = GetCmdSellVeh(vehicle_type); /* Get the list of vehicles in the depot */ BuildDepotVehicleList(vehicle_type, tile, &list, &list); CommandCost last_error = CMD_ERROR; bool had_success = false; for (uint i = 0; i < list.Length(); i++) { CommandCost ret = DoCommand(tile, list[i]->index | (1 << 20), 0, flags, sell_command); if (ret.Succeeded()) { cost.AddCost(ret); had_success = true; } else { last_error = ret; } } return had_success ? cost : last_error; } /** * Autoreplace all vehicles in the depot * @param tile Tile of the depot where the vehicles are * @param flags type of operation * @param p1 Type of vehicle * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdDepotMassAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleList list; CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES); VehicleType vehicle_type = Extract(p1); if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR; if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR; /* Get the list of vehicles in the depot */ BuildDepotVehicleList(vehicle_type, tile, &list, &list, true); for (uint i = 0; i < list.Length(); i++) { const Vehicle *v = list[i]; /* Ensure that the vehicle completely in the depot */ if (!v->IsChainInDepot()) continue; CommandCost ret = DoCommand(0, v->index, 0, flags, CMD_AUTOREPLACE_VEHICLE); if (ret.Succeeded()) cost.AddCost(ret); } return cost; } /** * Test if a name is unique among vehicle names. * @param name Name to test. * @return True ifffffff the name is unique. */ static bool IsUniqueVehicleName(const char *name) { const Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->name != NULL && strcmp(v->name, name) == 0) return false; } return true; } /** * Clone the custom name of a vehicle, adding or incrementing a number. * @param src Source vehicle, with a custom name. * @param dst Destination vehicle. */ static void CloneVehicleName(const Vehicle *src, Vehicle *dst) { char buf[256]; /* Find the position of the first digit in the last group of digits. */ size_t number_position; for (number_position = strlen(src->name); number_position > 0; number_position--) { /* The design of UTF-8 lets this work simply without having to check * for UTF-8 sequences. */ if (src->name[number_position - 1] < '0' || src->name[number_position - 1] > '9') break; } /* Format buffer and determine starting number. */ int num; byte padding = 0; if (number_position == strlen(src->name)) { /* No digit at the end, so start at number 2. */ strecpy(buf, src->name, lastof(buf)); strecat(buf, " ", lastof(buf)); number_position = strlen(buf); num = 2; } else { /* Found digits, parse them and start at the next number. */ strecpy(buf, src->name, lastof(buf)); buf[number_position] = '\0'; char *endptr; num = strtol(&src->name[number_position], &endptr, 10) + 1; padding = endptr - &src->name[number_position]; } /* Check if this name is already taken. */ for (int max_iterations = 1000; max_iterations > 0; max_iterations--, num++) { /* Attach the number to the temporary name. */ seprintf(&buf[number_position], lastof(buf), "%0*d", padding, num); /* Check the name is unique. */ if (IsUniqueVehicleName(buf)) { dst->name = stredup(buf); break; } } /* All done. If we didn't find a name, it'll just use its default. */ } /** * Clone a vehicle. If it is a train, it will clone all the cars too * @param tile tile of the depot where the cloned vehicle is build * @param flags type of operation * @param p1 the original vehicle's index * @param p2 1 = shared orders, else copied orders * @param text unused * @return the cost of this operation or an error */ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CommandCost total_cost(EXPENSES_NEW_VEHICLES); Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; Vehicle *v_front = v; Vehicle *w = NULL; Vehicle *w_front = NULL; Vehicle *w_rear = NULL; /* * v_front is the front engine in the original vehicle * v is the car/vehicle of the original vehicle that is currently being copied * w_front is the front engine of the cloned vehicle * w is the car/vehicle currently being cloned * w_rear is the rear end of the cloned train. It's used to add more cars and is only used by trains */ CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (v->type == VEH_TRAIN && (!v->IsFrontEngine() || Train::From(v)->crash_anim_pos >= 4400)) return CMD_ERROR; /* check that we can allocate enough vehicles */ if (!(flags & DC_EXEC)) { int veh_counter = 0; do { veh_counter++; } while ((v = v->Next()) != NULL); if (!Vehicle::CanAllocateItem(veh_counter)) { return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); } } v = v_front; do { if (v->type == VEH_TRAIN && Train::From(v)->IsRearDualheaded()) { /* we build the rear ends of multiheaded trains with the front ones */ continue; } /* In case we're building a multi headed vehicle and the maximum number of * vehicles is almost reached (e.g. max trains - 1) not all vehicles would * be cloned. When the non-primary engines were build they were seen as * 'new' vehicles whereas they would immediately be joined with a primary * engine. This caused the vehicle to be not build as 'the limit' had been * reached, resulting in partially build vehicles and such. */ DoCommandFlag build_flags = flags; if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE; CommandCost cost = DoCommand(tile, v->engine_type | (1 << 16), 0, build_flags, GetCmdBuildVeh(v)); if (cost.Failed()) { /* Can't build a part, then sell the stuff we already made; clear up the mess */ if (w_front != NULL) DoCommand(w_front->tile, w_front->index | (1 << 20), 0, flags, GetCmdSellVeh(w_front)); return cost; } total_cost.AddCost(cost); if (flags & DC_EXEC) { w = Vehicle::Get(_new_vehicle_id); if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) { SetBit(Train::From(w)->flags, VRF_REVERSE_DIRECTION); } if (v->type == VEH_TRAIN && !v->IsFrontEngine()) { /* this s a train car * add this unit to the end of the train */ CommandCost result = DoCommand(0, w->index | 1 << 20, w_rear->index, flags, CMD_MOVE_RAIL_VEHICLE); if (result.Failed()) { /* The train can't be joined to make the same consist as the original. * Sell what we already made (clean up) and return an error. */ DoCommand(w_front->tile, w_front->index | 1 << 20, 0, flags, GetCmdSellVeh(w_front)); DoCommand(w_front->tile, w->index | 1 << 20, 0, flags, GetCmdSellVeh(w)); return result; // return error and the message returned from CMD_MOVE_RAIL_VEHICLE } } else { /* this is a front engine or not a train. */ w_front = w; w->service_interval = v->service_interval; w->SetServiceIntervalIsCustom(v->ServiceIntervalIsCustom()); w->SetServiceIntervalIsPercent(v->ServiceIntervalIsPercent()); } w_rear = w; // trains needs to know the last car in the train, so they can add more in next loop } } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != NULL); if ((flags & DC_EXEC) && v_front->type == VEH_TRAIN) { /* for trains this needs to be the front engine due to the callback function */ _new_vehicle_id = w_front->index; } if (flags & DC_EXEC) { /* Cloned vehicles belong to the same group */ DoCommand(0, v_front->group_id, w_front->index, flags, CMD_ADD_VEHICLE_GROUP); } /* Take care of refitting. */ w = w_front; v = v_front; /* Both building and refitting are influenced by newgrf callbacks, which * makes it impossible to accurately estimate the cloning costs. In * particular, it is possible for engines of the same type to be built with * different numbers of articulated parts, so when refitting we have to * loop over real vehicles first, and then the articulated parts of those * vehicles in a different loop. */ do { do { if (flags & DC_EXEC) { assert(w != NULL); /* Find out what's the best sub type */ byte subtype = GetBestFittingSubType(v, w, v->cargo_type); if (w->cargo_type != v->cargo_type || w->cargo_subtype != subtype) { CommandCost cost = DoCommand(0, w->index, v->cargo_type | 1U << 7 | (subtype << 8), flags, GetCmdRefitVeh(v)); if (cost.Succeeded()) total_cost.AddCost(cost); } if (w->IsGroundVehicle() && w->HasArticulatedPart()) { w = w->GetNextArticulatedPart(); } else { break; } } else { const Engine *e = v->GetEngine(); CargoID initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID); if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) { bool dummy; total_cost.AddCost(GetRefitCost(NULL, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy)); } } if (v->IsGroundVehicle() && v->HasArticulatedPart()) { v = v->GetNextArticulatedPart(); } else { break; } } while (v != NULL); if ((flags & DC_EXEC) && v->type == VEH_TRAIN) w = w->GetNextVehicle(); } while (v->type == VEH_TRAIN && (v = v->GetNextVehicle()) != NULL); if (flags & DC_EXEC) { /* * Set the orders of the vehicle. Cannot do it earlier as we need * the vehicle refitted before doing this, otherwise the moved * cargo types might not match (passenger vs non-passenger) */ DoCommand(0, w_front->index | (p2 & 1 ? CO_SHARE : CO_COPY) << 30, v_front->index, flags, CMD_CLONE_ORDER); /* Now clone the vehicle's name, if it has one. */ if (v_front->name != NULL) CloneVehicleName(v_front, w_front); } /* Since we can't estimate the cost of cloning a vehicle accurately we must * check whether the company has enough money manually. */ if (!CheckCompanyHasMoney(total_cost)) { if (flags & DC_EXEC) { /* The vehicle has already been bought, so now it must be sold again. */ DoCommand(w_front->tile, w_front->index | 1 << 20, 0, flags, GetCmdSellVeh(w_front)); } return total_cost; } return total_cost; } /** * Send all vehicles of type to depots * @param flags the flags used for DoCommand() * @param service should the vehicles only get service in the depots * @param vli identifier of the vehicle list * @return 0 for success and CMD_ERROR if no vehicle is able to go to depot */ static CommandCost SendAllVehiclesToDepot(DoCommandFlag flags, bool service, const VehicleListIdentifier &vli) { VehicleList list; if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR; /* Send all the vehicles to a depot */ bool had_success = false; for (uint i = 0; i < list.Length(); i++) { const Vehicle *v = list[i]; CommandCost ret = DoCommand(v->tile, v->index | (service ? DEPOT_SERVICE : 0U) | DEPOT_DONT_CANCEL, 0, flags, GetCmdSendToDepot(vli.vtype)); if (ret.Succeeded()) { had_success = true; /* Return 0 if DC_EXEC is not set this is a valid goto depot command) * In this case we know that at least one vehicle can be sent to a depot * and we will issue the command. We can now safely quit the loop, knowing * it will succeed at least once. With DC_EXEC we really need to send them to the depot */ if (!(flags & DC_EXEC)) break; } } return had_success ? CommandCost() : CMD_ERROR; } /** * Send a vehicle to the depot. * @param tile unused * @param flags for command type * @param p1 bitmask * - p1 0-20: bitvehicle ID to send to the depot * - p1 bits 25-8 - DEPOT_ flags (see vehicle_type.h) * @param p2 packed VehicleListIdentifier. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSendVehicleToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (p1 & DEPOT_MASS_SEND) { /* Mass goto depot requested */ VehicleListIdentifier vli; if (!vli.Unpack(p2)) return CMD_ERROR; return SendAllVehiclesToDepot(flags, (p1 & DEPOT_SERVICE) != 0, vli); } Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); if (v == NULL) return CMD_ERROR; if (!v->IsPrimaryVehicle()) return CMD_ERROR; return v->SendToDepot(flags, (DepotCommand)(p1 & DEPOT_COMMAND_MASK)); } /** * Give a custom name to your vehicle * @param tile unused * @param flags type of operation * @param p1 vehicle ID to name * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_VEHICLE_NAME_CHARS) return CMD_ERROR; if (!(flags & DC_AUTOREPLACE) && !IsUniqueVehicleName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { free(v->name); v->name = reset ? NULL : stredup(text); InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 1); MarkWholeScreenDirty(); } return CommandCost(); } /** * Change the service interval of a vehicle * @param tile unused * @param flags type of operation * @param p1 vehicle ID that is being service-interval-changed * @param p2 bitmask * - p2 = (bit 0-15) - new service interval * - p2 = (bit 16) - service interval is custom flag * - p2 = (bit 17) - service interval is percentage flag * @param text unused * @return the cost of this operation or an error */ CommandCost CmdChangeServiceInt(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; const Company *company = Company::Get(v->owner); bool iscustom = HasBit(p2, 16); bool ispercent = iscustom ? HasBit(p2, 17) : company->settings.vehicle.servint_ispercent; uint16 serv_int; if (iscustom) { serv_int = GB(p2, 0, 16); if (serv_int != GetServiceIntervalClamped(serv_int, ispercent)) return CMD_ERROR; } else { serv_int = CompanyServiceInterval(company, v->type); } if (flags & DC_EXEC) { v->SetServiceInterval(serv_int); v->SetServiceIntervalIsCustom(iscustom); v->SetServiceIntervalIsPercent(ispercent); SetWindowDirty(WC_VEHICLE_DETAILS, v->index); } return CommandCost(); } openttd-1.5.3/src/widget_type.h0000644000000000000000000012235512627373441015200 0ustar rootroot/* $Id: widget_type.h 26971 2014-10-06 19:16:29Z rubidium $ */ /* * 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 widget_type.h Definitions about widgets. */ #ifndef WIDGET_TYPE_H #define WIDGET_TYPE_H #include "core/alloc_type.hpp" #include "core/bitmath_func.hpp" #include "core/math_func.hpp" #include "strings_type.h" #include "gfx_type.h" #include "window_type.h" static const int WIDGET_LIST_END = -1; ///< indicate the end of widgets' list for vararg functions /** Bits of the #WWT_MATRIX widget data. */ enum MatrixWidgetValues { /* Number of column bits of the WWT_MATRIX widget data. */ MAT_COL_START = 0, ///< Lowest bit of the number of columns. MAT_COL_BITS = 8, ///< Number of bits for the number of columns in the matrix. /* Number of row bits of the WWT_MATRIX widget data. */ MAT_ROW_START = 8, ///< Lowest bit of the number of rows. MAT_ROW_BITS = 8, ///< Number of bits for the number of rows in the matrix. }; /** Values for an arrow widget */ enum ArrowWidgetValues { AWV_DECREASE, ///< Arrow to the left or in case of RTL to the right AWV_INCREASE, ///< Arrow to the right or in case of RTL to the left AWV_LEFT, ///< Force the arrow to the left AWV_RIGHT, ///< Force the arrow to the right }; /** * Window widget types, nested widget types, and nested widget part types. */ enum WidgetType { /* Window widget types. */ WWT_EMPTY, ///< Empty widget, place holder to reserve space in widget array WWT_PANEL, ///< Simple depressed panel WWT_INSET, ///< Pressed (inset) panel, most commonly used as combo box _text_ area WWT_IMGBTN, ///< (Toggle) Button with image WWT_IMGBTN_2, ///< (Toggle) Button with diff image when clicked WWT_ARROWBTN, ///< (Toggle) Button with an arrow WWT_TEXTBTN, ///< (Toggle) Button with text WWT_TEXTBTN_2, ///< (Toggle) Button with diff text when clicked WWT_LABEL, ///< Centered label WWT_TEXT, ///< Pure simple text WWT_MATRIX, ///< Grid of rows and columns. @see MatrixWidgetValues WWT_FRAME, ///< Frame WWT_CAPTION, ///< Window caption (window title between closebox and stickybox) WWT_DEBUGBOX, ///< NewGRF debug box (at top-right of a window, between WWT_CAPTION and WWT_SHADEBOX) WWT_SHADEBOX, ///< Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX) WWT_DEFSIZEBOX, ///< Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX) WWT_STICKYBOX, ///< Sticky box (at top-right of a window, after WWT_DEFSIZEBOX) WWT_RESIZEBOX, ///< Resize box (normally at bottom-right of a window) WWT_CLOSEBOX, ///< Close box (at top-left of a window) WWT_DROPDOWN, ///< Drop down list WWT_EDITBOX, ///< a textbox for typing WWT_LAST, ///< Last Item. use WIDGETS_END to fill up padding!! /* Nested widget types. */ NWID_HORIZONTAL, ///< Horizontal container. NWID_HORIZONTAL_LTR, ///< Horizontal container that doesn't change the order of the widgets for RTL languages. NWID_VERTICAL, ///< Vertical container. NWID_MATRIX, ///< Matrix container. NWID_SPACER, ///< Invisible widget that takes some space. NWID_SELECTION, ///< Stacked widgets, only one visible at a time (eg in a panel with tabs). NWID_VIEWPORT, ///< Nested widget containing a viewport. NWID_BUTTON_DROPDOWN, ///< Button with a drop-down. NWID_HSCROLLBAR, ///< Horizontal scrollbar NWID_VSCROLLBAR, ///< Vertical scrollbar /* Nested widget part types. */ WPT_RESIZE, ///< Widget part for specifying resizing. WPT_MINSIZE, ///< Widget part for specifying minimal size. WPT_MINTEXTLINES, ///< Widget part for specifying minimal number of lines of text. WPT_FILL, ///< Widget part for specifying fill. WPT_DATATIP, ///< Widget part for specifying data and tooltip. WPT_PADDING, ///< Widget part for specifying a padding. WPT_PIPSPACE, ///< Widget part for specifying pre/inter/post space for containers. WPT_ENDCONTAINER, ///< Widget part to denote end of a container. WPT_FUNCTION, ///< Widget part for calling a user function. WPT_SCROLLBAR, ///< Widget part for attaching a scrollbar. /* Pushable window widget types. */ WWT_MASK = 0x7F, WWB_PUSHBUTTON = 1 << 7, WWT_PUSHBTN = WWT_PANEL | WWB_PUSHBUTTON, ///< Normal push-button (no toggle button) with custom drawing WWT_PUSHTXTBTN = WWT_TEXTBTN | WWB_PUSHBUTTON, ///< Normal push-button (no toggle button) with text caption WWT_PUSHIMGBTN = WWT_IMGBTN | WWB_PUSHBUTTON, ///< Normal push-button (no toggle button) with image caption WWT_PUSHARROWBTN = WWT_ARROWBTN | WWB_PUSHBUTTON, ///< Normal push-button (no toggle button) with arrow caption NWID_PUSHBUTTON_DROPDOWN = NWID_BUTTON_DROPDOWN | WWB_PUSHBUTTON, }; /** Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition() */ enum SizingType { ST_SMALLEST, ///< Initialize nested widget tree to smallest size. Also updates \e current_x and \e current_y. ST_RESIZE, ///< Resize the nested widget tree. }; /* Forward declarations. */ class NWidgetCore; class Scrollbar; /** * Baseclass for nested widgets. * @invariant After initialization, \f$current\_x = smallest\_x + n * resize\_x, for n \geq 0\f$. * @invariant After initialization, \f$current\_y = smallest\_y + m * resize\_y, for m \geq 0\f$. * @ingroup NestedWidgets */ class NWidgetBase : public ZeroedMemoryAllocator { public: NWidgetBase(WidgetType tp); virtual void SetupSmallestSize(Window *w, bool init_array) = 0; virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) = 0; virtual void FillNestedArray(NWidgetBase **array, uint length) = 0; virtual NWidgetCore *GetWidgetFromPos(int x, int y) = 0; virtual NWidgetBase *GetWidgetOfType(WidgetType tp); virtual bool IsHighlighted() const { return false; } virtual TextColour GetHighlightColour() const { return TC_INVALID; } virtual void SetHighlighted(TextColour highlight_colour) {} /** * Set additional space (padding) around the widget. * @param top Amount of additional space above the widget. * @param right Amount of additional space right of the widget. * @param bottom Amount of additional space below the widget. * @param left Amount of additional space left of the widget. */ inline void SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left) { this->padding_top = top; this->padding_right = right; this->padding_bottom = bottom; this->padding_left = left; } inline uint GetHorizontalStepSize(SizingType sizing) const; inline uint GetVerticalStepSize(SizingType sizing) const; virtual void Draw(const Window *w) = 0; virtual void SetDirty(const Window *w) const; WidgetType type; ///< Type of the widget / nested widget. uint fill_x; ///< Horizontal fill stepsize (from initial size, \c 0 means not resizable). uint fill_y; ///< Vertical fill stepsize (from initial size, \c 0 means not resizable). uint resize_x; ///< Horizontal resize step (\c 0 means not resizable). uint resize_y; ///< Vertical resize step (\c 0 means not resizable). /* Size of the widget in the smallest window possible. * Computed by #SetupSmallestSize() followed by #AssignSizePosition(). */ uint smallest_x; ///< Smallest horizontal size of the widget in a filled window. uint smallest_y; ///< Smallest vertical size of the widget in a filled window. /* Current widget size (that is, after resizing). */ uint current_x; ///< Current horizontal size (after resizing). uint current_y; ///< Current vertical size (after resizing). uint pos_x; ///< Horizontal position of top-left corner of the widget in the window. uint pos_y; ///< Vertical position of top-left corner of the widget in the window. NWidgetBase *next; ///< Pointer to next widget in container. Managed by parent container widget. NWidgetBase *prev; ///< Pointer to previous widget in container. Managed by parent container widget. uint8 padding_top; ///< Paddings added to the top of the widget. Managed by parent container widget. uint8 padding_right; ///< Paddings added to the right of the widget. Managed by parent container widget. (parent container may swap this with padding_left for RTL) uint8 padding_bottom; ///< Paddings added to the bottom of the widget. Managed by parent container widget. uint8 padding_left; ///< Paddings added to the left of the widget. Managed by parent container widget. (parent container may swap this with padding_right for RTL) protected: inline void StoreSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height); }; /** * Get the horizontal sizing step. * @param sizing Type of resize being performed. */ inline uint NWidgetBase::GetHorizontalStepSize(SizingType sizing) const { return (sizing == ST_RESIZE) ? this->resize_x : this->fill_x; } /** * Get the vertical sizing step. * @param sizing Type of resize being performed. */ inline uint NWidgetBase::GetVerticalStepSize(SizingType sizing) const { return (sizing == ST_RESIZE) ? this->resize_y : this->fill_y; } /** * Store size and position. * @param sizing Type of resizing to perform. * @param x Horizontal offset of the widget relative to the left edge of the window. * @param y Vertical offset of the widget relative to the top edge of the window. * @param given_width Width allocated to the widget. * @param given_height Height allocated to the widget. */ inline void NWidgetBase::StoreSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height) { this->pos_x = x; this->pos_y = y; if (sizing == ST_SMALLEST) { this->smallest_x = given_width; this->smallest_y = given_height; } this->current_x = given_width; this->current_y = given_height; } /** * Base class for a resizable nested widget. * @ingroup NestedWidgets */ class NWidgetResizeBase : public NWidgetBase { public: NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y); void SetMinimalSize(uint min_x, uint min_y); void SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size); void SetFill(uint fill_x, uint fill_y); void SetResize(uint resize_x, uint resize_y); void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); uint min_x; ///< Minimal horizontal size of only this widget. uint min_y; ///< Minimal vertical size of only this widget. }; /** Nested widget flags that affect display and interaction withe 'real' widgets. */ enum NWidgetDisplay { /* Generic. */ NDB_LOWERED = 0, ///< Widget is lowered (pressed down) bit. NDB_DISABLED = 1, ///< Widget is disabled (greyed out) bit. /* Viewport widget. */ NDB_NO_TRANSPARENCY = 2, ///< Viewport is never transparent. NDB_SHADE_GREY = 3, ///< Shade viewport to grey-scale. NDB_SHADE_DIMMED = 4, ///< Display dimmed colours in the viewport. /* Button dropdown widget. */ NDB_DROPDOWN_ACTIVE = 5, ///< Dropdown menu of the button dropdown widget is active. @see #NWID_BUTTON_DRPDOWN /* Scrollbar widget. */ NDB_SCROLLBAR_UP = 6, ///< Up-button is lowered bit. NDB_SCROLLBAR_DOWN = 7, ///< Down-button is lowered bit. /* Generic. */ NDB_HIGHLIGHT = 8, ///< Highlight of widget is on. ND_LOWERED = 1 << NDB_LOWERED, ///< Bit value of the lowered flag. ND_DISABLED = 1 << NDB_DISABLED, ///< Bit value of the disabled flag. ND_HIGHLIGHT = 1 << NDB_HIGHLIGHT, ///< Bit value of the highlight flag. ND_NO_TRANSPARENCY = 1 << NDB_NO_TRANSPARENCY, ///< Bit value of the 'no transparency' flag. ND_SHADE_GREY = 1 << NDB_SHADE_GREY, ///< Bit value of the 'shade to grey' flag. ND_SHADE_DIMMED = 1 << NDB_SHADE_DIMMED, ///< Bit value of the 'dimmed colours' flag. ND_DROPDOWN_ACTIVE = 1 << NDB_DROPDOWN_ACTIVE, ///< Bit value of the 'dropdown active' flag. ND_SCROLLBAR_UP = 1 << NDB_SCROLLBAR_UP, ///< Bit value of the 'scrollbar up' flag. ND_SCROLLBAR_DOWN = 1 << NDB_SCROLLBAR_DOWN, ///< Bit value of the 'scrollbar down' flag. ND_SCROLLBAR_BTN = ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN, ///< Bit value of the 'scrollbar up' or 'scrollbar down' flag. }; DECLARE_ENUM_AS_BIT_SET(NWidgetDisplay) /** * Base class for a 'real' widget. * @ingroup NestedWidgets */ class NWidgetCore : public NWidgetResizeBase { public: NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y, uint32 widget_data, StringID tool_tip); void SetIndex(int index); void SetDataTip(uint32 widget_data, StringID tool_tip); inline void SetLowered(bool lowered); inline bool IsLowered() const; inline void SetDisabled(bool disabled); inline bool IsDisabled() const; /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); /* virtual */ bool IsHighlighted() const; /* virtual */ TextColour GetHighlightColour() const; /* virtual */ void SetHighlighted(TextColour highlight_colour); NWidgetDisplay disp_flags; ///< Flags that affect display and interaction with the widget. Colours colour; ///< Colour of this widget. int index; ///< Index of the nested widget in the widget array of the window (\c -1 means 'not used'). uint32 widget_data; ///< Data of the widget. @see Widget::data StringID tool_tip; ///< Tooltip of the widget. @see Widget::tootips int scrollbar_index; ///< Index of an attached scrollbar. TextColour highlight_colour; ///< Colour of highlight. }; /** * Highlight the widget or not. * @param highlight_colour Widget must be highlighted (blink). */ inline void NWidgetCore::SetHighlighted(TextColour highlight_colour) { this->disp_flags = highlight_colour != TC_INVALID ? SETBITS(this->disp_flags, ND_HIGHLIGHT) : CLRBITS(this->disp_flags, ND_HIGHLIGHT); this->highlight_colour = highlight_colour; } /** Return whether the widget is highlighted. */ inline bool NWidgetCore::IsHighlighted() const { return HasBit(this->disp_flags, NDB_HIGHLIGHT); } /** Return the colour of the highlight. */ inline TextColour NWidgetCore::GetHighlightColour() const { return this->highlight_colour; } /** * Lower or raise the widget. * @param lowered Widget must be lowered (drawn pressed down). */ inline void NWidgetCore::SetLowered(bool lowered) { this->disp_flags = lowered ? SETBITS(this->disp_flags, ND_LOWERED) : CLRBITS(this->disp_flags, ND_LOWERED); } /** Return whether the widget is lowered. */ inline bool NWidgetCore::IsLowered() const { return HasBit(this->disp_flags, NDB_LOWERED); } /** * Disable (grey-out) or enable the widget. * @param disabled Widget must be disabled. */ inline void NWidgetCore::SetDisabled(bool disabled) { this->disp_flags = disabled ? SETBITS(this->disp_flags, ND_DISABLED) : CLRBITS(this->disp_flags, ND_DISABLED); } /** Return whether the widget is disabled. */ inline bool NWidgetCore::IsDisabled() const { return HasBit(this->disp_flags, NDB_DISABLED); } /** * Baseclass for container widgets. * @ingroup NestedWidgets */ class NWidgetContainer : public NWidgetBase { public: NWidgetContainer(WidgetType tp); ~NWidgetContainer(); void Add(NWidgetBase *wid); /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); /** Return whether the container is empty. */ inline bool IsEmpty() { return head == NULL; } /* virtual */ NWidgetBase *GetWidgetOfType(WidgetType tp); protected: NWidgetBase *head; ///< Pointer to first widget in container. NWidgetBase *tail; ///< Pointer to last widget in container. }; /** Display planes with zero size for #NWidgetStacked. */ enum StackedZeroSizePlanes { SZSP_VERTICAL = INT_MAX / 2, ///< Display plane with zero size horizontally, and filling and resizing vertically. SZSP_HORIZONTAL, ///< Display plane with zero size vertically, and filling and resizing horizontally. SZSP_NONE, ///< Display plane with zero size in both directions (none filling and resizing). SZSP_BEGIN = SZSP_VERTICAL, ///< First zero-size plane. }; /** * Stacked widgets, widgets all occupying the same space in the window. * #NWID_SELECTION allows for selecting one of several panels (planes) to tbe displayed. All planes must have the same size. * Since all planes are also initialized, switching between different planes can be done while the window is displayed. * * There are also a number of special planes (defined in #StackedZeroSizePlanes) that have zero size in one direction (and are stretchable in * the other direction) or have zero size in both directions. They are used to make all child planes of the widget disappear. * Unlike switching between the regular display planes (that all have the same size), switching from or to one of the zero-sized planes means that * a #Windows::ReInit() is needed to re-initialize the window since its size changes. */ class NWidgetStacked : public NWidgetContainer { public: NWidgetStacked(); void SetIndex(int index); void SetupSmallestSize(Window *w, bool init_array); void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); /* virtual */ void Draw(const Window *w); /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); void SetDisplayedPlane(int plane); int shown_plane; ///< Plane being displayed (for #NWID_SELECTION only). int index; ///< If non-negative, index in the #Window::nested_array. }; /** Nested widget container flags, */ enum NWidContainerFlags { NCB_EQUALSIZE = 0, ///< Containers should keep all their (resizing) children equally large. NC_NONE = 0, ///< All flags cleared. NC_EQUALSIZE = 1 << NCB_EQUALSIZE, ///< Value of the #NCB_EQUALSIZE flag. }; DECLARE_ENUM_AS_BIT_SET(NWidContainerFlags) /** Container with pre/inter/post child space. */ class NWidgetPIPContainer : public NWidgetContainer { public: NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags = NC_NONE); void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); /* virtual */ void Draw(const Window *w); /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); protected: NWidContainerFlags flags; ///< Flags of the container. uint8 pip_pre; ///< Amount of space before first widget. uint8 pip_inter; ///< Amount of space between widgets. uint8 pip_post; ///< Amount of space after last widget. }; /** * Horizontal container. * @ingroup NestedWidgets */ class NWidgetHorizontal : public NWidgetPIPContainer { public: NWidgetHorizontal(NWidContainerFlags flags = NC_NONE); void SetupSmallestSize(Window *w, bool init_array); void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); }; /** * Horizontal container that doesn't change the direction of the widgets for RTL languages. * @ingroup NestedWidgets */ class NWidgetHorizontalLTR : public NWidgetHorizontal { public: NWidgetHorizontalLTR(NWidContainerFlags flags = NC_NONE); void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); }; /** * Vertical container. * @ingroup NestedWidgets */ class NWidgetVertical : public NWidgetPIPContainer { public: NWidgetVertical(NWidContainerFlags flags = NC_NONE); void SetupSmallestSize(Window *w, bool init_array); void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); }; /** * Matrix container with implicitly equal sized (virtual) sub-widgets. * This widget must have exactly one sub-widget. After that this sub-widget * is used to draw all of the data within the matrix piece by piece. * DrawWidget and OnClick calls will be done to that sub-widget, where the * 16 high bits are used to encode the index into the matrix. * @ingroup NestedWidgets */ class NWidgetMatrix : public NWidgetPIPContainer { public: NWidgetMatrix(); void SetIndex(int index); void SetColour(Colours colour); void SetClicked(int clicked); void SetCount(int count); void SetScrollbar(Scrollbar *sb); void SetupSmallestSize(Window *w, bool init_array); void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); /* virtual */ void Draw(const Window *w); protected: int index; ///< If non-negative, index in the #Window::nested_array. Colours colour; ///< Colour of this widget. int clicked; ///< The currently clicked widget. int count; ///< Amount of valid widgets. Scrollbar *sb; ///< The scrollbar we're associated with. private: int widget_w; ///< The width of the child widget including inter spacing. int widget_h; ///< The height of the child widget including inter spacing. int widgets_x; ///< The number of visible widgets in horizontal direction. int widgets_y; ///< The number of visible widgets in vertical direction. void GetScrollOffsets(int &start_x, int &start_y, int &base_offs_x, int &base_offs_y); }; /** * Spacer widget. * @ingroup NestedWidgets */ class NWidgetSpacer : public NWidgetResizeBase { public: NWidgetSpacer(int length, int height); void SetupSmallestSize(Window *w, bool init_array); /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); /* virtual */ void Draw(const Window *w); /* virtual */ void SetDirty(const Window *w) const; /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); }; /** * Nested widget with a child. * @ingroup NestedWidgets */ class NWidgetBackground : public NWidgetCore { public: NWidgetBackground(WidgetType tp, Colours colour, int index, NWidgetPIPContainer *child = NULL); ~NWidgetBackground(); void Add(NWidgetBase *nwid); void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); void SetupSmallestSize(Window *w, bool init_array); void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); /* virtual */ void FillNestedArray(NWidgetBase **array, uint length); /* virtual */ void Draw(const Window *w); /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y); /* virtual */ NWidgetBase *GetWidgetOfType(WidgetType tp); private: NWidgetPIPContainer *child; ///< Child widget. }; /** * Nested widget to display a viewport in a window. * After initializing the nested widget tree, call #InitializeViewport(). After changing the window size, * call #UpdateViewportCoordinates() eg from Window::OnResize(). * If the #display_flags field contains the #ND_NO_TRANSPARENCY bit, the viewport will disable transparency. * Shading to grey-scale is controlled with the #ND_SHADE_GREY bit (used for B&W news papers), the #ND_SHADE_DIMMED gives dimmed colours (for colour news papers). * @todo Class derives from #NWidgetCore, but does not use #colour, #widget_data, or #tool_tip. * @ingroup NestedWidgets */ class NWidgetViewport : public NWidgetCore { public: NWidgetViewport(int index); /* virtual */ void SetupSmallestSize(Window *w, bool init_array); /* virtual */ void Draw(const Window *w); void InitializeViewport(Window *w, uint32 follow_flags, ZoomLevel zoom); void UpdateViewportCoordinates(Window *w); }; /** * Scrollbar data structure */ class Scrollbar { private: const bool is_vertical; ///< Scrollbar has vertical orientation. uint16 count; ///< Number of elements in the list. uint16 cap; ///< Number of visible elements of the scroll bar. uint16 pos; ///< Index of first visible item of the list. uint16 stepsize; ///< Distance to scroll, when pressing the buttons or using the wheel. public: /** Stepping sizes when scrolling */ enum ScrollbarStepping { SS_RAW, ///< Step in single units. SS_SMALL, ///< Step in #stepsize units. SS_BIG, ///< Step in #cap units. }; Scrollbar(bool is_vertical) : is_vertical(is_vertical), stepsize(1) { } /** * Gets the number of elements in the list * @return the number of elements */ inline uint16 GetCount() const { return this->count; } /** * Gets the number of visible elements of the scrollbar * @return the number of visible elements */ inline uint16 GetCapacity() const { return this->cap; } /** * Gets the position of the first visible element in the list * @return the position of the element */ inline uint16 GetPosition() const { return this->pos; } /** * Checks whether given current item is visible in the list * @param item to check * @return true iff the item is visible */ inline bool IsVisible(uint16 item) const { return IsInsideBS(item, this->GetPosition(), this->GetCapacity()); } /** * Is the scrollbar vertical or not? * @return True iff the scrollbar is vertical. */ inline bool IsVertical() const { return this->is_vertical; } /** * Set the distance to scroll when using the buttons or the wheel. * @param stepsize Scrolling speed. */ void SetStepSize(uint16 stepsize) { assert(stepsize > 0); this->stepsize = stepsize; } /** * Sets the number of elements in the list * @param num the number of elements in the list * @note updates the position if needed */ void SetCount(int num) { assert(num >= 0); assert(num <= MAX_UVALUE(uint16)); this->count = num; num -= this->cap; if (num < 0) num = 0; if (num < this->pos) this->pos = num; } /** * Set the capacity of visible elements. * @param capacity the new capacity * @note updates the position if needed */ void SetCapacity(int capacity) { assert(capacity > 0); assert(capacity <= MAX_UVALUE(uint16)); this->cap = capacity; if (this->cap + this->pos > this->count) this->pos = max(0, this->count - this->cap); } void SetCapacityFromWidget(Window *w, int widget, int padding = 0); /** * Sets the position of the first visible element * @param position the position of the element */ void SetPosition(int position) { assert(position >= 0); assert(this->count <= this->cap ? (position == 0) : (position + this->cap <= this->count)); this->pos = position; } /** * Updates the position of the first visible element by the given amount. * If the position would be too low or high it will be clamped appropriately * @param difference the amount of change requested * @param unit The stepping unit of \a difference */ void UpdatePosition(int difference, ScrollbarStepping unit = SS_SMALL) { if (difference == 0) return; switch (unit) { case SS_SMALL: difference *= this->stepsize; break; case SS_BIG: difference *= this->cap; break; default: break; } this->SetPosition(Clamp(this->pos + difference, 0, max(this->count - this->cap, 0))); } /** * Scroll towards the given position; if the item is visible nothing * happens, otherwise it will be shown either at the bottom or top of * the window depending on where in the list it was. * @param position the position to scroll towards. */ void ScrollTowards(int position) { if (position < this->GetPosition()) { /* scroll up to the item */ this->SetPosition(position); } else if (position >= this->GetPosition() + this->GetCapacity()) { /* scroll down so that the item is at the bottom */ this->SetPosition(position - this->GetCapacity() + 1); } } int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const; }; /** * Nested widget to display and control a scrollbar in a window. * Also assign the scrollbar to other widgets using #SetScrollbar() to make the mousewheel work. * @ingroup NestedWidgets */ class NWidgetScrollbar : public NWidgetCore, public Scrollbar { public: NWidgetScrollbar(WidgetType tp, Colours colour, int index); /* virtual */ void SetupSmallestSize(Window *w, bool init_array); /* virtual */ void Draw(const Window *w); static void InvalidateDimensionCache(); static Dimension GetVerticalDimension(); static Dimension GetHorizontalDimension(); private: static Dimension vertical_dimension; ///< Cached size of vertical scrollbar button. static Dimension horizontal_dimension; ///< Cached size of horizontal scrollbar button. }; /** * Leaf widget. * @ingroup NestedWidgets */ class NWidgetLeaf : public NWidgetCore { public: NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, StringID tip); /* virtual */ void SetupSmallestSize(Window *w, bool init_array); /* virtual */ void Draw(const Window *w); bool ButtonHit(const Point &pt); static void InvalidateDimensionCache(); static Dimension dropdown_dimension; ///< Cached size of a dropdown widget. private: static Dimension shadebox_dimension; ///< Cached size of a shadebox widget. static Dimension debugbox_dimension; ///< Cached size of a debugbox widget. static Dimension defsizebox_dimension; ///< Cached size of a defsizebox widget. static Dimension stickybox_dimension; ///< Cached size of a stickybox widget. static Dimension resizebox_dimension; ///< Cached size of a resizebox widget. static Dimension closebox_dimension; ///< Cached size of a closebox widget. }; /** * Return the biggest possible size of a nested widget. * @param base Base size of the widget. * @param max_space Available space for the widget. * @param step Stepsize of the widget. * @return Biggest possible size of the widget, assuming that \a base may only be incremented by \a step size steps. */ static inline uint ComputeMaxSize(uint base, uint max_space, uint step) { if (base >= max_space || step == 0) return base; if (step == 1) return max_space; uint increment = max_space - base; increment -= increment % step; return base + increment; } /** * @defgroup NestedWidgetParts Hierarchical widget parts * To make nested widgets easier to enter, nested widget parts have been created. They allow the tree to be defined in a flat array of parts. * * - Leaf widgets start with a #NWidget(WidgetType tp, Colours col, int16 idx) part. * Next, specify its properties with one or more of * - #SetMinimalSize Define the minimal size of the widget. * - #SetFill Define how the widget may grow to make it nicely. * - #SetDataTip Define the data and the tooltip of the widget. * - #SetResize Define how the widget may resize. * - #SetPadding Create additional space around the widget. * * - To insert a nested widget tree from an external source, nested widget part #NWidgetFunction exists. * For further customization, the #SetPadding part may be used. * * - Space widgets (#NWidgetSpacer) start with a #NWidget(WidgetType tp), followed by one or more of * - #SetMinimalSize Define the minimal size of the widget. * - #SetFill Define how the widget may grow to make it nicely. * - #SetResize Define how the widget may resize. * - #SetPadding Create additional space around the widget. * * - Container widgets #NWidgetHorizontal, #NWidgetHorizontalLTR, #NWidgetVertical, and #NWidgetMatrix, start with a #NWidget(WidgetType tp) part. * Their properties are derived from the child widgets so they cannot be specified. * You can however use * - #SetPadding Define additional padding around the container. * - #SetPIP Set additional pre/inter/post child widget space. * . * Underneath these properties, all child widgets of the container must be defined. To denote that they are childs, add an indent before the nested widget parts of * the child widgets (it has no meaning for the compiler but it makes the widget parts easier to read). * Below the last child widget, use an #EndContainer part. This part should be aligned with the #NWidget part that started the container. * * - Stacked widgets #NWidgetStacked map each of their children onto the same space. It behaves like a container, except there is no pre/inter/post space, * so the widget does not support #SetPIP. #SetPadding is allowed though. * Like the other container widgets, below the last child widgets, a #EndContainer part should be used to denote the end of the stacked widget. * * - Background widgets #NWidgetBackground start with a #NWidget(WidgetType tp, Colours col, int16 idx) part. * What follows depends on how the widget is used. * - If the widget is used as a leaf widget, that is, to create some space in the window to display a viewport or some text, use the properties of the * leaf widgets to define how it behaves. * - If the widget is used a background behind other widgets, it is considered to be a container widgets. Use the properties listed there to define its * behaviour. * . * In both cases, the background widget \b MUST end with a #EndContainer widget part. * * @see NestedWidgets */ /** * Widget part for storing data and tooltip information. * @ingroup NestedWidgetParts */ struct NWidgetPartDataTip { uint32 data; ///< Data value of the widget. StringID tooltip; ///< Tooltip of the widget. }; /** * Widget part for storing basic widget information. * @ingroup NestedWidgetParts */ struct NWidgetPartWidget { Colours colour; ///< Widget colour. int16 index; ///< Widget index in the widget array. }; /** * Widget part for storing padding. * @ingroup NestedWidgetParts */ struct NWidgetPartPaddings { uint8 top, right, bottom, left; ///< Paddings for all directions. }; /** * Widget part for storing pre/inter/post spaces. * @ingroup NestedWidgetParts */ struct NWidgetPartPIP { uint8 pre, inter, post; ///< Amount of space before/between/after child widgets. }; /** * Widget part for storing minimal text line data. * @ingroup NestedWidgetParts */ struct NWidgetPartTextLines { uint8 lines; ///< Number of text lines. uint8 spacing; ///< Extra spacing around lines. FontSize size; ///< Font size of text lines. }; /** * Pointer to function returning a nested widget. * @param biggest_index Pointer to storage for collecting the biggest index used in the nested widget. * @return Nested widget (tree). * @post \c *biggest_index must contain the value of the biggest index in the returned tree. */ typedef NWidgetBase *NWidgetFunctionType(int *biggest_index); /** * Partial widget specification to allow NWidgets to be written nested. * @ingroup NestedWidgetParts */ struct NWidgetPart { WidgetType type; ///< Type of the part. @see NWidgetPartType. union { Point xy; ///< Part with an x/y size. NWidgetPartDataTip data_tip; ///< Part with a data/tooltip. NWidgetPartWidget widget; ///< Part with a start of a widget. NWidgetPartPaddings padding; ///< Part with paddings. NWidgetPartPIP pip; ///< Part with pre/inter/post spaces. NWidgetPartTextLines text_lines; ///< Part with text line data. NWidgetFunctionType *func_ptr; ///< Part with a function call. NWidContainerFlags cont_flags; ///< Part with container flags. } u; }; /** * Widget part function for setting the resize step. * @param dx Horizontal resize step. 0 means no horizontal resizing. * @param dy Vertical resize step. 0 means no vertical resizing. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetResize(int16 dx, int16 dy) { NWidgetPart part; part.type = WPT_RESIZE; part.u.xy.x = dx; part.u.xy.y = dy; return part; } /** * Widget part function for setting the minimal size. * @param x Horizontal minimal size. * @param y Vertical minimal size. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetMinimalSize(int16 x, int16 y) { NWidgetPart part; part.type = WPT_MINSIZE; part.u.xy.x = x; part.u.xy.y = y; return part; } /** * Widget part function for setting the minimal text lines. * @param lines Number of text lines. * @param spacing Extra spacing required. * @param size Font size of text. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetMinimalTextLines(uint8 lines, uint8 spacing, FontSize size = FS_NORMAL) { NWidgetPart part; part.type = WPT_MINTEXTLINES; part.u.text_lines.lines = lines; part.u.text_lines.spacing = spacing; part.u.text_lines.size = size; return part; } /** * Widget part function for setting filling. * @param fill_x Horizontal filling step from minimal size. * @param fill_y Vertical filling step from minimal size. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetFill(uint fill_x, uint fill_y) { NWidgetPart part; part.type = WPT_FILL; part.u.xy.x = fill_x; part.u.xy.y = fill_y; return part; } /** * Widget part function for denoting the end of a container * (horizontal, vertical, WWT_FRAME, WWT_INSET, or WWT_PANEL). * @ingroup NestedWidgetParts */ static inline NWidgetPart EndContainer() { NWidgetPart part; part.type = WPT_ENDCONTAINER; return part; } /** * Widget part function for setting the data and tooltip. * @param data Data of the widget. * @param tip Tooltip of the widget. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetDataTip(uint32 data, StringID tip) { NWidgetPart part; part.type = WPT_DATATIP; part.u.data_tip.data = data; part.u.data_tip.tooltip = tip; return part; } /** * Widget part function for setting the data and tooltip of WWT_MATRIX widgets * @param cols Number of columns. \c 0 means to use draw columns with width according to the resize step size. * @param rows Number of rows. \c 0 means to use draw rows with height according to the resize step size. * @param tip Tooltip of the widget. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetMatrixDataTip(uint8 cols, uint8 rows, StringID tip) { return SetDataTip((rows << MAT_ROW_START) | (cols << MAT_COL_START), tip); } /** * Widget part function for setting additional space around a widget. * Parameters start above the widget, and are specified in clock-wise direction. * @param top The padding above the widget. * @param right The padding right of the widget. * @param bottom The padding below the widget. * @param left The padding left of the widget. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left) { NWidgetPart part; part.type = WPT_PADDING; part.u.padding.top = top; part.u.padding.right = right; part.u.padding.bottom = bottom; part.u.padding.left = left; return part; } /** * Widget part function for setting a padding. * @param padding The padding to use for all directions. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetPadding(uint8 padding) { return SetPadding(padding, padding, padding, padding); } /** * Widget part function for setting a pre/inter/post spaces. * @param pre The amount of space before the first widget. * @param inter The amount of space between widgets. * @param post The amount of space after the last widget. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetPIP(uint8 pre, uint8 inter, uint8 post) { NWidgetPart part; part.type = WPT_PIPSPACE; part.u.pip.pre = pre; part.u.pip.inter = inter; part.u.pip.post = post; return part; } /** * Attach a scrollbar to a widget. * The scrollbar is controlled when using the mousewheel on the widget. * Multiple widgets can refer to the same scrollbar to make the mousewheel work in all of them. * @param index Widget index of the scrollbar. * @ingroup NestedWidgetParts */ static inline NWidgetPart SetScrollbar(int index) { NWidgetPart part; part.type = WPT_SCROLLBAR; part.u.widget.index = index; return part; } /** * Widget part function for starting a new 'real' widget. * @param tp Type of the new nested widget. * @param col Colour of the new widget. * @param idx Index of the widget in the widget array. * @note with #WWT_PANEL, #WWT_FRAME, #WWT_INSET, a new container is started. * Child widgets must have a index bigger than the parent index. * @ingroup NestedWidgetParts */ static inline NWidgetPart NWidget(WidgetType tp, Colours col, int16 idx = -1) { NWidgetPart part; part.type = tp; part.u.widget.colour = col; part.u.widget.index = idx; return part; } /** * Widget part function for starting a new horizontal container, vertical container, or spacer widget. * @param tp Type of the new nested widget, #NWID_HORIZONTAL(_LTR), #NWID_VERTICAL, #NWID_SPACER, #NWID_SELECTION, and #NWID_MATRIX. * @param cont_flags Flags for the containers (#NWID_HORIZONTAL(_LTR) and #NWID_VERTICAL). * @ingroup NestedWidgetParts */ static inline NWidgetPart NWidget(WidgetType tp, NWidContainerFlags cont_flags = NC_NONE) { NWidgetPart part; part.type = tp; part.u.cont_flags = cont_flags; return part; } /** * Obtain a nested widget (sub)tree from an external source. * @param func_ptr Pointer to function that returns the tree. * @ingroup NestedWidgetParts */ static inline NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr) { NWidgetPart part; part.type = WPT_FUNCTION; part.u.func_ptr = func_ptr; return part; } NWidgetContainer *MakeNWidgets(const NWidgetPart *parts, int count, int *biggest_index, NWidgetContainer *container); NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *parts, int count, int *biggest_index, NWidgetStacked **shade_select); NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, int max_length, StringID button_tooltip); #endif /* WIDGET_TYPE_H */ openttd-1.5.3/src/newgrf_debug_gui.cpp0000644000000000000000000011203012627373442016477 0ustar rootroot/* $Id: newgrf_debug_gui.cpp 27174 2015-03-01 08:17:14Z alberth $ */ /* * 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 newgrf_debug_gui.cpp GUIs for debugging NewGRFs. */ #include "stdafx.h" #include #include "window_gui.h" #include "window_func.h" #include "fileio_func.h" #include "spritecache.h" #include "string_func.h" #include "strings_func.h" #include "textbuf_gui.h" #include "vehicle_gui.h" #include "zoom_func.h" #include "engine_base.h" #include "industry.h" #include "object_base.h" #include "station_base.h" #include "town.h" #include "vehicle_base.h" #include "train.h" #include "roadveh.h" #include "newgrf_airporttiles.h" #include "newgrf_debug.h" #include "newgrf_object.h" #include "newgrf_spritegroup.h" #include "newgrf_station.h" #include "newgrf_town.h" #include "newgrf_railtype.h" #include "newgrf_industries.h" #include "newgrf_industrytiles.h" #include "widgets/newgrf_debug_widget.h" #include "table/strings.h" #include "safeguards.h" /** The sprite picker. */ NewGrfDebugSpritePicker _newgrf_debug_sprite_picker = { SPM_NONE, NULL, 0, SmallVector() }; /** * Get the feature index related to the window number. * @param window_number The window to get the feature index from. * @return the feature index */ static inline uint GetFeatureIndex(uint window_number) { return GB(window_number, 0, 24); } /** * Get the window number for the inspect window given a * feature and index. * @param feature The feature we want to inspect. * @param index The index/identifier of the feature to inspect. * @return the InspectWindow (Window)Number */ static inline uint GetInspectWindowNumber(GrfSpecFeature feature, uint index) { assert((index >> 24) == 0); return (feature << 24) | index; } /** * The type of a property to show. This is used to * provide an appropriate representation in the GUI. */ enum NIType { NIT_INT, ///< The property is a simple integer NIT_CARGO, ///< The property is a cargo }; /** Representation of the data from a NewGRF property. */ struct NIProperty { const char *name; ///< A (human readable) name for the property ptrdiff_t offset; ///< Offset of the variable in the class byte read_size; ///< Number of bytes (i.e. byte, word, dword etc) byte prop; ///< The number of the property byte type; }; /** * Representation of the available callbacks with * information on when they actually apply. */ struct NICallback { const char *name; ///< The human readable name of the callback ptrdiff_t offset; ///< Offset of the variable in the class byte read_size; ///< The number of bytes (i.e. byte, word, dword etc) to read byte cb_bit; ///< The bit that needs to be set for this callback to be enabled uint16 cb_id; ///< The number of the callback }; /** Mask to show no bit needs to be enabled for the callback. */ static const int CBM_NO_BIT = UINT8_MAX; /** Representation on the NewGRF variables. */ struct NIVariable { const char *name; byte var; }; /** Helper class to wrap some functionality/queries in. */ class NIHelper { public: /** Silence a warning. */ virtual ~NIHelper() {} /** * Is the item with the given index inspectable? * @param index the index to check. * @return true iff the index is inspectable. */ virtual bool IsInspectable(uint index) const = 0; /** * Get the parent "window_number" of a given instance. * @param index the instance to get the parent for. * @return the parent's window_number or UINT32_MAX if there is none. */ virtual uint GetParent(uint index) const = 0; /** * Get the instance given an index. * @param index the index to get the instance for. * @return the instance. */ virtual const void *GetInstance(uint index) const = 0; /** * Get (NewGRF) specs given an index. * @param index the index to get the specs for for. * @return the specs. */ virtual const void *GetSpec(uint index) const = 0; /** * Set the string parameters to write the right data for a STRINGn. * @param index the index to get the string parameters for. */ virtual void SetStringParameters(uint index) const = 0; /** * Get the GRFID of the file that includes this item. * @param index index to check. * @return GRFID of the item. 0 means that the item is not inspectable. */ virtual uint32 GetGRFID(uint index) const = 0; /** * Resolve (action2) variable for a given index. * @param index The (instance) index to resolve the variable for. * @param var The variable to actually resolve. * @param param The varaction2 0x60+x parameter to pass. * @param avail Return whether the variable is available. * @return The resolved variable's value. */ virtual uint Resolve(uint index, uint var, uint param, bool *avail) const = 0; /** * Used to decide if the PSA needs a parameter or not. * @return True iff this item has a PSA that requires a parameter. */ virtual bool PSAWithParameter() const { return false; } /** * Allows to know the size of the persistent storage. * @param index Index of the item. * @param grfid Parameter for the PSA. Only required for items with parameters. * @return Size of the persistent storage in indices. */ virtual uint GetPSASize(uint index, uint32 grfid) const { return 0; } /** * Gets the first position of the array containing the persistent storage. * @param index Index of the item. * @param grfid Parameter for the PSA. Only required for items with parameters. * @return Pointer to the first position of the storage array or NULL if not present. */ virtual const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const { return NULL; } protected: /** * Helper to make setting the strings easier. * @param string the string to actually draw. * @param index the (instance) index for the string. */ void SetSimpleStringParameters(StringID string, uint32 index) const { SetDParam(0, string); SetDParam(1, index); } /** * Helper to make setting the strings easier for objects at a specific tile. * @param string the string to draw the object's name * @param index the (instance) index for the string. * @param tile the tile the object is at */ void SetObjectAtStringParameters(StringID string, uint32 index, TileIndex tile) const { SetDParam(0, STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT); SetDParam(1, string); SetDParam(2, index); SetDParam(3, tile); } }; /** Container for all information for a given feature. */ struct NIFeature { const NIProperty *properties; ///< The properties associated with this feature. const NICallback *callbacks; ///< The callbacks associated with this feature. const NIVariable *variables; ///< The variables associated with this feature. const NIHelper *helper; ///< The class container all helper functions. }; /* Load all the NewGRF debug data; externalised as it is just a huge bunch of tables. */ #include "table/newgrf_debug_data.h" /** * Get the feature number related to the window number. * @param window_number The window to get the feature number for. * @return The feature number. */ static inline GrfSpecFeature GetFeatureNum(uint window_number) { return (GrfSpecFeature)GB(window_number, 24, 8); } /** * Get the NIFeature related to the window number. * @param window_number The window to get the NIFeature for. * @return the NIFeature, or NULL is there isn't one. */ static inline const NIFeature *GetFeature(uint window_number) { GrfSpecFeature idx = GetFeatureNum(window_number); return idx < GSF_FAKE_END ? _nifeatures[idx] : NULL; } /** * Get the NIHelper related to the window number. * @param window_number The window to get the NIHelper for. * @pre GetFeature(window_number) != NULL * @return the NIHelper */ static inline const NIHelper *GetFeatureHelper(uint window_number) { return GetFeature(window_number)->helper; } /** Window used for inspecting NewGRFs. */ struct NewGRFInspectWindow : Window { static const int LEFT_OFFSET = 5; ///< Position of left edge static const int RIGHT_OFFSET = 5; ///< Position of right edge static const int TOP_OFFSET = 5; ///< Position of top edge static const int BOTTOM_OFFSET = 5; ///< Position of bottom edge /** The value for the variable 60 parameters. */ static uint32 var60params[GSF_FAKE_END][0x20]; /** GRFID of the caller of this window, 0 if it has no caller. */ uint32 caller_grfid; /** For ground vehicles: Index in vehicle chain. */ uint chain_index; /** The currently edited parameter, to update the right one. */ byte current_edit_param; Scrollbar *vscroll; /** * Check whether the given variable has a parameter. * @param variable the variable to check. * @return true iff the variable has a parameter. */ static bool HasVariableParameter(uint variable) { return IsInsideBS(variable, 0x60, 0x20); } /** * Set the GRFID of the item opening this window. * @param grfid GRFID of the item opening this window, or 0 if not opened by other window. */ void SetCallerGRFID(uint32 grfid) { this->caller_grfid = grfid; this->SetDirty(); } /** * Check whether this feature has chain index, i.e. refers to ground vehicles. */ bool HasChainIndex() const { GrfSpecFeature f = GetFeatureNum(this->window_number); return f == GSF_TRAINS || f == GSF_ROADVEHICLES; } /** * Get the feature index. * @return the feature index */ uint GetFeatureIndex() const { uint index = ::GetFeatureIndex(this->window_number); if (this->chain_index > 0) { assert(this->HasChainIndex()); const Vehicle *v = Vehicle::Get(index); v = v->Move(this->chain_index); if (v != NULL) index = v->index; } return index; } /** * Ensure that this->chain_index is in range. */ void ValidateChainIndex() { if (this->chain_index == 0) return; assert(this->HasChainIndex()); const Vehicle *v = Vehicle::Get(::GetFeatureIndex(this->window_number)); v = v->Move(this->chain_index); if (v == NULL) this->chain_index = 0; } NewGRFInspectWindow(WindowDesc *desc, WindowNumber wno) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NGRFI_SCROLLBAR); this->FinishInitNested(wno); this->vscroll->SetCount(0); this->SetWidgetDisabledState(WID_NGRFI_PARENT, GetFeatureHelper(this->window_number)->GetParent(this->GetFeatureIndex()) == UINT32_MAX); this->OnInvalidateData(0, true); } virtual void SetStringParameters(int widget) const { if (widget != WID_NGRFI_CAPTION) return; GetFeatureHelper(this->window_number)->SetStringParameters(this->GetFeatureIndex()); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_NGRFI_VEH_CHAIN: { assert(this->HasChainIndex()); GrfSpecFeature f = GetFeatureNum(this->window_number); size->height = max(size->height, GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height + 2 + WD_BEVEL_TOP + WD_BEVEL_BOTTOM); break; } case WID_NGRFI_MAINPANEL: resize->height = max(11, FONT_HEIGHT_NORMAL + 1); resize->width = 1; size->height = 5 * resize->height + TOP_OFFSET + BOTTOM_OFFSET; break; } } /** * Helper function to draw a string (line) in the window. * @param r The (screen) rectangle we must draw within * @param offset The offset (in lines) we want to draw for * @param format The format string */ void WARN_FORMAT(4, 5) DrawString(const Rect &r, int offset, const char *format, ...) const { char buf[1024]; va_list va; va_start(va, format); vseprintf(buf, lastof(buf), format, va); va_end(va); offset -= this->vscroll->GetPosition(); if (offset < 0 || offset >= this->vscroll->GetCapacity()) return; ::DrawString(r.left + LEFT_OFFSET, r.right - RIGHT_OFFSET, r.top + TOP_OFFSET + (offset * this->resize.step_height), buf, TC_BLACK); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_NGRFI_VEH_CHAIN: { const Vehicle *v = Vehicle::Get(this->GetFeatureIndex()); int total_width = 0; int sel_start = 0; int sel_end = 0; for (const Vehicle *u = v->First(); u != NULL; u = u->Next()) { if (u == v) sel_start = total_width; switch (u->type) { case VEH_TRAIN: total_width += Train ::From(u)->GetDisplayImageWidth(); break; case VEH_ROAD: total_width += RoadVehicle::From(u)->GetDisplayImageWidth(); break; default: NOT_REACHED(); } if (u == v) sel_end = total_width; } int width = r.right + 1 - r.left - WD_BEVEL_LEFT - WD_BEVEL_RIGHT; int skip = 0; if (total_width > width) { int sel_center = (sel_start + sel_end) / 2; if (sel_center > width / 2) skip = min(total_width - width, sel_center - width / 2); } GrfSpecFeature f = GetFeatureNum(this->window_number); int h = GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height; int y = (r.top + r.bottom - h) / 2; DrawVehicleImage(v->First(), r.left + WD_BEVEL_LEFT, r.right - WD_BEVEL_RIGHT, y + 1, INVALID_VEHICLE, EIT_IN_DETAILS, skip); /* Highlight the articulated part (this is different to the whole-vehicle highlighting of DrawVehicleImage */ if (_current_text_dir == TD_RTL) { DrawFrameRect(r.right - sel_end + skip, y, r.right - sel_start + skip, y + h, COLOUR_WHITE, FR_BORDERONLY); } else { DrawFrameRect(r.left + sel_start - skip, y, r.left + sel_end - skip, y + h, COLOUR_WHITE, FR_BORDERONLY); } break; } } if (widget != WID_NGRFI_MAINPANEL) return; uint index = this->GetFeatureIndex(); const NIFeature *nif = GetFeature(this->window_number); const NIHelper *nih = nif->helper; const void *base = nih->GetInstance(index); const void *base_spec = nih->GetSpec(index); uint i = 0; if (nif->variables != NULL) { this->DrawString(r, i++, "Variables:"); for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++) { bool avail = true; uint param = HasVariableParameter(niv->var) ? NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][niv->var - 0x60] : 0; uint value = nih->Resolve(index, niv->var, param, &avail); if (!avail) continue; if (HasVariableParameter(niv->var)) { this->DrawString(r, i++, " %02x[%02x]: %08x (%s)", niv->var, param, value, niv->name); } else { this->DrawString(r, i++, " %02x: %08x (%s)", niv->var, value, niv->name); } } } uint psa_size = nih->GetPSASize(index, this->caller_grfid); const int32 *psa = nih->GetPSAFirstPosition(index, this->caller_grfid); if (psa_size != 0 && psa != NULL) { if (nih->PSAWithParameter()) { this->DrawString(r, i++, "Persistent storage [%08X]:", BSWAP32(this->caller_grfid)); } else { this->DrawString(r, i++, "Persistent storage:"); } assert(psa_size % 4 == 0); for (uint j = 0; j < psa_size; j += 4, psa += 4) { this->DrawString(r, i++, " %i: %i %i %i %i", j, psa[0], psa[1], psa[2], psa[3]); } } if (nif->properties != NULL) { this->DrawString(r, i++, "Properties:"); for (const NIProperty *nip = nif->properties; nip->name != NULL; nip++) { const void *ptr = (const byte *)base + nip->offset; uint value; switch (nip->read_size) { case 1: value = *(const uint8 *)ptr; break; case 2: value = *(const uint16 *)ptr; break; case 4: value = *(const uint32 *)ptr; break; default: NOT_REACHED(); } StringID string; SetDParam(0, value); switch (nip->type) { case NIT_INT: string = STR_JUST_INT; break; case NIT_CARGO: string = value != INVALID_CARGO ? CargoSpec::Get(value)->name : STR_QUANTITY_N_A; break; default: NOT_REACHED(); } char buffer[64]; GetString(buffer, string, lastof(buffer)); this->DrawString(r, i++, " %02x: %s (%s)", nip->prop, buffer, nip->name); } } if (nif->callbacks != NULL) { this->DrawString(r, i++, "Callbacks:"); for (const NICallback *nic = nif->callbacks; nic->name != NULL; nic++) { if (nic->cb_bit != CBM_NO_BIT) { const void *ptr = (const byte *)base_spec + nic->offset; uint value; switch (nic->read_size) { case 1: value = *(const uint8 *)ptr; break; case 2: value = *(const uint16 *)ptr; break; case 4: value = *(const uint32 *)ptr; break; default: NOT_REACHED(); } if (!HasBit(value, nic->cb_bit)) continue; this->DrawString(r, i++, " %03x: %s", nic->cb_id, nic->name); } else { this->DrawString(r, i++, " %03x: %s (unmasked)", nic->cb_id, nic->name); } } } /* Not nice and certainly a hack, but it beats duplicating * this whole function just to count the actual number of * elements. Especially because they need to be redrawn. */ const_cast(this)->vscroll->SetCount(i); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_NGRFI_PARENT: { const NIHelper *nih = GetFeatureHelper(this->window_number); uint index = nih->GetParent(this->GetFeatureIndex()); ::ShowNewGRFInspectWindow(GetFeatureNum(index), ::GetFeatureIndex(index), nih->GetGRFID(this->GetFeatureIndex())); break; } case WID_NGRFI_VEH_PREV: if (this->chain_index > 0) { this->chain_index--; this->InvalidateData(); } break; case WID_NGRFI_VEH_NEXT: if (this->HasChainIndex()) { uint index = this->GetFeatureIndex(); Vehicle *v = Vehicle::Get(index); if (v != NULL && v->Next() != NULL) { this->chain_index++; this->InvalidateData(); } } break; case WID_NGRFI_MAINPANEL: { /* Does this feature have variables? */ const NIFeature *nif = GetFeature(this->window_number); if (nif->variables == NULL) return; /* Get the line, make sure it's within the boundaries. */ int line = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NGRFI_MAINPANEL, TOP_OFFSET); if (line == INT_MAX) return; /* Find the variable related to the line */ for (const NIVariable *niv = nif->variables; niv->name != NULL; niv++, line--) { if (line != 1) continue; // 1 because of the "Variables:" line if (!HasVariableParameter(niv->var)) break; this->current_edit_param = niv->var; ShowQueryString(STR_EMPTY, STR_NEWGRF_INSPECT_QUERY_CAPTION, 9, this, CS_HEXADECIMAL, QSF_NONE); } } } } virtual void OnQueryTextFinished(char *str) { if (StrEmpty(str)) return; NewGRFInspectWindow::var60params[GetFeatureNum(this->window_number)][this->current_edit_param - 0x60] = strtol(str, NULL, 16); this->SetDirty(); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_NGRFI_MAINPANEL, TOP_OFFSET + BOTTOM_OFFSET); } /** * 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; if (this->HasChainIndex()) { this->ValidateChainIndex(); this->SetWidgetDisabledState(WID_NGRFI_VEH_PREV, this->chain_index == 0); Vehicle *v = Vehicle::Get(this->GetFeatureIndex()); this->SetWidgetDisabledState(WID_NGRFI_VEH_NEXT, v == NULL || v->Next() == NULL); } } }; /* static */ uint32 NewGRFInspectWindow::var60params[GSF_FAKE_END][0x20] = { {0} }; // Use spec to have 0s in whole array static const NWidgetPart _nested_newgrf_inspect_chain_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_NGRFI_VEH_PREV), SetDataTip(AWV_DECREASE, STR_NULL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_NGRFI_VEH_NEXT), SetDataTip(AWV_INCREASE, STR_NULL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_NGRFI_VEH_CHAIN), SetFill(1, 0), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_NGRFI_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(WID_NGRFI_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_NGRFI_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), }; static const NWidgetPart _nested_newgrf_inspect_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_NGRFI_CAPTION), SetDataTip(STR_NEWGRF_INSPECT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NGRFI_PARENT), SetDataTip(STR_NEWGRF_INSPECT_PARENT_BUTTON, STR_NEWGRF_INSPECT_PARENT_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_NGRFI_MAINPANEL), SetMinimalSize(300, 0), SetScrollbar(WID_NGRFI_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_NGRFI_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), }; static WindowDesc _newgrf_inspect_chain_desc( WDP_AUTO, "newgrf_inspect_chain", 400, 300, WC_NEWGRF_INSPECT, WC_NONE, 0, _nested_newgrf_inspect_chain_widgets, lengthof(_nested_newgrf_inspect_chain_widgets) ); static WindowDesc _newgrf_inspect_desc( WDP_AUTO, "newgrf_inspect", 400, 300, WC_NEWGRF_INSPECT, WC_NONE, 0, _nested_newgrf_inspect_widgets, lengthof(_nested_newgrf_inspect_widgets) ); /** * Show the inspect window for a given feature and index. * The index is normally an in-game location/identifier, such * as a TileIndex or an IndustryID depending on the feature * we want to inspect. * @param feature The feature we want to inspect. * @param index The index/identifier of the feature to inspect. * @param grfid GRFID of the item opening this window, or 0 if not opened by other window. */ void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32 grfid) { if (!IsNewGRFInspectable(feature, index)) return; WindowNumber wno = GetInspectWindowNumber(feature, index); WindowDesc *desc = (feature == GSF_TRAINS || feature == GSF_ROADVEHICLES) ? &_newgrf_inspect_chain_desc : &_newgrf_inspect_desc; NewGRFInspectWindow *w = AllocateWindowDescFront(desc, wno, true); w->SetCallerGRFID(grfid); } /** * Invalidate the inspect window for a given feature and index. * The index is normally an in-game location/identifier, such * as a TileIndex or an IndustryID depending on the feature * we want to inspect. * @param feature The feature we want to invalidate the window for. * @param index The index/identifier of the feature to invalidate. */ void InvalidateNewGRFInspectWindow(GrfSpecFeature feature, uint index) { if (feature == GSF_INVALID) return; WindowNumber wno = GetInspectWindowNumber(feature, index); InvalidateWindowData(WC_NEWGRF_INSPECT, wno); } /** * Delete inspect window for a given feature and index. * The index is normally an in-game location/identifier, such * as a TileIndex or an IndustryID depending on the feature * we want to inspect. * @param feature The feature we want to delete the window for. * @param index The index/identifier of the feature to delete. */ void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index) { if (feature == GSF_INVALID) return; WindowNumber wno = GetInspectWindowNumber(feature, index); DeleteWindowById(WC_NEWGRF_INSPECT, wno); /* Reinitialise the land information window to remove the "debug" sprite if needed. * Note: Since we might be called from a command here, it is important to not execute * the invalidation immediately. The landinfo window tests commands itself. */ InvalidateWindowData(WC_LAND_INFO, 0, 1); } /** * Can we inspect the data given a certain feature and index. * The index is normally an in-game location/identifier, such * as a TileIndex or an IndustryID depending on the feature * we want to inspect. * @param feature The feature we want to inspect. * @param index The index/identifier of the feature to inspect. * @return true if there is something to show. */ bool IsNewGRFInspectable(GrfSpecFeature feature, uint index) { const NIFeature *nif = GetFeature(GetInspectWindowNumber(feature, index)); if (nif == NULL) return false; return nif->helper->IsInspectable(index); } /** * Get the GrfSpecFeature associated with the tile. * @param tile The tile to get the feature from. * @return the GrfSpecFeature. */ GrfSpecFeature GetGrfSpecFeature(TileIndex tile) { switch (GetTileType(tile)) { default: return GSF_INVALID; case MP_RAILWAY: return GSF_RAILTYPES; case MP_ROAD: return IsLevelCrossing(tile) ? GSF_RAILTYPES : GSF_INVALID; case MP_HOUSE: return GSF_HOUSES; case MP_INDUSTRY: return GSF_INDUSTRYTILES; case MP_OBJECT: return GSF_OBJECTS; case MP_STATION: switch (GetStationType(tile)) { case STATION_RAIL: return GSF_STATIONS; case STATION_AIRPORT: return GSF_AIRPORTTILES; default: return GSF_INVALID; } } } /** * Get the GrfSpecFeature associated with the vehicle. * @param type The vehicle type to get the feature from. * @return the GrfSpecFeature. */ GrfSpecFeature GetGrfSpecFeature(VehicleType type) { switch (type) { case VEH_TRAIN: return GSF_TRAINS; case VEH_ROAD: return GSF_ROADVEHICLES; case VEH_SHIP: return GSF_SHIPS; case VEH_AIRCRAFT: return GSF_AIRCRAFT; default: return GSF_INVALID; } } /**** Sprite Aligner ****/ /** Window used for aligning sprites. */ struct SpriteAlignerWindow : Window { typedef SmallPair XyOffs; ///< Pair for x and y offsets of the sprite before alignment. First value contains the x offset, second value y offset. SpriteID current_sprite; ///< The currently shown sprite. Scrollbar *vscroll; SmallMap offs_start_map; ///< Mapping of starting offsets for the sprites which have been aligned in the sprite aligner window. SpriteAlignerWindow(WindowDesc *desc, WindowNumber wno) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_SA_SCROLLBAR); this->FinishInitNested(wno); /* Oh yes, we assume there is at least one normal sprite! */ while (GetSpriteType(this->current_sprite) != ST_NORMAL) this->current_sprite++; } virtual void SetStringParameters(int widget) const { const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL); switch (widget) { case WID_SA_CAPTION: SetDParam(0, this->current_sprite); SetDParamStr(1, FioGetFilename(GetOriginFileSlot(this->current_sprite))); break; case WID_SA_OFFSETS_ABS: SetDParam(0, spr->x_offs); SetDParam(1, spr->y_offs); break; case WID_SA_OFFSETS_REL: { /* Relative offset is new absolute offset - starting absolute offset. * Show 0, 0 as the relative offsets if entry is not in the map (meaning they have not been changed yet). */ const SmallPair *key_offs_pair = this->offs_start_map.Find(this->current_sprite); if (key_offs_pair != this->offs_start_map.End()) { SetDParam(0, spr->x_offs - key_offs_pair->second.first); SetDParam(1, spr->y_offs - key_offs_pair->second.second); } else { SetDParam(0, 0); SetDParam(1, 0); } break; } default: break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_SA_LIST) return; resize->height = max(11, FONT_HEIGHT_NORMAL + 1); resize->width = 1; /* Resize to about 200 pixels (for the preview) */ size->height = (1 + 200 / resize->height) * resize->height; } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_SA_SPRITE: { /* Center the sprite ourselves */ const Sprite *spr = GetSprite(this->current_sprite, ST_NORMAL); int width = r.right - r.left + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT; int height = r.bottom - r.top + 1 - WD_BEVEL_TOP - WD_BEVEL_BOTTOM; int x = -UnScaleGUI(spr->x_offs) + (width - UnScaleGUI(spr->width) ) / 2; int y = -UnScaleGUI(spr->y_offs) + (height - UnScaleGUI(spr->height)) / 2; DrawPixelInfo new_dpi; if (!FillDrawPixelInfo(&new_dpi, r.left + WD_BEVEL_LEFT, r.top + WD_BEVEL_TOP, width, height)) break; DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &new_dpi; DrawSprite(this->current_sprite, PAL_NONE, x, y, NULL, ZOOM_LVL_GUI); _cur_dpi = old_dpi; break; } case WID_SA_LIST: { const NWidgetBase *nwid = this->GetWidget(widget); int step_size = nwid->resize_y; SmallVector &list = _newgrf_debug_sprite_picker.sprites; int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), list.Length()); int y = r.top + WD_FRAMERECT_TOP; for (int i = this->vscroll->GetPosition(); i < max; i++) { SetDParam(0, list[i]); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); y += step_size; } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_SA_PREVIOUS: do { this->current_sprite = (this->current_sprite == 0 ? GetMaxSpriteID() : this->current_sprite) - 1; } while (GetSpriteType(this->current_sprite) != ST_NORMAL); this->SetDirty(); break; case WID_SA_GOTO: ShowQueryString(STR_EMPTY, STR_SPRITE_ALIGNER_GOTO_CAPTION, 7, this, CS_NUMERAL, QSF_NONE); break; case WID_SA_NEXT: do { this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID(); } while (GetSpriteType(this->current_sprite) != ST_NORMAL); this->SetDirty(); break; case WID_SA_PICKER: this->LowerWidget(WID_SA_PICKER); _newgrf_debug_sprite_picker.mode = SPM_WAIT_CLICK; this->SetDirty(); break; case WID_SA_LIST: { const NWidgetBase *nwid = this->GetWidget(widget); int step_size = nwid->resize_y; uint i = this->vscroll->GetPosition() + (pt.y - nwid->pos_y) / step_size; if (i < _newgrf_debug_sprite_picker.sprites.Length()) { SpriteID spr = _newgrf_debug_sprite_picker.sprites[i]; if (GetSpriteType(spr) == ST_NORMAL) this->current_sprite = spr; } this->SetDirty(); break; } case WID_SA_UP: case WID_SA_DOWN: case WID_SA_LEFT: case WID_SA_RIGHT: { /* * Yes... this is a hack. * * No... I don't think it is useful to make this less of a hack. * * If you want to align sprites, you just need the number. Generally * the sprite caches are big enough to not remove the sprite from the * cache. If that's not the case, just let the NewGRF developer * increase the cache size instead of storing thousands of offsets * for the incredibly small chance that it's actually going to be * used by someone and the sprite cache isn't big enough for that * particular NewGRF developer. */ Sprite *spr = const_cast(GetSprite(this->current_sprite, ST_NORMAL)); /* Remember the original offsets of the current sprite, if not already in mapping. */ if (!(this->offs_start_map.Contains(this->current_sprite))) { this->offs_start_map.Insert(this->current_sprite, XyOffs(spr->x_offs, spr->y_offs)); } switch (widget) { case WID_SA_UP: spr->y_offs--; break; case WID_SA_DOWN: spr->y_offs++; break; case WID_SA_LEFT: spr->x_offs--; break; case WID_SA_RIGHT: spr->x_offs++; break; } /* Of course, we need to redraw the sprite, but where is it used? * Everywhere is a safe bet. */ MarkWholeScreenDirty(); break; } case WID_SA_RESET_REL: /* Reset the starting offsets for the current sprite. */ this->offs_start_map.Erase(this->current_sprite); this->SetDirty(); break; } } virtual void OnQueryTextFinished(char *str) { if (StrEmpty(str)) return; this->current_sprite = atoi(str); if (this->current_sprite >= GetMaxSpriteID()) this->current_sprite = 0; while (GetSpriteType(this->current_sprite) != ST_NORMAL) { this->current_sprite = (this->current_sprite + 1) % GetMaxSpriteID(); } this->SetDirty(); } /** * 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; if (data == 1) { /* Sprite picker finished */ this->RaiseWidget(WID_SA_PICKER); this->vscroll->SetCount(_newgrf_debug_sprite_picker.sprites.Length()); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_SA_LIST); } }; static const NWidgetPart _nested_sprite_aligner_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_SA_CAPTION), SetDataTip(STR_SPRITE_ALIGNER_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_HORIZONTAL), SetPIP(0, 0, 10), NWidget(NWID_VERTICAL), SetPIP(10, 5, 10), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 5, 10), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_PREVIOUS), SetDataTip(STR_SPRITE_ALIGNER_PREVIOUS_BUTTON, STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_GOTO), SetDataTip(STR_SPRITE_ALIGNER_GOTO_BUTTON, STR_SPRITE_ALIGNER_GOTO_TOOLTIP), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_NEXT), SetDataTip(STR_SPRITE_ALIGNER_NEXT_BUTTON, STR_SPRITE_ALIGNER_NEXT_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_UP), SetDataTip(SPR_ARROW_UP, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL_LTR), SetPIP(10, 5, 10), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_LEFT), SetDataTip(SPR_ARROW_LEFT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_SA_SPRITE), SetDataTip(STR_NULL, STR_SPRITE_ALIGNER_SPRITE_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_RIGHT), SetDataTip(SPR_ARROW_RIGHT, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SA_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SPRITE_ALIGNER_MOVE_TOOLTIP), SetResize(0, 0), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), NWidget(WWT_LABEL, COLOUR_GREY, WID_SA_OFFSETS_ABS), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS_ABS, STR_NULL), SetFill(1, 0), SetPadding(0, 10, 0, 10), NWidget(WWT_LABEL, COLOUR_GREY, WID_SA_OFFSETS_REL), SetDataTip(STR_SPRITE_ALIGNER_OFFSETS_REL, STR_NULL), SetFill(1, 0), SetPadding(0, 10, 0, 10), NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SA_RESET_REL), SetDataTip(STR_SPRITE_ALIGNER_RESET_BUTTON, STR_SPRITE_ALIGNER_RESET_TOOLTIP), SetFill(0, 0), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(10, 5, 10), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SA_PICKER), SetDataTip(STR_SPRITE_ALIGNER_PICKER_BUTTON, STR_SPRITE_ALIGNER_PICKER_TOOLTIP), SetFill(1, 0), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_SA_LIST), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 1), SetScrollbar(WID_SA_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SA_SCROLLBAR), EndContainer(), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _sprite_aligner_desc( WDP_AUTO, "sprite_aligner", 400, 300, WC_SPRITE_ALIGNER, WC_NONE, 0, _nested_sprite_aligner_widgets, lengthof(_nested_sprite_aligner_widgets) ); /** * Show the window for aligning sprites. */ void ShowSpriteAlignerWindow() { AllocateWindowDescFront(&_sprite_aligner_desc, 0); } openttd-1.5.3/src/sound.cpp0000644000000000000000000002330012627373442014326 0ustar rootroot/* $Id: sound.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 sound.cpp Handling of playing sounds. */ #include "stdafx.h" #include "landscape.h" #include "mixer.h" #include "newgrf_sound.h" #include "fios.h" #include "window_gui.h" #include "vehicle_base.h" /* The type of set we're replacing */ #define SET_TYPE "sounds" #include "base_media_func.h" #include "safeguards.h" static SoundEntry _original_sounds[ORIGINAL_SAMPLE_COUNT]; static void OpenBankFile(const char *filename) { memset(_original_sounds, 0, sizeof(_original_sounds)); /* If there is no sound file (nosound set), don't load anything */ if (filename == NULL) return; FioOpenFile(SOUND_SLOT, filename, BASESET_DIR); size_t pos = FioGetPos(); uint count = FioReadDword(); /* The new format has the highest bit always set */ bool new_format = HasBit(count, 31); ClrBit(count, 31); count /= 8; /* Simple check for the correct number of original sounds. */ if (count != ORIGINAL_SAMPLE_COUNT) { /* Corrupt sample data? Just leave the allocated memory as those tell * there is no sound to play (size = 0 due to calloc). Not allocating * the memory disables valid NewGRFs that replace sounds. */ DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename); return; } FioSeekTo(pos, SEEK_SET); for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) { _original_sounds[i].file_slot = SOUND_SLOT; _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos; _original_sounds[i].file_size = FioReadDword(); } for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) { SoundEntry *sound = &_original_sounds[i]; char name[255]; FioSeekTo(sound->file_offset, SEEK_SET); /* Check for special case, see else case */ FioReadBlock(name, FioReadByte()); // Read the name of the sound if (new_format || strcmp(name, "Corrupt sound") != 0) { FioSeekTo(12, SEEK_CUR); // Skip past RIFF header /* Read riff tags */ for (;;) { uint32 tag = FioReadDword(); uint32 size = FioReadDword(); if (tag == ' tmf') { FioReadWord(); // wFormatTag sound->channels = FioReadWord(); // wChannels sound->rate = FioReadDword(); // samples per second if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate. FioReadDword(); // avg bytes per second FioReadWord(); // alignment sound->bits_per_sample = FioReadByte(); // bits per sample FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR); } else if (tag == 'atad') { sound->file_size = size; sound->file_slot = SOUND_SLOT; sound->file_offset = FioGetPos(); break; } else { sound->file_size = 0; break; } } } else { /* * Special case for the jackhammer sound * (name in sample.cat is "Corrupt sound") * It's no RIFF file, but raw PCM data */ sound->channels = 1; sound->rate = 11025; sound->bits_per_sample = 8; sound->file_slot = SOUND_SLOT; sound->file_offset = FioGetPos(); } } } static bool SetBankSource(MixerChannel *mc, const SoundEntry *sound) { assert(sound != NULL); /* Check for valid sound size. */ if (sound->file_size == 0 || sound->file_size > ((size_t)-1) - 2) return false; int8 *mem = MallocT(sound->file_size + 2); /* Add two extra bytes so rate conversion can read these * without reading out of its input buffer. */ mem[sound->file_size ] = 0; mem[sound->file_size + 1] = 0; FioSeekToFile(sound->file_slot, sound->file_offset); FioReadBlock(mem, sound->file_size); /* 16-bit PCM WAV files should be signed by default */ if (sound->bits_per_sample == 8) { for (uint i = 0; i != sound->file_size; i++) { mem[i] += -128; // Convert unsigned sound data to signed } } #if TTD_ENDIAN == TTD_BIG_ENDIAN if (sound->bits_per_sample == 16) { uint num_samples = sound->file_size / 2; int16 *samples = (int16 *)mem; for (uint i = 0; i < num_samples; i++) { samples[i] = BSWAP16(samples[i]); } } #endif assert(sound->bits_per_sample == 8 || sound->bits_per_sample == 16); assert(sound->channels == 1); assert(sound->file_size != 0 && sound->rate != 0); MxSetChannelRawSrc(mc, mem, sound->file_size, sound->rate, sound->bits_per_sample == 16); return true; } void InitializeSound() { DEBUG(misc, 1, "Loading sound effects..."); OpenBankFile(BaseSounds::GetUsedSet()->files->filename); } /* Low level sound player */ static void StartSound(SoundID sound_id, float pan, uint volume) { if (volume == 0) return; SoundEntry *sound = GetSound(sound_id); if (sound == NULL) return; /* NewGRF sound that wasn't loaded yet? */ if (sound->rate == 0 && sound->file_slot != 0) { if (!LoadNewGRFSound(sound)) { /* Mark as invalid. */ sound->file_slot = 0; return; } } /* Empty sound? */ if (sound->rate == 0) return; MixerChannel *mc = MxAllocateChannel(); if (mc == NULL) return; if (!SetBankSource(mc, sound)) return; /* Apply the sound effect's own volume. */ volume = sound->volume * volume; MxSetChannelVolume(mc, volume, pan); MxActivateChannel(mc); } static const byte _vol_factor_by_zoom[] = {255, 255, 255, 190, 134, 87}; assert_compile(lengthof(_vol_factor_by_zoom) == ZOOM_LVL_COUNT); static const byte _sound_base_vol[] = { 128, 90, 128, 128, 128, 128, 128, 128, 128, 90, 90, 128, 128, 128, 128, 128, 128, 128, 128, 80, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 90, 90, 90, 128, 90, 128, 128, 90, 128, 128, 128, 90, 128, 128, 128, 128, 128, 128, 90, 128, 128, 128, 128, 90, 128, 128, 128, 128, 128, 128, 128, 128, 90, 90, 90, 128, 128, 128, 90, }; static const byte _sound_idx[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 1, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, }; void SndCopyToPool() { SoundEntry *sound = AllocateSound(ORIGINAL_SAMPLE_COUNT); for (uint i = 0; i < ORIGINAL_SAMPLE_COUNT; i++) { sound[i] = _original_sounds[_sound_idx[i]]; sound[i].volume = _sound_base_vol[i]; sound[i].priority = 0; } } /** * Decide 'where' (between left and right speaker) to play the sound effect. * @param sound Sound effect to play * @param left Left edge of virtual coordinates where the sound is produced * @param right Right edge of virtual coordinates where the sound is produced * @param top Top edge of virtual coordinates where the sound is produced * @param bottom Bottom edge of virtual coordinates where the sound is produced */ static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, int bottom) { if (_settings_client.music.effect_vol == 0) return; const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { const ViewPort *vp = w->viewport; if (vp != NULL && left < vp->virtual_left + vp->virtual_width && right > vp->virtual_left && top < vp->virtual_top + vp->virtual_height && bottom > vp->virtual_top) { int screen_x = (left + right) / 2 - vp->virtual_left; int width = (vp->virtual_width == 0 ? 1 : vp->virtual_width); float panning = (float)screen_x / width; StartSound( sound, panning, (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256 ); return; } } } void SndPlayTileFx(SoundID sound, TileIndex tile) { /* emits sound from center of the tile */ int x = min(MapMaxX() - 1, TileX(tile)) * TILE_SIZE + TILE_SIZE / 2; int y = min(MapMaxY() - 1, TileY(tile)) * TILE_SIZE - TILE_SIZE / 2; int z = (y < 0 ? 0 : GetSlopePixelZ(x, y)); Point pt = RemapCoords(x, y, z); y += 2 * TILE_SIZE; Point pt2 = RemapCoords(x, y, GetSlopePixelZ(x, y)); SndPlayScreenCoordFx(sound, pt.x, pt2.x, pt.y, pt2.y); } void SndPlayVehicleFx(SoundID sound, const Vehicle *v) { SndPlayScreenCoordFx(sound, v->coord.left, v->coord.right, v->coord.top, v->coord.bottom ); } void SndPlayFx(SoundID sound) { StartSound(sound, 0.5, _settings_client.music.effect_vol); } INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia, SoundsSet) /** Names corresponding to the sound set's files */ static const char * const _sound_file_names[] = { "samples" }; template /* static */ const char * const *BaseSet::file_names = _sound_file_names; template /* static */ const char *BaseMedia::GetExtension() { return ".obs"; // OpenTTD Base Sounds } template /* static */ bool BaseMedia::DetermineBestSet() { if (BaseMedia::used_set != NULL) return true; const Tbase_set *best = NULL; for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { /* Skip unusable sets */ if (c->GetNumMissing() != 0) continue; if (best == NULL || (best->fallback && !c->fallback) || best->valid_files < c->valid_files || (best->valid_files == c->valid_files && (best->shortname == c->shortname && best->version < c->version))) { best = c; } } BaseMedia::used_set = best; return BaseMedia::used_set != NULL; } openttd-1.5.3/src/base_station_base.h0000644000000000000000000002040412627373435016314 0ustar rootroot/* $Id: base_station_base.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 base_station_base.h Base classes/functions for base stations. */ #ifndef BASE_STATION_BASE_H #define BASE_STATION_BASE_H #include "core/pool_type.hpp" #include "command_type.h" #include "viewport_type.h" #include "station_map.h" typedef Pool StationPool; extern StationPool _station_pool; struct StationSpecList { const StationSpec *spec; uint32 grfid; ///< GRF ID of this custom station uint8 localidx; ///< Station ID within GRF of station }; /** StationRect - used to track station spread out rectangle - cheaper than scanning whole map */ struct StationRect : public Rect { enum StationRectMode { ADD_TEST = 0, ADD_TRY, ADD_FORCE }; StationRect(); void MakeEmpty(); bool PtInExtendedRect(int x, int y, int distance = 0) const; bool IsEmpty() const; CommandCost BeforeAddTile(TileIndex tile, StationRectMode mode); CommandCost BeforeAddRect(TileIndex tile, int w, int h, StationRectMode mode); bool AfterRemoveTile(BaseStation *st, TileIndex tile); bool AfterRemoveRect(BaseStation *st, TileArea ta); static bool ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a); StationRect& operator = (const Rect &src); }; /** Base class for all station-ish types */ struct BaseStation : StationPool::PoolItem<&_station_pool> { TileIndex xy; ///< Base tile of the station ViewportSign sign; ///< NOSAVE: Dimensions of sign byte delete_ctr; ///< Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is deleted. char *name; ///< Custom name StringID string_id; ///< Default name (town area) of station Town *town; ///< The town this station is associated with OwnerByte owner; ///< The owner of this station StationFacilityByte facilities; ///< The facilities that this station has uint8 num_specs; ///< Number of specs in the speclist StationSpecList *speclist; ///< List of station specs of this station Date build_date; ///< Date of construction uint16 random_bits; ///< Random bits assigned to this station byte waiting_triggers; ///< Waiting triggers (NewGRF) for this station uint8 cached_anim_triggers; ///< NOSAVE: Combined animation trigger bitmask, used to determine if trigger processing should happen. uint32 cached_cargo_triggers; ///< NOSAVE: Combined cargo trigger bitmask TileArea train_station; ///< Tile area the train 'station' part covers StationRect rect; ///< NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions /** * Initialize the base station. * @param tile The location of the station sign */ BaseStation(TileIndex tile) : xy(tile), train_station(INVALID_TILE, 0, 0) { } virtual ~BaseStation(); /** * Check whether a specific tile belongs to this station. * @param tile the tile to check * @return true if the tile belongs to this station */ virtual bool TileBelongsToRailStation(TileIndex tile) const = 0; /** * Helper function to get a NewGRF variable that isn't implemented by the base class. * @param object the resolver object related to this query * @param variable that is queried * @param parameter parameter for that variable * @param available will return false if ever the variable asked for does not exist * @return the value stored in the corresponding variable */ virtual uint32 GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const = 0; /** * Update the coordinated of the sign (as shown in the viewport). */ virtual void UpdateVirtCoord() = 0; /** * Get the tile area for a given station type. * @param ta tile area to fill. * @param type the type of the area */ virtual void GetTileArea(TileArea *ta, StationType type) const = 0; /** * Obtain the length of a platform * @pre tile must be a rail station tile * @param tile A tile that contains the platform in question * @return The length of the platform */ virtual uint GetPlatformLength(TileIndex tile) const = 0; /** * Determines the REMAINING length of a platform, starting at (and including) * the given tile. * @param tile the tile from which to start searching. Must be a rail station tile * @param dir The direction in which to search. * @return The platform length */ virtual uint GetPlatformLength(TileIndex tile, DiagDirection dir) const = 0; /** * Get the base station belonging to a specific tile. * @param tile The tile to get the base station from. * @return the station associated with that tile. */ static inline BaseStation *GetByTile(TileIndex tile) { return BaseStation::Get(GetStationIndex(tile)); } /** * Check whether the base station currently is in use; in use means * that it is not scheduled for deletion and that it still has some * facilities left. * @return true if still in use */ inline bool IsInUse() const { return (this->facilities & ~FACIL_WAYPOINT) != 0; } static void PostDestructor(size_t index); }; #define FOR_ALL_BASE_STATIONS(var) FOR_ALL_ITEMS_FROM(BaseStation, station_index, var, 0) /** * Class defining several overloaded accessors so we don't * have to cast base stations that often */ template struct SpecializedStation : public BaseStation { static const StationFacility EXPECTED_FACIL = Tis_waypoint ? FACIL_WAYPOINT : FACIL_NONE; ///< Specialized type /** * Set station type correctly * @param tile The base tile of the station. */ inline SpecializedStation(TileIndex tile) : BaseStation(tile) { this->facilities = EXPECTED_FACIL; } /** * Helper for checking whether the given station is of this type. * @param st the station to check. * @return true if the station is the type we expect it to be. */ static inline bool IsExpected(const BaseStation *st) { return (st->facilities & FACIL_WAYPOINT) == EXPECTED_FACIL; } /** * Tests whether given index is a valid index for station of this type * @param index tested index * @return is this index valid index of T? */ static inline bool IsValidID(size_t index) { return BaseStation::IsValidID(index) && IsExpected(BaseStation::Get(index)); } /** * Gets station with given index * @return pointer to station with given index casted to T * */ static inline T *Get(size_t index) { return (T *)BaseStation::Get(index); } /** * Returns station if the index is a valid index for this station type * @return pointer to station with given index if it's a station of this type */ static inline T *GetIfValid(size_t index) { return IsValidID(index) ? Get(index) : NULL; } /** * Get the station belonging to a specific tile. * @param tile The tile to get the station from. * @return the station associated with that tile. */ static inline T *GetByTile(TileIndex tile) { return GetIfValid(GetStationIndex(tile)); } /** * Converts a BaseStation to SpecializedStation with type checking. * @param st BaseStation pointer * @return pointer to SpecializedStation */ static inline T *From(BaseStation *st) { assert(IsExpected(st)); return (T *)st; } /** * Converts a const BaseStation to const SpecializedStation with type checking. * @param st BaseStation pointer * @return pointer to SpecializedStation */ static inline const T *From(const BaseStation *st) { assert(IsExpected(st)); return (const T *)st; } }; #define FOR_ALL_BASE_STATIONS_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, station_index, var, 0) if (name::IsExpected(var)) #endif /* BASE_STATION_BASE_H */ openttd-1.5.3/src/transport_type.h0000644000000000000000000000345212627373435015750 0ustar rootroot/* $Id: transport_type.h 22405 2011-05-01 19:14:12Z rubidium $ */ /* * 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 transport_type.h Base types related to transport. */ #ifndef TRANSPORT_TYPE_H #define TRANSPORT_TYPE_H #include "core/enum_type.hpp" /** Type for the company global vehicle unit number. */ typedef uint16 UnitID; /** Available types of transport */ enum TransportType { /* These constants are for now linked to the representation of bridges * and tunnels, so they can be used by GetTileTrackStatus_TunnelBridge. * In an ideal world, these constants would be used everywhere when * accessing tunnels and bridges. For now, you should just not change * the values for road and rail. */ TRANSPORT_BEGIN = 0, ///< Begin of the iterator. TRANSPORT_RAIL = TRANSPORT_BEGIN, ///< Transport by train TRANSPORT_ROAD, ///< Transport by road vehicle TRANSPORT_WATER, ///< Transport over water TRANSPORT_AIR, ///< Transport through air TRANSPORT_END, ///< End of iterations. INVALID_TRANSPORT = 0xff, ///< Sentinel for invalid transport types. }; /** Helper information for extract tool. */ template <> struct EnumPropsT : MakeEnumPropsT {}; #endif /* TRANSPORT_TYPE_H */ openttd-1.5.3/src/autoreplace_gui.cpp0000644000000000000000000007372412627373442016365 0ustar rootroot/* $Id: autoreplace_gui.cpp 26960 2014-10-05 11:20:02Z peter1138 $ */ /* * 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 autoreplace_gui.cpp GUI for autoreplace handling. */ #include "stdafx.h" #include "command_func.h" #include "vehicle_gui.h" #include "newgrf_engine.h" #include "rail.h" #include "strings_func.h" #include "window_func.h" #include "autoreplace_func.h" #include "company_func.h" #include "engine_base.h" #include "window_gui.h" #include "engine_gui.h" #include "settings_func.h" #include "core/geometry_func.hpp" #include "rail_gui.h" #include "widgets/dropdown_func.h" #include "widgets/autoreplace_widget.h" #include "safeguards.h" void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group); static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) { int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; return r; } /** * Rebuild the left autoreplace list if an engine is removed or added * @param e Engine to check if it is removed or added * @param id_g The group the engine belongs to * Note: this function only works if it is called either * - when a new vehicle is build, but before it's counted in num_engines * - when a vehicle is deleted and after it's subtracted from num_engines * - when not changing the count (used when changing replace orders) */ void InvalidateAutoreplaceWindow(EngineID e, GroupID id_g) { if (GetGroupNumEngines(_local_company, id_g, e) == 0 || GetGroupNumEngines(_local_company, ALL_GROUP, e) == 0) { /* We don't have any of this engine type. * Either we just sold the last one, we build a new one or we stopped replacing it. * In all cases, we need to update the left list */ InvalidateWindowData(WC_REPLACE_VEHICLE, Engine::Get(e)->type, 1); } } /** * When an engine is made buildable or is removed from being buildable, add/remove it from the build/autoreplace lists * @param type The type of engine */ void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type) { InvalidateWindowData(WC_REPLACE_VEHICLE, type, 0); // Update the autoreplace window InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well } static const StringID _start_replace_dropdown[] = { STR_REPLACE_VEHICLES_NOW, STR_REPLACE_VEHICLES_WHEN_OLD, INVALID_STRING_ID }; /** * Window for the autoreplacing of vehicles. */ class ReplaceVehicleWindow : public Window { EngineID sel_engine[2]; ///< Selected engine left and right. GUIEngineList engines[2]; ///< Left and right list of engines. bool replace_engines; ///< If \c true, engines are replaced, if \c false, wagons are replaced (only for trains). bool reset_sel_engine; ///< Also reset #sel_engine while updating left and/or right (#update_left and/or #update_right) and no valid engine selected. GroupID sel_group; ///< Group selected to replace. int details_height; ///< Minimal needed height of the details panels (found so far). byte sort_criteria; ///< Criteria of sorting vehicles. bool descending_sort_order; ///< Order of sorting vehicles. bool show_hidden_engines; ///< Whether to show the hidden engines. RailType sel_railtype; ///< Type of rail tracks selected. Scrollbar *vscroll[2]; /** * Figure out if an engine should be added to a list. * @param e The EngineID. * @param draw_left If \c true, the left list is drawn (the engines specific to the railtype you selected). * @param show_engines If \c true, the locomotives are drawn, else the wagons are drawn (never both). * @return \c true if the engine should be in the list (based on this check), else \c false. */ bool GenerateReplaceRailList(EngineID e, bool draw_left, bool show_engines) { const RailVehicleInfo *rvi = RailVehInfo(e); /* Ensure that the wagon/engine selection fits the engine. */ if ((rvi->railveh_type == RAILVEH_WAGON) == show_engines) return false; if (draw_left && show_engines) { /* Ensure that the railtype is specific to the selected one */ if (rvi->railtype != this->sel_railtype) return false; } return true; } /** * Generate an engines list * @param draw_left true if generating the left list, otherwise false */ void GenerateReplaceVehList(bool draw_left) { EngineID selected_engine = INVALID_ENGINE; VehicleType type = (VehicleType)this->window_number; byte side = draw_left ? 0 : 1; GUIEngineList *list = &this->engines[side]; list->Clear(); const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, type) { if (!draw_left && !this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; if (type == VEH_TRAIN && !this->GenerateReplaceRailList(eid, draw_left, this->replace_engines)) continue; // special rules for trains if (draw_left) { const uint num_engines = GetGroupNumEngines(_local_company, this->sel_group, eid); /* Skip drawing the engines we don't have any of and haven't set for replacement */ if (num_engines == 0 && EngineReplacementForCompany(Company::Get(_local_company), eid, this->sel_group) == INVALID_ENGINE) continue; } else { if (!CheckAutoreplaceValidity(this->sel_engine[0], eid, _local_company)) continue; } *list->Append() = eid; if (eid == this->sel_engine[side]) selected_engine = eid; // The selected engine is still in the list } this->sel_engine[side] = selected_engine; // update which engine we selected (the same or none, if it's not in the list anymore) if (draw_left) { EngList_Sort(list, &EngineNumberSorter); } else { _engine_sort_direction = this->descending_sort_order; EngList_Sort(list, _engine_sort_functions[this->window_number][this->sort_criteria]); } } /** Generate the lists */ void GenerateLists() { EngineID e = this->sel_engine[0]; if (this->engines[0].NeedRebuild()) { /* We need to rebuild the left engines list */ this->GenerateReplaceVehList(true); this->vscroll[0]->SetCount(this->engines[0].Length()); if (this->reset_sel_engine && this->sel_engine[0] == INVALID_ENGINE && this->engines[0].Length() != 0) { this->sel_engine[0] = this->engines[0][0]; } } if (this->engines[1].NeedRebuild() || e != this->sel_engine[0]) { /* Either we got a request to rebuild the right engines list, or the left engines list selected a different engine */ if (this->sel_engine[0] == INVALID_ENGINE) { /* Always empty the right engines list when nothing is selected in the left engines list */ this->engines[1].Clear(); this->sel_engine[1] = INVALID_ENGINE; } else { if (this->reset_sel_engine && this->sel_engine[0] != INVALID_ENGINE) { /* Select the current replacement for sel_engine[0]. */ const Company *c = Company::Get(_local_company); this->sel_engine[1] = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group); } /* Regenerate the list on the right. Note: This resets sel_engine[1] to INVALID_ENGINE, if it is no longer available. */ this->GenerateReplaceVehList(false); this->vscroll[1]->SetCount(this->engines[1].Length()); if (this->reset_sel_engine && this->sel_engine[1] != INVALID_ENGINE) { int position = 0; for (EngineID *it = this->engines[1].Begin(); it != this->engines[1].End(); ++it) { if (*it == this->sel_engine[1]) break; ++position; } this->vscroll[1]->ScrollTowards(position); } } } /* Reset the flags about needed updates */ this->engines[0].RebuildDone(); this->engines[1].RebuildDone(); this->reset_sel_engine = false; } /** * Handle click on the start replace button. * @param replace_when_old Replace now or only when old? */ void ReplaceClick_StartReplace(bool replace_when_old) { EngineID veh_from = this->sel_engine[0]; EngineID veh_to = this->sel_engine[1]; DoCommandP(0, (replace_when_old ? 1 : 0) | (this->sel_group << 16), veh_from + (veh_to << 16), CMD_SET_AUTOREPLACE); } public: ReplaceVehicleWindow(WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc) { if (vehicletype == VEH_TRAIN) { /* For rail vehicles find the most used vehicle type, which is usually * better than 'just' the first/previous vehicle type. */ uint type_count[RAILTYPE_END]; memset(type_count, 0, sizeof(type_count)); const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { if (e->u.rail.railveh_type == RAILVEH_WAGON) continue; type_count[e->u.rail.railtype] += GetGroupNumEngines(_local_company, id_g, e->index); } this->sel_railtype = RAILTYPE_BEGIN; for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { if (type_count[this->sel_railtype] < type_count[rt]) this->sel_railtype = rt; } } this->replace_engines = true; // start with locomotives (all other vehicles will not read this bool) this->engines[0].ForceRebuild(); this->engines[1].ForceRebuild(); this->reset_sel_engine = true; this->details_height = ((vehicletype == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; this->sel_engine[0] = INVALID_ENGINE; this->sel_engine[1] = INVALID_ENGINE; this->show_hidden_engines = _engine_sort_show_hidden_engines[vehicletype]; this->CreateNestedTree(); this->vscroll[0] = this->GetScrollbar(WID_RV_LEFT_SCROLLBAR); this->vscroll[1] = this->GetScrollbar(WID_RV_RIGHT_SCROLLBAR); NWidgetCore *widget = this->GetWidget(WID_RV_SHOW_HIDDEN_ENGINES); widget->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + vehicletype; widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + vehicletype; widget->SetLowered(this->show_hidden_engines); this->FinishInitNested(vehicletype); this->sort_criteria = _engine_sort_last_criteria[vehicletype]; this->descending_sort_order = _engine_sort_last_order[vehicletype]; this->owner = _local_company; this->sel_group = id_g; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_RV_SORT_ASCENDING_DESCENDING: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_RV_LEFT_MATRIX: case WID_RV_RIGHT_MATRIX: resize->height = GetEngineListHeight((VehicleType)this->window_number); size->height = (this->window_number <= VEH_ROAD ? 8 : 4) * resize->height; break; case WID_RV_LEFT_DETAILS: case WID_RV_RIGHT_DETAILS: size->height = this->details_height; break; case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { StringID str = this->GetWidget(widget)->widget_data; SetDParam(0, STR_CONFIG_SETTING_ON); Dimension d = GetStringBoundingBox(str); SetDParam(0, STR_CONFIG_SETTING_OFF); d = maxdim(d, GetStringBoundingBox(str)); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: { StringID str = this->GetWidget(widget)->widget_data; SetDParam(0, STR_REPLACE_ENGINES); Dimension d = GetStringBoundingBox(str); SetDParam(0, STR_REPLACE_WAGONS); d = maxdim(d, GetStringBoundingBox(str)); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_RV_INFO_TAB: { Dimension d = GetStringBoundingBox(STR_REPLACE_NOT_REPLACING); d = maxdim(d, GetStringBoundingBox(STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED)); d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { Dimension d = {0, 0}; for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { const RailtypeInfo *rti = GetRailTypeInfo(rt); /* Skip rail type if it has no label */ if (rti->label == 0) continue; d = maxdim(d, GetStringBoundingBox(rti->strings.replace_text)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_RV_START_REPLACE: { Dimension d = GetStringBoundingBox(STR_REPLACE_VEHICLES_START); for (int i = 0; _start_replace_dropdown[i] != INVALID_STRING_ID; i++) { d = maxdim(d, GetStringBoundingBox(_start_replace_dropdown[i])); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_RV_CAPTION: SetDParam(0, STR_REPLACE_VEHICLE_TRAIN + this->window_number); switch (this->sel_group) { case ALL_GROUP: SetDParam(1, STR_GROUP_ALL_TRAINS + this->window_number); break; case DEFAULT_GROUP: SetDParam(1, STR_GROUP_DEFAULT_TRAINS + this->window_number); break; default: SetDParam(1, STR_GROUP_NAME); SetDParam(2, sel_group); break; } break; case WID_RV_SORT_DROPDOWN: SetDParam(0, _engine_sort_listing[this->window_number][this->sort_criteria]); break; case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { const Company *c = Company::Get(_local_company); SetDParam(0, c->settings.renew_keep_length ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); break; } case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: SetDParam(0, this->replace_engines ? STR_REPLACE_ENGINES : STR_REPLACE_WAGONS); break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_RV_SORT_ASCENDING_DESCENDING: this->DrawSortButtonState(WID_RV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP); break; case WID_RV_INFO_TAB: { const Company *c = Company::Get(_local_company); StringID str; if (this->sel_engine[0] != INVALID_ENGINE) { if (!EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)) { str = STR_REPLACE_NOT_REPLACING; } else { bool when_old = false; EngineID e = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group, &when_old); str = when_old ? STR_REPLACE_REPLACING_WHEN_OLD : STR_ENGINE_NAME; SetDParam(0, e); } } else { str = STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED; } DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_BLACK, SA_HOR_CENTER); break; } case WID_RV_LEFT_MATRIX: case WID_RV_RIGHT_MATRIX: { int side = (widget == WID_RV_LEFT_MATRIX) ? 0 : 1; EngineID start = this->vscroll[side]->GetPosition(); // what is the offset for the start (scrolling) EngineID end = min(this->vscroll[side]->GetCapacity() + start, this->engines[side].Length()); /* Do the actual drawing */ DrawEngineList((VehicleType)this->window_number, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->engines[side], start, end, this->sel_engine[side], side == 0, this->sel_group); break; } } } virtual void OnPaint() { if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists(); Company *c = Company::Get(_local_company); /* Disable the "Start Replacing" button if: * Either engines list is empty * or The selected replacement engine has a replacement (to prevent loops). */ this->SetWidgetDisabledState(WID_RV_START_REPLACE, this->sel_engine[0] == INVALID_ENGINE || this->sel_engine[1] == INVALID_ENGINE || EngineReplacementForCompany(c, this->sel_engine[1], this->sel_group) != INVALID_ENGINE); /* Disable the "Stop Replacing" button if: * The left engines list (existing vehicle) is empty * or The selected vehicle has no replacement set up */ this->SetWidgetDisabledState(WID_RV_STOP_REPLACE, this->sel_engine[0] == INVALID_ENGINE || !EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)); if (this->window_number == VEH_TRAIN) { /* sets the colour of that art thing */ this->GetWidget(WID_RV_TRAIN_FLUFF_LEFT)->colour = _company_colours[_local_company]; this->GetWidget(WID_RV_TRAIN_FLUFF_RIGHT)->colour = _company_colours[_local_company]; /* Show the selected railtype in the pulldown menu */ this->GetWidget(WID_RV_TRAIN_RAILTYPE_DROPDOWN)->widget_data = GetRailTypeInfo(sel_railtype)->strings.replace_text; } this->DrawWidgets(); if (!this->IsShaded()) { int needed_height = this->details_height; /* Draw details panels. */ for (int side = 0; side < 2; side++) { if (this->sel_engine[side] != INVALID_ENGINE) { NWidgetBase *nwi = this->GetWidget(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS); int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side]); needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); } } if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. this->details_height = needed_height; this->ReInit(); return; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_RV_SORT_ASCENDING_DESCENDING: this->descending_sort_order ^= true; _engine_sort_last_order[this->window_number] = this->descending_sort_order; this->engines[1].ForceRebuild(); this->SetDirty(); break; case WID_RV_SHOW_HIDDEN_ENGINES: this->show_hidden_engines ^= true; _engine_sort_show_hidden_engines[this->window_number] = this->show_hidden_engines; this->engines[1].ForceRebuild(); this->SetWidgetLoweredState(widget, this->show_hidden_engines); this->SetDirty(); break; case WID_RV_SORT_DROPDOWN: DisplayVehicleSortDropDown(this, static_cast(this->window_number), this->sort_criteria, WID_RV_SORT_DROPDOWN); break; case WID_RV_TRAIN_ENGINEWAGON_TOGGLE: this->replace_engines = !(this->replace_engines); this->engines[0].ForceRebuild(); this->reset_sel_engine = true; this->SetDirty(); break; case WID_RV_TRAIN_RAILTYPE_DROPDOWN: // Railtype selection dropdown menu ShowDropDownList(this, GetRailTypeDropDownList(true), sel_railtype, WID_RV_TRAIN_RAILTYPE_DROPDOWN); break; case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING); break; case WID_RV_START_REPLACE: { // Start replacing if (this->GetWidget(widget)->ButtonHit(pt)) { this->HandleButtonClick(WID_RV_START_REPLACE); ReplaceClick_StartReplace(false); } else { bool replacment_when_old = EngineHasReplacementWhenOldForCompany(Company::Get(_local_company), this->sel_engine[0], this->sel_group); ShowDropDownMenu(this, _start_replace_dropdown, replacment_when_old ? 1 : 0, WID_RV_START_REPLACE, !this->replace_engines ? 1 << 1 : 0, 0); } break; } case WID_RV_STOP_REPLACE: { // Stop replacing EngineID veh_from = this->sel_engine[0]; DoCommandP(0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16), CMD_SET_AUTOREPLACE); break; } case WID_RV_LEFT_MATRIX: case WID_RV_RIGHT_MATRIX: { byte click_side; if (widget == WID_RV_LEFT_MATRIX) { click_side = 0; } else { click_side = 1; } uint i = this->vscroll[click_side]->GetScrolledRowFromWidget(pt.y, this, widget); size_t engine_count = this->engines[click_side].Length(); EngineID e = engine_count > i ? this->engines[click_side][i] : INVALID_ENGINE; if (e == this->sel_engine[click_side]) break; // we clicked the one we already selected this->sel_engine[click_side] = e; if (click_side == 0) { this->engines[1].ForceRebuild(); this->reset_sel_engine = true; } this->SetDirty(); break; } } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_RV_SORT_DROPDOWN: if (this->sort_criteria != index) { this->sort_criteria = index; _engine_sort_last_criteria[this->window_number] = this->sort_criteria; this->engines[1].ForceRebuild(); this->SetDirty(); } break; case WID_RV_TRAIN_RAILTYPE_DROPDOWN: { RailType temp = (RailType)index; if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything sel_railtype = temp; /* Reset scrollbar positions */ this->vscroll[0]->SetPosition(0); this->vscroll[1]->SetPosition(0); /* Rebuild the lists */ this->engines[0].ForceRebuild(); this->engines[1].ForceRebuild(); this->reset_sel_engine = true; this->SetDirty(); break; } case WID_RV_START_REPLACE: this->ReplaceClick_StartReplace(index != 0); break; } } virtual void OnResize() { this->vscroll[0]->SetCapacityFromWidget(this, WID_RV_LEFT_MATRIX); this->vscroll[1]->SetCapacityFromWidget(this, WID_RV_RIGHT_MATRIX); } /** * 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 (data != 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->engines[0].ForceRebuild(); } else { this->engines[1].ForceRebuild(); } } }; static const NWidgetPart _nested_replace_rail_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_VEHICLES_IN_USE, STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES, STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_RV_SHOW_HIDDEN_ENGINES), SetDataTip(STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN, STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(150, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_TOGGLE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_ENGINE_WAGON_SELECT, STR_REPLACE_ENGINE_WAGON_SELECT_HELP), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_LEFT), SetMinimalSize(15, 12), EndContainer(), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_TRAIN_RAILTYPE_DROPDOWN), SetMinimalSize(136, 12), SetDataTip(0x0, STR_REPLACE_HELP_RAILTYPE), SetResize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_TRAIN_FLUFF_RIGHT), SetMinimalSize(16, 12), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_WAGONREMOVE_TOGGLE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_REMOVE_WAGON, STR_REPLACE_REMOVE_WAGON_HELP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; static WindowDesc _replace_rail_vehicle_desc( WDP_AUTO, "replace_vehicle_train", 500, 140, WC_REPLACE_VEHICLE, WC_NONE, WDF_CONSTRUCTION, _nested_replace_rail_vehicle_widgets, lengthof(_nested_replace_rail_vehicle_widgets) ); static const NWidgetPart _nested_replace_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_RV_CAPTION), SetMinimalSize(433, 14), SetDataTip(STR_REPLACE_VEHICLES_WHITE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_VEHICLES_IN_USE, STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES, STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP), SetFill(1, 1), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_RV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_RV_SHOW_HIDDEN_ENGINES), SetDataTip(STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN, STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_LEFT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_LEFT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_LEFT_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_LEFT_SCROLLBAR), NWidget(WWT_MATRIX, COLOUR_GREY, WID_RV_RIGHT_MATRIX), SetMinimalSize(216, 0), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_REPLACE_HELP_RIGHT_ARRAY), SetResize(1, 1), SetScrollbar(WID_RV_RIGHT_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_RV_RIGHT_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON), NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; static WindowDesc _replace_vehicle_desc( WDP_AUTO, "replace_vehicle", 456, 118, WC_REPLACE_VEHICLE, WC_NONE, WDF_CONSTRUCTION, _nested_replace_vehicle_widgets, lengthof(_nested_replace_vehicle_widgets) ); /** * Show the autoreplace configuration window for a particular group. * @param id_g The group to replace the vehicles for. * @param vehicletype The type of vehicles in the group. */ void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype) { DeleteWindowById(WC_REPLACE_VEHICLE, vehicletype); new ReplaceVehicleWindow(vehicletype == VEH_TRAIN ? &_replace_rail_vehicle_desc : &_replace_vehicle_desc, vehicletype, id_g); } openttd-1.5.3/src/error_gui.cpp0000644000000000000000000003727612627373442015214 0ustar rootroot/* $Id: error_gui.cpp 27349 2015-07-30 18:48:25Z frosch $ */ /* * 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 error_gui.cpp GUI related to errors. */ #include "stdafx.h" #include "landscape.h" #include "newgrf_text.h" #include "error.h" #include "viewport_func.h" #include "gfx_func.h" #include "string_func.h" #include "company_base.h" #include "company_manager_face.h" #include "strings_func.h" #include "zoom_func.h" #include "window_func.h" #include "console_func.h" #include "window_gui.h" #include "widgets/error_widget.h" #include "table/strings.h" #include #include "safeguards.h" static const NWidgetPart _nested_errmsg_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_RED), NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_RED), NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_MESSAGE), SetPadding(0, 2, 0, 2), SetMinimalSize(236, 32), EndContainer(), }; static WindowDesc _errmsg_desc( WDP_MANUAL, "error", 0, 0, WC_ERRMSG, WC_NONE, 0, _nested_errmsg_widgets, lengthof(_nested_errmsg_widgets) ); static const NWidgetPart _nested_errmsg_face_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_RED), NWidget(WWT_CAPTION, COLOUR_RED, WID_EM_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_RED), NWidget(NWID_HORIZONTAL), SetPIP(2, 1, 2), NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_FACE), SetMinimalSize(92, 119), SetFill(0, 1), SetPadding(2, 0, 1, 0), NWidget(WWT_EMPTY, COLOUR_RED, WID_EM_MESSAGE), SetFill(0, 1), SetMinimalSize(238, 123), EndContainer(), EndContainer(), }; static WindowDesc _errmsg_face_desc( WDP_MANUAL, "error_face", 0, 0, WC_ERRMSG, WC_NONE, 0, _nested_errmsg_face_widgets, lengthof(_nested_errmsg_face_widgets) ); /** * Copy the given data into our instance. * @param data The data to copy. */ ErrorMessageData::ErrorMessageData(const ErrorMessageData &data) { *this = data; for (size_t i = 0; i < lengthof(this->strings); i++) { if (this->strings[i] != NULL) { this->strings[i] = stredup(this->strings[i]); this->decode_params[i] = (size_t)this->strings[i]; } } } /** Free all the strings. */ ErrorMessageData::~ErrorMessageData() { for (size_t i = 0; i < lengthof(this->strings); i++) free(this->strings[i]); } /** * Display an error message in a window. * @param summary_msg General error message showed in first line. Must be valid. * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. * @param duration The amount of time to show this error message. * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param textref_stack_grffile NewGRF that provides the #TextRefStack for the error message. * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. * @param textref_stack Values to put on the #TextRefStack. */ ErrorMessageData::ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) : duration(duration), textref_stack_grffile(textref_stack_grffile), textref_stack_size(textref_stack_size), summary_msg(summary_msg), detailed_msg(detailed_msg), face(INVALID_COMPANY) { this->position.x = x; this->position.y = y; memset(this->decode_params, 0, sizeof(this->decode_params)); memset(this->strings, 0, sizeof(this->strings)); if (textref_stack_size > 0) MemCpyT(this->textref_stack, textref_stack, textref_stack_size); assert(summary_msg != INVALID_STRING_ID); } /** * Copy error parameters from current DParams. */ void ErrorMessageData::CopyOutDParams() { /* Reset parameters */ for (size_t i = 0; i < lengthof(this->strings); i++) free(this->strings[i]); memset(this->decode_params, 0, sizeof(this->decode_params)); memset(this->strings, 0, sizeof(this->strings)); /* Get parameters using type information */ if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); CopyOutDParam(this->decode_params, this->strings, this->detailed_msg == INVALID_STRING_ID ? this->summary_msg : this->detailed_msg, lengthof(this->decode_params)); if (this->textref_stack_size > 0) StopTextRefStackUsage(); if (this->detailed_msg == STR_ERROR_OWNED_BY) { CompanyID company = (CompanyID)GetDParamX(this->decode_params, 2); if (company < MAX_COMPANIES) face = company; } } /** * Set a error string parameter. * @param n Parameter index * @param v Parameter value */ void ErrorMessageData::SetDParam(uint n, uint64 v) { this->decode_params[n] = v; } /** * Set a rawstring parameter. * @param n Parameter index * @param str Raw string */ void ErrorMessageData::SetDParamStr(uint n, const char *str) { free(this->strings[n]); this->strings[n] = stredup(str); } /** Define a queue with errors. */ typedef std::list ErrorList; /** The actual queue with errors. */ ErrorList _error_list; /** Whether the window system is initialized or not. */ bool _window_system_initialized = false; /** Window class for displaying an error message window. */ struct ErrmsgWindow : public Window, ErrorMessageData { private: uint height_summary; ///< Height of the #summary_msg string in pixels in the #WID_EM_MESSAGE widget. uint height_detailed; ///< Height of the #detailed_msg string in pixels in the #WID_EM_MESSAGE widget. public: ErrmsgWindow(const ErrorMessageData &data) : Window(data.HasFace() ? &_errmsg_face_desc : &_errmsg_desc), ErrorMessageData(data) { this->InitNested(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_EM_MESSAGE: { CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); int text_width = max(0, (int)size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); this->height_summary = GetStringHeight(this->summary_msg, text_width); this->height_detailed = (this->detailed_msg == INVALID_STRING_ID) ? 0 : GetStringHeight(this->detailed_msg, text_width); if (this->textref_stack_size > 0) StopTextRefStackUsage(); uint panel_height = WD_FRAMERECT_TOP + this->height_summary + WD_FRAMERECT_BOTTOM; if (this->detailed_msg != INVALID_STRING_ID) panel_height += this->height_detailed + WD_PAR_VSEP_WIDE; size->height = max(size->height, panel_height); break; } case WID_EM_FACE: { Dimension face_size = GetSpriteSize(SPR_GRADIENT); size->width = max(size->width, face_size.width); size->height = max(size->height, face_size.height); break; } } } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { /* Position (0, 0) given, center the window. */ if (this->position.x == 0 && this->position.y == 0) { Point pt = {(_screen.width - sm_width) >> 1, (_screen.height - sm_height) >> 1}; return pt; } /* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom. * Add a fixed distance 20 to make it less cluttered. */ int scr_top = GetMainViewTop() + 20; int scr_bot = GetMainViewBottom() - 20; Point pt = RemapCoords2(this->position.x, this->position.y); const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport; if (this->face == INVALID_COMPANY) { /* move x pos to opposite corner */ pt.x = UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left; pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - sm_width - 20 : 20; // Stay 20 pixels away from the edge of the screen. /* move y pos to opposite corner */ pt.y = UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top; pt.y = (pt.y < (_screen.height >> 1)) ? scr_bot - sm_height : scr_top; } else { pt.x = Clamp(UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left - (sm_width / 2), 0, _screen.width - sm_width); pt.y = Clamp(UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top - (sm_height / 2), scr_top, scr_bot - sm_height); } return pt; } /** * 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 company gets shut down, while displaying an error about it, remove the error message. */ if (this->face != INVALID_COMPANY && !Company::IsValidID(this->face)) delete this; } virtual void SetStringParameters(int widget) const { if (widget == WID_EM_CAPTION) CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_EM_FACE: { const Company *c = Company::Get(this->face); DrawCompanyManagerFace(c->face, c->colour, r.left, r.top); break; } case WID_EM_MESSAGE: CopyInDParam(0, this->decode_params, lengthof(this->decode_params)); if (this->textref_stack_size > 0) StartTextRefStackUsage(this->textref_stack_grffile, this->textref_stack_size, this->textref_stack); if (this->detailed_msg == INVALID_STRING_ID) { DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->summary_msg, TC_FROMSTRING, SA_CENTER); } else { int extra = (r.bottom - r.top + 1 - this->height_summary - this->height_detailed - WD_PAR_VSEP_WIDE) / 2; /* Note: NewGRF supplied error message often do not start with a colour code, so default to white. */ int top = r.top + WD_FRAMERECT_TOP; int bottom = top + this->height_summary + extra; DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->summary_msg, TC_WHITE, SA_CENTER); bottom = r.bottom - WD_FRAMERECT_BOTTOM; top = bottom - this->height_detailed - extra; DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, top, bottom, this->detailed_msg, TC_WHITE, SA_CENTER); } if (this->textref_stack_size > 0) StopTextRefStackUsage(); break; default: break; } } virtual void OnMouseLoop() { /* Disallow closing the window too easily, if timeout is disabled */ if (_right_button_down && this->duration != 0) delete this; } virtual void OnHundredthTick() { /* Timeout enabled? */ if (this->duration != 0) { this->duration--; if (this->duration == 0) delete this; } } ~ErrmsgWindow() { SetRedErrorSquare(INVALID_TILE); if (_window_system_initialized) ShowFirstError(); } virtual EventState OnKeyPress(WChar key, uint16 keycode) { if (keycode != WKC_SPACE) return ES_NOT_HANDLED; delete this; return ES_HANDLED; } /** * Check whether the currently shown error message was critical or not. * @return True iff the message was critical. */ bool IsCritical() { return this->duration == 0; } }; /** * Clear all errors from the queue. */ void ClearErrorMessages() { UnshowCriticalError(); _error_list.clear(); } /** Show the first error of the queue. */ void ShowFirstError() { _window_system_initialized = true; if (!_error_list.empty()) { new ErrmsgWindow(_error_list.front()); _error_list.pop_front(); } } /** * Unshow the critical error. This has to happen when a critical * error is shown and we uninitialise the window system, i.e. * remove all the windows. */ void UnshowCriticalError() { ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); if (_window_system_initialized && w != NULL) { if (w->IsCritical()) _error_list.push_front(*w); _window_system_initialized = false; delete w; } } /** * Display an error message in a window. * @param summary_msg General error message showed in first line. Must be valid. * @param detailed_msg Detailed error message showed in second line. Can be INVALID_STRING_ID. * @param wl Message severity. * @param x World X position (TileVirtX) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param y World Y position (TileVirtY) of the error location. Set both x and y to 0 to just center the message when there is no related error tile. * @param textref_stack_grffile NewGRF providing the #TextRefStack for the error message. * @param textref_stack_size Number of uint32 values to put on the #TextRefStack for the error message; 0 if the #TextRefStack shall not be used. * @param textref_stack Values to put on the #TextRefStack. */ void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x, int y, const GRFFile *textref_stack_grffile, uint textref_stack_size, const uint32 *textref_stack) { assert(textref_stack_size == 0 || (textref_stack_grffile != NULL && textref_stack != NULL)); if (summary_msg == STR_NULL) summary_msg = STR_EMPTY; if (wl != WL_INFO) { /* Print message to console */ char buf[DRAW_STRING_BUFFER]; if (textref_stack_size > 0) StartTextRefStackUsage(textref_stack_grffile, textref_stack_size, textref_stack); char *b = GetString(buf, summary_msg, lastof(buf)); if (detailed_msg != INVALID_STRING_ID) { b += seprintf(b, lastof(buf), " "); GetString(b, detailed_msg, lastof(buf)); } if (textref_stack_size > 0) StopTextRefStackUsage(); switch (wl) { case WL_WARNING: IConsolePrint(CC_WARNING, buf); break; default: IConsoleError(buf); break; } } bool no_timeout = wl == WL_CRITICAL; if (_settings_client.gui.errmsg_duration == 0 && !no_timeout) return; ErrorMessageData data(summary_msg, detailed_msg, no_timeout ? 0 : _settings_client.gui.errmsg_duration, x, y, textref_stack_grffile, textref_stack_size, textref_stack); data.CopyOutDParams(); ErrmsgWindow *w = (ErrmsgWindow*)FindWindowById(WC_ERRMSG, 0); if (w != NULL && w->IsCritical()) { /* A critical error is currently shown. */ if (wl == WL_CRITICAL) { /* Push another critical error in the queue of errors, * but do not put other errors in the queue. */ _error_list.push_back(data); } } else { /* Nothing or a non-critical error was shown. */ delete w; new ErrmsgWindow(data); } } /** * Schedule a list of errors. * Note: This does not try to display the error now. This is useful if the window system is not yet running. * @param data Error message datas; cleared afterwards */ void ScheduleErrorMessage(ErrorList &datas) { _error_list.splice(_error_list.end(), datas); } /** * Schedule an error. * Note: This does not try to display the error now. This is useful if the window system is not yet running. * @param data Error message data; cleared afterwards */ void ScheduleErrorMessage(const ErrorMessageData &data) { _error_list.push_back(data); } openttd-1.5.3/src/depot_cmd.cpp0000644000000000000000000000475312627373435015151 0ustar rootroot/* $Id: depot_cmd.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 depot_cmd.cpp %Command Handling for depots. */ #include "stdafx.h" #include "command_func.h" #include "depot_base.h" #include "company_func.h" #include "string_func.h" #include "town.h" #include "vehicle_gui.h" #include "vehiclelist.h" #include "window_func.h" #include "table/strings.h" #include "safeguards.h" /** * Check whether the given name is globally unique amongst depots. * @param name The name to check. * @return True if there is no depot with the given name. */ static bool IsUniqueDepotName(const char *name) { const Depot *d; FOR_ALL_DEPOTS(d) { if (d->name != NULL && strcmp(d->name, name) == 0) return false; } return true; } /** * Rename a depot. * @param tile unused * @param flags type of operation * @param p1 id of depot * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Depot *d = Depot::GetIfValid(p1); if (d == NULL) return CMD_ERROR; CommandCost ret = CheckTileOwnership(d->xy); if (ret.Failed()) return ret; bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_DEPOT_NAME_CHARS) return CMD_ERROR; if (!IsUniqueDepotName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { free(d->name); if (reset) { d->name = NULL; MakeDefaultName(d); } else { d->name = stredup(text); } /* Update the orders and depot */ SetWindowClassesDirty(WC_VEHICLE_ORDERS); SetWindowDirty(WC_VEHICLE_DEPOT, d->xy); /* Update the depot list */ VehicleType vt = GetDepotVehicleType(d->xy); SetWindowDirty(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_DEPOT_LIST, vt, GetTileOwner(d->xy), d->index).Pack()); } return CommandCost(); } openttd-1.5.3/src/newgrf_commons.cpp0000644000000000000000000007006312627373446016235 0ustar rootroot/* $Id: newgrf_commons.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_commons.cpp Implementation of the class %OverrideManagerBase * and its descendance, present and future. */ #include "stdafx.h" #include "debug.h" #include "landscape.h" #include "house.h" #include "industrytype.h" #include "newgrf_config.h" #include "clear_map.h" #include "station_map.h" #include "tree_map.h" #include "tunnelbridge_map.h" #include "newgrf_object.h" #include "genworld.h" #include "newgrf_spritegroup.h" #include "newgrf_text.h" #include "company_base.h" #include "error.h" #include "strings_func.h" #include "table/strings.h" #include "safeguards.h" /** * Constructor of generic class * @param offset end of original data for this entity. i.e: houses = 110 * @param maximum of entities this manager can deal with. i.e: houses = 512 * @param invalid is the ID used to identify an invalid entity id */ OverrideManagerBase::OverrideManagerBase(uint16 offset, uint16 maximum, uint16 invalid) { max_offset = offset; max_new_entities = maximum; invalid_ID = invalid; mapping_ID = CallocT(max_new_entities); entity_overrides = MallocT(max_offset); for (size_t i = 0; i < max_offset; i++) entity_overrides[i] = invalid; grfid_overrides = CallocT(max_offset); } /** * Destructor of the generic class. * Frees allocated memory of constructor */ OverrideManagerBase::~OverrideManagerBase() { free(mapping_ID); free(entity_overrides); free(grfid_overrides); } /** * Since the entity IDs defined by the GRF file does not necessarily correlate * to those used by the game, the IDs used for overriding old entities must be * translated when the entity spec is set. * @param local_id ID in grf file * @param grfid ID of the grf file * @param entity_type original entity type */ void OverrideManagerBase::Add(uint8 local_id, uint32 grfid, uint entity_type) { assert(entity_type < max_offset); /* An override can be set only once */ if (entity_overrides[entity_type] != invalid_ID) return; entity_overrides[entity_type] = local_id; grfid_overrides[entity_type] = grfid; } /** Resets the mapping, which is used while initializing game */ void OverrideManagerBase::ResetMapping() { memset(mapping_ID, 0, (max_new_entities - 1) * sizeof(EntityIDMapping)); } /** Resets the override, which is used while initializing game */ void OverrideManagerBase::ResetOverride() { for (uint16 i = 0; i < max_offset; i++) { entity_overrides[i] = invalid_ID; grfid_overrides[i] = 0; } } /** * Return the ID (if ever available) of a previously inserted entity. * @param grf_local_id ID of this entity within the grfID * @param grfid ID of the grf file * @return the ID of the candidate, of the Invalid flag item ID */ uint16 OverrideManagerBase::GetID(uint8 grf_local_id, uint32 grfid) const { const EntityIDMapping *map; for (uint16 id = 0; id < max_new_entities; id++) { map = &mapping_ID[id]; if (map->entity_id == grf_local_id && map->grfid == grfid) { return id; } } return invalid_ID; } /** * Reserves a place in the mapping array for an entity to be installed * @param grf_local_id is an arbitrary id given by the grf's author. Also known as setid * @param grfid is the id of the grf file itself * @param substitute_id is the original entity from which data is copied for the new one * @return the proper usable slot id, or invalid marker if none is found */ uint16 OverrideManagerBase::AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id) { uint16 id = this->GetID(grf_local_id, grfid); EntityIDMapping *map; /* Look to see if this entity has already been added. This is done * separately from the loop below in case a GRF has been deleted, and there * are any gaps in the array. */ if (id != invalid_ID) { return id; } /* This entity hasn't been defined before, so give it an ID now. */ for (id = max_offset; id < max_new_entities; id++) { map = &mapping_ID[id]; if (CheckValidNewID(id) && map->entity_id == 0 && map->grfid == 0) { map->entity_id = grf_local_id; map->grfid = grfid; map->substitute_id = substitute_id; return id; } } return invalid_ID; } /** * Gives the GRFID of the file the entity belongs to. * @param entity_id ID of the entity being queried. * @return GRFID. */ uint32 OverrideManagerBase::GetGRFID(uint16 entity_id) const { return mapping_ID[entity_id].grfid; } /** * Gives the substitute of the entity, as specified by the grf file * @param entity_id of the entity being queried * @return mapped id */ uint16 OverrideManagerBase::GetSubstituteID(uint16 entity_id) const { return mapping_ID[entity_id].substitute_id; } /** * Install the specs into the HouseSpecs array * It will find itself the proper slot on which it will go * @param hs HouseSpec read from the grf file, ready for inclusion */ void HouseOverrideManager::SetEntitySpec(const HouseSpec *hs) { HouseID house_id = this->AddEntityID(hs->grf_prop.local_id, hs->grf_prop.grffile->grfid, hs->grf_prop.subst_id); if (house_id == invalid_ID) { grfmsg(1, "House.SetEntitySpec: Too many houses allocated. Ignoring."); return; } MemCpyT(HouseSpec::Get(house_id), hs); /* Now add the overrides. */ for (int i = 0; i != max_offset; i++) { HouseSpec *overridden_hs = HouseSpec::Get(i); if (entity_overrides[i] != hs->grf_prop.local_id || grfid_overrides[i] != hs->grf_prop.grffile->grfid) continue; overridden_hs->grf_prop.override = house_id; entity_overrides[i] = invalid_ID; grfid_overrides[i] = 0; } } /** * Return the ID (if ever available) of a previously inserted entity. * @param grf_local_id ID of this entity within the grfID * @param grfid ID of the grf file * @return the ID of the candidate, of the Invalid flag item ID */ uint16 IndustryOverrideManager::GetID(uint8 grf_local_id, uint32 grfid) const { uint16 id = OverrideManagerBase::GetID(grf_local_id, grfid); if (id != invalid_ID) return id; /* No mapping found, try the overrides */ for (id = 0; id < max_offset; id++) { if (entity_overrides[id] == grf_local_id && grfid_overrides[id] == grfid) return id; } return invalid_ID; } /** * Method to find an entity ID and to mark it as reserved for the Industry to be included. * @param grf_local_id ID used by the grf file for pre-installation work (equivalent of TTDPatch's setid * @param grfid ID of the current grf file * @param substitute_id industry from which data has been copied * @return a free entity id (slotid) if ever one has been found, or Invalid_ID marker otherwise */ uint16 IndustryOverrideManager::AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id) { /* This entity hasn't been defined before, so give it an ID now. */ for (uint16 id = 0; id < max_new_entities; id++) { /* Skip overridden industries */ if (id < max_offset && entity_overrides[id] != invalid_ID) continue; /* Get the real live industry */ const IndustrySpec *inds = GetIndustrySpec(id); /* This industry must be one that is not available(enabled), mostly because of climate. * And it must not already be used by a grf (grffile == NULL). * So reserve this slot here, as it is the chosen one */ if (!inds->enabled && inds->grf_prop.grffile == NULL) { EntityIDMapping *map = &mapping_ID[id]; if (map->entity_id == 0 && map->grfid == 0) { /* winning slot, mark it as been used */ map->entity_id = grf_local_id; map->grfid = grfid; map->substitute_id = substitute_id; return id; } } } return invalid_ID; } /** * Method to install the new industry data in its proper slot * The slot assignment is internal of this method, since it requires * checking what is available * @param inds Industryspec that comes from the grf decoding process */ void IndustryOverrideManager::SetEntitySpec(IndustrySpec *inds) { /* First step : We need to find if this industry is already specified in the savegame data. */ IndustryType ind_id = this->GetID(inds->grf_prop.local_id, inds->grf_prop.grffile->grfid); if (ind_id == invalid_ID) { /* Not found. * Or it has already been overridden, so you've lost your place old boy. * Or it is a simple substitute. * We need to find a free available slot */ ind_id = this->AddEntityID(inds->grf_prop.local_id, inds->grf_prop.grffile->grfid, inds->grf_prop.subst_id); inds->grf_prop.override = invalid_ID; // make sure it will not be detected as overridden } if (ind_id == invalid_ID) { grfmsg(1, "Industry.SetEntitySpec: Too many industries allocated. Ignoring."); return; } /* Now that we know we can use the given id, copy the spec to its final destination... */ memcpy(&_industry_specs[ind_id], inds, sizeof(*inds)); /* ... and mark it as usable*/ _industry_specs[ind_id].enabled = true; } void IndustryTileOverrideManager::SetEntitySpec(const IndustryTileSpec *its) { IndustryGfx indt_id = this->AddEntityID(its->grf_prop.local_id, its->grf_prop.grffile->grfid, its->grf_prop.subst_id); if (indt_id == invalid_ID) { grfmsg(1, "IndustryTile.SetEntitySpec: Too many industry tiles allocated. Ignoring."); return; } memcpy(&_industry_tile_specs[indt_id], its, sizeof(*its)); /* Now add the overrides. */ for (int i = 0; i < max_offset; i++) { IndustryTileSpec *overridden_its = &_industry_tile_specs[i]; if (entity_overrides[i] != its->grf_prop.local_id || grfid_overrides[i] != its->grf_prop.grffile->grfid) continue; overridden_its->grf_prop.override = indt_id; overridden_its->enabled = false; entity_overrides[i] = invalid_ID; grfid_overrides[i] = 0; } } /** * Method to install the new object data in its proper slot * The slot assignment is internal of this method, since it requires * checking what is available * @param spec ObjectSpec that comes from the grf decoding process */ void ObjectOverrideManager::SetEntitySpec(ObjectSpec *spec) { /* First step : We need to find if this object is already specified in the savegame data. */ ObjectType type = this->GetID(spec->grf_prop.local_id, spec->grf_prop.grffile->grfid); if (type == invalid_ID) { /* Not found. * Or it has already been overridden, so you've lost your place old boy. * Or it is a simple substitute. * We need to find a free available slot */ type = this->AddEntityID(spec->grf_prop.local_id, spec->grf_prop.grffile->grfid, OBJECT_TRANSMITTER); } if (type == invalid_ID) { grfmsg(1, "Object.SetEntitySpec: Too many objects allocated. Ignoring."); return; } extern ObjectSpec _object_specs[NUM_OBJECTS]; /* Now that we know we can use the given id, copy the spec to its final destination. */ memcpy(&_object_specs[type], spec, sizeof(*spec)); ObjectClass::Assign(&_object_specs[type]); } /** * Function used by houses (and soon industries) to get information * on type of "terrain" the tile it is queries sits on. * @param tile TileIndex of the tile been queried * @param context The context of the tile. * @return value corresponding to the grf expected format: * Terrain type: 0 normal, 1 desert, 2 rainforest, 4 on or above snowline */ uint32 GetTerrainType(TileIndex tile, TileContext context) { switch (_settings_game.game_creation.landscape) { case LT_TROPIC: return GetTropicZone(tile); case LT_ARCTIC: { bool has_snow; switch (GetTileType(tile)) { case MP_CLEAR: /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */ if (_generating_world) goto genworld; has_snow = IsSnowTile(tile) && GetClearDensity(tile) >= 2; break; case MP_RAILWAY: { /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */ if (_generating_world) goto genworld; // we do not care about foundations here RailGroundType ground = GetRailGroundType(tile); has_snow = (ground == RAIL_GROUND_ICE_DESERT || (context == TCX_UPPER_HALFTILE && ground == RAIL_GROUND_HALF_SNOW)); break; } case MP_ROAD: /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */ if (_generating_world) goto genworld; // we do not care about foundations here has_snow = IsOnSnow(tile); break; case MP_TREES: { /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */ if (_generating_world) goto genworld; TreeGround ground = GetTreeGround(tile); has_snow = (ground == TREE_GROUND_SNOW_DESERT || ground == TREE_GROUND_ROUGH_SNOW) && GetTreeDensity(tile) >= 2; break; } case MP_TUNNELBRIDGE: if (context == TCX_ON_BRIDGE) { has_snow = (GetBridgeHeight(tile) > GetSnowLine()); } else { /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */ if (_generating_world) goto genworld; // we do not care about foundations here has_snow = HasTunnelBridgeSnowOrDesert(tile); } break; case MP_STATION: case MP_HOUSE: case MP_INDUSTRY: case MP_OBJECT: /* These tiles usually have a levelling foundation. So use max Z */ has_snow = (GetTileMaxZ(tile) > GetSnowLine()); break; case MP_VOID: case MP_WATER: genworld: has_snow = (GetTileZ(tile) > GetSnowLine()); break; default: NOT_REACHED(); } return has_snow ? 4 : 0; } default: return 0; } } /** * Get the tile at the given offset. * @param parameter The NewGRF "encoded" offset. * @param tile The tile to base the offset from. * @param signed_offsets Whether the offsets are to be interpreted as signed or not. * @param axis Axis of a railways station. * @return The tile at the offset. */ TileIndex GetNearbyTile(byte parameter, TileIndex tile, bool signed_offsets, Axis axis) { int8 x = GB(parameter, 0, 4); int8 y = GB(parameter, 4, 4); if (signed_offsets && x >= 8) x -= 16; if (signed_offsets && y >= 8) y -= 16; /* Swap width and height depending on axis for railway stations */ if (axis == INVALID_AXIS && HasStationTileRail(tile)) axis = GetRailStationAxis(tile); if (axis == AXIS_Y) Swap(x, y); /* Make sure we never roam outside of the map, better wrap in that case */ return TILE_MASK(tile + TileDiffXY(x, y)); } /** * Common part of station var 0x67, house var 0x62, indtile var 0x60, industry var 0x62. * * @param tile the tile of interest. * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8. * @return 0czzbbss: c = TileType; zz = TileZ; bb: 7-3 zero, 4-2 TerrainType, 1 water/shore, 0 zero; ss = TileSlope */ uint32 GetNearbyTileInformation(TileIndex tile, bool grf_version8) { TileType tile_type = GetTileType(tile); /* Fake tile type for trees on shore */ if (IsTileType(tile, MP_TREES) && GetTreeGround(tile) == TREE_GROUND_SHORE) tile_type = MP_WATER; int z; Slope tileh = GetTilePixelSlope(tile, &z); /* Return 0 if the tile is a land tile */ byte terrain_type = (HasTileWaterClass(tile) ? (GetWaterClass(tile) + 1) & 3 : 0) << 5 | GetTerrainType(tile) << 2 | (tile_type == MP_WATER ? 1 : 0) << 1; if (grf_version8) z /= TILE_HEIGHT; return tile_type << 24 | Clamp(z, 0, 0xFF) << 16 | terrain_type << 8 | tileh; } /** * Returns company information like in vehicle var 43 or station var 43. * @param owner Owner of the object. * @param l Livery of the object; NULL to use default. * @return NewGRF company information. */ uint32 GetCompanyInfo(CompanyID owner, const Livery *l) { if (l == NULL && Company::IsValidID(owner)) l = &Company::Get(owner)->livery[LS_DEFAULT]; return owner | (Company::IsValidAiID(owner) ? 0x10000 : 0) | (l != NULL ? (l->colour1 << 24) | (l->colour2 << 28) : 0); } /** * Get the error message from a shape/location/slope check callback result. * @param cb_res Callback result to translate. If bit 10 is set this is a standard error message, otherwise a NewGRF provided string. * @param grffile NewGRF to use to resolve a custom error message. * @param default_error Error message to use for the generic error. * @return CommandCost indicating success or the error message. */ CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, const GRFFile *grffile, StringID default_error) { CommandCost res; if (cb_res < 0x400) { res = CommandCost(GetGRFStringID(grffile->grfid, 0xD000 + cb_res)); } else { switch (cb_res) { case 0x400: return res; // No error. default: // unknown reason -> default error case 0x401: res = CommandCost(default_error); break; case 0x402: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST); break; case 0x403: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT); break; case 0x404: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE); break; case 0x405: res = CommandCost(STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE); break; case 0x406: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_SEA); break; case 0x407: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_CANAL); break; case 0x408: res = CommandCost(STR_ERROR_CAN_T_BUILD_ON_RIVER); break; } } /* Copy some parameters from the registers to the error message text ref. stack */ res.UseTextRefStack(grffile, 4); return res; } /** * Record that a NewGRF returned an unknown/invalid callback result. * Also show an error to the user. * @param grfid ID of the NewGRF causing the problem. * @param cbid Callback causing the problem. * @param cb_res Invalid result returned by the callback. */ void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res) { GRFConfig *grfconfig = GetGRFConfig(grfid); if (!HasBit(grfconfig->grf_bugs, GBUG_UNKNOWN_CB_RESULT)) { SetBit(grfconfig->grf_bugs, GBUG_UNKNOWN_CB_RESULT); SetDParamStr(0, grfconfig->GetName()); SetDParam(1, cbid); SetDParam(2, cb_res); ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, WL_CRITICAL); } /* debug output */ char buffer[512]; SetDParamStr(0, grfconfig->GetName()); GetString(buffer, STR_NEWGRF_BUGGY, lastof(buffer)); DEBUG(grf, 0, "%s", buffer + 3); SetDParam(1, cbid); SetDParam(2, cb_res); GetString(buffer, STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT, lastof(buffer)); DEBUG(grf, 0, "%s", buffer + 3); } /** * Converts a callback result into a boolean. * For grf version < 8 the result is checked for zero or non-zero. * For grf version >= 8 the callback result must be 0 or 1. * @param grffile NewGRF returning the value. * @param cbid Callback returning the value. * @param cb_res Callback result. * @return Boolean value. True if cb_res != 0. */ bool ConvertBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_res) { assert(cb_res != CALLBACK_FAILED); // We do not know what to return if (grffile->grf_version < 8) return cb_res != 0; if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res); return cb_res != 0; } /** * Converts a callback result into a boolean. * For grf version < 8 the first 8 bit of the result are checked for zero or non-zero. * For grf version >= 8 the callback result must be 0 or 1. * @param grffile NewGRF returning the value. * @param cbid Callback returning the value. * @param cb_res Callback result. * @return Boolean value. True if cb_res != 0. */ bool Convert8bitBooleanCallback(const GRFFile *grffile, uint16 cbid, uint16 cb_res) { assert(cb_res != CALLBACK_FAILED); // We do not know what to return if (grffile->grf_version < 8) return GB(cb_res, 0, 8) != 0; if (cb_res > 1) ErrorUnknownCallbackResult(grffile->grfid, cbid, cb_res); return cb_res != 0; } /* static */ SmallVector NewGRFSpriteLayout::result_seq; /** * Clone the building sprites of a spritelayout. * @param source The building sprites to copy. */ void NewGRFSpriteLayout::Clone(const DrawTileSeqStruct *source) { assert(this->seq == NULL); assert(source != NULL); size_t count = 1; // 1 for the terminator const DrawTileSeqStruct *element; foreach_draw_tile_seq(element, source) count++; DrawTileSeqStruct *sprites = MallocT(count); MemCpyT(sprites, source, count); this->seq = sprites; } /** * Clone a spritelayout. * @param source The spritelayout to copy. */ void NewGRFSpriteLayout::Clone(const NewGRFSpriteLayout *source) { this->Clone((const DrawTileSprites*)source); if (source->registers != NULL) { size_t count = 1; // 1 for the ground sprite const DrawTileSeqStruct *element; foreach_draw_tile_seq(element, source->seq) count++; TileLayoutRegisters *regs = MallocT(count); MemCpyT(regs, source->registers, count); this->registers = regs; } } /** * Allocate a spritelayout for \a num_sprites building sprites. * @param num_sprites Number of building sprites to allocate memory for. (not counting the terminator) */ void NewGRFSpriteLayout::Allocate(uint num_sprites) { assert(this->seq == NULL); DrawTileSeqStruct *sprites = CallocT(num_sprites + 1); sprites[num_sprites].MakeTerminator(); this->seq = sprites; } /** * Allocate memory for register modifiers. */ void NewGRFSpriteLayout::AllocateRegisters() { assert(this->seq != NULL); assert(this->registers == NULL); size_t count = 1; // 1 for the ground sprite const DrawTileSeqStruct *element; foreach_draw_tile_seq(element, this->seq) count++; this->registers = CallocT(count); } /** * Prepares a sprite layout before resolving action-1-2-3 chains. * Integrates offsets into the layout and determines which chains to resolve. * @note The function uses statically allocated temporary storage, which is reused everytime when calling the function. * That means, you have to use the sprite layout before calling #PrepareLayout() the next time. * @param orig_offset Offset to apply to non-action-1 sprites. * @param newgrf_ground_offset Offset to apply to action-1 ground sprites. * @param newgrf_offset Offset to apply to action-1 non-ground sprites. * @param constr_stage Construction stage (0-3) to apply to all action-1 sprites. * @param separate_ground Whether the ground sprite shall be resolved by a separate action-1-2-3 chain by default. * @return Bitmask of values for variable 10 to resolve action-1-2-3 chains for. */ uint32 NewGRFSpriteLayout::PrepareLayout(uint32 orig_offset, uint32 newgrf_ground_offset, uint32 newgrf_offset, uint constr_stage, bool separate_ground) const { result_seq.Clear(); uint32 var10_values = 0; /* Create a copy of the spritelayout, so we can modify some values. * Also include the groundsprite into the sequence for easier processing. */ DrawTileSeqStruct *result = result_seq.Append(); result->image = ground; result->delta_x = 0; result->delta_y = 0; result->delta_z = (int8)0x80; const DrawTileSeqStruct *dtss; foreach_draw_tile_seq(dtss, this->seq) { *result_seq.Append() = *dtss; } result_seq.Append()->MakeTerminator(); /* Determine the var10 values the action-1-2-3 chains needs to be resolved for, * and apply the default sprite offsets (unless disabled). */ const TileLayoutRegisters *regs = this->registers; bool ground = true; foreach_draw_tile_seq(result, result_seq.Begin()) { TileLayoutFlags flags = TLF_NOTHING; if (regs != NULL) flags = regs->flags; /* Record var10 value for the sprite */ if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) { uint8 var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0); SetBit(var10_values, var10); } /* Add default sprite offset, unless there is a custom one */ if (!(flags & TLF_SPRITE)) { if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) { result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset; if (constr_stage > 0 && regs != NULL) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_sprite_offset); } else { result->image.sprite += orig_offset; } } /* Record var10 value for the palette */ if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS)) { uint8 var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0); SetBit(var10_values, var10); } /* Add default palette offset, unless there is a custom one */ if (!(flags & TLF_PALETTE)) { if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) { result->image.sprite += ground ? newgrf_ground_offset : newgrf_offset; if (constr_stage > 0 && regs != NULL) result->image.sprite += GetConstructionStageOffset(constr_stage, regs->max_palette_offset); } } ground = false; if (regs != NULL) regs++; } return var10_values; } /** * Evaluates the register modifiers and integrates them into the preprocessed sprite layout. * @pre #PrepareLayout() needs calling first. * @param resolved_var10 The value of var10 the action-1-2-3 chain was evaluated for. * @param resolved_sprite Result sprite of the action-1-2-3 chain. * @param separate_ground Whether the ground sprite is resolved by a separate action-1-2-3 chain. * @return Resulting spritelayout after processing the registers. */ void NewGRFSpriteLayout::ProcessRegisters(uint8 resolved_var10, uint32 resolved_sprite, bool separate_ground) const { DrawTileSeqStruct *result; const TileLayoutRegisters *regs = this->registers; bool ground = true; foreach_draw_tile_seq(result, result_seq.Begin()) { TileLayoutFlags flags = TLF_NOTHING; if (regs != NULL) flags = regs->flags; /* Is the sprite or bounding box affected by an action-1-2-3 chain? */ if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_SPRITE_REG_FLAGS)) { /* Does the var10 value apply to this sprite? */ uint8 var10 = (flags & TLF_SPRITE_VAR10) ? regs->sprite_var10 : (ground && separate_ground ? 1 : 0); if (var10 == resolved_var10) { /* Apply registers */ if ((flags & TLF_DODRAW) && GetRegister(regs->dodraw) == 0) { result->image.sprite = 0; } else { if (HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) result->image.sprite += resolved_sprite; if (flags & TLF_SPRITE) { int16 offset = (int16)GetRegister(regs->sprite); // mask to 16 bits to avoid trouble if (!HasBit(result->image.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE) || (offset >= 0 && offset < regs->max_sprite_offset)) { result->image.sprite += offset; } else { result->image.sprite = SPR_IMG_QUERY; } } if (result->IsParentSprite()) { if (flags & TLF_BB_XY_OFFSET) { result->delta_x += (int32)GetRegister(regs->delta.parent[0]); result->delta_y += (int32)GetRegister(regs->delta.parent[1]); } if (flags & TLF_BB_Z_OFFSET) result->delta_z += (int32)GetRegister(regs->delta.parent[2]); } else { if (flags & TLF_CHILD_X_OFFSET) result->delta_x += (int32)GetRegister(regs->delta.child[0]); if (flags & TLF_CHILD_Y_OFFSET) result->delta_y += (int32)GetRegister(regs->delta.child[1]); } } } } /* Is the palette affected by an action-1-2-3 chain? */ if (result->image.sprite != 0 && (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (flags & TLF_PALETTE_REG_FLAGS))) { /* Does the var10 value apply to this sprite? */ uint8 var10 = (flags & TLF_PALETTE_VAR10) ? regs->palette_var10 : (ground && separate_ground ? 1 : 0); if (var10 == resolved_var10) { /* Apply registers */ if (HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) result->image.pal += resolved_sprite; if (flags & TLF_PALETTE) { int16 offset = (int16)GetRegister(regs->palette); // mask to 16 bits to avoid trouble if (!HasBit(result->image.pal, SPRITE_MODIFIER_CUSTOM_SPRITE) || (offset >= 0 && offset < regs->max_palette_offset)) { result->image.pal += offset; } else { result->image.sprite = SPR_IMG_QUERY; result->image.pal = PAL_NONE; } } } } ground = false; if (regs != NULL) regs++; } } openttd-1.5.3/src/heightmap.cpp0000644000000000000000000003607612627373442015162 0ustar rootroot/* $Id: heightmap.cpp 27044 2014-10-25 22:24:05Z frosch $ */ /* * 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 heightmap.cpp Creating of maps from heightmaps. */ #include "stdafx.h" #include "heightmap.h" #include "clear_map.h" #include "void_map.h" #include "error.h" #include "saveload/saveload.h" #include "bmp.h" #include "gfx_func.h" #include "fios.h" #include "fileio_func.h" #include "table/strings.h" #include "safeguards.h" /** * Convert RGB colours to Grayscale using 29.9% Red, 58.7% Green, 11.4% Blue * (average luminosity formula, NTSC Colour Space) */ static inline byte RGBToGrayscale(byte red, byte green, byte blue) { /* To avoid doubles and stuff, multiply it with a total of 65536 (16bits), then * divide by it to normalize the value to a byte again. */ return ((red * 19595) + (green * 38470) + (blue * 7471)) / 65536; } #ifdef WITH_PNG #include /** * The PNG Heightmap loader. */ static void ReadHeightmapPNGImageData(byte *map, png_structp png_ptr, png_infop info_ptr) { uint x, y; byte gray_palette[256]; png_bytep *row_pointers = NULL; bool has_palette = png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE; uint channels = png_get_channels(png_ptr, info_ptr); /* Get palette and convert it to grayscale */ if (has_palette) { int i; int palette_size; png_color *palette; bool all_gray = true; png_get_PLTE(png_ptr, info_ptr, &palette, &palette_size); for (i = 0; i < palette_size && (palette_size != 16 || all_gray); i++) { all_gray &= palette[i].red == palette[i].green && palette[i].red == palette[i].blue; gray_palette[i] = RGBToGrayscale(palette[i].red, palette[i].green, palette[i].blue); } /** * For a non-gray palette of size 16 we assume that * the order of the palette determines the height; * the first entry is the sea (level 0), the second one * level 1, etc. */ if (palette_size == 16 && !all_gray) { for (i = 0; i < palette_size; i++) { gray_palette[i] = 256 * i / palette_size; } } } row_pointers = png_get_rows(png_ptr, info_ptr); /* Read the raw image data and convert in 8-bit grayscale */ for (x = 0; x < png_get_image_width(png_ptr, info_ptr); x++) { for (y = 0; y < png_get_image_height(png_ptr, info_ptr); y++) { byte *pixel = &map[y * png_get_image_width(png_ptr, info_ptr) + x]; uint x_offset = x * channels; if (has_palette) { *pixel = gray_palette[row_pointers[y][x_offset]]; } else if (channels == 3) { *pixel = RGBToGrayscale(row_pointers[y][x_offset + 0], row_pointers[y][x_offset + 1], row_pointers[y][x_offset + 2]); } else { *pixel = row_pointers[y][x_offset]; } } } } /** * Reads the heightmap and/or size of the heightmap from a PNG file. * If map == NULL only the size of the PNG is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapPNG(char *filename, uint *x, uint *y, byte **map) { FILE *fp; png_structp png_ptr = NULL; png_infop info_ptr = NULL; fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); if (fp == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL || setjmp(png_jmpbuf(png_ptr))) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } png_init_io(png_ptr, fp); /* Allocate memory and read image, without alpha or 16-bit samples * (result is either 8-bit indexed/grayscale or 24-bit RGB) */ png_set_packing(png_ptr); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16, NULL); /* Maps of wrong colour-depth are not used. * (this should have been taken care of by stripping alpha and 16-bit samples on load) */ if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); /* Check if image dimensions don't overflow a size_t to avoid memory corruption. */ if ((uint64)width * height >= (size_t)-1) { ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return false; } if (map != NULL) { *map = MallocT(width * height); ReadHeightmapPNGImageData(*map, png_ptr, info_ptr); } *x = width; *y = height; fclose(fp); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return true; } #endif /* WITH_PNG */ /** * The BMP Heightmap loader. */ static void ReadHeightmapBMPImageData(byte *map, BmpInfo *info, BmpData *data) { uint x, y; byte gray_palette[256]; if (data->palette != NULL) { uint i; bool all_gray = true; if (info->palette_size != 2) { for (i = 0; i < info->palette_size && (info->palette_size != 16 || all_gray); i++) { all_gray &= data->palette[i].r == data->palette[i].g && data->palette[i].r == data->palette[i].b; gray_palette[i] = RGBToGrayscale(data->palette[i].r, data->palette[i].g, data->palette[i].b); } /** * For a non-gray palette of size 16 we assume that * the order of the palette determines the height; * the first entry is the sea (level 0), the second one * level 1, etc. */ if (info->palette_size == 16 && !all_gray) { for (i = 0; i < info->palette_size; i++) { gray_palette[i] = 256 * i / info->palette_size; } } } else { /** * For a palette of size 2 we assume that the order of the palette determines the height; * the first entry is the sea (level 0), the second one is the land (level 1) */ gray_palette[0] = 0; gray_palette[1] = 16; } } /* Read the raw image data and convert in 8-bit grayscale */ for (y = 0; y < info->height; y++) { byte *pixel = &map[y * info->width]; byte *bitmap = &data->bitmap[y * info->width * (info->bpp == 24 ? 3 : 1)]; for (x = 0; x < info->width; x++) { if (info->bpp != 24) { *pixel++ = gray_palette[*bitmap++]; } else { *pixel++ = RGBToGrayscale(*bitmap, *(bitmap + 1), *(bitmap + 2)); bitmap += 3; } } } } /** * Reads the heightmap and/or size of the heightmap from a BMP file. * If map == NULL only the size of the BMP is read, otherwise a map * with grayscale pixels is allocated and assigned to *map. */ static bool ReadHeightmapBMP(char *filename, uint *x, uint *y, byte **map) { FILE *f; BmpInfo info; BmpData data; BmpBuffer buffer; /* Init BmpData */ memset(&data, 0, sizeof(data)); f = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR); if (f == NULL) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR); return false; } BmpInitializeBuffer(&buffer, f); if (!BmpReadHeader(&buffer, &info, &data)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } /* Check if image dimensions don't overflow a size_t to avoid memory corruption. */ if ((uint64)info.width * info.height >= (size_t)-1 / (info.bpp == 24 ? 3 : 1)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } if (map != NULL) { if (!BmpReadBitmap(&buffer, &info, &data)) { ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR); fclose(f); BmpDestroyData(&data); return false; } *map = MallocT(info.width * info.height); ReadHeightmapBMPImageData(*map, &info, &data); } BmpDestroyData(&data); *x = info.width; *y = info.height; fclose(f); return true; } /** * Converts a given grayscale map to something that fits in OTTD map system * and create a map of that data. * @param img_width the with of the image in pixels/tiles * @param img_height the height of the image in pixels/tiles * @param map the input map */ static void GrayscaleToMapHeights(uint img_width, uint img_height, byte *map) { /* Defines the detail of the aspect ratio (to avoid doubles) */ const uint num_div = 16384; uint width, height; uint row, col; uint row_pad = 0, col_pad = 0; uint img_scale; uint img_row, img_col; TileIndex tile; /* Get map size and calculate scale and padding values */ switch (_settings_game.game_creation.heightmap_rotation) { default: NOT_REACHED(); case HM_COUNTER_CLOCKWISE: width = MapSizeX(); height = MapSizeY(); break; case HM_CLOCKWISE: width = MapSizeY(); height = MapSizeX(); break; } if ((img_width * num_div) / img_height > ((width * num_div) / height)) { /* Image is wider than map - center vertically */ img_scale = (width * num_div) / img_width; row_pad = (1 + height - ((img_height * img_scale) / num_div)) / 2; } else { /* Image is taller than map - center horizontally */ img_scale = (height * num_div) / img_height; col_pad = (1 + width - ((img_width * img_scale) / num_div)) / 2; } if (_settings_game.construction.freeform_edges) { for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0)); for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y)); } /* Form the landscape */ for (row = 0; row < height; row++) { for (col = 0; col < width; col++) { switch (_settings_game.game_creation.heightmap_rotation) { default: NOT_REACHED(); case HM_COUNTER_CLOCKWISE: tile = TileXY(col, row); break; case HM_CLOCKWISE: tile = TileXY(row, col); break; } /* Check if current tile is within the 1-pixel map edge or padding regions */ if ((!_settings_game.construction.freeform_edges && DistanceFromEdge(tile) <= 1) || (row < row_pad) || (row >= (height - row_pad - (_settings_game.construction.freeform_edges ? 0 : 1))) || (col < col_pad) || (col >= (width - col_pad - (_settings_game.construction.freeform_edges ? 0 : 1)))) { SetTileHeight(tile, 0); } else { /* Use nearest neighbour resizing to scale map data. * We rotate the map 45 degrees (counter)clockwise */ img_row = (((row - row_pad) * num_div) / img_scale); switch (_settings_game.game_creation.heightmap_rotation) { default: NOT_REACHED(); case HM_COUNTER_CLOCKWISE: img_col = (((width - 1 - col - col_pad) * num_div) / img_scale); break; case HM_CLOCKWISE: img_col = (((col - col_pad) * num_div) / img_scale); break; } assert(img_row < img_height); assert(img_col < img_width); uint heightmap_height = map[img_row * img_width + img_col]; if (heightmap_height > 0) { /* 0 is sea level. * Other grey scales are scaled evenly to the available height levels > 0. * (The coastline is independent from the number of height levels) */ heightmap_height = 1 + (heightmap_height - 1) * _settings_game.construction.max_heightlevel / 255; } SetTileHeight(tile, heightmap_height); } /* Only clear the tiles within the map area. */ if (IsInnerTile(tile)) { MakeClear(tile, CLEAR_GRASS, 3); } } } } /** * This function takes care of the fact that land in OpenTTD can never differ * more than 1 in height */ void FixSlopes() { uint width, height; int row, col; byte current_tile; /* Adjust height difference to maximum one horizontal/vertical change. */ width = MapSizeX(); height = MapSizeY(); /* Top and left edge */ for (row = 0; (uint)row < height; row++) { for (col = 0; (uint)col < width; col++) { current_tile = MAX_TILE_HEIGHT; if (col != 0) { /* Find lowest tile; either the top or left one */ current_tile = TileHeight(TileXY(col - 1, row)); // top edge } if (row != 0) { if (TileHeight(TileXY(col, row - 1)) < current_tile) { current_tile = TileHeight(TileXY(col, row - 1)); // left edge } } /* Does the height differ more than one? */ if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) { /* Then change the height to be no more than one */ SetTileHeight(TileXY(col, row), current_tile + 1); } } } /* Bottom and right edge */ for (row = height - 1; row >= 0; row--) { for (col = width - 1; col >= 0; col--) { current_tile = MAX_TILE_HEIGHT; if ((uint)col != width - 1) { /* Find lowest tile; either the bottom and right one */ current_tile = TileHeight(TileXY(col + 1, row)); // bottom edge } if ((uint)row != height - 1) { if (TileHeight(TileXY(col, row + 1)) < current_tile) { current_tile = TileHeight(TileXY(col, row + 1)); // right edge } } /* Does the height differ more than one? */ if (TileHeight(TileXY(col, row)) >= (uint)current_tile + 2) { /* Then change the height to be no more than one */ SetTileHeight(TileXY(col, row), current_tile + 1); } } } } /** * Reads the heightmap with the correct file reader */ static bool ReadHeightMap(char *filename, uint *x, uint *y, byte **map) { switch (_file_to_saveload.mode) { default: NOT_REACHED(); #ifdef WITH_PNG case SL_PNG: return ReadHeightmapPNG(filename, x, y, map); #endif /* WITH_PNG */ case SL_BMP: return ReadHeightmapBMP(filename, x, y, map); } } /** * Get the dimensions of a heightmap. * @param filename to query * @param x dimension x * @param y dimension y * @return Returns false if loading of the image failed. */ bool GetHeightmapDimensions(char *filename, uint *x, uint *y) { return ReadHeightMap(filename, x, y, NULL); } /** * Load a heightmap from file and change the map in his current dimensions * to a landscape representing the heightmap. * It converts pixels to height. The brighter, the higher. * @param filename of the heightmap file to be imported */ void LoadHeightmap(char *filename) { uint x, y; byte *map = NULL; if (!ReadHeightMap(filename, &x, &y, &map)) { free(map); return; } GrayscaleToMapHeights(x, y, map); free(map); FixSlopes(); MarkWholeScreenDirty(); } /** * Make an empty world where all tiles are of height 'tile_height'. * @param tile_height of the desired new empty world */ void FlatEmptyWorld(byte tile_height) { int edge_distance = _settings_game.construction.freeform_edges ? 0 : 2; for (uint row = edge_distance; row < MapSizeY() - edge_distance; row++) { for (uint col = edge_distance; col < MapSizeX() - edge_distance; col++) { SetTileHeight(TileXY(col, row), tile_height); } } FixSlopes(); MarkWholeScreenDirty(); } openttd-1.5.3/src/base_media_base.h0000644000000000000000000002411012627373442015706 0ustar rootroot/* $Id: base_media_base.h 24487 2012-08-20 21:01:40Z yexo $ */ /* * 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 base_media_base.h Generic functions for replacing base data (graphics, sounds). */ #ifndef BASE_MEDIA_BASE_H #define BASE_MEDIA_BASE_H #include "fileio_func.h" #include "core/smallmap_type.hpp" #include "gfx_type.h" #include "textfile_type.h" #include "textfile_gui.h" /* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */ struct IniFile; struct ContentInfo; /** Structure holding filename and MD5 information about a single file */ struct MD5File { /** The result of a checksum check */ enum ChecksumResult { CR_MATCH, ///< The file did exist and the md5 checksum did match CR_MISMATCH, ///< The file did exist, just the md5 checksum did not match CR_NO_FILE, ///< The file did not exist }; const char *filename; ///< filename uint8 hash[16]; ///< md5 sum of the file const char *missing_warning; ///< warning when this file is missing ChecksumResult CheckMD5(Subdirectory subdir, size_t max_size) const; }; /** * Information about a single base set. * @tparam T the real class we're going to be * @tparam Tnum_files the number of files in the set * @tparam Tsearch_in_tars whether to search in the tars or not */ template struct BaseSet { typedef SmallMap TranslatedStrings; /** Number of files in this set */ static const size_t NUM_FILES = Tnum_files; /** Whether to search in the tars or not. */ static const bool SEARCH_IN_TARS = Tsearch_in_tars; /** Internal names of the files in this set. */ static const char * const *file_names; const char *name; ///< The name of the base set TranslatedStrings description; ///< Description of the base set uint32 shortname; ///< Four letter short variant of the name uint32 version; ///< The version of this base set bool fallback; ///< This set is a fallback set, i.e. it should be used only as last resort MD5File files[NUM_FILES]; ///< All files part of this set uint found_files; ///< Number of the files that could be found uint valid_files; ///< Number of the files that could be found and are valid T *next; ///< The next base set in this list /** Free everything we allocated */ ~BaseSet() { free(this->name); for (TranslatedStrings::iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { free(iter->first); free(iter->second); } for (uint i = 0; i < NUM_FILES; i++) { free(this->files[i].filename); free(this->files[i].missing_warning); } delete this->next; } /** * Get the number of missing files. * @return the number */ int GetNumMissing() const { return Tnum_files - this->found_files; } /** * Get the number of invalid files. * @note a missing file is invalid too! * @return the number */ int GetNumInvalid() const { return Tnum_files - this->valid_files; } bool FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename = true); /** * Get the description for the given ISO code. * It falls back to the first two characters of the ISO code in case * no match could be made with the full ISO code. If even then the * matching fails the default is returned. * @param isocode the isocode to search for * @return the description */ const char *GetDescription(const char *isocode = NULL) const { if (isocode != NULL) { /* First the full ISO code */ for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { if (strcmp(iter->first, isocode) == 0) return iter->second; } /* Then the first two characters */ for (TranslatedStrings::const_iterator iter = this->description.Begin(); iter != this->description.End(); iter++) { if (strncmp(iter->first, isocode, 2) == 0) return iter->second; } } /* Then fall back */ return this->description.Begin()->second; } /** * Calculate and check the MD5 hash of the supplied file. * @param file The file get the hash of. * @param subdir The sub directory to get the files from. * @return * - #CR_MATCH if the MD5 hash matches * - #CR_MISMATCH if the MD5 does not match * - #CR_NO_FILE if the file misses */ static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir) { return file->CheckMD5(subdir, SIZE_MAX); } /** * Search a textfile file next to this base media. * @param type The type of the textfile to search for. * @return The filename for the textfile, \c NULL otherwise. */ const char *GetTextfile(TextfileType type) const { for (uint i = 0; i < NUM_FILES; i++) { const char *textfile = ::GetTextfile(type, BASESET_DIR, this->files[i].filename); if (textfile != NULL) { return textfile; } } return NULL; } }; /** * Base for all base media (graphics, sounds) * @tparam Tbase_set the real set we're going to be */ template class BaseMedia : FileScanner { protected: static Tbase_set *available_sets; ///< All available sets static Tbase_set *duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded. static const Tbase_set *used_set; ///< The currently used set /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); /** * Get the extension that is used to identify this set. * @return the extension */ static const char *GetExtension(); public: /** The set as saved in the config file. */ static const char *ini_set; /** * Determine the graphics pack that has to be used. * The one with the most correct files wins. * @return true if a best set has been found. */ static bool DetermineBestSet(); /** Do the scan for files. */ static uint FindSets() { BaseMedia fs; /* Searching in tars is only done in the old "data" directories basesets. */ uint num = fs.Scan(GetExtension(), Tbase_set::SEARCH_IN_TARS ? OLD_DATA_DIR : OLD_GM_DIR, Tbase_set::SEARCH_IN_TARS); return num + fs.Scan(GetExtension(), BASESET_DIR, Tbase_set::SEARCH_IN_TARS); } static Tbase_set *GetAvailableSets(); static bool SetSet(const char *name); static char *GetSetsList(char *p, const char *last); static int GetNumSets(); static int GetIndexOfUsedSet(); static const Tbase_set *GetSet(int index); static const Tbase_set *GetUsedSet(); /** * Check whether we have an set with the exact characteristics as ci. * @param ci the characteristics to search on (shortname and md5sum) * @param md5sum whether to check the MD5 checksum * @return true iff we have an set matching. */ static bool HasSet(const ContentInfo *ci, bool md5sum); }; /** * Check whether there's a base set matching some information. * @param ci The content info to compare it to. * @param md5sum Should the MD5 checksum be tested as well? * @param s The list with sets. * @return The filename of the first file of the base set, or \c NULL if there is no match. */ template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s); /** Types of graphics in the base graphics set */ enum GraphicsFileType { GFT_BASE, ///< Base sprites for all climates GFT_LOGOS, ///< Logos, landscape icons and original terrain generator sprites GFT_ARCTIC, ///< Landscape replacement sprites for arctic GFT_TROPICAL, ///< Landscape replacement sprites for tropical GFT_TOYLAND, ///< Landscape replacement sprites for toyland GFT_EXTRA, ///< Extra sprites that were not part of the original sprites MAX_GFT, ///< We are looking for this amount of GRFs }; /** Blitter type for base graphics sets. */ enum BlitterType { BLT_8BPP, ///< Base set has 8 bpp sprites only. BLT_32BPP, ///< Base set has both 8 bpp and 32 bpp sprites. }; /** All data of a graphics set. */ struct GraphicsSet : BaseSet { PaletteType palette; ///< Palette of this graphics set BlitterType blitter; ///< Blitter of this graphics set bool FillSetDetails(struct IniFile *ini, const char *path, const char *full_filename); static MD5File::ChecksumResult CheckMD5(const MD5File *file, Subdirectory subdir); }; /** All data/functions related with replacing the base graphics. */ class BaseGraphics : public BaseMedia { public: }; /** All data of a sounds set. */ struct SoundsSet : BaseSet { }; /** All data/functions related with replacing the base sounds */ class BaseSounds : public BaseMedia { public: }; /** Maximum number of songs in the 'class' playlists. */ static const uint NUM_SONGS_CLASS = 10; /** Number of classes for songs */ static const uint NUM_SONG_CLASSES = 3; /** Maximum number of songs in the full playlist; theme song + the classes */ static const uint NUM_SONGS_AVAILABLE = 1 + NUM_SONG_CLASSES * NUM_SONGS_CLASS; /** Maximum number of songs in the (custom) playlist */ static const uint NUM_SONGS_PLAYLIST = 32; /** All data of a music set. */ struct MusicSet : BaseSet { /** The name of the different songs. */ char song_name[NUM_SONGS_AVAILABLE][32]; byte track_nr[NUM_SONGS_AVAILABLE]; byte num_available; bool FillSetDetails(struct IniFile *ini, const char *path, const char *full_filename); }; /** All data/functions related with replacing the base music */ class BaseMusic : public BaseMedia { public: }; #endif /* BASE_MEDIA_BASE_H */ openttd-1.5.3/src/vehicle_type.h0000644000000000000000000000706712627373442015337 0ustar rootroot/* $Id: vehicle_type.h 23080 2011-11-01 16:51:47Z frosch $ */ /* * 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 vehicle_type.h Types related to vehicles. */ #ifndef VEHICLE_TYPE_H #define VEHICLE_TYPE_H #include "core/enum_type.hpp" /** The type all our vehicle IDs have. */ typedef uint32 VehicleID; /** Available vehicle types. */ enum VehicleType { VEH_BEGIN, VEH_TRAIN = VEH_BEGIN, ///< %Train vehicle type. VEH_ROAD, ///< Road vehicle type. VEH_SHIP, ///< %Ship vehicle type. VEH_AIRCRAFT, ///< %Aircraft vehicle type. VEH_COMPANY_END, ///< Last company-ownable type. VEH_EFFECT = VEH_COMPANY_END, ///< Effect vehicle type (smoke, explosions, sparks, bubbles) VEH_DISASTER, ///< Disaster vehicle type. VEH_END, VEH_INVALID = 0xFF, ///< Non-existing type of vehicle. }; DECLARE_POSTFIX_INCREMENT(VehicleType) /** Helper information for extract tool. */ template <> struct EnumPropsT : MakeEnumPropsT {}; /** It needs to be 8bits, because we save and load it as such */ typedef SimpleTinyEnumT VehicleTypeByte; struct Vehicle; struct Train; struct RoadVehicle; struct Ship; struct Aircraft; struct EffectVehicle; struct DisasterVehicle; /** Base vehicle class. */ struct BaseVehicle { VehicleTypeByte type; ///< Type of vehicle }; static const VehicleID INVALID_VEHICLE = 0xFFFFF; ///< Constant representing a non-existing vehicle. /** Pathfinding option states */ enum VehiclePathFinders { VPF_OPF = 0, ///< The Original PathFinder (only for ships) VPF_NPF = 1, ///< New PathFinder VPF_YAPF = 2, ///< Yet Another PathFinder }; /** Flags to add to p1 for goto depot commands. */ enum DepotCommand { DEPOT_SERVICE = (1U << 28), ///< The vehicle will leave the depot right after arrival (serivce only) DEPOT_MASS_SEND = (1U << 29), ///< Tells that it's a mass send to depot command (type in VLW flag) DEPOT_DONT_CANCEL = (1U << 30), ///< Don't cancel current goto depot command if any DEPOT_LOCATE_HANGAR = (1U << 31), ///< Find another airport if the target one lacks a hangar DEPOT_COMMAND_MASK = 0xFU << 28, }; static const uint MAX_LENGTH_VEHICLE_NAME_CHARS = 32; ///< The maximum length of a vehicle name in characters including '\0' /** The length of a vehicle in tile units. */ static const uint VEHICLE_LENGTH = 8; /** Vehicle acceleration models. */ enum AccelerationModel { AM_ORIGINAL, AM_REALISTIC, }; /** Visualisation contexts of vehicles and engines. */ enum EngineImageType { EIT_ON_MAP = 0x00, ///< Vehicle drawn in viewport. EIT_IN_DEPOT = 0x10, ///< Vehicle drawn in depot. EIT_IN_DETAILS = 0x11, ///< Vehicle drawn in vehicle details, refit window, ... EIT_IN_LIST = 0x12, ///< Vehicle drawn in vehicle list, group list, ... EIT_PURCHASE = 0x20, ///< Vehicle drawn in purchase list, autoreplace gui, ... EIT_PREVIEW = 0x21, ///< Vehicle drawn in preview window, news, ... }; #endif /* VEHICLE_TYPE_H */ openttd-1.5.3/src/newgrf_commons.h0000644000000000000000000003152312627373435015676 0ustar rootroot/* $Id: newgrf_commons.h 26241 2014-01-12 18:00:39Z frosch $ */ /* * 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 newgrf_commons.h This file simplyfies and embeds a common mechanism of * loading/saving and mapping of grf entities. */ #ifndef NEWGRF_COMMONS_H #define NEWGRF_COMMONS_H #include "sprite.h" #include "core/alloc_type.hpp" #include "core/smallvec_type.hpp" #include "command_type.h" #include "direction_type.h" #include "company_type.h" /** Context for tile accesses */ enum TileContext { TCX_NORMAL, ///< Nothing special. TCX_UPPER_HALFTILE, ///< Querying information about the upper part of a tile with halftile foundation. TCX_ON_BRIDGE, ///< Querying information about stuff on the bridge (via some bridgehead). }; /** * Flags to enable register usage in sprite layouts. */ enum TileLayoutFlags { TLF_NOTHING = 0x00, TLF_DODRAW = 0x01, ///< Only draw sprite if value of register TileLayoutRegisters::dodraw is non-zero. TLF_SPRITE = 0x02, ///< Add signed offset to sprite from register TileLayoutRegisters::sprite. TLF_PALETTE = 0x04, ///< Add signed offset to palette from register TileLayoutRegisters::palette. TLF_CUSTOM_PALETTE = 0x08, ///< Palette is from Action 1 (moved to SPRITE_MODIFIER_CUSTOM_SPRITE in palette during loading). TLF_BB_XY_OFFSET = 0x10, ///< Add signed offset to bounding box X and Y positions from register TileLayoutRegisters::delta.parent[0..1]. TLF_BB_Z_OFFSET = 0x20, ///< Add signed offset to bounding box Z positions from register TileLayoutRegisters::delta.parent[2]. TLF_CHILD_X_OFFSET = 0x10, ///< Add signed offset to child sprite X positions from register TileLayoutRegisters::delta.child[0]. TLF_CHILD_Y_OFFSET = 0x20, ///< Add signed offset to child sprite Y positions from register TileLayoutRegisters::delta.child[1]. TLF_SPRITE_VAR10 = 0x40, ///< Resolve sprite with a specific value in variable 10. TLF_PALETTE_VAR10 = 0x80, ///< Resolve palette with a specific value in variable 10. TLF_KNOWN_FLAGS = 0x7F, ///< Known flags. Any unknown set flag will disable the GRF. /** Flags which are still required after loading the GRF. */ TLF_DRAWING_FLAGS = ~TLF_CUSTOM_PALETTE, /** Flags which do not work for the (first) ground sprite. */ TLF_NON_GROUND_FLAGS = TLF_BB_XY_OFFSET | TLF_BB_Z_OFFSET | TLF_CHILD_X_OFFSET | TLF_CHILD_Y_OFFSET, /** Flags which refer to using multiple action-1-2-3 chains. */ TLF_VAR10_FLAGS = TLF_SPRITE_VAR10 | TLF_PALETTE_VAR10, /** Flags which require resolving the action-1-2-3 chain for the sprite, even if it is no action-1 sprite. */ TLF_SPRITE_REG_FLAGS = TLF_DODRAW | TLF_SPRITE | TLF_BB_XY_OFFSET | TLF_BB_Z_OFFSET | TLF_CHILD_X_OFFSET | TLF_CHILD_Y_OFFSET, /** Flags which require resolving the action-1-2-3 chain for the palette, even if it is no action-1 palette. */ TLF_PALETTE_REG_FLAGS = TLF_PALETTE, }; DECLARE_ENUM_AS_BIT_SET(TileLayoutFlags) /** * Determines which sprite to use from a spriteset for a specific construction stage. * @param construction_stage Construction stage 0 - 3. * @param num_sprites Number of available sprites to select stage from. * @return Sprite to use */ static inline uint GetConstructionStageOffset(uint construction_stage, uint num_sprites) { assert(num_sprites > 0); if (num_sprites > 4) num_sprites = 4; switch (construction_stage) { case 0: return 0; case 1: return num_sprites > 2 ? 1 : 0; case 2: return num_sprites > 2 ? num_sprites - 2 : 0; case 3: return num_sprites - 1; default: NOT_REACHED(); } } /** * Additional modifiers for items in sprite layouts. */ struct TileLayoutRegisters { TileLayoutFlags flags; ///< Flags defining which members are valid and to be used. uint8 dodraw; ///< Register deciding whether the sprite shall be drawn at all. Non-zero means drawing. uint8 sprite; ///< Register specifying a signed offset for the sprite. uint8 palette; ///< Register specifying a signed offset for the palette. uint16 max_sprite_offset; ///< Maximum offset to add to the sprite. (limited by size of the spriteset) uint16 max_palette_offset; ///< Maximum offset to add to the palette. (limited by size of the spriteset) union { uint8 parent[3]; ///< Registers for signed offsets for the bounding box position of parent sprites. uint8 child[2]; ///< Registers for signed offsets for the position of child sprites. } delta; uint8 sprite_var10; ///< Value for variable 10 when resolving the sprite. uint8 palette_var10; ///< Value for variable 10 when resolving the palette. }; static const uint TLR_MAX_VAR10 = 7; ///< Maximum value for var 10. /** * NewGRF supplied spritelayout. * In contrast to #DrawTileSprites this struct is for allocated * layouts on the heap. It allocates data and frees them on destruction. */ struct NewGRFSpriteLayout : ZeroedMemoryAllocator, DrawTileSprites { const TileLayoutRegisters *registers; /** * Number of sprites in all referenced spritesets. * If these numbers are inconsistent, then this is 0 and the real values are in \c registers. */ uint consistent_max_offset; void Allocate(uint num_sprites); void AllocateRegisters(); void Clone(const DrawTileSeqStruct *source); void Clone(const NewGRFSpriteLayout *source); /** * Clone a spritelayout. * @param source The spritelayout to copy. */ void Clone(const DrawTileSprites *source) { assert(source != NULL && this != source); this->ground = source->ground; this->Clone(source->seq); } virtual ~NewGRFSpriteLayout() { free(this->seq); free(this->registers); } /** * Tests whether this spritelayout needs preprocessing by * #PrepareLayout() and #ProcessRegisters(), or whether it can be * used directly. * @return true if preprocessing is needed */ bool NeedsPreprocessing() const { return this->registers != NULL; } uint32 PrepareLayout(uint32 orig_offset, uint32 newgrf_ground_offset, uint32 newgrf_offset, uint constr_stage, bool separate_ground) const; void ProcessRegisters(uint8 resolved_var10, uint32 resolved_sprite, bool separate_ground) const; /** * Returns the result spritelayout after preprocessing. * @pre #PrepareLayout() and #ProcessRegisters() need calling first. * @return result spritelayout */ const DrawTileSeqStruct *GetLayout(PalSpriteID *ground) const { DrawTileSeqStruct *front = result_seq.Begin(); *ground = front->image; return front + 1; } private: static SmallVector result_seq; ///< Temporary storage when preprocessing spritelayouts. }; /** * Maps an entity id stored on the map to a GRF file. * Entities are objects used ingame (houses, industries, industry tiles) for * which we need to correlate the ids from the grf files with the ones in the * the savegames themselves. * An array of EntityIDMapping structs is saved with the savegame so * that those GRFs can be loaded in a different order, or removed safely. The * index in the array is the entity's ID stored on the map. * * The substitute ID is the ID of an original entity that should be used instead * if the GRF containing the new entity is not available. */ struct EntityIDMapping { uint32 grfid; ///< The GRF ID of the file the entity belongs to uint8 entity_id; ///< The entity ID within the GRF file uint8 substitute_id; ///< The (original) entity ID to use if this GRF is not available }; class OverrideManagerBase { protected: uint16 *entity_overrides; uint32 *grfid_overrides; uint16 max_offset; ///< what is the length of the original entity's array of specs uint16 max_new_entities; ///< what is the amount of entities, old and new summed uint16 invalid_ID; ///< ID used to detected invalid entities; virtual bool CheckValidNewID(uint16 testid) { return true; } public: EntityIDMapping *mapping_ID; ///< mapping of ids from grf files. Public out of convenience OverrideManagerBase(uint16 offset, uint16 maximum, uint16 invalid); virtual ~OverrideManagerBase(); void ResetOverride(); void ResetMapping(); void Add(uint8 local_id, uint32 grfid, uint entity_type); virtual uint16 AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id); uint32 GetGRFID(uint16 entity_id) const; uint16 GetSubstituteID(uint16 entity_id) const; virtual uint16 GetID(uint8 grf_local_id, uint32 grfid) const; inline uint16 GetMaxMapping() const { return max_new_entities; } inline uint16 GetMaxOffset() const { return max_offset; } }; struct HouseSpec; class HouseOverrideManager : public OverrideManagerBase { public: HouseOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} void SetEntitySpec(const HouseSpec *hs); }; struct IndustrySpec; class IndustryOverrideManager : public OverrideManagerBase { public: IndustryOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} virtual uint16 AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id); virtual uint16 GetID(uint8 grf_local_id, uint32 grfid) const; void SetEntitySpec(IndustrySpec *inds); }; struct IndustryTileSpec; class IndustryTileOverrideManager : public OverrideManagerBase { protected: virtual bool CheckValidNewID(uint16 testid) { return testid != 0xFF; } public: IndustryTileOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} void SetEntitySpec(const IndustryTileSpec *indts); }; struct AirportSpec; class AirportOverrideManager : public OverrideManagerBase { public: AirportOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} void SetEntitySpec(AirportSpec *inds); }; struct AirportTileSpec; class AirportTileOverrideManager : public OverrideManagerBase { protected: virtual bool CheckValidNewID(uint16 testid) { return testid != 0xFF; } public: AirportTileOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} void SetEntitySpec(const AirportTileSpec *ats); }; struct ObjectSpec; class ObjectOverrideManager : public OverrideManagerBase { protected: virtual bool CheckValidNewID(uint16 testid) { return testid != 0xFF; } public: ObjectOverrideManager(uint16 offset, uint16 maximum, uint16 invalid) : OverrideManagerBase(offset, maximum, invalid) {} void SetEntitySpec(ObjectSpec *spec); }; extern HouseOverrideManager _house_mngr; extern IndustryOverrideManager _industry_mngr; extern IndustryTileOverrideManager _industile_mngr; extern AirportOverrideManager _airport_mngr; extern AirportTileOverrideManager _airporttile_mngr; extern ObjectOverrideManager _object_mngr; uint32 GetTerrainType(TileIndex tile, TileContext context = TCX_NORMAL); TileIndex GetNearbyTile(byte parameter, TileIndex tile, bool signed_offsets = true, Axis axis = INVALID_AXIS); uint32 GetNearbyTileInformation(TileIndex tile, bool grf_version8); uint32 GetCompanyInfo(CompanyID owner, const struct Livery *l = NULL); CommandCost GetErrorMessageFromLocationCallbackResult(uint16 cb_res, const GRFFile *grffile, StringID default_error); void ErrorUnknownCallbackResult(uint32 grfid, uint16 cbid, uint16 cb_res); bool ConvertBooleanCallback(const struct GRFFile *grffile, uint16 cbid, uint16 cb_res); bool Convert8bitBooleanCallback(const struct GRFFile *grffile, uint16 cbid, uint16 cb_res); /** * Data related to the handling of grf files. * @tparam Tcnt Number of spritegroups */ template struct GRFFilePropsBase { GRFFilePropsBase() : local_id(0), grffile(0) { /* The lack of some compilers to provide default constructors complying to the specs * requires us to zero the stuff ourself. */ memset(spritegroup, 0, sizeof(spritegroup)); } uint16 local_id; ///< id defined by the grf file for this entity const struct GRFFile *grffile; ///< grf file that introduced this entity const struct SpriteGroup *spritegroup[Tcnt]; ///< pointer to the different sprites of the entity }; /** Data related to the handling of grf files. */ struct GRFFileProps : GRFFilePropsBase<1> { /** Set all default data constructor for the props. */ GRFFileProps(uint16 subst_id = 0) : GRFFilePropsBase<1>(), subst_id(subst_id), override(subst_id) { } uint16 subst_id; uint16 override; ///< id of the entity been replaced by }; #endif /* NEWGRF_COMMONS_H */ openttd-1.5.3/src/rail_map.h0000644000000000000000000003726712627373434014451 0ustar rootroot/* $Id: rail_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 rail_map.h Hides the direct accesses to the map array with map accessors */ #ifndef RAIL_MAP_H #define RAIL_MAP_H #include "rail_type.h" #include "depot_type.h" #include "signal_func.h" #include "track_func.h" #include "tile_map.h" #include "signal_type.h" /** Different types of Rail-related tiles */ enum RailTileType { RAIL_TILE_NORMAL = 0, ///< Normal rail tile without signals RAIL_TILE_SIGNALS = 1, ///< Normal rail tile with signals RAIL_TILE_DEPOT = 3, ///< Depot (one entrance) }; /** * Returns the RailTileType (normal with or without signals, * waypoint or depot). * @param t the tile to get the information from * @pre IsTileType(t, MP_RAILWAY) * @return the RailTileType */ static inline RailTileType GetRailTileType(TileIndex t) { assert(IsTileType(t, MP_RAILWAY)); return (RailTileType)GB(_m[t].m5, 6, 2); } /** * Returns whether this is plain rails, with or without signals. Iow, if this * tiles RailTileType is RAIL_TILE_NORMAL or RAIL_TILE_SIGNALS. * @param t the tile to get the information from * @pre IsTileType(t, MP_RAILWAY) * @return true if and only if the tile is normal rail (with or without signals) */ static inline bool IsPlainRail(TileIndex t) { RailTileType rtt = GetRailTileType(t); return rtt == RAIL_TILE_NORMAL || rtt == RAIL_TILE_SIGNALS; } /** * Checks whether the tile is a rail tile or rail tile with signals. * @param t the tile to get the information from * @return true if and only if the tile is normal rail (with or without signals) */ static inline bool IsPlainRailTile(TileIndex t) { return IsTileType(t, MP_RAILWAY) && IsPlainRail(t); } /** * Checks if a rail tile has signals. * @param t the tile to get the information from * @pre IsTileType(t, MP_RAILWAY) * @return true if and only if the tile has signals */ static inline bool HasSignals(TileIndex t) { return GetRailTileType(t) == RAIL_TILE_SIGNALS; } /** * Add/remove the 'has signal' bit from the RailTileType * @param tile the tile to add/remove the signals to/from * @param signals whether the rail tile should have signals or not * @pre IsPlainRailTile(tile) */ static inline void SetHasSignals(TileIndex tile, bool signals) { assert(IsPlainRailTile(tile)); SB(_m[tile].m5, 6, 1, signals); } /** * Is this rail tile a rail depot? * @param t the tile to get the information from * @pre IsTileType(t, MP_RAILWAY) * @return true if and only if the tile is a rail depot */ static inline bool IsRailDepot(TileIndex t) { return GetRailTileType(t) == RAIL_TILE_DEPOT; } /** * Is this tile rail tile and a rail depot? * @param t the tile to get the information from * @return true if and only if the tile is a rail depot */ static inline bool IsRailDepotTile(TileIndex t) { return IsTileType(t, MP_RAILWAY) && IsRailDepot(t); } /** * Gets the rail type of the given tile * @param t the tile to get the rail type from * @return the rail type of the tile */ static inline RailType GetRailType(TileIndex t) { return (RailType)GB(_m[t].m3, 0, 4); } /** * Sets the rail type of the given tile * @param t the tile to set the rail type of * @param r the new rail type for the tile */ static inline void SetRailType(TileIndex t, RailType r) { SB(_m[t].m3, 0, 4, r); } /** * Gets the track bits of the given tile * @param tile the tile to get the track bits from * @return the track bits of the tile */ static inline TrackBits GetTrackBits(TileIndex tile) { assert(IsPlainRailTile(tile)); return (TrackBits)GB(_m[tile].m5, 0, 6); } /** * Sets the track bits of the given tile * @param t the tile to set the track bits of * @param b the new track bits for the tile */ static inline void SetTrackBits(TileIndex t, TrackBits b) { assert(IsPlainRailTile(t)); SB(_m[t].m5, 0, 6, b); } /** * Returns whether the given track is present on the given tile. * @param tile the tile to check the track presence of * @param track the track to search for on the tile * @pre IsPlainRailTile(tile) * @return true if and only if the given track exists on the tile */ static inline bool HasTrack(TileIndex tile, Track track) { return HasBit(GetTrackBits(tile), track); } /** * Returns the direction the depot is facing to * @param t the tile to get the depot facing from * @pre IsRailDepotTile(t) * @return the direction the depot is facing */ static inline DiagDirection GetRailDepotDirection(TileIndex t) { return (DiagDirection)GB(_m[t].m5, 0, 2); } /** * Returns the track of a depot, ignoring direction * @pre IsRailDepotTile(t) * @param t the tile to get the depot track from * @return the track of the depot */ static inline Track GetRailDepotTrack(TileIndex t) { return DiagDirToDiagTrack(GetRailDepotDirection(t)); } /** * Returns the reserved track bits of the tile * @pre IsPlainRailTile(t) * @param t the tile to query * @return the track bits */ static inline TrackBits GetRailReservationTrackBits(TileIndex t) { assert(IsPlainRailTile(t)); byte track_b = GB(_m[t].m2, 8, 3); Track track = (Track)(track_b - 1); // map array saves Track+1 if (track_b == 0) return TRACK_BIT_NONE; return (TrackBits)(TrackToTrackBits(track) | (HasBit(_m[t].m2, 11) ? TrackToTrackBits(TrackToOppositeTrack(track)) : 0)); } /** * Sets the reserved track bits of the tile * @pre IsPlainRailTile(t) && !TracksOverlap(b) * @param t the tile to change * @param b the track bits */ static inline void SetTrackReservation(TileIndex t, TrackBits b) { assert(IsPlainRailTile(t)); assert(b != INVALID_TRACK_BIT); assert(!TracksOverlap(b)); Track track = RemoveFirstTrack(&b); SB(_m[t].m2, 8, 3, track == INVALID_TRACK ? 0 : track + 1); SB(_m[t].m2, 11, 1, (byte)(b != TRACK_BIT_NONE)); } /** * Try to reserve a specific track on a tile * @pre IsPlainRailTile(t) && HasTrack(tile, t) * @param tile the tile * @param t the rack to reserve * @return true if successful */ static inline bool TryReserveTrack(TileIndex tile, Track t) { assert(HasTrack(tile, t)); TrackBits bits = TrackToTrackBits(t); TrackBits res = GetRailReservationTrackBits(tile); if ((res & bits) != TRACK_BIT_NONE) return false; // already reserved res |= bits; if (TracksOverlap(res)) return false; // crossing reservation present SetTrackReservation(tile, res); return true; } /** * Lift the reservation of a specific track on a tile * @pre IsPlainRailTile(t) && HasTrack(tile, t) * @param tile the tile * @param t the track to free */ static inline void UnreserveTrack(TileIndex tile, Track t) { assert(HasTrack(tile, t)); TrackBits res = GetRailReservationTrackBits(tile); res &= ~TrackToTrackBits(t); SetTrackReservation(tile, res); } /** * Get the reservation state of the depot * @pre IsRailDepot(t) * @param t the depot tile * @return reservation state */ static inline bool HasDepotReservation(TileIndex t) { assert(IsRailDepot(t)); return HasBit(_m[t].m5, 4); } /** * Set the reservation state of the depot * @pre IsRailDepot(t) * @param t the depot tile * @param b the reservation state */ static inline void SetDepotReservation(TileIndex t, bool b) { assert(IsRailDepot(t)); SB(_m[t].m5, 4, 1, (byte)b); } /** * Get the reserved track bits for a depot * @pre IsRailDepot(t) * @param t the tile * @return reserved track bits */ static inline TrackBits GetDepotReservationTrackBits(TileIndex t) { return HasDepotReservation(t) ? TrackToTrackBits(GetRailDepotTrack(t)) : TRACK_BIT_NONE; } static inline bool IsPbsSignal(SignalType s) { return s == SIGTYPE_PBS || s == SIGTYPE_PBS_ONEWAY; } static inline SignalType GetSignalType(TileIndex t, Track track) { assert(GetRailTileType(t) == RAIL_TILE_SIGNALS); byte pos = (track == TRACK_LOWER || track == TRACK_RIGHT) ? 4 : 0; return (SignalType)GB(_m[t].m2, pos, 3); } static inline void SetSignalType(TileIndex t, Track track, SignalType s) { assert(GetRailTileType(t) == RAIL_TILE_SIGNALS); byte pos = (track == TRACK_LOWER || track == TRACK_RIGHT) ? 4 : 0; SB(_m[t].m2, pos, 3, s); if (track == INVALID_TRACK) SB(_m[t].m2, 4, 3, s); } static inline bool IsPresignalEntry(TileIndex t, Track track) { return GetSignalType(t, track) == SIGTYPE_ENTRY || GetSignalType(t, track) == SIGTYPE_COMBO; } static inline bool IsPresignalExit(TileIndex t, Track track) { return GetSignalType(t, track) == SIGTYPE_EXIT || GetSignalType(t, track) == SIGTYPE_COMBO; } /** One-way signals can't be passed the 'wrong' way. */ static inline bool IsOnewaySignal(TileIndex t, Track track) { return GetSignalType(t, track) != SIGTYPE_PBS; } static inline void CycleSignalSide(TileIndex t, Track track) { byte sig; byte pos = (track == TRACK_LOWER || track == TRACK_RIGHT) ? 4 : 6; sig = GB(_m[t].m3, pos, 2); if (--sig == 0) sig = IsPbsSignal(GetSignalType(t, track)) ? 2 : 3; SB(_m[t].m3, pos, 2, sig); } static inline SignalVariant GetSignalVariant(TileIndex t, Track track) { byte pos = (track == TRACK_LOWER || track == TRACK_RIGHT) ? 7 : 3; return (SignalVariant)GB(_m[t].m2, pos, 1); } static inline void SetSignalVariant(TileIndex t, Track track, SignalVariant v) { byte pos = (track == TRACK_LOWER || track == TRACK_RIGHT) ? 7 : 3; SB(_m[t].m2, pos, 1, v); if (track == INVALID_TRACK) SB(_m[t].m2, 7, 1, v); } /** * Set the states of the signals (Along/AgainstTrackDir) * @param tile the tile to set the states for * @param state the new state */ static inline void SetSignalStates(TileIndex tile, uint state) { SB(_m[tile].m4, 4, 4, state); } /** * Set the states of the signals (Along/AgainstTrackDir) * @param tile the tile to set the states for * @return the state of the signals */ static inline uint GetSignalStates(TileIndex tile) { return GB(_m[tile].m4, 4, 4); } /** * Get the state of a single signal * @param t the tile to get the signal state for * @param signalbit the signal * @return the state of the signal */ static inline SignalState GetSingleSignalState(TileIndex t, byte signalbit) { return (SignalState)HasBit(GetSignalStates(t), signalbit); } /** * Set whether the given signals are present (Along/AgainstTrackDir) * @param tile the tile to set the present signals for * @param signals the signals that have to be present */ static inline void SetPresentSignals(TileIndex tile, uint signals) { SB(_m[tile].m3, 4, 4, signals); } /** * Get whether the given signals are present (Along/AgainstTrackDir) * @param tile the tile to get the present signals for * @return the signals that are present */ static inline uint GetPresentSignals(TileIndex tile) { return GB(_m[tile].m3, 4, 4); } /** * Checks whether the given signals is present * @param t the tile to check on * @param signalbit the signal * @return true if and only if the signal is present */ static inline bool IsSignalPresent(TileIndex t, byte signalbit) { return HasBit(GetPresentSignals(t), signalbit); } /** * Checks for the presence of signals (either way) on the given track on the * given rail tile. */ static inline bool HasSignalOnTrack(TileIndex tile, Track track) { assert(IsValidTrack(track)); return GetRailTileType(tile) == RAIL_TILE_SIGNALS && (GetPresentSignals(tile) & SignalOnTrack(track)) != 0; } /** * Checks for the presence of signals along the given trackdir on the given * rail tile. * * Along meaning if you are currently driving on the given trackdir, this is * the signal that is facing us (for which we stop when it's red). */ static inline bool HasSignalOnTrackdir(TileIndex tile, Trackdir trackdir) { assert (IsValidTrackdir(trackdir)); return GetRailTileType(tile) == RAIL_TILE_SIGNALS && GetPresentSignals(tile) & SignalAlongTrackdir(trackdir); } /** * Gets the state of the signal along the given trackdir. * * Along meaning if you are currently driving on the given trackdir, this is * the signal that is facing us (for which we stop when it's red). */ static inline SignalState GetSignalStateByTrackdir(TileIndex tile, Trackdir trackdir) { assert(IsValidTrackdir(trackdir)); assert(HasSignalOnTrack(tile, TrackdirToTrack(trackdir))); return GetSignalStates(tile) & SignalAlongTrackdir(trackdir) ? SIGNAL_STATE_GREEN : SIGNAL_STATE_RED; } /** * Sets the state of the signal along the given trackdir. */ static inline void SetSignalStateByTrackdir(TileIndex tile, Trackdir trackdir, SignalState state) { if (state == SIGNAL_STATE_GREEN) { // set 1 SetSignalStates(tile, GetSignalStates(tile) | SignalAlongTrackdir(trackdir)); } else { SetSignalStates(tile, GetSignalStates(tile) & ~SignalAlongTrackdir(trackdir)); } } /** * Is a pbs signal present along the trackdir? * @param tile the tile to check * @param td the trackdir to check */ static inline bool HasPbsSignalOnTrackdir(TileIndex tile, Trackdir td) { return IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, td) && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td))); } /** * Is a one-way signal blocking the trackdir? A one-way signal on the * trackdir against will block, but signals on both trackdirs won't. * @param tile the tile to check * @param td the trackdir to check */ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td) { return IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && !HasSignalOnTrackdir(tile, td) && IsOnewaySignal(tile, TrackdirToTrack(td)); } RailType GetTileRailType(TileIndex tile); /** The ground 'under' the rail */ enum RailGroundType { RAIL_GROUND_BARREN = 0, ///< Nothing (dirt) RAIL_GROUND_GRASS = 1, ///< Grassy RAIL_GROUND_FENCE_NW = 2, ///< Grass with a fence at the NW edge RAIL_GROUND_FENCE_SE = 3, ///< Grass with a fence at the SE edge RAIL_GROUND_FENCE_SENW = 4, ///< Grass with a fence at the NW and SE edges RAIL_GROUND_FENCE_NE = 5, ///< Grass with a fence at the NE edge RAIL_GROUND_FENCE_SW = 6, ///< Grass with a fence at the SW edge RAIL_GROUND_FENCE_NESW = 7, ///< Grass with a fence at the NE and SW edges RAIL_GROUND_FENCE_VERT1 = 8, ///< Grass with a fence at the eastern side RAIL_GROUND_FENCE_VERT2 = 9, ///< Grass with a fence at the western side RAIL_GROUND_FENCE_HORIZ1 = 10, ///< Grass with a fence at the southern side RAIL_GROUND_FENCE_HORIZ2 = 11, ///< Grass with a fence at the northern side RAIL_GROUND_ICE_DESERT = 12, ///< Icy or sandy RAIL_GROUND_WATER = 13, ///< Grass with a fence and shore or water on the free halftile RAIL_GROUND_HALF_SNOW = 14, ///< Snow only on higher part of slope (steep or one corner raised) }; static inline void SetRailGroundType(TileIndex t, RailGroundType rgt) { SB(_m[t].m4, 0, 4, rgt); } static inline RailGroundType GetRailGroundType(TileIndex t) { return (RailGroundType)GB(_m[t].m4, 0, 4); } static inline bool IsSnowRailGround(TileIndex t) { return GetRailGroundType(t) == RAIL_GROUND_ICE_DESERT; } static inline void MakeRailNormal(TileIndex t, Owner o, TrackBits b, RailType r) { SetTileType(t, MP_RAILWAY); SetTileOwner(t, o); _m[t].m2 = 0; _m[t].m3 = r; _m[t].m4 = 0; _m[t].m5 = RAIL_TILE_NORMAL << 6 | b; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } static inline void MakeRailDepot(TileIndex t, Owner o, DepotID did, DiagDirection d, RailType r) { SetTileType(t, MP_RAILWAY); SetTileOwner(t, o); _m[t].m2 = did; _m[t].m3 = r; _m[t].m4 = 0; _m[t].m5 = RAIL_TILE_DEPOT << 6 | d; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } #endif /* RAIL_MAP_H */ openttd-1.5.3/src/articulated_vehicles.cpp0000644000000000000000000003636712627373442017402 0ustar rootroot/* $Id: articulated_vehicles.cpp 26863 2014-09-20 15:31:26Z rubidium $ */ /* * 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 articulated_vehicles.cpp Implementation of articulated vehicles. */ #include "stdafx.h" #include "train.h" #include "roadveh.h" #include "vehicle_func.h" #include "engine_func.h" #include "company_func.h" #include "newgrf.h" #include "table/strings.h" #include "safeguards.h" static const uint MAX_ARTICULATED_PARTS = 100; ///< Maximum of articulated parts per vehicle, i.e. when to abort calling the articulated vehicle callback. /** * Determines the next articulated part to attach * @param index Position in chain * @param front_type Front engine type * @param front Front engine * @param mirrored Returns whether the part shall be flipped. * @return engine to add or INVALID_ENGINE */ static EngineID GetNextArticulatedPart(uint index, EngineID front_type, Vehicle *front = NULL, bool *mirrored = NULL) { assert(front == NULL || front->engine_type == front_type); const Engine *front_engine = Engine::Get(front_type); uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, index, 0, front_type, front); if (callback == CALLBACK_FAILED) return INVALID_ENGINE; if (front_engine->GetGRF()->grf_version < 8) { /* 8 bits, bit 7 for mirroring */ callback = GB(callback, 0, 8); if (callback == 0xFF) return INVALID_ENGINE; if (mirrored != NULL) *mirrored = HasBit(callback, 7); callback = GB(callback, 0, 7); } else { /* 15 bits, bit 14 for mirroring */ if (callback == 0x7FFF) return INVALID_ENGINE; if (mirrored != NULL) *mirrored = HasBit(callback, 14); callback = GB(callback, 0, 14); } return GetNewEngineID(front_engine->GetGRF(), front_engine->type, callback); } /** * Does a NewGRF report that this should be an articulated vehicle? * @param engine_type The engine to check. * @return True iff the articulated engine callback flag is set. */ bool IsArticulatedEngine(EngineID engine_type) { return HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE); } /** * Count the number of articulated parts of an engine. * @param engine_type The engine to get the number of parts of. * @param purchase_window Whether we are in the scope of the purchase window or not, i.e. whether we cannot allocate vehicles. * @return The number of parts. */ uint CountArticulatedParts(EngineID engine_type, bool purchase_window) { if (!HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return 0; /* If we can't allocate a vehicle now, we can't allocate it in the command * either, so it doesn't matter how many articulated parts there are. */ if (!Vehicle::CanAllocateItem()) return 0; Vehicle *v = NULL; if (!purchase_window) { v = new Vehicle(); v->engine_type = engine_type; v->owner = _current_company; } uint i; for (i = 1; i < MAX_ARTICULATED_PARTS; i++) { if (GetNextArticulatedPart(i, engine_type, v) == INVALID_ENGINE) break; } delete v; return i - 1; } /** * Returns the default (non-refitted) capacity of a specific EngineID. * @param engine the EngineID of interest * @param cargo_type returns the default cargo type, if needed * @return capacity */ static inline uint16 GetVehicleDefaultCapacity(EngineID engine, CargoID *cargo_type) { const Engine *e = Engine::Get(engine); CargoID cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID); if (cargo_type != NULL) *cargo_type = cargo; if (cargo == CT_INVALID) return 0; return e->GetDisplayDefaultCapacity(); } /** * Returns all cargoes a vehicle can carry. * @param engine the EngineID of interest * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask * @return bit set of CargoIDs */ static inline uint32 GetAvailableVehicleCargoTypes(EngineID engine, bool include_initial_cargo_type) { const Engine *e = Engine::Get(engine); if (!e->CanCarryCargo()) return 0; uint32 cargoes = e->info.refit_mask; if (include_initial_cargo_type) { SetBit(cargoes, e->GetDefaultCargoType()); } return cargoes; } /** * Get the capacity of the parts of a given engine. * @param engine The engine to get the capacities from. * @return The cargo capacities. */ CargoArray GetCapacityOfArticulatedParts(EngineID engine) { CargoArray capacity; const Engine *e = Engine::Get(engine); CargoID cargo_type; uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type); if (cargo_type < NUM_CARGO) capacity[cargo_type] = cargo_capacity; if (!e->IsGroundVehicle()) return capacity; if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return capacity; for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { EngineID artic_engine = GetNextArticulatedPart(i, engine); if (artic_engine == INVALID_ENGINE) break; cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type); if (cargo_type < NUM_CARGO) capacity[cargo_type] += cargo_capacity; } return capacity; } /** * Get the default cargoes and refits of an articulated vehicle. * The refits are linked to a cargo rather than an articulated part to prevent a long list of parts. * @param engine Model to investigate. * @param[out] cargoes Total amount of units that can be transported, summed by cargo. * @param[out] refits Whether a (possibly partial) refit for each cargo is possible. */ void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, uint32 *refits) { cargoes->Clear(); *refits = 0; const Engine *e = Engine::Get(engine); CargoID cargo_type; uint16 cargo_capacity = GetVehicleDefaultCapacity(engine, &cargo_type); if (cargo_type < NUM_CARGO && cargo_capacity > 0) { (*cargoes)[cargo_type] += cargo_capacity; if (IsEngineRefittable(engine)) SetBit(*refits, cargo_type); } if (!e->IsGroundVehicle() || !HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { EngineID artic_engine = GetNextArticulatedPart(i, engine); if (artic_engine == INVALID_ENGINE) break; cargo_capacity = GetVehicleDefaultCapacity(artic_engine, &cargo_type); if (cargo_type < NUM_CARGO && cargo_capacity > 0) { (*cargoes)[cargo_type] += cargo_capacity; if (IsEngineRefittable(artic_engine)) SetBit(*refits, cargo_type); } } } /** * Checks whether any of the articulated parts is refittable * @param engine the first part * @return true if refittable */ bool IsArticulatedVehicleRefittable(EngineID engine) { if (IsEngineRefittable(engine)) return true; const Engine *e = Engine::Get(engine); if (!e->IsGroundVehicle()) return false; if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return false; for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { EngineID artic_engine = GetNextArticulatedPart(i, engine); if (artic_engine == INVALID_ENGINE) break; if (IsEngineRefittable(artic_engine)) return true; } return false; } /** * Merges the refit_masks of all articulated parts. * @param engine the first part * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask * @param union_mask returns bit mask of CargoIDs which are a refit option for at least one articulated part * @param intersection_mask returns bit mask of CargoIDs which are a refit option for every articulated part (with default capacity > 0) */ void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, uint32 *union_mask, uint32 *intersection_mask) { const Engine *e = Engine::Get(engine); uint32 veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type); *union_mask = veh_cargoes; *intersection_mask = (veh_cargoes != 0) ? veh_cargoes : UINT32_MAX; if (!e->IsGroundVehicle()) return; if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { EngineID artic_engine = GetNextArticulatedPart(i, engine); if (artic_engine == INVALID_ENGINE) break; veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type); *union_mask |= veh_cargoes; if (veh_cargoes != 0) *intersection_mask &= veh_cargoes; } } /** * Ors the refit_masks of all articulated parts. * @param engine the first part * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask * @return bit mask of CargoIDs which are a refit option for at least one articulated part */ uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type) { uint32 union_mask, intersection_mask; GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask); return union_mask; } /** * Ands the refit_masks of all articulated parts. * @param engine the first part * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask * @return bit mask of CargoIDs which are a refit option for every articulated part (with default capacity > 0) */ uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type) { uint32 union_mask, intersection_mask; GetArticulatedRefitMasks(engine, include_initial_cargo_type, &union_mask, &intersection_mask); return intersection_mask; } /** * Tests if all parts of an articulated vehicle are refitted to the same cargo. * Note: Vehicles not carrying anything are ignored * @param v the first vehicle in the chain * @param cargo_type returns the common CargoID if needed. (CT_INVALID if no part is carrying something or they are carrying different things) * @return true if some parts are carrying different cargoes, false if all parts are carrying the same (nothing is also the same) */ bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type) { CargoID first_cargo = CT_INVALID; do { if (v->cargo_type != CT_INVALID && v->GetEngine()->CanCarryCargo()) { if (first_cargo == CT_INVALID) first_cargo = v->cargo_type; if (first_cargo != v->cargo_type) { if (cargo_type != NULL) *cargo_type = CT_INVALID; return true; } } v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL; } while (v != NULL); if (cargo_type != NULL) *cargo_type = first_cargo; return false; } /** * Checks whether the specs of freshly build articulated vehicles are consistent with the information specified in the purchase list. * Only essential information is checked to leave room for magic tricks/workarounds to grfcoders. * It checks: * For autoreplace/-renew: * - Default cargo type (without capacity) * - intersection and union of refit masks. */ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v) { const Engine *engine = v->GetEngine(); uint32 purchase_refit_union, purchase_refit_intersection; GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection); CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type); uint32 real_refit_union = 0; uint32 real_refit_intersection = UINT_MAX; CargoArray real_default_capacity; do { uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true); real_refit_union |= refit_mask; if (refit_mask != 0) real_refit_intersection &= refit_mask; assert(v->cargo_type < NUM_CARGO); real_default_capacity[v->cargo_type] += v->cargo_cap; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL; } while (v != NULL); /* Check whether the vehicle carries more cargoes than expected */ bool carries_more = false; for (CargoID cid = 0; cid < NUM_CARGO; cid++) { if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) { carries_more = true; break; } } /* show a warning once for each GRF after each game load */ if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) { ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false); } } /** * Add the remaining articulated parts to the given vehicle. * @param first The head of the articulated bit. */ void AddArticulatedParts(Vehicle *first) { VehicleType type = first->type; if (!HasBit(EngInfo(first->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; Vehicle *v = first; for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { bool flip_image; EngineID engine_type = GetNextArticulatedPart(i, first->engine_type, first, &flip_image); if (engine_type == INVALID_ENGINE) return; /* In the (very rare) case the GRF reported wrong number of articulated parts * and we run out of available vehicles, bail out. */ if (!Vehicle::CanAllocateItem()) return; GroundVehicleCache *gcache = v->GetGroundVehicleCache(); gcache->first_engine = v->engine_type; // Needs to be set before first callback const Engine *e_artic = Engine::Get(engine_type); switch (type) { default: NOT_REACHED(); case VEH_TRAIN: { Train *front = Train::From(first); Train *t = new Train(); v->SetNext(t); v = t; t->subtype = 0; t->track = front->track; t->railtype = front->railtype; t->spritenum = e_artic->u.rail.image_index; if (e_artic->CanCarryCargo()) { t->cargo_type = e_artic->GetDefaultCargoType(); t->cargo_cap = e_artic->u.rail.capacity; // Callback 36 is called when the consist is finished } else { t->cargo_type = front->cargo_type; // Needed for livery selection t->cargo_cap = 0; } t->refit_cap = 0; t->SetArticulatedPart(); break; } case VEH_ROAD: { RoadVehicle *front = RoadVehicle::From(first); RoadVehicle *rv = new RoadVehicle(); v->SetNext(rv); v = rv; rv->subtype = 0; gcache->cached_veh_length = VEHICLE_LENGTH; // Callback is called when the consist is finished rv->state = RVSB_IN_DEPOT; rv->roadtype = front->roadtype; rv->compatible_roadtypes = front->compatible_roadtypes; rv->spritenum = e_artic->u.road.image_index; if (e_artic->CanCarryCargo()) { rv->cargo_type = e_artic->GetDefaultCargoType(); rv->cargo_cap = e_artic->u.road.capacity; // Callback 36 is called when the consist is finished } else { rv->cargo_type = front->cargo_type; // Needed for livery selection rv->cargo_cap = 0; } rv->refit_cap = 0; rv->SetArticulatedPart(); break; } } /* get common values from first engine */ v->direction = first->direction; v->owner = first->owner; v->tile = first->tile; v->x_pos = first->x_pos; v->y_pos = first->y_pos; v->z_pos = first->z_pos; v->build_year = first->build_year; v->vehstatus = first->vehstatus & ~VS_STOPPED; v->cargo_subtype = 0; v->max_age = 0; v->engine_type = engine_type; v->value = 0; v->cur_image = SPR_IMG_QUERY; v->random_bits = VehicleRandomBits(); if (flip_image) v->spritenum++; v->UpdatePosition(); } } openttd-1.5.3/src/tile_map.h0000644000000000000000000002166412627373443014451 0ustar rootroot/* $Id: tile_map.h 27148 2015-02-14 12:53:07Z frosch $ */ /* * 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 tile_map.h Map writing/reading functions for tiles. */ #ifndef TILE_MAP_H #define TILE_MAP_H #include "slope_type.h" #include "map_func.h" #include "core/bitmath_func.hpp" #include "settings_type.h" /** * Returns the height of a tile * * This function returns the height of the northern corner of a tile. * This is saved in the global map-array. It does not take affect by * any slope-data of the tile. * * @param tile The tile to get the height from * @return the height of the tile * @pre tile < MapSize() */ static inline uint TileHeight(TileIndex tile) { assert(tile < MapSize()); return _m[tile].height; } uint TileHeightOutsideMap(int x, int y); /** * Sets the height of a tile. * * This function sets the height of the northern corner of a tile. * * @param tile The tile to change the height * @param height The new height value of the tile * @pre tile < MapSize() * @pre heigth <= MAX_TILE_HEIGHT */ static inline void SetTileHeight(TileIndex tile, uint height) { assert(tile < MapSize()); assert(height <= MAX_TILE_HEIGHT); _m[tile].height = height; } /** * Returns the height of a tile in pixels. * * This function returns the height of the northern corner of a tile in pixels. * * @param tile The tile to get the height * @return The height of the tile in pixel */ static inline uint TilePixelHeight(TileIndex tile) { return TileHeight(tile) * TILE_HEIGHT; } /** * Returns the tile height for a coordinate outside map. Such a height is * needed for painting the area outside map using completely black tiles. * The idea is descending to heightlevel 0 as fast as possible. * @param x The X-coordinate (same unit as TileX). * @param y The Y-coordinate (same unit as TileY). * @return The height in pixels in the same unit as TilePixelHeight. */ static inline uint TilePixelHeightOutsideMap(int x, int y) { return TileHeightOutsideMap(x, y) * TILE_HEIGHT; } /** * Get the tiletype of a given tile. * * @param tile The tile to get the TileType * @return The tiletype of the tile * @pre tile < MapSize() */ static inline TileType GetTileType(TileIndex tile) { assert(tile < MapSize()); return (TileType)GB(_m[tile].type, 4, 4); } /** * Check if a tile is within the map (not a border) * * @param tile The tile to check * @return Whether the tile is in the interior of the map * @pre tile < MapSize() */ static inline bool IsInnerTile(TileIndex tile) { assert(tile < MapSize()); uint x = TileX(tile); uint y = TileY(tile); return x < MapMaxX() && y < MapMaxY() && ((x > 0 && y > 0) || !_settings_game.construction.freeform_edges); } /** * Set the type of a tile * * This functions sets the type of a tile. If the type * MP_VOID is selected the tile must be at the south-west or * south-east edges of the map and vice versa. * * @param tile The tile to save the new type * @param type The type to save * @pre tile < MapSize() * @pre type MP_VOID <=> tile is on the south-east or south-west edge. */ static inline void SetTileType(TileIndex tile, TileType type) { assert(tile < MapSize()); /* VOID tiles (and no others) are exactly allowed at the lower left and right * edges of the map. If _settings_game.construction.freeform_edges is true, * the upper edges of the map are also VOID tiles. */ assert(IsInnerTile(tile) == (type != MP_VOID)); SB(_m[tile].type, 4, 4, type); } /** * Checks if a tile is a give tiletype. * * This function checks if a tile got the given tiletype. * * @param tile The tile to check * @param type The type to check against * @return true If the type matches against the type of the tile */ static inline bool IsTileType(TileIndex tile, TileType type) { return GetTileType(tile) == type; } /** * Checks if a tile is valid * * @param tile The tile to check * @return True if the tile is on the map and not one of MP_VOID. */ static inline bool IsValidTile(TileIndex tile) { return tile < MapSize() && !IsTileType(tile, MP_VOID); } /** * Returns the owner of a tile * * This function returns the owner of a tile. This cannot used * for tiles which type is one of MP_HOUSE, MP_VOID and MP_INDUSTRY * as no company owned any of these buildings. * * @param tile The tile to check * @return The owner of the tile * @pre IsValidTile(tile) * @pre The type of the tile must not be MP_HOUSE and MP_INDUSTRY */ static inline Owner GetTileOwner(TileIndex tile) { assert(IsValidTile(tile)); assert(!IsTileType(tile, MP_HOUSE)); assert(!IsTileType(tile, MP_INDUSTRY)); return (Owner)GB(_m[tile].m1, 0, 5); } /** * Sets the owner of a tile * * This function sets the owner status of a tile. Note that you cannot * set a owner for tiles of type MP_HOUSE, MP_VOID and MP_INDUSTRY. * * @param tile The tile to change the owner status. * @param owner The new owner. * @pre IsValidTile(tile) * @pre The type of the tile must not be MP_HOUSE and MP_INDUSTRY */ static inline void SetTileOwner(TileIndex tile, Owner owner) { assert(IsValidTile(tile)); assert(!IsTileType(tile, MP_HOUSE)); assert(!IsTileType(tile, MP_INDUSTRY)); SB(_m[tile].m1, 0, 5, owner); } /** * Checks if a tile belongs to the given owner * * @param tile The tile to check * @param owner The owner to check against * @return True if a tile belongs the the given owner */ static inline bool IsTileOwner(TileIndex tile, Owner owner) { return GetTileOwner(tile) == owner; } /** * Set the tropic zone * @param tile the tile to set the zone of * @param type the new type * @pre tile < MapSize() */ static inline void SetTropicZone(TileIndex tile, TropicZone type) { assert(tile < MapSize()); assert(!IsTileType(tile, MP_VOID) || type == TROPICZONE_NORMAL); SB(_m[tile].type, 0, 2, type); } /** * Get the tropic zone * @param tile the tile to get the zone of * @pre tile < MapSize() * @return the zone type */ static inline TropicZone GetTropicZone(TileIndex tile) { assert(tile < MapSize()); return (TropicZone)GB(_m[tile].type, 0, 2); } /** * Get the current animation frame * @param t the tile * @pre IsTileType(t, MP_HOUSE) || IsTileType(t, MP_OBJECT) || IsTileType(t, MP_INDUSTRY) ||IsTileType(t, MP_STATION) * @return frame number */ static inline byte GetAnimationFrame(TileIndex t) { assert(IsTileType(t, MP_HOUSE) || IsTileType(t, MP_OBJECT) || IsTileType(t, MP_INDUSTRY) ||IsTileType(t, MP_STATION)); return _me[t].m7; } /** * Set a new animation frame * @param t the tile * @param frame the new frame number * @pre IsTileType(t, MP_HOUSE) || IsTileType(t, MP_OBJECT) || IsTileType(t, MP_INDUSTRY) ||IsTileType(t, MP_STATION) */ static inline void SetAnimationFrame(TileIndex t, byte frame) { assert(IsTileType(t, MP_HOUSE) || IsTileType(t, MP_OBJECT) || IsTileType(t, MP_INDUSTRY) ||IsTileType(t, MP_STATION)); _me[t].m7 = frame; } Slope GetTileSlope(TileIndex tile, int *h = NULL); int GetTileZ(TileIndex tile); int GetTileMaxZ(TileIndex tile); bool IsTileFlat(TileIndex tile, int *h = NULL); /** * Return the slope of a given tile * @param tile Tile to compute slope of * @param h If not \c NULL, pointer to storage of z height * @return Slope of the tile, except for the HALFTILE part */ static inline Slope GetTilePixelSlope(TileIndex tile, int *h) { Slope s = GetTileSlope(tile, h); if (h != NULL) *h *= TILE_HEIGHT; return s; } Slope GetTilePixelSlopeOutsideMap(int x, int y, int *h); /** * Get bottom height of the tile * @param tile Tile to compute height of * @return Minimum height of the tile */ static inline int GetTilePixelZ(TileIndex tile) { return GetTileZ(tile) * TILE_HEIGHT; } int GetTilePixelZOutsideMap(int x, int y); /** * Get top height of the tile * @param t Tile to compute height of * @return Maximum height of the tile */ static inline int GetTileMaxPixelZ(TileIndex tile) { return GetTileMaxZ(tile) * TILE_HEIGHT; } int GetTileMaxPixelZOutsideMap(int x, int y); /** * Calculate a hash value from a tile position * * @param x The X coordinate * @param y The Y coordinate * @return The hash of the tile */ static inline uint TileHash(uint x, uint y) { uint hash = x >> 4; hash ^= x >> 6; hash ^= y >> 4; hash -= y >> 6; return hash; } /** * Get the last two bits of the TileHash * from a tile position. * * @see TileHash() * @param x The X coordinate * @param y The Y coordinate * @return The last two bits from hash of the tile */ static inline uint TileHash2Bit(uint x, uint y) { return GB(TileHash(x, y), 0, 2); } #endif /* TILE_MAP_H */ openttd-1.5.3/src/saveload/0000755000000000000000000000000012627373446014276 5ustar rootrootopenttd-1.5.3/src/saveload/signs_sl.cpp0000644000000000000000000000541712627373446016632 0ustar rootroot/* $Id: signs_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 signs_sl.cpp Code handling saving and loading of economy data */ #include "../stdafx.h" #include "../signs_base.h" #include "../fios.h" #include "saveload.h" #include "../safeguards.h" /** Description of a sign within the savegame. */ static const SaveLoad _sign_desc[] = { SLE_CONDVAR(Sign, name, SLE_NAME, 0, 83), SLE_CONDSTR(Sign, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION), SLE_CONDVAR(Sign, x, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), SLE_CONDVAR(Sign, y, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), SLE_CONDVAR(Sign, x, SLE_INT32, 5, SL_MAX_VERSION), SLE_CONDVAR(Sign, y, SLE_INT32, 5, SL_MAX_VERSION), SLE_CONDVAR(Sign, owner, SLE_UINT8, 6, SL_MAX_VERSION), SLE_CONDVAR(Sign, z, SLE_FILE_U8 | SLE_VAR_I32, 0, 163), SLE_CONDVAR(Sign, z, SLE_INT32, 164, SL_MAX_VERSION), SLE_END() }; /** Save all signs */ static void Save_SIGN() { Sign *si; FOR_ALL_SIGNS(si) { SlSetArrayIndex(si->index); SlObject(si, _sign_desc); } } /** Load all signs */ static void Load_SIGN() { int index; while ((index = SlIterateArray()) != -1) { Sign *si = new (index) Sign(); SlObject(si, _sign_desc); /* Before version 6.1, signs didn't have owner. * Before version 83, invalid signs were determined by si->str == 0. * Before version 103, owner could be a bankrupted company. * - we can't use IsValidCompany() now, so this is fixed in AfterLoadGame() * All signs that were saved are valid (including those with just 'Sign' and INVALID_OWNER). * - so set owner to OWNER_NONE if needed (signs from pre-version 6.1 would be lost) */ if (IsSavegameVersionBefore(6, 1) || (IsSavegameVersionBefore(83) && si->owner == INVALID_OWNER)) { si->owner = OWNER_NONE; } /* Signs placed in scenario editor shall now be OWNER_DEITY */ if (IsSavegameVersionBefore(171) && si->owner == OWNER_NONE && _saveload_mode == SLD_LOAD_SCENARIO) { si->owner = OWNER_DEITY; } } } /** Chunk handlers related to signs. */ extern const ChunkHandler _sign_chunk_handlers[] = { { 'SIGN', Save_SIGN, Load_SIGN, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/depot_sl.cpp0000644000000000000000000000425012627373446016614 0ustar rootroot/* $Id: depot_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 depot_sl.cpp Code handling saving and loading of depots */ #include "../stdafx.h" #include "../depot_base.h" #include "../town.h" #include "saveload.h" #include "../safeguards.h" static TownID _town_index; static const SaveLoad _depot_desc[] = { SLE_CONDVAR(Depot, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Depot, xy, SLE_UINT32, 6, SL_MAX_VERSION), SLEG_CONDVAR(_town_index, SLE_UINT16, 0, 140), SLE_CONDREF(Depot, town, REF_TOWN, 141, SL_MAX_VERSION), SLE_CONDVAR(Depot, town_cn, SLE_UINT16, 141, SL_MAX_VERSION), SLE_CONDSTR(Depot, name, SLE_STR, 0, 141, SL_MAX_VERSION), SLE_CONDVAR(Depot, build_date, SLE_INT32, 142, SL_MAX_VERSION), SLE_END() }; static void Save_DEPT() { Depot *depot; FOR_ALL_DEPOTS(depot) { SlSetArrayIndex(depot->index); SlObject(depot, _depot_desc); } } static void Load_DEPT() { int index; while ((index = SlIterateArray()) != -1) { Depot *depot = new (index) Depot(); SlObject(depot, _depot_desc); /* Set the town 'pointer' so we can restore it later. */ if (IsSavegameVersionBefore(141)) depot->town = (Town *)(size_t)_town_index; } } static void Ptrs_DEPT() { Depot *depot; FOR_ALL_DEPOTS(depot) { SlObject(depot, _depot_desc); if (IsSavegameVersionBefore(141)) depot->town = Town::Get((size_t)depot->town); } } extern const ChunkHandler _depot_chunk_handlers[] = { { 'DEPT', Save_DEPT, Load_DEPT, Ptrs_DEPT, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/vehicle_sl.cpp0000644000000000000000000011150512627373446017122 0ustar rootroot/* $Id: vehicle_sl.cpp 26872 2014-09-21 11:12:42Z rubidium $ */ /* * 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 vehicle_sl.cpp Code handling saving and loading of vehicles */ #include "../stdafx.h" #include "../vehicle_func.h" #include "../train.h" #include "../roadveh.h" #include "../ship.h" #include "../aircraft.h" #include "../station_base.h" #include "../effectvehicle_base.h" #include "../company_base.h" #include "../company_func.h" #include "../disaster_vehicle.h" #include "saveload.h" #include #include "../safeguards.h" /** * Link front and rear multiheaded engines to each other * This is done when loading a savegame */ void ConnectMultiheadedTrains() { Train *v; FOR_ALL_TRAINS(v) { v->other_multiheaded_part = NULL; } FOR_ALL_TRAINS(v) { if (v->IsFrontEngine() || v->IsFreeWagon()) { /* Two ways to associate multiheaded parts to each other: * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>.. * bracket-matching: Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>.. * * Note: Old savegames might contain chains which do not comply with these rules, e.g. * - the front and read parts have invalid orders * - different engine types might be combined * - there might be different amounts of front and rear parts. * * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur. * This is why two matching strategies are needed. */ bool sequential_matching = v->IsFrontEngine(); for (Train *u = v; u != NULL; u = u->GetNextVehicle()) { if (u->other_multiheaded_part != NULL) continue; // we already linked this one if (u->IsMultiheaded()) { if (!u->IsEngine()) { /* we got a rear car without a front car. We will convert it to a front one */ u->SetEngine(); u->spritenum--; } /* Find a matching back part */ EngineID eid = u->engine_type; Train *w; if (sequential_matching) { for (w = u->GetNextVehicle(); w != NULL; w = w->GetNextVehicle()) { if (w->engine_type != eid || w->other_multiheaded_part != NULL || !w->IsMultiheaded()) continue; /* we found a car to partner with this engine. Now we will make sure it face the right way */ if (w->IsEngine()) { w->ClearEngine(); w->spritenum++; } break; } } else { uint stack_pos = 0; for (w = u->GetNextVehicle(); w != NULL; w = w->GetNextVehicle()) { if (w->engine_type != eid || w->other_multiheaded_part != NULL || !w->IsMultiheaded()) continue; if (w->IsEngine()) { stack_pos++; } else { if (stack_pos == 0) break; stack_pos--; } } } if (w != NULL) { w->other_multiheaded_part = u; u->other_multiheaded_part = w; } else { /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */ u->ClearMultiheaded(); } } } } } } /** * Converts all trains to the new subtype format introduced in savegame 16.2 * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found */ void ConvertOldMultiheadToNew() { Train *t; FOR_ALL_TRAINS(t) SetBit(t->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop FOR_ALL_TRAINS(t) { if (HasBit(t->subtype, 7) && ((t->subtype & ~0x80) == 0 || (t->subtype & ~0x80) == 4)) { for (Train *u = t; u != NULL; u = u->Next()) { const RailVehicleInfo *rvi = RailVehInfo(u->engine_type); ClrBit(u->subtype, 7); switch (u->subtype) { case 0: // TS_Front_Engine if (rvi->railveh_type == RAILVEH_MULTIHEAD) u->SetMultiheaded(); u->SetFrontEngine(); u->SetEngine(); break; case 1: // TS_Artic_Part u->subtype = 0; u->SetArticulatedPart(); break; case 2: // TS_Not_First u->subtype = 0; if (rvi->railveh_type == RAILVEH_WAGON) { /* normal wagon */ u->SetWagon(); break; } if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) { /* rear end of a multiheaded engine */ u->SetMultiheaded(); break; } if (rvi->railveh_type == RAILVEH_MULTIHEAD) u->SetMultiheaded(); u->SetEngine(); break; case 4: // TS_Free_Car u->subtype = 0; u->SetWagon(); u->SetFreeWagon(); break; default: SlErrorCorrupt("Invalid train subtype"); } } } } } /** need to be called to load aircraft from old version */ void UpdateOldAircraft() { /* set airport_flags to 0 for all airports just to be sure */ Station *st; FOR_ALL_STATIONS(st) { st->airport.flags = 0; // reset airport } Aircraft *a; FOR_ALL_AIRCRAFT(a) { /* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor) * skip those */ if (a->IsNormalAircraft()) { /* airplane in terminal stopped doesn't hurt anyone, so goto next */ if ((a->vehstatus & VS_STOPPED) && a->state == 0) { a->state = HANGAR; continue; } AircraftLeaveHangar(a, a->direction); // make airplane visible if it was in a depot for example a->vehstatus &= ~VS_STOPPED; // make airplane moving UpdateAircraftCache(a); a->cur_speed = a->vcache.cached_max_speed; // so aircraft don't have zero speed while in air if (!a->current_order.IsType(OT_GOTO_STATION) && !a->current_order.IsType(OT_GOTO_DEPOT)) { /* reset current order so aircraft doesn't have invalid "station-only" order */ a->current_order.MakeDummy(); } a->state = FLYING; AircraftNextAirportPos_and_Order(a); // move it to the entry point of the airport GetNewVehiclePosResult gp = GetNewVehiclePos(a); a->tile = 0; // aircraft in air is tile=0 /* correct speed of helicopter-rotors */ if (a->subtype == AIR_HELICOPTER) a->Next()->Next()->cur_speed = 32; /* set new position x,y,z */ GetAircraftFlightLevelBounds(a, &a->z_pos, NULL); SetAircraftPosition(a, gp.x, gp.y, GetAircraftFlightLevel(a)); } } } /** * Check all vehicles to ensure their engine type is valid * for the currently loaded NewGRFs (that includes none...) * This only makes a difference if NewGRFs are missing, otherwise * all vehicles will be valid. This does not make such a game * playable, it only prevents crash. */ static void CheckValidVehicles() { size_t total_engines = Engine::GetPoolSize(); EngineID first_engine[4] = { INVALID_ENGINE, INVALID_ENGINE, INVALID_ENGINE, INVALID_ENGINE }; Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { first_engine[VEH_TRAIN] = e->index; break; } FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { first_engine[VEH_ROAD] = e->index; break; } FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) { first_engine[VEH_SHIP] = e->index; break; } FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) { first_engine[VEH_AIRCRAFT] = e->index; break; } Vehicle *v; FOR_ALL_VEHICLES(v) { /* Test if engine types match */ switch (v->type) { case VEH_TRAIN: case VEH_ROAD: case VEH_SHIP: case VEH_AIRCRAFT: if (v->engine_type >= total_engines || v->type != v->GetEngine()->type) { v->engine_type = first_engine[v->type]; } break; default: break; } } } extern byte _age_cargo_skip_counter; // From misc_sl.cpp /** Called after load to update coordinates */ void AfterLoadVehicles(bool part_of_load) { Vehicle *v; FOR_ALL_VEHICLES(v) { /* Reinstate the previous pointer */ if (v->Next() != NULL) v->Next()->previous = v; if (v->NextShared() != NULL) v->NextShared()->previous_shared = v; if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID; v->first = NULL; if (v->IsGroundVehicle()) v->GetGroundVehicleCache()->first_engine = INVALID_ENGINE; } /* AfterLoadVehicles may also be called in case of NewGRF reload, in this * case we may not convert orders again. */ if (part_of_load) { /* Create shared vehicle chain for very old games (pre 5,2) and create * OrderList from shared vehicle chains. For this to work correctly, the * following conditions must be fulfilled: * a) both next_shared and previous_shared are not set for pre 5,2 games * b) both next_shared and previous_shared are set for later games */ std::map mapping; FOR_ALL_VEHICLES(v) { if (v->orders.old != NULL) { if (IsSavegameVersionBefore(105)) { // Pre-105 didn't save an OrderList if (mapping[v->orders.old] == NULL) { /* This adds the whole shared vehicle chain for case b */ /* Creating an OrderList here is safe because the number of vehicles * allowed in these savegames matches the number of OrderLists. As * such each vehicle can get an OrderList and it will (still) fit. */ assert(OrderList::CanAllocateItem()); v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v); } else { v->orders.list = mapping[v->orders.old]; /* For old games (case a) we must create the shared vehicle chain */ if (IsSavegameVersionBefore(5, 2)) { v->AddToShared(v->orders.list->GetFirstSharedVehicle()); } } } else { // OrderList was saved as such, only recalculate not saved values if (v->PreviousShared() == NULL) { v->orders.list->Initialize(v->orders.list->first, v); } } } } } FOR_ALL_VEHICLES(v) { /* Fill the first pointers */ if (v->Previous() == NULL) { for (Vehicle *u = v; u != NULL; u = u->Next()) { u->first = v; } } } if (part_of_load) { if (IsSavegameVersionBefore(105)) { /* Before 105 there was no order for shared orders, thus it messed up horribly */ FOR_ALL_VEHICLES(v) { if (v->First() != v || v->orders.list != NULL || v->previous_shared != NULL || v->next_shared == NULL) continue; /* As above, allocating OrderList here is safe. */ assert(OrderList::CanAllocateItem()); v->orders.list = new OrderList(NULL, v); for (Vehicle *u = v; u != NULL; u = u->next_shared) { u->orders.list = v->orders.list; } } } if (IsSavegameVersionBefore(157)) { /* The road vehicle subtype was converted to a flag. */ RoadVehicle *rv; FOR_ALL_ROADVEHICLES(rv) { if (rv->subtype == 0) { /* The road vehicle is at the front. */ rv->SetFrontEngine(); } else if (rv->subtype == 1) { /* The road vehicle is an articulated part. */ rv->subtype = 0; rv->SetArticulatedPart(); } else { SlErrorCorrupt("Invalid road vehicle subtype"); } } } if (IsSavegameVersionBefore(160)) { /* In some old savegames there might be some "crap" stored. */ FOR_ALL_VEHICLES(v) { if (!v->IsPrimaryVehicle() && v->type != VEH_DISASTER) { v->current_order.Free(); v->unitnumber = 0; } } } if (IsSavegameVersionBefore(162)) { /* Set the vehicle-local cargo age counter from the old global counter. */ FOR_ALL_VEHICLES(v) { v->cargo_age_counter = _age_cargo_skip_counter; } } if (IsSavegameVersionBefore(180)) { /* Set service interval flags */ FOR_ALL_VEHICLES(v) { if (!v->IsPrimaryVehicle()) continue; const Company *c = Company::Get(v->owner); int interval = CompanyServiceInterval(c, v->type); v->SetServiceIntervalIsCustom(v->GetServiceInterval() != interval); v->SetServiceIntervalIsPercent(c->settings.vehicle.servint_ispercent); } } } CheckValidVehicles(); FOR_ALL_VEHICLES(v) { assert(v->first != NULL); switch (v->type) { case VEH_TRAIN: { Train *t = Train::From(v); if (t->IsFrontEngine() || t->IsFreeWagon()) { t->gcache.last_speed = t->cur_speed; // update displayed train speed t->ConsistChanged(CCF_SAVELOAD); } break; } case VEH_ROAD: { RoadVehicle *rv = RoadVehicle::From(v); if (rv->IsFrontEngine()) { rv->gcache.last_speed = rv->cur_speed; // update displayed road vehicle speed RoadVehUpdateCache(rv); if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { rv->CargoChanged(); } } break; } case VEH_SHIP: Ship::From(v)->UpdateCache(); break; default: break; } } /* Stop non-front engines */ if (part_of_load && IsSavegameVersionBefore(112)) { FOR_ALL_VEHICLES(v) { if (v->type == VEH_TRAIN) { Train *t = Train::From(v); if (!t->IsFrontEngine()) { if (t->IsEngine()) t->vehstatus |= VS_STOPPED; /* cur_speed is now relevant for non-front parts - nonzero breaks * moving-wagons-inside-depot- and autoreplace- code */ t->cur_speed = 0; } } /* trains weren't stopping gradually in old OTTD versions (and TTO/TTD) * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */ if ((v->vehstatus & VS_STOPPED) && (v->type != VEH_TRAIN || IsSavegameVersionBefore(2, 1))) { v->cur_speed = 0; } } } FOR_ALL_VEHICLES(v) { switch (v->type) { case VEH_ROAD: { RoadVehicle *rv = RoadVehicle::From(v); rv->roadtype = HasBit(EngInfo(v->First()->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; rv->compatible_roadtypes = RoadTypeToRoadTypes(rv->roadtype); /* FALL THROUGH */ } case VEH_TRAIN: case VEH_SHIP: v->cur_image = v->GetImage(v->direction, EIT_ON_MAP); break; case VEH_AIRCRAFT: if (Aircraft::From(v)->IsNormalAircraft()) { v->cur_image = v->GetImage(v->direction, EIT_ON_MAP); /* The plane's shadow will have the same image as the plane */ Vehicle *shadow = v->Next(); shadow->cur_image = v->cur_image; /* In the case of a helicopter we will update the rotor sprites */ if (v->subtype == AIR_HELICOPTER) { Vehicle *rotor = shadow->Next(); rotor->cur_image = GetRotorImage(Aircraft::From(v), EIT_ON_MAP); } UpdateAircraftCache(Aircraft::From(v), true); } break; default: break; } v->UpdateDeltaXY(v->direction); v->coord.left = INVALID_COORD; v->UpdatePosition(); v->UpdateViewport(false); } } bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // From train_cmd.cpp void ReverseTrainDirection(Train *v); void ReverseTrainSwapVeh(Train *v, int l, int r); /** Fixup old train spacing. */ void FixupTrainLengths() { /* Vehicle center was moved from 4 units behind the front to half the length * behind the front. Move vehicles so they end up on the same spot. */ Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->type == VEH_TRAIN && v->IsPrimaryVehicle()) { /* The vehicle center is now more to the front depending on vehicle length, * so we need to move all vehicles forward to cover the difference to the * old center, otherwise wagon spacing in trains would be broken upon load. */ for (Train *u = Train::From(v); u != NULL; u = u->Next()) { if (u->track == TRACK_BIT_DEPOT || (u->vehstatus & VS_CRASHED)) continue; Train *next = u->Next(); /* Try to pull the vehicle half its length forward. */ int diff = (VEHICLE_LENGTH - u->gcache.cached_veh_length) / 2; int done; for (done = 0; done < diff; done++) { if (!TrainController(u, next, false)) break; } if (next != NULL && done < diff && u->IsFrontEngine()) { /* Pulling the front vehicle forwards failed, we either encountered a dead-end * or a red signal. To fix this, we try to move the whole train the required * space backwards and re-do the fix up of the front vehicle. */ /* Ignore any signals when backtracking. */ TrainForceProceeding old_tfp = u->force_proceed; u->force_proceed = TFP_SIGNAL; /* Swap start<>end, start+1<>end-1, ... */ int r = CountVehiclesInChain(u) - 1; // number of vehicles - 1 int l = 0; do ReverseTrainSwapVeh(u, l++, r--); while (l <= r); /* We moved the first vehicle which is now the last. Move it back to the * original position as we will fix up the last vehicle later in the loop. */ for (int i = 0; i < done; i++) TrainController(u->Last(), NULL); /* Move the train backwards to get space for the first vehicle. As the stopping * distance from a line end is rounded up, move the train one unit more to cater * for front vehicles with odd lengths. */ int moved; for (moved = 0; moved < diff + 1; moved++) { if (!TrainController(u, NULL, false)) break; } /* Swap start<>end, start+1<>end-1, ... again. */ r = CountVehiclesInChain(u) - 1; // number of vehicles - 1 l = 0; do ReverseTrainSwapVeh(u, l++, r--); while (l <= r); u->force_proceed = old_tfp; /* Tracks are too short to fix the train length. The player has to fix the * train in a depot. Bail out so we don't damage the vehicle chain any more. */ if (moved < diff + 1) break; /* Re-do the correction for the first vehicle. */ for (done = 0; done < diff; done++) TrainController(u, next, false); /* We moved one unit more backwards than needed for even-length front vehicles, * try to move that unit forward again. We don't care if this step fails. */ TrainController(u, NULL, false); } /* If the next wagon is still in a depot, check if it shouldn't be outside already. */ if (next != NULL && next->track == TRACK_BIT_DEPOT) { int d = TicksToLeaveDepot(u); if (d <= 0) { /* Next vehicle should have left the depot already, show it and pull forward. */ next->vehstatus &= ~VS_HIDDEN; next->track = TrackToTrackBits(GetRailDepotTrack(next->tile)); for (int i = 0; i >= d; i--) TrainController(next, NULL); } } } /* Update all cached properties after moving the vehicle chain around. */ Train::From(v)->ConsistChanged(CCF_TRACK); } } } static uint8 _cargo_days; static uint16 _cargo_source; static uint32 _cargo_source_xy; static uint16 _cargo_count; static uint16 _cargo_paid_for; static Money _cargo_feeder_share; static uint32 _cargo_loaded_at_xy; /** * Make it possible to make the saveload tables "friends" of other classes. * @param vt the vehicle type. Can be VEH_END for the common vehicle description data * @return the saveload description */ const SaveLoad *GetVehicleDescription(VehicleType vt) { /** Save and load of vehicles */ static const SaveLoad _common_veh_desc[] = { SLE_VAR(Vehicle, subtype, SLE_UINT8), SLE_REF(Vehicle, next, REF_VEHICLE_OLD), SLE_CONDVAR(Vehicle, name, SLE_NAME, 0, 83), SLE_CONDSTR(Vehicle, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, unitnumber, SLE_FILE_U8 | SLE_VAR_U16, 0, 7), SLE_CONDVAR(Vehicle, unitnumber, SLE_UINT16, 8, SL_MAX_VERSION), SLE_VAR(Vehicle, owner, SLE_UINT8), SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Vehicle, x_pos, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Vehicle, y_pos, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, 0, 163), SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, 164, SL_MAX_VERSION), SLE_VAR(Vehicle, direction, SLE_UINT8), SLE_CONDNULL(2, 0, 57), SLE_VAR(Vehicle, spritenum, SLE_UINT8), SLE_CONDNULL(5, 0, 57), SLE_VAR(Vehicle, engine_type, SLE_UINT16), SLE_CONDNULL(2, 0, 151), SLE_VAR(Vehicle, cur_speed, SLE_UINT16), SLE_VAR(Vehicle, subspeed, SLE_UINT8), SLE_VAR(Vehicle, acceleration, SLE_UINT8), SLE_VAR(Vehicle, progress, SLE_UINT8), SLE_VAR(Vehicle, vehstatus, SLE_UINT8), SLE_CONDVAR(Vehicle, last_station_visited, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), SLE_CONDVAR(Vehicle, last_station_visited, SLE_UINT16, 5, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, last_loading_station, SLE_UINT16, 182, SL_MAX_VERSION), SLE_VAR(Vehicle, cargo_type, SLE_UINT8), SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, 35, SL_MAX_VERSION), SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67), SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6), SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67), SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67), SLE_VAR(Vehicle, cargo_cap, SLE_UINT16), SLE_CONDVAR(Vehicle, refit_cap, SLE_UINT16, 182, SL_MAX_VERSION), SLEG_CONDVAR( _cargo_count, SLE_UINT16, 0, 67), SLE_CONDLST(Vehicle, cargo.packets, REF_CARGO_PACKET, 68, SL_MAX_VERSION), SLE_CONDARR(Vehicle, cargo.action_counts, SLE_UINT, VehicleCargoList::NUM_MOVE_TO_ACTION, 181, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, cargo_age_counter, SLE_UINT16, 162, SL_MAX_VERSION), SLE_VAR(Vehicle, day_counter, SLE_UINT8), SLE_VAR(Vehicle, tick_counter, SLE_UINT8), SLE_CONDVAR(Vehicle, running_ticks, SLE_UINT8, 88, SL_MAX_VERSION), SLE_VAR(Vehicle, cur_implicit_order_index, SLE_UINT8), SLE_CONDVAR(Vehicle, cur_real_order_index, SLE_UINT8, 158, SL_MAX_VERSION), /* num_orders is now part of OrderList and is not saved but counted */ SLE_CONDNULL(1, 0, 104), /* This next line is for version 4 and prior compatibility.. it temporarily reads type and flags (which were both 4 bits) into type. Later on this is converted correctly */ SLE_CONDVAR(Vehicle, current_order.type, SLE_UINT8, 0, 4), SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), /* Orders for version 5 and on */ SLE_CONDVAR(Vehicle, current_order.type, SLE_UINT8, 5, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, current_order.flags, SLE_UINT8, 5, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, 5, SL_MAX_VERSION), /* Refit in current order */ SLE_CONDVAR(Vehicle, current_order.refit_cargo, SLE_UINT8, 36, SL_MAX_VERSION), SLE_CONDNULL(1, 36, 181), // refit_subtype /* Timetable in current order */ SLE_CONDVAR(Vehicle, current_order.wait_time, SLE_UINT16, 67, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, current_order.travel_time, SLE_UINT16, 67, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, current_order.max_speed, SLE_UINT16, 174, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, timetable_start, SLE_INT32, 129, SL_MAX_VERSION), SLE_CONDREF(Vehicle, orders, REF_ORDER, 0, 104), SLE_CONDREF(Vehicle, orders, REF_ORDERLIST, 105, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, max_age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, max_age, SLE_INT32, 31, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, date_of_last_service, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, date_of_last_service, SLE_INT32, 31, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, 0, 30), SLE_CONDVAR(Vehicle, service_interval, SLE_FILE_U32 | SLE_VAR_U16, 31, 179), SLE_CONDVAR(Vehicle, service_interval, SLE_UINT16, 180, SL_MAX_VERSION), SLE_VAR(Vehicle, reliability, SLE_UINT16), SLE_VAR(Vehicle, reliability_spd_dec, SLE_UINT16), SLE_VAR(Vehicle, breakdown_ctr, SLE_UINT8), SLE_VAR(Vehicle, breakdown_delay, SLE_UINT8), SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8), SLE_VAR(Vehicle, breakdown_chance, SLE_UINT8), SLE_CONDVAR(Vehicle, build_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, build_year, SLE_INT32, 31, SL_MAX_VERSION), SLE_VAR(Vehicle, load_unload_ticks, SLE_UINT16), SLEG_CONDVAR( _cargo_paid_for, SLE_UINT16, 45, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, 40, 179), SLE_CONDVAR(Vehicle, vehicle_flags, SLE_UINT16, 180, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, profit_this_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), SLE_CONDVAR(Vehicle, profit_this_year, SLE_INT64, 65, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, profit_last_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, 65, SL_MAX_VERSION), SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64, 51, 64), SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), SLEG_CONDVAR( _cargo_loaded_at_xy, SLE_UINT32, 51, 67), SLE_CONDVAR(Vehicle, value, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), SLE_CONDVAR(Vehicle, value, SLE_INT64, 65, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, random_bits, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, waiting_triggers, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDREF(Vehicle, next_shared, REF_VEHICLE, 2, SL_MAX_VERSION), SLE_CONDNULL(2, 2, 68), SLE_CONDNULL(4, 69, 100), SLE_CONDVAR(Vehicle, group_id, SLE_UINT16, 60, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, current_order_time, SLE_UINT32, 67, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, lateness_counter, SLE_INT32, 67, SL_MAX_VERSION), SLE_CONDNULL(10, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _train_desc[] = { SLE_WRITEBYTE(Vehicle, type, VEH_TRAIN), SLE_VEH_INCLUDE(), SLE_VAR(Train, crash_anim_pos, SLE_UINT16), SLE_VAR(Train, force_proceed, SLE_UINT8), SLE_VAR(Train, railtype, SLE_UINT8), SLE_VAR(Train, track, SLE_UINT8), SLE_CONDVAR(Train, flags, SLE_FILE_U8 | SLE_VAR_U16, 2, 99), SLE_CONDVAR(Train, flags, SLE_UINT16, 100, SL_MAX_VERSION), SLE_CONDNULL(2, 2, 59), SLE_CONDVAR(Train, wait_counter, SLE_UINT16, 136, SL_MAX_VERSION), SLE_CONDNULL(2, 2, 19), SLE_CONDVAR(Train, gv_flags, SLE_UINT16, 139, SL_MAX_VERSION), SLE_CONDNULL(11, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _roadveh_desc[] = { SLE_WRITEBYTE(Vehicle, type, VEH_ROAD), SLE_VEH_INCLUDE(), SLE_VAR(RoadVehicle, state, SLE_UINT8), SLE_VAR(RoadVehicle, frame, SLE_UINT8), SLE_VAR(RoadVehicle, blocked_ctr, SLE_UINT16), SLE_VAR(RoadVehicle, overtaking, SLE_UINT8), SLE_VAR(RoadVehicle, overtaking_ctr, SLE_UINT8), SLE_VAR(RoadVehicle, crashed_ctr, SLE_UINT16), SLE_VAR(RoadVehicle, reverse_ctr, SLE_UINT8), SLE_CONDNULL(2, 6, 68), SLE_CONDVAR(RoadVehicle, gv_flags, SLE_UINT16, 139, SL_MAX_VERSION), SLE_CONDNULL(4, 69, 130), SLE_CONDNULL(2, 6, 130), SLE_CONDNULL(16, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _ship_desc[] = { SLE_WRITEBYTE(Vehicle, type, VEH_SHIP), SLE_VEH_INCLUDE(), SLE_VAR(Ship, state, SLE_UINT8), SLE_CONDNULL(16, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _aircraft_desc[] = { SLE_WRITEBYTE(Vehicle, type, VEH_AIRCRAFT), SLE_VEH_INCLUDE(), SLE_VAR(Aircraft, crashed_counter, SLE_UINT16), SLE_VAR(Aircraft, pos, SLE_UINT8), SLE_CONDVAR(Aircraft, targetairport, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), SLE_CONDVAR(Aircraft, targetairport, SLE_UINT16, 5, SL_MAX_VERSION), SLE_VAR(Aircraft, state, SLE_UINT8), SLE_CONDVAR(Aircraft, previous_pos, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDVAR(Aircraft, last_direction, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDVAR(Aircraft, number_consecutive_turns, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDVAR(Aircraft, turn_counter, SLE_UINT8, 136, SL_MAX_VERSION), SLE_CONDVAR(Aircraft, flags, SLE_UINT8, 167, SL_MAX_VERSION), SLE_CONDNULL(13, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _special_desc[] = { SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT), SLE_VAR(Vehicle, subtype, SLE_UINT8), SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, 0, 163), SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, 164, SL_MAX_VERSION), SLE_VAR(Vehicle, cur_image, SLE_FILE_U16 | SLE_VAR_U32), SLE_CONDNULL(5, 0, 57), SLE_VAR(Vehicle, progress, SLE_UINT8), SLE_VAR(Vehicle, vehstatus, SLE_UINT8), SLE_VAR(EffectVehicle, animation_state, SLE_UINT16), SLE_VAR(EffectVehicle, animation_substate, SLE_UINT8), SLE_CONDVAR(Vehicle, spritenum, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDNULL(15, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _disaster_desc[] = { SLE_WRITEBYTE(Vehicle, type, VEH_DISASTER), SLE_REF(Vehicle, next, REF_VEHICLE_OLD), SLE_VAR(Vehicle, subtype, SLE_UINT8), SLE_CONDVAR(Vehicle, tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Vehicle, tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, dest_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Vehicle, dest_tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, x_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), SLE_CONDVAR(Vehicle, x_pos, SLE_INT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, y_pos, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), SLE_CONDVAR(Vehicle, y_pos, SLE_INT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, 0, 163), SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, 164, SL_MAX_VERSION), SLE_VAR(Vehicle, direction, SLE_UINT8), SLE_CONDNULL(5, 0, 57), SLE_VAR(Vehicle, owner, SLE_UINT8), SLE_VAR(Vehicle, vehstatus, SLE_UINT8), SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, 5, SL_MAX_VERSION), SLE_VAR(Vehicle, cur_image, SLE_FILE_U16 | SLE_VAR_U32), SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), SLE_VAR(Vehicle, tick_counter, SLE_UINT8), SLE_CONDVAR(DisasterVehicle, image_override, SLE_FILE_U16 | SLE_VAR_U32, 0, 190), SLE_CONDVAR(DisasterVehicle, image_override, SLE_UINT32, 191, SL_MAX_VERSION), SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target, SLE_FILE_U16 | SLE_VAR_U32, 0, 190), SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target, SLE_UINT32, 191, SL_MAX_VERSION), SLE_CONDVAR(DisasterVehicle, flags, SLE_UINT8, 194, SL_MAX_VERSION), SLE_CONDNULL(16, 2, 143), // old reserved space SLE_END() }; static const SaveLoad * const _veh_descs[] = { _train_desc, _roadveh_desc, _ship_desc, _aircraft_desc, _special_desc, _disaster_desc, _common_veh_desc, }; return _veh_descs[vt]; } /** Will be called when the vehicles need to be saved. */ static void Save_VEHS() { Vehicle *v; /* Write the vehicles */ FOR_ALL_VEHICLES(v) { SlSetArrayIndex(v->index); SlObject(v, GetVehicleDescription(v->type)); } } /** Will be called when vehicles need to be loaded. */ void Load_VEHS() { int index; _cargo_count = 0; while ((index = SlIterateArray()) != -1) { Vehicle *v; VehicleType vtype = (VehicleType)SlReadByte(); switch (vtype) { case VEH_TRAIN: v = new (index) Train(); break; case VEH_ROAD: v = new (index) RoadVehicle(); break; case VEH_SHIP: v = new (index) Ship(); break; case VEH_AIRCRAFT: v = new (index) Aircraft(); break; case VEH_EFFECT: v = new (index) EffectVehicle(); break; case VEH_DISASTER: v = new (index) DisasterVehicle(); break; case VEH_INVALID: // Savegame shouldn't contain invalid vehicles default: SlErrorCorrupt("Invalid vehicle type"); } SlObject(v, GetVehicleDescription(vtype)); if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) { /* Don't construct the packet with station here, because that'll fail with old savegames */ CargoPacket *cp = new CargoPacket(_cargo_count, _cargo_days, _cargo_source, _cargo_source_xy, _cargo_loaded_at_xy, _cargo_feeder_share); v->cargo.Append(cp); } /* Old savegames used 'last_station_visited = 0xFF' */ if (IsSavegameVersionBefore(5) && v->last_station_visited == 0xFF) { v->last_station_visited = INVALID_STATION; } if (IsSavegameVersionBefore(182)) v->last_loading_station = INVALID_STATION; if (IsSavegameVersionBefore(5)) { /* Convert the current_order.type (which is a mix of type and flags, because * in those versions, they both were 4 bits big) to type and flags */ v->current_order.flags = GB(v->current_order.type, 4, 4); v->current_order.type &= 0x0F; } /* Advanced vehicle lists got added */ if (IsSavegameVersionBefore(60)) v->group_id = DEFAULT_GROUP; } } static void Ptrs_VEHS() { Vehicle *v; FOR_ALL_VEHICLES(v) { SlObject(v, GetVehicleDescription(v->type)); } } extern const ChunkHandler _veh_chunk_handlers[] = { { 'VEHS', Save_VEHS, Load_VEHS, Ptrs_VEHS, NULL, CH_SPARSE_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/newgrf_sl.h0000644000000000000000000000170512627373446016440 0ustar rootroot/* $Id: newgrf_sl.h 21886 2011-01-22 09:53:15Z rubidium $ */ /* * 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 newgrf_sl.h Code handling saving and loading of NewGRF mappings. */ #ifndef SAVELOAD_NEWGRF_SL_H #define SAVELOAD_NEWGRF_SL_H #include "../newgrf_commons.h" void Save_NewGRFMapping(const OverrideManagerBase &mapping); void Load_NewGRFMapping(OverrideManagerBase &mapping); #endif /* SAVELOAD_NEWGRF_SL_H */ openttd-1.5.3/src/saveload/strings_sl.cpp0000644000000000000000000001102112627373446017164 0ustar rootroot/* $Id: strings_sl.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 strings_sl.cpp Code handling saving and loading of strings */ #include "../stdafx.h" #include "../string_func.h" #include "saveload_internal.h" #include "table/strings.h" #include "../safeguards.h" static const int NUM_OLD_STRINGS = 512; ///< The number of custom strings stored in old savegames. static const int LEN_OLD_STRINGS = 32; ///< The number of characters per string. static const int LEN_OLD_STRINGS_TTO = 24; ///< The number of characters per string in TTO savegames. /** * Remap a string ID from the old format to the new format * @param s StringID that requires remapping * @return translated ID */ StringID RemapOldStringID(StringID s) { switch (s) { case 0x0006: return STR_SV_EMPTY; case 0x7000: return STR_SV_UNNAMED; case 0x70E4: return SPECSTR_COMPANY_NAME_START; case 0x70E9: return SPECSTR_COMPANY_NAME_START; case 0x8864: return STR_SV_TRAIN_NAME; case 0x902B: return STR_SV_ROAD_VEHICLE_NAME; case 0x9830: return STR_SV_SHIP_NAME; case 0xA02F: return STR_SV_AIRCRAFT_NAME; default: if (IsInsideMM(s, 0x300F, 0x3030)) { return s - 0x300F + STR_SV_STNAME; } else { return s; } } } /** Location to load the old names to. */ char *_old_name_array = NULL; /** * Copy and convert old custom names to UTF-8. * They were all stored in a 512 by 32 (200 by 24 for TTO) long string array * and are now stored with stations, waypoints and other places with names. * @param id the StringID of the custom name to clone. * @return the clones custom name. */ char *CopyFromOldName(StringID id) { /* Is this name an (old) custom name? */ if (GB(id, 11, 5) != 15) return NULL; if (IsSavegameVersionBefore(37)) { /* Allow for expansion when converted to UTF-8. */ char tmp[LEN_OLD_STRINGS * MAX_CHAR_LENGTH]; uint offs = _savegame_type == SGT_TTO ? LEN_OLD_STRINGS_TTO * GB(id, 0, 8) : LEN_OLD_STRINGS * GB(id, 0, 9); const char *strfrom = &_old_name_array[offs]; char *strto = tmp; for (; *strfrom != '\0'; strfrom++) { WChar c = (byte)*strfrom; /* Map from non-ISO8859-15 characters to UTF-8. */ switch (c) { case 0xA4: c = 0x20AC; break; // Euro case 0xA6: c = 0x0160; break; // S with caron case 0xA8: c = 0x0161; break; // s with caron case 0xB4: c = 0x017D; break; // Z with caron case 0xB8: c = 0x017E; break; // z with caron case 0xBC: c = 0x0152; break; // OE ligature case 0xBD: c = 0x0153; break; // oe ligature case 0xBE: c = 0x0178; break; // Y with diaresis default: break; } /* Check character will fit into our buffer. */ if (strto + Utf8CharLen(c) > lastof(tmp)) break; strto += Utf8Encode(strto, c); } /* Terminate the new string and copy it back to the name array */ *strto = '\0'; return stredup(tmp); } else { /* Name will already be in UTF-8. */ return stredup(&_old_name_array[LEN_OLD_STRINGS * GB(id, 0, 9)]); } } /** * Free the memory of the old names array. * Should be called once the old names have all been converted. */ void ResetOldNames() { free(_old_name_array); _old_name_array = NULL; } /** * Initialize the old names table memory. */ void InitializeOldNames() { free(_old_name_array); _old_name_array = CallocT(NUM_OLD_STRINGS * LEN_OLD_STRINGS); // 200 * 24 would be enough for TTO savegames } /** * Load the NAME chunk. */ static void Load_NAME() { int index; while ((index = SlIterateArray()) != -1) { if (index >= NUM_OLD_STRINGS) SlErrorCorrupt("Invalid old name index"); if (SlGetFieldLength() > (uint)LEN_OLD_STRINGS) SlErrorCorrupt("Invalid old name length"); SlArray(&_old_name_array[LEN_OLD_STRINGS * index], SlGetFieldLength(), SLE_UINT8); /* Make sure the old name is null terminated */ _old_name_array[LEN_OLD_STRINGS * index + LEN_OLD_STRINGS - 1] = '\0'; } } /** Chunk handlers related to strings. */ extern const ChunkHandler _name_chunk_handlers[] = { { 'NAME', NULL, Load_NAME, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/map_sl.cpp0000644000000000000000000001672612627373446016271 0ustar rootroot/* $Id: map_sl.cpp 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 map_sl.cpp Code handling saving and loading of map */ #include "../stdafx.h" #include "../map_func.h" #include "../core/bitmath_func.hpp" #include "../fios.h" #include "saveload.h" #include "../safeguards.h" static uint32 _map_dim_x; static uint32 _map_dim_y; static const SaveLoadGlobVarList _map_dimensions[] = { SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION), SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION), SLEG_END() }; static void Save_MAPS() { _map_dim_x = MapSizeX(); _map_dim_y = MapSizeY(); SlGlobList(_map_dimensions); } static void Load_MAPS() { SlGlobList(_map_dimensions); AllocateMap(_map_dim_x, _map_dim_y); } static void Check_MAPS() { SlGlobList(_map_dimensions); _load_check_data.map_size_x = _map_dim_x; _load_check_data.map_size_y = _map_dim_y; } static const uint MAP_SL_BUF_SIZE = 4096; static void Load_MAPT() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].type = buf[j]; } } static void Save_MAPT() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].type; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAPH() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].height = buf[j]; } } static void Save_MAPH() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].height; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP1() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m1 = buf[j]; } } static void Save_MAP1() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m1; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP2() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, /* In those versions the m2 was 8 bits */ IsSavegameVersionBefore(5) ? SLE_FILE_U8 | SLE_VAR_U16 : SLE_UINT16 ); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m2 = buf[j]; } } static void Save_MAP2() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size * sizeof(uint16)); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m2; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT16); } } static void Load_MAP3() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m3 = buf[j]; } } static void Save_MAP3() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m3; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP4() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m4 = buf[j]; } } static void Save_MAP4() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m4; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP5() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _m[i++].m5 = buf[j]; } } static void Save_MAP5() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _m[i++].m5; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP6() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); if (IsSavegameVersionBefore(42)) { for (TileIndex i = 0; i != size;) { /* 1024, otherwise we overflow on 64x64 maps! */ SlArray(buf, 1024, SLE_UINT8); for (uint j = 0; j != 1024; j++) { _me[i++].m6 = GB(buf[j], 0, 2); _me[i++].m6 = GB(buf[j], 2, 2); _me[i++].m6 = GB(buf[j], 4, 2); _me[i++].m6 = GB(buf[j], 6, 2); } } } else { for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m6 = buf[j]; } } } static void Save_MAP6() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m6; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } static void Load_MAP7() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); for (TileIndex i = 0; i != size;) { SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) _me[i++].m7 = buf[j]; } } static void Save_MAP7() { SmallStackSafeStackAlloc buf; TileIndex size = MapSize(); SlSetLength(size); for (TileIndex i = 0; i != size;) { for (uint j = 0; j != MAP_SL_BUF_SIZE; j++) buf[j] = _me[i++].m7; SlArray(buf, MAP_SL_BUF_SIZE, SLE_UINT8); } } extern const ChunkHandler _map_chunk_handlers[] = { { 'MAPS', Save_MAPS, Load_MAPS, NULL, Check_MAPS, CH_RIFF }, { 'MAPT', Save_MAPT, Load_MAPT, NULL, NULL, CH_RIFF }, { 'MAPH', Save_MAPH, Load_MAPH, NULL, NULL, CH_RIFF }, { 'MAPO', Save_MAP1, Load_MAP1, NULL, NULL, CH_RIFF }, { 'MAP2', Save_MAP2, Load_MAP2, NULL, NULL, CH_RIFF }, { 'M3LO', Save_MAP3, Load_MAP3, NULL, NULL, CH_RIFF }, { 'M3HI', Save_MAP4, Load_MAP4, NULL, NULL, CH_RIFF }, { 'MAP5', Save_MAP5, Load_MAP5, NULL, NULL, CH_RIFF }, { 'MAPE', Save_MAP6, Load_MAP6, NULL, NULL, CH_RIFF }, { 'MAP7', Save_MAP7, Load_MAP7, NULL, NULL, CH_RIFF | CH_LAST }, }; openttd-1.5.3/src/saveload/autoreplace_sl.cpp0000644000000000000000000000374012627373446020010 0ustar rootroot/* $Id: autoreplace_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 autoreplace_sl.cpp Code handling saving and loading of autoreplace rules */ #include "../stdafx.h" #include "../autoreplace_base.h" #include "saveload.h" #include "../safeguards.h" static const SaveLoad _engine_renew_desc[] = { SLE_VAR(EngineRenew, from, SLE_UINT16), SLE_VAR(EngineRenew, to, SLE_UINT16), SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS), SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION), SLE_CONDVAR(EngineRenew, replace_when_old, SLE_BOOL, 175, SL_MAX_VERSION), SLE_END() }; static void Save_ERNW() { EngineRenew *er; FOR_ALL_ENGINE_RENEWS(er) { SlSetArrayIndex(er->index); SlObject(er, _engine_renew_desc); } } static void Load_ERNW() { int index; while ((index = SlIterateArray()) != -1) { EngineRenew *er = new (index) EngineRenew(); SlObject(er, _engine_renew_desc); /* Advanced vehicle lists, ungrouped vehicles got added */ if (IsSavegameVersionBefore(60)) { er->group_id = ALL_GROUP; } else if (IsSavegameVersionBefore(71)) { if (er->group_id == DEFAULT_GROUP) er->group_id = ALL_GROUP; } } } static void Ptrs_ERNW() { EngineRenew *er; FOR_ALL_ENGINE_RENEWS(er) { SlObject(er, _engine_renew_desc); } } extern const ChunkHandler _autoreplace_chunk_handlers[] = { { 'ERNW', Save_ERNW, Load_ERNW, Ptrs_ERNW, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/goal_sl.cpp0000644000000000000000000000313312627373446016422 0ustar rootroot/* $Id: goal_sl.cpp 26593 2014-05-17 17:18:07Z frosch $ */ /* * 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 goal_sl.cpp Code handling saving and loading of goals */ #include "../stdafx.h" #include "../goal_base.h" #include "saveload.h" #include "../safeguards.h" static const SaveLoad _goals_desc[] = { SLE_VAR(Goal, company, SLE_FILE_U16 | SLE_VAR_U8), SLE_VAR(Goal, type, SLE_FILE_U16 | SLE_VAR_U8), SLE_VAR(Goal, dst, SLE_UINT32), SLE_STR(Goal, text, SLE_STR | SLF_ALLOW_CONTROL, 0), SLE_CONDSTR(Goal, progress, SLE_STR | SLF_ALLOW_CONTROL, 0, 182, SL_MAX_VERSION), SLE_CONDVAR(Goal, completed, SLE_BOOL, 182, SL_MAX_VERSION), SLE_END() }; static void Save_GOAL() { Goal *s; FOR_ALL_GOALS(s) { SlSetArrayIndex(s->index); SlObject(s, _goals_desc); } } static void Load_GOAL() { int index; while ((index = SlIterateArray()) != -1) { Goal *s = new (index) Goal(); SlObject(s, _goals_desc); } } extern const ChunkHandler _goal_chunk_handlers[] = { { 'GOAL', Save_GOAL, Load_GOAL, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/ai_sl.cpp0000644000000000000000000001112312627373446016067 0ustar rootroot/* $Id: ai_sl.cpp 26493 2014-04-24 04:41:54Z rubidium $ */ /* * 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 ai_sl.cpp Handles the saveload part of the AIs */ #include "../stdafx.h" #include "../company_base.h" #include "../debug.h" #include "saveload.h" #include "../string_func.h" #include "../ai/ai.hpp" #include "../ai/ai_config.hpp" #include "../network/network.h" #include "../ai/ai_instance.hpp" #include "../safeguards.h" static char _ai_saveload_name[64]; static int _ai_saveload_version; static char _ai_saveload_settings[1024]; static bool _ai_saveload_is_random; static const SaveLoad _ai_company[] = { SLEG_STR(_ai_saveload_name, SLE_STRB), SLEG_STR(_ai_saveload_settings, SLE_STRB), SLEG_CONDVAR(_ai_saveload_version, SLE_UINT32, 108, SL_MAX_VERSION), SLEG_CONDVAR(_ai_saveload_is_random, SLE_BOOL, 136, SL_MAX_VERSION), SLE_END() }; static void SaveReal_AIPL(int *index_ptr) { CompanyID index = (CompanyID)*index_ptr; AIConfig *config = AIConfig::GetConfig(index); if (config->HasScript()) { strecpy(_ai_saveload_name, config->GetName(), lastof(_ai_saveload_name)); _ai_saveload_version = config->GetVersion(); } else { /* No AI is configured for this so store an empty string as name. */ _ai_saveload_name[0] = '\0'; _ai_saveload_version = -1; } _ai_saveload_is_random = config->IsRandom(); _ai_saveload_settings[0] = '\0'; config->SettingsToString(_ai_saveload_settings, lastof(_ai_saveload_settings)); SlObject(NULL, _ai_company); /* If the AI was active, store his data too */ if (Company::IsValidAiID(index)) AI::Save(index); } static void Load_AIPL() { /* Free all current data */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->Change(NULL); } CompanyID index; while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) { if (index >= MAX_COMPANIES) SlErrorCorrupt("Too many AI configs"); _ai_saveload_is_random = 0; _ai_saveload_version = -1; SlObject(NULL, _ai_company); if (_networking && !_network_server) { if (Company::IsValidAiID(index)) AIInstance::LoadEmpty(); continue; } AIConfig *config = AIConfig::GetConfig(index, AIConfig::SSS_FORCE_GAME); if (StrEmpty(_ai_saveload_name)) { /* A random AI. */ config->Change(NULL, -1, false, true); } else { config->Change(_ai_saveload_name, _ai_saveload_version, false, _ai_saveload_is_random); if (!config->HasScript()) { /* No version of the AI available that can load the data. Try to load the * latest version of the AI instead. */ config->Change(_ai_saveload_name, -1, false, _ai_saveload_is_random); if (!config->HasScript()) { if (strcmp(_ai_saveload_name, "%_dummy") != 0) { DEBUG(script, 0, "The savegame has an AI by the name '%s', version %d which is no longer available.", _ai_saveload_name, _ai_saveload_version); DEBUG(script, 0, "A random other AI will be loaded in its place."); } else { DEBUG(script, 0, "The savegame had no AIs available at the time of saving."); DEBUG(script, 0, "A random available AI will be loaded now."); } } else { DEBUG(script, 0, "The savegame has an AI by the name '%s', version %d which is no longer available.", _ai_saveload_name, _ai_saveload_version); DEBUG(script, 0, "The latest version of that AI has been loaded instead, but it'll not get the savegame data as it's incompatible."); } /* Make sure the AI doesn't get the saveload data, as he was not the * writer of the saveload data in the first place */ _ai_saveload_version = -1; } } config->StringToSettings(_ai_saveload_settings); /* Start the AI directly if it was active in the savegame */ if (Company::IsValidAiID(index)) { AI::StartNew(index, false); AI::Load(index, _ai_saveload_version); } } } static void Save_AIPL() { for (int i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { SlSetArrayIndex(i); SlAutolength((AutolengthProc *)SaveReal_AIPL, &i); } } extern const ChunkHandler _ai_chunk_handlers[] = { { 'AIPL', Save_AIPL, Load_AIPL, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/misc_sl.cpp0000644000000000000000000001376412627373446016446 0ustar rootroot/* $Id: misc_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 misc_sl.cpp Saving and loading of things that didn't fit anywhere else */ #include "../stdafx.h" #include "../date_func.h" #include "../zoom_func.h" #include "../window_gui.h" #include "../window_func.h" #include "../viewport_func.h" #include "../gfx_func.h" #include "../core/random_func.hpp" #include "../fios.h" #include "saveload.h" #include "../safeguards.h" extern TileIndex _cur_tileloop_tile; extern uint16 _disaster_delay; extern byte _trees_tick_ctr; /* Keep track of current game position */ int _saved_scrollpos_x; int _saved_scrollpos_y; ZoomLevelByte _saved_scrollpos_zoom; void SaveViewportBeforeSaveGame() { const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); if (w != NULL) { _saved_scrollpos_x = w->viewport->scrollpos_x; _saved_scrollpos_y = w->viewport->scrollpos_y; _saved_scrollpos_zoom = w->viewport->zoom; } } void ResetViewportAfterLoadGame() { Window *w = FindWindowById(WC_MAIN_WINDOW, 0); w->viewport->scrollpos_x = _saved_scrollpos_x; w->viewport->scrollpos_y = _saved_scrollpos_y; w->viewport->dest_scrollpos_x = _saved_scrollpos_x; w->viewport->dest_scrollpos_y = _saved_scrollpos_y; ViewPort *vp = w->viewport; vp->zoom = (ZoomLevel)min(_saved_scrollpos_zoom, ZOOM_LVL_MAX); vp->virtual_width = ScaleByZoom(vp->width, vp->zoom); vp->virtual_height = ScaleByZoom(vp->height, vp->zoom); /* If zoom_max is ZOOM_LVL_MIN then the setting has not been loaded yet, therefore all levels are allowed. */ if (_settings_client.gui.zoom_max != ZOOM_LVL_MIN) { /* Ensure zoom level is allowed */ while (vp->zoom < _settings_client.gui.zoom_min) DoZoomInOutWindow(ZOOM_OUT, w); while (vp->zoom > _settings_client.gui.zoom_max) DoZoomInOutWindow(ZOOM_IN, w); } DoZoomInOutWindow(ZOOM_NONE, w); // update button status MarkWholeScreenDirty(); } byte _age_cargo_skip_counter; ///< Skip aging of cargo? Used before savegame version 162. static const SaveLoadGlobVarList _date_desc[] = { SLEG_CONDVAR(_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLEG_CONDVAR(_date, SLE_INT32, 31, SL_MAX_VERSION), SLEG_VAR(_date_fract, SLE_UINT16), SLEG_VAR(_tick_counter, SLE_UINT16), SLE_CONDNULL(2, 0, 156), // _vehicle_id_ctr_day SLEG_CONDVAR(_age_cargo_skip_counter, SLE_UINT8, 0, 161), SLE_CONDNULL(1, 0, 45), SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLEG_CONDVAR(_cur_tileloop_tile, SLE_UINT32, 6, SL_MAX_VERSION), SLEG_VAR(_disaster_delay, SLE_UINT16), SLE_CONDNULL(2, 0, 119), SLEG_VAR(_random.state[0], SLE_UINT32), SLEG_VAR(_random.state[1], SLE_UINT32), SLE_CONDNULL(1, 0, 9), SLE_CONDNULL(4, 10, 119), SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32), SLEG_CONDVAR(_next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32, 0, 108), SLEG_CONDVAR(_next_competitor_start, SLE_UINT32, 109, SL_MAX_VERSION), SLEG_VAR(_trees_tick_ctr, SLE_UINT8), SLEG_CONDVAR(_pause_mode, SLE_UINT8, 4, SL_MAX_VERSION), SLE_CONDNULL(4, 11, 119), SLEG_END() }; static const SaveLoadGlobVarList _date_check_desc[] = { SLEG_CONDVAR(_load_check_data.current_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLEG_CONDVAR(_load_check_data.current_date, SLE_INT32, 31, SL_MAX_VERSION), SLE_NULL(2), // _date_fract SLE_NULL(2), // _tick_counter SLE_CONDNULL(2, 0, 156), // _vehicle_id_ctr_day SLE_CONDNULL(1, 0, 161), // _age_cargo_skip_counter SLE_CONDNULL(1, 0, 45), SLE_CONDNULL(2, 0, 5), // _cur_tileloop_tile SLE_CONDNULL(4, 6, SL_MAX_VERSION), // _cur_tileloop_tile SLE_NULL(2), // _disaster_delay SLE_CONDNULL(2, 0, 119), SLE_NULL(4), // _random.state[0] SLE_NULL(4), // _random.state[1] SLE_CONDNULL(1, 0, 9), SLE_CONDNULL(4, 10, 119), SLE_NULL(1), // _cur_company_tick_index SLE_CONDNULL(2, 0, 108), // _next_competitor_start SLE_CONDNULL(4, 109, SL_MAX_VERSION), // _next_competitor_start SLE_NULL(1), // _trees_tick_ctr SLE_CONDNULL(1, 4, SL_MAX_VERSION), // _pause_mode SLE_CONDNULL(4, 11, 119), SLEG_END() }; /* Save load date related variables as well as persistent tick counters * XXX: currently some unrelated stuff is just put here */ static void SaveLoad_DATE() { SlGlobList(_date_desc); } static void Check_DATE() { SlGlobList(_date_check_desc); if (IsSavegameVersionBefore(31)) { _load_check_data.current_date += DAYS_TILL_ORIGINAL_BASE_YEAR; } } static const SaveLoadGlobVarList _view_desc[] = { SLEG_CONDVAR(_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), SLEG_CONDVAR(_saved_scrollpos_x, SLE_INT32, 6, SL_MAX_VERSION), SLEG_CONDVAR(_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), SLEG_CONDVAR(_saved_scrollpos_y, SLE_INT32, 6, SL_MAX_VERSION), SLEG_VAR(_saved_scrollpos_zoom, SLE_UINT8), SLEG_END() }; static void SaveLoad_VIEW() { SlGlobList(_view_desc); } extern const ChunkHandler _misc_chunk_handlers[] = { { 'DATE', SaveLoad_DATE, SaveLoad_DATE, NULL, Check_DATE, CH_RIFF}, { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, NULL, NULL, CH_RIFF | CH_LAST}, }; openttd-1.5.3/src/saveload/engine_sl.cpp0000644000000000000000000001551112627373446016750 0ustar rootroot/* $Id: engine_sl.cpp 27270 2015-05-08 17:23:55Z frosch $ */ /* * 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 engine_sl.cpp Code handling saving and loading of engines */ #include "../stdafx.h" #include "saveload_internal.h" #include "../engine_base.h" #include "../string_func.h" #include #include "../safeguards.h" static const SaveLoad _engine_desc[] = { SLE_CONDVAR(Engine, intro_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Engine, intro_date, SLE_INT32, 31, SL_MAX_VERSION), SLE_CONDVAR(Engine, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Engine, age, SLE_INT32, 31, SL_MAX_VERSION), SLE_VAR(Engine, reliability, SLE_UINT16), SLE_VAR(Engine, reliability_spd_dec, SLE_UINT16), SLE_VAR(Engine, reliability_start, SLE_UINT16), SLE_VAR(Engine, reliability_max, SLE_UINT16), SLE_VAR(Engine, reliability_final, SLE_UINT16), SLE_VAR(Engine, duration_phase_1, SLE_UINT16), SLE_VAR(Engine, duration_phase_2, SLE_UINT16), SLE_VAR(Engine, duration_phase_3, SLE_UINT16), SLE_CONDNULL(1, 0, 120), SLE_VAR(Engine, flags, SLE_UINT8), SLE_CONDNULL(1, 0, 178), // old preview_company_rank SLE_CONDVAR(Engine, preview_asked, SLE_UINT16, 179, SL_MAX_VERSION), SLE_CONDVAR(Engine, preview_company, SLE_UINT8, 179, SL_MAX_VERSION), SLE_VAR(Engine, preview_wait, SLE_UINT8), SLE_CONDNULL(1, 0, 44), SLE_CONDVAR(Engine, company_avail, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), SLE_CONDVAR(Engine, company_avail, SLE_UINT16, 104, SL_MAX_VERSION), SLE_CONDVAR(Engine, company_hidden, SLE_UINT16, 193, SL_MAX_VERSION), SLE_CONDSTR(Engine, name, SLE_STR, 0, 84, SL_MAX_VERSION), SLE_CONDNULL(16, 2, 143), // old reserved space SLE_END() }; static std::vector _temp_engine; /** * Allocate an Engine structure, but not using the pools. * The allocated Engine must be freed using FreeEngine; * @return Allocated engine. */ static Engine* CallocEngine() { uint8 *zero = CallocT(sizeof(Engine)); Engine *engine = new (zero) Engine(); return engine; } /** * Deallocate an Engine constructed by CallocEngine. * @param e Engine to free. */ static void FreeEngine(Engine *e) { if (e != NULL) { e->~Engine(); free(e); } } Engine *GetTempDataEngine(EngineID index) { if (index < _temp_engine.size()) { return _temp_engine[index]; } else if (index == _temp_engine.size()) { _temp_engine.push_back(CallocEngine()); return _temp_engine[index]; } else { NOT_REACHED(); } } static void Save_ENGN() { Engine *e; FOR_ALL_ENGINES(e) { SlSetArrayIndex(e->index); SlObject(e, _engine_desc); } } static void Load_ENGN() { /* As engine data is loaded before engines are initialized we need to load * this information into a temporary array. This is then copied into the * engine pool after processing NewGRFs by CopyTempEngineData(). */ int index; while ((index = SlIterateArray()) != -1) { Engine *e = GetTempDataEngine(index); SlObject(e, _engine_desc); if (IsSavegameVersionBefore(179)) { /* preview_company_rank was replaced with preview_company and preview_asked. * Just cancel any previews. */ e->flags &= ~4; // ENGINE_OFFER_WINDOW_OPEN e->preview_company = INVALID_COMPANY; e->preview_asked = (CompanyMask)-1; } } } /** * Copy data from temporary engine array into the real engine pool. */ void CopyTempEngineData() { Engine *e; FOR_ALL_ENGINES(e) { if (e->index >= _temp_engine.size()) break; const Engine *se = GetTempDataEngine(e->index); e->intro_date = se->intro_date; e->age = se->age; e->reliability = se->reliability; e->reliability_spd_dec = se->reliability_spd_dec; e->reliability_start = se->reliability_start; e->reliability_max = se->reliability_max; e->reliability_final = se->reliability_final; e->duration_phase_1 = se->duration_phase_1; e->duration_phase_2 = se->duration_phase_2; e->duration_phase_3 = se->duration_phase_3; e->flags = se->flags; e->preview_asked = se->preview_asked; e->preview_company = se->preview_company; e->preview_wait = se->preview_wait; e->company_avail = se->company_avail; e->company_hidden = se->company_hidden; if (se->name != NULL) e->name = stredup(se->name); } /* Get rid of temporary data */ for (std::vector::iterator it = _temp_engine.begin(); it != _temp_engine.end(); ++it) { FreeEngine(*it); } _temp_engine.clear(); } static void Load_ENGS() { /* Load old separate String ID list into a temporary array. This * was always 256 entries. */ StringID names[256]; SlArray(names, lengthof(names), SLE_STRINGID); /* Copy each string into the temporary engine array. */ for (EngineID engine = 0; engine < lengthof(names); engine++) { Engine *e = GetTempDataEngine(engine); e->name = CopyFromOldName(names[engine]); } } /** Save and load the mapping between the engine id in the pool, and the grf file it came from. */ static const SaveLoad _engine_id_mapping_desc[] = { SLE_VAR(EngineIDMapping, grfid, SLE_UINT32), SLE_VAR(EngineIDMapping, internal_id, SLE_UINT16), SLE_VAR(EngineIDMapping, type, SLE_UINT8), SLE_VAR(EngineIDMapping, substitute_id, SLE_UINT8), SLE_END() }; static void Save_EIDS() { const EngineIDMapping *end = _engine_mngr.End(); uint index = 0; for (EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) { SlSetArrayIndex(index); SlObject(eid, _engine_id_mapping_desc); } } static void Load_EIDS() { _engine_mngr.Clear(); while (SlIterateArray() != -1) { EngineIDMapping *eid = _engine_mngr.Append(); SlObject(eid, _engine_id_mapping_desc); } } extern const ChunkHandler _engine_chunk_handlers[] = { { 'EIDS', Save_EIDS, Load_EIDS, NULL, NULL, CH_ARRAY }, { 'ENGN', Save_ENGN, Load_ENGN, NULL, NULL, CH_ARRAY }, { 'ENGS', NULL, Load_ENGS, NULL, NULL, CH_RIFF | CH_LAST }, }; openttd-1.5.3/src/saveload/saveload.h0000644000000000000000000005640012627373446016252 0ustar rootroot/* $Id: saveload.h 26591 2014-05-16 17:41:55Z rubidium $ */ /* * 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 saveload.h Functions/types related to saving and loading games. */ #ifndef SAVELOAD_H #define SAVELOAD_H #include "../fileio_type.h" #include "../strings_type.h" /** Save or load result codes. */ enum SaveOrLoadResult { SL_OK = 0, ///< completed successfully SL_ERROR = 1, ///< error that was caught before internal structures were modified SL_REINIT = 2, ///< error that was caught in the middle of updating game state, need to clear it. (can only happen during load) }; /** Save or load mode. @see SaveOrLoad */ enum SaveOrLoadMode { SL_INVALID = -1, ///< Invalid mode. SL_LOAD = 0, ///< Load game. SL_SAVE = 1, ///< Save game. SL_OLD_LOAD = 2, ///< Load old game. SL_PNG = 3, ///< Load PNG file (height map). SL_BMP = 4, ///< Load BMP file (height map). SL_LOAD_CHECK = 5, ///< Load for game preview. }; /** Types of save games. */ enum SavegameType { SGT_TTD, ///< TTD savegame (can be detected incorrectly) SGT_TTDP1, ///< TTDP savegame ( -//- ) (data at NW border) SGT_TTDP2, ///< TTDP savegame in new format (data at SE border) SGT_OTTD, ///< OTTD savegame SGT_TTO, ///< TTO savegame SGT_INVALID = 0xFF, ///< broken savegame (used internally) }; void GenerateDefaultSaveName(char *buf, const char *last); void SetSaveLoadError(uint16 str); const char *GetSaveLoadErrorString(); SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded = true); void WaitTillSaved(); void ProcessAsyncSaveFinish(); void DoExitSave(); SaveOrLoadResult SaveWithFilter(struct SaveFilter *writer, bool threaded); SaveOrLoadResult LoadWithFilter(struct LoadFilter *reader); typedef void ChunkSaveLoadProc(); typedef void AutolengthProc(void *arg); /** Handlers and description of chunk. */ struct ChunkHandler { uint32 id; ///< Unique ID (4 letters). ChunkSaveLoadProc *save_proc; ///< Save procedure of the chunk. ChunkSaveLoadProc *load_proc; ///< Load procedure of the chunk. ChunkSaveLoadProc *ptrs_proc; ///< Manipulate pointers in the chunk. ChunkSaveLoadProc *load_check_proc; ///< Load procedure for game preview. uint32 flags; ///< Flags of the chunk. @see ChunkType }; struct NullStruct { byte null; }; /** Type of reference (#SLE_REF, #SLE_CONDREF). */ enum SLRefType { REF_ORDER = 0, ///< Load/save a reference to an order. REF_VEHICLE = 1, ///< Load/save a reference to a vehicle. REF_STATION = 2, ///< Load/save a reference to a station. REF_TOWN = 3, ///< Load/save a reference to a town. REF_VEHICLE_OLD = 4, ///< Load/save an old-style reference to a vehicle (for pre-4.4 savegames). REF_ROADSTOPS = 5, ///< Load/save a reference to a bus/truck stop. REF_ENGINE_RENEWS = 6, ///< Load/save a reference to an engine renewal (autoreplace). REF_CARGO_PACKET = 7, ///< Load/save a reference to a cargo packet. REF_ORDERLIST = 8, ///< Load/save a reference to an orderlist. REF_STORAGE = 9, ///< Load/save a reference to a persistent storage. REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph. REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job. }; /** Highest possible savegame version. */ #define SL_MAX_VERSION UINT16_MAX /** Flags of a chunk. */ enum ChunkType { CH_RIFF = 0, CH_ARRAY = 1, CH_SPARSE_ARRAY = 2, CH_TYPE_MASK = 3, CH_LAST = 8, ///< Last chunk in this array. CH_AUTO_LENGTH = 16, }; /** * VarTypes is the general bitmasked magic type that tells us * certain characteristics about the variable it refers to. For example * SLE_FILE_* gives the size(type) as it would be in the savegame and * SLE_VAR_* the size(type) as it is in memory during runtime. These are * the first 8 bits (0-3 SLE_FILE, 4-7 SLE_VAR). * Bits 8-15 are reserved for various flags as explained below */ enum VarTypes { /* 4 bits allocated a maximum of 16 types for NumberType */ SLE_FILE_I8 = 0, SLE_FILE_U8 = 1, SLE_FILE_I16 = 2, SLE_FILE_U16 = 3, SLE_FILE_I32 = 4, SLE_FILE_U32 = 5, SLE_FILE_I64 = 6, SLE_FILE_U64 = 7, SLE_FILE_STRINGID = 8, ///< StringID offset into strings-array SLE_FILE_STRING = 9, /* 6 more possible file-primitives */ /* 4 bits allocated a maximum of 16 types for NumberType */ SLE_VAR_BL = 0 << 4, SLE_VAR_I8 = 1 << 4, SLE_VAR_U8 = 2 << 4, SLE_VAR_I16 = 3 << 4, SLE_VAR_U16 = 4 << 4, SLE_VAR_I32 = 5 << 4, SLE_VAR_U32 = 6 << 4, SLE_VAR_I64 = 7 << 4, SLE_VAR_U64 = 8 << 4, SLE_VAR_NULL = 9 << 4, ///< useful to write zeros in savegame. SLE_VAR_STRB = 10 << 4, ///< string (with pre-allocated buffer) SLE_VAR_STRBQ = 11 << 4, ///< string enclosed in quotes (with pre-allocated buffer) SLE_VAR_STR = 12 << 4, ///< string pointer SLE_VAR_STRQ = 13 << 4, ///< string pointer enclosed in quotes SLE_VAR_NAME = 14 << 4, ///< old custom name to be converted to a char pointer /* 1 more possible memory-primitives */ /* Shortcut values */ SLE_VAR_CHAR = SLE_VAR_I8, /* Default combinations of variables. As savegames change, so can variables * and thus it is possible that the saved value and internal size do not * match and you need to specify custom combo. The defaults are listed here */ SLE_BOOL = SLE_FILE_I8 | SLE_VAR_BL, SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8, SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8, SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16, SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16, SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32, SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32, SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64, SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64, SLE_CHAR = SLE_FILE_I8 | SLE_VAR_CHAR, SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U16, SLE_STRINGBUF = SLE_FILE_STRING | SLE_VAR_STRB, SLE_STRINGBQUOTE = SLE_FILE_STRING | SLE_VAR_STRBQ, SLE_STRING = SLE_FILE_STRING | SLE_VAR_STR, SLE_STRINGQUOTE = SLE_FILE_STRING | SLE_VAR_STRQ, SLE_NAME = SLE_FILE_STRINGID | SLE_VAR_NAME, /* Shortcut values */ SLE_UINT = SLE_UINT32, SLE_INT = SLE_INT32, SLE_STRB = SLE_STRINGBUF, SLE_STRBQ = SLE_STRINGBQUOTE, SLE_STR = SLE_STRING, SLE_STRQ = SLE_STRINGQUOTE, /* 8 bits allocated for a maximum of 8 flags * Flags directing saving/loading of a variable */ SLF_NOT_IN_SAVE = 1 << 8, ///< do not save with savegame, basically client-based SLF_NOT_IN_CONFIG = 1 << 9, ///< do not save to config file SLF_NO_NETWORK_SYNC = 1 << 10, ///< do not synchronize over network (but it is saved if SLF_NOT_IN_SAVE is not set) SLF_ALLOW_CONTROL = 1 << 11, ///< allow control codes in the strings SLF_ALLOW_NEWLINE = 1 << 12, ///< allow new lines in the strings /* 3 more possible flags */ }; typedef uint32 VarType; /** Type of data saved. */ enum SaveLoadTypes { SL_VAR = 0, ///< Save/load a variable. SL_REF = 1, ///< Save/load a reference. SL_ARR = 2, ///< Save/load an array. SL_STR = 3, ///< Save/load a string. SL_LST = 4, ///< Save/load a list. /* non-normal save-load types */ SL_WRITEBYTE = 8, SL_VEH_INCLUDE = 9, SL_ST_INCLUDE = 10, SL_END = 15 }; typedef byte SaveLoadType; ///< Save/load type. @see SaveLoadTypes /** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */ struct SaveLoad { bool global; ///< should we load a global variable or a non-global one SaveLoadType cmd; ///< the action to take with the saved/loaded type, All types need different action VarType conv; ///< type of the variable to be saved, int uint16 length; ///< (conditional) length of the variable (eg. arrays) (max array size is 65536 elements) uint16 version_from; ///< save/load the variable starting from this savegame version uint16 version_to; ///< save/load the variable until this savegame version /* NOTE: This element either denotes the address of the variable for a global * variable, or the offset within a struct which is then bound to a variable * during runtime. Decision on which one to use is controlled by the function * that is called to save it. address: global=true, offset: global=false */ void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536) size_t size; ///< the sizeof size. }; /** Same as #SaveLoad but global variables are used (for better readability); */ typedef SaveLoad SaveLoadGlobVarList; /** * Storage of simple variables, references (pointers), and arrays. * @param cmd Load/save type. @see SaveLoadType * @param base Name of the class or struct containing the variable. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. * @param from First savegame version that has the field. * @param to Last savegame version that has the field. * @note In general, it is better to use one of the SLE_* macros below. */ #define SLE_GENERAL(cmd, base, variable, type, length, from, to) {false, cmd, type, length, from, to, (void*)cpp_offsetof(base, variable), cpp_sizeof(base, variable)} /** * Storage of a variable in some savegame versions. * @param base Name of the class or struct containing the variable. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. * @param from First savegame version that has the field. * @param to Last savegame version that has the field. */ #define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to) /** * Storage of a reference in some savegame versions. * @param base Name of the class or struct containing the variable. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Type of the reference, a value from #SLRefType. * @param from First savegame version that has the field. * @param to Last savegame version that has the field. */ #define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to) /** * Storage of an array in some savegame versions. * @param base Name of the class or struct containing the array. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. * @param length Number of elements in the array. * @param from First savegame version that has the array. * @param to Last savegame version that has the array. */ #define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to) /** * Storage of a string in some savegame versions. * @param base Name of the class or struct containing the string. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. * @param length Number of elements in the string (only used for fixed size buffers). * @param from First savegame version that has the string. * @param to Last savegame version that has the string. */ #define SLE_CONDSTR(base, variable, type, length, from, to) SLE_GENERAL(SL_STR, base, variable, type, length, from, to) /** * Storage of a list in some savegame versions. * @param base Name of the class or struct containing the list. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. * @param from First savegame version that has the list. * @param to Last savegame version that has the list. */ #define SLE_CONDLST(base, variable, type, from, to) SLE_GENERAL(SL_LST, base, variable, type, 0, from, to) /** * Storage of a variable in every version of a savegame. * @param base Name of the class or struct containing the variable. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. */ #define SLE_VAR(base, variable, type) SLE_CONDVAR(base, variable, type, 0, SL_MAX_VERSION) /** * Storage of a reference in every version of a savegame. * @param base Name of the class or struct containing the variable. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Type of the reference, a value from #SLRefType. */ #define SLE_REF(base, variable, type) SLE_CONDREF(base, variable, type, 0, SL_MAX_VERSION) /** * Storage of an array in every version of a savegame. * @param base Name of the class or struct containing the array. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. * @param length Number of elements in the array. */ #define SLE_ARR(base, variable, type, length) SLE_CONDARR(base, variable, type, length, 0, SL_MAX_VERSION) /** * Storage of a string in every savegame version. * @param base Name of the class or struct containing the string. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. * @param length Number of elements in the string (only used for fixed size buffers). */ #define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, type, length, 0, SL_MAX_VERSION) /** * Storage of a list in every savegame version. * @param base Name of the class or struct containing the list. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. */ #define SLE_LST(base, variable, type) SLE_CONDLST(base, variable, type, 0, SL_MAX_VERSION) /** * Empty space in every savegame version. * @param length Length of the empty space. */ #define SLE_NULL(length) SLE_CONDNULL(length, 0, SL_MAX_VERSION) /** * Empty space in some savegame versions. * @param length Length of the empty space. * @param from First savegame version that has the empty space. * @param to Last savegame version that has the empty space. */ #define SLE_CONDNULL(length, from, to) SLE_CONDARR(NullStruct, null, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to) /** Translate values ingame to different values in the savegame and vv. */ #define SLE_WRITEBYTE(base, variable, value) SLE_GENERAL(SL_WRITEBYTE, base, variable, 0, 0, value, value) #define SLE_VEH_INCLUDE() {false, SL_VEH_INCLUDE, 0, 0, 0, SL_MAX_VERSION, NULL, 0} #define SLE_ST_INCLUDE() {false, SL_ST_INCLUDE, 0, 0, 0, SL_MAX_VERSION, NULL, 0} /** End marker of a struct/class save or load. */ #define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL, 0} /** * Storage of global simple variables, references (pointers), and arrays. * @param cmd Load/save type. @see SaveLoadType * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. * @param from First savegame version that has the field. * @param to Last savegame version that has the field. * @note In general, it is better to use one of the SLEG_* macros below. */ #define SLEG_GENERAL(cmd, variable, type, length, from, to) {true, cmd, type, length, from, to, (void*)&variable, sizeof(variable)} /** * Storage of a global variable in some savegame versions. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. * @param from First savegame version that has the field. * @param to Last savegame version that has the field. */ #define SLEG_CONDVAR(variable, type, from, to) SLEG_GENERAL(SL_VAR, variable, type, 0, from, to) /** * Storage of a global reference in some savegame versions. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. * @param from First savegame version that has the field. * @param to Last savegame version that has the field. */ #define SLEG_CONDREF(variable, type, from, to) SLEG_GENERAL(SL_REF, variable, type, 0, from, to) /** * Storage of a global array in some savegame versions. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. * @param length Number of elements in the array. * @param from First savegame version that has the array. * @param to Last savegame version that has the array. */ #define SLEG_CONDARR(variable, type, length, from, to) SLEG_GENERAL(SL_ARR, variable, type, length, from, to) /** * Storage of a global string in some savegame versions. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. * @param length Number of elements in the string (only used for fixed size buffers). * @param from First savegame version that has the string. * @param to Last savegame version that has the string. */ #define SLEG_CONDSTR(variable, type, length, from, to) SLEG_GENERAL(SL_STR, variable, type, length, from, to) /** * Storage of a global list in some savegame versions. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. * @param from First savegame version that has the list. * @param to Last savegame version that has the list. */ #define SLEG_CONDLST(variable, type, from, to) SLEG_GENERAL(SL_LST, variable, type, 0, from, to) /** * Storage of a global variable in every savegame version. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. */ #define SLEG_VAR(variable, type) SLEG_CONDVAR(variable, type, 0, SL_MAX_VERSION) /** * Storage of a global reference in every savegame version. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. */ #define SLEG_REF(variable, type) SLEG_CONDREF(variable, type, 0, SL_MAX_VERSION) /** * Storage of a global array in every savegame version. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. */ #define SLEG_ARR(variable, type) SLEG_CONDARR(variable, type, lengthof(variable), 0, SL_MAX_VERSION) /** * Storage of a global string in every savegame version. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. */ #define SLEG_STR(variable, type) SLEG_CONDSTR(variable, type, lengthof(variable), 0, SL_MAX_VERSION) /** * Storage of a global list in every savegame version. * @param variable Name of the global variable. * @param type Storage of the data in memory and in the savegame. */ #define SLEG_LST(variable, type) SLEG_CONDLST(variable, type, 0, SL_MAX_VERSION) /** * Empty global space in some savegame versions. * @param length Length of the empty space. * @param from First savegame version that has the empty space. * @param to Last savegame version that has the empty space. */ #define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_NOT_IN_CONFIG, length, from, to, (void*)NULL} /** End marker of global variables save or load. */ #define SLEG_END() {true, SL_END, 0, 0, 0, 0, NULL, 0} /** * Checks whether the savegame is below \a major.\a minor. * @param major Major number of the version to check against. * @param minor Minor number of the version to check against. If \a minor is 0 or not specified, only the major number is checked. * @return Savegame version is earlier than the specified version. */ static inline bool IsSavegameVersionBefore(uint16 major, byte minor = 0) { extern uint16 _sl_version; extern byte _sl_minor_version; return _sl_version < major || (minor > 0 && _sl_version == major && _sl_minor_version < minor); } /** * Checks if some version from/to combination falls within the range of the * active savegame version. * @param version_from Lowest version number that falls within the range. * @param version_to Highest version number that falls within the range. * @return Active savegame version falls within the given range. */ static inline bool SlIsObjectCurrentlyValid(uint16 version_from, uint16 version_to) { extern const uint16 SAVEGAME_VERSION; if (SAVEGAME_VERSION < version_from || SAVEGAME_VERSION > version_to) return false; return true; } /** * Get the NumberType of a setting. This describes the integer type * as it is represented in memory * @param type VarType holding information about the variable-type * @return return the SLE_VAR_* part of a variable-type description */ static inline VarType GetVarMemType(VarType type) { return type & 0xF0; // GB(type, 4, 4) << 4; } /** * Get the #FileType of a setting. This describes the integer type * as it is represented in a savegame/file * @param type VarType holding information about the file-type * @param return the SLE_FILE_* part of a variable-type description */ static inline VarType GetVarFileType(VarType type) { return type & 0xF; // GB(type, 0, 4); } /** * Check if the given saveload type is a numeric type. * @param conv the type to check * @return True if it's a numeric type. */ static inline bool IsNumericType(VarType conv) { return GetVarMemType(conv) <= SLE_VAR_U64; } /** * Get the address of the variable. Which one to pick depends on the object * pointer. If it is NULL we are dealing with global variables so the address * is taken. If non-null only the offset is stored in the union and we need * to add this to the address of the object */ static inline void *GetVariableAddress(const void *object, const SaveLoad *sld) { return const_cast((const byte*)(sld->global ? NULL : object) + (ptrdiff_t)sld->address); } int64 ReadValue(const void *ptr, VarType conv); void WriteValue(void *ptr, VarType conv, int64 val); void SlSetArrayIndex(uint index); int SlIterateArray(); void SlAutolength(AutolengthProc *proc, void *arg); size_t SlGetFieldLength(); void SlSetLength(size_t length); size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld); size_t SlCalcObjLength(const void *object, const SaveLoad *sld); byte SlReadByte(); void SlWriteByte(byte b); void SlGlobList(const SaveLoadGlobVarList *sldg); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); void NORETURN SlError(StringID string, const char *extra_msg = NULL); void NORETURN SlErrorCorrupt(const char *msg); bool SaveloadCrashWithMissingNewGRFs(); extern char _savegame_format[8]; extern bool _do_autosave; #endif /* SAVELOAD_H */ openttd-1.5.3/src/saveload/group_sl.cpp0000644000000000000000000000351112627373446016634 0ustar rootroot/* $Id: group_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 group_sl.cpp Code handling saving and loading of economy data */ #include "../stdafx.h" #include "../group.h" #include "saveload.h" #include "../safeguards.h" static const SaveLoad _group_desc[] = { SLE_CONDVAR(Group, name, SLE_NAME, 0, 83), SLE_CONDSTR(Group, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION), SLE_CONDNULL(2, 0, 163), // num_vehicle SLE_VAR(Group, owner, SLE_UINT8), SLE_VAR(Group, vehicle_type, SLE_UINT8), SLE_VAR(Group, replace_protection, SLE_BOOL), SLE_CONDVAR(Group, parent, SLE_UINT16, 189, SL_MAX_VERSION), SLE_END() }; static void Save_GRPS() { Group *g; FOR_ALL_GROUPS(g) { SlSetArrayIndex(g->index); SlObject(g, _group_desc); } } static void Load_GRPS() { int index; while ((index = SlIterateArray()) != -1) { Group *g = new (index) Group(); SlObject(g, _group_desc); if (IsSavegameVersionBefore(189)) g->parent = INVALID_GROUP; } } extern const ChunkHandler _group_chunk_handlers[] = { { 'GRPS', Save_GRPS, Load_GRPS, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/saveload_internal.h0000644000000000000000000000364612627373446020152 0ustar rootroot/* $Id: saveload_internal.h 25620 2013-07-21 13:18:45Z zuu $ */ /* * 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 saveload_internal.h Declaration of functions used in more save/load files */ #ifndef SAVELOAD_INTERNAL_H #define SAVELOAD_INTERNAL_H #include "../company_manager_face.h" #include "../order_base.h" #include "../engine_type.h" #include "saveload.h" void InitializeOldNames(); StringID RemapOldStringID(StringID s); char *CopyFromOldName(StringID id); void ResetOldNames(); void MoveBuoysToWaypoints(); void MoveWaypointsToBaseStations(); const SaveLoad *GetBaseStationDescription(); void AfterLoadVehicles(bool part_of_load); void FixupTrainLengths(); void AfterLoadStations(); void AfterLoadRoadStops(); void AfterLoadLabelMaps(); void AfterLoadStoryBook(); void AfterLoadLinkGraphs(); void AfterLoadCompanyStats(); void UpdateHousesAndTowns(); void UpdateOldAircraft(); void SaveViewportBeforeSaveGame(); void ResetViewportAfterLoadGame(); void ConvertOldMultiheadToNew(); void ConnectMultiheadedTrains(); Engine *GetTempDataEngine(EngineID index); void CopyTempEngineData(); extern int32 _saved_scrollpos_x; extern int32 _saved_scrollpos_y; extern ZoomLevelByte _saved_scrollpos_zoom; extern SavegameType _savegame_type; extern uint32 _ttdp_version; CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face); Order UnpackOldOrder(uint16 packed); #endif /* SAVELOAD_INTERNAL_H */ openttd-1.5.3/src/saveload/gamelog_sl.cpp0000644000000000000000000001224112627373446017113 0ustar rootroot/* $Id: gamelog_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 gamelog_sl.cpp Code handling saving and loading of gamelog data */ #include "../stdafx.h" #include "../gamelog_internal.h" #include "../fios.h" #include "saveload.h" #include "../safeguards.h" static const SaveLoad _glog_action_desc[] = { SLE_VAR(LoggedAction, tick, SLE_UINT16), SLE_END() }; static const SaveLoad _glog_mode_desc[] = { SLE_VAR(LoggedChange, mode.mode, SLE_UINT8), SLE_VAR(LoggedChange, mode.landscape, SLE_UINT8), SLE_END() }; static const SaveLoad _glog_revision_desc[] = { SLE_ARR(LoggedChange, revision.text, SLE_UINT8, NETWORK_REVISION_LENGTH), SLE_VAR(LoggedChange, revision.newgrf, SLE_UINT32), SLE_VAR(LoggedChange, revision.slver, SLE_UINT16), SLE_VAR(LoggedChange, revision.modified, SLE_UINT8), SLE_END() }; static const SaveLoad _glog_oldver_desc[] = { SLE_VAR(LoggedChange, oldver.type, SLE_UINT32), SLE_VAR(LoggedChange, oldver.version, SLE_UINT32), SLE_END() }; static const SaveLoad _glog_setting_desc[] = { SLE_STR(LoggedChange, setting.name, SLE_STR, 128), SLE_VAR(LoggedChange, setting.oldval, SLE_INT32), SLE_VAR(LoggedChange, setting.newval, SLE_INT32), SLE_END() }; static const SaveLoad _glog_grfadd_desc[] = { SLE_VAR(LoggedChange, grfadd.grfid, SLE_UINT32 ), SLE_ARR(LoggedChange, grfadd.md5sum, SLE_UINT8, 16), SLE_END() }; static const SaveLoad _glog_grfrem_desc[] = { SLE_VAR(LoggedChange, grfrem.grfid, SLE_UINT32), SLE_END() }; static const SaveLoad _glog_grfcompat_desc[] = { SLE_VAR(LoggedChange, grfcompat.grfid, SLE_UINT32 ), SLE_ARR(LoggedChange, grfcompat.md5sum, SLE_UINT8, 16), SLE_END() }; static const SaveLoad _glog_grfparam_desc[] = { SLE_VAR(LoggedChange, grfparam.grfid, SLE_UINT32), SLE_END() }; static const SaveLoad _glog_grfmove_desc[] = { SLE_VAR(LoggedChange, grfmove.grfid, SLE_UINT32), SLE_VAR(LoggedChange, grfmove.offset, SLE_INT32), SLE_END() }; static const SaveLoad _glog_grfbug_desc[] = { SLE_VAR(LoggedChange, grfbug.data, SLE_UINT64), SLE_VAR(LoggedChange, grfbug.grfid, SLE_UINT32), SLE_VAR(LoggedChange, grfbug.bug, SLE_UINT8), SLE_END() }; static const SaveLoad _glog_emergency_desc[] = { SLE_END() }; static const SaveLoad * const _glog_desc[] = { _glog_mode_desc, _glog_revision_desc, _glog_oldver_desc, _glog_setting_desc, _glog_grfadd_desc, _glog_grfrem_desc, _glog_grfcompat_desc, _glog_grfparam_desc, _glog_grfmove_desc, _glog_grfbug_desc, _glog_emergency_desc, }; assert_compile(lengthof(_glog_desc) == GLCT_END); static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_actions) { assert(gamelog_action == NULL); assert(gamelog_actions == 0); GamelogActionType at; while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) { gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1); LoggedAction *la = &gamelog_action[gamelog_actions++]; la->at = at; SlObject(la, _glog_action_desc); // has to be saved after 'DATE'! la->change = NULL; la->changes = 0; GamelogChangeType ct; while ((ct = (GamelogChangeType)SlReadByte()) != GLCT_NONE) { la->change = ReallocT(la->change, la->changes + 1); LoggedChange *lc = &la->change[la->changes++]; /* for SLE_STR, pointer has to be valid! so make it NULL */ memset(lc, 0, sizeof(*lc)); lc->ct = ct; assert((uint)ct < GLCT_END); SlObject(lc, _glog_desc[ct]); } } } static void Save_GLOG() { const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; size_t length = 0; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { const LoggedChange *lcend = &la->change[la->changes]; for (LoggedChange *lc = la->change; lc != lcend; lc++) { assert((uint)lc->ct < lengthof(_glog_desc)); length += SlCalcObjLength(lc, _glog_desc[lc->ct]) + 1; } length += 4; } length++; SlSetLength(length); for (LoggedAction *la = _gamelog_action; la != laend; la++) { SlWriteByte(la->at); SlObject(la, _glog_action_desc); const LoggedChange *lcend = &la->change[la->changes]; for (LoggedChange *lc = la->change; lc != lcend; lc++) { SlWriteByte(lc->ct); assert((uint)lc->ct < GLCT_END); SlObject(lc, _glog_desc[lc->ct]); } SlWriteByte(GLCT_NONE); } SlWriteByte(GLAT_NONE); } static void Load_GLOG() { Load_GLOG_common(_gamelog_action, _gamelog_actions); } static void Check_GLOG() { Load_GLOG_common(_load_check_data.gamelog_action, _load_check_data.gamelog_actions); } extern const ChunkHandler _gamelog_chunk_handlers[] = { { 'GLOG', Save_GLOG, Load_GLOG, NULL, Check_GLOG, CH_RIFF | CH_LAST } }; openttd-1.5.3/src/saveload/subsidy_sl.cpp0000644000000000000000000000363112627373446017165 0ustar rootroot/* $Id: subsidy_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 subsidy_sl.cpp Code handling saving and loading of subsidies */ #include "../stdafx.h" #include "../subsidy_base.h" #include "saveload.h" #include "../safeguards.h" static const SaveLoad _subsidies_desc[] = { SLE_VAR(Subsidy, cargo_type, SLE_UINT8), SLE_VAR(Subsidy, remaining, SLE_UINT8), SLE_CONDVAR(Subsidy, awarded, SLE_UINT8, 125, SL_MAX_VERSION), SLE_CONDVAR(Subsidy, src_type, SLE_UINT8, 125, SL_MAX_VERSION), SLE_CONDVAR(Subsidy, dst_type, SLE_UINT8, 125, SL_MAX_VERSION), SLE_CONDVAR(Subsidy, src, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), SLE_CONDVAR(Subsidy, src, SLE_UINT16, 5, SL_MAX_VERSION), SLE_CONDVAR(Subsidy, dst, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), SLE_CONDVAR(Subsidy, dst, SLE_UINT16, 5, SL_MAX_VERSION), SLE_END() }; static void Save_SUBS() { Subsidy *s; FOR_ALL_SUBSIDIES(s) { SlSetArrayIndex(s->index); SlObject(s, _subsidies_desc); } } static void Load_SUBS() { int index; while ((index = SlIterateArray()) != -1) { Subsidy *s = new (index) Subsidy(); SlObject(s, _subsidies_desc); } } extern const ChunkHandler _subsidy_chunk_handlers[] = { { 'SUBS', Save_SUBS, Load_SUBS, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/oldloader.h0000644000000000000000000001122612627373446016416 0ustar rootroot/* $Id: oldloader.h 23595 2011-12-19 17:48:04Z rubidium $ */ /* * 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 oldloader.h Declarations of strctures and function used in loader of old savegames */ #ifndef OLDLOADER_H #define OLDLOADER_H #include "saveload.h" #include "../tile_type.h" static const uint BUFFER_SIZE = 4096; static const uint OLD_MAP_SIZE = 256 * 256; struct LoadgameState { FILE *file; uint chunk_size; bool decoding; byte decode_char; uint buffer_count; uint buffer_cur; byte buffer[BUFFER_SIZE]; uint total_read; }; /* OldChunk-Type */ enum OldChunkType { OC_SIMPLE = 0, OC_NULL = 1, OC_CHUNK = 2, OC_ASSERT = 3, /* 4 bits allocated (16 max) */ OC_TTD = 1 << 4, ///< chunk is valid ONLY for TTD savegames OC_TTO = 1 << 5, ///< -//- TTO (default is neither of these) /* 4 bits allocated */ OC_VAR_I8 = 1 << 8, OC_VAR_U8 = 2 << 8, OC_VAR_I16 = 3 << 8, OC_VAR_U16 = 4 << 8, OC_VAR_I32 = 5 << 8, OC_VAR_U32 = 6 << 8, OC_VAR_I64 = 7 << 8, OC_VAR_U64 = 8 << 8, /* 8 bits allocated (256 max) */ OC_FILE_I8 = 1 << 16, OC_FILE_U8 = 2 << 16, OC_FILE_I16 = 3 << 16, OC_FILE_U16 = 4 << 16, OC_FILE_I32 = 5 << 16, OC_FILE_U32 = 6 << 16, /* 8 bits allocated (256 max) */ OC_INT8 = OC_VAR_I8 | OC_FILE_I8, OC_UINT8 = OC_VAR_U8 | OC_FILE_U8, OC_INT16 = OC_VAR_I16 | OC_FILE_I16, OC_UINT16 = OC_VAR_U16 | OC_FILE_U16, OC_INT32 = OC_VAR_I32 | OC_FILE_I32, OC_UINT32 = OC_VAR_U32 | OC_FILE_U32, OC_TILE = OC_VAR_U32 | OC_FILE_U16, /** * Dereference the pointer once before writing to it, * so we do not have to use big static arrays. */ OC_DEREFERENCE_POINTER = 1 << 31, OC_END = 0, ///< End of the whole chunk, all 32 bits set to zero }; DECLARE_ENUM_AS_BIT_SET(OldChunkType) typedef bool OldChunkProc(LoadgameState *ls, int num); struct OldChunks { OldChunkType type; ///< Type of field uint32 amount; ///< Amount of fields void *ptr; ///< Pointer where to save the data (may only be set if offset is 0) uint offset; ///< Offset from basepointer (may only be set if ptr is NULL) OldChunkProc *proc; ///< Pointer to function that is called with OC_CHUNK }; /* If it fails, check lines above.. */ assert_compile(sizeof(TileIndex) == 4); extern uint _bump_assert_value; byte ReadByte(LoadgameState *ls); bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks); bool LoadTTDMain(LoadgameState *ls); bool LoadTTOMain(LoadgameState *ls); static inline uint16 ReadUint16(LoadgameState *ls) { byte x = ReadByte(ls); return x | ReadByte(ls) << 8; } static inline uint32 ReadUint32(LoadgameState *ls) { uint16 x = ReadUint16(ls); return x | ReadUint16(ls) << 16; } /* Help: * - OCL_SVAR: load 'type' to offset 'offset' in a struct of type 'base', which must also * be given via base in LoadChunk() as real pointer * - OCL_VAR: load 'type' to a global var * - OCL_END: every struct must end with this * - OCL_NULL: read 'amount' of bytes and send them to /dev/null or something * - OCL_CHUNK: load another proc to load a part of the savegame, 'amount' times * - OCL_ASSERT: to check if we are really at the place we expect to be.. because old savegames are too binary to be sure ;) */ #define OCL_SVAR(type, base, offset) { type, 1, NULL, (uint)cpp_offsetof(base, offset), NULL } #define OCL_VAR(type, amount, pointer) { type, amount, pointer, 0, NULL } #define OCL_END() { OC_END, 0, NULL, 0, NULL } #define OCL_CNULL(type, amount) { OC_NULL | type, amount, NULL, 0, NULL } #define OCL_CCHUNK(type, amount, proc) { OC_CHUNK | type, amount, NULL, 0, proc } #define OCL_ASSERT(type, size) { OC_ASSERT | type, 1, NULL, size, NULL } #define OCL_NULL(amount) OCL_CNULL((OldChunkType)0, amount) #define OCL_CHUNK(amount, proc) OCL_CCHUNK((OldChunkType)0, amount, proc) #endif /* OLDLOADER_H */ openttd-1.5.3/src/saveload/station_sl.cpp0000644000000000000000000005563412627373446017176 0ustar rootroot/* $Id: station_sl.cpp 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 station_sl.cpp Code handling saving and loading of stations. */ #include "../stdafx.h" #include "../station_base.h" #include "../waypoint_base.h" #include "../roadstop_base.h" #include "../vehicle_base.h" #include "../newgrf_station.h" #include "saveload.h" #include "table/strings.h" #include "../safeguards.h" /** * Update the buoy orders to be waypoint orders. * @param o the order 'list' to check. */ static void UpdateWaypointOrder(Order *o) { if (!o->IsType(OT_GOTO_STATION)) return; const Station *st = Station::Get(o->GetDestination()); if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) return; o->MakeGoToWaypoint(o->GetDestination()); } /** * Perform all steps to upgrade from the old station buoys to the new version * that uses waypoints. This includes some old saveload mechanics. */ void MoveBuoysToWaypoints() { /* Buoy orders become waypoint orders */ OrderList *ol; FOR_ALL_ORDER_LISTS(ol) { VehicleType vt = ol->GetFirstSharedVehicle()->type; if (vt != VEH_SHIP && vt != VEH_TRAIN) continue; for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); } Vehicle *v; FOR_ALL_VEHICLES(v) { VehicleType vt = v->type; if (vt != VEH_SHIP && vt != VEH_TRAIN) continue; UpdateWaypointOrder(&v->current_order); } /* Now make the stations waypoints */ Station *st; FOR_ALL_STATIONS(st) { if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) continue; StationID index = st->index; TileIndex xy = st->xy; Town *town = st->town; StringID string_id = st->string_id; char *name = st->name; st->name = NULL; Date build_date = st->build_date; /* TTDPatch could use "buoys with rail station" for rail waypoints */ bool train = st->train_station.tile != INVALID_TILE; TileArea train_st = st->train_station; /* Delete the station, so we can make it a real waypoint. */ delete st; /* Stations and waypoints are in the same pool, so if a station * is deleted there must be place for a Waypoint. */ assert(Waypoint::CanAllocateItem()); Waypoint *wp = new (index) Waypoint(xy); wp->town = town; wp->string_id = train ? STR_SV_STNAME_WAYPOINT : STR_SV_STNAME_BUOY; wp->name = name; wp->delete_ctr = 0; // Just reset delete counter for once. wp->build_date = build_date; wp->owner = train ? GetTileOwner(xy) : OWNER_NONE; if (IsInsideBS(string_id, STR_SV_STNAME_BUOY, 9)) wp->town_cn = string_id - STR_SV_STNAME_BUOY; if (train) { /* When we make a rail waypoint of the station, convert the map as well. */ TILE_AREA_LOOP(t, train_st) { if (!IsTileType(t, MP_STATION) || GetStationIndex(t) != index) continue; SB(_me[t].m6, 3, 3, STATION_WAYPOINT); wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE); } wp->train_station = train_st; wp->facilities |= FACIL_TRAIN; } else if (IsBuoyTile(xy) && GetStationIndex(xy) == index) { wp->rect.BeforeAddTile(xy, StationRect::ADD_FORCE); wp->facilities |= FACIL_DOCK; } } } void AfterLoadStations() { /* Update the speclists of all stations to point to the currently loaded custom stations. */ BaseStation *st; FOR_ALL_BASE_STATIONS(st) { for (uint i = 0; i < st->num_specs; i++) { if (st->speclist[i].grfid == 0) continue; st->speclist[i].spec = StationClass::GetByGrf(st->speclist[i].grfid, st->speclist[i].localidx, NULL); } if (Station::IsExpected(st)) { Station *sta = Station::From(st); for (const RoadStop *rs = sta->bus_stops; rs != NULL; rs = rs->next) sta->bus_station.Add(rs->xy); for (const RoadStop *rs = sta->truck_stops; rs != NULL; rs = rs->next) sta->truck_station.Add(rs->xy); } StationUpdateCachedTriggers(st); } } /** * (Re)building of road stop caches after loading a savegame. */ void AfterLoadRoadStops() { /* First construct the drive through entries */ RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { if (IsDriveThroughStopTile(rs->xy)) rs->MakeDriveThrough(); } /* And then rebuild the data in those entries */ FOR_ALL_ROADSTOPS(rs) { if (!HasBit(rs->status, RoadStop::RSSFB_BASE_ENTRY)) continue; rs->GetEntry(DIAGDIR_NE)->Rebuild(rs); rs->GetEntry(DIAGDIR_NW)->Rebuild(rs); } } static const SaveLoad _roadstop_desc[] = { SLE_VAR(RoadStop, xy, SLE_UINT32), SLE_CONDNULL(1, 0, 44), SLE_VAR(RoadStop, status, SLE_UINT8), /* Index was saved in some versions, but this is not needed */ SLE_CONDNULL(4, 0, 8), SLE_CONDNULL(2, 0, 44), SLE_CONDNULL(1, 0, 25), SLE_REF(RoadStop, next, REF_ROADSTOPS), SLE_CONDNULL(2, 0, 44), SLE_CONDNULL(4, 0, 24), SLE_CONDNULL(1, 25, 25), SLE_END() }; static const SaveLoad _old_station_desc[] = { SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Station, xy, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDNULL(4, 0, 5), ///< bus/lorry tile SLE_CONDVAR(Station, train_station.tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Station, train_station.tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Station, airport.tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Station, dock_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Station, dock_tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_REF(Station, town, REF_TOWN), SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16), SLE_CONDVAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, 2, SL_MAX_VERSION), SLE_CONDNULL(1, 0, 3), ///< alpha_order SLE_VAR(Station, string_id, SLE_STRINGID), SLE_CONDSTR(Station, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION), SLE_CONDVAR(Station, indtype, SLE_UINT8, 103, SL_MAX_VERSION), SLE_CONDVAR(Station, had_vehicle_of_type, SLE_FILE_U16 | SLE_VAR_U8, 0, 121), SLE_CONDVAR(Station, had_vehicle_of_type, SLE_UINT8, 122, SL_MAX_VERSION), SLE_VAR(Station, time_since_load, SLE_UINT8), SLE_VAR(Station, time_since_unload, SLE_UINT8), SLE_VAR(Station, delete_ctr, SLE_UINT8), SLE_VAR(Station, owner, SLE_UINT8), SLE_VAR(Station, facilities, SLE_UINT8), SLE_VAR(Station, airport.type, SLE_UINT8), SLE_CONDNULL(2, 0, 5), ///< Truck/bus stop status SLE_CONDNULL(1, 0, 4), ///< Blocked months SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U16, 0, 2), SLE_CONDVAR(Station, airport.flags, SLE_VAR_U64 | SLE_FILE_U32, 3, 45), SLE_CONDVAR(Station, airport.flags, SLE_UINT64, 46, SL_MAX_VERSION), SLE_CONDNULL(2, 0, 25), ///< last-vehicle SLE_CONDVAR(Station, last_vehicle_type, SLE_UINT8, 26, SL_MAX_VERSION), SLE_CONDNULL(2, 3, 25), ///< custom station class and id SLE_CONDVAR(Station, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), SLE_CONDVAR(Station, build_date, SLE_INT32, 31, SL_MAX_VERSION), SLE_CONDREF(Station, bus_stops, REF_ROADSTOPS, 6, SL_MAX_VERSION), SLE_CONDREF(Station, truck_stops, REF_ROADSTOPS, 6, SL_MAX_VERSION), /* Used by newstations for graphic variations */ SLE_CONDVAR(Station, random_bits, SLE_UINT16, 27, SL_MAX_VERSION), SLE_CONDVAR(Station, waiting_triggers, SLE_UINT8, 27, SL_MAX_VERSION), SLE_CONDVAR(Station, num_specs, SLE_UINT8, 27, SL_MAX_VERSION), SLE_CONDLST(Station, loading_vehicles, REF_VEHICLE, 57, SL_MAX_VERSION), /* reserve extra space in savegame here. (currently 32 bytes) */ SLE_CONDNULL(32, 2, SL_MAX_VERSION), SLE_END() }; static uint16 _waiting_acceptance; static uint32 _num_flows; static uint16 _cargo_source; static uint32 _cargo_source_xy; static uint8 _cargo_days; static Money _cargo_feeder_share; static const SaveLoad _station_speclist_desc[] = { SLE_CONDVAR(StationSpecList, grfid, SLE_UINT32, 27, SL_MAX_VERSION), SLE_CONDVAR(StationSpecList, localidx, SLE_UINT8, 27, SL_MAX_VERSION), SLE_END() }; std::list _packets; uint32 _num_dests; struct FlowSaveLoad { FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {} StationID source; StationID via; uint32 share; bool restricted; }; static const SaveLoad _flow_desc[] = { SLE_VAR(FlowSaveLoad, source, SLE_UINT16), SLE_VAR(FlowSaveLoad, via, SLE_UINT16), SLE_VAR(FlowSaveLoad, share, SLE_UINT32), SLE_CONDVAR(FlowSaveLoad, restricted, SLE_BOOL, 187, SL_MAX_VERSION), SLE_END() }; /** * Wrapper function to get the GoodsEntry's internal structure while * some of the variables itself are private. * @return the saveload description for GoodsEntry. */ const SaveLoad *GetGoodsDesc() { static const SaveLoad goods_desc[] = { SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, 0, 67), SLE_CONDVAR(GoodsEntry, status, SLE_UINT8, 68, SL_MAX_VERSION), SLE_CONDNULL(2, 51, 67), SLE_VAR(GoodsEntry, time_since_pickup, SLE_UINT8), SLE_VAR(GoodsEntry, rating, SLE_UINT8), SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6), SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67), SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67), SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67), SLE_VAR(GoodsEntry, last_speed, SLE_UINT8), SLE_VAR(GoodsEntry, last_age, SLE_UINT8), SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64), SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67), SLE_CONDVAR(GoodsEntry, amount_fract, SLE_UINT8, 150, SL_MAX_VERSION), SLEG_CONDLST( _packets, REF_CARGO_PACKET, 68, 182), SLEG_CONDVAR( _num_dests, SLE_UINT32, 183, SL_MAX_VERSION), SLE_CONDVAR(GoodsEntry, cargo.reserved_count, SLE_UINT, 181, SL_MAX_VERSION), SLE_CONDVAR(GoodsEntry, link_graph, SLE_UINT16, 183, SL_MAX_VERSION), SLE_CONDVAR(GoodsEntry, node, SLE_UINT16, 183, SL_MAX_VERSION), SLEG_CONDVAR( _num_flows, SLE_UINT32, 183, SL_MAX_VERSION), SLE_CONDVAR(GoodsEntry, max_waiting_cargo, SLE_UINT32, 183, SL_MAX_VERSION), SLE_END() }; return goods_desc; } typedef std::pair > StationCargoPair; static const SaveLoad _cargo_list_desc[] = { SLE_VAR(StationCargoPair, first, SLE_UINT16), SLE_LST(StationCargoPair, second, REF_CARGO_PACKET), SLE_END() }; /** * Swap the temporary packets with the packets without specific destination in * the given goods entry. Assert that at least one of those is empty. * @param ge Goods entry to swap with. */ static void SwapPackets(GoodsEntry *ge) { StationCargoPacketMap &ge_packets = const_cast(*ge->cargo.Packets()); if (_packets.empty()) { std::map >::iterator it(ge_packets.find(INVALID_STATION)); if (it == ge_packets.end()) { return; } else { it->second.swap(_packets); } } else { assert(ge_packets[INVALID_STATION].empty()); ge_packets[INVALID_STATION].swap(_packets); } } static void Load_STNS() { int index; while ((index = SlIterateArray()) != -1) { Station *st = new (index) Station(); SlObject(st, _old_station_desc); _waiting_acceptance = 0; uint num_cargo = IsSavegameVersionBefore(55) ? 12 : NUM_CARGO; for (CargoID i = 0; i < num_cargo; i++) { GoodsEntry *ge = &st->goods[i]; SlObject(ge, GetGoodsDesc()); SwapPackets(ge); if (IsSavegameVersionBefore(68)) { SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); if (GB(_waiting_acceptance, 0, 12) != 0) { /* In old versions, enroute_from used 0xFF as INVALID_STATION */ StationID source = (IsSavegameVersionBefore(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; /* Make sure we can allocate the CargoPacket. This is safe * as there can only be ~64k stations and 32 cargoes in these * savegame versions. As the CargoPacketPool has more than * 16 million entries; it fits by an order of magnitude. */ assert(CargoPacket::CanAllocateItem()); /* Don't construct the packet with station here, because that'll fail with old savegames */ CargoPacket *cp = new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, source, _cargo_source_xy, _cargo_source_xy, _cargo_feeder_share); ge->cargo.Append(cp, INVALID_STATION); SB(ge->status, GoodsEntry::GES_RATING, 1, 1); } } } if (st->num_specs != 0) { /* Allocate speclist memory when loading a game */ st->speclist = CallocT(st->num_specs); for (uint i = 0; i < st->num_specs; i++) { SlObject(&st->speclist[i], _station_speclist_desc); } } } } static void Ptrs_STNS() { /* Don't run when savegame version is higher than or equal to 123. */ if (!IsSavegameVersionBefore(123)) return; Station *st; FOR_ALL_STATIONS(st) { if (!IsSavegameVersionBefore(68)) { for (CargoID i = 0; i < NUM_CARGO; i++) { GoodsEntry *ge = &st->goods[i]; SwapPackets(ge); SlObject(ge, GetGoodsDesc()); SwapPackets(ge); } } SlObject(st, _old_station_desc); } } static const SaveLoad _base_station_desc[] = { SLE_VAR(BaseStation, xy, SLE_UINT32), SLE_REF(BaseStation, town, REF_TOWN), SLE_VAR(BaseStation, string_id, SLE_STRINGID), SLE_STR(BaseStation, name, SLE_STR | SLF_ALLOW_CONTROL, 0), SLE_VAR(BaseStation, delete_ctr, SLE_UINT8), SLE_VAR(BaseStation, owner, SLE_UINT8), SLE_VAR(BaseStation, facilities, SLE_UINT8), SLE_VAR(BaseStation, build_date, SLE_INT32), /* Used by newstations for graphic variations */ SLE_VAR(BaseStation, random_bits, SLE_UINT16), SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8), SLE_VAR(BaseStation, num_specs, SLE_UINT8), SLE_END() }; static OldPersistentStorage _old_st_persistent_storage; static const SaveLoad _station_desc[] = { SLE_WRITEBYTE(Station, facilities, FACIL_NONE), SLE_ST_INCLUDE(), SLE_VAR(Station, train_station.tile, SLE_UINT32), SLE_VAR(Station, train_station.w, SLE_FILE_U8 | SLE_VAR_U16), SLE_VAR(Station, train_station.h, SLE_FILE_U8 | SLE_VAR_U16), SLE_REF(Station, bus_stops, REF_ROADSTOPS), SLE_REF(Station, truck_stops, REF_ROADSTOPS), SLE_VAR(Station, dock_tile, SLE_UINT32), SLE_VAR(Station, airport.tile, SLE_UINT32), SLE_CONDVAR(Station, airport.w, SLE_FILE_U8 | SLE_VAR_U16, 140, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.h, SLE_FILE_U8 | SLE_VAR_U16, 140, SL_MAX_VERSION), SLE_VAR(Station, airport.type, SLE_UINT8), SLE_CONDVAR(Station, airport.layout, SLE_UINT8, 145, SL_MAX_VERSION), SLE_VAR(Station, airport.flags, SLE_UINT64), SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, 145, SL_MAX_VERSION), SLEG_CONDARR(_old_st_persistent_storage.storage, SLE_UINT32, 16, 145, 160), SLE_CONDREF(Station, airport.psa, REF_STORAGE, 161, SL_MAX_VERSION), SLE_VAR(Station, indtype, SLE_UINT8), SLE_VAR(Station, time_since_load, SLE_UINT8), SLE_VAR(Station, time_since_unload, SLE_UINT8), SLE_VAR(Station, last_vehicle_type, SLE_UINT8), SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8), SLE_LST(Station, loading_vehicles, REF_VEHICLE), SLE_CONDVAR(Station, always_accepted, SLE_UINT32, 127, SL_MAX_VERSION), SLE_END() }; static const SaveLoad _waypoint_desc[] = { SLE_WRITEBYTE(Waypoint, facilities, FACIL_WAYPOINT), SLE_ST_INCLUDE(), SLE_VAR(Waypoint, town_cn, SLE_UINT16), SLE_CONDVAR(Waypoint, train_station.tile, SLE_UINT32, 124, SL_MAX_VERSION), SLE_CONDVAR(Waypoint, train_station.w, SLE_FILE_U8 | SLE_VAR_U16, 124, SL_MAX_VERSION), SLE_CONDVAR(Waypoint, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, 124, SL_MAX_VERSION), SLE_END() }; /** * Get the base station description to be used for SL_ST_INCLUDE * @return the base station description. */ const SaveLoad *GetBaseStationDescription() { return _base_station_desc; } static void RealSave_STNN(BaseStation *bst) { bool waypoint = (bst->facilities & FACIL_WAYPOINT) != 0; SlObject(bst, waypoint ? _waypoint_desc : _station_desc); if (!waypoint) { Station *st = Station::From(bst); for (CargoID i = 0; i < NUM_CARGO; i++) { _num_dests = (uint32)st->goods[i].cargo.Packets()->MapSize(); _num_flows = 0; for (FlowStatMap::const_iterator it(st->goods[i].flows.begin()); it != st->goods[i].flows.end(); ++it) { _num_flows += (uint32)it->second.GetShares()->size(); } SlObject(&st->goods[i], GetGoodsDesc()); for (FlowStatMap::const_iterator outer_it(st->goods[i].flows.begin()); outer_it != st->goods[i].flows.end(); ++outer_it) { const FlowStat::SharesMap *shares = outer_it->second.GetShares(); uint32 sum_shares = 0; FlowSaveLoad flow; flow.source = outer_it->first; for (FlowStat::SharesMap::const_iterator inner_it(shares->begin()); inner_it != shares->end(); ++inner_it) { flow.via = inner_it->second; flow.share = inner_it->first - sum_shares; flow.restricted = inner_it->first > outer_it->second.GetUnrestricted(); sum_shares = inner_it->first; assert(flow.share > 0); SlObject(&flow, _flow_desc); } } for (StationCargoPacketMap::ConstMapIterator it(st->goods[i].cargo.Packets()->begin()); it != st->goods[i].cargo.Packets()->end(); ++it) { SlObject(const_cast(&(*it)), _cargo_list_desc); } } } for (uint i = 0; i < bst->num_specs; i++) { SlObject(&bst->speclist[i], _station_speclist_desc); } } static void Save_STNN() { BaseStation *st; /* Write the stations */ FOR_ALL_BASE_STATIONS(st) { SlSetArrayIndex(st->index); SlAutolength((AutolengthProc*)RealSave_STNN, st); } } static void Load_STNN() { int index; while ((index = SlIterateArray()) != -1) { bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0; BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station(); SlObject(bst, waypoint ? _waypoint_desc : _station_desc); if (!waypoint) { Station *st = Station::From(bst); /* Before savegame version 161, persistent storages were not stored in a pool. */ if (IsSavegameVersionBefore(161) && !IsSavegameVersionBefore(145) && st->facilities & FACIL_AIRPORT) { /* Store the old persistent storage. The GRFID will be added later. */ assert(PersistentStorage::CanAllocateItem()); st->airport.psa = new PersistentStorage(0, 0, 0); memcpy(st->airport.psa->storage, _old_st_persistent_storage.storage, sizeof(st->airport.psa->storage)); } for (CargoID i = 0; i < NUM_CARGO; i++) { SlObject(&st->goods[i], GetGoodsDesc()); FlowSaveLoad flow; FlowStat *fs = NULL; StationID prev_source = INVALID_STATION; for (uint32 j = 0; j < _num_flows; ++j) { SlObject(&flow, _flow_desc); if (fs == NULL || prev_source != flow.source) { fs = &(st->goods[i].flows.insert(std::make_pair(flow.source, FlowStat(flow.via, flow.share, flow.restricted))).first->second); } else { fs->AppendShare(flow.via, flow.share, flow.restricted); } prev_source = flow.source; } if (IsSavegameVersionBefore(183)) { SwapPackets(&st->goods[i]); } else { StationCargoPair pair; for (uint j = 0; j < _num_dests; ++j) { SlObject(&pair, _cargo_list_desc); const_cast(*(st->goods[i].cargo.Packets()))[pair.first].swap(pair.second); assert(pair.second.empty()); } } } } if (bst->num_specs != 0) { /* Allocate speclist memory when loading a game */ bst->speclist = CallocT(bst->num_specs); for (uint i = 0; i < bst->num_specs; i++) { SlObject(&bst->speclist[i], _station_speclist_desc); } } } } static void Ptrs_STNN() { /* Don't run when savegame version lower than 123. */ if (IsSavegameVersionBefore(123)) return; Station *st; FOR_ALL_STATIONS(st) { for (CargoID i = 0; i < NUM_CARGO; i++) { GoodsEntry *ge = &st->goods[i]; if (IsSavegameVersionBefore(183)) { SwapPackets(ge); SlObject(ge, GetGoodsDesc()); SwapPackets(ge); } else { SlObject(ge, GetGoodsDesc()); for (StationCargoPacketMap::ConstMapIterator it = ge->cargo.Packets()->begin(); it != ge->cargo.Packets()->end(); ++it) { SlObject(const_cast(&(*it)), _cargo_list_desc); } } } SlObject(st, _station_desc); } Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { SlObject(wp, _waypoint_desc); } } static void Save_ROADSTOP() { RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { SlSetArrayIndex(rs->index); SlObject(rs, _roadstop_desc); } } static void Load_ROADSTOP() { int index; while ((index = SlIterateArray()) != -1) { RoadStop *rs = new (index) RoadStop(INVALID_TILE); SlObject(rs, _roadstop_desc); } } static void Ptrs_ROADSTOP() { RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { SlObject(rs, _roadstop_desc); } } extern const ChunkHandler _station_chunk_handlers[] = { { 'STNS', NULL, Load_STNS, Ptrs_STNS, NULL, CH_ARRAY }, { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, NULL, CH_ARRAY }, { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/order_sl.cpp0000644000000000000000000002277612627373446016631 0ustar rootroot/* $Id: order_sl.cpp 26819 2014-09-14 15:11:33Z rubidium $ */ /* * 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 order_sl.cpp Code handling saving and loading of orders */ #include "../stdafx.h" #include "../order_backup.h" #include "../settings_type.h" #include "../network/network.h" #include "saveload_internal.h" #include "../safeguards.h" /** * Converts this order from an old savegame's version; * it moves all bits to the new location. */ void Order::ConvertFromOldSavegame() { uint8 old_flags = this->flags; this->flags = 0; /* First handle non-stop - use value from savegame if possible, else use value from config file */ if (_settings_client.gui.sg_new_nonstop || (IsSavegameVersionBefore(22) && _savegame_type != SGT_TTO && _savegame_type != SGT_TTD && _settings_client.gui.new_nonstop)) { /* OFB_NON_STOP */ this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_ANY_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); } else { this->SetNonStopType((old_flags & 8) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); } switch (this->GetType()) { /* Only a few types need the other savegame conversions. */ case OT_GOTO_DEPOT: case OT_GOTO_STATION: case OT_LOADING: break; default: return; } if (this->GetType() != OT_GOTO_DEPOT) { /* Then the load flags */ if ((old_flags & 2) != 0) { // OFB_UNLOAD this->SetLoadType(OLFB_NO_LOAD); } else if ((old_flags & 4) == 0) { // !OFB_FULL_LOAD this->SetLoadType(OLF_LOAD_IF_POSSIBLE); } else { /* old OTTD versions stored full_load_any in config file - assume it was enabled when loading */ this->SetLoadType(_settings_client.gui.sg_full_load_any || IsSavegameVersionBefore(22) ? OLF_FULL_LOAD_ANY : OLFB_FULL_LOAD); } if (this->IsType(OT_GOTO_STATION)) this->SetStopLocation(OSL_PLATFORM_FAR_END); /* Finally fix the unload flags */ if ((old_flags & 1) != 0) { // OFB_TRANSFER this->SetUnloadType(OUFB_TRANSFER); } else if ((old_flags & 2) != 0) { // OFB_UNLOAD this->SetUnloadType(OUFB_UNLOAD); } else { this->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); } } else { /* Then the depot action flags */ this->SetDepotActionType(((old_flags & 6) == 4) ? ODATFB_HALT : ODATF_SERVICE_ONLY); /* Finally fix the depot type flags */ uint t = ((old_flags & 6) == 6) ? ODTFB_SERVICE : ODTF_MANUAL; if ((old_flags & 2) != 0) t |= ODTFB_PART_OF_ORDERS; this->SetDepotOrderType((OrderDepotTypeFlags)t); } } /** * Unpacks a order from savegames with version 4 and lower * @param packed packed order * @return unpacked order */ static Order UnpackVersion4Order(uint16 packed) { return Order(GB(packed, 8, 8) << 16 | GB(packed, 4, 4) << 8 | GB(packed, 0, 4)); } /** * Unpacks a order from savegames made with TTD(Patch) * @param packed packed order * @return unpacked order */ Order UnpackOldOrder(uint16 packed) { Order order = UnpackVersion4Order(packed); /* * Sanity check * TTD stores invalid orders as OT_NOTHING with non-zero flags/station */ if (order.IsType(OT_NOTHING) && packed != 0) order.MakeDummy(); return order; } const SaveLoad *GetOrderDescription() { static const SaveLoad _order_desc[] = { SLE_VAR(Order, type, SLE_UINT8), SLE_VAR(Order, flags, SLE_UINT8), SLE_VAR(Order, dest, SLE_UINT16), SLE_REF(Order, next, REF_ORDER), SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, 36, SL_MAX_VERSION), SLE_CONDNULL(1, 36, 181), // refit_subtype SLE_CONDVAR(Order, wait_time, SLE_UINT16, 67, SL_MAX_VERSION), SLE_CONDVAR(Order, travel_time, SLE_UINT16, 67, SL_MAX_VERSION), SLE_CONDVAR(Order, max_speed, SLE_UINT16, 172, SL_MAX_VERSION), /* Leftover from the minor savegame version stuff * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */ SLE_CONDNULL(10, 5, 35), SLE_END() }; return _order_desc; } static void Save_ORDR() { Order *order; FOR_ALL_ORDERS(order) { SlSetArrayIndex(order->index); SlObject(order, GetOrderDescription()); } } static void Load_ORDR() { if (IsSavegameVersionBefore(5, 2)) { /* Version older than 5.2 did not have a ->next pointer. Convert them * (in the old days, the orderlist was 5000 items big) */ size_t len = SlGetFieldLength(); if (IsSavegameVersionBefore(5)) { /* Pre-version 5 had another layout for orders * (uint16 instead of uint32) */ len /= sizeof(uint16); uint16 *orders = MallocT(len + 1); SlArray(orders, len, SLE_UINT16); for (size_t i = 0; i < len; ++i) { Order *o = new (i) Order(); o->AssignOrder(UnpackVersion4Order(orders[i])); } free(orders); } else if (IsSavegameVersionBefore(5, 2)) { len /= sizeof(uint32); uint32 *orders = MallocT(len + 1); SlArray(orders, len, SLE_UINT32); for (size_t i = 0; i < len; ++i) { new (i) Order(orders[i]); } free(orders); } /* Update all the next pointer */ Order *o; FOR_ALL_ORDERS(o) { /* Delete invalid orders */ if (o->IsType(OT_NOTHING)) { delete o; continue; } /* The orders were built like this: * While the order is valid, set the previous will get its next pointer set */ Order *prev = Order::GetIfValid(order_index - 1); if (prev != NULL) prev->next = o; } } else { int index; while ((index = SlIterateArray()) != -1) { Order *order = new (index) Order(); SlObject(order, GetOrderDescription()); if (IsSavegameVersionBefore(190)) { order->SetTravelTimetabled(order->GetTravelTime() > 0); order->SetWaitTimetabled(order->GetWaitTime() > 0); } } } } static void Ptrs_ORDR() { /* Orders from old savegames have pointers corrected in Load_ORDR */ if (IsSavegameVersionBefore(5, 2)) return; Order *o; FOR_ALL_ORDERS(o) { SlObject(o, GetOrderDescription()); } } const SaveLoad *GetOrderListDescription() { static const SaveLoad _orderlist_desc[] = { SLE_REF(OrderList, first, REF_ORDER), SLE_END() }; return _orderlist_desc; } static void Save_ORDL() { OrderList *list; FOR_ALL_ORDER_LISTS(list) { SlSetArrayIndex(list->index); SlObject(list, GetOrderListDescription()); } } static void Load_ORDL() { int index; while ((index = SlIterateArray()) != -1) { /* set num_orders to 0 so it's a valid OrderList */ OrderList *list = new (index) OrderList(0); SlObject(list, GetOrderListDescription()); } } static void Ptrs_ORDL() { OrderList *list; FOR_ALL_ORDER_LISTS(list) { SlObject(list, GetOrderListDescription()); } } const SaveLoad *GetOrderBackupDescription() { static const SaveLoad _order_backup_desc[] = { SLE_VAR(OrderBackup, user, SLE_UINT32), SLE_VAR(OrderBackup, tile, SLE_UINT32), SLE_VAR(OrderBackup, group, SLE_UINT16), SLE_CONDVAR(OrderBackup, service_interval, SLE_FILE_U32 | SLE_VAR_U16, 0, 191), SLE_CONDVAR(OrderBackup, service_interval, SLE_UINT16, 192, SL_MAX_VERSION), SLE_STR(OrderBackup, name, SLE_STR, 0), SLE_CONDNULL(2, 0, 191), // clone (2 bytes of pointer, i.e. garbage) SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, 192, SL_MAX_VERSION), SLE_VAR(OrderBackup, cur_real_order_index, SLE_UINT8), SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_UINT8, 176, SL_MAX_VERSION), SLE_CONDVAR(OrderBackup, current_order_time, SLE_UINT32, 176, SL_MAX_VERSION), SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, 176, SL_MAX_VERSION), SLE_CONDVAR(OrderBackup, timetable_start, SLE_INT32, 176, SL_MAX_VERSION), SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U16, 176, 179), SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_UINT16, 180, SL_MAX_VERSION), SLE_REF(OrderBackup, orders, REF_ORDER), SLE_END() }; return _order_backup_desc; } static void Save_BKOR() { /* We only save this when we're a network server * as we want this information on our clients. For * normal games this information isn't needed. */ if (!_networking || !_network_server) return; OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { SlSetArrayIndex(ob->index); SlObject(ob, GetOrderBackupDescription()); } } void Load_BKOR() { int index; while ((index = SlIterateArray()) != -1) { /* set num_orders to 0 so it's a valid OrderList */ OrderBackup *ob = new (index) OrderBackup(); SlObject(ob, GetOrderBackupDescription()); } } static void Ptrs_BKOR() { OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { SlObject(ob, GetOrderBackupDescription()); } } extern const ChunkHandler _order_chunk_handlers[] = { { 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, NULL, CH_ARRAY}, { 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, NULL, CH_ARRAY}, { 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/story_sl.cpp0000644000000000000000000000716212627373446016666 0ustar rootroot/* $Id: story_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 story_sl.cpp Code handling saving and loading of story pages */ #include "../stdafx.h" #include "../story_base.h" #include "saveload.h" #include "../safeguards.h" /** Called after load to trash broken pages. */ void AfterLoadStoryBook() { if (IsSavegameVersionBefore(185)) { /* Trash all story pages and page elements because * they were saved with wrong data types. */ _story_page_element_pool.CleanPool(); _story_page_pool.CleanPool(); } } static const SaveLoad _story_page_elements_desc[] = { SLE_CONDVAR(StoryPageElement, sort_value, SLE_FILE_U16 | SLE_VAR_U32, 0, 184), SLE_CONDVAR(StoryPageElement, sort_value, SLE_UINT32, 185, SL_MAX_VERSION), SLE_VAR(StoryPageElement, page, SLE_UINT16), SLE_CONDVAR(StoryPageElement, type, SLE_FILE_U16 | SLE_VAR_U8, 0, 184), SLE_CONDVAR(StoryPageElement, type, SLE_UINT8, 185, SL_MAX_VERSION), SLE_VAR(StoryPageElement, referenced_id, SLE_UINT32), SLE_STR(StoryPageElement, text, SLE_STR | SLF_ALLOW_CONTROL, 0), SLE_END() }; static void Save_STORY_PAGE_ELEMENT() { StoryPageElement *s; FOR_ALL_STORY_PAGE_ELEMENTS(s) { SlSetArrayIndex(s->index); SlObject(s, _story_page_elements_desc); } } static void Load_STORY_PAGE_ELEMENT() { int index; uint32 max_sort_value = 0; while ((index = SlIterateArray()) != -1) { StoryPageElement *s = new (index) StoryPageElement(); SlObject(s, _story_page_elements_desc); if (s->sort_value > max_sort_value) { max_sort_value = s->sort_value; } } /* Update the next sort value, so that the next * created page is shown after all existing pages. */ _story_page_element_next_sort_value = max_sort_value + 1; } static const SaveLoad _story_pages_desc[] = { SLE_CONDVAR(StoryPage, sort_value, SLE_FILE_U16 | SLE_VAR_U32, 0, 184), SLE_CONDVAR(StoryPage, sort_value, SLE_UINT32, 185, SL_MAX_VERSION), SLE_VAR(StoryPage, date, SLE_UINT32), SLE_CONDVAR(StoryPage, company, SLE_FILE_U16 | SLE_VAR_U8, 0, 184), SLE_CONDVAR(StoryPage, company, SLE_UINT8, 185, SL_MAX_VERSION), SLE_STR(StoryPage, title, SLE_STR | SLF_ALLOW_CONTROL, 0), SLE_END() }; static void Save_STORY_PAGE() { StoryPage *s; FOR_ALL_STORY_PAGES(s) { SlSetArrayIndex(s->index); SlObject(s, _story_pages_desc); } } static void Load_STORY_PAGE() { int index; uint32 max_sort_value = 0; while ((index = SlIterateArray()) != -1) { StoryPage *s = new (index) StoryPage(); SlObject(s, _story_pages_desc); if (s->sort_value > max_sort_value) { max_sort_value = s->sort_value; } } /* Update the next sort value, so that the next * created page is shown after all existing pages. */ _story_page_next_sort_value = max_sort_value + 1; } extern const ChunkHandler _story_page_chunk_handlers[] = { { 'STPE', Save_STORY_PAGE_ELEMENT, Load_STORY_PAGE_ELEMENT, NULL, NULL, CH_ARRAY}, { 'STPA', Save_STORY_PAGE, Load_STORY_PAGE, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/object_sl.cpp0000644000000000000000000000460312627373446016751 0ustar rootroot/* $Id: object_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 object_sl.cpp Code handling saving and loading of objects */ #include "../stdafx.h" #include "../object_base.h" #include "../object_map.h" #include "saveload.h" #include "newgrf_sl.h" #include "../safeguards.h" static const SaveLoad _object_desc[] = { SLE_VAR(Object, location.tile, SLE_UINT32), SLE_VAR(Object, location.w, SLE_FILE_U8 | SLE_VAR_U16), SLE_VAR(Object, location.h, SLE_FILE_U8 | SLE_VAR_U16), SLE_REF(Object, town, REF_TOWN), SLE_VAR(Object, build_date, SLE_UINT32), SLE_CONDVAR(Object, colour, SLE_UINT8, 148, SL_MAX_VERSION), SLE_CONDVAR(Object, view, SLE_UINT8, 155, SL_MAX_VERSION), SLE_CONDVAR(Object, type, SLE_UINT16, 186, SL_MAX_VERSION), SLE_END() }; static void Save_OBJS() { Object *o; /* Write the objects */ FOR_ALL_OBJECTS(o) { SlSetArrayIndex(o->index); SlObject(o, _object_desc); } } static void Load_OBJS() { int index; while ((index = SlIterateArray()) != -1) { Object *o = new (index) Object(); SlObject(o, _object_desc); } } static void Ptrs_OBJS() { Object *o; FOR_ALL_OBJECTS(o) { SlObject(o, _object_desc); if (IsSavegameVersionBefore(148) && !IsTileType(o->location.tile, MP_OBJECT)) { /* Due to a small bug stale objects could remain. */ delete o; } } } static void Save_OBID() { Save_NewGRFMapping(_object_mngr); } static void Load_OBID() { Load_NewGRFMapping(_object_mngr); } extern const ChunkHandler _object_chunk_handlers[] = { { 'OBID', Save_OBID, Load_OBID, NULL, NULL, CH_ARRAY }, { 'OBJS', Save_OBJS, Load_OBJS, Ptrs_OBJS, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/game_sl.cpp0000644000000000000000000001416512627373446016420 0ustar rootroot/* $Id: game_sl.cpp 27003 2014-10-12 18:41:53Z rubidium $ */ /* * 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 game_sl.cpp Handles the saveload part of the GameScripts */ #include "../stdafx.h" #include "../debug.h" #include "saveload.h" #include "../string_func.h" #include "../game/game.hpp" #include "../game/game_config.hpp" #include "../network/network.h" #include "../game/game_instance.hpp" #include "../game/game_text.hpp" #include "../safeguards.h" static char _game_saveload_name[64]; static int _game_saveload_version; static char _game_saveload_settings[1024]; static bool _game_saveload_is_random; static const SaveLoad _game_script[] = { SLEG_STR(_game_saveload_name, SLE_STRB), SLEG_STR(_game_saveload_settings, SLE_STRB), SLEG_VAR(_game_saveload_version, SLE_UINT32), SLEG_VAR(_game_saveload_is_random, SLE_BOOL), SLE_END() }; static void SaveReal_GSDT(int *index_ptr) { GameConfig *config = GameConfig::GetConfig(); if (config->HasScript()) { strecpy(_game_saveload_name, config->GetName(), lastof(_game_saveload_name)); _game_saveload_version = config->GetVersion(); } else { /* No GameScript is configured for this so store an empty string as name. */ _game_saveload_name[0] = '\0'; _game_saveload_version = -1; } _game_saveload_is_random = config->IsRandom(); _game_saveload_settings[0] = '\0'; config->SettingsToString(_game_saveload_settings, lastof(_game_saveload_settings)); SlObject(NULL, _game_script); Game::Save(); } static void Load_GSDT() { /* Free all current data */ GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME)->Change(NULL); if ((CompanyID)SlIterateArray() == (CompanyID)-1) return; _game_saveload_version = -1; SlObject(NULL, _game_script); if (_networking && !_network_server) { GameInstance::LoadEmpty(); if ((CompanyID)SlIterateArray() != (CompanyID)-1) SlErrorCorrupt("Too many GameScript configs"); return; } GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME); if (StrEmpty(_game_saveload_name)) { } else { config->Change(_game_saveload_name, _game_saveload_version, false, _game_saveload_is_random); if (!config->HasScript()) { /* No version of the GameScript available that can load the data. Try to load the * latest version of the GameScript instead. */ config->Change(_game_saveload_name, -1, false, _game_saveload_is_random); if (!config->HasScript()) { if (strcmp(_game_saveload_name, "%_dummy") != 0) { DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %d which is no longer available.", _game_saveload_name, _game_saveload_version); DEBUG(script, 0, "This game will continue to run without GameScript."); } else { DEBUG(script, 0, "The savegame had no GameScript available at the time of saving."); DEBUG(script, 0, "This game will continue to run without GameScript."); } } else { DEBUG(script, 0, "The savegame has an GameScript by the name '%s', version %d which is no longer available.", _game_saveload_name, _game_saveload_version); DEBUG(script, 0, "The latest version of that GameScript has been loaded instead, but it'll not get the savegame data as it's incompatible."); } /* Make sure the GameScript doesn't get the saveload data, as he was not the * writer of the saveload data in the first place */ _game_saveload_version = -1; } } config->StringToSettings(_game_saveload_settings); /* Start the GameScript directly if it was active in the savegame */ Game::StartNew(); Game::Load(_game_saveload_version); if ((CompanyID)SlIterateArray() != (CompanyID)-1) SlErrorCorrupt("Too many GameScript configs"); } static void Save_GSDT() { SlSetArrayIndex(0); SlAutolength((AutolengthProc *)SaveReal_GSDT, NULL); } extern GameStrings *_current_data; static const char *_game_saveload_string; static uint _game_saveload_strings; static const SaveLoad _game_language_header[] = { SLEG_STR(_game_saveload_string, SLE_STR), SLEG_VAR(_game_saveload_strings, SLE_UINT32), SLE_END() }; static const SaveLoad _game_language_string[] = { SLEG_STR(_game_saveload_string, SLE_STR | SLF_ALLOW_CONTROL), SLE_END() }; static void SaveReal_GSTR(LanguageStrings *ls) { _game_saveload_string = ls->language; _game_saveload_strings = ls->lines.Length(); SlObject(NULL, _game_language_header); for (uint i = 0; i < _game_saveload_strings; i++) { _game_saveload_string = ls->lines[i]; SlObject(NULL, _game_language_string); } } static void Load_GSTR() { delete _current_data; _current_data = new GameStrings(); while (SlIterateArray() != -1) { _game_saveload_string = NULL; SlObject(NULL, _game_language_header); LanguageStrings *ls = new LanguageStrings(_game_saveload_string != NULL ? _game_saveload_string : ""); for (uint i = 0; i < _game_saveload_strings; i++) { SlObject(NULL, _game_language_string); *ls->lines.Append() = stredup(_game_saveload_string != NULL ? _game_saveload_string : ""); } *_current_data->raw_strings.Append() = ls; } /* If there were no strings in the savegame, set GameStrings to NULL */ if (_current_data->raw_strings.Length() == 0) { delete _current_data; _current_data = NULL; return; } _current_data->Compile(); ReconsiderGameScriptLanguage(); } static void Save_GSTR() { if (_current_data == NULL) return; for (uint i = 0; i < _current_data->raw_strings.Length(); i++) { SlSetArrayIndex(i); SlAutolength((AutolengthProc *)SaveReal_GSTR, _current_data->raw_strings[i]); } } extern const ChunkHandler _game_chunk_handlers[] = { { 'GSTR', Save_GSTR, Load_GSTR, NULL, NULL, CH_ARRAY }, { 'GSDT', Save_GSDT, Load_GSDT, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/storage_sl.cpp0000644000000000000000000000345112627373446017147 0ustar rootroot/* $Id: storage_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 storage_sl.cpp Code handling saving and loading of persistent storages. */ #include "../stdafx.h" #include "../newgrf_storage.h" #include "saveload.h" #include "../safeguards.h" /** Description of the data to save and load in #PersistentStorage. */ static const SaveLoad _storage_desc[] = { SLE_CONDVAR(PersistentStorage, grfid, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDARR(PersistentStorage, storage, SLE_UINT32, 16, 161, SL_MAX_VERSION), SLE_END() }; /** Load persistent storage data. */ static void Load_PSAC() { int index; while ((index = SlIterateArray()) != -1) { assert(PersistentStorage::CanAllocateItem()); PersistentStorage *ps = new (index) PersistentStorage(0, 0, 0); SlObject(ps, _storage_desc); } } /** Save persistent storage data. */ static void Save_PSAC() { PersistentStorage *ps; /* Write the industries */ FOR_ALL_STORAGES(ps) { ps->ClearChanges(); SlSetArrayIndex(ps->index); SlObject(ps, _storage_desc); } } /** Chunk handler for persistent storages. */ extern const ChunkHandler _persistent_storage_chunk_handlers[] = { { 'PSAC', Save_PSAC, Load_PSAC, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/newgrf_sl.cpp0000644000000000000000000000645712627373446017004 0ustar rootroot/* $Id: newgrf_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_sl.cpp Code handling saving and loading of newgrf config */ #include "../stdafx.h" #include "../fios.h" #include "saveload.h" #include "newgrf_sl.h" #include "../safeguards.h" /** Save and load the mapping between a spec and the NewGRF it came from. */ static const SaveLoad _newgrf_mapping_desc[] = { SLE_VAR(EntityIDMapping, grfid, SLE_UINT32), SLE_VAR(EntityIDMapping, entity_id, SLE_UINT8), SLE_VAR(EntityIDMapping, substitute_id, SLE_UINT8), SLE_END() }; /** * Save a GRF ID + local id -> OpenTTD's id mapping. * @param mapping The mapping to save. */ void Save_NewGRFMapping(const OverrideManagerBase &mapping) { for (uint i = 0; i < mapping.GetMaxMapping(); i++) { SlSetArrayIndex(i); SlObject(&mapping.mapping_ID[i], _newgrf_mapping_desc); } } /** * Load a GRF ID + local id -> OpenTTD's id mapping. * @param mapping The mapping to load. */ void Load_NewGRFMapping(OverrideManagerBase &mapping) { /* Clear the current mapping stored. * This will create the manager if ever it is not yet done */ mapping.ResetMapping(); uint max_id = mapping.GetMaxMapping(); int index; while ((index = SlIterateArray()) != -1) { if ((uint)index >= max_id) break; SlObject(&mapping.mapping_ID[index], _newgrf_mapping_desc); } } static const SaveLoad _grfconfig_desc[] = { SLE_STR(GRFConfig, filename, SLE_STR, 0x40), SLE_VAR(GRFConfig, ident.grfid, SLE_UINT32), SLE_ARR(GRFConfig, ident.md5sum, SLE_UINT8, 16), SLE_CONDVAR(GRFConfig, version, SLE_UINT32, 151, SL_MAX_VERSION), SLE_ARR(GRFConfig, param, SLE_UINT32, 0x80), SLE_VAR(GRFConfig, num_params, SLE_UINT8), SLE_CONDVAR(GRFConfig, palette, SLE_UINT8, 101, SL_MAX_VERSION), SLE_END() }; static void Save_NGRF() { int index = 0; for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { if (HasBit(c->flags, GCF_STATIC)) continue; SlSetArrayIndex(index++); SlObject(c, _grfconfig_desc); } } static void Load_NGRF_common(GRFConfig *&grfconfig) { ClearGRFConfigList(&grfconfig); while (SlIterateArray() != -1) { GRFConfig *c = new GRFConfig(); SlObject(c, _grfconfig_desc); if (IsSavegameVersionBefore(101)) c->SetSuitablePalette(); AppendToGRFConfigList(&grfconfig, c); } } static void Load_NGRF() { Load_NGRF_common(_grfconfig); /* Append static NewGRF configuration, but only if there are some NewGRFs. */ if (_game_mode != GM_MENU || _all_grfs != NULL) AppendStaticGRFConfigs(&_grfconfig); } static void Check_NGRF() { Load_NGRF_common(_load_check_data.grfconfig); } extern const ChunkHandler _newgrf_chunk_handlers[] = { { 'NGRF', Save_NGRF, Load_NGRF, NULL, Check_NGRF, CH_ARRAY | CH_LAST } }; openttd-1.5.3/src/saveload/economy_sl.cpp0000644000000000000000000000763512627373446017164 0ustar rootroot/* $Id: economy_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 economy_sl.cpp Code handling saving and loading of economy data */ #include "../stdafx.h" #include "../economy_func.h" #include "../economy_base.h" #include "saveload.h" #include "../safeguards.h" /** Prices in pre 126 savegames */ static void Load_PRIC() { /* Old games store 49 base prices, very old games store them as int32 */ int vt = IsSavegameVersionBefore(65) ? SLE_FILE_I32 : SLE_FILE_I64; SlArray(NULL, 49, vt | SLE_VAR_NULL); SlArray(NULL, 49, SLE_FILE_U16 | SLE_VAR_NULL); } /** Cargo payment rates in pre 126 savegames */ static void Load_CAPR() { uint num_cargo = IsSavegameVersionBefore(55) ? 12 : NUM_CARGO; int vt = IsSavegameVersionBefore(65) ? SLE_FILE_I32 : SLE_FILE_I64; SlArray(NULL, num_cargo, vt | SLE_VAR_NULL); SlArray(NULL, num_cargo, SLE_FILE_U16 | SLE_VAR_NULL); } static const SaveLoad _economy_desc[] = { SLE_CONDNULL(4, 0, 64), // max_loan SLE_CONDNULL(8, 65, 143), // max_loan SLE_CONDVAR(Economy, old_max_loan_unround, SLE_FILE_I32 | SLE_VAR_I64, 0, 64), SLE_CONDVAR(Economy, old_max_loan_unround, SLE_INT64, 65, 125), SLE_CONDVAR(Economy, old_max_loan_unround_fract, SLE_UINT16, 70, 125), SLE_CONDVAR(Economy, inflation_prices, SLE_UINT64, 126, SL_MAX_VERSION), SLE_CONDVAR(Economy, inflation_payment, SLE_UINT64, 126, SL_MAX_VERSION), SLE_VAR(Economy, fluct, SLE_INT16), SLE_VAR(Economy, interest_rate, SLE_UINT8), SLE_VAR(Economy, infl_amount, SLE_UINT8), SLE_VAR(Economy, infl_amount_pr, SLE_UINT8), SLE_CONDVAR(Economy, industry_daily_change_counter, SLE_UINT32, 102, SL_MAX_VERSION), SLE_END() }; /** Economy variables */ static void Save_ECMY() { SlObject(&_economy, _economy_desc); } /** Economy variables */ static void Load_ECMY() { SlObject(&_economy, _economy_desc); StartupIndustryDailyChanges(IsSavegameVersionBefore(102)); // old savegames will need to be initialized } static const SaveLoad _cargopayment_desc[] = { SLE_REF(CargoPayment, front, REF_VEHICLE), SLE_VAR(CargoPayment, route_profit, SLE_INT64), SLE_VAR(CargoPayment, visual_profit, SLE_INT64), SLE_CONDVAR(CargoPayment, visual_transfer, SLE_INT64, 181, SL_MAX_VERSION), SLE_END() }; static void Save_CAPY() { CargoPayment *cp; FOR_ALL_CARGO_PAYMENTS(cp) { SlSetArrayIndex(cp->index); SlObject(cp, _cargopayment_desc); } } static void Load_CAPY() { int index; while ((index = SlIterateArray()) != -1) { CargoPayment *cp = new (index) CargoPayment(); SlObject(cp, _cargopayment_desc); } } static void Ptrs_CAPY() { CargoPayment *cp; FOR_ALL_CARGO_PAYMENTS(cp) { SlObject(cp, _cargopayment_desc); } } extern const ChunkHandler _economy_chunk_handlers[] = { { 'CAPY', Save_CAPY, Load_CAPY, Ptrs_CAPY, NULL, CH_ARRAY}, { 'PRIC', NULL, Load_PRIC, NULL, NULL, CH_RIFF | CH_AUTO_LENGTH}, { 'CAPR', NULL, Load_CAPR, NULL, NULL, CH_RIFF | CH_AUTO_LENGTH}, { 'ECMY', Save_ECMY, Load_ECMY, NULL, NULL, CH_RIFF | CH_LAST}, }; openttd-1.5.3/src/saveload/town_sl.cpp0000644000000000000000000003060112627373446016467 0ustar rootroot/* $Id: town_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 town_sl.cpp Code handling saving and loading of towns and houses */ #include "../stdafx.h" #include "../newgrf_house.h" #include "../town.h" #include "../landscape.h" #include "../subsidy_func.h" #include "saveload.h" #include "newgrf_sl.h" #include "../safeguards.h" /** * Rebuild all the cached variables of towns. */ void RebuildTownCaches() { Town *town; InitializeBuildingCounts(); /* Reset town population and num_houses */ FOR_ALL_TOWNS(town) { town->cache.population = 0; town->cache.num_houses = 0; } for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_id = GetHouseType(t); town = Town::GetByTile(t); IncreaseBuildingCount(town, house_id); if (IsHouseCompleted(t)) town->cache.population += HouseSpec::Get(house_id)->population; /* Increase the number of houses for every house, but only once. */ if (GetHouseNorthPart(house_id) == 0) town->cache.num_houses++; } /* Update the population and num_house dependent values */ FOR_ALL_TOWNS(town) { UpdateTownRadius(town); UpdateTownCargoes(town); } UpdateTownCargoBitmap(); } /** * Check and update town and house values. * * Checked are the HouseIDs. Updated are the * town population the number of houses per * town, the town radius and the max passengers * of the town. */ void UpdateHousesAndTowns() { for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_id = GetCleanHouseType(t); if (!HouseSpec::Get(house_id)->enabled && house_id >= NEW_HOUSE_OFFSET) { /* The specs for this type of house are not available any more, so * replace it with the substitute original house type. */ house_id = _house_mngr.GetSubstituteID(house_id); SetHouseType(t, house_id); } } /* Check for cases when a NewGRF has set a wrong house substitute type. */ for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; HouseID house_type = GetCleanHouseType(t); TileIndex north_tile = t + GetHouseNorthPart(house_type); // modifies 'house_type'! if (t == north_tile) { const HouseSpec *hs = HouseSpec::Get(house_type); bool valid_house = true; if (hs->building_flags & TILE_SIZE_2x1) { TileIndex tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_1x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; } else if (hs->building_flags & TILE_SIZE_2x2) { TileIndex tile = t + TileDiffXY(0, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 1) valid_house = false; tile = t + TileDiffXY(1, 0); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 2) valid_house = false; tile = t + TileDiffXY(1, 1); if (!IsTileType(tile, MP_HOUSE) || GetCleanHouseType(tile) != house_type + 3) valid_house = false; } /* If not all tiles of this house are present remove the house. * The other tiles will get removed later in this loop because * their north tile is not the correct type anymore. */ if (!valid_house) DoClearSquare(t); } else if (!IsTileType(north_tile, MP_HOUSE) || GetCleanHouseType(north_tile) != house_type) { /* This tile should be part of a multi-tile building but the * north tile of this house isn't on the map. */ DoClearSquare(t); } } RebuildTownCaches(); } /** Save and load of towns. */ static const SaveLoad _town_desc[] = { SLE_CONDVAR(Town, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Town, xy, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDNULL(2, 0, 2), ///< population, no longer in use SLE_CONDNULL(4, 3, 84), ///< population, no longer in use SLE_CONDNULL(2, 0, 91), ///< num_houses, no longer in use SLE_CONDVAR(Town, townnamegrfid, SLE_UINT32, 66, SL_MAX_VERSION), SLE_VAR(Town, townnametype, SLE_UINT16), SLE_VAR(Town, townnameparts, SLE_UINT32), SLE_CONDSTR(Town, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION), SLE_VAR(Town, flags, SLE_UINT8), SLE_CONDVAR(Town, statues, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), SLE_CONDVAR(Town, statues, SLE_UINT16, 104, SL_MAX_VERSION), SLE_CONDNULL(1, 0, 1), ///< sort_index, no longer in use SLE_CONDVAR(Town, have_ratings, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), SLE_CONDVAR(Town, have_ratings, SLE_UINT16, 104, SL_MAX_VERSION), SLE_CONDARR(Town, ratings, SLE_INT16, 8, 0, 103), SLE_CONDARR(Town, ratings, SLE_INT16, MAX_COMPANIES, 104, SL_MAX_VERSION), /* failed bribe attempts are stored since savegame format 4 */ SLE_CONDARR(Town, unwanted, SLE_INT8, 8, 4, 103), SLE_CONDARR(Town, unwanted, SLE_INT8, MAX_COMPANIES, 104, SL_MAX_VERSION), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_FILE_U16 | SLE_VAR_U32, 0, 8), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_max, SLE_UINT32, 9, 164), SLE_CONDVAR(Town, supplied[CT_MAIL].old_max, SLE_UINT32, 9, 164), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_max, SLE_UINT32, 9, 164), SLE_CONDVAR(Town, supplied[CT_MAIL].new_max, SLE_UINT32, 9, 164), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].old_act, SLE_UINT32, 9, 164), SLE_CONDVAR(Town, supplied[CT_MAIL].old_act, SLE_UINT32, 9, 164), SLE_CONDVAR(Town, supplied[CT_PASSENGERS].new_act, SLE_UINT32, 9, 164), SLE_CONDVAR(Town, supplied[CT_MAIL].new_act, SLE_UINT32, 9, 164), SLE_CONDNULL(2, 0, 163), ///< pct_pass_transported / pct_mail_transported, now computed on the fly SLE_CONDVAR(Town, received[TE_FOOD].old_act, SLE_UINT16, 0, 164), SLE_CONDVAR(Town, received[TE_WATER].old_act, SLE_UINT16, 0, 164), SLE_CONDVAR(Town, received[TE_FOOD].new_act, SLE_UINT16, 0, 164), SLE_CONDVAR(Town, received[TE_WATER].new_act, SLE_UINT16, 0, 164), SLE_CONDARR(Town, goal, SLE_UINT32, NUM_TE, 165, SL_MAX_VERSION), SLE_CONDSTR(Town, text, SLE_STR | SLF_ALLOW_CONTROL, 0, 168, SL_MAX_VERSION), SLE_CONDVAR(Town, time_until_rebuild, SLE_FILE_U8 | SLE_VAR_U16, 0, 53), SLE_CONDVAR(Town, grow_counter, SLE_FILE_U8 | SLE_VAR_U16, 0, 53), SLE_CONDVAR(Town, growth_rate, SLE_FILE_U8 | SLE_VAR_I16, 0, 53), SLE_CONDVAR(Town, time_until_rebuild, SLE_UINT16, 54, SL_MAX_VERSION), SLE_CONDVAR(Town, grow_counter, SLE_UINT16, 54, SL_MAX_VERSION), SLE_CONDVAR(Town, growth_rate, SLE_FILE_I16 | SLE_VAR_U16, 54, 164), SLE_CONDVAR(Town, growth_rate, SLE_UINT16, 165, SL_MAX_VERSION), SLE_VAR(Town, fund_buildings_months, SLE_UINT8), SLE_VAR(Town, road_build_months, SLE_UINT8), SLE_CONDVAR(Town, exclusivity, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDVAR(Town, exclusive_counter, SLE_UINT8, 2, SL_MAX_VERSION), SLE_CONDVAR(Town, larger_town, SLE_BOOL, 56, SL_MAX_VERSION), SLE_CONDVAR(Town, layout, SLE_UINT8, 113, SL_MAX_VERSION), SLE_CONDLST(Town, psa_list, REF_STORAGE, 161, SL_MAX_VERSION), SLE_CONDVAR(Town, cargo_produced, SLE_UINT32, 166, SL_MAX_VERSION), /* reserve extra space in savegame here. (currently 30 bytes) */ SLE_CONDNULL(30, 2, SL_MAX_VERSION), SLE_END() }; static const SaveLoad _town_supplied_desc[] = { SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT32, 165, SL_MAX_VERSION), SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT32, 165, SL_MAX_VERSION), SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT32, 165, SL_MAX_VERSION), SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT32, 165, SL_MAX_VERSION), SLE_END() }; static const SaveLoad _town_received_desc[] = { SLE_CONDVAR(TransportedCargoStat, old_max, SLE_UINT16, 165, SL_MAX_VERSION), SLE_CONDVAR(TransportedCargoStat, new_max, SLE_UINT16, 165, SL_MAX_VERSION), SLE_CONDVAR(TransportedCargoStat, old_act, SLE_UINT16, 165, SL_MAX_VERSION), SLE_CONDVAR(TransportedCargoStat, new_act, SLE_UINT16, 165, SL_MAX_VERSION), SLE_END() }; static void Save_HIDS() { Save_NewGRFMapping(_house_mngr); } static void Load_HIDS() { Load_NewGRFMapping(_house_mngr); } const SaveLoad *GetTileMatrixDesc() { /* Here due to private member vars. */ static const SaveLoad _tilematrix_desc[] = { SLE_VAR(AcceptanceMatrix, area.tile, SLE_UINT32), SLE_VAR(AcceptanceMatrix, area.w, SLE_UINT16), SLE_VAR(AcceptanceMatrix, area.h, SLE_UINT16), SLE_END() }; return _tilematrix_desc; } static void RealSave_Town(Town *t) { SlObject(t, _town_desc); for (CargoID i = 0; i < NUM_CARGO; i++) { SlObject(&t->supplied[i], _town_supplied_desc); } for (int i = TE_BEGIN; i < NUM_TE; i++) { SlObject(&t->received[i], _town_received_desc); } if (IsSavegameVersionBefore(166)) return; SlObject(&t->cargo_accepted, GetTileMatrixDesc()); if (t->cargo_accepted.area.w != 0) { uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32); } } static void Save_TOWN() { Town *t; FOR_ALL_TOWNS(t) { SlSetArrayIndex(t->index); SlAutolength((AutolengthProc*)RealSave_Town, t); } } static void Load_TOWN() { int index; while ((index = SlIterateArray()) != -1) { Town *t = new (index) Town(); SlObject(t, _town_desc); for (CargoID i = 0; i < NUM_CARGO; i++) { SlObject(&t->supplied[i], _town_supplied_desc); } for (int i = TE_BEGIN; i < TE_END; i++) { SlObject(&t->received[i], _town_received_desc); } if (t->townnamegrfid == 0 && !IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1) && GB(t->townnametype, 11, 5) != 15) { SlErrorCorrupt("Invalid town name generator"); } if (IsSavegameVersionBefore(166)) continue; SlObject(&t->cargo_accepted, GetTileMatrixDesc()); if (t->cargo_accepted.area.w != 0) { uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; t->cargo_accepted.data = MallocT(arr_len); SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32); /* Rebuild total cargo acceptance. */ UpdateTownCargoTotal(t); } } } /** Fix pointers when loading town data. */ static void Ptrs_TOWN() { /* Don't run when savegame version lower than 161. */ if (IsSavegameVersionBefore(161)) return; Town *t; FOR_ALL_TOWNS(t) { SlObject(t, _town_desc); } } /** Chunk handler for towns. */ extern const ChunkHandler _town_chunk_handlers[] = { { 'HIDS', Save_HIDS, Load_HIDS, NULL, NULL, CH_ARRAY }, { 'CITY', Save_TOWN, Load_TOWN, Ptrs_TOWN, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/afterload.cpp0000644000000000000000000030054612627373446016753 0ustar rootroot/* $Id: afterload.cpp 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 afterload.cpp Code updating data after game load */ #include "../stdafx.h" #include "../void_map.h" #include "../signs_base.h" #include "../depot_base.h" #include "../fios.h" #include "../gamelog_internal.h" #include "../network/network.h" #include "../gfxinit.h" #include "../viewport_func.h" #include "../industry.h" #include "../clear_map.h" #include "../vehicle_func.h" #include "../string_func.h" #include "../date_func.h" #include "../roadveh.h" #include "../train.h" #include "../station_base.h" #include "../waypoint_base.h" #include "../roadstop_base.h" #include "../tunnelbridge_map.h" #include "../pathfinder/yapf/yapf_cache.h" #include "../elrail_func.h" #include "../signs_func.h" #include "../aircraft.h" #include "../object_map.h" #include "../object_base.h" #include "../tree_map.h" #include "../company_func.h" #include "../road_cmd.h" #include "../ai/ai.hpp" #include "../ai/ai_gui.hpp" #include "../town.h" #include "../economy_base.h" #include "../animated_tile_func.h" #include "../subsidy_base.h" #include "../subsidy_func.h" #include "../newgrf.h" #include "../engine_func.h" #include "../rail_gui.h" #include "../core/backup_type.hpp" #include "../smallmap_gui.h" #include "../news_func.h" #include "../order_backup.h" #include "../error.h" #include "../disaster_vehicle.h" #include "saveload_internal.h" #include #include "../safeguards.h" extern Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY); /** * Makes a tile canal or water depending on the surroundings. * * Must only be used for converting old savegames. Use WaterClass now. * * This as for example docks and shipdepots do not store * whether the tile used to be canal or 'normal' water. * @param t the tile to change. * @param include_invalid_water_class Also consider WATER_CLASS_INVALID, i.e. industry tiles on land */ void SetWaterClassDependingOnSurroundings(TileIndex t, bool include_invalid_water_class) { /* If the slope is not flat, we always assume 'land' (if allowed). Also for one-corner-raised-shores. * Note: Wrt. autosloping under industry tiles this is the most fool-proof behaviour. */ if (!IsTileFlat(t)) { if (include_invalid_water_class) { SetWaterClass(t, WATER_CLASS_INVALID); return; } else { SlErrorCorrupt("Invalid water class for dry tile"); } } /* Mark tile dirty in all cases */ MarkTileDirtyByTile(t); if (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1) { /* tiles at map borders are always WATER_CLASS_SEA */ SetWaterClass(t, WATER_CLASS_SEA); return; } bool has_water = false; bool has_canal = false; bool has_river = false; for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { TileIndex neighbour = TileAddByDiagDir(t, dir); switch (GetTileType(neighbour)) { case MP_WATER: /* clear water and shipdepots have already a WaterClass associated */ if (IsCoast(neighbour)) { has_water = true; } else if (!IsLock(neighbour)) { switch (GetWaterClass(neighbour)) { case WATER_CLASS_SEA: has_water = true; break; case WATER_CLASS_CANAL: has_canal = true; break; case WATER_CLASS_RIVER: has_river = true; break; default: SlErrorCorrupt("Invalid water class for tile"); } } break; case MP_RAILWAY: /* Shore or flooded halftile */ has_water |= (GetRailGroundType(neighbour) == RAIL_GROUND_WATER); break; case MP_TREES: /* trees on shore */ has_water |= (GB(_m[neighbour].m2, 4, 2) == TREE_GROUND_SHORE); break; default: break; } } if (!has_water && !has_canal && !has_river && include_invalid_water_class) { SetWaterClass(t, WATER_CLASS_INVALID); return; } if (has_river && !has_canal) { SetWaterClass(t, WATER_CLASS_RIVER); } else if (has_canal || !has_water) { SetWaterClass(t, WATER_CLASS_CANAL); } else { SetWaterClass(t, WATER_CLASS_SEA); } } static void ConvertTownOwner() { for (TileIndex tile = 0; tile != MapSize(); tile++) { switch (GetTileType(tile)) { case MP_ROAD: if (GB(_m[tile].m5, 4, 2) == ROAD_TILE_CROSSING && HasBit(_m[tile].m3, 7)) { _m[tile].m3 = OWNER_TOWN; } /* FALL THROUGH */ case MP_TUNNELBRIDGE: if (_m[tile].m1 & 0x80) SetTileOwner(tile, OWNER_TOWN); break; default: break; } } } /* since savegame version 4.1, exclusive transport rights are stored at towns */ static void UpdateExclusiveRights() { Town *t; FOR_ALL_TOWNS(t) { t->exclusivity = INVALID_COMPANY; } /* FIXME old exclusive rights status is not being imported (stored in s->blocked_months_obsolete) * could be implemented this way: * 1.) Go through all stations * Build an array town_blocked[ town_id ][ company_id ] * that stores if at least one station in that town is blocked for a company * 2.) Go through that array, if you find a town that is not blocked for * one company, but for all others, then give him exclusivity. */ } static const byte convert_currency[] = { 0, 1, 12, 8, 3, 10, 14, 19, 4, 5, 9, 11, 13, 6, 17, 16, 22, 21, 7, 15, 18, 2, 20, }; /* since savegame version 4.2 the currencies are arranged differently */ static void UpdateCurrencies() { _settings_game.locale.currency = convert_currency[_settings_game.locale.currency]; } /* Up to revision 1413 the invisible tiles at the southern border have not been * MP_VOID, even though they should have. This is fixed by this function */ static void UpdateVoidTiles() { uint i; for (i = 0; i < MapMaxY(); ++i) MakeVoid(i * MapSizeX() + MapMaxX()); for (i = 0; i < MapSizeX(); ++i) MakeVoid(MapSizeX() * MapMaxY() + i); } static inline RailType UpdateRailType(RailType rt, RailType min) { return rt >= min ? (RailType)(rt + 1): rt; } /** * Update the viewport coordinates of all signs. */ void UpdateAllVirtCoords() { UpdateAllStationVirtCoords(); UpdateAllSignVirtCoords(); UpdateAllTownVirtCoords(); } /** * Initialization of the windows and several kinds of caches. * This is not done directly in AfterLoadGame because these * functions require that all saveload conversions have been * done. As people tend to add savegame conversion stuff after * the intialization of the windows and caches quite some bugs * had been made. * Moving this out of there is both cleaner and less bug-prone. */ static void InitializeWindowsAndCaches() { /* Initialize windows */ ResetWindowSystem(); SetupColoursAndInitialWindow(); /* Update coordinates of the signs. */ UpdateAllVirtCoords(); ResetViewportAfterLoadGame(); Company *c; FOR_ALL_COMPANIES(c) { /* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it * accordingly if it is not the case. No need to set it on companies that are not been used already, * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */ if (_file_to_saveload.filetype == FT_SCENARIO && c->inaugurated_year != MIN_YEAR) { c->inaugurated_year = _cur_year; } } /* Count number of objects per type */ Object *o; FOR_ALL_OBJECTS(o) { Object::IncTypeCount(o->type); } /* Identify owners of persistent storage arrays */ Industry *i; FOR_ALL_INDUSTRIES(i) { if (i->psa != NULL) { i->psa->feature = GSF_INDUSTRIES; i->psa->tile = i->location.tile; } } Station *s; FOR_ALL_STATIONS(s) { if (s->airport.psa != NULL) { s->airport.psa->feature = GSF_AIRPORTS; s->airport.psa->tile = s->airport.tile; } } Town *t; FOR_ALL_TOWNS(t) { for (std::list::iterator it = t->psa_list.begin(); it != t->psa_list.end(); ++it) { (*it)->feature = GSF_FAKE_TOWNS; (*it)->tile = t->xy; } } RecomputePrices(); GroupStatistics::UpdateAfterLoad(); Station::RecomputeIndustriesNearForAll(); RebuildSubsidisedSourceAndDestinationCache(); /* Towns have a noise controlled number of airports system * So each airport's noise value must be added to the town->noise_reached value * Reset each town's noise_reached value to '0' before. */ UpdateAirportsNoise(); CheckTrainsLengths(); ShowNewGRFError(); ShowAIDebugWindowIfAIError(); /* Rebuild the smallmap list of owners. */ BuildOwnerLegend(); } typedef void (CDECL *SignalHandlerPointer)(int); static SignalHandlerPointer _prev_segfault = NULL; static SignalHandlerPointer _prev_abort = NULL; static SignalHandlerPointer _prev_fpe = NULL; static void CDECL HandleSavegameLoadCrash(int signum); /** * Replaces signal handlers of SIGSEGV and SIGABRT * and stores pointers to original handlers in memory. */ static void SetSignalHandlers() { _prev_segfault = signal(SIGSEGV, HandleSavegameLoadCrash); _prev_abort = signal(SIGABRT, HandleSavegameLoadCrash); _prev_fpe = signal(SIGFPE, HandleSavegameLoadCrash); } /** * Resets signal handlers back to original handlers. */ static void ResetSignalHandlers() { signal(SIGSEGV, _prev_segfault); signal(SIGABRT, _prev_abort); signal(SIGFPE, _prev_fpe); } /** * Try to find the overridden GRF identifier of the given GRF. * @param c the GRF to get the 'previous' version of. * @return the GRF identifier or \a c if none could be found. */ static const GRFIdentifier *GetOverriddenIdentifier(const GRFConfig *c) { const LoggedAction *la = &_gamelog_action[_gamelog_actions - 1]; if (la->at != GLAT_LOAD) return &c->ident; const LoggedChange *lcend = &la->change[la->changes]; for (const LoggedChange *lc = la->change; lc != lcend; lc++) { if (lc->ct == GLCT_GRFCOMPAT && lc->grfcompat.grfid == c->ident.grfid) return &lc->grfcompat; } return &c->ident; } /** Was the saveload crash because of missing NewGRFs? */ static bool _saveload_crash_with_missing_newgrfs = false; /** * Did loading the savegame cause a crash? If so, * were NewGRFs missing? * @return when the saveload crashed due to missing NewGRFs. */ bool SaveloadCrashWithMissingNewGRFs() { return _saveload_crash_with_missing_newgrfs; } /** * Signal handler used to give a user a more useful report for crashes during * the savegame loading process; especially when there's problems with the * NewGRFs that are required by the savegame. * @param signum received signal */ static void CDECL HandleSavegameLoadCrash(int signum) { ResetSignalHandlers(); char buffer[8192]; char *p = buffer; p += seprintf(p, lastof(buffer), "Loading your savegame caused OpenTTD to crash.\n"); for (const GRFConfig *c = _grfconfig; !_saveload_crash_with_missing_newgrfs && c != NULL; c = c->next) { _saveload_crash_with_missing_newgrfs = HasBit(c->flags, GCF_COMPATIBLE) || c->status == GCS_NOT_FOUND; } if (_saveload_crash_with_missing_newgrfs) { p += seprintf(p, lastof(buffer), "This is most likely caused by a missing NewGRF or a NewGRF that\n" "has been loaded as replacement for a missing NewGRF. OpenTTD\n" "cannot easily determine whether a replacement NewGRF is of a newer\n" "or older version.\n" "It will load a NewGRF with the same GRF ID as the missing NewGRF.\n" "This means that if the author makes incompatible NewGRFs with the\n" "same GRF ID OpenTTD cannot magically do the right thing. In most\n" "cases OpenTTD will load the savegame and not crash, but this is an\n" "exception.\n" "Please load the savegame with the appropriate NewGRFs installed.\n" "The missing/compatible NewGRFs are:\n"); for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) { if (HasBit(c->flags, GCF_COMPATIBLE)) { const GRFIdentifier *replaced = GetOverriddenIdentifier(c); char buf[40]; md5sumToString(buf, lastof(buf), replaced->md5sum); p += seprintf(p, lastof(buffer), "NewGRF %08X (checksum %s) not found.\n Loaded NewGRF \"%s\" with same GRF ID instead.\n", BSWAP32(c->ident.grfid), buf, c->filename); } if (c->status == GCS_NOT_FOUND) { char buf[40]; md5sumToString(buf, lastof(buf), c->ident.md5sum); p += seprintf(p, lastof(buffer), "NewGRF %08X (%s) not found; checksum %s.\n", BSWAP32(c->ident.grfid), c->filename, buf); } } } else { p += seprintf(p, lastof(buffer), "This is probably caused by a corruption in the savegame.\n" "Please file a bug report and attach this savegame.\n"); } ShowInfo(buffer); SignalHandlerPointer call = NULL; switch (signum) { case SIGSEGV: call = _prev_segfault; break; case SIGABRT: call = _prev_abort; break; case SIGFPE: call = _prev_fpe; break; default: NOT_REACHED(); } if (call != NULL) call(signum); } /** * Tries to change owner of this rail tile to a valid owner. In very old versions it could happen that * a rail track had an invalid owner. When conversion isn't possible, track is removed. * @param t tile to update */ static void FixOwnerOfRailTrack(TileIndex t) { assert(!Company::IsValidID(GetTileOwner(t)) && (IsLevelCrossingTile(t) || IsPlainRailTile(t))); /* remove leftover rail piece from crossing (from very old savegames) */ Train *v = NULL, *w; FOR_ALL_TRAINS(w) { if (w->tile == t) { v = w; break; } } if (v != NULL) { /* when there is a train on crossing (it could happen in TTD), set owner of crossing to train owner */ SetTileOwner(t, v->owner); return; } /* try to find any connected rail */ for (DiagDirection dd = DIAGDIR_BEGIN; dd < DIAGDIR_END; dd++) { TileIndex tt = t + TileOffsByDiagDir(dd); if (GetTileTrackStatus(t, TRANSPORT_RAIL, 0, dd) != 0 && GetTileTrackStatus(tt, TRANSPORT_RAIL, 0, ReverseDiagDir(dd)) != 0 && Company::IsValidID(GetTileOwner(tt))) { SetTileOwner(t, GetTileOwner(tt)); return; } } if (IsLevelCrossingTile(t)) { /* else change the crossing to normal road (road vehicles won't care) */ MakeRoadNormal(t, GetCrossingRoadBits(t), GetRoadTypes(t), GetTownIndex(t), GetRoadOwner(t, ROADTYPE_ROAD), GetRoadOwner(t, ROADTYPE_TRAM)); return; } /* if it's not a crossing, make it clean land */ MakeClear(t, CLEAR_GRASS, 0); } /** * Fixes inclination of a vehicle. Older OpenTTD versions didn't update the bits correctly. * @param v vehicle * @param dir vehicle's direction, or # INVALID_DIR if it can be ignored * @return inclination bits to set */ static uint FixVehicleInclination(Vehicle *v, Direction dir) { /* Compute place where this vehicle entered the tile */ int entry_x = v->x_pos; int entry_y = v->y_pos; switch (dir) { case DIR_NE: entry_x |= TILE_UNIT_MASK; break; case DIR_NW: entry_y |= TILE_UNIT_MASK; break; case DIR_SW: entry_x &= ~TILE_UNIT_MASK; break; case DIR_SE: entry_y &= ~TILE_UNIT_MASK; break; case INVALID_DIR: break; default: NOT_REACHED(); } byte entry_z = GetSlopePixelZ(entry_x, entry_y); /* Compute middle of the tile. */ int middle_x = (v->x_pos & ~TILE_UNIT_MASK) + TILE_SIZE / 2; int middle_y = (v->y_pos & ~TILE_UNIT_MASK) + TILE_SIZE / 2; byte middle_z = GetSlopePixelZ(middle_x, middle_y); /* middle_z == entry_z, no height change. */ if (middle_z == entry_z) return 0; /* middle_z < entry_z, we are going downwards. */ if (middle_z < entry_z) return 1U << GVF_GOINGDOWN_BIT; /* middle_z > entry_z, we are going upwards. */ return 1U << GVF_GOINGUP_BIT; } /** * Checks for the possibility that a bridge may be on this tile * These are in fact all the tile types on which a bridge can be found * @param t The tile to analyze * @return True if a bridge might have been present prior to savegame 194. */ static inline bool MayHaveBridgeAbove(TileIndex t) { return IsTileType(t, MP_CLEAR) || IsTileType(t, MP_RAILWAY) || IsTileType(t, MP_ROAD) || IsTileType(t, MP_WATER) || IsTileType(t, MP_TUNNELBRIDGE) || IsTileType(t, MP_OBJECT); } /** * Perform a (large) amount of savegame conversion *magic* in order to * load older savegames and to fill the caches for various purposes. * @return True iff conversion went without a problem. */ bool AfterLoadGame() { SetSignalHandlers(); TileIndex map_size = MapSize(); extern TileIndex _cur_tileloop_tile; // From landscape.cpp. /* The LFSR used in RunTileLoop iteration cannot have a zeroed state, make it non-zeroed. */ if (_cur_tileloop_tile == 0) _cur_tileloop_tile = 1; if (IsSavegameVersionBefore(98)) GamelogOldver(); GamelogTestRevision(); GamelogTestMode(); if (IsSavegameVersionBefore(98)) GamelogGRFAddList(_grfconfig); if (IsSavegameVersionBefore(119)) { _pause_mode = (_pause_mode == 2) ? PM_PAUSED_NORMAL : PM_UNPAUSED; } else if (_network_dedicated && (_pause_mode & PM_PAUSED_ERROR) != 0) { DEBUG(net, 0, "The loading savegame was paused due to an error state."); DEBUG(net, 0, " The savegame cannot be used for multiplayer!"); /* Restore the signals */ ResetSignalHandlers(); return false; } else if (!_networking || _network_server) { /* If we are in single player, i.e. not networking, and loading the * savegame or we are loading the savegame as network server we do * not want to be bothered by being paused because of the automatic * reason of a network server, e.g. joining clients or too few * active clients. Note that resetting these values for a network * client are very bad because then the client is going to execute * the game loop when the server is not, i.e. it desyncs. */ _pause_mode &= ~PMB_PAUSED_NETWORK; } /* In very old versions, size of train stations was stored differently. * They had swapped width and height if station was built along the Y axis. * TTO and TTD used 3 bits for width/height, while OpenTTD used 4. * Because the data stored by TTDPatch are unusable for rail stations > 7x7, * recompute the width and height. Doing this unconditionally for all old * savegames simplifies the code. */ if (IsSavegameVersionBefore(2)) { Station *st; FOR_ALL_STATIONS(st) { st->train_station.w = st->train_station.h = 0; } for (TileIndex t = 0; t < map_size; t++) { if (!IsTileType(t, MP_STATION)) continue; if (_m[t].m5 > 7) continue; // is it a rail station tile? st = Station::Get(_m[t].m2); assert(st->train_station.tile != 0); int dx = TileX(t) - TileX(st->train_station.tile); int dy = TileY(t) - TileY(st->train_station.tile); assert(dx >= 0 && dy >= 0); st->train_station.w = max(st->train_station.w, dx + 1); st->train_station.h = max(st->train_station.h, dy + 1); } } if (IsSavegameVersionBefore(194)) { _settings_game.construction.max_heightlevel = 15; /* In old savegame versions, the heightlevel was coded in bits 0..3 of the type field */ for (TileIndex t = 0; t < map_size; t++) { _m[t].height = GB(_m[t].type, 0, 4); SB(_m[t].type, 0, 2, GB(_me[t].m6, 0, 2)); SB(_me[t].m6, 0, 2, 0); if (MayHaveBridgeAbove(t)) { SB(_m[t].type, 2, 2, GB(_me[t].m6, 6, 2)); SB(_me[t].m6, 6, 2, 0); } else { SB(_m[t].type, 2, 2, 0); } } } /* in version 2.1 of the savegame, town owner was unified. */ if (IsSavegameVersionBefore(2, 1)) ConvertTownOwner(); /* from version 4.1 of the savegame, exclusive rights are stored at towns */ if (IsSavegameVersionBefore(4, 1)) UpdateExclusiveRights(); /* from version 4.2 of the savegame, currencies are in a different order */ if (IsSavegameVersionBefore(4, 2)) UpdateCurrencies(); /* In old version there seems to be a problem that water is owned by * OWNER_NONE, not OWNER_WATER.. I can't replicate it for the current * (4.3) version, so I just check when versions are older, and then * walk through the whole map.. */ if (IsSavegameVersionBefore(4, 3)) { for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_WATER) && GetTileOwner(t) >= MAX_COMPANIES) { SetTileOwner(t, OWNER_WATER); } } } if (IsSavegameVersionBefore(84)) { Company *c; FOR_ALL_COMPANIES(c) { c->name = CopyFromOldName(c->name_1); if (c->name != NULL) c->name_1 = STR_SV_UNNAMED; c->president_name = CopyFromOldName(c->president_name_1); if (c->president_name != NULL) c->president_name_1 = SPECSTR_PRESIDENT_NAME; } Station *st; FOR_ALL_STATIONS(st) { st->name = CopyFromOldName(st->string_id); /* generating new name would be too much work for little effect, use the station name fallback */ if (st->name != NULL) st->string_id = STR_SV_STNAME_FALLBACK; } Town *t; FOR_ALL_TOWNS(t) { t->name = CopyFromOldName(t->townnametype); if (t->name != NULL) t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; } } /* From this point the old names array is cleared. */ ResetOldNames(); if (IsSavegameVersionBefore(106)) { /* no station is determined by 'tile == INVALID_TILE' now (instead of '0') */ Station *st; FOR_ALL_STATIONS(st) { if (st->airport.tile == 0) st->airport.tile = INVALID_TILE; if (st->dock_tile == 0) st->dock_tile = INVALID_TILE; if (st->train_station.tile == 0) st->train_station.tile = INVALID_TILE; } /* the same applies to Company::location_of_HQ */ Company *c; FOR_ALL_COMPANIES(c) { if (c->location_of_HQ == 0 || (IsSavegameVersionBefore(4) && c->location_of_HQ == 0xFFFF)) { c->location_of_HQ = INVALID_TILE; } } } /* convert road side to my format. */ if (_settings_game.vehicle.road_side) _settings_game.vehicle.road_side = 1; /* Check if all NewGRFs are present, we are very strict in MP mode */ GRFListCompatibility gcf_res = IsGoodGRFConfigList(_grfconfig); for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { if (c->status == GCS_NOT_FOUND) { GamelogGRFRemove(c->ident.grfid); } else if (HasBit(c->flags, GCF_COMPATIBLE)) { GamelogGRFCompatible(&c->ident); } } if (_networking && gcf_res != GLC_ALL_GOOD) { SetSaveLoadError(STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH); /* Restore the signals */ ResetSignalHandlers(); return false; } switch (gcf_res) { case GLC_COMPATIBLE: ShowErrorMessage(STR_NEWGRF_COMPATIBLE_LOAD_WARNING, INVALID_STRING_ID, WL_CRITICAL); break; case GLC_NOT_FOUND: ShowErrorMessage(STR_NEWGRF_DISABLED_WARNING, INVALID_STRING_ID, WL_CRITICAL); _pause_mode = PM_PAUSED_ERROR; break; default: break; } /* The value of _date_fract got divided, so make sure that old games are converted correctly. */ if (IsSavegameVersionBefore(11, 1) || (IsSavegameVersionBefore(147) && _date_fract > DAY_TICKS)) _date_fract /= 885; /* Update current year * must be done before loading sprites as some newgrfs check it */ SetDate(_date, _date_fract); /* * Force the old behaviour for compatibility reasons with old savegames. As new * settings can only be loaded from new savegames loading old savegames with new * versions of OpenTTD will normally initialize settings newer than the savegame * version with "new game" defaults which the player can define to their liking. * For some settings we override that to keep the behaviour the same as when the * game was saved. * * Note that there is no non-stop in here. This is because the setting could have * either value in TTDPatch. To convert it properly the user has to make sure the * right value has been chosen in the settings. Otherwise we will be converting * it incorrectly in half of the times without a means to correct that. */ if (IsSavegameVersionBefore(4, 2)) _settings_game.station.modified_catchment = false; if (IsSavegameVersionBefore(6, 1)) _settings_game.pf.forbid_90_deg = false; if (IsSavegameVersionBefore(21)) _settings_game.vehicle.train_acceleration_model = 0; if (IsSavegameVersionBefore(90)) _settings_game.vehicle.plane_speed = 4; if (IsSavegameVersionBefore(95)) _settings_game.vehicle.dynamic_engines = 0; if (IsSavegameVersionBefore(96)) _settings_game.economy.station_noise_level = false; if (IsSavegameVersionBefore(133)) { _settings_game.vehicle.roadveh_acceleration_model = 0; _settings_game.vehicle.train_slope_steepness = 3; } if (IsSavegameVersionBefore(134)) _settings_game.economy.feeder_payment_share = 75; if (IsSavegameVersionBefore(138)) _settings_game.vehicle.plane_crashes = 2; if (IsSavegameVersionBefore(139)) _settings_game.vehicle.roadveh_slope_steepness = 7; if (IsSavegameVersionBefore(143)) _settings_game.economy.allow_town_level_crossings = true; if (IsSavegameVersionBefore(159)) { _settings_game.vehicle.max_train_length = 50; _settings_game.construction.max_bridge_length = 64; _settings_game.construction.max_tunnel_length = 64; } if (IsSavegameVersionBefore(166)) _settings_game.economy.infrastructure_maintenance = false; if (IsSavegameVersionBefore(183)) { _settings_game.linkgraph.distribution_pax = DT_MANUAL; _settings_game.linkgraph.distribution_mail = DT_MANUAL; _settings_game.linkgraph.distribution_armoured = DT_MANUAL; _settings_game.linkgraph.distribution_default = DT_MANUAL; } /* Load the sprites */ GfxLoadSprites(); LoadStringWidthTable(); /* Copy temporary data to Engine pool */ CopyTempEngineData(); /* Connect front and rear engines of multiheaded trains and converts * subtype to the new format */ if (IsSavegameVersionBefore(17, 1)) ConvertOldMultiheadToNew(); /* Connect front and rear engines of multiheaded trains */ ConnectMultiheadedTrains(); /* Fix the CargoPackets *and* fix the caches of CargoLists. * If this isn't done before Stations and especially Vehicles are * running their AfterLoad we might get in trouble. In the case of * vehicles we could give the wrong (cached) count of items in a * vehicle which causes different results when getting their caches * filled; and that could eventually lead to desyncs. */ CargoPacket::AfterLoad(); /* Oilrig was moved from id 15 to 9. We have to do this conversion * here as AfterLoadVehicles can check it indirectly via the newgrf * code. */ if (IsSavegameVersionBefore(139)) { Station *st; FOR_ALL_STATIONS(st) { if (st->airport.tile != INVALID_TILE && st->airport.type == 15) { st->airport.type = AT_OILRIG; } } } /* Update all vehicles */ AfterLoadVehicles(true); /* Make sure there is an AI attached to an AI company */ { Company *c; FOR_ALL_COMPANIES(c) { if (c->is_ai && c->ai_instance == NULL) AI::StartNew(c->index); } } /* make sure there is a town in the game */ if (_game_mode == GM_NORMAL && Town::GetNumItems() == 0) { SetSaveLoadError(STR_ERROR_NO_TOWN_IN_SCENARIO); /* Restore the signals */ ResetSignalHandlers(); return false; } /* The void tiles on the southern border used to belong to a wrong class (pre 4.3). * This problem appears in savegame version 21 too, see r3455. But after loading the * savegame and saving again, the buggy map array could be converted to new savegame * version. It didn't show up before r12070. */ if (IsSavegameVersionBefore(87)) UpdateVoidTiles(); /* If Load Scenario / New (Scenario) Game is used, * a company does not exist yet. So create one here. * 1 exception: network-games. Those can have 0 companies * But this exception is not true for non-dedicated network servers! */ if (!Company::IsValidID(COMPANY_FIRST) && (!_networking || (_networking && _network_server && !_network_dedicated))) { DoStartupNewCompany(false); Company *c = Company::Get(COMPANY_FIRST); c->settings = _settings_client.company; } /* Fix the cache for cargo payments. */ CargoPayment *cp; FOR_ALL_CARGO_PAYMENTS(cp) { cp->front->cargo_payment = cp; cp->current_station = cp->front->last_station_visited; } if (IsSavegameVersionBefore(72)) { /* Locks in very old savegames had OWNER_WATER as owner */ for (TileIndex t = 0; t < MapSize(); t++) { switch (GetTileType(t)) { default: break; case MP_WATER: if (GetWaterTileType(t) == WATER_TILE_LOCK && GetTileOwner(t) == OWNER_WATER) SetTileOwner(t, OWNER_NONE); break; case MP_STATION: { if (HasBit(_me[t].m6, 3)) SetBit(_me[t].m6, 2); StationGfx gfx = GetStationGfx(t); StationType st; if ( IsInsideMM(gfx, 0, 8)) { // Rail station st = STATION_RAIL; SetStationGfx(t, gfx - 0); } else if (IsInsideMM(gfx, 8, 67)) { // Airport st = STATION_AIRPORT; SetStationGfx(t, gfx - 8); } else if (IsInsideMM(gfx, 67, 71)) { // Truck st = STATION_TRUCK; SetStationGfx(t, gfx - 67); } else if (IsInsideMM(gfx, 71, 75)) { // Bus st = STATION_BUS; SetStationGfx(t, gfx - 71); } else if (gfx == 75) { // Oil rig st = STATION_OILRIG; SetStationGfx(t, gfx - 75); } else if (IsInsideMM(gfx, 76, 82)) { // Dock st = STATION_DOCK; SetStationGfx(t, gfx - 76); } else if (gfx == 82) { // Buoy st = STATION_BUOY; SetStationGfx(t, gfx - 82); } else if (IsInsideMM(gfx, 83, 168)) { // Extended airport st = STATION_AIRPORT; SetStationGfx(t, gfx - 83 + 67 - 8); } else if (IsInsideMM(gfx, 168, 170)) { // Drive through truck st = STATION_TRUCK; SetStationGfx(t, gfx - 168 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); } else if (IsInsideMM(gfx, 170, 172)) { // Drive through bus st = STATION_BUS; SetStationGfx(t, gfx - 170 + GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); } else { /* Restore the signals */ ResetSignalHandlers(); return false; } SB(_me[t].m6, 3, 3, st); break; } } } } for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_STATION: { BaseStation *bst = BaseStation::GetByTile(t); /* Set up station spread */ bst->rect.BeforeAddTile(t, StationRect::ADD_FORCE); /* Waypoints don't have road stops/oil rigs in the old format */ if (!Station::IsExpected(bst)) break; Station *st = Station::From(bst); switch (GetStationType(t)) { case STATION_TRUCK: case STATION_BUS: if (IsSavegameVersionBefore(6)) { /* Before version 5 you could not have more than 250 stations. * Version 6 adds large maps, so you could only place 253*253 * road stops on a map (no freeform edges) = 64009. So, yes * someone could in theory create such a full map to trigger * this assertion, it's safe to assume that's only something * theoretical and does not happen in normal games. */ assert(RoadStop::CanAllocateItem()); /* From this version on there can be multiple road stops of the * same type per station. Convert the existing stops to the new * internal data structure. */ RoadStop *rs = new RoadStop(t); RoadStop **head = IsTruckStop(t) ? &st->truck_stops : &st->bus_stops; *head = rs; } break; case STATION_OILRIG: { /* Very old savegames sometimes have phantom oil rigs, i.e. * an oil rig which got shut down, but not completely removed from * the map */ TileIndex t1 = TILE_ADDXY(t, 0, 1); if (IsTileType(t1, MP_INDUSTRY) && GetIndustryGfx(t1) == GFX_OILRIG_1) { /* The internal encoding of oil rigs was changed twice. * It was 3 (till 2.2) and later 5 (till 5.1). * Setting it unconditionally does not hurt. */ Station::GetByTile(t)->airport.type = AT_OILRIG; } else { DeleteOilRig(t); } break; } default: break; } break; } default: break; } } /* In version 2.2 of the savegame, we have new airports, so status of all aircraft is reset. * This has to be called after the oilrig airport_type update above ^^^ ! */ if (IsSavegameVersionBefore(2, 2)) UpdateOldAircraft(); /* In version 6.1 we put the town index in the map-array. To do this, we need * to use m2 (16bit big), so we need to clean m2, and that is where this is * all about ;) */ if (IsSavegameVersionBefore(6, 1)) { for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_HOUSE: _m[t].m4 = _m[t].m2; SetTownIndex(t, CalcClosestTownFromTile(t)->index); break; case MP_ROAD: _m[t].m4 |= (_m[t].m2 << 4); if ((GB(_m[t].m5, 4, 2) == ROAD_TILE_CROSSING ? (Owner)_m[t].m3 : GetTileOwner(t)) == OWNER_TOWN) { SetTownIndex(t, CalcClosestTownFromTile(t)->index); } else { SetTownIndex(t, 0); } break; default: break; } } } /* Force the freeform edges to false for old savegames. */ if (IsSavegameVersionBefore(111)) { _settings_game.construction.freeform_edges = false; } /* From version 9.0, we update the max passengers of a town (was sometimes negative * before that. */ if (IsSavegameVersionBefore(9)) { Town *t; FOR_ALL_TOWNS(t) UpdateTownMaxPass(t); } /* From version 16.0, we included autorenew on engines, which are now saved, but * of course, we do need to initialize them for older savegames. */ if (IsSavegameVersionBefore(16)) { Company *c; FOR_ALL_COMPANIES(c) { c->engine_renew_list = NULL; c->settings.engine_renew = false; c->settings.engine_renew_months = 6; c->settings.engine_renew_money = 100000; } /* When loading a game, _local_company is not yet set to the correct value. * However, in a dedicated server we are a spectator, so nothing needs to * happen. In case we are not a dedicated server, the local company always * becomes company 0, unless we are in the scenario editor where all the * companies are 'invalid'. */ c = Company::GetIfValid(COMPANY_FIRST); if (!_network_dedicated && c != NULL) { c->settings = _settings_client.company; } } if (IsSavegameVersionBefore(48)) { for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_RAILWAY: if (IsPlainRail(t)) { /* Swap ground type and signal type for plain rail tiles, so the * ground type uses the same bits as for depots and waypoints. */ uint tmp = GB(_m[t].m4, 0, 4); SB(_m[t].m4, 0, 4, GB(_m[t].m2, 0, 4)); SB(_m[t].m2, 0, 4, tmp); } else if (HasBit(_m[t].m5, 2)) { /* Split waypoint and depot rail type and remove the subtype. */ ClrBit(_m[t].m5, 2); ClrBit(_m[t].m5, 6); } break; case MP_ROAD: /* Swap m3 and m4, so the track type for rail crossings is the * same as for normal rail. */ Swap(_m[t].m3, _m[t].m4); break; default: break; } } } if (IsSavegameVersionBefore(61)) { /* Added the RoadType */ bool old_bridge = IsSavegameVersionBefore(42); for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_ROAD: SB(_m[t].m5, 6, 2, GB(_m[t].m5, 4, 2)); switch (GetRoadTileType(t)) { default: SlErrorCorrupt("Invalid road tile type"); case ROAD_TILE_NORMAL: SB(_m[t].m4, 0, 4, GB(_m[t].m5, 0, 4)); SB(_m[t].m4, 4, 4, 0); SB(_me[t].m6, 2, 4, 0); break; case ROAD_TILE_CROSSING: SB(_m[t].m4, 5, 2, GB(_m[t].m5, 2, 2)); break; case ROAD_TILE_DEPOT: break; } SetRoadTypes(t, ROADTYPES_ROAD); break; case MP_STATION: if (IsRoadStop(t)) SetRoadTypes(t, ROADTYPES_ROAD); break; case MP_TUNNELBRIDGE: /* Middle part of "old" bridges */ if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { SetRoadTypes(t, ROADTYPES_ROAD); } break; default: break; } } } if (IsSavegameVersionBefore(114)) { bool fix_roadtypes = !IsSavegameVersionBefore(61); bool old_bridge = IsSavegameVersionBefore(42); for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_ROAD: if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_me[t].m7, 5, 3)); SB(_me[t].m7, 5, 1, GB(_m[t].m3, 7, 1)); // snow/desert switch (GetRoadTileType(t)) { default: SlErrorCorrupt("Invalid road tile type"); case ROAD_TILE_NORMAL: SB(_me[t].m7, 0, 4, GB(_m[t].m3, 0, 4)); // road works SB(_me[t].m6, 3, 3, GB(_m[t].m3, 4, 3)); // ground SB(_m[t].m3, 0, 4, GB(_m[t].m4, 4, 4)); // tram bits SB(_m[t].m3, 4, 4, GB(_m[t].m5, 0, 4)); // tram owner SB(_m[t].m5, 0, 4, GB(_m[t].m4, 0, 4)); // road bits break; case ROAD_TILE_CROSSING: SB(_me[t].m7, 0, 5, GB(_m[t].m4, 0, 5)); // road owner SB(_me[t].m6, 3, 3, GB(_m[t].m3, 4, 3)); // ground SB(_m[t].m3, 4, 4, GB(_m[t].m5, 0, 4)); // tram owner SB(_m[t].m5, 0, 1, GB(_m[t].m4, 6, 1)); // road axis SB(_m[t].m5, 5, 1, GB(_m[t].m4, 5, 1)); // crossing state break; case ROAD_TILE_DEPOT: break; } if (!IsRoadDepot(t) && !HasTownOwnedRoad(t)) { const Town *town = CalcClosestTownFromTile(t); if (town != NULL) SetTownIndex(t, town->index); } _m[t].m4 = 0; break; case MP_STATION: if (!IsRoadStop(t)) break; if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); SB(_me[t].m7, 0, 5, HasBit(_me[t].m6, 2) ? OWNER_TOWN : GetTileOwner(t)); SB(_m[t].m3, 4, 4, _m[t].m1); _m[t].m4 = 0; break; case MP_TUNNELBRIDGE: if (old_bridge && IsBridge(t) && HasBit(_m[t].m5, 6)) break; if (((old_bridge && IsBridge(t)) ? (TransportType)GB(_m[t].m5, 1, 2) : GetTunnelBridgeTransportType(t)) == TRANSPORT_ROAD) { if (fix_roadtypes) SetRoadTypes(t, (RoadTypes)GB(_m[t].m3, 0, 3)); Owner o = GetTileOwner(t); SB(_me[t].m7, 0, 5, o); // road owner SB(_m[t].m3, 4, 4, o == OWNER_NONE ? OWNER_TOWN : o); // tram owner } SB(_me[t].m6, 2, 4, GB(_m[t].m2, 4, 4)); // bridge type SB(_me[t].m7, 5, 1, GB(_m[t].m4, 7, 1)); // snow/desert _m[t].m2 = 0; _m[t].m4 = 0; break; default: break; } } } if (IsSavegameVersionBefore(42)) { Vehicle *v; for (TileIndex t = 0; t < map_size; t++) { if (MayHaveBridgeAbove(t)) ClearBridgeMiddle(t); if (IsBridgeTile(t)) { if (HasBit(_m[t].m5, 6)) { // middle part Axis axis = (Axis)GB(_m[t].m5, 0, 1); if (HasBit(_m[t].m5, 5)) { // transport route under bridge? if (GB(_m[t].m5, 3, 2) == TRANSPORT_RAIL) { MakeRailNormal( t, GetTileOwner(t), axis == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X, GetRailType(t) ); } else { TownID town = IsTileOwner(t, OWNER_TOWN) ? ClosestTownFromTile(t, UINT_MAX)->index : 0; MakeRoadNormal( t, axis == AXIS_X ? ROAD_Y : ROAD_X, ROADTYPES_ROAD, town, GetTileOwner(t), OWNER_NONE ); } } else { if (GB(_m[t].m5, 3, 2) == 0) { MakeClear(t, CLEAR_GRASS, 3); } else { if (!IsTileFlat(t)) { MakeShore(t); } else { if (GetTileOwner(t) == OWNER_WATER) { MakeSea(t); } else { MakeCanal(t, GetTileOwner(t), Random()); } } } } SetBridgeMiddle(t, axis); } else { // ramp Axis axis = (Axis)GB(_m[t].m5, 0, 1); uint north_south = GB(_m[t].m5, 5, 1); DiagDirection dir = ReverseDiagDir(XYNSToDiagDir(axis, north_south)); TransportType type = (TransportType)GB(_m[t].m5, 1, 2); _m[t].m5 = 1 << 7 | type << 2 | dir; } } } FOR_ALL_VEHICLES(v) { if (!v->IsGroundVehicle()) continue; if (IsBridgeTile(v->tile)) { DiagDirection dir = GetTunnelBridgeDirection(v->tile); if (dir != DirToDiagDir(v->direction)) continue; switch (dir) { default: SlErrorCorrupt("Invalid vehicle direction"); case DIAGDIR_NE: if ((v->x_pos & 0xF) != 0) continue; break; case DIAGDIR_SE: if ((v->y_pos & 0xF) != TILE_SIZE - 1) continue; break; case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break; case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue; break; } } else if (v->z_pos > GetSlopePixelZ(v->x_pos, v->y_pos)) { v->tile = GetNorthernBridgeEnd(v->tile); } else { continue; } if (v->type == VEH_TRAIN) { Train::From(v)->track = TRACK_BIT_WORMHOLE; } else { RoadVehicle::From(v)->state = RVSB_WORMHOLE; } } } /* Elrails got added in rev 24 */ if (IsSavegameVersionBefore(24)) { RailType min_rail = RAILTYPE_ELECTRIC; Train *v; FOR_ALL_TRAINS(v) { RailType rt = RailVehInfo(v->engine_type)->railtype; v->railtype = rt; if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL; } /* .. so we convert the entire map from normal to elrail (so maintain "fairness") */ for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_RAILWAY: SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); break; case MP_ROAD: if (IsLevelCrossing(t)) { SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); } break; case MP_STATION: if (HasStationRail(t)) { SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); } break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) { SetRailType(t, UpdateRailType(GetRailType(t), min_rail)); } break; default: break; } } FOR_ALL_TRAINS(v) { if (v->IsFrontEngine() || v->IsFreeWagon()) v->ConsistChanged(CCF_TRACK); } } /* In version 16.1 of the savegame a company can decide if trains, which get * replaced, shall keep their old length. In all prior versions, just default * to false */ if (IsSavegameVersionBefore(16, 1)) { Company *c; FOR_ALL_COMPANIES(c) c->settings.renew_keep_length = false; } if (IsSavegameVersionBefore(123)) { /* Waypoints became subclasses of stations ... */ MoveWaypointsToBaseStations(); /* ... and buoys were moved to waypoints. */ MoveBuoysToWaypoints(); } /* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making * room for PBS. Now in version 21 move it back :P. */ if (IsSavegameVersionBefore(21) && !IsSavegameVersionBefore(15)) { for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_RAILWAY: if (HasSignals(t)) { /* Original signal type/variant was stored in m4 but since saveload * version 48 they are in m2. The bits has been already moved to m2 * (see the code somewhere above) so don't use m4, use m2 instead. */ /* convert PBS signals to combo-signals */ if (HasBit(_m[t].m2, 2)) SB(_m[t].m2, 0, 2, SIGTYPE_COMBO); /* move the signal variant back */ SB(_m[t].m2, 2, 1, HasBit(_m[t].m2, 3) ? SIG_SEMAPHORE : SIG_ELECTRIC); ClrBit(_m[t].m2, 3); } /* Clear PBS reservation on track */ if (!IsRailDepotTile(t)) { SB(_m[t].m4, 4, 4, 0); } else { ClrBit(_m[t].m3, 6); } break; case MP_STATION: // Clear PBS reservation on station ClrBit(_m[t].m3, 6); break; default: break; } } } if (IsSavegameVersionBefore(25)) { RoadVehicle *rv; FOR_ALL_ROADVEHICLES(rv) { rv->vehstatus &= ~0x40; } } if (IsSavegameVersionBefore(26)) { Station *st; FOR_ALL_STATIONS(st) { st->last_vehicle_type = VEH_INVALID; } } YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); if (IsSavegameVersionBefore(34)) { Company *c; FOR_ALL_COMPANIES(c) ResetCompanyLivery(c); } Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = GetCompanyRailtypes(c->index); c->avail_roadtypes = GetCompanyRoadtypes(c->index); } if (!IsSavegameVersionBefore(27)) AfterLoadStations(); /* Time starts at 0 instead of 1920. * Account for this in older games by adding an offset */ if (IsSavegameVersionBefore(31)) { Station *st; Waypoint *wp; Engine *e; Industry *i; Vehicle *v; _date += DAYS_TILL_ORIGINAL_BASE_YEAR; _cur_year += ORIGINAL_BASE_YEAR; FOR_ALL_STATIONS(st) st->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; FOR_ALL_WAYPOINTS(wp) wp->build_date += DAYS_TILL_ORIGINAL_BASE_YEAR; FOR_ALL_ENGINES(e) e->intro_date += DAYS_TILL_ORIGINAL_BASE_YEAR; FOR_ALL_COMPANIES(c) c->inaugurated_year += ORIGINAL_BASE_YEAR; FOR_ALL_INDUSTRIES(i) i->last_prod_year += ORIGINAL_BASE_YEAR; FOR_ALL_VEHICLES(v) { v->date_of_last_service += DAYS_TILL_ORIGINAL_BASE_YEAR; v->build_year += ORIGINAL_BASE_YEAR; } } /* From 32 on we save the industry who made the farmland. * To give this prettiness to old savegames, we remove all farmfields and * plant new ones. */ if (IsSavegameVersionBefore(32)) { Industry *i; for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) { /* remove fields */ MakeClear(t, CLEAR_GRASS, 3); } } FOR_ALL_INDUSTRIES(i) { uint j; if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) { for (j = 0; j != 50; j++) PlantRandomFarmField(i); } } } /* Setting no refit flags to all orders in savegames from before refit in orders were added */ if (IsSavegameVersionBefore(36)) { Order *order; Vehicle *v; FOR_ALL_ORDERS(order) { order->SetRefit(CT_NO_REFIT); } FOR_ALL_VEHICLES(v) { v->current_order.SetRefit(CT_NO_REFIT); } } /* from version 38 we have optional elrails, since we cannot know the * preference of a user, let elrails enabled; it can be disabled manually */ if (IsSavegameVersionBefore(38)) _settings_game.vehicle.disable_elrails = false; /* do the same as when elrails were enabled/disabled manually just now */ SettingsDisableElrail(_settings_game.vehicle.disable_elrails); InitializeRailGUI(); /* From version 53, the map array was changed for house tiles to allow * space for newhouses grf features. A new byte, m7, was also added. */ if (IsSavegameVersionBefore(53)) { for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_HOUSE)) { if (GB(_m[t].m3, 6, 2) != TOWN_HOUSE_COMPLETED) { /* Move the construction stage from m3[7..6] to m5[5..4]. * The construction counter does not have to move. */ SB(_m[t].m5, 3, 2, GB(_m[t].m3, 6, 2)); SB(_m[t].m3, 6, 2, 0); /* The "house is completed" bit is now in m6[2]. */ SetHouseCompleted(t, false); } else { /* The "lift has destination" bit has been moved from * m5[7] to m7[0]. */ SB(_me[t].m7, 0, 1, HasBit(_m[t].m5, 7)); ClrBit(_m[t].m5, 7); /* The "lift is moving" bit has been removed, as it does * the same job as the "lift has destination" bit. */ ClrBit(_m[t].m1, 7); /* The position of the lift goes from m1[7..0] to m6[7..2], * making m1 totally free, now. The lift position does not * have to be a full byte since the maximum value is 36. */ SetLiftPosition(t, GB(_m[t].m1, 0, 6 )); _m[t].m1 = 0; _m[t].m3 = 0; SetHouseCompleted(t, true); } } } } /* Check and update house and town values */ UpdateHousesAndTowns(); if (IsSavegameVersionBefore(43)) { for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_INDUSTRY)) { switch (GetIndustryGfx(t)) { case GFX_POWERPLANT_SPARKS: _m[t].m3 = GB(_m[t].m1, 2, 5); break; case GFX_OILWELL_ANIMATED_1: case GFX_OILWELL_ANIMATED_2: case GFX_OILWELL_ANIMATED_3: _m[t].m3 = GB(_m[t].m1, 0, 2); break; case GFX_COAL_MINE_TOWER_ANIMATED: case GFX_COPPER_MINE_TOWER_ANIMATED: case GFX_GOLD_MINE_TOWER_ANIMATED: _m[t].m3 = _m[t].m1; break; default: // No animation states to change break; } } } } if (IsSavegameVersionBefore(45)) { Vehicle *v; /* Originally just the fact that some cargo had been paid for was * stored to stop people cheating and cashing in several times. This * wasn't enough though as it was cleared when the vehicle started * loading again, even if it didn't actually load anything, so now the * amount that has been paid is stored. */ FOR_ALL_VEHICLES(v) { ClrBit(v->vehicle_flags, 2); } } /* Buoys do now store the owner of the previous water tile, which can never * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ if (IsSavegameVersionBefore(46)) { Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { if ((wp->facilities & FACIL_DOCK) != 0 && IsTileOwner(wp->xy, OWNER_NONE) && TileHeight(wp->xy) == 0) SetTileOwner(wp->xy, OWNER_WATER); } } if (IsSavegameVersionBefore(50)) { Aircraft *v; /* Aircraft units changed from 8 mph to 1 km-ish/h */ FOR_ALL_AIRCRAFT(v) { if (v->subtype <= AIR_AIRCRAFT) { const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); v->cur_speed *= 128; v->cur_speed /= 10; v->acceleration = avi->acceleration; } } } if (IsSavegameVersionBefore(49)) FOR_ALL_COMPANIES(c) c->face = ConvertFromOldCompanyManagerFace(c->face); if (IsSavegameVersionBefore(52)) { for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_OBJECT) && _m[t].m5 == OBJECT_STATUE) { _m[t].m2 = CalcClosestTownFromTile(t)->index; } } } /* A setting containing the proportion of towns that grow twice as * fast was added in version 54. From version 56 this is now saved in the * town as cities can be built specifically in the scenario editor. */ if (IsSavegameVersionBefore(56)) { Town *t; FOR_ALL_TOWNS(t) { if (_settings_game.economy.larger_towns != 0 && (t->index % _settings_game.economy.larger_towns) == 0) { t->larger_town = true; } } } if (IsSavegameVersionBefore(57)) { Vehicle *v; /* Added a FIFO queue of vehicles loading at stations */ FOR_ALL_VEHICLES(v) { if ((v->type != VEH_TRAIN || Train::From(v)->IsFrontEngine()) && // for all locs !(v->vehstatus & (VS_STOPPED | VS_CRASHED)) && // not stopped or crashed v->current_order.IsType(OT_LOADING)) { // loading Station::Get(v->last_station_visited)->loading_vehicles.push_back(v); /* The loading finished flag is *only* set when actually completely * finished. Because the vehicle is loading, it is not finished. */ ClrBit(v->vehicle_flags, VF_LOADING_FINISHED); } } } else if (IsSavegameVersionBefore(59)) { /* For some reason non-loading vehicles could be in the station's loading vehicle list */ Station *st; FOR_ALL_STATIONS(st) { std::list::iterator iter; for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end();) { Vehicle *v = *iter; iter++; if (!v->current_order.IsType(OT_LOADING)) st->loading_vehicles.remove(v); } } } if (IsSavegameVersionBefore(58)) { /* Setting difficulty industry_density other than zero get bumped to +1 * since a new option (very low at position 1) has been added */ if (_settings_game.difficulty.industry_density > 0) { _settings_game.difficulty.industry_density++; } /* Same goes for number of towns, although no test is needed, just an increment */ _settings_game.difficulty.number_towns++; } if (IsSavegameVersionBefore(64)) { /* Since now we allow different signal types and variants on a single tile. * Move signal states to m4 to make room and clone the signal type/variant. */ for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_RAILWAY) && HasSignals(t)) { /* move signal states */ SetSignalStates(t, GB(_m[t].m2, 4, 4)); SB(_m[t].m2, 4, 4, 0); /* clone signal type and variant */ SB(_m[t].m2, 4, 3, GB(_m[t].m2, 0, 3)); } } } if (IsSavegameVersionBefore(69)) { /* In some old savegames a bit was cleared when it should not be cleared */ RoadVehicle *rv; FOR_ALL_ROADVEHICLES(rv) { if (rv->state == 250 || rv->state == 251) { SetBit(rv->state, 2); } } } if (IsSavegameVersionBefore(70)) { /* Added variables to support newindustries */ Industry *i; FOR_ALL_INDUSTRIES(i) i->founder = OWNER_NONE; } /* From version 82, old style canals (above sealevel (0), WATER owner) are no longer supported. Replace the owner for those by OWNER_NONE. */ if (IsSavegameVersionBefore(82)) { for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_WATER) && GetWaterTileType(t) == WATER_TILE_CLEAR && GetTileOwner(t) == OWNER_WATER && TileHeight(t) != 0) { SetTileOwner(t, OWNER_NONE); } } } /* * Add the 'previous' owner to the ship depots so we can reset it with * the correct values when it gets destroyed. This prevents that * someone can remove canals owned by somebody else and it prevents * making floods using the removal of ship depots. */ if (IsSavegameVersionBefore(83)) { for (TileIndex t = 0; t < map_size; t++) { if (IsShipDepotTile(t)) { _m[t].m4 = (TileHeight(t) == 0) ? OWNER_WATER : OWNER_NONE; } } } if (IsSavegameVersionBefore(74)) { Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) { st->goods[c].last_speed = 0; if (st->goods[c].cargo.AvailableCount() != 0) SetBit(st->goods[c].status, GoodsEntry::GES_RATING); } } } if (IsSavegameVersionBefore(78)) { Industry *i; uint j; FOR_ALL_INDUSTRIES(i) { const IndustrySpec *indsp = GetIndustrySpec(i->type); for (j = 0; j < lengthof(i->produced_cargo); j++) { i->produced_cargo[j] = indsp->produced_cargo[j]; } for (j = 0; j < lengthof(i->accepts_cargo); j++) { i->accepts_cargo[j] = indsp->accepts_cargo[j]; } } } /* Before version 81, the density of grass was always stored as zero, and * grassy trees were always drawn fully grassy. Furthermore, trees on rough * land used to have zero density, now they have full density. Therefore, * make all grassy/rough land trees have a density of 3. */ if (IsSavegameVersionBefore(81)) { for (TileIndex t = 0; t < map_size; t++) { if (GetTileType(t) == MP_TREES) { TreeGround groundType = (TreeGround)GB(_m[t].m2, 4, 2); if (groundType != TREE_GROUND_SNOW_DESERT) SB(_m[t].m2, 6, 2, 3); } } } if (IsSavegameVersionBefore(93)) { /* Rework of orders. */ Order *order; FOR_ALL_ORDERS(order) order->ConvertFromOldSavegame(); Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->orders.list != NULL && v->orders.list->GetFirstOrder() != NULL && v->orders.list->GetFirstOrder()->IsType(OT_NOTHING)) { v->orders.list->FreeChain(); v->orders.list = NULL; } v->current_order.ConvertFromOldSavegame(); if (v->type == VEH_ROAD && v->IsPrimaryVehicle() && v->FirstShared() == v) { FOR_VEHICLE_ORDERS(v, order) order->SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); } } } else if (IsSavegameVersionBefore(94)) { /* Unload and transfer are now mutual exclusive. */ Order *order; FOR_ALL_ORDERS(order) { if ((order->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { order->SetUnloadType(OUFB_TRANSFER); order->SetLoadType(OLFB_NO_LOAD); } } Vehicle *v; FOR_ALL_VEHICLES(v) { if ((v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == (OUFB_UNLOAD | OUFB_TRANSFER)) { v->current_order.SetUnloadType(OUFB_TRANSFER); v->current_order.SetLoadType(OLFB_NO_LOAD); } } } if (IsSavegameVersionBefore(84)) { /* Set all share owners to INVALID_COMPANY for * 1) all inactive companies * (when inactive companies were stored in the savegame - TTD, TTDP and some * *really* old revisions of OTTD; else it is already set in InitializeCompanies()) * 2) shares that are owned by inactive companies or self * (caused by cheating clients in earlier revisions) */ FOR_ALL_COMPANIES(c) { for (uint i = 0; i < 4; i++) { CompanyID company = c->share_owners[i]; if (company == INVALID_COMPANY) continue; if (!Company::IsValidID(company) || company == c->index) c->share_owners[i] = INVALID_COMPANY; } } } /* The water class was moved/unified. */ if (IsSavegameVersionBefore(146)) { for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_STATION: switch (GetStationType(t)) { case STATION_OILRIG: case STATION_DOCK: case STATION_BUOY: SetWaterClass(t, (WaterClass)GB(_m[t].m3, 0, 2)); SB(_m[t].m3, 0, 2, 0); break; default: SetWaterClass(t, WATER_CLASS_INVALID); break; } break; case MP_WATER: SetWaterClass(t, (WaterClass)GB(_m[t].m3, 0, 2)); SB(_m[t].m3, 0, 2, 0); break; case MP_OBJECT: SetWaterClass(t, WATER_CLASS_INVALID); break; default: /* No water class. */ break; } } } if (IsSavegameVersionBefore(86)) { for (TileIndex t = 0; t < map_size; t++) { /* Move river flag and update canals to use water class */ if (IsTileType(t, MP_WATER)) { if (GetWaterClass(t) != WATER_CLASS_RIVER) { if (IsWater(t)) { Owner o = GetTileOwner(t); if (o == OWNER_WATER) { MakeSea(t); } else { MakeCanal(t, o, Random()); } } else if (IsShipDepot(t)) { Owner o = (Owner)_m[t].m4; // Original water owner SetWaterClass(t, o == OWNER_WATER ? WATER_CLASS_SEA : WATER_CLASS_CANAL); } } } } /* Update locks, depots, docks and buoys to have a water class based * on its neighbouring tiles. Done after river and canal updates to * ensure neighbours are correct. */ for (TileIndex t = 0; t < map_size; t++) { if (!IsTileFlat(t)) continue; if (IsTileType(t, MP_WATER) && IsLock(t)) SetWaterClassDependingOnSurroundings(t, false); if (IsTileType(t, MP_STATION) && (IsDock(t) || IsBuoy(t))) SetWaterClassDependingOnSurroundings(t, false); } } if (IsSavegameVersionBefore(87)) { for (TileIndex t = 0; t < map_size; t++) { /* skip oil rigs at borders! */ if ((IsTileType(t, MP_WATER) || IsBuoyTile(t)) && (TileX(t) == 0 || TileY(t) == 0 || TileX(t) == MapMaxX() - 1 || TileY(t) == MapMaxY() - 1)) { /* Some version 86 savegames have wrong water class at map borders (under buoy, or after removing buoy). * This conversion has to be done before buoys with invalid owner are removed. */ SetWaterClass(t, WATER_CLASS_SEA); } if (IsBuoyTile(t) || IsDriveThroughStopTile(t) || IsTileType(t, MP_WATER)) { Owner o = GetTileOwner(t); if (o < MAX_COMPANIES && !Company::IsValidID(o)) { Backup cur_company(_current_company, o, FILE_LINE); ChangeTileOwner(t, o, INVALID_OWNER); cur_company.Restore(); } if (IsBuoyTile(t)) { /* reset buoy owner to OWNER_NONE in the station struct * (even if it is owned by active company) */ Waypoint::GetByTile(t)->owner = OWNER_NONE; } } else if (IsTileType(t, MP_ROAD)) { /* works for all RoadTileType */ for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { /* update even non-existing road types to update tile owner too */ Owner o = GetRoadOwner(t, rt); if (o < MAX_COMPANIES && !Company::IsValidID(o)) SetRoadOwner(t, rt, OWNER_NONE); } if (IsLevelCrossing(t)) { if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); } } else if (IsPlainRailTile(t)) { if (!Company::IsValidID(GetTileOwner(t))) FixOwnerOfRailTrack(t); } } /* Convert old PF settings to new */ if (_settings_game.pf.yapf.rail_use_yapf || IsSavegameVersionBefore(28)) { _settings_game.pf.pathfinder_for_trains = VPF_YAPF; } else { _settings_game.pf.pathfinder_for_trains = VPF_NPF; } if (_settings_game.pf.yapf.road_use_yapf || IsSavegameVersionBefore(28)) { _settings_game.pf.pathfinder_for_roadvehs = VPF_YAPF; } else { _settings_game.pf.pathfinder_for_roadvehs = VPF_NPF; } if (_settings_game.pf.yapf.ship_use_yapf) { _settings_game.pf.pathfinder_for_ships = VPF_YAPF; } else { _settings_game.pf.pathfinder_for_ships = (_settings_game.pf.new_pathfinding_all ? VPF_NPF : VPF_OPF); } } if (IsSavegameVersionBefore(88)) { /* Profits are now with 8 bit fract */ Vehicle *v; FOR_ALL_VEHICLES(v) { v->profit_this_year <<= 8; v->profit_last_year <<= 8; v->running_ticks = 0; } } if (IsSavegameVersionBefore(91)) { /* Increase HouseAnimationFrame from 5 to 7 bits */ for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_HOUSE) && GetHouseType(t) >= NEW_HOUSE_OFFSET) { SB(_me[t].m6, 2, 6, GB(_me[t].m6, 3, 5)); SB(_m[t].m3, 5, 1, 0); } } } if (IsSavegameVersionBefore(62)) { /* Remove all trams from savegames without tram support. * There would be trams without tram track under causing crashes sooner or later. */ RoadVehicle *v; FOR_ALL_ROADVEHICLES(v) { if (v->First() == v && HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM)) { ShowErrorMessage(STR_WARNING_LOADGAME_REMOVED_TRAMS, INVALID_STRING_ID, WL_CRITICAL); delete v; } } } if (IsSavegameVersionBefore(99)) { for (TileIndex t = 0; t < map_size; t++) { /* Set newly introduced WaterClass of industry tiles */ if (IsTileType(t, MP_STATION) && IsOilRig(t)) { SetWaterClassDependingOnSurroundings(t, true); } if (IsTileType(t, MP_INDUSTRY)) { if ((GetIndustrySpec(GetIndustryType(t))->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0) { SetWaterClassDependingOnSurroundings(t, true); } else { SetWaterClass(t, WATER_CLASS_INVALID); } } /* Replace "house construction year" with "house age" */ if (IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)) { _m[t].m5 = Clamp(_cur_year - (_m[t].m5 + ORIGINAL_BASE_YEAR), 0, 0xFF); } } } /* Move the signal variant back up one bit for PBS. We don't convert the old PBS * format here, as an old layout wouldn't work properly anyway. To be safe, we * clear any possible PBS reservations as well. */ if (IsSavegameVersionBefore(100)) { for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_RAILWAY: if (HasSignals(t)) { /* move the signal variant */ SetSignalVariant(t, TRACK_UPPER, HasBit(_m[t].m2, 2) ? SIG_SEMAPHORE : SIG_ELECTRIC); SetSignalVariant(t, TRACK_LOWER, HasBit(_m[t].m2, 6) ? SIG_SEMAPHORE : SIG_ELECTRIC); ClrBit(_m[t].m2, 2); ClrBit(_m[t].m2, 6); } /* Clear PBS reservation on track */ if (IsRailDepot(t)) { SetDepotReservation(t, false); } else { SetTrackReservation(t, TRACK_BIT_NONE); } break; case MP_ROAD: // Clear PBS reservation on crossing if (IsLevelCrossing(t)) SetCrossingReservation(t, false); break; case MP_STATION: // Clear PBS reservation on station if (HasStationRail(t)) SetRailStationReservation(t, false); break; case MP_TUNNELBRIDGE: // Clear PBS reservation on tunnels/bridges if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false); break; default: break; } } } /* Reserve all tracks trains are currently on. */ if (IsSavegameVersionBefore(101)) { const Train *t; FOR_ALL_TRAINS(t) { if (t->First() == t) t->ReserveTrackUnderConsist(); } } if (IsSavegameVersionBefore(102)) { for (TileIndex t = 0; t < map_size; t++) { /* Now all crossings should be in correct state */ if (IsLevelCrossingTile(t)) UpdateLevelCrossing(t, false); } } if (IsSavegameVersionBefore(103)) { /* Non-town-owned roads now store the closest town */ UpdateNearestTownForRoadTiles(false); /* signs with invalid owner left from older savegames */ Sign *si; FOR_ALL_SIGNS(si) { if (si->owner != OWNER_NONE && !Company::IsValidID(si->owner)) si->owner = OWNER_NONE; } /* Station can get named based on an industry type, but the current ones * are not, so mark them as if they are not named by an industry. */ Station *st; FOR_ALL_STATIONS(st) { st->indtype = IT_INVALID; } } if (IsSavegameVersionBefore(104)) { Aircraft *a; FOR_ALL_AIRCRAFT(a) { /* Set engine_type of shadow and rotor */ if (!a->IsNormalAircraft()) { a->engine_type = a->First()->engine_type; } } /* More companies ... */ Company *c; FOR_ALL_COMPANIES(c) { if (c->bankrupt_asked == 0xFF) c->bankrupt_asked = 0xFFFF; } Engine *e; FOR_ALL_ENGINES(e) { if (e->company_avail == 0xFF) e->company_avail = 0xFFFF; } Town *t; FOR_ALL_TOWNS(t) { if (t->have_ratings == 0xFF) t->have_ratings = 0xFFFF; for (uint i = 8; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL; } } if (IsSavegameVersionBefore(112)) { for (TileIndex t = 0; t < map_size; t++) { /* Check for HQ bit being set, instead of using map accessor, * since we've already changed it code-wise */ if (IsTileType(t, MP_OBJECT) && HasBit(_m[t].m5, 7)) { /* Move size and part identification of HQ out of the m5 attribute, * on new locations */ _m[t].m3 = GB(_m[t].m5, 0, 5); _m[t].m5 = OBJECT_HQ; } } } if (IsSavegameVersionBefore(144)) { for (TileIndex t = 0; t < map_size; t++) { if (!IsTileType(t, MP_OBJECT)) continue; /* Reordering/generalisation of the object bits. */ ObjectType type = _m[t].m5; SB(_me[t].m6, 2, 4, type == OBJECT_HQ ? GB(_m[t].m3, 2, 3) : 0); _m[t].m3 = type == OBJECT_HQ ? GB(_m[t].m3, 1, 1) | GB(_m[t].m3, 0, 1) << 4 : 0; /* Make sure those bits are clear as well! */ _m[t].m4 = 0; _me[t].m7 = 0; } } if (IsSavegameVersionBefore(147) && Object::GetNumItems() == 0) { /* Make real objects for object tiles. */ for (TileIndex t = 0; t < map_size; t++) { if (!IsTileType(t, MP_OBJECT)) continue; if (Town::GetNumItems() == 0) { /* No towns, so remove all objects! */ DoClearSquare(t); } else { uint offset = _m[t].m3; /* Also move the animation state. */ _m[t].m3 = GB(_me[t].m6, 2, 4); SB(_me[t].m6, 2, 4, 0); if (offset == 0) { /* No offset, so make the object. */ ObjectType type = _m[t].m5; int size = type == OBJECT_HQ ? 2 : 1; if (!Object::CanAllocateItem()) { /* Nice... you managed to place 64k lighthouses and * antennae on the map... boohoo. */ SlError(STR_ERROR_TOO_MANY_OBJECTS); } Object *o = new Object(); o->location.tile = t; o->location.w = size; o->location.h = size; o->build_date = _date; o->town = type == OBJECT_STATUE ? Town::Get(_m[t].m2) : CalcClosestTownFromTile(t, UINT_MAX); _m[t].m2 = o->index; Object::IncTypeCount(type); } else { /* We're at an offset, so get the ID from our "root". */ TileIndex northern_tile = t - TileXY(GB(offset, 0, 4), GB(offset, 4, 4)); assert(IsTileType(northern_tile, MP_OBJECT)); _m[t].m2 = _m[northern_tile].m2; } } } } if (IsSavegameVersionBefore(113)) { /* allow_town_roads is added, set it if town_layout wasn't TL_NO_ROADS */ if (_settings_game.economy.town_layout == 0) { // was TL_NO_ROADS _settings_game.economy.allow_town_roads = false; _settings_game.economy.town_layout = TL_BETTER_ROADS; } else { _settings_game.economy.allow_town_roads = true; _settings_game.economy.town_layout = _settings_game.economy.town_layout - 1; } /* Initialize layout of all towns. Older versions were using different * generator for random town layout, use it if needed. */ Town *t; FOR_ALL_TOWNS(t) { if (_settings_game.economy.town_layout != TL_RANDOM) { t->layout = _settings_game.economy.town_layout; continue; } /* Use old layout randomizer code */ byte layout = TileHash(TileX(t->xy), TileY(t->xy)) % 6; switch (layout) { default: break; case 5: layout = 1; break; case 0: layout = 2; break; } t->layout = layout - 1; } } if (IsSavegameVersionBefore(114)) { /* There could be (deleted) stations with invalid owner, set owner to OWNER NONE. * The conversion affects oil rigs and buoys too, but it doesn't matter as * they have st->owner == OWNER_NONE already. */ Station *st; FOR_ALL_STATIONS(st) { if (!Company::IsValidID(st->owner)) st->owner = OWNER_NONE; } } /* Trains could now stop in a specific location. */ if (IsSavegameVersionBefore(117)) { Order *o; FOR_ALL_ORDERS(o) { if (o->IsType(OT_GOTO_STATION)) o->SetStopLocation(OSL_PLATFORM_FAR_END); } } if (IsSavegameVersionBefore(120)) { extern VehicleDefaultSettings _old_vds; Company *c; FOR_ALL_COMPANIES(c) { c->settings.vehicle = _old_vds; } } if (IsSavegameVersionBefore(121)) { /* Delete small ufos heading for non-existing vehicles */ Vehicle *v; FOR_ALL_DISASTERVEHICLES(v) { if (v->subtype == 2 /* ST_SMALL_UFO */ && v->current_order.GetDestination() != 0) { const Vehicle *u = Vehicle::GetIfValid(v->dest_tile); if (u == NULL || u->type != VEH_ROAD || !RoadVehicle::From(u)->IsFrontEngine()) { delete v; } } } /* We didn't store cargo payment yet, so make them for vehicles that are * currently at a station and loading/unloading. If they don't get any * payment anymore they just removed in the next load/unload cycle. * However, some 0.7 versions might have cargo payment. For those we just * add cargopayment for the vehicles that don't have it. */ Station *st; FOR_ALL_STATIONS(st) { std::list::iterator iter; for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) { /* There are always as many CargoPayments as Vehicles. We need to make the * assert() in Pool::GetNew() happy by calling CanAllocateItem(). */ assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); assert(CargoPayment::CanAllocateItem()); Vehicle *v = *iter; if (v->cargo_payment == NULL) v->cargo_payment = new CargoPayment(v); } } } if (IsSavegameVersionBefore(122)) { /* Animated tiles would sometimes not be actually animated or * in case of old savegames duplicate. */ extern TileIndex *_animated_tile_list; extern uint _animated_tile_count; for (uint i = 0; i < _animated_tile_count; /* Nothing */) { /* Remove if tile is not animated */ bool remove = _tile_type_procs[GetTileType(_animated_tile_list[i])]->animate_tile_proc == NULL; /* and remove if duplicate */ for (uint j = 0; !remove && j < i; j++) { remove = _animated_tile_list[i] == _animated_tile_list[j]; } if (remove) { DeleteAnimatedTile(_animated_tile_list[i]); } else { i++; } } } if (IsSavegameVersionBefore(124) && !IsSavegameVersionBefore(1)) { /* The train station tile area was added, but for really old (TTDPatch) it's already valid. */ Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { if (wp->facilities & FACIL_TRAIN) { wp->train_station.tile = wp->xy; wp->train_station.w = 1; wp->train_station.h = 1; } else { wp->train_station.tile = INVALID_TILE; wp->train_station.w = 0; wp->train_station.h = 0; } } } if (IsSavegameVersionBefore(125)) { /* Convert old subsidies */ Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (s->remaining < 12) { /* Converting nonawarded subsidy */ s->remaining = 12 - s->remaining; // convert "age" to "remaining" s->awarded = INVALID_COMPANY; // not awarded to anyone const CargoSpec *cs = CargoSpec::Get(s->cargo_type); switch (cs->town_effect) { case TE_PASSENGERS: case TE_MAIL: /* Town -> Town */ s->src_type = s->dst_type = ST_TOWN; if (Town::IsValidID(s->src) && Town::IsValidID(s->dst)) continue; break; case TE_GOODS: case TE_FOOD: /* Industry -> Town */ s->src_type = ST_INDUSTRY; s->dst_type = ST_TOWN; if (Industry::IsValidID(s->src) && Town::IsValidID(s->dst)) continue; break; default: /* Industry -> Industry */ s->src_type = s->dst_type = ST_INDUSTRY; if (Industry::IsValidID(s->src) && Industry::IsValidID(s->dst)) continue; break; } } else { /* Do our best for awarded subsidies. The original source or destination industry * can't be determined anymore for awarded subsidies, so invalidate them. * Town -> Town subsidies are converted using simple heuristic */ s->remaining = 24 - s->remaining; // convert "age of awarded subsidy" to "remaining" const CargoSpec *cs = CargoSpec::Get(s->cargo_type); switch (cs->town_effect) { case TE_PASSENGERS: case TE_MAIL: { /* Town -> Town */ const Station *ss = Station::GetIfValid(s->src); const Station *sd = Station::GetIfValid(s->dst); if (ss != NULL && sd != NULL && ss->owner == sd->owner && Company::IsValidID(ss->owner)) { s->src_type = s->dst_type = ST_TOWN; s->src = ss->town->index; s->dst = sd->town->index; s->awarded = ss->owner; continue; } break; } default: break; } } /* Awarded non-town subsidy or invalid source/destination, invalidate */ delete s; } } if (IsSavegameVersionBefore(126)) { /* Recompute inflation based on old unround loan limit * Note: Max loan is 500000. With an inflation of 4% across 170 years * that results in a max loan of about 0.7 * 2^31. * So taking the 16 bit fractional part into account there are plenty of bits left * for unmodified savegames ... */ uint64 aimed_inflation = (_economy.old_max_loan_unround << 16 | _economy.old_max_loan_unround_fract) / _settings_game.difficulty.max_loan; /* ... well, just clamp it then. */ if (aimed_inflation > MAX_INFLATION) aimed_inflation = MAX_INFLATION; /* Simulate the inflation, so we also get the payment inflation */ while (_economy.inflation_prices < aimed_inflation) { if (AddInflation(false)) break; } } if (IsSavegameVersionBefore(128)) { const Depot *d; FOR_ALL_DEPOTS(d) { _m[d->xy].m2 = d->index; if (IsTileType(d->xy, MP_WATER)) _m[GetOtherShipDepotTile(d->xy)].m2 = d->index; } } /* The behaviour of force_proceed has been changed. Now * it counts signals instead of some random time out. */ if (IsSavegameVersionBefore(131)) { Train *t; FOR_ALL_TRAINS(t) { if (t->force_proceed != TFP_NONE) { t->force_proceed = TFP_STUCK; } } } /* The bits for the tree ground and tree density have * been swapped (m2 bits 7..6 and 5..4. */ if (IsSavegameVersionBefore(135)) { for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_CLEAR)) { if (GetRawClearGround(t) == CLEAR_SNOW) { SetClearGroundDensity(t, CLEAR_GRASS, GetClearDensity(t)); SetBit(_m[t].m3, 4); } else { ClrBit(_m[t].m3, 4); } } if (IsTileType(t, MP_TREES)) { uint density = GB(_m[t].m2, 6, 2); uint ground = GB(_m[t].m2, 4, 2); uint counter = GB(_m[t].m2, 0, 4); _m[t].m2 = ground << 6 | density << 4 | counter; } } } /* Wait counter and load/unload ticks got split. */ if (IsSavegameVersionBefore(136)) { Aircraft *a; FOR_ALL_AIRCRAFT(a) { a->turn_counter = a->current_order.IsType(OT_LOADING) ? 0 : a->load_unload_ticks; } Train *t; FOR_ALL_TRAINS(t) { t->wait_counter = t->current_order.IsType(OT_LOADING) ? 0 : t->load_unload_ticks; } } /* Airport tile animation uses animation frame instead of other graphics id */ if (IsSavegameVersionBefore(137)) { struct AirportTileConversion { byte old_start; byte num_frames; }; static const AirportTileConversion atc[] = { {31, 12}, // APT_RADAR_GRASS_FENCE_SW {50, 4}, // APT_GRASS_FENCE_NE_FLAG {62, 2}, // 1 unused tile {66, 12}, // APT_RADAR_FENCE_SW {78, 12}, // APT_RADAR_FENCE_NE {101, 10}, // 9 unused tiles {111, 8}, // 7 unused tiles {119, 15}, // 14 unused tiles (radar) {140, 4}, // APT_GRASS_FENCE_NE_FLAG_2 }; for (TileIndex t = 0; t < map_size; t++) { if (IsAirportTile(t)) { StationGfx old_gfx = GetStationGfx(t); byte offset = 0; for (uint i = 0; i < lengthof(atc); i++) { if (old_gfx < atc[i].old_start) { SetStationGfx(t, old_gfx - offset); break; } if (old_gfx < atc[i].old_start + atc[i].num_frames) { SetAnimationFrame(t, old_gfx - atc[i].old_start); SetStationGfx(t, atc[i].old_start - offset); break; } offset += atc[i].num_frames - 1; } } } } if (IsSavegameVersionBefore(140)) { Station *st; FOR_ALL_STATIONS(st) { if (st->airport.tile != INVALID_TILE) { st->airport.w = st->airport.GetSpec()->size_x; st->airport.h = st->airport.GetSpec()->size_y; } } } if (IsSavegameVersionBefore(141)) { for (TileIndex t = 0; t < map_size; t++) { /* Reset tropic zone for VOID tiles, they shall not have any. */ if (IsTileType(t, MP_VOID)) SetTropicZone(t, TROPICZONE_NORMAL); } /* We need to properly number/name the depots. * The first step is making sure none of the depots uses the * 'default' names, after that we can assign the names. */ Depot *d; FOR_ALL_DEPOTS(d) d->town_cn = UINT16_MAX; FOR_ALL_DEPOTS(d) MakeDefaultName(d); } if (IsSavegameVersionBefore(142)) { Depot *d; FOR_ALL_DEPOTS(d) d->build_date = _date; } /* In old versions it was possible to remove an airport while a plane was * taking off or landing. This gives all kind of problems when building * another airport in the same station so we don't allow that anymore. * For old savegames with such aircraft we just throw them in the air and * treat the aircraft like they were flying already. */ if (IsSavegameVersionBefore(146)) { Aircraft *v; FOR_ALL_AIRCRAFT(v) { if (!v->IsNormalAircraft()) continue; Station *st = GetTargetAirportIfValid(v); if (st == NULL && v->state != FLYING) { v->state = FLYING; UpdateAircraftCache(v); AircraftNextAirportPos_and_Order(v); /* get aircraft back on running altitude */ if ((v->vehstatus & VS_CRASHED) == 0) { GetAircraftFlightLevelBounds(v, &v->z_pos, NULL); SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlightLevel(v)); } } } } /* Move the animation frame to the same location (m7) for all objects. */ if (IsSavegameVersionBefore(147)) { for (TileIndex t = 0; t < map_size; t++) { switch (GetTileType(t)) { case MP_HOUSE: if (GetHouseType(t) >= NEW_HOUSE_OFFSET) { uint per_proc = _me[t].m7; _me[t].m7 = GB(_me[t].m6, 2, 6) | (GB(_m[t].m3, 5, 1) << 6); SB(_m[t].m3, 5, 1, 0); SB(_me[t].m6, 2, 6, min(per_proc, 63)); } break; case MP_INDUSTRY: { uint rand = _me[t].m7; _me[t].m7 = _m[t].m3; _m[t].m3 = rand; break; } case MP_OBJECT: _me[t].m7 = _m[t].m3; _m[t].m3 = 0; break; default: /* For stations/airports it's already at m7 */ break; } } } /* Add (random) colour to all objects. */ if (IsSavegameVersionBefore(148)) { Object *o; FOR_ALL_OBJECTS(o) { Owner owner = GetTileOwner(o->location.tile); o->colour = (owner == OWNER_NONE) ? Random() & 0xF : Company::Get(owner)->livery->colour1; } } if (IsSavegameVersionBefore(149)) { for (TileIndex t = 0; t < map_size; t++) { if (!IsTileType(t, MP_STATION)) continue; if (!IsBuoy(t) && !IsOilRig(t) && !(IsDock(t) && IsTileFlat(t))) { SetWaterClass(t, WATER_CLASS_INVALID); } } /* Waypoints with custom name may have a non-unique town_cn, * renumber those. First set all affected waypoints to the * highest possible number to get them numbered in the * order they have in the pool. */ Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { if (wp->name != NULL) wp->town_cn = UINT16_MAX; } FOR_ALL_WAYPOINTS(wp) { if (wp->name != NULL) MakeDefaultName(wp); } } if (IsSavegameVersionBefore(152)) { _industry_builder.Reset(); // Initialize industry build data. /* The moment vehicles go from hidden to visible changed. This means * that vehicles don't always get visible anymore causing things to * get messed up just after loading the savegame. This fixes that. */ Vehicle *v; FOR_ALL_VEHICLES(v) { /* Not all vehicle types can be inside a tunnel. Furthermore, * testing IsTunnelTile() for invalid tiles causes a crash. */ if (!v->IsGroundVehicle()) continue; /* Is the vehicle in a tunnel? */ if (!IsTunnelTile(v->tile)) continue; /* Is the vehicle actually at a tunnel entrance/exit? */ TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos); if (!IsTunnelTile(vtile)) continue; /* Are we actually in this tunnel? Or maybe a lower tunnel? */ if (GetSlopePixelZ(v->x_pos, v->y_pos) != v->z_pos) continue; /* What way are we going? */ const DiagDirection dir = GetTunnelBridgeDirection(vtile); const DiagDirection vdir = DirToDiagDir(v->direction); /* Have we passed the visibility "switch" state already? */ byte pos = (DiagDirToAxis(vdir) == AXIS_X ? v->x_pos : v->y_pos) & TILE_UNIT_MASK; byte frame = (vdir == DIAGDIR_NE || vdir == DIAGDIR_NW) ? TILE_SIZE - 1 - pos : pos; extern const byte _tunnel_visibility_frame[DIAGDIR_END]; /* Should the vehicle be hidden or not? */ bool hidden; if (dir == vdir) { // Entering tunnel hidden = frame >= _tunnel_visibility_frame[dir]; v->tile = vtile; } else if (dir == ReverseDiagDir(vdir)) { // Leaving tunnel hidden = frame < TILE_SIZE - _tunnel_visibility_frame[dir]; /* v->tile changes at the moment when the vehicle leaves the tunnel. */ v->tile = hidden ? GetOtherTunnelBridgeEnd(vtile) : vtile; } else { /* We could get here in two cases: * - for road vehicles, it is reversing at the end of the tunnel * - it is crashed in the tunnel entry (both train or RV destroyed by UFO) * Whatever case it is, do not change anything and use the old values. * Especially changing RV's state would break its reversing in the middle. */ continue; } if (hidden) { v->vehstatus |= VS_HIDDEN; switch (v->type) { case VEH_TRAIN: Train::From(v)->track = TRACK_BIT_WORMHOLE; break; case VEH_ROAD: RoadVehicle::From(v)->state = RVSB_WORMHOLE; break; default: NOT_REACHED(); } } else { v->vehstatus &= ~VS_HIDDEN; switch (v->type) { case VEH_TRAIN: Train::From(v)->track = DiagDirToDiagTrackBits(vdir); break; case VEH_ROAD: RoadVehicle::From(v)->state = DiagDirToDiagTrackdir(vdir); RoadVehicle::From(v)->frame = frame; break; default: NOT_REACHED(); } } } } if (IsSavegameVersionBefore(153)) { RoadVehicle *rv; FOR_ALL_ROADVEHICLES(rv) { if (rv->state == RVSB_IN_DEPOT || rv->state == RVSB_WORMHOLE) continue; bool loading = rv->current_order.IsType(OT_LOADING) || rv->current_order.IsType(OT_LEAVESTATION); if (HasBit(rv->state, RVS_IN_ROAD_STOP)) { extern const byte _road_stop_stop_frame[]; SB(rv->state, RVS_ENTERED_STOP, 1, loading || rv->frame > _road_stop_stop_frame[rv->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)]); } else if (HasBit(rv->state, RVS_IN_DT_ROAD_STOP)) { SB(rv->state, RVS_ENTERED_STOP, 1, loading || rv->frame > RVC_DRIVE_THROUGH_STOP_FRAME); } } } if (IsSavegameVersionBefore(156)) { /* The train's pathfinder lost flag got moved. */ Train *t; FOR_ALL_TRAINS(t) { if (!HasBit(t->flags, 5)) continue; ClrBit(t->flags, 5); SetBit(t->vehicle_flags, VF_PATHFINDER_LOST); } /* Introduced terraform/clear limits. */ Company *c; FOR_ALL_COMPANIES(c) { c->terraform_limit = _settings_game.construction.terraform_frame_burst << 16; c->clear_limit = _settings_game.construction.clear_frame_burst << 16; } } if (IsSavegameVersionBefore(158)) { Vehicle *v; FOR_ALL_VEHICLES(v) { switch (v->type) { case VEH_TRAIN: { Train *t = Train::From(v); /* Clear old GOINGUP / GOINGDOWN flags. * It was changed in savegame version 139, but savegame * version 158 doesn't use these bits, so it doesn't hurt * to clear them unconditionally. */ ClrBit(t->flags, 1); ClrBit(t->flags, 2); /* Clear both bits first. */ ClrBit(t->gv_flags, GVF_GOINGUP_BIT); ClrBit(t->gv_flags, GVF_GOINGDOWN_BIT); /* Crashed vehicles can't be going up/down. */ if (t->vehstatus & VS_CRASHED) break; /* Only X/Y tracks can be sloped. */ if (t->track != TRACK_BIT_X && t->track != TRACK_BIT_Y) break; t->gv_flags |= FixVehicleInclination(t, t->direction); break; } case VEH_ROAD: { RoadVehicle *rv = RoadVehicle::From(v); ClrBit(rv->gv_flags, GVF_GOINGUP_BIT); ClrBit(rv->gv_flags, GVF_GOINGDOWN_BIT); /* Crashed vehicles can't be going up/down. */ if (rv->vehstatus & VS_CRASHED) break; if (rv->state == RVSB_IN_DEPOT || rv->state == RVSB_WORMHOLE) break; TrackStatus ts = GetTileTrackStatus(rv->tile, TRANSPORT_ROAD, rv->compatible_roadtypes); TrackBits trackbits = TrackStatusToTrackBits(ts); /* Only X/Y tracks can be sloped. */ if (trackbits != TRACK_BIT_X && trackbits != TRACK_BIT_Y) break; Direction dir = rv->direction; /* Test if we are reversing. */ Axis a = trackbits == TRACK_BIT_X ? AXIS_X : AXIS_Y; if (AxisToDirection(a) != dir && AxisToDirection(a) != ReverseDir(dir)) { /* When reversing, the road vehicle is on the edge of the tile, * so it can be safely compared to the middle of the tile. */ dir = INVALID_DIR; } rv->gv_flags |= FixVehicleInclination(rv, dir); break; } case VEH_SHIP: break; default: continue; } if (IsBridgeTile(v->tile) && TileVirtXY(v->x_pos, v->y_pos) == v->tile) { /* In old versions, z_pos was 1 unit lower on bridge heads. * However, this invalid state could be converted to new savegames * by loading and saving the game in a new version. */ v->z_pos = GetSlopePixelZ(v->x_pos, v->y_pos); DiagDirection dir = GetTunnelBridgeDirection(v->tile); if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && v->direction != DiagDirToDir(dir)) { /* If the train has left the bridge, it shouldn't have * track == TRACK_BIT_WORMHOLE - this could happen * when the train was reversed while on the last "tick" * on the ramp before leaving the ramp to the bridge. */ Train::From(v)->track = DiagDirToDiagTrackBits(dir); } } /* If the vehicle is really above v->tile (not in a wormhole), * it should have set v->z_pos correctly. */ assert(v->tile != TileVirtXY(v->x_pos, v->y_pos) || v->z_pos == GetSlopePixelZ(v->x_pos, v->y_pos)); } /* Fill Vehicle::cur_real_order_index */ FOR_ALL_VEHICLES(v) { if (!v->IsPrimaryVehicle()) continue; /* Older versions are less strict with indices being in range and fix them on the fly */ if (v->cur_implicit_order_index >= v->GetNumOrders()) v->cur_implicit_order_index = 0; v->cur_real_order_index = v->cur_implicit_order_index; v->UpdateRealOrderIndex(); } } if (IsSavegameVersionBefore(159)) { /* If the savegame is old (before version 100), then the value of 255 * for these settings did not mean "disabled". As such everything * before then did reverse. * To simplify stuff we disable all turning around or we do not * disable anything at all. So, if some reversing was disabled we * will keep reversing disabled, otherwise it'll be turned on. */ _settings_game.pf.reverse_at_signals = IsSavegameVersionBefore(100) || (_settings_game.pf.wait_oneway_signal != 255 && _settings_game.pf.wait_twoway_signal != 255 && _settings_game.pf.wait_for_pbs_path != 255); Train *t; FOR_ALL_TRAINS(t) { _settings_game.vehicle.max_train_length = max(_settings_game.vehicle.max_train_length, CeilDiv(t->gcache.cached_total_length, TILE_SIZE)); } } if (IsSavegameVersionBefore(160)) { /* Setting difficulty industry_density other than zero get bumped to +1 * since a new option (minimal at position 1) has been added */ if (_settings_game.difficulty.industry_density > 0) { _settings_game.difficulty.industry_density++; } } if (IsSavegameVersionBefore(161)) { /* Before savegame version 161, persistent storages were not stored in a pool. */ if (!IsSavegameVersionBefore(76)) { Industry *ind; FOR_ALL_INDUSTRIES(ind) { assert(ind->psa != NULL); /* Check if the old storage was empty. */ bool is_empty = true; for (uint i = 0; i < sizeof(ind->psa->storage); i++) { if (ind->psa->GetValue(i) != 0) { is_empty = false; break; } } if (!is_empty) { ind->psa->grfid = _industry_mngr.GetGRFID(ind->type); } else { delete ind->psa; ind->psa = NULL; } } } if (!IsSavegameVersionBefore(145)) { Station *st; FOR_ALL_STATIONS(st) { if (!(st->facilities & FACIL_AIRPORT)) continue; assert(st->airport.psa != NULL); /* Check if the old storage was empty. */ bool is_empty = true; for (uint i = 0; i < sizeof(st->airport.psa->storage); i++) { if (st->airport.psa->GetValue(i) != 0) { is_empty = false; break; } } if (!is_empty) { st->airport.psa->grfid = _airport_mngr.GetGRFID(st->airport.type); } else { delete st->airport.psa; st->airport.psa = NULL; } } } } /* This triggers only when old snow_lines were copied into the snow_line_height. */ if (IsSavegameVersionBefore(164) && _settings_game.game_creation.snow_line_height >= MIN_SNOWLINE_HEIGHT * TILE_HEIGHT) { _settings_game.game_creation.snow_line_height /= TILE_HEIGHT; } if (IsSavegameVersionBefore(164) && !IsSavegameVersionBefore(32)) { /* We store 4 fences in the field tiles instead of only SE and SW. */ for (TileIndex t = 0; t < map_size; t++) { if (!IsTileType(t, MP_CLEAR) && !IsTileType(t, MP_TREES)) continue; if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_FIELDS)) continue; uint fence = GB(_m[t].m4, 5, 3); if (fence != 0 && IsTileType(TILE_ADDXY(t, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(t, 1, 0), CLEAR_FIELDS)) { SetFence(TILE_ADDXY(t, 1, 0), DIAGDIR_NE, fence); } fence = GB(_m[t].m4, 2, 3); if (fence != 0 && IsTileType(TILE_ADDXY(t, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(t, 0, 1), CLEAR_FIELDS)) { SetFence(TILE_ADDXY(t, 0, 1), DIAGDIR_NW, fence); } SB(_m[t].m4, 2, 3, 0); SB(_m[t].m4, 5, 3, 0); } } /* The center of train vehicles was changed, fix up spacing. */ if (IsSavegameVersionBefore(164)) FixupTrainLengths(); if (IsSavegameVersionBefore(165)) { Town *t; FOR_ALL_TOWNS(t) { /* Set the default cargo requirement for town growth */ switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER; break; case LT_TROPIC: if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT; if (FindFirstCargoWithTownEffect(TE_WATER) != NULL) t->goal[TE_WATER] = TOWN_GROWTH_DESERT; break; } } } if (IsSavegameVersionBefore(165)) { /* Adjust zoom level to account for new levels */ _saved_scrollpos_zoom = _saved_scrollpos_zoom + ZOOM_LVL_SHIFT; _saved_scrollpos_x *= ZOOM_LVL_BASE; _saved_scrollpos_y *= ZOOM_LVL_BASE; } /* When any NewGRF has been changed the availability of some vehicles might * have been changed too. e->company_avail must be set to 0 in that case * which is done by StartupEngines(). */ if (gcf_res != GLC_ALL_GOOD) StartupEngines(); if (IsSavegameVersionBefore(166)) { /* Update cargo acceptance map of towns. */ for (TileIndex t = 0; t < map_size; t++) { if (!IsTileType(t, MP_HOUSE)) continue; Town::Get(GetTownIndex(t))->cargo_accepted.Add(t); } Town *town; FOR_ALL_TOWNS(town) { UpdateTownCargoes(town); } } /* The road owner of standard road stops was not properly accounted for. */ if (IsSavegameVersionBefore(172)) { for (TileIndex t = 0; t < map_size; t++) { if (!IsStandardRoadStopTile(t)) continue; Owner o = GetTileOwner(t); SetRoadOwner(t, ROADTYPE_ROAD, o); SetRoadOwner(t, ROADTYPE_TRAM, o); } } if (IsSavegameVersionBefore(175)) { /* Introduced tree planting limit. */ Company *c; FOR_ALL_COMPANIES(c) c->tree_limit = _settings_game.construction.tree_frame_burst << 16; } if (IsSavegameVersionBefore(177)) { /* Fix too high inflation rates */ if (_economy.inflation_prices > MAX_INFLATION) _economy.inflation_prices = MAX_INFLATION; if (_economy.inflation_payment > MAX_INFLATION) _economy.inflation_payment = MAX_INFLATION; /* We have to convert the quarters of bankruptcy into months of bankruptcy */ FOR_ALL_COMPANIES(c) { c->months_of_bankruptcy = 3 * c->months_of_bankruptcy; } } if (IsSavegameVersionBefore(178)) { extern uint8 _old_diff_level; /* Initialise script settings profile */ _settings_game.script.settings_profile = IsInsideMM(_old_diff_level, SP_BEGIN, SP_END) ? _old_diff_level : (uint)SP_MEDIUM; } if (IsSavegameVersionBefore(182)) { Aircraft *v; /* Aircraft acceleration variable was bonkers */ FOR_ALL_AIRCRAFT(v) { if (v->subtype <= AIR_AIRCRAFT) { const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); v->acceleration = avi->acceleration; } } /* Blocked tiles could be reserved due to a bug, which causes * other places to assert upon e.g. station reconstruction. */ for (TileIndex t = 0; t < map_size; t++) { if (HasStationTileRail(t) && IsStationTileBlocked(t)) { SetRailStationReservation(t, false); } } } if (IsSavegameVersionBefore(184)) { /* The global units configuration is split up in multiple configurations. */ extern uint8 _old_units; _settings_game.locale.units_velocity = Clamp(_old_units, 0, 2); _settings_game.locale.units_power = Clamp(_old_units, 0, 2); _settings_game.locale.units_weight = Clamp(_old_units, 1, 2); _settings_game.locale.units_volume = Clamp(_old_units, 1, 2); _settings_game.locale.units_force = 2; _settings_game.locale.units_height = Clamp(_old_units, 0, 2); } if (IsSavegameVersionBefore(186)) { /* Move ObjectType from map to pool */ for (TileIndex t = 0; t < map_size; t++) { if (IsTileType(t, MP_OBJECT)) { Object *o = Object::Get(_m[t].m2); o->type = _m[t].m5; _m[t].m5 = 0; // zero upper bits of (now bigger) ObjectID } } } if (IsSavegameVersionBefore(188)) { /* Fix articulated road vehicles. * Some curves were shorter than other curves. * Now they have the same length, but that means that trailing articulated parts will * take longer to go through the curve than the parts in front which already left the courve. * So, make articulated parts catch up. */ RoadVehicle *v; bool roadside = _settings_game.vehicle.road_side == 1; SmallVector skip_frames; FOR_ALL_ROADVEHICLES(v) { if (!v->IsFrontEngine()) continue; skip_frames.Clear(); TileIndex prev_tile = v->tile; uint prev_tile_skip = 0; uint cur_skip = 0; for (RoadVehicle *u = v; u != NULL; u = u->Next()) { if (u->tile != prev_tile) { prev_tile_skip = cur_skip; prev_tile = u->tile; } else { cur_skip = prev_tile_skip; } uint *this_skip = skip_frames.Append(); *this_skip = prev_tile_skip; /* The following 3 curves now take longer than before */ switch (u->state) { case 2: cur_skip++; if (u->frame <= (roadside ? 9 : 5)) *this_skip = cur_skip; break; case 4: cur_skip++; if (u->frame <= (roadside ? 5 : 9)) *this_skip = cur_skip; break; case 5: cur_skip++; if (u->frame <= (roadside ? 4 : 2)) *this_skip = cur_skip; break; default: break; } } while (cur_skip > skip_frames[0]) { RoadVehicle *u = v; RoadVehicle *prev = NULL; for (uint *it = skip_frames.Begin(); it != skip_frames.End(); ++it, prev = u, u = u->Next()) { extern bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev); if (*it >= cur_skip) IndividualRoadVehicleController(u, prev); } cur_skip--; } } } /* * Only keep order-backups for network clients. * If we are a network server or not networking, then we just loaded a previously * saved-by-server savegame. There are no clients with a backup, so clear it. * Furthermore before savegame version 192 the actual content was always corrupt. */ if (!_networking || _network_server || IsSavegameVersionBefore(192)) { /* Note: We cannot use CleanPool since that skips part of the destructor * and then leaks un-reachable Orders in the order pool. */ OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { delete ob; } } /* Station acceptance is some kind of cache */ if (IsSavegameVersionBefore(127)) { Station *st; FOR_ALL_STATIONS(st) UpdateStationAcceptance(st, false); } /* Road stops is 'only' updating some caches */ AfterLoadRoadStops(); AfterLoadLabelMaps(); AfterLoadCompanyStats(); AfterLoadStoryBook(); GamelogPrintDebug(1); InitializeWindowsAndCaches(); /* Restore the signals */ ResetSignalHandlers(); AfterLoadLinkGraphs(); return true; } /** * Reload all NewGRF files during a running game. This is a cut-down * version of AfterLoadGame(). * XXX - We need to reset the vehicle position hash because with a non-empty * hash AfterLoadVehicles() will loop infinitely. We need AfterLoadVehicles() * to recalculate vehicle data as some NewGRF vehicle sets could have been * removed or added and changed statistics */ void ReloadNewGRFData() { /* reload grf data */ GfxLoadSprites(); LoadStringWidthTable(); RecomputePrices(); /* reload vehicles */ ResetVehicleHash(); AfterLoadVehicles(false); StartupEngines(); GroupStatistics::UpdateAfterLoad(); /* update station graphics */ AfterLoadStations(); /* Update company statistics. */ AfterLoadCompanyStats(); /* Check and update house and town values */ UpdateHousesAndTowns(); /* Delete news referring to no longer existing entities */ DeleteInvalidEngineNews(); /* Update livery selection windows */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) InvalidateWindowData(WC_COMPANY_COLOUR, i); /* Update company infrastructure counts. */ InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); /* redraw the whole screen */ MarkWholeScreenDirty(); CheckTrainsLengths(); } openttd-1.5.3/src/saveload/animated_tile_sl.cpp0000644000000000000000000000460312627373446020302 0ustar rootroot/* $Id: animated_tile_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 animated_tile_sl.cpp Code handling saving and loading of animated tiles */ #include "../stdafx.h" #include "../tile_type.h" #include "../core/alloc_func.hpp" #include "saveload.h" #include "../safeguards.h" extern TileIndex *_animated_tile_list; extern uint _animated_tile_count; extern uint _animated_tile_allocated; /** * Save the ANIT chunk. */ static void Save_ANIT() { SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list)); SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); } /** * Load the ANIT chunk; the chunk containing the animated tiles. */ static void Load_ANIT() { /* Before version 80 we did NOT have a variable length animated tile table */ if (IsSavegameVersionBefore(80)) { /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ SlArray(_animated_tile_list, 256, IsSavegameVersionBefore(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { if (_animated_tile_list[_animated_tile_count] == 0) break; } return; } _animated_tile_count = (uint)SlGetFieldLength() / sizeof(*_animated_tile_list); /* Determine a nice rounded size for the amount of allocated tiles */ _animated_tile_allocated = 256; while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2; _animated_tile_list = ReallocT(_animated_tile_list, _animated_tile_allocated); SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); } /** * "Definition" imported by the saveload code to be able to load and save * the animated tile table. */ extern const ChunkHandler _animated_tile_chunk_handlers[] = { { 'ANIT', Save_ANIT, Load_ANIT, NULL, NULL, CH_RIFF | CH_LAST}, }; openttd-1.5.3/src/saveload/cargomonitor_sl.cpp0000644000000000000000000000552212627373446020207 0ustar rootroot/* $Id: cargomonitor_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cargomonitor_sl.cpp Code handling saving and loading of Cargo monitoring. */ #include "../stdafx.h" #include "../cargomonitor.h" #include "saveload.h" #include "../safeguards.h" /** Temporary storage of cargo monitoring data for loading or saving it. */ struct TempStorage { CargoMonitorID number; uint32 amount; }; /** Description of the #TempStorage structure for the purpose of load and save. */ static const SaveLoad _cargomonitor_pair_desc[] = { SLE_VAR(TempStorage, number, SLE_UINT32), SLE_VAR(TempStorage, amount, SLE_UINT32), SLE_END() }; /** Save the #_cargo_deliveries monitoring map. */ static void SaveDelivery() { TempStorage storage; int i = 0; CargoMonitorMap::const_iterator iter = _cargo_deliveries.begin(); while (iter != _cargo_deliveries.end()) { storage.number = iter->first; storage.amount = iter->second; SlSetArrayIndex(i); SlObject(&storage, _cargomonitor_pair_desc); i++; iter++; } } /** Load the #_cargo_deliveries monitoring map. */ static void LoadDelivery() { TempStorage storage; ClearCargoDeliveryMonitoring(); for (;;) { if (SlIterateArray() < 0) break; SlObject(&storage, _cargomonitor_pair_desc); std::pair p(storage.number, storage.amount); _cargo_deliveries.insert(p); } } /** Save the #_cargo_pickups monitoring map. */ static void SavePickup() { TempStorage storage; int i = 0; CargoMonitorMap::const_iterator iter = _cargo_pickups.begin(); while (iter != _cargo_pickups.end()) { storage.number = iter->first; storage.amount = iter->second; SlSetArrayIndex(i); SlObject(&storage, _cargomonitor_pair_desc); i++; iter++; } } /** Load the #_cargo_pickups monitoring map. */ static void LoadPickup() { TempStorage storage; ClearCargoPickupMonitoring(); for (;;) { if (SlIterateArray() < 0) break; SlObject(&storage, _cargomonitor_pair_desc); std::pair p(storage.number, storage.amount); _cargo_pickups.insert(p); } } /** Chunk definition of the cargomonitoring maps. */ extern const ChunkHandler _cargomonitor_chunk_handlers[] = { { 'CMDL', SaveDelivery, LoadDelivery, NULL, NULL, CH_ARRAY}, { 'CMPU', SavePickup, LoadPickup, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/oldloader.cpp0000644000000000000000000002216212627373446016752 0ustar rootroot/* $Id: oldloader.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 oldloader.cpp Functions for handling of TTO/TTD/TTDP savegames. */ #include "../stdafx.h" #include "../debug.h" #include "../strings_type.h" #include "../string_func.h" #include "../settings_type.h" #include "../fileio_func.h" #include "table/strings.h" #include "saveload_internal.h" #include "oldloader.h" #include #include "../safeguards.h" static const int TTO_HEADER_SIZE = 41; static const int TTD_HEADER_SIZE = 49; uint32 _bump_assert_value; static inline OldChunkType GetOldChunkType(OldChunkType type) {return (OldChunkType)GB(type, 0, 4);} static inline OldChunkType GetOldChunkVarType(OldChunkType type) {return (OldChunkType)(GB(type, 8, 8) << 8);} static inline OldChunkType GetOldChunkFileType(OldChunkType type) {return (OldChunkType)(GB(type, 16, 8) << 16);} static inline byte CalcOldVarLen(OldChunkType type) { static const byte type_mem_size[] = {0, 1, 1, 2, 2, 4, 4, 8}; byte length = GB(type, 8, 8); assert(length != 0 && length < lengthof(type_mem_size)); return type_mem_size[length]; } /** * * Reads a byte from a file (do not call yourself, use ReadByte()) * */ static byte ReadByteFromFile(LoadgameState *ls) { /* To avoid slow reads, we read BUFFER_SIZE of bytes per time and just return a byte per time */ if (ls->buffer_cur >= ls->buffer_count) { /* Read some new bytes from the file */ int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file); /* We tried to read, but there is nothing in the file anymore.. */ if (count == 0) { DEBUG(oldloader, 0, "Read past end of file, loading failed"); throw std::exception(); } ls->buffer_count = count; ls->buffer_cur = 0; } return ls->buffer[ls->buffer_cur++]; } /** * * Reads a byte from the buffer and decompress if needed * */ byte ReadByte(LoadgameState *ls) { /* Old savegames have a nice compression algorithm (RLE) which means that we have a chunk, which starts with a length byte. If that byte is negative, we have to repeat the next byte that many times ( + 1). Else, we need to read that amount of bytes. Works pretty well if you have many zeros behind each other */ if (ls->chunk_size == 0) { /* Read new chunk */ int8 new_byte = ReadByteFromFile(ls); if (new_byte < 0) { /* Repeat next char for new_byte times */ ls->decoding = true; ls->decode_char = ReadByteFromFile(ls); ls->chunk_size = -new_byte + 1; } else { ls->decoding = false; ls->chunk_size = new_byte + 1; } } ls->total_read++; ls->chunk_size--; return ls->decoding ? ls->decode_char : ReadByteFromFile(ls); } /** * * Loads a chunk from the old savegame * */ bool LoadChunk(LoadgameState *ls, void *base, const OldChunks *chunks) { byte *base_ptr = (byte*)base; for (const OldChunks *chunk = chunks; chunk->type != OC_END; chunk++) { if (((chunk->type & OC_TTD) && _savegame_type == SGT_TTO) || ((chunk->type & OC_TTO) && _savegame_type != SGT_TTO)) { /* TTD(P)-only chunk, but TTO savegame || TTO-only chunk, but TTD/TTDP savegame */ continue; } byte *ptr = (byte*)chunk->ptr; if (chunk->type & OC_DEREFERENCE_POINTER) ptr = *(byte**)ptr; for (uint i = 0; i < chunk->amount; i++) { /* Handle simple types */ if (GetOldChunkType(chunk->type) != 0) { switch (GetOldChunkType(chunk->type)) { /* Just read the byte and forget about it */ case OC_NULL: ReadByte(ls); break; case OC_CHUNK: /* Call function, with 'i' as parameter to tell which item we * are going to read */ if (!chunk->proc(ls, i)) return false; break; case OC_ASSERT: DEBUG(oldloader, 4, "Assert point: 0x%X / 0x%X", ls->total_read, chunk->offset + _bump_assert_value); if (ls->total_read != chunk->offset + _bump_assert_value) throw std::exception(); default: break; } } else { uint64 res = 0; /* Reading from the file: bits 16 to 23 have the FILE type */ switch (GetOldChunkFileType(chunk->type)) { case OC_FILE_I8: res = (int8)ReadByte(ls); break; case OC_FILE_U8: res = ReadByte(ls); break; case OC_FILE_I16: res = (int16)ReadUint16(ls); break; case OC_FILE_U16: res = ReadUint16(ls); break; case OC_FILE_I32: res = (int32)ReadUint32(ls); break; case OC_FILE_U32: res = ReadUint32(ls); break; default: NOT_REACHED(); } /* When both pointers are NULL, we are just skipping data */ if (base_ptr == NULL && chunk->ptr == NULL) continue; /* Writing to the var: bits 8 to 15 have the VAR type */ if (chunk->ptr == NULL) ptr = base_ptr + chunk->offset; /* Write the data */ switch (GetOldChunkVarType(chunk->type)) { case OC_VAR_I8: *(int8 *)ptr = GB(res, 0, 8); break; case OC_VAR_U8: *(uint8 *)ptr = GB(res, 0, 8); break; case OC_VAR_I16:*(int16 *)ptr = GB(res, 0, 16); break; case OC_VAR_U16:*(uint16*)ptr = GB(res, 0, 16); break; case OC_VAR_I32:*(int32 *)ptr = res; break; case OC_VAR_U32:*(uint32*)ptr = res; break; case OC_VAR_I64:*(int64 *)ptr = res; break; case OC_VAR_U64:*(uint64*)ptr = res; break; default: NOT_REACHED(); } /* Increase pointer base for arrays when looping */ if (chunk->amount > 1 && chunk->ptr != NULL) ptr += CalcOldVarLen(chunk->type); } } } return true; } /** * * Initialize some data before reading * */ static void InitLoading(LoadgameState *ls) { ls->chunk_size = 0; ls->total_read = 0; ls->decoding = false; ls->decode_char = 0; ls->buffer_cur = 0; ls->buffer_count = 0; memset(ls->buffer, 0, BUFFER_SIZE); _bump_assert_value = 0; _settings_game.construction.freeform_edges = false; // disable so we can convert map array (SetTileType is still used) } /** * Verifies the title has a valid checksum * @param title title and checksum * @param len the length of the title to read/checksum * @return true iff the title is valid * @note the title (incl. checksum) has to be at least 41/49 (HEADER_SIZE) bytes long! */ static bool VerifyOldNameChecksum(char *title, uint len) { uint16 sum = 0; for (uint i = 0; i < len - 2; i++) { sum += title[i]; sum = ROL(sum, 1); } sum ^= 0xAAAA; // computed checksum uint16 sum2 = title[len - 2]; // checksum in file SB(sum2, 8, 8, title[len - 1]); return sum == sum2; } static inline bool CheckOldSavegameType(FILE *f, char *temp, const char *last, uint len) { assert(last - temp + 1 >= (int)len); if (fread(temp, 1, len, f) != len) { temp[0] = '\0'; // if reading failed, make the name empty return false; } bool ret = VerifyOldNameChecksum(temp, len); temp[len - 2] = '\0'; // name is null-terminated in savegame, but it's better to be sure str_validate(temp, last); return ret; } static SavegameType DetermineOldSavegameType(FILE *f, char *title, const char *last) { assert_compile(TTD_HEADER_SIZE >= TTO_HEADER_SIZE); char temp[TTD_HEADER_SIZE] = "Unknown"; SavegameType type = SGT_TTO; /* Can't fseek to 0 as in tar files that is not correct */ long pos = ftell(f); if (pos >= 0 && !CheckOldSavegameType(f, temp, lastof(temp), TTO_HEADER_SIZE)) { type = SGT_TTD; if (fseek(f, pos, SEEK_SET) < 0 || !CheckOldSavegameType(f, temp, lastof(temp), TTD_HEADER_SIZE)) { type = SGT_INVALID; } } if (title != NULL) { switch (type) { case SGT_TTO: title = strecpy(title, "(TTO) ", last); break; case SGT_TTD: title = strecpy(title, "(TTD) ", last); break; default: title = strecpy(title, "(broken) ", last); break; } title = strecpy(title, temp, last); } return type; } typedef bool LoadOldMainProc(LoadgameState *ls); bool LoadOldSaveGame(const char *file) { LoadgameState ls; DEBUG(oldloader, 3, "Trying to load a TTD(Patch) savegame"); InitLoading(&ls); /* Open file */ ls.file = FioFOpenFile(file, "rb", NO_DIRECTORY); if (ls.file == NULL) { DEBUG(oldloader, 0, "Cannot open file '%s'", file); return false; } SavegameType type = DetermineOldSavegameType(ls.file, NULL, NULL); LoadOldMainProc *proc = NULL; switch (type) { case SGT_TTO: proc = &LoadTTOMain; break; case SGT_TTD: proc = &LoadTTDMain; break; default: break; } _savegame_type = type; bool game_loaded; try { game_loaded = proc != NULL && proc(&ls); } catch (...) { game_loaded = false; } if (!game_loaded) { SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED); fclose(ls.file); return false; } _pause_mode = 2; return true; } void GetOldSaveGameName(const char *file, char *title, const char *last) { FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY); if (f == NULL) { *title = '\0'; return; } DetermineOldSavegameType(f, title, last); fclose(f); } openttd-1.5.3/src/saveload/industry_sl.cpp0000644000000000000000000001476212627373446017373 0ustar rootroot/* $Id: industry_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 industry_sl.cpp Code handling saving and loading of industries */ #include "../stdafx.h" #include "../industry.h" #include "saveload.h" #include "newgrf_sl.h" #include "../safeguards.h" static OldPersistentStorage _old_ind_persistent_storage; static const SaveLoad _industry_desc[] = { SLE_CONDVAR(Industry, location.tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Industry, location.tile, SLE_UINT32, 6, SL_MAX_VERSION), SLE_VAR(Industry, location.w, SLE_FILE_U8 | SLE_VAR_U16), SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16), SLE_REF(Industry, town, REF_TOWN), SLE_CONDNULL( 2, 0, 60), ///< used to be industry's produced_cargo SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, 78, SL_MAX_VERSION), SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, 70, SL_MAX_VERSION), SLE_ARR(Industry, produced_cargo_waiting, SLE_UINT16, 2), SLE_ARR(Industry, production_rate, SLE_UINT8, 2), SLE_CONDNULL( 3, 0, 60), ///< used to be industry's accepts_cargo SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, 78, SL_MAX_VERSION), SLE_VAR(Industry, prod_level, SLE_UINT8), SLE_ARR(Industry, this_month_production, SLE_UINT16, 2), SLE_ARR(Industry, this_month_transported, SLE_UINT16, 2), SLE_ARR(Industry, last_month_pct_transported, SLE_UINT8, 2), SLE_ARR(Industry, last_month_production, SLE_UINT16, 2), SLE_ARR(Industry, last_month_transported, SLE_UINT16, 2), SLE_VAR(Industry, counter, SLE_UINT16), SLE_VAR(Industry, type, SLE_UINT8), SLE_VAR(Industry, owner, SLE_UINT8), SLE_VAR(Industry, random_colour, SLE_UINT8), SLE_CONDVAR(Industry, last_prod_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Industry, last_prod_year, SLE_INT32, 31, SL_MAX_VERSION), SLE_VAR(Industry, was_cargo_delivered, SLE_UINT8), SLE_CONDVAR(Industry, founder, SLE_UINT8, 70, SL_MAX_VERSION), SLE_CONDVAR(Industry, construction_date, SLE_INT32, 70, SL_MAX_VERSION), SLE_CONDVAR(Industry, construction_type, SLE_UINT8, 70, SL_MAX_VERSION), SLE_CONDVAR(Industry, last_cargo_accepted_at, SLE_INT32, 70, SL_MAX_VERSION), SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, 73, SL_MAX_VERSION), SLEG_CONDARR(_old_ind_persistent_storage.storage, SLE_UINT32, 16, 76, 160), SLE_CONDREF(Industry, psa, REF_STORAGE, 161, SL_MAX_VERSION), SLE_CONDVAR(Industry, random_triggers, SLE_UINT8, 82, SL_MAX_VERSION), SLE_CONDVAR(Industry, random, SLE_UINT16, 82, SL_MAX_VERSION), SLE_CONDNULL(32, 2, 143), // old reserved space SLE_END() }; static void Save_INDY() { Industry *ind; /* Write the industries */ FOR_ALL_INDUSTRIES(ind) { SlSetArrayIndex(ind->index); SlObject(ind, _industry_desc); } } static void Save_IIDS() { Save_NewGRFMapping(_industry_mngr); } static void Save_TIDS() { Save_NewGRFMapping(_industile_mngr); } static void Load_INDY() { int index; Industry::ResetIndustryCounts(); while ((index = SlIterateArray()) != -1) { Industry *i = new (index) Industry(); SlObject(i, _industry_desc); /* Before savegame version 161, persistent storages were not stored in a pool. */ if (IsSavegameVersionBefore(161) && !IsSavegameVersionBefore(76)) { /* Store the old persistent storage. The GRFID will be added later. */ assert(PersistentStorage::CanAllocateItem()); i->psa = new PersistentStorage(0, 0, 0); memcpy(i->psa->storage, _old_ind_persistent_storage.storage, sizeof(i->psa->storage)); } Industry::IncIndustryTypeCount(i->type); } } static void Load_IIDS() { Load_NewGRFMapping(_industry_mngr); } static void Load_TIDS() { Load_NewGRFMapping(_industile_mngr); } static void Ptrs_INDY() { Industry *i; FOR_ALL_INDUSTRIES(i) { SlObject(i, _industry_desc); } } /** Description of the data to save and load in #IndustryBuildData. */ static const SaveLoad _industry_builder_desc[] = { SLEG_VAR(_industry_builder.wanted_inds, SLE_UINT32), SLEG_END() }; /** Load/save industry builder. */ static void LoadSave_IBLD() { SlGlobList(_industry_builder_desc); } /** Description of the data to save and load in #IndustryTypeBuildData. */ static const SaveLoad _industrytype_builder_desc[] = { SLE_VAR(IndustryTypeBuildData, probability, SLE_UINT32), SLE_VAR(IndustryTypeBuildData, min_number, SLE_UINT8), SLE_VAR(IndustryTypeBuildData, target_count, SLE_UINT16), SLE_VAR(IndustryTypeBuildData, max_wait, SLE_UINT16), SLE_VAR(IndustryTypeBuildData, wait_count, SLE_UINT16), SLE_END() }; /** Save industry-type build data. */ static void Save_ITBL() { for (int i = 0; i < NUM_INDUSTRYTYPES; i++) { SlSetArrayIndex(i); SlObject(_industry_builder.builddata + i, _industrytype_builder_desc); } } /** Load industry-type build data. */ static void Load_ITBL() { int index; for (int i = 0; i < NUM_INDUSTRYTYPES; i++) { index = SlIterateArray(); assert(index == i); SlObject(_industry_builder.builddata + i, _industrytype_builder_desc); } index = SlIterateArray(); assert(index == -1); } extern const ChunkHandler _industry_chunk_handlers[] = { { 'INDY', Save_INDY, Load_INDY, Ptrs_INDY, NULL, CH_ARRAY}, { 'IIDS', Save_IIDS, Load_IIDS, NULL, NULL, CH_ARRAY}, { 'TIDS', Save_TIDS, Load_TIDS, NULL, NULL, CH_ARRAY}, { 'IBLD', LoadSave_IBLD, LoadSave_IBLD, NULL, NULL, CH_RIFF}, { 'ITBL', Save_ITBL, Load_ITBL, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/waypoint_sl.cpp0000644000000000000000000001671512627373446017364 0ustar rootroot/* $Id: waypoint_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 waypoint_sl.cpp Code handling saving and loading of waypoints */ #include "../stdafx.h" #include "../waypoint_base.h" #include "../newgrf_station.h" #include "../vehicle_base.h" #include "../town.h" #include "../newgrf.h" #include "table/strings.h" #include "saveload_internal.h" #include "../safeguards.h" /** Helper structure to convert from the old waypoint system. */ struct OldWaypoint { size_t index; TileIndex xy; TownID town_index; Town *town; uint16 town_cn; StringID string_id; char *name; uint8 delete_ctr; Date build_date; uint8 localidx; uint32 grfid; const StationSpec *spec; OwnerByte owner; size_t new_index; }; /** Temporary array with old waypoints. */ static SmallVector _old_waypoints; /** * Update the waypoint orders to get the new waypoint ID. * @param o the order 'list' to check. */ static void UpdateWaypointOrder(Order *o) { if (!o->IsType(OT_GOTO_WAYPOINT)) return; for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { if (wp->index != o->GetDestination()) continue; o->SetDestination((DestinationID)wp->new_index); return; } } /** * Perform all steps to upgrade from the old waypoints to the new version * that uses station. This includes some old saveload mechanics. */ void MoveWaypointsToBaseStations() { /* In version 17, ground type is moved from m2 to m4 for depots and * waypoints to make way for storing the index in m2. The custom graphics * id which was stored in m4 is now saved as a grf/id reference in the * waypoint struct. */ if (IsSavegameVersionBefore(17)) { for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { if (wp->delete_ctr != 0) continue; // The waypoint was deleted /* Waypoint indices were not added to the map prior to this. */ _m[wp->xy].m2 = (StationID)wp->index; if (HasBit(_m[wp->xy].m3, 4)) { wp->spec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(_m[wp->xy].m4 + 1); } } } else { /* As of version 17, we recalculate the custom graphic ID of waypoints * from the GRF ID / station index. */ for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { StationClass* stclass = StationClass::Get(STAT_CLASS_WAYP); for (uint i = 0; i < stclass->GetSpecCount(); i++) { const StationSpec *statspec = stclass->GetSpec(i); if (statspec != NULL && statspec->grf_prop.grffile->grfid == wp->grfid && statspec->grf_prop.local_id == wp->localidx) { wp->spec = statspec; break; } } } } if (!Waypoint::CanAllocateItem(_old_waypoints.Length())) SlError(STR_ERROR_TOO_MANY_STATIONS_LOADING); /* All saveload conversions have been done. Create the new waypoints! */ for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { Waypoint *new_wp = new Waypoint(wp->xy); new_wp->town = wp->town; new_wp->town_cn = wp->town_cn; new_wp->name = wp->name; new_wp->delete_ctr = 0; // Just reset delete counter for once. new_wp->build_date = wp->build_date; new_wp->owner = wp->owner; new_wp->string_id = STR_SV_STNAME_WAYPOINT; TileIndex t = wp->xy; if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp->index) { /* The tile might've been reserved! */ bool reserved = !IsSavegameVersionBefore(100) && HasBit(_m[t].m5, 4); /* The tile really has our waypoint, so reassign the map array */ MakeRailWaypoint(t, GetTileOwner(t), new_wp->index, (Axis)GB(_m[t].m5, 0, 1), 0, GetRailType(t)); new_wp->facilities |= FACIL_TRAIN; new_wp->owner = GetTileOwner(t); SetRailStationReservation(t, reserved); if (wp->spec != NULL) { SetCustomStationSpecIndex(t, AllocateSpecToStation(wp->spec, new_wp, true)); } new_wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE); } wp->new_index = new_wp->index; } /* Update the orders of vehicles */ OrderList *ol; FOR_ALL_ORDER_LISTS(ol) { if (ol->GetFirstSharedVehicle()->type != VEH_TRAIN) continue; for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); } Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->type != VEH_TRAIN) continue; UpdateWaypointOrder(&v->current_order); } _old_waypoints.Reset(); } static const SaveLoad _old_waypoint_desc[] = { SLE_CONDVAR(OldWaypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(OldWaypoint, xy, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(OldWaypoint, town_index, SLE_UINT16, 12, 121), SLE_CONDREF(OldWaypoint, town, REF_TOWN, 122, SL_MAX_VERSION), SLE_CONDVAR(OldWaypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, 12, 88), SLE_CONDVAR(OldWaypoint, town_cn, SLE_UINT16, 89, SL_MAX_VERSION), SLE_CONDVAR(OldWaypoint, string_id, SLE_STRINGID, 0, 83), SLE_CONDSTR(OldWaypoint, name, SLE_STR, 0, 84, SL_MAX_VERSION), SLE_VAR(OldWaypoint, delete_ctr, SLE_UINT8), SLE_CONDVAR(OldWaypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), SLE_CONDVAR(OldWaypoint, build_date, SLE_INT32, 31, SL_MAX_VERSION), SLE_CONDVAR(OldWaypoint, localidx, SLE_UINT8, 3, SL_MAX_VERSION), SLE_CONDVAR(OldWaypoint, grfid, SLE_UINT32, 17, SL_MAX_VERSION), SLE_CONDVAR(OldWaypoint, owner, SLE_UINT8, 101, SL_MAX_VERSION), SLE_END() }; static void Load_WAYP() { /* Precaution for when loading failed and it didn't get cleared */ _old_waypoints.Clear(); int index; while ((index = SlIterateArray()) != -1) { OldWaypoint *wp = _old_waypoints.Append(); memset(wp, 0, sizeof(*wp)); wp->index = index; SlObject(wp, _old_waypoint_desc); } } static void Ptrs_WAYP() { for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { SlObject(wp, _old_waypoint_desc); if (IsSavegameVersionBefore(12)) { wp->town_cn = (wp->string_id & 0xC000) == 0xC000 ? (wp->string_id >> 8) & 0x3F : 0; wp->town = ClosestTownFromTile(wp->xy, UINT_MAX); } else if (IsSavegameVersionBefore(122)) { /* Only for versions 12 .. 122 */ if (!Town::IsValidID(wp->town_index)) { /* Upon a corrupted waypoint we'll likely get here. The next step will be to * loop over all Ptrs procs to NULL the pointers. However, we don't know * whether we're in the NULL or "normal" Ptrs proc. So just clear the list * of old waypoints we constructed and then this waypoint (and the other * possibly corrupt ones) will not be queried in the NULL Ptrs proc run. */ _old_waypoints.Clear(); SlErrorCorrupt("Referencing invalid Town"); } wp->town = Town::Get(wp->town_index); } if (IsSavegameVersionBefore(84)) { wp->name = CopyFromOldName(wp->string_id); } } } extern const ChunkHandler _waypoint_chunk_handlers[] = { { 'CHKP', NULL, Load_WAYP, Ptrs_WAYP, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/saveload_filter.h0000644000000000000000000000554312627373446017621 0ustar rootroot/* $Id: saveload_filter.h 21395 2010-12-05 14:41:34Z rubidium $ */ /* * 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 saveload_filter.h Declaration of filters used for saving and loading savegames. */ #ifndef SAVELOAD_FILTER_H #define SAVELOAD_FILTER_H /** Interface for filtering a savegame till it is loaded. */ struct LoadFilter { /** Chained to the (savegame) filters. */ LoadFilter *chain; /** * Initialise this filter. * @param chain The next filter in this chain. */ LoadFilter(LoadFilter *chain) : chain(chain) { } /** Make sure the writers are properly closed. */ virtual ~LoadFilter() { delete this->chain; } /** * Read a given number of bytes from the savegame. * @param buf The bytes to read. * @param len The number of bytes to read. * @return The number of actually read bytes. */ virtual size_t Read(byte *buf, size_t len) = 0; /** * Reset this filter to read from the beginning of the file. */ virtual void Reset() { this->chain->Reset(); } }; /** * Instantiator for a load filter. * @param chain The next filter in this chain. * @tparam T The type of load filter to create. */ template LoadFilter *CreateLoadFilter(LoadFilter *chain) { return new T(chain); } /** Interface for filtering a savegame till it is written. */ struct SaveFilter { /** Chained to the (savegame) filters. */ SaveFilter *chain; /** * Initialise this filter. * @param chain The next filter in this chain. */ SaveFilter(SaveFilter *chain) : chain(chain) { } /** Make sure the writers are properly closed. */ virtual ~SaveFilter() { delete this->chain; } /** * Write a given number of bytes into the savegame. * @param buf The bytes to write. * @param len The number of bytes to write. */ virtual void Write(byte *buf, size_t len) = 0; /** * Prepare everything to finish writing the savegame. */ virtual void Finish() { if (this->chain != NULL) this->chain->Finish(); } }; /** * Instantiator for a save filter. * @param chain The next filter in this chain. * @param compression_level The requested level of compression. * @tparam T The type of save filter to create. */ template SaveFilter *CreateSaveFilter(SaveFilter *chain, byte compression_level) { return new T(chain, compression_level); } #endif /* SAVELOAD_FILTER_H */ openttd-1.5.3/src/saveload/cheat_sl.cpp0000644000000000000000000000334612627373446016572 0ustar rootroot/* $Id: cheat_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cheat_sl.cpp Code handling saving and loading of cheats */ #include "../stdafx.h" #include "../cheat_type.h" #include "saveload.h" #include "../safeguards.h" /** * Save the cheat values. */ static void Save_CHTS() { /* Cannot use lengthof because _cheats is of type Cheats, not Cheat */ byte count = sizeof(_cheats) / sizeof(Cheat); Cheat *cht = (Cheat*) &_cheats; Cheat *cht_last = &cht[count]; SlSetLength(count * 2); for (; cht != cht_last; cht++) { SlWriteByte(cht->been_used); SlWriteByte(cht->value); } } /** * Load the cheat values. */ static void Load_CHTS() { Cheat *cht = (Cheat*)&_cheats; size_t count = SlGetFieldLength() / 2; /* Cannot use lengthof because _cheats is of type Cheats, not Cheat */ if (count > sizeof(_cheats) / sizeof(Cheat)) SlErrorCorrupt("Too many cheat values"); for (uint i = 0; i < count; i++) { cht[i].been_used = (SlReadByte() != 0); cht[i].value = (SlReadByte() != 0); } } /** Chunk handlers related to cheats. */ extern const ChunkHandler _cheat_chunk_handlers[] = { { 'CHTS', Save_CHTS, Load_CHTS, NULL, NULL, CH_RIFF | CH_LAST}, }; openttd-1.5.3/src/saveload/cargopacket_sl.cpp0000644000000000000000000001132212627373446017762 0ustar rootroot/* $Id: cargopacket_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cargopacket_sl.cpp Code handling saving and loading of cargo packets */ #include "../stdafx.h" #include "../vehicle_base.h" #include "../station_base.h" #include "saveload.h" #include "../safeguards.h" /** * Savegame conversion for cargopackets. */ /* static */ void CargoPacket::AfterLoad() { if (IsSavegameVersionBefore(44)) { Vehicle *v; /* If we remove a station while cargo from it is still en route, payment calculation will assume * 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy * stores the coordinates, preserving them even if the station is removed. However, if a game is loaded * where this situation exists, the cargo-source information is lost. in this case, we set the source * to the current tile of the vehicle to prevent excessive profits */ FOR_ALL_VEHICLES(v) { const CargoPacketList *packets = v->cargo.Packets(); for (VehicleCargoList::ConstIterator it(packets->begin()); it != packets->end(); it++) { CargoPacket *cp = *it; cp->source_xy = Station::IsValidID(cp->source) ? Station::Get(cp->source)->xy : v->tile; cp->loaded_at_xy = cp->source_xy; } } /* Store position of the station where the goods come from, so there * are no very high payments when stations get removed. However, if the * station where the goods came from is already removed, the source * information is lost. In that case we set it to the position of this * station */ Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) { GoodsEntry *ge = &st->goods[c]; const StationCargoPacketMap *packets = ge->cargo.Packets(); for (StationCargoList::ConstIterator it(packets->begin()); it != packets->end(); it++) { CargoPacket *cp = *it; cp->source_xy = Station::IsValidID(cp->source) ? Station::Get(cp->source)->xy : st->xy; cp->loaded_at_xy = cp->source_xy; } } } } if (IsSavegameVersionBefore(120)) { /* CargoPacket's source should be either INVALID_STATION or a valid station */ CargoPacket *cp; FOR_ALL_CARGOPACKETS(cp) { if (!Station::IsValidID(cp->source)) cp->source = INVALID_STATION; } } if (!IsSavegameVersionBefore(68)) { /* Only since version 68 we have cargo packets. Savegames from before used * 'new CargoPacket' + cargolist.Append so their caches are already * correct and do not need rebuilding. */ Vehicle *v; FOR_ALL_VEHICLES(v) v->cargo.InvalidateCache(); Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache(); } } if (IsSavegameVersionBefore(181)) { Vehicle *v; FOR_ALL_VEHICLES(v) v->cargo.KeepAll(); } } /** * Wrapper function to get the CargoPacket's internal structure while * some of the variables itself are private. * @return the saveload description for CargoPackets. */ const SaveLoad *GetCargoPacketDesc() { static const SaveLoad _cargopacket_desc[] = { SLE_VAR(CargoPacket, source, SLE_UINT16), SLE_VAR(CargoPacket, source_xy, SLE_UINT32), SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32), SLE_VAR(CargoPacket, count, SLE_UINT16), SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8), SLE_VAR(CargoPacket, feeder_share, SLE_INT64), SLE_CONDVAR(CargoPacket, source_type, SLE_UINT8, 125, SL_MAX_VERSION), SLE_CONDVAR(CargoPacket, source_id, SLE_UINT16, 125, SL_MAX_VERSION), /* Used to be paid_for, but that got changed. */ SLE_CONDNULL(1, 0, 120), SLE_END() }; return _cargopacket_desc; } /** * Save the cargo packets. */ static void Save_CAPA() { CargoPacket *cp; FOR_ALL_CARGOPACKETS(cp) { SlSetArrayIndex(cp->index); SlObject(cp, GetCargoPacketDesc()); } } /** * Load the cargo packets. */ static void Load_CAPA() { int index; while ((index = SlIterateArray()) != -1) { CargoPacket *cp = new (index) CargoPacket(); SlObject(cp, GetCargoPacketDesc()); } } /** Chunk handlers related to cargo packets. */ extern const ChunkHandler _cargopacket_chunk_handlers[] = { { 'CAPA', Save_CAPA, Load_CAPA, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/oldloader_sl.cpp0000644000000000000000000016653412627373446017464 0ustar rootroot/* $Id: oldloader_sl.cpp 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 oldloader_sl.cpp Chunks and fix-ups for TTO/TTD/TTDP savegames. TTO loader code is based on SVXConverter by Roman Vetter. */ #include "../stdafx.h" #include "../town.h" #include "../industry.h" #include "../company_func.h" #include "../aircraft.h" #include "../roadveh.h" #include "../ship.h" #include "../train.h" #include "../signs_base.h" #include "../station_base.h" #include "../subsidy_base.h" #include "../debug.h" #include "../depot_base.h" #include "../date_func.h" #include "../vehicle_func.h" #include "../effectvehicle_base.h" #include "../engine_func.h" #include "../company_base.h" #include "../disaster_vehicle.h" #include "saveload_internal.h" #include "oldloader.h" #include "table/strings.h" #include "../table/engines.h" #include "../table/townname.h" #include "../safeguards.h" static bool _read_ttdpatch_flags; ///< Have we (tried to) read TTDPatch extra flags? static uint16 _old_extra_chunk_nums; ///< Number of extra TTDPatch chunks static byte _old_vehicle_multiplier; ///< TTDPatch vehicle multiplier static uint8 *_old_map3; void FixOldMapArray() { /* TTO/TTD/TTDP savegames could have buoys at tile 0 * (without assigned station struct) */ MemSetT(&_m[0], 0); SetTileType(0, MP_WATER); SetTileOwner(0, OWNER_WATER); } static void FixTTDMapArray() { /* _old_map3 is moved to _m::m3 and _m::m4 */ for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) { _m[t].m3 = _old_map3[t * 2]; _m[t].m4 = _old_map3[t * 2 + 1]; } for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) { switch (GetTileType(t)) { case MP_STATION: _m[t].m4 = 0; // We do not understand this TTDP station mapping (yet) switch (_m[t].m5) { /* We have drive through stops at a totally different place */ case 0x53: case 0x54: _m[t].m5 += 170 - 0x53; break; // Bus drive through case 0x57: case 0x58: _m[t].m5 += 168 - 0x57; break; // Truck drive through case 0x55: case 0x56: _m[t].m5 += 170 - 0x55; break; // Bus tram stop case 0x59: case 0x5A: _m[t].m5 += 168 - 0x59; break; // Truck tram stop default: break; } break; case MP_RAILWAY: /* We save presignals different from TTDPatch, convert them */ if (GB(_m[t].m5, 6, 2) == 1) { // RAIL_TILE_SIGNALS /* This byte is always zero in TTD for this type of tile */ if (_m[t].m4) { // Convert the presignals to our own format _m[t].m4 = (_m[t].m4 >> 1) & 7; } } /* TTDPatch stores PBS things in L6 and all elsewhere; so we'll just * clear it for ourselves and let OTTD's rebuild PBS itself */ _m[t].m4 &= 0xF; // Only keep the lower four bits; upper four is PBS break; case MP_WATER: /* if water class == 3, make river there */ if (GB(_m[t].m3, 0, 2) == 3) { SetTileType(t, MP_WATER); SetTileOwner(t, OWNER_WATER); _m[t].m2 = 0; _m[t].m3 = 2; // WATER_CLASS_RIVER _m[t].m4 = Random(); _m[t].m5 = 0; } break; default: break; } } FixOldMapArray(); } static void FixTTDDepots() { const Depot *d; FOR_ALL_DEPOTS_FROM(d, 252) { if (!IsDepotTile(d->xy) || GetDepotIndex(d->xy) != d->index) { /** Workaround for SVXConverter bug, depots 252-255 could be invalid */ delete d; } } } #define FIXNUM(x, y, z) (((((x) << 16) / (y)) + 1) << z) static uint32 RemapOldTownName(uint32 townnameparts, byte old_town_name_type) { switch (old_town_name_type) { case 0: case 3: // English, American /* Already OK */ return townnameparts; case 1: // French /* For some reason 86 needs to be subtracted from townnameparts * 0000 0000 0000 0000 0000 0000 1111 1111 */ return FIXNUM(townnameparts - 86, lengthof(_name_french_real), 0); case 2: // German DEBUG(misc, 0, "German Townnames are buggy (%d)", townnameparts); return townnameparts; case 4: // Latin-American /* 0000 0000 0000 0000 0000 0000 1111 1111 */ return FIXNUM(townnameparts, lengthof(_name_spanish_real), 0); case 5: // Silly /* NUM_SILLY_1 - lower 16 bits * NUM_SILLY_2 - upper 16 bits without leading 1 (first 8 bytes) * 1000 0000 2222 2222 0000 0000 1111 1111 */ return FIXNUM(townnameparts, lengthof(_name_silly_1), 0) | FIXNUM(GB(townnameparts, 16, 8), lengthof(_name_silly_2), 16); } return 0; } #undef FIXNUM static void FixOldTowns() { Town *town; /* Convert town-names if needed */ FOR_ALL_TOWNS(town) { if (IsInsideMM(town->townnametype, 0x20C1, 0x20C3)) { town->townnametype = SPECSTR_TOWNNAME_ENGLISH + _settings_game.game_creation.town_name; town->townnameparts = RemapOldTownName(town->townnameparts, _settings_game.game_creation.town_name); } } } static StringID *_old_vehicle_names; /** * Convert the old style vehicles into something that resembles * the old new style savegames. Then #AfterLoadGame can handle * the rest of the conversion. */ void FixOldVehicles() { Vehicle *v; FOR_ALL_VEHICLES(v) { if ((size_t)v->next == 0xFFFF) { v->next = NULL; } else { v->next = Vehicle::GetIfValid((size_t)v->next); } /* For some reason we need to correct for this */ switch (v->spritenum) { case 0xfd: break; case 0xff: v->spritenum = 0xfe; break; default: v->spritenum >>= 1; break; } /* Vehicle-subtype is different in TTD(Patch) */ if (v->type == VEH_EFFECT) v->subtype = v->subtype >> 1; v->name = CopyFromOldName(_old_vehicle_names[v->index]); /* We haven't used this bit for stations for ages */ if (v->type == VEH_ROAD) { RoadVehicle *rv = RoadVehicle::From(v); if (rv->state != RVSB_IN_DEPOT && rv->state != RVSB_WORMHOLE) { ClrBit(rv->state, 2); if (IsTileType(rv->tile, MP_STATION) && _m[rv->tile].m5 >= 168) { /* Update the vehicle's road state to show we're in a drive through road stop. */ SetBit(rv->state, RVS_IN_DT_ROAD_STOP); } } } /* The subtype should be 0, but it sometimes isn't :( */ if (v->type == VEH_ROAD || v->type == VEH_SHIP) v->subtype = 0; /* Sometimes primary vehicles would have a nothing (invalid) order * or vehicles that could not have an order would still have a * (loading) order which causes assertions and the like later on. */ if (!IsCompanyBuildableVehicleType(v) || (v->IsPrimaryVehicle() && v->current_order.IsType(OT_NOTHING))) { v->current_order.MakeDummy(); } /* Shared orders are fixed in AfterLoadVehicles now */ } } static bool FixTTOMapArray() { for (TileIndex t = 0; t < OLD_MAP_SIZE; t++) { TileType tt = GetTileType(t); if (tt == 11) { /* TTO has a different way of storing monorail. * Instead of using bits in m3 it uses a different tile type. */ _m[t].m3 = 1; // rail type = monorail (in TTD) SetTileType(t, MP_RAILWAY); _m[t].m2 = 1; // set monorail ground to RAIL_GROUND_GRASS tt = MP_RAILWAY; } switch (tt) { case MP_CLEAR: break; case MP_RAILWAY: switch (GB(_m[t].m5, 6, 2)) { case 0: // RAIL_TILE_NORMAL break; case 1: // RAIL_TILE_SIGNALS _m[t].m4 = (~_m[t].m5 & 1) << 2; // signal variant (present only in OTTD) SB(_m[t].m2, 6, 2, GB(_m[t].m5, 3, 2)); // signal status _m[t].m3 |= 0xC0; // both signals are present _m[t].m5 = HasBit(_m[t].m5, 5) ? 2 : 1; // track direction (only X or Y) _m[t].m5 |= 0x40; // RAIL_TILE_SIGNALS break; case 3: // RAIL_TILE_DEPOT _m[t].m2 = 0; break; default: return false; } break; case MP_ROAD: // road (depot) or level crossing switch (GB(_m[t].m5, 4, 4)) { case 0: // ROAD_TILE_NORMAL if (_m[t].m2 == 4) _m[t].m2 = 5; // 'small trees' -> ROADSIDE_TREES break; case 1: // ROAD_TILE_CROSSING (there aren't monorail crossings in TTO) _m[t].m3 = _m[t].m1; // set owner of road = owner of rail break; case 2: // ROAD_TILE_DEPOT break; default: return false; } break; case MP_HOUSE: _m[t].m3 = _m[t].m2 & 0xC0; // construction stage _m[t].m2 &= 0x3F; // building type if (_m[t].m2 >= 5) _m[t].m2++; // skip "large office block on snow" break; case MP_TREES: _m[t].m3 = GB(_m[t].m5, 3, 3); // type of trees _m[t].m5 &= 0xC7; // number of trees and growth status break; case MP_STATION: _m[t].m3 = (_m[t].m5 >= 0x08 && _m[t].m5 <= 0x0F) ? 1 : 0; // monorail -> 1, others 0 (rail, road, airport, dock) if (_m[t].m5 >= 8) _m[t].m5 -= 8; // shift for monorail if (_m[t].m5 >= 0x42) _m[t].m5++; // skip heliport break; case MP_WATER: _m[t].m3 = _m[t].m2 = 0; break; case MP_VOID: _m[t].m2 = _m[t].m3 = _m[t].m5 = 0; break; case MP_INDUSTRY: _m[t].m3 = 0; switch (_m[t].m5) { case 0x24: // farm silo _m[t].m5 = 0x25; break; case 0x25: case 0x27: // farm case 0x28: case 0x29: case 0x2A: case 0x2B: // factory _m[t].m5--; break; default: if (_m[t].m5 >= 0x2C) _m[t].m5 += 3; // iron ore mine, steel mill or bank break; } break; case MP_TUNNELBRIDGE: if (HasBit(_m[t].m5, 7)) { // bridge byte m5 = _m[t].m5; _m[t].m5 = m5 & 0xE1; // copy bits 7..5, 1 if (GB(m5, 1, 2) == 1) _m[t].m5 |= 0x02; // road bridge if (GB(m5, 1, 2) == 3) _m[t].m2 |= 0xA0; // monorail bridge -> tubular, steel bridge if (!HasBit(m5, 6)) { // bridge head _m[t].m3 = (GB(m5, 1, 2) == 3) ? 1 : 0; // track subtype (1 for monorail, 0 for others) } else { // middle bridge part _m[t].m3 = HasBit(m5, 2) ? 0x10 : 0; // track subtype on bridge if (GB(m5, 3, 2) == 3) _m[t].m3 |= 1; // track subtype under bridge if (GB(m5, 3, 2) == 1) _m[t].m5 |= 0x08; // set for road/water under (0 for rail/clear) } } else { // tunnel entrance/exit _m[t].m2 = 0; _m[t].m3 = HasBit(_m[t].m5, 3); // monorail _m[t].m5 &= HasBit(_m[t].m5, 3) ? 0x03 : 0x07 ; // direction, transport type (== 0 for rail) } break; case MP_OBJECT: _m[t].m2 = 0; _m[t].m3 = 0; break; default: return false; } } FixOldMapArray(); return true; } static Engine *_old_engines; static bool FixTTOEngines() { /** TTD->TTO remapping of engines; 255 means there is no equivalent. SVXConverter uses (almost) the same table. */ static const EngineID ttd_to_tto[] = { 0, 255, 255, 255, 255, 255, 255, 255, 5, 7, 8, 9, 10, 11, 12, 13, 255, 255, 255, 255, 255, 255, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 29, 28, 30, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 255, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 44, 45, 46, 255, 255, 255, 255, 47, 48, 255, 49, 50, 255, 255, 255, 255, 51, 52, 255, 53, 54, 255, 55, 56, 255, 57, 59, 255, 58, 60, 255, 61, 62, 255, 63, 64, 255, 65, 66, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 67, 68, 69, 70, 71, 255, 255, 76, 77, 255, 255, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 102, 255, 255 }; /** TTO->TTD remapping of engines. SVXConverter uses the same table. */ static const EngineID tto_to_ttd[] = { 0, 0, 8, 8, 8, 8, 8, 9, 10, 11, 12, 13, 14, 15, 15, 22, 23, 24, 25, 26, 27, 29, 28, 30, 31, 32, 33, 34, 35, 36, 37, 55, 57, 59, 58, 60, 61, 62, 63, 64, 65, 66, 67, 116, 116, 117, 118, 123, 124, 126, 127, 132, 133, 135, 136, 138, 139, 141, 142, 144, 145, 147, 148, 150, 151, 153, 154, 204, 205, 206, 207, 208, 211, 212, 211, 212, 211, 212, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 253 }; Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->engine_type >= lengthof(tto_to_ttd)) return false; v->engine_type = tto_to_ttd[v->engine_type]; } /* Load the default engine set. Many of them will be overridden later */ uint j = 0; for (uint i = 0; i < lengthof(_orig_rail_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_TRAIN, i); for (uint i = 0; i < lengthof(_orig_road_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_ROAD, i); for (uint i = 0; i < lengthof(_orig_ship_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_SHIP, i); for (uint i = 0; i < lengthof(_orig_aircraft_vehicle_info); i++, j++) new (GetTempDataEngine(j)) Engine(VEH_AIRCRAFT, i); Date aging_date = min(_date + DAYS_TILL_ORIGINAL_BASE_YEAR, ConvertYMDToDate(2050, 0, 1)); for (EngineID i = 0; i < 256; i++) { int oi = ttd_to_tto[i]; Engine *e = GetTempDataEngine(i); if (oi == 255) { /* Default engine is used */ _date += DAYS_TILL_ORIGINAL_BASE_YEAR; StartupOneEngine(e, aging_date); e->intro_date -= DAYS_TILL_ORIGINAL_BASE_YEAR; _date -= DAYS_TILL_ORIGINAL_BASE_YEAR; /* Make sure for example monorail and maglev are available when they should be */ if (_date >= e->intro_date && HasBit(e->info.climates, 0)) { e->flags |= ENGINE_AVAILABLE; e->company_avail = (CompanyMask)0xFF; e->age = _date > e->intro_date ? (_date - e->intro_date) / 30 : 0; } } else { /* Using data from TTO savegame */ Engine *oe = &_old_engines[oi]; e->intro_date = oe->intro_date; e->age = oe->age; e->reliability = oe->reliability; e->reliability_spd_dec = oe->reliability_spd_dec; e->reliability_start = oe->reliability_start; e->reliability_max = oe->reliability_max; e->reliability_final = oe->reliability_final; e->duration_phase_1 = oe->duration_phase_1; e->duration_phase_2 = oe->duration_phase_2; e->duration_phase_3 = oe->duration_phase_3; e->flags = oe->flags; e->company_avail = 0; /* One or more engines were remapped to this one. Make this engine available * if at least one of them was available. */ for (uint j = 0; j < lengthof(tto_to_ttd); j++) { if (tto_to_ttd[j] == i && _old_engines[j].company_avail != 0) { e->company_avail = (CompanyMask)0xFF; e->flags |= ENGINE_AVAILABLE; break; } } e->info.climates = 1; } e->preview_company = INVALID_COMPANY; e->preview_asked = (CompanyMask)-1; e->preview_wait = 0; e->name = NULL; } return true; } static void FixTTOCompanies() { Company *c; FOR_ALL_COMPANIES(c) { c->cur_economy.company_value = CalculateCompanyValue(c); // company value history is zeroed } } static inline byte RemapTTOColour(byte tto) { /** Lossy remapping of TTO colours to TTD colours. SVXConverter uses the same conversion. */ static const byte tto_colour_remap[] = { COLOUR_DARK_BLUE, COLOUR_GREY, COLOUR_YELLOW, COLOUR_RED, COLOUR_PURPLE, COLOUR_DARK_GREEN, COLOUR_ORANGE, COLOUR_PALE_GREEN, COLOUR_BLUE, COLOUR_GREEN, COLOUR_CREAM, COLOUR_BROWN, COLOUR_WHITE, COLOUR_LIGHT_BLUE, COLOUR_MAUVE, COLOUR_PINK }; if ((size_t)tto >= lengthof(tto_colour_remap)) return COLOUR_GREY; // this shouldn't happen return tto_colour_remap[tto]; } static inline uint RemapTownIndex(uint x) { return _savegame_type == SGT_TTO ? (x - 0x264) / 78 : (x - 0x264) / 94; } static inline uint RemapOrderIndex(uint x) { return _savegame_type == SGT_TTO ? (x - 0x1AC4) / 2 : (x - 0x1C18) / 2; } extern TileIndex *_animated_tile_list; extern uint _animated_tile_count; extern char *_old_name_array; static uint32 _old_town_index; static uint16 _old_string_id; static uint16 _old_string_id_2; static void ReadTTDPatchFlags() { if (_read_ttdpatch_flags) return; _read_ttdpatch_flags = true; /* Set default values */ _old_vehicle_multiplier = 1; _ttdp_version = 0; _old_extra_chunk_nums = 0; _bump_assert_value = 0; if (_savegame_type == SGT_TTO) return; /* TTDPatch misuses _old_map3 for flags.. read them! */ _old_vehicle_multiplier = _old_map3[0]; /* Somehow.... there was an error in some savegames, so 0 becomes 1 * and 1 becomes 2. The rest of the values are okay */ if (_old_vehicle_multiplier < 2) _old_vehicle_multiplier++; _old_vehicle_names = MallocT(_old_vehicle_multiplier * 850); /* TTDPatch increases the Vehicle-part in the middle of the game, * so if the multiplier is anything else but 1, the assert fails.. * bump the assert value so it doesn't! * (1 multiplier == 850 vehicles * 1 vehicle == 128 bytes */ _bump_assert_value = (_old_vehicle_multiplier - 1) * 850 * 128; for (uint i = 0; i < 17; i++) { // check tile 0, too if (_old_map3[i] != 0) _savegame_type = SGT_TTDP1; } /* Check if we have a modern TTDPatch savegame (has extra data all around) */ if (memcmp(&_old_map3[0x1FFFA], "TTDp", 4) == 0) _savegame_type = SGT_TTDP2; _old_extra_chunk_nums = _old_map3[_savegame_type == SGT_TTDP2 ? 0x1FFFE : 0x2]; /* Clean the misused places */ for (uint i = 0; i < 17; i++) _old_map3[i] = 0; for (uint i = 0x1FE00; i < 0x20000; i++) _old_map3[i] = 0; if (_savegame_type == SGT_TTDP2) DEBUG(oldloader, 2, "Found TTDPatch game"); DEBUG(oldloader, 3, "Vehicle-multiplier is set to %d (%d vehicles)", _old_vehicle_multiplier, _old_vehicle_multiplier * 850); } static const OldChunks town_chunk[] = { OCL_SVAR( OC_TILE, Town, xy ), OCL_NULL( 2 ), ///< population, no longer in use OCL_SVAR( OC_UINT16, Town, townnametype ), OCL_SVAR( OC_UINT32, Town, townnameparts ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Town, grow_counter ), OCL_NULL( 1 ), ///< sort_index, no longer in use OCL_NULL( 4 ), ///< sign-coordinates, no longer in use OCL_NULL( 2 ), ///< namewidth, no longer in use OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Town, flags ), OCL_NULL( 10 ), ///< radius, no longer in use OCL_SVAR( OC_INT16, Town, ratings[0] ), OCL_SVAR( OC_INT16, Town, ratings[1] ), OCL_SVAR( OC_INT16, Town, ratings[2] ), OCL_SVAR( OC_INT16, Town, ratings[3] ), OCL_SVAR( OC_INT16, Town, ratings[4] ), OCL_SVAR( OC_INT16, Town, ratings[5] ), OCL_SVAR( OC_INT16, Town, ratings[6] ), OCL_SVAR( OC_INT16, Town, ratings[7] ), OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Town, have_ratings ), OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Town, statues ), OCL_NULL( 2 ), ///< num_houses, no longer in use OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Town, time_until_rebuild ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Town, growth_rate ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_PASSENGERS].new_max ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_MAIL].new_max ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_PASSENGERS].new_act ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_MAIL].new_act ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_PASSENGERS].old_max ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_MAIL].old_max ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_PASSENGERS].old_act ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Town, supplied[CT_MAIL].old_act ), OCL_NULL( 2 ), ///< pct_pass_transported / pct_mail_transported, now computed on the fly OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].new_act ), OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].new_act ), OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_FOOD].old_act ), OCL_SVAR( OC_TTD | OC_UINT16, Town, received[TE_WATER].old_act ), OCL_SVAR( OC_UINT8, Town, road_build_months ), OCL_SVAR( OC_UINT8, Town, fund_buildings_months ), OCL_CNULL( OC_TTD, 8 ), ///< some junk at the end of the record OCL_END() }; static bool LoadOldTown(LoadgameState *ls, int num) { Town *t = new (num) Town(); if (!LoadChunk(ls, t, town_chunk)) return false; if (t->xy != 0) { if (_savegame_type == SGT_TTO) { /* 0x10B6 is auto-generated name, others are custom names */ t->townnametype = t->townnametype == 0x10B6 ? 0x20C1 : t->townnametype + 0x2A00; } } else { delete t; } return true; } static uint16 _old_order; static const OldChunks order_chunk[] = { OCL_VAR ( OC_UINT16, 1, &_old_order ), OCL_END() }; static bool LoadOldOrder(LoadgameState *ls, int num) { if (!LoadChunk(ls, NULL, order_chunk)) return false; Order *o = new (num) Order(); o->AssignOrder(UnpackOldOrder(_old_order)); if (o->IsType(OT_NOTHING)) { delete o; } else { /* Relink the orders to each other (in the orders for one vehicle are behind each other, * with an invalid order (OT_NOTHING) as indication that it is the last order */ Order *prev = Order::GetIfValid(num - 1); if (prev != NULL) prev->next = o; } return true; } static bool LoadOldAnimTileList(LoadgameState *ls, int num) { /* This is slightly hackish - we must load a chunk into an array whose * address isn't static, but instead pointed to by _animated_tile_list. * To achieve that, create an OldChunks list on the stack on the fly. * The list cannot be static because the value of _animated_tile_list * can change between calls. */ const OldChunks anim_chunk[] = { OCL_VAR ( OC_TILE, 256, _animated_tile_list ), OCL_END () }; if (!LoadChunk(ls, NULL, anim_chunk)) return false; /* Update the animated tile counter by counting till the first zero in the array */ for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { if (_animated_tile_list[_animated_tile_count] == 0) break; } return true; } static const OldChunks depot_chunk[] = { OCL_SVAR( OC_TILE, Depot, xy ), OCL_VAR ( OC_UINT32, 1, &_old_town_index ), OCL_END() }; static bool LoadOldDepot(LoadgameState *ls, int num) { Depot *d = new (num) Depot(); if (!LoadChunk(ls, d, depot_chunk)) return false; if (d->xy != 0) { /* In some cases, there could be depots referencing invalid town. */ Town *t = Town::GetIfValid(RemapTownIndex(_old_town_index)); if (t == NULL) t = Town::GetRandom(); d->town = t; } else { delete d; } return true; } static StationID _current_station_id; static uint16 _waiting_acceptance; static uint8 _cargo_source; static uint8 _cargo_days; static const OldChunks goods_chunk[] = { OCL_VAR ( OC_UINT16, 1, &_waiting_acceptance ), OCL_SVAR( OC_UINT8, GoodsEntry, time_since_pickup ), OCL_SVAR( OC_UINT8, GoodsEntry, rating ), OCL_VAR ( OC_UINT8, 1, &_cargo_source ), OCL_VAR ( OC_UINT8, 1, &_cargo_days ), OCL_SVAR( OC_UINT8, GoodsEntry, last_speed ), OCL_SVAR( OC_UINT8, GoodsEntry, last_age ), OCL_END() }; static bool LoadOldGood(LoadgameState *ls, int num) { /* for TTO games, 12th (num == 11) goods entry is created in the Station constructor */ if (_savegame_type == SGT_TTO && num == 11) return true; Station *st = Station::Get(_current_station_id); GoodsEntry *ge = &st->goods[num]; if (!LoadChunk(ls, ge, goods_chunk)) return false; SB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); SB(ge->status, GoodsEntry::GES_RATING, 1, _cargo_source != 0xFF); if (GB(_waiting_acceptance, 0, 12) != 0 && CargoPacket::CanAllocateItem()) { ge->cargo.Append(new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, 0, 0), INVALID_STATION); } return true; } static const OldChunks station_chunk[] = { OCL_SVAR( OC_TILE, Station, xy ), OCL_VAR ( OC_UINT32, 1, &_old_town_index ), OCL_NULL( 4 ), ///< bus/lorry tile OCL_SVAR( OC_TILE, Station, train_station.tile ), OCL_SVAR( OC_TILE, Station, airport.tile ), OCL_SVAR( OC_TILE, Station, dock_tile ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Station, train_station.w ), OCL_NULL( 1 ), ///< sort-index, no longer in use OCL_NULL( 2 ), ///< sign-width, no longer in use OCL_VAR ( OC_UINT16, 1, &_old_string_id ), OCL_NULL( 4 ), ///< sign left/top, no longer in use OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Station, had_vehicle_of_type ), OCL_CHUNK( 12, LoadOldGood ), OCL_SVAR( OC_UINT8, Station, time_since_load ), OCL_SVAR( OC_UINT8, Station, time_since_unload ), OCL_SVAR( OC_UINT8, Station, delete_ctr ), OCL_SVAR( OC_UINT8, Station, owner ), OCL_SVAR( OC_UINT8, Station, facilities ), OCL_SVAR( OC_TTD | OC_UINT8, Station, airport.type ), OCL_SVAR( OC_TTO | OC_FILE_U16 | OC_VAR_U64, Station, airport.flags ), OCL_NULL( 3 ), ///< bus/truck status, blocked months, no longer in use OCL_CNULL( OC_TTD, 1 ), ///< unknown OCL_SVAR( OC_TTD | OC_FILE_U16 | OC_VAR_U64, Station, airport.flags ), OCL_CNULL( OC_TTD, 2 ), ///< last_vehicle. now last_vehicle_type OCL_CNULL( OC_TTD, 4 ), ///< junk at end of chunk OCL_END() }; static bool LoadOldStation(LoadgameState *ls, int num) { Station *st = new (num) Station(); _current_station_id = num; if (!LoadChunk(ls, st, station_chunk)) return false; if (st->xy != 0) { st->town = Town::Get(RemapTownIndex(_old_town_index)); if (_savegame_type == SGT_TTO) { if (IsInsideBS(_old_string_id, 0x180F, 32)) { st->string_id = STR_SV_STNAME + (_old_string_id - 0x180F); // automatic name } else { st->string_id = _old_string_id + 0x2800; // custom name } if (HasBit(st->airport.flags, 8)) { st->airport.type = 1; // large airport } else if (HasBit(st->airport.flags, 6)) { st->airport.type = 3; // oil rig } else { st->airport.type = 0; // small airport } } else { st->string_id = RemapOldStringID(_old_string_id); } } else { delete st; } return true; } static const OldChunks industry_chunk[] = { OCL_SVAR( OC_TILE, Industry, location.tile ), OCL_VAR ( OC_UINT32, 1, &_old_town_index ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Industry, location.w ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Industry, location.h ), OCL_NULL( 2 ), ///< used to be industry's produced_cargo OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced_cargo_waiting[0] ), OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced_cargo_waiting[1] ), OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced_cargo_waiting[0] ), OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced_cargo_waiting[1] ), OCL_SVAR( OC_UINT8, Industry, production_rate[0] ), OCL_SVAR( OC_UINT8, Industry, production_rate[1] ), OCL_NULL( 3 ), ///< used to be industry's accepts_cargo OCL_SVAR( OC_UINT8, Industry, prod_level ), OCL_SVAR( OC_UINT16, Industry, this_month_production[0] ), OCL_SVAR( OC_UINT16, Industry, this_month_production[1] ), OCL_SVAR( OC_UINT16, Industry, this_month_transported[0] ), OCL_SVAR( OC_UINT16, Industry, this_month_transported[1] ), OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[0] ), OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[1] ), OCL_SVAR( OC_UINT16, Industry, last_month_production[0] ), OCL_SVAR( OC_UINT16, Industry, last_month_production[1] ), OCL_SVAR( OC_UINT16, Industry, last_month_transported[0] ), OCL_SVAR( OC_UINT16, Industry, last_month_transported[1] ), OCL_SVAR( OC_UINT8, Industry, type ), OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, counter ), OCL_SVAR( OC_UINT8, Industry, owner ), OCL_SVAR( OC_UINT8, Industry, random_colour ), OCL_SVAR( OC_TTD | OC_FILE_U8 | OC_VAR_I32, Industry, last_prod_year ), OCL_SVAR( OC_TTD | OC_UINT16, Industry, counter ), OCL_SVAR( OC_TTD | OC_UINT8, Industry, was_cargo_delivered ), OCL_CNULL( OC_TTD, 9 ), ///< Random junk at the end of this chunk OCL_END() }; static bool LoadOldIndustry(LoadgameState *ls, int num) { Industry *i = new (num) Industry(); if (!LoadChunk(ls, i, industry_chunk)) return false; if (i->location.tile != 0) { i->town = Town::Get(RemapTownIndex(_old_town_index)); if (_savegame_type == SGT_TTO) { if (i->type > 0x06) i->type++; // Printing Works were added if (i->type == 0x0A) i->type = 0x12; // Iron Ore Mine has different ID YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); i->last_prod_year = ymd.year; i->random_colour = RemapTTOColour(i->random_colour); } Industry::IncIndustryTypeCount(i->type); } else { delete i; } return true; } static CompanyID _current_company_id; static int32 _old_yearly; static const OldChunks _company_yearly_chunk[] = { OCL_VAR( OC_INT32, 1, &_old_yearly ), OCL_END() }; static bool LoadOldCompanyYearly(LoadgameState *ls, int num) { Company *c = Company::Get(_current_company_id); for (uint i = 0; i < 13; i++) { if (_savegame_type == SGT_TTO && i == 6) { _old_yearly = 0; // property maintenance } else { if (!LoadChunk(ls, NULL, _company_yearly_chunk)) return false; } c->yearly_expenses[num][i] = _old_yearly; } return true; } static const OldChunks _company_economy_chunk[] = { OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, CompanyEconomyEntry, income ), OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, CompanyEconomyEntry, expenses ), OCL_SVAR( OC_INT32, CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1] ), OCL_SVAR( OC_INT32, CompanyEconomyEntry, performance_history ), OCL_SVAR( OC_TTD | OC_FILE_I32 | OC_VAR_I64, CompanyEconomyEntry, company_value ), OCL_END() }; static bool LoadOldCompanyEconomy(LoadgameState *ls, int num) { Company *c = Company::Get(_current_company_id); if (!LoadChunk(ls, &c->cur_economy, _company_economy_chunk)) return false; /* Don't ask, but the number in TTD(Patch) are inversed to OpenTTD */ c->cur_economy.income = -c->cur_economy.income; c->cur_economy.expenses = -c->cur_economy.expenses; for (uint i = 0; i < 24; i++) { if (!LoadChunk(ls, &c->old_economy[i], _company_economy_chunk)) return false; c->old_economy[i].income = -c->old_economy[i].income; c->old_economy[i].expenses = -c->old_economy[i].expenses; } return true; } static const OldChunks _company_chunk[] = { OCL_VAR ( OC_UINT16, 1, &_old_string_id ), OCL_SVAR( OC_UINT32, Company, name_2 ), OCL_SVAR( OC_UINT32, Company, face ), OCL_VAR ( OC_UINT16, 1, &_old_string_id_2 ), OCL_SVAR( OC_UINT32, Company, president_name_2 ), OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Company, money ), OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Company, current_loan ), OCL_SVAR( OC_UINT8, Company, colour ), OCL_SVAR( OC_UINT8, Company, money_fraction ), OCL_SVAR( OC_UINT8, Company, months_of_bankruptcy ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Company, bankrupt_asked ), OCL_SVAR( OC_FILE_U32 | OC_VAR_I64, Company, bankrupt_value ), OCL_SVAR( OC_UINT16, Company, bankrupt_timeout ), OCL_CNULL( OC_TTD, 4 ), // cargo_types OCL_CNULL( OC_TTO, 2 ), // cargo_types OCL_CHUNK( 3, LoadOldCompanyYearly ), OCL_CHUNK( 1, LoadOldCompanyEconomy ), OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Company, inaugurated_year), OCL_SVAR( OC_TILE, Company, last_build_coordinate ), OCL_SVAR( OC_UINT8, Company, num_valid_stat_ent ), OCL_NULL( 230 ), // Old AI OCL_SVAR( OC_UINT8, Company, block_preview ), OCL_CNULL( OC_TTD, 1 ), // Old AI OCL_SVAR( OC_TTD | OC_UINT8, Company, avail_railtypes ), OCL_SVAR( OC_TILE, Company, location_of_HQ ), OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[0] ), OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[1] ), OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[2] ), OCL_SVAR( OC_TTD | OC_UINT8, Company, share_owners[3] ), OCL_CNULL( OC_TTD, 8 ), ///< junk at end of chunk OCL_END() }; static bool LoadOldCompany(LoadgameState *ls, int num) { Company *c = new (num) Company(); _current_company_id = (CompanyID)num; if (!LoadChunk(ls, c, _company_chunk)) return false; if (_old_string_id == 0) { delete c; return true; } if (_savegame_type == SGT_TTO) { /* adjust manager's face */ if (HasBit(c->face, 27) && GB(c->face, 26, 1) == GB(c->face, 19, 1)) { /* if face would be black in TTD, adjust tie colour and thereby face colour */ ClrBit(c->face, 27); } /* Company name */ if (_old_string_id == 0 || _old_string_id == 0x4C00) { _old_string_id = STR_SV_UNNAMED; // "Unnamed" } else if (GB(_old_string_id, 8, 8) == 0x52) { _old_string_id += 0x2A00; // Custom name } else { _old_string_id = RemapOldStringID(_old_string_id += 0x240D); // Automatic name } c->name_1 = _old_string_id; /* Manager name */ switch (_old_string_id_2) { case 0x4CDA: _old_string_id_2 = SPECSTR_PRESIDENT_NAME; break; // automatic name case 0x0006: _old_string_id_2 = STR_SV_EMPTY; break; // empty name default: _old_string_id_2 = _old_string_id_2 + 0x2A00; break; // custom name } c->president_name_1 = _old_string_id_2; c->colour = RemapTTOColour(c->colour); if (num != 0) c->is_ai = true; } else { c->name_1 = RemapOldStringID(_old_string_id); c->president_name_1 = RemapOldStringID(_old_string_id_2); if (num == 0) { /* If the first company has no name, make sure we call it UNNAMED */ if (c->name_1 == 0) { c->name_1 = STR_SV_UNNAMED; } } else { /* Beside some multiplayer maps (1 on 1), which we don't official support, * all other companies are an AI.. mark them as such */ c->is_ai = true; } /* Sometimes it is better to not ask.. in old scenarios, the money * was always 893288 pounds. In the newer versions this is correct, * but correct for those oldies * Ps: this also means that if you had exact 893288 pounds, you will go back * to 100000.. this is a very VERY small chance ;) */ if (c->money == 893288) c->money = c->current_loan = 100000; } _company_colours[num] = (Colours)c->colour; c->inaugurated_year -= ORIGINAL_BASE_YEAR; return true; } static uint32 _old_order_ptr; static uint16 _old_next_ptr; static VehicleID _current_vehicle_id; static const OldChunks vehicle_train_chunk[] = { OCL_SVAR( OC_UINT8, Train, track ), OCL_SVAR( OC_UINT8, Train, force_proceed ), OCL_SVAR( OC_UINT16, Train, crash_anim_pos ), OCL_SVAR( OC_UINT8, Train, railtype ), OCL_NULL( 5 ), ///< Junk OCL_END() }; static const OldChunks vehicle_road_chunk[] = { OCL_SVAR( OC_UINT8, RoadVehicle, state ), OCL_SVAR( OC_UINT8, RoadVehicle, frame ), OCL_SVAR( OC_UINT16, RoadVehicle, blocked_ctr ), OCL_SVAR( OC_UINT8, RoadVehicle, overtaking ), OCL_SVAR( OC_UINT8, RoadVehicle, overtaking_ctr ), OCL_SVAR( OC_UINT16, RoadVehicle, crashed_ctr ), OCL_SVAR( OC_UINT8, RoadVehicle, reverse_ctr ), OCL_NULL( 1 ), ///< Junk OCL_END() }; static const OldChunks vehicle_ship_chunk[] = { OCL_SVAR( OC_UINT8, Ship, state ), OCL_NULL( 9 ), ///< Junk OCL_END() }; static const OldChunks vehicle_air_chunk[] = { OCL_SVAR( OC_UINT8, Aircraft, pos ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Aircraft, targetairport ), OCL_SVAR( OC_UINT16, Aircraft, crashed_counter ), OCL_SVAR( OC_UINT8, Aircraft, state ), OCL_NULL( 5 ), ///< Junk OCL_END() }; static const OldChunks vehicle_effect_chunk[] = { OCL_SVAR( OC_UINT16, EffectVehicle, animation_state ), OCL_SVAR( OC_UINT8, EffectVehicle, animation_substate ), OCL_NULL( 7 ), // Junk OCL_END() }; static const OldChunks vehicle_disaster_chunk[] = { OCL_SVAR( OC_UINT16, DisasterVehicle, image_override ), OCL_SVAR( OC_UINT16, DisasterVehicle, big_ufo_destroyer_target ), OCL_NULL( 6 ), ///< Junk OCL_END() }; static const OldChunks vehicle_empty_chunk[] = { OCL_NULL( 10 ), ///< Junk OCL_END() }; static bool LoadOldVehicleUnion(LoadgameState *ls, int num) { Vehicle *v = Vehicle::GetIfValid(_current_vehicle_id); uint temp = ls->total_read; bool res; if (v == NULL) { res = LoadChunk(ls, NULL, vehicle_empty_chunk); } else { switch (v->type) { default: SlErrorCorrupt("Invalid vehicle type"); case VEH_TRAIN : res = LoadChunk(ls, v, vehicle_train_chunk); break; case VEH_ROAD : res = LoadChunk(ls, v, vehicle_road_chunk); break; case VEH_SHIP : res = LoadChunk(ls, v, vehicle_ship_chunk); break; case VEH_AIRCRAFT: res = LoadChunk(ls, v, vehicle_air_chunk); break; case VEH_EFFECT : res = LoadChunk(ls, v, vehicle_effect_chunk); break; case VEH_DISASTER: res = LoadChunk(ls, v, vehicle_disaster_chunk); break; } } /* This chunk size should always be 10 bytes */ if (ls->total_read - temp != 10) { DEBUG(oldloader, 0, "Assert failed in VehicleUnion: invalid chunk size"); return false; } return res; } static uint16 _cargo_count; static const OldChunks vehicle_chunk[] = { OCL_SVAR( OC_UINT8, Vehicle, subtype ), OCL_NULL( 2 ), ///< Hash, calculated automatically OCL_NULL( 2 ), ///< Index, calculated automatically OCL_VAR ( OC_UINT32, 1, &_old_order_ptr ), OCL_VAR ( OC_UINT16, 1, &_old_order ), OCL_NULL ( 1 ), ///< num_orders, now calculated OCL_SVAR( OC_UINT8, Vehicle, cur_implicit_order_index ), OCL_SVAR( OC_TILE, Vehicle, dest_tile ), OCL_SVAR( OC_UINT16, Vehicle, load_unload_ticks ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, date_of_last_service ), OCL_SVAR( OC_UINT16, Vehicle, service_interval ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, last_station_visited ), OCL_SVAR( OC_TTD | OC_UINT8, Vehicle, tick_counter ), OCL_CNULL( OC_TTD, 2 ), ///< max_speed, now it is calculated. OCL_CNULL( OC_TTO, 1 ), ///< max_speed, now it is calculated. OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, x_pos ), OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Vehicle, y_pos ), OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Vehicle, z_pos ), OCL_SVAR( OC_UINT8, Vehicle, direction ), OCL_NULL( 2 ), ///< x_offs and y_offs, calculated automatically OCL_NULL( 2 ), ///< x_extent and y_extent, calculated automatically OCL_NULL( 1 ), ///< z_extent, calculated automatically OCL_SVAR( OC_UINT8, Vehicle, owner ), OCL_SVAR( OC_TILE, Vehicle, tile ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, cur_image ), OCL_NULL( 8 ), ///< Vehicle sprite box, calculated automatically OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, Vehicle, vehstatus ), OCL_SVAR( OC_TTD | OC_UINT16, Vehicle, cur_speed ), OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Vehicle, cur_speed ), OCL_SVAR( OC_UINT8, Vehicle, subspeed ), OCL_SVAR( OC_UINT8, Vehicle, acceleration ), OCL_SVAR( OC_UINT8, Vehicle, progress ), OCL_SVAR( OC_UINT8, Vehicle, cargo_type ), OCL_SVAR( OC_TTD | OC_UINT16, Vehicle, cargo_cap ), OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Vehicle, cargo_cap ), OCL_VAR ( OC_TTD | OC_UINT16, 1, &_cargo_count ), OCL_VAR ( OC_TTO | OC_FILE_U8 | OC_VAR_U16, 1, &_cargo_count ), OCL_VAR ( OC_UINT8, 1, &_cargo_source ), OCL_VAR ( OC_UINT8, 1, &_cargo_days ), OCL_SVAR( OC_TTO | OC_UINT8, Vehicle, tick_counter ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, age ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, max_age ), OCL_SVAR( OC_FILE_U8 | OC_VAR_I32, Vehicle, build_year ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, unitnumber ), OCL_SVAR( OC_TTD | OC_UINT16, Vehicle, engine_type ), OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Vehicle, engine_type ), OCL_SVAR( OC_UINT8, Vehicle, spritenum ), OCL_SVAR( OC_UINT8, Vehicle, day_counter ), OCL_SVAR( OC_UINT8, Vehicle, breakdowns_since_last_service ), OCL_SVAR( OC_UINT8, Vehicle, breakdown_ctr ), OCL_SVAR( OC_UINT8, Vehicle, breakdown_delay ), OCL_SVAR( OC_UINT8, Vehicle, breakdown_chance ), OCL_CNULL( OC_TTO, 1 ), OCL_SVAR( OC_UINT16, Vehicle, reliability ), OCL_SVAR( OC_UINT16, Vehicle, reliability_spd_dec ), OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_this_year ), OCL_SVAR( OC_FILE_I32 | OC_VAR_I64, Vehicle, profit_last_year ), OCL_VAR ( OC_UINT16, 1, &_old_next_ptr ), OCL_SVAR( OC_FILE_U32 | OC_VAR_I64, Vehicle, value ), OCL_VAR ( OC_UINT16, 1, &_old_string_id ), OCL_CHUNK( 1, LoadOldVehicleUnion ), OCL_CNULL( OC_TTO, 24 ), ///< junk OCL_CNULL( OC_TTD, 20 ), ///< junk at end of struct (TTDPatch has some data in it) OCL_END() }; /** * Load the vehicles of an old style savegame. * @param ls State (buffer) of the currently loaded game. * @param num The number of vehicles to load. * @return True iff loading went without problems. */ bool LoadOldVehicle(LoadgameState *ls, int num) { /* Read the TTDPatch flags, because we need some info from it */ ReadTTDPatchFlags(); for (uint i = 0; i < _old_vehicle_multiplier; i++) { _current_vehicle_id = num * _old_vehicle_multiplier + i; Vehicle *v; if (_savegame_type == SGT_TTO) { uint type = ReadByte(ls); switch (type) { default: return false; case 0x00 /* VEH_INVALID */: v = NULL; break; case 0x25 /* MONORAIL */: case 0x20 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break; case 0x21 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break; case 0x22 /* VEH_SHIP */: v = new (_current_vehicle_id) Ship(); break; case 0x23 /* VEH_AIRCRAFT */: v = new (_current_vehicle_id) Aircraft(); break; case 0x24 /* VEH_EFFECT */: v = new (_current_vehicle_id) EffectVehicle(); break; case 0x26 /* VEH_DISASTER */: v = new (_current_vehicle_id) DisasterVehicle(); break; } if (!LoadChunk(ls, v, vehicle_chunk)) return false; if (v == NULL) continue; v->refit_cap = v->cargo_cap; SpriteID sprite = v->cur_image; /* no need to override other sprites */ if (IsInsideMM(sprite, 1460, 1465)) { sprite += 580; // aircraft smoke puff } else if (IsInsideMM(sprite, 2096, 2115)) { sprite += 977; // special effects part 1 } else if (IsInsideMM(sprite, 2396, 2436)) { sprite += 1305; // special effects part 2 } else if (IsInsideMM(sprite, 2516, 2539)) { sprite += 1385; // rotor or disaster-related vehicles } v->cur_image = sprite; switch (v->type) { case VEH_TRAIN: { static const byte spriteset_rail[] = { 0, 2, 4, 4, 8, 10, 12, 14, 16, 18, 20, 22, 40, 42, 44, 46, 48, 52, 54, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140 }; if (v->spritenum / 2 >= lengthof(spriteset_rail)) return false; v->spritenum = spriteset_rail[v->spritenum / 2]; // adjust railway sprite set offset Train::From(v)->railtype = type == 0x25 ? 1 : 0; // monorail / rail break; } case VEH_ROAD: if (v->spritenum >= 22) v->spritenum += 12; break; case VEH_SHIP: v->spritenum += 2; switch (v->spritenum) { case 2: // oil tanker && cargo type != oil if (v->cargo_type != CT_OIL) v->spritenum = 0; // make it a coal/goods ship break; case 4: // passenger ship && cargo type == mail if (v->cargo_type == CT_MAIL) v->spritenum = 0; // make it a mail ship break; default: break; } break; default: break; } switch (_old_string_id) { case 0x0000: break; // empty (invalid vehicles) case 0x0006: _old_string_id = STR_SV_EMPTY; break; // empty (special vehicles) case 0x8495: _old_string_id = STR_SV_TRAIN_NAME; break; // "Train X" case 0x8842: _old_string_id = STR_SV_ROAD_VEHICLE_NAME; break; // "Road Vehicle X" case 0x8C3B: _old_string_id = STR_SV_SHIP_NAME; break; // "Ship X" case 0x9047: _old_string_id = STR_SV_AIRCRAFT_NAME; break; // "Aircraft X" default: _old_string_id += 0x2A00; break; // custom name } _old_vehicle_names[_current_vehicle_id] = _old_string_id; } else { /* Read the vehicle type and allocate the right vehicle */ switch (ReadByte(ls)) { default: SlErrorCorrupt("Invalid vehicle type"); case 0x00 /* VEH_INVALID */: v = NULL; break; case 0x10 /* VEH_TRAIN */: v = new (_current_vehicle_id) Train(); break; case 0x11 /* VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break; case 0x12 /* VEH_SHIP */: v = new (_current_vehicle_id) Ship(); break; case 0x13 /* VEH_AIRCRAFT*/: v = new (_current_vehicle_id) Aircraft(); break; case 0x14 /* VEH_EFFECT */: v = new (_current_vehicle_id) EffectVehicle(); break; case 0x15 /* VEH_DISASTER*/: v = new (_current_vehicle_id) DisasterVehicle(); break; } if (!LoadChunk(ls, v, vehicle_chunk)) return false; if (v == NULL) continue; _old_vehicle_names[_current_vehicle_id] = RemapOldStringID(_old_string_id); /* This should be consistent, else we have a big problem... */ if (v->index != _current_vehicle_id) { DEBUG(oldloader, 0, "Loading failed - vehicle-array is invalid"); return false; } } if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) { uint max = _savegame_type == SGT_TTO ? 3000 : 5000; uint old_id = RemapOrderIndex(_old_order_ptr); if (old_id < max) v->orders.old = Order::Get(old_id); // don't accept orders > max number of orders } v->current_order.AssignOrder(UnpackOldOrder(_old_order)); v->next = (Vehicle *)(size_t)_old_next_ptr; if (_cargo_count != 0 && CargoPacket::CanAllocateItem()) { StationID source = (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; TileIndex source_xy = (source != INVALID_STATION) ? Station::Get(source)->xy : 0; v->cargo.Append(new CargoPacket(_cargo_count, _cargo_days, source, source_xy, source_xy)); } } return true; } static const OldChunks sign_chunk[] = { OCL_VAR ( OC_UINT16, 1, &_old_string_id ), OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, x ), OCL_SVAR( OC_FILE_U16 | OC_VAR_I32, Sign, y ), OCL_SVAR( OC_FILE_U16 | OC_VAR_I8, Sign, z ), OCL_NULL( 6 ), ///< Width of sign, no longer in use OCL_END() }; static bool LoadOldSign(LoadgameState *ls, int num) { Sign *si = new (num) Sign(); if (!LoadChunk(ls, si, sign_chunk)) return false; if (_old_string_id != 0) { if (_savegame_type == SGT_TTO) { if (_old_string_id != 0x140A) si->name = CopyFromOldName(_old_string_id + 0x2A00); } else { si->name = CopyFromOldName(RemapOldStringID(_old_string_id)); } si->owner = OWNER_NONE; } else { delete si; } return true; } static const OldChunks engine_chunk[] = { OCL_SVAR( OC_UINT16, Engine, company_avail ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, intro_date ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Engine, age ), OCL_SVAR( OC_UINT16, Engine, reliability ), OCL_SVAR( OC_UINT16, Engine, reliability_spd_dec ), OCL_SVAR( OC_UINT16, Engine, reliability_start ), OCL_SVAR( OC_UINT16, Engine, reliability_max ), OCL_SVAR( OC_UINT16, Engine, reliability_final ), OCL_SVAR( OC_UINT16, Engine, duration_phase_1 ), OCL_SVAR( OC_UINT16, Engine, duration_phase_2 ), OCL_SVAR( OC_UINT16, Engine, duration_phase_3 ), OCL_NULL( 1 ), // lifelength OCL_SVAR( OC_UINT8, Engine, flags ), OCL_NULL( 1 ), // preview_company_rank OCL_SVAR( OC_UINT8, Engine, preview_wait ), OCL_CNULL( OC_TTD, 2 ), ///< railtype + junk OCL_END() }; static bool LoadOldEngine(LoadgameState *ls, int num) { Engine *e = _savegame_type == SGT_TTO ? &_old_engines[num] : GetTempDataEngine(num); return LoadChunk(ls, e, engine_chunk); } static bool LoadOldEngineName(LoadgameState *ls, int num) { Engine *e = GetTempDataEngine(num); e->name = CopyFromOldName(RemapOldStringID(ReadUint16(ls))); return true; } static const OldChunks subsidy_chunk[] = { OCL_SVAR( OC_UINT8, Subsidy, cargo_type ), OCL_SVAR( OC_UINT8, Subsidy, remaining ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, src ), OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Subsidy, dst ), OCL_END() }; static bool LoadOldSubsidy(LoadgameState *ls, int num) { Subsidy *s = new (num) Subsidy(); bool ret = LoadChunk(ls, s, subsidy_chunk); if (s->cargo_type == CT_INVALID) delete s; return ret; } static const OldChunks game_difficulty_chunk[] = { OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, max_no_competitors ), OCL_NULL( 2), // competitor_start_time OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, number_towns ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, industry_density ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, DifficultySettings, max_loan ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, initial_interest ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, vehicle_costs ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, competitor_speed ), OCL_NULL( 2), // competitor_intelligence OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, vehicle_breakdowns ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, subsidy_multiplier ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, construction_cost ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, terrain_type ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, quantity_sea_lakes ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, economy ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, line_reverse_mode ), OCL_SVAR( OC_FILE_U16 | OC_VAR_U8, DifficultySettings, disasters ), OCL_END() }; static bool LoadOldGameDifficulty(LoadgameState *ls, int num) { bool ret = LoadChunk(ls, &_settings_game.difficulty, game_difficulty_chunk); _settings_game.difficulty.max_loan *= 1000; return ret; } static bool LoadOldMapPart1(LoadgameState *ls, int num) { if (_savegame_type == SGT_TTO) { MemSetT(_m, 0, OLD_MAP_SIZE); MemSetT(_me, 0, OLD_MAP_SIZE); } for (uint i = 0; i < OLD_MAP_SIZE; i++) { _m[i].m1 = ReadByte(ls); } for (uint i = 0; i < OLD_MAP_SIZE; i++) { _m[i].m2 = ReadByte(ls); } if (_savegame_type != SGT_TTO) { for (uint i = 0; i < OLD_MAP_SIZE; i++) { _old_map3[i * 2] = ReadByte(ls); _old_map3[i * 2 + 1] = ReadByte(ls); } for (uint i = 0; i < OLD_MAP_SIZE / 4; i++) { byte b = ReadByte(ls); _me[i * 4 + 0].m6 = GB(b, 0, 2); _me[i * 4 + 1].m6 = GB(b, 2, 2); _me[i * 4 + 2].m6 = GB(b, 4, 2); _me[i * 4 + 3].m6 = GB(b, 6, 2); } } return true; } static bool LoadOldMapPart2(LoadgameState *ls, int num) { uint i; for (i = 0; i < OLD_MAP_SIZE; i++) { _m[i].type = ReadByte(ls); } for (i = 0; i < OLD_MAP_SIZE; i++) { _m[i].m5 = ReadByte(ls); } return true; } static bool LoadTTDPatchExtraChunks(LoadgameState *ls, int num) { ReadTTDPatchFlags(); DEBUG(oldloader, 2, "Found %d extra chunk(s)", _old_extra_chunk_nums); for (int i = 0; i != _old_extra_chunk_nums; i++) { uint16 id = ReadUint16(ls); uint32 len = ReadUint32(ls); switch (id) { /* List of GRFIDs, used in the savegame. 0x8004 is the new ID * They are saved in a 'GRFID:4 active:1' format, 5 bytes for each entry */ case 0x2: case 0x8004: { /* Skip the first element: TTDP hack for the Action D special variables (FFFF0000 01) */ ReadUint32(ls); ReadByte(ls); len -= 5; ClearGRFConfigList(&_grfconfig); while (len != 0) { uint32 grfid = ReadUint32(ls); if (ReadByte(ls) == 1) { GRFConfig *c = new GRFConfig("TTDP game, no information"); c->ident.grfid = grfid; AppendToGRFConfigList(&_grfconfig, c); DEBUG(oldloader, 3, "TTDPatch game using GRF file with GRFID %0X", BSWAP32(c->ident.grfid)); } len -= 5; } /* Append static NewGRF configuration */ AppendStaticGRFConfigs(&_grfconfig); break; } /* TTDPatch version and configuration */ case 0x3: _ttdp_version = ReadUint32(ls); DEBUG(oldloader, 3, "Game saved with TTDPatch version %d.%d.%d r%d", GB(_ttdp_version, 24, 8), GB(_ttdp_version, 20, 4), GB(_ttdp_version, 16, 4), GB(_ttdp_version, 0, 16)); len -= 4; while (len-- != 0) ReadByte(ls); // skip the configuration break; default: DEBUG(oldloader, 4, "Skipping unknown extra chunk %X", id); while (len-- != 0) ReadByte(ls); break; } } return true; } extern TileIndex _cur_tileloop_tile; extern uint16 _disaster_delay; extern byte _trees_tick_ctr; extern byte _age_cargo_skip_counter; // From misc_sl.cpp extern uint8 _old_diff_level; extern uint8 _old_units; static const OldChunks main_chunk[] = { OCL_ASSERT( OC_TTD, 0 ), OCL_ASSERT( OC_TTO, 0 ), OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_date ), OCL_VAR ( OC_UINT16, 1, &_date_fract ), OCL_NULL( 600 ), ///< TextEffects OCL_VAR ( OC_UINT32, 2, &_random.state ), OCL_ASSERT( OC_TTD, 0x264 ), OCL_ASSERT( OC_TTO, 0x264 ), OCL_CCHUNK( OC_TTD, 70, LoadOldTown ), OCL_CCHUNK( OC_TTO, 80, LoadOldTown ), OCL_ASSERT( OC_TTD, 0x1C18 ), OCL_ASSERT( OC_TTO, 0x1AC4 ), OCL_CCHUNK( OC_TTD, 5000, LoadOldOrder ), OCL_CCHUNK( OC_TTO, 3000, LoadOldOrder ), OCL_ASSERT( OC_TTD, 0x4328 ), OCL_ASSERT( OC_TTO, 0x3234 ), OCL_CHUNK( 1, LoadOldAnimTileList ), OCL_NULL( 4 ), ///< old end-of-order-list-pointer, no longer in use OCL_ASSERT( OC_TTO, 0x3438 ), OCL_CCHUNK( OC_TTD, 255, LoadOldDepot ), OCL_CCHUNK( OC_TTO, 252, LoadOldDepot ), OCL_ASSERT( OC_TTD, 0x4B26 ), OCL_ASSERT( OC_TTO, 0x3A20 ), OCL_NULL( 4 ), ///< town counter, no longer in use OCL_NULL( 2 ), ///< timer_counter, no longer in use OCL_NULL( 2 ), ///< land_code, no longer in use OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_age_cargo_skip_counter ), OCL_VAR ( OC_UINT16, 1, &_tick_counter ), OCL_VAR ( OC_TILE, 1, &_cur_tileloop_tile ), OCL_ASSERT( OC_TTO, 0x3A2E ), OCL_CNULL( OC_TTO, 48 * 6 ), ///< prices OCL_CNULL( OC_TTD, 49 * 6 ), ///< prices OCL_ASSERT( OC_TTO, 0x3B4E ), OCL_CNULL( OC_TTO, 11 * 8 ), ///< cargo payment rates OCL_CNULL( OC_TTD, 12 * 8 ), ///< cargo payment rates OCL_ASSERT( OC_TTD, 0x4CBA ), OCL_ASSERT( OC_TTO, 0x3BA6 ), OCL_CHUNK( 1, LoadOldMapPart1 ), OCL_ASSERT( OC_TTD, 0x48CBA ), OCL_ASSERT( OC_TTO, 0x23BA6 ), OCL_CCHUNK( OC_TTD, 250, LoadOldStation ), OCL_CCHUNK( OC_TTO, 200, LoadOldStation ), OCL_ASSERT( OC_TTO, 0x29E16 ), OCL_CCHUNK( OC_TTD, 90, LoadOldIndustry ), OCL_CCHUNK( OC_TTO, 100, LoadOldIndustry ), OCL_ASSERT( OC_TTO, 0x2ADB6 ), OCL_CHUNK( 8, LoadOldCompany ), OCL_ASSERT( OC_TTD, 0x547F2 ), OCL_ASSERT( OC_TTO, 0x2C746 ), OCL_CCHUNK( OC_TTD, 850, LoadOldVehicle ), OCL_CCHUNK( OC_TTO, 800, LoadOldVehicle ), OCL_ASSERT( OC_TTD, 0x6F0F2 ), OCL_ASSERT( OC_TTO, 0x45746 ), OCL_VAR ( OC_TTD | OC_UINT8 | OC_DEREFERENCE_POINTER, 32 * 500, &_old_name_array ), OCL_VAR ( OC_TTO | OC_UINT8 | OC_DEREFERENCE_POINTER, 24 * 200, &_old_name_array ), OCL_ASSERT( OC_TTO, 0x46A06 ), OCL_NULL( 0x2000 ), ///< Old hash-table, no longer in use OCL_CHUNK( 40, LoadOldSign ), OCL_ASSERT( OC_TTO, 0x48C36 ), OCL_CCHUNK( OC_TTD, 256, LoadOldEngine ), OCL_CCHUNK( OC_TTO, 103, LoadOldEngine ), OCL_ASSERT( OC_TTO, 0x496AC ), OCL_NULL ( 2 ), // _vehicle_id_ctr_day OCL_CHUNK( 8, LoadOldSubsidy ), OCL_ASSERT( OC_TTO, 0x496CE ), OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_next_competitor_start ), OCL_CNULL( OC_TTO, 2 ), ///< available monorail bitmask OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_x ), OCL_VAR ( OC_FILE_I16 | OC_VAR_I32, 1, &_saved_scrollpos_y ), OCL_VAR ( OC_FILE_U16 | OC_VAR_U8, 1, &_saved_scrollpos_zoom ), OCL_NULL( 4 ), ///< max_loan OCL_VAR ( OC_FILE_U32 | OC_VAR_I64, 1, &_economy.old_max_loan_unround ), OCL_VAR ( OC_INT16, 1, &_economy.fluct ), OCL_VAR ( OC_UINT16, 1, &_disaster_delay ), OCL_ASSERT( OC_TTO, 0x496E4 ), OCL_CNULL( OC_TTD, 144 ), ///< cargo-stuff OCL_CCHUNK( OC_TTD, 256, LoadOldEngineName ), OCL_CNULL( OC_TTD, 144 ), ///< AI cargo-stuff OCL_NULL( 2 ), ///< Company indexes of companies, no longer in use OCL_NULL( 1 ), ///< Station tick counter, no longer in use OCL_VAR ( OC_UINT8, 1, &_settings_game.locale.currency ), OCL_VAR ( OC_UINT8, 1, &_old_units ), OCL_VAR ( OC_FILE_U8 | OC_VAR_U32, 1, &_cur_company_tick_index ), OCL_NULL( 2 ), ///< Date stuff, calculated automatically OCL_NULL( 8 ), ///< Company colours, calculated automatically OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount ), OCL_VAR ( OC_UINT8, 1, &_economy.infl_amount_pr ), OCL_VAR ( OC_UINT8, 1, &_economy.interest_rate ), OCL_NULL( 1 ), // available airports OCL_VAR ( OC_UINT8, 1, &_settings_game.vehicle.road_side ), OCL_VAR ( OC_UINT8, 1, &_settings_game.game_creation.town_name ), OCL_CHUNK( 1, LoadOldGameDifficulty ), OCL_ASSERT( OC_TTD, 0x77130 ), OCL_VAR ( OC_UINT8, 1, &_old_diff_level ), OCL_VAR ( OC_TTD | OC_UINT8, 1, &_settings_game.game_creation.landscape ), OCL_VAR ( OC_TTD | OC_UINT8, 1, &_trees_tick_ctr ), OCL_CNULL( OC_TTD, 1 ), ///< Custom vehicle types yes/no, no longer used OCL_VAR ( OC_TTD | OC_UINT8, 1, &_settings_game.game_creation.snow_line_height ), OCL_CNULL( OC_TTD, 32 ), ///< new_industry_randtable, no longer used (because of new design) OCL_CNULL( OC_TTD, 36 ), ///< cargo-stuff OCL_ASSERT( OC_TTD, 0x77179 ), OCL_ASSERT( OC_TTO, 0x4971D ), OCL_CHUNK( 1, LoadOldMapPart2 ), OCL_ASSERT( OC_TTD, 0x97179 ), OCL_ASSERT( OC_TTO, 0x6971D ), /* Below any (if available) extra chunks from TTDPatch can follow */ OCL_CHUNK(1, LoadTTDPatchExtraChunks), OCL_END() }; bool LoadTTDMain(LoadgameState *ls) { DEBUG(oldloader, 3, "Reading main chunk..."); _read_ttdpatch_flags = false; /* Load the biggest chunk */ SmallStackSafeStackAlloc map3; _old_map3 = map3.data; _old_vehicle_names = NULL; try { if (!LoadChunk(ls, NULL, main_chunk)) { DEBUG(oldloader, 0, "Loading failed"); free(_old_vehicle_names); return false; } } catch (...) { free(_old_vehicle_names); throw; } DEBUG(oldloader, 3, "Done, converting game data..."); FixTTDMapArray(); FixTTDDepots(); /* Fix some general stuff */ _settings_game.game_creation.landscape = _settings_game.game_creation.landscape & 0xF; /* Fix the game to be compatible with OpenTTD */ FixOldTowns(); FixOldVehicles(); /* We have a new difficulty setting */ _settings_game.difficulty.town_council_tolerance = Clamp(_old_diff_level, 0, 2); DEBUG(oldloader, 3, "Finished converting game data"); DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted"); free(_old_vehicle_names); return true; } bool LoadTTOMain(LoadgameState *ls) { DEBUG(oldloader, 3, "Reading main chunk..."); _read_ttdpatch_flags = false; SmallStackSafeStackAlloc engines; // we don't want to call Engine constructor here _old_engines = (Engine *)engines.data; SmallStackSafeStackAlloc vehnames; _old_vehicle_names = vehnames.data; /* Load the biggest chunk */ if (!LoadChunk(ls, NULL, main_chunk)) { DEBUG(oldloader, 0, "Loading failed"); return false; } DEBUG(oldloader, 3, "Done, converting game data..."); if (_settings_game.game_creation.town_name != 0) _settings_game.game_creation.town_name++; _settings_game.game_creation.landscape = 0; _trees_tick_ctr = 0xFF; if (!FixTTOMapArray() || !FixTTOEngines()) { DEBUG(oldloader, 0, "Conversion failed"); return false; } FixOldTowns(); FixOldVehicles(); FixTTOCompanies(); /* We have a new difficulty setting */ _settings_game.difficulty.town_council_tolerance = Clamp(_old_diff_level, 0, 2); /* SVXConverter about cargo payment rates correction: * "increase them to compensate for the faster time advance in TTD compared to TTO * which otherwise would cause much less income while the annual running costs of * the vehicles stay the same" */ _economy.inflation_payment = min(_economy.inflation_payment * 124 / 74, MAX_INFLATION); DEBUG(oldloader, 3, "Finished converting game data"); DEBUG(oldloader, 1, "TTO savegame successfully converted"); return true; } openttd-1.5.3/src/saveload/airport_sl.cpp0000644000000000000000000000236612627373446017167 0ustar rootroot/* $Id: airport_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 airport_sl.cpp Code handling saving and loading airport ids */ #include "../stdafx.h" #include "saveload.h" #include "newgrf_sl.h" #include "../safeguards.h" static void Save_APID() { Save_NewGRFMapping(_airport_mngr); } static void Load_APID() { Load_NewGRFMapping(_airport_mngr); } static void Save_ATID() { Save_NewGRFMapping(_airporttile_mngr); } static void Load_ATID() { Load_NewGRFMapping(_airporttile_mngr); } extern const ChunkHandler _airport_chunk_handlers[] = { { 'ATID', Save_ATID, Load_ATID, NULL, NULL, CH_ARRAY }, { 'APID', Save_APID, Load_APID, NULL, NULL, CH_ARRAY | CH_LAST }, }; openttd-1.5.3/src/saveload/labelmaps_sl.cpp0000644000000000000000000000630112627373446017440 0ustar rootroot/* $Id: labelmaps_sl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 labelmaps_sl.cpp Code handling saving and loading of rail type label mappings */ #include "../stdafx.h" #include "../station_map.h" #include "../tunnelbridge_map.h" #include "saveload.h" #include "../safeguards.h" static SmallVector _railtype_list; /** * Test if any saved rail type labels are different to the currently loaded * rail types, which therefore requires conversion. * @return true if (and only if) conversion due to rail type changes is needed. */ static bool NeedRailTypeConversion() { for (uint i = 0; i < _railtype_list.Length(); i++) { if ((RailType)i < RAILTYPE_END) { const RailtypeInfo *rti = GetRailTypeInfo((RailType)i); if (rti->label != _railtype_list[i]) return true; } else { if (_railtype_list[i] != 0) return true; } } /* No rail type conversion is necessary */ return false; } void AfterLoadLabelMaps() { if (NeedRailTypeConversion()) { SmallVector railtype_conversion_map; for (uint i = 0; i < _railtype_list.Length(); i++) { RailType r = GetRailTypeByLabel(_railtype_list[i]); if (r == INVALID_RAILTYPE) r = RAILTYPE_BEGIN; *railtype_conversion_map.Append() = r; } for (TileIndex t = 0; t < MapSize(); t++) { switch (GetTileType(t)) { case MP_RAILWAY: SetRailType(t, railtype_conversion_map[GetRailType(t)]); break; case MP_ROAD: if (IsLevelCrossing(t)) { SetRailType(t, railtype_conversion_map[GetRailType(t)]); } break; case MP_STATION: if (HasStationRail(t)) { SetRailType(t, railtype_conversion_map[GetRailType(t)]); } break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) { SetRailType(t, railtype_conversion_map[GetRailType(t)]); } break; default: break; } } } _railtype_list.Clear(); } /** Container for a label for SaveLoad system */ struct LabelObject { uint32 label; }; static const SaveLoad _label_object_desc[] = { SLE_VAR(LabelObject, label, SLE_UINT32), SLE_END(), }; static void Save_RAIL() { LabelObject lo; for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) { lo.label = GetRailTypeInfo(r)->label; SlSetArrayIndex(r); SlObject(&lo, _label_object_desc); } } static void Load_RAIL() { _railtype_list.Clear(); LabelObject lo; while (SlIterateArray() != -1) { SlObject(&lo, _label_object_desc); *_railtype_list.Append() = (RailTypeLabel)lo.label; } } extern const ChunkHandler _labelmaps_chunk_handlers[] = { { 'RAIL', Save_RAIL, Load_RAIL, NULL, NULL, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/company_sl.cpp0000644000000000000000000004707612627373446017164 0ustar rootroot/* $Id: company_sl.cpp 26590 2014-05-16 17:39:35Z rubidium $ */ /* * 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 company_sl.cpp Code handling saving and loading of company data */ #include "../stdafx.h" #include "../company_func.h" #include "../company_manager_face.h" #include "../fios.h" #include "../tunnelbridge_map.h" #include "../tunnelbridge.h" #include "../station_base.h" #include "saveload.h" #include "table/strings.h" #include "../safeguards.h" /** * Converts an old company manager's face format to the new company manager's face format * * Meaning of the bits in the old face (some bits are used in several times): * - 4 and 5: chin * - 6 to 9: eyebrows * - 10 to 13: nose * - 13 to 15: lips (also moustache for males) * - 16 to 19: hair * - 20 to 22: eye colour * - 20 to 27: tie, ear rings etc. * - 28 to 30: glasses * - 19, 26 and 27: race (bit 27 set and bit 19 equal to bit 26 = black, otherwise white) * - 31: gender (0 = male, 1 = female) * * @param face the face in the old format * @return the face in the new format */ CompanyManagerFace ConvertFromOldCompanyManagerFace(uint32 face) { CompanyManagerFace cmf = 0; GenderEthnicity ge = GE_WM; if (HasBit(face, 31)) SetBit(ge, GENDER_FEMALE); if (HasBit(face, 27) && (HasBit(face, 26) == HasBit(face, 19))) SetBit(ge, ETHNICITY_BLACK); SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, ge, ge); SetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge, GB(face, 28, 3) <= 1); SetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge, HasBit(ge, ETHNICITY_BLACK) ? 0 : ClampU(GB(face, 20, 3), 5, 7) - 5); SetCompanyManagerFaceBits(cmf, CMFV_CHIN, ge, ScaleCompanyManagerFaceValue(CMFV_CHIN, ge, GB(face, 4, 2))); SetCompanyManagerFaceBits(cmf, CMFV_EYEBROWS, ge, ScaleCompanyManagerFaceValue(CMFV_EYEBROWS, ge, GB(face, 6, 4))); SetCompanyManagerFaceBits(cmf, CMFV_HAIR, ge, ScaleCompanyManagerFaceValue(CMFV_HAIR, ge, GB(face, 16, 4))); SetCompanyManagerFaceBits(cmf, CMFV_JACKET, ge, ScaleCompanyManagerFaceValue(CMFV_JACKET, ge, GB(face, 20, 2))); SetCompanyManagerFaceBits(cmf, CMFV_COLLAR, ge, ScaleCompanyManagerFaceValue(CMFV_COLLAR, ge, GB(face, 22, 2))); SetCompanyManagerFaceBits(cmf, CMFV_GLASSES, ge, GB(face, 28, 1)); uint lips = GB(face, 10, 4); if (!HasBit(ge, GENDER_FEMALE) && lips < 4) { SetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge, true); SetCompanyManagerFaceBits(cmf, CMFV_MOUSTACHE, ge, max(lips, 1U) - 1); } else { if (!HasBit(ge, GENDER_FEMALE)) { lips = lips * 15 / 16; lips -= 3; if (HasBit(ge, ETHNICITY_BLACK) && lips > 8) lips = 0; } else { lips = ScaleCompanyManagerFaceValue(CMFV_LIPS, ge, lips); } SetCompanyManagerFaceBits(cmf, CMFV_LIPS, ge, lips); uint nose = GB(face, 13, 3); if (ge == GE_WF) { nose = (nose * 3 >> 3) * 3 >> 2; // There is 'hole' in the nose sprites for females } else { nose = ScaleCompanyManagerFaceValue(CMFV_NOSE, ge, nose); } SetCompanyManagerFaceBits(cmf, CMFV_NOSE, ge, nose); } uint tie_earring = GB(face, 24, 4); if (!HasBit(ge, GENDER_FEMALE) || tie_earring < 3) { // Not all females have an earring if (HasBit(ge, GENDER_FEMALE)) SetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge, true); SetCompanyManagerFaceBits(cmf, CMFV_TIE_EARRING, ge, HasBit(ge, GENDER_FEMALE) ? tie_earring : ScaleCompanyManagerFaceValue(CMFV_TIE_EARRING, ge, tie_earring / 2)); } return cmf; } /** Rebuilding of company statistics after loading a savegame. */ void AfterLoadCompanyStats() { /* Reset infrastructure statistics to zero. */ Company *c; FOR_ALL_COMPANIES(c) MemSetT(&c->infrastructure, 0); /* Collect airport count. */ Station *st; FOR_ALL_STATIONS(st) { if ((st->facilities & FACIL_AIRPORT) && Company::IsValidID(st->owner)) { Company::Get(st->owner)->infrastructure.airport++; } } for (TileIndex tile = 0; tile < MapSize(); tile++) { switch (GetTileType(tile)) { case MP_RAILWAY: c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { uint pieces = 1; if (IsPlainRail(tile)) { TrackBits bits = GetTrackBits(tile); pieces = CountBits(bits); if (TracksOverlap(bits)) pieces *= pieces; } c->infrastructure.rail[GetRailType(tile)] += pieces; if (HasSignals(tile)) c->infrastructure.signal += CountBits(GetPresentSignals(tile)); } break; case MP_ROAD: { if (IsLevelCrossing(tile)) { c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR; } /* Iterate all present road types as each can have a different owner. */ RoadType rt; FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { c = Company::GetIfValid(IsRoadDepot(tile) ? GetTileOwner(tile) : GetRoadOwner(tile, rt)); /* A level crossings and depots have two road bits. */ if (c != NULL) c->infrastructure.road[rt] += IsNormalRoad(tile) ? CountBits(GetRoadBits(tile, rt)) : 2; } break; } case MP_STATION: c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL && GetStationType(tile) != STATION_AIRPORT && !IsBuoy(tile)) c->infrastructure.station++; switch (GetStationType(tile)) { case STATION_RAIL: case STATION_WAYPOINT: if (c != NULL && !IsStationTileBlocked(tile)) c->infrastructure.rail[GetRailType(tile)]++; break; case STATION_BUS: case STATION_TRUCK: { /* Iterate all present road types as each can have a different owner. */ RoadType rt; FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) c->infrastructure.road[rt] += 2; // A road stop has two road bits. } break; } case STATION_DOCK: case STATION_BUOY: if (GetWaterClass(tile) == WATER_CLASS_CANAL) { if (c != NULL) c->infrastructure.water++; } break; default: break; } break; case MP_WATER: if (IsShipDepot(tile) || IsLock(tile)) { c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { if (IsShipDepot(tile)) c->infrastructure.water += LOCK_DEPOT_TILE_FACTOR; if (IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE) { /* The middle tile specifies the owner of the lock. */ c->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // the middle tile specifies the owner of the break; // do not count the middle tile as canal } } } /* FALL THROUGH */ case MP_OBJECT: if (GetWaterClass(tile) == WATER_CLASS_CANAL) { c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) c->infrastructure.water++; } break; case MP_TUNNELBRIDGE: { /* Only count the tunnel/bridge if we're on the northern end tile. */ TileIndex other_end = GetOtherTunnelBridgeEnd(tile); if (tile < other_end) { /* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate * the higher structural maintenance needs, and don't forget the end tiles. */ uint len = (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; switch (GetTunnelBridgeTransportType(tile)) { case TRANSPORT_RAIL: c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += len; break; case TRANSPORT_ROAD: { /* Iterate all present road types as each can have a different owner. */ RoadType rt; FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) c->infrastructure.road[rt] += len * 2; // A full diagonal road has two road bits. } break; } case TRANSPORT_WATER: c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) c->infrastructure.water += len; break; default: break; } } break; } default: break; } } } /* Save/load of companies */ static const SaveLoad _company_desc[] = { SLE_VAR(CompanyProperties, name_2, SLE_UINT32), SLE_VAR(CompanyProperties, name_1, SLE_STRINGID), SLE_CONDSTR(CompanyProperties, name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION), SLE_VAR(CompanyProperties, president_name_1, SLE_UINT16), SLE_VAR(CompanyProperties, president_name_2, SLE_UINT32), SLE_CONDSTR(CompanyProperties, president_name, SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION), SLE_VAR(CompanyProperties, face, SLE_UINT32), /* money was changed to a 64 bit field in savegame version 1. */ SLE_CONDVAR(CompanyProperties, money, SLE_VAR_I64 | SLE_FILE_I32, 0, 0), SLE_CONDVAR(CompanyProperties, money, SLE_INT64, 1, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, current_loan, SLE_VAR_I64 | SLE_FILE_I32, 0, 64), SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, 65, SL_MAX_VERSION), SLE_VAR(CompanyProperties, colour, SLE_UINT8), SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8), SLE_CONDVAR(CompanyProperties, avail_railtypes, SLE_VAR_I32 | SLE_FILE_I8, 0, 57), SLE_VAR(CompanyProperties, block_preview, SLE_UINT8), SLE_CONDNULL(2, 0, 93), ///< cargo_types SLE_CONDNULL(4, 94, 169), ///< cargo_types SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(CompanyProperties, location_of_HQ, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(CompanyProperties, last_build_coordinate, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_FILE_U8 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(CompanyProperties, inaugurated_year, SLE_INT32, 31, SL_MAX_VERSION), SLE_ARR(CompanyProperties, share_owners, SLE_UINT8, 4), SLE_VAR(CompanyProperties, num_valid_stat_ent, SLE_UINT8), SLE_VAR(CompanyProperties, months_of_bankruptcy, SLE_UINT8), SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_FILE_U8 | SLE_VAR_U16, 0, 103), SLE_CONDVAR(CompanyProperties, bankrupt_asked, SLE_UINT16, 104, SL_MAX_VERSION), SLE_VAR(CompanyProperties, bankrupt_timeout, SLE_INT16), SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_VAR_I64 | SLE_FILE_I32, 0, 64), SLE_CONDVAR(CompanyProperties, bankrupt_value, SLE_INT64, 65, SL_MAX_VERSION), /* yearly expenses was changed to 64-bit in savegame version 2. */ SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_FILE_I32 | SLE_VAR_I64, 3 * 13, 0, 1), SLE_CONDARR(CompanyProperties, yearly_expenses, SLE_INT64, 3 * 13, 2, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, is_ai, SLE_BOOL, 2, SL_MAX_VERSION), SLE_CONDNULL(1, 107, 111), ///< is_noai SLE_CONDNULL(1, 4, 99), SLE_CONDVAR(CompanyProperties, terraform_limit, SLE_UINT32, 156, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, clear_limit, SLE_UINT32, 156, SL_MAX_VERSION), SLE_CONDVAR(CompanyProperties, tree_limit, SLE_UINT32, 175, SL_MAX_VERSION), SLE_END() }; static const SaveLoad _company_settings_desc[] = { /* Engine renewal settings */ SLE_CONDNULL(512, 16, 18), SLE_CONDREF(Company, engine_renew_list, REF_ENGINE_RENEWS, 19, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.engine_renew, SLE_BOOL, 16, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.engine_renew_months, SLE_INT16, 16, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.engine_renew_money, SLE_UINT32, 16, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.renew_keep_length, SLE_BOOL, 2, SL_MAX_VERSION), /* Default vehicle settings */ SLE_CONDVAR(Company, settings.vehicle.servint_ispercent, SLE_BOOL, 120, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.vehicle.servint_trains, SLE_UINT16, 120, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.vehicle.servint_roadveh, SLE_UINT16, 120, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.vehicle.servint_aircraft, SLE_UINT16, 120, SL_MAX_VERSION), SLE_CONDVAR(Company, settings.vehicle.servint_ships, SLE_UINT16, 120, SL_MAX_VERSION), SLE_CONDNULL(63, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _company_settings_skip_desc[] = { /* Engine renewal settings */ SLE_CONDNULL(512, 16, 18), SLE_CONDNULL(2, 19, 68), // engine_renew_list SLE_CONDNULL(4, 69, SL_MAX_VERSION), // engine_renew_list SLE_CONDNULL(1, 16, SL_MAX_VERSION), // settings.engine_renew SLE_CONDNULL(2, 16, SL_MAX_VERSION), // settings.engine_renew_months SLE_CONDNULL(4, 16, SL_MAX_VERSION), // settings.engine_renew_money SLE_CONDNULL(1, 2, SL_MAX_VERSION), // settings.renew_keep_length /* Default vehicle settings */ SLE_CONDNULL(1, 120, SL_MAX_VERSION), // settings.vehicle.servint_ispercent SLE_CONDNULL(2, 120, SL_MAX_VERSION), // settings.vehicle.servint_trains SLE_CONDNULL(2, 120, SL_MAX_VERSION), // settings.vehicle.servint_roadveh SLE_CONDNULL(2, 120, SL_MAX_VERSION), // settings.vehicle.servint_aircraft SLE_CONDNULL(2, 120, SL_MAX_VERSION), // settings.vehicle.servint_ships SLE_CONDNULL(63, 2, 143), // old reserved space SLE_END() }; static const SaveLoad _company_economy_desc[] = { /* these were changed to 64-bit in savegame format 2 */ SLE_CONDVAR(CompanyEconomyEntry, income, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), SLE_CONDVAR(CompanyEconomyEntry, income, SLE_INT64, 2, SL_MAX_VERSION), SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), SLE_CONDVAR(CompanyEconomyEntry, expenses, SLE_INT64, 2, SL_MAX_VERSION), SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_FILE_I32 | SLE_VAR_I64, 0, 1), SLE_CONDVAR(CompanyEconomyEntry, company_value, SLE_INT64, 2, SL_MAX_VERSION), SLE_CONDVAR(CompanyEconomyEntry, delivered_cargo[NUM_CARGO - 1], SLE_INT32, 0, 169), SLE_CONDARR(CompanyEconomyEntry, delivered_cargo, SLE_UINT32, NUM_CARGO, 170, SL_MAX_VERSION), SLE_VAR(CompanyEconomyEntry, performance_history, SLE_INT32), SLE_END() }; /* We do need to read this single value, as the bigger it gets, the more data is stored */ struct CompanyOldAI { uint8 num_build_rec; }; static const SaveLoad _company_ai_desc[] = { SLE_CONDNULL(2, 0, 106), SLE_CONDNULL(2, 0, 12), SLE_CONDNULL(4, 13, 106), SLE_CONDNULL(8, 0, 106), SLE_CONDVAR(CompanyOldAI, num_build_rec, SLE_UINT8, 0, 106), SLE_CONDNULL(3, 0, 106), SLE_CONDNULL(2, 0, 5), SLE_CONDNULL(4, 6, 106), SLE_CONDNULL(2, 0, 5), SLE_CONDNULL(4, 6, 106), SLE_CONDNULL(2, 0, 106), SLE_CONDNULL(2, 0, 5), SLE_CONDNULL(4, 6, 106), SLE_CONDNULL(2, 0, 5), SLE_CONDNULL(4, 6, 106), SLE_CONDNULL(2, 0, 106), SLE_CONDNULL(2, 0, 68), SLE_CONDNULL(4, 69, 106), SLE_CONDNULL(18, 0, 106), SLE_CONDNULL(20, 0, 106), SLE_CONDNULL(32, 0, 106), SLE_CONDNULL(64, 2, 106), SLE_END() }; static const SaveLoad _company_ai_build_rec_desc[] = { SLE_CONDNULL(2, 0, 5), SLE_CONDNULL(4, 6, 106), SLE_CONDNULL(2, 0, 5), SLE_CONDNULL(4, 6, 106), SLE_CONDNULL(8, 0, 106), SLE_END() }; static const SaveLoad _company_livery_desc[] = { SLE_CONDVAR(Livery, in_use, SLE_BOOL, 34, SL_MAX_VERSION), SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION), SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION), SLE_END() }; static void SaveLoad_PLYR_common(Company *c, CompanyProperties *cprops) { int i; SlObject(cprops, _company_desc); if (c != NULL) { SlObject(c, _company_settings_desc); } else { char nothing; SlObject(¬hing, _company_settings_skip_desc); } /* Keep backwards compatible for savegames, so load the old AI block */ if (IsSavegameVersionBefore(107) && cprops->is_ai) { CompanyOldAI old_ai; char nothing; SlObject(&old_ai, _company_ai_desc); for (i = 0; i != old_ai.num_build_rec; i++) { SlObject(¬hing, _company_ai_build_rec_desc); } } /* Write economy */ SlObject(&cprops->cur_economy, _company_economy_desc); /* Write old economy entries. */ if (cprops->num_valid_stat_ent > lengthof(cprops->old_economy)) SlErrorCorrupt("Too many old economy entries"); for (i = 0; i < cprops->num_valid_stat_ent; i++) { SlObject(&cprops->old_economy[i], _company_economy_desc); } /* Write each livery entry. */ int num_liveries = IsSavegameVersionBefore(63) ? LS_END - 4 : (IsSavegameVersionBefore(85) ? LS_END - 2: LS_END); if (c != NULL) { for (i = 0; i < num_liveries; i++) { SlObject(&c->livery[i], _company_livery_desc); } if (num_liveries < LS_END) { /* We want to insert some liveries somewhere in between. This means some have to be moved. */ memmove(&c->livery[LS_FREIGHT_WAGON], &c->livery[LS_PASSENGER_WAGON_MONORAIL], (LS_END - LS_FREIGHT_WAGON) * sizeof(c->livery[0])); c->livery[LS_PASSENGER_WAGON_MONORAIL] = c->livery[LS_MONORAIL]; c->livery[LS_PASSENGER_WAGON_MAGLEV] = c->livery[LS_MAGLEV]; } if (num_liveries == LS_END - 4) { /* Copy bus/truck liveries over to trams */ c->livery[LS_PASSENGER_TRAM] = c->livery[LS_BUS]; c->livery[LS_FREIGHT_TRAM] = c->livery[LS_TRUCK]; } } else { /* Skip liveries */ Livery dummy_livery; for (i = 0; i < num_liveries; i++) { SlObject(&dummy_livery, _company_livery_desc); } } } static void SaveLoad_PLYR(Company *c) { SaveLoad_PLYR_common(c, c); } static void Save_PLYR() { Company *c; FOR_ALL_COMPANIES(c) { SlSetArrayIndex(c->index); SlAutolength((AutolengthProc*)SaveLoad_PLYR, c); } } static void Load_PLYR() { int index; while ((index = SlIterateArray()) != -1) { Company *c = new (index) Company(); SaveLoad_PLYR(c); _company_colours[index] = (Colours)c->colour; } } static void Check_PLYR() { int index; while ((index = SlIterateArray()) != -1) { CompanyProperties *cprops = new CompanyProperties(); memset(cprops, 0, sizeof(*cprops)); SaveLoad_PLYR_common(NULL, cprops); /* We do not load old custom names */ if (IsSavegameVersionBefore(84)) { if (GB(cprops->name_1, 11, 5) == 15) { cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE; } if (GB(cprops->president_name_1, 11, 5) == 15) { cprops->president_name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE; } } if (cprops->name == NULL && !IsInsideMM(cprops->name_1, SPECSTR_COMPANY_NAME_START, SPECSTR_COMPANY_NAME_LAST + 1) && cprops->name_1 != STR_GAME_SAVELOAD_NOT_AVAILABLE && cprops->name_1 != STR_SV_UNNAMED && cprops->name_1 != SPECSTR_ANDCO_NAME && cprops->name_1 != SPECSTR_PRESIDENT_NAME && cprops->name_1 != SPECSTR_SILLY_NAME) { cprops->name_1 = STR_GAME_SAVELOAD_NOT_AVAILABLE; } if (!_load_check_data.companies.Insert(index, cprops)) delete cprops; } } static void Ptrs_PLYR() { Company *c; FOR_ALL_COMPANIES(c) { SlObject(c, _company_settings_desc); } } extern const ChunkHandler _company_chunk_handlers[] = { { 'PLYR', Save_PLYR, Load_PLYR, Ptrs_PLYR, Check_PLYR, CH_ARRAY | CH_LAST}, }; openttd-1.5.3/src/saveload/linkgraph_sl.cpp0000644000000000000000000002005012627373446017454 0ustar rootroot/* $Id: linkgraph_sl.cpp 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 linkgraph_sl.cpp Code handling saving and loading of link graphs */ #include "../stdafx.h" #include "../linkgraph/linkgraph.h" #include "../linkgraph/linkgraphjob.h" #include "../linkgraph/linkgraphschedule.h" #include "../settings_internal.h" #include "saveload.h" #include "../safeguards.h" typedef LinkGraph::BaseNode Node; typedef LinkGraph::BaseEdge Edge; const SettingDesc *GetSettingDescription(uint index); static uint16 _num_nodes; /** * Get a SaveLoad array for a link graph. * @return SaveLoad array for link graph. */ const SaveLoad *GetLinkGraphDesc() { static const SaveLoad link_graph_desc[] = { SLE_VAR(LinkGraph, last_compression, SLE_INT32), SLEG_VAR(_num_nodes, SLE_UINT16), SLE_VAR(LinkGraph, cargo, SLE_UINT8), SLE_END() }; return link_graph_desc; } /** * Get a SaveLoad array for a link graph job. The settings struct is derived from * the global settings saveload array. The exact entries are calculated when the function * is called the first time. * It's necessary to keep a copy of the settings for each link graph job so that you can * change the settings while in-game and still not mess with current link graph runs. * Of course the settings have to be saved and loaded, too, to avoid desyncs. * @return Array of SaveLoad structs. */ const SaveLoad *GetLinkGraphJobDesc() { static SmallVector saveloads; static const char *prefix = "linkgraph."; /* Build the SaveLoad array on first call and don't touch it later on */ if (saveloads.Length() == 0) { size_t offset_gamesettings = cpp_offsetof(GameSettings, linkgraph); size_t offset_component = cpp_offsetof(LinkGraphJob, settings); size_t prefixlen = strlen(prefix); int setting = 0; const SettingDesc *desc = GetSettingDescription(setting); while (desc->save.cmd != SL_END) { if (desc->desc.name != NULL && strncmp(desc->desc.name, prefix, prefixlen) == 0) { SaveLoad sl = desc->save; char *&address = reinterpret_cast(sl.address); address -= offset_gamesettings; address += offset_component; *(saveloads.Append()) = sl; } desc = GetSettingDescription(++setting); } const SaveLoad job_desc[] = { SLE_VAR(LinkGraphJob, join_date, SLE_INT32), SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16), SLE_END() }; int i = 0; do { *(saveloads.Append()) = job_desc[i++]; } while (saveloads[saveloads.Length() - 1].cmd != SL_END); } return &saveloads[0]; } /** * Get a SaveLoad array for the link graph schedule. * @return SaveLoad array for the link graph schedule. */ const SaveLoad *GetLinkGraphScheduleDesc() { static const SaveLoad schedule_desc[] = { SLE_LST(LinkGraphSchedule, schedule, REF_LINK_GRAPH), SLE_LST(LinkGraphSchedule, running, REF_LINK_GRAPH_JOB), SLE_END() }; return schedule_desc; } /* Edges and nodes are saved in the correct order, so we don't need to save their IDs. */ /** * SaveLoad desc for a link graph node. */ static const SaveLoad _node_desc[] = { SLE_CONDVAR(Node, xy, SLE_UINT32, 191, SL_MAX_VERSION), SLE_VAR(Node, supply, SLE_UINT32), SLE_VAR(Node, demand, SLE_UINT32), SLE_VAR(Node, station, SLE_UINT16), SLE_VAR(Node, last_update, SLE_INT32), SLE_END() }; /** * SaveLoad desc for a link graph edge. */ static const SaveLoad _edge_desc[] = { SLE_CONDNULL(4, 0, 190), // distance SLE_VAR(Edge, capacity, SLE_UINT32), SLE_VAR(Edge, usage, SLE_UINT32), SLE_VAR(Edge, last_unrestricted_update, SLE_INT32), SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, 187, SL_MAX_VERSION), SLE_VAR(Edge, next_edge, SLE_UINT16), SLE_END() }; /** * Save/load a link graph. * @param comp Link graph to be saved or loaded. */ void SaveLoad_LinkGraph(LinkGraph &lg) { uint size = lg.Size(); for (NodeID from = 0; from < size; ++from) { Node *node = &lg.nodes[from]; SlObject(node, _node_desc); if (IsSavegameVersionBefore(191)) { /* We used to save the full matrix ... */ for (NodeID to = 0; to < size; ++to) { SlObject(&lg.edges[from][to], _edge_desc); } } else { /* ... but as that wasted a lot of space we save a sparse matrix now. */ for (NodeID to = from; to != INVALID_NODE; to = lg.edges[from][to].next_edge) { SlObject(&lg.edges[from][to], _edge_desc); } } } } /** * Save a link graph job. * @param lgj LinkGraphJob to be saved. */ static void DoSave_LGRJ(LinkGraphJob *lgj) { SlObject(lgj, GetLinkGraphJobDesc()); _num_nodes = lgj->Size(); SlObject(const_cast(&lgj->Graph()), GetLinkGraphDesc()); SaveLoad_LinkGraph(const_cast(lgj->Graph())); } /** * Save a link graph. * @param lg LinkGraph to be saved. */ static void DoSave_LGRP(LinkGraph *lg) { _num_nodes = lg->Size(); SlObject(lg, GetLinkGraphDesc()); SaveLoad_LinkGraph(*lg); } /** * Load all link graphs. */ static void Load_LGRP() { int index; while ((index = SlIterateArray()) != -1) { if (!LinkGraph::CanAllocateItem()) { /* Impossible as they have been present in previous game. */ NOT_REACHED(); } LinkGraph *lg = new (index) LinkGraph(); SlObject(lg, GetLinkGraphDesc()); lg->Init(_num_nodes); SaveLoad_LinkGraph(*lg); } } /** * Load all link graph jobs. */ static void Load_LGRJ() { int index; while ((index = SlIterateArray()) != -1) { if (!LinkGraphJob::CanAllocateItem()) { /* Impossible as they have been present in previous game. */ NOT_REACHED(); } LinkGraphJob *lgj = new (index) LinkGraphJob(); SlObject(lgj, GetLinkGraphJobDesc()); LinkGraph &lg = const_cast(lgj->Graph()); SlObject(&lg, GetLinkGraphDesc()); lg.Init(_num_nodes); SaveLoad_LinkGraph(lg); } } /** * Load the link graph schedule. */ static void Load_LGRS() { SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); } /** * Spawn the threads for running link graph calculations. * Has to be done after loading as the cargo classes might have changed. */ void AfterLoadLinkGraphs() { if (IsSavegameVersionBefore(191)) { LinkGraph *lg; FOR_ALL_LINK_GRAPHS(lg) { for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) { (*lg)[node_id].UpdateLocation(Station::Get((*lg)[node_id].Station())->xy); } } LinkGraphJob *lgj; FOR_ALL_LINK_GRAPH_JOBS(lgj) { lg = &(const_cast(lgj->Graph())); for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) { (*lg)[node_id].UpdateLocation(Station::Get((*lg)[node_id].Station())->xy); } } } LinkGraphSchedule::instance.SpawnAll(); } /** * Save all link graphs. */ static void Save_LGRP() { LinkGraph *lg; FOR_ALL_LINK_GRAPHS(lg) { SlSetArrayIndex(lg->index); SlAutolength((AutolengthProc*)DoSave_LGRP, lg); } } /** * Save all link graph jobs. */ static void Save_LGRJ() { LinkGraphJob *lgj; FOR_ALL_LINK_GRAPH_JOBS(lgj) { SlSetArrayIndex(lgj->index); SlAutolength((AutolengthProc*)DoSave_LGRJ, lgj); } } /** * Save the link graph schedule. */ static void Save_LGRS() { SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); } /** * Substitute pointers in link graph schedule. */ static void Ptrs_LGRS() { SlObject(&LinkGraphSchedule::instance, GetLinkGraphScheduleDesc()); } extern const ChunkHandler _linkgraph_chunk_handlers[] = { { 'LGRP', Save_LGRP, Load_LGRP, NULL, NULL, CH_ARRAY }, { 'LGRJ', Save_LGRJ, Load_LGRJ, NULL, NULL, CH_ARRAY }, { 'LGRS', Save_LGRS, Load_LGRS, Ptrs_LGRS, NULL, CH_LAST } }; openttd-1.5.3/src/saveload/saveload.cpp0000644000000000000000000024545512627373446016617 0ustar rootroot/* $Id: saveload.cpp 27003 2014-10-12 18:41:53Z rubidium $ */ /* * 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 saveload.cpp * All actions handling saving and loading goes on in this file. The general actions * are as follows for saving a game (loading is analogous): *
    *
  1. initialize the writer by creating a temporary memory-buffer for it *
  2. go through all to-be saved elements, each 'chunk' (#ChunkHandler) prefixed by a label *
  3. use their description array (#SaveLoad) to know what elements to save and in what version * of the game it was active (used when loading) *
  4. write all data byte-by-byte to the temporary buffer so it is endian-safe *
  5. when the buffer is full; flush it to the output (eg save to file) (_sl.buf, _sl.bufp, _sl.bufe) *
  6. repeat this until everything is done, and flush any remaining output to file *
*/ #include "../stdafx.h" #include "../debug.h" #include "../station_base.h" #include "../thread/thread.h" #include "../town.h" #include "../network/network.h" #include "../window_func.h" #include "../strings_func.h" #include "../core/endian_func.hpp" #include "../vehicle_base.h" #include "../company_func.h" #include "../date_func.h" #include "../autoreplace_base.h" #include "../roadstop_base.h" #include "../linkgraph/linkgraph.h" #include "../linkgraph/linkgraphjob.h" #include "../statusbar_gui.h" #include "../fileio_func.h" #include "../gamelog.h" #include "../string_func.h" #include "../fios.h" #include "../error.h" #include "table/strings.h" #include "saveload_internal.h" #include "saveload_filter.h" #include "../safeguards.h" /* * Previous savegame versions, the trunk revision where they were * introduced and the released version that had that particular * savegame version. * Up to savegame version 18 there is a minor version as well. * * 1.0 0.1.x, 0.2.x * 2.0 0.3.0 * 2.1 0.3.1, 0.3.2 * 3.x lost * 4.0 1 * 4.1 122 0.3.3, 0.3.4 * 4.2 1222 0.3.5 * 4.3 1417 * 4.4 1426 * 5.0 1429 * 5.1 1440 * 5.2 1525 0.3.6 * 6.0 1721 * 6.1 1768 * 7.0 1770 * 8.0 1786 * 9.0 1909 * 10.0 2030 * 11.0 2033 * 11.1 2041 * 12.1 2046 * 13.1 2080 0.4.0, 0.4.0.1 * 14.0 2441 * 15.0 2499 * 16.0 2817 * 16.1 3155 * 17.0 3212 * 17.1 3218 * 18 3227 * 19 3396 * 20 3403 * 21 3472 0.4.x * 22 3726 * 23 3915 * 24 4150 * 25 4259 * 26 4466 * 27 4757 * 28 4987 * 29 5070 * 30 5946 * 31 5999 * 32 6001 * 33 6440 * 34 6455 * 35 6602 * 36 6624 * 37 7182 * 38 7195 * 39 7269 * 40 7326 * 41 7348 0.5.x * 42 7573 * 43 7642 * 44 8144 * 45 8501 * 46 8705 * 47 8735 * 48 8935 * 49 8969 * 50 8973 * 51 8978 * 52 9066 * 53 9316 * 54 9613 * 55 9638 * 56 9667 * 57 9691 * 58 9762 * 59 9779 * 60 9874 * 61 9892 * 62 9905 * 63 9956 * 64 10006 * 65 10210 * 66 10211 * 67 10236 * 68 10266 * 69 10319 * 70 10541 * 71 10567 * 72 10601 * 73 10903 * 74 11030 * 75 11107 * 76 11139 * 77 11172 * 78 11176 * 79 11188 * 80 11228 * 81 11244 * 82 11410 * 83 11589 * 84 11822 * 85 11874 * 86 12042 * 87 12129 * 88 12134 * 89 12160 * 90 12293 * 91 12347 * 92 12381 0.6.x * 93 12648 * 94 12816 * 95 12924 * 96 13226 * 97 13256 * 98 13375 * 99 13838 * 100 13952 * 101 14233 * 102 14332 * 103 14598 * 104 14735 * 105 14803 * 106 14919 * 107 15027 * 108 15045 * 109 15075 * 110 15148 * 111 15190 * 112 15290 * 113 15340 * 114 15601 * 115 15695 * 116 15893 0.7.x * 117 16037 * 118 16129 * 119 16242 * 120 16439 * 121 16694 * 122 16855 * 123 16909 * 124 16993 * 125 17113 * 126 17433 * 127 17439 * 128 18281 * 129 18292 * 130 18404 * 131 18481 * 132 18522 * 133 18674 * 134 18703 * 135 18719 * 136 18764 * 137 18912 * 138 18942 1.0.x * 139 19346 * 140 19382 * 141 19799 * 142 20003 * 143 20048 * 144 20334 * 145 20376 * 146 20446 * 147 20621 * 148 20659 * 149 20832 * 150 20857 * 151 20918 * 152 21171 * 153 21263 * 154 21426 * 155 21453 * 156 21728 * 157 21862 * 158 21933 * 159 21962 * 160 21974 1.1.x * 161 22567 * 162 22713 * 163 22767 * 164 23290 * 165 23304 * 166 23415 * 167 23504 * 168 23637 * 169 23816 * 170 23826 * 171 23835 * 172 23947 * 173 23967 1.2.0-RC1 * 174 23973 1.2.x * 175 24136 * 176 24446 * 177 24619 * 178 24789 * 179 24810 * 180 24998 1.3.x * 181 25012 * 182 25296 * 183 25363 * 184 25508 * 185 25620 * 186 25833 * 187 25899 * 188 26169 1.4.x * 189 26450 * 190 26547 * 191 26646 * 192 26700 * 193 26802 * 194 26881 */ extern const uint16 SAVEGAME_VERSION = 194; ///< Current savegame version of OpenTTD. SavegameType _savegame_type; ///< type of savegame we are loading uint32 _ttdp_version; ///< version of TTDP savegame (if applicable) uint16 _sl_version; ///< the major savegame version identifier byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! char _savegame_format[8]; ///< how to compress savegames bool _do_autosave; ///< are we doing an autosave at the moment? /** What are we currently doing? */ enum SaveLoadAction { SLA_LOAD, ///< loading SLA_SAVE, ///< saving SLA_PTRS, ///< fixing pointers SLA_NULL, ///< null all pointers (on loading error) SLA_LOAD_CHECK, ///< partial loading into #_load_check_data }; enum NeedLength { NL_NONE = 0, ///< not working in NeedLength mode NL_WANTLENGTH = 1, ///< writing length and data NL_CALCLENGTH = 2, ///< need to calculate the length }; /** Save in chunks of 128 KiB. */ static const size_t MEMORY_CHUNK_SIZE = 128 * 1024; /** A buffer for reading (and buffering) savegame data. */ struct ReadBuffer { byte buf[MEMORY_CHUNK_SIZE]; ///< Buffer we're going to read from. byte *bufp; ///< Location we're at reading the buffer. byte *bufe; ///< End of the buffer we can read from. LoadFilter *reader; ///< The filter used to actually read. size_t read; ///< The amount of read bytes so far from the filter. /** * Initialise our variables. * @param reader The filter to actually read data. */ ReadBuffer(LoadFilter *reader) : bufp(NULL), bufe(NULL), reader(reader), read(0) { } inline byte ReadByte() { if (this->bufp == this->bufe) { size_t len = this->reader->Read(this->buf, lengthof(this->buf)); if (len == 0) SlErrorCorrupt("Unexpected end of chunk"); this->read += len; this->bufp = this->buf; this->bufe = this->buf + len; } return *this->bufp++; } /** * Get the size of the memory dump made so far. * @return The size. */ size_t GetSize() const { return this->read - (this->bufe - this->bufp); } }; /** Container for dumping the savegame (quickly) to memory. */ struct MemoryDumper { AutoFreeSmallVector blocks; ///< Buffer with blocks of allocated memory. byte *buf; ///< Buffer we're going to write to. byte *bufe; ///< End of the buffer we write to. /** Initialise our variables. */ MemoryDumper() : buf(NULL), bufe(NULL) { } /** * Write a single byte into the dumper. * @param b The byte to write. */ inline void WriteByte(byte b) { /* Are we at the end of this chunk? */ if (this->buf == this->bufe) { this->buf = CallocT(MEMORY_CHUNK_SIZE); *this->blocks.Append() = this->buf; this->bufe = this->buf + MEMORY_CHUNK_SIZE; } *this->buf++ = b; } /** * Flush this dumper into a writer. * @param writer The filter we want to use. */ void Flush(SaveFilter *writer) { uint i = 0; size_t t = this->GetSize(); while (t > 0) { size_t to_write = min(MEMORY_CHUNK_SIZE, t); writer->Write(this->blocks[i++], to_write); t -= to_write; } writer->Finish(); } /** * Get the size of the memory dump made so far. * @return The size. */ size_t GetSize() const { return this->blocks.Length() * MEMORY_CHUNK_SIZE - (this->bufe - this->buf); } }; /** The saveload struct, containing reader-writer functions, buffer, version, etc. */ struct SaveLoadParams { SaveLoadAction action; ///< are we doing a save or a load atm. NeedLength need_length; ///< working in NeedLength (Autolength) mode? byte block_mode; ///< ??? bool error; ///< did an error occur or not size_t obj_len; ///< the length of the current object we are busy with int array_index, last_array_index; ///< in the case of an array, the current and last positions MemoryDumper *dumper; ///< Memory dumper to write the savegame to. SaveFilter *sf; ///< Filter to write the savegame to. ReadBuffer *reader; ///< Savegame reading buffer. LoadFilter *lf; ///< Filter to read the savegame from. StringID error_str; ///< the translatable error message to show char *extra_msg; ///< the error message byte ff_state; ///< The state of fast-forward when saving started. bool saveinprogress; ///< Whether there is currently a save in progress. }; static SaveLoadParams _sl; ///< Parameters used for/at saveload. /* these define the chunks */ extern const ChunkHandler _gamelog_chunk_handlers[]; extern const ChunkHandler _map_chunk_handlers[]; extern const ChunkHandler _misc_chunk_handlers[]; extern const ChunkHandler _name_chunk_handlers[]; extern const ChunkHandler _cheat_chunk_handlers[] ; extern const ChunkHandler _setting_chunk_handlers[]; extern const ChunkHandler _company_chunk_handlers[]; extern const ChunkHandler _engine_chunk_handlers[]; extern const ChunkHandler _veh_chunk_handlers[]; extern const ChunkHandler _waypoint_chunk_handlers[]; extern const ChunkHandler _depot_chunk_handlers[]; extern const ChunkHandler _order_chunk_handlers[]; extern const ChunkHandler _town_chunk_handlers[]; extern const ChunkHandler _sign_chunk_handlers[]; extern const ChunkHandler _station_chunk_handlers[]; extern const ChunkHandler _industry_chunk_handlers[]; extern const ChunkHandler _economy_chunk_handlers[]; extern const ChunkHandler _subsidy_chunk_handlers[]; extern const ChunkHandler _cargomonitor_chunk_handlers[]; extern const ChunkHandler _goal_chunk_handlers[]; extern const ChunkHandler _story_page_chunk_handlers[]; extern const ChunkHandler _ai_chunk_handlers[]; extern const ChunkHandler _game_chunk_handlers[]; extern const ChunkHandler _animated_tile_chunk_handlers[]; extern const ChunkHandler _newgrf_chunk_handlers[]; extern const ChunkHandler _group_chunk_handlers[]; extern const ChunkHandler _cargopacket_chunk_handlers[]; extern const ChunkHandler _autoreplace_chunk_handlers[]; extern const ChunkHandler _labelmaps_chunk_handlers[]; extern const ChunkHandler _linkgraph_chunk_handlers[]; extern const ChunkHandler _airport_chunk_handlers[]; extern const ChunkHandler _object_chunk_handlers[]; extern const ChunkHandler _persistent_storage_chunk_handlers[]; /** Array of all chunks in a savegame, \c NULL terminated. */ static const ChunkHandler * const _chunk_handlers[] = { _gamelog_chunk_handlers, _map_chunk_handlers, _misc_chunk_handlers, _name_chunk_handlers, _cheat_chunk_handlers, _setting_chunk_handlers, _veh_chunk_handlers, _waypoint_chunk_handlers, _depot_chunk_handlers, _order_chunk_handlers, _industry_chunk_handlers, _economy_chunk_handlers, _subsidy_chunk_handlers, _cargomonitor_chunk_handlers, _goal_chunk_handlers, _story_page_chunk_handlers, _engine_chunk_handlers, _town_chunk_handlers, _sign_chunk_handlers, _station_chunk_handlers, _company_chunk_handlers, _ai_chunk_handlers, _game_chunk_handlers, _animated_tile_chunk_handlers, _newgrf_chunk_handlers, _group_chunk_handlers, _cargopacket_chunk_handlers, _autoreplace_chunk_handlers, _labelmaps_chunk_handlers, _linkgraph_chunk_handlers, _airport_chunk_handlers, _object_chunk_handlers, _persistent_storage_chunk_handlers, NULL, }; /** * Iterate over all chunk handlers. * @param ch the chunk handler iterator */ #define FOR_ALL_CHUNK_HANDLERS(ch) \ for (const ChunkHandler * const *chsc = _chunk_handlers; *chsc != NULL; chsc++) \ for (const ChunkHandler *ch = *chsc; ch != NULL; ch = (ch->flags & CH_LAST) ? NULL : ch + 1) /** Null all pointers (convert index -> NULL) */ static void SlNullPointers() { _sl.action = SLA_NULL; /* We don't want any savegame conversion code to run * during NULLing; especially those that try to get * pointers from other pools. */ _sl_version = SAVEGAME_VERSION; DEBUG(sl, 1, "Nulling pointers"); FOR_ALL_CHUNK_HANDLERS(ch) { if (ch->ptrs_proc != NULL) { DEBUG(sl, 2, "Nulling pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id); ch->ptrs_proc(); } } DEBUG(sl, 1, "All pointers nulled"); assert(_sl.action == SLA_NULL); } /** * Error handler. Sets everything up to show an error message and to clean * up the mess of a partial savegame load. * @param string The translatable error message to show. * @param extra_msg An extra error message coming from one of the APIs. * @note This function does never return as it throws an exception to * break out of all the saveload code. */ void NORETURN SlError(StringID string, const char *extra_msg) { /* Distinguish between loading into _load_check_data vs. normal save/load. */ if (_sl.action == SLA_LOAD_CHECK) { _load_check_data.error = string; free(_load_check_data.error_data); _load_check_data.error_data = (extra_msg == NULL) ? NULL : stredup(extra_msg); } else { _sl.error_str = string; free(_sl.extra_msg); _sl.extra_msg = (extra_msg == NULL) ? NULL : stredup(extra_msg); } /* We have to NULL all pointers here; we might be in a state where * the pointers are actually filled with indices, which means that * when we access them during cleaning the pool dereferences of * those indices will be made with segmentation faults as result. */ if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers(); throw std::exception(); } /** * Error handler for corrupt savegames. Sets everything up to show the * error message and to clean up the mess of a partial savegame load. * @param msg Location the corruption has been spotted. * @note This function does never return as it throws an exception to * break out of all the saveload code. */ void NORETURN SlErrorCorrupt(const char *msg) { SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, msg); } typedef void (*AsyncSaveFinishProc)(); ///< Callback for when the savegame loading is finished. static AsyncSaveFinishProc _async_save_finish = NULL; ///< Callback to call when the savegame loading is finished. static ThreadObject *_save_thread; ///< The thread we're using to compress and write a savegame /** * Called by save thread to tell we finished saving. * @param proc The callback to call when saving is done. */ static void SetAsyncSaveFinish(AsyncSaveFinishProc proc) { if (_exit_game) return; while (_async_save_finish != NULL) CSleep(10); _async_save_finish = proc; } /** * Handle async save finishes. */ void ProcessAsyncSaveFinish() { if (_async_save_finish == NULL) return; _async_save_finish(); _async_save_finish = NULL; if (_save_thread != NULL) { _save_thread->Join(); delete _save_thread; _save_thread = NULL; } } /** * Wrapper for reading a byte from the buffer. * @return The read byte. */ byte SlReadByte() { return _sl.reader->ReadByte(); } /** * Wrapper for writing a byte to the dumper. * @param b The byte to write. */ void SlWriteByte(byte b) { _sl.dumper->WriteByte(b); } static inline int SlReadUint16() { int x = SlReadByte() << 8; return x | SlReadByte(); } static inline uint32 SlReadUint32() { uint32 x = SlReadUint16() << 16; return x | SlReadUint16(); } static inline uint64 SlReadUint64() { uint32 x = SlReadUint32(); uint32 y = SlReadUint32(); return (uint64)x << 32 | y; } static inline void SlWriteUint16(uint16 v) { SlWriteByte(GB(v, 8, 8)); SlWriteByte(GB(v, 0, 8)); } static inline void SlWriteUint32(uint32 v) { SlWriteUint16(GB(v, 16, 16)); SlWriteUint16(GB(v, 0, 16)); } static inline void SlWriteUint64(uint64 x) { SlWriteUint32((uint32)(x >> 32)); SlWriteUint32((uint32)x); } /** * Read in bytes from the file/data structure but don't do * anything with them, discarding them in effect * @param length The amount of bytes that is being treated this way */ static inline void SlSkipBytes(size_t length) { for (; length != 0; length--) SlReadByte(); } /** * Read in the header descriptor of an object or an array. * If the highest bit is set (7), then the index is bigger than 127 * elements, so use the next byte to read in the real value. * The actual value is then both bytes added with the first shifted * 8 bits to the left, and dropping the highest bit (which only indicated a big index). * x = ((x & 0x7F) << 8) + SlReadByte(); * @return Return the value of the index */ static uint SlReadSimpleGamma() { uint i = SlReadByte(); if (HasBit(i, 7)) { i &= ~0x80; if (HasBit(i, 6)) { i &= ~0x40; if (HasBit(i, 5)) { i &= ~0x20; if (HasBit(i, 4)) { i &= ~0x10; if (HasBit(i, 3)) { SlErrorCorrupt("Unsupported gamma"); } i = SlReadByte(); // 32 bits only. } i = (i << 8) | SlReadByte(); } i = (i << 8) | SlReadByte(); } i = (i << 8) | SlReadByte(); } return i; } /** * Write the header descriptor of an object or an array. * If the element is bigger than 127, use 2 bytes for saving * and use the highest byte of the first written one as a notice * that the length consists of 2 bytes, etc.. like this: * 0xxxxxxx * 10xxxxxx xxxxxxxx * 110xxxxx xxxxxxxx xxxxxxxx * 1110xxxx xxxxxxxx xxxxxxxx xxxxxxxx * 11110--- xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx * We could extend the scheme ad infinum to support arbitrarily * large chunks, but as sizeof(size_t) == 4 is still very common * we don't support anything above 32 bits. That's why in the last * case the 3 most significant bits are unused. * @param i Index being written */ static void SlWriteSimpleGamma(size_t i) { if (i >= (1 << 7)) { if (i >= (1 << 14)) { if (i >= (1 << 21)) { if (i >= (1 << 28)) { assert(i <= UINT32_MAX); // We can only support 32 bits for now. SlWriteByte((byte)(0xF0)); SlWriteByte((byte)(i >> 24)); } else { SlWriteByte((byte)(0xE0 | (i >> 24))); } SlWriteByte((byte)(i >> 16)); } else { SlWriteByte((byte)(0xC0 | (i >> 16))); } SlWriteByte((byte)(i >> 8)); } else { SlWriteByte((byte)(0x80 | (i >> 8))); } } SlWriteByte((byte)i); } /** Return how many bytes used to encode a gamma value */ static inline uint SlGetGammaLength(size_t i) { return 1 + (i >= (1 << 7)) + (i >= (1 << 14)) + (i >= (1 << 21)) + (i >= (1 << 28)); } static inline uint SlReadSparseIndex() { return SlReadSimpleGamma(); } static inline void SlWriteSparseIndex(uint index) { SlWriteSimpleGamma(index); } static inline uint SlReadArrayLength() { return SlReadSimpleGamma(); } static inline void SlWriteArrayLength(size_t length) { SlWriteSimpleGamma(length); } static inline uint SlGetArrayLength(size_t length) { return SlGetGammaLength(length); } /** * Return the size in bytes of a certain type of normal/atomic variable * as it appears in memory. See VarTypes * @param conv VarType type of variable that is used for calculating the size * @return Return the size of this type in bytes */ static inline uint SlCalcConvMemLen(VarType conv) { static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0}; byte length = GB(conv, 4, 4); switch (length << 4) { case SLE_VAR_STRB: case SLE_VAR_STRBQ: case SLE_VAR_STR: case SLE_VAR_STRQ: return SlReadArrayLength(); default: assert(length < lengthof(conv_mem_size)); return conv_mem_size[length]; } } /** * Return the size in bytes of a certain type of normal/atomic variable * as it appears in a saved game. See VarTypes * @param conv VarType type of variable that is used for calculating the size * @return Return the size of this type in bytes */ static inline byte SlCalcConvFileLen(VarType conv) { static const byte conv_file_size[] = {1, 1, 2, 2, 4, 4, 8, 8, 2}; byte length = GB(conv, 0, 4); assert(length < lengthof(conv_file_size)); return conv_file_size[length]; } /** Return the size in bytes of a reference (pointer) */ static inline size_t SlCalcRefLen() { return IsSavegameVersionBefore(69) ? 2 : 4; } void SlSetArrayIndex(uint index) { _sl.need_length = NL_WANTLENGTH; _sl.array_index = index; } static size_t _next_offs; /** * Iterate through the elements of an array and read the whole thing * @return The index of the object, or -1 if we have reached the end of current block */ int SlIterateArray() { int index; /* After reading in the whole array inside the loop * we must have read in all the data, so we must be at end of current block. */ if (_next_offs != 0 && _sl.reader->GetSize() != _next_offs) SlErrorCorrupt("Invalid chunk size"); for (;;) { uint length = SlReadArrayLength(); if (length == 0) { _next_offs = 0; return -1; } _sl.obj_len = --length; _next_offs = _sl.reader->GetSize() + length; switch (_sl.block_mode) { case CH_SPARSE_ARRAY: index = (int)SlReadSparseIndex(); break; case CH_ARRAY: index = _sl.array_index++; break; default: DEBUG(sl, 0, "SlIterateArray error"); return -1; // error } if (length != 0) return index; } } /** * Skip an array or sparse array */ void SlSkipArray() { while (SlIterateArray() != -1) { SlSkipBytes(_next_offs - _sl.reader->GetSize()); } } /** * Sets the length of either a RIFF object or the number of items in an array. * This lets us load an object or an array of arbitrary size * @param length The length of the sought object/array */ void SlSetLength(size_t length) { assert(_sl.action == SLA_SAVE); switch (_sl.need_length) { case NL_WANTLENGTH: _sl.need_length = NL_NONE; switch (_sl.block_mode) { case CH_RIFF: /* Ugly encoding of >16M RIFF chunks * The lower 24 bits are normal * The uppermost 4 bits are bits 24:27 */ assert(length < (1 << 28)); SlWriteUint32((uint32)((length & 0xFFFFFF) | ((length >> 24) << 28))); break; case CH_ARRAY: assert(_sl.last_array_index <= _sl.array_index); while (++_sl.last_array_index <= _sl.array_index) { SlWriteArrayLength(1); } SlWriteArrayLength(length + 1); break; case CH_SPARSE_ARRAY: SlWriteArrayLength(length + 1 + SlGetArrayLength(_sl.array_index)); // Also include length of sparse index. SlWriteSparseIndex(_sl.array_index); break; default: NOT_REACHED(); } break; case NL_CALCLENGTH: _sl.obj_len += (int)length; break; default: NOT_REACHED(); } } /** * Save/Load bytes. These do not need to be converted to Little/Big Endian * so directly write them or read them to/from file * @param ptr The source or destination of the object being manipulated * @param length number of bytes this fast CopyBytes lasts */ static void SlCopyBytes(void *ptr, size_t length) { byte *p = (byte *)ptr; switch (_sl.action) { case SLA_LOAD_CHECK: case SLA_LOAD: for (; length != 0; length--) *p++ = SlReadByte(); break; case SLA_SAVE: for (; length != 0; length--) SlWriteByte(*p++); break; default: NOT_REACHED(); } } /** Get the length of the current object */ size_t SlGetFieldLength() { return _sl.obj_len; } /** * Return a signed-long version of the value of a setting * @param ptr pointer to the variable * @param conv type of variable, can be a non-clean * type, eg one with other flags because it is parsed * @return returns the value of the pointer-setting */ int64 ReadValue(const void *ptr, VarType conv) { switch (GetVarMemType(conv)) { case SLE_VAR_BL: return (*(const bool *)ptr != 0); case SLE_VAR_I8: return *(const int8 *)ptr; case SLE_VAR_U8: return *(const byte *)ptr; case SLE_VAR_I16: return *(const int16 *)ptr; case SLE_VAR_U16: return *(const uint16*)ptr; case SLE_VAR_I32: return *(const int32 *)ptr; case SLE_VAR_U32: return *(const uint32*)ptr; case SLE_VAR_I64: return *(const int64 *)ptr; case SLE_VAR_U64: return *(const uint64*)ptr; case SLE_VAR_NULL:return 0; default: NOT_REACHED(); } } /** * Write the value of a setting * @param ptr pointer to the variable * @param conv type of variable, can be a non-clean type, eg * with other flags. It is parsed upon read * @param val the new value being given to the variable */ void WriteValue(void *ptr, VarType conv, int64 val) { switch (GetVarMemType(conv)) { case SLE_VAR_BL: *(bool *)ptr = (val != 0); break; case SLE_VAR_I8: *(int8 *)ptr = val; break; case SLE_VAR_U8: *(byte *)ptr = val; break; case SLE_VAR_I16: *(int16 *)ptr = val; break; case SLE_VAR_U16: *(uint16*)ptr = val; break; case SLE_VAR_I32: *(int32 *)ptr = val; break; case SLE_VAR_U32: *(uint32*)ptr = val; break; case SLE_VAR_I64: *(int64 *)ptr = val; break; case SLE_VAR_U64: *(uint64*)ptr = val; break; case SLE_VAR_NAME: *(char**)ptr = CopyFromOldName(val); break; case SLE_VAR_NULL: break; default: NOT_REACHED(); } } /** * Handle all conversion and typechecking of variables here. * In the case of saving, read in the actual value from the struct * and then write them to file, endian safely. Loading a value * goes exactly the opposite way * @param ptr The object being filled/read * @param conv VarType type of the current element of the struct */ static void SlSaveLoadConv(void *ptr, VarType conv) { switch (_sl.action) { case SLA_SAVE: { int64 x = ReadValue(ptr, conv); /* Write the value to the file and check if its value is in the desired range */ switch (GetVarFileType(conv)) { case SLE_FILE_I8: assert(x >= -128 && x <= 127); SlWriteByte(x);break; case SLE_FILE_U8: assert(x >= 0 && x <= 255); SlWriteByte(x);break; case SLE_FILE_I16:assert(x >= -32768 && x <= 32767); SlWriteUint16(x);break; case SLE_FILE_STRINGID: case SLE_FILE_U16:assert(x >= 0 && x <= 65535); SlWriteUint16(x);break; case SLE_FILE_I32: case SLE_FILE_U32: SlWriteUint32((uint32)x);break; case SLE_FILE_I64: case SLE_FILE_U64: SlWriteUint64(x);break; default: NOT_REACHED(); } break; } case SLA_LOAD_CHECK: case SLA_LOAD: { int64 x; /* Read a value from the file */ switch (GetVarFileType(conv)) { case SLE_FILE_I8: x = (int8 )SlReadByte(); break; case SLE_FILE_U8: x = (byte )SlReadByte(); break; case SLE_FILE_I16: x = (int16 )SlReadUint16(); break; case SLE_FILE_U16: x = (uint16)SlReadUint16(); break; case SLE_FILE_I32: x = (int32 )SlReadUint32(); break; case SLE_FILE_U32: x = (uint32)SlReadUint32(); break; case SLE_FILE_I64: x = (int64 )SlReadUint64(); break; case SLE_FILE_U64: x = (uint64)SlReadUint64(); break; case SLE_FILE_STRINGID: x = RemapOldStringID((uint16)SlReadUint16()); break; default: NOT_REACHED(); } /* Write The value to the struct. These ARE endian safe. */ WriteValue(ptr, conv, x); break; } case SLA_PTRS: break; case SLA_NULL: break; default: NOT_REACHED(); } } /** * Calculate the net length of a string. This is in almost all cases * just strlen(), but if the string is not properly terminated, we'll * resort to the maximum length of the buffer. * @param ptr pointer to the stringbuffer * @param length maximum length of the string (buffer). If -1 we don't care * about a maximum length, but take string length as it is. * @return return the net length of the string */ static inline size_t SlCalcNetStringLen(const char *ptr, size_t length) { if (ptr == NULL) return 0; return min(strlen(ptr), length - 1); } /** * Calculate the gross length of the string that it * will occupy in the savegame. This includes the real length, returned * by SlCalcNetStringLen and the length that the index will occupy. * @param ptr pointer to the stringbuffer * @param length maximum length of the string (buffer size, etc.) * @param conv type of data been used * @return return the gross length of the string */ static inline size_t SlCalcStringLen(const void *ptr, size_t length, VarType conv) { size_t len; const char *str; switch (GetVarMemType(conv)) { default: NOT_REACHED(); case SLE_VAR_STR: case SLE_VAR_STRQ: str = *(const char * const *)ptr; len = SIZE_MAX; break; case SLE_VAR_STRB: case SLE_VAR_STRBQ: str = (const char *)ptr; len = length; break; } len = SlCalcNetStringLen(str, len); return len + SlGetArrayLength(len); // also include the length of the index } /** * Save/Load a string. * @param ptr the string being manipulated * @param length of the string (full length) * @param conv must be SLE_FILE_STRING */ static void SlString(void *ptr, size_t length, VarType conv) { switch (_sl.action) { case SLA_SAVE: { size_t len; switch (GetVarMemType(conv)) { default: NOT_REACHED(); case SLE_VAR_STRB: case SLE_VAR_STRBQ: len = SlCalcNetStringLen((char *)ptr, length); break; case SLE_VAR_STR: case SLE_VAR_STRQ: ptr = *(char **)ptr; len = SlCalcNetStringLen((char *)ptr, SIZE_MAX); break; } SlWriteArrayLength(len); SlCopyBytes(ptr, len); break; } case SLA_LOAD_CHECK: case SLA_LOAD: { size_t len = SlReadArrayLength(); switch (GetVarMemType(conv)) { default: NOT_REACHED(); case SLE_VAR_STRB: case SLE_VAR_STRBQ: if (len >= length) { DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating"); SlCopyBytes(ptr, length); SlSkipBytes(len - length); len = length - 1; } else { SlCopyBytes(ptr, len); } break; case SLE_VAR_STR: case SLE_VAR_STRQ: // Malloc'd string, free previous incarnation, and allocate free(*(char **)ptr); if (len == 0) { *(char **)ptr = NULL; return; } else { *(char **)ptr = MallocT(len + 1); // terminating '\0' ptr = *(char **)ptr; SlCopyBytes(ptr, len); } break; } ((char *)ptr)[len] = '\0'; // properly terminate the string StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK; if ((conv & SLF_ALLOW_CONTROL) != 0) { settings = settings | SVS_ALLOW_CONTROL_CODE; if (IsSavegameVersionBefore(169)) { str_fix_scc_encoded((char *)ptr, (char *)ptr + len); } } if ((conv & SLF_ALLOW_NEWLINE) != 0) { settings = settings | SVS_ALLOW_NEWLINE; } str_validate((char *)ptr, (char *)ptr + len, settings); break; } case SLA_PTRS: break; case SLA_NULL: break; default: NOT_REACHED(); } } /** * Return the size in bytes of a certain type of atomic array * @param length The length of the array counted in elements * @param conv VarType type of the variable that is used in calculating the size */ static inline size_t SlCalcArrayLen(size_t length, VarType conv) { return SlCalcConvFileLen(conv) * length; } /** * Save/Load an array. * @param array The array being manipulated * @param length The length of the array in elements * @param conv VarType type of the atomic array (int, byte, uint64, etc.) */ void SlArray(void *array, size_t length, VarType conv) { if (_sl.action == SLA_PTRS || _sl.action == SLA_NULL) return; /* Automatically calculate the length? */ if (_sl.need_length != NL_NONE) { SlSetLength(SlCalcArrayLen(length, conv)); /* Determine length only? */ if (_sl.need_length == NL_CALCLENGTH) return; } /* NOTICE - handle some buggy stuff, in really old versions everything was saved * as a byte-type. So detect this, and adjust array size accordingly */ if (_sl.action != SLA_SAVE && _sl_version == 0) { /* all arrays except difficulty settings */ if (conv == SLE_INT16 || conv == SLE_UINT16 || conv == SLE_STRINGID || conv == SLE_INT32 || conv == SLE_UINT32) { SlCopyBytes(array, length * SlCalcConvFileLen(conv)); return; } /* used for conversion of Money 32bit->64bit */ if (conv == (SLE_FILE_I32 | SLE_VAR_I64)) { for (uint i = 0; i < length; i++) { ((int64*)array)[i] = (int32)BSWAP32(SlReadUint32()); } return; } } /* If the size of elements is 1 byte both in file and memory, no special * conversion is needed, use specialized copy-copy function to speed up things */ if (conv == SLE_INT8 || conv == SLE_UINT8) { SlCopyBytes(array, length); } else { byte *a = (byte*)array; byte mem_size = SlCalcConvMemLen(conv); for (; length != 0; length --) { SlSaveLoadConv(a, conv); a += mem_size; // get size } } } /** * Pointers cannot be saved to a savegame, so this functions gets * the index of the item, and if not available, it hussles with * pointers (looks really bad :() * Remember that a NULL item has value 0, and all * indices have +1, so vehicle 0 is saved as index 1. * @param obj The object that we want to get the index of * @param rt SLRefType type of the object the index is being sought of * @return Return the pointer converted to an index of the type pointed to */ static size_t ReferenceToInt(const void *obj, SLRefType rt) { assert(_sl.action == SLA_SAVE); if (obj == NULL) return 0; switch (rt) { case REF_VEHICLE_OLD: // Old vehicles we save as new ones case REF_VEHICLE: return ((const Vehicle*)obj)->index + 1; case REF_STATION: return ((const Station*)obj)->index + 1; case REF_TOWN: return ((const Town*)obj)->index + 1; case REF_ORDER: return ((const Order*)obj)->index + 1; case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1; case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1; case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1; case REF_ORDERLIST: return ((const OrderList*)obj)->index + 1; case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1; case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1; case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1; default: NOT_REACHED(); } } /** * Pointers cannot be loaded from a savegame, so this function * gets the index from the savegame and returns the appropriate * pointer from the already loaded base. * Remember that an index of 0 is a NULL pointer so all indices * are +1 so vehicle 0 is saved as 1. * @param index The index that is being converted to a pointer * @param rt SLRefType type of the object the pointer is sought of * @return Return the index converted to a pointer of any type */ static void *IntToReference(size_t index, SLRefType rt) { assert_compile(sizeof(size_t) <= sizeof(void *)); assert(_sl.action == SLA_PTRS); /* After version 4.3 REF_VEHICLE_OLD is saved as REF_VEHICLE, * and should be loaded like that */ if (rt == REF_VEHICLE_OLD && !IsSavegameVersionBefore(4, 4)) { rt = REF_VEHICLE; } /* No need to look up NULL pointers, just return immediately */ if (index == (rt == REF_VEHICLE_OLD ? 0xFFFF : 0)) return NULL; /* Correct index. Old vehicles were saved differently: * invalid vehicle was 0xFFFF, now we use 0x0000 for everything invalid. */ if (rt != REF_VEHICLE_OLD) index--; switch (rt) { case REF_ORDERLIST: if (OrderList::IsValidID(index)) return OrderList::Get(index); SlErrorCorrupt("Referencing invalid OrderList"); case REF_ORDER: if (Order::IsValidID(index)) return Order::Get(index); /* in old versions, invalid order was used to mark end of order list */ if (IsSavegameVersionBefore(5, 2)) return NULL; SlErrorCorrupt("Referencing invalid Order"); case REF_VEHICLE_OLD: case REF_VEHICLE: if (Vehicle::IsValidID(index)) return Vehicle::Get(index); SlErrorCorrupt("Referencing invalid Vehicle"); case REF_STATION: if (Station::IsValidID(index)) return Station::Get(index); SlErrorCorrupt("Referencing invalid Station"); case REF_TOWN: if (Town::IsValidID(index)) return Town::Get(index); SlErrorCorrupt("Referencing invalid Town"); case REF_ROADSTOPS: if (RoadStop::IsValidID(index)) return RoadStop::Get(index); SlErrorCorrupt("Referencing invalid RoadStop"); case REF_ENGINE_RENEWS: if (EngineRenew::IsValidID(index)) return EngineRenew::Get(index); SlErrorCorrupt("Referencing invalid EngineRenew"); case REF_CARGO_PACKET: if (CargoPacket::IsValidID(index)) return CargoPacket::Get(index); SlErrorCorrupt("Referencing invalid CargoPacket"); case REF_STORAGE: if (PersistentStorage::IsValidID(index)) return PersistentStorage::Get(index); SlErrorCorrupt("Referencing invalid PersistentStorage"); case REF_LINK_GRAPH: if (LinkGraph::IsValidID(index)) return LinkGraph::Get(index); SlErrorCorrupt("Referencing invalid LinkGraph"); case REF_LINK_GRAPH_JOB: if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index); SlErrorCorrupt("Referencing invalid LinkGraphJob"); default: NOT_REACHED(); } } /** * Return the size in bytes of a list * @param list The std::list to find the size of */ static inline size_t SlCalcListLen(const void *list) { const std::list *l = (const std::list *) list; int type_size = IsSavegameVersionBefore(69) ? 2 : 4; /* Each entry is saved as type_size bytes, plus type_size bytes are used for the length * of the list */ return l->size() * type_size + type_size; } /** * Save/Load a list. * @param list The list being manipulated * @param conv SLRefType type of the list (Vehicle *, Station *, etc) */ static void SlList(void *list, SLRefType conv) { /* Automatically calculate the length? */ if (_sl.need_length != NL_NONE) { SlSetLength(SlCalcListLen(list)); /* Determine length only? */ if (_sl.need_length == NL_CALCLENGTH) return; } typedef std::list PtrList; PtrList *l = (PtrList *)list; switch (_sl.action) { case SLA_SAVE: { SlWriteUint32((uint32)l->size()); PtrList::iterator iter; for (iter = l->begin(); iter != l->end(); ++iter) { void *ptr = *iter; SlWriteUint32((uint32)ReferenceToInt(ptr, conv)); } break; } case SLA_LOAD_CHECK: case SLA_LOAD: { size_t length = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32(); /* Load each reference and push to the end of the list */ for (size_t i = 0; i < length; i++) { size_t data = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32(); l->push_back((void *)data); } break; } case SLA_PTRS: { PtrList temp = *l; l->clear(); PtrList::iterator iter; for (iter = temp.begin(); iter != temp.end(); ++iter) { void *ptr = IntToReference((size_t)*iter, conv); l->push_back(ptr); } break; } case SLA_NULL: l->clear(); break; default: NOT_REACHED(); } } /** Are we going to save this object or not? */ static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld) { if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false; if (sld->conv & SLF_NOT_IN_SAVE) return false; return true; } /** * Are we going to load this variable when loading a savegame or not? * @note If the variable is skipped it is skipped in the savegame * bytestream itself as well, so there is no need to skip it somewhere else */ static inline bool SlSkipVariableOnLoad(const SaveLoad *sld) { if ((sld->conv & SLF_NO_NETWORK_SYNC) && _sl.action != SLA_SAVE && _networking && !_network_server) { SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length); return true; } return false; } /** * Calculate the size of an object. * @param object to be measured * @param sld The SaveLoad description of the object so we know how to manipulate it * @return size of given object */ size_t SlCalcObjLength(const void *object, const SaveLoad *sld) { size_t length = 0; /* Need to determine the length and write a length tag. */ for (; sld->cmd != SL_END; sld++) { length += SlCalcObjMemberLength(object, sld); } return length; } size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld) { assert(_sl.action == SLA_SAVE); switch (sld->cmd) { case SL_VAR: case SL_REF: case SL_ARR: case SL_STR: case SL_LST: /* CONDITIONAL saveload types depend on the savegame version */ if (!SlIsObjectValidInSavegame(sld)) break; switch (sld->cmd) { case SL_VAR: return SlCalcConvFileLen(sld->conv); case SL_REF: return SlCalcRefLen(); case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv); case SL_STR: return SlCalcStringLen(GetVariableAddress(object, sld), sld->length, sld->conv); case SL_LST: return SlCalcListLen(GetVariableAddress(object, sld)); default: NOT_REACHED(); } break; case SL_WRITEBYTE: return 1; // a byte is logically of size 1 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END)); case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription()); default: NOT_REACHED(); } return 0; } /** * Check whether the variable size of the variable in the saveload configuration * matches with the actual variable size. * @param sld The saveload configuration to test. */ static bool IsVariableSizeRight(const SaveLoad *sld) { switch (sld->cmd) { case SL_VAR: switch (GetVarMemType(sld->conv)) { case SLE_VAR_BL: return sld->size == sizeof(bool); case SLE_VAR_I8: case SLE_VAR_U8: return sld->size == sizeof(int8); case SLE_VAR_I16: case SLE_VAR_U16: return sld->size == sizeof(int16); case SLE_VAR_I32: case SLE_VAR_U32: return sld->size == sizeof(int32); case SLE_VAR_I64: case SLE_VAR_U64: return sld->size == sizeof(int64); default: return sld->size == sizeof(void *); } case SL_REF: /* These should all be pointer sized. */ return sld->size == sizeof(void *); case SL_STR: /* These should be pointer sized, or fixed array. */ return sld->size == sizeof(void *) || sld->size == sld->length; default: return true; } } bool SlObjectMember(void *ptr, const SaveLoad *sld) { assert(IsVariableSizeRight(sld)); VarType conv = GB(sld->conv, 0, 8); switch (sld->cmd) { case SL_VAR: case SL_REF: case SL_ARR: case SL_STR: case SL_LST: /* CONDITIONAL saveload types depend on the savegame version */ if (!SlIsObjectValidInSavegame(sld)) return false; if (SlSkipVariableOnLoad(sld)) return false; switch (sld->cmd) { case SL_VAR: SlSaveLoadConv(ptr, conv); break; case SL_REF: // Reference variable, translate switch (_sl.action) { case SLA_SAVE: SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv)); break; case SLA_LOAD_CHECK: case SLA_LOAD: *(size_t *)ptr = IsSavegameVersionBefore(69) ? SlReadUint16() : SlReadUint32(); break; case SLA_PTRS: *(void **)ptr = IntToReference(*(size_t *)ptr, (SLRefType)conv); break; case SLA_NULL: *(void **)ptr = NULL; break; default: NOT_REACHED(); } break; case SL_ARR: SlArray(ptr, sld->length, conv); break; case SL_STR: SlString(ptr, sld->length, sld->conv); break; case SL_LST: SlList(ptr, (SLRefType)conv); break; default: NOT_REACHED(); } break; /* SL_WRITEBYTE translates a value of a variable to another one upon * saving or loading. * XXX - variable renaming abuse * game_value: the value of the variable ingame is abused by sld->version_from * file_value: the value of the variable in the savegame is abused by sld->version_to */ case SL_WRITEBYTE: switch (_sl.action) { case SLA_SAVE: SlWriteByte(sld->version_to); break; case SLA_LOAD_CHECK: case SLA_LOAD: *(byte *)ptr = sld->version_from; break; case SLA_PTRS: break; case SLA_NULL: break; default: NOT_REACHED(); } break; /* SL_VEH_INCLUDE loads common code for vehicles */ case SL_VEH_INCLUDE: SlObject(ptr, GetVehicleDescription(VEH_END)); break; case SL_ST_INCLUDE: SlObject(ptr, GetBaseStationDescription()); break; default: NOT_REACHED(); } return true; } /** * Main SaveLoad function. * @param object The object that is being saved or loaded * @param sld The SaveLoad description of the object so we know how to manipulate it */ void SlObject(void *object, const SaveLoad *sld) { /* Automatically calculate the length? */ if (_sl.need_length != NL_NONE) { SlSetLength(SlCalcObjLength(object, sld)); if (_sl.need_length == NL_CALCLENGTH) return; } for (; sld->cmd != SL_END; sld++) { void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld); SlObjectMember(ptr, sld); } } /** * Save or Load (a list of) global variables * @param sldg The global variable that is being loaded or saved */ void SlGlobList(const SaveLoadGlobVarList *sldg) { SlObject(NULL, (const SaveLoad*)sldg); } /** * Do something of which I have no idea what it is :P * @param proc The callback procedure that is called * @param arg The variable that will be used for the callback procedure */ void SlAutolength(AutolengthProc *proc, void *arg) { size_t offs; assert(_sl.action == SLA_SAVE); /* Tell it to calculate the length */ _sl.need_length = NL_CALCLENGTH; _sl.obj_len = 0; proc(arg); /* Setup length */ _sl.need_length = NL_WANTLENGTH; SlSetLength(_sl.obj_len); offs = _sl.dumper->GetSize() + _sl.obj_len; /* And write the stuff */ proc(arg); if (offs != _sl.dumper->GetSize()) SlErrorCorrupt("Invalid chunk size"); } /** * Load a chunk of data (eg vehicles, stations, etc.) * @param ch The chunkhandler that will be used for the operation */ static void SlLoadChunk(const ChunkHandler *ch) { byte m = SlReadByte(); size_t len; size_t endoffs; _sl.block_mode = m; _sl.obj_len = 0; switch (m) { case CH_ARRAY: _sl.array_index = 0; ch->load_proc(); break; case CH_SPARSE_ARRAY: ch->load_proc(); break; default: if ((m & 0xF) == CH_RIFF) { /* Read length */ len = (SlReadByte() << 16) | ((m >> 4) << 24); len += SlReadUint16(); _sl.obj_len = len; endoffs = _sl.reader->GetSize() + len; ch->load_proc(); if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size"); } else { SlErrorCorrupt("Invalid chunk type"); } break; } } /** * Load a chunk of data for checking savegames. * If the chunkhandler is NULL, the chunk is skipped. * @param ch The chunkhandler that will be used for the operation */ static void SlLoadCheckChunk(const ChunkHandler *ch) { byte m = SlReadByte(); size_t len; size_t endoffs; _sl.block_mode = m; _sl.obj_len = 0; switch (m) { case CH_ARRAY: _sl.array_index = 0; if (ch->load_check_proc) { ch->load_check_proc(); } else { SlSkipArray(); } break; case CH_SPARSE_ARRAY: if (ch->load_check_proc) { ch->load_check_proc(); } else { SlSkipArray(); } break; default: if ((m & 0xF) == CH_RIFF) { /* Read length */ len = (SlReadByte() << 16) | ((m >> 4) << 24); len += SlReadUint16(); _sl.obj_len = len; endoffs = _sl.reader->GetSize() + len; if (ch->load_check_proc) { ch->load_check_proc(); } else { SlSkipBytes(len); } if (_sl.reader->GetSize() != endoffs) SlErrorCorrupt("Invalid chunk size"); } else { SlErrorCorrupt("Invalid chunk type"); } break; } } /** * Stub Chunk handlers to only calculate length and do nothing else. * The intended chunk handler that should be called. */ static ChunkSaveLoadProc *_stub_save_proc; /** * Stub Chunk handlers to only calculate length and do nothing else. * Actually call the intended chunk handler. * @param arg ignored parameter. */ static inline void SlStubSaveProc2(void *arg) { _stub_save_proc(); } /** * Stub Chunk handlers to only calculate length and do nothing else. * Call SlAutoLenth with our stub save proc that will eventually * call the intended chunk handler. */ static void SlStubSaveProc() { SlAutolength(SlStubSaveProc2, NULL); } /** * Save a chunk of data (eg. vehicles, stations, etc.). Each chunk is * prefixed by an ID identifying it, followed by data, and terminator where appropriate * @param ch The chunkhandler that will be used for the operation */ static void SlSaveChunk(const ChunkHandler *ch) { ChunkSaveLoadProc *proc = ch->save_proc; /* Don't save any chunk information if there is no save handler. */ if (proc == NULL) return; SlWriteUint32(ch->id); DEBUG(sl, 2, "Saving chunk %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id); if (ch->flags & CH_AUTO_LENGTH) { /* Need to calculate the length. Solve that by calling SlAutoLength in the save_proc. */ _stub_save_proc = proc; proc = SlStubSaveProc; } _sl.block_mode = ch->flags & CH_TYPE_MASK; switch (ch->flags & CH_TYPE_MASK) { case CH_RIFF: _sl.need_length = NL_WANTLENGTH; proc(); break; case CH_ARRAY: _sl.last_array_index = 0; SlWriteByte(CH_ARRAY); proc(); SlWriteArrayLength(0); // Terminate arrays break; case CH_SPARSE_ARRAY: SlWriteByte(CH_SPARSE_ARRAY); proc(); SlWriteArrayLength(0); // Terminate arrays break; default: NOT_REACHED(); } } /** Save all chunks */ static void SlSaveChunks() { FOR_ALL_CHUNK_HANDLERS(ch) { SlSaveChunk(ch); } /* Terminator */ SlWriteUint32(0); } /** * Find the ChunkHandler that will be used for processing the found * chunk in the savegame or in memory * @param id the chunk in question * @return returns the appropriate chunkhandler */ static const ChunkHandler *SlFindChunkHandler(uint32 id) { FOR_ALL_CHUNK_HANDLERS(ch) if (ch->id == id) return ch; return NULL; } /** Load all chunks */ static void SlLoadChunks() { uint32 id; const ChunkHandler *ch; for (id = SlReadUint32(); id != 0; id = SlReadUint32()) { DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); ch = SlFindChunkHandler(id); if (ch == NULL) SlErrorCorrupt("Unknown chunk type"); SlLoadChunk(ch); } } /** Load all chunks for savegame checking */ static void SlLoadCheckChunks() { uint32 id; const ChunkHandler *ch; for (id = SlReadUint32(); id != 0; id = SlReadUint32()) { DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id); ch = SlFindChunkHandler(id); if (ch == NULL) SlErrorCorrupt("Unknown chunk type"); SlLoadCheckChunk(ch); } } /** Fix all pointers (convert index -> pointer) */ static void SlFixPointers() { _sl.action = SLA_PTRS; DEBUG(sl, 1, "Fixing pointers"); FOR_ALL_CHUNK_HANDLERS(ch) { if (ch->ptrs_proc != NULL) { DEBUG(sl, 2, "Fixing pointers for %c%c%c%c", ch->id >> 24, ch->id >> 16, ch->id >> 8, ch->id); ch->ptrs_proc(); } } DEBUG(sl, 1, "All pointers fixed"); assert(_sl.action == SLA_PTRS); } /** Yes, simply reading from a file. */ struct FileReader : LoadFilter { FILE *file; ///< The file to read from. long begin; ///< The begin of the file. /** * Create the file reader, so it reads from a specific file. * @param file The file to read from. */ FileReader(FILE *file) : LoadFilter(NULL), file(file), begin(ftell(file)) { } /** Make sure everything is cleaned up. */ ~FileReader() { if (this->file != NULL) fclose(this->file); this->file = NULL; /* Make sure we don't double free. */ _sl.sf = NULL; } /* virtual */ size_t Read(byte *buf, size_t size) { /* We're in the process of shutting down, i.e. in "failure" mode. */ if (this->file == NULL) return 0; return fread(buf, 1, size, this->file); } /* virtual */ void Reset() { clearerr(this->file); if (fseek(this->file, this->begin, SEEK_SET)) { DEBUG(sl, 1, "Could not reset the file reading"); } } }; /** Yes, simply writing to a file. */ struct FileWriter : SaveFilter { FILE *file; ///< The file to write to. /** * Create the file writer, so it writes to a specific file. * @param file The file to write to. */ FileWriter(FILE *file) : SaveFilter(NULL), file(file) { } /** Make sure everything is cleaned up. */ ~FileWriter() { this->Finish(); /* Make sure we don't double free. */ _sl.sf = NULL; } /* virtual */ void Write(byte *buf, size_t size) { /* We're in the process of shutting down, i.e. in "failure" mode. */ if (this->file == NULL) return; if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE); } /* virtual */ void Finish() { if (this->file != NULL) fclose(this->file); this->file = NULL; } }; /******************************************* ********** START OF LZO CODE ************** *******************************************/ #ifdef WITH_LZO #include /** Buffer size for the LZO compressor */ static const uint LZO_BUFFER_SIZE = 8192; /** Filter using LZO compression. */ struct LZOLoadFilter : LoadFilter { /** * Initialise this filter. * @param chain The next filter in this chain. */ LZOLoadFilter(LoadFilter *chain) : LoadFilter(chain) { if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor"); } /* virtual */ size_t Read(byte *buf, size_t ssize) { assert(ssize >= LZO_BUFFER_SIZE); /* Buffer size is from the LZO docs plus the chunk header size. */ byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2]; uint32 tmp[2]; uint32 size; lzo_uint len; /* Read header*/ if (this->chain->Read((byte*)tmp, sizeof(tmp)) != sizeof(tmp)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE, "File read failed"); /* Check if size is bad */ ((uint32*)out)[0] = size = tmp[1]; if (_sl_version != 0) { tmp[0] = TO_BE32(tmp[0]); size = TO_BE32(size); } if (size >= sizeof(out)) SlErrorCorrupt("Inconsistent size"); /* Read block */ if (this->chain->Read(out + sizeof(uint32), size) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); /* Verify checksum */ if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum"); /* Decompress */ lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL); return len; } }; /** Filter using LZO compression. */ struct LZOSaveFilter : SaveFilter { /** * Initialise this filter. * @param chain The next filter in this chain. * @param compression_level The requested level of compression. */ LZOSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain) { if (lzo_init() != LZO_E_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor"); } /* virtual */ void Write(byte *buf, size_t size) { const lzo_bytep in = buf; /* Buffer size is from the LZO docs plus the chunk header size. */ byte out[LZO_BUFFER_SIZE + LZO_BUFFER_SIZE / 16 + 64 + 3 + sizeof(uint32) * 2]; byte wrkmem[LZO1X_1_MEM_COMPRESS]; lzo_uint outlen; do { /* Compress up to LZO_BUFFER_SIZE bytes at once. */ lzo_uint len = size > LZO_BUFFER_SIZE ? LZO_BUFFER_SIZE : (lzo_uint)size; lzo1x_1_compress(in, len, out + sizeof(uint32) * 2, &outlen, wrkmem); ((uint32*)out)[1] = TO_BE32((uint32)outlen); ((uint32*)out)[0] = TO_BE32(lzo_adler32(0, out + sizeof(uint32), outlen + sizeof(uint32))); this->chain->Write(out, outlen + sizeof(uint32) * 2); /* Move to next data chunk. */ size -= len; in += len; } while (size > 0); } }; #endif /* WITH_LZO */ /********************************************* ******** START OF NOCOMP CODE (uncompressed)* *********************************************/ /** Filter without any compression. */ struct NoCompLoadFilter : LoadFilter { /** * Initialise this filter. * @param chain The next filter in this chain. */ NoCompLoadFilter(LoadFilter *chain) : LoadFilter(chain) { } /* virtual */ size_t Read(byte *buf, size_t size) { return this->chain->Read(buf, size); } }; /** Filter without any compression. */ struct NoCompSaveFilter : SaveFilter { /** * Initialise this filter. * @param chain The next filter in this chain. * @param compression_level The requested level of compression. */ NoCompSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain) { } /* virtual */ void Write(byte *buf, size_t size) { this->chain->Write(buf, size); } }; /******************************************** ********** START OF ZLIB CODE ************** ********************************************/ #if defined(WITH_ZLIB) #include /** Filter using Zlib compression. */ struct ZlibLoadFilter : LoadFilter { z_stream z; ///< Stream state we are reading from. byte fread_buf[MEMORY_CHUNK_SIZE]; ///< Buffer for reading from the file. /** * Initialise this filter. * @param chain The next filter in this chain. */ ZlibLoadFilter(LoadFilter *chain) : LoadFilter(chain) { memset(&this->z, 0, sizeof(this->z)); if (inflateInit(&this->z) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor"); } /** Clean everything up. */ ~ZlibLoadFilter() { inflateEnd(&this->z); } /* virtual */ size_t Read(byte *buf, size_t size) { this->z.next_out = buf; this->z.avail_out = (uint)size; do { /* read more bytes from the file? */ if (this->z.avail_in == 0) { this->z.next_in = this->fread_buf; this->z.avail_in = (uint)this->chain->Read(this->fread_buf, sizeof(this->fread_buf)); } /* inflate the data */ int r = inflate(&this->z, 0); if (r == Z_STREAM_END) break; if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "inflate() failed"); } while (this->z.avail_out != 0); return size - this->z.avail_out; } }; /** Filter using Zlib compression. */ struct ZlibSaveFilter : SaveFilter { z_stream z; ///< Stream state we are writing to. /** * Initialise this filter. * @param chain The next filter in this chain. * @param compression_level The requested level of compression. */ ZlibSaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain) { memset(&this->z, 0, sizeof(this->z)); if (deflateInit(&this->z, compression_level) != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor"); } /** Clean up what we allocated. */ ~ZlibSaveFilter() { deflateEnd(&this->z); } /** * Helper loop for writing the data. * @param p The bytes to write. * @param len Amount of bytes to write. * @param mode Mode for deflate. */ void WriteLoop(byte *p, size_t len, int mode) { byte buf[MEMORY_CHUNK_SIZE]; // output buffer uint n; this->z.next_in = p; this->z.avail_in = (uInt)len; do { this->z.next_out = buf; this->z.avail_out = sizeof(buf); /** * For the poor next soul who sees many valgrind warnings of the * "Conditional jump or move depends on uninitialised value(s)" kind: * According to the author of zlib it is not a bug and it won't be fixed. * http://groups.google.com/group/comp.compression/browse_thread/thread/b154b8def8c2a3ef/cdf9b8729ce17ee2 * [Mark Adler, Feb 24 2004, 'zlib-1.2.1 valgrind warnings' in the newsgroup comp.compression] */ int r = deflate(&this->z, mode); /* bytes were emitted? */ if ((n = sizeof(buf) - this->z.avail_out) != 0) { this->chain->Write(buf, n); } if (r == Z_STREAM_END) break; if (r != Z_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "zlib returned error code"); } while (this->z.avail_in || !this->z.avail_out); } /* virtual */ void Write(byte *buf, size_t size) { this->WriteLoop(buf, size, 0); } /* virtual */ void Finish() { this->WriteLoop(NULL, 0, Z_FINISH); this->chain->Finish(); } }; #endif /* WITH_ZLIB */ /******************************************** ********** START OF LZMA CODE ************** ********************************************/ #if defined(WITH_LZMA) #include /** * Have a copy of an initialised LZMA stream. We need this as it's * impossible to "re"-assign LZMA_STREAM_INIT to a variable in some * compilers, i.e. LZMA_STREAM_INIT can't be used to set something. * This var has to be used instead. */ static const lzma_stream _lzma_init = LZMA_STREAM_INIT; /** Filter without any compression. */ struct LZMALoadFilter : LoadFilter { lzma_stream lzma; ///< Stream state that we are reading from. byte fread_buf[MEMORY_CHUNK_SIZE]; ///< Buffer for reading from the file. /** * Initialise this filter. * @param chain The next filter in this chain. */ LZMALoadFilter(LoadFilter *chain) : LoadFilter(chain), lzma(_lzma_init) { /* Allow saves up to 256 MB uncompressed */ if (lzma_auto_decoder(&this->lzma, 1 << 28, 0) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize decompressor"); } /** Clean everything up. */ ~LZMALoadFilter() { lzma_end(&this->lzma); } /* virtual */ size_t Read(byte *buf, size_t size) { this->lzma.next_out = buf; this->lzma.avail_out = size; do { /* read more bytes from the file? */ if (this->lzma.avail_in == 0) { this->lzma.next_in = this->fread_buf; this->lzma.avail_in = this->chain->Read(this->fread_buf, sizeof(this->fread_buf)); } /* inflate the data */ lzma_ret r = lzma_code(&this->lzma, LZMA_RUN); if (r == LZMA_STREAM_END) break; if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code"); } while (this->lzma.avail_out != 0); return size - this->lzma.avail_out; } }; /** Filter using LZMA compression. */ struct LZMASaveFilter : SaveFilter { lzma_stream lzma; ///< Stream state that we are writing to. /** * Initialise this filter. * @param chain The next filter in this chain. * @param compression_level The requested level of compression. */ LZMASaveFilter(SaveFilter *chain, byte compression_level) : SaveFilter(chain), lzma(_lzma_init) { if (lzma_easy_encoder(&this->lzma, compression_level, LZMA_CHECK_CRC32) != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "cannot initialize compressor"); } /** Clean up what we allocated. */ ~LZMASaveFilter() { lzma_end(&this->lzma); } /** * Helper loop for writing the data. * @param p The bytes to write. * @param len Amount of bytes to write. * @param action Action for lzma_code. */ void WriteLoop(byte *p, size_t len, lzma_action action) { byte buf[MEMORY_CHUNK_SIZE]; // output buffer size_t n; this->lzma.next_in = p; this->lzma.avail_in = len; do { this->lzma.next_out = buf; this->lzma.avail_out = sizeof(buf); lzma_ret r = lzma_code(&this->lzma, action); /* bytes were emitted? */ if ((n = sizeof(buf) - this->lzma.avail_out) != 0) { this->chain->Write(buf, n); } if (r == LZMA_STREAM_END) break; if (r != LZMA_OK) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, "liblzma returned error code"); } while (this->lzma.avail_in || !this->lzma.avail_out); } /* virtual */ void Write(byte *buf, size_t size) { this->WriteLoop(buf, size, LZMA_RUN); } /* virtual */ void Finish() { this->WriteLoop(NULL, 0, LZMA_FINISH); this->chain->Finish(); } }; #endif /* WITH_LZMA */ /******************************************* ************* END OF CODE ***************** *******************************************/ /** The format for a reader/writer type of a savegame */ struct SaveLoadFormat { const char *name; ///< name of the compressor/decompressor (debug-only) uint32 tag; ///< the 4-letter tag by which it is identified in the savegame LoadFilter *(*init_load)(LoadFilter *chain); ///< Constructor for the load filter. SaveFilter *(*init_write)(SaveFilter *chain, byte compression); ///< Constructor for the save filter. byte min_compression; ///< the minimum compression level of this format byte default_compression; ///< the default compression level of this format byte max_compression; ///< the maximum compression level of this format }; /** The different saveload formats known/understood by OpenTTD. */ static const SaveLoadFormat _saveload_formats[] = { #if defined(WITH_LZO) /* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */ {"lzo", TO_BE32X('OTTD'), CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, #else {"lzo", TO_BE32X('OTTD'), NULL, NULL, 0, 0, 0}, #endif /* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */ {"none", TO_BE32X('OTTN'), CreateLoadFilter, CreateSaveFilter, 0, 0, 0}, #if defined(WITH_ZLIB) /* After level 6 the speed reduction is significant (1.5x to 2.5x slower per level), but the reduction in filesize is * fairly insignificant (~1% for each step). Lower levels become ~5-10% bigger by each level than level 6 while level * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */ {"zlib", TO_BE32X('OTTZ'), CreateLoadFilter, CreateSaveFilter, 0, 6, 9}, #else {"zlib", TO_BE32X('OTTZ'), NULL, NULL, 0, 0, 0}, #endif #if defined(WITH_LZMA) /* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves. * Higher compression levels are possible, and might improve savegame size by up to 25%, but are also up to 10 times slower. * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50% * slower while not improving the filesize, while level 0 and 1 are faster, but don't reduce savegame size much. * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is preferred over .tar.lzma. */ {"lzma", TO_BE32X('OTTX'), CreateLoadFilter, CreateSaveFilter, 0, 2, 9}, #else {"lzma", TO_BE32X('OTTX'), NULL, NULL, 0, 0, 0}, #endif }; /** * Return the savegameformat of the game. Whether it was created with ZLIB compression * uncompressed, or another type * @param s Name of the savegame format. If NULL it picks the first available one * @param compression_level Output for telling what compression level we want. * @return Pointer to SaveLoadFormat struct giving all characteristics of this type of savegame */ static const SaveLoadFormat *GetSavegameFormat(char *s, byte *compression_level) { const SaveLoadFormat *def = lastof(_saveload_formats); /* find default savegame format, the highest one with which files can be written */ while (!def->init_write) def--; if (!StrEmpty(s)) { /* Get the ":..." of the compression level out of the way */ char *complevel = strrchr(s, ':'); if (complevel != NULL) *complevel = '\0'; for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) { if (slf->init_write != NULL && strcmp(s, slf->name) == 0) { *compression_level = slf->default_compression; if (complevel != NULL) { /* There is a compression level in the string. * First restore the : we removed to do proper name matching, * then move the the begin of the actual version. */ *complevel = ':'; complevel++; /* Get the version and determine whether all went fine. */ char *end; long level = strtol(complevel, &end, 10); if (end == complevel || level != Clamp(level, slf->min_compression, slf->max_compression)) { SetDParamStr(0, complevel); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL, WL_CRITICAL); } else { *compression_level = level; } } return slf; } } SetDParamStr(0, s); SetDParamStr(1, def->name); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM, WL_CRITICAL); /* Restore the string by adding the : back */ if (complevel != NULL) *complevel = ':'; } *compression_level = def->default_compression; return def; } /* actual loader/saver function */ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings); extern bool AfterLoadGame(); extern bool LoadOldSaveGame(const char *file); /** * Clear/free saveload state. */ static inline void ClearSaveLoadState() { delete _sl.dumper; _sl.dumper = NULL; delete _sl.sf; _sl.sf = NULL; delete _sl.reader; _sl.reader = NULL; delete _sl.lf; _sl.lf = NULL; } /** * Update the gui accordingly when starting saving * and set locks on saveload. Also turn off fast-forward cause with that * saving takes Aaaaages */ static void SaveFileStart() { _sl.ff_state = _fast_forward; _fast_forward = 0; if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE); InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START); _sl.saveinprogress = true; } /** Update the gui accordingly when saving is done and release locks on saveload. */ static void SaveFileDone() { if (_game_mode != GM_MENU) _fast_forward = _sl.ff_state; if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE); InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH); _sl.saveinprogress = false; } /** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */ void SetSaveLoadError(StringID str) { _sl.error_str = str; } /** Get the string representation of the error message */ const char *GetSaveLoadErrorString() { SetDParam(0, _sl.error_str); SetDParamStr(1, _sl.extra_msg); static char err_str[512]; GetString(err_str, _sl.action == SLA_SAVE ? STR_ERROR_GAME_SAVE_FAILED : STR_ERROR_GAME_LOAD_FAILED, lastof(err_str)); return err_str; } /** Show a gui message when saving has failed */ static void SaveFileError() { SetDParamStr(0, GetSaveLoadErrorString()); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); SaveFileDone(); } /** * We have written the whole game into memory, _memory_savegame, now find * and appropriate compressor and start writing to file. */ static SaveOrLoadResult SaveFileToDisk(bool threaded) { try { byte compression; const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression); /* We have written our stuff to memory, now write it to file! */ uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) }; _sl.sf->Write((byte*)hdr, sizeof(hdr)); _sl.sf = fmt->init_write(_sl.sf, compression); _sl.dumper->Flush(_sl.sf); ClearSaveLoadState(); if (threaded) SetAsyncSaveFinish(SaveFileDone); return SL_OK; } catch (...) { ClearSaveLoadState(); AsyncSaveFinishProc asfp = SaveFileDone; /* We don't want to shout when saving is just * cancelled due to a client disconnecting. */ if (_sl.error_str != STR_NETWORK_ERROR_LOSTCONNECTION) { /* Skip the "colour" character */ DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3); asfp = SaveFileError; } if (threaded) { SetAsyncSaveFinish(asfp); } else { asfp(); } return SL_ERROR; } } /** Thread run function for saving the file to disk. */ static void SaveFileToDiskThread(void *arg) { SaveFileToDisk(true); } void WaitTillSaved() { if (_save_thread == NULL) return; _save_thread->Join(); delete _save_thread; _save_thread = NULL; /* Make sure every other state is handled properly as well. */ ProcessAsyncSaveFinish(); } /** * Actually perform the saving of the savegame. * General tactics is to first save the game to memory, then write it to file * using the writer, either in threaded mode if possible, or single-threaded. * @param writer The filter to write the savegame to. * @param threaded Whether to try to perform the saving asynchronously. * @return Return the result of the action. #SL_OK or #SL_ERROR */ static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded) { assert(!_sl.saveinprogress); _sl.dumper = new MemoryDumper(); _sl.sf = writer; _sl_version = SAVEGAME_VERSION; SaveViewportBeforeSaveGame(); SlSaveChunks(); SaveFileStart(); if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread)) { if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode..."); SaveOrLoadResult result = SaveFileToDisk(false); SaveFileDone(); return result; } return SL_OK; } /** * Save the game using a (writer) filter. * @param writer The filter to write the savegame to. * @param threaded Whether to try to perform the saving asynchronously. * @return Return the result of the action. #SL_OK or #SL_ERROR */ SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded) { try { _sl.action = SLA_SAVE; return DoSave(writer, threaded); } catch (...) { ClearSaveLoadState(); return SL_ERROR; } } /** * Actually perform the loading of a "non-old" savegame. * @param reader The filter to read the savegame from. * @param load_check Whether to perform the checking ("preview") or actually load the game. * @return Return the result of the action. #SL_OK or #SL_REINIT ("unload" the game) */ static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check) { _sl.lf = reader; if (load_check) { /* Clear previous check data */ _load_check_data.Clear(); /* Mark SL_LOAD_CHECK as supported for this savegame. */ _load_check_data.checkable = true; } uint32 hdr[2]; if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); /* see if we have any loader for this type. */ const SaveLoadFormat *fmt = _saveload_formats; for (;;) { /* No loader found, treat as version 0 and use LZO format */ if (fmt == endof(_saveload_formats)) { DEBUG(sl, 0, "Unknown savegame type, trying to load it as the buggy format"); _sl.lf->Reset(); _sl_version = 0; _sl_minor_version = 0; /* Try to find the LZO savegame format; it uses 'OTTD' as tag. */ fmt = _saveload_formats; for (;;) { if (fmt == endof(_saveload_formats)) { /* Who removed LZO support? Bad bad boy! */ NOT_REACHED(); } if (fmt->tag == TO_BE32X('OTTD')) break; fmt++; } break; } if (fmt->tag == hdr[0]) { /* check version number */ _sl_version = TO_BE32(hdr[1]) >> 16; /* Minor is not used anymore from version 18.0, but it is still needed * in versions before that (4 cases) which can't be removed easy. * Therefore it is loaded, but never saved (or, it saves a 0 in any scenario). */ _sl_minor_version = (TO_BE32(hdr[1]) >> 8) & 0xFF; DEBUG(sl, 1, "Loading savegame version %d", _sl_version); /* Is the version higher than the current? */ if (_sl_version > SAVEGAME_VERSION) SlError(STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME); break; } fmt++; } /* loader for this savegame type is not implemented? */ if (fmt->init_load == NULL) { char err_str[64]; seprintf(err_str, lastof(err_str), "Loader for '%s' is not available.", fmt->name); SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str); } _sl.lf = fmt->init_load(_sl.lf); _sl.reader = new ReadBuffer(_sl.lf); _next_offs = 0; if (!load_check) { /* Old maps were hardcoded to 256x256 and thus did not contain * any mapsize information. Pre-initialize to 256x256 to not to * confuse old games */ InitializeGame(256, 256, true, true); GamelogReset(); if (IsSavegameVersionBefore(4)) { /* * NewGRFs were introduced between 0.3,4 and 0.3.5, which both * shared savegame version 4. Anything before that 'obviously' * does not have any NewGRFs. Between the introduction and * savegame version 41 (just before 0.5) the NewGRF settings * were not stored in the savegame and they were loaded by * using the settings from the main menu. * So, to recap: * - savegame version < 4: do not load any NewGRFs. * - savegame version >= 41: load NewGRFs from savegame, which is * already done at this stage by * overwriting the main menu settings. * - other savegame versions: use main menu settings. * * This means that users *can* crash savegame version 4..40 * savegames if they set incompatible NewGRFs in the main menu, * but can't crash anymore for savegame version < 4 savegames. * * Note: this is done here because AfterLoadGame is also called * for TTO/TTD/TTDP savegames which have their own NewGRF logic. */ ClearGRFConfigList(&_grfconfig); } } if (load_check) { /* Load chunks into _load_check_data. * No pools are loaded. References are not possible, and thus do not need resolving. */ SlLoadCheckChunks(); } else { /* Load chunks and resolve references */ SlLoadChunks(); SlFixPointers(); } ClearSaveLoadState(); _savegame_type = SGT_OTTD; if (load_check) { /* The only part from AfterLoadGame() we need */ _load_check_data.grf_compatibility = IsGoodGRFConfigList(_load_check_data.grfconfig); } else { GamelogStartAction(GLAT_LOAD); /* After loading fix up savegame for any internal changes that * might have occurred since then. If it fails, load back the old game. */ if (!AfterLoadGame()) { GamelogStopAction(); return SL_REINIT; } GamelogStopAction(); } return SL_OK; } /** * Load the game using a (reader) filter. * @param reader The filter to read the savegame from. * @return Return the result of the action. #SL_OK or #SL_REINIT ("unload" the game) */ SaveOrLoadResult LoadWithFilter(LoadFilter *reader) { try { _sl.action = SLA_LOAD; return DoLoad(reader, false); } catch (...) { ClearSaveLoadState(); return SL_REINIT; } } /** * Main Save or Load function where the high-level saveload functions are * handled. It opens the savegame, selects format and checks versions * @param filename The name of the savegame being created/loaded * @param mode Save or load mode. Load can also be a TTD(Patch) game. Use #SL_LOAD, #SL_OLD_LOAD, #SL_LOAD_CHECK, or #SL_SAVE. * @param sb The sub directory to save the savegame in * @param threaded True when threaded saving is allowed * @return Return the result of the action. #SL_OK, #SL_ERROR, or #SL_REINIT ("unload" the game) */ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, bool threaded) { /* An instance of saving is already active, so don't go saving again */ if (_sl.saveinprogress && mode == SL_SAVE && threaded) { /* if not an autosave, but a user action, show error message */ if (!_do_autosave) ShowErrorMessage(STR_ERROR_SAVE_STILL_IN_PROGRESS, INVALID_STRING_ID, WL_ERROR); return SL_OK; } WaitTillSaved(); try { /* Load a TTDLX or TTDPatch game */ if (mode == SL_OLD_LOAD) { InitializeGame(256, 256, true, true); // set a mapsize of 256x256 for TTDPatch games or it might get confused /* TTD/TTO savegames have no NewGRFs, TTDP savegame have them * and if so a new NewGRF list will be made in LoadOldSaveGame. * Note: this is done here because AfterLoadGame is also called * for OTTD savegames which have their own NewGRF logic. */ ClearGRFConfigList(&_grfconfig); GamelogReset(); if (!LoadOldSaveGame(filename)) return SL_REINIT; _sl_version = 0; _sl_minor_version = 0; GamelogStartAction(GLAT_LOAD); if (!AfterLoadGame()) { GamelogStopAction(); return SL_REINIT; } GamelogStopAction(); return SL_OK; } switch (mode) { case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break; case SL_LOAD: _sl.action = SLA_LOAD; break; case SL_SAVE: _sl.action = SLA_SAVE; break; default: NOT_REACHED(); } FILE *fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb); /* Make it a little easier to load savegames from the console */ if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR); if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR); if (fh == NULL && mode != SL_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR); if (fh == NULL) { SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE); } if (mode == SL_SAVE) { // SAVE game DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename); if (_network_server || !_settings_client.gui.threaded_saves) threaded = false; return DoSave(new FileWriter(fh), threaded); } /* LOAD game */ assert(mode == SL_LOAD || mode == SL_LOAD_CHECK); DEBUG(desync, 1, "load: %s", filename); return DoLoad(new FileReader(fh), mode == SL_LOAD_CHECK); } catch (...) { ClearSaveLoadState(); /* Skip the "colour" character */ if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3); /* A saver/loader exception!! reinitialize all variables to prevent crash! */ return (mode == SL_LOAD || mode == SL_OLD_LOAD) ? SL_REINIT : SL_ERROR; } } /** Do a save when exiting the game (_settings_client.gui.autosave_on_exit) */ void DoExitSave() { SaveOrLoad("exit.sav", SL_SAVE, AUTOSAVE_DIR); } /** * Fill the buffer with the default name for a savegame *or* screenshot. * @param buf the buffer to write to. * @param last the last element in the buffer. */ void GenerateDefaultSaveName(char *buf, const char *last) { /* Check if we have a name for this map, which is the name of the first * available company. When there's no company available we'll use * 'Spectator' as "company" name. */ CompanyID cid = _local_company; if (!Company::IsValidID(cid)) { const Company *c; FOR_ALL_COMPANIES(c) { cid = c->index; break; } } SetDParam(0, cid); /* Insert current date */ switch (_settings_client.gui.date_format_in_default_names) { case 0: SetDParam(1, STR_JUST_DATE_LONG); break; case 1: SetDParam(1, STR_JUST_DATE_TINY); break; case 2: SetDParam(1, STR_JUST_DATE_ISO); break; default: NOT_REACHED(); } SetDParam(2, _date); /* Get the correct string (special string for when there's not company) */ GetString(buf, !Company::IsValidID(cid) ? STR_SAVEGAME_NAME_SPECTATOR : STR_SAVEGAME_NAME_DEFAULT, last); SanitizeFilename(buf); } #if 0 /** * Function to get the type of the savegame by looking at the file header. * NOTICE: Not used right now, but could be used if extensions of savegames are garbled * @param file Savegame to be checked * @return SL_OLD_LOAD or SL_LOAD of the file */ int GetSavegameType(char *file) { const SaveLoadFormat *fmt; uint32 hdr; FILE *f; int mode = SL_OLD_LOAD; f = fopen(file, "rb"); if (fread(&hdr, sizeof(hdr), 1, f) != 1) { DEBUG(sl, 0, "Savegame is obsolete or invalid format"); mode = SL_LOAD; // don't try to get filename, just show name as it is written } else { /* see if we have any loader for this type. */ for (fmt = _saveload_formats; fmt != endof(_saveload_formats); fmt++) { if (fmt->tag == hdr) { mode = SL_LOAD; // new type of savegame break; } } } fclose(f); return mode; } #endif openttd-1.5.3/src/terraform_cmd.cpp0000644000000000000000000004133412627373442016031 0ustar rootroot/* $Id: terraform_cmd.cpp 26902 2014-09-21 17:37:30Z rubidium $ */ /* * 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 terraform_cmd.cpp Commands related to terraforming. */ #include "stdafx.h" #include "command_func.h" #include "tunnel_map.h" #include "bridge_map.h" #include "viewport_func.h" #include "genworld.h" #include "object_base.h" #include "company_base.h" #include "company_func.h" #include "table/strings.h" #include #include #include "safeguards.h" /** Set of tiles. */ typedef std::set TileIndexSet; /** Mapping of tiles to their height. */ typedef std::map TileIndexToHeightMap; /** State of the terraforming. */ struct TerraformerState { TileIndexSet dirty_tiles; ///< The tiles that need to be redrawn. TileIndexToHeightMap tile_to_new_height; ///< The tiles for which the height has changed. }; TileIndex _terraform_err_tile; ///< first tile we couldn't terraform /** * Gets the TileHeight (height of north corner) of a tile as of current terraforming progress. * * @param ts TerraformerState. * @param tile Tile. * @return TileHeight. */ static int TerraformGetHeightOfTile(const TerraformerState *ts, TileIndex tile) { TileIndexToHeightMap::const_iterator it = ts->tile_to_new_height.find(tile); return it != ts->tile_to_new_height.end() ? it->second : TileHeight(tile); } /** * Stores the TileHeight (height of north corner) of a tile in a TerraformerState. * * @param ts TerraformerState. * @param tile Tile. * @param height New TileHeight. */ static void TerraformSetHeightOfTile(TerraformerState *ts, TileIndex tile, int height) { ts->tile_to_new_height[tile] = height; } /** * Adds a tile to the "tile_table" in a TerraformerState. * * @param ts TerraformerState. * @param tile Tile. * @ingroup dirty */ static void TerraformAddDirtyTile(TerraformerState *ts, TileIndex tile) { ts->dirty_tiles.insert(tile); } /** * Adds all tiles that incident with the north corner of a specific tile to the "tile_table" in a TerraformerState. * * @param ts TerraformerState. * @param tile Tile. * @ingroup dirty */ static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile) { /* Make sure all tiles passed to TerraformAddDirtyTile are within [0, MapSize()] */ if (TileY(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1)); if (TileY(tile) >= 1 && TileX(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1)); if (TileX(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, 0)); TerraformAddDirtyTile(ts, tile); } /** * Terraform the north corner of a tile to a specific height. * * @param ts TerraformerState. * @param tile Tile. * @param height Aimed height. * @return Error code or cost. */ static CommandCost TerraformTileHeight(TerraformerState *ts, TileIndex tile, int height) { assert(tile < MapSize()); /* Check range of destination height */ if (height < 0) return_cmd_error(STR_ERROR_ALREADY_AT_SEA_LEVEL); if (height > _settings_game.construction.max_heightlevel) return_cmd_error(STR_ERROR_TOO_HIGH); /* * Check if the terraforming has any effect. * This can only be true, if multiple corners of the start-tile are terraformed (i.e. the terraforming is done by towns/industries etc.). * In this case the terraforming should fail. (Don't know why.) */ if (height == TerraformGetHeightOfTile(ts, tile)) return CMD_ERROR; /* Check "too close to edge of map". Only possible when freeform-edges is off. */ uint x = TileX(tile); uint y = TileY(tile); if (!_settings_game.construction.freeform_edges && ((x <= 1) || (y <= 1) || (x >= MapMaxX() - 1) || (y >= MapMaxY() - 1))) { /* * Determine a sensible error tile */ if (x == 1) x = 0; if (y == 1) y = 0; _terraform_err_tile = TileXY(x, y); return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP); } /* Mark incident tiles that are involved in the terraforming. */ TerraformAddDirtyTileAround(ts, tile); /* Store the height modification */ TerraformSetHeightOfTile(ts, tile, height); CommandCost total_cost(EXPENSES_CONSTRUCTION); /* Increment cost */ total_cost.AddCost(_price[PR_TERRAFORM]); /* Recurse to neighboured corners if height difference is larger than 1 */ { const TileIndexDiffC *ttm; TileIndex orig_tile = tile; static const TileIndexDiffC _terraform_tilepos[] = { { 1, 0}, // move to tile in SE {-2, 0}, // undo last move, and move to tile in NW { 1, 1}, // undo last move, and move to tile in SW { 0, -2} // undo last move, and move to tile in NE }; for (ttm = _terraform_tilepos; ttm != endof(_terraform_tilepos); ttm++) { tile += ToTileIndexDiff(*ttm); if (tile >= MapSize()) continue; /* Make sure we don't wrap around the map */ if (Delta(TileX(orig_tile), TileX(tile)) == MapSizeX() - 1) continue; if (Delta(TileY(orig_tile), TileY(tile)) == MapSizeY() - 1) continue; /* Get TileHeight of neighboured tile as of current terraform progress */ int r = TerraformGetHeightOfTile(ts, tile); int height_diff = height - r; /* Is the height difference to the neighboured corner greater than 1? */ if (abs(height_diff) > 1) { /* Terraform the neighboured corner. The resulting height difference should be 1. */ height_diff += (height_diff < 0 ? 1 : -1); CommandCost cost = TerraformTileHeight(ts, tile, r + height_diff); if (cost.Failed()) return cost; total_cost.AddCost(cost); } } } return total_cost; } /** * Terraform land * @param tile tile to terraform * @param flags for this command type * @param p1 corners to terraform (SLOPE_xxx) * @param p2 direction; eg up (non-zero) or down (zero) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { _terraform_err_tile = INVALID_TILE; CommandCost total_cost(EXPENSES_CONSTRUCTION); int direction = (p2 != 0 ? 1 : -1); TerraformerState ts; /* Compute the costs and the terraforming result in a model of the landscape */ if ((p1 & SLOPE_W) != 0 && tile + TileDiffXY(1, 0) < MapSize()) { TileIndex t = tile + TileDiffXY(1, 0); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } if ((p1 & SLOPE_S) != 0 && tile + TileDiffXY(1, 1) < MapSize()) { TileIndex t = tile + TileDiffXY(1, 1); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } if ((p1 & SLOPE_E) != 0 && tile + TileDiffXY(0, 1) < MapSize()) { TileIndex t = tile + TileDiffXY(0, 1); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } if ((p1 & SLOPE_N) != 0) { TileIndex t = tile + TileDiffXY(0, 0); CommandCost cost = TerraformTileHeight(&ts, t, TileHeight(t) + direction); if (cost.Failed()) return cost; total_cost.AddCost(cost); } /* Check if the terraforming is valid wrt. tunnels, bridges and objects on the surface * Pass == 0: Collect tileareas which are caused to be auto-cleared. * Pass == 1: Collect the actual cost. */ for (int pass = 0; pass < 2; pass++) { for (TileIndexSet::const_iterator it = ts.dirty_tiles.begin(); it != ts.dirty_tiles.end(); it++) { TileIndex tile = *it; assert(tile < MapSize()); /* MP_VOID tiles can be terraformed but as tunnels and bridges * cannot go under / over these tiles they don't need checking. */ if (IsTileType(tile, MP_VOID)) continue; /* Find new heights of tile corners */ int z_N = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 0)); int z_W = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 0)); int z_S = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(1, 1)); int z_E = TerraformGetHeightOfTile(&ts, tile + TileDiffXY(0, 1)); /* Find min and max height of tile */ int z_min = min(min(z_N, z_W), min(z_S, z_E)); int z_max = max(max(z_N, z_W), max(z_S, z_E)); /* Compute tile slope */ Slope tileh = (z_max > z_min + 1 ? SLOPE_STEEP : SLOPE_FLAT); if (z_W > z_min) tileh |= SLOPE_W; if (z_S > z_min) tileh |= SLOPE_S; if (z_E > z_min) tileh |= SLOPE_E; if (z_N > z_min) tileh |= SLOPE_N; if (pass == 0) { /* Check if bridge would take damage */ if (IsBridgeAbove(tile)) { int bridge_height = GetBridgeHeight(GetSouthernBridgeEnd(tile)); /* Check if bridge would take damage. */ if (direction == 1 && bridge_height <= z_max) { _terraform_err_tile = tile; // highlight the tile under the bridge return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } /* Is the bridge above not too high afterwards? */ if (direction == -1 && bridge_height > (z_min + _settings_game.construction.max_bridge_height)) { _terraform_err_tile = tile; return_cmd_error(STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND); } } /* Check if tunnel would take damage */ if (direction == -1 && IsTunnelInWay(tile, z_min)) { _terraform_err_tile = tile; // highlight the tile above the tunnel return_cmd_error(STR_ERROR_EXCAVATION_WOULD_DAMAGE); } } /* Is the tile already cleared? */ const ClearedObjectArea *coa = FindClearedObject(tile); bool indirectly_cleared = coa != NULL && coa->first_tile != tile; /* Check tiletype-specific things, and add extra-cost */ const bool curr_gen = _generating_world; if (_game_mode == GM_EDITOR) _generating_world = true; // used to create green terraformed land DoCommandFlag tile_flags = flags | DC_AUTO | DC_FORCE_CLEAR_TILE; if (pass == 0) { tile_flags &= ~DC_EXEC; tile_flags |= DC_NO_MODIFY_TOWN_RATING; } CommandCost cost; if (indirectly_cleared) { cost = DoCommand(tile, 0, 0, tile_flags, CMD_LANDSCAPE_CLEAR); } else { cost = _tile_type_procs[GetTileType(tile)]->terraform_tile_proc(tile, tile_flags, z_min, tileh); } _generating_world = curr_gen; if (cost.Failed()) { _terraform_err_tile = tile; return cost; } if (pass == 1) total_cost.AddCost(cost); } } Company *c = Company::GetIfValid(_current_company); if (c != NULL && GB(c->terraform_limit, 16, 16) < ts.tile_to_new_height.size()) { return_cmd_error(STR_ERROR_TERRAFORM_LIMIT_REACHED); } if (flags & DC_EXEC) { /* change the height */ for (TileIndexToHeightMap::const_iterator it = ts.tile_to_new_height.begin(); it != ts.tile_to_new_height.end(); it++) { TileIndex tile = it->first; int height = it->second; SetTileHeight(tile, (uint)height); } /* Finally mark the dirty tiles dirty */ for (TileIndexSet::const_iterator it = ts.dirty_tiles.begin(); it != ts.dirty_tiles.end(); it++) { MarkTileDirtyByTile(*it); int height = TerraformGetHeightOfTile(&ts, *it); /* Now, if we alter the height of the map edge, we need to take care * about repainting the affected areas outside map as well. * Remember: * Outside map, we assume that our landscape descends to * height zero as fast as possible. * Those simulated tiles (they don't exist as datastructure, * only as concept in code) need to be repainted properly, * otherwise we will get ugly glitches. * * Furthermore, note that we have to take care about the possibility, * that landscape was higher before the change, * so also tiles a bit outside need to be repainted. */ int x = TileX(*it); int y = TileY(*it); if (x == 0) { if (y == 0) { /* Height of the northern corner is altered. */ for (int cx = 0; cx >= -height - 1; cx--) { for (int cy = 0; cy >= -height - 1; cy--) { /* This means, tiles in the sector north of that * corner need to be repainted. */ if (cx + cy >= -height - 2) { /* But only tiles that actually might have changed. */ MarkTileDirtyByTileOutsideMap(cx, cy); } } } } else if (y < (int)MapMaxY()) { for (int cx = 0; cx >= -height - 1; cx--) { MarkTileDirtyByTileOutsideMap(cx, y); } } else { for (int cx = 0; cx >= -height - 1; cx--) { for (int cy = (int)MapMaxY(); cy <= (int)MapMaxY() + height + 1; cy++) { if (cx + ((int)MapMaxY() - cy) >= -height - 2) { MarkTileDirtyByTileOutsideMap(cx, cy); } } } } } else if (x < (int)MapMaxX()) { if (y == 0) { for (int cy = 0; cy >= -height - 1; cy--) { MarkTileDirtyByTileOutsideMap(x, cy); } } else if (y < (int)MapMaxY()) { /* Nothing to be done here, we are inside the map. */ } else { for (int cy = (int)MapMaxY(); cy <= (int)MapMaxY() + height + 1; cy++) { MarkTileDirtyByTileOutsideMap(x, cy); } } } else { if (y == 0) { for (int cx = (int)MapMaxX(); cx <= (int)MapMaxX() + height + 1; cx++) { for (int cy = 0; cy >= -height - 1; cy--) { if (((int)MapMaxX() - cx) + cy >= -height - 2) { MarkTileDirtyByTileOutsideMap(cx, cy); } } } } else if (y < (int)MapMaxY()) { for (int cx = (int)MapMaxX(); cx <= (int)MapMaxX() + height + 1; cx++) { MarkTileDirtyByTileOutsideMap(cx, y); } } else { for (int cx = (int)MapMaxX(); cx <= (int)MapMaxX() + height + 1; cx++) { for (int cy = (int)MapMaxY(); cy <= (int)MapMaxY() + height + 1; cy++) { if (((int)MapMaxX() - cx) + ((int)MapMaxY() - cy) >= -height - 2) { MarkTileDirtyByTileOutsideMap(cx, cy); } } } } } } if (c != NULL) c->terraform_limit -= ts.tile_to_new_height.size() << 16; } return total_cost; } /** * Levels a selected (rectangle) area of land * @param tile end tile of area-drag * @param flags for this command type * @param p1 start tile of area drag * @param p2 various bitstuffed data. * bit 0: Whether to use the Orthogonal (0) or Diagonal (1) iterator. * bits 1 - 2: Mode of leveling \c LevelMode. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdLevelLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (p1 >= MapSize()) return CMD_ERROR; _terraform_err_tile = INVALID_TILE; /* remember level height */ uint oldh = TileHeight(p1); /* compute new height */ uint h = oldh; LevelMode lm = (LevelMode)GB(p2, 1, 2); switch (lm) { case LM_LEVEL: break; case LM_RAISE: h++; break; case LM_LOWER: h--; break; default: return CMD_ERROR; } /* Check range of destination height */ if (h > _settings_game.construction.max_heightlevel) return_cmd_error((oldh == 0) ? STR_ERROR_ALREADY_AT_SEA_LEVEL : STR_ERROR_TOO_HIGH); Money money = GetAvailableMoneyForCommand(); CommandCost cost(EXPENSES_CONSTRUCTION); CommandCost last_error(lm == LM_LEVEL ? STR_ERROR_ALREADY_LEVELLED : INVALID_STRING_ID); bool had_success = false; const Company *c = Company::GetIfValid(_current_company); int limit = (c == NULL ? INT32_MAX : GB(c->terraform_limit, 16, 16)); if (limit == 0) return_cmd_error(STR_ERROR_TERRAFORM_LIMIT_REACHED); TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(tile, p1); for (; *iter != INVALID_TILE; ++(*iter)) { TileIndex t = *iter; uint curh = TileHeight(t); while (curh != h) { CommandCost ret = DoCommand(t, SLOPE_N, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND); if (ret.Failed()) { last_error = ret; /* Did we reach the limit? */ if (ret.GetErrorMessage() == STR_ERROR_TERRAFORM_LIMIT_REACHED) limit = 0; break; } if (flags & DC_EXEC) { money -= ret.GetCost(); if (money < 0) { _additional_cash_required = ret.GetCost(); delete iter; return cost; } DoCommand(t, SLOPE_N, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND); } else { /* When we're at the terraform limit we better bail (unneeded) testing as well. * This will probably cause the terraforming cost to be underestimated, but only * when it's near the terraforming limit. Even then, the estimation is * completely off due to it basically counting terraforming double, so it being * cut off earlier might even give a better estimate in some cases. */ if (--limit <= 0) { had_success = true; break; } } cost.AddCost(ret); curh += (curh > h) ? -1 : 1; had_success = true; } if (limit <= 0) break; } delete iter; return had_success ? cost : last_error; } openttd-1.5.3/src/cheat_type.h0000644000000000000000000000376712627373445015012 0ustar rootroot/* $Id: cheat_type.h 26887 2014-09-21 12:39:24Z rubidium $ */ /* * 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 cheat_type.h Types related to cheating. */ #ifndef CHEAT_TYPE_H #define CHEAT_TYPE_H /** * Info about each of the cheats. */ struct Cheat { bool been_used; ///< has this cheat been used before? bool value; ///< tells if the bool cheat is active or not }; /** * WARNING! Do _not_ remove entries in Cheats struct or change the order * of the existing ones! Would break downward compatibility. * Only add new entries at the end of the struct! */ struct Cheats { Cheat magic_bulldozer; ///< dynamite industries, objects Cheat switch_company; ///< change to another company Cheat money; ///< get rich or poor 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 Cheat dummy2; ///< empty cheat (change the climate of the map) Cheat change_date; ///< changes date ingame Cheat setup_prod; ///< setup raw-material production in game Cheat dummy3; ///< empty cheat (enable running el-engines on normal rail) Cheat edit_max_hl; ///< edit the maximum heightlevel; this is a cheat because of the fact that it needs to reset NewGRF game state and doing so as a simple configuration breaks the expectation of many }; extern Cheats _cheats; #endif /* CHEAT_TYPE_H */ openttd-1.5.3/src/newgrf_town.cpp0000644000000000000000000001664412627373441015551 0ustar rootroot/* $Id: newgrf_town.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_town.cpp Implementation of the town part of NewGRF houses. */ #include "stdafx.h" #include "debug.h" #include "town.h" #include "newgrf_town.h" #include "safeguards.h" /** * Resolver of a town scope. * @param ro Surrounding resolver. * @param t %Town of the scope. * @param readonly Scope may change persistent storage of the town. */ TownScopeResolver::TownScopeResolver(ResolverObject &ro, Town *t, bool readonly) : ScopeResolver(ro) { this->t = t; this->readonly = readonly; } /* virtual */ uint32 TownScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { switch (variable) { /* Larger towns */ case 0x40: if (_settings_game.economy.larger_towns == 0) return 2; if (this->t->larger_town) return 1; return 0; /* Town index */ case 0x41: return this->t->index; /* Get a variable from the persistent storage */ case 0x7C: { /* Check the persistent storage for the GrfID stored in register 100h. */ uint32 grfid = GetRegister(0x100); if (grfid == 0xFFFFFFFF) { if (this->ro.grffile == NULL) return 0; grfid = this->ro.grffile->grfid; } std::list::iterator iter; for (iter = this->t->psa_list.begin(); iter != this->t->psa_list.end(); iter++) { if ((*iter)->grfid == grfid) return (*iter)->GetValue(parameter); } return 0; } /* Town properties */ case 0x80: return this->t->xy; case 0x81: return GB(this->t->xy, 8, 8); case 0x82: return ClampToU16(this->t->cache.population); case 0x83: return GB(ClampToU16(this->t->cache.population), 8, 8); case 0x8A: return this->t->grow_counter; case 0x92: return this->t->flags; // In original game, 0x92 and 0x93 are really one word. Since flags is a byte, this is to adjust case 0x93: return 0; case 0x94: return ClampToU16(this->t->cache.squared_town_zone_radius[0]); case 0x95: return GB(ClampToU16(this->t->cache.squared_town_zone_radius[0]), 8, 8); case 0x96: return ClampToU16(this->t->cache.squared_town_zone_radius[1]); case 0x97: return GB(ClampToU16(this->t->cache.squared_town_zone_radius[1]), 8, 8); case 0x98: return ClampToU16(this->t->cache.squared_town_zone_radius[2]); case 0x99: return GB(ClampToU16(this->t->cache.squared_town_zone_radius[2]), 8, 8); case 0x9A: return ClampToU16(this->t->cache.squared_town_zone_radius[3]); case 0x9B: return GB(ClampToU16(this->t->cache.squared_town_zone_radius[3]), 8, 8); case 0x9C: return ClampToU16(this->t->cache.squared_town_zone_radius[4]); case 0x9D: return GB(ClampToU16(this->t->cache.squared_town_zone_radius[4]), 8, 8); case 0x9E: return this->t->ratings[0]; case 0x9F: return GB(this->t->ratings[0], 8, 8); case 0xA0: return this->t->ratings[1]; case 0xA1: return GB(this->t->ratings[1], 8, 8); case 0xA2: return this->t->ratings[2]; case 0xA3: return GB(this->t->ratings[2], 8, 8); case 0xA4: return this->t->ratings[3]; case 0xA5: return GB(this->t->ratings[3], 8, 8); case 0xA6: return this->t->ratings[4]; case 0xA7: return GB(this->t->ratings[4], 8, 8); case 0xA8: return this->t->ratings[5]; case 0xA9: return GB(this->t->ratings[5], 8, 8); case 0xAA: return this->t->ratings[6]; case 0xAB: return GB(this->t->ratings[6], 8, 8); case 0xAC: return this->t->ratings[7]; case 0xAD: return GB(this->t->ratings[7], 8, 8); case 0xAE: return this->t->have_ratings; case 0xB2: return this->t->statues; case 0xB6: return ClampToU16(this->t->cache.num_houses); case 0xB9: return this->t->growth_rate & (~TOWN_GROW_RATE_CUSTOM); case 0xBA: return ClampToU16(this->t->supplied[CT_PASSENGERS].new_max); case 0xBB: return GB(ClampToU16(this->t->supplied[CT_PASSENGERS].new_max), 8, 8); case 0xBC: return ClampToU16(this->t->supplied[CT_MAIL].new_max); case 0xBD: return GB(ClampToU16(this->t->supplied[CT_MAIL].new_max), 8, 8); case 0xBE: return ClampToU16(this->t->supplied[CT_PASSENGERS].new_act); case 0xBF: return GB(ClampToU16(this->t->supplied[CT_PASSENGERS].new_act), 8, 8); case 0xC0: return ClampToU16(this->t->supplied[CT_MAIL].new_act); case 0xC1: return GB(ClampToU16(this->t->supplied[CT_MAIL].new_act), 8, 8); case 0xC2: return ClampToU16(this->t->supplied[CT_PASSENGERS].old_max); case 0xC3: return GB(ClampToU16(this->t->supplied[CT_PASSENGERS].old_max), 8, 8); case 0xC4: return ClampToU16(this->t->supplied[CT_MAIL].old_max); case 0xC5: return GB(ClampToU16(this->t->supplied[CT_MAIL].old_max), 8, 8); case 0xC6: return ClampToU16(this->t->supplied[CT_PASSENGERS].old_act); case 0xC7: return GB(ClampToU16(this->t->supplied[CT_PASSENGERS].old_act), 8, 8); case 0xC8: return ClampToU16(this->t->supplied[CT_MAIL].old_act); case 0xC9: return GB(ClampToU16(this->t->supplied[CT_MAIL].old_act), 8, 8); case 0xCA: return this->t->GetPercentTransported(CT_PASSENGERS); case 0xCB: return this->t->GetPercentTransported(CT_MAIL); case 0xCC: return this->t->received[TE_FOOD].new_act; case 0xCD: return GB(this->t->received[TE_FOOD].new_act, 8, 8); case 0xCE: return this->t->received[TE_WATER].new_act; case 0xCF: return GB(this->t->received[TE_WATER].new_act, 8, 8); case 0xD0: return this->t->received[TE_FOOD].old_act; case 0xD1: return GB(this->t->received[TE_FOOD].old_act, 8, 8); case 0xD2: return this->t->received[TE_WATER].old_act; case 0xD3: return GB(this->t->received[TE_WATER].old_act, 8, 8); case 0xD4: return this->t->road_build_months; case 0xD5: return this->t->fund_buildings_months; } DEBUG(grf, 1, "Unhandled town variable 0x%X", variable); *available = false; return UINT_MAX; } /* virtual */ void TownScopeResolver::StorePSA(uint pos, int32 value) { if (this->readonly) return; assert(this->t != NULL); /* We can't store anything if the caller has no #GRFFile. */ if (this->ro.grffile == NULL) return; /* Check the persistent storage for the GrfID stored in register 100h. */ uint32 grfid = GetRegister(0x100); /* A NewGRF can only write in the persistent storage associated to its own GRFID. */ if (grfid == 0xFFFFFFFF) grfid = this->ro.grffile->grfid; if (grfid != this->ro.grffile->grfid) return; /* Check if the storage exists. */ std::list::iterator iter; for (iter = t->psa_list.begin(); iter != t->psa_list.end(); iter++) { if ((*iter)->grfid == grfid) { (*iter)->StoreValue(pos, value); return; } } /* Create a new storage. */ assert(PersistentStorage::CanAllocateItem()); PersistentStorage *psa = new PersistentStorage(grfid, GSF_FAKE_TOWNS, this->t->xy); psa->StoreValue(pos, value); t->psa_list.push_back(psa); } /** * Resolver for a town. * @param grffile NewGRF file associated with the town. * @param t %Town of the scope. * @param readonly Scope may change persistent storage of the town. */ TownResolverObject::TownResolverObject(const struct GRFFile *grffile, Town *t, bool readonly) : ResolverObject(grffile), town_scope(*this, t, readonly) { } openttd-1.5.3/src/station_type.h0000644000000000000000000001001312627373435015364 0ustar rootroot/* $Id: station_type.h 25890 2013-10-20 13:47:11Z fonsinchen $ */ /* * 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 station_type.h Types related to stations. */ #ifndef STATION_TYPE_H #define STATION_TYPE_H #include "core/smallvec_type.hpp" #include "core/smallstack_type.hpp" #include "tilearea_type.h" #include typedef uint16 StationID; typedef uint16 RoadStopID; struct BaseStation; struct Station; struct RoadStop; struct StationSpec; struct Waypoint; static const StationID NEW_STATION = 0xFFFE; static const StationID INVALID_STATION = 0xFFFF; typedef SmallStack StationIDStack; /** Station types */ enum StationType { STATION_RAIL, STATION_AIRPORT, STATION_TRUCK, STATION_BUS, STATION_OILRIG, STATION_DOCK, STATION_BUOY, STATION_WAYPOINT, }; /** Types of RoadStops */ enum RoadStopType { ROADSTOP_BUS, ///< A standard stop for buses ROADSTOP_TRUCK, ///< A standard stop for trucks }; /** The facilities a station might be having */ enum StationFacility { FACIL_NONE = 0, ///< The station has no facilities at all FACIL_TRAIN = 1 << 0, ///< Station with train station FACIL_TRUCK_STOP = 1 << 1, ///< Station with truck stops FACIL_BUS_STOP = 1 << 2, ///< Station with bus stops FACIL_AIRPORT = 1 << 3, ///< Station with an airport FACIL_DOCK = 1 << 4, ///< Station with a dock FACIL_WAYPOINT = 1 << 7, ///< Station is a waypoint }; DECLARE_ENUM_AS_BIT_SET(StationFacility) typedef SimpleTinyEnumT StationFacilityByte; /** The vehicles that may have visited a station */ enum StationHadVehicleOfType { HVOT_NONE = 0, ///< Station has seen no vehicles HVOT_TRAIN = 1 << 1, ///< Station has seen a train HVOT_BUS = 1 << 2, ///< Station has seen a bus HVOT_TRUCK = 1 << 3, ///< Station has seen a truck HVOT_AIRCRAFT = 1 << 4, ///< Station has seen an aircraft HVOT_SHIP = 1 << 5, ///< Station has seen a ship HVOT_WAYPOINT = 1 << 6, ///< Station is a waypoint (NewGRF only!) }; DECLARE_ENUM_AS_BIT_SET(StationHadVehicleOfType) typedef SimpleTinyEnumT StationHadVehicleOfTypeByte; /** The different catchment areas used */ enum CatchmentArea { CA_NONE = 0, ///< Catchment when the station has no facilities CA_BUS = 3, ///< Catchment for bus stops with "modified catchment" enabled CA_TRUCK = 3, ///< Catchment for truck stops with "modified catchment" enabled CA_TRAIN = 4, ///< Catchment for train stations with "modified catchment" enabled CA_DOCK = 5, ///< Catchment for docks with "modified catchment" enabled CA_UNMODIFIED = 4, ///< Catchment for all stations with "modified catchment" disabled MAX_CATCHMENT = 10, ///< Maximum catchment for airports with "modified catchment" enabled }; static const uint MAX_LENGTH_STATION_NAME_CHARS = 32; ///< The maximum length of a station name in characters including '\0' /** List of station IDs */ typedef std::list StationIDList; /** List of stations */ typedef SmallVector StationList; /** * Structure contains cached list of stations nearby. The list * is created upon first call to GetStations() */ class StationFinder : TileArea { StationList stations; ///< List of stations nearby public: /** * Constructs StationFinder * @param area the area to search from */ StationFinder(const TileArea &area) : TileArea(area) {} const StationList *GetStations(); }; #endif /* STATION_TYPE_H */ openttd-1.5.3/src/engine_gui.h0000644000000000000000000000456712627373435014774 0ustar rootroot/* $Id: engine_gui.h 26804 2014-09-07 16:14:06Z alberth $ */ /* * 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 engine_gui.h %Engine GUI functions, used by build_vehicle_gui and autoreplace_gui */ #ifndef ENGINE_GUI_H #define ENGINE_GUI_H #include "engine_type.h" #include "sortlist_type.h" #include "gfx_type.h" #include "vehicle_type.h" typedef GUIList GUIEngineList; typedef int CDECL EngList_SortTypeFunction(const EngineID*, const EngineID*); ///< argument type for #EngList_Sort. void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare); void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items); StringID GetEngineCategoryName(EngineID engine); StringID GetEngineInfoString(EngineID engine); void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type); void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type); void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type); void DrawShipEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type); void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type); extern bool _engine_sort_direction; extern byte _engine_sort_last_criteria[]; extern bool _engine_sort_last_order[]; extern bool _engine_sort_show_hidden_engines[]; extern const StringID _engine_sort_listing[][12]; extern EngList_SortTypeFunction * const _engine_sort_functions[][11]; uint GetEngineListHeight(VehicleType type); void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button); #endif /* ENGINE_GUI_H */ openttd-1.5.3/src/town_map.h0000644000000000000000000002324212627373435014476 0ustar rootroot/* $Id: town_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 town_map.h Accessors for towns */ #ifndef TOWN_MAP_H #define TOWN_MAP_H #include "road_map.h" #include "house.h" /** * Get the index of which town this house/street is attached to. * @param t the tile * @pre IsTileType(t, MP_HOUSE) or IsTileType(t, MP_ROAD) but not a road depot * @return TownID */ static inline TownID GetTownIndex(TileIndex t) { assert(IsTileType(t, MP_HOUSE) || (IsTileType(t, MP_ROAD) && !IsRoadDepot(t))); return _m[t].m2; } /** * Set the town index for a road or house tile. * @param t the tile * @param index the index of the town * @pre IsTileType(t, MP_HOUSE) or IsTileType(t, MP_ROAD) but not a road depot */ static inline void SetTownIndex(TileIndex t, TownID index) { assert(IsTileType(t, MP_HOUSE) || (IsTileType(t, MP_ROAD) && !IsRoadDepot(t))); _m[t].m2 = index; } /** * Get the type of this house, which is an index into the house spec array * without doing any NewGRF related translations. * @param t the tile * @pre IsTileType(t, MP_HOUSE) * @return house type */ static inline HouseID GetCleanHouseType(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return _m[t].m4 | (GB(_m[t].m3, 6, 1) << 8); } /** * Get the type of this house, which is an index into the house spec array * @param t the tile * @pre IsTileType(t, MP_HOUSE) * @return house type */ static inline HouseID GetHouseType(TileIndex t) { return GetTranslatedHouseID(GetCleanHouseType(t)); } /** * Set the house type. * @param t the tile * @param house_id the new house type * @pre IsTileType(t, MP_HOUSE) */ static inline void SetHouseType(TileIndex t, HouseID house_id) { assert(IsTileType(t, MP_HOUSE)); _m[t].m4 = GB(house_id, 0, 8); SB(_m[t].m3, 6, 1, GB(house_id, 8, 1)); } /** * Check if the lift of this animated house has a destination * @param t the tile * @return has destination */ static inline bool LiftHasDestination(TileIndex t) { return HasBit(_me[t].m7, 0); } /** * Set the new destination of the lift for this animated house, and activate * the LiftHasDestination bit. * @param t the tile * @param dest new destination */ static inline void SetLiftDestination(TileIndex t, byte dest) { SetBit(_me[t].m7, 0); SB(_me[t].m7, 1, 3, dest); } /** * Get the current destination for this lift * @param t the tile * @return destination */ static inline byte GetLiftDestination(TileIndex t) { return GB(_me[t].m7, 1, 3); } /** * Stop the lift of this animated house from moving. * Clears the first 4 bits of m7 at once, clearing the LiftHasDestination bit * and the destination. * @param t the tile */ static inline void HaltLift(TileIndex t) { SB(_me[t].m7, 0, 4, 0); } /** * Get the position of the lift on this animated house * @param t the tile * @return position, from 0 to 36 */ static inline byte GetLiftPosition(TileIndex t) { return GB(_me[t].m6, 2, 6); } /** * Set the position of the lift on this animated house * @param t the tile * @param pos position, from 0 to 36 */ static inline void SetLiftPosition(TileIndex t, byte pos) { SB(_me[t].m6, 2, 6, pos); } /** * Get the completion of this house * @param t the tile * @return true if it is, false if it is not */ static inline bool IsHouseCompleted(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return HasBit(_m[t].m3, 7); } /** * Mark this house as been completed * @param t the tile * @param status */ static inline void SetHouseCompleted(TileIndex t, bool status) { assert(IsTileType(t, MP_HOUSE)); SB(_m[t].m3, 7, 1, !!status); } /** * House Construction Scheme. * Construction counter, for buildings under construction. Incremented on every * periodic tile processing. * On wraparound, the stage of building in is increased. * GetHouseBuildingStage is taking care of the real stages, * (as the sprite for the next phase of house building) * (Get|Inc)HouseConstructionTick is simply a tick counter between the * different stages */ /** * Gets the building stage of a house * Since the stage is used for determining what sprite to use, * if the house is complete (and that stage no longer is available), * fool the system by returning the TOWN_HOUSE_COMPLETE (3), * thus showing a beautiful complete house. * @param t the tile of the house to get the building stage of * @pre IsTileType(t, MP_HOUSE) * @return the building stage of the house */ static inline byte GetHouseBuildingStage(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return IsHouseCompleted(t) ? (byte)TOWN_HOUSE_COMPLETED : GB(_m[t].m5, 3, 2); } /** * Gets the construction stage of a house * @param t the tile of the house to get the construction stage of * @pre IsTileType(t, MP_HOUSE) * @return the construction stage of the house */ static inline byte GetHouseConstructionTick(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return IsHouseCompleted(t) ? 0 : GB(_m[t].m5, 0, 3); } /** * Sets the increment stage of a house * It is working with the whole counter + stage 5 bits, making it * easier to work: the wraparound is automatic. * @param t the tile of the house to increment the construction stage of * @pre IsTileType(t, MP_HOUSE) */ static inline void IncHouseConstructionTick(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); AB(_m[t].m5, 0, 5, 1); if (GB(_m[t].m5, 3, 2) == TOWN_HOUSE_COMPLETED) { /* House is now completed. * Store the year of construction as well, for newgrf house purpose */ SetHouseCompleted(t, true); } } /** * Sets the age of the house to zero. * Needs to be called after the house is completed. During construction stages the map space is used otherwise. * @param t the tile of this house * @pre IsTileType(t, MP_HOUSE) && IsHouseCompleted(t) */ static inline void ResetHouseAge(TileIndex t) { assert(IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)); _m[t].m5 = 0; } /** * Increments the age of the house. * @param t the tile of this house * @pre IsTileType(t, MP_HOUSE) */ static inline void IncrementHouseAge(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); if (IsHouseCompleted(t) && _m[t].m5 < 0xFF) _m[t].m5++; } /** * Get the age of the house * @param t the tile of this house * @pre IsTileType(t, MP_HOUSE) * @return year */ static inline Year GetHouseAge(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return IsHouseCompleted(t) ? _m[t].m5 : 0; } /** * Set the random bits for this house. * This is required for newgrf house * @param t the tile of this house * @param random the new random bits * @pre IsTileType(t, MP_HOUSE) */ static inline void SetHouseRandomBits(TileIndex t, byte random) { assert(IsTileType(t, MP_HOUSE)); _m[t].m1 = random; } /** * Get the random bits for this house. * This is required for newgrf house * @param t the tile of this house * @pre IsTileType(t, MP_HOUSE) * @return random bits */ static inline byte GetHouseRandomBits(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return _m[t].m1; } /** * Set the activated triggers bits for this house. * This is required for newgrf house * @param t the tile of this house * @param triggers the activated triggers * @pre IsTileType(t, MP_HOUSE) */ static inline void SetHouseTriggers(TileIndex t, byte triggers) { assert(IsTileType(t, MP_HOUSE)); SB(_m[t].m3, 0, 5, triggers); } /** * Get the already activated triggers bits for this house. * This is required for newgrf house * @param t the tile of this house * @pre IsTileType(t, MP_HOUSE) * @return triggers */ static inline byte GetHouseTriggers(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return GB(_m[t].m3, 0, 5); } /** * Get the amount of time remaining before the tile loop processes this tile. * @param t the house tile * @pre IsTileType(t, MP_HOUSE) * @return time remaining */ static inline byte GetHouseProcessingTime(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); return GB(_me[t].m6, 2, 6); } /** * Set the amount of time remaining before the tile loop processes this tile. * @param t the house tile * @param time the time to be set * @pre IsTileType(t, MP_HOUSE) */ static inline void SetHouseProcessingTime(TileIndex t, byte time) { assert(IsTileType(t, MP_HOUSE)); SB(_me[t].m6, 2, 6, time); } /** * Decrease the amount of time remaining before the tile loop processes this tile. * @param t the house tile * @pre IsTileType(t, MP_HOUSE) */ static inline void DecHouseProcessingTime(TileIndex t) { assert(IsTileType(t, MP_HOUSE)); _me[t].m6 -= 1 << 2; } /** * Make the tile a house. * @param t tile index * @param tid Town index * @param counter of construction step * @param stage of construction (used for drawing) * @param type of house. Index into house specs array * @param random_bits required for newgrf houses * @pre IsTileType(t, MP_CLEAR) */ static inline void MakeHouseTile(TileIndex t, TownID tid, byte counter, byte stage, HouseID type, byte random_bits) { assert(IsTileType(t, MP_CLEAR)); SetTileType(t, MP_HOUSE); _m[t].m1 = random_bits; _m[t].m2 = tid; _m[t].m3 = 0; SetHouseType(t, type); SetHouseCompleted(t, stage == TOWN_HOUSE_COMPLETED); _m[t].m5 = IsHouseCompleted(t) ? 0 : (stage << 3 | counter); SetAnimationFrame(t, 0); SetHouseProcessingTime(t, HouseSpec::Get(type)->processing_time); } #endif /* TOWN_MAP_H */ openttd-1.5.3/src/newgrf.cpp0000644000000000000000000112712212627373435014500 0ustar rootroot/* $Id: newgrf.cpp 27138 2015-02-06 21:56:50Z frosch $ */ /* * 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 newgrf.cpp Base of all NewGRF support. */ #include "stdafx.h" #include #include "debug.h" #include "fileio_func.h" #include "engine_func.h" #include "engine_base.h" #include "bridge.h" #include "town.h" #include "newgrf_engine.h" #include "newgrf_text.h" #include "fontcache.h" #include "currency.h" #include "landscape.h" #include "newgrf_cargo.h" #include "newgrf_house.h" #include "newgrf_sound.h" #include "newgrf_station.h" #include "industrytype.h" #include "newgrf_canal.h" #include "newgrf_townname.h" #include "newgrf_industries.h" #include "newgrf_airporttiles.h" #include "newgrf_airport.h" #include "newgrf_object.h" #include "rev.h" #include "fios.h" #include "strings_func.h" #include "date_func.h" #include "string_func.h" #include "network/network.h" #include #include "smallmap_gui.h" #include "genworld.h" #include "error.h" #include "vehicle_func.h" #include "language.h" #include "vehicle_base.h" #include "table/strings.h" #include "table/build_industry.h" #include "safeguards.h" /* TTDPatch extended GRF format codec * (c) Petr Baudis 2004 (GPL'd) * Changes by Florian octo Forster are (c) by the OpenTTD development team. * * Contains portions of documentation by TTDPatch team. * Thanks especially to Josef Drexler for the documentation as well as a lot * of help at #tycoon. Also thanks to Michael Blunck for his GRF files which * served as subject to the initial testing of this codec. */ /** List of all loaded GRF files */ static SmallVector _grf_files; /** Miscellaneous GRF features, set by Action 0x0D, parameter 0x9E */ byte _misc_grf_features = 0; /** 32 * 8 = 256 flags. Apparently TTDPatch uses this many.. */ static uint32 _ttdpatch_flags[8]; /** Indicates which are the newgrf features currently loaded ingame */ GRFLoadedFeatures _loaded_newgrf_features; static const uint MAX_SPRITEGROUP = UINT8_MAX; ///< Maximum GRF-local ID for a spritegroup. /** Temporary data during loading of GRFs */ struct GrfProcessingState { private: /** Definition of a single Action1 spriteset */ struct SpriteSet { SpriteID sprite; ///< SpriteID of the first sprite of the set. uint num_sprites; ///< Number of sprites in the set. }; /** Currently referenceable spritesets */ std::map spritesets[GSF_END]; public: /* Global state */ GrfLoadingStage stage; ///< Current loading stage SpriteID spriteid; ///< First available SpriteID for loading realsprites. /* Local state in the file */ uint file_index; ///< File index of currently processed GRF file. GRFFile *grffile; ///< Currently processed GRF file. GRFConfig *grfconfig; ///< Config of the currently processed GRF file. uint32 nfo_line; ///< Currently processed pseudo sprite number in the GRF. byte grf_container_ver; ///< Container format of the current GRF file. /* Kind of return values when processing certain actions */ int skip_sprites; ///< Number of psuedo sprites to skip before processing the next one. (-1 to skip to end of file) /* Currently referenceable spritegroups */ SpriteGroup *spritegroups[MAX_SPRITEGROUP + 1]; /** Clear temporary data before processing the next file in the current loading stage */ void ClearDataForNextFile() { this->nfo_line = 0; this->skip_sprites = 0; for (uint i = 0; i < GSF_END; i++) { this->spritesets[i].clear(); } memset(this->spritegroups, 0, sizeof(this->spritegroups)); } /** * Records new spritesets. * @param feature GrfSpecFeature the set is defined for. * @param first_sprite SpriteID of the first sprite in the set. * @param first_set First spriteset to define. * @param numsets Number of sets to define. * @param numents Number of sprites per set to define. */ void AddSpriteSets(byte feature, SpriteID first_sprite, uint first_set, uint numsets, uint numents) { assert(feature < GSF_END); for (uint i = 0; i < numsets; i++) { SpriteSet &set = this->spritesets[feature][first_set + i]; set.sprite = first_sprite + i * numents; set.num_sprites = numents; } } /** * Check whether there are any valid spritesets for a feature. * @param feature GrfSpecFeature to check. * @return true if there are any valid sets. * @note Spritesets with zero sprites are valid to allow callback-failures. */ bool HasValidSpriteSets(byte feature) const { assert(feature < GSF_END); return !this->spritesets[feature].empty(); } /** * Check whether a specific set is defined. * @param feature GrfSpecFeature to check. * @param set Set to check. * @return true if the set is valid. * @note Spritesets with zero sprites are valid to allow callback-failures. */ bool IsValidSpriteSet(byte feature, uint set) const { assert(feature < GSF_END); return this->spritesets[feature].find(set) != this->spritesets[feature].end(); } /** * Returns the first sprite of a spriteset. * @param feature GrfSpecFeature to query. * @param set Set to query. * @return First sprite of the set. */ SpriteID GetSprite(byte feature, uint set) const { assert(IsValidSpriteSet(feature, set)); return this->spritesets[feature].find(set)->second.sprite; } /** * Returns the number of sprites in a spriteset * @param feature GrfSpecFeature to query. * @param set Set to query. * @return Number of sprites in the set. */ uint GetNumEnts(byte feature, uint set) const { assert(IsValidSpriteSet(feature, set)); return this->spritesets[feature].find(set)->second.num_sprites; } }; static GrfProcessingState _cur; /** * Helper to check whether an image index is valid for a particular NewGRF vehicle. * @param The type of vehicle. * @param image_index The image index to check. * @return True iff the image index is valid, or 0xFD (use new graphics). */ template static inline bool IsValidNewGRFImageIndex(uint8 image_index) { return image_index == 0xFD || IsValidImageIndex(image_index); } class OTTDByteReaderSignal { }; /** Class to read from a NewGRF file */ class ByteReader { protected: byte *data; byte *end; public: ByteReader(byte *data, byte *end) : data(data), end(end) { } inline byte ReadByte() { if (data < end) return *(data)++; throw OTTDByteReaderSignal(); } uint16 ReadWord() { uint16 val = ReadByte(); return val | (ReadByte() << 8); } uint16 ReadExtendedByte() { uint16 val = ReadByte(); return val == 0xFF ? ReadWord() : val; } uint32 ReadDWord() { uint32 val = ReadWord(); return val | (ReadWord() << 16); } uint32 ReadVarSize(byte size) { switch (size) { case 1: return ReadByte(); case 2: return ReadWord(); case 4: return ReadDWord(); default: NOT_REACHED(); return 0; } } const char *ReadString() { char *string = reinterpret_cast(data); size_t string_length = ttd_strnlen(string, Remaining()); if (string_length == Remaining()) { /* String was not NUL terminated, so make sure it is now. */ string[string_length - 1] = '\0'; grfmsg(7, "String was not terminated with a zero byte."); } else { /* Increase the string length to include the NUL byte. */ string_length++; } Skip(string_length); return string; } inline size_t Remaining() const { return end - data; } inline bool HasData(size_t count = 1) const { return data + count <= end; } inline byte *Data() { return data; } inline void Skip(size_t len) { data += len; /* It is valid to move the buffer to exactly the end of the data, * as there may not be any more data read. */ if (data > end) throw OTTDByteReaderSignal(); } }; typedef void (*SpecialSpriteHandler)(ByteReader *buf); static const uint NUM_STATIONS_PER_GRF = 255; ///< Number of StationSpecs per NewGRF; limited to 255 to allow extending Action3 with an extended byte later on. /** Temporary engine data used when loading only */ struct GRFTempEngineData { /** Summary state of refittability properties */ enum Refittability { UNSET = 0, ///< No properties assigned. Default refit masks shall be activated. EMPTY, ///< GRF defined vehicle as not-refittable. The vehicle shall only carry the default cargo. NONEMPTY, ///< GRF defined the vehicle as refittable. If the refitmask is empty after translation (cargotypes not available), disable the vehicle. }; uint16 cargo_allowed; uint16 cargo_disallowed; RailTypeLabel railtypelabel; const GRFFile *defaultcargo_grf; ///< GRF defining the cargo translation table to use if the default cargo is the 'first refittable'. Refittability refittability; ///< Did the newgrf set any refittability property? If not, default refittability will be applied. bool prop27_set; ///< Did the NewGRF set property 27 (misc flags)? uint8 rv_max_speed; ///< Temporary storage of RV prop 15, maximum speed in mph/0.8 uint32 ctt_include_mask; ///< Cargo types always included in the refit mask. uint32 ctt_exclude_mask; ///< Cargo types always excluded from the refit mask. /** * Update the summary refittability on setting a refittability property. * @param non_empty true if the GRF sets the vehicle to be refittable. */ void UpdateRefittability(bool non_empty) { if (non_empty) { this->refittability = NONEMPTY; } else if (this->refittability == UNSET) { this->refittability = EMPTY; } } }; static GRFTempEngineData *_gted; ///< Temporary engine data used during NewGRF loading /** * Contains the GRF ID of the owner of a vehicle if it has been reserved. * GRM for vehicles is only used if dynamic engine allocation is disabled, * so 256 is the number of original engines. */ static uint32 _grm_engines[256]; /** Contains the GRF ID of the owner of a cargo if it has been reserved */ static uint32 _grm_cargoes[NUM_CARGO * 2]; struct GRFLocation { uint32 grfid; uint32 nfoline; GRFLocation(uint32 grfid, uint32 nfoline) : grfid(grfid), nfoline(nfoline) { } bool operator<(const GRFLocation &other) const { return this->grfid < other.grfid || (this->grfid == other.grfid && this->nfoline < other.nfoline); } bool operator == (const GRFLocation &other) const { return this->grfid == other.grfid && this->nfoline == other.nfoline; } }; static std::map _grm_sprites; typedef std::map GRFLineToSpriteOverride; static GRFLineToSpriteOverride _grf_line_to_action6_sprite_override; /** * DEBUG() function dedicated to newGRF debugging messages * Function is essentially the same as DEBUG(grf, severity, ...) with the * addition of file:line information when parsing grf files. * NOTE: for the above reason(s) grfmsg() should ONLY be used for * loading/parsing grf files, not for runtime debug messages as there * is no file information available during that time. * @param severity debugging severity level, see debug.h * @param str message in printf() format */ void CDECL grfmsg(int severity, const char *str, ...) { char buf[1024]; va_list va; va_start(va, str); vseprintf(buf, lastof(buf), str, va); va_end(va); DEBUG(grf, severity, "[%s:%d] %s", _cur.grfconfig->filename, _cur.nfo_line, buf); } /** * Obtain a NewGRF file by its grfID * @param grfid The grfID to obtain the file for * @return The file. */ static GRFFile *GetFileByGRFID(uint32 grfid) { const GRFFile * const *end = _grf_files.End(); for (GRFFile * const *file = _grf_files.Begin(); file != end; file++) { if ((*file)->grfid == grfid) return *file; } return NULL; } /** * Obtain a NewGRF file by its filename * @param filename The filename to obtain the file for. * @return The file. */ static GRFFile *GetFileByFilename(const char *filename) { const GRFFile * const *end = _grf_files.End(); for (GRFFile * const *file = _grf_files.Begin(); file != end; file++) { if (strcmp((*file)->filename, filename) == 0) return *file; } return NULL; } /** Reset all NewGRFData that was used only while processing data */ static void ClearTemporaryNewGRFData(GRFFile *gf) { /* Clear the GOTO labels used for GRF processing */ for (GRFLabel *l = gf->label; l != NULL;) { GRFLabel *l2 = l->next; free(l); l = l2; } gf->label = NULL; } /** * Disable a GRF * @param message Error message or STR_NULL. * @param config GRFConfig to disable, NULL for current. * @return Error message of the GRF for further customisation. */ static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = NULL) { GRFFile *file; if (config != NULL) { file = GetFileByGRFID(config->ident.grfid); } else { config = _cur.grfconfig; file = _cur.grffile; } config->status = GCS_DISABLED; if (file != NULL) ClearTemporaryNewGRFData(file); if (config == _cur.grfconfig) _cur.skip_sprites = -1; if (message != STR_NULL) { delete config->error; config->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, message); if (config == _cur.grfconfig) config->error->param_value[0] = _cur.nfo_line; } return config->error; } /** * Information for mapping static StringIDs. */ struct StringIDMapping { uint32 grfid; ///< Source NewGRF. StringID source; ///< Source StringID (GRF local). StringID *target; ///< Destination for mapping result. }; typedef SmallVector StringIDMappingVector; static StringIDMappingVector _string_to_grf_mapping; /** * Record a static StringID for getting translated later. * @param source Source StringID (GRF local). * @param target Destination for the mapping result. */ static void AddStringForMapping(StringID source, StringID *target) { *target = STR_UNDEFINED; StringIDMapping *item = _string_to_grf_mapping.Append(); item->grfid = _cur.grffile->grfid; item->source = source; item->target = target; } /** * Perform a mapping from TTDPatch's string IDs to OpenTTD's * string IDs, but only for the ones we are aware off; the rest * like likely unused and will show a warning. * @param str the string ID to convert * @return the converted string ID */ static StringID TTDPStringIDToOTTDStringIDMapping(StringID str) { /* StringID table for TextIDs 0x4E->0x6D */ static const StringID units_volume[] = { STR_ITEMS, STR_PASSENGERS, STR_TONS, STR_BAGS, STR_LITERS, STR_ITEMS, STR_CRATES, STR_TONS, STR_TONS, STR_TONS, STR_TONS, STR_BAGS, STR_TONS, STR_TONS, STR_TONS, STR_BAGS, STR_TONS, STR_TONS, STR_BAGS, STR_LITERS, STR_TONS, STR_LITERS, STR_TONS, STR_ITEMS, STR_BAGS, STR_LITERS, STR_TONS, STR_ITEMS, STR_TONS, STR_ITEMS, STR_LITERS, STR_ITEMS }; /* A string straight from a NewGRF; this was already translated by MapGRFStringID(). */ assert(!IsInsideMM(str, 0xD000, 0xD7FF)); #define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \ assert_compile(stringend - stringid == end - begin); \ if (str >= begin && str <= end) return str + (stringid - begin) /* We have some changes in our cargo strings, resulting in some missing. */ TEXTID_TO_STRINGID(0x000E, 0x002D, STR_CARGO_PLURAL_NOTHING, STR_CARGO_PLURAL_FIZZY_DRINKS); TEXTID_TO_STRINGID(0x002E, 0x004D, STR_CARGO_SINGULAR_NOTHING, STR_CARGO_SINGULAR_FIZZY_DRINK); if (str >= 0x004E && str <= 0x006D) return units_volume[str - 0x004E]; TEXTID_TO_STRINGID(0x006E, 0x008D, STR_QUANTITY_NOTHING, STR_QUANTITY_FIZZY_DRINKS); TEXTID_TO_STRINGID(0x008E, 0x00AD, STR_ABBREV_NOTHING, STR_ABBREV_FIZZY_DRINKS); TEXTID_TO_STRINGID(0x00D1, 0x00E0, STR_COLOUR_DARK_BLUE, STR_COLOUR_WHITE); /* Map building names according to our lang file changes. There are several * ranges of house ids, all of which need to be remapped to allow newgrfs * to use original house names. */ TEXTID_TO_STRINGID(0x200F, 0x201F, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1); TEXTID_TO_STRINGID(0x2036, 0x2041, STR_TOWN_BUILDING_NAME_COTTAGES_1, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1); TEXTID_TO_STRINGID(0x2059, 0x205C, STR_TOWN_BUILDING_NAME_IGLOO_1, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1); /* Same thing for industries */ TEXTID_TO_STRINGID(0x4802, 0x4826, STR_INDUSTRY_NAME_COAL_MINE, STR_INDUSTRY_NAME_SUGAR_MINE); TEXTID_TO_STRINGID(0x482D, 0x482E, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_PLANTED); TEXTID_TO_STRINGID(0x4832, 0x4834, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES); TEXTID_TO_STRINGID(0x4835, 0x4838, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM); TEXTID_TO_STRINGID(0x4839, 0x483A, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM); switch (str) { case 0x4830: return STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY; case 0x4831: return STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED; case 0x483B: return STR_ERROR_CAN_ONLY_BE_POSITIONED; } #undef TEXTID_TO_STRINGID if (str == STR_NULL) return STR_EMPTY; DEBUG(grf, 0, "Unknown StringID 0x%04X remapped to STR_EMPTY. Please open a Feature Request if you need it", str); return STR_EMPTY; } /** * Used when setting an object's property to map to the GRF's strings * while taking in consideration the "drift" between TTDPatch string system and OpenTTD's one * @param grfid Id of the grf file. * @param str StringID that we want to have the equivalent in OoenTTD. * @return The properly adjusted StringID. */ StringID MapGRFStringID(uint32 grfid, StringID str) { /* 0xD0 and 0xDC stand for all the TextIDs in the range * of 0xD000 (misc graphics texts) and 0xDC00 (misc persistent texts). * These strings are unique to each grf file, and thus require to be used with the * grfid in which they are declared */ switch (GB(str, 8, 8)) { case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xDC: return GetGRFStringID(grfid, str); case 0xD4: case 0xD5: case 0xD6: case 0xD7: /* Strings embedded via 0x81 have 0x400 added to them (no real * explanation why...) */ return GetGRFStringID(grfid, str - 0x400); default: break; } return TTDPStringIDToOTTDStringIDMapping(str); } static std::map _grf_id_overrides; /** * Set the override for a NewGRF * @param source_grfid The grfID which wants to override another NewGRF. * @param target_grfid The grfID which is being overridden. */ static void SetNewGRFOverride(uint32 source_grfid, uint32 target_grfid) { _grf_id_overrides[source_grfid] = target_grfid; grfmsg(5, "SetNewGRFOverride: Added override of 0x%X to 0x%X", BSWAP32(source_grfid), BSWAP32(target_grfid)); } /** * Returns the engine associated to a certain internal_id, resp. allocates it. * @param file NewGRF that wants to change the engine. * @param type Vehicle type. * @param internal_id Engine ID inside the NewGRF. * @param static_access If the engine is not present, return NULL instead of allocating a new engine. (Used for static Action 0x04). * @return The requested engine. */ static Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16 internal_id, bool static_access = false) { /* Hack for add-on GRFs that need to modify another GRF's engines. This lets * them use the same engine slots. */ uint32 scope_grfid = INVALID_GRFID; // If not using dynamic_engines, all newgrfs share their ID range if (_settings_game.vehicle.dynamic_engines) { /* If dynamic_engies is enabled, there can be multiple independent ID ranges. */ scope_grfid = file->grfid; uint32 override = _grf_id_overrides[file->grfid]; if (override != 0) { scope_grfid = override; const GRFFile *grf_match = GetFileByGRFID(override); if (grf_match == NULL) { grfmsg(5, "Tried mapping from GRFID %x to %x but target is not loaded", BSWAP32(file->grfid), BSWAP32(override)); } else { grfmsg(5, "Mapping from GRFID %x to %x", BSWAP32(file->grfid), BSWAP32(override)); } } /* Check if the engine is registered in the override manager */ EngineID engine = _engine_mngr.GetID(type, internal_id, scope_grfid); if (engine != INVALID_ENGINE) { Engine *e = Engine::Get(engine); if (e->grf_prop.grffile == NULL) e->grf_prop.grffile = file; return e; } } /* Check if there is an unreserved slot */ EngineID engine = _engine_mngr.GetID(type, internal_id, INVALID_GRFID); if (engine != INVALID_ENGINE) { Engine *e = Engine::Get(engine); if (e->grf_prop.grffile == NULL) { e->grf_prop.grffile = file; grfmsg(5, "Replaced engine at index %d for GRFID %x, type %d, index %d", e->index, BSWAP32(file->grfid), type, internal_id); } /* Reserve the engine slot */ if (!static_access) { EngineIDMapping *eid = _engine_mngr.Get(engine); eid->grfid = scope_grfid; // Note: this is INVALID_GRFID if dynamic_engines is disabled, so no reservation } return e; } if (static_access) return NULL; if (!Engine::CanAllocateItem()) { grfmsg(0, "Can't allocate any more engines"); return NULL; } size_t engine_pool_size = Engine::GetPoolSize(); /* ... it's not, so create a new one based off an existing engine */ Engine *e = new Engine(type, internal_id); e->grf_prop.grffile = file; /* Reserve the engine slot */ assert(_engine_mngr.Length() == e->index); EngineIDMapping *eid = _engine_mngr.Append(); eid->type = type; eid->grfid = scope_grfid; // Note: this is INVALID_GRFID if dynamic_engines is disabled, so no reservation eid->internal_id = internal_id; eid->substitute_id = min(internal_id, _engine_counts[type]); // substitute_id == _engine_counts[subtype] means "no substitute" if (engine_pool_size != Engine::GetPoolSize()) { /* Resize temporary engine data ... */ _gted = ReallocT(_gted, Engine::GetPoolSize()); /* and blank the new block. */ size_t len = (Engine::GetPoolSize() - engine_pool_size) * sizeof(*_gted); memset(_gted + engine_pool_size, 0, len); } if (type == VEH_TRAIN) { _gted[e->index].railtypelabel = GetRailTypeInfo(e->u.rail.railtype)->label; } grfmsg(5, "Created new engine at index %d for GRFID %x, type %d, index %d", e->index, BSWAP32(file->grfid), type, internal_id); return e; } /** * Return the ID of a new engine * @param file The NewGRF file providing the engine. * @param type The Vehicle type. * @param internal_id NewGRF-internal ID of the engine. * @return The new EngineID. * @note depending on the dynamic_engine setting and a possible override * property the grfID may be unique or overwriting or partially re-defining * properties of an existing engine. */ EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16 internal_id) { uint32 scope_grfid = INVALID_GRFID; // If not using dynamic_engines, all newgrfs share their ID range if (_settings_game.vehicle.dynamic_engines) { scope_grfid = file->grfid; uint32 override = _grf_id_overrides[file->grfid]; if (override != 0) scope_grfid = override; } return _engine_mngr.GetID(type, internal_id, scope_grfid); } /** * Map the colour modifiers of TTDPatch to those that Open is using. * @param grf_sprite Pointer to the structure been modified. */ static void MapSpriteMappingRecolour(PalSpriteID *grf_sprite) { if (HasBit(grf_sprite->pal, 14)) { ClrBit(grf_sprite->pal, 14); SetBit(grf_sprite->sprite, SPRITE_MODIFIER_OPAQUE); } if (HasBit(grf_sprite->sprite, 14)) { ClrBit(grf_sprite->sprite, 14); SetBit(grf_sprite->sprite, PALETTE_MODIFIER_TRANSPARENT); } if (HasBit(grf_sprite->sprite, 15)) { ClrBit(grf_sprite->sprite, 15); SetBit(grf_sprite->sprite, PALETTE_MODIFIER_COLOUR); } } /** * Read a sprite and a palette from the GRF and convert them into a format * suitable to OpenTTD. * @param buf Input stream. * @param read_flags Whether to read TileLayoutFlags. * @param invert_action1_flag Set to true, if palette bit 15 means 'not from action 1'. * @param use_cur_spritesets Whether to use currently referenceable action 1 sets. * @param feature GrfSpecFeature to use spritesets from. * @param [out] grf_sprite Read sprite and palette. * @param [out] max_sprite_offset Optionally returns the number of sprites in the spriteset of the sprite. (0 if no spritset) * @param [out] max_palette_offset Optionally returns the number of sprites in the spriteset of the palette. (0 if no spritset) * @return Read TileLayoutFlags. */ static TileLayoutFlags ReadSpriteLayoutSprite(ByteReader *buf, bool read_flags, bool invert_action1_flag, bool use_cur_spritesets, int feature, PalSpriteID *grf_sprite, uint16 *max_sprite_offset = NULL, uint16 *max_palette_offset = NULL) { grf_sprite->sprite = buf->ReadWord(); grf_sprite->pal = buf->ReadWord(); TileLayoutFlags flags = read_flags ? (TileLayoutFlags)buf->ReadWord() : TLF_NOTHING; MapSpriteMappingRecolour(grf_sprite); bool custom_sprite = HasBit(grf_sprite->pal, 15) != invert_action1_flag; ClrBit(grf_sprite->pal, 15); if (custom_sprite) { /* Use sprite from Action 1 */ uint index = GB(grf_sprite->sprite, 0, 14); if (use_cur_spritesets && (!_cur.IsValidSpriteSet(feature, index) || _cur.GetNumEnts(feature, index) == 0)) { grfmsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset %d", index); grf_sprite->sprite = SPR_IMG_QUERY; grf_sprite->pal = PAL_NONE; } else { SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index; if (max_sprite_offset != NULL) *max_sprite_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; SB(grf_sprite->sprite, 0, SPRITE_WIDTH, sprite); SetBit(grf_sprite->sprite, SPRITE_MODIFIER_CUSTOM_SPRITE); } } else if ((flags & TLF_SPRITE_VAR10) && !(flags & TLF_SPRITE_REG_FLAGS)) { grfmsg(1, "ReadSpriteLayoutSprite: Spritelayout specifies var10 value for non-action-1 sprite"); DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT); return flags; } if (flags & TLF_CUSTOM_PALETTE) { /* Use palette from Action 1 */ uint index = GB(grf_sprite->pal, 0, 14); if (use_cur_spritesets && (!_cur.IsValidSpriteSet(feature, index) || _cur.GetNumEnts(feature, index) == 0)) { grfmsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset %d for 'palette'", index); grf_sprite->pal = PAL_NONE; } else { SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index; if (max_palette_offset != NULL) *max_palette_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; SB(grf_sprite->pal, 0, SPRITE_WIDTH, sprite); SetBit(grf_sprite->pal, SPRITE_MODIFIER_CUSTOM_SPRITE); } } else if ((flags & TLF_PALETTE_VAR10) && !(flags & TLF_PALETTE_REG_FLAGS)) { grfmsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 value for non-action-1 palette"); DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT); return flags; } return flags; } /** * Preprocess the TileLayoutFlags and read register modifiers from the GRF. * @param buf Input stream. * @param flags TileLayoutFlags to process. * @param is_parent Whether the sprite is a parentsprite with a bounding box. * @param dts Sprite layout to insert data into. * @param index Sprite index to process; 0 for ground sprite. */ static void ReadSpriteLayoutRegisters(ByteReader *buf, TileLayoutFlags flags, bool is_parent, NewGRFSpriteLayout *dts, uint index) { if (!(flags & TLF_DRAWING_FLAGS)) return; if (dts->registers == NULL) dts->AllocateRegisters(); TileLayoutRegisters ®s = const_cast(dts->registers[index]); regs.flags = flags & TLF_DRAWING_FLAGS; if (flags & TLF_DODRAW) regs.dodraw = buf->ReadByte(); if (flags & TLF_SPRITE) regs.sprite = buf->ReadByte(); if (flags & TLF_PALETTE) regs.palette = buf->ReadByte(); if (is_parent) { if (flags & TLF_BB_XY_OFFSET) { regs.delta.parent[0] = buf->ReadByte(); regs.delta.parent[1] = buf->ReadByte(); } if (flags & TLF_BB_Z_OFFSET) regs.delta.parent[2] = buf->ReadByte(); } else { if (flags & TLF_CHILD_X_OFFSET) regs.delta.child[0] = buf->ReadByte(); if (flags & TLF_CHILD_Y_OFFSET) regs.delta.child[1] = buf->ReadByte(); } if (flags & TLF_SPRITE_VAR10) { regs.sprite_var10 = buf->ReadByte(); if (regs.sprite_var10 > TLR_MAX_VAR10) { grfmsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 (%d) exceeding the maximal allowed value %d", regs.sprite_var10, TLR_MAX_VAR10); DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT); return; } } if (flags & TLF_PALETTE_VAR10) { regs.palette_var10 = buf->ReadByte(); if (regs.palette_var10 > TLR_MAX_VAR10) { grfmsg(1, "ReadSpriteLayoutRegisters: Spritelayout specifies var10 (%d) exceeding the maximal allowed value %d", regs.palette_var10, TLR_MAX_VAR10); DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT); return; } } } /** * Read a spritelayout from the GRF. * @param buf Input * @param num_building_sprites Number of building sprites to read * @param use_cur_spritesets Whether to use currently referenceable action 1 sets. * @param feature GrfSpecFeature to use spritesets from. * @param allow_var10 Whether the spritelayout may specifiy var10 values for resolving multiple action-1-2-3 chains * @param no_z_position Whether bounding boxes have no Z offset * @param dts Layout container to output into * @return True on error (GRF was disabled). */ static bool ReadSpriteLayout(ByteReader *buf, uint num_building_sprites, bool use_cur_spritesets, byte feature, bool allow_var10, bool no_z_position, NewGRFSpriteLayout *dts) { bool has_flags = HasBit(num_building_sprites, 6); ClrBit(num_building_sprites, 6); TileLayoutFlags valid_flags = TLF_KNOWN_FLAGS; if (!allow_var10) valid_flags &= ~TLF_VAR10_FLAGS; dts->Allocate(num_building_sprites); // allocate before reading groundsprite flags uint16 *max_sprite_offset = AllocaM(uint16, num_building_sprites + 1); uint16 *max_palette_offset = AllocaM(uint16, num_building_sprites + 1); MemSetT(max_sprite_offset, 0, num_building_sprites + 1); MemSetT(max_palette_offset, 0, num_building_sprites + 1); /* Groundsprite */ TileLayoutFlags flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &dts->ground, max_sprite_offset, max_palette_offset); if (_cur.skip_sprites < 0) return true; if (flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS)) { grfmsg(1, "ReadSpriteLayout: Spritelayout uses invalid flag 0x%x for ground sprite", flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS)); DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT); return true; } ReadSpriteLayoutRegisters(buf, flags, false, dts, 0); if (_cur.skip_sprites < 0) return true; for (uint i = 0; i < num_building_sprites; i++) { DrawTileSeqStruct *seq = const_cast(&dts->seq[i]); flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &seq->image, max_sprite_offset + i + 1, max_palette_offset + i + 1); if (_cur.skip_sprites < 0) return true; if (flags & ~valid_flags) { grfmsg(1, "ReadSpriteLayout: Spritelayout uses unknown flag 0x%x", flags & ~valid_flags); DisableGrf(STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT); return true; } seq->delta_x = buf->ReadByte(); seq->delta_y = buf->ReadByte(); if (!no_z_position) seq->delta_z = buf->ReadByte(); if (seq->IsParentSprite()) { seq->size_x = buf->ReadByte(); seq->size_y = buf->ReadByte(); seq->size_z = buf->ReadByte(); } ReadSpriteLayoutRegisters(buf, flags, seq->IsParentSprite(), dts, i + 1); if (_cur.skip_sprites < 0) return true; } /* Check if the number of sprites per spriteset is consistent */ bool is_consistent = true; dts->consistent_max_offset = 0; for (uint i = 0; i < num_building_sprites + 1; i++) { if (max_sprite_offset[i] > 0) { if (dts->consistent_max_offset == 0) { dts->consistent_max_offset = max_sprite_offset[i]; } else if (dts->consistent_max_offset != max_sprite_offset[i]) { is_consistent = false; break; } } if (max_palette_offset[i] > 0) { if (dts->consistent_max_offset == 0) { dts->consistent_max_offset = max_palette_offset[i]; } else if (dts->consistent_max_offset != max_palette_offset[i]) { is_consistent = false; break; } } } /* When the Action1 sets are unknown, everything should be 0 (no spriteset usage) or UINT16_MAX (some spriteset usage) */ assert(use_cur_spritesets || (is_consistent && (dts->consistent_max_offset == 0 || dts->consistent_max_offset == UINT16_MAX))); if (!is_consistent || dts->registers != NULL) { dts->consistent_max_offset = 0; if (dts->registers == NULL) dts->AllocateRegisters(); for (uint i = 0; i < num_building_sprites + 1; i++) { TileLayoutRegisters ®s = const_cast(dts->registers[i]); regs.max_sprite_offset = max_sprite_offset[i]; regs.max_palette_offset = max_palette_offset[i]; } } return false; } /** * Translate the refit mask. */ static uint32 TranslateRefitMask(uint32 refit_mask) { uint32 result = 0; uint8 bit; FOR_EACH_SET_BIT(bit, refit_mask) { CargoID cargo = GetCargoTranslation(bit, _cur.grffile, true); if (cargo != CT_INVALID) SetBit(result, cargo); } return result; } /** * Converts TTD(P) Base Price pointers into the enum used by OTTD * See http://wiki.ttdpatch.net/tiki-index.php?page=BaseCosts * @param base_pointer TTD(P) Base Price Pointer * @param error_location Function name for grf error messages * @param[out] index If \a base_pointer is valid, \a index is assigned to the matching price; else it is left unchanged */ static void ConvertTTDBasePrice(uint32 base_pointer, const char *error_location, Price *index) { /* Special value for 'none' */ if (base_pointer == 0) { *index = INVALID_PRICE; return; } static const uint32 start = 0x4B34; ///< Position of first base price static const uint32 size = 6; ///< Size of each base price record if (base_pointer < start || (base_pointer - start) % size != 0 || (base_pointer - start) / size >= PR_END) { grfmsg(1, "%s: Unsupported running cost base 0x%04X, ignoring", error_location, base_pointer); return; } *index = (Price)((base_pointer - start) / size); } /** Possible return values for the FeatureChangeInfo functions */ enum ChangeInfoResult { CIR_SUCCESS, ///< Variable was parsed and read CIR_DISABLED, ///< GRF was disabled due to error CIR_UNHANDLED, ///< Variable was parsed but unread CIR_UNKNOWN, ///< Variable is unknown CIR_INVALID_ID, ///< Attempt to modify an invalid ID }; typedef ChangeInfoResult (*VCI_Handler)(uint engine, int numinfo, int prop, ByteReader *buf); /** * Define properties common to all vehicles * @param ei Engine info. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteReader *buf) { switch (prop) { case 0x00: // Introduction date ei->base_intro = buf->ReadWord() + DAYS_TILL_ORIGINAL_BASE_YEAR; break; case 0x02: // Decay speed ei->decay_speed = buf->ReadByte(); break; case 0x03: // Vehicle life ei->lifelength = buf->ReadByte(); break; case 0x04: // Model life ei->base_life = buf->ReadByte(); break; case 0x06: // Climates available ei->climates = buf->ReadByte(); break; case PROP_VEHICLE_LOAD_AMOUNT: // 0x07 Loading speed /* Amount of cargo loaded during a vehicle's "loading tick" */ ei->load_amount = buf->ReadByte(); break; default: return CIR_UNKNOWN; } return CIR_SUCCESS; } /** * Define properties for rail vehicles * @param engine :ocal ID of the first vehicle. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_TRAIN, engine + i); if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; RailVehicleInfo *rvi = &e->u.rail; switch (prop) { case 0x05: { // Track type uint8 tracktype = buf->ReadByte(); if (tracktype < _cur.grffile->railtype_list.Length()) { _gted[e->index].railtypelabel = _cur.grffile->railtype_list[tracktype]; break; } switch (tracktype) { case 0: _gted[e->index].railtypelabel = rvi->engclass >= 2 ? RAILTYPE_ELECTRIC_LABEL : RAILTYPE_RAIL_LABEL; break; case 1: _gted[e->index].railtypelabel = RAILTYPE_MONO_LABEL; break; case 2: _gted[e->index].railtypelabel = RAILTYPE_MAGLEV_LABEL; break; default: grfmsg(1, "RailVehicleChangeInfo: Invalid track type %d specified, ignoring", tracktype); break; } break; } case 0x08: // AI passenger service /* Tells the AI that this engine is designed for * passenger services and shouldn't be used for freight. */ rvi->ai_passenger_only = buf->ReadByte(); break; case PROP_TRAIN_SPEED: { // 0x09 Speed (1 unit is 1 km-ish/h) uint16 speed = buf->ReadWord(); if (speed == 0xFFFF) speed = 0; rvi->max_speed = speed; break; } case PROP_TRAIN_POWER: // 0x0B Power rvi->power = buf->ReadWord(); /* Set engine / wagon state based on power */ if (rvi->power != 0) { if (rvi->railveh_type == RAILVEH_WAGON) { rvi->railveh_type = RAILVEH_SINGLEHEAD; } } else { rvi->railveh_type = RAILVEH_WAGON; } break; case PROP_TRAIN_RUNNING_COST_FACTOR: // 0x0D Running cost factor rvi->running_cost = buf->ReadByte(); break; case 0x0E: // Running cost base ConvertTTDBasePrice(buf->ReadDWord(), "RailVehicleChangeInfo", &rvi->running_cost_class); break; case 0x12: { // Sprite ID uint8 spriteid = buf->ReadByte(); uint8 orig_spriteid = spriteid; /* TTD sprite IDs point to a location in a 16bit array, but we use it * as an array index, so we need it to be half the original value. */ if (spriteid < 0xFD) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { rvi->image_index = spriteid; } else { grfmsg(1, "RailVehicleChangeInfo: Invalid Sprite %d specified, ignoring", orig_spriteid); rvi->image_index = 0; } break; } case 0x13: { // Dual-headed uint8 dual = buf->ReadByte(); if (dual != 0) { rvi->railveh_type = RAILVEH_MULTIHEAD; } else { rvi->railveh_type = rvi->power == 0 ? RAILVEH_WAGON : RAILVEH_SINGLEHEAD; } break; } case PROP_TRAIN_CARGO_CAPACITY: // 0x14 Cargo capacity rvi->capacity = buf->ReadByte(); break; case 0x15: { // Cargo type _gted[e->index].defaultcargo_grf = _cur.grffile; uint8 ctype = buf->ReadByte(); if (ctype == 0xFF) { /* 0xFF is specified as 'use first refittable' */ ei->cargo_type = CT_INVALID; } else if (_cur.grffile->grf_version >= 8) { /* Use translated cargo. Might result in CT_INVALID (first refittable), if cargo is not defined. */ ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); } else if (ctype < NUM_CARGO) { /* Use untranslated cargo. */ ei->cargo_type = ctype; } else { ei->cargo_type = CT_INVALID; grfmsg(2, "RailVehicleChangeInfo: Invalid cargo type %d, using first refittable", ctype); } break; } case PROP_TRAIN_WEIGHT: // 0x16 Weight SB(rvi->weight, 0, 8, buf->ReadByte()); break; case PROP_TRAIN_COST_FACTOR: // 0x17 Cost factor rvi->cost_factor = buf->ReadByte(); break; case 0x18: // AI rank grfmsg(2, "RailVehicleChangeInfo: Property 0x18 'AI rank' not used by NoAI, ignored."); buf->ReadByte(); break; case 0x19: { // Engine traction type /* What do the individual numbers mean? * 0x00 .. 0x07: Steam * 0x08 .. 0x27: Diesel * 0x28 .. 0x31: Electric * 0x32 .. 0x37: Monorail * 0x38 .. 0x41: Maglev */ uint8 traction = buf->ReadByte(); EngineClass engclass; if (traction <= 0x07) { engclass = EC_STEAM; } else if (traction <= 0x27) { engclass = EC_DIESEL; } else if (traction <= 0x31) { engclass = EC_ELECTRIC; } else if (traction <= 0x37) { engclass = EC_MONORAIL; } else if (traction <= 0x41) { engclass = EC_MAGLEV; } else { break; } if (_cur.grffile->railtype_list.Length() == 0) { /* Use traction type to select between normal and electrified * rail only when no translation list is in place. */ if (_gted[e->index].railtypelabel == RAILTYPE_RAIL_LABEL && engclass >= EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_ELECTRIC_LABEL; if (_gted[e->index].railtypelabel == RAILTYPE_ELECTRIC_LABEL && engclass < EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_RAIL_LABEL; } rvi->engclass = engclass; break; } case 0x1A: // Alter purchase list sort order AlterVehicleListOrder(e->index, buf->ReadExtendedByte()); break; case 0x1B: // Powered wagons power bonus rvi->pow_wag_power = buf->ReadWord(); break; case 0x1C: // Refit cost ei->refit_cost = buf->ReadByte(); break; case 0x1D: { // Refit cargo uint32 mask = buf->ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); _gted[e->index].defaultcargo_grf = _cur.grffile; break; } case 0x1E: // Callback ei->callback_mask = buf->ReadByte(); break; case PROP_TRAIN_TRACTIVE_EFFORT: // 0x1F Tractive effort coefficient rvi->tractive_effort = buf->ReadByte(); break; case 0x20: // Air drag rvi->air_drag = buf->ReadByte(); break; case PROP_TRAIN_SHORTEN_FACTOR: // 0x21 Shorter vehicle rvi->shorten_factor = buf->ReadByte(); break; case 0x22: // Visual effect rvi->visual_effect = buf->ReadByte(); /* Avoid accidentally setting visual_effect to the default value * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */ if (rvi->visual_effect == VE_DEFAULT) { assert(HasBit(rvi->visual_effect, VE_DISABLE_EFFECT)); SB(rvi->visual_effect, VE_TYPE_START, VE_TYPE_COUNT, 0); } break; case 0x23: // Powered wagons weight bonus rvi->pow_wag_weight = buf->ReadByte(); break; case 0x24: { // High byte of vehicle weight byte weight = buf->ReadByte(); if (weight > 4) { grfmsg(2, "RailVehicleChangeInfo: Nonsensical weight of %d tons, ignoring", weight << 8); } else { SB(rvi->weight, 8, 8, weight); } break; } case PROP_TRAIN_USER_DATA: // 0x25 User-defined bit mask to set when checking veh. var. 42 rvi->user_def_data = buf->ReadByte(); break; case 0x26: // Retire vehicle early ei->retire_early = buf->ReadByte(); break; case 0x27: // Miscellaneous flags ei->misc_flags = buf->ReadByte(); _loaded_newgrf_features.has_2CC |= HasBit(ei->misc_flags, EF_USES_2CC); _gted[e->index].prop27_set = true; break; case 0x28: // Cargo classes allowed _gted[e->index].cargo_allowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0); _gted[e->index].defaultcargo_grf = _cur.grffile; break; case 0x29: // Cargo classes disallowed _gted[e->index].cargo_disallowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(false); break; case 0x2A: // Long format introduction date (days since year 0) ei->base_intro = buf->ReadDWord(); break; case PROP_TRAIN_CARGO_AGE_PERIOD: // 0x2B Cargo aging period ei->cargo_age_period = buf->ReadWord(); break; case 0x2C: // CTT refit include list case 0x2D: { // CTT refit exclude list uint8 count = buf->ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x2C && count != 0); if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur.grffile; uint32 &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile); if (ctype == CT_INVALID) continue; SetBit(ctt, ctype); } break; } default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; } } return ret; } /** * Define properties for road vehicles * @param engine Local ID of the first vehicle. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_ROAD, engine + i); if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; RoadVehicleInfo *rvi = &e->u.road; switch (prop) { case 0x08: // Speed (1 unit is 0.5 kmh) rvi->max_speed = buf->ReadByte(); break; case PROP_ROADVEH_RUNNING_COST_FACTOR: // 0x09 Running cost factor rvi->running_cost = buf->ReadByte(); break; case 0x0A: // Running cost base ConvertTTDBasePrice(buf->ReadDWord(), "RoadVehicleChangeInfo", &rvi->running_cost_class); break; case 0x0E: { // Sprite ID uint8 spriteid = buf->ReadByte(); uint8 orig_spriteid = spriteid; /* cars have different custom id in the GRF file */ if (spriteid == 0xFF) spriteid = 0xFD; if (spriteid < 0xFD) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { rvi->image_index = spriteid; } else { grfmsg(1, "RoadVehicleChangeInfo: Invalid Sprite %d specified, ignoring", orig_spriteid); rvi->image_index = 0; } break; } case PROP_ROADVEH_CARGO_CAPACITY: // 0x0F Cargo capacity rvi->capacity = buf->ReadByte(); break; case 0x10: { // Cargo type _gted[e->index].defaultcargo_grf = _cur.grffile; uint8 ctype = buf->ReadByte(); if (ctype == 0xFF) { /* 0xFF is specified as 'use first refittable' */ ei->cargo_type = CT_INVALID; } else if (_cur.grffile->grf_version >= 8) { /* Use translated cargo. Might result in CT_INVALID (first refittable), if cargo is not defined. */ ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); } else if (ctype < NUM_CARGO) { /* Use untranslated cargo. */ ei->cargo_type = ctype; } else { ei->cargo_type = CT_INVALID; grfmsg(2, "RailVehicleChangeInfo: Invalid cargo type %d, using first refittable", ctype); } break; } case PROP_ROADVEH_COST_FACTOR: // 0x11 Cost factor rvi->cost_factor = buf->ReadByte(); break; case 0x12: // SFX rvi->sfx = buf->ReadByte(); break; case PROP_ROADVEH_POWER: // Power in units of 10 HP. rvi->power = buf->ReadByte(); break; case PROP_ROADVEH_WEIGHT: // Weight in units of 1/4 tons. rvi->weight = buf->ReadByte(); break; case PROP_ROADVEH_SPEED: // Speed in mph/0.8 _gted[e->index].rv_max_speed = buf->ReadByte(); break; case 0x16: { // Cargoes available for refitting uint32 mask = buf->ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); _gted[e->index].defaultcargo_grf = _cur.grffile; break; } case 0x17: // Callback mask ei->callback_mask = buf->ReadByte(); break; case PROP_ROADVEH_TRACTIVE_EFFORT: // Tractive effort coefficient in 1/256. rvi->tractive_effort = buf->ReadByte(); break; case 0x19: // Air drag rvi->air_drag = buf->ReadByte(); break; case 0x1A: // Refit cost ei->refit_cost = buf->ReadByte(); break; case 0x1B: // Retire vehicle early ei->retire_early = buf->ReadByte(); break; case 0x1C: // Miscellaneous flags ei->misc_flags = buf->ReadByte(); _loaded_newgrf_features.has_2CC |= HasBit(ei->misc_flags, EF_USES_2CC); break; case 0x1D: // Cargo classes allowed _gted[e->index].cargo_allowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0); _gted[e->index].defaultcargo_grf = _cur.grffile; break; case 0x1E: // Cargo classes disallowed _gted[e->index].cargo_disallowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(false); break; case 0x1F: // Long format introduction date (days since year 0) ei->base_intro = buf->ReadDWord(); break; case 0x20: // Alter purchase list sort order AlterVehicleListOrder(e->index, buf->ReadExtendedByte()); break; case 0x21: // Visual effect rvi->visual_effect = buf->ReadByte(); /* Avoid accidentally setting visual_effect to the default value * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */ if (rvi->visual_effect == VE_DEFAULT) { assert(HasBit(rvi->visual_effect, VE_DISABLE_EFFECT)); SB(rvi->visual_effect, VE_TYPE_START, VE_TYPE_COUNT, 0); } break; case PROP_ROADVEH_CARGO_AGE_PERIOD: // 0x22 Cargo aging period ei->cargo_age_period = buf->ReadWord(); break; case PROP_ROADVEH_SHORTEN_FACTOR: // 0x23 Shorter vehicle rvi->shorten_factor = buf->ReadByte(); break; case 0x24: // CTT refit include list case 0x25: { // CTT refit exclude list uint8 count = buf->ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x24 && count != 0); if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur.grffile; uint32 &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile); if (ctype == CT_INVALID) continue; SetBit(ctt, ctype); } break; } default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; } } return ret; } /** * Define properties for ships * @param engine Local ID of the first vehicle. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_SHIP, engine + i); if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; ShipVehicleInfo *svi = &e->u.ship; switch (prop) { case 0x08: { // Sprite ID uint8 spriteid = buf->ReadByte(); uint8 orig_spriteid = spriteid; /* ships have different custom id in the GRF file */ if (spriteid == 0xFF) spriteid = 0xFD; if (spriteid < 0xFD) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { svi->image_index = spriteid; } else { grfmsg(1, "ShipVehicleChangeInfo: Invalid Sprite %d specified, ignoring", orig_spriteid); svi->image_index = 0; } break; } case 0x09: // Refittable svi->old_refittable = (buf->ReadByte() != 0); break; case PROP_SHIP_COST_FACTOR: // 0x0A Cost factor svi->cost_factor = buf->ReadByte(); break; case PROP_SHIP_SPEED: // 0x0B Speed (1 unit is 0.5 km-ish/h) svi->max_speed = buf->ReadByte(); break; case 0x0C: { // Cargo type _gted[e->index].defaultcargo_grf = _cur.grffile; uint8 ctype = buf->ReadByte(); if (ctype == 0xFF) { /* 0xFF is specified as 'use first refittable' */ ei->cargo_type = CT_INVALID; } else if (_cur.grffile->grf_version >= 8) { /* Use translated cargo. Might result in CT_INVALID (first refittable), if cargo is not defined. */ ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); } else if (ctype < NUM_CARGO) { /* Use untranslated cargo. */ ei->cargo_type = ctype; } else { ei->cargo_type = CT_INVALID; grfmsg(2, "RailVehicleChangeInfo: Invalid cargo type %d, using first refittable", ctype); } break; } case PROP_SHIP_CARGO_CAPACITY: // 0x0D Cargo capacity svi->capacity = buf->ReadWord(); break; case PROP_SHIP_RUNNING_COST_FACTOR: // 0x0F Running cost factor svi->running_cost = buf->ReadByte(); break; case 0x10: // SFX svi->sfx = buf->ReadByte(); break; case 0x11: { // Cargoes available for refitting uint32 mask = buf->ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); _gted[e->index].defaultcargo_grf = _cur.grffile; break; } case 0x12: // Callback mask ei->callback_mask = buf->ReadByte(); break; case 0x13: // Refit cost ei->refit_cost = buf->ReadByte(); break; case 0x14: // Ocean speed fraction svi->ocean_speed_frac = buf->ReadByte(); break; case 0x15: // Canal speed fraction svi->canal_speed_frac = buf->ReadByte(); break; case 0x16: // Retire vehicle early ei->retire_early = buf->ReadByte(); break; case 0x17: // Miscellaneous flags ei->misc_flags = buf->ReadByte(); _loaded_newgrf_features.has_2CC |= HasBit(ei->misc_flags, EF_USES_2CC); break; case 0x18: // Cargo classes allowed _gted[e->index].cargo_allowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0); _gted[e->index].defaultcargo_grf = _cur.grffile; break; case 0x19: // Cargo classes disallowed _gted[e->index].cargo_disallowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(false); break; case 0x1A: // Long format introduction date (days since year 0) ei->base_intro = buf->ReadDWord(); break; case 0x1B: // Alter purchase list sort order AlterVehicleListOrder(e->index, buf->ReadExtendedByte()); break; case 0x1C: // Visual effect svi->visual_effect = buf->ReadByte(); /* Avoid accidentally setting visual_effect to the default value * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */ if (svi->visual_effect == VE_DEFAULT) { assert(HasBit(svi->visual_effect, VE_DISABLE_EFFECT)); SB(svi->visual_effect, VE_TYPE_START, VE_TYPE_COUNT, 0); } break; case PROP_SHIP_CARGO_AGE_PERIOD: // 0x1D Cargo aging period ei->cargo_age_period = buf->ReadWord(); break; case 0x1E: // CTT refit include list case 0x1F: { // CTT refit exclude list uint8 count = buf->ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x1E && count != 0); if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur.grffile; uint32 &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile); if (ctype == CT_INVALID) continue; SetBit(ctt, ctype); } break; } default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; } } return ret; } /** * Define properties for aircraft * @param engine Local ID of the aircraft. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult AircraftVehicleChangeInfo(uint engine, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; for (int i = 0; i < numinfo; i++) { Engine *e = GetNewEngine(_cur.grffile, VEH_AIRCRAFT, engine + i); if (e == NULL) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; AircraftVehicleInfo *avi = &e->u.air; switch (prop) { case 0x08: { // Sprite ID uint8 spriteid = buf->ReadByte(); uint8 orig_spriteid = spriteid; /* aircraft have different custom id in the GRF file */ if (spriteid == 0xFF) spriteid = 0xFD; if (spriteid < 0xFD) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { avi->image_index = spriteid; } else { grfmsg(1, "AircraftVehicleChangeInfo: Invalid Sprite %d specified, ignoring", orig_spriteid); avi->image_index = 0; } break; } case 0x09: // Helicopter if (buf->ReadByte() == 0) { avi->subtype = AIR_HELI; } else { SB(avi->subtype, 0, 1, 1); // AIR_CTOL } break; case 0x0A: // Large SB(avi->subtype, 1, 1, (buf->ReadByte() != 0 ? 1 : 0)); // AIR_FAST break; case PROP_AIRCRAFT_COST_FACTOR: // 0x0B Cost factor avi->cost_factor = buf->ReadByte(); break; case PROP_AIRCRAFT_SPEED: // 0x0C Speed (1 unit is 8 mph, we translate to 1 unit is 1 km-ish/h) avi->max_speed = (buf->ReadByte() * 128) / 10; break; case 0x0D: // Acceleration avi->acceleration = buf->ReadByte(); break; case PROP_AIRCRAFT_RUNNING_COST_FACTOR: // 0x0E Running cost factor avi->running_cost = buf->ReadByte(); break; case PROP_AIRCRAFT_PASSENGER_CAPACITY: // 0x0F Passenger capacity avi->passenger_capacity = buf->ReadWord(); break; case PROP_AIRCRAFT_MAIL_CAPACITY: // 0x11 Mail capacity avi->mail_capacity = buf->ReadByte(); break; case 0x12: // SFX avi->sfx = buf->ReadByte(); break; case 0x13: { // Cargoes available for refitting uint32 mask = buf->ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); _gted[e->index].defaultcargo_grf = _cur.grffile; break; } case 0x14: // Callback mask ei->callback_mask = buf->ReadByte(); break; case 0x15: // Refit cost ei->refit_cost = buf->ReadByte(); break; case 0x16: // Retire vehicle early ei->retire_early = buf->ReadByte(); break; case 0x17: // Miscellaneous flags ei->misc_flags = buf->ReadByte(); _loaded_newgrf_features.has_2CC |= HasBit(ei->misc_flags, EF_USES_2CC); break; case 0x18: // Cargo classes allowed _gted[e->index].cargo_allowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed != 0); _gted[e->index].defaultcargo_grf = _cur.grffile; break; case 0x19: // Cargo classes disallowed _gted[e->index].cargo_disallowed = buf->ReadWord(); _gted[e->index].UpdateRefittability(false); break; case 0x1A: // Long format introduction date (days since year 0) ei->base_intro = buf->ReadDWord(); break; case 0x1B: // Alter purchase list sort order AlterVehicleListOrder(e->index, buf->ReadExtendedByte()); break; case PROP_AIRCRAFT_CARGO_AGE_PERIOD: // 0x1C Cargo aging period ei->cargo_age_period = buf->ReadWord(); break; case 0x1D: // CTT refit include list case 0x1E: { // CTT refit exclude list uint8 count = buf->ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x1D && count != 0); if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur.grffile; uint32 &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile); if (ctype == CT_INVALID) continue; SetBit(ctt, ctype); } break; } case PROP_AIRCRAFT_RANGE: // 0x1F Max aircraft range avi->max_range = buf->ReadWord(); break; default: ret = CommonVehicleChangeInfo(ei, prop, buf); break; } } return ret; } /** * Define properties for stations * @param stdid StationID of the first station tile. * @param numinfo Number of subsequent station tiles to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (stid + numinfo > NUM_STATIONS_PER_GRF) { grfmsg(1, "StationChangeInfo: Station %u is invalid, max %u, ignoring", stid + numinfo, NUM_STATIONS_PER_GRF); return CIR_INVALID_ID; } /* Allocate station specs if necessary */ if (_cur.grffile->stations == NULL) _cur.grffile->stations = CallocT(NUM_STATIONS_PER_GRF); for (int i = 0; i < numinfo; i++) { StationSpec *statspec = _cur.grffile->stations[stid + i]; /* Check that the station we are modifying is defined. */ if (statspec == NULL && prop != 0x08) { grfmsg(2, "StationChangeInfo: Attempt to modify undefined station %u, ignoring", stid + i); return CIR_INVALID_ID; } switch (prop) { case 0x08: { // Class ID StationSpec **spec = &_cur.grffile->stations[stid + i]; /* Property 0x08 is special; it is where the station is allocated */ if (*spec == NULL) *spec = CallocT(1); /* Swap classid because we read it in BE meaning WAYP or DFLT */ uint32 classid = buf->ReadDWord(); (*spec)->cls_id = StationClass::Allocate(BSWAP32(classid)); break; } case 0x09: // Define sprite layout statspec->tiles = buf->ReadExtendedByte(); delete[] statspec->renderdata; // delete earlier loaded stuff statspec->renderdata = new NewGRFSpriteLayout[statspec->tiles]; for (uint t = 0; t < statspec->tiles; t++) { NewGRFSpriteLayout *dts = &statspec->renderdata[t]; dts->consistent_max_offset = UINT16_MAX; // Spritesets are unknown, so no limit. if (buf->HasData(4) && *(uint32*)buf->Data() == 0) { buf->Skip(4); extern const DrawTileSprites _station_display_datas_rail[8]; dts->Clone(&_station_display_datas_rail[t % 8]); continue; } ReadSpriteLayoutSprite(buf, false, false, false, GSF_STATIONS, &dts->ground); /* On error, bail out immediately. Temporary GRF data was already freed */ if (_cur.skip_sprites < 0) return CIR_DISABLED; static SmallVector tmp_layout; tmp_layout.Clear(); for (;;) { /* no relative bounding box support */ DrawTileSeqStruct *dtss = tmp_layout.Append(); MemSetT(dtss, 0); dtss->delta_x = buf->ReadByte(); if (dtss->IsTerminator()) break; dtss->delta_y = buf->ReadByte(); dtss->delta_z = buf->ReadByte(); dtss->size_x = buf->ReadByte(); dtss->size_y = buf->ReadByte(); dtss->size_z = buf->ReadByte(); ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss->image); /* On error, bail out immediately. Temporary GRF data was already freed */ if (_cur.skip_sprites < 0) return CIR_DISABLED; } dts->Clone(tmp_layout.Begin()); } break; case 0x0A: { // Copy sprite layout byte srcid = buf->ReadByte(); const StationSpec *srcstatspec = _cur.grffile->stations[srcid]; if (srcstatspec == NULL) { grfmsg(1, "StationChangeInfo: Station %u is not defined, cannot copy sprite layout to %u.", srcid, stid + i); continue; } delete[] statspec->renderdata; // delete earlier loaded stuff statspec->tiles = srcstatspec->tiles; statspec->renderdata = new NewGRFSpriteLayout[statspec->tiles]; for (uint t = 0; t < statspec->tiles; t++) { statspec->renderdata[t].Clone(&srcstatspec->renderdata[t]); } break; } case 0x0B: // Callback mask statspec->callback_mask = buf->ReadByte(); break; case 0x0C: // Disallowed number of platforms statspec->disallowed_platforms = buf->ReadByte(); break; case 0x0D: // Disallowed platform lengths statspec->disallowed_lengths = buf->ReadByte(); break; case 0x0E: // Define custom layout statspec->copied_layouts = false; while (buf->HasData()) { byte length = buf->ReadByte(); byte number = buf->ReadByte(); StationLayout layout; uint l, p; if (length == 0 || number == 0) break; if (length > statspec->lengths) { statspec->platforms = ReallocT(statspec->platforms, length); memset(statspec->platforms + statspec->lengths, 0, length - statspec->lengths); statspec->layouts = ReallocT(statspec->layouts, length); memset(statspec->layouts + statspec->lengths, 0, (length - statspec->lengths) * sizeof(*statspec->layouts)); statspec->lengths = length; } l = length - 1; // index is zero-based if (number > statspec->platforms[l]) { statspec->layouts[l] = ReallocT(statspec->layouts[l], number); /* We expect NULL being 0 here, but C99 guarantees that. */ memset(statspec->layouts[l] + statspec->platforms[l], 0, (number - statspec->platforms[l]) * sizeof(**statspec->layouts)); statspec->platforms[l] = number; } p = 0; layout = MallocT(length * number); try { for (l = 0; l < length; l++) { for (p = 0; p < number; p++) { layout[l * number + p] = buf->ReadByte(); } } } catch (...) { free(layout); throw; } l--; p--; free(statspec->layouts[l][p]); statspec->layouts[l][p] = layout; } break; case 0x0F: { // Copy custom layout byte srcid = buf->ReadByte(); const StationSpec *srcstatspec = _cur.grffile->stations[srcid]; if (srcstatspec == NULL) { grfmsg(1, "StationChangeInfo: Station %u is not defined, cannot copy tile layout to %u.", srcid, stid + i); continue; } statspec->lengths = srcstatspec->lengths; statspec->platforms = srcstatspec->platforms; statspec->layouts = srcstatspec->layouts; statspec->copied_layouts = true; break; } case 0x10: // Little/lots cargo threshold statspec->cargo_threshold = buf->ReadWord(); break; case 0x11: // Pylon placement statspec->pylons = buf->ReadByte(); break; case 0x12: // Cargo types for random triggers statspec->cargo_triggers = buf->ReadDWord(); if (_cur.grffile->grf_version >= 7) { statspec->cargo_triggers = TranslateRefitMask(statspec->cargo_triggers); } break; case 0x13: // General flags statspec->flags = buf->ReadByte(); break; case 0x14: // Overhead wire placement statspec->wires = buf->ReadByte(); break; case 0x15: // Blocked tiles statspec->blocked = buf->ReadByte(); break; case 0x16: // Animation info statspec->animation.frames = buf->ReadByte(); statspec->animation.status = buf->ReadByte(); break; case 0x17: // Animation speed statspec->animation.speed = buf->ReadByte(); break; case 0x18: // Animation triggers statspec->animation.triggers = buf->ReadWord(); break; case 0x1A: // Advanced sprite layout statspec->tiles = buf->ReadExtendedByte(); delete[] statspec->renderdata; // delete earlier loaded stuff statspec->renderdata = new NewGRFSpriteLayout[statspec->tiles]; for (uint t = 0; t < statspec->tiles; t++) { NewGRFSpriteLayout *dts = &statspec->renderdata[t]; uint num_building_sprites = buf->ReadByte(); /* On error, bail out immediately. Temporary GRF data was already freed */ if (ReadSpriteLayout(buf, num_building_sprites, false, GSF_STATIONS, true, false, dts)) return CIR_DISABLED; } break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Define properties for water features * @param id Type of the first water feature. * @param numinfo Number of subsequent water feature ids to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult CanalChangeInfo(uint id, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (id + numinfo > CF_END) { grfmsg(1, "CanalChangeInfo: Canal feature %u is invalid, max %u, ignoring", id + numinfo, CF_END); return CIR_INVALID_ID; } for (int i = 0; i < numinfo; i++) { CanalProperties *cp = &_cur.grffile->canal_local_properties[id + i]; switch (prop) { case 0x08: cp->callback_mask = buf->ReadByte(); break; case 0x09: cp->flags = buf->ReadByte(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Define properties for bridges * @param brid BridgeID of the bridge. * @param numinfo Number of subsequent bridgeIDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult BridgeChangeInfo(uint brid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (brid + numinfo > MAX_BRIDGES) { grfmsg(1, "BridgeChangeInfo: Bridge %u is invalid, max %u, ignoring", brid + numinfo, MAX_BRIDGES); return CIR_INVALID_ID; } for (int i = 0; i < numinfo; i++) { BridgeSpec *bridge = &_bridge[brid + i]; switch (prop) { case 0x08: { // Year of availability /* We treat '0' as always available */ byte year = buf->ReadByte(); bridge->avail_year = (year > 0 ? ORIGINAL_BASE_YEAR + year : 0); break; } case 0x09: // Minimum length bridge->min_length = buf->ReadByte(); break; case 0x0A: // Maximum length bridge->max_length = buf->ReadByte(); if (bridge->max_length > 16) bridge->max_length = 0xFFFF; break; case 0x0B: // Cost factor bridge->price = buf->ReadByte(); break; case 0x0C: // Maximum speed bridge->speed = buf->ReadWord(); break; case 0x0D: { // Bridge sprite tables byte tableid = buf->ReadByte(); byte numtables = buf->ReadByte(); if (bridge->sprite_table == NULL) { /* Allocate memory for sprite table pointers and zero out */ bridge->sprite_table = CallocT(7); } for (; numtables-- != 0; tableid++) { if (tableid >= 7) { // skip invalid data grfmsg(1, "BridgeChangeInfo: Table %d >= 7, skipping", tableid); for (byte sprite = 0; sprite < 32; sprite++) buf->ReadDWord(); continue; } if (bridge->sprite_table[tableid] == NULL) { bridge->sprite_table[tableid] = MallocT(32); } for (byte sprite = 0; sprite < 32; sprite++) { SpriteID image = buf->ReadWord(); PaletteID pal = buf->ReadWord(); bridge->sprite_table[tableid][sprite].sprite = image; bridge->sprite_table[tableid][sprite].pal = pal; MapSpriteMappingRecolour(&bridge->sprite_table[tableid][sprite]); } } break; } case 0x0E: // Flags; bit 0 - disable far pillars bridge->flags = buf->ReadByte(); break; case 0x0F: // Long format year of availability (year since year 0) bridge->avail_year = Clamp(buf->ReadDWord(), MIN_YEAR, MAX_YEAR); break; case 0x10: { // purchase string StringID newone = GetGRFStringID(_cur.grffile->grfid, buf->ReadWord()); if (newone != STR_UNDEFINED) bridge->material = newone; break; } case 0x11: // description of bridge with rails or roads case 0x12: { StringID newone = GetGRFStringID(_cur.grffile->grfid, buf->ReadWord()); if (newone != STR_UNDEFINED) bridge->transport_name[prop - 0x11] = newone; break; } case 0x13: // 16 bits cost multiplier bridge->price = buf->ReadWord(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Ignore a house property * @param prop Property to read. * @param buf Property value. * @return ChangeInfoResult. */ static ChangeInfoResult IgnoreTownHouseProperty(int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; switch (prop) { case 0x09: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x11: case 0x14: case 0x15: case 0x16: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1F: buf->ReadByte(); break; case 0x0A: case 0x10: case 0x12: case 0x13: case 0x21: case 0x22: buf->ReadWord(); break; case 0x1E: buf->ReadDWord(); break; case 0x17: for (uint j = 0; j < 4; j++) buf->ReadByte(); break; case 0x20: { byte count = buf->ReadByte(); for (byte j = 0; j < count; j++) buf->ReadByte(); break; } default: ret = CIR_UNKNOWN; break; } return ret; } /** * Define properties for houses * @param hid HouseID of the house. * @param numinfo Number of subsequent houseIDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult TownHouseChangeInfo(uint hid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (hid + numinfo > NUM_HOUSES_PER_GRF) { grfmsg(1, "TownHouseChangeInfo: Too many houses loaded (%u), max (%u). Ignoring.", hid + numinfo, NUM_HOUSES_PER_GRF); return CIR_INVALID_ID; } /* Allocate house specs if they haven't been allocated already. */ if (_cur.grffile->housespec == NULL) { _cur.grffile->housespec = CallocT(NUM_HOUSES_PER_GRF); } for (int i = 0; i < numinfo; i++) { HouseSpec *housespec = _cur.grffile->housespec[hid + i]; if (prop != 0x08 && housespec == NULL) { /* If the house property 08 is not yet set, ignore this property */ ChangeInfoResult cir = IgnoreTownHouseProperty(prop, buf); if (cir > ret) ret = cir; continue; } switch (prop) { case 0x08: { // Substitute building type, and definition of a new house HouseSpec **house = &_cur.grffile->housespec[hid + i]; byte subs_id = buf->ReadByte(); if (subs_id == 0xFF) { /* Instead of defining a new house, a substitute house id * of 0xFF disables the old house with the current id. */ HouseSpec::Get(hid + i)->enabled = false; continue; } else if (subs_id >= NEW_HOUSE_OFFSET) { /* The substitute id must be one of the original houses. */ grfmsg(2, "TownHouseChangeInfo: Attempt to use new house %u as substitute house for %u. Ignoring.", subs_id, hid + i); continue; } /* Allocate space for this house. */ if (*house == NULL) *house = CallocT(1); housespec = *house; MemCpyT(housespec, HouseSpec::Get(subs_id)); housespec->enabled = true; housespec->grf_prop.local_id = hid + i; housespec->grf_prop.subst_id = subs_id; housespec->grf_prop.grffile = _cur.grffile; housespec->random_colour[0] = 0x04; // those 4 random colours are the base colour housespec->random_colour[1] = 0x08; // for all new houses housespec->random_colour[2] = 0x0C; // they stand for red, blue, orange and green housespec->random_colour[3] = 0x06; /* Make sure that the third cargo type is valid in this * climate. This can cause problems when copying the properties * of a house that accepts food, where the new house is valid * in the temperate climate. */ if (!CargoSpec::Get(housespec->accepts_cargo[2])->IsValid()) { housespec->cargo_acceptance[2] = 0; } _loaded_newgrf_features.has_newhouses = true; break; } case 0x09: // Building flags housespec->building_flags = (BuildingFlags)buf->ReadByte(); break; case 0x0A: { // Availability years uint16 years = buf->ReadWord(); housespec->min_year = GB(years, 0, 8) > 150 ? MAX_YEAR : ORIGINAL_BASE_YEAR + GB(years, 0, 8); housespec->max_year = GB(years, 8, 8) > 150 ? MAX_YEAR : ORIGINAL_BASE_YEAR + GB(years, 8, 8); break; } case 0x0B: // Population housespec->population = buf->ReadByte(); break; case 0x0C: // Mail generation multiplier housespec->mail_generation = buf->ReadByte(); break; case 0x0D: // Passenger acceptance case 0x0E: // Mail acceptance housespec->cargo_acceptance[prop - 0x0D] = buf->ReadByte(); break; case 0x0F: { // Goods/candy, food/fizzy drinks acceptance int8 goods = buf->ReadByte(); /* If value of goods is negative, it means in fact food or, if in toyland, fizzy_drink acceptance. * Else, we have "standard" 3rd cargo type, goods or candy, for toyland once more */ CargoID cid = (goods >= 0) ? ((_settings_game.game_creation.landscape == LT_TOYLAND) ? CT_CANDY : CT_GOODS) : ((_settings_game.game_creation.landscape == LT_TOYLAND) ? CT_FIZZY_DRINKS : CT_FOOD); /* Make sure the cargo type is valid in this climate. */ if (!CargoSpec::Get(cid)->IsValid()) goods = 0; housespec->accepts_cargo[2] = cid; housespec->cargo_acceptance[2] = abs(goods); // but we do need positive value here break; } case 0x10: // Local authority rating decrease on removal housespec->remove_rating_decrease = buf->ReadWord(); break; case 0x11: // Removal cost multiplier housespec->removal_cost = buf->ReadByte(); break; case 0x12: // Building name ID AddStringForMapping(buf->ReadWord(), &housespec->building_name); break; case 0x13: // Building availability mask housespec->building_availability = (HouseZones)buf->ReadWord(); break; case 0x14: // House callback mask housespec->callback_mask |= buf->ReadByte(); break; case 0x15: { // House override byte byte override = buf->ReadByte(); /* The house being overridden must be an original house. */ if (override >= NEW_HOUSE_OFFSET) { grfmsg(2, "TownHouseChangeInfo: Attempt to override new house %u with house id %u. Ignoring.", override, hid + i); continue; } _house_mngr.Add(hid + i, _cur.grffile->grfid, override); break; } case 0x16: // Periodic refresh multiplier housespec->processing_time = min(buf->ReadByte(), 63); break; case 0x17: // Four random colours to use for (uint j = 0; j < 4; j++) housespec->random_colour[j] = buf->ReadByte(); break; case 0x18: // Relative probability of appearing housespec->probability = buf->ReadByte(); break; case 0x19: // Extra flags housespec->extra_flags = (HouseExtraFlags)buf->ReadByte(); break; case 0x1A: // Animation frames housespec->animation.frames = buf->ReadByte(); housespec->animation.status = GB(housespec->animation.frames, 7, 1); SB(housespec->animation.frames, 7, 1, 0); break; case 0x1B: // Animation speed housespec->animation.speed = Clamp(buf->ReadByte(), 2, 16); break; case 0x1C: // Class of the building type housespec->class_id = AllocateHouseClassID(buf->ReadByte(), _cur.grffile->grfid); break; case 0x1D: // Callback mask part 2 housespec->callback_mask |= (buf->ReadByte() << 8); break; case 0x1E: { // Accepted cargo types uint32 cargotypes = buf->ReadDWord(); /* Check if the cargo types should not be changed */ if (cargotypes == 0xFFFFFFFF) break; for (uint j = 0; j < 3; j++) { /* Get the cargo number from the 'list' */ uint8 cargo_part = GB(cargotypes, 8 * j, 8); CargoID cargo = GetCargoTranslation(cargo_part, _cur.grffile); if (cargo == CT_INVALID) { /* Disable acceptance of invalid cargo type */ housespec->cargo_acceptance[j] = 0; } else { housespec->accepts_cargo[j] = cargo; } } break; } case 0x1F: // Minimum life span housespec->minimum_life = buf->ReadByte(); break; case 0x20: { // Cargo acceptance watch list byte count = buf->ReadByte(); for (byte j = 0; j < count; j++) { CargoID cargo = GetCargoTranslation(buf->ReadByte(), _cur.grffile); if (cargo != CT_INVALID) SetBit(housespec->watched_cargoes, cargo); } break; } case 0x21: // long introduction year housespec->min_year = buf->ReadWord(); break; case 0x22: // long maximum year housespec->max_year = buf->ReadWord(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Get the language map associated with a given NewGRF and language. * @param grfid The NewGRF to get the map for. * @param language_id The (NewGRF) language ID to get the map for. * @return The LanguageMap, or NULL if it couldn't be found. */ /* static */ const LanguageMap *LanguageMap::GetLanguageMap(uint32 grfid, uint8 language_id) { /* LanguageID "MAX_LANG", i.e. 7F is any. This language can't have a gender/case mapping, but has to be handled gracefully. */ const GRFFile *grffile = GetFileByGRFID(grfid); return (grffile != NULL && grffile->language_map != NULL && language_id < MAX_LANG) ? &grffile->language_map[language_id] : NULL; } /** * Load a cargo- or railtype-translation table. * @param gvid ID of the global variable. This is basically only checked for zerones. * @param numinfo Number of subsequent IDs to change the property for. * @param buf The property value. * @param [in,out] translation_table Storage location for the translation table. * @param name Name of the table for debug output. * @return ChangeInfoResult. */ template static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader *buf, T &translation_table, const char *name) { if (gvid != 0) { grfmsg(1, "LoadTranslationTable: %s translation table must start at zero", name); return CIR_INVALID_ID; } translation_table.Clear(); for (int i = 0; i < numinfo; i++) { uint32 item = buf->ReadDWord(); *translation_table.Append() = BSWAP32(item); } return CIR_SUCCESS; } /** * Define properties for global variables * @param gvid ID of the global variable. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, ByteReader *buf) { /* Properties which are handled as a whole */ switch (prop) { case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->cargo_list, "Cargo"); case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); default: break; } /* Properties which are handled per item */ ChangeInfoResult ret = CIR_SUCCESS; for (int i = 0; i < numinfo; i++) { switch (prop) { case 0x08: { // Cost base factor int factor = buf->ReadByte(); uint price = gvid + i; if (price < PR_END) { _cur.grffile->price_base_multipliers[price] = min(factor - 8, MAX_PRICE_MODIFIER); } else { grfmsg(1, "GlobalVarChangeInfo: Price %d out of range, ignoring", price); } break; } case 0x0A: { // Currency display names uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); StringID newone = GetGRFStringID(_cur.grffile->grfid, buf->ReadWord()); if ((newone != STR_UNDEFINED) && (curidx < CURRENCY_END)) { _currency_specs[curidx].name = newone; } break; } case 0x0B: { // Currency multipliers uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); uint32 rate = buf->ReadDWord(); if (curidx < CURRENCY_END) { /* TTDPatch uses a multiple of 1000 for its conversion calculations, * which OTTD does not. For this reason, divide grf value by 1000, * to be compatible */ _currency_specs[curidx].rate = rate / 1000; } else { grfmsg(1, "GlobalVarChangeInfo: Currency multipliers %d out of range, ignoring", curidx); } break; } case 0x0C: { // Currency options uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); uint16 options = buf->ReadWord(); if (curidx < CURRENCY_END) { _currency_specs[curidx].separator[0] = GB(options, 0, 8); _currency_specs[curidx].separator[1] = '\0'; /* By specifying only one bit, we prevent errors, * since newgrf specs said that only 0 and 1 can be set for symbol_pos */ _currency_specs[curidx].symbol_pos = GB(options, 8, 1); } else { grfmsg(1, "GlobalVarChangeInfo: Currency option %d out of range, ignoring", curidx); } break; } case 0x0D: { // Currency prefix symbol uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); uint32 tempfix = buf->ReadDWord(); if (curidx < CURRENCY_END) { memcpy(_currency_specs[curidx].prefix, &tempfix, 4); _currency_specs[curidx].prefix[4] = 0; } else { grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx); } break; } case 0x0E: { // Currency suffix symbol uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); uint32 tempfix = buf->ReadDWord(); if (curidx < CURRENCY_END) { memcpy(&_currency_specs[curidx].suffix, &tempfix, 4); _currency_specs[curidx].suffix[4] = 0; } else { grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx); } break; } case 0x0F: { // Euro introduction dates uint curidx = GetNewgrfCurrencyIdConverted(gvid + i); Year year_euro = buf->ReadWord(); if (curidx < CURRENCY_END) { _currency_specs[curidx].to_euro = year_euro; } else { grfmsg(1, "GlobalVarChangeInfo: Euro intro date %d out of range, ignoring", curidx); } break; } case 0x10: // Snow line height table if (numinfo > 1 || IsSnowLineSet()) { grfmsg(1, "GlobalVarChangeInfo: The snowline can only be set once (%d)", numinfo); } else if (buf->Remaining() < SNOW_LINE_MONTHS * SNOW_LINE_DAYS) { grfmsg(1, "GlobalVarChangeInfo: Not enough entries set in the snowline table (" PRINTF_SIZE ")", buf->Remaining()); } else { byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS]; for (uint i = 0; i < SNOW_LINE_MONTHS; i++) { for (uint j = 0; j < SNOW_LINE_DAYS; j++) { table[i][j] = buf->ReadByte(); if (_cur.grffile->grf_version >= 8) { if (table[i][j] != 0xFF) table[i][j] = table[i][j] * (1 + _settings_game.construction.max_heightlevel) / 256; } else { if (table[i][j] >= 128) { /* no snow */ table[i][j] = 0xFF; } else { table[i][j] = table[i][j] * (1 + _settings_game.construction.max_heightlevel) / 128; } } } } SetSnowLine(table); } break; case 0x11: // GRF match for engine allocation /* This is loaded during the reservation stage, so just skip it here. */ /* Each entry is 8 bytes. */ buf->Skip(8); break; case 0x13: // Gender translation table case 0x14: // Case translation table case 0x15: { // Plural form translation uint curidx = gvid + i; // The current index, i.e. language. const LanguageMetadata *lang = curidx < MAX_LANG ? GetLanguage(curidx) : NULL; if (lang == NULL) { grfmsg(1, "GlobalVarChangeInfo: Language %d is not known, ignoring", curidx); /* Skip over the data. */ if (prop == 0x15) { buf->ReadByte(); } else { while (buf->ReadByte() != 0) { buf->ReadString(); } } break; } if (_cur.grffile->language_map == NULL) _cur.grffile->language_map = new LanguageMap[MAX_LANG]; if (prop == 0x15) { uint plural_form = buf->ReadByte(); if (plural_form >= LANGUAGE_MAX_PLURAL) { grfmsg(1, "GlobalVarChanceInfo: Plural form %d is out of range, ignoring", plural_form); } else { _cur.grffile->language_map[curidx].plural_form = plural_form; } break; } byte newgrf_id = buf->ReadByte(); // The NewGRF (custom) identifier. while (newgrf_id != 0) { const char *name = buf->ReadString(); // The name for the OpenTTD identifier. /* We'll just ignore the UTF8 identifier character. This is (fairly) * safe as OpenTTD's strings gender/cases are usually in ASCII which * is just a subset of UTF8, or they need the bigger UTF8 characters * such as Cyrillic. Thus we will simply assume they're all UTF8. */ WChar c; size_t len = Utf8Decode(&c, name); if (c == NFO_UTF8_IDENTIFIER) name += len; LanguageMap::Mapping map; map.newgrf_id = newgrf_id; if (prop == 0x13) { map.openttd_id = lang->GetGenderIndex(name); if (map.openttd_id >= MAX_NUM_GENDERS) { grfmsg(1, "GlobalVarChangeInfo: Gender name %s is not known, ignoring", name); } else { *_cur.grffile->language_map[curidx].gender_map.Append() = map; } } else { map.openttd_id = lang->GetCaseIndex(name); if (map.openttd_id >= MAX_NUM_CASES) { grfmsg(1, "GlobalVarChangeInfo: Case name %s is not known, ignoring", name); } else { *_cur.grffile->language_map[curidx].case_map.Append() = map; } } newgrf_id = buf->ReadByte(); } break; } default: ret = CIR_UNKNOWN; break; } } return ret; } static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, ByteReader *buf) { /* Properties which are handled as a whole */ switch (prop) { case 0x09: // Cargo Translation Table; loading during both reservation and activation stage (in case it is selected depending on defined cargos) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->cargo_list, "Cargo"); case 0x12: // Rail type translation table; loading during both reservation and activation stage (in case it is selected depending on defined railtypes) return LoadTranslationTable(gvid, numinfo, buf, _cur.grffile->railtype_list, "Rail type"); default: break; } /* Properties which are handled per item */ ChangeInfoResult ret = CIR_SUCCESS; for (int i = 0; i < numinfo; i++) { switch (prop) { case 0x08: // Cost base factor case 0x15: // Plural form translation buf->ReadByte(); break; case 0x0A: // Currency display names case 0x0C: // Currency options case 0x0F: // Euro introduction dates buf->ReadWord(); break; case 0x0B: // Currency multipliers case 0x0D: // Currency prefix symbol case 0x0E: // Currency suffix symbol buf->ReadDWord(); break; case 0x10: // Snow line height table buf->Skip(SNOW_LINE_MONTHS * SNOW_LINE_DAYS); break; case 0x11: { // GRF match for engine allocation uint32 s = buf->ReadDWord(); uint32 t = buf->ReadDWord(); SetNewGRFOverride(s, t); break; } case 0x13: // Gender translation table case 0x14: // Case translation table while (buf->ReadByte() != 0) { buf->ReadString(); } break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Define properties for cargoes * @param cid Local ID of the cargo. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult CargoChangeInfo(uint cid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (cid + numinfo > NUM_CARGO) { grfmsg(2, "CargoChangeInfo: Cargo type %d out of range (max %d)", cid + numinfo, NUM_CARGO - 1); return CIR_INVALID_ID; } for (int i = 0; i < numinfo; i++) { CargoSpec *cs = CargoSpec::Get(cid + i); switch (prop) { case 0x08: // Bit number of cargo cs->bitnum = buf->ReadByte(); if (cs->IsValid()) { cs->grffile = _cur.grffile; SetBit(_cargo_mask, cid + i); } else { ClrBit(_cargo_mask, cid + i); } break; case 0x09: // String ID for cargo type name AddStringForMapping(buf->ReadWord(), &cs->name); break; case 0x0A: // String for 1 unit of cargo AddStringForMapping(buf->ReadWord(), &cs->name_single); break; case 0x0B: // String for singular quantity of cargo (e.g. 1 tonne of coal) case 0x1B: // String for cargo units /* String for units of cargo. This is different in OpenTTD * (e.g. tonnes) to TTDPatch (e.g. {COMMA} tonne of coal). * Property 1B is used to set OpenTTD's behaviour. */ AddStringForMapping(buf->ReadWord(), &cs->units_volume); break; case 0x0C: // String for plural quantity of cargo (e.g. 10 tonnes of coal) case 0x1C: // String for any amount of cargo /* Strings for an amount of cargo. This is different in OpenTTD * (e.g. {WEIGHT} of coal) to TTDPatch (e.g. {COMMA} tonnes of coal). * Property 1C is used to set OpenTTD's behaviour. */ AddStringForMapping(buf->ReadWord(), &cs->quantifier); break; case 0x0D: // String for two letter cargo abbreviation AddStringForMapping(buf->ReadWord(), &cs->abbrev); break; case 0x0E: // Sprite ID for cargo icon cs->sprite = buf->ReadWord(); break; case 0x0F: // Weight of one unit of cargo cs->weight = buf->ReadByte(); break; case 0x10: // Used for payment calculation cs->transit_days[0] = buf->ReadByte(); break; case 0x11: // Used for payment calculation cs->transit_days[1] = buf->ReadByte(); break; case 0x12: // Base cargo price cs->initial_payment = buf->ReadDWord(); break; case 0x13: // Colour for station rating bars cs->rating_colour = buf->ReadByte(); break; case 0x14: // Colour for cargo graph cs->legend_colour = buf->ReadByte(); break; case 0x15: // Freight status cs->is_freight = (buf->ReadByte() != 0); break; case 0x16: // Cargo classes cs->classes = buf->ReadWord(); break; case 0x17: // Cargo label cs->label = buf->ReadDWord(); cs->label = BSWAP32(cs->label); break; case 0x18: { // Town growth substitute type uint8 substitute_type = buf->ReadByte(); switch (substitute_type) { case 0x00: cs->town_effect = TE_PASSENGERS; break; case 0x02: cs->town_effect = TE_MAIL; break; case 0x05: cs->town_effect = TE_GOODS; break; case 0x09: cs->town_effect = TE_WATER; break; case 0x0B: cs->town_effect = TE_FOOD; break; default: grfmsg(1, "CargoChangeInfo: Unknown town growth substitute value %d, setting to none.", substitute_type); /* FALL THROUGH */ case 0xFF: cs->town_effect = TE_NONE; break; } break; } case 0x19: // Town growth coefficient cs->multipliertowngrowth = buf->ReadWord(); break; case 0x1A: // Bitmask of callbacks to use cs->callback_mask = buf->ReadByte(); break; case 0x1D: // Vehicle capacity muliplier cs->multiplier = max(1u, buf->ReadWord()); break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Define properties for sound effects * @param sid Local ID of the sound. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult SoundEffectChangeInfo(uint sid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (_cur.grffile->sound_offset == 0) { grfmsg(1, "SoundEffectChangeInfo: No effects defined, skipping"); return CIR_INVALID_ID; } if (sid + numinfo - ORIGINAL_SAMPLE_COUNT > _cur.grffile->num_sounds) { grfmsg(1, "SoundEffectChangeInfo: Attemting to change undefined sound effect (%u), max (%u). Ignoring.", sid + numinfo, ORIGINAL_SAMPLE_COUNT + _cur.grffile->num_sounds); return CIR_INVALID_ID; } for (int i = 0; i < numinfo; i++) { SoundEntry *sound = GetSound(sid + i + _cur.grffile->sound_offset - ORIGINAL_SAMPLE_COUNT); switch (prop) { case 0x08: // Relative volume sound->volume = buf->ReadByte(); break; case 0x09: // Priority sound->priority = buf->ReadByte(); break; case 0x0A: { // Override old sound SoundID orig_sound = buf->ReadByte(); if (orig_sound >= ORIGINAL_SAMPLE_COUNT) { grfmsg(1, "SoundEffectChangeInfo: Original sound %d not defined (max %d)", orig_sound, ORIGINAL_SAMPLE_COUNT); } else { SoundEntry *old_sound = GetSound(orig_sound); /* Literally copy the data of the new sound over the original */ *old_sound = *sound; } break; } default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Ignore an industry tile property * @param prop The property to ignore. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult IgnoreIndustryTileProperty(int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; switch (prop) { case 0x09: case 0x0D: case 0x0E: case 0x10: case 0x11: case 0x12: buf->ReadByte(); break; case 0x0A: case 0x0B: case 0x0C: case 0x0F: buf->ReadWord(); break; default: ret = CIR_UNKNOWN; break; } return ret; } /** * Define properties for industry tiles * @param indtid Local ID of the industry tile. * @param numinfo Number of subsequent industry tile IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (indtid + numinfo > NUM_INDUSTRYTILES_PER_GRF) { grfmsg(1, "IndustryTilesChangeInfo: Too many industry tiles loaded (%u), max (%u). Ignoring.", indtid + numinfo, NUM_INDUSTRYTILES_PER_GRF); return CIR_INVALID_ID; } /* Allocate industry tile specs if they haven't been allocated already. */ if (_cur.grffile->indtspec == NULL) { _cur.grffile->indtspec = CallocT(NUM_INDUSTRYTILES_PER_GRF); } for (int i = 0; i < numinfo; i++) { IndustryTileSpec *tsp = _cur.grffile->indtspec[indtid + i]; if (prop != 0x08 && tsp == NULL) { ChangeInfoResult cir = IgnoreIndustryTileProperty(prop, buf); if (cir > ret) ret = cir; continue; } switch (prop) { case 0x08: { // Substitute industry tile type IndustryTileSpec **tilespec = &_cur.grffile->indtspec[indtid + i]; byte subs_id = buf->ReadByte(); if (subs_id >= NEW_INDUSTRYTILEOFFSET) { /* The substitute id must be one of the original industry tile. */ grfmsg(2, "IndustryTilesChangeInfo: Attempt to use new industry tile %u as substitute industry tile for %u. Ignoring.", subs_id, indtid + i); continue; } /* Allocate space for this industry. */ if (*tilespec == NULL) { *tilespec = CallocT(1); tsp = *tilespec; memcpy(tsp, &_industry_tile_specs[subs_id], sizeof(_industry_tile_specs[subs_id])); tsp->enabled = true; /* A copied tile should not have the animation infos copied too. * The anim_state should be left untouched, though * It is up to the author to animate them himself */ tsp->anim_production = INDUSTRYTILE_NOANIM; tsp->anim_next = INDUSTRYTILE_NOANIM; tsp->grf_prop.local_id = indtid + i; tsp->grf_prop.subst_id = subs_id; tsp->grf_prop.grffile = _cur.grffile; _industile_mngr.AddEntityID(indtid + i, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot } break; } case 0x09: { // Industry tile override byte ovrid = buf->ReadByte(); /* The industry being overridden must be an original industry. */ if (ovrid >= NEW_INDUSTRYTILEOFFSET) { grfmsg(2, "IndustryTilesChangeInfo: Attempt to override new industry tile %u with industry tile id %u. Ignoring.", ovrid, indtid + i); continue; } _industile_mngr.Add(indtid + i, _cur.grffile->grfid, ovrid); break; } case 0x0A: // Tile acceptance case 0x0B: case 0x0C: { uint16 acctp = buf->ReadWord(); tsp->accepts_cargo[prop - 0x0A] = GetCargoTranslation(GB(acctp, 0, 8), _cur.grffile); tsp->acceptance[prop - 0x0A] = GB(acctp, 8, 8); break; } case 0x0D: // Land shape flags tsp->slopes_refused = (Slope)buf->ReadByte(); break; case 0x0E: // Callback mask tsp->callback_mask = buf->ReadByte(); break; case 0x0F: // Animation information tsp->animation.frames = buf->ReadByte(); tsp->animation.status = buf->ReadByte(); break; case 0x10: // Animation speed tsp->animation.speed = buf->ReadByte(); break; case 0x11: // Triggers for callback 25 tsp->animation.triggers = buf->ReadByte(); break; case 0x12: // Special flags tsp->special_flags = (IndustryTileSpecialFlags)buf->ReadByte(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Ignore an industry property * @param prop The property to ignore. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult IgnoreIndustryProperty(int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; switch (prop) { case 0x09: case 0x0B: case 0x0F: case 0x12: case 0x13: case 0x14: case 0x17: case 0x18: case 0x19: case 0x21: case 0x22: buf->ReadByte(); break; case 0x0C: case 0x0D: case 0x0E: case 0x10: case 0x1B: case 0x1F: case 0x24: buf->ReadWord(); break; case 0x11: case 0x1A: case 0x1C: case 0x1D: case 0x1E: case 0x20: case 0x23: buf->ReadDWord(); break; case 0x0A: { byte num_table = buf->ReadByte(); for (byte j = 0; j < num_table; j++) { for (uint k = 0;; k++) { byte x = buf->ReadByte(); if (x == 0xFE && k == 0) { buf->ReadByte(); buf->ReadByte(); break; } byte y = buf->ReadByte(); if (x == 0 && y == 0x80) break; byte gfx = buf->ReadByte(); if (gfx == 0xFE) buf->ReadWord(); } } break; } case 0x16: for (byte j = 0; j < 3; j++) buf->ReadByte(); break; case 0x15: { byte number_of_sounds = buf->ReadByte(); for (uint8 j = 0; j < number_of_sounds; j++) { buf->ReadByte(); } break; } default: ret = CIR_UNKNOWN; break; } return ret; } /** * Validate the industry layout; e.g. to prevent duplicate tiles. * @param layout The layout to check. * @param size The size of the layout. * @return True if the layout is deemed valid. */ static bool ValidateIndustryLayout(const IndustryTileTable *layout, int size) { for (int i = 0; i < size - 1; i++) { for (int j = i + 1; j < size; j++) { if (layout[i].ti.x == layout[j].ti.x && layout[i].ti.y == layout[j].ti.y) { return false; } } } return true; } /** Clean the tile table of the IndustrySpec if it's needed. */ static void CleanIndustryTileTable(IndustrySpec *ind) { if (HasBit(ind->cleanup_flag, CLEAN_TILELAYOUT) && ind->table != NULL) { for (int j = 0; j < ind->num_table; j++) { /* remove the individual layouts */ free(ind->table[j]); } /* remove the layouts pointers */ free(ind->table); ind->table = NULL; } } /** * Define properties for industries * @param indid Local ID of the industry. * @param numinfo Number of subsequent industry IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult IndustriesChangeInfo(uint indid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (indid + numinfo > NUM_INDUSTRYTYPES_PER_GRF) { grfmsg(1, "IndustriesChangeInfo: Too many industries loaded (%u), max (%u). Ignoring.", indid + numinfo, NUM_INDUSTRYTYPES_PER_GRF); return CIR_INVALID_ID; } /* Allocate industry specs if they haven't been allocated already. */ if (_cur.grffile->industryspec == NULL) { _cur.grffile->industryspec = CallocT(NUM_INDUSTRYTYPES_PER_GRF); } for (int i = 0; i < numinfo; i++) { IndustrySpec *indsp = _cur.grffile->industryspec[indid + i]; if (prop != 0x08 && indsp == NULL) { ChangeInfoResult cir = IgnoreIndustryProperty(prop, buf); if (cir > ret) ret = cir; continue; } switch (prop) { case 0x08: { // Substitute industry type IndustrySpec **indspec = &_cur.grffile->industryspec[indid + i]; byte subs_id = buf->ReadByte(); if (subs_id == 0xFF) { /* Instead of defining a new industry, a substitute industry id * of 0xFF disables the old industry with the current id. */ _industry_specs[indid + i].enabled = false; continue; } else if (subs_id >= NEW_INDUSTRYOFFSET) { /* The substitute id must be one of the original industry. */ grfmsg(2, "_industry_specs: Attempt to use new industry %u as substitute industry for %u. Ignoring.", subs_id, indid + i); continue; } /* Allocate space for this industry. * Only need to do it once. If ever it is called again, it should not * do anything */ if (*indspec == NULL) { *indspec = CallocT(1); indsp = *indspec; memcpy(indsp, &_origin_industry_specs[subs_id], sizeof(_industry_specs[subs_id])); indsp->enabled = true; indsp->grf_prop.local_id = indid + i; indsp->grf_prop.subst_id = subs_id; indsp->grf_prop.grffile = _cur.grffile; /* If the grf industry needs to check its surounding upon creation, it should * rely on callbacks, not on the original placement functions */ indsp->check_proc = CHECK_NOTHING; } break; } case 0x09: { // Industry type override byte ovrid = buf->ReadByte(); /* The industry being overridden must be an original industry. */ if (ovrid >= NEW_INDUSTRYOFFSET) { grfmsg(2, "IndustriesChangeInfo: Attempt to override new industry %u with industry id %u. Ignoring.", ovrid, indid + i); continue; } indsp->grf_prop.override = ovrid; _industry_mngr.Add(indid + i, _cur.grffile->grfid, ovrid); break; } case 0x0A: { // Set industry layout(s) byte new_num_layouts = buf->ReadByte(); // Number of layaouts /* We read the total size in bytes, but we can't rely on the * newgrf to provide a sane value. First assume the value is * sane but later on we make sure we enlarge the array if the * newgrf contains more data. Each tile uses either 3 or 5 * bytes, so to play it safe we assume 3. */ uint32 def_num_tiles = buf->ReadDWord() / 3 + 1; IndustryTileTable **tile_table = CallocT(new_num_layouts); // Table with tiles to compose an industry IndustryTileTable *itt = CallocT(def_num_tiles); // Temporary array to read the tile layouts from the GRF uint size; const IndustryTileTable *copy_from; try { for (byte j = 0; j < new_num_layouts; j++) { for (uint k = 0;; k++) { if (k >= def_num_tiles) { grfmsg(3, "IndustriesChangeInfo: Incorrect size for industry tile layout definition for industry %u.", indid); /* Size reported by newgrf was not big enough so enlarge the array. */ def_num_tiles *= 2; itt = ReallocT(itt, def_num_tiles); } itt[k].ti.x = buf->ReadByte(); // Offsets from northermost tile if (itt[k].ti.x == 0xFE && k == 0) { /* This means we have to borrow the layout from an old industry */ IndustryType type = buf->ReadByte(); // industry holding required layout byte laynbr = buf->ReadByte(); // layout number to borrow copy_from = _origin_industry_specs[type].table[laynbr]; for (size = 1;; size++) { if (copy_from[size - 1].ti.x == -0x80 && copy_from[size - 1].ti.y == 0) break; } break; } itt[k].ti.y = buf->ReadByte(); // Or table definition finalisation if (itt[k].ti.x == 0 && itt[k].ti.y == 0x80) { /* Not the same terminator. The one we are using is rather x = -80, y = x . So, adjust it. */ itt[k].ti.x = -0x80; itt[k].ti.y = 0; itt[k].gfx = 0; size = k + 1; copy_from = itt; break; } itt[k].gfx = buf->ReadByte(); if (itt[k].gfx == 0xFE) { /* Use a new tile from this GRF */ int local_tile_id = buf->ReadWord(); /* Read the ID from the _industile_mngr. */ int tempid = _industile_mngr.GetID(local_tile_id, _cur.grffile->grfid); if (tempid == INVALID_INDUSTRYTILE) { grfmsg(2, "IndustriesChangeInfo: Attempt to use industry tile %u with industry id %u, not yet defined. Ignoring.", local_tile_id, indid); } else { /* Declared as been valid, can be used */ itt[k].gfx = tempid; size = k + 1; copy_from = itt; } } else if (itt[k].gfx == 0xFF) { itt[k].ti.x = (int8)GB(itt[k].ti.x, 0, 8); itt[k].ti.y = (int8)GB(itt[k].ti.y, 0, 8); /* When there were only 256x256 maps, TileIndex was a uint16 and * itt[k].ti was just a TileIndexDiff that was added to it. * As such negative "x" values were shifted into the "y" position. * x = -1, y = 1 -> x = 255, y = 0 * Since GRF version 8 the position is interpreted as pair of independent int8. * For GRF version < 8 we need to emulate the old shifting behaviour. */ if (_cur.grffile->grf_version < 8 && itt[k].ti.x < 0) itt[k].ti.y += 1; } } if (!ValidateIndustryLayout(copy_from, size)) { /* The industry layout was not valid, so skip this one. */ grfmsg(1, "IndustriesChangeInfo: Invalid industry layout for industry id %u. Ignoring", indid); new_num_layouts--; j--; } else { tile_table[j] = CallocT(size); memcpy(tile_table[j], copy_from, sizeof(*copy_from) * size); } } } catch (...) { for (int i = 0; i < new_num_layouts; i++) { free(tile_table[i]); } free(tile_table); free(itt); throw; } /* Clean the tile table if it was already set by a previous prop A. */ CleanIndustryTileTable(indsp); /* Install final layout construction in the industry spec */ indsp->num_table = new_num_layouts; indsp->table = tile_table; SetBit(indsp->cleanup_flag, CLEAN_TILELAYOUT); free(itt); break; } case 0x0B: // Industry production flags indsp->life_type = (IndustryLifeType)buf->ReadByte(); break; case 0x0C: // Industry closure message AddStringForMapping(buf->ReadWord(), &indsp->closure_text); break; case 0x0D: // Production increase message AddStringForMapping(buf->ReadWord(), &indsp->production_up_text); break; case 0x0E: // Production decrease message AddStringForMapping(buf->ReadWord(), &indsp->production_down_text); break; case 0x0F: // Fund cost multiplier indsp->cost_multiplier = buf->ReadByte(); break; case 0x10: // Production cargo types for (byte j = 0; j < 2; j++) { indsp->produced_cargo[j] = GetCargoTranslation(buf->ReadByte(), _cur.grffile); } break; case 0x11: // Acceptance cargo types for (byte j = 0; j < 3; j++) { indsp->accepts_cargo[j] = GetCargoTranslation(buf->ReadByte(), _cur.grffile); } buf->ReadByte(); // Unnused, eat it up break; case 0x12: // Production multipliers case 0x13: indsp->production_rate[prop - 0x12] = buf->ReadByte(); break; case 0x14: // Minimal amount of cargo distributed indsp->minimal_cargo = buf->ReadByte(); break; case 0x15: { // Random sound effects indsp->number_of_sounds = buf->ReadByte(); uint8 *sounds = MallocT(indsp->number_of_sounds); try { for (uint8 j = 0; j < indsp->number_of_sounds; j++) { sounds[j] = buf->ReadByte(); } } catch (...) { free(sounds); throw; } if (HasBit(indsp->cleanup_flag, CLEAN_RANDOMSOUNDS)) { free(indsp->random_sounds); } indsp->random_sounds = sounds; SetBit(indsp->cleanup_flag, CLEAN_RANDOMSOUNDS); break; } case 0x16: // Conflicting industry types for (byte j = 0; j < 3; j++) indsp->conflicting[j] = buf->ReadByte(); break; case 0x17: // Probability in random game indsp->appear_creation[_settings_game.game_creation.landscape] = buf->ReadByte(); break; case 0x18: // Probability during gameplay indsp->appear_ingame[_settings_game.game_creation.landscape] = buf->ReadByte(); break; case 0x19: // Map colour indsp->map_colour = buf->ReadByte(); break; case 0x1A: // Special industry flags to define special behavior indsp->behaviour = (IndustryBehaviour)buf->ReadDWord(); break; case 0x1B: // New industry text ID AddStringForMapping(buf->ReadWord(), &indsp->new_industry_text); break; case 0x1C: // Input cargo multipliers for the three input cargo types case 0x1D: case 0x1E: { uint32 multiples = buf->ReadDWord(); indsp->input_cargo_multiplier[prop - 0x1C][0] = GB(multiples, 0, 16); indsp->input_cargo_multiplier[prop - 0x1C][1] = GB(multiples, 16, 16); break; } case 0x1F: // Industry name AddStringForMapping(buf->ReadWord(), &indsp->name); break; case 0x20: // Prospecting success chance indsp->prospecting_chance = buf->ReadDWord(); break; case 0x21: // Callback mask case 0x22: { // Callback additional mask byte aflag = buf->ReadByte(); SB(indsp->callback_mask, (prop - 0x21) * 8, 8, aflag); break; } case 0x23: // removal cost multiplier indsp->removal_cost_multiplier = buf->ReadDWord(); break; case 0x24: { // name for nearby station uint16 str = buf->ReadWord(); if (str == 0) { indsp->station_name = STR_NULL; } else { AddStringForMapping(str, &indsp->station_name); } break; } default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Create a copy of the tile table so it can be freed later * without problems. * @param as The AirportSpec to copy the arrays of. */ static void DuplicateTileTable(AirportSpec *as) { AirportTileTable **table_list = MallocT(as->num_table); for (int i = 0; i < as->num_table; i++) { uint num_tiles = 1; const AirportTileTable *it = as->table[0]; do { num_tiles++; } while ((++it)->ti.x != -0x80); table_list[i] = MallocT(num_tiles); MemCpyT(table_list[i], as->table[i], num_tiles); } as->table = table_list; HangarTileTable *depot_table = MallocT(as->nof_depots); MemCpyT(depot_table, as->depot_table, as->nof_depots); as->depot_table = depot_table; } /** * Define properties for airports * @param airport Local ID of the airport. * @param numinfo Number of subsequent airport IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (airport + numinfo > NUM_AIRPORTS_PER_GRF) { grfmsg(1, "AirportChangeInfo: Too many airports, trying id (%u), max (%u). Ignoring.", airport + numinfo, NUM_AIRPORTS_PER_GRF); return CIR_INVALID_ID; } /* Allocate industry specs if they haven't been allocated already. */ if (_cur.grffile->airportspec == NULL) { _cur.grffile->airportspec = CallocT(NUM_AIRPORTS_PER_GRF); } for (int i = 0; i < numinfo; i++) { AirportSpec *as = _cur.grffile->airportspec[airport + i]; if (as == NULL && prop != 0x08 && prop != 0x09) { grfmsg(2, "AirportChangeInfo: Attempt to modify undefined airport %u, ignoring", airport + i); return CIR_INVALID_ID; } switch (prop) { case 0x08: { // Modify original airport byte subs_id = buf->ReadByte(); if (subs_id == 0xFF) { /* Instead of defining a new airport, an airport id * of 0xFF disables the old airport with the current id. */ AirportSpec::GetWithoutOverride(airport + i)->enabled = false; continue; } else if (subs_id >= NEW_AIRPORT_OFFSET) { /* The substitute id must be one of the original airports. */ grfmsg(2, "AirportChangeInfo: Attempt to use new airport %u as substitute airport for %u. Ignoring.", subs_id, airport + i); continue; } AirportSpec **spec = &_cur.grffile->airportspec[airport + i]; /* Allocate space for this airport. * Only need to do it once. If ever it is called again, it should not * do anything */ if (*spec == NULL) { *spec = MallocT(1); as = *spec; memcpy(as, AirportSpec::GetWithoutOverride(subs_id), sizeof(*as)); as->enabled = true; as->grf_prop.local_id = airport + i; as->grf_prop.subst_id = subs_id; as->grf_prop.grffile = _cur.grffile; /* override the default airport */ _airport_mngr.Add(airport + i, _cur.grffile->grfid, subs_id); /* Create a copy of the original tiletable so it can be freed later. */ DuplicateTileTable(as); } break; } case 0x0A: { // Set airport layout as->num_table = buf->ReadByte(); // Number of layaouts as->rotation = MallocT(as->num_table); uint32 defsize = buf->ReadDWord(); // Total size of the definition AirportTileTable **tile_table = CallocT(as->num_table); // Table with tiles to compose the airport AirportTileTable *att = CallocT(defsize); // Temporary array to read the tile layouts from the GRF int size; const AirportTileTable *copy_from; try { for (byte j = 0; j < as->num_table; j++) { as->rotation[j] = (Direction)buf->ReadByte(); for (int k = 0;; k++) { att[k].ti.x = buf->ReadByte(); // Offsets from northermost tile att[k].ti.y = buf->ReadByte(); if (att[k].ti.x == 0 && att[k].ti.y == 0x80) { /* Not the same terminator. The one we are using is rather * x = -80, y = 0 . So, adjust it. */ att[k].ti.x = -0x80; att[k].ti.y = 0; att[k].gfx = 0; size = k + 1; copy_from = att; break; } att[k].gfx = buf->ReadByte(); if (att[k].gfx == 0xFE) { /* Use a new tile from this GRF */ int local_tile_id = buf->ReadWord(); /* Read the ID from the _airporttile_mngr. */ uint16 tempid = _airporttile_mngr.GetID(local_tile_id, _cur.grffile->grfid); if (tempid == INVALID_AIRPORTTILE) { grfmsg(2, "AirportChangeInfo: Attempt to use airport tile %u with airport id %u, not yet defined. Ignoring.", local_tile_id, airport + i); } else { /* Declared as been valid, can be used */ att[k].gfx = tempid; size = k + 1; copy_from = att; } } else if (att[k].gfx == 0xFF) { att[k].ti.x = (int8)GB(att[k].ti.x, 0, 8); att[k].ti.y = (int8)GB(att[k].ti.y, 0, 8); } if (as->rotation[j] == DIR_E || as->rotation[j] == DIR_W) { as->size_x = max(as->size_x, att[k].ti.y + 1); as->size_y = max(as->size_y, att[k].ti.x + 1); } else { as->size_x = max(as->size_x, att[k].ti.x + 1); as->size_y = max(as->size_y, att[k].ti.y + 1); } } tile_table[j] = CallocT(size); memcpy(tile_table[j], copy_from, sizeof(*copy_from) * size); } /* Install final layout construction in the airport spec */ as->table = tile_table; free(att); } catch (...) { for (int i = 0; i < as->num_table; i++) { free(tile_table[i]); } free(tile_table); free(att); throw; } break; } case 0x0C: as->min_year = buf->ReadWord(); as->max_year = buf->ReadWord(); if (as->max_year == 0xFFFF) as->max_year = MAX_YEAR; break; case 0x0D: as->ttd_airport_type = (TTDPAirportType)buf->ReadByte(); break; case 0x0E: as->catchment = Clamp(buf->ReadByte(), 1, MAX_CATCHMENT); break; case 0x0F: as->noise_level = buf->ReadByte(); break; case 0x10: AddStringForMapping(buf->ReadWord(), &as->name); break; case 0x11: // Maintenance cost factor as->maintenance_cost = buf->ReadWord(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Ignore properties for objects * @param prop The property to ignore. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult IgnoreObjectProperty(uint prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; switch (prop) { case 0x0B: case 0x0C: case 0x0D: case 0x12: case 0x14: case 0x16: case 0x17: buf->ReadByte(); break; case 0x09: case 0x0A: case 0x10: case 0x11: case 0x13: case 0x15: buf->ReadWord(); break; case 0x08: case 0x0E: case 0x0F: buf->ReadDWord(); break; default: ret = CIR_UNKNOWN; break; } return ret; } /** * Define properties for objects * @param id Local ID of the object. * @param numinfo Number of subsequent objectIDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult ObjectChangeInfo(uint id, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (id + numinfo > NUM_OBJECTS_PER_GRF) { grfmsg(1, "ObjectChangeInfo: Too many objects loaded (%u), max (%u). Ignoring.", id + numinfo, NUM_OBJECTS_PER_GRF); return CIR_INVALID_ID; } /* Allocate object specs if they haven't been allocated already. */ if (_cur.grffile->objectspec == NULL) { _cur.grffile->objectspec = CallocT(NUM_OBJECTS_PER_GRF); } for (int i = 0; i < numinfo; i++) { ObjectSpec *spec = _cur.grffile->objectspec[id + i]; if (prop != 0x08 && spec == NULL) { /* If the object property 08 is not yet set, ignore this property */ ChangeInfoResult cir = IgnoreObjectProperty(prop, buf); if (cir > ret) ret = cir; continue; } switch (prop) { case 0x08: { // Class ID ObjectSpec **ospec = &_cur.grffile->objectspec[id + i]; /* Allocate space for this object. */ if (*ospec == NULL) { *ospec = CallocT(1); (*ospec)->views = 1; // Default for NewGRFs that don't set it. } /* Swap classid because we read it in BE. */ uint32 classid = buf->ReadDWord(); (*ospec)->cls_id = ObjectClass::Allocate(BSWAP32(classid)); (*ospec)->enabled = true; break; } case 0x09: { // Class name ObjectClass *objclass = ObjectClass::Get(spec->cls_id); AddStringForMapping(buf->ReadWord(), &objclass->name); break; } case 0x0A: // Object name AddStringForMapping(buf->ReadWord(), &spec->name); break; case 0x0B: // Climate mask spec->climate = buf->ReadByte(); break; case 0x0C: // Size spec->size = buf->ReadByte(); break; case 0x0D: // Build cost multipler spec->build_cost_multiplier = buf->ReadByte(); spec->clear_cost_multiplier = spec->build_cost_multiplier; break; case 0x0E: // Introduction date spec->introduction_date = buf->ReadDWord(); break; case 0x0F: // End of life spec->end_of_life_date = buf->ReadDWord(); break; case 0x10: // Flags spec->flags = (ObjectFlags)buf->ReadWord(); _loaded_newgrf_features.has_2CC |= (spec->flags & OBJECT_FLAG_2CC_COLOUR) != 0; break; case 0x11: // Animation info spec->animation.frames = buf->ReadByte(); spec->animation.status = buf->ReadByte(); break; case 0x12: // Animation speed spec->animation.speed = buf->ReadByte(); break; case 0x13: // Animation triggers spec->animation.triggers = buf->ReadWord(); break; case 0x14: // Removal cost multiplier spec->clear_cost_multiplier = buf->ReadByte(); break; case 0x15: // Callback mask spec->callback_mask = buf->ReadWord(); break; case 0x16: // Building height spec->height = buf->ReadByte(); break; case 0x17: // Views spec->views = buf->ReadByte(); if (spec->views != 1 && spec->views != 2 && spec->views != 4) { grfmsg(2, "ObjectChangeInfo: Invalid number of views (%u) for object id %u. Ignoring.", spec->views, id + i); spec->views = 1; } break; case 0x18: // Amount placed on 256^2 map on map creation spec->generate_amount = buf->ReadByte(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } /** * Define properties for railtypes * @param id ID of the railtype. * @param numinfo Number of subsequent IDs to change the property for. * @param prop The property to change. * @param buf The property value. * @return ChangeInfoResult. */ static ChangeInfoResult RailTypeChangeInfo(uint id, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; extern RailtypeInfo _railtypes[RAILTYPE_END]; if (id + numinfo > RAILTYPE_END) { grfmsg(1, "RailTypeChangeInfo: Rail type %u is invalid, max %u, ignoring", id + numinfo, RAILTYPE_END); return CIR_INVALID_ID; } for (int i = 0; i < numinfo; i++) { RailType rt = _cur.grffile->railtype_map[id + i]; if (rt == INVALID_RAILTYPE) return CIR_INVALID_ID; RailtypeInfo *rti = &_railtypes[rt]; switch (prop) { case 0x08: // Label of rail type /* Skipped here as this is loaded during reservation stage. */ buf->ReadDWord(); break; case 0x09: { // Toolbar caption of railtype (sets name as well for backwards compatibility for grf ver < 8) uint16 str = buf->ReadWord(); AddStringForMapping(str, &rti->strings.toolbar_caption); if (_cur.grffile->grf_version < 8) { AddStringForMapping(str, &rti->strings.name); } break; } case 0x0A: // Menu text of railtype AddStringForMapping(buf->ReadWord(), &rti->strings.menu_text); break; case 0x0B: // Build window caption AddStringForMapping(buf->ReadWord(), &rti->strings.build_caption); break; case 0x0C: // Autoreplace text AddStringForMapping(buf->ReadWord(), &rti->strings.replace_text); break; case 0x0D: // New locomotive text AddStringForMapping(buf->ReadWord(), &rti->strings.new_loco); break; case 0x0E: // Compatible railtype list case 0x0F: // Powered railtype list case 0x18: // Railtype list required for date introduction case 0x19: // Introduced railtype list { /* Rail type compatibility bits are added to the existing bits * to allow multiple GRFs to modify compatibility with the * default rail types. */ int n = buf->ReadByte(); for (int j = 0; j != n; j++) { RailTypeLabel label = buf->ReadDWord(); RailType rt = GetRailTypeByLabel(BSWAP32(label), false); if (rt != INVALID_RAILTYPE) { switch (prop) { case 0x0F: SetBit(rti->powered_railtypes, rt); // Powered implies compatible. case 0x0E: SetBit(rti->compatible_railtypes, rt); break; case 0x18: SetBit(rti->introduction_required_railtypes, rt); break; case 0x19: SetBit(rti->introduces_railtypes, rt); break; } } } break; } case 0x10: // Rail Type flags rti->flags = (RailTypeFlags)buf->ReadByte(); break; case 0x11: // Curve speed advantage rti->curve_speed = buf->ReadByte(); break; case 0x12: // Station graphic rti->fallback_railtype = Clamp(buf->ReadByte(), 0, 2); break; case 0x13: // Construction cost factor rti->cost_multiplier = buf->ReadWord(); break; case 0x14: // Speed limit rti->max_speed = buf->ReadWord(); break; case 0x15: // Acceleration model rti->acceleration_type = Clamp(buf->ReadByte(), 0, 2); break; case 0x16: // Map colour rti->map_colour = buf->ReadByte(); break; case 0x17: // Introduction date rti->introduction_date = buf->ReadDWord(); break; case 0x1A: // Sort order rti->sorting_order = buf->ReadByte(); break; case 0x1B: // Name of railtype (overridden by prop 09 for grf ver < 8) AddStringForMapping(buf->ReadWord(), &rti->strings.name); break; case 0x1C: // Maintenance cost factor rti->maintenance_multiplier = buf->ReadWord(); break; case 0x1D: // Alternate rail type label list /* Skipped here as this is loaded during reservation stage. */ for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } static ChangeInfoResult RailTypeReserveInfo(uint id, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; extern RailtypeInfo _railtypes[RAILTYPE_END]; if (id + numinfo > RAILTYPE_END) { grfmsg(1, "RailTypeReserveInfo: Rail type %u is invalid, max %u, ignoring", id + numinfo, RAILTYPE_END); return CIR_INVALID_ID; } for (int i = 0; i < numinfo; i++) { switch (prop) { case 0x08: // Label of rail type { RailTypeLabel rtl = buf->ReadDWord(); rtl = BSWAP32(rtl); RailType rt = GetRailTypeByLabel(rtl, false); if (rt == INVALID_RAILTYPE) { /* Set up new rail type */ rt = AllocateRailType(rtl); } _cur.grffile->railtype_map[id + i] = rt; break; } case 0x09: // Toolbar caption of railtype case 0x0A: // Menu text case 0x0B: // Build window caption case 0x0C: // Autoreplace text case 0x0D: // New loco case 0x13: // Construction cost case 0x14: // Speed limit case 0x1B: // Name of railtype case 0x1C: // Maintenance cost factor buf->ReadWord(); break; case 0x1D: // Alternate rail type label list if (_cur.grffile->railtype_map[id + i] != INVALID_RAILTYPE) { int n = buf->ReadByte(); for (int j = 0; j != n; j++) { *_railtypes[_cur.grffile->railtype_map[id + i]].alternate_labels.Append() = BSWAP32(buf->ReadDWord()); } break; } grfmsg(1, "RailTypeReserveInfo: Ignoring property 1D for rail type %u because no label was set", id + i); /* FALL THROUGH */ case 0x0E: // Compatible railtype list case 0x0F: // Powered railtype list case 0x18: // Railtype list required for date introduction case 0x19: // Introduced railtype list for (int j = buf->ReadByte(); j != 0; j--) buf->ReadDWord(); break; case 0x10: // Rail Type flags case 0x11: // Curve speed advantage case 0x12: // Station graphic case 0x15: // Acceleration model case 0x16: // Map colour case 0x1A: // Sort order buf->ReadByte(); break; case 0x17: // Introduction date buf->ReadDWord(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } static ChangeInfoResult AirportTilesChangeInfo(uint airtid, int numinfo, int prop, ByteReader *buf) { ChangeInfoResult ret = CIR_SUCCESS; if (airtid + numinfo > NUM_AIRPORTTILES_PER_GRF) { grfmsg(1, "AirportTileChangeInfo: Too many airport tiles loaded (%u), max (%u). Ignoring.", airtid + numinfo, NUM_AIRPORTTILES_PER_GRF); return CIR_INVALID_ID; } /* Allocate airport tile specs if they haven't been allocated already. */ if (_cur.grffile->airtspec == NULL) { _cur.grffile->airtspec = CallocT(NUM_AIRPORTTILES_PER_GRF); } for (int i = 0; i < numinfo; i++) { AirportTileSpec *tsp = _cur.grffile->airtspec[airtid + i]; if (prop != 0x08 && tsp == NULL) { grfmsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile %u. Ignoring.", airtid + i); return CIR_INVALID_ID; } switch (prop) { case 0x08: { // Substitute airport tile type AirportTileSpec **tilespec = &_cur.grffile->airtspec[airtid + i]; byte subs_id = buf->ReadByte(); if (subs_id >= NEW_AIRPORTTILE_OFFSET) { /* The substitute id must be one of the original airport tiles. */ grfmsg(2, "AirportTileChangeInfo: Attempt to use new airport tile %u as substitute airport tile for %u. Ignoring.", subs_id, airtid + i); continue; } /* Allocate space for this airport tile. */ if (*tilespec == NULL) { *tilespec = CallocT(1); tsp = *tilespec; memcpy(tsp, AirportTileSpec::Get(subs_id), sizeof(AirportTileSpec)); tsp->enabled = true; tsp->animation.status = ANIM_STATUS_NO_ANIMATION; tsp->grf_prop.local_id = airtid + i; tsp->grf_prop.subst_id = subs_id; tsp->grf_prop.grffile = _cur.grffile; _airporttile_mngr.AddEntityID(airtid + i, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot } break; } case 0x09: { // Airport tile override byte override = buf->ReadByte(); /* The airport tile being overridden must be an original airport tile. */ if (override >= NEW_AIRPORTTILE_OFFSET) { grfmsg(2, "AirportTileChangeInfo: Attempt to override new airport tile %u with airport tile id %u. Ignoring.", override, airtid + i); continue; } _airporttile_mngr.Add(airtid + i, _cur.grffile->grfid, override); break; } case 0x0E: // Callback mask tsp->callback_mask = buf->ReadByte(); break; case 0x0F: // Animation information tsp->animation.frames = buf->ReadByte(); tsp->animation.status = buf->ReadByte(); break; case 0x10: // Animation speed tsp->animation.speed = buf->ReadByte(); break; case 0x11: // Animation triggers tsp->animation.triggers = buf->ReadByte(); break; default: ret = CIR_UNKNOWN; break; } } return ret; } static bool HandleChangeInfoResult(const char *caller, ChangeInfoResult cir, uint8 feature, uint8 property) { switch (cir) { default: NOT_REACHED(); case CIR_DISABLED: /* Error has already been printed; just stop parsing */ return true; case CIR_SUCCESS: return false; case CIR_UNHANDLED: grfmsg(1, "%s: Ignoring property 0x%02X of feature 0x%02X (not implemented)", caller, property, feature); return false; case CIR_UNKNOWN: grfmsg(0, "%s: Unknown property 0x%02X of feature 0x%02X, disabling", caller, property, feature); /* FALL THROUGH */ case CIR_INVALID_ID: { /* No debug message for an invalid ID, as it has already been output */ GRFError *error = DisableGrf(cir == CIR_INVALID_ID ? STR_NEWGRF_ERROR_INVALID_ID : STR_NEWGRF_ERROR_UNKNOWN_PROPERTY); if (cir != CIR_INVALID_ID) error->param_value[1] = property; return true; } } } /* Action 0x00 */ static void FeatureChangeInfo(ByteReader *buf) { /* <00> ()... * * B feature * B num-props how many properties to change per vehicle/station * B num-info how many vehicles/stations to change * E id ID of first vehicle/station to change, if num-info is * greater than one, this one and the following * vehicles/stations will be changed * B property what property to change, depends on the feature * V new-info new bytes of info (variable size; depends on properties) */ static const VCI_Handler handler[] = { /* GSF_TRAINS */ RailVehicleChangeInfo, /* GSF_ROADVEHICLES */ RoadVehicleChangeInfo, /* GSF_SHIPS */ ShipVehicleChangeInfo, /* GSF_AIRCRAFT */ AircraftVehicleChangeInfo, /* GSF_STATIONS */ StationChangeInfo, /* GSF_CANALS */ CanalChangeInfo, /* GSF_BRIDGES */ BridgeChangeInfo, /* GSF_HOUSES */ TownHouseChangeInfo, /* GSF_GLOBALVAR */ GlobalVarChangeInfo, /* GSF_INDUSTRYTILES */ IndustrytilesChangeInfo, /* GSF_INDUSTRIES */ IndustriesChangeInfo, /* GSF_CARGOES */ NULL, // Cargo is handled during reservation /* GSF_SOUNDFX */ SoundEffectChangeInfo, /* GSF_AIRPORTS */ AirportChangeInfo, /* GSF_SIGNALS */ NULL, /* GSF_OBJECTS */ ObjectChangeInfo, /* GSF_RAILTYPES */ RailTypeChangeInfo, /* GSF_AIRPORTTILES */ AirportTilesChangeInfo, }; uint8 feature = buf->ReadByte(); uint8 numprops = buf->ReadByte(); uint numinfo = buf->ReadByte(); uint engine = buf->ReadExtendedByte(); grfmsg(6, "FeatureChangeInfo: feature %d, %d properties, to apply to %d+%d", feature, numprops, engine, numinfo); if (feature >= lengthof(handler) || handler[feature] == NULL) { if (feature != GSF_CARGOES) grfmsg(1, "FeatureChangeInfo: Unsupported feature %d, skipping", feature); return; } /* Mark the feature as used by the grf */ SetBit(_cur.grffile->grf_features, feature); while (numprops-- && buf->HasData()) { uint8 prop = buf->ReadByte(); ChangeInfoResult cir = handler[feature](engine, numinfo, prop, buf); if (HandleChangeInfoResult("FeatureChangeInfo", cir, feature, prop)) return; } } /* Action 0x00 (GLS_SAFETYSCAN) */ static void SafeChangeInfo(ByteReader *buf) { uint8 feature = buf->ReadByte(); uint8 numprops = buf->ReadByte(); uint numinfo = buf->ReadByte(); buf->ReadExtendedByte(); // id if (feature == GSF_BRIDGES && numprops == 1) { uint8 prop = buf->ReadByte(); /* Bridge property 0x0D is redefinition of sprite layout tables, which * is considered safe. */ if (prop == 0x0D) return; } else if (feature == GSF_GLOBALVAR && numprops == 1) { uint8 prop = buf->ReadByte(); /* Engine ID Mappings are safe, if the source is static */ if (prop == 0x11) { bool is_safe = true; for (uint i = 0; i < numinfo; i++) { uint32 s = buf->ReadDWord(); buf->ReadDWord(); // dest const GRFConfig *grfconfig = GetGRFConfig(s); if (grfconfig != NULL && !HasBit(grfconfig->flags, GCF_STATIC)) { is_safe = false; break; } } if (is_safe) return; } } SetBit(_cur.grfconfig->flags, GCF_UNSAFE); /* Skip remainder of GRF */ _cur.skip_sprites = -1; } /* Action 0x00 (GLS_RESERVE) */ static void ReserveChangeInfo(ByteReader *buf) { uint8 feature = buf->ReadByte(); if (feature != GSF_CARGOES && feature != GSF_GLOBALVAR && feature != GSF_RAILTYPES) return; uint8 numprops = buf->ReadByte(); uint8 numinfo = buf->ReadByte(); uint8 index = buf->ReadExtendedByte(); while (numprops-- && buf->HasData()) { uint8 prop = buf->ReadByte(); ChangeInfoResult cir = CIR_SUCCESS; switch (feature) { default: NOT_REACHED(); case GSF_CARGOES: cir = CargoChangeInfo(index, numinfo, prop, buf); break; case GSF_GLOBALVAR: cir = GlobalVarReserveInfo(index, numinfo, prop, buf); break; case GSF_RAILTYPES: cir = RailTypeReserveInfo(index, numinfo, prop, buf); break; } if (HandleChangeInfoResult("ReserveChangeInfo", cir, feature, prop)) return; } } /* Action 0x01 */ static void NewSpriteSet(ByteReader *buf) { /* Basic format: <01> * Extended format: <01> 00 * * B feature feature to define sprites for * 0, 1, 2, 3: veh-type, 4: train stations * E first-set first sprite set to define * B num-sets number of sprite sets (extended byte in extended format) * E num-ent how many entries per sprite set * For vehicles, this is the number of different * vehicle directions in each sprite set * Set num-dirs=8, unless your sprites are symmetric. * In that case, use num-dirs=4. */ uint8 feature = buf->ReadByte(); uint16 num_sets = buf->ReadByte(); uint16 first_set = 0; if (num_sets == 0 && buf->HasData(3)) { /* Extended Action1 format. * Some GRFs define zero sets of zero sprites, though there is actually no use in that. Ignore them. */ first_set = buf->ReadExtendedByte(); num_sets = buf->ReadExtendedByte(); } uint16 num_ents = buf->ReadExtendedByte(); _cur.AddSpriteSets(feature, _cur.spriteid, first_set, num_sets, num_ents); grfmsg(7, "New sprite set at %d of type %d, consisting of %d sets with %d views each (total %d)", _cur.spriteid, feature, num_sets, num_ents, num_sets * num_ents ); for (int i = 0; i < num_sets * num_ents; i++) { _cur.nfo_line++; LoadNextSprite(_cur.spriteid++, _cur.file_index, _cur.nfo_line, _cur.grf_container_ver); } } /* Action 0x01 (SKIP) */ static void SkipAct1(ByteReader *buf) { buf->ReadByte(); uint16 num_sets = buf->ReadByte(); if (num_sets == 0 && buf->HasData(3)) { /* Extended Action1 format. * Some GRFs define zero sets of zero sprites, though there is actually no use in that. Ignore them. */ buf->ReadExtendedByte(); // first_set num_sets = buf->ReadExtendedByte(); } uint16 num_ents = buf->ReadExtendedByte(); _cur.skip_sprites = num_sets * num_ents; grfmsg(3, "SkipAct1: Skipping %d sprites", _cur.skip_sprites); } /* Helper function to either create a callback or link to a previously * defined spritegroup. */ static const SpriteGroup *GetGroupFromGroupID(byte setid, byte type, uint16 groupid) { if (HasBit(groupid, 15)) { assert(CallbackResultSpriteGroup::CanAllocateItem()); return new CallbackResultSpriteGroup(groupid, _cur.grffile->grf_version >= 8); } if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == NULL) { grfmsg(1, "GetGroupFromGroupID(0x%02X:0x%02X): Groupid 0x%04X does not exist, leaving empty", setid, type, groupid); return NULL; } return _cur.spritegroups[groupid]; } /** * Helper function to either create a callback or a result sprite group. * @param feature GrfSpecFeature to define spritegroup for. * @param setid SetID of the currently being parsed Action2. (only for debug output) * @param type Type of the currently being parsed Action2. (only for debug output) * @param spriteid Raw value from the GRF for the new spritegroup; describes either the return value or the referenced spritegroup. * @return Created spritegroup. */ static const SpriteGroup *CreateGroupFromGroupID(byte feature, byte setid, byte type, uint16 spriteid) { if (HasBit(spriteid, 15)) { assert(CallbackResultSpriteGroup::CanAllocateItem()); return new CallbackResultSpriteGroup(spriteid, _cur.grffile->grf_version >= 8); } if (!_cur.IsValidSpriteSet(feature, spriteid)) { grfmsg(1, "CreateGroupFromGroupID(0x%02X:0x%02X): Sprite set %u invalid", setid, type, spriteid); return NULL; } SpriteID spriteset_start = _cur.GetSprite(feature, spriteid); uint num_sprites = _cur.GetNumEnts(feature, spriteid); /* Ensure that the sprites are loeded */ assert(spriteset_start + num_sprites <= _cur.spriteid); assert(ResultSpriteGroup::CanAllocateItem()); return new ResultSpriteGroup(spriteset_start, num_sprites); } /* Action 0x02 */ static void NewSpriteGroup(ByteReader *buf) { /* <02> * * B feature see action 1 * B set-id ID of this particular definition * B type/num-entries * if 80 or greater, this is a randomized or variational * list definition, see below * otherwise it specifies a number of entries, the exact * meaning depends on the feature * V feature-specific-data (huge mess, don't even look it up --pasky) */ SpriteGroup *act_group = NULL; uint8 feature = buf->ReadByte(); uint8 setid = buf->ReadByte(); uint8 type = buf->ReadByte(); /* Sprite Groups are created here but they are allocated from a pool, so * we do not need to delete anything if there is an exception from the * ByteReader. */ switch (type) { /* Deterministic Sprite Group */ case 0x81: // Self scope, byte case 0x82: // Parent scope, byte case 0x85: // Self scope, word case 0x86: // Parent scope, word case 0x89: // Self scope, dword case 0x8A: // Parent scope, dword { byte varadjust; byte varsize; assert(DeterministicSpriteGroup::CanAllocateItem()); DeterministicSpriteGroup *group = new DeterministicSpriteGroup(); act_group = group; group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; switch (GB(type, 2, 2)) { default: NOT_REACHED(); case 0: group->size = DSG_SIZE_BYTE; varsize = 1; break; case 1: group->size = DSG_SIZE_WORD; varsize = 2; break; case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break; } static SmallVector adjusts; adjusts.Clear(); /* Loop through the var adjusts. Unfortunately we don't know how many we have * from the outset, so we shall have to keep reallocing. */ do { DeterministicSpriteGroupAdjust *adjust = adjusts.Append(); /* The first var adjust doesn't have an operation specified, so we set it to add. */ adjust->operation = adjusts.Length() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf->ReadByte(); adjust->variable = buf->ReadByte(); if (adjust->variable == 0x7E) { /* Link subroutine group */ adjust->subroutine = GetGroupFromGroupID(setid, type, buf->ReadByte()); } else { adjust->parameter = IsInsideMM(adjust->variable, 0x60, 0x80) ? buf->ReadByte() : 0; } varadjust = buf->ReadByte(); adjust->shift_num = GB(varadjust, 0, 5); adjust->type = (DeterministicSpriteGroupAdjustType)GB(varadjust, 6, 2); adjust->and_mask = buf->ReadVarSize(varsize); if (adjust->type != DSGA_TYPE_NONE) { adjust->add_val = buf->ReadVarSize(varsize); adjust->divmod_val = buf->ReadVarSize(varsize); } else { adjust->add_val = 0; adjust->divmod_val = 0; } /* Continue reading var adjusts while bit 5 is set. */ } while (HasBit(varadjust, 5)); group->num_adjusts = adjusts.Length(); group->adjusts = MallocT(group->num_adjusts); MemCpyT(group->adjusts, adjusts.Begin(), group->num_adjusts); group->num_ranges = buf->ReadByte(); if (group->num_ranges > 0) group->ranges = CallocT(group->num_ranges); for (uint i = 0; i < group->num_ranges; i++) { group->ranges[i].group = GetGroupFromGroupID(setid, type, buf->ReadWord()); group->ranges[i].low = buf->ReadVarSize(varsize); group->ranges[i].high = buf->ReadVarSize(varsize); } group->default_group = GetGroupFromGroupID(setid, type, buf->ReadWord()); break; } /* Randomized Sprite Group */ case 0x80: // Self scope case 0x83: // Parent scope case 0x84: // Relative scope { assert(RandomizedSpriteGroup::CanAllocateItem()); RandomizedSpriteGroup *group = new RandomizedSpriteGroup(); act_group = group; group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; if (HasBit(type, 2)) { if (feature <= GSF_AIRCRAFT) group->var_scope = VSG_SCOPE_RELATIVE; group->count = buf->ReadByte(); } uint8 triggers = buf->ReadByte(); group->triggers = GB(triggers, 0, 7); group->cmp_mode = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY; group->lowest_randbit = buf->ReadByte(); group->num_groups = buf->ReadByte(); group->groups = CallocT(group->num_groups); for (uint i = 0; i < group->num_groups; i++) { group->groups[i] = GetGroupFromGroupID(setid, type, buf->ReadWord()); } break; } /* Neither a variable or randomized sprite group... must be a real group */ default: { switch (feature) { case GSF_TRAINS: case GSF_ROADVEHICLES: case GSF_SHIPS: case GSF_AIRCRAFT: case GSF_STATIONS: case GSF_CANALS: case GSF_CARGOES: case GSF_AIRPORTS: case GSF_RAILTYPES: { byte num_loaded = type; byte num_loading = buf->ReadByte(); if (!_cur.HasValidSpriteSets(feature)) { grfmsg(0, "NewSpriteGroup: No sprite set to work on! Skipping"); return; } assert(RealSpriteGroup::CanAllocateItem()); RealSpriteGroup *group = new RealSpriteGroup(); act_group = group; group->num_loaded = num_loaded; group->num_loading = num_loading; if (num_loaded > 0) group->loaded = CallocT(num_loaded); if (num_loading > 0) group->loading = CallocT(num_loading); grfmsg(6, "NewSpriteGroup: New SpriteGroup 0x%02X, %u loaded, %u loading", setid, num_loaded, num_loading); for (uint i = 0; i < num_loaded; i++) { uint16 spriteid = buf->ReadWord(); group->loaded[i] = CreateGroupFromGroupID(feature, setid, type, spriteid); grfmsg(8, "NewSpriteGroup: + rg->loaded[%i] = subset %u", i, spriteid); } for (uint i = 0; i < num_loading; i++) { uint16 spriteid = buf->ReadWord(); group->loading[i] = CreateGroupFromGroupID(feature, setid, type, spriteid); grfmsg(8, "NewSpriteGroup: + rg->loading[%i] = subset %u", i, spriteid); } break; } case GSF_HOUSES: case GSF_AIRPORTTILES: case GSF_OBJECTS: case GSF_INDUSTRYTILES: { byte num_building_sprites = max((uint8)1, type); assert(TileLayoutSpriteGroup::CanAllocateItem()); TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup(); act_group = group; /* On error, bail out immediately. Temporary GRF data was already freed */ if (ReadSpriteLayout(buf, num_building_sprites, true, feature, false, type == 0, &group->dts)) return; break; } case GSF_INDUSTRIES: { if (type > 1) { grfmsg(1, "NewSpriteGroup: Unsupported industry production version %d, skipping", type); break; } assert(IndustryProductionSpriteGroup::CanAllocateItem()); IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup(); act_group = group; group->version = type; if (type == 0) { for (uint i = 0; i < 3; i++) { group->subtract_input[i] = (int16)buf->ReadWord(); // signed } for (uint i = 0; i < 2; i++) { group->add_output[i] = buf->ReadWord(); // unsigned } group->again = buf->ReadByte(); } else { for (uint i = 0; i < 3; i++) { group->subtract_input[i] = buf->ReadByte(); } for (uint i = 0; i < 2; i++) { group->add_output[i] = buf->ReadByte(); } group->again = buf->ReadByte(); } break; } /* Loading of Tile Layout and Production Callback groups would happen here */ default: grfmsg(1, "NewSpriteGroup: Unsupported feature %d, skipping", feature); } } } _cur.spritegroups[setid] = act_group; } static CargoID TranslateCargo(uint8 feature, uint8 ctype) { if (feature == GSF_OBJECTS) { switch (ctype) { case 0: return 0; case 0xFF: return CT_PURCHASE_OBJECT; default: grfmsg(1, "TranslateCargo: Invalid cargo bitnum %d for objects, skipping.", ctype); return CT_INVALID; } } /* Special cargo types for purchase list and stations */ if (feature == GSF_STATIONS && ctype == 0xFE) return CT_DEFAULT_NA; if (ctype == 0xFF) return CT_PURCHASE; if (_cur.grffile->cargo_list.Length() == 0) { /* No cargo table, so use bitnum values */ if (ctype >= 32) { grfmsg(1, "TranslateCargo: Cargo bitnum %d out of range (max 31), skipping.", ctype); return CT_INVALID; } const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { if (cs->bitnum == ctype) { grfmsg(6, "TranslateCargo: Cargo bitnum %d mapped to cargo type %d.", ctype, cs->Index()); return cs->Index(); } } grfmsg(5, "TranslateCargo: Cargo bitnum %d not available in this climate, skipping.", ctype); return CT_INVALID; } /* Check if the cargo type is out of bounds of the cargo translation table */ if (ctype >= _cur.grffile->cargo_list.Length()) { grfmsg(1, "TranslateCargo: Cargo type %d out of range (max %d), skipping.", ctype, _cur.grffile->cargo_list.Length() - 1); return CT_INVALID; } /* Look up the cargo label from the translation table */ CargoLabel cl = _cur.grffile->cargo_list[ctype]; if (cl == 0) { grfmsg(5, "TranslateCargo: Cargo type %d not available in this climate, skipping.", ctype); return CT_INVALID; } ctype = GetCargoIDByLabel(cl); if (ctype == CT_INVALID) { grfmsg(5, "TranslateCargo: Cargo '%c%c%c%c' unsupported, skipping.", GB(cl, 24, 8), GB(cl, 16, 8), GB(cl, 8, 8), GB(cl, 0, 8)); return CT_INVALID; } grfmsg(6, "TranslateCargo: Cargo '%c%c%c%c' mapped to cargo type %d.", GB(cl, 24, 8), GB(cl, 16, 8), GB(cl, 8, 8), GB(cl, 0, 8), ctype); return ctype; } static bool IsValidGroupID(uint16 groupid, const char *function) { if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == NULL) { grfmsg(1, "%s: Spritegroup 0x%04X out of range or empty, skipping.", function, groupid); return false; } return true; } static void VehicleMapSpriteGroup(ByteReader *buf, byte feature, uint8 idcount) { static EngineID *last_engines; static uint last_engines_count; bool wagover = false; /* Test for 'wagon override' flag */ if (HasBit(idcount, 7)) { wagover = true; /* Strip off the flag */ idcount = GB(idcount, 0, 7); if (last_engines_count == 0) { grfmsg(0, "VehicleMapSpriteGroup: WagonOverride: No engine to do override with"); return; } grfmsg(6, "VehicleMapSpriteGroup: WagonOverride: %u engines, %u wagons", last_engines_count, idcount); } else { if (last_engines_count != idcount) { last_engines = ReallocT(last_engines, idcount); last_engines_count = idcount; } } EngineID *engines = AllocaM(EngineID, idcount); for (uint i = 0; i < idcount; i++) { Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, buf->ReadExtendedByte()); if (e == NULL) { /* No engine could be allocated?!? Deal with it. Okay, * this might look bad. Also make sure this NewGRF * gets disabled, as a half loaded one is bad. */ HandleChangeInfoResult("VehicleMapSpriteGroup", CIR_INVALID_ID, 0, 0); return; } engines[i] = e->index; if (!wagover) last_engines[i] = engines[i]; } uint8 cidcount = buf->ReadByte(); for (uint c = 0; c < cidcount; c++) { uint8 ctype = buf->ReadByte(); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) continue; grfmsg(8, "VehicleMapSpriteGroup: * [%d] Cargo type 0x%X, group id 0x%02X", c, ctype, groupid); ctype = TranslateCargo(feature, ctype); if (ctype == CT_INVALID) continue; for (uint i = 0; i < idcount; i++) { EngineID engine = engines[i]; grfmsg(7, "VehicleMapSpriteGroup: [%d] Engine %d...", i, engine); if (wagover) { SetWagonOverrideSprites(engine, ctype, _cur.spritegroups[groupid], last_engines, last_engines_count); } else { SetCustomEngineSprites(engine, ctype, _cur.spritegroups[groupid]); } } } uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) return; grfmsg(8, "-- Default group id 0x%04X", groupid); for (uint i = 0; i < idcount; i++) { EngineID engine = engines[i]; if (wagover) { SetWagonOverrideSprites(engine, CT_DEFAULT, _cur.spritegroups[groupid], last_engines, last_engines_count); } else { SetCustomEngineSprites(engine, CT_DEFAULT, _cur.spritegroups[groupid]); SetEngineGRF(engine, _cur.grffile); } } } static void CanalMapSpriteGroup(ByteReader *buf, uint8 idcount) { CanalFeature *cfs = AllocaM(CanalFeature, idcount); for (uint i = 0; i < idcount; i++) { cfs[i] = (CanalFeature)buf->ReadByte(); } uint8 cidcount = buf->ReadByte(); buf->Skip(cidcount * 3); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "CanalMapSpriteGroup")) return; for (uint i = 0; i < idcount; i++) { CanalFeature cf = cfs[i]; if (cf >= CF_END) { grfmsg(1, "CanalMapSpriteGroup: Canal subset %d out of range, skipping", cf); continue; } _water_feature[cf].grffile = _cur.grffile; _water_feature[cf].group = _cur.spritegroups[groupid]; } } static void StationMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *stations = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { stations[i] = buf->ReadByte(); } uint8 cidcount = buf->ReadByte(); for (uint c = 0; c < cidcount; c++) { uint8 ctype = buf->ReadByte(); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) continue; ctype = TranslateCargo(GSF_STATIONS, ctype); if (ctype == CT_INVALID) continue; for (uint i = 0; i < idcount; i++) { StationSpec *statspec = _cur.grffile->stations == NULL ? NULL : _cur.grffile->stations[stations[i]]; if (statspec == NULL) { grfmsg(1, "StationMapSpriteGroup: Station with ID 0x%02X does not exist, skipping", stations[i]); continue; } statspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid]; } } uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) return; for (uint i = 0; i < idcount; i++) { StationSpec *statspec = _cur.grffile->stations == NULL ? NULL : _cur.grffile->stations[stations[i]]; if (statspec == NULL) { grfmsg(1, "StationMapSpriteGroup: Station with ID 0x%02X does not exist, skipping", stations[i]); continue; } if (statspec->grf_prop.grffile != NULL) { grfmsg(1, "StationMapSpriteGroup: Station with ID 0x%02X mapped multiple times, skipping", stations[i]); continue; } statspec->grf_prop.spritegroup[CT_DEFAULT] = _cur.spritegroups[groupid]; statspec->grf_prop.grffile = _cur.grffile; statspec->grf_prop.local_id = stations[i]; StationClass::Assign(statspec); } } static void TownHouseMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *houses = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { houses[i] = buf->ReadByte(); } /* Skip the cargo type section, we only care about the default group */ uint8 cidcount = buf->ReadByte(); buf->Skip(cidcount * 3); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "TownHouseMapSpriteGroup")) return; if (_cur.grffile->housespec == NULL) { grfmsg(1, "TownHouseMapSpriteGroup: No houses defined, skipping"); return; } for (uint i = 0; i < idcount; i++) { HouseSpec *hs = _cur.grffile->housespec[houses[i]]; if (hs == NULL) { grfmsg(1, "TownHouseMapSpriteGroup: House %d undefined, skipping.", houses[i]); continue; } hs->grf_prop.spritegroup[0] = _cur.spritegroups[groupid]; } } static void IndustryMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *industries = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { industries[i] = buf->ReadByte(); } /* Skip the cargo type section, we only care about the default group */ uint8 cidcount = buf->ReadByte(); buf->Skip(cidcount * 3); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "IndustryMapSpriteGroup")) return; if (_cur.grffile->industryspec == NULL) { grfmsg(1, "IndustryMapSpriteGroup: No industries defined, skipping"); return; } for (uint i = 0; i < idcount; i++) { IndustrySpec *indsp = _cur.grffile->industryspec[industries[i]]; if (indsp == NULL) { grfmsg(1, "IndustryMapSpriteGroup: Industry %d undefined, skipping", industries[i]); continue; } indsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid]; } } static void IndustrytileMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *indtiles = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { indtiles[i] = buf->ReadByte(); } /* Skip the cargo type section, we only care about the default group */ uint8 cidcount = buf->ReadByte(); buf->Skip(cidcount * 3); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "IndustrytileMapSpriteGroup")) return; if (_cur.grffile->indtspec == NULL) { grfmsg(1, "IndustrytileMapSpriteGroup: No industry tiles defined, skipping"); return; } for (uint i = 0; i < idcount; i++) { IndustryTileSpec *indtsp = _cur.grffile->indtspec[indtiles[i]]; if (indtsp == NULL) { grfmsg(1, "IndustrytileMapSpriteGroup: Industry tile %d undefined, skipping", indtiles[i]); continue; } indtsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid]; } } static void CargoMapSpriteGroup(ByteReader *buf, uint8 idcount) { CargoID *cargoes = AllocaM(CargoID, idcount); for (uint i = 0; i < idcount; i++) { cargoes[i] = buf->ReadByte(); } /* Skip the cargo type section, we only care about the default group */ uint8 cidcount = buf->ReadByte(); buf->Skip(cidcount * 3); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "CargoMapSpriteGroup")) return; for (uint i = 0; i < idcount; i++) { CargoID cid = cargoes[i]; if (cid >= NUM_CARGO) { grfmsg(1, "CargoMapSpriteGroup: Cargo ID %d out of range, skipping", cid); continue; } CargoSpec *cs = CargoSpec::Get(cid); cs->grffile = _cur.grffile; cs->group = _cur.spritegroups[groupid]; } } static void ObjectMapSpriteGroup(ByteReader *buf, uint8 idcount) { if (_cur.grffile->objectspec == NULL) { grfmsg(1, "ObjectMapSpriteGroup: No object tiles defined, skipping"); return; } uint8 *objects = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { objects[i] = buf->ReadByte(); } uint8 cidcount = buf->ReadByte(); for (uint c = 0; c < cidcount; c++) { uint8 ctype = buf->ReadByte(); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) continue; ctype = TranslateCargo(GSF_OBJECTS, ctype); if (ctype == CT_INVALID) continue; for (uint i = 0; i < idcount; i++) { ObjectSpec *spec = _cur.grffile->objectspec[objects[i]]; if (spec == NULL) { grfmsg(1, "ObjectMapSpriteGroup: Object with ID 0x%02X undefined, skipping", objects[i]); continue; } spec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid]; } } uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) return; for (uint i = 0; i < idcount; i++) { ObjectSpec *spec = _cur.grffile->objectspec[objects[i]]; if (spec == NULL) { grfmsg(1, "ObjectMapSpriteGroup: Object with ID 0x%02X undefined, skipping", objects[i]); continue; } if (spec->grf_prop.grffile != NULL) { grfmsg(1, "ObjectMapSpriteGroup: Object with ID 0x%02X mapped multiple times, skipping", objects[i]); continue; } spec->grf_prop.spritegroup[0] = _cur.spritegroups[groupid]; spec->grf_prop.grffile = _cur.grffile; spec->grf_prop.local_id = objects[i]; } } static void RailTypeMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *railtypes = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { railtypes[i] = _cur.grffile->railtype_map[buf->ReadByte()]; } uint8 cidcount = buf->ReadByte(); for (uint c = 0; c < cidcount; c++) { uint8 ctype = buf->ReadByte(); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "RailTypeMapSpriteGroup")) continue; if (ctype >= RTSG_END) continue; extern RailtypeInfo _railtypes[RAILTYPE_END]; for (uint i = 0; i < idcount; i++) { if (railtypes[i] != INVALID_RAILTYPE) { RailtypeInfo *rti = &_railtypes[railtypes[i]]; rti->grffile[ctype] = _cur.grffile; rti->group[ctype] = _cur.spritegroups[groupid]; } } } /* Railtypes do not use the default group. */ buf->ReadWord(); } static void AirportMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *airports = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { airports[i] = buf->ReadByte(); } /* Skip the cargo type section, we only care about the default group */ uint8 cidcount = buf->ReadByte(); buf->Skip(cidcount * 3); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "AirportMapSpriteGroup")) return; if (_cur.grffile->airportspec == NULL) { grfmsg(1, "AirportMapSpriteGroup: No airports defined, skipping"); return; } for (uint i = 0; i < idcount; i++) { AirportSpec *as = _cur.grffile->airportspec[airports[i]]; if (as == NULL) { grfmsg(1, "AirportMapSpriteGroup: Airport %d undefined, skipping", airports[i]); continue; } as->grf_prop.spritegroup[0] = _cur.spritegroups[groupid]; } } static void AirportTileMapSpriteGroup(ByteReader *buf, uint8 idcount) { uint8 *airptiles = AllocaM(uint8, idcount); for (uint i = 0; i < idcount; i++) { airptiles[i] = buf->ReadByte(); } /* Skip the cargo type section, we only care about the default group */ uint8 cidcount = buf->ReadByte(); buf->Skip(cidcount * 3); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "AirportTileMapSpriteGroup")) return; if (_cur.grffile->airtspec == NULL) { grfmsg(1, "AirportTileMapSpriteGroup: No airport tiles defined, skipping"); return; } for (uint i = 0; i < idcount; i++) { AirportTileSpec *airtsp = _cur.grffile->airtspec[airptiles[i]]; if (airtsp == NULL) { grfmsg(1, "AirportTileMapSpriteGroup: Airport tile %d undefined, skipping", airptiles[i]); continue; } airtsp->grf_prop.spritegroup[0] = _cur.spritegroups[groupid]; } } /* Action 0x03 */ static void FeatureMapSpriteGroup(ByteReader *buf) { /* <03> ... [ ]... * id-list := [] [id-list] * cargo-list := [cargo-list] * * B feature see action 0 * B n-id bits 0-6: how many IDs this definition applies to * bit 7: if set, this is a wagon override definition (see below) * B ids the IDs for which this definition applies * B num-cid number of cargo IDs (sprite group IDs) in this definition * can be zero, in that case the def-cid is used always * B cargo-type type of this cargo type (e.g. mail=2, wood=7, see below) * W cid cargo ID (sprite group ID) for this type of cargo * W def-cid default cargo ID (sprite group ID) */ uint8 feature = buf->ReadByte(); uint8 idcount = buf->ReadByte(); /* If idcount is zero, this is a feature callback */ if (idcount == 0) { /* Skip number of cargo ids? */ buf->ReadByte(); uint16 groupid = buf->ReadWord(); if (!IsValidGroupID(groupid, "FeatureMapSpriteGroup")) return; grfmsg(6, "FeatureMapSpriteGroup: Adding generic feature callback for feature %d", feature); AddGenericCallback(feature, _cur.grffile, _cur.spritegroups[groupid]); return; } /* Mark the feature as used by the grf (generic callbacks do not count) */ SetBit(_cur.grffile->grf_features, feature); grfmsg(6, "FeatureMapSpriteGroup: Feature %d, %d ids", feature, idcount); switch (feature) { case GSF_TRAINS: case GSF_ROADVEHICLES: case GSF_SHIPS: case GSF_AIRCRAFT: VehicleMapSpriteGroup(buf, feature, idcount); return; case GSF_CANALS: CanalMapSpriteGroup(buf, idcount); return; case GSF_STATIONS: StationMapSpriteGroup(buf, idcount); return; case GSF_HOUSES: TownHouseMapSpriteGroup(buf, idcount); return; case GSF_INDUSTRIES: IndustryMapSpriteGroup(buf, idcount); return; case GSF_INDUSTRYTILES: IndustrytileMapSpriteGroup(buf, idcount); return; case GSF_CARGOES: CargoMapSpriteGroup(buf, idcount); return; case GSF_AIRPORTS: AirportMapSpriteGroup(buf, idcount); return; case GSF_OBJECTS: ObjectMapSpriteGroup(buf, idcount); break; case GSF_RAILTYPES: RailTypeMapSpriteGroup(buf, idcount); break; case GSF_AIRPORTTILES: AirportTileMapSpriteGroup(buf, idcount); return; default: grfmsg(1, "FeatureMapSpriteGroup: Unsupported feature %d, skipping", feature); return; } } /* Action 0x04 */ static void FeatureNewName(ByteReader *buf) { /* <04> * * B veh-type see action 0 (as 00..07, + 0A * But IF veh-type = 48, then generic text * B language-id If bit 6 is set, This is the extended language scheme, * with up to 64 language. * Otherwise, it is a mapping where set bits have meaning * 0 = american, 1 = english, 2 = german, 3 = french, 4 = spanish * Bit 7 set means this is a generic text, not a vehicle one (or else) * B num-veh number of vehicles which are getting a new name * B/W offset number of the first vehicle that gets a new name * Byte : ID of vehicle to change * Word : ID of string to change/add * S data new texts, each of them zero-terminated, after * which the next name begins. */ bool new_scheme = _cur.grffile->grf_version >= 7; uint8 feature = buf->ReadByte(); uint8 lang = buf->ReadByte(); uint8 num = buf->ReadByte(); bool generic = HasBit(lang, 7); uint16 id; if (generic) { id = buf->ReadWord(); } else if (feature <= GSF_AIRCRAFT) { id = buf->ReadExtendedByte(); } else { id = buf->ReadByte(); } ClrBit(lang, 7); uint16 endid = id + num; grfmsg(6, "FeatureNewName: About to rename engines %d..%d (feature %d) in language 0x%02X", id, endid, feature, lang); for (; id < endid && buf->HasData(); id++) { const char *name = buf->ReadString(); grfmsg(8, "FeatureNewName: 0x%04X <- %s", id, name); switch (feature) { case GSF_TRAINS: case GSF_ROADVEHICLES: case GSF_SHIPS: case GSF_AIRCRAFT: if (!generic) { Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, id, HasBit(_cur.grfconfig->flags, GCF_STATIC)); if (e == NULL) break; StringID string = AddGRFString(_cur.grffile->grfid, e->index, lang, new_scheme, false, name, e->info.string_id); e->info.string_id = string; } else { AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, true, name, STR_UNDEFINED); } break; case GSF_INDUSTRIES: { AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, true, name, STR_UNDEFINED); break; } case GSF_HOUSES: default: switch (GB(id, 8, 8)) { case 0xC4: // Station class name if (_cur.grffile->stations == NULL || _cur.grffile->stations[GB(id, 0, 8)] == NULL) { grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8)); } else { StationClassID cls_id = _cur.grffile->stations[GB(id, 0, 8)]->cls_id; StationClass::Get(cls_id)->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); } break; case 0xC5: // Station name if (_cur.grffile->stations == NULL || _cur.grffile->stations[GB(id, 0, 8)] == NULL) { grfmsg(1, "FeatureNewName: Attempt to name undefined station 0x%X, ignoring", GB(id, 0, 8)); } else { _cur.grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); } break; case 0xC7: // Airporttile name if (_cur.grffile->airtspec == NULL || _cur.grffile->airtspec[GB(id, 0, 8)] == NULL) { grfmsg(1, "FeatureNewName: Attempt to name undefined airport tile 0x%X, ignoring", GB(id, 0, 8)); } else { _cur.grffile->airtspec[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); } break; case 0xC9: // House name if (_cur.grffile->housespec == NULL || _cur.grffile->housespec[GB(id, 0, 8)] == NULL) { grfmsg(1, "FeatureNewName: Attempt to name undefined house 0x%X, ignoring.", GB(id, 0, 8)); } else { _cur.grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); } break; case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xDC: AddGRFString(_cur.grffile->grfid, id, lang, new_scheme, true, name, STR_UNDEFINED); break; default: grfmsg(7, "FeatureNewName: Unsupported ID (0x%04X)", id); break; } break; } } } /** * Sanitize incoming sprite offsets for Action 5 graphics replacements. * @param num The number of sprites to load. * @param offset Offset from the base. * @param max_sprites The maximum number of sprites that can be loaded in this action 5. * @param name Used for error warnings. * @return The number of sprites that is going to be skipped. */ static uint16 SanitizeSpriteOffset(uint16& num, uint16 offset, int max_sprites, const char *name) { if (offset >= max_sprites) { grfmsg(1, "GraphicsNew: %s sprite offset must be less than %i, skipping", name, max_sprites); uint orig_num = num; num = 0; return orig_num; } if (offset + num > max_sprites) { grfmsg(4, "GraphicsNew: %s sprite overflow, truncating...", name); uint orig_num = num; num = max(max_sprites - offset, 0); return orig_num - num; } return 0; } /** The type of action 5 type. */ enum Action5BlockType { A5BLOCK_FIXED, ///< Only allow replacing a whole block of sprites. (TTDP compatible) A5BLOCK_ALLOW_OFFSET, ///< Allow replacing any subset by specifiing an offset. A5BLOCK_INVALID, ///< unknown/not-implemented type }; /** Information about a single action 5 type. */ struct Action5Type { Action5BlockType block_type; ///< How is this Action5 type processed? SpriteID sprite_base; ///< Load the sprites starting from this sprite. uint16 min_sprites; ///< If the Action5 contains less sprites, the whole block will be ignored. uint16 max_sprites; ///< If the Action5 contains more sprites, only the first max_sprites sprites will be used. const char *name; ///< Name for error messages. }; /** The information about action 5 types. */ static const Action5Type _action5_types[] = { /* Note: min_sprites should not be changed. Therefore these constants are directly here and not in sprites.h */ /* 0x00 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x00" }, /* 0x01 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x01" }, /* 0x02 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x02" }, /* 0x03 */ { A5BLOCK_INVALID, 0, 0, 0, "Type 0x03" }, /* 0x04 */ { A5BLOCK_ALLOW_OFFSET, SPR_SIGNALS_BASE, 1, PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT, "Signal graphics" }, /* 0x05 */ { A5BLOCK_ALLOW_OFFSET, SPR_ELRAIL_BASE, 1, ELRAIL_SPRITE_COUNT, "Catenary graphics" }, /* 0x06 */ { A5BLOCK_ALLOW_OFFSET, SPR_SLOPES_BASE, 1, NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT, "Foundation graphics" }, /* 0x07 */ { A5BLOCK_INVALID, 0, 75, 0, "TTDP GUI graphics" }, // Not used by OTTD. /* 0x08 */ { A5BLOCK_ALLOW_OFFSET, SPR_CANALS_BASE, 1, CANALS_SPRITE_COUNT, "Canal graphics" }, /* 0x09 */ { A5BLOCK_ALLOW_OFFSET, SPR_ONEWAY_BASE, 1, ONEWAY_SPRITE_COUNT, "One way road graphics" }, /* 0x0A */ { A5BLOCK_ALLOW_OFFSET, SPR_2CCMAP_BASE, 1, TWOCCMAP_SPRITE_COUNT, "2CC colour maps" }, /* 0x0B */ { A5BLOCK_ALLOW_OFFSET, SPR_TRAMWAY_BASE, 1, TRAMWAY_SPRITE_COUNT, "Tramway graphics" }, /* 0x0C */ { A5BLOCK_INVALID, 0, 133, 0, "Snowy temperate tree" }, // Not yet used by OTTD. /* 0x0D */ { A5BLOCK_FIXED, SPR_SHORE_BASE, 16, SPR_SHORE_SPRITE_COUNT, "Shore graphics" }, /* 0x0E */ { A5BLOCK_INVALID, 0, 0, 0, "New Signals graphics" }, // Not yet used by OTTD. /* 0x0F */ { A5BLOCK_ALLOW_OFFSET, SPR_TRACKS_FOR_SLOPES_BASE, 1, TRACKS_FOR_SLOPES_SPRITE_COUNT, "Sloped rail track" }, /* 0x10 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORTX_BASE, 1, AIRPORTX_SPRITE_COUNT, "Airport graphics" }, /* 0x11 */ { A5BLOCK_ALLOW_OFFSET, SPR_ROADSTOP_BASE, 1, ROADSTOP_SPRITE_COUNT, "Road stop graphics" }, /* 0x12 */ { A5BLOCK_ALLOW_OFFSET, SPR_AQUEDUCT_BASE, 1, AQUEDUCT_SPRITE_COUNT, "Aqueduct graphics" }, /* 0x13 */ { A5BLOCK_ALLOW_OFFSET, SPR_AUTORAIL_BASE, 1, AUTORAIL_SPRITE_COUNT, "Autorail graphics" }, /* 0x14 */ { A5BLOCK_ALLOW_OFFSET, SPR_FLAGS_BASE, 1, FLAGS_SPRITE_COUNT, "Flag graphics" }, /* 0x15 */ { A5BLOCK_ALLOW_OFFSET, SPR_OPENTTD_BASE, 1, OPENTTD_SPRITE_COUNT, "OpenTTD GUI graphics" }, /* 0x16 */ { A5BLOCK_ALLOW_OFFSET, SPR_AIRPORT_PREVIEW_BASE, 1, SPR_AIRPORT_PREVIEW_COUNT, "Airport preview graphics" }, /* 0x17 */ { A5BLOCK_ALLOW_OFFSET, SPR_RAILTYPE_TUNNEL_BASE, 1, RAILTYPE_TUNNEL_BASE_COUNT, "Railtype tunnel base" }, /* 0x18 */ { A5BLOCK_ALLOW_OFFSET, SPR_PALETTE_BASE, 1, PALETTE_SPRITE_COUNT, "Palette" }, }; /* Action 0x05 */ static void GraphicsNew(ByteReader *buf) { /* <05> * * B graphics-type What set of graphics the sprites define. * E num-sprites How many sprites are in this set? * V other data Graphics type specific data. Currently unused. */ /* TODO */ uint8 type = buf->ReadByte(); uint16 num = buf->ReadExtendedByte(); uint16 offset = HasBit(type, 7) ? buf->ReadExtendedByte() : 0; ClrBit(type, 7); // Clear the high bit as that only indicates whether there is an offset. if ((type == 0x0D) && (num == 10) && _cur.grffile->is_ottdfile) { /* Special not-TTDP-compatible case used in openttd.grf * Missing shore sprites and initialisation of SPR_SHORE_BASE */ grfmsg(2, "GraphicsNew: Loading 10 missing shore sprites from extra grf."); LoadNextSprite(SPR_SHORE_BASE + 0, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_STEEP_S LoadNextSprite(SPR_SHORE_BASE + 5, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_STEEP_W LoadNextSprite(SPR_SHORE_BASE + 7, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_WSE LoadNextSprite(SPR_SHORE_BASE + 10, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_STEEP_N LoadNextSprite(SPR_SHORE_BASE + 11, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_NWS LoadNextSprite(SPR_SHORE_BASE + 13, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_ENW LoadNextSprite(SPR_SHORE_BASE + 14, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_SEN LoadNextSprite(SPR_SHORE_BASE + 15, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_STEEP_E LoadNextSprite(SPR_SHORE_BASE + 16, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_EW LoadNextSprite(SPR_SHORE_BASE + 17, _cur.file_index, _cur.nfo_line++, _cur.grf_container_ver); // SLOPE_NS if (_loaded_newgrf_features.shore == SHORE_REPLACE_NONE) _loaded_newgrf_features.shore = SHORE_REPLACE_ONLY_NEW; return; } /* Supported type? */ if ((type >= lengthof(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) { grfmsg(2, "GraphicsNew: Custom graphics (type 0x%02X) sprite block of length %u (unimplemented, ignoring)", type, num); _cur.skip_sprites = num; return; } const Action5Type *action5_type = &_action5_types[type]; /* Contrary to TTDP we allow always to specify too few sprites as we allow always an offset, * except for the long version of the shore type: * Ignore offset if not allowed */ if ((action5_type->block_type != A5BLOCK_ALLOW_OFFSET) && (offset != 0)) { grfmsg(1, "GraphicsNew: %s (type 0x%02X) do not allow an field. Ignoring offset.", action5_type->name, type); offset = 0; } /* Ignore action5 if too few sprites are specified. (for TTDP compatibility) * This does not make sense, if is allowed */ if ((action5_type->block_type == A5BLOCK_FIXED) && (num < action5_type->min_sprites)) { grfmsg(1, "GraphicsNew: %s (type 0x%02X) count must be at least %d. Only %d were specified. Skipping.", action5_type->name, type, action5_type->min_sprites, num); _cur.skip_sprites = num; return; } /* Load at most max_sprites sprites. Skip remaining sprites. (for compatibility with TTDP and future extentions) */ uint16 skip_num = SanitizeSpriteOffset(num, offset, action5_type->max_sprites, action5_type->name); SpriteID replace = action5_type->sprite_base + offset; /* Load sprites starting from , then skip sprites. */ grfmsg(2, "GraphicsNew: Replacing sprites %d to %d of %s (type 0x%02X) at SpriteID 0x%04X", offset, offset + num - 1, action5_type->name, type, replace); for (; num > 0; num--) { _cur.nfo_line++; LoadNextSprite(replace == 0 ? _cur.spriteid++ : replace++, _cur.file_index, _cur.nfo_line, _cur.grf_container_ver); } if (type == 0x0D) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_5; _cur.skip_sprites = skip_num; } /* Action 0x05 (SKIP) */ static void SkipAct5(ByteReader *buf) { /* Ignore type byte */ buf->ReadByte(); /* Skip the sprites of this action */ _cur.skip_sprites = buf->ReadExtendedByte(); grfmsg(3, "SkipAct5: Skipping %d sprites", _cur.skip_sprites); } /** * Check whether we are (obviously) missing some of the extra * (Action 0x05) sprites that we like to use. * When missing sprites are found a warning will be shown. */ void CheckForMissingSprites() { /* Don't break out quickly, but allow to check the other * sprites as well, so we can give the best information. */ bool missing = false; for (uint8 i = 0; i < lengthof(_action5_types); i++) { const Action5Type *type = &_action5_types[i]; if (type->block_type == A5BLOCK_INVALID) continue; for (uint j = 0; j < type->max_sprites; j++) { if (!SpriteExists(type->sprite_base + j)) { DEBUG(grf, 0, "%s sprites are missing", type->name); missing = true; /* No need to log more of the same. */ break; } } } if (missing) { ShowErrorMessage(IsReleasedVersion() ? STR_NEWGRF_ERROR_MISSING_SPRITES : STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE, INVALID_STRING_ID, WL_CRITICAL); } } /** * Reads a variable common to VarAction2 and Action7/9/D. * * Returns VarAction2 variable 'param' resp. Action7/9/D variable '0x80 + param'. * If a variable is not accessible from all four actions, it is handled in the action specific functions. * * @param param variable number (as for VarAction2, for Action7/9/D you have to subtract 0x80 first). * @param value returns the value of the variable. * @param grffile NewGRF querying the variable * @return true iff the variable is known and the value is returned in 'value'. */ bool GetGlobalVariable(byte param, uint32 *value, const GRFFile *grffile) { switch (param) { case 0x00: // current date *value = max(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0); return true; case 0x01: // current year *value = Clamp(_cur_year, ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR) - ORIGINAL_BASE_YEAR; return true; case 0x02: { // detailed date information: month of year (bit 0-7), day of month (bit 8-12), leap year (bit 15), day of year (bit 16-24) YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); Date start_of_year = ConvertYMDToDate(ymd.year, 0, 1); *value = ymd.month | (ymd.day - 1) << 8 | (IsLeapYear(ymd.year) ? 1 << 15 : 0) | (_date - start_of_year) << 16; return true; } case 0x03: // current climate, 0=temp, 1=arctic, 2=trop, 3=toyland *value = _settings_game.game_creation.landscape; return true; case 0x06: // road traffic side, bit 4 clear=left, set=right *value = _settings_game.vehicle.road_side << 4; return true; case 0x09: // date fraction *value = _date_fract * 885; return true; case 0x0A: // animation counter *value = _tick_counter; return true; case 0x0B: { // TTDPatch version uint major = 2; uint minor = 6; uint revision = 1; // special case: 2.0.1 is 2.0.10 uint build = 1382; *value = (major << 24) | (minor << 20) | (revision << 16) | build; return true; } case 0x0D: // TTD Version, 00=DOS, 01=Windows *value = _cur.grfconfig->palette & GRFP_USE_MASK; return true; case 0x0E: // Y-offset for train sprites *value = _cur.grffile->traininfo_vehicle_pitch; return true; case 0x0F: // Rail track type cost factors *value = 0; SB(*value, 0, 8, GetRailTypeInfo(RAILTYPE_RAIL)->cost_multiplier); // normal rail if (_settings_game.vehicle.disable_elrails) { /* skip elrail multiplier - disabled */ SB(*value, 8, 8, GetRailTypeInfo(RAILTYPE_MONO)->cost_multiplier); // monorail } else { SB(*value, 8, 8, GetRailTypeInfo(RAILTYPE_ELECTRIC)->cost_multiplier); // electified railway /* Skip monorail multiplier - no space in result */ } SB(*value, 16, 8, GetRailTypeInfo(RAILTYPE_MAGLEV)->cost_multiplier); // maglev return true; case 0x11: // current rail tool type *value = 0; // constant fake value to avoid desync return true; case 0x12: // Game mode *value = _game_mode; return true; /* case 0x13: // Tile refresh offset to left not implemented */ /* case 0x14: // Tile refresh offset to right not implemented */ /* case 0x15: // Tile refresh offset upwards not implemented */ /* case 0x16: // Tile refresh offset downwards not implemented */ /* case 0x17: // temperate snow line not implemented */ case 0x1A: // Always -1 *value = UINT_MAX; return true; case 0x1B: // Display options *value = 0x3F; // constant fake value to avoid desync return true; case 0x1D: // TTD Platform, 00=TTDPatch, 01=OpenTTD *value = 1; return true; case 0x1E: // Miscellaneous GRF features *value = _misc_grf_features; /* Add the local flags */ assert(!HasBit(*value, GMB_TRAIN_WIDTH_32_PIXELS)); if (_cur.grffile->traininfo_vehicle_width == VEHICLEINFO_FULL_VEHICLE_WIDTH) SetBit(*value, GMB_TRAIN_WIDTH_32_PIXELS); return true; /* case 0x1F: // locale dependent settings not implemented to avoid desync */ case 0x20: { // snow line height byte snowline = GetSnowLine(); if (_settings_game.game_creation.landscape == LT_ARCTIC && snowline <= _settings_game.construction.max_heightlevel) { *value = Clamp(snowline * (grffile->grf_version >= 8 ? 1 : TILE_HEIGHT), 0, 0xFE); } else { /* No snow */ *value = 0xFF; } return true; } case 0x21: // OpenTTD version *value = _openttd_newgrf_version; return true; case 0x22: // difficulty level *value = SP_CUSTOM; return true; case 0x23: // long format date *value = _date; return true; case 0x24: // long format year *value = _cur_year; return true; default: return false; } } static uint32 GetParamVal(byte param, uint32 *cond_val) { /* First handle variable common with VarAction2 */ uint32 value; if (GetGlobalVariable(param - 0x80, &value, _cur.grffile)) return value; /* Non-common variable */ switch (param) { case 0x84: { // GRF loading stage uint32 res = 0; if (_cur.stage > GLS_INIT) SetBit(res, 0); if (_cur.stage == GLS_RESERVE) SetBit(res, 8); if (_cur.stage == GLS_ACTIVATION) SetBit(res, 9); return res; } case 0x85: // TTDPatch flags, only for bit tests if (cond_val == NULL) { /* Supported in Action 0x07 and 0x09, not 0x0D */ return 0; } else { uint32 param_val = _ttdpatch_flags[*cond_val / 0x20]; *cond_val %= 0x20; return param_val; } case 0x88: // GRF ID check return 0; /* case 0x99: Global ID offset not implemented */ default: /* GRF Parameter */ if (param < 0x80) return _cur.grffile->GetParam(param); /* In-game variable. */ grfmsg(1, "Unsupported in-game variable 0x%02X", param); return UINT_MAX; } } /* Action 0x06 */ static void CfgApply(ByteReader *buf) { /* <06> ... * * B param-num Number of parameter to substitute (First = "zero") * Ignored if that parameter was not specified in newgrf.cfg * B param-size How many bytes to replace. If larger than 4, the * bytes of the following parameter are used. In that * case, nothing is applied unless *all* parameters * were specified. * B offset Offset into data from beginning of next sprite * to place where parameter is to be stored. */ /* Preload the next sprite */ size_t pos = FioGetPos(); uint32 num = _cur.grf_container_ver >= 2 ? FioReadDword() : FioReadWord(); uint8 type = FioReadByte(); byte *preload_sprite = NULL; /* Check if the sprite is a pseudo sprite. We can't operate on real sprites. */ if (type == 0xFF) { preload_sprite = MallocT(num); FioReadBlock(preload_sprite, num); } /* Reset the file position to the start of the next sprite */ FioSeekTo(pos, SEEK_SET); if (type != 0xFF) { grfmsg(2, "CfgApply: Ignoring (next sprite is real, unsupported)"); free(preload_sprite); return; } GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line + 1); GRFLineToSpriteOverride::iterator it = _grf_line_to_action6_sprite_override.find(location); if (it != _grf_line_to_action6_sprite_override.end()) { free(preload_sprite); preload_sprite = _grf_line_to_action6_sprite_override[location]; } else { _grf_line_to_action6_sprite_override[location] = preload_sprite; } /* Now perform the Action 0x06 on our data. */ for (;;) { uint i; uint param_num; uint param_size; uint offset; bool add_value; /* Read the parameter to apply. 0xFF indicates no more data to change. */ param_num = buf->ReadByte(); if (param_num == 0xFF) break; /* Get the size of the parameter to use. If the size covers multiple * double words, sequential parameter values are used. */ param_size = buf->ReadByte(); /* Bit 7 of param_size indicates we should add to the original value * instead of replacing it. */ add_value = HasBit(param_size, 7); param_size = GB(param_size, 0, 7); /* Where to apply the data to within the pseudo sprite data. */ offset = buf->ReadExtendedByte(); /* If the parameter is a GRF parameter (not an internal variable) check * if it (and all further sequential parameters) has been defined. */ if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= _cur.grffile->param_end) { grfmsg(2, "CfgApply: Ignoring (param %d not set)", (param_num + (param_size - 1) / 4)); break; } grfmsg(8, "CfgApply: Applying %u bytes from parameter 0x%02X at offset 0x%04X", param_size, param_num, offset); bool carry = false; for (i = 0; i < param_size && offset + i < num; i++) { uint32 value = GetParamVal(param_num + i / 4, NULL); /* Reset carry flag for each iteration of the variable (only really * matters if param_size is greater than 4) */ if (i % 4 == 0) carry = false; if (add_value) { uint new_value = preload_sprite[offset + i] + GB(value, (i % 4) * 8, 8) + (carry ? 1 : 0); preload_sprite[offset + i] = GB(new_value, 0, 8); /* Check if the addition overflowed */ carry = new_value >= 256; } else { preload_sprite[offset + i] = GB(value, (i % 4) * 8, 8); } } } } /** * Disable a static NewGRF when it is influencing another (non-static) * NewGRF as this could cause desyncs. * * We could just tell the NewGRF querying that the file doesn't exist, * but that might give unwanted results. Disabling the NewGRF gives the * best result as no NewGRF author can complain about that. * @param c The NewGRF to disable. */ static void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig *c) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC, c); error->data = stredup(_cur.grfconfig->GetName()); } /* Action 0x07 * Action 0x09 */ static void SkipIf(ByteReader *buf) { /* <07/09> * * B param-num * B param-size * B condition-type * V value * B num-sprites */ /* TODO: More params. More condition types. */ uint32 cond_val = 0; uint32 mask = 0; bool result; uint8 param = buf->ReadByte(); uint8 paramsize = buf->ReadByte(); uint8 condtype = buf->ReadByte(); if (condtype < 2) { /* Always 1 for bit tests, the given value should be ignored. */ paramsize = 1; } switch (paramsize) { case 8: cond_val = buf->ReadDWord(); mask = buf->ReadDWord(); break; case 4: cond_val = buf->ReadDWord(); mask = 0xFFFFFFFF; break; case 2: cond_val = buf->ReadWord(); mask = 0x0000FFFF; break; case 1: cond_val = buf->ReadByte(); mask = 0x000000FF; break; default: break; } if (param < 0x80 && _cur.grffile->param_end <= param) { grfmsg(7, "SkipIf: Param %d undefined, skipping test", param); return; } uint32 param_val = GetParamVal(param, &cond_val); grfmsg(7, "SkipIf: Test condtype %d, param 0x%08X, condval 0x%08X", condtype, param_val, cond_val); /* * Parameter (variable in specs) 0x88 can only have GRF ID checking * conditions, except conditions 0x0B, 0x0C (cargo availability) and * 0x0D, 0x0E (Rail type availability) as those ignore the parameter. * So, when the condition type is one of those, the specific variable * 0x88 code is skipped, so the "general" code for the cargo * availability conditions kicks in. */ if (param == 0x88 && (condtype < 0x0B || condtype > 0x0E)) { /* GRF ID checks */ GRFConfig *c = GetGRFConfig(cond_val, mask); if (c != NULL && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) { DisableStaticNewGRFInfluencingNonStaticNewGRFs(c); c = NULL; } if (condtype != 10 && c == NULL) { grfmsg(7, "SkipIf: GRFID 0x%08X unknown, skipping test", BSWAP32(cond_val)); return; } switch (condtype) { /* Tests 0x06 to 0x0A are only for param 0x88, GRFID checks */ case 0x06: // Is GRFID active? result = c->status == GCS_ACTIVATED; break; case 0x07: // Is GRFID non-active? result = c->status != GCS_ACTIVATED; break; case 0x08: // GRFID is not but will be active? result = c->status == GCS_INITIALISED; break; case 0x09: // GRFID is or will be active? result = c->status == GCS_ACTIVATED || c->status == GCS_INITIALISED; break; case 0x0A: // GRFID is not nor will be active /* This is the only condtype that doesn't get ignored if the GRFID is not found */ result = c == NULL || c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND; break; default: grfmsg(1, "SkipIf: Unsupported GRF condition type %02X. Ignoring", condtype); return; } } else { /* Parameter or variable tests */ switch (condtype) { case 0x00: result = !!(param_val & (1 << cond_val)); break; case 0x01: result = !(param_val & (1 << cond_val)); break; case 0x02: result = (param_val & mask) == cond_val; break; case 0x03: result = (param_val & mask) != cond_val; break; case 0x04: result = (param_val & mask) < cond_val; break; case 0x05: result = (param_val & mask) > cond_val; break; case 0x0B: result = GetCargoIDByLabel(BSWAP32(cond_val)) == CT_INVALID; break; case 0x0C: result = GetCargoIDByLabel(BSWAP32(cond_val)) != CT_INVALID; break; case 0x0D: result = GetRailTypeByLabel(BSWAP32(cond_val)) == INVALID_RAILTYPE; break; case 0x0E: result = GetRailTypeByLabel(BSWAP32(cond_val)) != INVALID_RAILTYPE; break; default: grfmsg(1, "SkipIf: Unsupported condition type %02X. Ignoring", condtype); return; } } if (!result) { grfmsg(2, "SkipIf: Not skipping sprites, test was false"); return; } uint8 numsprites = buf->ReadByte(); /* numsprites can be a GOTO label if it has been defined in the GRF * file. The jump will always be the first matching label that follows * the current nfo_line. If no matching label is found, the first matching * label in the file is used. */ GRFLabel *choice = NULL; for (GRFLabel *label = _cur.grffile->label; label != NULL; label = label->next) { if (label->label != numsprites) continue; /* Remember a goto before the current line */ if (choice == NULL) choice = label; /* If we find a label here, this is definitely good */ if (label->nfo_line > _cur.nfo_line) { choice = label; break; } } if (choice != NULL) { grfmsg(2, "SkipIf: Jumping to label 0x%0X at line %d, test was true", choice->label, choice->nfo_line); FioSeekTo(choice->pos, SEEK_SET); _cur.nfo_line = choice->nfo_line; return; } grfmsg(2, "SkipIf: Skipping %d sprites, test was true", numsprites); _cur.skip_sprites = numsprites; if (_cur.skip_sprites == 0) { /* Zero means there are no sprites to skip, so * we use -1 to indicate that all further * sprites should be skipped. */ _cur.skip_sprites = -1; /* If an action 8 hasn't been encountered yet, disable the grf. */ if (_cur.grfconfig->status != (_cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED)) { DisableGrf(); } } } /* Action 0x08 (GLS_FILESCAN) */ static void ScanInfo(ByteReader *buf) { uint8 grf_version = buf->ReadByte(); uint32 grfid = buf->ReadDWord(); const char *name = buf->ReadString(); _cur.grfconfig->ident.grfid = grfid; if (grf_version < 2 || grf_version > 8) { SetBit(_cur.grfconfig->flags, GCF_INVALID); DEBUG(grf, 0, "%s: NewGRF \"%s\" (GRFID %08X) uses GRF version %d, which is incompatible with this version of OpenTTD.", _cur.grfconfig->filename, name, BSWAP32(grfid), grf_version); } /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ if (GB(grfid, 24, 8) == 0xFF) SetBit(_cur.grfconfig->flags, GCF_SYSTEM); AddGRFTextToList(&_cur.grfconfig->name->text, 0x7F, grfid, false, name); if (buf->HasData()) { const char *info = buf->ReadString(); AddGRFTextToList(&_cur.grfconfig->info->text, 0x7F, grfid, true, info); } /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */ _cur.skip_sprites = -1; } /* Action 0x08 */ static void GRFInfo(ByteReader *buf) { /* <08> * * B version newgrf version, currently 06 * 4*B grf-id globally unique ID of this .grf file * S name name of this .grf set * S info string describing the set, and e.g. author and copyright */ uint8 version = buf->ReadByte(); uint32 grfid = buf->ReadDWord(); const char *name = buf->ReadString(); if (_cur.stage < GLS_RESERVE && _cur.grfconfig->status != GCS_UNKNOWN) { DisableGrf(STR_NEWGRF_ERROR_MULTIPLE_ACTION_8); return; } if (_cur.grffile->grfid != grfid) { DEBUG(grf, 0, "GRFInfo: GRFID %08X in FILESCAN stage does not match GRFID %08X in INIT/RESERVE/ACTIVATION stage", BSWAP32(_cur.grffile->grfid), BSWAP32(grfid)); _cur.grffile->grfid = grfid; } _cur.grffile->grf_version = version; _cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED; /* Do swap the GRFID for displaying purposes since people expect that */ DEBUG(grf, 1, "GRFInfo: Loaded GRFv%d set %08X - %s (palette: %s, version: %i)", version, BSWAP32(grfid), name, (_cur.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur.grfconfig->version); } /* Action 0x0A */ static void SpriteReplace(ByteReader *buf) { /* <0A> [ ...] * : * * B num-sets How many sets of sprites to replace. * Each set: * B num-sprites How many sprites are in this set * W first-sprite First sprite number to replace */ uint8 num_sets = buf->ReadByte(); for (uint i = 0; i < num_sets; i++) { uint8 num_sprites = buf->ReadByte(); uint16 first_sprite = buf->ReadWord(); grfmsg(2, "SpriteReplace: [Set %d] Changing %d sprites, beginning with %d", i, num_sprites, first_sprite ); for (uint j = 0; j < num_sprites; j++) { int load_index = first_sprite + j; _cur.nfo_line++; LoadNextSprite(load_index, _cur.file_index, _cur.nfo_line, _cur.grf_container_ver); // XXX /* Shore sprites now located at different addresses. * So detect when the old ones get replaced. */ if (IsInsideMM(load_index, SPR_ORIGINALSHORE_START, SPR_ORIGINALSHORE_END + 1)) { if (_loaded_newgrf_features.shore != SHORE_REPLACE_ACTION_5) _loaded_newgrf_features.shore = SHORE_REPLACE_ACTION_A; } } } } /* Action 0x0A (SKIP) */ static void SkipActA(ByteReader *buf) { uint8 num_sets = buf->ReadByte(); for (uint i = 0; i < num_sets; i++) { /* Skip the sprites this replaces */ _cur.skip_sprites += buf->ReadByte(); /* But ignore where they go */ buf->ReadWord(); } grfmsg(3, "SkipActA: Skipping %d sprites", _cur.skip_sprites); } /* Action 0x0B */ static void GRFLoadError(ByteReader *buf) { /* <0B> [ 00] [] 00 [] * * B severity 00: notice, contine loading grf file * 01: warning, continue loading grf file * 02: error, but continue loading grf file, and attempt * loading grf again when loading or starting next game * 03: error, abort loading and prevent loading again in * the future (only when restarting the patch) * B language-id see action 4, use 1F for built-in error messages * B message-id message to show, see below * S message for custom messages (message-id FF), text of the message * not present for built-in messages. * V data additional data for built-in (or custom) messages * B parnum parameter numbers to be shown in the message (maximum of 2) */ static const StringID msgstr[] = { STR_NEWGRF_ERROR_VERSION_NUMBER, STR_NEWGRF_ERROR_DOS_OR_WINDOWS, STR_NEWGRF_ERROR_UNSET_SWITCH, STR_NEWGRF_ERROR_INVALID_PARAMETER, STR_NEWGRF_ERROR_LOAD_BEFORE, STR_NEWGRF_ERROR_LOAD_AFTER, STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER, }; static const StringID sevstr[] = { STR_NEWGRF_ERROR_MSG_INFO, STR_NEWGRF_ERROR_MSG_WARNING, STR_NEWGRF_ERROR_MSG_ERROR, STR_NEWGRF_ERROR_MSG_FATAL }; byte severity = buf->ReadByte(); byte lang = buf->ReadByte(); byte message_id = buf->ReadByte(); /* Skip the error if it isn't valid for the current language. */ if (!CheckGrfLangID(lang, _cur.grffile->grf_version)) return; /* Skip the error until the activation stage unless bit 7 of the severity * is set. */ if (!HasBit(severity, 7) && _cur.stage == GLS_INIT) { grfmsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage %d", _cur.stage); return; } ClrBit(severity, 7); if (severity >= lengthof(sevstr)) { grfmsg(7, "GRFLoadError: Invalid severity id %d. Setting to 2 (non-fatal error).", severity); severity = 2; } else if (severity == 3) { /* This is a fatal error, so make sure the GRF is deactivated and no * more of it gets loaded. */ DisableGrf(); /* Make sure we show fatal errors, instead of silly infos from before */ delete _cur.grfconfig->error; _cur.grfconfig->error = NULL; } if (message_id >= lengthof(msgstr) && message_id != 0xFF) { grfmsg(7, "GRFLoadError: Invalid message id."); return; } if (buf->Remaining() <= 1) { grfmsg(7, "GRFLoadError: No message data supplied."); return; } /* For now we can only show one message per newgrf file. */ if (_cur.grfconfig->error != NULL) return; GRFError *error = new GRFError(sevstr[severity]); if (message_id == 0xFF) { /* This is a custom error message. */ if (buf->HasData()) { const char *message = buf->ReadString(); error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, NULL, SCC_RAW_STRING_POINTER); } else { grfmsg(7, "GRFLoadError: No custom message supplied."); error->custom_message = stredup(""); } } else { error->message = msgstr[message_id]; } if (buf->HasData()) { const char *data = buf->ReadString(); error->data = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, data); } else { grfmsg(7, "GRFLoadError: No message data supplied."); error->data = stredup(""); } /* Only two parameter numbers can be used in the string. */ for (uint i = 0; i < lengthof(error->param_value) && buf->HasData(); i++) { uint param_number = buf->ReadByte(); error->param_value[i] = _cur.grffile->GetParam(param_number); } _cur.grfconfig->error = error; } /* Action 0x0C */ static void GRFComment(ByteReader *buf) { /* <0C> [] * * V ignored Anything following the 0C is ignored */ if (!buf->HasData()) return; const char *text = buf->ReadString(); grfmsg(2, "GRFComment: %s", text); } /* Action 0x0D (GLS_SAFETYSCAN) */ static void SafeParamSet(ByteReader *buf) { uint8 target = buf->ReadByte(); /* Only writing GRF parameters is considered safe */ if (target < 0x80) return; /* GRM could be unsafe, but as here it can only happen after other GRFs * are loaded, it should be okay. If the GRF tried to use the slots it * reserved, it would be marked unsafe anyway. GRM for (e.g. bridge) * sprites is considered safe. */ SetBit(_cur.grfconfig->flags, GCF_UNSAFE); /* Skip remainder of GRF */ _cur.skip_sprites = -1; } static uint32 GetPatchVariable(uint8 param) { switch (param) { /* start year - 1920 */ case 0x0B: return max(_settings_game.game_creation.starting_year, ORIGINAL_BASE_YEAR) - ORIGINAL_BASE_YEAR; /* freight trains weight factor */ case 0x0E: return _settings_game.vehicle.freight_trains; /* empty wagon speed increase */ case 0x0F: return 0; /* plane speed factor; our patch option is reversed from TTDPatch's, * the following is good for 1x, 2x and 4x (most common?) and... * well not really for 3x. */ case 0x10: switch (_settings_game.vehicle.plane_speed) { default: case 4: return 1; case 3: return 2; case 2: return 2; case 1: return 4; } /* 2CC colourmap base sprite */ case 0x11: return SPR_2CCMAP_BASE; /* map size: format = -MABXYSS * M : the type of map * bit 0 : set : squared map. Bit 1 is now not relevant * clear : rectangle map. Bit 1 will indicate the bigger edge of the map * bit 1 : set : Y is the bigger edge. Bit 0 is clear * clear : X is the bigger edge. * A : minimum edge(log2) of the map * B : maximum edge(log2) of the map * XY : edges(log2) of each side of the map. * SS : combination of both X and Y, thus giving the size(log2) of the map */ case 0x13: { byte map_bits = 0; byte log_X = MapLogX() - 6; // substraction is required to make the minimal size (64) zero based byte log_Y = MapLogY() - 6; byte max_edge = max(log_X, log_Y); if (log_X == log_Y) { // we have a squared map, since both edges are identical SetBit(map_bits, 0); } else { if (max_edge == log_Y) SetBit(map_bits, 1); // edge Y been the biggest, mark it } return (map_bits << 24) | (min(log_X, log_Y) << 20) | (max_edge << 16) | (log_X << 12) | (log_Y << 8) | (log_X + log_Y); } /* The maximum height of the map. */ case 0x14: return _settings_game.construction.max_heightlevel; /* Extra foundations base sprite */ case 0x15: return SPR_SLOPES_BASE; /* Shore base sprite */ case 0x16: return SPR_SHORE_BASE; default: grfmsg(2, "ParamSet: Unknown Patch variable 0x%02X.", param); return 0; } } static uint32 PerformGRM(uint32 *grm, uint16 num_ids, uint16 count, uint8 op, uint8 target, const char *type) { uint start = 0; uint size = 0; if (op == 6) { /* Return GRFID of set that reserved ID */ return grm[_cur.grffile->GetParam(target)]; } /* With an operation of 2 or 3, we want to reserve a specific block of IDs */ if (op == 2 || op == 3) start = _cur.grffile->GetParam(target); for (uint i = start; i < num_ids; i++) { if (grm[i] == 0) { size++; } else { if (op == 2 || op == 3) break; start = i + 1; size = 0; } if (size == count) break; } if (size == count) { /* Got the slot... */ if (op == 0 || op == 3) { grfmsg(2, "ParamSet: GRM: Reserving %d %s at %d", count, type, start); for (uint i = 0; i < count; i++) grm[start + i] = _cur.grffile->grfid; } return start; } /* Unable to allocate */ if (op != 4 && op != 5) { /* Deactivate GRF */ grfmsg(0, "ParamSet: GRM: Unable to allocate %d %s, deactivating", count, type); DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED); return UINT_MAX; } grfmsg(1, "ParamSet: GRM: Unable to allocate %d %s", count, type); return UINT_MAX; } /** Action 0x0D: Set parameter */ static void ParamSet(ByteReader *buf) { /* <0D> [] * * B target parameter number where result is stored * B operation operation to perform, see below * B source1 first source operand * B source2 second source operand * D data data to use in the calculation, not necessary * if both source1 and source2 refer to actual parameters * * Operations * 00 Set parameter equal to source1 * 01 Addition, source1 + source2 * 02 Subtraction, source1 - source2 * 03 Unsigned multiplication, source1 * source2 (both unsigned) * 04 Signed multiplication, source1 * source2 (both signed) * 05 Unsigned bit shift, source1 by source2 (source2 taken to be a * signed quantity; left shift if positive and right shift if * negative, source1 is unsigned) * 06 Signed bit shift, source1 by source2 * (source2 like in 05, and source1 as well) */ uint8 target = buf->ReadByte(); uint8 oper = buf->ReadByte(); uint32 src1 = buf->ReadByte(); uint32 src2 = buf->ReadByte(); uint32 data = 0; if (buf->Remaining() >= 4) data = buf->ReadDWord(); /* You can add 80 to the operation to make it apply only if the target * is not defined yet. In this respect, a parameter is taken to be * defined if any of the following applies: * - it has been set to any value in the newgrf(w).cfg parameter list * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by * an earlier action D */ if (HasBit(oper, 7)) { if (target < 0x80 && target < _cur.grffile->param_end) { grfmsg(7, "ParamSet: Param %u already defined, skipping", target); return; } oper = GB(oper, 0, 7); } if (src2 == 0xFE) { if (GB(data, 0, 8) == 0xFF) { if (data == 0x0000FFFF) { /* Patch variables */ src1 = GetPatchVariable(src1); } else { /* GRF Resource Management */ uint8 op = src1; uint8 feature = GB(data, 8, 8); uint16 count = GB(data, 16, 16); if (_cur.stage == GLS_RESERVE) { if (feature == 0x08) { /* General sprites */ if (op == 0) { /* Check if the allocated sprites will fit below the original sprite limit */ if (_cur.spriteid + count >= 16384) { grfmsg(0, "ParamSet: GRM: Unable to allocate %d sprites; try changing NewGRF order", count); DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED); return; } /* Reserve space at the current sprite ID */ grfmsg(4, "ParamSet: GRM: Allocated %d sprites at %d", count, _cur.spriteid); _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)] = _cur.spriteid; _cur.spriteid += count; } } /* Ignore GRM result during reservation */ src1 = 0; } else if (_cur.stage == GLS_ACTIVATION) { switch (feature) { case 0x00: // Trains case 0x01: // Road Vehicles case 0x02: // Ships case 0x03: // Aircraft if (!_settings_game.vehicle.dynamic_engines) { src1 = PerformGRM(&_grm_engines[_engine_offsets[feature]], _engine_counts[feature], count, op, target, "vehicles"); if (_cur.skip_sprites == -1) return; } else { /* GRM does not apply for dynamic engine allocation. */ switch (op) { case 2: case 3: src1 = _cur.grffile->GetParam(target); break; default: src1 = 0; break; } } break; case 0x08: // General sprites switch (op) { case 0: /* Return space reserved during reservation stage */ src1 = _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)]; grfmsg(4, "ParamSet: GRM: Using pre-allocated sprites at %d", src1); break; case 1: src1 = _cur.spriteid; break; default: grfmsg(1, "ParamSet: GRM: Unsupported operation %d for general sprites", op); return; } break; case 0x0B: // Cargo /* There are two ranges: one for cargo IDs and one for cargo bitmasks */ src1 = PerformGRM(_grm_cargoes, NUM_CARGO * 2, count, op, target, "cargoes"); if (_cur.skip_sprites == -1) return; break; default: grfmsg(1, "ParamSet: GRM: Unsupported feature 0x%X", feature); return; } } else { /* Ignore GRM during initialization */ src1 = 0; } } } else { /* Read another GRF File's parameter */ const GRFFile *file = GetFileByGRFID(data); GRFConfig *c = GetGRFConfig(data); if (c != NULL && HasBit(c->flags, GCF_STATIC) && !HasBit(_cur.grfconfig->flags, GCF_STATIC) && _networking) { /* Disable the read GRF if it is a static NewGRF. */ DisableStaticNewGRFInfluencingNonStaticNewGRFs(c); src1 = 0; } else if (file == NULL || c == NULL || c->status == GCS_DISABLED) { src1 = 0; } else if (src1 == 0xFE) { src1 = c->version; } else { src1 = file->GetParam(src1); } } } else { /* The source1 and source2 operands refer to the grf parameter number * like in action 6 and 7. In addition, they can refer to the special * variables available in action 7, or they can be FF to use the value * of . If referring to parameters that are undefined, a value * of 0 is used instead. */ src1 = (src1 == 0xFF) ? data : GetParamVal(src1, NULL); src2 = (src2 == 0xFF) ? data : GetParamVal(src2, NULL); } /* TODO: You can access the parameters of another GRF file by using * source2=FE, source1=the other GRF's parameter number and data=GRF * ID. This is only valid with operation 00 (set). If the GRF ID * cannot be found, a value of 0 is used for the parameter value * instead. */ uint32 res; switch (oper) { case 0x00: res = src1; break; case 0x01: res = src1 + src2; break; case 0x02: res = src1 - src2; break; case 0x03: res = src1 * src2; break; case 0x04: res = (int32)src1 * (int32)src2; break; case 0x05: if ((int32)src2 < 0) { res = src1 >> -(int32)src2; } else { res = src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures. } break; case 0x06: if ((int32)src2 < 0) { res = (int32)src1 >> -(int32)src2; } else { res = (int32)src1 << (src2 & 0x1F); // Same behaviour as in EvalAdjustT, mask 'value' to 5 bits, which should behave the same on all architectures. } break; case 0x07: // Bitwise AND res = src1 & src2; break; case 0x08: // Bitwise OR res = src1 | src2; break; case 0x09: // Unsigned division if (src2 == 0) { res = src1; } else { res = src1 / src2; } break; case 0x0A: // Signed divison if (src2 == 0) { res = src1; } else { res = (int32)src1 / (int32)src2; } break; case 0x0B: // Unsigned modulo if (src2 == 0) { res = src1; } else { res = src1 % src2; } break; case 0x0C: // Signed modulo if (src2 == 0) { res = src1; } else { res = (int32)src1 % (int32)src2; } break; default: grfmsg(0, "ParamSet: Unknown operation %d, skipping", oper); return; } switch (target) { case 0x8E: // Y-Offset for train sprites _cur.grffile->traininfo_vehicle_pitch = res; break; case 0x8F: { // Rail track type cost factors extern RailtypeInfo _railtypes[RAILTYPE_END]; _railtypes[RAILTYPE_RAIL].cost_multiplier = GB(res, 0, 8); if (_settings_game.vehicle.disable_elrails) { _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 0, 8); _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 8, 8); } else { _railtypes[RAILTYPE_ELECTRIC].cost_multiplier = GB(res, 8, 8); _railtypes[RAILTYPE_MONO].cost_multiplier = GB(res, 16, 8); } _railtypes[RAILTYPE_MAGLEV].cost_multiplier = GB(res, 16, 8); break; } /* @todo implement */ case 0x93: // Tile refresh offset to left case 0x94: // Tile refresh offset to right case 0x95: // Tile refresh offset upwards case 0x96: // Tile refresh offset downwards case 0x97: // Snow line height case 0x99: // Global ID offset grfmsg(7, "ParamSet: Skipping unimplemented target 0x%02X", target); break; case 0x9E: // Miscellaneous GRF features /* Set train list engine width */ _cur.grffile->traininfo_vehicle_width = HasBit(res, GMB_TRAIN_WIDTH_32_PIXELS) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH; /* Remove the local flags from the global flags */ ClrBit(res, GMB_TRAIN_WIDTH_32_PIXELS); _misc_grf_features = res; break; case 0x9F: // locale-dependent settings grfmsg(7, "ParamSet: Skipping unimplemented target 0x%02X", target); break; default: if (target < 0x80) { _cur.grffile->param[target] = res; /* param is zeroed by default */ if (target + 1U > _cur.grffile->param_end) _cur.grffile->param_end = target + 1; } else { grfmsg(7, "ParamSet: Skipping unknown target 0x%02X", target); } break; } } /* Action 0x0E (GLS_SAFETYSCAN) */ static void SafeGRFInhibit(ByteReader *buf) { /* <0E> * * B num Number of GRFIDs that follow * D grfids GRFIDs of the files to deactivate */ uint8 num = buf->ReadByte(); for (uint i = 0; i < num; i++) { uint32 grfid = buf->ReadDWord(); /* GRF is unsafe it if tries to deactivate other GRFs */ if (grfid != _cur.grfconfig->ident.grfid) { SetBit(_cur.grfconfig->flags, GCF_UNSAFE); /* Skip remainder of GRF */ _cur.skip_sprites = -1; return; } } } /* Action 0x0E */ static void GRFInhibit(ByteReader *buf) { /* <0E> * * B num Number of GRFIDs that follow * D grfids GRFIDs of the files to deactivate */ uint8 num = buf->ReadByte(); for (uint i = 0; i < num; i++) { uint32 grfid = buf->ReadDWord(); GRFConfig *file = GetGRFConfig(grfid); /* Unset activation flag */ if (file != NULL && file != _cur.grfconfig) { grfmsg(2, "GRFInhibit: Deactivating file '%s'", file->filename); GRFError *error = DisableGrf(STR_NEWGRF_ERROR_FORCEFULLY_DISABLED, file); error->data = stredup(_cur.grfconfig->GetName()); } } } /** Action 0x0F - Define Town names */ static void FeatureTownName(ByteReader *buf) { /* <0F> * * B id ID of this definition in bottom 7 bits (final definition if bit 7 set) * V style-name Name of the style (only for final definition) * B num-parts Number of parts in this definition * V parts The parts */ uint32 grfid = _cur.grffile->grfid; GRFTownName *townname = AddGRFTownName(grfid); byte id = buf->ReadByte(); grfmsg(6, "FeatureTownName: definition 0x%02X", id & 0x7F); if (HasBit(id, 7)) { /* Final definition */ ClrBit(id, 7); bool new_scheme = _cur.grffile->grf_version >= 7; byte lang = buf->ReadByte(); byte nb_gen = townname->nb_gen; do { ClrBit(lang, 7); const char *name = buf->ReadString(); char *lang_name = TranslateTTDPatchCodes(grfid, lang, false, name); grfmsg(6, "FeatureTownName: lang 0x%X -> '%s'", lang, lang_name); free(lang_name); townname->name[nb_gen] = AddGRFString(grfid, id, lang, new_scheme, false, name, STR_UNDEFINED); lang = buf->ReadByte(); } while (lang != 0); townname->id[nb_gen] = id; townname->nb_gen++; } byte nb = buf->ReadByte(); grfmsg(6, "FeatureTownName: %u parts", nb); townname->nbparts[id] = nb; townname->partlist[id] = CallocT(nb); for (int i = 0; i < nb; i++) { byte nbtext = buf->ReadByte(); townname->partlist[id][i].bitstart = buf->ReadByte(); townname->partlist[id][i].bitcount = buf->ReadByte(); townname->partlist[id][i].maxprob = 0; townname->partlist[id][i].partcount = nbtext; townname->partlist[id][i].parts = CallocT(nbtext); grfmsg(6, "FeatureTownName: part %d contains %d texts and will use GB(seed, %d, %d)", i, nbtext, townname->partlist[id][i].bitstart, townname->partlist[id][i].bitcount); for (int j = 0; j < nbtext; j++) { byte prob = buf->ReadByte(); if (HasBit(prob, 7)) { byte ref_id = buf->ReadByte(); if (townname->nbparts[ref_id] == 0) { grfmsg(0, "FeatureTownName: definition 0x%02X doesn't exist, deactivating", ref_id); DelGRFTownName(grfid); DisableGrf(STR_NEWGRF_ERROR_INVALID_ID); return; } grfmsg(6, "FeatureTownName: part %d, text %d, uses intermediate definition 0x%02X (with probability %d)", i, j, ref_id, prob & 0x7F); townname->partlist[id][i].parts[j].data.id = ref_id; } else { const char *text = buf->ReadString(); townname->partlist[id][i].parts[j].data.text = TranslateTTDPatchCodes(grfid, 0, false, text); grfmsg(6, "FeatureTownName: part %d, text %d, '%s' (with probability %d)", i, j, townname->partlist[id][i].parts[j].data.text, prob); } townname->partlist[id][i].parts[j].prob = prob; townname->partlist[id][i].maxprob += GB(prob, 0, 7); } grfmsg(6, "FeatureTownName: part %d, total probability %d", i, townname->partlist[id][i].maxprob); } } /** Action 0x10 - Define goto label */ static void DefineGotoLabel(ByteReader *buf) { /* <10>
//main.nut. */ *strrchr(path, PATHSEPCHAR) = '\0'; checksum.Scan(".nut", path); } return memcmp(ci->md5sum, checksum.md5sum, sizeof(ci->md5sum)) == 0; } bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum) { for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) { if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return true; } return false; } const char *ScriptScanner::FindMainScript(const ContentInfo *ci, bool md5sum) { for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) { if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return (*it).second->GetMainScript(); } return NULL; } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/script/squirrel_std.cpp0000644000000000000000000000622712627373433017233 0ustar rootroot/* $Id: squirrel_std.cpp 26782 2014-09-06 20:22:59Z rubidium $ */ /* * 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 squirrel_std.cpp Implements the Squirrel Standard Function class */ #include "../stdafx.h" #include #include #include "../debug.h" #include "squirrel_std.hpp" #include "../core/alloc_func.hpp" #include "../core/math_func.hpp" #include "../string_func.h" #include "../safeguards.h" SQInteger SquirrelStd::min(HSQUIRRELVM vm) { SQInteger tmp1, tmp2; sq_getinteger(vm, 2, &tmp1); sq_getinteger(vm, 3, &tmp2); sq_pushinteger(vm, ::min(tmp1, tmp2)); return 1; } SQInteger SquirrelStd::max(HSQUIRRELVM vm) { SQInteger tmp1, tmp2; sq_getinteger(vm, 2, &tmp1); sq_getinteger(vm, 3, &tmp2); sq_pushinteger(vm, ::max(tmp1, tmp2)); return 1; } SQInteger SquirrelStd::require(HSQUIRRELVM vm) { SQInteger top = sq_gettop(vm); const SQChar *filename; sq_getstring(vm, 2, &filename); /* Get the script-name of the current file, so we can work relative from it */ SQStackInfos si; sq_stackinfos(vm, 1, &si); if (si.source == NULL) { DEBUG(misc, 0, "[squirrel] Couldn't detect the script-name of the 'require'-caller; this should never happen!"); return SQ_ERROR; } char path[MAX_PATH]; strecpy(path, si.source, lastof(path)); /* Keep the dir, remove the rest */ SQChar *s = strrchr(path, PATHSEPCHAR); if (s != NULL) { /* Keep the PATHSEPCHAR there, remove the rest */ s++; *s = '\0'; } strecat(path, filename, lastof(path)); #if (PATHSEPCHAR != '/') for (char *n = path; *n != '\0'; n++) if (*n == '/') *n = PATHSEPCHAR; #endif Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); bool ret = engine->LoadScript(vm, path); /* Reset the top, so the stack stays correct */ sq_settop(vm, top); return ret ? 0 : SQ_ERROR; } SQInteger SquirrelStd::notifyallexceptions(HSQUIRRELVM vm) { SQBool b; if (sq_gettop(vm) >= 1) { if (SQ_SUCCEEDED(sq_getbool(vm, -1, &b))) { sq_notifyallexceptions(vm, b); return 0; } } return SQ_ERROR; } void squirrel_register_global_std(Squirrel *engine) { /* We don't use squirrel_helper here, as we want to register to the global * scope and not to a class. */ engine->AddMethod("require", &SquirrelStd::require, 2, ".s"); engine->AddMethod("notifyallexceptions", &SquirrelStd::notifyallexceptions, 2, ".b"); } void squirrel_register_std(Squirrel *engine) { /* We don't use squirrel_helper here, as we want to register to the global * scope and not to a class. */ engine->AddMethod("min", &SquirrelStd::min, 3, ".ii"); engine->AddMethod("max", &SquirrelStd::max, 3, ".ii"); sqstd_register_mathlib(engine->GetVM()); } openttd-1.5.3/src/script/script_fatalerror.hpp0000644000000000000000000000242712627373434020244 0ustar rootroot/* $Id: script_fatalerror.hpp 23378 2011-11-30 14:02:15Z truebrain $ */ /* * 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 script_fatalerror.hpp The definition of Script_FatalError. */ #ifndef SCRIPT_FATALERROR_HPP #define SCRIPT_FATALERROR_HPP /** * A throw-class that is given when the script made a fatal error. */ class Script_FatalError { public: /** * Creates a "fatal error" exception. * @param msg The message describing the cause of the fatal error. */ Script_FatalError(const char *msg) : msg(msg) {} /** * The error message associated with the fatal error. * @return The error message. */ const char *GetErrorMessage() { return msg; } private: const char *msg; ///< The error message. }; #endif /* SCRIPT_FATALERROR_HPP */ openttd-1.5.3/src/script/squirrel_std.hpp0000644000000000000000000000425612627373433017240 0ustar rootroot/* $Id: squirrel_std.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 squirrel_std.hpp defines the Squirrel Standard Function class */ #ifndef SQUIRREL_STD_HPP #define SQUIRREL_STD_HPP #include "squirrel.hpp" #if defined(__APPLE__) /* Which idiotic system makes 'require' a macro? :s Oh well.... */ #undef require #endif /* __APPLE__ */ /** * By default we want to give a set of standard commands to a SQ script. * Most of them are easy wrappers around internal functions. Of course we * could just as easy include things like the stdmath of SQ, but of those * functions we are sure they work on all our supported targets. */ class SquirrelStd { public: /** * Get the lowest of two integers. */ static SQInteger min(HSQUIRRELVM vm); /** * Get the highest of two integers. */ static SQInteger max(HSQUIRRELVM vm); /** * Load another file on runtime. * @note This is always loaded on the root-level, no matter where you call this. * @note The filename is always relative from the script it is called from. Absolute calls are NOT allowed! */ static SQInteger require(HSQUIRRELVM vm); /** * Enable/disable stack trace showing for handled exceptions. */ static SQInteger notifyallexceptions(HSQUIRRELVM vm); }; /** * Register all standard functions we want to give to a script. */ void squirrel_register_std(Squirrel *engine); /** * Register all standard functions that are available on first startup. * @note this set is very limited, and is only meant to load other scripts and things like that. */ void squirrel_register_global_std(Squirrel *engine); #endif /* SQUIRREL_STD_HPP */ openttd-1.5.3/src/script/script_config.cpp0000644000000000000000000001446512627373434017350 0ustar rootroot/* $Id: script_config.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 script_config.cpp Implementation of ScriptConfig. */ #include "../stdafx.h" #include "../settings_type.h" #include "../core/random_func.hpp" #include "script_info.hpp" #include "../textfile_gui.h" #include "../string_func.h" #include "../safeguards.h" void ScriptConfig::Change(const char *name, int version, bool force_exact_match, bool is_random) { free(this->name); this->name = (name == NULL) ? NULL : stredup(name); this->info = (name == NULL) ? NULL : this->FindInfo(this->name, version, force_exact_match); this->version = (info == NULL) ? -1 : info->GetVersion(); this->is_random = is_random; if (this->config_list != NULL) delete this->config_list; this->config_list = (info == NULL) ? NULL : new ScriptConfigItemList(); if (this->config_list != NULL) this->PushExtraConfigList(); this->ClearConfigList(); if (_game_mode == GM_NORMAL && this->info != NULL) { /* If we're in an existing game and the Script is changed, set all settings * for the Script that have the random flag to a random value. */ for (ScriptConfigItemList::const_iterator it = this->info->GetConfigList()->begin(); it != this->info->GetConfigList()->end(); it++) { if ((*it).flags & SCRIPTCONFIG_RANDOM) { this->SetSetting((*it).name, InteractiveRandomRange((*it).max_value - (*it).min_value) + (*it).min_value); } } this->AddRandomDeviation(); } } ScriptConfig::ScriptConfig(const ScriptConfig *config) { this->name = (config->name == NULL) ? NULL : stredup(config->name); this->info = config->info; this->version = config->version; this->config_list = NULL; this->is_random = config->is_random; for (SettingValueList::const_iterator it = config->settings.begin(); it != config->settings.end(); it++) { this->settings[stredup((*it).first)] = (*it).second; } this->AddRandomDeviation(); } ScriptConfig::~ScriptConfig() { free(this->name); this->ResetSettings(); if (this->config_list != NULL) delete this->config_list; } ScriptInfo *ScriptConfig::GetInfo() const { return this->info; } const ScriptConfigItemList *ScriptConfig::GetConfigList() { if (this->info != NULL) return this->info->GetConfigList(); if (this->config_list == NULL) { this->config_list = new ScriptConfigItemList(); this->PushExtraConfigList(); } return this->config_list; } void ScriptConfig::ClearConfigList() { for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) { free((*it).first); } this->settings.clear(); } void ScriptConfig::AnchorUnchangeableSettings() { for (ScriptConfigItemList::const_iterator it = this->GetConfigList()->begin(); it != this->GetConfigList()->end(); it++) { if (((*it).flags & SCRIPTCONFIG_INGAME) == 0) { this->SetSetting((*it).name, this->GetSetting((*it).name)); } } } int ScriptConfig::GetSetting(const char *name) const { SettingValueList::const_iterator it = this->settings.find(name); if (it == this->settings.end()) return this->info->GetSettingDefaultValue(name); return (*it).second; } void ScriptConfig::SetSetting(const char *name, int value) { /* You can only set Script specific settings if an Script is selected. */ if (this->info == NULL) return; const ScriptConfigItem *config_item = this->info->GetConfigItem(name); if (config_item == NULL) return; value = Clamp(value, config_item->min_value, config_item->max_value); SettingValueList::iterator it = this->settings.find(name); if (it != this->settings.end()) { (*it).second = value; } else { this->settings[stredup(name)] = value; } } void ScriptConfig::ResetSettings() { for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) { free((*it).first); } this->settings.clear(); } void ScriptConfig::AddRandomDeviation() { for (ScriptConfigItemList::const_iterator it = this->GetConfigList()->begin(); it != this->GetConfigList()->end(); it++) { if ((*it).random_deviation != 0) { this->SetSetting((*it).name, InteractiveRandomRange((*it).random_deviation * 2) - (*it).random_deviation + this->GetSetting((*it).name)); } } } bool ScriptConfig::HasScript() const { return this->info != NULL; } bool ScriptConfig::IsRandom() const { return this->is_random; } const char *ScriptConfig::GetName() const { return this->name; } int ScriptConfig::GetVersion() const { return this->version; } void ScriptConfig::StringToSettings(const char *value) { char *value_copy = stredup(value); char *s = value_copy; while (s != NULL) { /* Analyze the string ('name=value,name=value\0') */ char *item_name = s; s = strchr(s, '='); if (s == NULL) break; if (*s == '\0') break; *s = '\0'; s++; char *item_value = s; s = strchr(s, ','); if (s != NULL) { *s = '\0'; s++; } this->SetSetting(item_name, atoi(item_value)); } free(value_copy); } void ScriptConfig::SettingsToString(char *string, const char *last) const { char *s = string; *s = '\0'; for (SettingValueList::const_iterator it = this->settings.begin(); it != this->settings.end(); it++) { char no[10]; seprintf(no, lastof(no), "%d", (*it).second); /* Check if the string would fit in the destination */ size_t needed_size = strlen((*it).first) + 1 + strlen(no); /* If it doesn't fit, skip the next settings */ if (string + needed_size > last) break; s = strecat(s, (*it).first, last); s = strecat(s, "=", last); s = strecat(s, no, last); s = strecat(s, ",", last); } /* Remove the last ',', but only if at least one setting was saved. */ if (s != string) s[-1] = '\0'; } const char *ScriptConfig::GetTextfile(TextfileType type, CompanyID slot) const { if (slot == INVALID_COMPANY || this->GetInfo() == NULL) return NULL; return ::GetTextfile(type, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR, this->GetInfo()->GetMainScript()); } openttd-1.5.3/src/script/squirrel_class.hpp0000644000000000000000000001111712627373434017546 0ustar rootroot/* $Id: squirrel_class.hpp 23651 2011-12-21 14:55:28Z yexo $ */ /* * 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 squirrel_class.hpp Defines templates for converting C++ classes to Squirrel classes */ #ifndef SQUIRREL_CLASS_HPP #define SQUIRREL_CLASS_HPP #include "squirrel_helper.hpp" /** * The template to define classes in Squirrel. It takes care of the creation * and calling of such classes, to minimize the API layer. */ template class DefSQClass { private: const char *classname; public: DefSQClass(const char *_classname) : classname(_classname) {} /** * This defines a method inside a class for Squirrel. */ template void DefSQMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; engine->AddMethod(function_name, DefSQNonStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); } /** * This defines a method inside a class for Squirrel, which has access to the 'engine' (experts only!). */ template void DefSQAdvancedMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; engine->AddMethod(function_name, DefSQAdvancedNonStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); } /** * This defines a method inside a class for Squirrel with defined params. * @note If you define nparam, make sure that he first param is always 'x', * which is the 'this' inside the function. This is hidden from the rest * of the code, but without it calling your function will fail! */ template void DefSQMethod(Squirrel *engine, Func function_proc, const char *function_name, int nparam, const char *params) { using namespace SQConvert; engine->AddMethod(function_name, DefSQNonStaticCallback, nparam, params, &function_proc, sizeof(function_proc)); } /** * This defines a static method inside a class for Squirrel. */ template void DefSQStaticMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; engine->AddMethod(function_name, DefSQStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); } /** * This defines a static method inside a class for Squirrel, which has access to the 'engine' (experts only!). */ template void DefSQAdvancedStaticMethod(Squirrel *engine, Func function_proc, const char *function_name) { using namespace SQConvert; engine->AddMethod(function_name, DefSQAdvancedStaticCallback, 0, NULL, &function_proc, sizeof(function_proc)); } /** * This defines a static method inside a class for Squirrel with defined params. * @note If you define nparam, make sure that he first param is always 'x', * which is the 'this' inside the function. This is hidden from the rest * of the code, but without it calling your function will fail! */ template void DefSQStaticMethod(Squirrel *engine, Func function_proc, const char *function_name, int nparam, const char *params) { using namespace SQConvert; engine->AddMethod(function_name, DefSQStaticCallback, nparam, params, &function_proc, sizeof(function_proc)); } template void DefSQConst(Squirrel *engine, Var value, const char *var_name) { engine->AddConst(var_name, value); } void PreRegister(Squirrel *engine) { engine->AddClassBegin(this->classname); } void PreRegister(Squirrel *engine, const char *parent_class) { engine->AddClassBegin(this->classname, parent_class); } template void AddConstructor(Squirrel *engine, const char *params) { using namespace SQConvert; engine->AddMethod("constructor", DefSQConstructorCallback, Tnparam, params); } void AddSQAdvancedConstructor(Squirrel *engine) { using namespace SQConvert; engine->AddMethod("constructor", DefSQAdvancedConstructorCallback, 0, NULL); } void PostRegister(Squirrel *engine) { engine->AddClassEnd(); } }; #endif /* SQUIRREL_CLASS_HPP */ openttd-1.5.3/src/script/script_instance.cpp0000644000000000000000000004653712627373433017713 0ustar rootroot/* $Id: script_instance.cpp 26785 2014-09-07 09:30:57Z rubidium $ */ /* * 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 script_instance.cpp Implementation of ScriptInstance. */ #include "../stdafx.h" #include "../debug.h" #include "../saveload/saveload.h" #include "../script/squirrel_class.hpp" #include "script_fatalerror.hpp" #include "script_storage.hpp" #include "script_info.hpp" #include "script_instance.hpp" #include "api/script_controller.hpp" #include "api/script_error.hpp" #include "api/script_event.hpp" #include "api/script_log.hpp" #include "../company_base.h" #include "../company_func.h" #include "../fileio_func.h" #include "../safeguards.h" ScriptStorage::~ScriptStorage() { /* Free our pointers */ if (event_data != NULL) ScriptEventController::FreeEventPointer(); if (log_data != NULL) ScriptLog::FreeLogPointer(); } /** * Callback called by squirrel when a script uses "print" and for error messages. * @param error_msg Is this an error message? * @param message The actual message text. */ static void PrintFunc(bool error_msg, const SQChar *message) { /* Convert to OpenTTD internal capable string */ ScriptController::Print(error_msg, message); } ScriptInstance::ScriptInstance(const char *APIName) : engine(NULL), versionAPI(NULL), controller(NULL), storage(NULL), instance(NULL), is_started(false), is_dead(false), is_save_data_on_stack(false), suspend(0), is_paused(false), callback(NULL) { this->storage = new ScriptStorage(); this->engine = new Squirrel(APIName); this->engine->SetPrintFunction(&PrintFunc); } void ScriptInstance::Initialize(const char *main_script, const char *instance_name, CompanyID company) { ScriptObject::ActiveInstance active(this); this->controller = new ScriptController(company); /* Register the API functions and classes */ this->engine->SetGlobalPointer(this->engine); this->RegisterAPI(); try { ScriptObject::SetAllowDoCommand(false); /* Load and execute the script for this script */ if (strcmp(main_script, "%_dummy") == 0) { this->LoadDummyScript(); } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) { if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to load script. AI is not started."); this->Died(); return; } /* Create the main-class */ this->instance = MallocT(1); if (!this->engine->CreateClassInstance(instance_name, this->controller, this->instance)) { this->Died(); return; } ScriptObject::SetAllowDoCommand(true); } catch (Script_FatalError e) { this->is_dead = true; this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); this->Died(); } } void ScriptInstance::RegisterAPI() { extern void squirrel_register_std(Squirrel *engine); squirrel_register_std(this->engine); } bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirectory dir) { char script_name[32]; seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version); char buf[MAX_PATH]; Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { FioAppendDirectory(buf, lastof(buf), sp, dir); strecat(buf, script_name, lastof(buf)); if (!FileExists(buf)) continue; if (this->engine->LoadScript(buf)) return true; ScriptLog::Error("Failed to load API compatibility script"); DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf); return false; } ScriptLog::Warning("API compatibility script not found"); return true; } ScriptInstance::~ScriptInstance() { ScriptObject::ActiveInstance active(this); if (instance != NULL) this->engine->ReleaseObject(this->instance); if (engine != NULL) delete this->engine; delete this->storage; delete this->controller; free(this->instance); } void ScriptInstance::Continue() { assert(this->suspend < 0); this->suspend = -this->suspend - 1; } void ScriptInstance::Died() { DEBUG(script, 0, "The script died unexpectedly."); this->is_dead = true; if (this->instance != NULL) this->engine->ReleaseObject(this->instance); delete this->engine; this->instance = NULL; this->engine = NULL; } void ScriptInstance::GameLoop() { ScriptObject::ActiveInstance active(this); if (this->IsDead()) return; if (this->engine->HasScriptCrashed()) { /* The script crashed during saving, kill it here. */ this->Died(); return; } if (this->is_paused) return; this->controller->ticks++; if (this->suspend < -1) this->suspend++; // Multiplayer suspend, increase up to -1. if (this->suspend < 0) return; // Multiplayer suspend, wait for Continue(). if (--this->suspend > 0) return; // Singleplayer suspend, decrease to 0. _current_company = ScriptObject::GetCompany(); /* If there is a callback to call, call that first */ if (this->callback != NULL) { if (this->is_save_data_on_stack) { sq_poptop(this->engine->GetVM()); this->is_save_data_on_stack = false; } try { this->callback(this); } catch (Script_Suspend e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); return; } } this->suspend = 0; this->callback = NULL; if (!this->is_started) { try { ScriptObject::SetAllowDoCommand(false); /* Run the constructor if it exists. Don't allow any DoCommands in it. */ if (this->engine->MethodExists(*this->instance, "constructor")) { if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) { if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started."); this->Died(); return; } } if (!this->CallLoad() || this->engine->IsSuspended()) { if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started."); this->Died(); return; } ScriptObject::SetAllowDoCommand(true); /* Start the script by calling Start() */ if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died(); } catch (Script_Suspend e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); } catch (Script_FatalError e) { this->is_dead = true; this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); this->Died(); } this->is_started = true; return; } if (this->is_save_data_on_stack) { sq_poptop(this->engine->GetVM()); this->is_save_data_on_stack = false; } /* Continue the VM */ try { if (!this->engine->Resume(_settings_game.script.script_max_opcode_till_suspend)) this->Died(); } catch (Script_Suspend e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); } catch (Script_FatalError e) { this->is_dead = true; this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); this->Died(); } } void ScriptInstance::CollectGarbage() const { if (this->is_started && !this->IsDead()) this->engine->CollectGarbage(); } /* static */ void ScriptInstance::DoCommandReturn(ScriptInstance *instance) { instance->engine->InsertResult(ScriptObject::GetLastCommandRes()); } /* static */ void ScriptInstance::DoCommandReturnVehicleID(ScriptInstance *instance) { instance->engine->InsertResult(ScriptObject::GetNewVehicleID()); } /* static */ void ScriptInstance::DoCommandReturnSignID(ScriptInstance *instance) { instance->engine->InsertResult(ScriptObject::GetNewSignID()); } /* static */ void ScriptInstance::DoCommandReturnGroupID(ScriptInstance *instance) { instance->engine->InsertResult(ScriptObject::GetNewGroupID()); } /* static */ void ScriptInstance::DoCommandReturnGoalID(ScriptInstance *instance) { instance->engine->InsertResult(ScriptObject::GetNewGoalID()); } /* static */ void ScriptInstance::DoCommandReturnStoryPageID(ScriptInstance *instance) { instance->engine->InsertResult(ScriptObject::GetNewStoryPageID()); } /* static */ void ScriptInstance::DoCommandReturnStoryPageElementID(ScriptInstance *instance) { instance->engine->InsertResult(ScriptObject::GetNewStoryPageElementID()); } ScriptStorage *ScriptInstance::GetStorage() { return this->storage; } void *ScriptInstance::GetLogPointer() { ScriptObject::ActiveInstance active(this); return ScriptObject::GetLogPointer(); } /* * All data is stored in the following format: * First 1 byte indicating if there is a data blob at all. * 1 byte indicating the type of data. * The data itself, this differs per type: * - integer: a binary representation of the integer (int32). * - string: First one byte with the string length, then a 0-terminated char * array. The string can't be longer than 255 bytes (including * terminating '\0'). * - array: All data-elements of the array are saved recursive in this * format, and ended with an element of the type * SQSL_ARRAY_TABLE_END. * - table: All key/value pairs are saved in this format (first key 1, then * value 1, then key 2, etc.). All keys and values can have an * arbitrary type (as long as it is supported by the save function * of course). The table is ended with an element of the type * SQSL_ARRAY_TABLE_END. * - bool: A single byte with value 1 representing true and 0 false. * - null: No data. */ /** The type of the data that follows in the savegame. */ enum SQSaveLoadType { SQSL_INT = 0x00, ///< The following data is an integer. SQSL_STRING = 0x01, ///< The following data is an string. SQSL_ARRAY = 0x02, ///< The following data is an array. SQSL_TABLE = 0x03, ///< The following data is an table. SQSL_BOOL = 0x04, ///< The following data is a boolean. SQSL_NULL = 0x05, ///< A null variable. SQSL_ARRAY_TABLE_END = 0xFF, ///< Marks the end of an array or table, no data follows. }; static byte _script_sl_byte; ///< Used as source/target by the script saveload code to store/load a single byte. /** SaveLoad array that saves/loads exactly one byte. */ static const SaveLoad _script_byte[] = { SLEG_VAR(_script_sl_byte, SLE_UINT8), SLE_END() }; /* static */ bool ScriptInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test) { if (max_depth == 0) { ScriptLog::Error("Savedata can only be nested to 25 deep. No data saved."); // SQUIRREL_MAX_DEPTH = 25 return false; } switch (sq_gettype(vm, index)) { case OT_INTEGER: { if (!test) { _script_sl_byte = SQSL_INT; SlObject(NULL, _script_byte); } SQInteger res; sq_getinteger(vm, index, &res); if (!test) { int value = (int)res; SlArray(&value, 1, SLE_INT32); } return true; } case OT_STRING: { if (!test) { _script_sl_byte = SQSL_STRING; SlObject(NULL, _script_byte); } const SQChar *buf; sq_getstring(vm, index, &buf); size_t len = strlen(buf) + 1; if (len >= 255) { ScriptLog::Error("Maximum string length is 254 chars. No data saved."); return false; } if (!test) { _script_sl_byte = (byte)len; SlObject(NULL, _script_byte); SlArray(const_cast(buf), len, SLE_CHAR); } return true; } case OT_ARRAY: { if (!test) { _script_sl_byte = SQSL_ARRAY; SlObject(NULL, _script_byte); } sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { /* Store the value */ bool res = SaveObject(vm, -1, max_depth - 1, test); sq_pop(vm, 2); if (!res) { sq_pop(vm, 1); return false; } } sq_pop(vm, 1); if (!test) { _script_sl_byte = SQSL_ARRAY_TABLE_END; SlObject(NULL, _script_byte); } return true; } case OT_TABLE: { if (!test) { _script_sl_byte = SQSL_TABLE; SlObject(NULL, _script_byte); } sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { /* Store the key + value */ bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test); sq_pop(vm, 2); if (!res) { sq_pop(vm, 1); return false; } } sq_pop(vm, 1); if (!test) { _script_sl_byte = SQSL_ARRAY_TABLE_END; SlObject(NULL, _script_byte); } return true; } case OT_BOOL: { if (!test) { _script_sl_byte = SQSL_BOOL; SlObject(NULL, _script_byte); } SQBool res; sq_getbool(vm, index, &res); if (!test) { _script_sl_byte = res ? 1 : 0; SlObject(NULL, _script_byte); } return true; } case OT_NULL: { if (!test) { _script_sl_byte = SQSL_NULL; SlObject(NULL, _script_byte); } return true; } default: ScriptLog::Error("You tried to save an unsupported type. No data saved."); return false; } } /* static */ void ScriptInstance::SaveEmpty() { _script_sl_byte = 0; SlObject(NULL, _script_byte); } void ScriptInstance::Save() { ScriptObject::ActiveInstance active(this); /* Don't save data if the script didn't start yet or if it crashed. */ if (this->engine == NULL || this->engine->HasScriptCrashed()) { SaveEmpty(); return; } HSQUIRRELVM vm = this->engine->GetVM(); if (this->is_save_data_on_stack) { _script_sl_byte = 1; SlObject(NULL, _script_byte); /* Save the data that was just loaded. */ SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false); } else if (!this->is_started) { SaveEmpty(); return; } else if (this->engine->MethodExists(*this->instance, "Save")) { HSQOBJECT savedata; /* We don't want to be interrupted during the save function. */ bool backup_allow = ScriptObject::GetAllowDoCommand(); ScriptObject::SetAllowDoCommand(false); try { if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) { /* The script crashed in the Save function. We can't kill * it here, but do so in the next script tick. */ SaveEmpty(); this->engine->CrashOccurred(); return; } } catch (Script_FatalError e) { /* If we don't mark the script as dead here cleaning up the squirrel * stack could throw Script_FatalError again. */ this->is_dead = true; this->engine->ThrowError(e.GetErrorMessage()); this->engine->ResumeError(); SaveEmpty(); /* We can't kill the script here, so mark it as crashed (not dead) and * kill it in the next script tick. */ this->is_dead = false; this->engine->CrashOccurred(); return; } ScriptObject::SetAllowDoCommand(backup_allow); if (!sq_istable(savedata)) { ScriptLog::Error(this->engine->IsSuspended() ? "This script took too long to Save." : "Save function should return a table."); SaveEmpty(); this->engine->CrashOccurred(); return; } sq_pushobject(vm, savedata); if (SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, true)) { _script_sl_byte = 1; SlObject(NULL, _script_byte); SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false); this->is_save_data_on_stack = true; } else { SaveEmpty(); this->engine->CrashOccurred(); } } else { ScriptLog::Warning("Save function is not implemented"); _script_sl_byte = 0; SlObject(NULL, _script_byte); } } void ScriptInstance::Pause() { /* Suspend script. */ HSQUIRRELVM vm = this->engine->GetVM(); Squirrel::DecreaseOps(vm, _settings_game.script.script_max_opcode_till_suspend); this->is_paused = true; } void ScriptInstance::Unpause() { this->is_paused = false; } bool ScriptInstance::IsPaused() { return this->is_paused; } /* static */ bool ScriptInstance::LoadObjects(HSQUIRRELVM vm) { SlObject(NULL, _script_byte); switch (_script_sl_byte) { case SQSL_INT: { int value; SlArray(&value, 1, SLE_INT32); if (vm != NULL) sq_pushinteger(vm, (SQInteger)value); return true; } case SQSL_STRING: { SlObject(NULL, _script_byte); static char buf[256]; SlArray(buf, _script_sl_byte, SLE_CHAR); if (vm != NULL) sq_pushstring(vm, buf, -1); return true; } case SQSL_ARRAY: { if (vm != NULL) sq_newarray(vm, 0); while (LoadObjects(vm)) { if (vm != NULL) sq_arrayappend(vm, -2); /* The value is popped from the stack by squirrel. */ } return true; } case SQSL_TABLE: { if (vm != NULL) sq_newtable(vm); while (LoadObjects(vm)) { LoadObjects(vm); if (vm != NULL) sq_rawset(vm, -3); /* The key (-2) and value (-1) are popped from the stack by squirrel. */ } return true; } case SQSL_BOOL: { SlObject(NULL, _script_byte); if (vm != NULL) sq_pushbool(vm, (SQBool)(_script_sl_byte != 0)); return true; } case SQSL_NULL: { if (vm != NULL) sq_pushnull(vm); return true; } case SQSL_ARRAY_TABLE_END: { return false; } default: NOT_REACHED(); } } /* static */ void ScriptInstance::LoadEmpty() { SlObject(NULL, _script_byte); /* Check if there was anything saved at all. */ if (_script_sl_byte == 0) return; LoadObjects(NULL); } void ScriptInstance::Load(int version) { ScriptObject::ActiveInstance active(this); if (this->engine == NULL || version == -1) { LoadEmpty(); return; } HSQUIRRELVM vm = this->engine->GetVM(); SlObject(NULL, _script_byte); /* Check if there was anything saved at all. */ if (_script_sl_byte == 0) return; sq_pushinteger(vm, version); LoadObjects(vm); this->is_save_data_on_stack = true; } bool ScriptInstance::CallLoad() { HSQUIRRELVM vm = this->engine->GetVM(); /* Is there save data that we should load? */ if (!this->is_save_data_on_stack) return true; /* Whatever happens, after CallLoad the savegame data is removed from the stack. */ this->is_save_data_on_stack = false; if (!this->engine->MethodExists(*this->instance, "Load")) { ScriptLog::Warning("Loading failed: there was data for the script to load, but the script does not have a Load() function."); /* Pop the savegame data and version. */ sq_pop(vm, 2); return true; } /* Go to the instance-root */ sq_pushobject(vm, *this->instance); /* Find the function-name inside the script */ sq_pushstring(vm, "Load", -1); /* Change the "Load" string in a function pointer */ sq_get(vm, -2); /* Push the main instance as "this" object */ sq_pushobject(vm, *this->instance); /* Push the version data and savegame data as arguments */ sq_push(vm, -5); sq_push(vm, -5); /* Call the script load function. sq_call removes the arguments (but not the * function pointer) from the stack. */ if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, MAX_SL_OPS))) return false; /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */ sq_pop(vm, 4); return true; } SQInteger ScriptInstance::GetOpsTillSuspend() { return this->engine->GetOpsTillSuspend(); } void ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { ScriptObject::ActiveInstance active(this); ScriptObject::SetLastCommandRes(result.Succeeded()); if (result.Failed()) { ScriptObject::SetLastError(ScriptError::StringToError(result.GetErrorMessage())); } else { ScriptObject::IncreaseDoCommandCosts(result.GetCost()); ScriptObject::SetLastCost(result.GetCost()); } } void ScriptInstance::InsertEvent(class ScriptEvent *event) { ScriptObject::ActiveInstance active(this); ScriptEventController::InsertEvent(event); } openttd-1.5.3/src/script/squirrel.cpp0000644000000000000000000004052312627373434016357 0ustar rootroot/* $Id: squirrel.cpp 26797 2014-09-07 16:03:41Z rubidium $ */ /* * 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 squirrel.cpp the implementation of the Squirrel class. It handles all Squirrel-stuff and gives a nice API back to work with. */ #include #include "../stdafx.h" #include "../debug.h" #include "squirrel_std.hpp" #include "../fileio_func.h" #include "../string_func.h" #include #include <../squirrel/sqpcheader.h> #include <../squirrel/sqvm.h> #include "../safeguards.h" void Squirrel::CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column) { SQChar buf[1024]; seprintf(buf, lastof(buf), "Error %s:" OTTD_PRINTF64 "/" OTTD_PRINTF64 ": %s", source, line, column, desc); /* Check if we have a custom print function */ Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); engine->crashed = true; SQPrintFunc *func = engine->print_func; if (func == NULL) { DEBUG(misc, 0, "[Squirrel] Compile error: %s", buf); } else { (*func)(true, buf); } } void Squirrel::ErrorPrintFunc(HSQUIRRELVM vm, const SQChar *s, ...) { va_list arglist; SQChar buf[1024]; va_start(arglist, s); vseprintf(buf, lastof(buf), s, arglist); va_end(arglist); /* Check if we have a custom print function */ SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func; if (func == NULL) { fprintf(stderr, "%s", buf); } else { (*func)(true, buf); } } void Squirrel::RunError(HSQUIRRELVM vm, const SQChar *error) { /* Set the print function to something that prints to stderr */ SQPRINTFUNCTION pf = sq_getprintfunc(vm); sq_setprintfunc(vm, &Squirrel::ErrorPrintFunc); /* Check if we have a custom print function */ SQChar buf[1024]; seprintf(buf, lastof(buf), "Your script made an error: %s\n", error); Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); SQPrintFunc *func = engine->print_func; if (func == NULL) { fprintf(stderr, "%s", buf); } else { (*func)(true, buf); } /* Print below the error the stack, so the users knows what is happening */ sqstd_printcallstack(vm); /* Reset the old print function */ sq_setprintfunc(vm, pf); } SQInteger Squirrel::_RunError(HSQUIRRELVM vm) { const SQChar *sErr = 0; if (sq_gettop(vm) >= 1) { if (SQ_SUCCEEDED(sq_getstring(vm, -1, &sErr))) { Squirrel::RunError(vm, sErr); return 0; } } Squirrel::RunError(vm, "unknown error"); return 0; } void Squirrel::PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...) { va_list arglist; SQChar buf[1024]; va_start(arglist, s); vseprintf(buf, lastof(buf) - 2, s, arglist); va_end(arglist); strecat(buf, "\n", lastof(buf)); /* Check if we have a custom print function */ SQPrintFunc *func = ((Squirrel *)sq_getforeignptr(vm))->print_func; if (func == NULL) { printf("%s", buf); } else { (*func)(false, buf); } } void Squirrel::AddMethod(const char *method_name, SQFUNCTION proc, uint nparam, const char *params, void *userdata, int size) { sq_pushstring(this->vm, method_name, -1); if (size != 0) { void *ptr = sq_newuserdata(vm, size); memcpy(ptr, userdata, size); } sq_newclosure(this->vm, proc, size != 0 ? 1 : 0); if (nparam != 0) sq_setparamscheck(this->vm, nparam, params); sq_setnativeclosurename(this->vm, -1, method_name); sq_newslot(this->vm, -3, SQFalse); } void Squirrel::AddConst(const char *var_name, int value) { sq_pushstring(this->vm, var_name, -1); sq_pushinteger(this->vm, value); sq_newslot(this->vm, -3, SQTrue); } void Squirrel::AddConst(const char *var_name, bool value) { sq_pushstring(this->vm, var_name, -1); sq_pushbool(this->vm, value); sq_newslot(this->vm, -3, SQTrue); } void Squirrel::AddClassBegin(const char *class_name) { sq_pushroottable(this->vm); sq_pushstring(this->vm, class_name, -1); sq_newclass(this->vm, SQFalse); } void Squirrel::AddClassBegin(const char *class_name, const char *parent_class) { sq_pushroottable(this->vm); sq_pushstring(this->vm, class_name, -1); sq_pushstring(this->vm, parent_class, -1); if (SQ_FAILED(sq_get(this->vm, -3))) { DEBUG(misc, 0, "[squirrel] Failed to initialize class '%s' based on parent class '%s'", class_name, parent_class); DEBUG(misc, 0, "[squirrel] Make sure that '%s' exists before trying to define '%s'", parent_class, class_name); return; } sq_newclass(this->vm, SQTrue); } void Squirrel::AddClassEnd() { sq_newslot(vm, -3, SQFalse); sq_pop(vm, 1); } bool Squirrel::MethodExists(HSQOBJECT instance, const char *method_name) { assert(!this->crashed); int top = sq_gettop(this->vm); /* Go to the instance-root */ sq_pushobject(this->vm, instance); /* Find the function-name inside the script */ sq_pushstring(this->vm, method_name, -1); if (SQ_FAILED(sq_get(this->vm, -2))) { sq_settop(this->vm, top); return false; } sq_settop(this->vm, top); return true; } bool Squirrel::Resume(int suspend) { assert(!this->crashed); /* Did we use more operations than we should have in the * previous tick? If so, subtract that from the current run. */ if (this->overdrawn_ops > 0 && suspend > 0) { this->overdrawn_ops -= suspend; /* Do we need to wait even more? */ if (this->overdrawn_ops >= 0) return true; /* We can now only run whatever is "left". */ suspend = -this->overdrawn_ops; } this->crashed = !sq_resumecatch(this->vm, suspend); this->overdrawn_ops = -this->vm->_ops_till_suspend; return this->vm->_suspended != 0; } void Squirrel::ResumeError() { assert(!this->crashed); sq_resumeerror(this->vm); } void Squirrel::CollectGarbage() { sq_collectgarbage(this->vm); } bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend) { assert(!this->crashed); /* Store the stack-location for the return value. We need to * restore this after saving or the stack will be corrupted * if we're in the middle of a DoCommand. */ SQInteger last_target = this->vm->_suspended_target; /* Store the current top */ int top = sq_gettop(this->vm); /* Go to the instance-root */ sq_pushobject(this->vm, instance); /* Find the function-name inside the script */ sq_pushstring(this->vm, method_name, -1); if (SQ_FAILED(sq_get(this->vm, -2))) { DEBUG(misc, 0, "[squirrel] Could not find '%s' in the class", method_name); sq_settop(this->vm, top); return false; } /* Call the method */ sq_pushobject(this->vm, instance); if (SQ_FAILED(sq_call(this->vm, 1, ret == NULL ? SQFalse : SQTrue, SQTrue, suspend))) return false; if (ret != NULL) sq_getstackobj(vm, -1, ret); /* Reset the top, but don't do so for the script main function, as we need * a correct stack when resuming. */ if (suspend == -1 || !this->IsSuspended()) sq_settop(this->vm, top); /* Restore the return-value location. */ this->vm->_suspended_target = last_target; return true; } bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend) { HSQOBJECT ret; if (!this->CallMethod(instance, method_name, &ret, suspend)) return false; if (ret._type != OT_STRING) return false; *res = stredup(ObjectToString(&ret)); ValidateString(*res); return true; } bool Squirrel::CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend) { HSQOBJECT ret; if (!this->CallMethod(instance, method_name, &ret, suspend)) return false; if (ret._type != OT_INTEGER) return false; *res = ObjectToInteger(&ret); return true; } bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend) { HSQOBJECT ret; if (!this->CallMethod(instance, method_name, &ret, suspend)) return false; if (ret._type != OT_BOOL) return false; *res = ObjectToBool(&ret); return true; } /* static */ bool Squirrel::CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name) { Squirrel *engine = (Squirrel *)sq_getforeignptr(vm); int oldtop = sq_gettop(vm); /* First, find the class */ sq_pushroottable(vm); if (prepend_API_name) { size_t len = strlen(class_name) + strlen(engine->GetAPIName()) + 1; char *class_name2 = (char *)alloca(len); seprintf(class_name2, class_name2 + len - 1, "%s%s", engine->GetAPIName(), class_name); sq_pushstring(vm, class_name2, -1); } else { sq_pushstring(vm, class_name, -1); } if (SQ_FAILED(sq_get(vm, -2))) { DEBUG(misc, 0, "[squirrel] Failed to find class by the name '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name); sq_settop(vm, oldtop); return false; } /* Create the instance */ if (SQ_FAILED(sq_createinstance(vm, -1))) { DEBUG(misc, 0, "[squirrel] Failed to create instance for class '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name); sq_settop(vm, oldtop); return false; } if (instance != NULL) { /* Find our instance */ sq_getstackobj(vm, -1, instance); /* Add a reference to it, so it survives for ever */ sq_addref(vm, instance); } sq_remove(vm, -2); // Class-name sq_remove(vm, -2); // Root-table /* Store it in the class */ sq_setinstanceup(vm, -1, real_instance); if (release_hook != NULL) sq_setreleasehook(vm, -1, release_hook); if (instance != NULL) sq_settop(vm, oldtop); return true; } bool Squirrel::CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance) { return Squirrel::CreateClassInstanceVM(this->vm, class_name, real_instance, instance, NULL); } Squirrel::Squirrel(const char *APIName) : APIName(APIName) { this->Initialize(); } void Squirrel::Initialize() { this->global_pointer = NULL; this->print_func = NULL; this->crashed = false; this->overdrawn_ops = 0; this->vm = sq_open(1024); /* Handle compile-errors ourself, so we can display it nicely */ sq_setcompilererrorhandler(this->vm, &Squirrel::CompileError); sq_notifyallexceptions(this->vm, SQTrue); /* Set a good print-function */ sq_setprintfunc(this->vm, &Squirrel::PrintFunc); /* Handle runtime-errors ourself, so we can display it nicely */ sq_newclosure(this->vm, &Squirrel::_RunError, 0); sq_seterrorhandler(this->vm); /* Set the foreign pointer, so we can always find this instance from within the VM */ sq_setforeignptr(this->vm, this); sq_pushroottable(this->vm); squirrel_register_global_std(this); } class SQFile { private: FILE *file; size_t size; size_t pos; public: SQFile(FILE *file, size_t size) : file(file), size(size), pos(0) {} size_t Read(void *buf, size_t elemsize, size_t count) { assert(elemsize != 0); if (this->pos + (elemsize * count) > this->size) { count = (this->size - this->pos) / elemsize; } if (count == 0) return 0; size_t ret = fread(buf, elemsize, count, this->file); this->pos += ret * elemsize; return ret; } }; static WChar _io_file_lexfeed_ASCII(SQUserPointer file) { unsigned char c; if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) return c; return 0; } static WChar _io_file_lexfeed_UTF8(SQUserPointer file) { char buffer[5]; /* Read the first character, and get the length based on UTF-8 specs. If invalid, bail out. */ if (((SQFile *)file)->Read(buffer, sizeof(buffer[0]), 1) != 1) return 0; uint len = Utf8EncodedCharLen(buffer[0]); if (len == 0) return -1; /* Read the remaining bits. */ if (len > 1 && ((SQFile *)file)->Read(buffer + 1, sizeof(buffer[0]), len - 1) != len - 1) return 0; /* Convert the character, and when definitely invalid, bail out as well. */ WChar c; if (Utf8Decode(&c, buffer) != len) return -1; return c; } static WChar _io_file_lexfeed_UCS2_no_swap(SQUserPointer file) { unsigned short c; if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) return (WChar)c; return 0; } static WChar _io_file_lexfeed_UCS2_swap(SQUserPointer file) { unsigned short c; if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) { c = ((c >> 8) & 0x00FF)| ((c << 8) & 0xFF00); return (WChar)c; } return 0; } static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger size) { SQInteger ret = ((SQFile *)file)->Read(buf, 1, size); if (ret == 0) return -1; return ret; } SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror) { size_t size; FILE *file; SQInteger ret; unsigned short us; unsigned char uc; SQLEXREADFUNC func; if (strncmp(this->GetAPIName(), "AI", 2) == 0) { file = FioFOpenFile(filename, "rb", AI_DIR, &size); if (file == NULL) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size); } else if (strncmp(this->GetAPIName(), "GS", 2) == 0) { file = FioFOpenFile(filename, "rb", GAME_DIR, &size); if (file == NULL) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size); } else { NOT_REACHED(); } if (file != NULL) { SQFile f(file, size); ret = fread(&us, 1, sizeof(us), file); /* Most likely an empty file */ if (ret != 2) us = 0; switch (us) { case SQ_BYTECODE_STREAM_TAG: { // BYTECODE if (fseek(file, -2, SEEK_CUR) < 0) { FioFCloseFile(file); return sq_throwerror(vm, "cannot seek the file"); } if (SQ_SUCCEEDED(sq_readclosure(vm, _io_file_read, &f))) { FioFCloseFile(file); return SQ_OK; } FioFCloseFile(file); return sq_throwerror(vm, "Couldn't read bytecode"); } case 0xFFFE: /* Either this file is encoded as big-endian and we're on a little-endian * machine, or this file is encoded as little-endian and we're on a big-endian * machine. Either way, swap the bytes of every word we read. */ func = _io_file_lexfeed_UCS2_swap; break; case 0xFEFF: func = _io_file_lexfeed_UCS2_no_swap; break; case 0xBBEF: // UTF-8 case 0xEFBB: // UTF-8 on big-endian machine if (fread(&uc, 1, sizeof(uc), file) == 0) { FioFCloseFile(file); return sq_throwerror(vm, "I/O error"); } if (uc != 0xBF) { FioFCloseFile(file); return sq_throwerror(vm, "Unrecognized encoding"); } func = _io_file_lexfeed_UTF8; break; default: // ASCII func = _io_file_lexfeed_ASCII; if (fseek(file, -2, SEEK_CUR) < 0) { FioFCloseFile(file); return sq_throwerror(vm, "cannot seek the file"); } break; } if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename, printerror))) { FioFCloseFile(file); return SQ_OK; } FioFCloseFile(file); return SQ_ERROR; } return sq_throwerror(vm, "cannot open the file"); } bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root) { /* Make sure we are always in the root-table */ if (in_root) sq_pushroottable(vm); SQInteger ops_left = vm->_ops_till_suspend; /* Load and run the script */ if (SQ_SUCCEEDED(LoadFile(vm, script, SQTrue))) { sq_push(vm, -2); if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue, 100000))) { sq_pop(vm, 1); /* After compiling the file we want to reset the amount of opcodes. */ vm->_ops_till_suspend = ops_left; return true; } } vm->_ops_till_suspend = ops_left; DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script); return false; } bool Squirrel::LoadScript(const char *script) { return LoadScript(this->vm, script); } Squirrel::~Squirrel() { this->Uninitialize(); } void Squirrel::Uninitialize() { /* Clean up the stuff */ sq_pop(this->vm, 1); sq_close(this->vm); } void Squirrel::Reset() { this->Uninitialize(); this->Initialize(); } void Squirrel::InsertResult(bool result) { sq_pushbool(this->vm, result); if (this->IsSuspended()) { // Called before resuming a suspended script? vm->GetAt(vm->_stackbase + vm->_suspended_target) = vm->GetUp(-1); vm->Pop(); } } void Squirrel::InsertResult(int result) { sq_pushinteger(this->vm, result); if (this->IsSuspended()) { // Called before resuming a suspended script? vm->GetAt(vm->_stackbase + vm->_suspended_target) = vm->GetUp(-1); vm->Pop(); } } /* static */ void Squirrel::DecreaseOps(HSQUIRRELVM vm, int ops) { vm->DecreaseOps(ops); } bool Squirrel::IsSuspended() { return this->vm->_suspended != 0; } bool Squirrel::HasScriptCrashed() { return this->crashed; } void Squirrel::CrashOccurred() { this->crashed = true; } bool Squirrel::CanSuspend() { return sq_can_suspend(this->vm); } SQInteger Squirrel::GetOpsTillSuspend() { return this->vm->_ops_till_suspend; } openttd-1.5.3/src/script/squirrel.hpp0000644000000000000000000002133212627373433016360 0ustar rootroot/* $Id: squirrel.hpp 26771 2014-09-06 17:30:33Z rubidium $ */ /* * 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 squirrel.hpp defines the Squirrel class */ #ifndef SQUIRREL_HPP #define SQUIRREL_HPP #include /** The type of script we're working with, i.e. for who is it? */ enum ScriptType { ST_AI, ///< The script is for AI scripts. ST_GS, ///< The script is for Game scripts. }; class Squirrel { private: typedef void (SQPrintFunc)(bool error_msg, const SQChar *message); HSQUIRRELVM vm; ///< The VirtualMachine instance for squirrel void *global_pointer; ///< Can be set by who ever initializes Squirrel SQPrintFunc *print_func; ///< Points to either NULL, or a custom print handler bool crashed; ///< True if the squirrel script made an error. int overdrawn_ops; ///< The amount of operations we have overdrawn. const char *APIName; ///< Name of the API used for this squirrel. /** * The internal RunError handler. It looks up the real error and calls RunError with it. */ static SQInteger _RunError(HSQUIRRELVM vm); /** * Get the API name. */ const char *GetAPIName() { return this->APIName; } /** Perform all initialization steps to create the engine. */ void Initialize(); /** Perform all the cleanups for the engine. */ void Uninitialize(); protected: /** * The CompileError handler. */ static void CompileError(HSQUIRRELVM vm, const SQChar *desc, const SQChar *source, SQInteger line, SQInteger column); /** * The RunError handler. */ static void RunError(HSQUIRRELVM vm, const SQChar *error); /** * If a user runs 'print' inside a script, this function gets the params. */ static void PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...); /** * If an error has to be print, this function is called. */ static void ErrorPrintFunc(HSQUIRRELVM vm, const SQChar *s, ...); public: Squirrel(const char *APIName); ~Squirrel(); /** * Get the squirrel VM. Try to avoid using this. */ HSQUIRRELVM GetVM() { return this->vm; } /** * Load a script. * @param script The full script-name to load. * @return False if loading failed. */ bool LoadScript(const char *script); bool LoadScript(HSQUIRRELVM vm, const char *script, bool in_root = true); /** * Load a file to a given VM. */ SQRESULT LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror); /** * Adds a function to the stack. Depending on the current state this means * either a method or a global function. */ void AddMethod(const char *method_name, SQFUNCTION proc, uint nparam = 0, const char *params = NULL, void *userdata = NULL, int size = 0); /** * Adds a const to the stack. Depending on the current state this means * either a const to a class or to the global space. */ void AddConst(const char *var_name, int value); /** * Adds a const to the stack. Depending on the current state this means * either a const to a class or to the global space. */ void AddConst(const char *var_name, uint value) { this->AddConst(var_name, (int)value); } /** * Adds a const to the stack. Depending on the current state this means * either a const to a class or to the global space. */ void AddConst(const char *var_name, bool value); /** * Adds a class to the global scope. Make sure to call AddClassEnd when you * are done adding methods. */ void AddClassBegin(const char *class_name); /** * Adds a class to the global scope, extending 'parent_class'. * Make sure to call AddClassEnd when you are done adding methods. */ void AddClassBegin(const char *class_name, const char *parent_class); /** * Finishes adding a class to the global scope. If this isn't called, no * class is really created. */ void AddClassEnd(); /** * Resume a VM when it was suspended via a throw. */ bool Resume(int suspend = -1); /** * Resume the VM with an error so it prints a stack trace. */ void ResumeError(); /** * Tell the VM to do a garbage collection run. */ void CollectGarbage(); void InsertResult(bool result); void InsertResult(int result); void InsertResult(uint result) { this->InsertResult((int)result); } /** * Call a method of an instance, in various flavors. * @return False if the script crashed or returned a wrong type. */ bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend); bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, NULL, suspend); } bool CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend); bool CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend); bool CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend); /** * Check if a method exists in an instance. */ bool MethodExists(HSQOBJECT instance, const char *method_name); /** * Creates a class instance. * @param vm The VM to create the class instance for * @param class_name The name of the class of which we create an instance. * @param real_instance The instance to the real class, if it represents a real class. * @param instance Returning value with the pointer to the instance. * @param release_hook Optional param to give a release hook. * @param prepend_API_name Optional parameter; if true, the class_name is prefixed with the current API name. * @return False if creating failed. */ static bool CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name = false); /** * Exactly the same as CreateClassInstanceVM, only callable without instance of Squirrel. */ bool CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance); /** * Get the real-instance pointer. * @note This will only work just after a function-call from within Squirrel * to your C++ function. */ static bool GetRealInstance(HSQUIRRELVM vm, SQUserPointer *ptr) { return SQ_SUCCEEDED(sq_getinstanceup(vm, 1, ptr, 0)); } /** * Get the Squirrel-instance pointer. * @note This will only work just after a function-call from within Squirrel * to your C++ function. */ static bool GetInstance(HSQUIRRELVM vm, HSQOBJECT *ptr, int pos = 1) { sq_getclass(vm, pos); sq_getstackobj(vm, pos, ptr); sq_pop(vm, 1); return true; } /** * Convert a Squirrel-object to a string. */ static const char *ObjectToString(HSQOBJECT *ptr) { return sq_objtostring(ptr); } /** * Convert a Squirrel-object to an integer. */ static int ObjectToInteger(HSQOBJECT *ptr) { return sq_objtointeger(ptr); } /** * Convert a Squirrel-object to a bool. */ static bool ObjectToBool(HSQOBJECT *ptr) { return sq_objtobool(ptr) == 1; } /** * Sets a pointer in the VM that is reachable from where ever you are in SQ. * Useful to keep track of the main instance. */ void SetGlobalPointer(void *ptr) { this->global_pointer = ptr; } /** * Get the pointer as set by SetGlobalPointer. */ static void *GetGlobalPointer(HSQUIRRELVM vm) { return ((Squirrel *)sq_getforeignptr(vm))->global_pointer; } /** * Set a custom print function, so you can handle outputs from SQ yourself. */ void SetPrintFunction(SQPrintFunc *func) { this->print_func = func; } /** * Throw a Squirrel error that will be nicely displayed to the user. */ void ThrowError(const char *error) { sq_throwerror(this->vm, error); } /** * Release a SQ object. */ void ReleaseObject(HSQOBJECT *ptr) { sq_release(this->vm, ptr); } /** * Tell the VM to remove \c amount ops from the number of ops till suspend. */ static void DecreaseOps(HSQUIRRELVM vm, int amount); /** * Did the squirrel code suspend or return normally. * @return True if the function suspended. */ bool IsSuspended(); /** * Find out if the squirrel script made an error before. */ bool HasScriptCrashed(); /** * Set the script status to crashed. */ void CrashOccurred(); /** * Are we allowed to suspend the squirrel script at this moment? */ bool CanSuspend(); /** * How many operations can we execute till suspension? */ SQInteger GetOpsTillSuspend(); /** * Completely reset the engine; start from scratch. */ void Reset(); }; #endif /* SQUIRREL_HPP */ openttd-1.5.3/src/script/squirrel_helper_type.hpp0000644000000000000000000000176012627373433020763 0ustar rootroot/* $Id: squirrel_helper_type.hpp 22406 2011-05-01 19:51:52Z rubidium $ */ /* * 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 squirrel_helper_type.hpp Helper structs for converting Squirrel data structures to C++. */ #ifndef SQUIRREL_HELPER_TYPE_HPP #define SQUIRREL_HELPER_TYPE_HPP /** Definition of a simple array. */ struct Array { int32 size; ///< The size of the array. int32 array[]; ///< The data of the array. }; #endif /* SQUIRREL_HELPER_TYPE_HPP */ openttd-1.5.3/src/script/api/0000755000000000000000000000000012627373434014552 5ustar rootrootopenttd-1.5.3/src/script/api/Doxyfile_AI0000644000000000000000000002306012627373434016632 0ustar rootroot# $Id: Doxyfile_AI 25595 2013-07-13 06:44:22Z rubidium $ # 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 . # Doxyfile 1.5.4 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "OpenTTD NoAI API" PROJECT_NUMBER = OUTPUT_DIRECTORY = ../../../docs/aidocs/ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class " \ "The $name widget " \ "The $name file " \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = ./ STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 2 ALIASES = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = YES EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = YES INTERNAL_DOCS = YES CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO GENERATE_DEPRECATEDLIST= NO ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = NO SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text " WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = . INPUT_ENCODING = UTF-8 FILE_PATTERNS = script_*.hpp \ ai_*.hpp RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = GetClassName DECLARE_ENUM_AS_BIT_SET DECLARE_POSTFIX_INCREMENT EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = "./doxygen_filter.sh AI" FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO HTML_DYNAMIC_SECTIONS = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 1 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DOXYGEN_API EXPAND_AS_DEFINED = DEF_COMMAND SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ../../../objs/openttd_noai.tag ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = NO DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO openttd-1.5.3/src/script/api/script_testmode.hpp0000644000000000000000000000360212627373434020474 0ustar rootroot/* $Id: script_testmode.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 script_testmode.hpp Switch the script instance to Test Mode. */ #ifndef SCRIPT_TESTMODE_HPP #define SCRIPT_TESTMODE_HPP #include "script_object.hpp" /** * Class to switch current mode to Test Mode. * If you create an instance of this class, the mode will be switched to * Testing. The original mode is stored and recovered from when ever the * instance is destroyed. * In Test mode all the commands you execute aren't really executed. The * system only checks if it would be able to execute your requests, and what * the cost would be. * @api ai game */ class ScriptTestMode : public ScriptObject { private: ScriptModeProc *last_mode; ///< The previous mode we were in. ScriptObject *last_instance; ///< The previous instance of the mode. protected: /** * The callback proc for Testing mode. */ static bool ModeProc(); public: /** * Creating instance of this class switches the build mode to Testing. * @note When the instance is destroyed, he restores the mode that was * current when the instance was created! */ ScriptTestMode(); /** * Destroying this instance reset the building mode to the mode it was * in when the instance was created. */ ~ScriptTestMode(); }; #endif /* SCRIPT_TESTMODE_HPP */ openttd-1.5.3/src/script/api/script_basestation.hpp0000644000000000000000000000574612627373434021177 0ustar rootroot/* $Id: script_basestation.hpp 26307 2014-02-06 19:50:34Z zuu $ */ /* * 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 script_basestation.hpp Base for stations/waypoint handling. */ #ifndef SCRIPT_BASESTATION_HPP #define SCRIPT_BASESTATION_HPP #include "script_text.hpp" #include "script_date.hpp" /** * Base class for stations and waypoints. * @api ai game */ class ScriptBaseStation : public ScriptObject { public: /** * Special station IDs for building adjacent/new stations when * the adjacent/distant join features are enabled. */ enum SpecialStationIDs { STATION_NEW = 0xFFFD, ///< Build a new station STATION_JOIN_ADJACENT = 0xFFFE, ///< Join an neighbouring station if one exists STATION_INVALID = 0xFFFF, ///< Invalid station id. }; /** * Checks whether the given basestation is valid and owned by you. * @param station_id The station to check. * @return True if and only if the basestation is valid. * @note IsValidBaseStation == (IsValidStation || IsValidWaypoint). */ static bool IsValidBaseStation(StationID station_id); /** * Get the name of a basestation. * @param station_id The basestation to get the name of. * @pre IsValidBaseStation(station_id). * @return The name of the station. */ static char *GetName(StationID station_id); /** * Set the name this basestation. * @param station_id The basestation to set the name of. * @param name The new name of the station (can be either a raw string, or a ScriptText object). * @pre IsValidBaseStation(station_id). * @pre name != NULL && len(name) != 0. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if the name was changed. */ static bool SetName(StationID station_id, Text *name); /** * Get the current location of a basestation. * @param station_id The basestation to get the location of. * @pre IsValidBaseStation(station_id). * @return The tile the basestation sign above it. * @note The tile is not necessarily a station tile (and if it is, it could also belong to another station). * @see ScriptTileList_StationType. */ static TileIndex GetLocation(StationID station_id); /** * Get the last date a station part was added to this station. * @param station_id The station to look at. * @return The last date some part of this station was build. */ static ScriptDate::Date GetConstructionDate(StationID station_id); }; #endif /* SCRIPT_BASESTATION_HPP */ openttd-1.5.3/src/script/api/script_industrylist.cpp0000644000000000000000000000275512627373434021430 0ustar rootroot/* $Id: script_industrylist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_industrylist.cpp Implementation of ScriptIndustryList and friends. */ #include "../../stdafx.h" #include "script_industrylist.hpp" #include "../../industry.h" #include "../../safeguards.h" ScriptIndustryList::ScriptIndustryList() { Industry *i; FOR_ALL_INDUSTRIES(i) { this->AddItem(i->index); } } ScriptIndustryList_CargoAccepting::ScriptIndustryList_CargoAccepting(CargoID cargo_id) { const Industry *i; FOR_ALL_INDUSTRIES(i) { for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { if (i->accepts_cargo[j] == cargo_id) this->AddItem(i->index); } } } ScriptIndustryList_CargoProducing::ScriptIndustryList_CargoProducing(CargoID cargo_id) { const Industry *i; FOR_ALL_INDUSTRIES(i) { for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == cargo_id) this->AddItem(i->index); } } } openttd-1.5.3/src/script/api/script_subsidylist.hpp0000644000000000000000000000176712627373434021240 0ustar rootroot/* $Id: script_subsidylist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_subsidylist.hpp List all the subsidies. */ #ifndef SCRIPT_SUBSIDYLIST_HPP #define SCRIPT_SUBSIDYLIST_HPP #include "script_list.hpp" /** * Creates a list of all current subsidies. * @api ai game * @ingroup ScriptList */ class ScriptSubsidyList : public ScriptList { public: ScriptSubsidyList(); }; #endif /* SCRIPT_SUBSIDYLIST_HPP */ openttd-1.5.3/src/script/api/script_bridge.hpp0000644000000000000000000001461612627373433020112 0ustar rootroot/* $Id: script_bridge.hpp 26149 2013-12-08 15:44:09Z frosch $ */ /* * 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 script_bridge.hpp Everything to query and build bridges. */ #ifndef SCRIPT_BRIDGE_HPP #define SCRIPT_BRIDGE_HPP #include "script_vehicle.hpp" /** * Class that handles all bridge related functions. * @api ai game */ class ScriptBridge : public ScriptObject { public: /** * All bridge related error messages. */ enum ErrorMessages { /** Base for bridge related errors */ ERR_BRIDGE_BASE = ScriptError::ERR_CAT_BRIDGE << ScriptError::ERR_CAT_BIT_SIZE, /** * The bridge you want to build is not available yet, * or it is not available for the requested length. */ ERR_BRIDGE_TYPE_UNAVAILABLE, // [STR_ERROR_CAN_T_BUILD_BRIDGE_HERE] /** One (or more) of the bridge head(s) ends in water. */ ERR_BRIDGE_CANNOT_END_IN_WATER, // [STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH] /** The bride heads need to be on the same height */ ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, // [STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT] }; /** * Checks whether the given bridge type is valid. * @param bridge_id The bridge to check. * @return True if and only if the bridge type is valid. */ static bool IsValidBridge(BridgeID bridge_id); /** * Checks whether the given tile is actually a bridge start or end tile. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is the beginning or end of a bridge. */ static bool IsBridgeTile(TileIndex tile); /** * Get the BridgeID of a bridge at a given tile. * @param tile The tile to get the BridgeID from. * @pre IsBridgeTile(tile). * @return The BridgeID from the bridge at tile 'tile'. */ static BridgeID GetBridgeID(TileIndex tile); /** * Get the name of a bridge. * @param bridge_id The bridge to get the name of. * @pre IsValidBridge(bridge_id). * @return The name the bridge has. */ static char *GetName(BridgeID bridge_id); /** * Get the maximum speed of a bridge. * @param bridge_id The bridge to get the maximum speed of. * @pre IsValidBridge(bridge_id). * @return The maximum speed the bridge has. * @note The speed is in OpenTTD's internal speed unit. * This is mph / 1.6, which is roughly km/h. * To get km/h multiply this number by 1.00584. */ static int32 GetMaxSpeed(BridgeID bridge_id); /** * Get the new cost of a bridge, excluding the road and/or rail. * @param bridge_id The bridge to get the new cost of. * @param length The length of the bridge. * @pre IsValidBridge(bridge_id). * @return The new cost the bridge has. */ static Money GetPrice(BridgeID bridge_id, uint length); /** * Get the maximum length of a bridge. * @param bridge_id The bridge to get the maximum length of. * @pre IsValidBridge(bridge_id). * @returns The maximum length the bridge has. */ static int32 GetMaxLength(BridgeID bridge_id); /** * Get the minimum length of a bridge. * @param bridge_id The bridge to get the minimum length of. * @pre IsValidBridge(bridge_id). * @returns The minimum length the bridge has. */ static int32 GetMinLength(BridgeID bridge_id); /** * Internal function to help BuildBridge in case of road. * @api -all */ static bool _BuildBridgeRoad1(); /** * Internal function to help BuildBridge in case of road. * @api -all */ static bool _BuildBridgeRoad2(); /** * Build a bridge from one tile to the other. * As an extra for road, this functions builds two half-pieces of road on * each end of the bridge, making it easier for you to connect it to your * network. * @param vehicle_type The vehicle-type of bridge to build. * @param bridge_id The bridge-type to build. * @param start Where to start the bridge. * @param end Where to end the bridge. * @pre ScriptMap::IsValidTile(start). * @pre ScriptMap::IsValidTile(end). * @pre 'start' and 'end' are in a straight line, i.e. * ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or * ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end). * @pre vehicle_type == ScriptVehicle::VT_WATER || * (vehicle_type == ScriptVehicle::VT_ROAD && ScriptRoad::IsRoadTypeAvailable(ScriptRoad::GetCurrentRoadType())) || * (vehicle_type == ScriptVehicle::VT_RAIL && ScriptRail::IsRailTypeAvailable(ScriptRail::GetCurrentRailType())). * @game @pre Outside CompanyMode: vehicle_type == ScriptVehicle::VT_ROAD. * @exception ScriptError::ERR_ALREADY_BUILT * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @exception ScriptBridge::ERR_BRIDGE_TYPE_UNAVAILABLE * @exception ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER * @exception ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT * @return Whether the bridge has been/can be build or not. * @game @note Building a bridge (without CompanyMode) results in a bridge owned by towns. * @note No matter if the road pieces were build or not, if building the * bridge succeeded, this function returns true. */ static bool BuildBridge(ScriptVehicle::VehicleType vehicle_type, BridgeID bridge_id, TileIndex start, TileIndex end); /** * Removes a bridge, by executing it on either the start or end tile. * @param tile An end or start tile of the bridge. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the bridge has been/can be removed or not. */ static bool RemoveBridge(TileIndex tile); /** * Get the tile that is on the other end of a bridge starting at tile. * @param tile The tile that is an end of a bridge. * @pre ScriptMap::IsValidTile(tile). * @pre IsBridgeTile(tile). * @return The TileIndex that is the other end of the bridge. */ static TileIndex GetOtherBridgeEnd(TileIndex tile); }; #endif /* SCRIPT_BRIDGE_HPP */ openttd-1.5.3/src/script/api/script_storypagelist.hpp0000644000000000000000000000236012627373434021561 0ustar rootroot/* $Id: script_storypagelist.hpp 26304 2014-02-06 19:36:19Z zuu $ */ /* * 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 script_storypagelist.hpp List all story pages. */ #ifndef SCRIPT_STORYPAGELIST_HPP #define SCRIPT_STORYPAGELIST_HPP #include "script_list.hpp" #include "script_company.hpp" /** * Create a list of all story pages. * @api game * @ingroup ScriptList */ class ScriptStoryPageList : public ScriptList { public: /** * @param company The company to list story pages for, or ScriptCompany::COMPANY_INVALID to only show global pages. Global pages are always included independent of this parameter. */ ScriptStoryPageList(ScriptCompany::CompanyID company); }; #endif /* SCRIPT_STORYPAGELIST_HPP */ openttd-1.5.3/src/script/api/script_industry.hpp0000644000000000000000000001651112627373434020534 0ustar rootroot/* $Id: script_industry.hpp 23614 2011-12-19 20:57:23Z truebrain $ */ /* * 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 script_industry.hpp Everything to query and build industries. */ #ifndef SCRIPT_INDUSTRY_HPP #define SCRIPT_INDUSTRY_HPP #include "script_object.hpp" /** * Class that handles all industry related functions. * @api ai game */ class ScriptIndustry : public ScriptObject { public: /** Ways for an industry to accept a cargo. */ enum CargoAcceptState { CAS_NOT_ACCEPTED, ///< The CargoID is not accepted by this industry. CAS_ACCEPTED, ///< The industry currently accepts this CargoID. CAS_TEMP_REFUSED, ///< The industry temporarily refuses to accept this CargoID but may do so again in the future. }; /** * Gets the number of industries. * @return The number of industries. * @note The maximum valid IndustryID can be higher than the value returned. */ static int32 GetIndustryCount(); /** * Checks whether the given industry index is valid. * @param industry_id The index to check. * @return True if and only if the industry is valid. */ static bool IsValidIndustry(IndustryID industry_id); /** * Get the IndustryID of a tile, if there is an industry. * @param tile The tile to find the IndustryID of. * @return IndustryID of the industry. * @post Use IsValidIndustry() to see if the industry is valid. * @note GetIndustryID will return an invalid IndustryID for the * station tile of industries with a dock/heliport. */ static IndustryID GetIndustryID(TileIndex tile); /** * Get the name of the industry. * @param industry_id The industry to get the name of. * @pre IsValidIndustry(industry_id). * @return The name of the industry. */ static char *GetName(IndustryID industry_id); /** * See whether an industry currently accepts a certain cargo. * @param industry_id The index of the industry. * @param cargo_id The index of the cargo. * @pre IsValidIndustry(industry_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return Whether the industry accepts, temporarily refuses or never accepts this cargo. */ static CargoAcceptState IsCargoAccepted(IndustryID industry_id, CargoID cargo_id); /** * Get the amount of cargo stockpiled for processing. * @param industry_id The index of the industry. * @param cargo_id The index of the cargo. * @pre IsValidIndustry(industry_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return The amount of cargo that is waiting for processing. */ static int32 GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id); /** * Get the total last month's production of the given cargo at an industry. * @param industry_id The index of the industry. * @param cargo_id The index of the cargo. * @pre IsValidIndustry(industry_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return The last month's production of the given cargo for this industry. */ static int32 GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id); /** * Get the total amount of cargo transported from an industry last month. * @param industry_id The index of the industry. * @param cargo_id The index of the cargo. * @pre IsValidIndustry(industry_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return The amount of given cargo transported from this industry last month. */ static int32 GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id); /** * Get the percentage of cargo transported from an industry last month. * @param industry_id The index of the industry. * @param cargo_id The index of the cargo. * @pre IsValidIndustry(industry_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return The percentage of given cargo transported from this industry last month. */ static int32 GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id); /** * Gets the location of the industry. * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @return The location of the industry. */ static TileIndex GetLocation(IndustryID industry_id); /** * Get the number of stations around an industry. All stations that can * service the industry are counted, your own stations but also your * opponents stations. * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @return The number of stations around an industry. */ static int32 GetAmountOfStationsAround(IndustryID industry_id); /** * Get the manhattan distance from the tile to the ScriptIndustry::GetLocation() * of the industry. * @param industry_id The industry to get the distance to. * @param tile The tile to get the distance to. * @pre IsValidIndustry(industry_id). * @pre ScriptMap::IsValidTile(tile). * @return The distance between industry and tile. */ static int32 GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile); /** * Get the square distance from the tile to the ScriptIndustry::GetLocation() * of the industry. * @param industry_id The industry to get the distance to. * @param tile The tile to get the distance to. * @pre IsValidIndustry(industry_id). * @pre ScriptMap::IsValidTile(tile). * @return The distance between industry and tile. */ static int32 GetDistanceSquareToTile(IndustryID industry_id, TileIndex tile); /** * Is this industry built on water. * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @return True when the industry is built on water. */ static bool IsBuiltOnWater(IndustryID industry_id); /** * Does this industry have a heliport? * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @return True when the industry has a heliport. */ static bool HasHeliport(IndustryID industry_id); /** * Gets the location of the industry's heliport. * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @pre HasHeliport(industry_id). * @return The location of the industry's heliport. */ static TileIndex GetHeliportLocation(IndustryID industry_id); /** * Does this industry have a dock? * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @return True when the industry has a dock. */ static bool HasDock(IndustryID industry_id); /** * Gets the location of the industry's dock. * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @pre HasDock(industry_id). * @return The location of the industry's dock. */ static TileIndex GetDockLocation(IndustryID industry_id); /** * Get the IndustryType of the industry. * @param industry_id The index of the industry. * @pre IsValidIndustry(industry_id). * @return The IndustryType of the industry. */ static IndustryType GetIndustryType(IndustryID industry_id); }; #endif /* SCRIPT_INDUSTRY_HPP */ openttd-1.5.3/src/script/api/script_stationlist.hpp0000644000000000000000000002322312627373434021226 0ustar rootroot/* $Id: script_stationlist.hpp 27003 2014-10-12 18:41:53Z rubidium $ */ /* * 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 script_stationlist.hpp List all the stations (you own). */ #ifndef SCRIPT_STATIONLIST_HPP #define SCRIPT_STATIONLIST_HPP #include "script_list.hpp" #include "script_station.hpp" /** * Creates a list of stations of which you are the owner. * @api ai game * @ingroup ScriptList */ class ScriptStationList : public ScriptList { public: /** * @param station_type The type of station to make a list of stations for. */ ScriptStationList(ScriptStation::StationType station_type); }; /** * Creates a list of stations associated with cargo at a station. This is very generic. Use the * subclasses for all practical purposes. * @api ai game * @ingroup ScriptList */ class ScriptStationList_Cargo : public ScriptList { public: /** * Criteria of selecting and grouping cargo at a station. */ enum CargoSelector { CS_BY_FROM, ///< Group by origin station. CS_VIA_BY_FROM, ///< Select by next hop and group by origin station. CS_BY_VIA, ///< Group by next hop. CS_FROM_BY_VIA ///< Select by origin station and group by next hop. }; /** * Ways of associating cargo to stations. */ enum CargoMode { CM_WAITING, ///< Waiting cargo. CM_PLANNED ///< Planned cargo. }; /** * Creates a list of stations associated with cargo in the specified way, selected and grouped * by the chosen criteria. * @param mode Mode of association, either waiting cargo or planned cargo. * @param selector Mode of grouping and selecting to be applied. * @param station_id Station to be queried. * @param cargo Cargo type to query for. * @param other_station Other station to restrict the query with. */ ScriptStationList_Cargo(ScriptStationList_Cargo::CargoMode mode, ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo, StationID other_station); protected: /** * Creates an empty list. */ ScriptStationList_Cargo() {} }; /** * Creates a list of stations associated with cargo waiting at a station. This is very generic. Use * the subclasses for all practical purposes. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoWaiting : public ScriptStationList_Cargo { protected: friend class ScriptStationList_Cargo; /** * Creates an empty list. */ ScriptStationList_CargoWaiting() {} /** * Add waiting cargo to the list. * @param station_id Station to query for waiting cargo. * @param cargo Cargo type to query for. * @param other_station Other station to restrict the query with. */ template void Add(StationID station_id, CargoID cargo, StationID other_station = INVALID_STATION); public: /** * Creates a list of stations associated with waiting cargo, selected and grouped by the chosen * criteria. * @param selector Mode of grouping and selecting to be applied. * @param station_id Station to be queried. * @param cargo Cargo type to query for. * @param other_station Other station to restrict the query with. */ ScriptStationList_CargoWaiting(ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo, StationID other_station); }; /** * Creates a list of stations associated with cargo planned to pass a station. This is very * generic. Use the subclasses for all practical purposes. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoPlanned : public ScriptStationList_Cargo { protected: friend class ScriptStationList_Cargo; /** * Creates an empty list. */ ScriptStationList_CargoPlanned() {} /** * Add planned cargo to the list. * @param station_id Station to query for waiting cargo. * @param cargo Cargo type to query for. * @param other_station Other station to restrict the query with. */ template void Add(StationID station_id, CargoID cargo, StationID other_station = INVALID_STATION); public: /** * Creates a list of stations associated with cargo planned to pass the station, selected and * grouped by the chosen criteria. * @param selector Mode of grouping and selecting to be applied. * @param station_id Station to be queried. * @param cargo Cargo type to query for. * @param other_station Other station to restrict the query with. */ ScriptStationList_CargoPlanned(ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo, StationID other_station); }; /** * Creates a list of origin stations of waiting cargo at a station, with the amounts of cargo * waiting from each of those origin stations as values. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoWaitingByFrom : public ScriptStationList_CargoWaiting { public: /** * @param station_id Station to query for waiting cargo. * @param cargo Cargo type to query for. */ ScriptStationList_CargoWaitingByFrom(StationID station_id, CargoID cargo); }; /** * Creates a list of origin stations of cargo waiting at a station for a transfer via another * station, with the amounts of cargo waiting from each of those origin stations as values. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoWaitingViaByFrom : public ScriptStationList_CargoWaiting { public: /** * @param station_id Station to query for waiting cargo. * @param cargo Cargo type to query for. * @param via Next hop to restrict the query with. */ ScriptStationList_CargoWaitingViaByFrom(StationID station_id, CargoID cargo, StationID via); }; /** * Creates a list of next hops of waiting cargo at a station, with the amounts of cargo waiting for * each of those next hops as values. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoWaitingByVia : public ScriptStationList_CargoWaiting { public: /** * @param station_id Station to query for waiting cargo. * @param cargo Cargo type to query for. */ ScriptStationList_CargoWaitingByVia(StationID station_id, CargoID cargo); }; /** * Creates a list of next hops of waiting cargo from a specific station at another station, with * the amounts of cargo waiting for each of those next hops as values. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoWaitingFromByVia : public ScriptStationList_CargoWaiting { public: /** * @param station_id Station to query for waiting cargo. * @param cargo Cargo type to query for. * @param from Origin station to restrict the query with. */ ScriptStationList_CargoWaitingFromByVia(StationID station_id, CargoID cargo, StationID from); }; /** * Creates a list of origin stations of cargo planned to pass a station, with the monthly amounts * of cargo planned for each of those origin stations as values. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoPlannedByFrom : public ScriptStationList_CargoPlanned { public: /** * @param station_id Station to query for planned flows. * @param cargo Cargo type to query for. */ ScriptStationList_CargoPlannedByFrom(StationID station_id, CargoID cargo); }; /** * Creates a list of origin stations of cargo planned to pass a station going via another station, * with the monthly amounts of cargo planned for each of those origin stations as values. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoPlannedViaByFrom : public ScriptStationList_CargoPlanned { public: /** * @param station_id Station to query for planned flows. * @param cargo Cargo type to query for. * @param via Next hop to restrict the query with. */ ScriptStationList_CargoPlannedViaByFrom(StationID station_id, CargoID cargo, StationID via); }; /** * Creates a list of next hops of cargo planned to pass a station, with the monthly amounts of * cargo planned for each of those next hops as values. * Cargo planned to go "via" the station being queried will actually be delivered there. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoPlannedByVia : public ScriptStationList_CargoPlanned { public: /** * @param station_id Station to query for planned flows. * @param cargo Cargo type to query for. */ ScriptStationList_CargoPlannedByVia(StationID station_id, CargoID cargo); }; /** * Creates a list of next hops of cargo planned to pass a station and originating from another * station, with the monthly amounts of cargo planned for each of those next hops as values. * Cargo planned to go "via" the station being queried will actually be delivered there. * @api ai game * @ingroup ScriptList */ class ScriptStationList_CargoPlannedFromByVia : public ScriptStationList_CargoPlanned { public: /** * @param station_id Station to query for planned flows. * @param cargo Cargo type to query for. * @param from Origin station to restrict the query with. */ ScriptStationList_CargoPlannedFromByVia(StationID station_id, CargoID cargo, StationID from); }; /** * Creates a list of stations which the vehicle has in its orders. * @api ai game * @ingroup ScriptList */ class ScriptStationList_Vehicle : public ScriptList { public: /** * @param vehicle_id The vehicle to get the list of stations he has in its orders from. */ ScriptStationList_Vehicle(VehicleID vehicle_id); }; #endif /* SCRIPT_STATIONLIST_HPP */ openttd-1.5.3/src/script/api/script_airport.cpp0000644000000000000000000001345712627373434020334 0ustar rootroot/* $Id: script_airport.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_airport.cpp Implementation of ScriptAirport. */ #include "../../stdafx.h" #include "script_airport.hpp" #include "script_station.hpp" #include "../../station_base.h" #include "../../town.h" #include "../../safeguards.h" /* static */ bool ScriptAirport::IsValidAirportType(AirportType type) { return IsAirportInformationAvailable(type) && ::AirportSpec::Get(type)->IsAvailable(); } /* static */ bool ScriptAirport::IsAirportInformationAvailable(AirportType type) { return type >= 0 && type < (AirportType)NUM_AIRPORTS && AirportSpec::Get(type)->enabled; } /* static */ Money ScriptAirport::GetPrice(AirportType type) { if (!IsValidAirportType(type)) return -1; const AirportSpec *as = ::AirportSpec::Get(type); return _price[PR_BUILD_STATION_AIRPORT] * as->size_x * as->size_y; } /* static */ bool ScriptAirport::IsHangarTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_STATION) && ::IsHangar(tile); } /* static */ bool ScriptAirport::IsAirportTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_STATION) && ::IsAirport(tile); } /* static */ int32 ScriptAirport::GetAirportWidth(AirportType type) { if (!IsAirportInformationAvailable(type)) return -1; return ::AirportSpec::Get(type)->size_x; } /* static */ int32 ScriptAirport::GetAirportHeight(AirportType type) { if (!IsAirportInformationAvailable(type)) return -1; return ::AirportSpec::Get(type)->size_y; } /* static */ int32 ScriptAirport::GetAirportCoverageRadius(AirportType type) { if (!IsAirportInformationAvailable(type)) return -1; return _settings_game.station.modified_catchment ? ::AirportSpec::Get(type)->catchment : (uint)CA_UNMODIFIED; } /* static */ bool ScriptAirport::BuildAirport(TileIndex tile, AirportType type, StationID station_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsValidAirportType(type)); EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id)); uint p2 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 1; p2 |= (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16; return ScriptObject::DoCommand(tile, type, p2, CMD_BUILD_AIRPORT); } /* static */ bool ScriptAirport::RemoveAirport(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)) EnforcePrecondition(false, IsAirportTile(tile) || IsHangarTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ int32 ScriptAirport::GetNumHangars(TileIndex tile) { if (!::IsValidTile(tile)) return -1; if (!::IsTileType(tile, MP_STATION)) return -1; const Station *st = ::Station::GetByTile(tile); if (st->owner != ScriptObject::GetCompany() && ScriptObject::GetCompany() != OWNER_DEITY) return -1; if ((st->facilities & FACIL_AIRPORT) == 0) return -1; return st->airport.GetNumHangars(); } /* static */ TileIndex ScriptAirport::GetHangarOfAirport(TileIndex tile) { if (!::IsValidTile(tile)) return INVALID_TILE; if (!::IsTileType(tile, MP_STATION)) return INVALID_TILE; if (GetNumHangars(tile) < 1) return INVALID_TILE; const Station *st = ::Station::GetByTile(tile); if (st->owner != ScriptObject::GetCompany() && ScriptObject::GetCompany() != OWNER_DEITY) return INVALID_TILE; if ((st->facilities & FACIL_AIRPORT) == 0) return INVALID_TILE; return st->airport.GetHangarTile(0); } /* static */ ScriptAirport::AirportType ScriptAirport::GetAirportType(TileIndex tile) { if (!ScriptTile::IsStationTile(tile)) return AT_INVALID; StationID station_id = ::GetStationIndex(tile); if (!ScriptStation::HasStationType(station_id, ScriptStation::STATION_AIRPORT)) return AT_INVALID; return (AirportType)::Station::Get(station_id)->airport.type; } /* static */ int ScriptAirport::GetNoiseLevelIncrease(TileIndex tile, AirportType type) { extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it); extern uint8 GetAirportNoiseLevelForTown(const AirportSpec *as, TileIterator &it, TileIndex town_tile); if (!::IsValidTile(tile)) return -1; if (!IsAirportInformationAvailable(type)) return -1; if (_settings_game.economy.station_noise_level) { const AirportSpec *as = ::AirportSpec::Get(type); AirportTileTableIterator it(as->table[0], tile); const Town *t = AirportGetNearestTown(as, it); return GetAirportNoiseLevelForTown(as, it, t->xy); } return 1; } /* static */ TownID ScriptAirport::GetNearestTown(TileIndex tile, AirportType type) { extern Town *AirportGetNearestTown(const AirportSpec *as, const TileIterator &it); if (!::IsValidTile(tile)) return INVALID_TOWN; if (!IsAirportInformationAvailable(type)) return INVALID_TOWN; const AirportSpec *as = AirportSpec::Get(type); return AirportGetNearestTown(as, AirportTileTableIterator(as->table[0], tile))->index; } /* static */ uint16 ScriptAirport::GetMaintenanceCostFactor(AirportType type) { if (!IsAirportInformationAvailable(type)) return INVALID_TOWN; return AirportSpec::Get(type)->maintenance_cost; } openttd-1.5.3/src/script/api/script_industrytype.cpp0000644000000000000000000001326312627373434021432 0ustar rootroot/* $Id: script_industrytype.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_industrytype.cpp Implementation of ScriptIndustryType. */ #include "../../stdafx.h" #include "script_industrytype.hpp" #include "script_map.hpp" #include "script_error.hpp" #include "../../strings_func.h" #include "../../industry.h" #include "../../newgrf_industries.h" #include "../../core/random_func.hpp" #include "../../safeguards.h" /* static */ bool ScriptIndustryType::IsValidIndustryType(IndustryType industry_type) { if (industry_type >= NUM_INDUSTRYTYPES) return false; return ::GetIndustrySpec(industry_type)->enabled; } /* static */ bool ScriptIndustryType::IsRawIndustry(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; return ::GetIndustrySpec(industry_type)->IsRawIndustry(); } /* static */ bool ScriptIndustryType::IsProcessingIndustry(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; return ::GetIndustrySpec(industry_type)->IsProcessingIndustry(); } /* static */ bool ScriptIndustryType::ProductionCanIncrease(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; if (_settings_game.game_creation.landscape != LT_TEMPERATE) return true; return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_DONT_INCR_PROD) == 0; } /* static */ Money ScriptIndustryType::GetConstructionCost(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return -1; if (::GetIndustrySpec(industry_type)->IsRawIndustry() && _settings_game.construction.raw_industry_construction == 0) return -1; return ::GetIndustrySpec(industry_type)->GetConstructionCost(); } /* static */ char *ScriptIndustryType::GetName(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return NULL; return GetString(::GetIndustrySpec(industry_type)->name); } /* static */ ScriptList *ScriptIndustryType::GetProducedCargo(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return NULL; const IndustrySpec *ins = ::GetIndustrySpec(industry_type); ScriptList *list = new ScriptList(); for (size_t i = 0; i < lengthof(ins->produced_cargo); i++) { if (ins->produced_cargo[i] != CT_INVALID) list->AddItem(ins->produced_cargo[i]); } return list; } /* static */ ScriptList *ScriptIndustryType::GetAcceptedCargo(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return NULL; const IndustrySpec *ins = ::GetIndustrySpec(industry_type); ScriptList *list = new ScriptList(); for (size_t i = 0; i < lengthof(ins->accepts_cargo); i++) { if (ins->accepts_cargo[i] != CT_INVALID) list->AddItem(ins->accepts_cargo[i]); } return list; } /* static */ bool ScriptIndustryType::CanBuildIndustry(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; const bool deity = ScriptObject::GetCompany() == OWNER_DEITY; if (::GetIndustryProbabilityCallback(industry_type, deity ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) return false; if (deity) return true; if (!::GetIndustrySpec(industry_type)->IsRawIndustry()) return true; /* raw_industry_construction == 1 means "Build as other industries" */ return _settings_game.construction.raw_industry_construction == 1; } /* static */ bool ScriptIndustryType::CanProspectIndustry(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; const bool deity = ScriptObject::GetCompany() == OWNER_DEITY; if (!deity && !::GetIndustrySpec(industry_type)->IsRawIndustry()) return false; if (::GetIndustryProbabilityCallback(industry_type, deity ? IACT_RANDOMCREATION : IACT_USERCREATION, 1) == 0) return false; /* raw_industry_construction == 2 means "prospect" */ return deity || _settings_game.construction.raw_industry_construction == 2; } /* static */ bool ScriptIndustryType::BuildIndustry(IndustryType industry_type, TileIndex tile) { EnforcePrecondition(false, CanBuildIndustry(industry_type)); EnforcePrecondition(false, ScriptMap::IsValidTile(tile)); uint32 seed = ::InteractiveRandom(); return ScriptObject::DoCommand(tile, (1 << 16) | (::InteractiveRandomRange(::GetIndustrySpec(industry_type)->num_table) << 8) | industry_type, seed, CMD_BUILD_INDUSTRY); } /* static */ bool ScriptIndustryType::ProspectIndustry(IndustryType industry_type) { EnforcePrecondition(false, CanProspectIndustry(industry_type)); uint32 seed = ::InteractiveRandom(); return ScriptObject::DoCommand(0, industry_type, seed, CMD_BUILD_INDUSTRY); } /* static */ bool ScriptIndustryType::IsBuiltOnWater(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0; } /* static */ bool ScriptIndustryType::HasHeliport(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0; } /* static */ bool ScriptIndustryType::HasDock(IndustryType industry_type) { if (!IsValidIndustryType(industry_type)) return false; return (::GetIndustrySpec(industry_type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0; } openttd-1.5.3/src/script/api/script_story_page.cpp0000644000000000000000000001655612627373434021033 0ustar rootroot/* $Id: script_story_page.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_story_page.cpp Implementation of ScriptStoryPage. */ #include "../../stdafx.h" #include "script_story_page.hpp" #include "script_error.hpp" #include "script_industry.hpp" #include "script_map.hpp" #include "script_town.hpp" #include "script_goal.hpp" #include "../script_instance.hpp" #include "../../story_base.h" #include "../../goal_base.h" #include "../../string_func.h" #include "../../tile_map.h" #include "../../safeguards.h" /* static */ bool ScriptStoryPage::IsValidStoryPage(StoryPageID story_page_id) { return ::StoryPage::IsValidID(story_page_id); } /* static */ bool ScriptStoryPage::IsValidStoryPageElement(StoryPageElementID story_page_element_id) { return ::StoryPageElement::IsValidID(story_page_element_id); } /* static */ ScriptStoryPage::StoryPageID ScriptStoryPage::New(ScriptCompany::CompanyID company, Text *title) { CCountedPtr counter(title); EnforcePrecondition(STORY_PAGE_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(STORY_PAGE_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); uint8 c = company; if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; if (!ScriptObject::DoCommand(0, c, 0, CMD_CREATE_STORY_PAGE, title != NULL? title->GetEncodedText() : NULL, &ScriptInstance::DoCommandReturnStoryPageID)) return STORY_PAGE_INVALID; /* In case of test-mode, we return StoryPageID 0 */ return (ScriptStoryPage::StoryPageID)0; } /* static */ ScriptStoryPage::StoryPageElementID ScriptStoryPage::NewElement(StoryPageID story_page_id, StoryPageElementType type, uint32 reference, Text *text) { CCountedPtr counter(text); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, IsValidStoryPage(story_page_id)); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && !StrEmpty(text->GetEncodedText()))); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_LOCATION || ::IsValidTile(reference)); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_GOAL || ScriptGoal::IsValidGoal((ScriptGoal::GoalID)reference)); EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_GOAL || !(StoryPage::Get(story_page_id)->company == INVALID_COMPANY && Goal::Get(reference)->company != INVALID_COMPANY)); if (!ScriptObject::DoCommand(type == SPET_LOCATION ? reference : 0, story_page_id + (type << 16), type == SPET_GOAL ? reference : 0, CMD_CREATE_STORY_PAGE_ELEMENT, type == SPET_TEXT || type == SPET_LOCATION ? text->GetEncodedText() : NULL, &ScriptInstance::DoCommandReturnStoryPageElementID)) return STORY_PAGE_ELEMENT_INVALID; /* In case of test-mode, we return StoryPageElementID 0 */ return (ScriptStoryPage::StoryPageElementID)0; } /* static */ bool ScriptStoryPage::UpdateElement(StoryPageElementID story_page_element_id, uint32 reference, Text *text) { CCountedPtr counter(text); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, IsValidStoryPageElement(story_page_element_id)); StoryPageElement *pe = StoryPageElement::Get(story_page_element_id); StoryPage *p = StoryPage::Get(pe->page); ::StoryPageElementType type = pe->type; EnforcePrecondition(false, (type != ::SPET_TEXT && type != ::SPET_LOCATION) || (text != NULL && !StrEmpty(text->GetEncodedText()))); EnforcePrecondition(false, type != ::SPET_LOCATION || ::IsValidTile(reference)); EnforcePrecondition(false, type != ::SPET_GOAL || ScriptGoal::IsValidGoal((ScriptGoal::GoalID)reference)); EnforcePrecondition(false, type != ::SPET_GOAL || !(p->company == INVALID_COMPANY && Goal::Get(reference)->company != INVALID_COMPANY)); return ScriptObject::DoCommand(type == ::SPET_LOCATION ? reference : 0, story_page_element_id, type == ::SPET_GOAL ? reference : 0, CMD_UPDATE_STORY_PAGE_ELEMENT, type == ::SPET_TEXT || type == ::SPET_LOCATION ? text->GetEncodedText() : NULL); } /* static */ uint32 ScriptStoryPage::GetPageSortValue(StoryPageID story_page_id) { EnforcePrecondition(false, IsValidStoryPage(story_page_id)); return StoryPage::Get(story_page_id)->sort_value; } /* static */ uint32 ScriptStoryPage::GetPageElementSortValue(StoryPageElementID story_page_element_id) { EnforcePrecondition(false, IsValidStoryPageElement(story_page_element_id)); return StoryPageElement::Get(story_page_element_id)->sort_value; } /* static */ bool ScriptStoryPage::SetTitle(StoryPageID story_page_id, Text *title) { CCountedPtr counter(title); EnforcePrecondition(false, IsValidStoryPage(story_page_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); return ScriptObject::DoCommand(0, story_page_id, 0, CMD_SET_STORY_PAGE_TITLE, title != NULL? title->GetEncodedText() : NULL); } /* static */ ScriptCompany::CompanyID ScriptStoryPage::GetCompany(StoryPageID story_page_id) { EnforcePrecondition(ScriptCompany::COMPANY_INVALID, IsValidStoryPage(story_page_id)); CompanyID c = StoryPage::Get(story_page_id)->company; ScriptCompany::CompanyID company = c == INVALID_COMPANY ? ScriptCompany::COMPANY_INVALID : (ScriptCompany::CompanyID)c; return company; } /* static */ ScriptDate::Date ScriptStoryPage::GetDate(StoryPageID story_page_id) { EnforcePrecondition(ScriptDate::DATE_INVALID, IsValidStoryPage(story_page_id)); EnforcePrecondition(ScriptDate::DATE_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); return (ScriptDate::Date)StoryPage::Get(story_page_id)->date; } /* static */ bool ScriptStoryPage::SetDate(StoryPageID story_page_id, ScriptDate::Date date) { EnforcePrecondition(false, IsValidStoryPage(story_page_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); return ScriptObject::DoCommand(0, story_page_id, date, CMD_SET_STORY_PAGE_DATE, NULL); } /* static */ bool ScriptStoryPage::Show(StoryPageID story_page_id) { EnforcePrecondition(false, IsValidStoryPage(story_page_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); return ScriptObject::DoCommand(0, story_page_id, 0, CMD_SHOW_STORY_PAGE); } /* static */ bool ScriptStoryPage::Remove(StoryPageID story_page_id) { EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, IsValidStoryPage(story_page_id)); return ScriptObject::DoCommand(0, story_page_id, 0, CMD_REMOVE_STORY_PAGE); } /* static */ bool ScriptStoryPage::RemoveElement(StoryPageElementID story_page_element_id) { EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, IsValidStoryPageElement(story_page_element_id)); return ScriptObject::DoCommand(0, story_page_element_id, 0, CMD_REMOVE_STORY_PAGE_ELEMENT); } openttd-1.5.3/src/script/api/script_tunnel.hpp0000644000000000000000000001160412627373434020156 0ustar rootroot/* $Id: script_tunnel.hpp 26149 2013-12-08 15:44:09Z frosch $ */ /* * 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 script_tunnel.hpp Everything to query and build tunnels. */ #ifndef SCRIPT_TUNNEL_HPP #define SCRIPT_TUNNEL_HPP #include "script_vehicle.hpp" /** * Class that handles all tunnel related functions. * @api ai game */ class ScriptTunnel : public ScriptObject { public: /** * All tunnel related errors. */ enum ErrorMessages { /** Base for bridge related errors */ ERR_TUNNEL_BASE = ScriptError::ERR_CAT_TUNNEL << ScriptError::ERR_CAT_BIT_SIZE, /** Can't build tunnels on water */ ERR_TUNNEL_CANNOT_BUILD_ON_WATER, // [STR_ERROR_CAN_T_BUILD_ON_WATER] /** The start tile must slope either North, South, West or East */ ERR_TUNNEL_START_SITE_UNSUITABLE, // [STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL] /** Another tunnel is in the way */ ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY, // [STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY] /** Unable to excavate land at the end to create the tunnel's exit */ ERR_TUNNEL_END_SITE_UNSUITABLE, // [STR_ERROR_UNABLE_TO_EXCAVATE_LAND] }; /** * Check whether the tile is an entrance to a tunnel. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is the beginning or end of a tunnel. */ static bool IsTunnelTile(TileIndex tile); /** * Get the tile that exits on the other end of a (would be) tunnel starting * at tile. If there is no 'simple' inclined slope at the start tile, * this function will return ScriptMap::TILE_INVALID. * @param tile The tile that is an entrance to a tunnel or the tile where you may want to build a tunnel. * @pre ScriptMap::IsValidTile(tile). * @return The TileIndex that is the other end of the (would be) tunnel, or * ScriptMap::TILE_INVALID if no other end was found (can't build tunnel). * @note Even if this function returns a valid tile, that is no guarantee * that building a tunnel will succeed. Use BuildTunnel in ScriptTestMode to * check whether a tunnel can actually be build. */ static TileIndex GetOtherTunnelEnd(TileIndex tile); /** * Internal function to help BuildTunnel in case of road. * @api -all */ static bool _BuildTunnelRoad1(); /** * Internal function to help BuildTunnel in case of road. * @api -all */ static bool _BuildTunnelRoad2(); /** * Builds a tunnel starting at start. The direction of the tunnel depends * on the slope of the start tile. Tunnels can be created for either * rails or roads; use the appropriate ScriptVehicle::VehicleType. * As an extra for road, this functions builds two half-pieces of road on * each end of the tunnel, making it easier for you to connect it to your * network. * @param start Where to start the tunnel. * @param vehicle_type The vehicle-type of tunnel to build. * @pre ScriptMap::IsValidTile(start). * @pre (vehicle_type == ScriptVehicle::VT_ROAD && ScriptRoad::IsRoadTypeAvailable(ScriptRoad::GetCurrentRoadType())) || * (vehicle_type == ScriptVehicle::VT_RAIL && ScriptRail::IsRailTypeAvailable(ScriptRail::GetCurrentRailType())). * @game @pre Outside CompanyMode: vehicle_type == ScriptVehicle::VT_ROAD. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptTunnel::ERR_TUNNEL_CANNOT_BUILD_ON_WATER * @exception ScriptTunnel::ERR_TUNNEL_START_SITE_UNSUITABLE * @exception ScriptTunnel::ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY * @exception ScriptTunnel::ERR_TUNNEL_END_SITE_UNSUITABLE * @return Whether the tunnel has been/can be build or not. * @note The slope of a tile can be determined by ScriptTile::GetSlope(TileIndex). * @note No matter if the road pieces were build or not, if building the * tunnel succeeded, this function returns true. * @game @note Building a bridge (without CompanyMode) results in a bridge owned by towns. */ static bool BuildTunnel(ScriptVehicle::VehicleType vehicle_type, TileIndex start); /** * Remove the tunnel whose entrance is located at tile. * @param tile The tile that is an entrance to a tunnel. * @pre ScriptMap::IsValidTile(tile) && IsTunnelTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the tunnel has been/can be removed or not. */ static bool RemoveTunnel(TileIndex tile); }; #endif /* SCRIPT_TUNNEL_HPP */ openttd-1.5.3/src/script/api/script_log.cpp0000644000000000000000000000534312627373433017427 0ustar rootroot/* $Id: script_log.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 script_log.cpp Implementation of ScriptLog. */ #include "../../stdafx.h" #include "script_log.hpp" #include "../../core/alloc_func.hpp" #include "../../debug.h" #include "../../window_func.h" #include "../../string_func.h" #include "../../safeguards.h" /* static */ void ScriptLog::Info(const char *message) { ScriptLog::Log(LOG_INFO, message); } /* static */ void ScriptLog::Warning(const char *message) { ScriptLog::Log(LOG_WARNING, message); } /* static */ void ScriptLog::Error(const char *message) { ScriptLog::Log(LOG_ERROR, message); } /* static */ void ScriptLog::Log(ScriptLog::ScriptLogType level, const char *message) { if (ScriptObject::GetLogPointer() == NULL) { ScriptObject::GetLogPointer() = new LogData(); LogData *log = (LogData *)ScriptObject::GetLogPointer(); log->lines = CallocT(400); log->type = CallocT(400); log->count = 400; log->pos = log->count - 1; log->used = 0; } LogData *log = (LogData *)ScriptObject::GetLogPointer(); /* Go to the next log-line */ log->pos = (log->pos + 1) % log->count; if (log->used != log->count) log->used++; /* Free last message, and write new message */ free(log->lines[log->pos]); log->lines[log->pos] = stredup(message); log->type[log->pos] = level; /* Cut string after first \n */ char *p; while ((p = strchr(log->lines[log->pos], '\n')) != NULL) { *p = '\0'; break; } char logc; switch (level) { case LOG_SQ_ERROR: logc = 'S'; break; case LOG_ERROR: logc = 'E'; break; case LOG_SQ_INFO: logc = 'P'; break; case LOG_WARNING: logc = 'W'; break; case LOG_INFO: logc = 'I'; break; default: logc = '?'; break; } /* Also still print to debug window */ DEBUG(script, level, "[%d] [%c] %s", (uint)ScriptObject::GetRootCompany(), logc, log->lines[log->pos]); InvalidateWindowData(WC_AI_DEBUG, 0, ScriptObject::GetRootCompany()); } /* static */ void ScriptLog::FreeLogPointer() { LogData *log = (LogData *)ScriptObject::GetLogPointer(); for (int i = 0; i < log->count; i++) { free(log->lines[i]); } free(log->lines); free(log->type); delete log; } openttd-1.5.3/src/script/api/script_grouplist.cpp0000644000000000000000000000174312627373434020677 0ustar rootroot/* $Id: script_grouplist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_grouplist.cpp Implementation of ScriptGroupList and friends. */ #include "../../stdafx.h" #include "script_grouplist.hpp" #include "../../group.h" #include "../../safeguards.h" ScriptGroupList::ScriptGroupList() { Group *g; FOR_ALL_GROUPS(g) { if (g->owner == ScriptObject::GetCompany()) this->AddItem(g->index); } } openttd-1.5.3/src/script/api/script_cargolist.cpp0000644000000000000000000000417312627373433020635 0ustar rootroot/* $Id: script_cargolist.cpp 26580 2014-05-11 18:02:11Z rubidium $ */ /* * 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 script_cargolist.cpp Implementation of ScriptCargoList and friends. */ #include "../../stdafx.h" #include "script_cargolist.hpp" #include "script_industry.hpp" #include "script_station.hpp" #include "../../cargotype.h" #include "../../industry.h" #include "../../station_base.h" #include "../../safeguards.h" ScriptCargoList::ScriptCargoList() { const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { this->AddItem(cs->Index()); } } ScriptCargoList_IndustryAccepting::ScriptCargoList_IndustryAccepting(IndustryID industry_id) { if (!ScriptIndustry::IsValidIndustry(industry_id)) return; Industry *ind = ::Industry::Get(industry_id); for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) { CargoID cargo_id = ind->accepts_cargo[i]; if (cargo_id != CT_INVALID) { this->AddItem(cargo_id); } } } ScriptCargoList_IndustryProducing::ScriptCargoList_IndustryProducing(IndustryID industry_id) { if (!ScriptIndustry::IsValidIndustry(industry_id)) return; Industry *ind = ::Industry::Get(industry_id); for (uint i = 0; i < lengthof(ind->produced_cargo); i++) { CargoID cargo_id = ind->produced_cargo[i]; if (cargo_id != CT_INVALID) { this->AddItem(cargo_id); } } } ScriptCargoList_StationAccepting::ScriptCargoList_StationAccepting(StationID station_id) { if (!ScriptStation::IsValidStation(station_id)) return; Station *st = ::Station::Get(station_id); for (CargoID i = 0; i < NUM_CARGO; i++) { if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) this->AddItem(i); } } openttd-1.5.3/src/script/api/squirrel_export.sh0000755000000000000000000001117312627373434020363 0ustar rootroot#!/bin/bash # $Id: squirrel_export.sh 23652 2011-12-21 15:06:00Z truebrain $ # 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 . # Set neutral locale so sort behaves the same everywhere LC_ALL=C export LC_ALL # We really need gawk for this! AWK=gawk ${AWK} --version > /dev/null 2> /dev/null if [ "$?" != "0" ]; then echo "This script needs gawk to run properly" exit 1 fi # This must be called from within a src/???/api directory. scriptdir=`dirname $0` apilc=`pwd | sed "s@/api@@;s@.*/@@"` # Check if we are in the root directory of the API, as then we generate all APIs if [ "$apilc" = "script" ]; then for api in `find -type d | cut -b3- | grep -v '\.svn\|/'`; do if [ -z "$api" ]; then continue; fi echo "Generating for API '$api' ..." cd $api sh $scriptdir/../`basename $0` cd .. done exit 0 fi case $apilc in template) apiuc="Template" ;; ai) apiuc="AI" ;; game) apiuc="GS" ;; *) echo "Unknown API type."; exit 1 ;; esac if [ -z "$1" ]; then for f in `ls ../*.hpp`; do bf=`basename ${f} | sed s@script_@${apilc}_@` # ScriptController has custom code, and should not be generated if [ "`basename ${f}`" = "script_controller.hpp" ]; then continue; fi if [ "`basename ${f}`" = "script_object.hpp" ]; then continue; fi ${AWK} -v api=${apiuc} -f ${scriptdir}/squirrel_export.awk ${f} > ${bf}.tmp if [ "`wc -l ${bf}.tmp | cut -d\ -f1`" = "0" ]; then if [ -f "${bf}.sq" ]; then echo "Deleted: ${bf}.sq" svn del --force ${bf}.sq > /dev/null 2>&1 fi rm -f ${bf}.tmp elif ! [ -f "${bf}.sq" ] || [ -n "`diff -I '$Id' ${bf}.tmp ${bf}.sq 2> /dev/null || echo boo`" ]; then mv ${bf}.tmp ${bf}.sq echo "Updated: ${bf}.sq" svn add ${bf}.sq > /dev/null 2>&1 svn propset svn:eol-style native ${bf}.sq > /dev/null 2>&1 svn propset svn:keywords Id ${bf}.sq > /dev/null 2>&1 else rm -f ${bf}.tmp fi done else ${AWK} -v api=${apiuc} -f ${scriptdir}/squirrel_export.awk $1 > $1.tmp if [ `wc -l $1.tmp | cut -d\ -f1` -eq "0" ]; then if [ -f "$1.sq" ]; then echo "Deleted: $1.sq" svn del --force $1.sq > /dev/null 2>&1 fi rm -f $1.tmp elif ! [ -f "${f}.sq" ] || [ -n "`diff -I '$Id' $1.sq $1.tmp 2> /dev/null || echo boo`" ]; then mv $1.tmp $1.sq echo "Updated: $1.sq" svn add $1.sq > /dev/null 2>&1 svn propset svn:eol-style native $1.sq > /dev/null 2>&1 svn propset svn:keywords Id $1.sq > /dev/null 2>&1 else rm -f $1.tmp fi fi # Remove .hpp.sq if .hpp doesn't exist anymore for f in `ls *.hpp.sq`; do f=`echo ${f} | sed "s/.hpp.sq$/.hpp/;s@${apilc}_@script_@"` if [ ! -f ../${f} ];then echo "Deleted: ${f}.sq" svn del --force ${f}.sq > /dev/null 2>&1 fi done if [ "$apilc" = "template" ]; then exit 0; fi # Add stuff to ${apilc}_instance.cpp f="../../../${apilc}/${apilc}_instance.cpp" functions=`` echo " { } /.hpp.sq/ { if (match(\$0, \"template\")) print \$0; next } /SQ${apiuc}Controller_Register/ { print \$0; next } /SQ${apiuc}.*_Register/ { next } /Note: this line is a marker in squirrel_export.sh. Do not change!/ { print \$0 gsub(\"^.*/\", \"\") split(\"`grep '^void SQ'${apiuc}'.*_Register(Squirrel \*engine)$' *.hpp.sq | sed 's/:.*$//' | sort | uniq | tr -d '\r' | tr '\n' ' '`\", files, \" \") for (i = 1; files[i] != \"\"; i++) { print \"#include \\\"../script/api/${apilc}/\" files[i] \"\\\"\" \$0 } next; } /\/\* Register all classes \*\// { print \$0 gsub(\"^.*/\", \"\") # List needs to be registered with squirrel before all List subclasses. print \" SQ${apiuc}List_Register(this->engine);\" \$0 split(\"`grep '^void SQ'${apiuc}'.*_Register(Squirrel \*engine)$' *.hpp.sq | grep -v 'SQ'${apiuc}'List_Register' | sed 's/^.*void //;s/Squirrel \*/this->/;s/$/;/;s/_Register/0000Register/g;' | sort | sed 's/0000Register/_Register/g' | tr -d '\r' | tr '\n' ' '`\", regs, \" \") for (i = 1; regs[i] != \"\"; i++) { if (regs[i] == \"SQ${apiuc}Controller_Register(this->engine);\") continue print \" \" regs[i] \$0 } next } { print \$0; } " > ${f}.awk ${AWK} -f ${f}.awk ${f} > ${f}.tmp if ! [ -f "${f}" ] || [ -n "`diff -I '$Id' ${f} ${f}.tmp 2> /dev/null || echo boo`" ]; then mv ${f}.tmp ${f} echo "Updated: ${f}" else rm -f ${f}.tmp fi rm -f ${f}.awk openttd-1.5.3/src/script/api/script_townlist.hpp0000644000000000000000000000225112627373434020532 0ustar rootroot/* $Id: script_townlist.hpp 23614 2011-12-19 20:57:23Z truebrain $ */ /* * 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 script_townlist.hpp List all the towns. */ #ifndef SCRIPT_TOWNLIST_HPP #define SCRIPT_TOWNLIST_HPP #include "script_list.hpp" /** * Creates a list of towns that are currently on the map. * @api ai game * @ingroup ScriptList */ class ScriptTownList : public ScriptList { public: ScriptTownList(); }; /** * Creates a list of all TownEffects known in the game. * @api ai game * @ingroup ScriptList */ class ScriptTownEffectList : public ScriptList { public: ScriptTownEffectList(); }; #endif /* SCRIPT_TOWNLIST_HPP */ openttd-1.5.3/src/script/api/script_execmode.cpp0000644000000000000000000000315612627373434020440 0ustar rootroot/* $Id: script_execmode.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_execmode.cpp Implementation of ScriptExecMode. */ #include "../../stdafx.h" #include "script_execmode.hpp" #include "../script_instance.hpp" #include "../script_fatalerror.hpp" #include "../../safeguards.h" bool ScriptExecMode::ModeProc() { /* In execution mode we only return 'true', telling the DoCommand it * should continue with the real execution of the command. */ return true; } ScriptExecMode::ScriptExecMode() { this->last_mode = this->GetDoCommandMode(); this->last_instance = this->GetDoCommandModeInstance(); this->SetDoCommandMode(&ScriptExecMode::ModeProc, this); } ScriptExecMode::~ScriptExecMode() { if (this->GetDoCommandModeInstance() != this) { /* Ignore this error if the script already died. */ if (!ScriptObject::GetActiveInstance()->IsDead()) { throw Script_FatalError("ScriptExecMode object was removed while it was not the latest *Mode object created."); } } this->SetDoCommandMode(this->last_mode, this->last_instance); } openttd-1.5.3/src/script/api/script_date.cpp0000644000000000000000000000370212627373434017561 0ustar rootroot/* $Id: script_date.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_date.cpp Implementation of ScriptDate. */ #include #include "../../stdafx.h" #include "script_date.hpp" #include "../../date_func.h" #include "../../safeguards.h" /* static */ bool ScriptDate::IsValidDate(Date date) { return date >= 0; } /* static */ ScriptDate::Date ScriptDate::GetCurrentDate() { return (ScriptDate::Date)_date; } /* static */ int32 ScriptDate::GetYear(ScriptDate::Date date) { if (date < 0) return DATE_INVALID; ::YearMonthDay ymd; ::ConvertDateToYMD(date, &ymd); return ymd.year; } /* static */ int32 ScriptDate::GetMonth(ScriptDate::Date date) { if (date < 0) return DATE_INVALID; ::YearMonthDay ymd; ::ConvertDateToYMD(date, &ymd); return ymd.month + 1; } /* static */ int32 ScriptDate::GetDayOfMonth(ScriptDate::Date date) { if (date < 0) return DATE_INVALID; ::YearMonthDay ymd; ::ConvertDateToYMD(date, &ymd); return ymd.day; } /* static */ ScriptDate::Date ScriptDate::GetDate(int32 year, int32 month, int32 day_of_month) { if (month < 1 || month > 12) return DATE_INVALID; if (day_of_month < 1 || day_of_month > 31) return DATE_INVALID; if (year < 0 || year > MAX_YEAR) return DATE_INVALID; return (ScriptDate::Date)::ConvertYMDToDate(year, month - 1, day_of_month); } /* static */ int32 ScriptDate::GetSystemTime() { time_t t; time(&t); return t; } openttd-1.5.3/src/script/api/script_road.cpp0000644000000000000000000005531312627373434017576 0ustar rootroot/* $Id: script_road.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_road.cpp Implementation of ScriptRoad. */ #include "../../stdafx.h" #include "script_map.hpp" #include "script_station.hpp" #include "script_cargo.hpp" #include "../../station_base.h" #include "../../script/squirrel_helper_type.hpp" #include "../../safeguards.h" /* static */ ScriptRoad::RoadVehicleType ScriptRoad::GetRoadVehicleTypeForCargo(CargoID cargo_type) { return ScriptCargo::HasCargoClass(cargo_type, ScriptCargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK; } /* static */ bool ScriptRoad::IsRoadTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) != ROAD_TILE_DEPOT) || IsDriveThroughRoadStationTile(tile); } /* static */ bool ScriptRoad::IsRoadDepotTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; return ::IsTileType(tile, MP_ROAD) && ::GetRoadTileType(tile) == ROAD_TILE_DEPOT && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; } /* static */ bool ScriptRoad::IsRoadStationTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; return ::IsRoadStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; } /* static */ bool ScriptRoad::IsDriveThroughRoadStationTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; return ::IsDriveThroughStopTile(tile) && (::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()) & ::GetRoadTypes(tile)) != 0; } /* static */ bool ScriptRoad::IsRoadTypeAvailable(RoadType road_type) { return ::IsValidRoadType((::RoadType)road_type) && ::HasRoadTypesAvail(ScriptObject::GetCompany(), ::RoadTypeToRoadTypes((::RoadType)road_type)); } /* static */ ScriptRoad::RoadType ScriptRoad::GetCurrentRoadType() { return (RoadType)ScriptObject::GetRoadType(); } /* static */ void ScriptRoad::SetCurrentRoadType(RoadType road_type) { if (!IsRoadTypeAvailable(road_type)) return; ScriptObject::SetRoadType((::RoadType)road_type); } /* static */ bool ScriptRoad::HasRoadType(TileIndex tile, RoadType road_type) { if (!ScriptMap::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(road_type)) return false; return ::GetAnyRoadBits(tile, (::RoadType)road_type, false) != ROAD_NONE; } /* static */ bool ScriptRoad::AreRoadTilesConnected(TileIndex t1, TileIndex t2) { if (!::IsValidTile(t1)) return false; if (!::IsValidTile(t2)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; /* Tiles not neighbouring */ if ((abs((int)::TileX(t1) - (int)::TileX(t2)) + abs((int)::TileY(t1) - (int)::TileY(t2))) != 1) return false; RoadBits r1 = ::GetAnyRoadBits(t1, ScriptObject::GetRoadType()); RoadBits r2 = ::GetAnyRoadBits(t2, ScriptObject::GetRoadType()); uint dir_1 = (::TileX(t1) == ::TileX(t2)) ? (::TileY(t1) < ::TileY(t2) ? 2 : 0) : (::TileX(t1) < ::TileX(t2) ? 1 : 3); uint dir_2 = 2 ^ dir_1; DisallowedRoadDirections drd2 = IsNormalRoadTile(t2) ? GetDisallowedRoadDirections(t2) : DRD_NONE; return HasBit(r1, dir_1) && HasBit(r2, dir_2) && drd2 != DRD_BOTH && drd2 != (dir_1 > dir_2 ? DRD_SOUTHBOUND : DRD_NORTHBOUND); } /* Helper functions for ScriptRoad::CanBuildConnectedRoadParts(). */ /** * Check whether the given existing bits the start and end part can be build. * As the function assumes the bits being build on a slope that does not * allow level foundations all of the existing parts will always be in * a straight line. This also needs to hold for the start and end parts, * otherwise it is for sure not valid. Finally a check will be done to * determine whether the existing road parts match the to-be-build parts. * As they can only be placed in one direction, just checking the start * part with the first existing part is enough. * @param existing The existing road parts. * @param start The part that should be build first. * @param end The part that will be build second. * @return True if and only if the road bits can be build. */ static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 end) { return (start + end == 0) && (existing->size == 0 || existing->array[0] == start || existing->array[0] == end); } /** * Lookup function for building road parts when building on slopes is disabled. * @param slope The slope of the tile to examine. * @param existing The existing road parts. * @param start The part that should be build first. * @param end The part that will be build second. * @return 0 when the build parts do not connect, 1 when they do connect once * they are build or 2 when building the first part automatically * builds the second part. */ static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end) { switch (slope) { /* Flat slopes can always be build. */ case SLOPE_FLAT: return 1; /* Only 4 of the slopes can be build upon. Testing the existing bits is * necessary because these bits can be something else when the settings * in the game have been changed. */ case SLOPE_NE: case SLOPE_SW: return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0; case SLOPE_SE: case SLOPE_NW: return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0; /* Any other tile cannot be built on. */ default: return 0; } } /** * Rotate a neighbour bit a single time clockwise. * @param neighbour The neighbour. * @return The rotate neighbour data. */ static int32 RotateNeighbour(int32 neighbour) { switch (neighbour) { case -2: return -1; case -1: return 2; case 1: return -2; case 2: return 1; default: NOT_REACHED(); } } /** * Convert a neighbour to a road bit representation for easy internal use. * @param neighbour The neighbour. * @return The bits representing the direction. */ static RoadBits NeighbourToRoadBits(int32 neighbour) { switch (neighbour) { case -2: return ROAD_NW; case -1: return ROAD_NE; case 2: return ROAD_SE; case 1: return ROAD_SW; default: NOT_REACHED(); } } /** * Lookup function for building road parts when building on slopes is enabled. * @param slope The slope of the tile to examine. * @param existing The existing neighbours. * @param start The part that should be build first. * @param end The part that will be build second. * @return 0 when the build parts do not connect, 1 when they do connect once * they are build or 2 when building the first part automatically * builds the second part. */ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end) { /* Steep slopes behave the same as slopes with one corner raised. */ if (IsSteepSlope(slope)) { slope = SlopeWithOneCornerRaised(GetHighestSlopeCorner(slope)); } /* The slope is not steep. Furthermore lots of slopes are generally the * same but are only rotated. So to reduce the amount of lookup work that * needs to be done the data is made uniform. This means rotating the * existing parts and updating the slope. */ static const ::Slope base_slopes[] = { SLOPE_FLAT, SLOPE_W, SLOPE_W, SLOPE_SW, SLOPE_W, SLOPE_EW, SLOPE_SW, SLOPE_WSE, SLOPE_W, SLOPE_SW, SLOPE_EW, SLOPE_WSE, SLOPE_SW, SLOPE_WSE, SLOPE_WSE}; static const byte base_rotates[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 2, 3, 2, 2, 1}; if (slope >= (::Slope)lengthof(base_slopes)) { /* This slope is an invalid slope, so ignore it. */ return -1; } byte base_rotate = base_rotates[slope]; slope = base_slopes[slope]; /* Some slopes don't need rotating, so return early when we know we do * not need to rotate. */ switch (slope) { case SLOPE_FLAT: /* Flat slopes can always be build. */ return 1; case SLOPE_EW: case SLOPE_WSE: /* A slope similar to a SLOPE_EW or SLOPE_WSE will always cause * foundations which makes them accessible from all sides. */ return 1; case SLOPE_W: case SLOPE_SW: /* A slope for which we need perform some calculations. */ break; default: /* An invalid slope. */ return -1; } /* Now perform the actual rotation. */ for (int j = 0; j < base_rotate; j++) { for (int i = 0; i < existing->size; i++) { existing->array[i] = RotateNeighbour(existing->array[i]); } start = RotateNeighbour(start); end = RotateNeighbour(end); } /* Create roadbits out of the data for easier handling. */ RoadBits start_roadbits = NeighbourToRoadBits(start); RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end); RoadBits existing_roadbits = ROAD_NONE; for (int i = 0; i < existing->size; i++) { existing_roadbits |= NeighbourToRoadBits(existing->array[i]); } switch (slope) { case SLOPE_W: /* A slope similar to a SLOPE_W. */ switch (new_roadbits) { case ROAD_N: case ROAD_E: case ROAD_S: /* Cannot build anything with a turn from the low side. */ return 0; case ROAD_X: case ROAD_Y: /* A 'sloped' tile is going to be build. */ if ((existing_roadbits | new_roadbits) != new_roadbits) { /* There is already a foundation on the tile, or at least * another slope that is not compatible with the new one. */ return 0; } /* If the start is in the low part, it is automatically * building the second part too. */ return ((start_roadbits & ROAD_E) && !(existing_roadbits & ROAD_W)) ? 2 : 1; default: /* Roadbits causing a foundation are going to be build. * When the existing roadbits are slopes (the lower bits * are used), this cannot be done. */ if ((existing_roadbits | new_roadbits) == new_roadbits) return 1; return (existing_roadbits & ROAD_E) ? 0 : 1; } case SLOPE_SW: /* A slope similar to a SLOPE_SW. */ switch (new_roadbits) { case ROAD_N: case ROAD_E: /* Cannot build anything with a turn from the low side. */ return 0; case ROAD_X: /* A 'sloped' tile is going to be build. */ if ((existing_roadbits | new_roadbits) != new_roadbits) { /* There is already a foundation on the tile, or at least * another slope that is not compatible with the new one. */ return 0; } /* If the start is in the low part, it is automatically * building the second part too. */ return ((start_roadbits & ROAD_NE) && !(existing_roadbits & ROAD_SW)) ? 2 : 1; default: /* Roadbits causing a foundation are going to be build. * When the existing roadbits are slopes (the lower bits * are used), this cannot be done. */ return (existing_roadbits & ROAD_NE) ? 0 : 1; } default: NOT_REACHED(); } } /** * Normalise all input data so we can easily handle it without needing * to call the API lots of times or create large if-elseif-elseif-else * constructs. * In this case it means that a TileXY(0, -1) becomes -2 and TileXY(0, 1) * becomes 2. TileXY(-1, 0) and TileXY(1, 0) stay respectively -1 and 1. * Any other value means that it is an invalid tile offset. * @param tile The tile to normalise. * @return True if and only if the tile offset is valid. */ static bool NormaliseTileOffset(int32 *tile) { if (*tile == 1 || *tile == -1) return true; if (*tile == ::TileDiffXY(0, -1)) { *tile = -2; return true; } if (*tile == ::TileDiffXY(0, 1)) { *tile = 2; return true; } return false; } /* static */ int32 ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array *existing, TileIndex start_, TileIndex end_) { ::Slope slope = (::Slope)slope_; int32 start = start_; int32 end = end_; /* The start tile and end tile cannot be the same tile either. */ if (start == end) return -1; for (int i = 0; i < existing->size; i++) { if (!NormaliseTileOffset(&existing->array[i])) return -1; } if (!NormaliseTileOffset(&start)) return -1; if (!NormaliseTileOffset(&end)) return -1; /* Without build on slopes the characteristics are vastly different, so use * a different helper function (one that is much simpler). */ return _settings_game.construction.build_on_slopes ? LookupWithBuildOnSlopes(slope, existing, start, end) : LookupWithoutBuildOnSlopes(slope, existing, start, end); } /* static */ int32 ScriptRoad::CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end) { if (!::IsValidTile(tile) || !::IsValidTile(start) || !::IsValidTile(end)) return -1; if (::DistanceManhattan(tile, start) != 1 || ::DistanceManhattan(tile, end) != 1) return -1; /* ROAD_NW ROAD_SW ROAD_SE ROAD_NE */ static const TileIndex neighbours[] = {::TileDiffXY(0, -1), ::TileDiffXY(1, 0), ::TileDiffXY(0, 1), ::TileDiffXY(-1, 0)}; Array *existing = (Array*)alloca(sizeof(Array) + lengthof(neighbours) * sizeof(int32)); existing->size = 0; ::RoadBits rb = ::ROAD_NONE; if (::IsNormalRoadTile(tile)) { rb = ::GetAllRoadBits(tile); } else { for (::RoadType rt = ::ROADTYPE_BEGIN; rt < ::ROADTYPE_END; rt++) rb |= ::GetAnyRoadBits(tile, rt); } for (uint i = 0; i < lengthof(neighbours); i++) { if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i]; } return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), existing, start - tile, end - tile); } /** * Check whether one can reach (possibly by building) a road piece the center * of the neighbouring tile. This includes roads and (drive through) stations. * @param rts The road type we want to know reachability for * @param start_tile The tile to "enter" the neighbouring tile. * @param neighbour The direction to the neighbouring tile to "enter". * @return true if and only if the tile is reachable. */ static bool NeighbourHasReachableRoad(::RoadTypes rts, TileIndex start_tile, DiagDirection neighbour) { TileIndex neighbour_tile = ::TileAddByDiagDir(start_tile, neighbour); if ((rts & ::GetRoadTypes(neighbour_tile)) == 0) return false; switch (::GetTileType(neighbour_tile)) { case MP_ROAD: return (::GetRoadTileType(neighbour_tile) != ROAD_TILE_DEPOT); case MP_STATION: if (::IsDriveThroughStopTile(neighbour_tile)) { return (::DiagDirToAxis(neighbour) == ::DiagDirToAxis(::GetRoadStopDir(neighbour_tile))); } return false; default: return false; } } /* static */ int32 ScriptRoad::GetNeighbourRoadCount(TileIndex tile) { if (!::IsValidTile(tile)) return false; if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false; ::RoadTypes rts = ::RoadTypeToRoadTypes((::RoadType)GetCurrentRoadType()); int32 neighbour = 0; if (TileX(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NE)) neighbour++; if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SE)) neighbour++; if (NeighbourHasReachableRoad(rts, tile, DIAGDIR_SW)) neighbour++; if (TileY(tile) > 0 && NeighbourHasReachableRoad(rts, tile, DIAGDIR_NW)) neighbour++; return neighbour; } /* static */ TileIndex ScriptRoad::GetRoadDepotFrontTile(TileIndex depot) { if (!IsRoadDepotTile(depot)) return INVALID_TILE; return depot + ::TileOffsByDiagDir(::GetRoadDepotDirection(depot)); } /* static */ TileIndex ScriptRoad::GetRoadStationFrontTile(TileIndex station) { if (!IsRoadStationTile(station)) return INVALID_TILE; return station + ::TileOffsByDiagDir(::GetRoadStopDir(station)); } /* static */ TileIndex ScriptRoad::GetDriveThroughBackTile(TileIndex station) { if (!IsDriveThroughRoadStationTile(station)) return INVALID_TILE; return station + ::TileOffsByDiagDir(::ReverseDiagDir(::GetRoadStopDir(station))); } /* static */ bool ScriptRoad::_BuildRoadInternal(TileIndex start, TileIndex end, bool one_way, bool full) { EnforcePrecondition(false, start != end); EnforcePrecondition(false, ::IsValidTile(start)); EnforcePrecondition(false, ::IsValidTile(end)); EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); EnforcePrecondition(false, !one_way || ScriptObject::GetRoadType() == ::ROADTYPE_ROAD); EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType())); return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (((start < end) == !full) ? 1 : 2) | (ScriptObject::GetRoadType() << 3) | ((one_way ? 1 : 0) << 5) | 1 << 6, CMD_BUILD_LONG_ROAD); } /* static */ bool ScriptRoad::BuildRoad(TileIndex start, TileIndex end) { return _BuildRoadInternal(start, end, false, false); } /* static */ bool ScriptRoad::BuildOneWayRoad(TileIndex start, TileIndex end) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); return _BuildRoadInternal(start, end, true, false); } /* static */ bool ScriptRoad::BuildRoadFull(TileIndex start, TileIndex end) { return _BuildRoadInternal(start, end, false, true); } /* static */ bool ScriptRoad::BuildOneWayRoadFull(TileIndex start, TileIndex end) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); return _BuildRoadInternal(start, end, true, true); } /* static */ bool ScriptRoad::BuildRoadDepot(TileIndex tile, TileIndex front) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, tile != front); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(front)); EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front)); EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType())); uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0); return ScriptObject::DoCommand(tile, entrance_dir | (ScriptObject::GetRoadType() << 2), 0, CMD_BUILD_ROAD_DEPOT); } /* static */ bool ScriptRoad::_BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, tile != front); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(front)); EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front)); EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id)); EnforcePrecondition(false, road_veh_type == ROADVEHTYPE_BUS || road_veh_type == ROADVEHTYPE_TRUCK); EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType())); uint entrance_dir; if (drive_through) { entrance_dir = ::TileY(tile) != ::TileY(front); } else { entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0); } uint p2 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 32; p2 |= drive_through ? 2 : 0; p2 |= road_veh_type == ROADVEHTYPE_TRUCK ? 1 : 0; p2 |= ::RoadTypeToRoadTypes(ScriptObject::GetRoadType()) << 2; p2 |= entrance_dir << 6; p2 |= (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16; return ScriptObject::DoCommand(tile, 1 | 1 << 8, p2, CMD_BUILD_ROAD_STOP); } /* static */ bool ScriptRoad::BuildRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id) { return _BuildRoadStationInternal(tile, front, road_veh_type, false, station_id); } /* static */ bool ScriptRoad::BuildDriveThroughRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id) { return _BuildRoadStationInternal(tile, front, road_veh_type, true, station_id); } /* static */ bool ScriptRoad::RemoveRoad(TileIndex start, TileIndex end) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, start != end); EnforcePrecondition(false, ::IsValidTile(start)); EnforcePrecondition(false, ::IsValidTile(end)); EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType())); return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 1 : 2) | (ScriptObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD); } /* static */ bool ScriptRoad::RemoveRoadFull(TileIndex start, TileIndex end) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, start != end); EnforcePrecondition(false, ::IsValidTile(start)); EnforcePrecondition(false, ::IsValidTile(end)); EnforcePrecondition(false, ::TileX(start) == ::TileX(end) || ::TileY(start) == ::TileY(end)); EnforcePrecondition(false, IsRoadTypeAvailable(GetCurrentRoadType())); return ScriptObject::DoCommand(start, end, (::TileY(start) != ::TileY(end) ? 4 : 0) | (start < end ? 2 : 1) | (ScriptObject::GetRoadType() << 3), CMD_REMOVE_LONG_ROAD); } /* static */ bool ScriptRoad::RemoveRoadDepot(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsTileType(tile, MP_ROAD)) EnforcePrecondition(false, GetRoadTileType(tile) == ROAD_TILE_DEPOT); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ bool ScriptRoad::RemoveRoadStation(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsTileType(tile, MP_STATION)); EnforcePrecondition(false, IsRoadStop(tile)); return ScriptObject::DoCommand(tile, 1 | 1 << 8, GetRoadStopType(tile), CMD_REMOVE_ROAD_STOP); } /* static */ Money ScriptRoad::GetBuildCost(RoadType roadtype, BuildType build_type) { if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return -1; switch (build_type) { case BT_ROAD: return ::GetPrice(PR_BUILD_ROAD, 1, NULL); case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_ROAD, 1, NULL); case BT_BUS_STOP: return ::GetPrice(PR_BUILD_STATION_BUS, 1, NULL); case BT_TRUCK_STOP: return ::GetPrice(PR_BUILD_STATION_TRUCK, 1, NULL); default: return -1; } } /* static */ uint16 ScriptRoad::GetMaintenanceCostFactor(RoadType roadtype) { if (!ScriptRoad::IsRoadTypeAvailable(roadtype)) return 0; return roadtype == ROADTYPE_TRAM ? 3 : 2; } openttd-1.5.3/src/script/api/script_sign.cpp0000644000000000000000000000605412627373434017607 0ustar rootroot/* $Id: script_sign.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_sign.cpp Implementation of ScriptSign. */ #include "../../stdafx.h" #include "script_sign.hpp" #include "table/strings.h" #include "../script_instance.hpp" #include "../../signs_base.h" #include "../../string_func.h" #include "../../strings_func.h" #include "../../tile_map.h" #include "../../safeguards.h" /* static */ bool ScriptSign::IsValidSign(SignID sign_id) { const Sign *si = ::Sign::GetIfValid(sign_id); return si != NULL && (si->owner == ScriptObject::GetCompany() || si->owner == OWNER_DEITY); } /* static */ ScriptCompany::CompanyID ScriptSign::GetOwner(SignID sign_id) { if (!IsValidSign(sign_id)) return ScriptCompany::COMPANY_INVALID; return static_cast((int)::Sign::Get(sign_id)->owner); } /* static */ bool ScriptSign::SetName(SignID sign_id, Text *name) { CCountedPtr counter(name); EnforcePrecondition(false, IsValidSign(sign_id)); EnforcePrecondition(false, name != NULL); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_SIGN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::DoCommand(0, sign_id, 0, CMD_RENAME_SIGN, text); } /* static */ char *ScriptSign::GetName(SignID sign_id) { if (!IsValidSign(sign_id)) return NULL; ::SetDParam(0, sign_id); return GetString(STR_SIGN_NAME); } /* static */ TileIndex ScriptSign::GetLocation(SignID sign_id) { if (!IsValidSign(sign_id)) return INVALID_TILE; const Sign *sign = ::Sign::Get(sign_id); return ::TileVirtXY(sign->x, sign->y); } /* static */ bool ScriptSign::RemoveSign(SignID sign_id) { EnforcePrecondition(false, IsValidSign(sign_id)); return ScriptObject::DoCommand(0, sign_id, 0, CMD_RENAME_SIGN, ""); } /* static */ SignID ScriptSign::BuildSign(TileIndex location, Text *name) { CCountedPtr counter(name); EnforcePrecondition(INVALID_SIGN, ::IsValidTile(location)); EnforcePrecondition(INVALID_SIGN, name != NULL); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(INVALID_SIGN, text); EnforcePreconditionCustomError(INVALID_SIGN, ::Utf8StringLength(text) < MAX_LENGTH_SIGN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); if (!ScriptObject::DoCommand(location, 0, 0, CMD_PLACE_SIGN, text, &ScriptInstance::DoCommandReturnSignID)) return INVALID_SIGN; /* In case of test-mode, we return SignID 0 */ return 0; } openttd-1.5.3/src/script/api/script_marine.hpp0000644000000000000000000001762612627373434020136 0ustar rootroot/* $Id: script_marine.hpp 23633 2011-12-19 21:05:36Z truebrain $ */ /* * 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 script_marine.hpp Everything to query and build marine. */ #ifndef SCRIPT_MARINE_HPP #define SCRIPT_MARINE_HPP #include "script_error.hpp" /** * Class that handles all marine related functions. * @api ai game */ class ScriptMarine : public ScriptObject { public: /** * All marine related error messages. */ enum ErrorMessages { /** Base for marine related errors */ ERR_MARINE_BASE = ScriptError::ERR_CAT_MARINE << ScriptError::ERR_CAT_BIT_SIZE, /** Infrastructure must be built on water */ ERR_MARINE_MUST_BE_BUILT_ON_WATER, // [STR_ERROR_MUST_BE_BUILT_ON_WATER] }; /** * Types of water-related objects in the game. */ enum BuildType { BT_DOCK, ///< Build a dock BT_DEPOT, ///< Build a ship depot BT_BUOY, ///< Build a buoy }; /** * Checks whether the given tile is actually a tile with a water depot. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a water depot. */ static bool IsWaterDepotTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a dock. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a dock. */ static bool IsDockTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a buoy. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a buoy. */ static bool IsBuoyTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a lock. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a lock. */ static bool IsLockTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a canal. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a canal. */ static bool IsCanalTile(TileIndex tile); /** * Checks whether the given tiles are directly connected, i.e. whether * a ship vehicle can travel from the center of the first tile to the * center of the second tile. * @param tile_from The source tile. * @param tile_to The destination tile. * @pre ScriptMap::IsValidTile(tile_from). * @pre ScriptMap::IsValidTile(tile_to). * @pre 'tile_from' and 'tile_to' are directly neighbouring tiles. * @return True if and only if a ship can go from tile_from to tile_to. */ static bool AreWaterTilesConnected(TileIndex tile_from, TileIndex tile_to); /** * Builds a water depot on tile. * @param tile The tile where the water depot will be build. * @param front A tile on the same axis with 'tile' as the depot shall be oriented. * @pre ScriptMap::IsValidTile(tile). * @pre ScriptMap::IsValidTile(front). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_SITE_UNSUITABLE * @exception ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER * @return Whether the water depot has been/can be build or not. * @note A WaterDepot is 1 tile in width, and 2 tiles in length. * @note The depot will be built towards the south from 'tile', not necessarily towards 'front'. */ static bool BuildWaterDepot(TileIndex tile, TileIndex front); /** * Builds a dock where tile is the tile still on land. * @param tile The tile still on land of the dock. * @param station_id The station to join, ScriptStation::STATION_NEW or ScriptStation::STATION_JOIN_ADJACENT. * @pre ScriptMap::IsValidTile(tile). * @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_SITE_UNSUITABLE * @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS * @return Whether the dock has been/can be build or not. */ static bool BuildDock(TileIndex tile, StationID station_id); /** * Builds a buoy on tile. * @param tile The tile where the buoy will be build. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_SITE_UNSUITABLE * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS * @return Whether the buoy has been/can be build or not. */ static bool BuildBuoy(TileIndex tile); /** * Builds a lock on tile. * @param tile The tile where the lock will be build. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptError::ERR_SITE_UNSUITABLE * @return Whether the lock has been/can be build or not. */ static bool BuildLock(TileIndex tile); /** * Builds a canal on tile. * @param tile The tile where the canal will be build. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_ALREADY_BUILT * @return Whether the canal has been/can be build or not. */ static bool BuildCanal(TileIndex tile); /** * Removes a water depot. * @param tile Any tile of the water depot. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the water depot has been/can be removed or not. */ static bool RemoveWaterDepot(TileIndex tile); /** * Removes a dock. * @param tile Any tile of the dock. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the dock has been/can be removed or not. */ static bool RemoveDock(TileIndex tile); /** * Removes a buoy. * @param tile Any tile of the buoy. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the buoy has been/can be removed or not. */ static bool RemoveBuoy(TileIndex tile); /** * Removes a lock. * @param tile Any tile of the lock. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the lock has been/can be removed or not. */ static bool RemoveLock(TileIndex tile); /** * Removes a canal. * @param tile Any tile of the canal. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the canal has been/can be removed or not. */ static bool RemoveCanal(TileIndex tile); /** * Get the baseprice of building a water-related object. * @param build_type the type of object to build * @return The baseprice of building the given object. */ static Money GetBuildCost(BuildType build_type); }; #endif /* SCRIPT_MARINE_HPP */ openttd-1.5.3/src/script/api/script_industrytypelist.hpp0000644000000000000000000000205512627373434022330 0ustar rootroot/* $Id: script_industrytypelist.hpp 23614 2011-12-19 20:57:23Z truebrain $ */ /* * 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 script_industrytypelist.hpp List all available industry types. */ #ifndef SCRIPT_INDUSTRYTYPELIST_HPP #define SCRIPT_INDUSTRYTYPELIST_HPP #include "script_industrytype.hpp" /** * Creates a list of valid industry types. * @api ai game * @ingroup ScriptList */ class ScriptIndustryTypeList : public ScriptList { public: ScriptIndustryTypeList(); }; #endif /* SCRIPT_INDUSTRYTYPELIST_HPP */ openttd-1.5.3/src/script/api/script_cargo.hpp0000644000000000000000000001373312627373434017751 0ustar rootroot/* $Id: script_cargo.hpp 26396 2014-03-10 22:18:53Z zuu $ */ /* * 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 script_cargo.hpp Everything to query cargoes. */ #ifndef SCRIPT_CARGO_HPP #define SCRIPT_CARGO_HPP #include "script_object.hpp" #include "../../cargotype.h" #include "../../linkgraph/linkgraph_type.h" /** * Class that handles all cargo related functions. * @api ai game */ class ScriptCargo : public ScriptObject { public: /** * The classes of cargo. */ enum CargoClass { /* Note: these values represent part of the in-game CargoClass enum */ CC_PASSENGERS = ::CC_PASSENGERS, ///< Passengers. Cargoes of this class appear at bus stops. Cargoes not of this class appear at truck stops. CC_MAIL = ::CC_MAIL, ///< Mail CC_EXPRESS = ::CC_EXPRESS, ///< Express cargo (Goods, Food, Candy, but also possible for passengers) CC_ARMOURED = ::CC_ARMOURED, ///< Armoured cargo (Valuables, Gold, Diamonds) CC_BULK = ::CC_BULK, ///< Bulk cargo (Coal, Grain etc., Ores, Fruit) CC_PIECE_GOODS = ::CC_PIECE_GOODS, ///< Piece goods (Livestock, Wood, Steel, Paper) CC_LIQUID = ::CC_LIQUID, ///< Liquids (Oil, Water, Rubber) CC_REFRIGERATED = ::CC_REFRIGERATED, ///< Refrigerated cargo (Food, Fruit) CC_HAZARDOUS = ::CC_HAZARDOUS, ///< Hazardous cargo (Nuclear Fuel, Explosives, etc.) CC_COVERED = ::CC_COVERED, ///< Covered/Sheltered Freight (Transporation in Box Vans, Silo Wagons, etc.) }; /** * The effects a cargo can have on a town. */ enum TownEffect { /* Note: these values represent part of the in-game TownEffect enum */ TE_NONE = ::TE_NONE, ///< This cargo has no effect on a town TE_PASSENGERS = ::TE_PASSENGERS, ///< This cargo supplies passengers to a town TE_MAIL = ::TE_MAIL, ///< This cargo supplies mail to a town TE_GOODS = ::TE_GOODS, ///< This cargo supplies goods to a town TE_WATER = ::TE_WATER, ///< This cargo supplies water to a town TE_FOOD = ::TE_FOOD, ///< This cargo supplies food to a town }; /** * Special cargo types. */ enum SpecialCargoID { /* Note: these values represent part of the in-game CargoTypes enum */ CT_AUTO_REFIT = ::CT_AUTO_REFIT, ///< Automatically choose cargo type when doing auto-refitting. CT_NO_REFIT = ::CT_NO_REFIT, ///< Do not refit cargo of a vehicle. }; /** * Type of cargo distribution. */ enum DistributionType { DT_MANUAL = ::DT_MANUAL, ///< Manual distribution. DT_ASYMMETRIC = ::DT_ASYMMETRIC, ///< Asymmetric distribution. Usually cargo will only travel in one direction. DT_SYMMETRIC = ::DT_SYMMETRIC, ///< Symmetric distribution. The same amount of cargo travels in each direction between each pair of nodes. INVALID_DISTRIBUTION_TYPE = 0xFFFF, ///< Invalid distribution type. }; /** * Checks whether the given cargo type is valid. * @param cargo_type The cargo to check. * @return True if and only if the cargo type is valid. */ static bool IsValidCargo(CargoID cargo_type); /** * Checks whether the given town effect type is valid. * @param towneffect_type The town effect to check. * @return True if and only if the town effect type is valid. */ static bool IsValidTownEffect(TownEffect towneffect_type); /** * Gets the string representation of the cargo label. * @param cargo_type The cargo to get the string representation of. * @pre ScriptCargo::IsValidCargo(cargo_type). * @return The cargo label. * @note Never use this to check if it is a certain cargo. NewGRF can * redefine all of the names. */ static char *GetCargoLabel(CargoID cargo_type); /** * Checks whether the give cargo is a freight or not. * This defines whether the "freight train weight multiplier" will apply to * trains transporting this cargo. * @param cargo_type The cargo to check on. * @pre ScriptCargo::IsValidCargo(cargo_type). * @return True if and only if the cargo is freight. */ static bool IsFreight(CargoID cargo_type); /** * Check if this cargo is in the requested cargo class. * @param cargo_type The cargo to check on. * @pre ScriptCargo::IsValidCargo(cargo_type). * @param cargo_class The class to check for. * @return True if and only if the cargo is in the cargo class. */ static bool HasCargoClass(CargoID cargo_type, CargoClass cargo_class); /** * Get the effect this cargo has on a town. * @param cargo_type The cargo to check on. * @pre ScriptCargo::IsValidCargo(cargo_type). * @return The effect this cargo has on a town, or TE_NONE if it has no effect. */ static TownEffect GetTownEffect(CargoID cargo_type); /** * Get the income for transporting a piece of cargo over the * given distance within the specified time. * @param cargo_type The cargo to transport. * @pre ScriptCargo::IsValidCargo(cargo_type). * @param distance The distance the cargo travels from begin to end. * @param days_in_transit Amount of (game) days the cargo is in transit. The max value of this variable is 637. Any value higher returns the same as 637 would. * @return The amount of money that would be earned by this trip. */ static Money GetCargoIncome(CargoID cargo_type, uint32 distance, uint32 days_in_transit); /** * Get the cargo distribution type for a cargo. * @param cargo_type The cargo to check on. * @return The cargo distribution type for the given cargo. */ static DistributionType GetDistributionType(CargoID cargo_type); }; #endif /* SCRIPT_CARGO_HPP */ openttd-1.5.3/src/script/api/script_tunnel.cpp0000644000000000000000000001202312627373434020145 0ustar rootroot/* $Id: script_tunnel.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_tunnel.cpp Implementation of ScriptTunnel. */ #include "../../stdafx.h" #include "script_tunnel.hpp" #include "script_rail.hpp" #include "../script_instance.hpp" #include "../../tunnel_map.h" #include "../../safeguards.h" /* static */ bool ScriptTunnel::IsTunnelTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTunnelTile(tile); } /* static */ TileIndex ScriptTunnel::GetOtherTunnelEnd(TileIndex tile) { if (!::IsValidTile(tile)) return INVALID_TILE; /* If it's a tunnel already, take the easy way out! */ if (IsTunnelTile(tile)) return ::GetOtherTunnelEnd(tile); int start_z; Slope start_tileh = ::GetTileSlope(tile, &start_z); DiagDirection direction = ::GetInclinedSlopeDirection(start_tileh); if (direction == INVALID_DIAGDIR) return INVALID_TILE; TileIndexDiff delta = ::TileOffsByDiagDir(direction); int end_z; do { tile += delta; if (!::IsValidTile(tile)) return INVALID_TILE; ::GetTileSlope(tile, &end_z); } while (start_z != end_z); return tile; } /** * Helper function to connect a just built tunnel to nearby roads. * @param instance The script instance we have to built the road for. */ static void _DoCommandReturnBuildTunnel2(class ScriptInstance *instance) { if (!ScriptTunnel::_BuildTunnelRoad2()) { ScriptInstance::DoCommandReturn(instance); return; } /* This can never happen, as in test-mode this callback is never executed, * and in execute-mode, the other callback is called. */ NOT_REACHED(); } /** * Helper function to connect a just built tunnel to nearby roads. * @param instance The script instance we have to built the road for. */ static void _DoCommandReturnBuildTunnel1(class ScriptInstance *instance) { if (!ScriptTunnel::_BuildTunnelRoad1()) { ScriptInstance::DoCommandReturn(instance); return; } /* This can never happen, as in test-mode this callback is never executed, * and in execute-mode, the other callback is called. */ NOT_REACHED(); } /* static */ bool ScriptTunnel::BuildTunnel(ScriptVehicle::VehicleType vehicle_type, TileIndex start) { EnforcePrecondition(false, ::IsValidTile(start)); EnforcePrecondition(false, vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_ROAD); EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_RAIL || ScriptRail::IsRailTypeAvailable(ScriptRail::GetCurrentRailType())); EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_ROAD || ScriptRoad::IsRoadTypeAvailable(ScriptRoad::GetCurrentRoadType())); EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY || vehicle_type == ScriptVehicle::VT_ROAD); uint type = 0; if (vehicle_type == ScriptVehicle::VT_ROAD) { type |= (TRANSPORT_ROAD << 8); type |= ::RoadTypeToRoadTypes((::RoadType)ScriptObject::GetRoadType()); } else { type |= (TRANSPORT_RAIL << 8); type |= ScriptRail::GetCurrentRailType(); } /* For rail we do nothing special */ if (vehicle_type == ScriptVehicle::VT_RAIL) { return ScriptObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL); } ScriptObject::SetCallbackVariable(0, start); return ScriptObject::DoCommand(start, type, 0, CMD_BUILD_TUNNEL, NULL, &::_DoCommandReturnBuildTunnel1); } /* static */ bool ScriptTunnel::_BuildTunnelRoad1() { /* Build the piece of road on the 'start' side of the tunnel */ TileIndex end = ScriptObject::GetCallbackVariable(0); TileIndex start = ScriptTunnel::GetOtherTunnelEnd(end); DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &::_DoCommandReturnBuildTunnel2); } /* static */ bool ScriptTunnel::_BuildTunnelRoad2() { /* Build the piece of road on the 'end' side of the tunnel */ TileIndex end = ScriptObject::GetCallbackVariable(0); TileIndex start = ScriptTunnel::GetOtherTunnelEnd(end); DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); return ScriptObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD); } /* static */ bool ScriptTunnel::RemoveTunnel(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsTunnelTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } openttd-1.5.3/src/script/api/script_event.cpp0000644000000000000000000000450012627373434017762 0ustar rootroot/* $Id: script_event.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_event.cpp Implementation of ScriptEvent. */ #include "../../stdafx.h" #include "script_event_types.hpp" #include #include "../../safeguards.h" /** The queue of events for a script. */ struct ScriptEventData { std::queue stack; ///< The actual queue. }; /* static */ void ScriptEventController::CreateEventPointer() { assert(ScriptObject::GetEventPointer() == NULL); ScriptObject::GetEventPointer() = new ScriptEventData(); } /* static */ void ScriptEventController::FreeEventPointer() { ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer(); /* Free all waiting events (if any) */ while (!data->stack.empty()) { ScriptEvent *e = data->stack.front(); data->stack.pop(); e->Release(); } /* Now kill our data pointer */ delete data; } /* static */ bool ScriptEventController::IsEventWaiting() { if (ScriptObject::GetEventPointer() == NULL) ScriptEventController::CreateEventPointer(); ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer(); return !data->stack.empty(); } /* static */ ScriptEvent *ScriptEventController::GetNextEvent() { if (ScriptObject::GetEventPointer() == NULL) ScriptEventController::CreateEventPointer(); ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer(); if (data->stack.empty()) return NULL; ScriptEvent *e = data->stack.front(); data->stack.pop(); return e; } /* static */ void ScriptEventController::InsertEvent(ScriptEvent *event) { if (ScriptObject::GetEventPointer() == NULL) ScriptEventController::CreateEventPointer(); ScriptEventData *data = (ScriptEventData *)ScriptObject::GetEventPointer(); event->AddRef(); data->stack.push(event); } openttd-1.5.3/src/script/api/script_signlist.cpp0000644000000000000000000000176612627373434020510 0ustar rootroot/* $Id: script_signlist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_signlist.cpp Implementation of ScriptSignList and friends. */ #include "../../stdafx.h" #include "script_signlist.hpp" #include "script_sign.hpp" #include "../../signs_base.h" #include "../../safeguards.h" ScriptSignList::ScriptSignList() { Sign *s; FOR_ALL_SIGNS(s) { if (ScriptSign::IsValidSign(s->index)) this->AddItem(s->index); } } openttd-1.5.3/src/script/api/script_railtypelist.cpp0000644000000000000000000000210712627373434021367 0ustar rootroot/* $Id: script_railtypelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_railtypelist.cpp Implementation of ScriptRailTypeList and friends. */ #include "../../stdafx.h" #include "script_railtypelist.hpp" #include "../../rail.h" #include "../../safeguards.h" ScriptRailTypeList::ScriptRailTypeList() { for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { if (ScriptObject::GetCompany() == OWNER_DEITY || ::HasRailtypeAvail(ScriptObject::GetCompany(), rt)) this->AddItem(rt); } } openttd-1.5.3/src/script/api/script_goal.hpp0000644000000000000000000001745412627373434017604 0ustar rootroot/* $Id: script_goal.hpp 26012 2013-11-16 17:41:57Z zuu $ */ /* * 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 script_goal.hpp Everything to manipulate the current running goal. */ #ifndef SCRIPT_GOAL_HPP #define SCRIPT_GOAL_HPP #include "script_company.hpp" #include "../../goal_type.h" /** * Class that handles some goal related functions. * * Goals are saved and loaded. Upon bankruptcy or company takeover, all company * specific goals are removed for that company. You can also remove individual * goals using #Remove. * * @api game */ class ScriptGoal : public ScriptObject { public: /** * The goal IDs. */ enum GoalID { /* Note: these values represent part of the in-game GoalID enum */ GOAL_INVALID = ::INVALID_GOALTYPE, ///< An invalid goal id. }; /** * Goal types that can be given to a goal. */ enum GoalType { /* Note: these values represent part of the in-game GoalType enum */ GT_NONE = ::GT_NONE, ///< Destination is not linked. GT_TILE = ::GT_TILE, ///< Destination is a tile. GT_INDUSTRY = ::GT_INDUSTRY, ///< Destination is an industry. GT_TOWN = ::GT_TOWN, ///< Destination is a town. GT_COMPANY = ::GT_COMPANY, ///< Destination is a company. GT_STORY_PAGE = ::GT_STORY_PAGE ///< Destination is a story page. }; /** * Types of queries we could do to the user. * Basically the title of the question window. */ enum QuestionType { QT_QUESTION, ///< Asking a simple question; title: Question. QT_INFORMATION, ///< Showing an informational message; title: Information. QT_WARNING, ///< Showing a warning; title: Warning. QT_ERROR, ///< Showing an error; title: Error. }; /** * Types of buttons that can be in the question window. */ enum QuestionButton { /* Note: these values represent part of the string list starting with STR_GOAL_QUESTION_BUTTON_CANCEL */ BUTTON_CANCEL = (1 << 0), ///< Cancel button. BUTTON_OK = (1 << 1), ///< OK button. BUTTON_NO = (1 << 2), ///< No button. BUTTON_YES = (1 << 3), ///< Yes button. BUTTON_DECLINE = (1 << 4), ///< Decline button. BUTTON_ACCEPT = (1 << 5), ///< Accept button. BUTTON_IGNORE = (1 << 6), ///< Ignore button. BUTTON_RETRY = (1 << 7), ///< Retry button. BUTTON_PREVIOUS = (1 << 8), ///< Previous button. BUTTON_NEXT = (1 << 9), ///< Next button. BUTTON_STOP = (1 << 10), ///< Stop button. BUTTON_START = (1 << 11), ///< Start button. BUTTON_GO = (1 << 12), ///< Go button. BUTTON_CONTINUE = (1 << 13), ///< Continue button. BUTTON_RESTART = (1 << 14), ///< Restart button. BUTTON_POSTPONE = (1 << 15), ///< Postpone button. BUTTON_SURRENDER = (1 << 16), ///< Surrender button. BUTTON_CLOSE = (1 << 17), ///< Close button. }; /** * Check whether this is a valid goalID. * @param goal_id The GoalID to check. * @return True if and only if this goal is valid. */ static bool IsValidGoal(GoalID goal_id); /** * Create a new goal. * @param company The company to create the goal for, or ScriptCompany::COMPANY_INVALID for all. * @param goal The goal to add to the GUI (can be either a raw string, or a ScriptText object). * @param type The type of the goal. * @param destination The destination of the \a type type. * @return The new GoalID, or GOAL_INVALID if it failed. * @pre No ScriptCompanyMode may be in scope. * @pre goal != NULL && len(goal) != 0. * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID. * @pre if type is GT_STORY_PAGE, the company of the goal and the company of the story page need to match: * \li Global goals can only reference global story pages. * \li Company specific goals can reference global story pages and story pages of the same company. */ static GoalID New(ScriptCompany::CompanyID company, Text *goal, GoalType type, uint32 destination); /** * Remove a goal from the list. * @param goal_id The goal to remove. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidGoal(goal_id). */ static bool Remove(GoalID goal_id); /** * Update goal text of a goal. * @param goal_id The goal to update. * @param goal The new goal text (can be either a raw string, or a ScriptText object). * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre goal != NULL && len(goal) != 0. * @pre IsValidGoal(goal_id). */ static bool SetText(GoalID goal_id, Text *goal); /** * Update the progress text of a goal. The progress text is a text that * is shown adjacent to the goal but in a separate column. Try to keep * the progress string short. * @param goal_id The goal to update. * @param progress The new progress text for the goal (can be either a raw string, * or a ScriptText object). To clear the progress string you can pass NULL or an * empty string. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidGoal(goal_id). */ static bool SetProgress(GoalID goal_id, Text *progress); /** * Update completed status of goal * @param goal_id The goal to update. * @param complete The new goal completed status. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidGoal(goal_id). */ static bool SetCompleted(GoalID goal_id, bool complete); /** * Checks if a given goal have been marked as completed. * @param goal_id The goal to check complete status. * @return True if the goal is completed, otherwise false. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidGoal(goal_id). */ static bool IsCompleted(GoalID goal_id); /** * Ask a question. * @param uniqueid Your unique id to distinguish results of multiple questions in the returning event. * @param company The company to ask the question, or ScriptCompany::COMPANY_INVALID for all. * @param question The question to ask (can be either a raw string, or a ScriptText object). * @param type The type of question that is being asked. * @param buttons Any combinations (at least 1, up to 3) of buttons defined in QuestionButton. Like BUTTON_YES + BUTTON_NO. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre question != NULL && len(question) != 0. * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID. * @pre CountBits(buttons) >= 1 && CountBits(buttons) <= 3. * @note Replies to the question are given by you via the event ScriptEvent_GoalQuestionAnswer. * @note There is no guarantee you ever get a reply on your question. */ static bool Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons); /** * Close the question on all clients. * @param uniqueid The uniqueid of the question you want to close. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @note If you send a question to a single company, and get a reply for them, * the question is already closed on all clients. Only use this function if * you want to timeout a question, or if you send the question to all * companies, but you are only interested in the reply of the first. */ static bool CloseQuestion(uint16 uniqueid); }; #endif /* SCRIPT_GOAL_HPP */ openttd-1.5.3/src/script/api/script_infrastructure.cpp0000644000000000000000000001146212627373433021725 0ustar rootroot/* $Id: script_infrastructure.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_infrastructure.cpp Implementation of ScriptInfrastructure. */ #include "../../stdafx.h" #include "script_infrastructure.hpp" #include "../../company_base.h" #include "../../rail.h" #include "../../road_func.h" #include "../../water.h" #include "../../station_func.h" #include "../../safeguards.h" /* static */ uint32 ScriptInfrastructure::GetRailPieceCount(ScriptCompany::CompanyID company, ScriptRail::RailType railtype) { company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID || (::RailType)railtype >= RAILTYPE_END) return 0; return ::Company::Get((::CompanyID)company)->infrastructure.rail[railtype]; } /* static */ uint32 ScriptInfrastructure::GetRoadPieceCount(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype) { company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID || (::RoadType)roadtype >= ROADTYPE_END) return 0; return ::Company::Get((::CompanyID)company)->infrastructure.road[roadtype]; } /* static */ uint32 ScriptInfrastructure::GetInfrastructurePieceCount(ScriptCompany::CompanyID company, Infrastructure infra_type) { company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return 0; ::Company *c = ::Company::Get((::CompanyID)company); switch (infra_type) { case INFRASTRUCTURE_RAIL: { uint32 count = 0; for (::RailType rt = ::RAILTYPE_BEGIN; rt != ::RAILTYPE_END; rt++) { count += c->infrastructure.rail[rt]; } return count; } case INFRASTRUCTURE_SIGNALS: return c->infrastructure.signal; case INFRASTRUCTURE_ROAD: { uint32 count = 0; for (::RoadType rt = ::ROADTYPE_BEGIN; rt != ::ROADTYPE_END; rt++) { count += c->infrastructure.road[rt]; } return count; } case INFRASTRUCTURE_CANAL: return c->infrastructure.water; case INFRASTRUCTURE_STATION: return c->infrastructure.station; case INFRASTRUCTURE_AIRPORT: return c->infrastructure.airport; default: return 0; } } /* static */ Money ScriptInfrastructure::GetMonthlyRailCosts(ScriptCompany::CompanyID company, ScriptRail::RailType railtype) { company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID || (::RailType)railtype >= RAILTYPE_END || !_settings_game.economy.infrastructure_maintenance) return 0; const ::Company *c = ::Company::Get((::CompanyID)company); return ::RailMaintenanceCost((::RailType)railtype, c->infrastructure.rail[railtype], c->infrastructure.GetRailTotal()); } /* static */ Money ScriptInfrastructure::GetMonthlyRoadCosts(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype) { company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID || (::RoadType)roadtype >= ROADTYPE_END || !_settings_game.economy.infrastructure_maintenance) return 0; return ::RoadMaintenanceCost((::RoadType)roadtype, ::Company::Get((::CompanyID)company)->infrastructure.road[roadtype]); } /* static */ Money ScriptInfrastructure::GetMonthlyInfrastructureCosts(ScriptCompany::CompanyID company, Infrastructure infra_type) { company = ScriptCompany::ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID || !_settings_game.economy.infrastructure_maintenance) return 0; ::Company *c = ::Company::Get((::CompanyID)company); switch (infra_type) { case INFRASTRUCTURE_RAIL: { Money cost; uint32 rail_total = c->infrastructure.GetRailTotal(); for (::RailType rt = ::RAILTYPE_BEGIN; rt != ::RAILTYPE_END; rt++) { cost += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total); } return cost; } case INFRASTRUCTURE_SIGNALS: return SignalMaintenanceCost(c->infrastructure.signal); case INFRASTRUCTURE_ROAD: { Money cost; for (::RoadType rt = ::ROADTYPE_BEGIN; rt != ::ROADTYPE_END; rt++) { cost += RoadMaintenanceCost(rt, c->infrastructure.road[rt]); } return cost; } case INFRASTRUCTURE_CANAL: return CanalMaintenanceCost(c->infrastructure.water); case INFRASTRUCTURE_STATION: return StationMaintenanceCost(c->infrastructure.station); case INFRASTRUCTURE_AIRPORT: return AirportMaintenanceCost(c->index); default: return 0; } } openttd-1.5.3/src/script/api/script_base.cpp0000644000000000000000000000366212627373434017563 0ustar rootroot/* $Id: script_base.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_base.cpp Implementation of ScriptBase. */ #include "../../stdafx.h" #include "script_base.hpp" #include "script_error.hpp" #include "../../network/network.h" #include "../../core/random_func.hpp" #include "../../safeguards.h" /* static */ uint32 ScriptBase::Rand() { /* We pick RandomRange if we are in SP (so when saved, we do the same over and over) * but we pick InteractiveRandomRange if we are a network_server or network-client. */ if (_networking) return ::InteractiveRandom(); return ::Random(); } /* static */ uint32 ScriptBase::RandItem(int unused_param) { return ScriptBase::Rand(); } /* static */ uint ScriptBase::RandRange(uint max) { /* We pick RandomRange if we are in SP (so when saved, we do the same over and over) * but we pick InteractiveRandomRange if we are a network_server or network-client. */ if (_networking) return ::InteractiveRandomRange(max); return ::RandomRange(max); } /* static */ uint32 ScriptBase::RandRangeItem(int unused_param, uint max) { return ScriptBase::RandRange(max); } /* static */ bool ScriptBase::Chance(uint out, uint max) { EnforcePrecondition(false, out <= max); return ScriptBase::RandRange(max) < out; } /* static */ bool ScriptBase::ChanceItem(int unused_param, uint out, uint max) { return ScriptBase::Chance(out, max); } openttd-1.5.3/src/script/api/script_tilelist.hpp0000644000000000000000000000702512627373434020504 0ustar rootroot/* $Id: script_tilelist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_tilelist.hpp List tiles. */ #ifndef SCRIPT_TILELIST_HPP #define SCRIPT_TILELIST_HPP #include "script_station.hpp" #include "script_list.hpp" /** * Creates an empty list, in which you can add tiles. * @api ai game * @ingroup ScriptList */ class ScriptTileList : public ScriptList { public: /** * Adds the rectangle between tile_from and tile_to to the to-be-evaluated tiles. * @param tile_from One corner of the tiles to add. * @param tile_to The other corner of the tiles to add. * @pre ScriptMap::IsValidTile(tile_from). * @pre ScriptMap::IsValidTile(tile_to). */ void AddRectangle(TileIndex tile_from, TileIndex tile_to); /** * Add a tile to the to-be-evaluated tiles. * @param tile The tile to add. * @pre ScriptMap::IsValidTile(tile). */ void AddTile(TileIndex tile); /** * Remove the tiles inside the rectangle between tile_from and tile_to form the list. * @param tile_from One corner of the tiles to remove. * @param tile_to The other corner of the files to remove. * @pre ScriptMap::IsValidTile(tile_from). * @pre ScriptMap::IsValidTile(tile_to). */ void RemoveRectangle(TileIndex tile_from, TileIndex tile_to); /** * Remove a tile from the list. * @param tile The tile to remove. * @pre ScriptMap::IsValidTile(tile). */ void RemoveTile(TileIndex tile); }; /** * Creates a list of tiles that will accept cargo for the given industry. * @note If a simular industry is close, it might happen that this industry receives the cargo. * @api ai game * @ingroup ScriptList */ class ScriptTileList_IndustryAccepting : public ScriptTileList { public: /** * @param industry_id The industry to create the ScriptTileList around. * @param radius The radius of the station you will be using. * @pre ScriptIndustry::IsValidIndustry(industry_id). * @pre radius > 0. */ ScriptTileList_IndustryAccepting(IndustryID industry_id, int radius); }; /** * Creates a list of tiles which the industry checks to see if a station is * there to receive cargo produced by this industry. * @api ai game * @ingroup ScriptList */ class ScriptTileList_IndustryProducing : public ScriptTileList { public: /** * @param industry_id The industry to create the ScriptTileList around. * @param radius The radius of the station you will be using. * @pre ScriptIndustry::IsValidIndustry(industry_id). * @pre radius > 0. */ ScriptTileList_IndustryProducing(IndustryID industry_id, int radius); }; /** * Creates a list of tiles which have the requested StationType of the * StationID. * @api ai game * @ingroup ScriptList */ class ScriptTileList_StationType : public ScriptTileList { public: /** * @param station_id The station to create the ScriptTileList for. * @param station_type The StationType to create the ScriptList for. */ ScriptTileList_StationType(StationID station_id, ScriptStation::StationType station_type); }; #endif /* SCRIPT_TILELIST_HPP */ openttd-1.5.3/src/script/api/script_vehicle.cpp0000644000000000000000000003714112627373433020266 0ustar rootroot/* $Id: script_vehicle.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_vehicle.cpp Implementation of ScriptVehicle. */ #include "../../stdafx.h" #include "script_engine.hpp" #include "script_cargo.hpp" #include "script_gamesettings.hpp" #include "script_group.hpp" #include "../script_instance.hpp" #include "../../string_func.h" #include "../../strings_func.h" #include "../../command_func.h" #include "../../roadveh.h" #include "../../train.h" #include "../../vehicle_func.h" #include "../../aircraft.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ bool ScriptVehicle::IsValidVehicle(VehicleID vehicle_id) { const Vehicle *v = ::Vehicle::GetIfValid(vehicle_id); return v != NULL && (v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && (v->IsPrimaryVehicle() || (v->type == VEH_TRAIN && ::Train::From(v)->IsFreeWagon())); } /* static */ ScriptCompany::CompanyID ScriptVehicle::GetOwner(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return ScriptCompany::COMPANY_INVALID; return static_cast((int)::Vehicle::Get(vehicle_id)->owner); } /* static */ int32 ScriptVehicle::GetNumWagons(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; int num = 1; const Train *v = ::Train::GetIfValid(vehicle_id); if (v != NULL) { while ((v = v->GetNextUnit()) != NULL) num++; } return num; } /* static */ int ScriptVehicle::GetLength(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; const Vehicle *v = ::Vehicle::Get(vehicle_id); return v->IsGroundVehicle() ? v->GetGroundVehicleCache()->cached_total_length : -1; } /* static */ VehicleID ScriptVehicle::BuildVehicle(TileIndex depot, EngineID engine_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(VEHICLE_INVALID, ScriptEngine::IsBuildable(engine_id)); ::VehicleType type = ::Engine::Get(engine_id)->type; EnforcePreconditionCustomError(VEHICLE_INVALID, !ScriptGameSettings::IsDisabledVehicleType((ScriptVehicle::VehicleType)type), ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); if (!ScriptObject::DoCommand(depot, engine_id, 0, ::GetCmdBuildVeh(type), NULL, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID; /* In case of test-mode, we return VehicleID 0 */ return 0; } /* static */ VehicleID ScriptVehicle::CloneVehicle(TileIndex depot, VehicleID vehicle_id, bool share_orders) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); if (!ScriptObject::DoCommand(depot, vehicle_id, share_orders, CMD_CLONE_VEHICLE, NULL, &ScriptInstance::DoCommandReturnVehicleID)) return VEHICLE_INVALID; /* In case of test-mode, we return VehicleID 0 */ return 0; } /* static */ bool ScriptVehicle::_MoveWagonInternal(VehicleID source_vehicle_id, int source_wagon, bool move_attached_wagons, int dest_vehicle_id, int dest_wagon) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(source_vehicle_id) && source_wagon < GetNumWagons(source_vehicle_id)); EnforcePrecondition(false, dest_vehicle_id == -1 || (IsValidVehicle(dest_vehicle_id) && dest_wagon < GetNumWagons(dest_vehicle_id))); EnforcePrecondition(false, ::Vehicle::Get(source_vehicle_id)->type == VEH_TRAIN); EnforcePrecondition(false, dest_vehicle_id == -1 || ::Vehicle::Get(dest_vehicle_id)->type == VEH_TRAIN); const Train *v = ::Train::Get(source_vehicle_id); while (source_wagon-- > 0) v = v->GetNextUnit(); const Train *w = NULL; if (dest_vehicle_id != -1) { w = ::Train::Get(dest_vehicle_id); while (dest_wagon-- > 0) w = w->GetNextUnit(); } return ScriptObject::DoCommand(0, v->index | (move_attached_wagons ? 1 : 0) << 20, w == NULL ? ::INVALID_VEHICLE : w->index, CMD_MOVE_RAIL_VEHICLE); } /* static */ bool ScriptVehicle::MoveWagon(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon) { return _MoveWagonInternal(source_vehicle_id, source_wagon, false, dest_vehicle_id, dest_wagon); } /* static */ bool ScriptVehicle::MoveWagonChain(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon) { return _MoveWagonInternal(source_vehicle_id, source_wagon, true, dest_vehicle_id, dest_wagon); } /* static */ int ScriptVehicle::GetRefitCapacity(VehicleID vehicle_id, CargoID cargo) { if (!IsValidVehicle(vehicle_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; CommandCost res = ::DoCommand(0, vehicle_id, cargo, DC_QUERY_COST, GetCmdRefitVeh(::Vehicle::Get(vehicle_id))); return res.Succeeded() ? _returned_refit_capacity : -1; } /* static */ bool ScriptVehicle::RefitVehicle(VehicleID vehicle_id, CargoID cargo) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id) && ScriptCargo::IsValidCargo(cargo)); return ScriptObject::DoCommand(0, vehicle_id, cargo, GetCmdRefitVeh(::Vehicle::Get(vehicle_id))); } /* static */ bool ScriptVehicle::SellVehicle(VehicleID vehicle_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); const Vehicle *v = ::Vehicle::Get(vehicle_id); return ScriptObject::DoCommand(0, vehicle_id | (v->type == VEH_TRAIN ? 1 : 0) << 20, 0, GetCmdSellVeh(v)); } /* static */ bool ScriptVehicle::_SellWagonInternal(VehicleID vehicle_id, int wagon, bool sell_attached_wagons) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id) && wagon < GetNumWagons(vehicle_id)); EnforcePrecondition(false, ::Vehicle::Get(vehicle_id)->type == VEH_TRAIN); const Train *v = ::Train::Get(vehicle_id); while (wagon-- > 0) v = v->GetNextUnit(); return ScriptObject::DoCommand(0, v->index | (sell_attached_wagons ? 1 : 0) << 20, 0, CMD_SELL_VEHICLE); } /* static */ bool ScriptVehicle::SellWagon(VehicleID vehicle_id, int wagon) { return _SellWagonInternal(vehicle_id, wagon, false); } /* static */ bool ScriptVehicle::SellWagonChain(VehicleID vehicle_id, int wagon) { return _SellWagonInternal(vehicle_id, wagon, true); } /* static */ bool ScriptVehicle::SendVehicleToDepot(VehicleID vehicle_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); return ScriptObject::DoCommand(0, vehicle_id, 0, GetCmdSendToDepot(::Vehicle::Get(vehicle_id))); } /* static */ bool ScriptVehicle::SendVehicleToDepotForServicing(VehicleID vehicle_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); return ScriptObject::DoCommand(0, vehicle_id | DEPOT_SERVICE, 0, GetCmdSendToDepot(::Vehicle::Get(vehicle_id))); } /* static */ bool ScriptVehicle::IsInDepot(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return false; return ::Vehicle::Get(vehicle_id)->IsChainInDepot(); } /* static */ bool ScriptVehicle::IsStoppedInDepot(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return false; return ::Vehicle::Get(vehicle_id)->IsStoppedInDepot(); } /* static */ bool ScriptVehicle::StartStopVehicle(VehicleID vehicle_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); return ScriptObject::DoCommand(0, vehicle_id, 0, CMD_START_STOP_VEHICLE); } /* static */ bool ScriptVehicle::ReverseVehicle(VehicleID vehicle_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); EnforcePrecondition(false, ::Vehicle::Get(vehicle_id)->type == VEH_ROAD || ::Vehicle::Get(vehicle_id)->type == VEH_TRAIN); switch (::Vehicle::Get(vehicle_id)->type) { case VEH_ROAD: return ScriptObject::DoCommand(0, vehicle_id, 0, CMD_TURN_ROADVEH); case VEH_TRAIN: return ScriptObject::DoCommand(0, vehicle_id, 0, CMD_REVERSE_TRAIN_DIRECTION); default: NOT_REACHED(); } } /* static */ bool ScriptVehicle::SetName(VehicleID vehicle_id, Text *name) { CCountedPtr counter(name); EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidVehicle(vehicle_id)); EnforcePrecondition(false, name != NULL); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_VEHICLE_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::DoCommand(0, vehicle_id, 0, CMD_RENAME_VEHICLE, text); } /* static */ TileIndex ScriptVehicle::GetLocation(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return INVALID_TILE; const Vehicle *v = ::Vehicle::Get(vehicle_id); if (v->type == VEH_AIRCRAFT) { uint x = Clamp(v->x_pos / TILE_SIZE, 0, ::MapSizeX() - 2); uint y = Clamp(v->y_pos / TILE_SIZE, 0, ::MapSizeY() - 2); return ::TileXY(x, y); } return v->tile; } /* static */ EngineID ScriptVehicle::GetEngineType(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE; return ::Vehicle::Get(vehicle_id)->engine_type; } /* static */ EngineID ScriptVehicle::GetWagonEngineType(VehicleID vehicle_id, int wagon) { if (!IsValidVehicle(vehicle_id)) return INVALID_ENGINE; if (wagon >= GetNumWagons(vehicle_id)) return INVALID_ENGINE; const Vehicle *v = ::Vehicle::Get(vehicle_id); if (v->type == VEH_TRAIN) { while (wagon-- > 0) v = ::Train::From(v)->GetNextUnit(); } return v->engine_type; } /* static */ int32 ScriptVehicle::GetUnitNumber(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->unitnumber; } /* static */ char *ScriptVehicle::GetName(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return NULL; ::SetDParam(0, vehicle_id); return GetString(STR_VEHICLE_NAME); } /* static */ int32 ScriptVehicle::GetAge(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->age; } /* static */ int32 ScriptVehicle::GetWagonAge(VehicleID vehicle_id, int wagon) { if (!IsValidVehicle(vehicle_id)) return -1; if (wagon >= GetNumWagons(vehicle_id)) return -1; const Vehicle *v = ::Vehicle::Get(vehicle_id); if (v->type == VEH_TRAIN) { while (wagon-- > 0) v = ::Train::From(v)->GetNextUnit(); } return v->age; } /* static */ int32 ScriptVehicle::GetMaxAge(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->max_age; } /* static */ int32 ScriptVehicle::GetAgeLeft(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->max_age - ::Vehicle::Get(vehicle_id)->age; } /* static */ int32 ScriptVehicle::GetCurrentSpeed(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; const ::Vehicle *v = ::Vehicle::Get(vehicle_id); return (v->vehstatus & (::VS_STOPPED | ::VS_CRASHED)) == 0 ? v->GetDisplaySpeed() : 0; // km-ish/h } /* static */ ScriptVehicle::VehicleState ScriptVehicle::GetState(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return ScriptVehicle::VS_INVALID; const Vehicle *v = ::Vehicle::Get(vehicle_id); byte vehstatus = v->vehstatus; if (vehstatus & ::VS_CRASHED) return ScriptVehicle::VS_CRASHED; if (v->breakdown_ctr != 0) return ScriptVehicle::VS_BROKEN; if (v->IsStoppedInDepot()) return ScriptVehicle::VS_IN_DEPOT; if (vehstatus & ::VS_STOPPED) return ScriptVehicle::VS_STOPPED; if (v->current_order.IsType(OT_LOADING)) return ScriptVehicle::VS_AT_STATION; return ScriptVehicle::VS_RUNNING; } /* static */ Money ScriptVehicle::GetRunningCost(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->GetRunningCost() >> 8; } /* static */ Money ScriptVehicle::GetProfitThisYear(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->GetDisplayProfitThisYear(); } /* static */ Money ScriptVehicle::GetProfitLastYear(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->GetDisplayProfitLastYear(); } /* static */ Money ScriptVehicle::GetCurrentValue(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; return ::Vehicle::Get(vehicle_id)->value; } /* static */ ScriptVehicle::VehicleType ScriptVehicle::GetVehicleType(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return VT_INVALID; switch (::Vehicle::Get(vehicle_id)->type) { case VEH_ROAD: return VT_ROAD; case VEH_TRAIN: return VT_RAIL; case VEH_SHIP: return VT_WATER; case VEH_AIRCRAFT: return VT_AIR; default: return VT_INVALID; } } /* static */ ScriptRoad::RoadType ScriptVehicle::GetRoadType(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return ScriptRoad::ROADTYPE_INVALID; if (GetVehicleType(vehicle_id) != VT_ROAD) return ScriptRoad::ROADTYPE_INVALID; return (ScriptRoad::RoadType)(::RoadVehicle::Get(vehicle_id))->roadtype; } /* static */ int32 ScriptVehicle::GetCapacity(VehicleID vehicle_id, CargoID cargo) { if (!IsValidVehicle(vehicle_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; uint32 amount = 0; for (const Vehicle *v = ::Vehicle::Get(vehicle_id); v != NULL; v = v->Next()) { if (v->cargo_type == cargo) amount += v->cargo_cap; } return amount; } /* static */ int32 ScriptVehicle::GetCargoLoad(VehicleID vehicle_id, CargoID cargo) { if (!IsValidVehicle(vehicle_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; uint32 amount = 0; for (const Vehicle *v = ::Vehicle::Get(vehicle_id); v != NULL; v = v->Next()) { if (v->cargo_type == cargo) amount += v->cargo.StoredCount(); } return amount; } /* static */ GroupID ScriptVehicle::GetGroupID(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return ScriptGroup::GROUP_INVALID; return ::Vehicle::Get(vehicle_id)->group_id; } /* static */ bool ScriptVehicle::IsArticulated(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return false; if (GetVehicleType(vehicle_id) != VT_ROAD && GetVehicleType(vehicle_id) != VT_RAIL) return false; const Vehicle *v = ::Vehicle::Get(vehicle_id); switch (v->type) { case VEH_ROAD: return ::RoadVehicle::From(v)->HasArticulatedPart(); case VEH_TRAIN: return ::Train::From(v)->HasArticulatedPart(); default: NOT_REACHED(); } } /* static */ bool ScriptVehicle::HasSharedOrders(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return false; Vehicle *v = ::Vehicle::Get(vehicle_id); return v->orders.list != NULL && v->orders.list->GetNumVehicles() > 1; } /* static */ int ScriptVehicle::GetReliability(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return -1; const Vehicle *v = ::Vehicle::Get(vehicle_id); return ::ToPercent16(v->reliability); } /* static */ uint ScriptVehicle::GetMaximumOrderDistance(VehicleID vehicle_id) { if (!IsValidVehicle(vehicle_id)) return 0; const ::Vehicle *v = ::Vehicle::Get(vehicle_id); switch (v->type) { case VEH_SHIP: return _settings_game.pf.pathfinder_for_ships != VPF_NPF ? 129 : 0; case VEH_AIRCRAFT: return ::Aircraft::From(v)->acache.cached_max_range_sqr; default: return 0; } } openttd-1.5.3/src/script/api/script_vehiclelist.hpp0000644000000000000000000000557112627373434021172 0ustar rootroot/* $Id: script_vehiclelist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_vehiclelist.hpp List all the vehicles (you own). */ #ifndef SCRIPT_VEHICLELIST_HPP #define SCRIPT_VEHICLELIST_HPP #include "script_list.hpp" #include "script_vehicle.hpp" /** * Creates a list of vehicles of which you are the owner. * @api ai game * @ingroup ScriptList */ class ScriptVehicleList : public ScriptList { public: ScriptVehicleList(); }; /** * Creates a list of vehicles that have orders to a given station. * @api ai game * @ingroup ScriptList */ class ScriptVehicleList_Station : public ScriptList { public: /** * @param station_id The station to get the list of vehicles from, which have orders to it. * @pre ScriptBaseStation::IsValidBaseStation(station_id) */ ScriptVehicleList_Station(StationID station_id); }; /** * Creates a list of vehicles that have orders to a given depot. * The list is created with a tile. If the tile is part of an airport all * aircraft having a depot order on a hangar of that airport will be * returned. For all other vehicle types the tile has to be a depot or * an empty list will be returned. * @api ai game * @ingroup ScriptList */ class ScriptVehicleList_Depot : public ScriptList { public: /** * @param tile The tile of the depot to get the list of vehicles from, which have orders to it. */ ScriptVehicleList_Depot(TileIndex tile); }; /** * Creates a list of vehicles that share orders. * @api ai game * @ingroup ScriptList */ class ScriptVehicleList_SharedOrders : public ScriptList { public: /** * @param vehicle_id The vehicle that the rest shared orders with. */ ScriptVehicleList_SharedOrders(VehicleID vehicle_id); }; /** * Creates a list of vehicles that are in a group. * @api ai * @ingroup ScriptList */ class ScriptVehicleList_Group : public ScriptList { public: /** * @param group_id The ID of the group the vehicles are in. */ ScriptVehicleList_Group(GroupID group_id); }; /** * Creates a list of vehicles that are in the default group. * @api ai * @ingroup ScriptList */ class ScriptVehicleList_DefaultGroup : public ScriptList { public: /** * @param vehicle_type The VehicleType to get the list of vehicles for. */ ScriptVehicleList_DefaultGroup(ScriptVehicle::VehicleType vehicle_type); }; #endif /* SCRIPT_VEHICLELIST_HPP */ openttd-1.5.3/src/script/api/script_enginelist.cpp0000644000000000000000000000217012627373434021003 0ustar rootroot/* $Id: script_enginelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_enginelist.cpp Implementation of ScriptEngineList and friends. */ #include "../../stdafx.h" #include "script_enginelist.hpp" #include "../../engine_base.h" #include "../../safeguards.h" ScriptEngineList::ScriptEngineList(ScriptVehicle::VehicleType vehicle_type) { Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, (::VehicleType)vehicle_type) { if (ScriptObject::GetCompany() == OWNER_DEITY || HasBit(e->company_avail, ScriptObject::GetCompany())) this->AddItem(e->index); } } openttd-1.5.3/src/script/api/script_map.cpp0000644000000000000000000000403712627373434017423 0ustar rootroot/* $Id: script_map.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_map.cpp Implementation of ScriptMap. */ #include "../../stdafx.h" #include "script_map.hpp" #include "../../tile_map.h" #include "../../safeguards.h" /* static */ bool ScriptMap::IsValidTile(TileIndex t) { return ::IsValidTile(t); } /* static */ TileIndex ScriptMap::GetMapSize() { return ::MapSize(); } /* static */ uint32 ScriptMap::GetMapSizeX() { return ::MapSizeX(); } /* static */ uint32 ScriptMap::GetMapSizeY() { return ::MapSizeY(); } /* static */ int32 ScriptMap::GetTileX(TileIndex t) { if (!::IsValidTile(t)) return -1; return ::TileX(t); } /* static */ int32 ScriptMap::GetTileY(TileIndex t) { if (!::IsValidTile(t)) return -1; return ::TileY(t); } /* static */ TileIndex ScriptMap::GetTileIndex(uint32 x, uint32 y) { return ::TileXY(x, y); } /* static */ int32 ScriptMap::DistanceManhattan(TileIndex t1, TileIndex t2) { if (!::IsValidTile(t1) || !::IsValidTile(t2)) return -1; return ::DistanceManhattan(t1, t2); } /* static */ int32 ScriptMap::DistanceMax(TileIndex t1, TileIndex t2) { if (!::IsValidTile(t1) || !::IsValidTile(t2)) return -1; return ::DistanceMax(t1, t2); } /* static */ int32 ScriptMap::DistanceSquare(TileIndex t1, TileIndex t2) { if (!::IsValidTile(t1) || !::IsValidTile(t2)) return -1; return ::DistanceSquare(t1, t2); } /* static */ int32 ScriptMap::DistanceFromEdge(TileIndex t) { if (!::IsValidTile(t)) return -1; return ::DistanceFromEdge(t); } openttd-1.5.3/src/script/api/script_news.cpp0000644000000000000000000000431712627373433017622 0ustar rootroot/* $Id: script_news.cpp 27164 2015-02-22 17:25:29Z alberth $ */ /* * 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 script_news.cpp Implementation of ScriptNews. */ #include "../../stdafx.h" #include "script_news.hpp" #include "script_industry.hpp" #include "script_station.hpp" #include "script_map.hpp" #include "script_town.hpp" #include "script_error.hpp" #include "../../command_type.h" #include "../../string_func.h" #include "../../safeguards.h" /* static */ bool ScriptNews::Create(NewsType type, Text *text, ScriptCompany::CompanyID company, NewsReferenceType ref_type, uint32 reference) { CCountedPtr counter(text); EnforcePrecondition(false, text != NULL); const char *encoded = text->GetEncodedText(); EnforcePreconditionEncodedText(false, encoded); EnforcePrecondition(false, type == NT_ECONOMY || type == NT_SUBSIDIES || type == NT_GENERAL); EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); EnforcePrecondition(false, (ref_type == NR_NONE) || (ref_type == NR_TILE && ScriptMap::IsValidTile(reference)) || (ref_type == NR_STATION && ScriptStation::IsValidStation(reference)) || (ref_type == NR_INDUSTRY && ScriptIndustry::IsValidIndustry(reference)) || (ref_type == NR_TOWN && ScriptTown::IsValidTown(reference))); uint8 c = company; if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; if (ref_type == NR_NONE) reference = 0; return ScriptObject::DoCommand(0, type | (ref_type << 8) | (c << 16), reference, CMD_CUSTOM_NEWS_ITEM, encoded); } openttd-1.5.3/src/script/api/script_storypagelist.cpp0000644000000000000000000000226712627373434021562 0ustar rootroot/* $Id: script_storypagelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_storypagelist.cpp Implementation of ScriptStoryPageList and friends. */ #include "../../stdafx.h" #include "script_storypagelist.hpp" #include "script_story_page.hpp" #include "../../story_base.h" #include "../../safeguards.h" ScriptStoryPageList::ScriptStoryPageList(ScriptCompany::CompanyID company) { uint8 c = company; if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; StoryPage *p; FOR_ALL_STORY_PAGES(p) { if (p->company == c || p->company == INVALID_COMPANY) { this->AddItem(p->index); } } } openttd-1.5.3/src/script/api/script_subsidy.cpp0000644000000000000000000000733112627373434020330 0ustar rootroot/* $Id: script_subsidy.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_subsidy.cpp Implementation of ScriptSubsidy. */ #include "../../stdafx.h" #include "script_subsidy.hpp" #include "script_date.hpp" #include "script_industry.hpp" #include "script_town.hpp" #include "script_error.hpp" #include "../../subsidy_base.h" #include "../../station_base.h" #include "../../safeguards.h" /* static */ bool ScriptSubsidy::IsValidSubsidy(SubsidyID subsidy_id) { return ::Subsidy::IsValidID(subsidy_id); } /* static */ bool ScriptSubsidy::IsAwarded(SubsidyID subsidy_id) { if (!IsValidSubsidy(subsidy_id)) return false; return ::Subsidy::Get(subsidy_id)->IsAwarded(); } /* static */ bool ScriptSubsidy::Create(CargoID cargo_type, SubsidyParticipantType from_type, uint16 from_id, SubsidyParticipantType to_type, uint16 to_id) { EnforcePrecondition(false, ScriptCargo::IsValidCargo(cargo_type)); EnforcePrecondition(false, from_type == SPT_INDUSTRY || from_type == SPT_TOWN); EnforcePrecondition(false, to_type == SPT_INDUSTRY || to_type == SPT_TOWN); EnforcePrecondition(false, (from_type == SPT_INDUSTRY && ScriptIndustry::IsValidIndustry(from_id)) || (from_type == SPT_TOWN && ScriptTown::IsValidTown(from_id))); EnforcePrecondition(false, (to_type == SPT_INDUSTRY && ScriptIndustry::IsValidIndustry(to_id)) || (to_type == SPT_TOWN && ScriptTown::IsValidTown(to_id))); return ScriptObject::DoCommand(0, from_type | (from_id << 8) | (cargo_type << 24), to_type | (to_id << 8), CMD_CREATE_SUBSIDY); } /* static */ ScriptCompany::CompanyID ScriptSubsidy::GetAwardedTo(SubsidyID subsidy_id) { if (!IsAwarded(subsidy_id)) return ScriptCompany::COMPANY_INVALID; return (ScriptCompany::CompanyID)((byte)::Subsidy::Get(subsidy_id)->awarded); } /* static */ ScriptDate::Date ScriptSubsidy::GetExpireDate(SubsidyID subsidy_id) { if (!IsValidSubsidy(subsidy_id)) return ScriptDate::DATE_INVALID; int year = ScriptDate::GetYear(ScriptDate::GetCurrentDate()); int month = ScriptDate::GetMonth(ScriptDate::GetCurrentDate()); month += ::Subsidy::Get(subsidy_id)->remaining; year += (month - 1) / 12; month = ((month - 1) % 12) + 1; return ScriptDate::GetDate(year, month, 1); } /* static */ CargoID ScriptSubsidy::GetCargoType(SubsidyID subsidy_id) { if (!IsValidSubsidy(subsidy_id)) return CT_INVALID; return ::Subsidy::Get(subsidy_id)->cargo_type; } /* static */ ScriptSubsidy::SubsidyParticipantType ScriptSubsidy::GetSourceType(SubsidyID subsidy_id) { if (!IsValidSubsidy(subsidy_id)) return SPT_INVALID; return (SubsidyParticipantType)(uint)::Subsidy::Get(subsidy_id)->src_type; } /* static */ int32 ScriptSubsidy::GetSourceIndex(SubsidyID subsidy_id) { if (!IsValidSubsidy(subsidy_id)) return INVALID_STATION; return ::Subsidy::Get(subsidy_id)->src; } /* static */ ScriptSubsidy::SubsidyParticipantType ScriptSubsidy::GetDestinationType(SubsidyID subsidy_id) { if (!IsValidSubsidy(subsidy_id)) return SPT_INVALID; return (SubsidyParticipantType)(uint)::Subsidy::Get(subsidy_id)->dst_type; } /* static */ int32 ScriptSubsidy::GetDestinationIndex(SubsidyID subsidy_id) { if (!IsValidSubsidy(subsidy_id)) return INVALID_STATION; return ::Subsidy::Get(subsidy_id)->dst; } openttd-1.5.3/src/script/api/script_vehicle.hpp0000644000000000000000000005545312627373434020302 0ustar rootroot/* $Id: script_vehicle.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 script_vehicle.hpp Everything to query and build vehicles. */ #ifndef SCRIPT_VEHICLE_HPP #define SCRIPT_VEHICLE_HPP #include "script_road.hpp" /** * Class that handles all vehicle related functions. * @api ai game */ class ScriptVehicle : public ScriptObject { public: /** * All vehicle related error messages. */ enum ErrorMessages { /** Base for vehicle related errors */ ERR_VEHICLE_BASE = ScriptError::ERR_CAT_VEHICLE << ScriptError::ERR_CAT_BIT_SIZE, /** Too many vehicles in the game, can't build any more. */ ERR_VEHICLE_TOO_MANY, // [STR_ERROR_TOO_MANY_VEHICLES_IN_GAME] /** Vehicle is not available */ ERR_VEHICLE_NOT_AVAILABLE, // [STR_ERROR_AIRCRAFT_NOT_AVAILABLE, STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE, STR_ERROR_SHIP_NOT_AVAILABLE, STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE] /** Vehicle can't be build due to game settigns */ ERR_VEHICLE_BUILD_DISABLED, // [STR_ERROR_CAN_T_BUY_TRAIN, STR_ERROR_CAN_T_BUY_ROAD_VEHICLE, STR_ERROR_CAN_T_BUY_SHIP, STR_ERROR_CAN_T_BUY_AIRCRAFT] /** Vehicle can't be build in the selected depot */ ERR_VEHICLE_WRONG_DEPOT, // [STR_ERROR_DEPOT_WRONG_DEPOT_TYPE] /** Vehicle can't return to the depot */ ERR_VEHICLE_CANNOT_SEND_TO_DEPOT, // [STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT, STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT, STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR] /** Vehicle can't start / stop */ ERR_VEHICLE_CANNOT_START_STOP, // [STR_ERROR_CAN_T_STOP_START_TRAIN, STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE, STR_ERROR_CAN_T_STOP_START_SHIP, STR_ERROR_CAN_T_STOP_START_AIRCRAFT] /** Vehicle can't turn */ ERR_VEHICLE_CANNOT_TURN, // [STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN, STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN, STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE, STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS] /** Vehicle can't be refit */ ERR_VEHICLE_CANNOT_REFIT, // [STR_ERROR_CAN_T_REFIT_TRAIN, STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE, STR_ERROR_CAN_T_REFIT_SHIP, STR_ERROR_CAN_T_REFIT_AIRCRAFT] /** Vehicle is destroyed */ ERR_VEHICLE_IS_DESTROYED, // [STR_ERROR_VEHICLE_IS_DESTROYED] /** Vehicle is not in a depot */ ERR_VEHICLE_NOT_IN_DEPOT, // [STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR, STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT, STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT, STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT] /** Vehicle is flying */ ERR_VEHICLE_IN_FLIGHT, // [STR_ERROR_AIRCRAFT_IS_IN_FLIGHT] /** Vehicle is without power */ ERR_VEHICLE_NO_POWER, // [STR_ERROR_TRAIN_START_NO_POWER] /** Vehicle would get too long during construction. */ ERR_VEHICLE_TOO_LONG, // [STR_ERROR_TRAIN_TOO_LONG] }; /** * The type of a vehicle available in the game. Trams for example are * road vehicles, as maglev is a rail vehicle. */ enum VehicleType { VT_RAIL, ///< Rail type vehicle. VT_ROAD, ///< Road type vehicle (bus / truck). VT_WATER, ///< Water type vehicle. VT_AIR, ///< Air type vehicle. VT_INVALID = 0xFF, ///< Invalid vehicle type. }; /** * The different states a vehicle can be in. */ enum VehicleState { VS_RUNNING, ///< The vehicle is currently running. VS_STOPPED, ///< The vehicle is stopped manually. VS_IN_DEPOT, ///< The vehicle is stopped in the depot. VS_AT_STATION, ///< The vehicle is stopped at a station and is currently loading or unloading. VS_BROKEN, ///< The vehicle has broken down and will start running again in a while. VS_CRASHED, ///< The vehicle is crashed (and will never run again). VS_INVALID = 0xFF, ///< An invalid vehicle state. }; static const VehicleID VEHICLE_INVALID = 0xFFFFF; ///< Invalid VehicleID. /** * Checks whether the given vehicle is valid and owned by you. * @param vehicle_id The vehicle to check. * @return True if and only if the vehicle is valid. */ static bool IsValidVehicle(VehicleID vehicle_id); /** * Get the number of wagons a vehicle has. * @param vehicle_id The vehicle to get the number of wagons from. * @pre IsValidVehicle(vehicle_id). * @return The number of wagons the vehicle has. */ static int32 GetNumWagons(VehicleID vehicle_id); /** * Set the name of a vehicle. * @param vehicle_id The vehicle to set the name for. * @param name The name for the vehicle (can be either a raw string, or a ScriptText object). * @pre IsValidVehicle(vehicle_id). * @pre name != NULL && len(name) != 0. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if and only if the name was changed. */ static bool SetName(VehicleID vehicle_id, Text *name); /** * Get the name of a vehicle. * @param vehicle_id The vehicle to get the name of. * @pre IsValidVehicle(vehicle_id). * @return The name the vehicle has. */ static char *GetName(VehicleID vehicle_id); /** * Get the owner of a vehicle. * @param vehicle_id The vehicle to get the owner of. * @pre IsValidVehicle(vehicle_id). * @return The owner the vehicle has. * @api -ai */ static ScriptCompany::CompanyID GetOwner(VehicleID vehicle_id); /** * Get the current location of a vehicle. * @param vehicle_id The vehicle to get the location of. * @pre IsValidVehicle(vehicle_id). * @return The tile the vehicle is currently on. */ static TileIndex GetLocation(VehicleID vehicle_id); /** * Get the engine-type of a vehicle. * @param vehicle_id The vehicle to get the engine-type of. * @pre IsValidVehicle(vehicle_id). * @return The engine type the vehicle has. */ static EngineID GetEngineType(VehicleID vehicle_id); /** * Get the engine-type of a wagon. * @param vehicle_id The vehicle to get the engine-type of. * @param wagon The wagon in the vehicle to get the engine-type of. * @pre IsValidVehicle(vehicle_id). * @pre wagon < GetNumWagons(vehicle_id). * @return The engine type the vehicle has. */ static EngineID GetWagonEngineType(VehicleID vehicle_id, int wagon); /** * Get the unitnumber of a vehicle. * @param vehicle_id The vehicle to get the unitnumber of. * @pre IsValidVehicle(vehicle_id). * @return The unitnumber the vehicle has. */ static int32 GetUnitNumber(VehicleID vehicle_id); /** * Get the current age of a vehicle. * @param vehicle_id The vehicle to get the age of. * @pre IsValidVehicle(vehicle_id). * @return The current age the vehicle has. * @note The age is in days. */ static int32 GetAge(VehicleID vehicle_id); /** * Get the current age of a second (or third, etc.) engine in a train vehicle. * @param vehicle_id The vehicle to get the age of. * @param wagon The wagon in the vehicle to get the age of. * @pre IsValidVehicle(vehicle_id). * @pre wagon < GetNumWagons(vehicle_id). * @return The current age the vehicle has. * @note The age is in days. */ static int32 GetWagonAge(VehicleID vehicle_id, int wagon); /** * Get the maximum age of a vehicle. * @param vehicle_id The vehicle to get the age of. * @pre IsValidVehicle(vehicle_id). * @return The maximum age the vehicle has. * @note The age is in days. */ static int32 GetMaxAge(VehicleID vehicle_id); /** * Get the age a vehicle has left (maximum - current). * @param vehicle_id The vehicle to get the age of. * @pre IsValidVehicle(vehicle_id). * @return The age the vehicle has left. * @note The age is in days. */ static int32 GetAgeLeft(VehicleID vehicle_id); /** * Get the current speed of a vehicle. * @param vehicle_id The vehicle to get the speed of. * @pre IsValidVehicle(vehicle_id). * @return The current speed of the vehicle. * @note The speed is in OpenTTD's internal speed unit. * This is mph / 1.6, which is roughly km/h. * To get km/h multiply this number by 1.00584. */ static int32 GetCurrentSpeed(VehicleID vehicle_id); /** * Get the current state of a vehicle. * @param vehicle_id The vehicle to get the state of. * @pre IsValidVehicle(vehicle_id). * @return The current state of the vehicle. */ static VehicleState GetState(VehicleID vehicle_id); /** * Get the running cost of this vehicle. * @param vehicle_id The vehicle to get the running cost of. * @pre IsValidVehicle(vehicle_id). * @return The running cost of the vehicle per year. * @note Cost is per year; divide by 365 to get per day. * @note This is not equal to ScriptEngine::GetRunningCost for Trains, because * wagons and second engines can add up in the calculation too. */ static Money GetRunningCost(VehicleID vehicle_id); /** * Get the current profit of a vehicle. * @param vehicle_id The vehicle to get the profit of. * @pre IsValidVehicle(vehicle_id). * @return The current profit the vehicle has. */ static Money GetProfitThisYear(VehicleID vehicle_id); /** * Get the profit of last year of a vehicle. * @param vehicle_id The vehicle to get the profit of. * @pre IsValidVehicle(vehicle_id). * @return The profit the vehicle had last year. */ static Money GetProfitLastYear(VehicleID vehicle_id); /** * Get the current value of a vehicle. * @param vehicle_id The vehicle to get the value of. * @pre IsValidVehicle(vehicle_id). * @return The value the vehicle currently has (the amount you should get * when you would sell the vehicle right now). */ static Money GetCurrentValue(VehicleID vehicle_id); /** * Get the type of vehicle. * @param vehicle_id The vehicle to get the type of. * @pre IsValidVehicle(vehicle_id). * @return The vehicle type. */ static ScriptVehicle::VehicleType GetVehicleType(VehicleID vehicle_id); /** * Get the RoadType of the vehicle. * @param vehicle_id The vehicle to get the RoadType of. * @pre IsValidVehicle(vehicle_id). * @pre GetVehicleType(vehicle_id) == VT_ROAD. * @return The RoadType the vehicle has. */ static ScriptRoad::RoadType GetRoadType(VehicleID vehicle_id); /** * Check if a vehicle is in a depot. * @param vehicle_id The vehicle to check. * @pre IsValidVehicle(vehicle_id). * @return True if and only if the vehicle is in a depot. */ static bool IsInDepot(VehicleID vehicle_id); /** * Check if a vehicle is in a depot and stopped. * @param vehicle_id The vehicle to check. * @pre IsValidVehicle(vehicle_id). * @return True if and only if the vehicle is in a depot and stopped. */ static bool IsStoppedInDepot(VehicleID vehicle_id); /** * Builds a vehicle with the given engine at the given depot. * @param depot The depot where the vehicle will be build. * @param engine_id The engine to use for this vehicle. * @pre The tile at depot has a depot that can build the engine and * is owned by you. * @pre ScriptEngine::IsBuildable(engine_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_TOO_MANY * @exception ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED * @exception ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT * @return The VehicleID of the new vehicle, or an invalid VehicleID when * it failed. Check the return value using IsValidVehicle. In test-mode * 0 is returned if it was successful; any other value indicates failure. * @note In Test Mode it means you can't assign orders yet to this vehicle, * as the vehicle isn't really built yet. Build it for real first before * assigning orders. */ static VehicleID BuildVehicle(TileIndex depot, EngineID engine_id); /** * Clones a vehicle at the given depot, copying or cloning its orders. * @param depot The depot where the vehicle will be build. * @param vehicle_id The vehicle to use as example for the new vehicle. * @param share_orders Should the orders be copied or shared? * @pre The tile 'depot' has a depot on it, allowing 'vehicle_id'-type vehicles. * @pre IsValidVehicle(vehicle_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_TOO_MANY * @exception ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED * @exception ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT * @return The VehicleID of the new vehicle, or an invalid VehicleID when * it failed. Check the return value using IsValidVehicle. In test-mode * 0 is returned if it was successful; any other value indicates failure. */ static VehicleID CloneVehicle(TileIndex depot, VehicleID vehicle_id, bool share_orders); /** * Move a wagon after another wagon. * @param source_vehicle_id The vehicle to move a wagon away from. * @param source_wagon The wagon in source_vehicle to move. * @param dest_vehicle_id The vehicle to move the wagon to, or -1 to create a new vehicle. * @param dest_wagon The wagon in dest_vehicle to place source_wagon after. * @pre IsValidVehicle(source_vehicle_id). * @pre source_wagon < GetNumWagons(source_vehicle_id). * @pre dest_vehicle_id == -1 || (IsValidVehicle(dest_vehicle_id) && dest_wagon < GetNumWagons(dest_vehicle_id)). * @pre GetVehicleType(source_vehicle_id) == VT_RAIL. * @pre dest_vehicle_id == -1 || GetVehicleType(dest_vehicle_id) == VT_RAIL. * @game @pre Valid ScriptCompanyMode active in scope. * @return Whether or not moving the wagon succeeded. */ static bool MoveWagon(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon); /** * Move a chain of wagons after another wagon. * @param source_vehicle_id The vehicle to move a wagon away from. * @param source_wagon The first wagon in source_vehicle to move. * @param dest_vehicle_id The vehicle to move the wagons to, or -1 to create a new vehicle. * @param dest_wagon The wagon in dest_vehicle to place source_wagon and following wagons after. * @pre IsValidVehicle(source_vehicle_id). * @pre source_wagon < GetNumWagons(source_vehicle_id). * @pre dest_vehicle_id == -1 || (IsValidVehicle(dest_vehicle_id) && dest_wagon < GetNumWagons(dest_vehicle_id)). * @pre GetVehicleType(source_vehicle_id) == VT_RAIL. * @pre dest_vehicle_id == -1 || GetVehicleType(dest_vehicle_id) == VT_RAIL. * @game @pre Valid ScriptCompanyMode active in scope. * @return Whether or not moving the wagons succeeded. */ static bool MoveWagonChain(VehicleID source_vehicle_id, int source_wagon, int dest_vehicle_id, int dest_wagon); /** * Gets the capacity of the given vehicle when refitted to the given cargo type. * @param vehicle_id The vehicle to refit. * @param cargo The cargo to refit to. * @pre IsValidVehicle(vehicle_id). * @pre ScriptCargo::IsValidCargo(cargo). * @pre You must own the vehicle. * @pre The vehicle must be stopped in the depot. * @return The capacity the vehicle will have when refited. */ static int GetRefitCapacity(VehicleID vehicle_id, CargoID cargo); /** * Refits a vehicle to the given cargo type. * @param vehicle_id The vehicle to refit. * @param cargo The cargo to refit to. * @pre IsValidVehicle(vehicle_id). * @pre ScriptCargo::IsValidCargo(cargo). * @pre You must own the vehicle. * @pre The vehicle must be stopped in the depot. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT * @exception ScriptVehicle::ERR_VEHICLE_IS_DESTROYED * @exception ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT * @return True if and only if the refit succeeded. */ static bool RefitVehicle(VehicleID vehicle_id, CargoID cargo); /** * Sells the given vehicle. * @param vehicle_id The vehicle to sell. * @pre IsValidVehicle(vehicle_id). * @pre You must own the vehicle. * @pre The vehicle must be stopped in the depot. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_IS_DESTROYED * @exception ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT * @return True if and only if the vehicle has been sold. */ static bool SellVehicle(VehicleID vehicle_id); /** * Sells the given wagon from the vehicle. * @param vehicle_id The vehicle to sell a wagon from. * @param wagon The wagon to sell. * @pre IsValidVehicle(vehicle_id). * @pre wagon < GetNumWagons(vehicle_id). * @pre You must own the vehicle. * @pre The vehicle must be stopped in the depot. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_IS_DESTROYED * @exception ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT * @return True if and only if the wagon has been sold. */ static bool SellWagon(VehicleID vehicle_id, int wagon); /** * Sells all wagons from the vehicle starting from a given position. * @param vehicle_id The vehicle to sell a wagon from. * @param wagon The wagon to sell. * @pre IsValidVehicle(vehicle_id). * @pre wagon < GetNumWagons(vehicle_id). * @pre You must own the vehicle. * @pre The vehicle must be stopped in the depot. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_IS_DESTROYED * @exception ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT * @return True if and only if the wagons have been sold. */ static bool SellWagonChain(VehicleID vehicle_id, int wagon); /** * Sends the given vehicle to a depot. If the vehicle has already been * sent to a depot it continues with its normal orders instead. * @param vehicle_id The vehicle to send to a depot. * @pre IsValidVehicle(vehicle_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT * @return True if the current order was changed. */ static bool SendVehicleToDepot(VehicleID vehicle_id); /** * Sends the given vehicle to a depot for servicing. If the vehicle has * already been sent to a depot it continues with its normal orders instead. * @param vehicle_id The vehicle to send to a depot for servicing. * @pre IsValidVehicle(vehicle_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT * @return True if the current order was changed. */ static bool SendVehicleToDepotForServicing(VehicleID vehicle_id); /** * Starts or stops the given vehicle depending on the current state. * @param vehicle_id The vehicle to start/stop. * @pre IsValidVehicle(vehicle_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP * @exception (For aircraft only): ScriptVehicle::ERR_VEHICLE_IN_FLIGHT * @exception (For trains only): ScriptVehicle::ERR_VEHICLE_NO_POWER * @return True if and only if the vehicle has been started or stopped. */ static bool StartStopVehicle(VehicleID vehicle_id); /** * Turn the given vehicle so it'll drive the other way. * @param vehicle_id The vehicle to turn. * @pre IsValidVehicle(vehicle_id). * @pre GetVehicleType(vehicle_id) == VT_ROAD || GetVehicleType(vehicle_id) == VT_RAIL. * @game @pre Valid ScriptCompanyMode active in scope. * @return True if and only if the vehicle has started to turn. * @note Vehicles cannot always be reversed. For example busses and trucks need to be running * and not be inside a depot. */ static bool ReverseVehicle(VehicleID vehicle_id); /** * Get the maximum amount of a specific cargo the given vehicle can transport. * @param vehicle_id The vehicle to get the capacity of. * @param cargo The cargo to get the capacity for. * @pre IsValidVehicle(vehicle_id). * @pre ScriptCargo::IsValidCargo(cargo). * @return The maximum amount of the given cargo the vehicle can transport. */ static int32 GetCapacity(VehicleID vehicle_id, CargoID cargo); /** * Get the length of a the total vehicle in 1/16's of a tile. * @param vehicle_id The vehicle to get the length of. * @pre IsValidVehicle(vehicle_id). * @pre GetVehicleType(vehicle_id) == VT_ROAD || GetVehicleType(vehicle_id) == VT_RAIL. * @return The length of the engine. */ static int GetLength(VehicleID vehicle_id); /** * Get the amount of a specific cargo the given vehicle is transporting. * @param vehicle_id The vehicle to get the load amount of. * @param cargo The cargo to get the loaded amount for. * @pre IsValidVehicle(vehicle_id). * @pre ScriptCargo::IsValidCargo(cargo). * @return The amount of the given cargo the vehicle is currently transporting. */ static int32 GetCargoLoad(VehicleID vehicle_id, CargoID cargo); /** * Get the group of a given vehicle. * @param vehicle_id The vehicle to get the group from. * @return The group of the given vehicle. */ static GroupID GetGroupID(VehicleID vehicle_id); /** * Check if the vehicle is articulated. * @param vehicle_id The vehicle to check. * @pre IsValidVehicle(vehicle_id). * @pre GetVehicleType(vehicle_id) == VT_ROAD || GetVehicleType(vehicle_id) == VT_RAIL. * @return True if the vehicle is articulated. */ static bool IsArticulated(VehicleID vehicle_id); /** * Check if the vehicle has shared orders. * @param vehicle_id The vehicle to check. * @pre IsValidVehicle(vehicle_id). * @return True if the vehicle has shared orders. */ static bool HasSharedOrders(VehicleID vehicle_id); /** * Get the current reliability of a vehicle. * @param vehicle_id The vehicle to check. * @pre IsValidVehicle(vehicle_id). * @return The current reliability (0-100%). */ static int GetReliability(VehicleID vehicle_id); /** * Get the maximum allowed distance between two orders for a vehicle. * The distance returned is a vehicle-type specific distance independent from other * map distances, you may use the result of this function to compare it * with the result of ScriptOrder::GetOrderDistance. * @param vehicle_id The vehicle to get the distance for. * @pre IsValidVehicle(vehicle_id). * @return The maximum distance between two orders for this vehicle * or 0 if the distance is unlimited. * @note The unit of the order distances is unspecified and should * not be compared with map distances * @see ScriptOrder::GetOrderDistance */ static uint GetMaximumOrderDistance(VehicleID vehicle_id); private: /** * Internal function used by SellWagon(Chain). */ static bool _SellWagonInternal(VehicleID vehicle_id, int wagon, bool sell_attached_wagons); /** * Internal function used by MoveWagon(Chain). */ static bool _MoveWagonInternal(VehicleID source_vehicle_id, int source_wagon, bool move_attached_wagons, int dest_vehicle_id, int dest_wagon); }; #endif /* SCRIPT_VEHICLE_HPP */ openttd-1.5.3/src/script/api/script_object.cpp0000644000000000000000000002274312627373434020120 0ustar rootroot/* $Id: script_object.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 script_object.cpp Implementation of ScriptObject. */ #include "../../stdafx.h" #include "../../script/squirrel.hpp" #include "../../command_func.h" #include "../../company_func.h" #include "../../company_base.h" #include "../../network/network.h" #include "../../genworld.h" #include "../../string_func.h" #include "../../strings_func.h" #include "../script_storage.hpp" #include "../script_instance.hpp" #include "../script_fatalerror.hpp" #include "script_error.hpp" #include "../../safeguards.h" /** * Get the storage associated with the current ScriptInstance. * @return The storage. */ static ScriptStorage *GetStorage() { return ScriptObject::GetActiveInstance()->GetStorage(); } /* static */ ScriptInstance *ScriptObject::ActiveInstance::active = NULL; ScriptObject::ActiveInstance::ActiveInstance(ScriptInstance *instance) { this->last_active = ScriptObject::ActiveInstance::active; ScriptObject::ActiveInstance::active = instance; } ScriptObject::ActiveInstance::~ActiveInstance() { ScriptObject::ActiveInstance::active = this->last_active; } /* static */ ScriptInstance *ScriptObject::GetActiveInstance() { assert(ScriptObject::ActiveInstance::active != NULL); return ScriptObject::ActiveInstance::active; } /* static */ void ScriptObject::SetDoCommandDelay(uint ticks) { assert(ticks > 0); GetStorage()->delay = ticks; } /* static */ uint ScriptObject::GetDoCommandDelay() { return GetStorage()->delay; } /* static */ void ScriptObject::SetDoCommandMode(ScriptModeProc *proc, ScriptObject *instance) { GetStorage()->mode = proc; GetStorage()->mode_instance = instance; } /* static */ ScriptModeProc *ScriptObject::GetDoCommandMode() { return GetStorage()->mode; } /* static */ ScriptObject *ScriptObject::GetDoCommandModeInstance() { return GetStorage()->mode_instance; } /* static */ void ScriptObject::SetDoCommandCosts(Money value) { GetStorage()->costs = CommandCost(value); } /* static */ void ScriptObject::IncreaseDoCommandCosts(Money value) { GetStorage()->costs.AddCost(value); } /* static */ Money ScriptObject::GetDoCommandCosts() { return GetStorage()->costs.GetCost(); } /* static */ void ScriptObject::SetLastError(ScriptErrorType last_error) { GetStorage()->last_error = last_error; } /* static */ ScriptErrorType ScriptObject::GetLastError() { return GetStorage()->last_error; } /* static */ void ScriptObject::SetLastCost(Money last_cost) { GetStorage()->last_cost = last_cost; } /* static */ Money ScriptObject::GetLastCost() { return GetStorage()->last_cost; } /* static */ void ScriptObject::SetRoadType(RoadType road_type) { GetStorage()->road_type = road_type; } /* static */ RoadType ScriptObject::GetRoadType() { return GetStorage()->road_type; } /* static */ void ScriptObject::SetRailType(RailType rail_type) { GetStorage()->rail_type = rail_type; } /* static */ RailType ScriptObject::GetRailType() { return GetStorage()->rail_type; } /* static */ void ScriptObject::SetLastCommandRes(bool res) { GetStorage()->last_command_res = res; /* Also store the results of various global variables */ SetNewVehicleID(_new_vehicle_id); SetNewSignID(_new_sign_id); SetNewGroupID(_new_group_id); SetNewGoalID(_new_goal_id); SetNewStoryPageID(_new_story_page_id); SetNewStoryPageElementID(_new_story_page_element_id); } /* static */ bool ScriptObject::GetLastCommandRes() { return GetStorage()->last_command_res; } /* static */ void ScriptObject::SetNewVehicleID(VehicleID vehicle_id) { GetStorage()->new_vehicle_id = vehicle_id; } /* static */ VehicleID ScriptObject::GetNewVehicleID() { return GetStorage()->new_vehicle_id; } /* static */ void ScriptObject::SetNewSignID(SignID sign_id) { GetStorage()->new_sign_id = sign_id; } /* static */ SignID ScriptObject::GetNewSignID() { return GetStorage()->new_sign_id; } /* static */ void ScriptObject::SetNewGroupID(GroupID group_id) { GetStorage()->new_group_id = group_id; } /* static */ GroupID ScriptObject::GetNewGroupID() { return GetStorage()->new_group_id; } /* static */ void ScriptObject::SetNewGoalID(GoalID goal_id) { GetStorage()->new_goal_id = goal_id; } /* static */ GroupID ScriptObject::GetNewGoalID() { return GetStorage()->new_goal_id; } /* static */ void ScriptObject::SetNewStoryPageID(StoryPageID story_page_id) { GetStorage()->new_story_page_id = story_page_id; } /* static */ GroupID ScriptObject::GetNewStoryPageID() { return GetStorage()->new_story_page_id; } /* static */ void ScriptObject::SetNewStoryPageElementID(StoryPageElementID story_page_element_id) { GetStorage()->new_story_page_element_id = story_page_element_id; } /* static */ GroupID ScriptObject::GetNewStoryPageElementID() { return GetStorage()->new_story_page_element_id; } /* static */ void ScriptObject::SetAllowDoCommand(bool allow) { GetStorage()->allow_do_command = allow; } /* static */ bool ScriptObject::GetAllowDoCommand() { return GetStorage()->allow_do_command; } /* static */ void ScriptObject::SetCompany(CompanyID company) { if (GetStorage()->root_company == INVALID_OWNER) GetStorage()->root_company = company; GetStorage()->company = company; _current_company = company; } /* static */ CompanyID ScriptObject::GetCompany() { return GetStorage()->company; } /* static */ CompanyID ScriptObject::GetRootCompany() { return GetStorage()->root_company; } /* static */ bool ScriptObject::CanSuspend() { Squirrel *squirrel = ScriptObject::GetActiveInstance()->engine; return GetStorage()->allow_do_command && squirrel->CanSuspend(); } /* static */ void *&ScriptObject::GetEventPointer() { return GetStorage()->event_data; } /* static */ void *&ScriptObject::GetLogPointer() { return GetStorage()->log_data; } /* static */ char *ScriptObject::GetString(StringID string) { char buffer[64]; ::GetString(buffer, string, lastof(buffer)); ::str_validate(buffer, lastof(buffer), SVS_NONE); return ::stredup(buffer); } /* static */ void ScriptObject::SetCallbackVariable(int index, int value) { if ((size_t)index >= GetStorage()->callback_value.size()) GetStorage()->callback_value.resize(index + 1); GetStorage()->callback_value[index] = value; } /* static */ int ScriptObject::GetCallbackVariable(int index) { return GetStorage()->callback_value[index]; } /* static */ bool ScriptObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, Script_SuspendCallbackProc *callback) { if (!ScriptObject::CanSuspend()) { throw Script_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator."); } if (ScriptObject::GetCompany() != OWNER_DEITY && !::Company::IsValidID(ScriptObject::GetCompany())) { ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_INVALID_COMPANY); return false; } if (!StrEmpty(text) && (GetCommandFlags(cmd) & CMD_STR_CTRL) == 0) { /* The string must be valid, i.e. not contain special codes. Since some * can be made with GSText, make sure the control codes are removed. */ ::str_validate(const_cast(text), text + strlen(text), SVS_NONE); } /* Set the default callback to return a true/false result of the DoCommand */ if (callback == NULL) callback = &ScriptInstance::DoCommandReturn; /* Are we only interested in the estimate costs? */ bool estimate_only = GetDoCommandMode() != NULL && !GetDoCommandMode()(); #ifdef ENABLE_NETWORK /* Only set p2 when the command does not come from the network. */ if (GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = UINT32_MAX; #endif /* Try to perform the command. */ CommandCost res = ::DoCommandPInternal(tile, p1, p2, cmd, (_networking && !_generating_world) ? ScriptObject::GetActiveInstance()->GetDoCommandCallback() : NULL, text, false, estimate_only); /* We failed; set the error and bail out */ if (res.Failed()) { SetLastError(ScriptError::StringToError(res.GetErrorMessage())); return false; } /* No error, then clear it. */ SetLastError(ScriptError::ERR_NONE); /* Estimates, update the cost for the estimate and be done */ if (estimate_only) { IncreaseDoCommandCosts(res.GetCost()); return true; } /* Costs of this operation. */ SetLastCost(res.GetCost()); SetLastCommandRes(true); if (_generating_world) { IncreaseDoCommandCosts(res.GetCost()); if (callback != NULL) { /* Insert return value into to stack and throw a control code that * the return value in the stack should be used. */ callback(GetActiveInstance()); throw SQInteger(1); } return true; } else if (_networking) { /* Suspend the script till the command is really executed. */ throw Script_Suspend(-(int)GetDoCommandDelay(), callback); } else { IncreaseDoCommandCosts(res.GetCost()); /* Suspend the script player for 1+ ticks, so it simulates multiplayer. This * both avoids confusion when a developer launched his script in a * multiplayer game, but also gives time for the GUI and human player * to interact with the game. */ throw Script_Suspend(GetDoCommandDelay(), callback); } NOT_REACHED(); } openttd-1.5.3/src/script/api/script_event_types.hpp0000644000000000000000000007371312627373434021227 0ustar rootroot/* $Id: script_event_types.hpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 script_event_types.hpp The detailed types of all events. */ #ifndef SCRIPT_EVENT_TYPES_HPP #define SCRIPT_EVENT_TYPES_HPP #include "script_event.hpp" #include "script_goal.hpp" #include "script_window.hpp" /** * Event Vehicle Crash, indicating a vehicle of yours is crashed. * It contains the crash site, the crashed vehicle and the reason for the crash. * @api ai game */ class ScriptEventVehicleCrashed : public ScriptEvent { public: /** * The reasons for vehicle crashes */ enum CrashReason { CRASH_TRAIN, ///< Two trains collided CRASH_RV_LEVEL_CROSSING, ///< Road vehicle got under a train CRASH_RV_UFO, ///< Road vehicle got under a landing ufo CRASH_PLANE_LANDING, ///< Plane crashed on landing CRASH_AIRCRAFT_NO_AIRPORT, ///< Aircraft crashed after it found not a single airport for landing CRASH_FLOODED, ///< Vehicle was flooded }; /** * @param vehicle The vehicle that crashed. * @param crash_site Where the vehicle crashed. * @param crash_reason The reason why the vehicle crashed. */ ScriptEventVehicleCrashed(VehicleID vehicle, TileIndex crash_site, CrashReason crash_reason) : ScriptEvent(ET_VEHICLE_CRASHED), crash_site(crash_site), vehicle(vehicle), crash_reason(crash_reason) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventVehicleCrashed *Convert(ScriptEvent *instance) { return (ScriptEventVehicleCrashed *)instance; } /** * Get the VehicleID of the crashed vehicle. * @return The crashed vehicle. */ VehicleID GetVehicleID() { return this->vehicle; } /** * Find the tile the vehicle crashed. * @return The crash site. */ TileIndex GetCrashSite() { return this->crash_site; } /** * Get the reason for crashing * @return The reason for crashing */ CrashReason GetCrashReason() { return this->crash_reason; } private: TileIndex crash_site; ///< The location of the crash. VehicleID vehicle; ///< The crashed vehicle. CrashReason crash_reason; ///< The reason for crashing. }; /** * Event Subsidy Offered, indicating someone offered a subsidy. * @api ai game */ class ScriptEventSubsidyOffer : public ScriptEvent { public: /** * @param subsidy_id The index of this subsidy in the _subsidies array. */ ScriptEventSubsidyOffer(SubsidyID subsidy_id) : ScriptEvent(ET_SUBSIDY_OFFER), subsidy_id(subsidy_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventSubsidyOffer *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyOffer *)instance; } /** * Get the SubsidyID of the subsidy. * @return The subsidy id. */ SubsidyID GetSubsidyID() { return this->subsidy_id; } private: SubsidyID subsidy_id; ///< The subsidy that got offered. }; /** * Event Subsidy Offer Expired, indicating a subsidy will no longer be awarded. * @api ai game */ class ScriptEventSubsidyOfferExpired : public ScriptEvent { public: /** * @param subsidy_id The index of this subsidy in the _subsidies array. */ ScriptEventSubsidyOfferExpired(SubsidyID subsidy_id) : ScriptEvent(ET_SUBSIDY_OFFER_EXPIRED), subsidy_id(subsidy_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventSubsidyOfferExpired *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyOfferExpired *)instance; } /** * Get the SubsidyID of the subsidy. * @return The subsidy id. */ SubsidyID GetSubsidyID() { return this->subsidy_id; } private: SubsidyID subsidy_id; ///< The subsidy offer that expired. }; /** * Event Subsidy Awarded, indicating a subsidy is awarded to some company. * @api ai game */ class ScriptEventSubsidyAwarded : public ScriptEvent { public: /** * @param subsidy_id The index of this subsidy in the _subsidies array. */ ScriptEventSubsidyAwarded(SubsidyID subsidy_id) : ScriptEvent(ET_SUBSIDY_AWARDED), subsidy_id(subsidy_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventSubsidyAwarded *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyAwarded *)instance; } /** * Get the SubsidyID of the subsidy. * @return The subsidy id. */ SubsidyID GetSubsidyID() { return this->subsidy_id; } private: SubsidyID subsidy_id; ///< The subsidy that was awarded. }; /** * Event Subsidy Expired, indicating a route that was once subsidized no longer is. * @api ai game */ class ScriptEventSubsidyExpired : public ScriptEvent { public: /** * @param subsidy_id The index of this subsidy in the _subsidies array. */ ScriptEventSubsidyExpired(SubsidyID subsidy_id) : ScriptEvent(ET_SUBSIDY_EXPIRED), subsidy_id(subsidy_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventSubsidyExpired *Convert(ScriptEvent *instance) { return (ScriptEventSubsidyExpired *)instance; } /** * Get the SubsidyID of the subsidy. * @return The subsidy id. */ SubsidyID GetSubsidyID() { return this->subsidy_id; } private: SubsidyID subsidy_id; ///< The subsidy that expired. }; /** * Event Engine Preview, indicating a manufacturer offer you to test a new engine. * You can get the same information about the offered engine as a real user * would see in the offer window. And you can also accept the offer. * @api ai */ class ScriptEventEnginePreview : public ScriptEvent { public: /** * @param engine The engine offered to test. */ ScriptEventEnginePreview(EngineID engine) : ScriptEvent(ET_ENGINE_PREVIEW), engine(engine) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventEnginePreview *Convert(ScriptEvent *instance) { return (ScriptEventEnginePreview *)instance; } /** * Get the name of the offered engine. * @return The name the engine has. */ char *GetName(); /** * Get the cargo-type of the offered engine. In case it can transport multiple cargoes, it * returns the first/main. * @return The cargo-type of the engine. */ CargoID GetCargoType(); /** * Get the capacity of the offered engine. In case it can transport multiple cargoes, it * returns the first/main. * @return The capacity of the engine. */ int32 GetCapacity(); /** * Get the maximum speed of the offered engine. * @return The maximum speed the engine has. * @note The speed is in OpenTTD's internal speed unit. * This is mph / 1.6, which is roughly km/h. * To get km/h multiply this number by 1.00584. */ int32 GetMaxSpeed(); /** * Get the new cost of the offered engine. * @return The new cost the engine has. */ Money GetPrice(); /** * Get the running cost of the offered engine. * @return The running cost of the vehicle per year. * @note Cost is per year; divide by 365 to get per day. */ Money GetRunningCost(); /** * Get the type of the offered engine. * @return The type the engine has. */ #ifdef DOXYGEN_API ScriptVehicle::VehicleType GetVehicleType(); #else int32 GetVehicleType(); #endif /* DOXYGEN_API */ /** * Accept the engine preview. * @return True when the accepting succeeded. */ bool AcceptPreview(); private: EngineID engine; ///< The engine the preview is for. /** * Check whether the engine from this preview is still valid. * @return True iff the engine is still valid. */ bool IsEngineValid() const; }; /** * Event Company New, indicating a new company has been created. * @api ai game */ class ScriptEventCompanyNew : public ScriptEvent { public: /** * @param owner The new company. */ ScriptEventCompanyNew(Owner owner) : ScriptEvent(ET_COMPANY_NEW), owner((ScriptCompany::CompanyID)owner) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventCompanyNew *Convert(ScriptEvent *instance) { return (ScriptEventCompanyNew *)instance; } /** * Get the CompanyID of the company that has been created. * @return The CompanyID of the company. */ ScriptCompany::CompanyID GetCompanyID() { return this->owner; } private: ScriptCompany::CompanyID owner; ///< The new company. }; /** * Event Company In Trouble, indicating a company is in trouble and might go * bankrupt soon. * @api ai game */ class ScriptEventCompanyInTrouble : public ScriptEvent { public: /** * @param owner The company that is in trouble. */ ScriptEventCompanyInTrouble(Owner owner) : ScriptEvent(ET_COMPANY_IN_TROUBLE), owner((ScriptCompany::CompanyID)owner) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventCompanyInTrouble *Convert(ScriptEvent *instance) { return (ScriptEventCompanyInTrouble *)instance; } /** * Get the CompanyID of the company that is in trouble. * @return The CompanyID of the company in trouble. */ ScriptCompany::CompanyID GetCompanyID() { return this->owner; } private: ScriptCompany::CompanyID owner; ///< The company that is in trouble. }; /** * Event Company Ask Merger, indicating a company can be bought (cheaply) by you. * @api ai */ class ScriptEventCompanyAskMerger : public ScriptEvent { public: /** * @param owner The company that can be bough. * @param value The value/costs of buying the company. */ ScriptEventCompanyAskMerger(Owner owner, int32 value) : ScriptEvent(ET_COMPANY_ASK_MERGER), owner((ScriptCompany::CompanyID)owner), value(value) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventCompanyAskMerger *Convert(ScriptEvent *instance) { return (ScriptEventCompanyAskMerger *)instance; } /** * Get the CompanyID of the company that can be bought. * @return The CompanyID of the company that can be bought. * @note If the company is bought this will become invalid. */ ScriptCompany::CompanyID GetCompanyID() { return this->owner; } /** * Get the value of the new company. * @return The value of the new company. */ int32 GetValue() { return this->value; } /** * Take over the company for this merger. * @return true if the merger was a success. */ bool AcceptMerger(); private: ScriptCompany::CompanyID owner; ///< The company that is in trouble. int32 value; ///< The value of the company, i.e. the amount you would pay. }; /** * Event Company Merger, indicating a company has been bought by another * company. * @api ai game */ class ScriptEventCompanyMerger : public ScriptEvent { public: /** * @param old_owner The company bought off. * @param new_owner The company that bought owner. */ ScriptEventCompanyMerger(Owner old_owner, Owner new_owner) : ScriptEvent(ET_COMPANY_MERGER), old_owner((ScriptCompany::CompanyID)old_owner), new_owner((ScriptCompany::CompanyID)new_owner) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventCompanyMerger *Convert(ScriptEvent *instance) { return (ScriptEventCompanyMerger *)instance; } /** * Get the CompanyID of the company that has been bought. * @return The CompanyID of the company that has been bought. * @note: The value below is not valid anymore as CompanyID, and * ScriptCompany::ResolveCompanyID will return COMPANY_COMPANY. It's * only useful if you're keeping track of company's yourself. */ ScriptCompany::CompanyID GetOldCompanyID() { return this->old_owner; } /** * Get the CompanyID of the new owner. * @return The CompanyID of the new owner. */ ScriptCompany::CompanyID GetNewCompanyID() { return this->new_owner; } private: ScriptCompany::CompanyID old_owner; ///< The company that ended to exist. ScriptCompany::CompanyID new_owner; ///< The company that's the end result of the merger. }; /** * Event Company Bankrupt, indicating a company has gone bankrupt. * @api ai game */ class ScriptEventCompanyBankrupt : public ScriptEvent { public: /** * @param owner The company that has gone bankrupt. */ ScriptEventCompanyBankrupt(Owner owner) : ScriptEvent(ET_COMPANY_BANKRUPT), owner((ScriptCompany::CompanyID)owner) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventCompanyBankrupt *Convert(ScriptEvent *instance) { return (ScriptEventCompanyBankrupt *)instance; } /** * Get the CompanyID of the company that has gone bankrupt. * @return The CompanyID of the company that has gone bankrupt. */ ScriptCompany::CompanyID GetCompanyID() { return this->owner; } private: ScriptCompany::CompanyID owner; ///< The company that has gone bankrupt. }; /** * Event Vehicle Lost, indicating a vehicle can't find its way to its destination. * @api ai */ class ScriptEventVehicleLost : public ScriptEvent { public: /** * @param vehicle_id The vehicle that is lost. */ ScriptEventVehicleLost(VehicleID vehicle_id) : ScriptEvent(ET_VEHICLE_LOST), vehicle_id(vehicle_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventVehicleLost *Convert(ScriptEvent *instance) { return (ScriptEventVehicleLost *)instance; } /** * Get the VehicleID of the vehicle that is lost. * @return The VehicleID of the vehicle that is lost. */ VehicleID GetVehicleID() { return this->vehicle_id; } private: VehicleID vehicle_id; ///< The vehicle that is lost. }; /** * Event VehicleWaitingInDepot, indicating a vehicle has arrived a depot and is now waiting there. * @api ai */ class ScriptEventVehicleWaitingInDepot : public ScriptEvent { public: /** * @param vehicle_id The vehicle that is waiting in a depot. */ ScriptEventVehicleWaitingInDepot(VehicleID vehicle_id) : ScriptEvent(ET_VEHICLE_WAITING_IN_DEPOT), vehicle_id(vehicle_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventVehicleWaitingInDepot *Convert(ScriptEvent *instance) { return (ScriptEventVehicleWaitingInDepot *)instance; } /** * Get the VehicleID of the vehicle that is waiting in a depot. * @return The VehicleID of the vehicle that is waiting in a depot. */ VehicleID GetVehicleID() { return this->vehicle_id; } private: VehicleID vehicle_id; ///< The vehicle that is waiting in the depot. }; /** * Event Vehicle Unprofitable, indicating a vehicle lost money last year. * @api ai */ class ScriptEventVehicleUnprofitable : public ScriptEvent { public: /** * @param vehicle_id The vehicle that was unprofitable. */ ScriptEventVehicleUnprofitable(VehicleID vehicle_id) : ScriptEvent(ET_VEHICLE_UNPROFITABLE), vehicle_id(vehicle_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventVehicleUnprofitable *Convert(ScriptEvent *instance) { return (ScriptEventVehicleUnprofitable *)instance; } /** * Get the VehicleID of the vehicle that lost money. * @return The VehicleID of the vehicle that lost money. */ VehicleID GetVehicleID() { return this->vehicle_id; } private: VehicleID vehicle_id; ///< The vehicle that is unprofitable. }; /** * Event Industry Open, indicating a new industry has been created. * @api ai game */ class ScriptEventIndustryOpen : public ScriptEvent { public: /** * @param industry_id The new industry. */ ScriptEventIndustryOpen(IndustryID industry_id) : ScriptEvent(ET_INDUSTRY_OPEN), industry_id(industry_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventIndustryOpen *Convert(ScriptEvent *instance) { return (ScriptEventIndustryOpen *)instance; } /** * Get the IndustryID of the new industry. * @return The IndustryID of the industry. */ IndustryID GetIndustryID() { return this->industry_id; } private: IndustryID industry_id; ///< The industry that opened. }; /** * Event Industry Close, indicating an industry is going to be closed. * @api ai game */ class ScriptEventIndustryClose : public ScriptEvent { public: /** * @param industry_id The new industry. */ ScriptEventIndustryClose(IndustryID industry_id) : ScriptEvent(ET_INDUSTRY_CLOSE), industry_id(industry_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventIndustryClose *Convert(ScriptEvent *instance) { return (ScriptEventIndustryClose *)instance; } /** * Get the IndustryID of the closing industry. * @return The IndustryID of the industry. */ IndustryID GetIndustryID() { return this->industry_id; } private: IndustryID industry_id; ///< The industry that closed. }; /** * Event Engine Available, indicating a new engine is available. * @api ai */ class ScriptEventEngineAvailable : public ScriptEvent { public: /** * @param engine The engine that is available. */ ScriptEventEngineAvailable(EngineID engine) : ScriptEvent(ET_ENGINE_AVAILABLE), engine(engine) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventEngineAvailable *Convert(ScriptEvent *instance) { return (ScriptEventEngineAvailable *)instance; } /** * Get the EngineID of the new engine. * @return The EngineID of the new engine. */ EngineID GetEngineID() { return this->engine; } private: EngineID engine; ///< The engine that became available. }; /** * Event Station First Vehicle, indicating a station has been visited by a vehicle for the first time. * @api ai game */ class ScriptEventStationFirstVehicle : public ScriptEvent { public: /** * @param station The station visited for the first time. * @param vehicle The vehicle visiting the station. */ ScriptEventStationFirstVehicle(StationID station, VehicleID vehicle) : ScriptEvent(ET_STATION_FIRST_VEHICLE), station(station), vehicle(vehicle) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventStationFirstVehicle *Convert(ScriptEvent *instance) { return (ScriptEventStationFirstVehicle *)instance; } /** * Get the StationID of the visited station. * @return The StationID of the visited station. */ StationID GetStationID() { return this->station; } /** * Get the VehicleID of the first vehicle. * @return The VehicleID of the first vehicle. */ VehicleID GetVehicleID() { return this->vehicle; } private: StationID station; ///< The station the vehicle arrived at. VehicleID vehicle; ///< The vehicle that arrived at the station. }; /** * Event Disaster Zeppeliner Crashed, indicating a zeppeliner has crashed on an airport and is blocking the runway. * @api ai */ class ScriptEventDisasterZeppelinerCrashed : public ScriptEvent { public: /** * @param station The station containing the affected airport */ ScriptEventDisasterZeppelinerCrashed(StationID station) : ScriptEvent(ET_DISASTER_ZEPPELINER_CRASHED), station(station) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventDisasterZeppelinerCrashed *Convert(ScriptEvent *instance) { return (ScriptEventDisasterZeppelinerCrashed *)instance; } /** * Get the StationID of the station containing the affected airport. * @return The StationID of the station containing the affected airport. */ StationID GetStationID() { return this->station; } private: StationID station; ///< The station the zeppeliner crashed. }; /** * Event Disaster Zeppeliner Cleared, indicating a previously crashed zeppeliner has been removed, and the airport is operating again. * @api ai */ class ScriptEventDisasterZeppelinerCleared : public ScriptEvent { public: /** * @param station The station containing the affected airport */ ScriptEventDisasterZeppelinerCleared(StationID station) : ScriptEvent(ET_DISASTER_ZEPPELINER_CLEARED), station(station) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventDisasterZeppelinerCleared *Convert(ScriptEvent *instance) { return (ScriptEventDisasterZeppelinerCleared *)instance; } /** * Get the StationID of the station containing the affected airport. * @return The StationID of the station containing the affected airport. */ StationID GetStationID() { return this->station; } private: StationID station; ///< The station the zeppeliner crashed. }; /** * Event Town Founded, indicating a new town has been created. * @api ai game */ class ScriptEventTownFounded : public ScriptEvent { public: /** * @param town The town that was created. */ ScriptEventTownFounded(TownID town) : ScriptEvent(ET_TOWN_FOUNDED), town(town) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventTownFounded *Convert(ScriptEvent *instance) { return (ScriptEventTownFounded *)instance; } /** * Get the TownID of the town. * @return The TownID of the town that was created. */ TownID GetTownID() { return this->town; } private: TownID town; ///< The town that got founded. }; /** * Event AircraftDestTooFar, indicating the next destination of an aircraft is too far away. * This event can be trigger when the current oder of an aircraft changes, usually either when * loading is done or when switch manually. * @api ai */ class ScriptEventAircraftDestTooFar : public ScriptEvent { public: /** * @param vehicle_id The aircraft whose destination is too far away. */ ScriptEventAircraftDestTooFar(VehicleID vehicle_id) : ScriptEvent(ET_AIRCRAFT_DEST_TOO_FAR), vehicle_id(vehicle_id) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventAircraftDestTooFar *Convert(ScriptEvent *instance) { return (ScriptEventAircraftDestTooFar *)instance; } /** * Get the VehicleID of the aircraft whose destination is too far away. * @return The VehicleID of the aircraft whose destination is too far away. */ VehicleID GetVehicleID() { return this->vehicle_id; } private: VehicleID vehicle_id; ///< The vehicle aircraft whose destination is too far away. }; /** * Event Admin Port, indicating the admin port is sending you information. * @api game */ class ScriptEventAdminPort : public ScriptEvent { public: /** * @param json The JSON string which got sent. */ ScriptEventAdminPort(const char *json); ~ScriptEventAdminPort(); /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventAdminPort *Convert(ScriptEvent *instance) { return (ScriptEventAdminPort *)instance; } /** * Get the information that was sent to you back as Squirrel object. */ SQInteger GetObject(HSQUIRRELVM vm); private: char *json; ///< The JSON string. /** * Read a table from a JSON string. * @param vm The VM used. * @param p The (part of the) JSON string reading. */ char *ReadTable(HSQUIRRELVM vm, char *p); /** * Read a value from a JSON string. * @param vm The VM used. * @param p The (part of the) JSON string reading. */ char *ReadValue(HSQUIRRELVM vm, char *p); /** * Read a string from a JSON string. * @param vm The VM used. * @param p The (part of the) JSON string reading. */ char *ReadString(HSQUIRRELVM vm, char *p); }; /** * Event Window Widget Click, when a user clicks on a highlighted widget. * @api game */ class ScriptEventWindowWidgetClick : public ScriptEvent { public: /** * @param window The windowclass that was clicked. * @param number The windownumber that was clicked. * @param widget The widget in the window that was clicked. */ ScriptEventWindowWidgetClick(ScriptWindow::WindowClass window, uint32 number, uint8 widget) : ScriptEvent(ET_WINDOW_WIDGET_CLICK), window(window), number(number), widget(widget) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventWindowWidgetClick *Convert(ScriptEvent *instance) { return (ScriptEventWindowWidgetClick *)instance; } /** * Get the class of the window that was clicked. */ ScriptWindow::WindowClass GetWindowClass() { return this->window; } /** * Get the number of the window that was clicked. */ uint32 GetWindowNumber() { return this->number; } /** * Get the number of the widget that was clicked. */ uint8 GetWidgetNumber() { return this->widget; } private: ScriptWindow::WindowClass window; ///< Window of the click. uint32 number; ///< Number of the click. uint8 widget; ///< Widget of the click. }; /** * Event Goal Question Answer, where you receive the answer given to your questions. * @note It is possible that you get more than 1 answer from the same company * (due to lag). Please keep this in mind while handling this event. * @api game */ class ScriptEventGoalQuestionAnswer : public ScriptEvent { public: /** * @param uniqueid The uniqueID you have given this question. * @param company The company that is replying. * @param button The button the company pressed. */ ScriptEventGoalQuestionAnswer(uint16 uniqueid, ScriptCompany::CompanyID company, ScriptGoal::QuestionButton button) : ScriptEvent(ET_GOAL_QUESTION_ANSWER), uniqueid(uniqueid), company(company), button(button) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventGoalQuestionAnswer *Convert(ScriptEvent *instance) { return (ScriptEventGoalQuestionAnswer *)instance; } /** * Get the unique id of the question. */ uint16 GetUniqueID() { return this->uniqueid; } /** * Get the company that pressed a button. */ ScriptCompany::CompanyID GetCompany() { return this->company; } /** * Get the button that got pressed. */ ScriptGoal::QuestionButton GetButton() { return this->button; } private: uint16 uniqueid; ///< The uniqueid of the question. ScriptCompany::CompanyID company; ///< The company given the answer. ScriptGoal::QuestionButton button; ///< The button he pressed. }; /** * Base class for events involving a town and a company. * @api ai game */ class ScriptEventCompanyTown : public ScriptEvent { public: /** * @param event The eventtype. * @param company The company. * @param town The town. */ ScriptEventCompanyTown(ScriptEventType event, ScriptCompany::CompanyID company, TownID town) : ScriptEvent(event), company(company), town(town) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventCompanyTown *Convert(ScriptEvent *instance) { return (ScriptEventCompanyTown *)instance; } /** * Get the CompanyID of the company. * @return The CompanyID of the company involved into the event. */ ScriptCompany::CompanyID GetCompanyID() { return this->company; } /** * Get the TownID of the town. * @return The TownID of the town involved into the event. */ TownID GetTownID() { return this->town; } private: ScriptCompany::CompanyID company; ///< The company involved into the event. TownID town; ///< The town involved into the event. }; /** * Event Exclusive Transport Rights, indicating that company bought * exclusive transport rights in a town. * @api ai game */ class ScriptEventExclusiveTransportRights : public ScriptEventCompanyTown { public: /** * @param company The company. * @param town The town. */ ScriptEventExclusiveTransportRights(ScriptCompany::CompanyID company, TownID town) : ScriptEventCompanyTown(ET_EXCLUSIVE_TRANSPORT_RIGHTS, company, town) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventExclusiveTransportRights *Convert(ScriptEventCompanyTown *instance) { return (ScriptEventExclusiveTransportRights *)instance; } }; /** * Event Road Reconstruction, indicating that company triggered * road reconstructions in a town. * @api ai game */ class ScriptEventRoadReconstruction : public ScriptEventCompanyTown { public: /** * @param company The company. * @param town The town. */ ScriptEventRoadReconstruction(ScriptCompany::CompanyID company, TownID town) : ScriptEventCompanyTown(ET_ROAD_RECONSTRUCTION, company, town) {} /** * Convert an ScriptEvent to the real instance. * @param instance The instance to convert. * @return The converted instance. */ static ScriptEventRoadReconstruction *Convert(ScriptEventCompanyTown *instance) { return (ScriptEventRoadReconstruction *)instance; } }; #endif /* SCRIPT_EVENT_TYPES_HPP */ openttd-1.5.3/src/script/api/script_goal.cpp0000644000000000000000000001312712627373433017567 0ustar rootroot/* $Id: script_goal.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_goal.cpp Implementation of ScriptGoal. */ #include "../../stdafx.h" #include "script_goal.hpp" #include "script_error.hpp" #include "script_industry.hpp" #include "script_map.hpp" #include "script_town.hpp" #include "script_story_page.hpp" #include "../script_instance.hpp" #include "../../goal_base.h" #include "../../string_func.h" #include "../../safeguards.h" /* static */ bool ScriptGoal::IsValidGoal(GoalID goal_id) { return ::Goal::IsValidID(goal_id); } /* static */ ScriptGoal::GoalID ScriptGoal::New(ScriptCompany::CompanyID company, Text *goal, GoalType type, uint32 destination) { CCountedPtr counter(goal); EnforcePrecondition(GOAL_INVALID, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(GOAL_INVALID, goal != NULL); const char *text = goal->GetEncodedText(); EnforcePreconditionEncodedText(GOAL_INVALID, text); EnforcePrecondition(GOAL_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); uint8 c = company; if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; StoryPage *story_page = NULL; if (type == GT_STORY_PAGE && ScriptStoryPage::IsValidStoryPage((ScriptStoryPage::StoryPageID)destination)) story_page = ::StoryPage::Get((ScriptStoryPage::StoryPageID)destination); EnforcePrecondition(GOAL_INVALID, (type == GT_NONE && destination == 0) || (type == GT_TILE && ScriptMap::IsValidTile(destination)) || (type == GT_INDUSTRY && ScriptIndustry::IsValidIndustry(destination)) || (type == GT_TOWN && ScriptTown::IsValidTown(destination)) || (type == GT_COMPANY && ScriptCompany::ResolveCompanyID((ScriptCompany::CompanyID)destination) != ScriptCompany::COMPANY_INVALID) || (type == GT_STORY_PAGE && story_page != NULL && (c == INVALID_COMPANY ? story_page->company == INVALID_COMPANY : story_page->company == INVALID_COMPANY || story_page->company == c))); if (!ScriptObject::DoCommand(0, type | (c << 8), destination, CMD_CREATE_GOAL, text, &ScriptInstance::DoCommandReturnGoalID)) return GOAL_INVALID; /* In case of test-mode, we return GoalID 0 */ return (ScriptGoal::GoalID)0; } /* static */ bool ScriptGoal::Remove(GoalID goal_id) { EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, IsValidGoal(goal_id)); return ScriptObject::DoCommand(0, goal_id, 0, CMD_REMOVE_GOAL); } /* static */ bool ScriptGoal::SetText(GoalID goal_id, Text *goal) { CCountedPtr counter(goal); EnforcePrecondition(false, IsValidGoal(goal_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, goal != NULL); EnforcePrecondition(false, !StrEmpty(goal->GetEncodedText())); return ScriptObject::DoCommand(0, goal_id, 0, CMD_SET_GOAL_TEXT, goal->GetEncodedText()); } /* static */ bool ScriptGoal::SetProgress(GoalID goal_id, Text *progress) { CCountedPtr counter(progress); EnforcePrecondition(false, IsValidGoal(goal_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); /* Ensure null as used for emtpy string. */ if (progress != NULL && StrEmpty(progress->GetEncodedText())) { progress = NULL; } return ScriptObject::DoCommand(0, goal_id, 0, CMD_SET_GOAL_PROGRESS, progress != NULL ? progress->GetEncodedText() : NULL); } /* static */ bool ScriptGoal::SetCompleted(GoalID goal_id, bool completed) { EnforcePrecondition(false, IsValidGoal(goal_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); return ScriptObject::DoCommand(0, goal_id, completed ? 1 : 0, CMD_SET_GOAL_COMPLETED); } /* static */ bool ScriptGoal::IsCompleted(GoalID goal_id) { EnforcePrecondition(false, IsValidGoal(goal_id)); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); Goal *g = Goal::Get(goal_id); return g != NULL && g->completed; } /* static */ bool ScriptGoal::Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons) { CCountedPtr counter(question); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, question != NULL); const char *text = question->GetEncodedText(); EnforcePreconditionEncodedText(false, text); EnforcePrecondition(false, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID); EnforcePrecondition(false, CountBits(buttons) >= 1 && CountBits(buttons) <= 3); EnforcePrecondition(false, buttons < (1 << ::GOAL_QUESTION_BUTTON_COUNT)); EnforcePrecondition(false, (int)type < ::GOAL_QUESTION_TYPE_COUNT); uint8 c = company; if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY; return ScriptObject::DoCommand(0, uniqueid | (c << 16) | (type << 24), buttons, CMD_GOAL_QUESTION, text); } /* static */ bool ScriptGoal::CloseQuestion(uint16 uniqueid) { EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); return ScriptObject::DoCommand(0, uniqueid, 0, CMD_GOAL_QUESTION_ANSWER); } openttd-1.5.3/src/script/api/script_tilelist.cpp0000644000000000000000000001210712627373434020474 0ustar rootroot/* $Id: script_tilelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_tilelist.cpp Implementation of ScriptTileList and friends. */ #include "../../stdafx.h" #include "script_tilelist.hpp" #include "script_industry.hpp" #include "../../industry.h" #include "../../station_base.h" #include "../../safeguards.h" void ScriptTileList::AddRectangle(TileIndex t1, TileIndex t2) { if (!::IsValidTile(t1)) return; if (!::IsValidTile(t2)) return; TileArea ta(t1, t2); TILE_AREA_LOOP(t, ta) this->AddItem(t); } void ScriptTileList::AddTile(TileIndex tile) { if (!::IsValidTile(tile)) return; this->AddItem(tile); } void ScriptTileList::RemoveRectangle(TileIndex t1, TileIndex t2) { if (!::IsValidTile(t1)) return; if (!::IsValidTile(t2)) return; TileArea ta(t1, t2); TILE_AREA_LOOP(t, ta) this->RemoveItem(t); } void ScriptTileList::RemoveTile(TileIndex tile) { if (!::IsValidTile(tile)) return; this->RemoveItem(tile); } ScriptTileList_IndustryAccepting::ScriptTileList_IndustryAccepting(IndustryID industry_id, int radius) { if (!ScriptIndustry::IsValidIndustry(industry_id) || radius <= 0) return; const Industry *i = ::Industry::Get(industry_id); /* Check if this industry accepts anything */ { bool cargo_accepts = false; for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { if (i->accepts_cargo[j] != CT_INVALID) cargo_accepts = true; } if (!cargo_accepts) return; } if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED; TileArea ta(i->location.tile - ::TileDiffXY(radius, radius), i->location.w + radius * 2, i->location.h + radius * 2); TILE_AREA_LOOP(cur_tile, ta) { if (!::IsValidTile(cur_tile)) continue; /* Exclude all tiles that belong to this industry */ if (::IsTileType(cur_tile, MP_INDUSTRY) && ::GetIndustryIndex(cur_tile) == industry_id) continue; /* Only add the tile if it accepts the cargo (sometimes just 1 tile of an * industry triggers the acceptance). */ CargoArray acceptance = ::GetAcceptanceAroundTiles(cur_tile, 1, 1, radius); { bool cargo_accepts = false; for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { if (i->accepts_cargo[j] != CT_INVALID && acceptance[i->accepts_cargo[j]] != 0) cargo_accepts = true; } if (!cargo_accepts) continue; } this->AddTile(cur_tile); } } ScriptTileList_IndustryProducing::ScriptTileList_IndustryProducing(IndustryID industry_id, int radius) { if (!ScriptIndustry::IsValidIndustry(industry_id) || radius <= 0) return; const Industry *i = ::Industry::Get(industry_id); /* Check if this industry produces anything */ bool cargo_produces = false; for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] != CT_INVALID) cargo_produces = true; } if (!cargo_produces) return; if (!_settings_game.station.modified_catchment) radius = CA_UNMODIFIED; TileArea ta(i->location.tile - ::TileDiffXY(radius, radius), i->location.w + radius * 2, i->location.h + radius * 2); TILE_AREA_LOOP(cur_tile, ta) { if (!::IsValidTile(cur_tile)) continue; /* Exclude all tiles that belong to this industry */ if (::IsTileType(cur_tile, MP_INDUSTRY) && ::GetIndustryIndex(cur_tile) == industry_id) continue; this->AddTile(cur_tile); } } ScriptTileList_StationType::ScriptTileList_StationType(StationID station_id, ScriptStation::StationType station_type) { if (!ScriptStation::IsValidStation(station_id)) return; const StationRect *rect = &::Station::Get(station_id)->rect; uint station_type_value = 0; /* Convert ScriptStation::StationType to ::StationType, but do it in a * bitmask, so we can scan for multiple entries at the same time. */ if ((station_type & ScriptStation::STATION_TRAIN) != 0) station_type_value |= (1 << ::STATION_RAIL); if ((station_type & ScriptStation::STATION_TRUCK_STOP) != 0) station_type_value |= (1 << ::STATION_TRUCK); if ((station_type & ScriptStation::STATION_BUS_STOP) != 0) station_type_value |= (1 << ::STATION_BUS); if ((station_type & ScriptStation::STATION_AIRPORT) != 0) station_type_value |= (1 << ::STATION_AIRPORT) | (1 << ::STATION_OILRIG); if ((station_type & ScriptStation::STATION_DOCK) != 0) station_type_value |= (1 << ::STATION_DOCK) | (1 << ::STATION_OILRIG); TileArea ta(::TileXY(rect->left, rect->top), rect->right - rect->left + 1, rect->bottom - rect->top + 1); TILE_AREA_LOOP(cur_tile, ta) { if (!::IsTileType(cur_tile, MP_STATION)) continue; if (::GetStationIndex(cur_tile) != station_id) continue; if (!HasBit(station_type_value, ::GetStationType(cur_tile))) continue; this->AddTile(cur_tile); } } openttd-1.5.3/src/script/api/script_group.hpp0000644000000000000000000001606212627373434020010 0ustar rootroot/* $Id: script_group.hpp 24776 2012-12-01 13:12:39Z alberth $ */ /* * 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 script_group.hpp Everything to put vehicles into groups. */ #ifndef SCRIPT_GROUP_HPP #define SCRIPT_GROUP_HPP #include "script_vehicle.hpp" #include "../../group_type.h" /** * Class that handles all group related functions. * @api ai */ class ScriptGroup : public ScriptObject { public: /** * The group IDs of some special groups. */ enum GroupID { /* Note: these values represent part of the in-game static values */ GROUP_ALL = ::ALL_GROUP, ///< All vehicles are in this group. GROUP_DEFAULT = ::DEFAULT_GROUP, ///< Vehicles not put in any other group are in this one. GROUP_INVALID = ::INVALID_GROUP, ///< An invalid group id. }; /** * Checks whether the given group is valid. * @param group_id The group to check. * @pre group_id != GROUP_DEFAULT && group_id != GROUP_ALL. * @return True if and only if the group is valid. */ static bool IsValidGroup(GroupID group_id); /** * Create a new group. * @param vehicle_type The type of vehicle to create a group for. * @return The GroupID of the new group, or an invalid GroupID when * it failed. Check the return value using IsValidGroup(). In test-mode * 0 is returned if it was successful; any other value indicates failure. */ static GroupID CreateGroup(ScriptVehicle::VehicleType vehicle_type); /** * Delete the given group. When the deletion succeeds all vehicles in the * given group will move to the GROUP_DEFAULT. * @param group_id The group to delete. * @pre IsValidGroup(group_id). * @return True if and only if the group was successfully deleted. */ static bool DeleteGroup(GroupID group_id); /** * Get the vehicle type of a group. * @param group_id The group to get the type from. * @pre IsValidGroup(group_id). * @return The vehicletype of the given group. */ static ScriptVehicle::VehicleType GetVehicleType(GroupID group_id); /** * Set the name of a group. * @param group_id The group to set the name for. * @param name The name for the group (can be either a raw string, or a ScriptText object). * @pre IsValidGroup(group_id). * @pre name != NULL && len(name) != 0 * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if and only if the name was changed. */ static bool SetName(GroupID group_id, Text *name); /** * Get the name of a group. * @param group_id The group to get the name of. * @pre IsValidGroup(group_id). * @return The name the group has. */ static char *GetName(GroupID group_id); /** * Enable or disable autoreplace protected. If the protection is * enabled, global autoreplace won't affect vehicles in this group. * @param group_id The group to change the protection for. * @param enable True if protection should be enabled. * @pre IsValidGroup(group_id). * @return True if and only if the protection was successfully changed. */ static bool EnableAutoReplaceProtection(GroupID group_id, bool enable); /** * Get the autoreplace protection status. * @param group_id The group to get the protection status for. * @pre IsValidGroup(group_id). * @return The autoreplace protection status for the given group. */ static bool GetAutoReplaceProtection(GroupID group_id); /** * Get the number of engines in a given group. * @param group_id The group to get the number of engines in. * @param engine_id The engine id to count. * @pre IsValidGroup(group_id) || group_id == GROUP_ALL || group_id == GROUP_DEFAULT. * @return The number of engines with id engine_id in the group with id group_id. */ static int32 GetNumEngines(GroupID group_id, EngineID engine_id); /** * Move a vehicle to a group. * @param group_id The group to move the vehicle to. * @param vehicle_id The vehicle to move to the group. * @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @return True if and only if the vehicle was successfully moved to the group. * @note A vehicle can be in only one group at the same time. To remove it from * a group, move it to another or to GROUP_DEFAULT. Moving the vehicle to the * given group means removing it from another group. */ static bool MoveVehicle(GroupID group_id, VehicleID vehicle_id); /** * Enable or disable the removal of wagons when a (part of a) vehicle is * (auto)replaced with a longer variant (longer wagons or longer engines) * If enabled, wagons are removed from the end of the vehicle until it * fits in the same number of tiles as it did before. * @param keep_length If true, wagons will be removed if the new engine is longer. * @return True if and only if the value was successfully changed. */ static bool EnableWagonRemoval(bool keep_length); /** * Get the current status of wagon removal. * @return Whether or not wagon removal is enabled. */ static bool HasWagonRemoval(); /** * Start replacing all vehicles with a specified engine with another engine. * @param group_id The group to replace vehicles from. Use ALL_GROUP to replace * vehicles from all groups that haven't set autoreplace protection. * @param engine_id_old The engine id to start replacing. * @param engine_id_new The engine id to replace with. * @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL. * @pre ScriptEngine.IsBuildable(engine_id_new). * @return True if and if the replacing was successfully started. * @note To stop autoreplacing engine_id_old, call StopAutoReplace(group_id, engine_id_old). */ static bool SetAutoReplace(GroupID group_id, EngineID engine_id_old, EngineID engine_id_new); /** * Get the EngineID the given EngineID is replaced with. * @param group_id The group to get the replacement from. * @param engine_id The engine that is being replaced. * @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL. * @return The EngineID that is replacing engine_id or an invalid EngineID * in case engine_id is not begin replaced. */ static EngineID GetEngineReplacement(GroupID group_id, EngineID engine_id); /** * Stop replacing a certain engine in the specified group. * @param group_id The group to stop replacing the engine in. * @param engine_id The engine id to stop replacing with another engine. * @pre IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL. * @return True if and if the replacing was successfully stopped. */ static bool StopAutoReplace(GroupID group_id, EngineID engine_id); }; #endif /* SCRIPT_GROUP_HPP */ openttd-1.5.3/src/script/api/script_types.hpp0000644000000000000000000002016612627373434020020 0ustar rootroot/* $Id: script_types.hpp 25342 2013-06-09 12:19:09Z zuu $ */ /* * 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 script_types.hpp Defines all the types of the game, like IDs of various objects. * * IDs are used to identify certain objects. They are only unique within the object type, so for example a vehicle may have VehicleID 2009, * while a station has StationID 2009 at the same time. Also IDs are assigned arbitrary, you cannot assume them to be consecutive. * Also note that some IDs are static and never change, while others are allocated dynamically and might be * reused for other objects once they are released. So be careful, which IDs you store for which purpose and whether they stay valid all the time. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
type object acquired released reused
#BridgeID bridge type introduction \ref newgrf_changes "(1)" never \ref newgrf_changes "(1)" no \ref newgrf_changes "(1)"
#CargoID cargo type game start \ref newgrf_changes "(1)" never \ref newgrf_changes "(1)" no \ref newgrf_changes "(1)"
#EngineID engine type introduction, preview \ref dynamic_engines "(2)" engines retires \ref dynamic_engines "(2)" no \ref dynamic_engines "(2)"
#GoalID goal creation deletion yes
#GroupID vehicle group creation deletion yes
#IndustryID industry construction closure yes
#IndustryType industry type game start \ref newgrf_changes "(1)" never \ref newgrf_changes "(1)" no
#SignID sign construction deletion yes
#StationID station construction expiration of 'grey' station sign after deletion yes
#SubsidyID subsidy offer announcement (offer) expiration yes
#TileIndex tile on map game start never no
#TownID town game start never no
#VehicleID vehicle construction, autorenew, autoreplace destruction, autorenew, autoreplace yes
* * @remarks * \li \anchor newgrf_changes (1) in-game changes of newgrfs may reassign/invalidate IDs (will also cause other trouble though). * \li \anchor dynamic_engines (2) engine IDs are reassigned/invalidated on changing 'allow multiple newgrf engine sets' (only allowed as long as no vehicles are built). */ #ifndef SCRIPT_TYPES_HPP #define SCRIPT_TYPES_HPP #include "../../core/overflowsafe_type.hpp" #include "../../company_type.h" #include /* Define all types here, so we don't have to include the whole _type.h maze */ typedef uint BridgeType; ///< Internal name, not of any use for you. typedef byte CargoID; ///< The ID of a cargo. class CommandCost; ///< The cost of a command. typedef uint16 EngineID; ///< The ID of an engine. typedef uint16 GoalID; ///< The ID of a goal. typedef uint16 GroupID; ///< The ID of a group. typedef uint16 IndustryID; ///< The ID of an industry. typedef uint8 IndustryType; ///< The ID of an industry-type. typedef OverflowSafeInt64 Money; ///< Money, stored in a 32bit/64bit safe way. For scripts money is always in pounds. typedef uint16 SignID; ///< The ID of a sign. typedef uint16 StationID; ///< The ID of a station. typedef uint16 StringID; ///< The ID of a string. typedef uint16 SubsidyID; ///< The ID of a subsidy. typedef uint16 StoryPageID; ///< The ID of a story page. typedef uint16 StoryPageElementID; ///< The ID of a story page element. typedef uint32 TileIndex; ///< The ID of a tile (just named differently). typedef uint16 TownID; ///< The ID of a town. typedef uint32 VehicleID; ///< The ID of a vehicle. /* Types we defined ourself, as the OpenTTD core doesn't have them (yet) */ typedef uint ScriptErrorType;///< The types of errors inside the script framework. typedef BridgeType BridgeID; ///< The ID of a bridge. #endif /* SCRIPT_TYPES_HPP */ openttd-1.5.3/src/script/api/script_text.hpp0000644000000000000000000001140612627373434017635 0ustar rootroot/* $Id: script_text.hpp 27102 2015-01-01 20:50:43Z rubidium $ */ /* * 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 script_text.hpp Everything to handle text which can be translated. */ #ifndef SCRIPT_TEXT_HPP #define SCRIPT_TEXT_HPP #include "script_object.hpp" #include "../../core/alloc_type.hpp" /** * Internal parent object of all Text-like objects. * @api -all */ class Text : public ScriptObject { public: /** * Convert a ScriptText to a normal string. * @return A string (in a static buffer), or NULL. * @api -all */ virtual const char *GetEncodedText() = 0; /** * Convert a #ScriptText into a decoded normal string. * @return A string (in a static buffer), or NULL. * @api -all */ const char *GetDecodedText(); }; /** * Internally used class to create a raw text in a Text object. * @api -all */ class RawText : public Text { public: RawText(const char *text); ~RawText(); /* virtual */ const char *GetEncodedText() { return this->text; } private: const char *text; }; /** * Class that handles all text related functions. You can define a language * file in lang/english.txt, in the same format as OpenTTD does, including * tags like {BLACK}, {STRING1} etc. The name given to this string is made * available to you in ScriptText, for example: ScriptText.STR_NEWS, if your * english.txt contains: STR_NEWS :{BLACK}Welcome {COMPANY}! * * In translation files like lang/dutch.txt you can then translate such * strings, like: STR_NEWS :{BLACK}Hallo {COMPANY}! * When the user has the dutch language selected, it will automatically use * the translated string when available. The fallback language is always * the english language. * * If you use parameters in your strings, you will have to define those * parameters, for example like this: * \code local text = ScriptText(ScriptText.STR_NEWS); * text.AddParam(1); \endcode * This will set the {COMPANY} to the name of Company 1. Alternatively you * can directly give those arguments to the ScriptText constructor, like this: * \code local text = ScriptText(ScriptText.STR_NEWS, 1); \endcode * * @api game */ class ScriptText : public Text , public ZeroedMemoryAllocator { public: static const int SCRIPT_TEXT_MAX_PARAMETERS = 20; ///< The maximum amount of parameters you can give to one object. #ifndef DOXYGEN_API /** * The constructor wrapper from Squirrel. */ ScriptText(HSQUIRRELVM vm); #else /** * Generate a text from string. You can set parameters to the instance which * can be required for the string. * @param string The string of the text. * @param ... Optional arguments for this string. */ ScriptText(StringID string, ...); #endif ~ScriptText(); #ifndef DOXYGEN_API /** * Used for .param_N and [] set from Squirrel. */ SQInteger _set(HSQUIRRELVM vm); /** * Set the parameter. */ SQInteger SetParam(HSQUIRRELVM vm); /** * Add an parameter */ SQInteger AddParam(HSQUIRRELVM vm); #else /** * Set the parameter to a value. * @param parameter Which parameter to set. * @param value The value of the parameter. Has to be string, integer or an instance of the class ScriptText. */ void SetParam(int parameter, Object value); /** * Add a value as parameter (appending it). * @param value The value of the parameter. Has to be string, integer or an instance of the class ScriptText. * @return The same object as on which this is called, so you can chain. */ ScriptText *AddParam(Object value); #endif /* DOXYGEN_API */ /* virtual */ const char *GetEncodedText(); private: StringID string; char *params[SCRIPT_TEXT_MAX_PARAMETERS]; int64 parami[SCRIPT_TEXT_MAX_PARAMETERS]; ScriptText *paramt[SCRIPT_TEXT_MAX_PARAMETERS]; int paramc; /** * Internal function for recursive calling this function over multiple * instances, while writing in the same buffer. * @param p The current position in the buffer. * @param lastofp The last position valid in the buffer. * @param param_count The number of parameters that are in the string. * @return The new current position in the buffer. */ char *_GetEncodedText(char *p, char *lastofp, int ¶m_count); /** * Set a parameter, where the value is the first item on the stack. */ SQInteger _SetParam(int k, HSQUIRRELVM vm); }; #endif /* SCRIPT_TEXT_HPP */ openttd-1.5.3/src/script/api/script_viewport.hpp0000644000000000000000000000235712627373434020535 0ustar rootroot/* $Id: script_viewport.hpp 25594 2013-07-13 06:38:54Z rubidium $ */ /* * 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 script_viewport.hpp Everything to manipulate the user's viewport. */ #ifndef SCRIPT_VIEWPORT_HPP #define SCRIPT_VIEWPORT_HPP #include "script_object.hpp" /** * Class that manipulates the user's viewport. * @api game */ class ScriptViewport : public ScriptObject { public: /** * Scroll the viewport to the given tile, where the tile will be in the * center of the screen. * @param tile The tile to put in the center of the screen. * @pre ! ScriptGame::IsMultiplayer(). * @pre ScriptMap::IsValidTile(tile). */ static void ScrollTo(TileIndex tile); }; #endif /* SCRIPT_ADMIN_HPP */ openttd-1.5.3/src/script/api/ai/0000755000000000000000000000000012627373434015143 5ustar rootrootopenttd-1.5.3/src/script/api/ai/ai_signlist.hpp.sq0000644000000000000000000000220512627373434020602 0ustar rootroot/* $Id: ai_signlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_signlist.hpp" #include "../template/template_signlist.hpp.sq" template <> const char *GetClassName() { return "AISignList"; } void SQAISignList_Register(Squirrel *engine) { DefSQClass SQAISignList("AISignList"); SQAISignList.PreRegister(engine, "AIList"); SQAISignList.AddConstructor(engine, "x"); SQAISignList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_base.hpp.sq0000644000000000000000000000315512627373434017665 0ustar rootroot/* $Id: ai_base.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_base.hpp" #include "../template/template_base.hpp.sq" template <> const char *GetClassName() { return "AIBase"; } void SQAIBase_Register(Squirrel *engine) { DefSQClass SQAIBase("AIBase"); SQAIBase.PreRegister(engine); SQAIBase.AddConstructor(engine, "x"); SQAIBase.DefSQStaticMethod(engine, &ScriptBase::Rand, "Rand", 1, "."); SQAIBase.DefSQStaticMethod(engine, &ScriptBase::RandItem, "RandItem", 2, ".i"); SQAIBase.DefSQStaticMethod(engine, &ScriptBase::RandRange, "RandRange", 2, ".i"); SQAIBase.DefSQStaticMethod(engine, &ScriptBase::RandRangeItem, "RandRangeItem", 3, ".ii"); SQAIBase.DefSQStaticMethod(engine, &ScriptBase::Chance, "Chance", 3, ".ii"); SQAIBase.DefSQStaticMethod(engine, &ScriptBase::ChanceItem, "ChanceItem", 4, ".iii"); SQAIBase.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_controller.hpp.sq0000644000000000000000000000375712627373434021146 0ustar rootroot/* $Id: ai_controller.hpp.sq 24542 2012-09-21 20:49:43Z zuu $ */ /* * 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 . */ #include "../script_controller.hpp" template <> const char *GetClassName() { return "AIController"; } void SQAIController_Register(Squirrel *engine) { DefSQClass SQAIController("AIController"); SQAIController.PreRegister(engine); SQAIController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", 1, "."); SQAIController.DefSQStaticMethod(engine, &ScriptController::GetOpsTillSuspend, "GetOpsTillSuspend", 1, "."); SQAIController.DefSQStaticMethod(engine, &ScriptController::SetCommandDelay, "SetCommandDelay", 2, ".i"); SQAIController.DefSQStaticMethod(engine, &ScriptController::Sleep, "Sleep", 2, ".i"); SQAIController.DefSQStaticMethod(engine, &ScriptController::Break, "Break", 2, ".s"); SQAIController.DefSQStaticMethod(engine, &ScriptController::GetSetting, "GetSetting", 2, ".s"); SQAIController.DefSQStaticMethod(engine, &ScriptController::GetVersion, "GetVersion", 1, "."); SQAIController.DefSQStaticMethod(engine, &ScriptController::Print, "Print", 3, ".bs"); SQAIController.PostRegister(engine); /* Register the import statement to the global scope */ SQAIController.DefSQStaticMethod(engine, &ScriptController::Import, "import", 4, ".ssi"); } openttd-1.5.3/src/script/api/ai/ai_infrastructure.hpp.sq0000644000000000000000000000530212627373434022027 0ustar rootroot/* $Id: ai_infrastructure.hpp.sq 23416 2011-12-03 23:40:57Z michi_cc $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_infrastructure.hpp" #include "../template/template_infrastructure.hpp.sq" template <> const char *GetClassName() { return "AIInfrastructure"; } void SQAIInfrastructure_Register(Squirrel *engine) { DefSQClass SQAIInfrastructure("AIInfrastructure"); SQAIInfrastructure.PreRegister(engine); SQAIInfrastructure.AddConstructor(engine, "x"); SQAIInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_RAIL, "INFRASTRUCTURE_RAIL"); SQAIInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_SIGNALS, "INFRASTRUCTURE_SIGNALS"); SQAIInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_ROAD, "INFRASTRUCTURE_ROAD"); SQAIInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_CANAL, "INFRASTRUCTURE_CANAL"); SQAIInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_STATION, "INFRASTRUCTURE_STATION"); SQAIInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_AIRPORT, "INFRASTRUCTURE_AIRPORT"); SQAIInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetRailPieceCount, "GetRailPieceCount", 3, ".ii"); SQAIInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetRoadPieceCount, "GetRoadPieceCount", 3, ".ii"); SQAIInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetInfrastructurePieceCount, "GetInfrastructurePieceCount", 3, ".ii"); SQAIInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetMonthlyRailCosts, "GetMonthlyRailCosts", 3, ".ii"); SQAIInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetMonthlyRoadCosts, "GetMonthlyRoadCosts", 3, ".ii"); SQAIInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetMonthlyInfrastructureCosts, "GetMonthlyInfrastructureCosts", 3, ".ii"); SQAIInfrastructure.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_date.hpp.sq0000644000000000000000000000327212627373434017670 0ustar rootroot/* $Id: ai_date.hpp.sq 26307 2014-02-06 19:50:34Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_date.hpp" #include "../template/template_date.hpp.sq" template <> const char *GetClassName() { return "AIDate"; } void SQAIDate_Register(Squirrel *engine) { DefSQClass SQAIDate("AIDate"); SQAIDate.PreRegister(engine); SQAIDate.AddConstructor(engine, "x"); SQAIDate.DefSQConst(engine, ScriptDate::DATE_INVALID, "DATE_INVALID"); SQAIDate.DefSQStaticMethod(engine, &ScriptDate::IsValidDate, "IsValidDate", 2, ".i"); SQAIDate.DefSQStaticMethod(engine, &ScriptDate::GetCurrentDate, "GetCurrentDate", 1, "."); SQAIDate.DefSQStaticMethod(engine, &ScriptDate::GetYear, "GetYear", 2, ".i"); SQAIDate.DefSQStaticMethod(engine, &ScriptDate::GetMonth, "GetMonth", 2, ".i"); SQAIDate.DefSQStaticMethod(engine, &ScriptDate::GetDayOfMonth, "GetDayOfMonth", 2, ".i"); SQAIDate.DefSQStaticMethod(engine, &ScriptDate::GetDate, "GetDate", 4, ".iii"); SQAIDate.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_accounting.hpp.sq0000644000000000000000000000251212627373434021101 0ustar rootroot/* $Id: ai_accounting.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_accounting.hpp" #include "../template/template_accounting.hpp.sq" template <> const char *GetClassName() { return "AIAccounting"; } void SQAIAccounting_Register(Squirrel *engine) { DefSQClass SQAIAccounting("AIAccounting"); SQAIAccounting.PreRegister(engine); SQAIAccounting.AddConstructor(engine, "x"); SQAIAccounting.DefSQMethod(engine, &ScriptAccounting::GetCosts, "GetCosts", 1, "x"); SQAIAccounting.DefSQMethod(engine, &ScriptAccounting::ResetCosts, "ResetCosts", 1, "x"); SQAIAccounting.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_subsidy.hpp.sq0000644000000000000000000000445212627373434020436 0ustar rootroot/* $Id: ai_subsidy.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_subsidy.hpp" #include "../template/template_subsidy.hpp.sq" template <> const char *GetClassName() { return "AISubsidy"; } void SQAISubsidy_Register(Squirrel *engine) { DefSQClass SQAISubsidy("AISubsidy"); SQAISubsidy.PreRegister(engine); SQAISubsidy.AddConstructor(engine, "x"); SQAISubsidy.DefSQConst(engine, ScriptSubsidy::SPT_INDUSTRY, "SPT_INDUSTRY"); SQAISubsidy.DefSQConst(engine, ScriptSubsidy::SPT_TOWN, "SPT_TOWN"); SQAISubsidy.DefSQConst(engine, ScriptSubsidy::SPT_INVALID, "SPT_INVALID"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::IsValidSubsidy, "IsValidSubsidy", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::IsAwarded, "IsAwarded", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetAwardedTo, "GetAwardedTo", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetExpireDate, "GetExpireDate", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetCargoType, "GetCargoType", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetSourceType, "GetSourceType", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetSourceIndex, "GetSourceIndex", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetDestinationType, "GetDestinationType", 2, ".i"); SQAISubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetDestinationIndex, "GetDestinationIndex", 2, ".i"); SQAISubsidy.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_airport.hpp.sq0000644000000000000000000001037412627373434020434 0ustar rootroot/* $Id: ai_airport.hpp.sq 23416 2011-12-03 23:40:57Z michi_cc $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_airport.hpp" #include "../template/template_airport.hpp.sq" template <> const char *GetClassName() { return "AIAirport"; } void SQAIAirport_Register(Squirrel *engine) { DefSQClass SQAIAirport("AIAirport"); SQAIAirport.PreRegister(engine); SQAIAirport.AddConstructor(engine, "x"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_SMALL, "AT_SMALL"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_LARGE, "AT_LARGE"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_METROPOLITAN, "AT_METROPOLITAN"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_INTERNATIONAL, "AT_INTERNATIONAL"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_COMMUTER, "AT_COMMUTER"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_INTERCON, "AT_INTERCON"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_HELIPORT, "AT_HELIPORT"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_HELISTATION, "AT_HELISTATION"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_HELIDEPOT, "AT_HELIDEPOT"); SQAIAirport.DefSQConst(engine, ScriptAirport::AT_INVALID, "AT_INVALID"); SQAIAirport.DefSQConst(engine, ScriptAirport::PT_HELICOPTER, "PT_HELICOPTER"); SQAIAirport.DefSQConst(engine, ScriptAirport::PT_SMALL_PLANE, "PT_SMALL_PLANE"); SQAIAirport.DefSQConst(engine, ScriptAirport::PT_BIG_PLANE, "PT_BIG_PLANE"); SQAIAirport.DefSQConst(engine, ScriptAirport::PT_INVALID, "PT_INVALID"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::IsValidAirportType, "IsValidAirportType", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::IsAirportInformationAvailable, "IsAirportInformationAvailable", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetPrice, "GetPrice", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::IsHangarTile, "IsHangarTile", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::IsAirportTile, "IsAirportTile", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportWidth, "GetAirportWidth", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportHeight, "GetAirportHeight", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportCoverageRadius, "GetAirportCoverageRadius", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetNumHangars, "GetNumHangars", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetHangarOfAirport, "GetHangarOfAirport", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::BuildAirport, "BuildAirport", 4, ".iii"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::RemoveAirport, "RemoveAirport", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportType, "GetAirportType", 2, ".i"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetNoiseLevelIncrease, "GetNoiseLevelIncrease", 3, ".ii"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetNearestTown, "GetNearestTown", 3, ".ii"); SQAIAirport.DefSQStaticMethod(engine, &ScriptAirport::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQAIAirport.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_rail.hpp.sq0000644000000000000000000002156712627373434017711 0ustar rootroot/* $Id: ai_rail.hpp.sq 25614 2013-07-15 18:19:26Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_rail.hpp" #include "../template/template_rail.hpp.sq" template <> const char *GetClassName() { return "AIRail"; } void SQAIRail_Register(Squirrel *engine) { DefSQClass SQAIRail("AIRail"); SQAIRail.PreRegister(engine); SQAIRail.AddConstructor(engine, "x"); SQAIRail.DefSQConst(engine, ScriptRail::ERR_RAIL_BASE, "ERR_RAIL_BASE"); SQAIRail.DefSQConst(engine, ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); SQAIRail.DefSQConst(engine, ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); SQAIRail.DefSQConst(engine, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING, "ERR_RAILTYPE_DISALLOWS_CROSSING"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTYPE_INVALID, "RAILTYPE_INVALID"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTRACK_NE_SW, "RAILTRACK_NE_SW"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTRACK_NW_SE, "RAILTRACK_NW_SE"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTRACK_NW_NE, "RAILTRACK_NW_NE"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTRACK_SW_SE, "RAILTRACK_SW_SE"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTRACK_NW_SW, "RAILTRACK_NW_SW"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTRACK_NE_SE, "RAILTRACK_NE_SE"); SQAIRail.DefSQConst(engine, ScriptRail::RAILTRACK_INVALID, "RAILTRACK_INVALID"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_NORMAL, "SIGNALTYPE_NORMAL"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_ENTRY, "SIGNALTYPE_ENTRY"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_EXIT, "SIGNALTYPE_EXIT"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_COMBO, "SIGNALTYPE_COMBO"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_PBS, "SIGNALTYPE_PBS"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_PBS_ONEWAY, "SIGNALTYPE_PBS_ONEWAY"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_TWOWAY, "SIGNALTYPE_TWOWAY"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_NORMAL_TWOWAY, "SIGNALTYPE_NORMAL_TWOWAY"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_ENTRY_TWOWAY, "SIGNALTYPE_ENTRY_TWOWAY"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_EXIT_TWOWAY, "SIGNALTYPE_EXIT_TWOWAY"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_COMBO_TWOWAY, "SIGNALTYPE_COMBO_TWOWAY"); SQAIRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_NONE, "SIGNALTYPE_NONE"); SQAIRail.DefSQConst(engine, ScriptRail::BT_TRACK, "BT_TRACK"); SQAIRail.DefSQConst(engine, ScriptRail::BT_SIGNAL, "BT_SIGNAL"); SQAIRail.DefSQConst(engine, ScriptRail::BT_DEPOT, "BT_DEPOT"); SQAIRail.DefSQConst(engine, ScriptRail::BT_STATION, "BT_STATION"); SQAIRail.DefSQConst(engine, ScriptRail::BT_WAYPOINT, "BT_WAYPOINT"); ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_ON_ONEWAY_ROAD, ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_ARE_NO_SIGNALS, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_STATION, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); ScriptError::RegisterErrorMapString(ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING, "ERR_RAILTYPE_DISALLOWS_CROSSING"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetName, "GetName", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::IsRailTile, "IsRailTile", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::IsLevelCrossingTile, "IsLevelCrossingTile", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::IsRailDepotTile, "IsRailDepotTile", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::IsRailStationTile, "IsRailStationTile", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::IsRailWaypointTile, "IsRailWaypointTile", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::IsRailTypeAvailable, "IsRailTypeAvailable", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetCurrentRailType, "GetCurrentRailType", 1, "."); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::SetCurrentRailType, "SetCurrentRailType", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::TrainCanRunOnRail, "TrainCanRunOnRail", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::TrainHasPowerOnRail, "TrainHasPowerOnRail", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetRailType, "GetRailType", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::ConvertRailType, "ConvertRailType", 4, ".iii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetRailDepotFrontTile, "GetRailDepotFrontTile", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetRailStationDirection, "GetRailStationDirection", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailDepot, "BuildRailDepot", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailStation, "BuildRailStation", 6, ".iiiii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::BuildNewGRFRailStation, "BuildNewGRFRailStation", 11, ".iiiiiiiiib"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailWaypoint, "BuildRailWaypoint", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRailWaypointTileRectangle, "RemoveRailWaypointTileRectangle", 4, ".iib"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRailStationTileRectangle, "RemoveRailStationTileRectangle", 4, ".iib"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetRailTracks, "GetRailTracks", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailTrack, "BuildRailTrack", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRailTrack, "RemoveRailTrack", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::AreTilesConnected, "AreTilesConnected", 4, ".iii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::BuildRail, "BuildRail", 4, ".iii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRail, "RemoveRail", 4, ".iii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetSignalType, "GetSignalType", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::BuildSignal, "BuildSignal", 4, ".iii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::RemoveSignal, "RemoveSignal", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetBuildCost, "GetBuildCost", 3, ".ii"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQAIRail.DefSQStaticMethod(engine, &ScriptRail::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQAIRail.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_cargo.hpp.sq0000644000000000000000000000737612627373434020057 0ustar rootroot/* $Id: ai_cargo.hpp.sq 26396 2014-03-10 22:18:53Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargo.hpp" #include "../template/template_cargo.hpp.sq" template <> const char *GetClassName() { return "AICargo"; } void SQAICargo_Register(Squirrel *engine) { DefSQClass SQAICargo("AICargo"); SQAICargo.PreRegister(engine); SQAICargo.AddConstructor(engine, "x"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_PASSENGERS, "CC_PASSENGERS"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_MAIL, "CC_MAIL"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_EXPRESS, "CC_EXPRESS"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_ARMOURED, "CC_ARMOURED"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_BULK, "CC_BULK"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_PIECE_GOODS, "CC_PIECE_GOODS"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_LIQUID, "CC_LIQUID"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_REFRIGERATED, "CC_REFRIGERATED"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_HAZARDOUS, "CC_HAZARDOUS"); SQAICargo.DefSQConst(engine, ScriptCargo::CC_COVERED, "CC_COVERED"); SQAICargo.DefSQConst(engine, ScriptCargo::TE_NONE, "TE_NONE"); SQAICargo.DefSQConst(engine, ScriptCargo::TE_PASSENGERS, "TE_PASSENGERS"); SQAICargo.DefSQConst(engine, ScriptCargo::TE_MAIL, "TE_MAIL"); SQAICargo.DefSQConst(engine, ScriptCargo::TE_GOODS, "TE_GOODS"); SQAICargo.DefSQConst(engine, ScriptCargo::TE_WATER, "TE_WATER"); SQAICargo.DefSQConst(engine, ScriptCargo::TE_FOOD, "TE_FOOD"); SQAICargo.DefSQConst(engine, ScriptCargo::CT_AUTO_REFIT, "CT_AUTO_REFIT"); SQAICargo.DefSQConst(engine, ScriptCargo::CT_NO_REFIT, "CT_NO_REFIT"); SQAICargo.DefSQConst(engine, ScriptCargo::DT_MANUAL, "DT_MANUAL"); SQAICargo.DefSQConst(engine, ScriptCargo::DT_ASYMMETRIC, "DT_ASYMMETRIC"); SQAICargo.DefSQConst(engine, ScriptCargo::DT_SYMMETRIC, "DT_SYMMETRIC"); SQAICargo.DefSQConst(engine, ScriptCargo::INVALID_DISTRIBUTION_TYPE, "INVALID_DISTRIBUTION_TYPE"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::IsValidCargo, "IsValidCargo", 2, ".i"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::IsValidTownEffect, "IsValidTownEffect", 2, ".i"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::GetCargoLabel, "GetCargoLabel", 2, ".i"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::IsFreight, "IsFreight", 2, ".i"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::HasCargoClass, "HasCargoClass", 3, ".ii"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::GetTownEffect, "GetTownEffect", 2, ".i"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::GetCargoIncome, "GetCargoIncome", 4, ".iii"); SQAICargo.DefSQStaticMethod(engine, &ScriptCargo::GetDistributionType, "GetDistributionType", 2, ".i"); SQAICargo.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_event_types.hpp.sq0000644000000000000000000004441512627373434021324 0ustar rootroot/* $Id: ai_event_types.hpp.sq 24291 2012-05-26 14:16:45Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_event_types.hpp" #include "../template/template_event_types.hpp.sq" template <> const char *GetClassName() { return "AIEventVehicleCrashed"; } void SQAIEventVehicleCrashed_Register(Squirrel *engine) { DefSQClass SQAIEventVehicleCrashed("AIEventVehicleCrashed"); SQAIEventVehicleCrashed.PreRegister(engine, "AIEvent"); SQAIEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_TRAIN, "CRASH_TRAIN"); SQAIEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, "CRASH_RV_LEVEL_CROSSING"); SQAIEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_RV_UFO, "CRASH_RV_UFO"); SQAIEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, "CRASH_PLANE_LANDING"); SQAIEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT, "CRASH_AIRCRAFT_NO_AIRPORT"); SQAIEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_FLOODED, "CRASH_FLOODED"); SQAIEventVehicleCrashed.DefSQStaticMethod(engine, &ScriptEventVehicleCrashed::Convert, "Convert", 2, ".x"); SQAIEventVehicleCrashed.DefSQMethod(engine, &ScriptEventVehicleCrashed::GetVehicleID, "GetVehicleID", 1, "x"); SQAIEventVehicleCrashed.DefSQMethod(engine, &ScriptEventVehicleCrashed::GetCrashSite, "GetCrashSite", 1, "x"); SQAIEventVehicleCrashed.DefSQMethod(engine, &ScriptEventVehicleCrashed::GetCrashReason, "GetCrashReason", 1, "x"); SQAIEventVehicleCrashed.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventSubsidyOffer"; } void SQAIEventSubsidyOffer_Register(Squirrel *engine) { DefSQClass SQAIEventSubsidyOffer("AIEventSubsidyOffer"); SQAIEventSubsidyOffer.PreRegister(engine, "AIEvent"); SQAIEventSubsidyOffer.DefSQStaticMethod(engine, &ScriptEventSubsidyOffer::Convert, "Convert", 2, ".x"); SQAIEventSubsidyOffer.DefSQMethod(engine, &ScriptEventSubsidyOffer::GetSubsidyID, "GetSubsidyID", 1, "x"); SQAIEventSubsidyOffer.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventSubsidyOfferExpired"; } void SQAIEventSubsidyOfferExpired_Register(Squirrel *engine) { DefSQClass SQAIEventSubsidyOfferExpired("AIEventSubsidyOfferExpired"); SQAIEventSubsidyOfferExpired.PreRegister(engine, "AIEvent"); SQAIEventSubsidyOfferExpired.DefSQStaticMethod(engine, &ScriptEventSubsidyOfferExpired::Convert, "Convert", 2, ".x"); SQAIEventSubsidyOfferExpired.DefSQMethod(engine, &ScriptEventSubsidyOfferExpired::GetSubsidyID, "GetSubsidyID", 1, "x"); SQAIEventSubsidyOfferExpired.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventSubsidyAwarded"; } void SQAIEventSubsidyAwarded_Register(Squirrel *engine) { DefSQClass SQAIEventSubsidyAwarded("AIEventSubsidyAwarded"); SQAIEventSubsidyAwarded.PreRegister(engine, "AIEvent"); SQAIEventSubsidyAwarded.DefSQStaticMethod(engine, &ScriptEventSubsidyAwarded::Convert, "Convert", 2, ".x"); SQAIEventSubsidyAwarded.DefSQMethod(engine, &ScriptEventSubsidyAwarded::GetSubsidyID, "GetSubsidyID", 1, "x"); SQAIEventSubsidyAwarded.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventSubsidyExpired"; } void SQAIEventSubsidyExpired_Register(Squirrel *engine) { DefSQClass SQAIEventSubsidyExpired("AIEventSubsidyExpired"); SQAIEventSubsidyExpired.PreRegister(engine, "AIEvent"); SQAIEventSubsidyExpired.DefSQStaticMethod(engine, &ScriptEventSubsidyExpired::Convert, "Convert", 2, ".x"); SQAIEventSubsidyExpired.DefSQMethod(engine, &ScriptEventSubsidyExpired::GetSubsidyID, "GetSubsidyID", 1, "x"); SQAIEventSubsidyExpired.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventEnginePreview"; } void SQAIEventEnginePreview_Register(Squirrel *engine) { DefSQClass SQAIEventEnginePreview("AIEventEnginePreview"); SQAIEventEnginePreview.PreRegister(engine, "AIEvent"); SQAIEventEnginePreview.DefSQStaticMethod(engine, &ScriptEventEnginePreview::Convert, "Convert", 2, ".x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::GetName, "GetName", 1, "x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::GetCargoType, "GetCargoType", 1, "x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::GetCapacity, "GetCapacity", 1, "x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::GetMaxSpeed, "GetMaxSpeed", 1, "x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::GetPrice, "GetPrice", 1, "x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::GetRunningCost, "GetRunningCost", 1, "x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::GetVehicleType, "GetVehicleType", 1, "x"); SQAIEventEnginePreview.DefSQMethod(engine, &ScriptEventEnginePreview::AcceptPreview, "AcceptPreview", 1, "x"); SQAIEventEnginePreview.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventCompanyNew"; } void SQAIEventCompanyNew_Register(Squirrel *engine) { DefSQClass SQAIEventCompanyNew("AIEventCompanyNew"); SQAIEventCompanyNew.PreRegister(engine, "AIEvent"); SQAIEventCompanyNew.DefSQStaticMethod(engine, &ScriptEventCompanyNew::Convert, "Convert", 2, ".x"); SQAIEventCompanyNew.DefSQMethod(engine, &ScriptEventCompanyNew::GetCompanyID, "GetCompanyID", 1, "x"); SQAIEventCompanyNew.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventCompanyInTrouble"; } void SQAIEventCompanyInTrouble_Register(Squirrel *engine) { DefSQClass SQAIEventCompanyInTrouble("AIEventCompanyInTrouble"); SQAIEventCompanyInTrouble.PreRegister(engine, "AIEvent"); SQAIEventCompanyInTrouble.DefSQStaticMethod(engine, &ScriptEventCompanyInTrouble::Convert, "Convert", 2, ".x"); SQAIEventCompanyInTrouble.DefSQMethod(engine, &ScriptEventCompanyInTrouble::GetCompanyID, "GetCompanyID", 1, "x"); SQAIEventCompanyInTrouble.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventCompanyAskMerger"; } void SQAIEventCompanyAskMerger_Register(Squirrel *engine) { DefSQClass SQAIEventCompanyAskMerger("AIEventCompanyAskMerger"); SQAIEventCompanyAskMerger.PreRegister(engine, "AIEvent"); SQAIEventCompanyAskMerger.DefSQStaticMethod(engine, &ScriptEventCompanyAskMerger::Convert, "Convert", 2, ".x"); SQAIEventCompanyAskMerger.DefSQMethod(engine, &ScriptEventCompanyAskMerger::GetCompanyID, "GetCompanyID", 1, "x"); SQAIEventCompanyAskMerger.DefSQMethod(engine, &ScriptEventCompanyAskMerger::GetValue, "GetValue", 1, "x"); SQAIEventCompanyAskMerger.DefSQMethod(engine, &ScriptEventCompanyAskMerger::AcceptMerger, "AcceptMerger", 1, "x"); SQAIEventCompanyAskMerger.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventCompanyMerger"; } void SQAIEventCompanyMerger_Register(Squirrel *engine) { DefSQClass SQAIEventCompanyMerger("AIEventCompanyMerger"); SQAIEventCompanyMerger.PreRegister(engine, "AIEvent"); SQAIEventCompanyMerger.DefSQStaticMethod(engine, &ScriptEventCompanyMerger::Convert, "Convert", 2, ".x"); SQAIEventCompanyMerger.DefSQMethod(engine, &ScriptEventCompanyMerger::GetOldCompanyID, "GetOldCompanyID", 1, "x"); SQAIEventCompanyMerger.DefSQMethod(engine, &ScriptEventCompanyMerger::GetNewCompanyID, "GetNewCompanyID", 1, "x"); SQAIEventCompanyMerger.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventCompanyBankrupt"; } void SQAIEventCompanyBankrupt_Register(Squirrel *engine) { DefSQClass SQAIEventCompanyBankrupt("AIEventCompanyBankrupt"); SQAIEventCompanyBankrupt.PreRegister(engine, "AIEvent"); SQAIEventCompanyBankrupt.DefSQStaticMethod(engine, &ScriptEventCompanyBankrupt::Convert, "Convert", 2, ".x"); SQAIEventCompanyBankrupt.DefSQMethod(engine, &ScriptEventCompanyBankrupt::GetCompanyID, "GetCompanyID", 1, "x"); SQAIEventCompanyBankrupt.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventVehicleLost"; } void SQAIEventVehicleLost_Register(Squirrel *engine) { DefSQClass SQAIEventVehicleLost("AIEventVehicleLost"); SQAIEventVehicleLost.PreRegister(engine, "AIEvent"); SQAIEventVehicleLost.DefSQStaticMethod(engine, &ScriptEventVehicleLost::Convert, "Convert", 2, ".x"); SQAIEventVehicleLost.DefSQMethod(engine, &ScriptEventVehicleLost::GetVehicleID, "GetVehicleID", 1, "x"); SQAIEventVehicleLost.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventVehicleWaitingInDepot"; } void SQAIEventVehicleWaitingInDepot_Register(Squirrel *engine) { DefSQClass SQAIEventVehicleWaitingInDepot("AIEventVehicleWaitingInDepot"); SQAIEventVehicleWaitingInDepot.PreRegister(engine, "AIEvent"); SQAIEventVehicleWaitingInDepot.DefSQStaticMethod(engine, &ScriptEventVehicleWaitingInDepot::Convert, "Convert", 2, ".x"); SQAIEventVehicleWaitingInDepot.DefSQMethod(engine, &ScriptEventVehicleWaitingInDepot::GetVehicleID, "GetVehicleID", 1, "x"); SQAIEventVehicleWaitingInDepot.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventVehicleUnprofitable"; } void SQAIEventVehicleUnprofitable_Register(Squirrel *engine) { DefSQClass SQAIEventVehicleUnprofitable("AIEventVehicleUnprofitable"); SQAIEventVehicleUnprofitable.PreRegister(engine, "AIEvent"); SQAIEventVehicleUnprofitable.DefSQStaticMethod(engine, &ScriptEventVehicleUnprofitable::Convert, "Convert", 2, ".x"); SQAIEventVehicleUnprofitable.DefSQMethod(engine, &ScriptEventVehicleUnprofitable::GetVehicleID, "GetVehicleID", 1, "x"); SQAIEventVehicleUnprofitable.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventIndustryOpen"; } void SQAIEventIndustryOpen_Register(Squirrel *engine) { DefSQClass SQAIEventIndustryOpen("AIEventIndustryOpen"); SQAIEventIndustryOpen.PreRegister(engine, "AIEvent"); SQAIEventIndustryOpen.DefSQStaticMethod(engine, &ScriptEventIndustryOpen::Convert, "Convert", 2, ".x"); SQAIEventIndustryOpen.DefSQMethod(engine, &ScriptEventIndustryOpen::GetIndustryID, "GetIndustryID", 1, "x"); SQAIEventIndustryOpen.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventIndustryClose"; } void SQAIEventIndustryClose_Register(Squirrel *engine) { DefSQClass SQAIEventIndustryClose("AIEventIndustryClose"); SQAIEventIndustryClose.PreRegister(engine, "AIEvent"); SQAIEventIndustryClose.DefSQStaticMethod(engine, &ScriptEventIndustryClose::Convert, "Convert", 2, ".x"); SQAIEventIndustryClose.DefSQMethod(engine, &ScriptEventIndustryClose::GetIndustryID, "GetIndustryID", 1, "x"); SQAIEventIndustryClose.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventEngineAvailable"; } void SQAIEventEngineAvailable_Register(Squirrel *engine) { DefSQClass SQAIEventEngineAvailable("AIEventEngineAvailable"); SQAIEventEngineAvailable.PreRegister(engine, "AIEvent"); SQAIEventEngineAvailable.DefSQStaticMethod(engine, &ScriptEventEngineAvailable::Convert, "Convert", 2, ".x"); SQAIEventEngineAvailable.DefSQMethod(engine, &ScriptEventEngineAvailable::GetEngineID, "GetEngineID", 1, "x"); SQAIEventEngineAvailable.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventStationFirstVehicle"; } void SQAIEventStationFirstVehicle_Register(Squirrel *engine) { DefSQClass SQAIEventStationFirstVehicle("AIEventStationFirstVehicle"); SQAIEventStationFirstVehicle.PreRegister(engine, "AIEvent"); SQAIEventStationFirstVehicle.DefSQStaticMethod(engine, &ScriptEventStationFirstVehicle::Convert, "Convert", 2, ".x"); SQAIEventStationFirstVehicle.DefSQMethod(engine, &ScriptEventStationFirstVehicle::GetStationID, "GetStationID", 1, "x"); SQAIEventStationFirstVehicle.DefSQMethod(engine, &ScriptEventStationFirstVehicle::GetVehicleID, "GetVehicleID", 1, "x"); SQAIEventStationFirstVehicle.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventDisasterZeppelinerCrashed"; } void SQAIEventDisasterZeppelinerCrashed_Register(Squirrel *engine) { DefSQClass SQAIEventDisasterZeppelinerCrashed("AIEventDisasterZeppelinerCrashed"); SQAIEventDisasterZeppelinerCrashed.PreRegister(engine, "AIEvent"); SQAIEventDisasterZeppelinerCrashed.DefSQStaticMethod(engine, &ScriptEventDisasterZeppelinerCrashed::Convert, "Convert", 2, ".x"); SQAIEventDisasterZeppelinerCrashed.DefSQMethod(engine, &ScriptEventDisasterZeppelinerCrashed::GetStationID, "GetStationID", 1, "x"); SQAIEventDisasterZeppelinerCrashed.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventDisasterZeppelinerCleared"; } void SQAIEventDisasterZeppelinerCleared_Register(Squirrel *engine) { DefSQClass SQAIEventDisasterZeppelinerCleared("AIEventDisasterZeppelinerCleared"); SQAIEventDisasterZeppelinerCleared.PreRegister(engine, "AIEvent"); SQAIEventDisasterZeppelinerCleared.DefSQStaticMethod(engine, &ScriptEventDisasterZeppelinerCleared::Convert, "Convert", 2, ".x"); SQAIEventDisasterZeppelinerCleared.DefSQMethod(engine, &ScriptEventDisasterZeppelinerCleared::GetStationID, "GetStationID", 1, "x"); SQAIEventDisasterZeppelinerCleared.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventTownFounded"; } void SQAIEventTownFounded_Register(Squirrel *engine) { DefSQClass SQAIEventTownFounded("AIEventTownFounded"); SQAIEventTownFounded.PreRegister(engine, "AIEvent"); SQAIEventTownFounded.DefSQStaticMethod(engine, &ScriptEventTownFounded::Convert, "Convert", 2, ".x"); SQAIEventTownFounded.DefSQMethod(engine, &ScriptEventTownFounded::GetTownID, "GetTownID", 1, "x"); SQAIEventTownFounded.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventAircraftDestTooFar"; } void SQAIEventAircraftDestTooFar_Register(Squirrel *engine) { DefSQClass SQAIEventAircraftDestTooFar("AIEventAircraftDestTooFar"); SQAIEventAircraftDestTooFar.PreRegister(engine, "AIEvent"); SQAIEventAircraftDestTooFar.DefSQStaticMethod(engine, &ScriptEventAircraftDestTooFar::Convert, "Convert", 2, ".x"); SQAIEventAircraftDestTooFar.DefSQMethod(engine, &ScriptEventAircraftDestTooFar::GetVehicleID, "GetVehicleID", 1, "x"); SQAIEventAircraftDestTooFar.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventCompanyTown"; } void SQAIEventCompanyTown_Register(Squirrel *engine) { DefSQClass SQAIEventCompanyTown("AIEventCompanyTown"); SQAIEventCompanyTown.PreRegister(engine, "AIEvent"); SQAIEventCompanyTown.DefSQStaticMethod(engine, &ScriptEventCompanyTown::Convert, "Convert", 2, ".x"); SQAIEventCompanyTown.DefSQMethod(engine, &ScriptEventCompanyTown::GetCompanyID, "GetCompanyID", 1, "x"); SQAIEventCompanyTown.DefSQMethod(engine, &ScriptEventCompanyTown::GetTownID, "GetTownID", 1, "x"); SQAIEventCompanyTown.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventExclusiveTransportRights"; } void SQAIEventExclusiveTransportRights_Register(Squirrel *engine) { DefSQClass SQAIEventExclusiveTransportRights("AIEventExclusiveTransportRights"); SQAIEventExclusiveTransportRights.PreRegister(engine, "AIEventCompanyTown"); SQAIEventExclusiveTransportRights.AddConstructor(engine, "xii"); SQAIEventExclusiveTransportRights.DefSQStaticMethod(engine, &ScriptEventExclusiveTransportRights::Convert, "Convert", 2, ".x"); SQAIEventExclusiveTransportRights.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventRoadReconstruction"; } void SQAIEventRoadReconstruction_Register(Squirrel *engine) { DefSQClass SQAIEventRoadReconstruction("AIEventRoadReconstruction"); SQAIEventRoadReconstruction.PreRegister(engine, "AIEventCompanyTown"); SQAIEventRoadReconstruction.AddConstructor(engine, "xii"); SQAIEventRoadReconstruction.DefSQStaticMethod(engine, &ScriptEventRoadReconstruction::Convert, "Convert", 2, ".x"); SQAIEventRoadReconstruction.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_log.hpp.sq0000644000000000000000000000244212627373434017532 0ustar rootroot/* $Id: ai_log.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_log.hpp" #include "../template/template_log.hpp.sq" template <> const char *GetClassName() { return "AILog"; } void SQAILog_Register(Squirrel *engine) { DefSQClass SQAILog("AILog"); SQAILog.PreRegister(engine); SQAILog.AddConstructor(engine, "x"); SQAILog.DefSQStaticMethod(engine, &ScriptLog::Info, "Info", 2, ".."); SQAILog.DefSQStaticMethod(engine, &ScriptLog::Warning, "Warning", 2, ".."); SQAILog.DefSQStaticMethod(engine, &ScriptLog::Error, "Error", 2, ".."); SQAILog.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_bridge.hpp.sq0000644000000000000000000000656112627373434020213 0ustar rootroot/* $Id: ai_bridge.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_bridge.hpp" #include "../template/template_bridge.hpp.sq" template <> const char *GetClassName() { return "AIBridge"; } void SQAIBridge_Register(Squirrel *engine) { DefSQClass SQAIBridge("AIBridge"); SQAIBridge.PreRegister(engine); SQAIBridge.AddConstructor(engine, "x"); SQAIBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_BASE, "ERR_BRIDGE_BASE"); SQAIBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_TYPE_UNAVAILABLE, "ERR_BRIDGE_TYPE_UNAVAILABLE"); SQAIBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER, "ERR_BRIDGE_CANNOT_END_IN_WATER"); SQAIBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, "ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT"); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, ScriptBridge::ERR_BRIDGE_TYPE_UNAVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH, ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER); ScriptError::RegisterErrorMap(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT, ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT); ScriptError::RegisterErrorMapString(ScriptBridge::ERR_BRIDGE_TYPE_UNAVAILABLE, "ERR_BRIDGE_TYPE_UNAVAILABLE"); ScriptError::RegisterErrorMapString(ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER, "ERR_BRIDGE_CANNOT_END_IN_WATER"); ScriptError::RegisterErrorMapString(ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, "ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::IsValidBridge, "IsValidBridge", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::IsBridgeTile, "IsBridgeTile", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::GetBridgeID, "GetBridgeID", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::GetName, "GetName", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::GetPrice, "GetPrice", 3, ".ii"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::GetMaxLength, "GetMaxLength", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::GetMinLength, "GetMinLength", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::BuildBridge, "BuildBridge", 5, ".iiii"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::RemoveBridge, "RemoveBridge", 2, ".i"); SQAIBridge.DefSQStaticMethod(engine, &ScriptBridge::GetOtherBridgeEnd, "GetOtherBridgeEnd", 2, ".i"); SQAIBridge.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_town.hpp.sq0000644000000000000000000001640412627373434017743 0ustar rootroot/* $Id: ai_town.hpp.sq 25969 2013-11-12 17:57:32Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_town.hpp" #include "../template/template_town.hpp.sq" template <> const char *GetClassName() { return "AITown"; } void SQAITown_Register(Squirrel *engine) { DefSQClass SQAITown("AITown"); SQAITown.PreRegister(engine); SQAITown.AddConstructor(engine, "x"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ADVERTISE_SMALL, "TOWN_ACTION_ADVERTISE_SMALL"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ADVERTISE_MEDIUM, "TOWN_ACTION_ADVERTISE_MEDIUM"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ADVERTISE_LARGE, "TOWN_ACTION_ADVERTISE_LARGE"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ROAD_REBUILD, "TOWN_ACTION_ROAD_REBUILD"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_BUILD_STATUE, "TOWN_ACTION_BUILD_STATUE"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_FUND_BUILDINGS, "TOWN_ACTION_FUND_BUILDINGS"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_BUY_RIGHTS, "TOWN_ACTION_BUY_RIGHTS"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_ACTION_BRIBE, "TOWN_ACTION_BRIBE"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_NONE, "TOWN_RATING_NONE"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_APPALLING, "TOWN_RATING_APPALLING"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_VERY_POOR, "TOWN_RATING_VERY_POOR"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_POOR, "TOWN_RATING_POOR"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_MEDIOCRE, "TOWN_RATING_MEDIOCRE"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_GOOD, "TOWN_RATING_GOOD"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_VERY_GOOD, "TOWN_RATING_VERY_GOOD"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_EXCELLENT, "TOWN_RATING_EXCELLENT"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_OUTSTANDING, "TOWN_RATING_OUTSTANDING"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_RATING_INVALID, "TOWN_RATING_INVALID"); SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_ORIGINAL, "ROAD_LAYOUT_ORIGINAL"); SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_BETTER_ROADS, "ROAD_LAYOUT_BETTER_ROADS"); SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_2x2, "ROAD_LAYOUT_2x2"); SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_3x3, "ROAD_LAYOUT_3x3"); SQAITown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_INVALID, "ROAD_LAYOUT_INVALID"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_SIZE_SMALL, "TOWN_SIZE_SMALL"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_SIZE_MEDIUM, "TOWN_SIZE_MEDIUM"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_SIZE_LARGE, "TOWN_SIZE_LARGE"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_SIZE_INVALID, "TOWN_SIZE_INVALID"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_GROWTH_NONE, "TOWN_GROWTH_NONE"); SQAITown.DefSQConst(engine, ScriptTown::TOWN_GROWTH_NORMAL, "TOWN_GROWTH_NORMAL"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetTownCount, "GetTownCount", 1, "."); SQAITown.DefSQStaticMethod(engine, &ScriptTown::IsValidTown, "IsValidTown", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetName, "GetName", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetPopulation, "GetPopulation", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetHouseCount, "GetHouseCount", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetLocation, "GetLocation", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthProduction, "GetLastMonthProduction", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthSupplied, "GetLastMonthSupplied", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthTransportedPercentage, "GetLastMonthTransportedPercentage", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthReceived, "GetLastMonthReceived", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetCargoGoal, "GetCargoGoal", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetGrowthRate, "GetGrowthRate", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::IsWithinTownInfluence, "IsWithinTownInfluence", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::HasStatue, "HasStatue", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::IsCity, "IsCity", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetRoadReworkDuration, "GetRoadReworkDuration", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetFundBuildingsDuration, "GetFundBuildingsDuration", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetExclusiveRightsCompany, "GetExclusiveRightsCompany", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetExclusiveRightsDuration, "GetExclusiveRightsDuration", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::IsActionAvailable, "IsActionAvailable", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::PerformTownAction, "PerformTownAction", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::FoundTown, "FoundTown", 6, ".iibi."); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetRating, "GetRating", 3, ".ii"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetAllowedNoise, "GetAllowedNoise", 2, ".i"); SQAITown.DefSQStaticMethod(engine, &ScriptTown::GetRoadLayout, "GetRoadLayout", 2, ".i"); SQAITown.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_bridgelist.hpp.sq0000644000000000000000000000315312627373434021101 0ustar rootroot/* $Id: ai_bridgelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_bridgelist.hpp" #include "../template/template_bridgelist.hpp.sq" template <> const char *GetClassName() { return "AIBridgeList"; } void SQAIBridgeList_Register(Squirrel *engine) { DefSQClass SQAIBridgeList("AIBridgeList"); SQAIBridgeList.PreRegister(engine, "AIList"); SQAIBridgeList.AddConstructor(engine, "x"); SQAIBridgeList.PostRegister(engine); } template <> const char *GetClassName() { return "AIBridgeList_Length"; } void SQAIBridgeList_Length_Register(Squirrel *engine) { DefSQClass SQAIBridgeList_Length("AIBridgeList_Length"); SQAIBridgeList_Length.PreRegister(engine, "AIList"); SQAIBridgeList_Length.AddConstructor(engine, "xi"); SQAIBridgeList_Length.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_testmode.hpp.sq0000644000000000000000000000217312627373434020576 0ustar rootroot/* $Id: ai_testmode.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_testmode.hpp" #include "../template/template_testmode.hpp.sq" template <> const char *GetClassName() { return "AITestMode"; } void SQAITestMode_Register(Squirrel *engine) { DefSQClass SQAITestMode("AITestMode"); SQAITestMode.PreRegister(engine); SQAITestMode.AddConstructor(engine, "x"); SQAITestMode.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_event.hpp.sq0000644000000000000000000001123112627373434020066 0ustar rootroot/* $Id: ai_event.hpp.sq 24291 2012-05-26 14:16:45Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_event.hpp" #include "../template/template_event.hpp.sq" template <> const char *GetClassName() { return "AIEvent"; } void SQAIEvent_Register(Squirrel *engine) { DefSQClass SQAIEvent("AIEvent"); SQAIEvent.PreRegister(engine); SQAIEvent.AddConstructor(engine, "xi"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_INVALID, "ET_INVALID"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_TEST, "ET_TEST"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_OFFER, "ET_SUBSIDY_OFFER"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_OFFER_EXPIRED, "ET_SUBSIDY_OFFER_EXPIRED"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_AWARDED, "ET_SUBSIDY_AWARDED"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_EXPIRED, "ET_SUBSIDY_EXPIRED"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_ENGINE_PREVIEW, "ET_ENGINE_PREVIEW"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_NEW, "ET_COMPANY_NEW"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_IN_TROUBLE, "ET_COMPANY_IN_TROUBLE"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_ASK_MERGER, "ET_COMPANY_ASK_MERGER"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_MERGER, "ET_COMPANY_MERGER"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_BANKRUPT, "ET_COMPANY_BANKRUPT"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_CRASHED, "ET_VEHICLE_CRASHED"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_LOST, "ET_VEHICLE_LOST"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_WAITING_IN_DEPOT, "ET_VEHICLE_WAITING_IN_DEPOT"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_UNPROFITABLE, "ET_VEHICLE_UNPROFITABLE"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_INDUSTRY_OPEN, "ET_INDUSTRY_OPEN"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_INDUSTRY_CLOSE, "ET_INDUSTRY_CLOSE"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_ENGINE_AVAILABLE, "ET_ENGINE_AVAILABLE"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_STATION_FIRST_VEHICLE, "ET_STATION_FIRST_VEHICLE"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_DISASTER_ZEPPELINER_CRASHED, "ET_DISASTER_ZEPPELINER_CRASHED"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_DISASTER_ZEPPELINER_CLEARED, "ET_DISASTER_ZEPPELINER_CLEARED"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_TOWN_FOUNDED, "ET_TOWN_FOUNDED"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_AIRCRAFT_DEST_TOO_FAR, "ET_AIRCRAFT_DEST_TOO_FAR"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_ADMIN_PORT, "ET_ADMIN_PORT"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_WINDOW_WIDGET_CLICK, "ET_WINDOW_WIDGET_CLICK"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_GOAL_QUESTION_ANSWER, "ET_GOAL_QUESTION_ANSWER"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_EXCLUSIVE_TRANSPORT_RIGHTS, "ET_EXCLUSIVE_TRANSPORT_RIGHTS"); SQAIEvent.DefSQConst(engine, ScriptEvent::ET_ROAD_RECONSTRUCTION, "ET_ROAD_RECONSTRUCTION"); SQAIEvent.DefSQMethod(engine, &ScriptEvent::GetEventType, "GetEventType", 1, "x"); SQAIEvent.PostRegister(engine); } template <> const char *GetClassName() { return "AIEventController"; } void SQAIEventController_Register(Squirrel *engine) { DefSQClass SQAIEventController("AIEventController"); SQAIEventController.PreRegister(engine); SQAIEventController.AddConstructor(engine, "x"); SQAIEventController.DefSQStaticMethod(engine, &ScriptEventController::IsEventWaiting, "IsEventWaiting", 1, "."); SQAIEventController.DefSQStaticMethod(engine, &ScriptEventController::GetNextEvent, "GetNextEvent", 1, "."); SQAIEventController.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_grouplist.hpp.sq0000644000000000000000000000222212627373434020775 0ustar rootroot/* $Id: ai_grouplist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_grouplist.hpp" #include "../template/template_grouplist.hpp.sq" template <> const char *GetClassName() { return "AIGroupList"; } void SQAIGroupList_Register(Squirrel *engine) { DefSQClass SQAIGroupList("AIGroupList"); SQAIGroupList.PreRegister(engine, "AIList"); SQAIGroupList.AddConstructor(engine, "x"); SQAIGroupList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_error.hpp.sq0000644000000000000000000002602712627373434020107 0ustar rootroot/* $Id: ai_error.hpp.sq 24982 2013-02-08 20:34:27Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_error.hpp" #include "../template/template_error.hpp.sq" template <> const char *GetClassName() { return "AIError"; } void SQAIError_Register(Squirrel *engine) { DefSQClass SQAIError("AIError"); SQAIError.PreRegister(engine); SQAIError.AddConstructor(engine, "x"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_NONE, "ERR_CAT_NONE"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_GENERAL, "ERR_CAT_GENERAL"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_VEHICLE, "ERR_CAT_VEHICLE"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_STATION, "ERR_CAT_STATION"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_BRIDGE, "ERR_CAT_BRIDGE"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_TUNNEL, "ERR_CAT_TUNNEL"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_TILE, "ERR_CAT_TILE"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_SIGN, "ERR_CAT_SIGN"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_RAIL, "ERR_CAT_RAIL"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_ROAD, "ERR_CAT_ROAD"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_ORDER, "ERR_CAT_ORDER"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_MARINE, "ERR_CAT_MARINE"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_WAYPOINT, "ERR_CAT_WAYPOINT"); SQAIError.DefSQConst(engine, ScriptError::ERR_CAT_BIT_SIZE, "ERR_CAT_BIT_SIZE"); SQAIError.DefSQConst(engine, ScriptError::ERR_NONE, "ERR_NONE"); SQAIError.DefSQConst(engine, ScriptError::ERR_UNKNOWN, "ERR_UNKNOWN"); SQAIError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_FAILED, "ERR_PRECONDITION_FAILED"); SQAIError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG, "ERR_PRECONDITION_STRING_TOO_LONG"); SQAIError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, "ERR_PRECONDITION_TOO_MANY_PARAMETERS"); SQAIError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_INVALID_COMPANY, "ERR_PRECONDITION_INVALID_COMPANY"); SQAIError.DefSQConst(engine, ScriptError::ERR_NEWGRF_SUPPLIED_ERROR, "ERR_NEWGRF_SUPPLIED_ERROR"); SQAIError.DefSQConst(engine, ScriptError::ERR_GENERAL_BASE, "ERR_GENERAL_BASE"); SQAIError.DefSQConst(engine, ScriptError::ERR_NOT_ENOUGH_CASH, "ERR_NOT_ENOUGH_CASH"); SQAIError.DefSQConst(engine, ScriptError::ERR_LOCAL_AUTHORITY_REFUSES, "ERR_LOCAL_AUTHORITY_REFUSES"); SQAIError.DefSQConst(engine, ScriptError::ERR_ALREADY_BUILT, "ERR_ALREADY_BUILT"); SQAIError.DefSQConst(engine, ScriptError::ERR_AREA_NOT_CLEAR, "ERR_AREA_NOT_CLEAR"); SQAIError.DefSQConst(engine, ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY, "ERR_OWNED_BY_ANOTHER_COMPANY"); SQAIError.DefSQConst(engine, ScriptError::ERR_NAME_IS_NOT_UNIQUE, "ERR_NAME_IS_NOT_UNIQUE"); SQAIError.DefSQConst(engine, ScriptError::ERR_FLAT_LAND_REQUIRED, "ERR_FLAT_LAND_REQUIRED"); SQAIError.DefSQConst(engine, ScriptError::ERR_LAND_SLOPED_WRONG, "ERR_LAND_SLOPED_WRONG"); SQAIError.DefSQConst(engine, ScriptError::ERR_VEHICLE_IN_THE_WAY, "ERR_VEHICLE_IN_THE_WAY"); SQAIError.DefSQConst(engine, ScriptError::ERR_SITE_UNSUITABLE, "ERR_SITE_UNSUITABLE"); SQAIError.DefSQConst(engine, ScriptError::ERR_TOO_CLOSE_TO_EDGE, "ERR_TOO_CLOSE_TO_EDGE"); SQAIError.DefSQConst(engine, ScriptError::ERR_STATION_TOO_SPREAD_OUT, "ERR_STATION_TOO_SPREAD_OUT"); ScriptError::RegisterErrorMap(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY, ScriptError::ERR_NOT_ENOUGH_CASH); ScriptError::RegisterErrorMap(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, ScriptError::ERR_LOCAL_AUTHORITY_REFUSES); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_BUILT, ScriptError::ERR_ALREADY_BUILT); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, ScriptError::ERR_ALREADY_BUILT); ScriptError::RegisterErrorMap(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_RAILROAD, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_BUOY_IN_THE_WAY, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_COMPANY_HEADQUARTERS_IN, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_OBJECT_IN_THE_WAY, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_REMOVE_ROAD_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_EXCAVATION_WOULD_DAMAGE, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER, ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY); ScriptError::RegisterErrorMap(STR_ERROR_OWNED_BY, ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY); ScriptError::RegisterErrorMap(STR_ERROR_NAME_MUST_BE_UNIQUE, ScriptError::ERR_NAME_IS_NOT_UNIQUE); ScriptError::RegisterErrorMap(STR_ERROR_FLAT_LAND_REQUIRED, ScriptError::ERR_FLAT_LAND_REQUIRED); ScriptError::RegisterErrorMap(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION, ScriptError::ERR_LAND_SLOPED_WRONG); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_VEHICLE_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_SHIP_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_SITE_UNSUITABLE, ScriptError::ERR_SITE_UNSUITABLE); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP, ScriptError::ERR_TOO_CLOSE_TO_EDGE); ScriptError::RegisterErrorMap(STR_ERROR_STATION_TOO_SPREAD_OUT, ScriptError::ERR_STATION_TOO_SPREAD_OUT); ScriptError::RegisterErrorMapString(ScriptError::ERR_NONE, "ERR_NONE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_UNKNOWN, "ERR_UNKNOWN"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_FAILED, "ERR_PRECONDITION_FAILED"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_STRING_TOO_LONG, "ERR_PRECONDITION_STRING_TOO_LONG"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, "ERR_PRECONDITION_TOO_MANY_PARAMETERS"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_INVALID_COMPANY, "ERR_PRECONDITION_INVALID_COMPANY"); ScriptError::RegisterErrorMapString(ScriptError::ERR_NEWGRF_SUPPLIED_ERROR, "ERR_NEWGRF_SUPPLIED_ERROR"); ScriptError::RegisterErrorMapString(ScriptError::ERR_NOT_ENOUGH_CASH, "ERR_NOT_ENOUGH_CASH"); ScriptError::RegisterErrorMapString(ScriptError::ERR_LOCAL_AUTHORITY_REFUSES, "ERR_LOCAL_AUTHORITY_REFUSES"); ScriptError::RegisterErrorMapString(ScriptError::ERR_ALREADY_BUILT, "ERR_ALREADY_BUILT"); ScriptError::RegisterErrorMapString(ScriptError::ERR_AREA_NOT_CLEAR, "ERR_AREA_NOT_CLEAR"); ScriptError::RegisterErrorMapString(ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY, "ERR_OWNED_BY_ANOTHER_COMPANY"); ScriptError::RegisterErrorMapString(ScriptError::ERR_NAME_IS_NOT_UNIQUE, "ERR_NAME_IS_NOT_UNIQUE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_FLAT_LAND_REQUIRED, "ERR_FLAT_LAND_REQUIRED"); ScriptError::RegisterErrorMapString(ScriptError::ERR_LAND_SLOPED_WRONG, "ERR_LAND_SLOPED_WRONG"); ScriptError::RegisterErrorMapString(ScriptError::ERR_VEHICLE_IN_THE_WAY, "ERR_VEHICLE_IN_THE_WAY"); ScriptError::RegisterErrorMapString(ScriptError::ERR_SITE_UNSUITABLE, "ERR_SITE_UNSUITABLE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_TOO_CLOSE_TO_EDGE, "ERR_TOO_CLOSE_TO_EDGE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_STATION_TOO_SPREAD_OUT, "ERR_STATION_TOO_SPREAD_OUT"); SQAIError.DefSQStaticMethod(engine, &ScriptError::GetErrorCategory, "GetErrorCategory", 1, "."); SQAIError.DefSQStaticMethod(engine, &ScriptError::GetLastError, "GetLastError", 1, "."); SQAIError.DefSQStaticMethod(engine, &ScriptError::GetLastErrorString, "GetLastErrorString", 1, "."); SQAIError.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_gamesettings.hpp.sq0000644000000000000000000000304112627373434021437 0ustar rootroot/* $Id: ai_gamesettings.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_gamesettings.hpp" #include "../template/template_gamesettings.hpp.sq" template <> const char *GetClassName() { return "AIGameSettings"; } void SQAIGameSettings_Register(Squirrel *engine) { DefSQClass SQAIGameSettings("AIGameSettings"); SQAIGameSettings.PreRegister(engine); SQAIGameSettings.AddConstructor(engine, "x"); SQAIGameSettings.DefSQStaticMethod(engine, &ScriptGameSettings::IsValid, "IsValid", 2, ".."); SQAIGameSettings.DefSQStaticMethod(engine, &ScriptGameSettings::GetValue, "GetValue", 2, ".."); SQAIGameSettings.DefSQStaticMethod(engine, &ScriptGameSettings::IsDisabledVehicleType, "IsDisabledVehicleType", 2, ".i"); SQAIGameSettings.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_subsidylist.hpp.sq0000644000000000000000000000225412627373434021330 0ustar rootroot/* $Id: ai_subsidylist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_subsidylist.hpp" #include "../template/template_subsidylist.hpp.sq" template <> const char *GetClassName() { return "AISubsidyList"; } void SQAISubsidyList_Register(Squirrel *engine) { DefSQClass SQAISubsidyList("AISubsidyList"); SQAISubsidyList.PreRegister(engine, "AIList"); SQAISubsidyList.AddConstructor(engine, "x"); SQAISubsidyList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_cargolist.hpp.sq0000644000000000000000000000546712627373434020752 0ustar rootroot/* $Id: ai_cargolist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargolist.hpp" #include "../template/template_cargolist.hpp.sq" template <> const char *GetClassName() { return "AICargoList"; } void SQAICargoList_Register(Squirrel *engine) { DefSQClass SQAICargoList("AICargoList"); SQAICargoList.PreRegister(engine, "AIList"); SQAICargoList.AddConstructor(engine, "x"); SQAICargoList.PostRegister(engine); } template <> const char *GetClassName() { return "AICargoList_IndustryAccepting"; } void SQAICargoList_IndustryAccepting_Register(Squirrel *engine) { DefSQClass SQAICargoList_IndustryAccepting("AICargoList_IndustryAccepting"); SQAICargoList_IndustryAccepting.PreRegister(engine, "AIList"); SQAICargoList_IndustryAccepting.AddConstructor(engine, "xi"); SQAICargoList_IndustryAccepting.PostRegister(engine); } template <> const char *GetClassName() { return "AICargoList_IndustryProducing"; } void SQAICargoList_IndustryProducing_Register(Squirrel *engine) { DefSQClass SQAICargoList_IndustryProducing("AICargoList_IndustryProducing"); SQAICargoList_IndustryProducing.PreRegister(engine, "AIList"); SQAICargoList_IndustryProducing.AddConstructor(engine, "xi"); SQAICargoList_IndustryProducing.PostRegister(engine); } template <> const char *GetClassName() { return "AICargoList_StationAccepting"; } void SQAICargoList_StationAccepting_Register(Squirrel *engine) { DefSQClass SQAICargoList_StationAccepting("AICargoList_StationAccepting"); SQAICargoList_StationAccepting.PreRegister(engine, "AIList"); SQAICargoList_StationAccepting.AddConstructor(engine, "xi"); SQAICargoList_StationAccepting.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_industrytype.hpp.sq0000644000000000000000000000626112627373434021537 0ustar rootroot/* $Id: ai_industrytype.hpp.sq 24513 2012-09-08 12:14:00Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrytype.hpp" #include "../template/template_industrytype.hpp.sq" template <> const char *GetClassName() { return "AIIndustryType"; } void SQAIIndustryType_Register(Squirrel *engine) { DefSQClass SQAIIndustryType("AIIndustryType"); SQAIIndustryType.PreRegister(engine); SQAIIndustryType.AddConstructor(engine, "x"); SQAIIndustryType.DefSQConst(engine, ScriptIndustryType::INDUSTRYTYPE_UNKNOWN, "INDUSTRYTYPE_UNKNOWN"); SQAIIndustryType.DefSQConst(engine, ScriptIndustryType::INDUSTRYTYPE_TOWN, "INDUSTRYTYPE_TOWN"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsValidIndustryType, "IsValidIndustryType", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetName, "GetName", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetProducedCargo, "GetProducedCargo", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetAcceptedCargo, "GetAcceptedCargo", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsRawIndustry, "IsRawIndustry", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsProcessingIndustry, "IsProcessingIndustry", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::ProductionCanIncrease, "ProductionCanIncrease", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetConstructionCost, "GetConstructionCost", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::CanBuildIndustry, "CanBuildIndustry", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::CanProspectIndustry, "CanProspectIndustry", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::BuildIndustry, "BuildIndustry", 3, ".ii"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::ProspectIndustry, "ProspectIndustry", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsBuiltOnWater, "IsBuiltOnWater", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::HasHeliport, "HasHeliport", 2, ".i"); SQAIIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::HasDock, "HasDock", 2, ".i"); SQAIIndustryType.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_townlist.hpp.sq0000644000000000000000000000304712627373434020636 0ustar rootroot/* $Id: ai_townlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_townlist.hpp" #include "../template/template_townlist.hpp.sq" template <> const char *GetClassName() { return "AITownList"; } void SQAITownList_Register(Squirrel *engine) { DefSQClass SQAITownList("AITownList"); SQAITownList.PreRegister(engine, "AIList"); SQAITownList.AddConstructor(engine, "x"); SQAITownList.PostRegister(engine); } template <> const char *GetClassName() { return "AITownEffectList"; } void SQAITownEffectList_Register(Squirrel *engine) { DefSQClass SQAITownEffectList("AITownEffectList"); SQAITownEffectList.PreRegister(engine, "AIList"); SQAITownEffectList.AddConstructor(engine, "x"); SQAITownEffectList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_industry.hpp.sq0000644000000000000000000000773012627373434020637 0ustar rootroot/* $Id: ai_industry.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industry.hpp" #include "../template/template_industry.hpp.sq" template <> const char *GetClassName() { return "AIIndustry"; } void SQAIIndustry_Register(Squirrel *engine) { DefSQClass SQAIIndustry("AIIndustry"); SQAIIndustry.PreRegister(engine); SQAIIndustry.AddConstructor(engine, "x"); SQAIIndustry.DefSQConst(engine, ScriptIndustry::CAS_NOT_ACCEPTED, "CAS_NOT_ACCEPTED"); SQAIIndustry.DefSQConst(engine, ScriptIndustry::CAS_ACCEPTED, "CAS_ACCEPTED"); SQAIIndustry.DefSQConst(engine, ScriptIndustry::CAS_TEMP_REFUSED, "CAS_TEMP_REFUSED"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetIndustryCount, "GetIndustryCount", 1, "."); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::IsValidIndustry, "IsValidIndustry", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetIndustryID, "GetIndustryID", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetName, "GetName", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::IsCargoAccepted, "IsCargoAccepted", 3, ".ii"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetStockpiledCargo, "GetStockpiledCargo", 3, ".ii"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLastMonthProduction, "GetLastMonthProduction", 3, ".ii"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLastMonthTransported, "GetLastMonthTransported", 3, ".ii"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLastMonthTransportedPercentage, "GetLastMonthTransportedPercentage", 3, ".ii"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLocation, "GetLocation", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetAmountOfStationsAround, "GetAmountOfStationsAround", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::IsBuiltOnWater, "IsBuiltOnWater", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::HasHeliport, "HasHeliport", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetHeliportLocation, "GetHeliportLocation", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::HasDock, "HasDock", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetDockLocation, "GetDockLocation", 2, ".i"); SQAIIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetIndustryType, "GetIndustryType", 2, ".i"); SQAIIndustry.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_waypointlist.hpp.sq0000644000000000000000000000332712627373434021522 0ustar rootroot/* $Id: ai_waypointlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_waypointlist.hpp" #include "../template/template_waypointlist.hpp.sq" template <> const char *GetClassName() { return "AIWaypointList"; } void SQAIWaypointList_Register(Squirrel *engine) { DefSQClass SQAIWaypointList("AIWaypointList"); SQAIWaypointList.PreRegister(engine, "AIList"); SQAIWaypointList.AddConstructor(engine, "xi"); SQAIWaypointList.PostRegister(engine); } template <> const char *GetClassName() { return "AIWaypointList_Vehicle"; } void SQAIWaypointList_Vehicle_Register(Squirrel *engine) { DefSQClass SQAIWaypointList_Vehicle("AIWaypointList_Vehicle"); SQAIWaypointList_Vehicle.PreRegister(engine, "AIList"); SQAIWaypointList_Vehicle.AddConstructor(engine, "xi"); SQAIWaypointList_Vehicle.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_tilelist.hpp.sq0000644000000000000000000000626112627373434020605 0ustar rootroot/* $Id: ai_tilelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tilelist.hpp" #include "../template/template_tilelist.hpp.sq" template <> const char *GetClassName() { return "AITileList"; } void SQAITileList_Register(Squirrel *engine) { DefSQClass SQAITileList("AITileList"); SQAITileList.PreRegister(engine, "AIList"); SQAITileList.AddConstructor(engine, "x"); SQAITileList.DefSQMethod(engine, &ScriptTileList::AddRectangle, "AddRectangle", 3, "xii"); SQAITileList.DefSQMethod(engine, &ScriptTileList::AddTile, "AddTile", 2, "xi"); SQAITileList.DefSQMethod(engine, &ScriptTileList::RemoveRectangle, "RemoveRectangle", 3, "xii"); SQAITileList.DefSQMethod(engine, &ScriptTileList::RemoveTile, "RemoveTile", 2, "xi"); SQAITileList.PostRegister(engine); } template <> const char *GetClassName() { return "AITileList_IndustryAccepting"; } void SQAITileList_IndustryAccepting_Register(Squirrel *engine) { DefSQClass SQAITileList_IndustryAccepting("AITileList_IndustryAccepting"); SQAITileList_IndustryAccepting.PreRegister(engine, "AITileList"); SQAITileList_IndustryAccepting.AddConstructor(engine, "xii"); SQAITileList_IndustryAccepting.PostRegister(engine); } template <> const char *GetClassName() { return "AITileList_IndustryProducing"; } void SQAITileList_IndustryProducing_Register(Squirrel *engine) { DefSQClass SQAITileList_IndustryProducing("AITileList_IndustryProducing"); SQAITileList_IndustryProducing.PreRegister(engine, "AITileList"); SQAITileList_IndustryProducing.AddConstructor(engine, "xii"); SQAITileList_IndustryProducing.PostRegister(engine); } template <> const char *GetClassName() { return "AITileList_StationType"; } void SQAITileList_StationType_Register(Squirrel *engine) { DefSQClass SQAITileList_StationType("AITileList_StationType"); SQAITileList_StationType.PreRegister(engine, "AITileList"); SQAITileList_StationType.AddConstructor(engine, "xii"); SQAITileList_StationType.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_sign.hpp.sq0000644000000000000000000000371612627373434017716 0ustar rootroot/* $Id: ai_sign.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_sign.hpp" #include "../template/template_sign.hpp.sq" template <> const char *GetClassName() { return "AISign"; } void SQAISign_Register(Squirrel *engine) { DefSQClass SQAISign("AISign"); SQAISign.PreRegister(engine); SQAISign.AddConstructor(engine, "x"); SQAISign.DefSQConst(engine, ScriptSign::ERR_SIGN_BASE, "ERR_SIGN_BASE"); SQAISign.DefSQConst(engine, ScriptSign::ERR_SIGN_TOO_MANY_SIGNS, "ERR_SIGN_TOO_MANY_SIGNS"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_SIGNS, ScriptSign::ERR_SIGN_TOO_MANY_SIGNS); ScriptError::RegisterErrorMapString(ScriptSign::ERR_SIGN_TOO_MANY_SIGNS, "ERR_SIGN_TOO_MANY_SIGNS"); SQAISign.DefSQStaticMethod(engine, &ScriptSign::IsValidSign, "IsValidSign", 2, ".i"); SQAISign.DefSQStaticMethod(engine, &ScriptSign::SetName, "SetName", 3, ".i."); SQAISign.DefSQStaticMethod(engine, &ScriptSign::GetName, "GetName", 2, ".i"); SQAISign.DefSQStaticMethod(engine, &ScriptSign::GetLocation, "GetLocation", 2, ".i"); SQAISign.DefSQStaticMethod(engine, &ScriptSign::BuildSign, "BuildSign", 3, ".i."); SQAISign.DefSQStaticMethod(engine, &ScriptSign::RemoveSign, "RemoveSign", 2, ".i"); SQAISign.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_order.hpp.sq0000644000000000000000000002666412627373434020100 0ustar rootroot/* $Id: ai_order.hpp.sq 24006 2012-03-04 16:40:06Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_order.hpp" #include "../template/template_order.hpp.sq" template <> const char *GetClassName() { return "AIOrder"; } void SQAIOrder_Register(Squirrel *engine) { DefSQClass SQAIOrder("AIOrder"); SQAIOrder.PreRegister(engine); SQAIOrder.AddConstructor(engine, "x"); SQAIOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_BASE, "ERR_ORDER_BASE"); SQAIOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_TOO_MANY, "ERR_ORDER_TOO_MANY"); SQAIOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION, "ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION"); SQAIOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE, "ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_NONE, "OF_NONE"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_NON_STOP_INTERMEDIATE, "OF_NON_STOP_INTERMEDIATE"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_NON_STOP_DESTINATION, "OF_NON_STOP_DESTINATION"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_UNLOAD, "OF_UNLOAD"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_TRANSFER, "OF_TRANSFER"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_NO_UNLOAD, "OF_NO_UNLOAD"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_FULL_LOAD, "OF_FULL_LOAD"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_FULL_LOAD_ANY, "OF_FULL_LOAD_ANY"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_NO_LOAD, "OF_NO_LOAD"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_SERVICE_IF_NEEDED, "OF_SERVICE_IF_NEEDED"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_STOP_IN_DEPOT, "OF_STOP_IN_DEPOT"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_GOTO_NEAREST_DEPOT, "OF_GOTO_NEAREST_DEPOT"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_NON_STOP_FLAGS, "OF_NON_STOP_FLAGS"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_UNLOAD_FLAGS, "OF_UNLOAD_FLAGS"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_LOAD_FLAGS, "OF_LOAD_FLAGS"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_DEPOT_FLAGS, "OF_DEPOT_FLAGS"); SQAIOrder.DefSQConst(engine, ScriptOrder::OF_INVALID, "OF_INVALID"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_LOAD_PERCENTAGE, "OC_LOAD_PERCENTAGE"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_RELIABILITY, "OC_RELIABILITY"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_MAX_SPEED, "OC_MAX_SPEED"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_AGE, "OC_AGE"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_REQUIRES_SERVICE, "OC_REQUIRES_SERVICE"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_UNCONDITIONALLY, "OC_UNCONDITIONALLY"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_REMAINING_LIFETIME, "OC_REMAINING_LIFETIME"); SQAIOrder.DefSQConst(engine, ScriptOrder::OC_INVALID, "OC_INVALID"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_EQUALS, "CF_EQUALS"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_NOT_EQUALS, "CF_NOT_EQUALS"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_LESS_THAN, "CF_LESS_THAN"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_LESS_EQUALS, "CF_LESS_EQUALS"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_MORE_THAN, "CF_MORE_THAN"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_MORE_EQUALS, "CF_MORE_EQUALS"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_IS_TRUE, "CF_IS_TRUE"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_IS_FALSE, "CF_IS_FALSE"); SQAIOrder.DefSQConst(engine, ScriptOrder::CF_INVALID, "CF_INVALID"); SQAIOrder.DefSQConst(engine, ScriptOrder::ORDER_CURRENT, "ORDER_CURRENT"); SQAIOrder.DefSQConst(engine, ScriptOrder::ORDER_INVALID, "ORDER_INVALID"); SQAIOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_NEAR, "STOPLOCATION_NEAR"); SQAIOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_MIDDLE, "STOPLOCATION_MIDDLE"); SQAIOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_FAR, "STOPLOCATION_FAR"); SQAIOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_INVALID, "STOPLOCATION_INVALID"); ScriptError::RegisterErrorMap(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS, ScriptOrder::ERR_ORDER_TOO_MANY); ScriptError::RegisterErrorMap(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION, ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE, ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE); ScriptError::RegisterErrorMapString(ScriptOrder::ERR_ORDER_TOO_MANY, "ERR_ORDER_TOO_MANY"); ScriptError::RegisterErrorMapString(ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION, "ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION"); ScriptError::RegisterErrorMapString(ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE, "ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsValidVehicleOrder, "IsValidVehicleOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsGotoStationOrder, "IsGotoStationOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsGotoDepotOrder, "IsGotoDepotOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsGotoWaypointOrder, "IsGotoWaypointOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsConditionalOrder, "IsConditionalOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsVoidOrder, "IsVoidOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsRefitOrder, "IsRefitOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsCurrentOrderPartOfOrderList, "IsCurrentOrderPartOfOrderList", 2, ".i"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::ResolveOrderPosition, "ResolveOrderPosition", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::AreOrderFlagsValid, "AreOrderFlagsValid", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::IsValidConditionalOrder, "IsValidConditionalOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCount, "GetOrderCount", 2, ".i"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderDestination, "GetOrderDestination", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderFlags, "GetOrderFlags", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderJumpTo, "GetOrderJumpTo", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCondition, "GetOrderCondition", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCompareFunction, "GetOrderCompareFunction", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCompareValue, "GetOrderCompareValue", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetStopLocation, "GetStopLocation", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderRefit, "GetOrderRefit", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SetOrderJumpTo, "SetOrderJumpTo", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SetOrderCondition, "SetOrderCondition", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SetOrderCompareFunction, "SetOrderCompareFunction", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SetOrderCompareValue, "SetOrderCompareValue", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SetStopLocation, "SetStopLocation", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SetOrderRefit, "SetOrderRefit", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::AppendOrder, "AppendOrder", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::AppendConditionalOrder, "AppendConditionalOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::InsertOrder, "InsertOrder", 5, ".iiii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::InsertConditionalOrder, "InsertConditionalOrder", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::RemoveOrder, "RemoveOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SetOrderFlags, "SetOrderFlags", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::MoveOrder, "MoveOrder", 4, ".iii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::SkipToOrder, "SkipToOrder", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::CopyOrders, "CopyOrders", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::ShareOrders, "ShareOrders", 3, ".ii"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::UnshareOrders, "UnshareOrders", 2, ".i"); SQAIOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderDistance, "GetOrderDistance", 4, ".iii"); SQAIOrder.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_list.hpp.sq0000644000000000000000000001040112627373434017716 0ustar rootroot/* $Id: ai_list.hpp.sq 26894 2014-09-21 16:25:15Z fonsinchen $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_list.hpp" #include "../template/template_list.hpp.sq" template <> const char *GetClassName() { return "AIList"; } void SQAIList_Register(Squirrel *engine) { DefSQClass SQAIList("AIList"); SQAIList.PreRegister(engine); SQAIList.AddConstructor(engine, "x"); SQAIList.DefSQConst(engine, ScriptList::SORT_BY_VALUE, "SORT_BY_VALUE"); SQAIList.DefSQConst(engine, ScriptList::SORT_BY_ITEM, "SORT_BY_ITEM"); SQAIList.DefSQConst(engine, ScriptList::SORT_ASCENDING, "SORT_ASCENDING"); SQAIList.DefSQConst(engine, ScriptList::SORT_DESCENDING, "SORT_DESCENDING"); SQAIList.DefSQMethod(engine, &ScriptList::AddItem, "AddItem", 3, "xii"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveItem, "RemoveItem", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::Clear, "Clear", 1, "x"); SQAIList.DefSQMethod(engine, &ScriptList::HasItem, "HasItem", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::Begin, "Begin", 1, "x"); SQAIList.DefSQMethod(engine, &ScriptList::Next, "Next", 1, "x"); SQAIList.DefSQMethod(engine, &ScriptList::IsEmpty, "IsEmpty", 1, "x"); SQAIList.DefSQMethod(engine, &ScriptList::IsEnd, "IsEnd", 1, "x"); SQAIList.DefSQMethod(engine, &ScriptList::Count, "Count", 1, "x"); SQAIList.DefSQMethod(engine, &ScriptList::GetValue, "GetValue", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::SetValue, "SetValue", 3, "xii"); SQAIList.DefSQMethod(engine, &ScriptList::Sort, "Sort", 3, "xib"); SQAIList.DefSQMethod(engine, &ScriptList::AddList, "AddList", 2, "xx"); SQAIList.DefSQMethod(engine, &ScriptList::SwapList, "SwapList", 2, "xx"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveAboveValue, "RemoveAboveValue", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveBelowValue, "RemoveBelowValue", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveBetweenValue, "RemoveBetweenValue", 3, "xii"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveValue, "RemoveValue", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveTop, "RemoveTop", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveBottom, "RemoveBottom", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::RemoveList, "RemoveList", 2, "xx"); SQAIList.DefSQMethod(engine, &ScriptList::KeepAboveValue, "KeepAboveValue", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::KeepBelowValue, "KeepBelowValue", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::KeepBetweenValue, "KeepBetweenValue", 3, "xii"); SQAIList.DefSQMethod(engine, &ScriptList::KeepValue, "KeepValue", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::KeepTop, "KeepTop", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::KeepBottom, "KeepBottom", 2, "xi"); SQAIList.DefSQMethod(engine, &ScriptList::KeepList, "KeepList", 2, "xx"); SQAIList.DefSQAdvancedMethod(engine, &ScriptList::_get, "_get"); SQAIList.DefSQAdvancedMethod(engine, &ScriptList::_set, "_set"); SQAIList.DefSQAdvancedMethod(engine, &ScriptList::_nexti, "_nexti"); SQAIList.DefSQAdvancedMethod(engine, &ScriptList::Valuate, "Valuate"); SQAIList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_station.hpp.sq0000644000000000000000000001426312627373434020436 0ustar rootroot/* $Id: ai_station.hpp.sq 26892 2014-09-21 16:20:14Z fonsinchen $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_station.hpp" #include "../template/template_station.hpp.sq" template <> const char *GetClassName() { return "AIStation"; } void SQAIStation_Register(Squirrel *engine) { DefSQClass SQAIStation("AIStation"); SQAIStation.PreRegister(engine, "AIBaseStation"); SQAIStation.AddConstructor(engine, "x"); SQAIStation.DefSQConst(engine, ScriptStation::ERR_STATION_BASE, "ERR_STATION_BASE"); SQAIStation.DefSQConst(engine, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, "ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION"); SQAIStation.DefSQConst(engine, ScriptStation::ERR_STATION_TOO_MANY_STATIONS, "ERR_STATION_TOO_MANY_STATIONS"); SQAIStation.DefSQConst(engine, ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN, "ERR_STATION_TOO_MANY_STATIONS_IN_TOWN"); SQAIStation.DefSQConst(engine, ScriptStation::STATION_TRAIN, "STATION_TRAIN"); SQAIStation.DefSQConst(engine, ScriptStation::STATION_TRUCK_STOP, "STATION_TRUCK_STOP"); SQAIStation.DefSQConst(engine, ScriptStation::STATION_BUS_STOP, "STATION_BUS_STOP"); SQAIStation.DefSQConst(engine, ScriptStation::STATION_AIRPORT, "STATION_AIRPORT"); SQAIStation.DefSQConst(engine, ScriptStation::STATION_DOCK, "STATION_DOCK"); SQAIStation.DefSQConst(engine, ScriptStation::STATION_ANY, "STATION_ANY"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_STATIONS_LOADING, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_TRUCK_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_BUS_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT, ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, "ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION"); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_MANY_STATIONS, "ERR_STATION_TOO_MANY_STATIONS"); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN, "ERR_STATION_TOO_MANY_STATIONS_IN_TOWN"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::IsValidStation, "IsValidStation", 2, ".i"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetStationID, "GetStationID", 2, ".i"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaiting, "GetCargoWaiting", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaitingFrom, "GetCargoWaitingFrom", 4, ".iii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaitingVia, "GetCargoWaitingVia", 4, ".iii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaitingFromVia, "GetCargoWaitingFromVia", 5, ".iiii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlanned, "GetCargoPlanned", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlannedFrom, "GetCargoPlannedFrom", 4, ".iii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlannedVia, "GetCargoPlannedVia", 4, ".iii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlannedFromVia, "GetCargoPlannedFromVia", 5, ".iiii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::HasCargoRating, "HasCargoRating", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoRating, "GetCargoRating", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetCoverageRadius, "GetCoverageRadius", 2, ".i"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetStationCoverageRadius, "GetStationCoverageRadius", 2, ".i"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::IsWithinTownInfluence, "IsWithinTownInfluence", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::HasStationType, "HasStationType", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::HasRoadType, "HasRoadType", 3, ".ii"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::GetNearestTown, "GetNearestTown", 2, ".i"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::IsAirportClosed, "IsAirportClosed", 2, ".i"); SQAIStation.DefSQStaticMethod(engine, &ScriptStation::OpenCloseAirport, "OpenCloseAirport", 2, ".i"); SQAIStation.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_depotlist.hpp.sq0000644000000000000000000000227312627373434020762 0ustar rootroot/* $Id: ai_depotlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_depotlist.hpp" #include "../template/template_depotlist.hpp.sq" template <> const char *GetClassName() { return "AIDepotList"; } void SQAIDepotList_Register(Squirrel *engine) { DefSQClass SQAIDepotList("AIDepotList"); SQAIDepotList.PreRegister(engine, "AIList"); SQAIDepotList.AddConstructor(engine, "xi"); SQAIDepotList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_engine.hpp.sq0000644000000000000000000000764012627373434020223 0ustar rootroot/* $Id: ai_engine.hpp.sq 23506 2011-12-13 00:43:59Z michi_cc $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_engine.hpp" #include "../template/template_engine.hpp.sq" template <> const char *GetClassName() { return "AIEngine"; } void SQAIEngine_Register(Squirrel *engine) { DefSQClass SQAIEngine("AIEngine"); SQAIEngine.PreRegister(engine); SQAIEngine.AddConstructor(engine, "x"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsValidEngine, "IsValidEngine", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsBuildable, "IsBuildable", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetName, "GetName", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetCargoType, "GetCargoType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRefitCargo, "CanRefitCargo", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::CanPullCargo, "CanPullCargo", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetCapacity, "GetCapacity", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetReliability, "GetReliability", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetPrice, "GetPrice", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaxAge, "GetMaxAge", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRunningCost, "GetRunningCost", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetPower, "GetPower", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetWeight, "GetWeight", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaxTractiveEffort, "GetMaxTractiveEffort", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetDesignDate, "GetDesignDate", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetVehicleType, "GetVehicleType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsWagon, "IsWagon", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRail, "CanRunOnRail", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRail, "HasPowerOnRail", 3, ".ii"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRoadType, "GetRoadType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRailType, "GetRailType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::IsArticulated, "IsArticulated", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetPlaneType, "GetPlaneType", 2, ".i"); SQAIEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaximumOrderDistance, "GetMaximumOrderDistance", 2, ".i"); SQAIEngine.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_basestation.hpp.sq0000644000000000000000000000402612627373434021265 0ustar rootroot/* $Id: ai_basestation.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_basestation.hpp" #include "../template/template_basestation.hpp.sq" template <> const char *GetClassName() { return "AIBaseStation"; } void SQAIBaseStation_Register(Squirrel *engine) { DefSQClass SQAIBaseStation("AIBaseStation"); SQAIBaseStation.PreRegister(engine); SQAIBaseStation.AddConstructor(engine, "x"); SQAIBaseStation.DefSQConst(engine, ScriptBaseStation::STATION_NEW, "STATION_NEW"); SQAIBaseStation.DefSQConst(engine, ScriptBaseStation::STATION_JOIN_ADJACENT, "STATION_JOIN_ADJACENT"); SQAIBaseStation.DefSQConst(engine, ScriptBaseStation::STATION_INVALID, "STATION_INVALID"); SQAIBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::IsValidBaseStation, "IsValidBaseStation", 2, ".i"); SQAIBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::GetName, "GetName", 2, ".i"); SQAIBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::SetName, "SetName", 3, ".i."); SQAIBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::GetLocation, "GetLocation", 2, ".i"); SQAIBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::GetConstructionDate, "GetConstructionDate", 2, ".i"); SQAIBaseStation.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_tunnel.hpp.sq0000644000000000000000000000603712627373434020262 0ustar rootroot/* $Id: ai_tunnel.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tunnel.hpp" #include "../template/template_tunnel.hpp.sq" template <> const char *GetClassName() { return "AITunnel"; } void SQAITunnel_Register(Squirrel *engine) { DefSQClass SQAITunnel("AITunnel"); SQAITunnel.PreRegister(engine); SQAITunnel.AddConstructor(engine, "x"); SQAITunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_BASE, "ERR_TUNNEL_BASE"); SQAITunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_CANNOT_BUILD_ON_WATER, "ERR_TUNNEL_CANNOT_BUILD_ON_WATER"); SQAITunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_START_SITE_UNSUITABLE, "ERR_TUNNEL_START_SITE_UNSUITABLE"); SQAITunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY, "ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY"); SQAITunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_END_SITE_UNSUITABLE, "ERR_TUNNEL_END_SITE_UNSUITABLE"); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUILD_ON_WATER, ScriptTunnel::ERR_TUNNEL_CANNOT_BUILD_ON_WATER); ScriptError::RegisterErrorMap(STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL, ScriptTunnel::ERR_TUNNEL_START_SITE_UNSUITABLE); ScriptError::RegisterErrorMap(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY, ScriptTunnel::ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_UNABLE_TO_EXCAVATE_LAND, ScriptTunnel::ERR_TUNNEL_END_SITE_UNSUITABLE); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_CANNOT_BUILD_ON_WATER, "ERR_TUNNEL_CANNOT_BUILD_ON_WATER"); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_START_SITE_UNSUITABLE, "ERR_TUNNEL_START_SITE_UNSUITABLE"); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY, "ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY"); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_END_SITE_UNSUITABLE, "ERR_TUNNEL_END_SITE_UNSUITABLE"); SQAITunnel.DefSQStaticMethod(engine, &ScriptTunnel::IsTunnelTile, "IsTunnelTile", 2, ".i"); SQAITunnel.DefSQStaticMethod(engine, &ScriptTunnel::GetOtherTunnelEnd, "GetOtherTunnelEnd", 2, ".i"); SQAITunnel.DefSQStaticMethod(engine, &ScriptTunnel::BuildTunnel, "BuildTunnel", 3, ".ii"); SQAITunnel.DefSQStaticMethod(engine, &ScriptTunnel::RemoveTunnel, "RemoveTunnel", 2, ".i"); SQAITunnel.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_railtypelist.hpp.sq0000644000000000000000000000227112627373434021476 0ustar rootroot/* $Id: ai_railtypelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_railtypelist.hpp" #include "../template/template_railtypelist.hpp.sq" template <> const char *GetClassName() { return "AIRailTypeList"; } void SQAIRailTypeList_Register(Squirrel *engine) { DefSQClass SQAIRailTypeList("AIRailTypeList"); SQAIRailTypeList.PreRegister(engine, "AIList"); SQAIRailTypeList.AddConstructor(engine, "x"); SQAIRailTypeList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_industrylist.hpp.sq0000644000000000000000000000444312627373434021531 0ustar rootroot/* $Id: ai_industrylist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrylist.hpp" #include "../template/template_industrylist.hpp.sq" template <> const char *GetClassName() { return "AIIndustryList"; } void SQAIIndustryList_Register(Squirrel *engine) { DefSQClass SQAIIndustryList("AIIndustryList"); SQAIIndustryList.PreRegister(engine, "AIList"); SQAIIndustryList.AddConstructor(engine, "x"); SQAIIndustryList.PostRegister(engine); } template <> const char *GetClassName() { return "AIIndustryList_CargoAccepting"; } void SQAIIndustryList_CargoAccepting_Register(Squirrel *engine) { DefSQClass SQAIIndustryList_CargoAccepting("AIIndustryList_CargoAccepting"); SQAIIndustryList_CargoAccepting.PreRegister(engine, "AIList"); SQAIIndustryList_CargoAccepting.AddConstructor(engine, "xi"); SQAIIndustryList_CargoAccepting.PostRegister(engine); } template <> const char *GetClassName() { return "AIIndustryList_CargoProducing"; } void SQAIIndustryList_CargoProducing_Register(Squirrel *engine) { DefSQClass SQAIIndustryList_CargoProducing("AIIndustryList_CargoProducing"); SQAIIndustryList_CargoProducing.PreRegister(engine, "AIList"); SQAIIndustryList_CargoProducing.AddConstructor(engine, "xi"); SQAIIndustryList_CargoProducing.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_marine.hpp.sq0000644000000000000000000000730712627373434020231 0ustar rootroot/* $Id: ai_marine.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_marine.hpp" #include "../template/template_marine.hpp.sq" template <> const char *GetClassName() { return "AIMarine"; } void SQAIMarine_Register(Squirrel *engine) { DefSQClass SQAIMarine("AIMarine"); SQAIMarine.PreRegister(engine); SQAIMarine.AddConstructor(engine, "x"); SQAIMarine.DefSQConst(engine, ScriptMarine::ERR_MARINE_BASE, "ERR_MARINE_BASE"); SQAIMarine.DefSQConst(engine, ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER, "ERR_MARINE_MUST_BE_BUILT_ON_WATER"); SQAIMarine.DefSQConst(engine, ScriptMarine::BT_DOCK, "BT_DOCK"); SQAIMarine.DefSQConst(engine, ScriptMarine::BT_DEPOT, "BT_DEPOT"); SQAIMarine.DefSQConst(engine, ScriptMarine::BT_BUOY, "BT_BUOY"); ScriptError::RegisterErrorMap(STR_ERROR_MUST_BE_BUILT_ON_WATER, ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER); ScriptError::RegisterErrorMapString(ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER, "ERR_MARINE_MUST_BE_BUILT_ON_WATER"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::IsWaterDepotTile, "IsWaterDepotTile", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::IsDockTile, "IsDockTile", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::IsBuoyTile, "IsBuoyTile", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::IsLockTile, "IsLockTile", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::IsCanalTile, "IsCanalTile", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::AreWaterTilesConnected, "AreWaterTilesConnected", 3, ".ii"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildWaterDepot, "BuildWaterDepot", 3, ".ii"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildDock, "BuildDock", 3, ".ii"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildBuoy, "BuildBuoy", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildLock, "BuildLock", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildCanal, "BuildCanal", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveWaterDepot, "RemoveWaterDepot", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveDock, "RemoveDock", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveBuoy, "RemoveBuoy", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveLock, "RemoveLock", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveCanal, "RemoveCanal", 2, ".i"); SQAIMarine.DefSQStaticMethod(engine, &ScriptMarine::GetBuildCost, "GetBuildCost", 2, ".i"); SQAIMarine.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_map.hpp.sq0000644000000000000000000000425612627373434017533 0ustar rootroot/* $Id: ai_map.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_map.hpp" #include "../template/template_map.hpp.sq" template <> const char *GetClassName() { return "AIMap"; } void SQAIMap_Register(Squirrel *engine) { DefSQClass SQAIMap("AIMap"); SQAIMap.PreRegister(engine); SQAIMap.AddConstructor(engine, "x"); SQAIMap.DefSQConst(engine, ScriptMap::TILE_INVALID, "TILE_INVALID"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::IsValidTile, "IsValidTile", 2, ".i"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::GetMapSize, "GetMapSize", 1, "."); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::GetMapSizeX, "GetMapSizeX", 1, "."); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::GetMapSizeY, "GetMapSizeY", 1, "."); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::GetTileX, "GetTileX", 2, ".i"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::GetTileY, "GetTileY", 2, ".i"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::GetTileIndex, "GetTileIndex", 3, ".ii"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::DistanceManhattan, "DistanceManhattan", 3, ".ii"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::DistanceMax, "DistanceMax", 3, ".ii"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::DistanceSquare, "DistanceSquare", 3, ".ii"); SQAIMap.DefSQStaticMethod(engine, &ScriptMap::DistanceFromEdge, "DistanceFromEdge", 2, ".i"); SQAIMap.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_waypoint.hpp.sq0000644000000000000000000000532112627373434020622 0ustar rootroot/* $Id: ai_waypoint.hpp.sq 23521 2011-12-15 18:40:15Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_waypoint.hpp" #include "../template/template_waypoint.hpp.sq" template <> const char *GetClassName() { return "AIWaypoint"; } void SQAIWaypoint_Register(Squirrel *engine) { DefSQClass SQAIWaypoint("AIWaypoint"); SQAIWaypoint.PreRegister(engine, "AIBaseStation"); SQAIWaypoint.AddConstructor(engine, "x"); SQAIWaypoint.DefSQConst(engine, ScriptWaypoint::ERR_WAYPOINT_BASE, "ERR_WAYPOINT_BASE"); SQAIWaypoint.DefSQConst(engine, ScriptWaypoint::ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT, "ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT"); SQAIWaypoint.DefSQConst(engine, ScriptWaypoint::ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS, "ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS"); SQAIWaypoint.DefSQConst(engine, ScriptWaypoint::WAYPOINT_RAIL, "WAYPOINT_RAIL"); SQAIWaypoint.DefSQConst(engine, ScriptWaypoint::WAYPOINT_BUOY, "WAYPOINT_BUOY"); SQAIWaypoint.DefSQConst(engine, ScriptWaypoint::WAYPOINT_ANY, "WAYPOINT_ANY"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT, ScriptWaypoint::ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT); ScriptError::RegisterErrorMap(STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING, ScriptWaypoint::ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS); ScriptError::RegisterErrorMapString(ScriptWaypoint::ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT, "ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT"); ScriptError::RegisterErrorMapString(ScriptWaypoint::ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS, "ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS"); SQAIWaypoint.DefSQStaticMethod(engine, &ScriptWaypoint::IsValidWaypoint, "IsValidWaypoint", 2, ".i"); SQAIWaypoint.DefSQStaticMethod(engine, &ScriptWaypoint::GetWaypointID, "GetWaypointID", 2, ".i"); SQAIWaypoint.DefSQStaticMethod(engine, &ScriptWaypoint::HasWaypointType, "HasWaypointType", 3, ".ii"); SQAIWaypoint.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_enginelist.hpp.sq0000644000000000000000000000230712627373434021112 0ustar rootroot/* $Id: ai_enginelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_enginelist.hpp" #include "../template/template_enginelist.hpp.sq" template <> const char *GetClassName() { return "AIEngineList"; } void SQAIEngineList_Register(Squirrel *engine) { DefSQClass SQAIEngineList("AIEngineList"); SQAIEngineList.PreRegister(engine, "AIList"); SQAIEngineList.AddConstructor(engine, "xi"); SQAIEngineList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_company.hpp.sq0000644000000000000000000001237312627373434020423 0ustar rootroot/* $Id: ai_company.hpp.sq 23521 2011-12-15 18:40:15Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_company.hpp" #include "../template/template_company.hpp.sq" template <> const char *GetClassName() { return "AICompany"; } void SQAICompany_Register(Squirrel *engine) { DefSQClass SQAICompany("AICompany"); SQAICompany.PreRegister(engine); SQAICompany.AddConstructor(engine, "x"); SQAICompany.DefSQConst(engine, ScriptCompany::CURRENT_QUARTER, "CURRENT_QUARTER"); SQAICompany.DefSQConst(engine, ScriptCompany::EARLIEST_QUARTER, "EARLIEST_QUARTER"); SQAICompany.DefSQConst(engine, ScriptCompany::COMPANY_FIRST, "COMPANY_FIRST"); SQAICompany.DefSQConst(engine, ScriptCompany::COMPANY_LAST, "COMPANY_LAST"); SQAICompany.DefSQConst(engine, ScriptCompany::COMPANY_INVALID, "COMPANY_INVALID"); SQAICompany.DefSQConst(engine, ScriptCompany::COMPANY_SELF, "COMPANY_SELF"); SQAICompany.DefSQConst(engine, ScriptCompany::GENDER_MALE, "GENDER_MALE"); SQAICompany.DefSQConst(engine, ScriptCompany::GENDER_FEMALE, "GENDER_FEMALE"); SQAICompany.DefSQConst(engine, ScriptCompany::GENDER_INVALID, "GENDER_INVALID"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::ResolveCompanyID, "ResolveCompanyID", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::IsMine, "IsMine", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetName, "SetName", 2, ".."); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetName, "GetName", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetPresidentName, "SetPresidentName", 2, ".."); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetPresidentName, "GetPresidentName", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetPresidentGender, "SetPresidentGender", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetPresidentGender, "GetPresidentGender", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetLoanAmount, "SetLoanAmount", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetMinimumLoanAmount, "SetMinimumLoanAmount", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetLoanAmount, "GetLoanAmount", 1, "."); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetMaxLoanAmount, "GetMaxLoanAmount", 1, "."); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetLoanInterval, "GetLoanInterval", 1, "."); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetBankBalance, "GetBankBalance", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyIncome, "GetQuarterlyIncome", 3, ".ii"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyExpenses, "GetQuarterlyExpenses", 3, ".ii"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyCargoDelivered, "GetQuarterlyCargoDelivered", 3, ".ii"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyPerformanceRating, "GetQuarterlyPerformanceRating", 3, ".ii"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyCompanyValue, "GetQuarterlyCompanyValue", 3, ".ii"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::BuildCompanyHQ, "BuildCompanyHQ", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetCompanyHQ, "GetCompanyHQ", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetAutoRenewStatus, "SetAutoRenewStatus", 2, ".b"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetAutoRenewStatus, "GetAutoRenewStatus", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetAutoRenewMonths, "SetAutoRenewMonths", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetAutoRenewMonths, "GetAutoRenewMonths", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::SetAutoRenewMoney, "SetAutoRenewMoney", 2, ".i"); SQAICompany.DefSQStaticMethod(engine, &ScriptCompany::GetAutoRenewMoney, "GetAutoRenewMoney", 2, ".i"); SQAICompany.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_road.hpp.sq0000644000000000000000000001625712627373434017707 0ustar rootroot/* $Id: ai_road.hpp.sq 23416 2011-12-03 23:40:57Z michi_cc $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_road.hpp" #include "../template/template_road.hpp.sq" template <> const char *GetClassName() { return "AIRoad"; } void SQAIRoad_Register(Squirrel *engine) { DefSQClass SQAIRoad("AIRoad"); SQAIRoad.PreRegister(engine); SQAIRoad.AddConstructor(engine, "x"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_BASE, "ERR_ROAD_BASE"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_ROAD, "ROADTYPE_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_TRAM, "ROADTYPE_TRAM"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_INVALID, "ROADTYPE_INVALID"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_BUS, "ROADVEHTYPE_BUS"); SQAIRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_TRUCK, "ROADVEHTYPE_TRUCK"); SQAIRoad.DefSQConst(engine, ScriptRoad::BT_ROAD, "BT_ROAD"); SQAIRoad.DefSQConst(engine, ScriptRoad::BT_DEPOT, "BT_DEPOT"); SQAIRoad.DefSQConst(engine, ScriptRoad::BT_BUS_STOP, "BT_BUS_STOP"); SQAIRoad.DefSQConst(engine, ScriptRoad::BT_TRUCK_STOP, "BT_TRUCK_STOP"); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_WORKS_IN_PROGRESS, ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_DIRECTION, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadVehicleTypeForCargo, "GetRoadVehicleTypeForCargo", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTile, "IsRoadTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadDepotTile, "IsRoadDepotTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadStationTile, "IsRoadStationTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsDriveThroughRoadStationTile, "IsDriveThroughRoadStationTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTypeAvailable, "IsRoadTypeAvailable", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetCurrentRoadType, "GetCurrentRoadType", 1, "."); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::SetCurrentRoadType, "SetCurrentRoadType", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::HasRoadType, "HasRoadType", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::AreRoadTilesConnected, "AreRoadTilesConnected", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadParts, "CanBuildConnectedRoadParts", 5, ".iaii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadPartsHere, "CanBuildConnectedRoadPartsHere", 4, ".iii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetNeighbourRoadCount, "GetNeighbourRoadCount", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadDepotFrontTile, "GetRoadDepotFrontTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadStationFrontTile, "GetRoadStationFrontTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetDriveThroughBackTile, "GetDriveThroughBackTile", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoad, "BuildRoad", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildOneWayRoad, "BuildOneWayRoad", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoadFull, "BuildRoadFull", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildOneWayRoadFull, "BuildOneWayRoadFull", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoadDepot, "BuildRoadDepot", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoadStation, "BuildRoadStation", 5, ".iiii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildDriveThroughRoadStation, "BuildDriveThroughRoadStation", 5, ".iiii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoad, "RemoveRoad", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadFull, "RemoveRoadFull", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadDepot, "RemoveRoadDepot", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadStation, "RemoveRoadStation", 2, ".i"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetBuildCost, "GetBuildCost", 3, ".ii"); SQAIRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQAIRoad.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_tile.hpp.sq0000644000000000000000000002407312627373434017712 0ustar rootroot/* $Id: ai_tile.hpp.sq 25213 2013-04-30 17:16:32Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tile.hpp" #include "../template/template_tile.hpp.sq" template <> const char *GetClassName() { return "AITile"; } void SQAITile_Register(Squirrel *engine) { DefSQClass SQAITile("AITile"); SQAITile.PreRegister(engine); SQAITile.AddConstructor(engine, "x"); SQAITile.DefSQConst(engine, ScriptTile::ERR_TILE_BASE, "ERR_TILE_BASE"); SQAITile.DefSQConst(engine, ScriptTile::ERR_TILE_TOO_HIGH, "ERR_TILE_TOO_HIGH"); SQAITile.DefSQConst(engine, ScriptTile::ERR_TILE_TOO_LOW, "ERR_TILE_TOO_LOW"); SQAITile.DefSQConst(engine, ScriptTile::ERR_AREA_ALREADY_FLAT, "ERR_AREA_ALREADY_FLAT"); SQAITile.DefSQConst(engine, ScriptTile::ERR_EXCAVATION_WOULD_DAMAGE, "ERR_EXCAVATION_WOULD_DAMAGE"); SQAITile.DefSQConst(engine, ScriptTile::CORNER_W, "CORNER_W"); SQAITile.DefSQConst(engine, ScriptTile::CORNER_S, "CORNER_S"); SQAITile.DefSQConst(engine, ScriptTile::CORNER_E, "CORNER_E"); SQAITile.DefSQConst(engine, ScriptTile::CORNER_N, "CORNER_N"); SQAITile.DefSQConst(engine, ScriptTile::CORNER_INVALID, "CORNER_INVALID"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_FLAT, "SLOPE_FLAT"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_W, "SLOPE_W"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_S, "SLOPE_S"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_E, "SLOPE_E"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_N, "SLOPE_N"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_STEEP, "SLOPE_STEEP"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_NW, "SLOPE_NW"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_SW, "SLOPE_SW"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_SE, "SLOPE_SE"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_NE, "SLOPE_NE"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_EW, "SLOPE_EW"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_NS, "SLOPE_NS"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_ELEVATED, "SLOPE_ELEVATED"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_NWS, "SLOPE_NWS"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_WSE, "SLOPE_WSE"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_SEN, "SLOPE_SEN"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_ENW, "SLOPE_ENW"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_W, "SLOPE_STEEP_W"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_S, "SLOPE_STEEP_S"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_E, "SLOPE_STEEP_E"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_N, "SLOPE_STEEP_N"); SQAITile.DefSQConst(engine, ScriptTile::SLOPE_INVALID, "SLOPE_INVALID"); SQAITile.DefSQConst(engine, ScriptTile::TRANSPORT_RAIL, "TRANSPORT_RAIL"); SQAITile.DefSQConst(engine, ScriptTile::TRANSPORT_ROAD, "TRANSPORT_ROAD"); SQAITile.DefSQConst(engine, ScriptTile::TRANSPORT_WATER, "TRANSPORT_WATER"); SQAITile.DefSQConst(engine, ScriptTile::TRANSPORT_AIR, "TRANSPORT_AIR"); SQAITile.DefSQConst(engine, ScriptTile::TRANSPORT_INVALID, "TRANSPORT_INVALID"); SQAITile.DefSQConst(engine, ScriptTile::BT_FOUNDATION, "BT_FOUNDATION"); SQAITile.DefSQConst(engine, ScriptTile::BT_TERRAFORM, "BT_TERRAFORM"); SQAITile.DefSQConst(engine, ScriptTile::BT_BUILD_TREES, "BT_BUILD_TREES"); SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_GRASS, "BT_CLEAR_GRASS"); SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_ROUGH, "BT_CLEAR_ROUGH"); SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_ROCKY, "BT_CLEAR_ROCKY"); SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_FIELDS, "BT_CLEAR_FIELDS"); SQAITile.DefSQConst(engine, ScriptTile::BT_CLEAR_HOUSE, "BT_CLEAR_HOUSE"); SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_NORMAL, "TERRAIN_NORMAL"); SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_DESERT, "TERRAIN_DESERT"); SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_RAINFOREST, "TERRAIN_RAINFOREST"); SQAITile.DefSQConst(engine, ScriptTile::TERRAIN_SNOW, "TERRAIN_SNOW"); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_HIGH); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_LOW); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_LEVELLED, ScriptTile::ERR_AREA_ALREADY_FLAT); ScriptError::RegisterErrorMap(STR_ERROR_EXCAVATION_WOULD_DAMAGE, ScriptTile::ERR_EXCAVATION_WOULD_DAMAGE); ScriptError::RegisterErrorMapString(ScriptTile::ERR_TILE_TOO_HIGH, "ERR_TILE_TOO_HIGH"); ScriptError::RegisterErrorMapString(ScriptTile::ERR_TILE_TOO_LOW, "ERR_TILE_TOO_LOW"); ScriptError::RegisterErrorMapString(ScriptTile::ERR_AREA_ALREADY_FLAT, "ERR_AREA_ALREADY_FLAT"); ScriptError::RegisterErrorMapString(ScriptTile::ERR_EXCAVATION_WOULD_DAMAGE, "ERR_EXCAVATION_WOULD_DAMAGE"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsBuildable, "IsBuildable", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsBuildableRectangle, "IsBuildableRectangle", 4, ".iii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsWaterTile, "IsWaterTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsCoastTile, "IsCoastTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsStationTile, "IsStationTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsSteepSlope, "IsSteepSlope", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsHalftileSlope, "IsHalftileSlope", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::HasTreeOnTile, "HasTreeOnTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsFarmTile, "IsFarmTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsRockTile, "IsRockTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsRoughTile, "IsRoughTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsSnowTile, "IsSnowTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsDesertTile, "IsDesertTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetTerrainType, "GetTerrainType", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetSlope, "GetSlope", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetComplementSlope, "GetComplementSlope", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetMinHeight, "GetMinHeight", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetMaxHeight, "GetMaxHeight", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetCornerHeight, "GetCornerHeight", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetOwner, "GetOwner", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::HasTransportType, "HasTransportType", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetCargoAcceptance, "GetCargoAcceptance", 6, ".iiiii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetCargoProduction, "GetCargoProduction", 6, ".iiiii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::RaiseTile, "RaiseTile", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::LowerTile, "LowerTile", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::LevelTiles, "LevelTiles", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::DemolishTile, "DemolishTile", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::PlantTree, "PlantTree", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::PlantTreeRectangle, "PlantTreeRectangle", 4, ".iii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::IsWithinTownInfluence, "IsWithinTownInfluence", 3, ".ii"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetTownAuthority, "GetTownAuthority", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetClosestTown, "GetClosestTown", 2, ".i"); SQAITile.DefSQStaticMethod(engine, &ScriptTile::GetBuildCost, "GetBuildCost", 2, ".i"); SQAITile.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_stationlist.hpp.sq0000644000000000000000000002236312627373434021332 0ustar rootroot/* $Id: ai_stationlist.hpp.sq 26893 2014-09-21 16:20:48Z fonsinchen $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_stationlist.hpp" #include "../template/template_stationlist.hpp.sq" template <> const char *GetClassName() { return "AIStationList"; } void SQAIStationList_Register(Squirrel *engine) { DefSQClass SQAIStationList("AIStationList"); SQAIStationList.PreRegister(engine, "AIList"); SQAIStationList.AddConstructor(engine, "xi"); SQAIStationList.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_Cargo"; } void SQAIStationList_Cargo_Register(Squirrel *engine) { DefSQClass SQAIStationList_Cargo("AIStationList_Cargo"); SQAIStationList_Cargo.PreRegister(engine, "AIList"); SQAIStationList_Cargo.AddConstructor(engine, "xiiiii"); SQAIStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_BY_FROM, "CS_BY_FROM"); SQAIStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_VIA_BY_FROM, "CS_VIA_BY_FROM"); SQAIStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_BY_VIA, "CS_BY_VIA"); SQAIStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_FROM_BY_VIA, "CS_FROM_BY_VIA"); SQAIStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CM_WAITING, "CM_WAITING"); SQAIStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CM_PLANNED, "CM_PLANNED"); SQAIStationList_Cargo.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoWaiting"; } void SQAIStationList_CargoWaiting_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoWaiting("AIStationList_CargoWaiting"); SQAIStationList_CargoWaiting.PreRegister(engine, "AIStationList_Cargo"); SQAIStationList_CargoWaiting.AddConstructor(engine, "xiiii"); SQAIStationList_CargoWaiting.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoPlanned"; } void SQAIStationList_CargoPlanned_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoPlanned("AIStationList_CargoPlanned"); SQAIStationList_CargoPlanned.PreRegister(engine, "AIStationList_Cargo"); SQAIStationList_CargoPlanned.AddConstructor(engine, "xiiii"); SQAIStationList_CargoPlanned.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoWaitingByFrom"; } void SQAIStationList_CargoWaitingByFrom_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoWaitingByFrom("AIStationList_CargoWaitingByFrom"); SQAIStationList_CargoWaitingByFrom.PreRegister(engine, "AIStationList_CargoWaiting"); SQAIStationList_CargoWaitingByFrom.AddConstructor(engine, "xii"); SQAIStationList_CargoWaitingByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoWaitingViaByFrom"; } void SQAIStationList_CargoWaitingViaByFrom_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoWaitingViaByFrom("AIStationList_CargoWaitingViaByFrom"); SQAIStationList_CargoWaitingViaByFrom.PreRegister(engine, "AIStationList_CargoWaiting"); SQAIStationList_CargoWaitingViaByFrom.AddConstructor(engine, "xiii"); SQAIStationList_CargoWaitingViaByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoWaitingByVia"; } void SQAIStationList_CargoWaitingByVia_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoWaitingByVia("AIStationList_CargoWaitingByVia"); SQAIStationList_CargoWaitingByVia.PreRegister(engine, "AIStationList_CargoWaiting"); SQAIStationList_CargoWaitingByVia.AddConstructor(engine, "xii"); SQAIStationList_CargoWaitingByVia.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoWaitingFromByVia"; } void SQAIStationList_CargoWaitingFromByVia_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoWaitingFromByVia("AIStationList_CargoWaitingFromByVia"); SQAIStationList_CargoWaitingFromByVia.PreRegister(engine, "AIStationList_CargoWaiting"); SQAIStationList_CargoWaitingFromByVia.AddConstructor(engine, "xiii"); SQAIStationList_CargoWaitingFromByVia.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoPlannedByFrom"; } void SQAIStationList_CargoPlannedByFrom_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoPlannedByFrom("AIStationList_CargoPlannedByFrom"); SQAIStationList_CargoPlannedByFrom.PreRegister(engine, "AIStationList_CargoPlanned"); SQAIStationList_CargoPlannedByFrom.AddConstructor(engine, "xii"); SQAIStationList_CargoPlannedByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoPlannedViaByFrom"; } void SQAIStationList_CargoPlannedViaByFrom_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoPlannedViaByFrom("AIStationList_CargoPlannedViaByFrom"); SQAIStationList_CargoPlannedViaByFrom.PreRegister(engine, "AIStationList_CargoPlanned"); SQAIStationList_CargoPlannedViaByFrom.AddConstructor(engine, "xiii"); SQAIStationList_CargoPlannedViaByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoPlannedByVia"; } void SQAIStationList_CargoPlannedByVia_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoPlannedByVia("AIStationList_CargoPlannedByVia"); SQAIStationList_CargoPlannedByVia.PreRegister(engine, "AIStationList_CargoPlanned"); SQAIStationList_CargoPlannedByVia.AddConstructor(engine, "xii"); SQAIStationList_CargoPlannedByVia.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_CargoPlannedFromByVia"; } void SQAIStationList_CargoPlannedFromByVia_Register(Squirrel *engine) { DefSQClass SQAIStationList_CargoPlannedFromByVia("AIStationList_CargoPlannedFromByVia"); SQAIStationList_CargoPlannedFromByVia.PreRegister(engine, "AIStationList_CargoPlanned"); SQAIStationList_CargoPlannedFromByVia.AddConstructor(engine, "xiii"); SQAIStationList_CargoPlannedFromByVia.PostRegister(engine); } template <> const char *GetClassName() { return "AIStationList_Vehicle"; } void SQAIStationList_Vehicle_Register(Squirrel *engine) { DefSQClass SQAIStationList_Vehicle("AIStationList_Vehicle"); SQAIStationList_Vehicle.PreRegister(engine, "AIList"); SQAIStationList_Vehicle.AddConstructor(engine, "xi"); SQAIStationList_Vehicle.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_industrytypelist.hpp.sq0000644000000000000000000000235512627373434022433 0ustar rootroot/* $Id: ai_industrytypelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrytypelist.hpp" #include "../template/template_industrytypelist.hpp.sq" template <> const char *GetClassName() { return "AIIndustryTypeList"; } void SQAIIndustryTypeList_Register(Squirrel *engine) { DefSQClass SQAIIndustryTypeList("AIIndustryTypeList"); SQAIIndustryTypeList.PreRegister(engine, "AIList"); SQAIIndustryTypeList.AddConstructor(engine, "x"); SQAIIndustryTypeList.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_vehicle.hpp.sq0000644000000000000000000003653512627373434020402 0ustar rootroot/* $Id: ai_vehicle.hpp.sq 23506 2011-12-13 00:43:59Z michi_cc $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_vehicle.hpp" #include "../template/template_vehicle.hpp.sq" template <> const char *GetClassName() { return "AIVehicle"; } void SQAIVehicle_Register(Squirrel *engine) { DefSQClass SQAIVehicle("AIVehicle"); SQAIVehicle.PreRegister(engine); SQAIVehicle.AddConstructor(engine, "x"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_BASE, "ERR_VEHICLE_BASE"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_TOO_MANY, "ERR_VEHICLE_TOO_MANY"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE, "ERR_VEHICLE_NOT_AVAILABLE"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED, "ERR_VEHICLE_BUILD_DISABLED"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT, "ERR_VEHICLE_WRONG_DEPOT"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT, "ERR_VEHICLE_CANNOT_SEND_TO_DEPOT"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP, "ERR_VEHICLE_CANNOT_START_STOP"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN, "ERR_VEHICLE_CANNOT_TURN"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT, "ERR_VEHICLE_CANNOT_REFIT"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_IS_DESTROYED, "ERR_VEHICLE_IS_DESTROYED"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT, "ERR_VEHICLE_NOT_IN_DEPOT"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_IN_FLIGHT, "ERR_VEHICLE_IN_FLIGHT"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_NO_POWER, "ERR_VEHICLE_NO_POWER"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_TOO_LONG, "ERR_VEHICLE_TOO_LONG"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VT_RAIL, "VT_RAIL"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VT_ROAD, "VT_ROAD"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VT_WATER, "VT_WATER"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VT_AIR, "VT_AIR"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VT_INVALID, "VT_INVALID"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VS_RUNNING, "VS_RUNNING"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VS_STOPPED, "VS_STOPPED"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VS_IN_DEPOT, "VS_IN_DEPOT"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VS_AT_STATION, "VS_AT_STATION"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VS_BROKEN, "VS_BROKEN"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VS_CRASHED, "VS_CRASHED"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VS_INVALID, "VS_INVALID"); SQAIVehicle.DefSQConst(engine, ScriptVehicle::VEHICLE_INVALID, "VEHICLE_INVALID"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME, ScriptVehicle::ERR_VEHICLE_TOO_MANY); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_SHIP_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_TRAIN, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_ROAD_VEHICLE, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_SHIP, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_AIRCRAFT, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE, ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_TRAIN, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_SHIP, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_AIRCRAFT, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_TRAIN, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_SHIP, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_AIRCRAFT, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_VEHICLE_IS_DESTROYED, ScriptVehicle::ERR_VEHICLE_IS_DESTROYED); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT, ScriptVehicle::ERR_VEHICLE_IN_FLIGHT); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_START_NO_POWER, ScriptVehicle::ERR_VEHICLE_NO_POWER); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_TOO_LONG, ScriptVehicle::ERR_VEHICLE_TOO_LONG); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_TOO_MANY, "ERR_VEHICLE_TOO_MANY"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE, "ERR_VEHICLE_NOT_AVAILABLE"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED, "ERR_VEHICLE_BUILD_DISABLED"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT, "ERR_VEHICLE_WRONG_DEPOT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT, "ERR_VEHICLE_CANNOT_SEND_TO_DEPOT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP, "ERR_VEHICLE_CANNOT_START_STOP"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_TURN, "ERR_VEHICLE_CANNOT_TURN"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT, "ERR_VEHICLE_CANNOT_REFIT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_IS_DESTROYED, "ERR_VEHICLE_IS_DESTROYED"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT, "ERR_VEHICLE_NOT_IN_DEPOT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_IN_FLIGHT, "ERR_VEHICLE_IN_FLIGHT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_NO_POWER, "ERR_VEHICLE_NO_POWER"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_TOO_LONG, "ERR_VEHICLE_TOO_LONG"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsValidVehicle, "IsValidVehicle", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetNumWagons, "GetNumWagons", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SetName, "SetName", 3, ".i."); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetName, "GetName", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetLocation, "GetLocation", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetEngineType, "GetEngineType", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetWagonEngineType, "GetWagonEngineType", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetUnitNumber, "GetUnitNumber", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetAge, "GetAge", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetWagonAge, "GetWagonAge", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetMaxAge, "GetMaxAge", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetAgeLeft, "GetAgeLeft", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCurrentSpeed, "GetCurrentSpeed", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetState, "GetState", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetRunningCost, "GetRunningCost", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetProfitThisYear, "GetProfitThisYear", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetProfitLastYear, "GetProfitLastYear", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCurrentValue, "GetCurrentValue", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetVehicleType, "GetVehicleType", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetRoadType, "GetRoadType", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsInDepot, "IsInDepot", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsStoppedInDepot, "IsStoppedInDepot", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::BuildVehicle, "BuildVehicle", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::CloneVehicle, "CloneVehicle", 4, ".iib"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagon, "MoveWagon", 5, ".iiii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagonChain, "MoveWagonChain", 5, ".iiii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetRefitCapacity, "GetRefitCapacity", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::RefitVehicle, "RefitVehicle", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SellVehicle, "SellVehicle", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SellWagon, "SellWagon", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SellWagonChain, "SellWagonChain", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SendVehicleToDepot, "SendVehicleToDepot", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SendVehicleToDepotForServicing, "SendVehicleToDepotForServicing", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::StartStopVehicle, "StartStopVehicle", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::ReverseVehicle, "ReverseVehicle", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCapacity, "GetCapacity", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetLength, "GetLength", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCargoLoad, "GetCargoLoad", 3, ".ii"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetGroupID, "GetGroupID", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsArticulated, "IsArticulated", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::HasSharedOrders, "HasSharedOrders", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetReliability, "GetReliability", 2, ".i"); SQAIVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetMaximumOrderDistance, "GetMaximumOrderDistance", 2, ".i"); SQAIVehicle.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_group.hpp.sq0000644000000000000000000000612412627373434020106 0ustar rootroot/* $Id: ai_group.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_group.hpp" #include "../template/template_group.hpp.sq" template <> const char *GetClassName() { return "AIGroup"; } void SQAIGroup_Register(Squirrel *engine) { DefSQClass SQAIGroup("AIGroup"); SQAIGroup.PreRegister(engine); SQAIGroup.AddConstructor(engine, "x"); SQAIGroup.DefSQConst(engine, ScriptGroup::GROUP_ALL, "GROUP_ALL"); SQAIGroup.DefSQConst(engine, ScriptGroup::GROUP_DEFAULT, "GROUP_DEFAULT"); SQAIGroup.DefSQConst(engine, ScriptGroup::GROUP_INVALID, "GROUP_INVALID"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::IsValidGroup, "IsValidGroup", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::CreateGroup, "CreateGroup", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::DeleteGroup, "DeleteGroup", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetVehicleType, "GetVehicleType", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::SetName, "SetName", 3, ".i."); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetName, "GetName", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::EnableAutoReplaceProtection, "EnableAutoReplaceProtection", 3, ".ib"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetAutoReplaceProtection, "GetAutoReplaceProtection", 2, ".i"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetNumEngines, "GetNumEngines", 3, ".ii"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::MoveVehicle, "MoveVehicle", 3, ".ii"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::EnableWagonRemoval, "EnableWagonRemoval", 2, ".b"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::HasWagonRemoval, "HasWagonRemoval", 1, "."); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::SetAutoReplace, "SetAutoReplace", 4, ".iii"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::GetEngineReplacement, "GetEngineReplacement", 3, ".ii"); SQAIGroup.DefSQStaticMethod(engine, &ScriptGroup::StopAutoReplace, "StopAutoReplace", 3, ".ii"); SQAIGroup.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_execmode.hpp.sq0000644000000000000000000000217312627373434020543 0ustar rootroot/* $Id: ai_execmode.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_execmode.hpp" #include "../template/template_execmode.hpp.sq" template <> const char *GetClassName() { return "AIExecMode"; } void SQAIExecMode_Register(Squirrel *engine) { DefSQClass SQAIExecMode("AIExecMode"); SQAIExecMode.PreRegister(engine); SQAIExecMode.AddConstructor(engine, "x"); SQAIExecMode.PostRegister(engine); } openttd-1.5.3/src/script/api/ai/ai_vehiclelist.hpp.sq0000644000000000000000000000717612627373434021275 0ustar rootroot/* $Id: ai_vehiclelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_vehiclelist.hpp" #include "../template/template_vehiclelist.hpp.sq" template <> const char *GetClassName() { return "AIVehicleList"; } void SQAIVehicleList_Register(Squirrel *engine) { DefSQClass SQAIVehicleList("AIVehicleList"); SQAIVehicleList.PreRegister(engine, "AIList"); SQAIVehicleList.AddConstructor(engine, "x"); SQAIVehicleList.PostRegister(engine); } template <> const char *GetClassName() { return "AIVehicleList_Station"; } void SQAIVehicleList_Station_Register(Squirrel *engine) { DefSQClass SQAIVehicleList_Station("AIVehicleList_Station"); SQAIVehicleList_Station.PreRegister(engine, "AIList"); SQAIVehicleList_Station.AddConstructor(engine, "xi"); SQAIVehicleList_Station.PostRegister(engine); } template <> const char *GetClassName() { return "AIVehicleList_Depot"; } void SQAIVehicleList_Depot_Register(Squirrel *engine) { DefSQClass SQAIVehicleList_Depot("AIVehicleList_Depot"); SQAIVehicleList_Depot.PreRegister(engine, "AIList"); SQAIVehicleList_Depot.AddConstructor(engine, "xi"); SQAIVehicleList_Depot.PostRegister(engine); } template <> const char *GetClassName() { return "AIVehicleList_SharedOrders"; } void SQAIVehicleList_SharedOrders_Register(Squirrel *engine) { DefSQClass SQAIVehicleList_SharedOrders("AIVehicleList_SharedOrders"); SQAIVehicleList_SharedOrders.PreRegister(engine, "AIList"); SQAIVehicleList_SharedOrders.AddConstructor(engine, "xi"); SQAIVehicleList_SharedOrders.PostRegister(engine); } template <> const char *GetClassName() { return "AIVehicleList_Group"; } void SQAIVehicleList_Group_Register(Squirrel *engine) { DefSQClass SQAIVehicleList_Group("AIVehicleList_Group"); SQAIVehicleList_Group.PreRegister(engine, "AIList"); SQAIVehicleList_Group.AddConstructor(engine, "xi"); SQAIVehicleList_Group.PostRegister(engine); } template <> const char *GetClassName() { return "AIVehicleList_DefaultGroup"; } void SQAIVehicleList_DefaultGroup_Register(Squirrel *engine) { DefSQClass SQAIVehicleList_DefaultGroup("AIVehicleList_DefaultGroup"); SQAIVehicleList_DefaultGroup.PreRegister(engine, "AIList"); SQAIVehicleList_DefaultGroup.AddConstructor(engine, "xi"); SQAIVehicleList_DefaultGroup.PostRegister(engine); } openttd-1.5.3/src/script/api/script_error.cpp0000644000000000000000000000511412627373434017774 0ustar rootroot/* $Id: script_error.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 script_error.cpp Implementation of ScriptError. */ #include "../../stdafx.h" #include "script_error.hpp" #include "../../core/bitmath_func.hpp" #include "../../string_func.h" #include "../../safeguards.h" ScriptError::ScriptErrorMap ScriptError::error_map = ScriptError::ScriptErrorMap(); ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::ScriptErrorMapString(); /* static */ ScriptErrorType ScriptError::GetLastError() { return ScriptObject::GetLastError(); } /* static */ char *ScriptError::GetLastErrorString() { return stredup((*error_map_string.find(ScriptError::GetLastError())).second); } /* static */ ScriptErrorType ScriptError::StringToError(StringID internal_string_id) { uint index = GB(internal_string_id, 11, 5); switch (GB(internal_string_id, 11, 5)) { case 26: case 28: case 29: case 30: // NewGRF strings. return ERR_NEWGRF_SUPPLIED_ERROR; /* DO NOT SWAP case 14 and 4 because that will break StringToError due * to the index dependency that relies on FALL THROUGHs. */ case 14: if (index < 0xE4) break; // Player name case 4: if (index < 0xC0) break; // Town name case 15: // Custom name case 31: // Dynamic strings /* These strings are 'random' and have no meaning. * They actually shouldn't even be returned as error messages. */ return ERR_UNKNOWN; default: break; } ScriptErrorMap::iterator it = error_map.find(internal_string_id); if (it == error_map.end()) return ERR_UNKNOWN; return (*it).second; } /* static */ void ScriptError::RegisterErrorMap(StringID internal_string_id, ScriptErrorType ai_error_msg) { error_map[internal_string_id] = ai_error_msg; } /* static */ void ScriptError::RegisterErrorMapString(ScriptErrorType ai_error_msg, const char *message) { error_map_string[ai_error_msg] = message; } /* static */ ScriptError::ErrorCategories ScriptError::GetErrorCategory() { return (ScriptError::ErrorCategories)(GetLastError() >> (uint)ERR_CAT_BIT_SIZE); } openttd-1.5.3/src/script/api/script_viewport.cpp0000644000000000000000000000206412627373434020523 0ustar rootroot/* $Id: script_viewport.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_viewport.cpp Implementation of ScriptViewport. */ #include "../../stdafx.h" #include "script_viewport.hpp" #include "script_game.hpp" #include "script_map.hpp" #include "../../viewport_func.h" #include "../../safeguards.h" /* static */ void ScriptViewport::ScrollTo(TileIndex tile) { if (ScriptGame::IsMultiplayer()) return; if (!ScriptMap::IsValidTile(tile)) return; ScrollMainWindowToTile(tile); } openttd-1.5.3/src/script/api/game/0000755000000000000000000000000012627373433015462 5ustar rootrootopenttd-1.5.3/src/script/api/game/game_industrylist.hpp.sq0000644000000000000000000000444512627373433022372 0ustar rootroot/* $Id: game_industrylist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrylist.hpp" #include "../template/template_industrylist.hpp.sq" template <> const char *GetClassName() { return "GSIndustryList"; } void SQGSIndustryList_Register(Squirrel *engine) { DefSQClass SQGSIndustryList("GSIndustryList"); SQGSIndustryList.PreRegister(engine, "GSList"); SQGSIndustryList.AddConstructor(engine, "x"); SQGSIndustryList.PostRegister(engine); } template <> const char *GetClassName() { return "GSIndustryList_CargoAccepting"; } void SQGSIndustryList_CargoAccepting_Register(Squirrel *engine) { DefSQClass SQGSIndustryList_CargoAccepting("GSIndustryList_CargoAccepting"); SQGSIndustryList_CargoAccepting.PreRegister(engine, "GSList"); SQGSIndustryList_CargoAccepting.AddConstructor(engine, "xi"); SQGSIndustryList_CargoAccepting.PostRegister(engine); } template <> const char *GetClassName() { return "GSIndustryList_CargoProducing"; } void SQGSIndustryList_CargoProducing_Register(Squirrel *engine) { DefSQClass SQGSIndustryList_CargoProducing("GSIndustryList_CargoProducing"); SQGSIndustryList_CargoProducing.PreRegister(engine, "GSList"); SQGSIndustryList_CargoProducing.AddConstructor(engine, "xi"); SQGSIndustryList_CargoProducing.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_log.hpp.sq0000644000000000000000000000244412627373433020373 0ustar rootroot/* $Id: game_log.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_log.hpp" #include "../template/template_log.hpp.sq" template <> const char *GetClassName() { return "GSLog"; } void SQGSLog_Register(Squirrel *engine) { DefSQClass SQGSLog("GSLog"); SQGSLog.PreRegister(engine); SQGSLog.AddConstructor(engine, "x"); SQGSLog.DefSQStaticMethod(engine, &ScriptLog::Info, "Info", 2, ".."); SQGSLog.DefSQStaticMethod(engine, &ScriptLog::Warning, "Warning", 2, ".."); SQGSLog.DefSQStaticMethod(engine, &ScriptLog::Error, "Error", 2, ".."); SQGSLog.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_news.hpp.sq0000644000000000000000000000401012627373433020555 0ustar rootroot/* $Id: game_news.hpp.sq 27164 2015-02-22 17:25:29Z alberth $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_news.hpp" #include "../template/template_news.hpp.sq" template <> const char *GetClassName() { return "GSNews"; } void SQGSNews_Register(Squirrel *engine) { DefSQClass SQGSNews("GSNews"); SQGSNews.PreRegister(engine); SQGSNews.AddConstructor(engine, "x"); SQGSNews.DefSQConst(engine, ScriptNews::NT_ACCIDENT, "NT_ACCIDENT"); SQGSNews.DefSQConst(engine, ScriptNews::NT_COMPANY_INFO, "NT_COMPANY_INFO"); SQGSNews.DefSQConst(engine, ScriptNews::NT_ECONOMY, "NT_ECONOMY"); SQGSNews.DefSQConst(engine, ScriptNews::NT_ADVICE, "NT_ADVICE"); SQGSNews.DefSQConst(engine, ScriptNews::NT_ACCEPTANCE, "NT_ACCEPTANCE"); SQGSNews.DefSQConst(engine, ScriptNews::NT_SUBSIDIES, "NT_SUBSIDIES"); SQGSNews.DefSQConst(engine, ScriptNews::NT_GENERAL, "NT_GENERAL"); SQGSNews.DefSQConst(engine, ScriptNews::NR_NONE, "NR_NONE"); SQGSNews.DefSQConst(engine, ScriptNews::NR_TILE, "NR_TILE"); SQGSNews.DefSQConst(engine, ScriptNews::NR_STATION, "NR_STATION"); SQGSNews.DefSQConst(engine, ScriptNews::NR_INDUSTRY, "NR_INDUSTRY"); SQGSNews.DefSQConst(engine, ScriptNews::NR_TOWN, "NR_TOWN"); SQGSNews.DefSQStaticMethod(engine, &ScriptNews::Create, "Create", 6, ".i.iii"); SQGSNews.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_companymode.hpp.sq0000644000000000000000000000226012627373433022121 0ustar rootroot/* $Id: game_companymode.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_companymode.hpp" #include "../template/template_companymode.hpp.sq" template <> const char *GetClassName() { return "GSCompanyMode"; } void SQGSCompanyMode_Register(Squirrel *engine) { DefSQClass SQGSCompanyMode("GSCompanyMode"); SQGSCompanyMode.PreRegister(engine); SQGSCompanyMode.AddConstructor(engine, "xi"); SQGSCompanyMode.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_signlist.hpp.sq0000644000000000000000000000220712627373433021443 0ustar rootroot/* $Id: game_signlist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_signlist.hpp" #include "../template/template_signlist.hpp.sq" template <> const char *GetClassName() { return "GSSignList"; } void SQGSSignList_Register(Squirrel *engine) { DefSQClass SQGSSignList("GSSignList"); SQGSSignList.PreRegister(engine, "GSList"); SQGSSignList.AddConstructor(engine, "x"); SQGSSignList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_order.hpp.sq0000644000000000000000000002251512627373433020726 0ustar rootroot/* $Id: game_order.hpp.sq 24006 2012-03-04 16:40:06Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_order.hpp" #include "../template/template_order.hpp.sq" template <> const char *GetClassName() { return "GSOrder"; } void SQGSOrder_Register(Squirrel *engine) { DefSQClass SQGSOrder("GSOrder"); SQGSOrder.PreRegister(engine); SQGSOrder.AddConstructor(engine, "x"); SQGSOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_BASE, "ERR_ORDER_BASE"); SQGSOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_TOO_MANY, "ERR_ORDER_TOO_MANY"); SQGSOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION, "ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION"); SQGSOrder.DefSQConst(engine, ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE, "ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_NONE, "OF_NONE"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_NON_STOP_INTERMEDIATE, "OF_NON_STOP_INTERMEDIATE"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_NON_STOP_DESTINATION, "OF_NON_STOP_DESTINATION"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_UNLOAD, "OF_UNLOAD"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_TRANSFER, "OF_TRANSFER"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_NO_UNLOAD, "OF_NO_UNLOAD"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_FULL_LOAD, "OF_FULL_LOAD"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_FULL_LOAD_ANY, "OF_FULL_LOAD_ANY"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_NO_LOAD, "OF_NO_LOAD"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_SERVICE_IF_NEEDED, "OF_SERVICE_IF_NEEDED"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_STOP_IN_DEPOT, "OF_STOP_IN_DEPOT"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_GOTO_NEAREST_DEPOT, "OF_GOTO_NEAREST_DEPOT"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_NON_STOP_FLAGS, "OF_NON_STOP_FLAGS"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_UNLOAD_FLAGS, "OF_UNLOAD_FLAGS"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_LOAD_FLAGS, "OF_LOAD_FLAGS"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_DEPOT_FLAGS, "OF_DEPOT_FLAGS"); SQGSOrder.DefSQConst(engine, ScriptOrder::OF_INVALID, "OF_INVALID"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_LOAD_PERCENTAGE, "OC_LOAD_PERCENTAGE"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_RELIABILITY, "OC_RELIABILITY"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_MAX_SPEED, "OC_MAX_SPEED"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_AGE, "OC_AGE"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_REQUIRES_SERVICE, "OC_REQUIRES_SERVICE"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_UNCONDITIONALLY, "OC_UNCONDITIONALLY"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_REMAINING_LIFETIME, "OC_REMAINING_LIFETIME"); SQGSOrder.DefSQConst(engine, ScriptOrder::OC_INVALID, "OC_INVALID"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_EQUALS, "CF_EQUALS"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_NOT_EQUALS, "CF_NOT_EQUALS"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_LESS_THAN, "CF_LESS_THAN"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_LESS_EQUALS, "CF_LESS_EQUALS"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_MORE_THAN, "CF_MORE_THAN"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_MORE_EQUALS, "CF_MORE_EQUALS"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_IS_TRUE, "CF_IS_TRUE"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_IS_FALSE, "CF_IS_FALSE"); SQGSOrder.DefSQConst(engine, ScriptOrder::CF_INVALID, "CF_INVALID"); SQGSOrder.DefSQConst(engine, ScriptOrder::ORDER_CURRENT, "ORDER_CURRENT"); SQGSOrder.DefSQConst(engine, ScriptOrder::ORDER_INVALID, "ORDER_INVALID"); SQGSOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_NEAR, "STOPLOCATION_NEAR"); SQGSOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_MIDDLE, "STOPLOCATION_MIDDLE"); SQGSOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_FAR, "STOPLOCATION_FAR"); SQGSOrder.DefSQConst(engine, ScriptOrder::STOPLOCATION_INVALID, "STOPLOCATION_INVALID"); ScriptError::RegisterErrorMap(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS, ScriptOrder::ERR_ORDER_TOO_MANY); ScriptError::RegisterErrorMap(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION, ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE, ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE); ScriptError::RegisterErrorMapString(ScriptOrder::ERR_ORDER_TOO_MANY, "ERR_ORDER_TOO_MANY"); ScriptError::RegisterErrorMapString(ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION, "ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION"); ScriptError::RegisterErrorMapString(ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE, "ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsValidVehicleOrder, "IsValidVehicleOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsGotoStationOrder, "IsGotoStationOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsGotoDepotOrder, "IsGotoDepotOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsGotoWaypointOrder, "IsGotoWaypointOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsConditionalOrder, "IsConditionalOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsVoidOrder, "IsVoidOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsRefitOrder, "IsRefitOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsCurrentOrderPartOfOrderList, "IsCurrentOrderPartOfOrderList", 2, ".i"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::ResolveOrderPosition, "ResolveOrderPosition", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::AreOrderFlagsValid, "AreOrderFlagsValid", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::IsValidConditionalOrder, "IsValidConditionalOrder", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCount, "GetOrderCount", 2, ".i"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderDestination, "GetOrderDestination", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderFlags, "GetOrderFlags", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderJumpTo, "GetOrderJumpTo", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCondition, "GetOrderCondition", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCompareFunction, "GetOrderCompareFunction", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderCompareValue, "GetOrderCompareValue", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetStopLocation, "GetStopLocation", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderRefit, "GetOrderRefit", 3, ".ii"); SQGSOrder.DefSQStaticMethod(engine, &ScriptOrder::GetOrderDistance, "GetOrderDistance", 4, ".iii"); SQGSOrder.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_infrastructure.hpp.sq0000644000000000000000000000530512627373433022671 0ustar rootroot/* $Id: game_infrastructure.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_infrastructure.hpp" #include "../template/template_infrastructure.hpp.sq" template <> const char *GetClassName() { return "GSInfrastructure"; } void SQGSInfrastructure_Register(Squirrel *engine) { DefSQClass SQGSInfrastructure("GSInfrastructure"); SQGSInfrastructure.PreRegister(engine); SQGSInfrastructure.AddConstructor(engine, "x"); SQGSInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_RAIL, "INFRASTRUCTURE_RAIL"); SQGSInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_SIGNALS, "INFRASTRUCTURE_SIGNALS"); SQGSInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_ROAD, "INFRASTRUCTURE_ROAD"); SQGSInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_CANAL, "INFRASTRUCTURE_CANAL"); SQGSInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_STATION, "INFRASTRUCTURE_STATION"); SQGSInfrastructure.DefSQConst(engine, ScriptInfrastructure::INFRASTRUCTURE_AIRPORT, "INFRASTRUCTURE_AIRPORT"); SQGSInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetRailPieceCount, "GetRailPieceCount", 3, ".ii"); SQGSInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetRoadPieceCount, "GetRoadPieceCount", 3, ".ii"); SQGSInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetInfrastructurePieceCount, "GetInfrastructurePieceCount", 3, ".ii"); SQGSInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetMonthlyRailCosts, "GetMonthlyRailCosts", 3, ".ii"); SQGSInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetMonthlyRoadCosts, "GetMonthlyRoadCosts", 3, ".ii"); SQGSInfrastructure.DefSQStaticMethod(engine, &ScriptInfrastructure::GetMonthlyInfrastructureCosts, "GetMonthlyInfrastructureCosts", 3, ".ii"); SQGSInfrastructure.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_industrytype.hpp.sq0000644000000000000000000000626312627373433022400 0ustar rootroot/* $Id: game_industrytype.hpp.sq 24513 2012-09-08 12:14:00Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrytype.hpp" #include "../template/template_industrytype.hpp.sq" template <> const char *GetClassName() { return "GSIndustryType"; } void SQGSIndustryType_Register(Squirrel *engine) { DefSQClass SQGSIndustryType("GSIndustryType"); SQGSIndustryType.PreRegister(engine); SQGSIndustryType.AddConstructor(engine, "x"); SQGSIndustryType.DefSQConst(engine, ScriptIndustryType::INDUSTRYTYPE_UNKNOWN, "INDUSTRYTYPE_UNKNOWN"); SQGSIndustryType.DefSQConst(engine, ScriptIndustryType::INDUSTRYTYPE_TOWN, "INDUSTRYTYPE_TOWN"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsValidIndustryType, "IsValidIndustryType", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetName, "GetName", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetProducedCargo, "GetProducedCargo", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetAcceptedCargo, "GetAcceptedCargo", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsRawIndustry, "IsRawIndustry", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsProcessingIndustry, "IsProcessingIndustry", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::ProductionCanIncrease, "ProductionCanIncrease", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::GetConstructionCost, "GetConstructionCost", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::CanBuildIndustry, "CanBuildIndustry", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::CanProspectIndustry, "CanProspectIndustry", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::BuildIndustry, "BuildIndustry", 3, ".ii"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::ProspectIndustry, "ProspectIndustry", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::IsBuiltOnWater, "IsBuiltOnWater", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::HasHeliport, "HasHeliport", 2, ".i"); SQGSIndustryType.DefSQStaticMethod(engine, &ScriptIndustryType::HasDock, "HasDock", 2, ".i"); SQGSIndustryType.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_gamesettings.hpp.sq0000644000000000000000000000272612627373433022307 0ustar rootroot/* $Id: game_gamesettings.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_gamesettings.hpp" #include "../template/template_gamesettings.hpp.sq" template <> const char *GetClassName() { return "GSGameSettings"; } void SQGSGameSettings_Register(Squirrel *engine) { DefSQClass SQGSGameSettings("GSGameSettings"); SQGSGameSettings.PreRegister(engine); SQGSGameSettings.AddConstructor(engine, "x"); SQGSGameSettings.DefSQStaticMethod(engine, &ScriptGameSettings::IsValid, "IsValid", 2, ".."); SQGSGameSettings.DefSQStaticMethod(engine, &ScriptGameSettings::GetValue, "GetValue", 2, ".."); SQGSGameSettings.DefSQStaticMethod(engine, &ScriptGameSettings::SetValue, "SetValue", 3, "..i"); SQGSGameSettings.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_cargo.hpp.sq0000644000000000000000000000740012627373433020702 0ustar rootroot/* $Id: game_cargo.hpp.sq 26396 2014-03-10 22:18:53Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargo.hpp" #include "../template/template_cargo.hpp.sq" template <> const char *GetClassName() { return "GSCargo"; } void SQGSCargo_Register(Squirrel *engine) { DefSQClass SQGSCargo("GSCargo"); SQGSCargo.PreRegister(engine); SQGSCargo.AddConstructor(engine, "x"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_PASSENGERS, "CC_PASSENGERS"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_MAIL, "CC_MAIL"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_EXPRESS, "CC_EXPRESS"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_ARMOURED, "CC_ARMOURED"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_BULK, "CC_BULK"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_PIECE_GOODS, "CC_PIECE_GOODS"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_LIQUID, "CC_LIQUID"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_REFRIGERATED, "CC_REFRIGERATED"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_HAZARDOUS, "CC_HAZARDOUS"); SQGSCargo.DefSQConst(engine, ScriptCargo::CC_COVERED, "CC_COVERED"); SQGSCargo.DefSQConst(engine, ScriptCargo::TE_NONE, "TE_NONE"); SQGSCargo.DefSQConst(engine, ScriptCargo::TE_PASSENGERS, "TE_PASSENGERS"); SQGSCargo.DefSQConst(engine, ScriptCargo::TE_MAIL, "TE_MAIL"); SQGSCargo.DefSQConst(engine, ScriptCargo::TE_GOODS, "TE_GOODS"); SQGSCargo.DefSQConst(engine, ScriptCargo::TE_WATER, "TE_WATER"); SQGSCargo.DefSQConst(engine, ScriptCargo::TE_FOOD, "TE_FOOD"); SQGSCargo.DefSQConst(engine, ScriptCargo::CT_AUTO_REFIT, "CT_AUTO_REFIT"); SQGSCargo.DefSQConst(engine, ScriptCargo::CT_NO_REFIT, "CT_NO_REFIT"); SQGSCargo.DefSQConst(engine, ScriptCargo::DT_MANUAL, "DT_MANUAL"); SQGSCargo.DefSQConst(engine, ScriptCargo::DT_ASYMMETRIC, "DT_ASYMMETRIC"); SQGSCargo.DefSQConst(engine, ScriptCargo::DT_SYMMETRIC, "DT_SYMMETRIC"); SQGSCargo.DefSQConst(engine, ScriptCargo::INVALID_DISTRIBUTION_TYPE, "INVALID_DISTRIBUTION_TYPE"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::IsValidCargo, "IsValidCargo", 2, ".i"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::IsValidTownEffect, "IsValidTownEffect", 2, ".i"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::GetCargoLabel, "GetCargoLabel", 2, ".i"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::IsFreight, "IsFreight", 2, ".i"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::HasCargoClass, "HasCargoClass", 3, ".ii"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::GetTownEffect, "GetTownEffect", 2, ".i"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::GetCargoIncome, "GetCargoIncome", 4, ".iii"); SQGSCargo.DefSQStaticMethod(engine, &ScriptCargo::GetDistributionType, "GetDistributionType", 2, ".i"); SQGSCargo.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_station.hpp.sq0000644000000000000000000001446012627373433021274 0ustar rootroot/* $Id: game_station.hpp.sq 26892 2014-09-21 16:20:14Z fonsinchen $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_station.hpp" #include "../template/template_station.hpp.sq" template <> const char *GetClassName() { return "GSStation"; } void SQGSStation_Register(Squirrel *engine) { DefSQClass SQGSStation("GSStation"); SQGSStation.PreRegister(engine, "GSBaseStation"); SQGSStation.AddConstructor(engine, "x"); SQGSStation.DefSQConst(engine, ScriptStation::ERR_STATION_BASE, "ERR_STATION_BASE"); SQGSStation.DefSQConst(engine, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, "ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION"); SQGSStation.DefSQConst(engine, ScriptStation::ERR_STATION_TOO_MANY_STATIONS, "ERR_STATION_TOO_MANY_STATIONS"); SQGSStation.DefSQConst(engine, ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN, "ERR_STATION_TOO_MANY_STATIONS_IN_TOWN"); SQGSStation.DefSQConst(engine, ScriptStation::STATION_TRAIN, "STATION_TRAIN"); SQGSStation.DefSQConst(engine, ScriptStation::STATION_TRUCK_STOP, "STATION_TRUCK_STOP"); SQGSStation.DefSQConst(engine, ScriptStation::STATION_BUS_STOP, "STATION_BUS_STOP"); SQGSStation.DefSQConst(engine, ScriptStation::STATION_AIRPORT, "STATION_AIRPORT"); SQGSStation.DefSQConst(engine, ScriptStation::STATION_DOCK, "STATION_DOCK"); SQGSStation.DefSQConst(engine, ScriptStation::STATION_ANY, "STATION_ANY"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK, ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_STATIONS_LOADING, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_TRUCK_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_BUS_STOPS, ScriptStation::ERR_STATION_TOO_MANY_STATIONS); ScriptError::RegisterErrorMap(STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT, ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, "ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION"); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_MANY_STATIONS, "ERR_STATION_TOO_MANY_STATIONS"); ScriptError::RegisterErrorMapString(ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN, "ERR_STATION_TOO_MANY_STATIONS_IN_TOWN"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::IsValidStation, "IsValidStation", 2, ".i"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetOwner, "GetOwner", 2, ".i"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetStationID, "GetStationID", 2, ".i"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaiting, "GetCargoWaiting", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaitingFrom, "GetCargoWaitingFrom", 4, ".iii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaitingVia, "GetCargoWaitingVia", 4, ".iii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoWaitingFromVia, "GetCargoWaitingFromVia", 5, ".iiii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlanned, "GetCargoPlanned", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlannedFrom, "GetCargoPlannedFrom", 4, ".iii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlannedVia, "GetCargoPlannedVia", 4, ".iii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoPlannedFromVia, "GetCargoPlannedFromVia", 5, ".iiii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::HasCargoRating, "HasCargoRating", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCargoRating, "GetCargoRating", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetCoverageRadius, "GetCoverageRadius", 2, ".i"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetStationCoverageRadius, "GetStationCoverageRadius", 2, ".i"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::IsWithinTownInfluence, "IsWithinTownInfluence", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::HasStationType, "HasStationType", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::HasRoadType, "HasRoadType", 3, ".ii"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::GetNearestTown, "GetNearestTown", 2, ".i"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::IsAirportClosed, "IsAirportClosed", 2, ".i"); SQGSStation.DefSQStaticMethod(engine, &ScriptStation::OpenCloseAirport, "OpenCloseAirport", 2, ".i"); SQGSStation.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_viewport.hpp.sq0000644000000000000000000000232712627373433021471 0ustar rootroot/* $Id: game_viewport.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_viewport.hpp" #include "../template/template_viewport.hpp.sq" template <> const char *GetClassName() { return "GSViewport"; } void SQGSViewport_Register(Squirrel *engine) { DefSQClass SQGSViewport("GSViewport"); SQGSViewport.PreRegister(engine); SQGSViewport.AddConstructor(engine, "x"); SQGSViewport.DefSQStaticMethod(engine, &ScriptViewport::ScrollTo, "ScrollTo", 2, ".i"); SQGSViewport.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_sign.hpp.sq0000644000000000000000000000404712627373433020553 0ustar rootroot/* $Id: game_sign.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_sign.hpp" #include "../template/template_sign.hpp.sq" template <> const char *GetClassName() { return "GSSign"; } void SQGSSign_Register(Squirrel *engine) { DefSQClass SQGSSign("GSSign"); SQGSSign.PreRegister(engine); SQGSSign.AddConstructor(engine, "x"); SQGSSign.DefSQConst(engine, ScriptSign::ERR_SIGN_BASE, "ERR_SIGN_BASE"); SQGSSign.DefSQConst(engine, ScriptSign::ERR_SIGN_TOO_MANY_SIGNS, "ERR_SIGN_TOO_MANY_SIGNS"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_SIGNS, ScriptSign::ERR_SIGN_TOO_MANY_SIGNS); ScriptError::RegisterErrorMapString(ScriptSign::ERR_SIGN_TOO_MANY_SIGNS, "ERR_SIGN_TOO_MANY_SIGNS"); SQGSSign.DefSQStaticMethod(engine, &ScriptSign::IsValidSign, "IsValidSign", 2, ".i"); SQGSSign.DefSQStaticMethod(engine, &ScriptSign::SetName, "SetName", 3, ".i."); SQGSSign.DefSQStaticMethod(engine, &ScriptSign::GetName, "GetName", 2, ".i"); SQGSSign.DefSQStaticMethod(engine, &ScriptSign::GetOwner, "GetOwner", 2, ".i"); SQGSSign.DefSQStaticMethod(engine, &ScriptSign::GetLocation, "GetLocation", 2, ".i"); SQGSSign.DefSQStaticMethod(engine, &ScriptSign::BuildSign, "BuildSign", 3, ".i."); SQGSSign.DefSQStaticMethod(engine, &ScriptSign::RemoveSign, "RemoveSign", 2, ".i"); SQGSSign.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_rail.hpp.sq0000644000000000000000000002157112627373433020543 0ustar rootroot/* $Id: game_rail.hpp.sq 25614 2013-07-15 18:19:26Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_rail.hpp" #include "../template/template_rail.hpp.sq" template <> const char *GetClassName() { return "GSRail"; } void SQGSRail_Register(Squirrel *engine) { DefSQClass SQGSRail("GSRail"); SQGSRail.PreRegister(engine); SQGSRail.AddConstructor(engine, "x"); SQGSRail.DefSQConst(engine, ScriptRail::ERR_RAIL_BASE, "ERR_RAIL_BASE"); SQGSRail.DefSQConst(engine, ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); SQGSRail.DefSQConst(engine, ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); SQGSRail.DefSQConst(engine, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING, "ERR_RAILTYPE_DISALLOWS_CROSSING"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTYPE_INVALID, "RAILTYPE_INVALID"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTRACK_NE_SW, "RAILTRACK_NE_SW"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTRACK_NW_SE, "RAILTRACK_NW_SE"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTRACK_NW_NE, "RAILTRACK_NW_NE"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTRACK_SW_SE, "RAILTRACK_SW_SE"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTRACK_NW_SW, "RAILTRACK_NW_SW"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTRACK_NE_SE, "RAILTRACK_NE_SE"); SQGSRail.DefSQConst(engine, ScriptRail::RAILTRACK_INVALID, "RAILTRACK_INVALID"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_NORMAL, "SIGNALTYPE_NORMAL"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_ENTRY, "SIGNALTYPE_ENTRY"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_EXIT, "SIGNALTYPE_EXIT"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_COMBO, "SIGNALTYPE_COMBO"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_PBS, "SIGNALTYPE_PBS"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_PBS_ONEWAY, "SIGNALTYPE_PBS_ONEWAY"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_TWOWAY, "SIGNALTYPE_TWOWAY"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_NORMAL_TWOWAY, "SIGNALTYPE_NORMAL_TWOWAY"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_ENTRY_TWOWAY, "SIGNALTYPE_ENTRY_TWOWAY"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_EXIT_TWOWAY, "SIGNALTYPE_EXIT_TWOWAY"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_COMBO_TWOWAY, "SIGNALTYPE_COMBO_TWOWAY"); SQGSRail.DefSQConst(engine, ScriptRail::SIGNALTYPE_NONE, "SIGNALTYPE_NONE"); SQGSRail.DefSQConst(engine, ScriptRail::BT_TRACK, "BT_TRACK"); SQGSRail.DefSQConst(engine, ScriptRail::BT_SIGNAL, "BT_SIGNAL"); SQGSRail.DefSQConst(engine, ScriptRail::BT_DEPOT, "BT_DEPOT"); SQGSRail.DefSQConst(engine, ScriptRail::BT_STATION, "BT_STATION"); SQGSRail.DefSQConst(engine, ScriptRail::BT_WAYPOINT, "BT_WAYPOINT"); ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_ON_ONEWAY_ROAD, ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_ARE_NO_SIGNALS, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_THERE_IS_NO_STATION, ScriptRail::ERR_UNSUITABLE_TRACK); ScriptError::RegisterErrorMap(STR_ERROR_CROSSING_DISALLOWED, ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING); ScriptError::RegisterErrorMapString(ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD, "ERR_CROSSING_ON_ONEWAY_ROAD"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_UNSUITABLE_TRACK, "ERR_UNSUITABLE_TRACK"); ScriptError::RegisterErrorMapString(ScriptRail::ERR_RAILTYPE_DISALLOWS_CROSSING, "ERR_RAILTYPE_DISALLOWS_CROSSING"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetName, "GetName", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::IsRailTile, "IsRailTile", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::IsLevelCrossingTile, "IsLevelCrossingTile", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::IsRailDepotTile, "IsRailDepotTile", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::IsRailStationTile, "IsRailStationTile", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::IsRailWaypointTile, "IsRailWaypointTile", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::IsRailTypeAvailable, "IsRailTypeAvailable", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetCurrentRailType, "GetCurrentRailType", 1, "."); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::SetCurrentRailType, "SetCurrentRailType", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::TrainCanRunOnRail, "TrainCanRunOnRail", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::TrainHasPowerOnRail, "TrainHasPowerOnRail", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetRailType, "GetRailType", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::ConvertRailType, "ConvertRailType", 4, ".iii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetRailDepotFrontTile, "GetRailDepotFrontTile", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetRailStationDirection, "GetRailStationDirection", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailDepot, "BuildRailDepot", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailStation, "BuildRailStation", 6, ".iiiii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::BuildNewGRFRailStation, "BuildNewGRFRailStation", 11, ".iiiiiiiiib"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailWaypoint, "BuildRailWaypoint", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRailWaypointTileRectangle, "RemoveRailWaypointTileRectangle", 4, ".iib"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRailStationTileRectangle, "RemoveRailStationTileRectangle", 4, ".iib"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetRailTracks, "GetRailTracks", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::BuildRailTrack, "BuildRailTrack", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRailTrack, "RemoveRailTrack", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::AreTilesConnected, "AreTilesConnected", 4, ".iii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::BuildRail, "BuildRail", 4, ".iii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::RemoveRail, "RemoveRail", 4, ".iii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetSignalType, "GetSignalType", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::BuildSignal, "BuildSignal", 4, ".iii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::RemoveSignal, "RemoveSignal", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetBuildCost, "GetBuildCost", 3, ".ii"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQGSRail.DefSQStaticMethod(engine, &ScriptRail::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQGSRail.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_goal.hpp.sq0000644000000000000000000001001712627373433020527 0ustar rootroot/* $Id: game_goal.hpp.sq 26012 2013-11-16 17:41:57Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_goal.hpp" #include "../template/template_goal.hpp.sq" template <> const char *GetClassName() { return "GSGoal"; } void SQGSGoal_Register(Squirrel *engine) { DefSQClass SQGSGoal("GSGoal"); SQGSGoal.PreRegister(engine); SQGSGoal.AddConstructor(engine, "x"); SQGSGoal.DefSQConst(engine, ScriptGoal::GOAL_INVALID, "GOAL_INVALID"); SQGSGoal.DefSQConst(engine, ScriptGoal::GT_NONE, "GT_NONE"); SQGSGoal.DefSQConst(engine, ScriptGoal::GT_TILE, "GT_TILE"); SQGSGoal.DefSQConst(engine, ScriptGoal::GT_INDUSTRY, "GT_INDUSTRY"); SQGSGoal.DefSQConst(engine, ScriptGoal::GT_TOWN, "GT_TOWN"); SQGSGoal.DefSQConst(engine, ScriptGoal::GT_COMPANY, "GT_COMPANY"); SQGSGoal.DefSQConst(engine, ScriptGoal::GT_STORY_PAGE, "GT_STORY_PAGE"); SQGSGoal.DefSQConst(engine, ScriptGoal::QT_QUESTION, "QT_QUESTION"); SQGSGoal.DefSQConst(engine, ScriptGoal::QT_INFORMATION, "QT_INFORMATION"); SQGSGoal.DefSQConst(engine, ScriptGoal::QT_WARNING, "QT_WARNING"); SQGSGoal.DefSQConst(engine, ScriptGoal::QT_ERROR, "QT_ERROR"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_CANCEL, "BUTTON_CANCEL"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_OK, "BUTTON_OK"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_NO, "BUTTON_NO"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_YES, "BUTTON_YES"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_DECLINE, "BUTTON_DECLINE"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_ACCEPT, "BUTTON_ACCEPT"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_IGNORE, "BUTTON_IGNORE"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_RETRY, "BUTTON_RETRY"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_PREVIOUS, "BUTTON_PREVIOUS"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_NEXT, "BUTTON_NEXT"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_STOP, "BUTTON_STOP"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_START, "BUTTON_START"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_GO, "BUTTON_GO"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_CONTINUE, "BUTTON_CONTINUE"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_RESTART, "BUTTON_RESTART"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_POSTPONE, "BUTTON_POSTPONE"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_SURRENDER, "BUTTON_SURRENDER"); SQGSGoal.DefSQConst(engine, ScriptGoal::BUTTON_CLOSE, "BUTTON_CLOSE"); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsValidGoal, "IsValidGoal", 2, ".i"); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::New, "New", 5, ".i.ii"); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Remove, "Remove", 2, ".i"); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetText, "SetText", 3, ".i."); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetProgress, "SetProgress", 3, ".i."); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetCompleted, "SetCompleted", 3, ".ib"); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsCompleted, "IsCompleted", 2, ".i"); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Question, "Question", 6, ".ii.ii"); SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::CloseQuestion, "CloseQuestion", 2, ".i"); SQGSGoal.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_vehicle.hpp.sq0000644000000000000000000003674312627373433021242 0ustar rootroot/* $Id: game_vehicle.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_vehicle.hpp" #include "../template/template_vehicle.hpp.sq" template <> const char *GetClassName() { return "GSVehicle"; } void SQGSVehicle_Register(Squirrel *engine) { DefSQClass SQGSVehicle("GSVehicle"); SQGSVehicle.PreRegister(engine); SQGSVehicle.AddConstructor(engine, "x"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_BASE, "ERR_VEHICLE_BASE"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_TOO_MANY, "ERR_VEHICLE_TOO_MANY"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE, "ERR_VEHICLE_NOT_AVAILABLE"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED, "ERR_VEHICLE_BUILD_DISABLED"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT, "ERR_VEHICLE_WRONG_DEPOT"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT, "ERR_VEHICLE_CANNOT_SEND_TO_DEPOT"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP, "ERR_VEHICLE_CANNOT_START_STOP"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN, "ERR_VEHICLE_CANNOT_TURN"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT, "ERR_VEHICLE_CANNOT_REFIT"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_IS_DESTROYED, "ERR_VEHICLE_IS_DESTROYED"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT, "ERR_VEHICLE_NOT_IN_DEPOT"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_IN_FLIGHT, "ERR_VEHICLE_IN_FLIGHT"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_NO_POWER, "ERR_VEHICLE_NO_POWER"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::ERR_VEHICLE_TOO_LONG, "ERR_VEHICLE_TOO_LONG"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VT_RAIL, "VT_RAIL"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VT_ROAD, "VT_ROAD"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VT_WATER, "VT_WATER"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VT_AIR, "VT_AIR"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VT_INVALID, "VT_INVALID"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VS_RUNNING, "VS_RUNNING"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VS_STOPPED, "VS_STOPPED"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VS_IN_DEPOT, "VS_IN_DEPOT"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VS_AT_STATION, "VS_AT_STATION"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VS_BROKEN, "VS_BROKEN"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VS_CRASHED, "VS_CRASHED"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VS_INVALID, "VS_INVALID"); SQGSVehicle.DefSQConst(engine, ScriptVehicle::VEHICLE_INVALID, "VEHICLE_INVALID"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME, ScriptVehicle::ERR_VEHICLE_TOO_MANY); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_SHIP_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE, ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_TRAIN, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_ROAD_VEHICLE, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_SHIP, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUY_AIRCRAFT, ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED); ScriptError::RegisterErrorMap(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE, ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR, ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_TRAIN, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_SHIP, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_STOP_START_AIRCRAFT, ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS, ScriptVehicle::ERR_VEHICLE_CANNOT_TURN); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_TRAIN, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_SHIP, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_REFIT_AIRCRAFT, ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT); ScriptError::RegisterErrorMap(STR_ERROR_VEHICLE_IS_DESTROYED, ScriptVehicle::ERR_VEHICLE_IS_DESTROYED); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT, ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_IS_IN_FLIGHT, ScriptVehicle::ERR_VEHICLE_IN_FLIGHT); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_START_NO_POWER, ScriptVehicle::ERR_VEHICLE_NO_POWER); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_TOO_LONG, ScriptVehicle::ERR_VEHICLE_TOO_LONG); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_TOO_MANY, "ERR_VEHICLE_TOO_MANY"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_NOT_AVAILABLE, "ERR_VEHICLE_NOT_AVAILABLE"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_BUILD_DISABLED, "ERR_VEHICLE_BUILD_DISABLED"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_WRONG_DEPOT, "ERR_VEHICLE_WRONG_DEPOT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_SEND_TO_DEPOT, "ERR_VEHICLE_CANNOT_SEND_TO_DEPOT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_START_STOP, "ERR_VEHICLE_CANNOT_START_STOP"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_TURN, "ERR_VEHICLE_CANNOT_TURN"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_CANNOT_REFIT, "ERR_VEHICLE_CANNOT_REFIT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_IS_DESTROYED, "ERR_VEHICLE_IS_DESTROYED"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_NOT_IN_DEPOT, "ERR_VEHICLE_NOT_IN_DEPOT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_IN_FLIGHT, "ERR_VEHICLE_IN_FLIGHT"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_NO_POWER, "ERR_VEHICLE_NO_POWER"); ScriptError::RegisterErrorMapString(ScriptVehicle::ERR_VEHICLE_TOO_LONG, "ERR_VEHICLE_TOO_LONG"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsValidVehicle, "IsValidVehicle", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetNumWagons, "GetNumWagons", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SetName, "SetName", 3, ".i."); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetName, "GetName", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetOwner, "GetOwner", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetLocation, "GetLocation", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetEngineType, "GetEngineType", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetWagonEngineType, "GetWagonEngineType", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetUnitNumber, "GetUnitNumber", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetAge, "GetAge", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetWagonAge, "GetWagonAge", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetMaxAge, "GetMaxAge", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetAgeLeft, "GetAgeLeft", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCurrentSpeed, "GetCurrentSpeed", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetState, "GetState", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetRunningCost, "GetRunningCost", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetProfitThisYear, "GetProfitThisYear", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetProfitLastYear, "GetProfitLastYear", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCurrentValue, "GetCurrentValue", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetVehicleType, "GetVehicleType", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetRoadType, "GetRoadType", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsInDepot, "IsInDepot", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsStoppedInDepot, "IsStoppedInDepot", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::BuildVehicle, "BuildVehicle", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::CloneVehicle, "CloneVehicle", 4, ".iib"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagon, "MoveWagon", 5, ".iiii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::MoveWagonChain, "MoveWagonChain", 5, ".iiii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetRefitCapacity, "GetRefitCapacity", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::RefitVehicle, "RefitVehicle", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SellVehicle, "SellVehicle", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SellWagon, "SellWagon", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SellWagonChain, "SellWagonChain", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SendVehicleToDepot, "SendVehicleToDepot", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::SendVehicleToDepotForServicing, "SendVehicleToDepotForServicing", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::StartStopVehicle, "StartStopVehicle", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::ReverseVehicle, "ReverseVehicle", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCapacity, "GetCapacity", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetLength, "GetLength", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetCargoLoad, "GetCargoLoad", 3, ".ii"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetGroupID, "GetGroupID", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::IsArticulated, "IsArticulated", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::HasSharedOrders, "HasSharedOrders", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetReliability, "GetReliability", 2, ".i"); SQGSVehicle.DefSQStaticMethod(engine, &ScriptVehicle::GetMaximumOrderDistance, "GetMaximumOrderDistance", 2, ".i"); SQGSVehicle.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_bridge.hpp.sq0000644000000000000000000000656312627373433021054 0ustar rootroot/* $Id: game_bridge.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_bridge.hpp" #include "../template/template_bridge.hpp.sq" template <> const char *GetClassName() { return "GSBridge"; } void SQGSBridge_Register(Squirrel *engine) { DefSQClass SQGSBridge("GSBridge"); SQGSBridge.PreRegister(engine); SQGSBridge.AddConstructor(engine, "x"); SQGSBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_BASE, "ERR_BRIDGE_BASE"); SQGSBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_TYPE_UNAVAILABLE, "ERR_BRIDGE_TYPE_UNAVAILABLE"); SQGSBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER, "ERR_BRIDGE_CANNOT_END_IN_WATER"); SQGSBridge.DefSQConst(engine, ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, "ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT"); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, ScriptBridge::ERR_BRIDGE_TYPE_UNAVAILABLE); ScriptError::RegisterErrorMap(STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH, ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER); ScriptError::RegisterErrorMap(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT, ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT); ScriptError::RegisterErrorMapString(ScriptBridge::ERR_BRIDGE_TYPE_UNAVAILABLE, "ERR_BRIDGE_TYPE_UNAVAILABLE"); ScriptError::RegisterErrorMapString(ScriptBridge::ERR_BRIDGE_CANNOT_END_IN_WATER, "ERR_BRIDGE_CANNOT_END_IN_WATER"); ScriptError::RegisterErrorMapString(ScriptBridge::ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT, "ERR_BRIDGE_HEADS_NOT_ON_SAME_HEIGHT"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::IsValidBridge, "IsValidBridge", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::IsBridgeTile, "IsBridgeTile", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::GetBridgeID, "GetBridgeID", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::GetName, "GetName", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::GetPrice, "GetPrice", 3, ".ii"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::GetMaxLength, "GetMaxLength", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::GetMinLength, "GetMinLength", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::BuildBridge, "BuildBridge", 5, ".iiii"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::RemoveBridge, "RemoveBridge", 2, ".i"); SQGSBridge.DefSQStaticMethod(engine, &ScriptBridge::GetOtherBridgeEnd, "GetOtherBridgeEnd", 2, ".i"); SQGSBridge.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_townlist.hpp.sq0000644000000000000000000000305112627373433021470 0ustar rootroot/* $Id: game_townlist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_townlist.hpp" #include "../template/template_townlist.hpp.sq" template <> const char *GetClassName() { return "GSTownList"; } void SQGSTownList_Register(Squirrel *engine) { DefSQClass SQGSTownList("GSTownList"); SQGSTownList.PreRegister(engine, "GSList"); SQGSTownList.AddConstructor(engine, "x"); SQGSTownList.PostRegister(engine); } template <> const char *GetClassName() { return "GSTownEffectList"; } void SQGSTownEffectList_Register(Squirrel *engine) { DefSQClass SQGSTownEffectList("GSTownEffectList"); SQGSTownEffectList.PreRegister(engine, "GSList"); SQGSTownEffectList.AddConstructor(engine, "x"); SQGSTownEffectList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_waypoint.hpp.sq0000644000000000000000000000532412627373433021464 0ustar rootroot/* $Id: game_waypoint.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_waypoint.hpp" #include "../template/template_waypoint.hpp.sq" template <> const char *GetClassName() { return "GSWaypoint"; } void SQGSWaypoint_Register(Squirrel *engine) { DefSQClass SQGSWaypoint("GSWaypoint"); SQGSWaypoint.PreRegister(engine, "GSBaseStation"); SQGSWaypoint.AddConstructor(engine, "x"); SQGSWaypoint.DefSQConst(engine, ScriptWaypoint::ERR_WAYPOINT_BASE, "ERR_WAYPOINT_BASE"); SQGSWaypoint.DefSQConst(engine, ScriptWaypoint::ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT, "ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT"); SQGSWaypoint.DefSQConst(engine, ScriptWaypoint::ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS, "ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS"); SQGSWaypoint.DefSQConst(engine, ScriptWaypoint::WAYPOINT_RAIL, "WAYPOINT_RAIL"); SQGSWaypoint.DefSQConst(engine, ScriptWaypoint::WAYPOINT_BUOY, "WAYPOINT_BUOY"); SQGSWaypoint.DefSQConst(engine, ScriptWaypoint::WAYPOINT_ANY, "WAYPOINT_ANY"); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT, ScriptWaypoint::ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT); ScriptError::RegisterErrorMap(STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING, ScriptWaypoint::ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS); ScriptError::RegisterErrorMapString(ScriptWaypoint::ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT, "ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT"); ScriptError::RegisterErrorMapString(ScriptWaypoint::ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS, "ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS"); SQGSWaypoint.DefSQStaticMethod(engine, &ScriptWaypoint::IsValidWaypoint, "IsValidWaypoint", 2, ".i"); SQGSWaypoint.DefSQStaticMethod(engine, &ScriptWaypoint::GetWaypointID, "GetWaypointID", 2, ".i"); SQGSWaypoint.DefSQStaticMethod(engine, &ScriptWaypoint::HasWaypointType, "HasWaypointType", 3, ".ii"); SQGSWaypoint.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_depotlist.hpp.sq0000644000000000000000000000227512627373433021623 0ustar rootroot/* $Id: game_depotlist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_depotlist.hpp" #include "../template/template_depotlist.hpp.sq" template <> const char *GetClassName() { return "GSDepotList"; } void SQGSDepotList_Register(Squirrel *engine) { DefSQClass SQGSDepotList("GSDepotList"); SQGSDepotList.PreRegister(engine, "GSList"); SQGSDepotList.AddConstructor(engine, "xi"); SQGSDepotList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_airport.hpp.sq0000644000000000000000000001037712627373433021276 0ustar rootroot/* $Id: game_airport.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_airport.hpp" #include "../template/template_airport.hpp.sq" template <> const char *GetClassName() { return "GSAirport"; } void SQGSAirport_Register(Squirrel *engine) { DefSQClass SQGSAirport("GSAirport"); SQGSAirport.PreRegister(engine); SQGSAirport.AddConstructor(engine, "x"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_SMALL, "AT_SMALL"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_LARGE, "AT_LARGE"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_METROPOLITAN, "AT_METROPOLITAN"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_INTERNATIONAL, "AT_INTERNATIONAL"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_COMMUTER, "AT_COMMUTER"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_INTERCON, "AT_INTERCON"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_HELIPORT, "AT_HELIPORT"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_HELISTATION, "AT_HELISTATION"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_HELIDEPOT, "AT_HELIDEPOT"); SQGSAirport.DefSQConst(engine, ScriptAirport::AT_INVALID, "AT_INVALID"); SQGSAirport.DefSQConst(engine, ScriptAirport::PT_HELICOPTER, "PT_HELICOPTER"); SQGSAirport.DefSQConst(engine, ScriptAirport::PT_SMALL_PLANE, "PT_SMALL_PLANE"); SQGSAirport.DefSQConst(engine, ScriptAirport::PT_BIG_PLANE, "PT_BIG_PLANE"); SQGSAirport.DefSQConst(engine, ScriptAirport::PT_INVALID, "PT_INVALID"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::IsValidAirportType, "IsValidAirportType", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::IsAirportInformationAvailable, "IsAirportInformationAvailable", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetPrice, "GetPrice", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::IsHangarTile, "IsHangarTile", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::IsAirportTile, "IsAirportTile", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportWidth, "GetAirportWidth", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportHeight, "GetAirportHeight", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportCoverageRadius, "GetAirportCoverageRadius", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetNumHangars, "GetNumHangars", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetHangarOfAirport, "GetHangarOfAirport", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::BuildAirport, "BuildAirport", 4, ".iii"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::RemoveAirport, "RemoveAirport", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetAirportType, "GetAirportType", 2, ".i"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetNoiseLevelIncrease, "GetNoiseLevelIncrease", 3, ".ii"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetNearestTown, "GetNearestTown", 3, ".ii"); SQGSAirport.DefSQStaticMethod(engine, &ScriptAirport::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQGSAirport.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_tile.hpp.sq0000644000000000000000000002407512627373433020553 0ustar rootroot/* $Id: game_tile.hpp.sq 25213 2013-04-30 17:16:32Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tile.hpp" #include "../template/template_tile.hpp.sq" template <> const char *GetClassName() { return "GSTile"; } void SQGSTile_Register(Squirrel *engine) { DefSQClass SQGSTile("GSTile"); SQGSTile.PreRegister(engine); SQGSTile.AddConstructor(engine, "x"); SQGSTile.DefSQConst(engine, ScriptTile::ERR_TILE_BASE, "ERR_TILE_BASE"); SQGSTile.DefSQConst(engine, ScriptTile::ERR_TILE_TOO_HIGH, "ERR_TILE_TOO_HIGH"); SQGSTile.DefSQConst(engine, ScriptTile::ERR_TILE_TOO_LOW, "ERR_TILE_TOO_LOW"); SQGSTile.DefSQConst(engine, ScriptTile::ERR_AREA_ALREADY_FLAT, "ERR_AREA_ALREADY_FLAT"); SQGSTile.DefSQConst(engine, ScriptTile::ERR_EXCAVATION_WOULD_DAMAGE, "ERR_EXCAVATION_WOULD_DAMAGE"); SQGSTile.DefSQConst(engine, ScriptTile::CORNER_W, "CORNER_W"); SQGSTile.DefSQConst(engine, ScriptTile::CORNER_S, "CORNER_S"); SQGSTile.DefSQConst(engine, ScriptTile::CORNER_E, "CORNER_E"); SQGSTile.DefSQConst(engine, ScriptTile::CORNER_N, "CORNER_N"); SQGSTile.DefSQConst(engine, ScriptTile::CORNER_INVALID, "CORNER_INVALID"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_FLAT, "SLOPE_FLAT"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_W, "SLOPE_W"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_S, "SLOPE_S"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_E, "SLOPE_E"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_N, "SLOPE_N"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_STEEP, "SLOPE_STEEP"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_NW, "SLOPE_NW"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_SW, "SLOPE_SW"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_SE, "SLOPE_SE"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_NE, "SLOPE_NE"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_EW, "SLOPE_EW"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_NS, "SLOPE_NS"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_ELEVATED, "SLOPE_ELEVATED"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_NWS, "SLOPE_NWS"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_WSE, "SLOPE_WSE"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_SEN, "SLOPE_SEN"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_ENW, "SLOPE_ENW"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_W, "SLOPE_STEEP_W"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_S, "SLOPE_STEEP_S"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_E, "SLOPE_STEEP_E"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_STEEP_N, "SLOPE_STEEP_N"); SQGSTile.DefSQConst(engine, ScriptTile::SLOPE_INVALID, "SLOPE_INVALID"); SQGSTile.DefSQConst(engine, ScriptTile::TRANSPORT_RAIL, "TRANSPORT_RAIL"); SQGSTile.DefSQConst(engine, ScriptTile::TRANSPORT_ROAD, "TRANSPORT_ROAD"); SQGSTile.DefSQConst(engine, ScriptTile::TRANSPORT_WATER, "TRANSPORT_WATER"); SQGSTile.DefSQConst(engine, ScriptTile::TRANSPORT_AIR, "TRANSPORT_AIR"); SQGSTile.DefSQConst(engine, ScriptTile::TRANSPORT_INVALID, "TRANSPORT_INVALID"); SQGSTile.DefSQConst(engine, ScriptTile::BT_FOUNDATION, "BT_FOUNDATION"); SQGSTile.DefSQConst(engine, ScriptTile::BT_TERRAFORM, "BT_TERRAFORM"); SQGSTile.DefSQConst(engine, ScriptTile::BT_BUILD_TREES, "BT_BUILD_TREES"); SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_GRASS, "BT_CLEAR_GRASS"); SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_ROUGH, "BT_CLEAR_ROUGH"); SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_ROCKY, "BT_CLEAR_ROCKY"); SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_FIELDS, "BT_CLEAR_FIELDS"); SQGSTile.DefSQConst(engine, ScriptTile::BT_CLEAR_HOUSE, "BT_CLEAR_HOUSE"); SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_NORMAL, "TERRAIN_NORMAL"); SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_DESERT, "TERRAIN_DESERT"); SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_RAINFOREST, "TERRAIN_RAINFOREST"); SQGSTile.DefSQConst(engine, ScriptTile::TERRAIN_SNOW, "TERRAIN_SNOW"); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_HIGH); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_AT_SEA_LEVEL, ScriptTile::ERR_TILE_TOO_LOW); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_LEVELLED, ScriptTile::ERR_AREA_ALREADY_FLAT); ScriptError::RegisterErrorMap(STR_ERROR_EXCAVATION_WOULD_DAMAGE, ScriptTile::ERR_EXCAVATION_WOULD_DAMAGE); ScriptError::RegisterErrorMapString(ScriptTile::ERR_TILE_TOO_HIGH, "ERR_TILE_TOO_HIGH"); ScriptError::RegisterErrorMapString(ScriptTile::ERR_TILE_TOO_LOW, "ERR_TILE_TOO_LOW"); ScriptError::RegisterErrorMapString(ScriptTile::ERR_AREA_ALREADY_FLAT, "ERR_AREA_ALREADY_FLAT"); ScriptError::RegisterErrorMapString(ScriptTile::ERR_EXCAVATION_WOULD_DAMAGE, "ERR_EXCAVATION_WOULD_DAMAGE"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsBuildable, "IsBuildable", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsBuildableRectangle, "IsBuildableRectangle", 4, ".iii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsWaterTile, "IsWaterTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsCoastTile, "IsCoastTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsStationTile, "IsStationTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsSteepSlope, "IsSteepSlope", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsHalftileSlope, "IsHalftileSlope", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::HasTreeOnTile, "HasTreeOnTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsFarmTile, "IsFarmTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsRockTile, "IsRockTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsRoughTile, "IsRoughTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsSnowTile, "IsSnowTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsDesertTile, "IsDesertTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetTerrainType, "GetTerrainType", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetSlope, "GetSlope", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetComplementSlope, "GetComplementSlope", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetMinHeight, "GetMinHeight", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetMaxHeight, "GetMaxHeight", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetCornerHeight, "GetCornerHeight", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetOwner, "GetOwner", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::HasTransportType, "HasTransportType", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetCargoAcceptance, "GetCargoAcceptance", 6, ".iiiii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetCargoProduction, "GetCargoProduction", 6, ".iiiii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::RaiseTile, "RaiseTile", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::LowerTile, "LowerTile", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::LevelTiles, "LevelTiles", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::DemolishTile, "DemolishTile", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::PlantTree, "PlantTree", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::PlantTreeRectangle, "PlantTreeRectangle", 4, ".iii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::IsWithinTownInfluence, "IsWithinTownInfluence", 3, ".ii"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetTownAuthority, "GetTownAuthority", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetClosestTown, "GetClosestTown", 2, ".i"); SQGSTile.DefSQStaticMethod(engine, &ScriptTile::GetBuildCost, "GetBuildCost", 2, ".i"); SQGSTile.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_subsidylist.hpp.sq0000644000000000000000000000225612627373433022171 0ustar rootroot/* $Id: game_subsidylist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_subsidylist.hpp" #include "../template/template_subsidylist.hpp.sq" template <> const char *GetClassName() { return "GSSubsidyList"; } void SQGSSubsidyList_Register(Squirrel *engine) { DefSQClass SQGSSubsidyList("GSSubsidyList"); SQGSSubsidyList.PreRegister(engine, "GSList"); SQGSSubsidyList.AddConstructor(engine, "x"); SQGSSubsidyList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_event_types.hpp.sq0000644000000000000000000003351512627373433022162 0ustar rootroot/* $Id: game_event_types.hpp.sq 24291 2012-05-26 14:16:45Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_event_types.hpp" #include "../template/template_event_types.hpp.sq" template <> const char *GetClassName() { return "GSEventVehicleCrashed"; } void SQGSEventVehicleCrashed_Register(Squirrel *engine) { DefSQClass SQGSEventVehicleCrashed("GSEventVehicleCrashed"); SQGSEventVehicleCrashed.PreRegister(engine, "GSEvent"); SQGSEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_TRAIN, "CRASH_TRAIN"); SQGSEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING, "CRASH_RV_LEVEL_CROSSING"); SQGSEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_RV_UFO, "CRASH_RV_UFO"); SQGSEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, "CRASH_PLANE_LANDING"); SQGSEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT, "CRASH_AIRCRAFT_NO_AIRPORT"); SQGSEventVehicleCrashed.DefSQConst(engine, ScriptEventVehicleCrashed::CRASH_FLOODED, "CRASH_FLOODED"); SQGSEventVehicleCrashed.DefSQStaticMethod(engine, &ScriptEventVehicleCrashed::Convert, "Convert", 2, ".x"); SQGSEventVehicleCrashed.DefSQMethod(engine, &ScriptEventVehicleCrashed::GetVehicleID, "GetVehicleID", 1, "x"); SQGSEventVehicleCrashed.DefSQMethod(engine, &ScriptEventVehicleCrashed::GetCrashSite, "GetCrashSite", 1, "x"); SQGSEventVehicleCrashed.DefSQMethod(engine, &ScriptEventVehicleCrashed::GetCrashReason, "GetCrashReason", 1, "x"); SQGSEventVehicleCrashed.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventSubsidyOffer"; } void SQGSEventSubsidyOffer_Register(Squirrel *engine) { DefSQClass SQGSEventSubsidyOffer("GSEventSubsidyOffer"); SQGSEventSubsidyOffer.PreRegister(engine, "GSEvent"); SQGSEventSubsidyOffer.DefSQStaticMethod(engine, &ScriptEventSubsidyOffer::Convert, "Convert", 2, ".x"); SQGSEventSubsidyOffer.DefSQMethod(engine, &ScriptEventSubsidyOffer::GetSubsidyID, "GetSubsidyID", 1, "x"); SQGSEventSubsidyOffer.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventSubsidyOfferExpired"; } void SQGSEventSubsidyOfferExpired_Register(Squirrel *engine) { DefSQClass SQGSEventSubsidyOfferExpired("GSEventSubsidyOfferExpired"); SQGSEventSubsidyOfferExpired.PreRegister(engine, "GSEvent"); SQGSEventSubsidyOfferExpired.DefSQStaticMethod(engine, &ScriptEventSubsidyOfferExpired::Convert, "Convert", 2, ".x"); SQGSEventSubsidyOfferExpired.DefSQMethod(engine, &ScriptEventSubsidyOfferExpired::GetSubsidyID, "GetSubsidyID", 1, "x"); SQGSEventSubsidyOfferExpired.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventSubsidyAwarded"; } void SQGSEventSubsidyAwarded_Register(Squirrel *engine) { DefSQClass SQGSEventSubsidyAwarded("GSEventSubsidyAwarded"); SQGSEventSubsidyAwarded.PreRegister(engine, "GSEvent"); SQGSEventSubsidyAwarded.DefSQStaticMethod(engine, &ScriptEventSubsidyAwarded::Convert, "Convert", 2, ".x"); SQGSEventSubsidyAwarded.DefSQMethod(engine, &ScriptEventSubsidyAwarded::GetSubsidyID, "GetSubsidyID", 1, "x"); SQGSEventSubsidyAwarded.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventSubsidyExpired"; } void SQGSEventSubsidyExpired_Register(Squirrel *engine) { DefSQClass SQGSEventSubsidyExpired("GSEventSubsidyExpired"); SQGSEventSubsidyExpired.PreRegister(engine, "GSEvent"); SQGSEventSubsidyExpired.DefSQStaticMethod(engine, &ScriptEventSubsidyExpired::Convert, "Convert", 2, ".x"); SQGSEventSubsidyExpired.DefSQMethod(engine, &ScriptEventSubsidyExpired::GetSubsidyID, "GetSubsidyID", 1, "x"); SQGSEventSubsidyExpired.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventCompanyNew"; } void SQGSEventCompanyNew_Register(Squirrel *engine) { DefSQClass SQGSEventCompanyNew("GSEventCompanyNew"); SQGSEventCompanyNew.PreRegister(engine, "GSEvent"); SQGSEventCompanyNew.DefSQStaticMethod(engine, &ScriptEventCompanyNew::Convert, "Convert", 2, ".x"); SQGSEventCompanyNew.DefSQMethod(engine, &ScriptEventCompanyNew::GetCompanyID, "GetCompanyID", 1, "x"); SQGSEventCompanyNew.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventCompanyInTrouble"; } void SQGSEventCompanyInTrouble_Register(Squirrel *engine) { DefSQClass SQGSEventCompanyInTrouble("GSEventCompanyInTrouble"); SQGSEventCompanyInTrouble.PreRegister(engine, "GSEvent"); SQGSEventCompanyInTrouble.DefSQStaticMethod(engine, &ScriptEventCompanyInTrouble::Convert, "Convert", 2, ".x"); SQGSEventCompanyInTrouble.DefSQMethod(engine, &ScriptEventCompanyInTrouble::GetCompanyID, "GetCompanyID", 1, "x"); SQGSEventCompanyInTrouble.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventCompanyMerger"; } void SQGSEventCompanyMerger_Register(Squirrel *engine) { DefSQClass SQGSEventCompanyMerger("GSEventCompanyMerger"); SQGSEventCompanyMerger.PreRegister(engine, "GSEvent"); SQGSEventCompanyMerger.DefSQStaticMethod(engine, &ScriptEventCompanyMerger::Convert, "Convert", 2, ".x"); SQGSEventCompanyMerger.DefSQMethod(engine, &ScriptEventCompanyMerger::GetOldCompanyID, "GetOldCompanyID", 1, "x"); SQGSEventCompanyMerger.DefSQMethod(engine, &ScriptEventCompanyMerger::GetNewCompanyID, "GetNewCompanyID", 1, "x"); SQGSEventCompanyMerger.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventCompanyBankrupt"; } void SQGSEventCompanyBankrupt_Register(Squirrel *engine) { DefSQClass SQGSEventCompanyBankrupt("GSEventCompanyBankrupt"); SQGSEventCompanyBankrupt.PreRegister(engine, "GSEvent"); SQGSEventCompanyBankrupt.DefSQStaticMethod(engine, &ScriptEventCompanyBankrupt::Convert, "Convert", 2, ".x"); SQGSEventCompanyBankrupt.DefSQMethod(engine, &ScriptEventCompanyBankrupt::GetCompanyID, "GetCompanyID", 1, "x"); SQGSEventCompanyBankrupt.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventIndustryOpen"; } void SQGSEventIndustryOpen_Register(Squirrel *engine) { DefSQClass SQGSEventIndustryOpen("GSEventIndustryOpen"); SQGSEventIndustryOpen.PreRegister(engine, "GSEvent"); SQGSEventIndustryOpen.DefSQStaticMethod(engine, &ScriptEventIndustryOpen::Convert, "Convert", 2, ".x"); SQGSEventIndustryOpen.DefSQMethod(engine, &ScriptEventIndustryOpen::GetIndustryID, "GetIndustryID", 1, "x"); SQGSEventIndustryOpen.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventIndustryClose"; } void SQGSEventIndustryClose_Register(Squirrel *engine) { DefSQClass SQGSEventIndustryClose("GSEventIndustryClose"); SQGSEventIndustryClose.PreRegister(engine, "GSEvent"); SQGSEventIndustryClose.DefSQStaticMethod(engine, &ScriptEventIndustryClose::Convert, "Convert", 2, ".x"); SQGSEventIndustryClose.DefSQMethod(engine, &ScriptEventIndustryClose::GetIndustryID, "GetIndustryID", 1, "x"); SQGSEventIndustryClose.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventStationFirstVehicle"; } void SQGSEventStationFirstVehicle_Register(Squirrel *engine) { DefSQClass SQGSEventStationFirstVehicle("GSEventStationFirstVehicle"); SQGSEventStationFirstVehicle.PreRegister(engine, "GSEvent"); SQGSEventStationFirstVehicle.DefSQStaticMethod(engine, &ScriptEventStationFirstVehicle::Convert, "Convert", 2, ".x"); SQGSEventStationFirstVehicle.DefSQMethod(engine, &ScriptEventStationFirstVehicle::GetStationID, "GetStationID", 1, "x"); SQGSEventStationFirstVehicle.DefSQMethod(engine, &ScriptEventStationFirstVehicle::GetVehicleID, "GetVehicleID", 1, "x"); SQGSEventStationFirstVehicle.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventTownFounded"; } void SQGSEventTownFounded_Register(Squirrel *engine) { DefSQClass SQGSEventTownFounded("GSEventTownFounded"); SQGSEventTownFounded.PreRegister(engine, "GSEvent"); SQGSEventTownFounded.DefSQStaticMethod(engine, &ScriptEventTownFounded::Convert, "Convert", 2, ".x"); SQGSEventTownFounded.DefSQMethod(engine, &ScriptEventTownFounded::GetTownID, "GetTownID", 1, "x"); SQGSEventTownFounded.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventAdminPort"; } void SQGSEventAdminPort_Register(Squirrel *engine) { DefSQClass SQGSEventAdminPort("GSEventAdminPort"); SQGSEventAdminPort.PreRegister(engine, "GSEvent"); SQGSEventAdminPort.DefSQStaticMethod(engine, &ScriptEventAdminPort::Convert, "Convert", 2, ".x"); SQGSEventAdminPort.DefSQAdvancedMethod(engine, &ScriptEventAdminPort::GetObject, "GetObject"); SQGSEventAdminPort.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventWindowWidgetClick"; } void SQGSEventWindowWidgetClick_Register(Squirrel *engine) { DefSQClass SQGSEventWindowWidgetClick("GSEventWindowWidgetClick"); SQGSEventWindowWidgetClick.PreRegister(engine, "GSEvent"); SQGSEventWindowWidgetClick.DefSQStaticMethod(engine, &ScriptEventWindowWidgetClick::Convert, "Convert", 2, ".x"); SQGSEventWindowWidgetClick.DefSQMethod(engine, &ScriptEventWindowWidgetClick::GetWindowClass, "GetWindowClass", 1, "x"); SQGSEventWindowWidgetClick.DefSQMethod(engine, &ScriptEventWindowWidgetClick::GetWindowNumber, "GetWindowNumber", 1, "x"); SQGSEventWindowWidgetClick.DefSQMethod(engine, &ScriptEventWindowWidgetClick::GetWidgetNumber, "GetWidgetNumber", 1, "x"); SQGSEventWindowWidgetClick.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventGoalQuestionAnswer"; } void SQGSEventGoalQuestionAnswer_Register(Squirrel *engine) { DefSQClass SQGSEventGoalQuestionAnswer("GSEventGoalQuestionAnswer"); SQGSEventGoalQuestionAnswer.PreRegister(engine, "GSEvent"); SQGSEventGoalQuestionAnswer.DefSQStaticMethod(engine, &ScriptEventGoalQuestionAnswer::Convert, "Convert", 2, ".x"); SQGSEventGoalQuestionAnswer.DefSQMethod(engine, &ScriptEventGoalQuestionAnswer::GetUniqueID, "GetUniqueID", 1, "x"); SQGSEventGoalQuestionAnswer.DefSQMethod(engine, &ScriptEventGoalQuestionAnswer::GetCompany, "GetCompany", 1, "x"); SQGSEventGoalQuestionAnswer.DefSQMethod(engine, &ScriptEventGoalQuestionAnswer::GetButton, "GetButton", 1, "x"); SQGSEventGoalQuestionAnswer.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventCompanyTown"; } void SQGSEventCompanyTown_Register(Squirrel *engine) { DefSQClass SQGSEventCompanyTown("GSEventCompanyTown"); SQGSEventCompanyTown.PreRegister(engine, "GSEvent"); SQGSEventCompanyTown.DefSQStaticMethod(engine, &ScriptEventCompanyTown::Convert, "Convert", 2, ".x"); SQGSEventCompanyTown.DefSQMethod(engine, &ScriptEventCompanyTown::GetCompanyID, "GetCompanyID", 1, "x"); SQGSEventCompanyTown.DefSQMethod(engine, &ScriptEventCompanyTown::GetTownID, "GetTownID", 1, "x"); SQGSEventCompanyTown.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventExclusiveTransportRights"; } void SQGSEventExclusiveTransportRights_Register(Squirrel *engine) { DefSQClass SQGSEventExclusiveTransportRights("GSEventExclusiveTransportRights"); SQGSEventExclusiveTransportRights.PreRegister(engine, "GSEventCompanyTown"); SQGSEventExclusiveTransportRights.AddConstructor(engine, "xii"); SQGSEventExclusiveTransportRights.DefSQStaticMethod(engine, &ScriptEventExclusiveTransportRights::Convert, "Convert", 2, ".x"); SQGSEventExclusiveTransportRights.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventRoadReconstruction"; } void SQGSEventRoadReconstruction_Register(Squirrel *engine) { DefSQClass SQGSEventRoadReconstruction("GSEventRoadReconstruction"); SQGSEventRoadReconstruction.PreRegister(engine, "GSEventCompanyTown"); SQGSEventRoadReconstruction.AddConstructor(engine, "xii"); SQGSEventRoadReconstruction.DefSQStaticMethod(engine, &ScriptEventRoadReconstruction::Convert, "Convert", 2, ".x"); SQGSEventRoadReconstruction.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_subsidy.hpp.sq0000644000000000000000000000463512627373433021300 0ustar rootroot/* $Id: game_subsidy.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_subsidy.hpp" #include "../template/template_subsidy.hpp.sq" template <> const char *GetClassName() { return "GSSubsidy"; } void SQGSSubsidy_Register(Squirrel *engine) { DefSQClass SQGSSubsidy("GSSubsidy"); SQGSSubsidy.PreRegister(engine); SQGSSubsidy.AddConstructor(engine, "x"); SQGSSubsidy.DefSQConst(engine, ScriptSubsidy::SPT_INDUSTRY, "SPT_INDUSTRY"); SQGSSubsidy.DefSQConst(engine, ScriptSubsidy::SPT_TOWN, "SPT_TOWN"); SQGSSubsidy.DefSQConst(engine, ScriptSubsidy::SPT_INVALID, "SPT_INVALID"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::IsValidSubsidy, "IsValidSubsidy", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::IsAwarded, "IsAwarded", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::Create, "Create", 6, ".iiiii"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetAwardedTo, "GetAwardedTo", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetExpireDate, "GetExpireDate", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetCargoType, "GetCargoType", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetSourceType, "GetSourceType", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetSourceIndex, "GetSourceIndex", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetDestinationType, "GetDestinationType", 2, ".i"); SQGSSubsidy.DefSQStaticMethod(engine, &ScriptSubsidy::GetDestinationIndex, "GetDestinationIndex", 2, ".i"); SQGSSubsidy.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_story_page.hpp.sq0000644000000000000000000000643612627373433021773 0ustar rootroot/* $Id: game_story_page.hpp.sq 26306 2014-02-06 19:48:19Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_story_page.hpp" #include "../template/template_story_page.hpp.sq" template <> const char *GetClassName() { return "GSStoryPage"; } void SQGSStoryPage_Register(Squirrel *engine) { DefSQClass SQGSStoryPage("GSStoryPage"); SQGSStoryPage.PreRegister(engine); SQGSStoryPage.AddConstructor(engine, "x"); SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::STORY_PAGE_INVALID, "STORY_PAGE_INVALID"); SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::STORY_PAGE_ELEMENT_INVALID, "STORY_PAGE_ELEMENT_INVALID"); SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::SPET_TEXT, "SPET_TEXT"); SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::SPET_LOCATION, "SPET_LOCATION"); SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::SPET_GOAL, "SPET_GOAL"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::IsValidStoryPage, "IsValidStoryPage", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::IsValidStoryPageElement, "IsValidStoryPageElement", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::New, "New", 3, ".i."); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::NewElement, "NewElement", 5, ".iii."); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::UpdateElement, "UpdateElement", 4, ".ii."); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::GetPageSortValue, "GetPageSortValue", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::GetPageElementSortValue, "GetPageElementSortValue", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::GetCompany, "GetCompany", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::GetDate, "GetDate", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::SetDate, "SetDate", 3, ".ii"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::SetTitle, "SetTitle", 3, ".i."); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::Show, "Show", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::Remove, "Remove", 2, ".i"); SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::RemoveElement, "RemoveElement", 2, ".i"); SQGSStoryPage.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_window.hpp.sq0000644000000000000000000043526512627373433021134 0ustar rootroot/* $Id: game_window.hpp.sq 27174 2015-03-01 08:17:14Z alberth $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_window.hpp" #include "../template/template_window.hpp.sq" template <> const char *GetClassName() { return "GSWindow"; } void SQGSWindow_Register(Squirrel *engine) { DefSQClass SQGSWindow("GSWindow"); SQGSWindow.PreRegister(engine); SQGSWindow.AddConstructor(engine, "x"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_AI, "WN_GAME_OPTIONS_AI"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_ABOUT, "WN_GAME_OPTIONS_ABOUT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_NEWGRF_STATE, "WN_GAME_OPTIONS_NEWGRF_STATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_OPTIONS, "WN_GAME_OPTIONS_GAME_OPTIONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_GAME_OPTIONS_GAME_SETTINGS, "WN_GAME_OPTIONS_GAME_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING, "WN_QUERY_STRING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_QUERY_STRING_SIGN, "WN_QUERY_STRING_SIGN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY, "WN_CONFIRM_POPUP_QUERY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, "WN_CONFIRM_POPUP_QUERY_BOOTSTRAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_GAME, "WN_NETWORK_WINDOW_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_LOBBY, "WN_NETWORK_WINDOW_LOBBY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_CONTENT_LIST, "WN_NETWORK_WINDOW_CONTENT_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_WINDOW_START, "WN_NETWORK_WINDOW_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_JOIN, "WN_NETWORK_STATUS_WINDOW_JOIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, "WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NONE, "WC_NONE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_WINDOW, "WC_MAIN_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MAIN_TOOLBAR, "WC_MAIN_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATUS_BAR, "WC_STATUS_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TOOLBAR, "WC_BUILD_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_BUILD_TOOLBAR, "WC_SCEN_BUILD_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_TREES, "WC_BUILD_TREES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRANSPARENCY_TOOLBAR, "WC_TRANSPARENCY_TOOLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_SIGNAL, "WC_BUILD_SIGNAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SMALLMAP, "WC_SMALLMAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ERRMSG, "WC_ERRMSG"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOOLTIPS, "WC_TOOLTIPS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_QUERY_STRING, "WC_QUERY_STRING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONFIRM_POPUP_QUERY, "WC_CONFIRM_POPUP_QUERY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOAL_QUESTION, "WC_GOAL_QUESTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SAVELOAD, "WC_SAVELOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LAND_INFO, "WC_LAND_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DROPDOWN_MENU, "WC_DROPDOWN_MENU"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OSK, "WC_OSK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SET_DATE, "WC_SET_DATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_SETTINGS, "WC_AI_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRF_PARAMETERS, "WC_GRF_PARAMETERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TEXTFILE, "WC_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_AUTHORITY, "WC_TOWN_AUTHORITY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DETAILS, "WC_VEHICLE_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_REFIT, "WC_VEHICLE_REFIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_ORDERS, "WC_VEHICLE_ORDERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_REPLACE_VEHICLE, "WC_REPLACE_VEHICLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_TIMETABLE, "WC_VEHICLE_TIMETABLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_COLOUR, "WC_COMPANY_COLOUR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_MANAGER_FACE, "WC_COMPANY_MANAGER_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_STATION, "WC_SELECT_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWS_WINDOW, "WC_NEWS_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_DIRECTORY, "WC_TOWN_DIRECTORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SUBSIDIES_LIST, "WC_SUBSIDIES_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_DIRECTORY, "WC_INDUSTRY_DIRECTORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MESSAGE_HISTORY, "WC_MESSAGE_HISTORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SIGN_LIST, "WC_SIGN_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_LIST, "WC_AI_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOALS_LIST, "WC_GOALS_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STORY_BOOK, "WC_STORY_BOOK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_LIST, "WC_STATION_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRAINS_LIST, "WC_TRAINS_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ROADVEH_LIST, "WC_ROADVEH_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SHIPS_LIST, "WC_SHIPS_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AIRCRAFT_LIST, "WC_AIRCRAFT_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_VIEW, "WC_TOWN_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_VIEW, "WC_VEHICLE_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_VIEW, "WC_STATION_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DEPOT, "WC_VEHICLE_DEPOT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_WAYPOINT_VIEW, "WC_WAYPOINT_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_VIEW, "WC_INDUSTRY_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY, "WC_COMPANY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_OBJECT, "WC_BUILD_OBJECT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_VEHICLE, "WC_BUILD_VEHICLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_BRIDGE, "WC_BUILD_BRIDGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_STATION, "WC_BUILD_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUS_STATION, "WC_BUS_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRUCK_STATION, "WC_TRUCK_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_DEPOT, "WC_BUILD_DEPOT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_WAYPOINT, "WC_BUILD_WAYPOINT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FOUND_TOWN, "WC_FOUND_TOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUILD_INDUSTRY, "WC_BUILD_INDUSTRY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SELECT_GAME, "WC_SELECT_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SCEN_LAND_GEN, "WC_SCEN_LAND_GEN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GENERATE_LANDSCAPE, "WC_GENERATE_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MODAL_PROGRESS, "WC_MODAL_PROGRESS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_WINDOW, "WC_NETWORK_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST, "WC_CLIENT_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CLIENT_LIST_POPUP, "WC_CLIENT_LIST_POPUP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NETWORK_STATUS_WINDOW, "WC_NETWORK_STATUS_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SEND_NETWORK_MSG, "WC_SEND_NETWORK_MSG"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_PASSWORD_WINDOW, "WC_COMPANY_PASSWORD_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INDUSTRY_CARGOES, "WC_INDUSTRY_CARGOES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRAPH_LEGEND, "WC_GRAPH_LEGEND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_FINANCES, "WC_FINANCES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INCOME_GRAPH, "WC_INCOME_GRAPH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_OPERATING_PROFIT, "WC_OPERATING_PROFIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_DELIVERED_CARGO, "WC_DELIVERED_CARGO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_HISTORY, "WC_PERFORMANCE_HISTORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_VALUE, "WC_COMPANY_VALUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_LEAGUE, "WC_COMPANY_LEAGUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PAYMENT_RATES, "WC_PAYMENT_RATES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_PERFORMANCE_DETAIL, "WC_PERFORMANCE_DETAIL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_COMPANY_INFRASTRUCTURE, "WC_COMPANY_INFRASTRUCTURE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BUY_COMPANY, "WC_BUY_COMPANY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENGINE_PREVIEW, "WC_ENGINE_PREVIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_WINDOW, "WC_MUSIC_WINDOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_MUSIC_TRACK_SELECTION, "WC_MUSIC_TRACK_SELECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GAME_OPTIONS, "WC_GAME_OPTIONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CUSTOM_CURRENCY, "WC_CUSTOM_CURRENCY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CHEATS, "WC_CHEATS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_EXTRA_VIEW_PORT, "WC_EXTRA_VIEW_PORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_CONSOLE, "WC_CONSOLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_BOOTSTRAP, "WC_BOOTSTRAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_HIGHSCORE, "WC_HIGHSCORE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ENDSCREEN, "WC_ENDSCREEN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_DEBUG, "WC_AI_DEBUG"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWGRF_INSPECT, "WC_NEWGRF_INSPECT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SPRITE_ALIGNER, "WC_SPRITE_ALIGNER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_LINKGRAPH_LEGEND, "WC_LINKGRAPH_LEGEND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SAVE_PRESET, "WC_SAVE_PRESET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_INVALID, "WC_INVALID"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLUE, "TC_BLUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_SILVER, "TC_SILVER"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GOLD, "TC_GOLD"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_RED, "TC_RED"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_PURPLE, "TC_PURPLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BROWN, "TC_LIGHT_BROWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_ORANGE, "TC_ORANGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREEN, "TC_GREEN"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_YELLOW, "TC_YELLOW"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_GREEN, "TC_DARK_GREEN"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_CREAM, "TC_CREAM"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BROWN, "TC_BROWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_WHITE, "TC_WHITE"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_LIGHT_BLUE, "TC_LIGHT_BLUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_GREY, "TC_GREY"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_DARK_BLUE, "TC_DARK_BLUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_BLACK, "TC_BLACK"); SQGSWindow.DefSQConst(engine, ScriptWindow::TC_INVALID, "TC_INVALID"); SQGSWindow.DefSQConst(engine, ScriptWindow::NUMBER_ALL, "NUMBER_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WIDGET_ALL, "WIDGET_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CAPTION, "WID_AIL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_LIST, "WID_AIL_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_SCROLLBAR, "WID_AIL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_INFO_BG, "WID_AIL_INFO_BG"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_ACCEPT, "WID_AIL_ACCEPT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIL_CANCEL, "WID_AIL_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_CAPTION, "WID_AIS_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_BACKGROUND, "WID_AIS_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_SCROLLBAR, "WID_AIS_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_ACCEPT, "WID_AIS_ACCEPT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIS_RESET, "WID_AIS_RESET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_BACKGROUND, "WID_AIC_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_DECREASE, "WID_AIC_DECREASE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_INCREASE, "WID_AIC_INCREASE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_NUMBER, "WID_AIC_NUMBER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_GAMELIST, "WID_AIC_GAMELIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_LIST, "WID_AIC_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_SCROLLBAR, "WID_AIC_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_UP, "WID_AIC_MOVE_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_MOVE_DOWN, "WID_AIC_MOVE_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CHANGE, "WID_AIC_CHANGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONFIGURE, "WID_AIC_CONFIGURE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CLOSE, "WID_AIC_CLOSE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_TEXTFILE, "WID_AIC_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AIC_CONTENT_DOWNLOAD, "WID_AIC_CONTENT_DOWNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_VIEW, "WID_AID_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_NAME_TEXT, "WID_AID_NAME_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SETTINGS, "WID_AID_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCRIPT_GAME, "WID_AID_SCRIPT_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_RELOAD_TOGGLE, "WID_AID_RELOAD_TOGGLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_LOG_PANEL, "WID_AID_LOG_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_SCROLLBAR, "WID_AID_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_START, "WID_AID_COMPANY_BUTTON_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_COMPANY_BUTTON_END, "WID_AID_COMPANY_BUTTON_END"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STRING_WIDGETS, "WID_AID_BREAK_STRING_WIDGETS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_ON_OFF_BTN, "WID_AID_BREAK_STR_ON_OFF_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_BREAK_STR_EDIT_BOX, "WID_AID_BREAK_STR_EDIT_BOX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_MATCH_CASE_BTN, "WID_AID_MATCH_CASE_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AID_CONTINUE_BTN, "WID_AID_CONTINUE_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_AIRPORT, "WID_AT_AIRPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AT_DEMOLISH, "WID_AT_DEMOLISH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_CLASS_DROPDOWN, "WID_AP_CLASS_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_LIST, "WID_AP_AIRPORT_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_SCROLLBAR, "WID_AP_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_NUM, "WID_AP_LAYOUT_NUM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_DECREASE, "WID_AP_LAYOUT_DECREASE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_LAYOUT_INCREASE, "WID_AP_LAYOUT_INCREASE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_AIRPORT_SPRITE, "WID_AP_AIRPORT_SPRITE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_EXTRA_TEXT, "WID_AP_EXTRA_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BOTTOMPANEL, "WID_AP_BOTTOMPANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_COVERAGE_LABEL, "WID_AP_COVERAGE_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DONTHILIGHT, "WID_AP_BTN_DONTHILIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_AP_BTN_DOHILIGHT, "WID_AP_BTN_DOHILIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_CAPTION, "WID_RV_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_SORT_ASCENDING_DESCENDING, "WID_RV_SORT_ASCENDING_DESCENDING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_SHOW_HIDDEN_ENGINES, "WID_RV_SHOW_HIDDEN_ENGINES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_SORT_DROPDOWN, "WID_RV_SORT_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_MATRIX, "WID_RV_LEFT_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_SCROLLBAR, "WID_RV_LEFT_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_MATRIX, "WID_RV_RIGHT_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_SCROLLBAR, "WID_RV_RIGHT_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_LEFT_DETAILS, "WID_RV_LEFT_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_RIGHT_DETAILS, "WID_RV_RIGHT_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_START_REPLACE, "WID_RV_START_REPLACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_INFO_TAB, "WID_RV_INFO_TAB"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_STOP_REPLACE, "WID_RV_STOP_REPLACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, "WID_RV_TRAIN_ENGINEWAGON_TOGGLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_LEFT, "WID_RV_TRAIN_FLUFF_LEFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_RAILTYPE_DROPDOWN, "WID_RV_TRAIN_RAILTYPE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_FLUFF_RIGHT, "WID_RV_TRAIN_FLUFF_RIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, "WID_RV_TRAIN_WAGONREMOVE_TOGGLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BB_BACKGROUND, "WID_BB_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_QUESTION, "WID_BAFD_QUESTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_YES, "WID_BAFD_YES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BAFD_NO, "WID_BAFD_NO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_CAPTION, "WID_BBS_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_ORDER, "WID_BBS_DROPDOWN_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_DROPDOWN_CRITERIA, "WID_BBS_DROPDOWN_CRITERIA"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_BRIDGE_LIST, "WID_BBS_BRIDGE_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BBS_SCROLLBAR, "WID_BBS_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CAPTION, "WID_BV_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_ASCENDING_DESCENDING, "WID_BV_SORT_ASCENDING_DESCENDING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SORT_DROPDOWN, "WID_BV_SORT_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_CARGO_FILTER_DROPDOWN, "WID_BV_CARGO_FILTER_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SHOW_HIDDEN_ENGINES, "WID_BV_SHOW_HIDDEN_ENGINES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_LIST, "WID_BV_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SCROLLBAR, "WID_BV_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_PANEL, "WID_BV_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD, "WID_BV_BUILD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_SHOW_HIDE, "WID_BV_SHOW_HIDE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_BUILD_SEL, "WID_BV_BUILD_SEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BV_RENAME, "WID_BV_RENAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PANEL, "WID_C_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_CAPTION, "WID_C_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE, "WID_C_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_FACE_TITLE, "WID_C_FACE_TITLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INAUGURATION, "WID_C_DESC_INAUGURATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME, "WID_C_DESC_COLOUR_SCHEME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, "WID_C_DESC_COLOUR_SCHEME_EXAMPLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE, "WID_C_DESC_VEHICLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_VEHICLE_COUNTS, "WID_C_DESC_VEHICLE_COUNTS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_COMPANY_VALUE, "WID_C_DESC_COMPANY_VALUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE, "WID_C_DESC_INFRASTRUCTURE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_INFRASTRUCTURE_COUNTS, "WID_C_DESC_INFRASTRUCTURE_COUNTS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_DESC_OWNERS, "WID_C_SELECT_DESC_OWNERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_DESC_OWNERS, "WID_C_DESC_OWNERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_BUTTONS, "WID_C_SELECT_BUTTONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_NEW_FACE, "WID_C_NEW_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COLOUR_SCHEME, "WID_C_COLOUR_SCHEME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_PRESIDENT_NAME, "WID_C_PRESIDENT_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_NAME, "WID_C_COMPANY_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUY_SHARE, "WID_C_BUY_SHARE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELL_SHARE, "WID_C_SELL_SHARE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_VIEW_BUILD_HQ, "WID_C_SELECT_VIEW_BUILD_HQ"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_HQ, "WID_C_VIEW_HQ"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BUILD_HQ, "WID_C_BUILD_HQ"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_RELOCATE, "WID_C_SELECT_RELOCATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_RELOCATE_HQ, "WID_C_RELOCATE_HQ"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_VIEW_INFRASTRUCTURE, "WID_C_VIEW_INFRASTRUCTURE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_HAS_PASSWORD, "WID_C_HAS_PASSWORD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_SELECT_MULTIPLAYER, "WID_C_SELECT_MULTIPLAYER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_PASSWORD, "WID_C_COMPANY_PASSWORD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_COMPANY_JOIN, "WID_C_COMPANY_JOIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_CAPTION, "WID_CF_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOGGLE_SIZE, "WID_CF_TOGGLE_SIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_PANEL, "WID_CF_SEL_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_CATEGORY, "WID_CF_EXPS_CATEGORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE1, "WID_CF_EXPS_PRICE1"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE2, "WID_CF_EXPS_PRICE2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_EXPS_PRICE3, "WID_CF_EXPS_PRICE3"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_PANEL, "WID_CF_TOTAL_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_MAXLOAN, "WID_CF_SEL_MAXLOAN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_BALANCE_VALUE, "WID_CF_BALANCE_VALUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_VALUE, "WID_CF_LOAN_VALUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_LOAN_LINE, "WID_CF_LOAN_LINE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_TOTAL_VALUE, "WID_CF_TOTAL_VALUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_GAP, "WID_CF_MAXLOAN_GAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_MAXLOAN_VALUE, "WID_CF_MAXLOAN_VALUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_SEL_BUTTONS, "WID_CF_SEL_BUTTONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INCREASE_LOAN, "WID_CF_INCREASE_LOAN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_REPAY_LOAN, "WID_CF_REPAY_LOAN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CF_INFRASTRUCTURE, "WID_CF_INFRASTRUCTURE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CAPTION, "WID_SCL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_GENERAL, "WID_SCL_CLASS_GENERAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_RAIL, "WID_SCL_CLASS_RAIL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_ROAD, "WID_SCL_CLASS_ROAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_SHIP, "WID_SCL_CLASS_SHIP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_CLASS_AIRCRAFT, "WID_SCL_CLASS_AIRCRAFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SPACER_DROPDOWN, "WID_SCL_SPACER_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_PRI_COL_DROPDOWN, "WID_SCL_PRI_COL_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_SEC_COL_DROPDOWN, "WID_SCL_SEC_COL_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCL_MATRIX, "WID_SCL_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CAPTION, "WID_SCMF_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL, "WID_SCMF_TOGGLE_LARGE_SMALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SELECT_FACE, "WID_SCMF_SELECT_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CANCEL, "WID_SCMF_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ACCEPT, "WID_SCMF_ACCEPT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE, "WID_SCMF_MALE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE, "WID_SCMF_FEMALE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_MALE2, "WID_SCMF_MALE2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FEMALE2, "WID_SCMF_FEMALE2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_LOADSAVE, "WID_SCMF_SEL_LOADSAVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_MALEFEMALE, "WID_SCMF_SEL_MALEFEMALE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SEL_PARTS, "WID_SCMF_SEL_PARTS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_RANDOM_NEW_FACE, "WID_SCMF_RANDOM_NEW_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, "WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACE, "WID_SCMF_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LOAD, "WID_SCMF_LOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_FACECODE, "WID_SCMF_FACECODE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_SAVE, "WID_SCMF_SAVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, "WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_TEXT, "WID_SCMF_TIE_EARRING_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_TEXT, "WID_SCMF_LIPS_MOUSTACHE_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES_TEXT, "WID_SCMF_HAS_GLASSES_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_TEXT, "WID_SCMF_HAIR_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_TEXT, "WID_SCMF_EYEBROWS_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_TEXT, "WID_SCMF_EYECOLOUR_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_TEXT, "WID_SCMF_GLASSES_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_TEXT, "WID_SCMF_NOSE_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_TEXT, "WID_SCMF_CHIN_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_TEXT, "WID_SCMF_JACKET_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_TEXT, "WID_SCMF_COLLAR_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_EUR, "WID_SCMF_ETHNICITY_EUR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_ETHNICITY_AFR, "WID_SCMF_ETHNICITY_AFR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_MOUSTACHE_EARRING, "WID_SCMF_HAS_MOUSTACHE_EARRING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAS_GLASSES, "WID_SCMF_HAS_GLASSES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_L, "WID_SCMF_EYECOLOUR_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR, "WID_SCMF_EYECOLOUR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYECOLOUR_R, "WID_SCMF_EYECOLOUR_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_L, "WID_SCMF_CHIN_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN, "WID_SCMF_CHIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_CHIN_R, "WID_SCMF_CHIN_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_L, "WID_SCMF_EYEBROWS_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS, "WID_SCMF_EYEBROWS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_EYEBROWS_R, "WID_SCMF_EYEBROWS_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_L, "WID_SCMF_LIPS_MOUSTACHE_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE, "WID_SCMF_LIPS_MOUSTACHE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_LIPS_MOUSTACHE_R, "WID_SCMF_LIPS_MOUSTACHE_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_L, "WID_SCMF_NOSE_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE, "WID_SCMF_NOSE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_NOSE_R, "WID_SCMF_NOSE_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_L, "WID_SCMF_HAIR_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR, "WID_SCMF_HAIR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_HAIR_R, "WID_SCMF_HAIR_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_L, "WID_SCMF_JACKET_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET, "WID_SCMF_JACKET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_JACKET_R, "WID_SCMF_JACKET_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_L, "WID_SCMF_COLLAR_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR, "WID_SCMF_COLLAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_COLLAR_R, "WID_SCMF_COLLAR_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_L, "WID_SCMF_TIE_EARRING_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING, "WID_SCMF_TIE_EARRING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_TIE_EARRING_R, "WID_SCMF_TIE_EARRING_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_L, "WID_SCMF_GLASSES_L"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES, "WID_SCMF_GLASSES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SCMF_GLASSES_R, "WID_SCMF_GLASSES_R"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_CAPTION, "WID_CI_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_DESC, "WID_CI_RAIL_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_RAIL_COUNT, "WID_CI_RAIL_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_DESC, "WID_CI_ROAD_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_ROAD_COUNT, "WID_CI_ROAD_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_DESC, "WID_CI_WATER_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_WATER_COUNT, "WID_CI_WATER_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_DESC, "WID_CI_STATION_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_STATION_COUNT, "WID_CI_STATION_COUNT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL_DESC, "WID_CI_TOTAL_DESC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CI_TOTAL, "WID_CI_TOTAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_CAPTION, "WID_BC_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_FACE, "WID_BC_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_QUESTION, "WID_BC_QUESTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_NO, "WID_BC_NO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BC_YES, "WID_BC_YES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_C_BACKGROUND, "WID_C_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_DAY, "WID_SD_DAY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_MONTH, "WID_SD_MONTH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_YEAR, "WID_SD_YEAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SD_SET_DATE, "WID_SD_SET_DATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CAPTION, "WID_D_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL, "WID_D_SELL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_SELL_CHAIN, "WID_D_SHOW_SELL_CHAIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_CHAIN, "WID_D_SELL_CHAIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SELL_ALL, "WID_D_SELL_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_AUTOREPLACE, "WID_D_AUTOREPLACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_MATRIX, "WID_D_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_V_SCROLL, "WID_D_V_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_H_SCROLL, "WID_D_SHOW_H_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_H_SCROLL, "WID_D_H_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_BUILD, "WID_D_BUILD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_CLONE, "WID_D_CLONE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_LOCATION, "WID_D_LOCATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_SHOW_RENAME, "WID_D_SHOW_RENAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_RENAME, "WID_D_RENAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_VEHICLE_LIST, "WID_D_VEHICLE_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_STOP_ALL, "WID_D_STOP_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_D_START_ALL, "WID_D_START_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_BACKGROUND, "WID_BDD_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_X, "WID_BDD_X"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BDD_Y, "WID_BDD_Y"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_CANAL, "WID_DT_CANAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_LOCK, "WID_DT_LOCK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEMOLISH, "WID_DT_DEMOLISH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_DEPOT, "WID_DT_DEPOT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_STATION, "WID_DT_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUOY, "WID_DT_BUOY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_RIVER, "WID_DT_RIVER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_BUILD_AQUEDUCT, "WID_DT_BUILD_AQUEDUCT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DT_INVALID, "WID_DT_INVALID"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_ITEMS, "WID_DM_ITEMS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SHOW_SCROLL, "WID_DM_SHOW_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DM_SCROLL, "WID_DM_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_QUESTION, "WID_EP_QUESTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_NO, "WID_EP_NO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EP_YES, "WID_EP_YES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_CAPTION, "WID_EM_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_FACE, "WID_EM_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EM_MESSAGE, "WID_EM_MESSAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CAPTION, "WID_SL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYNAME, "WID_SL_SORT_BYNAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SORT_BYDATE, "WID_SL_SORT_BYDATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_BACKGROUND, "WID_SL_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_FILE_BACKGROUND, "WID_SL_FILE_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_HOME_BUTTON, "WID_SL_HOME_BUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DRIVES_DIRECTORIES_LIST, "WID_SL_DRIVES_DIRECTORIES_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SCROLLBAR, "WID_SL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD, "WID_SL_CONTENT_DOWNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_OSK_TITLE, "WID_SL_SAVE_OSK_TITLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DELETE_SELECTION, "WID_SL_DELETE_SELECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_SAVE_GAME, "WID_SL_SAVE_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_CONTENT_DOWNLOAD_SEL, "WID_SL_CONTENT_DOWNLOAD_SEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_DETAILS, "WID_SL_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_NEWGRF_INFO, "WID_SL_NEWGRF_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_LOAD_BUTTON, "WID_SL_LOAD_BUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SL_MISSING_NEWGRFS, "WID_SL_MISSING_NEWGRFS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TEMPERATE, "WID_GL_TEMPERATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ARCTIC, "WID_GL_ARCTIC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TROPICAL, "WID_GL_TROPICAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOYLAND, "WID_GL_TOYLAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_X_PULLDOWN, "WID_GL_MAPSIZE_X_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAPSIZE_Y_PULLDOWN, "WID_GL_MAPSIZE_Y_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TOWN_PULLDOWN, "WID_GL_TOWN_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_INDUSTRY_PULLDOWN, "WID_GL_INDUSTRY_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_GENERATE_BUTTON, "WID_GL_GENERATE_BUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAX_HEIGHTLEVEL_DOWN, "WID_GL_MAX_HEIGHTLEVEL_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAX_HEIGHTLEVEL_TEXT, "WID_GL_MAX_HEIGHTLEVEL_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MAX_HEIGHTLEVEL_UP, "WID_GL_MAX_HEIGHTLEVEL_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_DOWN, "WID_GL_START_DATE_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_TEXT, "WID_GL_START_DATE_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_DATE_UP, "WID_GL_START_DATE_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_DOWN, "WID_GL_SNOW_LEVEL_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_TEXT, "WID_GL_SNOW_LEVEL_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SNOW_LEVEL_UP, "WID_GL_SNOW_LEVEL_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TREE_PULLDOWN, "WID_GL_TREE_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LANDSCAPE_PULLDOWN, "WID_GL_LANDSCAPE_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_NAME_TEXT, "WID_GL_HEIGHTMAP_NAME_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_SIZE_TEXT, "WID_GL_HEIGHTMAP_SIZE_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, "WID_GL_HEIGHTMAP_ROTATION_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_TERRAIN_PULLDOWN, "WID_GL_TERRAIN_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_PULLDOWN, "WID_GL_WATER_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RIVER_PULLDOWN, "WID_GL_RIVER_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SMOOTHNESS_PULLDOWN, "WID_GL_SMOOTHNESS_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_VARIETY_PULLDOWN, "WID_GL_VARIETY_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BORDERS_RANDOM, "WID_GL_BORDERS_RANDOM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NW, "WID_GL_WATER_NW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_NE, "WID_GL_WATER_NE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SE, "WID_GL_WATER_SE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_WATER_SW, "WID_GL_WATER_SW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TEMPERATE, "WID_CS_TEMPERATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_ARCTIC, "WID_CS_ARCTIC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TROPICAL, "WID_CS_TROPICAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_TOYLAND, "WID_CS_TOYLAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_EMPTY_WORLD, "WID_CS_EMPTY_WORLD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_RANDOM_WORLD, "WID_CS_RANDOM_WORLD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_X_PULLDOWN, "WID_CS_MAPSIZE_X_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_MAPSIZE_Y_PULLDOWN, "WID_CS_MAPSIZE_Y_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_DOWN, "WID_CS_START_DATE_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_TEXT, "WID_CS_START_DATE_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_START_DATE_UP, "WID_CS_START_DATE_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_DOWN, "WID_CS_FLAT_LAND_HEIGHT_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_TEXT, "WID_CS_FLAT_LAND_HEIGHT_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CS_FLAT_LAND_HEIGHT_UP, "WID_CS_FLAT_LAND_HEIGHT_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_BAR, "WID_GP_PROGRESS_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_TEXT, "WID_GP_PROGRESS_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_ABORT, "WID_GP_ABORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_CAPTION, "WID_GOAL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_LIST, "WID_GOAL_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GOAL_SCROLLBAR, "WID_GOAL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_CAPTION, "WID_GQ_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_QUESTION, "WID_GQ_QUESTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTONS, "WID_GQ_BUTTONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_1, "WID_GQ_BUTTON_1"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_2, "WID_GQ_BUTTON_2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_BUTTON_3, "WID_GQ_BUTTON_3"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_BACKGROUND, "WID_GL_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_FIRST_COMPANY, "WID_GL_FIRST_COMPANY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LAST_COMPANY, "WID_GL_LAST_COMPANY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_KEY_BUTTON, "WID_CV_KEY_BUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_BACKGROUND, "WID_CV_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_GRAPH, "WID_CV_GRAPH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CV_RESIZE, "WID_CV_RESIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_KEY, "WID_PHG_KEY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_DETAILED_PERFORMANCE, "WID_PHG_DETAILED_PERFORMANCE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_BACKGROUND, "WID_PHG_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_GRAPH, "WID_PHG_GRAPH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PHG_RESIZE, "WID_PHG_RESIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_BACKGROUND, "WID_CPR_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_HEADER, "WID_CPR_HEADER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_GRAPH, "WID_CPR_GRAPH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_RESIZE, "WID_CPR_RESIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_FOOTER, "WID_CPR_FOOTER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_ENABLE_CARGOES, "WID_CPR_ENABLE_CARGOES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_DISABLE_CARGOES, "WID_CPR_DISABLE_CARGOES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CPR_CARGO_FIRST, "WID_CPR_CARGO_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_BACKGROUND, "WID_CL_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_FIRST, "WID_PRD_SCORE_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_SCORE_LAST, "WID_PRD_SCORE_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_FIRST, "WID_PRD_COMPANY_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_PRD_COMPANY_LAST, "WID_PRD_COMPANY_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CAPTION, "WID_GL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_ORDER, "WID_GL_SORT_BY_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SORT_BY_DROPDOWN, "WID_GL_SORT_BY_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE, "WID_GL_LIST_VEHICLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_VEHICLE_SCROLLBAR, "WID_GL_LIST_VEHICLE_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_AVAILABLE_VEHICLES, "WID_GL_AVAILABLE_VEHICLES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_MANAGE_VEHICLES_DROPDOWN, "WID_GL_MANAGE_VEHICLES_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_STOP_ALL, "WID_GL_STOP_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_START_ALL, "WID_GL_START_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_ALL_VEHICLES, "WID_GL_ALL_VEHICLES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DEFAULT_VEHICLES, "WID_GL_DEFAULT_VEHICLES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP, "WID_GL_LIST_GROUP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_LIST_GROUP_SCROLLBAR, "WID_GL_LIST_GROUP_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_CREATE_GROUP, "WID_GL_CREATE_GROUP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_DELETE_GROUP, "WID_GL_DELETE_GROUP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_RENAME_GROUP, "WID_GL_RENAME_GROUP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_REPLACE_PROTECTION, "WID_GL_REPLACE_PROTECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_H_BACKGROUND, "WID_H_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_MATRIX_WIDGET, "WID_DPI_MATRIX_WIDGET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_SCROLLBAR, "WID_DPI_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_INFOPANEL, "WID_DPI_INFOPANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_DISPLAY_WIDGET, "WID_DPI_DISPLAY_WIDGET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_DPI_FUND_WIDGET, "WID_DPI_FUND_WIDGET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_CAPTION, "WID_IV_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_VIEWPORT, "WID_IV_VIEWPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_INFO, "WID_IV_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_GOTO, "WID_IV_GOTO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IV_DISPLAY, "WID_IV_DISPLAY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_ORDER, "WID_ID_DROPDOWN_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_DROPDOWN_CRITERIA, "WID_ID_DROPDOWN_CRITERIA"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_INDUSTRY_LIST, "WID_ID_INDUSTRY_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ID_SCROLLBAR, "WID_ID_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CAPTION, "WID_IC_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_NOTIFY, "WID_IC_NOTIFY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_PANEL, "WID_IC_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_SCROLLBAR, "WID_IC_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_CARGO_DROPDOWN, "WID_IC_CARGO_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_IC_IND_DROPDOWN, "WID_IC_IND_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GENERATE_GAME, "WID_SGI_GENERATE_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_LOAD_GAME, "WID_SGI_LOAD_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_SCENARIO, "WID_SGI_PLAY_SCENARIO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_HEIGHTMAP, "WID_SGI_PLAY_HEIGHTMAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EDIT_SCENARIO, "WID_SGI_EDIT_SCENARIO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_PLAY_NETWORK, "WID_SGI_PLAY_NETWORK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TEMPERATE_LANDSCAPE, "WID_SGI_TEMPERATE_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_ARCTIC_LANDSCAPE, "WID_SGI_ARCTIC_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TROPIC_LANDSCAPE, "WID_SGI_TROPIC_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TOYLAND_LANDSCAPE, "WID_SGI_TOYLAND_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION_SELECTION, "WID_SGI_TRANSLATION_SELECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_TRANSLATION, "WID_SGI_TRANSLATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_OPTIONS, "WID_SGI_OPTIONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_HIGHSCORE, "WID_SGI_HIGHSCORE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_SETTINGS_OPTIONS, "WID_SGI_SETTINGS_OPTIONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_GRF_SETTINGS, "WID_SGI_GRF_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_CONTENT_DOWNLOAD, "WID_SGI_CONTENT_DOWNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_AI_SETTINGS, "WID_SGI_AI_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SGI_EXIT, "WID_SGI_EXIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CAPTION, "WID_LGL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION, "WID_LGL_SATURATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_FIRST, "WID_LGL_SATURATION_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_SATURATION_LAST, "WID_LGL_SATURATION_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES, "WID_LGL_COMPANIES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_FIRST, "WID_LGL_COMPANY_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANY_LAST, "WID_LGL_COMPANY_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_ALL, "WID_LGL_COMPANIES_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_COMPANIES_NONE, "WID_LGL_COMPANIES_NONE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES, "WID_LGL_CARGOES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_FIRST, "WID_LGL_CARGO_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGO_LAST, "WID_LGL_CARGO_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_ALL, "WID_LGL_CARGOES_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LGL_CARGOES_NONE, "WID_LGL_CARGOES_NONE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_VIEWPORT, "WID_M_VIEWPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_LI_BACKGROUND, "WID_LI_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BACKGROUND, "WID_TT_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_SCROLLING_TEXT, "WID_A_SCROLLING_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_A_WEBSITE, "WID_A_WEBSITE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CAPTION, "WID_QS_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_TEXT, "WID_QS_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_DEFAULT, "WID_QS_DEFAULT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_CANCEL, "WID_QS_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QS_OK, "WID_QS_OK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_CAPTION, "WID_Q_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_TEXT, "WID_Q_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_NO, "WID_Q_NO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_Q_YES, "WID_Q_YES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CAPTION, "WID_TF_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_WRAPTEXT, "WID_TF_WRAPTEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_BACKGROUND, "WID_TF_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_VSCROLLBAR, "WID_TF_VSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_HSCROLLBAR, "WID_TF_HSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_LEFT, "WID_MTS_LIST_LEFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_PLAYLIST, "WID_MTS_PLAYLIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_LIST_RIGHT, "WID_MTS_LIST_RIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_ALL, "WID_MTS_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_OLD, "WID_MTS_OLD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_NEW, "WID_MTS_NEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_EZY, "WID_MTS_EZY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM1, "WID_MTS_CUSTOM1"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CUSTOM2, "WID_MTS_CUSTOM2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MTS_CLEAR, "WID_MTS_CLEAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PREV, "WID_M_PREV"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEXT, "WID_M_NEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_STOP, "WID_M_STOP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PLAY, "WID_M_PLAY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SLIDERS, "WID_M_SLIDERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_MUSIC_VOL, "WID_M_MUSIC_VOL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EFFECT_VOL, "WID_M_EFFECT_VOL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_BACKGROUND, "WID_M_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK, "WID_M_TRACK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NR, "WID_M_TRACK_NR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_TITLE, "WID_M_TRACK_TITLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_TRACK_NAME, "WID_M_TRACK_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_SHUFFLE, "WID_M_SHUFFLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_PROGRAMME, "WID_M_PROGRAMME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_ALL, "WID_M_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_OLD, "WID_M_OLD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_NEW, "WID_M_NEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_EZY, "WID_M_EZY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM1, "WID_M_CUSTOM1"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_M_CUSTOM2, "WID_M_CUSTOM2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_CLOSE, "WID_NC_CLOSE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_BACKGROUND, "WID_NC_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_DESTINATION, "WID_NC_DESTINATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_TEXTBOX, "WID_NC_TEXTBOX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NC_SENDBUTTON, "WID_NC_SENDBUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_BACKGROUND, "WID_NCDS_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCDS_CANCELOK, "WID_NCDS_CANCELOK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_BACKGROUND, "WID_NCL_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER_CAPT, "WID_NCL_FILTER_CAPT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_FILTER, "WID_NCL_FILTER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CHECKBOX, "WID_NCL_CHECKBOX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TYPE, "WID_NCL_TYPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_NAME, "WID_NCL_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_MATRIX, "WID_NCL_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SCROLLBAR, "WID_NCL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DETAILS, "WID_NCL_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_TEXTFILE, "WID_NCL_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_ALL, "WID_NCL_SELECT_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SELECT_UPDATE, "WID_NCL_SELECT_UPDATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_UNSELECT, "WID_NCL_UNSELECT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_OPEN_URL, "WID_NCL_OPEN_URL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_CANCEL, "WID_NCL_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_DOWNLOAD, "WID_NCL_DOWNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEL_ALL_UPDATE, "WID_NCL_SEL_ALL_UPDATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCL_SEARCH_EXTERNAL, "WID_NCL_SEARCH_EXTERNAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAIN, "WID_NG_MAIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONNECTION, "WID_NG_CONNECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CONN_BTN, "WID_NG_CONN_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT_LABEL, "WID_NG_CLIENT_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENT, "WID_NG_CLIENT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER_LABEL, "WID_NG_FILTER_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FILTER, "WID_NG_FILTER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_HEADER, "WID_NG_HEADER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NAME, "WID_NG_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CLIENTS, "WID_NG_CLIENTS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MAPSIZE, "WID_NG_MAPSIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DATE, "WID_NG_DATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_YEARS, "WID_NG_YEARS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_INFO, "WID_NG_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_MATRIX, "WID_NG_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_SCROLLBAR, "WID_NG_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_LABEL, "WID_NG_LASTJOINED_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED, "WID_NG_LASTJOINED"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_LASTJOINED_SPACER, "WID_NG_LASTJOINED_SPACER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS, "WID_NG_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_DETAILS_SPACER, "WID_NG_DETAILS_SPACER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_JOIN, "WID_NG_JOIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_REFRESH, "WID_NG_REFRESH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF, "WID_NG_NEWGRF"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_SEL, "WID_NG_NEWGRF_SEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING, "WID_NG_NEWGRF_MISSING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_NEWGRF_MISSING_SEL, "WID_NG_NEWGRF_MISSING_SEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_FIND, "WID_NG_FIND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_ADD, "WID_NG_ADD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_START, "WID_NG_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NG_CANCEL, "WID_NG_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_BACKGROUND, "WID_NSS_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME_LABEL, "WID_NSS_GAMENAME_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GAMENAME, "WID_NSS_GAMENAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SETPWD, "WID_NSS_SETPWD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_LABEL, "WID_NSS_CONNTYPE_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CONNTYPE_BTN, "WID_NSS_CONNTYPE_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_LABEL, "WID_NSS_CLIENTS_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTND, "WID_NSS_CLIENTS_BTND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_TXT, "WID_NSS_CLIENTS_TXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CLIENTS_BTNU, "WID_NSS_CLIENTS_BTNU"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_LABEL, "WID_NSS_COMPANIES_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTND, "WID_NSS_COMPANIES_BTND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_TXT, "WID_NSS_COMPANIES_TXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_COMPANIES_BTNU, "WID_NSS_COMPANIES_BTNU"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_LABEL, "WID_NSS_SPECTATORS_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTND, "WID_NSS_SPECTATORS_BTND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_TXT, "WID_NSS_SPECTATORS_TXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_SPECTATORS_BTNU, "WID_NSS_SPECTATORS_BTNU"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_LABEL, "WID_NSS_LANGUAGE_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LANGUAGE_BTN, "WID_NSS_LANGUAGE_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_GENERATE_GAME, "WID_NSS_GENERATE_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_LOAD_GAME, "WID_NSS_LOAD_GAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_SCENARIO, "WID_NSS_PLAY_SCENARIO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_PLAY_HEIGHTMAP, "WID_NSS_PLAY_HEIGHTMAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NSS_CANCEL, "WID_NSS_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_BACKGROUND, "WID_NL_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_TEXT, "WID_NL_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_HEADER, "WID_NL_HEADER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_MATRIX, "WID_NL_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SCROLLBAR, "WID_NL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_DETAILS, "WID_NL_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_JOIN, "WID_NL_JOIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_NEW, "WID_NL_NEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_SPECTATE, "WID_NL_SPECTATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_REFRESH, "WID_NL_REFRESH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NL_CANCEL, "WID_NL_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CL_PANEL, "WID_CL_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CLP_PANEL, "WID_CLP_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_BACKGROUND, "WID_NJS_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NJS_CANCELOK, "WID_NJS_CANCELOK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_BACKGROUND, "WID_NCP_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_LABEL, "WID_NCP_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_PASSWORD, "WID_NCP_PASSWORD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, "WID_NCP_SAVE_AS_DEFAULT_PASSWORD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_CANCEL, "WID_NCP_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NCP_OK, "WID_NCP_OK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_CAPTION, "WID_NGRFI_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_PARENT, "WID_NGRFI_PARENT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_PREV, "WID_NGRFI_VEH_PREV"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_NEXT, "WID_NGRFI_VEH_NEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_VEH_CHAIN, "WID_NGRFI_VEH_CHAIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_MAINPANEL, "WID_NGRFI_MAINPANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NGRFI_SCROLLBAR, "WID_NGRFI_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_CAPTION, "WID_SA_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PREVIOUS, "WID_SA_PREVIOUS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_GOTO, "WID_SA_GOTO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_NEXT, "WID_SA_NEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_UP, "WID_SA_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LEFT, "WID_SA_LEFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_RIGHT, "WID_SA_RIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_DOWN, "WID_SA_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SPRITE, "WID_SA_SPRITE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_OFFSETS_ABS, "WID_SA_OFFSETS_ABS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_OFFSETS_REL, "WID_SA_OFFSETS_REL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_PICKER, "WID_SA_PICKER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_LIST, "WID_SA_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_SCROLLBAR, "WID_SA_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SA_RESET_REL, "WID_SA_RESET_REL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_NUMPAR, "WID_NP_SHOW_NUMPAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_DEC, "WID_NP_NUMPAR_DEC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_INC, "WID_NP_NUMPAR_INC"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR, "WID_NP_NUMPAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_NUMPAR_TEXT, "WID_NP_NUMPAR_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_BACKGROUND, "WID_NP_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SCROLLBAR, "WID_NP_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_ACCEPT, "WID_NP_ACCEPT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_RESET, "WID_NP_RESET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_DESCRIPTION, "WID_NP_SHOW_DESCRIPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_DESCRIPTION, "WID_NP_DESCRIPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_LIST, "WID_NS_PRESET_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_SAVE, "WID_NS_PRESET_SAVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_DELETE, "WID_NS_PRESET_DELETE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_ADD, "WID_NS_ADD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_REMOVE, "WID_NS_REMOVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_UP, "WID_NS_MOVE_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_MOVE_DOWN, "WID_NS_MOVE_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_UPGRADE, "WID_NS_UPGRADE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILTER, "WID_NS_FILTER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_FILE_LIST, "WID_NS_FILE_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLLBAR, "WID_NS_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_AVAIL_LIST, "WID_NS_AVAIL_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SCROLL2BAR, "WID_NS_SCROLL2BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO_TITLE, "WID_NS_NEWGRF_INFO_TITLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_INFO, "WID_NS_NEWGRF_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_OPEN_URL, "WID_NS_OPEN_URL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_NEWGRF_TEXTFILE, "WID_NS_NEWGRF_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SET_PARAMETERS, "WID_NS_SET_PARAMETERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_VIEW_PARAMETERS, "WID_NS_VIEW_PARAMETERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_TOGGLE_PALETTE, "WID_NS_TOGGLE_PALETTE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_APPLY_CHANGES, "WID_NS_APPLY_CHANGES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES, "WID_NS_RESCAN_FILES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_RESCAN_FILES2, "WID_NS_RESCAN_FILES2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD, "WID_NS_CONTENT_DOWNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_CONTENT_DOWNLOAD2, "WID_NS_CONTENT_DOWNLOAD2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_REMOVE, "WID_NS_SHOW_REMOVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_APPLY, "WID_NS_SHOW_APPLY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SVP_PRESET_LIST, "WID_SVP_PRESET_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SVP_SCROLLBAR, "WID_SVP_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SVP_EDITBOX, "WID_SVP_EDITBOX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SVP_CANCEL, "WID_SVP_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SVP_SAVE, "WID_SVP_SAVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_BAR, "WID_SP_PROGRESS_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_TEXT, "WID_SP_PROGRESS_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_PANEL, "WID_N_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_TITLE, "WID_N_TITLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_HEADLINE, "WID_N_HEADLINE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CLOSEBOX, "WID_N_CLOSEBOX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_DATE, "WID_N_DATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_CAPTION, "WID_N_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_INSET, "WID_N_INSET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VIEWPORT, "WID_N_VIEWPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_COMPANY_MSG, "WID_N_COMPANY_MSG"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MESSAGE, "WID_N_MESSAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_FACE, "WID_N_MGR_FACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_MGR_NAME, "WID_N_MGR_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_TITLE, "WID_N_VEH_TITLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_BKGND, "WID_N_VEH_BKGND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_NAME, "WID_N_VEH_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_SPR, "WID_N_VEH_SPR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_VEH_INFO, "WID_N_VEH_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_STICKYBOX, "WID_MH_STICKYBOX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_BACKGROUND, "WID_MH_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_MH_SCROLLBAR, "WID_MH_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_CLASS_LIST, "WID_BO_CLASS_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SCROLLBAR, "WID_BO_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_MATRIX, "WID_BO_OBJECT_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SPRITE, "WID_BO_OBJECT_SPRITE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_NAME, "WID_BO_OBJECT_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_OBJECT_SIZE, "WID_BO_OBJECT_SIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_INFO, "WID_BO_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_MATRIX, "WID_BO_SELECT_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_IMAGE, "WID_BO_SELECT_IMAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BO_SELECT_SCROLL, "WID_BO_SELECT_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_CAPTION, "WID_O_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_TIMETABLE_VIEW, "WID_O_TIMETABLE_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_ORDER_LIST, "WID_O_ORDER_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SCROLLBAR, "WID_O_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SKIP, "WID_O_SKIP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_DELETE, "WID_O_DELETE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_STOP_SHARING, "WID_O_STOP_SHARING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_NON_STOP, "WID_O_NON_STOP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_GOTO, "WID_O_GOTO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_FULL_LOAD, "WID_O_FULL_LOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_UNLOAD, "WID_O_UNLOAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT, "WID_O_REFIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SERVICE, "WID_O_SERVICE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_EMPTY, "WID_O_EMPTY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_REFIT_DROPDOWN, "WID_O_REFIT_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VARIABLE, "WID_O_COND_VARIABLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_COMPARATOR, "WID_O_COND_COMPARATOR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_COND_VALUE, "WID_O_COND_VALUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_LEFT, "WID_O_SEL_TOP_LEFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_MIDDLE, "WID_O_SEL_TOP_MIDDLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_RIGHT, "WID_O_SEL_TOP_RIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, "WID_O_SEL_TOP_ROW_GROUNDVEHICLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_TOP_ROW, "WID_O_SEL_TOP_ROW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SEL_BOTTOM_MIDDLE, "WID_O_SEL_BOTTOM_MIDDLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_O_SHARED_ORDER_LIST, "WID_O_SHARED_ORDER_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPTION, "WID_OSK_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_TEXT, "WID_OSK_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CANCEL, "WID_OSK_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_OK, "WID_OSK_OK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_BACKSPACE, "WID_OSK_BACKSPACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPECIAL, "WID_OSK_SPECIAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_CAPS, "WID_OSK_CAPS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SHIFT, "WID_OSK_SHIFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_SPACE, "WID_OSK_SPACE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LEFT, "WID_OSK_LEFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_RIGHT, "WID_OSK_RIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_LETTERS, "WID_OSK_LETTERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_FIRST, "WID_OSK_NUMBERS_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_NUMBERS_LAST, "WID_OSK_NUMBERS_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_FIRST, "WID_OSK_QWERTY_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_QWERTY_LAST, "WID_OSK_QWERTY_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_FIRST, "WID_OSK_ASDFG_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ASDFG_LAST, "WID_OSK_ASDFG_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_FIRST, "WID_OSK_ZXCVB_FIRST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_OSK_ZXCVB_LAST, "WID_OSK_ZXCVB_LAST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CAPTION, "WID_RAT_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_NS, "WID_RAT_BUILD_NS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_X, "WID_RAT_BUILD_X"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_EW, "WID_RAT_BUILD_EW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_Y, "WID_RAT_BUILD_Y"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_AUTORAIL, "WID_RAT_AUTORAIL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_DEMOLISH, "WID_RAT_DEMOLISH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_DEPOT, "WID_RAT_BUILD_DEPOT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_WAYPOINT, "WID_RAT_BUILD_WAYPOINT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_STATION, "WID_RAT_BUILD_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_SIGNALS, "WID_RAT_BUILD_SIGNALS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_BRIDGE, "WID_RAT_BUILD_BRIDGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_BUILD_TUNNEL, "WID_RAT_BUILD_TUNNEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_REMOVE, "WID_RAT_REMOVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_RAT_CONVERT_RAIL, "WID_RAT_CONVERT_RAIL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_X, "WID_BRAS_PLATFORM_DIR_X"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DIR_Y, "WID_BRAS_PLATFORM_DIR_Y"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_1, "WID_BRAS_PLATFORM_NUM_1"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_2, "WID_BRAS_PLATFORM_NUM_2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_3, "WID_BRAS_PLATFORM_NUM_3"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_4, "WID_BRAS_PLATFORM_NUM_4"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_5, "WID_BRAS_PLATFORM_NUM_5"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_6, "WID_BRAS_PLATFORM_NUM_6"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_7, "WID_BRAS_PLATFORM_NUM_7"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_1, "WID_BRAS_PLATFORM_LEN_1"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_2, "WID_BRAS_PLATFORM_LEN_2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_3, "WID_BRAS_PLATFORM_LEN_3"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_4, "WID_BRAS_PLATFORM_LEN_4"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_5, "WID_BRAS_PLATFORM_LEN_5"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_6, "WID_BRAS_PLATFORM_LEN_6"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_7, "WID_BRAS_PLATFORM_LEN_7"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_DRAG_N_DROP, "WID_BRAS_PLATFORM_DRAG_N_DROP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_OFF, "WID_BRAS_HIGHLIGHT_OFF"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_HIGHLIGHT_ON, "WID_BRAS_HIGHLIGHT_ON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_COVERAGE_TEXTS, "WID_BRAS_COVERAGE_TEXTS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX, "WID_BRAS_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_IMAGE, "WID_BRAS_IMAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_MATRIX_SCROLL, "WID_BRAS_MATRIX_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_DEFSIZE, "WID_BRAS_SHOW_NEWST_DEFSIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_ADDITIONS, "WID_BRAS_SHOW_NEWST_ADDITIONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_MATRIX, "WID_BRAS_SHOW_NEWST_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_RESIZE, "WID_BRAS_SHOW_NEWST_RESIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_SHOW_NEWST_TYPE, "WID_BRAS_SHOW_NEWST_TYPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_LIST, "WID_BRAS_NEWST_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_NEWST_SCROLL, "WID_BRAS_NEWST_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_NUM_BEGIN, "WID_BRAS_PLATFORM_NUM_BEGIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAS_PLATFORM_LEN_BEGIN, "WID_BRAS_PLATFORM_LEN_BEGIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_NORM, "WID_BS_SEMAPHORE_NORM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_ENTRY, "WID_BS_SEMAPHORE_ENTRY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_EXIT, "WID_BS_SEMAPHORE_EXIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_COMBO, "WID_BS_SEMAPHORE_COMBO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS, "WID_BS_SEMAPHORE_PBS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_SEMAPHORE_PBS_OWAY, "WID_BS_SEMAPHORE_PBS_OWAY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_NORM, "WID_BS_ELECTRIC_NORM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_ENTRY, "WID_BS_ELECTRIC_ENTRY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_EXIT, "WID_BS_ELECTRIC_EXIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_COMBO, "WID_BS_ELECTRIC_COMBO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS, "WID_BS_ELECTRIC_PBS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_ELECTRIC_PBS_OWAY, "WID_BS_ELECTRIC_PBS_OWAY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_CONVERT, "WID_BS_CONVERT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, "WID_BS_DRAG_SIGNALS_DENSITY_LABEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, "WID_BS_DRAG_SIGNALS_DENSITY_DECREASE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, "WID_BS_DRAG_SIGNALS_DENSITY_INCREASE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NE, "WID_BRAD_DEPOT_NE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SE, "WID_BRAD_DEPOT_SE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_SW, "WID_BRAD_DEPOT_SW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRAD_DEPOT_NW, "WID_BRAD_DEPOT_NW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT_MATRIX, "WID_BRW_WAYPOINT_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_WAYPOINT, "WID_BRW_WAYPOINT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BRW_SCROLL, "WID_BRW_SCROLL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_X, "WID_ROT_ROAD_X"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ROAD_Y, "WID_ROT_ROAD_Y"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_AUTOROAD, "WID_ROT_AUTOROAD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEMOLISH, "WID_ROT_DEMOLISH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_DEPOT, "WID_ROT_DEPOT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUS_STATION, "WID_ROT_BUS_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_TRUCK_STATION, "WID_ROT_TRUCK_STATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_ONE_WAY, "WID_ROT_ONE_WAY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_BRIDGE, "WID_ROT_BUILD_BRIDGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_BUILD_TUNNEL, "WID_ROT_BUILD_TUNNEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ROT_REMOVE, "WID_ROT_REMOVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_CAPTION, "WID_BROD_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NE, "WID_BROD_DEPOT_NE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SE, "WID_BROD_DEPOT_SE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_SW, "WID_BROD_DEPOT_SW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROD_DEPOT_NW, "WID_BROD_DEPOT_NW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_CAPTION, "WID_BROS_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_BACKGROUND, "WID_BROS_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NE, "WID_BROS_STATION_NE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SE, "WID_BROS_STATION_SE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_SW, "WID_BROS_STATION_SW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_NW, "WID_BROS_STATION_NW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_X, "WID_BROS_STATION_X"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_STATION_Y, "WID_BROS_STATION_Y"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_OFF, "WID_BROS_LT_OFF"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_LT_ON, "WID_BROS_LT_ON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BROS_INFO, "WID_BROS_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BACKGROUND, "WID_GO_BACKGROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_CURRENCY_DROPDOWN, "WID_GO_CURRENCY_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_DISTANCE_DROPDOWN, "WID_GO_DISTANCE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_ROADSIDE_DROPDOWN, "WID_GO_ROADSIDE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_TOWNNAME_DROPDOWN, "WID_GO_TOWNNAME_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_AUTOSAVE_DROPDOWN, "WID_GO_AUTOSAVE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_LANG_DROPDOWN, "WID_GO_LANG_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_RESOLUTION_DROPDOWN, "WID_GO_RESOLUTION_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_FULLSCREEN_BUTTON, "WID_GO_FULLSCREEN_BUTTON"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_GUI_ZOOM_DROPDOWN, "WID_GO_GUI_ZOOM_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DROPDOWN, "WID_GO_BASE_GRF_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_STATUS, "WID_GO_BASE_GRF_STATUS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_TEXTFILE, "WID_GO_BASE_GRF_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_GRF_DESCRIPTION, "WID_GO_BASE_GRF_DESCRIPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DROPDOWN, "WID_GO_BASE_SFX_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_TEXTFILE, "WID_GO_BASE_SFX_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_SFX_DESCRIPTION, "WID_GO_BASE_SFX_DESCRIPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DROPDOWN, "WID_GO_BASE_MUSIC_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_STATUS, "WID_GO_BASE_MUSIC_STATUS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_TEXTFILE, "WID_GO_BASE_MUSIC_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GO_BASE_MUSIC_DESCRIPTION, "WID_GO_BASE_MUSIC_DESCRIPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_FILTER, "WID_GS_FILTER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_OPTIONSPANEL, "WID_GS_OPTIONSPANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_SCROLLBAR, "WID_GS_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_HELP_TEXT, "WID_GS_HELP_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_EXPAND_ALL, "WID_GS_EXPAND_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_COLLAPSE_ALL, "WID_GS_COLLAPSE_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_CATEGORY, "WID_GS_RESTRICT_CATEGORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_TYPE, "WID_GS_RESTRICT_TYPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_RESTRICT_DROPDOWN, "WID_GS_RESTRICT_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GS_TYPE_DROPDOWN, "WID_GS_TYPE_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_DOWN, "WID_CC_RATE_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE_UP, "WID_CC_RATE_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_RATE, "WID_CC_RATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR_EDIT, "WID_CC_SEPARATOR_EDIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SEPARATOR, "WID_CC_SEPARATOR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX_EDIT, "WID_CC_PREFIX_EDIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREFIX, "WID_CC_PREFIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX_EDIT, "WID_CC_SUFFIX_EDIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_SUFFIX, "WID_CC_SUFFIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_DOWN, "WID_CC_YEAR_DOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR_UP, "WID_CC_YEAR_UP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_YEAR, "WID_CC_YEAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_CC_PREVIEW, "WID_CC_PREVIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_CAPTION, "WID_SIL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_LIST, "WID_SIL_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_SCROLLBAR, "WID_SIL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_TEXT, "WID_SIL_FILTER_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_MATCH_CASE_BTN, "WID_SIL_FILTER_MATCH_CASE_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SIL_FILTER_ENTER_BTN, "WID_SIL_FILTER_ENTER_BTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CAPTION, "WID_QES_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_TEXT, "WID_QES_TEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_OK, "WID_QES_OK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_CANCEL, "WID_QES_CANCEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_DELETE, "WID_QES_DELETE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_PREVIOUS, "WID_QES_PREVIOUS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_QES_NEXT, "WID_QES_NEXT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CAPTION, "WID_SM_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP_BORDER, "WID_SM_MAP_BORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_MAP, "WID_SM_MAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LEGEND, "WID_SM_LEGEND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_BLANK, "WID_SM_BLANK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_IN, "WID_SM_ZOOM_IN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ZOOM_OUT, "WID_SM_ZOOM_OUT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CONTOUR, "WID_SM_CONTOUR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEHICLES, "WID_SM_VEHICLES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_INDUSTRIES, "WID_SM_INDUSTRIES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_LINKSTATS, "WID_SM_LINKSTATS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ROUTES, "WID_SM_ROUTES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_VEGETATION, "WID_SM_VEGETATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_OWNERS, "WID_SM_OWNERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_CENTERMAP, "WID_SM_CENTERMAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_TOGGLETOWNNAME, "WID_SM_TOGGLETOWNNAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SELECT_BUTTONS, "WID_SM_SELECT_BUTTONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_ENABLE_ALL, "WID_SM_ENABLE_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_DISABLE_ALL, "WID_SM_DISABLE_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SM_SHOW_HEIGHT, "WID_SM_SHOW_HEIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CAPTION, "WID_SV_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_ORDER, "WID_SV_SORT_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SORT_BY, "WID_SV_SORT_BY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP, "WID_SV_GROUP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_GROUP_BY, "WID_SV_GROUP_BY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_WAITING, "WID_SV_WAITING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SCROLLBAR, "WID_SV_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPT_RATING_LIST, "WID_SV_ACCEPT_RATING_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_LOCATION, "WID_SV_LOCATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ACCEPTS_RATINGS, "WID_SV_ACCEPTS_RATINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_RENAME, "WID_SV_RENAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_CLOSE_AIRPORT, "WID_SV_CLOSE_AIRPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_TRAINS, "WID_SV_TRAINS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_ROADVEHS, "WID_SV_ROADVEHS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_SHIPS, "WID_SV_SHIPS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SV_PLANES, "WID_SV_PLANES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CAPTION, "WID_STL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_LIST, "WID_STL_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SCROLLBAR, "WID_STL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRAIN, "WID_STL_TRAIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_TRUCK, "WID_STL_TRUCK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_BUS, "WID_STL_BUS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_AIRPLANE, "WID_STL_AIRPLANE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SHIP, "WID_STL_SHIP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_FACILALL, "WID_STL_FACILALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_NOCARGOWAITING, "WID_STL_NOCARGOWAITING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOALL, "WID_STL_CARGOALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTBY, "WID_STL_SORTBY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_SORTDROPBTN, "WID_STL_SORTDROPBTN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_STL_CARGOSTART, "WID_STL_CARGOSTART"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_CAPTION, "WID_JS_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_PANEL, "WID_JS_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_JS_SCROLLBAR, "WID_JS_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_LEFT, "WID_S_LEFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_MIDDLE, "WID_S_MIDDLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_RIGHT, "WID_S_RIGHT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_CAPTION, "WID_SB_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SEL_PAGE, "WID_SB_SEL_PAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PAGE_PANEL, "WID_SB_PAGE_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SCROLLBAR, "WID_SB_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PREV_PAGE, "WID_SB_PREV_PAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_NEXT_PAGE, "WID_SB_NEXT_PAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_PANEL, "WID_SUL_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_SCROLLBAR, "WID_SUL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHOW_PLACE_OBJECT, "WID_TT_SHOW_PLACE_OBJECT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS_START, "WID_TT_BUTTONS_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOWER_LAND, "WID_TT_LOWER_LAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_RAISE_LAND, "WID_TT_RAISE_LAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LEVEL_LAND, "WID_TT_LEVEL_LAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_DEMOLISH, "WID_TT_DEMOLISH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUY_LAND, "WID_TT_BUY_LAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLANT_TREES, "WID_TT_PLANT_TREES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_SIGN, "WID_TT_PLACE_SIGN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_PLACE_OBJECT, "WID_TT_PLACE_OBJECT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_SHOW_PLACE_DESERT, "WID_ETT_SHOW_PLACE_DESERT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_START, "WID_ETT_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DOTS, "WID_ETT_DOTS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_START, "WID_ETT_BUTTONS_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DEMOLISH, "WID_ETT_DEMOLISH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LOWER_LAND, "WID_ETT_LOWER_LAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RAISE_LAND, "WID_ETT_RAISE_LAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_LEVEL_LAND, "WID_ETT_LEVEL_LAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_ROCKS, "WID_ETT_PLACE_ROCKS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_DESERT, "WID_ETT_PLACE_DESERT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_PLACE_OBJECT, "WID_ETT_PLACE_OBJECT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_BUTTONS_END, "WID_ETT_BUTTONS_END"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_INCREASE_SIZE, "WID_ETT_INCREASE_SIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_DECREASE_SIZE, "WID_ETT_DECREASE_SIZE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_NEW_SCENARIO, "WID_ETT_NEW_SCENARIO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_ETT_RESET_LANDSCAPE, "WID_ETT_RESET_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CAPTION, "WID_VT_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ORDER_VIEW, "WID_VT_ORDER_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_TIMETABLE_PANEL, "WID_VT_TIMETABLE_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_PANEL, "WID_VT_ARRIVAL_DEPARTURE_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SCROLLBAR, "WID_VT_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SUMMARY_PANEL, "WID_VT_SUMMARY_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_START_DATE, "WID_VT_START_DATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_TIME, "WID_VT_CHANGE_TIME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_TIME, "WID_VT_CLEAR_TIME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_RESET_LATENESS, "WID_VT_RESET_LATENESS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_AUTOFILL, "WID_VT_AUTOFILL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED, "WID_VT_EXPECTED"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_SHARED_ORDER_LIST, "WID_VT_SHARED_ORDER_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_ARRIVAL_DEPARTURE_SELECTION, "WID_VT_ARRIVAL_DEPARTURE_SELECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_EXPECTED_SELECTION, "WID_VT_EXPECTED_SELECTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CHANGE_SPEED, "WID_VT_CHANGE_SPEED"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VT_CLEAR_SPEED, "WID_VT_CLEAR_SPEED"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_PAUSE, "WID_TN_PAUSE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FAST_FORWARD, "WID_TN_FAST_FORWARD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SETTINGS, "WID_TN_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SAVE, "WID_TN_SAVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SMALL_MAP, "WID_TN_SMALL_MAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TOWNS, "WID_TN_TOWNS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SUBSIDIES, "WID_TN_SUBSIDIES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STATIONS, "WID_TN_STATIONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_FINANCES, "WID_TN_FINANCES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_COMPANIES, "WID_TN_COMPANIES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_STORY, "WID_TN_STORY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GOAL, "WID_TN_GOAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_GRAPHS, "WID_TN_GRAPHS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LEAGUE, "WID_TN_LEAGUE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_INDUSTRIES, "WID_TN_INDUSTRIES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_VEHICLE_START, "WID_TN_VEHICLE_START"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_TRAINS, "WID_TN_TRAINS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADVEHS, "WID_TN_ROADVEHS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SHIPS, "WID_TN_SHIPS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIRCRAFTS, "WID_TN_AIRCRAFTS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_IN, "WID_TN_ZOOM_IN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ZOOM_OUT, "WID_TN_ZOOM_OUT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_RAILS, "WID_TN_RAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_ROADS, "WID_TN_ROADS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_WATER, "WID_TN_WATER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_AIR, "WID_TN_AIR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_LANDSCAPE, "WID_TN_LANDSCAPE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MUSIC_SOUND, "WID_TN_MUSIC_SOUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_MESSAGES, "WID_TN_MESSAGES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_HELP, "WID_TN_HELP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_SWITCH_BAR, "WID_TN_SWITCH_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TN_END, "WID_TN_END"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_PAUSE, "WID_TE_PAUSE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_FAST_FORWARD, "WID_TE_FAST_FORWARD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SETTINGS, "WID_TE_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SAVE, "WID_TE_SAVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SPACER, "WID_TE_SPACER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE, "WID_TE_DATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_BACKWARD, "WID_TE_DATE_BACKWARD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_FORWARD, "WID_TE_DATE_FORWARD"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SMALL_MAP, "WID_TE_SMALL_MAP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_IN, "WID_TE_ZOOM_IN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ZOOM_OUT, "WID_TE_ZOOM_OUT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_LAND_GENERATE, "WID_TE_LAND_GENERATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TOWN_GENERATE, "WID_TE_TOWN_GENERATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_INDUSTRY, "WID_TE_INDUSTRY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_ROADS, "WID_TE_ROADS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_WATER, "WID_TE_WATER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_TREES, "WID_TE_TREES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SIGNS, "WID_TE_SIGNS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_DATE_PANEL, "WID_TE_DATE_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_MUSIC_SOUND, "WID_TE_MUSIC_SOUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_HELP, "WID_TE_HELP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TE_SWITCH_BAR, "WID_TE_SWITCH_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_ORDER, "WID_TD_SORT_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SORT_CRITERIA, "WID_TD_SORT_CRITERIA"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_LIST, "WID_TD_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_SCROLLBAR, "WID_TD_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TD_WORLD_POPULATION, "WID_TD_WORLD_POPULATION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_CAPTION, "WID_TA_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_RATING_INFO, "WID_TA_RATING_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_COMMAND_LIST, "WID_TA_COMMAND_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_SCROLLBAR, "WID_TA_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_ACTION_INFO, "WID_TA_ACTION_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TA_EXECUTE, "WID_TA_EXECUTE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CAPTION, "WID_TV_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_VIEWPORT, "WID_TV_VIEWPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_INFO, "WID_TV_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CENTER_VIEW, "WID_TV_CENTER_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_SHOW_AUTHORITY, "WID_TV_SHOW_AUTHORITY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_CHANGE_NAME, "WID_TV_CHANGE_NAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_EXPAND, "WID_TV_EXPAND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TV_DELETE, "WID_TV_DELETE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_NEW_TOWN, "WID_TF_NEW_TOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_RANDOM_TOWN, "WID_TF_RANDOM_TOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_MANY_RANDOM_TOWNS, "WID_TF_MANY_RANDOM_TOWNS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_EDITBOX, "WID_TF_TOWN_NAME_EDITBOX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_TOWN_NAME_RANDOM, "WID_TF_TOWN_NAME_RANDOM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_SMALL, "WID_TF_SIZE_SMALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_MEDIUM, "WID_TF_SIZE_MEDIUM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_LARGE, "WID_TF_SIZE_LARGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_SIZE_RANDOM, "WID_TF_SIZE_RANDOM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CITY, "WID_TF_CITY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_ORIGINAL, "WID_TF_LAYOUT_ORIGINAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_BETTER, "WID_TF_LAYOUT_BETTER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID2, "WID_TF_LAYOUT_GRID2"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_GRID3, "WID_TF_LAYOUT_GRID3"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_LAYOUT_RANDOM, "WID_TF_LAYOUT_RANDOM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BEGIN, "WID_TT_BEGIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SIGNS, "WID_TT_SIGNS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_TREES, "WID_TT_TREES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_HOUSES, "WID_TT_HOUSES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_INDUSTRIES, "WID_TT_INDUSTRIES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUILDINGS, "WID_TT_BUILDINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BRIDGES, "WID_TT_BRIDGES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_STRUCTURES, "WID_TT_STRUCTURES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_CATENARY, "WID_TT_CATENARY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_LOADING, "WID_TT_LOADING"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_END, "WID_TT_END"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_BUTTONS, "WID_TT_BUTTONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_11, "WID_BT_TYPE_11"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_12, "WID_BT_TYPE_12"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_13, "WID_BT_TYPE_13"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_14, "WID_BT_TYPE_14"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_21, "WID_BT_TYPE_21"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_22, "WID_BT_TYPE_22"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_23, "WID_BT_TYPE_23"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_24, "WID_BT_TYPE_24"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_31, "WID_BT_TYPE_31"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_32, "WID_BT_TYPE_32"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_33, "WID_BT_TYPE_33"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_34, "WID_BT_TYPE_34"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_TYPE_RANDOM, "WID_BT_TYPE_RANDOM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_BT_MANY_RANDOM, "WID_BT_MANY_RANDOM"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CAPTION, "WID_VV_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_VIEWPORT, "WID_VV_VIEWPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_START_STOP, "WID_VV_START_STOP"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CENTER_MAIN_VIEW, "WID_VV_CENTER_MAIN_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_GOTO_DEPOT, "WID_VV_GOTO_DEPOT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_REFIT, "WID_VV_REFIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_ORDERS, "WID_VV_SHOW_ORDERS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SHOW_DETAILS, "WID_VV_SHOW_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_CLONE, "WID_VV_CLONE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_DEPOT_CLONE, "WID_VV_SELECT_DEPOT_CLONE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_SELECT_REFIT_TURN, "WID_VV_SELECT_REFIT_TURN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_TURN_AROUND, "WID_VV_TURN_AROUND"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VV_FORCE_PROCEED, "WID_VV_FORCE_PROCEED"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_CAPTION, "WID_VR_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_VEHICLE_PANEL_DISPLAY, "WID_VR_VEHICLE_PANEL_DISPLAY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SHOW_HSCROLLBAR, "WID_VR_SHOW_HSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_HSCROLLBAR, "WID_VR_HSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SELECT_HEADER, "WID_VR_SELECT_HEADER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_MATRIX, "WID_VR_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_SCROLLBAR, "WID_VR_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_INFO, "WID_VR_INFO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VR_REFIT, "WID_VR_REFIT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_CAPTION, "WID_VD_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_RENAME_VEHICLE, "WID_VD_RENAME_VEHICLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_TOP_DETAILS, "WID_VD_TOP_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_INCREASE_SERVICING_INTERVAL, "WID_VD_INCREASE_SERVICING_INTERVAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DECREASE_SERVICING_INTERVAL, "WID_VD_DECREASE_SERVICING_INTERVAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICE_INTERVAL_DROPDOWN, "WID_VD_SERVICE_INTERVAL_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SERVICING_INTERVAL, "WID_VD_SERVICING_INTERVAL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MIDDLE_DETAILS, "WID_VD_MIDDLE_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_MATRIX, "WID_VD_MATRIX"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_SCROLLBAR, "WID_VD_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CARGO_CARRIED, "WID_VD_DETAILS_CARGO_CARRIED"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TRAIN_VEHICLES, "WID_VD_DETAILS_TRAIN_VEHICLES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_CAPACITY_OF_EACH, "WID_VD_DETAILS_CAPACITY_OF_EACH"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VD_DETAILS_TOTAL_CARGO, "WID_VD_DETAILS_TOTAL_CARGO"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_CAPTION, "WID_VL_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_ORDER, "WID_VL_SORT_ORDER"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SORT_BY_PULLDOWN, "WID_VL_SORT_BY_PULLDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_LIST, "WID_VL_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_SCROLLBAR, "WID_VL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_HIDE_BUTTONS, "WID_VL_HIDE_BUTTONS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_AVAILABLE_VEHICLES, "WID_VL_AVAILABLE_VEHICLES"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_MANAGE_VEHICLES_DROPDOWN, "WID_VL_MANAGE_VEHICLES_DROPDOWN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_STOP_ALL, "WID_VL_STOP_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_VL_START_ALL, "WID_VL_START_ALL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_CAPTION, "WID_EV_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEWPORT, "WID_EV_VIEWPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_IN, "WID_EV_ZOOM_IN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_ZOOM_OUT, "WID_EV_ZOOM_OUT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_MAIN_TO_VIEW, "WID_EV_MAIN_TO_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_EV_VIEW_TO_MAIN, "WID_EV_VIEW_TO_MAIN"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CAPTION, "WID_W_CAPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_VIEWPORT, "WID_W_VIEWPORT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_CENTER_VIEW, "WID_W_CENTER_VIEW"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_RENAME, "WID_W_RENAME"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_W_SHOW_VEHICLES, "WID_W_SHOW_VEHICLES"); SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Close, "Close", 3, ".ii"); SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::IsOpen, "IsOpen", 3, ".ii"); SQGSWindow.DefSQStaticMethod(engine, &ScriptWindow::Highlight, "Highlight", 5, ".iiii"); SQGSWindow.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_date.hpp.sq0000644000000000000000000000343012627373433020523 0ustar rootroot/* $Id: game_date.hpp.sq 26307 2014-02-06 19:50:34Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_date.hpp" #include "../template/template_date.hpp.sq" template <> const char *GetClassName() { return "GSDate"; } void SQGSDate_Register(Squirrel *engine) { DefSQClass SQGSDate("GSDate"); SQGSDate.PreRegister(engine); SQGSDate.AddConstructor(engine, "x"); SQGSDate.DefSQConst(engine, ScriptDate::DATE_INVALID, "DATE_INVALID"); SQGSDate.DefSQStaticMethod(engine, &ScriptDate::IsValidDate, "IsValidDate", 2, ".i"); SQGSDate.DefSQStaticMethod(engine, &ScriptDate::GetCurrentDate, "GetCurrentDate", 1, "."); SQGSDate.DefSQStaticMethod(engine, &ScriptDate::GetYear, "GetYear", 2, ".i"); SQGSDate.DefSQStaticMethod(engine, &ScriptDate::GetMonth, "GetMonth", 2, ".i"); SQGSDate.DefSQStaticMethod(engine, &ScriptDate::GetDayOfMonth, "GetDayOfMonth", 2, ".i"); SQGSDate.DefSQStaticMethod(engine, &ScriptDate::GetDate, "GetDate", 4, ".iii"); SQGSDate.DefSQStaticMethod(engine, &ScriptDate::GetSystemTime, "GetSystemTime", 1, "."); SQGSDate.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_tilelist.hpp.sq0000644000000000000000000000626312627373433021446 0ustar rootroot/* $Id: game_tilelist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tilelist.hpp" #include "../template/template_tilelist.hpp.sq" template <> const char *GetClassName() { return "GSTileList"; } void SQGSTileList_Register(Squirrel *engine) { DefSQClass SQGSTileList("GSTileList"); SQGSTileList.PreRegister(engine, "GSList"); SQGSTileList.AddConstructor(engine, "x"); SQGSTileList.DefSQMethod(engine, &ScriptTileList::AddRectangle, "AddRectangle", 3, "xii"); SQGSTileList.DefSQMethod(engine, &ScriptTileList::AddTile, "AddTile", 2, "xi"); SQGSTileList.DefSQMethod(engine, &ScriptTileList::RemoveRectangle, "RemoveRectangle", 3, "xii"); SQGSTileList.DefSQMethod(engine, &ScriptTileList::RemoveTile, "RemoveTile", 2, "xi"); SQGSTileList.PostRegister(engine); } template <> const char *GetClassName() { return "GSTileList_IndustryAccepting"; } void SQGSTileList_IndustryAccepting_Register(Squirrel *engine) { DefSQClass SQGSTileList_IndustryAccepting("GSTileList_IndustryAccepting"); SQGSTileList_IndustryAccepting.PreRegister(engine, "GSTileList"); SQGSTileList_IndustryAccepting.AddConstructor(engine, "xii"); SQGSTileList_IndustryAccepting.PostRegister(engine); } template <> const char *GetClassName() { return "GSTileList_IndustryProducing"; } void SQGSTileList_IndustryProducing_Register(Squirrel *engine) { DefSQClass SQGSTileList_IndustryProducing("GSTileList_IndustryProducing"); SQGSTileList_IndustryProducing.PreRegister(engine, "GSTileList"); SQGSTileList_IndustryProducing.AddConstructor(engine, "xii"); SQGSTileList_IndustryProducing.PostRegister(engine); } template <> const char *GetClassName() { return "GSTileList_StationType"; } void SQGSTileList_StationType_Register(Squirrel *engine) { DefSQClass SQGSTileList_StationType("GSTileList_StationType"); SQGSTileList_StationType.PreRegister(engine, "GSTileList"); SQGSTileList_StationType.AddConstructor(engine, "xii"); SQGSTileList_StationType.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_vehiclelist.hpp.sq0000644000000000000000000000520112627373433022117 0ustar rootroot/* $Id: game_vehiclelist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_vehiclelist.hpp" #include "../template/template_vehiclelist.hpp.sq" template <> const char *GetClassName() { return "GSVehicleList"; } void SQGSVehicleList_Register(Squirrel *engine) { DefSQClass SQGSVehicleList("GSVehicleList"); SQGSVehicleList.PreRegister(engine, "GSList"); SQGSVehicleList.AddConstructor(engine, "x"); SQGSVehicleList.PostRegister(engine); } template <> const char *GetClassName() { return "GSVehicleList_Station"; } void SQGSVehicleList_Station_Register(Squirrel *engine) { DefSQClass SQGSVehicleList_Station("GSVehicleList_Station"); SQGSVehicleList_Station.PreRegister(engine, "GSList"); SQGSVehicleList_Station.AddConstructor(engine, "xi"); SQGSVehicleList_Station.PostRegister(engine); } template <> const char *GetClassName() { return "GSVehicleList_Depot"; } void SQGSVehicleList_Depot_Register(Squirrel *engine) { DefSQClass SQGSVehicleList_Depot("GSVehicleList_Depot"); SQGSVehicleList_Depot.PreRegister(engine, "GSList"); SQGSVehicleList_Depot.AddConstructor(engine, "xi"); SQGSVehicleList_Depot.PostRegister(engine); } template <> const char *GetClassName() { return "GSVehicleList_SharedOrders"; } void SQGSVehicleList_SharedOrders_Register(Squirrel *engine) { DefSQClass SQGSVehicleList_SharedOrders("GSVehicleList_SharedOrders"); SQGSVehicleList_SharedOrders.PreRegister(engine, "GSList"); SQGSVehicleList_SharedOrders.AddConstructor(engine, "xi"); SQGSVehicleList_SharedOrders.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_text.hpp.sq0000644000000000000000000000255712627373433020603 0ustar rootroot/* $Id: game_text.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_text.hpp" #include "../template/template_text.hpp.sq" template <> const char *GetClassName() { return "GSText"; } void SQGSText_Register(Squirrel *engine) { DefSQClass SQGSText("GSText"); SQGSText.PreRegister(engine); SQGSText.AddSQAdvancedConstructor(engine); SQGSText.DefSQConst(engine, ScriptText::SCRIPT_TEXT_MAX_PARAMETERS, "SCRIPT_TEXT_MAX_PARAMETERS"); SQGSText.DefSQAdvancedMethod(engine, &ScriptText::_set, "_set"); SQGSText.DefSQAdvancedMethod(engine, &ScriptText::SetParam, "SetParam"); SQGSText.DefSQAdvancedMethod(engine, &ScriptText::AddParam, "AddParam"); SQGSText.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_controller.hpp.sq0000644000000000000000000000376112627373433022000 0ustar rootroot/* $Id: game_controller.hpp.sq 24542 2012-09-21 20:49:43Z zuu $ */ /* * 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 . */ #include "../script_controller.hpp" template <> const char *GetClassName() { return "GSController"; } void SQGSController_Register(Squirrel *engine) { DefSQClass SQGSController("GSController"); SQGSController.PreRegister(engine); SQGSController.DefSQStaticMethod(engine, &ScriptController::GetTick, "GetTick", 1, "."); SQGSController.DefSQStaticMethod(engine, &ScriptController::GetOpsTillSuspend, "GetOpsTillSuspend", 1, "."); SQGSController.DefSQStaticMethod(engine, &ScriptController::SetCommandDelay, "SetCommandDelay", 2, ".i"); SQGSController.DefSQStaticMethod(engine, &ScriptController::Sleep, "Sleep", 2, ".i"); SQGSController.DefSQStaticMethod(engine, &ScriptController::Break, "Break", 2, ".s"); SQGSController.DefSQStaticMethod(engine, &ScriptController::GetSetting, "GetSetting", 2, ".s"); SQGSController.DefSQStaticMethod(engine, &ScriptController::GetVersion, "GetVersion", 1, "."); SQGSController.DefSQStaticMethod(engine, &ScriptController::Print, "Print", 3, ".bs"); SQGSController.PostRegister(engine); /* Register the import statement to the global scope */ SQGSController.DefSQStaticMethod(engine, &ScriptController::Import, "import", 4, ".ssi"); } openttd-1.5.3/src/script/api/game/game_road.hpp.sq0000644000000000000000000001626212627373433020542 0ustar rootroot/* $Id: game_road.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_road.hpp" #include "../template/template_road.hpp.sq" template <> const char *GetClassName() { return "GSRoad"; } void SQGSRoad_Register(Squirrel *engine) { DefSQClass SQGSRoad("GSRoad"); SQGSRoad.PreRegister(engine); SQGSRoad.AddConstructor(engine, "x"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_BASE, "ERR_ROAD_BASE"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_ROAD, "ROADTYPE_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_TRAM, "ROADTYPE_TRAM"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADTYPE_INVALID, "ROADTYPE_INVALID"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_BUS, "ROADVEHTYPE_BUS"); SQGSRoad.DefSQConst(engine, ScriptRoad::ROADVEHTYPE_TRUCK, "ROADVEHTYPE_TRUCK"); SQGSRoad.DefSQConst(engine, ScriptRoad::BT_ROAD, "BT_ROAD"); SQGSRoad.DefSQConst(engine, ScriptRoad::BT_DEPOT, "BT_DEPOT"); SQGSRoad.DefSQConst(engine, ScriptRoad::BT_BUS_STOP, "BT_BUS_STOP"); SQGSRoad.DefSQConst(engine, ScriptRoad::BT_TRUCK_STOP, "BT_TRUCK_STOP"); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_WORKS_IN_PROGRESS, ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_DIRECTION, ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION); ScriptError::RegisterErrorMap(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD, ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD); ScriptError::RegisterErrorMap(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION, ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS, "ERR_ROAD_WORKS_IN_PROGRESS"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, "ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, "ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD"); ScriptError::RegisterErrorMapString(ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, "ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadVehicleTypeForCargo, "GetRoadVehicleTypeForCargo", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTile, "IsRoadTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadDepotTile, "IsRoadDepotTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadStationTile, "IsRoadStationTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsDriveThroughRoadStationTile, "IsDriveThroughRoadStationTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::IsRoadTypeAvailable, "IsRoadTypeAvailable", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetCurrentRoadType, "GetCurrentRoadType", 1, "."); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::SetCurrentRoadType, "SetCurrentRoadType", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::HasRoadType, "HasRoadType", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::AreRoadTilesConnected, "AreRoadTilesConnected", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadParts, "CanBuildConnectedRoadParts", 5, ".iaii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::CanBuildConnectedRoadPartsHere, "CanBuildConnectedRoadPartsHere", 4, ".iii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetNeighbourRoadCount, "GetNeighbourRoadCount", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadDepotFrontTile, "GetRoadDepotFrontTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetRoadStationFrontTile, "GetRoadStationFrontTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetDriveThroughBackTile, "GetDriveThroughBackTile", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoad, "BuildRoad", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildOneWayRoad, "BuildOneWayRoad", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoadFull, "BuildRoadFull", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildOneWayRoadFull, "BuildOneWayRoadFull", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoadDepot, "BuildRoadDepot", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildRoadStation, "BuildRoadStation", 5, ".iiii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::BuildDriveThroughRoadStation, "BuildDriveThroughRoadStation", 5, ".iiii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoad, "RemoveRoad", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadFull, "RemoveRoadFull", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadDepot, "RemoveRoadDepot", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::RemoveRoadStation, "RemoveRoadStation", 2, ".i"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetBuildCost, "GetBuildCost", 3, ".ii"); SQGSRoad.DefSQStaticMethod(engine, &ScriptRoad::GetMaintenanceCostFactor, "GetMaintenanceCostFactor", 2, ".i"); SQGSRoad.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_game.hpp.sq0000644000000000000000000000344512627373433020525 0ustar rootroot/* $Id: game_game.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_game.hpp" #include "../template/template_game.hpp.sq" template <> const char *GetClassName() { return "GSGame"; } void SQGSGame_Register(Squirrel *engine) { DefSQClass SQGSGame("GSGame"); SQGSGame.PreRegister(engine); SQGSGame.AddConstructor(engine, "x"); SQGSGame.DefSQConst(engine, ScriptGame::LT_TEMPERATE, "LT_TEMPERATE"); SQGSGame.DefSQConst(engine, ScriptGame::LT_ARCTIC, "LT_ARCTIC"); SQGSGame.DefSQConst(engine, ScriptGame::LT_TROPIC, "LT_TROPIC"); SQGSGame.DefSQConst(engine, ScriptGame::LT_TOYLAND, "LT_TOYLAND"); SQGSGame.DefSQStaticMethod(engine, &ScriptGame::Pause, "Pause", 1, "."); SQGSGame.DefSQStaticMethod(engine, &ScriptGame::Unpause, "Unpause", 1, "."); SQGSGame.DefSQStaticMethod(engine, &ScriptGame::IsPaused, "IsPaused", 1, "."); SQGSGame.DefSQStaticMethod(engine, &ScriptGame::GetLandscape, "GetLandscape", 1, "."); SQGSGame.DefSQStaticMethod(engine, &ScriptGame::IsMultiplayer, "IsMultiplayer", 1, "."); SQGSGame.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_cargomonitor.hpp.sq0000644000000000000000000000351212627373433022312 0ustar rootroot/* $Id: game_cargomonitor.hpp.sq 24406 2012-07-15 17:11:14Z alberth $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargomonitor.hpp" #include "../template/template_cargomonitor.hpp.sq" template <> const char *GetClassName() { return "GSCargoMonitor"; } void SQGSCargoMonitor_Register(Squirrel *engine) { DefSQClass SQGSCargoMonitor("GSCargoMonitor"); SQGSCargoMonitor.PreRegister(engine); SQGSCargoMonitor.AddConstructor(engine, "x"); SQGSCargoMonitor.DefSQStaticMethod(engine, &ScriptCargoMonitor::GetTownDeliveryAmount, "GetTownDeliveryAmount", 5, ".iiib"); SQGSCargoMonitor.DefSQStaticMethod(engine, &ScriptCargoMonitor::GetIndustryDeliveryAmount, "GetIndustryDeliveryAmount", 5, ".iiib"); SQGSCargoMonitor.DefSQStaticMethod(engine, &ScriptCargoMonitor::GetTownPickupAmount, "GetTownPickupAmount", 5, ".iiib"); SQGSCargoMonitor.DefSQStaticMethod(engine, &ScriptCargoMonitor::GetIndustryPickupAmount, "GetIndustryPickupAmount", 5, ".iiib"); SQGSCargoMonitor.DefSQStaticMethod(engine, &ScriptCargoMonitor::StopAllMonitoring, "StopAllMonitoring", 1, "."); SQGSCargoMonitor.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_testmode.hpp.sq0000644000000000000000000000217512627373433021437 0ustar rootroot/* $Id: game_testmode.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_testmode.hpp" #include "../template/template_testmode.hpp.sq" template <> const char *GetClassName() { return "GSTestMode"; } void SQGSTestMode_Register(Squirrel *engine) { DefSQClass SQGSTestMode("GSTestMode"); SQGSTestMode.PreRegister(engine); SQGSTestMode.AddConstructor(engine, "x"); SQGSTestMode.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_enginelist.hpp.sq0000644000000000000000000000231112627373433021744 0ustar rootroot/* $Id: game_enginelist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_enginelist.hpp" #include "../template/template_enginelist.hpp.sq" template <> const char *GetClassName() { return "GSEngineList"; } void SQGSEngineList_Register(Squirrel *engine) { DefSQClass SQGSEngineList("GSEngineList"); SQGSEngineList.PreRegister(engine, "GSList"); SQGSEngineList.AddConstructor(engine, "xi"); SQGSEngineList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_marine.hpp.sq0000644000000000000000000000731112627373433021063 0ustar rootroot/* $Id: game_marine.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_marine.hpp" #include "../template/template_marine.hpp.sq" template <> const char *GetClassName() { return "GSMarine"; } void SQGSMarine_Register(Squirrel *engine) { DefSQClass SQGSMarine("GSMarine"); SQGSMarine.PreRegister(engine); SQGSMarine.AddConstructor(engine, "x"); SQGSMarine.DefSQConst(engine, ScriptMarine::ERR_MARINE_BASE, "ERR_MARINE_BASE"); SQGSMarine.DefSQConst(engine, ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER, "ERR_MARINE_MUST_BE_BUILT_ON_WATER"); SQGSMarine.DefSQConst(engine, ScriptMarine::BT_DOCK, "BT_DOCK"); SQGSMarine.DefSQConst(engine, ScriptMarine::BT_DEPOT, "BT_DEPOT"); SQGSMarine.DefSQConst(engine, ScriptMarine::BT_BUOY, "BT_BUOY"); ScriptError::RegisterErrorMap(STR_ERROR_MUST_BE_BUILT_ON_WATER, ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER); ScriptError::RegisterErrorMapString(ScriptMarine::ERR_MARINE_MUST_BE_BUILT_ON_WATER, "ERR_MARINE_MUST_BE_BUILT_ON_WATER"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::IsWaterDepotTile, "IsWaterDepotTile", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::IsDockTile, "IsDockTile", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::IsBuoyTile, "IsBuoyTile", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::IsLockTile, "IsLockTile", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::IsCanalTile, "IsCanalTile", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::AreWaterTilesConnected, "AreWaterTilesConnected", 3, ".ii"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildWaterDepot, "BuildWaterDepot", 3, ".ii"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildDock, "BuildDock", 3, ".ii"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildBuoy, "BuildBuoy", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildLock, "BuildLock", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::BuildCanal, "BuildCanal", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveWaterDepot, "RemoveWaterDepot", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveDock, "RemoveDock", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveBuoy, "RemoveBuoy", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveLock, "RemoveLock", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::RemoveCanal, "RemoveCanal", 2, ".i"); SQGSMarine.DefSQStaticMethod(engine, &ScriptMarine::GetBuildCost, "GetBuildCost", 2, ".i"); SQGSMarine.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_industrytypelist.hpp.sq0000644000000000000000000000235712627373433023274 0ustar rootroot/* $Id: game_industrytypelist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrytypelist.hpp" #include "../template/template_industrytypelist.hpp.sq" template <> const char *GetClassName() { return "GSIndustryTypeList"; } void SQGSIndustryTypeList_Register(Squirrel *engine) { DefSQClass SQGSIndustryTypeList("GSIndustryTypeList"); SQGSIndustryTypeList.PreRegister(engine, "GSList"); SQGSIndustryTypeList.AddConstructor(engine, "x"); SQGSIndustryTypeList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_storypagelist.hpp.sq0000644000000000000000000000225012627373433022516 0ustar rootroot/* $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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_storypagelist.hpp" #include "../template/template_storypagelist.hpp.sq" template <> const char *GetClassName() { return "GSStoryPageList"; } void SQGSStoryPageList_Register(Squirrel *engine) { DefSQClass SQGSStoryPageList("GSStoryPageList"); SQGSStoryPageList.PreRegister(engine, "GSList"); SQGSStoryPageList.AddConstructor(engine, "xi"); SQGSStoryPageList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_base.hpp.sq0000644000000000000000000000315712627373433020526 0ustar rootroot/* $Id: game_base.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_base.hpp" #include "../template/template_base.hpp.sq" template <> const char *GetClassName() { return "GSBase"; } void SQGSBase_Register(Squirrel *engine) { DefSQClass SQGSBase("GSBase"); SQGSBase.PreRegister(engine); SQGSBase.AddConstructor(engine, "x"); SQGSBase.DefSQStaticMethod(engine, &ScriptBase::Rand, "Rand", 1, "."); SQGSBase.DefSQStaticMethod(engine, &ScriptBase::RandItem, "RandItem", 2, ".i"); SQGSBase.DefSQStaticMethod(engine, &ScriptBase::RandRange, "RandRange", 2, ".i"); SQGSBase.DefSQStaticMethod(engine, &ScriptBase::RandRangeItem, "RandRangeItem", 3, ".ii"); SQGSBase.DefSQStaticMethod(engine, &ScriptBase::Chance, "Chance", 3, ".ii"); SQGSBase.DefSQStaticMethod(engine, &ScriptBase::ChanceItem, "ChanceItem", 4, ".iii"); SQGSBase.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_engine.hpp.sq0000644000000000000000000000764312627373433021065 0ustar rootroot/* $Id: game_engine.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_engine.hpp" #include "../template/template_engine.hpp.sq" template <> const char *GetClassName() { return "GSEngine"; } void SQGSEngine_Register(Squirrel *engine) { DefSQClass SQGSEngine("GSEngine"); SQGSEngine.PreRegister(engine); SQGSEngine.AddConstructor(engine, "x"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsValidEngine, "IsValidEngine", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsBuildable, "IsBuildable", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetName, "GetName", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetCargoType, "GetCargoType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRefitCargo, "CanRefitCargo", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::CanPullCargo, "CanPullCargo", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetCapacity, "GetCapacity", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetReliability, "GetReliability", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaxSpeed, "GetMaxSpeed", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetPrice, "GetPrice", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaxAge, "GetMaxAge", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRunningCost, "GetRunningCost", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetPower, "GetPower", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetWeight, "GetWeight", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaxTractiveEffort, "GetMaxTractiveEffort", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetDesignDate, "GetDesignDate", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetVehicleType, "GetVehicleType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsWagon, "IsWagon", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::CanRunOnRail, "CanRunOnRail", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::HasPowerOnRail, "HasPowerOnRail", 3, ".ii"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRoadType, "GetRoadType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetRailType, "GetRailType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::IsArticulated, "IsArticulated", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetPlaneType, "GetPlaneType", 2, ".i"); SQGSEngine.DefSQStaticMethod(engine, &ScriptEngine::GetMaximumOrderDistance, "GetMaximumOrderDistance", 2, ".i"); SQGSEngine.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_waypointlist.hpp.sq0000644000000000000000000000333112627373433022354 0ustar rootroot/* $Id: game_waypointlist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_waypointlist.hpp" #include "../template/template_waypointlist.hpp.sq" template <> const char *GetClassName() { return "GSWaypointList"; } void SQGSWaypointList_Register(Squirrel *engine) { DefSQClass SQGSWaypointList("GSWaypointList"); SQGSWaypointList.PreRegister(engine, "GSList"); SQGSWaypointList.AddConstructor(engine, "xi"); SQGSWaypointList.PostRegister(engine); } template <> const char *GetClassName() { return "GSWaypointList_Vehicle"; } void SQGSWaypointList_Vehicle_Register(Squirrel *engine) { DefSQClass SQGSWaypointList_Vehicle("GSWaypointList_Vehicle"); SQGSWaypointList_Vehicle.PreRegister(engine, "GSList"); SQGSWaypointList_Vehicle.AddConstructor(engine, "xi"); SQGSWaypointList_Vehicle.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_basestation.hpp.sq0000644000000000000000000000403012627373433022117 0ustar rootroot/* $Id: game_basestation.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_basestation.hpp" #include "../template/template_basestation.hpp.sq" template <> const char *GetClassName() { return "GSBaseStation"; } void SQGSBaseStation_Register(Squirrel *engine) { DefSQClass SQGSBaseStation("GSBaseStation"); SQGSBaseStation.PreRegister(engine); SQGSBaseStation.AddConstructor(engine, "x"); SQGSBaseStation.DefSQConst(engine, ScriptBaseStation::STATION_NEW, "STATION_NEW"); SQGSBaseStation.DefSQConst(engine, ScriptBaseStation::STATION_JOIN_ADJACENT, "STATION_JOIN_ADJACENT"); SQGSBaseStation.DefSQConst(engine, ScriptBaseStation::STATION_INVALID, "STATION_INVALID"); SQGSBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::IsValidBaseStation, "IsValidBaseStation", 2, ".i"); SQGSBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::GetName, "GetName", 2, ".i"); SQGSBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::SetName, "SetName", 3, ".i."); SQGSBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::GetLocation, "GetLocation", 2, ".i"); SQGSBaseStation.DefSQStaticMethod(engine, &ScriptBaseStation::GetConstructionDate, "GetConstructionDate", 2, ".i"); SQGSBaseStation.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_railtypelist.hpp.sq0000644000000000000000000000227312627373433022337 0ustar rootroot/* $Id: game_railtypelist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_railtypelist.hpp" #include "../template/template_railtypelist.hpp.sq" template <> const char *GetClassName() { return "GSRailTypeList"; } void SQGSRailTypeList_Register(Squirrel *engine) { DefSQClass SQGSRailTypeList("GSRailTypeList"); SQGSRailTypeList.PreRegister(engine, "GSList"); SQGSRailTypeList.AddConstructor(engine, "x"); SQGSRailTypeList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_town.hpp.sq0000644000000000000000000001763312627373433020607 0ustar rootroot/* $Id: game_town.hpp.sq 25969 2013-11-12 17:57:32Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_town.hpp" #include "../template/template_town.hpp.sq" template <> const char *GetClassName() { return "GSTown"; } void SQGSTown_Register(Squirrel *engine) { DefSQClass SQGSTown("GSTown"); SQGSTown.PreRegister(engine); SQGSTown.AddConstructor(engine, "x"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ADVERTISE_SMALL, "TOWN_ACTION_ADVERTISE_SMALL"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ADVERTISE_MEDIUM, "TOWN_ACTION_ADVERTISE_MEDIUM"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ADVERTISE_LARGE, "TOWN_ACTION_ADVERTISE_LARGE"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_ROAD_REBUILD, "TOWN_ACTION_ROAD_REBUILD"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_BUILD_STATUE, "TOWN_ACTION_BUILD_STATUE"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_FUND_BUILDINGS, "TOWN_ACTION_FUND_BUILDINGS"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_BUY_RIGHTS, "TOWN_ACTION_BUY_RIGHTS"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_ACTION_BRIBE, "TOWN_ACTION_BRIBE"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_NONE, "TOWN_RATING_NONE"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_APPALLING, "TOWN_RATING_APPALLING"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_VERY_POOR, "TOWN_RATING_VERY_POOR"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_POOR, "TOWN_RATING_POOR"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_MEDIOCRE, "TOWN_RATING_MEDIOCRE"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_GOOD, "TOWN_RATING_GOOD"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_VERY_GOOD, "TOWN_RATING_VERY_GOOD"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_EXCELLENT, "TOWN_RATING_EXCELLENT"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_OUTSTANDING, "TOWN_RATING_OUTSTANDING"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_RATING_INVALID, "TOWN_RATING_INVALID"); SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_ORIGINAL, "ROAD_LAYOUT_ORIGINAL"); SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_BETTER_ROADS, "ROAD_LAYOUT_BETTER_ROADS"); SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_2x2, "ROAD_LAYOUT_2x2"); SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_3x3, "ROAD_LAYOUT_3x3"); SQGSTown.DefSQConst(engine, ScriptTown::ROAD_LAYOUT_INVALID, "ROAD_LAYOUT_INVALID"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_SIZE_SMALL, "TOWN_SIZE_SMALL"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_SIZE_MEDIUM, "TOWN_SIZE_MEDIUM"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_SIZE_LARGE, "TOWN_SIZE_LARGE"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_SIZE_INVALID, "TOWN_SIZE_INVALID"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_GROWTH_NONE, "TOWN_GROWTH_NONE"); SQGSTown.DefSQConst(engine, ScriptTown::TOWN_GROWTH_NORMAL, "TOWN_GROWTH_NORMAL"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetTownCount, "GetTownCount", 1, "."); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::IsValidTown, "IsValidTown", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetName, "GetName", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::SetName, "SetName", 3, ".i."); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::SetText, "SetText", 3, ".i."); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetPopulation, "GetPopulation", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetHouseCount, "GetHouseCount", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetLocation, "GetLocation", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthProduction, "GetLastMonthProduction", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthSupplied, "GetLastMonthSupplied", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthTransportedPercentage, "GetLastMonthTransportedPercentage", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetLastMonthReceived, "GetLastMonthReceived", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::SetCargoGoal, "SetCargoGoal", 4, ".iii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetCargoGoal, "GetCargoGoal", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::SetGrowthRate, "SetGrowthRate", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetGrowthRate, "GetGrowthRate", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::IsWithinTownInfluence, "IsWithinTownInfluence", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::HasStatue, "HasStatue", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::IsCity, "IsCity", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetRoadReworkDuration, "GetRoadReworkDuration", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetFundBuildingsDuration, "GetFundBuildingsDuration", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetExclusiveRightsCompany, "GetExclusiveRightsCompany", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetExclusiveRightsDuration, "GetExclusiveRightsDuration", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::IsActionAvailable, "IsActionAvailable", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::PerformTownAction, "PerformTownAction", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::ExpandTown, "ExpandTown", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::FoundTown, "FoundTown", 6, ".iibi."); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetRating, "GetRating", 3, ".ii"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetAllowedNoise, "GetAllowedNoise", 2, ".i"); SQGSTown.DefSQStaticMethod(engine, &ScriptTown::GetRoadLayout, "GetRoadLayout", 2, ".i"); SQGSTown.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_storypageelementlist.hpp.sq0000644000000000000000000000240612627373433024073 0ustar rootroot/* $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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_storypageelementlist.hpp" #include "../template/template_storypageelementlist.hpp.sq" template <> const char *GetClassName() { return "GSStoryPageElementList"; } void SQGSStoryPageElementList_Register(Squirrel *engine) { DefSQClass SQGSStoryPageElementList("GSStoryPageElementList"); SQGSStoryPageElementList.PreRegister(engine, "GSList"); SQGSStoryPageElementList.AddConstructor(engine, "xi"); SQGSStoryPageElementList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_tunnel.hpp.sq0000644000000000000000000000604112627373433021114 0ustar rootroot/* $Id: game_tunnel.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tunnel.hpp" #include "../template/template_tunnel.hpp.sq" template <> const char *GetClassName() { return "GSTunnel"; } void SQGSTunnel_Register(Squirrel *engine) { DefSQClass SQGSTunnel("GSTunnel"); SQGSTunnel.PreRegister(engine); SQGSTunnel.AddConstructor(engine, "x"); SQGSTunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_BASE, "ERR_TUNNEL_BASE"); SQGSTunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_CANNOT_BUILD_ON_WATER, "ERR_TUNNEL_CANNOT_BUILD_ON_WATER"); SQGSTunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_START_SITE_UNSUITABLE, "ERR_TUNNEL_START_SITE_UNSUITABLE"); SQGSTunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY, "ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY"); SQGSTunnel.DefSQConst(engine, ScriptTunnel::ERR_TUNNEL_END_SITE_UNSUITABLE, "ERR_TUNNEL_END_SITE_UNSUITABLE"); ScriptError::RegisterErrorMap(STR_ERROR_CAN_T_BUILD_ON_WATER, ScriptTunnel::ERR_TUNNEL_CANNOT_BUILD_ON_WATER); ScriptError::RegisterErrorMap(STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL, ScriptTunnel::ERR_TUNNEL_START_SITE_UNSUITABLE); ScriptError::RegisterErrorMap(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY, ScriptTunnel::ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_UNABLE_TO_EXCAVATE_LAND, ScriptTunnel::ERR_TUNNEL_END_SITE_UNSUITABLE); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_CANNOT_BUILD_ON_WATER, "ERR_TUNNEL_CANNOT_BUILD_ON_WATER"); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_START_SITE_UNSUITABLE, "ERR_TUNNEL_START_SITE_UNSUITABLE"); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY, "ERR_TUNNEL_ANOTHER_TUNNEL_IN_THE_WAY"); ScriptError::RegisterErrorMapString(ScriptTunnel::ERR_TUNNEL_END_SITE_UNSUITABLE, "ERR_TUNNEL_END_SITE_UNSUITABLE"); SQGSTunnel.DefSQStaticMethod(engine, &ScriptTunnel::IsTunnelTile, "IsTunnelTile", 2, ".i"); SQGSTunnel.DefSQStaticMethod(engine, &ScriptTunnel::GetOtherTunnelEnd, "GetOtherTunnelEnd", 2, ".i"); SQGSTunnel.DefSQStaticMethod(engine, &ScriptTunnel::BuildTunnel, "BuildTunnel", 3, ".ii"); SQGSTunnel.DefSQStaticMethod(engine, &ScriptTunnel::RemoveTunnel, "RemoveTunnel", 2, ".i"); SQGSTunnel.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_accounting.hpp.sq0000644000000000000000000000251412627373433021742 0ustar rootroot/* $Id: game_accounting.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_accounting.hpp" #include "../template/template_accounting.hpp.sq" template <> const char *GetClassName() { return "GSAccounting"; } void SQGSAccounting_Register(Squirrel *engine) { DefSQClass SQGSAccounting("GSAccounting"); SQGSAccounting.PreRegister(engine); SQGSAccounting.AddConstructor(engine, "x"); SQGSAccounting.DefSQMethod(engine, &ScriptAccounting::GetCosts, "GetCosts", 1, "x"); SQGSAccounting.DefSQMethod(engine, &ScriptAccounting::ResetCosts, "ResetCosts", 1, "x"); SQGSAccounting.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_bridgelist.hpp.sq0000644000000000000000000000315512627373433021742 0ustar rootroot/* $Id: game_bridgelist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_bridgelist.hpp" #include "../template/template_bridgelist.hpp.sq" template <> const char *GetClassName() { return "GSBridgeList"; } void SQGSBridgeList_Register(Squirrel *engine) { DefSQClass SQGSBridgeList("GSBridgeList"); SQGSBridgeList.PreRegister(engine, "GSList"); SQGSBridgeList.AddConstructor(engine, "x"); SQGSBridgeList.PostRegister(engine); } template <> const char *GetClassName() { return "GSBridgeList_Length"; } void SQGSBridgeList_Length_Register(Squirrel *engine) { DefSQClass SQGSBridgeList_Length("GSBridgeList_Length"); SQGSBridgeList_Length.PreRegister(engine, "GSList"); SQGSBridgeList_Length.AddConstructor(engine, "xi"); SQGSBridgeList_Length.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_event.hpp.sq0000644000000000000000000001123312627373433020727 0ustar rootroot/* $Id: game_event.hpp.sq 24291 2012-05-26 14:16:45Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_event.hpp" #include "../template/template_event.hpp.sq" template <> const char *GetClassName() { return "GSEvent"; } void SQGSEvent_Register(Squirrel *engine) { DefSQClass SQGSEvent("GSEvent"); SQGSEvent.PreRegister(engine); SQGSEvent.AddConstructor(engine, "xi"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_INVALID, "ET_INVALID"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_TEST, "ET_TEST"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_OFFER, "ET_SUBSIDY_OFFER"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_OFFER_EXPIRED, "ET_SUBSIDY_OFFER_EXPIRED"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_AWARDED, "ET_SUBSIDY_AWARDED"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_SUBSIDY_EXPIRED, "ET_SUBSIDY_EXPIRED"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_ENGINE_PREVIEW, "ET_ENGINE_PREVIEW"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_NEW, "ET_COMPANY_NEW"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_IN_TROUBLE, "ET_COMPANY_IN_TROUBLE"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_ASK_MERGER, "ET_COMPANY_ASK_MERGER"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_MERGER, "ET_COMPANY_MERGER"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_COMPANY_BANKRUPT, "ET_COMPANY_BANKRUPT"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_CRASHED, "ET_VEHICLE_CRASHED"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_LOST, "ET_VEHICLE_LOST"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_WAITING_IN_DEPOT, "ET_VEHICLE_WAITING_IN_DEPOT"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_VEHICLE_UNPROFITABLE, "ET_VEHICLE_UNPROFITABLE"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_INDUSTRY_OPEN, "ET_INDUSTRY_OPEN"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_INDUSTRY_CLOSE, "ET_INDUSTRY_CLOSE"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_ENGINE_AVAILABLE, "ET_ENGINE_AVAILABLE"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_STATION_FIRST_VEHICLE, "ET_STATION_FIRST_VEHICLE"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_DISASTER_ZEPPELINER_CRASHED, "ET_DISASTER_ZEPPELINER_CRASHED"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_DISASTER_ZEPPELINER_CLEARED, "ET_DISASTER_ZEPPELINER_CLEARED"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_TOWN_FOUNDED, "ET_TOWN_FOUNDED"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_AIRCRAFT_DEST_TOO_FAR, "ET_AIRCRAFT_DEST_TOO_FAR"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_ADMIN_PORT, "ET_ADMIN_PORT"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_WINDOW_WIDGET_CLICK, "ET_WINDOW_WIDGET_CLICK"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_GOAL_QUESTION_ANSWER, "ET_GOAL_QUESTION_ANSWER"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_EXCLUSIVE_TRANSPORT_RIGHTS, "ET_EXCLUSIVE_TRANSPORT_RIGHTS"); SQGSEvent.DefSQConst(engine, ScriptEvent::ET_ROAD_RECONSTRUCTION, "ET_ROAD_RECONSTRUCTION"); SQGSEvent.DefSQMethod(engine, &ScriptEvent::GetEventType, "GetEventType", 1, "x"); SQGSEvent.PostRegister(engine); } template <> const char *GetClassName() { return "GSEventController"; } void SQGSEventController_Register(Squirrel *engine) { DefSQClass SQGSEventController("GSEventController"); SQGSEventController.PreRegister(engine); SQGSEventController.AddConstructor(engine, "x"); SQGSEventController.DefSQStaticMethod(engine, &ScriptEventController::IsEventWaiting, "IsEventWaiting", 1, "."); SQGSEventController.DefSQStaticMethod(engine, &ScriptEventController::GetNextEvent, "GetNextEvent", 1, "."); SQGSEventController.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_industry.hpp.sq0000644000000000000000000000773212627373433021500 0ustar rootroot/* $Id: game_industry.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industry.hpp" #include "../template/template_industry.hpp.sq" template <> const char *GetClassName() { return "GSIndustry"; } void SQGSIndustry_Register(Squirrel *engine) { DefSQClass SQGSIndustry("GSIndustry"); SQGSIndustry.PreRegister(engine); SQGSIndustry.AddConstructor(engine, "x"); SQGSIndustry.DefSQConst(engine, ScriptIndustry::CAS_NOT_ACCEPTED, "CAS_NOT_ACCEPTED"); SQGSIndustry.DefSQConst(engine, ScriptIndustry::CAS_ACCEPTED, "CAS_ACCEPTED"); SQGSIndustry.DefSQConst(engine, ScriptIndustry::CAS_TEMP_REFUSED, "CAS_TEMP_REFUSED"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetIndustryCount, "GetIndustryCount", 1, "."); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::IsValidIndustry, "IsValidIndustry", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetIndustryID, "GetIndustryID", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetName, "GetName", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::IsCargoAccepted, "IsCargoAccepted", 3, ".ii"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetStockpiledCargo, "GetStockpiledCargo", 3, ".ii"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLastMonthProduction, "GetLastMonthProduction", 3, ".ii"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLastMonthTransported, "GetLastMonthTransported", 3, ".ii"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLastMonthTransportedPercentage, "GetLastMonthTransportedPercentage", 3, ".ii"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetLocation, "GetLocation", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetAmountOfStationsAround, "GetAmountOfStationsAround", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetDistanceManhattanToTile, "GetDistanceManhattanToTile", 3, ".ii"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetDistanceSquareToTile, "GetDistanceSquareToTile", 3, ".ii"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::IsBuiltOnWater, "IsBuiltOnWater", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::HasHeliport, "HasHeliport", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetHeliportLocation, "GetHeliportLocation", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::HasDock, "HasDock", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetDockLocation, "GetDockLocation", 2, ".i"); SQGSIndustry.DefSQStaticMethod(engine, &ScriptIndustry::GetIndustryType, "GetIndustryType", 2, ".i"); SQGSIndustry.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_map.hpp.sq0000644000000000000000000000426012627373433020365 0ustar rootroot/* $Id: game_map.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_map.hpp" #include "../template/template_map.hpp.sq" template <> const char *GetClassName() { return "GSMap"; } void SQGSMap_Register(Squirrel *engine) { DefSQClass SQGSMap("GSMap"); SQGSMap.PreRegister(engine); SQGSMap.AddConstructor(engine, "x"); SQGSMap.DefSQConst(engine, ScriptMap::TILE_INVALID, "TILE_INVALID"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::IsValidTile, "IsValidTile", 2, ".i"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::GetMapSize, "GetMapSize", 1, "."); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::GetMapSizeX, "GetMapSizeX", 1, "."); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::GetMapSizeY, "GetMapSizeY", 1, "."); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::GetTileX, "GetTileX", 2, ".i"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::GetTileY, "GetTileY", 2, ".i"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::GetTileIndex, "GetTileIndex", 3, ".ii"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::DistanceManhattan, "DistanceManhattan", 3, ".ii"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::DistanceMax, "DistanceMax", 3, ".ii"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::DistanceSquare, "DistanceSquare", 3, ".ii"); SQGSMap.DefSQStaticMethod(engine, &ScriptMap::DistanceFromEdge, "DistanceFromEdge", 2, ".i"); SQGSMap.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_cargolist.hpp.sq0000644000000000000000000000547112627373433021604 0ustar rootroot/* $Id: game_cargolist.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargolist.hpp" #include "../template/template_cargolist.hpp.sq" template <> const char *GetClassName() { return "GSCargoList"; } void SQGSCargoList_Register(Squirrel *engine) { DefSQClass SQGSCargoList("GSCargoList"); SQGSCargoList.PreRegister(engine, "GSList"); SQGSCargoList.AddConstructor(engine, "x"); SQGSCargoList.PostRegister(engine); } template <> const char *GetClassName() { return "GSCargoList_IndustryAccepting"; } void SQGSCargoList_IndustryAccepting_Register(Squirrel *engine) { DefSQClass SQGSCargoList_IndustryAccepting("GSCargoList_IndustryAccepting"); SQGSCargoList_IndustryAccepting.PreRegister(engine, "GSList"); SQGSCargoList_IndustryAccepting.AddConstructor(engine, "xi"); SQGSCargoList_IndustryAccepting.PostRegister(engine); } template <> const char *GetClassName() { return "GSCargoList_IndustryProducing"; } void SQGSCargoList_IndustryProducing_Register(Squirrel *engine) { DefSQClass SQGSCargoList_IndustryProducing("GSCargoList_IndustryProducing"); SQGSCargoList_IndustryProducing.PreRegister(engine, "GSList"); SQGSCargoList_IndustryProducing.AddConstructor(engine, "xi"); SQGSCargoList_IndustryProducing.PostRegister(engine); } template <> const char *GetClassName() { return "GSCargoList_StationAccepting"; } void SQGSCargoList_StationAccepting_Register(Squirrel *engine) { DefSQClass SQGSCargoList_StationAccepting("GSCargoList_StationAccepting"); SQGSCargoList_StationAccepting.PreRegister(engine, "GSList"); SQGSCargoList_StationAccepting.AddConstructor(engine, "xi"); SQGSCargoList_StationAccepting.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_stationlist.hpp.sq0000644000000000000000000002236512627373433022173 0ustar rootroot/* $Id: game_stationlist.hpp.sq 26893 2014-09-21 16:20:48Z fonsinchen $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_stationlist.hpp" #include "../template/template_stationlist.hpp.sq" template <> const char *GetClassName() { return "GSStationList"; } void SQGSStationList_Register(Squirrel *engine) { DefSQClass SQGSStationList("GSStationList"); SQGSStationList.PreRegister(engine, "GSList"); SQGSStationList.AddConstructor(engine, "xi"); SQGSStationList.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_Cargo"; } void SQGSStationList_Cargo_Register(Squirrel *engine) { DefSQClass SQGSStationList_Cargo("GSStationList_Cargo"); SQGSStationList_Cargo.PreRegister(engine, "GSList"); SQGSStationList_Cargo.AddConstructor(engine, "xiiiii"); SQGSStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_BY_FROM, "CS_BY_FROM"); SQGSStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_VIA_BY_FROM, "CS_VIA_BY_FROM"); SQGSStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_BY_VIA, "CS_BY_VIA"); SQGSStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CS_FROM_BY_VIA, "CS_FROM_BY_VIA"); SQGSStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CM_WAITING, "CM_WAITING"); SQGSStationList_Cargo.DefSQConst(engine, ScriptStationList_Cargo::CM_PLANNED, "CM_PLANNED"); SQGSStationList_Cargo.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoWaiting"; } void SQGSStationList_CargoWaiting_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoWaiting("GSStationList_CargoWaiting"); SQGSStationList_CargoWaiting.PreRegister(engine, "GSStationList_Cargo"); SQGSStationList_CargoWaiting.AddConstructor(engine, "xiiii"); SQGSStationList_CargoWaiting.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoPlanned"; } void SQGSStationList_CargoPlanned_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoPlanned("GSStationList_CargoPlanned"); SQGSStationList_CargoPlanned.PreRegister(engine, "GSStationList_Cargo"); SQGSStationList_CargoPlanned.AddConstructor(engine, "xiiii"); SQGSStationList_CargoPlanned.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoWaitingByFrom"; } void SQGSStationList_CargoWaitingByFrom_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoWaitingByFrom("GSStationList_CargoWaitingByFrom"); SQGSStationList_CargoWaitingByFrom.PreRegister(engine, "GSStationList_CargoWaiting"); SQGSStationList_CargoWaitingByFrom.AddConstructor(engine, "xii"); SQGSStationList_CargoWaitingByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoWaitingViaByFrom"; } void SQGSStationList_CargoWaitingViaByFrom_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoWaitingViaByFrom("GSStationList_CargoWaitingViaByFrom"); SQGSStationList_CargoWaitingViaByFrom.PreRegister(engine, "GSStationList_CargoWaiting"); SQGSStationList_CargoWaitingViaByFrom.AddConstructor(engine, "xiii"); SQGSStationList_CargoWaitingViaByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoWaitingByVia"; } void SQGSStationList_CargoWaitingByVia_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoWaitingByVia("GSStationList_CargoWaitingByVia"); SQGSStationList_CargoWaitingByVia.PreRegister(engine, "GSStationList_CargoWaiting"); SQGSStationList_CargoWaitingByVia.AddConstructor(engine, "xii"); SQGSStationList_CargoWaitingByVia.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoWaitingFromByVia"; } void SQGSStationList_CargoWaitingFromByVia_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoWaitingFromByVia("GSStationList_CargoWaitingFromByVia"); SQGSStationList_CargoWaitingFromByVia.PreRegister(engine, "GSStationList_CargoWaiting"); SQGSStationList_CargoWaitingFromByVia.AddConstructor(engine, "xiii"); SQGSStationList_CargoWaitingFromByVia.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoPlannedByFrom"; } void SQGSStationList_CargoPlannedByFrom_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoPlannedByFrom("GSStationList_CargoPlannedByFrom"); SQGSStationList_CargoPlannedByFrom.PreRegister(engine, "GSStationList_CargoPlanned"); SQGSStationList_CargoPlannedByFrom.AddConstructor(engine, "xii"); SQGSStationList_CargoPlannedByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoPlannedViaByFrom"; } void SQGSStationList_CargoPlannedViaByFrom_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoPlannedViaByFrom("GSStationList_CargoPlannedViaByFrom"); SQGSStationList_CargoPlannedViaByFrom.PreRegister(engine, "GSStationList_CargoPlanned"); SQGSStationList_CargoPlannedViaByFrom.AddConstructor(engine, "xiii"); SQGSStationList_CargoPlannedViaByFrom.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoPlannedByVia"; } void SQGSStationList_CargoPlannedByVia_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoPlannedByVia("GSStationList_CargoPlannedByVia"); SQGSStationList_CargoPlannedByVia.PreRegister(engine, "GSStationList_CargoPlanned"); SQGSStationList_CargoPlannedByVia.AddConstructor(engine, "xii"); SQGSStationList_CargoPlannedByVia.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_CargoPlannedFromByVia"; } void SQGSStationList_CargoPlannedFromByVia_Register(Squirrel *engine) { DefSQClass SQGSStationList_CargoPlannedFromByVia("GSStationList_CargoPlannedFromByVia"); SQGSStationList_CargoPlannedFromByVia.PreRegister(engine, "GSStationList_CargoPlanned"); SQGSStationList_CargoPlannedFromByVia.AddConstructor(engine, "xiii"); SQGSStationList_CargoPlannedFromByVia.PostRegister(engine); } template <> const char *GetClassName() { return "GSStationList_Vehicle"; } void SQGSStationList_Vehicle_Register(Squirrel *engine) { DefSQClass SQGSStationList_Vehicle("GSStationList_Vehicle"); SQGSStationList_Vehicle.PreRegister(engine, "GSList"); SQGSStationList_Vehicle.AddConstructor(engine, "xi"); SQGSStationList_Vehicle.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_admin.hpp.sq0000644000000000000000000000224112627373433020675 0ustar rootroot/* $Id: game_admin.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_admin.hpp" #include "../template/template_admin.hpp.sq" template <> const char *GetClassName() { return "GSAdmin"; } void SQGSAdmin_Register(Squirrel *engine) { DefSQClass SQGSAdmin("GSAdmin"); SQGSAdmin.PreRegister(engine); SQGSAdmin.AddConstructor(engine, "x"); SQGSAdmin.DefSQAdvancedStaticMethod(engine, &ScriptAdmin::Send, "Send"); SQGSAdmin.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_execmode.hpp.sq0000644000000000000000000000217512627373433021404 0ustar rootroot/* $Id: game_execmode.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_execmode.hpp" #include "../template/template_execmode.hpp.sq" template <> const char *GetClassName() { return "GSExecMode"; } void SQGSExecMode_Register(Squirrel *engine) { DefSQClass SQGSExecMode("GSExecMode"); SQGSExecMode.PreRegister(engine); SQGSExecMode.AddConstructor(engine, "x"); SQGSExecMode.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_error.hpp.sq0000644000000000000000000002603112627373433020741 0ustar rootroot/* $Id: game_error.hpp.sq 24982 2013-02-08 20:34:27Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_error.hpp" #include "../template/template_error.hpp.sq" template <> const char *GetClassName() { return "GSError"; } void SQGSError_Register(Squirrel *engine) { DefSQClass SQGSError("GSError"); SQGSError.PreRegister(engine); SQGSError.AddConstructor(engine, "x"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_NONE, "ERR_CAT_NONE"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_GENERAL, "ERR_CAT_GENERAL"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_VEHICLE, "ERR_CAT_VEHICLE"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_STATION, "ERR_CAT_STATION"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_BRIDGE, "ERR_CAT_BRIDGE"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_TUNNEL, "ERR_CAT_TUNNEL"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_TILE, "ERR_CAT_TILE"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_SIGN, "ERR_CAT_SIGN"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_RAIL, "ERR_CAT_RAIL"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_ROAD, "ERR_CAT_ROAD"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_ORDER, "ERR_CAT_ORDER"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_MARINE, "ERR_CAT_MARINE"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_WAYPOINT, "ERR_CAT_WAYPOINT"); SQGSError.DefSQConst(engine, ScriptError::ERR_CAT_BIT_SIZE, "ERR_CAT_BIT_SIZE"); SQGSError.DefSQConst(engine, ScriptError::ERR_NONE, "ERR_NONE"); SQGSError.DefSQConst(engine, ScriptError::ERR_UNKNOWN, "ERR_UNKNOWN"); SQGSError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_FAILED, "ERR_PRECONDITION_FAILED"); SQGSError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG, "ERR_PRECONDITION_STRING_TOO_LONG"); SQGSError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, "ERR_PRECONDITION_TOO_MANY_PARAMETERS"); SQGSError.DefSQConst(engine, ScriptError::ERR_PRECONDITION_INVALID_COMPANY, "ERR_PRECONDITION_INVALID_COMPANY"); SQGSError.DefSQConst(engine, ScriptError::ERR_NEWGRF_SUPPLIED_ERROR, "ERR_NEWGRF_SUPPLIED_ERROR"); SQGSError.DefSQConst(engine, ScriptError::ERR_GENERAL_BASE, "ERR_GENERAL_BASE"); SQGSError.DefSQConst(engine, ScriptError::ERR_NOT_ENOUGH_CASH, "ERR_NOT_ENOUGH_CASH"); SQGSError.DefSQConst(engine, ScriptError::ERR_LOCAL_AUTHORITY_REFUSES, "ERR_LOCAL_AUTHORITY_REFUSES"); SQGSError.DefSQConst(engine, ScriptError::ERR_ALREADY_BUILT, "ERR_ALREADY_BUILT"); SQGSError.DefSQConst(engine, ScriptError::ERR_AREA_NOT_CLEAR, "ERR_AREA_NOT_CLEAR"); SQGSError.DefSQConst(engine, ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY, "ERR_OWNED_BY_ANOTHER_COMPANY"); SQGSError.DefSQConst(engine, ScriptError::ERR_NAME_IS_NOT_UNIQUE, "ERR_NAME_IS_NOT_UNIQUE"); SQGSError.DefSQConst(engine, ScriptError::ERR_FLAT_LAND_REQUIRED, "ERR_FLAT_LAND_REQUIRED"); SQGSError.DefSQConst(engine, ScriptError::ERR_LAND_SLOPED_WRONG, "ERR_LAND_SLOPED_WRONG"); SQGSError.DefSQConst(engine, ScriptError::ERR_VEHICLE_IN_THE_WAY, "ERR_VEHICLE_IN_THE_WAY"); SQGSError.DefSQConst(engine, ScriptError::ERR_SITE_UNSUITABLE, "ERR_SITE_UNSUITABLE"); SQGSError.DefSQConst(engine, ScriptError::ERR_TOO_CLOSE_TO_EDGE, "ERR_TOO_CLOSE_TO_EDGE"); SQGSError.DefSQConst(engine, ScriptError::ERR_STATION_TOO_SPREAD_OUT, "ERR_STATION_TOO_SPREAD_OUT"); ScriptError::RegisterErrorMap(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY, ScriptError::ERR_NOT_ENOUGH_CASH); ScriptError::RegisterErrorMap(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS, ScriptError::ERR_LOCAL_AUTHORITY_REFUSES); ScriptError::RegisterErrorMap(STR_ERROR_ALREADY_BUILT, ScriptError::ERR_ALREADY_BUILT); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, ScriptError::ERR_ALREADY_BUILT); ScriptError::RegisterErrorMap(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_RAILROAD, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_BUOY_IN_THE_WAY, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_COMPANY_HEADQUARTERS_IN, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_OBJECT_IN_THE_WAY, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_REMOVE_ROAD_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_EXCAVATION_WOULD_DAMAGE, ScriptError::ERR_AREA_NOT_CLEAR); ScriptError::RegisterErrorMap(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER, ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY); ScriptError::RegisterErrorMap(STR_ERROR_OWNED_BY, ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY); ScriptError::RegisterErrorMap(STR_ERROR_NAME_MUST_BE_UNIQUE, ScriptError::ERR_NAME_IS_NOT_UNIQUE); ScriptError::RegisterErrorMap(STR_ERROR_FLAT_LAND_REQUIRED, ScriptError::ERR_FLAT_LAND_REQUIRED); ScriptError::RegisterErrorMap(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION, ScriptError::ERR_LAND_SLOPED_WRONG); ScriptError::RegisterErrorMap(STR_ERROR_TRAIN_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_ROAD_VEHICLE_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_SHIP_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_AIRCRAFT_IN_THE_WAY, ScriptError::ERR_VEHICLE_IN_THE_WAY); ScriptError::RegisterErrorMap(STR_ERROR_SITE_UNSUITABLE, ScriptError::ERR_SITE_UNSUITABLE); ScriptError::RegisterErrorMap(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP, ScriptError::ERR_TOO_CLOSE_TO_EDGE); ScriptError::RegisterErrorMap(STR_ERROR_STATION_TOO_SPREAD_OUT, ScriptError::ERR_STATION_TOO_SPREAD_OUT); ScriptError::RegisterErrorMapString(ScriptError::ERR_NONE, "ERR_NONE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_UNKNOWN, "ERR_UNKNOWN"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_FAILED, "ERR_PRECONDITION_FAILED"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_STRING_TOO_LONG, "ERR_PRECONDITION_STRING_TOO_LONG"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, "ERR_PRECONDITION_TOO_MANY_PARAMETERS"); ScriptError::RegisterErrorMapString(ScriptError::ERR_PRECONDITION_INVALID_COMPANY, "ERR_PRECONDITION_INVALID_COMPANY"); ScriptError::RegisterErrorMapString(ScriptError::ERR_NEWGRF_SUPPLIED_ERROR, "ERR_NEWGRF_SUPPLIED_ERROR"); ScriptError::RegisterErrorMapString(ScriptError::ERR_NOT_ENOUGH_CASH, "ERR_NOT_ENOUGH_CASH"); ScriptError::RegisterErrorMapString(ScriptError::ERR_LOCAL_AUTHORITY_REFUSES, "ERR_LOCAL_AUTHORITY_REFUSES"); ScriptError::RegisterErrorMapString(ScriptError::ERR_ALREADY_BUILT, "ERR_ALREADY_BUILT"); ScriptError::RegisterErrorMapString(ScriptError::ERR_AREA_NOT_CLEAR, "ERR_AREA_NOT_CLEAR"); ScriptError::RegisterErrorMapString(ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY, "ERR_OWNED_BY_ANOTHER_COMPANY"); ScriptError::RegisterErrorMapString(ScriptError::ERR_NAME_IS_NOT_UNIQUE, "ERR_NAME_IS_NOT_UNIQUE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_FLAT_LAND_REQUIRED, "ERR_FLAT_LAND_REQUIRED"); ScriptError::RegisterErrorMapString(ScriptError::ERR_LAND_SLOPED_WRONG, "ERR_LAND_SLOPED_WRONG"); ScriptError::RegisterErrorMapString(ScriptError::ERR_VEHICLE_IN_THE_WAY, "ERR_VEHICLE_IN_THE_WAY"); ScriptError::RegisterErrorMapString(ScriptError::ERR_SITE_UNSUITABLE, "ERR_SITE_UNSUITABLE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_TOO_CLOSE_TO_EDGE, "ERR_TOO_CLOSE_TO_EDGE"); ScriptError::RegisterErrorMapString(ScriptError::ERR_STATION_TOO_SPREAD_OUT, "ERR_STATION_TOO_SPREAD_OUT"); SQGSError.DefSQStaticMethod(engine, &ScriptError::GetErrorCategory, "GetErrorCategory", 1, "."); SQGSError.DefSQStaticMethod(engine, &ScriptError::GetLastError, "GetLastError", 1, "."); SQGSError.DefSQStaticMethod(engine, &ScriptError::GetLastErrorString, "GetLastErrorString", 1, "."); SQGSError.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_list.hpp.sq0000644000000000000000000001040312627373433020557 0ustar rootroot/* $Id: game_list.hpp.sq 26894 2014-09-21 16:25:15Z fonsinchen $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_list.hpp" #include "../template/template_list.hpp.sq" template <> const char *GetClassName() { return "GSList"; } void SQGSList_Register(Squirrel *engine) { DefSQClass SQGSList("GSList"); SQGSList.PreRegister(engine); SQGSList.AddConstructor(engine, "x"); SQGSList.DefSQConst(engine, ScriptList::SORT_BY_VALUE, "SORT_BY_VALUE"); SQGSList.DefSQConst(engine, ScriptList::SORT_BY_ITEM, "SORT_BY_ITEM"); SQGSList.DefSQConst(engine, ScriptList::SORT_ASCENDING, "SORT_ASCENDING"); SQGSList.DefSQConst(engine, ScriptList::SORT_DESCENDING, "SORT_DESCENDING"); SQGSList.DefSQMethod(engine, &ScriptList::AddItem, "AddItem", 3, "xii"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveItem, "RemoveItem", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::Clear, "Clear", 1, "x"); SQGSList.DefSQMethod(engine, &ScriptList::HasItem, "HasItem", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::Begin, "Begin", 1, "x"); SQGSList.DefSQMethod(engine, &ScriptList::Next, "Next", 1, "x"); SQGSList.DefSQMethod(engine, &ScriptList::IsEmpty, "IsEmpty", 1, "x"); SQGSList.DefSQMethod(engine, &ScriptList::IsEnd, "IsEnd", 1, "x"); SQGSList.DefSQMethod(engine, &ScriptList::Count, "Count", 1, "x"); SQGSList.DefSQMethod(engine, &ScriptList::GetValue, "GetValue", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::SetValue, "SetValue", 3, "xii"); SQGSList.DefSQMethod(engine, &ScriptList::Sort, "Sort", 3, "xib"); SQGSList.DefSQMethod(engine, &ScriptList::AddList, "AddList", 2, "xx"); SQGSList.DefSQMethod(engine, &ScriptList::SwapList, "SwapList", 2, "xx"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveAboveValue, "RemoveAboveValue", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveBelowValue, "RemoveBelowValue", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveBetweenValue, "RemoveBetweenValue", 3, "xii"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveValue, "RemoveValue", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveTop, "RemoveTop", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveBottom, "RemoveBottom", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::RemoveList, "RemoveList", 2, "xx"); SQGSList.DefSQMethod(engine, &ScriptList::KeepAboveValue, "KeepAboveValue", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::KeepBelowValue, "KeepBelowValue", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::KeepBetweenValue, "KeepBetweenValue", 3, "xii"); SQGSList.DefSQMethod(engine, &ScriptList::KeepValue, "KeepValue", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::KeepTop, "KeepTop", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::KeepBottom, "KeepBottom", 2, "xi"); SQGSList.DefSQMethod(engine, &ScriptList::KeepList, "KeepList", 2, "xx"); SQGSList.DefSQAdvancedMethod(engine, &ScriptList::_get, "_get"); SQGSList.DefSQAdvancedMethod(engine, &ScriptList::_set, "_set"); SQGSList.DefSQAdvancedMethod(engine, &ScriptList::_nexti, "_nexti"); SQGSList.DefSQAdvancedMethod(engine, &ScriptList::Valuate, "Valuate"); SQGSList.PostRegister(engine); } openttd-1.5.3/src/script/api/game/game_company.hpp.sq0000644000000000000000000001407712627373433021265 0ustar rootroot/* $Id: game_company.hpp.sq 25808 2013-10-02 21:44:31Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_company.hpp" #include "../template/template_company.hpp.sq" template <> const char *GetClassName() { return "GSCompany"; } void SQGSCompany_Register(Squirrel *engine) { DefSQClass SQGSCompany("GSCompany"); SQGSCompany.PreRegister(engine); SQGSCompany.AddConstructor(engine, "x"); SQGSCompany.DefSQConst(engine, ScriptCompany::CURRENT_QUARTER, "CURRENT_QUARTER"); SQGSCompany.DefSQConst(engine, ScriptCompany::EARLIEST_QUARTER, "EARLIEST_QUARTER"); SQGSCompany.DefSQConst(engine, ScriptCompany::COMPANY_FIRST, "COMPANY_FIRST"); SQGSCompany.DefSQConst(engine, ScriptCompany::COMPANY_LAST, "COMPANY_LAST"); SQGSCompany.DefSQConst(engine, ScriptCompany::COMPANY_INVALID, "COMPANY_INVALID"); SQGSCompany.DefSQConst(engine, ScriptCompany::COMPANY_SELF, "COMPANY_SELF"); SQGSCompany.DefSQConst(engine, ScriptCompany::GENDER_MALE, "GENDER_MALE"); SQGSCompany.DefSQConst(engine, ScriptCompany::GENDER_FEMALE, "GENDER_FEMALE"); SQGSCompany.DefSQConst(engine, ScriptCompany::GENDER_INVALID, "GENDER_INVALID"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_CONSTRUCTION, "EXPENSES_CONSTRUCTION"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_NEW_VEHICLES, "EXPENSES_NEW_VEHICLES"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_TRAIN_RUN, "EXPENSES_TRAIN_RUN"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_ROADVEH_RUN, "EXPENSES_ROADVEH_RUN"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_AIRCRAFT_RUN, "EXPENSES_AIRCRAFT_RUN"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_SHIP_RUN, "EXPENSES_SHIP_RUN"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_PROPERTY, "EXPENSES_PROPERTY"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_TRAIN_INC, "EXPENSES_TRAIN_INC"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_ROADVEH_INC, "EXPENSES_ROADVEH_INC"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_AIRCRAFT_INC, "EXPENSES_AIRCRAFT_INC"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_SHIP_INC, "EXPENSES_SHIP_INC"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_LOAN_INT, "EXPENSES_LOAN_INT"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_OTHER, "EXPENSES_OTHER"); SQGSCompany.DefSQConst(engine, ScriptCompany::EXPENSES_INVALID, "EXPENSES_INVALID"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::ResolveCompanyID, "ResolveCompanyID", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::SetName, "SetName", 2, ".."); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetName, "GetName", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::SetPresidentName, "SetPresidentName", 2, ".."); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetPresidentName, "GetPresidentName", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetPresidentGender, "GetPresidentGender", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::SetLoanAmount, "SetLoanAmount", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::SetMinimumLoanAmount, "SetMinimumLoanAmount", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetLoanAmount, "GetLoanAmount", 1, "."); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetMaxLoanAmount, "GetMaxLoanAmount", 1, "."); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetLoanInterval, "GetLoanInterval", 1, "."); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetBankBalance, "GetBankBalance", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::ChangeBankBalance, "ChangeBankBalance", 4, ".iii"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyIncome, "GetQuarterlyIncome", 3, ".ii"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyExpenses, "GetQuarterlyExpenses", 3, ".ii"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyCargoDelivered, "GetQuarterlyCargoDelivered", 3, ".ii"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyPerformanceRating, "GetQuarterlyPerformanceRating", 3, ".ii"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetQuarterlyCompanyValue, "GetQuarterlyCompanyValue", 3, ".ii"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::BuildCompanyHQ, "BuildCompanyHQ", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetCompanyHQ, "GetCompanyHQ", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetAutoRenewStatus, "GetAutoRenewStatus", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetAutoRenewMonths, "GetAutoRenewMonths", 2, ".i"); SQGSCompany.DefSQStaticMethod(engine, &ScriptCompany::GetAutoRenewMoney, "GetAutoRenewMoney", 2, ".i"); SQGSCompany.PostRegister(engine); } openttd-1.5.3/src/script/api/script_airport.hpp0000644000000000000000000001707512627373433020340 0ustar rootroot/* $Id: script_airport.hpp 25705 2013-08-09 18:43:44Z rubidium $ */ /* * 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 script_airport.hpp Everything to query and build airports. */ #ifndef SCRIPT_AIRPORT_HPP #define SCRIPT_AIRPORT_HPP #include "script_object.hpp" #include "../../airport.h" /** * Class that handles all airport related functions. * @api ai game */ class ScriptAirport : public ScriptObject { public: /** * The types of airports available in the game. */ enum AirportType { /* Note: these values represent part of the in-game AirportTypes enum */ AT_SMALL = ::AT_SMALL, ///< The small airport. AT_LARGE = ::AT_LARGE, ///< The large airport. AT_METROPOLITAN = ::AT_METROPOLITAN, ///< The metropolitan airport. AT_INTERNATIONAL = ::AT_INTERNATIONAL, ///< The international airport. AT_COMMUTER = ::AT_COMMUTER, ///< The commuter airport. AT_INTERCON = ::AT_INTERCON, ///< The intercontinental airport. AT_HELIPORT = ::AT_HELIPORT, ///< The heliport. AT_HELISTATION = ::AT_HELISTATION, ///< The helistation. AT_HELIDEPOT = ::AT_HELIDEPOT, ///< The helidepot. AT_INVALID = ::AT_INVALID, ///< Invalid airport. }; /** * All plane types available. */ enum PlaneType { /* Note: these values represent part of the in-game values, which are not defined in an enum */ PT_HELICOPTER = 0, ///< A helicopter. PT_SMALL_PLANE = 1, ///< A small plane. PT_BIG_PLANE = 3, ///< A big plane. PT_INVALID = -1, ///< An invalid PlaneType }; /** * Checks whether the given AirportType is valid and available. * @param type The AirportType to check. * @return True if and only if the AirportType is valid and available. * @post return value == true -> IsAirportInformationAvailable returns true. */ static bool IsValidAirportType(AirportType type); /** * Can you get information on this airport type? As opposed to * IsValidAirportType this will return also return true when * an airport type is no longer buildable. * @param type The AirportType to check. * @return True if and only if the AirportType is valid. * @post return value == false -> IsValidAirportType returns false. */ static bool IsAirportInformationAvailable(AirportType type); /** * Get the cost to build this AirportType. * @param type The AirportType to check. * @pre AirportAvailable(type). * @return The cost of building this AirportType. */ static Money GetPrice(AirportType type); /** * Checks whether the given tile is actually a tile with a hangar. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a hangar. */ static bool IsHangarTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with an airport. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has an airport. */ static bool IsAirportTile(TileIndex tile); /** * Get the width of this type of airport. * @param type The type of airport. * @pre IsAirportInformationAvailable(type). * @return The width in tiles. */ static int32 GetAirportWidth(AirportType type); /** * Get the height of this type of airport. * @param type The type of airport. * @pre IsAirportInformationAvailable(type). * @return The height in tiles. */ static int32 GetAirportHeight(AirportType type); /** * Get the coverage radius of this type of airport. * @param type The type of airport. * @pre IsAirportInformationAvailable(type). * @return The radius in tiles. */ static int32 GetAirportCoverageRadius(AirportType type); /** * Get the number of hangars of the airport. * @param tile Any tile of the airport. * @pre ScriptMap::IsValidTile(tile). * @return The number of hangars of the airport. */ static int32 GetNumHangars(TileIndex tile); /** * Get the first hangar tile of the airport. * @param tile Any tile of the airport. * @pre ScriptMap::IsValidTile(tile). * @pre GetNumHangars(tile) > 0. * @return The first hangar tile of the airport. * @note Possible there are more hangars, but you won't be able to find them * without walking over all the tiles of the airport and using * IsHangarTile() on them. */ static TileIndex GetHangarOfAirport(TileIndex tile); /** * Builds a airport with tile at the topleft corner. * @param tile The topleft corner of the airport. * @param type The type of airport to build. * @param station_id The station to join, ScriptStation::STATION_NEW or ScriptStation::STATION_JOIN_ADJACENT. * @pre ScriptMap::IsValidTile(tile). * @pre AirportAvailable(type). * @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @exception ScriptError::ERR_LOCAL_AUTHORITY_REFUSES * @exception ScriptStation::ERR_STATION_TOO_LARGE * @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION * @return Whether the airport has been/can be build or not. */ static bool BuildAirport(TileIndex tile, AirportType type, StationID station_id); /** * Removes an airport. * @param tile Any tile of the airport. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return Whether the airport has been/can be removed or not. */ static bool RemoveAirport(TileIndex tile); /** * Get the AirportType of an existing airport. * @param tile Any tile of the airport. * @pre ScriptTile::IsStationTile(tile). * @pre ScriptStation::HasStationType(ScriptStation.GetStationID(tile), ScriptStation::STATION_AIRPORT). * @return The AirportType of the airport. */ static AirportType GetAirportType(TileIndex tile); /** * Get the noise that will be added to the nearest town if an airport was * built at this tile. * @param tile The tile to check. * @param type The AirportType to check. * @pre IsAirportInformationAvailable(type). * @return The amount of noise added to the nearest town. * @note The noise will be added to the town with TownID GetNearestTown(tile, type). */ static int GetNoiseLevelIncrease(TileIndex tile, AirportType type); /** * Get the TownID of the town whose local authority will influence * an airport at some tile. * @param tile The tile to check. * @param type The AirportType to check. * @pre IsAirportInformationAvailable(type). * @return The TownID of the town closest to the tile. */ static TownID GetNearestTown(TileIndex tile, AirportType type); /** * Get the maintenance cost factor of an airport type. * @param type The airport type to get the maintenance factor of. * @pre IsAirportInformationAvailable(type) * @return Maintenance cost factor of the airport type. */ static uint16 GetMaintenanceCostFactor(AirportType type); }; #endif /* SCRIPT_AIRPORT_HPP */ openttd-1.5.3/src/script/api/game_changelog.hpp0000644000000000000000000001004312627373434020201 0ustar rootroot/* $Id: game_changelog.hpp 27433 2015-11-01 12:09:41Z frosch $ */ /* * 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 game_changelog.hpp Lists all changes / additions to the API. * * Only new / renamed / deleted api functions will be listed here. A list of * bug fixes can be found in the normal changelog. Note that removed API * functions may still be available if you return an older API version * in GetAPIVersion() in info.nut. * * \b 1.5.3 * * No changes * * \b 1.5.2 * * No changes * * \b 1.5.1 * * No changes * * \b 1.5.0 * * API additions: * \li GSList::SwapList * \li GSStation::GetCargoPlanned * \li GSStation::GetCargoPlannedFrom * \li GSStation::GetCargoPlannedFromVia * \li GSStation::GetCargoPlannedVia * \li GSStation::GetCargoWaitingFromVia * \li GSStationList_CargoPlannedByFrom * \li GSStationList_CargoPlannedByVia * \li GSStationList_CargoPlannedFromByVia * \li GSStationList_CargoPlannedViaByFrom * \li GSStationList_CargoWaitingByFrom * \li GSStationList_CargoWaitingByVia * \li GSStationList_CargoWaitingFromByVia * \li GSStationList_CargoWaitingViaByFrom * * Other changes: * \li GSNews::Create takes two extra parameters to refer to a location, station, * industry, or town. The user can click at the news message to jump to the * referred location. * * \b 1.4.4 * * No changes * * \b 1.4.3 * * No changes * * \b 1.4.2 * * Other changes: * \li GSCargoMonitor delivery and pickup monitor functions have improved boundary checking for * their parameters, and return \c -1 if they are found out of bounds. * * \b 1.4.1 * * No changes * * \b 1.4.0 * * API additions: * \li AICargo::GetDistributionType * \li GSCompany::ChangeBankBalance * \li GSDate::DATE_INVALID * \li GSDate::IsValidDate * \li GSGoal::GT_STORY_PAGE * \li GSGoal::IsCompleted * \li GSGoal::SetCompleted * \li GSGoal::SetProgress * \li GSGoal::SetText * \li GSStation::HasCargoRating * \li GSStation::GetCargoWaitingFrom * \li GSStation::GetCargoWaitingVia * \li GSStoryPage * \li GSStoryPageList * \li GSStoryPageElementList * \li GSTile::GetTerrainType * \li GSTown::FoundTown * \li GSTown::GetFundBuildingsDuration * \li GSTown::SetName * \li GSTown::TOWN_GROWTH_NONE * \li GSTown::TOWN_GROWTH_NORMAL * * Other changes: * \li GSGoal::New can now create up to 64000 concurrent goals. The old limit was 256 goals. * \li GSStation::GetCargoRating does return -1 for cargo-station combinations that * do not have a rating yet instead of returning 69. * * \b 1.3.3 * * No changes * * \b 1.3.2 * * No changes * * \b 1.3.1 * * API additions: * \li GSTile::GetTerrainType * * \b 1.3.0 * * API additions: * \li GSCargoMonitor * \li GSEngine::IsValidEngine and GSEngine::IsBuildable when outside GSCompanyMode scope * \li GSEventExclusiveTransportRights * \li GSEventRoadReconstruction * \li GSNews::NT_ACCIDENT, GSNews::NT_COMPANY_INFO, GSNews::NT_ADVICE, GSNews::NT_ACCEPTANCE * \li GSIndustryType::IsProcessingIndustry * \li GSStation::IsAirportClosed * \li GSStation::OpenCloseAirport * \li GSController::Break * \li GSIndustryType::BuildIndustry, GSIndustryType::CanBuildIndustry, GSIndustryType::ProspectIndustry and GSIndustryType::CanProspectIndustry when outside GSCompanyMode scope * * Other changes: * \li Company specific goals are now removed when a company goes bankrupt or is taken over. * * \b 1.2.3 * * No changes * * \b 1.2.2 * * No changes * * \b 1.2.1 * * No changes * * \b 1.2.0 * \li First stable release with the NoGo framework. */ openttd-1.5.3/src/script/api/script_error.hpp0000644000000000000000000002200012627373434017772 0ustar rootroot/* $Id: script_error.hpp 24982 2013-02-08 20:34:27Z rubidium $ */ /* * 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 script_error.hpp Everything to query errors. */ #ifndef SCRIPT_ERROR_HPP #define SCRIPT_ERROR_HPP #include "script_object.hpp" #include /** * Helper to write precondition enforcers for the script API in an abbreviated manner. * @param returnval The value to return on failure. * @param condition The condition that must be obeyed. */ #define EnforcePrecondition(returnval, condition) \ if (!(condition)) { \ ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED); \ return returnval; \ } /** * Helper to write precondition enforcers for the script API in an abbreviated manner. * @param returnval The value to return on failure. * @param condition The condition that must be obeyed. * @param error_code The error code passed to ScriptObject::SetLastError. */ #define EnforcePreconditionCustomError(returnval, condition, error_code) \ if (!(condition)) { \ ScriptObject::SetLastError(error_code); \ return returnval; \ } /** * Helper to write precondition enforcers for the script API in an abbreviated manner for encoded texts. * @param returnval The value to return on failure. * @param string The string that is checked. */ #define EnforcePreconditionEncodedText(returnval, string) \ if ((string) == NULL) { \ ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_TOO_MANY_PARAMETERS); \ return returnval; \ } \ if (StrEmpty(string)) { \ ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED); \ return returnval; \ } /** * Class that handles all error related functions. * @api ai game */ class ScriptError : public ScriptObject { public: /** * All categories errors can be divided in. */ enum ErrorCategories { ERR_CAT_NONE = 0, ///< Error messages not related to any category. ERR_CAT_GENERAL, ///< Error messages related to general things. ERR_CAT_VEHICLE, ///< Error messages related to building / maintaining vehicles. ERR_CAT_STATION, ///< Error messages related to building / maintaining stations. ERR_CAT_BRIDGE, ///< Error messages related to building / removing bridges. ERR_CAT_TUNNEL, ///< Error messages related to building / removing tunnels. ERR_CAT_TILE, ///< Error messages related to raising / lowering and demolishing tiles. ERR_CAT_SIGN, ///< Error messages related to building / removing signs. ERR_CAT_RAIL, ///< Error messages related to building / maintaining rails. ERR_CAT_ROAD, ///< Error messages related to building / maintaining roads. ERR_CAT_ORDER, ///< Error messages related to managing orders. ERR_CAT_MARINE, ///< Error messages related to building / removing ships, docks and channels. ERR_CAT_WAYPOINT, ///< Error messages related to building / maintaining waypoints. /** * DO NOT USE! The error bitsize determines how many errors can be stored in * a category and what the offsets are of all categories. */ ERR_CAT_BIT_SIZE = 8, }; /** * All general related error messages. */ enum ErrorMessages { /** Initial error value */ ERR_NONE = ERR_CAT_NONE << ERR_CAT_BIT_SIZE, // [] /** If an error occurred and the error wasn't mapped */ ERR_UNKNOWN, // [] /** If a precondition is not met */ ERR_PRECONDITION_FAILED, // [] /** A string supplied was too long */ ERR_PRECONDITION_STRING_TOO_LONG, // [] /** A string had too many parameters */ ERR_PRECONDITION_TOO_MANY_PARAMETERS, // [] /** The company you use is invalid */ ERR_PRECONDITION_INVALID_COMPANY, // [] /** An error returned by a NewGRF. No possibility to get the exact error in an script readable format */ ERR_NEWGRF_SUPPLIED_ERROR, // [] /** Base for general errors */ ERR_GENERAL_BASE = ERR_CAT_GENERAL << ERR_CAT_BIT_SIZE, /** Not enough cash to perform the previous action */ ERR_NOT_ENOUGH_CASH, // [STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY] /** Local authority won't allow the previous action */ ERR_LOCAL_AUTHORITY_REFUSES, // [STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS] /** The piece of infrastructure you tried to build is already in place */ ERR_ALREADY_BUILT, // [STR_ERROR_ALREADY_BUILT, STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST] /** Area isn't clear, try to demolish the building on it */ ERR_AREA_NOT_CLEAR, // [STR_ERROR_BUILDING_MUST_BE_DEMOLISHED, STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, STR_ERROR_MUST_DEMOLISH_RAILROAD, STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST, STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST, STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST, STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST, STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST, STR_ERROR_BUOY_IN_THE_WAY, STR_ERROR_MUST_DEMOLISH_DOCK_FIRST, STR_ERROR_GENERIC_OBJECT_IN_THE_WAY, STR_ERROR_COMPANY_HEADQUARTERS_IN, STR_ERROR_OBJECT_IN_THE_WAY, STR_ERROR_MUST_REMOVE_ROAD_FIRST, STR_ERROR_MUST_REMOVE_RAILROAD_TRACK, STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST, STR_ERROR_EXCAVATION_WOULD_DAMAGE] /** Area / property is owned by another company */ ERR_OWNED_BY_ANOTHER_COMPANY, // [STR_ERROR_AREA_IS_OWNED_BY_ANOTHER, STR_ERROR_OWNED_BY] /** The name given is not unique for the object type */ ERR_NAME_IS_NOT_UNIQUE, // [STR_ERROR_NAME_MUST_BE_UNIQUE] /** The building you want to build requires flat land */ ERR_FLAT_LAND_REQUIRED, // [STR_ERROR_FLAT_LAND_REQUIRED] /** Land is sloped in the wrong direction for this build action */ ERR_LAND_SLOPED_WRONG, // [STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION] /** A vehicle is in the way */ ERR_VEHICLE_IN_THE_WAY, // [STR_ERROR_TRAIN_IN_THE_WAY, STR_ERROR_ROAD_VEHICLE_IN_THE_WAY, STR_ERROR_SHIP_IN_THE_WAY, STR_ERROR_AIRCRAFT_IN_THE_WAY] /** Site is unsuitable */ ERR_SITE_UNSUITABLE, // [STR_ERROR_SITE_UNSUITABLE] /** Too close to the edge of the map */ ERR_TOO_CLOSE_TO_EDGE, // [STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP] /** Station is too spread out */ ERR_STATION_TOO_SPREAD_OUT, // [STR_ERROR_STATION_TOO_SPREAD_OUT] }; /** * Check the membership of the last thrown error. * @return The category the error belongs to. * @note The last throw error can be acquired by calling GetLastError(). */ static ErrorCategories GetErrorCategory(); /** * Get the last error. * @return An ErrorMessages enum value. */ static ScriptErrorType GetLastError(); /** * Get the last error in string format (for human readability). * @return An ErrorMessage enum item, as string. */ static char *GetLastErrorString(); /** * Get the error based on the OpenTTD StringID. * @api -all * @param internal_string_id The string to convert. * @return The script equivalent error message. */ static ScriptErrorType StringToError(StringID internal_string_id); /** * Map an internal OpenTTD error message to its script equivalent. * @api -all * @param internal_string_id The OpenTTD StringID used for an error. * @param ai_error_msg The script equivalent error message. */ static void RegisterErrorMap(StringID internal_string_id, ScriptErrorType ai_error_msg); /** * Map an internal OpenTTD error message to its script equivalent. * @api -all * @param ai_error_msg The script error message representation. * @param message The string representation of this error message, used for debug purposes. */ static void RegisterErrorMapString(ScriptErrorType ai_error_msg, const char *message); private: typedef std::map ScriptErrorMap; ///< The type for mapping between error (internal OpenTTD) StringID to the script error type. typedef std::map ScriptErrorMapString; ///< The type for mapping between error type and textual representation. static ScriptErrorMap error_map; ///< The mapping between error (internal OpenTTD) StringID to the script error type. static ScriptErrorMapString error_map_string; ///< The mapping between error type and textual representation. }; #endif /* SCRIPT_ERROR_HPP */ openttd-1.5.3/src/script/api/generate_widget.sh0000755000000000000000000000175312627373434020254 0ustar rootroot#!/bin/bash # $Id: generate_widget.sh 24664 2012-11-05 19:53:05Z frosch $ # 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 . # Set neutral locale so sort behaves the same everywhere LC_ALL=C export LC_ALL # We really need gawk for this! AWK=gawk ${AWK} --version > /dev/null 2> /dev/null if [ "$?" != "0" ]; then echo "This script needs gawk to run properly" exit 1 fi ${AWK} -f generate_widget.awk script_window.hpp > script_window.tmp mv script_window.tmp script_window.hpp openttd-1.5.3/src/script/api/script_date.hpp0000644000000000000000000000605412627373434017571 0ustar rootroot/* $Id: script_date.hpp 26307 2014-02-06 19:50:34Z zuu $ */ /* * 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 script_date.hpp Everything to query and manipulate date related information. */ #ifndef SCRIPT_DATE_HPP #define SCRIPT_DATE_HPP #include "script_object.hpp" #include "../../date_type.h" /** * Class that handles all date related (calculation) functions. * @api ai game * * @note Months and days of month are 1-based; the first month of the * year is 1 and the first day of the month is also 1. * @note Years are zero based; they start with the year 0. * @note Dates can be used to determine the number of days between * two different moments in time because they count the number * of days since the year 0. */ class ScriptDate : public ScriptObject { public: /** * Date data type is an integer value. Use ScriptDate::GetDate to * compose valid date values for a known year, month and day. */ enum Date { DATE_INVALID = ::INVALID_DATE, ///< A value representing an invalid date. }; /** * Validates if a date value represent a valid date. * @param date The date to validate. * @return True if the date is valid, otherwise false */ static bool IsValidDate(Date date); /** * Get the current date. * This is the number of days since epoch under the assumption that * there is a leap year every 4 years, except when dividable by * 100 but not by 400. * @return The current date. */ static Date GetCurrentDate(); /** * Get the year of the given date. * @param date The date to get the year of. * @return The year. */ static int32 GetYear(Date date); /** * Get the month of the given date. * @param date The date to get the month of. * @return The month. */ static int32 GetMonth(Date date); /** * Get the day (of the month) of the given date. * @param date The date to get the day of. * @return The day. */ static int32 GetDayOfMonth(Date date); /** * Get the date given a year, month and day of month. * @param year The year of the to-be determined date. * @param month The month of the to-be determined date. * @param day_of_month The day of month of the to-be determined date. * @return The date. */ static Date GetDate(int32 year, int32 month, int32 day_of_month); /** * Get the time of the host system. * @return The amount of seconds passed since 1 Jan 1970. * @api -ai * @note This uses the clock of the host system, which can skew or be set back. Use with caution. */ static int32 GetSystemTime(); }; #endif /* SCRIPT_DATE_HPP */ openttd-1.5.3/src/script/api/script_group.cpp0000644000000000000000000001174612627373434020007 0ustar rootroot/* $Id: script_group.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_group.cpp Implementation of ScriptGroup. */ #include "../../stdafx.h" #include "script_group.hpp" #include "script_engine.hpp" #include "../script_instance.hpp" #include "../../string_func.h" #include "../../strings_func.h" #include "../../autoreplace_func.h" #include "../../settings_func.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ bool ScriptGroup::IsValidGroup(GroupID group_id) { const Group *g = ::Group::GetIfValid(group_id); return g != NULL && g->owner == ScriptObject::GetCompany(); } /* static */ ScriptGroup::GroupID ScriptGroup::CreateGroup(ScriptVehicle::VehicleType vehicle_type) { if (!ScriptObject::DoCommand(0, (::VehicleType)vehicle_type, 0, CMD_CREATE_GROUP, NULL, &ScriptInstance::DoCommandReturnGroupID)) return GROUP_INVALID; /* In case of test-mode, we return GroupID 0 */ return (ScriptGroup::GroupID)0; } /* static */ bool ScriptGroup::DeleteGroup(GroupID group_id) { EnforcePrecondition(false, IsValidGroup(group_id)); return ScriptObject::DoCommand(0, group_id, 0, CMD_DELETE_GROUP); } /* static */ ScriptVehicle::VehicleType ScriptGroup::GetVehicleType(GroupID group_id) { if (!IsValidGroup(group_id)) return ScriptVehicle::VT_INVALID; return (ScriptVehicle::VehicleType)((::VehicleType)::Group::Get(group_id)->vehicle_type); } /* static */ bool ScriptGroup::SetName(GroupID group_id, Text *name) { CCountedPtr counter(name); EnforcePrecondition(false, IsValidGroup(group_id)); EnforcePrecondition(false, name != NULL); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_GROUP_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::DoCommand(0, group_id, 0, CMD_ALTER_GROUP, text); } /* static */ char *ScriptGroup::GetName(GroupID group_id) { if (!IsValidGroup(group_id)) return NULL; ::SetDParam(0, group_id); return GetString(STR_GROUP_NAME); } /* static */ bool ScriptGroup::EnableAutoReplaceProtection(GroupID group_id, bool enable) { EnforcePrecondition(false, IsValidGroup(group_id)); return ScriptObject::DoCommand(0, group_id, enable ? 1 : 0, CMD_SET_GROUP_REPLACE_PROTECTION); } /* static */ bool ScriptGroup::GetAutoReplaceProtection(GroupID group_id) { if (!IsValidGroup(group_id)) return false; return ::Group::Get(group_id)->replace_protection; } /* static */ int32 ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id) { if (!IsValidGroup(group_id) && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return -1; return GetGroupNumEngines(ScriptObject::GetCompany(), group_id, engine_id); } /* static */ bool ScriptGroup::MoveVehicle(GroupID group_id, VehicleID vehicle_id) { EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT); EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); return ScriptObject::DoCommand(0, group_id, vehicle_id, CMD_ADD_VEHICLE_GROUP); } /* static */ bool ScriptGroup::EnableWagonRemoval(bool enable_removal) { if (HasWagonRemoval() == enable_removal) return true; return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.renew_keep_length"), enable_removal ? 1 : 0, CMD_CHANGE_COMPANY_SETTING); } /* static */ bool ScriptGroup::HasWagonRemoval() { return ::Company::Get(ScriptObject::GetCompany())->settings.renew_keep_length; } /* static */ bool ScriptGroup::SetAutoReplace(GroupID group_id, EngineID engine_id_old, EngineID engine_id_new) { EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL); EnforcePrecondition(false, ScriptEngine::IsBuildable(engine_id_new)); return ScriptObject::DoCommand(0, group_id << 16, (engine_id_new << 16) | engine_id_old, CMD_SET_AUTOREPLACE); } /* static */ EngineID ScriptGroup::GetEngineReplacement(GroupID group_id, EngineID engine_id) { if (!IsValidGroup(group_id) && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return ::INVALID_ENGINE; return ::EngineReplacementForCompany(Company::Get(ScriptObject::GetCompany()), engine_id, group_id); } /* static */ bool ScriptGroup::StopAutoReplace(GroupID group_id, EngineID engine_id) { EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL); return ScriptObject::DoCommand(0, group_id << 16, (::INVALID_ENGINE << 16) | engine_id, CMD_SET_AUTOREPLACE); } openttd-1.5.3/src/script/api/script_controller.hpp0000644000000000000000000002065212627373434021037 0ustar rootroot/* $Id: script_controller.hpp 27111 2015-01-04 15:14:13Z alberth $ */ /* * 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 script_controller.hpp The controller of the script. */ #ifndef SCRIPT_CONTROLLER_HPP #define SCRIPT_CONTROLLER_HPP #include "script_types.hpp" #include "../../core/string_compare_type.hpp" #include /** * The Controller, the class each Script should extend. It creates the Script, * makes sure the logic kicks in correctly, and that #GetTick() has a valid * value. * * When starting a new game, or when loading a game, OpenTTD tries to match a * script that matches to the specified version as close as possible. It tries * (from first to last, stopping as soon as the attempt succeeds) * * - load the exact same version of the same script, * - load the latest version of the same script that supports loading data from * the saved version (the version of saved data must be equal or greater * than ScriptInfo::MinVersionToLoad), * - load the latest version of the same script (ignoring version requirements), * - (for AIs) load a random AI, and finally * - (for AIs) load the dummy AI. * * After determining the script to use, starting it is done as follows * * - An instance is constructed of the class derived from ScriptController * (class name is retrieved from ScriptInfo::CreateInstance). * - If there is script data available in the loaded game and if the data is * loadable according to ScriptInfo::MinVersionToLoad, #Load is called with the * data from the loaded game. * - Finally, #Start is called to start execution of the script. * * See also http://wiki.openttd.org/AI:Save/Load for more details. * * @api ai game */ class ScriptController { friend class AIScanner; friend class ScriptInstance; public: /** * Initializer of the ScriptController. * @param company The company this Script is normally serving. */ ScriptController(CompanyID company); /** * Destructor of the ScriptController. */ ~ScriptController(); /** * This function is called to start your script. Your script starts here. If you * return from this function, your script dies, so make sure that doesn't * happen. * @note Cannot be called from within your script. */ void Start(); #ifdef DOXYGEN_API /** * Save the state of the script. * * By implementing this function, you can store some data inside the savegame. * The function should return a table with the information you want to store. * You can only store: * * - integers, * - strings, * - arrays (max. 25 levels deep), * - tables (max. 25 levels deep), * - booleans, and * - nulls. * * In particular, instances of classes can't be saved including * ScriptList. Such a list should be converted to an array or table on * save and converted back on load. * * The function is called as soon as the user saves the game, * independently of other activities of the script. The script is not * notified of the call. To avoid race-conditions between #Save and the * other script code, change variables directly after a #Sleep, it is * very unlikely, to get interrupted at that point in the execution. * See also http://wiki.openttd.org/AI:Save/Load for more details. * * @note No other information is saved than the table returned by #Save. * For example all pending events are lost as soon as the game is loaded. * * @return Data of the script that should be stored in the save game. */ SquirrelTable Save(); /** * Load saved data just before calling #Start. * The function is only called when there is data to load. * @param version Version number of the script that created the \a data. * @param data Data that was saved (return value of #Save). */ void Load(int version, SquirrelTable data); #endif /* DOXYGEN_API */ /** * Find at which tick your script currently is. * @return returns the current tick. */ static uint GetTick(); /** * Get the number of operations the script may still execute this tick. * @return The amount of operations left to execute. * @note This number can go negative when certain uninteruptable * operations are executed. The amount of operations that you go * over the limit will be deducted from the next tick you would * be allowed to run. */ static int GetOpsTillSuspend(); /** * Get the value of one of your settings you set via info.nut. * @param name The name of the setting. * @return the value for the setting, or -1 if the setting is not known. */ static int GetSetting(const char *name); /** * Get the OpenTTD version of this executable. The version is formatted * with the bits having the following meaning: * 28-31 major version * 24-27 minor version * 20-23 build * 19 1 if it is a release, 0 if it is not. * 0-18 revision number; 0 when the revision is unknown. * @return The version in newgrf format. */ static uint GetVersion(); /** * Change the minimum amount of time the script should be put in suspend mode * when you execute a command. Normally in SP this is 1, and in MP it is * what ever delay the server has been programmed to delay commands * (normally between 1 and 5). To give a more 'real' effect to your script, * you can control that number here. * @param ticks The minimum amount of ticks to wait. * @pre Ticks should be positive. Too big values will influence performance of the script. * @note If the number is lower than the MP setting, the MP setting wins. */ static void SetCommandDelay(int ticks); /** * Sleep for X ticks. The code continues after this line when the X script ticks * are passed. Mind that an script tick is different from in-game ticks and * differ per script speed. * @param ticks the ticks to wait * @pre ticks > 0. * @post the value of GetTick() will be changed exactly 'ticks' in value after * calling this. */ static void Sleep(int ticks); /** * Break execution of the script when script developer tools are active. For * other users, nothing will happen when you call this function. To resume * the script, you have to click on the continue button in the AI debug * window. It is not recommended to leave calls to this function in scripts * that you publish or upload to bananas. * @param message to print in the AI debug window when the break occurs. * @note gui.ai_developer_tools setting must be enabled or the break is * ignored. */ static void Break(const char* message); /** * When Squirrel triggers a print, this function is called. * Squirrel calls this when 'print' is used, or when the script made an error. * @param error_msg If true, it is a Squirrel error message. * @param message The message Squirrel logged. * @note Use ScriptLog.Info/Warning/Error instead of 'print'. */ static void Print(bool error_msg, const char *message); /** * Import a library. * @param library The name of the library to import. The name should be composed as ScriptInfo::GetCategory() + "." + * ScriptInfo::CreateInstance(). * @param class_name Under which name you want it to be available (or "" if you just want the returning object). * @param version Which version you want specifically. * @return The loaded library object. If class_name is set, it is also available (under the scope of the import) under that name. * @note This command can be called from the global space, and does not need an instance. */ static HSQOBJECT Import(const char *library, const char *class_name, int version); private: typedef std::map LoadedLibraryList; ///< The type for loaded libraries. uint ticks; ///< The amount of ticks we're sleeping. LoadedLibraryList loaded_library; ///< The libraries we loaded. int loaded_library_count; ///< The amount of libraries. /** * Register all classes that are known inside the script API. */ void RegisterClasses(); }; #endif /* SCRIPT_CONTROLLER_HPP */ openttd-1.5.3/src/script/api/script_waypoint.hpp0000644000000000000000000000536612627373434020533 0ustar rootroot/* $Id: script_waypoint.hpp 23770 2012-01-07 18:37:22Z smatz $ */ /* * 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 script_waypoint.hpp Everything to query and build waypoints. */ #ifndef SCRIPT_WAYPOINT_HPP #define SCRIPT_WAYPOINT_HPP #include "script_basestation.hpp" #include "script_error.hpp" #include "../../station_type.h" /** * Class that handles all waypoint related functions. * @api ai game */ class ScriptWaypoint : public ScriptBaseStation { public: /** * All waypoint related error messages. */ enum ErrorMessages { /** Base for waypoint related errors */ ERR_WAYPOINT_BASE = ScriptError::ERR_CAT_WAYPOINT << ScriptError::ERR_CAT_BIT_SIZE, /** The waypoint is build too close to another waypoint */ ERR_WAYPOINT_TOO_CLOSE_TO_ANOTHER_WAYPOINT, // [STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT] /** The waypoint would join more than one existing waypoint together. */ ERR_WAYPOINT_ADJOINS_MULTIPLE_WAYPOINTS, // [STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING] }; /** * Type of waypoints known in the game. */ enum WaypointType { /* Note: these values represent part of the in-game StationFacility enum */ WAYPOINT_RAIL = (int)::FACIL_TRAIN, ///< Rail waypoint WAYPOINT_BUOY = (int)::FACIL_DOCK, ///< Buoy WAYPOINT_ANY = WAYPOINT_RAIL | WAYPOINT_BUOY, ///< All waypoint types }; /** * Checks whether the given waypoint is valid and owned by you. * @param waypoint_id The waypoint to check. * @return True if and only if the waypoint is valid. */ static bool IsValidWaypoint(StationID waypoint_id); /** * Get the StationID of a tile. * @param tile The tile to find the StationID of. * @pre ScriptRail::IsRailWaypointTile(tile). * @return StationID of the waypoint. */ static StationID GetWaypointID(TileIndex tile); /** * Check if any part of the waypoint contains a waypoint of the type waypoint_type * @param waypoint_id The waypoint to look at. * @param waypoint_type The WaypointType to look for. * @return True if the waypoint has a waypoint part of the type waypoint_type. */ static bool HasWaypointType(StationID waypoint_id, WaypointType waypoint_type); }; DECLARE_ENUM_AS_BIT_SET(ScriptWaypoint::WaypointType) #endif /* SCRIPT_WAYPOINT_HPP */ openttd-1.5.3/src/script/api/script_depotlist.cpp0000644000000000000000000000354112627373434020654 0ustar rootroot/* $Id: script_depotlist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_depotlist.cpp Implementation of ScriptDepotList and friends. */ #include "../../stdafx.h" #include "script_depotlist.hpp" #include "../../depot_base.h" #include "../../station_base.h" #include "../../safeguards.h" ScriptDepotList::ScriptDepotList(ScriptTile::TransportType transport_type) { ::TileType tile_type; switch (transport_type) { default: return; case ScriptTile::TRANSPORT_ROAD: tile_type = ::MP_ROAD; break; case ScriptTile::TRANSPORT_RAIL: tile_type = ::MP_RAILWAY; break; case ScriptTile::TRANSPORT_WATER: tile_type = ::MP_WATER; break; case ScriptTile::TRANSPORT_AIR: { /* Hangars are not seen as real depots by the depot code. */ const Station *st; FOR_ALL_STATIONS(st) { if (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) { for (uint i = 0; i < st->airport.GetNumHangars(); i++) { this->AddItem(st->airport.GetHangarTile(i)); } } } return; } } /* Handle 'standard' depots. */ const Depot *depot; FOR_ALL_DEPOTS(depot) { if ((::GetTileOwner(depot->xy) == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && ::IsTileType(depot->xy, tile_type)) this->AddItem(depot->xy); } } openttd-1.5.3/src/script/api/script_waypoint.cpp0000644000000000000000000000320112627373434020510 0ustar rootroot/* $Id: script_waypoint.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_waypoint.cpp Implementation of ScriptWaypoint. */ #include "../../stdafx.h" #include "script_waypoint.hpp" #include "script_rail.hpp" #include "script_marine.hpp" #include "../../waypoint_base.h" #include "../../safeguards.h" /* static */ bool ScriptWaypoint::IsValidWaypoint(StationID waypoint_id) { const Waypoint *wp = ::Waypoint::GetIfValid(waypoint_id); return wp != NULL && (wp->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || wp->owner == OWNER_NONE); } /* static */ StationID ScriptWaypoint::GetWaypointID(TileIndex tile) { if (!ScriptRail::IsRailWaypointTile(tile) && !ScriptMarine::IsBuoyTile(tile)) return STATION_INVALID; return ::GetStationIndex(tile); } /* static */ bool ScriptWaypoint::HasWaypointType(StationID waypoint_id, WaypointType waypoint_type) { if (!IsValidWaypoint(waypoint_id)) return false; if (!HasExactlyOneBit(waypoint_type)) return false; return (::Waypoint::Get(waypoint_id)->facilities & waypoint_type) != 0; } openttd-1.5.3/src/script/api/script_townlist.cpp0000644000000000000000000000204212627373434020523 0ustar rootroot/* $Id: script_townlist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_townlist.cpp Implementation of ScriptTownList and friends. */ #include "../../stdafx.h" #include "script_townlist.hpp" #include "../../town.h" #include "../../safeguards.h" ScriptTownList::ScriptTownList() { Town *t; FOR_ALL_TOWNS(t) { this->AddItem(t->index); } } ScriptTownEffectList::ScriptTownEffectList() { for (int i = TE_BEGIN; i < TE_END; i++) { this->AddItem(i); } } openttd-1.5.3/src/script/api/script_game.hpp0000644000000000000000000000413612627373434017564 0ustar rootroot/* $Id: script_game.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 script_game.hpp Everything to manipulate the current running game. */ #ifndef SCRIPT_GAME_HPP #define SCRIPT_GAME_HPP #include "script_object.hpp" #include "../../landscape_type.h" /** * Class that handles some game related functions. * @api game */ class ScriptGame : public ScriptObject { public: /** * Type of landscapes known in the game. */ enum LandscapeType { /* Note: these values represent part of the in-game LandscapeType enum */ LT_TEMPERATE = ::LT_TEMPERATE, ///< Temperate climate. LT_ARCTIC = ::LT_ARCTIC, ///< Arctic climate. LT_TROPIC = ::LT_TROPIC, ///< Tropic climate. LT_TOYLAND = ::LT_TOYLAND, ///< Toyland climate. }; /** * Pause the server. * @return True if the action succeeded. */ static bool Pause(); /** * Unpause the server. * @return True if the action succeeded. */ static bool Unpause(); /** * Check if the game is paused. * @return True if and only if the game is paused (by which-ever means). * @note That a game is paused, doesn't always means you can unpause it. If * the game has been manually paused, or because of the pause_on_join in * Multiplayer for example, you cannot unpause the game. */ static bool IsPaused(); /** * Get the current landscape. */ static LandscapeType GetLandscape(); /** * Is this a multiplayer game? * @return True if this is a server in a multiplayer game. */ static bool IsMultiplayer(); }; #endif /* SCRIPT_GAME_HPP */ openttd-1.5.3/src/script/api/script_accounting.cpp0000644000000000000000000000221612627373434020775 0ustar rootroot/* $Id: script_accounting.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_accounting.cpp Implementation of ScriptAccounting. */ #include "../../stdafx.h" #include "script_accounting.hpp" #include "../../safeguards.h" Money ScriptAccounting::GetCosts() { return this->GetDoCommandCosts(); } void ScriptAccounting::ResetCosts() { this->SetDoCommandCosts(0); } ScriptAccounting::ScriptAccounting() { this->last_costs = this->GetDoCommandCosts(); this->SetDoCommandCosts(0); } ScriptAccounting::~ScriptAccounting() { this->SetDoCommandCosts(this->last_costs); } openttd-1.5.3/src/script/api/Doxyfile_Game0000644000000000000000000002306612627373434017220 0ustar rootroot# $Id: Doxyfile_Game 25595 2013-07-13 06:44:22Z rubidium $ # 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 . # Doxyfile 1.5.4 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "OpenTTD Game API" PROJECT_NUMBER = OUTPUT_DIRECTORY = ../../../docs/gamedocs/ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class " \ "The $name widget " \ "The $name file " \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = ./ STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 2 ALIASES = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = YES EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = YES INTERNAL_DOCS = YES CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = NO GENERATE_TESTLIST = NO GENERATE_BUGLIST = NO GENERATE_DEPRECATEDLIST= NO ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = NO SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES WARN_FORMAT = "$file:$line: $text " WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = . INPUT_ENCODING = UTF-8 FILE_PATTERNS = script_*.hpp \ game_*.hpp RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = GetClassName DECLARE_ENUM_AS_BIT_SET DECLARE_POSTFIX_INCREMENT EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = "./doxygen_filter.sh GS" FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO HTML_DYNAMIC_SECTIONS = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 1 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = DOXYGEN_API EXPAND_AS_DEFINED = DEF_COMMAND SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ../../../objs/openttd_nogo.tag ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = NO DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO openttd-1.5.3/src/script/api/script_window.cpp0000644000000000000000000000400212627373433020144 0ustar rootroot/* $Id: script_window.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_window.cpp Implementation of ScriptWindow. */ #include "../../stdafx.h" #include "script_window.hpp" #include "script_game.hpp" #include "../../window_func.h" #include "../../window_gui.h" #include "../../safeguards.h" /* static */ void ScriptWindow::Close(WindowClass window, uint32 number) { if (ScriptGame::IsMultiplayer()) return; if (number == NUMBER_ALL) { DeleteWindowByClass((::WindowClass)window); return; } DeleteWindowById((::WindowClass)window, number); } /* static */ bool ScriptWindow::IsOpen(WindowClass window, uint32 number) { if (ScriptGame::IsMultiplayer()) return false; if (number == NUMBER_ALL) { return (FindWindowByClass((::WindowClass)window) != NULL); } return FindWindowById((::WindowClass)window, number) != NULL; } /* static */ void ScriptWindow::Highlight(WindowClass window, uint32 number, uint8 widget, TextColour colour) { if (ScriptGame::IsMultiplayer()) return; if (number == NUMBER_ALL) return; if (!IsOpen(window, number)) return; if (colour != TC_INVALID && (::TextColour)colour >= ::TC_END) return; Window *w = FindWindowById((::WindowClass)window, number); if (widget == WIDGET_ALL) { if (colour != TC_INVALID) return; w->DisableAllWidgetHighlight(); return; } const NWidgetBase *wid = w->GetWidget(widget); if (wid == NULL) return; w->SetWidgetHighlight(widget, (::TextColour)colour); } openttd-1.5.3/src/script/api/script_bridge.cpp0000644000000000000000000001465012627373434020104 0ustar rootroot/* $Id: script_bridge.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_bridge.cpp Implementation of ScriptBridge. */ #include "../../stdafx.h" #include "script_bridge.hpp" #include "script_rail.hpp" #include "../script_instance.hpp" #include "../../bridge_map.h" #include "../../strings_func.h" #include "../../date_func.h" #include "../../safeguards.h" /* static */ bool ScriptBridge::IsValidBridge(BridgeID bridge_id) { return bridge_id < MAX_BRIDGES && ::GetBridgeSpec(bridge_id)->avail_year <= _cur_year; } /* static */ bool ScriptBridge::IsBridgeTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsBridgeTile(tile); } /* static */ BridgeID ScriptBridge::GetBridgeID(TileIndex tile) { if (!IsBridgeTile(tile)) return (BridgeID)-1; return (BridgeID)::GetBridgeType(tile); } /** * Helper function to connect a just built bridge to nearby roads. * @param instance The script instance we have to built the road for. */ static void _DoCommandReturnBuildBridge2(class ScriptInstance *instance) { if (!ScriptBridge::_BuildBridgeRoad2()) { ScriptInstance::DoCommandReturn(instance); return; } /* This can never happen, as in test-mode this callback is never executed, * and in execute-mode, the other callback is called. */ NOT_REACHED(); } /** * Helper function to connect a just built bridge to nearby roads. * @param instance The script instance we have to built the road for. */ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance) { if (!ScriptBridge::_BuildBridgeRoad1()) { ScriptInstance::DoCommandReturn(instance); return; } /* This can never happen, as in test-mode this callback is never executed, * and in execute-mode, the other callback is called. */ NOT_REACHED(); } /* static */ bool ScriptBridge::BuildBridge(ScriptVehicle::VehicleType vehicle_type, BridgeID bridge_id, TileIndex start, TileIndex end) { EnforcePrecondition(false, start != end); EnforcePrecondition(false, ::IsValidTile(start) && ::IsValidTile(end)); EnforcePrecondition(false, TileX(start) == TileX(end) || TileY(start) == TileY(end)); EnforcePrecondition(false, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER); EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_RAIL || ScriptRail::IsRailTypeAvailable(ScriptRail::GetCurrentRailType())); EnforcePrecondition(false, vehicle_type != ScriptVehicle::VT_ROAD || ScriptRoad::IsRoadTypeAvailable(ScriptRoad::GetCurrentRoadType())); EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY || vehicle_type == ScriptVehicle::VT_ROAD); uint type = 0; switch (vehicle_type) { case ScriptVehicle::VT_ROAD: type |= (TRANSPORT_ROAD << 15); type |= (::RoadTypeToRoadTypes((::RoadType)ScriptObject::GetRoadType()) << 8); break; case ScriptVehicle::VT_RAIL: type |= (TRANSPORT_RAIL << 15); type |= (ScriptRail::GetCurrentRailType() << 8); break; case ScriptVehicle::VT_WATER: type |= (TRANSPORT_WATER << 15); break; default: NOT_REACHED(); } /* For rail and water we do nothing special */ if (vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER) { return ScriptObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE); } ScriptObject::SetCallbackVariable(0, start); ScriptObject::SetCallbackVariable(1, end); return ScriptObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE, NULL, &::_DoCommandReturnBuildBridge1); } /* static */ bool ScriptBridge::_BuildBridgeRoad1() { /* Build the piece of road on the 'start' side of the bridge */ TileIndex end = ScriptObject::GetCallbackVariable(0); TileIndex start = ScriptObject::GetCallbackVariable(1); DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); return ScriptObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &::_DoCommandReturnBuildBridge2); } /* static */ bool ScriptBridge::_BuildBridgeRoad2() { /* Build the piece of road on the 'end' side of the bridge */ TileIndex end = ScriptObject::GetCallbackVariable(0); TileIndex start = ScriptObject::GetCallbackVariable(1); DiagDirection dir_1 = ::DiagdirBetweenTiles(end, start); DiagDirection dir_2 = ::ReverseDiagDir(dir_1); return ScriptObject::DoCommand(end + ::TileOffsByDiagDir(dir_2), ::DiagDirToRoadBits(dir_1) | (ScriptObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD); } /* static */ bool ScriptBridge::RemoveBridge(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsBridgeTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ char *ScriptBridge::GetName(BridgeID bridge_id) { if (!IsValidBridge(bridge_id)) return NULL; return GetString(::GetBridgeSpec(bridge_id)->transport_name[0]); } /* static */ int32 ScriptBridge::GetMaxSpeed(BridgeID bridge_id) { if (!IsValidBridge(bridge_id)) return -1; return ::GetBridgeSpec(bridge_id)->speed; // km-ish/h } /* static */ Money ScriptBridge::GetPrice(BridgeID bridge_id, uint length) { if (!IsValidBridge(bridge_id)) return -1; return ::CalcBridgeLenCostFactor(length) * _price[PR_BUILD_BRIDGE] * ::GetBridgeSpec(bridge_id)->price >> 8; } /* static */ int32 ScriptBridge::GetMaxLength(BridgeID bridge_id) { if (!IsValidBridge(bridge_id)) return -1; return min(::GetBridgeSpec(bridge_id)->max_length, _settings_game.construction.max_bridge_length) + 2; } /* static */ int32 ScriptBridge::GetMinLength(BridgeID bridge_id) { if (!IsValidBridge(bridge_id)) return -1; return ::GetBridgeSpec(bridge_id)->min_length + 2; } /* static */ TileIndex ScriptBridge::GetOtherBridgeEnd(TileIndex tile) { if (!::IsValidTile(tile)) return INVALID_TILE; if (!IsBridgeTile(tile)) return INVALID_TILE; return ::GetOtherBridgeEnd(tile); } openttd-1.5.3/src/script/api/script_company.hpp0000644000000000000000000003246312627373434020325 0ustar rootroot/* $Id: script_company.hpp 26915 2014-09-24 16:45:20Z frosch $ */ /* * 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 script_company.hpp Everything to query a company's financials and statistics or build company related buildings. */ #ifndef SCRIPT_COMPANY_HPP #define SCRIPT_COMPANY_HPP #include "script_text.hpp" #include "../../economy_type.h" /** * Class that handles all company related functions. * @api ai game */ class ScriptCompany : public ScriptObject { public: /** The range of possible quarters to get company information of. */ enum Quarter { CURRENT_QUARTER = 0, ///< The current quarter. EARLIEST_QUARTER = ::MAX_HISTORY_QUARTERS, ///< The earliest quarter company information is available for. }; /** Different constants related to CompanyID. */ enum CompanyID { /* Note: these values represent part of the in-game Owner enum */ COMPANY_FIRST = ::COMPANY_FIRST, ///< The first available company. COMPANY_LAST = ::MAX_COMPANIES, ///< The last available company. /* Custom added value, only valid for this API */ COMPANY_INVALID = -1, ///< An invalid company. COMPANY_SELF = 254, ///< Constant that gets resolved to the correct company index for your company. }; /** Possible genders for company presidents. */ enum Gender { GENDER_MALE, ///< A male person. GENDER_FEMALE, ///< A female person. GENDER_INVALID = -1, ///< An invalid gender. }; /** * Types of expenses. * @api -ai */ enum ExpensesType { EXPENSES_CONSTRUCTION = ::EXPENSES_CONSTRUCTION, ///< Construction costs. EXPENSES_NEW_VEHICLES = ::EXPENSES_NEW_VEHICLES, ///< New vehicles. EXPENSES_TRAIN_RUN = ::EXPENSES_TRAIN_RUN, ///< Running costs trains. EXPENSES_ROADVEH_RUN = ::EXPENSES_ROADVEH_RUN, ///< Running costs road vehicles. EXPENSES_AIRCRAFT_RUN = ::EXPENSES_AIRCRAFT_RUN, ///< Running costs aircrafts. EXPENSES_SHIP_RUN = ::EXPENSES_SHIP_RUN, ///< Running costs ships. EXPENSES_PROPERTY = ::EXPENSES_PROPERTY, ///< Property costs. EXPENSES_TRAIN_INC = ::EXPENSES_TRAIN_INC, ///< Income from trains. EXPENSES_ROADVEH_INC = ::EXPENSES_ROADVEH_INC, ///< Income from road vehicles. EXPENSES_AIRCRAFT_INC = ::EXPENSES_AIRCRAFT_INC, ///< Income from aircrafts. EXPENSES_SHIP_INC = ::EXPENSES_SHIP_INC, ///< Income from ships. EXPENSES_LOAN_INT = ::EXPENSES_LOAN_INT, ///< Interest payments over the loan. EXPENSES_OTHER = ::EXPENSES_OTHER, ///< Other expenses. EXPENSES_INVALID = ::INVALID_EXPENSES, ///< Invalid expense type. }; /** * Resolved the given company index to the correct index for the company. If * the company index was COMPANY_SELF it will be resolved to the index of * your company. If the company with the given index does not exist it will * return COMPANY_INVALID. * @param company The company index to resolve. * @return The resolved company index. */ static CompanyID ResolveCompanyID(CompanyID company); /** * Check if a CompanyID is your CompanyID, to ease up checks. * @param company The company index to check. * @return True if and only if this company is your CompanyID. * @api -game */ static bool IsMine(CompanyID company); /** * Set the name of your company. * @param name The new name of the company (can be either a raw string, or a ScriptText object). * @pre name != NULL && len(name) != 0. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if the name was changed. */ static bool SetName(Text *name); /** * Get the name of the given company. * @param company The company to get the name for. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The name of the given company. */ static char *GetName(CompanyID company); /** * Set the name of your president. * @param name The new name of the president (can be either a raw string, or a ScriptText object). * @pre name != NULL && len(name) != 0. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if the name was changed. */ static bool SetPresidentName(Text *name); /** * Get the name of the president of the given company. * @param company The company to get the president's name for. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The name of the president of the given company. */ static char *GetPresidentName(CompanyID company); /** * Set the gender of the president of your company. * @param gender The new gender for your president. * @pre GetPresidentGender(ScriptCompany.COMPANY_SELF) != gender. * @return True if the gender was changed. * @note When successful a random face will be created. * @api -game */ static bool SetPresidentGender(Gender gender); /** * Get the gender of the president of the given company. * @param company The company to get the presidents gender off. * @return The gender of the president. */ static Gender GetPresidentGender(CompanyID company); /** * Sets the amount to loan. * @param loan The amount to loan (multiplier of GetLoanInterval()). * @pre 'loan' must be non-negative. * @pre GetLoanInterval() must be a multiplier of 'loan'. * @pre 'loan' must be below GetMaxLoanAmount(). * @pre 'loan' - GetLoanAmount() + GetBankBalance() must be non-negative. * @game @pre Valid ScriptCompanyMode active in scope. * @return True if the loan could be set to your requested amount. */ static bool SetLoanAmount(Money loan); /** * Sets the minimum amount to loan, i.e. the given amount of loan rounded up. * @param loan The amount to loan (any positive number). * @pre 'loan' must be non-negative. * @pre 'loan' must be below GetMaxLoanAmount(). * @game @pre Valid ScriptCompanyMode active in scope. * @return True if we could allocate a minimum of 'loan' loan. */ static bool SetMinimumLoanAmount(Money loan); /** * Gets the amount your company have loaned. * @return The amount loaned money. * @post GetLoanInterval() is always a multiplier of the return value. */ static Money GetLoanAmount(); /** * Gets the maximum amount your company can loan. * @return The maximum amount your company can loan. * @post GetLoanInterval() is always a multiplier of the return value. */ static Money GetMaxLoanAmount(); /** * Gets the interval/loan step. * @return The loan step. * @post Return value is always positive. */ static Money GetLoanInterval(); /** * Gets the bank balance. In other words, the amount of money the given company can spent. * @param company The company to get the bank balance of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The actual bank balance. */ static Money GetBankBalance(CompanyID company); /** * Changes the bank balance by a delta value. This method does not affect the loan but instead * allows a GS to give or take money from a company. * @param company The company to change the bank balance of. * @param delta Amount of money to give or take from the bank balance. A positive value adds money to the bank balance. * @param expenses_type The account in the finances window that will register the cost. * @return True, if the bank balance was changed. * @game @pre No ScriptCompanyMode active in scope. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @pre delta >= -2**31 * @pre delta < 2**31 * @note You need to create your own news message to inform about costs/gifts that you create using this command. * @api -ai */ static bool ChangeBankBalance(CompanyID company, Money delta, ExpensesType expenses_type); /** * Get the income of the company in the given quarter. * Note that this function only considers recurring income from vehicles; * it does not include one-time income from selling stuff. * @param company The company to get the quarterly income of. * @param quarter The quarter to get the income of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @pre quarter <= EARLIEST_QUARTER. * @return The gross income of the company in the given quarter. */ static Money GetQuarterlyIncome(CompanyID company, uint32 quarter); /** * Get the expenses of the company in the given quarter. * Note that this function only considers recurring expenses from vehicle * running cost, maintenance and interests; it does not include one-time * expenses from construction and buying stuff. * @param company The company to get the quarterly expenses of. * @param quarter The quarter to get the expenses of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @pre quarter <= EARLIEST_QUARTER. * @return The expenses of the company in the given quarter. */ static Money GetQuarterlyExpenses(CompanyID company, uint32 quarter); /** * Get the amount of cargo delivered by the given company in the given quarter. * @param company The company to get the amount of delivered cargo of. * @param quarter The quarter to get the amount of delivered cargo of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @pre quarter <= EARLIEST_QUARTER. * @return The amount of cargo delivered by the given company in the given quarter. */ static int32 GetQuarterlyCargoDelivered(CompanyID company, uint32 quarter); /** * Get the performance rating of the given company in the given quarter. * @param company The company to get the performance rating of. * @param quarter The quarter to get the performance rating of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @pre quarter <= EARLIEST_QUARTER. * @pre quarter != CURRENT_QUARTER. * @note The performance rating is calculated after every quarter, so the value for CURRENT_QUARTER is undefined. * @return The performance rating of the given company in the given quarter. */ static int32 GetQuarterlyPerformanceRating(CompanyID company, uint32 quarter); /** * Get the value of the company in the given quarter. * @param company The company to get the value of. * @param quarter The quarter to get the value of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @pre quarter <= EARLIEST_QUARTER. * @return The value of the company in the given quarter. */ static Money GetQuarterlyCompanyValue(CompanyID company, uint32 quarter); /** * Build your company's HQ on the given tile. * @param tile The tile to build your HQ on, this tile is the most northern tile of your HQ. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @return True if the HQ could be build. * @note An HQ can not be removed, only by water or rebuilding; If an HQ is * build again, the old one is removed. */ static bool BuildCompanyHQ(TileIndex tile); /** * Return the location of a company's HQ. * @param company The company the get the HQ of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The tile of the company's HQ, this tile is the most northern tile * of that HQ, or ScriptMap::TILE_INVALID if there is no HQ yet. */ static TileIndex GetCompanyHQ(CompanyID company); /** * Set whether autorenew is enabled for your company. * @param autorenew The new autorenew status. * @return True if autorenew status has been modified. * @api -game */ static bool SetAutoRenewStatus(bool autorenew); /** * Return whether autorenew is enabled for a company. * @param company The company to get the autorenew status of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return True if autorenew is enabled. */ static bool GetAutoRenewStatus(CompanyID company); /** * Set the number of months before/after max age to autorenew an engine for your company. * @param months The new months between autorenew. * @return True if autorenew months has been modified. * @api -game */ static bool SetAutoRenewMonths(int16 months); /** * Return the number of months before/after max age to autorenew an engine for a company. * @param company The company to get the autorenew months of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The months before/after max age of engine. */ static int16 GetAutoRenewMonths(CompanyID company); /** * Set the minimum money needed to autorenew an engine for your company. * @param money The new minimum required money for autorenew to work. * @return True if autorenew money has been modified. * @pre money >= 0 * @pre money < 2**32 * @api -game */ static bool SetAutoRenewMoney(Money money); /** * Return the minimum money needed to autorenew an engine for a company. * @param company The company to get the autorenew money of. * @pre ResolveCompanyID(company) != COMPANY_INVALID. * @return The minimum required money for autorenew to work. */ static Money GetAutoRenewMoney(CompanyID company); }; DECLARE_POSTFIX_INCREMENT(ScriptCompany::CompanyID) #endif /* SCRIPT_COMPANY_HPP */ openttd-1.5.3/src/script/api/script_industrylist.hpp0000644000000000000000000000331212627373434021423 0ustar rootroot/* $Id: script_industrylist.hpp 23614 2011-12-19 20:57:23Z truebrain $ */ /* * 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 script_industrylist.hpp List all the industries. */ #ifndef SCRIPT_INDUSTRYLIST_HPP #define SCRIPT_INDUSTRYLIST_HPP #include "script_list.hpp" /** * Creates a list of industries that are currently on the map. * @api ai game * @ingroup ScriptList */ class ScriptIndustryList : public ScriptList { public: ScriptIndustryList(); }; /** * Creates a list of industries that accepts a given cargo. * @api ai game * @ingroup ScriptList */ class ScriptIndustryList_CargoAccepting : public ScriptList { public: /** * @param cargo_id The cargo this industry should accept. */ ScriptIndustryList_CargoAccepting(CargoID cargo_id); }; /** * Creates a list of industries that can produce a given cargo. * @note It also contains industries that currently produces 0 units of the cargo. * @api ai game * @ingroup ScriptList */ class ScriptIndustryList_CargoProducing : public ScriptList { public: /** * @param cargo_id The cargo this industry should produce. */ ScriptIndustryList_CargoProducing(CargoID cargo_id); }; #endif /* SCRIPT_INDUSTRYLIST_HPP */ openttd-1.5.3/src/script/api/template/0000755000000000000000000000000012627373433016364 5ustar rootrootopenttd-1.5.3/src/script/api/template/template_subsidylist.hpp.sq0000644000000000000000000000414512627373433023774 0ustar rootroot/* $Id: template_subsidylist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_subsidylist.hpp" namespace SQConvert { /* Allow ScriptSubsidyList to be used as Squirrel parameter */ template <> inline ScriptSubsidyList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSubsidyList *)instance; } template <> inline ScriptSubsidyList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidyList *)instance; } template <> inline const ScriptSubsidyList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSubsidyList *)instance; } template <> inline const ScriptSubsidyList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidyList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptSubsidyList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "SubsidyList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_town.hpp.sq0000644000000000000000000000751012627373433022404 0ustar rootroot/* $Id: template_town.hpp.sq 25967 2013-11-12 17:56:35Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_town.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptTown::TownAction GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTown::TownAction)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTown::TownAction res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTown::TownRating GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTown::TownRating)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTown::TownRating res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTown::RoadLayout GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTown::RoadLayout)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTown::RoadLayout res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTown::TownSize GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTown::TownSize)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTown::TownSize res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTown::TownGrowth GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTown::TownGrowth)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTown::TownGrowth res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptTown to be used as Squirrel parameter */ template <> inline ScriptTown *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTown *)instance; } template <> inline ScriptTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTown *)instance; } template <> inline const ScriptTown *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTown *)instance; } template <> inline const ScriptTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTown *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTown *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Town", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_tilelist.hpp.sq0000644000000000000000000001540112627373433023244 0ustar rootroot/* $Id: template_tilelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tilelist.hpp" namespace SQConvert { /* Allow ScriptTileList to be used as Squirrel parameter */ template <> inline ScriptTileList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList *)instance; } template <> inline ScriptTileList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList *)instance; } template <> inline const ScriptTileList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList *)instance; } template <> inline const ScriptTileList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTileList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptTileList_IndustryAccepting to be used as Squirrel parameter */ template <> inline ScriptTileList_IndustryAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_IndustryAccepting *)instance; } template <> inline ScriptTileList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryAccepting *)instance; } template <> inline const ScriptTileList_IndustryAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_IndustryAccepting *)instance; } template <> inline const ScriptTileList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryAccepting *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_IndustryAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_IndustryAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptTileList_IndustryProducing to be used as Squirrel parameter */ template <> inline ScriptTileList_IndustryProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_IndustryProducing *)instance; } template <> inline ScriptTileList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryProducing *)instance; } template <> inline const ScriptTileList_IndustryProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_IndustryProducing *)instance; } template <> inline const ScriptTileList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_IndustryProducing *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_IndustryProducing *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_IndustryProducing", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptTileList_StationType to be used as Squirrel parameter */ template <> inline ScriptTileList_StationType *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_StationType *)instance; } template <> inline ScriptTileList_StationType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_StationType *)instance; } template <> inline const ScriptTileList_StationType *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTileList_StationType *)instance; } template <> inline const ScriptTileList_StationType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTileList_StationType *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTileList_StationType *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TileList_StationType", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_industry.hpp.sq0000644000000000000000000000500712627373433023275 0ustar rootroot/* $Id: template_industry.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industry.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptIndustry::CargoAcceptState GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptIndustry::CargoAcceptState)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustry::CargoAcceptState res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptIndustry to be used as Squirrel parameter */ template <> inline ScriptIndustry *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustry *)instance; } template <> inline ScriptIndustry &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustry *)instance; } template <> inline const ScriptIndustry *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustry *)instance; } template <> inline const ScriptIndustry &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustry *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustry *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Industry", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_basestation.hpp.sq0000644000000000000000000000512412627373433023730 0ustar rootroot/* $Id: template_basestation.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_basestation.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptBaseStation::SpecialStationIDs GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptBaseStation::SpecialStationIDs)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptBaseStation::SpecialStationIDs res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptBaseStation to be used as Squirrel parameter */ template <> inline ScriptBaseStation *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBaseStation *)instance; } template <> inline ScriptBaseStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBaseStation *)instance; } template <> inline const ScriptBaseStation *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBaseStation *)instance; } template <> inline const ScriptBaseStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBaseStation *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptBaseStation *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BaseStation", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_rail.hpp.sq0000644000000000000000000000752012627373433022345 0ustar rootroot/* $Id: template_rail.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_rail.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptRail::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRail::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRail::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRail::RailType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRail::RailType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRail::RailType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRail::RailTrack GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRail::RailTrack)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRail::RailTrack res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRail::SignalType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRail::SignalType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRail::SignalType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRail::BuildType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRail::BuildType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRail::BuildType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptRail to be used as Squirrel parameter */ template <> inline ScriptRail *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRail *)instance; } template <> inline ScriptRail &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRail *)instance; } template <> inline const ScriptRail *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRail *)instance; } template <> inline const ScriptRail &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRail *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptRail *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Rail", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_log.hpp.sq0000644000000000000000000000371512627373433022201 0ustar rootroot/* $Id: template_log.hpp.sq 23597 2011-12-19 20:44:31Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_log.hpp" namespace SQConvert { /* Allow ScriptLog to be used as Squirrel parameter */ template <> inline ScriptLog *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptLog *)instance; } template <> inline ScriptLog &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptLog *)instance; } template <> inline const ScriptLog *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptLog *)instance; } template <> inline const ScriptLog &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptLog *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptLog *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Log", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_storypagelist.hpp.sq0000644000000000000000000000410612627373433024324 0ustar rootroot/* $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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_storypagelist.hpp" namespace SQConvert { /* Allow ScriptStoryPageList to be used as Squirrel parameter */ template <> inline ScriptStoryPageList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPageList *)instance; } template <> inline ScriptStoryPageList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageList *)instance; } template <> inline const ScriptStoryPageList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPageList *)instance; } template <> inline const ScriptStoryPageList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPageList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPageList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_viewport.hpp.sq0000644000000000000000000000405412627373433023274 0ustar rootroot/* $Id: template_viewport.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_viewport.hpp" namespace SQConvert { /* Allow ScriptViewport to be used as Squirrel parameter */ template <> inline ScriptViewport *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptViewport *)instance; } template <> inline ScriptViewport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptViewport *)instance; } template <> inline const ScriptViewport *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptViewport *)instance; } template <> inline const ScriptViewport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptViewport *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptViewport *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Viewport", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_admin.hpp.sq0000644000000000000000000000376312627373433022513 0ustar rootroot/* $Id: template_admin.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_admin.hpp" namespace SQConvert { /* Allow ScriptAdmin to be used as Squirrel parameter */ template <> inline ScriptAdmin *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAdmin *)instance; } template <> inline ScriptAdmin &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAdmin *)instance; } template <> inline const ScriptAdmin *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAdmin *)instance; } template <> inline const ScriptAdmin &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAdmin *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptAdmin *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Admin", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_goal.hpp.sq0000644000000000000000000000674112627373433022344 0ustar rootroot/* $Id: template_goal.hpp.sq 23827 2012-01-21 12:03:55Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_goal.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptGoal::GoalID GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptGoal::GoalID)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptGoal::GoalID res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptGoal::GoalType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptGoal::GoalType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptGoal::GoalType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptGoal::QuestionType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptGoal::QuestionType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptGoal::QuestionType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptGoal::QuestionButton GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptGoal::QuestionButton)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptGoal::QuestionButton res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptGoal to be used as Squirrel parameter */ template <> inline ScriptGoal *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGoal *)instance; } template <> inline ScriptGoal &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGoal *)instance; } template <> inline const ScriptGoal *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGoal *)instance; } template <> inline const ScriptGoal &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGoal *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptGoal *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Goal", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_base.hpp.sq0000644000000000000000000000374012627373433022330 0ustar rootroot/* $Id: template_base.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_base.hpp" namespace SQConvert { /* Allow ScriptBase to be used as Squirrel parameter */ template <> inline ScriptBase *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBase *)instance; } template <> inline ScriptBase &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBase *)instance; } template <> inline const ScriptBase *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBase *)instance; } template <> inline const ScriptBase &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBase *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptBase *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Base", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_vehicle.hpp.sq0000644000000000000000000000636312627373433023041 0ustar rootroot/* $Id: template_vehicle.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_vehicle.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptVehicle::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptVehicle::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicle::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptVehicle::VehicleType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptVehicle::VehicleType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicle::VehicleType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptVehicle::VehicleState GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptVehicle::VehicleState)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicle::VehicleState res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptVehicle to be used as Squirrel parameter */ template <> inline ScriptVehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicle *)instance; } template <> inline ScriptVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicle *)instance; } template <> inline const ScriptVehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicle *)instance; } template <> inline const ScriptVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicle *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Vehicle", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_date.hpp.sq0000644000000000000000000000454512627373433022337 0ustar rootroot/* $Id: template_date.hpp.sq 26307 2014-02-06 19:50:34Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_date.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptDate::Date GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptDate::Date)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptDate::Date res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptDate to be used as Squirrel parameter */ template <> inline ScriptDate *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptDate *)instance; } template <> inline ScriptDate &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDate *)instance; } template <> inline const ScriptDate *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptDate *)instance; } template <> inline const ScriptDate &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDate *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptDate *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Date", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_bridge.hpp.sq0000644000000000000000000000471012627373433022650 0ustar rootroot/* $Id: template_bridge.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_bridge.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptBridge::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptBridge::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptBridge::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptBridge to be used as Squirrel parameter */ template <> inline ScriptBridge *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridge *)instance; } template <> inline ScriptBridge &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridge *)instance; } template <> inline const ScriptBridge *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridge *)instance; } template <> inline const ScriptBridge &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridge *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptBridge *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Bridge", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_waypoint.hpp.sq0000644000000000000000000000561012627373433023266 0ustar rootroot/* $Id: template_waypoint.hpp.sq 23521 2011-12-15 18:40:15Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_waypoint.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptWaypoint::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWaypoint::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWaypoint::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWaypoint::WaypointType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWaypoint::WaypointType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWaypoint::WaypointType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptWaypoint to be used as Squirrel parameter */ template <> inline ScriptWaypoint *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypoint *)instance; } template <> inline ScriptWaypoint &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypoint *)instance; } template <> inline const ScriptWaypoint *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypoint *)instance; } template <> inline const ScriptWaypoint &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypoint *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptWaypoint *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Waypoint", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_industrytype.hpp.sq0000644000000000000000000000516612627373433024205 0ustar rootroot/* $Id: template_industrytype.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrytype.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptIndustryType::SpecialIndustryType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptIndustryType::SpecialIndustryType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryType::SpecialIndustryType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptIndustryType to be used as Squirrel parameter */ template <> inline ScriptIndustryType *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryType *)instance; } template <> inline ScriptIndustryType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryType *)instance; } template <> inline const ScriptIndustryType *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryType *)instance; } template <> inline const ScriptIndustryType &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryType *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryType *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryType", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_vehiclelist.hpp.sq0000644000000000000000000002320512627373433023727 0ustar rootroot/* $Id: template_vehiclelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_vehiclelist.hpp" namespace SQConvert { /* Allow ScriptVehicleList to be used as Squirrel parameter */ template <> inline ScriptVehicleList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList *)instance; } template <> inline ScriptVehicleList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList *)instance; } template <> inline const ScriptVehicleList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList *)instance; } template <> inline const ScriptVehicleList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptVehicleList_Station to be used as Squirrel parameter */ template <> inline ScriptVehicleList_Station *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Station *)instance; } template <> inline ScriptVehicleList_Station &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Station *)instance; } template <> inline const ScriptVehicleList_Station *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Station *)instance; } template <> inline const ScriptVehicleList_Station &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Station *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Station *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Station", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptVehicleList_Depot to be used as Squirrel parameter */ template <> inline ScriptVehicleList_Depot *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Depot *)instance; } template <> inline ScriptVehicleList_Depot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Depot *)instance; } template <> inline const ScriptVehicleList_Depot *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Depot *)instance; } template <> inline const ScriptVehicleList_Depot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Depot *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Depot *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Depot", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptVehicleList_SharedOrders to be used as Squirrel parameter */ template <> inline ScriptVehicleList_SharedOrders *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_SharedOrders *)instance; } template <> inline ScriptVehicleList_SharedOrders &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_SharedOrders *)instance; } template <> inline const ScriptVehicleList_SharedOrders *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_SharedOrders *)instance; } template <> inline const ScriptVehicleList_SharedOrders &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_SharedOrders *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_SharedOrders *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_SharedOrders", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptVehicleList_Group to be used as Squirrel parameter */ template <> inline ScriptVehicleList_Group *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Group *)instance; } template <> inline ScriptVehicleList_Group &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Group *)instance; } template <> inline const ScriptVehicleList_Group *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_Group *)instance; } template <> inline const ScriptVehicleList_Group &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_Group *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_Group *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_Group", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptVehicleList_DefaultGroup to be used as Squirrel parameter */ template <> inline ScriptVehicleList_DefaultGroup *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_DefaultGroup *)instance; } template <> inline ScriptVehicleList_DefaultGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_DefaultGroup *)instance; } template <> inline const ScriptVehicleList_DefaultGroup *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptVehicleList_DefaultGroup *)instance; } template <> inline const ScriptVehicleList_DefaultGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptVehicleList_DefaultGroup *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptVehicleList_DefaultGroup *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "VehicleList_DefaultGroup", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_station.hpp.sq0000644000000000000000000000554712627373433023106 0ustar rootroot/* $Id: template_station.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_station.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptStation::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStation::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptStation::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptStation::StationType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStation::StationType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptStation::StationType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptStation to be used as Squirrel parameter */ template <> inline ScriptStation *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStation *)instance; } template <> inline ScriptStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStation *)instance; } template <> inline const ScriptStation *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStation *)instance; } template <> inline const ScriptStation &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStation *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStation *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Station", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_gamesettings.hpp.sq0000644000000000000000000000417012627373433024106 0ustar rootroot/* $Id: template_gamesettings.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_gamesettings.hpp" namespace SQConvert { /* Allow ScriptGameSettings to be used as Squirrel parameter */ template <> inline ScriptGameSettings *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGameSettings *)instance; } template <> inline ScriptGameSettings &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGameSettings *)instance; } template <> inline const ScriptGameSettings *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGameSettings *)instance; } template <> inline const ScriptGameSettings &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGameSettings *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptGameSettings *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "GameSettings", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_text.hpp.sq0000644000000000000000000000411612627373433022400 0ustar rootroot/* $Id: template_text.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_text.hpp" namespace SQConvert { /* Allow ScriptText to be used as Squirrel parameter */ template <> inline ScriptText *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptText *)instance; } template <> inline ScriptText &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptText *)instance; } template <> inline const ScriptText *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptText *)instance; } template <> inline const ScriptText &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptText *)instance; } template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { if (sq_gettype(vm, index) == OT_INSTANCE) { return GetParam(ForceType(), vm, index, ptr); } if (sq_gettype(vm, index) == OT_STRING) { return new RawText(GetParam(ForceType(), vm, index, ptr)); } return NULL; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_error.hpp.sq0000644000000000000000000000550112627373433022544 0ustar rootroot/* $Id: template_error.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_error.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptError::ErrorCategories GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptError::ErrorCategories)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptError::ErrorCategories res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptError::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptError::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptError::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptError to be used as Squirrel parameter */ template <> inline ScriptError *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptError *)instance; } template <> inline ScriptError &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptError *)instance; } template <> inline const ScriptError *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptError *)instance; } template <> inline const ScriptError &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptError *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptError *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Error", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_cargomonitor.hpp.sq0000644000000000000000000000416612627373433024124 0ustar rootroot/* $Id: template_cargomonitor.hpp.sq 24406 2012-07-15 17:11:14Z alberth $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargomonitor.hpp" namespace SQConvert { /* Allow ScriptCargoMonitor to be used as Squirrel parameter */ template <> inline ScriptCargoMonitor *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoMonitor *)instance; } template <> inline ScriptCargoMonitor &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoMonitor *)instance; } template <> inline const ScriptCargoMonitor *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoMonitor *)instance; } template <> inline const ScriptCargoMonitor &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoMonitor *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargoMonitor *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoMonitor", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_industrytypelist.hpp.sq0000644000000000000000000000430412627373433025072 0ustar rootroot/* $Id: template_industrytypelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrytypelist.hpp" namespace SQConvert { /* Allow ScriptIndustryTypeList to be used as Squirrel parameter */ template <> inline ScriptIndustryTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryTypeList *)instance; } template <> inline ScriptIndustryTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryTypeList *)instance; } template <> inline const ScriptIndustryTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryTypeList *)instance; } template <> inline const ScriptIndustryTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryTypeList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryTypeList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryTypeList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_order.hpp.sq0000644000000000000000000001055412627373433022532 0ustar rootroot/* $Id: template_order.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_order.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptOrder::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptOrder::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptOrder::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptOrder::ScriptOrderFlags GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptOrder::ScriptOrderFlags)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptOrder::ScriptOrderFlags res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptOrder::OrderCondition GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptOrder::OrderCondition)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptOrder::OrderCondition res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptOrder::CompareFunction GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptOrder::CompareFunction)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptOrder::CompareFunction res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptOrder::OrderPosition GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptOrder::OrderPosition)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptOrder::OrderPosition res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptOrder::StopLocation GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptOrder::StopLocation)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptOrder::StopLocation res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptOrder to be used as Squirrel parameter */ template <> inline ScriptOrder *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptOrder *)instance; } template <> inline ScriptOrder &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptOrder *)instance; } template <> inline const ScriptOrder *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptOrder *)instance; } template <> inline const ScriptOrder &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptOrder *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptOrder *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Order", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_execmode.hpp.sq0000644000000000000000000000405412627373433023206 0ustar rootroot/* $Id: template_execmode.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_execmode.hpp" namespace SQConvert { /* Allow ScriptExecMode to be used as Squirrel parameter */ template <> inline ScriptExecMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptExecMode *)instance; } template <> inline ScriptExecMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptExecMode *)instance; } template <> inline const ScriptExecMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptExecMode *)instance; } template <> inline const ScriptExecMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptExecMode *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptExecMode *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "ExecMode", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_bridgelist.hpp.sq0000644000000000000000000000704212627373433023545 0ustar rootroot/* $Id: template_bridgelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_bridgelist.hpp" namespace SQConvert { /* Allow ScriptBridgeList to be used as Squirrel parameter */ template <> inline ScriptBridgeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridgeList *)instance; } template <> inline ScriptBridgeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList *)instance; } template <> inline const ScriptBridgeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridgeList *)instance; } template <> inline const ScriptBridgeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptBridgeList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BridgeList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptBridgeList_Length to be used as Squirrel parameter */ template <> inline ScriptBridgeList_Length *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridgeList_Length *)instance; } template <> inline ScriptBridgeList_Length &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList_Length *)instance; } template <> inline const ScriptBridgeList_Length *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptBridgeList_Length *)instance; } template <> inline const ScriptBridgeList_Length &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptBridgeList_Length *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptBridgeList_Length *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "BridgeList_Length", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_road.hpp.sq0000644000000000000000000000677312627373433022354 0ustar rootroot/* $Id: template_road.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_road.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptRoad::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::RoadType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::RoadVehicleType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::RoadVehicleType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::RoadVehicleType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptRoad::BuildType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptRoad::BuildType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad::BuildType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptRoad to be used as Squirrel parameter */ template <> inline ScriptRoad *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRoad *)instance; } template <> inline ScriptRoad &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoad *)instance; } template <> inline const ScriptRoad *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRoad *)instance; } template <> inline const ScriptRoad &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRoad *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptRoad *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Road", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_townlist.hpp.sq0000644000000000000000000000671112627373433023302 0ustar rootroot/* $Id: template_townlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_townlist.hpp" namespace SQConvert { /* Allow ScriptTownList to be used as Squirrel parameter */ template <> inline ScriptTownList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTownList *)instance; } template <> inline ScriptTownList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownList *)instance; } template <> inline const ScriptTownList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTownList *)instance; } template <> inline const ScriptTownList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTownList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TownList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptTownEffectList to be used as Squirrel parameter */ template <> inline ScriptTownEffectList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTownEffectList *)instance; } template <> inline ScriptTownEffectList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownEffectList *)instance; } template <> inline const ScriptTownEffectList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTownEffectList *)instance; } template <> inline const ScriptTownEffectList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTownEffectList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTownEffectList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TownEffectList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_game.hpp.sq0000644000000000000000000000463012627373433022326 0ustar rootroot/* $Id: template_game.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_game.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptGame::LandscapeType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptGame::LandscapeType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptGame::LandscapeType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptGame to be used as Squirrel parameter */ template <> inline ScriptGame *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGame *)instance; } template <> inline ScriptGame &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGame *)instance; } template <> inline const ScriptGame *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGame *)instance; } template <> inline const ScriptGame &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGame *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptGame *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Game", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_list.hpp.sq0000644000000000000000000000461112627373433022367 0ustar rootroot/* $Id: template_list.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_list.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptList::SorterType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptList::SorterType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptList::SorterType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptList to be used as Squirrel parameter */ template <> inline ScriptList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptList *)instance; } template <> inline ScriptList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptList *)instance; } template <> inline const ScriptList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptList *)instance; } template <> inline const ScriptList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "List", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_signlist.hpp.sq0000644000000000000000000000405412627373433023251 0ustar rootroot/* $Id: template_signlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_signlist.hpp" namespace SQConvert { /* Allow ScriptSignList to be used as Squirrel parameter */ template <> inline ScriptSignList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSignList *)instance; } template <> inline ScriptSignList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSignList *)instance; } template <> inline const ScriptSignList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSignList *)instance; } template <> inline const ScriptSignList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSignList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptSignList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "SignList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_news.hpp.sq0000644000000000000000000000542312627373433022372 0ustar rootroot/* $Id: template_news.hpp.sq 27164 2015-02-22 17:25:29Z alberth $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_news.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptNews::NewsType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptNews::NewsType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptNews::NewsType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptNews::NewsReferenceType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptNews::NewsReferenceType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptNews::NewsReferenceType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptNews to be used as Squirrel parameter */ template <> inline ScriptNews *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptNews *)instance; } template <> inline ScriptNews &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptNews *)instance; } template <> inline const ScriptNews *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptNews *)instance; } template <> inline const ScriptNews &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptNews *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptNews *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "News", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_tile.hpp.sq0000644000000000000000000001027012627373433022347 0ustar rootroot/* $Id: template_tile.hpp.sq 25213 2013-04-30 17:16:32Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tile.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptTile::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTile::Corner GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::Corner)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile::Corner res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTile::Slope GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::Slope)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile::Slope res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTile::TransportType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::TransportType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile::TransportType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTile::BuildType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::BuildType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile::BuildType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptTile::TerrainType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTile::TerrainType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile::TerrainType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptTile to be used as Squirrel parameter */ template <> inline ScriptTile *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTile *)instance; } template <> inline ScriptTile &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTile *)instance; } template <> inline const ScriptTile *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTile *)instance; } template <> inline const ScriptTile &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTile *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTile *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Tile", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_railtypelist.hpp.sq0000644000000000000000000000417012627373433024141 0ustar rootroot/* $Id: template_railtypelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_railtypelist.hpp" namespace SQConvert { /* Allow ScriptRailTypeList to be used as Squirrel parameter */ template <> inline ScriptRailTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRailTypeList *)instance; } template <> inline ScriptRailTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRailTypeList *)instance; } template <> inline const ScriptRailTypeList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptRailTypeList *)instance; } template <> inline const ScriptRailTypeList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptRailTypeList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptRailTypeList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "RailTypeList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_waypointlist.hpp.sq0000644000000000000000000000717312627373433024170 0ustar rootroot/* $Id: template_waypointlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_waypointlist.hpp" namespace SQConvert { /* Allow ScriptWaypointList to be used as Squirrel parameter */ template <> inline ScriptWaypointList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypointList *)instance; } template <> inline ScriptWaypointList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList *)instance; } template <> inline const ScriptWaypointList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypointList *)instance; } template <> inline const ScriptWaypointList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptWaypointList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "WaypointList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptWaypointList_Vehicle to be used as Squirrel parameter */ template <> inline ScriptWaypointList_Vehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypointList_Vehicle *)instance; } template <> inline ScriptWaypointList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList_Vehicle *)instance; } template <> inline const ScriptWaypointList_Vehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWaypointList_Vehicle *)instance; } template <> inline const ScriptWaypointList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWaypointList_Vehicle *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptWaypointList_Vehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "WaypointList_Vehicle", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_industrylist.hpp.sq0000644000000000000000000001255412627373433024176 0ustar rootroot/* $Id: template_industrylist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_industrylist.hpp" namespace SQConvert { /* Allow ScriptIndustryList to be used as Squirrel parameter */ template <> inline ScriptIndustryList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList *)instance; } template <> inline ScriptIndustryList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList *)instance; } template <> inline const ScriptIndustryList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList *)instance; } template <> inline const ScriptIndustryList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptIndustryList_CargoAccepting to be used as Squirrel parameter */ template <> inline ScriptIndustryList_CargoAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList_CargoAccepting *)instance; } template <> inline ScriptIndustryList_CargoAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoAccepting *)instance; } template <> inline const ScriptIndustryList_CargoAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList_CargoAccepting *)instance; } template <> inline const ScriptIndustryList_CargoAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoAccepting *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList_CargoAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList_CargoAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptIndustryList_CargoProducing to be used as Squirrel parameter */ template <> inline ScriptIndustryList_CargoProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList_CargoProducing *)instance; } template <> inline ScriptIndustryList_CargoProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoProducing *)instance; } template <> inline const ScriptIndustryList_CargoProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptIndustryList_CargoProducing *)instance; } template <> inline const ScriptIndustryList_CargoProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptIndustryList_CargoProducing *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptIndustryList_CargoProducing *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "IndustryList_CargoProducing", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_depotlist.hpp.sq0000644000000000000000000000407712627373433023431 0ustar rootroot/* $Id: template_depotlist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_depotlist.hpp" namespace SQConvert { /* Allow ScriptDepotList to be used as Squirrel parameter */ template <> inline ScriptDepotList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptDepotList *)instance; } template <> inline ScriptDepotList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDepotList *)instance; } template <> inline const ScriptDepotList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptDepotList *)instance; } template <> inline const ScriptDepotList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptDepotList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptDepotList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "DepotList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_event_types.hpp.sq0000644000000000000000000012727312627373433023773 0ustar rootroot/* $Id: template_event_types.hpp.sq 24291 2012-05-26 14:16:45Z frosch $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_event_types.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptEventVehicleCrashed::CrashReason GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptEventVehicleCrashed::CrashReason)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleCrashed::CrashReason res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptEventVehicleCrashed to be used as Squirrel parameter */ template <> inline ScriptEventVehicleCrashed *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleCrashed *)instance; } template <> inline ScriptEventVehicleCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleCrashed *)instance; } template <> inline const ScriptEventVehicleCrashed *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleCrashed *)instance; } template <> inline const ScriptEventVehicleCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleCrashed *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleCrashed *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleCrashed", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventSubsidyOffer to be used as Squirrel parameter */ template <> inline ScriptEventSubsidyOffer *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyOffer *)instance; } template <> inline ScriptEventSubsidyOffer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOffer *)instance; } template <> inline const ScriptEventSubsidyOffer *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyOffer *)instance; } template <> inline const ScriptEventSubsidyOffer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOffer *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyOffer *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyOffer", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventSubsidyOfferExpired to be used as Squirrel parameter */ template <> inline ScriptEventSubsidyOfferExpired *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyOfferExpired *)instance; } template <> inline ScriptEventSubsidyOfferExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOfferExpired *)instance; } template <> inline const ScriptEventSubsidyOfferExpired *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyOfferExpired *)instance; } template <> inline const ScriptEventSubsidyOfferExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyOfferExpired *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyOfferExpired *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyOfferExpired", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventSubsidyAwarded to be used as Squirrel parameter */ template <> inline ScriptEventSubsidyAwarded *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyAwarded *)instance; } template <> inline ScriptEventSubsidyAwarded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyAwarded *)instance; } template <> inline const ScriptEventSubsidyAwarded *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyAwarded *)instance; } template <> inline const ScriptEventSubsidyAwarded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyAwarded *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyAwarded *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyAwarded", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventSubsidyExpired to be used as Squirrel parameter */ template <> inline ScriptEventSubsidyExpired *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyExpired *)instance; } template <> inline ScriptEventSubsidyExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyExpired *)instance; } template <> inline const ScriptEventSubsidyExpired *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventSubsidyExpired *)instance; } template <> inline const ScriptEventSubsidyExpired &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventSubsidyExpired *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventSubsidyExpired *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventSubsidyExpired", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventEnginePreview to be used as Squirrel parameter */ template <> inline ScriptEventEnginePreview *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventEnginePreview *)instance; } template <> inline ScriptEventEnginePreview &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEnginePreview *)instance; } template <> inline const ScriptEventEnginePreview *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventEnginePreview *)instance; } template <> inline const ScriptEventEnginePreview &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEnginePreview *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventEnginePreview *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventEnginePreview", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventCompanyNew to be used as Squirrel parameter */ template <> inline ScriptEventCompanyNew *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyNew *)instance; } template <> inline ScriptEventCompanyNew &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyNew *)instance; } template <> inline const ScriptEventCompanyNew *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyNew *)instance; } template <> inline const ScriptEventCompanyNew &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyNew *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyNew *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyNew", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventCompanyInTrouble to be used as Squirrel parameter */ template <> inline ScriptEventCompanyInTrouble *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyInTrouble *)instance; } template <> inline ScriptEventCompanyInTrouble &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyInTrouble *)instance; } template <> inline const ScriptEventCompanyInTrouble *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyInTrouble *)instance; } template <> inline const ScriptEventCompanyInTrouble &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyInTrouble *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyInTrouble *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyInTrouble", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventCompanyAskMerger to be used as Squirrel parameter */ template <> inline ScriptEventCompanyAskMerger *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyAskMerger *)instance; } template <> inline ScriptEventCompanyAskMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyAskMerger *)instance; } template <> inline const ScriptEventCompanyAskMerger *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyAskMerger *)instance; } template <> inline const ScriptEventCompanyAskMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyAskMerger *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyAskMerger *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyAskMerger", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventCompanyMerger to be used as Squirrel parameter */ template <> inline ScriptEventCompanyMerger *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyMerger *)instance; } template <> inline ScriptEventCompanyMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyMerger *)instance; } template <> inline const ScriptEventCompanyMerger *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyMerger *)instance; } template <> inline const ScriptEventCompanyMerger &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyMerger *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyMerger *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyMerger", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventCompanyBankrupt to be used as Squirrel parameter */ template <> inline ScriptEventCompanyBankrupt *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyBankrupt *)instance; } template <> inline ScriptEventCompanyBankrupt &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyBankrupt *)instance; } template <> inline const ScriptEventCompanyBankrupt *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyBankrupt *)instance; } template <> inline const ScriptEventCompanyBankrupt &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyBankrupt *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyBankrupt *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyBankrupt", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventVehicleLost to be used as Squirrel parameter */ template <> inline ScriptEventVehicleLost *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleLost *)instance; } template <> inline ScriptEventVehicleLost &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleLost *)instance; } template <> inline const ScriptEventVehicleLost *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleLost *)instance; } template <> inline const ScriptEventVehicleLost &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleLost *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleLost *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleLost", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventVehicleWaitingInDepot to be used as Squirrel parameter */ template <> inline ScriptEventVehicleWaitingInDepot *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleWaitingInDepot *)instance; } template <> inline ScriptEventVehicleWaitingInDepot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleWaitingInDepot *)instance; } template <> inline const ScriptEventVehicleWaitingInDepot *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleWaitingInDepot *)instance; } template <> inline const ScriptEventVehicleWaitingInDepot &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleWaitingInDepot *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleWaitingInDepot *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleWaitingInDepot", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventVehicleUnprofitable to be used as Squirrel parameter */ template <> inline ScriptEventVehicleUnprofitable *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleUnprofitable *)instance; } template <> inline ScriptEventVehicleUnprofitable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleUnprofitable *)instance; } template <> inline const ScriptEventVehicleUnprofitable *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventVehicleUnprofitable *)instance; } template <> inline const ScriptEventVehicleUnprofitable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventVehicleUnprofitable *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventVehicleUnprofitable *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventVehicleUnprofitable", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventIndustryOpen to be used as Squirrel parameter */ template <> inline ScriptEventIndustryOpen *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventIndustryOpen *)instance; } template <> inline ScriptEventIndustryOpen &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryOpen *)instance; } template <> inline const ScriptEventIndustryOpen *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventIndustryOpen *)instance; } template <> inline const ScriptEventIndustryOpen &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryOpen *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventIndustryOpen *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventIndustryOpen", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventIndustryClose to be used as Squirrel parameter */ template <> inline ScriptEventIndustryClose *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventIndustryClose *)instance; } template <> inline ScriptEventIndustryClose &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryClose *)instance; } template <> inline const ScriptEventIndustryClose *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventIndustryClose *)instance; } template <> inline const ScriptEventIndustryClose &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventIndustryClose *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventIndustryClose *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventIndustryClose", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventEngineAvailable to be used as Squirrel parameter */ template <> inline ScriptEventEngineAvailable *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventEngineAvailable *)instance; } template <> inline ScriptEventEngineAvailable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEngineAvailable *)instance; } template <> inline const ScriptEventEngineAvailable *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventEngineAvailable *)instance; } template <> inline const ScriptEventEngineAvailable &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventEngineAvailable *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventEngineAvailable *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventEngineAvailable", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventStationFirstVehicle to be used as Squirrel parameter */ template <> inline ScriptEventStationFirstVehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventStationFirstVehicle *)instance; } template <> inline ScriptEventStationFirstVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventStationFirstVehicle *)instance; } template <> inline const ScriptEventStationFirstVehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventStationFirstVehicle *)instance; } template <> inline const ScriptEventStationFirstVehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventStationFirstVehicle *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventStationFirstVehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventStationFirstVehicle", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventDisasterZeppelinerCrashed to be used as Squirrel parameter */ template <> inline ScriptEventDisasterZeppelinerCrashed *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventDisasterZeppelinerCrashed *)instance; } template <> inline ScriptEventDisasterZeppelinerCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCrashed *)instance; } template <> inline const ScriptEventDisasterZeppelinerCrashed *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventDisasterZeppelinerCrashed *)instance; } template <> inline const ScriptEventDisasterZeppelinerCrashed &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCrashed *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventDisasterZeppelinerCrashed *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventDisasterZeppelinerCrashed", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventDisasterZeppelinerCleared to be used as Squirrel parameter */ template <> inline ScriptEventDisasterZeppelinerCleared *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventDisasterZeppelinerCleared *)instance; } template <> inline ScriptEventDisasterZeppelinerCleared &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCleared *)instance; } template <> inline const ScriptEventDisasterZeppelinerCleared *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventDisasterZeppelinerCleared *)instance; } template <> inline const ScriptEventDisasterZeppelinerCleared &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventDisasterZeppelinerCleared *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventDisasterZeppelinerCleared *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventDisasterZeppelinerCleared", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventTownFounded to be used as Squirrel parameter */ template <> inline ScriptEventTownFounded *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventTownFounded *)instance; } template <> inline ScriptEventTownFounded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventTownFounded *)instance; } template <> inline const ScriptEventTownFounded *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventTownFounded *)instance; } template <> inline const ScriptEventTownFounded &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventTownFounded *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventTownFounded *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventTownFounded", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventAircraftDestTooFar to be used as Squirrel parameter */ template <> inline ScriptEventAircraftDestTooFar *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventAircraftDestTooFar *)instance; } template <> inline ScriptEventAircraftDestTooFar &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAircraftDestTooFar *)instance; } template <> inline const ScriptEventAircraftDestTooFar *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventAircraftDestTooFar *)instance; } template <> inline const ScriptEventAircraftDestTooFar &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAircraftDestTooFar *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventAircraftDestTooFar *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventAircraftDestTooFar", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventAdminPort to be used as Squirrel parameter */ template <> inline ScriptEventAdminPort *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventAdminPort *)instance; } template <> inline ScriptEventAdminPort &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAdminPort *)instance; } template <> inline const ScriptEventAdminPort *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventAdminPort *)instance; } template <> inline const ScriptEventAdminPort &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventAdminPort *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventAdminPort *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventAdminPort", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventWindowWidgetClick to be used as Squirrel parameter */ template <> inline ScriptEventWindowWidgetClick *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventWindowWidgetClick *)instance; } template <> inline ScriptEventWindowWidgetClick &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventWindowWidgetClick *)instance; } template <> inline const ScriptEventWindowWidgetClick *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventWindowWidgetClick *)instance; } template <> inline const ScriptEventWindowWidgetClick &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventWindowWidgetClick *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventWindowWidgetClick *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventWindowWidgetClick", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventGoalQuestionAnswer to be used as Squirrel parameter */ template <> inline ScriptEventGoalQuestionAnswer *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventGoalQuestionAnswer *)instance; } template <> inline ScriptEventGoalQuestionAnswer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventGoalQuestionAnswer *)instance; } template <> inline const ScriptEventGoalQuestionAnswer *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventGoalQuestionAnswer *)instance; } template <> inline const ScriptEventGoalQuestionAnswer &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventGoalQuestionAnswer *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventGoalQuestionAnswer *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventGoalQuestionAnswer", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventCompanyTown to be used as Squirrel parameter */ template <> inline ScriptEventCompanyTown *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyTown *)instance; } template <> inline ScriptEventCompanyTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyTown *)instance; } template <> inline const ScriptEventCompanyTown *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventCompanyTown *)instance; } template <> inline const ScriptEventCompanyTown &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventCompanyTown *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventCompanyTown *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventCompanyTown", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventExclusiveTransportRights to be used as Squirrel parameter */ template <> inline ScriptEventExclusiveTransportRights *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventExclusiveTransportRights *)instance; } template <> inline ScriptEventExclusiveTransportRights &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventExclusiveTransportRights *)instance; } template <> inline const ScriptEventExclusiveTransportRights *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventExclusiveTransportRights *)instance; } template <> inline const ScriptEventExclusiveTransportRights &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventExclusiveTransportRights *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventExclusiveTransportRights *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventExclusiveTransportRights", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventRoadReconstruction to be used as Squirrel parameter */ template <> inline ScriptEventRoadReconstruction *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventRoadReconstruction *)instance; } template <> inline ScriptEventRoadReconstruction &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventRoadReconstruction *)instance; } template <> inline const ScriptEventRoadReconstruction *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventRoadReconstruction *)instance; } template <> inline const ScriptEventRoadReconstruction &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventRoadReconstruction *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventRoadReconstruction *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventRoadReconstruction", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_storypageelementlist.hpp.sq0000644000000000000000000000430412627373433025676 0ustar rootroot/* $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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_storypageelementlist.hpp" namespace SQConvert { /* Allow ScriptStoryPageElementList to be used as Squirrel parameter */ template <> inline ScriptStoryPageElementList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPageElementList *)instance; } template <> inline ScriptStoryPageElementList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageElementList *)instance; } template <> inline const ScriptStoryPageElementList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPageElementList *)instance; } template <> inline const ScriptStoryPageElementList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPageElementList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPageElementList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPageElementList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_companymode.hpp.sq0000644000000000000000000000414512627373433023731 0ustar rootroot/* $Id: template_companymode.hpp.sq 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_companymode.hpp" namespace SQConvert { /* Allow ScriptCompanyMode to be used as Squirrel parameter */ template <> inline ScriptCompanyMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCompanyMode *)instance; } template <> inline ScriptCompanyMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompanyMode *)instance; } template <> inline const ScriptCompanyMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCompanyMode *)instance; } template <> inline const ScriptCompanyMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompanyMode *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCompanyMode *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CompanyMode", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_group.hpp.sq0000644000000000000000000000462212627373433022552 0ustar rootroot/* $Id: template_group.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_group.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptGroup::GroupID GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptGroup::GroupID)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptGroup::GroupID res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptGroup to be used as Squirrel parameter */ template <> inline ScriptGroup *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGroup *)instance; } template <> inline ScriptGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroup *)instance; } template <> inline const ScriptGroup *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGroup *)instance; } template <> inline const ScriptGroup &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroup *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptGroup *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Group", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_company.hpp.sq0000644000000000000000000000706312627373433023066 0ustar rootroot/* $Id: template_company.hpp.sq 25788 2013-09-21 13:07:42Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_company.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptCompany::Quarter GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCompany::Quarter)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCompany::Quarter res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptCompany::CompanyID GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCompany::CompanyID)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCompany::CompanyID res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptCompany::Gender GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCompany::Gender)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCompany::Gender res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptCompany::ExpensesType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCompany::ExpensesType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCompany::ExpensesType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptCompany to be used as Squirrel parameter */ template <> inline ScriptCompany *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCompany *)instance; } template <> inline ScriptCompany &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompany *)instance; } template <> inline const ScriptCompany *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCompany *)instance; } template <> inline const ScriptCompany &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCompany *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCompany *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Company", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_engine.hpp.sq0000644000000000000000000000400612627373433022657 0ustar rootroot/* $Id: template_engine.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_engine.hpp" namespace SQConvert { /* Allow ScriptEngine to be used as Squirrel parameter */ template <> inline ScriptEngine *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEngine *)instance; } template <> inline ScriptEngine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngine *)instance; } template <> inline const ScriptEngine *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEngine *)instance; } template <> inline const ScriptEngine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngine *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEngine *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Engine", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_enginelist.hpp.sq0000644000000000000000000000412212627373433023552 0ustar rootroot/* $Id: template_enginelist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_enginelist.hpp" namespace SQConvert { /* Allow ScriptEngineList to be used as Squirrel parameter */ template <> inline ScriptEngineList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEngineList *)instance; } template <> inline ScriptEngineList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngineList *)instance; } template <> inline const ScriptEngineList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEngineList *)instance; } template <> inline const ScriptEngineList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEngineList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEngineList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EngineList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_testmode.hpp.sq0000644000000000000000000000405412627373433023241 0ustar rootroot/* $Id: template_testmode.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_testmode.hpp" namespace SQConvert { /* Allow ScriptTestMode to be used as Squirrel parameter */ template <> inline ScriptTestMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTestMode *)instance; } template <> inline ScriptTestMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTestMode *)instance; } template <> inline const ScriptTestMode *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTestMode *)instance; } template <> inline const ScriptTestMode &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTestMode *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTestMode *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "TestMode", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_window.hpp.sq0000644000000000000000000014660112627373433022731 0ustar rootroot/* $Id: template_window.hpp.sq 26610 2014-05-24 19:11:20Z alberth $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_window.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptWindow::WindowNumberEnum GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WindowNumberEnum)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WindowNumberEnum res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::WindowClass GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WindowClass)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WindowClass res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TextColour GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TextColour)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TextColour res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NumberType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NumberType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NumberType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::WidgetType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WidgetType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WidgetType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::AIListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::AISettingsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AISettingsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AISettingsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::AIConfigWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIConfigWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIConfigWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::AIDebugWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AIDebugWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AIDebugWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::AirportToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AirportToolbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AirportToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::AirportPickerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AirportPickerWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AirportPickerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ReplaceVehicleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ReplaceVehicleWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ReplaceVehicleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BootstrapBackgroundWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BootstrapBackgroundWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BootstrapBackgroundWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BootstrapAskForDownloadWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BootstrapAskForDownloadWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BootstrapAskForDownloadWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildBridgeSelectionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildBridgeSelectionWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildBridgeSelectionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildVehicleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildVehicleWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildVehicleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CheatWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CheatWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CheatWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CompanyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CompanyFinancesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyFinancesWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyFinancesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SelectCompanyLiveryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectCompanyLiveryWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectCompanyLiveryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SelectCompanyManagerFaceWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectCompanyManagerFaceWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectCompanyManagerFaceWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CompanyInfrastructureWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyInfrastructureWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyInfrastructureWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuyCompanyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuyCompanyWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuyCompanyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ConsoleWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ConsoleWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ConsoleWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SetDateWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SetDateWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SetDateWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::DepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DepotWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildDockDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildDockDepotWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildDockDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::DockToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DockToolbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DockToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::DropdownMenuWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DropdownMenuWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DropdownMenuWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::EnginePreviewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::EnginePreviewWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::EnginePreviewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ErrorMessageWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ErrorMessageWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ErrorMessageWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SaveLoadWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SaveLoadWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SaveLoadWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GenerateLandscapeWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GenerateLandscapeWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GenerateLandscapeWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CreateScenarioWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CreateScenarioWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CreateScenarioWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GenerationProgressWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GenerationProgressWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GenerationProgressWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GoalListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GoalListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GoalListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GoalQuestionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GoalQuestionWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GoalQuestionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GraphLegendWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GraphLegendWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GraphLegendWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CompanyValueWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyValueWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyValueWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::PerformanceHistoryGraphWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::PerformanceHistoryGraphWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::PerformanceHistoryGraphWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CargoPaymentRatesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CargoPaymentRatesWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CargoPaymentRatesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CompanyLeagueWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CompanyLeagueWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CompanyLeagueWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::PerformanceRatingDetailsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::PerformanceRatingDetailsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::PerformanceRatingDetailsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GroupListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GroupListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GroupListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::HighscoreWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::HighscoreWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::HighscoreWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::DynamicPlaceIndustriesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::DynamicPlaceIndustriesWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::DynamicPlaceIndustriesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::IndustryViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryViewWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::IndustryDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryDirectoryWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::IndustryCargoesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::IndustryCargoesWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::IndustryCargoesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SelectGameIntroWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SelectGameIntroWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SelectGameIntroWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::LinkGraphLegendWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::LinkGraphLegendWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::LinkGraphLegendWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::MainWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MainWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MainWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::LandInfoWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::LandInfoWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::LandInfoWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ToolTipsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolTipsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolTipsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::AboutWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::AboutWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::AboutWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::QueryStringWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryStringWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryStringWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::QueryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TextfileWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TextfileWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TextfileWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::MusicTrackSelectionWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MusicTrackSelectionWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MusicTrackSelectionWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::MusicWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MusicWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MusicWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetWorkChatWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetWorkChatWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetWorkChatWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetworkContentDownloadStatusWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkContentDownloadStatusWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkContentDownloadStatusWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetworkContentListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkContentListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkContentListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetworkGameWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkGameWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkGameWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetworkStartServerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkStartServerWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkStartServerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetworkLobbyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkLobbyWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkLobbyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ClientListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ClientListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ClientListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ClientListPopupWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ClientListPopupWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ClientListPopupWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetworkJoinStatusWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkJoinStatusWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkJoinStatusWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NetworkCompanyPasswordWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NetworkCompanyPasswordWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NetworkCompanyPasswordWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NewGRFInspectWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFInspectWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFInspectWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SpriteAlignerWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SpriteAlignerWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SpriteAlignerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NewGRFParametersWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFParametersWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFParametersWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NewGRFStateWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFStateWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFStateWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SavePresetWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SavePresetWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SavePresetWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ScanProgressWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ScanProgressWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ScanProgressWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NewsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::MessageHistoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MessageHistoryWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::MessageHistoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildObjectWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildObjectWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildObjectWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::OrderWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::OrderWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::OrderWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::OnScreenKeyboardWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::OnScreenKeyboardWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::OnScreenKeyboardWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::RailToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::RailToolbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::RailToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildRailStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailStationWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildSignalWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildSignalWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildSignalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildRailDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailDepotWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildRailWaypointWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRailWaypointWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRailWaypointWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::RoadToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::RoadToolbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::RoadToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildRoadDepotWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRoadDepotWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRoadDepotWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildRoadStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildRoadStationWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildRoadStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GameOptionsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GameOptionsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GameOptionsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::GameSettingsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::GameSettingsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::GameSettingsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::CustomCurrencyWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::CustomCurrencyWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::CustomCurrencyWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SignListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SignListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SignListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::QueryEditSignWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::QueryEditSignWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::QueryEditSignWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SmallMapWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SmallMapWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SmallMapWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::StationViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StationViewWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StationViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::StationListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StationListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StationListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::JoinStationWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::JoinStationWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::JoinStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::StatusbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StatusbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StatusbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::StoryBookWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StoryBookWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StoryBookWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SubsidyListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SubsidyListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SubsidyListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TerraformToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TerraformToolbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::EditorTerraformToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::EditorTerraformToolbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::EditorTerraformToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::VehicleTimetableWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleTimetableWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleTimetableWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ToolbarNormalWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarNormalWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarNormalWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ToolbarEditorWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ToolbarEditorWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ToolbarEditorWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownDirectoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownDirectoryWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownDirectoryWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownAuthorityWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownAuthorityWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownAuthorityWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownViewWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TownFoundingWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TownFoundingWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TownFoundingWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TransparencyToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TransparencyToolbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TransparencyToolbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::BuildTreesWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::BuildTreesWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::BuildTreesWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::VehicleViewWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleViewWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleViewWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::VehicleRefitWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleRefitWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleRefitWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::VehicleDetailsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleDetailsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleDetailsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::VehicleListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::VehicleListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::VehicleListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ExtraViewportWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ExtraViewportWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ExtraViewportWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::WaypointWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::WaypointWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::WaypointWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptWindow to be used as Squirrel parameter */ template <> inline ScriptWindow *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWindow *)instance; } template <> inline ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } template <> inline const ScriptWindow *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptWindow *)instance; } template <> inline const ScriptWindow &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptWindow *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Window", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_cargo.hpp.sq0000644000000000000000000000706512627373433022515 0ustar rootroot/* $Id: template_cargo.hpp.sq 26396 2014-03-10 22:18:53Z zuu $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargo.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptCargo::CargoClass GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCargo::CargoClass)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargo::CargoClass res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptCargo::TownEffect GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCargo::TownEffect)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargo::TownEffect res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptCargo::SpecialCargoID GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCargo::SpecialCargoID)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargo::SpecialCargoID res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptCargo::DistributionType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptCargo::DistributionType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargo::DistributionType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptCargo to be used as Squirrel parameter */ template <> inline ScriptCargo *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargo *)instance; } template <> inline ScriptCargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargo *)instance; } template <> inline const ScriptCargo *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargo *)instance; } template <> inline const ScriptCargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargo *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargo *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Cargo", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_cargolist.hpp.sq0000644000000000000000000001563412627373433023412 0ustar rootroot/* $Id: template_cargolist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_cargolist.hpp" namespace SQConvert { /* Allow ScriptCargoList to be used as Squirrel parameter */ template <> inline ScriptCargoList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList *)instance; } template <> inline ScriptCargoList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList *)instance; } template <> inline const ScriptCargoList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList *)instance; } template <> inline const ScriptCargoList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptCargoList_IndustryAccepting to be used as Squirrel parameter */ template <> inline ScriptCargoList_IndustryAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_IndustryAccepting *)instance; } template <> inline ScriptCargoList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryAccepting *)instance; } template <> inline const ScriptCargoList_IndustryAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_IndustryAccepting *)instance; } template <> inline const ScriptCargoList_IndustryAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryAccepting *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_IndustryAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_IndustryAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptCargoList_IndustryProducing to be used as Squirrel parameter */ template <> inline ScriptCargoList_IndustryProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_IndustryProducing *)instance; } template <> inline ScriptCargoList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryProducing *)instance; } template <> inline const ScriptCargoList_IndustryProducing *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_IndustryProducing *)instance; } template <> inline const ScriptCargoList_IndustryProducing &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_IndustryProducing *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_IndustryProducing *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_IndustryProducing", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptCargoList_StationAccepting to be used as Squirrel parameter */ template <> inline ScriptCargoList_StationAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_StationAccepting *)instance; } template <> inline ScriptCargoList_StationAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_StationAccepting *)instance; } template <> inline const ScriptCargoList_StationAccepting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptCargoList_StationAccepting *)instance; } template <> inline const ScriptCargoList_StationAccepting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptCargoList_StationAccepting *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptCargoList_StationAccepting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "CargoList_StationAccepting", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_stationlist.hpp.sq0000644000000000000000000005516012627373433023776 0ustar rootroot/* $Id: template_stationlist.hpp.sq 26893 2014-09-21 16:20:48Z fonsinchen $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_stationlist.hpp" namespace SQConvert { /* Allow ScriptStationList to be used as Squirrel parameter */ template <> inline ScriptStationList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList *)instance; } template <> inline ScriptStationList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList *)instance; } template <> inline const ScriptStationList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList *)instance; } template <> inline const ScriptStationList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptStationList_Cargo::CargoSelector GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStationList_Cargo::CargoSelector)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Cargo::CargoSelector res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptStationList_Cargo::CargoMode GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStationList_Cargo::CargoMode)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Cargo::CargoMode res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptStationList_Cargo to be used as Squirrel parameter */ template <> inline ScriptStationList_Cargo *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_Cargo *)instance; } template <> inline ScriptStationList_Cargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Cargo *)instance; } template <> inline const ScriptStationList_Cargo *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_Cargo *)instance; } template <> inline const ScriptStationList_Cargo &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Cargo *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Cargo *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_Cargo", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoWaiting to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoWaiting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaiting *)instance; } template <> inline ScriptStationList_CargoWaiting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaiting *)instance; } template <> inline const ScriptStationList_CargoWaiting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaiting *)instance; } template <> inline const ScriptStationList_CargoWaiting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaiting *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaiting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaiting", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoPlanned to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoPlanned *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlanned *)instance; } template <> inline ScriptStationList_CargoPlanned &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlanned *)instance; } template <> inline const ScriptStationList_CargoPlanned *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlanned *)instance; } template <> inline const ScriptStationList_CargoPlanned &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlanned *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlanned *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlanned", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoWaitingByFrom to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoWaitingByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingByFrom *)instance; } template <> inline ScriptStationList_CargoWaitingByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByFrom *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoWaitingViaByFrom to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoWaitingViaByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingViaByFrom *)instance; } template <> inline ScriptStationList_CargoWaitingViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingViaByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingViaByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingViaByFrom *)instance; } template <> inline const ScriptStationList_CargoWaitingViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingViaByFrom *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingViaByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingViaByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoWaitingByVia to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoWaitingByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingByVia *)instance; } template <> inline ScriptStationList_CargoWaitingByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingByVia *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingByVia", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoWaitingFromByVia to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoWaitingFromByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingFromByVia *)instance; } template <> inline ScriptStationList_CargoWaitingFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingFromByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingFromByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoWaitingFromByVia *)instance; } template <> inline const ScriptStationList_CargoWaitingFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoWaitingFromByVia *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoWaitingFromByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoWaitingFromByVia", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoPlannedByFrom to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoPlannedByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedByFrom *)instance; } template <> inline ScriptStationList_CargoPlannedByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByFrom *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoPlannedViaByFrom to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoPlannedViaByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedViaByFrom *)instance; } template <> inline ScriptStationList_CargoPlannedViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedViaByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedViaByFrom *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedViaByFrom *)instance; } template <> inline const ScriptStationList_CargoPlannedViaByFrom &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedViaByFrom *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedViaByFrom *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedViaByFrom", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoPlannedByVia to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoPlannedByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedByVia *)instance; } template <> inline ScriptStationList_CargoPlannedByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedByVia *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedByVia", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_CargoPlannedFromByVia to be used as Squirrel parameter */ template <> inline ScriptStationList_CargoPlannedFromByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedFromByVia *)instance; } template <> inline ScriptStationList_CargoPlannedFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedFromByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedFromByVia *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_CargoPlannedFromByVia *)instance; } template <> inline const ScriptStationList_CargoPlannedFromByVia &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_CargoPlannedFromByVia *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_CargoPlannedFromByVia *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_CargoPlannedFromByVia", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptStationList_Vehicle to be used as Squirrel parameter */ template <> inline ScriptStationList_Vehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_Vehicle *)instance; } template <> inline ScriptStationList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Vehicle *)instance; } template <> inline const ScriptStationList_Vehicle *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStationList_Vehicle *)instance; } template <> inline const ScriptStationList_Vehicle &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStationList_Vehicle *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStationList_Vehicle *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StationList_Vehicle", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_marine.hpp.sq0000644000000000000000000000550012627373433022665 0ustar rootroot/* $Id: template_marine.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_marine.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptMarine::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptMarine::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptMarine::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptMarine::BuildType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptMarine::BuildType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptMarine::BuildType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptMarine to be used as Squirrel parameter */ template <> inline ScriptMarine *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptMarine *)instance; } template <> inline ScriptMarine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMarine *)instance; } template <> inline const ScriptMarine *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptMarine *)instance; } template <> inline const ScriptMarine &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMarine *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptMarine *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Marine", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_grouplist.hpp.sq0000644000000000000000000000407712627373433023452 0ustar rootroot/* $Id: template_grouplist.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_grouplist.hpp" namespace SQConvert { /* Allow ScriptGroupList to be used as Squirrel parameter */ template <> inline ScriptGroupList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGroupList *)instance; } template <> inline ScriptGroupList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroupList *)instance; } template <> inline const ScriptGroupList *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptGroupList *)instance; } template <> inline const ScriptGroupList &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptGroupList *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptGroupList *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "GroupList", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_accounting.hpp.sq0000644000000000000000000000412212627373433023543 0ustar rootroot/* $Id: template_accounting.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_accounting.hpp" namespace SQConvert { /* Allow ScriptAccounting to be used as Squirrel parameter */ template <> inline ScriptAccounting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAccounting *)instance; } template <> inline ScriptAccounting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAccounting *)instance; } template <> inline const ScriptAccounting *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAccounting *)instance; } template <> inline const ScriptAccounting &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAccounting *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptAccounting *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Accounting", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_airport.hpp.sq0000644000000000000000000000552312627373433023077 0ustar rootroot/* $Id: template_airport.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_airport.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptAirport::AirportType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptAirport::AirportType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptAirport::AirportType res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptAirport::PlaneType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptAirport::PlaneType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptAirport::PlaneType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptAirport to be used as Squirrel parameter */ template <> inline ScriptAirport *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAirport *)instance; } template <> inline ScriptAirport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAirport *)instance; } template <> inline const ScriptAirport *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptAirport *)instance; } template <> inline const ScriptAirport &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptAirport *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptAirport *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Airport", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_event.hpp.sq0000644000000000000000000000753112627373433022541 0ustar rootroot/* $Id: template_event.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_event.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptEvent::ScriptEventType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptEvent::ScriptEventType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptEvent::ScriptEventType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptEvent to be used as Squirrel parameter */ template <> inline ScriptEvent *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEvent *)instance; } template <> inline ScriptEvent &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEvent *)instance; } template <> inline const ScriptEvent *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEvent *)instance; } template <> inline const ScriptEvent &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEvent *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEvent *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, "Event", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert namespace SQConvert { /* Allow ScriptEventController to be used as Squirrel parameter */ template <> inline ScriptEventController *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventController *)instance; } template <> inline ScriptEventController &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventController *)instance; } template <> inline const ScriptEventController *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptEventController *)instance; } template <> inline const ScriptEventController &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptEventController *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptEventController *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "EventController", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_story_page.hpp.sq0000644000000000000000000000657112627373433023577 0ustar rootroot/* $Id: template_story_page.hpp.sq 25371 2013-06-09 13:18:37Z rubidium $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_story_page.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptStoryPage::StoryPageID GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStoryPage::StoryPageID)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPage::StoryPageID res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptStoryPage::StoryPageElementID GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStoryPage::StoryPageElementID)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPage::StoryPageElementID res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptStoryPage::StoryPageElementType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStoryPage::StoryPageElementType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPage::StoryPageElementType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptStoryPage to be used as Squirrel parameter */ template <> inline ScriptStoryPage *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPage *)instance; } template <> inline ScriptStoryPage &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPage *)instance; } template <> inline const ScriptStoryPage *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPage *)instance; } template <> inline const ScriptStoryPage &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPage *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptStoryPage *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPage", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_tunnel.hpp.sq0000644000000000000000000000471012627373433022721 0ustar rootroot/* $Id: template_tunnel.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_tunnel.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptTunnel::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptTunnel::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptTunnel::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptTunnel to be used as Squirrel parameter */ template <> inline ScriptTunnel *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTunnel *)instance; } template <> inline ScriptTunnel &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTunnel *)instance; } template <> inline const ScriptTunnel *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptTunnel *)instance; } template <> inline const ScriptTunnel &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptTunnel *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptTunnel *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Tunnel", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_sign.hpp.sq0000644000000000000000000000463012627373433022355 0ustar rootroot/* $Id: template_sign.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_sign.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptSign::ErrorMessages GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptSign::ErrorMessages)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptSign::ErrorMessages res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptSign to be used as Squirrel parameter */ template <> inline ScriptSign *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSign *)instance; } template <> inline ScriptSign &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSign *)instance; } template <> inline const ScriptSign *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSign *)instance; } template <> inline const ScriptSign &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSign *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptSign *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Sign", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_subsidy.hpp.sq0000644000000000000000000000501512627373433023075 0ustar rootroot/* $Id: template_subsidy.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_subsidy.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptSubsidy::SubsidyParticipantType GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptSubsidy::SubsidyParticipantType)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptSubsidy::SubsidyParticipantType res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptSubsidy to be used as Squirrel parameter */ template <> inline ScriptSubsidy *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSubsidy *)instance; } template <> inline ScriptSubsidy &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidy *)instance; } template <> inline const ScriptSubsidy *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptSubsidy *)instance; } template <> inline const ScriptSubsidy &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptSubsidy *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptSubsidy *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Subsidy", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_map.hpp.sq0000644000000000000000000000371512627373433022175 0ustar rootroot/* $Id: template_map.hpp.sq 23379 2011-11-30 14:11:02Z truebrain $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_map.hpp" namespace SQConvert { /* Allow ScriptMap to be used as Squirrel parameter */ template <> inline ScriptMap *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptMap *)instance; } template <> inline ScriptMap &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMap *)instance; } template <> inline const ScriptMap *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptMap *)instance; } template <> inline const ScriptMap &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptMap *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptMap *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Map", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/template/template_infrastructure.hpp.sq0000644000000000000000000000521412627373433024474 0ustar rootroot/* $Id: template_infrastructure.hpp.sq 23416 2011-12-03 23:40:57Z michi_cc $ */ /* * 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 . */ /* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */ #include "../script_infrastructure.hpp" namespace SQConvert { /* Allow enums to be used as Squirrel parameters */ template <> inline ScriptInfrastructure::Infrastructure GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptInfrastructure::Infrastructure)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptInfrastructure::Infrastructure res) { sq_pushinteger(vm, (int32)res); return 1; } /* Allow ScriptInfrastructure to be used as Squirrel parameter */ template <> inline ScriptInfrastructure *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptInfrastructure *)instance; } template <> inline ScriptInfrastructure &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptInfrastructure *)instance; } template <> inline const ScriptInfrastructure *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptInfrastructure *)instance; } template <> inline const ScriptInfrastructure &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptInfrastructure *)instance; } template <> inline int Return(HSQUIRRELVM vm, ScriptInfrastructure *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "Infrastructure", res, NULL, DefSQDestructorCallback, true); return 1; } } // namespace SQConvert openttd-1.5.3/src/script/api/script_list.cpp0000644000000000000000000005457712627373434017637 0ustar rootroot/* $Id: script_list.cpp 27272 2015-05-08 17:32:57Z frosch $ */ /* * 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 script_list.cpp Implementation of ScriptList. */ #include "../../stdafx.h" #include "script_list.hpp" #include "../../debug.h" #include "../../script/squirrel.hpp" #include "../../safeguards.h" /** * Base class for any ScriptList sorter. */ class ScriptListSorter { protected: ScriptList *list; ///< The list that's being sorted. bool has_no_more_items; ///< Whether we have more items to iterate over. int64 item_next; ///< The next item we will show. public: /** * Virtual dtor, needed to mute warnings. */ virtual ~ScriptListSorter() { } /** * Get the first item of the sorter. */ virtual int64 Begin() = 0; /** * Stop iterating a sorter. */ virtual void End() = 0; /** * Get the next item of the sorter. */ virtual int64 Next() = 0; /** * See if the sorter has reached the end. */ bool IsEnd() { return this->list->buckets.empty() || this->has_no_more_items; } /** * Callback from the list if an item gets removed. */ virtual void Remove(int item) = 0; /** * Attach the sorter to a new list. This assumes the content of the old list has been moved to * the new list, too, so that we don't have to invalidate any iterators. Note that std::swap * doesn't invalidate iterators on lists and maps, so that should be safe. * @param target New list to attach to. */ virtual void Retarget(ScriptList *new_list) { this->list = new_list; } }; /** * Sort by value, ascending. */ class ScriptListSorterValueAscending : public ScriptListSorter { private: ScriptList::ScriptListBucket::iterator bucket_iter; ///< The iterator over the list to find the buckets. ScriptList::ScriptItemList *bucket_list; ///< The current bucket list we're iterator over. ScriptList::ScriptItemList::iterator bucket_list_iter; ///< The iterator over the bucket list. public: /** * Create a new sorter. * @param list The list to sort. */ ScriptListSorterValueAscending(ScriptList *list) { this->list = list; this->End(); } int64 Begin() { if (this->list->buckets.empty()) return 0; this->has_no_more_items = false; this->bucket_iter = this->list->buckets.begin(); this->bucket_list = &(*this->bucket_iter).second; this->bucket_list_iter = this->bucket_list->begin(); this->item_next = *this->bucket_list_iter; int64 item_current = this->item_next; FindNext(); return item_current; } void End() { this->bucket_list = NULL; this->has_no_more_items = true; this->item_next = 0; } /** * Find the next item, and store that information. */ void FindNext() { if (this->bucket_list == NULL) { this->has_no_more_items = true; return; } this->bucket_list_iter++; if (this->bucket_list_iter == this->bucket_list->end()) { this->bucket_iter++; if (this->bucket_iter == this->list->buckets.end()) { this->bucket_list = NULL; return; } this->bucket_list = &(*this->bucket_iter).second; this->bucket_list_iter = this->bucket_list->begin(); } this->item_next = *this->bucket_list_iter; } int64 Next() { if (this->IsEnd()) return 0; int64 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (this->IsEnd()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } }; /** * Sort by value, descending. */ class ScriptListSorterValueDescending : public ScriptListSorter { private: /* Note: We cannot use reverse_iterator. * The iterators must only be invalidated when the element they are pointing to is removed. * This only holds for forward iterators. */ ScriptList::ScriptListBucket::iterator bucket_iter; ///< The iterator over the list to find the buckets. ScriptList::ScriptItemList *bucket_list; ///< The current bucket list we're iterator over. ScriptList::ScriptItemList::iterator bucket_list_iter; ///< The iterator over the bucket list. public: /** * Create a new sorter. * @param list The list to sort. */ ScriptListSorterValueDescending(ScriptList *list) { this->list = list; this->End(); } int64 Begin() { if (this->list->buckets.empty()) return 0; this->has_no_more_items = false; /* Go to the end of the bucket-list */ this->bucket_iter = this->list->buckets.end(); --this->bucket_iter; this->bucket_list = &(*this->bucket_iter).second; /* Go to the end of the items in the bucket */ this->bucket_list_iter = this->bucket_list->end(); --this->bucket_list_iter; this->item_next = *this->bucket_list_iter; int64 item_current = this->item_next; FindNext(); return item_current; } void End() { this->bucket_list = NULL; this->has_no_more_items = true; this->item_next = 0; } /** * Find the next item, and store that information. */ void FindNext() { if (this->bucket_list == NULL) { this->has_no_more_items = true; return; } if (this->bucket_list_iter == this->bucket_list->begin()) { if (this->bucket_iter == this->list->buckets.begin()) { this->bucket_list = NULL; return; } this->bucket_iter--; this->bucket_list = &(*this->bucket_iter).second; /* Go to the end of the items in the bucket */ this->bucket_list_iter = this->bucket_list->end(); --this->bucket_list_iter; } else { this->bucket_list_iter--; } this->item_next = *this->bucket_list_iter; } int64 Next() { if (this->IsEnd()) return 0; int64 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (this->IsEnd()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } }; /** * Sort by item, ascending. */ class ScriptListSorterItemAscending : public ScriptListSorter { private: ScriptList::ScriptListMap::iterator item_iter; ///< The iterator over the items in the map. public: /** * Create a new sorter. * @param list The list to sort. */ ScriptListSorterItemAscending(ScriptList *list) { this->list = list; this->End(); } int64 Begin() { if (this->list->items.empty()) return 0; this->has_no_more_items = false; this->item_iter = this->list->items.begin(); this->item_next = (*this->item_iter).first; int64 item_current = this->item_next; FindNext(); return item_current; } void End() { this->has_no_more_items = true; } /** * Find the next item, and store that information. */ void FindNext() { if (this->item_iter == this->list->items.end()) { this->has_no_more_items = true; return; } this->item_iter++; if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first; } int64 Next() { if (this->IsEnd()) return 0; int64 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (this->IsEnd()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } }; /** * Sort by item, descending. */ class ScriptListSorterItemDescending : public ScriptListSorter { private: /* Note: We cannot use reverse_iterator. * The iterators must only be invalidated when the element they are pointing to is removed. * This only holds for forward iterators. */ ScriptList::ScriptListMap::iterator item_iter; ///< The iterator over the items in the map. public: /** * Create a new sorter. * @param list The list to sort. */ ScriptListSorterItemDescending(ScriptList *list) { this->list = list; this->End(); } int64 Begin() { if (this->list->items.empty()) return 0; this->has_no_more_items = false; this->item_iter = this->list->items.end(); --this->item_iter; this->item_next = (*this->item_iter).first; int64 item_current = this->item_next; FindNext(); return item_current; } void End() { this->has_no_more_items = true; } /** * Find the next item, and store that information. */ void FindNext() { if (this->item_iter == this->list->items.end()) { this->has_no_more_items = true; return; } if (this->item_iter == this->list->items.begin()) { /* Use 'end' as marker for 'beyond begin' */ this->item_iter = this->list->items.end(); } else { this->item_iter--; } if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first; } int64 Next() { if (this->IsEnd()) return 0; int64 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (this->IsEnd()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } }; ScriptList::ScriptList() { /* Default sorter */ this->sorter = new ScriptListSorterValueDescending(this); this->sorter_type = SORT_BY_VALUE; this->sort_ascending = false; this->initialized = false; this->modifications = 0; } ScriptList::~ScriptList() { delete this->sorter; } bool ScriptList::HasItem(int64 item) { return this->items.count(item) == 1; } void ScriptList::Clear() { this->modifications++; this->items.clear(); this->buckets.clear(); this->sorter->End(); } void ScriptList::AddItem(int64 item, int64 value) { this->modifications++; if (this->HasItem(item)) return; this->items[item] = value; this->buckets[value].insert(item); } void ScriptList::RemoveItem(int64 item) { this->modifications++; ScriptListMap::iterator item_iter = this->items.find(item); if (item_iter == this->items.end()) return; int64 value = item_iter->second; this->sorter->Remove(item); ScriptListBucket::iterator bucket_iter = this->buckets.find(value); assert(bucket_iter != this->buckets.end()); bucket_iter->second.erase(item); if (bucket_iter->second.empty()) this->buckets.erase(bucket_iter); this->items.erase(item_iter); } int64 ScriptList::Begin() { this->initialized = true; return this->sorter->Begin(); } int64 ScriptList::Next() { if (this->initialized == false) { DEBUG(script, 0, "Next() is invalid as Begin() is never called"); return 0; } return this->sorter->Next(); } bool ScriptList::IsEmpty() { return this->items.empty(); } bool ScriptList::IsEnd() { if (this->initialized == false) { DEBUG(script, 0, "IsEnd() is invalid as Begin() is never called"); return true; } return this->sorter->IsEnd(); } int32 ScriptList::Count() { return (int32)this->items.size(); } int64 ScriptList::GetValue(int64 item) { ScriptListMap::const_iterator item_iter = this->items.find(item); return item_iter == this->items.end() ? 0 : item_iter->second; } bool ScriptList::SetValue(int64 item, int64 value) { this->modifications++; ScriptListMap::iterator item_iter = this->items.find(item); if (item_iter == this->items.end()) return false; int64 value_old = item_iter->second; if (value_old == value) return true; this->sorter->Remove(item); ScriptListBucket::iterator bucket_iter = this->buckets.find(value_old); assert(bucket_iter != this->buckets.end()); bucket_iter->second.erase(item); if (bucket_iter->second.empty()) this->buckets.erase(bucket_iter); item_iter->second = value; this->buckets[value].insert(item); return true; } void ScriptList::Sort(SorterType sorter, bool ascending) { this->modifications++; if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return; if (sorter == this->sorter_type && ascending == this->sort_ascending) return; delete this->sorter; switch (sorter) { case SORT_BY_ITEM: if (ascending) { this->sorter = new ScriptListSorterItemAscending(this); } else { this->sorter = new ScriptListSorterItemDescending(this); } break; case SORT_BY_VALUE: if (ascending) { this->sorter = new ScriptListSorterValueAscending(this); } else { this->sorter = new ScriptListSorterValueDescending(this); } break; default: NOT_REACHED(); } this->sorter_type = sorter; this->sort_ascending = ascending; this->initialized = false; } void ScriptList::AddList(ScriptList *list) { if (list == this) return; ScriptListMap *list_items = &list->items; for (ScriptListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) { this->AddItem((*iter).first); this->SetValue((*iter).first, (*iter).second); } } void ScriptList::SwapList(ScriptList *list) { if (list == this) return; this->items.swap(list->items); this->buckets.swap(list->buckets); Swap(this->sorter, list->sorter); Swap(this->sorter_type, list->sorter_type); Swap(this->sort_ascending, list->sort_ascending); Swap(this->initialized, list->initialized); Swap(this->modifications, list->modifications); this->sorter->Retarget(this); list->sorter->Retarget(list); } void ScriptList::RemoveAboveValue(int64 value) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second > value) this->RemoveItem((*iter).first); } } void ScriptList::RemoveBelowValue(int64 value) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second < value) this->RemoveItem((*iter).first); } } void ScriptList::RemoveBetweenValue(int64 start, int64 end) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second > start && (*iter).second < end) this->RemoveItem((*iter).first); } } void ScriptList::RemoveValue(int64 value) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second == value) this->RemoveItem((*iter).first); } } void ScriptList::RemoveTop(int32 count) { this->modifications++; if (!this->sort_ascending) { this->Sort(this->sorter_type, !this->sort_ascending); this->RemoveBottom(count); this->Sort(this->sorter_type, !this->sort_ascending); return; } switch (this->sorter_type) { default: NOT_REACHED(); case SORT_BY_VALUE: for (ScriptListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) { ScriptItemList *items = &(*iter).second; size_t size = items->size(); for (ScriptItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) { if (--count < 0) return; this->RemoveItem(*iter); /* When the last item is removed from the bucket, the bucket itself is removed. * This means that the iterators can be invalid after a call to RemoveItem. */ if (--size == 0) break; } } break; case SORT_BY_ITEM: for (ScriptListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) { if (--count < 0) return; this->RemoveItem((*iter).first); } break; } } void ScriptList::RemoveBottom(int32 count) { this->modifications++; if (!this->sort_ascending) { this->Sort(this->sorter_type, !this->sort_ascending); this->RemoveTop(count); this->Sort(this->sorter_type, !this->sort_ascending); return; } switch (this->sorter_type) { default: NOT_REACHED(); case SORT_BY_VALUE: for (ScriptListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) { ScriptItemList *items = &(*iter).second; size_t size = items->size(); for (ScriptItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) { if (--count < 0) return; this->RemoveItem(*iter); /* When the last item is removed from the bucket, the bucket itself is removed. * This means that the iterators can be invalid after a call to RemoveItem. */ if (--size == 0) break; } } break; case SORT_BY_ITEM: for (ScriptListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) { if (--count < 0) return; this->RemoveItem((*iter).first); } break; } } void ScriptList::RemoveList(ScriptList *list) { this->modifications++; if (list == this) { Clear(); } else { ScriptListMap *list_items = &list->items; for (ScriptListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) { this->RemoveItem((*iter).first); } } } void ScriptList::KeepAboveValue(int64 value) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second <= value) this->RemoveItem((*iter).first); } } void ScriptList::KeepBelowValue(int64 value) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second >= value) this->RemoveItem((*iter).first); } } void ScriptList::KeepBetweenValue(int64 start, int64 end) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second <= start || (*iter).second >= end) this->RemoveItem((*iter).first); } } void ScriptList::KeepValue(int64 value) { this->modifications++; for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second != value) this->RemoveItem((*iter).first); } } void ScriptList::KeepTop(int32 count) { this->modifications++; this->RemoveBottom(this->Count() - count); } void ScriptList::KeepBottom(int32 count) { this->modifications++; this->RemoveTop(this->Count() - count); } void ScriptList::KeepList(ScriptList *list) { if (list == this) return; this->modifications++; ScriptList tmp; tmp.AddList(this); tmp.RemoveList(list); this->RemoveList(&tmp); } SQInteger ScriptList::_get(HSQUIRRELVM vm) { if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR; SQInteger idx; sq_getinteger(vm, 2, &idx); ScriptListMap::const_iterator item_iter = this->items.find(idx); if (item_iter == this->items.end()) return SQ_ERROR; sq_pushinteger(vm, item_iter->second); return 1; } SQInteger ScriptList::_set(HSQUIRRELVM vm) { if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR; if (sq_gettype(vm, 3) != OT_INTEGER && sq_gettype(vm, 3) != OT_NULL) { return sq_throwerror(vm, "you can only assign integers to this list"); } SQInteger idx, val; sq_getinteger(vm, 2, &idx); if (sq_gettype(vm, 3) == OT_NULL) { this->RemoveItem(idx); return 0; } sq_getinteger(vm, 3, &val); if (!this->HasItem(idx)) { this->AddItem(idx, val); return 0; } this->SetValue(idx, val); return 0; } SQInteger ScriptList::_nexti(HSQUIRRELVM vm) { if (sq_gettype(vm, 2) == OT_NULL) { if (this->IsEmpty()) { sq_pushnull(vm); return 1; } sq_pushinteger(vm, this->Begin()); return 1; } SQInteger idx; sq_getinteger(vm, 2, &idx); int val = this->Next(); if (this->IsEnd()) { sq_pushnull(vm); return 1; } sq_pushinteger(vm, val); return 1; } SQInteger ScriptList::Valuate(HSQUIRRELVM vm) { this->modifications++; /* The first parameter is the instance of ScriptList. */ int nparam = sq_gettop(vm) - 1; if (nparam < 1) { return sq_throwerror(vm, "You need to give a least a Valuator as parameter to ScriptList::Valuate"); } /* Make sure the valuator function is really a function, and not any * other type. It's parameter 2 for us, but for the user it's the * first parameter they give. */ SQObjectType valuator_type = sq_gettype(vm, 2); if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) { return sq_throwerror(vm, "parameter 1 has an invalid type (expected function)"); } /* Don't allow docommand from a Valuator, as we can't resume in * mid C++-code. */ bool backup_allow = ScriptObject::GetAllowDoCommand(); ScriptObject::SetAllowDoCommand(false); /* Push the function to call */ sq_push(vm, 2); for (ScriptListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) { /* Check for changing of items. */ int previous_modification_count = this->modifications; /* Push the root table as instance object, this is what squirrel does for meta-functions. */ sq_pushroottable(vm); /* Push all arguments for the valuator function. */ sq_pushinteger(vm, (*iter).first); for (int i = 0; i < nparam - 1; i++) { sq_push(vm, i + 3); } /* Call the function. Squirrel pops all parameters and pushes the return value. */ if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) { ScriptObject::SetAllowDoCommand(backup_allow); return SQ_ERROR; } /* Retrieve the return value */ SQInteger value; switch (sq_gettype(vm, -1)) { case OT_INTEGER: { sq_getinteger(vm, -1, &value); break; } case OT_BOOL: { SQBool v; sq_getbool(vm, -1, &v); value = v ? 1 : 0; break; } default: { /* See below for explanation. The extra pop is the return value. */ sq_pop(vm, nparam + 4); ScriptObject::SetAllowDoCommand(backup_allow); return sq_throwerror(vm, "return value of valuator is not valid (not integer/bool)"); } } /* Was something changed? */ if (previous_modification_count != this->modifications) { /* See below for explanation. The extra pop is the return value. */ sq_pop(vm, nparam + 4); ScriptObject::SetAllowDoCommand(backup_allow); return sq_throwerror(vm, "modifying valuated list outside of valuator function"); } this->SetValue((*iter).first, value); /* Pop the return value. */ sq_poptop(vm); Squirrel::DecreaseOps(vm, 5); } /* Pop from the squirrel stack: * 1. The root stable (as instance object). * 2. The valuator function. * 3. The parameters given to this function. * 4. The ScriptList instance object. */ sq_pop(vm, nparam + 3); ScriptObject::SetAllowDoCommand(backup_allow); return 0; } openttd-1.5.3/src/script/api/script_sign.hpp0000644000000000000000000000634312627373434017615 0ustar rootroot/* $Id: script_sign.hpp 23636 2011-12-19 21:06:06Z truebrain $ */ /* * 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 script_sign.hpp Everything to query and build signs. */ #ifndef SCRIPT_SIGN_HPP #define SCRIPT_SIGN_HPP #include "script_company.hpp" #include "script_error.hpp" /** * Class that handles all sign related functions. * @api ai game */ class ScriptSign : public ScriptObject { public: /** * All sign related error messages. */ enum ErrorMessages { /** Base for sign building related errors */ ERR_SIGN_BASE = ScriptError::ERR_CAT_SIGN << ScriptError::ERR_CAT_BIT_SIZE, /** Too many signs have been placed */ ERR_SIGN_TOO_MANY_SIGNS, // [STR_ERROR_TOO_MANY_SIGNS] }; /** * Checks whether the given sign index is valid. * @param sign_id The index to check. * @return True if and only if the sign is valid. */ static bool IsValidSign(SignID sign_id); /** * Set the name of a sign. * @param sign_id The sign to set the name for. * @param name The name for the sign (can be either a raw string, or a ScriptText object). * @pre IsValidSign(sign_id). * @pre name != NULL && len(name) != 0. * @exception ScriptError::ERR_NAME_IS_NOT_UNIQUE * @return True if and only if the name was changed. */ static bool SetName(SignID sign_id, Text *name); /** * Get the name of the sign. * @param sign_id The sign to get the name of. * @pre IsValidSign(sign_id). * @return The name of the sign. */ static char *GetName(SignID sign_id); /** * Get the owner of a sign. * @param sign_id The sign to get the owner of. * @pre IsValidSign(sign_id). * @return The owner the sign has. * @api -ai */ static ScriptCompany::CompanyID GetOwner(SignID sign_id); /** * Gets the location of the sign. * @param sign_id The sign to get the location of. * @pre IsValidSign(sign_id). * @return The location of the sign. */ static TileIndex GetLocation(SignID sign_id); /** * Builds a sign on the map. * @param location The place to build the sign. * @param name The text to place on the sign (can be either a raw string, or a ScriptText object). * @pre ScriptMap::IsValidTile(location). * @pre name != NULL && len(name) != 0. * @exception ScriptSign::ERR_SIGN_TOO_MANY_SIGNS * @return The SignID of the build sign (use IsValidSign() to check for validity). * In test-mode it returns 0 if successful, or any other value to indicate * failure. */ static SignID BuildSign(TileIndex location, Text *name); /** * Removes a sign from the map. * @param sign_id The sign to remove. * @pre IsValidSign(sign_id). * @return True if and only if the sign has been removed. */ static bool RemoveSign(SignID sign_id); }; #endif /* SCRIPT_SIGN_HPP */ openttd-1.5.3/src/script/api/script_tile.hpp0000644000000000000000000005135412627373434017614 0ustar rootroot/* $Id: script_tile.hpp 25213 2013-04-30 17:16:32Z rubidium $ */ /* * 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 script_tile.hpp Everything to query and manipulate tiles. */ #ifndef SCRIPT_TILE_HPP #define SCRIPT_TILE_HPP #include "script_error.hpp" #include "script_company.hpp" #include "../../slope_type.h" #include "../../transport_type.h" /** * Class that handles all tile related functions. * @api ai game */ class ScriptTile : public ScriptObject { public: /** * Error messages related to modifying tiles. */ enum ErrorMessages { /** Base for tile related errors */ ERR_TILE_BASE = ScriptError::ERR_CAT_TILE << ScriptError::ERR_CAT_BIT_SIZE, /** Tile can't be raised any higher */ ERR_TILE_TOO_HIGH, // [STR_ERROR_ALREADY_AT_SEA_LEVEL] /** Tile can't be lowered any lower */ ERR_TILE_TOO_LOW, // [STR_ERROR_ALREADY_AT_SEA_LEVEL] /** The area was already flat */ ERR_AREA_ALREADY_FLAT, // [STR_ERROR_ALREADY_LEVELLED] /** There is a tunnel underneed */ ERR_EXCAVATION_WOULD_DAMAGE, // [STR_ERROR_EXCAVATION_WOULD_DAMAGE] }; /** * Enumeration for corners of tiles. */ enum Corner { /* Note: these values represent part of the in-game Corner enum */ CORNER_W = ::CORNER_W, ///< West corner CORNER_S = ::CORNER_S, ///< South corner CORNER_E = ::CORNER_E, ///< East corner CORNER_N = ::CORNER_N, ///< North corner CORNER_INVALID = ::CORNER_INVALID, ///< An invalid corner }; /** * Enumeration for the slope-type. * * This enumeration use the chars N, E, S, W corresponding the * direction North, East, South and West. The top corner of a tile * is the north-part of the tile. */ enum Slope { /* Note: these values represent part of the in-game Slope enum */ SLOPE_FLAT = ::SLOPE_FLAT, ///< A flat tile SLOPE_W = ::SLOPE_W, ///< The west corner of the tile is raised SLOPE_S = ::SLOPE_S, ///< The south corner of the tile is raised SLOPE_E = ::SLOPE_E, ///< The east corner of the tile is raised SLOPE_N = ::SLOPE_N, ///< The north corner of the tile is raised SLOPE_STEEP = ::SLOPE_STEEP, ///< Indicates the slope is steep (The corner opposite of the not-raised corner is raised two times) SLOPE_NW = ::SLOPE_NW, ///< North and west corner are raised SLOPE_SW = ::SLOPE_SW, ///< South and west corner are raised SLOPE_SE = ::SLOPE_SE, ///< South and east corner are raised SLOPE_NE = ::SLOPE_NE, ///< North and east corner are raised SLOPE_EW = ::SLOPE_EW, ///< East and west corner are raised SLOPE_NS = ::SLOPE_NS, ///< North and south corner are raised SLOPE_ELEVATED = ::SLOPE_ELEVATED, ///< Bit mask containing all 'simple' slopes. Does not appear as a slope. SLOPE_NWS = ::SLOPE_NWS, ///< North, west and south corner are raised SLOPE_WSE = ::SLOPE_WSE, ///< West, south and east corner are raised SLOPE_SEN = ::SLOPE_SEN, ///< South, east and north corner are raised SLOPE_ENW = ::SLOPE_ENW, ///< East, north and west corner are raised SLOPE_STEEP_W = ::SLOPE_STEEP_W, ///< A steep slope falling to east (from west) SLOPE_STEEP_S = ::SLOPE_STEEP_S, ///< A steep slope falling to north (from south) SLOPE_STEEP_E = ::SLOPE_STEEP_E, ///< A steep slope falling to west (from east) SLOPE_STEEP_N = ::SLOPE_STEEP_N, ///< A steep slope falling to south (from north) /* Custom added value, only valid for this API */ SLOPE_INVALID = 0xFFFF, ///< An invalid slope }; /** * The different transport types a tile can have. */ enum TransportType { /* Note: these values represent part of the in-game TransportType enum */ TRANSPORT_RAIL = ::TRANSPORT_RAIL, ///< Tile with rail. TRANSPORT_ROAD = ::TRANSPORT_ROAD, ///< Tile with road. TRANSPORT_WATER = ::TRANSPORT_WATER, ///< Tile with navigable waterways. TRANSPORT_AIR = ::TRANSPORT_AIR, ///< Tile with airport. /* Custom added value, only valid for this API */ TRANSPORT_INVALID = -1, ///< Tile without any transport type. }; /** * Get the base cost for building/clearing several things. */ enum BuildType { BT_FOUNDATION, ///< Build a foundation under something BT_TERRAFORM, ///< Terraform BT_BUILD_TREES, ///< Build trees BT_CLEAR_GRASS, ///< Clear a tile with just grass BT_CLEAR_ROUGH, ///< Clear a rough tile BT_CLEAR_ROCKY, ///< Clear a tile with rocks BT_CLEAR_FIELDS, ///< Clear a tile with farm fields BT_CLEAR_HOUSE, ///< Clear a tile with a house }; /** * The types of terrain a tile can have. * * @note When a desert or rainforest tile are changed, their terrain type will remain the same. In other words, a sea tile can be of the desert terrain type. * @note The snow terrain type can change to the normal terrain type and vice versa based on landscaping or variable snow lines from NewGRFs. */ enum TerrainType { TERRAIN_NORMAL, ///< A normal tile (default); not desert, rainforest or snow. TERRAIN_DESERT, ///< A tile in the desert (manually set in in scenarios, below certain height and certain distance from water in random games). TERRAIN_RAINFOREST, ///< A tile in the rainforest (manually set in scenarios, certain distance away from deserts in random games), TERRAIN_SNOW ///< A tile on or above the snowline level. }; /** * Check if this tile is buildable, i.e. no things on it that needs * demolishing. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if it is buildable, false if not. * @note For trams you also might want to check for ScriptRoad::IsRoad(), * as you can build tram-rails on road-tiles. * @note For rail you also might want to check for ScriptRoad::IsRoad(), * as in some cases you can build rails on road-tiles. */ static bool IsBuildable(TileIndex tile); /** * Check if this tile is buildable in a rectangle around a tile, with the * entry in the list as top-left. * @param tile The tile to check on. * @param width The width of the rectangle. * @param height The height of the rectangle. * @pre ScriptMap::IsValidTile(tile). * @return True if it is buildable, false if not. */ static bool IsBuildableRectangle(TileIndex tile, uint width, uint height); /** * Checks whether the given tile is actually a water tile. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is a water tile. */ static bool IsWaterTile(TileIndex tile); /** * Checks whether the given tile is actually a coast tile. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is a coast tile. * @note Building on coast tiles in general is more expensive. This is not * true if there are also trees on the tile, see #HasTreeOnTile. */ static bool IsCoastTile(TileIndex tile); /** * Checks whether the given tile is a station tile of any station. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is a station tile. */ static bool IsStationTile(TileIndex tile); /** * Check if a tile has a steep slope. * Steep slopes are slopes with a height difference of 2 across one diagonal of the tile. * @param slope The slope to check on. * @pre slope != SLOPE_INVALID. * @return True if the slope is a steep slope. */ static bool IsSteepSlope(Slope slope); /** * Check if a tile has a halftile slope. * Halftile slopes appear on top of halftile foundations. E.g. the slope you get when building a horizontal railtrack on the top of a SLOPE_N or SLOPE_STEEP_N. * @param slope The slope to check on. * @pre slope != SLOPE_INVALID. * @return True if the slope is a halftile slope. * @note Currently there is no API function that would return or accept a halftile slope. */ static bool IsHalftileSlope(Slope slope); /** * Check if the tile has any tree on it. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if there is a tree on the tile. */ static bool HasTreeOnTile(TileIndex tile); /** * Check if the tile is a farmland tile. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is farmland. */ static bool IsFarmTile(TileIndex tile); /** * Check if the tile is a rock tile. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is rock tile. */ static bool IsRockTile(TileIndex tile); /** * Check if the tile is a rough tile. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is rough tile. */ static bool IsRoughTile(TileIndex tile); /** * Check if the tile without buildings or infrastructure is a snow tile. * @note If you want to know if a tile (with or without buildings and infrastructure) is on or above the snowline, use ScriptTile::GetTerrainType(tile). * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is snow tile. */ static bool IsSnowTile(TileIndex tile); /** * Check if the tile without buildings or infrastructure is a desert tile. * @note If you want to know if a tile (with or without buildings and infrastructure) is in a desert, use ScriptTile::GetTerrainType(tile). * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile is desert tile. */ static bool IsDesertTile(TileIndex tile); /** * Get the type of terrain regardless of buildings or infrastructure. * @note When a desert or rainforest tile are changed, their terrain type will remain the same. In other words, a sea tile can be of the desert terrain type. * @note The snow terrain type can change to the normal terrain type and vice versa based on landscaping or variable snow lines from NewGRFs. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return The #TerrainType. */ static TerrainType GetTerrainType(TileIndex tile); /** * Get the slope of a tile. * This is the slope of the bare tile. A possible foundation on the tile does not influence this slope. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @return Bit mask encoding the slope. See #Slope for a description of the returned values. */ static Slope GetSlope(TileIndex tile); /** * Get the complement of the slope. * @param slope The slope to get the complement of. * @pre slope != SLOPE_INVALID. * @pre !IsSteepSlope(slope). * @pre !IsHalftileSlope(slope). * @return The complement of a slope. This means that all corners that * weren't raised, are raised, and visa versa. */ static Slope GetComplementSlope(Slope slope); /** * Get the minimal height on a tile. * 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 ScriptMap::IsValidTile(tile). * @return The height of the lowest corner of the tile, ranging from 0 to 15. */ static int32 GetMinHeight(TileIndex tile); /** * Get the maximal height on a tile. * 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 ScriptMap::IsValidTile(tile). * @return The height of the highest corner of the tile, ranging from 0 to 15. */ static int32 GetMaxHeight(TileIndex tile); /** * Get the height of a certain corner of a tile. * 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. * @param corner The corner to query. * @pre ScriptMap::IsValidTile(tile). * @return The height of the lowest corner of the tile, ranging from 0 to 15. */ static int32 GetCornerHeight(TileIndex tile, Corner corner); /** * Get the owner of the tile. * @param tile The tile to get the owner from. * @pre ScriptMap::IsValidTile(tile). * @return The CompanyID of the owner of the tile, or COMPANY_INVALID if * there is no owner (grass/industry/water tiles, etc.). */ static ScriptCompany::CompanyID GetOwner(TileIndex tile); /** * Checks whether the given tile contains parts suitable for the given * TransportType. * @param tile The tile to check. * @param transport_type The TransportType to check against. * @pre ScriptMap::IsValidTile(tile). * @pre transport_type != TRANSPORT_AIR. * @note Returns false on tiles with roadworks and on road tiles with only * a single piece of road as these tiles cannot be used to transport * anything on. It furthermore returns true on some coast tile for * TRANSPORT_WATER because ships can navigate over them. * @note Use ScriptAirport.IsAirportTile to check for airport tiles. Aircraft * can fly over every tile on the map so using HasTransportType * doesn't make sense for TRANSPORT_AIR. * @return True if and only if the tile has the given TransportType. */ static bool HasTransportType(TileIndex tile, TransportType transport_type); /** * Check how much cargo this tile accepts. * It creates a radius around the tile, and adds up all acceptance of this * cargo. * @param tile The tile to check on. * @param cargo_type The cargo to check the acceptance of. * @param width The width of the station. * @param height The height of the station. * @param radius The radius of the station. * @pre ScriptMap::IsValidTile(tile). * @pre ScriptCargo::IsValidCargo(cargo_type) * @pre width > 0. * @pre height > 0. * @pre radius >= 0. * @return Value below 8 means no acceptance; the more the better. */ static int32 GetCargoAcceptance(TileIndex tile, CargoID cargo_type, int width, int height, int radius); /** * Checks how many producers in the radius produces this cargo. * It creates a radius around the tile, and counts all producer of this cargo. * @param tile The tile to check on. * @param cargo_type The cargo to check the production of. * @param width The width of the station. * @param height The height of the station. * @param radius The radius of the station. * @pre ScriptMap::IsValidTile(tile). * @pre ScriptCargo::IsValidCargo(cargo_type) * @pre width > 0. * @pre height > 0. * @pre radius >= 0. * @return The number of producers that produce this cargo within radius of the tile. */ static int32 GetCargoProduction(TileIndex tile, CargoID cargo_type, int width, int height, int radius); /** * Get the manhattan distance from the tile to the tile. * @param tile_from The tile to get the distance to. * @param tile_to The tile to get the distance to. * @return The distance between the two tiles. */ static int32 GetDistanceManhattanToTile(TileIndex tile_from, TileIndex tile_to); /** * Get the square distance from the tile to the tile. * @param tile_from The tile to get the distance to. * @param tile_to The tile to get the distance to. * @return The distance between the two tiles. */ static int32 GetDistanceSquareToTile(TileIndex tile_from, TileIndex tile_to); /** * Raise the given corners of the tile. The corners can be combined, * for example: SLOPE_N | SLOPE_W (= SLOPE_NW) will raise the west and the north corner. * @note The corners will be modified in the order west (first), south, east, north (last). * Changing one corner might cause another corner to be changed too. So modifiing * multiple corners may result in changing some corners by multiple steps. * @param tile The tile to raise. * @param slope Corners to raise (SLOPE_xxx). * @pre tile < ScriptMap::GetMapSize(). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_TOO_CLOSE_TO_EDGE * @exception ScriptTile::ERR_TILE_TOO_HIGH * @return 0 means failed, 1 means success. */ static bool RaiseTile(TileIndex tile, int32 slope); /** * Lower the given corners of the tile. The corners can be combined, * for example: SLOPE_N | SLOPE_W (= SLOPE_NW) will lower the west and the north corner. * @note The corners will be modified in the order west (first), south, east, north (last). * Changing one corner might cause another corner to be changed too. So modifiing * multiple corners may result in changing some corners by multiple steps. * @param tile The tile to lower. * @param slope Corners to lower (SLOPE_xxx). * @pre tile < ScriptMap::GetMapSize(). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_TOO_CLOSE_TO_EDGE * @exception ScriptTile::ERR_TILE_TOO_LOW * @return 0 means failed, 1 means success. */ static bool LowerTile(TileIndex tile, int32 slope); /** * Level all tiles in the rectangle between start_tile and end_tile so they * are at the same height. All tiles will be raised or lowered until * they are at height ScriptTile::GetCornerHeight(start_tile, ScriptTile::CORNER_N). * @param start_tile One corner of the rectangle to level. * @param end_tile The opposite corner of the rectangle. * @pre start_tile < ScriptMap::GetMapSize(). * @pre end_tile < ScriptMap::GetMapSize(). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_TOO_CLOSE_TO_EDGE * @return True if one or more tiles were leveled. * @note Even if leveling some part fails, some other part may have been * successfully leveled already. * @note This function may return true in ScriptTestMode, although it fails in * ScriptExecMode. */ static bool LevelTiles(TileIndex start_tile, TileIndex end_tile); /** * Destroy everything on the given tile. * @param tile The tile to demolish. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @return True if and only if the tile was demolished. */ static bool DemolishTile(TileIndex tile); /** * Create a random tree on a tile. * @param tile The tile to build a tree on. * @pre ScriptMap::IsValidTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @return True if and only if a tree was added on the tile. */ static bool PlantTree(TileIndex tile); /** * Create a random tree on a rectangle of tiles. * @param tile The top left tile of the rectangle. * @param width The width of the rectangle. * @param height The height of the rectangle. * @pre ScriptMap::IsValidTile(tile). * @pre width >= 1 && width <= 20. * @pre height >= 1 && height <= 20. * @game @pre Valid ScriptCompanyMode active in scope. * @return True if and only if a tree was added on any of the tiles in the rectangle. */ static bool PlantTreeRectangle(TileIndex tile, uint width, uint height); /** * Find out if this tile is within the rating influence of a town. * If a station sign would be on this tile, the servicing quality of the station would * influence the rating of the town. * @param tile The tile to check. * @param town_id The town to check. * @return True if the tile is within the rating influence of the town. */ static bool IsWithinTownInfluence(TileIndex tile, TownID town_id); /** * Find the town which has authority for the tile. * The rating of your company in this town will be checked and affected when * building stations, trees etc. * @param tile The tile to check. * @return The TownID of the town which has authority on this tile. */ static TownID GetTownAuthority(TileIndex tile); /** * Find the town that is closest to a tile. Stations you build at this tile * will belong to this town. * @param tile The tile to check. * @return The TownID of the town closest to the tile. */ static TownID GetClosestTown(TileIndex tile); /** * Get the baseprice of building/clearing various tile-related things. * @param build_type the type to build * @return The baseprice of building or removing the given object. */ static Money GetBuildCost(BuildType build_type); }; #endif /* SCRIPT_TILE_HPP */ openttd-1.5.3/src/script/api/script_controller.cpp0000644000000000000000000001352512627373434021033 0ustar rootroot/* $Id: script_controller.cpp 26774 2014-09-06 17:46:56Z rubidium $ */ /* * 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 script_controller.cpp Implementation of ScriptControler. */ #include "../../stdafx.h" #include "../../string_func.h" #include "../../script/squirrel.hpp" #include "../../rev.h" #include "script_controller.hpp" #include "script_error.hpp" #include "../script_fatalerror.hpp" #include "../script_info.hpp" #include "../script_instance.hpp" #include "script_log.hpp" #include "../../ai/ai_gui.hpp" #include "../../settings_type.h" #include "../../network/network.h" #include "../../safeguards.h" /* static */ void ScriptController::SetCommandDelay(int ticks) { if (ticks <= 0) return; ScriptObject::SetDoCommandDelay(ticks); } /* static */ void ScriptController::Sleep(int ticks) { if (!ScriptObject::CanSuspend()) { throw Script_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator."); } if (ticks <= 0) { ScriptLog::Warning("Sleep() value should be > 0. Assuming value 1."); ticks = 1; } throw Script_Suspend(ticks, NULL); } /* static */ void ScriptController::Break(const char* message) { if (_network_dedicated || !_settings_client.gui.ai_developer_tools) return; ScriptObject::GetActiveInstance()->Pause(); char log_message[1024]; seprintf(log_message, lastof(log_message), "Break: %s", message); ScriptLog::Log(ScriptLog::LOG_SQ_ERROR, log_message); /* Inform script developer that his script has been paused and * needs manual action to continue. */ ShowAIDebugWindow(ScriptObject::GetRootCompany()); if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) { ScriptObject::DoCommand(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); } } /* static */ void ScriptController::Print(bool error_msg, const char *message) { ScriptLog::Log(error_msg ? ScriptLog::LOG_SQ_ERROR : ScriptLog::LOG_SQ_INFO, message); } ScriptController::ScriptController(CompanyID company) : ticks(0), loaded_library_count(0) { ScriptObject::SetCompany(company); } ScriptController::~ScriptController() { for (LoadedLibraryList::iterator iter = this->loaded_library.begin(); iter != this->loaded_library.end(); iter++) { free((*iter).second); free((*iter).first); } this->loaded_library.clear(); } /* static */ uint ScriptController::GetTick() { return ScriptObject::GetActiveInstance()->GetController()->ticks; } /* static */ int ScriptController::GetOpsTillSuspend() { return ScriptObject::GetActiveInstance()->GetOpsTillSuspend(); } /* static */ int ScriptController::GetSetting(const char *name) { return ScriptObject::GetActiveInstance()->GetSetting(name); } /* static */ uint ScriptController::GetVersion() { return _openttd_newgrf_version; } /* static */ HSQOBJECT ScriptController::Import(const char *library, const char *class_name, int version) { ScriptController *controller = ScriptObject::GetActiveInstance()->GetController(); Squirrel *engine = ScriptObject::GetActiveInstance()->engine; HSQUIRRELVM vm = engine->GetVM(); /* Internally we store libraries as 'library.version' */ char library_name[1024]; seprintf(library_name, lastof(library_name), "%s.%d", library, version); strtolower(library_name); ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version); if (lib == NULL) { char error[1024]; seprintf(error, lastof(error), "couldn't find library '%s' with version %d", library, version); throw sq_throwerror(vm, error); } /* Get the current table/class we belong to */ HSQOBJECT parent; sq_getstackobj(vm, 1, &parent); char fake_class[1024]; LoadedLibraryList::iterator iter = controller->loaded_library.find(library_name); if (iter != controller->loaded_library.end()) { strecpy(fake_class, (*iter).second, lastof(fake_class)); } else { int next_number = ++controller->loaded_library_count; /* Create a new fake internal name */ seprintf(fake_class, lastof(fake_class), "_internalNA%d", next_number); /* Load the library in a 'fake' namespace, so we can link it to the name the user requested */ sq_pushroottable(vm); sq_pushstring(vm, fake_class, -1); sq_newclass(vm, SQFalse); /* Load the library */ if (!engine->LoadScript(vm, lib->GetMainScript(), false)) { char error[1024]; seprintf(error, lastof(error), "there was a compile error when importing '%s' version %d", library, version); throw sq_throwerror(vm, error); } /* Create the fake class */ sq_newslot(vm, -3, SQFalse); sq_pop(vm, 1); controller->loaded_library[stredup(library_name)] = stredup(fake_class); } /* Find the real class inside the fake class (like 'sets.Vector') */ sq_pushroottable(vm); sq_pushstring(vm, fake_class, -1); if (SQ_FAILED(sq_get(vm, -2))) { throw sq_throwerror(vm, "internal error assigning library class"); } sq_pushstring(vm, lib->GetInstanceName(), -1); if (SQ_FAILED(sq_get(vm, -2))) { char error[1024]; seprintf(error, lastof(error), "unable to find class '%s' in the library '%s' version %d", lib->GetInstanceName(), library, version); throw sq_throwerror(vm, error); } HSQOBJECT obj; sq_getstackobj(vm, -1, &obj); sq_pop(vm, 3); if (StrEmpty(class_name)) return obj; /* Now link the name the user wanted to our 'fake' class */ sq_pushobject(vm, parent); sq_pushstring(vm, class_name, -1); sq_pushobject(vm, obj); sq_newclass(vm, SQTrue); sq_newslot(vm, -3, SQFalse); sq_pop(vm, 1); return obj; } openttd-1.5.3/src/script/api/script_storypageelementlist.hpp0000644000000000000000000000243112627373434023132 0ustar rootroot/* $Id: script_storypageelementlist.hpp 26305 2014-02-06 19:41:56Z zuu $ */ /* * 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 script_storypageelementlist.hpp List all story page elements. */ #ifndef SCRIPT_STORYPAGEELEMENTLIST_HPP #define SCRIPT_STORYPAGEELEMENTLIST_HPP #include "script_list.hpp" #include "script_company.hpp" #include "script_story_page.hpp" /** * Create a list of all story page elements. * @api game * @ingroup ScriptList */ class ScriptStoryPageElementList : public ScriptList { public: /** * @param story_page_id The page id of the story page of which all page elements should be included in the list. */ ScriptStoryPageElementList(ScriptStoryPage::StoryPageID story_page_id); }; #endif /* SCRIPT_STORYPAGEELEMENTLIST_HPP */ openttd-1.5.3/src/script/api/script_subsidy.hpp0000644000000000000000000001227712627373434020342 0ustar rootroot/* $Id: script_subsidy.hpp 26307 2014-02-06 19:50:34Z zuu $ */ /* * 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 script_subsidy.hpp Everything to query subsidies. */ #ifndef SCRIPT_SUBSIDY_HPP #define SCRIPT_SUBSIDY_HPP #include "script_company.hpp" #include "script_date.hpp" /** * Class that handles all subsidy related functions. * @api ai game */ class ScriptSubsidy : public ScriptObject { public: /** * Enumeration for source and destination of a subsidy. * @note The list of values may grow in future. */ enum SubsidyParticipantType { /* Values are important, as they represent the internal state of the game. * It is originally named SourceType. ST_HEADQUARTERS is intentionally * left out, as it cannot be used for Subsidies. */ SPT_INDUSTRY = 0, ///< Subsidy participant is an industry SPT_TOWN = 1, ///< Subsidy participant is a town SPT_INVALID = 0xFF, ///< Invalid/unknown participant type }; /** * Check whether this is a valid SubsidyID. * @param subsidy_id The SubsidyID to check. * @return True if and only if this subsidy is still valid. */ static bool IsValidSubsidy(SubsidyID subsidy_id); /** * Checks whether this subsidy is already awarded to some company. * @param subsidy_id The SubsidyID to check. * @pre IsValidSubsidy(subsidy). * @return True if and only if this subsidy is already awarded. */ static bool IsAwarded(SubsidyID subsidy_id); /** * Create a new subsidy. * @param cargo_type The type of cargo to cary for the subsidy. * @param from_type The type of the subsidy on the 'from' side. * @param from_id The ID of the 'from' side. * @param to_type The type of the subsidy on the 'to' side. * @param to_id The ID of the 'to' side. * @return True if the action succeeded. * @pre ScriptCargo::IsValidCargo(cargo_type) * @pre from_type == SPT_INDUSTRY || from_type == SPT_TOWN. * @pre to_type == SPT_INDUSTRY || to_type == SPT_TOWN. * @pre (from_type == SPT_INDUSTRY && ScriptIndustry::IsValidIndustry(from_id)) || (from_type == SPT_TOWN && ScriptTown::IsValidTown(from_id)) * @pre (to_type == SPT_INDUSTRY && ScriptIndustry::IsValidIndustry(to_id)) || (to_type == SPT_TOWN && ScriptTown::IsValidTown(to_id)) * @api -ai */ static bool Create(CargoID cargo_type, SubsidyParticipantType from_type, uint16 from_id, SubsidyParticipantType to_type, uint16 to_id); /** * Get the company index of the company this subsidy is awarded to. * @param subsidy_id The SubsidyID to check. * @pre IsAwarded(subsidy_id). * @return The companyindex of the company this subsidy is awarded to. */ static ScriptCompany::CompanyID GetAwardedTo(SubsidyID subsidy_id); /** * Get the date this subsidy expires. In case the subsidy is already * awarded, return the date the subsidy expires, else, return the date the * offer expires. * @param subsidy_id The SubsidyID to check. * @pre IsValidSubsidy(subsidy_id). * @return The last valid date of this subsidy. * @note The return value of this function will change if the subsidy is * awarded. */ static ScriptDate::Date GetExpireDate(SubsidyID subsidy_id); /** * Get the cargo type that has to be transported in order to be awarded this * subsidy. * @param subsidy_id The SubsidyID to check. * @pre IsValidSubsidy(subsidy_id). * @return The cargo type to transport. */ static CargoID GetCargoType(SubsidyID subsidy_id); /** * Returns the type of source of subsidy. * @param subsidy_id The SubsidyID to check. * @pre IsValidSubsidy(subsidy_id). * @return Type of source of subsidy. */ static SubsidyParticipantType GetSourceType(SubsidyID subsidy_id); /** * Return the source IndustryID/TownID the subsidy is for. * \li GetSourceType(subsidy_id) == SPT_INDUSTRY -> return the IndustryID. * \li GetSourceType(subsidy_id) == SPT_TOWN -> return the TownID. * @param subsidy_id The SubsidyID to check. * @pre IsValidSubsidy(subsidy_id). * @return One of TownID/IndustryID. */ static int32 GetSourceIndex(SubsidyID subsidy_id); /** * Returns the type of destination of subsidy. * @param subsidy_id The SubsidyID to check. * @pre IsValidSubsidy(subsidy_id). * @return Type of destination of subsidy. */ static SubsidyParticipantType GetDestinationType(SubsidyID subsidy_id); /** * Return the destination IndustryID/TownID the subsidy is for. * \li GetDestinationType(subsidy_id) == SPT_INDUSTRY -> return the IndustryID. * \li GetDestinationType(subsidy_id) == SPT_TOWN -> return the TownID. * @param subsidy_id the SubsidyID to check. * @pre IsValidSubsidy(subsidy_id). * @return One of TownID/IndustryID. */ static int32 GetDestinationIndex(SubsidyID subsidy_id); }; #endif /* SCRIPT_SUBSIDY_HPP */ openttd-1.5.3/src/script/api/script_engine.cpp0000644000000000000000000002154712627373434020120 0ustar rootroot/* $Id: script_engine.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_engine.cpp Implementation of ScriptEngine. */ #include "../../stdafx.h" #include "script_engine.hpp" #include "script_cargo.hpp" #include "../../company_base.h" #include "../../strings_func.h" #include "../../rail.h" #include "../../engine_base.h" #include "../../engine_func.h" #include "../../articulated_vehicles.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ bool ScriptEngine::IsValidEngine(EngineID engine_id) { const Engine *e = ::Engine::GetIfValid(engine_id); if (e == NULL || !e->IsEnabled()) return false; /* AIs have only access to engines they can purchase or still have in use. * Deity has access to all engined that will be or were available ever. */ CompanyID company = ScriptObject::GetCompany(); return company == OWNER_DEITY || ::IsEngineBuildable(engine_id, e->type, company) || ::Company::Get(company)->group_all[e->type].num_engines[engine_id] > 0; } /* static */ bool ScriptEngine::IsBuildable(EngineID engine_id) { const Engine *e = ::Engine::GetIfValid(engine_id); return e != NULL && ::IsEngineBuildable(engine_id, e->type, ScriptObject::GetCompany()); } /* static */ char *ScriptEngine::GetName(EngineID engine_id) { if (!IsValidEngine(engine_id)) return NULL; ::SetDParam(0, engine_id); return GetString(STR_ENGINE_NAME); } /* static */ CargoID ScriptEngine::GetCargoType(EngineID engine_id) { if (!IsValidEngine(engine_id)) return CT_INVALID; CargoArray cap = ::GetCapacityOfArticulatedParts(engine_id); CargoID most_cargo = CT_INVALID; uint amount = 0; for (CargoID cid = 0; cid < NUM_CARGO; cid++) { if (cap[cid] > amount) { amount = cap[cid]; most_cargo = cid; } } return most_cargo; } /* static */ bool ScriptEngine::CanRefitCargo(EngineID engine_id, CargoID cargo_id) { if (!IsValidEngine(engine_id)) return false; if (!ScriptCargo::IsValidCargo(cargo_id)) return false; return HasBit(::GetUnionOfArticulatedRefitMasks(engine_id, true), cargo_id); } /* static */ bool ScriptEngine::CanPullCargo(EngineID engine_id, CargoID cargo_id) { if (!IsValidEngine(engine_id)) return false; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false; if (!ScriptCargo::IsValidCargo(cargo_id)) return false; return (::RailVehInfo(engine_id)->ai_passenger_only != 1) || ScriptCargo::HasCargoClass(cargo_id, ScriptCargo::CC_PASSENGERS); } /* static */ int32 ScriptEngine::GetCapacity(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; const Engine *e = ::Engine::Get(engine_id); switch (e->type) { case VEH_ROAD: case VEH_TRAIN: { CargoArray capacities = GetCapacityOfArticulatedParts(engine_id); for (CargoID c = 0; c < NUM_CARGO; c++) { if (capacities[c] == 0) continue; return capacities[c]; } return -1; } case VEH_SHIP: case VEH_AIRCRAFT: return e->GetDisplayDefaultCapacity(); default: NOT_REACHED(); } } /* static */ int32 ScriptEngine::GetReliability(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1; return ::ToPercent16(::Engine::Get(engine_id)->reliability); } /* static */ int32 ScriptEngine::GetMaxSpeed(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; const Engine *e = ::Engine::Get(engine_id); int32 max_speed = e->GetDisplayMaxSpeed(); // km-ish/h if (e->type == VEH_AIRCRAFT) max_speed /= _settings_game.vehicle.plane_speed; return max_speed; } /* static */ Money ScriptEngine::GetPrice(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; return ::Engine::Get(engine_id)->GetCost(); } /* static */ int32 ScriptEngine::GetMaxAge(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; if (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL && IsWagon(engine_id)) return -1; return ::Engine::Get(engine_id)->GetLifeLengthInDays(); } /* static */ Money ScriptEngine::GetRunningCost(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; return ::Engine::Get(engine_id)->GetRunningCost(); } /* static */ int32 ScriptEngine::GetPower(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1; if (IsWagon(engine_id)) return -1; return ::Engine::Get(engine_id)->GetPower(); } /* static */ int32 ScriptEngine::GetWeight(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1; return ::Engine::Get(engine_id)->GetDisplayWeight(); } /* static */ int32 ScriptEngine::GetMaxTractiveEffort(EngineID engine_id) { if (!IsValidEngine(engine_id)) return -1; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL && GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return -1; if (IsWagon(engine_id)) return -1; return ::Engine::Get(engine_id)->GetDisplayMaxTractiveEffort(); } /* static */ ScriptDate::Date ScriptEngine::GetDesignDate(EngineID engine_id) { if (!IsValidEngine(engine_id)) return ScriptDate::DATE_INVALID; return (ScriptDate::Date)::Engine::Get(engine_id)->intro_date; } /* static */ ScriptVehicle::VehicleType ScriptEngine::GetVehicleType(EngineID engine_id) { if (!IsValidEngine(engine_id)) return ScriptVehicle::VT_INVALID; switch (::Engine::Get(engine_id)->type) { case VEH_ROAD: return ScriptVehicle::VT_ROAD; case VEH_TRAIN: return ScriptVehicle::VT_RAIL; case VEH_SHIP: return ScriptVehicle::VT_WATER; case VEH_AIRCRAFT: return ScriptVehicle::VT_AIR; default: NOT_REACHED(); } } /* static */ bool ScriptEngine::IsWagon(EngineID engine_id) { if (!IsValidEngine(engine_id)) return false; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false; return ::RailVehInfo(engine_id)->power == 0; } /* static */ bool ScriptEngine::CanRunOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type) { if (!IsValidEngine(engine_id)) return false; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false; if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false; return ::IsCompatibleRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type); } /* static */ bool ScriptEngine::HasPowerOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type) { if (!IsValidEngine(engine_id)) return false; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false; if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false; return ::HasPowerOnRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type); } /* static */ ScriptRoad::RoadType ScriptEngine::GetRoadType(EngineID engine_id) { if (!IsValidEngine(engine_id)) return ScriptRoad::ROADTYPE_INVALID; if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD) return ScriptRoad::ROADTYPE_INVALID; return HasBit(::EngInfo(engine_id)->misc_flags, EF_ROAD_TRAM) ? ScriptRoad::ROADTYPE_TRAM : ScriptRoad::ROADTYPE_ROAD; } /* static */ ScriptRail::RailType ScriptEngine::GetRailType(EngineID engine_id) { if (!IsValidEngine(engine_id)) return ScriptRail::RAILTYPE_INVALID; if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return ScriptRail::RAILTYPE_INVALID; return (ScriptRail::RailType)(uint)::RailVehInfo(engine_id)->railtype; } /* static */ bool ScriptEngine::IsArticulated(EngineID engine_id) { if (!IsValidEngine(engine_id)) return false; if (GetVehicleType(engine_id) != ScriptVehicle::VT_ROAD && GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false; return IsArticulatedEngine(engine_id); } /* static */ ScriptAirport::PlaneType ScriptEngine::GetPlaneType(EngineID engine_id) { if (!IsValidEngine(engine_id)) return ScriptAirport::PT_INVALID; if (GetVehicleType(engine_id) != ScriptVehicle::VT_AIR) return ScriptAirport::PT_INVALID; return (ScriptAirport::PlaneType)::AircraftVehInfo(engine_id)->subtype; } /* static */ uint ScriptEngine::GetMaximumOrderDistance(EngineID engine_id) { if (!IsValidEngine(engine_id)) return 0; switch (GetVehicleType(engine_id)) { case ScriptVehicle::VT_WATER: return _settings_game.pf.pathfinder_for_ships != VPF_NPF ? 129 : 0; case ScriptVehicle::VT_AIR: return ::Engine::Get(engine_id)->GetRange() * ::Engine::Get(engine_id)->GetRange(); default: return 0; } } openttd-1.5.3/src/script/api/script_marine.cpp0000644000000000000000000001412312627373434020116 0ustar rootroot/* $Id: script_marine.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_marine.cpp Implementation of ScriptMarine. */ #include "../../stdafx.h" #include "script_marine.hpp" #include "script_station.hpp" #include "../../station_base.h" #include "../../tile_cmd.h" #include "../../safeguards.h" /* static */ bool ScriptMarine::IsWaterDepotTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_WATER) && ::GetWaterTileType(tile) == WATER_TILE_DEPOT; } /* static */ bool ScriptMarine::IsDockTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_STATION) && ::IsDock(tile); } /* static */ bool ScriptMarine::IsBuoyTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_STATION) && ::IsBuoy(tile); } /* static */ bool ScriptMarine::IsLockTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_WATER) && ::GetWaterTileType(tile) == WATER_TILE_LOCK; } /* static */ bool ScriptMarine::IsCanalTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_WATER) && ::IsCanal(tile); } /* static */ bool ScriptMarine::AreWaterTilesConnected(TileIndex t1, TileIndex t2) { if (!::IsValidTile(t1)) return false; if (!::IsValidTile(t2)) return false; /* Tiles not neighbouring */ if (::DistanceManhattan(t1, t2) != 1) return false; DiagDirection to_other_tile = ::DiagdirBetweenTiles(t2, t1); /* Determine the reachable tracks from the shared edge */ TrackBits gtts1 = ::TrackStatusToTrackBits(::GetTileTrackStatus(t1, TRANSPORT_WATER, 0, to_other_tile)) & ::DiagdirReachesTracks(to_other_tile); if (gtts1 == TRACK_BIT_NONE) return false; to_other_tile = ReverseDiagDir(to_other_tile); TrackBits gtts2 = ::TrackStatusToTrackBits(::GetTileTrackStatus(t2, TRANSPORT_WATER, 0, to_other_tile)) & ::DiagdirReachesTracks(to_other_tile); return gtts2 != TRACK_BIT_NONE; } /* static */ bool ScriptMarine::BuildWaterDepot(TileIndex tile, TileIndex front) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(front)); EnforcePrecondition(false, (::TileX(front) == ::TileX(tile)) != (::TileY(front) == ::TileY(tile))); return ScriptObject::DoCommand(tile, ::TileX(front) == ::TileX(tile), 0, CMD_BUILD_SHIP_DEPOT); } /* static */ bool ScriptMarine::BuildDock(TileIndex tile, StationID station_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id)); uint p1 = station_id == ScriptStation::STATION_JOIN_ADJACENT ? 0 : 1; uint p2 = (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16; return ScriptObject::DoCommand(tile, p1, p2, CMD_BUILD_DOCK); } /* static */ bool ScriptMarine::BuildBuoy(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_BUILD_BUOY); } /* static */ bool ScriptMarine::BuildLock(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_BUILD_LOCK); } /* static */ bool ScriptMarine::BuildCanal(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::DoCommand(tile, tile, WATER_CLASS_CANAL, CMD_BUILD_CANAL); } /* static */ bool ScriptMarine::RemoveWaterDepot(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsWaterDepotTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ bool ScriptMarine::RemoveDock(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsDockTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ bool ScriptMarine::RemoveBuoy(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsBuoyTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ bool ScriptMarine::RemoveLock(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsLockTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ bool ScriptMarine::RemoveCanal(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsCanalTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ Money ScriptMarine::GetBuildCost(BuildType build_type) { switch (build_type) { case BT_DOCK: return ::GetPrice(PR_BUILD_STATION_DOCK, 1, NULL); case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_SHIP, 1, NULL); case BT_BUOY: return ::GetPrice(PR_BUILD_WAYPOINT_BUOY, 1, NULL); default: return -1; } } openttd-1.5.3/src/script/api/script_companymode.hpp0000644000000000000000000000424312627373434021165 0ustar rootroot/* $Id: script_companymode.hpp 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 script_companymode.hpp Switch the company. */ #ifndef SCRIPT_COMPANYMODE_HPP #define SCRIPT_COMPANYMODE_HPP #include "script_object.hpp" /** * Class to switch the current company. * If you create an instance of this class, the company will be switched. * The original company is stored and recovered from when ever the * instance is destroyed. * All actions performed within the scope of this mode, will be executed * on behalf of the company you switched to. This includes any costs * attached to the action performed. If the company does not have the * funds the action will be aborted. In other words, this is like the * real player is executing the commands. * If the company is not valid during an action, the error * ERR_PRECONDITION_INVALID_COMPANY will be returned. You can switch to * invalid companies, or a company can become invalid (bankrupt) while you * are switched to it. * @api game */ class ScriptCompanyMode : public ScriptObject { private: CompanyID last_company; ///< The previous company we were in. public: /** * Creating instance of this class switches the company used for queries * and commands. * @param company The new company to switch to. * @note When the instance is destroyed, he restores the company that was * current when the instance was created! */ ScriptCompanyMode(int company); /** * Destroying this instance reset the company to that what it was * in when the instance was created. */ ~ScriptCompanyMode(); }; #endif /* SCRIPT_COMPANYMODE_HPP */ openttd-1.5.3/src/script/api/script_base.hpp0000644000000000000000000000570712627373434017572 0ustar rootroot/* $Id: script_base.hpp 25148 2013-04-06 11:59:27Z rubidium $ */ /* * 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 script_base.hpp Everything to query basic things. */ #ifndef SCRIPT_BASE_HPP #define SCRIPT_BASE_HPP #include "script_object.hpp" /** * Class that handles some basic functions. * @api ai game * * @note The random functions are not called Random and RandomRange, because * RANDOM_DEBUG does some tricky stuff, which messes with those names. * @note In MP we cannot use Random because that will cause desyncs (scripts are * ran on the server only, not on all clients). This means that * we use InteractiveRandom in MP. Rand() takes care of this for you. */ class ScriptBase : public ScriptObject { public: /** * Get a random value. * @return A random value between 0 and MAX(uint32). */ static uint32 Rand(); /** * Get a random value. * @param unused_param This parameter is not used, but is needed to work with lists. * @return A random value between 0 and MAX(uint32). */ static uint32 RandItem(int unused_param); /** * Get a random value in a range. * @param max The first number this function will never return (the maximum it returns is max - 1). * @return A random value between 0 .. max - 1. */ static uint RandRange(uint max); /** * Get a random value in a range. * @param unused_param This parameter is not used, but is needed to work with lists. * @param max The first number this function will never return (the maximum it returns is max - 1). * @return A random value between 0 .. max - 1. */ static uint RandRangeItem(int unused_param, uint max); /** * Returns approximately 'out' times true when called 'max' times. * After all, it is a random function. * @param out How many times it should return true. * @param max Out of this many times. * @pre \a out is at most equal to \a max. * @return True if the chance worked out. */ static bool Chance(uint out, uint max); /** * Returns approximately 'out' times true when called 'max' times. * After all, it is a random function. * @param unused_param This parameter is not used, but is needed to work with lists. * @param out How many times it should return true. * @param max Out of this many times. * @pre \a out is at most equal to \a max. * @return True if the chance worked out. */ static bool ChanceItem(int unused_param, uint out, uint max); }; #endif /* SCRIPT_BASE_HPP */ openttd-1.5.3/src/script/api/script_info_docs.hpp0000644000000000000000000002413512627373434020617 0ustar rootroot/* $Id: script_info_docs.hpp 26038 2013-11-18 20:09:09Z frosch $ */ /* * 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 script_info_docs.hpp Description of the functions an Script can/must provide in ScriptInfo. */ /* This file exists purely for doxygen purposes. */ /** * 'Abstract' class of the Scripts use to register themselves. * * @note This class is not part of the API. It is purely to document what * Scripts must or can implemented to provide information to OpenTTD to * base configuring/starting/loading the Script on. * * @note The required functions are also needed for Script Libraries, but in * that case you extend ScriptLibrary. As such the information here can * be used for libraries, but the information will not be shown in the * GUI except for error/debug messages. * * @api ai game */ class ScriptInfo { public: /** * Gets the author name to be shown in the 'Available Scripts' window. * * @return The author name of the Script. * @note This function is required. */ string GetAuthor(); /** * Gets the Scripts name. This is shown in the 'Available Scripts' window * and at all other places where the Script is mentioned, like the debug * window or OpenTTD's help message. The name is used to uniquely * identify an Script within OpenTTD and this name is used in savegames * and the configuration file. * * @return The name of the Script. * @note This function is required. * @note This name is not used as library name by ScriptController::Import, * instead the name returned by #CreateInstance is used. */ string GetName(); /** * Gets a 4 ASCII character short name of the Script to uniquely * identify it from other Scripts. The short name is primarily * used as unique identifier for the content system. * The content system uses besides the short name also the * MD5 checksum of all the source files to uniquely identify * a specific version of the Script. * * The short name must consist of precisely four ASCII * characters, or more precisely four non-zero bytes. * * @return The name of the Script. * @note This function is required. */ string GetShortName(); /** * Gets the description to be shown in the 'Available Scripts' window. * * @return The description for the Script. * @note This function is required. */ string GetDescription(); /** * Gets the version of the Script. This is a number to (in theory) * uniquely identify the versions of an Script. Generally the * 'instance' of an Script with the highest version is chosen to * be loaded. * * When OpenTTD finds, during starting, a duplicate Script with the * same version number one is randomly chosen. So it is * important that this number is regularly updated/incremented. * * @return The version number of the Script. * @note This function is required. */ int GetVersion(); /** * Gets the lowest version of the Script that OpenTTD can still load * the savegame of. In other words, from which version until this * version can the Script load the savegames. * * If this function does not exist OpenTTD assumes it can only * load savegames of this version. As such it will not upgrade * to this version upon load. * * @return The lowest version number we load the savegame data. * @note This function is optional. */ int MinVersionToLoad(); /** * Gets the development/release date of the Script. * * The intention of this is to give the user an idea how old the * Script is and whether there might be a newer version. * * @return The development/release date for the Script. * @note This function is required. */ string GetDate(); /** * Can this Script be used as random Script? * * The idea behind this function is to 'forbid' highly * competitive or other special Scripts from running in games unless * the user explicitly selects the Script to be loaded. This to * try to prevent users from complaining that the Script is too * aggressive or does not build profitable routes. * * If this function does not exist OpenTTD assumes the Script can * be used as random Script. As such it will be randomly chosen. * * @return True if the Script can be used as random Script. * @note This function is optional. * * @api -game */ bool UseAsRandomAI(); /** * Can a non-developer select Script for a new game. * * The idea behind this function is to 'forbid' using your script with a new * game if you for example specifically wrote it for a certain scenario. * * @return True if the Script can be selected from the GUI as non-developer. * @note This function is optional. Default is false. * * @api -ai */ bool IsDeveloperOnly(); /** * Gets the name of main class of the Script so OpenTTD knows * what class to instantiate. For libraries, this name is also * used when other scripts import it using ScriptController::Import. * * @return The class name of the Script. * @note This function is required. */ string CreateInstance(); /** * Gets the API version this Script is written for. If this function * does not exist API compatibility with version 0.7 is assumed. * If the function returns something OpenTTD does not understand, * for example a newer version or a string that is not a version, * the Script will not be loaded. * * Although in the future we might need to make a separate * compatibility 'wrapper' for a specific version of OpenTTD, for * example '0.7.1', we will use only the major and minor number * and not the bugfix number as valid return for this function. * * Valid return values are: * - "0.7" (for AI only) * - "1.0" (for AI only) * - "1.1" (for AI only) * - "1.2" (for both AI and GS) * - "1.3" (for both AI and GS) * * @return The version this Script is compatible with. */ string GetAPIVersion(); /** * Gets the URL to be shown in the 'this Script has crashed' message * and in the 'Available Scripts' window. If this function does not * exist no URL will be shown. * * This function purely exists to redirect users of the Script to the * right place on the internet to discuss the Script and report bugs * of this Script. * * @return The URL to show. * @note This function is optional. */ string GetURL(); /** * Gets the settings that OpenTTD shows in the "Script Parameters" window * so the user can customize the Script. This is a special function that * doesn't need to return anything. Instead you can call AddSetting * and AddLabels here. * * @note This function is optional. */ void GetSettings(); /** Miscellaneous flags for Script settings. */ enum ScriptConfigFlags { CONFIG_NONE, ///< Normal setting. CONFIG_RANDOM, ///< When randomizing the Script, pick any value between min_value and max_value. CONFIG_BOOLEAN, ///< This value is a boolean (either 0 (false) or 1 (true) ). CONFIG_INGAME, ///< This setting can be changed while the Script is running. CONFIG_DEVELOPER, ///< This setting will only be visible when the Script development tools are active. }; /** * Add a user configurable setting for this Script. You can call this * as many times as you have settings. * @param setting_description A table with all information about a * single setting. The table should have the following name/value pairs: * - name The name of the setting, this is used in openttd.cfg to * store the current configuration of Scripts. Required. * - description A single line describing the setting. Required. * - min_value The minimum value of this setting. Required for integer * settings and not allowed for boolean settings. * - max_value The maximum value of this setting. Required for integer * settings and not allowed for boolean settings. * - easy_value The default value if the easy difficulty level * is selected. Required. * - medium_value The default value if the medium difficulty level * is selected. Required. * - hard_value The default value if the hard difficulty level * is selected. Required. * - custom_value The default value if the custom difficulty level * is selected. Required. * - random_deviation If this property has a nonzero value, then the * actual value of the setting in game will be * user_configured_value + random(-random_deviation, random_deviation). * Not allowed if the CONFIG_RANDOM flag is set, otherwise optional. * - step_size The increase/decrease of the value every time the user * clicks one of the up/down arrow buttons. Optional, default is 1. * - flags Bitmask of some flags, see ScriptConfigFlags. Required. * * @note This is a function provided by OpenTTD, you don't have to * include it in your Script but should just call it from GetSettings. */ void AddSetting(table setting_description); /** * Add labels for the values of a setting. Instead of a number the * user will see the corresponding name. * @param setting_name The name of the setting. * @param value_names A table that maps values to names. The first * character of every identifier is ignored and the rest should * be an integer of the value you define a name for. The value * is a short description of that value. * To define labels for a setting named "competition_level" you could * for example call it like this: * AddLabels("competition_level", {_0 = "no competition", _1 = "some competition", * _2 = "a lot of competition"}); * * @note This is a function provided by OpenTTD, you don't have to * include it in your Script but should just call it from GetSettings. */ void AddLabels(const char *setting_name, table value_names); }; openttd-1.5.3/src/script/api/script_engine.hpp0000644000000000000000000002452412627373434020123 0ustar rootroot/* $Id: script_engine.hpp 27123 2015-01-20 19:11:31Z frosch $ */ /* * 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 script_engine.hpp Everything to query and build engines. */ #ifndef SCRIPT_ENGINE_HPP #define SCRIPT_ENGINE_HPP #include "script_vehicle.hpp" #include "script_rail.hpp" #include "script_airport.hpp" #include "script_date.hpp" /** * Class that handles all engine related functions. * @api ai game */ class ScriptEngine : public ScriptObject { public: /** * Checks whether the given engine type is valid. * An engine is valid for a company if it has at least one vehicle of this engine or it's currently buildable. * @game Outside ScriptCompanyMode scope the function reports all engines valid, which were or will be available at some point. * @param engine_id The engine to check. * @return True if and only if the engine type is valid. */ static bool IsValidEngine(EngineID engine_id); /** * Checks whether the given engine type is buildable for a company. * @game Outside ScriptCompanyMode scope the function checks whether the engine is currently buildable by all companies (no exclusive preview). * @param engine_id The engine to check. * @return True if and only if the engine type is buildable. */ static bool IsBuildable(EngineID engine_id); /** * Get the name of an engine. * @param engine_id The engine to get the name of. * @pre IsValidEngine(engine_id). * @return The name the engine has. */ static char *GetName(EngineID engine_id); /** * Get the cargo-type of an engine. In case it can transport multiple cargoes, it * returns the first/main. * @param engine_id The engine to get the cargo-type of. * @pre IsValidEngine(engine_id). * @return The cargo-type of the engine. */ static CargoID GetCargoType(EngineID engine_id); /** * Check if the cargo of an engine can be refitted to your requested. If * the engine already allows this cargo, the function also returns true. * In case of articulated vehicles the function decides whether at least one * part can carry the cargo. * @param engine_id The engine to check for refitting. * @param cargo_id The cargo to check for refitting. * @pre IsValidEngine(engine_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return True if the engine can carry this cargo, either via refit, or * by default. */ static bool CanRefitCargo(EngineID engine_id, CargoID cargo_id); /** * Check if the engine can pull a wagon with the given cargo. * @param engine_id The engine to check. * @param cargo_id The cargo to check. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL. * @pre ScriptCargo::IsValidCargo(cargo_id). * @return True if the engine can pull wagons carrying this cargo. * @note This function is not exhaustive; a true here does not mean * that the vehicle can pull the wagons, a false does mean it can't. */ static bool CanPullCargo(EngineID engine_id, CargoID cargo_id); /** * Get the capacity of an engine. In case it can transport multiple cargoes, it * returns the first/main. * @param engine_id The engine to get the capacity of. * @pre IsValidEngine(engine_id). * @return The capacity of the engine. */ static int32 GetCapacity(EngineID engine_id); /** * Get the reliability of an engine. The value is between 0 and 100, where * 100 means 100% reliability (never breaks down) and 0 means 0% * reliability (you most likely don't want to buy it). * @param engine_id The engine to get the reliability of. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) != ScriptVehicle::VT_TRAIN || !IsWagon(engine_id). * @return The reliability the engine has. */ static int32 GetReliability(EngineID engine_id); /** * Get the maximum speed of an engine. * @param engine_id The engine to get the maximum speed of. * @pre IsValidEngine(engine_id). * @return The maximum speed the engine has. * @note The speed is in OpenTTD's internal speed unit. * This is mph / 1.6, which is roughly km/h. * To get km/h multiply this number by 1.00584. */ static int32 GetMaxSpeed(EngineID engine_id); /** * Get the new cost of an engine. * @param engine_id The engine to get the new cost of. * @pre IsValidEngine(engine_id). * @return The new cost the engine has. */ static Money GetPrice(EngineID engine_id); /** * Get the maximum age of a brand new engine. * @param engine_id The engine to get the maximum age of. * @pre IsValidEngine(engine_id). * @returns The maximum age of a new engine in days. * @note Age is in days; divide by 366 to get per year. */ static int32 GetMaxAge(EngineID engine_id); /** * Get the running cost of an engine. * @param engine_id The engine to get the running cost of. * @pre IsValidEngine(engine_id). * @return The running cost of a vehicle per year. * @note Cost is per year; divide by 365 to get per day. */ static Money GetRunningCost(EngineID engine_id); /** * Get the power of an engine. * @param engine_id The engine to get the power of. * @pre IsValidEngine(engine_id). * @pre (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL || GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD) && !IsWagon(engine_id). * @return The power of the engine in hp. */ static int32 GetPower(EngineID engine_id); /** * Get the weight of an engine. * @param engine_id The engine to get the weight of. * @pre IsValidEngine(engine_id). * @pre (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL || GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD). * @return The weight of the engine in metric tons. */ static int32 GetWeight(EngineID engine_id); /** * Get the maximum tractive effort of an engine. * @param engine_id The engine to get the maximum tractive effort of. * @pre IsValidEngine(engine_id). * @pre (GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL || GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD) && !IsWagon(engine_id). * @return The maximum tractive effort of the engine in kN. */ static int32 GetMaxTractiveEffort(EngineID engine_id); /** * Get the date this engine was designed. * @param engine_id The engine to get the design date of. * @pre IsValidEngine(engine_id). * @return The date this engine was designed. */ static ScriptDate::Date GetDesignDate(EngineID engine_id); /** * Get the type of an engine. * @param engine_id The engine to get the type of. * @pre IsValidEngine(engine_id). * @return The type the engine has. */ static ScriptVehicle::VehicleType GetVehicleType(EngineID engine_id); /** * Check if an engine is a wagon. * @param engine_id The engine to check. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL. * @return Whether or not the engine is a wagon. */ static bool IsWagon(EngineID engine_id); /** * Check if a train vehicle can run on a RailType. * @param engine_id The engine to check. * @param track_rail_type The type you want to check. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL. * @pre ScriptRail::IsRailTypeAvailable(track_rail_type). * @return Whether an engine of type 'engine_id' can run on 'track_rail_type'. * @note Even if a train can run on a RailType that doesn't mean that it'll be * able to power the train. Use HasPowerOnRail for that. */ static bool CanRunOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type); /** * Check if a train engine has power on a RailType. * @param engine_id The engine to check. * @param track_rail_type Another RailType. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL. * @pre ScriptRail::IsRailTypeAvailable(track_rail_type). * @return Whether an engine of type 'engine_id' has power on 'track_rail_type'. */ static bool HasPowerOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type); /** * Get the RoadType of the engine. * @param engine_id The engine to get the RoadType of. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD. * @return The RoadType the engine has. */ static ScriptRoad::RoadType GetRoadType(EngineID engine_id); /** * Get the RailType of the engine. * @param engine_id The engine to get the RailType of. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL. * @return The RailType the engine has. */ static ScriptRail::RailType GetRailType(EngineID engine_id); /** * Check if the engine is articulated. * @param engine_id The engine to check. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_ROAD || GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL. * @return True if the engine is articulated. */ static bool IsArticulated(EngineID engine_id); /** * Get the PlaneType of the engine. * @param engine_id The engine to get the PlaneType of. * @pre IsValidEngine(engine_id). * @pre GetVehicleType(engine_id) == ScriptVehicle::VT_AIR. * @return The PlaneType the engine has. */ static ScriptAirport::PlaneType GetPlaneType(EngineID engine_id); /** * Get the maximum allowed distance between two orders for an engine. * The distance returned is a vehicle-type specific distance independent from other * map distances, you may use the result of this function to compare it * with the result of ScriptOrder::GetOrderDistance. * @param engine_id The engine to get the max distance for. * @pre IsValidEngine(engine_id). * @return The maximum distance between two orders for the engine * or 0 if the distance is unlimited. * @note The unit of the order distances is unspecified and should * not be compared with map distances * @see ScriptOrder::GetOrderDistance */ static uint GetMaximumOrderDistance(EngineID engine_id); }; #endif /* SCRIPT_ENGINE_HPP */ openttd-1.5.3/src/script/api/script_vehiclelist.cpp0000644000000000000000000000744112627373434021163 0ustar rootroot/* $Id: script_vehiclelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_vehiclelist.cpp Implementation of ScriptVehicleList and friends. */ #include "../../stdafx.h" #include "script_vehiclelist.hpp" #include "script_group.hpp" #include "script_map.hpp" #include "script_station.hpp" #include "../../depot_map.h" #include "../../vehicle_base.h" #include "../../safeguards.h" ScriptVehicleList::ScriptVehicleList() { const Vehicle *v; FOR_ALL_VEHICLES(v) { if ((v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && v->IsPrimaryVehicle()) this->AddItem(v->index); } } ScriptVehicleList_Station::ScriptVehicleList_Station(StationID station_id) { if (!ScriptBaseStation::IsValidBaseStation(station_id)) return; const Vehicle *v; FOR_ALL_VEHICLES(v) { if ((v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && v->IsPrimaryVehicle()) { const Order *order; FOR_VEHICLE_ORDERS(v, order) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station_id) { this->AddItem(v->index); break; } } } } } ScriptVehicleList_Depot::ScriptVehicleList_Depot(TileIndex tile) { if (!ScriptMap::IsValidTile(tile)) return; DestinationID dest; VehicleType type; switch (GetTileType(tile)) { case MP_STATION: // Aircraft if (!IsAirport(tile)) return; type = VEH_AIRCRAFT; dest = GetStationIndex(tile); break; case MP_RAILWAY: if (!IsRailDepot(tile)) return; type = VEH_TRAIN; dest = GetDepotIndex(tile); break; case MP_ROAD: if (!IsRoadDepot(tile)) return; type = VEH_ROAD; dest = GetDepotIndex(tile); break; case MP_WATER: if (!IsShipDepot(tile)) return; type = VEH_SHIP; dest = GetDepotIndex(tile); break; default: // No depot return; } const Vehicle *v; FOR_ALL_VEHICLES(v) { if ((v->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && v->IsPrimaryVehicle() && v->type == type) { const Order *order; FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == dest) { this->AddItem(v->index); break; } } } } } ScriptVehicleList_SharedOrders::ScriptVehicleList_SharedOrders(VehicleID vehicle_id) { if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return; for (const Vehicle *v = Vehicle::Get(vehicle_id)->FirstShared(); v != NULL; v = v->NextShared()) { this->AddItem(v->index); } } ScriptVehicleList_Group::ScriptVehicleList_Group(GroupID group_id) { if (!ScriptGroup::IsValidGroup((ScriptGroup::GroupID)group_id)) return; const Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == ScriptObject::GetCompany() && v->IsPrimaryVehicle()) { if (v->group_id == group_id) this->AddItem(v->index); } } } ScriptVehicleList_DefaultGroup::ScriptVehicleList_DefaultGroup(ScriptVehicle::VehicleType vehicle_type) { if (vehicle_type < ScriptVehicle::VT_RAIL || vehicle_type > ScriptVehicle::VT_AIR) return; const Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == ScriptObject::GetCompany() && v->IsPrimaryVehicle()) { if (v->type == (::VehicleType)vehicle_type && v->group_id == ScriptGroup::GROUP_DEFAULT) this->AddItem(v->index); } } } openttd-1.5.3/src/script/api/script_subsidylist.cpp0000644000000000000000000000171112627373433021217 0ustar rootroot/* $Id: script_subsidylist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_subsidylist.cpp Implementation of ScriptSubsidyList. */ #include "../../stdafx.h" #include "script_subsidylist.hpp" #include "../../subsidy_base.h" #include "../../safeguards.h" ScriptSubsidyList::ScriptSubsidyList() { const Subsidy *s; FOR_ALL_SUBSIDIES(s) { this->AddItem(s->index); } } openttd-1.5.3/src/script/api/script_industry.cpp0000644000000000000000000001455412627373434020534 0ustar rootroot/* $Id: script_industry.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_industry.cpp Implementation of ScriptIndustry. */ #include "../../stdafx.h" #include "script_industry.hpp" #include "script_cargo.hpp" #include "script_map.hpp" #include "../../industry.h" #include "../../strings_func.h" #include "../../station_base.h" #include "../../newgrf_industries.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ int32 ScriptIndustry::GetIndustryCount() { return (int32)::Industry::GetNumItems(); } /* static */ bool ScriptIndustry::IsValidIndustry(IndustryID industry_id) { return ::Industry::IsValidID(industry_id); } /* static */ IndustryID ScriptIndustry::GetIndustryID(TileIndex tile) { if (!::IsValidTile(tile) || !::IsTileType(tile, MP_INDUSTRY)) return INVALID_INDUSTRY; return ::GetIndustryIndex(tile); } /* static */ char *ScriptIndustry::GetName(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return NULL; ::SetDParam(0, industry_id); return GetString(STR_INDUSTRY_NAME); } /* static */ ScriptIndustry::CargoAcceptState ScriptIndustry::IsCargoAccepted(IndustryID industry_id, CargoID cargo_id) { if (!IsValidIndustry(industry_id)) return CAS_NOT_ACCEPTED; if (!ScriptCargo::IsValidCargo(cargo_id)) return CAS_NOT_ACCEPTED; Industry *i = ::Industry::Get(industry_id); for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { if (i->accepts_cargo[j] == cargo_id) { if (IndustryTemporarilyRefusesCargo(i, cargo_id)) return CAS_TEMP_REFUSED; return CAS_ACCEPTED; } } return CAS_NOT_ACCEPTED; } /* static */ int32 ScriptIndustry::GetStockpiledCargo(IndustryID industry_id, CargoID cargo_id) { if (!IsValidIndustry(industry_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo_id)) return -1; Industry *ind = ::Industry::Get(industry_id); for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) { CargoID cid = ind->accepts_cargo[i]; if (cid == cargo_id) { return ind->incoming_cargo_waiting[i]; } } return -1; } /* static */ int32 ScriptIndustry::GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id) { if (!IsValidIndustry(industry_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo_id)) return -1; const Industry *i = ::Industry::Get(industry_id); for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == cargo_id) return i->last_month_production[j]; } return -1; } /* static */ int32 ScriptIndustry::GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id) { if (!IsValidIndustry(industry_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo_id)) return -1; const Industry *i = ::Industry::Get(industry_id); for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == cargo_id) return i->last_month_transported[j]; } return -1; } /* static */ int32 ScriptIndustry::GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id) { if (!IsValidIndustry(industry_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo_id)) return -1; const Industry *i = ::Industry::Get(industry_id); for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == cargo_id) return ::ToPercent8(i->last_month_pct_transported[j]); } return -1; } /* static */ TileIndex ScriptIndustry::GetLocation(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return INVALID_TILE; return ::Industry::Get(industry_id)->location.tile; } /* static */ int32 ScriptIndustry::GetAmountOfStationsAround(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return -1; Industry *ind = ::Industry::Get(industry_id); StationList stations; ::FindStationsAroundTiles(ind->location, &stations); return (int32)stations.Length(); } /* static */ int32 ScriptIndustry::GetDistanceManhattanToTile(IndustryID industry_id, TileIndex tile) { if (!IsValidIndustry(industry_id)) return -1; return ScriptMap::DistanceManhattan(tile, GetLocation(industry_id)); } /* static */ int32 ScriptIndustry::GetDistanceSquareToTile(IndustryID industry_id, TileIndex tile) { if (!IsValidIndustry(industry_id)) return -1; return ScriptMap::DistanceSquare(tile, GetLocation(industry_id)); } /* static */ bool ScriptIndustry::IsBuiltOnWater(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return false; return (::GetIndustrySpec(::Industry::Get(industry_id)->type)->behaviour & INDUSTRYBEH_BUILT_ONWATER) != 0; } /* static */ bool ScriptIndustry::HasHeliport(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return false; return (::GetIndustrySpec(::Industry::Get(industry_id)->type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0; } /* static */ TileIndex ScriptIndustry::GetHeliportLocation(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return INVALID_TILE; if (!HasHeliport(industry_id)) return INVALID_TILE; const Industry *ind = ::Industry::Get(industry_id); TILE_AREA_LOOP(tile_cur, ind->location) { if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) { return tile_cur; } } return INVALID_TILE; } /* static */ bool ScriptIndustry::HasDock(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return false; return (::GetIndustrySpec(::Industry::Get(industry_id)->type)->behaviour & INDUSTRYBEH_AI_AIRSHIP_ROUTES) != 0; } /* static */ TileIndex ScriptIndustry::GetDockLocation(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return INVALID_TILE; if (!HasDock(industry_id)) return INVALID_TILE; const Industry *ind = ::Industry::Get(industry_id); TILE_AREA_LOOP(tile_cur, ind->location) { if (IsTileType(tile_cur, MP_STATION) && IsOilRig(tile_cur)) { return tile_cur; } } return INVALID_TILE; } /* static */ IndustryType ScriptIndustry::GetIndustryType(IndustryID industry_id) { if (!IsValidIndustry(industry_id)) return INVALID_INDUSTRYTYPE; return ::Industry::Get(industry_id)->type; } openttd-1.5.3/src/script/api/script_industrytypelist.cpp0000644000000000000000000000202012627373433022312 0ustar rootroot/* $Id: script_industrytypelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_industrytypelist.cpp Implementation of ScriptIndustryTypeList. */ #include "../../stdafx.h" #include "script_industrytypelist.hpp" #include "../../industry.h" #include "../../safeguards.h" ScriptIndustryTypeList::ScriptIndustryTypeList() { for (int i = 0; i < NUM_INDUSTRYTYPES; i++) { if (ScriptIndustryType::IsValidIndustryType(i)) this->AddItem(i); } } openttd-1.5.3/src/script/api/doxygen_filter.awk0000644000000000000000000001435212627373434020305 0ustar rootroot# $Id: doxygen_filter.awk 23650 2011-12-21 14:30:08Z yexo $ # 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 . # # Awk script to automatically generate the code needed # to export the script APIs to Squirrel. # # Note that arrays are 1 based... # BEGIN { cls = "" api_selected = "" cls_in_api = "" cls_level = 0 skip_function_body = "false" skip_function_par = 0 RS = "\r|\n" apis = tolower(api) if (apis == "gs") apis = "game" } { gsub(/Script/, api) } { if (skip_function_body == "true") { input = $0 gsub(/[^{]/, "", input) skip_function_par += length(input) if (skip_function_par > 0) { input = $0 gsub(/[^}]/, "", input) skip_function_par -= length(input) if (skip_function_par == 0) skip_function_body = "false" } } if (skip_function_body == "true") next } /@file/ { gsub(/script/, apis) } /^([ ]*)\* @api/ { if (api == "Script") { api_selected = "true" next } # By default, classes are not selected if (cls_level == 0) api_selected = "false" gsub("^([ ]*)", "", $0) gsub("* @api ", "", $0) if ($0 == "none") { api_selected = "false" } else if ($0 == "-all") { api_selected = "false" } else if (match($0, "-" apis)) { api_selected = "false" } else if (match($0, apis)) { api_selected = "true" } next } # Ignore forward declarations of classes /^( *)class(.*);/ { next; } # We only want to have public functions exported for now /^( *)class/ { if (cls_level == 0) { if (api_selected == "") { print "Class '"$2"' has no @api. It won't be published to any API." > "/dev/stderr" api_selected = "false" } public = "false" cls_param[0] = "" cls_param[1] = 1 cls_param[2] = "x" cls_in_api = api_selected api_selected = "" cls = $2 if (cls_in_api == "true") { print comment_buffer print print "public:" comment_buffer = "" } } else if (cls_level == 1) { if (api_selected == "") api_selected = cls_in_api if (api_selected == "true") { print comment_buffer print print "public:" comment_buffer = "" } api_selected = "" } else { print "Classes nested too deep" > "/dev/stderr" exit 1 } cls_level++ next } /^( *)public/ { if (cls_level == 1) comment_buffer = ""; public = "true"; next; } /^( *)protected/ { if (cls_level == 1) comment_buffer = ""; public = "false"; next; } /^( *)private/ { if (cls_level == 1) comment_buffer = ""; public = "false"; next; } # Ignore special doxygen blocks /^#ifndef DOXYGEN_API/ { doxygen_skip = "true"; next; } /^#ifdef DOXYGEN_API/ { doxygen_skip = "next"; next; } /^#endif \/\* DOXYGEN_API \*\// { doxygen_skip = "false"; next; } /^#else/ { if (doxygen_skip == "next") { doxygen_skip = "true"; } else { doxygen_skip = "false"; } next; } { if (doxygen_skip == "true") next } /^#/ { next } # Store comments /\/\*\*.*\*\// { comment_buffer = $0; comment = "false"; next; } /\/\*.*\*\// { comment_buffer = ""; comment = "false"; next; } /\/\*\*/ { comment_buffer = $0 "\n"; comment = "true"; next; } /\/\*/ { comment_buffer = ""; comment = "false"; next; } /\*\// { comment_buffer = comment_buffer $0; comment = "false"; next; } { if (comment == "true" && !match($0, /@api/)) { if (match($0, /@game /) && api != "GS") next; if (match($0, /@ai /) && api != "AI") next; gsub("@game ", "", $0); gsub("@ai ", "", $0); comment_buffer = comment_buffer $0 "\n"; next; } } # We need to make specialized conversions for structs /^( *)struct/ { comments_so_far = comment_buffer comment_buffer = "" cls_level++ # Check if we want to publish this struct if (api_selected == "") api_selected = cls_in_api if (api_selected == "false") { api_selected = "" next } api_selected = "" if (public == "false") next print comments_so_far print $0 next } # We need to make specialized conversions for enums /^( *)enum/ { comments_so_far = comment_buffer comment_buffer = "" cls_level++ # Check if we want to publish this enum if (api_selected == "") api_selected = cls_in_api if (api_selected == "false") { api_selected = "" next } api_selected = "" if (public == "false") next in_enum = "true" print comments_so_far print $0 next } # Maybe the end of the class, if so we can start with the Squirrel export pretty soon /};/ { comment_buffer = "" cls_level-- if (cls_level != 0) { if (in_enum == "true") print in_enum = "false" next } if (cls == "") { next } if (cls_in_api == "true") print next; } # Empty/white lines /^([ ]*)$/ { print $0 next } # Skip non-public functions { if (public == "false") next } # Add enums { if (in_enum == "true") { print comment_buffer comment_buffer = "" gsub("=([^/]*),", ",", $0) print $0 # Check if this a special error enum if (match(enums[enum_size], ".*::ErrorMessages") != 0) { # syntax: # enum ErrorMessages { # ERR_SOME_ERROR, // [STR_ITEM1, STR_ITEM2, ...] # } ##TODO: don't print the STR_* } next } } # Add a const (non-enum) value /^[ ]*static const \w+ \w+ = -?\(?\w*\)?\w+;/ { if (api_selected == "") api_selected = cls_in_api if (api_selected == "false") { api_selected = "" comment_buffer = "" next } print comment_buffer print $0 comment_buffer = "" next } # Add a method to the list /^.*\(.*\).*$/ { if (cls_level != 1) next if (!match($0, ";")) { gsub(/ :$/, ";") skip_function_body = "true" } if (match($0, "~")) { if (api_selected != "") { print "Destructor for '"cls"' has @api. Tag ignored." > "/dev/stderr" api_selected = "" } next } # Check if we want to publish this function if (api_selected == "") api_selected = cls_in_api if (api_selected == "false") { api_selected = "" comment_buffer = "" next } api_selected = "" print comment_buffer print $0 comment_buffer = "" next } openttd-1.5.3/src/script/api/script_gamesettings.hpp0000644000000000000000000000725012627373434021345 0ustar rootroot/* $Id: script_gamesettings.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 script_gamesettings.hpp Everything to read game settings. */ #ifndef SCRIPT_GAMESETTINGS_HPP #define SCRIPT_GAMESETTINGS_HPP #include "script_vehicle.hpp" /** * Class that handles all game settings related functions. * @api ai game * * @note ScriptGameSettings::IsValid and ScriptGameSettings::GetValue are functions * that rely on the settings as OpenTTD stores them in savegame and * openttd.cfg. No guarantees can be given on the long term validity, * consistency and stability of the names, values and value ranges. * Using these settings can be dangerous and could cause issues in * future versions. To make sure that a setting still exists in the * current version you have to run ScriptGameSettings::IsValid before * accessing it. * * @note The names of the setting for ScriptGameSettings::IsValid and * ScriptGameSettings::GetValue are the same ones as those that are shown by * the list_settings command in the in-game console. Settings that are * string based are NOT supported and GameSettings::IsValid will return * false for them. These settings will not be supported either because * they have no relevance for the script (default client names, server IPs, * etc.). */ class ScriptGameSettings : public ScriptObject { public: /** * Is the given game setting a valid setting for this instance of OpenTTD? * @param setting The setting to check for existence. * @warning Results of this function are not governed by the API. This means * that a setting that previously existed can be gone or has * changed its name. * @note Results achieved in the past offer no guarantee for the future. * @return True if and only if the setting is valid. */ static bool IsValid(const char *setting); /** * Gets the value of the game setting. * @param setting The setting to get the value of. * @pre IsValid(setting). * @warning Results of this function are not governed by the API. This means * that the value of settings may be out of the expected range. It * also means that a setting that previously existed can be gone or * has changed its name/characteristics. * @note Results achieved in the past offer no guarantee for the future. * @return The value for the setting. */ static int32 GetValue(const char *setting); /** * Sets the value of the game setting. * @param setting The setting to set the value of. * @param value The value to set the setting to. * @pre IsValid(setting). * @return True if the action succeeded. * @note Results achieved in the past offer no guarantee for the future. * @api -ai */ static bool SetValue(const char *setting, int value); /** * Checks whether the given vehicle-type is disabled for companies. * @param vehicle_type The vehicle-type to check. * @return True if the vehicle-type is disabled. * @api -game */ static bool IsDisabledVehicleType(ScriptVehicle::VehicleType vehicle_type); }; #endif /* SCRIPT_GAMESETTINGS_HPP */ openttd-1.5.3/src/script/api/script_cargolist.hpp0000644000000000000000000000415712627373434020645 0ustar rootroot/* $Id: script_cargolist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_cargolist.hpp List all the cargoes. */ #ifndef SCRIPT_CARGOLIST_HPP #define SCRIPT_CARGOLIST_HPP #include "script_list.hpp" /** * Creates a list of cargoes that can be produced in the current game. * @api ai game * @ingroup ScriptList */ class ScriptCargoList : public ScriptList { public: ScriptCargoList(); }; /** * Creates a list of cargoes that the given industry accepts. * @note This list also includes cargoes that are temporarily not accepted * by this industry, @see ScriptIndustry::IsCargoAccepted. * @api ai game * @ingroup ScriptList */ class ScriptCargoList_IndustryAccepting : public ScriptList { public: /** * @param industry_id The industry to get the list of cargoes it accepts from. */ ScriptCargoList_IndustryAccepting(IndustryID industry_id); }; /** * Creates a list of cargoes that the given industry can produce. * @api ai game * @ingroup ScriptList */ class ScriptCargoList_IndustryProducing : public ScriptList { public: /** * @param industry_id The industry to get the list of cargoes it produces from. */ ScriptCargoList_IndustryProducing(IndustryID industry_id); }; /** * Creates a list of cargoes that the given station accepts. * @api ai game * @ingroup ScriptList */ class ScriptCargoList_StationAccepting : public ScriptList { public: /** * @param station_id The station to get the list of cargoes it accepts from. */ ScriptCargoList_StationAccepting(StationID station_id); }; #endif /* SCRIPT_CARGOLIST_HPP */ openttd-1.5.3/src/script/api/script_object.hpp0000644000000000000000000001613612627373434020124 0ustar rootroot/* $Id: script_object.hpp 25342 2013-06-09 12:19:09Z zuu $ */ /* * 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 script_object.hpp Main object, on which all objects depend. */ #ifndef SCRIPT_OBJECT_HPP #define SCRIPT_OBJECT_HPP #include "../../misc/countedptr.hpp" #include "../../road_type.h" #include "../../rail_type.h" #include "script_types.hpp" #include "../script_suspend.hpp" /** * The callback function for Mode-classes. */ typedef bool (ScriptModeProc)(); /** * Uper-parent object of all API classes. You should never use this class in * your script, as it doesn't publish any public functions. It is used * internally to have a common place to handle general things, like internal * command processing, and command-validation checks. * @api none */ class ScriptObject : public SimpleCountedObject { friend class ScriptInstance; friend class ScriptController; protected: /** * A class that handles the current active instance. By instantiating it at * the beginning of a function with the current active instance, it remains * active till the scope of the variable closes. It then automatically * reverts to the active instance it was before instantiating. */ class ActiveInstance { friend class ScriptObject; public: ActiveInstance(ScriptInstance *instance); ~ActiveInstance(); private: ScriptInstance *last_active; ///< The active instance before we go instantiated. static ScriptInstance *active; ///< The global current active instance. }; public: /** * Store the latest result of a DoCommand per company. * @param res The result of the last command. */ static void SetLastCommandRes(bool res); /** * Get the currently active instance. * @return The instance. */ static class ScriptInstance *GetActiveInstance(); protected: /** * Executes a raw DoCommand for the script. */ static bool DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text = NULL, Script_SuspendCallbackProc *callback = NULL); /** * Sets the DoCommand costs counter to a value. */ static void SetDoCommandCosts(Money value); /** * Increase the current value of the DoCommand costs counter. */ static void IncreaseDoCommandCosts(Money value); /** * Get the current DoCommand costs counter. */ static Money GetDoCommandCosts(); /** * Set the DoCommand last error. */ static void SetLastError(ScriptErrorType last_error); /** * Get the DoCommand last error. */ static ScriptErrorType GetLastError(); /** * Set the road type. */ static void SetRoadType(RoadType road_type); /** * Get the road type. */ static RoadType GetRoadType(); /** * Set the rail type. */ static void SetRailType(RailType rail_type); /** * Get the rail type. */ static RailType GetRailType(); /** * Set the current mode of your script to this proc. */ static void SetDoCommandMode(ScriptModeProc *proc, ScriptObject *instance); /** * Get the current mode your script is currently under. */ static ScriptModeProc *GetDoCommandMode(); /** * Get the instance of the current mode your script is currently under. */ static ScriptObject *GetDoCommandModeInstance(); /** * Set the delay of the DoCommand. */ static void SetDoCommandDelay(uint ticks); /** * Get the delay of the DoCommand. */ static uint GetDoCommandDelay(); /** * Get the latest result of a DoCommand. */ static bool GetLastCommandRes(); /** * Get the latest stored new_vehicle_id. */ static VehicleID GetNewVehicleID(); /** * Get the latest stored new_sign_id. */ static SignID GetNewSignID(); /** * Get the latest stored new_group_id. */ static GroupID GetNewGroupID(); /** * Get the latest stored new_goal_id. */ static GoalID GetNewGoalID(); /** * Get the latest stored new_story_page_id. */ static StoryPageID GetNewStoryPageID(); /** * Get the latest stored new_story_page_id. */ static StoryPageID GetNewStoryPageElementID(); /** * Store a allow_do_command per company. * @param allow The new allow. */ static void SetAllowDoCommand(bool allow); /** * Get the internal value of allow_do_command. This can differ * from CanSuspend() if the reason we are not allowed * to execute a DoCommand is in squirrel and not the API. * In that case use this function to restore the previous value. * @return True iff DoCommands are allowed in the current scope. */ static bool GetAllowDoCommand(); /** * Set the current company to execute commands for or request * information about. * @param company The new company. */ static void SetCompany(CompanyID company); /** * Get the current company we are executing commands for or * requesting information about. * @return The current company. */ static CompanyID GetCompany(); /** * Get the root company, the company that the script really * runs under / for. * @return The root company. */ static CompanyID GetRootCompany(); /** * Set the cost of the last command. */ static void SetLastCost(Money last_cost); /** * Get the cost of the last command. */ static Money GetLastCost(); /** * Set a variable that can be used by callback functions to pass information. */ static void SetCallbackVariable(int index, int value); /** * Get the variable that is used by callback functions to pass information. */ static int GetCallbackVariable(int index); /** * Can we suspend the script at this moment? */ static bool CanSuspend(); /** * Get the pointer to store event data in. */ static void *&GetEventPointer(); /** * Get the pointer to store log message in. */ static void *&GetLogPointer(); /** * Get an allocated string with all control codes stripped off. */ static char *GetString(StringID string); private: /** * Store a new_vehicle_id per company. * @param vehicle_id The new VehicleID. */ static void SetNewVehicleID(VehicleID vehicle_id); /** * Store a new_sign_id per company. * @param sign_id The new SignID. */ static void SetNewSignID(SignID sign_id); /** * Store a new_group_id per company. * @param group_id The new GroupID. */ static void SetNewGroupID(GroupID group_id); /** * Store a new_goal_id per company. * @param goal_id The new GoalID. */ static void SetNewGoalID(GoalID goal_id); /** * Store a new_story_page_id per company. * @param story_page_id The new StoryPageID. */ static void SetNewStoryPageID(StoryPageID story_page_id); /** * Store a new_story_page_id per company. * @param story_page_id The new StoryPageID. */ static void SetNewStoryPageElementID(StoryPageElementID story_page_element_id); }; #endif /* SCRIPT_OBJECT_HPP */ openttd-1.5.3/src/script/api/script_infrastructure.hpp0000644000000000000000000000727012627373434021735 0ustar rootroot/* $Id: script_infrastructure.hpp 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 script_infrastructure.hpp Everything to query a company's infrastructure. */ #ifndef SCRIPT_INFRASTRUCTURE_HPP #define SCRIPT_INFRASTRUCTURE_HPP #include "script_road.hpp" #include "script_rail.hpp" /** * Class that handles all company infrastructure related functions. * @api ai game */ class ScriptInfrastructure : public ScriptObject { public: /** Infrastructure categories. */ enum Infrastructure { INFRASTRUCTURE_RAIL, ///< Rail infrastructure. INFRASTRUCTURE_SIGNALS, ///< Signal infrastructure. INFRASTRUCTURE_ROAD, ///< Road infrastructure. INFRASTRUCTURE_CANAL, ///< Canal infrastructure. INFRASTRUCTURE_STATION, ///< Station infrastructure. INFRASTRUCTURE_AIRPORT, ///< Airport infrastructure. }; /** * Return the number of rail pieces of a specific rail type for a company. * @param company The company to get the count for. * @param railtype Rail type to get the count of. * @return Count for the rail type. */ static uint32 GetRailPieceCount(ScriptCompany::CompanyID company, ScriptRail::RailType railtype); /** * Return the number of road pieces of a specific road type for a company. * @param company The company to get the count for. * @param roadtype Road type to get the count of. * @return Count for the road type. */ static uint32 GetRoadPieceCount(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype); /** * Return the number of pieces of an infrastructure category for a company. * @param company The company to get the count for. * @param infra_type Infrastructure category to get the cost of. * @return Count for the wanted category. * @note #INFRASTRUCTURE_RAIL and #INFRASTRUCTURE_ROAD return the total count for all rail/road types. */ static uint32 GetInfrastructurePieceCount(ScriptCompany::CompanyID company, Infrastructure infra_type); /** * Return the monthly maintenance costs of a specific rail type for a company. * @param company The company to get the monthly cost for. * @param railtype Rail type to get the cost of. * @return Monthly maintenance cost for the rail type. */ static Money GetMonthlyRailCosts(ScriptCompany::CompanyID company, ScriptRail::RailType railtype); /** * Return the monthly maintenance costs of a specific road type for a company. * @param company The company to get the monthly cost for. * @param roadtype Road type to get the cost of. * @return Monthly maintenance cost for the road type. */ static Money GetMonthlyRoadCosts(ScriptCompany::CompanyID company, ScriptRoad::RoadType roadtype); /** * Return the monthly maintenance costs of an infrastructure category for a company. * @param company The company to get the monthly cost for. * @param infra_type Infrastructure category to get the cost of. * @return Monthly maintenance cost for the wanted category. * @note #INFRASTRUCTURE_RAIL and #INFRASTRUCTURE_ROAD return the total cost for all rail/road types. */ static Money GetMonthlyInfrastructureCosts(ScriptCompany::CompanyID company, Infrastructure infra_type); }; #endif /* SCRIPT_INFRASTRUCTURE_HPP */ openttd-1.5.3/src/script/api/script_road.hpp0000644000000000000000000005372212627373434017605 0ustar rootroot/* $Id: script_road.hpp 26149 2013-12-08 15:44:09Z frosch $ */ /* * 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 script_road.hpp Everything to query and build roads. */ #ifndef SCRIPT_ROAD_HPP #define SCRIPT_ROAD_HPP #include "script_tile.hpp" /** * Class that handles all road related functions. * @api ai game */ class ScriptRoad : public ScriptObject { public: /** * All road related error messages. */ enum ErrorMessages { /** Base for road building / maintaining errors */ ERR_ROAD_BASE = ScriptError::ERR_CAT_ROAD << ScriptError::ERR_CAT_BIT_SIZE, /** Road works are in progress */ ERR_ROAD_WORKS_IN_PROGRESS, // [STR_ERROR_ROAD_WORKS_IN_PROGRESS] /** Drive through is in the wrong direction */ ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION, // [STR_ERROR_DRIVE_THROUGH_DIRECTION] /** Drive through roads can't be build on town owned roads */ ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD, // [STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD] /** One way roads can't have junctions */ ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS, // [STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION] }; /** * Types of road known to the game. */ enum RoadType { /* Note: these values represent part of the in-game RoadType enum */ ROADTYPE_ROAD = ::ROADTYPE_ROAD, ///< Build road objects. ROADTYPE_TRAM = ::ROADTYPE_TRAM, ///< Build tram objects. /* Custom added value, only valid for this API */ ROADTYPE_INVALID = -1, ///< Invalid RoadType. }; /** * Type of road station. */ enum RoadVehicleType { ROADVEHTYPE_BUS, ///< Build objects useable for busses and passenger trams ROADVEHTYPE_TRUCK, ///< Build objects useable for trucks and cargo trams }; /** * Types of road-related objects in the game. */ enum BuildType { BT_ROAD, ///< Build a piece of road BT_DEPOT, ///< Build a road depot BT_BUS_STOP, ///< Build a bus stop BT_TRUCK_STOP, ///< Build a truck stop }; /** * Determines whether a busstop or a truckstop is needed to transport a certain cargo. * @param cargo_type The cargo to test. * @pre ScriptCargo::IsValidCargo(cargo_type). * @return The road vehicle type needed to transport the cargo. */ static RoadVehicleType GetRoadVehicleTypeForCargo(CargoID cargo_type); /** * Checks whether the given tile is actually a tile with road that can be * used to traverse a tile. This excludes road depots and 'normal' road * stations, but includes drive through stations. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has road. */ static bool IsRoadTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a road depot. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @return True if and only if the tile has a road depot. */ static bool IsRoadDepotTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a road station. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @return True if and only if the tile has a road station. */ static bool IsRoadStationTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a drive through * road station. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @return True if and only if the tile has a drive through road station. */ static bool IsDriveThroughRoadStationTile(TileIndex tile); /** * Check if a given RoadType is available. * @param road_type The RoadType to check for. * @game @pre Valid ScriptCompanyMode active in scope. * @return True if this RoadType can be used. */ static bool IsRoadTypeAvailable(RoadType road_type); /** * Get the current RoadType set for all ScriptRoad functions. * @return The RoadType currently set. */ static RoadType GetCurrentRoadType(); /** * Set the RoadType for all further ScriptRoad functions. * @param road_type The RoadType to set. */ static void SetCurrentRoadType(RoadType road_type); /** * Check if a given tile has RoadType. * @param tile The tile to check. * @param road_type The RoadType to check for. * @pre ScriptMap::IsValidTile(tile). * @pre IsRoadTypeAvailable(road_type). * @return True if the tile contains a RoadType object. */ static bool HasRoadType(TileIndex tile, RoadType road_type); /** * Checks whether the given tiles are directly connected, i.e. whether * a road vehicle can travel from the center of the first tile to the * center of the second tile. * @param tile_from The source tile. * @param tile_to The destination tile. * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @pre ScriptMap::IsValidTile(tile_from). * @pre ScriptMap::IsValidTile(tile_to). * @pre 'tile_from' and 'tile_to' are directly neighbouring tiles. * @return True if and only if a road vehicle can go from tile_from to tile_to. */ static bool AreRoadTilesConnected(TileIndex tile_from, TileIndex tile_to); /** * Lookup function for building road parts independend on whether the * "building on slopes" setting is enabled or not. * This implementation can be used for abstract reasoning about a tile as * it needs the slope and existing road parts of the tile as information. * @param slope The slope of the tile to examine. * @param existing An array with the existing neighbours in the same format * as "start" and "end", e.g. ScriptMap.GetTileIndex(0, 1). * As a result of this all values of the existing array * must be of type integer. * @param start The tile from where the 'tile to be considered' will be * entered. This is a relative tile, so valid parameters are: * ScriptMap.GetTileIndex(0, 1), ScriptMap.GetTileIndex(0, -1), * ScriptMap.GetTileIndex(1, 0) and ScriptMap.GetTileIndex(-1, 0). * @param end The tile from where the 'tile to be considered' will be * exited. This is a relative tile, sovalid parameters are: * ScriptMap.GetTileIndex(0, 1), ScriptMap.GetTileIndex(0, -1), * ScriptMap.GetTileIndex(1, 0) and ScriptMap.GetTileIndex(-1, 0). * @pre start != end. * @pre slope must be a valid slope, i.e. one specified in ScriptTile::Slope. * @note Passing data that would be invalid in-game, e.g. existing containing * road parts that can not be build on a tile with the given slope, * does not necessarily means that -1 is returned, i.e. not all * preconditions written here or assumed by the game are extensively * checked to make sure the data entered is valid. * @return 0 when the build parts do not connect, 1 when they do connect once * they are build or 2 when building the first part automatically * builds the second part. -1 means the preconditions are not met. */ static int32 CanBuildConnectedRoadParts(ScriptTile::Slope slope, struct Array *existing, TileIndex start, TileIndex end); /** * Lookup function for building road parts independend on whether the * "building on slopes" setting is enabled or not. * This implementation can be used for reasoning about an existing tile. * @param tile The the tile to examine. * @param start The tile from where "tile" will be entered. * @param end The tile from where "tile" will be exited. * @pre start != end. * @pre tile != start. * @pre tile != end. * @pre ScriptMap.IsValidTile(tile). * @pre ScriptMap.IsValidTile(start). * @pre ScriptMap.IsValidTile(end). * @pre ScriptMap.GetDistanceManhattanToTile(tile, start) == 1. * @pre ScriptMap.GetDistanceManhattanToTile(tile, end) == 1. * @return 0 when the build parts do not connect, 1 when they do connect once * they are build or 2 when building the first part automatically * builds the second part. -1 means the preconditions are not met. */ static int32 CanBuildConnectedRoadPartsHere(TileIndex tile, TileIndex start, TileIndex end); /** * Count how many neighbours are road. * @param tile The tile to check on. * @pre ScriptMap::IsValidTile(tile). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @return 0 means no neighbour road; max value is 4. */ static int32 GetNeighbourRoadCount(TileIndex tile); /** * Gets the tile in front of a road depot. * @param depot The road depot tile. * @pre IsRoadDepotTile(depot). * @return The tile in front of the depot. */ static TileIndex GetRoadDepotFrontTile(TileIndex depot); /** * Gets the tile in front of a road station. * @param station The road station tile. * @pre IsRoadStationTile(station). * @return The tile in front of the road station. */ static TileIndex GetRoadStationFrontTile(TileIndex station); /** * Gets the tile at the back of a drive through road station. * So, one side of the drive through station is retrieved with * GetTileInFrontOfStation, the other with this function. * @param station The road station tile. * @pre IsDriveThroughRoadStationTile(station). * @return The tile at the back of the drive through road station. */ static TileIndex GetDriveThroughBackTile(TileIndex station); /** * Builds a road from the center of tile start to the center of tile end. * @param start The start tile of the road. * @param end The end tile of the road. * @pre 'start' is not equal to 'end'. * @pre ScriptMap::IsValidTile(start). * @pre ScriptMap::IsValidTile(end). * @pre 'start' and 'end' are in a straight line, i.e. * ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or * ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @exception ScriptError::ERR_ALREADY_BUILT * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @note Construction will fail if an obstacle is found between the start and end tiles. * @game @note Building a piece of road (without CompanyMode) results in a piece of road owned by towns. * @return Whether the road has been/can be build or not. */ static bool BuildRoad(TileIndex start, TileIndex end); /** * Builds a one-way road from the center of tile start to the center * of tile end. If the road already exists, it is made one-way road. * If the road already exists and is already one-way in this direction, * the road is made two-way again. If the road already exists but is * one-way in the other direction, it's made a 'no'-way road (it's * forbidden to enter the tile from any direction). * @param start The start tile of the road. * @param end The end tile of the road. * @pre 'start' is not equal to 'end'. * @pre ScriptMap::IsValidTile(start). * @pre ScriptMap::IsValidTile(end). * @pre 'start' and 'end' are in a straight line, i.e. * ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or * ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end). * @pre GetCurrentRoadType() == ROADTYPE_ROAD. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_ALREADY_BUILT * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @note Construction will fail if an obstacle is found between the start and end tiles. * @return Whether the road has been/can be build or not. */ static bool BuildOneWayRoad(TileIndex start, TileIndex end); /** * Builds a road from the edge of tile start to the edge of tile end (both * included). * @param start The start tile of the road. * @param end The end tile of the road. * @pre 'start' is not equal to 'end'. * @pre ScriptMap::IsValidTile(start). * @pre ScriptMap::IsValidTile(end). * @pre 'start' and 'end' are in a straight line, i.e. * ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or * ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @exception ScriptError::ERR_ALREADY_BUILT * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @note Construction will fail if an obstacle is found between the start and end tiles. * @game @note Building a piece of road (without CompanyMode) results in a piece of road owned by towns. * @return Whether the road has been/can be build or not. */ static bool BuildRoadFull(TileIndex start, TileIndex end); /** * Builds a one-way road from the edge of tile start to the edge of tile end * (both included). If the road already exists, it is made one-way road. * If the road already exists and is already one-way in this direction, * the road is made two-way again. If the road already exists but is * one-way in the other direction, it's made a 'no'-way road (it's * forbidden to enter the tile from any direction). * @param start The start tile of the road. * @param start The start tile of the road. * @param end The end tile of the road. * @pre 'start' is not equal to 'end'. * @pre ScriptMap::IsValidTile(start). * @pre ScriptMap::IsValidTile(end). * @pre 'start' and 'end' are in a straight line, i.e. * ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or * ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end). * @pre GetCurrentRoadType() == ROADTYPE_ROAD. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_ALREADY_BUILT * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptRoad::ERR_ROAD_ONE_WAY_ROADS_CANNOT_HAVE_JUNCTIONS * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @note Construction will fail if an obstacle is found between the start and end tiles. * @return Whether the road has been/can be build or not. */ static bool BuildOneWayRoadFull(TileIndex start, TileIndex end); /** * Builds a road depot. * @param tile Place to build the depot. * @param front The tile exactly in front of the depot. * @pre ScriptMap::IsValidTile(tile). * @pre ScriptMap::IsValidTile(front). * @pre 'tile' is not equal to 'front', but in a straight line of it. * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @exception ScriptError::ERR_AREA_NOT_CLEAR * @return Whether the road depot has been/can be build or not. */ static bool BuildRoadDepot(TileIndex tile, TileIndex front); /** * Builds a road bus or truck station. * @param tile Place to build the station. * @param front The tile exactly in front of the station. * @param road_veh_type Whether to build a truck or bus station. * @param station_id The station to join, ScriptStation::STATION_NEW or ScriptStation::STATION_JOIN_ADJACENT. * @pre ScriptMap::IsValidTile(tile). * @pre ScriptMap::IsValidTile(front). * @pre 'tile' is not equal to 'front', but in a straight line of it. * @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id). * @pre GetCurrentRoadType() == ROADTYPE_ROAD. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @exception ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION * @exception ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN * @return Whether the station has been/can be build or not. */ static bool BuildRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id); /** * Builds a drive-through road bus or truck station. * @param tile Place to build the station. * @param front A tile on the same axis with 'tile' as the station shall be oriented. * @param road_veh_type Whether to build a truck or bus station. * @param station_id The station to join, ScriptStation::STATION_NEW or ScriptStation::STATION_JOIN_ADJACENT. * @pre ScriptMap::IsValidTile(tile). * @pre ScriptMap::IsValidTile(front). * @pre 'tile' is not equal to 'front', but in a straight line of it. * @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @exception ScriptRoad::ERR_ROAD_DRIVE_THROUGH_WRONG_DIRECTION * @exception ScriptRoad::ERR_ROAD_CANNOT_BUILD_ON_TOWN_ROAD * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN * @return Whether the station has been/can be build or not. */ static bool BuildDriveThroughRoadStation(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, StationID station_id); /** * Removes a road from the center of tile start to the center of tile end. * @param start The start tile of the road. * @param end The end tile of the road. * @pre 'start' is not equal to 'end'. * @pre ScriptMap::IsValidTile(start). * @pre ScriptMap::IsValidTile(end). * @pre 'start' and 'end' are in a straight line, i.e. * ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or * ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @return Whether the road has been/can be removed or not. */ static bool RemoveRoad(TileIndex start, TileIndex end); /** * Removes a road from the edge of tile start to the edge of tile end (both * included). * @param start The start tile of the road. * @param end The end tile of the road. * @pre 'start' is not equal to 'end'. * @pre ScriptMap::IsValidTile(start). * @pre ScriptMap::IsValidTile(end). * @pre 'start' and 'end' are in a straight line, i.e. * ScriptMap::GetTileX(start) == ScriptMap::GetTileX(end) or * ScriptMap::GetTileY(start) == ScriptMap::GetTileY(end). * @pre IsRoadTypeAvailable(GetCurrentRoadType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @return Whether the road has been/can be removed or not. */ static bool RemoveRoadFull(TileIndex start, TileIndex end); /** * Removes a road depot. * @param tile Place to remove the depot from. * @pre ScriptMap::IsValidTile(tile). * @pre Tile is a road depot. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @return Whether the road depot has been/can be removed or not. */ static bool RemoveRoadDepot(TileIndex tile); /** * Removes a road bus or truck station. * @param tile Place to remove the station from. * @pre ScriptMap::IsValidTile(tile). * @pre Tile is a road station. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_VEHICLE_IN_THE_WAY * @return Whether the station has been/can be removed or not. */ static bool RemoveRoadStation(TileIndex tile); /** * Get the baseprice of building a road-related object. * @param roadtype the roadtype that is build (on) * @param build_type the type of object to build * @pre IsRoadTypeAvailable(railtype) * @return The baseprice of building the given object. */ static Money GetBuildCost(RoadType roadtype, BuildType build_type); /** * Get the maintenance cost factor of a roadtype. * @param roadtype The roadtype to get the maintenance factor of. * @pre IsRoadTypeAvailable(roadtype) * @return Maintenance cost factor of the roadtype. */ static uint16 GetMaintenanceCostFactor(RoadType roadtype); private: /** * Internal function used by Build(OneWay)Road(Full). */ static bool _BuildRoadInternal(TileIndex start, TileIndex end, bool one_way, bool full); /** * Internal function used by Build(DriveThrough)RoadStation. */ static bool _BuildRoadStationInternal(TileIndex tile, TileIndex front, RoadVehicleType road_veh_type, bool drive_through, StationID station_id); }; #endif /* SCRIPT_ROAD_HPP */ openttd-1.5.3/src/script/api/doxygen_filter.sh0000755000000000000000000000201112627373434020125 0ustar rootroot#!/bin/bash # $Id: doxygen_filter.sh 23610 2011-12-19 20:56:42Z truebrain $ # 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 . # Set neutral locale so sort behaves the same everywhere LC_ALL=C export LC_ALL # We really need gawk for this! AWK=gawk ${AWK} --version > /dev/null 2> /dev/null if [ "$?" != "0" ]; then echo "This script needs gawk to run properly" exit 1 fi case $2 in *ai_changelog.hpp) cat $2; exit 0;; *game_changelog.hpp) cat $2; exit 0;; esac ${AWK} -v api=$1 -f doxygen_filter.awk $2 openttd-1.5.3/src/script/api/script_cargomonitor.hpp0000644000000000000000000001307712627373434021362 0ustar rootroot/* $Id: script_cargomonitor.hpp 26685 2014-07-12 17:04:14Z alberth $ */ /* * 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 script_cargomonitor.hpp Everything to monitor cargo pickup and deliveries by companies. */ #ifndef SCRIPT_CARGO_MONITOR_HPP #define SCRIPT_CARGO_MONITOR_HPP #include "script_list.hpp" #include "script_object.hpp" #include "script_company.hpp" #include "../../cargomonitor.h" /** * Class that handles all cargo movement monitoring related functions. * * To get an understanding of what users are transporting, this class provides cargo pick-up and delivery monitoring functions. * It works as follows: * - Select a company, a cargo-type, and an industry that gets the cargo triplet. * - Perform a call to #GetIndustryDeliveryAmount, setting 'keep_monitoring' to \c true. * The return value is not important, but from this moment the program accumulates all deliveries by * the given company to the given industry of the given cargo type. * - Some time later, perform another call to #GetIndustryDeliveryAmount. It returns the accumulated * amount of cargo that the company has delivered. * The call causes the collected amount to be reset. On the next call you will thus always get the * delivered amount since the previous call. * - When monitoring the deliveries is not interesting any more, set 'keep_monitoring' to \c false. * The collecting process that happens between calls is stopped. * * In the same way you can monitor town deliveries, and you can monitor pick-up from towns and industries. * The latter get added at the moment the cargo is delivered. This prevents users from getting credit for * picking up cargo without delivering it. * * The active monitors are saved and loaded. Upon bankruptcy or company takeover, the cargo monitors are * automatically stopped for that company. You can reset to the empty state with #StopAllMonitoring. * * @api game */ class ScriptCargoMonitor : public ScriptObject { public: /** * Get the amount of cargo delivered to a town by a company since the last query, and update the monitoring state. * @param company %Company to query. * @param cargo Cargo type to query. * @param town_id %Town to query. * @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends. * @return Amount of delivered cargo of the given cargo type to the given town by the given company since the last call, or * \c -1 if a parameter is out-of-bound. */ static int32 GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring); /** * Get the amount of cargo delivered to an industry by a company since the last query, and update the monitoring state. * @param company %Company to query. * @param cargo Cargo type to query. * @param industry_id %Industry to query. * @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends. * @return Amount of delivered cargo of the given cargo type to the given industry by the given company since the last call, or * \c -1 if a parameter is out-of-bound. */ static int32 GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring); /** * Get the amount of cargo picked up (and delivered) from a town by a company since the last query, and update the monitoring state. * @param company %Company to query. * @param cargo Cargo type to query. * @param town_id %Town to query. * @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends. * @return Amount of picked up cargo of the given cargo type to the given town by the given company since the last call, or * \c -1 if a parameter is out-of-bound. * @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it. */ static int32 GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring); /** * Get the amount of cargo picked up (and delivered) from an industry by a company since the last query, and update the monitoring state. * @param company %Company to query. * @param cargo Cargo type to query. * @param industry_id %Industry to query. * @param keep_monitoring If \c true, the given combination continues to be monitored for the next call. If \c false, monitoring ends. * @return Amount of picked up cargo of the given cargo type to the given industry by the given company since the last call, or * \c -1 if a parameter is out-of-bound. * @note Amounts of picked-up cargo are added during final delivery of it, to prevent users from getting credit for picking up without delivering it. */ static int32 GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring); /** Stop monitoring everything. */ static void StopAllMonitoring(); }; #endif /* SCRIPT_CARGO_MONITOR_HPP */ openttd-1.5.3/src/script/api/script_event.hpp0000644000000000000000000000603512627373433017773 0ustar rootroot/* $Id: script_event.hpp 24291 2012-05-26 14:16:45Z frosch $ */ /* * 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 script_event.hpp Everything to handle events from the game. */ #ifndef SCRIPT_EVENT_HPP #define SCRIPT_EVENT_HPP #include "script_object.hpp" /** * Class that handles all event related functions. * You can lookup the type, and than convert it to the real event-class. * That way you can request more detailed information about the event. * @api ai game */ class ScriptEvent : public ScriptObject { public: /** * The type of event. Needed to lookup the detailed class. */ enum ScriptEventType { ET_INVALID = 0, ET_TEST, ET_SUBSIDY_OFFER, ET_SUBSIDY_OFFER_EXPIRED, ET_SUBSIDY_AWARDED, ET_SUBSIDY_EXPIRED, ET_ENGINE_PREVIEW, ET_COMPANY_NEW, ET_COMPANY_IN_TROUBLE, ET_COMPANY_ASK_MERGER, ET_COMPANY_MERGER, ET_COMPANY_BANKRUPT, ET_VEHICLE_CRASHED, ET_VEHICLE_LOST, ET_VEHICLE_WAITING_IN_DEPOT, ET_VEHICLE_UNPROFITABLE, ET_INDUSTRY_OPEN, ET_INDUSTRY_CLOSE, ET_ENGINE_AVAILABLE, ET_STATION_FIRST_VEHICLE, ET_DISASTER_ZEPPELINER_CRASHED, ET_DISASTER_ZEPPELINER_CLEARED, ET_TOWN_FOUNDED, ET_AIRCRAFT_DEST_TOO_FAR, ET_ADMIN_PORT, ET_WINDOW_WIDGET_CLICK, ET_GOAL_QUESTION_ANSWER, ET_EXCLUSIVE_TRANSPORT_RIGHTS, ET_ROAD_RECONSTRUCTION, }; /** * Constructor of ScriptEvent, to get the type of event. */ ScriptEvent(ScriptEvent::ScriptEventType type) : type(type) {} /** * Get the event-type. * @return The @c ScriptEventType. */ ScriptEventType GetEventType() { return this->type; } protected: /** * The type of this event. */ ScriptEventType type; }; /** * Class that handles all event related functions. * @api ai game * @note it is not needed to create an instance of ScriptEvent to access it, as * all members are static, and all data is stored script instance-wide. */ class ScriptEventController : public ScriptObject { public: /** * Check if there is an event waiting. * @return true if there is an event on the stack. */ static bool IsEventWaiting(); /** * Get the next event. * @return a class of the event-child issues. */ static ScriptEvent *GetNextEvent(); /** * Insert an event to the queue for the company. * @param event The event to insert. * @api -all */ static void InsertEvent(ScriptEvent *event); /** * Free the event pointer. * @api -all */ static void FreeEventPointer(); private: /** * Create the event pointer. */ static void CreateEventPointer(); }; #endif /* SCRIPT_EVENT_HPP */ openttd-1.5.3/src/script/api/script_station.hpp0000644000000000000000000003435112627373433020335 0ustar rootroot/* $Id: script_station.hpp 27123 2015-01-20 19:11:31Z frosch $ */ /* * 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 script_station.hpp Everything to query and build stations. */ #ifndef SCRIPT_STATION_HPP #define SCRIPT_STATION_HPP #include "script_road.hpp" #include "script_basestation.hpp" #include "../../station_type.h" /** * Class that handles all station related functions. * @api ai game */ class ScriptStation : public ScriptBaseStation { public: /** * All station related error messages. */ enum ErrorMessages { /** Base for station related errors */ ERR_STATION_BASE = ScriptError::ERR_CAT_STATION << ScriptError::ERR_CAT_BIT_SIZE, /** The station is build too close to another station, airport or dock */ ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION, // [STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT, STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION, STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK] /** There are too many stations, airports and docks in the game */ ERR_STATION_TOO_MANY_STATIONS, // [STR_ERROR_TOO_MANY_STATIONS_LOADING, STR_ERROR_TOO_MANY_TRUCK_STOPS, STR_ERROR_TOO_MANY_BUS_STOPS] /** There are too many stations, airports of docks in a town */ ERR_STATION_TOO_MANY_STATIONS_IN_TOWN, // [STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT] }; /** * Type of stations known in the game. */ enum StationType { /* Note: these values represent part of the in-game StationFacility enum */ STATION_TRAIN = (int)::FACIL_TRAIN, ///< Train station STATION_TRUCK_STOP = (int)::FACIL_TRUCK_STOP, ///< Truck station STATION_BUS_STOP = (int)::FACIL_BUS_STOP, ///< Bus station STATION_AIRPORT = (int)::FACIL_AIRPORT, ///< Airport STATION_DOCK = (int)::FACIL_DOCK, ///< Dock STATION_ANY = STATION_TRAIN | STATION_TRUCK_STOP | STATION_BUS_STOP | STATION_AIRPORT | STATION_DOCK, ///< All station types }; /** * Checks whether the given station is valid and owned by you. * @param station_id The station to check. * @return True if and only if the station is valid. */ static bool IsValidStation(StationID station_id); /** * Get the owner of a station. * @param station_id The station to get the owner of. * @pre IsValidStation(station_id). * @return The owner the station has. * @api -ai */ static ScriptCompany::CompanyID GetOwner(StationID station_id); /** * Get the StationID of a tile, if there is a station. * @param tile The tile to find the stationID of * @return StationID of the station. * @post Use IsValidStation() to see if the station is valid. */ static StationID GetStationID(TileIndex tile); /** * See how much cargo there is waiting on a station. * @param station_id The station to get the cargo-waiting of. * @param cargo_id The cargo to get the cargo-waiting of. * @pre IsValidStation(station_id). * @pre IsValidCargo(cargo_id). * @return The amount of units waiting at the station. */ static int32 GetCargoWaiting(StationID station_id, CargoID cargo_id); /** * See how much cargo with a specific source station there is waiting on a station. * @param station_id The station to get the cargo-waiting of. * @param from_station_id The source station of the cargo. Pass STATION_INVALID to get cargo of which the source has been deleted. * @param cargo_id The cargo to get the cargo-waiting of. * @pre IsValidStation(station_id). * @pre IsValidStation(from_station_id) || from_station_id == STATION_INVALID. * @pre IsValidCargo(cargo_id). * @return The amount of units waiting at the station originating from from_station_id. * @note source station means, the station where cargo was first loaded. */ static int32 GetCargoWaitingFrom(StationID station_id, StationID from_station_id, CargoID cargo_id); /** * See how much cargo with a specific via-station there is waiting on a station. * @param station_id The station to get the cargo-waiting of. * @param via_station_id The next station the cargo is going to. Pass STATION_INVALID to get waiting cargo for "via any station". * @param cargo_id The cargo to get the cargo-waiting of. * @pre IsValidStation(station_id). * @pre IsValidStation(via_station_id) || via_station_id == STATION_INVALID. * @pre IsValidCargo(cargo_id). * @return The amount of units waiting at the station with via_station_id as next hop. * @note if ScriptCargo.GetCargoDistributionType(cargo_id) == ScriptCargo.DT_MANUAL, then all waiting cargo will have STATION_INVALID as next hop. */ static int32 GetCargoWaitingVia(StationID station_id, StationID via_station_id, CargoID cargo_id); /** * See how much cargo with a specific via-station and source station there is waiting on a station. * @param station_id The station to get the cargo-waiting of. * @param from_station_id The source station of the cargo. Pass STATION_INVALID to get cargo of which the source has been deleted. * @param via_station_id The next station the cargo is going to. Pass STATION_INVALID to get waiting cargo for "via any station". * @param cargo_id The cargo to get the cargo-waiting of. * @pre IsValidStation(station_id). * @pre IsValidStation(from_station_id) || from_station_id == STATION_INVALID. * @pre IsValidStation(via_station_id) || via_station_id == STATION_INVALID. * @pre IsValidCargo(cargo_id). * @return The amount of units waiting at the station with from_station_id as source and via_station_id as next hop. * @note if ScriptCargo.GetCargoDistributionType(cargo_id) == ScriptCargo.DT_MANUAL, then all waiting cargo will have STATION_INVALID as next hop. */ static int32 GetCargoWaitingFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id); /** * See how much cargo was planned to pass (including production and consumption) this station per month. * @param station_id The station to get the planned flow for. * @param cargo_id The cargo type to get the planned flow for. * @pre IsValidStation(station_id). * @pre IsValidCargo(cargo_id). * @return The amount of cargo units planned to pass the station per month. */ static int32 GetCargoPlanned(StationID station_id, CargoID cargo_id); /** * See how much cargo from the specified origin was planned to pass (including production and consumption) this station per month. * @param station_id The station to get the planned flow for. * @param from_station_id The station the cargo originates at. * @param cargo_id The cargo type to get the planned flow for. * @pre IsValidStation(station_id). * @pre IsValidStation(from_station_id) || from_station_id == STATION_INVALID. * @pre IsValidCargo(cargo_id). * @return The amount of cargo units from the specified origin planned to pass the station per month. */ static int32 GetCargoPlannedFrom(StationID station_id, StationID from_station_id, CargoID cargo_id); /** * See how much cargo was planned to pass (including production and consumption) this station per month, heading for the specified next hop. * @param station_id The station to get the planned flow for. * @param via_station_id The next station the cargo will go on to. * @param cargo_id The cargo type to get the planned flow for. * @pre IsValidStation(station_id). * @pre IsValidStation(via_station_id) || via_station_id == STATION_INVALID. * @pre IsValidCargo(cargo_id). * @return The amount of cargo units planned to pass the station per month, going via the specified next hop. * @note Cargo planned to go "via" the same station that's being queried is actually planned to be consumed there. */ static int32 GetCargoPlannedVia(StationID station_id, StationID via_station_id, CargoID cargo_id); /** * See how much cargo from the specified origin was planned to pass this station per month, * heading for the specified next hop. * @param station_id The station to get the planned flow for. * @param from_station_id The station the cargo originates at. * @param via_station_id The next station the cargo will go on to. * @param cargo_id The cargo type to get the planned flow for. * @pre IsValidStation(station_id). * @pre IsValidStation(from_station_id) || from_station_id == STATION_INVALID. * @pre IsValidStation(via_station_id) || via_station_id == STATION_INVALID. * @pre IsValidCargo(cargo_id). * @return The amount of cargo units from the specified origin planned to pass the station per month, going via the specified next hop. * @note Cargo planned to go "via" the same station that's being queried is actually planned to be consumed there. * @note Cargo planned to pass "from" the same station that's being queried is actually produced there. */ static int32 GetCargoPlannedFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id); /** * Check whether the given cargo at the given station a rating. * @param station_id The station to get the cargo-rating state of. * @param cargo_id The cargo to get the cargo-rating state of. * @pre IsValidStation(station_id). * @pre IsValidCargo(cargo_id). * @return True if the cargo has a rating, otherwise false. */ static bool HasCargoRating(StationID station_id, CargoID cargo_id); /** * See how high the rating is of a cargo on a station. * @param station_id The station to get the cargo-rating of. * @param cargo_id The cargo to get the cargo-rating of. * @pre IsValidStation(station_id). * @pre IsValidCargo(cargo_id). * @pre HasCargoRating(station_id, cargo_id). * @return The rating in percent of the cargo on the station. */ static int32 GetCargoRating(StationID station_id, CargoID cargo_id); /** * Get the coverage radius of this type of station. * @param station_type The type of station. * @pre station_type != STATION_AIRPORT. * @return The radius in tiles. * @note Coverage radius of airports needs to be requested via ScriptAirport::GetAirportCoverageRadius(), as it requires AirportType. */ static int32 GetCoverageRadius(ScriptStation::StationType station_type); /** * Get the coverage radius of this station. * @param station_id The station to get the coverage radius of. * @pre IsValidStation(station_id). * @return The radius in tiles. */ static int32 GetStationCoverageRadius(StationID station_id); /** * Get the manhattan distance from the tile to the ScriptStation::GetLocation() * of the station. * @param station_id The station to get the distance to. * @param tile The tile to get the distance to. * @pre IsValidStation(station_id). * @return The distance between station and tile. */ static int32 GetDistanceManhattanToTile(StationID station_id, TileIndex tile); /** * Get the square distance from the tile to the ScriptStation::GetLocation() * of the station. * @param station_id The station to get the distance to. * @param tile The tile to get the distance to. * @pre IsValidStation(station_id). * @return The distance between station and tile. */ static int32 GetDistanceSquareToTile(StationID station_id, TileIndex tile); /** * Find out if this station is within the rating influence of a town. * The service quality of stations with signs within this radius * influences the rating of the town. * @param station_id The station to check. * @param town_id The town to check. * @return True if the tile is within the rating influence of the town. */ static bool IsWithinTownInfluence(StationID station_id, TownID town_id); /** * Check if any part of the station contains a station of the type * StationType * @param station_id The station to look at. * @param station_type The StationType to look for. * @return True if the station has a station part of the type StationType. */ static bool HasStationType(StationID station_id, StationType station_type); /** * Check if any part of the station contains a station of the type * RoadType. * @param station_id The station to look at. * @param road_type The RoadType to look for. * @return True if the station has a station part of the type RoadType. */ static bool HasRoadType(StationID station_id, ScriptRoad::RoadType road_type); /** * Get the town that was nearest to the given station when the station was built. * @param station_id The station to look at. * @return The TownID of the town whose center tile was closest to the station * at the time the station was built. * @note There is no guarantee that the station is even near the returned town * nor that the returns town is closest to the station now. A station that was * 'walked' to the other end of the map will still return the same town. Also, * towns grow, towns change. So don't depend on this value too much. */ static TownID GetNearestTown(StationID station_id); /** * Get the open/closed state of an airport. * @param station_id The airport to look at. * @pre IsValidStation(station_id). * @pre HasStationType(station_id, STATION_AIRPORT). * @return True if the airport is currently closed to incoming traffic. */ static bool IsAirportClosed(StationID station_id); /** * Toggle the open/closed state of an airport. * @param station_id The airport to modify. * @pre IsValidStation(station_id). * @pre HasStationType(station_id, STATION_AIRPORT). * @return True if the state was toggled successfully. */ static bool OpenCloseAirport(StationID station_id); private: template static bool IsCargoRequestValid(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id); template static int32 CountCargoWaiting(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id); template static int32 CountCargoPlanned(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id); }; DECLARE_ENUM_AS_BIT_SET(ScriptStation::StationType) #endif /* SCRIPT_STATION_HPP */ openttd-1.5.3/src/script/api/script_story_page.hpp0000644000000000000000000002256712627373434021037 0ustar rootroot/* $Id: script_story_page.hpp 26307 2014-02-06 19:50:34Z zuu $ */ /* * 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 script_story_page.hpp Everything to manipulate a story page. */ #ifndef SCRIPT_STORY_HPP #define SCRIPT_STORY_HPP #include "script_company.hpp" #include "script_date.hpp" #include "../../story_type.h" #include "../../story_base.h" /** * Class that handles story page related functions. * * To create a page: * 1. Create the page * 2. Create page elements that will be appended to the page in the order which they are created. * * Pages can be either global or company specific. It is possible to mix, but the only mixed solution * that will work is to have all global pages first. Once you create the first company specific page, * it is not recommended to add additional global pages unless you clear up all pages first. * * Page elements are stacked vertically on a page. If goal elements are used, the element will * become empty if the goal is removed while the page still exist. Instead of removing the goal, * you can mark it as complete and the Story Book will show that the goal is completed. * * Mind that users might want to go back to old pages later on. Thus do not remove pages in * the story book unless you really need to. * * @api game */ class ScriptStoryPage : public ScriptObject { public: /** * The story page IDs. */ enum StoryPageID { /* Note: these values represent part of the in-game StoryPageID enum */ STORY_PAGE_INVALID = ::INVALID_STORY_PAGE, ///< An invalid story page id. }; /** * The story page element IDs. */ enum StoryPageElementID { /* Note: these values represent part of the in-game StoryPageElementID enum */ STORY_PAGE_ELEMENT_INVALID = ::INVALID_STORY_PAGE_ELEMENT, ///< An invalid story page element id. }; /** * Story page element types. */ enum StoryPageElementType { SPET_TEXT = ::SPET_TEXT, ///< An element that displays a block of text. SPET_LOCATION = ::SPET_LOCATION, ///< An element that displays a single line of text along with a button to view the referenced location. SPET_GOAL = ::SPET_GOAL, ///< An element that displays a goal. }; /** * Check whether this is a valid story page ID. * @param story_page_id The StoryPageID to check. * @return True if and only if this story page is valid. */ static bool IsValidStoryPage(StoryPageID story_page_id); /** * Check whether this is a valid story page element ID. * @param story_page_element_id The StoryPageElementID to check. * @return True if and only if this story page element is valid. */ static bool IsValidStoryPageElement(StoryPageElementID story_page_element_id); /** * Create a new story page. * @param company The company to create the story page for, or ScriptCompany::COMPANY_INVALID for all. * @param title Page title (can be either a raw string, a ScriptText object, or null). * @return The new StoryPageID, or STORY_PAGE_INVALID if it failed. * @pre No ScriptCompanyMode may be in scope. * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID. */ static StoryPageID New(ScriptCompany::CompanyID company, Text *title); /** * Create a new story page element. * @param story_page_id The page id of the story page which the page element should be appended to. * @param type Which page element type to create. * @param reference A reference value to the object that is refered to by some page element types. When type is SPET_GOAL, this is the goal ID. When type is SPET_LOCATION, this is the TileIndex. * @param text The body text of page elements that allow custom text. (SPET_TEXT and SPET_LOCATION) * @return The new StoryPageElementID, or STORY_PAGE_ELEMENT_INVALID if it failed. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page). * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && len(text) != 0). * @pre type != SPET_LOCATION || ScriptMap::IsValidTile(reference). * @pre type != SPET_GOAL || ScriptGoal::IsValidGoal(reference). * @pre if type is SPET_GOAL and story_page is a global page, then referenced goal must be global. */ static StoryPageElementID NewElement(StoryPageID story_page_id, StoryPageElementType type, uint32 reference, Text *text); /** * Update the content of a page element * @param story_page_element_id The page id of the story page which the page element should be appended to. * @param reference A reference value to the object that is refered to by some page element types. See also NewElement. * @param text The body text of page elements that allow custom text. See also NewElement. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page). * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && len(text) != 0). * @pre type != SPET_LOCATION || ScriptMap::IsValidTile(reference). * @pre type != SPET_GOAL || ScriptGoal::IsValidGoal(reference). * @pre if type is SPET_GOAL and story_page is a global page, then referenced goal must be global. */ static bool UpdateElement(StoryPageElementID story_page_element_id, uint32 reference, Text *text); /** * Get story page sort value. Each page has a sort value that is internally assigned and used * to sort the pages in the story book. OpenTTD maintains this number so that the sort order * is perceived. This API exist only so that you can sort ScriptStoryPageList the same order * as in GUI. You should not use this number for anything else. * @param story_page_id The story page to get the sort value of. * @return Page sort value. */ static uint32 GetPageSortValue(StoryPageID story_page_id); /** * Get story page element sort value. Each page element has a sort value that is internally * assigned and used to sort the page elements within a page of the story book. OpenTTD * maintains this number so that the sort order is perceived. This API exist only so that * you can sort ScriptStoryPageList the same order as in GUI. You should not use this number * for anything else. * @param story_page_element_id The story page element to get the sort value of. * @return Page element sort value. */ static uint32 GetPageElementSortValue(StoryPageElementID story_page_element_id); /** * Get the company which the page belongs to. If the page is global, * ScriptCompany::COMPANY_INVALID is returned. * @param story_page_id The story page to get the company for. * @return owner company or ScriptCompany::COMPANY_INVALID * @pre IsValidStoryPage(story_page_id). */ static ScriptCompany::CompanyID GetCompany(StoryPageID story_page_id); /** * Get the page date which is displayed at the top of each page. * @param story_page_id The story page to get the date of. * @return The date * @pre IsValidStoryPage(story_page_id). */ static ScriptDate::Date GetDate(StoryPageID story_page_id); /** * Update date of a story page. The date is shown in the top left of the page * @param story_page_id The story page to set the date for. * @param date Date to display at the top of story page or ScriptDate::DATE_INVALID to disable showing date on this page. (also, @see ScriptDate) * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page_id). */ static bool SetDate(StoryPageID story_page_id, ScriptDate::Date date); /** * Update title of a story page. The title is shown in the page selector drop down. * @param story_page_id The story page to update. * @param title Page title (can be either a raw string, a ScriptText object, or null). * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page_id). */ static bool SetTitle(StoryPageID story_page_id, Text *title); /** * Opens the Story Book if not yet open and selects the given page. * @param story_page_id The story page to update. If it is a global page, clients of all * companies are affecetd. Otherwise only the clients of the company which the page belongs * to are affected. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page_id). */ static bool Show(StoryPageID story_page_id); /** * Remove a story page and all the page elements * associated with it. * @param story_page_id The story page to remove. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPage(story_page_id). */ static bool Remove(StoryPageID story_page_id); /** * Removes a story page element. * @param story_page_element_id The story page element to remove. * @return True if the action succeeded. * @pre No ScriptCompanyMode may be in scope. * @pre IsValidStoryPageElement(story_page_element_id). */ static bool RemoveElement(StoryPageElementID story_page_element_id); }; #endif /* SCRIPT_STORY_HPP */ openttd-1.5.3/src/script/api/script_game.cpp0000644000000000000000000000267312627373434017563 0ustar rootroot/* $Id: script_game.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_game.cpp Implementation of ScriptGame. */ #include "../../stdafx.h" #include "script_game.hpp" #include "../../command_type.h" #include "../../settings_type.h" #include "../../network/network.h" #include "../../safeguards.h" /* static */ bool ScriptGame::Pause() { return ScriptObject::DoCommand(0, PM_PAUSED_GAME_SCRIPT, 1, CMD_PAUSE); } /* static */ bool ScriptGame::Unpause() { return ScriptObject::DoCommand(0, PM_PAUSED_GAME_SCRIPT, 0, CMD_PAUSE); } /* static */ bool ScriptGame::IsPaused() { return !!_pause_mode; } /* static */ ScriptGame::LandscapeType ScriptGame::GetLandscape() { return (ScriptGame::LandscapeType)_settings_game.game_creation.landscape; } /* static */ bool ScriptGame::IsMultiplayer() { #ifdef ENABLE_NETWORK return _network_server; #else return false; #endif } openttd-1.5.3/src/script/api/script_stationlist.cpp0000644000000000000000000002132412627373434021221 0ustar rootroot/* $Id: script_stationlist.cpp 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 script_stationlist.cpp Implementation of ScriptStationList and friends. */ #include "../../stdafx.h" #include "script_stationlist.hpp" #include "script_vehicle.hpp" #include "script_cargo.hpp" #include "../../station_base.h" #include "../../vehicle_base.h" #include "../../safeguards.h" ScriptStationList::ScriptStationList(ScriptStation::StationType station_type) { Station *st; FOR_ALL_STATIONS(st) { if ((st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && (st->facilities & station_type) != 0) this->AddItem(st->index); } } ScriptStationList_Vehicle::ScriptStationList_Vehicle(VehicleID vehicle_id) { if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return; Vehicle *v = ::Vehicle::Get(vehicle_id); for (Order *o = v->GetFirstOrder(); o != NULL; o = o->next) { if (o->IsType(OT_GOTO_STATION)) this->AddItem(o->GetDestination()); } } ScriptStationList_Cargo::ScriptStationList_Cargo(ScriptStationList_Cargo::CargoMode mode, ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo, StationID other_station) { switch (mode) { case CM_WAITING: ScriptStationList_CargoWaiting(selector, station_id, cargo, other_station).SwapList(this); break; case CM_PLANNED: ScriptStationList_CargoPlanned(selector, station_id, cargo, other_station).SwapList(this); break; default: NOT_REACHED(); } } ScriptStationList_CargoWaiting::ScriptStationList_CargoWaiting( ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo, StationID other_station) { switch (selector) { case CS_BY_FROM: ScriptStationList_CargoWaitingByFrom(station_id, cargo).SwapList(this); break; case CS_VIA_BY_FROM: ScriptStationList_CargoWaitingViaByFrom(station_id, cargo, other_station).SwapList(this); break; case CS_BY_VIA: ScriptStationList_CargoWaitingByVia(station_id, cargo).SwapList(this); break; case CS_FROM_BY_VIA: ScriptStationList_CargoWaitingFromByVia(station_id, cargo, other_station).SwapList(this); break; default: NOT_REACHED(); } } ScriptStationList_CargoPlanned::ScriptStationList_CargoPlanned( ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo, StationID other_station) { switch (selector) { case CS_BY_FROM: ScriptStationList_CargoPlannedByFrom(station_id, cargo).SwapList(this); break; case CS_VIA_BY_FROM: ScriptStationList_CargoPlannedViaByFrom(station_id, cargo, other_station).SwapList(this); break; case CS_BY_VIA: ScriptStationList_CargoPlannedByVia(station_id, cargo).SwapList(this); break; case CS_FROM_BY_VIA: ScriptStationList_CargoPlannedFromByVia(station_id, cargo, other_station).SwapList(this); break; default: NOT_REACHED(); } } class CargoCollector { public: CargoCollector(ScriptStationList_Cargo *parent, StationID station_id, CargoID cargo, StationID other); ~CargoCollector() ; template void Update(StationID from, StationID via, uint amount); const GoodsEntry *GE() const { return ge; } private: void SetValue(); ScriptStationList_Cargo *list; const GoodsEntry *ge; StationID other_station; StationID last_key; uint amount; }; CargoCollector::CargoCollector(ScriptStationList_Cargo *parent, StationID station_id, CargoID cargo, StationID other) : list(parent), ge(NULL), other_station(other), last_key(INVALID_STATION), amount(0) { if (!ScriptStation::IsValidStation(station_id)) return; if (!ScriptCargo::IsValidCargo(cargo)) return; this->ge = &(Station::Get(station_id)->goods[cargo]); } CargoCollector::~CargoCollector() { this->SetValue(); } void CargoCollector::SetValue() { if (this->amount > 0) { if (this->list->HasItem(this->last_key)) { this->list->SetValue(this->last_key, this->list->GetValue(this->last_key) + this->amount); } else { this->list->AddItem(this->last_key, this->amount); } } } template void CargoCollector::Update(StationID from, StationID via, uint amount) { StationID key = INVALID_STATION; switch (Tselector) { case ScriptStationList_Cargo::CS_VIA_BY_FROM: if (via != this->other_station) return; /* fall through */ case ScriptStationList_Cargo::CS_BY_FROM: key = from; break; case ScriptStationList_Cargo::CS_FROM_BY_VIA: if (from != this->other_station) return; /* fall through */ case ScriptStationList_Cargo::CS_BY_VIA: key = via; break; } if (key == this->last_key) { this->amount += amount; } else { this->SetValue(); this->amount = amount; this->last_key = key; } } template void ScriptStationList_CargoWaiting::Add(StationID station_id, CargoID cargo, StationID other_station) { CargoCollector collector(this, station_id, cargo, other_station); if (collector.GE() == NULL) return; StationCargoList::ConstIterator iter = collector.GE()->cargo.Packets()->begin(); StationCargoList::ConstIterator end = collector.GE()->cargo.Packets()->end(); for (; iter != end; ++iter) { collector.Update((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count()); } } template void ScriptStationList_CargoPlanned::Add(StationID station_id, CargoID cargo, StationID other_station) { CargoCollector collector(this, station_id, cargo, other_station); if (collector.GE() == NULL) return; FlowStatMap::const_iterator iter = collector.GE()->flows.begin(); FlowStatMap::const_iterator end = collector.GE()->flows.end(); for (; iter != end; ++iter) { const FlowStat::SharesMap *shares = iter->second.GetShares(); uint prev = 0; for (FlowStat::SharesMap::const_iterator flow_iter = shares->begin(); flow_iter != shares->end(); ++flow_iter) { collector.Update(iter->first, flow_iter->second, flow_iter->first - prev); prev = flow_iter->first; } } } ScriptStationList_CargoWaitingByFrom::ScriptStationList_CargoWaitingByFrom(StationID station_id, CargoID cargo) { this->Add(station_id, cargo); } ScriptStationList_CargoWaitingViaByFrom::ScriptStationList_CargoWaitingViaByFrom( StationID station_id, CargoID cargo, StationID via) { CargoCollector collector(this, station_id, cargo, via); if (collector.GE() == NULL) return; std::pair range = collector.GE()->cargo.Packets()->equal_range(via); for (StationCargoList::ConstIterator iter = range.first; iter != range.second; ++iter) { collector.Update((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count()); } } ScriptStationList_CargoWaitingByVia::ScriptStationList_CargoWaitingByVia(StationID station_id, CargoID cargo) { this->Add(station_id, cargo); } ScriptStationList_CargoWaitingFromByVia::ScriptStationList_CargoWaitingFromByVia( StationID station_id, CargoID cargo, StationID from) { this->Add(station_id, cargo, from); } ScriptStationList_CargoPlannedByFrom::ScriptStationList_CargoPlannedByFrom(StationID station_id, CargoID cargo) { this->Add(station_id, cargo); } ScriptStationList_CargoPlannedViaByFrom::ScriptStationList_CargoPlannedViaByFrom( StationID station_id, CargoID cargo, StationID via) { this->Add(station_id, cargo, via); } ScriptStationList_CargoPlannedByVia::ScriptStationList_CargoPlannedByVia(StationID station_id, CargoID cargo) { this->Add(station_id, cargo); } ScriptStationList_CargoPlannedFromByVia::ScriptStationList_CargoPlannedFromByVia( StationID station_id, CargoID cargo, StationID from) { CargoCollector collector(this, station_id, cargo, from); if (collector.GE() == NULL) return; FlowStatMap::const_iterator iter = collector.GE()->flows.find(from); if (iter == collector.GE()->flows.end()) return; const FlowStat::SharesMap *shares = iter->second.GetShares(); uint prev = 0; for (FlowStat::SharesMap::const_iterator flow_iter = shares->begin(); flow_iter != shares->end(); ++flow_iter) { collector.Update(iter->first, flow_iter->second, flow_iter->first - prev); prev = flow_iter->first; } } openttd-1.5.3/src/script/api/script_grouplist.hpp0000644000000000000000000000211712627373434020700 0ustar rootroot/* $Id: script_grouplist.hpp 23370 2011-11-29 23:27:26Z truebrain $ */ /* * 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 script_grouplist.hpp List all the groups (you own). */ #ifndef SCRIPT_GROUPLIST_HPP #define SCRIPT_GROUPLIST_HPP #include "script_list.hpp" /** * Creates a list of groups of which you are the owner. * @note Neither ScriptGroup::GROUP_ALL nor ScriptGroup::GROUP_DEFAULT is in this list. * @api ai * @ingroup ScriptList */ class ScriptGroupList : public ScriptList { public: ScriptGroupList(); }; #endif /* SCRIPT_GROUPLIST_HPP */ openttd-1.5.3/src/script/api/script_bridgelist.hpp0000644000000000000000000000241512627373434021001 0ustar rootroot/* $Id: script_bridgelist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_bridgelist.hpp List all the bridges. */ #ifndef SCRIPT_BRIDGELIST_HPP #define SCRIPT_BRIDGELIST_HPP #include "script_list.hpp" /** * Create a list of bridges types. * @api ai game * @ingroup ScriptList */ class ScriptBridgeList : public ScriptList { public: ScriptBridgeList(); }; /** * Create a list of bridges types that can be built on a specific length. * @api ai game * @ingroup ScriptList */ class ScriptBridgeList_Length : public ScriptList { public: /** * @param length The length of the bridge you want to build. */ ScriptBridgeList_Length(uint length); }; #endif /* SCRIPT_BRIDGELIST_HPP */ openttd-1.5.3/src/script/api/script_news.hpp0000644000000000000000000000675312627373434017636 0ustar rootroot/* $Id: script_news.hpp 27164 2015-02-22 17:25:29Z alberth $ */ /* * 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 script_news.hpp Everything to handle news messages. */ #ifndef SCRIPT_NEWS_HPP #define SCRIPT_NEWS_HPP #include "script_company.hpp" #include "../../news_type.h" /** * Class that handles news messages. * @api game */ class ScriptNews : public ScriptObject { public: /** * Enumeration for the news types that a script can create news for. */ enum NewsType { /* Arbitrary selection of NewsTypes which might make sense for scripts */ NT_ACCIDENT = ::NT_ACCIDENT, ///< Category accidents. NT_COMPANY_INFO = ::NT_COMPANY_INFO, ///< Category company info. NT_ECONOMY = ::NT_ECONOMY, ///< Category economy. NT_ADVICE = ::NT_ADVICE, ///< Category vehicle advice. NT_ACCEPTANCE = ::NT_ACCEPTANCE, ///< Category acceptance changes. NT_SUBSIDIES = ::NT_SUBSIDIES, ///< Category subsidies. NT_GENERAL = ::NT_GENERAL, ///< Category general. }; /** * Reference to a game element. */ enum NewsReferenceType { /* Selection of useful game elements to refer to. */ NR_NONE = ::NR_NONE, ///< No reference supplied. NR_TILE = ::NR_TILE, ///< Reference location, scroll to the location when clicking on the news. NR_STATION = ::NR_STATION, ///< Reference station, scroll to the station when clicking on the news. Delete news when the station is deleted. NR_INDUSTRY = ::NR_INDUSTRY, ///< Reference industry, scrolls to the industry when clicking on the news. Delete news when the industry is deleted. NR_TOWN = ::NR_TOWN, ///< Reference town, scroll to the town when clicking on the news. }; /** * Create a news message for everybody, or for one company. * @param type The type of the news. * @param text The text message to show (can be either a raw string, or a ScriptText object). * @param company The company, or COMPANY_INVALID for all companies. * @param ref_type Type of referred game element. * @param reference The referenced game element of \a ref_type. * - For #NR_NONE this parameter is ignored. * - For #NR_TILE this parameter should be a valid location (ScriptMap::IsValidTile). * - For #NR_STATION this parameter should be a valid stationID (ScriptStation::IsValidStation). * - For #NR_INDUSTRY this parameter should be a valid industryID (ScriptIndustry::IsValidIndustry). * - For #NR_TOWN this parameter should be a valid townID (ScriptTown::IsValidTown). * @return True if the action succeeded. * @pre type must be #NT_ECONOMY, #NT_SUBSIDIES, or #NT_GENERAL. * @pre text != NULL. * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID. * @pre The \a reference condition must be fulfilled. */ static bool Create(NewsType type, Text *text, ScriptCompany::CompanyID company, NewsReferenceType ref_type, uint32 reference); }; #endif /* SCRIPT_NEWS_HPP */ openttd-1.5.3/src/script/api/script_company.cpp0000644000000000000000000002433312627373434020315 0ustar rootroot/* $Id: script_company.cpp 27026 2014-10-21 16:58:15Z rubidium $ */ /* * 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 script_company.cpp Implementation of ScriptCompany. */ #include "../../stdafx.h" #include "script_company.hpp" #include "script_error.hpp" #include "script_companymode.hpp" #include "../../company_func.h" #include "../../company_base.h" #include "../../company_manager_face.h" #include "../../economy_func.h" #include "../../object_type.h" #include "../../strings_func.h" #include "../../tile_map.h" #include "../../string_func.h" #include "../../settings_func.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ ScriptCompany::CompanyID ScriptCompany::ResolveCompanyID(ScriptCompany::CompanyID company) { if (company == COMPANY_SELF) { if (!::Company::IsValidID((::CompanyID)_current_company)) return COMPANY_INVALID; return (CompanyID)((byte)_current_company); } return ::Company::IsValidID((::CompanyID)company) ? company : COMPANY_INVALID; } /* static */ bool ScriptCompany::IsMine(ScriptCompany::CompanyID company) { return ResolveCompanyID(company) == ResolveCompanyID(COMPANY_SELF); } /* static */ bool ScriptCompany::SetName(Text *name) { CCountedPtr counter(name); EnforcePrecondition(false, name != NULL); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_COMPANY_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::DoCommand(0, 0, 0, CMD_RENAME_COMPANY, text); } /* static */ char *ScriptCompany::GetName(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return NULL; ::SetDParam(0, company); return GetString(STR_COMPANY_NAME); } /* static */ bool ScriptCompany::SetPresidentName(Text *name) { CCountedPtr counter(name); EnforcePrecondition(false, name != NULL); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_PRESIDENT_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::DoCommand(0, 0, 0, CMD_RENAME_PRESIDENT, text); } /* static */ char *ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); static const int len = 64; char *president_name = MallocT(len); if (company != COMPANY_INVALID) { ::SetDParam(0, company); ::GetString(president_name, STR_PRESIDENT_NAME, &president_name[len - 1]); } else { *president_name = '\0'; } return president_name; } /* static */ bool ScriptCompany::SetPresidentGender(Gender gender) { EnforcePrecondition(false, gender == GENDER_MALE || gender == GENDER_FEMALE); EnforcePrecondition(false, GetPresidentGender(ScriptCompany::COMPANY_SELF) != gender); CompanyManagerFace cmf; GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (::InteractiveRandom() & (1 << ETHNICITY_BLACK))); RandomCompanyManagerFaceBits(cmf, ge, false); return ScriptObject::DoCommand(0, 0, cmf, CMD_SET_COMPANY_MANAGER_FACE); } /* static */ ScriptCompany::Gender ScriptCompany::GetPresidentGender(CompanyID company) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return GENDER_INVALID; GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(Company::Get(company)->face, CMFV_GEN_ETHN, GE_WM); return HasBit(ge, ::GENDER_FEMALE) ? GENDER_FEMALE : GENDER_MALE; } /* static */ Money ScriptCompany::GetQuarterlyIncome(ScriptCompany::CompanyID company, uint32 quarter) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::Company::Get((::CompanyID)company)->cur_economy.income; } return ::Company::Get((::CompanyID)company)->old_economy[quarter - 1].income; } /* static */ Money ScriptCompany::GetQuarterlyExpenses(ScriptCompany::CompanyID company, uint32 quarter) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::Company::Get((::CompanyID)company)->cur_economy.expenses; } return ::Company::Get((::CompanyID)company)->old_economy[quarter - 1].expenses; } /* static */ int32 ScriptCompany::GetQuarterlyCargoDelivered(ScriptCompany::CompanyID company, uint32 quarter) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::Company::Get((::CompanyID)company)->cur_economy.delivered_cargo.GetSum >(); } return ::Company::Get((::CompanyID)company)->old_economy[quarter - 1].delivered_cargo.GetSum >(); } /* static */ int32 ScriptCompany::GetQuarterlyPerformanceRating(ScriptCompany::CompanyID company, uint32 quarter) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter == CURRENT_QUARTER) return -1; return ::Company::Get((::CompanyID)company)->old_economy[quarter - 1].performance_history; } /* static */ Money ScriptCompany::GetQuarterlyCompanyValue(ScriptCompany::CompanyID company, uint32 quarter) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::CalculateCompanyValue(::Company::Get((::CompanyID)company)); } return ::Company::Get((::CompanyID)company)->old_economy[quarter - 1].company_value; } /* static */ Money ScriptCompany::GetBankBalance(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return -1; return ::Company::Get((CompanyID)company)->money; } /* static */ Money ScriptCompany::GetLoanAmount() { ScriptCompany::CompanyID company = ResolveCompanyID(COMPANY_SELF); if (company == COMPANY_INVALID) return -1; return ::Company::Get(company)->current_loan; } /* static */ Money ScriptCompany::GetMaxLoanAmount() { return _economy.max_loan; } /* static */ Money ScriptCompany::GetLoanInterval() { return LOAN_INTERVAL; } /* static */ bool ScriptCompany::SetLoanAmount(Money loan) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, loan >= 0); EnforcePrecondition(false, ((int64)loan % GetLoanInterval()) == 0); EnforcePrecondition(false, loan <= GetMaxLoanAmount()); EnforcePrecondition(false, (loan - GetLoanAmount() + GetBankBalance(COMPANY_SELF)) >= 0); if (loan == GetLoanAmount()) return true; return ScriptObject::DoCommand(0, abs(loan - GetLoanAmount()), 2, (loan > GetLoanAmount()) ? CMD_INCREASE_LOAN : CMD_DECREASE_LOAN); } /* static */ bool ScriptCompany::SetMinimumLoanAmount(Money loan) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, loan >= 0); Money over_interval = (int64)loan % GetLoanInterval(); if (over_interval != 0) loan += GetLoanInterval() - over_interval; EnforcePrecondition(false, loan <= GetMaxLoanAmount()); SetLoanAmount(loan); return GetLoanAmount() == loan; } /* static */ bool ScriptCompany::ChangeBankBalance(CompanyID company, Money delta, ExpensesType expenses_type) { EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, expenses_type < (ExpensesType)::EXPENSES_END); EnforcePrecondition(false, (int64)delta >= INT32_MIN); EnforcePrecondition(false, (int64)delta <= INT32_MAX); company = ResolveCompanyID(company); EnforcePrecondition(false, company != COMPANY_INVALID); return ScriptObject::DoCommand(0, (uint32)(delta), company | expenses_type << 8 , CMD_CHANGE_BANK_BALANCE); } /* static */ bool ScriptCompany::BuildCompanyHQ(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::DoCommand(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT); } /* static */ TileIndex ScriptCompany::GetCompanyHQ(CompanyID company) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return INVALID_TILE; TileIndex loc = ::Company::Get((CompanyID)company)->location_of_HQ; return (loc == 0) ? INVALID_TILE : loc; } /* static */ bool ScriptCompany::SetAutoRenewStatus(bool autorenew) { return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.engine_renew"), autorenew ? 1 : 0, CMD_CHANGE_COMPANY_SETTING); } /* static */ bool ScriptCompany::GetAutoRenewStatus(CompanyID company) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return false; return ::Company::Get((CompanyID)company)->settings.engine_renew; } /* static */ bool ScriptCompany::SetAutoRenewMonths(int16 months) { return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.engine_renew_months"), months, CMD_CHANGE_COMPANY_SETTING); } /* static */ int16 ScriptCompany::GetAutoRenewMonths(CompanyID company) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return 0; return ::Company::Get((CompanyID)company)->settings.engine_renew_months; } /* static */ bool ScriptCompany::SetAutoRenewMoney(Money money) { EnforcePrecondition(false, money >= 0); EnforcePrecondition(false, (int64)money <= UINT32_MAX); return ScriptObject::DoCommand(0, ::GetCompanySettingIndex("company.engine_renew_money"), money, CMD_CHANGE_COMPANY_SETTING); } /* static */ Money ScriptCompany::GetAutoRenewMoney(CompanyID company) { company = ResolveCompanyID(company); if (company == COMPANY_INVALID) return 0; return ::Company::Get((CompanyID)company)->settings.engine_renew_money; } openttd-1.5.3/src/script/api/generate_widget.awk0000644000000000000000000000613712627373434020422 0ustar rootroot# $Id: generate_widget.awk 24664 2012-11-05 19:53:05Z frosch $ # 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 . # # Awk script to automatically generate the enums in script_window.hpp # # The file is scanned for @enum and @endenum tokens, and the content between them is replaced by an enum from a different file. # # Example: # // @enum enumname filename # ... content here is replaced ... # // @endenum # # The parameter "enumname" specifies the enumeration to extract. This can also be a regular expression. # The parameter "filename" specifies the relative path to the file, where the enumeration is extracted from. This can also be a glob expression. # # BEGIN { skiptillend = 0; } /@enum/ { print; add_indent = gensub("[^ ]*", "", "g"); sub(".*@enum *", ""); enum = $1; pattern = $2; files = "echo " pattern; files | getline filelist; close(files); split(filelist, filearray); count = asort(filearray); for (i = 1; i <= count; i++) { active = 0; active_comment = 0; comment = ""; file = filearray[i]; print add_indent "/* automatically generated from " file " */" while ((getline < file) > 0) { sub(rm_indent, ""); # Remember possible doxygen comment before enum declaration if ((active == 0) && (match($0, "/\\*\\*") > 0)) { comment = add_indent $0; active_comment = 1; } else if (active_comment == 1) { comment = comment "\n" add_indent $0; } # Check for enum match if (match($0, "^ *enum *" enum " *\\{") > 0) { rm_indent = $0; gsub("[^ ]*", "", rm_indent); active = 1; if (active_comment > 0) print comment; active_comment = 0; comment = ""; } # Forget doxygen comment, if no enum follows if (active_comment == 2 && $0 != "") { active_comment = 0; comment = ""; } if (active_comment == 1 && match($0, "\\*/") > 0) active_comment = 2; if (active != 0) { if (match($0, "^ *[A-Za-z0-9_]* *[,=]") > 0) { # Transform enum values sub(" *=[^,]*", ""); sub(" *//", " //"); match($0, "^( *)([A-Za-z0-9_]+),(.*)", parts); enumwidth - length(parts[2]) if (parts[3] == "") { printf "%s%s%-45s= ::%s\n", add_indent, parts[1], parts[2], (parts[2] ",") } else { printf "%s%s%-45s= ::%-45s%s\n", add_indent, parts[1], parts[2], (parts[2] ","), parts[3]; } } else if ($0 == "") { print ""; } else { print add_indent $0; } } if (match($0, "^ *\\};") > 0) { if (active != 0) print ""; active = 0; } } close(file); } skiptillend = 1; next; } /@endenum/ { print; skiptillend = 0; next; } { if (skiptillend == 0) print; } openttd-1.5.3/src/script/api/script_admin.cpp0000644000000000000000000000713212627373434017735 0ustar rootroot/* $Id: script_admin.cpp 26774 2014-09-06 17:46:56Z rubidium $ */ /* * 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 script_admin.cpp Implementation of ScriptAdmin. */ #include "../../stdafx.h" #include "script_admin.hpp" #include "script_log.hpp" #include "../../network/network_admin.h" #include "../script_instance.hpp" #include "../../string_func.h" #include "../../safeguards.h" /* static */ bool ScriptAdmin::MakeJSON(HSQUIRRELVM vm, SQInteger index, int max_depth, std::string &data) { if (max_depth == 0) { ScriptLog::Error("Send parameters can only be nested to 25 deep. No data sent."); // SQUIRREL_MAX_DEPTH = 25 return false; } switch (sq_gettype(vm, index)) { case OT_INTEGER: { SQInteger res; sq_getinteger(vm, index, &res); char buf[10]; seprintf(buf, lastof(buf), "%d", (int32)res); data = buf; return true; } case OT_STRING: { const SQChar *buf; sq_getstring(vm, index, &buf); size_t len = strlen(buf) + 1; if (len >= 255) { ScriptLog::Error("Maximum string length is 254 chars. No data sent."); return false; } data = std::string("\"") + buf + "\""; return true; } case OT_ARRAY: { data = "[ "; bool first = true; sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { if (!first) data += ", "; if (first) first = false; std::string tmp; bool res = MakeJSON(vm, -1, max_depth - 1, tmp); sq_pop(vm, 2); if (!res) { sq_pop(vm, 1); return false; } data += tmp; } sq_pop(vm, 1); data += " ]"; return true; } case OT_TABLE: { data = "{ "; bool first = true; sq_pushnull(vm); while (SQ_SUCCEEDED(sq_next(vm, index - 1))) { if (!first) data += ", "; if (first) first = false; std::string key; std::string value; /* Store the key + value */ bool res = MakeJSON(vm, -2, max_depth - 1, key) && MakeJSON(vm, -1, max_depth - 1, value); sq_pop(vm, 2); if (!res) { sq_pop(vm, 1); return false; } data += key + ": " + value; } sq_pop(vm, 1); data += " }"; return true; } case OT_BOOL: { SQBool res; sq_getbool(vm, index, &res); if (res) { data = "true"; return true; } data = "false"; return true; } case OT_NULL: { data = "null"; return true; } default: ScriptLog::Error("You tried to send an unsupported type. No data sent."); return false; } } /* static */ SQInteger ScriptAdmin::Send(HSQUIRRELVM vm) { if (sq_gettop(vm) - 1 != 1) return sq_throwerror(vm, "wrong number of parameters"); if (sq_gettype(vm, 2) != OT_TABLE) { return sq_throwerror(vm, "ScriptAdmin::Send requires a table as first parameter. No data sent."); } std::string json; ScriptAdmin::MakeJSON(vm, -1, SQUIRREL_MAX_DEPTH, json); #ifdef ENABLE_NETWORK if (json.length() > NETWORK_GAMESCRIPT_JSON_LENGTH) { ScriptLog::Error("You are trying to send a table that is too large to the AdminPort. No data sent."); sq_pushinteger(vm, 0); return 1; } NetworkAdminGameScript(json.c_str()); #endif /* ENABLE_NETWORK */ sq_pushinteger(vm, 1); return 1; } openttd-1.5.3/src/script/api/script_order.hpp0000644000000000000000000007201712627373434017771 0ustar rootroot/* $Id: script_order.hpp 25612 2013-07-14 20:21:36Z rubidium $ */ /* * 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 script_order.hpp Everything to query and build orders. */ #ifndef SCRIPT_ORDER_HPP #define SCRIPT_ORDER_HPP #include "script_vehicle.hpp" #include "../../order_type.h" /** * Class that handles all order related functions. * @api ai game */ class ScriptOrder : public ScriptObject { public: /** * All order related error messages. */ enum ErrorMessages { /** Base for all order related errors */ ERR_ORDER_BASE = ScriptError::ERR_CAT_ORDER << ScriptError::ERR_CAT_BIT_SIZE, /** No more space for orders */ ERR_ORDER_TOO_MANY, // [STR_ERROR_NO_MORE_SPACE_FOR_ORDERS] /** Destination of new order is to far away from the previous order */ ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION, // [STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION] /** Aircraft has not enough range to copy/share orders. */ ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE, // [STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE] }; /** * Flags that can be used to modify the behaviour of orders. */ enum ScriptOrderFlags { /** Just go to the station/depot, stop unload if possible and load if needed. */ OF_NONE = 0, /** Do not stop at the stations that are passed when going to the destination. Only for trains and road vehicles. */ OF_NON_STOP_INTERMEDIATE = 1 << 0, /** Do not stop at the destination station. Only for trains and road vehicles. */ OF_NON_STOP_DESTINATION = 1 << 1, /** Always unload the vehicle; only for stations. Cannot be set when OF_TRANSFER or OF_NO_UNLOAD is set. */ OF_UNLOAD = 1 << 2, /** Transfer instead of deliver the goods; only for stations. Cannot be set when OF_UNLOAD or OF_NO_UNLOAD is set. */ OF_TRANSFER = 1 << 3, /** Never unload the vehicle; only for stations. Cannot be set when OF_UNLOAD, OF_TRANSFER or OF_NO_LOAD is set. */ OF_NO_UNLOAD = 1 << 4, /** Wt till the vehicle is fully loaded; only for stations. Cannot be set when OF_NO_LOAD is set. */ OF_FULL_LOAD = 2 << 5, /** Wt till at least one cargo of the vehicle is fully loaded; only for stations. Cannot be set when OF_NO_LOAD is set. */ OF_FULL_LOAD_ANY = 3 << 5, /** Do not load any cargo; only for stations. Cannot be set when OF_NO_UNLOAD, OF_FULL_LOAD or OF_FULL_LOAD_ANY is set. */ OF_NO_LOAD = 1 << 7, /** Service the vehicle when needed, otherwise skip this order; only for depots. */ OF_SERVICE_IF_NEEDED = 1 << 2, /** Stop in the depot instead of only go there for servicing; only for depots. */ OF_STOP_IN_DEPOT = 1 << 3, /** Go to nearest depot. */ OF_GOTO_NEAREST_DEPOT = 1 << 8, /** All flags related to non-stop settings. */ OF_NON_STOP_FLAGS = OF_NON_STOP_INTERMEDIATE | OF_NON_STOP_DESTINATION, /** All flags related to unloading. */ OF_UNLOAD_FLAGS = OF_TRANSFER | OF_UNLOAD | OF_NO_UNLOAD, /** All flags related to loading. */ OF_LOAD_FLAGS = OF_FULL_LOAD | OF_FULL_LOAD_ANY | OF_NO_LOAD, /** All flags related to depots. */ OF_DEPOT_FLAGS = OF_SERVICE_IF_NEEDED | OF_STOP_IN_DEPOT | OF_GOTO_NEAREST_DEPOT, /** For marking invalid order flags */ OF_INVALID = 0xFFFF, }; /** * All conditions a conditional order can depend on. */ enum OrderCondition { /* Note: these values represent part of the in-game OrderConditionVariable enum */ OC_LOAD_PERCENTAGE = ::OCV_LOAD_PERCENTAGE, ///< Skip based on the amount of load, value is in tons. OC_RELIABILITY = ::OCV_RELIABILITY, ///< Skip based on the reliability, value is percent (0..100). OC_MAX_SPEED = ::OCV_MAX_SPEED, ///< Skip based on the maximum speed, value is in OpenTTD's internal speed unit, see ScriptEngine::GetMaxSpeed. OC_AGE = ::OCV_AGE, ///< Skip based on the age, value is in years. OC_REQUIRES_SERVICE = ::OCV_REQUIRES_SERVICE, ///< Skip when the vehicle requires service, no value. OC_UNCONDITIONALLY = ::OCV_UNCONDITIONALLY, ///< Always skip, no compare function, no value. OC_REMAINING_LIFETIME = ::OCV_REMAINING_LIFETIME, ///< Skip based on the remaining lifetime /* Custom added value, only valid for this API */ OC_INVALID = -1, ///< An invalid condition, do not use. }; /** * Comparators for conditional orders. */ enum CompareFunction { /* Note: these values represent part of the in-game OrderConditionComparator enum */ CF_EQUALS = ::OCC_EQUALS, ///< Skip if both values are equal CF_NOT_EQUALS = ::OCC_NOT_EQUALS, ///< Skip if both values are not equal CF_LESS_THAN = ::OCC_LESS_THAN, ///< Skip if the value is less than the limit CF_LESS_EQUALS = ::OCC_LESS_EQUALS, ///< Skip if the value is less or equal to the limit CF_MORE_THAN = ::OCC_MORE_THAN, ///< Skip if the value is more than the limit CF_MORE_EQUALS = ::OCC_MORE_EQUALS, ///< Skip if the value is more or equal to the limit CF_IS_TRUE = ::OCC_IS_TRUE, ///< Skip if the variable is true CF_IS_FALSE = ::OCC_IS_FALSE, ///< Skip if the variable is false /* Custom added value, only valid for this API */ CF_INVALID = -1, ///< Invalid compare function, do not use. }; /** * Index in the list of orders for a vehicle. The first order has index 0, the second * order index 1, etc. The current order can be queried by using ORDER_CURRENT. Do not * use ORDER_INVALID yourself, it's used as return value by for example ResolveOrderPosition. * @note Automatic orders are hidden from scripts, so OrderPosition 0 will always be the first * manual order. */ enum OrderPosition { ORDER_CURRENT = 0xFF, ///< Constant that gets resolved to the current order. ORDER_INVALID = -1, ///< An invalid order. }; /** Where to stop trains in a station that's longer than the train */ enum StopLocation { STOPLOCATION_NEAR, ///< Stop the train as soon as it's completely in the station STOPLOCATION_MIDDLE, ///< Stop the train in the middle of the station STOPLOCATION_FAR, ///< Stop the train at the far end of the station STOPLOCATION_INVALID = -1, ///< An invalid stop location }; /** * Checks whether the given order id is valid for the given vehicle. * @param vehicle_id The vehicle to check the order index for. * @param order_position The order index to check. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @return True if and only if the order_position is valid for the given vehicle. */ static bool IsValidVehicleOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the given order is a goto-station order. * @param vehicle_id The vehicle to check. * @param order_position The order index to check. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @return True if and only if the order is a goto-station order. */ static bool IsGotoStationOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the given order is a goto-depot order. * @param vehicle_id The vehicle to check. * @param order_position The order index to check. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @return True if and only if the order is a goto-depot order. */ static bool IsGotoDepotOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the given order is a goto-waypoint order. * @param vehicle_id The vehicle to check. * @param order_position The order index to check. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @return True if and only if the order is a goto-waypoint order. */ static bool IsGotoWaypointOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the given order is a conditional order. * @param vehicle_id The vehicle to check. * @param order_position The order index to check. * @pre order_position != ORDER_CURRENT && IsValidVehicleOrder(vehicle_id, order_position). * @return True if and only if the order is a conditional order. */ static bool IsConditionalOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the given order is a void order. * A void order is an order that used to be a goto station, depot or waypoint order but * its destination got removed. In OpenTTD these orders as shown as "(Invalid Order)" * in the order list of a vehicle. * @param vehicle_id The vehicle to check. * @param order_position The order index to check. * @pre order_position != ORDER_CURRENT && IsValidVehicleOrder(vehicle_id, order_position). * @return True if and only if the order is a void order. */ static bool IsVoidOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the given order has a valid refit cargo. * @param vehicle_id The vehicle to check. * @param order_position The order index to check. * @pre order_position != ORDER_CURRENT && IsValidVehicleOrder(vehicle_id, order_position). * @return True if and only if the order is has a valid refit cargo. */ static bool IsRefitOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the current order is part of the orderlist. * @param vehicle_id The vehicle to check. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @return True if and only if the current order is part of the order list. * @note If the order is a non-'non-stop' order, and the vehicle is currently * (un)loading at a station that is not the final destination, this function * will still return true. */ static bool IsCurrentOrderPartOfOrderList(VehicleID vehicle_id); /** * Resolves the given order index to the correct index for the given vehicle. * If the order index was ORDER_CURRENT it will be resolved to the index of * the current order (as shown in the order list). If the order with the * given index does not exist it will return ORDER_INVALID. * @param vehicle_id The vehicle to check the order index for. * @param order_position The order index to resolve. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @return The resolved order index. */ static OrderPosition ResolveOrderPosition(VehicleID vehicle_id, OrderPosition order_position); /** * Checks whether the given order flags are valid for the given destination. * @param destination The destination of the order. * @param order_flags The flags given to the order. * @return True if and only if the order_flags are valid for the given location. */ static bool AreOrderFlagsValid(TileIndex destination, ScriptOrderFlags order_flags); /** * Checks whether the given combination of condition and compare function is valid. * @param condition The condition to check. * @param compare The compare function to check. * @return True if and only if the combination of condition and compare function is valid. */ static bool IsValidConditionalOrder(OrderCondition condition, CompareFunction compare); /** * Returns the number of orders for the given vehicle. * @param vehicle_id The vehicle to get the order count of. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @return The number of orders for the given vehicle or a negative * value when the vehicle does not exist. */ static int32 GetOrderCount(VehicleID vehicle_id); /** * Gets the destination of the given order for the given vehicle. * @param vehicle_id The vehicle to get the destination for. * @param order_position The order to get the destination for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position). * @note Giving ORDER_CURRENT as order_position will give the order that is * currently being executed by the vehicle. This is not necessarily the * current order as given by ResolveOrderPosition (the current index in the * order list) as manual or autoservicing depot orders do not show up * in the orderlist, but they can be the current order of a vehicle. * @return The destination tile of the order. */ static TileIndex GetOrderDestination(VehicleID vehicle_id, OrderPosition order_position); /** * Gets the ScriptOrderFlags of the given order for the given vehicle. * @param vehicle_id The vehicle to get the destination for. * @param order_position The order to get the destination for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position == ORDER_CURRENT || (!IsConditionalOrder(vehicle_id, order_position) && !IsVoidOrder(vehicle_id, order_position)). * @note Giving ORDER_CURRENT as order_position will give the order that is * currently being executed by the vehicle. This is not necessarily the * current order as given by ResolveOrderPosition (the current index in the * order list) as manual or autoservicing depot orders do not show up * in the orderlist, but they can be the current order of a vehicle. * @return The ScriptOrderFlags of the order. */ static ScriptOrderFlags GetOrderFlags(VehicleID vehicle_id, OrderPosition order_position); /** * Gets the OrderPosition to jump to if the check succeeds of the given order for the given vehicle. * @param vehicle_id The vehicle to get the OrderPosition for. * @param order_position The order to get the OrderPosition for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @return The target of the conditional jump. */ static OrderPosition GetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position); /** * Gets the OrderCondition of the given order for the given vehicle. * @param vehicle_id The vehicle to get the condition type for. * @param order_position The order to get the condition type for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @return The OrderCondition of the order. */ static OrderCondition GetOrderCondition(VehicleID vehicle_id, OrderPosition order_position); /** * Gets the CompareFunction of the given order for the given vehicle. * @param vehicle_id The vehicle to get the compare function for. * @param order_position The order to get the compare function for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @return The CompareFunction of the order. */ static CompareFunction GetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position); /** * Gets the value to compare against of the given order for the given vehicle. * @param vehicle_id The vehicle to get the value for. * @param order_position The order to get the value for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @return The value to compare against of the order. */ static int32 GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position); /** * Gets the stoplocation of the given order for the given train. * @param vehicle_id The vehicle to get the value for. * @param order_position The order to get the value for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre ScriptVehicle::GetVehicleType(vehicle_id) == ScriptVehicle::VT_RAIL. * @pre IsGotoStationOrder(vehicle_id, order_position). * @return The relative position where the train will stop inside a station. */ static StopLocation GetStopLocation(VehicleID vehicle_id, OrderPosition order_position); /** * Gets the refit cargo type of the given order for the given vehicle. * @param vehicle_id The vehicle to get the refit cargo for. * @param order_position The order to get the refit cargo for. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position == ORDER_CURRENT || IsGotoStationOrder(vehicle_id, order_position) || IsGotoDepotOrder(vehicle_id, order_position). * @note Giving ORDER_CURRENT as order_position will give the order that is * currently being executed by the vehicle. This is not necessarily the * current order as given by ResolveOrderPosition (the current index in the * order list) as manual or autoservicing depot orders do not show up * in the orderlist, but they can be the current order of a vehicle. * @return The refit cargo of the order or CT_NO_REFIT if no refit is set. */ static CargoID GetOrderRefit(VehicleID vehicle_id, OrderPosition order_position); /** * Sets the OrderPosition to jump to if the check succeeds of the given order for the given vehicle. * @param vehicle_id The vehicle to set the OrderPosition for. * @param order_position The order to set the OrderPosition for. * @param jump_to The order to jump to if the check succeeds. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre IsValidVehicleOrder(vehicle_id, jump_to). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @return Whether the order has been/can be changed. * @api -game */ static bool SetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to); /** * Sets the OrderCondition of the given order for the given vehicle. * @param vehicle_id The vehicle to set the condition type for. * @param order_position The order to set the condition type for. * @param condition The condition to compare on. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @pre condition >= OC_LOAD_PERCENTAGE && condition <= OC_UNCONDITIONALLY. * @return Whether the order has been/can be changed. * @api -game */ static bool SetOrderCondition(VehicleID vehicle_id, OrderPosition order_position, OrderCondition condition); /** * Sets the CompareFunction of the given order for the given vehicle. * @param vehicle_id The vehicle to set the compare function for. * @param order_position The order to set the compare function for. * @param compare The new compare function of the order. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @pre compare >= CF_EQUALS && compare <= CF_IS_FALSE. * @return Whether the order has been/can be changed. * @api -game */ static bool SetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position, CompareFunction compare); /** * Sets the value to compare against of the given order for the given vehicle. * @param vehicle_id The vehicle to set the value for. * @param order_position The order to set the value for. * @param value The value to compare against. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position). * @pre value >= 0 && value < 2048. * @return Whether the order has been/can be changed. * @api -game */ static bool SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, int32 value); /** * Sets the stoplocation of the given order for the given train. * @param vehicle_id The vehicle to get the value for. * @param order_position The order to get the value for. * @param stop_location The relative position where a train will stop inside a station. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre ScriptVehicle::GetVehicleType(vehicle_id) == ScriptVehicle::VT_RAIL. * @pre IsGotoStationOrder(vehicle_id, order_position). * @pre stop_location >= STOPLOCATION_NEAR && stop_location <= STOPLOCATION_FAR * @return Whether the order has been/can be changed. * @api -game */ static bool SetStopLocation(VehicleID vehicle_id, OrderPosition order_position, StopLocation stop_location); /** * Sets the refit cargo type of the given order for the given vehicle. * @param vehicle_id The vehicle to set the refit cargo for. * @param order_position The order to set the refit cargo for. * @param refit_cargo The cargo to refit to. The refit can be cleared by passing CT_NO_REFIT. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre IsGotoStationOrder(vehicle_id, order_position) || (IsGotoDepotOrder(vehicle_id, order_position) && refit_cargo != CT_AUTO_REFIT). * @pre ScriptCargo::IsValidCargo(refit_cargo) || refit_cargo == CT_AUTO_REFIT || refit_cargo == CT_NO_REFIT * @return Whether the order has been/can be changed. * @api -game */ static bool SetOrderRefit(VehicleID vehicle_id, OrderPosition order_position, CargoID refit_cargo); /** * Appends an order to the end of the vehicle's order list. * @param vehicle_id The vehicle to append the order to. * @param destination The destination of the order. * @param order_flags The flags given to the order. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @pre AreOrderFlagsValid(destination, order_flags). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptOrder::ERR_ORDER_TOO_MANY * @exception ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION * @return True if and only if the order was appended. * @api -game */ static bool AppendOrder(VehicleID vehicle_id, TileIndex destination, ScriptOrderFlags order_flags); /** * Appends a conditional order to the end of the vehicle's order list. * @param vehicle_id The vehicle to append the order to. * @param jump_to The OrderPosition to jump to if the condition is true. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @pre IsValidVehicleOrder(vehicle_id, jump_to). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptOrder::ERR_ORDER_TOO_MANY * @return True if and only if the order was appended. * @api -game */ static bool AppendConditionalOrder(VehicleID vehicle_id, OrderPosition jump_to); /** * Inserts an order before the given order_position into the vehicle's order list. * @param vehicle_id The vehicle to add the order to. * @param order_position The order to place the new order before. * @param destination The destination of the order. * @param order_flags The flags given to the order. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre AreOrderFlagsValid(destination, order_flags). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptOrder::ERR_ORDER_TOO_MANY * @exception ScriptOrder::ERR_ORDER_TOO_FAR_AWAY_FROM_PREVIOUS_DESTINATION * @return True if and only if the order was inserted. * @api -game */ static bool InsertOrder(VehicleID vehicle_id, OrderPosition order_position, TileIndex destination, ScriptOrderFlags order_flags); /** * Appends a conditional order before the given order_position into the vehicle's order list. * @param vehicle_id The vehicle to add the order to. * @param order_position The order to place the new order before. * @param jump_to The OrderPosition to jump to if the condition is true. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre IsValidVehicleOrder(vehicle_id, jump_to). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptOrder::ERR_ORDER_TOO_MANY * @return True if and only if the order was inserted. * @api -game */ static bool InsertConditionalOrder(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to); /** * Removes an order from the vehicle's order list. * @param vehicle_id The vehicle to remove the order from. * @param order_position The order to remove from the order list. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return True if and only if the order was removed. * @api -game */ static bool RemoveOrder(VehicleID vehicle_id, OrderPosition order_position); /** * Internal function to help SetOrderFlags. * @api -all */ static bool _SetOrderFlags(); /** * Changes the order flags of the given order. * @param vehicle_id The vehicle to change the order of. * @param order_position The order to change. * @param order_flags The new flags given to the order. * @pre IsValidVehicleOrder(vehicle_id, order_position). * @pre AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags). * @pre (order_flags & OF_GOTO_NEAREST_DEPOT) == (GetOrderFlags(vehicle_id, order_position) & OF_GOTO_NEAREST_DEPOT). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return True if and only if the order was changed. * @api -game */ static bool SetOrderFlags(VehicleID vehicle_id, OrderPosition order_position, ScriptOrderFlags order_flags); /** * Move an order inside the orderlist * @param vehicle_id The vehicle to move the orders. * @param order_position_move The order to move. * @param order_position_target The target order * @pre IsValidVehicleOrder(vehicle_id, order_position_move). * @pre IsValidVehicleOrder(vehicle_id, order_position_target). * @pre order_position_move != order_position_target. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return True if and only if the order was moved. * @note If the order is moved to a lower place (e.g. from 7 to 2) * the target order is moved upwards (e.g. 3). If the order is moved * to a higher place (e.g. from 7 to 9) the target will be moved * downwards (e.g. 8). * @api -game */ static bool MoveOrder(VehicleID vehicle_id, OrderPosition order_position_move, OrderPosition order_position_target); /** * Make a vehicle execute next_order instead of its current order. * @param vehicle_id The vehicle that should skip some orders. * @param next_order The order the vehicle should skip to. * @pre IsValidVehicleOrder(vehicle_id, next_order). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @return True if and only the current order was changed. * @api -game */ static bool SkipToOrder(VehicleID vehicle_id, OrderPosition next_order); /** * Copies the orders from another vehicle. The orders of the main vehicle * are going to be the orders of the changed vehicle. * @param vehicle_id The vehicle to copy the orders to. * @param main_vehicle_id The vehicle to copy the orders from. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @pre ScriptVehicle::IsValidVehicle(main_vehicle_id). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptOrder::ERR_ORDER_TOO_MANY * @exception ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE * @return True if and only if the copying succeeded. * @api -game */ static bool CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id); /** * Shares the orders between two vehicles. The orders of the main * vehicle are going to be the orders of the changed vehicle. * @param vehicle_id The vehicle to add to the shared order list. * @param main_vehicle_id The vehicle to share the orders with. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @pre ScriptVehicle::IsValidVehicle(main_vehicle_id). * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE * @return True if and only if the sharing succeeded. * @api -game */ static bool ShareOrders(VehicleID vehicle_id, VehicleID main_vehicle_id); /** * Removes the given vehicle from a shared orders list. * @param vehicle_id The vehicle to remove from the shared order list. * @pre ScriptVehicle::IsValidVehicle(vehicle_id). * @return True if and only if the unsharing succeeded. * @api -game */ static bool UnshareOrders(VehicleID vehicle_id); /** * Get the distance between two points for a vehicle type. * Use this function to compute the distance between two tiles wrt. a vehicle type. * These vehicle-type specific distances are independent from other map distances, you may * use the result of this function to compare it with the result of * ScriptEngine::GetMaximumOrderDistance or ScriptVehicle::GetMaximumOrderDistance. * @param vehicle_type The vehicle type to get the distance for. * @param origin_tile Origin, can be any tile or a tile of a specific station. * @param dest_tile Destination, can be any tile or a tile of a specific station. * @return The distance between the origin and the destination for a * vehicle of the given vehicle type. * @note The unit of the order distances is unspecified and should * not be compared with map distances * @see ScriptEngine::GetMaximumOrderDistance and ScriptVehicle::GetMaximumOrderDistance */ static uint GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile); }; DECLARE_ENUM_AS_BIT_SET(ScriptOrder::ScriptOrderFlags) #endif /* SCRIPT_ORDER_HPP */ openttd-1.5.3/src/script/api/script_execmode.hpp0000644000000000000000000000341512627373433020442 0ustar rootroot/* $Id: script_execmode.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 script_execmode.hpp Switch the script to Execute Mode. */ #ifndef SCRIPT_EXECMODE_HPP #define SCRIPT_EXECMODE_HPP #include "script_object.hpp" /** * Class to switch current mode to Execute Mode. * If you create an instance of this class, the mode will be switched to * Execute. The original mode is stored and recovered from when ever the * instance is destroyed. * In Execute mode all commands you do are executed for real. * @api ai game */ class ScriptExecMode : public ScriptObject { private: ScriptModeProc *last_mode; ///< The previous mode we were in. ScriptObject *last_instance; ///< The previous instance of the mode. protected: /** * The callback proc for Execute mode. */ static bool ModeProc(); public: /** * Creating instance of this class switches the build mode to Execute. * @note When the instance is destroyed, he restores the mode that was * current when the instance was created! */ ScriptExecMode(); /** * Destroying this instance reset the building mode to the mode it was * in when the instance was created. */ ~ScriptExecMode(); }; #endif /* SCRIPT_EXECMODE_HPP */ openttd-1.5.3/src/script/api/script_cargo.cpp0000644000000000000000000000560412627373434017742 0ustar rootroot/* $Id: script_cargo.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_cargo.cpp Implementation of ScriptCargo. */ #include "../../stdafx.h" #include "script_cargo.hpp" #include "../../economy_func.h" #include "../../core/bitmath_func.hpp" #include "../../settings_type.h" #include "../../safeguards.h" /* static */ bool ScriptCargo::IsValidCargo(CargoID cargo_type) { return (cargo_type < NUM_CARGO && ::CargoSpec::Get(cargo_type)->IsValid()); } /* static */ bool ScriptCargo::IsValidTownEffect(TownEffect towneffect_type) { return (towneffect_type >= (TownEffect)TE_BEGIN && towneffect_type < (TownEffect)TE_END); } /* static */ char *ScriptCargo::GetCargoLabel(CargoID cargo_type) { if (!IsValidCargo(cargo_type)) return NULL; const CargoSpec *cargo = ::CargoSpec::Get(cargo_type); /* cargo->label is a uint32 packing a 4 character non-terminated string, * like "PASS", "COAL", "OIL_". New ones can be defined by NewGRFs */ char *cargo_label = MallocT(sizeof(cargo->label) + 1); for (uint i = 0; i < sizeof(cargo->label); i++) { cargo_label[i] = GB(cargo->label, (uint8)(sizeof(cargo->label) - i - 1) * 8, 8); } cargo_label[sizeof(cargo->label)] = '\0'; return cargo_label; } /* static */ bool ScriptCargo::IsFreight(CargoID cargo_type) { if (!IsValidCargo(cargo_type)) return false; const CargoSpec *cargo = ::CargoSpec::Get(cargo_type); return cargo->is_freight; } /* static */ bool ScriptCargo::HasCargoClass(CargoID cargo_type, CargoClass cargo_class) { if (!IsValidCargo(cargo_type)) return false; return ::IsCargoInClass(cargo_type, (::CargoClass)cargo_class); } /* static */ ScriptCargo::TownEffect ScriptCargo::GetTownEffect(CargoID cargo_type) { if (!IsValidCargo(cargo_type)) return TE_NONE; return (ScriptCargo::TownEffect)::CargoSpec::Get(cargo_type)->town_effect; } /* static */ Money ScriptCargo::GetCargoIncome(CargoID cargo_type, uint32 distance, uint32 days_in_transit) { if (!IsValidCargo(cargo_type)) return -1; return ::GetTransportedGoodsIncome(1, distance, Clamp(days_in_transit * 2 / 5, 0, 255), cargo_type); } /* static */ ScriptCargo::DistributionType ScriptCargo::GetDistributionType(CargoID cargo_type) { if (!ScriptCargo::IsValidCargo(cargo_type)) return INVALID_DISTRIBUTION_TYPE; return (ScriptCargo::DistributionType)_settings_game.linkgraph.GetDistributionType(cargo_type); }openttd-1.5.3/src/script/api/script_accounting.hpp0000644000000000000000000000430312627373434021001 0ustar rootroot/* $Id: script_accounting.hpp 24008 2012-03-04 16:54:12Z rubidium $ */ /* * 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 script_accounting.hpp Everything to handle script accounting things. */ #ifndef SCRIPT_ACCOUNTING_HPP #define SCRIPT_ACCOUNTING_HPP #include "script_object.hpp" /** * Class that keeps track of the costs, so you can request how much a block of * commands did cost in total. Works in both Execute as in Test mode. * @api ai game * Example: *
 *   {
 *     local costs = ScriptAccounting();
 *     BuildRoad(from_here, to_here);
 *     BuildRoad(from_there, to_there);
 *     print("Costs for route is: " + costs.GetCosts());
 *   }
 * 
*/ class ScriptAccounting : public ScriptObject { public: /** * Creating instance of this class starts counting the costs of commands * from zero. Saves the current value of GetCosts so we can return to * the old value when the instance gets deleted. */ ScriptAccounting(); /** * Restore the ScriptAccounting that was on top when we created this instance. * So basically restore the value of GetCosts to what it was before we * created this instance. */ ~ScriptAccounting(); /** * Get the current value of the costs. * @return The current costs. * @note when nesting ScriptAccounting instances all instances' GetCosts * will always return the value of the 'top' instance. */ Money GetCosts(); /** * Reset the costs to zero. * @note when nesting ScriptAccounting instances all instances' ResetCosts * will always effect on the 'top' instance. */ void ResetCosts(); private: Money last_costs; ///< The last cost we did return. }; #endif /* SCRIPT_ACCOUNTING_HPP */ openttd-1.5.3/src/script/api/script_cargomonitor.cpp0000644000000000000000000000572712627373434021360 0ustar rootroot/* $Id: script_cargomonitor.cpp 26685 2014-07-12 17:04:14Z alberth $ */ /* * 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 script_cargomonitor.cpp Code to monitor cargo pickup and deliveries by companies. */ #include "../../stdafx.h" #include "script_cargo.hpp" #include "script_cargomonitor.hpp" #include "../../town.h" #include "../../industry.h" #include "../../safeguards.h" /* static */ int32 ScriptCargoMonitor::GetTownDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring) { CompanyID cid = static_cast(company); if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Town::IsValidID(town_id)) return -1; CargoMonitorID monitor = EncodeCargoTownMonitor(cid, cargo, town_id); return GetDeliveryAmount(monitor, keep_monitoring); } /* static */ int32 ScriptCargoMonitor::GetIndustryDeliveryAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring) { CompanyID cid = static_cast(company); if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Industry::IsValidID(industry_id)) return -1; CargoMonitorID monitor = EncodeCargoIndustryMonitor(cid, cargo, industry_id); return GetDeliveryAmount(monitor, keep_monitoring); } /* static */ int32 ScriptCargoMonitor::GetTownPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, TownID town_id, bool keep_monitoring) { CompanyID cid = static_cast(company); if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Town::IsValidID(town_id)) return -1; CargoMonitorID monitor = EncodeCargoTownMonitor(cid, cargo, town_id); return GetPickupAmount(monitor, keep_monitoring); } /* static */ int32 ScriptCargoMonitor::GetIndustryPickupAmount(ScriptCompany::CompanyID company, CargoID cargo, IndustryID industry_id, bool keep_monitoring) { CompanyID cid = static_cast(company); if (cid < OWNER_BEGIN || cid >= MAX_COMPANIES) return -1; if (!ScriptCargo::IsValidCargo(cargo)) return -1; if (!::Industry::IsValidID(industry_id)) return -1; CargoMonitorID monitor = EncodeCargoIndustryMonitor(cid, cargo, industry_id); return GetPickupAmount(monitor, keep_monitoring); } /* static */ void ScriptCargoMonitor::StopAllMonitoring() { ClearCargoPickupMonitoring(); ClearCargoDeliveryMonitoring(); } openttd-1.5.3/src/script/api/script_tile.cpp0000644000000000000000000002431312627373434017602 0ustar rootroot/* $Id: script_tile.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_tile.cpp Implementation of ScriptTile. */ #include "../../stdafx.h" #include "script_tile.hpp" #include "script_map.hpp" #include "script_town.hpp" #include "../../station_func.h" #include "../../water_map.h" #include "../../clear_map.h" #include "../../tree_map.h" #include "../../town.h" #include "../../landscape.h" #include "../../safeguards.h" /* static */ bool ScriptTile::IsBuildable(TileIndex tile) { if (!::IsValidTile(tile)) return false; switch (::GetTileType(tile)) { default: return false; case MP_CLEAR: return true; case MP_TREES: return true; case MP_WATER: return IsCoast(tile); case MP_ROAD: /* Tram bits aren't considered buildable */ if (::GetRoadTypes(tile) != ROADTYPES_ROAD) return false; /* Depots and crossings aren't considered buildable */ if (::GetRoadTileType(tile) != ROAD_TILE_NORMAL) return false; if (!HasExactlyOneBit(::GetRoadBits(tile, ROADTYPE_ROAD))) return false; if (::IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) return true; if (::IsRoadOwner(tile, ROADTYPE_ROAD, ScriptObject::GetCompany())) return true; return false; } } /* static */ bool ScriptTile::IsBuildableRectangle(TileIndex tile, uint width, uint height) { /* Check whether we can extract valid X and Y */ if (!::IsValidTile(tile)) return false; uint tx = ScriptMap::GetTileX(tile); uint ty = ScriptMap::GetTileY(tile); for (uint x = tx; x < width + tx; x++) { for (uint y = ty; y < height + ty; y++) { if (!IsBuildable(ScriptMap::GetTileIndex(x, y))) return false; } } return true; } /* static */ bool ScriptTile::IsWaterTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_WATER) && !::IsCoast(tile); } /* static */ bool ScriptTile::IsCoastTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_WATER) && ::IsCoast(tile)) || (::IsTileType(tile, MP_TREES) && ::GetTreeGround(tile) == TREE_GROUND_SHORE); } /* static */ bool ScriptTile::IsStationTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_STATION); } /* static */ bool ScriptTile::IsSteepSlope(Slope slope) { if ((slope & ~(SLOPE_ELEVATED | SLOPE_STEEP | SLOPE_HALFTILE_MASK)) != 0) return false; return ::IsSteepSlope((::Slope)slope); } /* static */ bool ScriptTile::IsHalftileSlope(Slope slope) { if ((slope & ~(SLOPE_ELEVATED | SLOPE_STEEP | SLOPE_HALFTILE_MASK)) != 0) return false; return ::IsHalftileSlope((::Slope)slope); } /* static */ bool ScriptTile::HasTreeOnTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsTileType(tile, MP_TREES); } /* static */ bool ScriptTile::IsFarmTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_FIELDS)); } /* static */ bool ScriptTile::IsRockTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_CLEAR) && ::GetRawClearGround(tile) == ::CLEAR_ROCKS); } /* static */ bool ScriptTile::IsRoughTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_CLEAR) && ::GetRawClearGround(tile) == ::CLEAR_ROUGH); } /* static */ bool ScriptTile::IsSnowTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_CLEAR) && ::IsSnowTile(tile)); } /* static */ bool ScriptTile::IsDesertTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_DESERT)); } /* static */ ScriptTile::TerrainType ScriptTile::GetTerrainType(TileIndex tile) { if (!::IsValidTile(tile)) return TERRAIN_NORMAL; switch (::GetTerrainType(tile)) { default: case 0: return TERRAIN_NORMAL; case 1: return TERRAIN_DESERT; case 2: return TERRAIN_RAINFOREST; case 4: return TERRAIN_SNOW; } } /* static */ ScriptTile::Slope ScriptTile::GetSlope(TileIndex tile) { if (!::IsValidTile(tile)) return SLOPE_INVALID; return (Slope)::GetTileSlope(tile); } /* static */ ScriptTile::Slope ScriptTile::GetComplementSlope(Slope slope) { if ((slope & ~SLOPE_ELEVATED) != 0) return SLOPE_INVALID; return (Slope)::ComplementSlope((::Slope)slope); } /* static */ int32 ScriptTile::GetMinHeight(TileIndex tile) { if (!::IsValidTile(tile)) return -1; return ::GetTileZ(tile); } /* static */ int32 ScriptTile::GetMaxHeight(TileIndex tile) { if (!::IsValidTile(tile)) return -1; return ::GetTileMaxZ(tile); } /* static */ int32 ScriptTile::GetCornerHeight(TileIndex tile, Corner corner) { if (!::IsValidTile(tile) || !::IsValidCorner((::Corner)corner)) return -1; int z; ::Slope slope = ::GetTileSlope(tile, &z); return (z + ::GetSlopeZInCorner(slope, (::Corner)corner)); } /* static */ ScriptCompany::CompanyID ScriptTile::GetOwner(TileIndex tile) { if (!::IsValidTile(tile)) return ScriptCompany::COMPANY_INVALID; if (::IsTileType(tile, MP_HOUSE)) return ScriptCompany::COMPANY_INVALID; if (::IsTileType(tile, MP_INDUSTRY)) return ScriptCompany::COMPANY_INVALID; return ScriptCompany::ResolveCompanyID((ScriptCompany::CompanyID)(byte)::GetTileOwner(tile)); } /* static */ bool ScriptTile::HasTransportType(TileIndex tile, TransportType transport_type) { if (!::IsValidTile(tile)) return false; return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, UINT32_MAX)) != TRACKDIR_BIT_NONE; } /* static */ int32 ScriptTile::GetCargoAcceptance(TileIndex tile, CargoID cargo_type, int width, int height, int radius) { if (!::IsValidTile(tile) || width <= 0 || height <= 0 || radius < 0 || !ScriptCargo::IsValidCargo(cargo_type)) return -1; CargoArray acceptance = ::GetAcceptanceAroundTiles(tile, width, height, _settings_game.station.modified_catchment ? radius : (int)CA_UNMODIFIED); return acceptance[cargo_type]; } /* static */ int32 ScriptTile::GetCargoProduction(TileIndex tile, CargoID cargo_type, int width, int height, int radius) { if (!::IsValidTile(tile) || width <= 0 || height <= 0 || radius < 0 || !ScriptCargo::IsValidCargo(cargo_type)) return -1; CargoArray produced = ::GetProductionAroundTiles(tile, width, height, _settings_game.station.modified_catchment ? radius : (int)CA_UNMODIFIED); return produced[cargo_type]; } /* static */ int32 ScriptTile::GetDistanceManhattanToTile(TileIndex tile_from, TileIndex tile_to) { return ScriptMap::DistanceManhattan(tile_from, tile_to); } /* static */ int32 ScriptTile::GetDistanceSquareToTile(TileIndex tile_from, TileIndex tile_to) { return ScriptMap::DistanceSquare(tile_from, tile_to); } /* static */ bool ScriptTile::RaiseTile(TileIndex tile, int32 slope) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, tile < ::MapSize()); return ScriptObject::DoCommand(tile, slope, 1, CMD_TERRAFORM_LAND); } /* static */ bool ScriptTile::LowerTile(TileIndex tile, int32 slope) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, tile < ::MapSize()); return ScriptObject::DoCommand(tile, slope, 0, CMD_TERRAFORM_LAND); } /* static */ bool ScriptTile::LevelTiles(TileIndex start_tile, TileIndex end_tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, start_tile < ::MapSize()); EnforcePrecondition(false, end_tile < ::MapSize()); return ScriptObject::DoCommand(end_tile, start_tile, LM_LEVEL << 1, CMD_LEVEL_LAND); } /* static */ bool ScriptTile::DemolishTile(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR); } /* static */ bool ScriptTile::PlantTree(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::DoCommand(tile, TREE_INVALID, tile, CMD_PLANT_TREE); } /* static */ bool ScriptTile::PlantTreeRectangle(TileIndex tile, uint width, uint height) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, width >= 1 && width <= 20); EnforcePrecondition(false, height >= 1 && height <= 20); TileIndex end_tile = tile + ::TileDiffXY(width - 1, height - 1); return ScriptObject::DoCommand(tile, TREE_INVALID, end_tile, CMD_PLANT_TREE); } /* static */ bool ScriptTile::IsWithinTownInfluence(TileIndex tile, TownID town_id) { return ScriptTown::IsWithinTownInfluence(town_id, tile); } /* static */ TownID ScriptTile::GetTownAuthority(TileIndex tile) { if (!::IsValidTile(tile)) return INVALID_TOWN; Town *town = ::ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); if (town == NULL) return INVALID_TOWN; return town->index; } /* static */ TownID ScriptTile::GetClosestTown(TileIndex tile) { if (!::IsValidTile(tile)) return INVALID_TOWN; Town *town = ::ClosestTownFromTile(tile, UINT_MAX); if (town == NULL) return INVALID_TOWN; return town->index; } /* static */ Money ScriptTile::GetBuildCost(BuildType build_type) { switch (build_type) { case BT_FOUNDATION: return ::GetPrice(PR_BUILD_FOUNDATION, 1, NULL); case BT_TERRAFORM: return ::GetPrice(PR_TERRAFORM, 1, NULL); case BT_BUILD_TREES: return ::GetPrice(PR_BUILD_TREES, 1, NULL); case BT_CLEAR_GRASS: return ::GetPrice(PR_CLEAR_GRASS, 1, NULL); case BT_CLEAR_ROUGH: return ::GetPrice(PR_CLEAR_ROUGH, 1, NULL); case BT_CLEAR_ROCKY: return ::GetPrice(PR_CLEAR_ROCKS, 1, NULL); case BT_CLEAR_FIELDS: return ::GetPrice(PR_CLEAR_FIELDS, 1, NULL); case BT_CLEAR_HOUSE: return ::GetPrice(PR_CLEAR_HOUSE, 1, NULL); default: return -1; } } openttd-1.5.3/src/script/api/script_event_types.cpp0000644000000000000000000001511712627373434021214 0ustar rootroot/* $Id: script_event_types.cpp 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 script_event_types.cpp Implementation of all EventTypes. */ #include "../../stdafx.h" #include "script_event_types.hpp" #include "script_vehicle.hpp" #include "script_log.hpp" #include "../../strings_func.h" #include "../../settings_type.h" #include "../../engine_base.h" #include "../../articulated_vehicles.h" #include "../../string_func.h" #include "table/strings.h" #include "../../safeguards.h" bool ScriptEventEnginePreview::IsEngineValid() const { const Engine *e = ::Engine::GetIfValid(this->engine); return e != NULL && e->IsEnabled(); } char *ScriptEventEnginePreview::GetName() { if (!this->IsEngineValid()) return NULL; ::SetDParam(0, this->engine); return GetString(STR_ENGINE_NAME); } CargoID ScriptEventEnginePreview::GetCargoType() { if (!this->IsEngineValid()) return CT_INVALID; CargoArray cap = ::GetCapacityOfArticulatedParts(this->engine); CargoID most_cargo = CT_INVALID; uint amount = 0; for (CargoID cid = 0; cid < NUM_CARGO; cid++) { if (cap[cid] > amount) { amount = cap[cid]; most_cargo = cid; } } return most_cargo; } int32 ScriptEventEnginePreview::GetCapacity() { if (!this->IsEngineValid()) return -1; const Engine *e = ::Engine::Get(this->engine); switch (e->type) { case VEH_ROAD: case VEH_TRAIN: { CargoArray capacities = GetCapacityOfArticulatedParts(this->engine); for (CargoID c = 0; c < NUM_CARGO; c++) { if (capacities[c] == 0) continue; return capacities[c]; } return -1; } case VEH_SHIP: case VEH_AIRCRAFT: return e->GetDisplayDefaultCapacity(); default: NOT_REACHED(); } } int32 ScriptEventEnginePreview::GetMaxSpeed() { if (!this->IsEngineValid()) return -1; const Engine *e = ::Engine::Get(this->engine); int32 max_speed = e->GetDisplayMaxSpeed(); // km-ish/h if (e->type == VEH_AIRCRAFT) max_speed /= _settings_game.vehicle.plane_speed; return max_speed; } Money ScriptEventEnginePreview::GetPrice() { if (!this->IsEngineValid()) return -1; return ::Engine::Get(this->engine)->GetCost(); } Money ScriptEventEnginePreview::GetRunningCost() { if (!this->IsEngineValid()) return -1; return ::Engine::Get(this->engine)->GetRunningCost(); } int32 ScriptEventEnginePreview::GetVehicleType() { if (!this->IsEngineValid()) return ScriptVehicle::VT_INVALID; switch (::Engine::Get(this->engine)->type) { case VEH_ROAD: return ScriptVehicle::VT_ROAD; case VEH_TRAIN: return ScriptVehicle::VT_RAIL; case VEH_SHIP: return ScriptVehicle::VT_WATER; case VEH_AIRCRAFT: return ScriptVehicle::VT_AIR; default: NOT_REACHED(); } } bool ScriptEventEnginePreview::AcceptPreview() { if (!this->IsEngineValid()) return false; return ScriptObject::DoCommand(0, this->engine, 0, CMD_WANT_ENGINE_PREVIEW); } bool ScriptEventCompanyAskMerger::AcceptMerger() { return ScriptObject::DoCommand(0, this->owner, 0, CMD_BUY_COMPANY); } ScriptEventAdminPort::ScriptEventAdminPort(const char *json) : ScriptEvent(ET_ADMIN_PORT), json(stredup(json)) { } ScriptEventAdminPort::~ScriptEventAdminPort() { free(this->json); } #define SKIP_EMPTY(p) while (*(p) == ' ' || *(p) == '\n' || *(p) == '\r') (p)++; #define RETURN_ERROR(stack) { ScriptLog::Error("Received invalid JSON data from AdminPort."); if (stack != 0) sq_pop(vm, stack); return NULL; } SQInteger ScriptEventAdminPort::GetObject(HSQUIRRELVM vm) { char *p = this->json; if (this->ReadTable(vm, p) == NULL) { sq_pushnull(vm); return 1; } return 1; } char *ScriptEventAdminPort::ReadString(HSQUIRRELVM vm, char *p) { char *value = p; bool escape = false; for (;;) { if (*p == '\\') { escape = true; p++; continue; } if (*p == '"' && escape) { escape = false; p++; continue; } escape = false; if (*p == '"') break; if (*p == '\0') RETURN_ERROR(0); p++; } *p = '\0'; sq_pushstring(vm, value, -1); *p++ = '"'; return p; } char *ScriptEventAdminPort::ReadTable(HSQUIRRELVM vm, char *p) { sq_newtable(vm); SKIP_EMPTY(p); if (*p++ != '{') RETURN_ERROR(1); for (;;) { SKIP_EMPTY(p); if (*p++ != '"') RETURN_ERROR(1); p = ReadString(vm, p); if (p == NULL) { sq_pop(vm, 1); return NULL; } SKIP_EMPTY(p); if (*p++ != ':') RETURN_ERROR(2); p = this->ReadValue(vm, p); if (p == NULL) { sq_pop(vm, 2); return NULL; } sq_rawset(vm, -3); /* The key (-2) and value (-1) are popped from the stack by squirrel. */ SKIP_EMPTY(p); if (*p == ',') { p++; continue; } break; } SKIP_EMPTY(p); if (*p++ != '}') RETURN_ERROR(1); return p; } char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, char *p) { SKIP_EMPTY(p); if (strncmp(p, "false", 5) == 0) { sq_pushinteger(vm, 0); return p + 5; } if (strncmp(p, "true", 4) == 0) { sq_pushinteger(vm, 1); return p + 4; } if (strncmp(p, "null", 4) == 0) { sq_pushnull(vm); return p + 4; } switch (*p) { case '"': { /* String */ p = ReadString(vm, ++p); if (p == NULL) return NULL; break; } case '{': { /* Table */ p = this->ReadTable(vm, p); if (p == NULL) return NULL; break; } case '[': { /* Array */ sq_newarray(vm, 0); /* Empty array? */ char *p2 = p + 1; SKIP_EMPTY(p2); if (*p2 == ']') { p = p2 + 1; break; } while (*p++ != ']') { p = this->ReadValue(vm, p); if (p == NULL) { sq_pop(vm, 1); return NULL; } sq_arrayappend(vm, -2); SKIP_EMPTY(p); if (*p == ',') continue; if (*p == ']') break; RETURN_ERROR(1); } p++; break; } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': case '-': { /* Integer */ const char *value = p++; for (;;) { switch (*p++) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': continue; default: break; } p--; break; } int res = atoi(value); sq_pushinteger(vm, (SQInteger)res); break; } default: RETURN_ERROR(0); } return p; } #undef SKIP_EMPTY #undef RETURN_ERROR openttd-1.5.3/src/script/api/script_waypointlist.cpp0000644000000000000000000000306312627373434021412 0ustar rootroot/* $Id: script_waypointlist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_waypointlist.cpp Implementation of ScriptWaypointList and friends. */ #include "../../stdafx.h" #include "script_waypointlist.hpp" #include "script_vehicle.hpp" #include "../../vehicle_base.h" #include "../../waypoint_base.h" #include "../../safeguards.h" ScriptWaypointList::ScriptWaypointList(ScriptWaypoint::WaypointType waypoint_type) { const Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { if ((wp->facilities & waypoint_type) && (wp->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || wp->owner == OWNER_NONE)) this->AddItem(wp->index); } } ScriptWaypointList_Vehicle::ScriptWaypointList_Vehicle(VehicleID vehicle_id) { if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return; const Vehicle *v = ::Vehicle::Get(vehicle_id); for (const Order *o = v->GetFirstOrder(); o != NULL; o = o->next) { if (o->IsType(OT_GOTO_WAYPOINT)) this->AddItem(o->GetDestination()); } } openttd-1.5.3/src/script/api/ai_changelog.hpp0000644000000000000000000003251212627373434017666 0ustar rootroot/* $Id: ai_changelog.hpp 27433 2015-11-01 12:09:41Z frosch $ */ /* * 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 ai_changelog.hpp Lists all changes / additions to the API. * * Only new / renamed / deleted api functions will be listed here. A list of * bug fixes can be found in the normal changelog. Note that removed API * functions may still be available if you return an older API version * in GetAPIVersion() in info.nut. * * \b 1.5.3 * * No changes * * \b 1.5.2 * * No changes * * \b 1.5.1 * * No changes * * \b 1.5.0 * * API additions: * \li AIList::SwapList * \li AIStation::GetCargoPlanned * \li AIStation::GetCargoPlannedFrom * \li AIStation::GetCargoPlannedFromVia * \li AIStation::GetCargoPlannedVia * \li AIStation::GetCargoWaitingFromVia * \li AIStationList_CargoPlannedByFrom * \li AIStationList_CargoPlannedByVia * \li AIStationList_CargoPlannedFromByVia * \li AIStationList_CargoPlannedViaByFrom * \li AIStationList_CargoWaitingByFrom * \li AIStationList_CargoWaitingByVia * \li AIStationList_CargoWaitingFromByVia * \li AIStationList_CargoWaitingViaByFrom * * \b 1.4.4 * * No changes * * \b 1.4.3 * * No changes * * \b 1.4.2 * * No changes * * \b 1.4.1 * * No changes * * \b 1.4.0 * * API additions: * \li AICargo::GetDistributionType * \li AIDate::DATE_INVALID * \li AIDate::IsValidDate * \li AIStation::HasCargoRating * \li AIStation::GetCargoWaitingFrom * \li AIStation::GetCargoWaitingVia * \li AITile::GetTerrainType * \li AITown::FoundTown * \li AITown::GetFundBuildingsDuration * \li AITown::TOWN_GROWTH_NONE * * Other changes: * \li AIStation::GetCargoRating does return -1 for cargo-station combinations that * do not have a rating yet instead of returning 69. * * \b 1.3.3 * * No changes * * \b 1.3.2 * * No changes * * \b 1.3.1 * * API additions: * \li AITile::GetTerrainType * * \b 1.3.0 * * API additions: * \li AIEventExclusiveTransportRights * \li AIEventRoadReconstruction * \li AIIndustryType::IsProcessingIndustry * \li AIStation::IsAirportClosed * \li AIStation::OpenCloseAirport * \li AIController::Break * * \b 1.2.3 * * No changes * * \b 1.2.2 * * No changes * * \b 1.2.1 * * No changes * * \b 1.2.0 * * API additions: * * \li AIAirport::GetMaintenanceCostFactor * \li AICargo::CT_AUTO_REFIT * \li AICargo::CT_NO_REFIT * \li AICargo::IsValidTownEffect * \li AICargoList_StationAccepting * \li AICompany::GetQuarterlyIncome * \li AICompany::GetQuarterlyExpenses * \li AICompany::GetQuarterlyCargoDelivered * \li AICompany::GetQuarterlyPerformanceRating * \li AICompany::GetQuarterlyCompanyValue * \li AIController::GetOpsTillSuspend * \li AIEngine::GetMaximumOrderDistance * \li AIEventAircraftDestTooFar * \li AIInfo::CONFIG_DEVELOPER * \li AIInfrastructure * \li AIOrder::ERR_ORDER_AIRCRAFT_NOT_ENOUGH_RANGE * \li AIOrder::GetOrderDistance * \li AIOrder::GetOrderRefit * \li AIOrder::IsRefitOrder * \li AIOrder::SetOrderRefit * \li AIRail::GetMaintenanceCostFactor * \li AIRoad::GetMaintenanceCostFactor * \li AITile::GetTownAuthority * \li AITown::GetCargoGoal * \li AITown::GetGrowthRate * \li AITown::GetLastMonthReceived * \li AITownEffectList (to walk over all available town effects) * \li AIVehicle::ERR_VEHICLE_TOO_LONG in case vehicle length limit is reached * \li AIVehicle::GetMaximumOrderDistance * * API renames: * \li AITown::GetLastMonthTransported to AITown::GetLastMonthSupplied to better * reflect what it does. * \li AIInfo has all its configure settings renamed from AICONFIG to just CONFIG * like CONFIG_RANDOM. * \li AIEvent has all its types renamed from AI_ET_ prefix to just ET_ prefix, * like ET_SUBSIDY_OFFER. * \li AIOrder has all its types renamed from AIOF_ prefix to just OF_ prefix. * * API removals: * \li AICompany::GetCompanyValue, use AICompany::GetQuarterlyCompanyValue instead. * * Other changes: * \li AITown::GetLastMonthProduction no longer has prerequisites based on town * effects. * \li AITown::GetLastMonthTransported resp. AITown::GetLastMonthSupplied no longer has prerequisites based on * town effects. * \li AITown::GetLastMonthTransportedPercentage no longer has prerequisites * based on town effects. * * \b 1.1.5 * * No changes * * \b 1.1.4 * * API additions: * \li AIVehicle::ERR_VEHICLE_TOO_LONG in case vehicle length limit is reached. * * \b 1.1.3 * * No changes * * \b 1.1.2 * * No changes * * \b 1.1.1 * * No changes * * \b 1.1.0 * * API additions: * \li IsEnd for all lists. * \li AIEventTownFounded * \li AIIndustry::GetIndustryID * \li AIIndustryType::INDUSTRYTYPE_TOWN * \li AIIndustryType::INDUSTRYTYPE_UNKNOWN * \li AIOrder::IsVoidOrder * \li AIRail::GetName * \li AITown::IsCity * * API removals: * \li HasNext for all lists. * \li AIAbstractList, use AIList instead. * \li AIList::ChangeItem, use AIList::SetValue instead. * \li AIRail::ERR_NONUNIFORM_STATIONS_DISABLED, that error is never returned anymore. * * Other changes: * \li AIEngine::GetMaxTractiveEffort can be used for road vehicles. * \li AIEngine::GetPower can be used for road vehicles. * \li AIEngine::GetWeight can be used for road vehicles. * \li AIIndustry::IsCargoAccepted now returns CargoAcceptState instead of a boolean. * \li AIOrder::GetOrderFlags returns AIOrder::AIOF_INVALID for void orders as well. * \li AIRoad::BuildDriveThroughRoadStation now allows overbuilding. * \li AIRoad::BuildRoadStation now allows overbuilding. * * \b 1.0.5 * * No changes * * \b 1.0.4 * * No changes * * \b 1.0.3 * * API additions: * \li AIRail::ERR_RAILTYPE_DISALLOWS_CROSSING * * \b 1.0.2 * * Other changes: * \li AIBridge::GetPrice now returns the price of the bridge without the cost for the rail or road. * * \b 1.0.1 * * API additions: * \li AIRail::GetMaxSpeed * * \b 1.0.0 * * API additions: * \li AIBaseStation * \li AIEngine::IsBuildable * \li AIEventCompanyAskMerger * \li AIIndustry::GetLastMonthTransportedPercentage * \li AIInfo::AICONFIG_INGAME * \li AIMarine::GetBuildCost * \li AIOrder::AIOF_GOTO_NEAREST_DEPOT * \li AIOrder::GetStopLocation * \li AIOrder::SetStopLocation * \li AIRail::RemoveRailStationTileRectangle * \li AIRail::RemoveRailWaypointTileRectangle * \li AIRail::GetBuildCost * \li AIRoad::GetBuildCost * \li AISubsidy::SubsidyParticipantType * \li AISubsidy::GetSourceType * \li AISubsidy::GetSourceIndex * \li AISubsidy::GetDestinationType * \li AISubsidy::GetDestinationIndex * \li AITile::GetBuildCost * \li AITown::GetLastMonthTransportedPercentage * \li AIVehicleList_Depot * \li AIWaypoint::WaypointType * \li AIWaypoint::HasWaypointType * \li Some error messages to AIWaypoint * * API removals: * \li AIOrder::ChangeOrder, use AIOrder::SetOrderFlags instead * \li AIRail::RemoveRailStationTileRect, use AIRail::RemoveRailStationTileRectangle instead * \li AIRail::RemoveRailWaypoint, use AIRail::RemoveRailWaypointTileRectangle instead * \li AISign::GetMaxSignID, use AISignList instead * \li AIStation::ERR_STATION_TOO_LARGE, use AIError::ERR_STATION_TOO_SPREAD_OUT instead * \li AISubsidy::SourceIsTown, use AISubsidy::GetSourceType instead * \li AISubsidy::GetSource, use AISubsidy::GetSourceIndex instead * \li AISubsidy::DestinationIsTown, use AISubsidy::GetDestinationType instead * \li AISubsidy::GetDestination, use AISubsidy::GetDestinationIndex instead * \li AITile::GetHeight, use AITile::GetMinHeight/GetMaxHeight/GetCornerHeight instead * \li AITown::GetMaxProduction, use AITown::GetLastMonthProduction instead * \li AIVehicle::SkipToVehicleOrder, use AIOrder::SkipToOrder instead * \li AIWaypoint::WAYPOINT_INVALID, use AIBaseStation::STATION_INVALID instead * * Other changes: * \li The GetName / SetName / GetLocation functions were moved from AIStation * and AIWaypoint to AIBaseStation, but you can still use AIStation.GetName * as before * \li The GetConstructionDate function was moved from AIStation to * AIBaseStation, but can still be used as AIStation.GetConstructionDate * \li WaypointID was replaced by StationID. All WaypointIDs from previous * savegames are invalid. Use STATION_INVALID instead of WAYPOINT_INVALID * \li AIWaypointList constructor now needs a WaypointType similar to AIStationList, * it can also handle buoys. * \li AIVehicleList_Station now also works for waypoints * \li Stations can be build over rail without signals that is in the right * direction for the to-be built station. It will also convert the rail if * the station's rail type supports the old type. * \li GetAPIVersion() was added as function to info.nut. If it does not exist * API version 0.7 is assumed. This function should return the major and * minor number of the stable version of the API the AI is written against. * For 0.7.2 that would be 0.7, for 1.1.3 it would be 1.1, etc. * \li The subsidy logic has changed. Subsidy is now awarded when cargo * originating from subsidy source is delivered to station that has subsidy * destination it its catchment area. One industry tile or one town house * is enough as long as station accepts the cargo. Awarded subsidies are no * longer bound to stations used for first delivery, any station can be * used for loading and unloading as long as cargo is transfered from * source to destination. * \li Make AIEngine:CanRefitCargo() not report refittability to mail by * default for aircraft. It is not necessarily true. This means that even * if the aircraft can carry mail (as secondary cargo) it does not return * true if the aircraft cannot carry it as its only cargo. * \li Improve behaviour of AIEngine::GetCargoType(), AIEventEnginePreview::GetCargoType() * and AIEngine::CanRefitCargo() for articulated vehicles. For * CanRefitCargo true is returned if at least one part can be refitted. * For GetCargoType the first most used cargo type is returned. * \li AIIndustryType::GetConstructionCost() now returns -1 if the industry is * neither buildable nor prospectable. * \li AIEngine::IsValidEngine will now return true if you have at least one * vehicle of that type in your company, regardless if it's still buildable * or not. AIEngine::IsBuildable returns only true when you can actually * build an engine. * \li AITile::GetCargoProduction will now return the number of producers, * including houses instead the number of producing tiles. This means that * also industries that do not have a tile within the radius, but where * the search bounding box and the industry's bounding box intersect, are * counted. Previously these industries (and their cargoes), although they * produced cargo for a station at the given location, were not returned. * \li AIRail::BuildRail will now fail completely if there is an obstacle * between the begin and end, instead of building up to the obstacle and * returning that everything went okay. * \li Orders for buoys are now waypoint orders, i.e. instead of using the * station orders for buoys one has to use waypoint orders. * \li Autoreplaces can now also be set for the default group via AIGroup. * * \b 0.7.5 * * No changes * * \b 0.7.4 * * No changes * * \b 0.7.3 * * API additions: * \li AIAbstractList::SORT_ASCENDING * \li AIAbstractList::SORT_DESCENDING * \li AIAirport::IsAirportInformationAvailable * \li AICompany::GetPresidentGender * \li AICompany::SetPresidentGender * \li AIEngine::GetDesignDate * \li AIStation::GetConstructionDate * * Other changes: * \li AIs are now killed when they execute a DoCommand or Sleep at a time * they are not allowed to do so. * \li When the API requests a string as parameter you can give every squirrel * type and it will be converted to a string * \li AIs can create subclasses of API classes and use API constants as part * of their own constants * * \b 0.7.2 * * API additions: * \li AIVehicle::GetReliability * * Other changes: * \li DoCommands and sleeps in call, acall, pcall and valuators are disallowed * * \b 0.7.1 * * API additions: * \li AIAirport::GetPrice * \li AIController::GetVersion * \li AIOrder::AIOF_DEPOT_FLAGS * \li AIOrder::AIOF_STOP_IN_DEPOT * \li AIOrder::IsCurrentOrderPartOfOrderList * \li AIOrder::IsGotoDepotOrder * \li AIOrder::IsGotoStationOrder * \li AIOrder::IsGotoWaypointOrder * \li AISignList * \li AITile::CORNER_[WSEN] * \li AITile::ERR_AREA_ALREADY_FLAT * \li AITile::ERR_EXCAVATION_WOULD_DAMAGE * \li AITile::GetCornerHeight * \li AITile::GetMaxHeight * \li AITile::GetMinHeight * \li AIVehicle::SendVehicleToDepotForServicing * * Other changes: * \li GetURL() was added as optional function to info.nut * \li UseAsRandomAI() was added as optional function to info.nut * \li A limit was introduced on the time the AI spends in the constructor and Load function * * \b 0.7.0 * \li First stable release with the NoAI framework. */ openttd-1.5.3/src/script/api/script_rail.cpp0000644000000000000000000005327212627373434017602 0ustar rootroot/* $Id: script_rail.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_rail.cpp Implementation of ScriptRail. */ #include "../../stdafx.h" #include "script_rail.hpp" #include "script_map.hpp" #include "script_station.hpp" #include "script_industrytype.hpp" #include "script_cargo.hpp" #include "../../debug.h" #include "../../station_base.h" #include "../../newgrf_generic.h" #include "../../newgrf_station.h" #include "../../strings_func.h" #include "../../safeguards.h" /* static */ char *ScriptRail::GetName(RailType rail_type) { if (!IsRailTypeAvailable(rail_type)) return NULL; return GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text); } /* static */ bool ScriptRail::IsRailTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return (::IsTileType(tile, MP_RAILWAY) && !::IsRailDepot(tile)) || (::HasStationTileRail(tile) && !::IsStationTileBlocked(tile)) || ::IsLevelCrossingTile(tile); } /* static */ bool ScriptRail::IsLevelCrossingTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsLevelCrossingTile(tile); } /* static */ bool ScriptRail::IsRailDepotTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsRailDepotTile(tile); } /* static */ bool ScriptRail::IsRailStationTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsRailStationTile(tile); } /* static */ bool ScriptRail::IsRailWaypointTile(TileIndex tile) { if (!::IsValidTile(tile)) return false; return ::IsRailWaypointTile(tile); } /* static */ bool ScriptRail::IsRailTypeAvailable(RailType rail_type) { if ((::RailType)rail_type < RAILTYPE_BEGIN || (::RailType)rail_type >= RAILTYPE_END) return false; return ScriptObject::GetCompany() == OWNER_DEITY || ::HasRailtypeAvail(ScriptObject::GetCompany(), (::RailType)rail_type); } /* static */ ScriptRail::RailType ScriptRail::GetCurrentRailType() { return (RailType)ScriptObject::GetRailType(); } /* static */ void ScriptRail::SetCurrentRailType(RailType rail_type) { if (!IsRailTypeAvailable(rail_type)) return; ScriptObject::SetRailType((::RailType)rail_type); } /* static */ bool ScriptRail::TrainCanRunOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type) { if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false; if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false; return ::IsCompatibleRail((::RailType)engine_rail_type, (::RailType)track_rail_type); } /* static */ bool ScriptRail::TrainHasPowerOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type) {\ if (!ScriptRail::IsRailTypeAvailable(engine_rail_type)) return false; if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false; return ::HasPowerOnRail((::RailType)engine_rail_type, (::RailType)track_rail_type); } /* static */ ScriptRail::RailType ScriptRail::GetRailType(TileIndex tile) { if (!ScriptTile::HasTransportType(tile, ScriptTile::TRANSPORT_RAIL)) return RAILTYPE_INVALID; return (RailType)::GetRailType(tile); } /* static */ bool ScriptRail::ConvertRailType(TileIndex start_tile, TileIndex end_tile, ScriptRail::RailType convert_to) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(start_tile)); EnforcePrecondition(false, ::IsValidTile(end_tile)); EnforcePrecondition(false, IsRailTypeAvailable(convert_to)); return ScriptObject::DoCommand(start_tile, end_tile, convert_to, CMD_CONVERT_RAIL); } /* static */ TileIndex ScriptRail::GetRailDepotFrontTile(TileIndex depot) { if (!IsRailDepotTile(depot)) return INVALID_TILE; return depot + ::TileOffsByDiagDir(::GetRailDepotDirection(depot)); } /* static */ ScriptRail::RailTrack ScriptRail::GetRailStationDirection(TileIndex tile) { if (!IsRailStationTile(tile)) return RAILTRACK_INVALID; return (RailTrack)::GetRailStationTrackBits(tile); } /* static */ bool ScriptRail::BuildRailDepot(TileIndex tile, TileIndex front) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, tile != front); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(front)); EnforcePrecondition(false, ::TileX(tile) == ::TileX(front) || ::TileY(tile) == ::TileY(front)); EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType())); uint entrance_dir = (::TileX(tile) == ::TileX(front)) ? (::TileY(tile) < ::TileY(front) ? 1 : 3) : (::TileX(tile) < ::TileX(front) ? 2 : 0); return ScriptObject::DoCommand(tile, ScriptObject::GetRailType(), entrance_dir, CMD_BUILD_TRAIN_DEPOT); } /* static */ bool ScriptRail::BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW); EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF); EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF); EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType())); EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id)); uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8); if (direction == RAILTRACK_NW_SE) p1 |= (1 << 4); if (station_id != ScriptStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24); return ScriptObject::DoCommand(tile, p1, (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16, CMD_BUILD_RAIL_STATION); } /* static */ bool ScriptRail::BuildNewGRFRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, int distance, bool source_station) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW); EnforcePrecondition(false, num_platforms > 0 && num_platforms <= 0xFF); EnforcePrecondition(false, platform_length > 0 && platform_length <= 0xFF); EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType())); EnforcePrecondition(false, station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id)); EnforcePrecondition(false, ScriptCargo::IsValidCargo(cargo_id)); EnforcePrecondition(false, source_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(source_industry)); EnforcePrecondition(false, goal_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(goal_industry)); uint32 p1 = GetCurrentRailType() | (platform_length << 16) | (num_platforms << 8); if (direction == RAILTRACK_NW_SE) p1 |= 1 << 4; if (station_id != ScriptStation::STATION_JOIN_ADJACENT) p1 |= (1 << 24); const GRFFile *file; uint16 res = GetAiPurchaseCallbackResult(GSF_STATIONS, cargo_id, 0, source_industry, goal_industry, min(255, distance / 2), AICE_STATION_GET_STATION_ID, source_station ? 0 : 1, min(15, num_platforms) << 4 | min(15, platform_length), &file); uint32 p2 = (ScriptStation::IsValidStation(station_id) ? station_id : INVALID_STATION) << 16; if (res != CALLBACK_FAILED) { int index = 0; const StationSpec *spec = StationClass::GetByGrf(file->grfid, res, &index); if (spec == NULL) { DEBUG(grf, 1, "%s returned an invalid station ID for 'AI construction/purchase selection (18)' callback", file->filename); } else { /* We might have gotten an usable station spec. Try to build it, but if it fails we'll fall back to the original station. */ if (ScriptObject::DoCommand(tile, p1, p2 | spec->cls_id | index << 8, CMD_BUILD_RAIL_STATION)) return true; } } return ScriptObject::DoCommand(tile, p1, p2, CMD_BUILD_RAIL_STATION); } /* static */ bool ScriptRail::BuildRailWaypoint(TileIndex tile) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, IsRailTile(tile)); EnforcePrecondition(false, GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE); EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType())); return ScriptObject::DoCommand(tile, GetCurrentRailType() | (GetRailTracks(tile) == RAILTRACK_NE_SW ? AXIS_X : AXIS_Y) << 4 | 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_RAIL_WAYPOINT); } /* static */ bool ScriptRail::RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(tile2)); return ScriptObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_WAYPOINT); } /* static */ bool ScriptRail::RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(tile2)); return ScriptObject::DoCommand(tile, tile2, keep_rail ? 1 : 0, CMD_REMOVE_FROM_RAIL_STATION); } /* static */ uint ScriptRail::GetRailTracks(TileIndex tile) { if (!IsRailTile(tile)) return RAILTRACK_INVALID; if (IsRailStationTile(tile) || IsRailWaypointTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile)); if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile); if (IsRailDepotTile(tile)) return ::TRACK_BIT_NONE; return ::GetTrackBits(tile); } /* static */ bool ScriptRail::BuildRailTrack(TileIndex tile, RailTrack rail_track) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, rail_track != 0); EnforcePrecondition(false, (rail_track & ~::TRACK_BIT_ALL) == 0); EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0); EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType())); return ScriptObject::DoCommand(tile, tile, GetCurrentRailType() | (FindFirstTrack((::TrackBits)rail_track) << 4), CMD_BUILD_RAILROAD_TRACK); } /* static */ bool ScriptRail::RemoveRailTrack(TileIndex tile, RailTrack rail_track) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsPlainRailTile(tile) || ::IsLevelCrossingTile(tile)); EnforcePrecondition(false, GetRailTracks(tile) & rail_track); EnforcePrecondition(false, KillFirstBit((uint)rail_track) == 0); return ScriptObject::DoCommand(tile, tile, FindFirstTrack((::TrackBits)rail_track) << 4, CMD_REMOVE_RAILROAD_TRACK); } /* static */ bool ScriptRail::AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to) { if (!IsRailTile(tile)) return false; if (from == to || ScriptMap::DistanceManhattan(from, tile) != 1 || ScriptMap::DistanceManhattan(tile, to) != 1) return false; if (to < from) ::Swap(from, to); if (tile - from == 1) { if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NE_SW) != 0; if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NE_SE) != 0; } else if (tile - from == ::MapSizeX()) { if (tile - to == 1) return (GetRailTracks(tile) & RAILTRACK_NW_NE) != 0; if (to - tile == 1) return (GetRailTracks(tile) & RAILTRACK_NW_SW) != 0; if (to - tile == ::MapSizeX()) return (GetRailTracks(tile) & RAILTRACK_NW_SE) != 0; } else { return (GetRailTracks(tile) & RAILTRACK_SW_SE) != 0; } NOT_REACHED(); } /** * Prepare the second parameter for CmdBuildRailroadTrack and CmdRemoveRailroadTrack. The direction * depends on all three tiles. Sometimes the third tile needs to be adjusted. */ static uint32 SimulateDrag(TileIndex from, TileIndex tile, TileIndex *to) { int diag_offset = abs(abs((int)::TileX(*to) - (int)::TileX(tile)) - abs((int)::TileY(*to) - (int)::TileY(tile))); uint32 p2 = 0; if (::TileY(from) == ::TileY(*to)) { p2 |= (TRACK_X << 4); *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1); } else if (::TileX(from) == ::TileX(*to)) { p2 |= (TRACK_Y << 4); *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1); } else if (::TileY(from) < ::TileY(tile)) { if (::TileX(*to) < ::TileX(tile)) { p2 |= (TRACK_UPPER << 4); } else { p2 |= (TRACK_LEFT << 4); } if (diag_offset != 0) { *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1); } else { *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1); } } else if (::TileY(from) > ::TileY(tile)) { if (::TileX(*to) < ::TileX(tile)) { p2 |= (TRACK_RIGHT << 4); } else { p2 |= (TRACK_LOWER << 4); } if (diag_offset != 0) { *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1); } else { *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1); } } else if (::TileX(from) < ::TileX(tile)) { if (::TileY(*to) < ::TileY(tile)) { p2 |= (TRACK_UPPER << 4); } else { p2 |= (TRACK_RIGHT << 4); } if (diag_offset == 0) { *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1); } else { *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1); } } else if (::TileX(from) > ::TileX(tile)) { if (::TileY(*to) < ::TileY(tile)) { p2 |= (TRACK_LEFT << 4); } else { p2 |= (TRACK_LOWER << 4); } if (diag_offset == 0) { *to -= Clamp((int)::TileX(*to) - (int)::TileX(tile), -1, 1); } else { *to -= ::MapSizeX() * Clamp((int)::TileY(*to) - (int)::TileY(tile), -1, 1); } } return p2; } /* static */ bool ScriptRail::BuildRail(TileIndex from, TileIndex tile, TileIndex to) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(from)); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(to)); EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1); EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1); EnforcePrecondition(false, IsRailTypeAvailable(GetCurrentRailType())); int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile))); EnforcePrecondition(false, diag_offset <= 1 || (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) || (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to))); uint32 p2 = SimulateDrag(from, tile, &to) | 1 << 8 | ScriptRail::GetCurrentRailType();; return ScriptObject::DoCommand(tile, to, p2, CMD_BUILD_RAILROAD_TRACK); } /* static */ bool ScriptRail::RemoveRail(TileIndex from, TileIndex tile, TileIndex to) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ::IsValidTile(from)); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, ::IsValidTile(to)); EnforcePrecondition(false, ::DistanceManhattan(from, tile) == 1); EnforcePrecondition(false, ::DistanceManhattan(tile, to) >= 1); int diag_offset = abs(abs((int)::TileX(to) - (int)::TileX(tile)) - abs((int)::TileY(to) - (int)::TileY(tile))); EnforcePrecondition(false, diag_offset <= 1 || (::TileX(from) == ::TileX(tile) && ::TileX(tile) == ::TileX(to)) || (::TileY(from) == ::TileY(tile) && ::TileY(tile) == ::TileY(to))); uint32 p2 = SimulateDrag(from, tile, &to); return ScriptObject::DoCommand(tile, to, p2, CMD_REMOVE_RAILROAD_TRACK); } /** * Contains information about the trackdir that belongs to a track when entering * from a specific direction. */ struct ScriptRailSignalData { Track track; ///< The track that will be taken to travel. Trackdir trackdir; ///< The Trackdir belonging to that track. uint signal_cycles; ///< How many times the signal should be cycled in order to build it in the correct direction. }; static const int NUM_TRACK_DIRECTIONS = 3; ///< The number of directions you can go when entering a tile. /** * List information about the trackdir and number of needed cycles for building signals when * entering a track from a specific direction. The first index is the difference between the * TileIndex of the previous and current tile, where (-)MapSizeX is replaced with -2 / 2 and * 2 it added. */ static const ScriptRailSignalData _possible_trackdirs[5][NUM_TRACK_DIRECTIONS] = { {{TRACK_UPPER, TRACKDIR_UPPER_E, 0}, {TRACK_Y, TRACKDIR_Y_SE, 0}, {TRACK_LEFT, TRACKDIR_LEFT_S, 1}}, {{TRACK_RIGHT, TRACKDIR_RIGHT_S, 1}, {TRACK_X, TRACKDIR_X_SW, 1}, {TRACK_UPPER, TRACKDIR_UPPER_W, 1}}, {{INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}, {INVALID_TRACK, INVALID_TRACKDIR, 0}}, {{TRACK_LOWER, TRACKDIR_LOWER_E, 0}, {TRACK_X, TRACKDIR_X_NE, 0}, {TRACK_LEFT, TRACKDIR_LEFT_N, 0}}, {{TRACK_RIGHT, TRACKDIR_RIGHT_N, 0}, {TRACK_Y, TRACKDIR_Y_NW, 1}, {TRACK_LOWER, TRACKDIR_LOWER_W, 1}} }; /* static */ ScriptRail::SignalType ScriptRail::GetSignalType(TileIndex tile, TileIndex front) { if (ScriptMap::DistanceManhattan(tile, front) != 1) return SIGNALTYPE_NONE; if (!::IsTileType(tile, MP_RAILWAY) || !::HasSignals(tile)) return SIGNALTYPE_NONE; int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile)); for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) { const Track &track = _possible_trackdirs[data_index][i].track; if (!(::TrackToTrackBits(track) & GetRailTracks(tile))) continue; if (!HasSignalOnTrack(tile, track)) continue; if (!HasSignalOnTrackdir(tile, _possible_trackdirs[data_index][i].trackdir)) continue; SignalType st = (SignalType)::GetSignalType(tile, track); if (HasSignalOnTrackdir(tile, ::ReverseTrackdir(_possible_trackdirs[data_index][i].trackdir))) st = (SignalType)(st | SIGNALTYPE_TWOWAY); return st; } return SIGNALTYPE_NONE; } /** * Check if signal_type is a valid SignalType. */ static bool IsValidSignalType(int signal_type) { if (signal_type < ScriptRail::SIGNALTYPE_NORMAL || signal_type > ScriptRail::SIGNALTYPE_COMBO_TWOWAY) return false; if (signal_type > ScriptRail::SIGNALTYPE_PBS_ONEWAY && signal_type < ScriptRail::SIGNALTYPE_NORMAL_TWOWAY) return false; return true; } /* static */ bool ScriptRail::BuildSignal(TileIndex tile, TileIndex front, SignalType signal) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1) EnforcePrecondition(false, ::IsPlainRailTile(tile)); EnforcePrecondition(false, ::IsValidSignalType(signal)); Track track = INVALID_TRACK; uint signal_cycles; int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile)); for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) { const Track &t = _possible_trackdirs[data_index][i].track; if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue; track = t; signal_cycles = _possible_trackdirs[data_index][i].signal_cycles; break; } EnforcePrecondition(false, track != INVALID_TRACK); uint p1 = track; if (signal < SIGNALTYPE_TWOWAY) { if (signal != SIGNALTYPE_PBS && signal != SIGNALTYPE_PBS_ONEWAY) signal_cycles++; p1 |= (signal_cycles << 15); } p1 |= ((signal >= SIGNALTYPE_TWOWAY ? signal ^ SIGNALTYPE_TWOWAY : signal) << 5); return ScriptObject::DoCommand(tile, p1, 0, CMD_BUILD_SIGNALS); } /* static */ bool ScriptRail::RemoveSignal(TileIndex tile, TileIndex front) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, ScriptMap::DistanceManhattan(tile, front) == 1) EnforcePrecondition(false, GetSignalType(tile, front) != SIGNALTYPE_NONE); Track track = INVALID_TRACK; int data_index = 2 + (::TileX(front) - ::TileX(tile)) + 2 * (::TileY(front) - ::TileY(tile)); for (int i = 0; i < NUM_TRACK_DIRECTIONS; i++) { const Track &t = _possible_trackdirs[data_index][i].track; if (!(::TrackToTrackBits(t) & GetRailTracks(tile))) continue; track = t; break; } EnforcePrecondition(false, track != INVALID_TRACK); return ScriptObject::DoCommand(tile, track, 0, CMD_REMOVE_SIGNALS); } /* static */ Money ScriptRail::GetBuildCost(RailType railtype, BuildType build_type) { if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1; switch (build_type) { case BT_TRACK: return ::RailBuildCost((::RailType)railtype); case BT_SIGNAL: return ::GetPrice(PR_BUILD_SIGNALS, 1, NULL); case BT_DEPOT: return ::GetPrice(PR_BUILD_DEPOT_TRAIN, 1, NULL); case BT_STATION: return ::GetPrice(PR_BUILD_STATION_RAIL, 1, NULL) + ::GetPrice(PR_BUILD_STATION_RAIL_LENGTH, 1, NULL); case BT_WAYPOINT: return ::GetPrice(PR_BUILD_WAYPOINT_RAIL, 1, NULL); default: return -1; } } /* static */ int32 ScriptRail::GetMaxSpeed(RailType railtype) { if (!ScriptRail::IsRailTypeAvailable(railtype)) return -1; return ::GetRailTypeInfo((::RailType)railtype)->max_speed; } /* static */ uint16 ScriptRail::GetMaintenanceCostFactor(RailType railtype) { if (!ScriptRail::IsRailTypeAvailable(railtype)) return 0; return ::GetRailTypeInfo((::RailType)railtype)->maintenance_multiplier; } openttd-1.5.3/src/script/api/script_bridgelist.cpp0000644000000000000000000000242712627373434020777 0ustar rootroot/* $Id: script_bridgelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_bridgelist.cpp Implementation of ScriptBridgeList and friends. */ #include "../../stdafx.h" #include "script_bridgelist.hpp" #include "script_bridge.hpp" #include "../../bridge.h" #include "../../safeguards.h" ScriptBridgeList::ScriptBridgeList() { for (byte j = 0; j < MAX_BRIDGES; j++) { if (ScriptBridge::IsValidBridge(j)) this->AddItem(j); } } ScriptBridgeList_Length::ScriptBridgeList_Length(uint length) { for (byte j = 0; j < MAX_BRIDGES; j++) { if (ScriptBridge::IsValidBridge(j)) { if (length >= (uint)ScriptBridge::GetMinLength(j) && length <= (uint)ScriptBridge::GetMaxLength(j)) this->AddItem(j); } } } openttd-1.5.3/src/script/api/script_waypointlist.hpp0000644000000000000000000000300612627373434021414 0ustar rootroot/* $Id: script_waypointlist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_waypointlist.hpp List all the waypoints (you own). */ #ifndef SCRIPT_WAYPOINTLIST_HPP #define SCRIPT_WAYPOINTLIST_HPP #include "script_list.hpp" #include "script_waypoint.hpp" /** * Creates a list of waypoints of which you are the owner. * @api ai game * @ingroup ScriptList */ class ScriptWaypointList : public ScriptList { public: /** * @param waypoint_type The type of waypoint to make a list of waypoints for. */ ScriptWaypointList(ScriptWaypoint::WaypointType waypoint_type); }; /** * Creates a list of waypoints which the vehicle has in its orders. * @api ai game * @ingroup ScriptList */ class ScriptWaypointList_Vehicle : public ScriptList { public: /** * @param vehicle_id The vehicle to get the list of waypoints he has in its orders from. */ ScriptWaypointList_Vehicle(VehicleID vehicle_id); }; #endif /* SCRIPT_WAYPOINTLIST_HPP */ openttd-1.5.3/src/script/api/script_log.hpp0000644000000000000000000000604512627373434017435 0ustar rootroot/* $Id: script_log.hpp 24957 2013-02-02 19:46:46Z rubidium $ */ /* * 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 script_log.hpp Everything to handle and issue log messages. */ #ifndef SCRIPT_LOG_HPP #define SCRIPT_LOG_HPP #include "script_object.hpp" /** * Class that handles all log related functions. * @api ai game */ class ScriptLog : public ScriptObject { /* ScriptController needs access to Enum and Log, in order to keep the flow from * OpenTTD core to script API clear and simple. */ friend class ScriptController; public: /** * Log levels; The value is also feed to DEBUG() lvl. * This has no use for you, as script writer. * @api -all */ enum ScriptLogType { LOG_SQ_ERROR = 0, ///< Squirrel printed an error. LOG_ERROR = 1, ///< User printed an error. LOG_SQ_INFO = 2, ///< Squirrel printed some info. LOG_WARNING = 3, ///< User printed some warning. LOG_INFO = 4, ///< User printed some info. }; /** * Internal representation of the log-data inside the script. * This has no use for you, as script writer. * @api -all */ struct LogData { char **lines; ///< The log-lines. ScriptLog::ScriptLogType *type; ///< Per line, which type of log it was. int count; ///< Total amount of log-lines possible. int pos; ///< Current position in lines. int used; ///< Total amount of used log-lines. }; /** * Print an Info message to the logs. * @param message The message to log. * @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs. */ static void Info(const char *message); /** * Print a Warning message to the logs. * @param message The message to log. * @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs. */ static void Warning(const char *message); /** * Print an Error message to the logs. * @param message The message to log. * @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs. */ static void Error(const char *message); /** * Free the log pointer. * @api -all */ static void FreeLogPointer(); private: /** * Internal command to log the message in a common way. */ static void Log(ScriptLog::ScriptLogType level, const char *message); }; #endif /* SCRIPT_LOG_HPP */ openttd-1.5.3/src/script/api/script_depotlist.hpp0000644000000000000000000000227212627373434020661 0ustar rootroot/* $Id: script_depotlist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_depotlist.hpp List all the depots (you own). */ #ifndef SCRIPT_DEPOTLIST_HPP #define SCRIPT_DEPOTLIST_HPP #include "script_list.hpp" #include "script_tile.hpp" /** * Creates a list of the locations of the depots (and hangars) of which you are the owner. * @api ai game * @ingroup ScriptList */ class ScriptDepotList : public ScriptList { public: /** * @param transport_type The type of transport to make a list of depots for. */ ScriptDepotList(ScriptTile::TransportType transport_type); }; #endif /* SCRIPT_DEPOTLIST_HPP */ openttd-1.5.3/src/script/api/script_order.cpp0000644000000000000000000007246712627373434017775 0ustar rootroot/* $Id: script_order.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_order.cpp Implementation of ScriptOrder. */ #include "../../stdafx.h" #include "script_order.hpp" #include "script_cargo.hpp" #include "script_map.hpp" #include "../script_instance.hpp" #include "../../debug.h" #include "../../vehicle_base.h" #include "../../roadstop_base.h" #include "../../depot_base.h" #include "../../station_base.h" #include "../../waypoint_base.h" #include "../../safeguards.h" /** * Gets the order type given a tile * @param t the tile to get the order from * @return the order type, or OT_END when there is no order */ static OrderType GetOrderTypeByTile(TileIndex t) { if (!::IsValidTile(t)) return OT_END; switch (::GetTileType(t)) { default: break; case MP_STATION: if (IsBuoy(t) || IsRailWaypoint(t)) return OT_GOTO_WAYPOINT; if (IsHangar(t)) return OT_GOTO_DEPOT; return OT_GOTO_STATION; case MP_WATER: if (::IsShipDepot(t)) return OT_GOTO_DEPOT; break; case MP_ROAD: if (::GetRoadTileType(t) == ROAD_TILE_DEPOT) return OT_GOTO_DEPOT; break; case MP_RAILWAY: if (IsRailDepot(t)) return OT_GOTO_DEPOT; break; } return OT_END; } /* static */ bool ScriptOrder::IsValidVehicleOrder(VehicleID vehicle_id, OrderPosition order_position) { return ScriptVehicle::IsValidVehicle(vehicle_id) && order_position >= 0 && (order_position < ::Vehicle::Get(vehicle_id)->GetNumManualOrders() || order_position == ORDER_CURRENT); } /** * Get the current order the vehicle is executing. If the current order is in * the order list, return the order from the orderlist. If the current order * was a manual order, return the current order. */ static const Order *ResolveOrder(VehicleID vehicle_id, ScriptOrder::OrderPosition order_position) { const Vehicle *v = ::Vehicle::Get(vehicle_id); if (order_position == ScriptOrder::ORDER_CURRENT) { const Order *order = &v->current_order; if (order->GetType() == OT_GOTO_DEPOT && !(order->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return order; order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position); if (order_position == ScriptOrder::ORDER_INVALID) return NULL; } const Order *order = v->GetFirstOrder(); while (order->GetType() == OT_IMPLICIT) order = order->next; while (order_position > 0) { order_position = (ScriptOrder::OrderPosition)(order_position - 1); order = order->next; while (order->GetType() == OT_IMPLICIT) order = order->next; } return order; } /** * Convert an ScriptOrder::OrderPosition (which is the manual order index) to an order index * as expected by the OpenTTD commands. * @param order_position The OrderPosition to convert. * @return An OpenTTD-internal index for the same order. */ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOrder::OrderPosition order_position) { const Vehicle *v = ::Vehicle::Get(vehicle_id); if (order_position == v->GetNumManualOrders()) return v->GetNumOrders(); assert(ScriptOrder::IsValidVehicleOrder(vehicle_id, order_position)); int res = (int)order_position; const Order *order = v->orders.list->GetFirstOrder(); for (; order->GetType() == OT_IMPLICIT; order = order->next) res++; while (order_position > 0) { order_position = (ScriptOrder::OrderPosition)(order_position - 1); order = order->next; for (; order->GetType() == OT_IMPLICIT; order = order->next) res++; } return res; } /* static */ bool ScriptOrder::IsGotoStationOrder(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); return order != NULL && order->GetType() == OT_GOTO_STATION; } /* static */ bool ScriptOrder::IsGotoDepotOrder(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); return order != NULL && order->GetType() == OT_GOTO_DEPOT; } /* static */ bool ScriptOrder::IsGotoWaypointOrder(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); return order != NULL && order->GetType() == OT_GOTO_WAYPOINT; } /* static */ bool ScriptOrder::IsConditionalOrder(VehicleID vehicle_id, OrderPosition order_position) { if (order_position == ORDER_CURRENT) return false; if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::Vehicle::Get(vehicle_id)->GetOrder(ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position)); return order->GetType() == OT_CONDITIONAL; } /* static */ bool ScriptOrder::IsVoidOrder(VehicleID vehicle_id, OrderPosition order_position) { if (order_position == ORDER_CURRENT) return false; if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); return order->GetType() == OT_DUMMY; } /* static */ bool ScriptOrder::IsRefitOrder(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return false; const Order *order = ::ResolveOrder(vehicle_id, order_position); return order != NULL && order->IsRefit(); } /* static */ bool ScriptOrder::IsCurrentOrderPartOfOrderList(VehicleID vehicle_id) { if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return false; if (GetOrderCount(vehicle_id) == 0) return false; const Order *order = &::Vehicle::Get(vehicle_id)->current_order; if (order->GetType() != OT_GOTO_DEPOT) return true; return (order->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0; } /* static */ ScriptOrder::OrderPosition ScriptOrder::ResolveOrderPosition(VehicleID vehicle_id, OrderPosition order_position) { if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return ORDER_INVALID; int num_manual_orders = ::Vehicle::Get(vehicle_id)->GetNumManualOrders(); if (num_manual_orders == 0) return ORDER_INVALID; if (order_position == ORDER_CURRENT) { int cur_order_pos = ::Vehicle::Get(vehicle_id)->cur_real_order_index; const Order *order = ::Vehicle::Get(vehicle_id)->GetFirstOrder(); int num_implicit_orders = 0; for (int i = 0; i < cur_order_pos; i++) { if (order->GetType() == OT_IMPLICIT) num_implicit_orders++; order = order->next; } int real_order_pos = cur_order_pos - num_implicit_orders; assert(real_order_pos < num_manual_orders); return (ScriptOrder::OrderPosition)real_order_pos; } return (order_position >= 0 && order_position < num_manual_orders) ? order_position : ORDER_INVALID; } /* static */ bool ScriptOrder::AreOrderFlagsValid(TileIndex destination, ScriptOrderFlags order_flags) { OrderType ot = (order_flags & OF_GOTO_NEAREST_DEPOT) ? OT_GOTO_DEPOT : ::GetOrderTypeByTile(destination); switch (ot) { case OT_GOTO_STATION: return (order_flags & ~(OF_NON_STOP_FLAGS | OF_UNLOAD_FLAGS | OF_LOAD_FLAGS)) == 0 && /* Test the different mutual exclusive flags. */ ((order_flags & OF_TRANSFER) == 0 || (order_flags & OF_UNLOAD) == 0) && ((order_flags & OF_TRANSFER) == 0 || (order_flags & OF_NO_UNLOAD) == 0) && ((order_flags & OF_UNLOAD) == 0 || (order_flags & OF_NO_UNLOAD) == 0) && ((order_flags & OF_UNLOAD) == 0 || (order_flags & OF_NO_UNLOAD) == 0) && ((order_flags & OF_NO_UNLOAD) == 0 || (order_flags & OF_NO_LOAD) == 0) && ((order_flags & OF_FULL_LOAD_ANY) == 0 || (order_flags & OF_NO_LOAD) == 0); case OT_GOTO_DEPOT: return (order_flags & ~(OF_NON_STOP_FLAGS | OF_DEPOT_FLAGS)) == 0 && ((order_flags & OF_SERVICE_IF_NEEDED) == 0 || (order_flags & OF_STOP_IN_DEPOT) == 0); case OT_GOTO_WAYPOINT: return (order_flags & ~(OF_NON_STOP_FLAGS)) == 0; default: return false; } } /* static */ bool ScriptOrder::IsValidConditionalOrder(OrderCondition condition, CompareFunction compare) { switch (condition) { case OC_LOAD_PERCENTAGE: case OC_RELIABILITY: case OC_MAX_SPEED: case OC_AGE: case OC_REMAINING_LIFETIME: return compare >= CF_EQUALS && compare <= CF_MORE_EQUALS; case OC_REQUIRES_SERVICE: return compare == CF_IS_TRUE || compare == CF_IS_FALSE; case OC_UNCONDITIONALLY: return true; default: return false; } } /* static */ int32 ScriptOrder::GetOrderCount(VehicleID vehicle_id) { return ScriptVehicle::IsValidVehicle(vehicle_id) ? ::Vehicle::Get(vehicle_id)->GetNumManualOrders() : -1; } /* static */ TileIndex ScriptOrder::GetOrderDestination(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return INVALID_TILE; const Order *order = ::ResolveOrder(vehicle_id, order_position); if (order == NULL || order->GetType() == OT_CONDITIONAL) return INVALID_TILE; const Vehicle *v = ::Vehicle::Get(vehicle_id); switch (order->GetType()) { case OT_GOTO_DEPOT: { /* We don't know where the nearest depot is... (yet) */ if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) return INVALID_TILE; if (v->type != VEH_AIRCRAFT) return ::Depot::Get(order->GetDestination())->xy; /* Aircraft's hangars are referenced by StationID, not DepotID */ const Station *st = ::Station::Get(order->GetDestination()); if (!st->airport.HasHangar()) return INVALID_TILE; return st->airport.GetHangarTile(0); } case OT_GOTO_STATION: { const Station *st = ::Station::Get(order->GetDestination()); if (st->train_station.tile != INVALID_TILE) { TILE_AREA_LOOP(t, st->train_station) { if (st->TileBelongsToRailStation(t)) return t; } } else if (st->dock_tile != INVALID_TILE) { return st->dock_tile; } else if (st->bus_stops != NULL) { return st->bus_stops->xy; } else if (st->truck_stops != NULL) { return st->truck_stops->xy; } else if (st->airport.tile != INVALID_TILE) { TILE_AREA_LOOP(tile, st->airport) { if (st->TileBelongsToAirport(tile) && !::IsHangar(tile)) return tile; } } return INVALID_TILE; } case OT_GOTO_WAYPOINT: { const Waypoint *wp = ::Waypoint::Get(order->GetDestination()); if (wp->train_station.tile != INVALID_TILE) { TILE_AREA_LOOP(t, wp->train_station) { if (wp->TileBelongsToRailStation(t)) return t; } } /* If the waypoint has no rail waypoint tiles, it must have a buoy */ return wp->xy; } default: return INVALID_TILE; } } /* static */ ScriptOrder::ScriptOrderFlags ScriptOrder::GetOrderFlags(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return OF_INVALID; const Order *order = ::ResolveOrder(vehicle_id, order_position); if (order == NULL || order->GetType() == OT_CONDITIONAL || order->GetType() == OT_DUMMY) return OF_INVALID; ScriptOrderFlags order_flags = OF_NONE; order_flags |= (ScriptOrderFlags)order->GetNonStopType(); switch (order->GetType()) { case OT_GOTO_DEPOT: if (order->GetDepotOrderType() & ODTFB_SERVICE) order_flags |= OF_SERVICE_IF_NEEDED; if (order->GetDepotActionType() & ODATFB_HALT) order_flags |= OF_STOP_IN_DEPOT; if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) order_flags |= OF_GOTO_NEAREST_DEPOT; break; case OT_GOTO_STATION: order_flags |= (ScriptOrderFlags)(order->GetLoadType() << 5); order_flags |= (ScriptOrderFlags)(order->GetUnloadType() << 2); break; default: break; } return order_flags; } /* static */ ScriptOrder::OrderPosition ScriptOrder::GetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return ORDER_INVALID; if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return ORDER_INVALID; const Order *order = ::ResolveOrder(vehicle_id, order_position); return (OrderPosition)order->GetConditionSkipToOrder(); } /* static */ ScriptOrder::OrderCondition ScriptOrder::GetOrderCondition(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return OC_INVALID; if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return OC_INVALID; const Order *order = ::ResolveOrder(vehicle_id, order_position); return (OrderCondition)order->GetConditionVariable(); } /* static */ ScriptOrder::CompareFunction ScriptOrder::GetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return CF_INVALID; if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return CF_INVALID; const Order *order = ::ResolveOrder(vehicle_id, order_position); return (CompareFunction)order->GetConditionComparator(); } /* static */ int32 ScriptOrder::GetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return -1; if (order_position == ORDER_CURRENT || !IsConditionalOrder(vehicle_id, order_position)) return -1; const Order *order = ::ResolveOrder(vehicle_id, order_position); int32 value = order->GetConditionValue(); if (order->GetConditionVariable() == OCV_MAX_SPEED) value = value * 16 / 10; return value; } /* static */ ScriptOrder::StopLocation ScriptOrder::GetStopLocation(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return STOPLOCATION_INVALID; if (ScriptVehicle::GetVehicleType(vehicle_id) != ScriptVehicle::VT_RAIL) return STOPLOCATION_INVALID; if (!IsGotoStationOrder(vehicle_id, order_position)) return STOPLOCATION_INVALID; const Order *order = ::ResolveOrder(vehicle_id, order_position); return (ScriptOrder::StopLocation)order->GetStopLocation(); } /* static */ CargoID ScriptOrder::GetOrderRefit(VehicleID vehicle_id, OrderPosition order_position) { if (!IsValidVehicleOrder(vehicle_id, order_position)) return CT_NO_REFIT; if (order_position != ORDER_CURRENT && !IsGotoStationOrder(vehicle_id, order_position) && !IsGotoDepotOrder(vehicle_id, order_position)) return CT_NO_REFIT; const Order *order = ::ResolveOrder(vehicle_id, order_position); return order->IsRefit() ? order->GetRefitCargo() : (CargoID)CT_NO_REFIT; } /* static */ bool ScriptOrder::SetOrderJumpTo(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to) { EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position)); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT); return ScriptObject::DoCommand(0, vehicle_id | (order_position << 20), MOF_COND_DESTINATION | (jump_to << 4), CMD_MODIFY_ORDER); } /* static */ bool ScriptOrder::SetOrderCondition(VehicleID vehicle_id, OrderPosition order_position, OrderCondition condition) { EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position)); EnforcePrecondition(false, condition >= OC_LOAD_PERCENTAGE && condition <= OC_REMAINING_LIFETIME); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_VARIABLE | (condition << 4), CMD_MODIFY_ORDER); } /* static */ bool ScriptOrder::SetOrderCompareFunction(VehicleID vehicle_id, OrderPosition order_position, CompareFunction compare) { EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position)); EnforcePrecondition(false, compare >= CF_EQUALS && compare <= CF_IS_FALSE); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_COMPARATOR | (compare << 4), CMD_MODIFY_ORDER); } /* static */ bool ScriptOrder::SetOrderCompareValue(VehicleID vehicle_id, OrderPosition order_position, int32 value) { EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); EnforcePrecondition(false, order_position != ORDER_CURRENT && IsConditionalOrder(vehicle_id, order_position)); EnforcePrecondition(false, value >= 0 && value < 2048); if (GetOrderCondition(vehicle_id, order_position) == OC_MAX_SPEED) value = value * 10 / 16; int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), MOF_COND_VALUE | (value << 4), CMD_MODIFY_ORDER); } /* static */ bool ScriptOrder::SetStopLocation(VehicleID vehicle_id, OrderPosition order_position, StopLocation stop_location) { EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); EnforcePrecondition(false, ScriptVehicle::GetVehicleType(vehicle_id) == ScriptVehicle::VT_RAIL); EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position)); EnforcePrecondition(false, stop_location >= STOPLOCATION_NEAR && stop_location <= STOPLOCATION_FAR); order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); uint32 p1 = vehicle_id | (order_pos << 20); uint32 p2 = MOF_STOP_LOCATION | (stop_location << 4); return ScriptObject::DoCommand(0, p1, p2, CMD_MODIFY_ORDER); } /* static */ bool ScriptOrder::SetOrderRefit(VehicleID vehicle_id, OrderPosition order_position, CargoID refit_cargo) { EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); EnforcePrecondition(false, IsGotoStationOrder(vehicle_id, order_position) || (IsGotoDepotOrder(vehicle_id, order_position) && refit_cargo != CT_AUTO_REFIT)); EnforcePrecondition(false, ScriptCargo::IsValidCargo(refit_cargo) || refit_cargo == CT_AUTO_REFIT || refit_cargo == CT_NO_REFIT); uint32 p1 = vehicle_id; uint32 p2 = refit_cargo | ScriptOrderPositionToRealOrderPosition(vehicle_id, ScriptOrder::ResolveOrderPosition(vehicle_id, order_position)) << 16; return ScriptObject::DoCommand(0, p1, p2, CMD_ORDER_REFIT); } /* static */ bool ScriptOrder::AppendOrder(VehicleID vehicle_id, TileIndex destination, ScriptOrderFlags order_flags) { EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags)); return InsertOrder(vehicle_id, (ScriptOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), destination, order_flags); } /* static */ bool ScriptOrder::AppendConditionalOrder(VehicleID vehicle_id, OrderPosition jump_to) { EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to)); return InsertConditionalOrder(vehicle_id, (ScriptOrder::OrderPosition)::Vehicle::Get(vehicle_id)->GetNumManualOrders(), jump_to); } /* static */ bool ScriptOrder::InsertOrder(VehicleID vehicle_id, OrderPosition order_position, TileIndex destination, ScriptOrder::ScriptOrderFlags order_flags) { /* IsValidVehicleOrder is not good enough because it does not allow appending. */ if (order_position == ORDER_CURRENT) order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position); EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders()); EnforcePrecondition(false, AreOrderFlagsValid(destination, order_flags)); Order order; OrderType ot = (order_flags & OF_GOTO_NEAREST_DEPOT) ? OT_GOTO_DEPOT : ::GetOrderTypeByTile(destination); switch (ot) { case OT_GOTO_DEPOT: { OrderDepotTypeFlags odtf = (OrderDepotTypeFlags)(ODTFB_PART_OF_ORDERS | ((order_flags & OF_SERVICE_IF_NEEDED) ? ODTFB_SERVICE : 0)); OrderDepotActionFlags odaf = (OrderDepotActionFlags)(ODATF_SERVICE_ONLY | ((order_flags & OF_STOP_IN_DEPOT) ? ODATFB_HALT : 0)); if (order_flags & OF_GOTO_NEAREST_DEPOT) odaf |= ODATFB_NEAREST_DEPOT; OrderNonStopFlags onsf = (OrderNonStopFlags)((order_flags & OF_NON_STOP_INTERMEDIATE) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); if (order_flags & OF_GOTO_NEAREST_DEPOT) { order.MakeGoToDepot(0, odtf, onsf, odaf); } else { /* Check explicitly if the order is to a station (for aircraft) or * to a depot (other vehicle types). */ if (::Vehicle::Get(vehicle_id)->type == VEH_AIRCRAFT) { if (!::IsTileType(destination, MP_STATION)) return false; order.MakeGoToDepot(::GetStationIndex(destination), odtf, onsf, odaf); } else { if (::IsTileType(destination, MP_STATION)) return false; order.MakeGoToDepot(::GetDepotIndex(destination), odtf, onsf, odaf); } } break; } case OT_GOTO_STATION: order.MakeGoToStation(::GetStationIndex(destination)); order.SetLoadType((OrderLoadFlags)GB(order_flags, 5, 3)); order.SetUnloadType((OrderUnloadFlags)GB(order_flags, 2, 3)); order.SetStopLocation(OSL_PLATFORM_FAR_END); break; case OT_GOTO_WAYPOINT: order.MakeGoToWaypoint(::GetStationIndex(destination)); break; default: return false; } order.SetNonStopType((OrderNonStopFlags)GB(order_flags, 0, 2)); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), order.Pack(), CMD_INSERT_ORDER); } /* static */ bool ScriptOrder::InsertConditionalOrder(VehicleID vehicle_id, OrderPosition order_position, OrderPosition jump_to) { /* IsValidVehicleOrder is not good enough because it does not allow appending. */ if (order_position == ORDER_CURRENT) order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position); EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); EnforcePrecondition(false, order_position >= 0 && order_position <= ::Vehicle::Get(vehicle_id)->GetNumManualOrders()); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, jump_to) && jump_to != ORDER_CURRENT); Order order; order.MakeConditional(jump_to); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), order.Pack(), CMD_INSERT_ORDER); } /* static */ bool ScriptOrder::RemoveOrder(VehicleID vehicle_id, OrderPosition order_position) { order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); return ScriptObject::DoCommand(0, vehicle_id, order_pos, CMD_DELETE_ORDER); } /* static */ bool ScriptOrder::SkipToOrder(VehicleID vehicle_id, OrderPosition next_order) { next_order = ScriptOrder::ResolveOrderPosition(vehicle_id, next_order); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, next_order)); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, next_order); return ScriptObject::DoCommand(0, vehicle_id, order_pos, CMD_SKIP_TO_ORDER); } /** * Callback handler as SetOrderFlags possibly needs multiple DoCommand calls * to be able to set all order flags correctly. As we need to wait till the * command has completed before we know the next bits to change we need to * call the function multiple times. Each time it'll reduce the difference * between the wanted and the current order. * @param instance The script instance we are doing the callback for. */ static void _DoCommandReturnSetOrderFlags(class ScriptInstance *instance) { ScriptObject::SetLastCommandRes(ScriptOrder::_SetOrderFlags()); ScriptInstance::DoCommandReturn(instance); } /* static */ bool ScriptOrder::_SetOrderFlags() { /* Make sure we don't go into an infinite loop */ int retry = ScriptObject::GetCallbackVariable(3) - 1; if (retry < 0) { DEBUG(script, 0, "Possible infinite loop in SetOrderFlags() detected"); return false; } ScriptObject::SetCallbackVariable(3, retry); VehicleID vehicle_id = (VehicleID)ScriptObject::GetCallbackVariable(0); OrderPosition order_position = (OrderPosition)ScriptObject::GetCallbackVariable(1); ScriptOrderFlags order_flags = (ScriptOrderFlags)ScriptObject::GetCallbackVariable(2); order_position = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position)); EnforcePrecondition(false, AreOrderFlagsValid(GetOrderDestination(vehicle_id, order_position), order_flags)); const Order *order = ::ResolveOrder(vehicle_id, order_position); int order_pos = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position); ScriptOrderFlags current = GetOrderFlags(vehicle_id, order_position); EnforcePrecondition(false, (order_flags & OF_GOTO_NEAREST_DEPOT) == (current & OF_GOTO_NEAREST_DEPOT)); if ((current & OF_NON_STOP_FLAGS) != (order_flags & OF_NON_STOP_FLAGS)) { return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_NON_STOP_FLAGS) << 4 | MOF_NON_STOP, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); } switch (order->GetType()) { case OT_GOTO_DEPOT: if ((current & OF_DEPOT_FLAGS) != (order_flags & OF_DEPOT_FLAGS)) { uint data = DA_ALWAYS_GO; if (order_flags & OF_SERVICE_IF_NEEDED) data = DA_SERVICE; if (order_flags & OF_STOP_IN_DEPOT) data = DA_STOP; return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (data << 4) | MOF_DEPOT_ACTION, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); } break; case OT_GOTO_STATION: if ((current & OF_UNLOAD_FLAGS) != (order_flags & OF_UNLOAD_FLAGS)) { return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_UNLOAD_FLAGS) << 2 | MOF_UNLOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); } if ((current & OF_LOAD_FLAGS) != (order_flags & OF_LOAD_FLAGS)) { return ScriptObject::DoCommand(0, vehicle_id | (order_pos << 20), (order_flags & OF_LOAD_FLAGS) >> 1 | MOF_LOAD, CMD_MODIFY_ORDER, NULL, &::_DoCommandReturnSetOrderFlags); } break; default: break; } assert(GetOrderFlags(vehicle_id, order_position) == order_flags); return true; } /* static */ bool ScriptOrder::SetOrderFlags(VehicleID vehicle_id, OrderPosition order_position, ScriptOrder::ScriptOrderFlags order_flags) { ScriptObject::SetCallbackVariable(0, vehicle_id); ScriptObject::SetCallbackVariable(1, order_position); ScriptObject::SetCallbackVariable(2, order_flags); /* In case another client(s) change orders at the same time we could * end in an infinite loop. This stops that from happening ever. */ ScriptObject::SetCallbackVariable(3, 8); return ScriptOrder::_SetOrderFlags(); } /* static */ bool ScriptOrder::MoveOrder(VehicleID vehicle_id, OrderPosition order_position_move, OrderPosition order_position_target) { order_position_move = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position_move); order_position_target = ScriptOrder::ResolveOrderPosition(vehicle_id, order_position_target); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_move)); EnforcePrecondition(false, IsValidVehicleOrder(vehicle_id, order_position_target)); EnforcePrecondition(false, order_position_move != order_position_target); int order_pos_move = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position_move); int order_pos_target = ScriptOrderPositionToRealOrderPosition(vehicle_id, order_position_target); return ScriptObject::DoCommand(0, vehicle_id, order_pos_move | (order_pos_target << 16), CMD_MOVE_ORDER); } /* static */ bool ScriptOrder::CopyOrders(VehicleID vehicle_id, VehicleID main_vehicle_id) { EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(main_vehicle_id)); return ScriptObject::DoCommand(0, vehicle_id | CO_COPY << 30, main_vehicle_id, CMD_CLONE_ORDER); } /* static */ bool ScriptOrder::ShareOrders(VehicleID vehicle_id, VehicleID main_vehicle_id) { EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(main_vehicle_id)); return ScriptObject::DoCommand(0, vehicle_id | CO_SHARE << 30, main_vehicle_id, CMD_CLONE_ORDER); } /* static */ bool ScriptOrder::UnshareOrders(VehicleID vehicle_id) { EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id)); return ScriptObject::DoCommand(0, vehicle_id | CO_UNSHARE << 30, 0, CMD_CLONE_ORDER); } /* static */ uint ScriptOrder::GetOrderDistance(ScriptVehicle::VehicleType vehicle_type, TileIndex origin_tile, TileIndex dest_tile) { if (vehicle_type == ScriptVehicle::VT_AIR) { if (ScriptTile::IsStationTile(origin_tile) && ::Station::GetByTile(origin_tile)->airport.tile != INVALID_TILE) origin_tile = ::Station::GetByTile(origin_tile)->airport.tile; if (ScriptTile::IsStationTile(dest_tile) && ::Station::GetByTile(dest_tile)->airport.tile != INVALID_TILE) dest_tile = ::Station::GetByTile(dest_tile)->airport.tile; return ScriptMap::DistanceSquare(origin_tile, dest_tile); } else { return ScriptMap::DistanceManhattan(origin_tile, dest_tile); } } openttd-1.5.3/src/script/api/script_station.cpp0000644000000000000000000002162412627373434020330 0ustar rootroot/* $Id: script_station.cpp 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 script_station.cpp Implementation of ScriptStation. */ #include "../../stdafx.h" #include "script_station.hpp" #include "script_map.hpp" #include "script_town.hpp" #include "script_cargo.hpp" #include "../../station_base.h" #include "../../roadstop_base.h" #include "../../town.h" #include "../../safeguards.h" /* static */ bool ScriptStation::IsValidStation(StationID station_id) { const Station *st = ::Station::GetIfValid(station_id); return st != NULL && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE); } /* static */ ScriptCompany::CompanyID ScriptStation::GetOwner(StationID station_id) { if (!IsValidStation(station_id)) return ScriptCompany::COMPANY_INVALID; return static_cast((int)::Station::Get(station_id)->owner); } /* static */ StationID ScriptStation::GetStationID(TileIndex tile) { if (!::IsValidTile(tile) || !::IsTileType(tile, MP_STATION)) return INVALID_STATION; return ::GetStationIndex(tile); } template /* static */ bool ScriptStation::IsCargoRequestValid(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id) { if (!IsValidStation(station_id)) return false; if (Tfrom && !IsValidStation(from_station_id) && from_station_id != STATION_INVALID) return false; if (Tvia && !IsValidStation(via_station_id) && via_station_id != STATION_INVALID) return false; if (!ScriptCargo::IsValidCargo(cargo_id)) return false; return true; } template /* static */ int32 ScriptStation::CountCargoWaiting(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id) { if (!ScriptStation::IsCargoRequestValid(station_id, from_station_id, via_station_id, cargo_id)) { return -1; } const StationCargoList &cargo_list = ::Station::Get(station_id)->goods[cargo_id].cargo; if (!Tfrom && !Tvia) return cargo_list.TotalCount(); uint16 cargo_count = 0; std::pair range = Tvia ? cargo_list.Packets()->equal_range(via_station_id) : std::make_pair(StationCargoList::ConstIterator(cargo_list.Packets()->begin()), StationCargoList::ConstIterator(cargo_list.Packets()->end())); for (StationCargoList::ConstIterator it = range.first; it != range.second; it++) { const CargoPacket *cp = *it; if (!Tfrom || cp->SourceStation() == from_station_id) cargo_count += cp->Count(); } return cargo_count; } /* static */ int32 ScriptStation::GetCargoWaiting(StationID station_id, CargoID cargo_id) { return CountCargoWaiting(station_id, STATION_INVALID, STATION_INVALID, cargo_id); } /* static */ int32 ScriptStation::GetCargoWaitingFrom(StationID station_id, StationID from_station_id, CargoID cargo_id) { return CountCargoWaiting(station_id, from_station_id, STATION_INVALID, cargo_id); } /* static */ int32 ScriptStation::GetCargoWaitingVia(StationID station_id, StationID via_station_id, CargoID cargo_id) { return CountCargoWaiting(station_id, STATION_INVALID, via_station_id, cargo_id); } /* static */ int32 ScriptStation::GetCargoWaitingFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id) { return CountCargoWaiting(station_id, from_station_id, via_station_id, cargo_id); } template /* static */ int32 ScriptStation::CountCargoPlanned(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id) { if (!ScriptStation::IsCargoRequestValid(station_id, from_station_id, via_station_id, cargo_id)) { return -1; } const FlowStatMap &flows = ::Station::Get(station_id)->goods[cargo_id].flows; if (Tfrom) { return Tvia ? flows.GetFlowFromVia(from_station_id, via_station_id) : flows.GetFlowFrom(from_station_id); } else { return Tvia ? flows.GetFlowVia(via_station_id) : flows.GetFlow(); } } /* static */ int32 ScriptStation::GetCargoPlanned(StationID station_id, CargoID cargo_id) { return CountCargoPlanned(station_id, STATION_INVALID, STATION_INVALID, cargo_id); } /* static */ int32 ScriptStation::GetCargoPlannedFrom(StationID station_id, StationID from_station_id, CargoID cargo_id) { return CountCargoPlanned(station_id, from_station_id, STATION_INVALID, cargo_id); } /* static */ int32 ScriptStation::GetCargoPlannedVia(StationID station_id, StationID via_station_id, CargoID cargo_id) { return CountCargoPlanned(station_id, STATION_INVALID, via_station_id, cargo_id); } /* static */ int32 ScriptStation::GetCargoPlannedFromVia(StationID station_id, StationID from_station_id, StationID via_station_id, CargoID cargo_id) { return CountCargoPlanned(station_id, from_station_id, via_station_id, cargo_id); } /* static */ bool ScriptStation::HasCargoRating(StationID station_id, CargoID cargo_id) { if (!IsValidStation(station_id)) return false; if (!ScriptCargo::IsValidCargo(cargo_id)) return false; return ::Station::Get(station_id)->goods[cargo_id].HasRating(); } /* static */ int32 ScriptStation::GetCargoRating(StationID station_id, CargoID cargo_id) { if (!ScriptStation::HasCargoRating(station_id, cargo_id)) return -1; return ::ToPercent8(::Station::Get(station_id)->goods[cargo_id].rating); } /* static */ int32 ScriptStation::GetCoverageRadius(ScriptStation::StationType station_type) { if (station_type == STATION_AIRPORT) return -1; if (!HasExactlyOneBit(station_type)) return -1; if (!_settings_game.station.modified_catchment) return CA_UNMODIFIED; switch (station_type) { case STATION_TRAIN: return CA_TRAIN; case STATION_TRUCK_STOP: return CA_TRUCK; case STATION_BUS_STOP: return CA_BUS; case STATION_DOCK: return CA_DOCK; default: return CA_NONE; } } /* static */ int32 ScriptStation::GetStationCoverageRadius(StationID station_id) { if (!IsValidStation(station_id)) return -1; return Station::Get(station_id)->GetCatchmentRadius(); } /* static */ int32 ScriptStation::GetDistanceManhattanToTile(StationID station_id, TileIndex tile) { if (!IsValidStation(station_id)) return -1; return ScriptMap::DistanceManhattan(tile, GetLocation(station_id)); } /* static */ int32 ScriptStation::GetDistanceSquareToTile(StationID station_id, TileIndex tile) { if (!IsValidStation(station_id)) return -1; return ScriptMap::DistanceSquare(tile, GetLocation(station_id)); } /* static */ bool ScriptStation::IsWithinTownInfluence(StationID station_id, TownID town_id) { if (!IsValidStation(station_id)) return false; return ScriptTown::IsWithinTownInfluence(town_id, GetLocation(station_id)); } /* static */ bool ScriptStation::HasStationType(StationID station_id, StationType station_type) { if (!IsValidStation(station_id)) return false; if (!HasExactlyOneBit(station_type)) return false; return (::Station::Get(station_id)->facilities & station_type) != 0; } /* static */ bool ScriptStation::HasRoadType(StationID station_id, ScriptRoad::RoadType road_type) { if (!IsValidStation(station_id)) return false; if (!ScriptRoad::IsRoadTypeAvailable(road_type)) return false; ::RoadTypes r = RoadTypeToRoadTypes((::RoadType)road_type); for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_BUS); rs != NULL; rs = rs->next) { if ((::GetRoadTypes(rs->xy) & r) != 0) return true; } for (const RoadStop *rs = ::Station::Get(station_id)->GetPrimaryRoadStop(ROADSTOP_TRUCK); rs != NULL; rs = rs->next) { if ((::GetRoadTypes(rs->xy) & r) != 0) return true; } return false; } /* static */ TownID ScriptStation::GetNearestTown(StationID station_id) { if (!IsValidStation(station_id)) return INVALID_TOWN; return ::Station::Get(station_id)->town->index; } /* static */ bool ScriptStation::IsAirportClosed(StationID station_id) { EnforcePrecondition(false, IsValidStation(station_id)); EnforcePrecondition(false, HasStationType(station_id, STATION_AIRPORT)); return (::Station::Get(station_id)->airport.flags & AIRPORT_CLOSED_block) != 0; } /* static */ bool ScriptStation::OpenCloseAirport(StationID station_id) { EnforcePrecondition(false, IsValidStation(station_id)); EnforcePrecondition(false, HasStationType(station_id, STATION_AIRPORT)); return ScriptObject::DoCommand(0, station_id, 0, CMD_OPEN_CLOSE_AIRPORT); } openttd-1.5.3/src/script/api/script_enginelist.hpp0000644000000000000000000000222112627373434021005 0ustar rootroot/* $Id: script_enginelist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_enginelist.hpp List all the engines. */ #ifndef SCRIPT_ENGINELIST_HPP #define SCRIPT_ENGINELIST_HPP #include "script_list.hpp" #include "script_vehicle.hpp" /** * Create a list of engines based on a vehicle type. * @api ai game * @ingroup ScriptList */ class ScriptEngineList : public ScriptList { public: /** * @param vehicle_type The type of vehicle to make a list of engines for. */ ScriptEngineList(ScriptVehicle::VehicleType vehicle_type); }; #endif /* SCRIPT_ENGINELIST_HPP */ openttd-1.5.3/src/script/api/script_town.hpp0000644000000000000000000004003012627373434017633 0ustar rootroot/* $Id: script_town.hpp 26915 2014-09-24 16:45:20Z frosch $ */ /* * 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 script_town.hpp Everything to query towns. */ #ifndef SCRIPT_TOWN_HPP #define SCRIPT_TOWN_HPP #include "script_cargo.hpp" #include "script_company.hpp" #include "../../town_type.h" /** * Class that handles all town related functions. * @api ai game */ class ScriptTown : public ScriptObject { public: /** * Actions that one can perform on a town. */ enum TownAction { /* Note: these values represent part of the in-game order of the _town_action_proc array */ /** * The cargo ratings temporary gains 25% of rating (in * absolute percentage, so 10% becomes 35%, with a max of 99%) * for all stations within 10 tiles. */ TOWN_ACTION_ADVERTISE_SMALL = 0, /** * The cargo ratings temporary gains 44% of rating (in * absolute percentage, so 10% becomes 54%, with a max of 99%) * for all stations within 15 tiles. */ TOWN_ACTION_ADVERTISE_MEDIUM = 1, /** * The cargo ratings temporary gains 63% of rating (in * absolute percentage, so 10% becomes 73%, with a max of 99%) * for all stations within 20 tiles. */ TOWN_ACTION_ADVERTISE_LARGE = 2, /** * Rebuild the roads of this town for 6 months. */ TOWN_ACTION_ROAD_REBUILD = 3, /** * Build a statue in this town. */ TOWN_ACTION_BUILD_STATUE = 4, /** * Fund the creation of extra buildings for 3 months. */ TOWN_ACTION_FUND_BUILDINGS = 5, /** * Buy exclusive rights for this town for 12 months. */ TOWN_ACTION_BUY_RIGHTS = 6, /** * Bribe the town in order to get a higher rating. */ TOWN_ACTION_BRIBE = 7, }; /** * Different ratings one could have in a town. */ enum TownRating { TOWN_RATING_NONE, ///< The company got no rating in the town. TOWN_RATING_APPALLING, ///< The company got an appalling rating in the town . TOWN_RATING_VERY_POOR, ///< The company got an very poor rating in the town. TOWN_RATING_POOR, ///< The company got an poor rating in the town. TOWN_RATING_MEDIOCRE, ///< The company got an mediocre rating in the town. TOWN_RATING_GOOD, ///< The company got an good rating in the town. TOWN_RATING_VERY_GOOD, ///< The company got an very good rating in the town. TOWN_RATING_EXCELLENT, ///< The company got an excellent rating in the town. TOWN_RATING_OUTSTANDING, ///< The company got an outstanding rating in the town. TOWN_RATING_INVALID = -1, ///< The town rating for invalid towns/companies. }; /** * Possible layouts for the roads in a town. */ enum RoadLayout { /* Note: these values represent part of the in-game TownLayout enum */ ROAD_LAYOUT_ORIGINAL = ::TL_ORIGINAL, ///< Original algorithm (min. 1 distance between roads). ROAD_LAYOUT_BETTER_ROADS = ::TL_BETTER_ROADS, ///< Extended original algorithm (min. 2 distance between roads). ROAD_LAYOUT_2x2 = ::TL_2X2_GRID, ///< Geometric 2x2 grid algorithm ROAD_LAYOUT_3x3 = ::TL_3X3_GRID, ///< Geometric 3x3 grid algorithm /* Custom added value, only valid for this API */ ROAD_LAYOUT_INVALID = -1, ///< The layout for invalid towns. }; /** * Possible town construction sizes. */ enum TownSize { TOWN_SIZE_SMALL = ::TSZ_SMALL, ///< Small town. TOWN_SIZE_MEDIUM = ::TSZ_MEDIUM, ///< Medium town. TOWN_SIZE_LARGE = ::TSZ_LARGE, ///< Large town. TOWN_SIZE_INVALID = -1, ///< Invalid town size. }; /** * Special values for SetGrowthRate. */ enum TownGrowth { TOWN_GROWTH_NONE = 0xFFFF, ///< Town does not grow at all. TOWN_GROWTH_NORMAL = 0x10000, ///< Use default town growth algorithm instead of custom growth rate. }; /** * Gets the number of towns. * @return The number of towns. */ static int32 GetTownCount(); /** * Checks whether the given town index is valid. * @param town_id The index to check. * @return True if and only if the town is valid. */ static bool IsValidTown(TownID town_id); /** * Get the name of the town. * @param town_id The town to get the name of. * @pre IsValidTown(town_id). * @return The name of the town. */ static char *GetName(TownID town_id); /** * Rename a town. * @param town_id The town to rename * @param name The new name of the town. If NULL or an empty string is passed, the town name will be reset to the default name. * @pre IsValidTown(town_id). * @return True if the action succeeded. * @api -ai */ static bool SetName(TownID town_id, Text *name); /** * Set the custom text of a town, shown in the GUI. * @param town_id The town to set the custom text of. * @param text The text to set it to (can be either a raw string, or a ScriptText object). * @pre IsValidTown(town_id). * @return True if the action succeeded. * @api -ai */ static bool SetText(TownID town_id, Text *text); /** * Gets the number of inhabitants in the town. * @param town_id The town to get the population of. * @pre IsValidTown(town_id). * @return The number of inhabitants. */ static int32 GetPopulation(TownID town_id); /** * Gets the number of houses in the town. * @param town_id The town to get the number of houses of. * @pre IsValidTown(town_id). * @return The number of houses. */ static int32 GetHouseCount(TownID town_id); /** * Gets the location of the town. * @param town_id The town to get the location of. * @pre IsValidTown(town_id). * @return The location of the town. */ static TileIndex GetLocation(TownID town_id); /** * Get the total last month's production of the given cargo at a town. * @param town_id The index of the town. * @param cargo_id The index of the cargo. * @pre IsValidTown(town_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return The last month's production of the given cargo for this town. */ static int32 GetLastMonthProduction(TownID town_id, CargoID cargo_id); /** * Get the total amount of cargo supplied from a town last month. * @param town_id The index of the town. * @param cargo_id The index of the cargo. * @pre IsValidTown(town_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return The amount of cargo supplied for transport from this town last month. */ static int32 GetLastMonthSupplied(TownID town_id, CargoID cargo_id); /** * Get the percentage of transported production of the given cargo at a town. * @param town_id The index of the town. * @param cargo_id The index of the cargo. * @pre IsValidTown(town_id). * @pre ScriptCargo::IsValidCargo(cargo_id). * @return The percentage of given cargo transported from this town last month. */ static int32 GetLastMonthTransportedPercentage(TownID town_id, CargoID cargo_id); /** * Get the total amount of cargo effects received by a town last month. * @param town_id The index of the town. * @param towneffect_id The index of the cargo. * @pre IsValidTown(town_id). * @pre ScriptCargo::IsValidTownEffect(cargo_id). * @return The amount of cargo received by this town last month for this cargo effect. */ static int32 GetLastMonthReceived(TownID town_id, ScriptCargo::TownEffect towneffect_id); /** * Set the goal of a cargo for this town. * @param town_id The index of the town. * @param towneffect_id The index of the towneffect. * @param goal The new goal. * @pre IsValidTown(town_id). * @pre ScriptCargo::IsValidTownEffect(towneffect_id). * @return True if the action succeeded. * @api -ai */ static bool SetCargoGoal(TownID town_id, ScriptCargo::TownEffect towneffect_id, uint32 goal); /** * Get the amount of cargo that needs to be delivered (per TownEffect) for a * town to grow. All goals need to be reached before a town will grow. * @param town_id The index of the town. * @param towneffect_id The index of the towneffect. * @pre IsValidTown(town_id). * @pre ScriptCargo::IsValidTownEffect(towneffect_id). * @return The goal of the cargo. * @note Goals can change over time. For example with a changing snowline, or * with a growing town. */ static uint32 GetCargoGoal(TownID town_id, ScriptCargo::TownEffect towneffect_id); /** * Set the amount of days between town growth. * @param town_id The index of the town. * @param days_between_town_growth The amount of days between town growth, TOWN_GROWTH_NONE or TOWN_GROWTH_NORMAL. * @pre IsValidTown(town_id). * @pre days_between_town_growth <= 30000 || days_between_town_growth == TOWN_GROWTH_NONE || days_between_town_growth == TOWN_GROWTH_NORMAL. * @return True if the action succeeded. * @note Even when setting a growth rate, towns only grow when the conditions for growth (SetCargoCoal) are met, * and the game settings (economy.town_growth_rate) allow town growth at all. * @note When changing the growth rate, the relative progress is preserved and scaled to the new rate. * @api -ai */ static bool SetGrowthRate(TownID town_id, uint32 days_between_town_growth); /** * Get the amount of days between town growth. * @param town_id The index of the town. * @pre IsValidTown(town_id). * @return Amount of days between town growth, or TOWN_GROWTH_NONE. * @note This function does not indicate when it will grow next. It only tells you the time between growths. */ static int32 GetGrowthRate(TownID town_id); /** * Get the manhattan distance from the tile to the ScriptTown::GetLocation() * of the town. * @param town_id The town to get the distance to. * @param tile The tile to get the distance to. * @pre IsValidTown(town_id). * @return The distance between town and tile. */ static int32 GetDistanceManhattanToTile(TownID town_id, TileIndex tile); /** * Get the square distance from the tile to the ScriptTown::GetLocation() * of the town. * @param town_id The town to get the distance to. * @param tile The tile to get the distance to. * @pre IsValidTown(town_id). * @return The distance between town and tile. */ static int32 GetDistanceSquareToTile(TownID town_id, TileIndex tile); /** * Find out if this tile is within the rating influence of a town. * If a station sign would be on this tile, the servicing quality of the station would * influence the rating of the town. * @param town_id The town to check. * @param tile The tile to check. * @pre IsValidTown(town_id). * @return True if the tile is within the rating influence of the town. */ static bool IsWithinTownInfluence(TownID town_id, TileIndex tile); /** * Find out if this town has a statue for the current company. * @param town_id The town to check. * @pre IsValidTown(town_id). * @game @pre Valid ScriptCompanyMode active in scope. * @return True if the town has a statue. */ static bool HasStatue(TownID town_id); /** * Find out if the town is a city. * @param town_id The town to check. * @pre IsValidTown(town_id). * @return True if the town is a city. */ static bool IsCity(TownID town_id); /** * Find out how long the town is undergoing road reconstructions. * @param town_id The town to check. * @pre IsValidTown(town_id). * @return The number of months the road reworks are still going to take. * The value 0 means that there are currently no road reworks. */ static int GetRoadReworkDuration(TownID town_id); /** * Find out how long new buildings are still being funded in a town. * @param town_id The town to check. * @pre IsValidTown(town_id). * @return The number of months building construction is still funded. * The value 0 means that there is currently no funding. */ static int GetFundBuildingsDuration(TownID town_id); /** * Find out which company currently has the exclusive rights of this town. * @param town_id The town to check. * @pre IsValidTown(town_id). * @game @pre Valid ScriptCompanyMode active in scope. * @return The company that has the exclusive rights. The value * ScriptCompany::COMPANY_INVALID means that there are currently no * exclusive rights given out to anyone. */ static ScriptCompany::CompanyID GetExclusiveRightsCompany(TownID town_id); /** * Find out how long the town is under influence of the exclusive rights. * @param town_id The town to check. * @pre IsValidTown(town_id). * @return The number of months the exclusive rights hold. * The value 0 means that there are currently no exclusive rights * given out to anyone. */ static int32 GetExclusiveRightsDuration(TownID town_id); /** * Find out if an action can currently be performed on the town. * @param town_id The town to perform the action on. * @param town_action The action to perform on the town. * @pre IsValidTown(town_id). * @game @pre Valid ScriptCompanyMode active in scope. * @return True if and only if the action can performed. */ static bool IsActionAvailable(TownID town_id, TownAction town_action); /** * Perform a town action on this town. * @param town_id The town to perform the action on. * @param town_action The action to perform on the town. * @pre IsValidTown(town_id). * @pre IsActionAvailable(town_id, town_action). * @game @pre Valid ScriptCompanyMode active in scope. * @return True if the action succeeded. */ static bool PerformTownAction(TownID town_id, TownAction town_action); /** * Expand the town. * @param town_id The town to expand. * @param houses The amount of houses to grow the town with. * @pre IsValidTown(town_id). * @pre houses > 0. * @return True if the action succeeded. * @api -ai */ static bool ExpandTown(TownID town_id, int houses); /** * Found a new town. * @param tile The location of the new town. * @param size The town size of the new town. * @param city True if the new town should be a city. * @param layout The town layout of the new town. * @param name The name of the new town. Pass NULL to use a random town name. * @game @pre no company mode in scope || ScriptSettings.GetValue("economy.found_town") != 0. * @ai @pre ScriptSettings.GetValue("economy.found_town") != 0. * @game @pre no company mode in scope || size != TOWN_SIZE_LARGE. * @ai @pre size != TOWN_SIZE_LARGE. * @pre size != TOWN_SIZE_INVALID. * @pre layout != ROAD_LAYOUT_INVALID. * @return True if the action succeeded. * @game @note Companies are restricted by the advanced setting that controls if funding towns is allowed or not. If custom road layout is forbidden and there is a company mode in scope, the layout parameter will be ignored. * @ai @note AIs are restricted by the advanced setting that controls if funding towns is allowed or not. If custom road layout is forbidden, the layout parameter will be ignored. */ static bool FoundTown(TileIndex tile, TownSize size, bool city, RoadLayout layout, Text *name); /** * Get the rating of a company within a town. * @param town_id The town to get the rating for. * @param company_id The company to get the rating for. * @pre IsValidTown(town_id). * @pre ScriptCompany.ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID. * @return The rating as shown to humans. */ static TownRating GetRating(TownID town_id, ScriptCompany::CompanyID company_id); /** * Get the maximum level of noise that still can be added by airports * before the town start to refuse building a new airport. * @param town_id The town to get the allowed noise from. * @return The noise that still can be added. */ static int GetAllowedNoise(TownID town_id); /** * Get the road layout for a town. * @param town_id The town to get the road layout from. * @return The RoadLayout for the town. */ static RoadLayout GetRoadLayout(TownID town_id); }; #endif /* SCRIPT_TOWN_HPP */ openttd-1.5.3/src/script/api/script_map.hpp0000644000000000000000000001001212627373434017416 0ustar rootroot/* $Id: script_map.hpp 23614 2011-12-19 20:57:23Z truebrain $ */ /* * 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 script_map.hpp Everything to query and manipulate map metadata. */ #ifndef SCRIPT_MAP_HPP #define SCRIPT_MAP_HPP #include "script_object.hpp" #include "../../tile_type.h" /** * Class that handles all map related functions. * @api ai game */ class ScriptMap : public ScriptObject { public: static const int TILE_INVALID = (int)INVALID_TILE; ///< Invalid TileIndex. /** * Checks whether the given tile is valid. * @param tile The tile to check. * @return True is the tile it within the boundaries of the map. */ static bool IsValidTile(TileIndex tile); /** * Gets the number of tiles in the map. * @return The size of the map in tiles. * @post Return value is always positive. */ static TileIndex GetMapSize(); /** * Gets the amount of tiles along the SW and NE border. * @return The length along the SW and NE borders. * @post Return value is always positive. */ static uint32 GetMapSizeX(); /** * Gets the amount of tiles along the SE and NW border. * @return The length along the SE and NW borders. * @post Return value is always positive. */ static uint32 GetMapSizeY(); /** * Gets the place along the SW/NE border (X-value). * @param tile The tile to get the X-value of. * @pre IsValidTile(tile). * @return The X-value. * @post Return value is always lower than GetMapSizeX(). */ static int32 GetTileX(TileIndex tile); /** * Gets the place along the SE/NW border (Y-value). * @param tile The tile to get the Y-value of. * @pre IsValidTile(tile). * @return The Y-value. * @post Return value is always lower than GetMapSizeY(). */ static int32 GetTileY(TileIndex tile); /** * Gets the TileIndex given a x,y-coordinate. * @param x The X coordinate. * @param y The Y coordinate. * @pre x < GetMapSizeX(). * @pre y < GetMapSizeY(). * @return The TileIndex for the given (x,y) coordinate. */ static TileIndex GetTileIndex(uint32 x, uint32 y); /** * Calculates the Manhattan distance; the difference of * the X and Y added together. * @param tile_from The start tile. * @param tile_to The destination tile. * @pre IsValidTile(tile_from). * @pre IsValidTile(tile_to). * @return The Manhattan distance between the tiles. */ static int32 DistanceManhattan(TileIndex tile_from, TileIndex tile_to); /** * Calculates the distance between two tiles via 1D calculation. * This means the distance between X or the distance between Y, depending * on which one is bigger. * @param tile_from The start tile. * @param tile_to The destination tile. * @pre IsValidTile(tile_from). * @pre IsValidTile(tile_to). * @return The maximum distance between the tiles. */ static int32 DistanceMax(TileIndex tile_from, TileIndex tile_to); /** * The squared distance between the two tiles. * This is the distance is the length of the shortest straight line * between both points. * @param tile_from The start tile. * @param tile_to The destination tile. * @pre IsValidTile(tile_from). * @pre IsValidTile(tile_to). * @return The squared distance between the tiles. */ static int32 DistanceSquare(TileIndex tile_from, TileIndex tile_to); /** * Calculates the shortest distance to the edge. * @param tile From where the distance has to be calculated. * @pre IsValidTile(tile). * @return The distances to the closest edge. */ static int32 DistanceFromEdge(TileIndex tile); }; #endif /* SCRIPT_MAP_HPP */ openttd-1.5.3/src/script/api/script_list.hpp0000644000000000000000000002141712627373434017627 0ustar rootroot/* $Id: script_list.hpp 27104 2015-01-01 21:08:19Z rubidium $ */ /* * 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 script_list.hpp A list which can keep item/value pairs, which you can walk. */ /** @defgroup ScriptList Classes that create a list of items. */ #ifndef SCRIPT_LIST_HPP #define SCRIPT_LIST_HPP #include "script_object.hpp" #include #include class ScriptListSorter; /** * Class that creates a list which can keep item/value pairs, which you can walk. * @api ai game */ class ScriptList : public ScriptObject { public: /** Type of sorter */ enum SorterType { SORT_BY_VALUE, ///< Sort the list based on the value of the item. SORT_BY_ITEM, ///< Sort the list based on the item itself. }; /** Sort ascending */ static const bool SORT_ASCENDING = true; /** Sort descending */ static const bool SORT_DESCENDING = false; private: ScriptListSorter *sorter; ///< Sorting algorithm SorterType sorter_type; ///< Sorting type bool sort_ascending; ///< Whether to sort ascending or descending bool initialized; ///< Whether an iteration has been started int modifications; ///< Number of modification that has been done. To prevent changing data while valuating. public: typedef std::set ScriptItemList; ///< The list of items inside the bucket typedef std::map ScriptListBucket; ///< The bucket list per value typedef std::map ScriptListMap; ///< List per item ScriptListMap items; ///< The items in the list ScriptListBucket buckets; ///< The items in the list, sorted by value ScriptList(); ~ScriptList(); #ifdef DOXYGEN_API /** * Add a single item to the list. * @param item the item to add. Should be unique, otherwise it is ignored. * @param value the value to assign. */ void AddItem(int64 item, int64 value); #else void AddItem(int64 item, int64 value = 0); #endif /* DOXYGEN_API */ /** * Remove a single item from the list. * @param item the item to remove. If not existing, it is ignored. */ void RemoveItem(int64 item); /** * Clear the list, making Count() returning 0 and IsEmpty() returning true. */ void Clear(); /** * Check if an item is in the list. * @param item the item to check for. * @return true if the item is in the list. */ bool HasItem(int64 item); /** * Go to the beginning of the list and return the item. To get the value use list.GetValue(list.Begin()). * @return the first item. * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list. */ int64 Begin(); /** * Go to the next item in the list and return the item. To get the value use list.GetValue(list.Next()). * @return the next item. * @note returns 0 if beyond end-of-list. Use IsEnd() to check for end-of-list. */ int64 Next(); /** * Check if a list is empty. * @return true if the list is empty. */ bool IsEmpty(); /** * Check if there is a element left. In other words, if this is false, * the last call to Begin() or Next() returned a valid item. * @return true if the current item is beyond end-of-list. */ bool IsEnd(); /** * Returns the amount of items in the list. * @return amount of items in the list. */ int32 Count(); /** * Get the value that belongs to this item. * @param item the item to get the value from * @return the value that belongs to this item. */ int64 GetValue(int64 item); /** * Set a value of an item directly. * @param item the item to set the value for. * @param value the value to give to the item * @return true if we could set the item to value, false otherwise. * @note Changing values of items while looping through a list might cause * entries to be skipped. Be very careful with such operations. */ bool SetValue(int64 item, int64 value); /** * Sort this list by the given sorter and direction. * @param sorter the type of sorter to use * @param ascending if true, lowest value is on top, else at bottom. * @note the current item stays at the same place. * @see SORT_ASCENDING SORT_DESCENDING */ void Sort(SorterType sorter, bool ascending); /** * Add one list to another one. * @param list The list that will be added to the caller. * @post The list to be added ('list') stays unmodified. * @note All added items keep their value as it was in 'list'. * @note If the item already exists inside the caller, the value of the * list that is added is set on the item. */ void AddList(ScriptList *list); /** * Swap the contents of two lists. * @param list The list that will be swapped with. */ void SwapList(ScriptList *list); /** * Removes all items with a higher value than 'value'. * @param value the value above which all items are removed. */ void RemoveAboveValue(int64 value); /** * Removes all items with a lower value than 'value'. * @param value the value below which all items are removed. */ void RemoveBelowValue(int64 value); /** * Removes all items with a value above start and below end. * @param start the lower bound of the to be removed values (exclusive). * @param end the upper bound of the to be removed values (exclusive). */ void RemoveBetweenValue(int64 start, int64 end); /** * Remove all items with this value. * @param value the value to remove. */ void RemoveValue(int64 value); /** * Remove the first count items. * @param count the amount of items to remove. */ void RemoveTop(int32 count); /** * Remove the last count items. * @param count the amount of items to remove. */ void RemoveBottom(int32 count); /** * Remove everything that is in the given list from this list (same item index that is). * @param list the list of items to remove. * @pre list != NULL */ void RemoveList(ScriptList *list); /** * Keep all items with a higher value than 'value'. * @param value the value above which all items are kept. */ void KeepAboveValue(int64 value); /** * Keep all items with a lower value than 'value'. * @param value the value below which all items are kept. */ void KeepBelowValue(int64 value); /** * Keep all items with a value above start and below end. * @param start the lower bound of the to be kept values (exclusive). * @param end the upper bound of the to be kept values (exclusive). */ void KeepBetweenValue(int64 start, int64 end); /** * Keep all items with this value. * @param value the value to keep. */ void KeepValue(int64 value); /** * Keep the first count items, i.e. remove everything except the first count items. * @param count the amount of items to keep. */ void KeepTop(int32 count); /** * Keep the last count items, i.e. remove everything except the last count items. * @param count the amount of items to keep. */ void KeepBottom(int32 count); /** * Keeps everything that is in the given list from this list (same item index that is). * @param list the list of items to keep. * @pre list != NULL */ void KeepList(ScriptList *list); #ifndef DOXYGEN_API /** * Used for 'foreach()' and [] get from Squirrel. */ SQInteger _get(HSQUIRRELVM vm); /** * Used for [] set from Squirrel. */ SQInteger _set(HSQUIRRELVM vm); /** * Used for 'foreach()' from Squirrel. */ SQInteger _nexti(HSQUIRRELVM vm); /** * The Valuate() wrapper from Squirrel. */ SQInteger Valuate(HSQUIRRELVM vm); #else /** * Give all items a value defined by the valuator you give. * @param valuator_function The function which will be doing the valuation. * @param params The params to give to the valuators (minus the first param, * which is always the index-value we are valuating). * @note You may not add, remove or change (setting the value of) items while * valuating. You may also not (re)sort while valuating. * @note You can write your own valuators and use them. Just remember that * the first parameter should be the index-value, and it should return * an integer. * @note Example: * list.Valuate(ScriptBridge.GetPrice, 5); * list.Valuate(ScriptBridge.GetMaxLength); * function MyVal(bridge_id, myparam) * { * return myparam * bridge_id; // This is silly * } * list.Valuate(MyVal, 12); */ void Valuate(void *valuator_function, int params, ...); #endif /* DOXYGEN_API */ }; #endif /* SCRIPT_LIST_HPP */ openttd-1.5.3/src/script/api/script_admin.hpp0000644000000000000000000000371712627373433017746 0ustar rootroot/* $Id: script_admin.hpp 25594 2013-07-13 06:38:54Z rubidium $ */ /* * 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 script_admin.hpp Everything to communicate with the AdminPort. */ #ifndef SCRIPT_ADMIN_HPP #define SCRIPT_ADMIN_HPP #include #include "script_object.hpp" /** * Class that handles communication with the AdminPort. * @api game */ class ScriptAdmin : public ScriptObject { public: #ifndef DOXYGEN_API /** * Internal representation of the Send function. */ static SQInteger Send(HSQUIRRELVM vm); #else /** * Send information to the AdminPort. The information can be anything * as long as it isn't a class or instance thereof. * @param table The information to send, in a table. For example: { param = "param" }. * @return True if and only if the data was successfully converted to JSON * and send to the AdminPort. * @note If the resulting JSON of your table is larger than 1450 bytes, * nothing will be sent (and false will be returned). */ static bool Send(void *table); #endif /* DOXYGEN_API */ private: /** * Convert a Squirrel structure into a JSON string. * @param vm The VM to operate on. * @param index The index we are currently working for. * @param max_depth The maximal depth to follow the squirrel struct. * @param data The resulting json string. */ static bool MakeJSON(HSQUIRRELVM vm, SQInteger index, int max_depth, std::string &data); }; #endif /* SCRIPT_ADMIN_HPP */ openttd-1.5.3/src/script/api/script_text.cpp0000644000000000000000000001257012627373434017633 0ustar rootroot/* $Id: script_text.cpp 27102 2015-01-01 20:50:43Z rubidium $ */ /* * 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 script_text.cpp Implementation of ScriptText. */ #include "../../stdafx.h" #include "../../string_func.h" #include "../../strings_func.h" #include "script_text.hpp" #include "../../table/control_codes.h" #include "table/strings.h" #include "../../safeguards.h" RawText::RawText(const char *text) : text(stredup(text)) { } RawText::~RawText() { free(this->text); } ScriptText::ScriptText(HSQUIRRELVM vm) : ZeroedMemoryAllocator() { int nparam = sq_gettop(vm) - 1; if (nparam < 1) { throw sq_throwerror(vm, "You need to pass at least a StringID to the constructor"); } /* First resolve the StringID. */ SQInteger sqstring; if (SQ_FAILED(sq_getinteger(vm, 2, &sqstring))) { throw sq_throwerror(vm, "First argument must be a valid StringID"); } this->string = sqstring; /* The rest of the parameters must be arguments. */ for (int i = 0; i < nparam - 1; i++) { /* Push the parameter to the top of the stack. */ sq_push(vm, i + 3); if (SQ_FAILED(this->_SetParam(i, vm))) { this->~ScriptText(); throw sq_throwerror(vm, "Invalid parameter"); } /* Pop the parameter again. */ sq_pop(vm, 1); } } ScriptText::~ScriptText() { for (int i = 0; i < SCRIPT_TEXT_MAX_PARAMETERS; i++) { free(this->params[i]); if (this->paramt[i] != NULL) this->paramt[i]->Release(); } } SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) { if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR; free(this->params[parameter]); if (this->paramt[parameter] != NULL) this->paramt[parameter]->Release(); this->parami[parameter] = 0; this->params[parameter] = NULL; this->paramt[parameter] = NULL; switch (sq_gettype(vm, -1)) { case OT_STRING: { const SQChar *value; sq_getstring(vm, -1, &value); this->params[parameter] = stredup(value); ValidateString(this->params[parameter]); break; } case OT_INTEGER: { SQInteger value; sq_getinteger(vm, -1, &value); this->parami[parameter] = value; break; } case OT_INSTANCE: { SQUserPointer real_instance = NULL; HSQOBJECT instance; sq_getstackobj(vm, -1, &instance); /* Validate if it is a GSText instance */ sq_pushroottable(vm); sq_pushstring(vm, "GSText", -1); sq_get(vm, -2); sq_pushobject(vm, instance); if (sq_instanceof(vm) != SQTrue) return SQ_ERROR; sq_pop(vm, 3); /* Get the 'real' instance of this class */ sq_getinstanceup(vm, -1, &real_instance, 0); if (real_instance == NULL) return SQ_ERROR; ScriptText *value = static_cast(real_instance); value->AddRef(); this->paramt[parameter] = value; break; } default: return SQ_ERROR; } if (this->paramc <= parameter) this->paramc = parameter + 1; return 0; } SQInteger ScriptText::SetParam(HSQUIRRELVM vm) { if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR; SQInteger k; sq_getinteger(vm, 2, &k); if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR; if (k < 1) return SQ_ERROR; k--; return this->_SetParam(k, vm); } SQInteger ScriptText::AddParam(HSQUIRRELVM vm) { SQInteger res; res = this->_SetParam(this->paramc, vm); if (res != 0) return res; /* Push our own instance back on top of the stack */ sq_push(vm, 1); return 1; } SQInteger ScriptText::_set(HSQUIRRELVM vm) { int32 k; if (sq_gettype(vm, 2) == OT_STRING) { const SQChar *key_string; sq_getstring(vm, 2, &key_string); ValidateString(key_string); if (strncmp(key_string, "param_", 6) != 0 || strlen(key_string) > 8) return SQ_ERROR; k = atoi(key_string + 6); } else if (sq_gettype(vm, 2) == OT_INTEGER) { SQInteger key; sq_getinteger(vm, 2, &key); k = (int32)key; } else { return SQ_ERROR; } if (k > SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR; if (k < 1) return SQ_ERROR; k--; return this->_SetParam(k, vm); } const char *ScriptText::GetEncodedText() { static char buf[1024]; int param_count = 0; this->_GetEncodedText(buf, lastof(buf), param_count); return (param_count > SCRIPT_TEXT_MAX_PARAMETERS) ? NULL : buf; } char *ScriptText::_GetEncodedText(char *p, char *lastofp, int ¶m_count) { p += Utf8Encode(p, SCC_ENCODED); p += seprintf(p, lastofp, "%X", this->string); for (int i = 0; i < this->paramc; i++) { if (this->params[i] != NULL) { p += seprintf(p, lastofp, ":\"%s\"", this->params[i]); param_count++; continue; } if (this->paramt[i] != NULL) { p += seprintf(p, lastofp, ":"); p = this->paramt[i]->_GetEncodedText(p, lastofp, param_count); continue; } p += seprintf(p, lastofp,":" OTTD_PRINTFHEX64, this->parami[i]); param_count++; } return p; } const char *Text::GetDecodedText() { const char *encoded_text = this->GetEncodedText(); if (encoded_text == NULL) return NULL; static char buf[1024]; ::SetDParamStr(0, encoded_text); ::GetString(buf, STR_JUST_RAW_STRING, lastof(buf)); return buf; } openttd-1.5.3/src/script/api/script_railtypelist.hpp0000644000000000000000000000200612627373434021372 0ustar rootroot/* $Id: script_railtypelist.hpp 23615 2011-12-19 20:57:34Z truebrain $ */ /* * 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 script_railtypelist.hpp List all available railtypes. */ #ifndef SCRIPT_RAILTYPELIST_HPP #define SCRIPT_RAILTYPELIST_HPP #include "script_list.hpp" /** * Creates a list of all available railtypes. * @api ai game * @ingroup ScriptList */ class ScriptRailTypeList : public ScriptList { public: ScriptRailTypeList(); }; #endif /* SCRIPT_RAILTYPELIST_HPP */ openttd-1.5.3/src/script/api/script_gamesettings.cpp0000644000000000000000000000450012627373433021332 0ustar rootroot/* $Id: script_gamesettings.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_gamesettings.cpp Implementation of ScriptGameSettings. */ #include "../../stdafx.h" #include "script_gamesettings.hpp" #include "../../settings_internal.h" #include "../../settings_type.h" #include "../../command_type.h" #include "../../safeguards.h" /* static */ bool ScriptGameSettings::IsValid(const char *setting) { uint i; const SettingDesc *sd = GetSettingFromName(setting, &i); return sd != NULL && sd->desc.cmd != SDT_STRING; } /* static */ int32 ScriptGameSettings::GetValue(const char *setting) { if (!IsValid(setting)) return -1; uint index; const SettingDesc *sd = GetSettingFromName(setting, &index); void *ptr = GetVariableAddress(&_settings_game, &sd->save); if (sd->desc.cmd == SDT_BOOLX) return *(bool*)ptr; return (int32)ReadValue(ptr, sd->save.conv); } /* static */ bool ScriptGameSettings::SetValue(const char *setting, int value) { if (!IsValid(setting)) return false; uint index; const SettingDesc *sd = GetSettingFromName(setting, &index); if ((sd->save.conv & SLF_NO_NETWORK_SYNC) != 0) return false; if (sd->desc.cmd != SDT_BOOLX && sd->desc.cmd != SDT_NUMX) return false; return ScriptObject::DoCommand(0, index, value, CMD_CHANGE_SETTING); } /* static */ bool ScriptGameSettings::IsDisabledVehicleType(ScriptVehicle::VehicleType vehicle_type) { switch (vehicle_type) { case ScriptVehicle::VT_RAIL: return _settings_game.ai.ai_disable_veh_train; case ScriptVehicle::VT_ROAD: return _settings_game.ai.ai_disable_veh_roadveh; case ScriptVehicle::VT_WATER: return _settings_game.ai.ai_disable_veh_ship; case ScriptVehicle::VT_AIR: return _settings_game.ai.ai_disable_veh_aircraft; default: return true; } } openttd-1.5.3/src/script/api/script_companymode.cpp0000644000000000000000000000217412627373434021161 0ustar rootroot/* $Id: script_companymode.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_companymode.cpp Implementation of ScriptCompanyMode. */ #include "../../stdafx.h" #include "script_companymode.hpp" #include "../../safeguards.h" ScriptCompanyMode::ScriptCompanyMode(int company) { if (company < OWNER_BEGIN || company >= MAX_COMPANIES) company = INVALID_COMPANY; this->last_company = ScriptObject::GetCompany(); ScriptObject::SetCompany((CompanyID)company); } ScriptCompanyMode::~ScriptCompanyMode() { ScriptObject::SetCompany(this->last_company); } openttd-1.5.3/src/script/api/script_basestation.cpp0000644000000000000000000000503412627373434021160 0ustar rootroot/* $Id: script_basestation.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_basestation.cpp Implementation of ScriptBaseStation. */ #include "../../stdafx.h" #include "script_basestation.hpp" #include "script_error.hpp" #include "../../station_base.h" #include "../../string_func.h" #include "../../strings_func.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ bool ScriptBaseStation::IsValidBaseStation(StationID station_id) { const BaseStation *st = ::BaseStation::GetIfValid(station_id); return st != NULL && (st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY || st->owner == OWNER_NONE); } /* static */ char *ScriptBaseStation::GetName(StationID station_id) { if (!IsValidBaseStation(station_id)) return NULL; ::SetDParam(0, station_id); return GetString(::Station::IsValidID(station_id) ? STR_STATION_NAME : STR_WAYPOINT_NAME); } /* static */ bool ScriptBaseStation::SetName(StationID station_id, Text *name) { CCountedPtr counter(name); EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidBaseStation(station_id)); EnforcePrecondition(false, name != NULL); const char *text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_STATION_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::DoCommand(0, station_id, 0, ::Station::IsValidID(station_id) ? CMD_RENAME_STATION : CMD_RENAME_WAYPOINT, text); } /* static */ TileIndex ScriptBaseStation::GetLocation(StationID station_id) { if (!IsValidBaseStation(station_id)) return INVALID_TILE; return ::BaseStation::Get(station_id)->xy; } /* static */ ScriptDate::Date ScriptBaseStation::GetConstructionDate(StationID station_id) { if (!IsValidBaseStation(station_id)) return ScriptDate::DATE_INVALID; return (ScriptDate::Date)::BaseStation::Get(station_id)->build_date; } openttd-1.5.3/src/script/api/script_testmode.cpp0000644000000000000000000000316012627373434020466 0ustar rootroot/* $Id: script_testmode.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_testmode.cpp Implementation of ScriptTestMode. */ #include "../../stdafx.h" #include "script_testmode.hpp" #include "../script_instance.hpp" #include "../script_fatalerror.hpp" #include "../../safeguards.h" bool ScriptTestMode::ModeProc() { /* In test mode we only return 'false', telling the DoCommand it * should stop after testing the command and return with that result. */ return false; } ScriptTestMode::ScriptTestMode() { this->last_mode = this->GetDoCommandMode(); this->last_instance = this->GetDoCommandModeInstance(); this->SetDoCommandMode(&ScriptTestMode::ModeProc, this); } ScriptTestMode::~ScriptTestMode() { if (this->GetDoCommandModeInstance() != this) { /* Ignore this error if the script already died. */ if (!ScriptObject::GetActiveInstance()->IsDead()) { throw Script_FatalError("Testmode object was removed while it was not the latest *Mode object created."); } } this->SetDoCommandMode(this->last_mode, this->last_instance); } openttd-1.5.3/src/script/api/script_window.hpp0000644000000000000000000057102612627373434020171 0ustar rootroot/* $Id: script_window.hpp 27174 2015-03-01 08:17:14Z alberth $ */ /* * 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 script_window.hpp Everything to handle window interaction. */ #ifndef SCRIPT_WINDOW_HPP #define SCRIPT_WINDOW_HPP #include "script_object.hpp" #include "../../window_type.h" #include "../../gfx_type.h" #include "../../widgets/ai_widget.h" #include "../../widgets/airport_widget.h" #include "../../widgets/autoreplace_widget.h" #include "../../widgets/bootstrap_widget.h" #include "../../widgets/bridge_widget.h" #include "../../widgets/build_vehicle_widget.h" #include "../../widgets/cheat_widget.h" #include "../../widgets/company_widget.h" #include "../../widgets/console_widget.h" #include "../../widgets/date_widget.h" #include "../../widgets/depot_widget.h" #include "../../widgets/dock_widget.h" #include "../../widgets/dropdown_widget.h" #include "../../widgets/engine_widget.h" #include "../../widgets/error_widget.h" #include "../../widgets/fios_widget.h" #include "../../widgets/genworld_widget.h" #include "../../widgets/goal_widget.h" #include "../../widgets/graph_widget.h" #include "../../widgets/group_widget.h" #include "../../widgets/highscore_widget.h" #include "../../widgets/industry_widget.h" #include "../../widgets/intro_widget.h" #include "../../widgets/main_widget.h" #include "../../widgets/misc_widget.h" #include "../../widgets/music_widget.h" #include "../../widgets/network_chat_widget.h" #include "../../widgets/network_content_widget.h" #include "../../widgets/network_widget.h" #include "../../widgets/newgrf_debug_widget.h" #include "../../widgets/newgrf_widget.h" #include "../../widgets/news_widget.h" #include "../../widgets/object_widget.h" #include "../../widgets/order_widget.h" #include "../../widgets/osk_widget.h" #include "../../widgets/rail_widget.h" #include "../../widgets/road_widget.h" #include "../../widgets/settings_widget.h" #include "../../widgets/sign_widget.h" #include "../../widgets/smallmap_widget.h" #include "../../widgets/station_widget.h" #include "../../widgets/statusbar_widget.h" #include "../../widgets/subsidy_widget.h" #include "../../widgets/terraform_widget.h" #include "../../widgets/timetable_widget.h" #include "../../widgets/toolbar_widget.h" #include "../../widgets/town_widget.h" #include "../../widgets/transparency_widget.h" #include "../../widgets/tree_widget.h" #include "../../widgets/vehicle_widget.h" #include "../../widgets/viewport_widget.h" #include "../../widgets/waypoint_widget.h" #include "../../widgets/link_graph_legend_widget.h" #include "../../widgets/story_widget.h" /** * Class that handles window interaction. A Window in OpenTTD has two imporant * values. The WindowClass, and a Window number. The first indicates roughly * which window it is. WC_TOWN_VIEW for example, is the view of a town. * The Window number is a bit more complex, as it depends mostly on the * WindowClass. For example for WC_TOWN_VIEW it is the TownID. In general a * good rule of thumb is: either the number is always 0, or the ID of the * object in question. * In the comment at the widget enum, it is mentioned how the number is used. * * Note, that the detailed window layout is very version specific. * Enum values might be added, changed or removed in future versions without notice * in the changelog, and there won't be any means of compatibility. * * @api game */ class ScriptWindow : public ScriptObject { public: // @enum WindowNumberEnum ../../window_type.h /* automatically generated from ../../window_type.h */ /** %Window numbers. */ enum WindowNumberEnum { WN_GAME_OPTIONS_AI = ::WN_GAME_OPTIONS_AI, ///< AI settings. WN_GAME_OPTIONS_ABOUT = ::WN_GAME_OPTIONS_ABOUT, ///< About window. WN_GAME_OPTIONS_NEWGRF_STATE = ::WN_GAME_OPTIONS_NEWGRF_STATE, ///< NewGRF settings. WN_GAME_OPTIONS_GAME_OPTIONS = ::WN_GAME_OPTIONS_GAME_OPTIONS, ///< Game options. WN_GAME_OPTIONS_GAME_SETTINGS = ::WN_GAME_OPTIONS_GAME_SETTINGS, ///< Game settings. WN_QUERY_STRING = ::WN_QUERY_STRING, ///< Query string. WN_QUERY_STRING_SIGN = ::WN_QUERY_STRING_SIGN, ///< Query string for signs. WN_CONFIRM_POPUP_QUERY = ::WN_CONFIRM_POPUP_QUERY, ///< Query popup confirm. WN_CONFIRM_POPUP_QUERY_BOOTSTRAP = ::WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, ///< Query popup confirm for bootstrap. WN_NETWORK_WINDOW_GAME = ::WN_NETWORK_WINDOW_GAME, ///< Network game window. WN_NETWORK_WINDOW_LOBBY = ::WN_NETWORK_WINDOW_LOBBY, ///< Network lobby window. WN_NETWORK_WINDOW_CONTENT_LIST = ::WN_NETWORK_WINDOW_CONTENT_LIST, ///< Network content list. WN_NETWORK_WINDOW_START = ::WN_NETWORK_WINDOW_START, ///< Network start server. WN_NETWORK_STATUS_WINDOW_JOIN = ::WN_NETWORK_STATUS_WINDOW_JOIN, ///< Network join status. WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD = ::WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, ///< Network content download status. }; // @endenum // @enum WindowClass ../../window_type.h /* automatically generated from ../../window_type.h */ /** %Window classes. */ enum WindowClass { WC_NONE = ::WC_NONE, ///< No window, redirects to WC_MAIN_WINDOW. /** * Main window; %Window numbers: * - 0 = #MainWidgets */ WC_MAIN_WINDOW = ::WC_MAIN_WINDOW, /** * Main toolbar (the long bar at the top); %Window numbers: * - 0 = #ToolbarNormalWidgets * - 0 = #ToolbarEditorWidgets */ WC_MAIN_TOOLBAR = ::WC_MAIN_TOOLBAR, /** * Statusbar (at the bottom of your screen); %Window numbers: * - 0 = #StatusbarWidgets */ WC_STATUS_BAR = ::WC_STATUS_BAR, /** * Build toolbar; %Window numbers: * - #TRANSPORT_RAIL = #RailToolbarWidgets * - #TRANSPORT_AIR = #AirportToolbarWidgets * - #TRANSPORT_WATER = #DockToolbarWidgets * - #TRANSPORT_ROAD = #RoadToolbarWidgets */ WC_BUILD_TOOLBAR = ::WC_BUILD_TOOLBAR, /** * Scenario build toolbar; %Window numbers: * - #TRANSPORT_WATER = #DockToolbarWidgets * - #TRANSPORT_ROAD = #RoadToolbarWidgets */ WC_SCEN_BUILD_TOOLBAR = ::WC_SCEN_BUILD_TOOLBAR, /** * Build trees toolbar; %Window numbers: * - 0 = #BuildTreesWidgets */ WC_BUILD_TREES = ::WC_BUILD_TREES, /** * Transparency toolbar; %Window numbers: * - 0 = #TransparencyToolbarWidgets */ WC_TRANSPARENCY_TOOLBAR = ::WC_TRANSPARENCY_TOOLBAR, /** * Build signal toolbar; %Window numbers: * - #TRANSPORT_RAIL = #BuildSignalWidgets */ WC_BUILD_SIGNAL = ::WC_BUILD_SIGNAL, /** * Small map; %Window numbers: * - 0 = #SmallMapWidgets */ WC_SMALLMAP = ::WC_SMALLMAP, /** * Error message; %Window numbers: * - 0 = #ErrorMessageWidgets */ WC_ERRMSG = ::WC_ERRMSG, /** * Tooltip window; %Window numbers: * - 0 = #ToolTipsWidgets */ WC_TOOLTIPS = ::WC_TOOLTIPS, /** * Query string window; %Window numbers: * - #WN_QUERY_STRING = #QueryStringWidgets * - #WN_QUERY_STRING_SIGN = #QueryEditSignWidgets */ WC_QUERY_STRING = ::WC_QUERY_STRING, /** * Popup with confirm question; %Window numbers: * - #WN_CONFIRM_POPUP_QUERY = #QueryWidgets * - #WN_CONFIRM_POPUP_QUERY_BOOTSTRAP = #BootstrapAskForDownloadWidgets */ WC_CONFIRM_POPUP_QUERY = ::WC_CONFIRM_POPUP_QUERY, /** * Popup with a set of buttons, designed to ask the user a question * from a GameScript. %Window numbers: * - uniqueid = #GoalQuestionWidgets */ WC_GOAL_QUESTION = ::WC_GOAL_QUESTION, /** * Saveload window; %Window numbers: * - 0 = #SaveLoadWidgets */ WC_SAVELOAD = ::WC_SAVELOAD, /** * Land info window; %Window numbers: * - 0 = #LandInfoWidgets */ WC_LAND_INFO = ::WC_LAND_INFO, /** * Drop down menu; %Window numbers: * - 0 = #DropdownMenuWidgets */ WC_DROPDOWN_MENU = ::WC_DROPDOWN_MENU, /** * On Screen Keyboard; %Window numbers: * - 0 = #OnScreenKeyboardWidgets */ WC_OSK = ::WC_OSK, /** * Set date; %Window numbers: * - #VehicleID = #SetDateWidgets */ WC_SET_DATE = ::WC_SET_DATE, /** * AI settings; %Window numbers: * - 0 = #AISettingsWidgets */ WC_AI_SETTINGS = ::WC_AI_SETTINGS, /** * NewGRF parameters; %Window numbers: * - 0 = #NewGRFParametersWidgets */ WC_GRF_PARAMETERS = ::WC_GRF_PARAMETERS, /** * textfile; %Window numbers: * - 0 = #TextfileWidgets */ WC_TEXTFILE = ::WC_TEXTFILE, /** * Town authority; %Window numbers: * - #TownID = #TownAuthorityWidgets */ WC_TOWN_AUTHORITY = ::WC_TOWN_AUTHORITY, /** * Vehicle details; %Window numbers: * - #VehicleID = #VehicleDetailsWidgets */ WC_VEHICLE_DETAILS = ::WC_VEHICLE_DETAILS, /** * Vehicle refit; %Window numbers: * - #VehicleID = #VehicleRefitWidgets */ WC_VEHICLE_REFIT = ::WC_VEHICLE_REFIT, /** * Vehicle orders; %Window numbers: * - #VehicleID = #OrderWidgets */ WC_VEHICLE_ORDERS = ::WC_VEHICLE_ORDERS, /** * Replace vehicle window; %Window numbers: * - #VehicleType = #ReplaceVehicleWidgets */ WC_REPLACE_VEHICLE = ::WC_REPLACE_VEHICLE, /** * Vehicle timetable; %Window numbers: * - #VehicleID = #VehicleTimetableWidgets */ WC_VEHICLE_TIMETABLE = ::WC_VEHICLE_TIMETABLE, /** * Company colour selection; %Window numbers: * - #CompanyID = #SelectCompanyLiveryWidgets */ WC_COMPANY_COLOUR = ::WC_COMPANY_COLOUR, /** * Alter company face window; %Window numbers: * - #CompanyID = #SelectCompanyManagerFaceWidgets */ WC_COMPANY_MANAGER_FACE = ::WC_COMPANY_MANAGER_FACE, /** * Select station (when joining stations); %Window numbers: * - 0 = #JoinStationWidgets */ WC_SELECT_STATION = ::WC_SELECT_STATION, /** * News window; %Window numbers: * - 0 = #NewsWidgets */ WC_NEWS_WINDOW = ::WC_NEWS_WINDOW, /** * Town directory; %Window numbers: * - 0 = #TownDirectoryWidgets */ WC_TOWN_DIRECTORY = ::WC_TOWN_DIRECTORY, /** * Subsidies list; %Window numbers: * - 0 = #SubsidyListWidgets */ WC_SUBSIDIES_LIST = ::WC_SUBSIDIES_LIST, /** * Industry directory; %Window numbers: * - 0 = #IndustryDirectoryWidgets */ WC_INDUSTRY_DIRECTORY = ::WC_INDUSTRY_DIRECTORY, /** * News history list; %Window numbers: * - 0 = #MessageHistoryWidgets */ WC_MESSAGE_HISTORY = ::WC_MESSAGE_HISTORY, /** * Sign list; %Window numbers: * - 0 = #SignListWidgets */ WC_SIGN_LIST = ::WC_SIGN_LIST, /** * AI list; %Window numbers: * - 0 = #AIListWidgets */ WC_AI_LIST = ::WC_AI_LIST, /** * Goals list; %Window numbers: * - 0 ; #GoalListWidgets */ WC_GOALS_LIST = ::WC_GOALS_LIST, /** * Story book; %Window numbers: * - CompanyID = #StoryBookWidgets */ WC_STORY_BOOK = ::WC_STORY_BOOK, /** * Station list; %Window numbers: * - #CompanyID = #StationListWidgets */ WC_STATION_LIST = ::WC_STATION_LIST, /** * Trains list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_TRAINS_LIST = ::WC_TRAINS_LIST, /** * Road vehicle list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_ROADVEH_LIST = ::WC_ROADVEH_LIST, /** * Ships list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_SHIPS_LIST = ::WC_SHIPS_LIST, /** * Aircraft list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_AIRCRAFT_LIST = ::WC_AIRCRAFT_LIST, /** * Town view; %Window numbers: * - #TownID = #TownViewWidgets */ WC_TOWN_VIEW = ::WC_TOWN_VIEW, /** * Vehicle view; %Window numbers: * - #VehicleID = #VehicleViewWidgets */ WC_VEHICLE_VIEW = ::WC_VEHICLE_VIEW, /** * Station view; %Window numbers: * - #StationID = #StationViewWidgets */ WC_STATION_VIEW = ::WC_STATION_VIEW, /** * Depot view; %Window numbers: * - #TileIndex = #DepotWidgets */ WC_VEHICLE_DEPOT = ::WC_VEHICLE_DEPOT, /** * Waypoint view; %Window numbers: * - #WaypointID = #WaypointWidgets */ WC_WAYPOINT_VIEW = ::WC_WAYPOINT_VIEW, /** * Industry view; %Window numbers: * - #IndustryID = #IndustryViewWidgets */ WC_INDUSTRY_VIEW = ::WC_INDUSTRY_VIEW, /** * Company view; %Window numbers: * - #CompanyID = #CompanyWidgets */ WC_COMPANY = ::WC_COMPANY, /** * Build object; %Window numbers: * - 0 = #BuildObjectWidgets */ WC_BUILD_OBJECT = ::WC_BUILD_OBJECT, /** * Build vehicle; %Window numbers: * - #VehicleType = #BuildVehicleWidgets * - #TileIndex = #BuildVehicleWidgets */ WC_BUILD_VEHICLE = ::WC_BUILD_VEHICLE, /** * Build bridge; %Window numbers: * - #TransportType = #BuildBridgeSelectionWidgets */ WC_BUILD_BRIDGE = ::WC_BUILD_BRIDGE, /** * Build station; %Window numbers: * - #TRANSPORT_AIR = #AirportPickerWidgets * - #TRANSPORT_WATER = #DockToolbarWidgets * - #TRANSPORT_RAIL = #BuildRailStationWidgets */ WC_BUILD_STATION = ::WC_BUILD_STATION, /** * Build bus station; %Window numbers: * - #TRANSPORT_ROAD = #BuildRoadStationWidgets */ WC_BUS_STATION = ::WC_BUS_STATION, /** * Build truck station; %Window numbers: * - #TRANSPORT_ROAD = #BuildRoadStationWidgets */ WC_TRUCK_STATION = ::WC_TRUCK_STATION, /** * Build depot; %Window numbers: * - #TRANSPORT_WATER = #BuildDockDepotWidgets * - #TRANSPORT_RAIL = #BuildRailDepotWidgets * - #TRANSPORT_ROAD = #BuildRoadDepotWidgets */ WC_BUILD_DEPOT = ::WC_BUILD_DEPOT, /** * Build waypoint; %Window numbers: * - #TRANSPORT_RAIL = #BuildRailWaypointWidgets */ WC_BUILD_WAYPOINT = ::WC_BUILD_WAYPOINT, /** * Found a town; %Window numbers: * - 0 = #TownFoundingWidgets */ WC_FOUND_TOWN = ::WC_FOUND_TOWN, /** * Build industry; %Window numbers: * - 0 = #DynamicPlaceIndustriesWidgets */ WC_BUILD_INDUSTRY = ::WC_BUILD_INDUSTRY, /** * Select game window; %Window numbers: * - 0 = #SelectGameIntroWidgets */ WC_SELECT_GAME = ::WC_SELECT_GAME, /** * Landscape generation (in Scenario Editor); %Window numbers: * - 0 = #TerraformToolbarWidgets * - 0 = #EditorTerraformToolbarWidgets */ WC_SCEN_LAND_GEN = ::WC_SCEN_LAND_GEN, /** * Generate landscape (newgame); %Window numbers: * - GLWM_SCENARIO = #CreateScenarioWidgets * - #GenenerateLandscapeWindowMode = #GenerateLandscapeWidgets */ WC_GENERATE_LANDSCAPE = ::WC_GENERATE_LANDSCAPE, /** * Progress report of landscape generation; %Window numbers: * - 0 = #GenerationProgressWidgets * - 1 = #ScanProgressWidgets */ WC_MODAL_PROGRESS = ::WC_MODAL_PROGRESS, /** * Network window; %Window numbers: * - #WN_NETWORK_WINDOW_GAME = #NetworkGameWidgets * - #WN_NETWORK_WINDOW_LOBBY = #NetworkLobbyWidgets * - #WN_NETWORK_WINDOW_CONTENT_LIST = #NetworkContentListWidgets * - #WN_NETWORK_WINDOW_START = #NetworkStartServerWidgets */ WC_NETWORK_WINDOW = ::WC_NETWORK_WINDOW, /** * Client list; %Window numbers: * - 0 = #ClientListWidgets */ WC_CLIENT_LIST = ::WC_CLIENT_LIST, /** * Popup for the client list; %Window numbers: * - #ClientID = #ClientListPopupWidgets */ WC_CLIENT_LIST_POPUP = ::WC_CLIENT_LIST_POPUP, /** * Network status window; %Window numbers: * - #WN_NETWORK_STATUS_WINDOW_JOIN = #NetworkJoinStatusWidgets * - #WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD = #NetworkContentDownloadStatusWidgets */ WC_NETWORK_STATUS_WINDOW = ::WC_NETWORK_STATUS_WINDOW, /** * Chatbox; %Window numbers: * - #DestType = #NetWorkChatWidgets */ WC_SEND_NETWORK_MSG = ::WC_SEND_NETWORK_MSG, /** * Company password query; %Window numbers: * - 0 = #NetworkCompanyPasswordWidgets */ WC_COMPANY_PASSWORD_WINDOW = ::WC_COMPANY_PASSWORD_WINDOW, /** * Industry cargoes chain; %Window numbers: * - 0 = #IndustryCargoesWidgets */ WC_INDUSTRY_CARGOES = ::WC_INDUSTRY_CARGOES, /** * Legend for graphs; %Window numbers: * - 0 = #GraphLegendWidgets */ WC_GRAPH_LEGEND = ::WC_GRAPH_LEGEND, /** * Finances of a company; %Window numbers: * - #CompanyID = #CompanyWidgets */ WC_FINANCES = ::WC_FINANCES, /** * Income graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_INCOME_GRAPH = ::WC_INCOME_GRAPH, /** * Operating profit graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_OPERATING_PROFIT = ::WC_OPERATING_PROFIT, /** * Delivered cargo graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_DELIVERED_CARGO = ::WC_DELIVERED_CARGO, /** * Performance history graph; %Window numbers: * - 0 = #PerformanceHistoryGraphWidgets */ WC_PERFORMANCE_HISTORY = ::WC_PERFORMANCE_HISTORY, /** * Company value graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_COMPANY_VALUE = ::WC_COMPANY_VALUE, /** * Company league window; %Window numbers: * - 0 = #CompanyLeagueWidgets */ WC_COMPANY_LEAGUE = ::WC_COMPANY_LEAGUE, /** * Payment rates graph; %Window numbers: * - 0 = #CargoPaymentRatesWidgets */ WC_PAYMENT_RATES = ::WC_PAYMENT_RATES, /** * Performance detail window; %Window numbers: * - 0 = #PerformanceRatingDetailsWidgets */ WC_PERFORMANCE_DETAIL = ::WC_PERFORMANCE_DETAIL, /** * Company infrastructure overview; %Window numbers: * - #CompanyID = #CompanyInfrastructureWidgets */ WC_COMPANY_INFRASTRUCTURE = ::WC_COMPANY_INFRASTRUCTURE, /** * Buyout company (merger); %Window numbers: * - #CompanyID = #BuyCompanyWidgets */ WC_BUY_COMPANY = ::WC_BUY_COMPANY, /** * Engine preview window; %Window numbers: * - #EngineID = #EnginePreviewWidgets */ WC_ENGINE_PREVIEW = ::WC_ENGINE_PREVIEW, /** * Music window; %Window numbers: * - 0 = #MusicWidgets */ WC_MUSIC_WINDOW = ::WC_MUSIC_WINDOW, /** * Music track selection; %Window numbers: * - 0 = MusicTrackSelectionWidgets */ WC_MUSIC_TRACK_SELECTION = ::WC_MUSIC_TRACK_SELECTION, /** * Game options window; %Window numbers: * - #WN_GAME_OPTIONS_AI = #AIConfigWidgets * - #WN_GAME_OPTIONS_ABOUT = #AboutWidgets * - #WN_GAME_OPTIONS_NEWGRF_STATE = #NewGRFStateWidgets * - #WN_GAME_OPTIONS_GAME_OPTIONS = #GameOptionsWidgets * - #WN_GAME_OPTIONS_GAME_SETTINGS = #GameSettingsWidgets */ WC_GAME_OPTIONS = ::WC_GAME_OPTIONS, /** * Custom currency; %Window numbers: * - 0 = #CustomCurrencyWidgets */ WC_CUSTOM_CURRENCY = ::WC_CUSTOM_CURRENCY, /** * Cheat window; %Window numbers: * - 0 = #CheatWidgets */ WC_CHEATS = ::WC_CHEATS, /** * Extra viewport; %Window numbers: * - Ascending value = #ExtraViewportWidgets */ WC_EXTRA_VIEW_PORT = ::WC_EXTRA_VIEW_PORT, /** * Console; %Window numbers: * - 0 = #ConsoleWidgets */ WC_CONSOLE = ::WC_CONSOLE, /** * Bootstrap; %Window numbers: * - 0 = #BootstrapBackgroundWidgets */ WC_BOOTSTRAP = ::WC_BOOTSTRAP, /** * Highscore; %Window numbers: * - 0 = #HighscoreWidgets */ WC_HIGHSCORE = ::WC_HIGHSCORE, /** * Endscreen; %Window numbers: * - 0 = #HighscoreWidgets */ WC_ENDSCREEN = ::WC_ENDSCREEN, /** * AI debug window; %Window numbers: * - 0 = #AIDebugWidgets */ WC_AI_DEBUG = ::WC_AI_DEBUG, /** * NewGRF inspect (debug); %Window numbers: * - Packed value = #NewGRFInspectWidgets */ WC_NEWGRF_INSPECT = ::WC_NEWGRF_INSPECT, /** * Sprite aligner (debug); %Window numbers: * - 0 = #SpriteAlignerWidgets */ WC_SPRITE_ALIGNER = ::WC_SPRITE_ALIGNER, /** * Linkgraph legend; %Window numbers: * - 0 = #LinkGraphWidgets */ WC_LINKGRAPH_LEGEND = ::WC_LINKGRAPH_LEGEND, /** * Save preset; %Window numbers: * - 0 = #SavePresetWidgets */ WC_SAVE_PRESET = ::WC_SAVE_PRESET, WC_INVALID = ::WC_INVALID, ///< Invalid window. }; // @endenum /** * The colours in the game which you can use for text and highlights. */ enum TextColour { /* Note: these values represent part of the in-game TextColour enum */ TC_BLUE = ::TC_BLUE, ///< Blue colour. TC_SILVER = ::TC_SILVER, ///< Silver colour. TC_GOLD = ::TC_GOLD, ///< Gold colour. TC_RED = ::TC_RED, ///< Red colour. TC_PURPLE = ::TC_PURPLE, ///< Purple colour. TC_LIGHT_BROWN = ::TC_LIGHT_BROWN, ///< Light brown colour. TC_ORANGE = ::TC_ORANGE, ///< Orange colour. TC_GREEN = ::TC_GREEN, ///< Green colour. TC_YELLOW = ::TC_YELLOW, ///< Yellow colour. TC_DARK_GREEN = ::TC_DARK_GREEN, ///< Dark green colour. TC_CREAM = ::TC_CREAM, ///< Cream colour. TC_BROWN = ::TC_BROWN, ///< Brown colour. TC_WHITE = ::TC_WHITE, ///< White colour. TC_LIGHT_BLUE = ::TC_LIGHT_BLUE, ///< Light blue colour. TC_GREY = ::TC_GREY, ///< Grey colour. TC_DARK_BLUE = ::TC_DARK_BLUE, ///< Dark blue colour. TC_BLACK = ::TC_BLACK, ///< Black colour. TC_INVALID = ::TC_INVALID, ///< Invalid colour. }; /** * Special number values. */ enum NumberType { NUMBER_ALL = 0xFFFFFFFF, ///< Value to select all windows of a class. }; /** * Special widget values. */ enum WidgetType { WIDGET_ALL = 0xFF, ///< Value to select all widgets of a window. }; /** * Close a window. * @param window The class of the window to close. * @param number The number of the window to close, or NUMBER_ALL to close all of this class. * @pre !ScriptGame::IsMultiplayer(). */ static void Close(WindowClass window, uint32 number); /** * Check if a window is open. * @param window The class of the window to check for. * @param number The number of the window to check for, or NUMBER_ALL to check for any in the class. * @pre !ScriptGame::IsMultiplayer(). * @return True if the window is open. */ static bool IsOpen(WindowClass window, uint32 number); /** * Highlight a widget in a window. * @param window The class of the window to highlight a widget in. * @param number The number of the window to highlight a widget in. * @param widget The widget in the window to highlight, or WIDGET_ALL (in combination with TC_INVALID) to disable all widget highlighting on this window. * @param colour The colour of the highlight, or TC_INVALID for disabling. * @pre !ScriptGame::IsMultiplayer(). * @pre number != NUMBER_ALL. * @pre colour < TC_END || (widget == WIDGET_ALL && colour == TC_INVALID). * @pre IsOpen(window, number). */ static void Highlight(WindowClass window, uint32 number, uint8 widget, TextColour colour); // @enum .*Widgets ../../widgets/*_widget.h /* automatically generated from ../../widgets/ai_widget.h */ /** Widgets of the #AIListWindow class. */ enum AIListWidgets { WID_AIL_CAPTION = ::WID_AIL_CAPTION, ///< Caption of the window. WID_AIL_LIST = ::WID_AIL_LIST, ///< The matrix with all available AIs. WID_AIL_SCROLLBAR = ::WID_AIL_SCROLLBAR, ///< Scrollbar next to the AI list. WID_AIL_INFO_BG = ::WID_AIL_INFO_BG, ///< Panel to draw some AI information on. WID_AIL_ACCEPT = ::WID_AIL_ACCEPT, ///< Accept button. WID_AIL_CANCEL = ::WID_AIL_CANCEL, ///< Cancel button. }; /** Widgets of the #AISettingsWindow class. */ enum AISettingsWidgets { WID_AIS_CAPTION = ::WID_AIS_CAPTION, ///< Caption of the window. WID_AIS_BACKGROUND = ::WID_AIS_BACKGROUND, ///< Panel to draw the settings on. WID_AIS_SCROLLBAR = ::WID_AIS_SCROLLBAR, ///< Scrollbar to scroll through all settings. WID_AIS_ACCEPT = ::WID_AIS_ACCEPT, ///< Accept button. WID_AIS_RESET = ::WID_AIS_RESET, ///< Reset button. }; /** Widgets of the #AIConfigWindow class. */ enum AIConfigWidgets { WID_AIC_BACKGROUND = ::WID_AIC_BACKGROUND, ///< Window background. WID_AIC_DECREASE = ::WID_AIC_DECREASE, ///< Decrease the number of AIs. WID_AIC_INCREASE = ::WID_AIC_INCREASE, ///< Increase the number of AIs. WID_AIC_NUMBER = ::WID_AIC_NUMBER, ///< Number of AIs. WID_AIC_GAMELIST = ::WID_AIC_GAMELIST, ///< List with current selected GameScript. WID_AIC_LIST = ::WID_AIC_LIST, ///< List with currently selected AIs. WID_AIC_SCROLLBAR = ::WID_AIC_SCROLLBAR, ///< Scrollbar to scroll through the selected AIs. WID_AIC_MOVE_UP = ::WID_AIC_MOVE_UP, ///< Move up button. WID_AIC_MOVE_DOWN = ::WID_AIC_MOVE_DOWN, ///< Move down button. WID_AIC_CHANGE = ::WID_AIC_CHANGE, ///< Select another AI button. WID_AIC_CONFIGURE = ::WID_AIC_CONFIGURE, ///< Change AI settings button. WID_AIC_CLOSE = ::WID_AIC_CLOSE, ///< Close window button. WID_AIC_TEXTFILE = ::WID_AIC_TEXTFILE, ///< Open AI readme, changelog (+1) or license (+2). WID_AIC_CONTENT_DOWNLOAD = ::WID_AIC_CONTENT_DOWNLOAD, ///< Download content button. }; /** Widgets of the #AIDebugWindow class. */ enum AIDebugWidgets { WID_AID_VIEW = ::WID_AID_VIEW, ///< The row of company buttons. WID_AID_NAME_TEXT = ::WID_AID_NAME_TEXT, ///< Name of the current selected. WID_AID_SETTINGS = ::WID_AID_SETTINGS, ///< Settings button. WID_AID_SCRIPT_GAME = ::WID_AID_SCRIPT_GAME, ///< Game Script button. WID_AID_RELOAD_TOGGLE = ::WID_AID_RELOAD_TOGGLE, ///< Reload button. WID_AID_LOG_PANEL = ::WID_AID_LOG_PANEL, ///< Panel where the log is in. WID_AID_SCROLLBAR = ::WID_AID_SCROLLBAR, ///< Scrollbar of the log panel. WID_AID_COMPANY_BUTTON_START = ::WID_AID_COMPANY_BUTTON_START, ///< Buttons in the VIEW. WID_AID_COMPANY_BUTTON_END = ::WID_AID_COMPANY_BUTTON_END, ///< Last possible button in the VIEW. WID_AID_BREAK_STRING_WIDGETS = ::WID_AID_BREAK_STRING_WIDGETS, ///< The panel to handle the breaking on string. WID_AID_BREAK_STR_ON_OFF_BTN = ::WID_AID_BREAK_STR_ON_OFF_BTN, ///< Enable breaking on string. WID_AID_BREAK_STR_EDIT_BOX = ::WID_AID_BREAK_STR_EDIT_BOX, ///< Edit box for the string to break on. WID_AID_MATCH_CASE_BTN = ::WID_AID_MATCH_CASE_BTN, ///< Checkbox to use match caching or not. WID_AID_CONTINUE_BTN = ::WID_AID_CONTINUE_BTN, ///< Continue button. }; /* automatically generated from ../../widgets/airport_widget.h */ /** Widgets of the #BuildAirToolbarWindow class. */ enum AirportToolbarWidgets { WID_AT_AIRPORT = ::WID_AT_AIRPORT, ///< Build airport button. WID_AT_DEMOLISH = ::WID_AT_DEMOLISH, ///< Demolish button. }; /** Widgets of the #BuildAirportWindow class. */ enum AirportPickerWidgets { WID_AP_CLASS_DROPDOWN = ::WID_AP_CLASS_DROPDOWN, ///< Dropdown of airport classes. WID_AP_AIRPORT_LIST = ::WID_AP_AIRPORT_LIST, ///< List of airports. WID_AP_SCROLLBAR = ::WID_AP_SCROLLBAR, ///< Scrollbar of the list. WID_AP_LAYOUT_NUM = ::WID_AP_LAYOUT_NUM, ///< Current number of the layout. WID_AP_LAYOUT_DECREASE = ::WID_AP_LAYOUT_DECREASE, ///< Decrease the layout number. WID_AP_LAYOUT_INCREASE = ::WID_AP_LAYOUT_INCREASE, ///< Increase the layout number. WID_AP_AIRPORT_SPRITE = ::WID_AP_AIRPORT_SPRITE, ///< A visual display of the airport currently selected. WID_AP_EXTRA_TEXT = ::WID_AP_EXTRA_TEXT, ///< Additional text about the airport. WID_AP_BOTTOMPANEL = ::WID_AP_BOTTOMPANEL, ///< Panel at the bottom. WID_AP_COVERAGE_LABEL = ::WID_AP_COVERAGE_LABEL, ///< Label if you want to see the coverage. WID_AP_BTN_DONTHILIGHT = ::WID_AP_BTN_DONTHILIGHT, ///< Don't show the coverage button. WID_AP_BTN_DOHILIGHT = ::WID_AP_BTN_DOHILIGHT, ///< Show the coverage button. }; /* automatically generated from ../../widgets/autoreplace_widget.h */ /** Widgets of the #ReplaceVehicleWindow class. */ enum ReplaceVehicleWidgets { WID_RV_CAPTION = ::WID_RV_CAPTION, ///< Caption of the window. /* Sort dropdown at the right. */ WID_RV_SORT_ASCENDING_DESCENDING = ::WID_RV_SORT_ASCENDING_DESCENDING, ///< Ascending/descending sort order button. WID_RV_SHOW_HIDDEN_ENGINES = ::WID_RV_SHOW_HIDDEN_ENGINES, ///< Toggle whether to display the hidden vehicles. WID_RV_SORT_DROPDOWN = ::WID_RV_SORT_DROPDOWN, ///< Dropdown for the sort criteria. /* Left and right matrix + details. */ WID_RV_LEFT_MATRIX = ::WID_RV_LEFT_MATRIX, ///< The matrix on the left. WID_RV_LEFT_SCROLLBAR = ::WID_RV_LEFT_SCROLLBAR, ///< The scrollbar for the matrix on the left. WID_RV_RIGHT_MATRIX = ::WID_RV_RIGHT_MATRIX, ///< The matrix on the right. WID_RV_RIGHT_SCROLLBAR = ::WID_RV_RIGHT_SCROLLBAR, ///< The scrollbar for the matrix on the right. WID_RV_LEFT_DETAILS = ::WID_RV_LEFT_DETAILS, ///< Details of the entry on the left. WID_RV_RIGHT_DETAILS = ::WID_RV_RIGHT_DETAILS, ///< Details of the entry on the right. /* Button row. */ WID_RV_START_REPLACE = ::WID_RV_START_REPLACE, ///< Start Replacing button. WID_RV_INFO_TAB = ::WID_RV_INFO_TAB, ///< Info tab. WID_RV_STOP_REPLACE = ::WID_RV_STOP_REPLACE, ///< Stop Replacing button. /* Train only widgets. */ WID_RV_TRAIN_ENGINEWAGON_TOGGLE = ::WID_RV_TRAIN_ENGINEWAGON_TOGGLE, ///< Button to toggle engines and/or wagons. WID_RV_TRAIN_FLUFF_LEFT = ::WID_RV_TRAIN_FLUFF_LEFT, ///< The fluff on the left. WID_RV_TRAIN_RAILTYPE_DROPDOWN = ::WID_RV_TRAIN_RAILTYPE_DROPDOWN, ///< Dropdown menu about the railtype. WID_RV_TRAIN_FLUFF_RIGHT = ::WID_RV_TRAIN_FLUFF_RIGHT, ///< The fluff on the right. WID_RV_TRAIN_WAGONREMOVE_TOGGLE = ::WID_RV_TRAIN_WAGONREMOVE_TOGGLE, ///< Button to toggle removing wagons. }; /* automatically generated from ../../widgets/bootstrap_widget.h */ /** Widgets of the #BootstrapBackground class. */ enum BootstrapBackgroundWidgets { WID_BB_BACKGROUND = ::WID_BB_BACKGROUND, ///< Background of the window. }; /** Widgets of the #BootstrapContentDownloadStatusWindow class. */ enum BootstrapAskForDownloadWidgets { WID_BAFD_QUESTION = ::WID_BAFD_QUESTION, ///< The question whether to download. WID_BAFD_YES = ::WID_BAFD_YES, ///< An affirmative answer to the question. WID_BAFD_NO = ::WID_BAFD_NO, ///< An negative answer to the question. }; /* automatically generated from ../../widgets/bridge_widget.h */ /** Widgets of the #BuildBridgeWindow class. */ enum BuildBridgeSelectionWidgets { WID_BBS_CAPTION = ::WID_BBS_CAPTION, ///< Caption of the window. WID_BBS_DROPDOWN_ORDER = ::WID_BBS_DROPDOWN_ORDER, ///< Direction of sort dropdown. WID_BBS_DROPDOWN_CRITERIA = ::WID_BBS_DROPDOWN_CRITERIA, ///< Criteria of sort dropdown. WID_BBS_BRIDGE_LIST = ::WID_BBS_BRIDGE_LIST, ///< List of bridges. WID_BBS_SCROLLBAR = ::WID_BBS_SCROLLBAR, ///< Scrollbar of the list. }; /* automatically generated from ../../widgets/build_vehicle_widget.h */ /** Widgets of the #BuildVehicleWindow class. */ enum BuildVehicleWidgets { WID_BV_CAPTION = ::WID_BV_CAPTION, ///< Caption of window. WID_BV_SORT_ASCENDING_DESCENDING = ::WID_BV_SORT_ASCENDING_DESCENDING, ///< Sort direction. WID_BV_SORT_DROPDOWN = ::WID_BV_SORT_DROPDOWN, ///< Criteria of sorting dropdown. WID_BV_CARGO_FILTER_DROPDOWN = ::WID_BV_CARGO_FILTER_DROPDOWN, ///< Cargo filter dropdown. WID_BV_SHOW_HIDDEN_ENGINES = ::WID_BV_SHOW_HIDDEN_ENGINES, ///< Toggle whether to display the hidden vehicles. WID_BV_LIST = ::WID_BV_LIST, ///< List of vehicles. WID_BV_SCROLLBAR = ::WID_BV_SCROLLBAR, ///< Scrollbar of list. WID_BV_PANEL = ::WID_BV_PANEL, ///< Button panel. WID_BV_BUILD = ::WID_BV_BUILD, ///< Build panel. WID_BV_SHOW_HIDE = ::WID_BV_SHOW_HIDE, ///< Button to hide or show the selected engine. WID_BV_BUILD_SEL = ::WID_BV_BUILD_SEL, ///< Build button. WID_BV_RENAME = ::WID_BV_RENAME, ///< Rename button. }; /* automatically generated from ../../widgets/cheat_widget.h */ /** Widgets of the #CheatWindow class.. */ enum CheatWidgets { WID_C_PANEL = ::WID_C_PANEL, ///< Panel where all cheats are shown in. }; /* automatically generated from ../../widgets/company_widget.h */ /** Widgets of the #CompanyWindow class. */ enum CompanyWidgets { WID_C_CAPTION = ::WID_C_CAPTION, ///< Caption of the window. WID_C_FACE = ::WID_C_FACE, ///< View of the face. WID_C_FACE_TITLE = ::WID_C_FACE_TITLE, ///< Title for the face. WID_C_DESC_INAUGURATION = ::WID_C_DESC_INAUGURATION, ///< Inauguration. WID_C_DESC_COLOUR_SCHEME = ::WID_C_DESC_COLOUR_SCHEME, ///< Colour scheme. WID_C_DESC_COLOUR_SCHEME_EXAMPLE = ::WID_C_DESC_COLOUR_SCHEME_EXAMPLE, ///< Colour scheme example. WID_C_DESC_VEHICLE = ::WID_C_DESC_VEHICLE, ///< Vehicles. WID_C_DESC_VEHICLE_COUNTS = ::WID_C_DESC_VEHICLE_COUNTS, ///< Vehicle count. WID_C_DESC_COMPANY_VALUE = ::WID_C_DESC_COMPANY_VALUE, ///< Company value. WID_C_DESC_INFRASTRUCTURE = ::WID_C_DESC_INFRASTRUCTURE, ///< Infrastructure. WID_C_DESC_INFRASTRUCTURE_COUNTS = ::WID_C_DESC_INFRASTRUCTURE_COUNTS, ///< Infrastructure count. WID_C_SELECT_DESC_OWNERS = ::WID_C_SELECT_DESC_OWNERS, ///< Owners. WID_C_DESC_OWNERS = ::WID_C_DESC_OWNERS, ///< Owner in Owners. WID_C_SELECT_BUTTONS = ::WID_C_SELECT_BUTTONS, ///< Selection widget for the button bar. WID_C_NEW_FACE = ::WID_C_NEW_FACE, ///< Button to make new face. WID_C_COLOUR_SCHEME = ::WID_C_COLOUR_SCHEME, ///< Button to change colour scheme. WID_C_PRESIDENT_NAME = ::WID_C_PRESIDENT_NAME, ///< Button to change president name. WID_C_COMPANY_NAME = ::WID_C_COMPANY_NAME, ///< Button to change company name. WID_C_BUY_SHARE = ::WID_C_BUY_SHARE, ///< Button to buy a share. WID_C_SELL_SHARE = ::WID_C_SELL_SHARE, ///< Button to sell a share. WID_C_SELECT_VIEW_BUILD_HQ = ::WID_C_SELECT_VIEW_BUILD_HQ, ///< Panel about HQ. WID_C_VIEW_HQ = ::WID_C_VIEW_HQ, ///< Button to view the HQ. WID_C_BUILD_HQ = ::WID_C_BUILD_HQ, ///< Button to build the HQ. WID_C_SELECT_RELOCATE = ::WID_C_SELECT_RELOCATE, ///< Panel about 'Relocate HQ'. WID_C_RELOCATE_HQ = ::WID_C_RELOCATE_HQ, ///< Button to relocate the HQ. WID_C_VIEW_INFRASTRUCTURE = ::WID_C_VIEW_INFRASTRUCTURE, ///< Panel about infrastructure. WID_C_HAS_PASSWORD = ::WID_C_HAS_PASSWORD, ///< Has company password lock. WID_C_SELECT_MULTIPLAYER = ::WID_C_SELECT_MULTIPLAYER, ///< Multiplayer selection panel. WID_C_COMPANY_PASSWORD = ::WID_C_COMPANY_PASSWORD, ///< Button to set company password. WID_C_COMPANY_JOIN = ::WID_C_COMPANY_JOIN, ///< Button to join company. }; /** Widgets of the #CompanyFinancesWindow class. */ enum CompanyFinancesWidgets { WID_CF_CAPTION = ::WID_CF_CAPTION, ///< Caption of the window. WID_CF_TOGGLE_SIZE = ::WID_CF_TOGGLE_SIZE, ///< Toggle windows size. WID_CF_SEL_PANEL = ::WID_CF_SEL_PANEL, ///< Select panel or nothing. WID_CF_EXPS_CATEGORY = ::WID_CF_EXPS_CATEGORY, ///< Column for expenses category strings. WID_CF_EXPS_PRICE1 = ::WID_CF_EXPS_PRICE1, ///< Column for year Y-2 expenses. WID_CF_EXPS_PRICE2 = ::WID_CF_EXPS_PRICE2, ///< Column for year Y-1 expenses. WID_CF_EXPS_PRICE3 = ::WID_CF_EXPS_PRICE3, ///< Column for year Y expenses. WID_CF_TOTAL_PANEL = ::WID_CF_TOTAL_PANEL, ///< Panel for totals. WID_CF_SEL_MAXLOAN = ::WID_CF_SEL_MAXLOAN, ///< Selection of maxloan column. WID_CF_BALANCE_VALUE = ::WID_CF_BALANCE_VALUE, ///< Bank balance value. WID_CF_LOAN_VALUE = ::WID_CF_LOAN_VALUE, ///< Loan. WID_CF_LOAN_LINE = ::WID_CF_LOAN_LINE, ///< Line for summing bank balance and loan. WID_CF_TOTAL_VALUE = ::WID_CF_TOTAL_VALUE, ///< Total. WID_CF_MAXLOAN_GAP = ::WID_CF_MAXLOAN_GAP, ///< Gap above max loan widget. WID_CF_MAXLOAN_VALUE = ::WID_CF_MAXLOAN_VALUE, ///< Max loan widget. WID_CF_SEL_BUTTONS = ::WID_CF_SEL_BUTTONS, ///< Selection of buttons. WID_CF_INCREASE_LOAN = ::WID_CF_INCREASE_LOAN, ///< Increase loan. WID_CF_REPAY_LOAN = ::WID_CF_REPAY_LOAN, ///< Decrease loan.. WID_CF_INFRASTRUCTURE = ::WID_CF_INFRASTRUCTURE, ///< View company infrastructure. }; /** Widgets of the #SelectCompanyLiveryWindow class. */ enum SelectCompanyLiveryWidgets { WID_SCL_CAPTION = ::WID_SCL_CAPTION, ///< Caption of window. WID_SCL_CLASS_GENERAL = ::WID_SCL_CLASS_GENERAL, ///< Class general. WID_SCL_CLASS_RAIL = ::WID_SCL_CLASS_RAIL, ///< Class rail. WID_SCL_CLASS_ROAD = ::WID_SCL_CLASS_ROAD, ///< Class road. WID_SCL_CLASS_SHIP = ::WID_SCL_CLASS_SHIP, ///< Class ship. WID_SCL_CLASS_AIRCRAFT = ::WID_SCL_CLASS_AIRCRAFT, ///< Class aircraft. WID_SCL_SPACER_DROPDOWN = ::WID_SCL_SPACER_DROPDOWN, ///< Spacer for dropdown. WID_SCL_PRI_COL_DROPDOWN = ::WID_SCL_PRI_COL_DROPDOWN, ///< Dropdown for primary colour. WID_SCL_SEC_COL_DROPDOWN = ::WID_SCL_SEC_COL_DROPDOWN, ///< Dropdown for secondary colour. WID_SCL_MATRIX = ::WID_SCL_MATRIX, ///< Matrix. }; /** * Widgets of the #SelectCompanyManagerFaceWindow class. * Do not change the order of the widgets from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R, * this order is needed for the WE_CLICK event of DrawFaceStringLabel(). */ enum SelectCompanyManagerFaceWidgets { WID_SCMF_CAPTION = ::WID_SCMF_CAPTION, ///< Caption of window. WID_SCMF_TOGGLE_LARGE_SMALL = ::WID_SCMF_TOGGLE_LARGE_SMALL, ///< Toggle for large or small. WID_SCMF_SELECT_FACE = ::WID_SCMF_SELECT_FACE, ///< Select face. WID_SCMF_CANCEL = ::WID_SCMF_CANCEL, ///< Cancel. WID_SCMF_ACCEPT = ::WID_SCMF_ACCEPT, ///< Accept. WID_SCMF_MALE = ::WID_SCMF_MALE, ///< Male button in the simple view. WID_SCMF_FEMALE = ::WID_SCMF_FEMALE, ///< Female button in the simple view. WID_SCMF_MALE2 = ::WID_SCMF_MALE2, ///< Male button in the advanced view. WID_SCMF_FEMALE2 = ::WID_SCMF_FEMALE2, ///< Female button in the advanced view. WID_SCMF_SEL_LOADSAVE = ::WID_SCMF_SEL_LOADSAVE, ///< Selection to display the load/save/number buttons in the advanced view. WID_SCMF_SEL_MALEFEMALE = ::WID_SCMF_SEL_MALEFEMALE, ///< Selection to display the male/female buttons in the simple view. WID_SCMF_SEL_PARTS = ::WID_SCMF_SEL_PARTS, ///< Selection to display the buttons for setting each part of the face in the advanced view. WID_SCMF_RANDOM_NEW_FACE = ::WID_SCMF_RANDOM_NEW_FACE, ///< Create random new face. WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON = ::WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON, ///< Toggle for large or small. WID_SCMF_FACE = ::WID_SCMF_FACE, ///< Current face. WID_SCMF_LOAD = ::WID_SCMF_LOAD, ///< Load face. WID_SCMF_FACECODE = ::WID_SCMF_FACECODE, ///< Get the face code. WID_SCMF_SAVE = ::WID_SCMF_SAVE, ///< Save face. WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT = ::WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT, ///< Text about moustache and earring. WID_SCMF_TIE_EARRING_TEXT = ::WID_SCMF_TIE_EARRING_TEXT, ///< Text about tie and earring. WID_SCMF_LIPS_MOUSTACHE_TEXT = ::WID_SCMF_LIPS_MOUSTACHE_TEXT, ///< Text about lips and moustache. WID_SCMF_HAS_GLASSES_TEXT = ::WID_SCMF_HAS_GLASSES_TEXT, ///< Text about glasses. WID_SCMF_HAIR_TEXT = ::WID_SCMF_HAIR_TEXT, ///< Text about hair. WID_SCMF_EYEBROWS_TEXT = ::WID_SCMF_EYEBROWS_TEXT, ///< Text about eyebrows. WID_SCMF_EYECOLOUR_TEXT = ::WID_SCMF_EYECOLOUR_TEXT, ///< Text about eyecolour. WID_SCMF_GLASSES_TEXT = ::WID_SCMF_GLASSES_TEXT, ///< Text about glasses. WID_SCMF_NOSE_TEXT = ::WID_SCMF_NOSE_TEXT, ///< Text about nose. WID_SCMF_CHIN_TEXT = ::WID_SCMF_CHIN_TEXT, ///< Text about chin. WID_SCMF_JACKET_TEXT = ::WID_SCMF_JACKET_TEXT, ///< Text about jacket. WID_SCMF_COLLAR_TEXT = ::WID_SCMF_COLLAR_TEXT, ///< Text about collar. WID_SCMF_ETHNICITY_EUR = ::WID_SCMF_ETHNICITY_EUR, ///< Text about ethnicity european. WID_SCMF_ETHNICITY_AFR = ::WID_SCMF_ETHNICITY_AFR, ///< Text about ethnicity african. WID_SCMF_HAS_MOUSTACHE_EARRING = ::WID_SCMF_HAS_MOUSTACHE_EARRING, ///< Has moustache or earring. WID_SCMF_HAS_GLASSES = ::WID_SCMF_HAS_GLASSES, ///< Has glasses. WID_SCMF_EYECOLOUR_L = ::WID_SCMF_EYECOLOUR_L, ///< Eyecolour left. WID_SCMF_EYECOLOUR = ::WID_SCMF_EYECOLOUR, ///< Eyecolour. WID_SCMF_EYECOLOUR_R = ::WID_SCMF_EYECOLOUR_R, ///< Eyecolour right. WID_SCMF_CHIN_L = ::WID_SCMF_CHIN_L, ///< Chin left. WID_SCMF_CHIN = ::WID_SCMF_CHIN, ///< Chin. WID_SCMF_CHIN_R = ::WID_SCMF_CHIN_R, ///< Chin right. WID_SCMF_EYEBROWS_L = ::WID_SCMF_EYEBROWS_L, ///< Eyebrows left. WID_SCMF_EYEBROWS = ::WID_SCMF_EYEBROWS, ///< Eyebrows. WID_SCMF_EYEBROWS_R = ::WID_SCMF_EYEBROWS_R, ///< Eyebrows right. WID_SCMF_LIPS_MOUSTACHE_L = ::WID_SCMF_LIPS_MOUSTACHE_L, ///< Lips / Moustache left. WID_SCMF_LIPS_MOUSTACHE = ::WID_SCMF_LIPS_MOUSTACHE, ///< Lips / Moustache. WID_SCMF_LIPS_MOUSTACHE_R = ::WID_SCMF_LIPS_MOUSTACHE_R, ///< Lips / Moustache right. WID_SCMF_NOSE_L = ::WID_SCMF_NOSE_L, ///< Nose left. WID_SCMF_NOSE = ::WID_SCMF_NOSE, ///< Nose. WID_SCMF_NOSE_R = ::WID_SCMF_NOSE_R, ///< Nose right. WID_SCMF_HAIR_L = ::WID_SCMF_HAIR_L, ///< Hair left. WID_SCMF_HAIR = ::WID_SCMF_HAIR, ///< Hair. WID_SCMF_HAIR_R = ::WID_SCMF_HAIR_R, ///< Hair right. WID_SCMF_JACKET_L = ::WID_SCMF_JACKET_L, ///< Jacket left. WID_SCMF_JACKET = ::WID_SCMF_JACKET, ///< Jacket. WID_SCMF_JACKET_R = ::WID_SCMF_JACKET_R, ///< Jacket right. WID_SCMF_COLLAR_L = ::WID_SCMF_COLLAR_L, ///< Collar left. WID_SCMF_COLLAR = ::WID_SCMF_COLLAR, ///< Collar. WID_SCMF_COLLAR_R = ::WID_SCMF_COLLAR_R, ///< Collar right. WID_SCMF_TIE_EARRING_L = ::WID_SCMF_TIE_EARRING_L, ///< Tie / Earring left. WID_SCMF_TIE_EARRING = ::WID_SCMF_TIE_EARRING, ///< Tie / Earring. WID_SCMF_TIE_EARRING_R = ::WID_SCMF_TIE_EARRING_R, ///< Tie / Earring right. WID_SCMF_GLASSES_L = ::WID_SCMF_GLASSES_L, ///< Glasses left. WID_SCMF_GLASSES = ::WID_SCMF_GLASSES, ///< Glasses. WID_SCMF_GLASSES_R = ::WID_SCMF_GLASSES_R, ///< Glasses right. }; /** Widgets of the #CompanyInfrastructureWindow class. */ enum CompanyInfrastructureWidgets { WID_CI_CAPTION = ::WID_CI_CAPTION, ///< Caption of window. WID_CI_RAIL_DESC = ::WID_CI_RAIL_DESC, ///< Description of rail. WID_CI_RAIL_COUNT = ::WID_CI_RAIL_COUNT, ///< Count of rail. WID_CI_ROAD_DESC = ::WID_CI_ROAD_DESC, ///< Description of road. WID_CI_ROAD_COUNT = ::WID_CI_ROAD_COUNT, ///< Count of road. WID_CI_WATER_DESC = ::WID_CI_WATER_DESC, ///< Description of water. WID_CI_WATER_COUNT = ::WID_CI_WATER_COUNT, ///< Count of water. WID_CI_STATION_DESC = ::WID_CI_STATION_DESC, ///< Description of station. WID_CI_STATION_COUNT = ::WID_CI_STATION_COUNT, ///< Count of station. WID_CI_TOTAL_DESC = ::WID_CI_TOTAL_DESC, ///< Description of total. WID_CI_TOTAL = ::WID_CI_TOTAL, ///< Count of total. }; /** Widgets of the #BuyCompanyWindow class. */ enum BuyCompanyWidgets { WID_BC_CAPTION = ::WID_BC_CAPTION, ///< Caption of window. WID_BC_FACE = ::WID_BC_FACE, ///< Face button. WID_BC_QUESTION = ::WID_BC_QUESTION, ///< Question text. WID_BC_NO = ::WID_BC_NO, ///< No button. WID_BC_YES = ::WID_BC_YES, ///< Yes button. }; /* automatically generated from ../../widgets/console_widget.h */ /** Widgets of the #IConsoleWindow class. */ enum ConsoleWidgets { WID_C_BACKGROUND = ::WID_C_BACKGROUND, ///< Background of the console. }; /* automatically generated from ../../widgets/date_widget.h */ /** Widgets of the #SetDateWindow class. */ enum SetDateWidgets { WID_SD_DAY = ::WID_SD_DAY, ///< Dropdown for the day. WID_SD_MONTH = ::WID_SD_MONTH, ///< Dropdown for the month. WID_SD_YEAR = ::WID_SD_YEAR, ///< Dropdown for the year. WID_SD_SET_DATE = ::WID_SD_SET_DATE, ///< Actually set the date. }; /* automatically generated from ../../widgets/depot_widget.h */ /** Widgets of the #DepotWindow class. */ enum DepotWidgets { WID_D_CAPTION = ::WID_D_CAPTION, ///< Caption of window. WID_D_SELL = ::WID_D_SELL, ///< Sell button. WID_D_SHOW_SELL_CHAIN = ::WID_D_SHOW_SELL_CHAIN, ///< Show sell chain panel. WID_D_SELL_CHAIN = ::WID_D_SELL_CHAIN, ///< Sell chain button. WID_D_SELL_ALL = ::WID_D_SELL_ALL, ///< Sell all button. WID_D_AUTOREPLACE = ::WID_D_AUTOREPLACE, ///< Autoreplace button. WID_D_MATRIX = ::WID_D_MATRIX, ///< Matrix of vehicles. WID_D_V_SCROLL = ::WID_D_V_SCROLL, ///< Vertical scrollbar. WID_D_SHOW_H_SCROLL = ::WID_D_SHOW_H_SCROLL, ///< Show horizontal scrollbar panel. WID_D_H_SCROLL = ::WID_D_H_SCROLL, ///< Horizontal scrollbar. WID_D_BUILD = ::WID_D_BUILD, ///< Build button. WID_D_CLONE = ::WID_D_CLONE, ///< Clone button. WID_D_LOCATION = ::WID_D_LOCATION, ///< Location button. WID_D_SHOW_RENAME = ::WID_D_SHOW_RENAME, ///< Show rename panel. WID_D_RENAME = ::WID_D_RENAME, ///< Rename button. WID_D_VEHICLE_LIST = ::WID_D_VEHICLE_LIST, ///< List of vehicles. WID_D_STOP_ALL = ::WID_D_STOP_ALL, ///< Stop all button. WID_D_START_ALL = ::WID_D_START_ALL, ///< Start all button. }; /* automatically generated from ../../widgets/dock_widget.h */ /** Widgets of the #BuildDocksDepotWindow class. */ enum BuildDockDepotWidgets { WID_BDD_BACKGROUND = ::WID_BDD_BACKGROUND, ///< Background of the window. WID_BDD_X = ::WID_BDD_X, ///< X-direction button. WID_BDD_Y = ::WID_BDD_Y, ///< Y-direction button. }; /** Widgets of the #BuildDocksToolbarWindow class. */ enum DockToolbarWidgets { WID_DT_CANAL = ::WID_DT_CANAL, ///< Build canal button. WID_DT_LOCK = ::WID_DT_LOCK, ///< Build lock button. WID_DT_DEMOLISH = ::WID_DT_DEMOLISH, ///< Demolish aka dynamite button. WID_DT_DEPOT = ::WID_DT_DEPOT, ///< Build depot button. WID_DT_STATION = ::WID_DT_STATION, ///< Build station button. WID_DT_BUOY = ::WID_DT_BUOY, ///< Build buoy button. WID_DT_RIVER = ::WID_DT_RIVER, ///< Build river button (in scenario editor). WID_DT_BUILD_AQUEDUCT = ::WID_DT_BUILD_AQUEDUCT, ///< Build aqueduct button. WID_DT_INVALID = ::WID_DT_INVALID, ///< Used to initialize a variable. }; /* automatically generated from ../../widgets/dropdown_widget.h */ /** Widgets of the #DropdownWindow class. */ enum DropdownMenuWidgets { WID_DM_ITEMS = ::WID_DM_ITEMS, ///< Panel showing the dropdown items. WID_DM_SHOW_SCROLL = ::WID_DM_SHOW_SCROLL, ///< Hide scrollbar if too few items. WID_DM_SCROLL = ::WID_DM_SCROLL, ///< Scrollbar. }; /* automatically generated from ../../widgets/engine_widget.h */ /** Widgets of the #EnginePreviewWindow class. */ enum EnginePreviewWidgets { WID_EP_QUESTION = ::WID_EP_QUESTION, ///< The container for the question. WID_EP_NO = ::WID_EP_NO, ///< No button. WID_EP_YES = ::WID_EP_YES, ///< Yes button. }; /* automatically generated from ../../widgets/error_widget.h */ /** Widgets of the #ErrmsgWindow class. */ enum ErrorMessageWidgets { WID_EM_CAPTION = ::WID_EM_CAPTION, ///< Caption of the window. WID_EM_FACE = ::WID_EM_FACE, ///< Error title. WID_EM_MESSAGE = ::WID_EM_MESSAGE, ///< Error message. }; /* automatically generated from ../../widgets/fios_widget.h */ /** Widgets of the #SaveLoadWindow class. */ enum SaveLoadWidgets { WID_SL_CAPTION = ::WID_SL_CAPTION, ///< Caption of the window. WID_SL_SORT_BYNAME = ::WID_SL_SORT_BYNAME, ///< Sort by name button. WID_SL_SORT_BYDATE = ::WID_SL_SORT_BYDATE, ///< Sort by date button. WID_SL_BACKGROUND = ::WID_SL_BACKGROUND, ///< Background of window. WID_SL_FILE_BACKGROUND = ::WID_SL_FILE_BACKGROUND, ///< Background of file selection. WID_SL_HOME_BUTTON = ::WID_SL_HOME_BUTTON, ///< Home button. WID_SL_DRIVES_DIRECTORIES_LIST = ::WID_SL_DRIVES_DIRECTORIES_LIST, ///< Drives list. WID_SL_SCROLLBAR = ::WID_SL_SCROLLBAR, ///< Scrollbar of the file list. WID_SL_CONTENT_DOWNLOAD = ::WID_SL_CONTENT_DOWNLOAD, ///< Content download button, only available for play scenario/heightmap. WID_SL_SAVE_OSK_TITLE = ::WID_SL_SAVE_OSK_TITLE, ///< Title textbox, only available for save operations. WID_SL_DELETE_SELECTION = ::WID_SL_DELETE_SELECTION, ///< Delete button, only available for save operations. WID_SL_SAVE_GAME = ::WID_SL_SAVE_GAME, ///< Save button, only available for save operations. WID_SL_CONTENT_DOWNLOAD_SEL = ::WID_SL_CONTENT_DOWNLOAD_SEL, ///< Selection 'stack' to 'hide' the content download. WID_SL_DETAILS = ::WID_SL_DETAILS, ///< Panel with game details. WID_SL_NEWGRF_INFO = ::WID_SL_NEWGRF_INFO, ///< Button to open NewGgrf configuration. WID_SL_LOAD_BUTTON = ::WID_SL_LOAD_BUTTON, ///< Button to load game/scenario. WID_SL_MISSING_NEWGRFS = ::WID_SL_MISSING_NEWGRFS, ///< Button to find missing NewGRFs online. }; /* automatically generated from ../../widgets/genworld_widget.h */ /** Widgets of the #GenerateLandscapeWindow class. */ enum GenerateLandscapeWidgets { WID_GL_TEMPERATE = ::WID_GL_TEMPERATE, ///< Button with icon "Temperate". WID_GL_ARCTIC = ::WID_GL_ARCTIC, ///< Button with icon "Arctic". WID_GL_TROPICAL = ::WID_GL_TROPICAL, ///< Button with icon "Tropical". WID_GL_TOYLAND = ::WID_GL_TOYLAND, ///< Button with icon "Toyland". WID_GL_MAPSIZE_X_PULLDOWN = ::WID_GL_MAPSIZE_X_PULLDOWN, ///< Dropdown 'map X size'. WID_GL_MAPSIZE_Y_PULLDOWN = ::WID_GL_MAPSIZE_Y_PULLDOWN, ///< Dropdown 'map Y size'. WID_GL_TOWN_PULLDOWN = ::WID_GL_TOWN_PULLDOWN, ///< Dropdown 'No. of towns'. WID_GL_INDUSTRY_PULLDOWN = ::WID_GL_INDUSTRY_PULLDOWN, ///< Dropdown 'No. of industries'. WID_GL_GENERATE_BUTTON = ::WID_GL_GENERATE_BUTTON, ///< 'Generate' button. WID_GL_MAX_HEIGHTLEVEL_DOWN = ::WID_GL_MAX_HEIGHTLEVEL_DOWN, ///< Decrease max. heightlevel WID_GL_MAX_HEIGHTLEVEL_TEXT = ::WID_GL_MAX_HEIGHTLEVEL_TEXT, ///< Max. heightlevel WID_GL_MAX_HEIGHTLEVEL_UP = ::WID_GL_MAX_HEIGHTLEVEL_UP, ///< Increase max. heightlevel WID_GL_START_DATE_DOWN = ::WID_GL_START_DATE_DOWN, ///< Decrease start year. WID_GL_START_DATE_TEXT = ::WID_GL_START_DATE_TEXT, ///< Start year. WID_GL_START_DATE_UP = ::WID_GL_START_DATE_UP, ///< Increase start year. WID_GL_SNOW_LEVEL_DOWN = ::WID_GL_SNOW_LEVEL_DOWN, ///< Decrease snow level. WID_GL_SNOW_LEVEL_TEXT = ::WID_GL_SNOW_LEVEL_TEXT, ///< Snow level. WID_GL_SNOW_LEVEL_UP = ::WID_GL_SNOW_LEVEL_UP, ///< Increase snow level. WID_GL_TREE_PULLDOWN = ::WID_GL_TREE_PULLDOWN, ///< Dropdown 'Tree algorithm'. WID_GL_LANDSCAPE_PULLDOWN = ::WID_GL_LANDSCAPE_PULLDOWN, ///< Dropdown 'Land generator'. WID_GL_HEIGHTMAP_NAME_TEXT = ::WID_GL_HEIGHTMAP_NAME_TEXT, ///< Heightmap name. WID_GL_HEIGHTMAP_SIZE_TEXT = ::WID_GL_HEIGHTMAP_SIZE_TEXT, ///< Size of heightmap. WID_GL_HEIGHTMAP_ROTATION_PULLDOWN = ::WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, ///< Dropdown 'Heightmap rotation'. WID_GL_TERRAIN_PULLDOWN = ::WID_GL_TERRAIN_PULLDOWN, ///< Dropdown 'Terrain type'. WID_GL_WATER_PULLDOWN = ::WID_GL_WATER_PULLDOWN, ///< Dropdown 'Sea level'. WID_GL_RIVER_PULLDOWN = ::WID_GL_RIVER_PULLDOWN, ///< Dropdown 'Rivers'. WID_GL_SMOOTHNESS_PULLDOWN = ::WID_GL_SMOOTHNESS_PULLDOWN, ///< Dropdown 'Smoothness'. WID_GL_VARIETY_PULLDOWN = ::WID_GL_VARIETY_PULLDOWN, ///< Dropdown 'Variety distribution'. WID_GL_BORDERS_RANDOM = ::WID_GL_BORDERS_RANDOM, ///< 'Random'/'Manual' borders. WID_GL_WATER_NW = ::WID_GL_WATER_NW, ///< NW 'Water'/'Freeform'. WID_GL_WATER_NE = ::WID_GL_WATER_NE, ///< NE 'Water'/'Freeform'. WID_GL_WATER_SE = ::WID_GL_WATER_SE, ///< SE 'Water'/'Freeform'. WID_GL_WATER_SW = ::WID_GL_WATER_SW, ///< SW 'Water'/'Freeform'. }; /** Widgets of the #CreateScenarioWindow class. */ enum CreateScenarioWidgets { WID_CS_TEMPERATE = ::WID_CS_TEMPERATE, ///< Select temperate landscape style. WID_CS_ARCTIC = ::WID_CS_ARCTIC, ///< Select arctic landscape style. WID_CS_TROPICAL = ::WID_CS_TROPICAL, ///< Select tropical landscape style. WID_CS_TOYLAND = ::WID_CS_TOYLAND, ///< Select toy-land landscape style. WID_CS_EMPTY_WORLD = ::WID_CS_EMPTY_WORLD, ///< Generate an empty flat world. WID_CS_RANDOM_WORLD = ::WID_CS_RANDOM_WORLD, ///< Generate random land button WID_CS_MAPSIZE_X_PULLDOWN = ::WID_CS_MAPSIZE_X_PULLDOWN, ///< Pull-down arrow for x map size. WID_CS_MAPSIZE_Y_PULLDOWN = ::WID_CS_MAPSIZE_Y_PULLDOWN, ///< Pull-down arrow for y map size. WID_CS_START_DATE_DOWN = ::WID_CS_START_DATE_DOWN, ///< Decrease start year (start earlier). WID_CS_START_DATE_TEXT = ::WID_CS_START_DATE_TEXT, ///< Clickable start date value. WID_CS_START_DATE_UP = ::WID_CS_START_DATE_UP, ///< Increase start year (start later). WID_CS_FLAT_LAND_HEIGHT_DOWN = ::WID_CS_FLAT_LAND_HEIGHT_DOWN, ///< Decrease flat land height. WID_CS_FLAT_LAND_HEIGHT_TEXT = ::WID_CS_FLAT_LAND_HEIGHT_TEXT, ///< Clickable flat land height value. WID_CS_FLAT_LAND_HEIGHT_UP = ::WID_CS_FLAT_LAND_HEIGHT_UP, ///< Increase flat land height. }; /** Widgets of the #GenerateProgressWindow class. */ enum GenerationProgressWidgets { WID_GP_PROGRESS_BAR = ::WID_GP_PROGRESS_BAR, ///< Progress bar. WID_GP_PROGRESS_TEXT = ::WID_GP_PROGRESS_TEXT, ///< Text with the progress bar. WID_GP_ABORT = ::WID_GP_ABORT, ///< Abort button. }; /* automatically generated from ../../widgets/goal_widget.h */ /** Widgets of the #GoalListWindow class. */ enum GoalListWidgets { WID_GOAL_CAPTION = ::WID_GOAL_CAPTION, ///< Caption of the window. WID_GOAL_LIST = ::WID_GOAL_LIST, ///< Goal list. WID_GOAL_SCROLLBAR = ::WID_GOAL_SCROLLBAR, ///< Scrollbar of the goal list. }; /** Widgets of the #GoalQuestionWindow class. */ enum GoalQuestionWidgets { WID_GQ_CAPTION = ::WID_GQ_CAPTION, ///< Caption of the window. WID_GQ_QUESTION = ::WID_GQ_QUESTION, ///< Question text. WID_GQ_BUTTONS = ::WID_GQ_BUTTONS, ///< Buttons selection (between 1, 2 or 3). WID_GQ_BUTTON_1 = ::WID_GQ_BUTTON_1, ///< First button. WID_GQ_BUTTON_2 = ::WID_GQ_BUTTON_2, ///< Second button. WID_GQ_BUTTON_3 = ::WID_GQ_BUTTON_3, ///< Third button. }; /* automatically generated from ../../widgets/graph_widget.h */ /** Widgets of the #GraphLegendWindow class. */ enum GraphLegendWidgets { WID_GL_BACKGROUND = ::WID_GL_BACKGROUND, ///< Background of the window. WID_GL_FIRST_COMPANY = ::WID_GL_FIRST_COMPANY, ///< First company in the legend. WID_GL_LAST_COMPANY = ::WID_GL_LAST_COMPANY, ///< Last company in the legend. }; /** Widgets of the #OperatingProfitGraphWindow class, #IncomeGraphWindow class, #DeliveredCargoGraphWindow class, and #CompanyValueGraphWindow class. */ enum CompanyValueWidgets { WID_CV_KEY_BUTTON = ::WID_CV_KEY_BUTTON, ///< Key button. WID_CV_BACKGROUND = ::WID_CV_BACKGROUND, ///< Background of the window. WID_CV_GRAPH = ::WID_CV_GRAPH, ///< Graph itself. WID_CV_RESIZE = ::WID_CV_RESIZE, ///< Resize button. }; /** Widget of the #PerformanceHistoryGraphWindow class. */ enum PerformanceHistoryGraphWidgets { WID_PHG_KEY = ::WID_PHG_KEY, ///< Key button. WID_PHG_DETAILED_PERFORMANCE = ::WID_PHG_DETAILED_PERFORMANCE, ///< Detailed performance. WID_PHG_BACKGROUND = ::WID_PHG_BACKGROUND, ///< Background of the window. WID_PHG_GRAPH = ::WID_PHG_GRAPH, ///< Graph itself. WID_PHG_RESIZE = ::WID_PHG_RESIZE, ///< Resize button. }; /** Widget of the #PaymentRatesGraphWindow class. */ enum CargoPaymentRatesWidgets { WID_CPR_BACKGROUND = ::WID_CPR_BACKGROUND, ///< Background of the window. WID_CPR_HEADER = ::WID_CPR_HEADER, ///< Header. WID_CPR_GRAPH = ::WID_CPR_GRAPH, ///< Graph itself. WID_CPR_RESIZE = ::WID_CPR_RESIZE, ///< Resize button. WID_CPR_FOOTER = ::WID_CPR_FOOTER, ///< Footer. WID_CPR_ENABLE_CARGOES = ::WID_CPR_ENABLE_CARGOES, ///< Enable cargoes button. WID_CPR_DISABLE_CARGOES = ::WID_CPR_DISABLE_CARGOES, ///< Disable cargoes button. WID_CPR_CARGO_FIRST = ::WID_CPR_CARGO_FIRST, ///< First cargo in the list. }; /** Widget of the #CompanyLeagueWindow class. */ enum CompanyLeagueWidgets { WID_CL_BACKGROUND = ::WID_CL_BACKGROUND, ///< Background of the window. }; /** Widget of the #PerformanceRatingDetailWindow class. */ enum PerformanceRatingDetailsWidgets { WID_PRD_SCORE_FIRST = ::WID_PRD_SCORE_FIRST, ///< First entry in the score list. WID_PRD_SCORE_LAST = ::WID_PRD_SCORE_LAST, ///< Last entry in the score list. WID_PRD_COMPANY_FIRST = ::WID_PRD_COMPANY_FIRST, ///< First company. WID_PRD_COMPANY_LAST = ::WID_PRD_COMPANY_LAST, ///< Last company. }; /* automatically generated from ../../widgets/group_widget.h */ /** Widgets of the #VehicleGroupWindow class. */ enum GroupListWidgets { WID_GL_CAPTION = ::WID_GL_CAPTION, ///< Caption of the window. WID_GL_SORT_BY_ORDER = ::WID_GL_SORT_BY_ORDER, ///< Sort order. WID_GL_SORT_BY_DROPDOWN = ::WID_GL_SORT_BY_DROPDOWN, ///< Sort by dropdown list. WID_GL_LIST_VEHICLE = ::WID_GL_LIST_VEHICLE, ///< List of the vehicles. WID_GL_LIST_VEHICLE_SCROLLBAR = ::WID_GL_LIST_VEHICLE_SCROLLBAR, ///< Scrollbar for the list. WID_GL_AVAILABLE_VEHICLES = ::WID_GL_AVAILABLE_VEHICLES, ///< Available vehicles. WID_GL_MANAGE_VEHICLES_DROPDOWN = ::WID_GL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. WID_GL_STOP_ALL = ::WID_GL_STOP_ALL, ///< Stop all button. WID_GL_START_ALL = ::WID_GL_START_ALL, ///< Start all button. WID_GL_ALL_VEHICLES = ::WID_GL_ALL_VEHICLES, ///< All vehicles entry. WID_GL_DEFAULT_VEHICLES = ::WID_GL_DEFAULT_VEHICLES, ///< Default vehicles entry. WID_GL_LIST_GROUP = ::WID_GL_LIST_GROUP, ///< List of the groups. WID_GL_LIST_GROUP_SCROLLBAR = ::WID_GL_LIST_GROUP_SCROLLBAR, ///< Scrollbar for the list. WID_GL_CREATE_GROUP = ::WID_GL_CREATE_GROUP, ///< Create group button. WID_GL_DELETE_GROUP = ::WID_GL_DELETE_GROUP, ///< Delete group button. WID_GL_RENAME_GROUP = ::WID_GL_RENAME_GROUP, ///< Rename group button. WID_GL_REPLACE_PROTECTION = ::WID_GL_REPLACE_PROTECTION, ///< Replace protection button. }; /* automatically generated from ../../widgets/highscore_widget.h */ /** Widgets of the #EndGameHighScoreBaseWindow class and #HighScoreWindow class. */ enum HighscoreWidgets { WID_H_BACKGROUND = ::WID_H_BACKGROUND, ///< Background of the window. }; /* automatically generated from ../../widgets/industry_widget.h */ /** Widgets of the #BuildIndustryWindow class. */ enum DynamicPlaceIndustriesWidgets { WID_DPI_MATRIX_WIDGET = ::WID_DPI_MATRIX_WIDGET, ///< Matrix of the industries. WID_DPI_SCROLLBAR = ::WID_DPI_SCROLLBAR, ///< Scrollbar of the matrix. WID_DPI_INFOPANEL = ::WID_DPI_INFOPANEL, ///< Info panel about the industry. WID_DPI_DISPLAY_WIDGET = ::WID_DPI_DISPLAY_WIDGET, ///< Display chain button. WID_DPI_FUND_WIDGET = ::WID_DPI_FUND_WIDGET, ///< Fund button. }; /** Widgets of the #IndustryViewWindow class. */ enum IndustryViewWidgets { WID_IV_CAPTION = ::WID_IV_CAPTION, ///< Caption of the window. WID_IV_VIEWPORT = ::WID_IV_VIEWPORT, ///< Viewport of the industry. WID_IV_INFO = ::WID_IV_INFO, ///< Info of the industry. WID_IV_GOTO = ::WID_IV_GOTO, ///< Goto button. WID_IV_DISPLAY = ::WID_IV_DISPLAY, ///< Display chain button. }; /** Widgets of the #IndustryDirectoryWindow class. */ enum IndustryDirectoryWidgets { WID_ID_DROPDOWN_ORDER = ::WID_ID_DROPDOWN_ORDER, ///< Dropdown for the order of the sort. WID_ID_DROPDOWN_CRITERIA = ::WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort. WID_ID_INDUSTRY_LIST = ::WID_ID_INDUSTRY_LIST, ///< Industry list. WID_ID_SCROLLBAR = ::WID_ID_SCROLLBAR, ///< Scrollbar of the list. }; /** Widgets of the #IndustryCargoesWindow class */ enum IndustryCargoesWidgets { WID_IC_CAPTION = ::WID_IC_CAPTION, ///< Caption of the window. WID_IC_NOTIFY = ::WID_IC_NOTIFY, ///< Row of buttons at the bottom. WID_IC_PANEL = ::WID_IC_PANEL, ///< Panel that shows the chain. WID_IC_SCROLLBAR = ::WID_IC_SCROLLBAR, ///< Scrollbar of the panel. WID_IC_CARGO_DROPDOWN = ::WID_IC_CARGO_DROPDOWN, ///< Select cargo dropdown. WID_IC_IND_DROPDOWN = ::WID_IC_IND_DROPDOWN, ///< Select industry dropdown. }; /* automatically generated from ../../widgets/intro_widget.h */ /** Widgets of the #SelectGameWindow class. */ enum SelectGameIntroWidgets { WID_SGI_GENERATE_GAME = ::WID_SGI_GENERATE_GAME, ///< Generate game button. WID_SGI_LOAD_GAME = ::WID_SGI_LOAD_GAME, ///< Load game button. WID_SGI_PLAY_SCENARIO = ::WID_SGI_PLAY_SCENARIO, ///< Play scenario button. WID_SGI_PLAY_HEIGHTMAP = ::WID_SGI_PLAY_HEIGHTMAP, ///< Play heightmap button. WID_SGI_EDIT_SCENARIO = ::WID_SGI_EDIT_SCENARIO, ///< Edit scenario button. WID_SGI_PLAY_NETWORK = ::WID_SGI_PLAY_NETWORK, ///< Play network button. WID_SGI_TEMPERATE_LANDSCAPE = ::WID_SGI_TEMPERATE_LANDSCAPE, ///< Select temperate landscape button. WID_SGI_ARCTIC_LANDSCAPE = ::WID_SGI_ARCTIC_LANDSCAPE, ///< Select arctic landscape button. WID_SGI_TROPIC_LANDSCAPE = ::WID_SGI_TROPIC_LANDSCAPE, ///< Select tropic landscape button. WID_SGI_TOYLAND_LANDSCAPE = ::WID_SGI_TOYLAND_LANDSCAPE, ///< Select toyland landscape button. WID_SGI_TRANSLATION_SELECTION = ::WID_SGI_TRANSLATION_SELECTION, ///< Translation selection. WID_SGI_TRANSLATION = ::WID_SGI_TRANSLATION, ///< Translation. WID_SGI_OPTIONS = ::WID_SGI_OPTIONS, ///< Options button. WID_SGI_HIGHSCORE = ::WID_SGI_HIGHSCORE, ///< Highscore button. WID_SGI_SETTINGS_OPTIONS = ::WID_SGI_SETTINGS_OPTIONS, ///< Settings button. WID_SGI_GRF_SETTINGS = ::WID_SGI_GRF_SETTINGS, ///< NewGRF button. WID_SGI_CONTENT_DOWNLOAD = ::WID_SGI_CONTENT_DOWNLOAD, ///< Content Download button. WID_SGI_AI_SETTINGS = ::WID_SGI_AI_SETTINGS, ///< AI button. WID_SGI_EXIT = ::WID_SGI_EXIT, ///< Exit button. }; /* automatically generated from ../../widgets/link_graph_legend_widget.h */ /** Widgets of the WC_LINKGRAPH_LEGEND. */ enum LinkGraphLegendWidgets { WID_LGL_CAPTION = ::WID_LGL_CAPTION, ///< Caption widget. WID_LGL_SATURATION = ::WID_LGL_SATURATION, ///< Saturation legend. WID_LGL_SATURATION_FIRST = ::WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST = ::WID_LGL_SATURATION_LAST, WID_LGL_COMPANIES = ::WID_LGL_COMPANIES, ///< Company selection widget. WID_LGL_COMPANY_FIRST = ::WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST = ::WID_LGL_COMPANY_LAST, WID_LGL_COMPANIES_ALL = ::WID_LGL_COMPANIES_ALL, WID_LGL_COMPANIES_NONE = ::WID_LGL_COMPANIES_NONE, WID_LGL_CARGOES = ::WID_LGL_CARGOES, ///< Cargo selection widget. WID_LGL_CARGO_FIRST = ::WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST = ::WID_LGL_CARGO_LAST, WID_LGL_CARGOES_ALL = ::WID_LGL_CARGOES_ALL, WID_LGL_CARGOES_NONE = ::WID_LGL_CARGOES_NONE, }; /* automatically generated from ../../widgets/main_widget.h */ /** Widgets of the #MainWindow class. */ enum MainWidgets { WID_M_VIEWPORT = ::WID_M_VIEWPORT, ///< Main window viewport. }; /* automatically generated from ../../widgets/misc_widget.h */ /** Widgets of the #LandInfoWindow class. */ enum LandInfoWidgets { WID_LI_BACKGROUND = ::WID_LI_BACKGROUND, ///< Background of the window. }; /** Widgets of the #TooltipsWindow class. */ enum ToolTipsWidgets { WID_TT_BACKGROUND = ::WID_TT_BACKGROUND, ///< Background of the window. }; /** Widgets of the #AboutWindow class. */ enum AboutWidgets { WID_A_SCROLLING_TEXT = ::WID_A_SCROLLING_TEXT, ///< The actually scrolling text. WID_A_WEBSITE = ::WID_A_WEBSITE, ///< URL of OpenTTD website. }; /** Widgets of the #QueryStringWindow class. */ enum QueryStringWidgets { WID_QS_CAPTION = ::WID_QS_CAPTION, ///< Caption of the window. WID_QS_TEXT = ::WID_QS_TEXT, ///< Text of the query. WID_QS_DEFAULT = ::WID_QS_DEFAULT, ///< Default button. WID_QS_CANCEL = ::WID_QS_CANCEL, ///< Cancel button. WID_QS_OK = ::WID_QS_OK, ///< OK button. }; /** Widgets of the #QueryWindow class. */ enum QueryWidgets { WID_Q_CAPTION = ::WID_Q_CAPTION, ///< Caption of the window. WID_Q_TEXT = ::WID_Q_TEXT, ///< Text of the query. WID_Q_NO = ::WID_Q_NO, ///< Yes button. WID_Q_YES = ::WID_Q_YES, ///< No button. }; /** Widgets of the #TextfileWindow class. */ enum TextfileWidgets { WID_TF_CAPTION = ::WID_TF_CAPTION, ///< The caption of the window. WID_TF_WRAPTEXT = ::WID_TF_WRAPTEXT, ///< Whether or not to wrap the text. WID_TF_BACKGROUND = ::WID_TF_BACKGROUND, ///< Panel to draw the textfile on. WID_TF_VSCROLLBAR = ::WID_TF_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. WID_TF_HSCROLLBAR = ::WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. }; /* automatically generated from ../../widgets/music_widget.h */ /** Widgets of the #MusicTrackSelectionWindow class. */ enum MusicTrackSelectionWidgets { WID_MTS_LIST_LEFT = ::WID_MTS_LIST_LEFT, ///< Left button. WID_MTS_PLAYLIST = ::WID_MTS_PLAYLIST, ///< Playlist. WID_MTS_LIST_RIGHT = ::WID_MTS_LIST_RIGHT, ///< Right button. WID_MTS_ALL = ::WID_MTS_ALL, ///< All button. WID_MTS_OLD = ::WID_MTS_OLD, ///< Old button. WID_MTS_NEW = ::WID_MTS_NEW, ///< New button. WID_MTS_EZY = ::WID_MTS_EZY, ///< Ezy button. WID_MTS_CUSTOM1 = ::WID_MTS_CUSTOM1, ///< Custom1 button. WID_MTS_CUSTOM2 = ::WID_MTS_CUSTOM2, ///< Custom2 button. WID_MTS_CLEAR = ::WID_MTS_CLEAR, ///< Clear button. }; /** Widgets of the #MusicWindow class. */ enum MusicWidgets { WID_M_PREV = ::WID_M_PREV, ///< Previous button. WID_M_NEXT = ::WID_M_NEXT, ///< Next button. WID_M_STOP = ::WID_M_STOP, ///< Stop button. WID_M_PLAY = ::WID_M_PLAY, ///< Play button. WID_M_SLIDERS = ::WID_M_SLIDERS, ///< Sliders. WID_M_MUSIC_VOL = ::WID_M_MUSIC_VOL, ///< Music volume. WID_M_EFFECT_VOL = ::WID_M_EFFECT_VOL, ///< Effect volume. WID_M_BACKGROUND = ::WID_M_BACKGROUND, ///< Background of the window. WID_M_TRACK = ::WID_M_TRACK, ///< Track playing. WID_M_TRACK_NR = ::WID_M_TRACK_NR, ///< Track number. WID_M_TRACK_TITLE = ::WID_M_TRACK_TITLE, ///< Track title. WID_M_TRACK_NAME = ::WID_M_TRACK_NAME, ///< Track name. WID_M_SHUFFLE = ::WID_M_SHUFFLE, ///< Shuffle button. WID_M_PROGRAMME = ::WID_M_PROGRAMME, ///< Program button. WID_M_ALL = ::WID_M_ALL, ///< All button. WID_M_OLD = ::WID_M_OLD, ///< Old button. WID_M_NEW = ::WID_M_NEW, ///< New button. WID_M_EZY = ::WID_M_EZY, ///< Ezy button. WID_M_CUSTOM1 = ::WID_M_CUSTOM1, ///< Custom1 button. WID_M_CUSTOM2 = ::WID_M_CUSTOM2, ///< Custom2 button. }; /* automatically generated from ../../widgets/network_chat_widget.h */ /** Widgets of the #NetworkChatWindow class. */ enum NetWorkChatWidgets { WID_NC_CLOSE = ::WID_NC_CLOSE, ///< Close button. WID_NC_BACKGROUND = ::WID_NC_BACKGROUND, ///< Background of the window. WID_NC_DESTINATION = ::WID_NC_DESTINATION, ///< Destination. WID_NC_TEXTBOX = ::WID_NC_TEXTBOX, ///< Textbox. WID_NC_SENDBUTTON = ::WID_NC_SENDBUTTON, ///< Send button. }; /* automatically generated from ../../widgets/network_content_widget.h */ /** Widgets of the #NetworkContentDownloadStatusWindow class. */ enum NetworkContentDownloadStatusWidgets { WID_NCDS_BACKGROUND = ::WID_NCDS_BACKGROUND, ///< Background of the window. WID_NCDS_CANCELOK = ::WID_NCDS_CANCELOK, ///< (Optional) Cancel/OK button. }; /** Widgets of the #NetworkContentListWindow class. */ enum NetworkContentListWidgets { WID_NCL_BACKGROUND = ::WID_NCL_BACKGROUND, ///< Resize button. WID_NCL_FILTER_CAPT = ::WID_NCL_FILTER_CAPT, ///< Caption for the filter editbox. WID_NCL_FILTER = ::WID_NCL_FILTER, ///< Filter editbox. WID_NCL_CHECKBOX = ::WID_NCL_CHECKBOX, ///< Button above checkboxes. WID_NCL_TYPE = ::WID_NCL_TYPE, ///< 'Type' button. WID_NCL_NAME = ::WID_NCL_NAME, ///< 'Name' button. WID_NCL_MATRIX = ::WID_NCL_MATRIX, ///< Panel with list of content. WID_NCL_SCROLLBAR = ::WID_NCL_SCROLLBAR, ///< Scrollbar of matrix. WID_NCL_DETAILS = ::WID_NCL_DETAILS, ///< Panel with content details. WID_NCL_TEXTFILE = ::WID_NCL_TEXTFILE, ///< Open readme, changelog (+1) or license (+2) of a file in the content window. WID_NCL_SELECT_ALL = ::WID_NCL_SELECT_ALL, ///< 'Select all' button. WID_NCL_SELECT_UPDATE = ::WID_NCL_SELECT_UPDATE, ///< 'Select updates' button. WID_NCL_UNSELECT = ::WID_NCL_UNSELECT, ///< 'Unselect all' button. WID_NCL_OPEN_URL = ::WID_NCL_OPEN_URL, ///< 'Open url' button. WID_NCL_CANCEL = ::WID_NCL_CANCEL, ///< 'Cancel' button. WID_NCL_DOWNLOAD = ::WID_NCL_DOWNLOAD, ///< 'Download' button. WID_NCL_SEL_ALL_UPDATE = ::WID_NCL_SEL_ALL_UPDATE, ///< #NWID_SELECTION widget for select all/update buttons.. WID_NCL_SEARCH_EXTERNAL = ::WID_NCL_SEARCH_EXTERNAL, ///< Search external sites for missing NewGRF. }; /* automatically generated from ../../widgets/network_widget.h */ /** Widgets of the #NetworkGameWindow class. */ enum NetworkGameWidgets { WID_NG_MAIN = ::WID_NG_MAIN, ///< Main panel. WID_NG_CONNECTION = ::WID_NG_CONNECTION, ///< Label in front of connection droplist. WID_NG_CONN_BTN = ::WID_NG_CONN_BTN, ///< 'Connection' droplist button. WID_NG_CLIENT_LABEL = ::WID_NG_CLIENT_LABEL, ///< Label in front of client name edit box. WID_NG_CLIENT = ::WID_NG_CLIENT, ///< Panel with editbox to set client name. WID_NG_FILTER_LABEL = ::WID_NG_FILTER_LABEL, ///< Label in front of the filter/search edit box. WID_NG_FILTER = ::WID_NG_FILTER, ///< Panel with the edit box to enter the search text. WID_NG_HEADER = ::WID_NG_HEADER, ///< Header container of the matrix. WID_NG_NAME = ::WID_NG_NAME, ///< 'Name' button. WID_NG_CLIENTS = ::WID_NG_CLIENTS, ///< 'Clients' button. WID_NG_MAPSIZE = ::WID_NG_MAPSIZE, ///< 'Map size' button. WID_NG_DATE = ::WID_NG_DATE, ///< 'Date' button. WID_NG_YEARS = ::WID_NG_YEARS, ///< 'Years' button. WID_NG_INFO = ::WID_NG_INFO, ///< Third button in the game list panel. WID_NG_MATRIX = ::WID_NG_MATRIX, ///< Panel with list of games. WID_NG_SCROLLBAR = ::WID_NG_SCROLLBAR, ///< Scrollbar of matrix. WID_NG_LASTJOINED_LABEL = ::WID_NG_LASTJOINED_LABEL, ///< Label "Last joined server:". WID_NG_LASTJOINED = ::WID_NG_LASTJOINED, ///< Info about the last joined server. WID_NG_LASTJOINED_SPACER = ::WID_NG_LASTJOINED_SPACER, ///< Spacer after last joined server panel. WID_NG_DETAILS = ::WID_NG_DETAILS, ///< Panel with game details. WID_NG_DETAILS_SPACER = ::WID_NG_DETAILS_SPACER, ///< Spacer for game actual details. WID_NG_JOIN = ::WID_NG_JOIN, ///< 'Join game' button. WID_NG_REFRESH = ::WID_NG_REFRESH, ///< 'Refresh server' button. WID_NG_NEWGRF = ::WID_NG_NEWGRF, ///< 'NewGRF Settings' button. WID_NG_NEWGRF_SEL = ::WID_NG_NEWGRF_SEL, ///< Selection 'widget' to hide the NewGRF settings. WID_NG_NEWGRF_MISSING = ::WID_NG_NEWGRF_MISSING, ///< 'Find missing NewGRF online' button. WID_NG_NEWGRF_MISSING_SEL = ::WID_NG_NEWGRF_MISSING_SEL, ///< Selection widget for the above button. WID_NG_FIND = ::WID_NG_FIND, ///< 'Find server' button. WID_NG_ADD = ::WID_NG_ADD, ///< 'Add server' button. WID_NG_START = ::WID_NG_START, ///< 'Start server' button. WID_NG_CANCEL = ::WID_NG_CANCEL, ///< 'Cancel' button. }; /** Widgets of the #NetworkStartServerWindow class. */ enum NetworkStartServerWidgets { WID_NSS_BACKGROUND = ::WID_NSS_BACKGROUND, ///< Background of the window. WID_NSS_GAMENAME_LABEL = ::WID_NSS_GAMENAME_LABEL, ///< Label for the game name. WID_NSS_GAMENAME = ::WID_NSS_GAMENAME, ///< Background for editbox to set game name. WID_NSS_SETPWD = ::WID_NSS_SETPWD, ///< 'Set password' button. WID_NSS_CONNTYPE_LABEL = ::WID_NSS_CONNTYPE_LABEL, ///< Label for 'connection type'. WID_NSS_CONNTYPE_BTN = ::WID_NSS_CONNTYPE_BTN, ///< 'Connection type' droplist button. WID_NSS_CLIENTS_LABEL = ::WID_NSS_CLIENTS_LABEL, ///< Label for 'max clients'. WID_NSS_CLIENTS_BTND = ::WID_NSS_CLIENTS_BTND, ///< 'Max clients' downarrow. WID_NSS_CLIENTS_TXT = ::WID_NSS_CLIENTS_TXT, ///< 'Max clients' text. WID_NSS_CLIENTS_BTNU = ::WID_NSS_CLIENTS_BTNU, ///< 'Max clients' uparrow. WID_NSS_COMPANIES_LABEL = ::WID_NSS_COMPANIES_LABEL, ///< Label for 'max companies'. WID_NSS_COMPANIES_BTND = ::WID_NSS_COMPANIES_BTND, ///< 'Max companies' downarrow. WID_NSS_COMPANIES_TXT = ::WID_NSS_COMPANIES_TXT, ///< 'Max companies' text. WID_NSS_COMPANIES_BTNU = ::WID_NSS_COMPANIES_BTNU, ///< 'Max companies' uparrow. WID_NSS_SPECTATORS_LABEL = ::WID_NSS_SPECTATORS_LABEL, ///< Label for 'max spectators'. WID_NSS_SPECTATORS_BTND = ::WID_NSS_SPECTATORS_BTND, ///< 'Max spectators' downarrow. WID_NSS_SPECTATORS_TXT = ::WID_NSS_SPECTATORS_TXT, ///< 'Max spectators' text. WID_NSS_SPECTATORS_BTNU = ::WID_NSS_SPECTATORS_BTNU, ///< 'Max spectators' uparrow. WID_NSS_LANGUAGE_LABEL = ::WID_NSS_LANGUAGE_LABEL, ///< Label for 'language spoken'. WID_NSS_LANGUAGE_BTN = ::WID_NSS_LANGUAGE_BTN, ///< 'Language spoken' droplist button. WID_NSS_GENERATE_GAME = ::WID_NSS_GENERATE_GAME, ///< New game button. WID_NSS_LOAD_GAME = ::WID_NSS_LOAD_GAME, ///< Load game button. WID_NSS_PLAY_SCENARIO = ::WID_NSS_PLAY_SCENARIO, ///< Play scenario button. WID_NSS_PLAY_HEIGHTMAP = ::WID_NSS_PLAY_HEIGHTMAP, ///< Play heightmap button. WID_NSS_CANCEL = ::WID_NSS_CANCEL, ///< 'Cancel' button. }; /** Widgets of the #NetworkLobbyWindow class. */ enum NetworkLobbyWidgets { WID_NL_BACKGROUND = ::WID_NL_BACKGROUND, ///< Background of the window. WID_NL_TEXT = ::WID_NL_TEXT, ///< Heading text. WID_NL_HEADER = ::WID_NL_HEADER, ///< Header above list of companies. WID_NL_MATRIX = ::WID_NL_MATRIX, ///< List of companies. WID_NL_SCROLLBAR = ::WID_NL_SCROLLBAR, ///< Scroll bar. WID_NL_DETAILS = ::WID_NL_DETAILS, ///< Company details. WID_NL_JOIN = ::WID_NL_JOIN, ///< 'Join company' button. WID_NL_NEW = ::WID_NL_NEW, ///< 'New company' button. WID_NL_SPECTATE = ::WID_NL_SPECTATE, ///< 'Spectate game' button. WID_NL_REFRESH = ::WID_NL_REFRESH, ///< 'Refresh server' button. WID_NL_CANCEL = ::WID_NL_CANCEL, ///< 'Cancel' button. }; /** Widgets of the #NetworkClientListWindow class. */ enum ClientListWidgets { WID_CL_PANEL = ::WID_CL_PANEL, ///< Panel of the window. }; /** Widgets of the #NetworkClientListPopupWindow class. */ enum ClientListPopupWidgets { WID_CLP_PANEL = ::WID_CLP_PANEL, ///< Panel of the window. }; /** Widgets of the #NetworkJoinStatusWindow class. */ enum NetworkJoinStatusWidgets { WID_NJS_BACKGROUND = ::WID_NJS_BACKGROUND, ///< Background of the window. WID_NJS_CANCELOK = ::WID_NJS_CANCELOK, ///< Cancel / OK button. }; /** Widgets of the #NetworkCompanyPasswordWindow class. */ enum NetworkCompanyPasswordWidgets { WID_NCP_BACKGROUND = ::WID_NCP_BACKGROUND, ///< Background of the window. WID_NCP_LABEL = ::WID_NCP_LABEL, ///< Label in front of the password field. WID_NCP_PASSWORD = ::WID_NCP_PASSWORD, ///< Input field for the password. WID_NCP_SAVE_AS_DEFAULT_PASSWORD = ::WID_NCP_SAVE_AS_DEFAULT_PASSWORD, ///< Toggle 'button' for saving the current password as default password. WID_NCP_CANCEL = ::WID_NCP_CANCEL, ///< Close the window without changing anything. WID_NCP_OK = ::WID_NCP_OK, ///< Safe the password etc. }; /* automatically generated from ../../widgets/newgrf_debug_widget.h */ /** Widgets of the #NewGRFInspectWindow class. */ enum NewGRFInspectWidgets { WID_NGRFI_CAPTION = ::WID_NGRFI_CAPTION, ///< The caption bar of course. WID_NGRFI_PARENT = ::WID_NGRFI_PARENT, ///< Inspect the parent. WID_NGRFI_VEH_PREV = ::WID_NGRFI_VEH_PREV, ///< Go to previous vehicle in chain. WID_NGRFI_VEH_NEXT = ::WID_NGRFI_VEH_NEXT, ///< Go to next vehicle in chain. WID_NGRFI_VEH_CHAIN = ::WID_NGRFI_VEH_CHAIN, ///< Display for vehicle chain. WID_NGRFI_MAINPANEL = ::WID_NGRFI_MAINPANEL, ///< Panel widget containing the actual data. WID_NGRFI_SCROLLBAR = ::WID_NGRFI_SCROLLBAR, ///< Scrollbar. }; /** Widgets of the #SpriteAlignerWindow class. */ enum SpriteAlignerWidgets { WID_SA_CAPTION = ::WID_SA_CAPTION, ///< Caption of the window. WID_SA_PREVIOUS = ::WID_SA_PREVIOUS, ///< Skip to the previous sprite. WID_SA_GOTO = ::WID_SA_GOTO, ///< Go to a given sprite. WID_SA_NEXT = ::WID_SA_NEXT, ///< Skip to the next sprite. WID_SA_UP = ::WID_SA_UP, ///< Move the sprite up. WID_SA_LEFT = ::WID_SA_LEFT, ///< Move the sprite to the left. WID_SA_RIGHT = ::WID_SA_RIGHT, ///< Move the sprite to the right. WID_SA_DOWN = ::WID_SA_DOWN, ///< Move the sprite down. WID_SA_SPRITE = ::WID_SA_SPRITE, ///< The actual sprite. WID_SA_OFFSETS_ABS = ::WID_SA_OFFSETS_ABS, ///< The sprite offsets (absolute). WID_SA_OFFSETS_REL = ::WID_SA_OFFSETS_REL, ///< The sprite offsets (relative). WID_SA_PICKER = ::WID_SA_PICKER, ///< Sprite picker. WID_SA_LIST = ::WID_SA_LIST, ///< Queried sprite list. WID_SA_SCROLLBAR = ::WID_SA_SCROLLBAR, ///< Scrollbar for sprite list. WID_SA_RESET_REL = ::WID_SA_RESET_REL, ///< Reset relative sprite offset }; /* automatically generated from ../../widgets/newgrf_widget.h */ /** Widgets of the #NewGRFParametersWindow class. */ enum NewGRFParametersWidgets { WID_NP_SHOW_NUMPAR = ::WID_NP_SHOW_NUMPAR, ///< #NWID_SELECTION to optionally display #WID_NP_NUMPAR. WID_NP_NUMPAR_DEC = ::WID_NP_NUMPAR_DEC, ///< Button to decrease number of parameters. WID_NP_NUMPAR_INC = ::WID_NP_NUMPAR_INC, ///< Button to increase number of parameters. WID_NP_NUMPAR = ::WID_NP_NUMPAR, ///< Optional number of parameters. WID_NP_NUMPAR_TEXT = ::WID_NP_NUMPAR_TEXT, ///< Text description. WID_NP_BACKGROUND = ::WID_NP_BACKGROUND, ///< Panel to draw the settings on. WID_NP_SCROLLBAR = ::WID_NP_SCROLLBAR, ///< Scrollbar to scroll through all settings. WID_NP_ACCEPT = ::WID_NP_ACCEPT, ///< Accept button. WID_NP_RESET = ::WID_NP_RESET, ///< Reset button. WID_NP_SHOW_DESCRIPTION = ::WID_NP_SHOW_DESCRIPTION, ///< #NWID_SELECTION to optionally display parameter descriptions. WID_NP_DESCRIPTION = ::WID_NP_DESCRIPTION, ///< Multi-line description of a parameter. }; /** Widgets of the #NewGRFWindow class. */ enum NewGRFStateWidgets { WID_NS_PRESET_LIST = ::WID_NS_PRESET_LIST, ///< Active NewGRF preset. WID_NS_PRESET_SAVE = ::WID_NS_PRESET_SAVE, ///< Save list of active NewGRFs as presets. WID_NS_PRESET_DELETE = ::WID_NS_PRESET_DELETE, ///< Delete active preset. WID_NS_ADD = ::WID_NS_ADD, ///< Add NewGRF to active list. WID_NS_REMOVE = ::WID_NS_REMOVE, ///< Remove NewGRF from active list. WID_NS_MOVE_UP = ::WID_NS_MOVE_UP, ///< Move NewGRF up in active list. WID_NS_MOVE_DOWN = ::WID_NS_MOVE_DOWN, ///< Move NewGRF down in active list. WID_NS_UPGRADE = ::WID_NS_UPGRADE, ///< Upgrade NewGRFs that have a newer version available. WID_NS_FILTER = ::WID_NS_FILTER, ///< Filter list of available NewGRFs. WID_NS_FILE_LIST = ::WID_NS_FILE_LIST, ///< List window of active NewGRFs. WID_NS_SCROLLBAR = ::WID_NS_SCROLLBAR, ///< Scrollbar for active NewGRF list. WID_NS_AVAIL_LIST = ::WID_NS_AVAIL_LIST, ///< List window of available NewGRFs. WID_NS_SCROLL2BAR = ::WID_NS_SCROLL2BAR, ///< Scrollbar for available NewGRF list. WID_NS_NEWGRF_INFO_TITLE = ::WID_NS_NEWGRF_INFO_TITLE, ///< Title for Info on selected NewGRF. WID_NS_NEWGRF_INFO = ::WID_NS_NEWGRF_INFO, ///< Panel for Info on selected NewGRF. WID_NS_OPEN_URL = ::WID_NS_OPEN_URL, ///< Open URL of NewGRF. WID_NS_NEWGRF_TEXTFILE = ::WID_NS_NEWGRF_TEXTFILE, ///< Open NewGRF readme, changelog (+1) or license (+2). WID_NS_SET_PARAMETERS = ::WID_NS_SET_PARAMETERS, ///< Open Parameters Window for selected NewGRF for editing parameters. WID_NS_VIEW_PARAMETERS = ::WID_NS_VIEW_PARAMETERS, ///< Open Parameters Window for selected NewGRF for viewing parameters. WID_NS_TOGGLE_PALETTE = ::WID_NS_TOGGLE_PALETTE, ///< Toggle Palette of selected, active NewGRF. WID_NS_APPLY_CHANGES = ::WID_NS_APPLY_CHANGES, ///< Apply changes to NewGRF config. WID_NS_RESCAN_FILES = ::WID_NS_RESCAN_FILES, ///< Rescan files (available NewGRFs). WID_NS_RESCAN_FILES2 = ::WID_NS_RESCAN_FILES2, ///< Rescan files (active NewGRFs). WID_NS_CONTENT_DOWNLOAD = ::WID_NS_CONTENT_DOWNLOAD, ///< Open content download (available NewGRFs). WID_NS_CONTENT_DOWNLOAD2 = ::WID_NS_CONTENT_DOWNLOAD2, ///< Open content download (active NewGRFs). WID_NS_SHOW_REMOVE = ::WID_NS_SHOW_REMOVE, ///< Select active list buttons (0, 1 = simple layout). WID_NS_SHOW_APPLY = ::WID_NS_SHOW_APPLY, ///< Select display of the buttons below the 'details'. }; /** Widgets of the #SavePresetWindow class. */ enum SavePresetWidgets { WID_SVP_PRESET_LIST = ::WID_SVP_PRESET_LIST, ///< List with available preset names. WID_SVP_SCROLLBAR = ::WID_SVP_SCROLLBAR, ///< Scrollbar for the list available preset names. WID_SVP_EDITBOX = ::WID_SVP_EDITBOX, ///< Edit box for changing the preset name. WID_SVP_CANCEL = ::WID_SVP_CANCEL, ///< Button to cancel saving the preset. WID_SVP_SAVE = ::WID_SVP_SAVE, ///< Button to save the preset. }; /** Widgets of the #ScanProgressWindow class. */ enum ScanProgressWidgets { WID_SP_PROGRESS_BAR = ::WID_SP_PROGRESS_BAR, ///< Simple progress bar. WID_SP_PROGRESS_TEXT = ::WID_SP_PROGRESS_TEXT, ///< Text explaining what is happening. }; /* automatically generated from ../../widgets/news_widget.h */ /** Widgets of the #NewsWindow class. */ enum NewsWidgets { WID_N_PANEL = ::WID_N_PANEL, ///< Panel of the window. WID_N_TITLE = ::WID_N_TITLE, ///< Title of the company news. WID_N_HEADLINE = ::WID_N_HEADLINE, ///< The news headline. WID_N_CLOSEBOX = ::WID_N_CLOSEBOX, ///< Close the window. WID_N_DATE = ::WID_N_DATE, ///< Date of the news item. WID_N_CAPTION = ::WID_N_CAPTION, ///< Title bar of the window. Only used in small news items. WID_N_INSET = ::WID_N_INSET, ///< Inset around the viewport in the window. Only used in small news items. WID_N_VIEWPORT = ::WID_N_VIEWPORT, ///< Viewport in the window. WID_N_COMPANY_MSG = ::WID_N_COMPANY_MSG, ///< Message in company news items. WID_N_MESSAGE = ::WID_N_MESSAGE, ///< Space for displaying the message. Only used in small news items. WID_N_MGR_FACE = ::WID_N_MGR_FACE, ///< Face of the manager. WID_N_MGR_NAME = ::WID_N_MGR_NAME, ///< Name of the manager. WID_N_VEH_TITLE = ::WID_N_VEH_TITLE, ///< Vehicle new title. WID_N_VEH_BKGND = ::WID_N_VEH_BKGND, ///< Dark background of new vehicle news. WID_N_VEH_NAME = ::WID_N_VEH_NAME, ///< Name of the new vehicle. WID_N_VEH_SPR = ::WID_N_VEH_SPR, ///< Graphical display of the new vehicle. WID_N_VEH_INFO = ::WID_N_VEH_INFO, ///< Some technical data of the new vehicle. }; /** Widgets of the #MessageHistoryWindow class. */ enum MessageHistoryWidgets { WID_MH_STICKYBOX = ::WID_MH_STICKYBOX, ///< Stickybox. WID_MH_BACKGROUND = ::WID_MH_BACKGROUND, ///< Background of the window. WID_MH_SCROLLBAR = ::WID_MH_SCROLLBAR, ///< Scrollbar for the list. }; /* automatically generated from ../../widgets/object_widget.h */ /** Widgets of the #BuildObjectWindow class. */ enum BuildObjectWidgets { WID_BO_CLASS_LIST = ::WID_BO_CLASS_LIST, ///< The list with classes. WID_BO_SCROLLBAR = ::WID_BO_SCROLLBAR, ///< The scrollbar associated with the list. WID_BO_OBJECT_MATRIX = ::WID_BO_OBJECT_MATRIX, ///< The matrix with preview sprites. WID_BO_OBJECT_SPRITE = ::WID_BO_OBJECT_SPRITE, ///< A preview sprite of the object. WID_BO_OBJECT_NAME = ::WID_BO_OBJECT_NAME, ///< The name of the selected object. WID_BO_OBJECT_SIZE = ::WID_BO_OBJECT_SIZE, ///< The size of the selected object. WID_BO_INFO = ::WID_BO_INFO, ///< Other information about the object (from the NewGRF). WID_BO_SELECT_MATRIX = ::WID_BO_SELECT_MATRIX, ///< Selection preview matrix of objects of a given class. WID_BO_SELECT_IMAGE = ::WID_BO_SELECT_IMAGE, ///< Preview image in the #WID_BO_SELECT_MATRIX. WID_BO_SELECT_SCROLL = ::WID_BO_SELECT_SCROLL, ///< Scrollbar next to the #WID_BO_SELECT_MATRIX. }; /* automatically generated from ../../widgets/order_widget.h */ /** Widgets of the #OrdersWindow class. */ enum OrderWidgets { WID_O_CAPTION = ::WID_O_CAPTION, ///< Caption of the window. WID_O_TIMETABLE_VIEW = ::WID_O_TIMETABLE_VIEW, ///< Toggle timetable view. WID_O_ORDER_LIST = ::WID_O_ORDER_LIST, ///< Order list panel. WID_O_SCROLLBAR = ::WID_O_SCROLLBAR, ///< Order list scrollbar. WID_O_SKIP = ::WID_O_SKIP, ///< Skip current order. WID_O_DELETE = ::WID_O_DELETE, ///< Delete selected order. WID_O_STOP_SHARING = ::WID_O_STOP_SHARING, ///< Stop sharing orders. WID_O_NON_STOP = ::WID_O_NON_STOP, ///< Goto non-stop to destination. WID_O_GOTO = ::WID_O_GOTO, ///< Goto destination. WID_O_FULL_LOAD = ::WID_O_FULL_LOAD, ///< Select full load. WID_O_UNLOAD = ::WID_O_UNLOAD, ///< Select unload. WID_O_REFIT = ::WID_O_REFIT, ///< Select refit. WID_O_SERVICE = ::WID_O_SERVICE, ///< Select service (at depot). WID_O_EMPTY = ::WID_O_EMPTY, ///< Placeholder for refit dropdown when not owner. WID_O_REFIT_DROPDOWN = ::WID_O_REFIT_DROPDOWN, ///< Open refit options. WID_O_COND_VARIABLE = ::WID_O_COND_VARIABLE, ///< Choose condition variable. WID_O_COND_COMPARATOR = ::WID_O_COND_COMPARATOR, ///< Choose condition type. WID_O_COND_VALUE = ::WID_O_COND_VALUE, ///< Choose condition value. WID_O_SEL_TOP_LEFT = ::WID_O_SEL_TOP_LEFT, ///< #NWID_SELECTION widget for left part of the top row of the 'your train' order window. WID_O_SEL_TOP_MIDDLE = ::WID_O_SEL_TOP_MIDDLE, ///< #NWID_SELECTION widget for middle part of the top row of the 'your train' order window. WID_O_SEL_TOP_RIGHT = ::WID_O_SEL_TOP_RIGHT, ///< #NWID_SELECTION widget for right part of the top row of the 'your train' order window. WID_O_SEL_TOP_ROW_GROUNDVEHICLE = ::WID_O_SEL_TOP_ROW_GROUNDVEHICLE, ///< #NWID_SELECTION widget for the top row of the 'your train' order window. WID_O_SEL_TOP_ROW = ::WID_O_SEL_TOP_ROW, ///< #NWID_SELECTION widget for the top row of the 'your non-trains' order window. WID_O_SEL_BOTTOM_MIDDLE = ::WID_O_SEL_BOTTOM_MIDDLE, ///< #NWID_SELECTION widget for the middle part of the bottom row of the 'your train' order window. WID_O_SHARED_ORDER_LIST = ::WID_O_SHARED_ORDER_LIST, ///< Open list of shared vehicles. }; /* automatically generated from ../../widgets/osk_widget.h */ /** Widgets of the #OskWindow class. */ enum OnScreenKeyboardWidgets { WID_OSK_CAPTION = ::WID_OSK_CAPTION, ///< Caption of window. WID_OSK_TEXT = ::WID_OSK_TEXT, ///< Edit box. WID_OSK_CANCEL = ::WID_OSK_CANCEL, ///< Cancel key. WID_OSK_OK = ::WID_OSK_OK, ///< Ok key. WID_OSK_BACKSPACE = ::WID_OSK_BACKSPACE, ///< Backspace key. WID_OSK_SPECIAL = ::WID_OSK_SPECIAL, ///< Special key (at keyboards often used for tab key). WID_OSK_CAPS = ::WID_OSK_CAPS, ///< Capslock key. WID_OSK_SHIFT = ::WID_OSK_SHIFT, ///< Shift(lock) key. WID_OSK_SPACE = ::WID_OSK_SPACE, ///< Space bar. WID_OSK_LEFT = ::WID_OSK_LEFT, ///< Cursor left key. WID_OSK_RIGHT = ::WID_OSK_RIGHT, ///< Cursor right key. WID_OSK_LETTERS = ::WID_OSK_LETTERS, ///< First widget of the 'normal' keys. WID_OSK_NUMBERS_FIRST = ::WID_OSK_NUMBERS_FIRST, ///< First widget of the numbers row. WID_OSK_NUMBERS_LAST = ::WID_OSK_NUMBERS_LAST, ///< Last widget of the numbers row. WID_OSK_QWERTY_FIRST = ::WID_OSK_QWERTY_FIRST, ///< First widget of the qwerty row. WID_OSK_QWERTY_LAST = ::WID_OSK_QWERTY_LAST, ///< Last widget of the qwerty row. WID_OSK_ASDFG_FIRST = ::WID_OSK_ASDFG_FIRST, ///< First widget of the asdfg row. WID_OSK_ASDFG_LAST = ::WID_OSK_ASDFG_LAST, ///< Last widget of the asdfg row. WID_OSK_ZXCVB_FIRST = ::WID_OSK_ZXCVB_FIRST, ///< First widget of the zxcvb row. WID_OSK_ZXCVB_LAST = ::WID_OSK_ZXCVB_LAST, ///< Last widget of the zxcvb row. }; /* automatically generated from ../../widgets/rail_widget.h */ /** Widgets of the #BuildRailToolbarWindow class. */ enum RailToolbarWidgets { /* Name starts with RA instead of R, because of collision with RoadToolbarWidgets */ WID_RAT_CAPTION = ::WID_RAT_CAPTION, ///< Caption of the window. WID_RAT_BUILD_NS = ::WID_RAT_BUILD_NS, ///< Build rail along the game view Y axis. WID_RAT_BUILD_X = ::WID_RAT_BUILD_X, ///< Build rail along the game grid X axis. WID_RAT_BUILD_EW = ::WID_RAT_BUILD_EW, ///< Build rail along the game view X axis. WID_RAT_BUILD_Y = ::WID_RAT_BUILD_Y, ///< Build rail along the game grid Y axis. WID_RAT_AUTORAIL = ::WID_RAT_AUTORAIL, ///< Autorail tool. WID_RAT_DEMOLISH = ::WID_RAT_DEMOLISH, ///< Destroy something with dynamite! WID_RAT_BUILD_DEPOT = ::WID_RAT_BUILD_DEPOT, ///< Build a depot. WID_RAT_BUILD_WAYPOINT = ::WID_RAT_BUILD_WAYPOINT, ///< Build a waypoint. WID_RAT_BUILD_STATION = ::WID_RAT_BUILD_STATION, ///< Build a station. WID_RAT_BUILD_SIGNALS = ::WID_RAT_BUILD_SIGNALS, ///< Build signals. WID_RAT_BUILD_BRIDGE = ::WID_RAT_BUILD_BRIDGE, ///< Build a bridge. WID_RAT_BUILD_TUNNEL = ::WID_RAT_BUILD_TUNNEL, ///< Build a tunnel. WID_RAT_REMOVE = ::WID_RAT_REMOVE, ///< Bulldozer to remove rail. WID_RAT_CONVERT_RAIL = ::WID_RAT_CONVERT_RAIL, ///< Convert other rail to this type. }; /** Widgets of the #BuildRailStationWindow class. */ enum BuildRailStationWidgets { /* Name starts with BRA instead of BR, because of collision with BuildRoadStationWidgets */ WID_BRAS_PLATFORM_DIR_X = ::WID_BRAS_PLATFORM_DIR_X, ///< Button to select '/' view. WID_BRAS_PLATFORM_DIR_Y = ::WID_BRAS_PLATFORM_DIR_Y, ///< Button to select '\' view. WID_BRAS_PLATFORM_NUM_1 = ::WID_BRAS_PLATFORM_NUM_1, ///< Button to select stations with a single platform. WID_BRAS_PLATFORM_NUM_2 = ::WID_BRAS_PLATFORM_NUM_2, ///< Button to select stations with 2 platforms. WID_BRAS_PLATFORM_NUM_3 = ::WID_BRAS_PLATFORM_NUM_3, ///< Button to select stations with 3 platforms. WID_BRAS_PLATFORM_NUM_4 = ::WID_BRAS_PLATFORM_NUM_4, ///< Button to select stations with 4 platforms. WID_BRAS_PLATFORM_NUM_5 = ::WID_BRAS_PLATFORM_NUM_5, ///< Button to select stations with 5 platforms. WID_BRAS_PLATFORM_NUM_6 = ::WID_BRAS_PLATFORM_NUM_6, ///< Button to select stations with 6 platforms. WID_BRAS_PLATFORM_NUM_7 = ::WID_BRAS_PLATFORM_NUM_7, ///< Button to select stations with 7 platforms. WID_BRAS_PLATFORM_LEN_1 = ::WID_BRAS_PLATFORM_LEN_1, ///< Button to select single tile length station platforms. WID_BRAS_PLATFORM_LEN_2 = ::WID_BRAS_PLATFORM_LEN_2, ///< Button to select 2 tiles length station platforms. WID_BRAS_PLATFORM_LEN_3 = ::WID_BRAS_PLATFORM_LEN_3, ///< Button to select 3 tiles length station platforms. WID_BRAS_PLATFORM_LEN_4 = ::WID_BRAS_PLATFORM_LEN_4, ///< Button to select 4 tiles length station platforms. WID_BRAS_PLATFORM_LEN_5 = ::WID_BRAS_PLATFORM_LEN_5, ///< Button to select 5 tiles length station platforms. WID_BRAS_PLATFORM_LEN_6 = ::WID_BRAS_PLATFORM_LEN_6, ///< Button to select 6 tiles length station platforms. WID_BRAS_PLATFORM_LEN_7 = ::WID_BRAS_PLATFORM_LEN_7, ///< Button to select 7 tiles length station platforms. WID_BRAS_PLATFORM_DRAG_N_DROP = ::WID_BRAS_PLATFORM_DRAG_N_DROP, ///< Button to enable drag and drop type station placement. WID_BRAS_HIGHLIGHT_OFF = ::WID_BRAS_HIGHLIGHT_OFF, ///< Button for turning coverage highlighting off. WID_BRAS_HIGHLIGHT_ON = ::WID_BRAS_HIGHLIGHT_ON, ///< Button for turning coverage highlighting on. WID_BRAS_COVERAGE_TEXTS = ::WID_BRAS_COVERAGE_TEXTS, ///< Empty space for the coverage texts. WID_BRAS_MATRIX = ::WID_BRAS_MATRIX, ///< Matrix widget displaying the available stations. WID_BRAS_IMAGE = ::WID_BRAS_IMAGE, ///< Panel used at each cell of the matrix. WID_BRAS_MATRIX_SCROLL = ::WID_BRAS_MATRIX_SCROLL, ///< Scrollbar of the matrix widget. WID_BRAS_SHOW_NEWST_DEFSIZE = ::WID_BRAS_SHOW_NEWST_DEFSIZE, ///< Selection for default-size button for newstation. WID_BRAS_SHOW_NEWST_ADDITIONS = ::WID_BRAS_SHOW_NEWST_ADDITIONS, ///< Selection for newstation class selection list. WID_BRAS_SHOW_NEWST_MATRIX = ::WID_BRAS_SHOW_NEWST_MATRIX, ///< Selection for newstation image matrix. WID_BRAS_SHOW_NEWST_RESIZE = ::WID_BRAS_SHOW_NEWST_RESIZE, ///< Selection for panel and resize at bottom right for newstation. WID_BRAS_SHOW_NEWST_TYPE = ::WID_BRAS_SHOW_NEWST_TYPE, ///< Display of selected station type. WID_BRAS_NEWST_LIST = ::WID_BRAS_NEWST_LIST, ///< List with available newstation classes. WID_BRAS_NEWST_SCROLL = ::WID_BRAS_NEWST_SCROLL, ///< Scrollbar of the #WID_BRAS_NEWST_LIST. WID_BRAS_PLATFORM_NUM_BEGIN = ::WID_BRAS_PLATFORM_NUM_BEGIN, ///< Helper for determining the chosen platform width. WID_BRAS_PLATFORM_LEN_BEGIN = ::WID_BRAS_PLATFORM_LEN_BEGIN, ///< Helper for determining the chosen platform length. }; /** Widgets of the #BuildSignalWindow class. */ enum BuildSignalWidgets { WID_BS_SEMAPHORE_NORM = ::WID_BS_SEMAPHORE_NORM, ///< Build a semaphore normal block signal WID_BS_SEMAPHORE_ENTRY = ::WID_BS_SEMAPHORE_ENTRY, ///< Build a semaphore entry block signal WID_BS_SEMAPHORE_EXIT = ::WID_BS_SEMAPHORE_EXIT, ///< Build a semaphore exit block signal WID_BS_SEMAPHORE_COMBO = ::WID_BS_SEMAPHORE_COMBO, ///< Build a semaphore combo block signal WID_BS_SEMAPHORE_PBS = ::WID_BS_SEMAPHORE_PBS, ///< Build a semaphore path signal. WID_BS_SEMAPHORE_PBS_OWAY = ::WID_BS_SEMAPHORE_PBS_OWAY, ///< Build a semaphore one way path signal. WID_BS_ELECTRIC_NORM = ::WID_BS_ELECTRIC_NORM, ///< Build an electric normal block signal WID_BS_ELECTRIC_ENTRY = ::WID_BS_ELECTRIC_ENTRY, ///< Build an electric entry block signal WID_BS_ELECTRIC_EXIT = ::WID_BS_ELECTRIC_EXIT, ///< Build an electric exit block signal WID_BS_ELECTRIC_COMBO = ::WID_BS_ELECTRIC_COMBO, ///< Build an electric combo block signal WID_BS_ELECTRIC_PBS = ::WID_BS_ELECTRIC_PBS, ///< Build an electric path signal. WID_BS_ELECTRIC_PBS_OWAY = ::WID_BS_ELECTRIC_PBS_OWAY, ///< Build an electric one way path signal. WID_BS_CONVERT = ::WID_BS_CONVERT, ///< Convert the signal. WID_BS_DRAG_SIGNALS_DENSITY_LABEL = ::WID_BS_DRAG_SIGNALS_DENSITY_LABEL, ///< The current signal density. WID_BS_DRAG_SIGNALS_DENSITY_DECREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, ///< Decrease the signal density. WID_BS_DRAG_SIGNALS_DENSITY_INCREASE = ::WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, ///< Increase the signal density. }; /** Widgets of the #BuildRailDepotWindow class. */ enum BuildRailDepotWidgets { /* Name starts with BRA instead of BR, because of collision with BuildRoadDepotWidgets */ WID_BRAD_DEPOT_NE = ::WID_BRAD_DEPOT_NE, ///< Build a depot with the entrance in the north east. WID_BRAD_DEPOT_SE = ::WID_BRAD_DEPOT_SE, ///< Build a depot with the entrance in the south east. WID_BRAD_DEPOT_SW = ::WID_BRAD_DEPOT_SW, ///< Build a depot with the entrance in the south west. WID_BRAD_DEPOT_NW = ::WID_BRAD_DEPOT_NW, ///< Build a depot with the entrance in the north west. }; /** Widgets of the #BuildRailWaypointWindow class. */ enum BuildRailWaypointWidgets { WID_BRW_WAYPOINT_MATRIX = ::WID_BRW_WAYPOINT_MATRIX, ///< Matrix with waypoints. WID_BRW_WAYPOINT = ::WID_BRW_WAYPOINT, ///< A single waypoint. WID_BRW_SCROLL = ::WID_BRW_SCROLL, ///< Scrollbar for the matrix. }; /* automatically generated from ../../widgets/road_widget.h */ /** Widgets of the #BuildRoadToolbarWindow class. */ enum RoadToolbarWidgets { /* Name starts with RO instead of R, because of collision with RailToolbarWidgets */ WID_ROT_ROAD_X = ::WID_ROT_ROAD_X, ///< Build road in x-direction. WID_ROT_ROAD_Y = ::WID_ROT_ROAD_Y, ///< Build road in y-direction. WID_ROT_AUTOROAD = ::WID_ROT_AUTOROAD, ///< Autorail. WID_ROT_DEMOLISH = ::WID_ROT_DEMOLISH, ///< Demolish. WID_ROT_DEPOT = ::WID_ROT_DEPOT, ///< Build depot. WID_ROT_BUS_STATION = ::WID_ROT_BUS_STATION, ///< Build bus station. WID_ROT_TRUCK_STATION = ::WID_ROT_TRUCK_STATION, ///< Build truck station. WID_ROT_ONE_WAY = ::WID_ROT_ONE_WAY, ///< Build one-way road. WID_ROT_BUILD_BRIDGE = ::WID_ROT_BUILD_BRIDGE, ///< Build bridge. WID_ROT_BUILD_TUNNEL = ::WID_ROT_BUILD_TUNNEL, ///< Build tunnel. WID_ROT_REMOVE = ::WID_ROT_REMOVE, ///< Remove road. }; /** Widgets of the #BuildRoadDepotWindow class. */ enum BuildRoadDepotWidgets { /* Name starts with BRO instead of BR, because of collision with BuildRailDepotWidgets */ WID_BROD_CAPTION = ::WID_BROD_CAPTION, ///< Caption of the window. WID_BROD_DEPOT_NE = ::WID_BROD_DEPOT_NE, ///< Depot with NE entry. WID_BROD_DEPOT_SE = ::WID_BROD_DEPOT_SE, ///< Depot with SE entry. WID_BROD_DEPOT_SW = ::WID_BROD_DEPOT_SW, ///< Depot with SW entry. WID_BROD_DEPOT_NW = ::WID_BROD_DEPOT_NW, ///< Depot with NW entry. }; /** Widgets of the #BuildRoadStationWindow class. */ enum BuildRoadStationWidgets { /* Name starts with BRO instead of BR, because of collision with BuildRailStationWidgets */ WID_BROS_CAPTION = ::WID_BROS_CAPTION, ///< Caption of the window. WID_BROS_BACKGROUND = ::WID_BROS_BACKGROUND, ///< Background of the window. WID_BROS_STATION_NE = ::WID_BROS_STATION_NE, ///< Terminal station with NE entry. WID_BROS_STATION_SE = ::WID_BROS_STATION_SE, ///< Terminal station with SE entry. WID_BROS_STATION_SW = ::WID_BROS_STATION_SW, ///< Terminal station with SW entry. WID_BROS_STATION_NW = ::WID_BROS_STATION_NW, ///< Terminal station with NW entry. WID_BROS_STATION_X = ::WID_BROS_STATION_X, ///< Drive-through station in x-direction. WID_BROS_STATION_Y = ::WID_BROS_STATION_Y, ///< Drive-through station in y-direction. WID_BROS_LT_OFF = ::WID_BROS_LT_OFF, ///< Turn off area highlight. WID_BROS_LT_ON = ::WID_BROS_LT_ON, ///< Turn on area highlight. WID_BROS_INFO = ::WID_BROS_INFO, ///< Station acceptance info. }; /* automatically generated from ../../widgets/settings_widget.h */ /** Widgets of the #GameOptionsWindow class. */ enum GameOptionsWidgets { WID_GO_BACKGROUND = ::WID_GO_BACKGROUND, ///< Background of the window. WID_GO_CURRENCY_DROPDOWN = ::WID_GO_CURRENCY_DROPDOWN, ///< Currency dropdown. WID_GO_DISTANCE_DROPDOWN = ::WID_GO_DISTANCE_DROPDOWN, ///< Measuring unit dropdown. WID_GO_ROADSIDE_DROPDOWN = ::WID_GO_ROADSIDE_DROPDOWN, ///< Dropdown to select the road side (to set the right side ;)). WID_GO_TOWNNAME_DROPDOWN = ::WID_GO_TOWNNAME_DROPDOWN, ///< Town name dropdown. WID_GO_AUTOSAVE_DROPDOWN = ::WID_GO_AUTOSAVE_DROPDOWN, ///< Dropdown to say how often to autosave. WID_GO_LANG_DROPDOWN = ::WID_GO_LANG_DROPDOWN, ///< Language dropdown. WID_GO_RESOLUTION_DROPDOWN = ::WID_GO_RESOLUTION_DROPDOWN, ///< Dropdown for the resolution. WID_GO_FULLSCREEN_BUTTON = ::WID_GO_FULLSCREEN_BUTTON, ///< Toggle fullscreen. WID_GO_GUI_ZOOM_DROPDOWN = ::WID_GO_GUI_ZOOM_DROPDOWN, ///< Dropdown for the GUI zoom level. WID_GO_BASE_GRF_DROPDOWN = ::WID_GO_BASE_GRF_DROPDOWN, ///< Use to select a base GRF. WID_GO_BASE_GRF_STATUS = ::WID_GO_BASE_GRF_STATUS, ///< Info about missing files etc. WID_GO_BASE_GRF_TEXTFILE = ::WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). WID_GO_BASE_GRF_DESCRIPTION = ::WID_GO_BASE_GRF_DESCRIPTION, ///< Description of selected base GRF. WID_GO_BASE_SFX_DROPDOWN = ::WID_GO_BASE_SFX_DROPDOWN, ///< Use to select a base SFX. WID_GO_BASE_SFX_TEXTFILE = ::WID_GO_BASE_SFX_TEXTFILE, ///< Open base SFX readme, changelog (+1) or license (+2). WID_GO_BASE_SFX_DESCRIPTION = ::WID_GO_BASE_SFX_DESCRIPTION, ///< Description of selected base SFX. WID_GO_BASE_MUSIC_DROPDOWN = ::WID_GO_BASE_MUSIC_DROPDOWN, ///< Use to select a base music set. WID_GO_BASE_MUSIC_STATUS = ::WID_GO_BASE_MUSIC_STATUS, ///< Info about corrupted files etc. WID_GO_BASE_MUSIC_TEXTFILE = ::WID_GO_BASE_MUSIC_TEXTFILE, ///< Open base music readme, changelog (+1) or license (+2). WID_GO_BASE_MUSIC_DESCRIPTION = ::WID_GO_BASE_MUSIC_DESCRIPTION, ///< Description of selected base music set. }; /** Widgets of the #GameSettingsWindow class. */ enum GameSettingsWidgets { WID_GS_FILTER = ::WID_GS_FILTER, ///< Text filter. WID_GS_OPTIONSPANEL = ::WID_GS_OPTIONSPANEL, ///< Panel widget containing the option lists. WID_GS_SCROLLBAR = ::WID_GS_SCROLLBAR, ///< Scrollbar. WID_GS_HELP_TEXT = ::WID_GS_HELP_TEXT, ///< Information area to display help text of the selected option. WID_GS_EXPAND_ALL = ::WID_GS_EXPAND_ALL, ///< Expand all button. WID_GS_COLLAPSE_ALL = ::WID_GS_COLLAPSE_ALL, ///< Collapse all button. WID_GS_RESTRICT_CATEGORY = ::WID_GS_RESTRICT_CATEGORY, ///< Label upfront to the category drop-down box to restrict the list of settings to show WID_GS_RESTRICT_TYPE = ::WID_GS_RESTRICT_TYPE, ///< Label upfront to the type drop-down box to restrict the list of settings to show WID_GS_RESTRICT_DROPDOWN = ::WID_GS_RESTRICT_DROPDOWN, ///< The drop down box to restrict the list of settings WID_GS_TYPE_DROPDOWN = ::WID_GS_TYPE_DROPDOWN, ///< The drop down box to choose client/game/company/all settings }; /** Widgets of the #CustomCurrencyWindow class. */ enum CustomCurrencyWidgets { WID_CC_RATE_DOWN = ::WID_CC_RATE_DOWN, ///< Down button. WID_CC_RATE_UP = ::WID_CC_RATE_UP, ///< Up button. WID_CC_RATE = ::WID_CC_RATE, ///< Rate of currency. WID_CC_SEPARATOR_EDIT = ::WID_CC_SEPARATOR_EDIT, ///< Separator edit button. WID_CC_SEPARATOR = ::WID_CC_SEPARATOR, ///< Current separator. WID_CC_PREFIX_EDIT = ::WID_CC_PREFIX_EDIT, ///< Prefix edit button. WID_CC_PREFIX = ::WID_CC_PREFIX, ///< Current prefix. WID_CC_SUFFIX_EDIT = ::WID_CC_SUFFIX_EDIT, ///< Suffix edit button. WID_CC_SUFFIX = ::WID_CC_SUFFIX, ///< Current suffix. WID_CC_YEAR_DOWN = ::WID_CC_YEAR_DOWN, ///< Down button. WID_CC_YEAR_UP = ::WID_CC_YEAR_UP, ///< Up button. WID_CC_YEAR = ::WID_CC_YEAR, ///< Year of introduction. WID_CC_PREVIEW = ::WID_CC_PREVIEW, ///< Preview. }; /* automatically generated from ../../widgets/sign_widget.h */ /** Widgets of the #SignListWindow class. */ enum SignListWidgets { /* Name starts with SI instead of S, because of collision with SaveLoadWidgets */ WID_SIL_CAPTION = ::WID_SIL_CAPTION, ///< Caption of the window. WID_SIL_LIST = ::WID_SIL_LIST, ///< List of signs. WID_SIL_SCROLLBAR = ::WID_SIL_SCROLLBAR, ///< Scrollbar of list. WID_SIL_FILTER_TEXT = ::WID_SIL_FILTER_TEXT, ///< Text box for typing a filter string. WID_SIL_FILTER_MATCH_CASE_BTN = ::WID_SIL_FILTER_MATCH_CASE_BTN, ///< Button to toggle if case sensitive filtering should be used. WID_SIL_FILTER_ENTER_BTN = ::WID_SIL_FILTER_ENTER_BTN, ///< Scroll to first sign. }; /** Widgets of the #SignWindow class. */ enum QueryEditSignWidgets { WID_QES_CAPTION = ::WID_QES_CAPTION, ///< Caption of the window. WID_QES_TEXT = ::WID_QES_TEXT, ///< Text of the query. WID_QES_OK = ::WID_QES_OK, ///< OK button. WID_QES_CANCEL = ::WID_QES_CANCEL, ///< Cancel button. WID_QES_DELETE = ::WID_QES_DELETE, ///< Delete button. WID_QES_PREVIOUS = ::WID_QES_PREVIOUS, ///< Previous button. WID_QES_NEXT = ::WID_QES_NEXT, ///< Next button. }; /* automatically generated from ../../widgets/smallmap_widget.h */ /** Widgets of the #SmallMapWindow class. */ enum SmallMapWidgets { WID_SM_CAPTION = ::WID_SM_CAPTION, ///< Caption of the window. WID_SM_MAP_BORDER = ::WID_SM_MAP_BORDER, ///< Border around the smallmap. WID_SM_MAP = ::WID_SM_MAP, ///< Panel containing the smallmap. WID_SM_LEGEND = ::WID_SM_LEGEND, ///< Bottom panel to display smallmap legends. WID_SM_BLANK = ::WID_SM_BLANK, ///< Empty button as placeholder. WID_SM_ZOOM_IN = ::WID_SM_ZOOM_IN, ///< Button to zoom in one step. WID_SM_ZOOM_OUT = ::WID_SM_ZOOM_OUT, ///< Button to zoom out one step. WID_SM_CONTOUR = ::WID_SM_CONTOUR, ///< Button to select the contour view (height map). WID_SM_VEHICLES = ::WID_SM_VEHICLES, ///< Button to select the vehicles view. WID_SM_INDUSTRIES = ::WID_SM_INDUSTRIES, ///< Button to select the industries view. WID_SM_LINKSTATS = ::WID_SM_LINKSTATS, ///< Button to select the link stats view. WID_SM_ROUTES = ::WID_SM_ROUTES, ///< Button to select the routes view. WID_SM_VEGETATION = ::WID_SM_VEGETATION, ///< Button to select the vegetation view. WID_SM_OWNERS = ::WID_SM_OWNERS, ///< Button to select the owners view. WID_SM_CENTERMAP = ::WID_SM_CENTERMAP, ///< Button to move smallmap center to main window center. WID_SM_TOGGLETOWNNAME = ::WID_SM_TOGGLETOWNNAME, ///< Toggle button to display town names. WID_SM_SELECT_BUTTONS = ::WID_SM_SELECT_BUTTONS, ///< Selection widget for the buttons present in some smallmap modes. WID_SM_ENABLE_ALL = ::WID_SM_ENABLE_ALL, ///< Button to enable display of all legend entries. WID_SM_DISABLE_ALL = ::WID_SM_DISABLE_ALL, ///< Button to disable display of all legend entries. WID_SM_SHOW_HEIGHT = ::WID_SM_SHOW_HEIGHT, ///< Show heightmap toggle button. }; /* automatically generated from ../../widgets/station_widget.h */ /** Widgets of the #StationViewWindow class. */ enum StationViewWidgets { WID_SV_CAPTION = ::WID_SV_CAPTION, ///< Caption of the window. WID_SV_SORT_ORDER = ::WID_SV_SORT_ORDER, ///< 'Sort order' button WID_SV_SORT_BY = ::WID_SV_SORT_BY, ///< 'Sort by' button WID_SV_GROUP = ::WID_SV_GROUP, ///< label for "group by" WID_SV_GROUP_BY = ::WID_SV_GROUP_BY, ///< 'Group by' button WID_SV_WAITING = ::WID_SV_WAITING, ///< List of waiting cargo. WID_SV_SCROLLBAR = ::WID_SV_SCROLLBAR, ///< Scrollbar. WID_SV_ACCEPT_RATING_LIST = ::WID_SV_ACCEPT_RATING_LIST, ///< List of accepted cargoes / rating of cargoes. WID_SV_LOCATION = ::WID_SV_LOCATION, ///< 'Location' button. WID_SV_ACCEPTS_RATINGS = ::WID_SV_ACCEPTS_RATINGS, ///< 'Accepts' / 'Ratings' button. WID_SV_RENAME = ::WID_SV_RENAME, ///< 'Rename' button. WID_SV_CLOSE_AIRPORT = ::WID_SV_CLOSE_AIRPORT, ///< 'Close airport' button. WID_SV_TRAINS = ::WID_SV_TRAINS, ///< List of scheduled trains button. WID_SV_ROADVEHS = ::WID_SV_ROADVEHS, ///< List of scheduled road vehs button. WID_SV_SHIPS = ::WID_SV_SHIPS, ///< List of scheduled ships button. WID_SV_PLANES = ::WID_SV_PLANES, ///< List of scheduled planes button. }; /** Widgets of the #CompanyStationsWindow class. */ enum StationListWidgets { /* Name starts with ST instead of S, because of collision with SaveLoadWidgets */ WID_STL_CAPTION = ::WID_STL_CAPTION, ///< Caption of the window. WID_STL_LIST = ::WID_STL_LIST, ///< The main panel, list of stations. WID_STL_SCROLLBAR = ::WID_STL_SCROLLBAR, ///< Scrollbar next to the main panel. /* Vehicletypes need to be in order of StationFacility due to bit magic */ WID_STL_TRAIN = ::WID_STL_TRAIN, ///< 'TRAIN' button - list only facilities where is a railroad station. WID_STL_TRUCK = ::WID_STL_TRUCK, ///< 'TRUCK' button - list only facilities where is a truck stop. WID_STL_BUS = ::WID_STL_BUS, ///< 'BUS' button - list only facilities where is a bus stop. WID_STL_AIRPLANE = ::WID_STL_AIRPLANE, ///< 'AIRPLANE' button - list only facilities where is an airport. WID_STL_SHIP = ::WID_STL_SHIP, ///< 'SHIP' button - list only facilities where is a dock. WID_STL_FACILALL = ::WID_STL_FACILALL, ///< 'ALL' button - list all facilities. WID_STL_NOCARGOWAITING = ::WID_STL_NOCARGOWAITING, ///< 'NO' button - list stations where no cargo is waiting. WID_STL_CARGOALL = ::WID_STL_CARGOALL, ///< 'ALL' button - list all stations. WID_STL_SORTBY = ::WID_STL_SORTBY, ///< 'Sort by' button - reverse sort direction. WID_STL_SORTDROPBTN = ::WID_STL_SORTDROPBTN, ///< Dropdown button. WID_STL_CARGOSTART = ::WID_STL_CARGOSTART, ///< Widget numbers used for list of cargo types (not present in _company_stations_widgets). }; /** Widgets of the #SelectStationWindow class. */ enum JoinStationWidgets { WID_JS_CAPTION = ::WID_JS_CAPTION, // Caption of the window. WID_JS_PANEL = ::WID_JS_PANEL, // Main panel. WID_JS_SCROLLBAR = ::WID_JS_SCROLLBAR, // Scrollbar of the panel. }; /* automatically generated from ../../widgets/statusbar_widget.h */ /** Widgets of the #StatusBarWindow class. */ enum StatusbarWidgets { WID_S_LEFT = ::WID_S_LEFT, ///< Left part of the statusbar; date is shown there. WID_S_MIDDLE = ::WID_S_MIDDLE, ///< Middle part; current news or company name or *** SAVING *** or *** PAUSED ***. WID_S_RIGHT = ::WID_S_RIGHT, ///< Right part; bank balance. }; /* automatically generated from ../../widgets/story_widget.h */ /** Widgets of the #GoalListWindow class. */ enum StoryBookWidgets { WID_SB_CAPTION = ::WID_SB_CAPTION, ///< Caption of the window. WID_SB_SEL_PAGE = ::WID_SB_SEL_PAGE, ///< Page selector. WID_SB_PAGE_PANEL = ::WID_SB_PAGE_PANEL, ///< Page body. WID_SB_SCROLLBAR = ::WID_SB_SCROLLBAR, ///< Scrollbar of the goal list. WID_SB_PREV_PAGE = ::WID_SB_PREV_PAGE, ///< Prev button. WID_SB_NEXT_PAGE = ::WID_SB_NEXT_PAGE, ///< Next button. }; /* automatically generated from ../../widgets/subsidy_widget.h */ /** Widgets of the #SubsidyListWindow class. */ enum SubsidyListWidgets { /* Name starts with SU instead of S, because of collision with SaveLoadWidgets. */ WID_SUL_PANEL = ::WID_SUL_PANEL, ///< Main panel of window. WID_SUL_SCROLLBAR = ::WID_SUL_SCROLLBAR, ///< Scrollbar of panel. }; /* automatically generated from ../../widgets/terraform_widget.h */ /** Widgets of the #TerraformToolbarWindow class. */ enum TerraformToolbarWidgets { WID_TT_SHOW_PLACE_OBJECT = ::WID_TT_SHOW_PLACE_OBJECT, ///< Should the place object button be shown? WID_TT_BUTTONS_START = ::WID_TT_BUTTONS_START, ///< Start of pushable buttons. WID_TT_LOWER_LAND = ::WID_TT_LOWER_LAND, ///< Lower land button. WID_TT_RAISE_LAND = ::WID_TT_RAISE_LAND, ///< Raise land button. WID_TT_LEVEL_LAND = ::WID_TT_LEVEL_LAND, ///< Level land button. WID_TT_DEMOLISH = ::WID_TT_DEMOLISH, ///< Demolish aka dynamite button. WID_TT_BUY_LAND = ::WID_TT_BUY_LAND, ///< Buy land button. WID_TT_PLANT_TREES = ::WID_TT_PLANT_TREES, ///< Plant trees button (note: opens separate window, no place-push-button). WID_TT_PLACE_SIGN = ::WID_TT_PLACE_SIGN, ///< Place sign button. WID_TT_PLACE_OBJECT = ::WID_TT_PLACE_OBJECT, ///< Place object button. }; /** Widgets of the #ScenarioEditorLandscapeGenerationWindow class. */ enum EditorTerraformToolbarWidgets { WID_ETT_SHOW_PLACE_DESERT = ::WID_ETT_SHOW_PLACE_DESERT, ///< Should the place desert button be shown? WID_ETT_START = ::WID_ETT_START, ///< Used for iterations. WID_ETT_DOTS = ::WID_ETT_DOTS, ///< Invisible widget for rendering the terraform size on. WID_ETT_BUTTONS_START = ::WID_ETT_BUTTONS_START, ///< Start of pushable buttons. WID_ETT_DEMOLISH = ::WID_ETT_DEMOLISH, ///< Demolish aka dynamite button. WID_ETT_LOWER_LAND = ::WID_ETT_LOWER_LAND, ///< Lower land button. WID_ETT_RAISE_LAND = ::WID_ETT_RAISE_LAND, ///< Raise land button. WID_ETT_LEVEL_LAND = ::WID_ETT_LEVEL_LAND, ///< Level land button. WID_ETT_PLACE_ROCKS = ::WID_ETT_PLACE_ROCKS, ///< Place rocks button. WID_ETT_PLACE_DESERT = ::WID_ETT_PLACE_DESERT, ///< Place desert button (in tropical climate). WID_ETT_PLACE_OBJECT = ::WID_ETT_PLACE_OBJECT, ///< Place transmitter button. WID_ETT_BUTTONS_END = ::WID_ETT_BUTTONS_END, ///< End of pushable buttons. WID_ETT_INCREASE_SIZE = ::WID_ETT_INCREASE_SIZE, ///< Upwards arrow button to increase terraforming size. WID_ETT_DECREASE_SIZE = ::WID_ETT_DECREASE_SIZE, ///< Downwards arrow button to decrease terraforming size. WID_ETT_NEW_SCENARIO = ::WID_ETT_NEW_SCENARIO, ///< Button for generating a new scenario. WID_ETT_RESET_LANDSCAPE = ::WID_ETT_RESET_LANDSCAPE, ///< Button for removing all company-owned property. }; /* automatically generated from ../../widgets/timetable_widget.h */ /** Widgets of the #TimetableWindow class. */ enum VehicleTimetableWidgets { WID_VT_CAPTION = ::WID_VT_CAPTION, ///< Caption of the window. WID_VT_ORDER_VIEW = ::WID_VT_ORDER_VIEW, ///< Order view. WID_VT_TIMETABLE_PANEL = ::WID_VT_TIMETABLE_PANEL, ///< Timetable panel. WID_VT_ARRIVAL_DEPARTURE_PANEL = ::WID_VT_ARRIVAL_DEPARTURE_PANEL, ///< Panel with the expected/scheduled arrivals. WID_VT_SCROLLBAR = ::WID_VT_SCROLLBAR, ///< Scrollbar for the panel. WID_VT_SUMMARY_PANEL = ::WID_VT_SUMMARY_PANEL, ///< Summary panel. WID_VT_START_DATE = ::WID_VT_START_DATE, ///< Start date button. WID_VT_CHANGE_TIME = ::WID_VT_CHANGE_TIME, ///< Change time button. WID_VT_CLEAR_TIME = ::WID_VT_CLEAR_TIME, ///< Clear time button. WID_VT_RESET_LATENESS = ::WID_VT_RESET_LATENESS, ///< Reset lateness button. WID_VT_AUTOFILL = ::WID_VT_AUTOFILL, ///< Autofill button. WID_VT_EXPECTED = ::WID_VT_EXPECTED, ///< Toggle between expected and scheduled arrivals. WID_VT_SHARED_ORDER_LIST = ::WID_VT_SHARED_ORDER_LIST, ///< Show the shared order list. WID_VT_ARRIVAL_DEPARTURE_SELECTION = ::WID_VT_ARRIVAL_DEPARTURE_SELECTION, ///< Disable/hide the arrival departure panel. WID_VT_EXPECTED_SELECTION = ::WID_VT_EXPECTED_SELECTION, ///< Disable/hide the expected selection button. WID_VT_CHANGE_SPEED = ::WID_VT_CHANGE_SPEED, ///< Change speed limit button. WID_VT_CLEAR_SPEED = ::WID_VT_CLEAR_SPEED, ///< Clear speed limit button. }; /* automatically generated from ../../widgets/toolbar_widget.h */ /** Widgets of the #MainToolbarWindow class. */ enum ToolbarNormalWidgets { WID_TN_PAUSE = ::WID_TN_PAUSE, ///< Pause the game. WID_TN_FAST_FORWARD = ::WID_TN_FAST_FORWARD, ///< Fast forward the game. WID_TN_SETTINGS = ::WID_TN_SETTINGS, ///< Settings menu. WID_TN_SAVE = ::WID_TN_SAVE, ///< Save menu. WID_TN_SMALL_MAP = ::WID_TN_SMALL_MAP, ///< Small map menu. WID_TN_TOWNS = ::WID_TN_TOWNS, ///< Town menu. WID_TN_SUBSIDIES = ::WID_TN_SUBSIDIES, ///< Subsidy menu. WID_TN_STATIONS = ::WID_TN_STATIONS, ///< Station menu. WID_TN_FINANCES = ::WID_TN_FINANCES, ///< Finance menu. WID_TN_COMPANIES = ::WID_TN_COMPANIES, ///< Company menu. WID_TN_STORY = ::WID_TN_STORY, ///< Story menu. WID_TN_GOAL = ::WID_TN_GOAL, ///< Goal menu. WID_TN_GRAPHS = ::WID_TN_GRAPHS, ///< Graph menu. WID_TN_LEAGUE = ::WID_TN_LEAGUE, ///< Company league menu. WID_TN_INDUSTRIES = ::WID_TN_INDUSTRIES, ///< Industry menu. WID_TN_VEHICLE_START = ::WID_TN_VEHICLE_START, ///< Helper for the offset of the vehicle menus. WID_TN_TRAINS = ::WID_TN_TRAINS, ///< Train menu. WID_TN_ROADVEHS = ::WID_TN_ROADVEHS, ///< Road vehicle menu. WID_TN_SHIPS = ::WID_TN_SHIPS, ///< Ship menu. WID_TN_AIRCRAFTS = ::WID_TN_AIRCRAFTS, ///< Aircraft menu. WID_TN_ZOOM_IN = ::WID_TN_ZOOM_IN, ///< Zoom in the main viewport. WID_TN_ZOOM_OUT = ::WID_TN_ZOOM_OUT, ///< Zoom out the main viewport. WID_TN_RAILS = ::WID_TN_RAILS, ///< Rail building menu. WID_TN_ROADS = ::WID_TN_ROADS, ///< Road building menu. WID_TN_WATER = ::WID_TN_WATER, ///< Water building toolbar. WID_TN_AIR = ::WID_TN_AIR, ///< Airport building toolbar. WID_TN_LANDSCAPE = ::WID_TN_LANDSCAPE, ///< Landscaping toolbar. WID_TN_MUSIC_SOUND = ::WID_TN_MUSIC_SOUND, ///< Music/sound configuration menu. WID_TN_MESSAGES = ::WID_TN_MESSAGES, ///< Messages menu. WID_TN_HELP = ::WID_TN_HELP, ///< Help menu. WID_TN_SWITCH_BAR = ::WID_TN_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. WID_TN_END = ::WID_TN_END, ///< Helper for knowing the amount of widgets. }; /** Widgets of the #ScenarioEditorToolbarWindow class. */ enum ToolbarEditorWidgets { WID_TE_PAUSE = ::WID_TE_PAUSE, ///< Pause the game. WID_TE_FAST_FORWARD = ::WID_TE_FAST_FORWARD, ///< Fast forward the game. WID_TE_SETTINGS = ::WID_TE_SETTINGS, ///< Settings menu. WID_TE_SAVE = ::WID_TE_SAVE, ///< Save menu. WID_TE_SPACER = ::WID_TE_SPACER, ///< Spacer with "scenario editor" text. WID_TE_DATE = ::WID_TE_DATE, ///< The date of the scenario. WID_TE_DATE_BACKWARD = ::WID_TE_DATE_BACKWARD, ///< Reduce the date of the scenario. WID_TE_DATE_FORWARD = ::WID_TE_DATE_FORWARD, ///< Increase the date of the scenario. WID_TE_SMALL_MAP = ::WID_TE_SMALL_MAP, ///< Small map menu. WID_TE_ZOOM_IN = ::WID_TE_ZOOM_IN, ///< Zoom in the main viewport. WID_TE_ZOOM_OUT = ::WID_TE_ZOOM_OUT, ///< Zoom out the main viewport. WID_TE_LAND_GENERATE = ::WID_TE_LAND_GENERATE, ///< Land generation. WID_TE_TOWN_GENERATE = ::WID_TE_TOWN_GENERATE, ///< Town building window. WID_TE_INDUSTRY = ::WID_TE_INDUSTRY, ///< Industry building window. WID_TE_ROADS = ::WID_TE_ROADS, ///< Road building menu. WID_TE_WATER = ::WID_TE_WATER, ///< Water building toolbar. WID_TE_TREES = ::WID_TE_TREES, ///< Tree building toolbar. WID_TE_SIGNS = ::WID_TE_SIGNS, ///< Sign building. WID_TE_DATE_PANEL = ::WID_TE_DATE_PANEL, ///< Container for the date widgets. /* The following three need to have the same actual widget number as the normal toolbar due to shared code. */ WID_TE_MUSIC_SOUND = ::WID_TE_MUSIC_SOUND, ///< Music/sound configuration menu. WID_TE_HELP = ::WID_TE_HELP, ///< Help menu. WID_TE_SWITCH_BAR = ::WID_TE_SWITCH_BAR, ///< Only available when toolbar has been split to switch between different subsets. }; /* automatically generated from ../../widgets/town_widget.h */ /** Widgets of the #TownDirectoryWindow class. */ enum TownDirectoryWidgets { WID_TD_SORT_ORDER = ::WID_TD_SORT_ORDER, ///< Direction of sort dropdown. WID_TD_SORT_CRITERIA = ::WID_TD_SORT_CRITERIA, ///< Criteria of sort dropdown. WID_TD_LIST = ::WID_TD_LIST, ///< List of towns. WID_TD_SCROLLBAR = ::WID_TD_SCROLLBAR, ///< Scrollbar for the town list. WID_TD_WORLD_POPULATION = ::WID_TD_WORLD_POPULATION, ///< The world's population. }; /** Widgets of the #TownAuthorityWindow class. */ enum TownAuthorityWidgets { WID_TA_CAPTION = ::WID_TA_CAPTION, ///< Caption of window. WID_TA_RATING_INFO = ::WID_TA_RATING_INFO, ///< Overview with ratings for each company. WID_TA_COMMAND_LIST = ::WID_TA_COMMAND_LIST, ///< List of commands for the player. WID_TA_SCROLLBAR = ::WID_TA_SCROLLBAR, ///< Scrollbar of the list of commands. WID_TA_ACTION_INFO = ::WID_TA_ACTION_INFO, ///< Additional information about the action. WID_TA_EXECUTE = ::WID_TA_EXECUTE, ///< Do-it button. }; /** Widgets of the #TownViewWindow class. */ enum TownViewWidgets { WID_TV_CAPTION = ::WID_TV_CAPTION, ///< Caption of window. WID_TV_VIEWPORT = ::WID_TV_VIEWPORT, ///< View of the center of the town. WID_TV_INFO = ::WID_TV_INFO, ///< General information about the town. WID_TV_CENTER_VIEW = ::WID_TV_CENTER_VIEW, ///< Center the main view on this town. WID_TV_SHOW_AUTHORITY = ::WID_TV_SHOW_AUTHORITY, ///< Show the town authority window. WID_TV_CHANGE_NAME = ::WID_TV_CHANGE_NAME, ///< Change the name of this town. WID_TV_EXPAND = ::WID_TV_EXPAND, ///< Expand this town (scenario editor only). WID_TV_DELETE = ::WID_TV_DELETE, ///< Delete this town (scenario editor only). }; /** Widgets of the #FoundTownWindow class. */ enum TownFoundingWidgets { WID_TF_NEW_TOWN = ::WID_TF_NEW_TOWN, ///< Create a new town. WID_TF_RANDOM_TOWN = ::WID_TF_RANDOM_TOWN, ///< Randomly place a town. WID_TF_MANY_RANDOM_TOWNS = ::WID_TF_MANY_RANDOM_TOWNS, ///< Randomly place many towns. WID_TF_TOWN_NAME_EDITBOX = ::WID_TF_TOWN_NAME_EDITBOX, ///< Editor for the town name. WID_TF_TOWN_NAME_RANDOM = ::WID_TF_TOWN_NAME_RANDOM, ///< Generate a random town name. WID_TF_SIZE_SMALL = ::WID_TF_SIZE_SMALL, ///< Selection for a small town. WID_TF_SIZE_MEDIUM = ::WID_TF_SIZE_MEDIUM, ///< Selection for a medium town. WID_TF_SIZE_LARGE = ::WID_TF_SIZE_LARGE, ///< Selection for a large town. WID_TF_SIZE_RANDOM = ::WID_TF_SIZE_RANDOM, ///< Selection for a randomly sized town. WID_TF_CITY = ::WID_TF_CITY, ///< Selection for the town's city state. WID_TF_LAYOUT_ORIGINAL = ::WID_TF_LAYOUT_ORIGINAL, ///< Selection for the original town layout. WID_TF_LAYOUT_BETTER = ::WID_TF_LAYOUT_BETTER, ///< Selection for the better town layout. WID_TF_LAYOUT_GRID2 = ::WID_TF_LAYOUT_GRID2, ///< Selection for the 2x2 grid town layout. WID_TF_LAYOUT_GRID3 = ::WID_TF_LAYOUT_GRID3, ///< Selection for the 3x3 grid town layout. WID_TF_LAYOUT_RANDOM = ::WID_TF_LAYOUT_RANDOM, ///< Selection for a randomly chosen town layout. }; /* automatically generated from ../../widgets/transparency_widget.h */ /** Widgets of the #TransparenciesWindow class. */ enum TransparencyToolbarWidgets { /* Button row. */ WID_TT_BEGIN = ::WID_TT_BEGIN, ///< First toggle button. WID_TT_SIGNS = ::WID_TT_SIGNS, ///< Signs background transparency toggle button. WID_TT_TREES = ::WID_TT_TREES, ///< Trees transparency toggle button. WID_TT_HOUSES = ::WID_TT_HOUSES, ///< Houses transparency toggle button. WID_TT_INDUSTRIES = ::WID_TT_INDUSTRIES, ///< industries transparency toggle button. WID_TT_BUILDINGS = ::WID_TT_BUILDINGS, ///< Company buildings and structures transparency toggle button. WID_TT_BRIDGES = ::WID_TT_BRIDGES, ///< Bridges transparency toggle button. WID_TT_STRUCTURES = ::WID_TT_STRUCTURES, ///< Object structure transparency toggle button. WID_TT_CATENARY = ::WID_TT_CATENARY, ///< Catenary transparency toggle button. WID_TT_LOADING = ::WID_TT_LOADING, ///< Loading indicators transparency toggle button. WID_TT_END = ::WID_TT_END, ///< End of toggle buttons. /* Panel with buttons for invisibility */ WID_TT_BUTTONS = ::WID_TT_BUTTONS, ///< Panel with 'invisibility' buttons. }; /* automatically generated from ../../widgets/tree_widget.h */ /** Widgets of the #BuildTreesWindow class. */ enum BuildTreesWidgets { WID_BT_TYPE_11 = ::WID_BT_TYPE_11, ///< Tree 1st column 1st row. WID_BT_TYPE_12 = ::WID_BT_TYPE_12, ///< Tree 1st column 2nd row. WID_BT_TYPE_13 = ::WID_BT_TYPE_13, ///< Tree 1st column 3rd row. WID_BT_TYPE_14 = ::WID_BT_TYPE_14, ///< Tree 1st column 4th row. WID_BT_TYPE_21 = ::WID_BT_TYPE_21, ///< Tree 2st column 1st row. WID_BT_TYPE_22 = ::WID_BT_TYPE_22, ///< Tree 2st column 2nd row. WID_BT_TYPE_23 = ::WID_BT_TYPE_23, ///< Tree 2st column 3rd row. WID_BT_TYPE_24 = ::WID_BT_TYPE_24, ///< Tree 2st column 4th row. WID_BT_TYPE_31 = ::WID_BT_TYPE_31, ///< Tree 3st column 1st row. WID_BT_TYPE_32 = ::WID_BT_TYPE_32, ///< Tree 3st column 2nd row. WID_BT_TYPE_33 = ::WID_BT_TYPE_33, ///< Tree 3st column 3rd row. WID_BT_TYPE_34 = ::WID_BT_TYPE_34, ///< Tree 3st column 4th row. WID_BT_TYPE_RANDOM = ::WID_BT_TYPE_RANDOM, ///< Button to build random type of tree. WID_BT_MANY_RANDOM = ::WID_BT_MANY_RANDOM, ///< Button to build many random trees. }; /* automatically generated from ../../widgets/vehicle_widget.h */ /** Widgets of the #VehicleViewWindow class. */ enum VehicleViewWidgets { WID_VV_CAPTION = ::WID_VV_CAPTION, ///< Caption of window. WID_VV_VIEWPORT = ::WID_VV_VIEWPORT, ///< Viewport widget. WID_VV_START_STOP = ::WID_VV_START_STOP, ///< Start or stop this vehicle, and show information about the current state. WID_VV_CENTER_MAIN_VIEW = ::WID_VV_CENTER_MAIN_VIEW, ///< Center the main view on this vehicle. WID_VV_GOTO_DEPOT = ::WID_VV_GOTO_DEPOT, ///< Order this vehicle to go to the depot. WID_VV_REFIT = ::WID_VV_REFIT, ///< Open the refit window. WID_VV_SHOW_ORDERS = ::WID_VV_SHOW_ORDERS, ///< Show the orders of this vehicle. WID_VV_SHOW_DETAILS = ::WID_VV_SHOW_DETAILS, ///< Show details of this vehicle. WID_VV_CLONE = ::WID_VV_CLONE, ///< Clone this vehicle. WID_VV_SELECT_DEPOT_CLONE = ::WID_VV_SELECT_DEPOT_CLONE, ///< Selection widget between 'goto depot', and 'clone vehicle' buttons. WID_VV_SELECT_REFIT_TURN = ::WID_VV_SELECT_REFIT_TURN, ///< Selection widget between 'refit' and 'turn around' buttons. WID_VV_TURN_AROUND = ::WID_VV_TURN_AROUND, ///< Turn this vehicle around. WID_VV_FORCE_PROCEED = ::WID_VV_FORCE_PROCEED, ///< Force this vehicle to pass a signal at danger. }; /** Widgets of the #RefitWindow class. */ enum VehicleRefitWidgets { WID_VR_CAPTION = ::WID_VR_CAPTION, ///< Caption of window. WID_VR_VEHICLE_PANEL_DISPLAY = ::WID_VR_VEHICLE_PANEL_DISPLAY, ///< Display with a representation of the vehicle to refit. WID_VR_SHOW_HSCROLLBAR = ::WID_VR_SHOW_HSCROLLBAR, ///< Selection widget for the horizontal scrollbar. WID_VR_HSCROLLBAR = ::WID_VR_HSCROLLBAR, ///< Horizontal scrollbar or the vehicle display. WID_VR_SELECT_HEADER = ::WID_VR_SELECT_HEADER, ///< Header with question about the cargo to carry. WID_VR_MATRIX = ::WID_VR_MATRIX, ///< Options to refit to. WID_VR_SCROLLBAR = ::WID_VR_SCROLLBAR, ///< Scrollbar for the refit options. WID_VR_INFO = ::WID_VR_INFO, ///< Information about the currently selected refit option. WID_VR_REFIT = ::WID_VR_REFIT, ///< Perform the refit. }; /** Widgets of the #VehicleDetailsWindow class. */ enum VehicleDetailsWidgets { WID_VD_CAPTION = ::WID_VD_CAPTION, ///< Caption of window. WID_VD_RENAME_VEHICLE = ::WID_VD_RENAME_VEHICLE, ///< Rename this vehicle. WID_VD_TOP_DETAILS = ::WID_VD_TOP_DETAILS, ///< Panel with generic details. WID_VD_INCREASE_SERVICING_INTERVAL = ::WID_VD_INCREASE_SERVICING_INTERVAL, ///< Increase the servicing interval. WID_VD_DECREASE_SERVICING_INTERVAL = ::WID_VD_DECREASE_SERVICING_INTERVAL, ///< Decrease the servicing interval. WID_VD_SERVICE_INTERVAL_DROPDOWN = ::WID_VD_SERVICE_INTERVAL_DROPDOWN, ///< Dropdown to select default/days/percent service interval. WID_VD_SERVICING_INTERVAL = ::WID_VD_SERVICING_INTERVAL, ///< Information about the servicing interval. WID_VD_MIDDLE_DETAILS = ::WID_VD_MIDDLE_DETAILS, ///< Details for non-trains. WID_VD_MATRIX = ::WID_VD_MATRIX, ///< List of details for trains. WID_VD_SCROLLBAR = ::WID_VD_SCROLLBAR, ///< Scrollbar for train details. WID_VD_DETAILS_CARGO_CARRIED = ::WID_VD_DETAILS_CARGO_CARRIED, ///< Show carried cargo per part of the train. WID_VD_DETAILS_TRAIN_VEHICLES = ::WID_VD_DETAILS_TRAIN_VEHICLES, ///< Show all parts of the train with their description. WID_VD_DETAILS_CAPACITY_OF_EACH = ::WID_VD_DETAILS_CAPACITY_OF_EACH, ///< Show the capacity of all train parts. WID_VD_DETAILS_TOTAL_CARGO = ::WID_VD_DETAILS_TOTAL_CARGO, ///< Show the capacity and carried cargo amounts aggregated per cargo of the train. }; /** Widgets of the #VehicleListWindow class. */ enum VehicleListWidgets { WID_VL_CAPTION = ::WID_VL_CAPTION, ///< Caption of window. WID_VL_SORT_ORDER = ::WID_VL_SORT_ORDER, ///< Sort order. WID_VL_SORT_BY_PULLDOWN = ::WID_VL_SORT_BY_PULLDOWN, ///< Sort by dropdown list. WID_VL_LIST = ::WID_VL_LIST, ///< List of the vehicles. WID_VL_SCROLLBAR = ::WID_VL_SCROLLBAR, ///< Scrollbar for the list. WID_VL_HIDE_BUTTONS = ::WID_VL_HIDE_BUTTONS, ///< Selection to hide the buttons. WID_VL_AVAILABLE_VEHICLES = ::WID_VL_AVAILABLE_VEHICLES, ///< Available vehicles. WID_VL_MANAGE_VEHICLES_DROPDOWN = ::WID_VL_MANAGE_VEHICLES_DROPDOWN, ///< Manage vehicles dropdown list. WID_VL_STOP_ALL = ::WID_VL_STOP_ALL, ///< Stop all button. WID_VL_START_ALL = ::WID_VL_START_ALL, ///< Start all button. }; /* automatically generated from ../../widgets/viewport_widget.h */ /** Widgets of the #ExtraViewportWindow class. */ enum ExtraViewportWidgets { WID_EV_CAPTION = ::WID_EV_CAPTION, ///< Caption of window. WID_EV_VIEWPORT = ::WID_EV_VIEWPORT, ///< The viewport. WID_EV_ZOOM_IN = ::WID_EV_ZOOM_IN, ///< Zoom in. WID_EV_ZOOM_OUT = ::WID_EV_ZOOM_OUT, ///< Zoom out. WID_EV_MAIN_TO_VIEW = ::WID_EV_MAIN_TO_VIEW, ///< Center the view of this viewport on the main view. WID_EV_VIEW_TO_MAIN = ::WID_EV_VIEW_TO_MAIN, ///< Center the main view on the view of this viewport. }; /* automatically generated from ../../widgets/waypoint_widget.h */ /** Widgets of the #WaypointWindow class. */ enum WaypointWidgets { WID_W_CAPTION = ::WID_W_CAPTION, ///< Caption of window. WID_W_VIEWPORT = ::WID_W_VIEWPORT, ///< The viewport on this waypoint. WID_W_CENTER_VIEW = ::WID_W_CENTER_VIEW, ///< Center the main view on this waypoint. WID_W_RENAME = ::WID_W_RENAME, ///< Rename this waypoint. WID_W_SHOW_VEHICLES = ::WID_W_SHOW_VEHICLES, ///< Show the vehicles visiting this waypoint. }; // @endenum }; #endif /* SCRIPT_WINDOW_HPP */ openttd-1.5.3/src/script/api/script_storypageelementlist.cpp0000644000000000000000000000225412627373434023130 0ustar rootroot/* $Id: script_storypageelementlist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_storypageelementlist.cpp Implementation of ScriptStoryPageElementList and friends. */ #include "../../stdafx.h" #include "script_storypageelementlist.hpp" #include "../../story_base.h" #include "../../safeguards.h" ScriptStoryPageElementList::ScriptStoryPageElementList(ScriptStoryPage::StoryPageID story_page_id) { if (!ScriptStoryPage::IsValidStoryPage(story_page_id)) return; StoryPageElement *pe; FOR_ALL_STORY_PAGE_ELEMENTS(pe) { if (pe->page == story_page_id) { this->AddItem(pe->index); } } } openttd-1.5.3/src/script/api/script_town.cpp0000644000000000000000000002740212627373434017636 0ustar rootroot/* $Id: script_town.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 script_town.cpp Implementation of ScriptTown. */ #include "../../stdafx.h" #include "script_town.hpp" #include "script_map.hpp" #include "script_error.hpp" #include "../../town.h" #include "../../townname_func.h" #include "../../string_func.h" #include "../../strings_func.h" #include "../../station_base.h" #include "../../landscape.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ int32 ScriptTown::GetTownCount() { return (int32)::Town::GetNumItems(); } /* static */ bool ScriptTown::IsValidTown(TownID town_id) { return ::Town::IsValidID(town_id); } /* static */ char *ScriptTown::GetName(TownID town_id) { if (!IsValidTown(town_id)) return NULL; ::SetDParam(0, town_id); return GetString(STR_TOWN_NAME); } /* static */ bool ScriptTown::SetName(TownID town_id, Text *name) { CCountedPtr counter(name); const char *text = NULL; if (name != NULL) { text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); } EnforcePrecondition(false, IsValidTown(town_id)); return ScriptObject::DoCommand(0, town_id, 0, CMD_RENAME_TOWN, text); } /* static */ bool ScriptTown::SetText(TownID town_id, Text *text) { CCountedPtr counter(text); EnforcePrecondition(false, text != NULL); const char *encoded_text = text->GetEncodedText(); EnforcePreconditionEncodedText(false, encoded_text); EnforcePrecondition(false, IsValidTown(town_id)); return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, 0, CMD_TOWN_SET_TEXT, encoded_text); } /* static */ int32 ScriptTown::GetPopulation(TownID town_id) { if (!IsValidTown(town_id)) return -1; const Town *t = ::Town::Get(town_id); return t->cache.population; } /* static */ int32 ScriptTown::GetHouseCount(TownID town_id) { if (!IsValidTown(town_id)) return -1; const Town *t = ::Town::Get(town_id); return t->cache.num_houses; } /* static */ TileIndex ScriptTown::GetLocation(TownID town_id) { if (!IsValidTown(town_id)) return INVALID_TILE; const Town *t = ::Town::Get(town_id); return t->xy; } /* static */ int32 ScriptTown::GetLastMonthProduction(TownID town_id, CargoID cargo_id) { if (!IsValidTown(town_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo_id)) return -1; const Town *t = ::Town::Get(town_id); return t->supplied[cargo_id].old_max; } /* static */ int32 ScriptTown::GetLastMonthSupplied(TownID town_id, CargoID cargo_id) { if (!IsValidTown(town_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo_id)) return -1; const Town *t = ::Town::Get(town_id); return t->supplied[cargo_id].old_act; } /* static */ int32 ScriptTown::GetLastMonthTransportedPercentage(TownID town_id, CargoID cargo_id) { if (!IsValidTown(town_id)) return -1; if (!ScriptCargo::IsValidCargo(cargo_id)) return -1; const Town *t = ::Town::Get(town_id); return ::ToPercent8(t->GetPercentTransported(cargo_id)); } /* static */ int32 ScriptTown::GetLastMonthReceived(TownID town_id, ScriptCargo::TownEffect towneffect_id) { if (!IsValidTown(town_id)) return -1; if (!ScriptCargo::IsValidTownEffect(towneffect_id)) return -1; const Town *t = ::Town::Get(town_id); return t->received[towneffect_id].old_act; } /* static */ bool ScriptTown::SetCargoGoal(TownID town_id, ScriptCargo::TownEffect towneffect_id, uint32 goal) { EnforcePrecondition(false, IsValidTown(town_id)); EnforcePrecondition(false, ScriptCargo::IsValidTownEffect(towneffect_id)); return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id | (towneffect_id << 16), goal, CMD_TOWN_CARGO_GOAL); } /* static */ uint32 ScriptTown::GetCargoGoal(TownID town_id, ScriptCargo::TownEffect towneffect_id) { if (!IsValidTown(town_id)) return UINT32_MAX; if (!ScriptCargo::IsValidTownEffect(towneffect_id)) return UINT32_MAX; const Town *t = ::Town::Get(town_id); switch (t->goal[towneffect_id]) { case TOWN_GROWTH_WINTER: if (TileHeight(t->xy) >= GetSnowLine() && t->cache.population > 90) return 1; return 0; case TOWN_GROWTH_DESERT: if (GetTropicZone(t->xy) == TROPICZONE_DESERT && t->cache.population > 60) return 1; return 0; default: return t->goal[towneffect_id]; } } /* static */ bool ScriptTown::SetGrowthRate(TownID town_id, uint32 days_between_town_growth) { EnforcePrecondition(false, IsValidTown(town_id)); switch (days_between_town_growth) { case TOWN_GROWTH_NORMAL: days_between_town_growth = 0; break; case TOWN_GROWTH_NONE: days_between_town_growth = TOWN_GROW_RATE_CUSTOM_NONE; break; default: days_between_town_growth = days_between_town_growth * DAY_TICKS / TOWN_GROWTH_TICKS; EnforcePrecondition(false, days_between_town_growth < TOWN_GROW_RATE_CUSTOM); if (days_between_town_growth == 0) days_between_town_growth = 1; // as fast as possible break; } return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, days_between_town_growth, CMD_TOWN_GROWTH_RATE); } /* static */ int32 ScriptTown::GetGrowthRate(TownID town_id) { if (!IsValidTown(town_id)) return -1; const Town *t = ::Town::Get(town_id); if (t->growth_rate == TOWN_GROW_RATE_CUSTOM_NONE) return TOWN_GROWTH_NONE; return ((t->growth_rate & ~TOWN_GROW_RATE_CUSTOM) * TOWN_GROWTH_TICKS + DAY_TICKS) / DAY_TICKS; } /* static */ int32 ScriptTown::GetDistanceManhattanToTile(TownID town_id, TileIndex tile) { return ScriptMap::DistanceManhattan(tile, GetLocation(town_id)); } /* static */ int32 ScriptTown::GetDistanceSquareToTile(TownID town_id, TileIndex tile) { return ScriptMap::DistanceSquare(tile, GetLocation(town_id)); } /* static */ bool ScriptTown::IsWithinTownInfluence(TownID town_id, TileIndex tile) { if (!IsValidTown(town_id)) return false; const Town *t = ::Town::Get(town_id); return ((uint32)GetDistanceSquareToTile(town_id, tile) <= t->cache.squared_town_zone_radius[0]); } /* static */ bool ScriptTown::HasStatue(TownID town_id) { if (ScriptObject::GetCompany() == OWNER_DEITY) return false; if (!IsValidTown(town_id)) return false; return ::HasBit(::Town::Get(town_id)->statues, ScriptObject::GetCompany()); } /* static */ bool ScriptTown::IsCity(TownID town_id) { if (!IsValidTown(town_id)) return false; return ::Town::Get(town_id)->larger_town; } /* static */ int ScriptTown::GetRoadReworkDuration(TownID town_id) { if (!IsValidTown(town_id)) return -1; return ::Town::Get(town_id)->road_build_months; } /* static */ int ScriptTown::GetFundBuildingsDuration(TownID town_id) { if (!IsValidTown(town_id)) return -1; return ::Town::Get(town_id)->fund_buildings_months; } /* static */ ScriptCompany::CompanyID ScriptTown::GetExclusiveRightsCompany(TownID town_id) { if (ScriptObject::GetCompany() == OWNER_DEITY) return ScriptCompany::COMPANY_INVALID; if (!IsValidTown(town_id)) return ScriptCompany::COMPANY_INVALID; return (ScriptCompany::CompanyID)(int8)::Town::Get(town_id)->exclusivity; } /* static */ int32 ScriptTown::GetExclusiveRightsDuration(TownID town_id) { if (!IsValidTown(town_id)) return -1; return ::Town::Get(town_id)->exclusive_counter; } /* static */ bool ScriptTown::IsActionAvailable(TownID town_id, TownAction town_action) { if (ScriptObject::GetCompany() == OWNER_DEITY) return false; if (!IsValidTown(town_id)) return false; return HasBit(::GetMaskOfTownActions(NULL, ScriptObject::GetCompany(), ::Town::Get(town_id)), town_action); } /* static */ bool ScriptTown::PerformTownAction(TownID town_id, TownAction town_action) { EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY); EnforcePrecondition(false, IsValidTown(town_id)); EnforcePrecondition(false, IsActionAvailable(town_id, town_action)); return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, town_action, CMD_DO_TOWN_ACTION); } /* static */ bool ScriptTown::ExpandTown(TownID town_id, int houses) { EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY); EnforcePrecondition(false, IsValidTown(town_id)); EnforcePrecondition(false, houses > 0); return ScriptObject::DoCommand(::Town::Get(town_id)->xy, town_id, houses, CMD_EXPAND_TOWN); } /* static */ bool ScriptTown::FoundTown(TileIndex tile, TownSize size, bool city, RoadLayout layout, Text *name) { CCountedPtr counter(name); EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY || _settings_game.economy.found_town != TF_FORBIDDEN); EnforcePrecondition(false, ::IsValidTile(tile)); EnforcePrecondition(false, size == TOWN_SIZE_SMALL || size == TOWN_SIZE_MEDIUM || size == TOWN_SIZE_LARGE) EnforcePrecondition(false, size != TOWN_SIZE_LARGE || ScriptObject::GetCompany() == OWNER_DEITY); if (ScriptObject::GetCompany() == OWNER_DEITY || _settings_game.economy.found_town == TF_CUSTOM_LAYOUT) { EnforcePrecondition(false, layout == ROAD_LAYOUT_ORIGINAL || layout == ROAD_LAYOUT_BETTER_ROADS || layout == ROAD_LAYOUT_2x2 || layout == ROAD_LAYOUT_3x3); } else { /* The layout parameter is ignored for AIs when custom layouts is disabled. */ layout = (RoadLayout) (byte)_settings_game.economy.town_layout; } const char *text = NULL; if (name != NULL) { text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_TOWN_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); } uint32 townnameparts; if (!GenerateTownName(&townnameparts)) { ScriptObject::SetLastError(ScriptError::ERR_NAME_IS_NOT_UNIQUE); return false; } return ScriptObject::DoCommand(tile, size | (city ? 1 << 2 : 0) | layout << 3, townnameparts, CMD_FOUND_TOWN, text); } /* static */ ScriptTown::TownRating ScriptTown::GetRating(TownID town_id, ScriptCompany::CompanyID company_id) { if (!IsValidTown(town_id)) return TOWN_RATING_INVALID; ScriptCompany::CompanyID company = ScriptCompany::ResolveCompanyID(company_id); if (company == ScriptCompany::COMPANY_INVALID) return TOWN_RATING_INVALID; const Town *t = ::Town::Get(town_id); if (!HasBit(t->have_ratings, company)) { return TOWN_RATING_NONE; } else if (t->ratings[company] <= RATING_APPALLING) { return TOWN_RATING_APPALLING; } else if (t->ratings[company] <= RATING_VERYPOOR) { return TOWN_RATING_VERY_POOR; } else if (t->ratings[company] <= RATING_POOR) { return TOWN_RATING_POOR; } else if (t->ratings[company] <= RATING_MEDIOCRE) { return TOWN_RATING_MEDIOCRE; } else if (t->ratings[company] <= RATING_GOOD) { return TOWN_RATING_GOOD; } else if (t->ratings[company] <= RATING_VERYGOOD) { return TOWN_RATING_VERY_GOOD; } else if (t->ratings[company] <= RATING_EXCELLENT) { return TOWN_RATING_EXCELLENT; } else { return TOWN_RATING_OUTSTANDING; } } /* static */ int ScriptTown::GetAllowedNoise(TownID town_id) { if (!IsValidTown(town_id)) return -1; const Town *t = ::Town::Get(town_id); if (_settings_game.economy.station_noise_level) { return t->MaxTownNoise() - t->noise_reached; } int num = 0; const Station *st; FOR_ALL_STATIONS(st) { if (st->town == t && (st->facilities & FACIL_AIRPORT) && st->airport.type != AT_OILRIG) num++; } return max(0, 2 - num); } /* static */ ScriptTown::RoadLayout ScriptTown::GetRoadLayout(TownID town_id) { if (!IsValidTown(town_id)) return ROAD_LAYOUT_INVALID; return (ScriptTown::RoadLayout)((TownLayout)::Town::Get(town_id)->layout); } openttd-1.5.3/src/script/api/script_rail.hpp0000644000000000000000000005376512627373434017616 0ustar rootroot/* $Id: script_rail.hpp 25614 2013-07-15 18:19:26Z rubidium $ */ /* * 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 script_rail.hpp Everything to query and build rails. */ #ifndef SCRIPT_RAIL_HPP #define SCRIPT_RAIL_HPP #include "script_tile.hpp" #include "../../signal_type.h" #include "../../track_type.h" /** * Class that handles all rail related functions. * @api ai game */ class ScriptRail : public ScriptObject { public: /** * All rail related error messages. */ enum ErrorMessages { /** Base for rail building / maintaining errors */ ERR_RAIL_BASE = ScriptError::ERR_CAT_RAIL << ScriptError::ERR_CAT_BIT_SIZE, /** One-way roads cannot have crossings */ ERR_CROSSING_ON_ONEWAY_ROAD, // [STR_ERROR_CROSSING_ON_ONEWAY_ROAD] /** No suitable track could be found */ ERR_UNSUITABLE_TRACK, // [STR_ERROR_NO_SUITABLE_RAILROAD_TRACK, STR_ERROR_THERE_IS_NO_RAILROAD_TRACK, STR_ERROR_THERE_ARE_NO_SIGNALS, STR_ERROR_THERE_IS_NO_STATION] /** This railtype cannot have crossings */ ERR_RAILTYPE_DISALLOWS_CROSSING, // [STR_ERROR_CROSSING_DISALLOWED] }; /** * Types of rail known to the game. */ enum RailType { /* Note: these values represent part of the in-game static values */ RAILTYPE_INVALID = ::INVALID_RAILTYPE, ///< Invalid RailType. }; /** * A bitmap with all possible rail tracks on a tile. */ enum RailTrack { /* Note: these values represent part of the in-game TrackBits enum */ RAILTRACK_NE_SW = ::TRACK_BIT_X, ///< Track along the x-axis (north-east to south-west). RAILTRACK_NW_SE = ::TRACK_BIT_Y, ///< Track along the y-axis (north-west to south-east). RAILTRACK_NW_NE = ::TRACK_BIT_UPPER, ///< Track in the upper corner of the tile (north). RAILTRACK_SW_SE = ::TRACK_BIT_LOWER, ///< Track in the lower corner of the tile (south). RAILTRACK_NW_SW = ::TRACK_BIT_LEFT, ///< Track in the left corner of the tile (west). RAILTRACK_NE_SE = ::TRACK_BIT_RIGHT, ///< Track in the right corner of the tile (east). RAILTRACK_INVALID = ::INVALID_TRACK_BIT, ///< Flag for an invalid track. }; /** * Types of signal known to the game. */ enum SignalType { /* Note: these values represent part of the in-game SignalType enum */ SIGNALTYPE_NORMAL = ::SIGTYPE_NORMAL, ///< Normal signal. SIGNALTYPE_ENTRY = ::SIGTYPE_ENTRY, ///< Entry presignal. SIGNALTYPE_EXIT = ::SIGTYPE_EXIT, ///< Exit signal. SIGNALTYPE_COMBO = ::SIGTYPE_COMBO, ///< Combo signal. SIGNALTYPE_PBS = ::SIGTYPE_PBS, ///< Normal PBS signal. SIGNALTYPE_PBS_ONEWAY = ::SIGTYPE_PBS_ONEWAY, ///< No-entry PBS signal. SIGNALTYPE_TWOWAY = 8, ///< Bit mask for twoway signal. SIGNALTYPE_NORMAL_TWOWAY = SIGNALTYPE_NORMAL | SIGNALTYPE_TWOWAY, ///< Normal twoway signal. SIGNALTYPE_ENTRY_TWOWAY = SIGNALTYPE_ENTRY | SIGNALTYPE_TWOWAY, ///< Entry twoway signal. SIGNALTYPE_EXIT_TWOWAY = SIGNALTYPE_EXIT | SIGNALTYPE_TWOWAY, ///< Exit twoway signal. SIGNALTYPE_COMBO_TWOWAY = SIGNALTYPE_COMBO | SIGNALTYPE_TWOWAY, ///< Combo twoway signal. SIGNALTYPE_NONE = 0xFF, ///< No signal. }; /** * Types of rail-related objects in the game. */ enum BuildType { BT_TRACK, ///< Build a track BT_SIGNAL, ///< Build a signal BT_DEPOT, ///< Build a depot BT_STATION, ///< Build a station BT_WAYPOINT, ///< Build a rail waypoint }; /** * Get the name of a rail type. * @param rail_type The rail type to get the name of. * @pre IsRailTypeAvailable(rail_type). * @return The name the rail type has. * @note Since there is no string with only the name of the track, the text which * is shown in the dropdown where you can chose a track type is returned. This * means that the name could be something like "Maglev construction" instead * of just "Maglev". */ static char *GetName(RailType rail_type); /** * Checks whether the given tile is actually a tile with rail that can be * used to traverse a tile. This excludes rail depots but includes * stations and waypoints. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has rail. */ static bool IsRailTile(TileIndex tile); /** * Checks whether there is a road / rail crossing on a tile. * @param tile The tile to check. * @return True if and only if there is a road / rail crossing. */ static bool IsLevelCrossingTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a rail depot. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a rail depot. */ static bool IsRailDepotTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a rail station. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a rail station. */ static bool IsRailStationTile(TileIndex tile); /** * Checks whether the given tile is actually a tile with a rail waypoint. * @param tile The tile to check. * @pre ScriptMap::IsValidTile(tile). * @return True if and only if the tile has a rail waypoint. */ static bool IsRailWaypointTile(TileIndex tile); /** * Check if a given RailType is available. * @param rail_type The RailType to check for. * @return True if this RailType can be used. */ static bool IsRailTypeAvailable(RailType rail_type); /** * Get the current RailType set for all ScriptRail functions. * @return The RailType currently set. */ static RailType GetCurrentRailType(); /** * Set the RailType for all further ScriptRail functions. * @param rail_type The RailType to set. */ static void SetCurrentRailType(RailType rail_type); /** * Check if a train build for a rail type can run on another rail type. * @param engine_rail_type The rail type the train is build for. * @param track_rail_type The type you want to check. * @pre ScriptRail::IsRailTypeAvailable(engine_rail_type). * @pre ScriptRail::IsRailTypeAvailable(track_rail_type). * @return Whether a train build for 'engine_rail_type' can run on 'track_rail_type'. * @note Even if a train can run on a RailType that doesn't mean that it'll be * able to power the train. Use TrainHasPowerOnRail for that. */ static bool TrainCanRunOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type); /** * Check if a train build for a rail type has power on another rail type. * @param engine_rail_type The rail type the train is build for. * @param track_rail_type The type you want to check. * @pre ScriptRail::IsRailTypeAvailable(engine_rail_type). * @pre ScriptRail::IsRailTypeAvailable(track_rail_type). * @return Whether a train build for 'engine_rail_type' has power on 'track_rail_type'. */ static bool TrainHasPowerOnRail(ScriptRail::RailType engine_rail_type, ScriptRail::RailType track_rail_type); /** * Get the RailType that is used on a tile. * @param tile The tile to check. * @pre ScriptTile::HasTransportType(tile, ScriptTile.TRANSPORT_RAIL). * @return The RailType that is used on a tile. */ static RailType GetRailType(TileIndex tile); /** * Convert the tracks on all tiles within a rectangle to another RailType. * @param start_tile One corner of the rectangle. * @param end_tile The opposite corner of the rectangle. * @param convert_to The RailType you want to convert the rails to. * @pre ScriptMap::IsValidTile(start_tile). * @pre ScriptMap::IsValidTile(end_tile). * @pre IsRailTypeAvailable(convert_to). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptRail::ERR_UNSUITABLE_TRACK * @return Whether at least some rail has been converted successfully. */ static bool ConvertRailType(TileIndex start_tile, TileIndex end_tile, ScriptRail::RailType convert_to); /** * Gets the tile in front of a rail depot. * @param depot The rail depot tile. * @pre IsRailDepotTile(depot). * @return The tile in front of the depot. */ static TileIndex GetRailDepotFrontTile(TileIndex depot); /** * Gets the direction of a rail station tile. * @param tile The rail station tile. * @pre IsRailStationTile(tile). * @return The direction of the station (either RAILTRACK_NE_SW or RAILTRACK_NW_SE). */ static RailTrack GetRailStationDirection(TileIndex tile); /** * Builds a rail depot. * @param tile Place to build the depot. * @param front The tile exactly in front of the depot. * @pre ScriptMap::IsValidTile(tile). * @pre ScriptMap::IsValidTile(front). * @pre 'tile' is not equal to 'front', but in a straight line of it. * @pre IsRailTypeAvailable(GetCurrentRailType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @exception ScriptError::ERR_AREA_NOT_CLEAR * @return Whether the rail depot has been/can be build or not. */ static bool BuildRailDepot(TileIndex tile, TileIndex front); /** * Build a rail station. * @param tile Place to build the station. * @param direction The direction to build the station. * @param num_platforms The number of platforms to build. * @param platform_length The length of each platform. * @param station_id The station to join, ScriptStation::STATION_NEW or ScriptStation::STATION_JOIN_ADJACENT. * @pre IsRailTypeAvailable(GetCurrentRailType()). * @pre ScriptMap::IsValidTile(tile). * @pre direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW. * @pre num_platforms > 0 && num_platforms <= 255. * @pre platform_length > 0 && platform_length <= 255. * @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN * @return Whether the station has been/can be build or not. */ static bool BuildRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id); /** * Build a NewGRF rail station. This calls callback 18 to let a NewGRF * provide the station class / id to build, so we don't end up with * only the default stations on the map. * When no NewGRF provides a rail station, or an unbuildable rail station is * returned by a NewGRF, this function will fall back to building a default * non-NewGRF station as if ScriptRail::BuildRailStation was called. * @param tile Place to build the station. * @param direction The direction to build the station. * @param num_platforms The number of platforms to build. * @param platform_length The length of each platform. * @param station_id The station to join, ScriptStation::STATION_NEW or ScriptStation::STATION_JOIN_ADJACENT. * @param cargo_id The CargoID of the cargo that will be transported from / to this station. * @param source_industry The IndustryType of the industry you'll transport goods from, ScriptIndustryType::INDUSTRYTYPE_UNKNOWN or ScriptIndustryType::INDUSTRYTYPE_TOWN. * @param goal_industry The IndustryType of the industry you'll transport goods to, ScriptIndustryType::INDUSTRYTYPE_UNKNOWN or ScriptIndustryType::INDUSTRYTYPE_TOWN. * @param distance The manhattan distance you'll transport the cargo over. * @param source_station True if this is the source station, false otherwise. * @pre IsRailTypeAvailable(GetCurrentRailType()). * @pre ScriptMap::IsValidTile(tile). * @pre direction == RAILTRACK_NW_SE || direction == RAILTRACK_NE_SW. * @pre num_platforms > 0 && num_platforms <= 255. * @pre platform_length > 0 && platform_length <= 255. * @pre station_id == ScriptStation::STATION_NEW || station_id == ScriptStation::STATION_JOIN_ADJACENT || ScriptStation::IsValidStation(station_id). * @pre ScriptCargo::IsValidCargo(cargo_type) * @pre source_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || source_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(source_industry). * @pre goal_industry == ScriptIndustryType::INDUSTRYTYPE_UNKNOWN || goal_industry == ScriptIndustryType::INDUSTRYTYPE_TOWN || ScriptIndustryType::IsValidIndustryType(goal_industry). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_OWNED_BY_ANOTHER_COMPANY * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @exception ScriptStation::ERR_STATION_TOO_CLOSE_TO_ANOTHER_STATION * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS * @exception ScriptStation::ERR_STATION_TOO_MANY_STATIONS_IN_TOWN * @return Whether the station has been/can be build or not. */ static bool BuildNewGRFRailStation(TileIndex tile, RailTrack direction, uint num_platforms, uint platform_length, StationID station_id, CargoID cargo_id, IndustryType source_industry, IndustryType goal_industry, int distance, bool source_station); /** * Build a rail waypoint. * @param tile Place to build the waypoint. * @pre ScriptMap::IsValidTile(tile). * @pre IsRailTile(tile). * @pre GetRailTracks(tile) == RAILTRACK_NE_SW || GetRailTracks(tile) == RAILTRACK_NW_SE. * @pre IsRailTypeAvailable(GetCurrentRailType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_FLAT_LAND_REQUIRED * @return Whether the rail waypoint has been/can be build or not. */ static bool BuildRailWaypoint(TileIndex tile); /** * Remove all rail waypoint pieces within a rectangle on the map. * @param tile One corner of the rectangle to clear. * @param tile2 The opposite corner. * @param keep_rail Whether to keep the rail after removal. * @pre IsValidTile(tile). * @pre IsValidTile(tile2). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptRail::ERR_UNSUITABLE_TRACK * @return Whether at least one tile has been/can be cleared or not. */ static bool RemoveRailWaypointTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail); /** * Remove all rail station platform pieces within a rectangle on the map. * @param tile One corner of the rectangle to clear. * @param tile2 The opposite corner. * @param keep_rail Whether to keep the rail after removal. * @pre IsValidTile(tile). * @pre IsValidTile(tile2). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptRail::ERR_UNSUITABLE_TRACK * @return Whether at least one tile has been/can be cleared or not. */ static bool RemoveRailStationTileRectangle(TileIndex tile, TileIndex tile2, bool keep_rail); /** * Get all RailTracks on the given tile. * @note A depot has no railtracks. * @param tile The tile to check. * @pre IsRailTile(tile). * @return A bitmask of RailTrack with all RailTracks on the tile. */ static uint GetRailTracks(TileIndex tile); /** * Build rail on the given tile. * @param tile The tile to build on. * @param rail_track The RailTrack to build. * @pre ScriptMap::IsValidTile(tile). * @pre IsRailTypeAvailable(GetCurrentRailType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @exception ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD * @exception ScriptError::ERR_ALREADY_BUILT * @return Whether the rail has been/can be build or not. * @note You can only build a single track with this function so do not * use the values from RailTrack as bitmask. */ static bool BuildRailTrack(TileIndex tile, RailTrack rail_track); /** * Remove rail on the given tile. * @param tile The tile to remove rail from. * @param rail_track The RailTrack to remove. * @pre ScriptMap::IsValidTile(tile). * @pre (GetRailTracks(tile) & rail_track) != 0. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptRail::ERR_UNSUITABLE_TRACK * @return Whether the rail has been/can be removed or not. * @note You can only remove a single track with this function so do not * use the values from RailTrack as bitmask. */ static bool RemoveRailTrack(TileIndex tile, RailTrack rail_track); /** * Check if a tile connects two adjacent tiles. * @param from The first tile to connect. * @param tile The tile that is checked. * @param to The second tile to connect. * @pre from != to. * @pre ScriptMap::DistanceManhattan(from, tile) == 1. * @pre ScriptMap::DistanceManhattan(to, tile) == 1. * @return True if 'tile' connects 'from' and 'to'. */ static bool AreTilesConnected(TileIndex from, TileIndex tile, TileIndex to); /** * Build a rail connection between two tiles. * @param from The tile just before the tile to build on. * @param tile The first tile to build on. * @param to The tile just after the last tile to build on. * @pre from != to. * @pre ScriptMap::DistanceManhattan(from, tile) == 1. * @pre ScriptMap::DistanceManhattan(to, tile) >= 1. * @pre (abs(abs(ScriptMap::GetTileX(to) - ScriptMap::GetTileX(tile)) - * abs(ScriptMap::GetTileY(to) - ScriptMap::GetTileY(tile))) <= 1) || * (ScriptMap::GetTileX(from) == ScriptMap::GetTileX(tile) && ScriptMap::GetTileX(tile) == ScriptMap::GetTileX(to)) || * (ScriptMap::GetTileY(from) == ScriptMap::GetTileY(tile) && ScriptMap::GetTileY(tile) == ScriptMap::GetTileY(to)). * @pre IsRailTypeAvailable(GetCurrentRailType()). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptError::ERR_AREA_NOT_CLEAR * @exception ScriptError::ERR_LAND_SLOPED_WRONG * @exception ScriptRail::ERR_CROSSING_ON_ONEWAY_ROAD * @exception ScriptRoad::ERR_ROAD_WORKS_IN_PROGRESS * @exception ScriptError::ERR_ALREADY_BUILT * @note Construction will fail if an obstacle is found between the start and end tiles. * @return Whether the rail has been/can be build or not. */ static bool BuildRail(TileIndex from, TileIndex tile, TileIndex to); /** * Remove a rail connection between two tiles. * @param from The tile just before the tile to remove rail from. * @param tile The first tile to remove rail from. * @param to The tile just after the last tile to remove rail from. * @pre from != to. * @pre ScriptMap::DistanceManhattan(from, tile) == 1. * @pre ScriptMap::DistanceManhattan(to, tile) >= 1. * @pre (abs(abs(ScriptMap::GetTileX(to) - ScriptMap::GetTileX(tile)) - * abs(ScriptMap::GetTileY(to) - ScriptMap::GetTileY(tile))) <= 1) || * (ScriptMap::GetTileX(from) == ScriptMap::GetTileX(tile) && ScriptMap::GetTileX(tile) == ScriptMap::GetTileX(to)) || * (ScriptMap::GetTileY(from) == ScriptMap::GetTileY(tile) && ScriptMap::GetTileY(tile) == ScriptMap::GetTileY(to)). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptRail::ERR_UNSUITABLE_TRACK * @return Whether the rail has been/can be removed or not. */ static bool RemoveRail(TileIndex from, TileIndex tile, TileIndex to); /** * Get the SignalType of the signal on a tile or SIGNALTYPE_NONE if there is no signal. * @pre ScriptMap::DistanceManhattan(tile, front) == 1. * @param tile The tile that might have a signal. * @param front The tile in front of 'tile'. * @return The SignalType of the signal on 'tile' facing to 'front'. */ static SignalType GetSignalType(TileIndex tile, TileIndex front); /** * Build a signal on a tile. * @param tile The tile to build on. * @param front The tile in front of the signal. * @param signal The SignalType to build. * @pre ScriptMap::DistanceManhattan(tile, front) == 1. * @pre IsRailTile(tile) && !IsRailStationTile(tile) && !IsRailWaypointTile(tile). * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptRail::ERR_UNSUITABLE_TRACK * @return Whether the signal has been/can be build or not. */ static bool BuildSignal(TileIndex tile, TileIndex front, SignalType signal); /** * Remove a signal. * @param tile The tile to remove the signal from. * @param front The tile in front of the signal. * @pre ScriptMap::DistanceManhattan(tile, front) == 1. * @pre GetSignalType(tile, front) != SIGNALTYPE_NONE. * @game @pre Valid ScriptCompanyMode active in scope. * @exception ScriptRail::ERR_UNSUITABLE_TRACK * @return Whether the signal has been/can be removed or not. */ static bool RemoveSignal(TileIndex tile, TileIndex front); /** * Get the baseprice of building a rail-related object. * @param railtype the railtype that is build (on) * @param build_type the type of object to build * @pre IsRailTypeAvailable(railtype) * @return The baseprice of building the given object. */ static Money GetBuildCost(RailType railtype, BuildType build_type); /** * Get the maximum speed of trains running on this railtype. * @param railtype The railtype to get the maximum speed of. * @pre IsRailTypeAvailable(railtype) * @return The maximum speed trains can run on this railtype * or 0 if there is no limit. * @note The speed is in OpenTTD's internal speed unit. * This is mph / 1.6, which is roughly km/h. * To get km/h multiply this number by 1.00584. */ static int32 GetMaxSpeed(RailType railtype); /** * Get the maintenance cost factor of a railtype. * @param railtype The railtype to get the maintenance factor of. * @pre IsRailTypeAvailable(railtype) * @return Maintenance cost factor of the railtype. */ static uint16 GetMaintenanceCostFactor(RailType railtype); }; #endif /* SCRIPT_RAIL_HPP */ openttd-1.5.3/src/script/api/script_industrytype.hpp0000644000000000000000000002022112627373434021427 0ustar rootroot/* $Id: script_industrytype.hpp 26164 2013-12-17 20:41:51Z zuu $ */ /* * 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 script_industrytype.hpp Everything to query and build industries. */ #ifndef SCRIPT_INDUSTRYTYPE_HPP #define SCRIPT_INDUSTRYTYPE_HPP #include "script_list.hpp" /** * Class that handles all industry-type related functions. * @api ai game */ class ScriptIndustryType : public ScriptObject { public: /** * Special IndustryTypes. */ enum SpecialIndustryType { INDUSTRYTYPE_UNKNOWN = 0xFE, ///< Unknown/unspecific industrytype. (Usable for ScriptRail::BuildNewGRFRailStation()) INDUSTRYTYPE_TOWN = 0xFF, ///< No industry, but town. (Usable for ScriptRail::BuildNewGRFRailStation()) }; /** * Checks whether the given industry-type is valid. * @param industry_type The type check. * @return True if and only if the industry-type is valid. */ static bool IsValidIndustryType(IndustryType industry_type); /** * Get the name of an industry-type. * @param industry_type The type to get the name for. * @pre IsValidIndustryType(industry_type). * @return The name of an industry. */ static char *GetName(IndustryType industry_type); /** * Get a list of CargoID possible produced by this industry-type. * @warning This function only returns the default cargoes of the industry type. * Industries can specify new cargotypes on construction. * @param industry_type The type to get the CargoIDs for. * @pre IsValidIndustryType(industry_type). * @return The CargoIDs of all cargotypes this industry could produce. */ static ScriptList *GetProducedCargo(IndustryType industry_type); /** * Get a list of CargoID accepted by this industry-type. * @warning This function only returns the default cargoes of the industry type. * Industries can specify new cargotypes on construction. * @param industry_type The type to get the CargoIDs for. * @pre IsValidIndustryType(industry_type). * @return The CargoIDs of all cargotypes this industry accepts. */ static ScriptList *GetAcceptedCargo(IndustryType industry_type); /** * Is this industry type a raw industry? * Raw industries usually produce cargo without any prerequisites. * ("Usually" means that advanced NewGRF industry concepts might not fit the "raw"/"processing" * classification, so it's up to the interpretation of the NewGRF author.) * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True if it should be handled as a raw industry. * @note Industries might be neither raw nor processing. * This is usually the case for industries which produce nothing (e.g. power plants), * but also for weird industries like temperate banks and tropic lumber mills. */ static bool IsRawIndustry(IndustryType industry_type); /** * Is this industry type a processing industry? * Processing industries usually produce cargo when delivered with input cargo. * ("Usually" means that advanced NewGRF industry concepts might not fit the "raw"/"processing" * classification, so it's up to the interpretation of the NewGRF author.) * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True if it is a processing industry. * @note Industries might be neither raw nor processing. * This is usually the case for industries which produce nothing (e.g. power plants), * but also for weird industries like temperate banks and tropic lumber mills. */ static bool IsProcessingIndustry(IndustryType industry_type); /** * Can the production of this industry increase? * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True if the production of this industry can increase. */ static bool ProductionCanIncrease(IndustryType industry_type); /** * Get the cost for building this industry-type. * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return The cost for building this industry-type. */ static Money GetConstructionCost(IndustryType industry_type); /** * Can you build this type of industry? * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True if you can build this type of industry at locations of your choice. * @ai @note Returns false if you can only prospect this type of industry, or not build it at all. * @game @note If no valid ScriptCompanyMode active in scope, this method returns false if you can * @game only prospect this type of industry, or not build it at all. * @game @note If no valid ScriptCompanyMode active in scope, the script can * @game build as long as the industry type can be built. (a NewGRF can for example * @game reject construction based on current year) */ static bool CanBuildIndustry(IndustryType industry_type); /** * Can you prospect this type of industry? * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True if you can prospect this type of industry. * @ai @note If the setting "Manual primary industry construction method" is set * @ai to either "None" or "as other industries" this function always returns false. * @game @note If no valid ScriptCompanyMode is active in scope, and if the setting * @game "Manual primary industry construction method" is set to either "None" or * @game "as other industries" this function always returns false. * @game @note If no valid ScriptCompanyMode active in scope, the script can * @game prospect as long as the industry type can be built. (a NewGRF can for * @game example reject construction based on current year) */ static bool CanProspectIndustry(IndustryType industry_type); /** * Build an industry of the specified type. * @param industry_type The type of the industry to build. * @param tile The tile to build the industry on. * @pre CanBuildIndustry(industry_type). * @return True if the industry was successfully build. */ static bool BuildIndustry(IndustryType industry_type, TileIndex tile); /** * Prospect an industry of this type. Prospecting an industries let the game try to create * an industry on a random place on the map. * @param industry_type The type of the industry. * @pre CanProspectIndustry(industry_type). * @return True if no error occurred while trying to prospect. * @note Even if true is returned there is no guarantee a new industry is build. * @note If true is returned the money is paid, whether a new industry was build or not. * @game @note if no valid ScriptCompanyMode exist in scope, prospection will not fail * @game due to the general chance that prospection may fail. However prospection can still * @game fail if OpenTTD is unable to find a suitable location to place the industry. */ static bool ProspectIndustry(IndustryType industry_type); /** * Is this type of industry built on water. * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True when this type is built on water. */ static bool IsBuiltOnWater(IndustryType industry_type); /** * Does this type of industry have a heliport? * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True when this type has a heliport. */ static bool HasHeliport(IndustryType industry_type); /** * Does this type of industry have a dock? * @param industry_type The type of the industry. * @pre IsValidIndustryType(industry_type). * @return True when this type has a dock. */ static bool HasDock(IndustryType industry_type); }; #endif /* SCRIPT_INDUSTRYTYPE_HPP */ openttd-1.5.3/src/script/api/squirrel_export.awk0000644000000000000000000004277312627373434020542 0ustar rootroot# $Id: squirrel_export.awk 24288 2012-05-26 14:16:27Z frosch $ # 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 . # # Awk script to automatically generate the code needed # to export the script APIs to Squirrel. # # Note that arrays are 1 based... # # Simple insertion sort. function array_sort(ARRAY, ELEMENTS, temp, i, j) { for (i = 2; i <= ELEMENTS; i++) for (j = i; ARRAY[j - 1] > ARRAY[j]; --j) { temp = ARRAY[j] ARRAY[j] = ARRAY[j - 1] ARRAY[j - 1] = temp } return } function dump_class_templates(name) { realname = name gsub("^Script", "", realname) print " template <> inline " name " *GetParam(ForceType<" name " *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" print " template <> inline " name " &GetParam(ForceType<" name " &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" print " template <> inline const " name " *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (" name " *)instance; }" print " template <> inline const " name " &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(" name " *)instance; }" if (name == "ScriptEvent") { print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" } else if (name == "ScriptText") { print "" print " template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {" print " if (sq_gettype(vm, index) == OT_INSTANCE) {" print " return GetParam(ForceType(), vm, index, ptr);" print " }" print " if (sq_gettype(vm, index) == OT_STRING) {" print " return new RawText(GetParam(ForceType(), vm, index, ptr));" print " }" print " return NULL;" print " }" } else { print " template <> inline int Return<" name " *>(HSQUIRRELVM vm, " name " *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"" realname "\", res, NULL, DefSQDestructorCallback<" name ">, true); return 1; }" } } function dump_fileheader() { # Break the Id tag, so SVN doesn't replace it print "/* $I" "d$ */" print "" print "/*" print " * This file is part of OpenTTD." print " * 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." print " * 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." print " * 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 ." print " */" print "" print "/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */" print "" print "#include \"../" filename "\"" if (api != "Template") { gsub("script_", "template_", filename) print "#include \"../template/" filename ".sq\"" } } function reset_reader() { enum_size = 0 enum_value_size = 0 enum_string_to_error_size = 0 enum_error_to_string_size = 0 struct_size = 0 method_size = 0 static_method_size = 0 virtual_class = "false" cls = "" start_squirrel_define_on_next_line = "false" cls_level = 0 cls_in_api = "" } BEGIN { enum_size = 0 enum_value_size = 0 enum_string_to_error_size = 0 enum_error_to_string_size = 0 const_size = 0 struct_size = 0 method_size = 0 static_method_size = 0 virtual_class = "false" super_cls = "" cls = "" api_selected = "" cls_in_api = "" start_squirrel_define_on_next_line = "false" has_fileheader = "false" cls_level = 0 RS = "\r|\n" apis = tolower(api) if (apis == "gs") apis = "game" } /@file/ { filename = $3 gsub("^" apis "_", "script_", filename) } # Ignore special doxygen blocks /^#ifndef DOXYGEN_API/ { doxygen_skip = "next"; next; } /^#ifdef DOXYGEN_API/ { doxygen_skip = "true"; next; } /^#endif \/\* DOXYGEN_API \*\// { doxygen_skip = "false"; next; } /^#else/ { if (doxygen_skip == "next") { doxygen_skip = "true"; } else { doxygen_skip = "false"; } next; } { if (doxygen_skip == "true") next } /^([ ]*)\* @api/ { # By default, classes are not selected if (cls_level == 0) api_selected = "false" gsub("^([ ]*)", "", $0) gsub("* @api ", "", $0) if (api == "Template") { api_selected = "true" if ($0 == "none" || $0 == "-all") api_selected = "false" next } if ($0 == "none") { api_selected = "false" } else if ($0 == "-all") { api_selected = "false" } else if (match($0, "-" apis)) { api_selected = "false" } else if (match($0, apis)) { api_selected = "true" } next } # Remove the old squirrel stuff /#ifdef DEFINE_SQUIRREL_CLASS/ { squirrel_stuff = "true"; next; } /^#endif \/\* DEFINE_SQUIRREL_CLASS \*\// { if (squirrel_stuff == "true") { squirrel_stuff = "false"; next; } } { if (squirrel_stuff == "true") next; } # Ignore forward declarations of classes /^( *)class(.*);/ { next; } # We only want to have public functions exported for now /^( *)class/ { if (cls_level == 0) { if (api_selected == "") { print "Class '"$2"' has no @api. It won't be published to any API." > "/dev/stderr" api_selected = "false" } public = "false" cls_param[0] = "" cls_param[1] = 1 cls_param[2] = "x" cls_in_api = api_selected api_selected = "" cls = $2 if (match($4, "public") || match($4, "protected") || match($4, "private")) { super_cls = $5 } else { super_cls = $4 } } else if (cls_level == 1) { if (api_selected == "") api_selected = cls_in_api if (api_selected == "true") { struct_size++ structs[struct_size] = cls "::" $2 } api_selected = "" } cls_level++ next } /^( *)public/ { if (cls_level == 1) public = "true"; next; } /^( *)protected/ { if (cls_level == 1) public = "false"; next; } /^( *)private/ { if (cls_level == 1) public = "false"; next; } # Ignore the comments /^#/ { next; } /\/\*.*\*\// { comment = "false"; next; } /\/\*/ { comment = "true"; next; } /\*\// { comment = "false"; next; } { if (comment == "true") next } # We need to make specialized conversions for structs /^( *)struct/ { cls_level++ # Check if we want to publish this struct if (api_selected == "") api_selected = cls_in_api if (api_selected == "false") { api_selected = "" next } api_selected = "" if (public == "false") next if (cls_level != 1) next struct_size++ structs[struct_size] = cls "::" $2 next } # We need to make specialized conversions for enums /^( *)enum/ { cls_level++ # Check if we want to publish this enum if (api_selected == "") api_selected = cls_in_api if (api_selected == "false") { api_selected = "" next } api_selected = "" if (public == "false") next in_enum = "true" enum_size++ enums[enum_size] = cls "::" $2 next } # Maybe the end of the class, if so we can start with the Squirrel export pretty soon /};/ { cls_level-- if (cls_level != 0) { in_enum = "false"; next; } if (cls == "") { next; } start_squirrel_define_on_next_line = "true" next; } # Empty/white lines. When we may do the Squirrel export, do that export. /^([ ]*)$/ { if (start_squirrel_define_on_next_line == "false") next if (cls_in_api != "true") { reset_reader() next } if (has_fileheader == "false") { dump_fileheader() has_fileheader = "true" } spaces = " "; public = "false" namespace_opened = "false" api_cls = cls gsub("^Script", api, api_cls) api_super_cls = super_cls gsub("^Script", api, api_super_cls) print "" if (api == "Template") { # First check whether we have enums to print if (enum_size != 0) { if (namespace_opened == "false") { print "namespace SQConvert {" namespace_opened = "true" } print " /* Allow enums to be used as Squirrel parameters */" for (i = 1; i <= enum_size; i++) { print " template <> inline " enums[i] " GetParam(ForceType<" enums[i] ">, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (" enums[i] ")tmp; }" print " template <> inline int Return<" enums[i] ">(HSQUIRRELVM vm, " enums[i] " res) { sq_pushinteger(vm, (int32)res); return 1; }" delete enums[i] } } # Then check whether we have structs/classes to print if (struct_size != 0) { if (namespace_opened == "false") { print "namespace SQConvert {" namespace_opened = "true" } print " /* Allow inner classes/structs to be used as Squirrel parameters */" for (i = 1; i <= struct_size; i++) { dump_class_templates(structs[i]) delete structs[i] } } if (namespace_opened == "false") { print "namespace SQConvert {" namespace_opened = "true" } else { print "" } print " /* Allow " cls " to be used as Squirrel parameter */" dump_class_templates(cls) print "} // namespace SQConvert" reset_reader() next } print ""; print "template <> const char *GetClassName<" cls ", ST_" toupper(api) ">() { return \"" api_cls "\"; }" print ""; # Then do the registration functions of the class. */ print "void SQ" api_cls "_Register(Squirrel *engine)" print "{" print " DefSQClass<" cls ", ST_" toupper(api) "> SQ" api_cls "(\"" api_cls "\");" if (super_cls == "Text" || super_cls == "ScriptObject" || super_cls == "AIAbstractList::Valuator") { print " SQ" api_cls ".PreRegister(engine);" } else { print " SQ" api_cls ".PreRegister(engine, \"" api_super_cls "\");" } if (virtual_class == "false" && super_cls != "ScriptEvent") { if (cls_param[2] == "v") { print " SQ" api_cls ".AddSQAdvancedConstructor(engine);" } else { print " SQ" api_cls ".AddConstructor(engine, \"" cls_param[2] "\");" } } print "" # Enum values mlen = 0 for (i = 1; i <= enum_value_size; i++) { if (mlen <= length(enum_value[i])) mlen = length(enum_value[i]) } for (i = 1; i <= enum_value_size; i++) { print " SQ" api_cls ".DefSQConst(engine, " cls "::" enum_value[i] ", " substr(spaces, 1, mlen - length(enum_value[i])) "\"" enum_value[i] "\");" delete enum_value[i] } if (enum_value_size != 0) print "" # Const values mlen = 0 for (i = 1; i <= const_size; i++) { if (mlen <= length(const_value[i])) mlen = length(const_value[i]) } for (i = 1; i <= const_size; i++) { print " SQ" api_cls ".DefSQConst(engine, " cls "::" const_value[i] ", " substr(spaces, 1, mlen - length(const_value[i])) "\"" const_value[i] "\");" delete const_value[i] } if (const_size != 0) print "" # Mapping of OTTD strings to errors mlen = 0 for (i = 1; i <= enum_string_to_error_size; i++) { if (mlen <= length(enum_string_to_error_mapping_string[i])) mlen = length(enum_string_to_error_mapping_string[i]) } for (i = 1; i <= enum_string_to_error_size; i++) { print " ScriptError::RegisterErrorMap(" enum_string_to_error_mapping_string[i] ", " substr(spaces, 1, mlen - length(enum_string_to_error_mapping_string[i])) cls "::" enum_string_to_error_mapping_error[i] ");" delete enum_string_to_error_mapping_string[i] } if (enum_string_to_error_size != 0) print "" # Mapping of errors to human 'readable' strings. mlen = 0 for (i = 1; i <= enum_error_to_string_size; i++) { if (mlen <= length(enum_error_to_string_mapping[i])) mlen = length(enum_error_to_string_mapping[i]) } for (i = 1; i <= enum_error_to_string_size; i++) { print " ScriptError::RegisterErrorMapString(" cls "::" enum_error_to_string_mapping[i] ", " substr(spaces, 1, mlen - length(enum_error_to_string_mapping[i])) "\"" enum_error_to_string_mapping[i] "\");" delete enum_error_to_string_mapping[i] } if (enum_error_to_string_size != 0) print "" # Static methods mlen = 0 for (i = 1; i <= static_method_size; i++) { if (mlen <= length(static_methods[i, 0])) mlen = length(static_methods[i, 0]) } for (i = 1; i <= static_method_size; i++) { if (static_methods[i, 2] == "v") { print " SQ" api_cls ".DefSQAdvancedStaticMethod(engine, &" cls "::" static_methods[i, 0] ", " substr(spaces, 1, mlen - length(static_methods[i, 0]) - 8) "\"" static_methods[i, 0] "\");" } else { print " SQ" api_cls ".DefSQStaticMethod(engine, &" cls "::" static_methods[i, 0] ", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "\"" static_methods[i, 0] "\", " substr(spaces, 1, mlen - length(static_methods[i, 0])) "" static_methods[i, 1] ", \"" static_methods[i, 2] "\");" } delete static_methods[i] } if (static_method_size != 0) print "" if (virtual_class == "false") { # Non-static methods mlen = 0 for (i = 1; i <= method_size; i++) { if (mlen <= length(methods[i, 0])) mlen = length(methods[i, 0]) } for (i = 1; i <= method_size; i++) { if (methods[i, 2] == "v") { print " SQ" api_cls ".DefSQAdvancedMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0]) - 8) "\"" methods[i, 0] "\");" } else { print " SQ" api_cls ".DefSQMethod(engine, &" cls "::" methods[i, 0] ", " substr(spaces, 1, mlen - length(methods[i, 0])) "\"" methods[i, 0] "\", " substr(spaces, 1, mlen - length(methods[i, 0])) "" methods[i, 1] ", \"" methods[i, 2] "\");" } delete methods[i] } if (method_size != 0) print "" } print " SQ" api_cls ".PostRegister(engine);" print "}" reset_reader() next } # Skip non-public functions { if (public == "false") next } # Add enums { if (in_enum == "true") { enum_value_size++ sub(",", "", $1) enum_value[enum_value_size] = $1 # Check if this a special error enum if (match(enums[enum_size], ".*::ErrorMessages") != 0) { # syntax: # enum ErrorMessages { # ERR_SOME_ERROR, // [STR_ITEM1, STR_ITEM2, ...] # } # Set the mappings if (match($0, "\\[.*\\]") != 0) { mappings = substr($0, RSTART, RLENGTH); gsub("([\\[[:space:]\\]])", "", mappings); split(mappings, mapitems, ","); for (i = 1; i <= length(mapitems); i++) { enum_string_to_error_size++ enum_string_to_error_mapping_string[enum_string_to_error_size] = mapitems[i] enum_string_to_error_mapping_error[enum_string_to_error_size] = $1 } enum_error_to_string_size++ enum_error_to_string_mapping[enum_error_to_string_size] = $1 } } next } } # Add a const (non-enum) value /^[ ]*static const \w+ \w+ = -?\(?\w*\)?\w+;/ { const_size++ const_value[const_size] = $4 next } # Add a method to the list /^.*\(.*\).*$/ { if (cls_level != 1) next if (match($0, "~")) { if (api_selected != "") { print "Destructor for '"cls"' has @api. Tag ignored." > "/dev/stderr" api_selected = "" } next } is_static = match($0, "static") if (match($0, "virtual")) { virtual_class = "true" } gsub("\\yvirtual\\y", "", $0) gsub("\\ystatic\\y", "", $0) gsub("\\yconst\\y", "", $0) gsub("{.*", "", $0) param_s = $0 gsub("\\*", "", $0) gsub("\\(.*", "", $0) sub(".*\\(", "", param_s) sub("\\).*", "", param_s) funcname = $2 if ($1 == cls && funcname == "") { if (api_selected != "") { print "Constructor for '"cls"' has @api. Tag ignored." > "/dev/stderr" api_selected = "" } cls_param[0] = param_s if (param_s == "") next } else if (funcname == "") next split(param_s, params, ",") if (is_static) { types = "." } else { types = "x" } for (len = 1; params[len] != ""; len++) { sub("^[ ]*", "", params[len]) if (match(params[len], "\\*") || match(params[len], "&")) { if (match(params[len], "^char")) { # Many types can be converted to string, so use '.', not 's'. (handled by our glue code) types = types "." } else if (match(params[len], "^void")) { types = types "p" } else if (match(params[len], "^Array")) { types = types "a" } else if (match(params[len], "^struct Array")) { types = types "a" } else if (match(params[len], "^Text")) { types = types "." } else { types = types "x" } } else if (match(params[len], "^bool")) { types = types "b" } else if (match(params[len], "^HSQUIRRELVM")) { types = "v" } else { types = types "i" } } # Check if we want to publish this function if (api_selected == "") api_selected = cls_in_api if (api_selected == "false") { api_selected = "" next } api_selected = "" if ($1 == cls && funcname == "") { cls_param[1] = len; cls_param[2] = types; } else if (substr(funcname, 0, 1) == "_" && types != "v") { } else if (is_static) { static_method_size++ static_methods[static_method_size, 0] = funcname static_methods[static_method_size, 1] = len static_methods[static_method_size, 2] = types } else { method_size++ methods[method_size, 0] = funcname methods[method_size, 1] = len methods[method_size, 2] = types } next } openttd-1.5.3/src/script/api/script_signlist.hpp0000644000000000000000000000176612627373434020515 0ustar rootroot/* $Id: script_signlist.hpp 23614 2011-12-19 20:57:23Z truebrain $ */ /* * 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 script_signlist.hpp List all the signs of your company. */ #ifndef SCRIPT_SIGNLIST_HPP #define SCRIPT_SIGNLIST_HPP #include "script_list.hpp" /** * Create a list of signs your company has created. * @api ai game * @ingroup ScriptList */ class ScriptSignList : public ScriptList { public: ScriptSignList(); }; #endif /* SCRIPT_SIGNLIST_HPP */ openttd-1.5.3/src/script/script_instance.hpp0000644000000000000000000002002612627373434017702 0ustar rootroot/* $Id: script_instance.hpp 25342 2013-06-09 12:19:09Z zuu $ */ /* * 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 script_instance.hpp The ScriptInstance tracks a script. */ #ifndef SCRIPT_INSTANCE_HPP #define SCRIPT_INSTANCE_HPP #include #include "script_suspend.hpp" #include "../command_type.h" #include "../company_type.h" #include "../fileio_type.h" static const uint SQUIRREL_MAX_DEPTH = 25; ///< The maximum recursive depth for items stored in the savegame. /** Runtime information about a script like a pointer to the squirrel vm and the current state. */ class ScriptInstance { public: friend class ScriptObject; friend class ScriptController; /** * Create a new script. */ ScriptInstance(const char *APIName); virtual ~ScriptInstance(); /** * Initialize the script and prepare it for its first run. * @param main_script The full path of the script to load. * @param instance_name The name of the instance out of the script to load. * @param company Which company this script is serving. */ void Initialize(const char *main_script, const char *instance_name, CompanyID company); /** * Get the value of a setting of the current instance. * @param name The name of the setting. * @return the value for the setting, or -1 if the setting is not known. */ virtual int GetSetting(const char *name) = 0; /** * Find a library. * @param library The library name to find. * @param version The version the library should have. * @return The library if found, NULL otherwise. */ virtual class ScriptInfo *FindLibrary(const char *library, int version) = 0; /** * A script in multiplayer waits for the server to handle his DoCommand. * It keeps waiting for this until this function is called. */ void Continue(); /** * Run the GameLoop of a script. */ void GameLoop(); /** * Let the VM collect any garbage. */ void CollectGarbage() const; /** * Get the storage of this script. */ class ScriptStorage *GetStorage(); /** * Get the log pointer of this script. */ void *GetLogPointer(); /** * Return a true/false reply for a DoCommand. */ static void DoCommandReturn(ScriptInstance *instance); /** * Return a VehicleID reply for a DoCommand. */ static void DoCommandReturnVehicleID(ScriptInstance *instance); /** * Return a SignID reply for a DoCommand. */ static void DoCommandReturnSignID(ScriptInstance *instance); /** * Return a GroupID reply for a DoCommand. */ static void DoCommandReturnGroupID(ScriptInstance *instance); /** * Return a GoalID reply for a DoCommand. */ static void DoCommandReturnGoalID(ScriptInstance *instance); /** * Return a StoryPageID reply for a DoCommand. */ static void DoCommandReturnStoryPageID(ScriptInstance *instance); /** * Return a StoryPageElementID reply for a DoCommand. */ static void DoCommandReturnStoryPageElementID(ScriptInstance *instance); /** * Get the controller attached to the instance. */ class ScriptController *GetController() { return controller; } /** * Return the "this script died" value */ inline bool IsDead() const { return this->is_dead; } /** * Call the script Save function and save all data in the savegame. */ void Save(); /** * Don't save any data in the savegame. */ static void SaveEmpty(); /** * Load data from a savegame and store it on the stack. * @param version The version of the script when saving, or -1 if this was * not the original script saving the game. */ void Load(int version); /** * Load and discard data from a savegame. */ static void LoadEmpty(); /** * Suspends the script for the current tick and then pause the execution * of script. The script will not be resumed from its suspended state * until the script has been unpaused. */ void Pause(); /** * Checks if the script is paused. * @return true if the script is paused, otherwise false */ bool IsPaused(); /** * Resume execution of the script. This function will not actually execute * the script, but set a flag so that the script is executed my the usual * mechanism that executes the script. */ void Unpause(); /** * Get the number of operations the script can execute before being suspended. * This function is safe to call from within a function called by the script. * @return The number of operations to execute. */ SQInteger GetOpsTillSuspend(); /** * DoCommand callback function for all commands executed by scripts. * @param result The result of the command. * @param tile The tile on which the command was executed. * @param p1 p1 as given to DoCommandPInternal. * @param p2 p2 as given to DoCommandPInternal. */ void DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2); /** * Insert an event for this script. * @param event The event to insert. */ void InsertEvent(class ScriptEvent *event); /** * Check if the instance is sleeping, which either happened because the * script executed a DoCommand, executed this.Sleep() or it has been * paused. */ bool IsSleeping() { return this->suspend != 0; } protected: class Squirrel *engine; ///< A wrapper around the squirrel vm. const char *versionAPI; ///< Current API used by this script. /** * Register all API functions to the VM. */ virtual void RegisterAPI(); /** * Load squirrel scripts to emulate an older API. * @param api_version: API version to load scripts for * @param dir Subdirectory to find the scripts in * @return true iff script loading should proceed */ bool LoadCompatibilityScripts(const char *api_version, Subdirectory dir); /** * Tell the script it died. */ virtual void Died(); /** * Get the callback handling DoCommands in case of networking. */ virtual CommandCallback *GetDoCommandCallback() = 0; /** * Load the dummy script. */ virtual void LoadDummyScript() = 0; private: class ScriptController *controller; ///< The script main class. class ScriptStorage *storage; ///< Some global information for each running script. SQObject *instance; ///< Squirrel-pointer to the script main class. bool is_started; ///< Is the scripts constructor executed? bool is_dead; ///< True if the script has been stopped. bool is_save_data_on_stack; ///< Is the save data still on the squirrel stack? int suspend; ///< The amount of ticks to suspend this script before it's allowed to continue. bool is_paused; ///< Is the script paused? (a paused script will not be executed until unpaused) Script_SuspendCallbackProc *callback; ///< Callback that should be called in the next tick the script runs. /** * Call the script Load function if it exists and data was loaded * from a savegame. */ bool CallLoad(); /** * Save one object (int / string / array / table) to the savegame. * @param vm The virtual machine to get all the data from. * @param index The index on the squirrel stack of the element to save. * @param max_depth The maximum depth recursive arrays / tables will be stored * with before an error is returned. * @param test If true, don't really store the data but only check if it is * valid. * @return True if the saving was successful. */ static bool SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test); /** * Load all objects from a savegame. * @return True if the loading was successful. */ static bool LoadObjects(HSQUIRRELVM vm); }; #endif /* SCRIPT_INSTANCE_HPP */ openttd-1.5.3/src/script/script_info.hpp0000644000000000000000000001200612627373433017027 0ustar rootroot/* $Id: script_info.hpp 26057 2013-11-23 13:12:19Z rubidium $ */ /* * 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 script_info.hpp ScriptInfo keeps track of all information of a script, like Author, Description, ... */ #ifndef SCRIPT_INFO_HPP #define SCRIPT_INFO_HPP #include #include "../misc/countedptr.hpp" #include "script_config.hpp" /** The maximum number of operations for saving or loading the data of a script. */ static const int MAX_SL_OPS = 100000; /** The maximum number of operations for initial start of a script. */ static const int MAX_CONSTRUCTOR_OPS = 100000; /** Number of operations to create an instance of a script. */ static const int MAX_CREATEINSTANCE_OPS = 100000; /** Number of operations to get the author and similar information. */ static const int MAX_GET_OPS = 1000; /** Maximum number of operations allowed for getting a particular setting. */ static const int MAX_GET_SETTING_OPS = 100000; /** All static information from an Script like name, version, etc. */ class ScriptInfo : public SimpleCountedObject { public: ScriptInfo() : engine(NULL), SQ_instance(NULL), main_script(NULL), tar_file(NULL), author(NULL), name(NULL), short_name(NULL), description(NULL), date(NULL), instance_name(NULL), version(0), url(NULL), scanner(NULL) {} ~ScriptInfo(); /** * Get the Author of the script. */ const char *GetAuthor() const { return this->author; } /** * Get the Name of the script. */ const char *GetName() const { return this->name; } /** * Get the 4 character long short name of the script. */ const char *GetShortName() const { return this->short_name; } /** * Get the description of the script. */ const char *GetDescription() const { return this->description; } /** * Get the version of the script. */ int GetVersion() const { return this->version; } /** * Get the last-modified date of the script. */ const char *GetDate() const { return this->date; } /** * Get the name of the instance of the script to create. */ const char *GetInstanceName() const { return this->instance_name; } /** * Get the website for this script. */ const char *GetURL() const { return this->url; } /** * Get the filename of the main.nut script. */ const char *GetMainScript() const { return this->main_script; } /** * Get the filename of the tar the script is in. */ const char *GetTarFile() const { return this->tar_file; } /** * Check if a given method exists. */ bool CheckMethod(const char *name) const; /** * Process the creation of a FileInfo object. */ static SQInteger Constructor(HSQUIRRELVM vm, ScriptInfo *info); /** * Get the scanner which has found this ScriptInfo. */ virtual class ScriptScanner *GetScanner() { return this->scanner; } /** * Get the settings of the Script. */ bool GetSettings(); /** * Get the config list for this Script. */ const ScriptConfigItemList *GetConfigList() const; /** * Get the description of a certain Script config option. */ const ScriptConfigItem *GetConfigItem(const char *name) const; /** * Set a setting. */ SQInteger AddSetting(HSQUIRRELVM vm); /** * Add labels for a setting. */ SQInteger AddLabels(HSQUIRRELVM vm); /** * Get the default value for a setting. */ int GetSettingDefaultValue(const char *name) const; /** * Can this script be selected by developers only? */ virtual bool IsDeveloperOnly() const { return false; } protected: class Squirrel *engine; ///< Engine used to register for Squirrel. HSQOBJECT *SQ_instance; ///< The Squirrel instance created for this info. ScriptConfigItemList config_list; ///< List of settings from this Script. private: char *main_script; ///< The full path of the script. char *tar_file; ///< If, which tar file the script was in. const char *author; ///< Author of the script. const char *name; ///< Full name of the script. const char *short_name; ///< Short name (4 chars) which uniquely identifies the script. const char *description; ///< Small description of the script. const char *date; ///< The date the script was written at. const char *instance_name; ///< Name of the main class in the script. int version; ///< Version of the script. const char *url; ///< URL of the script. class ScriptScanner *scanner; ///< ScriptScanner object that was used to scan this script info. }; #endif /* SCRIPT_INFO_HPP */ openttd-1.5.3/src/script/script_suspend.hpp0000644000000000000000000000353212627373433017561 0ustar rootroot/* $Id: script_suspend.hpp 23378 2011-11-30 14:02:15Z truebrain $ */ /* * 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 script_suspend.hpp The Script_Suspend tracks the suspension of a script. */ #ifndef SCRIPT_SUSPEND_HPP #define SCRIPT_SUSPEND_HPP /** * The callback function when a script suspends. */ typedef void (Script_SuspendCallbackProc)(class ScriptInstance *instance); /** * A throw-class that is given when the script wants to suspend. */ class Script_Suspend { public: /** * Create the suspend exception. * @param time The amount of ticks to suspend. * @param callback The callback to call when the script may resume again. */ Script_Suspend(int time, Script_SuspendCallbackProc *callback) : time(time), callback(callback) {} /** * Get the amount of ticks the script should be suspended. * @return The amount of ticks to suspend the script. */ int GetSuspendTime() { return time; } /** * Get the callback to call when the script can run again. * @return The callback function to run. */ Script_SuspendCallbackProc *GetSuspendCallback() { return callback; } private: int time; ///< Amount of ticks to suspend the script. Script_SuspendCallbackProc *callback; ///< Callback function to call when the script can run again. }; #endif /* SCRIPT_SUSPEND_HPP */ openttd-1.5.3/src/town_cmd.cpp0000644000000000000000000032462712627373433015030 0ustar rootroot/* $Id: town_cmd.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 town_cmd.cpp Handling of town tiles. */ #include "stdafx.h" #include "road_internal.h" /* Cleaning up road bits */ #include "road_cmd.h" #include "landscape.h" #include "viewport_func.h" #include "cmd_helper.h" #include "command_func.h" #include "industry.h" #include "station_base.h" #include "company_base.h" #include "news_func.h" #include "error.h" #include "object.h" #include "genworld.h" #include "newgrf_debug.h" #include "newgrf_house.h" #include "newgrf_text.h" #include "autoslope.h" #include "tunnelbridge_map.h" #include "strings_func.h" #include "window_func.h" #include "string_func.h" #include "newgrf_cargo.h" #include "cheat_type.h" #include "animated_tile_func.h" #include "date_func.h" #include "subsidy_func.h" #include "core/pool_func.hpp" #include "town.h" #include "townname_func.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "depot_base.h" #include "object_map.h" #include "object_base.h" #include "ai/ai.hpp" #include "game/game.hpp" #include "table/strings.h" #include "table/town_land.h" #include "safeguards.h" TownID _new_town_id; uint32 _town_cargoes_accepted; ///< Bitmap of all cargoes accepted by houses. /* Initialize the town-pool */ TownPool _town_pool("Town"); INSTANTIATE_POOL_METHODS(Town) Town::~Town() { free(this->name); free(this->text); if (CleaningPool()) return; /* Delete town authority window * and remove from list of sorted towns */ DeleteWindowById(WC_TOWN_VIEW, this->index); /* Check no industry is related to us. */ const Industry *i; FOR_ALL_INDUSTRIES(i) assert(i->town != this); /* ... and no object is related to us. */ const Object *o; FOR_ALL_OBJECTS(o) assert(o->town != this); /* Check no tile is related to us. */ for (TileIndex tile = 0; tile < MapSize(); ++tile) { switch (GetTileType(tile)) { case MP_HOUSE: assert(GetTownIndex(tile) != this->index); break; case MP_ROAD: assert(!HasTownOwnedRoad(tile) || GetTownIndex(tile) != this->index); break; case MP_TUNNELBRIDGE: assert(!IsTileOwner(tile, OWNER_TOWN) || ClosestTownFromTile(tile, UINT_MAX) != this); break; default: break; } } /* Clear the persistent storage list. */ this->psa_list.clear(); DeleteSubsidyWith(ST_TOWN, this->index); DeleteNewGRFInspectWindow(GSF_FAKE_TOWNS, this->index); CargoPacket::InvalidateAllFrom(ST_TOWN, this->index); MarkWholeScreenDirty(); } /** * Invalidating of the "nearest town cache" has to be done * after removing item from the pool. * @param index index of deleted item */ void Town::PostDestructor(size_t index) { InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0); UpdateNearestTownForRoadTiles(false); /* Give objects a new home! */ Object *o; FOR_ALL_OBJECTS(o) { if (o->town == NULL) o->town = CalcClosestTownFromTile(o->location.tile, UINT_MAX); } } /** * Assigns town layout. If Random, generates one based on TileHash. */ void Town::InitializeLayout(TownLayout layout) { if (layout != TL_RANDOM) { this->layout = layout; return; } this->layout = TileHash(TileX(this->xy), TileY(this->xy)) % (NUM_TLS - 1); } /** * Return a random valid town. * @return random town, NULL if there are no towns */ /* static */ Town *Town::GetRandom() { if (Town::GetNumItems() == 0) return NULL; int num = RandomRange((uint16)Town::GetNumItems()); size_t index = MAX_UVALUE(size_t); while (num >= 0) { num--; index++; /* Make sure we have a valid town */ while (!Town::IsValidID(index)) { index++; assert(index < Town::GetPoolSize()); } } return Town::Get(index); } /** * Get the cost for removing this house * @return the cost (inflation corrected etc) */ Money HouseSpec::GetRemovalCost() const { return (_price[PR_CLEAR_HOUSE] * this->removal_cost) >> 8; } /* Local */ static int _grow_town_result; /* Describe the possible states */ enum TownGrowthResult { GROWTH_SUCCEED = -1, GROWTH_SEARCH_STOPPED = 0 // GROWTH_SEARCH_RUNNING >= 1 }; static bool BuildTownHouse(Town *t, TileIndex tile); static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout); static void TownDrawHouseLift(const TileInfo *ti) { AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile)); } typedef void TownDrawTileProc(const TileInfo *ti); static TownDrawTileProc * const _town_draw_tile_procs[1] = { TownDrawHouseLift }; /** * Return a random direction * * @return a random direction */ static inline DiagDirection RandomDiagDir() { return (DiagDirection)(3 & Random()); } /** * House Tile drawing handler. * Part of the tile loop process * @param ti TileInfo of the tile to draw */ static void DrawTile_Town(TileInfo *ti) { HouseID house_id = GetHouseType(ti->tile); if (house_id >= NEW_HOUSE_OFFSET) { /* Houses don't necessarily need new graphics. If they don't have a * spritegroup associated with them, then the sprite for the substitute * house id is drawn instead. */ if (HouseSpec::Get(house_id)->grf_prop.spritegroup[0] != NULL) { DrawNewHouseTile(ti, house_id); return; } else { house_id = HouseSpec::Get(house_id)->grf_prop.subst_id; } } /* Retrieve pointer to the draw town tile struct */ const DrawBuildingsTileStruct *dcts = &_town_draw_tile_data[house_id << 4 | TileHash2Bit(ti->x, ti->y) << 2 | GetHouseBuildingStage(ti->tile)]; if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); DrawGroundSprite(dcts->ground.sprite, dcts->ground.pal); /* If houses are invisible, do not draw the upper part */ if (IsInvisibilitySet(TO_HOUSES)) return; /* Add a house on top of the ground? */ SpriteID image = dcts->building.sprite; if (image != 0) { AddSortableSpriteToDraw(image, dcts->building.pal, ti->x + dcts->subtile_x, ti->y + dcts->subtile_y, dcts->width, dcts->height, dcts->dz, ti->z, IsTransparencySet(TO_HOUSES) ); if (IsTransparencySet(TO_HOUSES)) return; } { int proc = dcts->draw_proc - 1; if (proc >= 0) _town_draw_tile_procs[proc](ti); } } static int GetSlopePixelZ_Town(TileIndex tile, uint x, uint y) { return GetTileMaxPixelZ(tile); } /** Tile callback routine */ static Foundation GetFoundation_Town(TileIndex tile, Slope tileh) { HouseID hid = GetHouseType(tile); /* For NewGRF house tiles we might not be drawing a foundation. We need to * account for this, as other structures should * draw the wall of the foundation in this case. */ if (hid >= NEW_HOUSE_OFFSET) { const HouseSpec *hs = HouseSpec::Get(hid); if (hs->grf_prop.spritegroup[0] != NULL && HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) { uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, hid, Town::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED && !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res)) return FOUNDATION_NONE; } } return FlatteningFoundation(tileh); } /** * Animate a tile for a town * Only certain houses can be animated * The newhouses animation supersedes regular ones * @param tile TileIndex of the house to animate */ static void AnimateTile_Town(TileIndex tile) { if (GetHouseType(tile) >= NEW_HOUSE_OFFSET) { AnimateNewHouseTile(tile); return; } if (_tick_counter & 3) return; /* If the house is not one with a lift anymore, then stop this animating. * Not exactly sure when this happens, but probably when a house changes. * Before this was just a return...so it'd leak animated tiles.. * That bug seems to have been here since day 1?? */ if (!(HouseSpec::Get(GetHouseType(tile))->building_flags & BUILDING_IS_ANIMATED)) { DeleteAnimatedTile(tile); return; } if (!LiftHasDestination(tile)) { uint i; /* Building has 6 floors, number 0 .. 6, where 1 is illegal. * This is due to the fact that the first floor is, in the graphics, * the height of 2 'normal' floors. * Furthermore, there are 6 lift positions from floor N (incl) to floor N + 1 (excl) */ do { i = RandomRange(7); } while (i == 1 || i * 6 == GetLiftPosition(tile)); SetLiftDestination(tile, i); } int pos = GetLiftPosition(tile); int dest = GetLiftDestination(tile) * 6; pos += (pos < dest) ? 1 : -1; SetLiftPosition(tile, pos); if (pos == dest) { HaltLift(tile); DeleteAnimatedTile(tile); } MarkTileDirtyByTile(tile); } /** * Determines if a town is close to a tile * @param tile TileIndex of the tile to query * @param dist maximum distance to be accepted * @returns true if the tile correspond to the distance criteria */ static bool IsCloseToTown(TileIndex tile, uint dist) { /* On a large map with many towns, it may be faster to check the surroundings of the tile. * An iteration in TILE_AREA_LOOP() is generally 2 times faster than one in FOR_ALL_TOWNS(). */ if (Town::GetNumItems() > (size_t) (dist * dist * 2)) { const int tx = TileX(tile); const int ty = TileY(tile); TileArea tile_area = TileArea( TileXY(max(0, tx - (int) dist), max(0, ty - (int) dist)), TileXY(min(MapMaxX(), tx + (int) dist), min(MapMaxY(), ty + (int) dist)) ); TILE_AREA_LOOP(atile, tile_area) { if (GetTileType(atile) == MP_HOUSE) { Town *t = Town::GetByTile(atile); if (DistanceManhattan(tile, t->xy) < dist) return true; } } return false; } const Town *t; FOR_ALL_TOWNS(t) { if (DistanceManhattan(tile, t->xy) < dist) return true; } return false; } /** * Resize the sign(label) of the town after changes in * population (creation or growth or else) */ void Town::UpdateVirtCoord() { Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE); SetDParam(0, this->index); SetDParam(1, this->cache.population); this->cache.sign.UpdatePosition(pt.x, pt.y - 24 * ZOOM_LVL_BASE, _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, STR_VIEWPORT_TOWN); SetWindowDirty(WC_TOWN_VIEW, this->index); } /** Update the virtual coords needed to draw the town sign for all towns. */ void UpdateAllTownVirtCoords() { Town *t; FOR_ALL_TOWNS(t) { t->UpdateVirtCoord(); } } /** * Change the towns population * @param t Town which population has changed * @param mod population change (can be positive or negative) */ static void ChangePopulation(Town *t, int mod) { t->cache.population += mod; InvalidateWindowData(WC_TOWN_VIEW, t->index); // Cargo requirements may appear/vanish for small populations t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1); } /** * Determines the world population * Basically, count population of all towns, one by one * @return uint32 the calculated population of the world */ uint32 GetWorldPopulation() { uint32 pop = 0; const Town *t; FOR_ALL_TOWNS(t) pop += t->cache.population; return pop; } /** * Helper function for house completion stages progression * @param tile TileIndex of the house (or parts of it) to "grow" */ static void MakeSingleHouseBigger(TileIndex tile) { assert(IsTileType(tile, MP_HOUSE)); /* progress in construction stages */ IncHouseConstructionTick(tile); if (GetHouseConstructionTick(tile) != 0) return; AnimateNewHouseConstruction(tile); if (IsHouseCompleted(tile)) { /* Now that construction is complete, we can add the population of the * building to the town. */ ChangePopulation(Town::GetByTile(tile), HouseSpec::Get(GetHouseType(tile))->population); ResetHouseAge(tile); } MarkTileDirtyByTile(tile); } /** * Make the house advance in its construction stages until completion * @param tile TileIndex of house */ static void MakeTownHouseBigger(TileIndex tile) { uint flags = HouseSpec::Get(GetHouseType(tile))->building_flags; if (flags & BUILDING_HAS_1_TILE) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 0)); if (flags & BUILDING_2_TILES_Y) MakeSingleHouseBigger(TILE_ADDXY(tile, 0, 1)); if (flags & BUILDING_2_TILES_X) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 0)); if (flags & BUILDING_HAS_4_TILES) MakeSingleHouseBigger(TILE_ADDXY(tile, 1, 1)); } /** * Tile callback function. * * Periodic tic handler for houses and town * @param tile been asked to do its stuff */ static void TileLoop_Town(TileIndex tile) { HouseID house_id = GetHouseType(tile); /* NewHouseTileLoop returns false if Callback 21 succeeded, i.e. the house * doesn't exist any more, so don't continue here. */ if (house_id >= NEW_HOUSE_OFFSET && !NewHouseTileLoop(tile)) return; if (!IsHouseCompleted(tile)) { /* Construction is not completed. See if we can go further in construction*/ MakeTownHouseBigger(tile); return; } const HouseSpec *hs = HouseSpec::Get(house_id); /* If the lift has a destination, it is already an animated tile. */ if ((hs->building_flags & BUILDING_IS_ANIMATED) && house_id < NEW_HOUSE_OFFSET && !LiftHasDestination(tile) && Chance16(1, 2)) { AddAnimatedTile(tile); } Town *t = Town::GetByTile(tile); uint32 r = Random(); StationFinder stations(TileArea(tile, 1, 1)); if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) { for (uint i = 0; i < 256; i++) { uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, r, house_id, t, tile); if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break; CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile); if (cargo == CT_INVALID) continue; uint amt = GB(callback, 0, 8); if (amt == 0) continue; uint moved = MoveGoodsToStation(cargo, amt, ST_TOWN, t->index, stations.GetStations()); const CargoSpec *cs = CargoSpec::Get(cargo); t->supplied[cs->Index()].new_max += amt; t->supplied[cs->Index()].new_act += moved; } } else { if (GB(r, 0, 8) < hs->population) { uint amt = GB(r, 0, 8) / 8 + 1; if (EconomyIsInRecession()) amt = (amt + 1) >> 1; t->supplied[CT_PASSENGERS].new_max += amt; t->supplied[CT_PASSENGERS].new_act += MoveGoodsToStation(CT_PASSENGERS, amt, ST_TOWN, t->index, stations.GetStations()); } if (GB(r, 8, 8) < hs->mail_generation) { uint amt = GB(r, 8, 8) / 8 + 1; if (EconomyIsInRecession()) amt = (amt + 1) >> 1; t->supplied[CT_MAIL].new_max += amt; t->supplied[CT_MAIL].new_act += MoveGoodsToStation(CT_MAIL, amt, ST_TOWN, t->index, stations.GetStations()); } } Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); if ((hs->building_flags & BUILDING_HAS_1_TILE) && HasBit(t->flags, TOWN_IS_GROWING) && CanDeleteHouse(tile) && GetHouseAge(tile) >= hs->minimum_life && --t->time_until_rebuild == 0) { t->time_until_rebuild = GB(r, 16, 8) + 192; ClearTownHouse(t, tile); /* Rebuild with another house? */ if (GB(r, 24, 8) >= 12) BuildTownHouse(t, tile); } cur_company.Restore(); } static CommandCost ClearTile_Town(TileIndex tile, DoCommandFlag flags) { if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); if (!CanDeleteHouse(tile)) return CMD_ERROR; const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); CommandCost cost(EXPENSES_CONSTRUCTION); cost.AddCost(hs->GetRemovalCost()); int rating = hs->remove_rating_decrease; Town *t = Town::GetByTile(tile); if (Company::IsValidID(_current_company)) { if (rating > t->ratings[_current_company] && !(flags & DC_NO_TEST_TOWN_RATING) && !_cheats.magic_bulldozer.value) { SetDParam(0, t->index); return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS); } } ChangeTownRating(t, -rating, RATING_HOUSE_MINIMUM, flags); if (flags & DC_EXEC) { ClearTownHouse(t, tile); } return cost; } static void AddProducedCargo_Town(TileIndex tile, CargoArray &produced) { HouseID house_id = GetHouseType(tile); const HouseSpec *hs = HouseSpec::Get(house_id); Town *t = Town::GetByTile(tile); if (HasBit(hs->callback_mask, CBM_HOUSE_PRODUCE_CARGO)) { for (uint i = 0; i < 256; i++) { uint16 callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, house_id, t, tile); if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break; CargoID cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile); if (cargo == CT_INVALID) continue; produced[cargo]++; } } else { if (hs->population > 0) { produced[CT_PASSENGERS]++; } if (hs->mail_generation > 0) { produced[CT_MAIL]++; } } } static inline void AddAcceptedCargoSetMask(CargoID cargo, uint amount, CargoArray &acceptance, uint32 *always_accepted) { if (cargo == CT_INVALID || amount == 0) return; acceptance[cargo] += amount; SetBit(*always_accepted, cargo); } static void AddAcceptedCargo_Town(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); CargoID accepts[3]; /* Set the initial accepted cargo types */ for (uint8 i = 0; i < lengthof(accepts); i++) { accepts[i] = hs->accepts_cargo[i]; } /* Check for custom accepted cargo types */ if (HasBit(hs->callback_mask, CBM_HOUSE_ACCEPT_CARGO)) { uint16 callback = GetHouseCallback(CBID_HOUSE_ACCEPT_CARGO, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile); if (callback != CALLBACK_FAILED) { /* Replace accepted cargo types with translated values from callback */ accepts[0] = GetCargoTranslation(GB(callback, 0, 5), hs->grf_prop.grffile); accepts[1] = GetCargoTranslation(GB(callback, 5, 5), hs->grf_prop.grffile); accepts[2] = GetCargoTranslation(GB(callback, 10, 5), hs->grf_prop.grffile); } } /* Check for custom cargo acceptance */ if (HasBit(hs->callback_mask, CBM_HOUSE_CARGO_ACCEPTANCE)) { uint16 callback = GetHouseCallback(CBID_HOUSE_CARGO_ACCEPTANCE, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile); if (callback != CALLBACK_FAILED) { AddAcceptedCargoSetMask(accepts[0], GB(callback, 0, 4), acceptance, always_accepted); AddAcceptedCargoSetMask(accepts[1], GB(callback, 4, 4), acceptance, always_accepted); if (_settings_game.game_creation.landscape != LT_TEMPERATE && HasBit(callback, 12)) { /* The 'S' bit indicates food instead of goods */ AddAcceptedCargoSetMask(CT_FOOD, GB(callback, 8, 4), acceptance, always_accepted); } else { AddAcceptedCargoSetMask(accepts[2], GB(callback, 8, 4), acceptance, always_accepted); } return; } } /* No custom acceptance, so fill in with the default values */ for (uint8 i = 0; i < lengthof(accepts); i++) { AddAcceptedCargoSetMask(accepts[i], hs->cargo_acceptance[i], acceptance, always_accepted); } } static void GetTileDesc_Town(TileIndex tile, TileDesc *td) { const HouseID house = GetHouseType(tile); const HouseSpec *hs = HouseSpec::Get(house); bool house_completed = IsHouseCompleted(tile); td->str = hs->building_name; uint16 callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, house_completed ? 1 : 0, 0, house, Town::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { if (callback_res > 0x400) { ErrorUnknownCallbackResult(hs->grf_prop.grffile->grfid, CBID_HOUSE_CUSTOM_NAME, callback_res); } else { StringID new_name = GetGRFStringID(hs->grf_prop.grffile->grfid, 0xD000 + callback_res); if (new_name != STR_NULL && new_name != STR_UNDEFINED) { td->str = new_name; } } } if (!house_completed) { SetDParamX(td->dparam, 0, td->str); td->str = STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION; } if (hs->grf_prop.grffile != NULL) { const GRFConfig *gc = GetGRFConfig(hs->grf_prop.grffile->grfid); td->grf = gc->GetName(); } td->owner[0] = OWNER_TOWN; } static TrackStatus GetTileTrackStatus_Town(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { /* not used */ return 0; } static void ChangeTileOwner_Town(TileIndex tile, Owner old_owner, Owner new_owner) { /* not used */ } /** Update the total cargo acceptance of the whole town. * @param t The town to update. */ void UpdateTownCargoTotal(Town *t) { t->cargo_accepted_total = 0; const TileArea &area = t->cargo_accepted.GetArea(); TILE_AREA_LOOP(tile, area) { if (TileX(tile) % AcceptanceMatrix::GRID == 0 && TileY(tile) % AcceptanceMatrix::GRID == 0) { t->cargo_accepted_total |= t->cargo_accepted[tile]; } } } /** * Update accepted town cargoes around a specific tile. * @param t The town to update. * @param start Update the values around this tile. * @param update_total Set to true if the total cargo acceptance should be updated. */ static void UpdateTownCargoes(Town *t, TileIndex start, bool update_total = true) { CargoArray accepted, produced; uint32 dummy; /* Gather acceptance for all houses in an area around the start tile. * The area is composed of the square the tile is in, extended one square in all * directions as the coverage area of a single station is bigger than just one square. */ TileArea area = AcceptanceMatrix::GetAreaForTile(start, 1); TILE_AREA_LOOP(tile, area) { if (!IsTileType(tile, MP_HOUSE) || GetTownIndex(tile) != t->index) continue; AddAcceptedCargo_Town(tile, accepted, &dummy); AddProducedCargo_Town(tile, produced); } /* Create bitmap of produced and accepted cargoes. */ uint32 acc = 0; for (uint cid = 0; cid < NUM_CARGO; cid++) { if (accepted[cid] >= 8) SetBit(acc, cid); if (produced[cid] > 0) SetBit(t->cargo_produced, cid); } t->cargo_accepted[start] = acc; if (update_total) UpdateTownCargoTotal(t); } /** Update cargo acceptance for the complete town. * @param t The town to update. */ void UpdateTownCargoes(Town *t) { t->cargo_produced = 0; const TileArea &area = t->cargo_accepted.GetArea(); if (area.tile == INVALID_TILE) return; /* Update acceptance for each grid square. */ TILE_AREA_LOOP(tile, area) { if (TileX(tile) % AcceptanceMatrix::GRID == 0 && TileY(tile) % AcceptanceMatrix::GRID == 0) { UpdateTownCargoes(t, tile, false); } } /* Update the total acceptance. */ UpdateTownCargoTotal(t); } /** Updates the bitmap of all cargoes accepted by houses. */ void UpdateTownCargoBitmap() { Town *town; _town_cargoes_accepted = 0; FOR_ALL_TOWNS(town) { _town_cargoes_accepted |= town->cargo_accepted_total; } } static bool GrowTown(Town *t); static void TownTickHandler(Town *t) { if (HasBit(t->flags, TOWN_IS_GROWING)) { int i = t->grow_counter - 1; if (i < 0) { if (GrowTown(t)) { i = t->growth_rate & (~TOWN_GROW_RATE_CUSTOM); } else { i = 0; } } t->grow_counter = i; } } void OnTick_Town() { if (_game_mode == GM_EDITOR) return; Town *t; FOR_ALL_TOWNS(t) { /* Run town tick at regular intervals, but not all at once. */ if ((_tick_counter + t->index) % TOWN_GROWTH_TICKS == 0) { TownTickHandler(t); } } } /** * Return the RoadBits of a tile * * @note There are many other functions doing things like that. * @note Needs to be checked for needlessness. * @param tile The tile we want to analyse * @return The roadbits of the given tile */ static RoadBits GetTownRoadBits(TileIndex tile) { if (IsRoadDepotTile(tile) || IsStandardRoadStopTile(tile)) return ROAD_NONE; return GetAnyRoadBits(tile, ROADTYPE_ROAD, true); } /** * Check for parallel road inside a given distance. * Assuming a road from (tile - TileOffsByDiagDir(dir)) to tile, * is there a parallel road left or right of it within distance dist_multi? * * @param tile current tile * @param dir target direction * @param dist_multi distance multiplayer * @return true if there is a parallel road */ static bool IsNeighborRoadTile(TileIndex tile, const DiagDirection dir, uint dist_multi) { if (!IsValidTile(tile)) return false; /* Lookup table for the used diff values */ const TileIndexDiff tid_lt[3] = { TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT)), TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT)), TileOffsByDiagDir(ReverseDiagDir(dir)), }; dist_multi = (dist_multi + 1) * 4; for (uint pos = 4; pos < dist_multi; pos++) { /* Go (pos / 4) tiles to the left or the right */ TileIndexDiff cur = tid_lt[(pos & 1) ? 0 : 1] * (pos / 4); /* Use the current tile as origin, or go one tile backwards */ if (pos & 2) cur += tid_lt[2]; /* Test for roadbit parallel to dir and facing towards the middle axis */ if (IsValidTile(tile + cur) && GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true; } return false; } /** * Check if a Road is allowed on a given tile * * @param t The current town * @param tile The target tile * @param dir The direction in which we want to extend the town * @return true if it is allowed else false */ static bool IsRoadAllowedHere(Town *t, TileIndex tile, DiagDirection dir) { if (DistanceFromEdge(tile) == 0) return false; /* Prevent towns from building roads under bridges along the bridge. Looks silly. */ if (IsBridgeAbove(tile) && GetBridgeAxis(tile) == DiagDirToAxis(dir)) return false; /* Check if there already is a road at this point? */ if (GetTownRoadBits(tile) == ROAD_NONE) { /* No, try if we are able to build a road piece there. * If that fails clear the land, and if that fails exit. * This is to make sure that we can build a road here later. */ if (DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_Y : ROAD_X), 0, DC_AUTO, CMD_BUILD_ROAD).Failed() && DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR).Failed()) { return false; } } Slope cur_slope = _settings_game.construction.build_on_slopes ? GetFoundationSlope(tile) : GetTileSlope(tile); bool ret = !IsNeighborRoadTile(tile, dir, t->layout == TL_ORIGINAL ? 1 : 2); if (cur_slope == SLOPE_FLAT) return ret; /* If the tile is not a slope in the right direction, then * maybe terraform some. */ Slope desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE; if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) { if (Chance16(1, 8)) { CommandCost res = CMD_ERROR; if (!_generating_world && Chance16(1, 10)) { /* Note: Do not replace "^ SLOPE_ELEVATED" with ComplementSlope(). The slope might be steep. */ res = DoCommand(tile, Chance16(1, 16) ? cur_slope : cur_slope ^ SLOPE_ELEVATED, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND); } if (res.Failed() && Chance16(1, 3)) { /* We can consider building on the slope, though. */ return ret; } } return false; } return ret; } static bool TerraformTownTile(TileIndex tile, int edges, int dir) { assert(tile < MapSize()); CommandCost r = DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND); if (r.Failed() || r.GetCost() >= (_price[PR_TERRAFORM] + 2) * 8) return false; DoCommand(tile, edges, dir, DC_AUTO | DC_NO_WATER | DC_EXEC, CMD_TERRAFORM_LAND); return true; } static void LevelTownLand(TileIndex tile) { assert(tile < MapSize()); /* Don't terraform if land is plain or if there's a house there. */ if (IsTileType(tile, MP_HOUSE)) return; Slope tileh = GetTileSlope(tile); if (tileh == SLOPE_FLAT) return; /* First try up, then down */ if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) { TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0); } } /** * Generate the RoadBits of a grid tile * * @param t current town * @param tile tile in reference to the town * @param dir The direction to which we are growing ATM * @return the RoadBit of the current tile regarding * the selected town layout */ static RoadBits GetTownRoadGridElement(Town *t, TileIndex tile, DiagDirection dir) { /* align the grid to the downtown */ TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile); // Vector from downtown to the tile RoadBits rcmd = ROAD_NONE; switch (t->layout) { default: NOT_REACHED(); case TL_2X2_GRID: if ((grid_pos.x % 3) == 0) rcmd |= ROAD_Y; if ((grid_pos.y % 3) == 0) rcmd |= ROAD_X; break; case TL_3X3_GRID: if ((grid_pos.x % 4) == 0) rcmd |= ROAD_Y; if ((grid_pos.y % 4) == 0) rcmd |= ROAD_X; break; } /* Optimise only X-junctions */ if (rcmd != ROAD_ALL) return rcmd; RoadBits rb_template; switch (GetTileSlope(tile)) { default: rb_template = ROAD_ALL; break; case SLOPE_W: rb_template = ROAD_NW | ROAD_SW; break; case SLOPE_SW: rb_template = ROAD_Y | ROAD_SW; break; case SLOPE_S: rb_template = ROAD_SW | ROAD_SE; break; case SLOPE_SE: rb_template = ROAD_X | ROAD_SE; break; case SLOPE_E: rb_template = ROAD_SE | ROAD_NE; break; case SLOPE_NE: rb_template = ROAD_Y | ROAD_NE; break; case SLOPE_N: rb_template = ROAD_NE | ROAD_NW; break; case SLOPE_NW: rb_template = ROAD_X | ROAD_NW; break; case SLOPE_STEEP_W: case SLOPE_STEEP_S: case SLOPE_STEEP_E: case SLOPE_STEEP_N: rb_template = ROAD_NONE; break; } /* Stop if the template is compatible to the growth dir */ if (DiagDirToRoadBits(ReverseDiagDir(dir)) & rb_template) return rb_template; /* If not generate a straight road in the direction of the growth */ return DiagDirToRoadBits(dir) | DiagDirToRoadBits(ReverseDiagDir(dir)); } /** * Grows the town with an extra house. * Check if there are enough neighbor house tiles * next to the current tile. If there are enough * add another house. * * @param t The current town * @param tile The target tile for the extra house * @return true if an extra house has been added */ static bool GrowTownWithExtraHouse(Town *t, TileIndex tile) { /* We can't look further than that. */ if (DistanceFromEdge(tile) == 0) return false; uint counter = 0; // counts the house neighbor tiles /* Check the tiles E,N,W and S of the current tile for houses */ for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { /* Count both void and house tiles for checking whether there * are enough houses in the area. This to make it likely that * houses get build up to the edge of the map. */ switch (GetTileType(TileAddByDiagDir(tile, dir))) { case MP_HOUSE: case MP_VOID: counter++; break; default: break; } /* If there are enough neighbors stop here */ if (counter >= 3) { if (BuildTownHouse(t, tile)) { _grow_town_result = GROWTH_SUCCEED; return true; } return false; } } return false; } /** * Grows the town with a road piece. * * @param t The current town * @param tile The current tile * @param rcmd The RoadBits we want to build on the tile * @return true if the RoadBits have been added else false */ static bool GrowTownWithRoad(const Town *t, TileIndex tile, RoadBits rcmd) { if (DoCommand(tile, rcmd, t->index, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD).Succeeded()) { _grow_town_result = GROWTH_SUCCEED; return true; } return false; } /** * Grows the town with a bridge. * At first we check if a bridge is reasonable. * If so we check if we are able to build it. * * @param t The current town * @param tile The current tile * @param bridge_dir The valid direction in which to grow a bridge * @return true if a bridge has been build else false */ static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDirection bridge_dir) { assert(bridge_dir < DIAGDIR_END); const Slope slope = GetTileSlope(tile); /* Make sure the direction is compatible with the slope. * Well we check if the slope has an up bit set in the * reverse direction. */ if (slope != SLOPE_FLAT && slope & InclinedSlope(bridge_dir)) return false; /* Assure that the bridge is connectable to the start side */ if (!(GetTownRoadBits(TileAddByDiagDir(tile, ReverseDiagDir(bridge_dir))) & DiagDirToRoadBits(bridge_dir))) return false; /* We are in the right direction */ uint8 bridge_length = 0; // This value stores the length of the possible bridge TileIndex bridge_tile = tile; // Used to store the other waterside const int delta = TileOffsByDiagDir(bridge_dir); if (slope == SLOPE_FLAT) { /* Bridges starting on flat tiles are only allowed when crossing rivers. */ do { if (bridge_length++ >= 4) { /* Allow to cross rivers, not big lakes. */ return false; } bridge_tile += delta; } while (IsValidTile(bridge_tile) && IsWaterTile(bridge_tile) && !IsSea(bridge_tile)); } else { do { if (bridge_length++ >= 11) { /* Max 11 tile long bridges */ return false; } bridge_tile += delta; } while (IsValidTile(bridge_tile) && IsWaterTile(bridge_tile)); } /* no water tiles in between? */ if (bridge_length == 1) return false; for (uint8 times = 0; times <= 22; times++) { byte bridge_type = RandomRange(MAX_BRIDGES - 1); /* Can we actually build the bridge? */ if (DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE).Succeeded()) { DoCommand(tile, bridge_tile, bridge_type | ROADTYPES_ROAD << 8 | TRANSPORT_ROAD << 15, DC_EXEC | CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)), CMD_BUILD_BRIDGE); _grow_town_result = GROWTH_SUCCEED; return true; } } /* Quit if it selecting an appropriate bridge type fails a large number of times. */ return false; } /** * Grows the given town. * There are at the moment 3 possible way's for * the town expansion: * @li Generate a random tile and check if there is a road allowed * @li TL_ORIGINAL * @li TL_BETTER_ROADS * @li Check if the town geometry allows a road and which one * @li TL_2X2_GRID * @li TL_3X3_GRID * @li Forbid roads, only build houses * * @param tile_ptr The current tile * @param cur_rb The current tiles RoadBits * @param target_dir The target road dir * @param t1 The current town */ static void GrowTownInTile(TileIndex *tile_ptr, RoadBits cur_rb, DiagDirection target_dir, Town *t1) { RoadBits rcmd = ROAD_NONE; // RoadBits for the road construction command TileIndex tile = *tile_ptr; // The main tile on which we base our growth assert(tile < MapSize()); if (cur_rb == ROAD_NONE) { /* Tile has no road. First reset the status counter * to say that this is the last iteration. */ _grow_town_result = GROWTH_SEARCH_STOPPED; if (!_settings_game.economy.allow_town_roads && !_generating_world) return; if (!_settings_game.economy.allow_town_level_crossings && IsTileType(tile, MP_RAILWAY)) return; /* Remove hills etc */ if (!_settings_game.construction.build_on_slopes || Chance16(1, 6)) LevelTownLand(tile); /* Is a road allowed here? */ switch (t1->layout) { default: NOT_REACHED(); case TL_3X3_GRID: case TL_2X2_GRID: rcmd = GetTownRoadGridElement(t1, tile, target_dir); if (rcmd == ROAD_NONE) return; break; case TL_BETTER_ROADS: case TL_ORIGINAL: if (!IsRoadAllowedHere(t1, tile, target_dir)) return; DiagDirection source_dir = ReverseDiagDir(target_dir); if (Chance16(1, 4)) { /* Randomize a new target dir */ do target_dir = RandomDiagDir(); while (target_dir == source_dir); } if (!IsRoadAllowedHere(t1, TileAddByDiagDir(tile, target_dir), target_dir)) { /* A road is not allowed to continue the randomized road, * return if the road we're trying to build is curved. */ if (target_dir != ReverseDiagDir(source_dir)) return; /* Return if neither side of the new road is a house */ if (!IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90RIGHT)), MP_HOUSE) && !IsTileType(TileAddByDiagDir(tile, ChangeDiagDir(target_dir, DIAGDIRDIFF_90LEFT)), MP_HOUSE)) { return; } /* That means that the road is only allowed if there is a house * at any side of the new road. */ } rcmd = DiagDirToRoadBits(target_dir) | DiagDirToRoadBits(source_dir); break; } } else if (target_dir < DIAGDIR_END && !(cur_rb & DiagDirToRoadBits(ReverseDiagDir(target_dir)))) { /* Continue building on a partial road. * Should be always OK, so we only generate * the fitting RoadBits */ _grow_town_result = GROWTH_SEARCH_STOPPED; if (!_settings_game.economy.allow_town_roads && !_generating_world) return; switch (t1->layout) { default: NOT_REACHED(); case TL_3X3_GRID: case TL_2X2_GRID: rcmd = GetTownRoadGridElement(t1, tile, target_dir); break; case TL_BETTER_ROADS: case TL_ORIGINAL: rcmd = DiagDirToRoadBits(ReverseDiagDir(target_dir)); break; } } else { bool allow_house = true; // Value which decides if we want to construct a house /* Reached a tunnel/bridge? Then continue at the other side of it, unless * it is the starting tile. Half the time, we stay on this side then.*/ if (IsTileType(tile, MP_TUNNELBRIDGE)) { if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD && (target_dir != DIAGDIR_END || Chance16(1, 2))) { *tile_ptr = GetOtherTunnelBridgeEnd(tile); } return; } /* Possibly extend the road in a direction. * Randomize a direction and if it has a road, bail out. */ target_dir = RandomDiagDir(); if (cur_rb & DiagDirToRoadBits(target_dir)) return; /* This is the tile we will reach if we extend to this direction. */ TileIndex house_tile = TileAddByDiagDir(tile, target_dir); // position of a possible house /* Don't walk into water. */ if (HasTileWaterGround(house_tile)) return; if (!IsValidTile(house_tile)) return; if (_settings_game.economy.allow_town_roads || _generating_world) { switch (t1->layout) { default: NOT_REACHED(); case TL_3X3_GRID: // Use 2x2 grid afterwards! GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir)); /* FALL THROUGH */ case TL_2X2_GRID: rcmd = GetTownRoadGridElement(t1, tile, target_dir); allow_house = (rcmd & DiagDirToRoadBits(target_dir)) == ROAD_NONE; break; case TL_BETTER_ROADS: // Use original afterwards! GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir)); /* FALL THROUGH */ case TL_ORIGINAL: /* Allow a house at the edge. 60% chance or * always ok if no road allowed. */ rcmd = DiagDirToRoadBits(target_dir); allow_house = (!IsRoadAllowedHere(t1, house_tile, target_dir) || Chance16(6, 10)); break; } } if (allow_house) { /* Build a house, but not if there already is a house there. */ if (!IsTileType(house_tile, MP_HOUSE)) { /* Level the land if possible */ if (Chance16(1, 6)) LevelTownLand(house_tile); /* And build a house. * Set result to -1 if we managed to build it. */ if (BuildTownHouse(t1, house_tile)) { _grow_town_result = GROWTH_SUCCEED; } } return; } _grow_town_result = GROWTH_SEARCH_STOPPED; } /* Return if a water tile */ if (HasTileWaterGround(tile)) return; /* Make the roads look nicer */ rcmd = CleanUpRoadBits(tile, rcmd); if (rcmd == ROAD_NONE) return; /* Only use the target direction for bridges to ensure they're connected. * The target_dir is as computed previously according to town layout, so * it will match it perfectly. */ if (GrowTownWithBridge(t1, tile, target_dir)) return; GrowTownWithRoad(t1, tile, rcmd); } /** * Checks whether a road can be followed or is a dead end, that can not be extended to the next tile. * This only checks trivial but often cases. * @param tile Start tile for road. * @param dir Direction for road to follow or build. * @return true If road is or can be connected in the specified direction. */ static bool CanFollowRoad(TileIndex tile, DiagDirection dir) { TileIndex target_tile = tile + TileOffsByDiagDir(dir); if (!IsValidTile(target_tile)) return false; if (HasTileWaterGround(target_tile)) return false; RoadBits target_rb = GetTownRoadBits(target_tile); if (_settings_game.economy.allow_town_roads || _generating_world) { /* Check whether a road connection exists or can be build. */ switch (GetTileType(target_tile)) { case MP_ROAD: return target_rb != ROAD_NONE; case MP_STATION: return IsDriveThroughStopTile(target_tile); case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(target_tile) == TRANSPORT_ROAD; case MP_HOUSE: case MP_INDUSTRY: case MP_OBJECT: return false; default: /* Checked for void and water earlier */ return true; } } else { /* Check whether a road connection already exists, * and it leads somewhere else. */ RoadBits back_rb = DiagDirToRoadBits(ReverseDiagDir(dir)); return (target_rb & back_rb) != 0 && (target_rb & ~back_rb) != 0; } } /** * Returns "growth" if a house was built, or no if the build failed. * @param t town to inquiry * @param tile to inquiry * @return true if town expansion was possible */ static bool GrowTownAtRoad(Town *t, TileIndex tile) { /* Special case. * @see GrowTownInTile Check the else if */ DiagDirection target_dir = DIAGDIR_END; // The direction in which we want to extend the town assert(tile < MapSize()); /* Number of times to search. * Better roads, 2X2 and 3X3 grid grow quite fast so we give * them a little handicap. */ switch (t->layout) { case TL_BETTER_ROADS: _grow_town_result = 10 + t->cache.num_houses * 2 / 9; break; case TL_3X3_GRID: case TL_2X2_GRID: _grow_town_result = 10 + t->cache.num_houses * 1 / 9; break; default: _grow_town_result = 10 + t->cache.num_houses * 4 / 9; break; } do { RoadBits cur_rb = GetTownRoadBits(tile); // The RoadBits of the current tile /* Try to grow the town from this point */ GrowTownInTile(&tile, cur_rb, target_dir, t); if (_grow_town_result == GROWTH_SUCCEED) return true; /* Exclude the source position from the bitmask * and return if no more road blocks available */ if (IsValidDiagDirection(target_dir)) cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir)); if (cur_rb == ROAD_NONE) return false; if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* Only build in the direction away from the tunnel or bridge. */ target_dir = ReverseDiagDir(GetTunnelBridgeDirection(tile)); } else { /* Select a random bit from the blockmask, walk a step * and continue the search from there. */ do { if (cur_rb == ROAD_NONE) return false; RoadBits target_bits; do { target_dir = RandomDiagDir(); target_bits = DiagDirToRoadBits(target_dir); } while (!(cur_rb & target_bits)); cur_rb &= ~target_bits; } while (!CanFollowRoad(tile, target_dir)); } tile = TileAddByDiagDir(tile, target_dir); if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) { /* Don't allow building over roads of other cities */ if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && Town::GetByTile(tile) != t) { return false; } else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) { /* If we are in the SE, and this road-piece has no town owner yet, it just found an * owner :) (happy happy happy road now) */ SetRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN); SetTownIndex(tile, t->index); } } /* Max number of times is checked. */ } while (--_grow_town_result >= 0); return false; } /** * Generate a random road block. * The probability of a straight road * is somewhat higher than a curved. * * @return A RoadBits value with 2 bits set */ static RoadBits GenRandomRoadBits() { uint32 r = Random(); uint a = GB(r, 0, 2); uint b = GB(r, 8, 2); if (a == b) b ^= 2; return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b)); } /** * Grow the town * @param t town to grow * @return true iff something (house, road, bridge, ...) was built */ static bool GrowTown(Town *t) { static const TileIndexDiffC _town_coord_mod[] = { {-1, 0}, { 1, 1}, { 1, -1}, {-1, -1}, {-1, 0}, { 0, 2}, { 2, 0}, { 0, -2}, {-1, -1}, {-2, 2}, { 2, 2}, { 2, -2}, { 0, 0} }; /* Current "company" is a town */ Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); TileIndex tile = t->xy; // The tile we are working with ATM /* Find a road that we can base the construction on. */ const TileIndexDiffC *ptr; for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) { if (GetTownRoadBits(tile) != ROAD_NONE) { bool success = GrowTownAtRoad(t, tile); cur_company.Restore(); return success; } tile = TILE_ADD(tile, ToTileIndexDiff(*ptr)); } /* No road available, try to build a random road block by * clearing some land and then building a road there. */ if (_settings_game.economy.allow_town_roads || _generating_world) { tile = t->xy; for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) { /* Only work with plain land that not already has a house */ if (!IsTileType(tile, MP_HOUSE) && IsTileFlat(tile)) { if (DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded()) { DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD); cur_company.Restore(); return true; } } tile = TILE_ADD(tile, ToTileIndexDiff(*ptr)); } } cur_company.Restore(); return false; } void UpdateTownRadius(Town *t) { static const uint32 _town_squared_town_zone_radius_data[23][5] = { { 4, 0, 0, 0, 0}, // 0 { 16, 0, 0, 0, 0}, { 25, 0, 0, 0, 0}, { 36, 0, 0, 0, 0}, { 49, 0, 4, 0, 0}, { 64, 0, 4, 0, 0}, // 20 { 64, 0, 9, 0, 1}, { 64, 0, 9, 0, 4}, { 64, 0, 16, 0, 4}, { 81, 0, 16, 0, 4}, { 81, 0, 16, 0, 4}, // 40 { 81, 0, 25, 0, 9}, { 81, 36, 25, 0, 9}, { 81, 36, 25, 16, 9}, { 81, 49, 0, 25, 9}, { 81, 64, 0, 25, 9}, // 60 { 81, 64, 0, 36, 9}, { 81, 64, 0, 36, 16}, {100, 81, 0, 49, 16}, {100, 81, 0, 49, 25}, {121, 81, 0, 49, 25}, // 80 {121, 81, 0, 49, 25}, {121, 81, 0, 49, 36}, // 88 }; if (t->cache.num_houses < 92) { memcpy(t->cache.squared_town_zone_radius, _town_squared_town_zone_radius_data[t->cache.num_houses / 4], sizeof(t->cache.squared_town_zone_radius)); } else { int mass = t->cache.num_houses / 8; /* Actually we are proportional to sqrt() but that's right because we are covering an area. * The offsets are to make sure the radii do not decrease in size when going from the table * to the calculated value.*/ t->cache.squared_town_zone_radius[0] = mass * 15 - 40; t->cache.squared_town_zone_radius[1] = mass * 9 - 15; t->cache.squared_town_zone_radius[2] = 0; t->cache.squared_town_zone_radius[3] = mass * 5 - 5; t->cache.squared_town_zone_radius[4] = mass * 3 + 5; } } void UpdateTownMaxPass(Town *t) { t->supplied[CT_PASSENGERS].old_max = t->cache.population >> 3; t->supplied[CT_MAIL].old_max = t->cache.population >> 4; } /** * Does the actual town creation. * * @param t The town * @param tile Where to put it * @param townnameparts The town name * @param size Parameter for size determination * @param city whether to build a city or town * @param layout the (road) layout of the town * @param manual was the town placed manually? */ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize size, bool city, TownLayout layout, bool manual) { t->xy = tile; t->cache.num_houses = 0; t->time_until_rebuild = 10; UpdateTownRadius(t); t->flags = 0; t->cache.population = 0; t->grow_counter = 0; t->growth_rate = 250; /* Set the default cargo requirement for town growth */ switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_WINTER; break; case LT_TROPIC: if (FindFirstCargoWithTownEffect(TE_FOOD) != NULL) t->goal[TE_FOOD] = TOWN_GROWTH_DESERT; if (FindFirstCargoWithTownEffect(TE_WATER) != NULL) t->goal[TE_WATER] = TOWN_GROWTH_DESERT; break; } t->fund_buildings_months = 0; for (uint i = 0; i != MAX_COMPANIES; i++) t->ratings[i] = RATING_INITIAL; t->have_ratings = 0; t->exclusivity = INVALID_COMPANY; t->exclusive_counter = 0; t->statues = 0; extern int _nb_orig_names; if (_settings_game.game_creation.town_name < _nb_orig_names) { /* Original town name */ t->townnamegrfid = 0; t->townnametype = SPECSTR_TOWNNAME_START + _settings_game.game_creation.town_name; } else { /* Newgrf town name */ t->townnamegrfid = GetGRFTownNameId(_settings_game.game_creation.town_name - _nb_orig_names); t->townnametype = GetGRFTownNameType(_settings_game.game_creation.town_name - _nb_orig_names); } t->townnameparts = townnameparts; t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0); t->InitializeLayout(layout); t->larger_town = city; int x = (int)size * 16 + 3; if (size == TSZ_RANDOM) x = (Random() & 0xF) + 8; /* Don't create huge cities when founding town in-game */ if (city && (!manual || _game_mode == GM_EDITOR)) x *= _settings_game.economy.initial_city_size; t->cache.num_houses += x; UpdateTownRadius(t); int i = x * 4; do { GrowTown(t); } while (--i); t->cache.num_houses -= x; UpdateTownRadius(t); UpdateTownMaxPass(t); UpdateAirportsNoise(); } /** * Checks if it's possible to place a town at given tile * @param tile tile to check * @return error value or zero cost */ static CommandCost TownCanBePlacedHere(TileIndex tile) { /* Check if too close to the edge of map */ if (DistanceFromEdge(tile) < 12) { return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB); } /* Check distance to all other towns. */ if (IsCloseToTown(tile, 20)) { return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN); } /* Can only build on clear flat areas, possibly with trees. */ if ((!IsTileType(tile, MP_CLEAR) && !IsTileType(tile, MP_TREES)) || !IsTileFlat(tile)) { return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } return CommandCost(EXPENSES_OTHER); } /** * Verifies this custom name is unique. Only custom names are checked. * @param name name to check * @return is this name unique? */ static bool IsUniqueTownName(const char *name) { const Town *t; FOR_ALL_TOWNS(t) { if (t->name != NULL && strcmp(t->name, name) == 0) return false; } return true; } /** * Create a new town. * @param tile coordinates where town is built * @param flags type of operation * @param p1 0..1 size of the town (@see TownSize) * 2 true iff it should be a city * 3..5 town road layout (@see TownLayout) * 6 use random location (randomize \c tile ) * @param p2 town name parts * @param text Custom name for the town. If empty, the town name parts will be used. * @return the cost of this operation or an error */ CommandCost CmdFoundTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { TownSize size = Extract(p1); bool city = HasBit(p1, 2); TownLayout layout = Extract(p1); TownNameParams par(_settings_game.game_creation.town_name); bool random = HasBit(p1, 6); uint32 townnameparts = p2; if (size >= TSZ_END) return CMD_ERROR; if (layout >= NUM_TLS) return CMD_ERROR; /* Some things are allowed only in the scenario editor and for game scripts. */ if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY) { if (_settings_game.economy.found_town == TF_FORBIDDEN) return CMD_ERROR; if (size == TSZ_LARGE) return CMD_ERROR; if (random) return CMD_ERROR; if (_settings_game.economy.found_town != TF_CUSTOM_LAYOUT && layout != _settings_game.economy.town_layout) { return CMD_ERROR; } } else if (_current_company == OWNER_DEITY && random) { /* Random parameter is not allowed for Game Scripts. */ return CMD_ERROR; } if (StrEmpty(text)) { /* If supplied name is empty, townnameparts has to generate unique automatic name */ if (!VerifyTownName(townnameparts, &par)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } else { /* If name is not empty, it has to be unique custom name */ if (Utf8StringLength(text) >= MAX_LENGTH_TOWN_NAME_CHARS) return CMD_ERROR; if (!IsUniqueTownName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } /* Allocate town struct */ if (!Town::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_TOWNS); if (!random) { CommandCost ret = TownCanBePlacedHere(tile); if (ret.Failed()) return ret; } static const byte price_mult[][TSZ_RANDOM + 1] = {{ 15, 25, 40, 25 }, { 20, 35, 55, 35 }}; /* multidimensional arrays have to have defined length of non-first dimension */ assert_compile(lengthof(price_mult[0]) == 4); CommandCost cost(EXPENSES_OTHER, _price[PR_BUILD_TOWN]); byte mult = price_mult[city][size]; cost.MultiplyCost(mult); /* Create the town */ if (flags & DC_EXEC) { if (cost.GetCost() > GetAvailableMoneyForCommand()) { _additional_cash_required = cost.GetCost(); return CommandCost(EXPENSES_OTHER); } Backup old_generating_world(_generating_world, true, FILE_LINE); UpdateNearestTownForRoadTiles(true); Town *t; if (random) { t = CreateRandomTown(20, townnameparts, size, city, layout); if (t == NULL) { cost = CommandCost(STR_ERROR_NO_SPACE_FOR_TOWN); } else { _new_town_id = t->index; } } else { t = new Town(tile); DoCreateTown(t, tile, townnameparts, size, city, layout, true); } UpdateNearestTownForRoadTiles(false); old_generating_world.Restore(); if (t != NULL && !StrEmpty(text)) { t->name = stredup(text); t->UpdateVirtCoord(); } if (_game_mode != GM_EDITOR) { /* 't' can't be NULL since 'random' is false outside scenedit */ assert(!random); char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH]; SetDParam(0, _current_company); GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); char *cn = stredup(company_name); SetDParamStr(0, cn); SetDParam(1, t->index); AddTileNewsItem(STR_NEWS_NEW_TOWN, NT_INDUSTRY_OPEN, tile, cn); AI::BroadcastNewEvent(new ScriptEventTownFounded(t->index)); Game::NewEvent(new ScriptEventTownFounded(t->index)); } } return cost; } /** * Towns must all be placed on the same grid or when they eventually * interpenetrate their road networks will not mesh nicely; this * function adjusts a tile so that it aligns properly. * * @param tile the tile to start at * @param layout which town layout algo is in effect * @return the adjusted tile */ static TileIndex AlignTileToGrid(TileIndex tile, TownLayout layout) { switch (layout) { case TL_2X2_GRID: return TileXY(TileX(tile) - TileX(tile) % 3, TileY(tile) - TileY(tile) % 3); case TL_3X3_GRID: return TileXY(TileX(tile) & ~3, TileY(tile) & ~3); default: return tile; } } /** * Towns must all be placed on the same grid or when they eventually * interpenetrate their road networks will not mesh nicely; this * function tells you if a tile is properly aligned. * * @param tile the tile to start at * @param layout which town layout algo is in effect * @return true if the tile is in the correct location */ static bool IsTileAlignedToGrid(TileIndex tile, TownLayout layout) { switch (layout) { case TL_2X2_GRID: return TileX(tile) % 3 == 0 && TileY(tile) % 3 == 0; case TL_3X3_GRID: return TileX(tile) % 4 == 0 && TileY(tile) % 4 == 0; default: return true; } } /** * Used as the user_data for FindFurthestFromWater */ struct SpotData { TileIndex tile; ///< holds the tile that was found uint max_dist; ///< holds the distance that tile is from the water TownLayout layout; ///< tells us what kind of town we're building }; /** * CircularTileSearch callback; finds the tile furthest from any * water. slightly bit tricky, since it has to do a search of its own * in order to find the distance to the water from each square in the * radius. * * Also, this never returns true, because it needs to take into * account all locations being searched before it knows which is the * furthest. * * @param tile Start looking from this tile * @param user_data Storage area for data that must last across calls; * must be a pointer to struct SpotData * * @return always false */ static bool FindFurthestFromWater(TileIndex tile, void *user_data) { SpotData *sp = (SpotData*)user_data; uint dist = GetClosestWaterDistance(tile, true); if (IsTileType(tile, MP_CLEAR) && IsTileFlat(tile) && IsTileAlignedToGrid(tile, sp->layout) && dist > sp->max_dist) { sp->tile = tile; sp->max_dist = dist; } return false; } /** * CircularTileSearch callback; finds the nearest land tile * * @param tile Start looking from this tile * @param user_data not used */ static bool FindNearestEmptyLand(TileIndex tile, void *user_data) { return IsTileType(tile, MP_CLEAR); } /** * Given a spot on the map (presumed to be a water tile), find a good * coastal spot to build a city. We don't want to build too close to * the edge if we can help it (since that retards city growth) hence * the search within a search within a search. O(n*m^2), where n is * how far to search for land, and m is how far inland to look for a * flat spot. * * @param tile Start looking from this spot. * @param layout the road layout to search for * @return tile that was found */ static TileIndex FindNearestGoodCoastalTownSpot(TileIndex tile, TownLayout layout) { SpotData sp = { INVALID_TILE, 0, layout }; TileIndex coast = tile; if (CircularTileSearch(&coast, 40, FindNearestEmptyLand, NULL)) { CircularTileSearch(&coast, 10, FindFurthestFromWater, &sp); return sp.tile; } /* if we get here just give up */ return INVALID_TILE; } static Town *CreateRandomTown(uint attempts, uint32 townnameparts, TownSize size, bool city, TownLayout layout) { assert(_game_mode == GM_EDITOR || _generating_world); // These are the preconditions for CMD_DELETE_TOWN if (!Town::CanAllocateItem()) return NULL; do { /* Generate a tile index not too close from the edge */ TileIndex tile = AlignTileToGrid(RandomTile(), layout); /* if we tried to place the town on water, slide it over onto * the nearest likely-looking spot */ if (IsTileType(tile, MP_WATER)) { tile = FindNearestGoodCoastalTownSpot(tile, layout); if (tile == INVALID_TILE) continue; } /* Make sure town can be placed here */ if (TownCanBePlacedHere(tile).Failed()) continue; /* Allocate a town struct */ Town *t = new Town(tile); DoCreateTown(t, tile, townnameparts, size, city, layout, false); /* if the population is still 0 at the point, then the * placement is so bad it couldn't grow at all */ if (t->cache.population > 0) return t; Backup cur_company(_current_company, OWNER_TOWN, FILE_LINE); CommandCost rc = DoCommand(t->xy, t->index, 0, DC_EXEC, CMD_DELETE_TOWN); cur_company.Restore(); assert(rc.Succeeded()); /* We already know that we can allocate a single town when * entering this function. However, we create and delete * a town which "resets" the allocation checks. As such we * need to check again when assertions are enabled. */ assert(Town::CanAllocateItem()); } while (--attempts != 0); return NULL; } static const byte _num_initial_towns[4] = {5, 11, 23, 46}; // very low, low, normal, high /** * This function will generate a certain amount of towns, with a certain layout * It can be called from the scenario editor (i.e.: generate Random Towns) * as well as from world creation. * @param layout which towns will be set to, when created * @return true if towns have been successfully created */ bool GenerateTowns(TownLayout layout) { uint current_number = 0; uint difficulty = (_game_mode != GM_EDITOR) ? _settings_game.difficulty.number_towns : 0; uint total = (difficulty == (uint)CUSTOM_TOWN_NUMBER_DIFFICULTY) ? _settings_game.game_creation.custom_town_number : ScaleByMapSize(_num_initial_towns[difficulty] + (Random() & 7)); total = min(TownPool::MAX_SIZE, total); uint32 townnameparts; TownNames town_names; SetGeneratingWorldProgress(GWP_TOWN, total); /* First attempt will be made at creating the suggested number of towns. * Note that this is really a suggested value, not a required one. * We would not like the system to lock up just because the user wanted 100 cities on a 64*64 map, would we? */ do { bool city = (_settings_game.economy.larger_towns != 0 && Chance16(1, _settings_game.economy.larger_towns)); IncreaseGeneratingWorldProgress(GWP_TOWN); /* Get a unique name for the town. */ if (!GenerateTownName(&townnameparts, &town_names)) continue; /* try 20 times to create a random-sized town for the first loop. */ if (CreateRandomTown(20, townnameparts, TSZ_RANDOM, city, layout) != NULL) current_number++; // If creation was successful, raise a flag. } while (--total); town_names.clear(); if (current_number != 0) return true; /* If current_number is still zero at this point, it means that not a single town has been created. * So give it a last try, but now more aggressive */ if (GenerateTownName(&townnameparts) && CreateRandomTown(10000, townnameparts, TSZ_RANDOM, _settings_game.economy.larger_towns != 0, layout) != NULL) { return true; } /* If there are no towns at all and we are generating new game, bail out */ if (Town::GetNumItems() == 0 && _game_mode != GM_EDITOR) { ShowErrorMessage(STR_ERROR_COULD_NOT_CREATE_TOWN, INVALID_STRING_ID, WL_CRITICAL); } return false; // we are still without a town? we failed, simply } /** * Returns the bit corresponding to the town zone of the specified tile * @param t Town on which town zone is to be found * @param tile TileIndex where town zone needs to be found * @return the bit position of the given zone, as defined in HouseZones */ HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile) { uint dist = DistanceSquare(tile, t->xy); if (t->fund_buildings_months && dist <= 25) return HZB_TOWN_CENTRE; HouseZonesBits smallest = HZB_TOWN_EDGE; for (HouseZonesBits i = HZB_BEGIN; i < HZB_END; i++) { if (dist < t->cache.squared_town_zone_radius[i]) smallest = i; } return smallest; } /** * Clears tile and builds a house or house part. * @param tile tile index * @param t The town to clear the house for * @param counter of construction step * @param stage of construction (used for drawing) * @param type of house. Index into house specs array * @param random_bits required for newgrf houses * @pre house can be built here */ static inline void ClearMakeHouseTile(TileIndex tile, Town *t, byte counter, byte stage, HouseID type, byte random_bits) { CommandCost cc = DoCommand(tile, 0, 0, DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR); assert(cc.Succeeded()); IncreaseBuildingCount(t, type); MakeHouseTile(tile, t->index, counter, stage, type, random_bits); if (HouseSpec::Get(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(tile); MarkTileDirtyByTile(tile); } /** * Write house information into the map. For houses > 1 tile, all tiles are marked. * @param t tile index * @param town The town related to this house * @param counter of construction step * @param stage of construction (used for drawing) * @param type of house. Index into house specs array * @param random_bits required for newgrf houses * @pre house can be built here */ static void MakeTownHouse(TileIndex t, Town *town, byte counter, byte stage, HouseID type, byte random_bits) { BuildingFlags size = HouseSpec::Get(type)->building_flags; ClearMakeHouseTile(t, town, counter, stage, type, random_bits); if (size & BUILDING_2_TILES_Y) ClearMakeHouseTile(t + TileDiffXY(0, 1), town, counter, stage, ++type, random_bits); if (size & BUILDING_2_TILES_X) ClearMakeHouseTile(t + TileDiffXY(1, 0), town, counter, stage, ++type, random_bits); if (size & BUILDING_HAS_4_TILES) ClearMakeHouseTile(t + TileDiffXY(1, 1), town, counter, stage, ++type, random_bits); } /** * Checks if a house can be built here. Important is slope, bridge above * and ability to clear the land. * @param tile tile to check * @param town town that is checking * @param noslope are slopes (foundations) allowed? * @return true iff house can be built here */ static inline bool CanBuildHouseHere(TileIndex tile, TownID town, bool noslope) { /* cannot build on these slopes... */ Slope slope = GetTileSlope(tile); if ((noslope && slope != SLOPE_FLAT) || IsSteepSlope(slope)) return false; /* building under a bridge? */ if (IsBridgeAbove(tile)) return false; /* do not try to build over house owned by another town */ if (IsTileType(tile, MP_HOUSE) && GetTownIndex(tile) != town) return false; /* can we clear the land? */ return DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR).Succeeded(); } /** * Checks if a house can be built at this tile, must have the same max z as parameter. * @param tile tile to check * @param town town that is checking * @param z max z of this tile so more parts of a house are at the same height (with foundation) * @param noslope are slopes (foundations) allowed? * @return true iff house can be built here * @see CanBuildHouseHere() */ static inline bool CheckBuildHouseSameZ(TileIndex tile, TownID town, int z, bool noslope) { if (!CanBuildHouseHere(tile, town, noslope)) return false; /* if building on slopes is allowed, there will be flattening foundation (to tile max z) */ if (GetTileMaxZ(tile) != z) return false; return true; } /** * Checks if a house of size 2x2 can be built at this tile * @param tile tile, N corner * @param town town that is checking * @param z maximum tile z so all tile have the same max z * @param noslope are slopes (foundations) allowed? * @return true iff house can be built * @see CheckBuildHouseSameZ() */ static bool CheckFree2x2Area(TileIndex tile, TownID town, int z, bool noslope) { /* we need to check this tile too because we can be at different tile now */ if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false; for (DiagDirection d = DIAGDIR_SE; d < DIAGDIR_END; d++) { tile += TileOffsByDiagDir(d); if (!CheckBuildHouseSameZ(tile, town, z, noslope)) return false; } return true; } /** * Checks if current town layout allows building here * @param t town * @param tile tile to check * @return true iff town layout allows building here * @note see layouts */ static inline bool TownLayoutAllowsHouseHere(Town *t, TileIndex tile) { /* Allow towns everywhere when we don't build roads */ if (!_settings_game.economy.allow_town_roads && !_generating_world) return true; TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile); switch (t->layout) { case TL_2X2_GRID: if ((grid_pos.x % 3) == 0 || (grid_pos.y % 3) == 0) return false; break; case TL_3X3_GRID: if ((grid_pos.x % 4) == 0 || (grid_pos.y % 4) == 0) return false; break; default: break; } return true; } /** * Checks if current town layout allows 2x2 building here * @param t town * @param tile tile to check * @return true iff town layout allows 2x2 building here * @note see layouts */ static inline bool TownLayoutAllows2x2HouseHere(Town *t, TileIndex tile) { /* Allow towns everywhere when we don't build roads */ if (!_settings_game.economy.allow_town_roads && !_generating_world) return true; /* Compute relative position of tile. (Positive offsets are towards north) */ TileIndexDiffC grid_pos = TileIndexToTileIndexDiffC(t->xy, tile); switch (t->layout) { case TL_2X2_GRID: grid_pos.x %= 3; grid_pos.y %= 3; if ((grid_pos.x != 2 && grid_pos.x != -1) || (grid_pos.y != 2 && grid_pos.y != -1)) return false; break; case TL_3X3_GRID: if ((grid_pos.x & 3) < 2 || (grid_pos.y & 3) < 2) return false; break; default: break; } return true; } /** * Checks if 1x2 or 2x1 building is allowed here, also takes into account current town layout * Also, tests both building positions that occupy this tile * @param tile tile where the building should be built * @param t town * @param maxz all tiles should have the same height * @param noslope are slopes forbidden? * @param second diagdir from first tile to second tile */ static bool CheckTownBuild2House(TileIndex *tile, Town *t, int maxz, bool noslope, DiagDirection second) { /* 'tile' is already checked in BuildTownHouse() - CanBuildHouseHere() and slope test */ TileIndex tile2 = *tile + TileOffsByDiagDir(second); if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) return true; tile2 = *tile + TileOffsByDiagDir(ReverseDiagDir(second)); if (TownLayoutAllowsHouseHere(t, tile2) && CheckBuildHouseSameZ(tile2, t->index, maxz, noslope)) { *tile = tile2; return true; } return false; } /** * Checks if 2x2 building is allowed here, also takes into account current town layout * Also, tests all four building positions that occupy this tile * @param tile tile where the building should be built * @param t town * @param maxz all tiles should have the same height * @param noslope are slopes forbidden? */ static bool CheckTownBuild2x2House(TileIndex *tile, Town *t, int maxz, bool noslope) { TileIndex tile2 = *tile; for (DiagDirection d = DIAGDIR_SE;; d++) { // 'd' goes through DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_END if (TownLayoutAllows2x2HouseHere(t, tile2) && CheckFree2x2Area(tile2, t->index, maxz, noslope)) { *tile = tile2; return true; } if (d == DIAGDIR_END) break; tile2 += TileOffsByDiagDir(ReverseDiagDir(d)); // go clockwise } return false; } /** * Tries to build a house at this tile * @param t town the house will belong to * @param tile where the house will be built * @return false iff no house can be built at this tile */ static bool BuildTownHouse(Town *t, TileIndex tile) { /* forbidden building here by town layout */ if (!TownLayoutAllowsHouseHere(t, tile)) return false; /* no house allowed at all, bail out */ if (!CanBuildHouseHere(tile, t->index, false)) return false; Slope slope = GetTileSlope(tile); int maxz = GetTileMaxZ(tile); /* Get the town zone type of the current tile, as well as the climate. * This will allow to easily compare with the specs of the new house to build */ HouseZonesBits rad = GetTownRadiusGroup(t, tile); /* Above snow? */ int land = _settings_game.game_creation.landscape; if (land == LT_ARCTIC && maxz > HighestSnowLine()) land = -1; uint bitmask = (1 << rad) + (1 << (land + 12)); /* bits 0-4 are used * bits 11-15 are used * bits 5-10 are not used. */ HouseID houses[NUM_HOUSES]; uint num = 0; uint probs[NUM_HOUSES]; uint probability_max = 0; /* Generate a list of all possible houses that can be built. */ for (uint i = 0; i < NUM_HOUSES; i++) { const HouseSpec *hs = HouseSpec::Get(i); /* Verify that the candidate house spec matches the current tile status */ if ((~hs->building_availability & bitmask) != 0 || !hs->enabled || hs->grf_prop.override != INVALID_HOUSE_ID) continue; /* Don't let these counters overflow. Global counters are 32bit, there will never be that many houses. */ if (hs->class_id != HOUSE_NO_CLASS) { /* id_count is always <= class_count, so it doesn't need to be checked */ if (t->cache.building_counts.class_count[hs->class_id] == UINT16_MAX) continue; } else { /* If the house has no class, check id_count instead */ if (t->cache.building_counts.id_count[i] == UINT16_MAX) continue; } /* Without NewHouses, all houses have probability '1' */ uint cur_prob = (_loaded_newgrf_features.has_newhouses ? hs->probability : 1); probability_max += cur_prob; probs[num] = cur_prob; houses[num++] = (HouseID)i; } TileIndex baseTile = tile; while (probability_max > 0) { /* Building a multitile building can change the location of tile. * The building would still be built partially on that tile, but * its northern tile would be elsewhere. However, if the callback * fails we would be basing further work from the changed tile. * So a next 1x1 tile building could be built on the wrong tile. */ tile = baseTile; uint r = RandomRange(probability_max); uint i; for (i = 0; i < num; i++) { if (probs[i] > r) break; r -= probs[i]; } HouseID house = houses[i]; probability_max -= probs[i]; /* remove tested house from the set */ num--; houses[i] = houses[num]; probs[i] = probs[num]; const HouseSpec *hs = HouseSpec::Get(house); if (_loaded_newgrf_features.has_newhouses && !_generating_world && _game_mode != GM_EDITOR && (hs->extra_flags & BUILDING_IS_HISTORICAL) != 0) { continue; } if (_cur_year < hs->min_year || _cur_year > hs->max_year) continue; /* Special houses that there can be only one of. */ uint oneof = 0; if (hs->building_flags & BUILDING_IS_CHURCH) { SetBit(oneof, TOWN_HAS_CHURCH); } else if (hs->building_flags & BUILDING_IS_STADIUM) { SetBit(oneof, TOWN_HAS_STADIUM); } if (t->flags & oneof) continue; /* Make sure there is no slope? */ bool noslope = (hs->building_flags & TILE_NOT_SLOPED) != 0; if (noslope && slope != SLOPE_FLAT) continue; if (hs->building_flags & TILE_SIZE_2x2) { if (!CheckTownBuild2x2House(&tile, t, maxz, noslope)) continue; } else if (hs->building_flags & TILE_SIZE_2x1) { if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SW)) continue; } else if (hs->building_flags & TILE_SIZE_1x2) { if (!CheckTownBuild2House(&tile, t, maxz, noslope, DIAGDIR_SE)) continue; } else { /* 1x1 house checks are already done */ } byte random_bits = Random(); if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) { uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile, true, random_bits); if (callback_res != CALLBACK_FAILED && !Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_ALLOW_CONSTRUCTION, callback_res)) continue; } /* build the house */ t->cache.num_houses++; /* Special houses that there can be only one of. */ t->flags |= oneof; byte construction_counter = 0; byte construction_stage = 0; if (_generating_world || _game_mode == GM_EDITOR) { uint32 r = Random(); construction_stage = TOWN_HOUSE_COMPLETED; if (Chance16(1, 7)) construction_stage = GB(r, 0, 2); if (construction_stage == TOWN_HOUSE_COMPLETED) { ChangePopulation(t, hs->population); } else { construction_counter = GB(r, 2, 2); } } MakeTownHouse(tile, t, construction_counter, construction_stage, house, random_bits); UpdateTownRadius(t); UpdateTownCargoes(t, tile); return true; } return false; } /** * Update data structures when a house is removed * @param tile Tile of the house * @param t Town owning the house * @param house House type */ static void DoClearTownHouseHelper(TileIndex tile, Town *t, HouseID house) { assert(IsTileType(tile, MP_HOUSE)); DecreaseBuildingCount(t, house); DoClearSquare(tile); DeleteAnimatedTile(tile); DeleteNewGRFInspectWindow(GSF_HOUSES, tile); } /** * Determines if a given HouseID is part of a multitile house. * The given ID is set to the ID of the north tile and the TileDiff to the north tile is returned. * * @param house Is changed to the HouseID of the north tile of the same house * @return TileDiff from the tile of the given HouseID to the north tile */ TileIndexDiff GetHouseNorthPart(HouseID &house) { if (house >= 3) { // house id 0,1,2 MUST be single tile houses, or this code breaks. if (HouseSpec::Get(house - 1)->building_flags & TILE_SIZE_2x1) { house--; return TileDiffXY(-1, 0); } else if (HouseSpec::Get(house - 1)->building_flags & BUILDING_2_TILES_Y) { house--; return TileDiffXY(0, -1); } else if (HouseSpec::Get(house - 2)->building_flags & BUILDING_HAS_4_TILES) { house -= 2; return TileDiffXY(-1, 0); } else if (HouseSpec::Get(house - 3)->building_flags & BUILDING_HAS_4_TILES) { house -= 3; return TileDiffXY(-1, -1); } } return 0; } void ClearTownHouse(Town *t, TileIndex tile) { assert(IsTileType(tile, MP_HOUSE)); HouseID house = GetHouseType(tile); /* need to align the tile to point to the upper left corner of the house */ tile += GetHouseNorthPart(house); // modifies house to the ID of the north tile const HouseSpec *hs = HouseSpec::Get(house); /* Remove population from the town if the house is finished. */ if (IsHouseCompleted(tile)) { ChangePopulation(t, -hs->population); } t->cache.num_houses--; /* Clear flags for houses that only may exist once/town. */ if (hs->building_flags & BUILDING_IS_CHURCH) { ClrBit(t->flags, TOWN_HAS_CHURCH); } else if (hs->building_flags & BUILDING_IS_STADIUM) { ClrBit(t->flags, TOWN_HAS_STADIUM); } /* Do the actual clearing of tiles */ uint eflags = hs->building_flags; DoClearTownHouseHelper(tile, t, house); if (eflags & BUILDING_2_TILES_Y) DoClearTownHouseHelper(tile + TileDiffXY(0, 1), t, ++house); if (eflags & BUILDING_2_TILES_X) DoClearTownHouseHelper(tile + TileDiffXY(1, 0), t, ++house); if (eflags & BUILDING_HAS_4_TILES) DoClearTownHouseHelper(tile + TileDiffXY(1, 1), t, ++house); UpdateTownRadius(t); /* Update cargo acceptance. */ UpdateTownCargoes(t, tile); } /** * Rename a town (server-only). * @param tile unused * @param flags type of operation * @param p1 town ID to rename * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Town *t = Town::GetIfValid(p1); if (t == NULL) return CMD_ERROR; bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_TOWN_NAME_CHARS) return CMD_ERROR; if (!IsUniqueTownName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { free(t->name); t->name = reset ? NULL : stredup(text); t->UpdateVirtCoord(); InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1); UpdateAllStationVirtCoords(); } return CommandCost(); } /** * Determines the first cargo with a certain town effect * @param effect Town effect of interest * @return first active cargo slot with that effect */ const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect) { const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { if (cs->town_effect == effect) return cs; } return NULL; } static void UpdateTownGrowRate(Town *t); /** * Change the cargo goal of a town. * @param tile Unused. * @param flags Type of operation. * @param p1 various bitstuffed elements * - p1 = (bit 0 - 15) - Town ID to cargo game of. * - p1 = (bit 16 - 23) - TownEffect to change the game of. * @param p2 The new goal value. * @param text Unused. * @return Empty cost or an error. */ CommandCost CmdTownCargoGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; TownEffect te = (TownEffect)GB(p1, 16, 8); if (te < TE_BEGIN || te >= TE_END) return CMD_ERROR; uint16 index = GB(p1, 0, 16); Town *t = Town::GetIfValid(index); if (t == NULL) return CMD_ERROR; /* Validate if there is a cargo which is the requested TownEffect */ const CargoSpec *cargo = FindFirstCargoWithTownEffect(te); if (cargo == NULL) return CMD_ERROR; if (flags & DC_EXEC) { t->goal[te] = p2; UpdateTownGrowRate(t); InvalidateWindowData(WC_TOWN_VIEW, index); } return CommandCost(); } /** * Set a custom text in the Town window. * @param tile Unused. * @param flags Type of operation. * @param p1 Town ID to change the text of. * @param p2 Unused. * @param text The new text (empty to remove the text). * @return Empty cost or an error. */ CommandCost CmdTownSetText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; Town *t = Town::GetIfValid(p1); if (t == NULL) return CMD_ERROR; if (flags & DC_EXEC) { free(t->text); t->text = StrEmpty(text) ? NULL : stredup(text); InvalidateWindowData(WC_TOWN_VIEW, p1); } return CommandCost(); } /** * Change the growth rate of the town. * @param tile Unused. * @param flags Type of operation. * @param p1 Town ID to cargo game of. * @param p2 Amount of days between growth, or TOWN_GROW_RATE_CUSTOM_NONE, or 0 to reset custom growth rate. * @param text Unused. * @return Empty cost or an error. */ CommandCost CmdTownGrowthRate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if ((p2 & TOWN_GROW_RATE_CUSTOM) != 0 && p2 != TOWN_GROW_RATE_CUSTOM_NONE) return CMD_ERROR; if (GB(p2, 16, 16) != 0) return CMD_ERROR; Town *t = Town::GetIfValid(p1); if (t == NULL) return CMD_ERROR; if (flags & DC_EXEC) { if (p2 == 0) { /* Clear TOWN_GROW_RATE_CUSTOM, UpdateTownGrowRate will determine a proper value */ t->growth_rate = 0; } else { uint old_rate = t->growth_rate & ~TOWN_GROW_RATE_CUSTOM; if (t->grow_counter >= old_rate) { /* This also catches old_rate == 0 */ t->grow_counter = p2; } else { /* Scale grow_counter, so half finished houses stay half finished */ t->grow_counter = t->grow_counter * p2 / old_rate; } t->growth_rate = p2 | TOWN_GROW_RATE_CUSTOM; } UpdateTownGrowRate(t); InvalidateWindowData(WC_TOWN_VIEW, p1); } return CommandCost(); } /** * Expand a town (scenario editor only). * @param tile Unused. * @param flags Type of operation. * @param p1 Town ID to expand. * @param p2 Amount to grow, or 0 to grow a random size up to the current amount of houses. * @param text Unused. * @return Empty cost or an error. */ CommandCost CmdExpandTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_game_mode != GM_EDITOR && _current_company != OWNER_DEITY) return CMD_ERROR; Town *t = Town::GetIfValid(p1); if (t == NULL) return CMD_ERROR; if (flags & DC_EXEC) { /* The more houses, the faster we grow */ if (p2 == 0) { uint amount = RandomRange(ClampToU16(t->cache.num_houses / 10)) + 3; t->cache.num_houses += amount; UpdateTownRadius(t); uint n = amount * 10; do GrowTown(t); while (--n); t->cache.num_houses -= amount; } else { for (; p2 > 0; p2--) { /* Try several times to grow, as we are really suppose to grow */ for (uint i = 0; i < 25; i++) if (GrowTown(t)) break; } } UpdateTownRadius(t); UpdateTownMaxPass(t); } return CommandCost(); } /** * Delete a town (scenario editor or worldgen only). * @param tile Unused. * @param flags Type of operation. * @param p1 Town ID to delete. * @param p2 Unused. * @param text Unused. * @return Empty cost or an error. */ CommandCost CmdDeleteTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_game_mode != GM_EDITOR && !_generating_world) return CMD_ERROR; Town *t = Town::GetIfValid(p1); if (t == NULL) return CMD_ERROR; /* Stations refer to towns. */ const Station *st; FOR_ALL_STATIONS(st) { if (st->town == t) { /* Non-oil rig stations are always a problem. */ if (!(st->facilities & FACIL_AIRPORT) || st->airport.type != AT_OILRIG) return CMD_ERROR; /* We can only automatically delete oil rigs *if* there's no vehicle on them. */ CommandCost ret = DoCommand(st->airport.tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; } } /* Depots refer to towns. */ const Depot *d; FOR_ALL_DEPOTS(d) { if (d->town == t) return CMD_ERROR; } /* Check all tiles for town ownership. */ for (TileIndex tile = 0; tile < MapSize(); ++tile) { bool try_clear = false; switch (GetTileType(tile)) { case MP_ROAD: try_clear = HasTownOwnedRoad(tile) && GetTownIndex(tile) == t->index; break; case MP_TUNNELBRIDGE: try_clear = IsTileOwner(tile, OWNER_TOWN) && ClosestTownFromTile(tile, UINT_MAX) == t; break; case MP_HOUSE: try_clear = GetTownIndex(tile) == t->index; break; case MP_INDUSTRY: try_clear = Industry::GetByTile(tile)->town == t; break; case MP_OBJECT: if (Town::GetNumItems() == 1) { /* No towns will be left, remove it! */ try_clear = true; } else { Object *o = Object::GetByTile(tile); if (o->town == t) { if (o->type == OBJECT_STATUE) { /* Statue... always remove. */ try_clear = true; } else { /* Tell to find a new town. */ if (flags & DC_EXEC) o->town = NULL; } } } break; default: break; } if (try_clear) { CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; } } /* The town destructor will delete the other things related to the town. */ if (flags & DC_EXEC) delete t; return CommandCost(); } /** * Factor in the cost of each town action. * @see TownActions */ const byte _town_action_costs[TACT_COUNT] = { 2, 4, 9, 35, 48, 53, 117, 175 }; static CommandCost TownActionAdvertiseSmall(Town *t, DoCommandFlag flags) { if (flags & DC_EXEC) { ModifyStationRatingAround(t->xy, _current_company, 0x40, 10); } return CommandCost(); } static CommandCost TownActionAdvertiseMedium(Town *t, DoCommandFlag flags) { if (flags & DC_EXEC) { ModifyStationRatingAround(t->xy, _current_company, 0x70, 15); } return CommandCost(); } static CommandCost TownActionAdvertiseLarge(Town *t, DoCommandFlag flags) { if (flags & DC_EXEC) { ModifyStationRatingAround(t->xy, _current_company, 0xA0, 20); } return CommandCost(); } static CommandCost TownActionRoadRebuild(Town *t, DoCommandFlag flags) { /* Check if the company is allowed to fund new roads. */ if (!_settings_game.economy.fund_roads) return CMD_ERROR; if (flags & DC_EXEC) { t->road_build_months = 6; char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH]; SetDParam(0, _current_company); GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); char *cn = stredup(company_name); SetDParam(0, t->index); SetDParamStr(1, cn); AddNewsItem(STR_NEWS_ROAD_REBUILDING, NT_GENERAL, NF_NORMAL, NR_TOWN, t->index, NR_NONE, UINT32_MAX, cn); AI::BroadcastNewEvent(new ScriptEventRoadReconstruction((ScriptCompany::CompanyID)(Owner)_current_company, t->index)); Game::NewEvent(new ScriptEventRoadReconstruction((ScriptCompany::CompanyID)(Owner)_current_company, t->index)); } return CommandCost(); } /** * Check whether the land can be cleared. * @param tile Tile to check. * @return The tile can be cleared. */ static bool TryClearTile(TileIndex tile) { Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); CommandCost r = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); return r.Succeeded(); } /** Structure for storing data while searching the best place to build a statue. */ struct StatueBuildSearchData { TileIndex best_position; ///< Best position found so far. int tile_count; ///< Number of tiles tried. StatueBuildSearchData(TileIndex best_pos, int count) : best_position(best_pos), tile_count(count) { } }; /** * Search callback function for #TownActionBuildStatue. * @param tile Tile on which to perform the search. * @param user_data Reference to the statue search data. * @return Result of the test. */ static bool SearchTileForStatue(TileIndex tile, void *user_data) { static const int STATUE_NUMBER_INNER_TILES = 25; // Number of tiles int the center of the city, where we try to protect houses. StatueBuildSearchData *statue_data = (StatueBuildSearchData *)user_data; statue_data->tile_count++; /* Statues can be build on slopes, just like houses. Only the steep slopes is a no go. */ if (IsSteepSlope(GetTileSlope(tile))) return false; /* Don't build statues under bridges. */ if (IsBridgeAbove(tile)) return false; /* A clear-able open space is always preferred. */ if ((IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES)) && TryClearTile(tile)) { statue_data->best_position = tile; return true; } bool house = IsTileType(tile, MP_HOUSE); /* Searching inside the inner circle. */ if (statue_data->tile_count <= STATUE_NUMBER_INNER_TILES) { /* Save first house in inner circle. */ if (house && statue_data->best_position == INVALID_TILE && TryClearTile(tile)) { statue_data->best_position = tile; } /* If we have reached the end of the inner circle, and have a saved house, terminate the search. */ return statue_data->tile_count == STATUE_NUMBER_INNER_TILES && statue_data->best_position != INVALID_TILE; } /* Searching outside the circle, just pick the first possible spot. */ statue_data->best_position = tile; // Is optimistic, the condition below must also hold. return house && TryClearTile(tile); } /** * Perform a 9x9 tiles circular search from the center of the town * in order to find a free tile to place a statue * @param t town to search in * @param flags Used to check if the statue must be built or not. * @return Empty cost or an error. */ static CommandCost TownActionBuildStatue(Town *t, DoCommandFlag flags) { if (!Object::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_OBJECTS); TileIndex tile = t->xy; StatueBuildSearchData statue_data(INVALID_TILE, 0); if (!CircularTileSearch(&tile, 9, SearchTileForStatue, &statue_data)) return_cmd_error(STR_ERROR_STATUE_NO_SUITABLE_PLACE); if (flags & DC_EXEC) { Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); DoCommand(statue_data.best_position, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); BuildObject(OBJECT_STATUE, statue_data.best_position, _current_company, t); SetBit(t->statues, _current_company); // Once found and built, "inform" the Town. MarkTileDirtyByTile(statue_data.best_position); } return CommandCost(); } static CommandCost TownActionFundBuildings(Town *t, DoCommandFlag flags) { /* Check if it's allowed to buy the rights */ if (!_settings_game.economy.fund_buildings) return CMD_ERROR; if (flags & DC_EXEC) { /* Build next tick */ t->grow_counter = 1; /* And grow for 3 months */ t->fund_buildings_months = 3; /* Enable growth (also checking GameScript's opinion) */ UpdateTownGrowRate(t); SetWindowDirty(WC_TOWN_VIEW, t->index); } return CommandCost(); } static CommandCost TownActionBuyRights(Town *t, DoCommandFlag flags) { /* Check if it's allowed to buy the rights */ if (!_settings_game.economy.exclusive_rights) return CMD_ERROR; if (flags & DC_EXEC) { t->exclusive_counter = 12; t->exclusivity = _current_company; ModifyStationRatingAround(t->xy, _current_company, 130, 17); SetWindowClassesDirty(WC_STATION_VIEW); /* Spawn news message */ CompanyNewsInformation *cni = MallocT(1); cni->FillData(Company::Get(_current_company)); SetDParam(0, STR_NEWS_EXCLUSIVE_RIGHTS_TITLE); SetDParam(1, STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION); SetDParam(2, t->index); SetDParamStr(3, cni->company_name); AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NT_GENERAL, NF_COMPANY, NR_TOWN, t->index, NR_NONE, UINT32_MAX, cni); AI::BroadcastNewEvent(new ScriptEventExclusiveTransportRights((ScriptCompany::CompanyID)(Owner)_current_company, t->index)); Game::NewEvent(new ScriptEventExclusiveTransportRights((ScriptCompany::CompanyID)(Owner)_current_company, t->index)); } return CommandCost(); } static CommandCost TownActionBribe(Town *t, DoCommandFlag flags) { if (flags & DC_EXEC) { if (Chance16(1, 14)) { /* set as unwanted for 6 months */ t->unwanted[_current_company] = 6; /* set all close by station ratings to 0 */ Station *st; FOR_ALL_STATIONS(st) { if (st->town == t && st->owner == _current_company) { for (CargoID i = 0; i < NUM_CARGO; i++) st->goods[i].rating = 0; } } /* only show error message to the executing player. All errors are handled command.c * but this is special, because it can only 'fail' on a DC_EXEC */ if (IsLocalCompany()) ShowErrorMessage(STR_ERROR_BRIBE_FAILED, INVALID_STRING_ID, WL_INFO); /* decrease by a lot! * ChangeTownRating is only for stuff in demolishing. Bribe failure should * be independent of any cheat settings */ if (t->ratings[_current_company] > RATING_BRIBE_DOWN_TO) { t->ratings[_current_company] = RATING_BRIBE_DOWN_TO; SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } } else { ChangeTownRating(t, RATING_BRIBE_UP_STEP, RATING_BRIBE_MAXIMUM, DC_EXEC); } } return CommandCost(); } typedef CommandCost TownActionProc(Town *t, DoCommandFlag flags); static TownActionProc * const _town_action_proc[] = { TownActionAdvertiseSmall, TownActionAdvertiseMedium, TownActionAdvertiseLarge, TownActionRoadRebuild, TownActionBuildStatue, TownActionFundBuildings, TownActionBuyRights, TownActionBribe }; /** * Get a list of available actions to do at a town. * @param nump if not NULL add put the number of available actions in it * @param cid the company that is querying the town * @param t the town that is queried * @return bitmasked value of enabled actions */ uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t) { int num = 0; TownActions buttons = TACT_NONE; /* Spectators and unwanted have no options */ if (cid != COMPANY_SPECTATOR && !(_settings_game.economy.bribe && t->unwanted[cid])) { /* Things worth more than this are not shown */ Money avail = Company::Get(cid)->money + _price[PR_STATION_VALUE] * 200; /* Check the action bits for validity and * if they are valid add them */ for (uint i = 0; i != lengthof(_town_action_costs); i++) { const TownActions cur = (TownActions)(1 << i); /* Is the company not able to bribe ? */ if (cur == TACT_BRIBE && (!_settings_game.economy.bribe || t->ratings[cid] >= RATING_BRIBE_MAXIMUM)) continue; /* Is the company not able to buy exclusive rights ? */ if (cur == TACT_BUY_RIGHTS && !_settings_game.economy.exclusive_rights) continue; /* Is the company not able to fund buildings ? */ if (cur == TACT_FUND_BUILDINGS && !_settings_game.economy.fund_buildings) continue; /* Is the company not able to fund local road reconstruction? */ if (cur == TACT_ROAD_REBUILD && !_settings_game.economy.fund_roads) continue; /* Is the company not able to build a statue ? */ if (cur == TACT_BUILD_STATUE && HasBit(t->statues, cid)) continue; if (avail >= _town_action_costs[i] * _price[PR_TOWN_ACTION] >> 8) { buttons |= cur; num++; } } } if (nump != NULL) *nump = num; return buttons; } /** * Do a town action. * This performs an action such as advertising, building a statue, funding buildings, * but also bribing the town-council * @param tile unused * @param flags type of operation * @param p1 town to do the action at * @param p2 action to perform, @see _town_action_proc for the list of available actions * @param text unused * @return the cost of this operation or an error */ CommandCost CmdDoTownAction(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Town *t = Town::GetIfValid(p1); if (t == NULL || p2 >= lengthof(_town_action_proc)) return CMD_ERROR; if (!HasBit(GetMaskOfTownActions(NULL, _current_company, t), p2)) return CMD_ERROR; CommandCost cost(EXPENSES_OTHER, _price[PR_TOWN_ACTION] * _town_action_costs[p2] >> 8); CommandCost ret = _town_action_proc[p2](t, flags); if (ret.Failed()) return ret; if (flags & DC_EXEC) { SetWindowDirty(WC_TOWN_AUTHORITY, p1); } return cost; } static void UpdateTownRating(Town *t) { /* Increase company ratings if they're low */ const Company *c; FOR_ALL_COMPANIES(c) { if (t->ratings[c->index] < RATING_GROWTH_MAXIMUM) { t->ratings[c->index] = min((int)RATING_GROWTH_MAXIMUM, t->ratings[c->index] + RATING_GROWTH_UP_STEP); } } const Station *st; FOR_ALL_STATIONS(st) { if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) { if (st->time_since_load <= 20 || st->time_since_unload <= 20) { if (Company::IsValidID(st->owner)) { int new_rating = t->ratings[st->owner] + RATING_STATION_UP_STEP; t->ratings[st->owner] = min(new_rating, INT16_MAX); // do not let it overflow } } else { if (Company::IsValidID(st->owner)) { int new_rating = t->ratings[st->owner] + RATING_STATION_DOWN_STEP; t->ratings[st->owner] = max(new_rating, INT16_MIN); } } } } /* clamp all ratings to valid values */ for (uint i = 0; i < MAX_COMPANIES; i++) { t->ratings[i] = Clamp(t->ratings[i], RATING_MINIMUM, RATING_MAXIMUM); } SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } static void UpdateTownGrowRate(Town *t) { ClrBit(t->flags, TOWN_IS_GROWING); SetWindowDirty(WC_TOWN_VIEW, t->index); if (_settings_game.economy.town_growth_rate == 0 && t->fund_buildings_months == 0) return; if (t->fund_buildings_months == 0) { /* Check if all goals are reached for this town to grow (given we are not funding it) */ for (int i = TE_BEGIN; i < TE_END; i++) { switch (t->goal[i]) { case TOWN_GROWTH_WINTER: if (TileHeight(t->xy) >= GetSnowLine() && t->received[i].old_act == 0 && t->cache.population > 90) return; break; case TOWN_GROWTH_DESERT: if (GetTropicZone(t->xy) == TROPICZONE_DESERT && t->received[i].old_act == 0 && t->cache.population > 60) return; break; default: if (t->goal[i] > t->received[i].old_act) return; break; } } } if ((t->growth_rate & TOWN_GROW_RATE_CUSTOM) != 0) { if (t->growth_rate != TOWN_GROW_RATE_CUSTOM_NONE) SetBit(t->flags, TOWN_IS_GROWING); SetWindowDirty(WC_TOWN_VIEW, t->index); return; } /** * Towns are processed every TOWN_GROWTH_TICKS ticks, and this is the * number of times towns are processed before a new building is built. */ static const uint16 _grow_count_values[2][6] = { { 120, 120, 120, 100, 80, 60 }, // Fund new buildings has been activated { 320, 420, 300, 220, 160, 100 } // Normal values }; int n = 0; const Station *st; FOR_ALL_STATIONS(st) { if (DistanceSquare(st->xy, t->xy) <= t->cache.squared_town_zone_radius[0]) { if (st->time_since_load <= 20 || st->time_since_unload <= 20) { n++; } } } uint16 m; if (t->fund_buildings_months != 0) { m = _grow_count_values[0][min(n, 5)]; } else { m = _grow_count_values[1][min(n, 5)]; if (n == 0 && !Chance16(1, 12)) return; } /* Use the normal growth rate values if new buildings have been funded in * this town and the growth rate is set to none. */ uint growth_multiplier = _settings_game.economy.town_growth_rate != 0 ? _settings_game.economy.town_growth_rate - 1 : 1; m >>= growth_multiplier; if (t->larger_town) m /= 2; t->growth_rate = m / (t->cache.num_houses / 50 + 1); t->grow_counter = min(t->growth_rate, t->grow_counter); SetBit(t->flags, TOWN_IS_GROWING); SetWindowDirty(WC_TOWN_VIEW, t->index); } static void UpdateTownAmounts(Town *t) { for (CargoID i = 0; i < NUM_CARGO; i++) t->supplied[i].NewMonth(); for (int i = TE_BEGIN; i < TE_END; i++) t->received[i].NewMonth(); if (t->fund_buildings_months != 0) t->fund_buildings_months--; SetWindowDirty(WC_TOWN_VIEW, t->index); } static void UpdateTownUnwanted(Town *t) { const Company *c; FOR_ALL_COMPANIES(c) { if (t->unwanted[c->index] > 0) t->unwanted[c->index]--; } } /** * Checks whether the local authority allows construction of a new station (rail, road, airport, dock) on the given tile * @param tile The tile where the station shall be constructed. * @param flags Command flags. DC_NO_TEST_TOWN_RATING is tested. * @return Succeeded or failed command. */ CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags) { if (!Company::IsValidID(_current_company) || (flags & DC_NO_TEST_TOWN_RATING)) return CommandCost(); Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); if (t == NULL) return CommandCost(); if (t->ratings[_current_company] > RATING_VERYPOOR) return CommandCost(); SetDParam(0, t->index); return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS); } /** * Return the town closest to the given tile within \a threshold. * @param tile Starting point of the search. * @param threshold Biggest allowed distance to the town. * @return Closest town to \a tile within \a threshold, or \c NULL if there is no such town. * * @note This function only uses distance, the #ClosestTownFromTile function also takes town ownership into account. */ Town *CalcClosestTownFromTile(TileIndex tile, uint threshold) { Town *t; uint best = threshold; Town *best_town = NULL; FOR_ALL_TOWNS(t) { uint dist = DistanceManhattan(tile, t->xy); if (dist < best) { best = dist; best_town = t; } } return best_town; } /** * Return the town closest (in distance or ownership) to a given tile, within a given threshold. * @param tile Starting point of the search. * @param threshold Biggest allowed distance to the town. * @return Closest town to \a tile within \a threshold, or \c NULL if there is no such town. * * @note If you only care about distance, you can use the #CalcClosestTownFromTile function. */ Town *ClosestTownFromTile(TileIndex tile, uint threshold) { switch (GetTileType(tile)) { case MP_ROAD: if (IsRoadDepot(tile)) return CalcClosestTownFromTile(tile, threshold); if (!HasTownOwnedRoad(tile)) { TownID tid = GetTownIndex(tile); if (tid == (TownID)INVALID_TOWN) { /* in the case we are generating "many random towns", this value may be INVALID_TOWN */ if (_generating_world) return CalcClosestTownFromTile(tile, threshold); assert(Town::GetNumItems() == 0); return NULL; } assert(Town::IsValidID(tid)); Town *town = Town::Get(tid); if (DistanceManhattan(tile, town->xy) >= threshold) town = NULL; return town; } /* FALL THROUGH */ case MP_HOUSE: return Town::GetByTile(tile); default: return CalcClosestTownFromTile(tile, threshold); } } static bool _town_rating_test = false; ///< If \c true, town rating is in test-mode. static SmallMap _town_test_ratings; ///< Map of towns to modified ratings, while in town rating test-mode. /** * Switch the town rating to test-mode, to allow commands to be tested without affecting current ratings. * The function is safe to use in nested calls. * @param mode Test mode switch (\c true means go to test-mode, \c false means leave test-mode). */ void SetTownRatingTestMode(bool mode) { static int ref_count = 0; // Number of times test-mode is switched on. if (mode) { if (ref_count == 0) { _town_test_ratings.Clear(); } ref_count++; } else { assert(ref_count > 0); ref_count--; } _town_rating_test = !(ref_count == 0); } /** * Get the rating of a town for the #_current_company. * @param t Town to get the rating from. * @return Rating of the current company in the given town. */ static int GetRating(const Town *t) { if (_town_rating_test) { SmallMap::iterator it = _town_test_ratings.Find(t); if (it != _town_test_ratings.End()) { return it->second; } } return t->ratings[_current_company]; } /** * Changes town rating of the current company * @param t Town to affect * @param add Value to add * @param max Minimum (add < 0) resp. maximum (add > 0) rating that should be achievable with this change. * @param flags Command flags, especially DC_NO_MODIFY_TOWN_RATING is tested */ void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags) { /* if magic_bulldozer cheat is active, town doesn't penalize for removing stuff */ if (t == NULL || (flags & DC_NO_MODIFY_TOWN_RATING) || !Company::IsValidID(_current_company) || (_cheats.magic_bulldozer.value && add < 0)) { return; } int rating = GetRating(t); if (add < 0) { if (rating > max) { rating += add; if (rating < max) rating = max; } } else { if (rating < max) { rating += add; if (rating > max) rating = max; } } if (_town_rating_test) { _town_test_ratings[t] = rating; } else { SetBit(t->have_ratings, _current_company); t->ratings[_current_company] = rating; SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } } /** * Does the town authority allow the (destructive) action of the current company? * @param flags Checking flags of the command. * @param t Town that must allow the company action. * @param type Type of action that is wanted. * @return A succeeded command if the action is allowed, a failed command if it is not allowed. */ CommandCost CheckforTownRating(DoCommandFlag flags, Town *t, TownRatingCheckType type) { /* if magic_bulldozer cheat is active, town doesn't restrict your destructive actions */ if (t == NULL || !Company::IsValidID(_current_company) || _cheats.magic_bulldozer.value || (flags & DC_NO_TEST_TOWN_RATING)) { return CommandCost(); } /* minimum rating needed to be allowed to remove stuff */ static const int needed_rating[][TOWN_RATING_CHECK_TYPE_COUNT] = { /* ROAD_REMOVE, TUNNELBRIDGE_REMOVE */ { RATING_ROAD_NEEDED_PERMISSIVE, RATING_TUNNEL_BRIDGE_NEEDED_PERMISSIVE}, // Permissive { RATING_ROAD_NEEDED_NEUTRAL, RATING_TUNNEL_BRIDGE_NEEDED_NEUTRAL}, // Neutral { RATING_ROAD_NEEDED_HOSTILE, RATING_TUNNEL_BRIDGE_NEEDED_HOSTILE}, // Hostile }; /* check if you're allowed to remove the road/bridge/tunnel * owned by a town no removal if rating is lower than ... depends now on * difficulty setting. Minimum town rating selected by difficulty level */ int needed = needed_rating[_settings_game.difficulty.town_council_tolerance][type]; if (GetRating(t) < needed) { SetDParam(0, t->index); return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS); } return CommandCost(); } void TownsMonthlyLoop() { Town *t; FOR_ALL_TOWNS(t) { if (t->road_build_months != 0) t->road_build_months--; if (t->exclusive_counter != 0) { if (--t->exclusive_counter == 0) t->exclusivity = INVALID_COMPANY; } UpdateTownAmounts(t); UpdateTownRating(t); UpdateTownGrowRate(t); UpdateTownUnwanted(t); UpdateTownCargoes(t); } UpdateTownCargoBitmap(); } void TownsYearlyLoop() { /* Increment house ages */ for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_HOUSE)) continue; IncrementHouseAge(t); } } static CommandCost TerraformTile_Town(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { if (AutoslopeEnabled()) { HouseID house = GetHouseType(tile); GetHouseNorthPart(house); // modifies house to the ID of the north tile const HouseSpec *hs = HouseSpec::Get(house); /* Here we differ from TTDP by checking TILE_NOT_SLOPED */ if (((hs->building_flags & TILE_NOT_SLOPED) == 0) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) { bool allow_terraform = true; /* Call the autosloping callback per tile, not for the whole building at once. */ house = GetHouseType(tile); hs = HouseSpec::Get(house); if (HasBit(hs->callback_mask, CBM_HOUSE_AUTOSLOPE)) { /* If the callback fails, allow autoslope. */ uint16 res = GetHouseCallback(CBID_HOUSE_AUTOSLOPE, 0, 0, house, Town::GetByTile(tile), tile); if (res != CALLBACK_FAILED && ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_AUTOSLOPE, res)) allow_terraform = false; } if (allow_terraform) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } /** Tile callback functions for a town */ extern const TileTypeProcs _tile_type_town_procs = { DrawTile_Town, // draw_tile_proc GetSlopePixelZ_Town, // get_slope_z_proc ClearTile_Town, // clear_tile_proc AddAcceptedCargo_Town, // add_accepted_cargo_proc GetTileDesc_Town, // get_tile_desc_proc GetTileTrackStatus_Town, // get_tile_track_status_proc NULL, // click_tile_proc AnimateTile_Town, // animate_tile_proc TileLoop_Town, // tile_loop_proc ChangeTileOwner_Town, // change_tile_owner_proc AddProducedCargo_Town, // add_produced_cargo_proc NULL, // vehicle_enter_tile_proc GetFoundation_Town, // get_foundation_proc TerraformTile_Town, // terraform_tile_proc }; HouseSpec _house_specs[NUM_HOUSES]; void ResetHouses() { memset(&_house_specs, 0, sizeof(_house_specs)); memcpy(&_house_specs, &_original_house_specs, sizeof(_original_house_specs)); /* Reset any overrides that have been set. */ _house_mngr.ResetOverride(); } openttd-1.5.3/src/signs_gui.cpp0000644000000000000000000004465012627373446015204 0ustar rootroot/* $Id: signs_gui.cpp 26827 2014-09-15 19:26:03Z frosch $ */ /* * 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 signs_gui.cpp The GUI for signs. */ #include "stdafx.h" #include "company_gui.h" #include "company_func.h" #include "signs_base.h" #include "signs_func.h" #include "debug.h" #include "command_func.h" #include "strings_func.h" #include "window_func.h" #include "map_func.h" #include "viewport_func.h" #include "querystring_gui.h" #include "sortlist_type.h" #include "stringfilter_type.h" #include "string_func.h" #include "core/geometry_func.hpp" #include "hotkeys.h" #include "transparency.h" #include "widgets/sign_widget.h" #include "table/strings.h" #include "table/sprites.h" #include "safeguards.h" struct SignList { /** * A GUIList contains signs and uses a StringFilter for filtering. */ typedef GUIList GUISignList; static const Sign *last_sign; GUISignList signs; StringFilter string_filter; ///< The match string to be used when the GUIList is (re)-sorted. static bool match_case; ///< Should case sensitive matching be used? /** * Creates a SignList with filtering disabled by default. */ SignList() : string_filter(&match_case) { } void BuildSignsList() { if (!this->signs.NeedRebuild()) return; DEBUG(misc, 3, "Building sign list"); this->signs.Clear(); const Sign *si; FOR_ALL_SIGNS(si) *this->signs.Append() = si; this->signs.SetFilterState(true); this->FilterSignList(); this->signs.Compact(); this->signs.RebuildDone(); } /** Sort signs by their name */ static int CDECL SignNameSorter(const Sign * const *a, const Sign * const *b) { static char buf_cache[64]; char buf[64]; SetDParam(0, (*a)->index); GetString(buf, STR_SIGN_NAME, lastof(buf)); if (*b != last_sign) { last_sign = *b; SetDParam(0, (*b)->index); GetString(buf_cache, STR_SIGN_NAME, lastof(buf_cache)); } int r = strnatcmp(buf, buf_cache); // Sort by name (natural sorting). return r != 0 ? r : ((*a)->index - (*b)->index); } void SortSignsList() { if (!this->signs.Sort(&SignNameSorter)) return; /* Reset the name sorter sort cache */ this->last_sign = NULL; } /** Filter sign list by sign name */ static bool CDECL SignNameFilter(const Sign * const *a, StringFilter &filter) { /* Get sign string */ char buf1[MAX_LENGTH_SIGN_NAME_CHARS * MAX_CHAR_LENGTH]; SetDParam(0, (*a)->index); GetString(buf1, STR_SIGN_NAME, lastof(buf1)); filter.ResetState(); filter.AddLine(buf1); return filter.GetState(); } /** Filter sign list excluding OWNER_DEITY */ static bool CDECL OwnerDeityFilter(const Sign * const *a, StringFilter &filter) { /* You should never be able to edit signs of owner DEITY */ return (*a)->owner != OWNER_DEITY; } /** Filter sign list by owner */ static bool CDECL OwnerVisibilityFilter(const Sign * const *a, StringFilter &filter) { assert(!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)); /* Hide sign if non-own signs are hidden in the viewport */ return (*a)->owner == _local_company || (*a)->owner == OWNER_DEITY; } /** Filter out signs from the sign list that does not match the name filter */ void FilterSignList() { this->signs.Filter(&SignNameFilter, this->string_filter); if (_game_mode != GM_EDITOR) this->signs.Filter(&OwnerDeityFilter, this->string_filter); if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)) { this->signs.Filter(&OwnerVisibilityFilter, this->string_filter); } } }; const Sign *SignList::last_sign = NULL; bool SignList::match_case = false; /** Enum referring to the Hotkeys in the sign list window */ enum SignListHotkeys { SLHK_FOCUS_FILTER_BOX, ///< Focus the edit box for editing the filter string }; struct SignListWindow : Window, SignList { QueryString filter_editbox; ///< Filter editbox; int text_offset; ///< Offset of the sign text relative to the left edge of the WID_SIL_LIST widget. Scrollbar *vscroll; SignListWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), filter_editbox(MAX_LENGTH_SIGN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_SIGN_NAME_CHARS) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_SIL_SCROLLBAR); this->FinishInitNested(window_number); this->SetWidgetLoweredState(WID_SIL_FILTER_MATCH_CASE_BTN, SignList::match_case); /* Initialize the text edit widget */ this->querystrings[WID_SIL_FILTER_TEXT] = &this->filter_editbox; this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; /* Initialize the filtering variables */ this->SetFilterString(""); /* Create initial list. */ this->signs.ForceRebuild(); this->signs.ForceResort(); this->BuildSortSignList(); } /** * This function sets the filter string of the sign list. The contents of * the edit widget is not updated by this function. Depending on if the * new string is zero-length or not the clear button is made * disabled/enabled. The sign list is updated according to the new filter. */ void SetFilterString(const char *new_filter_string) { /* check if there is a new filter string */ this->string_filter.SetFilterTerm(new_filter_string); /* Rebuild the list of signs */ this->InvalidateData(); } virtual void OnPaint() { if (this->signs.NeedRebuild()) this->BuildSortSignList(); this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_SIL_LIST: { uint y = r.top + WD_FRAMERECT_TOP; // Offset from top of widget. /* No signs? */ if (this->vscroll->GetCount() == 0) { DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_STATION_LIST_NONE); return; } bool rtl = _current_text_dir == TD_RTL; int sprite_offset_y = (FONT_HEIGHT_NORMAL - 10) / 2 + 1; uint icon_left = 4 + (rtl ? r.right - this->text_offset : r.left); uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : this->text_offset); uint text_right = r.right - (rtl ? this->text_offset : WD_FRAMERECT_RIGHT); /* At least one sign available. */ for (uint16 i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < this->vscroll->GetCount(); i++) { const Sign *si = this->signs[i]; if (si->owner != OWNER_NONE) DrawCompanyIcon(si->owner, icon_left, y + sprite_offset_y); SetDParam(0, si->index); DrawString(text_left, text_right, y, STR_SIGN_NAME, TC_YELLOW); y += this->resize.step_height; } break; } } } virtual void SetStringParameters(int widget) const { if (widget == WID_SIL_CAPTION) SetDParam(0, this->vscroll->GetCount()); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_SIL_LIST: { uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SIL_LIST, WD_FRAMERECT_TOP); if (id_v == INT_MAX) return; const Sign *si = this->signs[id_v]; ScrollMainWindowToTile(TileVirtXY(si->x, si->y)); break; } case WID_SIL_FILTER_ENTER_BTN: if (this->signs.Length() >= 1) { const Sign *si = this->signs[0]; ScrollMainWindowToTile(TileVirtXY(si->x, si->y)); } break; case WID_SIL_FILTER_MATCH_CASE_BTN: SignList::match_case = !SignList::match_case; // Toggle match case this->SetWidgetLoweredState(WID_SIL_FILTER_MATCH_CASE_BTN, SignList::match_case); // Toggle button pushed state this->InvalidateData(); // Rebuild the list of signs break; } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_SIL_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SIL_LIST: { Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON); this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2; // 2 pixels space between icon and the sign text. resize->height = max(FONT_HEIGHT_NORMAL, spr_dim.height); Dimension d = {this->text_offset + WD_FRAMETEXT_RIGHT, WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM}; *size = maxdim(*size, d); break; } case WID_SIL_CAPTION: SetDParamMaxValue(0, Sign::GetPoolSize(), 3); *size = GetStringBoundingBox(STR_SIGN_LIST_CAPTION); size->height += padding.height; size->width += padding.width; break; } } virtual EventState OnHotkey(int hotkey) { switch (hotkey) { case SLHK_FOCUS_FILTER_BOX: this->SetFocusedWidget(WID_SIL_FILTER_TEXT); SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused. break; default: return ES_NOT_HANDLED; } return ES_HANDLED; } virtual void OnEditboxChanged(int widget) { if (widget == WID_SIL_FILTER_TEXT) this->SetFilterString(this->filter_editbox.text.buf); } void BuildSortSignList() { if (this->signs.NeedRebuild()) { this->BuildSignsList(); this->vscroll->SetCount(this->signs.Length()); this->SetWidgetDirty(WID_SIL_CAPTION); } this->SortSignsList(); } virtual void OnHundredthTick() { this->BuildSortSignList(); this->SetDirty(); } /** * 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) { /* When there is a filter string, we always need to rebuild the list even if * the amount of signs in total is unchanged, as the subset of signs that is * accepted by the filter might has changed. */ if (data == 0 || data == -1 || !this->string_filter.IsEmpty()) { // New or deleted sign, changed visibility setting or there is a filter string /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->signs.ForceRebuild(); } else { // Change of sign contents while there is no filter string this->signs.ForceResort(); } } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the SignListWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState SignListGlobalHotkeys(int hotkey) { if (_game_mode == GM_MENU) return ES_NOT_HANDLED; Window *w = ShowSignList(); if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } static Hotkey signlist_hotkeys[] = { Hotkey('F', "focus_filter_box", SLHK_FOCUS_FILTER_BOX), HOTKEY_LIST_END }; HotkeyList SignListWindow::hotkeys("signlist", signlist_hotkeys, SignListGlobalHotkeys); static const NWidgetPart _nested_sign_list_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_SIL_CAPTION), SetDataTip(STR_SIGN_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_SIL_LIST), SetMinimalSize(WD_FRAMETEXT_LEFT + 16 + 255 + WD_FRAMETEXT_RIGHT, 50), SetResize(1, 10), SetFill(1, 0), SetScrollbar(WID_SIL_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SIL_FILTER_TEXT), SetMinimalSize(80, 12), SetResize(1, 0), SetFill(1, 0), SetPadding(2, 2, 2, 2), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SIL_FILTER_MATCH_CASE_BTN), SetDataTip(STR_SIGN_LIST_MATCH_CASE, STR_SIGN_LIST_MATCH_CASE_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VERTICAL), SetFill(0, 1), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SIL_SCROLLBAR), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), }; static WindowDesc _sign_list_desc( WDP_AUTO, "list_signs", 358, 138, WC_SIGN_LIST, WC_NONE, 0, _nested_sign_list_widgets, lengthof(_nested_sign_list_widgets), &SignListWindow::hotkeys ); /** * Open the sign list window * * @return newly opened sign list window, or NULL if the window could not be opened. */ Window *ShowSignList() { return AllocateWindowDescFront(&_sign_list_desc, 0); } /** * Actually rename the sign. * @param index the sign to rename. * @param text the new name. * @return true if the window will already be removed after returning. */ static bool RenameSign(SignID index, const char *text) { bool remove = StrEmpty(text); DoCommandP(0, index, 0, CMD_RENAME_SIGN | (StrEmpty(text) ? CMD_MSG(STR_ERROR_CAN_T_DELETE_SIGN) : CMD_MSG(STR_ERROR_CAN_T_CHANGE_SIGN_NAME)), NULL, text); return remove; } struct SignWindow : Window, SignList { QueryString name_editbox; SignID cur_sign; SignWindow(WindowDesc *desc, const Sign *si) : Window(desc), name_editbox(MAX_LENGTH_SIGN_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_SIGN_NAME_CHARS) { this->querystrings[WID_QES_TEXT] = &this->name_editbox; this->name_editbox.caption = STR_EDIT_SIGN_CAPTION; this->name_editbox.cancel_button = WID_QES_CANCEL; this->name_editbox.ok_button = WID_QES_OK; this->InitNested(WN_QUERY_STRING_SIGN); UpdateSignEditWindow(si); this->SetFocusedWidget(WID_QES_TEXT); } void UpdateSignEditWindow(const Sign *si) { /* Display an empty string when the sign hasn't been edited yet */ if (si->name != NULL) { SetDParam(0, si->index); this->name_editbox.text.Assign(STR_SIGN_NAME); } else { this->name_editbox.text.DeleteAll(); } this->cur_sign = si->index; this->SetWidgetDirty(WID_QES_TEXT); this->SetFocusedWidget(WID_QES_TEXT); } /** * Returns a pointer to the (alphabetically) previous or next sign of the current sign. * @param next false if the previous sign is wanted, true if the next sign is wanted * @return pointer to the previous/next sign */ const Sign *PrevNextSign(bool next) { /* Rebuild the sign list */ this->signs.ForceRebuild(); this->signs.NeedResort(); this->BuildSignsList(); this->SortSignsList(); /* Search through the list for the current sign, excluding * - the first sign if we want the previous sign or * - the last sign if we want the next sign */ uint end = this->signs.Length() - (next ? 1 : 0); for (uint i = next ? 0 : 1; i < end; i++) { if (this->cur_sign == this->signs[i]->index) { /* We've found the current sign, so return the sign before/after it */ return this->signs[i + (next ? 1 : -1)]; } } /* If we haven't found the current sign by now, return the last/first sign */ return this->signs[next ? 0 : this->signs.Length() - 1]; } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_QES_CAPTION: SetDParam(0, this->name_editbox.caption); break; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_QES_PREVIOUS: case WID_QES_NEXT: { const Sign *si = this->PrevNextSign(widget == WID_QES_NEXT); /* Rebuild the sign list */ this->signs.ForceRebuild(); this->signs.NeedResort(); this->BuildSignsList(); this->SortSignsList(); /* Scroll to sign and reopen window */ ScrollMainWindowToTile(TileVirtXY(si->x, si->y)); UpdateSignEditWindow(si); break; } case WID_QES_DELETE: /* Only need to set the buffer to null, the rest is handled as the OK button */ RenameSign(this->cur_sign, ""); /* don't delete this, we are deleted in Sign::~Sign() -> DeleteRenameSignWindow() */ break; case WID_QES_OK: if (RenameSign(this->cur_sign, this->name_editbox.text.buf)) break; /* FALL THROUGH */ case WID_QES_CANCEL: delete this; break; } } }; static const NWidgetPart _nested_query_sign_edit_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_QES_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_QES_TEXT), SetMinimalSize(256, 12), SetDataTip(STR_EDIT_SIGN_SIGN_OSKTITLE, STR_NULL), SetPadding(2, 2, 2, 2), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_QES_OK), SetMinimalSize(61, 12), SetDataTip(STR_BUTTON_OK, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_QES_CANCEL), SetMinimalSize(60, 12), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_QES_DELETE), SetMinimalSize(60, 12), SetDataTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_QES_PREVIOUS), SetMinimalSize(11, 12), SetDataTip(AWV_DECREASE, STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_QES_NEXT), SetMinimalSize(11, 12), SetDataTip(AWV_INCREASE, STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP), EndContainer(), }; static WindowDesc _query_sign_edit_desc( WDP_CENTER, "query_sign", 0, 0, WC_QUERY_STRING, WC_NONE, WDF_CONSTRUCTION, _nested_query_sign_edit_widgets, lengthof(_nested_query_sign_edit_widgets) ); /** * Handle clicking on a sign. * @param si The sign that was clicked on. */ void HandleClickOnSign(const Sign *si) { if (_ctrl_pressed && (si->owner == _local_company || (si->owner == OWNER_DEITY && _game_mode == GM_EDITOR))) { RenameSign(si->index, NULL); return; } ShowRenameSignWindow(si); } /** * Show the window to change the text of a sign. * @param si The sign to show the window for. */ void ShowRenameSignWindow(const Sign *si) { /* Delete all other edit windows */ DeleteWindowByClass(WC_QUERY_STRING); new SignWindow(&_query_sign_edit_desc, si); } /** * Close the sign window associated with the given sign. * @param sign The sign to close the window for. */ void DeleteRenameSignWindow(SignID sign) { SignWindow *w = dynamic_cast(FindWindowById(WC_QUERY_STRING, WN_QUERY_STRING_SIGN)); if (w != NULL && w->cur_sign == sign) delete w; } openttd-1.5.3/src/company_func.h0000644000000000000000000000445212627373435015335 0ustar rootroot/* $Id: company_func.h 24996 2013-02-14 17:08:56Z rubidium $ */ /* * 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 company_func.h Functions related to companies. */ #ifndef COMPANY_FUNC_H #define COMPANY_FUNC_H #include "command_type.h" #include "company_type.h" #include "gfx_type.h" #include "vehicle_type.h" bool MayCompanyTakeOver(CompanyID cbig, CompanyID small); void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner); void GetNameOfOwner(Owner owner, TileIndex tile); void SetLocalCompany(CompanyID new_company); void ShowBuyCompanyDialog(CompanyID company); void CompanyAdminUpdate(const Company *company); void CompanyAdminBankrupt(CompanyID company_id); void UpdateLandscapingLimits(); bool CheckCompanyHasMoney(CommandCost &cost); void SubtractMoneyFromCompany(CommandCost cost); void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cost); CommandCost CheckOwnership(Owner owner, TileIndex tile = 0); CommandCost CheckTileOwnership(TileIndex tile); extern CompanyByte _local_company; extern CompanyByte _current_company; extern Colours _company_colours[MAX_COMPANIES]; extern CompanyManagerFace _company_manager_face; /** * Is the current company the local company? * @return \c true of the current company is the local company, \c false otherwise. */ static inline bool IsLocalCompany() { return _local_company == _current_company; } /** * Is the user representing \a company? * @param company Company where interaction is needed with. * @return Gives \c true if the user can answer questions interactively as representative of \a company, else \c false */ static inline bool IsInteractiveCompany(CompanyID company) { return company == _local_company; } int CompanyServiceInterval(const Company *c, VehicleType type); #endif /* COMPANY_FUNC_H */ openttd-1.5.3/src/gfx.cpp0000644000000000000000000015545212627373442014000 0ustar rootroot/* $Id: gfx.cpp 27351 2015-07-30 18:53:31Z frosch $ */ /* * 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 gfx.cpp Handling of drawing text and other gfx related stuff. */ #include "stdafx.h" #include "gfx_layout.h" #include "progress.h" #include "zoom_func.h" #include "blitter/factory.hpp" #include "video/video_driver.hpp" #include "strings_func.h" #include "settings_type.h" #include "network/network.h" #include "network/network_func.h" #include "window_func.h" #include "newgrf_debug.h" #include "table/palettes.h" #include "table/sprites.h" #include "table/control_codes.h" #include "safeguards.h" byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down bool _fullscreen; byte _support8bpp; CursorVars _cursor; bool _ctrl_pressed; ///< Is Ctrl pressed? bool _shift_pressed; ///< Is Shift pressed? byte _fast_forward; bool _left_button_down; ///< Is left mouse button pressed? bool _left_button_clicked; ///< Is left mouse button clicked? bool _right_button_down; ///< Is right mouse button pressed? bool _right_button_clicked; ///< Is right mouse button clicked? DrawPixelInfo _screen; bool _screen_disable_anim = false; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) bool _exit_game; GameMode _game_mode; SwitchMode _switch_mode; ///< The next mainloop command. PauseModeByte _pause_mode; Palette _cur_palette; static byte _stringwidth_table[FS_END][224]; ///< Cache containing width of often used characters. @see GetCharacterWidth() DrawPixelInfo *_cur_dpi; byte _colour_gradient[COLOUR_END][8]; static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE); static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub = NULL, SpriteID sprite_id = SPR_CURSOR_MOUSE, ZoomLevel zoom = ZOOM_LVL_NORMAL); static ReusableBuffer _cursor_backup; ZoomLevelByte _gui_zoom; ///< GUI Zoom level /** * The rect for repaint. * * This rectangle defines the area which should be repaint by the video driver. * * @ingroup dirty */ static Rect _invalid_rect; static const byte *_colour_remap_ptr; static byte _string_colourremap[3]; ///< Recoloursprite for stringdrawing. The grf loader ensures that #ST_FONT sprites only use colours 0 to 2. static const uint DIRTY_BLOCK_HEIGHT = 8; static const uint DIRTY_BLOCK_WIDTH = 64; static uint _dirty_bytes_per_line = 0; static byte *_dirty_blocks = NULL; extern uint _dirty_block_colour; void GfxScroll(int left, int top, int width, int height, int xo, int yo) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); if (xo == 0 && yo == 0) return; if (_cursor.visible) UndrawMouseCursor(); #ifdef ENABLE_NETWORK if (_networking) NetworkUndrawChatMessage(); #endif /* ENABLE_NETWORK */ blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo); /* This part of the screen is now dirty. */ VideoDriver::GetInstance()->MakeDirty(left, top, width, height); } /** * Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen. * * @pre dpi->zoom == ZOOM_LVL_NORMAL, right >= left, bottom >= top * @param left Minimum X (inclusive) * @param top Minimum Y (inclusive) * @param right Maximum X (inclusive) * @param bottom Maximum Y (inclusive) * @param colour A 8 bit palette index (FILLRECT_OPAQUE and FILLRECT_CHECKER) or a recolour spritenumber (FILLRECT_RECOLOUR) * @param mode * FILLRECT_OPAQUE: Fill the rectangle with the specified colour * FILLRECT_CHECKER: Like FILLRECT_OPAQUE, but only draw every second pixel (used to grey out things) * FILLRECT_RECOLOUR: Apply a recolour sprite to every pixel in the rectangle currently on screen */ void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); const DrawPixelInfo *dpi = _cur_dpi; void *dst; const int otop = top; const int oleft = left; if (dpi->zoom != ZOOM_LVL_NORMAL) return; if (left > right || top > bottom) return; if (right < dpi->left || left >= dpi->left + dpi->width) return; if (bottom < dpi->top || top >= dpi->top + dpi->height) return; if ( (left -= dpi->left) < 0) left = 0; right = right - dpi->left + 1; if (right > dpi->width) right = dpi->width; right -= left; assert(right > 0); if ( (top -= dpi->top) < 0) top = 0; bottom = bottom - dpi->top + 1; if (bottom > dpi->height) bottom = dpi->height; bottom -= top; assert(bottom > 0); dst = blitter->MoveTo(dpi->dst_ptr, left, top); switch (mode) { default: // FILLRECT_OPAQUE blitter->DrawRect(dst, right, bottom, (uint8)colour); break; case FILLRECT_RECOLOUR: blitter->DrawColourMappingRect(dst, right, bottom, GB(colour, 0, PALETTE_WIDTH)); break; case FILLRECT_CHECKER: { byte bo = (oleft - left + dpi->left + otop - top + dpi->top) & 1; do { for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour); dst = blitter->MoveTo(dst, 0, 1); } while (--bottom > 0); break; } } } /** * Check line clipping by using a linear equation and draw the visible part of * the line given by x/y and x2/y2. * @param video Destination pointer to draw into. * @param x X coordinate of first point. * @param y Y coordinate of first point. * @param x2 X coordinate of second point. * @param y2 Y coordinate of second point. * @param screen_width With of the screen to check clipping against. * @param screen_height Height of the screen to check clipping against. * @param colour Colour of the line. * @param width Width of the line. * @param dash Length of dashes for dashed lines. 0 means solid line. */ static inline void GfxDoDrawLine(void *video, int x, int y, int x2, int y2, int screen_width, int screen_height, uint8 colour, int width, int dash = 0) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); assert(width > 0); if (y2 == y || x2 == x) { /* Special case: horizontal/vertical line. All checks already done in GfxPreprocessLine. */ blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash); return; } int grade_y = y2 - y; int grade_x = x2 - x; /* Clipping rectangle. Slightly extended so we can ignore the width of the line. */ uint extra = CeilDiv(3 * width, 4); // not less then "width * sqrt(2) / 2" Rect clip = { -extra, -extra, screen_width - 1 + extra, screen_height - 1 + extra }; /* prevent integer overflows. */ int margin = 1; while (INT_MAX / abs(grade_y) < max(abs(clip.left - x), abs(clip.right - x))) { grade_y /= 2; grade_x /= 2; margin *= 2; // account for rounding errors } /* Imagine that the line is infinitely long and it intersects with * infinitely long left and right edges of the clipping rectangle. * If both intersection points are outside the clipping rectangle * and both on the same side of it, we don't need to draw anything. */ int left_isec_y = y + (clip.left - x) * grade_y / grade_x; int right_isec_y = y + (clip.right - x) * grade_y / grade_x; if ((left_isec_y > clip.bottom + margin && right_isec_y > clip.bottom + margin) || (left_isec_y < clip.top - margin && right_isec_y < clip.top - margin)) { return; } /* It is possible to use the line equation to further reduce the amount of * work the blitter has to do by shortening the effective line segment. * However, in order to get that right and prevent the flickering effects * of rounding errors so much additional code has to be run here that in * the general case the effect is not noticable. */ blitter->DrawLine(video, x, y, x2, y2, screen_width, screen_height, colour, width, dash); } /** * Align parameters of a line to the given DPI and check simple clipping. * @param dpi Screen parameters to align with. * @param x X coordinate of first point. * @param y Y coordinate of first point. * @param x2 X coordinate of second point. * @param y2 Y coordinate of second point. * @param width Width of the line. * @return True if the line is likely to be visible, false if it's certainly * invisible. */ static inline bool GfxPreprocessLine(DrawPixelInfo *dpi, int &x, int &y, int &x2, int &y2, int width) { x -= dpi->left; x2 -= dpi->left; y -= dpi->top; y2 -= dpi->top; /* Check simple clipping */ if (x + width / 2 < 0 && x2 + width / 2 < 0 ) return false; if (y + width / 2 < 0 && y2 + width / 2 < 0 ) return false; if (x - width / 2 > dpi->width && x2 - width / 2 > dpi->width ) return false; if (y - width / 2 > dpi->height && y2 - width / 2 > dpi->height) return false; return true; } void GfxDrawLine(int x, int y, int x2, int y2, int colour, int width, int dash) { DrawPixelInfo *dpi = _cur_dpi; if (GfxPreprocessLine(dpi, x, y, x2, y2, width)) { GfxDoDrawLine(dpi->dst_ptr, x, y, x2, y2, dpi->width, dpi->height, colour, width, dash); } } void GfxDrawLineUnscaled(int x, int y, int x2, int y2, int colour) { DrawPixelInfo *dpi = _cur_dpi; if (GfxPreprocessLine(dpi, x, y, x2, y2, 1)) { GfxDoDrawLine(dpi->dst_ptr, UnScaleByZoom(x, dpi->zoom), UnScaleByZoom(y, dpi->zoom), UnScaleByZoom(x2, dpi->zoom), UnScaleByZoom(y2, dpi->zoom), UnScaleByZoom(dpi->width, dpi->zoom), UnScaleByZoom(dpi->height, dpi->zoom), colour, 1); } } /** * Draws the projection of a parallelepiped. * This can be used to draw boxes in world coordinates. * * @param x Screen X-coordinate of top front corner. * @param y Screen Y-coordinate of top front corner. * @param dx1 Screen X-length of first edge. * @param dy1 Screen Y-length of first edge. * @param dx2 Screen X-length of second edge. * @param dy2 Screen Y-length of second edge. * @param dx3 Screen X-length of third edge. * @param dy3 Screen Y-length of third edge. */ void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3) { /* .... * .. .... * .. .... * .. ^ * <--__(dx1,dy1) /(dx2,dy2) * : --__ / : * : --__ / : * : *(x,y) : * : | : * : | .. * .... |(dx3,dy3) * .... | .. * ....V. */ static const byte colour = PC_WHITE; GfxDrawLineUnscaled(x, y, x + dx1, y + dy1, colour); GfxDrawLineUnscaled(x, y, x + dx2, y + dy2, colour); GfxDrawLineUnscaled(x, y, x + dx3, y + dy3, colour); GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx2, y + dy1 + dy2, colour); GfxDrawLineUnscaled(x + dx1, y + dy1, x + dx1 + dx3, y + dy1 + dy3, colour); GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx1, y + dy2 + dy1, colour); GfxDrawLineUnscaled(x + dx2, y + dy2, x + dx2 + dx3, y + dy2 + dy3, colour); GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx1, y + dy3 + dy1, colour); GfxDrawLineUnscaled(x + dx3, y + dy3, x + dx3 + dx2, y + dy3 + dy2, colour); } /** * Set the colour remap to be for the given colour. * @param colour the new colour of the remap. */ static void SetColourRemap(TextColour colour) { if (colour == TC_INVALID) return; /* Black strings have no shading ever; the shading is black, so it * would be invisible at best, but it actually makes it illegible. */ bool no_shade = (colour & TC_NO_SHADE) != 0 || colour == TC_BLACK; bool raw_colour = (colour & TC_IS_PALETTE_COLOUR) != 0; colour &= ~(TC_NO_SHADE | TC_IS_PALETTE_COLOUR); _string_colourremap[1] = raw_colour ? (byte)colour : _string_colourmap[colour]; _string_colourremap[2] = no_shade ? 0 : 1; _colour_remap_ptr = _string_colourremap; } /** * Drawing routine for drawing a laid out line of text. * @param line String to draw. * @param y The top most position to draw on. * @param left The left most position to draw on. * @param right The right most position to draw on. * @param align The alignment of the string when drawing left-to-right. In the * case a right-to-left language is chosen this is inverted so it * will be drawn in the right direction. * @param underline Whether to underline what has been drawn or not. * @param truncation Whether to perform string truncation or not. * * @return In case of left or center alignment the right most pixel we have drawn to. * In case of right alignment the left most pixel we have drawn to. */ static int DrawLayoutLine(const ParagraphLayouter::Line *line, int y, int left, int right, StringAlignment align, bool underline, bool truncation) { if (line->CountRuns() == 0) return 0; int w = line->GetWidth(); int h = line->GetLeading(); /* * The following is needed for truncation. * Depending on the text direction, we either remove bits at the rear * or the front. For this we shift the entire area to draw so it fits * within the left/right bounds and the side we do not truncate it on. * Then we determine the truncation location, i.e. glyphs that fall * outside of the range min_x - max_x will not be drawn; they are thus * the truncated glyphs. * * At a later step we insert the dots. */ int max_w = right - left + 1; // The maximum width. int offset_x = 0; // The offset we need for positioning the glyphs int min_x = left; // The minimum x position to draw normal glyphs on. int max_x = right; // The maximum x position to draw normal glyphs on. truncation &= max_w < w; // Whether we need to do truncation. int dot_width = 0; // Cache for the width of the dot. const Sprite *dot_sprite = NULL; // Cache for the sprite of the dot. if (truncation) { /* * Assumption may be made that all fonts of a run are of the same size. * In any case, we'll use these dots for the abbreviation, so even if * another size would be chosen it won't have truncated too little for * the truncation dots. */ FontCache *fc = ((const Font*)line->GetVisualRun(0)->GetFont())->fc; GlyphID dot_glyph = fc->MapCharToGlyph('.'); dot_width = fc->GetGlyphWidth(dot_glyph); dot_sprite = fc->GetGlyph(dot_glyph); if (_current_text_dir == TD_RTL) { min_x += 3 * dot_width; offset_x = w - 3 * dot_width - max_w; } else { max_x -= 3 * dot_width; } w = max_w; } /* In case we have a RTL language we swap the alignment. */ if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT; /* right is the right most position to draw on. In this case we want to do * calculations with the width of the string. In comparison right can be * seen as lastof(todraw) and width as lengthof(todraw). They differ by 1. * So most +1/-1 additions are to move from lengthof to 'indices'. */ switch (align & SA_HOR_MASK) { case SA_LEFT: /* right + 1 = left + w */ right = left + w - 1; break; case SA_HOR_CENTER: left = RoundDivSU(right + 1 + left - w, 2); /* right + 1 = left + w */ right = left + w - 1; break; case SA_RIGHT: left = right + 1 - w; break; default: NOT_REACHED(); } TextColour colour = TC_BLACK; bool draw_shadow = false; for (int run_index = 0; run_index < line->CountRuns(); run_index++) { const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); const Font *f = (const Font*)run->GetFont(); FontCache *fc = f->fc; colour = f->colour; SetColourRemap(colour); DrawPixelInfo *dpi = _cur_dpi; int dpi_left = dpi->left; int dpi_right = dpi->left + dpi->width - 1; draw_shadow = fc->GetDrawGlyphShadow() && (colour & TC_NO_SHADE) == 0 && colour != TC_BLACK; for (int i = 0; i < run->GetGlyphCount(); i++) { GlyphID glyph = run->GetGlyphs()[i]; /* Not a valid glyph (empty) */ if (glyph == 0xFFFF) continue; int begin_x = (int)run->GetPositions()[i * 2] + left - offset_x; int end_x = (int)run->GetPositions()[i * 2 + 2] + left - offset_x - 1; int top = (int)run->GetPositions()[i * 2 + 1] + y; /* Truncated away. */ if (truncation && (begin_x < min_x || end_x > max_x)) continue; const Sprite *sprite = fc->GetGlyph(glyph); /* Check clipping (the "+ 1" is for the shadow). */ if (begin_x + sprite->x_offs > dpi_right || begin_x + sprite->x_offs + sprite->width /* - 1 + 1 */ < dpi_left) continue; if (draw_shadow && (glyph & SPRITE_GLYPH) == 0) { SetColourRemap(TC_BLACK); GfxMainBlitter(sprite, begin_x + 1, top + 1, BM_COLOUR_REMAP); SetColourRemap(colour); } GfxMainBlitter(sprite, begin_x, top, BM_COLOUR_REMAP); } } if (truncation) { int x = (_current_text_dir == TD_RTL) ? left : (right - 3 * dot_width); for (int i = 0; i < 3; i++, x += dot_width) { if (draw_shadow) { SetColourRemap(TC_BLACK); GfxMainBlitter(dot_sprite, x + 1, y + 1, BM_COLOUR_REMAP); SetColourRemap(colour); } GfxMainBlitter(dot_sprite, x, y, BM_COLOUR_REMAP); } } if (underline) { GfxFillRect(left, y + h, right, y + h, _string_colourremap[1]); } return (align & SA_HOR_MASK) == SA_RIGHT ? left : right; } /** * Draw string, possibly truncated to make it fit in its allocated space * * @param left The left most position to draw on. * @param right The right most position to draw on. * @param top The top most position to draw on. * @param str String to draw. * @param colour Colour used for drawing the string, see DoDrawString() for details * @param align The alignment of the string when drawing left-to-right. In the * case a right-to-left language is chosen this is inverted so it * will be drawn in the right direction. * @param underline Whether to underline what has been drawn or not. * @param fontsize The size of the initial characters. * @return In case of left or center alignment the right most pixel we have drawn to. * In case of right alignment the left most pixel we have drawn to. */ int DrawString(int left, int right, int top, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) { /* The string may contain control chars to change the font, just use the biggest font for clipping. */ int max_height = max(max(FONT_HEIGHT_SMALL, FONT_HEIGHT_NORMAL), max(FONT_HEIGHT_LARGE, FONT_HEIGHT_MONO)); /* Funny glyphs may extent outside the usual bounds, so relax the clipping somewhat. */ int extra = max_height / 2; if (_cur_dpi->top + _cur_dpi->height + extra < top || _cur_dpi->top > top + max_height + extra || _cur_dpi->left + _cur_dpi->width + extra < left || _cur_dpi->left > right + extra) { return 0; } Layouter layout(str, INT32_MAX, colour, fontsize); if (layout.Length() == 0) return 0; return DrawLayoutLine(*layout.Begin(), top, left, right, align, underline, true); } /** * Draw string, possibly truncated to make it fit in its allocated space * * @param left The left most position to draw on. * @param right The right most position to draw on. * @param top The top most position to draw on. * @param str String to draw. * @param colour Colour used for drawing the string, see DoDrawString() for details * @param align The alignment of the string when drawing left-to-right. In the * case a right-to-left language is chosen this is inverted so it * will be drawn in the right direction. * @param underline Whether to underline what has been drawn or not. * @param fontsize The size of the initial characters. * @return In case of left or center alignment the right most pixel we have drawn to. * In case of right alignment the left most pixel we have drawn to. */ int DrawString(int left, int right, int top, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) { char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); return DrawString(left, right, top, buffer, colour, align, underline, fontsize); } /** * Calculates height of string (in pixels). The string is changed to a multiline string if needed. * @param str string to check * @param maxw maximum string width * @return height of pixels of string when it is drawn */ int GetStringHeight(const char *str, int maxw, FontSize fontsize) { Layouter layout(str, maxw, TC_FROMSTRING, fontsize); return layout.GetBounds().height; } /** * Calculates height of string (in pixels). The string is changed to a multiline string if needed. * @param str string to check * @param maxw maximum string width * @return height of pixels of string when it is drawn */ int GetStringHeight(StringID str, int maxw) { char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); return GetStringHeight(buffer, maxw); } /** * Calculates number of lines of string. The string is changed to a multiline string if needed. * @param str string to check * @param maxw maximum string width * @return number of lines of string when it is drawn */ int GetStringLineCount(StringID str, int maxw) { char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); Layouter layout(buffer, maxw); return layout.Length(); } /** * Calculate string bounding box for multi-line strings. * @param str String to check. * @param suggestion Suggested bounding box. * @return Bounding box for the multi-line string, may be bigger than \a suggestion. */ Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion) { Dimension box = {suggestion.width, GetStringHeight(str, suggestion.width)}; return box; } /** * Calculate string bounding box for multi-line strings. * @param str String to check. * @param suggestion Suggested bounding box. * @return Bounding box for the multi-line string, may be bigger than \a suggestion. */ Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion) { Dimension box = {suggestion.width, GetStringHeight(str, suggestion.width)}; return box; } /** * Draw string, possibly over multiple lines. * * @param left The left most position to draw on. * @param right The right most position to draw on. * @param top The top most position to draw on. * @param bottom The bottom most position to draw on. * @param str String to draw. * @param colour Colour used for drawing the string, see DoDrawString() for details * @param align The horizontal and vertical alignment of the string. * @param underline Whether to underline all strings * @param fontsize The size of the initial characters. * * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. */ int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) { int maxw = right - left + 1; int maxh = bottom - top + 1; /* It makes no sense to even try if it can't be drawn anyway, or * do we really want to support fonts of 0 or less pixels high? */ if (maxh <= 0) return top; Layouter layout(str, maxw, colour, fontsize); int total_height = layout.GetBounds().height; int y; switch (align & SA_VERT_MASK) { case SA_TOP: y = top; break; case SA_VERT_CENTER: y = RoundDivSU(bottom + top - total_height, 2); break; case SA_BOTTOM: y = bottom - total_height; break; default: NOT_REACHED(); } int last_line = top; int first_line = bottom; for (const ParagraphLayouter::Line **iter = layout.Begin(); iter != layout.End(); iter++) { const ParagraphLayouter::Line *line = *iter; int line_height = line->GetLeading(); if (y >= top && y < bottom) { last_line = y + line_height; if (first_line > y) first_line = y; DrawLayoutLine(line, y, left, right, align, underline, false); } y += line_height; } return ((align & SA_VERT_MASK) == SA_BOTTOM) ? first_line : last_line; } /** * Draw string, possibly over multiple lines. * * @param left The left most position to draw on. * @param right The right most position to draw on. * @param top The top most position to draw on. * @param bottom The bottom most position to draw on. * @param str String to draw. * @param colour Colour used for drawing the string, see DoDrawString() for details * @param align The horizontal and vertical alignment of the string. * @param underline Whether to underline all strings * @param fontsize The size of the initial characters. * * @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written. */ int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize) { char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); return DrawStringMultiLine(left, right, top, bottom, buffer, colour, align, underline, fontsize); } /** * Return the string dimension in pixels. The height and width are returned * in a single Dimension value. TINYFONT, BIGFONT modifiers are only * supported as the first character of the string. The returned dimensions * are therefore a rough estimation correct for all the current strings * but not every possible combination * @param str string to calculate pixel-width * @param start_fontsize Fontsize to start the text with * @return string width and height in pixels */ Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize) { Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); return layout.GetBounds(); } /** * Get bounding box of a string. Uses parameters set by #DParam if needed. * Has the same restrictions as #GetStringBoundingBox(const char *str). * @param strid String to examine. * @return Width and height of the bounding box for the string in pixels. */ Dimension GetStringBoundingBox(StringID strid) { char buffer[DRAW_STRING_BUFFER]; GetString(buffer, strid, lastof(buffer)); return GetStringBoundingBox(buffer); } /** * Get the leading corner of a character in a single-line string relative * to the start of the string. * @param str String containing the character. * @param ch Pointer to the character in the string. * @param start_fontsize Font size to start the text with. * @return Upper left corner of the glyph associated with the character. */ Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize) { Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); return layout.GetCharPosition(ch); } /** * Get the character from a string that is drawn at a specific position. * @param str String to test. * @param x Position relative to the start of the string. * @param start_fontsize Font size to start the text with. * @return Pointer to the character at the position or NULL if there is no character at the position. */ const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize) { if (x < 0) return NULL; Layouter layout(str, INT32_MAX, TC_FROMSTRING, start_fontsize); return layout.GetCharAtPosition(x); } /** * Draw single character horizontally centered around (x,y) * @param c Character (glyph) to draw * @param x X position to draw character * @param y Y position to draw character * @param colour Colour to use, see DoDrawString() for details */ void DrawCharCentered(WChar c, int x, int y, TextColour colour) { SetColourRemap(colour); GfxMainBlitter(GetGlyph(FS_NORMAL, c), x - GetCharacterWidth(FS_NORMAL, c) / 2, y, BM_COLOUR_REMAP); } /** * Get the size of a sprite. * @param sprid Sprite to examine. * @param [out] offset Optionally returns the sprite position offset. * @return Sprite size in pixels. * @note The size assumes (0, 0) as top-left coordinate and ignores any part of the sprite drawn at the left or above that position. */ Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom) { const Sprite *sprite = GetSprite(sprid, ST_NORMAL); if (offset != NULL) { offset->x = UnScaleByZoom(sprite->x_offs, zoom); offset->y = UnScaleByZoom(sprite->y_offs, zoom); } Dimension d; d.width = max(0, UnScaleByZoom(sprite->x_offs + sprite->width, zoom)); d.height = max(0, UnScaleByZoom(sprite->y_offs + sprite->height, zoom)); return d; } /** * Helper function to get the blitter mode for different types of palettes. * @param pal The palette to get the blitter mode for. * @return The blitter mode associated with the palette. */ static BlitterMode GetBlitterMode(PaletteID pal) { switch (pal) { case PAL_NONE: return BM_NORMAL; case PALETTE_CRASH: return BM_CRASH_REMAP; case PALETTE_ALL_BLACK: return BM_BLACK_REMAP; default: return BM_COLOUR_REMAP; } } /** * Draw a sprite in a viewport. * @param img Image number to draw * @param pal Palette to use. * @param x Left coordinate of image in viewport, scaled by zoom * @param y Top coordinate of image in viewport, scaled by zoom * @param sub If available, draw only specified part of the sprite */ void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub) { SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite); } else if (pal != PAL_NONE) { if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) { SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH)); } else { _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; } GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, GetBlitterMode(pal), sub, real_sprite); } else { GfxMainBlitterViewport(GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite); } } /** * Draw a sprite, not in a viewport * @param img Image number to draw * @param pal Palette to use. * @param x Left coordinate of image in pixels * @param y Top coordinate of image in pixels * @param sub If available, draw only specified part of the sprite * @param zoom Zoom level of sprite */ void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom) { SpriteID real_sprite = GB(img, 0, SPRITE_WIDTH); if (HasBit(img, PALETTE_MODIFIER_TRANSPARENT)) { _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_TRANSPARENT, sub, real_sprite, zoom); } else if (pal != PAL_NONE) { if (HasBit(pal, PALETTE_TEXT_RECOLOUR)) { SetColourRemap((TextColour)GB(pal, 0, PALETTE_WIDTH)); } else { _colour_remap_ptr = GetNonSprite(GB(pal, 0, PALETTE_WIDTH), ST_RECOLOUR) + 1; } GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, GetBlitterMode(pal), sub, real_sprite, zoom); } else { GfxMainBlitter(GetSprite(real_sprite, ST_NORMAL), x, y, BM_NORMAL, sub, real_sprite, zoom); } } /** * The code for setting up the blitter mode and sprite information before finally drawing the sprite. * @param sprite The sprite to draw. * @param x The X location to draw. * @param y The Y location to draw. * @param mode The settings for the blitter to pass. * @param sub Whether to only draw a sub set of the sprite. * @param zoom The zoom level at which to draw the sprites. * @tparam ZOOM_BASE The factor required to get the sub sprite information into the right size. * @tparam SCALED_XY Whether the X and Y are scaled or unscaled. */ template static void GfxBlitter(const Sprite * const sprite, int x, int y, BlitterMode mode, const SubSprite * const sub, SpriteID sprite_id, ZoomLevel zoom) { const DrawPixelInfo *dpi = _cur_dpi; Blitter::BlitterParams bp; if (SCALED_XY) { /* Scale it */ x = ScaleByZoom(x, zoom); y = ScaleByZoom(y, zoom); } /* Move to the correct offset */ x += sprite->x_offs; y += sprite->y_offs; if (sub == NULL) { /* No clipping. */ bp.skip_left = 0; bp.skip_top = 0; bp.width = UnScaleByZoom(sprite->width, zoom); bp.height = UnScaleByZoom(sprite->height, zoom); } else { /* Amount of pixels to clip from the source sprite */ int clip_left = max(0, -sprite->x_offs + sub->left * ZOOM_BASE ); int clip_top = max(0, -sprite->y_offs + sub->top * ZOOM_BASE ); int clip_right = max(0, sprite->width - (-sprite->x_offs + (sub->right + 1) * ZOOM_BASE)); int clip_bottom = max(0, sprite->height - (-sprite->y_offs + (sub->bottom + 1) * ZOOM_BASE)); if (clip_left + clip_right >= sprite->width) return; if (clip_top + clip_bottom >= sprite->height) return; bp.skip_left = UnScaleByZoomLower(clip_left, zoom); bp.skip_top = UnScaleByZoomLower(clip_top, zoom); bp.width = UnScaleByZoom(sprite->width - clip_left - clip_right, zoom); bp.height = UnScaleByZoom(sprite->height - clip_top - clip_bottom, zoom); x += ScaleByZoom(bp.skip_left, zoom); y += ScaleByZoom(bp.skip_top, zoom); } /* Copy the main data directly from the sprite */ bp.sprite = sprite->data; bp.sprite_width = sprite->width; bp.sprite_height = sprite->height; bp.top = 0; bp.left = 0; bp.dst = dpi->dst_ptr; bp.pitch = dpi->pitch; bp.remap = _colour_remap_ptr; assert(sprite->width > 0); assert(sprite->height > 0); if (bp.width <= 0) return; if (bp.height <= 0) return; y -= SCALED_XY ? ScaleByZoom(dpi->top, zoom) : dpi->top; int y_unscaled = UnScaleByZoom(y, zoom); /* Check for top overflow */ if (y < 0) { bp.height -= -y_unscaled; if (bp.height <= 0) return; bp.skip_top += -y_unscaled; y = 0; } else { bp.top = y_unscaled; } /* Check for bottom overflow */ y += SCALED_XY ? ScaleByZoom(bp.height - dpi->height, zoom) : ScaleByZoom(bp.height, zoom) - dpi->height; if (y > 0) { bp.height -= UnScaleByZoom(y, zoom); if (bp.height <= 0) return; } x -= SCALED_XY ? ScaleByZoom(dpi->left, zoom) : dpi->left; int x_unscaled = UnScaleByZoom(x, zoom); /* Check for left overflow */ if (x < 0) { bp.width -= -x_unscaled; if (bp.width <= 0) return; bp.skip_left += -x_unscaled; x = 0; } else { bp.left = x_unscaled; } /* Check for right overflow */ x += SCALED_XY ? ScaleByZoom(bp.width - dpi->width, zoom) : ScaleByZoom(bp.width, zoom) - dpi->width; if (x > 0) { bp.width -= UnScaleByZoom(x, zoom); if (bp.width <= 0) return; } assert(bp.skip_left + bp.width <= UnScaleByZoom(sprite->width, zoom)); assert(bp.skip_top + bp.height <= UnScaleByZoom(sprite->height, zoom)); /* We do not want to catch the mouse. However we also use that spritenumber for unknown (text) sprites. */ if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && sprite_id != SPR_CURSOR_MOUSE) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); void *topleft = blitter->MoveTo(bp.dst, bp.left, bp.top); void *bottomright = blitter->MoveTo(topleft, bp.width - 1, bp.height - 1); void *clicked = _newgrf_debug_sprite_picker.clicked_pixel; if (topleft <= clicked && clicked <= bottomright) { uint offset = (((size_t)clicked - (size_t)topleft) / (blitter->GetScreenDepth() / 8)) % bp.pitch; if (offset < (uint)bp.width) { _newgrf_debug_sprite_picker.sprites.Include(sprite_id); } } } BlitterFactory::GetCurrentBlitter()->Draw(&bp, mode, zoom); } static void GfxMainBlitterViewport(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub, SpriteID sprite_id) { GfxBlitter(sprite, x, y, mode, sub, sprite_id, _cur_dpi->zoom); } static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode, const SubSprite *sub, SpriteID sprite_id, ZoomLevel zoom) { GfxBlitter<1, true>(sprite, x, y, mode, sub, sprite_id, zoom); } void DoPaletteAnimations(); void GfxInitPalettes() { memcpy(&_cur_palette, &_palette, sizeof(_cur_palette)); DoPaletteAnimations(); } #define EXTR(p, q) (((uint16)(palette_animation_counter * (p)) * (q)) >> 16) #define EXTR2(p, q) (((uint16)(~palette_animation_counter * (p)) * (q)) >> 16) void DoPaletteAnimations() { /* Animation counter for the palette animation. */ static int palette_animation_counter = 0; palette_animation_counter += 8; Blitter *blitter = BlitterFactory::GetCurrentBlitter(); const Colour *s; const ExtraPaletteValues *ev = &_extra_palette_values; Colour old_val[PALETTE_ANIM_SIZE]; const uint old_tc = palette_animation_counter; uint i; uint j; if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { palette_animation_counter = 0; } Colour *palette_pos = &_cur_palette.palette[PALETTE_ANIM_START]; // Points to where animations are taking place on the palette /* Makes a copy of the current animation palette in old_val, * so the work on the current palette could be compared, see if there has been any changes */ memcpy(old_val, palette_pos, sizeof(old_val)); /* Fizzy Drink bubbles animation */ s = ev->fizzy_drink; j = EXTR2(512, EPV_CYCLES_FIZZY_DRINK); for (i = 0; i != EPV_CYCLES_FIZZY_DRINK; i++) { *palette_pos++ = s[j]; j++; if (j == EPV_CYCLES_FIZZY_DRINK) j = 0; } /* Oil refinery fire animation */ s = ev->oil_refinery; j = EXTR2(512, EPV_CYCLES_OIL_REFINERY); for (i = 0; i != EPV_CYCLES_OIL_REFINERY; i++) { *palette_pos++ = s[j]; j++; if (j == EPV_CYCLES_OIL_REFINERY) j = 0; } /* Radio tower blinking */ { byte i = (palette_animation_counter >> 1) & 0x7F; byte v; if (i < 0x3f) { v = 255; } else if (i < 0x4A || i >= 0x75) { v = 128; } else { v = 20; } palette_pos->r = v; palette_pos->g = 0; palette_pos->b = 0; palette_pos++; i ^= 0x40; if (i < 0x3f) { v = 255; } else if (i < 0x4A || i >= 0x75) { v = 128; } else { v = 20; } palette_pos->r = v; palette_pos->g = 0; palette_pos->b = 0; palette_pos++; } /* Handle lighthouse and stadium animation */ s = ev->lighthouse; j = EXTR(256, EPV_CYCLES_LIGHTHOUSE); for (i = 0; i != EPV_CYCLES_LIGHTHOUSE; i++) { *palette_pos++ = s[j]; j++; if (j == EPV_CYCLES_LIGHTHOUSE) j = 0; } /* Dark blue water */ s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->dark_water_toyland : ev->dark_water; j = EXTR(320, EPV_CYCLES_DARK_WATER); for (i = 0; i != EPV_CYCLES_DARK_WATER; i++) { *palette_pos++ = s[j]; j++; if (j == EPV_CYCLES_DARK_WATER) j = 0; } /* Glittery water */ s = (_settings_game.game_creation.landscape == LT_TOYLAND) ? ev->glitter_water_toyland : ev->glitter_water; j = EXTR(128, EPV_CYCLES_GLITTER_WATER); for (i = 0; i != EPV_CYCLES_GLITTER_WATER / 3; i++) { *palette_pos++ = s[j]; j += 3; if (j >= EPV_CYCLES_GLITTER_WATER) j -= EPV_CYCLES_GLITTER_WATER; } if (blitter != NULL && blitter->UsePaletteAnimation() == Blitter::PALETTE_ANIMATION_NONE) { palette_animation_counter = old_tc; } else { if (memcmp(old_val, &_cur_palette.palette[PALETTE_ANIM_START], sizeof(old_val)) != 0 && _cur_palette.count_dirty == 0) { /* Did we changed anything on the palette? Seems so. Mark it as dirty */ _cur_palette.first_dirty = PALETTE_ANIM_START; _cur_palette.count_dirty = PALETTE_ANIM_SIZE; } } } /** * Determine a contrasty text colour for a coloured background. * @param background Background colour. * @return TC_BLACK or TC_WHITE depending on what gives a better contrast. */ TextColour GetContrastColour(uint8 background) { Colour c = _cur_palette.palette[background]; /* Compute brightness according to http://www.w3.org/TR/AERT#color-contrast. * The following formula computes 1000 * brightness^2, with brightness being in range 0 to 255. */ uint sq1000_brightness = c.r * c.r * 299 + c.g * c.g * 587 + c.b * c.b * 114; /* Compare with threshold brightness 128 (50%) */ return sq1000_brightness < 128 * 128 * 1000 ? TC_WHITE : TC_BLACK; } /** * Initialize _stringwidth_table cache * @param monospace Whether to load the monospace cache or the normal fonts. */ void LoadStringWidthTable(bool monospace) { for (FontSize fs = monospace ? FS_MONO : FS_BEGIN; fs < (monospace ? FS_END : FS_MONO); fs++) { for (uint i = 0; i != 224; i++) { _stringwidth_table[fs][i] = GetGlyphWidth(fs, i + 32); } } ClearFontCache(); ReInitAllWindows(); } /** * Return width of character glyph. * @param size Font of the character * @param key Character code glyph * @return Width of the character glyph */ byte GetCharacterWidth(FontSize size, WChar key) { /* Use _stringwidth_table cache if possible */ if (key >= 32 && key < 256) return _stringwidth_table[size][key - 32]; return GetGlyphWidth(size, key); } /** * Return the maximum width of single digit. * @param size Font of the digit * @return Width of the digit. */ byte GetDigitWidth(FontSize size) { byte width = 0; for (char c = '0'; c <= '9'; c++) { width = max(GetCharacterWidth(size, c), width); } return width; } /** * Determine the broadest digits for guessing the maximum width of a n-digit number. * @param [out] front Broadest digit, which is not 0. (Use this digit as first digit for numbers with more than one digit.) * @param [out] next Broadest digit, including 0. (Use this digit for all digits, except the first one; or for numbers with only one digit.) * @param size Font of the digit */ void GetBroadestDigit(uint *front, uint *next, FontSize size) { int width = -1; for (char c = '9'; c >= '0'; c--) { int w = GetCharacterWidth(size, c); if (w > width) { width = w; *next = c - '0'; if (c != '0') *front = c - '0'; } } } void ScreenSizeChanged() { _dirty_bytes_per_line = CeilDiv(_screen.width, DIRTY_BLOCK_WIDTH); _dirty_blocks = ReallocT(_dirty_blocks, _dirty_bytes_per_line * CeilDiv(_screen.height, DIRTY_BLOCK_HEIGHT)); /* check the dirty rect */ if (_invalid_rect.right >= _screen.width) _invalid_rect.right = _screen.width; if (_invalid_rect.bottom >= _screen.height) _invalid_rect.bottom = _screen.height; /* screen size changed and the old bitmap is invalid now, so we don't want to undraw it */ _cursor.visible = false; } void UndrawMouseCursor() { /* Don't undraw the mouse cursor if the screen is not ready */ if (_screen.dst_ptr == NULL) return; if (_cursor.visible) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); _cursor.visible = false; blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), _cursor_backup.GetBuffer(), _cursor.draw_size.x, _cursor.draw_size.y); VideoDriver::GetInstance()->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); } } void DrawMouseCursor() { #if defined(WINCE) /* Don't ever draw the mouse for WinCE, as we work with a stylus */ return; #endif /* Don't draw the mouse cursor if the screen is not ready */ if (_screen.dst_ptr == NULL) return; Blitter *blitter = BlitterFactory::GetCurrentBlitter(); int x; int y; int w; int h; /* Redraw mouse cursor but only when it's inside the window */ if (!_cursor.in_window) return; /* Don't draw the mouse cursor if it's already drawn */ if (_cursor.visible) { if (!_cursor.dirty) return; UndrawMouseCursor(); } w = _cursor.size.x; x = _cursor.pos.x + _cursor.offs.x + _cursor.short_vehicle_offset; if (x < 0) { w += x; x = 0; } if (w > _screen.width - x) w = _screen.width - x; if (w <= 0) return; _cursor.draw_pos.x = x; _cursor.draw_size.x = w; h = _cursor.size.y; y = _cursor.pos.y + _cursor.offs.y; if (y < 0) { h += y; y = 0; } if (h > _screen.height - y) h = _screen.height - y; if (h <= 0) return; _cursor.draw_pos.y = y; _cursor.draw_size.y = h; uint8 *buffer = _cursor_backup.Allocate(blitter->BufferSize(w, h)); /* Make backup of stuff below cursor */ blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, _cursor.draw_pos.x, _cursor.draw_pos.y), buffer, _cursor.draw_size.x, _cursor.draw_size.y); /* Draw cursor on screen */ _cur_dpi = &_screen; DrawSprite(_cursor.sprite, _cursor.pal, _cursor.pos.x + _cursor.short_vehicle_offset, _cursor.pos.y); VideoDriver::GetInstance()->MakeDirty(_cursor.draw_pos.x, _cursor.draw_pos.y, _cursor.draw_size.x, _cursor.draw_size.y); _cursor.visible = true; _cursor.dirty = false; } void RedrawScreenRect(int left, int top, int right, int bottom) { assert(right <= _screen.width && bottom <= _screen.height); if (_cursor.visible) { if (right > _cursor.draw_pos.x && left < _cursor.draw_pos.x + _cursor.draw_size.x && bottom > _cursor.draw_pos.y && top < _cursor.draw_pos.y + _cursor.draw_size.y) { UndrawMouseCursor(); } } #ifdef ENABLE_NETWORK if (_networking) NetworkUndrawChatMessage(); #endif /* ENABLE_NETWORK */ DrawOverlappedWindowForAll(left, top, right, bottom); VideoDriver::GetInstance()->MakeDirty(left, top, right - left, bottom - top); } /** * Repaints the rectangle blocks which are marked as 'dirty'. * * @see SetDirtyBlocks */ void DrawDirtyBlocks() { byte *b = _dirty_blocks; const int w = Align(_screen.width, DIRTY_BLOCK_WIDTH); const int h = Align(_screen.height, DIRTY_BLOCK_HEIGHT); int x; int y; if (HasModalProgress()) { /* We are generating the world, so release our rights to the map and * painting while we are waiting a bit. */ _modal_progress_paint_mutex->EndCritical(); _modal_progress_work_mutex->EndCritical(); /* Wait a while and update _realtime_tick so we are given the rights */ if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT); _realtime_tick += MODAL_PROGRESS_REDRAW_TIMEOUT; _modal_progress_paint_mutex->BeginCritical(); _modal_progress_work_mutex->BeginCritical(); /* When we ended with the modal progress, do not draw the blocks. * Simply let the next run do so, otherwise we would be loading * the new state (and possibly change the blitter) when we hold * the drawing lock, which we must not do. */ if (_switch_mode != SM_NONE && !HasModalProgress()) return; } y = 0; do { x = 0; do { if (*b != 0) { int left; int top; int right = x + DIRTY_BLOCK_WIDTH; int bottom = y; byte *p = b; int h2; /* First try coalescing downwards */ do { *p = 0; p += _dirty_bytes_per_line; bottom += DIRTY_BLOCK_HEIGHT; } while (bottom != h && *p != 0); /* Try coalescing to the right too. */ h2 = (bottom - y) / DIRTY_BLOCK_HEIGHT; assert(h2 > 0); p = b; while (right != w) { byte *p2 = ++p; int h = h2; /* Check if a full line of dirty flags is set. */ do { if (!*p2) goto no_more_coalesc; p2 += _dirty_bytes_per_line; } while (--h != 0); /* Wohoo, can combine it one step to the right! * Do that, and clear the bits. */ right += DIRTY_BLOCK_WIDTH; h = h2; p2 = p; do { *p2 = 0; p2 += _dirty_bytes_per_line; } while (--h != 0); } no_more_coalesc: left = x; top = y; if (left < _invalid_rect.left ) left = _invalid_rect.left; if (top < _invalid_rect.top ) top = _invalid_rect.top; if (right > _invalid_rect.right ) right = _invalid_rect.right; if (bottom > _invalid_rect.bottom) bottom = _invalid_rect.bottom; if (left < right && top < bottom) { RedrawScreenRect(left, top, right, bottom); } } } while (b++, (x += DIRTY_BLOCK_WIDTH) != w); } while (b += -(int)(w / DIRTY_BLOCK_WIDTH) + _dirty_bytes_per_line, (y += DIRTY_BLOCK_HEIGHT) != h); ++_dirty_block_colour; _invalid_rect.left = w; _invalid_rect.top = h; _invalid_rect.right = 0; _invalid_rect.bottom = 0; } /** * This function extends the internal _invalid_rect rectangle as it * now contains the rectangle defined by the given parameters. Note * the point (0,0) is top left. * * @param left The left edge of the rectangle * @param top The top edge of the rectangle * @param right The right edge of the rectangle * @param bottom The bottom edge of the rectangle * @see DrawDirtyBlocks * * @todo The name of the function should be called like @c AddDirtyBlock as * it neither set a dirty rect nor add several dirty rects although * the function name is in plural. (Progman) */ void SetDirtyBlocks(int left, int top, int right, int bottom) { byte *b; int width; int height; if (left < 0) left = 0; if (top < 0) top = 0; if (right > _screen.width) right = _screen.width; if (bottom > _screen.height) bottom = _screen.height; if (left >= right || top >= bottom) return; if (left < _invalid_rect.left ) _invalid_rect.left = left; if (top < _invalid_rect.top ) _invalid_rect.top = top; if (right > _invalid_rect.right ) _invalid_rect.right = right; if (bottom > _invalid_rect.bottom) _invalid_rect.bottom = bottom; left /= DIRTY_BLOCK_WIDTH; top /= DIRTY_BLOCK_HEIGHT; b = _dirty_blocks + top * _dirty_bytes_per_line + left; width = ((right - 1) / DIRTY_BLOCK_WIDTH) - left + 1; height = ((bottom - 1) / DIRTY_BLOCK_HEIGHT) - top + 1; assert(width > 0 && height > 0); do { int i = width; do b[--i] = 0xFF; while (i != 0); b += _dirty_bytes_per_line; } while (--height != 0); } /** * This function mark the whole screen as dirty. This results in repainting * the whole screen. Use this with care as this function will break the * idea about marking only parts of the screen as 'dirty'. * @ingroup dirty */ void MarkWholeScreenDirty() { SetDirtyBlocks(0, 0, _screen.width, _screen.height); } /** * Set up a clipping area for only drawing into a certain area. To do this, * Fill a DrawPixelInfo object with the supplied relative rectangle, backup * the original (calling) _cur_dpi and assign the just returned DrawPixelInfo * _cur_dpi. When you are done, give restore _cur_dpi's original value * @param *n the DrawPixelInfo that will be the clipping rectangle box allowed * for drawing * @param left,top,width,height the relative coordinates of the clipping * rectangle relative to the current _cur_dpi. This will most likely be the * offset from the calling window coordinates * @return return false if the requested rectangle is not possible with the * current dpi pointer. Only continue of the return value is true, or you'll * get some nasty results */ bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); const DrawPixelInfo *o = _cur_dpi; n->zoom = ZOOM_LVL_NORMAL; assert(width > 0); assert(height > 0); if ((left -= o->left) < 0) { width += left; if (width <= 0) return false; n->left = -left; left = 0; } else { n->left = 0; } if (width > o->width - left) { width = o->width - left; if (width <= 0) return false; } n->width = width; if ((top -= o->top) < 0) { height += top; if (height <= 0) return false; n->top = -top; top = 0; } else { n->top = 0; } n->dst_ptr = blitter->MoveTo(o->dst_ptr, left, top); n->pitch = o->pitch; if (height > o->height - top) { height = o->height - top; if (height <= 0) return false; } n->height = height; return true; } /** * Update cursor dimension. * Called when changing cursor sprite resp. reloading grfs. */ void UpdateCursorSize() { CursorVars *cv = &_cursor; const Sprite *p = GetSprite(GB(cv->sprite, 0, SPRITE_WIDTH), ST_NORMAL); cv->size.y = UnScaleGUI(p->height); cv->size.x = UnScaleGUI(p->width); cv->offs.x = UnScaleGUI(p->x_offs); cv->offs.y = UnScaleGUI(p->y_offs); cv->dirty = true; } /** * Switch cursor to different sprite. * @param cursor Sprite to draw for the cursor. * @param pal Palette to use for recolouring. */ static void SetCursorSprite(CursorID cursor, PaletteID pal) { CursorVars *cv = &_cursor; if (cv->sprite == cursor) return; cv->sprite = cursor; cv->pal = pal; UpdateCursorSize(); cv->short_vehicle_offset = 0; } static void SwitchAnimatedCursor() { const AnimCursor *cur = _cursor.animate_cur; if (cur == NULL || cur->sprite == AnimCursor::LAST) cur = _cursor.animate_list; SetCursorSprite(cur->sprite, _cursor.pal); _cursor.animate_timeout = cur->display_time; _cursor.animate_cur = cur + 1; } void CursorTick() { if (_cursor.animate_timeout != 0 && --_cursor.animate_timeout == 0) { SwitchAnimatedCursor(); } } /** * Assign a single non-animated sprite to the cursor. * @param sprite Sprite to draw for the cursor. * @param pal Palette to use for recolouring. * @see SetAnimatedMouseCursor */ void SetMouseCursor(CursorID sprite, PaletteID pal) { /* Turn off animation */ _cursor.animate_timeout = 0; /* Set cursor */ SetCursorSprite(sprite, pal); } /** * Assign an animation to the cursor. * @param table Array of animation states. * @see SetMouseCursor */ void SetAnimatedMouseCursor(const AnimCursor *table) { _cursor.animate_list = table; _cursor.animate_cur = NULL; _cursor.pal = PAL_NONE; SwitchAnimatedCursor(); } /** * Update cursor position on mouse movement. * @param x New X position. * @param y New Y position. * @param queued True, if the OS queues mouse warps after pending mouse movement events. * False, if the warp applies instantaneous. * @return true, if the OS cursor position should be warped back to this->pos. */ bool CursorVars::UpdateCursorPosition(int x, int y, bool queued_warp) { /* Detecting relative mouse movement is somewhat tricky. * - There may be multiple mouse move events in the video driver queue (esp. when OpenTTD lags a bit). * - When we request warping the mouse position (return true), a mouse move event is appended at the end of the queue. * * So, when this->fix_at is active, we use the following strategy: * - The first movement triggers the warp to reset the mouse position. * - Subsequent events have to compute movement relative to the previous event. * - The relative movement is finished, when we receive the event matching the warp. */ if (x == this->pos.x && y == this->pos.y) { /* Warp finished. */ this->queued_warp = false; } this->delta.x = x - (this->queued_warp ? this->last_position.x : this->pos.x); this->delta.y = y - (this->queued_warp ? this->last_position.y : this->pos.y); this->last_position.x = x; this->last_position.y = y; bool need_warp = false; if (this->fix_at) { if (this->delta.x != 0 || this->delta.y != 0) { /* Trigger warp. * Note: We also trigger warping again, if there is already a pending warp. * This makes it more tolerant about the OS or other software inbetween * botchering the warp. */ this->queued_warp = queued_warp; need_warp = true; } } else if (this->pos.x != x || this->pos.y != y) { this->queued_warp = false; // Cancel warping, we are no longer confining the position. this->dirty = true; this->pos.x = x; this->pos.y = y; } return need_warp; } bool ChangeResInGame(int width, int height) { return (_screen.width == width && _screen.height == height) || VideoDriver::GetInstance()->ChangeResolution(width, height); } bool ToggleFullScreen(bool fs) { bool result = VideoDriver::GetInstance()->ToggleFullscreen(fs); if (_fullscreen != fs && _num_resolutions == 0) { DEBUG(driver, 0, "Could not find a suitable fullscreen resolution"); } return result; } static int CDECL compare_res(const Dimension *pa, const Dimension *pb) { int x = pa->width - pb->width; if (x != 0) return x; return pa->height - pb->height; } void SortResolutions(int count) { QSortT(_resolutions, count, &compare_res); } openttd-1.5.3/src/tar_type.h0000644000000000000000000000322112627373435014474 0ustar rootroot/* $Id: tar_type.h 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 tar_type.h Structs, typedefs and macros used for TAR file handling. */ #ifndef TAR_TYPE_H #define TAR_TYPE_H #include #include #include "fileio_type.h" /** The define of a TarList. */ struct TarListEntry { const char *filename; const char *dirname; /* MSVC goes copying around this struct after initialisation, so it tries * to free filename, which isn't set at that moment... but because it * initializes the variable with garbage, it's going to segfault. */ TarListEntry() : filename(NULL), dirname(NULL) {} ~TarListEntry() { free(this->filename); free(this->dirname); } }; struct TarFileListEntry { const char *tar_filename; size_t size; size_t position; }; typedef std::map TarList; typedef std::map TarFileList; extern TarList _tar_list[NUM_SUBDIRS]; extern TarFileList _tar_filelist[NUM_SUBDIRS]; #define FOR_ALL_TARS(tar, sd) for (tar = _tar_filelist[sd].begin(); tar != _tar_filelist[sd].end(); tar++) #endif /* TAR_TYPE_H */ openttd-1.5.3/src/station_gui.cpp0000644000000000000000000024421312627373441015532 0ustar rootroot/* $Id: station_gui.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 station_gui.cpp The GUI for stations. */ #include "stdafx.h" #include "debug.h" #include "gui.h" #include "textbuf_gui.h" #include "company_func.h" #include "command_func.h" #include "vehicle_gui.h" #include "cargotype.h" #include "station_gui.h" #include "strings_func.h" #include "string_func.h" #include "window_func.h" #include "viewport_func.h" #include "widgets/dropdown_func.h" #include "station_base.h" #include "waypoint_base.h" #include "tilehighlight_func.h" #include "company_base.h" #include "sortlist_type.h" #include "core/geometry_func.hpp" #include "vehiclelist.h" #include "town.h" #include "linkgraph/linkgraph.h" #include "zoom_func.h" #include "widgets/station_widget.h" #include "table/strings.h" #include #include #include "safeguards.h" /** * Calculates and draws the accepted or supplied cargo around the selected tile(s) * @param left x position where the string is to be drawn * @param right the right most position to draw on * @param top y position where the string is to be drawn * @param sct which type of cargo is to be displayed (passengers/non-passengers) * @param rad radius around selected tile(s) to be searched * @param supplies if supplied cargoes should be drawn, else accepted cargoes * @return Returns the y value below the string that was drawn */ int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies) { TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y); uint32 cargo_mask = 0; if (_thd.drawstyle == HT_RECT && tile < MapSize()) { CargoArray cargoes; if (supplies) { cargoes = GetProductionAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad); } else { cargoes = GetAcceptanceAroundTiles(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE, rad); } /* Convert cargo counts to a set of cargo bits, and draw the result. */ for (CargoID i = 0; i < NUM_CARGO; i++) { switch (sct) { case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break; case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break; case SCT_ALL: break; default: NOT_REACHED(); } if (cargoes[i] >= (supplies ? 1U : 8U)) SetBit(cargo_mask, i); } } SetDParam(0, cargo_mask); return DrawStringMultiLine(left, right, top, INT32_MAX, supplies ? STR_STATION_BUILD_SUPPLIES_CARGO : STR_STATION_BUILD_ACCEPTS_CARGO); } /** * Check whether we need to redraw the station coverage text. * If it is needed actually make the window for redrawing. * @param w the window to check. */ void CheckRedrawStationCoverage(const Window *w) { if (_thd.dirty & 1) { _thd.dirty &= ~1; w->SetDirty(); } } /** * Draw small boxes of cargo amount and ratings data at the given * coordinates. If amount exceeds 576 units, it is shown 'full', same * goes for the rating: at above 90% orso (224) it is also 'full' * * @param left left most coordinate to draw the box at * @param right right most coordinate to draw the box at * @param y coordinate to draw the box at * @param type Cargo type * @param amount Cargo amount * @param rating ratings data for that particular cargo * * @note Each cargo-bar is 16 pixels wide and 6 pixels high * @note Each rating 14 pixels wide and 1 pixel high and is 1 pixel below the cargo-bar */ static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating) { static const uint units_full = 576; ///< number of units to show station as 'full' static const uint rating_full = 224; ///< rating needed so it is shown as 'full' const CargoSpec *cs = CargoSpec::Get(type); if (!cs->IsValid()) return; int colour = cs->rating_colour; TextColour tc = GetContrastColour(colour); uint w = (minu(amount, units_full) + 5) / 36; int height = GetCharacterHeight(FS_SMALL); /* Draw total cargo (limited) on station (fits into 16 pixels) */ if (w != 0) GfxFillRect(left, y, left + w - 1, y + height, colour); /* Draw a one pixel-wide bar of additional cargo meter, useful * for stations with only a small amount (<=30) */ if (w == 0) { uint rest = amount / 5; if (rest != 0) { w += left; GfxFillRect(w, y + height - rest, w, y + height, colour); } } DrawString(left + 1, right, y, cs->abbrev, tc); /* Draw green/red ratings bar (fits into 14 pixels) */ y += height + 2; GfxFillRect(left + 1, y, left + 14, y, PC_RED); rating = minu(rating, rating_full) / 16; if (rating != 0) GfxFillRect(left + 1, y, left + rating, y, PC_GREEN); } typedef GUIList GUIStationList; /** * The list of stations per company. */ class CompanyStationsWindow : public Window { protected: /* Runtime saved values */ static Listing last_sorting; static byte facilities; // types of stations of interest static bool include_empty; // whether we should include stations without waiting cargo static const uint32 cargo_filter_max; static uint32 cargo_filter; // bitmap of cargo types to include static const Station *last_station; /* Constants for sorting stations */ static const StringID sorter_names[]; static GUIStationList::SortFunction * const sorter_funcs[]; GUIStationList stations; Scrollbar *vscroll; /** * (Re)Build station list * * @param owner company whose stations are to be in list */ void BuildStationsList(const Owner owner) { if (!this->stations.NeedRebuild()) return; DEBUG(misc, 3, "Building station list for company %d", owner); this->stations.Clear(); const Station *st; FOR_ALL_STATIONS(st) { if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, true, owner))) { if (this->facilities & st->facilities) { // only stations with selected facilities int num_waiting_cargo = 0; for (CargoID j = 0; j < NUM_CARGO; j++) { if (st->goods[j].HasRating()) { num_waiting_cargo++; // count number of waiting cargo if (HasBit(this->cargo_filter, j)) { *this->stations.Append() = st; break; } } } /* stations without waiting cargo */ if (num_waiting_cargo == 0 && this->include_empty) { *this->stations.Append() = st; } } } } this->stations.Compact(); this->stations.RebuildDone(); this->vscroll->SetCount(this->stations.Length()); // Update the scrollbar } /** Sort stations by their name */ static int CDECL StationNameSorter(const Station * const *a, const Station * const *b) { static char buf_cache[64]; char buf[64]; SetDParam(0, (*a)->index); GetString(buf, STR_STATION_NAME, lastof(buf)); if (*b != last_station) { last_station = *b; SetDParam(0, (*b)->index); GetString(buf_cache, STR_STATION_NAME, lastof(buf_cache)); } int r = strnatcmp(buf, buf_cache); // Sort by name (natural sorting). if (r == 0) return (*a)->index - (*b)->index; return r; } /** Sort stations by their type */ static int CDECL StationTypeSorter(const Station * const *a, const Station * const *b) { return (*a)->facilities - (*b)->facilities; } /** Sort stations by their waiting cargo */ static int CDECL StationWaitingTotalSorter(const Station * const *a, const Station * const *b) { int diff = 0; CargoID j; FOR_EACH_SET_CARGO_ID(j, cargo_filter) { diff += (*a)->goods[j].cargo.TotalCount() - (*b)->goods[j].cargo.TotalCount(); } return diff; } /** Sort stations by their available waiting cargo */ static int CDECL StationWaitingAvailableSorter(const Station * const *a, const Station * const *b) { int diff = 0; CargoID j; FOR_EACH_SET_CARGO_ID(j, cargo_filter) { diff += (*a)->goods[j].cargo.AvailableCount() - (*b)->goods[j].cargo.AvailableCount(); } return diff; } /** Sort stations by their rating */ static int CDECL StationRatingMaxSorter(const Station * const *a, const Station * const *b) { byte maxr1 = 0; byte maxr2 = 0; CargoID j; FOR_EACH_SET_CARGO_ID(j, cargo_filter) { if ((*a)->goods[j].HasRating()) maxr1 = max(maxr1, (*a)->goods[j].rating); if ((*b)->goods[j].HasRating()) maxr2 = max(maxr2, (*b)->goods[j].rating); } return maxr1 - maxr2; } /** Sort stations by their rating */ static int CDECL StationRatingMinSorter(const Station * const *a, const Station * const *b) { byte minr1 = 255; byte minr2 = 255; for (CargoID j = 0; j < NUM_CARGO; j++) { if (!HasBit(cargo_filter, j)) continue; if ((*a)->goods[j].HasRating()) minr1 = min(minr1, (*a)->goods[j].rating); if ((*b)->goods[j].HasRating()) minr2 = min(minr2, (*b)->goods[j].rating); } return -(minr1 - minr2); } /** Sort the stations list */ void SortStationsList() { if (!this->stations.Sort()) return; /* Reset name sorter sort cache */ this->last_station = NULL; /* Set the modified widget dirty */ this->SetWidgetDirty(WID_STL_LIST); } public: CompanyStationsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->stations.SetListing(this->last_sorting); this->stations.SetSortFuncs(this->sorter_funcs); this->stations.ForceRebuild(); this->stations.NeedResort(); this->SortStationsList(); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_STL_SCROLLBAR); this->FinishInitNested(window_number); this->owner = (Owner)this->window_number; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { if (!HasBit(this->cargo_filter, cs->Index())) continue; this->LowerWidget(WID_STL_CARGOSTART + index); } if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask; for (uint i = 0; i < 5; i++) { if (HasBit(this->facilities, i)) this->LowerWidget(i + WID_STL_TRAIN); } this->SetWidgetLoweredState(WID_STL_NOCARGOWAITING, this->include_empty); this->GetWidget(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()]; } ~CompanyStationsWindow() { this->last_sorting = this->stations.GetListing(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_STL_SORTBY: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_STL_SORTDROPBTN: { Dimension d = {0, 0}; for (int i = 0; this->sorter_names[i] != INVALID_STRING_ID; i++) { d = maxdim(d, GetStringBoundingBox(this->sorter_names[i])); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_STL_LIST: resize->height = FONT_HEIGHT_NORMAL; size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; break; case WID_STL_TRAIN: case WID_STL_TRUCK: case WID_STL_BUS: case WID_STL_AIRPLANE: case WID_STL_SHIP: size->height = max(FONT_HEIGHT_SMALL, 10) + padding.height; break; case WID_STL_CARGOALL: case WID_STL_FACILALL: case WID_STL_NOCARGOWAITING: { Dimension d = GetStringBoundingBox(widget == WID_STL_NOCARGOWAITING ? STR_ABBREV_NONE : STR_ABBREV_ALL); d.width += padding.width + 2; d.height += padding.height; *size = maxdim(*size, d); break; } default: if (widget >= WID_STL_CARGOSTART) { Dimension d = GetStringBoundingBox(_sorted_cargo_specs[widget - WID_STL_CARGOSTART]->abbrev); d.width += padding.width + 2; d.height += padding.height; *size = maxdim(*size, d); } break; } } virtual void OnPaint() { this->BuildStationsList((Owner)this->window_number); this->SortStationsList(); this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_STL_SORTBY: /* draw arrow pointing up/down for ascending/descending sorting */ this->DrawSortButtonState(WID_STL_SORTBY, this->stations.IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; case WID_STL_LIST: { bool rtl = _current_text_dir == TD_RTL; int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.Length()); int y = r.top + WD_FRAMERECT_TOP; for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner const Station *st = this->stations[i]; assert(st->xy != INVALID_TILE); /* Do not do the complex check HasStationInUse here, it may be even false * when the order had been removed and the station list hasn't been removed yet */ assert(st->owner == owner || st->owner == OWNER_NONE); SetDParam(0, st->index); SetDParam(1, st->facilities); int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); x += rtl ? -5 : 5; /* show cargo waiting and station ratings */ for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) { CargoID cid = _sorted_cargo_specs[j]->Index(); if (st->goods[cid].cargo.TotalCount() > 0) { /* For RTL we work in exactly the opposite direction. So * decrement the space needed first, then draw to the left * instead of drawing to the left and then incrementing * the space. */ if (rtl) { x -= 20; if (x < r.left + WD_FRAMERECT_LEFT) break; } StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating); if (!rtl) { x += 20; if (x > r.right - WD_FRAMERECT_RIGHT) break; } } } y += FONT_HEIGHT_NORMAL; } if (this->vscroll->GetCount() == 0) { // company has no stations DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_NONE); return; } break; } case WID_STL_NOCARGOWAITING: { int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER); break; } case WID_STL_CARGOALL: { int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); break; } case WID_STL_FACILALL: { int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); break; } default: if (widget >= WID_STL_CARGOSTART) { const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART]; int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1; GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour); TextColour tc = GetContrastColour(cs->rating_colour); DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER); } break; } } virtual void SetStringParameters(int widget) const { if (widget == WID_STL_CAPTION) { SetDParam(0, this->window_number); SetDParam(1, this->vscroll->GetCount()); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_STL_LIST: { uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, FONT_HEIGHT_NORMAL); if (id_v >= this->stations.Length()) return; // click out of list bound const Station *st = this->stations[id_v]; /* do not check HasStationInUse - it is slow and may be invalid */ assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE); if (_ctrl_pressed) { ShowExtraViewPortWindow(st->xy); } else { ScrollMainWindowToTile(st->xy); } break; } case WID_STL_TRAIN: case WID_STL_TRUCK: case WID_STL_BUS: case WID_STL_AIRPLANE: case WID_STL_SHIP: if (_ctrl_pressed) { ToggleBit(this->facilities, widget - WID_STL_TRAIN); this->ToggleWidgetLoweredState(widget); } else { uint i; FOR_EACH_SET_BIT(i, this->facilities) { this->RaiseWidget(i + WID_STL_TRAIN); } this->facilities = 1 << (widget - WID_STL_TRAIN); this->LowerWidget(widget); } this->stations.ForceRebuild(); this->SetDirty(); break; case WID_STL_FACILALL: for (uint i = WID_STL_TRAIN; i <= WID_STL_SHIP; i++) { this->LowerWidget(i); } this->facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK; this->stations.ForceRebuild(); this->SetDirty(); break; case WID_STL_CARGOALL: { for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { this->LowerWidget(WID_STL_CARGOSTART + i); } this->LowerWidget(WID_STL_NOCARGOWAITING); this->cargo_filter = _cargo_mask; this->include_empty = true; this->stations.ForceRebuild(); this->SetDirty(); break; } case WID_STL_SORTBY: // flip sorting method asc/desc this->stations.ToggleSortOrder(); this->SetDirty(); break; case WID_STL_SORTDROPBTN: // select sorting criteria dropdown menu ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), WID_STL_SORTDROPBTN, 0, 0); break; case WID_STL_NOCARGOWAITING: if (_ctrl_pressed) { this->include_empty = !this->include_empty; this->ToggleWidgetLoweredState(WID_STL_NOCARGOWAITING); } else { for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { this->RaiseWidget(WID_STL_CARGOSTART + i); } this->cargo_filter = 0; this->include_empty = true; this->LowerWidget(WID_STL_NOCARGOWAITING); } this->stations.ForceRebuild(); this->SetDirty(); break; default: if (widget >= WID_STL_CARGOSTART) { // change cargo_filter /* Determine the selected cargo type */ const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART]; if (_ctrl_pressed) { ToggleBit(this->cargo_filter, cs->Index()); this->ToggleWidgetLoweredState(widget); } else { for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { this->RaiseWidget(WID_STL_CARGOSTART + i); } this->RaiseWidget(WID_STL_NOCARGOWAITING); this->cargo_filter = 0; this->include_empty = false; SetBit(this->cargo_filter, cs->Index()); this->LowerWidget(widget); } this->stations.ForceRebuild(); this->SetDirty(); } break; } } virtual void OnDropdownSelect(int widget, int index) { if (this->stations.SortType() != index) { this->stations.SetSortType(index); /* Display the current sort variant */ this->GetWidget(WID_STL_SORTDROPBTN)->widget_data = this->sorter_names[this->stations.SortType()]; this->SetDirty(); } } virtual void OnTick() { if (_pause_mode != PM_UNPAUSED) return; if (this->stations.NeedResort()) { DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number); this->SetDirty(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_STL_LIST, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } /** * 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 (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->stations.ForceRebuild(); } else { this->stations.ForceResort(); } } }; Listing CompanyStationsWindow::last_sorting = {false, 0}; byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK; bool CompanyStationsWindow::include_empty = true; const uint32 CompanyStationsWindow::cargo_filter_max = UINT32_MAX; uint32 CompanyStationsWindow::cargo_filter = UINT32_MAX; const Station *CompanyStationsWindow::last_station = NULL; /* Availible station sorting functions */ GUIStationList::SortFunction * const CompanyStationsWindow::sorter_funcs[] = { &StationNameSorter, &StationTypeSorter, &StationWaitingTotalSorter, &StationWaitingAvailableSorter, &StationRatingMaxSorter, &StationRatingMinSorter }; /* Names of the sorting functions */ const StringID CompanyStationsWindow::sorter_names[] = { STR_SORT_BY_NAME, STR_SORT_BY_FACILITY, STR_SORT_BY_WAITING_TOTAL, STR_SORT_BY_WAITING_AVAILABLE, STR_SORT_BY_RATING_MAX, STR_SORT_BY_RATING_MIN, INVALID_STRING_ID }; /** * Make a horizontal row of cargo buttons, starting at widget #WID_STL_CARGOSTART. * @param biggest_index Pointer to store biggest used widget number of the buttons. * @return Horizontal row. */ static NWidgetBase *CargoWidgets(int *biggest_index) { NWidgetHorizontal *container = new NWidgetHorizontal(); for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i); panel->SetMinimalSize(14, 11); panel->SetResize(0, 0); panel->SetFill(0, 1); panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE); container->Add(panel); } *biggest_index = WID_STL_CARGOSTART + _sorted_standard_cargo_specs_size; return container; } static const NWidgetPart _nested_company_stations_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_STL_CAPTION), SetDataTip(STR_STATION_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 11), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 11), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 11), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 11), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 11), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(), NWidgetFunction(CargoWidgets), NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(), NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1), NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_STL_SORTBY), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_STL_SORTDROPBTN), SetMinimalSize(163, 12), SetDataTip(STR_SORT_BY_NAME, STR_TOOLTIP_SORT_CRITERIA), // widget_data gets overwritten. NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_LIST), SetMinimalSize(346, 125), SetResize(1, 10), SetDataTip(0x0, STR_STATION_LIST_TOOLTIP), SetScrollbar(WID_STL_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_STL_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), }; static WindowDesc _company_stations_desc( WDP_AUTO, "list_stations", 358, 162, WC_STATION_LIST, WC_NONE, 0, _nested_company_stations_widgets, lengthof(_nested_company_stations_widgets) ); /** * Opens window with list of company's stations * * @param company whose stations' list show */ void ShowCompanyStations(CompanyID company) { if (!Company::IsValidID(company)) return; AllocateWindowDescFront(&_company_stations_desc, company); } static const NWidgetPart _nested_station_view_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_SV_CAPTION), SetDataTip(STR_STATION_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SORT_ORDER), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_SORT_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_GROUP), SetMinimalSize(81, 12), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_GROUP, 0x0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SV_GROUP_BY), SetMinimalSize(168, 12), SetResize(1, 0), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_WAITING), SetMinimalSize(237, 44), SetResize(1, 10), SetScrollbar(WID_SV_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SV_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_SV_ACCEPT_RATING_LIST), SetMinimalSize(249, 23), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_LOCATION), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BUTTON_LOCATION, STR_STATION_VIEW_CENTER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ACCEPTS_RATINGS), SetMinimalSize(46, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_RENAME), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BUTTON_RENAME, STR_STATION_VIEW_RENAME_TOOLTIP), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SV_CLOSE_AIRPORT), SetMinimalSize(45, 12), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_STATION_VIEW_CLOSE_AIRPORT, STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_TRAINS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_ROADVEHS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_SHIPS), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SV_PLANES), SetMinimalSize(14, 12), SetFill(0, 1), SetDataTip(STR_PLANE, STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; /** * Draws icons of waiting cargo in the StationView window * * @param i type of cargo * @param waiting number of waiting units * @param left left most coordinate to draw on * @param right right most coordinate to draw on * @param y y coordinate * @param width the width of the view */ static void DrawCargoIcons(CargoID i, uint waiting, int left, int right, int y) { int width = ScaleGUITrad(10); uint num = min((waiting + (width / 2)) / width, (right - left) / width); // maximum is width / 10 icons so it won't overflow if (num == 0) return; SpriteID sprite = CargoSpec::Get(i)->GetCargoIcon(); int x = _current_text_dir == TD_RTL ? left : right - num * width; do { DrawSprite(sprite, PAL_NONE, x, y); x += width; } while (--num); } enum SortOrder { SO_DESCENDING, SO_ASCENDING }; class CargoDataEntry; enum CargoSortType { ST_AS_GROUPING, ///< by the same principle the entries are being grouped ST_COUNT, ///< by amount of cargo ST_STATION_STRING, ///< by station name ST_STATION_ID, ///< by station id ST_CARGO_ID, ///< by cargo id }; class CargoSorter { public: CargoSorter(CargoSortType t = ST_STATION_ID, SortOrder o = SO_ASCENDING) : type(t), order(o) {} CargoSortType GetSortType() {return this->type;} bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; private: CargoSortType type; SortOrder order; template bool SortId(Tid st1, Tid st2) const; bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; bool SortStation (StationID st1, StationID st2) const; }; typedef std::set CargoDataSet; /** * A cargo data entry representing one possible row in the station view window's * top part. Cargo data entries form a tree where each entry can have several * children. Parents keep track of the sums of their childrens' cargo counts. */ class CargoDataEntry { public: CargoDataEntry(); ~CargoDataEntry(); /** * Insert a new child or retrieve an existing child using a station ID as ID. * @param station ID of the station for which an entry shall be created or retrieved * @return a child entry associated with the given station. */ CargoDataEntry *InsertOrRetrieve(StationID station) { return this->InsertOrRetrieve(station); } /** * Insert a new child or retrieve an existing child using a cargo ID as ID. * @param cargo ID of the cargo for which an entry shall be created or retrieved * @return a child entry associated with the given cargo. */ CargoDataEntry *InsertOrRetrieve(CargoID cargo) { return this->InsertOrRetrieve(cargo); } void Update(uint count); /** * Remove a child associated with the given station. * @param station ID of the station for which the child should be removed. */ void Remove(StationID station) { CargoDataEntry t(station); this->Remove(&t); } /** * Remove a child associated with the given cargo. * @param cargo ID of the cargo for which the child should be removed. */ void Remove(CargoID cargo) { CargoDataEntry t(cargo); this->Remove(&t); } /** * Retrieve a child for the given station. Return NULL if it doesn't exist. * @param station ID of the station the child we're looking for is associated with. * @return a child entry for the given station or NULL. */ CargoDataEntry *Retrieve(StationID station) const { CargoDataEntry t(station); return this->Retrieve(this->children->find(&t)); } /** * Retrieve a child for the given cargo. Return NULL if it doesn't exist. * @param cargo ID of the cargo the child we're looking for is associated with. * @return a child entry for the given cargo or NULL. */ CargoDataEntry *Retrieve(CargoID cargo) const { CargoDataEntry t(cargo); return this->Retrieve(this->children->find(&t)); } void Resort(CargoSortType type, SortOrder order); /** * Get the station ID for this entry. */ StationID GetStation() const { return this->station; } /** * Get the cargo ID for this entry. */ CargoID GetCargo() const { return this->cargo; } /** * Get the cargo count for this entry. */ uint GetCount() const { return this->count; } /** * Get the parent entry for this entry. */ CargoDataEntry *GetParent() const { return this->parent; } /** * Get the number of children for this entry. */ uint GetNumChildren() const { return this->num_children; } /** * Get an iterator pointing to the begin of the set of children. */ CargoDataSet::iterator Begin() const { return this->children->begin(); } /** * Get an iterator pointing to the end of the set of children. */ CargoDataSet::iterator End() const { return this->children->end(); } /** * Has this entry transfers. */ bool HasTransfers() const { return this->transfers; } /** * Set the transfers state. */ void SetTransfers(bool value) { this->transfers = value; } void Clear(); private: CargoDataEntry(StationID st, uint c, CargoDataEntry *p); CargoDataEntry(CargoID car, uint c, CargoDataEntry *p); CargoDataEntry(StationID st); CargoDataEntry(CargoID car); CargoDataEntry *Retrieve(CargoDataSet::iterator i) const; template CargoDataEntry *InsertOrRetrieve(Tid s); void Remove(CargoDataEntry *comp); void IncrementSize(); CargoDataEntry *parent; ///< the parent of this entry. const union { StationID station; ///< ID of the station this entry is associated with. struct { CargoID cargo; ///< ID of the cargo this entry is associated with. bool transfers; ///< If there are transfers for this cargo. }; }; uint num_children; ///< the number of subentries belonging to this entry. uint count; ///< sum of counts of all children or amount of cargo for this entry. CargoDataSet *children; ///< the children of this entry. }; CargoDataEntry::CargoDataEntry() : parent(NULL), station(INVALID_STATION), num_children(0), count(0), children(new CargoDataSet(CargoSorter(ST_CARGO_ID))) {} CargoDataEntry::CargoDataEntry(CargoID cargo, uint count, CargoDataEntry *parent) : parent(parent), cargo(cargo), num_children(0), count(count), children(new CargoDataSet) {} CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) : parent(parent), station(station), num_children(0), count(count), children(new CargoDataSet) {} CargoDataEntry::CargoDataEntry(StationID station) : parent(NULL), station(station), num_children(0), count(0), children(NULL) {} CargoDataEntry::CargoDataEntry(CargoID cargo) : parent(NULL), cargo(cargo), num_children(0), count(0), children(NULL) {} CargoDataEntry::~CargoDataEntry() { this->Clear(); delete this->children; } /** * Delete all subentries, reset count and num_children and adapt parent's count. */ void CargoDataEntry::Clear() { if (this->children != NULL) { for (CargoDataSet::iterator i = this->children->begin(); i != this->children->end(); ++i) { assert(*i != this); delete *i; } this->children->clear(); } if (this->parent != NULL) this->parent->count -= this->count; this->count = 0; this->num_children = 0; } /** * Remove a subentry from this one and delete it. * @param child the entry to be removed. This may also be a synthetic entry * which only contains the ID of the entry to be removed. In this case child is * not deleted. */ void CargoDataEntry::Remove(CargoDataEntry *child) { CargoDataSet::iterator i = this->children->find(child); if (i != this->children->end()) { delete *i; this->children->erase(i); } } /** * Retrieve a subentry or insert it if it doesn't exist, yet. * @tparam ID type of ID: either StationID or CargoID * @param child_id ID of the child to be inserted or retrieved. * @return the new or retrieved subentry */ template CargoDataEntry *CargoDataEntry::InsertOrRetrieve(Tid child_id) { CargoDataEntry tmp(child_id); CargoDataSet::iterator i = this->children->find(&tmp); if (i == this->children->end()) { IncrementSize(); return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first); } else { CargoDataEntry *ret = *i; assert(this->children->value_comp().GetSortType() != ST_COUNT); return ret; } } /** * Update the count for this entry and propagate the change to the parent entry * if there is one. * @param count the amount to be added to this entry */ void CargoDataEntry::Update(uint count) { this->count += count; if (this->parent != NULL) this->parent->Update(count); } /** * Increment */ void CargoDataEntry::IncrementSize() { ++this->num_children; if (this->parent != NULL) this->parent->IncrementSize(); } void CargoDataEntry::Resort(CargoSortType type, SortOrder order) { CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order)); delete this->children; this->children = new_subs; } CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const { if (i == this->children->end()) { return NULL; } else { assert(this->children->value_comp().GetSortType() != ST_COUNT); return *i; } } bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const { switch (this->type) { case ST_STATION_ID: return this->SortId(cd1->GetStation(), cd2->GetStation()); case ST_CARGO_ID: return this->SortId(cd1->GetCargo(), cd2->GetCargo()); case ST_COUNT: return this->SortCount(cd1, cd2); case ST_STATION_STRING: return this->SortStation(cd1->GetStation(), cd2->GetStation()); default: NOT_REACHED(); } } template bool CargoSorter::SortId(Tid st1, Tid st2) const { return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1; } bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const { uint c1 = cd1->GetCount(); uint c2 = cd2->GetCount(); if (c1 == c2) { return this->SortStation(cd1->GetStation(), cd2->GetStation()); } else if (this->order == SO_ASCENDING) { return c1 < c2; } else { return c2 < c1; } } bool CargoSorter::SortStation(StationID st1, StationID st2) const { static char buf1[MAX_LENGTH_STATION_NAME_CHARS]; static char buf2[MAX_LENGTH_STATION_NAME_CHARS]; if (!Station::IsValidID(st1)) { return Station::IsValidID(st2) ? this->order == SO_ASCENDING : this->SortId(st1, st2); } else if (!Station::IsValidID(st2)) { return order == SO_DESCENDING; } SetDParam(0, st1); GetString(buf1, STR_STATION_NAME, lastof(buf1)); SetDParam(0, st2); GetString(buf2, STR_STATION_NAME, lastof(buf2)); int res = strnatcmp(buf1, buf2); // Sort by name (natural sorting). if (res == 0) { return this->SortId(st1, st2); } else { return (this->order == SO_ASCENDING) ? res < 0 : res > 0; } } /** * The StationView window */ struct StationViewWindow : public Window { /** * A row being displayed in the cargo view (as opposed to being "hidden" behind a plus sign). */ struct RowDisplay { RowDisplay(CargoDataEntry *f, StationID n) : filter(f), next_station(n) {} RowDisplay(CargoDataEntry *f, CargoID n) : filter(f), next_cargo(n) {} /** * Parent of the cargo entry belonging to the row. */ CargoDataEntry *filter; union { /** * ID of the station belonging to the entry actually displayed if it's to/from/via. */ StationID next_station; /** * ID of the cargo belonging to the entry actually displayed if it's cargo. */ CargoID next_cargo; }; }; typedef std::vector CargoDataVector; static const int NUM_COLUMNS = 4; ///< Number of "columns" in the cargo view: cargo, from, via, to /** * Type of data invalidation. */ enum Invalidation { INV_FLOWS = 0x100, ///< The planned flows have been recalculated and everything has to be updated. INV_CARGO = 0x200 ///< Some cargo has been added or removed. }; /** * Type of grouping used in each of the "columns". */ enum Grouping { GR_SOURCE, ///< Group by source of cargo ("from"). GR_NEXT, ///< Group by next station ("via"). GR_DESTINATION, ///< Group by estimated final destination ("to"). GR_CARGO, ///< Group by cargo type. }; /** * Display mode of the cargo view. */ enum Mode { MODE_WAITING, ///< Show cargo waiting at the station. MODE_PLANNED ///< Show cargo planned to pass through the station. }; uint expand_shrink_width; ///< The width allocated to the expand/shrink 'button' int rating_lines; ///< Number of lines in the cargo ratings view. int accepts_lines; ///< Number of lines in the accepted cargo view. Scrollbar *vscroll; /** Height of the #WID_SV_ACCEPT_RATING_LIST widget for different views. */ enum AcceptListHeight { ALH_RATING = 13, ///< Height of the cargo ratings view. ALH_ACCEPTS = 3, ///< Height of the accepted cargo view. }; static const StringID _sort_names[]; ///< Names of the sorting options in the dropdown. static const StringID _group_names[]; ///< Names of the grouping options in the dropdown. /** * Sort types of the different 'columns'. * In fact only ST_COUNT and ST_AS_GROUPING are active and you can only * sort all the columns in the same way. The other options haven't been * included in the GUI due to lack of space. */ CargoSortType sortings[NUM_COLUMNS]; /** Sort order (ascending/descending) for the 'columns'. */ SortOrder sort_orders[NUM_COLUMNS]; int scroll_to_row; ///< If set, scroll the main viewport to the station pointed to by this row. int grouping_index; ///< Currently selected entry in the grouping drop down. Mode current_mode; ///< Currently selected display mode of cargo view. Grouping groupings[NUM_COLUMNS]; ///< Grouping modes for the different columns. CargoDataEntry expanded_rows; ///< Parent entry of currently expanded rows. CargoDataEntry cached_destinations; ///< Cache for the flows passing through this station. CargoDataVector displayed_rows; ///< Parent entry of currently displayed rows (including collapsed ones). StationViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), scroll_to_row(INT_MAX), grouping_index(0) { this->rating_lines = ALH_RATING; this->accepts_lines = ALH_ACCEPTS; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_SV_SCROLLBAR); /* Nested widget tree creation is done in two steps to ensure that this->GetWidget(WID_SV_ACCEPTS_RATINGS) exists in UpdateWidgetSize(). */ this->FinishInitNested(window_number); this->groupings[0] = GR_CARGO; this->sortings[0] = ST_AS_GROUPING; this->SelectGroupBy(_settings_client.gui.station_gui_group_order); this->SelectSortBy(_settings_client.gui.station_gui_sort_by); this->sort_orders[0] = SO_ASCENDING; this->SelectSortOrder((SortOrder)_settings_client.gui.station_gui_sort_order); this->owner = Station::Get(window_number)->owner; } ~StationViewWindow() { DeleteWindowById(WC_TRAINS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_TRAIN, this->owner, this->window_number).Pack(), false); DeleteWindowById(WC_ROADVEH_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_ROAD, this->owner, this->window_number).Pack(), false); DeleteWindowById(WC_SHIPS_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_SHIP, this->owner, this->window_number).Pack(), false); DeleteWindowById(WC_AIRCRAFT_LIST, VehicleListIdentifier(VL_STATION_LIST, VEH_AIRCRAFT, this->owner, this->window_number).Pack(), false); } /** * Show a certain cargo entry characterized by source/next/dest station, cargo ID and amount of cargo at the * right place in the cargo view. I.e. update as many rows as are expanded following that characterization. * @param data Root entry of the tree. * @param cargo Cargo ID of the entry to be shown. * @param source Source station of the entry to be shown. * @param next Next station the cargo to be shown will visit. * @param dest Final destination of the cargo to be shown. * @param count Amount of cargo to be shown. */ void ShowCargo(CargoDataEntry *data, CargoID cargo, StationID source, StationID next, StationID dest, uint count) { if (count == 0) return; bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; const CargoDataEntry *expand = &this->expanded_rows; for (int i = 0; i < NUM_COLUMNS && expand != NULL; ++i) { switch (groupings[i]) { case GR_CARGO: assert(i == 0); data = data->InsertOrRetrieve(cargo); data->SetTransfers(source != this->window_number); expand = expand->Retrieve(cargo); break; case GR_SOURCE: if (auto_distributed || source != this->window_number) { data = data->InsertOrRetrieve(source); expand = expand->Retrieve(source); } break; case GR_NEXT: if (auto_distributed) { data = data->InsertOrRetrieve(next); expand = expand->Retrieve(next); } break; case GR_DESTINATION: if (auto_distributed) { data = data->InsertOrRetrieve(dest); expand = expand->Retrieve(dest); } break; } } data->Update(count); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SV_WAITING: resize->height = FONT_HEIGHT_NORMAL; size->height = WD_FRAMERECT_TOP + 4 * resize->height + WD_FRAMERECT_BOTTOM; this->expand_shrink_width = max(GetStringBoundingBox("-").width, GetStringBoundingBox("+").width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; break; case WID_SV_ACCEPT_RATING_LIST: size->height = WD_FRAMERECT_TOP + ((this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) ? this->accepts_lines : this->rating_lines) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; break; case WID_SV_CLOSE_AIRPORT: if (!(Station::Get(this->window_number)->facilities & FACIL_AIRPORT)) { /* Hide 'Close Airport' button if no airport present. */ size->width = 0; resize->width = 0; fill->width = 0; } break; } } virtual void OnPaint() { const Station *st = Station::Get(this->window_number); CargoDataEntry cargo; BuildCargoList(&cargo, st); this->vscroll->SetCount(cargo.GetNumChildren()); // update scrollbar /* disable some buttons */ this->SetWidgetDisabledState(WID_SV_RENAME, st->owner != _local_company); this->SetWidgetDisabledState(WID_SV_TRAINS, !(st->facilities & FACIL_TRAIN)); this->SetWidgetDisabledState(WID_SV_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP)); this->SetWidgetDisabledState(WID_SV_SHIPS, !(st->facilities & FACIL_DOCK)); this->SetWidgetDisabledState(WID_SV_PLANES, !(st->facilities & FACIL_AIRPORT)); this->SetWidgetDisabledState(WID_SV_CLOSE_AIRPORT, !(st->facilities & FACIL_AIRPORT) || st->owner != _local_company || st->owner == OWNER_NONE); // Also consider SE, where _local_company == OWNER_NONE this->SetWidgetLoweredState(WID_SV_CLOSE_AIRPORT, (st->facilities & FACIL_AIRPORT) && (st->airport.flags & AIRPORT_CLOSED_block) != 0); this->DrawWidgets(); if (!this->IsShaded()) { /* Draw 'accepted cargo' or 'cargo ratings'. */ const NWidgetBase *wid = this->GetWidget(WID_SV_ACCEPT_RATING_LIST); const Rect r = {wid->pos_x, wid->pos_y, wid->pos_x + wid->current_x - 1, wid->pos_y + wid->current_y - 1}; if (this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) { int lines = this->DrawAcceptedCargo(r); if (lines > this->accepts_lines) { // Resize the widget, and perform re-initialization of the window. this->accepts_lines = lines; this->ReInit(); return; } } else { int lines = this->DrawCargoRatings(r); if (lines > this->rating_lines) { // Resize the widget, and perform re-initialization of the window. this->rating_lines = lines; this->ReInit(); return; } } /* Draw arrow pointing up/down for ascending/descending sorting */ this->DrawSortButtonState(WID_SV_SORT_ORDER, sort_orders[1] == SO_ASCENDING ? SBS_UP : SBS_DOWN); int pos = this->vscroll->GetPosition(); int maxrows = this->vscroll->GetCapacity(); displayed_rows.clear(); /* Draw waiting cargo. */ NWidgetBase *nwi = this->GetWidget(WID_SV_WAITING); Rect waiting_rect = {nwi->pos_x, nwi->pos_y, nwi->pos_x + nwi->current_x - 1, nwi->pos_y + nwi->current_y - 1}; this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0); scroll_to_row = INT_MAX; } } virtual void SetStringParameters(int widget) const { const Station *st = Station::Get(this->window_number); SetDParam(0, st->index); SetDParam(1, st->facilities); } /** * Rebuild the cache for estimated destinations which is used to quickly show the "destination" entries * even if we actually don't know the destination of a certain packet from just looking at it. * @param i Cargo to recalculate the cache for. */ void RecalcDestinations(CargoID i) { const Station *st = Station::Get(this->window_number); CargoDataEntry *cargo_entry = cached_destinations.InsertOrRetrieve(i); cargo_entry->Clear(); const FlowStatMap &flows = st->goods[i].flows; for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) { StationID from = it->first; CargoDataEntry *source_entry = cargo_entry->InsertOrRetrieve(from); const FlowStat::SharesMap *shares = it->second.GetShares(); uint32 prev_count = 0; for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) { StationID via = flow_it->second; CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via); if (via == this->window_number) { via_entry->InsertOrRetrieve(via)->Update(flow_it->first - prev_count); } else { EstimateDestinations(i, from, via, flow_it->first - prev_count, via_entry); } prev_count = flow_it->first; } } } /** * Estimate the amounts of cargo per final destination for a given cargo, source station and next hop and * save the result as children of the given CargoDataEntry. * @param cargo ID of the cargo to estimate destinations for. * @param source Source station of the given batch of cargo. * @param next Intermediate hop to start the calculation at ("next hop"). * @param count Size of the batch of cargo. * @param dest CargoDataEntry to save the results in. */ void EstimateDestinations(CargoID cargo, StationID source, StationID next, uint count, CargoDataEntry *dest) { if (Station::IsValidID(next) && Station::IsValidID(source)) { CargoDataEntry tmp; const FlowStatMap &flowmap = Station::Get(next)->goods[cargo].flows; FlowStatMap::const_iterator map_it = flowmap.find(source); if (map_it != flowmap.end()) { const FlowStat::SharesMap *shares = map_it->second.GetShares(); uint32 prev_count = 0; for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) { tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count); prev_count = i->first; } } if (tmp.GetCount() == 0) { dest->InsertOrRetrieve(INVALID_STATION)->Update(count); } else { uint sum_estimated = 0; while (sum_estimated < count) { for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) { CargoDataEntry *child = *i; uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount()); if (estimate == 0) estimate = 1; sum_estimated += estimate; if (sum_estimated > count) { estimate -= sum_estimated - count; sum_estimated = count; } if (estimate > 0) { if (child->GetStation() == next) { dest->InsertOrRetrieve(next)->Update(estimate); } else { EstimateDestinations(cargo, source, child->GetStation(), estimate, dest); } } } } } } else { dest->InsertOrRetrieve(INVALID_STATION)->Update(count); } } /** * Build up the cargo view for PLANNED mode and a specific cargo. * @param i Cargo to show. * @param flows The current station's flows for that cargo. * @param cargo The CargoDataEntry to save the results in. */ void BuildFlowList(CargoID i, const FlowStatMap &flows, CargoDataEntry *cargo) { const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i); for (FlowStatMap::const_iterator it = flows.begin(); it != flows.end(); ++it) { StationID from = it->first; const CargoDataEntry *source_entry = source_dest->Retrieve(from); const FlowStat::SharesMap *shares = it->second.GetShares(); for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) { const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second); for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) { CargoDataEntry *dest_entry = *dest_it; ShowCargo(cargo, i, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount()); } } } } /** * Build up the cargo view for WAITING mode and a specific cargo. * @param i Cargo to show. * @param packets The current station's cargo list for that cargo. * @param cargo The CargoDataEntry to save the result in. */ void BuildCargoList(CargoID i, const StationCargoList &packets, CargoDataEntry *cargo) { const CargoDataEntry *source_dest = this->cached_destinations.Retrieve(i); for (StationCargoList::ConstIterator it = packets.Packets()->begin(); it != packets.Packets()->end(); it++) { const CargoPacket *cp = *it; StationID next = it.GetKey(); const CargoDataEntry *source_entry = source_dest->Retrieve(cp->SourceStation()); if (source_entry == NULL) { this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); continue; } const CargoDataEntry *via_entry = source_entry->Retrieve(next); if (via_entry == NULL) { this->ShowCargo(cargo, i, cp->SourceStation(), next, INVALID_STATION, cp->Count()); continue; } for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) { CargoDataEntry *dest_entry = *dest_it; uint val = DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount()); this->ShowCargo(cargo, i, cp->SourceStation(), next, dest_entry->GetStation(), val); } } this->ShowCargo(cargo, i, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount()); } /** * Build up the cargo view for all cargoes. * @param cargo The root cargo entry to save all results in. * @param st The station to calculate the cargo view from. */ void BuildCargoList(CargoDataEntry *cargo, const Station *st) { for (CargoID i = 0; i < NUM_CARGO; i++) { if (this->cached_destinations.Retrieve(i) == NULL) { this->RecalcDestinations(i); } if (this->current_mode == MODE_WAITING) { this->BuildCargoList(i, st->goods[i].cargo, cargo); } else { this->BuildFlowList(i, st->goods[i].flows, cargo); } } } /** * Mark a specific row, characterized by its CargoDataEntry, as expanded. * @param data The row to be marked as expanded. */ void SetDisplayedRow(const CargoDataEntry *data) { std::list stations; const CargoDataEntry *parent = data->GetParent(); if (parent->GetParent() == NULL) { this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, data->GetCargo())); return; } StationID next = data->GetStation(); while (parent->GetParent()->GetParent() != NULL) { stations.push_back(parent->GetStation()); parent = parent->GetParent(); } CargoID cargo = parent->GetCargo(); CargoDataEntry *filter = this->expanded_rows.Retrieve(cargo); while (!stations.empty()) { filter = filter->Retrieve(stations.back()); stations.pop_back(); } this->displayed_rows.push_back(RowDisplay(filter, next)); } /** * Select the correct string for an entry referring to the specified station. * @param station Station the entry is showing cargo for. * @param here String to be shown if the entry refers to the same station as this station GUI belongs to. * @param other_station String to be shown if the entry refers to a specific other station. * @param any String to be shown if the entry refers to "any station". * @return One of the three given strings or STR_STATION_VIEW_RESERVED, depending on what station the entry refers to. */ StringID GetEntryString(StationID station, StringID here, StringID other_station, StringID any) { if (station == this->window_number) { return here; } else if (station == INVALID_STATION) { return any; } else if (station == NEW_STATION) { return STR_STATION_VIEW_RESERVED; } else { SetDParam(2, station); return other_station; } } /** * Determine if we need to show the special "non-stop" string. * @param cd Entry we are going to show. * @param station Station the entry refers to. * @param column The "column" the entry will be shown in. * @return either STR_STATION_VIEW_VIA or STR_STATION_VIEW_NONSTOP. */ StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column) { CargoDataEntry *parent = cd->GetParent(); for (int i = column - 1; i > 0; --i) { if (this->groupings[i] == GR_DESTINATION) { if (parent->GetStation() == station) { return STR_STATION_VIEW_NONSTOP; } else { return STR_STATION_VIEW_VIA; } } parent = parent->GetParent(); } if (this->groupings[column + 1] == GR_DESTINATION) { CargoDataSet::iterator begin = cd->Begin(); CargoDataSet::iterator end = cd->End(); if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) { return STR_STATION_VIEW_NONSTOP; } else { return STR_STATION_VIEW_VIA; } } return STR_STATION_VIEW_VIA; } /** * Draw the given cargo entries in the station GUI. * @param entry Root entry for all cargo to be drawn. * @param r Screen rectangle to draw into. * @param pos Current row to be drawn to (counted down from 0 to -maxrows, same as vscroll->GetPosition()). * @param maxrows Maximum row to be drawn. * @param column Current "column" being drawn. * @param cargo Current cargo being drawn (if cargo column has been passed). * @return row (in "pos" counting) after the one we have last drawn to. */ int DrawEntries(CargoDataEntry *entry, Rect &r, int pos, int maxrows, int column, CargoID cargo = CT_INVALID) { if (this->sortings[column] == ST_AS_GROUPING) { if (this->groupings[column] != GR_CARGO) { entry->Resort(ST_STATION_STRING, this->sort_orders[column]); } } else { entry->Resort(ST_COUNT, this->sort_orders[column]); } for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) { CargoDataEntry *cd = *i; Grouping grouping = this->groupings[column]; if (grouping == GR_CARGO) cargo = cd->GetCargo(); bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; if (pos > -maxrows && pos <= 0) { StringID str = STR_EMPTY; int y = r.top + WD_FRAMERECT_TOP - pos * FONT_HEIGHT_NORMAL; SetDParam(0, cargo); SetDParam(1, cd->GetCount()); if (this->groupings[column] == GR_CARGO) { str = STR_STATION_VIEW_WAITING_CARGO; DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + WD_FRAMERECT_LEFT + this->expand_shrink_width, r.right - WD_FRAMERECT_RIGHT - this->expand_shrink_width, y); } else { if (!auto_distributed) grouping = GR_SOURCE; StationID station = cd->GetStation(); switch (grouping) { case GR_SOURCE: str = this->GetEntryString(station, STR_STATION_VIEW_FROM_HERE, STR_STATION_VIEW_FROM, STR_STATION_VIEW_FROM_ANY); break; case GR_NEXT: str = this->GetEntryString(station, STR_STATION_VIEW_VIA_HERE, STR_STATION_VIEW_VIA, STR_STATION_VIEW_VIA_ANY); if (str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column); break; case GR_DESTINATION: str = this->GetEntryString(station, STR_STATION_VIEW_TO_HERE, STR_STATION_VIEW_TO, STR_STATION_VIEW_TO_ANY); break; default: NOT_REACHED(); } if (pos == -this->scroll_to_row && Station::IsValidID(station)) { ScrollMainWindowToTile(Station::Get(station)->xy); } } bool rtl = _current_text_dir == TD_RTL; int text_left = rtl ? r.left + this->expand_shrink_width : r.left + WD_FRAMERECT_LEFT + column * this->expand_shrink_width; int text_right = rtl ? r.right - WD_FRAMERECT_LEFT - column * this->expand_shrink_width : r.right - this->expand_shrink_width; int shrink_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - this->expand_shrink_width + WD_FRAMERECT_LEFT; int shrink_right = rtl ? r.left + this->expand_shrink_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT; DrawString(text_left, text_right, y, str); if (column < NUM_COLUMNS - 1) { const char *sym = NULL; if (cd->GetNumChildren() > 0) { sym = "-"; } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) { sym = "+"; } else { /* Only draw '+' if there is something to be shown. */ const StationCargoList &list = Station::Get(this->window_number)->goods[cargo].cargo; if (grouping == GR_CARGO && (list.ReservedCount() > 0 || cd->HasTransfers())) { sym = "+"; } } if (sym) DrawString(shrink_left, shrink_right, y, sym, TC_YELLOW); } this->SetDisplayedRow(cd); } --pos; if (auto_distributed || column == 0) { pos = this->DrawEntries(cd, r, pos, maxrows, column + 1, cargo); } } return pos; } /** * Draw accepted cargo in the #WID_SV_ACCEPT_RATING_LIST widget. * @param r Rectangle of the widget. * @return Number of lines needed for drawing the accepted cargo. */ int DrawAcceptedCargo(const Rect &r) const { const Station *st = Station::Get(this->window_number); uint32 cargo_mask = 0; for (CargoID i = 0; i < NUM_CARGO; i++) { if (HasBit(st->goods[i].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(cargo_mask, i); } SetDParam(0, cargo_mask); int bottom = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INT32_MAX, STR_STATION_VIEW_ACCEPTS_CARGO); return CeilDiv(bottom - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL); } /** * Draw cargo ratings in the #WID_SV_ACCEPT_RATING_LIST widget. * @param r Rectangle of the widget. * @return Number of lines needed for drawing the cargo ratings. */ int DrawCargoRatings(const Rect &r) const { const Station *st = Station::Get(this->window_number); int y = r.top + WD_FRAMERECT_TOP; if (st->town->exclusive_counter > 0) { SetDParam(0, st->town->exclusivity); y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, st->town->exclusivity == st->owner ? STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF : STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY); y += WD_PAR_VSEP_WIDE; } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_VIEW_SUPPLY_RATINGS_TITLE); y += FONT_HEIGHT_NORMAL; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { const GoodsEntry *ge = &st->goods[cs->Index()]; if (!ge->HasRating()) continue; const LinkGraph *lg = LinkGraph::GetIfValid(ge->link_graph); SetDParam(0, cs->name); SetDParam(1, lg != NULL ? lg->Monthly((*lg)[ge->node].Supply()) : 0); SetDParam(2, STR_CARGO_RATING_APPALLING + (ge->rating >> 5)); SetDParam(3, ToPercent8(ge->rating)); DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT - 6, y, STR_STATION_VIEW_CARGO_SUPPLY_RATING); y += FONT_HEIGHT_NORMAL; } return CeilDiv(y - r.top - WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL); } /** * Expand or collapse a specific row. * @param filter Parent of the row. * @param next ID pointing to the row. */ template void HandleCargoWaitingClick(CargoDataEntry *filter, Tid next) { if (filter->Retrieve(next) != NULL) { filter->Remove(next); } else { filter->InsertOrRetrieve(next); } } /** * Handle a click on a specific row in the cargo view. * @param row Row being clicked. */ void HandleCargoWaitingClick(int row) { if (row < 0 || (uint)row >= this->displayed_rows.size()) return; if (_ctrl_pressed) { this->scroll_to_row = row; } else { RowDisplay &display = this->displayed_rows[row]; if (display.filter == &this->expanded_rows) { this->HandleCargoWaitingClick(display.filter, display.next_cargo); } else { this->HandleCargoWaitingClick(display.filter, display.next_station); } } this->SetWidgetDirty(WID_SV_WAITING); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_SV_WAITING: this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition()); break; case WID_SV_LOCATION: if (_ctrl_pressed) { ShowExtraViewPortWindow(Station::Get(this->window_number)->xy); } else { ScrollMainWindowToTile(Station::Get(this->window_number)->xy); } break; case WID_SV_ACCEPTS_RATINGS: { /* Swap between 'accepts' and 'ratings' view. */ int height_change; NWidgetCore *nwi = this->GetWidget(WID_SV_ACCEPTS_RATINGS); if (this->GetWidget(WID_SV_ACCEPTS_RATINGS)->widget_data == STR_STATION_VIEW_RATINGS_BUTTON) { nwi->SetDataTip(STR_STATION_VIEW_ACCEPTS_BUTTON, STR_STATION_VIEW_ACCEPTS_TOOLTIP); // Switch to accepts view. height_change = this->rating_lines - this->accepts_lines; } else { nwi->SetDataTip(STR_STATION_VIEW_RATINGS_BUTTON, STR_STATION_VIEW_RATINGS_TOOLTIP); // Switch to ratings view. height_change = this->accepts_lines - this->rating_lines; } this->ReInit(0, height_change * FONT_HEIGHT_NORMAL); break; } case WID_SV_RENAME: SetDParam(0, this->window_number); ShowQueryString(STR_STATION_NAME, STR_STATION_VIEW_RENAME_STATION_CAPTION, MAX_LENGTH_STATION_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); break; case WID_SV_CLOSE_AIRPORT: DoCommandP(0, this->window_number, 0, CMD_OPEN_CLOSE_AIRPORT); break; case WID_SV_TRAINS: // Show list of scheduled trains to this station case WID_SV_ROADVEHS: // Show list of scheduled road-vehicles to this station case WID_SV_SHIPS: // Show list of scheduled ships to this station case WID_SV_PLANES: { // Show list of scheduled aircraft to this station Owner owner = Station::Get(this->window_number)->owner; ShowVehicleListWindow(owner, (VehicleType)(widget - WID_SV_TRAINS), (StationID)this->window_number); break; } case WID_SV_SORT_BY: { /* The initial selection is composed of current mode and * sorting criteria for columns 1, 2, and 3. Column 0 is always * sorted by cargo ID. The others can theoretically be sorted * by different things but there is no UI for that. */ ShowDropDownMenu(this, _sort_names, this->current_mode * 2 + (this->sortings[1] == ST_COUNT ? 1 : 0), WID_SV_SORT_BY, 0, 0); break; } case WID_SV_GROUP_BY: { ShowDropDownMenu(this, _group_names, this->grouping_index, WID_SV_GROUP_BY, 0, 0); break; } case WID_SV_SORT_ORDER: { // flip sorting method asc/desc this->SelectSortOrder(this->sort_orders[1] == SO_ASCENDING ? SO_DESCENDING : SO_ASCENDING); this->SetTimeout(); this->LowerWidget(WID_SV_SORT_ORDER); break; } } } /** * Select a new sort order for the cargo view. * @param order New sort order. */ void SelectSortOrder(SortOrder order) { this->sort_orders[1] = this->sort_orders[2] = this->sort_orders[3] = order; _settings_client.gui.station_gui_sort_order = this->sort_orders[1]; this->SetDirty(); } /** * Select a new sort criterium for the cargo view. * @param index Row being selected in the sort criteria drop down. */ void SelectSortBy(int index) { _settings_client.gui.station_gui_sort_by = index; switch (_sort_names[index]) { case STR_STATION_VIEW_WAITING_STATION: this->current_mode = MODE_WAITING; this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING; break; case STR_STATION_VIEW_WAITING_AMOUNT: this->current_mode = MODE_WAITING; this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT; break; case STR_STATION_VIEW_PLANNED_STATION: this->current_mode = MODE_PLANNED; this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_AS_GROUPING; break; case STR_STATION_VIEW_PLANNED_AMOUNT: this->current_mode = MODE_PLANNED; this->sortings[1] = this->sortings[2] = this->sortings[3] = ST_COUNT; break; default: NOT_REACHED(); } /* Display the current sort variant */ this->GetWidget(WID_SV_SORT_BY)->widget_data = _sort_names[index]; this->SetDirty(); } /** * Select a new grouping mode for the cargo view. * @param index Row being selected in the grouping drop down. */ void SelectGroupBy(int index) { this->grouping_index = index; _settings_client.gui.station_gui_group_order = index; this->GetWidget(WID_SV_GROUP_BY)->widget_data = _group_names[index]; switch (_group_names[index]) { case STR_STATION_VIEW_GROUP_S_V_D: this->groupings[1] = GR_SOURCE; this->groupings[2] = GR_NEXT; this->groupings[3] = GR_DESTINATION; break; case STR_STATION_VIEW_GROUP_S_D_V: this->groupings[1] = GR_SOURCE; this->groupings[2] = GR_DESTINATION; this->groupings[3] = GR_NEXT; break; case STR_STATION_VIEW_GROUP_V_S_D: this->groupings[1] = GR_NEXT; this->groupings[2] = GR_SOURCE; this->groupings[3] = GR_DESTINATION; break; case STR_STATION_VIEW_GROUP_V_D_S: this->groupings[1] = GR_NEXT; this->groupings[2] = GR_DESTINATION; this->groupings[3] = GR_SOURCE; break; case STR_STATION_VIEW_GROUP_D_S_V: this->groupings[1] = GR_DESTINATION; this->groupings[2] = GR_SOURCE; this->groupings[3] = GR_NEXT; break; case STR_STATION_VIEW_GROUP_D_V_S: this->groupings[1] = GR_DESTINATION; this->groupings[2] = GR_NEXT; this->groupings[3] = GR_SOURCE; break; } this->SetDirty(); } virtual void OnDropdownSelect(int widget, int index) { if (widget == WID_SV_SORT_BY) { this->SelectSortBy(index); } else { this->SelectGroupBy(index); } } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; DoCommandP(0, this->window_number, 0, CMD_RENAME_STATION | CMD_MSG(STR_ERROR_CAN_T_RENAME_STATION), NULL, str); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_SV_WAITING, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } /** * Some data on this window has become invalid. Invalidate the cache for the given cargo if necessary. * @param data Information about the changed data. If it's a valid cargo ID, invalidate the cargo 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) { if (data >= 0 && data < NUM_CARGO) { this->cached_destinations.Remove((CargoID)data); } else { this->ReInit(); } } } }; const StringID StationViewWindow::_sort_names[] = { STR_STATION_VIEW_WAITING_STATION, STR_STATION_VIEW_WAITING_AMOUNT, STR_STATION_VIEW_PLANNED_STATION, STR_STATION_VIEW_PLANNED_AMOUNT, INVALID_STRING_ID }; const StringID StationViewWindow::_group_names[] = { STR_STATION_VIEW_GROUP_S_V_D, STR_STATION_VIEW_GROUP_S_D_V, STR_STATION_VIEW_GROUP_V_S_D, STR_STATION_VIEW_GROUP_V_D_S, STR_STATION_VIEW_GROUP_D_S_V, STR_STATION_VIEW_GROUP_D_V_S, INVALID_STRING_ID }; static WindowDesc _station_view_desc( WDP_AUTO, "view_station", 249, 117, WC_STATION_VIEW, WC_NONE, 0, _nested_station_view_widgets, lengthof(_nested_station_view_widgets) ); /** * Opens StationViewWindow for given station * * @param station station which window should be opened */ void ShowStationViewWindow(StationID station) { AllocateWindowDescFront(&_station_view_desc, station); } /** Struct containing TileIndex and StationID */ struct TileAndStation { TileIndex tile; ///< TileIndex StationID station; ///< StationID }; static SmallVector _deleted_stations_nearby; static SmallVector _stations_nearby_list; /** * Add station on this tile to _stations_nearby_list if it's fully within the * station spread. * @param tile Tile just being checked * @param user_data Pointer to TileArea context * @tparam T the type of station to look for */ template static bool AddNearbyStation(TileIndex tile, void *user_data) { TileArea *ctx = (TileArea *)user_data; /* First check if there were deleted stations here */ for (uint i = 0; i < _deleted_stations_nearby.Length(); i++) { TileAndStation *ts = _deleted_stations_nearby.Get(i); if (ts->tile == tile) { *_stations_nearby_list.Append() = _deleted_stations_nearby[i].station; _deleted_stations_nearby.Erase(ts); i--; } } /* Check if own station and if we stay within station spread */ if (!IsTileType(tile, MP_STATION)) return false; StationID sid = GetStationIndex(tile); /* This station is (likely) a waypoint */ if (!T::IsValidID(sid)) return false; T *st = T::Get(sid); if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false; if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) { *_stations_nearby_list.Append() = sid; } return false; // We want to include *all* nearby stations } /** * Circulate around the to-be-built station to find stations we could join. * Make sure that only stations are returned where joining wouldn't exceed * station spread and are our own station. * @param ta Base tile area of the to-be-built station * @param distant_join Search for adjacent stations (false) or stations fully * within station spread * @tparam T the type of station to look for */ template static const T *FindStationsNearby(TileArea ta, bool distant_join) { TileArea ctx = ta; _stations_nearby_list.Clear(); _deleted_stations_nearby.Clear(); /* Check the inside, to return, if we sit on another station */ TILE_AREA_LOOP(t, ta) { if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t); } /* Look for deleted stations */ const BaseStation *st; FOR_ALL_BASE_STATIONS(st) { if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) { /* Include only within station spread (yes, it is strictly less than) */ if (max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) { TileAndStation *ts = _deleted_stations_nearby.Append(); ts->tile = st->xy; ts->station = st->index; /* Add the station when it's within where we're going to build */ if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) && IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) { AddNearbyStation(st->xy, &ctx); } } } } /* Only search tiles where we have a chance to stay within the station spread. * The complete check needs to be done in the callback as we don't know the * extent of the found station, yet. */ if (distant_join && min(ta.w, ta.h) >= _settings_game.station.station_spread) return NULL; uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1; TileIndex tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N)); CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &ctx); return NULL; } static const NWidgetPart _nested_select_station_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_JS_CAPTION), SetDataTip(STR_JOIN_STATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_JS_PANEL), SetResize(1, 0), SetScrollbar(WID_JS_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_JS_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), EndContainer(), EndContainer(), }; /** * Window for selecting stations/waypoints to (distant) join to. * @tparam T The type of station to join with */ template struct SelectStationWindow : Window { CommandContainer select_station_cmd; ///< Command to build new station TileArea area; ///< Location of new station Scrollbar *vscroll; SelectStationWindow(WindowDesc *desc, const CommandContainer &cmd, TileArea ta) : Window(desc), select_station_cmd(cmd), area(ta) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_JS_SCROLLBAR); this->GetWidget(WID_JS_CAPTION)->widget_data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CAPTION : STR_JOIN_STATION_CAPTION; this->FinishInitNested(0); this->OnInvalidateData(0); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_JS_PANEL) return; /* Determine the widest string */ Dimension d = GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); for (uint i = 0; i < _stations_nearby_list.Length(); i++) { const T *st = T::Get(_stations_nearby_list[i]); SetDParam(0, st->index); SetDParam(1, st->facilities); d = maxdim(d, GetStringBoundingBox(T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION)); } resize->height = d.height; d.height *= 5; d.width += WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = d; } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_JS_PANEL) return; uint y = r.top + WD_FRAMERECT_TOP; if (this->vscroll->GetPosition() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT : STR_JOIN_STATION_CREATE_SPLITTED_STATION); y += this->resize.step_height; } for (uint i = max(1, this->vscroll->GetPosition()); i <= _stations_nearby_list.Length(); ++i, y += this->resize.step_height) { /* Don't draw anything if it extends past the end of the window. */ if (i - this->vscroll->GetPosition() >= this->vscroll->GetCapacity()) break; const T *st = T::Get(_stations_nearby_list[i - 1]); SetDParam(0, st->index); SetDParam(1, st->facilities); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION); } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget != WID_JS_PANEL) return; uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WD_FRAMERECT_TOP); bool distant_join = (st_index > 0); if (distant_join) st_index--; if (distant_join && st_index >= _stations_nearby_list.Length()) return; /* Insert station to be joined into stored command */ SB(this->select_station_cmd.p2, 16, 16, (distant_join ? _stations_nearby_list[st_index] : NEW_STATION)); /* Execute stored Command */ DoCommandP(&this->select_station_cmd); /* Close Window; this might cause double frees! */ DeleteWindowById(WC_SELECT_STATION, 0); } virtual void OnTick() { if (_thd.dirty & 2) { _thd.dirty &= ~2; this->SetDirty(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_JS_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } /** * 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; FindStationsNearby(this->area, true); this->vscroll->SetCount(_stations_nearby_list.Length() + 1); this->SetDirty(); } }; static WindowDesc _select_station_desc( WDP_AUTO, "build_station_join", 200, 180, WC_SELECT_STATION, WC_NONE, WDF_CONSTRUCTION, _nested_select_station_widgets, lengthof(_nested_select_station_widgets) ); /** * Check whether we need to show the station selection window. * @param cmd Command to build the station. * @param ta Tile area of the to-be-built station * @tparam T the type of station * @return whether we need to show the station selection window. */ template static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta) { /* Only show selection if distant join is enabled in the settings */ if (!_settings_game.station.distant_join_stations) return false; /* If a window is already opened and we didn't ctrl-click, * return true (i.e. just flash the old window) */ Window *selection_window = FindWindowById(WC_SELECT_STATION, 0); if (selection_window != NULL) { /* Abort current distant-join and start new one */ delete selection_window; UpdateTileSelection(); } /* only show the popup, if we press ctrl */ if (!_ctrl_pressed) return false; /* Now check if we could build there */ if (DoCommand(&cmd, CommandFlagsToDCFlags(GetCommandFlags(cmd.cmd))).Failed()) return false; /* Test for adjacent station or station below selection. * If adjacent-stations is disabled and we are building next to a station, do not show the selection window. * but join the other station immediately. */ const T *st = FindStationsNearby(ta, false); return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0); } /** * Show the station selection window when needed. If not, build the station. * @param cmd Command to build the station. * @param ta Area to build the station in * @tparam the class to find stations for */ template void ShowSelectBaseStationIfNeeded(const CommandContainer &cmd, TileArea ta) { if (StationJoinerNeeded(cmd, ta)) { if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); new SelectStationWindow(&_select_station_desc, cmd, ta); } else { DoCommandP(&cmd); } } /** * Show the station selection window when needed. If not, build the station. * @param cmd Command to build the station. * @param ta Area to build the station in */ void ShowSelectStationIfNeeded(const CommandContainer &cmd, TileArea ta) { ShowSelectBaseStationIfNeeded(cmd, ta); } /** * Show the waypoint selection window when needed. If not, build the waypoint. * @param cmd Command to build the waypoint. * @param ta Area to build the waypoint in */ void ShowSelectWaypointIfNeeded(const CommandContainer &cmd, TileArea ta) { ShowSelectBaseStationIfNeeded(cmd, ta); } openttd-1.5.3/src/newgrf_text.h0000644000000000000000000000713012627373442015202 0ustar rootroot/* $Id: newgrf_text.h 26243 2014-01-12 18:01:16Z frosch $ */ /* * 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 newgrf_text.h Header of Action 04 "universal holder" structure and functions */ #ifndef NEWGRF_TEXT_H #define NEWGRF_TEXT_H #include "string_type.h" #include "strings_type.h" #include "core/smallvec_type.hpp" #include "table/control_codes.h" /** This character, the thorn ('þ'), indicates a unicode string to NFO. */ static const WChar NFO_UTF8_IDENTIFIER = 0x00DE; StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid, bool new_scheme, bool allow_newlines, const char *text_to_add, StringID def_string); StringID GetGRFStringID(uint32 grfid, uint16 stringid); const char *GetGRFStringFromGRFText(const struct GRFText *text); const char *GetGRFStringPtr(uint16 stringid); void CleanUpStrings(); void SetCurrentGrfLangID(byte language_id); char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen = NULL, StringControlCode byte80 = SCC_NEWGRF_PRINT_WORD_STRING_ID); struct GRFText *DuplicateGRFText(struct GRFText *orig); void AddGRFTextToList(struct GRFText **list, struct GRFText *text_to_add); void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add); void AddGRFTextToList(struct GRFText **list, const char *text_to_add); void CleanUpGRFText(struct GRFText *grftext); bool CheckGrfLangID(byte lang_id, byte grf_version); void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values = NULL); void StopTextRefStackUsage(); void RewindTextRefStack(); bool UsingNewGRFTextStack(); struct TextRefStack *CreateTextRefStackBackup(); void RestoreTextRefStackBackup(struct TextRefStack *backup); uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv); /** Mapping of language data between a NewGRF and OpenTTD. */ struct LanguageMap { /** Mapping between NewGRF and OpenTTD IDs. */ struct Mapping { byte newgrf_id; ///< NewGRF's internal ID for a case/gender. byte openttd_id; ///< OpenTTD's internal ID for a case/gender. }; /* We need a vector and can't use SmallMap due to the fact that for "setting" a * gender of a string or requesting a case for a substring we want to map from * the NewGRF's internal ID to OpenTTD's ID whereas for the choice lists we map * the genders/cases/plural OpenTTD IDs to the NewGRF's internal IDs. In this * case a NewGRF developer/translator might want a different translation for * both cases. Thus we are basically implementing a multi-map. */ SmallVector gender_map; ///< Mapping of NewGRF and OpenTTD IDs for genders. SmallVector case_map; ///< Mapping of NewGRF and OpenTTD IDs for cases. int plural_form; ///< The plural form used for this language. int GetMapping(int newgrf_id, bool gender) const; int GetReverseMapping(int openttd_id, bool gender) const; static const LanguageMap *GetLanguageMap(uint32 grfid, uint8 language_id); }; #endif /* NEWGRF_TEXT_H */ openttd-1.5.3/src/tgp.h0000644000000000000000000000143012627373435013437 0ustar rootroot/* $Id: tgp.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 tgp.h Functions for the Perlin noise enhanced map generator. */ #ifndef TGP_H #define TGP_H void GenerateTerrainPerlin(); #endif /* TGP_H */ openttd-1.5.3/src/sortlist_type.h0000644000000000000000000002230612627373441015573 0ustar rootroot/* $Id: sortlist_type.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 sortlist_type.h Base types for having sorted lists in GUIs. */ #ifndef SORTLIST_TYPE_H #define SORTLIST_TYPE_H #include "core/enum_type.hpp" #include "core/bitmath_func.hpp" #include "core/sort_func.hpp" #include "core/smallvec_type.hpp" #include "date_type.h" /** Flags of the sort list. */ enum SortListFlags { VL_NONE = 0, ///< no sort VL_DESC = 1 << 0, ///< sort descending or ascending VL_RESORT = 1 << 1, ///< instruct the code to resort the list in the next loop VL_REBUILD = 1 << 2, ///< rebuild the sort list VL_FIRST_SORT = 1 << 3, ///< sort with quick sort first VL_FILTER = 1 << 4, ///< filter disabled/enabled VL_END = 1 << 5, }; DECLARE_ENUM_AS_BIT_SET(SortListFlags) /** Data structure describing how to show the list (what sort direction and criteria). */ struct Listing { bool order; ///< Ascending/descending byte criteria; ///< Sorting criteria }; /** Data structure describing what to show in the list (filter criteria). */ struct Filtering { bool state; ///< Filter on/off byte criteria; ///< Filtering criteria }; /** * List template of 'things' \p T to sort in a GUI. * @tparam T Type of data stored in the list to represent each item. * @tparam F Type of data fed as additional value to the filter function. @see FilterFunction */ template class GUIList : public SmallVector { public: typedef int CDECL SortFunction(const T*, const T*); ///< Signature of sort function. typedef bool CDECL FilterFunction(const T*, F); ///< Signature of filter function. protected: SortFunction * const *sort_func_list; ///< the sort criteria functions FilterFunction * const *filter_func_list; ///< the filter criteria functions SortListFlags flags; ///< used to control sorting/resorting/etc. uint8 sort_type; ///< what criteria to sort on uint8 filter_type; ///< what criteria to filter on uint16 resort_timer; ///< resort list after a given amount of ticks if set /** * Check if the list is sortable * * @return true if we can sort the list */ bool IsSortable() const { return (this->data != NULL && this->items >= 2); } /** * Reset the resort timer */ void ResetResortTimer() { /* Resort every 10 days */ this->resort_timer = DAY_TICKS * 10; } public: GUIList() : sort_func_list(NULL), filter_func_list(NULL), flags(VL_FIRST_SORT), sort_type(0), filter_type(0), resort_timer(1) {}; /** * Get the sorttype of the list * * @return The current sorttype */ uint8 SortType() const { return this->sort_type; } /** * Set the sorttype of the list * * @param n_type the new sort type */ void SetSortType(uint8 n_type) { if (this->sort_type != n_type) { SETBITS(this->flags, VL_RESORT | VL_FIRST_SORT); this->sort_type = n_type; } } /** * Export current sort conditions * * @return the current sort conditions */ Listing GetListing() const { Listing l; l.order = (this->flags & VL_DESC) != 0; l.criteria = this->sort_type; return l; } /** * Import sort conditions * * @param l The sort conditions we want to use */ void SetListing(Listing l) { if (l.order) { SETBITS(this->flags, VL_DESC); } else { CLRBITS(this->flags, VL_DESC); } this->sort_type = l.criteria; SETBITS(this->flags, VL_FIRST_SORT); } /** * Get the filtertype of the list * * @return The current filtertype */ uint8 FilterType() const { return this->filter_type; } /** * Set the filtertype of the list * * @param n_type the new filter type */ void SetFilterType(uint8 n_type) { if (this->filter_type != n_type) { this->filter_type = n_type; } } /** * Export current filter conditions * * @return the current filter conditions */ Filtering GetFiltering() const { Filtering f; f.state = (this->flags & VL_FILTER) != 0; f.criteria = this->filter_type; return f; } /** * Import filter conditions * * @param f The filter conditions we want to use */ void SetFiltering(Filtering f) { if (f.state) { SETBITS(this->flags, VL_FILTER); } else { CLRBITS(this->flags, VL_FILTER); } this->filter_type = f.criteria; } /** * Check if a resort is needed next loop * If used the resort timer will decrease every call * till 0. If 0 reached the resort bit will be set and * the timer will be reset. * * @return true if resort bit is set for next loop */ bool NeedResort() { if (--this->resort_timer == 0) { SETBITS(this->flags, VL_RESORT); this->ResetResortTimer(); return true; } return false; } /** * Force a resort next Sort call * Reset the resort timer if used too. */ void ForceResort() { SETBITS(this->flags, VL_RESORT); } /** * Check if the sort order is descending * * @return true if the sort order is descending */ bool IsDescSortOrder() const { return (this->flags & VL_DESC) != 0; } /** * Toggle the sort order * Since that is the worst condition for the sort function * reverse the list here. */ void ToggleSortOrder() { this->flags ^= VL_DESC; if (this->IsSortable()) MemReverseT(this->data, this->items); } /** * Sort the list. * For the first sorting we use quick sort since it is * faster for irregular sorted data. After that we * use gsort. * * @param compare The function to compare two list items * @return true if the list sequence has been altered * */ bool Sort(SortFunction *compare) { /* Do not sort if the resort bit is not set */ if (!(this->flags & VL_RESORT)) return false; CLRBITS(this->flags, VL_RESORT); this->ResetResortTimer(); /* Do not sort when the list is not sortable */ if (!this->IsSortable()) return false; const bool desc = (this->flags & VL_DESC) != 0; if (this->flags & VL_FIRST_SORT) { CLRBITS(this->flags, VL_FIRST_SORT); QSortT(this->data, this->items, compare, desc); return true; } GSortT(this->data, this->items, compare, desc); return true; } /** * Hand the array of sort function pointers to the sort list * * @param n_funcs The pointer to the first sort func */ void SetSortFuncs(SortFunction * const *n_funcs) { this->sort_func_list = n_funcs; } /** * Overload of #Sort(SortFunction *compare) * Overloaded to reduce external code * * @return true if the list sequence has been altered */ bool Sort() { assert(this->sort_func_list != NULL); return this->Sort(this->sort_func_list[this->sort_type]); } /** * Check if the filter is enabled * * @return true if the filter is enabled */ bool IsFilterEnabled() const { return (this->flags & VL_FILTER) != 0; } /** * Enable or disable the filter * * @param state If filtering should be enabled or disabled */ void SetFilterState(bool state) { if (state) { SETBITS(this->flags, VL_FILTER); } else { CLRBITS(this->flags, VL_FILTER); } } /** * Filter the list. * * @param decide The function to decide about an item * @param filter_data Additional data passed to the filter function * @return true if the list has been altered by filtering */ bool Filter(FilterFunction *decide, F filter_data) { /* Do not filter if the filter bit is not set */ if (!(this->flags & VL_FILTER)) return false; bool changed = false; for (uint iter = 0; iter < this->items;) { T *item = &this->data[iter]; if (!decide(item, filter_data)) { this->Erase(item); changed = true; } else { iter++; } } return changed; } /** * Hand the array of filter function pointers to the sort list * * @param n_funcs The pointer to the first filter func */ void SetFilterFuncs(FilterFunction * const *n_funcs) { this->filter_func_list = n_funcs; } /** * Filter the data with the currently selected filter. * * @param filter_data Additional data passed to the filter function. * @return true if the list has been altered by filtering */ bool Filter(F filter_data) { if (this->filter_func_list == NULL) return false; return this->Filter(this->filter_func_list[this->filter_type], filter_data); } /** * Check if a rebuild is needed * @return true if a rebuild is needed */ bool NeedRebuild() const { return (this->flags & VL_REBUILD) != 0; } /** * Force that a rebuild is needed */ void ForceRebuild() { SETBITS(this->flags, VL_REBUILD); } /** * Notify the sortlist that the rebuild is done * * @note This forces a resort */ void RebuildDone() { CLRBITS(this->flags, VL_REBUILD); SETBITS(this->flags, VL_RESORT | VL_FIRST_SORT); } }; #endif /* SORTLIST_TYPE_H */ openttd-1.5.3/src/command_func.h0000644000000000000000000001002312627373433015272 0ustar rootroot/* $Id: command_func.h 24139 2012-04-17 19:44:16Z michi_cc $ */ /* * 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 command_func.h Functions related to commands. */ #ifndef COMMAND_FUNC_H #define COMMAND_FUNC_H #include "command_type.h" #include "company_type.h" /** * Define a default return value for a failed command. * * This variable contains a CommandCost object with is declared as "failed". * Other functions just need to return this error if there is an error, * which doesn't need to specific by a StringID. */ static const CommandCost CMD_ERROR = CommandCost(INVALID_STRING_ID); /** * Returns from a function with a specific StringID as error. * * This macro is used to return from a function. The parameter contains the * StringID which will be returned. * * @param errcode The StringID to return */ #define return_cmd_error(errcode) return CommandCost(errcode); CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text = NULL); CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags); bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback = NULL, const char *text = NULL, bool my_cmd = true); bool DoCommandP(const CommandContainer *container, bool my_cmd = true); CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only); #ifdef ENABLE_NETWORK void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company); #endif /* ENABLE_NETWORK */ extern Money _additional_cash_required; bool IsValidCommand(uint32 cmd); CommandFlags GetCommandFlags(uint32 cmd); const char *GetCommandName(uint32 cmd); Money GetAvailableMoneyForCommand(); bool IsCommandAllowedWhilePaused(uint32 cmd); /** * Extracts the DC flags needed for DoCommand from the flags returned by GetCommandFlags * @param cmd_flags Flags from GetCommandFlags * @return flags for DoCommand */ static inline DoCommandFlag CommandFlagsToDCFlags(CommandFlags cmd_flags) { DoCommandFlag flags = DC_NONE; if (cmd_flags & CMD_NO_WATER) flags |= DC_NO_WATER; if (cmd_flags & CMD_AUTO) flags |= DC_AUTO; if (cmd_flags & CMD_ALL_TILES) flags |= DC_ALL_TILES; return flags; } /*** All command callbacks that exist ***/ /* ai/ai_instance.cpp */ CommandCallback CcAI; /* airport_gui.cpp */ CommandCallback CcBuildAirport; /* bridge_gui.cpp */ CommandCallback CcBuildBridge; /* dock_gui.cpp */ CommandCallback CcBuildDocks; CommandCallback CcBuildCanal; /* depot_gui.cpp */ CommandCallback CcCloneVehicle; /* game/game_instance.cpp */ CommandCallback CcGame; /* group_gui.cpp */ CommandCallback CcCreateGroup; CommandCallback CcAddVehicleNewGroup; /* industry_gui.cpp */ CommandCallback CcBuildIndustry; /* main_gui.cpp */ CommandCallback CcPlaySound10; CommandCallback CcPlaceSign; CommandCallback CcTerraform; CommandCallback CcGiveMoney; /* rail_gui.cpp */ CommandCallback CcPlaySound1E; CommandCallback CcRailDepot; CommandCallback CcStation; CommandCallback CcBuildRailTunnel; /* road_gui.cpp */ CommandCallback CcPlaySound1D; CommandCallback CcBuildRoadTunnel; CommandCallback CcRoadDepot; CommandCallback CcRoadStop; /* train_gui.cpp */ CommandCallback CcBuildWagon; /* town_gui.cpp */ CommandCallback CcFoundTown; CommandCallback CcFoundRandomTown; /* vehicle_gui.cpp */ CommandCallback CcBuildPrimaryVehicle; CommandCallback CcStartStopVehicle; #endif /* COMMAND_FUNC_H */ openttd-1.5.3/src/newgrf_airporttiles.h0000644000000000000000000000702012627373442016735 0ustar rootroot/* $Id: newgrf_airporttiles.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 newgrf_airporttiles.h NewGRF handling of airport tiles. */ #ifndef NEWGRF_AIRPORTTILES_H #define NEWGRF_AIRPORTTILES_H #include "airport.h" #include "station_map.h" #include "newgrf_animation_type.h" #include "newgrf_commons.h" #include "newgrf_spritegroup.h" /** Scope resolver for handling the tiles of an airport. */ struct AirportTileScopeResolver : public ScopeResolver { struct Station *st; ///< %Station of the airport for which the callback is run, or \c NULL for build gui. byte airport_id; ///< Type of airport for which the callback is run. TileIndex tile; ///< Tile for the callback, only valid for airporttile callbacks. AirportTileScopeResolver(ResolverObject &ro, const AirportTileSpec *ats, TileIndex tile, Station *st); /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; }; /** Resolver for tiles of an airport. */ struct AirportTileResolverObject : public ResolverObject { AirportTileScopeResolver tiles_scope; ///< Scope resolver for the tiles. AirportTileResolverObject(const AirportTileSpec *ats, TileIndex tile, Station *st, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &tiles_scope; default: return ResolverObject::GetScope(scope, relative); } } }; /** * Defines the data structure of each individual tile of an airport. */ struct AirportTileSpec { AnimationInfo animation; ///< Information about the animation. StringID name; ///< Tile Subname string, land information on this tile will give you "AirportName (TileSubname)" uint8 callback_mask; ///< Bitmask telling which grf callback is set uint8 animation_special_flags; ///< Extra flags to influence the animation bool enabled; ///< entity still available (by default true). newgrf can disable it, though GRFFileProps grf_prop; ///< properties related the the grf file static const AirportTileSpec *Get(StationGfx gfx); static const AirportTileSpec *GetByTile(TileIndex tile); static void ResetAirportTiles(); private: static AirportTileSpec tiles[NUM_AIRPORTTILES]; friend void AirportTileOverrideManager::SetEntitySpec(const AirportTileSpec *airpts); }; StationGfx GetTranslatedAirportTileID(StationGfx gfx); void AnimateAirportTile(TileIndex tile); void AirportTileAnimationTrigger(Station *st, TileIndex tile, AirpAnimationTrigger trigger, CargoID cargo_type = CT_INVALID); void AirportAnimationTrigger(Station *st, AirpAnimationTrigger trigger, CargoID cargo_type = CT_INVALID); bool DrawNewAirportTile(TileInfo *ti, Station *st, StationGfx gfx, const AirportTileSpec *airts); #endif /* NEWGRF_AIRPORTTILES_H */ openttd-1.5.3/src/company_gui.h0000644000000000000000000000230612627373442015160 0ustar rootroot/* $Id: company_gui.h 23410 2011-12-03 23:40:08Z michi_cc $ */ /* * 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 company_gui.h GUI Functions related to companies. */ #ifndef COMPANY_GUI_H #define COMPANY_GUI_H #include "company_type.h" #include "gfx_type.h" TextColour GetDrawStringCompanyColour(CompanyID company); void DrawCompanyIcon(CompanyID c, int x, int y); void ShowCompanyStations(CompanyID company); void ShowCompanyFinances(CompanyID company); void ShowCompany(CompanyID company); void InvalidateCompanyWindows(const Company *c); void DeleteCompanyWindows(CompanyID company); void DirtyCompanyInfrastructureWindows(CompanyID company); #endif /* COMPANY_GUI_H */ openttd-1.5.3/src/economy_base.h0000644000000000000000000000470712627373435015322 0ustar rootroot/* $Id: economy_base.h 25011 2013-02-17 14:50:54Z rubidium $ */ /* * 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 economy_base.h Base classes related to the economy. */ #ifndef ECONOMY_BASE_H #define ECONOMY_BASE_H #include "cargopacket.h" #include "company_type.h" /** Type of pool to store cargo payments in; little over 1 million. */ typedef Pool CargoPaymentPool; /** The actual pool to store cargo payments in. */ extern CargoPaymentPool _cargo_payment_pool; /** * Helper class to perform the cargo payment. */ struct CargoPayment : CargoPaymentPool::PoolItem<&_cargo_payment_pool> { Vehicle *front; ///< The front vehicle to do the payment of Money route_profit; ///< The amount of money to add/remove from the bank account Money visual_profit; ///< The visual profit to show Money visual_transfer; ///< The transfer credits to be shown /* Unsaved variables */ Company *owner; ///< The owner of the vehicle StationID current_station; ///< The current station CargoID ct; ///< The currently handled cargo type /** Constructor for pool saveload */ CargoPayment() {} CargoPayment(Vehicle *front); ~CargoPayment(); Money PayTransfer(const CargoPacket *cp, uint count); void PayFinalDelivery(const CargoPacket *cp, uint count); /** * Sets the currently handled cargo type. * @param ct the cargo type to handle from now on. */ void SetCargo(CargoID ct) { this->ct = ct; } }; /** * Iterate over all cargo payments from a given start position. * @param var The variable used for iterating. * @param start The start of the iteration. */ #define FOR_ALL_CARGO_PAYMENTS_FROM(var, start) FOR_ALL_ITEMS_FROM(CargoPayment, cargo_payment_index, var, start) /** * Iterate over all cargo payments. * @param var The variable used for iterating. */ #define FOR_ALL_CARGO_PAYMENTS(var) FOR_ALL_CARGO_PAYMENTS_FROM(var, 0) #endif /* ECONOMY_BASE_H */ openttd-1.5.3/src/ground_vehicle.cpp0000644000000000000000000001722012627373443016200 0ustar rootroot/* $Id: ground_vehicle.cpp 26702 2014-07-22 19:46:10Z rubidium $ */ /* * 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 ground_vehicle.cpp Implementation of GroundVehicle. */ #include "stdafx.h" #include "train.h" #include "roadveh.h" #include "depot_map.h" #include "safeguards.h" /** * Recalculates the cached total power of a vehicle. Should be called when the consist is changed. */ template void GroundVehicle::PowerChanged() { assert(this->First() == this); const T *v = T::From(this); uint32 total_power = 0; uint32 max_te = 0; uint32 number_of_parts = 0; uint16 max_track_speed = v->GetDisplayMaxSpeed(); for (const T *u = v; u != NULL; u = u->Next()) { uint32 current_power = u->GetPower() + u->GetPoweredPartPower(u); total_power += current_power; /* Only powered parts add tractive effort. */ if (current_power > 0) max_te += u->GetWeight() * u->GetTractiveEffort(); number_of_parts++; /* Get minimum max speed for this track. */ uint16 track_speed = u->GetMaxTrackSpeed(); if (track_speed > 0) max_track_speed = min(max_track_speed, track_speed); } byte air_drag; byte air_drag_value = v->GetAirDrag(); /* If air drag is set to zero (default), the resulting air drag coefficient is dependent on max speed. */ if (air_drag_value == 0) { uint16 max_speed = v->GetDisplayMaxSpeed(); /* Simplification of the method used in TTDPatch. It uses <= 10 to change more steadily from 128 to 196. */ air_drag = (max_speed <= 10) ? 192 : max(2048 / max_speed, 1); } else { /* According to the specs, a value of 0x01 in the air drag property means "no air drag". */ air_drag = (air_drag_value == 1) ? 0 : air_drag_value; } this->gcache.cached_air_drag = air_drag + 3 * air_drag * number_of_parts / 20; max_te *= 10000; // Tractive effort in (tonnes * 1000 * 10 =) N. max_te /= 256; // Tractive effort is a [0-255] coefficient. if (this->gcache.cached_power != total_power || this->gcache.cached_max_te != max_te) { /* Stop the vehicle if it has no power. */ if (total_power == 0) this->vehstatus |= VS_STOPPED; this->gcache.cached_power = total_power; this->gcache.cached_max_te = max_te; SetWindowDirty(WC_VEHICLE_DETAILS, this->index); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); } this->gcache.cached_max_track_speed = max_track_speed; } /** * Recalculates the cached weight of a vehicle and its parts. Should be called each time the cargo on * the consist changes. */ template void GroundVehicle::CargoChanged() { assert(this->First() == this); uint32 weight = 0; for (T *u = T::From(this); u != NULL; u = u->Next()) { uint32 current_weight = u->GetWeight(); weight += current_weight; /* Slope steepness is in percent, result in N. */ u->gcache.cached_slope_resistance = current_weight * u->GetSlopeSteepness() * 100; } /* Store consist weight in cache. */ this->gcache.cached_weight = max(1, weight); /* Friction in bearings and other mechanical parts is 0.1% of the weight (result in N). */ this->gcache.cached_axle_resistance = 10 * weight; /* Now update vehicle power (tractive effort is dependent on weight). */ this->PowerChanged(); } /** * Calculates the acceleration of the vehicle under its current conditions. * @return Current acceleration of the vehicle. */ template int GroundVehicle::GetAcceleration() const { /* Templated class used for function calls for performance reasons. */ const T *v = T::From(this); /* Speed is used squared later on, so U16 * U16, and then multiplied by other values. */ int64 speed = v->GetCurrentSpeed(); // [km/h-ish] /* Weight is stored in tonnes. */ int32 mass = this->gcache.cached_weight; /* Power is stored in HP, we need it in watts. * Each vehicle can have U16 power, 128 vehicles, HP -> watt * and km/h to m/s conversion below result in a maxium of * about 1.1E11, way more than 4.3E9 of int32. */ int64 power = this->gcache.cached_power * 746ll; /* This is constructed from: * - axle resistance: U16 power * 10 for 128 vehicles. * * 8.3E7 * - rolling friction: U16 power * 144 for 128 vehicles. * * 1.2E9 * - slope resistance: U16 weight * 100 * 10 (steepness) for 128 vehicles. * * 8.4E9 * - air drag: 28 * (U8 drag + 3 * U8 drag * 128 vehicles / 20) * U16 speed * U16 speed * * 6.2E14 before dividing by 1000 * Sum is 6.3E11, more than 4.3E9 of int32, so int64 is needed. */ int64 resistance = 0; bool maglev = v->GetAccelerationType() == 2; const int area = v->GetAirDragArea(); if (!maglev) { /* Static resistance plus rolling friction. */ resistance = this->gcache.cached_axle_resistance; resistance += mass * v->GetRollingFriction(); } /* Air drag; the air drag coefficient is in an arbitrary NewGRF-unit, * so we need some magic conversion factor. */ resistance += (area * this->gcache.cached_air_drag * speed * speed) / 1000; resistance += this->GetSlopeResistance(); /* This value allows to know if the vehicle is accelerating or braking. */ AccelStatus mode = v->GetAccelerationStatus(); const int max_te = this->gcache.cached_max_te; // [N] /* Constructued from power, with need to multiply by 18 and assuming * low speed, it needs to be a 64 bit integer too. */ int64 force; if (speed > 0) { if (!maglev) { /* Conversion factor from km/h to m/s is 5/18 to get [N] in the end. */ force = power * 18 / (speed * 5); if (mode == AS_ACCEL && force > max_te) force = max_te; } else { force = power / 25; } } else { /* "Kickoff" acceleration. */ force = (mode == AS_ACCEL && !maglev) ? min(max_te, power) : power; force = max(force, (mass * 8) + resistance); } if (mode == AS_ACCEL) { /* Easy way out when there is no acceleration. */ if (force == resistance) return 0; /* When we accelerate, make sure we always keep doing that, even when * the excess force is more than the mass. Otherwise a vehicle going * down hill will never slow down enough, and a vehicle that came up * a hill will never speed up enough to (eventually) get back to the * same (maximum) speed. */ int accel = ClampToI32((force - resistance) / (mass * 4)); return force < resistance ? min(-1, accel) : max(1, accel); } else { return ClampToI32(min(-force - resistance, -10000) / mass); } } /** * Check whether the whole vehicle chain is in the depot. * @return true if and only if the whole chain is in the depot. */ template bool GroundVehicle::IsChainInDepot() const { const T *v = this->First(); /* Is the front engine stationary in the depot? */ assert_compile((int)TRANSPORT_RAIL == (int)VEH_TRAIN); assert_compile((int)TRANSPORT_ROAD == (int)VEH_ROAD); if (!IsDepotTypeTile(v->tile, (TransportType)Type) || v->cur_speed != 0) return false; /* Check whether the rest is also already trying to enter the depot. */ for (; v != NULL; v = v->Next()) { if (!v->T::IsInDepot() || v->tile != this->tile) return false; } return true; } /* Instantiation for Train */ template struct GroundVehicle; /* Instantiation for RoadVehicle */ template struct GroundVehicle; openttd-1.5.3/src/os/0000755000000000000000000000000012627373441013114 5ustar rootrootopenttd-1.5.3/src/os/windows/0000755000000000000000000000000012627373441014606 5ustar rootrootopenttd-1.5.3/src/os/windows/win32.cpp0000644000000000000000000005573612627373441016274 0ustar rootroot/* $Id: win32.cpp 26606 2014-05-22 19:03:14Z frosch $ */ /* * 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 win32.cpp Implementation of MS Windows system calls */ #include "../../stdafx.h" #include "../../debug.h" #include "../../gfx_func.h" #include "../../textbuf_gui.h" #include "../../fileio_func.h" #include "../../fios.h" #include #include #include #include /* SHGetFolderPath */ #include #include "win32.h" #include "../../core/alloc_func.hpp" #include "../../openttd.h" #include "../../core/random_func.hpp" #include "../../string_func.h" #include "../../crashlog.h" #include #include /* Due to TCHAR, strncat and strncpy have to remain (for a while). */ #include "../../safeguards.h" #undef strncat #undef strncpy static bool _has_console; static bool _cursor_disable = true; static bool _cursor_visible = true; bool MyShowCursor(bool show, bool toggle) { if (toggle) _cursor_disable = !_cursor_disable; if (_cursor_disable) return show; if (_cursor_visible == show) return show; _cursor_visible = show; ShowCursor(show); return !show; } /** * Helper function needed by dynamically loading libraries * XXX: Hurray for MS only having an ANSI GetProcAddress function * on normal windows and no Wide version except for in Windows Mobile/CE */ bool LoadLibraryList(Function proc[], const char *dll) { while (*dll != '\0') { HMODULE lib; lib = LoadLibrary(MB_TO_WIDE(dll)); if (lib == NULL) return false; for (;;) { FARPROC p; while (*dll++ != '\0') { /* Nothing */ } if (*dll == '\0') break; #if defined(WINCE) p = GetProcAddress(lib, MB_TO_WIDE(dll)); #else p = GetProcAddress(lib, dll); #endif if (p == NULL) return false; *proc++ = (Function)p; } dll++; } return true; } void ShowOSErrorBox(const char *buf, bool system) { MyShowCursor(true); MessageBox(GetActiveWindow(), OTTD2FS(buf), _T("Error!"), MB_ICONSTOP); } void OSOpenBrowser(const char *url) { ShellExecute(GetActiveWindow(), _T("open"), OTTD2FS(url), NULL, NULL, SW_SHOWNORMAL); } /* Code below for windows version of opendir/readdir/closedir copied and * modified from Jan Wassenberg's GPL implementation posted over at * http://www.gamedev.net/community/forums/topic.asp?topic_id=364584&whichpage=1� */ struct DIR { HANDLE hFind; /* the dirent returned by readdir. * note: having only one global instance is not possible because * multiple independent opendir/readdir sequences must be supported. */ dirent ent; WIN32_FIND_DATA fd; /* since opendir calls FindFirstFile, we need a means of telling the * first call to readdir that we already have a file. * that's the case iff this is true */ bool at_first_entry; }; /* suballocator - satisfies most requests with a reusable static instance. * this avoids hundreds of alloc/free which would fragment the heap. * To guarantee concurrency, we fall back to malloc if the instance is * already in use (it's important to avoid surprises since this is such a * low-level routine). */ static DIR _global_dir; static LONG _global_dir_is_in_use = false; static inline DIR *dir_calloc() { DIR *d; if (InterlockedExchange(&_global_dir_is_in_use, true) == (LONG)true) { d = CallocT
(1); } else { d = &_global_dir; memset(d, 0, sizeof(*d)); } return d; } static inline void dir_free(DIR *d) { if (d == &_global_dir) { _global_dir_is_in_use = (LONG)false; } else { free(d); } } DIR *opendir(const TCHAR *path) { DIR *d; UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box DWORD fa = GetFileAttributes(path); if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) { d = dir_calloc(); if (d != NULL) { TCHAR search_path[MAX_PATH]; bool slash = path[_tcslen(path) - 1] == '\\'; /* build search path for FindFirstFile, try not to append additional slashes * as it throws Win9x off its groove for root directories */ _sntprintf(search_path, lengthof(search_path), _T("%s%s*"), path, slash ? _T("") : _T("\\")); *lastof(search_path) = '\0'; d->hFind = FindFirstFile(search_path, &d->fd); if (d->hFind != INVALID_HANDLE_VALUE || GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty d->ent.dir = d; d->at_first_entry = true; } else { dir_free(d); d = NULL; } } else { errno = ENOMEM; } } else { /* path not found or not a directory */ d = NULL; errno = ENOENT; } SetErrorMode(sem); // restore previous setting return d; } struct dirent *readdir(DIR *d) { DWORD prev_err = GetLastError(); // avoid polluting last error if (d->at_first_entry) { /* the directory was empty when opened */ if (d->hFind == INVALID_HANDLE_VALUE) return NULL; d->at_first_entry = false; } else if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err); return NULL; } /* This entry has passed all checks; return information about it. * (note: d_name is a pointer; see struct dirent definition) */ d->ent.d_name = d->fd.cFileName; return &d->ent; } int closedir(DIR *d) { FindClose(d->hFind); dir_free(d); return 0; } bool FiosIsRoot(const char *file) { return file[3] == '\0'; // C:\... } void FiosGetDrives() { #if defined(WINCE) /* WinCE only knows one drive: / */ FiosItem *fios = _fios_items.Append(); fios->type = FIOS_TYPE_DRIVE; fios->mtime = 0; seprintf(fios->name, lastof(fios->name), PATHSEP ""); strecpy(fios->title, fios->name, lastof(fios->title)); #else TCHAR drives[256]; const TCHAR *s; GetLogicalDriveStrings(lengthof(drives), drives); for (s = drives; *s != '\0';) { FiosItem *fios = _fios_items.Append(); fios->type = FIOS_TYPE_DRIVE; fios->mtime = 0; seprintf(fios->name, lastof(fios->name), "%c:", s[0] & 0xFF); strecpy(fios->title, fios->name, lastof(fios->title)); while (*s++ != '\0') { /* Nothing */ } } #endif } bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb) { /* hectonanoseconds between Windows and POSIX epoch */ static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL; const WIN32_FIND_DATA *fd = &ent->dir->fd; sb->st_size = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow; /* UTC FILETIME to seconds-since-1970 UTC * we just have to subtract POSIX epoch and scale down to units of seconds. * http://www.gamedev.net/community/forums/topic.asp?topic_id=294070&whichpage=1� * XXX - not entirely correct, since filetimes on FAT aren't UTC but local, * this won't entirely be correct, but we use the time only for comparison. */ sb->st_mtime = (time_t)((*(const uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7); sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG; return true; } bool FiosIsHiddenFile(const struct dirent *ent) { return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0; } bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) { UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box bool retval = false; TCHAR root[4]; DWORD spc, bps, nfc, tnc; _sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]); if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) { *tot = ((spc * bps) * (uint64)nfc); retval = true; } SetErrorMode(sem); // reset previous setting return retval; } static int ParseCommandLine(char *line, char **argv, int max_argc) { int n = 0; do { /* skip whitespace */ while (*line == ' ' || *line == '\t') line++; /* end? */ if (*line == '\0') break; /* special handling when quoted */ if (*line == '"') { argv[n++] = ++line; while (*line != '"') { if (*line == '\0') return n; line++; } } else { argv[n++] = line; while (*line != ' ' && *line != '\t') { if (*line == '\0') return n; line++; } } *line++ = '\0'; } while (n != max_argc); return n; } void CreateConsole() { #if defined(WINCE) /* WinCE doesn't support console stuff */ #else HANDLE hand; CONSOLE_SCREEN_BUFFER_INFO coninfo; if (_has_console) return; _has_console = true; AllocConsole(); hand = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hand, &coninfo); coninfo.dwSize.Y = 500; SetConsoleScreenBufferSize(hand, coninfo.dwSize); /* redirect unbuffered STDIN, STDOUT, STDERR to the console */ #if !defined(__CYGWIN__) /* Check if we can open a handle to STDOUT. */ int fd = _open_osfhandle((intptr_t)hand, _O_TEXT); if (fd == -1) { /* Free everything related to the console. */ FreeConsole(); _has_console = false; _close(fd); CloseHandle(hand); ShowInfo("Unable to open an output handle to the console. Check known-bugs.txt for details."); return; } *stdout = *_fdopen(fd, "w"); *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" ); *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" ); #else /* open_osfhandle is not in cygwin */ *stdout = *fdopen(1, "w" ); *stdin = *fdopen(0, "r" ); *stderr = *fdopen(2, "w" ); #endif setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); #endif } /** Temporary pointer to get the help message to the window */ static const char *_help_msg; /** Callback function to handle the window */ static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { char help_msg[8192]; const char *p = _help_msg; char *q = help_msg; while (q != lastof(help_msg) && *p != '\0') { if (*p == '\n') { *q++ = '\r'; if (q == lastof(help_msg)) { q[-1] = '\0'; break; } } *q++ = *p++; } *q = '\0'; /* We need to put the text in a separate buffer because the default * buffer in OTTD2FS might not be large enough (512 chars). */ TCHAR help_msg_buf[8192]; SetDlgItemText(wnd, 11, convert_to_fs(help_msg, help_msg_buf, lengthof(help_msg_buf))); SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE); } return TRUE; case WM_COMMAND: if (wParam == 12) ExitProcess(0); return TRUE; case WM_CLOSE: ExitProcess(0); } return FALSE; } void ShowInfo(const char *str) { if (_has_console) { fprintf(stderr, "%s\n", str); } else { bool old; ReleaseCapture(); _left_button_clicked = _left_button_down = false; old = MyShowCursor(true); if (strlen(str) > 2048) { /* The minimum length of the help message is 2048. Other messages sent via * ShowInfo are much shorter, or so long they need this way of displaying * them anyway. */ _help_msg = str; DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL, HelpDialogFunc); } else { /* We need to put the text in a separate buffer because the default * buffer in OTTD2FS might not be large enough (512 chars). */ TCHAR help_msg_buf[8192]; MessageBox(GetActiveWindow(), convert_to_fs(str, help_msg_buf, lengthof(help_msg_buf)), _T("OpenTTD"), MB_ICONINFORMATION | MB_OK); } MyShowCursor(old); } } #if defined(WINCE) int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) #else int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) #endif { int argc; char *argv[64]; // max 64 command line arguments CrashLog::InitialiseCrashLog(); #if defined(UNICODE) && !defined(WINCE) /* Check if a win9x user started the win32 version */ if (HasBit(GetVersion(), 31)) usererror("This version of OpenTTD doesn't run on windows 95/98/ME.\nPlease download the win9x binary and try again."); #endif /* Convert the command line to UTF-8. We need a dedicated buffer * for this because argv[] points into this buffer and this needs to * be available between subsequent calls to FS2OTTD(). */ char *cmdline = stredup(FS2OTTD(GetCommandLine())); #if defined(_DEBUG) CreateConsole(); #endif #if !defined(WINCE) _set_error_mode(_OUT_TO_MSGBOX); // force assertion output to messagebox #endif /* setup random seed to something quite random */ SetRandomSeed(GetTickCount()); argc = ParseCommandLine(cmdline, argv, lengthof(argv)); openttd_main(argc, argv); free(cmdline); return 0; } #if defined(WINCE) void GetCurrentDirectoryW(int length, wchar_t *path) { /* Get the name of this module */ GetModuleFileName(NULL, path, length); /* Remove the executable name, this we call CurrentDir */ wchar_t *pDest = wcsrchr(path, '\\'); if (pDest != NULL) { int result = pDest - path + 1; path[result] = '\0'; } } #endif char *getcwd(char *buf, size_t size) { #if defined(WINCE) TCHAR path[MAX_PATH]; GetModuleFileName(NULL, path, MAX_PATH); convert_from_fs(path, buf, size); /* GetModuleFileName returns dir with file, so remove everything behind latest '\\' */ char *p = strrchr(buf, '\\'); if (p != NULL) *p = '\0'; #else TCHAR path[MAX_PATH]; GetCurrentDirectory(MAX_PATH - 1, path); convert_from_fs(path, buf, size); #endif return buf; } void DetermineBasePaths(const char *exe) { char tmp[MAX_PATH]; TCHAR path[MAX_PATH]; #ifdef WITH_PERSONAL_DIR if (SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path))) { strecpy(tmp, FS2OTTD(path), lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); strecat(tmp, PERSONAL_DIR, lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_PERSONAL_DIR] = stredup(tmp); } else { _searchpaths[SP_PERSONAL_DIR] = NULL; } if (SUCCEEDED(OTTDSHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path))) { strecpy(tmp, FS2OTTD(path), lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); strecat(tmp, PERSONAL_DIR, lastof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_SHARED_DIR] = stredup(tmp); } else { _searchpaths[SP_SHARED_DIR] = NULL; } #else _searchpaths[SP_PERSONAL_DIR] = NULL; _searchpaths[SP_SHARED_DIR] = NULL; #endif /* Get the path to working directory of OpenTTD */ getcwd(tmp, lengthof(tmp)); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_WORKING_DIR] = stredup(tmp); if (!GetModuleFileName(NULL, path, lengthof(path))) { DEBUG(misc, 0, "GetModuleFileName failed (%lu)\n", GetLastError()); _searchpaths[SP_BINARY_DIR] = NULL; } else { TCHAR exec_dir[MAX_PATH]; _tcsncpy(path, convert_to_fs(exe, path, lengthof(path)), lengthof(path)); if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, NULL)) { DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError()); _searchpaths[SP_BINARY_DIR] = NULL; } else { strecpy(tmp, convert_from_fs(exec_dir, tmp, lengthof(tmp)), lastof(tmp)); char *s = strrchr(tmp, PATHSEPCHAR); *(s + 1) = '\0'; _searchpaths[SP_BINARY_DIR] = stredup(tmp); } } _searchpaths[SP_INSTALLATION_DIR] = NULL; _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL; } bool GetClipboardContents(char *buffer, const char *last) { HGLOBAL cbuf; const char *ptr; if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { OpenClipboard(NULL); cbuf = GetClipboardData(CF_UNICODETEXT); ptr = (const char*)GlobalLock(cbuf); int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (last - buffer) + 1, NULL, NULL); GlobalUnlock(cbuf); CloseClipboard(); if (out_len == 0) return false; #if !defined(UNICODE) } else if (IsClipboardFormatAvailable(CF_TEXT)) { OpenClipboard(NULL); cbuf = GetClipboardData(CF_TEXT); ptr = (const char*)GlobalLock(cbuf); strecpy(buffer, FS2OTTD(ptr), last); GlobalUnlock(cbuf); CloseClipboard(); #endif /* UNICODE */ } else { return false; } return true; } void CSleep(int milliseconds) { Sleep(milliseconds); } /** * Convert to OpenTTD's encoding from that of the local environment. * When the project is built in UNICODE, the system codepage is irrelevant and * the input string is wide. In ANSI mode, the string is in the * local codepage which we'll convert to wide-char, and then to UTF-8. * OpenTTD internal encoding is UTF8. * The returned value's contents can only be guaranteed until the next call to * this function. So if the value is needed for anything else, use convert_from_fs * @param name pointer to a valid string that will be converted (local, or wide) * @return pointer to the converted string; if failed string is of zero-length * @see the current code-page comes from video\win32_v.cpp, event-notification * WM_INPUTLANGCHANGE */ const char *FS2OTTD(const TCHAR *name) { static char utf8_buf[512]; return convert_from_fs(name, utf8_buf, lengthof(utf8_buf)); } /** * Convert from OpenTTD's encoding to that of the local environment. * When the project is built in UNICODE the system codepage is irrelevant and * the converted string is wide. In ANSI mode, the UTF8 string is converted * to multi-byte. * OpenTTD internal encoding is UTF8. * The returned value's contents can only be guaranteed until the next call to * this function. So if the value is needed for anything else, use convert_from_fs * @param name pointer to a valid string that will be converted (UTF8) * @param console_cp convert to the console encoding instead of the normal system encoding. * @return pointer to the converted string; if failed string is of zero-length */ const TCHAR *OTTD2FS(const char *name, bool console_cp) { static TCHAR system_buf[512]; return convert_to_fs(name, system_buf, lengthof(system_buf), console_cp); } /** * Convert to OpenTTD's encoding from that of the environment in * UNICODE. OpenTTD encoding is UTF8, local is wide * @param name pointer to a valid string that will be converted * @param utf8_buf pointer to a valid buffer that will receive the converted string * @param buflen length in characters of the receiving buffer * @return pointer to utf8_buf. If conversion fails the string is of zero-length */ char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen) { #if defined(UNICODE) const WCHAR *wide_buf = name; #else /* Convert string from the local codepage to UTF-16. */ int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0); if (wide_len == 0) { utf8_buf[0] = '\0'; return utf8_buf; } WCHAR *wide_buf = AllocaM(WCHAR, wide_len); MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len); #endif /* Convert UTF-16 string to UTF-8. */ int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (int)buflen, NULL, NULL); if (len == 0) utf8_buf[0] = '\0'; return utf8_buf; } /** * Convert from OpenTTD's encoding to that of the environment in * UNICODE. OpenTTD encoding is UTF8, local is wide * @param name pointer to a valid string that will be converted * @param utf16_buf pointer to a valid wide-char buffer that will receive the * converted string * @param buflen length in wide characters of the receiving buffer * @param console_cp convert to the console encoding instead of the normal system encoding. * @return pointer to utf16_buf. If conversion fails the string is of zero-length */ TCHAR *convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen, bool console_cp) { #if defined(UNICODE) int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (int)buflen); if (len == 0) system_buf[0] = '\0'; #else int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0); if (len == 0) { system_buf[0] = '\0'; return system_buf; } WCHAR *wide_buf = AllocaM(WCHAR, len); MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len); len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (int)buflen, NULL, NULL); if (len == 0) system_buf[0] = '\0'; #endif return system_buf; } /** * Our very own SHGetFolderPath function for support of windows operating * systems that don't have this function (eg Win9x, etc.). We try using the * native function, and if that doesn't exist we will try a more crude approach * of environment variables and hope for the best */ HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath) { static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL; static bool first_time = true; /* We only try to load the library one time; if it fails, it fails */ if (first_time) { #if defined(UNICODE) # define W(x) x "W" #else # define W(x) x "A" #endif /* The function lives in shell32.dll for all current Windows versions, but it first started to appear in SHFolder.dll. */ if (!LoadLibraryList((Function*)&SHGetFolderPath, "shell32.dll\0" W("SHGetFolderPath") "\0\0")) { if (!LoadLibraryList((Function*)&SHGetFolderPath, "SHFolder.dll\0" W("SHGetFolderPath") "\0\0")) { DEBUG(misc, 0, "Unable to load " W("SHGetFolderPath") "from either shell32.dll or SHFolder.dll"); } } #undef W first_time = false; } if (SHGetFolderPath != NULL) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath); /* SHGetFolderPath doesn't exist, try a more conservative approach, * eg environment variables. This is only included for legacy modes * MSDN says: that 'pszPath' is a "Pointer to a null-terminated string of * length MAX_PATH which will receive the path" so let's assume that * Windows 95 with Internet Explorer 5.0, Windows 98 with Internet Explorer 5.0, * Windows 98 Second Edition (SE), Windows NT 4.0 with Internet Explorer 5.0, * Windows NT 4.0 with Service Pack 4 (SP4) */ { DWORD ret; switch (csidl) { case CSIDL_FONTS: // Get the system font path, eg %WINDIR%\Fonts ret = GetEnvironmentVariable(_T("WINDIR"), pszPath, MAX_PATH); if (ret == 0) break; _tcsncat(pszPath, _T("\\Fonts"), MAX_PATH); return (HRESULT)0; case CSIDL_PERSONAL: case CSIDL_COMMON_DOCUMENTS: { HKEY key; if (RegOpenKeyEx(csidl == CSIDL_PERSONAL ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, REGSTR_PATH_SPECIAL_FOLDERS, 0, KEY_READ, &key) != ERROR_SUCCESS) break; DWORD len = MAX_PATH; ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T("Personal") : _T("Common Documents"), NULL, NULL, (LPBYTE)pszPath, &len); RegCloseKey(key); if (ret == ERROR_SUCCESS) return (HRESULT)0; break; } /* XXX - other types to go here when needed... */ } } return E_INVALIDARG; } /** Determine the current user's locale. */ const char *GetCurrentLocale(const char *) { char lang[9], country[9]; if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, lengthof(lang)) == 0 || GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, lengthof(country)) == 0) { /* Unable to retrieve the locale. */ return NULL; } /* Format it as 'en_us'. */ static char retbuf[6] = {lang[0], lang[1], '_', country[0], country[1], 0}; return retbuf; } uint GetCPUCoreCount() { SYSTEM_INFO info; GetSystemInfo(&info); return info.dwNumberOfProcessors; } openttd-1.5.3/src/os/windows/crashlog_win.cpp0000644000000000000000000005345112627373441020001 0ustar rootroot/* $Id: crashlog_win.cpp 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 crashlog_win.cpp Implementation of a crashlogger for Windows */ #include "../../stdafx.h" #include "../../crashlog.h" #include "win32.h" #include "../../core/alloc_func.hpp" #include "../../core/math_func.hpp" #include "../../string_func.h" #include "../../fileio_func.h" #include "../../strings_func.h" #include "../../gamelog.h" #include "../../saveload/saveload.h" #include "../../video/video_driver.hpp" #include #include #include "../../safeguards.h" static const uint MAX_SYMBOL_LEN = 512; static const uint MAX_FRAMES = 64; /* printf format specification for 32/64-bit addresses. */ #ifdef _M_AMD64 #define PRINTF_PTR "0x%016IX" #else #define PRINTF_PTR "0x%08X" #endif /** * Windows implementation for the crash logger. */ class CrashLogWindows : public CrashLog { /** Information about the encountered exception */ EXCEPTION_POINTERS *ep; /* virtual */ char *LogOSVersion(char *buffer, const char *last) const; /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const; /* virtual */ char *LogStacktrace(char *buffer, const char *last) const; /* virtual */ char *LogRegisters(char *buffer, const char *last) const; /* virtual */ char *LogModules(char *buffer, const char *last) const; public: #if defined(_MSC_VER) /* virtual */ int WriteCrashDump(char *filename, const char *filename_last) const; char *AppendDecodedStacktrace(char *buffer, const char *last) const; #else char *AppendDecodedStacktrace(char *buffer, const char *last) const { return buffer; } #endif /* _MSC_VER */ /** Buffer for the generated crash log */ char crashlog[65536]; /** Buffer for the filename of the crash log */ char crashlog_filename[MAX_PATH]; /** Buffer for the filename of the crash dump */ char crashdump_filename[MAX_PATH]; /** Buffer for the filename of the crash screenshot */ char screenshot_filename[MAX_PATH]; /** * A crash log is always generated when it's generated. * @param ep the data related to the exception. */ CrashLogWindows(EXCEPTION_POINTERS *ep = NULL) : ep(ep) { this->crashlog[0] = '\0'; this->crashlog_filename[0] = '\0'; this->crashdump_filename[0] = '\0'; this->screenshot_filename[0] = '\0'; } /** * Points to the current crash log. */ static CrashLogWindows *current; }; /* static */ CrashLogWindows *CrashLogWindows::current = NULL; /* virtual */ char *CrashLogWindows::LogOSVersion(char *buffer, const char *last) const { _OSVERSIONINFOA os; os.dwOSVersionInfoSize = sizeof(os); GetVersionExA(&os); return buffer + seprintf(buffer, last, "Operating system:\n" " Name: Windows\n" " Release: %d.%d.%d (%s)\n", (int)os.dwMajorVersion, (int)os.dwMinorVersion, (int)os.dwBuildNumber, os.szCSDVersion ); } /* virtual */ char *CrashLogWindows::LogError(char *buffer, const char *last, const char *message) const { return buffer + seprintf(buffer, last, "Crash reason:\n" " Exception: %.8X\n" #ifdef _M_AMD64 " Location: %.16IX\n" #else " Location: %.8X\n" #endif " Message: %s\n\n", (int)ep->ExceptionRecord->ExceptionCode, (size_t)ep->ExceptionRecord->ExceptionAddress, message == NULL ? "" : message ); } struct DebugFileInfo { uint32 size; uint32 crc32; SYSTEMTIME file_time; }; static uint32 *_crc_table; static void MakeCRCTable(uint32 *table) { uint32 crc, poly = 0xEDB88320L; int i; int j; _crc_table = table; for (i = 0; i != 256; i++) { crc = i; for (j = 8; j != 0; j--) { crc = (crc & 1 ? (crc >> 1) ^ poly : crc >> 1); } table[i] = crc; } } static uint32 CalcCRC(byte *data, uint size, uint32 crc) { for (; size > 0; size--) { crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF]; } return crc; } static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename) { HANDLE file; memset(dfi, 0, sizeof(*dfi)); file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0); if (file != INVALID_HANDLE_VALUE) { byte buffer[1024]; DWORD numread; uint32 filesize = 0; FILETIME write_time; uint32 crc = (uint32)-1; for (;;) { if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 || numread == 0) { break; } filesize += numread; crc = CalcCRC(buffer, numread, crc); } dfi->size = filesize; dfi->crc32 = crc ^ (uint32)-1; if (GetFileTime(file, NULL, NULL, &write_time)) { FileTimeToSystemTime(&write_time, &dfi->file_time); } CloseHandle(file); } } static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) { TCHAR buffer[MAX_PATH]; DebugFileInfo dfi; GetModuleFileName(mod, buffer, MAX_PATH); GetFileInfo(&dfi, buffer); output += seprintf(output, last, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n", FS2OTTD(buffer), mod, dfi.size, dfi.crc32, dfi.file_time.wYear, dfi.file_time.wMonth, dfi.file_time.wDay, dfi.file_time.wHour, dfi.file_time.wMinute, dfi.file_time.wSecond ); return output; } /* virtual */ char *CrashLogWindows::LogModules(char *output, const char *last) const { MakeCRCTable(AllocaM(uint32, 256)); BOOL (WINAPI *EnumProcessModules)(HANDLE, HMODULE*, DWORD, LPDWORD); output += seprintf(output, last, "Module information:\n"); if (LoadLibraryList((Function*)&EnumProcessModules, "psapi.dll\0EnumProcessModules\0\0")) { HMODULE modules[100]; DWORD needed; BOOL res; HANDLE proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); if (proc != NULL) { res = EnumProcessModules(proc, modules, sizeof(modules), &needed); CloseHandle(proc); if (res) { size_t count = min(needed / sizeof(HMODULE), lengthof(modules)); for (size_t i = 0; i != count; i++) output = PrintModuleInfo(output, last, modules[i]); return output + seprintf(output, last, "\n"); } } } output = PrintModuleInfo(output, last, NULL); return output + seprintf(output, last, "\n"); } /* virtual */ char *CrashLogWindows::LogRegisters(char *buffer, const char *last) const { buffer += seprintf(buffer, last, "Registers:\n"); #ifdef _M_AMD64 buffer += seprintf(buffer, last, " RAX: %.16I64X RBX: %.16I64X RCX: %.16I64X RDX: %.16I64X\n" " RSI: %.16I64X RDI: %.16I64X RBP: %.16I64X RSP: %.16I64X\n" " R8: %.16I64X R9: %.16I64X R10: %.16I64X R11: %.16I64X\n" " R12: %.16I64X R13: %.16I64X R14: %.16I64X R15: %.16I64X\n" " RIP: %.16I64X EFLAGS: %.8lX\n", ep->ContextRecord->Rax, ep->ContextRecord->Rbx, ep->ContextRecord->Rcx, ep->ContextRecord->Rdx, ep->ContextRecord->Rsi, ep->ContextRecord->Rdi, ep->ContextRecord->Rbp, ep->ContextRecord->Rsp, ep->ContextRecord->R8, ep->ContextRecord->R9, ep->ContextRecord->R10, ep->ContextRecord->R11, ep->ContextRecord->R12, ep->ContextRecord->R13, ep->ContextRecord->R14, ep->ContextRecord->R15, ep->ContextRecord->Rip, ep->ContextRecord->EFlags ); #else buffer += seprintf(buffer, last, " EAX: %.8X EBX: %.8X ECX: %.8X EDX: %.8X\n" " ESI: %.8X EDI: %.8X EBP: %.8X ESP: %.8X\n" " EIP: %.8X EFLAGS: %.8X\n", (int)ep->ContextRecord->Eax, (int)ep->ContextRecord->Ebx, (int)ep->ContextRecord->Ecx, (int)ep->ContextRecord->Edx, (int)ep->ContextRecord->Esi, (int)ep->ContextRecord->Edi, (int)ep->ContextRecord->Ebp, (int)ep->ContextRecord->Esp, (int)ep->ContextRecord->Eip, (int)ep->ContextRecord->EFlags ); #endif buffer += seprintf(buffer, last, "\n Bytes at instruction pointer:\n"); #ifdef _M_AMD64 byte *b = (byte*)ep->ContextRecord->Rip; #else byte *b = (byte*)ep->ContextRecord->Eip; #endif for (int i = 0; i != 24; i++) { if (IsBadReadPtr(b, 1)) { buffer += seprintf(buffer, last, " ??"); // OCR: WAS: , 0); } else { buffer += seprintf(buffer, last, " %.2X", *b); } b++; } return buffer + seprintf(buffer, last, "\n\n"); } /* virtual */ char *CrashLogWindows::LogStacktrace(char *buffer, const char *last) const { buffer += seprintf(buffer, last, "Stack trace:\n"); #ifdef _M_AMD64 uint32 *b = (uint32*)ep->ContextRecord->Rsp; #else uint32 *b = (uint32*)ep->ContextRecord->Esp; #endif for (int j = 0; j != 24; j++) { for (int i = 0; i != 8; i++) { if (IsBadReadPtr(b, sizeof(uint32))) { buffer += seprintf(buffer, last, " ????????"); // OCR: WAS - , 0); } else { buffer += seprintf(buffer, last, " %.8X", *b); } b++; } buffer += seprintf(buffer, last, "\n"); } return buffer + seprintf(buffer, last, "\n"); } #if defined(_MSC_VER) #include char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) const { #define M(x) x "\0" static const char dbg_import[] = M("dbghelp.dll") M("SymInitialize") M("SymSetOptions") M("SymCleanup") M("StackWalk64") M("SymFunctionTableAccess64") M("SymGetModuleBase64") M("SymGetModuleInfo64") M("SymGetSymFromAddr64") M("SymGetLineFromAddr64") M("") ; #undef M struct ProcPtrs { BOOL (WINAPI * pSymInitialize)(HANDLE, PCSTR, BOOL); BOOL (WINAPI * pSymSetOptions)(DWORD); BOOL (WINAPI * pSymCleanup)(HANDLE); BOOL (WINAPI * pStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, PFUNCTION_TABLE_ACCESS_ROUTINE64, PGET_MODULE_BASE_ROUTINE64, PTRANSLATE_ADDRESS_ROUTINE64); PVOID (WINAPI * pSymFunctionTableAccess64)(HANDLE, DWORD64); DWORD64 (WINAPI * pSymGetModuleBase64)(HANDLE, DWORD64); BOOL (WINAPI * pSymGetModuleInfo64)(HANDLE, DWORD64, PIMAGEHLP_MODULE64); BOOL (WINAPI * pSymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64); BOOL (WINAPI * pSymGetLineFromAddr64)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64); } proc; buffer += seprintf(buffer, last, "\nDecoded stack trace:\n"); /* Try to load the functions from the DLL, if that fails because of a too old dbghelp.dll, just skip it. */ if (LoadLibraryList((Function*)&proc, dbg_import)) { /* Initialize symbol handler. */ HANDLE hCur = GetCurrentProcess(); proc.pSymInitialize(hCur, NULL, TRUE); /* Load symbols only when needed, fail silently on errors, demangle symbol names. */ proc.pSymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_UNDNAME); /* Initialize starting stack frame from context record. */ STACKFRAME64 frame; memset(&frame, 0, sizeof(frame)); #ifdef _M_AMD64 frame.AddrPC.Offset = ep->ContextRecord->Rip; frame.AddrFrame.Offset = ep->ContextRecord->Rbp; frame.AddrStack.Offset = ep->ContextRecord->Rsp; #else frame.AddrPC.Offset = ep->ContextRecord->Eip; frame.AddrFrame.Offset = ep->ContextRecord->Ebp; frame.AddrStack.Offset = ep->ContextRecord->Esp; #endif frame.AddrPC.Mode = AddrModeFlat; frame.AddrFrame.Mode = AddrModeFlat; frame.AddrStack.Mode = AddrModeFlat; /* Copy context record as StackWalk64 may modify it. */ CONTEXT ctx; memcpy(&ctx, ep->ContextRecord, sizeof(ctx)); /* Allocate space for symbol info. */ IMAGEHLP_SYMBOL64 *sym_info = (IMAGEHLP_SYMBOL64*)alloca(sizeof(IMAGEHLP_SYMBOL64) + MAX_SYMBOL_LEN - 1); sym_info->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); sym_info->MaxNameLength = MAX_SYMBOL_LEN; /* Walk stack at most MAX_FRAMES deep in case the stack is corrupt. */ for (uint num = 0; num < MAX_FRAMES; num++) { if (!proc.pStackWalk64( #ifdef _M_AMD64 IMAGE_FILE_MACHINE_AMD64, #else IMAGE_FILE_MACHINE_I386, #endif hCur, GetCurrentThread(), &frame, &ctx, NULL, proc.pSymFunctionTableAccess64, proc.pSymGetModuleBase64, NULL)) break; if (frame.AddrPC.Offset == frame.AddrReturn.Offset) { buffer += seprintf(buffer, last, " \n"); break; } /* Get module name. */ const char *mod_name = "???"; IMAGEHLP_MODULE64 module; module.SizeOfStruct = sizeof(module); if (proc.pSymGetModuleInfo64(hCur, frame.AddrPC.Offset, &module)) { mod_name = module.ModuleName; } /* Print module and instruction pointer. */ buffer += seprintf(buffer, last, "[%02d] %-20s " PRINTF_PTR, num, mod_name, frame.AddrPC.Offset); /* Get symbol name and line info if possible. */ DWORD64 offset; if (proc.pSymGetSymFromAddr64(hCur, frame.AddrPC.Offset, &offset, sym_info)) { buffer += seprintf(buffer, last, " %s + %I64u", sym_info->Name, offset); DWORD line_offs; IMAGEHLP_LINE64 line; line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); if (proc.pSymGetLineFromAddr64(hCur, frame.AddrPC.Offset, &line_offs, &line)) { buffer += seprintf(buffer, last, " (%s:%d)", line.FileName, line.LineNumber); } } buffer += seprintf(buffer, last, "\n"); } proc.pSymCleanup(hCur); } return buffer + seprintf(buffer, last, "\n*** End of additional info ***\n"); } /* virtual */ int CrashLogWindows::WriteCrashDump(char *filename, const char *filename_last) const { int ret = 0; HMODULE dbghelp = LoadLibrary(_T("dbghelp.dll")); if (dbghelp != NULL) { typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, CONST PMINIDUMP_EXCEPTION_INFORMATION, CONST PMINIDUMP_USER_STREAM_INFORMATION, CONST PMINIDUMP_CALLBACK_INFORMATION); MiniDumpWriteDump_t funcMiniDumpWriteDump = (MiniDumpWriteDump_t)GetProcAddress(dbghelp, "MiniDumpWriteDump"); if (funcMiniDumpWriteDump != NULL) { seprintf(filename, filename_last, "%scrash.dmp", _personal_dir); HANDLE file = CreateFile(OTTD2FS(filename), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); HANDLE proc = GetCurrentProcess(); DWORD procid = GetCurrentProcessId(); MINIDUMP_EXCEPTION_INFORMATION mdei; MINIDUMP_USER_STREAM userstream; MINIDUMP_USER_STREAM_INFORMATION musi; userstream.Type = LastReservedStream + 1; userstream.Buffer = (void*)this->crashlog; userstream.BufferSize = (ULONG)strlen(this->crashlog) + 1; musi.UserStreamCount = 1; musi.UserStreamArray = &userstream; mdei.ThreadId = GetCurrentThreadId(); mdei.ExceptionPointers = ep; mdei.ClientPointers = false; funcMiniDumpWriteDump(proc, procid, file, MiniDumpWithDataSegs, &mdei, &musi, NULL); ret = 1; } else { ret = -1; } FreeLibrary(dbghelp); } return ret; } #endif /* _MSC_VER */ extern bool CloseConsoleLogIfActive(); static void ShowCrashlogWindow(); /** * Stack pointer for use when 'starting' the crash handler. * Not static as gcc's inline assembly needs it that way. */ void *_safe_esp = NULL; static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep) { if (CrashLogWindows::current != NULL) { CrashLog::AfterCrashLogCleanup(); ExitProcess(2); } if (GamelogTestEmergency()) { static const TCHAR _emergency_crash[] = _T("A serious fault condition occurred in the game. The game will shut down.\n") _T("As you loaded an emergency savegame no crash information will be generated.\n"); MessageBox(NULL, _emergency_crash, _T("Fatal Application Failure"), MB_ICONERROR); ExitProcess(3); } if (SaveloadCrashWithMissingNewGRFs()) { static const TCHAR _saveload_crash[] = _T("A serious fault condition occurred in the game. The game will shut down.\n") _T("As you loaded an savegame for which you do not have the required NewGRFs\n") _T("no crash information will be generated.\n"); MessageBox(NULL, _saveload_crash, _T("Fatal Application Failure"), MB_ICONERROR); ExitProcess(3); } CrashLogWindows *log = new CrashLogWindows(ep); CrashLogWindows::current = log; char *buf = log->FillCrashLog(log->crashlog, lastof(log->crashlog)); log->WriteCrashDump(log->crashdump_filename, lastof(log->crashdump_filename)); log->AppendDecodedStacktrace(buf, lastof(log->crashlog)); log->WriteCrashLog(log->crashlog, log->crashlog_filename, lastof(log->crashlog_filename)); log->WriteScreenshot(log->screenshot_filename, lastof(log->screenshot_filename)); /* Close any possible log files */ CloseConsoleLogIfActive(); if ((VideoDriver::GetInstance() == NULL || VideoDriver::GetInstance()->HasGUI()) && _safe_esp != NULL) { #ifdef _M_AMD64 ep->ContextRecord->Rip = (DWORD64)ShowCrashlogWindow; ep->ContextRecord->Rsp = (DWORD64)_safe_esp; #else ep->ContextRecord->Eip = (DWORD)ShowCrashlogWindow; ep->ContextRecord->Esp = (DWORD)_safe_esp; #endif return EXCEPTION_CONTINUE_EXECUTION; } CrashLog::AfterCrashLogCleanup(); return EXCEPTION_EXECUTE_HANDLER; } static void CDECL CustomAbort(int signal) { RaiseException(0xE1212012, 0, 0, NULL); } /* static */ void CrashLog::InitialiseCrashLog() { #ifdef _M_AMD64 CONTEXT ctx; RtlCaptureContext(&ctx); /* The stack pointer for AMD64 must always be 16-byte aligned inside a * function. As we are simulating a function call with the safe ESP value, * we need to subtract 8 for the imaginary return address otherwise stack * alignment would be wrong in the called function. */ _safe_esp = (void *)(ctx.Rsp - 8); #else #if defined(_MSC_VER) _asm { mov _safe_esp, esp } #else asm("movl %esp, __safe_esp"); #endif #endif /* SIGABRT is not an unhandled exception, so we need to intercept it. */ signal(SIGABRT, CustomAbort); #if defined(_MSC_VER) /* Don't show abort message as we will get the crashlog window anyway. */ _set_abort_behavior(0, _WRITE_ABORT_MSG); #endif SetUnhandledExceptionFilter(ExceptionHandler); } /* The crash log GUI */ static bool _expanded; static const TCHAR _crash_desc[] = _T("A serious fault condition occurred in the game. The game will shut down.\n") _T("Please send the crash information and the crash.dmp file (if any) to the developers.\n") _T("This will greatly help debugging. The correct place to do this is http://bugs.openttd.org. ") _T("The information contained in the report is displayed below.\n") _T("Press \"Emergency save\" to attempt saving the game. Generated file(s):\n") _T("%s"); static const TCHAR _save_succeeded[] = _T("Emergency save succeeded.\nIts location is '%s'.\n") _T("Be aware that critical parts of the internal game state may have become ") _T("corrupted. The saved game is not guaranteed to work."); static const TCHAR * const _expand_texts[] = {_T("S&how report >>"), _T("&Hide report <<") }; static void SetWndSize(HWND wnd, int mode) { RECT r, r2; GetWindowRect(wnd, &r); SetDlgItemText(wnd, 15, _expand_texts[mode == 1]); if (mode >= 0) { GetWindowRect(GetDlgItem(wnd, 11), &r2); int offs = r2.bottom - r2.top + 10; if (mode == 0) offs = -offs; SetWindowPos(wnd, HWND_TOPMOST, 0, 0, r.right - r.left, r.bottom - r.top + offs, SWP_NOMOVE | SWP_NOZORDER); } else { SetWindowPos(wnd, HWND_TOPMOST, (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2, (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2, 0, 0, SWP_NOSIZE); } } /* When TCHAR is char, then _sntprintf becomes snprintf. When TCHAR is wchar it doesn't. Likewise for strcat. */ #undef snprintf #undef strcat static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { /* We need to put the crash-log in a separate buffer because the default * buffer in MB_TO_WIDE is not large enough (512 chars) */ TCHAR crash_msgW[lengthof(CrashLogWindows::current->crashlog)]; /* Convert unix -> dos newlines because the edit box only supports that properly :( */ const char *unix_nl = CrashLogWindows::current->crashlog; char dos_nl[lengthof(CrashLogWindows::current->crashlog)]; char *p = dos_nl; WChar c; while ((c = Utf8Consume(&unix_nl)) && p < lastof(dos_nl) - 4) { // 4 is max number of bytes per character if (c == '\n') p += Utf8Encode(p, '\r'); p += Utf8Encode(p, c); } *p = '\0'; /* Add path to crash.log and crash.dmp (if any) to the crash window text */ size_t len = _tcslen(_crash_desc) + 2; len += _tcslen(OTTD2FS(CrashLogWindows::current->crashlog_filename)) + 2; len += _tcslen(OTTD2FS(CrashLogWindows::current->crashdump_filename)) + 2; len += _tcslen(OTTD2FS(CrashLogWindows::current->screenshot_filename)) + 1; TCHAR *text = AllocaM(TCHAR, len); _sntprintf(text, len, _crash_desc, OTTD2FS(CrashLogWindows::current->crashlog_filename)); if (OTTD2FS(CrashLogWindows::current->crashdump_filename)[0] != _T('\0')) { _tcscat(text, _T("\n")); _tcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename)); } if (OTTD2FS(CrashLogWindows::current->screenshot_filename)[0] != _T('\0')) { _tcscat(text, _T("\n")); _tcscat(text, OTTD2FS(CrashLogWindows::current->screenshot_filename)); } SetDlgItemText(wnd, 10, text); SetDlgItemText(wnd, 11, convert_to_fs(dos_nl, crash_msgW, lengthof(crash_msgW))); SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE); SetWndSize(wnd, -1); } return TRUE; case WM_COMMAND: switch (wParam) { case 12: // Close CrashLog::AfterCrashLogCleanup(); ExitProcess(2); case 13: // Emergency save char filename[MAX_PATH]; if (CrashLogWindows::current->WriteSavegame(filename, lastof(filename))) { size_t len = _tcslen(_save_succeeded) + _tcslen(OTTD2FS(filename)) + 1; TCHAR *text = AllocaM(TCHAR, len); _sntprintf(text, len, _save_succeeded, OTTD2FS(filename)); MessageBox(wnd, text, _T("Save successful"), MB_ICONINFORMATION); } else { MessageBox(wnd, _T("Save failed"), _T("Save failed"), MB_ICONINFORMATION); } break; case 15: // Expand window to show crash-message _expanded ^= 1; SetWndSize(wnd, _expanded); break; } return TRUE; case WM_CLOSE: CrashLog::AfterCrashLogCleanup(); ExitProcess(2); } return FALSE; } static void ShowCrashlogWindow() { ShowCursor(TRUE); ShowWindow(GetActiveWindow(), FALSE); DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(100), NULL, CrashDialogFunc); } openttd-1.5.3/src/os/windows/win32.h0000644000000000000000000000325312627373441015724 0ustar rootroot/* $Id: win32.h 27176 2015-03-02 09:10:16Z planetmaker $ */ /* * 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 win32.h declarations of functions for MS windows systems */ #ifndef WIN32_H #define WIN32_H #include bool MyShowCursor(bool show, bool toggle = false); typedef void (*Function)(int); bool LoadLibraryList(Function proc[], const char *dll); char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen); TCHAR *convert_to_fs(const char *name, TCHAR *utf16_buf, size_t buflen, bool console_cp = false); /* Function shortcuts for UTF-8 <> UNICODE conversion. When unicode is not * defined these macros return the string passed to them, with UNICODE * they return a pointer to the converted string. These functions use an * internal buffer of max 512 characters. */ #if defined(UNICODE) # define MB_TO_WIDE(str) OTTD2FS(str) # define WIDE_TO_MB(str) FS2OTTD(str) #else # define MB_TO_WIDE(str) (str) # define WIDE_TO_MB(str) (str) #endif HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR); #if defined(__MINGW32__) && !defined(__MINGW64__) #define SHGFP_TYPE_CURRENT 0 #endif /* __MINGW32__ */ #endif /* WIN32_H */ openttd-1.5.3/src/os/windows/ottdres.rc.in0000644000000000000000000000772412627373441017237 0ustar rootroot//Microsoft Developer Studio generated resource script. // $Id: ottdres.rc.in 27462 2015-12-01 19:36:48Z frosch $ // // 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 . // ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #define APSTUDIO_READONLY_SYMBOLS #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS #ifdef MSVC #include "winres.h" #else #define IDC_STATIC (-1) // all static controls #endif ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // Neutral (Default) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) #ifdef _WIN32 LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. 100 ICON DISCARDABLE "../../../media/openttd.ico" ///////////////////////////////////////////////////////////////////////////// // // Dialog // 100 DIALOG DISCARDABLE 0, 0, 305, 99 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Fatal Application Failure" FONT 8, "MS Sans Serif" BEGIN PUSHBUTTON "&Close",12,7,80,50,14 PUSHBUTTON "&Emergency save",13,155,80,68,14 PUSHBUTTON "",15,243,80,55,14 EDITTEXT 11,7,101,291,118,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL | NOT WS_TABSTOP LTEXT "",10,36,7,262,65 ICON 100,IDC_STATIC,9,9,20,20 END 101 DIALOG DISCARDABLE 0, 0, 600, 400 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "OpenTTD command line help" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "&OK",12,274,378,50,14,BS_CENTER EDITTEXT 11,7,6,583,365,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,5,3,!!REVISION!! PRODUCTVERSION 1,5,3,!!REVISION!! FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "000004b0" BEGIN VALUE "Comments", "This program is licensed under the GNU General Public License version 2.\0" VALUE "CompanyName", "OpenTTD Development Team\0" VALUE "FileDescription", "OpenTTD\0" VALUE "FileVersion", "!!VERSION!!\0" VALUE "InternalName", "openttd\0" VALUE "LegalCopyright", "Copyright \xA9 OpenTTD Developers 2002-2015. All Rights Reserved.\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "openttd.exe\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "OpenTTD\0" VALUE "ProductVersion", "!!VERSION!!\0" VALUE "SpecialBuild", "-\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x0, 1200 END END #endif // !_MAC #endif // Neutral (Default) resources ///////////////////////////////////////////////////////////////////////////// openttd-1.5.3/src/os/os2/0000755000000000000000000000000012627373441013617 5ustar rootrootopenttd-1.5.3/src/os/os2/os2.cpp0000644000000000000000000001141312627373441015026 0ustar rootroot/* $Id: os2.cpp 27092 2014-12-24 17:17:18Z frosch $ */ /* * 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 os2.cpp OS2 related OS support. */ #include "../../stdafx.h" #include "../../openttd.h" #include "../../gui.h" #include "../../fileio_func.h" #include "../../fios.h" #include "../../openttd.h" #include "../../core/random_func.hpp" #include "../../string_func.h" #include "../../textbuf_gui.h" #include "table/strings.h" #include #include #include #include #include #ifndef __INNOTEK_LIBC__ #include #endif #include "../../safeguards.h" #define INCL_WIN #define INCL_WINCLIPBOARD #include #ifndef __INNOTEK_LIBC__ #include #endif bool FiosIsRoot(const char *file) { return file[3] == '\0'; } void FiosGetDrives() { uint disk, disk2, save, total; #ifndef __INNOTEK_LIBC__ _dos_getdrive(&save); // save original drive #else save = _getdrive(); // save original drive char wd[MAX_PATH]; getcwd(wd, MAX_PATH); total = 'z'; #endif /* get an available drive letter */ #ifndef __INNOTEK_LIBC__ for (disk = 1;; disk++) { _dos_setdrive(disk, &total); #else for (disk = 'A';; disk++) { _chdrive(disk); #endif if (disk >= total) break; #ifndef __INNOTEK_LIBC__ _dos_getdrive(&disk2); #else disk2 = _getdrive(); #endif if (disk == disk2) { FiosItem *fios = _fios_items.Append(); fios->type = FIOS_TYPE_DRIVE; fios->mtime = 0; #ifndef __INNOTEK_LIBC__ snprintf(fios->name, lengthof(fios->name), "%c:", 'A' + disk - 1); #else snprintf(fios->name, lengthof(fios->name), "%c:", disk); #endif strecpy(fios->title, fios->name, lastof(fios->title)); } } /* Restore the original drive */ #ifndef __INNOTEK_LIBC__ _dos_setdrive(save, &total); #else chdir(wd); #endif } bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) { #ifndef __INNOTEK_LIBC__ struct diskfree_t free; char drive = path[0] - 'A' + 1; if (tot != NULL && _getdiskfree(drive, &free) == 0) { *tot = free.avail_clusters * free.sectors_per_cluster * free.bytes_per_sector; return true; } return false; #else uint64 free = 0; #ifdef HAS_STATVFS { struct statvfs s; if (statvfs(path, &s) != 0) return false; free = (uint64)s.f_frsize * s.f_bavail; } #endif if (tot != NULL) *tot = free; return true; #endif } bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb) { char filename[MAX_PATH]; snprintf(filename, lengthof(filename), "%s" PATHSEP "%s", path, ent->d_name); return stat(filename, sb) == 0; } bool FiosIsHiddenFile(const struct dirent *ent) { return ent->d_name[0] == '.'; } void ShowInfo(const char *str) { HAB hab; HMQ hmq; ULONG rc; /* init PM env. */ hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0); /* display the box */ rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (const unsigned char *)str, (const unsigned char *)"OpenTTD", 0, MB_OK | MB_MOVEABLE | MB_INFORMATION); /* terminate PM env. */ WinDestroyMsgQueue(hmq); WinTerminate(hab); } void ShowOSErrorBox(const char *buf, bool system) { HAB hab; HMQ hmq; ULONG rc; /* init PM env. */ hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0); /* display the box */ rc = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, (const unsigned char *)buf, (const unsigned char *)"OpenTTD", 0, MB_OK | MB_MOVEABLE | MB_ERROR); /* terminate PM env. */ WinDestroyMsgQueue(hmq); WinTerminate(hab); } int CDECL main(int argc, char *argv[]) { SetRandomSeed(time(NULL)); return openttd_main(argc, argv); } bool GetClipboardContents(char *buffer, const char *last) { /* XXX -- Currently no clipboard support implemented with GCC */ #ifndef __INNOTEK_LIBC__ HAB hab = 0; if (WinOpenClipbrd(hab)) { const char *text = (const char*)WinQueryClipbrdData(hab, CF_TEXT); if (text != NULL) { strecpy(buffer, text, last); WinCloseClipbrd(hab); return true; } WinCloseClipbrd(hab); } #endif return false; } void CSleep(int milliseconds) { #ifndef __INNOTEK_LIBC__ delay(milliseconds); #else usleep(milliseconds * 1000); #endif } const char *FS2OTTD(const char *name) {return name;} const char *OTTD2FS(const char *name) {return name;} uint GetCPUCoreCount() { return 1; } void OSOpenBrowser(const char *url) { // stub only DEBUG(misc, 0, "Failed to open url: %s", url); } openttd-1.5.3/src/os/unix/0000755000000000000000000000000012627373441014077 5ustar rootrootopenttd-1.5.3/src/os/unix/crashlog_unix.cpp0000644000000000000000000001241412627373441017452 0ustar rootroot/* $Id: crashlog_unix.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 crashlog_unix.cpp Unix crash log handler */ #include "../../stdafx.h" #include "../../crashlog.h" #include "../../string_func.h" #include "../../gamelog.h" #include "../../saveload/saveload.h" #include #include #include #if defined(__GLIBC__) /* Execinfo (and thus making stacktraces) is a GNU extension */ # include #elif defined(SUNOS) # include # include #endif #if defined(__NetBSD__) #include #endif #include "../../safeguards.h" /** * Unix implementation for the crash logger. */ class CrashLogUnix : public CrashLog { /** Signal that has been thrown. */ int signum; /* virtual */ char *LogOSVersion(char *buffer, const char *last) const { struct utsname name; if (uname(&name) < 0) { return buffer + seprintf(buffer, last, "Could not get OS version: %s\n", strerror(errno)); } return buffer + seprintf(buffer, last, "Operating system:\n" " Name: %s\n" " Release: %s\n" " Version: %s\n" " Machine: %s\n", name.sysname, name.release, name.version, name.machine ); } /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const { return buffer + seprintf(buffer, last, "Crash reason:\n" " Signal: %s (%d)\n" " Message: %s\n\n", strsignal(this->signum), this->signum, message == NULL ? "" : message ); } #if defined(SUNOS) /** Data needed while walking up the stack */ struct StackWalkerParams { char **bufptr; ///< Buffer const char *last; ///< End of buffer int counter; ///< We are at counter-th stack level }; /** * Callback used while walking up the stack. * @param pc program counter * @param sig 'active' signal (unused) * @param params parameters * @return always 0, continue walking up the stack */ static int SunOSStackWalker(uintptr_t pc, int sig, void *params) { StackWalkerParams *wp = (StackWalkerParams *)params; /* Resolve program counter to file and nearest symbol (if possible) */ Dl_info dli; if (dladdr((void *)pc, &dli) != 0) { *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] %s(%s+0x%x) [0x%x]\n", wp->counter, dli.dli_fname, dli.dli_sname, (int)((byte *)pc - (byte *)dli.dli_saddr), (uint)pc); } else { *wp->bufptr += seprintf(*wp->bufptr, wp->last, " [%02i] [0x%x]\n", wp->counter, (uint)pc); } wp->counter++; return 0; } #endif /* virtual */ char *LogStacktrace(char *buffer, const char *last) const { buffer += seprintf(buffer, last, "Stacktrace:\n"); #if defined(__GLIBC__) void *trace[64]; int trace_size = backtrace(trace, lengthof(trace)); char **messages = backtrace_symbols(trace, trace_size); for (int i = 0; i < trace_size; i++) { buffer += seprintf(buffer, last, " [%02i] %s\n", i, messages[i]); } free(messages); #elif defined(SUNOS) ucontext_t uc; if (getcontext(&uc) != 0) { buffer += seprintf(buffer, last, " getcontext() failed\n\n"); return buffer; } StackWalkerParams wp = { &buffer, last, 0 }; walkcontext(&uc, &CrashLogUnix::SunOSStackWalker, &wp); #else buffer += seprintf(buffer, last, " Not supported.\n"); #endif return buffer + seprintf(buffer, last, "\n"); } public: /** * A crash log is always generated by signal. * @param signum the signal that was caused by the crash. */ CrashLogUnix(int signum) : signum(signum) { } }; /** The signals we want our crash handler to handle. */ static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL }; /** * Entry point for the crash handler. * @note Not static so it shows up in the backtrace. * @param signum the signal that caused us to crash. */ static void CDECL HandleCrash(int signum) { /* Disable all handling of signals by us, so we don't go into infinite loops. */ for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) { signal(*i, SIG_DFL); } if (GamelogTestEmergency()) { printf("A serious fault condition occurred in the game. The game will shut down.\n"); printf("As you loaded an emergency savegame no crash information will be generated.\n"); abort(); } if (SaveloadCrashWithMissingNewGRFs()) { printf("A serious fault condition occurred in the game. The game will shut down.\n"); printf("As you loaded an savegame for which you do not have the required NewGRFs\n"); printf("no crash information will be generated.\n"); abort(); } CrashLogUnix log(signum); log.MakeCrashLog(); CrashLog::AfterCrashLogCleanup(); abort(); } /* static */ void CrashLog::InitialiseCrashLog() { for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) { signal(*i, HandleCrash); } } openttd-1.5.3/src/os/unix/unix.cpp0000644000000000000000000002222112627373441015565 0ustar rootroot/* $Id: unix.cpp 26724 2014-08-09 19:39:14Z alberth $ */ /* * 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 unix.cpp Implementation of Unix specific file handling. */ #include "../../stdafx.h" #include "../../textbuf_gui.h" #include "../../openttd.h" #include "../../crashlog.h" #include "../../core/random_func.hpp" #include "../../debug.h" #include "../../string_func.h" #include #include #include #include #include #ifdef __APPLE__ #include #elif (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) || defined(__GLIBC__) #define HAS_STATVFS #endif #if defined(OPENBSD) || defined(__NetBSD__) || defined(__FreeBSD__) #define HAS_SYSCTL #endif #ifdef HAS_STATVFS #include #endif #ifdef HAS_SYSCTL #include #endif #ifdef __MORPHOS__ #include ULONG __stack = (1024*1024)*2; // maybe not that much is needed actually ;) /* The system supplied definition of SIG_IGN does not match */ #undef SIG_IGN #define SIG_IGN (void (*)(int))1 #endif /* __MORPHOS__ */ #ifdef __AMIGA__ #warning add stack symbol to avoid that user needs to set stack manually (tokai) // ULONG __stack = #endif #if defined(__APPLE__) #if defined(WITH_SDL) /* the mac implementation needs this file included in the same file as main() */ #include #endif #endif #include "../../safeguards.h" bool FiosIsRoot(const char *path) { #if !defined(__MORPHOS__) && !defined(__AMIGAOS__) return path[1] == '\0'; #else /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */ const char *s = strchr(path, ':'); return s != NULL && s[1] == '\0'; #endif } void FiosGetDrives() { return; } bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) { uint64 free = 0; #ifdef __APPLE__ struct statfs s; if (statfs(path, &s) != 0) return false; free = (uint64)s.f_bsize * s.f_bavail; #elif defined(HAS_STATVFS) struct statvfs s; if (statvfs(path, &s) != 0) return false; free = (uint64)s.f_frsize * s.f_bavail; #endif if (tot != NULL) *tot = free; return true; } bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb) { char filename[MAX_PATH]; int res; #if defined(__MORPHOS__) || defined(__AMIGAOS__) /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */ if (FiosIsRoot(path)) { res = seprintf(filename, lastof(filename), "%s:%s", path, ent->d_name); } else // XXX - only next line! #else assert(path[strlen(path) - 1] == PATHSEPCHAR); if (strlen(path) > 2) assert(path[strlen(path) - 2] != PATHSEPCHAR); #endif res = seprintf(filename, lastof(filename), "%s%s", path, ent->d_name); /* Could we fully concatenate the path and filename? */ if (res >= (int)lengthof(filename) || res < 0) return false; return stat(filename, sb) == 0; } bool FiosIsHiddenFile(const struct dirent *ent) { return ent->d_name[0] == '.'; } #ifdef WITH_ICONV #include #include #include "../../debug.h" #include "../../string_func.h" const char *GetCurrentLocale(const char *param); #define INTERNALCODE "UTF-8" /** * Try and try to decipher the current locale from environmental * variables. MacOSX is hardcoded, other OS's are dynamic. If no suitable * locale can be found, don't do any conversion "" */ static const char *GetLocalCode() { #if defined(__APPLE__) return "UTF-8-MAC"; #else /* Strip locale (eg en_US.UTF-8) to only have UTF-8 */ const char *locale = GetCurrentLocale("LC_CTYPE"); if (locale != NULL) locale = strchr(locale, '.'); return (locale == NULL) ? "" : locale + 1; #endif } /** * Convert between locales, which from and which to is set in the calling * functions OTTD2FS() and FS2OTTD(). */ static const char *convert_tofrom_fs(iconv_t convd, const char *name) { static char buf[1024]; /* There are different implementations of iconv. The older ones, * e.g. SUSv2, pass a const pointer, whereas the newer ones, e.g. * IEEE 1003.1 (2004), pass a non-const pointer. */ #ifdef HAVE_NON_CONST_ICONV char *inbuf = const_cast(name); #else const char *inbuf = name; #endif char *outbuf = buf; size_t outlen = sizeof(buf) - 1; size_t inlen = strlen(name); strecpy(outbuf, name, outbuf + outlen); iconv(convd, NULL, NULL, NULL, NULL); if (iconv(convd, &inbuf, &inlen, &outbuf, &outlen) == (size_t)(-1)) { DEBUG(misc, 0, "[iconv] error converting '%s'. Errno %d", name, errno); } *outbuf = '\0'; /* FIX: invalid characters will abort conversion, but they shouldn't occur? */ return buf; } /** * Convert from OpenTTD's encoding to that of the local environment * @param name pointer to a valid string that will be converted * @return pointer to a new stringbuffer that contains the converted string */ const char *OTTD2FS(const char *name) { static iconv_t convd = (iconv_t)(-1); if (convd == (iconv_t)(-1)) { const char *env = GetLocalCode(); convd = iconv_open(env, INTERNALCODE); if (convd == (iconv_t)(-1)) { DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", INTERNALCODE, env); return name; } } return convert_tofrom_fs(convd, name); } /** * Convert to OpenTTD's encoding from that of the local environment * @param name pointer to a valid string that will be converted * @return pointer to a new stringbuffer that contains the converted string */ const char *FS2OTTD(const char *name) { static iconv_t convd = (iconv_t)(-1); if (convd == (iconv_t)(-1)) { const char *env = GetLocalCode(); convd = iconv_open(INTERNALCODE, env); if (convd == (iconv_t)(-1)) { DEBUG(misc, 0, "[iconv] conversion from codeset '%s' to '%s' unsupported", env, INTERNALCODE); return name; } } return convert_tofrom_fs(convd, name); } #else const char *FS2OTTD(const char *name) {return name;} const char *OTTD2FS(const char *name) {return name;} #endif /* WITH_ICONV */ void ShowInfo(const char *str) { fprintf(stderr, "%s\n", str); } #if !defined(__APPLE__) void ShowOSErrorBox(const char *buf, bool system) { /* All unix systems, except OSX. Only use escape codes on a TTY. */ if (isatty(fileno(stderr))) { fprintf(stderr, "\033[1;31mError: %s\033[0;39m\n", buf); } else { fprintf(stderr, "Error: %s\n", buf); } } #endif #ifdef WITH_COCOA void cocoaSetupAutoreleasePool(); void cocoaReleaseAutoreleasePool(); #endif int CDECL main(int argc, char *argv[]) { int ret; #ifdef WITH_COCOA cocoaSetupAutoreleasePool(); /* This is passed if we are launched by double-clicking */ if (argc >= 2 && strncmp(argv[1], "-psn", 4) == 0) { argv[1] = NULL; argc = 1; } #endif CrashLog::InitialiseCrashLog(); SetRandomSeed(time(NULL)); signal(SIGPIPE, SIG_IGN); ret = openttd_main(argc, argv); #ifdef WITH_COCOA cocoaReleaseAutoreleasePool(); #endif return ret; } #ifndef WITH_COCOA bool GetClipboardContents(char *buffer, const char *last) { return false; } #endif /* multi os compatible sleep function */ #ifdef __AMIGA__ /* usleep() implementation */ # include # include extern struct Device *TimerBase = NULL; extern struct MsgPort *TimerPort = NULL; extern struct timerequest *TimerRequest = NULL; #endif /* __AMIGA__ */ void CSleep(int milliseconds) { #if defined(PSP) sceKernelDelayThread(milliseconds * 1000); #elif defined(__BEOS__) snooze(milliseconds * 1000); #elif defined(__AMIGA__) { ULONG signals; ULONG TimerSigBit = 1 << TimerPort->mp_SigBit; /* send IORequest */ TimerRequest->tr_node.io_Command = TR_ADDREQUEST; TimerRequest->tr_time.tv_secs = (milliseconds * 1000) / 1000000; TimerRequest->tr_time.tv_micro = (milliseconds * 1000) % 1000000; SendIO((struct IORequest *)TimerRequest); if (!((signals = Wait(TimerSigBit | SIGBREAKF_CTRL_C)) & TimerSigBit) ) { AbortIO((struct IORequest *)TimerRequest); } WaitIO((struct IORequest *)TimerRequest); } #else usleep(milliseconds * 1000); #endif } #ifndef __APPLE__ uint GetCPUCoreCount() { uint count = 1; #ifdef HAS_SYSCTL int ncpu = 0; size_t len = sizeof(ncpu); #ifdef OPENBSD int name[2]; name[0] = CTL_HW; name[1] = HW_NCPU; if (sysctl(name, 2, &ncpu, &len, NULL, 0) < 0) { ncpu = 0; } #else if (sysctlbyname("hw.availcpu", &ncpu, &len, NULL, 0) < 0) { sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0); } #endif /* #ifdef OPENBSD */ if (ncpu > 0) count = ncpu; #elif defined(_SC_NPROCESSORS_ONLN) long res = sysconf(_SC_NPROCESSORS_ONLN); if (res > 0) count = res; #endif return count; } void OSOpenBrowser(const char *url) { pid_t child_pid = fork(); if (child_pid != 0) return; const char *args[3]; args[0] = "xdg-open"; args[1] = url; args[2] = NULL; execvp(args[0], const_cast(args)); DEBUG(misc, 0, "Failed to open url: %s", url); exit(0); } #endif openttd-1.5.3/src/os/macosx/0000755000000000000000000000000012627373441014406 5ustar rootrootopenttd-1.5.3/src/os/macosx/macos.h0000644000000000000000000000350012627373441015657 0ustar rootroot/* $Id: macos.h 25663 2013-08-05 20:36:06Z michi_cc $ */ /* * 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 macos.h Functions related to MacOS support. */ #ifndef MACOS_H #define MACOS_H /** Helper function displaying a message the best possible way. */ void ShowMacDialog(const char *title, const char *message, const char *button_label); void GetMacOSVersion(int *return_major, int *return_minor, int *return_bugfix); /** * Check if we are at least running on the specified version of Mac OS. * @param major major version of the os. This would be 10 in the case of 10.4.11. * @param minor minor version of the os. This would be 4 in the case of 10.4.11. * @param bugfix bugfix version of the os. This would be 11 in the case of 10.4.11. * @return true if the running os is at least what we asked, false otherwise. */ static inline bool MacOSVersionIsAtLeast(long major, long minor, long bugfix) { int version_major, version_minor, version_bugfix; GetMacOSVersion(&version_major, &version_minor, &version_bugfix); if (version_major < major) return false; if (version_major == major && version_minor < minor) return false; if (version_major == major && version_minor == minor && version_bugfix < bugfix) return false; return true; } bool IsMonospaceFont(CFStringRef name); #endif /* MACOS_H */ openttd-1.5.3/src/os/macosx/G5_detector.cpp0000644000000000000000000000261512627373441017262 0ustar rootroot/* $Id: G5_detector.cpp 24524 2012-09-13 18:42:33Z yexo $ */ /* * 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 G5_detector.cpp Detection for G5 machines (PowerPC). */ #include #include #include #include #include #ifndef CPU_SUBTYPE_POWERPC_970 #define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) #endif /* this function is a lightly modified version of some code from Apple's developer homepage to detect G5 CPUs at runtime */ int main() { host_basic_info_data_t hostInfo; mach_msg_type_number_t infoCount; boolean_t is_G5; infoCount = HOST_BASIC_INFO_COUNT; host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); is_G5 = ((hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970)); if (is_G5) printf("1"); } openttd-1.5.3/src/os/macosx/splash.cpp0000644000000000000000000001205112627373441016403 0ustar rootroot/* $Id: splash.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 splash.cpp Splash screen support for OSX. */ #include "../../stdafx.h" #include "../../openttd.h" #include "../../debug.h" #include "../../gfx_func.h" #include "../../fileio_func.h" #include "../../blitter/factory.hpp" #include "../../core/mem_func.hpp" #include "splash.h" #ifdef WITH_PNG #include #include "../../safeguards.h" /** * Handle pnglib error. * * @param png_ptr Pointer to png struct. * @param message Error message text. */ static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message) { DEBUG(misc, 0, "[libpng] error: %s - %s", message, (char *)png_get_error_ptr(png_ptr)); longjmp(png_jmpbuf(png_ptr), 1); } /** * Handle warning in pnglib. * * @param png_ptr Pointer to png struct. * @param message Warning message text. */ static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message) { DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (char *)png_get_error_ptr(png_ptr)); } /** * Display a splash image shown on startup (WITH_PNG). */ void DisplaySplashImage() { FILE *f = FioFOpenFile(SPLASH_IMAGE_FILE, "r", BASESET_DIR); if (f == NULL) return; png_byte header[8]; fread(header, sizeof(png_byte), 8, f); if (png_sig_cmp(header, 0, 8) != 0) { fclose(f); return; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, png_my_error, png_my_warning); if (png_ptr == NULL) { fclose(f); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); fclose(f); return; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); fclose(f); return; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } png_init_io(png_ptr, f); png_set_sig_bytes(png_ptr, 8); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); uint width = png_get_image_width(png_ptr, info_ptr); uint height = png_get_image_height(png_ptr, info_ptr); uint bit_depth = png_get_bit_depth(png_ptr, info_ptr); uint color_type = png_get_color_type(png_ptr, info_ptr); if (color_type != PNG_COLOR_TYPE_PALETTE || bit_depth != 8) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) { png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } png_colorp palette; int num_palette; png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr); if (width > (uint) _screen.width) width = _screen.width; if (height > (uint) _screen.height) height = _screen.height; uint xoff = (_screen.width - width) / 2; uint yoff = (_screen.height - height) / 2; switch (BlitterFactory::GetCurrentBlitter()->GetScreenDepth()) { case 8: { uint8 *dst_ptr = (uint8 *)_screen.dst_ptr; /* Initialize buffer */ MemSetT(dst_ptr, 0xff, _screen.pitch * _screen.height); for (uint y = 0; y < height; y++) { uint8 *src = row_pointers[y]; uint8 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff; memcpy(dst, src, width); } for (int i = 0; i < num_palette; i++) { _cur_palette.palette[i].a = i == 0 ? 0 : 0xff; _cur_palette.palette[i].r = palette[i].red; _cur_palette.palette[i].g = palette[i].green; _cur_palette.palette[i].b = palette[i].blue; } _cur_palette.palette[0xff].a = 0xff; _cur_palette.palette[0xff].r = 0; _cur_palette.palette[0xff].g = 0; _cur_palette.palette[0xff].b = 0; _cur_palette.first_dirty = 0; _cur_palette.count_dirty = 256; break; } case 32: { uint32 *dst_ptr = (uint32 *)_screen.dst_ptr; /* Initialize buffer */ MemSetT(dst_ptr, 0, _screen.pitch * _screen.height); for (uint y = 0; y < height; y++) { uint8 *src = row_pointers[y]; uint32 *dst = dst_ptr + (yoff + y) * _screen.pitch + xoff; for (uint x = 0; x < width; x++) { dst[x] = palette[src[x]].blue | (palette[src[x]].green << 8) | (palette[src[x]].red << 16) | 0xff000000; } } break; } } png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); fclose(f); return; } #else /* WITH_PNG */ /** * Empty 'Display a splash image' routine (WITHOUT_PNG). */ void DisplaySplashImage() {} #endif /* WITH_PNG */ openttd-1.5.3/src/os/macosx/splash.h0000644000000000000000000000150212627373441016047 0ustar rootroot/* $Id: splash.h 22913 2011-09-09 20:28:48Z rubidium $ */ /* * 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 splash.h Functions to support splash screens for OSX. */ #ifndef SPLASH_H #define SPLASH_H #define SPLASH_IMAGE_FILE "splash.png" void DisplaySplashImage(); #endif /* SPLASH_H */ openttd-1.5.3/src/os/macosx/osx_stdafx.h0000644000000000000000000000617712627373441016754 0ustar rootroot/* $Id: osx_stdafx.h 26709 2014-07-30 20:19:29Z planetmaker $ */ /* * 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 osx_stdafx.h OSX is different on some places. */ #ifndef MACOS_STDAFX_H #define MACOS_STDAFX_H /* It would seem that to ensure backward compability we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */ #ifndef MAC_OS_X_VERSION_10_3 #define MAC_OS_X_VERSION_10_3 1030 #endif #ifndef MAC_OS_X_VERSION_10_4 #define MAC_OS_X_VERSION_10_4 1040 #endif #ifndef MAC_OS_X_VERSION_10_5 #define MAC_OS_X_VERSION_10_5 1050 #endif #ifndef MAC_OS_X_VERSION_10_6 #define MAC_OS_X_VERSION_10_6 1060 #endif #ifndef MAC_OS_X_VERSION_10_7 #define MAC_OS_X_VERSION_10_7 1070 #endif #ifndef MAC_OS_X_VERSION_10_8 #define MAC_OS_X_VERSION_10_8 1080 #endif #ifndef MAC_OS_X_VERSION_10_9 #define MAC_OS_X_VERSION_10_9 1090 #endif #define __STDC_LIMIT_MACROS #include /* Some gcc versions include assert.h via this header. As this would interfere * with our own assert redefinition, include this header first. */ #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) # include #endif /* Check for mismatching 'architectures' */ #if !defined(STRGEN) && !defined(SETTINGSGEN) && ((defined(__LP64__) && !defined(_SQ64)) || (!defined(__LP64__) && defined(_SQ64))) # error "Compiling 64 bits without _SQ64 set! (or vice versa)" #endif #include /* Name conflict */ #define Rect OTTDRect #define Point OTTDPoint #define WindowClass OTTDWindowClass #define ScriptOrder OTTDScriptOrder #define Palette OTTDPalette #define GlyphID OTTDGlyphID #include #include #undef Rect #undef Point #undef WindowClass #undef ScriptOrder #undef Palette #undef GlyphID /* remove the variables that CoreServices defines, but we define ourselves too */ #undef bool #undef false #undef true /* Name conflict */ #define GetTime OTTD_GetTime #define SL_ERROR OSX_SL_ERROR /* NSInteger and NSUInteger are part of 10.5 and higher. */ #ifndef NSInteger #ifdef __LP64__ typedef long NSInteger; typedef unsigned long NSUInteger; #else typedef int NSInteger; typedef unsigned int NSUInteger; #endif /* __LP64__ */ #endif /* NSInteger */ #ifndef CGFLOAT_DEFINED #ifdef __LP64__ typedef double CGFloat; #else typedef float CGFloat; #endif /* __LP64__ */ #endif /* CGFLOAT_DEFINED */ /* OS X SDK versions >= 10.5 have a non-const iconv. */ #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 # define HAVE_NON_CONST_ICONV #endif #endif /* MACOS_STDAFX_H */ openttd-1.5.3/src/os/macosx/crashlog_osx.cpp0000644000000000000000000001705212627373441017612 0ustar rootroot/* $Id: crashlog_osx.cpp 26709 2014-07-30 20:19:29Z planetmaker $ */ /* * 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 crashlog_osx.cpp OS X crash log handler */ #include "../../stdafx.h" #include "../../crashlog.h" #include "../../string_func.h" #include "../../gamelog.h" #include "../../saveload/saveload.h" #include "macos.h" #include #include #include #include #include #include "../../safeguards.h" /* Macro testing a stack address for valid alignment. */ #if defined(__i386__) #define IS_ALIGNED(addr) (((uintptr_t)(addr) & 0xf) == 8) #else #define IS_ALIGNED(addr) (((uintptr_t)(addr) & 0xf) == 0) #endif /* printf format specification for 32/64-bit addresses. */ #ifdef __LP64__ #define PRINTF_PTR "0x%016lx" #else #define PRINTF_PTR "0x%08lx" #endif #define MAX_STACK_FRAMES 64 /** * OSX implementation for the crash logger. */ class CrashLogOSX : public CrashLog { /** Signal that has been thrown. */ int signum; char filename_log[MAX_PATH]; ///< Path of crash.log char filename_save[MAX_PATH]; ///< Path of crash.sav char filename_screenshot[MAX_PATH]; ///< Path of crash.(png|bmp|pcx) /* virtual */ char *LogOSVersion(char *buffer, const char *last) const { int ver_maj, ver_min, ver_bug; GetMacOSVersion(&ver_maj, &ver_min, &ver_bug); const NXArchInfo *arch = NXGetLocalArchInfo(); return buffer + seprintf(buffer, last, "Operating system:\n" " Name: Mac OS X\n" " Release: %d.%d.%d\n" " Machine: %s\n" " Min Ver: %d\n", ver_maj, ver_min, ver_bug, arch != NULL ? arch->description : "unknown", MAC_OS_X_VERSION_MIN_REQUIRED ); } /* virtual */ char *LogError(char *buffer, const char *last, const char *message) const { return buffer + seprintf(buffer, last, "Crash reason:\n" " Signal: %s (%d)\n" " Message: %s\n\n", strsignal(this->signum), this->signum, message == NULL ? "" : message ); } /* virtual */ char *LogStacktrace(char *buffer, const char *last) const { /* As backtrace() is only implemented in 10.5 or later, * we're rolling our own here. Mostly based on * http://stackoverflow.com/questions/289820/getting-the-current-stack-trace-on-mac-os-x * and some details looked up in the Darwin sources. */ buffer += seprintf(buffer, last, "\nStacktrace:\n"); void **frame; #if defined(__ppc__) || defined(__ppc64__) /* Apple says __builtin_frame_address can be broken on PPC. */ __asm__ volatile("mr %0, r1" : "=r" (frame)); #else frame = (void **)__builtin_frame_address(0); #endif for (int i = 0; frame != NULL && i < MAX_STACK_FRAMES; i++) { /* Get IP for current stack frame. */ #if defined(__ppc__) || defined(__ppc64__) void *ip = frame[2]; #else void *ip = frame[1]; #endif if (ip == NULL) break; /* Print running index. */ buffer += seprintf(buffer, last, " [%02d]", i); Dl_info dli; bool dl_valid = dladdr(ip, &dli) != 0; const char *fname = "???"; if (dl_valid && dli.dli_fname) { /* Valid image name? Extract filename from the complete path. */ const char *s = strrchr(dli.dli_fname, '/'); if (s != NULL) { fname = s + 1; } else { fname = dli.dli_fname; } } /* Print image name and IP. */ buffer += seprintf(buffer, last, " %-20s " PRINTF_PTR, fname, (uintptr_t)ip); /* Print function offset if information is available. */ if (dl_valid && dli.dli_sname != NULL && dli.dli_saddr != NULL) { /* Try to demangle a possible C++ symbol. */ int status = -1; char *func_name = abi::__cxa_demangle(dli.dli_sname, NULL, 0, &status); long int offset = (intptr_t)ip - (intptr_t)dli.dli_saddr; buffer += seprintf(buffer, last, " (%s + %ld)", func_name != NULL ? func_name : dli.dli_sname, offset); free(func_name); } buffer += seprintf(buffer, last, "\n"); /* Get address of next stack frame. */ void **next = (void **)frame[0]; /* Frame address not increasing or not aligned? Broken stack, exit! */ if (next <= frame || !IS_ALIGNED(next)) break; frame = next; } return buffer + seprintf(buffer, last, "\n"); } public: /** * A crash log is always generated by signal. * @param signum the signal that was caused by the crash. */ CrashLogOSX(int signum) : signum(signum) { filename_log[0] = '\0'; filename_save[0] = '\0'; filename_screenshot[0] = '\0'; } /** Generate the crash log. */ bool MakeCrashLog() { char buffer[65536]; bool ret = true; printf("Crash encountered, generating crash log...\n"); this->FillCrashLog(buffer, lastof(buffer)); printf("%s\n", buffer); printf("Crash log generated.\n\n"); printf("Writing crash log to disk...\n"); if (!this->WriteCrashLog(buffer, filename_log, lastof(filename_log))) { filename_log[0] = '\0'; ret = false; } printf("Writing crash savegame...\n"); if (!this->WriteSavegame(filename_save, lastof(filename_save))) { filename_save[0] = '\0'; ret = false; } printf("Writing crash savegame...\n"); if (!this->WriteScreenshot(filename_screenshot, lastof(filename_screenshot))) { filename_screenshot[0] = '\0'; ret = false; } return ret; } /** Show a dialog with the crash information. */ void DisplayCrashDialog() const { static const char crash_title[] = "A serious fault condition occurred in the game. The game will shut down."; char message[1024]; seprintf(message, lastof(message), "Please send the generated crash information and the last (auto)save to the developers. " "This will greatly help debugging. The correct place to do this is http://bugs.openttd.org.\n\n" "Generated file(s):\n%s\n%s\n%s", this->filename_log, this->filename_save, this->filename_screenshot); ShowMacDialog(crash_title, message, "Quit"); } }; /** The signals we want our crash handler to handle. */ static const int _signals_to_handle[] = { SIGSEGV, SIGABRT, SIGFPE, SIGBUS, SIGILL, SIGSYS }; /** * Entry point for the crash handler. * @note Not static so it shows up in the backtrace. * @param signum the signal that caused us to crash. */ void CDECL HandleCrash(int signum) { /* Disable all handling of signals by us, so we don't go into infinite loops. */ for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) { signal(*i, SIG_DFL); } if (GamelogTestEmergency()) { ShowMacDialog("A serious fault condition occurred in the game. The game will shut down.", "As you loaded an emergency savegame no crash information will be generated.\n", "Quit"); abort(); } if (SaveloadCrashWithMissingNewGRFs()) { ShowMacDialog("A serious fault condition occurred in the game. The game will shut down.", "As you loaded an savegame for which you do not have the required NewGRFs no crash information will be generated.\n", "Quit"); abort(); } CrashLogOSX log(signum); log.MakeCrashLog(); log.DisplayCrashDialog(); CrashLog::AfterCrashLogCleanup(); abort(); } /* static */ void CrashLog::InitialiseCrashLog() { for (const int *i = _signals_to_handle; i != endof(_signals_to_handle); i++) { signal(*i, HandleCrash); } } openttd-1.5.3/src/os/macosx/macos.mm0000644000000000000000000001443312627373441016050 0ustar rootroot/* $Id: macos.mm 26485 2014-04-23 20:44:42Z frosch $ */ /* * 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 macos.mm Code related to MacOSX. */ #include "../../stdafx.h" #include "../../core/bitmath_func.hpp" #include "../../rev.h" #include "macos.h" #include "../../string_func.h" #define Rect OTTDRect #define Point OTTDPoint #include #undef Rect #undef Point /* * This file contains objective C * Apple uses objective C instead of plain C to interact with OS specific/native functions */ /** * Get the version of the MacOS we are running under. Code adopted * from http://www.cocoadev.com/index.pl?DeterminingOSVersion * @param return_major major version of the os. This would be 10 in the case of 10.4.11 * @param return_minor minor version of the os. This would be 4 in the case of 10.4.11 * @param return_bugfix bugfix version of the os. This would be 11 in the case of 10.4.11 * A return value of -1 indicates that something went wrong and we don't know. */ void GetMacOSVersion(int *return_major, int *return_minor, int *return_bugfix) { *return_major = -1; *return_minor = -1; *return_bugfix = -1; SInt32 systemVersion, version_major, version_minor, version_bugfix; if (Gestalt(gestaltSystemVersion, &systemVersion) == noErr) { if (systemVersion >= 0x1040) { if (Gestalt(gestaltSystemVersionMajor, &version_major) == noErr) *return_major = (int)version_major; if (Gestalt(gestaltSystemVersionMinor, &version_minor) == noErr) *return_minor = (int)version_minor; if (Gestalt(gestaltSystemVersionBugFix, &version_bugfix) == noErr) *return_bugfix = (int)version_bugfix; } else { *return_major = (int)(GB(systemVersion, 12, 4) * 10 + GB(systemVersion, 8, 4)); *return_minor = (int)GB(systemVersion, 4, 4); *return_bugfix = (int)GB(systemVersion, 0, 4); } } } #ifdef WITH_SDL /** * Show the system dialogue message (SDL on MacOSX). * * @param title Window title. * @param message Message text. * @param buttonLabel Button text. */ void ShowMacDialog(const char *title, const char *message, const char *buttonLabel) { NSRunAlertPanel([ NSString stringWithUTF8String:title ], [ NSString stringWithUTF8String:message ], [ NSString stringWithUTF8String:buttonLabel ], nil, nil); } #elif defined WITH_COCOA extern void CocoaDialog(const char *title, const char *message, const char *buttonLabel); /** * Show the system dialogue message (Cocoa on MacOSX). * * @param title Window title. * @param message Message text. * @param buttonLabel Button text. */ void ShowMacDialog(const char *title, const char *message, const char *buttonLabel) { CocoaDialog(title, message, buttonLabel); } #else /** * Show the system dialogue message (console on MacOSX). * * @param title Window title. * @param message Message text. * @param buttonLabel Button text. */ void ShowMacDialog(const char *title, const char *message, const char *buttonLabel) { fprintf(stderr, "%s: %s\n", title, message); } #endif /** * Show an error message. * * @param buf error message text. * @param system message text originates from OS. */ void ShowOSErrorBox(const char *buf, bool system) { /* Display the error in the best way possible. */ if (system) { ShowMacDialog("OpenTTD has encountered an error", buf, "Quit"); } else { ShowMacDialog(buf, "See the readme for more info.", "Quit"); } } void OSOpenBrowser(const char *url) { [ [ NSWorkspace sharedWorkspace ] openURL:[ NSURL URLWithString:[ NSString stringWithUTF8String:url ] ] ]; } /** * Determine and return the current user's locale. */ const char *GetCurrentLocale(const char *) { static char retbuf[32] = { '\0' }; NSUserDefaults *defs = [ NSUserDefaults standardUserDefaults ]; NSArray *languages = [ defs objectForKey:@"AppleLanguages" ]; NSString *preferredLang = [ languages objectAtIndex:0 ]; /* preferredLang is either 2 or 5 characters long ("xx" or "xx_YY"). */ /* Since Apple introduced encoding to CString in OSX 10.4 we have to make a few conditions * to get the right code for the used version of OSX. */ #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) if (MacOSVersionIsAtLeast(10, 4, 0)) { [ preferredLang getCString:retbuf maxLength:32 encoding:NSASCIIStringEncoding ]; } else #endif { #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4) /* maxLength does not include the \0 char in contrast to the call above. */ [ preferredLang getCString:retbuf maxLength:31 ]; #endif } return retbuf; } #ifdef WITH_COCOA /** * Return the contents of the clipboard (COCOA). * * @param buffer Clipboard content. * @param last The pointer to the last element of the destination buffer * @return Whether clipboard is empty or not. */ bool GetClipboardContents(char *buffer, const char *last) { NSPasteboard *pb = [ NSPasteboard generalPasteboard ]; NSArray *types = [ NSArray arrayWithObject:NSStringPboardType ]; NSString *bestType = [ pb availableTypeFromArray:types ]; /* Clipboard has no text data available. */ if (bestType == nil) return false; NSString *string = [ pb stringForType:NSStringPboardType ]; if (string == nil || [ string length ] == 0) return false; strecpy(buffer, [ string UTF8String ], last); return true; } #endif uint GetCPUCoreCount() { uint count = 1; #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) if (MacOSVersionIsAtLeast(10, 5, 0)) { count = [ [ NSProcessInfo processInfo ] activeProcessorCount ]; } else #endif { #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) count = MPProcessorsScheduled(); #endif } return count; } /** * Check if a font is a monospace font. * @param name Name of the font. * @return True if the font is a monospace font. */ bool IsMonospaceFont(CFStringRef name) { NSFont *font = [ NSFont fontWithName:(NSString *)name size:0.0f ]; return font != NULL ? [ font isFixedPitch ] : false; } openttd-1.5.3/src/roadveh_cmd.cpp0000644000000000000000000016030212627373442015455 0ustar rootroot/* $Id: roadveh_cmd.cpp 27190 2015-03-16 20:01:14Z frosch $ */ /* * 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 roadveh_cmd.cpp Handling of road vehicles. */ #include "stdafx.h" #include "roadveh.h" #include "command_func.h" #include "news_func.h" #include "pathfinder/npf/npf_func.h" #include "station_base.h" #include "company_func.h" #include "articulated_vehicles.h" #include "newgrf_sound.h" #include "pathfinder/yapf/yapf.h" #include "strings_func.h" #include "tunnelbridge_map.h" #include "date_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "ai/ai.hpp" #include "game/game.hpp" #include "depot_map.h" #include "effectvehicle_func.h" #include "roadstop_base.h" #include "spritecache.h" #include "core/random_func.hpp" #include "company_base.h" #include "core/backup_type.hpp" #include "newgrf.h" #include "zoom_func.h" #include "table/strings.h" #include "safeguards.h" static const uint16 _roadveh_images[] = { 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14, 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74, 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C, 0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC, 0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC, 0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4, 0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C, 0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4 }; static const uint16 _roadveh_full_adder[] = { 0, 88, 0, 0, 0, 0, 48, 48, 48, 48, 0, 0, 64, 64, 0, 16, 16, 0, 88, 0, 0, 0, 0, 48, 48, 48, 48, 0, 0, 64, 64, 0, 16, 16, 0, 88, 0, 0, 0, 0, 48, 48, 48, 48, 0, 0, 64, 64, 0, 16, 16, 0, 8, 8, 8, 8, 0, 0, 0, 8, 8, 8, 8 }; assert_compile(lengthof(_roadveh_images) == lengthof(_roadveh_full_adder)); template <> bool IsValidImageIndex(uint8 image_index) { return image_index < lengthof(_roadveh_images); } /** 'Convert' the DiagDirection where a road vehicle enters to the trackdirs it can drive onto */ static const TrackdirBits _road_enter_dir_to_reachable_trackdirs[DIAGDIR_END] = { TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_X_NE, // Enter from north east TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_Y_SE, // Enter from south east TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_RIGHT_S, // Enter from south west TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_Y_NW // Enter from north west }; static const Trackdir _road_reverse_table[DIAGDIR_END] = { TRACKDIR_RVREV_NE, TRACKDIR_RVREV_SE, TRACKDIR_RVREV_SW, TRACKDIR_RVREV_NW }; /** Converts the exit direction of a depot to trackdir the vehicle is going to drive to */ static const Trackdir _roadveh_depot_exit_trackdir[DIAGDIR_END] = { TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW }; /** * Check whether a roadvehicle is a bus * @return true if bus */ bool RoadVehicle::IsBus() const { assert(this->IsFrontEngine()); return IsCargoInClass(this->cargo_type, CC_PASSENGERS); } /** * Get the width of a road vehicle image in the GUI. * @param offset Additional offset for positioning the sprite; set to NULL if not needed * @return Width in pixels */ int RoadVehicle::GetDisplayImageWidth(Point *offset) const { int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH; if (offset != NULL) { offset->x = ScaleGUITrad(reference_width) / 2; offset->y = 0; } return ScaleGUITrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH); } static SpriteID GetRoadVehIcon(EngineID engine, EngineImageType image_type) { const Engine *e = Engine::Get(engine); uint8 spritenum = e->u.road.image_index; if (is_custom_sprite(spritenum)) { SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type); if (sprite != 0) return sprite; spritenum = e->original_image_index; } assert(IsValidImageIndex(spritenum)); return DIR_W + _roadveh_images[spritenum]; } SpriteID RoadVehicle::GetImage(Direction direction, EngineImageType image_type) const { uint8 spritenum = this->spritenum; SpriteID sprite; if (is_custom_sprite(spritenum)) { sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type); if (sprite != 0) return sprite; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); sprite = direction + _roadveh_images[spritenum]; if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum]; return sprite; } /** * Draw a road vehicle engine. * @param left Left edge to draw within. * @param right Right edge to draw within. * @param preferred_x Preferred position of the engine. * @param y Vertical position of the engine. * @param engine Engine to draw * @param pal Palette to use. */ void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { SpriteID sprite = GetRoadVehIcon(engine, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); preferred_x = Clamp(preferred_x, left - UnScaleGUI(real_sprite->x_offs), right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); DrawSprite(sprite, pal, preferred_x, y); } /** * Get the size of the sprite of a road vehicle sprite heading west (used for lists). * @param engine The engine to get the sprite from. * @param[out] width The width of the sprite. * @param[out] height The height of the sprite. * @param[out] xoffs Number of pixels to shift the sprite to the right. * @param[out] yoffs Number of pixels to shift the sprite downwards. * @param image_type Context the sprite is used in. */ void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) { const Sprite *spr = GetSprite(GetRoadVehIcon(engine, image_type), ST_NORMAL); width = UnScaleGUI(spr->width); height = UnScaleGUI(spr->height); xoffs = UnScaleGUI(spr->x_offs); yoffs = UnScaleGUI(spr->y_offs); } /** * Get length of a road vehicle. * @param v Road vehicle to query length. * @return Length of the given road vehicle. */ static uint GetRoadVehLength(const RoadVehicle *v) { const Engine *e = v->GetEngine(); uint length = VEHICLE_LENGTH; uint16 veh_len = CALLBACK_FAILED; if (e->GetGRF() != NULL && e->GetGRF()->grf_version >= 8) { /* Use callback 36 */ veh_len = GetVehicleProperty(v, PROP_ROADVEH_SHORTEN_FACTOR, CALLBACK_FAILED); if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len); } else { /* Use callback 11 */ veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v); } if (veh_len == CALLBACK_FAILED) veh_len = e->u.road.shorten_factor; if (veh_len != 0) { length -= Clamp(veh_len, 0, VEHICLE_LENGTH - 1); } return length; } /** * Update the cache of a road vehicle. * @param v Road vehicle needing an update of its cache. * @param same_length should length of vehicles stay the same? * @pre \a v must be first road vehicle. */ void RoadVehUpdateCache(RoadVehicle *v, bool same_length) { assert(v->type == VEH_ROAD); assert(v->IsFrontEngine()); v->InvalidateNewGRFCacheOfChain(); v->gcache.cached_total_length = 0; for (RoadVehicle *u = v; u != NULL; u = u->Next()) { /* Check the v->first cache. */ assert(u->First() == v); /* Update the 'first engine' */ u->gcache.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type; /* Update the length of the vehicle. */ uint veh_len = GetRoadVehLength(u); /* Verify length hasn't changed. */ if (same_length && veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u); u->gcache.cached_veh_length = veh_len; v->gcache.cached_total_length += u->gcache.cached_veh_length; /* Update visual effect */ u->UpdateVisualEffect(); /* Update cargo aging period. */ u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_ROADVEH_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period); } uint max_speed = GetVehicleProperty(v, PROP_ROADVEH_SPEED, 0); v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed; } /** * Build a road vehicle. * @param tile tile of the depot where road vehicle is built. * @param flags type of operation. * @param e the engine to build. * @param data unused. * @param ret[out] the vehicle that has been built. * @return the cost of this operation or an error. */ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret) { if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE); if (flags & DC_EXEC) { const RoadVehicleInfo *rvi = &e->u.road; RoadVehicle *v = new RoadVehicle(); *ret = v; v->direction = DiagDirToDir(GetRoadDepotDirection(tile)); v->owner = _current_company; v->tile = tile; int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2; int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2; v->x_pos = x; v->y_pos = y; v->z_pos = GetSlopePixelZ(x, y); v->state = RVSB_IN_DEPOT; v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; v->spritenum = rvi->image_index; v->cargo_type = e->GetDefaultCargoType(); v->cargo_cap = rvi->capacity; v->refit_cap = 0; v->last_station_visited = INVALID_STATION; v->last_loading_station = INVALID_STATION; v->engine_type = e->index; v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback v->reliability = e->reliability; v->reliability_spd_dec = e->reliability_spd_dec; v->max_age = e->GetLifeLengthInDays(); _new_vehicle_id = v->index; v->SetServiceInterval(Company::Get(v->owner)->settings.vehicle.servint_roadveh); v->date_of_last_service = _date; v->build_year = _cur_year; v->cur_image = SPR_IMG_QUERY; v->random_bits = VehicleRandomBits(); v->SetFrontEngine(); v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD; v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype); v->gcache.cached_veh_length = VEHICLE_LENGTH; if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); AddArticulatedParts(v); v->InvalidateNewGRFCacheOfChain(); /* Call various callbacks after the whole consist has been constructed */ for (RoadVehicle *u = v; u != NULL; u = u->Next()) { u->cargo_cap = u->GetEngine()->DetermineCapacity(u); u->refit_cap = 0; v->InvalidateNewGRFCache(); u->InvalidateNewGRFCache(); } RoadVehUpdateCache(v); /* Initialize cached values for realistic acceleration. */ if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) v->CargoChanged(); v->UpdatePosition(); CheckConsistencyOfArticulatedVehicle(v); } return CommandCost(); } static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance) { if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0); switch (_settings_game.pf.pathfinder_for_roadvehs) { case VPF_NPF: return NPFRoadVehicleFindNearestDepot(v, max_distance); case VPF_YAPF: return YapfRoadVehicleFindNearestDepot(v, max_distance); default: NOT_REACHED(); } } bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { FindDepotData rfdd = FindClosestRoadDepot(this, 0); if (rfdd.best_length == UINT_MAX) return false; if (location != NULL) *location = rfdd.tile; if (destination != NULL) *destination = GetDepotIndex(rfdd.tile); return true; } /** * Turn a roadvehicle around. * @param tile unused * @param flags operation to perform * @param p1 vehicle ID to turn * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { RoadVehicle *v = RoadVehicle::GetIfValid(p1); if (v == NULL) return CMD_ERROR; if (!v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if ((v->vehstatus & VS_STOPPED) || (v->vehstatus & VS_CRASHED) || v->breakdown_ctr != 0 || v->overtaking != 0 || v->state == RVSB_WORMHOLE || v->IsInDepot() || v->current_order.IsType(OT_LOADING)) { return CMD_ERROR; } if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR; if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR; if (flags & DC_EXEC) v->reverse_ctr = 180; return CommandCost(); } void RoadVehicle::MarkDirty() { for (RoadVehicle *v = this; v != NULL; v = v->Next()) { v->colourmap = PAL_NONE; v->UpdateViewport(true, false); } this->CargoChanged(); } void RoadVehicle::UpdateDeltaXY(Direction direction) { static const int8 _delta_xy_table[8][10] = { /* y_extent, x_extent, y_offs, x_offs, y_bb_offs, x_bb_offs, y_extent_shorten, x_extent_shorten, y_bb_offs_shorten, x_bb_offs_shorten */ {3, 3, -1, -1, 0, 0, -1, -1, -1, -1}, // N {3, 7, -1, -3, 0, -1, 0, -1, 0, 0}, // NE {3, 3, -1, -1, 0, 0, 1, -1, 1, -1}, // E {7, 3, -3, -1, -1, 0, 0, 0, 1, 0}, // SE {3, 3, -1, -1, 0, 0, 1, 1, 1, 1}, // S {3, 7, -1, -3, 0, -1, 0, 0, 0, 1}, // SW {3, 3, -1, -1, 0, 0, -1, 1, -1, 1}, // W {7, 3, -3, -1, -1, 0, -1, 0, 0, 0}, // NW }; int shorten = VEHICLE_LENGTH - this->gcache.cached_veh_length; if (!IsDiagonalDirection(direction)) shorten >>= 1; const int8 *bb = _delta_xy_table[direction]; this->x_bb_offs = bb[5] + bb[9] * shorten; this->y_bb_offs = bb[4] + bb[8] * shorten;; this->x_offs = bb[3]; this->y_offs = bb[2]; this->x_extent = bb[1] + bb[7] * shorten; this->y_extent = bb[0] + bb[6] * shorten; this->z_extent = 6; } /** * Calculates the maximum speed of the vehicle under its current conditions. * @return Maximum speed of the vehicle. */ inline int RoadVehicle::GetCurrentMaxSpeed() const { int max_speed = this->vcache.cached_max_speed; /* Limit speed to 50% while reversing, 75% in curves. */ for (const RoadVehicle *u = this; u != NULL; u = u->Next()) { if (_settings_game.vehicle.roadveh_acceleration_model == AM_REALISTIC) { if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)this->state)) { max_speed = this->vcache.cached_max_speed / 2; break; } else if ((u->direction & 1) == 0) { max_speed = this->vcache.cached_max_speed * 3 / 4; } } /* Vehicle is on the middle part of a bridge. */ if (u->state == RVSB_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) { max_speed = min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed * 2); } } return min(max_speed, this->current_order.GetMaxSpeed() * 2); } /** * Delete last vehicle of a chain road vehicles. * @param v First roadvehicle. */ static void DeleteLastRoadVeh(RoadVehicle *v) { RoadVehicle *first = v->First(); Vehicle *u = v; for (; v->Next() != NULL; v = v->Next()) u = v; u->SetNext(NULL); v->last_station_visited = first->last_station_visited; // for PreDestructor /* Only leave the road stop when we're really gone. */ if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v); delete v; } static void RoadVehSetRandomDirection(RoadVehicle *v) { static const DirDiff delta[] = { DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT }; do { uint32 r = Random(); v->direction = ChangeDir(v->direction, delta[r & 3]); v->UpdateViewport(true, true); } while ((v = v->Next()) != NULL); } /** * Road vehicle chain has crashed. * @param v First roadvehicle. * @return whether the chain still exists. */ static bool RoadVehIsCrashed(RoadVehicle *v) { v->crashed_ctr++; if (v->crashed_ctr == 2) { CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); } else if (v->crashed_ctr <= 45) { if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v); } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) { bool ret = v->Next() != NULL; DeleteLastRoadVeh(v); return ret; } return true; } /** * Check routine whether a road and a train vehicle have collided. * @param v %Train vehicle to test. * @param data Road vehicle to test. * @return %Train vehicle if the vehicles collided, else \c NULL. */ static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data) { const Vehicle *u = (Vehicle*)data; return (v->type == VEH_TRAIN && abs(v->z_pos - u->z_pos) <= 6 && abs(v->x_pos - u->x_pos) <= 4 && abs(v->y_pos - u->y_pos) <= 4) ? v : NULL; } uint RoadVehicle::Crash(bool flooded) { uint pass = this->GroundVehicleBase::Crash(flooded); if (this->IsFrontEngine()) { pass += 1; // driver /* If we're in a drive through road stop we ought to leave it */ if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) { RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this); } } this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded return pass; } static void RoadVehCrash(RoadVehicle *v) { uint pass = v->Crash(); AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING)); Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING)); SetDParam(0, pass); AddVehicleNewsItem( (pass == 1) ? STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH, NT_ACCIDENT, v->index ); ModifyStationRatingAround(v->tile, v->owner, -160, 22); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v); } static bool RoadVehCheckTrainCrash(RoadVehicle *v) { for (RoadVehicle *u = v; u != NULL; u = u->Next()) { if (u->state == RVSB_WORMHOLE) continue; TileIndex tile = u->tile; if (!IsLevelCrossingTile(tile)) continue; if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) { RoadVehCrash(v); return true; } } return false; } TileIndex RoadVehicle::GetOrderStationLocation(StationID station) { if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION; const Station *st = Station::Get(station); if (!CanVehicleUseStation(this, st)) { /* There is no stop left at the station, so don't even TRY to go there */ this->IncrementRealOrderIndex(); return 0; } return st->xy; } static void StartRoadVehSound(const RoadVehicle *v) { if (!PlayVehicleSound(v, VSE_START)) { SoundID s = RoadVehInfo(v->engine_type)->sfx; if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0) { s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN; } SndPlayVehicleFx(s, v); } } struct RoadVehFindData { int x; int y; const Vehicle *veh; Vehicle *best; uint best_diff; Direction dir; }; static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data) { static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 }; static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 }; RoadVehFindData *rvf = (RoadVehFindData*)data; short x_diff = v->x_pos - rvf->x; short y_diff = v->y_pos - rvf->y; if (v->type == VEH_ROAD && !v->IsInDepot() && abs(v->z_pos - rvf->veh->z_pos) < 6 && v->direction == rvf->dir && rvf->veh->First() != v->First() && (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) && (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) && (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) && (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) { uint diff = abs(x_diff) + abs(y_diff); if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) { rvf->best = v; rvf->best_diff = diff; } } return NULL; } static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true) { RoadVehFindData rvf; RoadVehicle *front = v->First(); if (front->reverse_ctr != 0) return NULL; rvf.x = x; rvf.y = y; rvf.dir = dir; rvf.veh = v; rvf.best_diff = UINT_MAX; if (front->state == RVSB_WORMHOLE) { FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose); FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose); } else { FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose); } /* This code protects a roadvehicle from being blocked for ever * If more than 1480 / 74 days a road vehicle is blocked, it will * drive just through it. The ultimate backup-code of TTD. * It can be disabled. */ if (rvf.best_diff == UINT_MAX) { front->blocked_ctr = 0; return NULL; } if (update_blocked_ctr && ++front->blocked_ctr > 1480) return NULL; return RoadVehicle::From(rvf.best); } /** * A road vehicle arrives at a station. If it is the first time, create a news item. * @param v Road vehicle that arrived. * @param st Station where the road vehicle arrived. */ static void RoadVehArrivesAt(const RoadVehicle *v, Station *st) { if (v->IsBus()) { /* Check if station was ever visited before */ if (!(st->had_vehicle_of_type & HVOT_BUS)) { st->had_vehicle_of_type |= HVOT_BUS; SetDParam(0, st->index); AddVehicleNewsItem( v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index ); AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index)); Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index)); } } else { /* Check if station was ever visited before */ if (!(st->had_vehicle_of_type & HVOT_TRUCK)) { st->had_vehicle_of_type |= HVOT_TRUCK; SetDParam(0, st->index); AddVehicleNewsItem( v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index ); AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index)); Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index)); } } } /** * This function looks at the vehicle and updates its speed (cur_speed * and subspeed) variables. Furthermore, it returns the distance that * the vehicle can drive this tick. #Vehicle::GetAdvanceDistance() determines * the distance to drive before moving a step on the map. * @return distance to drive. */ int RoadVehicle::UpdateSpeed() { switch (_settings_game.vehicle.roadveh_acceleration_model) { default: NOT_REACHED(); case AM_ORIGINAL: return this->DoUpdateSpeed(this->overtaking != 0 ? 512 : 256, 0, this->GetCurrentMaxSpeed()); case AM_REALISTIC: return this->DoUpdateSpeed(this->GetAcceleration() + (this->overtaking != 0 ? 256 : 0), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 4, this->GetCurrentMaxSpeed()); } } static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y) { static const Direction _roadveh_new_dir[] = { DIR_N , DIR_NW, DIR_W , INVALID_DIR, DIR_NE, DIR_N , DIR_SW, INVALID_DIR, DIR_E , DIR_SE, DIR_S }; x = x - v->x_pos + 1; y = y - v->y_pos + 1; if ((uint)x > 2 || (uint)y > 2) return v->direction; return _roadveh_new_dir[y * 4 + x]; } static Direction RoadVehGetSlidingDirection(const RoadVehicle *v, int x, int y) { Direction new_dir = RoadVehGetNewDirection(v, x, y); Direction old_dir = v->direction; DirDiff delta; if (new_dir == old_dir) return old_dir; delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT); return ChangeDir(old_dir, delta); } struct OvertakeData { const RoadVehicle *u; const RoadVehicle *v; TileIndex tile; Trackdir trackdir; }; static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data) { const OvertakeData *od = (OvertakeData*)data; return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : NULL; } /** * Check if overtaking is possible on a piece of track * * @param od Information about the tile and the involved vehicles * @return true if we have to abort overtaking */ static bool CheckRoadBlockedForOvertaking(OvertakeData *od) { TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes); TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts); TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits); /* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */ if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true; /* Are there more vehicles on the tile except the two vehicles involved in overtaking */ return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake); } static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u) { OvertakeData od; od.v = v; od.u = u; /* Trams can't overtake other trams */ if (v->roadtype == ROADTYPE_TRAM) return; /* Don't overtake in stations */ if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return; /* For now, articulated road vehicles can't overtake anything. */ if (v->HasArticulatedPart()) return; /* Vehicles are not driving in same direction || direction is not a diagonal direction */ if (v->direction != u->direction || !(v->direction & 1)) return; /* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */ if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return; /* Can't overtake a vehicle that is moving faster than us. If the vehicle in front is * accelerating, take the maximum speed for the comparison, else the current speed. * Original acceleration always accelerates, so always use the maximum speed. */ int u_speed = (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL || u->GetAcceleration() > 0) ? u->GetCurrentMaxSpeed() : u->cur_speed; if (u_speed >= v->GetCurrentMaxSpeed() && !(u->vehstatus & VS_STOPPED) && u->cur_speed != 0) { return; } od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction)); /* Are the current and the next tile suitable for overtaking? * - Does the track continue along od.trackdir * - No junctions * - No barred levelcrossing * - No other vehicles in the way */ od.tile = v->tile; if (CheckRoadBlockedForOvertaking(&od)) return; od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction)); if (CheckRoadBlockedForOvertaking(&od)) return; /* When the vehicle in front of us is stopped we may only take * half the time to pass it than when the vehicle is moving. */ v->overtaking_ctr = (od.u->cur_speed == 0 || (od.u->vehstatus & VS_STOPPED)) ? RV_OVERTAKE_TIMEOUT / 2 : 0; v->overtaking = RVSB_DRIVE_SIDE; } static void RoadZPosAffectSpeed(RoadVehicle *v, int old_z) { if (old_z == v->z_pos || _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) return; if (old_z < v->z_pos) { v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10% } else { uint16 spd = v->cur_speed + 2; if (spd <= v->vcache.cached_max_speed) v->cur_speed = spd; } } static int PickRandomBit(uint bits) { uint i; uint num = RandomRange(CountBits(bits)); for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {} return i; } /** * Returns direction to for a road vehicle to take or * INVALID_TRACKDIR if the direction is currently blocked * @param v the Vehicle to do the pathfinding for * @param tile the where to start the pathfinding * @param enterdir the direction the vehicle enters the tile from * @return the Trackdir to take */ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection enterdir) { #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; } TileIndex desttile; Trackdir best_track; bool path_found = true; TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes); TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts); if (IsTileType(tile, MP_ROAD)) { if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) { /* Road depot owned by another company or with the wrong orientation */ trackdirs = TRACKDIR_BIT_NONE; } } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) { /* Standard road stop (drive-through stops are treated as normal road) */ if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) { /* different station owner or wrong orientation or the vehicle has articulated parts */ trackdirs = TRACKDIR_BIT_NONE; } else { /* Our station */ RoadStopType rstype = v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK; if (GetRoadStopType(tile) != rstype) { /* Wrong station type */ trackdirs = TRACKDIR_BIT_NONE; } else { /* Proper station type, check if there is free loading bay */ if (!_settings_game.pf.roadveh_queue && IsStandardRoadStopTile(tile) && !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) { /* Station is full and RV queuing is off */ trackdirs = TRACKDIR_BIT_NONE; } } } } /* The above lookups should be moved to GetTileTrackStatus in the * future, but that requires more changes to the pathfinder and other * stuff, probably even more arguments to GTTS. */ /* Remove tracks unreachable from the enter dir */ trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir]; if (trackdirs == TRACKDIR_BIT_NONE) { /* No reachable tracks, so we'll reverse */ return_track(_road_reverse_table[enterdir]); } if (v->reverse_ctr != 0) { bool reverse = true; if (v->roadtype == ROADTYPE_TRAM) { /* Trams may only reverse on a tile if it contains at least the straight * trackbits or when it is a valid turning tile (i.e. one roadbit) */ RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM); RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir)); reverse = ((rb & straight) == straight) || (rb == DiagDirToRoadBits(enterdir)); } if (reverse) { v->reverse_ctr = 0; if (v->tile != tile) { return_track(_road_reverse_table[enterdir]); } } } desttile = v->dest_tile; if (desttile == 0) { /* We've got no destination, pick a random track */ return_track(PickRandomBit(trackdirs)); } /* Only one track to choose between? */ if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) { return_track(FindFirstBit2x64(trackdirs)); } switch (_settings_game.pf.pathfinder_for_roadvehs) { case VPF_NPF: best_track = NPFRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found); break; case VPF_YAPF: best_track = YapfRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found); break; default: NOT_REACHED(); } v->HandlePathfindingResult(path_found); found_best_track:; if (HasBit(red_signals, best_track)) return INVALID_TRACKDIR; return best_track; } struct RoadDriveEntry { byte x, y; }; #include "table/roadveh_movement.h" static bool RoadVehLeaveDepot(RoadVehicle *v, bool first) { /* Don't leave unless v and following wagons are in the depot. */ for (const RoadVehicle *u = v; u != NULL; u = u->Next()) { if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false; } DiagDirection dir = GetRoadDepotDirection(v->tile); v->direction = DiagDirToDir(dir); Trackdir tdir = _roadveh_depot_exit_trackdir[dir]; const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir]; int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF); int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF); if (first) { /* We are leaving a depot, but have to go to the exact same one; re-enter */ if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) { VehicleEnterDepot(v); return true; } if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true; VehicleServiceInDepot(v); StartRoadVehSound(v); /* Vehicle is about to leave a depot */ v->cur_speed = 0; } v->vehstatus &= ~VS_HIDDEN; v->state = tdir; v->frame = RVC_DEPOT_START_FRAME; v->x_pos = x; v->y_pos = y; v->UpdatePosition(); v->UpdateInclination(true, true); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); return true; } static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed) { if (prev->tile == v->tile && !already_reversed) { /* If the previous vehicle is on the same tile as this vehicle is * then it must have reversed. */ return _road_reverse_table[entry_dir]; } byte prev_state = prev->state; Trackdir dir; if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) { DiagDirection diag_dir = INVALID_DIAGDIR; if (IsTileType(tile, MP_TUNNELBRIDGE)) { diag_dir = GetTunnelBridgeDirection(tile); } else if (IsRoadDepotTile(tile)) { diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile)); } if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR; dir = DiagDirToDiagTrackdir(diag_dir); } else { if (already_reversed && prev->tile != tile) { /* * The vehicle has reversed, but did not go straight back. * It immediately turn onto another tile. This means that * the roadstate of the previous vehicle cannot be used * as the direction we have to go with this vehicle. * * Next table is build in the following way: * - first row for when the vehicle in front went to the northern or * western tile, second for southern and eastern. * - columns represent the entry direction. * - cell values are determined by the Trackdir one has to take from * the entry dir (column) to the tile in north or south by only * going over the trackdirs used for turning 90 degrees, i.e. * TRACKDIR_{UPPER,RIGHT,LOWER,LEFT}_{N,E,S,W}. */ static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = { { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E }, { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }}; dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)]; } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) { dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK); } else if (prev_state < TRACKDIR_END) { dir = (Trackdir)prev_state; } else { return INVALID_TRACKDIR; } } /* Do some sanity checking. */ static const RoadBits required_roadbits[] = { ROAD_X, ROAD_Y, ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE, ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X, ROAD_Y }; RoadBits required = required_roadbits[dir & 0x07]; if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) { dir = INVALID_TRACKDIR; } return dir; } /** * Can a tram track build without destruction on the given tile? * @param c the company that would be building the tram tracks * @param t the tile to build on. * @param r the road bits needed. * @return true when a track track can be build on 't' */ static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r) { /* The 'current' company is not necessarily the owner of the vehicle. */ Backup cur_company(_current_company, c, FILE_LINE); CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NO_WATER, CMD_BUILD_ROAD); cur_company.Restore(); return ret.Succeeded(); } bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev) { if (v->overtaking != 0) { if (IsTileType(v->tile, MP_STATION)) { /* Force us to be not overtaking! */ v->overtaking = 0; } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) { /* If overtaking just aborts at a random moment, we can have a out-of-bound problem, * if the vehicle started a corner. To protect that, only allow an abort of * overtake if we are on straight roads */ if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) { v->overtaking = 0; } } } /* If this vehicle is in a depot and we've reached this point it must be * one of the articulated parts. It will stay in the depot until activated * by the previous vehicle in the chain when it gets to the right place. */ if (v->IsInDepot()) return true; if (v->state == RVSB_WORMHOLE) { /* Vehicle is entering a depot or is on a bridge or in a tunnel */ GetNewVehiclePosResult gp = GetNewVehiclePos(v); if (v->IsFrontEngine()) { const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction); if (u != NULL) { v->cur_speed = u->First()->cur_speed; return false; } } if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { /* Vehicle has just entered a bridge or tunnel */ v->x_pos = gp.x; v->y_pos = gp.y; v->UpdatePosition(); v->UpdateInclination(true, true); return true; } v->x_pos = gp.x; v->y_pos = gp.y; v->UpdatePosition(); if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true); return true; } /* Get move position data for next frame. * For a drive-through road stop use 'straight road' move data. * In this case v->state is masked to give the road stop entry direction. */ RoadDriveEntry rd = _road_drive_data[v->roadtype][( (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1]; if (rd.x & RDE_NEXT_TILE) { TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3)); Trackdir dir; if (v->IsFrontEngine()) { /* If this is the front engine, look for the right path. */ dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3)); } else { dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false); } if (dir == INVALID_TRACKDIR) { if (!v->IsFrontEngine()) error("Disconnecting road vehicle."); v->cur_speed = 0; return false; } again: uint start_frame = RVC_DEFAULT_START_FRAME; if (IsReversingRoadTrackdir(dir)) { /* When turning around we can't be overtaking. */ v->overtaking = 0; /* Turning around */ if (v->roadtype == ROADTYPE_TRAM) { /* Determine the road bits the tram needs to be able to turn around * using the 'big' corner loop. */ RoadBits needed; switch (dir) { default: NOT_REACHED(); case TRACKDIR_RVREV_NE: needed = ROAD_SW; break; case TRACKDIR_RVREV_SE: needed = ROAD_NW; break; case TRACKDIR_RVREV_SW: needed = ROAD_NE; break; case TRACKDIR_RVREV_NW: needed = ROAD_SE; break; } if ((v->Previous() != NULL && v->Previous()->tile == tile) || (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) && (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) { /* * Taking the 'big' corner for trams only happens when: * - The previous vehicle in this (articulated) tram chain is * already on the 'next' tile, we just follow them regardless of * anything. When it is NOT on the 'next' tile, the tram started * doing a reversing turn when the piece of tram track on the next * tile did not exist yet. Do not use the big tram loop as that is * going to cause the tram to split up. * - Or the front of the tram can drive over the next tile. */ } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) { /* * Taking the 'small' corner for trams only happens when: * - We are not the from vehicle of an articulated tram. * - Or when the company cannot build on the next tile. * * The 'small' corner means that the vehicle is on the end of a * tram track and needs to start turning there. To do this properly * the tram needs to start at an offset in the tram turning 'code' * for 'big' corners. It furthermore does not go to the next tile, * so that needs to be fixed too. */ tile = v->tile; start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM; } else { /* The company can build on the next tile, so wait till (s)he does. */ v->cur_speed = 0; return false; } } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) { v->cur_speed = 0; return false; } else { tile = v->tile; } } /* Get position data for first frame on the new tile */ const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking]; int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x; int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y; Direction new_dir = RoadVehGetSlidingDirection(v, x, y); if (v->IsFrontEngine()) { Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir); if (u != NULL) { v->cur_speed = u->First()->cur_speed; return false; } } uint32 r = VehicleEnterTile(v, tile, x, y); if (HasBit(r, VETS_CANNOT_ENTER)) { if (!IsTileType(tile, MP_TUNNELBRIDGE)) { v->cur_speed = 0; return false; } /* Try an about turn to re-enter the previous tile */ dir = _road_reverse_table[rd.x & 3]; goto again; } if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) { if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) { /* New direction is trying to turn vehicle around. * We can't turn at the exit of a road stop so wait.*/ v->cur_speed = 0; return false; } /* If we are a drive through road stop and the next tile is of * the same road stop and the next tile isn't this one (i.e. we * are not reversing), then keep the reservation and state. * This way we will not be shortly unregister from the road * stop. It also makes it possible to load when on the edge of * two road stops; otherwise you could get vehicles that should * be loading but are not actually loading. */ if (IsDriveThroughStopTile(v->tile) && RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) && v->tile != tile) { /* So, keep 'our' state */ dir = (Trackdir)v->state; } else if (IsRoadStop(v->tile)) { /* We're not continuing our drive through road stop, so leave. */ RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v); } } if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { v->tile = tile; v->state = (byte)dir; v->frame = start_frame; } if (new_dir != v->direction) { v->direction = new_dir; if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2; } v->x_pos = x; v->y_pos = y; v->UpdatePosition(); RoadZPosAffectSpeed(v, v->UpdateInclination(true, true)); return true; } if (rd.x & RDE_TURNED) { /* Vehicle has finished turning around, it will now head back onto the same tile */ Trackdir dir; uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME; if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) { /* * The tram is turning around with one tram 'roadbit'. This means that * it is using the 'big' corner 'drive data'. However, to support the * trams to take a small corner, there is a 'turned' marker in the middle * of the turning 'drive data'. When the tram took the long corner, we * will still use the 'big' corner drive data, but we advance it one * frame. We furthermore set the driving direction so the turning is * going to be properly shown. */ turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM; switch (rd.x & 0x3) { default: NOT_REACHED(); case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break; case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break; case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break; case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break; } } else { if (v->IsFrontEngine()) { /* If this is the front engine, look for the right path. */ dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3)); } else { dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true); } } if (dir == INVALID_TRACKDIR) { v->cur_speed = 0; return false; } const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir]; int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x; int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y; Direction new_dir = RoadVehGetSlidingDirection(v, x, y); if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false; uint32 r = VehicleEnterTile(v, v->tile, x, y); if (HasBit(r, VETS_CANNOT_ENTER)) { v->cur_speed = 0; return false; } v->state = dir; v->frame = turn_around_start_frame; if (new_dir != v->direction) { v->direction = new_dir; if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2; } v->x_pos = x; v->y_pos = y; v->UpdatePosition(); RoadZPosAffectSpeed(v, v->UpdateInclination(true, true)); return true; } /* This vehicle is not in a wormhole and it hasn't entered a new tile. If * it's on a depot tile, check if it's time to activate the next vehicle in * the chain yet. */ if (v->Next() != NULL && IsRoadDepotTile(v->tile)) { if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) { RoadVehLeaveDepot(v->Next(), false); } } /* Calculate new position for the vehicle */ int x = (v->x_pos & ~15) + (rd.x & 15); int y = (v->y_pos & ~15) + (rd.y & 15); Direction new_dir = RoadVehGetSlidingDirection(v, x, y); if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) { /* Vehicle is not in a road stop. * Check for another vehicle to overtake */ RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir); if (u != NULL) { u = u->First(); /* There is a vehicle in front overtake it if possible */ if (v->overtaking == 0) RoadVehCheckOvertake(v, u); if (v->overtaking == 0) v->cur_speed = u->cur_speed; /* In case an RV is stopped in a road stop, why not try to load? */ if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) && v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) && GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) { Station *st = Station::GetByTile(v->tile); v->last_station_visited = st->index; RoadVehArrivesAt(v, st); v->BeginLoading(); } return false; } } Direction old_dir = v->direction; if (new_dir != old_dir) { v->direction = new_dir; if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2; /* Delay the vehicle in curves by making it require one additional frame per turning direction (two in total). * A vehicle has to spend at least 9 frames on a tile, so the following articulated part can follow. * (The following part may only be one tile behind, and the front part is moved before the following ones.) * The short (inner) curve has 8 frames, this elongates it to 10. */ v->UpdateInclination(false, true); return true; } /* If the vehicle is in a normal road stop and the frame equals the stop frame OR * if the vehicle is in a drive-through road stop and this is the destination station * and it's the correct type of stop (bus or truck) and the frame equals the stop frame... * (the station test and stop type test ensure that other vehicles, using the road stop as * a through route, do not stop) */ if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) && _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) || (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) && v->owner == GetTileOwner(v->tile) && GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) && v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) { RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile)); Station *st = Station::GetByTile(v->tile); /* Vehicle is at the stop position (at a bay) in a road stop. * Note, if vehicle is loading/unloading it has already been handled, * so if we get here the vehicle has just arrived or is just ready to leave. */ if (!HasBit(v->state, RVS_ENTERED_STOP)) { /* Vehicle has arrived at a bay in a road stop */ if (IsDriveThroughStopTile(v->tile)) { TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction)); /* Check if next inline bay is free and has compatible road. */ if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) { v->frame++; v->x_pos = x; v->y_pos = y; v->UpdatePosition(); RoadZPosAffectSpeed(v, v->UpdateInclination(true, false)); return true; } } rs->SetEntranceBusy(false); SetBit(v->state, RVS_ENTERED_STOP); v->last_station_visited = st->index; if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) { RoadVehArrivesAt(v, st); v->BeginLoading(); return false; } } else { /* Vehicle is ready to leave a bay in a road stop */ if (rs->IsEntranceBusy()) { /* Road stop entrance is busy, so wait as there is nowhere else to go */ v->cur_speed = 0; return false; } if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free(); } if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true); StartRoadVehSound(v); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } /* Check tile position conditions - i.e. stop position in depot, * entry onto bridge or into tunnel */ uint32 r = VehicleEnterTile(v, v->tile, x, y); if (HasBit(r, VETS_CANNOT_ENTER)) { v->cur_speed = 0; return false; } if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) { v->current_order.Free(); } /* Move to next frame unless vehicle arrived at a stop position * in a depot or entered a tunnel/bridge */ if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++; v->x_pos = x; v->y_pos = y; v->UpdatePosition(); RoadZPosAffectSpeed(v, v->UpdateInclination(false, true)); return true; } static bool RoadVehController(RoadVehicle *v) { /* decrease counters */ v->current_order_time++; if (v->reverse_ctr != 0) v->reverse_ctr--; /* handle crashed */ if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) { return RoadVehIsCrashed(v); } /* road vehicle has broken down? */ if (v->HandleBreakdown()) return true; if (v->vehstatus & VS_STOPPED) return true; ProcessOrders(v); v->HandleLoading(); if (v->current_order.IsType(OT_LOADING)) return true; if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true; v->ShowVisualEffect(); /* Check how far the vehicle needs to proceed */ int j = v->UpdateSpeed(); int adv_spd = v->GetAdvanceDistance(); bool blocked = false; while (j >= adv_spd) { j -= adv_spd; RoadVehicle *u = v; for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) { if (!IndividualRoadVehicleController(u, prev)) { blocked = true; break; } } if (blocked) break; /* Determine distance to next map position */ adv_spd = v->GetAdvanceDistance(); /* Test for a collision, but only if another movement will occur. */ if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break; } v->SetLastSpeed(); for (RoadVehicle *u = v; u != NULL; u = u->Next()) { if ((u->vehstatus & VS_HIDDEN) != 0) continue; u->UpdateViewport(false, false); } /* If movement is blocked, set 'progress' to its maximum, so the roadvehicle does * not accelerate again before it can actually move. I.e. make sure it tries to advance again * on next tick to discover whether it is still blocked. */ if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j; return true; } Money RoadVehicle::GetRunningCost() const { const Engine *e = this->GetEngine(); if (e->u.road.running_cost_class == INVALID_PRICE) return 0; uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost); if (cost_factor == 0) return 0; return GetPrice(e->u.road.running_cost_class, cost_factor, e->GetGRF()); } bool RoadVehicle::Tick() { this->tick_counter++; if (this->IsFrontEngine()) { if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; return RoadVehController(this); } return true; } static void CheckIfRoadVehNeedsService(RoadVehicle *v) { /* If we already got a slot at a stop, use that FIRST, and go to a depot later */ if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return; if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } uint max_penalty; switch (_settings_game.pf.pathfinder_for_roadvehs) { case VPF_NPF: max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty; break; case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break; default: NOT_REACHED(); } FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty); /* Only go to the depot if it is not too far out of our way. */ if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) { if (v->current_order.IsType(OT_GOTO_DEPOT)) { /* If we were already heading for a depot but it has * suddenly moved farther away, we continue our normal * schedule? */ v->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } return; } DepotID depot = GetDepotIndex(rfdd.tile); if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS && !Chance16(1, 20)) { return; } SetBit(v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE); v->dest_tile = rfdd.tile; SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } void RoadVehicle::OnNewDay() { AgeVehicle(this); if (!this->IsFrontEngine()) return; if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this); if (this->blocked_ctr == 0) CheckVehicleBreakdown(this); CheckIfRoadVehNeedsService(this); CheckOrders(this); if (this->running_ticks == 0) return; CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS)); this->profit_this_year -= cost.GetCost(); this->running_ticks = 0; SubtractMoneyFromCompanyFract(this->owner, cost); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); SetWindowClassesDirty(WC_ROADVEH_LIST); } Trackdir RoadVehicle::GetVehicleTrackdir() const { if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR; if (this->IsInDepot()) { /* We'll assume the road vehicle is facing outwards */ return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile)); } if (IsStandardRoadStopTile(this->tile)) { /* We'll assume the road vehicle is facing outwards */ return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile)); // Road vehicle in a station } /* Drive through road stops / wormholes (tunnels) */ if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction)); /* If vehicle's state is a valid track direction (vehicle is not turning around) return it, * otherwise transform it into a valid track direction */ return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state); } openttd-1.5.3/src/newgrf_generic.cpp0000644000000000000000000002316412627373435016174 0ustar rootroot/* $Id: newgrf_generic.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_generic.cpp Handling of generic feature callbacks. */ #include "stdafx.h" #include "debug.h" #include "newgrf_spritegroup.h" #include "industrytype.h" #include "core/random_func.hpp" #include "newgrf_sound.h" #include "water_map.h" #include #include "safeguards.h" /** Scope resolver for generic objects and properties. */ struct GenericScopeResolver : public ScopeResolver { CargoID cargo_type; uint8 default_selection; uint8 src_industry; ///< Source industry substitute type. 0xFF for "town", 0xFE for "unknown". uint8 dst_industry; ///< Destination industry substitute type. 0xFF for "town", 0xFE for "unknown". uint8 distance; AIConstructionEvent event; uint8 count; uint8 station_size; GenericScopeResolver(ResolverObject &ro, bool ai_callback); /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; private: bool ai_callback; ///< Callback comes from the AI. }; /** Resolver object for generic objects/properties. */ struct GenericResolverObject : public ResolverObject { GenericScopeResolver generic_scope; GenericResolverObject(bool ai_callback, CallbackID callback = CBID_NO_CALLBACK); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &this->generic_scope; default: return ResolverObject::GetScope(scope, relative); } } /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; }; struct GenericCallback { const GRFFile *file; const SpriteGroup *group; GenericCallback(const GRFFile *file, const SpriteGroup *group) : file(file), group(group) { } }; typedef std::list GenericCallbackList; static GenericCallbackList _gcl[GSF_END]; /** * Reset all generic feature callback sprite groups. */ void ResetGenericCallbacks() { for (uint8 feature = 0; feature < lengthof(_gcl); feature++) { _gcl[feature].clear(); } } /** * Add a generic feature callback sprite group to the appropriate feature list. * @param feature The feature for the callback. * @param file The GRF of the callback. * @param group The sprite group of the callback. */ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *group) { if (feature >= lengthof(_gcl)) { grfmsg(5, "AddGenericCallback: Unsupported feature 0x%02X", feature); return; } /* Generic feature callbacks are evaluated in reverse (i.e. the last group * to be added is evaluated first, etc) thus we push the group to the * beginning of the list so a standard iterator will do the right thing. */ _gcl[feature].push_front(GenericCallback(file, group)); } /* virtual */ uint32 GenericScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { if (this->ai_callback) { switch (variable) { case 0x40: return this->ro.grffile->cargo_map[this->cargo_type]; case 0x80: return this->cargo_type; case 0x81: return CargoSpec::Get(this->cargo_type)->bitnum; case 0x82: return this->default_selection; case 0x83: return this->src_industry; case 0x84: return this->dst_industry; case 0x85: return this->distance; case 0x86: return this->event; case 0x87: return this->count; case 0x88: return this->station_size; default: break; } } DEBUG(grf, 1, "Unhandled generic feature variable 0x%02X", variable); *available = false; return UINT_MAX; } /* virtual */ const SpriteGroup *GenericResolverObject::ResolveReal(const RealSpriteGroup *group) const { if (group->num_loaded == 0) return NULL; return group->loaded[0]; } /** * Generic resolver. * @param ai_callback Callback comes from the AI. * @param callback Callback ID. */ GenericResolverObject::GenericResolverObject(bool ai_callback, CallbackID callback) : ResolverObject(NULL, callback), generic_scope(*this, ai_callback) { } /** * Generic scope resolver. * @param ro Surrounding resolver. * @param ai_callback Callback comes from the AI. */ GenericScopeResolver::GenericScopeResolver(ResolverObject &ro, bool ai_callback) : ScopeResolver(ro) { this->cargo_type = 0; this->default_selection = 0; this->src_industry = 0; this->dst_industry = 0; this->distance = 0; this->event = (AIConstructionEvent)0; this->count = 0; this->station_size = 0; this->ai_callback = ai_callback; } /** * Follow a generic feature callback list and return the first successful * answer * @param feature GRF Feature of callback * @param object pre-populated resolver object * @param param1_grfv7 callback_param1 for GRFs up to version 7. * @param param1_grfv8 callback_param1 for GRFs from version 8 on. * @param [out] file Optionally returns the GRFFile which made the final decision for the callback result. * May be NULL if not required. * @return callback value if successful or CALLBACK_FAILED */ static uint16 GetGenericCallbackResult(uint8 feature, ResolverObject &object, uint32 param1_grfv7, uint32 param1_grfv8, const GRFFile **file) { assert(feature < lengthof(_gcl)); /* Test each feature callback sprite group. */ for (GenericCallbackList::const_iterator it = _gcl[feature].begin(); it != _gcl[feature].end(); ++it) { object.grffile = it->file; object.root_spritegroup = it->group; /* Set callback param based on GRF version. */ object.callback_param1 = it->file->grf_version >= 8 ? param1_grfv8 : param1_grfv7; uint16 result = object.ResolveCallback(); if (result == CALLBACK_FAILED) continue; /* Return NewGRF file if necessary */ if (file != NULL) *file = it->file; return result; } /* No callback returned a valid result, so we've failed. */ return CALLBACK_FAILED; } /** * 'Execute' an AI purchase selection callback * * @param feature GRF Feature to call callback for. * @param cargo_type Cargotype to pass to callback. (Variable 80) * @param default_selection 'Default selection' to pass to callback. (Variable 82) * @param src_industry 'Source industry type' to pass to callback. (Variable 83) * @param dst_industry 'Destination industry type' to pass to callback. (Variable 84) * @param distance 'Distance between source and destination' to pass to callback. (Variable 85) * @param event 'AI construction event' to pass to callback. (Variable 86) * @param count 'Construction number' to pass to callback. (Variable 87) * @param station_size 'Station size' to pass to callback. (Variable 88) * @param [out] file Optionally returns the GRFFile which made the final decision for the callback result. * May be NULL if not required. * @return callback value if successful or CALLBACK_FAILED */ uint16 GetAiPurchaseCallbackResult(uint8 feature, CargoID cargo_type, uint8 default_selection, IndustryType src_industry, IndustryType dst_industry, uint8 distance, AIConstructionEvent event, uint8 count, uint8 station_size, const GRFFile **file) { GenericResolverObject object(true, CBID_GENERIC_AI_PURCHASE_SELECTION); if (src_industry != IT_AI_UNKNOWN && src_industry != IT_AI_TOWN) { const IndustrySpec *is = GetIndustrySpec(src_industry); /* If this is no original industry, use the substitute type */ if (is->grf_prop.subst_id != INVALID_INDUSTRYTYPE) src_industry = is->grf_prop.subst_id; } if (dst_industry != IT_AI_UNKNOWN && dst_industry != IT_AI_TOWN) { const IndustrySpec *is = GetIndustrySpec(dst_industry); /* If this is no original industry, use the substitute type */ if (is->grf_prop.subst_id != INVALID_INDUSTRYTYPE) dst_industry = is->grf_prop.subst_id; } object.generic_scope.cargo_type = cargo_type; object.generic_scope.default_selection = default_selection; object.generic_scope.src_industry = src_industry; object.generic_scope.dst_industry = dst_industry; object.generic_scope.distance = distance; object.generic_scope.event = event; object.generic_scope.count = count; object.generic_scope.station_size = station_size; uint16 callback = GetGenericCallbackResult(feature, object, 0, 0, file); if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8); return callback; } /** * 'Execute' the ambient sound effect callback. * @param tile Tile the sound effect should be generated for. */ void AmbientSoundEffectCallback(TileIndex tile) { assert(IsTileType(tile, MP_CLEAR) || IsTileType(tile, MP_TREES) || IsTileType(tile, MP_WATER)); /* Only run every 1/200-th time. */ uint32 r; // Save for later if (!Chance16R(1, 200, r) || !_settings_client.sound.ambient) return; /* Prepare resolver object. */ GenericResolverObject object(false, CBID_SOUNDS_AMBIENT_EFFECT); uint32 param1_v7 = GetTileType(tile) << 28 | Clamp(TileHeight(tile), 0, 15) << 24 | GB(r, 16, 8) << 16 | GetTerrainType(tile); uint32 param1_v8 = GetTileType(tile) << 24 | GetTileZ(tile) << 16 | GB(r, 16, 8) << 8 | (HasTileWaterClass(tile) ? GetWaterClass(tile) : 0) << 3 | GetTerrainType(tile); /* Run callback. */ const GRFFile *grf_file; uint16 callback = GetGenericCallbackResult(GSF_SOUNDFX, object, param1_v7, param1_v8, &grf_file); if (callback != CALLBACK_FAILED) PlayTileSound(grf_file, callback, tile); } openttd-1.5.3/src/waypoint_cmd.cpp0000644000000000000000000003430312627373443015701 0ustar rootroot/* $Id: waypoint_cmd.cpp 26879 2014-09-21 11:24:51Z rubidium $ */ /* * 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 waypoint_cmd.cpp %Command Handling for waypoints. */ #include "stdafx.h" #include "cmd_helper.h" #include "command_func.h" #include "landscape.h" #include "bridge_map.h" #include "town.h" #include "waypoint_base.h" #include "pathfinder/yapf/yapf_cache.h" #include "strings_func.h" #include "viewport_func.h" #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" #include "string_func.h" #include "company_func.h" #include "newgrf_station.h" #include "company_base.h" #include "water.h" #include "company_gui.h" #include "table/strings.h" #include "safeguards.h" /** * Update the virtual coords needed to draw the waypoint sign. */ void Waypoint::UpdateVirtCoord() { Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE); SetDParam(0, this->index); this->sign.UpdatePosition(pt.x, pt.y - 32 * ZOOM_LVL_BASE, STR_VIEWPORT_WAYPOINT); /* Recenter viewport */ InvalidateWindowData(WC_WAYPOINT_VIEW, this->index); } /** * Find a deleted waypoint close to a tile. * @param tile to search from * @param str the string to get the 'type' of * @param cid previous owner of the waypoint * @return the deleted nearby waypoint */ static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile, StringID str, CompanyID cid) { Waypoint *wp, *best = NULL; uint thres = 8; FOR_ALL_WAYPOINTS(wp) { if (!wp->IsInUse() && wp->string_id == str && wp->owner == cid) { uint cur_dist = DistanceManhattan(tile, wp->xy); if (cur_dist < thres) { thres = cur_dist; best = wp; } } } return best; } /** * Get the axis for a new waypoint. This means that if it is a valid * tile to build a waypoint on it returns a valid Axis, otherwise an * invalid one. * @param tile the tile to look at. * @return the axis for the to-be-build waypoint. */ Axis GetAxisForNewWaypoint(TileIndex tile) { /* The axis for rail waypoints is easy. */ if (IsRailWaypointTile(tile)) return GetRailStationAxis(tile); /* Non-plain rail type, no valid axis for waypoints. */ if (!IsTileType(tile, MP_RAILWAY) || GetRailTileType(tile) != RAIL_TILE_NORMAL) return INVALID_AXIS; switch (GetTrackBits(tile)) { case TRACK_BIT_X: return AXIS_X; case TRACK_BIT_Y: return AXIS_Y; default: return INVALID_AXIS; } } extern CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags); /** * Check whether the given tile is suitable for a waypoint. * @param tile the tile to check for suitability * @param axis the axis of the waypoint * @param waypoint Waypoint the waypoint to check for is already joined to. If we find another waypoint it can join to it will throw an error. */ static CommandCost IsValidTileForWaypoint(TileIndex tile, Axis axis, StationID *waypoint) { /* if waypoint is set, then we have special handling to allow building on top of already existing waypoints. * so waypoint points to INVALID_STATION if we can build on any waypoint. * Or it points to a waypoint if we're only allowed to build on exactly that waypoint. */ if (waypoint != NULL && IsTileType(tile, MP_STATION)) { if (!IsRailWaypoint(tile)) { return ClearTile_Station(tile, DC_AUTO); // get error message } else { StationID wp = GetStationIndex(tile); if (*waypoint == INVALID_STATION) { *waypoint = wp; } else if (*waypoint != wp) { return_cmd_error(STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING); } } } if (GetAxisForNewWaypoint(tile) != axis) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); Owner owner = GetTileOwner(tile); CommandCost ret = CheckOwnership(owner); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; Slope tileh = GetTileSlope(tile); if (tileh != SLOPE_FLAT && (!_settings_game.construction.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))) { return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); } if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); return CommandCost(); } extern void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec); extern CommandCost FindJoiningWaypoint(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Waypoint **wp); extern CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis axis); /** * Convert existing rail to waypoint. Eg build a waypoint station over * piece of rail * @param start_tile northern most tile where waypoint will be built * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 4) - orientation (Axis) * - p1 = (bit 8-15) - width of waypoint * - p1 = (bit 16-23) - height of waypoint * - p1 = (bit 24) - allow waypoints directly adjacent to other waypoints. * @param p2 various bitstuffed elements * - p2 = (bit 0- 7) - custom station class * - p2 = (bit 8-15) - custom station id * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* Unpack parameters */ Axis axis = Extract(p1); byte width = GB(p1, 8, 8); byte height = GB(p1, 16, 8); bool adjacent = HasBit(p1, 24); StationClassID spec_class = Extract(p2); byte spec_index = GB(p2, 8, 8); StationID station_to_join = GB(p2, 16, 16); /* Check if the given station class is valid */ if (spec_class != STAT_CLASS_WAYP) return CMD_ERROR; if (spec_index >= StationClass::Get(spec_class)->GetSpecCount()) return CMD_ERROR; /* The number of parts to build */ byte count = axis == AXIS_X ? height : width; if ((axis == AXIS_X ? width : height) != 1) return CMD_ERROR; if (count == 0 || count > _settings_game.station.station_spread) return CMD_ERROR; bool reuse = (station_to_join != NEW_STATION); if (!reuse) station_to_join = INVALID_STATION; bool distant_join = (station_to_join != INVALID_STATION); if (distant_join && (!_settings_game.station.distant_join_stations || !Waypoint::IsValidID(station_to_join))) return CMD_ERROR; /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */ StationID est = INVALID_STATION; /* Check whether the tiles we're building on are valid rail or not. */ TileIndexDiff offset = TileOffsByDiagDir(AxisToDiagDir(OtherAxis(axis))); for (int i = 0; i < count; i++) { TileIndex tile = start_tile + i * offset; CommandCost ret = IsValidTileForWaypoint(tile, axis, &est); if (ret.Failed()) return ret; } Waypoint *wp = NULL; TileArea new_location(TileArea(start_tile, width, height)); CommandCost ret = FindJoiningWaypoint(est, station_to_join, adjacent, new_location, &wp); if (ret.Failed()) return ret; /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */ TileIndex center_tile = start_tile + (count / 2) * offset; if (wp == NULL && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT, _current_company); if (wp != NULL) { /* Reuse an existing waypoint. */ if (wp->owner != _current_company) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT); /* check if we want to expand an already existing waypoint? */ if (wp->train_station.tile != INVALID_TILE) { CommandCost ret = CanExpandRailStation(wp, new_location, axis); if (ret.Failed()) return ret; } CommandCost ret = wp->rect.BeforeAddRect(start_tile, width, height, StationRect::ADD_TEST); if (ret.Failed()) return ret; } else { /* allocate and initialize new waypoint */ if (!Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING); } if (flags & DC_EXEC) { if (wp == NULL) { wp = new Waypoint(start_tile); } else if (!wp->IsInUse()) { /* Move existing (recently deleted) waypoint to the new location */ wp->xy = start_tile; } wp->owner = GetTileOwner(start_tile); wp->rect.BeforeAddRect(start_tile, width, height, StationRect::ADD_TRY); wp->delete_ctr = 0; wp->facilities |= FACIL_TRAIN; wp->build_date = _date; wp->string_id = STR_SV_STNAME_WAYPOINT; wp->train_station = new_location; if (wp->town == NULL) MakeDefaultName(wp); wp->UpdateVirtCoord(); const StationSpec *spec = StationClass::Get(spec_class)->GetSpec(spec_index); byte *layout_ptr = AllocaM(byte, count); if (spec == NULL) { /* The layout must be 0 for the 'normal' waypoints by design. */ memset(layout_ptr, 0, count); } else { /* But for NewGRF waypoints we like to have their style. */ GetStationLayout(layout_ptr, count, 1, spec); } byte map_spec_index = AllocateSpecToStation(spec, wp, true); Company *c = Company::Get(wp->owner); for (int i = 0; i < count; i++) { TileIndex tile = start_tile + i * offset; byte old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0; if (!HasStationTileRail(tile)) c->infrastructure.station++; bool reserved = IsTileType(tile, MP_RAILWAY) ? HasBit(GetRailReservationTrackBits(tile), AxisToTrack(axis)) : HasStationReservation(tile); MakeRailWaypoint(tile, wp->owner, wp->index, axis, layout_ptr[i], GetRailType(tile)); SetCustomStationSpecIndex(tile, map_spec_index); SetRailStationReservation(tile, reserved); MarkTileDirtyByTile(tile); DeallocateSpecFromStation(wp, old_specindex); YapfNotifyTrackLayoutChange(tile, AxisToTrack(axis)); } DirtyCompanyInfrastructureWindows(wp->owner); } return CommandCost(EXPENSES_CONSTRUCTION, count * _price[PR_BUILD_WAYPOINT_RAIL]); } /** * Build a buoy. * @param tile tile where to place the buoy * @param flags operation to perform * @param p1 unused * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (tile == 0 || !HasTileWaterGround(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); if (!IsTileFlat(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */ Waypoint *wp = FindDeletedWaypointCloseTo(tile, STR_SV_STNAME_BUOY, OWNER_NONE); if (wp == NULL && !Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING); CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_WAYPOINT_BUOY]); if (!IsWaterTile(tile)) { CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); } if (flags & DC_EXEC) { if (wp == NULL) { wp = new Waypoint(tile); } else { /* Move existing (recently deleted) buoy to the new location */ wp->xy = tile; InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index); } wp->rect.BeforeAddTile(tile, StationRect::ADD_TRY); wp->string_id = STR_SV_STNAME_BUOY; wp->facilities |= FACIL_DOCK; wp->owner = OWNER_NONE; wp->build_date = _date; if (wp->town == NULL) MakeDefaultName(wp); MakeBuoy(tile, wp->index, GetWaterClass(tile)); wp->UpdateVirtCoord(); InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index); } return cost; } /** * Remove a buoy * @param tile TileIndex been queried * @param flags operation to perform * @pre IsBuoyTile(tile) * @return cost or failure of operation */ CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags) { /* XXX: strange stuff, allow clearing as invalid company when clearing landscape */ if (!Company::IsValidID(_current_company) && !(flags & DC_BANKRUPT)) return_cmd_error(INVALID_STRING_ID); Waypoint *wp = Waypoint::GetByTile(tile); if (HasStationInUse(wp->index, false, _current_company)) return_cmd_error(STR_ERROR_BUOY_IS_IN_USE); /* remove the buoy if there is a ship on tile when company goes bankrupt... */ if (!(flags & DC_BANKRUPT)) { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; } if (flags & DC_EXEC) { wp->facilities &= ~FACIL_DOCK; InvalidateWindowData(WC_WAYPOINT_VIEW, wp->index); /* We have to set the water tile's state to the same state as before the * buoy was placed. Otherwise one could plant a buoy on a canal edge, * remove it and flood the land (if the canal edge is at level 0) */ MakeWaterKeepingClass(tile, GetTileOwner(tile)); wp->rect.AfterRemoveTile(wp, tile); wp->UpdateVirtCoord(); wp->delete_ctr = 0; } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WAYPOINT_BUOY]); } /** * Check whether the name is unique amongst the waypoints. * @param name The name to check. * @return True iff the name is unique. */ static bool IsUniqueWaypointName(const char *name) { const Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { if (wp->name != NULL && strcmp(wp->name, name) == 0) return false; } return true; } /** * Rename a waypoint. * @param tile unused * @param flags type of operation * @param p1 id of waypoint * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Waypoint *wp = Waypoint::GetIfValid(p1); if (wp == NULL) return CMD_ERROR; if (wp->owner != OWNER_NONE) { CommandCost ret = CheckOwnership(wp->owner); if (ret.Failed()) return ret; } bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_STATION_NAME_CHARS) return CMD_ERROR; if (!IsUniqueWaypointName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { free(wp->name); wp->name = reset ? NULL : stredup(text); wp->UpdateVirtCoord(); } return CommandCost(); } openttd-1.5.3/src/newgrf_airport.h0000644000000000000000000001263412627373435015705 0ustar rootroot/* $Id: newgrf_airport.h 25705 2013-08-09 18:43:44Z rubidium $ */ /* * 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 newgrf_airport.h NewGRF handling of airports. */ #ifndef NEWGRF_AIRPORT_H #define NEWGRF_AIRPORT_H #include "airport.h" #include "date_type.h" #include "newgrf_class.h" #include "newgrf_commons.h" #include "tilearea_type.h" /** Copy from station_map.h */ typedef byte StationGfx; /** Tile-offset / AirportTileID pair. */ struct AirportTileTable { TileIndexDiffC ti; ///< Tile offset from the top-most airport tile. StationGfx gfx; ///< AirportTile to use for this tile. }; /** Iterator to iterate over all tiles belonging to an airport spec. */ class AirportTileTableIterator : public TileIterator { private: const AirportTileTable *att; ///< The offsets. TileIndex base_tile; ///< The tile we base the offsets off. public: /** * Construct the iterator. * @param att The TileTable we want to iterate over. * @param base_tile The basetile for all offsets. */ AirportTileTableIterator(const AirportTileTable *att, TileIndex base_tile) : TileIterator(base_tile + ToTileIndexDiff(att->ti)), att(att), base_tile(base_tile) { } inline TileIterator& operator ++() { this->att++; if (this->att->ti.x == -0x80) { this->tile = INVALID_TILE; } else { this->tile = this->base_tile + ToTileIndexDiff(this->att->ti); } return *this; } /** Get the StationGfx for the current tile. */ StationGfx GetStationGfx() const { return this->att->gfx; } virtual AirportTileTableIterator *Clone() const { return new AirportTileTableIterator(*this); } }; /** List of default airport classes. */ enum AirportClassID { APC_BEGIN = 0, ///< Lowest valid airport class id APC_SMALL = 0, ///< id for small airports class APC_LARGE, ///< id for large airports class APC_HUB, ///< id for hub airports class APC_HELIPORT, ///< id for heliports APC_MAX = 16, ///< maximum number of airport classes }; /** Allow incrementing of AirportClassID variables */ DECLARE_POSTFIX_INCREMENT(AirportClassID) /** TTDP airport types. Used to map our types to TTDPatch's */ enum TTDPAirportType { ATP_TTDP_SMALL, ///< Same as AT_SMALL ATP_TTDP_LARGE, ///< Same as AT_LARGE ATP_TTDP_HELIPORT, ///< Same as AT_HELIPORT ATP_TTDP_OILRIG, ///< Same as AT_OILRIG }; /** A list of all hangar tiles in an airport */ struct HangarTileTable { TileIndexDiffC ti; ///< Tile offset from the top-most airport tile. Direction dir; ///< Direction of the exit. byte hangar_num; ///< The hangar to which this tile belongs. }; /** * Defines the data structure for an airport. */ struct AirportSpec { const struct AirportFTAClass *fsm; ///< the finite statemachine for the default airports const AirportTileTable * const *table; ///< list of the tiles composing the airport Direction *rotation; ///< the rotation of each tiletable byte num_table; ///< number of elements in the table const HangarTileTable *depot_table; ///< gives the position of the depots on the airports byte nof_depots; ///< the number of hangar tiles in this airport byte size_x; ///< size of airport in x direction byte size_y; ///< size of airport in y direction byte noise_level; ///< noise that this airport generates byte catchment; ///< catchment area of this airport Year min_year; ///< first year the airport is available Year max_year; ///< last year the airport is available StringID name; ///< name of this airport TTDPAirportType ttd_airport_type; ///< ttdpatch airport type (Small/Large/Helipad/Oilrig) AirportClassID cls_id; ///< the class to which this airport type belongs SpriteID preview_sprite; ///< preview sprite for this airport uint16 maintenance_cost; ///< maintenance cost multiplier /* Newgrf data */ bool enabled; ///< Entity still available (by default true). Newgrf can disable it, though. struct GRFFileProps grf_prop; ///< Properties related to the grf file. static const AirportSpec *Get(byte type); static AirportSpec *GetWithoutOverride(byte type); bool IsAvailable() const; static void ResetAirports(); /** Get the index of this spec. */ byte GetIndex() const { assert(this >= specs && this < endof(specs)); return (byte)(this - specs); } static AirportSpec dummy; ///< The dummy airport. private: static AirportSpec specs[NUM_AIRPORTS]; ///< Specs of the airports. }; /** Information related to airport classes. */ typedef NewGRFClass AirportClass; void BindAirportSpecs(); StringID GetAirportTextCallback(const AirportSpec *as, byte layout, uint16 callback); #endif /* NEWGRF_AIRPORT_H */ openttd-1.5.3/src/newgrf_townname.h0000644000000000000000000000327512627373435016056 0ustar rootroot/* $Id: newgrf_townname.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 newgrf_townname.h * Header of Action 0F "universal holder" structure and functions */ #ifndef NEWGRF_TOWNNAME_H #define NEWGRF_TOWNNAME_H #include "strings_type.h" struct NamePart { byte prob; ///< The relative probability of the following name to appear in the bottom 7 bits. union { char *text; ///< If probability bit 7 is clear byte id; ///< If probability bit 7 is set } data; }; struct NamePartList { byte partcount; byte bitstart; byte bitcount; uint16 maxprob; NamePart *parts; }; struct GRFTownName { uint32 grfid; byte nb_gen; byte id[128]; StringID name[128]; byte nbparts[128]; NamePartList *partlist[128]; GRFTownName *next; }; GRFTownName *AddGRFTownName(uint32 grfid); GRFTownName *GetGRFTownName(uint32 grfid); void DelGRFTownName(uint32 grfid); void CleanUpGRFTownNames(); StringID *GetGRFTownNameList(); char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last); uint32 GetGRFTownNameId(int gen); uint16 GetGRFTownNameType(int gen); #endif /* NEWGRF_TOWNNAME_H */ openttd-1.5.3/src/table/0000755000000000000000000000000012627373436013566 5ustar rootrootopenttd-1.5.3/src/table/airporttile_ids.h0000644000000000000000000000450212627373436017135 0ustar rootroot/* $Id: airporttile_ids.h 19099 2010-02-11 20:52:56Z yexo $ */ /* * 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 airporttile_ids.h Enum of the default airport tiles. */ #ifndef AIRPORTTILE_IDS_H #define AIRPORTTILE_IDS_H enum AirportTiles { APT_APRON, APT_APRON_FENCE_NW, APT_APRON_FENCE_SW, APT_STAND, APT_APRON_W, APT_APRON_S, APT_APRON_VER_CROSSING_S, APT_APRON_HOR_CROSSING_W, APT_APRON_VER_CROSSING_N, APT_APRON_HOR_CROSSING_E, APT_APRON_E, APT_ARPON_N, APT_APRON_HOR, APT_APRON_N_FENCE_SW, APT_RUNWAY_1, APT_RUNWAY_2, APT_RUNWAY_3, APT_RUNWAY_4, APT_RUNWAY_END_FENCE_SE, APT_BUILDING_2, APT_TOWER_FENCE_SW, APT_ROUND_TERMINAL, APT_BUILDING_3, APT_BUILDING_1, APT_DEPOT_SE, APT_STAND_1, APT_STAND_PIER_NE, APT_PIER_NW_NE, APT_PIER, APT_EMPTY, APT_EMPTY_FENCE_NE, APT_RADAR_GRASS_FENCE_SW, APT_RADIO_TOWER_FENCE_NE, APT_SMALL_BUILDING_3, APT_SMALL_BUILDING_2, APT_SMALL_BUILDING_1, APT_GRASS_FENCE_SW, APT_GRASS_2, APT_GRASS_1, APT_GRASS_FENCE_NE_FLAG, APT_RUNWAY_SMALL_NEAR_END, APT_RUNWAY_SMALL_MIDDLE, APT_RUNWAY_SMALL_FAR_END, APT_SMALL_DEPOT_SE, APT_HELIPORT, APT_RUNWAY_END, APT_RUNWAY_5, APT_TOWER, APT_APRON_FENCE_NE, APT_RUNWAY_END_FENCE_NW, APT_RUNWAY_FENCE_NW, APT_RADAR_FENCE_SW, APT_RADAR_FENCE_NE, APT_HELIPAD_1, APT_HELIPAD_2_FENCE_NW, APT_HELIPAD_2, APT_APRON_FENCE_NE_SW, APT_RUNWAY_END_FENCE_NW_SW, APT_RUNWAY_END_FENCE_SE_SW, APT_RUNWAY_END_FENCE_NE_NW, APT_RUNWAY_END_FENCE_NE_SE, APT_HELIPAD_2_FENCE_NE_SE, APT_APRON_FENCE_SE_SW, APT_LOW_BUILDING_FENCE_N, APT_LOW_BUILDING_FENCE_NW, APT_APRON_FENCE_SE, APT_HELIPAD_3_FENCE_SE_SW, APT_HELIPAD_3_FENCE_NW_SW, APT_HELIPAD_3_FENCE_NW, APT_LOW_BUILDING, APT_APRON_FENCE_NE_SE, APT_APRON_HALF_EAST, APT_APRON_HALF_WEST, APT_GRASS_FENCE_NE_FLAG_2, }; #endif /* AIRPORTTILE_IDS_H */ openttd-1.5.3/src/table/airport_movement.h0000644000000000000000000016322112627373436017336 0ustar rootroot/* $Id: airport_movement.h 22741 2011-08-13 12:43:05Z alberth $ */ /* * 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 airport_movement.h Heart of the airports and their finite state machines */ #ifndef AIRPORT_MOVEMENT_H #define AIRPORT_MOVEMENT_H /** * State machine input struct (from external file, etc.) * Finite sTate mAchine --> FTA */ struct AirportFTAbuildup { byte position; ///< The position that an airplane is at. byte heading; ///< The current orders (eg. TAKEOFF, HANGAR, ENDLANDING, etc.). uint64 block; ///< The block this position is on on the airport (st->airport.flags). byte next; ///< Next position from this position. }; /////////////////////////////////////////////////////////////////////// /////*********Movement Positions on Airports********************/////// /** * Airport movement data creation macro. * @param x X position. * @param y Y position. * @param flags Movement flags. * @param dir Direction. */ #define AMD(x, y, flags, dir) { x, y, flags, {dir} } /** Dummy airport. */ static const AirportMovingData _airport_moving_data_dummy[] = { AMD( 0, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), AMD( 0, 96, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), AMD( 96, 96, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), AMD( 96, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), }; /** Country Airfield (small) 4x3. */ static const AirportMovingData _airport_moving_data_country[22] = { AMD( 53, 3, AMED_EXACTPOS, DIR_SE), // 00 In Hangar AMD( 53, 27, 0, DIR_N ), // 01 Taxi to right outside depot AMD( 32, 23, AMED_EXACTPOS, DIR_NW), // 02 Terminal 1 AMD( 10, 23, AMED_EXACTPOS, DIR_NW), // 03 Terminal 2 AMD( 43, 37, 0, DIR_N ), // 04 Going towards terminal 2 AMD( 24, 37, 0, DIR_N ), // 05 Going towards terminal 2 AMD( 53, 37, 0, DIR_N ), // 06 Going for takeoff AMD( 61, 40, AMED_EXACTPOS, DIR_NE), // 07 Taxi to start of runway (takeoff) AMD( 3, 40, AMED_NOSPDCLAMP, DIR_N ), // 08 Accelerate to end of runway AMD( -79, 40, AMED_NOSPDCLAMP | AMED_TAKEOFF, DIR_N ), // 09 Take off AMD( 177, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 10 Fly to landing position in air AMD( 56, 40, AMED_NOSPDCLAMP | AMED_LAND, DIR_N ), // 11 Going down for land AMD( 3, 40, AMED_NOSPDCLAMP | AMED_BRAKE, DIR_N ), // 12 Just landed, brake until end of runway AMD( 7, 40, 0, DIR_N ), // 13 Just landed, turn around and taxi 1 square AMD( 53, 40, 0, DIR_N ), // 14 Taxi from runway to crossing AMD( 1, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 15 Fly around waiting for a landing spot (north-east) AMD( 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 16 Fly around waiting for a landing spot (north-west) AMD( 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 17 Fly around waiting for a landing spot (south-west) AMD( 273, 47, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 18 Fly around waiting for a landing spot (south) AMD( 44, 37, AMED_HELI_RAISE, DIR_N ), // 19 Helicopter takeoff AMD( 44, 40, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 20 In position above landing spot helicopter AMD( 44, 40, AMED_HELI_LOWER, DIR_N ), // 21 Helicopter landing }; /** Commuter Airfield (small) 5x4. */ static const AirportMovingData _airport_moving_data_commuter[37] = { AMD( 69, 3, AMED_EXACTPOS, DIR_SE), // 00 In Hangar AMD( 72, 22, 0, DIR_N ), // 01 Taxi to right outside depot AMD( 8, 22, AMED_EXACTPOS, DIR_SW), // 01 Taxi to right outside depot AMD( 24, 36, AMED_EXACTPOS, DIR_SE), // 03 Terminal 1 AMD( 40, 36, AMED_EXACTPOS, DIR_SE), // 04 Terminal 2 AMD( 56, 36, AMED_EXACTPOS, DIR_SE), // 05 Terminal 3 AMD( 40, 8, AMED_EXACTPOS, DIR_NE), // 06 Helipad 1 AMD( 56, 8, AMED_EXACTPOS, DIR_NE), // 07 Helipad 2 AMD( 24, 22, 0, DIR_SW), // 08 Taxiing AMD( 40, 22, 0, DIR_SW), // 09 Taxiing AMD( 56, 22, 0, DIR_SW), // 10 Taxiing AMD( 72, 40, 0, DIR_SE), // 11 Airport OUTWAY AMD( 72, 54, AMED_EXACTPOS, DIR_NE), // 12 Accelerate to end of runway AMD( 7, 54, AMED_NOSPDCLAMP, DIR_N ), // 13 Release control of runway, for smoother movement AMD( 5, 54, AMED_NOSPDCLAMP, DIR_N ), // 14 End of runway AMD( -79, 54, AMED_NOSPDCLAMP | AMED_TAKEOFF, DIR_N ), // 15 Take off AMD( 145, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 16 Fly to landing position in air AMD( 73, 54, AMED_NOSPDCLAMP | AMED_LAND, DIR_N ), // 17 Going down for land AMD( 3, 54, AMED_NOSPDCLAMP | AMED_BRAKE, DIR_N ), // 18 Just landed, brake until end of runway AMD( 12, 54, AMED_SLOWTURN, DIR_NW), // 19 Just landed, turn around and taxi AMD( 8, 32, 0, DIR_NW), // 20 Taxi from runway to crossing AMD( 1, 149, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 21 Fly around waiting for a landing spot (north-east) AMD( 1, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 22 Fly around waiting for a landing spot (north-west) AMD( 193, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 23 Fly around waiting for a landing spot (south-west) AMD( 225, 62, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 24 Fly around waiting for a landing spot (south) /* Helicopter */ AMD( 80, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 25 Bufferspace before helipad AMD( 80, 0, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 26 Bufferspace before helipad AMD( 32, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 27 Get in position for Helipad1 AMD( 48, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 28 Get in position for Helipad2 AMD( 32, 8, AMED_HELI_LOWER, DIR_N ), // 29 Land at Helipad1 AMD( 48, 8, AMED_HELI_LOWER, DIR_N ), // 30 Land at Helipad2 AMD( 32, 8, AMED_HELI_RAISE, DIR_N ), // 31 Takeoff Helipad1 AMD( 48, 8, AMED_HELI_RAISE, DIR_N ), // 32 Takeoff Helipad2 AMD( 64, 22, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 33 Go to position for Hangarentrance in air AMD( 64, 22, AMED_HELI_LOWER, DIR_N ), // 34 Land in front of hangar AMD( 40, 8, AMED_EXACTPOS, DIR_N ), // pre-helitakeoff helipad 1 AMD( 56, 8, AMED_EXACTPOS, DIR_N ), // pre-helitakeoff helipad 2 }; /** City Airport (large) 6x6. */ static const AirportMovingData _airport_moving_data_city[] = { AMD( 85, 3, AMED_EXACTPOS, DIR_SE), // 00 In Hangar AMD( 85, 22, 0, DIR_N ), // 01 Taxi to right outside depot AMD( 26, 41, AMED_EXACTPOS, DIR_SW), // 02 Terminal 1 AMD( 56, 22, AMED_EXACTPOS, DIR_SE), // 03 Terminal 2 AMD( 38, 8, AMED_EXACTPOS, DIR_SW), // 04 Terminal 3 AMD( 65, 6, 0, DIR_N ), // 05 Taxi to right in infront of terminal 2/3 AMD( 80, 27, 0, DIR_N ), // 06 Taxiway terminals 2-3 AMD( 44, 63, 0, DIR_N ), // 07 Taxi to Airport center AMD( 58, 71, 0, DIR_N ), // 08 Towards takeoff AMD( 72, 85, 0, DIR_N ), // 09 Taxi to runway (takeoff) AMD( 89, 85, AMED_EXACTPOS, DIR_NE), // 10 Taxi to start of runway (takeoff) AMD( 3, 85, AMED_NOSPDCLAMP, DIR_N ), // 11 Accelerate to end of runway AMD( -79, 85, AMED_NOSPDCLAMP | AMED_TAKEOFF, DIR_N ), // 12 Take off AMD( 177, 87, AMED_HOLD | AMED_SLOWTURN, DIR_N ), // 13 Fly to landing position in air AMD( 89, 87, AMED_HOLD | AMED_LAND, DIR_N ), // 14 Going down for land AMD( 20, 87, AMED_NOSPDCLAMP | AMED_BRAKE, DIR_N ), // 15 Just landed, brake until end of runway AMD( 20, 87, 0, DIR_N ), // 16 Just landed, turn around and taxi 1 square // NOT USED AMD( 36, 71, 0, DIR_N ), // 17 Taxi from runway to crossing AMD( 160, 87, AMED_HOLD | AMED_SLOWTURN, DIR_N ), // 18 Fly around waiting for a landing spot (north-east) AMD( 140, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 19 Final approach fix AMD( 257, 1, AMED_HOLD | AMED_SLOWTURN, DIR_N ), // 20 Fly around waiting for a landing spot (south-west) AMD( 273, 49, AMED_HOLD | AMED_SLOWTURN, DIR_N ), // 21 Fly around waiting for a landing spot (south) AMD( 44, 63, AMED_HELI_RAISE, DIR_N ), // 22 Helicopter takeoff AMD( 28, 74, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 23 In position above landing spot helicopter AMD( 28, 74, AMED_HELI_LOWER, DIR_N ), // 24 Helicopter landing AMD( 145, 1, AMED_HOLD | AMED_SLOWTURN, DIR_N ), // 25 Fly around waiting for a landing spot (north-west) AMD( -32, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 26 Initial approach fix (north) AMD( 300, -48, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 27 Initial approach fix (south) AMD( 140, -48, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 28 Intermediate Approach fix (south), IAF (west) AMD( -32, 120, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 29 Initial approach fix (east) }; /** Metropolitan Airport (metropolitan) - 2 runways. */ static const AirportMovingData _airport_moving_data_metropolitan[28] = { AMD( 85, 3, AMED_EXACTPOS, DIR_SE), // 00 In Hangar AMD( 85, 22, 0, DIR_N ), // 01 Taxi to right outside depot AMD( 26, 41, AMED_EXACTPOS, DIR_SW), // 02 Terminal 1 AMD( 56, 22, AMED_EXACTPOS, DIR_SE), // 03 Terminal 2 AMD( 38, 8, AMED_EXACTPOS, DIR_SW), // 04 Terminal 3 AMD( 65, 6, 0, DIR_N ), // 05 Taxi to right in infront of terminal 2/3 AMD( 80, 27, 0, DIR_N ), // 06 Taxiway terminals 2-3 AMD( 49, 58, 0, DIR_N ), // 07 Taxi to Airport center AMD( 72, 58, 0, DIR_N ), // 08 Towards takeoff AMD( 72, 69, 0, DIR_N ), // 09 Taxi to runway (takeoff) AMD( 89, 69, AMED_EXACTPOS, DIR_NE), // 10 Taxi to start of runway (takeoff) AMD( 3, 69, AMED_NOSPDCLAMP, DIR_N ), // 11 Accelerate to end of runway AMD( -79, 69, AMED_NOSPDCLAMP | AMED_TAKEOFF, DIR_N ), // 12 Take off AMD( 177, 85, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 13 Fly to landing position in air AMD( 89, 85, AMED_NOSPDCLAMP | AMED_LAND, DIR_N ), // 14 Going down for land AMD( 3, 85, AMED_NOSPDCLAMP | AMED_BRAKE, DIR_N ), // 15 Just landed, brake until end of runway AMD( 21, 85, 0, DIR_N ), // 16 Just landed, turn around and taxi 1 square AMD( 21, 69, 0, DIR_N ), // 17 On Runway-out taxiing to In-Way AMD( 21, 58, AMED_EXACTPOS, DIR_SW), // 18 Taxi from runway to crossing AMD( 1, 193, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 19 Fly around waiting for a landing spot (north-east) AMD( 1, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 20 Fly around waiting for a landing spot (north-west) AMD( 257, 1, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 21 Fly around waiting for a landing spot (south-west) AMD( 273, 49, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 22 Fly around waiting for a landing spot (south) AMD( 44, 58, 0, DIR_N ), // 23 Helicopter takeoff spot on ground (to clear airport sooner) AMD( 44, 63, AMED_HELI_RAISE, DIR_N ), // 24 Helicopter takeoff AMD( 15, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 25 Get in position above landing spot helicopter AMD( 15, 54, AMED_HELI_LOWER, DIR_N ), // 26 Helicopter landing AMD( 21, 58, AMED_EXACTPOS, DIR_SW), // 27 Transitions after landing to on-ground movement }; /** International Airport (international) - 2 runways, 6 terminals, dedicated helipad. */ static const AirportMovingData _airport_moving_data_international[51] = { AMD( 7, 55, AMED_EXACTPOS, DIR_SE), // 00 In Hangar 1 AMD( 100, 21, AMED_EXACTPOS, DIR_SE), // 01 In Hangar 2 AMD( 7, 70, 0, DIR_N ), // 02 Taxi to right outside depot AMD( 100, 36, 0, DIR_N ), // 03 Taxi to right outside depot AMD( 38, 70, AMED_EXACTPOS, DIR_SW), // 04 Terminal 1 AMD( 38, 54, AMED_EXACTPOS, DIR_SW), // 05 Terminal 2 AMD( 38, 38, AMED_EXACTPOS, DIR_SW), // 06 Terminal 3 AMD( 70, 70, AMED_EXACTPOS, DIR_NE), // 07 Terminal 4 AMD( 70, 54, AMED_EXACTPOS, DIR_NE), // 08 Terminal 5 AMD( 70, 38, AMED_EXACTPOS, DIR_NE), // 09 Terminal 6 AMD( 104, 71, AMED_EXACTPOS, DIR_NE), // 10 Helipad 1 AMD( 104, 55, AMED_EXACTPOS, DIR_NE), // 11 Helipad 2 AMD( 22, 87, 0, DIR_N ), // 12 Towards Terminals 4/5/6, Helipad 1/2 AMD( 60, 87, 0, DIR_N ), // 13 Towards Terminals 4/5/6, Helipad 1/2 AMD( 66, 87, 0, DIR_N ), // 14 Towards Terminals 4/5/6, Helipad 1/2 AMD( 86, 87, AMED_EXACTPOS, DIR_NW), // 15 Towards Terminals 4/5/6, Helipad 1/2 AMD( 86, 70, 0, DIR_N ), // 16 In Front of Terminal 4 / Helipad 1 AMD( 86, 54, 0, DIR_N ), // 17 In Front of Terminal 5 / Helipad 2 AMD( 86, 38, 0, DIR_N ), // 18 In Front of Terminal 6 AMD( 86, 22, 0, DIR_N ), // 19 Towards Terminals Takeoff (Taxiway) AMD( 66, 22, 0, DIR_N ), // 20 Towards Terminals Takeoff (Taxiway) AMD( 60, 22, 0, DIR_N ), // 21 Towards Terminals Takeoff (Taxiway) AMD( 38, 22, 0, DIR_N ), // 22 Towards Terminals Takeoff (Taxiway) AMD( 22, 70, 0, DIR_N ), // 23 In Front of Terminal 1 AMD( 22, 58, 0, DIR_N ), // 24 In Front of Terminal 2 AMD( 22, 38, 0, DIR_N ), // 25 In Front of Terminal 3 AMD( 22, 22, AMED_EXACTPOS, DIR_NW), // 26 Going for Takeoff AMD( 22, 6, 0, DIR_N ), // 27 On Runway-out, prepare for takeoff AMD( 3, 6, AMED_EXACTPOS, DIR_SW), // 28 Accelerate to end of runway AMD( 60, 6, AMED_NOSPDCLAMP, DIR_N ), // 29 Release control of runway, for smoother movement AMD( 105, 6, AMED_NOSPDCLAMP, DIR_N ), // 30 End of runway AMD( 190, 6, AMED_NOSPDCLAMP | AMED_TAKEOFF, DIR_N ), // 31 Take off AMD( 193, 104, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 32 Fly to landing position in air AMD( 105, 104, AMED_NOSPDCLAMP | AMED_LAND, DIR_N ), // 33 Going down for land AMD( 3, 104, AMED_NOSPDCLAMP | AMED_BRAKE, DIR_N ), // 34 Just landed, brake until end of runway AMD( 12, 104, AMED_SLOWTURN, DIR_N ), // 35 Just landed, turn around and taxi 1 square AMD( 7, 84, 0, DIR_N ), // 36 Taxi from runway to crossing AMD( 1, 209, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 37 Fly around waiting for a landing spot (north-east) AMD( 1, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 38 Fly around waiting for a landing spot (north-west) AMD( 273, 6, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 39 Fly around waiting for a landing spot (south-west) AMD( 305, 81, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 40 Fly around waiting for a landing spot (south) /* Helicopter */ AMD( 128, 80, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 41 Bufferspace before helipad AMD( 128, 80, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 42 Bufferspace before helipad AMD( 96, 71, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 43 Get in position for Helipad1 AMD( 96, 55, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 44 Get in position for Helipad2 AMD( 96, 71, AMED_HELI_LOWER, DIR_N ), // 45 Land at Helipad1 AMD( 96, 55, AMED_HELI_LOWER, DIR_N ), // 46 Land at Helipad2 AMD( 104, 71, AMED_HELI_RAISE, DIR_N ), // 47 Takeoff Helipad1 AMD( 104, 55, AMED_HELI_RAISE, DIR_N ), // 48 Takeoff Helipad2 AMD( 104, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 49 Go to position for Hangarentrance in air AMD( 104, 32, AMED_HELI_LOWER, DIR_N ), // 50 Land in HANGAR2_AREA to go to hangar }; /** Intercontinental Airport - 4 runways, 8 terminals, 2 dedicated helipads. */ static const AirportMovingData _airport_moving_data_intercontinental[77] = { AMD( 8, 87, AMED_EXACTPOS, DIR_SE), // 00 In Hangar 1 AMD( 136, 72, AMED_EXACTPOS, DIR_SE), // 01 In Hangar 2 AMD( 8, 104, 0, DIR_N ), // 02 Taxi to right outside depot 1 AMD( 136, 88, 0, DIR_N ), // 03 Taxi to right outside depot 2 AMD( 56, 120, AMED_EXACTPOS, DIR_W ), // 04 Terminal 1 AMD( 56, 104, AMED_EXACTPOS, DIR_SW), // 05 Terminal 2 AMD( 56, 88, AMED_EXACTPOS, DIR_SW), // 06 Terminal 3 AMD( 56, 72, AMED_EXACTPOS, DIR_SW), // 07 Terminal 4 AMD( 88, 120, AMED_EXACTPOS, DIR_N ), // 08 Terminal 5 AMD( 88, 104, AMED_EXACTPOS, DIR_NE), // 09 Terminal 6 AMD( 88, 88, AMED_EXACTPOS, DIR_NE), // 10 Terminal 7 AMD( 88, 72, AMED_EXACTPOS, DIR_NE), // 11 Terminal 8 AMD( 88, 56, AMED_EXACTPOS, DIR_SE), // 12 Helipad 1 AMD( 72, 56, AMED_EXACTPOS, DIR_NE), // 13 Helipad 2 AMD( 40, 136, 0, DIR_N ), // 14 Term group 2 enter 1 a AMD( 56, 136, 0, DIR_N ), // 15 Term group 2 enter 1 b AMD( 88, 136, 0, DIR_N ), // 16 Term group 2 enter 2 a AMD( 104, 136, 0, DIR_N ), // 17 Term group 2 enter 2 b AMD( 104, 120, 0, DIR_N ), // 18 Term group 2 - opp term 5 AMD( 104, 104, 0, DIR_N ), // 19 Term group 2 - opp term 6 & exit2 AMD( 104, 88, 0, DIR_N ), // 20 Term group 2 - opp term 7 & hangar area 2 AMD( 104, 72, 0, DIR_N ), // 21 Term group 2 - opp term 8 AMD( 104, 56, 0, DIR_N ), // 22 Taxi Term group 2 exit a AMD( 104, 40, 0, DIR_N ), // 23 Taxi Term group 2 exit b AMD( 56, 40, 0, DIR_N ), // 24 Term group 2 exit 2a AMD( 40, 40, 0, DIR_N ), // 25 Term group 2 exit 2b AMD( 40, 120, 0, DIR_N ), // 26 Term group 1 - opp term 1 AMD( 40, 104, 0, DIR_N ), // 27 Term group 1 - opp term 2 & hangar area 1 AMD( 40, 88, 0, DIR_N ), // 28 Term group 1 - opp term 3 AMD( 40, 72, 0, DIR_N ), // 29 Term group 1 - opp term 4 AMD( 18, 72, 0, DIR_NW), // 30 Outway 1 AMD( 8, 40, 0, DIR_NW), // 31 Airport OUTWAY AMD( 8, 24, AMED_EXACTPOS, DIR_SW), // 32 Accelerate to end of runway AMD( 119, 24, AMED_NOSPDCLAMP, DIR_N ), // 33 Release control of runway, for smoother movement AMD( 117, 24, AMED_NOSPDCLAMP, DIR_N ), // 34 End of runway AMD( 197, 24, AMED_NOSPDCLAMP | AMED_TAKEOFF, DIR_N ), // 35 Take off AMD( 254, 84, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 36 Flying to landing position in air AMD( 117, 168, AMED_NOSPDCLAMP | AMED_LAND, DIR_N ), // 37 Going down for land AMD( 8, 168, AMED_NOSPDCLAMP | AMED_BRAKE, DIR_N ), // 38 Just landed, brake until end of runway AMD( 8, 168, 0, DIR_N ), // 39 Just landed, turn around and taxi AMD( 8, 144, 0, DIR_NW), // 40 Taxi from runway AMD( 8, 128, 0, DIR_NW), // 41 Taxi from runway AMD( 8, 120, AMED_EXACTPOS, DIR_NW), // 42 Airport entrance AMD( 56, 344, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 43 Fly around waiting for a landing spot (north-east) AMD( -200, 88, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 44 Fly around waiting for a landing spot (north-west) AMD( 56, -168, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 45 Fly around waiting for a landing spot (south-west) AMD( 312, 88, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 46 Fly around waiting for a landing spot (south) /* Helicopter */ AMD( 96, 40, AMED_NOSPDCLAMP, DIR_N ), // 47 Bufferspace before helipad AMD( 96, 40, AMED_NOSPDCLAMP, DIR_N ), // 48 Bufferspace before helipad AMD( 82, 54, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 49 Get in position for Helipad1 AMD( 64, 56, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 50 Get in position for Helipad2 AMD( 81, 55, AMED_HELI_LOWER, DIR_N ), // 51 Land at Helipad1 AMD( 64, 56, AMED_HELI_LOWER, DIR_N ), // 52 Land at Helipad2 AMD( 80, 56, AMED_HELI_RAISE, DIR_N ), // 53 Takeoff Helipad1 AMD( 64, 56, AMED_HELI_RAISE, DIR_N ), // 54 Takeoff Helipad2 AMD( 136, 96, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 55 Go to position for Hangarentrance in air AMD( 136, 96, AMED_HELI_LOWER, DIR_N ), // 56 Land in front of hangar2 AMD( 126, 104, 0, DIR_SE), // 57 Outway 2 AMD( 136, 136, 0, DIR_NE), // 58 Airport OUTWAY 2 AMD( 136, 152, AMED_EXACTPOS, DIR_NE), // 59 Accelerate to end of runway2 AMD( 16, 152, AMED_NOSPDCLAMP, DIR_N ), // 60 Release control of runway2, for smoother movement AMD( 20, 152, AMED_NOSPDCLAMP, DIR_N ), // 61 End of runway2 AMD( -56, 152, AMED_NOSPDCLAMP | AMED_TAKEOFF, DIR_N ), // 62 Take off2 AMD( 24, 8, AMED_NOSPDCLAMP | AMED_LAND, DIR_N ), // 63 Going down for land2 AMD( 136, 8, AMED_NOSPDCLAMP | AMED_BRAKE, DIR_N ), // 64 Just landed, brake until end of runway2in AMD( 136, 8, 0, DIR_N ), // 65 Just landed, turn around and taxi AMD( 136, 24, 0, DIR_SE), // 66 Taxi from runway 2in AMD( 136, 40, 0, DIR_SE), // 67 Taxi from runway 2in AMD( 136, 56, AMED_EXACTPOS, DIR_NE), // 68 Airport entrance2 AMD( -56, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 69 Fly to landing position in air2 AMD( 88, 40, 0, DIR_N ), // 70 Taxi Term group 2 exit - opp heli1 AMD( 72, 40, 0, DIR_N ), // 71 Taxi Term group 2 exit - opp heli2 AMD( 88, 57, AMED_EXACTPOS, DIR_SE), // 72 pre-helitakeoff helipad 1 AMD( 71, 56, AMED_EXACTPOS, DIR_NE), // 73 pre-helitakeoff helipad 2 AMD( 8, 120, AMED_HELI_RAISE, DIR_N ), // 74 Helitakeoff outside depot 1 AMD( 136, 104, AMED_HELI_RAISE, DIR_N ), // 75 Helitakeoff outside depot 2 AMD( 197, 168, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 76 Fly to landing position in air1 }; /** Heliport (heliport). */ static const AirportMovingData _airport_moving_data_heliport[9] = { AMD( 5, 9, AMED_EXACTPOS, DIR_NE), // 0 - At heliport terminal AMD( 2, 9, AMED_HELI_RAISE, DIR_N ), // 1 - Take off (play sound) AMD( -3, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 2 - In position above landing spot helicopter AMD( -3, 9, AMED_HELI_LOWER, DIR_N ), // 3 - Land AMD( 2, 9, 0, DIR_N ), // 4 - Goto terminal on ground AMD( -31, 59, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 5 - Circle #1 (north-east) AMD( -31, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 6 - Circle #2 (north-west) AMD( 49, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 7 - Circle #3 (south-west) AMD( 70, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 8 - Circle #4 (south) }; /** HeliDepot 2x2 (heliport). */ static const AirportMovingData _airport_moving_data_helidepot[18] = { AMD( 24, 4, AMED_EXACTPOS, DIR_NE), // 0 - At depot AMD( 24, 28, 0, DIR_N ), // 1 Taxi to right outside depot AMD( 5, 38, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 2 Flying AMD( -15, -15, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 3 - Circle #1 (north-east) AMD( -15, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 4 - Circle #2 (north-west) AMD( 49, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 5 - Circle #3 (south-west) AMD( 49, -15, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 6 - Circle #4 (south-east) AMD( 8, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_NW), // 7 - PreHelipad AMD( 8, 32, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_NW), // 8 - Helipad AMD( 8, 16, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_NW), // 9 - Land AMD( 8, 16, AMED_HELI_LOWER, DIR_NW), // 10 - Land AMD( 8, 24, AMED_HELI_RAISE, DIR_N ), // 11 - Take off (play sound) AMD( 32, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_NW), // 12 Air to above hangar area AMD( 32, 24, AMED_HELI_LOWER, DIR_NW), // 13 Taxi to right outside depot AMD( 8, 24, AMED_EXACTPOS, DIR_NW), // 14 - on helipad1 AMD( 24, 28, AMED_HELI_RAISE, DIR_N ), // 15 Takeoff right outside depot AMD( 8, 24, AMED_HELI_RAISE, DIR_SW), // 16 - Take off (play sound) AMD( 8, 24, AMED_SLOWTURN | AMED_EXACTPOS, DIR_E ), // 17 - turn on helipad1 for takeoff }; /** HeliDepot 2x2 (heliport). */ static const AirportMovingData _airport_moving_data_helistation[33] = { AMD( 8, 3, AMED_EXACTPOS, DIR_SE), // 00 In Hangar2 AMD( 8, 22, 0, DIR_N ), // 01 outside hangar 2 AMD( 116, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 02 Fly to landing position in air AMD( 14, 22, AMED_HELI_RAISE, DIR_N ), // 03 Helitakeoff outside hangar1(play sound) AMD( 24, 22, 0, DIR_N ), // 04 taxiing AMD( 40, 22, 0, DIR_N ), // 05 taxiing AMD( 40, 8, AMED_EXACTPOS, DIR_NE), // 06 Helipad 1 AMD( 56, 8, AMED_EXACTPOS, DIR_NE), // 07 Helipad 2 AMD( 56, 24, AMED_EXACTPOS, DIR_NE), // 08 Helipad 3 AMD( 40, 8, AMED_EXACTPOS, DIR_N ), // 09 pre-helitakeoff helipad 1 AMD( 56, 8, AMED_EXACTPOS, DIR_N ), // 10 pre-helitakeoff helipad 2 AMD( 56, 24, AMED_EXACTPOS, DIR_N ), // 11 pre-helitakeoff helipad 3 AMD( 32, 8, AMED_HELI_RAISE, DIR_N ), // 12 Takeoff Helipad1 AMD( 48, 8, AMED_HELI_RAISE, DIR_N ), // 13 Takeoff Helipad2 AMD( 48, 24, AMED_HELI_RAISE, DIR_N ), // 14 Takeoff Helipad3 AMD( 84, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 15 Bufferspace before helipad AMD( 68, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 16 Bufferspace before helipad AMD( 32, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 17 Get in position for Helipad1 AMD( 48, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 18 Get in position for Helipad2 AMD( 48, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_NE), // 19 Get in position for Helipad3 AMD( 40, 8, AMED_HELI_LOWER, DIR_N ), // 20 Land at Helipad1 AMD( 48, 8, AMED_HELI_LOWER, DIR_N ), // 21 Land at Helipad2 AMD( 48, 24, AMED_HELI_LOWER, DIR_N ), // 22 Land at Helipad3 AMD( 0, 22, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 23 Go to position for Hangarentrance in air AMD( 0, 22, AMED_HELI_LOWER, DIR_N ), // 24 Land in front of hangar AMD( 148, -8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 25 Fly around waiting for a landing spot (south-east) AMD( 148, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 26 Fly around waiting for a landing spot (south-west) AMD( 132, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 27 Fly around waiting for a landing spot (south-west) AMD( 100, 24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 28 Fly around waiting for a landing spot (north-east) AMD( 84, 8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 29 Fly around waiting for a landing spot (south-east) AMD( 84, -8, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 30 Fly around waiting for a landing spot (south-west) AMD( 100, -24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 31 Fly around waiting for a landing spot (north-west) AMD( 132, -24, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 32 Fly around waiting for a landing spot (north-east) }; /** Oilrig. */ static const AirportMovingData _airport_moving_data_oilrig[9] = { AMD( 31, 9, AMED_EXACTPOS, DIR_NE), // 0 - At oilrig terminal AMD( 28, 9, AMED_HELI_RAISE, DIR_N ), // 1 - Take off (play sound) AMD( 23, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 2 - In position above landing spot helicopter AMD( 23, 9, AMED_HELI_LOWER, DIR_N ), // 3 - Land AMD( 28, 9, 0, DIR_N ), // 4 - Goto terminal on ground AMD( -31, 69, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 5 - circle #1 (north-east) AMD( -31, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 6 - circle #2 (north-west) AMD( 69, -49, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 7 - circle #3 (south-west) AMD( 69, 9, AMED_NOSPDCLAMP | AMED_SLOWTURN, DIR_N ), // 8 - circle #4 (south) }; #undef AMD /////////////////////////////////////////////////////////////////////// /////**********Movement Machine on Airports*********************/////// static const byte _airport_entries_dummy[] = {0, 1, 2, 3}; static const AirportFTAbuildup _airport_fta_dummy[] = { { 0, 0, 0, 3}, { 1, 0, 0, 0}, { 2, 0, 0, 1}, { 3, 0, 0, 2}, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; /* First element of terminals array tells us how many depots there are (to know size of array) * this may be changed later when airports are moved to external file */ static const HangarTileTable _airport_depots_country[] = { {{3, 0}, DIR_SE, 0} }; static const byte _airport_terminal_country[] = {1, 2}; static const byte _airport_entries_country[] = {16, 15, 18, 17}; static const AirportFTAbuildup _airport_fta_country[] = { { 0, HANGAR, NOTHING_block, 1 }, { 1, 255, AIRPORT_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM1, TERM1_block, 2 }, { 1, TERM2, 0, 4 }, { 1, HELITAKEOFF, 0, 19 }, { 1, 0, 0, 6 }, { 2, TERM1, TERM1_block, 1 }, { 3, TERM2, TERM2_block, 5 }, { 4, 255, AIRPORT_BUSY_block, 0 }, { 4, TERM2, 0, 5 }, { 4, HANGAR, 0, 1 }, { 4, TAKEOFF, 0, 6 }, { 4, HELITAKEOFF, 0, 1 }, { 5, 255, AIRPORT_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, 0, 0, 4 }, { 6, 0, AIRPORT_BUSY_block, 7 }, /* takeoff */ { 7, TAKEOFF, AIRPORT_BUSY_block, 8 }, { 8, STARTTAKEOFF, NOTHING_block, 9 }, { 9, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 10, FLYING, NOTHING_block, 15 }, { 10, LANDING, 0, 11 }, { 10, HELILANDING, 0, 20 }, { 11, LANDING, AIRPORT_BUSY_block, 12 }, { 12, 0, AIRPORT_BUSY_block, 13 }, { 13, ENDLANDING, AIRPORT_BUSY_block, 14 }, { 13, TERM2, 0, 5 }, { 13, 0, 0, 14 }, { 14, 0, AIRPORT_BUSY_block, 1 }, /* In air */ { 15, 0, NOTHING_block, 16 }, { 16, 0, NOTHING_block, 17 }, { 17, 0, NOTHING_block, 18 }, { 18, 0, NOTHING_block, 10 }, { 19, HELITAKEOFF, NOTHING_block, 0 }, { 20, HELILANDING, AIRPORT_BUSY_block, 21 }, { 21, HELIENDLANDING, AIRPORT_BUSY_block, 1 }, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_commuter[] = { {{4, 0}, DIR_SE, 0} }; static const byte _airport_terminal_commuter[] = { 1, 3 }; static const byte _airport_entries_commuter[] = {22, 21, 24, 23}; static const AirportFTAbuildup _airport_fta_commuter[] = { { 0, HANGAR, NOTHING_block, 1 }, { 0, HELITAKEOFF, HELIPAD2_block, 1 }, { 0, 0, 0, 1 }, { 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TAKEOFF, 0, 11 }, { 1, TERM1, TAXIWAY_BUSY_block, 10 }, { 1, TERM2, TAXIWAY_BUSY_block, 10 }, { 1, TERM3, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD1, TAXIWAY_BUSY_block, 10 }, { 1, HELIPAD2, TAXIWAY_BUSY_block, 10 }, { 1, HELITAKEOFF, TAXIWAY_BUSY_block, 10 }, { 1, 0, 0, 0 }, { 2, 255, AIRPORT_ENTRANCE_block, 2 }, { 2, HANGAR, 0, 8 }, { 2, TERM1, 0, 8 }, { 2, TERM2, 0, 8 }, { 2, TERM3, 0, 8 }, { 2, HELIPAD1, 0, 8 }, { 2, HELIPAD2, 0, 8 }, { 2, HELITAKEOFF, 0, 8 }, { 2, 0, 0, 2 }, { 3, TERM1, TERM1_block, 8 }, { 3, HANGAR, 0, 8 }, { 3, TAKEOFF, 0, 8 }, { 3, 0, 0, 3 }, { 4, TERM2, TERM2_block, 9 }, { 4, HANGAR, 0, 9 }, { 4, TAKEOFF, 0, 9 }, { 4, 0, 0, 4 }, { 5, TERM3, TERM3_block, 10 }, { 5, HANGAR, 0, 10 }, { 5, TAKEOFF, 0, 10 }, { 5, 0, 0, 5 }, { 6, HELIPAD1, HELIPAD1_block, 6 }, { 6, HANGAR, TAXIWAY_BUSY_block, 9 }, { 6, HELITAKEOFF, 0, 35 }, { 7, HELIPAD2, HELIPAD2_block, 7 }, { 7, HANGAR, TAXIWAY_BUSY_block, 10 }, { 7, HELITAKEOFF, 0, 36 }, { 8, 255, TAXIWAY_BUSY_block, 8 }, { 8, TAKEOFF, TAXIWAY_BUSY_block, 9 }, { 8, HANGAR, TAXIWAY_BUSY_block, 9 }, { 8, TERM1, TERM1_block, 3 }, { 8, 0, TAXIWAY_BUSY_block, 9 }, { 9, 255, TAXIWAY_BUSY_block, 9 }, { 9, TAKEOFF, TAXIWAY_BUSY_block, 10 }, { 9, HANGAR, TAXIWAY_BUSY_block, 10 }, { 9, TERM2, TERM2_block, 4 }, { 9, HELIPAD1, HELIPAD1_block, 6 }, { 9, HELITAKEOFF, HELIPAD1_block, 6 }, { 9, TERM1, TAXIWAY_BUSY_block, 8 }, { 9, 0, TAXIWAY_BUSY_block, 10 }, { 10, 255, TAXIWAY_BUSY_block, 10 }, { 10, TERM3, TERM3_block, 5 }, { 10, HELIPAD1, 0, 9 }, { 10, HELIPAD2, HELIPAD2_block, 7 }, { 10, HELITAKEOFF, HELIPAD2_block, 7 }, { 10, TAKEOFF, TAXIWAY_BUSY_block, 1 }, { 10, HANGAR, TAXIWAY_BUSY_block, 1 }, { 10, 0, TAXIWAY_BUSY_block, 9 }, { 11, 0, OUT_WAY_block, 12 }, /* takeoff */ { 12, TAKEOFF, RUNWAY_IN_OUT_block, 13 }, { 13, 0, RUNWAY_IN_OUT_block, 14 }, { 14, STARTTAKEOFF, RUNWAY_IN_OUT_block, 15 }, { 15, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 16, FLYING, NOTHING_block, 21 }, { 16, LANDING, IN_WAY_block, 17 }, { 16, HELILANDING, 0, 25 }, { 17, LANDING, RUNWAY_IN_OUT_block, 18 }, { 18, 0, RUNWAY_IN_OUT_block, 19 }, { 19, 0, RUNWAY_IN_OUT_block, 20 }, { 20, ENDLANDING, IN_WAY_block, 2 }, /* In Air */ { 21, 0, NOTHING_block, 22 }, { 22, 0, NOTHING_block, 23 }, { 23, 0, NOTHING_block, 24 }, { 24, 0, NOTHING_block, 16 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 25, HELILANDING, PRE_HELIPAD_block, 26 }, { 26, HELIENDLANDING, PRE_HELIPAD_block, 26 }, { 26, HELIPAD1, 0, 27 }, { 26, HELIPAD2, 0, 28 }, { 26, HANGAR, 0, 33 }, { 27, 0, NOTHING_block, 29 }, // helipad1 approach { 28, 0, NOTHING_block, 30 }, /* landing */ { 29, 255, NOTHING_block, 0 }, { 29, HELIPAD1, HELIPAD1_block, 6 }, { 30, 255, NOTHING_block, 0 }, { 30, HELIPAD2, HELIPAD2_block, 7 }, /* Helicopter -- takeoff */ { 31, HELITAKEOFF, NOTHING_block, 0 }, { 32, HELITAKEOFF, NOTHING_block, 0 }, { 33, 0, TAXIWAY_BUSY_block, 34 }, // need to go to hangar when waiting in air { 34, 0, TAXIWAY_BUSY_block, 1 }, { 35, 0, HELIPAD1_block, 31 }, { 36, 0, HELIPAD2_block, 32 }, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_city[] = { {{5, 0}, DIR_SE, 0} }; static const byte _airport_terminal_city[] = { 1, 3 }; static const byte _airport_entries_city[] = {26, 29, 27, 28}; static const AirportFTAbuildup _airport_fta_city[] = { { 0, HANGAR, NOTHING_block, 1 }, { 0, TAKEOFF, OUT_WAY_block, 1 }, { 0, 0, 0, 1 }, { 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7 { 2, TERM1, TERM1_block, 7 }, { 2, TAKEOFF, OUT_WAY_block, 7 }, { 2, 0, 0, 7 }, { 3, TERM2, TERM2_block, 5 }, { 3, TAKEOFF, OUT_WAY_block, 6 }, { 3, 0, 0, 6 }, { 4, TERM3, TERM3_block, 5 }, { 4, TAKEOFF, OUT_WAY_block, 5 }, { 4, 0, 0, 5 }, { 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 }, { 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, TERM2_block, 3 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 }, { 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, OUT_WAY_block, 8 }, { 7, HELITAKEOFF, 0, 22 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 }, { 8, 0, OUT_WAY_block, 9 }, { 9, 0, RUNWAY_IN_OUT_block, 10 }, /* takeoff */ { 10, TAKEOFF, RUNWAY_IN_OUT_block, 11 }, { 11, STARTTAKEOFF, NOTHING_block, 12 }, { 12, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 13, FLYING, NOTHING_block, 18 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 23 }, { 14, LANDING, RUNWAY_IN_OUT_block, 15 }, { 15, 0, RUNWAY_IN_OUT_block, 17 }, { 16, 0, RUNWAY_IN_OUT_block, 17 }, // not used, left for compatibility { 17, ENDLANDING, IN_WAY_block, 7 }, /* In Air */ { 18, 0, NOTHING_block, 25 }, { 19, 0, NOTHING_block, 20 }, { 20, 0, NOTHING_block, 21 }, { 21, 0, NOTHING_block, 13 }, /* helicopter */ { 22, HELITAKEOFF, NOTHING_block, 0 }, { 23, HELILANDING, IN_WAY_block, 24 }, { 24, HELIENDLANDING, IN_WAY_block, 17 }, { 25, 0, NOTHING_block, 20}, { 26, 0, NOTHING_block, 19}, { 27, 0, NOTHING_block, 28}, { 28, 0, NOTHING_block, 19}, { 29, 0, NOTHING_block, 26}, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_metropolitan[] = { {{5, 0}, DIR_SE, 0} }; static const byte _airport_terminal_metropolitan[] = { 1, 3 }; static const byte _airport_entries_metropolitan[] = {20, 19, 22, 21}; static const AirportFTAbuildup _airport_fta_metropolitan[] = { { 0, HANGAR, NOTHING_block, 1 }, { 1, 255, TAXIWAY_BUSY_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, TERM2, 0, 6 }, { 1, TERM3, 0, 6 }, { 1, 0, 0, 7 }, // for all else, go to 7 { 2, TERM1, TERM1_block, 7 }, { 3, TERM2, TERM2_block, 6 }, { 4, TERM3, TERM3_block, 5 }, { 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, TERM2, TERM2_block, 3 }, { 5, TERM3, TERM3_block, 4 }, { 5, 0, 0, 6 }, { 6, 255, TAXIWAY_BUSY_block, 0 }, { 6, TERM2, TERM2_block, 3 }, { 6, TERM3, 0, 5 }, { 6, HANGAR, 0, 1 }, { 6, 0, 0, 7 }, { 7, 255, TAXIWAY_BUSY_block, 0 }, { 7, TERM1, TERM1_block, 2 }, { 7, TAKEOFF, 0, 8 }, { 7, HELITAKEOFF, 0, 23 }, { 7, HANGAR, 0, 1 }, { 7, 0, 0, 6 }, { 8, 0, OUT_WAY_block, 9 }, { 9, 0, RUNWAY_OUT_block, 10 }, /* takeoff */ { 10, TAKEOFF, RUNWAY_OUT_block, 11 }, { 11, STARTTAKEOFF, NOTHING_block, 12 }, { 12, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 13, FLYING, NOTHING_block, 19 }, { 13, LANDING, 0, 14 }, { 13, HELILANDING, 0, 25 }, { 14, LANDING, RUNWAY_IN_block, 15 }, { 15, 0, RUNWAY_IN_block, 16 }, { 16, 255, RUNWAY_IN_block, 0 }, { 16, ENDLANDING, IN_WAY_block, 17 }, { 17, 255, RUNWAY_OUT_block, 0 }, { 17, ENDLANDING, IN_WAY_block, 18 }, { 18, ENDLANDING, IN_WAY_block, 27 }, /* In Air */ { 19, 0, NOTHING_block, 20 }, { 20, 0, NOTHING_block, 21 }, { 21, 0, NOTHING_block, 22 }, { 22, 0, NOTHING_block, 13 }, /* helicopter */ { 23, 0, NOTHING_block, 24 }, { 24, HELITAKEOFF, NOTHING_block, 0 }, { 25, HELILANDING, IN_WAY_block, 26 }, { 26, HELIENDLANDING, IN_WAY_block, 18 }, { 27, 255, TAXIWAY_BUSY_block, 27 }, { 27, TERM1, TERM1_block, 2 }, { 27, 0, 0, 7 }, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; static const HangarTileTable _airport_depots_international[] = { {{0, 3}, DIR_SE, 0}, {{6, 1}, DIR_SE, 1} }; static const byte _airport_terminal_international[] = { 2, 3, 3 }; static const byte _airport_entries_international[] = { 38, 37, 40, 39 }; static const AirportFTAbuildup _airport_fta_international[] = { { 0, HANGAR, NOTHING_block, 2 }, { 0, 255, TERM_GROUP1_block, 0 }, { 0, 255, TERM_GROUP2_ENTER1_block, 1 }, { 0, HELITAKEOFF, HELIPAD1_block, 2 }, { 0, 0, 0, 2 }, { 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, HELITAKEOFF, HELIPAD2_block, 3 }, { 1, 0, 0, 3 }, { 2, 255, AIRPORT_ENTRANCE_block, 0 }, { 2, HANGAR, 0, 0 }, { 2, TERM4, 0, 12 }, { 2, TERM5, 0, 12 }, { 2, TERM6, 0, 12 }, { 2, HELIPAD1, 0, 12 }, { 2, HELIPAD2, 0, 12 }, { 2, HELITAKEOFF, 0, 12 }, { 2, 0, 0, 23 }, { 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, 0, 0, 18 }, { 4, TERM1, TERM1_block, 23 }, { 4, HANGAR, AIRPORT_ENTRANCE_block, 23 }, { 4, 0, 0, 23 }, { 5, TERM2, TERM2_block, 24 }, { 5, HANGAR, AIRPORT_ENTRANCE_block, 24 }, { 5, 0, 0, 24 }, { 6, TERM3, TERM3_block, 25 }, { 6, HANGAR, AIRPORT_ENTRANCE_block, 25 }, { 6, 0, 0, 25 }, { 7, TERM4, TERM4_block, 16 }, { 7, HANGAR, HANGAR2_AREA_block, 16 }, { 7, 0, 0, 16 }, { 8, TERM5, TERM5_block, 17 }, { 8, HANGAR, HANGAR2_AREA_block, 17 }, { 8, 0, 0, 17 }, { 9, TERM6, TERM6_block, 18 }, { 9, HANGAR, HANGAR2_AREA_block, 18 }, { 9, 0, 0, 18 }, { 10, HELIPAD1, HELIPAD1_block, 10 }, { 10, HANGAR, HANGAR2_AREA_block, 16 }, { 10, HELITAKEOFF, 0, 47 }, { 11, HELIPAD2, HELIPAD2_block, 11 }, { 11, HANGAR, HANGAR2_AREA_block, 17 }, { 11, HELITAKEOFF, 0, 48 }, { 12, 0, TERM_GROUP2_ENTER1_block, 13 }, { 13, 0, TERM_GROUP2_ENTER1_block, 14 }, { 14, 0, TERM_GROUP2_ENTER2_block, 15 }, { 15, 0, TERM_GROUP2_ENTER2_block, 16 }, { 16, 255, TERM_GROUP2_block, 0 }, { 16, TERM4, TERM4_block, 7 }, { 16, HELIPAD1, HELIPAD1_block, 10 }, { 16, HELITAKEOFF, HELIPAD1_block, 10 }, { 16, 0, 0, 17 }, { 17, 255, TERM_GROUP2_block, 0 }, { 17, TERM5, TERM5_block, 8 }, { 17, TERM4, 0, 16 }, { 17, HELIPAD1, 0, 16 }, { 17, HELIPAD2, HELIPAD2_block, 11 }, { 17, HELITAKEOFF, HELIPAD2_block, 11 }, { 17, 0, 0, 18 }, { 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM6, TERM6_block, 9 }, { 18, TAKEOFF, 0, 19 }, { 18, HANGAR, HANGAR2_AREA_block, 3 }, { 18, 0, 0, 17 }, { 19, 0, TERM_GROUP2_EXIT1_block, 20 }, { 20, 0, TERM_GROUP2_EXIT1_block, 21 }, { 21, 0, TERM_GROUP2_EXIT2_block, 22 }, { 22, 0, TERM_GROUP2_EXIT2_block, 26 }, { 23, 255, TERM_GROUP1_block, 0 }, { 23, TERM1, TERM1_block, 4 }, { 23, HANGAR, AIRPORT_ENTRANCE_block, 2 }, { 23, 0, 0, 24 }, { 24, 255, TERM_GROUP1_block, 0 }, { 24, TERM2, TERM2_block, 5 }, { 24, TERM1, 0, 23 }, { 24, HANGAR, 0, 23 }, { 24, 0, 0, 25 }, { 25, 255, TERM_GROUP1_block, 0 }, { 25, TERM3, TERM3_block, 6 }, { 25, TAKEOFF, 0, 26 }, { 25, 0, 0, 24 }, { 26, 255, TAXIWAY_BUSY_block, 0 }, { 26, TAKEOFF, 0, 27 }, { 26, 0, 0, 25 }, { 27, 0, OUT_WAY_block, 28 }, /* takeoff */ { 28, TAKEOFF, OUT_WAY_block, 29 }, { 29, 0, RUNWAY_OUT_block, 30 }, { 30, STARTTAKEOFF, NOTHING_block, 31 }, { 31, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 32, FLYING, NOTHING_block, 37 }, { 32, LANDING, 0, 33 }, { 32, HELILANDING, 0, 41 }, { 33, LANDING, RUNWAY_IN_block, 34 }, { 34, 0, RUNWAY_IN_block, 35 }, { 35, 0, RUNWAY_IN_block, 36 }, { 36, ENDLANDING, IN_WAY_block, 36 }, { 36, 255, TERM_GROUP1_block, 0 }, { 36, 255, TERM_GROUP2_ENTER1_block, 1 }, { 36, TERM4, 0, 12 }, { 36, TERM5, 0, 12 }, { 36, TERM6, 0, 12 }, { 36, 0, 0, 2 }, /* In Air */ { 37, 0, NOTHING_block, 38 }, { 38, 0, NOTHING_block, 39 }, { 39, 0, NOTHING_block, 40 }, { 40, 0, NOTHING_block, 32 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 41, HELILANDING, PRE_HELIPAD_block, 42 }, { 42, HELIENDLANDING, PRE_HELIPAD_block, 42 }, { 42, HELIPAD1, 0, 43 }, { 42, HELIPAD2, 0, 44 }, { 42, HANGAR, 0, 49 }, { 43, 0, NOTHING_block, 45 }, { 44, 0, NOTHING_block, 46 }, /* landing */ { 45, 255, NOTHING_block, 0 }, { 45, HELIPAD1, HELIPAD1_block, 10 }, { 46, 255, NOTHING_block, 0 }, { 46, HELIPAD2, HELIPAD2_block, 11 }, /* Helicopter -- takeoff */ { 47, HELITAKEOFF, NOTHING_block, 0 }, { 48, HELITAKEOFF, NOTHING_block, 0 }, { 49, 0, HANGAR2_AREA_block, 50 }, // need to go to hangar when waiting in air { 50, 0, HANGAR2_AREA_block, 3 }, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; /* intercontinental */ static const HangarTileTable _airport_depots_intercontinental[] = { {{0, 5}, DIR_SE, 0}, {{8, 4}, DIR_SE, 1} }; static const byte _airport_terminal_intercontinental[] = { 2, 4, 4 }; static const byte _airport_entries_intercontinental[] = { 44, 43, 46, 45 }; static const AirportFTAbuildup _airport_fta_intercontinental[] = { { 0, HANGAR, NOTHING_block, 2 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 0 }, { 0, 255, HANGAR1_AREA_block | TERM_GROUP1_block, 1 }, { 0, TAKEOFF, HANGAR1_AREA_block | TERM_GROUP1_block, 2 }, { 0, 0, 0, 2 }, { 1, HANGAR, NOTHING_block, 3 }, { 1, 255, HANGAR2_AREA_block, 1 }, { 1, 255, HANGAR2_AREA_block, 0 }, { 1, 0, 0, 3 }, { 2, 255, HANGAR1_AREA_block, 0 }, { 2, 255, TERM_GROUP1_block, 0 }, { 2, 255, TERM_GROUP1_block, 1 }, { 2, HANGAR, 0, 0 }, { 2, TAKEOFF, TERM_GROUP1_block, 27 }, { 2, TERM5, 0, 26 }, { 2, TERM6, 0, 26 }, { 2, TERM7, 0, 26 }, { 2, TERM8, 0, 26 }, { 2, HELIPAD1, 0, 26 }, { 2, HELIPAD2, 0, 26 }, { 2, HELITAKEOFF, 0, 74 }, { 2, 0, 0, 27 }, { 3, 255, HANGAR2_AREA_block, 0 }, { 3, HANGAR, 0, 1 }, { 3, HELITAKEOFF, 0, 75 }, {3, TAKEOFF, 0, 59}, { 3, 0, 0, 20 }, { 4, TERM1, TERM1_block, 26 }, { 4, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 26 }, { 4, 0, 0, 26 }, { 5, TERM2, TERM2_block, 27 }, { 5, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 27 }, { 5, 0, 0, 27 }, { 6, TERM3, TERM3_block, 28 }, { 6, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 28 }, { 6, 0, 0, 28 }, { 7, TERM4, TERM4_block, 29 }, { 7, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 7, 0, 0, 29 }, { 8, TERM5, TERM5_block, 18 }, { 8, HANGAR, HANGAR2_AREA_block, 18 }, { 8, 0, 0, 18 }, { 9, TERM6, TERM6_block, 19 }, { 9, HANGAR, HANGAR2_AREA_block, 19 }, { 9, 0, 0, 19 }, { 10, TERM7, TERM7_block, 20 }, { 10, HANGAR, HANGAR2_AREA_block, 20 }, { 10, 0, 0, 20 }, { 11, TERM8, TERM8_block, 21 }, { 11, HANGAR, HANGAR2_AREA_block, 21 }, { 11, 0, 0, 21 }, { 12, HELIPAD1, HELIPAD1_block, 12 }, { 12, HANGAR, 0, 70 }, { 12, HELITAKEOFF, 0, 72 }, { 13, HELIPAD2, HELIPAD2_block, 13 }, { 13, HANGAR, 0, 71 }, { 13, HELITAKEOFF, 0, 73 }, { 14, 0, TERM_GROUP2_ENTER1_block, 15 }, { 15, 0, TERM_GROUP2_ENTER1_block, 16 }, { 16, 0, TERM_GROUP2_ENTER2_block, 17 }, { 17, 0, TERM_GROUP2_ENTER2_block, 18 }, { 18, 255, TERM_GROUP2_block, 0 }, { 18, TERM5, TERM5_block, 8 }, { 18, TAKEOFF, 0, 19 }, { 18, HELITAKEOFF, HELIPAD1_block, 19 }, { 18, 0, TERM_GROUP2_EXIT1_block, 19 }, { 19, 255, TERM_GROUP2_block, 0 }, { 19, TERM6, TERM6_block, 9 }, { 19, TERM5, 0, 18 }, { 19, TAKEOFF, 0, 57 }, { 19, HELITAKEOFF, HELIPAD1_block, 20 }, { 19, 0, TERM_GROUP2_EXIT1_block, 20 }, // add exit to runway out 2 { 20, 255, TERM_GROUP2_block, 0 }, { 20, TERM7, TERM7_block, 10 }, { 20, TERM5, 0, 19 }, { 20, TERM6, 0, 19 }, { 20, HANGAR, HANGAR2_AREA_block, 3 }, { 20, TAKEOFF, 0, 19 }, { 20, 0, TERM_GROUP2_EXIT1_block, 21 }, { 21, 255, TERM_GROUP2_block, 0 }, { 21, TERM8, TERM8_block, 11 }, { 21, HANGAR, HANGAR2_AREA_block, 20 }, { 21, TERM5, 0, 20 }, { 21, TERM6, 0, 20 }, { 21, TERM7, 0, 20 }, { 21, TAKEOFF, 0, 20 }, { 21, 0, TERM_GROUP2_EXIT1_block, 22 }, { 22, 255, TERM_GROUP2_block, 0 }, { 22, HANGAR, 0, 21 }, { 22, TERM5, 0, 21 }, { 22, TERM6, 0, 21 }, { 22, TERM7, 0, 21 }, { 22, TERM8, 0, 21 }, { 22, TAKEOFF, 0, 21 }, { 22, 0, 0, 23 }, { 23, 0, TERM_GROUP2_EXIT1_block, 70 }, { 24, 0, TERM_GROUP2_EXIT2_block, 25 }, { 25, 255, TERM_GROUP2_EXIT2_block, 0 }, { 25, HANGAR, HANGAR1_AREA_block | TERM_GROUP1_block, 29 }, { 25, 0, 0, 29 }, { 26, 255, TERM_GROUP1_block, 0 }, { 26, TERM1, TERM1_block, 4 }, { 26, HANGAR, HANGAR1_AREA_block, 27 }, { 26, TERM5, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM6, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM7, TERM_GROUP2_ENTER1_block, 14 }, { 26, TERM8, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD1, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELIPAD2, TERM_GROUP2_ENTER1_block, 14 }, { 26, HELITAKEOFF, TERM_GROUP2_ENTER1_block, 14 }, { 26, 0, 0, 27 }, { 27, 255, TERM_GROUP1_block, 0 }, { 27, TERM2, TERM2_block, 5 }, { 27, HANGAR, HANGAR1_AREA_block, 2 }, { 27, TERM1, 0, 26 }, { 27, TERM5, 0, 26 }, { 27, TERM6, 0, 26 }, { 27, TERM7, 0, 26 }, { 27, TERM8, 0, 26 }, { 27, HELIPAD1, 0, 14 }, { 27, HELIPAD2, 0, 14 }, { 27, 0, 0, 28 }, { 28, 255, TERM_GROUP1_block, 0 }, { 28, TERM3, TERM3_block, 6 }, { 28, HANGAR, HANGAR1_AREA_block, 27 }, { 28, TERM1, 0, 27 }, { 28, TERM2, 0, 27 }, { 28, TERM4, 0, 29 }, { 28, TERM5, 0, 14 }, { 28, TERM6, 0, 14 }, { 28, TERM7, 0, 14 }, { 28, TERM8, 0, 14 }, { 28, HELIPAD1, 0, 14 }, { 28, HELIPAD2, 0, 14 }, { 28, 0, 0, 29 }, { 29, 255, TERM_GROUP1_block, 0 }, { 29, TERM4, TERM4_block, 7 }, { 29, HANGAR, HANGAR1_AREA_block, 27 }, { 29, TAKEOFF, 0, 30 }, { 29, 0, 0, 28 }, { 30, 0, OUT_WAY_block2, 31 }, { 31, 0, OUT_WAY_block, 32 }, /* takeoff */ { 32, TAKEOFF, RUNWAY_OUT_block, 33 }, { 33, 0, RUNWAY_OUT_block, 34 }, { 34, STARTTAKEOFF, NOTHING_block, 35 }, { 35, ENDTAKEOFF, NOTHING_block, 0 }, /* landing */ { 36, 0, 0, 0 }, { 37, LANDING, RUNWAY_IN_block, 38 }, { 38, 0, RUNWAY_IN_block, 39 }, { 39, 0, RUNWAY_IN_block, 40 }, { 40, ENDLANDING, RUNWAY_IN_block, 41 }, { 41, 0, IN_WAY_block, 42 }, { 42, 255, IN_WAY_block, 0 }, { 42, 255, TERM_GROUP1_block, 0 }, { 42, 255, TERM_GROUP1_block, 1 }, { 42, HANGAR, 0, 2 }, { 42, 0, 0, 26 }, /* In Air */ { 43, 0, 0, 44 }, { 44, FLYING, 0, 45 }, { 44, HELILANDING, 0, 47 }, { 44, LANDING, 0, 69 }, { 44, 0, 0, 45 }, { 45, 0, 0, 46 }, { 46, FLYING, 0, 43 }, { 46, LANDING, 0, 76 }, { 46, 0, 0, 43 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 47, HELILANDING, PRE_HELIPAD_block, 48 }, { 48, HELIENDLANDING, PRE_HELIPAD_block, 48 }, { 48, HELIPAD1, 0, 49 }, { 48, HELIPAD2, 0, 50 }, { 48, HANGAR, 0, 55 }, { 49, 0, NOTHING_block, 51 }, { 50, 0, NOTHING_block, 52 }, /* landing */ { 51, 255, NOTHING_block, 0 }, { 51, HELIPAD1, HELIPAD1_block, 12 }, { 51, HANGAR, 0, 55 }, { 51, 0, 0, 12 }, { 52, 255, NOTHING_block, 0 }, { 52, HELIPAD2, HELIPAD2_block, 13 }, { 52, HANGAR, 0, 55 }, { 52, 0, 0, 13 }, /* Helicopter -- takeoff */ { 53, HELITAKEOFF, NOTHING_block, 0 }, { 54, HELITAKEOFF, NOTHING_block, 0 }, { 55, 0, HANGAR2_AREA_block, 56 }, // need to go to hangar when waiting in air { 56, 0, HANGAR2_AREA_block, 3 }, /* runway 2 out support */ { 57, 255, OUT_WAY2_block, 0 }, { 57, TAKEOFF, 0, 58 }, { 57, 0, 0, 58 }, { 58, 0, OUT_WAY2_block, 59 }, { 59, TAKEOFF, RUNWAY_OUT2_block, 60 }, // takeoff { 60, 0, RUNWAY_OUT2_block, 61 }, { 61, STARTTAKEOFF, NOTHING_block, 62 }, { 62, ENDTAKEOFF, NOTHING_block, 0 }, /* runway 2 in support */ { 63, LANDING, RUNWAY_IN2_block, 64 }, { 64, 0, RUNWAY_IN2_block, 65 }, { 65, 0, RUNWAY_IN2_block, 66 }, { 66, ENDLANDING, RUNWAY_IN2_block, 0 }, { 66, 255, 0, 1 }, { 66, 255, 0, 0 }, { 66, 0, 0, 67 }, { 67, 0, IN_WAY2_block, 68 }, { 68, 255, IN_WAY2_block, 0 }, { 68, 255, TERM_GROUP2_block, 1 }, { 68, 255, TERM_GROUP1_block, 0 }, { 68, HANGAR, HANGAR2_AREA_block, 22 }, { 68, 0, 0, 22 }, { 69, 255, RUNWAY_IN2_block, 0 }, { 69, 0, RUNWAY_IN2_block, 63 }, { 70, 255, TERM_GROUP2_EXIT1_block, 0 }, { 70, HELIPAD1, HELIPAD1_block, 12 }, { 70, HELITAKEOFF, HELIPAD1_block, 12 }, { 70, 0, 0, 71 }, { 71, 255, TERM_GROUP2_EXIT1_block, 0 }, { 71, HELIPAD2, HELIPAD2_block, 13 }, { 71, HELITAKEOFF, HELIPAD1_block, 12 }, { 71, 0, 0, 24 }, { 72, 0, HELIPAD1_block, 53 }, { 73, 0, HELIPAD2_block, 54 }, { 74, HELITAKEOFF, NOTHING_block, 0 }, { 75, HELITAKEOFF, NOTHING_block, 0 }, { 76, 255, RUNWAY_IN_block, 0 }, { 76, 0, RUNWAY_IN_block, 37 }, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; /* heliports, oilrigs don't have depots */ static const byte _airport_entries_heliport[] = { 7, 7, 7, 7 }; static const AirportFTAbuildup _airport_fta_heliport[] = { { 0, HELIPAD1, HELIPAD1_block, 1 }, { 1, HELITAKEOFF, NOTHING_block, 0 }, // takeoff { 2, 255, AIRPORT_BUSY_block, 0 }, { 2, HELILANDING, 0, 3 }, { 2, HELITAKEOFF, 0, 1 }, { 3, HELILANDING, AIRPORT_BUSY_block, 4 }, { 4, HELIENDLANDING, AIRPORT_BUSY_block, 4 }, { 4, HELIPAD1, HELIPAD1_block, 0 }, { 4, HELITAKEOFF, 0, 2 }, /* In Air */ { 5, 0, NOTHING_block, 6 }, { 6, 0, NOTHING_block, 7 }, { 7, 0, NOTHING_block, 8 }, { 8, FLYING, NOTHING_block, 5 }, { 8, HELILANDING, HELIPAD1_block, 2 }, // landing { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; #define _airport_entries_oilrig _airport_entries_heliport #define _airport_fta_oilrig _airport_fta_heliport /* helidepots */ static const HangarTileTable _airport_depots_helidepot[] = { {{1, 0}, DIR_SE, 0} }; static const byte _airport_entries_helidepot[] = { 4, 4, 4, 4 }; static const AirportFTAbuildup _airport_fta_helidepot[] = { { 0, HANGAR, NOTHING_block, 1 }, { 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELIPAD1, HELIPAD1_block, 14 }, { 1, HELITAKEOFF, 0, 15 }, { 1, 0, 0, 0 }, { 2, FLYING, NOTHING_block, 3 }, { 2, HELILANDING, PRE_HELIPAD_block, 7 }, { 2, HANGAR, 0, 12 }, { 2, HELITAKEOFF, NOTHING_block, 16 }, /* In Air */ { 3, 0, NOTHING_block, 4 }, { 4, 0, NOTHING_block, 5 }, { 5, 0, NOTHING_block, 6 }, { 6, 0, NOTHING_block, 2 }, /* Helicopter -- stay in air in special place as a buffer to choose from helipads */ { 7, HELILANDING, PRE_HELIPAD_block, 8 }, { 8, HELIENDLANDING, PRE_HELIPAD_block, 8 }, { 8, HELIPAD1, 0, 9 }, { 8, HANGAR, 0, 12 }, { 8, 0, 0, 2 }, { 9, 0, NOTHING_block, 10 }, /* landing */ { 10, 255, NOTHING_block, 10 }, { 10, HELIPAD1, HELIPAD1_block, 14 }, { 10, HANGAR, 0, 1 }, { 10, 0, 0, 14 }, /* Helicopter -- takeoff */ { 11, HELITAKEOFF, NOTHING_block, 0 }, { 12, 0, HANGAR2_AREA_block, 13 }, // need to go to hangar when waiting in air { 13, 0, HANGAR2_AREA_block, 1 }, { 14, HELIPAD1, HELIPAD1_block, 14 }, { 14, HANGAR, 0, 1 }, { 14, HELITAKEOFF, 0, 17 }, { 15, HELITAKEOFF, NOTHING_block, 0 }, // takeoff outside depot { 16, HELITAKEOFF, 0, 14 }, { 17, 0, NOTHING_block, 11 }, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; /* helistation */ static const HangarTileTable _airport_depots_helistation[] = { {{0, 0}, DIR_SE, 0} }; static const byte _airport_entries_helistation[] = { 25, 25, 25, 25 }; static const AirportFTAbuildup _airport_fta_helistation[] = { { 0, HANGAR, NOTHING_block, 8 }, { 0, HELIPAD1, 0, 1 }, { 0, HELIPAD2, 0, 1 }, { 0, HELIPAD3, 0, 1 }, { 0, HELITAKEOFF, 0, 1 }, { 0, 0, 0, 0 }, { 1, 255, HANGAR2_AREA_block, 0 }, { 1, HANGAR, 0, 0 }, { 1, HELITAKEOFF, 0, 3 }, { 1, 0, 0, 4 }, /* landing */ { 2, FLYING, NOTHING_block, 28 }, { 2, HELILANDING, 0, 15 }, { 2, 0, 0, 28 }, /* helicopter side */ { 3, HELITAKEOFF, NOTHING_block, 0 }, // helitakeoff outside hangar2 { 4, 255, TAXIWAY_BUSY_block, 0 }, { 4, HANGAR, HANGAR2_AREA_block, 1 }, { 4, HELITAKEOFF, 0, 1 }, { 4, 0, 0, 5 }, { 5, 255, TAXIWAY_BUSY_block, 0 }, { 5, HELIPAD1, HELIPAD1_block, 6 }, { 5, HELIPAD2, HELIPAD2_block, 7 }, { 5, HELIPAD3, HELIPAD3_block, 8 }, { 5, 0, 0, 4 }, { 6, HELIPAD1, HELIPAD1_block, 5 }, { 6, HANGAR, HANGAR2_AREA_block, 5 }, { 6, HELITAKEOFF, 0, 9 }, { 6, 0, 0, 6 }, { 7, HELIPAD2, HELIPAD2_block, 5 }, { 7, HANGAR, HANGAR2_AREA_block, 5 }, { 7, HELITAKEOFF, 0, 10 }, { 7, 0, 0, 7 }, { 8, HELIPAD3, HELIPAD3_block, 5 }, { 8, HANGAR, HANGAR2_AREA_block, 5 }, { 8, HELITAKEOFF, 0, 11 }, { 8, 0, 0, 8 }, { 9, 0, HELIPAD1_block, 12 }, { 10, 0, HELIPAD2_block, 13 }, { 11, 0, HELIPAD3_block, 14 }, { 12, HELITAKEOFF, NOTHING_block, 0 }, { 13, HELITAKEOFF, NOTHING_block, 0 }, { 14, HELITAKEOFF, NOTHING_block, 0 }, /* heli - in flight moves */ { 15, HELILANDING, PRE_HELIPAD_block, 16 }, { 16, HELIENDLANDING, PRE_HELIPAD_block, 16 }, { 16, HELIPAD1, 0, 17 }, { 16, HELIPAD2, 0, 18 }, { 16, HELIPAD3, 0, 19 }, { 16, HANGAR, 0, 23 }, { 17, 0, NOTHING_block, 20 }, { 18, 0, NOTHING_block, 21 }, { 19, 0, NOTHING_block, 22 }, /* heli landing */ { 20, 255, NOTHING_block, 0 }, { 20, HELIPAD1, HELIPAD1_block, 6 }, { 20, HANGAR, 0, 23 }, { 20, 0, 0, 6 }, { 21, 255, NOTHING_block, 0 }, { 21, HELIPAD2, HELIPAD2_block, 7 }, { 21, HANGAR, 0, 23 }, { 21, 0, 0, 7 }, { 22, 255, NOTHING_block, 0 }, { 22, HELIPAD3, HELIPAD3_block, 8 }, { 22, HANGAR, 0, 23 }, { 22, 0, 0, 8 }, { 23, 0, HANGAR2_AREA_block, 24 }, // need to go to helihangar when waiting in air { 24, 0, HANGAR2_AREA_block, 1 }, { 25, 0, NOTHING_block, 26 }, { 26, 0, NOTHING_block, 27 }, { 27, 0, NOTHING_block, 2 }, { 28, 0, NOTHING_block, 29 }, { 29, 0, NOTHING_block, 30 }, { 30, 0, NOTHING_block, 31 }, { 31, 0, NOTHING_block, 32 }, { 32, 0, NOTHING_block, 25 }, { MAX_ELEMENTS, 0, 0, 0 } // end marker. DO NOT REMOVE }; #endif /* AIRPORT_MOVEMENT_H */ openttd-1.5.3/src/table/landscape_sprite.h0000644000000000000000000000574512627373436017272 0ustar rootroot/* $Id: landscape_sprite.h 24877 2013-01-01 10:52:32Z rubidium $ */ /* * 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 landscape_sprite.h Offsets of sprites to replace for non-temperate landscapes. */ static const SpriteID END = 0xFFFF; static const SpriteID _landscape_spriteindexes_arctic[] = { 0xF67, 0xF9F, 0xAAD, 0xAB0, 0x83A, 0x845, 0xFA0, 0xFC9, 0x43F, 0x45E, 0x566, 0x56D, 0x945, 0x94C, 0x3ED, 0x40C, 0x515, 0x51C, 0x55A, 0x561, 0x534, 0x546, 0x93D, 0x944, 0x955, 0x95C, 0xFDD, 0xFEC, 0x87D, 0x883, 0xA2B, 0xA39, 0x497, 0x4B0, 0x572, 0x575, 0x94D, 0x954, 0x818, 0x81D, 0x3DE, 0x3EB, 0x1212, 0x1212, END }; static const SpriteID _landscape_spriteindexes_tropic[] = { 0xF67, 0xF9F, 0xAAD, 0xAB0, 0xFA0, 0xFC9, 0x43F, 0x45E, 0x566, 0x56D, 0x945, 0x94C, 0x3ED, 0x40C, 0x515, 0x51C, 0x55A, 0x561, 0x547, 0x559, 0x93D, 0x944, 0x955, 0x95C, 0xFDD, 0xFEC, 0x87D, 0x883, 0xA2B, 0xA39, 0x497, 0x4B0, 0x572, 0x575, 0x94D, 0x954, 0x5AE, 0x5AF, 0x118D, 0x11D8, 0x534, 0x546, 0x40D, 0x426, 0x45F, 0x478, 0x4B1, 0x4CA, 0x95D, 0x97C, 0x3DE, 0x3EB, 0x562, 0x565, 0x56E, 0x571, 0x57A, 0x57D, 0x83A, 0x845, 0xFF5, 0xFF5, 0xFF8, 0xFF8, 0x1212, 0x1212, END }; static const SpriteID _landscape_spriteindexes_toyland[] = { 0xF54, 0xF9F, 0xFDD, 0xFE5, 0xFEC, 0xFEC, 0xFA0, 0xFC9, 0x818, 0x81D, 0x521, 0x546, 0x57E, 0x57F, 0x3ED, 0x40C, 0x43F, 0x45E, 0x491, 0x4B0, 0xA48, 0xA48, 0x4FB, 0x50A, 0x55A, 0x561, 0x566, 0x56D, 0x572, 0x579, 0x427, 0x42C, 0x479, 0x47E, 0x4CB, 0x4D0, 0x4EF, 0x4FA, 0xE9D, 0xECC, 0xF3D, 0xF40, 0xB59, 0xB60, 0xE5D, 0xE6C, 0xA49, 0xA59, 0xA63, 0xA68, 0xA5A, 0xA62, 0xA78, 0xA83, 0xA69, 0xA77, 0xA84, 0xAA3, 0xAA7, 0xAAC, 0xA2B, 0xA47, 0x3DE, 0x3EB, 0x47F, 0x488, 0x4D1, 0x4DA, 0x42D, 0x436, 0x515, 0x51C, 0x580, 0x585, 0xC14, 0xCB3, 0xAAD, 0xAB0, 0xAB5, 0xB00, 0xB69, 0xB70, 0xB61, 0xB68, 0xBC9, 0xBD0, 0xBD9, 0xBE0, 0xBA9, 0xBB0, 0xBC1, 0xBC4, 0x2D0, 0x2D0, 0xAA5, 0xAA6, 0x50F, 0x50F, 0x2EA, 0x2EA, 0x2ED, 0x2EE, 0x512, 0x513, 0x4EB, 0x4EE, 0x4E7, 0x4EA, 0x985, 0xA28, 0x10E4, 0x1133, 0x93D, 0x95C, 0x97D, 0x984, 0x7DA, 0x7DA, 0x2E6, 0x2E6, 0x1, 0x1, 0xE54, 0xE54, 0x51F, 0x520, 0x514, 0x514, 0x511, 0x511, 0x322, 0x322, END }; openttd-1.5.3/src/table/settings.h.preamble0000644000000000000000000002224612627373436017373 0ustar rootroot/* $Id: settings.h.preamble 24991 2013-02-14 11:06:01Z matthijs $ */ /* * 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 table/settings.h Settings to save in the savegame and config file. */ /* Callback function used in _settings[] as well as _company_settings[] */ static size_t ConvertLandscape(const char *value); /**************************** * OTTD specific INI stuff ****************************/ /** * Settings-macro usage: * The list might look daunting at first, but is in general easy to understand. * The macros can be grouped depending on where the config variable is * stored: * 1. SDTG_something * These are for global variables, so this is the one you will use * for a #SettingDescGlobVarList section. Here 'var' refers to a * global variable. * 2. SDTC_something * These are for client-only variables. Here the 'var' refers to an * entry inside _settings_client. * 3. SDT_something * Thse are for members in the struct described by the current * #SettingDesc list / .ini file. Here, 'base' specifies type of the * struct while 'var' points out the member of the struct (the actual * struct to store it in is implicitely defined by the #SettingDesc * list / .ini file preamble the entry is in). * * The something part defines the type of variable to store. There are a * lot of types. Easy ones are: * - VAR: any number type, 'type' field specifies what number. eg int8 or uint32 * - BOOL: a boolean number type * - STR: a string or character. 'type' field specifies what string. Normal, string, or quoted * A bit more difficult to use are MMANY (meaning ManyOfMany) and OMANY (OneOfMany) * These are actually normal numbers, only bitmasked. In MMANY several bits can * be set, in the other only one. * If nothing fits you, you can use the GENERAL macros, but it exposes the * internal structure somewhat so it needs a little looking. There are _NULL() * macros as well, these fill up space so you can add more settings there (in * place) and you DON'T have to increase the savegame version. * * While reading values from openttd.cfg, some values may not be converted * properly, for any kind of reasons. In order to allow a process of self-cleaning * mechanism, a callback procedure is made available. You will have to supply the function, which * will work on a string, one function per setting. And of course, enable the callback param * on the appropriate macro. */ #define NSD_GENERAL(name, def, cmd, guiflags, min, max, interval, many, str, strhelp, strval, proc, load, cat)\ {name, (const void*)(size_t)(def), {(byte)cmd}, {(uint16)guiflags}, min, max, interval, many, str, strhelp, strval, proc, load, cat} /* Macros for various objects to go in the configuration file. * This section is for global variables */ #define SDTG_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, var, length, def, min, max, interval, full, str, strhelp, strval, proc, from, to, cat)\ {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, NULL, cat), SLEG_GENERAL(sle_cmd, var, type | flags, length, from, to)} #define SDTG_VAR(name, type, flags, guiflags, var, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(name, SDT_NUMX, SL_VAR, type, flags, guiflags, var, 0, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTG_BOOL(name, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(name, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, var, 0, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTG_LIST(name, type, length, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(name, SDT_INTLIST, SL_ARR, type, flags, guiflags, var, length, def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTG_STR(name, type, flags, guiflags, var, def, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(name, SDT_STRING, SL_STR, type, flags, guiflags, var, lengthof(var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTG_OMANY(name, type, flags, guiflags, var, def, max, full, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(name, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat) #define SDTG_MMANY(name, type, flags, guiflags, var, def, full, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(name, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, var, 0, def, 0, 0, 0, full, str, strhelp, strval, proc, from, to, cat) #define SDTG_NULL(length, from, to)\ {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLEG_NULL(length, from, to)} #define SDTG_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLEG_END()} /* Macros for various objects to go in the configuration file. * This section is for structures where their various members are saved */ #define SDT_GENERAL(name, sdt_cmd, sle_cmd, type, flags, guiflags, base, var, length, def, min, max, interval, full, str, strhelp, strval, proc, load, from, to, cat)\ {NSD_GENERAL(name, def, sdt_cmd, guiflags, min, max, interval, full, str, strhelp, strval, proc, load, cat), SLE_GENERAL(sle_cmd, base, var, type | flags, length, from, to)} #define SDT_VAR(base, var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\ SDT_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, base, var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, NULL, from, to, cat) #define SDT_BOOL(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ SDT_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, base, var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) #define SDT_LIST(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ SDT_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) #define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, lengthof(((base*)8)->var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) #define SDT_CHR(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, NULL, str, strhelp, strval, proc, NULL, from, to, cat) #define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat)\ SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat) #define SDT_MMANY(base, var, type, flags, guiflags, def, full, str, proc, strhelp, strval, from, to, cat)\ SDT_GENERAL(#var, SDT_MANYOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, 0, 0, full, str, strhelp, strval, proc, NULL, from, to, cat) #define SDT_NULL(length, from, to)\ {{"", NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLE_CONDNULL(length, from, to)} #define SDTC_VAR(var, type, flags, guiflags, def, min, max, interval, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(#var, SDT_NUMX, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, min, max, interval, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTC_BOOL(var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(#var, SDT_BOOLX, SL_VAR, SLE_BOOL, flags, guiflags, _settings_client.var, 1, def, 0, 1, 0, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTC_LIST(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(#var, SDT_INTLIST, SL_ARR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTC_STR(var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, _settings_client.var, lengthof(_settings_client.var), def, 0, 0, 0, NULL, str, strhelp, strval, proc, from, to, cat) #define SDTC_OMANY(var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, cat)\ SDTG_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, _settings_client.var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, from, to, cat) #define SDT_END() {{NULL, NULL, {0}, {0}, 0, 0, 0, NULL, STR_NULL, STR_NULL, STR_NULL, NULL, NULL, SC_NONE}, SLE_END()} openttd-1.5.3/src/table/gameopt_settings.ini0000644000000000000000000001514212627373436017646 0ustar rootroot; $Id: gameopt_settings.ini 26206 2014-01-02 17:55:57Z frosch $ ; ; 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 . ; [pre-amble] static const uint GAME_DIFFICULTY_NUM = 18; static uint16 _old_diff_custom[GAME_DIFFICULTY_NUM]; uint8 _old_diff_level; ///< Old difficulty level from old savegames uint8 _old_units; ///< Old units from old savegames /* Most of these strings are used both for gameopt-backward compatability * and the settings tables. The rest is here for consistency. */ static const char *_locale_currencies = "GBP|USD|EUR|YEN|ATS|BEF|CHF|CZK|DEM|DKK|ESP|FIM|FRF|GRD|HUF|ISK|ITL|NLG|NOK|PLN|RON|RUR|SIT|SEK|YTL|SKK|BRL|EEK|custom"; static const char *_locale_units = "imperial|metric|si"; static const char *_town_names = "english|french|german|american|latin|silly|swedish|dutch|finnish|polish|slovak|norwegian|hungarian|austrian|romanian|czech|swiss|danish|turkish|italian|catalan"; static const char *_climates = "temperate|arctic|tropic|toyland"; static const char *_autosave_interval = "off|monthly|quarterly|half year|yearly"; static const char *_roadsides = "left|right"; static const char *_savegame_date = "long|short|iso"; #ifdef ENABLE_NETWORK static const char *_server_langs = "ANY|ENGLISH|GERMAN|FRENCH|BRAZILIAN|BULGARIAN|CHINESE|CZECH|DANISH|DUTCH|ESPERANTO|FINNISH|HUNGARIAN|ICELANDIC|ITALIAN|JAPANESE|KOREAN|LITHUANIAN|NORWEGIAN|POLISH|PORTUGUESE|ROMANIAN|RUSSIAN|SLOVAK|SLOVENIAN|SPANISH|SWEDISH|TURKISH|UKRAINIAN|AFRIKAANS|CROATIAN|CATALAN|ESTONIAN|GALICIAN|GREEK|LATVIAN"; #endif /* ENABLE_NETWORK */ static const char *_osk_activation = "disabled|double|single|immediately"; static const char *_settings_profiles = "easy|medium|hard"; static const char *_news_display = "off|summarized|full"; static const SettingDesc _gameopt_settings[] = { /* In version 4 a new difficulty setting has been added to the difficulty settings, * town attitude towards demolishing. Needs special handling because some dimwit thought * it funny to have the GameDifficulty struct be an array while it is a struct of * same-sized members * XXX - To save file-space and since values are never bigger than about 10? only * save the first 16 bits in the savegame. Question is why the values are still int32 * and why not byte for example? * 'SLE_FILE_I16 | SLE_VAR_U16' in "diff_custom" is needed to get around SlArray() hack * for savegames version 0 - though it is an array, it has to go through the byteswap process */ [post-amble] }; [templates] SDTG_GENERAL = SDTG_GENERAL($name, $sdt_cmd, $sle_cmd, $type, $flags, $guiflags, $var, $length, $def, $min, $max, $interval, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_NULL = SDT_NULL($length, $from, $to), SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_END = SDT_END() [defaults] flags = 0 guiflags = 0 interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = NULL load = NULL from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED [SDTG_GENERAL] name = ""diff_custom"" sdt_cmd = SDT_INTLIST sle_cmd = SL_ARR type = SLE_FILE_I16 | SLE_VAR_U16 flags = SLF_NOT_IN_CONFIG var = _old_diff_custom length = 17 def = 0 min = 0 max = 0 full = NULL to = 3 [SDTG_GENERAL] name = ""diff_custom"" sdt_cmd = SDT_INTLIST sle_cmd = SL_ARR type = SLE_UINT16 flags = SLF_NOT_IN_CONFIG var = _old_diff_custom length = 18 def = 0 min = 0 max = 0 full = NULL from = 4 ## [SDTG_VAR] name = ""diff_level"" var = _old_diff_level type = SLE_UINT8 flags = SLF_NOT_IN_CONFIG def = SP_CUSTOM min = SP_EASY max = SP_CUSTOM cat = SC_BASIC [SDT_OMANY] base = GameSettings var = locale.currency type = SLE_UINT8 flags = SLF_NO_NETWORK_SYNC def = 0 max = CURRENCY_END - 1 full = _locale_currencies cat = SC_BASIC [SDTG_OMANY] name = ""units"" var = _old_units type = SLE_UINT8 flags = SLF_NOT_IN_CONFIG def = 1 max = 2 full = _locale_units cat = SC_BASIC # There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow # these bigger values (21-255). Invalid values will fallback to english on use and (undefined string) in GUI. [SDT_OMANY] base = GameSettings var = game_creation.town_name type = SLE_UINT8 def = 0 max = 255 full = _town_names cat = SC_BASIC [SDT_OMANY] base = GameSettings var = game_creation.landscape type = SLE_UINT8 def = 0 max = 3 full = _climates load = ConvertLandscape cat = SC_BASIC [SDT_VAR] base = GameSettings var = game_creation.snow_line_height type = SLE_UINT8 def = DEF_SNOWLINE_HEIGHT * TILE_HEIGHT min = MIN_SNOWLINE_HEIGHT * TILE_HEIGHT max = MAX_SNOWLINE_HEIGHT * TILE_HEIGHT to = 21 [SDT_NULL] length = 1 from = 22 to = 164 [SDT_NULL] length = 1 to = 22 [SDTC_OMANY] var = gui.autosave type = SLE_UINT8 from = 23 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 1 max = 4 full = _autosave_interval cat = SC_BASIC [SDT_OMANY] base = GameSettings var = vehicle.road_side type = SLE_UINT8 def = 1 max = 1 full = _roadsides cat = SC_BASIC [SDT_END] openttd-1.5.3/src/table/misc_settings.ini0000644000000000000000000001617712627373436017156 0ustar rootroot; $Id: misc_settings.ini 26990 2014-10-11 13:22:37Z peter1138 $ ; ; 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 . ; [pre-amble] extern char _config_language_file[MAX_PATH]; static const char *_support8bppmodes = "no|system|hardware"; static const SettingDescGlobVarList _misc_settings[] = { [post-amble] }; [templates] SDTG_LIST = SDTG_LIST($name, $type, $length, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_MMANY = SDTG_MMANY($name, $type, $flags, $guiflags, $var, $def, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_STR = SDTG_STR($name, $type, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_END = SDTG_END() [defaults] flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = 0 interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = NULL load = NULL from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED [SDTG_MMANY] name = ""display_opt"" type = SLE_UINT8 var = _display_opt def = (1 << DO_SHOW_TOWN_NAMES | 1 << DO_SHOW_STATION_NAMES | 1 << DO_SHOW_SIGNS | 1 << DO_FULL_ANIMATION | 1 << DO_FULL_DETAIL | 1 << DO_SHOW_WAYPOINT_NAMES | 1 << DO_SHOW_COMPETITOR_SIGNS) full = ""SHOW_TOWN_NAMES|SHOW_STATION_NAMES|SHOW_SIGNS|FULL_ANIMATION||FULL_DETAIL|WAYPOINTS|SHOW_COMPETITOR_SIGNS"" [SDTG_BOOL] name = ""fullscreen"" var = _fullscreen def = false cat = SC_BASIC [SDTG_OMANY] name = ""support8bpp"" type = SLE_UINT8 var = _support8bpp def = 0 max = 2 full = _support8bppmodes cat = SC_BASIC [SDTG_STR] name = ""graphicsset"" type = SLE_STRQ var = BaseGraphics::ini_set def = NULL cat = SC_BASIC [SDTG_STR] name = ""soundsset"" type = SLE_STRQ var = BaseSounds::ini_set def = NULL cat = SC_BASIC [SDTG_STR] name = ""musicset"" type = SLE_STRQ var = BaseMusic::ini_set def = NULL cat = SC_BASIC [SDTG_STR] name = ""videodriver"" type = SLE_STRQ var = _ini_videodriver def = NULL cat = SC_EXPERT [SDTG_STR] name = ""musicdriver"" type = SLE_STRQ var = _ini_musicdriver def = NULL cat = SC_EXPERT [SDTG_STR] name = ""sounddriver"" type = SLE_STRQ var = _ini_sounddriver def = NULL cat = SC_EXPERT [SDTG_STR] name = ""blitter"" type = SLE_STRQ var = _ini_blitter def = NULL [SDTG_STR] name = ""language"" type = SLE_STRB var = _config_language_file def = NULL cat = SC_BASIC ; workaround for implicit lengthof() in SDTG_LIST [SDTG_LIST] name = ""resolution"" type = SLE_INT length = 2 var = _cur_resolution def = ""640,480"" cat = SC_BASIC [SDTG_STR] name = ""screenshot_format"" type = SLE_STRB var = _screenshot_format_name def = NULL cat = SC_EXPERT [SDTG_STR] name = ""savegame_format"" type = SLE_STRB var = _savegame_format def = NULL cat = SC_EXPERT [SDTG_BOOL] name = ""rightclick_emulate"" var = _rightclick_emulate def = false [SDTG_STR] ifdef = WITH_FREETYPE name = ""small_font"" type = SLE_STRB var = _freetype.small.font def = NULL [SDTG_STR] ifdef = WITH_FREETYPE name = ""medium_font"" type = SLE_STRB var = _freetype.medium.font def = NULL [SDTG_STR] ifdef = WITH_FREETYPE name = ""large_font"" type = SLE_STRB var = _freetype.large.font def = NULL [SDTG_STR] ifdef = WITH_FREETYPE name = ""mono_font"" type = SLE_STRB var = _freetype.mono.font def = NULL [SDTG_VAR] ifdef = WITH_FREETYPE name = ""small_size"" type = SLE_UINT var = _freetype.small.size def = 0 min = 0 max = 72 [SDTG_VAR] ifdef = WITH_FREETYPE name = ""medium_size"" type = SLE_UINT var = _freetype.medium.size def = 0 min = 0 max = 72 [SDTG_VAR] ifdef = WITH_FREETYPE name = ""large_size"" type = SLE_UINT var = _freetype.large.size def = 0 min = 0 max = 72 [SDTG_VAR] ifdef = WITH_FREETYPE name = ""mono_size"" type = SLE_UINT var = _freetype.mono.size def = 0 min = 0 max = 72 [SDTG_BOOL] ifdef = WITH_FREETYPE name = ""small_aa"" var = _freetype.small.aa def = false [SDTG_BOOL] ifdef = WITH_FREETYPE name = ""medium_aa"" var = _freetype.medium.aa def = false [SDTG_BOOL] ifdef = WITH_FREETYPE name = ""large_aa"" var = _freetype.large.aa def = false [SDTG_BOOL] ifdef = WITH_FREETYPE name = ""mono_aa"" var = _freetype.mono.aa def = false [SDTG_VAR] name = ""sprite_cache_size_px"" type = SLE_UINT var = _sprite_cache_size def = 128 min = 1 max = 512 cat = SC_EXPERT [SDTG_VAR] name = ""player_face"" type = SLE_UINT32 var = _company_manager_face def = 0 min = 0 max = 0xFFFFFFFF cat = SC_BASIC [SDTG_VAR] name = ""transparency_options"" type = SLE_UINT var = _transparency_opt def = 0 min = 0 max = 0x1FF cat = SC_BASIC [SDTG_VAR] name = ""transparency_locks"" type = SLE_UINT var = _transparency_lock def = 0 min = 0 max = 0x1FF cat = SC_BASIC [SDTG_VAR] name = ""invisibility_options"" type = SLE_UINT var = _invisibility_opt def = 0 min = 0 max = 0xFF cat = SC_BASIC [SDTG_STR] name = ""keyboard"" type = SLE_STRB var = _keyboard_opt[0] def = NULL cat = SC_EXPERT [SDTG_STR] name = ""keyboard_caps"" type = SLE_STRB var = _keyboard_opt[1] def = NULL cat = SC_EXPERT [SDTG_VAR] name = ""last_newgrf_count"" type = SLE_UINT32 var = _settings_client.gui.last_newgrf_count def = 100 min = 0 max = UINT32_MAX cat = SC_EXPERT [SDTG_VAR] name = ""gui_zoom"" type = SLE_UINT8 var = _gui_zoom def = ZOOM_LVL_OUT_4X min = ZOOM_LVL_MIN max = ZOOM_LVL_OUT_4X cat = SC_BASIC [SDTG_END] openttd-1.5.3/src/table/genland.h0000644000000000000000000000506312627373436015353 0ustar rootroot/* $Id: genland.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 genland.h Table used to generate deserts and/or rain forests. */ #define M(x, y) {x, y} static const TileIndexDiffC _make_desert_or_rainforest_data[] = { M(-5, -6), M(-4, -6), M(-3, -6), M(-2, -6), M(-1, -6), M( 0, -5), M( 1, -5), M( 2, -5), M( 3, -5), M( 4, -5), M( 5, -5), M(-5, -5), M(-4, -5), M(-3, -5), M(-2, -5), M(-1, -5), M( 0, -4), M( 1, -4), M( 2, -4), M( 3, -4), M( 4, -4), M( 5, -4), M(-5, -4), M(-4, -4), M(-3, -4), M(-2, -4), M(-1, -4), M( 0, -3), M( 1, -3), M( 2, -3), M( 3, -3), M( 4, -3), M( 5, -3), M(-5, -3), M(-4, -3), M(-3, -3), M(-2, -3), M(-1, -3), M( 0, -2), M( 1, -2), M( 2, -2), M( 3, -2), M( 4, -2), M( 5, -2), M(-5, -2), M(-4, -2), M(-3, -2), M(-2, -2), M(-1, -2), M( 0, -1), M( 1, -1), M( 2, -1), M( 3, -1), M( 4, -1), M( 5, -1), M(-5, -1), M(-4, -1), M(-3, -1), M(-2, -1), M(-1, -1), M( 0, 0), M( 1, 0), M( 2, 0), M( 3, 0), M( 4, 0), M( 5, 0), M(-5, 0), M(-4, 0), M(-3, 0), M(-2, 0), M(-1, 0), M( 0, 1), M( 1, 1), M( 2, 1), M( 3, 1), M( 4, 1), M( 5, 1), M(-5, 1), M(-4, 1), M(-3, 1), M(-2, 1), M(-1, 1), M( 0, 2), M( 1, 2), M( 2, 2), M( 3, 2), M( 4, 2), M( 5, 2), M(-5, 2), M(-4, 2), M(-3, 2), M(-2, 2), M(-1, 2), M( 0, 3), M( 1, 3), M( 2, 3), M( 3, 3), M( 4, 3), M( 5, 3), M(-5, 3), M(-4, 3), M(-3, 3), M(-2, 3), M(-1, 3), M( 0, 4), M( 1, 4), M( 2, 4), M( 3, 4), M( 4, 4), M( 5, 4), M(-5, 4), M(-4, 4), M(-3, 4), M(-2, 4), M(-1, 4), M( 0, 5), M( 1, 5), M( 2, 5), M( 3, 5), M( 4, 5), M( 5, 5), M( 6, -3), M(-6, -4), M(-3, 5), M(-3, -7), M( 6, -2), M(-6, -3), M(-2, 5), M(-2, -7), M( 6, -1), M(-6, -2), M(-1, 5), M(-1, -7), M( 6, 0), M(-6, -1), M( 0, 6), M( 0, -6), M( 6, 1), M(-6, 0), M( 1, 6), M( 1, -6), M( 6, 2), M(-6, 1), M( 2, 6), M( 2, -6), M( 6, 3), M(-6, 2), M( 3, 6), M( 3, -6) }; #undef M openttd-1.5.3/src/table/settings.ini0000644000000000000000000027363112627373436016143 0ustar rootroot; $Id: settings.ini 27163 2015-02-22 15:26:27Z frosch $ ; ; 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 . ; [pre-amble] /* Begin - Callback Functions for the various settings */ static bool v_PositionMainToolbar(int32 p1); static bool v_PositionStatusbar(int32 p1); static bool PopulationInLabelActive(int32 p1); static bool RedrawScreen(int32 p1); static bool RedrawSmallmap(int32 p1); static bool StationSpreadChanged(int32 p1); static bool InvalidateBuildIndustryWindow(int32 p1); static bool CloseSignalGUI(int32 p1); static bool InvalidateTownViewWindow(int32 p1); static bool DeleteSelectStationWindow(int32 p1); static bool UpdateConsists(int32 p1); static bool TrainAccelerationModelChanged(int32 p1); static bool RoadVehAccelerationModelChanged(int32 p1); static bool TrainSlopeSteepnessChanged(int32 p1); static bool RoadVehSlopeSteepnessChanged(int32 p1); static bool DragSignalsDensityChanged(int32); static bool TownFoundingChanged(int32 p1); static bool DifficultyNoiseChange(int32 i); static bool MaxNoAIsChange(int32 i); static bool CheckRoadSide(int p1); static bool ChangeMaxHeightLevel(int32 p1); static bool CheckFreeformEdges(int32 p1); static bool ChangeDynamicEngines(int32 p1); static bool StationCatchmentChanged(int32 p1); static bool InvalidateVehTimetableWindow(int32 p1); static bool InvalidateCompanyLiveryWindow(int32 p1); static bool InvalidateNewGRFChangeWindows(int32 p1); static bool InvalidateIndustryViewWindow(int32 p1); static bool InvalidateAISettingsWindow(int32 p1); static bool RedrawTownAuthority(int32 p1); static bool InvalidateCompanyInfrastructureWindow(int32 p1); static bool InvalidateCompanyWindow(int32 p1); static bool ZoomMinMaxChanged(int32 p1); static bool MaxVehiclesChanged(int32 p1); #ifdef ENABLE_NETWORK static bool UpdateClientName(int32 p1); static bool UpdateServerPassword(int32 p1); static bool UpdateRconPassword(int32 p1); static bool UpdateClientConfigValues(int32 p1); #endif /* ENABLE_NETWORK */ /* End - Callback Functions for the various settings */ /* Some settings do not need to be synchronised when playing in multiplayer. * These include for example the GUI settings and will not be saved with the * savegame. * It is also a bit tricky since you would think that service_interval * for example doesn't need to be synched. Every client assigns the * service_interval value to the v->service_interval, meaning that every client * assigns his value. If the setting was company-based, that would mean that * vehicles could decide on different moments that they are heading back to a * service depot, causing desyncs on a massive scale. */ const SettingDesc _settings[] = { [post-amble] }; [templates] SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_OMANY = SDTG_OMANY($name, $type, $flags, $guiflags, $var, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTC_BOOL = SDTC_BOOL( $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTC_LIST = SDTC_LIST( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTC_OMANY = SDTC_OMANY( $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTC_STR = SDTC_STR( $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTC_VAR = SDTC_VAR( $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_OMANY = SDT_OMANY($base, $var, $type, $flags, $guiflags, $def, $max, $full, $str, $strhelp, $strval, $proc, $from, $to, $load, $cat), SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_NULL = SDT_NULL($length, $from, $to), SDT_END = SDT_END() [defaults] flags = 0 guiflags = 0 interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = NULL load = NULL from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED ; Saved settings variables. ; Do not ADD or REMOVE something in this "difficulty.XXX" table or before it. It breaks savegame compatability. [SDT_VAR] base = GameSettings var = difficulty.max_no_competitors type = SLE_UINT8 from = 97 def = 0 min = 0 max = MAX_COMPANIES - 1 interval = 1 proc = MaxNoAIsChange cat = SC_BASIC [SDT_NULL] length = 1 from = 97 to = 109 [SDT_VAR] base = GameSettings var = difficulty.number_towns type = SLE_UINT8 from = 97 guiflags = SGF_NEWGAME_ONLY def = 2 min = 0 max = 4 interval = 1 strval = STR_NUM_VERY_LOW cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.industry_density type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING def = ID_END - 1 min = 0 max = ID_END - 1 interval = 1 str = STR_CONFIG_SETTING_INDUSTRY_DENSITY strhelp = STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT strval = STR_FUNDING_ONLY cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.max_loan type = SLE_UINT32 from = 97 guiflags = SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO | SGF_CURRENCY def = 300000 min = 100000 max = 500000 interval = 50000 str = STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN strhelp = STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT strval = STR_JUST_CURRENCY_LONG cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.initial_interest type = SLE_UINT8 from = 97 guiflags = SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO def = 2 min = 2 max = 4 interval = 1 str = STR_CONFIG_SETTING_INTEREST_RATE strhelp = STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT strval = STR_CONFIG_SETTING_PERCENTAGE [SDT_VAR] base = GameSettings var = difficulty.vehicle_costs type = SLE_UINT8 from = 97 guiflags = SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO | SGF_MULTISTRING def = 0 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_RUNNING_COSTS strhelp = STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT strval = STR_SEA_LEVEL_LOW cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.competitor_speed type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING def = 2 min = 0 max = 4 interval = 1 str = STR_CONFIG_SETTING_CONSTRUCTION_SPEED strhelp = STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT strval = STR_AI_SPEED_VERY_SLOW cat = SC_BASIC [SDT_NULL] length = 1 from = 97 to = 109 [SDT_VAR] base = GameSettings var = difficulty.vehicle_breakdowns type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING def = 1 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS strhelp = STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT strval = STR_DISASTER_NONE cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.subsidy_multiplier type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING def = 2 min = 0 max = 3 interval = 1 str = STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER strhelp = STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT strval = STR_SUBSIDY_X1_5 [SDT_VAR] base = GameSettings var = difficulty.construction_cost type = SLE_UINT8 from = 97 guiflags = SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO | SGF_MULTISTRING def = 0 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_CONSTRUCTION_COSTS strhelp = STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT strval = STR_SEA_LEVEL_LOW cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.terrain_type type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING | SGF_NEWGAME_ONLY def = 1 min = 0 max = 4 interval = 1 str = STR_CONFIG_SETTING_TERRAIN_TYPE strhelp = STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT strval = STR_TERRAIN_TYPE_VERY_FLAT cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.quantity_sea_lakes type = SLE_UINT8 from = 97 guiflags = SGF_NEWGAME_ONLY def = 0 min = 0 max = 4 interval = 1 strval = STR_SEA_LEVEL_VERY_LOW cat = SC_BASIC [SDT_BOOL] base = GameSettings var = difficulty.economy from = 97 def = false str = STR_CONFIG_SETTING_RECESSIONS strhelp = STR_CONFIG_SETTING_RECESSIONS_HELPTEXT [SDT_BOOL] base = GameSettings var = difficulty.line_reverse_mode from = 97 def = false str = STR_CONFIG_SETTING_TRAIN_REVERSING strhelp = STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT [SDT_BOOL] base = GameSettings var = difficulty.disasters from = 97 def = false str = STR_CONFIG_SETTING_DISASTERS strhelp = STR_CONFIG_SETTING_DISASTERS_HELPTEXT cat = SC_BASIC [SDT_VAR] base = GameSettings var = difficulty.town_council_tolerance type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING def = 0 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_CITY_APPROVAL strhelp = STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT strval = STR_CITY_APPROVAL_PERMISSIVE proc = DifficultyNoiseChange [SDTG_VAR] name = ""diff_level"" var = _old_diff_level type = SLE_UINT8 flags = SLF_NOT_IN_CONFIG from = 97 to = 177 def = 3 min = 0 max = 3 cat = SC_BASIC ; There are only 21 predefined town_name values (0-20), but you can have more with newgrf action F so allow ; these bigger values (21-255). Invalid values will fallback to english on use and (undefined string) in GUI. [SDT_OMANY] base = GameSettings var = game_creation.town_name type = SLE_UINT8 from = 97 guiflags = SGF_NO_NETWORK def = 0 max = 255 full = _town_names cat = SC_BASIC [SDT_OMANY] base = GameSettings var = game_creation.landscape type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING | SGF_NEWGAME_ONLY def = 0 max = 3 full = _climates load = ConvertLandscape str = STR_CONFIG_SETTING_LANDSCAPE strhelp = STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT strval = STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE cat = SC_BASIC ; Snow line (or snow_line_height * TILE_HEIGHT) [SDT_NULL] length = 1 from = 97 to = 163 [SDT_OMANY] base = GameSettings var = vehicle.road_side type = SLE_UINT8 from = 97 guiflags = SGF_MULTISTRING | SGF_NO_NETWORK def = 1 max = 1 full = _roadsides str = STR_CONFIG_SETTING_ROAD_SIDE strhelp = STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT strval = STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT proc = CheckRoadSide ; Construction [SDT_VAR] base = GameSettings var = construction.max_heightlevel type = SLE_UINT8 from = 194 guiflags = SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO def = DEF_MAX_HEIGHTLEVEL min = MIN_MAX_HEIGHTLEVEL max = MAX_MAX_HEIGHTLEVEL interval = 1 str = STR_CONFIG_SETTING_MAX_HEIGHTLEVEL strhelp = STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT strval = STR_JUST_INT proc = ChangeMaxHeightLevel cat = SC_BASIC [SDT_BOOL] base = GameSettings var = construction.build_on_slopes guiflags = SGF_NO_NETWORK def = true cat = SC_EXPERT [SDT_VAR] base = GameSettings var = construction.command_pause_level type = SLE_UINT8 from = 154 guiflags = SGF_MULTISTRING | SGF_NO_NETWORK def = 1 min = 0 max = 3 interval = 1 str = STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL strhelp = STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT strval = STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS [SDT_VAR] base = GameSettings var = construction.terraform_per_64k_frames type = SLE_UINT32 from = 156 def = 64 << 16 min = 0 max = 1 << 30 interval = 1 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = construction.terraform_frame_burst type = SLE_UINT16 from = 156 def = 4096 min = 0 max = 1 << 30 interval = 1 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = construction.clear_per_64k_frames type = SLE_UINT32 from = 156 def = 64 << 16 min = 0 max = 1 << 30 interval = 1 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = construction.clear_frame_burst type = SLE_UINT16 from = 156 def = 4096 min = 0 max = 1 << 30 interval = 1 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = construction.tree_per_64k_frames type = SLE_UINT32 from = 175 def = 64 << 16 min = 0 max = 1 << 30 interval = 1 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = construction.tree_frame_burst type = SLE_UINT16 from = 175 def = 4096 min = 0 max = 1 << 30 interval = 1 cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = construction.autoslope from = 75 def = true str = STR_CONFIG_SETTING_AUTOSLOPE strhelp = STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = construction.extra_dynamite def = true str = STR_CONFIG_SETTING_EXTRADYNAMITE strhelp = STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT [SDT_VAR] base = GameSettings var = construction.max_bridge_length type = SLE_UINT16 from = 159 guiflags = SGF_NO_NETWORK def = 64 min = 1 max = MAX_MAP_SIZE interval = 1 str = STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH strhelp = STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT strval = STR_CONFIG_SETTING_TILE_LENGTH [SDT_VAR] base = GameSettings var = construction.max_bridge_height type = SLE_UINT8 from = 194 guiflags = SGF_NO_NETWORK def = 12 min = 1 max = MAX_TILE_HEIGHT interval = 1 str = STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT strhelp = STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT strval = STR_JUST_COMMA cat = SC_EXPERT [SDT_VAR] base = GameSettings var = construction.max_tunnel_length type = SLE_UINT16 from = 159 guiflags = SGF_NO_NETWORK def = 64 min = 1 max = MAX_MAP_SIZE interval = 1 str = STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH strhelp = STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT strval = STR_CONFIG_SETTING_TILE_LENGTH # construction.longbridges [SDT_NULL] length = 1 to = 158 [SDT_VAR] base = GameSettings var = construction.train_signal_side type = SLE_UINT8 guiflags = SGF_MULTISTRING | SGF_NO_NETWORK def = 1 min = 0 max = 2 str = STR_CONFIG_SETTING_SIGNALSIDE strhelp = STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT strval = STR_CONFIG_SETTING_SIGNALSIDE_LEFT proc = RedrawScreen cat = SC_BASIC [SDT_BOOL] base = GameSettings var = station.never_expire_airports guiflags = SGF_NO_NETWORK def = false str = STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS strhelp = STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT [SDT_VAR] base = GameSettings var = economy.town_layout type = SLE_UINT8 from = 59 guiflags = SGF_MULTISTRING def = TL_ORIGINAL min = TL_BEGIN max = NUM_TLS - 1 interval = 1 str = STR_CONFIG_SETTING_TOWN_LAYOUT strhelp = STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT strval = STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT proc = TownFoundingChanged [SDT_BOOL] base = GameSettings var = economy.allow_town_roads from = 113 guiflags = SGF_NO_NETWORK def = true str = STR_CONFIG_SETTING_ALLOW_TOWN_ROADS strhelp = STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT [SDT_VAR] base = GameSettings var = economy.found_town type = SLE_UINT8 from = 128 guiflags = SGF_MULTISTRING def = TF_FORBIDDEN min = TF_BEGIN max = TF_END - 1 interval = 1 str = STR_CONFIG_SETTING_TOWN_FOUNDING strhelp = STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT strval = STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN proc = TownFoundingChanged cat = SC_BASIC [SDT_BOOL] base = GameSettings var = economy.allow_town_level_crossings from = 143 guiflags = SGF_NO_NETWORK def = true str = STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS strhelp = STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT ; link graph [SDT_VAR] base = GameSettings var = linkgraph.recalc_interval type = SLE_UINT16 from = 183 def = 4 min = 2 max = 32 interval = 2 str = STR_CONFIG_SETTING_LINKGRAPH_INTERVAL strval = STR_JUST_COMMA strhelp = STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.recalc_time type = SLE_UINT16 from = 183 def = 16 min = 1 max = 4096 interval = 1 str = STR_CONFIG_SETTING_LINKGRAPH_TIME strval = STR_JUST_COMMA strhelp = STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.distribution_pax type = SLE_UINT8 from = 183 guiflags = SGF_MULTISTRING def = DT_MANUAL min = DT_MIN max = DT_MAX interval = 1 str = STR_CONFIG_SETTING_DISTRIBUTION_PAX strval = STR_CONFIG_SETTING_DISTRIBUTION_MANUAL strhelp = STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.distribution_mail type = SLE_UINT8 from = 183 guiflags = SGF_MULTISTRING def = DT_MANUAL min = DT_MIN max = DT_MAX interval = 1 str = STR_CONFIG_SETTING_DISTRIBUTION_MAIL strval = STR_CONFIG_SETTING_DISTRIBUTION_MANUAL strhelp = STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.distribution_armoured type = SLE_UINT8 from = 183 guiflags = SGF_MULTISTRING def = DT_MANUAL min = DT_MIN max = DT_MAX interval = 1 str = STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED strval = STR_CONFIG_SETTING_DISTRIBUTION_MANUAL strhelp = STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.distribution_default type = SLE_UINT8 from = 183 guiflags = SGF_MULTISTRING def = DT_MANUAL min = DT_BEGIN max = DT_MAX_NONSYMMETRIC interval = 1 str = STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT strval = STR_CONFIG_SETTING_DISTRIBUTION_MANUAL strhelp = STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.accuracy type = SLE_UINT8 from = 183 def = 16 min = 2 max = 64 interval = 1 str = STR_CONFIG_SETTING_LINKGRAPH_ACCURACY strval = STR_JUST_COMMA strhelp = STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.demand_distance type = SLE_UINT8 from = 183 def = 100 min = 0 max = 255 interval = 5 str = STR_CONFIG_SETTING_DEMAND_DISTANCE strval = STR_CONFIG_SETTING_PERCENTAGE strhelp = STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.demand_size type = SLE_UINT8 from = 183 def = 100 min = 0 max = 100 interval = 5 str = STR_CONFIG_SETTING_DEMAND_SIZE strval = STR_CONFIG_SETTING_PERCENTAGE strhelp = STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT [SDT_VAR] base = GameSettings var = linkgraph.short_path_saturation type = SLE_UINT8 from = 183 def = 80 min = 0 max = 250 interval = 5 str = STR_CONFIG_SETTING_SHORT_PATH_SATURATION strval = STR_CONFIG_SETTING_PERCENTAGE strhelp = STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT ; Vehicles [SDT_VAR] base = GameSettings var = vehicle.train_acceleration_model type = SLE_UINT8 guiflags = SGF_MULTISTRING def = 0 min = 0 max = 1 interval = 1 str = STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL strhelp = STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT strval = STR_CONFIG_SETTING_ORIGINAL proc = TrainAccelerationModelChanged [SDT_VAR] base = GameSettings var = vehicle.roadveh_acceleration_model type = SLE_UINT8 from = 139 guiflags = SGF_MULTISTRING def = 0 min = 0 max = 1 interval = 1 str = STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL strhelp = STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT strval = STR_CONFIG_SETTING_ORIGINAL proc = RoadVehAccelerationModelChanged [SDT_VAR] base = GameSettings var = vehicle.train_slope_steepness type = SLE_UINT8 from = 133 def = 3 min = 0 max = 10 interval = 1 str = STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS strhelp = STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT strval = STR_CONFIG_SETTING_PERCENTAGE proc = TrainSlopeSteepnessChanged cat = SC_EXPERT [SDT_VAR] base = GameSettings var = vehicle.roadveh_slope_steepness type = SLE_UINT8 from = 139 def = 7 min = 0 max = 10 interval = 1 str = STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS strhelp = STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT strval = STR_CONFIG_SETTING_PERCENTAGE proc = RoadVehSlopeSteepnessChanged cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.forbid_90_deg def = false str = STR_CONFIG_SETTING_FORBID_90_DEG strhelp = STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT cat = SC_EXPERT [SDT_VAR] base = GameSettings var = vehicle.max_train_length type = SLE_UINT8 from = 159 def = 7 min = 1 max = 64 interval = 1 str = STR_CONFIG_SETTING_TRAIN_LENGTH strhelp = STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT strval = STR_CONFIG_SETTING_TILE_LENGTH cat = SC_BASIC ; vehicle.mammoth_trains [SDT_NULL] length = 1 to = 158 [SDT_VAR] base = GameSettings var = vehicle.smoke_amount type = SLE_UINT8 from = 145 guiflags = SGF_MULTISTRING def = 1 min = 0 max = 2 str = STR_CONFIG_SETTING_SMOKE_AMOUNT strhelp = STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT strval = STR_CONFIG_SETTING_NONE ; order.gotodepot [SDT_NULL] length = 1 to = 158 ; path finder [SDT_BOOL] base = GameSettings var = pf.roadveh_queue def = true cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.new_pathfinding_all to = 86 def = false cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.yapf.ship_use_yapf from = 28 to = 86 def = false cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.yapf.road_use_yapf from = 28 to = 86 def = true cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.yapf.rail_use_yapf from = 28 to = 86 def = true cat = SC_EXPERT ## [SDT_VAR] base = GameSettings var = pf.pathfinder_for_trains type = SLE_UINT8 from = 87 guiflags = SGF_MULTISTRING def = 2 min = 1 max = 2 interval = 1 str = STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS strhelp = STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT strval = STR_CONFIG_SETTING_PATHFINDER_NPF cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.pathfinder_for_roadvehs type = SLE_UINT8 from = 87 guiflags = SGF_MULTISTRING def = 2 min = 1 max = 2 interval = 1 str = STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES strhelp = STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT strval = STR_CONFIG_SETTING_PATHFINDER_NPF cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.pathfinder_for_ships type = SLE_UINT8 from = 87 guiflags = SGF_MULTISTRING def = 2 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS strhelp = STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT strval = STR_CONFIG_SETTING_PATHFINDER_OPF cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = vehicle.never_expire_vehicles guiflags = SGF_NO_NETWORK def = false str = STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES strhelp = STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT [SDT_VAR] base = GameSettings var = vehicle.max_trains type = SLE_UINT16 def = 500 min = 0 max = 5000 str = STR_CONFIG_SETTING_MAX_TRAINS strhelp = STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT strval = STR_JUST_COMMA proc = MaxVehiclesChanged cat = SC_BASIC [SDT_VAR] base = GameSettings var = vehicle.max_roadveh type = SLE_UINT16 def = 500 min = 0 max = 5000 str = STR_CONFIG_SETTING_MAX_ROAD_VEHICLES strhelp = STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT strval = STR_JUST_COMMA proc = MaxVehiclesChanged cat = SC_BASIC [SDT_VAR] base = GameSettings var = vehicle.max_aircraft type = SLE_UINT16 def = 200 min = 0 max = 5000 str = STR_CONFIG_SETTING_MAX_AIRCRAFT strhelp = STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT strval = STR_JUST_COMMA proc = MaxVehiclesChanged cat = SC_BASIC [SDT_VAR] base = GameSettings var = vehicle.max_ships type = SLE_UINT16 def = 300 min = 0 max = 5000 str = STR_CONFIG_SETTING_MAX_SHIPS strhelp = STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT strval = STR_JUST_COMMA proc = MaxVehiclesChanged cat = SC_BASIC [SDTG_BOOL] name = NULL guiflags = SGF_NO_NETWORK var = _old_vds.servint_ispercent def = false to = 119 [SDTG_VAR] name = NULL type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_trains def = 150 min = 5 max = 800 to = 119 [SDTG_VAR] name = NULL type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_roadveh def = 150 min = 5 max = 800 to = 119 [SDTG_VAR] name = NULL type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_ships def = 360 min = 5 max = 800 to = 119 [SDTG_VAR] name = NULL type = SLE_UINT16 guiflags = SGF_0ISDISABLED var = _old_vds.servint_aircraft def = 150 min = 5 max = 800 to = 119 [SDT_BOOL] base = GameSettings var = order.no_servicing_if_no_breakdowns def = true str = STR_CONFIG_SETTING_NOSERVICE strhelp = STR_CONFIG_SETTING_NOSERVICE_HELPTEXT [SDT_BOOL] base = GameSettings var = vehicle.wagon_speed_limits guiflags = SGF_NO_NETWORK def = true str = STR_CONFIG_SETTING_WAGONSPEEDLIMITS strhelp = STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT proc = UpdateConsists [SDT_BOOL] base = GameSettings var = vehicle.disable_elrails from = 38 guiflags = SGF_NO_NETWORK def = false str = STR_CONFIG_SETTING_DISABLE_ELRAILS strhelp = STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT proc = SettingsDisableElrail cat = SC_EXPERT [SDT_VAR] base = GameSettings var = vehicle.freight_trains type = SLE_UINT8 from = 39 guiflags = SGF_NO_NETWORK def = 1 min = 1 max = 255 interval = 1 str = STR_CONFIG_SETTING_FREIGHT_TRAINS strhelp = STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT strval = STR_JUST_COMMA proc = UpdateConsists ; order.timetabling [SDT_NULL] length = 1 from = 67 to = 158 [SDT_VAR] base = GameSettings var = vehicle.plane_speed type = SLE_UINT8 from = 90 guiflags = SGF_NO_NETWORK def = 4 min = 1 max = 4 str = STR_CONFIG_SETTING_PLANE_SPEED strhelp = STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT strval = STR_CONFIG_SETTING_PLANE_SPEED_VALUE [SDT_BOOL] base = GameSettings var = vehicle.dynamic_engines from = 95 guiflags = SGF_NO_NETWORK def = true proc = ChangeDynamicEngines cat = SC_EXPERT [SDT_VAR] base = GameSettings var = vehicle.plane_crashes type = SLE_UINT8 from = 138 guiflags = SGF_MULTISTRING def = 2 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_PLANE_CRASHES strhelp = STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT strval = STR_CONFIG_SETTING_PLANE_CRASHES_NONE cat = SC_BASIC ; station.join_stations [SDT_NULL] length = 1 to = 158 [SDTC_BOOL] var = gui.sg_full_load_any from = 22 to = 92 def = true [SDT_BOOL] base = GameSettings var = order.improved_load guiflags = SGF_NO_NETWORK def = true cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = order.selectgoods def = true cat = SC_EXPERT [SDTC_BOOL] var = gui.sg_new_nonstop from = 22 to = 92 def = false ; station.nonuniform_stations [SDT_NULL] length = 1 to = 158 [SDT_VAR] base = GameSettings var = station.station_spread type = SLE_UINT8 def = 12 min = 4 max = 64 str = STR_CONFIG_SETTING_STATION_SPREAD strhelp = STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT strval = STR_CONFIG_SETTING_TILE_LENGTH proc = StationSpreadChanged cat = SC_BASIC [SDT_BOOL] base = GameSettings var = order.serviceathelipad def = true str = STR_CONFIG_SETTING_SERVICEATHELIPAD strhelp = STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = station.modified_catchment def = true str = STR_CONFIG_SETTING_CATCHMENT strhelp = STR_CONFIG_SETTING_CATCHMENT_HELPTEXT proc = StationCatchmentChanged cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = order.gradual_loading from = 40 guiflags = SGF_NO_NETWORK def = true cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = construction.road_stop_on_town_road from = 47 def = true str = STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD strhelp = STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT cat = SC_BASIC [SDT_BOOL] base = GameSettings var = construction.road_stop_on_competitor_road from = 114 def = true str = STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD strhelp = STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT cat = SC_BASIC [SDT_BOOL] base = GameSettings var = station.adjacent_stations from = 62 def = true cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = economy.station_noise_level from = 96 guiflags = SGF_NO_NETWORK def = false str = STR_CONFIG_SETTING_NOISE_LEVEL strhelp = STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT proc = InvalidateTownViewWindow [SDT_BOOL] base = GameSettings var = station.distant_join_stations from = 106 def = true str = STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS strhelp = STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT proc = DeleteSelectStationWindow ## [SDT_BOOL] base = GameSettings var = economy.inflation def = true str = STR_CONFIG_SETTING_INFLATION strhelp = STR_CONFIG_SETTING_INFLATION_HELPTEXT cat = SC_BASIC [SDT_VAR] base = GameSettings var = construction.raw_industry_construction type = SLE_UINT8 guiflags = SGF_MULTISTRING def = 0 min = 0 max = 2 str = STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD strhelp = STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT strval = STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE proc = InvalidateBuildIndustryWindow cat = SC_BASIC [SDT_VAR] base = GameSettings var = construction.industry_platform type = SLE_UINT8 from = 148 def = 1 min = 0 max = 4 str = STR_CONFIG_SETTING_INDUSTRY_PLATFORM strhelp = STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT strval = STR_CONFIG_SETTING_TILE_LENGTH cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = economy.multiple_industry_per_town def = false str = STR_CONFIG_SETTING_MULTIPINDTOWN strhelp = STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT [SDT_NULL] length = 1 to = 140 [SDT_BOOL] base = GameSettings var = economy.bribe def = true str = STR_CONFIG_SETTING_BRIBE strhelp = STR_CONFIG_SETTING_BRIBE_HELPTEXT proc = RedrawTownAuthority cat = SC_BASIC [SDT_BOOL] base = GameSettings var = economy.exclusive_rights from = 79 def = true str = STR_CONFIG_SETTING_ALLOW_EXCLUSIVE strhelp = STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT proc = RedrawTownAuthority cat = SC_BASIC [SDT_BOOL] base = GameSettings var = economy.fund_buildings from = 165 def = true str = STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS strhelp = STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT proc = RedrawTownAuthority cat = SC_BASIC [SDT_BOOL] base = GameSettings var = economy.fund_roads from = 160 def = true str = STR_CONFIG_SETTING_ALLOW_FUND_ROAD strhelp = STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT proc = RedrawTownAuthority cat = SC_BASIC [SDT_BOOL] base = GameSettings var = economy.give_money from = 79 def = true str = STR_CONFIG_SETTING_ALLOW_GIVE_MONEY strhelp = STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT cat = SC_BASIC [SDT_VAR] base = GameSettings var = game_creation.snow_line_height type = SLE_UINT8 guiflags = SGF_NO_NETWORK def = DEF_SNOWLINE_HEIGHT min = MIN_SNOWLINE_HEIGHT max = MAX_SNOWLINE_HEIGHT str = STR_CONFIG_SETTING_SNOWLINE_HEIGHT strhelp = STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT strval = STR_JUST_COMMA cat = SC_BASIC [SDT_NULL] length = 4 to = 143 [SDT_VAR] base = GameSettings var = game_creation.starting_year type = SLE_INT32 def = DEF_START_YEAR min = MIN_YEAR max = MAX_YEAR interval = 1 str = STR_CONFIG_SETTING_STARTING_YEAR strval = STR_JUST_INT cat = SC_BASIC [SDT_NULL] length = 4 to = 104 [SDT_BOOL] base = GameSettings var = economy.smooth_economy def = true str = STR_CONFIG_SETTING_SMOOTH_ECONOMY strhelp = STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT proc = InvalidateIndustryViewWindow cat = SC_BASIC [SDT_BOOL] base = GameSettings var = economy.allow_shares def = false str = STR_CONFIG_SETTING_ALLOW_SHARES strhelp = STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT proc = InvalidateCompanyWindow [SDT_VAR] base = GameSettings var = economy.feeder_payment_share type = SLE_UINT8 from = 134 def = 75 min = 0 max = 100 str = STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE strhelp = STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT strval = STR_CONFIG_SETTING_PERCENTAGE cat = SC_EXPERT [SDT_VAR] base = GameSettings var = economy.town_growth_rate type = SLE_UINT8 from = 54 guiflags = SGF_MULTISTRING def = 2 min = 0 max = 4 str = STR_CONFIG_SETTING_TOWN_GROWTH strhelp = STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT strval = STR_CONFIG_SETTING_TOWN_GROWTH_NONE [SDT_VAR] base = GameSettings var = economy.larger_towns type = SLE_UINT8 from = 54 guiflags = SGF_0ISDISABLED def = 4 min = 0 max = 255 interval = 1 str = STR_CONFIG_SETTING_LARGER_TOWNS strhelp = STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT strval = STR_CONFIG_SETTING_LARGER_TOWNS_VALUE [SDT_VAR] base = GameSettings var = economy.initial_city_size type = SLE_UINT8 from = 56 def = 2 min = 1 max = 10 interval = 1 str = STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER strhelp = STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT strval = STR_JUST_COMMA [SDT_BOOL] base = GameSettings var = economy.mod_road_rebuild from = 77 def = true cat = SC_EXPERT ; previously ai-new setting. [SDT_NULL] length = 1 to = 106 [SDT_OMANY] base = GameSettings var = script.settings_profile type = SLE_UINT8 from = 178 guiflags = SGF_MULTISTRING def = SP_EASY min = SP_EASY max = SP_HARD full = _settings_profiles str = STR_CONFIG_SETTING_AI_PROFILE strhelp = STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT strval = STR_CONFIG_SETTING_AI_PROFILE_EASY cat = SC_BASIC [SDT_BOOL] base = GameSettings var = ai.ai_in_multiplayer def = true str = STR_CONFIG_SETTING_AI_IN_MULTIPLAYER strhelp = STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT cat = SC_BASIC [SDT_BOOL] base = GameSettings var = ai.ai_disable_veh_train def = false str = STR_CONFIG_SETTING_AI_BUILDS_TRAINS strhelp = STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT [SDT_BOOL] base = GameSettings var = ai.ai_disable_veh_roadveh def = false str = STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES strhelp = STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT [SDT_BOOL] base = GameSettings var = ai.ai_disable_veh_aircraft def = false str = STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT strhelp = STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT [SDT_BOOL] base = GameSettings var = ai.ai_disable_veh_ship def = false str = STR_CONFIG_SETTING_AI_BUILDS_SHIPS strhelp = STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT [SDT_VAR] base = GameSettings var = script.script_max_opcode_till_suspend type = SLE_UINT32 from = 107 guiflags = SGF_NEWGAME_ONLY def = 10000 min = 5000 max = 250000 interval = 2500 str = STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES strhelp = STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT strval = STR_JUST_COMMA cat = SC_EXPERT ## [SDT_VAR] base = GameSettings var = vehicle.extend_vehicle_life type = SLE_UINT8 def = 0 min = 0 max = 100 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = economy.dist_local_authority type = SLE_UINT8 def = 20 min = 5 max = 60 cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.reverse_at_signals from = 159 def = false str = STR_CONFIG_SETTING_REVERSE_AT_SIGNALS strhelp = STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT [SDT_VAR] base = GameSettings var = pf.wait_oneway_signal type = SLE_UINT8 def = 15 min = 2 max = 255 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.wait_twoway_signal type = SLE_UINT8 def = 41 min = 2 max = 255 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = economy.town_noise_population[0] type = SLE_UINT16 from = 96 def = 800 min = 200 max = 65535 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = economy.town_noise_population[1] type = SLE_UINT16 from = 96 def = 2000 min = 400 max = 65535 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = economy.town_noise_population[2] type = SLE_UINT16 from = 96 def = 4000 min = 800 max = 65535 cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = economy.infrastructure_maintenance from = 166 def = false str = STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE strhelp = STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT proc = InvalidateCompanyInfrastructureWindow cat = SC_BASIC ## [SDT_VAR] base = GameSettings var = pf.wait_for_pbs_path type = SLE_UINT8 from = 100 def = 30 min = 2 max = 255 cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.reserve_paths from = 100 def = false cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.path_backoff_interval type = SLE_UINT8 from = 100 def = 20 min = 1 max = 255 cat = SC_EXPERT ## [SDT_VAR] base = GameSettings var = pf.opf.pf_maxlength type = SLE_UINT16 def = 4096 min = 64 max = 65535 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.opf.pf_maxdepth type = SLE_UINT8 def = 48 min = 4 max = 255 cat = SC_EXPERT ## [SDT_VAR] base = GameSettings var = pf.npf.npf_max_search_nodes type = SLE_UINT def = 10000 min = 500 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_firstred_penalty type = SLE_UINT def = 10 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_firstred_exit_penalty type = SLE_UINT def = 100 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_lastred_penalty type = SLE_UINT def = 10 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_station_penalty type = SLE_UINT def = 1 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_slope_penalty type = SLE_UINT def = 1 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_curve_penalty type = SLE_UINT def = 1 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_depot_reverse_penalty type = SLE_UINT def = 50 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_pbs_cross_penalty type = SLE_UINT from = 100 def = 3 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_rail_pbs_signal_back_penalty type = SLE_UINT from = 100 def = 15 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_buoy_penalty type = SLE_UINT def = 2 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_water_curve_penalty type = SLE_UINT def = 1 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_road_curve_penalty type = SLE_UINT def = 1 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_crossing_penalty type = SLE_UINT def = 3 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_road_drive_through_penalty type = SLE_UINT from = 47 def = 8 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_road_dt_occupied_penalty type = SLE_UINT from = 130 def = 8 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.npf_road_bay_occupied_penalty type = SLE_UINT from = 130 def = 15 * NPF_TILE_LENGTH min = 0 max = 100000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.npf.maximum_go_to_depot_penalty type = SLE_UINT from = 131 def = 20 * NPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT ## [SDT_BOOL] base = GameSettings var = pf.yapf.disable_node_optimization from = 28 def = false cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.max_search_nodes type = SLE_UINT from = 28 def = 10000 min = 500 max = 1000000 cat = SC_EXPERT [SDT_BOOL] base = GameSettings var = pf.yapf.rail_firstred_twoway_eol from = 28 def = false cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_firstred_penalty type = SLE_UINT from = 28 def = 10 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_firstred_exit_penalty type = SLE_UINT from = 28 def = 100 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_lastred_penalty type = SLE_UINT from = 28 def = 10 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_lastred_exit_penalty type = SLE_UINT from = 28 def = 100 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_station_penalty type = SLE_UINT from = 28 def = 10 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_slope_penalty type = SLE_UINT from = 28 def = 2 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_curve45_penalty type = SLE_UINT from = 28 def = 1 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_curve90_penalty type = SLE_UINT from = 28 def = 6 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_depot_reverse_penalty type = SLE_UINT from = 28 def = 50 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_crossing_penalty type = SLE_UINT from = 28 def = 3 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_look_ahead_max_signals type = SLE_UINT from = 28 def = 10 min = 1 max = 100 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_look_ahead_signal_p0 type = SLE_INT from = 28 def = 500 min = -1000000 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_look_ahead_signal_p1 type = SLE_INT from = 28 def = -100 min = -1000000 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_look_ahead_signal_p2 type = SLE_INT from = 28 def = 5 min = -1000000 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_pbs_cross_penalty type = SLE_UINT from = 100 def = 3 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_pbs_station_penalty type = SLE_UINT from = 100 def = 8 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_pbs_signal_back_penalty type = SLE_UINT from = 100 def = 15 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_doubleslip_penalty type = SLE_UINT from = 100 def = 1 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_longer_platform_penalty type = SLE_UINT from = 33 def = 8 * YAPF_TILE_LENGTH min = 0 max = 20000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_longer_platform_per_tile_penalty type = SLE_UINT from = 33 def = 0 * YAPF_TILE_LENGTH min = 0 max = 20000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_shorter_platform_penalty type = SLE_UINT from = 33 def = 40 * YAPF_TILE_LENGTH min = 0 max = 20000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.rail_shorter_platform_per_tile_penalty type = SLE_UINT from = 33 def = 0 * YAPF_TILE_LENGTH min = 0 max = 20000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.road_slope_penalty type = SLE_UINT from = 33 def = 2 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.road_curve_penalty type = SLE_UINT from = 33 def = 1 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.road_crossing_penalty type = SLE_UINT from = 33 def = 3 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.road_stop_penalty type = SLE_UINT from = 47 def = 8 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.road_stop_occupied_penalty type = SLE_UINT from = 130 def = 8 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.road_stop_bay_occupied_penalty type = SLE_UINT from = 130 def = 15 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = pf.yapf.maximum_go_to_depot_penalty type = SLE_UINT from = 131 def = 20 * YAPF_TILE_LENGTH min = 0 max = 1000000 cat = SC_EXPERT ## [SDT_VAR] base = GameSettings var = game_creation.land_generator type = SLE_UINT8 from = 30 guiflags = SGF_MULTISTRING | SGF_NEWGAME_ONLY def = 1 min = 0 max = 1 str = STR_CONFIG_SETTING_LAND_GENERATOR strhelp = STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT strval = STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL [SDT_VAR] base = GameSettings var = game_creation.oil_refinery_limit type = SLE_UINT8 from = 30 def = 32 min = 12 max = 48 str = STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE strval = STR_CONFIG_SETTING_TILE_LENGTH strhelp = STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT [SDT_VAR] base = GameSettings var = game_creation.tgen_smoothness type = SLE_UINT8 from = 30 guiflags = SGF_MULTISTRING | SGF_NEWGAME_ONLY def = 1 min = 0 max = 3 str = STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN strhelp = STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT strval = STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH cat = SC_BASIC [SDT_VAR] base = GameSettings var = game_creation.variety type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING | SGF_NEWGAME_ONLY def = 0 min = 0 max = 5 str = STR_CONFIG_SETTING_VARIETY strhelp = STR_CONFIG_SETTING_VARIETY_HELPTEXT strval = STR_VARIETY_NONE [SDT_VAR] base = GameSettings var = game_creation.generation_seed type = SLE_UINT32 from = 30 def = GENERATE_NEW_SEED min = 0 max = UINT32_MAX cat = SC_EXPERT [SDT_VAR] base = GameSettings var = game_creation.tree_placer type = SLE_UINT8 from = 30 guiflags = SGF_MULTISTRING | SGF_NEWGAME_ONLY | SGF_SCENEDIT_TOO def = 2 min = 0 max = 2 str = STR_CONFIG_SETTING_TREE_PLACER strhelp = STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT strval = STR_CONFIG_SETTING_TREE_PLACER_NONE [SDT_VAR] base = GameSettings var = game_creation.heightmap_rotation type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 min = 0 max = 1 str = STR_CONFIG_SETTING_HEIGHTMAP_ROTATION strval = STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE cat = SC_BASIC [SDT_VAR] base = GameSettings var = game_creation.se_flat_world_height type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 1 min = 0 max = 15 str = STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT strval = STR_JUST_COMMA cat = SC_BASIC ## [SDT_VAR] base = GameSettings var = game_creation.map_x type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 8 min = MIN_MAP_SIZE_BITS max = MAX_MAP_SIZE_BITS cat = SC_BASIC [SDT_VAR] base = GameSettings var = game_creation.map_y type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 8 min = MIN_MAP_SIZE_BITS max = MAX_MAP_SIZE_BITS cat = SC_BASIC [SDT_BOOL] base = GameSettings var = construction.freeform_edges from = 111 def = true proc = CheckFreeformEdges cat = SC_EXPERT [SDT_VAR] base = GameSettings var = game_creation.water_borders type = SLE_UINT8 from = 111 def = 15 min = 0 max = 16 [SDT_VAR] base = GameSettings var = game_creation.custom_town_number type = SLE_UINT16 from = 115 def = 1 min = 1 max = 5000 cat = SC_BASIC [SDT_VAR] base = GameSettings var = construction.extra_tree_placement type = SLE_UINT8 from = 132 guiflags = SGF_MULTISTRING def = 2 min = 0 max = 2 str = STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT strhelp = STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT strval = STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE cat = SC_BASIC [SDT_VAR] base = GameSettings var = game_creation.custom_sea_level type = SLE_UINT8 from = 149 def = 1 min = 2 max = 90 cat = SC_BASIC [SDT_VAR] base = GameSettings var = game_creation.min_river_length type = SLE_UINT8 from = 163 def = 16 min = 2 max = 255 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = game_creation.river_route_random type = SLE_UINT8 from = 163 def = 5 min = 1 max = 255 cat = SC_EXPERT [SDT_VAR] base = GameSettings var = game_creation.amount_of_rivers type = SLE_UINT8 from = 163 guiflags = SGF_MULTISTRING | SGF_NEWGAME_ONLY def = 2 min = 0 max = 3 str = STR_CONFIG_SETTING_RIVER_AMOUNT strhelp = STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT strval = STR_RIVERS_NONE ; locale [SDT_OMANY] base = GameSettings var = locale.currency type = SLE_UINT8 from = 97 flags = SLF_NO_NETWORK_SYNC def = 0 max = CURRENCY_END - 1 full = _locale_currencies proc = RedrawScreen cat = SC_BASIC [SDTG_OMANY] name = ""units"" var = _old_units type = SLE_UINT8 from = 97 to = 183 flags = SLF_NOT_IN_CONFIG def = 1 max = 2 full = _locale_units proc = RedrawScreen cat = SC_BASIC [SDT_OMANY] base = GameSettings var = locale.units_velocity type = SLE_UINT8 from = 184 flags = SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _locale_units proc = RedrawScreen cat = SC_BASIC str = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY strhelp = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT strval = STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL [SDT_OMANY] base = GameSettings var = locale.units_power type = SLE_UINT8 from = 184 flags = SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _locale_units proc = RedrawScreen cat = SC_BASIC str = STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER strhelp = STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT strval = STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL [SDT_OMANY] base = GameSettings var = locale.units_weight type = SLE_UINT8 from = 184 flags = SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _locale_units proc = RedrawScreen cat = SC_BASIC str = STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT strhelp = STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT strval = STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL [SDT_OMANY] base = GameSettings var = locale.units_volume type = SLE_UINT8 from = 184 flags = SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _locale_units proc = RedrawScreen cat = SC_BASIC str = STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME strhelp = STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT strval = STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL [SDT_OMANY] base = GameSettings var = locale.units_force type = SLE_UINT8 from = 184 flags = SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _locale_units proc = RedrawScreen cat = SC_BASIC str = STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE strhelp = STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT strval = STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL [SDT_OMANY] base = GameSettings var = locale.units_height type = SLE_UINT8 from = 184 flags = SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _locale_units proc = RedrawScreen cat = SC_BASIC str = STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT strhelp = STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT strval = STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL [SDT_STR] base = GameSettings var = locale.digit_group_separator type = SLE_STRQ from = 118 flags = SLF_NO_NETWORK_SYNC def = NULL proc = RedrawScreen cat = SC_BASIC [SDT_STR] base = GameSettings var = locale.digit_group_separator_currency type = SLE_STRQ from = 118 flags = SLF_NO_NETWORK_SYNC def = NULL proc = RedrawScreen cat = SC_BASIC [SDT_STR] base = GameSettings var = locale.digit_decimal_separator type = SLE_STRQ from = 126 flags = SLF_NO_NETWORK_SYNC def = NULL proc = RedrawScreen cat = SC_BASIC ;*************************************************************************** ; Unsaved setting variables. [SDTC_OMANY] var = gui.autosave type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 4 full = _autosave_interval str = STR_CONFIG_SETTING_AUTOSAVE strhelp = STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT strval = STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF cat = SC_BASIC [SDTC_BOOL] var = gui.threaded_saves flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true cat = SC_EXPERT [SDTC_OMANY] var = gui.date_format_in_default_names type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 max = 2 full = _savegame_date str = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES strhelp = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT strval = STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG [SDTC_BOOL] var = gui.show_finances flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SHOWFINANCES strhelp = STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT cat = SC_BASIC [SDTC_VAR] var = gui.auto_scrolling type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 min = 0 max = 3 str = STR_CONFIG_SETTING_AUTOSCROLL strhelp = STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT strval = STR_CONFIG_SETTING_AUTOSCROLL_DISABLED cat = SC_BASIC [SDTC_BOOL] var = gui.reverse_scroll flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_REVERSE_SCROLLING strhelp = STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT cat = SC_BASIC [SDTC_BOOL] var = gui.smooth_scroll flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_SMOOTH_SCROLLING strhelp = STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT [SDTC_BOOL] var = gui.left_mouse_btn_scrolling flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING strhelp = STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT cat = SC_BASIC [SDTC_BOOL] var = gui.measure_tooltip flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_MEASURE_TOOLTIP strhelp = STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT cat = SC_BASIC [SDTC_VAR] var = gui.errmsg_duration type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 5 min = 0 max = 20 str = STR_CONFIG_SETTING_ERRMSG_DURATION strhelp = STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT strval = STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE [SDTC_VAR] var = gui.hover_delay_ms type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_0ISDISABLED def = 250 min = 50 max = 6000 interval = 50 str = STR_CONFIG_SETTING_HOVER_DELAY strhelp = STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT strval = STR_CONFIG_SETTING_HOVER_DELAY_VALUE [SDTC_OMANY] var = gui.osk_activation type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC str = STR_CONFIG_SETTING_OSK_ACTIVATION strhelp = STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT strval = STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED guiflags = SGF_MULTISTRING full = _osk_activation def = 1 min = 0 max = 3 cat = SC_BASIC [SDTC_VAR] var = gui.toolbar_pos type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 min = 0 max = 2 str = STR_CONFIG_SETTING_TOOLBAR_POS strhelp = STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT strval = STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT proc = v_PositionMainToolbar cat = SC_BASIC [SDTC_VAR] var = gui.statusbar_pos type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 min = 0 max = 2 str = STR_CONFIG_SETTING_STATUSBAR_POS strhelp = STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT strval = STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT proc = v_PositionStatusbar cat = SC_BASIC [SDTC_VAR] var = gui.window_snap_radius type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_0ISDISABLED def = 10 min = 1 max = 32 str = STR_CONFIG_SETTING_SNAP_RADIUS strhelp = STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT strval = STR_CONFIG_SETTING_SNAP_RADIUS_VALUE cat = SC_EXPERT [SDTC_VAR] var = gui.window_soft_limit type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_0ISDISABLED def = 20 min = 5 max = 255 interval = 1 str = STR_CONFIG_SETTING_SOFT_LIMIT strhelp = STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT strval = STR_CONFIG_SETTING_SOFT_LIMIT_VALUE cat = SC_EXPERT [SDTC_VAR] var = gui.zoom_min type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = ZOOM_LVL_MIN min = ZOOM_LVL_MIN max = ZOOM_LVL_OUT_4X str = STR_CONFIG_SETTING_ZOOM_MIN strhelp = STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT strval = STR_CONFIG_SETTING_ZOOM_LVL_MIN proc = ZoomMinMaxChanged [SDTC_VAR] var = gui.zoom_max type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = ZOOM_LVL_MAX min = ZOOM_LVL_OUT_8X max = ZOOM_LVL_MAX str = STR_CONFIG_SETTING_ZOOM_MAX strhelp = STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT strval = STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X proc = ZoomMinMaxChanged [SDTC_BOOL] var = gui.population_in_label flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_POPULATION_IN_LABEL strhelp = STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT proc = PopulationInLabelActive [SDTC_BOOL] var = gui.link_terraform_toolbar flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR strhelp = STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT [SDTC_VAR] var = gui.smallmap_land_colour type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 min = 0 max = 2 str = STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR strhelp = STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT strval = STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN proc = RedrawSmallmap [SDTC_VAR] var = gui.liveries type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 min = 0 max = 2 str = STR_CONFIG_SETTING_LIVERIES strhelp = STR_CONFIG_SETTING_LIVERIES_HELPTEXT strval = STR_CONFIG_SETTING_LIVERIES_NONE proc = InvalidateCompanyLiveryWindow [SDTC_BOOL] var = gui.prefer_teamchat flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_PREFER_TEAMCHAT strhelp = STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT cat = SC_BASIC [SDTC_VAR] var = gui.scrollwheel_scrolling type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 min = 0 max = 2 str = STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING strhelp = STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT strval = STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM cat = SC_BASIC [SDTC_VAR] var = gui.scrollwheel_multiplier type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 5 min = 1 max = 15 interval = 1 str = STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER strhelp = STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT strval = STR_JUST_COMMA cat = SC_BASIC [SDTC_BOOL] var = gui.pause_on_newgame flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME strhelp = STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT cat = SC_BASIC [SDTC_VAR] var = gui.advanced_vehicle_list type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 min = 0 max = 2 str = STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS strhelp = STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT strval = STR_CONFIG_SETTING_COMPANIES_OFF [SDTC_BOOL] var = gui.timetable_in_ticks flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_TIMETABLE_IN_TICKS strhelp = STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT proc = InvalidateVehTimetableWindow cat = SC_EXPERT [SDTC_BOOL] var = gui.timetable_arrival_departure flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE strhelp = STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT proc = InvalidateVehTimetableWindow [SDTC_BOOL] var = gui.quick_goto flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_QUICKGOTO strhelp = STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT cat = SC_BASIC [SDTC_VAR] var = gui.loading_indicators type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 min = 0 max = 2 str = STR_CONFIG_SETTING_LOADING_INDICATORS strhelp = STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT strval = STR_CONFIG_SETTING_COMPANIES_OFF proc = RedrawScreen cat = SC_BASIC [SDTC_VAR] var = gui.default_rail_type type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 min = 0 max = 2 str = STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE strhelp = STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT strval = STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST cat = SC_BASIC [SDTC_BOOL] var = gui.enable_signal_gui flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI strhelp = STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT proc = CloseSignalGUI cat = SC_EXPERT [SDTC_VAR] var = gui.coloured_news_year type = SLE_INT32 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 2000 min = MIN_YEAR max = MAX_YEAR interval = 1 str = STR_CONFIG_SETTING_COLOURED_NEWS_YEAR strhelp = STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT strval = STR_JUST_INT cat = SC_EXPERT [SDTC_VAR] var = gui.drag_signals_density type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 4 min = 1 max = 20 str = STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY strhelp = STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT strval = STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE proc = DragSignalsDensityChanged cat = SC_BASIC [SDTC_BOOL] var = gui.drag_signals_fixed_distance flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE strhelp = STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT cat = SC_EXPERT [SDTC_VAR] var = gui.semaphore_build_before type = SLE_INT32 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 1950 min = MIN_YEAR max = MAX_YEAR interval = 1 str = STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE strhelp = STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT strval = STR_JUST_INT proc = ResetSignalVariant [SDTC_BOOL] var = gui.vehicle_income_warn flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_WARN_INCOME_LESS strhelp = STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT cat = SC_BASIC [SDTC_VAR] var = gui.order_review_system type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 min = 0 max = 2 str = STR_CONFIG_SETTING_ORDER_REVIEW strhelp = STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT strval = STR_CONFIG_SETTING_ORDER_REVIEW_OFF cat = SC_BASIC [SDTC_BOOL] var = gui.lost_vehicle_warn flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_WARN_LOST_VEHICLE strhelp = STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT [SDTC_BOOL] var = gui.disable_unsuitable_building flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING strhelp = STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT proc = RedrawScreen cat = SC_EXPERT [SDTC_BOOL] var = gui.new_nonstop flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT strhelp = STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT cat = SC_BASIC [SDTC_VAR] var = gui.stop_location type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_STOP_LOCATION strhelp = STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT strval = STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END cat = SC_BASIC [SDTC_BOOL] var = gui.keep_all_autosave flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false [SDTC_BOOL] var = gui.autosave_on_exit flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false cat = SC_BASIC [SDTC_VAR] var = gui.max_num_autosaves type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 16 min = 0 max = 255 [SDTC_BOOL] var = gui.auto_euro flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true [SDTC_VAR] var = gui.news_message_timeout type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 2 min = 1 max = 255 [SDTC_BOOL] var = gui.show_track_reservation flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION strhelp = STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT proc = RedrawScreen cat = SC_BASIC [SDTC_VAR] var = gui.default_signal_type type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE strhelp = STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT strval = STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL cat = SC_BASIC [SDTC_VAR] var = gui.cycle_signal_types type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 min = 0 max = 2 interval = 1 str = STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES strhelp = STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT strval = STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL [SDTC_VAR] var = gui.station_numtracks type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 1 min = 1 max = 7 [SDTC_VAR] var = gui.station_platlength type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 5 min = 1 max = 7 cat = SC_BASIC [SDTC_BOOL] var = gui.station_dragdrop flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true cat = SC_BASIC [SDTC_BOOL] var = gui.station_show_coverage flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false cat = SC_BASIC [SDTC_BOOL] var = gui.persistent_buildingtools flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS strhelp = STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT cat = SC_BASIC [SDTC_BOOL] var = gui.expenses_layout flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false str = STR_CONFIG_SETTING_EXPENSES_LAYOUT strhelp = STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT proc = RedrawScreen [SDTC_VAR] var = gui.station_gui_group_order type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 0 min = 0 max = 5 interval = 1 [SDTC_VAR] var = gui.station_gui_sort_by type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 0 min = 0 max = 3 interval = 1 [SDTC_VAR] var = gui.station_gui_sort_order type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 0 min = 0 max = 1 interval = 1 [SDTC_VAR] var = gui.missing_strings_threshold type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 25 min = 1 max = UINT8_MAX cat = SC_EXPERT [SDTC_VAR] var = gui.graph_line_thickness type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 3 min = 1 max = 5 str = STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS strhelp = STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT strval = STR_JUST_COMMA proc = RedrawScreen ; For the dedicated build we'll enable dates in logs by default. [SDTC_BOOL] ifdef = DEDICATED var = gui.show_date_in_logs flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true [SDTC_BOOL] ifndef = DEDICATED var = gui.show_date_in_logs flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false [SDTC_VAR] var = gui.settings_restriction_mode type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 0 min = 0 max = 2 [SDTC_VAR] var = gui.developer type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 1 min = 0 max = 2 cat = SC_EXPERT [SDTC_BOOL] var = gui.newgrf_developer_tools flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false proc = InvalidateNewGRFChangeWindows cat = SC_EXPERT [SDTC_BOOL] var = gui.ai_developer_tools flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false proc = InvalidateAISettingsWindow cat = SC_EXPERT [SDTC_BOOL] var = gui.scenario_developer flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false proc = InvalidateNewGRFChangeWindows [SDTC_BOOL] var = gui.newgrf_show_old_versions flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false cat = SC_EXPERT [SDTC_VAR] var = gui.newgrf_default_palette type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 min = 0 max = 1 proc = UpdateNewGRFConfigPalette cat = SC_EXPERT [SDTC_VAR] var = gui.console_backlog_timeout type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 100 min = 10 max = 65500 [SDTC_VAR] var = gui.console_backlog_length type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 100 min = 10 max = 65500 [SDTC_BOOL] var = sound.news_ticker flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_TICKER strhelp = STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT [SDTC_BOOL] var = sound.news_full flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_NEWS strhelp = STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT [SDTC_BOOL] var = sound.new_year flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_NEW_YEAR strhelp = STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT [SDTC_BOOL] var = sound.confirm flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_CONFIRM strhelp = STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT [SDTC_BOOL] var = sound.click_beep flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_CLICK strhelp = STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT [SDTC_BOOL] var = sound.disaster flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_DISASTER strhelp = STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT [SDTC_BOOL] var = sound.vehicle flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_VEHICLE strhelp = STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT [SDTC_BOOL] var = sound.ambient flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true str = STR_CONFIG_SETTING_SOUND_AMBIENT strhelp = STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT [SDTC_VAR] var = music.playlist type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 0 min = 0 max = 5 interval = 1 cat = SC_BASIC [SDTC_VAR] var = music.music_vol type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 127 min = 0 max = 127 interval = 1 cat = SC_BASIC [SDTC_VAR] var = music.effect_vol type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 127 min = 0 max = 127 interval = 1 cat = SC_BASIC [SDTC_LIST] var = music.custom_1 type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = NULL cat = SC_BASIC [SDTC_LIST] var = music.custom_2 type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = NULL cat = SC_BASIC [SDTC_BOOL] var = music.playing flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = true cat = SC_BASIC [SDTC_BOOL] var = music.shuffle flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false cat = SC_BASIC [SDTC_OMANY] var = news_display.arrival_player type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN strhelp = STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.arrival_other type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER strhelp = STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.accident type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS strhelp = STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.company_info type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION strhelp = STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.open type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN strhelp = STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.close type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE strhelp = STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.economy type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES strhelp = STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.production_player type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY strhelp = STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.production_other type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER strhelp = STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.production_nobody type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED strhelp = STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.advice type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_ADVICE strhelp = STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.new_vehicles type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_NEW_VEHICLES strhelp = STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.acceptance type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE strhelp = STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.subsidies type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 1 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_SUBSIDIES strhelp = STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_OMANY] var = news_display.general type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 2 max = 2 full = _news_display str = STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION strhelp = STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT strval = STR_CONFIG_SETTING_NEWS_MESSAGES_OFF [SDTC_VAR] ifdef = ENABLE_NETWORK var = gui.network_chat_box_width_pct type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 40 min = 10 max = 100 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = gui.network_chat_box_height type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 25 min = 5 max = 255 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = gui.network_chat_timeout type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 20 min = 1 max = 65535 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.sync_freq type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NOT_IN_CONFIG | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 100 min = 0 max = 100 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.frame_freq type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NOT_IN_CONFIG | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 0 min = 0 max = 100 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.commands_per_frame type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 2 min = 1 max = 65535 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_commands_in_queue type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 16 min = 1 max = 65535 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.bytes_per_frame type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 8 min = 1 max = 65535 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.bytes_per_frame_burst type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 256 min = 1 max = 65535 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_init_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 100 min = 0 max = 32000 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_join_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 500 min = 0 max = 32000 [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_download_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 1000 min = 0 max = 32000 [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_password_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 2000 min = 0 max = 32000 [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_lag_time type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 500 min = 0 max = 32000 [SDTC_BOOL] ifdef = ENABLE_NETWORK var = network.pause_on_join flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = true [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.server_port type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = NETWORK_DEFAULT_PORT min = 0 max = 65535 cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.server_admin_port type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = NETWORK_ADMIN_PORT min = 0 max = 65535 cat = SC_EXPERT [SDTC_BOOL] ifdef = ENABLE_NETWORK var = network.server_admin_chat flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = true cat = SC_EXPERT [SDTC_BOOL] ifdef = ENABLE_NETWORK var = network.server_advertise flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = false [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.lan_internet type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 0 min = 0 max = 1 [SDTC_STR] ifdef = ENABLE_NETWORK var = network.client_name type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = NULL proc = UpdateClientName cat = SC_BASIC [SDTC_STR] ifdef = ENABLE_NETWORK var = network.server_password type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = NULL proc = UpdateServerPassword cat = SC_BASIC [SDTC_STR] ifdef = ENABLE_NETWORK var = network.rcon_password type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = NULL proc = UpdateRconPassword cat = SC_BASIC [SDTC_STR] ifdef = ENABLE_NETWORK var = network.admin_password type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = NULL cat = SC_BASIC [SDTC_STR] ifdef = ENABLE_NETWORK var = network.default_company_pass type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = NULL [SDTC_STR] ifdef = ENABLE_NETWORK var = network.server_name type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = NULL cat = SC_BASIC [SDTC_STR] ifdef = ENABLE_NETWORK var = network.connect_to_ip type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = NULL [SDTC_STR] ifdef = ENABLE_NETWORK var = network.network_id type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = NULL [SDTC_BOOL] ifdef = ENABLE_NETWORK var = network.autoclean_companies flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = false [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.autoclean_unprotected type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_0ISDISABLED | SGF_NETWORK_ONLY def = 12 min = 0 max = 240 [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.autoclean_protected type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_0ISDISABLED | SGF_NETWORK_ONLY def = 36 min = 0 max = 240 [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.autoclean_novehicles type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_0ISDISABLED | SGF_NETWORK_ONLY def = 0 min = 0 max = 240 [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_companies type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 15 min = 1 max = MAX_COMPANIES proc = UpdateClientConfigValues cat = SC_BASIC [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_clients type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 25 min = 2 max = MAX_CLIENTS cat = SC_BASIC [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.max_spectators type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 15 min = 0 max = MAX_CLIENTS proc = UpdateClientConfigValues cat = SC_BASIC [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.restart_game_year type = SLE_INT32 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_0ISDISABLED | SGF_NETWORK_ONLY def = 0 min = MIN_YEAR max = MAX_YEAR interval = 1 [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.min_active_clients type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 0 min = 0 max = MAX_CLIENTS [SDTC_OMANY] ifdef = ENABLE_NETWORK var = network.server_lang type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = 0 max = 35 full = _server_langs cat = SC_BASIC [SDTC_BOOL] ifdef = ENABLE_NETWORK var = network.reload_cfg flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_NETWORK_ONLY def = false cat = SC_EXPERT [SDTC_STR] ifdef = ENABLE_NETWORK var = network.last_host type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = """" cat = SC_EXPERT [SDTC_VAR] ifdef = ENABLE_NETWORK var = network.last_port type = SLE_UINT16 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = 0 min = 0 max = UINT16_MAX cat = SC_EXPERT [SDTC_BOOL] ifdef = ENABLE_NETWORK var = network.no_http_content_downloads flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = false cat = SC_EXPERT ; Since the network code (CmdChangeSetting and friends) use the index in this array to decide ; which setting the server is talking about all conditional compilation of this array must be at the ; end. This isn't really the best solution, the settings the server can tell the client about should ; either use a seperate array or some other form of identifier. ; ; We might need to emulate a right mouse button on mac [SDTC_VAR] ifdef = __APPLE__ var = gui.right_mouse_btn_emulation type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = SGF_MULTISTRING def = 0 min = 0 max = 2 str = STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU strhelp = STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT strval = STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND cat = SC_BASIC [SDT_END] openttd-1.5.3/src/table/sprites.h0000644000000000000000000025473612627373436015451 0ustar rootroot/* $Id: sprites.h 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 sprites.h * This file contains all sprite-related enums and defines. These consist mainly of * the sprite numbers and a bunch of masks and macros to handle sprites and to get * rid of all the magic numbers in the code. * * @note * ALL SPRITE NUMBERS BELOW 5126 are in the main files * * All elements which consist of two elements should * have the same name and then suffixes * _GROUND and _BUILD for building-type sprites * _REAR and _FRONT for transport-type sprites (tiles where vehicles are on) * These sprites are split because of the Z order of the elements * (like some parts of a bridge are behind the vehicle, while others are before) * * * All sprites which are described here are referenced only one to a handful of times * throughout the code. When introducing new sprite enums, use meaningful names. * Don't be lazy and typing, and only use abbreviations when their meaning is clear or * the length of the enum would get out of hand. In that case EXPLAIN THE ABBREVATION * IN THIS FILE, and perhaps add some comments in the code where it is used. * Now, don't whine about this being too much typing work if the enums are like * 30 characters in length. If your editor doen't help you simplifying your work, * get a proper editor. If your Operating Systems don't have any decent editors, * get a proper Operating System. * * @todo Split the "Sprites" enum into smaller chunks and document them */ #ifndef SPRITES_H #define SPRITES_H #include "../gfx_type.h" static const SpriteID SPR_SELECT_TILE = 752; static const SpriteID SPR_DOT = 774; // corner marker for lower/raise land static const SpriteID SPR_DOT_SMALL = 4078; static const SpriteID SPR_WHITE_POINT = 4079; /* ASCII */ static const SpriteID SPR_ASCII_SPACE = 2; static const SpriteID SPR_ASCII_SPACE_SMALL = 226; static const SpriteID SPR_ASCII_SPACE_BIG = 450; static const SpriteID SPR_LARGE_SMALL_WINDOW = 682; /** Extra graphic spritenumbers */ static const SpriteID SPR_OPENTTD_BASE = 4896; static const uint16 OPENTTD_SPRITE_COUNT = 175; /* Halftile-selection sprites */ static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE; static const SpriteID SPR_HALFTILE_SELECTION_DOWN = SPR_OPENTTD_BASE + 4; static const SpriteID SPR_HALFTILE_SELECTION_UP = SPR_OPENTTD_BASE + 8; static const SpriteID SPR_SQUARE = SPR_OPENTTD_BASE + 38; // coloured square (used for newgrf compatibility) static const SpriteID SPR_BLOT = SPR_OPENTTD_BASE + 39; // coloured circle (used for server compatibility and installed content) static const SpriteID SPR_LOCK = SPR_OPENTTD_BASE + 40; // lock icon (for password protected servers) static const SpriteID SPR_BOX_EMPTY = SPR_OPENTTD_BASE + 41; static const SpriteID SPR_BOX_CHECKED = SPR_OPENTTD_BASE + 42; static const SpriteID SPR_WARNING_SIGN = SPR_OPENTTD_BASE + 43; // warning sign (shown if there are any newgrf errors) static const SpriteID SPR_WINDOW_RESIZE_RIGHT= SPR_OPENTTD_BASE + 44; // resize icon to the right static const SpriteID SPR_WINDOW_RESIZE_LEFT = SPR_OPENTTD_BASE + 149; // resize icon to the left static const SpriteID SPR_WINDOW_SHADE = SPR_OPENTTD_BASE + 151; // shade the window icon static const SpriteID SPR_WINDOW_UNSHADE = SPR_OPENTTD_BASE + 152; // unshade the window icon static const SpriteID SPR_WINDOW_DEBUG = SPR_OPENTTD_BASE + 153; // NewGRF debug window icon static const SpriteID SPR_IMG_PLAY_MUSIC_RTL = SPR_OPENTTD_BASE + 150; // play music button, but then for RTL users /* Arrow icons pointing in all 4 directions */ static const SpriteID SPR_ARROW_DOWN = SPR_OPENTTD_BASE + 45; static const SpriteID SPR_ARROW_UP = SPR_OPENTTD_BASE + 46; static const SpriteID SPR_ARROW_LEFT = SPR_OPENTTD_BASE + 47; static const SpriteID SPR_ARROW_RIGHT = SPR_OPENTTD_BASE + 48; static const SpriteID SPR_HOUSE_ICON = SPR_OPENTTD_BASE + 49; static const SpriteID SPR_SHARED_ORDERS_ICON = SPR_OPENTTD_BASE + 50; static const SpriteID SPR_PIN_UP = SPR_OPENTTD_BASE + 51; // pin icon static const SpriteID SPR_PIN_DOWN = SPR_OPENTTD_BASE + 52; static const SpriteID SPR_CLOSEBOX = 143; static const SpriteID SPR_CIRCLE_FOLDED = SPR_OPENTTD_BASE + 147; // (+) icon static const SpriteID SPR_CIRCLE_UNFOLDED = SPR_OPENTTD_BASE + 148; // (-) icon /* on screen keyboard icons */ static const SpriteID SPR_OSK_LEFT = SPR_OPENTTD_BASE + 138; static const SpriteID SPR_OSK_RIGHT = SPR_OPENTTD_BASE + 139; static const SpriteID SPR_OSK_CAPS = SPR_OPENTTD_BASE + 140; static const SpriteID SPR_OSK_SHIFT = SPR_OPENTTD_BASE + 141; static const SpriteID SPR_OSK_BACKSPACE = SPR_OPENTTD_BASE + 142; static const SpriteID SPR_OSK_SPECIAL = SPR_OPENTTD_BASE + 143; /** Clone vehicles stuff */ static const SpriteID SPR_CLONE_TRAIN = SPR_OPENTTD_BASE + 106; static const SpriteID SPR_CLONE_ROADVEH = SPR_OPENTTD_BASE + 107; static const SpriteID SPR_CLONE_SHIP = SPR_OPENTTD_BASE + 108; static const SpriteID SPR_CLONE_AIRCRAFT = SPR_OPENTTD_BASE + 109; static const SpriteID SPR_SELL_TRAIN = SPR_OPENTTD_BASE + 93; static const SpriteID SPR_SELL_ROADVEH = SPR_OPENTTD_BASE + 94; static const SpriteID SPR_SELL_SHIP = SPR_OPENTTD_BASE + 95; static const SpriteID SPR_SELL_AIRCRAFT = SPR_OPENTTD_BASE + 96; static const SpriteID SPR_SELL_ALL_TRAIN = SPR_OPENTTD_BASE + 97; static const SpriteID SPR_SELL_ALL_ROADVEH = SPR_OPENTTD_BASE + 98; static const SpriteID SPR_SELL_ALL_SHIP = SPR_OPENTTD_BASE + 99; static const SpriteID SPR_SELL_ALL_AIRCRAFT = SPR_OPENTTD_BASE + 100; static const SpriteID SPR_REPLACE_TRAIN = SPR_OPENTTD_BASE + 101; static const SpriteID SPR_REPLACE_ROADVEH = SPR_OPENTTD_BASE + 102; static const SpriteID SPR_REPLACE_SHIP = SPR_OPENTTD_BASE + 103; static const SpriteID SPR_REPLACE_AIRCRAFT = SPR_OPENTTD_BASE + 104; static const SpriteID SPR_SELL_CHAIN_TRAIN = SPR_OPENTTD_BASE + 105; static const SpriteID SPR_PROFIT_NA = SPR_OPENTTD_BASE + 154; static const SpriteID SPR_PROFIT_NEGATIVE = SPR_OPENTTD_BASE + 155; static const SpriteID SPR_PROFIT_SOME = SPR_OPENTTD_BASE + 156; static const SpriteID SPR_PROFIT_LOT = SPR_OPENTTD_BASE + 157; static const SpriteID SPR_UNREAD_NEWS = SPR_OPENTTD_BASE + 158; static const SpriteID SPR_EXCLUSIVE_TRANSPORT = SPR_OPENTTD_BASE + 159; static const SpriteID SPR_GROUP_REPLACE_PROTECT = SPR_OPENTTD_BASE + 160; static const SpriteID SPR_GROUP_REPLACE_ACTIVE = SPR_OPENTTD_BASE + 161; static const SpriteID SPR_GROUP_CREATE_TRAIN = SPR_OPENTTD_BASE + 114; static const SpriteID SPR_GROUP_CREATE_ROADVEH = SPR_OPENTTD_BASE + 115; static const SpriteID SPR_GROUP_CREATE_SHIP = SPR_OPENTTD_BASE + 116; static const SpriteID SPR_GROUP_CREATE_AIRCRAFT = SPR_OPENTTD_BASE + 117; static const SpriteID SPR_GROUP_DELETE_TRAIN = SPR_OPENTTD_BASE + 118; static const SpriteID SPR_GROUP_DELETE_ROADVEH = SPR_OPENTTD_BASE + 119; static const SpriteID SPR_GROUP_DELETE_SHIP = SPR_OPENTTD_BASE + 120; static const SpriteID SPR_GROUP_DELETE_AIRCRAFT = SPR_OPENTTD_BASE + 121; static const SpriteID SPR_GROUP_RENAME_TRAIN = SPR_OPENTTD_BASE + 122; static const SpriteID SPR_GROUP_RENAME_ROADVEH = SPR_OPENTTD_BASE + 123; static const SpriteID SPR_GROUP_RENAME_SHIP = SPR_OPENTTD_BASE + 124; static const SpriteID SPR_GROUP_RENAME_AIRCRAFT = SPR_OPENTTD_BASE + 125; static const SpriteID SPR_GROUP_REPLACE_ON_TRAIN = SPR_OPENTTD_BASE + 126; static const SpriteID SPR_GROUP_REPLACE_ON_ROADVEH = SPR_OPENTTD_BASE + 127; static const SpriteID SPR_GROUP_REPLACE_ON_SHIP = SPR_OPENTTD_BASE + 128; static const SpriteID SPR_GROUP_REPLACE_ON_AIRCRAFT = SPR_OPENTTD_BASE + 129; static const SpriteID SPR_GROUP_REPLACE_OFF_TRAIN = SPR_OPENTTD_BASE + 130; static const SpriteID SPR_GROUP_REPLACE_OFF_ROADVEH = SPR_OPENTTD_BASE + 131; static const SpriteID SPR_GROUP_REPLACE_OFF_SHIP = SPR_OPENTTD_BASE + 132; static const SpriteID SPR_GROUP_REPLACE_OFF_AIRCRAFT = SPR_OPENTTD_BASE + 133; static const SpriteID SPR_TOWN_RATING_NA = SPR_OPENTTD_BASE + 162; static const SpriteID SPR_TOWN_RATING_APALLING = SPR_OPENTTD_BASE + 163; static const SpriteID SPR_TOWN_RATING_MEDIOCRE = SPR_OPENTTD_BASE + 164; static const SpriteID SPR_TOWN_RATING_GOOD = SPR_OPENTTD_BASE + 165; static const SpriteID SPR_IMG_SWITCH_TOOLBAR = SPR_OPENTTD_BASE + 144; static const SpriteID SPR_IMG_DELETE_LEFT = SPR_OPENTTD_BASE + 166; static const SpriteID SPR_IMG_DELETE_RIGHT = SPR_OPENTTD_BASE + 167; static const SpriteID SPR_WINDOW_DEFSIZE = SPR_OPENTTD_BASE + 168; static const SpriteID SPR_IMG_CARGOFLOW = SPR_OPENTTD_BASE + 174; static const SpriteID SPR_SIGNALS_BASE = SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT; static const uint16 PRESIGNAL_SPRITE_COUNT = 48; static const uint16 PRESIGNAL_AND_SEMAPHORE_SPRITE_COUNT = 112; static const uint16 PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT = 240; static const SpriteID SPR_CANALS_BASE = SPR_SIGNALS_BASE + PRESIGNAL_SEMAPHORE_AND_PBS_SPRITE_COUNT; static const uint16 CANALS_SPRITE_COUNT = 65; /** Sprites for the Aqueduct. */ static const SpriteID SPR_AQUEDUCT_BASE = SPR_CANALS_BASE + CANALS_SPRITE_COUNT; static const SpriteID SPR_AQUEDUCT_RAMP_SW = SPR_AQUEDUCT_BASE + 0; static const SpriteID SPR_AQUEDUCT_RAMP_SE = SPR_AQUEDUCT_BASE + 1; static const SpriteID SPR_AQUEDUCT_RAMP_NE = SPR_AQUEDUCT_BASE + 2; static const SpriteID SPR_AQUEDUCT_RAMP_NW = SPR_AQUEDUCT_BASE + 3; static const SpriteID SPR_AQUEDUCT_MIDDLE_X = SPR_AQUEDUCT_BASE + 4; static const SpriteID SPR_AQUEDUCT_MIDDLE_Y = SPR_AQUEDUCT_BASE + 5; static const SpriteID SPR_AQUEDUCT_PILLAR_X = SPR_AQUEDUCT_BASE + 6; static const SpriteID SPR_AQUEDUCT_PILLAR_Y = SPR_AQUEDUCT_BASE + 7; static const uint16 AQUEDUCT_SPRITE_COUNT = 8; /** Sprites for 'highlighting' tracks on sloped land. */ static const SpriteID SPR_TRACKS_FOR_SLOPES_BASE = SPR_AQUEDUCT_BASE + AQUEDUCT_SPRITE_COUNT; static const SpriteID SPR_TRACKS_FOR_SLOPES_RAIL_BASE = SPR_TRACKS_FOR_SLOPES_BASE + 0; static const SpriteID SPR_TRACKS_FOR_SLOPES_MONO_BASE = SPR_TRACKS_FOR_SLOPES_BASE + 4; static const SpriteID SPR_TRACKS_FOR_SLOPES_MAGLEV_BASE = SPR_TRACKS_FOR_SLOPES_BASE + 8; static const uint16 TRACKS_FOR_SLOPES_SPRITE_COUNT = 12; static const SpriteID SPR_SLOPES_BASE = SPR_TRACKS_FOR_SLOPES_BASE + TRACKS_FOR_SLOPES_SPRITE_COUNT; static const SpriteID SPR_SLOPES_INCLINED_OFFSET = 15; static const SpriteID SPR_SLOPES_VIRTUAL_BASE = SPR_SLOPES_BASE - SPR_SLOPES_INCLINED_OFFSET; // The original foundations (see SPR_FOUNDATION_BASE below) are mapped before the additional foundations. static const SpriteID SPR_TRKFOUND_BLOCK_SIZE = 22; // The normal track foundation sprites are organized in blocks of 22. static const uint16 NORMAL_FOUNDATION_SPRITE_COUNT = 74; /** Halftile foundations */ static const SpriteID SPR_HALFTILE_FOUNDATION_BASE = SPR_SLOPES_BASE + NORMAL_FOUNDATION_SPRITE_COUNT; static const SpriteID SPR_HALFTILE_BLOCK_SIZE = 4; // The half tile foundation sprites are organized in blocks of 4. static const uint16 NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT = 90; static const SpriteID SPR_AUTORAIL_BASE = SPR_HALFTILE_FOUNDATION_BASE + NORMAL_AND_HALFTILE_FOUNDATION_SPRITE_COUNT; static const uint16 AUTORAIL_SPRITE_COUNT = 55; static const SpriteID SPR_ELRAIL_BASE = SPR_AUTORAIL_BASE + AUTORAIL_SPRITE_COUNT; static const uint16 ELRAIL_SPRITE_COUNT = 48; static const SpriteID SPR_2CCMAP_BASE = SPR_ELRAIL_BASE + ELRAIL_SPRITE_COUNT; static const uint16 TWOCCMAP_SPRITE_COUNT = 256; /** shore tiles - action 05-0D */ static const SpriteID SPR_SHORE_BASE = SPR_2CCMAP_BASE + TWOCCMAP_SPRITE_COUNT; static const SpriteID SPR_SHORE_SPRITE_COUNT = 18; static const SpriteID SPR_ORIGINALSHORE_START = 4062; static const SpriteID SPR_ORIGINALSHORE_END = 4069; static const SpriteID SPR_AIRPORTX_BASE = SPR_SHORE_BASE + SPR_SHORE_SPRITE_COUNT; // The sprites used for other airport angles static const SpriteID SPR_NEWAIRPORT_TARMAC = SPR_AIRPORTX_BASE; static const SpriteID SPR_NSRUNWAY1 = SPR_AIRPORTX_BASE + 1; static const SpriteID SPR_NSRUNWAY2 = SPR_AIRPORTX_BASE + 2; static const SpriteID SPR_NSRUNWAY3 = SPR_AIRPORTX_BASE + 3; static const SpriteID SPR_NSRUNWAY4 = SPR_AIRPORTX_BASE + 4; static const SpriteID SPR_NSRUNWAY_END = SPR_AIRPORTX_BASE + 5; static const SpriteID SPR_NEWHANGAR_S = SPR_AIRPORTX_BASE + 6; static const SpriteID SPR_NEWHANGAR_S_WALL = SPR_AIRPORTX_BASE + 7; static const SpriteID SPR_NEWHANGAR_W = SPR_AIRPORTX_BASE + 8; static const SpriteID SPR_NEWHANGAR_W_WALL = SPR_AIRPORTX_BASE + 9; static const SpriteID SPR_NEWHANGAR_N = SPR_AIRPORTX_BASE + 10; static const SpriteID SPR_NEWHANGAR_E = SPR_AIRPORTX_BASE + 11; static const SpriteID SPR_NEWHELIPAD = SPR_AIRPORTX_BASE + 12; static const SpriteID SPR_GRASS_RIGHT = SPR_AIRPORTX_BASE + 13; static const SpriteID SPR_GRASS_LEFT = SPR_AIRPORTX_BASE + 14; static const uint16 AIRPORTX_SPRITE_COUNT = 15; /** Airport preview sprites */ static const SpriteID SPR_AIRPORT_PREVIEW_BASE = SPR_AIRPORTX_BASE + AIRPORTX_SPRITE_COUNT; static const SpriteID SPR_AIRPORT_PREVIEW_SMALL = SPR_AIRPORT_PREVIEW_BASE; static const SpriteID SPR_AIRPORT_PREVIEW_LARGE = SPR_AIRPORT_PREVIEW_BASE + 1; static const SpriteID SPR_AIRPORT_PREVIEW_HELIPORT = SPR_AIRPORT_PREVIEW_BASE + 2; static const SpriteID SPR_AIRPORT_PREVIEW_METROPOLITAN = SPR_AIRPORT_PREVIEW_BASE + 3; static const SpriteID SPR_AIRPORT_PREVIEW_INTERNATIONAL = SPR_AIRPORT_PREVIEW_BASE + 4; static const SpriteID SPR_AIRPORT_PREVIEW_COMMUTER = SPR_AIRPORT_PREVIEW_BASE + 5; static const SpriteID SPR_AIRPORT_PREVIEW_HELIDEPOT = SPR_AIRPORT_PREVIEW_BASE + 6; static const SpriteID SPR_AIRPORT_PREVIEW_INTERCONTINENTAL = SPR_AIRPORT_PREVIEW_BASE + 7; static const SpriteID SPR_AIRPORT_PREVIEW_HELISTATION = SPR_AIRPORT_PREVIEW_BASE + 8; static const SpriteID SPR_AIRPORT_PREVIEW_COUNT = 9; static const SpriteID SPR_ROADSTOP_BASE = SPR_AIRPORT_PREVIEW_BASE + SPR_AIRPORT_PREVIEW_COUNT; // The sprites used for drive-through road stops static const SpriteID SPR_BUS_STOP_DT_Y_W = SPR_ROADSTOP_BASE; static const SpriteID SPR_BUS_STOP_DT_Y_E = SPR_ROADSTOP_BASE + 1; static const SpriteID SPR_BUS_STOP_DT_X_W = SPR_ROADSTOP_BASE + 2; static const SpriteID SPR_BUS_STOP_DT_X_E = SPR_ROADSTOP_BASE + 3; static const SpriteID SPR_TRUCK_STOP_DT_Y_W = SPR_ROADSTOP_BASE + 4; static const SpriteID SPR_TRUCK_STOP_DT_Y_E = SPR_ROADSTOP_BASE + 5; static const SpriteID SPR_TRUCK_STOP_DT_X_W = SPR_ROADSTOP_BASE + 6; static const SpriteID SPR_TRUCK_STOP_DT_X_E = SPR_ROADSTOP_BASE + 7; static const uint16 ROADSTOP_SPRITE_COUNT = 8; /** Tramway sprites */ static const SpriteID SPR_TRAMWAY_BASE = SPR_ROADSTOP_BASE + ROADSTOP_SPRITE_COUNT; static const SpriteID SPR_TRAMWAY_OVERLAY = SPR_TRAMWAY_BASE + 4; static const SpriteID SPR_TRAMWAY_TRAM = SPR_TRAMWAY_BASE + 27; static const SpriteID SPR_TRAMWAY_SLOPED_OFFSET = 11; static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_Y_W = SPR_TRAMWAY_BASE + 25; static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_Y_E = SPR_TRAMWAY_BASE + 23; static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_X_W = SPR_TRAMWAY_BASE + 24; static const SpriteID SPR_TRAMWAY_BUS_STOP_DT_X_E = SPR_TRAMWAY_BASE + 26; static const SpriteID SPR_TRAMWAY_PAVED_STRAIGHT_Y = SPR_TRAMWAY_BASE + 46; static const SpriteID SPR_TRAMWAY_PAVED_STRAIGHT_X = SPR_TRAMWAY_BASE + 47; static const SpriteID SPR_TRAMWAY_BACK_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 55; static const SpriteID SPR_TRAMWAY_FRONT_WIRES_STRAIGHT = SPR_TRAMWAY_BASE + 56; static const SpriteID SPR_TRAMWAY_BACK_WIRES_SLOPED = SPR_TRAMWAY_BASE + 72; static const SpriteID SPR_TRAMWAY_FRONT_WIRES_SLOPED = SPR_TRAMWAY_BASE + 68; static const SpriteID SPR_TRAMWAY_TUNNEL_WIRES = SPR_TRAMWAY_BASE + 80; static const SpriteID SPR_TRAMWAY_BRIDGE = SPR_TRAMWAY_BASE + 107; static const uint16 TRAMWAY_SPRITE_COUNT = 113; /** One way road sprites */ static const SpriteID SPR_ONEWAY_BASE = SPR_TRAMWAY_BASE + TRAMWAY_SPRITE_COUNT; static const uint16 ONEWAY_SPRITE_COUNT = 6; /** Flags sprites (in same order as enum NetworkLanguage) */ static const SpriteID SPR_FLAGS_BASE = SPR_ONEWAY_BASE + ONEWAY_SPRITE_COUNT; static const uint16 FLAGS_SPRITE_COUNT = 36; /** Tunnel sprites with grass only for custom railtype tunnel. */ static const SpriteID SPR_RAILTYPE_TUNNEL_BASE = SPR_FLAGS_BASE + FLAGS_SPRITE_COUNT; static const uint16 RAILTYPE_TUNNEL_BASE_COUNT = 16; /* Not really a sprite, but an empty bounding box. Used to construct bounding boxes that help sorting the sprites, but do not have a sprite associated. */ static const SpriteID SPR_EMPTY_BOUNDING_BOX = SPR_RAILTYPE_TUNNEL_BASE + RAILTYPE_TUNNEL_BASE_COUNT; static const uint16 EMPTY_BOUNDING_BOX_SPRITE_COUNT = 1; /* Black palette sprite, needed for painting (fictive) tiles outside map */ static const SpriteID SPR_PALETTE_BASE = SPR_EMPTY_BOUNDING_BOX + EMPTY_BOUNDING_BOX_SPRITE_COUNT; static const uint16 PALETTE_SPRITE_COUNT = 1; /* From where can we start putting NewGRFs? */ static const SpriteID SPR_NEWGRFS_BASE = SPR_PALETTE_BASE + PALETTE_SPRITE_COUNT; /* Manager face sprites */ static const SpriteID SPR_GRADIENT = 874; // background gradient behind manager face /* Icon showing company colour. */ static const SpriteID SPR_COMPANY_ICON = 747; /* is itself no foundation sprite, because tileh 0 has no foundation */ static const SpriteID SPR_FOUNDATION_BASE = 989; /* Shadow cell */ static const SpriteID SPR_SHADOW_CELL = 1004; /* Objects spritenumbers */ static const SpriteID SPR_TRANSMITTER = 2601; static const SpriteID SPR_LIGHTHOUSE = 2602; static const SpriteID SPR_TINYHQ_NORTH = 2603; static const SpriteID SPR_TINYHQ_EAST = 2604; static const SpriteID SPR_TINYHQ_WEST = 2605; static const SpriteID SPR_TINYHQ_SOUTH = 2606; static const SpriteID SPR_SMALLHQ_NORTH = 2607; static const SpriteID SPR_SMALLHQ_EAST = 2608; static const SpriteID SPR_SMALLHQ_WEST = 2609; static const SpriteID SPR_SMALLHQ_SOUTH = 2610; static const SpriteID SPR_MEDIUMHQ_NORTH = 2611; static const SpriteID SPR_MEDIUMHQ_NORTH_WALL = 2612; static const SpriteID SPR_MEDIUMHQ_EAST = 2613; static const SpriteID SPR_MEDIUMHQ_EAST_WALL = 2614; static const SpriteID SPR_MEDIUMHQ_WEST = 2615; static const SpriteID SPR_MEDIUMHQ_WEST_WALL = 2616; // very tiny piece of wall static const SpriteID SPR_MEDIUMHQ_SOUTH = 2617; static const SpriteID SPR_LARGEHQ_NORTH_GROUND = 2618; static const SpriteID SPR_LARGEHQ_NORTH_BUILD = 2619; static const SpriteID SPR_LARGEHQ_EAST_GROUND = 2620; static const SpriteID SPR_LARGEHQ_EAST_BUILD = 2621; static const SpriteID SPR_LARGEHQ_WEST_GROUND = 2622; static const SpriteID SPR_LARGEHQ_WEST_BUILD = 2623; static const SpriteID SPR_LARGEHQ_SOUTH = 2624; static const SpriteID SPR_HUGEHQ_NORTH_GROUND = 2625; static const SpriteID SPR_HUGEHQ_NORTH_BUILD = 2626; static const SpriteID SPR_HUGEHQ_EAST_GROUND = 2627; static const SpriteID SPR_HUGEHQ_EAST_BUILD = 2628; static const SpriteID SPR_HUGEHQ_WEST_GROUND = 2629; static const SpriteID SPR_HUGEHQ_WEST_BUILD = 2630; static const SpriteID SPR_HUGEHQ_SOUTH = 2631; static const SpriteID SPR_CONCRETE_GROUND = 1420; static const SpriteID SPR_STATUE_COMPANY = 2632; static const SpriteID SPR_BOUGHT_LAND = 4790; /* sprites for rail and rail stations*/ static const SpriteID SPR_RAIL_SNOW_OFFSET = 26; static const SpriteID SPR_MONO_SNOW_OFFSET = 26; static const SpriteID SPR_MGLV_SNOW_OFFSET = 26; static const SpriteID SPR_ORIGINAL_SIGNALS_BASE = 1275; static const SpriteID SPR_RAIL_SINGLE_X = 1005; static const SpriteID SPR_RAIL_SINGLE_Y = 1006; static const SpriteID SPR_RAIL_SINGLE_NORTH = 1007; static const SpriteID SPR_RAIL_SINGLE_SOUTH = 1008; static const SpriteID SPR_RAIL_SINGLE_EAST = 1009; static const SpriteID SPR_RAIL_SINGLE_WEST = 1010; static const SpriteID SPR_RAIL_TRACK_Y = 1011; static const SpriteID SPR_RAIL_TRACK_X = 1012; static const SpriteID SPR_RAIL_TRACK_BASE = 1018; static const SpriteID SPR_RAIL_TRACK_N_S = 1035; static const SpriteID SPR_RAIL_TRACK_Y_SNOW = 1037; static const SpriteID SPR_RAIL_TRACK_X_SNOW = 1038; static const SpriteID SPR_RAIL_DEPOT_SE_1 = 1063; static const SpriteID SPR_RAIL_DEPOT_SE_2 = 1064; static const SpriteID SPR_RAIL_DEPOT_SW_1 = 1065; static const SpriteID SPR_RAIL_DEPOT_SW_2 = 1066; static const SpriteID SPR_RAIL_DEPOT_NE = 1067; static const SpriteID SPR_RAIL_DEPOT_NW = 1068; static const SpriteID SPR_RAIL_PLATFORM_Y_FRONT = 1069; static const SpriteID SPR_RAIL_PLATFORM_X_REAR = 1070; static const SpriteID SPR_RAIL_PLATFORM_Y_REAR = 1071; static const SpriteID SPR_RAIL_PLATFORM_X_FRONT = 1072; static const SpriteID SPR_RAIL_PLATFORM_BUILDING_X = 1073; static const SpriteID SPR_RAIL_PLATFORM_BUILDING_Y = 1074; static const SpriteID SPR_RAIL_PLATFORM_PILLARS_Y_FRONT = 1075; static const SpriteID SPR_RAIL_PLATFORM_PILLARS_X_REAR = 1076; static const SpriteID SPR_RAIL_PLATFORM_PILLARS_Y_REAR = 1077; static const SpriteID SPR_RAIL_PLATFORM_PILLARS_X_FRONT = 1078; static const SpriteID SPR_RAIL_ROOF_STRUCTURE_X_TILE_A = 1079; // First half of the roof structure static const SpriteID SPR_RAIL_ROOF_STRUCTURE_Y_TILE_A = 1080; static const SpriteID SPR_RAIL_ROOF_STRUCTURE_X_TILE_B = 1081; // Second half of the roof structure static const SpriteID SPR_RAIL_ROOF_STRUCTURE_Y_TILE_B = 1082; static const SpriteID SPR_RAIL_ROOF_GLASS_X_TILE_A = 1083; // First half of the roof glass static const SpriteID SPR_RAIL_ROOF_GLASS_Y_TILE_A = 1084; static const SpriteID SPR_RAIL_ROOF_GLASS_X_TILE_B = 1085; // second half of the roof glass static const SpriteID SPR_RAIL_ROOF_GLASS_Y_TILE_B = 1086; static const SpriteID SPR_MONO_SINGLE_X = 1087; static const SpriteID SPR_MONO_SINGLE_Y = 1088; static const SpriteID SPR_MONO_SINGLE_NORTH = 1089; static const SpriteID SPR_MONO_SINGLE_SOUTH = 1090; static const SpriteID SPR_MONO_SINGLE_EAST = 1091; static const SpriteID SPR_MONO_SINGLE_WEST = 1092; static const SpriteID SPR_MONO_TRACK_Y = 1093; static const SpriteID SPR_MONO_TRACK_BASE = 1100; static const SpriteID SPR_MONO_TRACK_N_S = 1117; static const SpriteID SPR_MGLV_SINGLE_X = 1169; static const SpriteID SPR_MGLV_SINGLE_Y = 1170; static const SpriteID SPR_MGLV_SINGLE_NORTH = 1171; static const SpriteID SPR_MGLV_SINGLE_SOUTH = 1172; static const SpriteID SPR_MGLV_SINGLE_EAST = 1173; static const SpriteID SPR_MGLV_SINGLE_WEST = 1174; static const SpriteID SPR_MGLV_TRACK_Y = 1175; static const SpriteID SPR_MGLV_TRACK_BASE = 1182; static const SpriteID SPR_MGLV_TRACK_N_S = 1199; static const SpriteID SPR_WAYPOINT_X_1 = SPR_OPENTTD_BASE + 78; static const SpriteID SPR_WAYPOINT_X_2 = SPR_OPENTTD_BASE + 79; static const SpriteID SPR_WAYPOINT_Y_1 = SPR_OPENTTD_BASE + 80; static const SpriteID SPR_WAYPOINT_Y_2 = SPR_OPENTTD_BASE + 81; /* see _track_sloped_sprites in rail_cmd.cpp for slope offsets */ /* Track fences */ static const SpriteID SPR_TRACK_FENCE_FLAT_X = 1301; static const SpriteID SPR_TRACK_FENCE_FLAT_Y = 1302; static const SpriteID SPR_TRACK_FENCE_FLAT_VERT = 1303; static const SpriteID SPR_TRACK_FENCE_FLAT_HORZ = 1304; static const SpriteID SPR_TRACK_FENCE_SLOPE_SW = 1305; static const SpriteID SPR_TRACK_FENCE_SLOPE_SE = 1306; static const SpriteID SPR_TRACK_FENCE_SLOPE_NE = 1307; static const SpriteID SPR_TRACK_FENCE_SLOPE_NW = 1308; /* Base sprites for elrail. * Offsets via an enum are used so a complete list of absolute * sprite numbers is unnecessary. */ static const SpriteID SPR_WIRE_BASE = SPR_ELRAIL_BASE + 0; static const SpriteID SPR_PYLON_BASE = SPR_ELRAIL_BASE + 28; /* sprites for roads */ static const SpriteID SPR_ROAD_PAVED_STRAIGHT_Y = 1313; static const SpriteID SPR_ROAD_PAVED_STRAIGHT_X = 1314; /* sprites for airports and airfields*/ /* Small airports are AIRFIELD, everything else is AIRPORT */ static const SpriteID SPR_HELIPORT = 2633; static const SpriteID SPR_AIRPORT_APRON = 2634; static const SpriteID SPR_AIRPORT_AIRCRAFT_STAND = 2635; static const SpriteID SPR_AIRPORT_TAXIWAY_NS_WEST = 2636; static const SpriteID SPR_AIRPORT_TAXIWAY_EW_SOUTH = 2637; static const SpriteID SPR_AIRPORT_TAXIWAY_XING_SOUTH = 2638; static const SpriteID SPR_AIRPORT_TAXIWAY_XING_WEST = 2639; static const SpriteID SPR_AIRPORT_TAXIWAY_NS_CTR = 2640; static const SpriteID SPR_AIRPORT_TAXIWAY_XING_EAST = 2641; static const SpriteID SPR_AIRPORT_TAXIWAY_NS_EAST = 2642; static const SpriteID SPR_AIRPORT_TAXIWAY_EW_NORTH = 2643; static const SpriteID SPR_AIRPORT_TAXIWAY_EW_CTR = 2644; static const SpriteID SPR_AIRPORT_RUNWAY_EXIT_A = 2645; static const SpriteID SPR_AIRPORT_RUNWAY_EXIT_B = 2646; static const SpriteID SPR_AIRPORT_RUNWAY_EXIT_C = 2647; static const SpriteID SPR_AIRPORT_RUNWAY_EXIT_D = 2648; static const SpriteID SPR_AIRPORT_RUNWAY_END = 2649; // We should have different ends static const SpriteID SPR_AIRPORT_TERMINAL_A = 2650; static const SpriteID SPR_AIRPORT_TOWER = 2651; static const SpriteID SPR_AIRPORT_CONCOURSE = 2652; static const SpriteID SPR_AIRPORT_TERMINAL_B = 2653; static const SpriteID SPR_AIRPORT_TERMINAL_C = 2654; static const SpriteID SPR_AIRPORT_HANGAR_FRONT = 2655; static const SpriteID SPR_AIRPORT_HANGAR_REAR = 2656; static const SpriteID SPR_AIRFIELD_HANGAR_FRONT = 2657; static const SpriteID SPR_AIRFIELD_HANGAR_REAR = 2658; static const SpriteID SPR_AIRPORT_JETWAY_1 = 2659; static const SpriteID SPR_AIRPORT_JETWAY_2 = 2660; static const SpriteID SPR_AIRPORT_JETWAY_3 = 2661; static const SpriteID SPR_AIRPORT_PASSENGER_TUNNEL = 2662; static const SpriteID SPR_AIRPORT_FENCE_Y = 2663; static const SpriteID SPR_AIRPORT_FENCE_X = 2664; static const SpriteID SPR_AIRFIELD_TERM_A = 2665; static const SpriteID SPR_AIRFIELD_TERM_B = 2666; static const SpriteID SPR_AIRFIELD_TERM_C_GROUND = 2667; static const SpriteID SPR_AIRFIELD_TERM_C_BUILD = 2668; static const SpriteID SPR_AIRFIELD_APRON_A = 2669; static const SpriteID SPR_AIRFIELD_APRON_B = 2670; static const SpriteID SPR_AIRFIELD_APRON_C = 2671; static const SpriteID SPR_AIRFIELD_APRON_D = 2672; static const SpriteID SPR_AIRFIELD_RUNWAY_NEAR_END = 2673; static const SpriteID SPR_AIRFIELD_RUNWAY_MIDDLE = 2674; static const SpriteID SPR_AIRFIELD_RUNWAY_FAR_END = 2675; static const SpriteID SPR_AIRFIELD_WIND_1 = 2676; static const SpriteID SPR_AIRFIELD_WIND_2 = 2677; static const SpriteID SPR_AIRFIELD_WIND_3 = 2678; static const SpriteID SPR_AIRFIELD_WIND_4 = 2679; static const SpriteID SPR_AIRPORT_RADAR_1 = 2680; static const SpriteID SPR_AIRPORT_RADAR_2 = 2681; static const SpriteID SPR_AIRPORT_RADAR_3 = 2682; static const SpriteID SPR_AIRPORT_RADAR_4 = 2683; static const SpriteID SPR_AIRPORT_RADAR_5 = 2684; static const SpriteID SPR_AIRPORT_RADAR_6 = 2685; static const SpriteID SPR_AIRPORT_RADAR_7 = 2686; static const SpriteID SPR_AIRPORT_RADAR_8 = 2687; static const SpriteID SPR_AIRPORT_RADAR_9 = 2688; static const SpriteID SPR_AIRPORT_RADAR_A = 2689; static const SpriteID SPR_AIRPORT_RADAR_B = 2690; static const SpriteID SPR_AIRPORT_RADAR_C = 2691; static const SpriteID SPR_AIRPORT_HELIPAD = SPR_OPENTTD_BASE + 86; static const SpriteID SPR_AIRPORT_HELIDEPOT_OFFICE = 2095; /* Road Stops * Road stops have a ground tile and 3 buildings, one on each side * (except the side where the entry is). These are marked _A _B and _C */ static const SpriteID SPR_BUS_STOP_NE_GROUND = 2692; static const SpriteID SPR_BUS_STOP_SE_GROUND = 2693; static const SpriteID SPR_BUS_STOP_SW_GROUND = 2694; static const SpriteID SPR_BUS_STOP_NW_GROUND = 2695; static const SpriteID SPR_BUS_STOP_NE_BUILD_A = 2696; static const SpriteID SPR_BUS_STOP_SE_BUILD_A = 2697; static const SpriteID SPR_BUS_STOP_SW_BUILD_A = 2698; static const SpriteID SPR_BUS_STOP_NW_BUILD_A = 2699; static const SpriteID SPR_BUS_STOP_NE_BUILD_B = 2700; static const SpriteID SPR_BUS_STOP_SE_BUILD_B = 2701; static const SpriteID SPR_BUS_STOP_SW_BUILD_B = 2702; static const SpriteID SPR_BUS_STOP_NW_BUILD_B = 2703; static const SpriteID SPR_BUS_STOP_NE_BUILD_C = 2704; static const SpriteID SPR_BUS_STOP_SE_BUILD_C = 2705; static const SpriteID SPR_BUS_STOP_SW_BUILD_C = 2706; static const SpriteID SPR_BUS_STOP_NW_BUILD_C = 2707; static const SpriteID SPR_TRUCK_STOP_NE_GROUND = 2708; static const SpriteID SPR_TRUCK_STOP_SE_GROUND = 2709; static const SpriteID SPR_TRUCK_STOP_SW_GROUND = 2710; static const SpriteID SPR_TRUCK_STOP_NW_GROUND = 2711; static const SpriteID SPR_TRUCK_STOP_NE_BUILD_A = 2712; static const SpriteID SPR_TRUCK_STOP_SE_BUILD_A = 2713; static const SpriteID SPR_TRUCK_STOP_SW_BUILD_A = 2714; static const SpriteID SPR_TRUCK_STOP_NW_BUILD_A = 2715; static const SpriteID SPR_TRUCK_STOP_NE_BUILD_B = 2716; static const SpriteID SPR_TRUCK_STOP_SE_BUILD_B = 2717; static const SpriteID SPR_TRUCK_STOP_SW_BUILD_B = 2718; static const SpriteID SPR_TRUCK_STOP_NW_BUILD_B = 2719; static const SpriteID SPR_TRUCK_STOP_NE_BUILD_C = 2720; static const SpriteID SPR_TRUCK_STOP_SE_BUILD_C = 2721; static const SpriteID SPR_TRUCK_STOP_SW_BUILD_C = 2722; static const SpriteID SPR_TRUCK_STOP_NW_BUILD_C = 2723; /* Sprites for docks * Docks consist of two tiles, the sloped one and the flat one */ static const SpriteID SPR_DOCK_SLOPE_NE = 2727; static const SpriteID SPR_DOCK_SLOPE_SE = 2728; static const SpriteID SPR_DOCK_SLOPE_SW = 2729; static const SpriteID SPR_DOCK_SLOPE_NW = 2730; static const SpriteID SPR_DOCK_FLAT_X = 2731; // for NE and SW static const SpriteID SPR_DOCK_FLAT_Y = 2732; // for NW and SE static const SpriteID SPR_BUOY = 4076; // XXX this sucks, because it displays wrong stuff on canals /* Sprites for road */ static const SpriteID SPR_ROAD_Y = 1332; static const SpriteID SPR_ROAD_X = 1333; static const SpriteID SPR_ROAD_SLOPE_START = 1343; static const SpriteID SPR_ROAD_Y_SNOW = 1351; static const SpriteID SPR_ROAD_X_SNOW = 1352; /* see _road_sloped_sprites_offset in road_cmd.cpp for offsets for sloped road tiles */ static const SpriteID SPR_EXCAVATION_X = 1414; static const SpriteID SPR_EXCAVATION_Y = 1415; /* Landscape sprites */ static const SpriteID SPR_FLAT_BARE_LAND = 3924; static const SpriteID SPR_FLAT_1_THIRD_GRASS_TILE = 3943; static const SpriteID SPR_FLAT_2_THIRD_GRASS_TILE = 3962; static const SpriteID SPR_FLAT_GRASS_TILE = 3981; static const SpriteID SPR_FLAT_ROUGH_LAND = 4000; static const SpriteID SPR_FLAT_ROUGH_LAND_1 = 4019; static const SpriteID SPR_FLAT_ROUGH_LAND_2 = 4020; static const SpriteID SPR_FLAT_ROUGH_LAND_3 = 4021; static const SpriteID SPR_FLAT_ROUGH_LAND_4 = 4022; static const SpriteID SPR_FLAT_ROCKY_LAND_1 = 4023; static const SpriteID SPR_FLAT_ROCKY_LAND_2 = 4042; static const SpriteID SPR_FLAT_WATER_TILE = 4061; static const SpriteID SPR_FLAT_1_QUART_SNOW_DESERT_TILE = 4493; static const SpriteID SPR_FLAT_2_QUART_SNOW_DESERT_TILE = 4512; static const SpriteID SPR_FLAT_3_QUART_SNOW_DESERT_TILE = 4531; static const SpriteID SPR_FLAT_SNOW_DESERT_TILE = 4550; /* Hedge, Farmland-fence sprites */ static const SpriteID SPR_HEDGE_BUSHES = 4090; static const SpriteID SPR_HEDGE_BUSHES_WITH_GATE = 4096; static const SpriteID SPR_HEDGE_FENCE = 4102; static const SpriteID SPR_HEDGE_BLOOMBUSH_YELLOW = 4108; static const SpriteID SPR_HEDGE_BLOOMBUSH_RED = 4114; static const SpriteID SPR_HEDGE_STONE = 4120; /* Farmland sprites, only flat tiles listed, various stages */ static const SpriteID SPR_FARMLAND_BARE = 4126; static const SpriteID SPR_FARMLAND_STATE_1 = 4145; static const SpriteID SPR_FARMLAND_STATE_2 = 4164; static const SpriteID SPR_FARMLAND_STATE_3 = 4183; static const SpriteID SPR_FARMLAND_STATE_4 = 4202; static const SpriteID SPR_FARMLAND_STATE_5 = 4221; static const SpriteID SPR_FARMLAND_STATE_6 = 4240; static const SpriteID SPR_FARMLAND_STATE_7 = 4259; static const SpriteID SPR_FARMLAND_HAYPACKS = 4278; /* Water-related sprites */ static const SpriteID SPR_SHIP_DEPOT_SE_FRONT = 4070; static const SpriteID SPR_SHIP_DEPOT_SW_FRONT = 4071; static const SpriteID SPR_SHIP_DEPOT_NW = 4072; static const SpriteID SPR_SHIP_DEPOT_NE = 4073; static const SpriteID SPR_SHIP_DEPOT_SE_REAR = 4074; static const SpriteID SPR_SHIP_DEPOT_SW_REAR = 4075; /* here come sloped water sprites */ static const SpriteID SPR_WATER_SLOPE_Y_UP = SPR_CANALS_BASE + 0; // Water flowing negative Y direction static const SpriteID SPR_WATER_SLOPE_X_DOWN = SPR_CANALS_BASE + 1; // positive X static const SpriteID SPR_WATER_SLOPE_X_UP = SPR_CANALS_BASE + 2; // negative X static const SpriteID SPR_WATER_SLOPE_Y_DOWN = SPR_CANALS_BASE + 3; // positive Y /* sprites for the locks * there are 4 kinds of locks, each of them is 3 tiles long. * the four kinds are running in the X and Y direction and * are "lowering" either in the "+" or the "-" direction. * the three tiles are the center tile (where the slope is) * and a bottom and a top tile */ static const SpriteID SPR_LOCK_BASE = SPR_CANALS_BASE + 4; static const SpriteID SPR_LOCK_Y_UP_CENTER_REAR = SPR_CANALS_BASE + 4; static const SpriteID SPR_LOCK_X_DOWN_CENTER_REAR = SPR_CANALS_BASE + 5; static const SpriteID SPR_LOCK_X_UP_CENTER_REAR = SPR_CANALS_BASE + 6; static const SpriteID SPR_LOCK_Y_DOWN_CENTER_REAR = SPR_CANALS_BASE + 7; static const SpriteID SPR_LOCK_Y_UP_CENTER_FRONT = SPR_CANALS_BASE + 8; static const SpriteID SPR_LOCK_X_DOWN_CENTER_FRONT = SPR_CANALS_BASE + 9; static const SpriteID SPR_LOCK_X_UP_CENTER_FRONT = SPR_CANALS_BASE + 10; static const SpriteID SPR_LOCK_Y_DOWN_CENTER_FRONT = SPR_CANALS_BASE + 11; static const SpriteID SPR_LOCK_Y_UP_BOTTOM_REAR = SPR_CANALS_BASE + 12; static const SpriteID SPR_LOCK_X_DOWN_BOTTOM_REAR = SPR_CANALS_BASE + 13; static const SpriteID SPR_LOCK_X_UP_BOTTOM_REAR = SPR_CANALS_BASE + 14; static const SpriteID SPR_LOCK_Y_DOWN_BOTTOM_REAR = SPR_CANALS_BASE + 15; static const SpriteID SPR_LOCK_Y_UP_BOTTOM_FRONT = SPR_CANALS_BASE + 16; static const SpriteID SPR_LOCK_X_DOWN_BOTTOM_FRONT = SPR_CANALS_BASE + 17; static const SpriteID SPR_LOCK_X_UP_BOTTOM_FRONT = SPR_CANALS_BASE + 18; static const SpriteID SPR_LOCK_Y_DOWN_BOTTOM_FRONT = SPR_CANALS_BASE + 19; static const SpriteID SPR_LOCK_Y_UP_TOP_REAR = SPR_CANALS_BASE + 20; static const SpriteID SPR_LOCK_X_DOWN_TOP_REAR = SPR_CANALS_BASE + 21; static const SpriteID SPR_LOCK_X_UP_TOP_REAR = SPR_CANALS_BASE + 22; static const SpriteID SPR_LOCK_Y_DOWN_TOP_REAR = SPR_CANALS_BASE + 23; static const SpriteID SPR_LOCK_Y_UP_TOP_FRONT = SPR_CANALS_BASE + 24; static const SpriteID SPR_LOCK_X_DOWN_TOP_FRONT = SPR_CANALS_BASE + 25; static const SpriteID SPR_LOCK_X_UP_TOP_FRONT = SPR_CANALS_BASE + 26; static const SpriteID SPR_LOCK_Y_DOWN_TOP_FRONT = SPR_CANALS_BASE + 27; static const SpriteID SPR_CANAL_DIKES_BASE = SPR_CANALS_BASE + 52; /* Sprites for tunnels and bridges */ static const SpriteID SPR_TUNNEL_ENTRY_REAR_RAIL = 2365; static const SpriteID SPR_TUNNEL_ENTRY_REAR_MONO = 2373; static const SpriteID SPR_TUNNEL_ENTRY_REAR_MAGLEV = 2381; static const SpriteID SPR_TUNNEL_ENTRY_REAR_ROAD = 2389; /* Level crossings */ static const SpriteID SPR_CROSSING_OFF_X_RAIL = 1370; static const SpriteID SPR_CROSSING_OFF_X_MONO = 1382; static const SpriteID SPR_CROSSING_OFF_X_MAGLEV = 1394; /* bridge type sprites */ static const SpriteID SPR_PILLARS_BASE = SPR_OPENTTD_BASE + 14; /* Wooden bridge (type 0) */ static const SpriteID SPR_BTWDN_RAIL_Y_REAR = 2545; static const SpriteID SPR_BTWDN_RAIL_X_REAR = 2546; static const SpriteID SPR_BTWDN_ROAD_Y_REAR = 2547; static const SpriteID SPR_BTWDN_ROAD_X_REAR = 2548; static const SpriteID SPR_BTWDN_Y_FRONT = 2549; static const SpriteID SPR_BTWDN_X_FRONT = 2550; static const SpriteID SPR_BTWDN_Y_PILLAR = 2551; static const SpriteID SPR_BTWDN_X_PILLAR = 2552; static const SpriteID SPR_BTWDN_MONO_Y_REAR = 4360; static const SpriteID SPR_BTWDN_MONO_X_REAR = 4361; static const SpriteID SPR_BTWDN_MGLV_Y_REAR = 4400; static const SpriteID SPR_BTWDN_MGLV_X_REAR = 4401; /* ramps */ static const SpriteID SPR_BTWDN_ROAD_RAMP_Y_DOWN = 2529; static const SpriteID SPR_BTWDN_ROAD_RAMP_X_DOWN = 2530; static const SpriteID SPR_BTWDN_ROAD_RAMP_X_UP = 2531; // for some weird reason the order is swapped static const SpriteID SPR_BTWDN_ROAD_RAMP_Y_UP = 2532; // between X and Y. static const SpriteID SPR_BTWDN_ROAD_Y_SLOPE_UP = 2533; static const SpriteID SPR_BTWDN_ROAD_X_SLOPE_UP = 2534; static const SpriteID SPR_BTWDN_ROAD_Y_SLOPE_DOWN = 2535; static const SpriteID SPR_BTWDN_ROAD_X_SLOPE_DOWN = 2536; static const SpriteID SPR_BTWDN_RAIL_RAMP_Y_DOWN = 2537; static const SpriteID SPR_BTWDN_RAIL_RAMP_X_DOWN = 2538; static const SpriteID SPR_BTWDN_RAIL_RAMP_X_UP = 2539; // for some weird reason the order is swapped static const SpriteID SPR_BTWDN_RAIL_RAMP_Y_UP = 2540; // between X and Y. static const SpriteID SPR_BTWDN_RAIL_Y_SLOPE_UP = 2541; static const SpriteID SPR_BTWDN_RAIL_X_SLOPE_UP = 2542; static const SpriteID SPR_BTWDN_RAIL_Y_SLOPE_DOWN = 2543; static const SpriteID SPR_BTWDN_RAIL_X_SLOPE_DOWN = 2544; static const SpriteID SPR_BTWDN_MONO_RAMP_Y_DOWN = 4352; static const SpriteID SPR_BTWDN_MONO_RAMP_X_DOWN = 4353; static const SpriteID SPR_BTWDN_MONO_RAMP_X_UP = 4354; // for some weird reason the order is swapped static const SpriteID SPR_BTWDN_MONO_RAMP_Y_UP = 4355; // between X and Y. static const SpriteID SPR_BTWDN_MONO_Y_SLOPE_UP = 4356; static const SpriteID SPR_BTWDN_MONO_X_SLOPE_UP = 4357; static const SpriteID SPR_BTWDN_MONO_Y_SLOPE_DOWN = 4358; static const SpriteID SPR_BTWDN_MONO_X_SLOPE_DOWN = 4359; static const SpriteID SPR_BTWDN_MGLV_RAMP_Y_DOWN = 4392; static const SpriteID SPR_BTWDN_MGLV_RAMP_X_DOWN = 4393; static const SpriteID SPR_BTWDN_MGLV_RAMP_X_UP = 4394; // for some weird reason the order is swapped static const SpriteID SPR_BTWDN_MGLV_RAMP_Y_UP = 4395; // between X and Y. static const SpriteID SPR_BTWDN_MGLV_Y_SLOPE_UP = 4396; static const SpriteID SPR_BTWDN_MGLV_X_SLOPE_UP = 4397; static const SpriteID SPR_BTWDN_MGLV_Y_SLOPE_DOWN = 4398; static const SpriteID SPR_BTWDN_MGLV_X_SLOPE_DOWN = 4399; /* Steel Girder with arches * BTSGA == Bridge Type Steel Girder Arched * This is bridge type number 2 */ static const SpriteID SPR_BTSGA_RAIL_X_REAR = 2499; static const SpriteID SPR_BTSGA_RAIL_Y_REAR = 2500; static const SpriteID SPR_BTSGA_ROAD_X_REAR = 2501; static const SpriteID SPR_BTSGA_ROAD_Y_REAR = 2502; static const SpriteID SPR_BTSGA_X_FRONT = 2503; static const SpriteID SPR_BTSGA_Y_FRONT = 2504; static const SpriteID SPR_BTSGA_X_PILLAR = 2505; static const SpriteID SPR_BTSGA_Y_PILLAR = 2506; static const SpriteID SPR_BTSGA_MONO_X_REAR = 4324; static const SpriteID SPR_BTSGA_MONO_Y_REAR = 4325; static const SpriteID SPR_BTSGA_MGLV_X_REAR = 4364; static const SpriteID SPR_BTSGA_MGLV_Y_REAR = 4365; /* BTSUS == Suspension bridge * TILE_* denotes the different tiles a suspension bridge * can have * TILE_A and TILE_B are the "beginnings" and "ends" of the * suspension system. They have small rectangular endcaps * TILE_C and TILE_D look almost identical to TILE_A and * TILE_B, but they do not have the "endcaps". They form the * middle part * TILE_E is a condensed configuration of two pillars. while they * are usually 2 pillars apart, they only have 1 pillar separation * here * TILE_F is an extended configuration of pillars. They are * plugged in when pillars should be 3 tiles apart */ static const SpriteID SPR_BTSUS_ROAD_Y_REAR_TILE_A = 2453; static const SpriteID SPR_BTSUS_ROAD_Y_REAR_TILE_B = 2454; static const SpriteID SPR_BTSUS_Y_FRONT_TILE_A = 2455; static const SpriteID SPR_BTSUS_Y_FRONT_TILE_B = 2456; static const SpriteID SPR_BTSUS_ROAD_Y_REAR_TILE_D = 2457; static const SpriteID SPR_BTSUS_ROAD_Y_REAR_TILE_C = 2458; static const SpriteID SPR_BTSUS_Y_FRONT_TILE_D = 2459; static const SpriteID SPR_BTSUS_Y_FRONT_TILE_C = 2460; static const SpriteID SPR_BTSUS_ROAD_X_REAR_TILE_A = 2461; static const SpriteID SPR_BTSUS_ROAD_X_REAR_TILE_B = 2462; static const SpriteID SPR_BTSUS_X_FRONT_TILE_A = 2463; static const SpriteID SPR_BTSUS_X_FRONT_TILE_B = 2464; static const SpriteID SPR_BTSUS_ROAD_X_REAR_TILE_D = 2465; static const SpriteID SPR_BTSUS_ROAD_X_REAR_TILE_C = 2466; static const SpriteID SPR_BTSUS_X_FRONT_TILE_D = 2467; static const SpriteID SPR_BTSUS_X_FRONT_TILE_C = 2468; static const SpriteID SPR_BTSUS_RAIL_Y_REAR_TILE_A = 2469; static const SpriteID SPR_BTSUS_RAIL_Y_REAR_TILE_B = 2470; static const SpriteID SPR_BTSUS_RAIL_Y_REAR_TILE_D = 2471; static const SpriteID SPR_BTSUS_RAIL_Y_REAR_TILE_C = 2472; static const SpriteID SPR_BTSUS_RAIL_X_REAR_TILE_A = 2473; static const SpriteID SPR_BTSUS_RAIL_X_REAR_TILE_B = 2474; static const SpriteID SPR_BTSUS_RAIL_X_REAR_TILE_D = 2475; static const SpriteID SPR_BTSUS_RAIL_X_REAR_TILE_C = 2476; static const SpriteID SPR_BTSUS_Y_PILLAR_TILE_A = 2477; static const SpriteID SPR_BTSUS_Y_PILLAR_TILE_B = 2478; static const SpriteID SPR_BTSUS_Y_PILLAR_TILE_D = 2479; static const SpriteID SPR_BTSUS_Y_PILLAR_TILE_C = 2480; static const SpriteID SPR_BTSUS_X_PILLAR_TILE_A = 2481; static const SpriteID SPR_BTSUS_X_PILLAR_TILE_B = 2482; static const SpriteID SPR_BTSUS_X_PILLAR_TILE_D = 2483; static const SpriteID SPR_BTSUS_X_PILLAR_TILE_C = 2484; static const SpriteID SPR_BTSUS_RAIL_Y_REAR_TILE_E = 2485; static const SpriteID SPR_BTSUS_RAIL_X_REAR_TILE_E = 2486; static const SpriteID SPR_BTSUS_ROAD_Y_REAR_TILE_E = 2487; static const SpriteID SPR_BTSUS_ROAD_X_REAR_TILE_E = 2488; static const SpriteID SPR_BTSUS_Y_FRONT_TILE_E = 2489; static const SpriteID SPR_BTSUS_X_FRONT_TILE_E = 2490; static const SpriteID SPR_BTSUS_Y_PILLAR_TILE_E = 2491; static const SpriteID SPR_BTSUS_X_PILLAR_TILE_E = 2492; static const SpriteID SPR_BTSUS_RAIL_X_REAR_TILE_F = 2493; static const SpriteID SPR_BTSUS_RAIL_Y_REAR_TILE_F = 2494; static const SpriteID SPR_BTSUS_ROAD_X_REAR_TILE_F = 2495; static const SpriteID SPR_BTSUS_ROAD_Y_REAR_TILE_F = 2496; static const SpriteID SPR_BTSUS_X_FRONT = 2497; static const SpriteID SPR_BTSUS_Y_FRONT = 2498; static const SpriteID SPR_BTSUS_MONO_Y_REAR_TILE_A = 4334; static const SpriteID SPR_BTSUS_MONO_Y_REAR_TILE_B = 4335; static const SpriteID SPR_BTSUS_MONO_Y_REAR_TILE_D = 4336; static const SpriteID SPR_BTSUS_MONO_Y_REAR_TILE_C = 4337; static const SpriteID SPR_BTSUS_MONO_X_REAR_TILE_A = 4338; static const SpriteID SPR_BTSUS_MONO_X_REAR_TILE_B = 4339; static const SpriteID SPR_BTSUS_MONO_X_REAR_TILE_D = 4340; static const SpriteID SPR_BTSUS_MONO_X_REAR_TILE_C = 4341; static const SpriteID SPR_BTSUS_MONO_Y_REAR_TILE_E = 4342; static const SpriteID SPR_BTSUS_MONO_X_REAR_TILE_E = 4343; static const SpriteID SPR_BTSUS_MONO_X_REAR_TILE_F = 4344; static const SpriteID SPR_BTSUS_MONO_Y_REAR_TILE_F = 4345; static const SpriteID SPR_BTSUS_MGLV_Y_REAR_TILE_A = 4374; static const SpriteID SPR_BTSUS_MGLV_Y_REAR_TILE_B = 4375; static const SpriteID SPR_BTSUS_MGLV_Y_REAR_TILE_D = 4376; static const SpriteID SPR_BTSUS_MGLV_Y_REAR_TILE_C = 4377; static const SpriteID SPR_BTSUS_MGLV_X_REAR_TILE_A = 4378; static const SpriteID SPR_BTSUS_MGLV_X_REAR_TILE_B = 4379; static const SpriteID SPR_BTSUS_MGLV_X_REAR_TILE_D = 4380; static const SpriteID SPR_BTSUS_MGLV_X_REAR_TILE_C = 4381; static const SpriteID SPR_BTSUS_MGLV_Y_REAR_TILE_E = 4382; static const SpriteID SPR_BTSUS_MGLV_X_REAR_TILE_E = 4383; static const SpriteID SPR_BTSUS_MGLV_X_REAR_TILE_F = 4384; static const SpriteID SPR_BTSUS_MGLV_Y_REAR_TILE_F = 4385; /* cantilever bridges * They have three different kinds of tiles: * END(ing), MID(dle), BEG(ginning) */ static const SpriteID SPR_BTCAN_RAIL_X_BEG = 2507; static const SpriteID SPR_BTCAN_RAIL_X_MID = 2508; static const SpriteID SPR_BTCAN_RAIL_X_END = 2509; static const SpriteID SPR_BTCAN_RAIL_Y_END = 2510; static const SpriteID SPR_BTCAN_RAIL_Y_MID = 2511; static const SpriteID SPR_BTCAN_RAIL_Y_BEG = 2512; static const SpriteID SPR_BTCAN_ROAD_X_BEG = 2513; static const SpriteID SPR_BTCAN_ROAD_X_MID = 2514; static const SpriteID SPR_BTCAN_ROAD_X_END = 2515; static const SpriteID SPR_BTCAN_ROAD_Y_END = 2516; static const SpriteID SPR_BTCAN_ROAD_Y_MID = 2517; static const SpriteID SPR_BTCAN_ROAD_Y_BEG = 2518; static const SpriteID SPR_BTCAN_X_FRONT_BEG = 2519; static const SpriteID SPR_BTCAN_X_FRONT_MID = 2520; static const SpriteID SPR_BTCAN_X_FRONT_END = 2521; static const SpriteID SPR_BTCAN_Y_FRONT_END = 2522; static const SpriteID SPR_BTCAN_Y_FRONT_MID = 2523; static const SpriteID SPR_BTCAN_Y_FRONT_BEG = 2524; static const SpriteID SPR_BTCAN_X_PILLAR_BEG = 2525; static const SpriteID SPR_BTCAN_X_PILLAR_MID = 2526; static const SpriteID SPR_BTCAN_Y_PILLAR_MID = 2527; static const SpriteID SPR_BTCAN_Y_PILLAR_BEG = 2528; static const SpriteID SPR_BTCAN_MONO_X_BEG = 4346; static const SpriteID SPR_BTCAN_MONO_X_MID = 4347; static const SpriteID SPR_BTCAN_MONO_X_END = 4348; static const SpriteID SPR_BTCAN_MONO_Y_END = 4349; static const SpriteID SPR_BTCAN_MONO_Y_MID = 4350; static const SpriteID SPR_BTCAN_MONO_Y_BEG = 4351; static const SpriteID SPR_BTCAN_MGLV_X_BEG = 4386; static const SpriteID SPR_BTCAN_MGLV_X_MID = 4387; static const SpriteID SPR_BTCAN_MGLV_X_END = 4388; static const SpriteID SPR_BTCAN_MGLV_Y_END = 4389; static const SpriteID SPR_BTCAN_MGLV_Y_MID = 4390; static const SpriteID SPR_BTCAN_MGLV_Y_BEG = 4391; /* little concrete bridge */ static const SpriteID SPR_BTCON_RAIL_X = 2493; static const SpriteID SPR_BTCON_RAIL_Y = 2494; static const SpriteID SPR_BTCON_ROAD_X = 2495; static const SpriteID SPR_BTCON_ROAD_Y = 2496; static const SpriteID SPR_BTCON_X_FRONT = 2497; static const SpriteID SPR_BTCON_Y_FRONT = 2498; static const SpriteID SPR_BTCON_X_PILLAR = 2505; static const SpriteID SPR_BTCON_Y_PILLAR = 2506; static const SpriteID SPR_BTCON_MONO_X = 4344; static const SpriteID SPR_BTCON_MONO_Y = 4345; static const SpriteID SPR_BTCON_MGLV_X = 4384; static const SpriteID SPR_BTCON_MGLV_Y = 4385; /* little steel girder bridge */ static const SpriteID SPR_BTGIR_RAIL_X = 2553; static const SpriteID SPR_BTGIR_RAIL_Y = 2554; static const SpriteID SPR_BTGIR_ROAD_X = 2555; static const SpriteID SPR_BTGIR_ROAD_Y = 2556; static const SpriteID SPR_BTGIR_X_FRONT = 2557; static const SpriteID SPR_BTGIR_Y_FRONT = 2558; static const SpriteID SPR_BTGIR_X_PILLAR = 2505; static const SpriteID SPR_BTGIR_Y_PILLAR = 2506; static const SpriteID SPR_BTGIR_MONO_X = 4362; static const SpriteID SPR_BTGIR_MONO_Y = 4363; static const SpriteID SPR_BTGIR_MGLV_X = 4402; static const SpriteID SPR_BTGIR_MGLV_Y = 4403; /* tubular bridges * tubular bridges have 3 kinds of tiles: * a start tile (with only half a tube on the far side, marked _BEG * a middle tile (full tunnel), marked _MID * and an end tile (half a tube on the near side, marked _END */ static const SpriteID SPR_BTTUB_X_FRONT_BEG = 2559; static const SpriteID SPR_BTTUB_X_FRONT_MID = 2560; static const SpriteID SPR_BTTUB_X_FRONT_END = 2561; static const SpriteID SPR_BTTUB_Y_FRONT_END = 2562; static const SpriteID SPR_BTTUB_Y_FRONT_MID = 2563; static const SpriteID SPR_BTTUB_Y_FRONT_BEG = 2564; static const SpriteID SPR_BTTUB_X_PILLAR_BEG = 2565; static const SpriteID SPR_BTTUB_X_PILLAR_MID = 2566; static const SpriteID SPR_BTTUB_Y_PILLAR_MID = 2567; static const SpriteID SPR_BTTUB_Y_PILLAR_BEG = 2568; static const SpriteID SPR_BTTUB_X_RAIL_REAR_BEG = 2569; static const SpriteID SPR_BTTUB_X_RAIL_REAR_MID = 2570; static const SpriteID SPR_BTTUB_X_RAIL_REAR_END = 2571; static const SpriteID SPR_BTTUB_Y_RAIL_REAR_BEG = 2572; static const SpriteID SPR_BTTUB_Y_RAIL_REAR_MID = 2573; static const SpriteID SPR_BTTUB_Y_RAIL_REAR_END = 2574; static const SpriteID SPR_BTTUB_X_ROAD_REAR_BEG = 2575; static const SpriteID SPR_BTTUB_X_ROAD_REAR_MID = 2576; static const SpriteID SPR_BTTUB_X_ROAD_REAR_END = 2577; static const SpriteID SPR_BTTUB_Y_ROAD_REAR_BEG = 2578; static const SpriteID SPR_BTTUB_Y_ROAD_REAR_MID = 2579; static const SpriteID SPR_BTTUB_Y_ROAD_REAR_END = 2580; static const SpriteID SPR_BTTUB_X_MONO_REAR_BEG = 2581; static const SpriteID SPR_BTTUB_X_MONO_REAR_MID = 2582; static const SpriteID SPR_BTTUB_X_MONO_REAR_END = 2583; static const SpriteID SPR_BTTUB_Y_MONO_REAR_BEG = 2584; static const SpriteID SPR_BTTUB_Y_MONO_REAR_MID = 2585; static const SpriteID SPR_BTTUB_Y_MONO_REAR_END = 2586; static const SpriteID SPR_BTTUB_X_MGLV_REAR_BEG = 2587; static const SpriteID SPR_BTTUB_X_MGLV_REAR_MID = 2588; static const SpriteID SPR_BTTUB_X_MGLV_REAR_END = 2589; static const SpriteID SPR_BTTUB_Y_MGLV_REAR_BEG = 2590; static const SpriteID SPR_BTTUB_Y_MGLV_REAR_MID = 2591; static const SpriteID SPR_BTTUB_Y_MGLV_REAR_END = 2592; /* ramps (for all bridges except wood and tubular?)*/ static const SpriteID SPR_BTGEN_RAIL_X_SLOPE_DOWN = 2437; static const SpriteID SPR_BTGEN_RAIL_X_SLOPE_UP = 2438; static const SpriteID SPR_BTGEN_RAIL_Y_SLOPE_DOWN = 2439; static const SpriteID SPR_BTGEN_RAIL_Y_SLOPE_UP = 2440; static const SpriteID SPR_BTGEN_RAIL_RAMP_X_UP = 2441; static const SpriteID SPR_BTGEN_RAIL_RAMP_X_DOWN = 2442; static const SpriteID SPR_BTGEN_RAIL_RAMP_Y_UP = 2443; static const SpriteID SPR_BTGEN_RAIL_RAMP_Y_DOWN = 2444; static const SpriteID SPR_BTGEN_ROAD_X_SLOPE_DOWN = 2445; static const SpriteID SPR_BTGEN_ROAD_X_SLOPE_UP = 2446; static const SpriteID SPR_BTGEN_ROAD_Y_SLOPE_DOWN = 2447; static const SpriteID SPR_BTGEN_ROAD_Y_SLOPE_UP = 2448; static const SpriteID SPR_BTGEN_ROAD_RAMP_X_UP = 2449; static const SpriteID SPR_BTGEN_ROAD_RAMP_X_DOWN = 2450; static const SpriteID SPR_BTGEN_ROAD_RAMP_Y_UP = 2451; static const SpriteID SPR_BTGEN_ROAD_RAMP_Y_DOWN = 2452; static const SpriteID SPR_BTGEN_MONO_X_SLOPE_DOWN = 4326; static const SpriteID SPR_BTGEN_MONO_X_SLOPE_UP = 4327; static const SpriteID SPR_BTGEN_MONO_Y_SLOPE_DOWN = 4328; static const SpriteID SPR_BTGEN_MONO_Y_SLOPE_UP = 4329; static const SpriteID SPR_BTGEN_MONO_RAMP_X_UP = 4330; static const SpriteID SPR_BTGEN_MONO_RAMP_X_DOWN = 4331; static const SpriteID SPR_BTGEN_MONO_RAMP_Y_UP = 4332; static const SpriteID SPR_BTGEN_MONO_RAMP_Y_DOWN = 4333; static const SpriteID SPR_BTGEN_MGLV_X_SLOPE_DOWN = 4366; static const SpriteID SPR_BTGEN_MGLV_X_SLOPE_UP = 4367; static const SpriteID SPR_BTGEN_MGLV_Y_SLOPE_DOWN = 4368; static const SpriteID SPR_BTGEN_MGLV_Y_SLOPE_UP = 4369; static const SpriteID SPR_BTGEN_MGLV_RAMP_X_UP = 4370; static const SpriteID SPR_BTGEN_MGLV_RAMP_X_DOWN = 4371; static const SpriteID SPR_BTGEN_MGLV_RAMP_Y_UP = 4372; static const SpriteID SPR_BTGEN_MGLV_RAMP_Y_DOWN = 4373; /* Vehicle view sprites */ static const SpriteID SPR_CENTRE_VIEW_VEHICLE = 683; static const SpriteID SPR_SEND_TRAIN_TODEPOT = 685; static const SpriteID SPR_SEND_ROADVEH_TODEPOT = 686; static const SpriteID SPR_SEND_AIRCRAFT_TODEPOT = 687; static const SpriteID SPR_SEND_SHIP_TODEPOT = 688; static const SpriteID SPR_IGNORE_SIGNALS = 689; static const SpriteID SPR_SHOW_ORDERS = 690; static const SpriteID SPR_SHOW_VEHICLE_DETAILS = 691; static const SpriteID SPR_REFIT_VEHICLE = 692; static const SpriteID SPR_FORCE_VEHICLE_TURN = 715; /* Vehicle sprite-flags (red/green) */ static const SpriteID SPR_FLAG_VEH_STOPPED = 3090; static const SpriteID SPR_FLAG_VEH_RUNNING = 3091; static const SpriteID SPR_VEH_BUS_SW_VIEW = 3097; static const SpriteID SPR_VEH_BUS_SIDE_VIEW = 3098; /* Rotor sprite numbers */ static const SpriteID SPR_ROTOR_STOPPED = 3901; static const SpriteID SPR_ROTOR_MOVING_1 = 3902; static const SpriteID SPR_ROTOR_MOVING_3 = 3904; /* Town/house sprites */ static const SpriteID SPR_LIFT = 1443; /* used in town_land.h * CNST1..3 = Those are the different stages of construction * The last 2 hexas correspond to the type of building it represent, if any */ static const SpriteID SPR_CNST1_TALLOFFICE_00 = 1421; static const SpriteID SPR_CNST2_TALLOFFICE_00 = 1422; static const SpriteID SPR_CNST3_TALLOFFICE_00 = 1423; static const SpriteID SPR_GROUND_TALLOFFICE_00 = 1424; static const SpriteID SPR_BUILD_TALLOFFICE_00 = 1425; // temperate static const SpriteID SPR_CNST1_OFFICE_01 = 1426; static const SpriteID SPR_CNST2_OFFICE_01 = 1427; static const SpriteID SPR_BUILD_OFFICE_01 = 1428; // temperate static const SpriteID SPR_GROUND_OFFICE_01 = 1429; static const SpriteID SPR_CNST1_SMLBLCKFLATS_02 = 1430; // Small Block of Flats static const SpriteID SPR_CNST2_SMLBLCKFLATS_02 = 1431; static const SpriteID SPR_BUILD_SMLBLCKFLATS_02 = 1432; // temperate static const SpriteID SPR_GROUND_SMLBLCKFLATS_02 = 1433; static const SpriteID SPR_CNST1_TEMPCHURCH = 1434; static const SpriteID SPR_CNST2_TEMPCHURCH = 1435; static const SpriteID SPR_BUILD_TEMPCHURCH = 1436; static const SpriteID SPR_GROUND_TEMPCHURCH = 1437; static const SpriteID SPR_CNST1_LARGEOFFICE_04 = 1440; static const SpriteID SPR_CNST2_LARGEOFFICE_04 = 1441; static const SpriteID SPR_BUILD_LARGEOFFICE_04 = 1442; // temperate, sub-arctic, subtropical static const SpriteID SPR_BUILD_LARGEOFFICE_04_SNOW = 4569; // same, with snow /* These are in fact two houses for the same houseID. so V1 and V2 */ static const SpriteID SPR_CNST1_TOWNHOUSE_06_V1 = 1444; static const SpriteID SPR_CNST2_TOWNHOUSE_06_V1 = 1445; static const SpriteID SPR_BUILD_TOWNHOUSE_06_V1 = 1446; // 1st variation static const SpriteID SPR_GRND_TOWNHOUSE_06_V1 = 1447; static const SpriteID SPR_GRND_STADIUM_N = 1479; // stadium ground at north static const SpriteID SPR_GRND_STADIUM_E = 1480; // stadium ground at east static const SpriteID SPR_GRND_STADIUM_W = 1481; // stadium ground at west static const SpriteID SPR_GRND_STADIUM_S = 1482; // stadium ground at south static const SpriteID SPR_CNST1_TOWNHOUSE_06_V2 = 1501; // used as ground, but is stage1 static const SpriteID SPR_CNST1_TOWNHOUSE_06_V2_P = 1502; // pipes extensions for previous static const SpriteID SPR_CNST2_TOWNHOUSE_06_V2_G = 1503; // Ground of cnst stage 2 static const SpriteID SPR_CNST2_TOWNHOUSE_06_V2 = 1504; // real cnst stage 2 static const SpriteID SPR_GRND_TOWNHOUSE_06_V2 = 1505; static const SpriteID SPR_BUILD_TOWNHOUSE_06_V2 = 1506; // 2nd variation static const SpriteID SPR_CNST1_HOTEL_07_NW = 1448; static const SpriteID SPR_CNST2_HOTEL_07_NW = 1449; static const SpriteID SPR_BUILD_HOTEL_07_NW = 1450; static const SpriteID SPR_CNST1_HOTEL_07_SE = 1451; static const SpriteID SPR_CNST2_HOTEL_07_SE = 1452; static const SpriteID SPR_BUILD_HOTEL_07_SE = 1453; static const SpriteID SPR_STATUE_HORSERIDER_09 = 1454; static const SpriteID SPR_FOUNTAIN_0A = 1455; static const SpriteID SPR_PARKSTATUE_0B = 1456; static const SpriteID SPR_PARKALLEY_0C = 1457; static const SpriteID SPR_CNST1_OFFICE_0D = 1458; static const SpriteID SPR_CNST2_OFFICE_0D = 1459; static const SpriteID SPR_BUILD_OFFICE_0D = 1460; static const SpriteID SPR_CNST1_SHOPOFFICE_0E = 1461; static const SpriteID SPR_CNST2_SHOPOFFICE_0E = 1462; static const SpriteID SPR_BUILD_SHOPOFFICE_0E = 1463; static const SpriteID SPR_CNST1_SHOPOFFICE_0F = 1464; static const SpriteID SPR_CNST2_SHOPOFFICE_0F = 1465; static const SpriteID SPR_BUILD_SHOPOFFICE_0F = 1466; static const SpriteID SPR_GRND_HOUSE_TOY1 = 4675; static const SpriteID SPR_GRND_HOUSE_TOY2 = 4676; /* Easter egg/disaster sprites */ static const SpriteID SPR_BLIMP = 3905; // Zeppelin static const SpriteID SPR_BLIMP_CRASHING = 3906; static const SpriteID SPR_BLIMP_CRASHED = 3907; static const SpriteID SPR_UFO_SMALL_SCOUT = 3908; // XCOM - UFO Defense static const SpriteID SPR_UFO_SMALL_SCOUT_DARKER = 3909; static const SpriteID SPR_SUB_SMALL_NE = 3910; // Silent Service static const SpriteID SPR_SUB_SMALL_SE = 3911; static const SpriteID SPR_SUB_SMALL_SW = 3912; static const SpriteID SPR_SUB_SMALL_NW = 3913; static const SpriteID SPR_SUB_LARGE_NE = 3914; static const SpriteID SPR_SUB_LARGE_SE = 3915; static const SpriteID SPR_SUB_LARGE_SW = 3916; static const SpriteID SPR_SUB_LARGE_NW = 3917; static const SpriteID SPR_F_15 = 3918; // F-15 Strike Eagle static const SpriteID SPR_F_15_FIRING = 3919; static const SpriteID SPR_UFO_HARVESTER = 3920; // XCOM - UFO Defense static const SpriteID SPR_XCOM_SKYRANGER = 3921; static const SpriteID SPR_AH_64A = 3922; // Gunship static const SpriteID SPR_AH_64A_FIRING = 3923; /* main_gui.cpp */ static const SpriteID SPR_IMG_TERRAFORM_UP = 694; static const SpriteID SPR_IMG_TERRAFORM_DOWN = 695; static const SpriteID SPR_IMG_DYNAMITE = 703; static const SpriteID SPR_IMG_ROCKS = 4084; static const SpriteID SPR_IMG_DESERT = 4085; static const SpriteID SPR_IMG_TRANSMITTER = 4086; static const SpriteID SPR_IMG_LEVEL_LAND = SPR_OPENTTD_BASE + 91; static const SpriteID SPR_IMG_BUILD_CANAL = SPR_OPENTTD_BASE + 88; static const SpriteID SPR_IMG_BUILD_RIVER = SPR_OPENTTD_BASE + 136; static const SpriteID SPR_IMG_BUILD_LOCK = SPR_CANALS_BASE + 64; static const SpriteID SPR_IMG_PAUSE = 726; static const SpriteID SPR_IMG_FASTFORWARD = SPR_OPENTTD_BASE + 90; static const SpriteID SPR_IMG_SETTINGS = 751; static const SpriteID SPR_IMG_SAVE = 724; static const SpriteID SPR_IMG_SMALLMAP = 708; static const SpriteID SPR_IMG_TOWN = 4077; static const SpriteID SPR_IMG_SUBSIDIES = 679; static const SpriteID SPR_IMG_COMPANY_LIST = 1299; static const SpriteID SPR_IMG_COMPANY_FINANCE = 737; static const SpriteID SPR_IMG_COMPANY_GENERAL = 743; static const SpriteID SPR_IMG_GRAPHS = 745; static const SpriteID SPR_IMG_COMPANY_LEAGUE = 684; static const SpriteID SPR_IMG_SHOW_COUNTOURS = 738; static const SpriteID SPR_IMG_SHOW_VEHICLES = 739; static const SpriteID SPR_IMG_SHOW_ROUTES = 740; static const SpriteID SPR_IMG_INDUSTRY = 741; static const SpriteID SPR_IMG_PLANTTREES = 742; static const SpriteID SPR_IMG_TRAINLIST = 731; static const SpriteID SPR_IMG_TRUCKLIST = 732; static const SpriteID SPR_IMG_SHIPLIST = 733; static const SpriteID SPR_IMG_AIRPLANESLIST = 734; static const SpriteID SPR_IMG_ZOOMIN = 735; static const SpriteID SPR_IMG_ZOOMOUT = 736; static const SpriteID SPR_IMG_BUILDRAIL = 727; static const SpriteID SPR_IMG_BUILDROAD = 728; static const SpriteID SPR_IMG_BUILDWATER = 729; static const SpriteID SPR_IMG_BUILDAIR = 730; static const SpriteID SPR_IMG_LANDSCAPING = 4083; static const SpriteID SPR_IMG_MUSIC = 713; static const SpriteID SPR_IMG_MESSAGES = 680; static const SpriteID SPR_IMG_QUERY = 723; static const SpriteID SPR_IMG_SIGN = 4082; static const SpriteID SPR_IMG_BUY_LAND = 4791; static const SpriteID SPR_IMG_STORY_BOOK = SPR_OPENTTD_BASE + 169; /* OpenTTD in gamescreen */ static const SpriteID SPR_OTTD_O = 4842; static const SpriteID SPR_OTTD_P = 4841; static const SpriteID SPR_OTTD_E = SPR_OPENTTD_BASE + 12; static const SpriteID SPR_OTTD_D = SPR_OPENTTD_BASE + 13; static const SpriteID SPR_OTTD_N = 4839; static const SpriteID SPR_OTTD_T = 4836; /* Letters not used: R,A,S,Y,C (4837, 4838, 4840, 4843, 4844) */ static const SpriteID SPR_HIGHSCORE_CHART_BEGIN = 4804; static const SpriteID SPR_TYCOON_IMG1_BEGIN = 4814; static const SpriteID SPR_TYCOON_IMG2_BEGIN = 4824; /* Industry sprites */ static const SpriteID SPR_IT_SUGAR_MINE_SIEVE = 4775; static const SpriteID SPR_IT_SUGAR_MINE_CLOUDS = 4784; static const SpriteID SPR_IT_SUGAR_MINE_PILE = 4780; static const SpriteID SPR_IT_TOFFEE_QUARRY_TOFFEE = 4766; static const SpriteID SPR_IT_TOFFEE_QUARRY_SHOVEL = 4767; static const SpriteID SPR_IT_BUBBLE_GENERATOR_SPRING = 4746; static const SpriteID SPR_IT_BUBBLE_GENERATOR_BUBBLE = 4747; static const SpriteID SPR_IT_TOY_FACTORY_STAMP_HOLDER = 4717; static const SpriteID SPR_IT_TOY_FACTORY_STAMP = 4718; static const SpriteID SPR_IT_TOY_FACTORY_CLAY = 4719; static const SpriteID SPR_IT_TOY_FACTORY_ROBOT = 4720; static const SpriteID SPR_IT_POWER_PLANT_TRANSFORMERS = 2054; /* small icons of cargo available in station waiting*/ static const SpriteID SPR_CARGO_PASSENGER = 4297; static const SpriteID SPR_CARGO_COAL = 4298; static const SpriteID SPR_CARGO_MAIL = 4299; static const SpriteID SPR_CARGO_OIL = 4300; static const SpriteID SPR_CARGO_LIVESTOCK = 4301; static const SpriteID SPR_CARGO_GOODS = 4302; static const SpriteID SPR_CARGO_GRAIN = 4303; static const SpriteID SPR_CARGO_WOOD = 4304; static const SpriteID SPR_CARGO_IRON_ORE = 4305; static const SpriteID SPR_CARGO_STEEL = 4306; static const SpriteID SPR_CARGO_VALUES_GOLD = 4307; // shared between temperate and arctic static const SpriteID SPR_CARGO_FRUIT = 4308; static const SpriteID SPR_CARGO_COPPER_ORE = 4309; static const SpriteID SPR_CARGO_WATERCOLA = 4310; // shared between desert and toyland static const SpriteID SPR_CARGO_DIAMONDS = 4311; static const SpriteID SPR_CARGO_FOOD = 4312; static const SpriteID SPR_CARGO_PAPER = 4313; static const SpriteID SPR_CARGO_RUBBER = 4314; static const SpriteID SPR_CARGO_CANDY = 4315; static const SpriteID SPR_CARGO_SUGAR = 4316; static const SpriteID SPR_CARGO_TOYS = 4317; static const SpriteID SPR_CARGO_COTTONCANDY = 4318; static const SpriteID SPR_CARGO_FIZZYDRINK = 4319; static const SpriteID SPR_CARGO_TOFFEE = 4320; static const SpriteID SPR_CARGO_BUBBLES = 4321; static const SpriteID SPR_CARGO_PLASTIC = 4322; static const SpriteID SPR_CARGO_BATTERIES = 4323; /* Effect vehicles */ static const SpriteID SPR_BULLDOZER_NE = 1416; static const SpriteID SPR_BULLDOZER_SE = 1417; static const SpriteID SPR_BULLDOZER_SW = 1418; static const SpriteID SPR_BULLDOZER_NW = 1419; static const SpriteID SPR_SMOKE_0 = 2040; static const SpriteID SPR_SMOKE_1 = 2041; static const SpriteID SPR_SMOKE_2 = 2042; static const SpriteID SPR_SMOKE_3 = 2043; static const SpriteID SPR_SMOKE_4 = 2044; static const SpriteID SPR_DIESEL_SMOKE_0 = 3073; static const SpriteID SPR_DIESEL_SMOKE_1 = 3074; static const SpriteID SPR_DIESEL_SMOKE_2 = 3075; static const SpriteID SPR_DIESEL_SMOKE_3 = 3076; static const SpriteID SPR_DIESEL_SMOKE_4 = 3077; static const SpriteID SPR_DIESEL_SMOKE_5 = 3078; static const SpriteID SPR_STEAM_SMOKE_0 = 3079; static const SpriteID SPR_STEAM_SMOKE_1 = 3080; static const SpriteID SPR_STEAM_SMOKE_2 = 3081; static const SpriteID SPR_STEAM_SMOKE_3 = 3082; static const SpriteID SPR_STEAM_SMOKE_4 = 3083; static const SpriteID SPR_ELECTRIC_SPARK_0 = 3084; static const SpriteID SPR_ELECTRIC_SPARK_1 = 3085; static const SpriteID SPR_ELECTRIC_SPARK_2 = 3086; static const SpriteID SPR_ELECTRIC_SPARK_3 = 3087; static const SpriteID SPR_ELECTRIC_SPARK_4 = 3088; static const SpriteID SPR_ELECTRIC_SPARK_5 = 3089; static const SpriteID SPR_CHIMNEY_SMOKE_0 = 3701; static const SpriteID SPR_CHIMNEY_SMOKE_1 = 3702; static const SpriteID SPR_CHIMNEY_SMOKE_2 = 3703; static const SpriteID SPR_CHIMNEY_SMOKE_3 = 3704; static const SpriteID SPR_CHIMNEY_SMOKE_4 = 3705; static const SpriteID SPR_CHIMNEY_SMOKE_5 = 3706; static const SpriteID SPR_CHIMNEY_SMOKE_6 = 3707; static const SpriteID SPR_CHIMNEY_SMOKE_7 = 3708; static const SpriteID SPR_EXPLOSION_LARGE_0 = 3709; static const SpriteID SPR_EXPLOSION_LARGE_1 = 3710; static const SpriteID SPR_EXPLOSION_LARGE_2 = 3711; static const SpriteID SPR_EXPLOSION_LARGE_3 = 3712; static const SpriteID SPR_EXPLOSION_LARGE_4 = 3713; static const SpriteID SPR_EXPLOSION_LARGE_5 = 3714; static const SpriteID SPR_EXPLOSION_LARGE_6 = 3715; static const SpriteID SPR_EXPLOSION_LARGE_7 = 3716; static const SpriteID SPR_EXPLOSION_LARGE_8 = 3717; static const SpriteID SPR_EXPLOSION_LARGE_9 = 3718; static const SpriteID SPR_EXPLOSION_LARGE_A = 3719; static const SpriteID SPR_EXPLOSION_LARGE_B = 3720; static const SpriteID SPR_EXPLOSION_LARGE_C = 3721; static const SpriteID SPR_EXPLOSION_LARGE_D = 3722; static const SpriteID SPR_EXPLOSION_LARGE_E = 3723; static const SpriteID SPR_EXPLOSION_LARGE_F = 3724; static const SpriteID SPR_EXPLOSION_SMALL_0 = 3725; static const SpriteID SPR_EXPLOSION_SMALL_1 = 3726; static const SpriteID SPR_EXPLOSION_SMALL_2 = 3727; static const SpriteID SPR_EXPLOSION_SMALL_3 = 3728; static const SpriteID SPR_EXPLOSION_SMALL_4 = 3729; static const SpriteID SPR_EXPLOSION_SMALL_5 = 3730; static const SpriteID SPR_EXPLOSION_SMALL_6 = 3731; static const SpriteID SPR_EXPLOSION_SMALL_7 = 3732; static const SpriteID SPR_EXPLOSION_SMALL_8 = 3733; static const SpriteID SPR_EXPLOSION_SMALL_9 = 3734; static const SpriteID SPR_EXPLOSION_SMALL_A = 3735; static const SpriteID SPR_EXPLOSION_SMALL_B = 3736; static const SpriteID SPR_BREAKDOWN_SMOKE_0 = 3737; static const SpriteID SPR_BREAKDOWN_SMOKE_1 = 3738; static const SpriteID SPR_BREAKDOWN_SMOKE_2 = 3739; static const SpriteID SPR_BREAKDOWN_SMOKE_3 = 3740; static const SpriteID SPR_BUBBLE_0 = 4748; static const SpriteID SPR_BUBBLE_1 = 4749; static const SpriteID SPR_BUBBLE_2 = 4750; static const SpriteID SPR_BUBBLE_GENERATE_0 = 4751; static const SpriteID SPR_BUBBLE_GENERATE_1 = 4752; static const SpriteID SPR_BUBBLE_GENERATE_2 = 4753; static const SpriteID SPR_BUBBLE_GENERATE_3 = 4754; static const SpriteID SPR_BUBBLE_BURST_0 = 4755; static const SpriteID SPR_BUBBLE_BURST_1 = 4756; static const SpriteID SPR_BUBBLE_BURST_2 = 4757; static const SpriteID SPR_BUBBLE_ABSORB_0 = 4758; static const SpriteID SPR_BUBBLE_ABSORB_1 = 4759; static const SpriteID SPR_BUBBLE_ABSORB_2 = 4760; static const SpriteID SPR_BUBBLE_ABSORB_3 = 4761; static const SpriteID SPR_BUBBLE_ABSORB_4 = 4762; /* Electrified rail build menu */ static const SpriteID SPR_BUILD_NS_ELRAIL = SPR_ELRAIL_BASE + 36; static const SpriteID SPR_BUILD_X_ELRAIL = SPR_ELRAIL_BASE + 37; static const SpriteID SPR_BUILD_EW_ELRAIL = SPR_ELRAIL_BASE + 38; static const SpriteID SPR_BUILD_Y_ELRAIL = SPR_ELRAIL_BASE + 39; static const SpriteID SPR_BUILD_TUNNEL_ELRAIL = SPR_ELRAIL_BASE + 44; /* airport_gui.cpp */ static const SpriteID SPR_IMG_AIRPORT = 744; /* dock_gui.cpp */ static const SpriteID SPR_IMG_SHIP_DEPOT = 748; static const SpriteID SPR_IMG_SHIP_DOCK = 746; static const SpriteID SPR_IMG_BUOY = 693; static const SpriteID SPR_IMG_AQUEDUCT = SPR_OPENTTD_BASE + 145; /* music_gui.cpp */ static const SpriteID SPR_IMG_SKIP_TO_PREV = 709; static const SpriteID SPR_IMG_SKIP_TO_NEXT = 710; static const SpriteID SPR_IMG_STOP_MUSIC = 711; static const SpriteID SPR_IMG_PLAY_MUSIC = 712; /* road_gui.cpp */ static const SpriteID SPR_IMG_ROAD_Y_DIR = 1309; static const SpriteID SPR_IMG_ROAD_X_DIR = 1310; static const SpriteID SPR_IMG_AUTOROAD = SPR_OPENTTD_BASE + 82; static const SpriteID SPR_IMG_ROAD_DEPOT = 1295; static const SpriteID SPR_IMG_BUS_STATION = 749; static const SpriteID SPR_IMG_TRUCK_BAY = 750; static const SpriteID SPR_IMG_BRIDGE = 2594; static const SpriteID SPR_IMG_ROAD_TUNNEL = 2429; static const SpriteID SPR_IMG_REMOVE = 714; static const SpriteID SPR_IMG_ROAD_ONE_WAY = SPR_OPENTTD_BASE + 134; static const SpriteID SPR_IMG_TRAMWAY_Y_DIR = SPR_TRAMWAY_BASE + 0; static const SpriteID SPR_IMG_TRAMWAY_X_DIR = SPR_TRAMWAY_BASE + 1; static const SpriteID SPR_IMG_AUTOTRAM = SPR_OPENTTD_BASE + 84; /* rail_gui.cpp */ static const SpriteID SPR_IMG_RAIL_NS = 1251; static const SpriteID SPR_IMG_RAIL_NE = 1252; static const SpriteID SPR_IMG_RAIL_EW = 1253; static const SpriteID SPR_IMG_RAIL_NW = 1254; static const SpriteID SPR_IMG_AUTORAIL = SPR_OPENTTD_BASE + 53; static const SpriteID SPR_IMG_AUTOELRAIL = SPR_OPENTTD_BASE + 57; static const SpriteID SPR_IMG_AUTOMONO = SPR_OPENTTD_BASE + 63; static const SpriteID SPR_IMG_AUTOMAGLEV = SPR_OPENTTD_BASE + 69; static const SpriteID SPR_IMG_WAYPOINT = SPR_OPENTTD_BASE + 76; static const SpriteID SPR_IMG_DEPOT_RAIL = 1294; static const SpriteID SPR_IMG_DEPOT_ELRAIL = SPR_OPENTTD_BASE + 61; static const SpriteID SPR_IMG_DEPOT_MONO = SPR_OPENTTD_BASE + 67; static const SpriteID SPR_IMG_DEPOT_MAGLEV = SPR_OPENTTD_BASE + 73; static const SpriteID SPR_IMG_RAIL_STATION = 1298; static const SpriteID SPR_IMG_RAIL_SIGNALS = 1291; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_NORM = 1287; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_ENTRY = SPR_SIGNALS_BASE + 12; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_EXIT = SPR_SIGNALS_BASE + 28; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_COMBO = SPR_SIGNALS_BASE + 44; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PBS = SPR_SIGNALS_BASE + 124; static const SpriteID SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY = SPR_SIGNALS_BASE + 140; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_NORM = SPR_SIGNALS_BASE + 60; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_ENTRY = SPR_SIGNALS_BASE + 76; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_EXIT = SPR_SIGNALS_BASE + 92; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_COMBO = SPR_SIGNALS_BASE + 108; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PBS = SPR_SIGNALS_BASE + 188; static const SpriteID SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY= SPR_SIGNALS_BASE + 204; static const SpriteID SPR_IMG_SIGNAL_CONVERT = SPR_OPENTTD_BASE + 135; static const SpriteID SPR_IMG_TUNNEL_RAIL = 2430; static const SpriteID SPR_IMG_TUNNEL_MONO = 2431; static const SpriteID SPR_IMG_TUNNEL_MAGLEV = 2432; static const SpriteID SPR_IMG_CONVERT_RAIL = SPR_OPENTTD_BASE + 55; static const SpriteID SPR_IMG_CONVERT_ELRAIL = SPR_OPENTTD_BASE + 59; static const SpriteID SPR_IMG_CONVERT_MONO = SPR_OPENTTD_BASE + 65; static const SpriteID SPR_IMG_CONVERT_MAGLEV = SPR_OPENTTD_BASE + 71; /* story_gui.cpp */ static const SpriteID SPR_IMG_VIEW_LOCATION = SPR_OPENTTD_BASE + 170; static const SpriteID SPR_IMG_GOAL = SPR_OPENTTD_BASE + 171; static const SpriteID SPR_IMG_GOAL_COMPLETED = SPR_OPENTTD_BASE + 172; static const SpriteID SPR_IMG_GOAL_BROKEN_REF= SPR_OPENTTD_BASE + 173; /* intro_gui.cpp, genworld_gui.cpp */ static const SpriteID SPR_SELECT_TEMPERATE = 4882; static const SpriteID SPR_SELECT_TEMPERATE_PUSHED = 4883; static const SpriteID SPR_SELECT_SUB_ARCTIC = 4884; static const SpriteID SPR_SELECT_SUB_ARCTIC_PUSHED = 4885; static const SpriteID SPR_SELECT_SUB_TROPICAL = 4886; static const SpriteID SPR_SELECT_SUB_TROPICAL_PUSHED = 4887; static const SpriteID SPR_SELECT_TOYLAND = 4888; static const SpriteID SPR_SELECT_TOYLAND_PUSHED = 4889; /** Cursor sprite numbers */ /* Terraform * Cursors */ static const CursorID SPR_CURSOR_MOUSE = 0; static const CursorID SPR_CURSOR_ZZZ = 1; static const CursorID SPR_CURSOR_BUOY = 702; static const CursorID SPR_CURSOR_QUERY = 719; static const CursorID SPR_CURSOR_HQ = 720; static const CursorID SPR_CURSOR_SHIP_DEPOT = 721; static const CursorID SPR_CURSOR_SIGN = 722; static const CursorID SPR_CURSOR_TREE = 2010; static const CursorID SPR_CURSOR_BUY_LAND = 4792; static const CursorID SPR_CURSOR_LEVEL_LAND = SPR_OPENTTD_BASE + 92; static const CursorID SPR_CURSOR_TOWN = 4080; static const CursorID SPR_CURSOR_INDUSTRY = 4081; static const CursorID SPR_CURSOR_ROCKY_AREA = 4087; static const CursorID SPR_CURSOR_DESERT = 4088; static const CursorID SPR_CURSOR_TRANSMITTER = 4089; /* airport cursors */ static const CursorID SPR_CURSOR_AIRPORT = 2724; /* dock cursors */ static const CursorID SPR_CURSOR_DOCK = 3668; static const CursorID SPR_CURSOR_CANAL = SPR_OPENTTD_BASE + 89; static const CursorID SPR_CURSOR_LOCK = SPR_OPENTTD_BASE + 87; static const CursorID SPR_CURSOR_RIVER = SPR_OPENTTD_BASE + 137; static const CursorID SPR_CURSOR_AQUEDUCT = SPR_OPENTTD_BASE + 146; /* shared road & rail cursors */ static const CursorID SPR_CURSOR_BRIDGE = 2593; /* rail cursors */ static const CursorID SPR_CURSOR_NS_TRACK = 1263; static const CursorID SPR_CURSOR_SWNE_TRACK = 1264; static const CursorID SPR_CURSOR_EW_TRACK = 1265; static const CursorID SPR_CURSOR_NWSE_TRACK = 1266; static const CursorID SPR_CURSOR_NS_MONO = 1267; static const CursorID SPR_CURSOR_SWNE_MONO = 1268; static const CursorID SPR_CURSOR_EW_MONO = 1269; static const CursorID SPR_CURSOR_NWSE_MONO = 1270; static const CursorID SPR_CURSOR_NS_MAGLEV = 1271; static const CursorID SPR_CURSOR_SWNE_MAGLEV = 1272; static const CursorID SPR_CURSOR_EW_MAGLEV = 1273; static const CursorID SPR_CURSOR_NWSE_MAGLEV = 1274; static const CursorID SPR_CURSOR_NS_ELRAIL = SPR_ELRAIL_BASE + 40; static const CursorID SPR_CURSOR_SWNE_ELRAIL = SPR_ELRAIL_BASE + 41; static const CursorID SPR_CURSOR_EW_ELRAIL = SPR_ELRAIL_BASE + 42; static const CursorID SPR_CURSOR_NWSE_ELRAIL = SPR_ELRAIL_BASE + 43; static const CursorID SPR_CURSOR_RAIL_STATION = 1300; static const CursorID SPR_CURSOR_TUNNEL_RAIL = 2434; static const CursorID SPR_CURSOR_TUNNEL_ELRAIL = SPR_ELRAIL_BASE + 45; static const CursorID SPR_CURSOR_TUNNEL_MONO = 2435; static const CursorID SPR_CURSOR_TUNNEL_MAGLEV = 2436; static const CursorID SPR_CURSOR_AUTORAIL = SPR_OPENTTD_BASE + 54; static const CursorID SPR_CURSOR_AUTOELRAIL = SPR_OPENTTD_BASE + 58; static const CursorID SPR_CURSOR_AUTOMONO = SPR_OPENTTD_BASE + 64; static const CursorID SPR_CURSOR_AUTOMAGLEV = SPR_OPENTTD_BASE + 70; static const CursorID SPR_CURSOR_WAYPOINT = SPR_OPENTTD_BASE + 77; static const CursorID SPR_CURSOR_RAIL_DEPOT = 1296; static const CursorID SPR_CURSOR_ELRAIL_DEPOT = SPR_OPENTTD_BASE + 62; static const CursorID SPR_CURSOR_MONO_DEPOT = SPR_OPENTTD_BASE + 68; static const CursorID SPR_CURSOR_MAGLEV_DEPOT = SPR_OPENTTD_BASE + 74; static const CursorID SPR_CURSOR_CONVERT_RAIL = SPR_OPENTTD_BASE + 56; static const CursorID SPR_CURSOR_CONVERT_ELRAIL = SPR_OPENTTD_BASE + 60; static const CursorID SPR_CURSOR_CONVERT_MONO = SPR_OPENTTD_BASE + 66; static const CursorID SPR_CURSOR_CONVERT_MAGLEV = SPR_OPENTTD_BASE + 72; /* road cursors */ static const CursorID SPR_CURSOR_ROAD_NESW = 1311; static const CursorID SPR_CURSOR_ROAD_NWSE = 1312; static const CursorID SPR_CURSOR_AUTOROAD = SPR_OPENTTD_BASE + 83; static const CursorID SPR_CURSOR_TRAMWAY_NESW = SPR_TRAMWAY_BASE + 2; static const CursorID SPR_CURSOR_TRAMWAY_NWSE = SPR_TRAMWAY_BASE + 3; static const CursorID SPR_CURSOR_AUTOTRAM = SPR_OPENTTD_BASE + 85; static const CursorID SPR_CURSOR_ROAD_DEPOT = 1297; static const CursorID SPR_CURSOR_BUS_STATION = 2725; static const CursorID SPR_CURSOR_TRUCK_STATION = 2726; static const CursorID SPR_CURSOR_ROAD_TUNNEL = 2433; static const CursorID SPR_CURSOR_CLONE_TRAIN = SPR_OPENTTD_BASE + 110; static const CursorID SPR_CURSOR_CLONE_ROADVEH = SPR_OPENTTD_BASE + 111; static const CursorID SPR_CURSOR_CLONE_SHIP = SPR_OPENTTD_BASE + 112; static const CursorID SPR_CURSOR_CLONE_AIRPLANE = SPR_OPENTTD_BASE + 113; /** Animation macro in table/animcursors.h (_animcursors[]) */ static const CursorID SPR_CURSOR_DEMOLISH_FIRST = 704; static const CursorID SPR_CURSOR_DEMOLISH_1 = 705; static const CursorID SPR_CURSOR_DEMOLISH_2 = 706; static const CursorID SPR_CURSOR_DEMOLISH_LAST = 707; static const CursorID SPR_CURSOR_LOWERLAND_FIRST = 699; static const CursorID SPR_CURSOR_LOWERLAND_1 = 700; static const CursorID SPR_CURSOR_LOWERLAND_LAST = 701; static const CursorID SPR_CURSOR_RAISELAND_FIRST = 696; static const CursorID SPR_CURSOR_RAISELAND_1 = 697; static const CursorID SPR_CURSOR_RAISELAND_LAST = 698; static const CursorID SPR_CURSOR_PICKSTATION_FIRST = 716; static const CursorID SPR_CURSOR_PICKSTATION_1 = 717; static const CursorID SPR_CURSOR_PICKSTATION_LAST = 718; static const CursorID SPR_CURSOR_BUILDSIGNALS_FIRST = 1292; static const CursorID SPR_CURSOR_BUILDSIGNALS_LAST = 1293; /** Flag for saying a cursor sprite is an animated cursor. */ static const CursorID ANIMCURSOR_FLAG = 1U << 31; static const CursorID ANIMCURSOR_DEMOLISH = ANIMCURSOR_FLAG | 0; ///< 704 - 707 - demolish dynamite static const CursorID ANIMCURSOR_LOWERLAND = ANIMCURSOR_FLAG | 1; ///< 699 - 701 - lower land tool static const CursorID ANIMCURSOR_RAISELAND = ANIMCURSOR_FLAG | 2; ///< 696 - 698 - raise land tool static const CursorID ANIMCURSOR_PICKSTATION = ANIMCURSOR_FLAG | 3; ///< 716 - 718 - goto-order icon static const CursorID ANIMCURSOR_BUILDSIGNALS = ANIMCURSOR_FLAG | 4; ///< 1292 - 1293 - build signal /** * Bitmask setup. For the graphics system, 32 bits are used to define * the sprite to be displayed. This variable contains various information:

*

  • SPRITE_WIDTH is the number of bits used for the actual sprite to be displayed. * This always starts at bit 0.
  • *
  • TRANSPARENT_BIT is the bit number which toggles sprite transparency
  • *
  • RECOLOUR_BIT toggles the recolouring system
  • *
  • PALETTE_SPRITE_WIDTH and PALETTE_SPRITE_START determine the position and number of * bits used for the recolouring process. For transparency, it must be 0x322.
*/ enum SpriteSetup { /* These bits are applied to sprite ID */ TRANSPARENT_BIT = 31, ///< toggles transparency in the sprite RECOLOUR_BIT = 30, ///< toggles recolouring in the sprite CUSTOM_BIT = 29, OPAQUE_BIT = 28, /* This bit is applied to palette ID */ PALETTE_TEXT_RECOLOUR = 31, ///< Set if palette is actually a magic text recolour PALETTE_WIDTH = 24, ///< number of bits of the sprite containing the recolour palette SPRITE_WIDTH = 24, ///< number of bits for the sprite number }; /** * these masks change the colours of the palette for a sprite. * Apart from this bit, a sprite number is needed to define * the palette used for recolouring. This palette is stored * in the bits marked by PALETTE_SPRITE_MASK. * @note Do not modify this enum. Alter SpriteSetup instead * @see SpriteSetup */ enum Modifiers { SPRITE_MODIFIER_CUSTOM_SPRITE = CUSTOM_BIT, ///< Set when a sprite originates from an Action 1 SPRITE_MODIFIER_OPAQUE = OPAQUE_BIT, ///< Set when a sprite must not ever be displayed transparently PALETTE_MODIFIER_TRANSPARENT = TRANSPARENT_BIT, ///< when a sprite is to be displayed transparently, this bit needs to be set. PALETTE_MODIFIER_COLOUR = RECOLOUR_BIT, ///< this bit is set when a recolouring process is in action }; /** * Masks needed for sprite operations. * @note Do not modify this enum. Alter SpriteSetup instead * @see SpriteSetup */ enum SpriteMasks { MAX_SPRITES = 1 << SPRITE_WIDTH, ///< Maximum number of sprites that can be loaded at a given time SPRITE_MASK = MAX_SPRITES - 1, ///< The mask to for the main sprite MAX_PALETTES = 1 << PALETTE_WIDTH, PALETTE_MASK = MAX_PALETTES - 1, ///< The mask for the auxiliary sprite (the one that takes care of recolouring) }; assert_compile( (1 << TRANSPARENT_BIT & SPRITE_MASK) == 0 ); assert_compile( (1 << RECOLOUR_BIT & SPRITE_MASK) == 0 ); assert_compile( TRANSPARENT_BIT != RECOLOUR_BIT ); assert_compile( (1 << TRANSPARENT_BIT & PALETTE_MASK) == 0); assert_compile( (1 << RECOLOUR_BIT & PALETTE_MASK) == 0 ); static const PaletteID PAL_NONE = 0; static const PaletteID PALETTE_TILE_RED_PULSATING = 771; ///< pulsating red tile drawn if you try to build a wrong tunnel or raise/lower land where it is not possible static const PaletteID PALETTE_SEL_TILE_RED = 772; ///< makes a square red. is used when removing rails or other stuff static const PaletteID PALETTE_SEL_TILE_BLUE = 773; ///< This draws a blueish square (catchment areas for example) /* Company re-colour sprites */ static const PaletteID PALETTE_RECOLOUR_START = 775; ///< First recolour sprite for company colours static const PaletteID PALETTE_TO_DARK_BLUE = 775; static const PaletteID PALETTE_TO_PALE_GREEN = 776; static const PaletteID PALETTE_TO_PINK = 777; static const PaletteID PALETTE_TO_YELLOW = 778; static const PaletteID PALETTE_TO_RED = 779; static const PaletteID PALETTE_TO_LIGHT_BLUE = 780; static const PaletteID PALETTE_TO_GREEN = 781; static const PaletteID PALETTE_TO_DARK_GREEN = 782; static const PaletteID PALETTE_TO_BLUE = 783; static const PaletteID PALETTE_TO_CREAM = 784; /* maybe don't use as company colour because it doesn't display in the graphs? */ static const PaletteID PALETTE_TO_MAUVE = 785; static const PaletteID PALETTE_TO_PURPLE = 786; static const PaletteID PALETTE_TO_ORANGE = 787; static const PaletteID PALETTE_TO_BROWN = 788; static const PaletteID PALETTE_TO_GREY = 789; static const PaletteID PALETTE_TO_WHITE = 790; static const PaletteID PALETTE_TO_BARE_LAND = 791; ///< sets colour to bare land stuff for rail, road and crossings /* recolour sprites 792-794 are not used */ static const PaletteID PALETTE_TO_STRUCT_BLUE = 795; ///< sets bridge or structure to blue (e.g. some town houses) static const PaletteID PALETTE_TO_STRUCT_BROWN = 796; ///< sets bridge or structure to brown (e.g. cantilever bridge) static const PaletteID PALETTE_TO_STRUCT_WHITE = 797; ///< sets bridge or structure to white (e.g. some town houses) static const PaletteID PALETTE_TO_STRUCT_RED = 798; ///< sets bridge or structure to red (e.g. concrete and cantilever bridge) static const PaletteID PALETTE_TO_STRUCT_GREEN = 799; ///< sets bridge or structure to green (e.g. bridge) static const PaletteID PALETTE_TO_STRUCT_CONCRETE = 800; ///< Sets the suspension bridge to concrete, also other structures use it static const PaletteID PALETTE_TO_STRUCT_YELLOW = 801; ///< Sets the bridge colour to yellow (suspension and tubular) static const PaletteID PALETTE_TO_TRANSPARENT = 802; ///< This sets the sprite to transparent static const PaletteID PALETTE_NEWSPAPER = 803; ///< Recolour sprite for newspaper-greying. static const PaletteID PALETTE_CRASH = 804; ///< Recolour sprite greying of crashed vehicles. /* Two recolourings only used by the church */ static const PaletteID PALETTE_CHURCH_RED = 1438; ///< Recolour sprite for reddish churches static const PaletteID PALETTE_CHURCH_CREAM = 1439; ///< Recolour sprite for white churches static const PaletteID PALETTE_ALL_BLACK = SPR_PALETTE_BASE; ///< Exchange any color by black, needed for painting fictive tiles outside map #endif /* SPRITES_H */ openttd-1.5.3/src/table/roadveh_movement.h0000644000000000000000000005106612627373436017311 0ustar rootroot/* $Id: roadveh_movement.h 21263 2010-11-20 09:09:57Z rubidium $ */ /* * 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 table/roadveh_movement.h Data about how a road vehicle must drive on a tile */ static const RoadDriveEntry _roadveh_drive_data_0[] = { {15, 5}, {14, 5}, {13, 5}, {12, 5}, {11, 5}, {10, 5}, { 9, 5}, { 8, 5}, { 7, 5}, { 6, 5}, { 5, 5}, { 4, 5}, { 3, 5}, { 2, 5}, { 1, 5}, { 0, 5}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_1[] = { {5, 0}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {5, 6}, {5, 7}, {5, 8}, {5, 9}, {5, 10}, {5, 11}, {5, 12}, {5, 13}, {5, 14}, {5, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_drive_data_2[] = { {5, 0}, {5, 1}, {5, 2}, {4, 3}, {3, 4}, {2, 5}, {1, 5}, {0, 5}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_3[] = { {15, 5}, {14, 5}, {13, 5}, {12, 5}, {11, 5}, {10, 5}, { 9, 6}, { 8, 7}, { 7, 8}, { 6, 9}, { 5, 10}, { 5, 11}, { 5, 12}, { 5, 13}, { 5, 14}, { 5, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_drive_data_4[] = { { 5, 0}, { 5, 1}, { 5, 2}, { 5, 3}, { 5, 4}, { 5, 5}, { 6, 6}, { 7, 7}, { 8, 8}, { 9, 9}, {10, 9}, {11, 9}, {12, 9}, {13, 9}, {14, 9}, {15, 9}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_5[] = { {0, 9}, {1, 9}, {2, 9}, {3, 10}, {4, 11}, {5, 12}, {5, 13}, {5, 14}, {5, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_drive_data_6[] = { {0, 6}, {0, 7}, {0, 8}, {0, 9}, {RDE_TURNED | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_7[] = { {6, 15}, {7, 15}, {8, 15}, {9, 15}, {RDE_TURNED | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_8[] = { { 0, 9}, { 1, 9}, { 2, 9}, { 3, 9}, { 4, 9}, { 5, 9}, { 6, 9}, { 7, 9}, { 8, 9}, { 9, 9}, {10, 9}, {11, 9}, {12, 9}, {13, 9}, {14, 9}, {15, 9}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_9[] = { {9, 15}, {9, 14}, {9, 13}, {9, 12}, {9, 11}, {9, 10}, {9, 9}, {9, 8}, {9, 7}, {9, 6}, {9, 5}, {9, 4}, {9, 3}, {9, 2}, {9, 1}, {9, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_10[] = { {0, 9}, {1, 9}, {2, 9}, {3, 9}, {4, 9}, {5, 9}, {6, 8}, {7, 7}, {8, 6}, {9, 5}, {9, 4}, {9, 3}, {9, 2}, {9, 1}, {9, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_11[] = { { 9, 15}, { 9, 14}, { 9, 13}, {10, 12}, {11, 11}, {12, 10}, {13, 9}, {14, 9}, {15, 9}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_12[] = { {15, 5}, {14, 5}, {13, 5}, {12, 4}, {11, 3}, {10, 2}, { 9, 1}, { 9, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_13[] = { {9, 15}, {9, 14}, {9, 13}, {9, 12}, {9, 11}, {9, 10}, {8, 9}, {7, 8}, {6, 7}, {5, 6}, {4, 5}, {3, 5}, {2, 5}, {1, 5}, {0, 5}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_14[] = { {15, 8}, {15, 7}, {15, 6}, {15, 5}, {RDE_TURNED | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_15[] = { {8, 0}, {7, 0}, {6, 0}, {5, 0}, {RDE_TURNED | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_drive_data_16[] = { {15, 9}, {14, 9}, {13, 9}, {12, 9}, {11, 9}, {10, 9}, { 9, 9}, { 8, 9}, { 7, 9}, { 6, 9}, { 5, 9}, { 4, 9}, { 3, 9}, { 2, 9}, { 1, 9}, { 0, 9}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_17[] = { {9, 0}, {9, 1}, {9, 2}, {9, 3}, {9, 4}, {9, 5}, {9, 6}, {9, 7}, {9, 8}, {9, 9}, {9, 10}, {9, 11}, {9, 12}, {9, 13}, {9, 14}, {9, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_drive_data_18[] = { {9, 0}, {9, 1}, {9, 2}, {9, 3}, {9, 4}, {9, 5}, {8, 6}, {7, 7}, {6, 8}, {5, 9}, {4, 9}, {3, 9}, {2, 9}, {1, 9}, {0, 9}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_19[] = { {15, 9}, {14, 9}, {13, 9}, {12, 10}, {11, 11}, {10, 12}, { 9, 13}, { 9, 14}, { 9, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_drive_data_20[] = { { 9, 0}, { 9, 1}, {10, 2}, {11, 3}, {12, 4}, {13, 5}, {14, 5}, {15, 5}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_21[] = { {0, 5}, {1, 5}, {2, 5}, {3, 5}, {4, 5}, {5, 6}, {6, 7}, {7, 8}, {8, 9}, {9, 10}, {9, 11}, {9, 12}, {9, 13}, {9, 14}, {9, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_drive_data_22[] = { {0, 8}, {0, 7}, {0, 6}, {0, 5}, {RDE_TURNED | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_23[] = { {8, 15}, {7, 15}, {6, 15}, {5, 15}, {RDE_TURNED | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_24[] = { { 0, 5}, { 1, 5}, { 2, 5}, { 3, 5}, { 4, 5}, { 5, 5}, { 6, 5}, { 7, 5}, { 8, 5}, { 9, 5}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_25[] = { {5, 15}, {5, 14}, {5, 13}, {5, 12}, {5, 11}, {5, 10}, {5, 9}, {5, 8}, {5, 7}, {5, 6}, {5, 5}, {5, 4}, {5, 3}, {5, 2}, {5, 1}, {5, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_26[] = { {0, 5}, {1, 5}, {2, 5}, {3, 4}, {4, 3}, {5, 2}, {5, 1}, {5, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_27[] = { { 5, 15}, { 5, 14}, { 5, 13}, { 5, 12}, { 5, 11}, { 5, 10}, { 6, 9}, { 7, 8}, { 8, 7}, { 9, 6}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_drive_data_28[] = { {15, 9}, {14, 9}, {13, 9}, {12, 9}, {11, 9}, {10, 9}, { 9, 9}, { 8, 8}, { 7, 7}, { 6, 6}, { 5, 5}, { 5, 4}, { 5, 3}, { 5, 2}, { 5, 1}, { 5, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_drive_data_29[] = { {5, 15}, {5, 14}, {5, 13}, {5, 12}, {4, 11}, {3, 10}, {2, 9}, {1, 9}, {0, 9}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_30[] = { {15, 6}, {15, 7}, {15, 8}, {15, 9}, {RDE_TURNED | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_drive_data_31[] = { {6, 0}, {7, 0}, {8, 0}, {9, 0}, {RDE_TURNED | DIAGDIR_SE, 0} }; static const RoadDriveEntry _rv_station_left_sw_far[] = { {15, 5}, {14, 5}, {13, 6}, {13, 7}, {13, 8}, {13, 9}, {13, 10}, {13, 11}, {12, 12}, {11, 12}, {10, 12}, { 9, 12}, { 8, 12}, { 7, 12}, { 6, 12}, { 5, 11}, { 5, 10}, { 5, 9}, { 5, 8}, { 5, 7}, { 5, 6}, { 5, 7}, { 5, 8}, { 5, 9}, { 5, 10}, { 5, 11}, { 6, 12}, { 7, 12}, { 8, 12}, { 9, 12}, {10, 12}, {11, 12}, {12, 12}, {13, 11}, {13, 10}, {14, 9}, {15, 9}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _rv_station_left_nw_far[] = { { 5, 0}, { 5, 1}, { 6, 2}, { 7, 2}, { 8, 2}, { 9, 2}, {10, 2}, {11, 2}, {12, 3}, {12, 4}, {12, 5}, {12, 6}, {12, 7}, {12, 8}, {12, 9}, {11, 10}, {10, 10}, { 9, 10}, { 8, 10}, { 7, 10}, { 6, 10}, { 7, 10}, { 8, 10}, { 9, 10}, {10, 10}, {11, 10}, {12, 9}, {12, 8}, {12, 7}, {12, 6}, {12, 5}, {12, 4}, {12, 3}, {11, 2}, {10, 2}, { 9, 1}, { 9, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _rv_station_left_sw_near[] = { {15, 5}, {14, 5}, {13, 6}, {13, 7}, {13, 8}, {13, 9}, {13, 10}, {13, 11}, {12, 12}, {11, 12}, {10, 12}, { 9, 11}, { 9, 10}, { 9, 9}, { 9, 8}, { 9, 7}, { 9, 6}, { 9, 7}, { 9, 8}, { 9, 9}, { 9, 10}, { 9, 11}, {10, 12}, {11, 12}, {12, 12}, {13, 11}, {13, 10}, {14, 9}, {15, 9}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _rv_station_left_nw_near[] = { { 5, 0}, { 5, 1}, { 6, 2}, { 7, 2}, { 8, 2}, { 9, 2}, {10, 2}, {11, 2}, {12, 3}, {12, 4}, {12, 5}, {11, 6}, {10, 6}, { 9, 6}, { 8, 6}, { 7, 6}, { 6, 6}, { 7, 6}, { 8, 6}, { 9, 6}, {10, 6}, {11, 6}, {12, 5}, {12, 4}, {12, 3}, {11, 2}, {10, 2}, { 9, 1}, { 9, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _rv_station_left_ne_far[] = { { 0, 9}, { 1, 9}, { 2, 8}, { 2, 7}, { 2, 6}, { 2, 5}, { 2, 4}, { 3, 3}, { 4, 3}, { 5, 3}, { 6, 3}, { 7, 3}, { 8, 3}, { 9, 3}, {10, 4}, {10, 5}, {10, 6}, {10, 7}, {10, 8}, {10, 9}, {10, 8}, {10, 7}, {10, 6}, {10, 5}, {10, 4}, { 9, 3}, { 8, 3}, { 7, 3}, { 6, 3}, { 5, 3}, { 4, 3}, { 3, 3}, { 2, 4}, { 1, 5}, { 0, 5}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _rv_station_left_se_far[] = { {9, 15}, {9, 14}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {4, 13}, {3, 12}, {3, 11}, {3, 10}, {3, 9}, {3, 8}, {3, 7}, {3, 6}, {4, 5}, {5, 5}, {6, 5}, {7, 5}, {8, 5}, {9, 5}, {8, 5}, {7, 5}, {6, 5}, {5, 5}, {4, 5}, {3, 6}, {3, 7}, {3, 8}, {3, 9}, {3, 10}, {3, 11}, {3, 12}, {4, 13}, {5, 14}, {5, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _rv_station_left_ne_near[] = { {0, 9}, {1, 9}, {2, 8}, {2, 7}, {2, 6}, {2, 5}, {2, 4}, {3, 3}, {4, 3}, {5, 3}, {6, 4}, {6, 5}, {6, 6}, {6, 7}, {6, 8}, {6, 9}, {6, 8}, {6, 7}, {6, 6}, {6, 5}, {6, 4}, {5, 3}, {4, 3}, {3, 3}, {2, 4}, {1, 5}, {0, 5}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _rv_station_left_se_near[] = { {9, 15}, {9, 14}, {8, 13}, {7, 13}, {6, 13}, {5, 13}, {4, 13}, {3, 12}, {3, 11}, {3, 10}, {4, 9}, {5, 9}, {6, 9}, {7, 9}, {8, 9}, {9, 9}, {8, 9}, {7, 9}, {6, 9}, {5, 9}, {4, 9}, {3, 10}, {3, 11}, {3, 12}, {4, 13}, {5, 14}, {5, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _rv_station_right_sw_far[] = { {15, 9}, {14, 9}, {13, 10}, {13, 11}, {12, 12}, {11, 12}, {10, 12}, { 9, 12}, { 8, 12}, { 7, 12}, { 6, 12}, { 5, 11}, { 5, 10}, { 5, 9}, { 5, 8}, { 5, 7}, { 5, 6}, { 5, 7}, { 5, 8}, { 5, 9}, { 5, 10}, { 5, 11}, { 6, 12}, { 7, 12}, { 8, 12}, { 9, 12}, {10, 12}, {11, 12}, {12, 12}, {13, 11}, {13, 10}, {13, 9}, {13, 8}, {13, 7}, {13, 6}, {14, 5}, {15, 5}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _rv_station_right_nw_far[] = { { 9, 0}, { 9, 1}, {10, 2}, {11, 2}, {12, 3}, {12, 4}, {12, 5}, {12, 6}, {12, 7}, {12, 8}, {12, 9}, {11, 10}, {10, 10}, { 9, 10}, { 8, 10}, { 7, 10}, { 6, 10}, { 7, 10}, { 8, 10}, { 9, 10}, {10, 10}, {11, 10}, {12, 9}, {12, 8}, {12, 7}, {12, 6}, {12, 5}, {12, 4}, {12, 3}, {11, 2}, {10, 2}, { 9, 2}, { 8, 2}, { 7, 2}, { 6, 2}, { 5, 1}, { 5, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _rv_station_right_sw_near[] = { {15, 9}, {14, 9}, {13, 10}, {13, 11}, {12, 12}, {11, 12}, {10, 12}, { 9, 11}, { 9, 10}, { 9, 9}, { 9, 8}, { 9, 7}, { 9, 6}, { 9, 7}, { 9, 8}, { 9, 9}, { 9, 10}, { 9, 11}, {10, 12}, {11, 12}, {12, 12}, {13, 11}, {13, 10}, {13, 9}, {13, 8}, {13, 7}, {13, 6}, {14, 5}, {15, 5}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _rv_station_right_nw_near[] = { { 9, 0}, { 9, 1}, {10, 2}, {11, 2}, {12, 3}, {12, 4}, {12, 5}, {11, 6}, {10, 6}, { 9, 6}, { 8, 6}, { 7, 6}, { 6, 6}, { 7, 6}, { 8, 6}, { 9, 6}, {10, 6}, {11, 6}, {12, 5}, {12, 4}, {12, 3}, {11, 2}, {10, 2}, { 9, 2}, { 8, 2}, { 7, 2}, { 6, 2}, { 5, 1}, { 5, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _rv_station_right_ne_far[] = { { 0, 5}, { 1, 5}, { 2, 4}, { 3, 3}, { 4, 3}, { 5, 3}, { 6, 3}, { 7, 3}, { 8, 3}, { 9, 3}, {10, 4}, {10, 5}, {10, 6}, {10, 7}, {10, 8}, {10, 9}, {10, 8}, {10, 7}, {10, 6}, {10, 5}, {10, 4}, { 9, 3}, { 8, 3}, { 7, 3}, { 6, 3}, { 5, 3}, { 4, 3}, { 3, 3}, { 2, 4}, { 2, 5}, { 2, 6}, { 2, 7}, { 2, 8}, { 1, 9}, { 0, 9}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _rv_station_right_se_far[] = { {5, 15}, {5, 14}, {4, 13}, {3, 12}, {3, 11}, {3, 10}, {3, 9}, {3, 8}, {3, 7}, {3, 6}, {4, 5}, {5, 5}, {6, 5}, {7, 5}, {8, 5}, {9, 5}, {8, 5}, {7, 5}, {6, 5}, {5, 5}, {4, 5}, {3, 6}, {3, 7}, {3, 8}, {3, 9}, {3, 10}, {3, 11}, {3, 12}, {4, 13}, {5, 13}, {6, 13}, {7, 13}, {8, 13}, {9, 14}, {9, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _rv_station_right_ne_near[] = { {0, 5}, {1, 5}, {2, 4}, {3, 3}, {4, 3}, {5, 3}, {6, 4}, {6, 5}, {6, 6}, {6, 7}, {6, 8}, {6, 9}, {6, 8}, {6, 7}, {6, 6}, {6, 5}, {6, 4}, {5, 3}, {4, 3}, {3, 3}, {2, 4}, {2, 5}, {2, 6}, {2, 7}, {2, 8}, {1, 9}, {0, 9}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _rv_station_right_se_near[] = { {5, 15}, {5, 14}, {4, 13}, {3, 12}, {3, 11}, {3, 10}, {4, 9}, {5, 9}, {6, 9}, {7, 9}, {8, 9}, {9, 9}, {8, 9}, {7, 9}, {6, 9}, {5, 9}, {4, 9}, {3, 10}, {3, 11}, {3, 12}, {4, 13}, {5, 13}, {6, 13}, {7, 13}, {8, 13}, {9, 14}, {9, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry * const _road_road_drive_data[] = { _roadveh_drive_data_0, _roadveh_drive_data_1, _roadveh_drive_data_2, _roadveh_drive_data_3, _roadveh_drive_data_4, _roadveh_drive_data_5, _roadveh_drive_data_6, _roadveh_drive_data_7, _roadveh_drive_data_8, _roadveh_drive_data_9, _roadveh_drive_data_10, _roadveh_drive_data_11, _roadveh_drive_data_12, _roadveh_drive_data_13, _roadveh_drive_data_14, _roadveh_drive_data_15, _roadveh_drive_data_16, _roadveh_drive_data_17, _roadveh_drive_data_18, _roadveh_drive_data_19, _roadveh_drive_data_20, _roadveh_drive_data_21, _roadveh_drive_data_22, _roadveh_drive_data_23, _roadveh_drive_data_24, _roadveh_drive_data_25, _roadveh_drive_data_26, _roadveh_drive_data_27, _roadveh_drive_data_28, _roadveh_drive_data_29, _roadveh_drive_data_30, _roadveh_drive_data_31, _rv_station_left_sw_far, _rv_station_left_nw_far, _rv_station_left_sw_near, _rv_station_left_nw_near, _rv_station_left_sw_far, _rv_station_left_nw_far, _rv_station_left_sw_near, _rv_station_left_nw_near, _rv_station_left_ne_far, _rv_station_left_se_far, _rv_station_left_ne_near, _rv_station_left_se_near, _rv_station_left_ne_far, _rv_station_left_se_far, _rv_station_left_ne_near, _rv_station_left_se_near, _rv_station_right_sw_far, _rv_station_right_nw_far, _rv_station_right_sw_near, _rv_station_right_nw_near, _rv_station_right_sw_far, _rv_station_right_nw_far, _rv_station_right_sw_near, _rv_station_right_nw_near, _rv_station_right_ne_far, _rv_station_right_se_far, _rv_station_right_ne_near, _rv_station_right_se_near, _rv_station_right_ne_far, _rv_station_right_se_far, _rv_station_right_ne_near, _rv_station_right_se_near, }; /** Table of road stop stop frames, when to stop at a road stop. */ extern const byte _road_stop_stop_frame[] = { /* Duplicated left and right because of "entered stop" bit */ 20, 20, 16, 16, 20, 20, 16, 16, 19, 19, 15, 15, 19, 19, 15, 15, 16, 16, 12, 12, 16, 16, 12, 12, 15, 15, 11, 11, 15, 15, 11, 11 }; static const RoadDriveEntry _roadveh_tram_turn_ne_0[] = { {15, 5}, {14, 5}, {13, 5}, {12, 5}, {11, 5}, {10, 5}, { 9, 5}, { 8, 5}, { 7, 5}, { 6, 5}, { 5, 5}, { 4, 5}, { 3, 5}, { 2, 5}, { 1, 5}, { 0, 5}, { 0, 6}, { 0, 7}, { 0, 8}, { 0, 9}, {RDE_TURNED | DIAGDIR_SW, 0}, { 1, 9}, { 2, 9}, { 3, 9}, { 4, 9}, { 5, 9}, { 6, 9}, { 7, 9}, { 8, 9}, { 9, 9}, {10, 9}, {11, 9}, {12, 9}, {13, 9}, {14, 9}, {15, 9}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_tram_turn_ne_1[] = { {15, 9}, {14, 9}, {13, 9}, {12, 9}, {11, 9}, {10, 9}, { 9, 9}, { 8, 9}, { 7, 9}, { 6, 9}, { 5, 9}, { 4, 9}, { 3, 9}, { 2, 9}, { 1, 9}, { 0, 9}, { 0, 8}, { 0, 7}, { 0, 6}, { 0, 5}, {RDE_TURNED | DIAGDIR_SW, 0}, { 1, 5}, { 2, 5}, { 3, 5}, { 4, 5}, { 5, 5}, { 6, 5}, { 7, 5}, { 8, 5}, { 9, 5}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5}, {RDE_NEXT_TILE | DIAGDIR_SW, 0} }; static const RoadDriveEntry _roadveh_tram_turn_se_0[] = { {5, 0}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {5, 6}, {5, 7}, {5, 8}, {5, 9}, {5, 10}, {5, 11}, {5, 12}, {5, 13}, {5, 14}, {5, 15}, {6, 15}, {7, 15}, {8, 15}, {9, 15}, {RDE_TURNED | DIAGDIR_NW, 0}, {9, 14}, {9, 13}, {9, 12}, {9, 11}, {9, 10}, {9, 9}, {9, 8}, {9, 7}, {9, 6}, {9, 5}, {9, 4}, {9, 3}, {9, 2}, {9, 1}, {9, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_tram_turn_se_1[] = { {9, 0}, {9, 1}, {9, 2}, {9, 3}, {9, 4}, {9, 5}, {9, 6}, {9, 7}, {9, 8}, {9, 9}, {9, 10}, {9, 11}, {9, 12}, {9, 13}, {9, 14}, {9, 15}, {8, 15}, {7, 15}, {6, 15}, {5, 15}, {RDE_TURNED | DIAGDIR_NW, 0}, {5, 14}, {5, 13}, {5, 12}, {5, 11}, {5, 10}, {5, 9}, {5, 8}, {5, 7}, {5, 6}, {5, 5}, {5, 4}, {5, 3}, {5, 2}, {5, 1}, {5, 0}, {RDE_NEXT_TILE | DIAGDIR_NW, 0} }; static const RoadDriveEntry _roadveh_tram_turn_sw_0[] = { { 0, 9}, { 1, 9}, { 2, 9}, { 3, 9}, { 4, 9}, { 5, 9}, { 6, 9}, { 7, 9}, { 8, 9}, { 9, 9}, {10, 9}, {11, 9}, {12, 9}, {13, 9}, {14, 9}, {15, 9}, {15, 8}, {15, 7}, {15, 6}, {15, 5}, {RDE_TURNED | DIAGDIR_NE, 0}, {14, 5}, {13, 5}, {12, 5}, {11, 5}, {10, 5}, { 9, 5}, { 8, 5}, { 7, 5}, { 6, 5}, { 5, 5}, { 4, 5}, { 3, 5}, { 2, 5}, { 1, 5}, { 0, 5}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_tram_turn_sw_1[] = { { 0, 5}, { 1, 5}, { 2, 5}, { 3, 5}, { 4, 5}, { 5, 5}, { 6, 5}, { 7, 5}, { 8, 5}, { 9, 5}, {10, 5}, {11, 5}, {12, 5}, {13, 5}, {14, 5}, {15, 5}, {15, 6}, {15, 7}, {15, 8}, {15, 9}, {RDE_TURNED | DIAGDIR_NE, 0}, {14, 9}, {13, 9}, {12, 9}, {11, 9}, {10, 9}, { 9, 9}, { 8, 9}, { 7, 9}, { 6, 9}, { 5, 9}, { 4, 9}, { 3, 9}, { 2, 9}, { 1, 9}, { 0, 9}, {RDE_NEXT_TILE | DIAGDIR_NE, 0} }; static const RoadDriveEntry _roadveh_tram_turn_nw_0[] = { {9, 15}, {9, 14}, {9, 13}, {9, 12}, {9, 11}, {9, 10}, {9, 9}, {9, 8}, {9, 7}, {9, 6}, {9, 5}, {9, 4}, {9, 3}, {9, 2}, {9, 1}, {9, 0}, {8, 0}, {7, 0}, {6, 0}, {5, 0}, {RDE_TURNED | DIAGDIR_SE, 0}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}, {5, 6}, {5, 7}, {5, 8}, {5, 9}, {5, 10}, {5, 11}, {5, 12}, {5, 13}, {5, 14}, {5, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry _roadveh_tram_turn_nw_1[] = { {5, 15}, {5, 14}, {5, 13}, {5, 12}, {5, 11}, {5, 10}, {5, 9}, {5, 8}, {5, 7}, {5, 6}, {5, 5}, {5, 4}, {5, 3}, {5, 2}, {5, 1}, {5, 0}, {6, 0}, {7, 0}, {8, 0}, {9, 0}, {RDE_TURNED | DIAGDIR_SE, 0}, {9, 1}, {9, 2}, {9, 3}, {9, 4}, {9, 5}, {9, 6}, {9, 7}, {9, 8}, {9, 9}, {9, 10}, {9, 11}, {9, 12}, {9, 13}, {9, 14}, {9, 15}, {RDE_NEXT_TILE | DIAGDIR_SE, 0} }; static const RoadDriveEntry * const _road_tram_drive_data[] = { _roadveh_drive_data_0, _roadveh_drive_data_1, _roadveh_drive_data_2, _roadveh_drive_data_3, _roadveh_drive_data_4, _roadveh_drive_data_5, _roadveh_tram_turn_ne_0, _roadveh_tram_turn_se_0, _roadveh_drive_data_8, _roadveh_drive_data_9, _roadveh_drive_data_10, _roadveh_drive_data_11, _roadveh_drive_data_12, _roadveh_drive_data_13, _roadveh_tram_turn_sw_0, _roadveh_tram_turn_nw_0, _roadveh_drive_data_16, _roadveh_drive_data_17, _roadveh_drive_data_18, _roadveh_drive_data_19, _roadveh_drive_data_20, _roadveh_drive_data_21, _roadveh_tram_turn_ne_1, _roadveh_tram_turn_se_1, _roadveh_drive_data_24, _roadveh_drive_data_25, _roadveh_drive_data_26, _roadveh_drive_data_27, _roadveh_drive_data_28, _roadveh_drive_data_29, _roadveh_tram_turn_sw_1, _roadveh_tram_turn_nw_1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; static const RoadDriveEntry * const * const _road_drive_data[2] = { _road_road_drive_data, _road_tram_drive_data, }; openttd-1.5.3/src/table/currency_settings.ini0000644000000000000000000000370612627373436020047 0ustar rootroot; $Id: currency_settings.ini 24671 2012-11-08 10:04:00Z frosch $ ; ; 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 . ; [pre-amble] static const SettingDesc _currency_settings[] = { [post-amble] }; [templates] SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_CHR = SDT_CHR($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_END = SDT_END() [defaults] flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = 0 interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = NULL load = NULL from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED [SDT_VAR] base = CurrencySpec var = rate type = SLE_UINT16 def = 1 min = 0 max = UINT16_MAX [SDT_CHR] base = CurrencySpec var = separator def = ""."" cat = SC_BASIC [SDT_VAR] base = CurrencySpec var = to_euro type = SLE_INT32 def = 0 min = MIN_YEAR max = MAX_YEAR [SDT_STR] base = CurrencySpec var = prefix type = SLE_STRBQ def = NULL [SDT_STR] base = CurrencySpec var = suffix type = SLE_STRBQ def = "" credits"" [SDT_END] openttd-1.5.3/src/table/townname.h0000644000000000000000000014156512627373436015603 0ustar rootroot/* $Id: townname.h 27002 2014-10-12 18:26:54Z rubidium $ */ /* * 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 table/townname.h Namepart tables for the town name generator */ #include "../core/enum_type.hpp" static const char * const _name_original_english_1[] = { "Great ", "Little ", "New ", "Fort ", }; static const char * const _name_original_english_2[] = { "Wr", "B", "C", "Ch", "Br", "D", "Dr", "F", "Fr", "Fl", "G", "Gr", "H", "L", "M", "N", "P", "Pr", "Pl", "R", "S", "S", "Sl", "T", "Tr", "W", }; static const char * const _name_original_english_3[] = { "ar", "a", "e", "in", "on", "u", "un", "en", }; static const char * const _name_original_english_4[] = { "n", "ning", "ding", "d", "", "t", "fing", }; static const char * const _name_original_english_5[] = { "ville", "ham", "field", "ton", "town", "bridge", "bury", "wood", "ford", "hall", "ston", "way", "stone", "borough", "ley", "head", "bourne", "pool", "worth", "hill", "well", "hattan", "burg", }; static const char * const _name_original_english_6[] = { "-on-sea", " Bay", " Market", " Cross", " Bridge", " Falls", " City", " Ridge", " Springs", }; static const char * const _name_additional_english_prefix[] = { "Great ", "Little ", "New ", "Fort ", "St. ", "Old ", }; static const char * const _name_additional_english_1a[] = { "Pen", "Lough", "Stam", "Aber", "Acc", "Ex", "Ax", "Bre", "Cum", "Dun", "Fin", "Inver", "Kin", "Mon", "Nan", "Nant", "Pit", "Pol", "Pont", "Strath", "Tre", "Tilly", "Beck", "Canter", "Bath", "Liver", "Mal", "Ox", "Bletch", "Maccles", "Grim", "Wind", "Sher", "Gates", "Orp", "Brom", "Lewis", "Whit", "White", "Worm", "Tyne", "Avon", "Stan", }; static const char * const _name_additional_english_1b1[] = { "Wr", "B", "C", "Ch", "Br", "D", "Dr", "F", "Fr", "Fl", "G", "Gr", "H", "L", "M", "N", "P", "Pr", "Pl", "R", "S", "S", "Sl", "T", "Tr", "W", }; static const char * const _name_additional_english_1b2[] = { "ar", "a", "e", "in", "on", "u", "o", "ee", "es", "ea", "un", "en", }; static const char * const _name_additional_english_1b3a[] = { "n", "d", "", "t", "", "", }; static const char * const _name_additional_english_1b3b[] = { "ning", "ding", "fing", }; static const char * const _name_additional_english_2[] = { "ville", "ham", "field", "ton", "town", "borough", "bridge", "bury", "wood", "ditch", "ford", "hall", "dean", "leigh", "dore", "ston", "stow", "church", "wich", "low", "way", "stone", "minster", "ley", "head", "bourne", "pool", "worth", "hill", "well", "hattan", "burg", "berg", "burgh", "port", "stoke", "haven", "stable", "stock", "side", "brook", "don", "den", "down", "nor", "grove", "combe", "by", "say", "ney", "chester", "dale", "ness", "shaw", "thwaite", }; static const char * const _name_additional_english_3[] = { "-on-sea", " Bay", " Market", " Beeches", " Common", " Park", " Heath", " Marsh", " Green", " Castle", " End", " Rivers", " Cross", " Bridge", " Falls", " City", " Ridge", " Springs", }; static const char * const _name_austrian_a1[] = { "Bad ", "Deutsch ", "Gross ", "Klein ", "Markt ", "Maria ", }; static const char * const _name_austrian_a2[] = { "Aus", "Alten", "Braun", "V\xC3\xB6sl", "Mittern", "Nuss", "Neu", "Walters", "Breiten", "Eisen", "Feld", "Mittern", "Gall", "Obern", "Grat", "Heiligen", "Hof", "Holla", "Stein", "Eber", "Eggen", "Enzers", "Frauen", "Herren", "Hof", "H\xC3\xBCtt", "Kaisers", "K\xC3\xB6nigs", "Knittel", "Lang", "Ober", "Ollers", "Pfaffen", "Potten", "Salz", "Schwarz", "Stocker", "Unter", "Utten", "V\xC3\xB6sen", "Vill", "Weissen", }; static const char * const _name_austrian_a3[] = { "see", "bach", "dorf", "ach", "stein", "hofen", "au", "ach", "kirch", "kirchen", "kreuz", "brunn", "siedl", "markt", "wang", "haag", }; static const char * const _name_austrian_a4[] = { "Bruck", "Brunn", "Gams", "Grein", "Ried", "Faak", "Zell", "Spital", "Kirchberg", "Saal", "Taferl", "Wald", }; static const char * const _name_austrian_a5[] = { "St. ", "Sankt ", }; static const char * const _name_austrian_a6[] = { "Aegyd", "Andr\xC3\xA4", "Georgen", "Jakob", "Johann", "Leonhard", "Marein", "Lorenzen", "Margarethen", "Martin", "Michael", "Nikolai", "Oswald", "Peter", "P\xC3\xB6lten", "Stefan", "Stephan", "Thomas", "Veit", "Wolfgang", }; static const char * const _name_austrian_f1[] = { " an der ", " ob der ", }; static const char * const _name_austrian_f2[] = { "Donau", "Steyr", "Lafnitz", "Leitha", "Thaya", "Gail", "Drau", "Salzach", "Ybbs", "Traisen", "Enns", "Mur", "Ill", }; static const char * const _name_austrian_b1[] = { " am ", }; static const char * const _name_austrian_b2[] = { "Brenner", "Dachstein", "Gebirge", "Grossglockner", "Hausruck", "Semmering", "Wagram", "Wechsel", "Wilden Kaiser", "Ziller", }; static const char * const _name_german_real[] = { "Berlin", "Bonn", "Bremen", "Cottbus", "Chemnitz", "Dortmund", "Dresden", "Erfurt", "Erlangen", "Essen", "Fulda", "Gera", "Kassel", "Kiel", "K\xC3\xB6ln", "L\xC3\xBC""beck", "Magdeburg", "M\xC3\xBCnchen", "Potsdam", "Stuttgart", "Wiesbaden", }; static const char * const _name_german_pre[] = { "Bad ", "Klein ", "Neu ", }; static const char * const _name_german_1[] = { "Alb", "Als", "Ander", "Arns", "Bruns", "Bam", "Biele", "Cloppen", "Co", "Duis", "D\xC3\xBCssel", "Dannen", "Elb", "Els", "Elster", "Eichen", "Ems", "Fahr", "Falken", "Flens", "Frank", "Frei", "Freuden", "Fried", "F\xC3\xBCrsten", "Hahn", "Ham", "Harz", "Heidel", "Hers", "Herz", "Holz", "Hildes", "Inns", "Ilsen", "Ingols", "Kel", "Kies", "Korn", "Kor", "Kreuz", "Kulm", "Langen", "Lim", "Lohr", "L\xC3\xBCne", "Mel", "Michels", "M\xC3\xBChl", "Naum", "Nest", "Nord", "Nort", "Nien", "Nidda", "Nieder", "N\xC3\xBCrn", "Ober", "Offen", "Osna", "Olden", "Ols", "Oranien", "Pader", "Quedlin", "Quer", "Ravens", "Regens", "Rott", "Ros", "R\xC3\xBCssels", "Saal", "Saar", "Salz", "Sch\xC3\xB6ne", "Schwein", "Sonder", "Sonnen", "Stein", "Strals", "Straus", "S\xC3\xBC""d", "Ton", "Unter", "Ur", "Vor", "Wald", "War", "Wert", "Wester", "Witten", "Wolfs", "W\xC3\xBCrz", }; static const char * const _name_german_2[] = { "bach", "berg", "br\xC3\xBC""ck", "br\xC3\xBC""cken", "burg", "dorf", "feld", "furt", "hausen", "haven", "heim", "horst", "mund", "m\xC3\xBCnster", "stadt", "wald", }; static const char * const _name_german_3_an_der[] = { " an der ", }; static const char * const _name_german_3_am[] = { " am ", }; static const char * const _name_german_4_an_der[] = { "Oder", "Spree", "Donau", "Saale", "Elbe", }; static const char * const _name_german_4_am[] = { "Main", }; static const char * const _name_spanish_real[] = { "Caracas", "Maracay", "Maracaibo", "Valencia", "El Dorado", "Morrocoy", "Cata", "Cataito", "Ciudad Bol\xC3\xADvar", "Barquisimeto", "M\xC3\xA9rida", "Puerto Ordaz", "Santa Elena", "San Juan", "San Luis", "San Rafael", "Santiago", "Barcelona", "Barinas", "San Crist\xC3\xB3""bal", "San Fransisco", "San Mart\xC3\xADn", "Guayana", "San Carlos", "El Lim\xC3\xB3n", "Coro", "Corocoro", "Puerto Ayacucho", "Elorza", "Arismendi", "Trujillo", "Carupano", "Anaco", "Lima", "Cuzco", "Iquitos", "Callao", "Huacho", "Camana", "Puerto Chala", "Santa Cruz", "Quito", "Cuenca", "Huacho", "Tulc\xC3\xA1n", "Esmeraldas", "Ibarra", "San Lorenzo", "Macas", "Morana", "Machala", "Zamora", "Latacunga", "Tena", "Cochabamba", "Ascensi\xC3\xB3n", "Magdalena", "Santa Ana", "Manoa", "Sucre", "Oruro", "Uyuni", "Potos\xC3\xAD", "Tupiza", "La Quiaca", "Yacuiba", "San Borja", "Fuerte Olimpio", "Fort\xC3\xADn Esteros", "Campo Grande", "Bogota", "El Banco", "Zaragoza", "Neiva", "Mariano", "Cali", "La Palma", "Andoas", "Barranca", "Montevideo", "Valdivia", "Arica", "Temuco", "Tocopilla", "Mendoza", "Santa Rosa", }; static const char * const _name_french_real[] = { "Agincourt", "Lille", "Dinan", "Aubusson", "Rodez", "Bergerac", "Bordeaux", "Bayonne", "Montpellier", "Mont\xC3\xA9limar", "Valence", "Digne", "Nice", "Cannes", "St. Tropez", "Marseille", "Narbonne", "S\xC3\xA8te", "Aurillac", "Gu\xC3\xA9ret", "Le Creusot", "Nevers", "Auxerre", "Versailles", "Meaux", "Ch\xC3\xA2lons", "Compi\xC3\xA8gne", "Metz", "Chaumont", "Langres", "Bourg", "Lyon", "Vienne", "Grenoble", "Toulon", "Rennes", "Le Mans", "Angers", "Nantes", "Ch\xC3\xA2teauroux", "Orl\xC3\xA9""ans", "Lisieux", "Cherbourg", "Morlaix", "Cognac", "Agen", "Tulle", "Blois", "Troyes", "Charolles", "Grenoble", "Chamb\xC3\xA9ry", "Tours", "St. Brieuc", "St. Malo", "La Rochelle", "St. Flour", "Le Puy", "Vichy", "St. Valery", "Beaujolais", "Narbonne", "Albi", "Paris", "Biarritz", "B\xC3\xA9ziers", "N\xC3\xAEmes", "Chamonix", "Angoul\xC3\xA8me", "Alen\xC3\xA7on", }; static const char * const _name_silly_1[] = { "Binky", "Blubber", "Bumble", "Crinkle", "Crusty", "Dangle", "Dribble", "Flippety", "Google", "Muffin", "Nosey", "Pinker", "Quack", "Rumble", "Sleepy", "Sliggles", "Snooze", "Teddy", "Tinkle", "Twister", "Pinker", "Hippo", "Itchy", "Jelly", "Jingle", "Jolly", "Kipper", "Lazy", "Frogs", "Mouse", "Quack", "Cheeky", "Lumpy", "Grumpy", "Mangle", "Fiddle", "Slugs", "Noodles", "Poodles", "Shiver", "Rumble", "Pixie", "Puddle", "Riddle", "Rattle", "Rickety", "Waffle", "Sagging", "Sausage", "Egg", "Sleepy", "Scatter", "Scramble", "Silly", "Simple", "Trickle", "Slippery", "Slimey", "Slumber", "Soggy", "Sliggles", "Splutter", "Sulky", "Swindle", "Swivel", "Tasty", "Tangle", "Toggle", "Trotting", "Tumble", "Snooze", "Water", "Windy", "Amble", "Bubble", "Cheery", "Cheese", "Cockle", "Cracker", "Crumple", "Teddy", "Evil", "Fairy", "Falling", "Fishy", "Fizzle", "Frosty", "Griddle", }; static const char * const _name_silly_2[] = { "ton", "bury", "bottom", "ville", "well", "weed", "worth", "wig", "wick", "wood", "pool", "head", "burg", "gate", "bridge", }; static const char * const _name_swedish_1[] = { "Gamla ", "Lilla ", "Nya ", "Stora ", }; static const char * const _name_swedish_2[] = { "Boll", "Bor", "Ed", "En", "Erik", "Es", "Fin", "Fisk", "Gr\xC3\xB6n", "Hag", "Halm", "Karl", "Kram", "Kung", "Land", "Lid", "Lin", "Mal", "Malm", "Marie", "Ner", "Norr", "Oskar", "Sand", "Skog", "Stock", "Stor", "Str\xC3\xB6m", "Sund", "S\xC3\xB6""der", "Tall", "Tratt", "Troll", "Upp", "Var", "V\xC3\xA4ster", "\xC3\x84ngel", "\xC3\x96ster", }; static const char * const _name_swedish_2a[] = { "B", "Br", "D", "Dr", "Dv", "F", "Fj", "Fl", "Fr", "G", "Gl", "Gn", "Gr", "H", "J", "K", "Kl", "Kn", "Kr", "Kv", "L", "M", "N", "P", "Pl", "Pr", "R", "S", "Sk", "Skr", "Sl", "Sn", "Sp", "Spr", "St", "Str", "Sv", "T", "Tr", "Tv", "V", "Vr", }; static const char * const _name_swedish_2b[] = { "a", "e", "i", "o", "u", "y", "\xC3\xA5", "\xC3\xA4", "\xC3\xB6", }; static const char * const _name_swedish_2c[] = { "ck", "d", "dd", "g", "gg", "l", "ld", "m", "n", "nd", "ng", "nn", "p", "pp", "r", "rd", "rk", "rp", "rr", "rt", "s", "sk", "st", "t", "tt", "v", }; static const char * const _name_swedish_3[] = { "arp", "berg", "boda", "borg", "bro", "bukten", "by", "byn", "fors", "hammar", "hamn", "holm", "hus", "h\xC3\xA4ttan", "kulle", "k\xC3\xB6ping", "lund", "l\xC3\xB6v", "sala", "skrona", "sl\xC3\xA4tt", "sp\xC3\xA5ng", "stad", "sund", "svall", "svik", "s\xC3\xA5ker", "udde", "valla", "viken", "\xC3\xA4lv", "\xC3\xA5s", }; static const char * const _name_dutch_1[] = { "Nieuw ", "Oud ", "Groot ", "Zuid ", "Noord ", "Oost ", "West ", "Klein ", }; static const char * const _name_dutch_2[] = { "Hoog", "Laag", "Zuider", "Zuid", "Ooster", "Oost", "Wester", "West", "Hoofd", "Midden", "Eind", "Amster", "Amstel", "Dord", "Rotter", "Haar", "Til", "Enk", "Dok", "Veen", "Leidsch", "Lely", "En", "Kaats", "U", "Maas", "Mar", "Bla", "Al", "Alk", "Eer", "Drie", "Ter", "Groes", "Goes", "Soest", "Coe", "Uit", "Zwaag", "Hellen", "Slie", "IJ", "Grubben", "Groen", "Lek", "Ridder", "Schie", "Olde", "Roose", "Haar", "Til", "Loos", "Hil", }; static const char * const _name_dutch_3[] = { "Drog", "Nat", "Valk", "Bob", "Dedem", "Kollum", "Best", "Hoend", "Leeuw", "Graaf", "Uithuis", "Purm", "Hard", "Hell", "Werk", "Spijk", "Vink", "Wams", "Heerhug", "Koning", }; static const char * const _name_dutch_4[] = { "e", "er", "el", "en", "o", "s", }; static const char * const _name_dutch_5[] = { "stad", "vorst", "dorp", "dam", "beek", "doorn", "zijl", "zijlen", "lo", "muiden", "meden", "vliet", "nisse", "daal", "vorden", "vaart", "mond", "zaal", "water", "duinen", "heuvel", "geest", "kerk", "meer", "maar", "hoorn", "rade", "wijk", "berg", "heim", "sum", "richt", "burg", "recht", "drecht", "trecht", "tricht", "dricht", "lum", "rum", "halen", "oever", "wolde", "veen", "hoven", "gast", "kum", "hage", "dijk", "zwaag", "pomp", "huizen", "bergen", "schede", "mere", "end", }; static const char * const _name_finnish_real[] = { "Aijala", "Kisko", "Espoo", "Helsinki", "Tapiola", "J\xC3\xA4rvel\xC3\xA4", "Lahti", "Kotka", "Hamina", "Loviisa", "Kouvola", "Tampere", "Oulu", "Salo", "Malmi", "Pelto", "Koski", "Iisalmi", "Raisio", "Taavetti", "Joensuu", "Imatra", "Tapanila", "Pasila", "Turku", "Kupittaa", "Vaasa", "Pori", "Rauma", "Kolari", "Lieksa", }; static const char * const _name_finnish_1[] = { "Hiekka", "Haapa", "Mylly", "Sauna", "Uusi", "Vanha", "Kes\xC3\xA4", "Kuusi", "Pelto", "Tuomi", "Terva", "Olki", "Hein\xC3\xA4", "Sein\xC3\xA4", "Rova", "Koivu", "Kokko", "M\xC3\xA4nty", "Pihlaja", "Pet\xC3\xA4j\xC3\xA4", "Kielo", "Kauha", "Viita", "Kivi", "Riihi", "\xC3\x84\xC3\xA4ne", "Niini", }; static const char * const _name_finnish_2[] = { "Lappeen", "Lohjan", "Savon", "Lapin", "Pit\xC3\xA4j\xC3\xA4n", "Martin", "Kuusan", "Kemi", "Keri", "H\xC3\xA4meen", "Kangas", }; static const char * const _name_finnish_3[] = { "harju", "linna", "j\xC3\xA4rvi", "kallio", "m\xC3\xA4ki", "nummi", "joki", "kyl\xC3\xA4", "lampi", "lahti", "mets\xC3\xA4", "suo", "laakso", "niitty", "luoto", "hovi", "ranta", "koski", "salo", }; static const char * const _name_polish_1_m[] = { "Wielki ", "Ma\xC5\x82y ", "Z\xC5\x82y ", "Dobry ", "Nowy ", "Stary ", "Z\xC5\x82oty ", "Zielony ", "Bia\xC5\x82y ", "Modry ", "D\xC4\x99""bowy ", }; static const char * const _name_polish_1_f[] = { "Wielka ", "Ma\xC5\x82""a ", "Z\xC5\x82""a ", "Dobra ", "Nowa ", "Stara ", "Z\xC5\x82ota ", "Zielona ", "Bia\xC5\x82""a ", "Modra ", "D\xC4\x99""bowa ", }; static const char * const _name_polish_1_n[] = { "Wielkie ", "Ma\xC5\x82""e ", "Z\xC5\x82""e ", "Dobre ", "Nowe ", "Stare ", "Z\xC5\x82ote ", "Zielone ", "Bia\xC5\x82""e ", "Modre ", "D\xC4\x99""bowe ", }; static const char * const _name_polish_2_o[] = { "Frombork", "Gniezno", "Olsztyn", "Toru\xC5\x84", "Bydgoszcz", "Terespol", "Krak\xC3\xB3w", "Pozna\xC5\x84", "Wroc\xC5\x82""aw", "Katowice", "Cieszyn", "Bytom", "Frombork", "Hel", "Konin", "Lublin", "Malbork", "Sopot", "Sosnowiec", "Gda\xC5\x84sk", "Gdynia", "Sieradz", "Sandomierz", "Szczyrk", "Szczytno", "Szczecin", "Zakopane", "Szklarska Por\xC4\x99""ba", "Bochnia", "Golub-Dobrzyn", "Chojnice", "Ostrowiec", "Otwock", "Wolsztyn", }; static const char * const _name_polish_2_m[] = { "Jarocin", "Gogolin", "Tomasz\xC3\xB3w", "Piotrk\xC3\xB3w", "Lidzbark", "Rypin", "Radzymin", "Wo\xC5\x82omin", "Pruszk\xC3\xB3w", "Olsztynek", "Rypin", "Cisek", "Krotoszyn", "Stoczek", "Lubin", "Lubicz", "Milicz", "Targ", "Ostr\xC3\xB3w", "Ozimek", "Puck", "Rzepin", "Siewierz", "Stargard", "Starogard", "Turek", "Tymbark", "Wolsztyn", "Strzepcz", "Strzebielin", "Sochaczew", "Gr\xC4\x99""bocin", "Gniew", "Lubliniec", "Lubasz", "Lutomiersk", "Niemodlin", "Przeworsk", "Ursus", "Tyczyn", "Sztum", "Szczebrzeszyn", "Wolin", "Wrzeszcz", "Zgierz", "Zieleniec", "Drobin", "Garwolin", }; static const char * const _name_polish_2_f[] = { "Szprotawa", "Pogorzelica", "Mot\xC5\x82""awa", "Lubawa", "Nidzica", "Kruszwica", "Bierawa", "Brodnica", "Chojna", "Krzepica", "Ruda", "Rumia", "Tuchola", "Trzebinia", "Ustka", "Warszawa", "Bobowa", "Dukla", "Krynica", "Murowana", "Niemcza", "Zaspa", "Zawoja", "Wola", "Limanowa", "Rabka", "Skawina", "Pilawa", }; static const char * const _name_polish_2_n[] = { "Lipsko", "Pilzno", "Przodkowo", "Strzelno", "Susz", "Jaworzno", "Choszczno", "Mogilno", "Luzino", "Miasto", "Dziadowo", "Kowalewo", "Legionowo", "Miastko", "Zabrze", "Zawiercie", "Kochanowo", "Miechucino", "Mirachowo", "Robakowo", "Kosakowo", "Borne", "Braniewo", "Sulinowo", "Chmielno", "Jastrz\xC4\x99""bie", "Gryfino", "Koronowo", "Lubichowo", "Opoczno", }; static const char * const _name_polish_3_m[] = { " Wybudowanie", " \xC5\x9Awi\xC4\x99tokrzyski", " G\xC3\xB3rski", " Morski", " Zdr\xC3\xB3j", " Wody", " Bajoro", " Kraje\xC5\x84ski", " \xC5\x9Al\xC4\x85ski", " Mazowiecki", " Pomorski", " Wielki", " Maly", " Warmi\xC5\x84ski", " Mazurski", " Mniejszy", " Wi\xC4\x99kszy", " G\xC3\xB3rny", " Dolny", " Wielki", " Stary", " Nowy", " Wielkopolski", " Wzg\xC3\xB3rze", " Mosty", " Kujawski", " Ma\xC5\x82opolski", " Podlaski", " Lesny", }; static const char * const _name_polish_3_f[] = { " Wybudowanie", " \xC5\x9Awi\xC4\x99tokrzyska", " G\xC3\xB3rska", " Morska", " Zdr\xC3\xB3j", " Woda", " Bajoro", " Kraje\xC5\x84ska", " \xC5\x9Al\xC4\x85ska", " Mazowiecka", " Pomorska", " Wielka", " Ma\xC5\x82""a", " Warmi\xC5\x84ska", " Mazurska", " Mniejsza", " Wi\xC4\x99ksza", " G\xC3\xB3rna", " Dolna", " Wielka", " Stara", " Nowa", " Wielkopolska", " Wzg\xC3\xB3rza", " Mosty", " Kujawska", " Malopolska", " Podlaska", " Le\xC5\x9Bna", }; static const char * const _name_polish_3_n[] = { " Wybudowanie", " \xC5\x9Awietokrzyskie", " G\xC3\xB3rskie", " Morskie", " Zdr\xC3\xB3j", " Wody", " Bajoro", " Kraje\xC5\x84skie", " \xC5\x9Al\xC4\x85skie", " Mazowieckie", " Pomorskie", " Wielkie", " Ma\xC5\x82""e", " Warmi\xC5\x84skie ", " Mazurskie ", " Mniejsze", " Wi\xC4\x99ksze", " G\xC3\xB3rne", " Dolne", " Wielkie", " Stare", " Nowe", " Wielkopolskie", " Wzg\xC3\xB3rze", " Mosty", " Kujawskie", " Ma\xC5\x82opolskie", " Podlaskie", " Le\xC5\x9Bne", }; static const char * const _name_czech_real[] = { "A\xC5\xA1", "Bene\xC5\xA1ov", "Beroun", "Bezdru\xC5\xBEice", "Blansko", "B\xC5\x99""eclav", "Brno", "Brunt\xC3\xA1l", "\xC4\x8C""esk\xC3\xA1 L\xC3\xADpa", "\xC4\x8C""esk\xC3\xA9 Bud\xC4\x9Bjovice", "\xC4\x8C""esk\xC3\xBD Krumlov", "D\xC4\x9B\xC4\x8D\xC3\xADn", "Doma\xC5\xBElice", "Dub\xC3\xAD", "Fr\xC3\xBD""dek-M\xC3\xADstek", "Havl\xC3\xAD\xC4\x8Dk\xC5\xAFv Brod", "Hodon\xC3\xADn", "Hradec Kr\xC3\xA1lov\xC3\xA9", "Humpolec", "Cheb", "Chomutov", "Chrudim", "Jablonec nad Nisou", "Jesen\xC3\xADk", "Ji\xC4\x8D\xC3\xADn", "Jihlava", "Jind\xC5\x99ich\xC5\xAFv Hradec", "Karlovy Vary", "Karvin\xC3\xA1", "Kladno", "Klatovy", "Kol\xC3\xADn", "Kosmonosy", "Krom\xC4\x9B\xC5\x99\xC3\xAD\xC5\xBE", "Kutn\xC3\xA1 Hora", "Liberec", "Litom\xC4\x9B\xC5\x99ice", "Louny", "Man\xC4\x9Bt\xC3\xADn", "M\xC4\x9Bln\xC3\xADk", "Mlad\xC3\xA1 Boleslav", "Most", "N\xC3\xA1""chod", "Nov\xC3\xBD Ji\xC4\x8D\xC3\xADn", "Nymburk", "Olomouc", "Opava", "Or\xC3\xA1\xC4\x8Dov", "Ostrava", "Pardubice", "Pelh\xC5\x99imov", "Pol\xC5\xBEice", "P\xC3\xADsek", "Plze\xC5\x88", "Praha", "Prachatice", "P\xC5\x99""erov", "P\xC5\x99\xC3\xAD""bram", "Prost\xC4\x9Bjov", "Rakovn\xC3\xADk", "Rokycany", "Rudn\xC3\xA1", "Rychnov nad Kn\xC4\x9B\xC5\xBEnou", "Semily", "Sokolov", "Strakonice", "St\xC5\x99""edokluky", "\xC5\xA0umperk", "Svitavy", "T\xC3\xA1""bor", "Tachov", "Teplice", "T\xC5\x99""eb\xC3\xAD\xC4\x8D", "Trutnov", "Uhersk\xC3\xA9 Hradi\xC5\xA1t\xC4\x9B", "\xC3\x9Ast\xC3\xAD nad Labem", "\xC3\x9Ast\xC3\xAD nad Orlic\xC3\xAD", "Vset\xC3\xADn", "Vy\xC5\xA1kov", "\xC5\xBD\xC4\x8F\xC3\xA1r nad S\xC3\xA1zavou", "Zl\xC3\xADn", "Znojmo", }; /* The advanced hyperintelligent Czech town names generator! * The tables and MakeCzechTownName() is (c) Petr Baudis 2005 (GPL'd) * Feel free to ask me about anything unclear or if you need help * with cloning this for your own language. */ /* Sing., pl. */ enum CzechGender { CZG_SMASC, CZG_SFEM, CZG_SNEUT, CZG_PMASC, CZG_PFEM, CZG_PNEUT, /* Special for substantive stems - the ending chooses the gender. */ CZG_FREE, /* Like CZG_FREE, but disallow CZG_SNEUT. */ CZG_NFREE }; enum CzechPattern { CZP_JARNI, CZP_MLADY, CZP_PRIVL }; /* [CzechGender][CzechPattern] - replaces the last character of the adjective * by this. * XXX: [CZG_SMASC][CZP_PRIVL] needs special handling: -ovX -> -uv. */ static const char * const _name_czech_patmod[][3] = { /* CZG_SMASC */ { "\xC3\xAD", "\xC3\xBD", "X" }, /* CZG_SFEM */ { "\xC3\xAD", "\xC3\xA1", "a" }, /* CZG_SNEUT */ { "\xC3\xAD", "\xC3\xA9", "o" }, /* CZG_PMASC */ { "\xC3\xAD", "\xC3\xA9", "y" }, /* CZG_PFEM */ { "\xC3\xAD", "\xC3\xA9", "y" }, /* CZG_PNEUT */ { "\xC3\xAD", "\xC3\xA1", "a" } }; /* This way the substantive can choose only some adjectives/endings: * At least one of these flags must be satisfied: */ enum CzechAllow { CZA_SHORT = 1, CZA_MIDDLE = 2, CZA_LONG = 4, CZA_ALL = ~0 }; DECLARE_ENUM_AS_BIT_SET(CzechAllow) /* All these flags must be satisfied (in the stem->others direction): */ enum CzechChoose { CZC_NONE = 0, // No requirements. CZC_COLOR = 1, CZC_POSTFIX = 2, // Matched if postfix was inserted. CZC_NOPOSTFIX = 4, // Matched if no postfix was inserted. CZC_ANY = ~0 }; DECLARE_ENUM_AS_BIT_SET(CzechChoose) struct CzechNameSubst { CzechGender gender; CzechAllow allow; CzechChoose choose; const char *name; }; struct CzechNameAdj { CzechPattern pattern; CzechChoose choose; const char *name; }; /* Some of items which should be common are doubled. */ static const CzechNameAdj _name_czech_adj[] = { { CZP_JARNI, CZC_ANY, "Horn\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "Horn\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "Doln\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "Doln\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "P\xC5\x99""edn\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "Zadn\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "Kosteln\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "Havran\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "\xC5\x98\xC3\xAD\xC4\x8Dn\xC3\xAD" }, { CZP_JARNI, CZC_ANY, "Jezern\xC3\xAD" }, { CZP_MLADY, CZC_ANY, "Velk\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Velk\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Mal\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Mal\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Vysok\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "\xC4\x8C""esk\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Moravsk\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Slov\xC3\xA1""ck\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Slezsk\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Uhersk\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Star\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Star\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Nov\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Nov\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Mlad\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Kr\xC3\xA1lovsk\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Kamenn\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Cihlov\xC3\xBD" }, { CZP_MLADY, CZC_ANY, "Divn\xC3\xBD" }, { CZP_MLADY, CZC_COLOR, "\xC4\x8C""erven\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "\xC4\x8C""erven\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "\xC4\x8C""erven\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "Zelen\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "\xC5\xBDlut\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "Siv\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "\xC5\xA0""ed\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "B\xC3\xADl\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "B\xC3\xADl\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "Modr\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "R\xC5\xAF\xC5\xBEov\xC3\xA1" }, { CZP_MLADY, CZC_COLOR, "\xC4\x8C""ern\xC3\xA1" }, { CZP_PRIVL, CZC_ANY, "Kr\xC3\xA1lova" }, { CZP_PRIVL, CZC_ANY, "Janova" }, { CZP_PRIVL, CZC_ANY, "Karlova" }, { CZP_PRIVL, CZC_ANY, "Kry\xC5\xA1tofova" }, { CZP_PRIVL, CZC_ANY, "Ji\xC5\x99\xC3\xADkova" }, { CZP_PRIVL, CZC_ANY, "Petrova" }, { CZP_PRIVL, CZC_ANY, "Sudovo" }, }; /* Considered a stem for choose/allow matching purposes. */ static const CzechNameSubst _name_czech_subst_full[] = { { CZG_SMASC, CZA_ALL, CZC_COLOR, "Sedlec" }, { CZG_SMASC, CZA_ALL, CZC_COLOR, "Brod" }, { CZG_SMASC, CZA_ALL, CZC_COLOR, "Brod" }, { CZG_SMASC, CZA_ALL, CZC_NONE, "\xC3\x9Aval" }, { CZG_SMASC, CZA_ALL, CZC_COLOR, "\xC5\xBD\xC4\x8F\xC3\xA1r" }, { CZG_SMASC, CZA_ALL, CZC_COLOR, "Smrk" }, { CZG_SFEM, CZA_ALL, CZC_COLOR, "Hora" }, { CZG_SFEM, CZA_ALL, CZC_COLOR, "Lhota" }, { CZG_SFEM, CZA_ALL, CZC_COLOR, "Lhota" }, { CZG_SFEM, CZA_ALL, CZC_COLOR, "Hlava" }, { CZG_SFEM, CZA_ALL, CZC_COLOR, "L\xC3\xADpa" }, { CZG_SNEUT, CZA_ALL, CZC_COLOR, "Pole" }, { CZG_SNEUT, CZA_ALL, CZC_COLOR, "\xC3\x9A""dol\xC3\xAD" }, { CZG_PMASC, CZA_ALL, CZC_NONE, "\xC3\x9Avaly" }, { CZG_PFEM, CZA_ALL, CZC_COLOR, "Luka" }, { CZG_PNEUT, CZA_ALL, CZC_COLOR, "Pole" }, }; /* TODO: More stems needed. --pasky */ static const CzechNameSubst _name_czech_subst_stem[] = { { CZG_SMASC, CZA_MIDDLE, CZC_COLOR, "Kostel" }, { CZG_SMASC, CZA_MIDDLE, CZC_COLOR, "Kl\xC3\xA1\xC5\xA1ter" }, { CZG_SMASC, CZA_SHORT, CZC_COLOR, "Lhot" }, { CZG_SFEM, CZA_SHORT, CZC_COLOR, "Lhot" }, { CZG_SFEM, CZA_SHORT, CZC_COLOR, "Hur" }, { CZG_FREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Sedl" }, { CZG_FREE, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_COLOR, "Hrad" }, { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "Pras" }, { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "Ba\xC5\xBE" }, { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "Tes" }, { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "U\xC5\xBE" }, { CZG_NFREE, CZA_MIDDLE | CZA_LONG, CZC_POSTFIX, "B\xC5\x99" }, { CZG_NFREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Vod" }, { CZG_NFREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Jan" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Prach" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Kunr" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Strak" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "V\xC3\xADt" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Vy\xC5\xA1" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "\xC5\xBD""at" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "\xC5\xBD""er" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "St\xC5\x99""ed" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Harv" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Pruh" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Tach" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "P\xC3\xADsn" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Jin" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Jes" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Jar" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Sok" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Hod" }, { CZG_NFREE, CZA_LONG, CZC_NONE, "Net" }, { CZG_FREE, CZA_LONG, CZC_NONE, "Pra\xC5\xBE" }, { CZG_FREE, CZA_LONG, CZC_NONE, "Nerat" }, { CZG_FREE, CZA_LONG, CZC_NONE, "Kral" }, { CZG_FREE, CZA_LONG, CZC_NONE, "Hut" }, { CZG_FREE, CZA_LONG, CZC_NOPOSTFIX, "Pan" }, { CZG_FREE, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_NOPOSTFIX, "Odst\xC5\x99""ed" }, { CZG_FREE, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_COLOR, "Mrat" }, { CZG_FREE, CZA_LONG, CZC_COLOR, "Hlav" }, { CZG_FREE, CZA_SHORT | CZA_MIDDLE, CZC_NONE, "M\xC4\x9B\xC5\x99" }, { CZG_FREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Lip" }, }; /* Optional postfix inserted between stem and ending. */ static const char * const _name_czech_subst_postfix[] = { "av", "an", "at", "ov", "on", "ot", "ev", "en", "et", }; /* This array must have the both neutral genders at the end! */ static const CzechNameSubst _name_czech_subst_ending[] = { { CZG_SMASC, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "ec" }, { CZG_SMASC, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "\xC3\xADn" }, { CZG_SMASC, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_ANY, "ov" }, { CZG_SMASC, CZA_SHORT | CZA_LONG, CZC_ANY, "kov" }, { CZG_SMASC, CZA_LONG, CZC_POSTFIX, "\xC3\xADn" }, { CZG_SMASC, CZA_LONG, CZC_POSTFIX, "n\xC3\xADk" }, { CZG_SMASC, CZA_LONG, CZC_ANY, "burk" }, { CZG_SFEM, CZA_SHORT, CZC_ANY, "ka" }, { CZG_SFEM, CZA_MIDDLE, CZC_ANY, "inka" }, { CZG_SFEM, CZA_MIDDLE, CZC_ANY, "n\xC3\xA1" }, { CZG_SFEM, CZA_LONG, CZC_ANY, "ava" }, { CZG_PMASC, CZA_LONG, CZC_POSTFIX, "\xC3\xADky" }, { CZG_PMASC, CZA_LONG, CZC_ANY, "upy" }, { CZG_PMASC, CZA_LONG, CZC_ANY, "olupy" }, { CZG_PFEM, CZA_LONG, CZC_ANY, "avy" }, { CZG_PFEM, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_ANY, "ice" }, { CZG_PFEM, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_ANY, "i\xC4\x8Dky" }, { CZG_PNEUT, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "na" }, { CZG_SNEUT, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "no" }, { CZG_SNEUT, CZA_LONG, CZC_ANY, "i\xC5\xA1t\xC4\x9B" }, }; static const char * const _name_czech_suffix[] = { "nad Cidlinou", "nad Dyj\xC3\xAD", "nad Jihlavou", "nad Labem", "nad Lesy", "nad Moravou", "nad Nisou", "nad Odrou", "nad Ostravic\xC3\xAD", "nad S\xC3\xA1zavou", "nad Vltavou", "pod Prad\xC4\x9B""dem", "pod Radho\xC5\xA1t\xC4\x9Bm", "pod \xC5\x98\xC3\xADpem", "pod Sn\xC4\x9B\xC5\xBEkou", "pod \xC5\xA0pi\xC4\x8D\xC3\xA1kem", "pod Sedlem", "v \xC4\x8C""ech\xC3\xA1""ch", "na Morav\xC4\x9B", }; static const char * const _name_romanian_real[] = { "Adjud", "Alba Iulia", "Alexandria", "Babadag", "Bac\xC3\xA3u", "Baia Mare", "B\xC3\xA3ile Herculane", "B\xC3\xA3ilesti", "B\xC3\xA2rlad", "Bicaz", "Bistrita", "Blaj", "Borsec", "Botosani", "Br\xC3\xA3ila", "Brasov", "Bucuresti", "Buftea", "Buz\xC3\xA3u", "C\xC3\xA3l\xC3\xA3rasi", "Caransebes", "Cernavod\xC3\xA3", "Cluj-Napoca", "Constanta", "Covasna", "Craiova", "Dej", "Deva", "Dorohoi", "Dr.-Tr. Severin", "Dr\xC3\xA3g\xC3\xA3sani", "F\xC3\xA3g\xC3\xA3ras", "F\xC3\xA3lticeni", "Fetesti", "Focsani", "Galati", "Gheorgheni", "Giurgiu", "H\xC3\xA2rsova", "Hunedoara", "Husi", "Iasi", "Isaccea", "Lugoj", "M\xC3\xA3""cin", "Mangalia", "Medgidia", "Medias", "Miercurea Ciuc", "Mizil", "Motru", "N\xC3\xA3s\xC3\xA3ud", "N\xC3\xA3vodari", "Odobesti", "Oltenita", "Onesti", "Oradea", "Orsova", "Petrosani", "Piatra Neamt", "Pitesti", "Ploiesti", "Predeal", "R\xC3\xA2mnicu V\xC3\xA2lcea", "Reghin", "Resita", "Roman", "Rosiorii de Vede", "Satu Mare", "Sebes", "Sf\xC3\xA2ntu Gheorghe", "Sibiu", "Sighisoara", "Sinaia", "Slatina", "Slobozia", "Sovata", "Suceava", "Sulina", "T\xC3\xA3nd\xC3\xA3rei", "T\xC3\xA2rgoviste", "T\xC3\xA2rgu Jiu", "T\xC3\xA2rgu Mures", "Tecuci", "Timisoara", "Tulcea", "Turda", "Turnu M\xC3\xA3gurele", "Urziceni", "Vaslui", "Vatra Dornei", "Victoria", "Videle", "Zal\xC3\xA3u", }; static const char * const _name_slovak_real[] = { "Bratislava", "Banovce nad Bebravou", "Banska Bystrica", "Banska Stiavnica", "Bardejov", "Brezno", "Brezova pod Bradlom", "Bytca", "Cadca", "Cierna nad Tisou", "Detva", "Detva", "Dolny Kubin", "Dolny Kubin", "Dunajska Streda", "Gabcikovo", "Galanta", "Gbely", "Gelnica", "Handlova", "Hlohovec", "Holic", "Humenne", "Hurbanovo", "Kezmarok", "Komarno", "Kosice", "Kremnica", "Krompachy", "Kuty", "Leopoldov", "Levoca", "Liptovsky Mikulas", "Lucenec", "Malacky", "Martin", "Medzilaborce", "Michalovce", "Modra", "Myjava", "Namestovo", "Nitra", "Nova Bana", "Nove Mesto nad Vahom", "Nove Zamky", "Partizanske", "Pezinok", "Piestany", "Poltar", "Poprad", "Povazska Bystrica", "Prievidza", "Puchov", "Revuca", "Rimavska Sobota", "Roznava", "Ruzomberok", "Sabinov", "Sala", "Senec", "Senica", "Sered", "Skalica", "Sladkovicovo", "Smolenice", "Snina", "Stara Lubovna", "Stara Tura", "Strazske", "Stropkov", "Stupava", "Sturovo", "Sulekovo", "Topolcany", "Trebisov", "Trencin", "Trnava", "Turcianske Teplice", "Tvrdosin", "Vrable", "Vranov nad Toplou", "Zahorska Bystrica", "Zdiar", "Ziar nad Hronom", "Zilina", "Zlate Moravce", "Zvolen", }; static const char * const _name_norwegian_1[] = { "Arna", "Aust", "Bj\xC3\xB8rk", "Bj\xC3\xB8rn", "Brand", "B\xC3\xB8ver", "Drag", "Dr\xC3\xB8", "Eids", "Egge", "Fager", "Finns", "Flat", "Foll", "Foss", "Fugle", "Furu", "Gaus", "Galte", "Geir", "Gl\xC3\xB8s", "Gran", "Grind", "Grims", "Gr\xC3\xB8n", "Gr\xC3\xB8t", "Gulle", "Haka", "Hammer", "Haug", "Hol", "Hon", "Hop", "Hov", "Jess", "Kabel", "Kjerns", "Kjerring", "Knatte", "Krok", "K\xC3\xB8y", "Lang", "Lauv", "Leir", "Lund", "Logn", "Lo", "Lyng", "L\xC3\xB8n", "Mesna", "Mel", "Mo", "Nar", "Nitte", "Nord", "Odd", "Ola", "Otte", "Ran", "Rev", "Rog", "Roms", "Rosen", "Sand", "Sau", "Sel", "Sol", "Sjur", "Sk\xC3\xA5r", "Sl\xC3\xA5tt", "Stj\xC3\xB8r", "Stor", "Svart", "Svens", "Svin", "Sylte", "Syn", "Tran", "Vass", "Ved", "Vest", "Vesle", "Vik", "V\xC3\xA5g", }; static const char * const _name_norwegian_2[] = { "aker", "anger", "bakken", "bekk", "berg", "botn", "breen", "bu", "bugen", "by", "bygd", "b\xC3\xB8", "dal", "egga", "eid", "elv", "enga", "foss", "fjell", "fjord", "foten", "gard", "grend", "hammer", "haug", "havn", "heim", "hella", "hovda", "h\xC3\xB8""a", "h\xC3\xB8gda", "kampen", "kj\xC3\xB8len", "kollen", "kroken", "land", "lia", "mark", "moen", "myr", "nes", "nuten", "osen", "rike", "rud", "sand", "set", "sj\xC3\xB8""en", "skogen", "slette", "snipa", "stad", "stua", "stulen", "sund", "svingen", "s\xC3\xA6tra", "tinden", "tun", "vang", "vatn", "veid", "vik", "voll", "v\xC3\xA5g", "um", "\xC3\xA5sen", }; static const char * const _name_norwegian_real[] = { "Alta", "Arendal", "Askim", "Bergen", "Bod\xC3\xB8", "Brevik", "Bryne", "Br\xC3\xB8nn\xC3\xB8ysund", "Drammen", "Dr\xC3\xB8""bak", "Egersund", "Elverum", "Farsund", "Fauske", "Finnsnes", "Flekkefjord", "Flora", "Fosnav\xC3\xA5g", "Fredrikstad", "F\xC3\xB8rde", "Gj\xC3\xB8vik", "Grimstad", "Halden", "Hamar", "Hammerfest", "Harstad", "Haugesund", "Holmestrand", "Horten", "J\xC3\xB8rpeland", "Kirkenes", "Kolvereid", "Kongsberg", "Kongsvinger", "Kopervik", "Krager\xC3\xB8", "Kristiansand", "Kristiansund", "Langesund", "Larvik", "Leirvik", "Leknes", "Levanger", "Lillehammer", "Lillesand", "Lillestr\xC3\xB8m", "Lyngdal", "L\xC3\xB8renskog", "Mandal", "Mo i Rana", "Molde", "Mosj\xC3\xB8""en", "Moss", "Mysen", "M\xC3\xA5l\xC3\xB8y", "Namsos", "Narvik", "Notodden", "Odda", "Oslo", "Otta", "Porsgrunn", "Ringerike", "Ris\xC3\xB8r", "Rjukan", "Sandefjord", "Sandnes", "Sandnessj\xC3\xB8""en", "Sandvika", "Sarpsborg", "Sauda", "Ski", "Skien", "Skudeneshavn", "Sortland", "Stathelle", "Stavanger", "Steinkjer", "Stj\xC3\xB8rdal", "Stokmarknes", "Stord", "Svelvik", "Svolv\xC3\xA6r", "Troms\xC3\xB8", "Trondheim", "Tvedestrand", "T\xC3\xB8nsberg", "Ulsteinvik", "Vads\xC3\xB8", "Vard\xC3\xB8", "Verdals\xC3\xB8ra", "\xC3\x85krehamn", "\xC3\x85lesund", "\xC3\x85ndalsnes", }; static const char * const _name_hungarian_1[] = { "Nagy-", "Kis-", "Fels\xC5\x91-", "Als\xC3\xB3-", "\xC3\x9Aj-", }; static const char * const _name_hungarian_2[] = { "Bodrog", "Dr\xC3\xA1va", "Duna", "Hej\xC5\x91", "Hern\xC3\xA1""d", "R\xC3\xA1""ba", "Saj\xC3\xB3", "Szamos", "Tisza", "Zala", "Balaton", "Fert\xC5\x91", "Bakony", "Cserh\xC3\xA1t", "Bihar", "Hajd\xC3\xBA", "J\xC3\xA1sz", "Kun", "Magyar", "N\xC3\xB3gr\xC3\xA1""d", "Ny\xC3\xADr", "Somogy", "Sz\xC3\xA9kely", "Buda", "Gy\xC5\x91r", "Pest", "Feh\xC3\xA9r", "Cser\xC3\xA9p", "Erd\xC5\x91", "Hegy", "Homok", "Mez\xC5\x91", "Puszta", "S\xC3\xA1r", "Cs\xC3\xA1sz\xC3\xA1r", "Herceg", "Kir\xC3\xA1ly", "Nemes", "P\xC3\xBCsp\xC3\xB6k", "Szent", "Alm\xC3\xA1s", "Szilv\xC3\xA1s", "Agg", "Aranyos", "B\xC3\xA9k\xC3\xA9s", "Egyh\xC3\xA1zas", "Gagy", "Heves", "Kapos", "T\xC3\xA1pi\xC3\xB3", "Torna", "Vas", "V\xC3\xA1mos", "V\xC3\xA1s\xC3\xA1ros", }; static const char * const _name_hungarian_3[] = { "ap\xC3\xA1ti", "b\xC3\xA1""ba", "bikk", "dob", "fa", "f\xC3\xB6ld", "hegyes", "kak", "kereszt", "k\xC3\xBCrt", "lad\xC3\xA1ny", "m\xC3\xA9rges", "szalonta", "telek", "vas", "v\xC3\xB6lgy", }; static const char * const _name_hungarian_4[] = { "alja", "egyh\xC3\xA1za", "h\xC3\xA1za", "\xC3\xBAr", "v\xC3\xA1r", }; static const char * const _name_hungarian_real[] = { "Ajka", "Asz\xC3\xB3""d", "Badacsony", "Baja", "Budapest", "Debrecen", "Eger", "Fony\xC3\xB3""d", "G\xC3\xB6""d\xC3\xB6ll\xC5\x91", "Gy\xC5\x91r", "Gyula", "Karcag", "Kecskem\xC3\xA9t", "Keszthely", "Kisk\xC3\xB6re", "Kocsord", "Kom\xC3\xA1rom", "K\xC5\x91szeg", "Mak\xC3\xB3", "Moh\xC3\xA1""cs", "Miskolc", "\xC3\x93zd", "Paks", "P\xC3\xA1pa", "P\xC3\xA9""cs", "Polg\xC3\xA1r", "Sarkad", "Si\xC3\xB3""fok", "Szeged", "Szentes", "Szolnok", "Tihany", "Tokaj", "V\xC3\xA1""c", "Z\xC3\xA1hony", "Zirc", }; static const char * const _name_swiss_real[] = { "Aarau", "Aesch", "Altdorf", "Arosa", "Appenzell", "Arbon", "Altst\xC3\xA4tten", "Baar", "Baden", "Bellinzona", "Brig-Glis", "Bienne", "Bulle", "Binningen", "Burgdorf", "Bern", "Basel", "B\xC3\xBClach", "Carouge", "Cham", "Chiasso", "Chur", "Davos", "Del\xC3\xA9mont", "Dietikon", "D\xC3\xBC""bendorf", "Emmen", "Freienbach-Pf\xC3\xA4""ffikon", "Fribourg", "Frauenfeld", "Gen\xC3\xA8ve", "Glarus", "Gossau", "Grenchen", "Herisau", "Horgen", "Horw", "Illnau-Effretikon", "Ittigen", "Jona", "Kriens", "Kloten", "K\xC3\xB6niz", "Kreuzlingen", "K\xC3\xBCsnacht", "Agen", "Lancy", "La Chaux-de-Fonds", "Lenzburg", "Lugano", "Langenthal", "Littau", "Le Locle", "La Neuveville", "Locarno", "Liestal", "La Tour-de-Peilz", "Lausanne", "Lyss", "Luzern", "Martigny", "M\xC3\xBCnchenstein", "Meyrin", "Montreux", "Monthey", "Morges", "Murten", "Moutier", "Muttenz", "Neuch\xC3\xA2tel", "Neuhausen am Rheinfall", "Nyon", "Olten", "Onex", "Opfikon", "Ostermundigen", "Payerne", "Peseux", "Prilly", "Pully", "Rapperswil", "Richterswil", "Regensdorf", "Rheinfelden", "Riehen", "Renens", "Romanshorn", "Rorschach", "Stans", "Schaffhausen", "Steffisburg", "St. Gallen", "Schlieren", "Sierre", "Solothurn", "St. Moritz", "Sion", "Spiez", "St\xC3\xA4""fa", "Sursee", "Schwyz", "Thalwil", "Th\xC3\xB4nex", "Thun", "Uster", "Uzwil", "Vernier", "Volketswil", "Versoix", "Vevey", "W\xC3\xA4""denswil", "Wettingen", "Wil", "Wallisellen", "Winterthur", "Wohlen", "Worb", "Wetzikon", "Yverdon-les-Bains", "Zollikon", "Zofingen", "Z\xC3\xBCrich", "Zug", }; static const char * const _name_danish_1[] = { "Gamle ", "Lille ", "Nye ", "Store ", "Kirke ", "N\xC3\xB8rre ", "Vester ", "S\xC3\xB8nder ", "\xC3\x98ster ", "Hvide ", "H\xC3\xB8je ", "Kongens ", }; static const char * const _name_danish_2[] = { "Ager", "Alle", "Aske", "Balle", "Bede", "Birke", "Bjerring", "Bj\xC3\xA6ver", "Blommens", "Blok", "Bolder", "Bred", "Charlotten", "Christians", "Danne", "Diana", "Es", "Fredens", "Frederiks", "Fugle", "F\xC3\xA5re", "Gille", "Gis", "Givs", "Glams", "Glo", "Guld", "Had", "Haralds", "Hassel", "Hede", "Helle", "Hessel", "Hjorts", "Hol", "Horn", "Humle", "H\xC3\xB8j", "H\xC3\xB8r", "Is", "Jyde", "J\xC3\xA6gers", "Karls", "Klov", "Kokke", "Kvist", "Lang", "Lange", "Mari", "Nord", "Ny", "Oks", "Ring", "R\xC3\xB8""de", "Rung", "R\xC3\xB8r", "Rud", "Saks", "Salt", "Skam", "Silke", "Skod", "Sk\xC3\xA6l", "Sk\xC3\xA6r", "Sol", "Svend", "Svine", "Strand", "Stubbe", "Ting", "Tj\xC3\xA6re", "Tore", "Uger", "Ulf", "Val", "Vand", "Vej", "Vor", "V\xC3\xA6r", "\xC3\x98r", "\xC3\x85l", }; static const char * const _name_danish_3[] = { "basse", "borg", "berg", "bro", "by", "havn", "strup", "holm", "hus", "k\xC3\xB8""bing", "lund", "lunde", "sund", "ovre", "h\xC3\xB8j", "dal", "sted", "sten", "l\xC3\xB8se", "r\xC3\xB8""d", "magle", "s\xC3\xB8", "bjerg", "b\xC3\xA6k", "drup", "lev", "bo", "lyst", "feld", "skov", }; static const char * const _name_turkish_prefix[] = { "Ak\xC3\xA7""a", "Alt\xC4\xB1n", "Bah\xC3\xA7""e", "Boz", "B\xC3\xBCy\xC3\xBCk", "\xC3\x87""ay", "Do\xC4\x9Fu", "Eski", "G\xC3\xBCzel", "K\xC4\xB1z\xC4\xB1l", "K\xC3\xBC\xC3\xA7\xC3\xBCk", "Orta", "Sar\xC4\xB1", "Sultan", "Ulu", "Yeni", }; static const char * const _name_turkish_middle[] = { "aga\xC3\xA7", "ayva", "\xC3\xA7""am", "elma", "kurt", "pazar", "yal\xC4\xB1", }; static const char * const _name_turkish_suffix[] = { "dere", "hisar", "kale", "kaya", "kent", "k\xC3\xB6y", "ova", "\xC3\xB6z\xC3\xBC", "\xC3\xB6ren", "pazar", "saray", "tepe", "yer", "yurt", }; static const char * const _name_turkish_real[] = { "Adana", "Ad\xC4\xB1yaman", "Afyon", "A\xC4\x9Fr\xC4\xB1", "Amasya", "Antalya", "Artvin", "Bal\xC4\xB1kesir", "Bilecik", "Bitlis", "Bolu", "Burdur", "Bursa", "\xC3\x87""anakkale", "\xC3\x87""ank\xC4\xB1r\xC4\xB1", "Denizli", "Diyarbak\xC4\xB1r", "Edirne", "Elaz\xC4\xB1\xC4\x9F", "Erzurum", "Eskisehir", "Giresun", "G\xC3\xBCm\xC3\xBC\xC5\x9Fhane", "Hatay", "Isparta", "\xC4\xB0\xC3\xA7""el", "\xC4\xB0stanbul", "\xC4\xB0zmir", "Kars", "Kastamonu", "Kayseri", "Kirklareli", "Kocaeli", "Konya", "K\xC3\xBCtahya", "Malatya", "Manisa", "Kahramanmara\xC5\x9F", "Mardin", "Mu\xC4\x9Fla", "Mu\xC5\x9F", "Nev\xC5\x9F""ehir", "Ni\xC4\x9F""de", "Rize", "Sakarya", "Samsun", "Siirt", "Sinop", "Sivas", "Trabzon", "\xC5\x9E""anl\xC4\xB1urfa", "Van", "Yozgat", "Zonguldak", "Aksaray", "Bayburt", "Karaman", "\xC5\x9E\xC4\xB1rnak", "Bart\xC4\xB1n", "Ardahan", "I\xC4\x9F""d\xC4\xB1r", "Yalova", "Karab\xC3\xBCk", "Osmaniye", "D\xC3\xBCzce", }; static const char * const _name_italian_real[] = { "Roma", "Milano", "Napoli", "Torino", "Venezia", "Firenze", "Palermo", "Genova", "Parma", "Bologna", "Bari", "Cagliari", "Sassari", "Pisa", "Aosta", "Brescia", "Verona", "Bolzano", "Padova", "Udine", "Trieste", "Livorno", "Ancona", "Perugia", "Pescara", "L'Aquila", "Campobasso", "Potenza", "Cosenza", "Reggio Calabria", "Catania", "Caltanisetta", "Agrigento", "La Spezia", "Modena", "Vicenza", "Mantova", "Cremona", "Piacenza", "Reggio Emilia", "Foggia", "Benevento", "Salerno", "Catanzaro", "Lecce", "Como", "Lecco", "Sondrio", "Trento", "Desenzano", "Cuneo", "Asti", "Lodi", "Novara", "Biella", "Vercelli", "Rieti", "Nuoro", "Oristano", "Matera", "Taranto", "Varese", "Bergamo", "Pavia", "Caserta", "Frosinone", "Latina", "Enna", "Ragusa", "Siracusa", "Pordenone", "Imperia", "Verbania", "Alessandria", "Messina", "Siena", "Arezzo", "Grosseto", }; static const char * const _name_italian_pref[] = { "Alpe ", "Borgo ", "Cascina ", "Castel ", "Fonte ", "Forte ", "Malga ", "Pieve ", "Poggio ", "Rocca ", "Villa ", "Villar ", }; static const char * const _name_italian_1m[] = { "Bel", "Borgo", "Bosco", "Campo", "Capo", "Casal", "Castel", "Colle", "Fiume", "Fonte", "Lago", "Mezzo", "Monte", "Mon", "Orto", "Passo", "Prato", "Poggio", "Ponte", "Pozzo", "Sasso", "Tra", "Tre", "Ver", "Vico", }; static const char * const _name_italian_1f[] = { "Acqua", "Bra", "Cala", "Casa", "Chiesa", "Citta", "Civita", "Corte", "Costa", "Croce", "Fontana", "Grotta", "Guardia", "Mezza", "Palma", "Pietra", "Ripa", "Rocca", "Serra", "Torre", "Val", "Valle", "Villa", }; static const char * const _name_italian_2[] = { "bell", "bianc", "cald", "chiar", "cort", "ferrat", "fier", "fredd", "gioios", "grec", "guzz", "lung", "long", "migli", "negr", "ner", "nov", "nuov", "ross", "rotond", "scur", "secc", "sett", "vecchi", "ventos", "vers", "viv", }; static const char * const _name_italian_2i[] = { "", "breve", "brevi", "chiari", "ferro", "fieschi", "fiore", "fonte", "forte", "gate", "leone", "maggiore", "minore", "mole", "monte", "poli", "scuri", "terra", "te", "torrione", "vento", "verde", "versiere", }; static const char * const _name_italian_3[] = { " Marittimo", " Marittima", " del Capo", " del Monte", " di Sopra", " di Sotto", " sui Monti", " dei Marmi", " dei Sassi", " delle Fonti", " sui Prati", " a Mare", " Superiore", " Inferiore", " Terme", " Alta", " Bassa", " Brianza", " Vesuviano", " Scrivia", " Ticino", }; static const char * const _name_italian_river1[] = { " del", " sul", " al", " nel", }; static const char * const _name_italian_river2[] = { "l'Adda", "l'Adige", "le Alpi", "l'Arno", " Bormida", " Brenta", "la Dora Baltea", " Lambro", " Mincio", " Naviglio", "l'Oglio", "l'Olona", "l'Ombrone", " Panaro", " Piave", " Po", " Reno", " Scrivia", " Secchia", " Serio", " Tagliamento", " Tanaro", " Taro", " Ticino", " Tevere", }; static const char * const _name_catalan_real[] = { "Barcelona", "L'Hospitalet de Llobregat", "Cerdanyola", "Martorell", "Badalona", "Tarragona", "Lleida", "Girona", "Sabadell", "Terrassa", "Reus", "Valls", "Vic", "Vielha e Mijaran", "Amposta", "Tortosa", "Berga", "Olot", "Mollerussa", "Banyoles", "Figueres", "Balaguer", "Vilafranca del Pened\xC3\xA8s", "La Seu d'Urgell", "El Pont de Suert", "Igualada", "Manresa", "Solsona", "Les Borges Blanques", "Tremp", "Sort", "Colera", "Portbou", "El Vendrell", "Falset", "Ripoll", "Cervera", "Gandesa", "Matar\xC3\xB3", "Montblanc", "Vilanova i la Geltr\xC3\xBA", "T\xC3\xA0rrega", "Camprodon", "Campdev\xC3\xA0nol", "Cambrils", "Begur", "Setcases", "Palafrugell", "Begues", "El Bruc", "Cadaqu\xC3\xA9s", "Collbat\xC3\xB3", "Cervell\xC3\xB3", "Esparreguera", "Abrera", "Alp", "Das", "Cercs", "Manlleu", "El Masnou", "Molins de Rei", "Monistrol", "Rocallaura", "Rub\xC3\xAD", "Ripollet", "Sitges", "Roses", }; static const char * const _name_catalan_pref[] = { "El Pont de ", "Parets de ", "Canet de ", "Castellar de ", "Corbera de ", "Arenys de ", "Calella de ", "La Seu de ", "La Bisbal de ", "Torroella de ", "Port de ", "Vilafranca de ", "Vilanova de ", "Caldes de ", "La Conca de ", "Olesa de ", "La Roca de ", "Sant Esteve de ", "Sant Andreu de ", "Sant Jordi de ", "Sant Joan de ", "Sant Feliu de ", "Sant Quirze de ", "Sant Sadurn\xC3\xAD de ", "Santa Coloma de ", "Santa Margarida de ", "Santa Maria de ", "Sant Mart\xC3\xAD de ", "Sant Pere de ", "Sant Juli\xC3\xA0 de ", "Sant Vicen\xC3\xA7 de ", }; static const char * const _name_catalan_1m[] = { "Torrent", "Cami", "Mont", "Bell", "Puig", "Riu", }; static const char * const _name_catalan_1f[] = { "Pala", "Selva", "Vall", "Serra", "Torre", "Riba", "Cova", "Terra", }; static const char * const _name_catalan_2m[] = { "alt", "baix", "fosc", "pelat", "vent\xC3\xB3s", "negre", "roig", "gr\xC3\xADs", }; static const char * const _name_catalan_2f[] = { "baixa", "alta", "fosca", "clara", "negra", "roja", "grisa", "freda", }; static const char * const _name_catalan_3[] = { " Desp\xC3\xAD", " Desvern", " del Cam\xC3\xAD", " de Mar", " de Dalt", " de Baix", " del Vall\xC3\xA8s", " de Bergued\xC3\xA0", " de Conflent", " de la Plana", }; static const char * const _name_catalan_river1[] = { " d'Anoia", " de Ter", " de Llobregat", " d'Ebre", " de Segre", " de Francol\xC3\xAD", }; openttd-1.5.3/src/table/win32_settings.ini0000644000000000000000000000352312627373436017154 0ustar rootroot; $Id: win32_settings.ini 26522 2014-04-27 12:15:14Z frosch $ ; ; 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 . ; [pre-amble] /* win32_v.cpp only settings */ #if defined(WIN32) && !defined(DEDICATED) extern bool _force_full_redraw, _window_maximize; extern uint _display_hz; static const SettingDescGlobVarList _win32_settings[] = { [post-amble] }; #endif /* WIN32 */ [templates] SDTG_BOOL = SDTG_BOOL($name, $flags, $guiflags, $var, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_VAR = SDTG_VAR($name, $type, $flags, $guiflags, $var, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDTG_END = SDTG_END() [defaults] flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = 0 interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = NULL load = NULL from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED [SDTG_VAR] name = ""display_hz"" type = SLE_UINT var = _display_hz def = 0 min = 0 max = 120 cat = SC_EXPERT [SDTG_BOOL] name = ""force_full_redraw"" var = _force_full_redraw def = false cat = SC_EXPERT [SDTG_BOOL] name = ""window_maximize"" var = _window_maximize def = false cat = SC_BASIC [SDTG_END] openttd-1.5.3/src/table/track_land.h0000644000000000000000000000427412627373436016050 0ustar rootroot/* $Id: track_land.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 track_land.h Sprites to use and how to display them for train depot tiles. */ #define TILE_SEQ_LINE(img, dx, dy, sx, sy) { dx, dy, 0, sx, sy, 23, {img, PAL_NONE} }, #define TILE_SEQ_END() { (int8)0x80, 0, 0, 0, 0, 0, {0, 0} } static const DrawTileSeqStruct _depot_gfx_NE[] = { TILE_SEQ_LINE(SPR_RAIL_DEPOT_NE | (1 << PALETTE_MODIFIER_COLOUR), 2, 13, 13, 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _depot_gfx_SE[] = { TILE_SEQ_LINE(SPR_RAIL_DEPOT_SE_1 | (1 << PALETTE_MODIFIER_COLOUR), 2, 2, 1, 13) TILE_SEQ_LINE(SPR_RAIL_DEPOT_SE_2 | (1 << PALETTE_MODIFIER_COLOUR), 13, 2, 1, 13) TILE_SEQ_END() }; static const DrawTileSeqStruct _depot_gfx_SW[] = { TILE_SEQ_LINE(SPR_RAIL_DEPOT_SW_1 | (1 << PALETTE_MODIFIER_COLOUR), 2, 2, 13, 1) TILE_SEQ_LINE(SPR_RAIL_DEPOT_SW_2 | (1 << PALETTE_MODIFIER_COLOUR), 2, 13, 13, 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _depot_gfx_NW[] = { TILE_SEQ_LINE(SPR_RAIL_DEPOT_NW | (1 << PALETTE_MODIFIER_COLOUR), 13, 2, 1, 13) TILE_SEQ_END() }; static const DrawTileSprites _depot_gfx_table[] = { { {SPR_FLAT_GRASS_TILE, PAL_NONE}, _depot_gfx_NE }, { {SPR_RAIL_TRACK_Y, PAL_NONE}, _depot_gfx_SE }, { {SPR_RAIL_TRACK_X, PAL_NONE}, _depot_gfx_SW }, { {SPR_FLAT_GRASS_TILE, PAL_NONE}, _depot_gfx_NW } }; static const DrawTileSprites _depot_invisible_gfx_table[] = { { {SPR_RAIL_TRACK_X, PAL_NONE}, _depot_gfx_NE }, { {SPR_RAIL_TRACK_Y, PAL_NONE}, _depot_gfx_SE }, { {SPR_RAIL_TRACK_X, PAL_NONE}, _depot_gfx_SW }, { {SPR_RAIL_TRACK_Y, PAL_NONE}, _depot_gfx_NW } }; #undef TILE_SEQ_LINE #undef TILE_SEQ_END openttd-1.5.3/src/table/unicode.h0000644000000000000000000000366112627373436015373 0ustar rootroot/* $Id: unicode.h 23582 2011-12-17 21:42:11Z rubidium $ */ /* * 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 unicode.h Character mapping for using Unicode characters in OTTD. */ struct DefaultUnicodeMapping { WChar code; ///< Unicode value byte key; ///< Character index of sprite }; static const byte CLRA = 0; ///< Identifier to clear all glyphs at this codepoint /* Default unicode mapping table for sprite based glyphs. * This table allows us use unicode characters even though the glyphs don't * exist, or are in the wrong place, in the standard sprite fonts. * This is not used for FreeType rendering */ static const DefaultUnicodeMapping _default_unicode_map[] = { { 0x00A0, 0x20 }, // Non-breaking space / Up arrow { 0x00AA, CLRA }, // Feminine ordinal indicator / Down arrow { 0x00AC, CLRA }, // Not sign / Tick mark { 0x00AD, 0x20 }, // Soft hyphen / X mark { 0x00AF, CLRA }, // Macron / Right arrow { 0x00B4, CLRA }, // Acute accent / Train symbol { 0x00B5, CLRA }, // Micro sign / Truck symbol { 0x00B6, CLRA }, // Pilcrow sign / Bus symbol { 0x00B7, CLRA }, // Middle dot / Aircraft symbol { 0x00B8, CLRA }, // Cedilla / Ship symbol { 0x00B9, CLRA }, // Superscript 1 / Superscript -1 { 0x00BC, CLRA }, // One quarter / Small up arrow { 0x00BD, CLRA }, // One half / Small down arrow { 0x0178, 0x9F }, // Capital letter Y with diaeresis { 0x010D, 0x63 }, // Small letter c with caron }; openttd-1.5.3/src/table/palette_convert.h0000644000000000000000000001031312627373436017133 0ustar rootroot/* $Id: palette_convert.h 23433 2011-12-04 19:07:24Z rubidium $ */ /* * 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 palette_convert.h Translation tables from one GRF to another GRF. */ /** Converting from the Windows palette to the DOS palette */ extern const byte _palmap_w2d[] = { 0, 1, 2, 3, 4, 5, 6, 7, // 0..7 8, 9, 10, 11, 12, 13, 14, 15, // 8..15 16, 17, 18, 19, 20, 21, 22, 23, // 16..23 24, 25, 26, 27, 28, 29, 30, 31, // 24..31 6, 7, 34, 35, 36, 37, 38, 39, // 32..39 8, 41, 42, 43, 44, 45, 46, 47, // 40..47 48, 49, 50, 51, 52, 53, 54, 55, // 48..55 56, 57, 58, 59, 60, 61, 62, 63, // 56..63 64, 65, 66, 67, 68, 69, 70, 71, // 64..71 72, 73, 74, 75, 76, 77, 78, 79, // 72..79 80, 81, 82, 83, 84, 85, 86, 87, // 80..87 4, 89, 90, 91, 92, 93, 94, 95, // 88..95 96, 97, 98, 99, 100, 101, 102, 103, // 96..103 104, 105, 5, 107, 108, 109, 110, 111, // 104..111 112, 113, 114, 115, 116, 117, 118, 119, // 112..119 120, 121, 122, 123, 124, 125, 126, 127, // 120..127 128, 129, 130, 131, 132, 133, 134, 135, // 128..135 3, 137, 138, 139, 140, 141, 142, 143, // 136..143 144, 145, 146, 147, 148, 149, 150, 151, // 144..151 152, 153, 154, 155, 156, 157, 158, 159, // 152..159 160, 161, 162, 163, 164, 165, 166, 167, // 160..167 168, 169, 170, 171, 172, 173, 174, 175, // 168..175 176, 177, 178, 179, 180, 181, 182, 183, // 176..183 184, 185, 186, 187, 188, 189, 190, 191, // 184..191 192, 193, 194, 195, 196, 197, 198, 199, // 192..199 200, 201, 202, 203, 204, 205, 206, 207, // 200..207 208, 209, 210, 211, 212, 213, 214, 1, // 208..215 2, 245, 246, 247, 248, 249, 250, 251, // 216..223 252, 253, 254, 227, 228, 229, 230, 231, // 224..231 232, 233, 234, 235, 236, 237, 238, 239, // 232..239 240, 241, 242, 243, 244, 9, 218, 219, // 240..247 220, 221, 222, 223, 224, 225, 226, 255, // 248..255 }; /** Converting from the DOS palette to the Windows palette */ static const byte _palmap_d2w[] = { 0, 215, 216, 136, 88, 106, 32, 33, // 0..7 40, 245, 10, 11, 12, 13, 14, 15, // 8..15 16, 17, 18, 19, 20, 21, 22, 23, // 16..23 24, 25, 26, 27, 28, 29, 30, 31, // 24..31 53, 54, 34, 35, 36, 37, 38, 39, // 32..39 178, 41, 42, 43, 44, 45, 46, 47, // 40..47 48, 49, 50, 51, 52, 53, 54, 55, // 48..55 56, 57, 58, 59, 60, 61, 62, 63, // 56..63 64, 65, 66, 67, 68, 69, 70, 71, // 64..71 72, 73, 74, 75, 76, 77, 78, 79, // 72..79 80, 81, 82, 83, 84, 85, 86, 87, // 80..87 96, 89, 90, 91, 92, 93, 94, 95, // 88..95 96, 97, 98, 99, 100, 101, 102, 103, // 96..103 104, 105, 53, 107, 108, 109, 110, 111, // 104..111 112, 113, 114, 115, 116, 117, 118, 119, // 112..119 120, 121, 122, 123, 124, 125, 126, 127, // 120..127 128, 129, 130, 131, 132, 133, 134, 135, // 128..135 170, 137, 138, 139, 140, 141, 142, 143, // 136..143 144, 145, 146, 147, 148, 149, 150, 151, // 144..151 152, 153, 154, 155, 156, 157, 158, 159, // 152..159 160, 161, 162, 163, 164, 165, 166, 167, // 160..167 168, 169, 170, 171, 172, 173, 174, 175, // 168..175 176, 177, 178, 179, 180, 181, 182, 183, // 176..183 184, 185, 186, 187, 188, 189, 190, 191, // 184..191 192, 193, 194, 195, 196, 197, 198, 199, // 192..199 200, 201, 202, 203, 204, 205, 206, 207, // 200..207 208, 209, 210, 211, 212, 213, 214, 215, // 208..215 216, 217, 246, 247, 248, 249, 250, 251, // 216..223 252, 253, 254, 227, 228, 229, 230, 231, // 224..231 232, 233, 234, 235, 236, 237, 238, 239, // 232..239 240, 241, 242, 243, 244, 217, 218, 219, // 240..247 220, 221, 222, 223, 224, 225, 226, 255, // 248..255 }; openttd-1.5.3/src/table/industry_land.h0000644000000000000000000017174512627373436016635 0ustar rootroot/* $Id: industry_land.h 20286 2010-08-01 19:44:49Z frosch $ */ /* * 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 industry_land.h Information about the behaviour of the default industry tiles. */ /** * This is used to gather some data about animation * drawing in the industry code * Image_1-2-3 are in fact only offset in the sprites * used by the industry. * To specify an invalid one, either 255 or 0 is used, * depending of the industry. */ struct DrawIndustryAnimationStruct { int x; ///< coordinate x of the first image offset byte image_1; ///< image offset 1 byte image_2; ///< image offset 2 byte image_3; ///< image offset 3 }; /** * Simple structure gathering x,y coordinates for * industries animations */ struct DrawIndustryCoordinates { byte x; ///< coordinate x of the pair byte y; ///< coordinate y of the pair }; /** * Macro to ease the declaration of the array * @param s1 sprite ID of ground sprite * @param p1 palette ID of ground sprite * @param s2 sprite ID of building sprite * @param p2 palette ID of building sprite * @param sx coordinate x of the sprite * @param sy coordinate y of the sprite * @param w width of the sprite * @param h height of the sprite * @param dz virtual height of the sprite * @param p this allows to specify a special drawing procedure. * @see DrawBuildingsTileStruct */ #define M(s1, p1, s2, p2, sx, sy, w, h, dz, p) { { s1, p1 }, { s2, p2 }, sx, sy, w, h, dz, p } /** Structure for industry tiles drawing */ static const DrawBuildingsTileStruct _industry_draw_tile_data[NEW_INDUSTRYTILEOFFSET * 4] = { M( 0xf54, PAL_NONE, 0x7db, PAL_NONE, 7, 0, 9, 9, 10, 0), M( 0xf54, PAL_NONE, 0x7dc, PAL_NONE, 7, 0, 9, 9, 30, 0), M( 0xf54, PAL_NONE, 0x7dd, PAL_NONE, 7, 0, 9, 9, 30, 0), M( 0x7e6, PAL_NONE, 0x7dd, PAL_NONE, 7, 0, 9, 9, 30, 0), M( 0x7e6, PAL_NONE, 0x7dd, PAL_NONE, 7, 0, 9, 9, 30, 0), M( 0x7e6, PAL_NONE, 0x7de, PAL_NONE, 7, 0, 9, 9, 30, 0), M( 0x7e6, PAL_NONE, 0x7df, PAL_NONE, 7, 0, 9, 9, 30, 0), M( 0x7e6, PAL_NONE, 0x7df, PAL_NONE, 7, 0, 9, 9, 30, 0), M( 0xf54, PAL_NONE, 0x7e0, PAL_NONE, 1, 2, 15, 9, 30, 0), M( 0xf54, PAL_NONE, 0x7e1, PAL_NONE, 1, 2, 15, 9, 30, 0), M( 0xf54, PAL_NONE, 0x7e2, PAL_NONE, 1, 2, 15, 9, 30, 0), M( 0x7e6, PAL_NONE, 0x7e2, PAL_NONE, 1, 2, 15, 9, 30, 0), M( 0xf54, PAL_NONE, 0x7e3, PAL_NONE, 4, 4, 9, 9, 30, 0), M( 0xf54, PAL_NONE, 0x7e4, PAL_NONE, 4, 4, 9, 9, 30, 0), M( 0xf54, PAL_NONE, 0x7e5, PAL_NONE, 4, 4, 9, 9, 30, 0), M( 0x7e6, PAL_NONE, 0x7e5, PAL_NONE, 4, 4, 9, 9, 30, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e9, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e7, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x7fd, PAL_NONE, 1, 1, 14, 14, 5, 0), M( 0xf54, PAL_NONE, 0x7fe, PAL_NONE, 1, 1, 14, 14, 44, 0), M( 0xf54, PAL_NONE, 0x7ff, PAL_NONE, 1, 1, 14, 14, 44, 0), M( 0xf54, PAL_NONE, 0x7ff, PAL_NONE, 1, 1, 14, 14, 44, 0), M( 0xf54, PAL_NONE, 0x800, PAL_NONE, 0, 2, 16, 12, 6, 0), M( 0xf54, PAL_NONE, 0x801, PAL_NONE, 0, 2, 16, 12, 47, 0), M( 0xf54, PAL_NONE, 0x802, PAL_NONE, 0, 2, 16, 12, 50, 0), M( 0xf54, PAL_NONE, 0x802, PAL_NONE, 0, 2, 16, 12, 50, 0), M( 0xf54, PAL_NONE, 0x803, PAL_NONE, 1, 0, 14, 15, 5, 0), M( 0xf54, PAL_NONE, 0x804, PAL_NONE, 1, 0, 14, 15, 19, 0), M( 0xf54, PAL_NONE, 0x805, PAL_NONE, 1, 0, 14, 15, 21, 0), M( 0xf54, PAL_NONE, 0x805, PAL_NONE, 1, 0, 14, 15, 21, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x806, PAL_NONE, 1, 2, 14, 11, 32, 5), M( 0xf54, PAL_NONE, 0x80d, PAL_NONE, 1, 0, 13, 16, 8, 0), M( 0xf54, PAL_NONE, 0x80e, PAL_NONE, 1, 0, 13, 16, 20, 0), M( 0xf54, PAL_NONE, 0x80f, PAL_NONE, 1, 0, 13, 16, 20, 0), M( 0xf54, PAL_NONE, 0x80f, PAL_NONE, 1, 0, 13, 16, 20, 0), M( 0xf54, PAL_NONE, 0x810, PAL_NONE, 0, 1, 16, 14, 8, 0), M( 0xf54, PAL_NONE, 0x811, PAL_NONE, 0, 1, 16, 14, 21, 0), M( 0xf54, PAL_NONE, 0x812, PAL_NONE, 0, 1, 16, 14, 21, 0), M( 0xf54, PAL_NONE, 0x812, PAL_NONE, 0, 1, 16, 14, 21, 0), M( 0xf54, PAL_NONE, 0x813, PAL_NONE, 1, 1, 14, 14, 12, 0), M( 0xf54, PAL_NONE, 0x814, PAL_NONE, 1, 1, 14, 14, 15, 0), M( 0xf54, PAL_NONE, 0x815, PAL_NONE, 1, 1, 14, 14, 22, 0), M( 0xf54, PAL_NONE, 0x815, PAL_NONE, 1, 1, 14, 14, 22, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x816, PAL_NONE, 0, 0, 16, 15, 20, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x817, PAL_NONE, 0, 1, 16, 13, 19, 0), M( 0x81d, PAL_NONE, 0x818, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x819, PAL_NONE, 0, 0, 16, 16, 15, 0), M( 0x81d, PAL_NONE, 0x81a, PAL_NONE, 0, 0, 16, 16, 31, 0), M( 0x81d, PAL_NONE, 0x81b, PAL_NONE, 0, 0, 16, 16, 39, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0xf54, PAL_NONE, 0x81e | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 1, 1, 14, 14, 4, 0), M( 0xf54, PAL_NONE, 0x81f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 1, 1, 14, 14, 24, 0), M( 0xf54, PAL_NONE, 0x820 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 1, 1, 14, 14, 27, 0), M( 0x58c, PAL_NONE, 0x820 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 1, 1, 14, 14, 27, 0), M( 0xf54, PAL_NONE, 0x821 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 3, 3, 10, 9, 3, 0), M( 0xf54, PAL_NONE, 0x822 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 3, 3, 10, 9, 63, 0), M( 0xf54, PAL_NONE, 0x823 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 3, 3, 10, 9, 62, 0), M( 0x58c, PAL_NONE, 0x823 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 3, 3, 10, 9, 62, 0), M( 0xf54, PAL_NONE, 0x824 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 4, 4, 7, 7, 3, 0), M( 0xf54, PAL_NONE, 0x825 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 4, 4, 7, 7, 72, 0), M( 0xf54, PAL_NONE, 0x825 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 4, 4, 7, 7, 72, 0), M( 0x58c, PAL_NONE, 0x826 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 4, 4, 7, 7, 80, 0), M( 0xf54, PAL_NONE, 0x827 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 2, 0, 12, 16, 51, 0), M( 0xf54, PAL_NONE, 0x828 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 2, 0, 12, 16, 51, 0), M( 0xf54, PAL_NONE, 0x829 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 2, 0, 12, 16, 51, 0), M( 0x58c, PAL_NONE, 0x829 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 2, 0, 12, 16, 51, 0), M( 0xf54, PAL_NONE, 0x82a | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 26, 0), M( 0xf54, PAL_NONE, 0x82b | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 44, 0), M( 0xf54, PAL_NONE, 0x82c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 46, 0), M( 0x58c, PAL_NONE, 0x82c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 46, 0), M( 0xf54, PAL_NONE, 0x82d, PAL_NONE, 3, 1, 10, 13, 2, 0), M( 0xf54, PAL_NONE, 0x82e, PAL_NONE, 3, 1, 10, 13, 11, 0), M( 0xf54, PAL_NONE, 0x82f, PAL_NONE, 3, 1, 10, 13, 11, 0), M( 0x58c, PAL_NONE, 0x82f, PAL_NONE, 3, 1, 10, 13, 11, 0), M( 0xfdd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xfdd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xfdd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xfdd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xfdd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xfdd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xfdd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xfdd, PAL_NONE, 0x833, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x837, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x834, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x834, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x830, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x838, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x835, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x835, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x831, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x839, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x836, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x836, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0xfdd, PAL_NONE, 0x832, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x87d, PAL_NONE, 0x87e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x87e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x87e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x87e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x87f, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x880, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x881, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x882, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x883, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x883, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x882, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x881, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x880, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x87f, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x87d, PAL_NONE, 0x87e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x83a, PAL_NONE, 0x83c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83a, PAL_NONE, 0x83c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83a, PAL_NONE, 0x83c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83a, PAL_NONE, 0x83c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83b, PAL_NONE, 0x83d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83b, PAL_NONE, 0x83d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83b, PAL_NONE, 0x83d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83b, PAL_NONE, 0x83d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x83e, PAL_NONE, 0x83f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83e, PAL_NONE, 0x83f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x83e, PAL_NONE, 0x83f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x840, PAL_NONE, 0x841, PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x840, PAL_NONE, 0x841, PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x840, PAL_NONE, 0x841, PAL_NONE, 0, 0, 16, 16, 18, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x842, PAL_NONE, 0x843, PAL_NONE, 0, 0, 16, 16, 30, 0), M( 0x842, PAL_NONE, 0x843, PAL_NONE, 0, 0, 16, 16, 30, 0), M( 0x842, PAL_NONE, 0x843, PAL_NONE, 0, 0, 16, 16, 30, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x844, PAL_NONE, 0x845, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x844, PAL_NONE, 0x845, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x844, PAL_NONE, 0x845, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x7e6, PAL_NONE, 0x869, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x862 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x866 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86a, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x863 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x867 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x864 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x868 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86c, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x870, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x870, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x865 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0xf54, PAL_NONE, 0x871 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x875 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x875 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x879 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x872 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x876 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x876 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x87a | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x873 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x877 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x877 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x87b | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x874 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x878 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x878 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x87c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf54, PAL_NONE, 0x7ea, PAL_NONE, 3, 2, 8, 8, 18, 0), M( 0xf54, PAL_NONE, 0x7eb, PAL_NONE, 3, 2, 8, 8, 37, 0), M( 0xf54, PAL_NONE, 0x7ec, PAL_NONE, 3, 2, 8, 8, 49, 0), M( 0x7e6, PAL_NONE, 0x7ec, PAL_NONE, 3, 2, 8, 8, 49, 0), M( 0x7e6, PAL_NONE, 0x7ec, PAL_NONE, 3, 2, 8, 8, 49, 0), M( 0x7e6, PAL_NONE, 0x7ed, PAL_NONE, 3, 2, 8, 8, 49, 0), M( 0x7e6, PAL_NONE, 0x7ee, PAL_NONE, 3, 2, 8, 8, 49, 0), M( 0x7e6, PAL_NONE, 0x7ee, PAL_NONE, 3, 2, 8, 8, 49, 0), M( 0xf54, PAL_NONE, 0x7ef, PAL_NONE, 3, 2, 10, 7, 20, 0), M( 0xf54, PAL_NONE, 0x7f0, PAL_NONE, 3, 2, 10, 7, 40, 0), M( 0xf54, PAL_NONE, 0x7f1, PAL_NONE, 3, 2, 10, 7, 40, 0), M( 0x7e6, PAL_NONE, 0x7f1, PAL_NONE, 3, 2, 10, 7, 40, 0), M( 0xf54, PAL_NONE, 0x7f2, PAL_NONE, 4, 4, 7, 8, 22, 0), M( 0xf54, PAL_NONE, 0x7f3, PAL_NONE, 4, 4, 7, 8, 22, 0), M( 0xf54, PAL_NONE, 0x7f4, PAL_NONE, 4, 4, 7, 8, 22, 0), M( 0x7e6, PAL_NONE, 0x7f4, PAL_NONE, 4, 4, 7, 8, 22, 0), M( 0xf54, PAL_NONE, 0x7f5, PAL_NONE, 2, 1, 11, 13, 12, 0), M( 0xf54, PAL_NONE, 0x7f6, PAL_NONE, 2, 1, 11, 13, 12, 0), M( 0xf54, PAL_NONE, 0x7f7, PAL_NONE, 2, 1, 11, 13, 12, 0), M( 0x7e6, PAL_NONE, 0x7f7, PAL_NONE, 2, 1, 11, 13, 12, 0), M( 0x7e6, PAL_NONE, 0x85c, PAL_NONE, 0, 0, 1, 1, 1, 0), M( 0x851, PAL_NONE, 0x852, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x851, PAL_NONE, 0x852, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x846 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x847 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x7e6, PAL_NONE, 0x85d, PAL_NONE, 0, 0, 1, 1, 1, 0), M( 0x853, PAL_NONE, 0x854, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x853, PAL_NONE, 0x854, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x848 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x849 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x7e6, PAL_NONE, 0x85e, PAL_NONE, 0, 0, 1, 1, 1, 0), M( 0x855, PAL_NONE, 0x856, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x855, PAL_NONE, 0x856, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x84a | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x84b | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x7e6, PAL_NONE, 0x85f, PAL_NONE, 0, 0, 1, 1, 1, 0), M( 0x857, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x857, PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x84c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e6, PAL_NONE, 0x860, PAL_NONE, 0, 0, 1, 1, 1, 0), M( 0x858, PAL_NONE, 0x859, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x858, PAL_NONE, 0x859, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x84d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x84e | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x7e6, PAL_NONE, 0x861, PAL_NONE, 0, 0, 1, 1, 1, 0), M( 0x85a, PAL_NONE, 0x85b, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x85a, PAL_NONE, 0x85b, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x84f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x850 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x7e6, PAL_NONE, 0x884, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x884, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x884, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x886, PAL_NONE, 0x884, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x885, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x885, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x885, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x887, PAL_NONE, 0x885, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88e | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x890 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x890 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x891 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x892 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x893 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x893 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x894 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x895 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x896 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x896 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x897 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x898, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x899, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x899, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89a, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a6, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89b, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89c, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89c, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89d, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89e, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89f, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x89f, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a1, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a2, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a3, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a4, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a2, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a3, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8a5, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8a7, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8b7, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8b7, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8c7, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8a8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8a9, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8b9, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8b9, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8c9, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8aa, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8ba, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8ba, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8ca, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ab, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bb, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bb, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8cb, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ac, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bc, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bc, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8cc, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ad, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8cd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ae, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8be, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8be, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ce, PAL_NONE, 0x8d7, PAL_NONE, 0, 0, 16, 16, 35, 0), M( 0x8af, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bf, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8bf, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8cf, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b0, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c0, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c0, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8d0, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8d1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8d2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b3, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c3, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c3, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8d3, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b4, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c4, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c4, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8d4, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b5, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c5, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c5, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8d5, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8b6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8c6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8d6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ce, PAL_NONE, 0x8d7, PAL_NONE, 0, 0, 16, 16, 35, 0), M( 0x8ce, PAL_NONE, 0x8d8, PAL_NONE, 0, 0, 16, 16, 35, 0), M( 0x8ce, PAL_NONE, 0x8d9, PAL_NONE, 0, 0, 16, 16, 35, 0), M( 0x8ce, PAL_NONE, 0x8d9, PAL_NONE, 0, 0, 16, 16, 35, 0), M( 0x7e6, PAL_NONE, 0x88a, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88a, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88a, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x888, PAL_NONE, 0x88a, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88b, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88b, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x88b, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x889, PAL_NONE, 0x88b, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8da, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e3, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e3, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8ec, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8db, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e4, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e4, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8ed, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8dc, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e5, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e5, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8ee, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8dd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e6, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e6, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8ef, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8de, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8e7, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8e7, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f0, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8df, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8e8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8e8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8e0, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e9, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8e9, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x8f2, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8e1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ea, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ea, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f3, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8e2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8eb, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8eb, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f4, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f5, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x905, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x905, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x915, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x906, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x906, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x916, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f7, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x907, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x907, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x917, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f8, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x908, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x908, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x918, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8f9, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x909, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x909, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x919, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8fa, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x91a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8fb, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x91b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8fc, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90c, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90c, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x91c, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8fd, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90d, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90d, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x91d, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8fe, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90e, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90e, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x91e, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x8ff, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x90f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x91f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x900, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x910, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x910, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x920, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x901, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x911, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x911, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x921, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x902, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x912, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x912, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x922, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x903, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x913, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x913, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x923, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x904, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x914, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x914, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x924, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x925, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x925, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x925, PAL_NONE, 0x926, PAL_NONE, 0, 0, 16, 16, 30, 0), M( 0x925, PAL_NONE, 0x926, PAL_NONE, 0, 0, 16, 16, 30, 0), M( 0x925, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x925, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x925, PAL_NONE, 0x927, PAL_NONE, 0, 0, 16, 16, 30, 0), M( 0x925, PAL_NONE, 0x927, PAL_NONE, 0, 0, 16, 16, 30, 0), M( 0x11c6, PAL_NONE, 0x92b | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x92c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x92c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x92d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x92e | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x92f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x92f | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x930 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x928 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x929 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x929 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11c6, PAL_NONE, 0x92a | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x7e6, PAL_NONE, 0x869, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x862 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x866 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86a, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x863 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x867 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x864 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x868 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x86c, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x870, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x870, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x865 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 1, 1, 0, 0), M( 0x7e6, PAL_NONE, 0x931, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x935, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x935, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x939, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x932, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x936, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x936, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x93a, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x933, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x937, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x937, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x93b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x934, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x938, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x938, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x93c, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x81d, PAL_NONE, 0x818, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x819, PAL_NONE, 0, 0, 16, 16, 15, 0), M( 0x81d, PAL_NONE, 0x81a, PAL_NONE, 0, 0, 16, 16, 31, 0), M( 0x81d, PAL_NONE, 0x81b, PAL_NONE, 0, 0, 16, 16, 39, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0x81d, PAL_NONE, 0x81c, PAL_NONE, 0, 0, 16, 16, 7, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1245 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1248 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1248 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x124b | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1247 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x124a | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x124a | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x124d | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1246 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1249 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1249 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x124c | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x81d, PAL_NONE, 0x124e, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x124f, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1250, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1251, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1252, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1252, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1252, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1252, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1253, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1254, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1254, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x81d, PAL_NONE, 0x1255, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x125b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x125e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x125e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1261, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x125c, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x125f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x125f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1262, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x125d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1260, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1260, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x7e6, PAL_NONE, 0x1263, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1264, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1264, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1268, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1265, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1265, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1269, PAL_NONE, 0, 0, 16, 16, 50, 4), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1266, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1266, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x126a, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1267, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1267, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x126b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x126c, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1271, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1271, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1271, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1271, PAL_NONE, 0x1279, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1272, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1272, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1272, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1272, PAL_NONE, 0x127a, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1273, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1273, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1273, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1273, PAL_NONE, 0x127b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1274, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1274, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1274, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1274, PAL_NONE, 0x127c, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1275, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1275, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1275, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1275, PAL_NONE, 0x127d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1276, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1276, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1276, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1276, PAL_NONE, 0x127e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1277, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1277, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1277, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1277, PAL_NONE, 0x127f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1278, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1278, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1278, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1278, PAL_NONE, 0x1280, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1284 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1283 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1283 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1286 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1281 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1282 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1282 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1285 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1287 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1287 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1287 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1288 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1288 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x1288 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1243, PAL_NONE, 0x1289 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 3), M( 0x1243, PAL_NONE, 0x1289 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 3), M( 0x1243, PAL_NONE, 0x1289 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 3), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x1244, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129b, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129c, PAL_NONE, 0, 0, 16, 16, 50, 2), M( 0xf8d, PAL_NONE, 0x129c, PAL_NONE, 0, 0, 16, 16, 50, 2), M( 0xf8d, PAL_NONE, 0x129c, PAL_NONE, 0, 0, 16, 16, 50, 2), M( 0xf8d, PAL_NONE, 0x129c, PAL_NONE, 0, 0, 16, 16, 50, 2), M( 0xf8d, PAL_NONE, 0x129d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x129d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a0 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a0 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a0 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a0 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a1 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a1 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a1 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a1 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a2 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a2 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a2 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a2 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a3 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a3 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a3 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0x12a3 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a4 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a4 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a4 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a4 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a6 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a6 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a6 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a6 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 0), M( 0xf8d, PAL_NONE, 0x12a5 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 1), M( 0xf8d, PAL_NONE, 0x12a5 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 1), M( 0xf8d, PAL_NONE, 0x12a5 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 1), M( 0xf8d, PAL_NONE, 0x12a5 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 16, 50, 1), }; #undef M /* this is ONLY used for Sugar Mine*/ static const DrawIndustryAnimationStruct _draw_industry_spec1[96] = { { 8, 4, 0, 0}, { 6, 0, 1, 0}, { 4, 0, 2, 0}, { 6, 0, 3, 0}, { 8, 0, 4, 0}, { 10, 0, 5, 0}, { 12, 0, 6, 0}, { 10, 0, 1, 0}, { 8, 0, 2, 0}, { 6, 0, 3, 0}, { 4, 0, 4, 0}, { 6, 0, 5, 1}, { 8, 0, 6, 1}, { 10, 0, 1, 1}, { 12, 0, 2, 1}, { 10, 0, 3, 1}, { 8, 1, 4, 1}, { 6, 1, 5, 1}, { 4, 1, 6, 1}, { 6, 1, 1, 1}, { 8, 1, 2, 1}, { 10, 1, 3, 1}, { 12, 1, 4, 1}, { 10, 1, 5, 2}, { 8, 1, 6, 2}, { 6, 1, 1, 2}, { 4, 1, 2, 2}, { 6, 1, 3, 2}, { 8, 1, 4, 2}, { 10, 1, 5, 2}, { 12, 1, 6, 2}, { 10, 1, 1, 2}, { 8, 2, 2, 2}, { 6, 2, 3, 2}, { 4, 2, 4, 3}, { 6, 2, 5, 3}, { 8, 2, 6, 3}, { 10, 2, 1, 3}, { 12, 2, 2, 3}, { 10, 2, 3, 3}, { 8, 2, 4, 3}, { 6, 2, 5, 3}, { 4, 2, 6, 3}, { 6, 2, 1, 3}, { 8, 2, 2, 3}, { 10, 2, 3, 4}, { 12, 2, 4, 4}, { 10, 2, 5, 4}, { 8, 3, 6, 4}, { 6, 3, 1, 4}, { 4, 3, 2, 4}, { 6, 3, 3, 4}, { 8, 3, 4, 4}, { 10, 3, 5, 4}, { 12, 3, 6, 4}, { 10, 3, 1, 4}, { 8, 3, 2, 4}, { 6, 3, 3, 4}, { 4, 3, 4, 4}, { 6, 3, 5, 4}, { 8, 3, 6, 4}, { 10, 3, 1, 4}, { 12, 3, 2, 4}, { 10, 3, 3, 4}, { 8, 4, 4, 4}, { 6, 4, 5, 4}, { 4, 4, 6, 4}, { 6, 4, 0, 4}, { 8, 4, 0, 4}, { 10, 4, 0, 4}, { 12, 4, 0, 4}, { 10, 4, 0, 4}, { 8, 4, 0, 4}, { 6, 4, 0, 4}, { 4, 4, 0, 4}, { 6, 4, 0, 4}, { 8, 4, 0, 4}, { 10, 4, 0, 4}, { 12, 4, 0, 4}, { 10, 4, 0, 4}, { 8, 4, 0, 4}, { 6, 4, 0, 4}, { 4, 4, 0, 4}, { 6, 4, 0, 4}, { 8, 4, 0, 4}, { 10, 4, 0, 4}, { 12, 4, 0, 4}, { 10, 4, 0, 4}, { 8, 4, 0, 4}, { 6, 4, 0, 4}, { 4, 4, 0, 4}, { 6, 4, 0, 4}, { 8, 4, 0, 4}, { 10, 4, 0, 4}, { 12, 4, 0, 4}, { 10, 4, 0, 4}, }; /* this is ONLY used for Sugar Mine*/ static const DrawIndustryCoordinates _drawtile_proc1[5] = { {22, 73}, {17, 70}, {14, 69}, {10, 66}, { 8, 41}, }; /** * this is ONLY used for Toy Factory. * 255 means no drawing * @param img1 offset from base sprite SPR_IT_SUGAR_MINE_SIEVE * @param img2 offset from base sprite SPR_IT_SUGAR_MINE_CLOUDS * @param img3 offset from base sprite SPR_IT_SUGAR_MINE_PILE */ #define MD( img1, img2, img3) { (50 - img1 * 2), img1, img2, img3 } static const DrawIndustryAnimationStruct _industry_anim_offs_toys[] = { MD(255, 255, 0), MD( 0, 255, 0), MD( 1, 255, 0), MD( 2, 255, 0), MD( 3, 255, 0), MD( 4, 255, 0), MD( 5, 255, 0), MD( 6, 255, 0), MD( 7, 255, 0), MD( 8, 255, 0), MD( 9, 255, 0), MD( 10, 255, 0), MD( 11, 255, 0), MD( 12, 255, 0), MD( 13, 255, 0), MD( 14, 255, 0), MD( 15, 255, 0), MD( 16, 255, 0), MD( 17, 255, 0), MD( 18, 255, 0), MD( 18, 255, 1), MD( 18, 255, 2), MD( 18, 255, 4), MD( 18, 255, 6), MD( 18, 255, 8), MD( 18, 255, 11), MD( 18, 255, 14), MD( 18, 255, 17), MD( 18, 255, 20), MD( 18, 255, 24), MD(255, 0, 29), MD(255, 0, 24), MD(255, 0, 20), MD(255, 0, 17), MD(255, 0, 14), MD(255, 0, 11), MD(255, 0, 8), MD(255, 0, 6), MD(255, 0, 4), MD(255, 0, 2), MD(255, 0, 1), MD(255, 1, 0), MD(255, 2, 0), MD(255, 3, 0), MD(255, 4, 0), MD(255, 5, 0), MD(255, 6, 0), MD(255, 7, 0), MD(255, 8, 0), MD(255, 255, 0), }; #undef MD /* this is ONLY used for Toffee Quarry*/ static const byte _industry_anim_offs_toffee[] = { 255, 0, 0, 0, 2, 4, 6, 8, 10, 9, 7, 5, 3, 1, 255, 0, 0, 0, 2, 4, 6, 8, 10, 9, 7, 5, 3, 1, 255, 0, 0, 0, 2, 4, 6, 8, 10, 9, 7, 5, 3, 1, 255, 0, 0, 0, 2, 4, 6, 8, 10, 9, 7, 5, 3, 1, 255, 0, 0, 0, 2, 4, 6, 8, 10, 9, 7, 5, 3, 1 }; /* this is ONLY used for the Bubble Generator*/ static const byte _industry_anim_offs_bubbles[] = { 68, 69, 71, 74, 77, 80, 83, 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, }; /** * Movement of the sparks , only used for Power Station */ static const DrawIndustryCoordinates _coal_plant_sparks[] = { {11, 23}, {11, 11}, {14, 6}, {13, 3}, {18, 1}, {15, 0}, }; openttd-1.5.3/src/table/tree_land.h0000644000000000000000000005204612627373436015703 0ustar rootroot/* $Id: tree_land.h 17455 2009-09-07 13:38:57Z yexo $ */ /* * 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 tree_land.h Sprites to use and how to display them for tree tiles. */ #ifndef TREE_LAND_H #define TREE_LAND_H static const byte _tree_base_by_landscape[4] = {0, 12, 20, 32}; static const byte _tree_count_by_landscape[4] = {12, 8, 12, 9}; struct TreePos { uint8 x; uint8 y; }; static const TreePos _tree_layout_xy[][4] = { { { 9, 3 }, { 1, 8 }, { 0, 0 }, { 8, 9 } }, { { 4, 4 }, { 9, 1 }, { 6, 9 }, { 0, 9 } }, { { 9, 1 }, { 0, 9 }, { 6, 6 }, { 3, 0 } }, { { 3, 9 }, { 8, 2 }, { 9, 9 }, { 1, 5 } } }; static const PalSpriteID _tree_layout_sprite[164 + (79 - 48 + 1)][4] = { { { 0x652, PAL_NONE }, { 0x659, PAL_NONE }, { 0x660, PAL_NONE }, { 0x667, PAL_NONE } }, // 0 { { 0x652, PAL_NONE }, { 0x667, PAL_NONE }, { 0x66e, PAL_NONE }, { 0x675, PAL_NONE } }, // 1 { { 0x652, PAL_NONE }, { 0x66e, PAL_NONE }, { 0x659, PAL_NONE }, { 0x675, PAL_NONE } }, // 2 { { 0x652, PAL_NONE }, { 0x652, PAL_NONE }, { 0x660, PAL_NONE }, { 0x66e, PAL_NONE } }, // 3 { { 0x660, PAL_NONE }, { 0x667, PAL_NONE }, { 0x659, PAL_NONE }, { 0x652, PAL_NONE } }, // 4 { { 0x660, PAL_NONE }, { 0x675, PAL_NONE }, { 0x660, PAL_NONE }, { 0x660, PAL_NONE } }, // 5 { { 0x660, PAL_NONE }, { 0x652, PAL_NONE }, { 0x652, PAL_NONE }, { 0x66e, PAL_NONE } }, // 6 { { 0x660, PAL_NONE }, { 0x675, PAL_NONE }, { 0x667, PAL_NONE }, { 0x659, PAL_NONE } }, // 7 { { 0x675, PAL_NONE }, { 0x660, PAL_NONE }, { 0x675, PAL_NONE }, { 0x675, PAL_NONE } }, // 8 { { 0x675, PAL_NONE }, { 0x659, PAL_NONE }, { 0x652, PAL_NONE }, { 0x652, PAL_NONE } }, // 9 { { 0x675, PAL_NONE }, { 0x66e, PAL_NONE }, { 0x652, PAL_NONE }, { 0x652, PAL_NONE } }, // 10 { { 0x675, PAL_NONE }, { 0x667, PAL_NONE }, { 0x659, PAL_NONE }, { 0x667, PAL_NONE } }, // 11 { { 0x628, PAL_NONE }, { 0x652, PAL_NONE }, { 0x660, PAL_NONE }, { 0x62f, PAL_NONE } }, // 12 { { 0x628, PAL_NONE }, { 0x636, PAL_NONE }, { 0x675, PAL_NONE }, { 0x644, PAL_NONE } }, // 13 { { 0x628, PAL_NONE }, { 0x652, PAL_NONE }, { 0x63d, PAL_NONE }, { 0x66e, PAL_NONE } }, // 14 { { 0x628, PAL_NONE }, { 0x667, PAL_NONE }, { 0x644, PAL_NONE }, { 0x652, PAL_NONE } }, // 15 { { 0x644, PAL_NONE }, { 0x659, PAL_NONE }, { 0x660, PAL_NONE }, { 0x628, PAL_NONE } }, // 16 { { 0x644, PAL_NONE }, { 0x64b, PAL_NONE }, { 0x659, PAL_NONE }, { 0x636, PAL_NONE } }, // 17 { { 0x644, PAL_NONE }, { 0x675, PAL_NONE }, { 0x652, PAL_NONE }, { 0x63d, PAL_NONE } }, // 18 { { 0x644, PAL_NONE }, { 0x63d, PAL_NONE }, { 0x66e, PAL_NONE }, { 0x652, PAL_NONE } }, // 19 { { 0x636, PAL_NONE }, { 0x636, PAL_NONE }, { 0x628, PAL_NONE }, { 0x636, PAL_NONE } }, // 20 { { 0x636, PAL_NONE }, { 0x63d, PAL_NONE }, { 0x636, PAL_NONE }, { 0x636, PAL_NONE } }, // 21 { { 0x636, PAL_NONE }, { 0x64b, PAL_NONE }, { 0x636, PAL_NONE }, { 0x636, PAL_NONE } }, // 22 { { 0x636, PAL_NONE }, { 0x636, PAL_NONE }, { 0x636, PAL_NONE }, { 0x636, PAL_NONE } }, // 23 { { 0x64b, PAL_NONE }, { 0x628, PAL_NONE }, { 0x62f, PAL_NONE }, { 0x636, PAL_NONE } }, // 24 { { 0x64b, PAL_NONE }, { 0x63d, PAL_NONE }, { 0x644, PAL_NONE }, { 0x636, PAL_NONE } }, // 25 { { 0x64b, PAL_NONE }, { 0x636, PAL_NONE }, { 0x63d, PAL_NONE }, { 0x628, PAL_NONE } }, // 26 { { 0x64b, PAL_NONE }, { 0x64b, PAL_NONE }, { 0x636, PAL_NONE }, { 0x63d, PAL_NONE } }, // 27 { { 0x62f, PAL_NONE }, { 0x644, PAL_NONE }, { 0x644, PAL_NONE }, { 0x636, PAL_NONE } }, // 28 { { 0x62f, PAL_NONE }, { 0x62f, PAL_NONE }, { 0x636, PAL_NONE }, { 0x628, PAL_NONE } }, // 29 { { 0x62f, PAL_NONE }, { 0x64b, PAL_NONE }, { 0x636, PAL_NONE }, { 0x636, PAL_NONE } }, // 30 { { 0x62f, PAL_NONE }, { 0x636, PAL_NONE }, { 0x62f, PAL_NONE }, { 0x636, PAL_NONE } }, // 31 { { 0x67c, PAL_NONE }, { 0x675, PAL_NONE }, { 0x683, PAL_NONE }, { 0x67c, PAL_NONE } }, // 32 { { 0x67c, PAL_NONE }, { 0x69f, PAL_NONE }, { 0x67c, PAL_NONE }, { 0x659, PAL_NONE } }, // 33 { { 0x67c, PAL_NONE }, { 0x67c, PAL_NONE }, { 0x67c, PAL_NONE }, { 0x6a6, PAL_NONE } }, // 34 { { 0x67c, PAL_NONE }, { 0x691, PAL_NONE }, { 0x66e, PAL_NONE }, { 0x68a, PAL_NONE } }, // 35 { { 0x68a, PAL_NONE }, { 0x68a, PAL_NONE }, { 0x698, PAL_NONE }, { 0x68a, PAL_NONE } }, // 36 { { 0x68a, PAL_NONE }, { 0x698, PAL_NONE }, { 0x683, PAL_NONE }, { 0x68a, PAL_NONE } }, // 37 { { 0x68a, PAL_NONE }, { 0x67c, PAL_NONE }, { 0x691, PAL_NONE }, { 0x68a, PAL_NONE } }, // 38 { { 0x68a, PAL_NONE }, { 0x683, PAL_NONE }, { 0x6a6, PAL_NONE }, { 0x69f, PAL_NONE } }, // 39 { { 0x698, PAL_NONE }, { 0x68a, PAL_NONE }, { 0x698, PAL_NONE }, { 0x652, PAL_NONE } }, // 40 { { 0x698, PAL_NONE }, { 0x698, PAL_NONE }, { 0x660, PAL_NONE }, { 0x667, PAL_NONE } }, // 41 { { 0x698, PAL_NONE }, { 0x67c, PAL_NONE }, { 0x6a6, PAL_NONE }, { 0x698, PAL_NONE } }, // 42 { { 0x698, PAL_NONE }, { 0x698, PAL_NONE }, { 0x698, PAL_NONE }, { 0x691, PAL_NONE } }, // 43 { { 0x6a6, PAL_NONE }, { 0x6a6, PAL_NONE }, { 0x67c, PAL_NONE }, { 0x660, PAL_NONE } }, // 44 { { 0x6a6, PAL_NONE }, { 0x69f, PAL_NONE }, { 0x6a6, PAL_NONE }, { 0x652, PAL_NONE } }, // 45 { { 0x6a6, PAL_NONE }, { 0x67c, PAL_NONE }, { 0x6a6, PAL_NONE }, { 0x691, PAL_NONE } }, // 46 { { 0x6a6, PAL_NONE }, { 0x691, PAL_NONE }, { 0x69f, PAL_NONE }, { 0x6a6, PAL_NONE } }, // 47 { { 0x6ad, PAL_NONE }, { 0x6ad, PAL_NONE }, { 0x6ad, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 48 { { 0x6ad, PAL_NONE }, { 0x6ad, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6d0, PAL_NONE } }, // 49 { { 0x6ad, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6ad, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 50 { { 0x6ad, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6c9, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 51 { { 0x6d0, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 52 { { 0x6d0, PAL_NONE }, { 0x6ad, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6c9, PAL_NONE } }, // 53 { { 0x6d0, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6c2, PAL_NONE } }, // 54 { { 0x6d0, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 55 { { 0x6d7, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6d7, PAL_NONE } }, // 56 { { 0x6d7, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6ad, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 57 { { 0x6d7, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 58 { { 0x6d7, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 59 { { 0x6c2, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6c9, PAL_NONE }, { 0x6c2, PAL_NONE } }, // 60 { { 0x6c2, PAL_NONE }, { 0x6c9, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 61 { { 0x6c2, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 62 { { 0x6c2, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6c9, PAL_NONE } }, // 63 { { 0x6c9, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6b4, PAL_NONE }, { 0x6c2, PAL_NONE } }, // 64 { { 0x6c9, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6d7, PAL_NONE } }, // 65 { { 0x6c9, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6b4, PAL_NONE } }, // 66 { { 0x6c9, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6de, PAL_NONE } }, // 67 { { 0x6b4, PAL_NONE }, { 0x6b4, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6c9, PAL_NONE } }, // 68 { { 0x6b4, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6ad, PAL_NONE } }, // 69 { { 0x6b4, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6b4, PAL_NONE } }, // 70 { { 0x6b4, PAL_NONE }, { 0x6ad, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6de, PAL_NONE } }, // 71 { { 0x6bb, PAL_NONE }, { 0x6d0, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6c2, PAL_NONE } }, // 72 { { 0x6bb, PAL_NONE }, { 0x6b4, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6d7, PAL_NONE } }, // 73 { { 0x6bb, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6b4, PAL_NONE } }, // 74 { { 0x6bb, PAL_NONE }, { 0x6c9, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6de, PAL_NONE } }, // 75 { { 0x6de, PAL_NONE }, { 0x6d7, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6c2, PAL_NONE } }, // 76 { { 0x6de, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6d0, PAL_NONE } }, // 77 { { 0x6de, PAL_NONE }, { 0x6de, PAL_NONE }, { 0x6bb, PAL_NONE }, { 0x6b4, PAL_NONE } }, // 78 { { 0x6de, PAL_NONE }, { 0x6c9, PAL_NONE }, { 0x6c2, PAL_NONE }, { 0x6de, PAL_NONE } }, // 79 { { 0x72b, PAL_NONE }, { 0x732, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x739, PAL_NONE } }, // 80 { { 0x72b, PAL_NONE }, { 0x747, PAL_NONE }, { 0x755, PAL_NONE }, { 0x72b, PAL_NONE } }, // 81 { { 0x72b, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x76a, PAL_NONE }, { 0x786, PAL_NONE } }, // 82 { { 0x72b, PAL_NONE }, { 0x74e, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x72b, PAL_NONE } }, // 83 { { 0x732, PAL_NONE }, { 0x732, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x739, PAL_NONE } }, // 84 { { 0x732, PAL_NONE }, { 0x747, PAL_NONE }, { 0x732, PAL_NONE }, { 0x732, PAL_NONE } }, // 85 { { 0x732, PAL_NONE }, { 0x732, PAL_NONE }, { 0x755, PAL_NONE }, { 0x794, PAL_NONE } }, // 86 { { 0x732, PAL_NONE }, { 0x74e, PAL_NONE }, { 0x732, PAL_NONE }, { 0x78d, PAL_NONE } }, // 87 { { 0x747, PAL_NONE }, { 0x732, PAL_NONE }, { 0x747, PAL_NONE }, { 0x740, PAL_NONE } }, // 88 { { 0x747, PAL_NONE }, { 0x747, PAL_NONE }, { 0x732, PAL_NONE }, { 0x76a, PAL_NONE } }, // 89 { { 0x747, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x755, PAL_NONE }, { 0x747, PAL_NONE } }, // 90 { { 0x747, PAL_NONE }, { 0x786, PAL_NONE }, { 0x732, PAL_NONE }, { 0x747, PAL_NONE } }, // 91 { { 0x74e, PAL_NONE }, { 0x74e, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x794, PAL_NONE } }, // 92 { { 0x74e, PAL_NONE }, { 0x755, PAL_NONE }, { 0x732, PAL_NONE }, { 0x74e, PAL_NONE } }, // 93 { { 0x74e, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x786, PAL_NONE }, { 0x747, PAL_NONE } }, // 94 { { 0x74e, PAL_NONE }, { 0x74e, PAL_NONE }, { 0x732, PAL_NONE }, { 0x794, PAL_NONE } }, // 95 { { 0x76a, PAL_NONE }, { 0x76a, PAL_NONE }, { 0x74e, PAL_NONE }, { 0x74e, PAL_NONE } }, // 96 { { 0x76a, PAL_NONE }, { 0x794, PAL_NONE }, { 0x732, PAL_NONE }, { 0x76a, PAL_NONE } }, // 97 { { 0x76a, PAL_NONE }, { 0x732, PAL_NONE }, { 0x786, PAL_NONE }, { 0x76a, PAL_NONE } }, // 98 { { 0x76a, PAL_NONE }, { 0x786, PAL_NONE }, { 0x732, PAL_NONE }, { 0x78d, PAL_NONE } }, // 99 { { 0x78d, PAL_NONE }, { 0x78d, PAL_NONE }, { 0x74e, PAL_NONE }, { 0x794, PAL_NONE } }, // 100 { { 0x78d, PAL_NONE }, { 0x732, PAL_NONE }, { 0x739, PAL_NONE }, { 0x747, PAL_NONE } }, // 101 { { 0x78d, PAL_NONE }, { 0x732, PAL_NONE }, { 0x786, PAL_NONE }, { 0x76a, PAL_NONE } }, // 102 { { 0x78d, PAL_NONE }, { 0x786, PAL_NONE }, { 0x78d, PAL_NONE }, { 0x794, PAL_NONE } }, // 103 { { 0x786, PAL_NONE }, { 0x786, PAL_NONE }, { 0x740, PAL_NONE }, { 0x732, PAL_NONE } }, // 104 { { 0x786, PAL_NONE }, { 0x786, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x732, PAL_NONE } }, // 105 { { 0x786, PAL_NONE }, { 0x732, PAL_NONE }, { 0x786, PAL_NONE }, { 0x786, PAL_NONE } }, // 106 { { 0x786, PAL_NONE }, { 0x786, PAL_NONE }, { 0x78d, PAL_NONE }, { 0x794, PAL_NONE } }, // 107 { { 0x778, PAL_NONE }, { 0x778, PAL_NONE }, { 0x77f, PAL_NONE }, { 0x778, PAL_NONE } }, // 108 { { 0x778, PAL_NONE }, { 0x77f, PAL_NONE }, { 0x778, PAL_NONE }, { 0x77f, PAL_NONE } }, // 109 { { 0x778, PAL_NONE }, { 0x77f, PAL_NONE }, { 0x77f, PAL_NONE }, { 0x778, PAL_NONE } }, // 110 { { 0x778, PAL_NONE }, { 0x778, PAL_NONE }, { 0x778, PAL_NONE }, { 0x77f, PAL_NONE } }, // 111 { { 0x75c, PAL_NONE }, { 0x71d, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x724, PAL_NONE } }, // 112 { { 0x75c, PAL_NONE }, { 0x72b, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x763, PAL_NONE } }, // 113 { { 0x75c, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x771, PAL_NONE }, { 0x71d, PAL_NONE } }, // 114 { { 0x75c, PAL_NONE }, { 0x771, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x75c, PAL_NONE } }, // 115 { { 0x771, PAL_NONE }, { 0x771, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x71d, PAL_NONE } }, // 116 { { 0x771, PAL_NONE }, { 0x747, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x771, PAL_NONE } }, // 117 { { 0x771, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x771, PAL_NONE }, { 0x724, PAL_NONE } }, // 118 { { 0x771, PAL_NONE }, { 0x771, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x763, PAL_NONE } }, // 119 { { 0x71d, PAL_NONE }, { 0x71d, PAL_NONE }, { 0x771, PAL_NONE }, { 0x724, PAL_NONE } }, // 120 { { 0x71d, PAL_NONE }, { 0x74e, PAL_NONE }, { 0x763, PAL_NONE }, { 0x71d, PAL_NONE } }, // 121 { { 0x71d, PAL_NONE }, { 0x724, PAL_NONE }, { 0x794, PAL_NONE }, { 0x71d, PAL_NONE } }, // 122 { { 0x71d, PAL_NONE }, { 0x71d, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x78d, PAL_NONE } }, // 123 { { 0x794, PAL_NONE }, { 0x724, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x794, PAL_NONE } }, // 124 { { 0x794, PAL_NONE }, { 0x794, PAL_NONE }, { 0x75c, PAL_NONE }, { 0x71d, PAL_NONE } }, // 125 { { 0x794, PAL_NONE }, { 0x724, PAL_NONE }, { 0x794, PAL_NONE }, { 0x71d, PAL_NONE } }, // 126 { { 0x794, PAL_NONE }, { 0x794, PAL_NONE }, { 0x771, PAL_NONE }, { 0x78d, PAL_NONE } }, // 127 { { 0x79b, PALETTE_TO_RED }, { 0x79b, PALETTE_TO_PALE_GREEN }, { 0x79b, PALETTE_TO_MAUVE }, { 0x79b, PALETTE_TO_PURPLE } }, // 128 { { 0x79b, PAL_NONE }, { 0x79b, PALETTE_TO_GREY }, { 0x79b, PALETTE_TO_GREEN }, { 0x79b, PALETTE_TO_WHITE } }, // 129 { { 0x79b, PALETTE_TO_GREEN }, { 0x79b, PALETTE_TO_ORANGE }, { 0x79b, PALETTE_TO_PINK }, { 0x79b, PAL_NONE } }, // 130 { { 0x79b, PALETTE_TO_YELLOW }, { 0x79b, PALETTE_TO_RED }, { 0x79b, PALETTE_TO_CREAM }, { 0x79b, PALETTE_TO_RED } }, // 131 { { 0x7a2, PAL_NONE }, { 0x7a2, PALETTE_TO_RED }, { 0x7a2, PALETTE_TO_PINK }, { 0x7a2, PALETTE_TO_PURPLE } }, // 132 { { 0x7a2, PALETTE_TO_MAUVE }, { 0x7a2, PALETTE_TO_GREEN }, { 0x7a2, PALETTE_TO_PINK }, { 0x7a2, PALETTE_TO_GREY } }, // 133 { { 0x7a2, PALETTE_TO_RED }, { 0x7a2, PALETTE_TO_PALE_GREEN }, { 0x7a2, PALETTE_TO_YELLOW }, { 0x7a2, PALETTE_TO_WHITE } }, // 134 { { 0x7a2, PALETTE_TO_ORANGE }, { 0x7a2, PALETTE_TO_MAUVE }, { 0x7a2, PALETTE_TO_CREAM }, { 0x7a2, PALETTE_TO_BROWN } }, // 135 { { 0x7a9, PALETTE_TO_RED }, { 0x7a9, PAL_NONE }, { 0x7a9, PALETTE_TO_ORANGE }, { 0x7a9, PALETTE_TO_GREY } }, // 136 { { 0x7a9, PALETTE_TO_ORANGE }, { 0x7a9, PALETTE_TO_GREEN }, { 0x7a9, PALETTE_TO_PALE_GREEN }, { 0x7a9, PALETTE_TO_MAUVE } }, // 137 { { 0x7a9, PALETTE_TO_PINK }, { 0x7a9, PALETTE_TO_RED }, { 0x7a9, PALETTE_TO_GREEN }, { 0x7a9, PALETTE_TO_BROWN } }, // 138 { { 0x7a9, PALETTE_TO_GREEN }, { 0x7a9, PAL_NONE }, { 0x7a9, PALETTE_TO_RED }, { 0x7a9, PALETTE_TO_CREAM } }, // 139 { { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE } }, // 140 { { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE } }, // 141 { { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE } }, // 142 { { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE }, { 0x7b0, PAL_NONE } }, // 143 { { 0x7b7, PALETTE_TO_PINK }, { 0x7b7, PALETTE_TO_RED }, { 0x7b7, PALETTE_TO_ORANGE }, { 0x7b7, PALETTE_TO_MAUVE } }, // 144 { { 0x7b7, PALETTE_TO_RED }, { 0x7b7, PAL_NONE }, { 0x7b7, PALETTE_TO_GREY }, { 0x7b7, PALETTE_TO_CREAM } }, // 145 { { 0x7b7, PALETTE_TO_GREEN }, { 0x7b7, PALETTE_TO_BROWN }, { 0x7b7, PALETTE_TO_PINK }, { 0x7b7, PALETTE_TO_RED } }, // 146 { { 0x7b7, PAL_NONE }, { 0x7b7, PALETTE_TO_PALE_GREEN }, { 0x7b7, PALETTE_TO_ORANGE }, { 0x7b7, PALETTE_TO_RED } }, // 147 { { 0x7be, PALETTE_TO_RED }, { 0x7be, PALETTE_TO_PINK }, { 0x7be, PALETTE_TO_GREEN }, { 0x7be, PAL_NONE } }, // 148 { { 0x7be, PALETTE_TO_GREEN }, { 0x7be, PALETTE_TO_BROWN }, { 0x7be, PALETTE_TO_PURPLE }, { 0x7be, PALETTE_TO_GREY } }, // 149 { { 0x7be, PALETTE_TO_MAUVE }, { 0x7be, PALETTE_TO_CREAM }, { 0x7be, PALETTE_TO_ORANGE }, { 0x7be, PALETTE_TO_RED } }, // 150 { { 0x7be, PAL_NONE }, { 0x7be, PALETTE_TO_RED }, { 0x7be, PALETTE_TO_PALE_GREEN }, { 0x7be, PALETTE_TO_PINK } }, // 151 { { 0x7c5, PALETTE_TO_YELLOW }, { 0x7c5, PALETTE_TO_RED }, { 0x7c5, PALETTE_TO_WHITE }, { 0x7c5, PALETTE_TO_CREAM } }, // 152 { { 0x7c5, PALETTE_TO_RED }, { 0x7c5, PALETTE_TO_PALE_GREEN }, { 0x7c5, PALETTE_TO_BROWN }, { 0x7c5, PALETTE_TO_YELLOW } }, // 153 { { 0x7c5, PAL_NONE }, { 0x7c5, PALETTE_TO_PURPLE }, { 0x7c5, PALETTE_TO_GREEN }, { 0x7c5, PALETTE_TO_YELLOW } }, // 154 { { 0x7c5, PALETTE_TO_PINK }, { 0x7c5, PALETTE_TO_CREAM }, { 0x7c5, PAL_NONE }, { 0x7c5, PALETTE_TO_GREY } }, // 155 { { 0x7cc, PALETTE_TO_YELLOW }, { 0x7cc, PALETTE_TO_GREY }, { 0x7cc, PALETTE_TO_PURPLE }, { 0x7cc, PALETTE_TO_BROWN } }, // 156 { { 0x7cc, PALETTE_TO_GREEN }, { 0x7cc, PAL_NONE }, { 0x7cc, PALETTE_TO_CREAM }, { 0x7cc, PALETTE_TO_WHITE } }, // 157 { { 0x7cc, PALETTE_TO_RED }, { 0x7cc, PALETTE_TO_PALE_GREEN }, { 0x7cc, PALETTE_TO_MAUVE }, { 0x7cc, PALETTE_TO_RED } }, // 158 { { 0x7cc, PALETTE_TO_PINK }, { 0x7cc, PALETTE_TO_ORANGE }, { 0x7cc, PALETTE_TO_GREEN }, { 0x7cc, PALETTE_TO_YELLOW } }, // 159 { { 0x7d3, PALETTE_TO_RED }, { 0x7d3, PALETTE_TO_PINK }, { 0x7d3, PALETTE_TO_BROWN }, { 0x7d3, PALETTE_TO_WHITE } }, // 160 { { 0x7d3, PALETTE_TO_GREEN }, { 0x7d3, PALETTE_TO_ORANGE }, { 0x7d3, PALETTE_TO_GREY }, { 0x7d3, PALETTE_TO_MAUVE } }, // 161 { { 0x7d3, PALETTE_TO_YELLOW }, { 0x7d3, PALETTE_TO_PALE_GREEN }, { 0x7d3, PAL_NONE }, { 0x7d3, PALETTE_TO_CREAM } }, // 162 { { 0x7d3, PALETTE_TO_GREY }, { 0x7d3, PALETTE_TO_RED }, { 0x7d3, PALETTE_TO_WHITE }, { 0x7d3, PAL_NONE } }, // 163 /* the extra things follow */ { { 0x6e5, PAL_NONE }, { 0x6e5, PAL_NONE }, { 0x6e5, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 0 { { 0x6e5, PAL_NONE }, { 0x6e5, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x708, PAL_NONE } }, // 1 { { 0x6e5, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x6e5, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 2 { { 0x6e5, PAL_NONE }, { 0x708, PAL_NONE }, { 0x701, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 3 { { 0x708, PAL_NONE }, { 0x708, PAL_NONE }, { 0x708, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 4 { { 0x708, PAL_NONE }, { 0x6e5, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x701, PAL_NONE } }, // 5 { { 0x708, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x708, PAL_NONE }, { 0x6fa, PAL_NONE } }, // 6 { { 0x708, PAL_NONE }, { 0x708, PAL_NONE }, { 0x708, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 7 { { 0x70f, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x70f, PAL_NONE } }, // 8 { { 0x70f, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x6e5, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 9 { { 0x70f, PAL_NONE }, { 0x708, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 10 { { 0x70f, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x708, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 11 { { 0x6fa, PAL_NONE }, { 0x708, PAL_NONE }, { 0x701, PAL_NONE }, { 0x6fa, PAL_NONE } }, // 12 { { 0x6fa, PAL_NONE }, { 0x701, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 13 { { 0x6fa, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 14 { { 0x6fa, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x701, PAL_NONE } }, // 15 { { 0x701, PAL_NONE }, { 0x708, PAL_NONE }, { 0x6ec, PAL_NONE }, { 0x6fa, PAL_NONE } }, // 16 { { 0x701, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x716, PAL_NONE }, { 0x70f, PAL_NONE } }, // 17 { { 0x701, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x6ec, PAL_NONE } }, // 18 { { 0x701, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x716, PAL_NONE } }, // 19 { { 0x6ec, PAL_NONE }, { 0x6ec, PAL_NONE }, { 0x716, PAL_NONE }, { 0x701, PAL_NONE } }, // 20 { { 0x6ec, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x6e5, PAL_NONE } }, // 21 { { 0x6ec, PAL_NONE }, { 0x716, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x6ec, PAL_NONE } }, // 22 { { 0x6ec, PAL_NONE }, { 0x6e5, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x716, PAL_NONE } }, // 23 { { 0x6f3, PAL_NONE }, { 0x708, PAL_NONE }, { 0x716, PAL_NONE }, { 0x6fa, PAL_NONE } }, // 24 { { 0x6f3, PAL_NONE }, { 0x6ec, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x70f, PAL_NONE } }, // 25 { { 0x6f3, PAL_NONE }, { 0x716, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x6ec, PAL_NONE } }, // 26 { { 0x6f3, PAL_NONE }, { 0x701, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x716, PAL_NONE } }, // 27 { { 0x716, PAL_NONE }, { 0x70f, PAL_NONE }, { 0x716, PAL_NONE }, { 0x6fa, PAL_NONE } }, // 28 { { 0x716, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x716, PAL_NONE }, { 0x708, PAL_NONE } }, // 29 { { 0x716, PAL_NONE }, { 0x716, PAL_NONE }, { 0x6f3, PAL_NONE }, { 0x6ec, PAL_NONE } }, // 30 { { 0x716, PAL_NONE }, { 0x701, PAL_NONE }, { 0x6fa, PAL_NONE }, { 0x716, PAL_NONE } }, // 31 }; #endif /* TREE_LAND_H */ openttd-1.5.3/src/table/railtypes.h0000644000000000000000000001740112627373436015756 0ustar rootroot/* $Id: railtypes.h 24368 2012-07-02 15:55:13Z frosch $ */ /* * 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 railtypes.h * All the railtype-specific information is stored here. */ #ifndef RAILTYPES_H #define RAILTYPES_H /** * Global Railtype definition */ static const RailtypeInfo _original_railtypes[] = { /** Railway */ { // Main Sprites { SPR_RAIL_TRACK_Y, SPR_RAIL_TRACK_N_S, SPR_RAIL_TRACK_BASE, SPR_RAIL_SINGLE_X, SPR_RAIL_SINGLE_Y, SPR_RAIL_SINGLE_NORTH, SPR_RAIL_SINGLE_SOUTH, SPR_RAIL_SINGLE_EAST, SPR_RAIL_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_RAIL_BASE, SPR_CROSSING_OFF_X_RAIL, SPR_TUNNEL_ENTRY_REAR_RAIL }, /* GUI sprites */ { 0x4E3, 0x4E4, 0x4E5, 0x4E6, SPR_IMG_AUTORAIL, SPR_IMG_DEPOT_RAIL, SPR_IMG_TUNNEL_RAIL, SPR_IMG_CONVERT_RAIL, {} }, { SPR_CURSOR_NS_TRACK, SPR_CURSOR_SWNE_TRACK, SPR_CURSOR_EW_TRACK, SPR_CURSOR_NWSE_TRACK, SPR_CURSOR_AUTORAIL, SPR_CURSOR_RAIL_DEPOT, SPR_CURSOR_TUNNEL_RAIL, SPR_CURSOR_CONVERT_RAIL }, /* strings */ { STR_RAIL_NAME_RAILROAD, STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION, STR_RAIL_MENU_RAILROAD_CONSTRUCTION, STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION, STR_REPLACE_RAIL_VEHICLES, STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE, }, /* Offset of snow tiles */ SPR_RAIL_SNOW_OFFSET, /* Powered railtypes */ RAILTYPES_RAIL | RAILTYPES_ELECTRIC, /* Compatible railtypes */ RAILTYPES_RAIL | RAILTYPES_ELECTRIC, /* bridge offset */ 0, /* fallback_railtype */ 0, /* curve speed advantage (multiplier) */ 0, /* flags */ RTFB_NONE, /* cost multiplier */ 8, /* maintenance cost multiplier */ 8, /* acceleration type */ 0, /* max speed */ 0, /* rail type label */ 'RAIL', /* alternate labels */ RailTypeLabelList(), /* map colour */ 0x0A, /* introduction date */ INVALID_DATE, /* railtypes required for this to be introduced */ RAILTYPES_NONE, /* introduction rail types */ RAILTYPES_RAIL, /* sort order */ 0 << 4 | 7, { NULL }, { NULL }, }, /** Electrified railway */ { // Main Sprites { SPR_RAIL_TRACK_Y, SPR_RAIL_TRACK_N_S, SPR_RAIL_TRACK_BASE, SPR_RAIL_SINGLE_X, SPR_RAIL_SINGLE_Y, SPR_RAIL_SINGLE_NORTH, SPR_RAIL_SINGLE_SOUTH, SPR_RAIL_SINGLE_EAST, SPR_RAIL_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_RAIL_BASE, SPR_CROSSING_OFF_X_RAIL, SPR_TUNNEL_ENTRY_REAR_RAIL }, /* GUI sprites */ { SPR_BUILD_NS_ELRAIL, SPR_BUILD_X_ELRAIL, SPR_BUILD_EW_ELRAIL, SPR_BUILD_Y_ELRAIL, SPR_IMG_AUTOELRAIL, SPR_IMG_DEPOT_ELRAIL, SPR_BUILD_TUNNEL_ELRAIL, SPR_IMG_CONVERT_ELRAIL, {} }, { SPR_CURSOR_NS_ELRAIL, SPR_CURSOR_SWNE_ELRAIL, SPR_CURSOR_EW_ELRAIL, SPR_CURSOR_NWSE_ELRAIL, SPR_CURSOR_AUTOELRAIL, SPR_CURSOR_ELRAIL_DEPOT, SPR_CURSOR_TUNNEL_ELRAIL, SPR_CURSOR_CONVERT_ELRAIL }, /* strings */ { STR_RAIL_NAME_ELRAIL, STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION, STR_RAIL_MENU_ELRAIL_CONSTRUCTION, STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION, STR_REPLACE_ELRAIL_VEHICLES, STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE, }, /* Offset of snow tiles */ SPR_RAIL_SNOW_OFFSET, /* Powered railtypes */ RAILTYPES_ELECTRIC, /* Compatible railtypes */ RAILTYPES_ELECTRIC | RAILTYPES_RAIL, /* bridge offset */ 0, /* fallback_railtype */ 0, /* curve speed advantage (multiplier) */ 0, /* flags */ RTFB_CATENARY, /* cost multiplier */ 12, /* maintenance cost multiplier */ 12, /* acceleration type */ 0, /* max speed */ 0, /* rail type label */ 'ELRL', /* alternate labels */ RailTypeLabelList(), /* map colour */ 0x0A, /* introduction date */ INVALID_DATE, /* railtypes required for this to be introduced */ RAILTYPES_NONE, /* introduction rail types */ RAILTYPES_ELECTRIC, /* sort order */ 1 << 4 | 7, { NULL }, { NULL }, }, /** Monorail */ { // Main Sprites { SPR_MONO_TRACK_Y, SPR_MONO_TRACK_N_S, SPR_MONO_TRACK_BASE, SPR_MONO_SINGLE_X, SPR_MONO_SINGLE_Y, SPR_MONO_SINGLE_NORTH, SPR_MONO_SINGLE_SOUTH, SPR_MONO_SINGLE_EAST, SPR_MONO_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_MONO_BASE, SPR_CROSSING_OFF_X_MONO, SPR_TUNNEL_ENTRY_REAR_MONO }, /* GUI sprites */ { 0x4E7, 0x4E8, 0x4E9, 0x4EA, SPR_IMG_AUTOMONO, SPR_IMG_DEPOT_MONO, SPR_IMG_TUNNEL_MONO, SPR_IMG_CONVERT_MONO, {} }, { SPR_CURSOR_NS_MONO, SPR_CURSOR_SWNE_MONO, SPR_CURSOR_EW_MONO, SPR_CURSOR_NWSE_MONO, SPR_CURSOR_AUTOMONO, SPR_CURSOR_MONO_DEPOT, SPR_CURSOR_TUNNEL_MONO, SPR_CURSOR_CONVERT_MONO }, /* strings */ { STR_RAIL_NAME_MONORAIL, STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION, STR_RAIL_MENU_MONORAIL_CONSTRUCTION, STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION, STR_REPLACE_MONORAIL_VEHICLES, STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE, }, /* Offset of snow tiles */ SPR_MONO_SNOW_OFFSET, /* Powered railtypes */ RAILTYPES_MONO, /* Compatible Railtypes */ RAILTYPES_MONO, /* bridge offset */ 16, /* fallback_railtype */ 1, /* curve speed advantage (multiplier) */ 1, /* flags */ RTFB_NONE, /* cost multiplier */ 16, /* maintenance cost multiplier */ 16, /* acceleration type */ 1, /* max speed */ 0, /* rail type label */ 'MONO', /* alternate labels */ RailTypeLabelList(), /* map colour */ 0x0A, /* introduction date */ INVALID_DATE, /* railtypes required for this to be introduced */ RAILTYPES_NONE, /* introduction rail types */ RAILTYPES_MONO, /* sort order */ 2 << 4 | 7, { NULL }, { NULL }, }, /** Maglev */ { // Main sprites { SPR_MGLV_TRACK_Y, SPR_MGLV_TRACK_N_S, SPR_MGLV_TRACK_BASE, SPR_MGLV_SINGLE_X, SPR_MGLV_SINGLE_Y, SPR_MGLV_SINGLE_NORTH, SPR_MGLV_SINGLE_SOUTH, SPR_MGLV_SINGLE_EAST, SPR_MGLV_SINGLE_WEST, SPR_TRACKS_FOR_SLOPES_MAGLEV_BASE, SPR_CROSSING_OFF_X_MAGLEV, SPR_TUNNEL_ENTRY_REAR_MAGLEV }, /* GUI sprites */ { 0x4EB, 0x4EC, 0x4EE, 0x4ED, SPR_IMG_AUTOMAGLEV, SPR_IMG_DEPOT_MAGLEV, SPR_IMG_TUNNEL_MAGLEV, SPR_IMG_CONVERT_MAGLEV, {} }, { SPR_CURSOR_NS_MAGLEV, SPR_CURSOR_SWNE_MAGLEV, SPR_CURSOR_EW_MAGLEV, SPR_CURSOR_NWSE_MAGLEV, SPR_CURSOR_AUTOMAGLEV, SPR_CURSOR_MAGLEV_DEPOT, SPR_CURSOR_TUNNEL_MAGLEV, SPR_CURSOR_CONVERT_MAGLEV }, /* strings */ { STR_RAIL_NAME_MAGLEV, STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION, STR_RAIL_MENU_MAGLEV_CONSTRUCTION, STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION, STR_REPLACE_MAGLEV_VEHICLES, STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE, }, /* Offset of snow tiles */ SPR_MGLV_SNOW_OFFSET, /* Powered railtypes */ RAILTYPES_MAGLEV, /* Compatible Railtypes */ RAILTYPES_MAGLEV, /* bridge offset */ 24, /* fallback_railtype */ 2, /* curve speed advantage (multiplier) */ 2, /* flags */ RTFB_NONE, /* cost multiplier */ 24, /* maintenance cost multiplier */ 24, /* acceleration type */ 2, /* max speed */ 0, /* rail type label */ 'MGLV', /* alternate labels */ RailTypeLabelList(), /* map colour */ 0x0A, /* introduction date */ INVALID_DATE, /* railtypes required for this to be introduced */ RAILTYPES_NONE, /* introduction rail types */ RAILTYPES_MAGLEV, /* sort order */ 3 << 4 | 7, { NULL }, { NULL }, }, }; #endif /* RAILTYPES_H */ openttd-1.5.3/src/table/company_settings.ini0000644000000000000000000001011112627373436017647 0ustar rootroot; $Id: company_settings.ini 24996 2013-02-14 17:08:56Z rubidium $ ; ; 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 . ; [pre-amble] static bool CheckInterval(int32 p1); static bool InvalidateDetailsWindow(int32 p1); static bool UpdateIntervalTrains(int32 p1); static bool UpdateIntervalRoadVeh(int32 p1); static bool UpdateIntervalShips(int32 p1); static bool UpdateIntervalAircraft(int32 p1); static const SettingDesc _company_settings[] = { [post-amble] }; [templates] SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_END = SDT_END() [defaults] flags = 0 guiflags = SGF_PER_COMPANY interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = NULL load = NULL from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED [SDT_BOOL] base = CompanySettings var = engine_renew def = false str = STR_CONFIG_SETTING_AUTORENEW_VEHICLE strhelp = STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT [SDT_VAR] base = CompanySettings var = engine_renew_months type = SLE_INT16 guiflags = SGF_PER_COMPANY | SGF_DISPLAY_ABS def = 6 min = -12 max = 12 str = STR_CONFIG_SETTING_AUTORENEW_MONTHS strhelp = STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT strval = STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE [SDT_VAR] base = CompanySettings var = engine_renew_money type = SLE_UINT guiflags = SGF_PER_COMPANY | SGF_CURRENCY def = 100000 min = 0 max = 2000000 str = STR_CONFIG_SETTING_AUTORENEW_MONEY strhelp = STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT strval = STR_JUST_CURRENCY_LONG [SDT_BOOL] base = CompanySettings var = renew_keep_length def = false [SDT_BOOL] base = CompanySettings var = vehicle.servint_ispercent def = false str = STR_CONFIG_SETTING_SERVINT_ISPERCENT strhelp = STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT proc = CheckInterval [SDT_VAR] base = CompanySettings var = vehicle.servint_trains type = SLE_UINT16 guiflags = SGF_PER_COMPANY | SGF_0ISDISABLED def = 150 min = 5 max = 800 str = STR_CONFIG_SETTING_SERVINT_TRAINS strhelp = STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT strval = STR_CONFIG_SETTING_SERVINT_VALUE proc = UpdateIntervalTrains [SDT_VAR] base = CompanySettings var = vehicle.servint_roadveh type = SLE_UINT16 guiflags = SGF_PER_COMPANY | SGF_0ISDISABLED def = 150 min = 5 max = 800 str = STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES strhelp = STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT strval = STR_CONFIG_SETTING_SERVINT_VALUE proc = UpdateIntervalRoadVeh [SDT_VAR] base = CompanySettings var = vehicle.servint_ships type = SLE_UINT16 guiflags = SGF_PER_COMPANY | SGF_0ISDISABLED def = 360 min = 5 max = 800 str = STR_CONFIG_SETTING_SERVINT_SHIPS strhelp = STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT strval = STR_CONFIG_SETTING_SERVINT_VALUE proc = UpdateIntervalShips [SDT_VAR] base = CompanySettings var = vehicle.servint_aircraft type = SLE_UINT16 guiflags = SGF_PER_COMPANY | SGF_0ISDISABLED def = 100 min = 5 max = 800 str = STR_CONFIG_SETTING_SERVINT_AIRCRAFT strhelp = STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT strval = STR_CONFIG_SETTING_SERVINT_VALUE proc = UpdateIntervalAircraft [SDT_END] }; openttd-1.5.3/src/table/airporttiles.h0000644000000000000000000000464612627373436016472 0ustar rootroot/* $Id: airporttiles.h 20623 2010-08-26 15:31:40Z rubidium $ */ /* * 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 airporttiles.h Tables with airporttile defaults. */ #ifndef AIRPORTTILES_H #define AIRPORTTILES_H /** Writes all airport tile properties in the AirportTile struct */ #define AT(num_frames, anim_speed) {{num_frames, ANIM_STATUS_LOOPING, anim_speed, 0}, STR_NULL, 0, 0, true, GRFFileProps(INVALID_AIRPORTTILE)} /** Writes an airport tile without animation in the AirportTile struct */ #define AT_NOANIM {{0, ANIM_STATUS_NO_ANIMATION, 2, 0}, STR_NULL, 0, 0, true, GRFFileProps(INVALID_AIRPORTTILE)} /** * All default airport tiles. * @see AirportTiles for a list of names. */ static const AirportTileSpec _origin_airporttile_specs[] = { /* 0..9 */ AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT(11, 2), // APT_RADAR_GRASS_FENCE_SW AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT(3, 1), // APT_GRASS_FENCE_NE_FLAG AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT(11, 2), // APT_RADAR_FENCE_SW AT(11, 2), // APT_RADAR_FENCE_NE AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT_NOANIM, AT(3, 1), // APT_GRASS_FENCE_NE_FLAG_2 }; assert_compile(NEW_AIRPORTTILE_OFFSET == lengthof(_origin_airporttile_specs)); #undef AT_NOANIM #undef AT #endif /* AIRPORTTILES_H */ openttd-1.5.3/src/table/bridge_land.h0000644000000000000000000016525612627373436016210 0ustar rootroot/* $Id: bridge_land.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 bridge_land.h This file contains all the sprites for bridges * It consists of a number of arrays. *
  • _bridge_sprite_table_n_m. Defines all the sprites of a bridge besides the pylons. * n defines the number of the bridge type, m the number of the section. the highest m for * each bridge set defines the heads.
    * Sprites for middle sections are arranged in groups of four, the elements are: *
    1. Element containing the track. This element is logically behind the vehicle.
    2. *
    3. Element containing the structure that is logically between the vehicle and the camera
    4. *
    5. Element containing the pylons.
    * First group is for railway in X direction, second for railway in Y direction, two groups each follow for road, monorail and maglev

    *
    Elements for heads are arranged in groups of eight: *

    1. X direction, north end, flat
    2. *
    3. Y direction, north end, flat
    4. *
    5. X direction, south end, flat
    6. *
    7. Y direction, south end, flat
    8. *
    9. X direction, north end, sloped
    10. *
    11. Y direction, north end, sloped
    12. *
    13. X direction, south end, sloped
    14. *
    15. Y direction, south end, sloped
    * This is repeated 4 times, for rail, road, monorail, maglev
  • *
*/ # define MN(a) {a, PAL_NONE} # define MR(a) {a, PALETTE_TO_STRUCT_RED} # define MW(a) {a, PALETTE_TO_STRUCT_WHITE} # define MC(a) {a, PALETTE_TO_STRUCT_CONCRETE} static const PalSpriteID _aqueduct_sprites[] = { { SPR_AQUEDUCT_MIDDLE_X, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_X, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_MIDDLE_Y, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_PILLAR_Y, PAL_NONE }, { 0x0, PAL_NONE }, { SPR_AQUEDUCT_RAMP_SW, PAL_NONE }, { SPR_AQUEDUCT_RAMP_SE, PAL_NONE }, { SPR_AQUEDUCT_RAMP_NE, PAL_NONE }, { SPR_AQUEDUCT_RAMP_NW, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_4_0[] = { { 0x9A9, PAL_NONE }, { 0x99F, PAL_NONE }, { 0x9B1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9A5, PAL_NONE }, { 0x997, PAL_NONE }, { 0x9AD, PAL_NONE }, { 0x0, PAL_NONE }, { 0x99D, PAL_NONE }, { 0x99F, PAL_NONE }, { 0x9B1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x995, PAL_NONE }, { 0x997, PAL_NONE }, { 0x9AD, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F2, PAL_NONE }, { 0x99F, PAL_NONE }, { 0x9B1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10EE, PAL_NONE }, { 0x997, PAL_NONE }, { 0x9AD, PAL_NONE }, { 0x0, PAL_NONE }, { 0x111A, PAL_NONE }, { 0x99F, PAL_NONE }, { 0x9B1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1116, PAL_NONE }, { 0x997, PAL_NONE }, { 0x9AD, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_4_1[] = { { 0x9AA, PAL_NONE }, { 0x9A0, PAL_NONE }, { 0x9B2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9A6, PAL_NONE }, { 0x998, PAL_NONE }, { 0x9AE, PAL_NONE }, { 0x0, PAL_NONE }, { 0x99E, PAL_NONE }, { 0x9A0, PAL_NONE }, { 0x9B2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x996, PAL_NONE }, { 0x998, PAL_NONE }, { 0x9AE, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F3, PAL_NONE }, { 0x9A0, PAL_NONE }, { 0x9B2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10EF, PAL_NONE }, { 0x998, PAL_NONE }, { 0x9AE, PAL_NONE }, { 0x0, PAL_NONE }, { 0x111B, PAL_NONE }, { 0x9A0, PAL_NONE }, { 0x9B2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1117, PAL_NONE }, { 0x998, PAL_NONE }, { 0x9AE, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_4_2[] = { { 0x9AC, PAL_NONE }, { 0x9A4, PAL_NONE }, { 0x9B4, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9A8, PAL_NONE }, { 0x99C, PAL_NONE }, { 0x9B0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9A2, PAL_NONE }, { 0x9A4, PAL_NONE }, { 0x9B4, PAL_NONE }, { 0x0, PAL_NONE }, { 0x99A, PAL_NONE }, { 0x99C, PAL_NONE }, { 0x9B0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F5, PAL_NONE }, { 0x9A4, PAL_NONE }, { 0x9B4, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F1, PAL_NONE }, { 0x99C, PAL_NONE }, { 0x9B0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x111D, PAL_NONE }, { 0x9A4, PAL_NONE }, { 0x9B4, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1119, PAL_NONE }, { 0x99C, PAL_NONE }, { 0x9B0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_4_3[] = { { 0x9AB, PAL_NONE }, { 0x9A3, PAL_NONE }, { 0x9B3, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9A7, PAL_NONE }, { 0x99B, PAL_NONE }, { 0x9AF, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9A1, PAL_NONE }, { 0x9A3, PAL_NONE }, { 0x9B3, PAL_NONE }, { 0x0, PAL_NONE }, { 0x999, PAL_NONE }, { 0x99B, PAL_NONE }, { 0x9AF, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F4, PAL_NONE }, { 0x9A3, PAL_NONE }, { 0x9B3, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F0, PAL_NONE }, { 0x99B, PAL_NONE }, { 0x9AF, PAL_NONE }, { 0x0, PAL_NONE }, { 0x111C, PAL_NONE }, { 0x9A3, PAL_NONE }, { 0x9B3, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1118, PAL_NONE }, { 0x99B, PAL_NONE }, { 0x9AF, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_4_4[] = { { 0x9B6, PAL_NONE }, { 0x9BA, PAL_NONE }, { 0x9BC, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9B5, PAL_NONE }, { 0x9B9, PAL_NONE }, { 0x9BB, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9B8, PAL_NONE }, { 0x9BA, PAL_NONE }, { 0x9BC, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9B7, PAL_NONE }, { 0x9B9, PAL_NONE }, { 0x9BB, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F7, PAL_NONE }, { 0x9BA, PAL_NONE }, { 0x9BC, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F6, PAL_NONE }, { 0x9B9, PAL_NONE }, { 0x9BB, PAL_NONE }, { 0x0, PAL_NONE }, { 0x111F, PAL_NONE }, { 0x9BA, PAL_NONE }, { 0x9BC, PAL_NONE }, { 0x0, PAL_NONE }, { 0x111E, PAL_NONE }, { 0x9B9, PAL_NONE }, { 0x9BB, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_4_5[] = { { 0x9BD, PAL_NONE }, { 0x9C1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9BE, PAL_NONE }, { 0x9C2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9BF, PAL_NONE }, { 0x9C1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9C0, PAL_NONE }, { 0x9C2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F8, PAL_NONE }, { 0x9C1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F9, PAL_NONE }, { 0x9C2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1120, PAL_NONE }, { 0x9C1, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1121, PAL_NONE }, { 0x9C2, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_4_6[] = { { 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE }, { 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE }, { 0x98E, PAL_NONE }, { 0x990, PAL_NONE }, { 0x98D, PAL_NONE }, { 0x98F, PAL_NONE }, { 0x992, PAL_NONE }, { 0x994, PAL_NONE }, { 0x991, PAL_NONE }, { 0x993, PAL_NONE }, { 0x10E7, PAL_NONE }, { 0x10E9, PAL_NONE }, { 0x10E6, PAL_NONE }, { 0x10E8, PAL_NONE }, { 0x10EB, PAL_NONE }, { 0x10ED, PAL_NONE }, { 0x10EA, PAL_NONE }, { 0x10EC, PAL_NONE }, { 0x110F, PAL_NONE }, { 0x1111, PAL_NONE }, { 0x110E, PAL_NONE }, { 0x1110, PAL_NONE }, { 0x1113, PAL_NONE }, { 0x1115, PAL_NONE }, { 0x1112, PAL_NONE }, { 0x1114, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_5_0[] = { { 0x9A9, PALETTE_TO_STRUCT_YELLOW }, { 0x99F, PALETTE_TO_STRUCT_YELLOW }, { 0x9B1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9A5, PALETTE_TO_STRUCT_YELLOW }, { 0x997, PALETTE_TO_STRUCT_YELLOW }, { 0x9AD, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x99D, PALETTE_TO_STRUCT_YELLOW }, { 0x99F, PALETTE_TO_STRUCT_YELLOW }, { 0x9B1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x995, PALETTE_TO_STRUCT_YELLOW }, { 0x997, PALETTE_TO_STRUCT_YELLOW }, { 0x9AD, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F2, PALETTE_TO_STRUCT_YELLOW }, { 0x99F, PALETTE_TO_STRUCT_YELLOW }, { 0x9B1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10EE, PALETTE_TO_STRUCT_YELLOW }, { 0x997, PALETTE_TO_STRUCT_YELLOW }, { 0x9AD, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x111A, PALETTE_TO_STRUCT_YELLOW }, { 0x99F, PALETTE_TO_STRUCT_YELLOW }, { 0x9B1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x1116, PALETTE_TO_STRUCT_YELLOW }, { 0x997, PALETTE_TO_STRUCT_YELLOW }, { 0x9AD, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_5_1[] = { { 0x9AA, PALETTE_TO_STRUCT_YELLOW }, { 0x9A0, PALETTE_TO_STRUCT_YELLOW }, { 0x9B2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9A6, PALETTE_TO_STRUCT_YELLOW }, { 0x998, PALETTE_TO_STRUCT_YELLOW }, { 0x9AE, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x99E, PALETTE_TO_STRUCT_YELLOW }, { 0x9A0, PALETTE_TO_STRUCT_YELLOW }, { 0x9B2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x996, PALETTE_TO_STRUCT_YELLOW }, { 0x998, PALETTE_TO_STRUCT_YELLOW }, { 0x9AE, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F3, PALETTE_TO_STRUCT_YELLOW }, { 0x9A0, PALETTE_TO_STRUCT_YELLOW }, { 0x9B2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10EF, PALETTE_TO_STRUCT_YELLOW }, { 0x998, PALETTE_TO_STRUCT_YELLOW }, { 0x9AE, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x111B, PALETTE_TO_STRUCT_YELLOW }, { 0x9A0, PALETTE_TO_STRUCT_YELLOW }, { 0x9B2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x1117, PALETTE_TO_STRUCT_YELLOW }, { 0x998, PALETTE_TO_STRUCT_YELLOW }, { 0x9AE, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_5_2[] = { { 0x9AC, PALETTE_TO_STRUCT_YELLOW }, { 0x9A4, PALETTE_TO_STRUCT_YELLOW }, { 0x9B4, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9A8, PALETTE_TO_STRUCT_YELLOW }, { 0x99C, PALETTE_TO_STRUCT_YELLOW }, { 0x9B0, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9A2, PALETTE_TO_STRUCT_YELLOW }, { 0x9A4, PALETTE_TO_STRUCT_YELLOW }, { 0x9B4, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x99A, PALETTE_TO_STRUCT_YELLOW }, { 0x99C, PALETTE_TO_STRUCT_YELLOW }, { 0x9B0, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F5, PALETTE_TO_STRUCT_YELLOW }, { 0x9A4, PALETTE_TO_STRUCT_YELLOW }, { 0x9B4, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F1, PALETTE_TO_STRUCT_YELLOW }, { 0x99C, PALETTE_TO_STRUCT_YELLOW }, { 0x9B0, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x111D, PALETTE_TO_STRUCT_YELLOW }, { 0x9A4, PALETTE_TO_STRUCT_YELLOW }, { 0x9B4, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x1119, PALETTE_TO_STRUCT_YELLOW }, { 0x99C, PALETTE_TO_STRUCT_YELLOW }, { 0x9B0, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_5_3[] = { { 0x9AB, PALETTE_TO_STRUCT_YELLOW }, { 0x9A3, PALETTE_TO_STRUCT_YELLOW }, { 0x9B3, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9A7, PALETTE_TO_STRUCT_YELLOW }, { 0x99B, PALETTE_TO_STRUCT_YELLOW }, { 0x9AF, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9A1, PALETTE_TO_STRUCT_YELLOW }, { 0x9A3, PALETTE_TO_STRUCT_YELLOW }, { 0x9B3, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x999, PALETTE_TO_STRUCT_YELLOW }, { 0x99B, PALETTE_TO_STRUCT_YELLOW }, { 0x9AF, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F4, PALETTE_TO_STRUCT_YELLOW }, { 0x9A3, PALETTE_TO_STRUCT_YELLOW }, { 0x9B3, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F0, PALETTE_TO_STRUCT_YELLOW }, { 0x99B, PALETTE_TO_STRUCT_YELLOW }, { 0x9AF, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x111C, PALETTE_TO_STRUCT_YELLOW }, { 0x9A3, PALETTE_TO_STRUCT_YELLOW }, { 0x9B3, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x1118, PALETTE_TO_STRUCT_YELLOW }, { 0x99B, PALETTE_TO_STRUCT_YELLOW }, { 0x9AF, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_5_4[] = { { 0x9B6, PALETTE_TO_STRUCT_YELLOW }, { 0x9BA, PALETTE_TO_STRUCT_YELLOW }, { 0x9BC, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9B5, PALETTE_TO_STRUCT_YELLOW }, { 0x9B9, PALETTE_TO_STRUCT_YELLOW }, { 0x9BB, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9B8, PALETTE_TO_STRUCT_YELLOW }, { 0x9BA, PALETTE_TO_STRUCT_YELLOW }, { 0x9BC, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x9B7, PALETTE_TO_STRUCT_YELLOW }, { 0x9B9, PALETTE_TO_STRUCT_YELLOW }, { 0x9BB, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F7, PALETTE_TO_STRUCT_YELLOW }, { 0x9BA, PALETTE_TO_STRUCT_YELLOW }, { 0x9BC, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x10F6, PALETTE_TO_STRUCT_YELLOW }, { 0x9B9, PALETTE_TO_STRUCT_YELLOW }, { 0x9BB, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x111F, PALETTE_TO_STRUCT_YELLOW }, { 0x9BA, PALETTE_TO_STRUCT_YELLOW }, { 0x9BC, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x111E, PALETTE_TO_STRUCT_YELLOW }, { 0x9B9, PALETTE_TO_STRUCT_YELLOW }, { 0x9BB, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_5_5[] = { { 0x9BD, PALETTE_TO_STRUCT_YELLOW }, { 0x9C1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9BE, PALETTE_TO_STRUCT_YELLOW }, { 0x9C2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9BF, PALETTE_TO_STRUCT_YELLOW }, { 0x9C1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9C0, PALETTE_TO_STRUCT_YELLOW }, { 0x9C2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F8, PALETTE_TO_STRUCT_YELLOW }, { 0x9C1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10F9, PALETTE_TO_STRUCT_YELLOW }, { 0x9C2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1120, PALETTE_TO_STRUCT_YELLOW }, { 0x9C1, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1121, PALETTE_TO_STRUCT_YELLOW }, { 0x9C2, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_5_6[] = { { 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE }, { 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE }, { 0x98E, PALETTE_TO_STRUCT_YELLOW }, { 0x990, PALETTE_TO_STRUCT_YELLOW }, { 0x98D, PALETTE_TO_STRUCT_YELLOW }, { 0x98F, PALETTE_TO_STRUCT_YELLOW }, { 0x992, PALETTE_TO_STRUCT_YELLOW }, { 0x994, PALETTE_TO_STRUCT_YELLOW }, { 0x991, PALETTE_TO_STRUCT_YELLOW }, { 0x993, PALETTE_TO_STRUCT_YELLOW }, { 0x10E7, PALETTE_TO_STRUCT_YELLOW }, { 0x10E9, PALETTE_TO_STRUCT_YELLOW }, { 0x10E6, PALETTE_TO_STRUCT_YELLOW }, { 0x10E8, PALETTE_TO_STRUCT_YELLOW }, { 0x10EB, PALETTE_TO_STRUCT_YELLOW }, { 0x10ED, PALETTE_TO_STRUCT_YELLOW }, { 0x10EA, PALETTE_TO_STRUCT_YELLOW }, { 0x10EC, PALETTE_TO_STRUCT_YELLOW }, { 0x110F, PALETTE_TO_STRUCT_YELLOW }, { 0x1111, PALETTE_TO_STRUCT_YELLOW }, { 0x110E, PALETTE_TO_STRUCT_YELLOW }, { 0x1110, PALETTE_TO_STRUCT_YELLOW }, { 0x1113, PALETTE_TO_STRUCT_YELLOW }, { 0x1115, PALETTE_TO_STRUCT_YELLOW }, { 0x1112, PALETTE_TO_STRUCT_YELLOW }, { 0x1114, PALETTE_TO_STRUCT_YELLOW }, }; static const PalSpriteID _bridge_sprite_table_6_0[] = { { 0x9CD, PAL_NONE }, { 0x9D9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9CE, PAL_NONE }, { 0x9DA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D3, PAL_NONE }, { 0x9D9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D4, PAL_NONE }, { 0x9DA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FC, PAL_NONE }, { 0x9D9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FD, PAL_NONE }, { 0x9DA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1124, PAL_NONE }, { 0x9D9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1125, PAL_NONE }, { 0x9DA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_6_1[] = { { 0x9CB, PAL_NONE }, { 0x9D7, PAL_NONE }, { 0x9DD, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D0, PAL_NONE }, { 0x9DC, PAL_NONE }, { 0x9E0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D1, PAL_NONE }, { 0x9D7, PAL_NONE }, { 0x9DD, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D6, PAL_NONE }, { 0x9DC, PAL_NONE }, { 0x9E0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FA, PAL_NONE }, { 0x9D7, PAL_NONE }, { 0x9DD, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FF, PAL_NONE }, { 0x9DC, PAL_NONE }, { 0x9E0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1122, PAL_NONE }, { 0x9D7, PAL_NONE }, { 0x9DD, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1127, PAL_NONE }, { 0x9DC, PAL_NONE }, { 0x9E0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_6_2[] = { { 0x9CC, PAL_NONE }, { 0x9D8, PAL_NONE }, { 0x9DE, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9CF, PAL_NONE }, { 0x9DB, PAL_NONE }, { 0x9DF, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D2, PAL_NONE }, { 0x9D8, PAL_NONE }, { 0x9DE, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D5, PAL_NONE }, { 0x9DB, PAL_NONE }, { 0x9DF, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FB, PAL_NONE }, { 0x9D8, PAL_NONE }, { 0x9DE, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FE, PAL_NONE }, { 0x9DB, PAL_NONE }, { 0x9DF, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1123, PAL_NONE }, { 0x9D8, PAL_NONE }, { 0x9DE, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1126, PAL_NONE }, { 0x9DB, PAL_NONE }, { 0x9DF, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_6_3[] = { { 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE }, { 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE }, { 0x98E, PAL_NONE }, { 0x990, PAL_NONE }, { 0x98D, PAL_NONE }, { 0x98F, PAL_NONE }, { 0x992, PAL_NONE }, { 0x994, PAL_NONE }, { 0x991, PAL_NONE }, { 0x993, PAL_NONE }, { 0x10E7, PAL_NONE }, { 0x10E9, PAL_NONE }, { 0x10E6, PAL_NONE }, { 0x10E8, PAL_NONE }, { 0x10EB, PAL_NONE }, { 0x10ED, PAL_NONE }, { 0x10EA, PAL_NONE }, { 0x10EC, PAL_NONE }, { 0x110F, PAL_NONE }, { 0x1111, PAL_NONE }, { 0x110E, PAL_NONE }, { 0x1110, PAL_NONE }, { 0x1113, PAL_NONE }, { 0x1115, PAL_NONE }, { 0x1112, PAL_NONE }, { 0x1114, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_7_0[] = { { 0x9CD, PALETTE_TO_STRUCT_BROWN }, { 0x9D9, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9CE, PALETTE_TO_STRUCT_BROWN }, { 0x9DA, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D3, PALETTE_TO_STRUCT_BROWN }, { 0x9D9, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D4, PALETTE_TO_STRUCT_BROWN }, { 0x9DA, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FC, PALETTE_TO_STRUCT_BROWN }, { 0x9D9, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FD, PALETTE_TO_STRUCT_BROWN }, { 0x9DA, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1124, PALETTE_TO_STRUCT_BROWN }, { 0x9D9, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1125, PALETTE_TO_STRUCT_BROWN }, { 0x9DA, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_7_1[] = { { 0x9CB, PALETTE_TO_STRUCT_BROWN }, { 0x9D7, PALETTE_TO_STRUCT_BROWN }, { 0x9DD, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x9D0, PALETTE_TO_STRUCT_BROWN }, { 0x9DC, PALETTE_TO_STRUCT_BROWN }, { 0x9E0, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x9D1, PALETTE_TO_STRUCT_BROWN }, { 0x9D7, PALETTE_TO_STRUCT_BROWN }, { 0x9DD, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x9D6, PALETTE_TO_STRUCT_BROWN }, { 0x9DC, PALETTE_TO_STRUCT_BROWN }, { 0x9E0, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x10FA, PALETTE_TO_STRUCT_BROWN }, { 0x9D7, PALETTE_TO_STRUCT_BROWN }, { 0x9DD, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x10FF, PALETTE_TO_STRUCT_BROWN }, { 0x9DC, PALETTE_TO_STRUCT_BROWN }, { 0x9E0, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x1122, PALETTE_TO_STRUCT_BROWN }, { 0x9D7, PALETTE_TO_STRUCT_BROWN }, { 0x9DD, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x1127, PALETTE_TO_STRUCT_BROWN }, { 0x9DC, PALETTE_TO_STRUCT_BROWN }, { 0x9E0, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_7_2[] = { { 0x9CC, PALETTE_TO_STRUCT_BROWN }, { 0x9D8, PALETTE_TO_STRUCT_BROWN }, { 0x9DE, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x9CF, PALETTE_TO_STRUCT_BROWN }, { 0x9DB, PALETTE_TO_STRUCT_BROWN }, { 0x9DF, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x9D2, PALETTE_TO_STRUCT_BROWN }, { 0x9D8, PALETTE_TO_STRUCT_BROWN }, { 0x9DE, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x9D5, PALETTE_TO_STRUCT_BROWN }, { 0x9DB, PALETTE_TO_STRUCT_BROWN }, { 0x9DF, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x10FB, PALETTE_TO_STRUCT_BROWN }, { 0x9D8, PALETTE_TO_STRUCT_BROWN }, { 0x9DE, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x10FE, PALETTE_TO_STRUCT_BROWN }, { 0x9DB, PALETTE_TO_STRUCT_BROWN }, { 0x9DF, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x1123, PALETTE_TO_STRUCT_BROWN }, { 0x9D8, PALETTE_TO_STRUCT_BROWN }, { 0x9DE, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, { 0x1126, PALETTE_TO_STRUCT_BROWN }, { 0x9DB, PALETTE_TO_STRUCT_BROWN }, { 0x9DF, PALETTE_TO_STRUCT_BROWN }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_7_3[] = { { 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE }, { 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE }, { 0x98E, PALETTE_TO_STRUCT_BROWN }, { 0x990, PALETTE_TO_STRUCT_BROWN }, { 0x98D, PALETTE_TO_STRUCT_BROWN }, { 0x98F, PALETTE_TO_STRUCT_BROWN }, { 0x992, PALETTE_TO_STRUCT_BROWN }, { 0x994, PALETTE_TO_STRUCT_BROWN }, { 0x991, PALETTE_TO_STRUCT_BROWN }, { 0x993, PALETTE_TO_STRUCT_BROWN }, { 0x10E7, PALETTE_TO_STRUCT_BROWN }, { 0x10E9, PALETTE_TO_STRUCT_BROWN }, { 0x10E6, PALETTE_TO_STRUCT_BROWN }, { 0x10E8, PALETTE_TO_STRUCT_BROWN }, { 0x10EB, PALETTE_TO_STRUCT_BROWN }, { 0x10ED, PALETTE_TO_STRUCT_BROWN }, { 0x10EA, PALETTE_TO_STRUCT_BROWN }, { 0x10EC, PALETTE_TO_STRUCT_BROWN }, { 0x110F, PALETTE_TO_STRUCT_BROWN }, { 0x1111, PALETTE_TO_STRUCT_BROWN }, { 0x110E, PALETTE_TO_STRUCT_BROWN }, { 0x1110, PALETTE_TO_STRUCT_BROWN }, { 0x1113, PALETTE_TO_STRUCT_BROWN }, { 0x1115, PALETTE_TO_STRUCT_BROWN }, { 0x1112, PALETTE_TO_STRUCT_BROWN }, { 0x1114, PALETTE_TO_STRUCT_BROWN }, }; static const PalSpriteID _bridge_sprite_table_8_0[] = { { 0x9CD, PALETTE_TO_STRUCT_RED }, { 0x9D9, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9CE, PALETTE_TO_STRUCT_RED }, { 0x9DA, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D3, PALETTE_TO_STRUCT_RED }, { 0x9D9, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9D4, PALETTE_TO_STRUCT_RED }, { 0x9DA, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FC, PALETTE_TO_STRUCT_RED }, { 0x9D9, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x10FD, PALETTE_TO_STRUCT_RED }, { 0x9DA, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1124, PALETTE_TO_STRUCT_RED }, { 0x9D9, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1125, PALETTE_TO_STRUCT_RED }, { 0x9DA, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_8_1[] = { { 0x9CB, PALETTE_TO_STRUCT_RED }, { 0x9D7, PALETTE_TO_STRUCT_RED }, { 0x9DD, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x9D0, PALETTE_TO_STRUCT_RED }, { 0x9DC, PALETTE_TO_STRUCT_RED }, { 0x9E0, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x9D1, PALETTE_TO_STRUCT_RED }, { 0x9D7, PALETTE_TO_STRUCT_RED }, { 0x9DD, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x9D6, PALETTE_TO_STRUCT_RED }, { 0x9DC, PALETTE_TO_STRUCT_RED }, { 0x9E0, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x10FA, PALETTE_TO_STRUCT_RED }, { 0x9D7, PALETTE_TO_STRUCT_RED }, { 0x9DD, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x10FF, PALETTE_TO_STRUCT_RED }, { 0x9DC, PALETTE_TO_STRUCT_RED }, { 0x9E0, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x1122, PALETTE_TO_STRUCT_RED }, { 0x9D7, PALETTE_TO_STRUCT_RED }, { 0x9DD, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x1127, PALETTE_TO_STRUCT_RED }, { 0x9DC, PALETTE_TO_STRUCT_RED }, { 0x9E0, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_8_2[] = { { 0x9CC, PALETTE_TO_STRUCT_RED }, { 0x9D8, PALETTE_TO_STRUCT_RED }, { 0x9DE, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x9CF, PALETTE_TO_STRUCT_RED }, { 0x9DB, PALETTE_TO_STRUCT_RED }, { 0x9DF, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x9D2, PALETTE_TO_STRUCT_RED }, { 0x9D8, PALETTE_TO_STRUCT_RED }, { 0x9DE, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x9D5, PALETTE_TO_STRUCT_RED }, { 0x9DB, PALETTE_TO_STRUCT_RED }, { 0x9DF, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x10FB, PALETTE_TO_STRUCT_RED }, { 0x9D8, PALETTE_TO_STRUCT_RED }, { 0x9DE, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x10FE, PALETTE_TO_STRUCT_RED }, { 0x9DB, PALETTE_TO_STRUCT_RED }, { 0x9DF, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x1123, PALETTE_TO_STRUCT_RED }, { 0x9D8, PALETTE_TO_STRUCT_RED }, { 0x9DE, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, { 0x1126, PALETTE_TO_STRUCT_RED }, { 0x9DB, PALETTE_TO_STRUCT_RED }, { 0x9DF, PALETTE_TO_STRUCT_RED }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_8_3[] = { { 0x986, PAL_NONE }, { 0x988, PAL_NONE }, { 0x985, PAL_NONE }, { 0x987, PAL_NONE }, { 0x98A, PAL_NONE }, { 0x98C, PAL_NONE }, { 0x989, PAL_NONE }, { 0x98B, PAL_NONE }, { 0x98E, PALETTE_TO_STRUCT_RED }, { 0x990, PALETTE_TO_STRUCT_RED }, { 0x98D, PALETTE_TO_STRUCT_RED }, { 0x98F, PALETTE_TO_STRUCT_RED }, { 0x992, PALETTE_TO_STRUCT_RED }, { 0x994, PALETTE_TO_STRUCT_RED }, { 0x991, PALETTE_TO_STRUCT_RED }, { 0x993, PALETTE_TO_STRUCT_RED }, { 0x10E7, PALETTE_TO_STRUCT_RED }, { 0x10E9, PALETTE_TO_STRUCT_RED }, { 0x10E6, PALETTE_TO_STRUCT_RED }, { 0x10E8, PALETTE_TO_STRUCT_RED }, { 0x10EB, PALETTE_TO_STRUCT_RED }, { 0x10ED, PALETTE_TO_STRUCT_RED }, { 0x10EA, PALETTE_TO_STRUCT_RED }, { 0x10EC, PALETTE_TO_STRUCT_RED }, { 0x110F, PALETTE_TO_STRUCT_RED }, { 0x1111, PALETTE_TO_STRUCT_RED }, { 0x110E, PALETTE_TO_STRUCT_RED }, { 0x1110, PALETTE_TO_STRUCT_RED }, { 0x1113, PALETTE_TO_STRUCT_RED }, { 0x1115, PALETTE_TO_STRUCT_RED }, { 0x1112, PALETTE_TO_STRUCT_RED }, { 0x1114, PALETTE_TO_STRUCT_RED }, }; static const PalSpriteID _bridge_sprite_table_wood_middle[] = { MN( SPR_BTWDN_RAIL_X_REAR ), MN( SPR_BTWDN_X_FRONT ), MN( SPR_BTWDN_X_PILLAR ), MN( 0x0 ), MN( SPR_BTWDN_RAIL_Y_REAR ), MN( SPR_BTWDN_Y_FRONT ), MN( SPR_BTWDN_Y_PILLAR ), MN( 0x0 ), MN( SPR_BTWDN_ROAD_X_REAR ), MN( SPR_BTWDN_X_FRONT ), MN( SPR_BTWDN_X_PILLAR ), MN( 0x0 ), MN( SPR_BTWDN_ROAD_Y_REAR ), MN( SPR_BTWDN_Y_FRONT ), MN( SPR_BTWDN_Y_PILLAR ), MN( 0x0 ), MN( SPR_BTWDN_MONO_X_REAR ), MN( SPR_BTWDN_X_FRONT ), MN( SPR_BTWDN_X_PILLAR ), MN( 0x0 ), MN( SPR_BTWDN_MONO_Y_REAR ), MN( SPR_BTWDN_Y_FRONT ), MN( SPR_BTWDN_Y_PILLAR ), MN( 0x0 ), MN( SPR_BTWDN_MGLV_X_REAR ), MN( SPR_BTWDN_X_FRONT ), MN( SPR_BTWDN_X_PILLAR ), MN( 0x0 ), MN( SPR_BTWDN_MGLV_Y_REAR ), MN( SPR_BTWDN_Y_FRONT ), MN( SPR_BTWDN_Y_PILLAR ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_wood_heads[] = { MN( SPR_BTWDN_RAIL_X_SLOPE_UP ), MN( SPR_BTWDN_RAIL_Y_SLOPE_UP ), MN( SPR_BTWDN_RAIL_X_SLOPE_DOWN ), MN( SPR_BTWDN_RAIL_Y_SLOPE_DOWN ), MN( SPR_BTWDN_RAIL_RAMP_X_DOWN ), MN( SPR_BTWDN_RAIL_RAMP_Y_DOWN ), MN( SPR_BTWDN_RAIL_RAMP_X_UP ), MN( SPR_BTWDN_RAIL_RAMP_Y_UP ), MN( SPR_BTWDN_ROAD_X_SLOPE_UP ), MN( SPR_BTWDN_ROAD_Y_SLOPE_UP ), MN( SPR_BTWDN_ROAD_X_SLOPE_DOWN ), MN( SPR_BTWDN_ROAD_Y_SLOPE_DOWN ), MN( SPR_BTWDN_ROAD_RAMP_X_DOWN ), MN( SPR_BTWDN_ROAD_RAMP_Y_DOWN ), MN( SPR_BTWDN_ROAD_RAMP_X_UP ), MN( SPR_BTWDN_ROAD_RAMP_Y_UP ), MN( SPR_BTWDN_MONO_X_SLOPE_UP ), MN( SPR_BTWDN_MONO_Y_SLOPE_UP ), MN( SPR_BTWDN_MONO_X_SLOPE_DOWN ), MN( SPR_BTWDN_MONO_Y_SLOPE_DOWN ), MN( SPR_BTWDN_MONO_RAMP_X_DOWN ), MN( SPR_BTWDN_MONO_RAMP_Y_DOWN ), MN( SPR_BTWDN_MONO_RAMP_X_UP ), MN( SPR_BTWDN_MONO_RAMP_Y_UP ), MN( SPR_BTWDN_MGLV_X_SLOPE_UP ), MN( SPR_BTWDN_MGLV_Y_SLOPE_UP ), MN( SPR_BTWDN_MGLV_X_SLOPE_DOWN ), MN( SPR_BTWDN_MGLV_Y_SLOPE_DOWN ), MN( SPR_BTWDN_MGLV_RAMP_X_DOWN ), MN( SPR_BTWDN_MGLV_RAMP_Y_DOWN ), MN( SPR_BTWDN_MGLV_RAMP_X_UP ), MN( SPR_BTWDN_MGLV_RAMP_Y_UP ), }; static const PalSpriteID _bridge_sprite_table_concrete_middle[] = { MR( SPR_BTCON_RAIL_X ), MR( SPR_BTCON_X_FRONT ), MN( SPR_BTCON_X_PILLAR ), MN( 0x0 ), MR( SPR_BTCON_RAIL_Y ), MR( SPR_BTCON_Y_FRONT ), MN( SPR_BTCON_Y_PILLAR ), MN( 0x0 ), MR( SPR_BTCON_ROAD_X ), MR( SPR_BTCON_X_FRONT ), MN( SPR_BTCON_X_PILLAR ), MN( 0x0 ), MR( SPR_BTCON_ROAD_Y ), MR( SPR_BTCON_Y_FRONT ), MN( SPR_BTCON_Y_PILLAR ), MN( 0x0 ), MR( SPR_BTCON_MONO_X ), MR( SPR_BTCON_X_FRONT ), MN( SPR_BTCON_X_PILLAR ), MN( 0x0 ), MR( SPR_BTCON_MONO_Y ), MR( SPR_BTCON_Y_FRONT ), MN( SPR_BTCON_Y_PILLAR ), MN( 0x0 ), MR( SPR_BTCON_MGLV_X ), MR( SPR_BTCON_X_FRONT ), MN( SPR_BTCON_X_PILLAR ), MN( 0x0 ), MR( SPR_BTCON_MGLV_Y ), MR( SPR_BTCON_Y_FRONT ), MN( SPR_BTCON_Y_PILLAR ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_concrete_heads[] = { MN( SPR_BTGEN_RAIL_X_SLOPE_UP ), MN( SPR_BTGEN_RAIL_Y_SLOPE_UP ), MN( SPR_BTGEN_RAIL_X_SLOPE_DOWN ), MN( SPR_BTGEN_RAIL_Y_SLOPE_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_X_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_Y_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_X_UP ), MN( SPR_BTGEN_RAIL_RAMP_Y_UP ), MR( SPR_BTGEN_ROAD_X_SLOPE_UP ), MR( SPR_BTGEN_ROAD_Y_SLOPE_UP ), MR( SPR_BTGEN_ROAD_X_SLOPE_DOWN ), MR( SPR_BTGEN_ROAD_Y_SLOPE_DOWN ), MR( SPR_BTGEN_ROAD_RAMP_X_DOWN ), MR( SPR_BTGEN_ROAD_RAMP_Y_DOWN ), MR( SPR_BTGEN_ROAD_RAMP_X_UP ), MR( SPR_BTGEN_ROAD_RAMP_Y_UP ), MR( SPR_BTGEN_MONO_X_SLOPE_UP ), MR( SPR_BTGEN_MONO_Y_SLOPE_UP ), MR( SPR_BTGEN_MONO_X_SLOPE_DOWN ), MR( SPR_BTGEN_MONO_Y_SLOPE_DOWN ), MR( SPR_BTGEN_MONO_RAMP_X_DOWN ), MR( SPR_BTGEN_MONO_RAMP_Y_DOWN ), MR( SPR_BTGEN_MONO_RAMP_X_UP ), MR( SPR_BTGEN_MONO_RAMP_Y_UP ), MR( SPR_BTGEN_MGLV_X_SLOPE_UP ), MR( SPR_BTGEN_MGLV_Y_SLOPE_UP ), MR( SPR_BTGEN_MGLV_X_SLOPE_DOWN ), MR( SPR_BTGEN_MGLV_Y_SLOPE_DOWN ), MR( SPR_BTGEN_MGLV_RAMP_X_DOWN ), MR( SPR_BTGEN_MGLV_RAMP_Y_DOWN ), MR( SPR_BTGEN_MGLV_RAMP_X_UP ), MR( SPR_BTGEN_MGLV_RAMP_Y_UP ), }; static const PalSpriteID _bridge_sprite_table_archgirder_middle[] = { MN( SPR_BTSGA_RAIL_X_REAR ), MN( SPR_BTSGA_X_FRONT ), MN( SPR_BTSGA_X_PILLAR ), MN( 0x0 ), MN( SPR_BTSGA_RAIL_Y_REAR ), MN( SPR_BTSGA_Y_FRONT ), MN( SPR_BTSGA_Y_PILLAR ), MN( 0x0 ), MN( SPR_BTSGA_ROAD_X_REAR ), MN( SPR_BTSGA_X_FRONT ), MN( SPR_BTSGA_X_PILLAR ), MN( 0x0 ), MN( SPR_BTSGA_ROAD_Y_REAR ), MN( SPR_BTSGA_Y_FRONT ), MN( SPR_BTSGA_Y_PILLAR ), MN( 0x0 ), MN( SPR_BTSGA_MONO_X_REAR ), MN( SPR_BTSGA_X_FRONT ), MN( SPR_BTSGA_X_PILLAR ), MN( 0x0 ), MN( SPR_BTSGA_MONO_Y_REAR ), MN( SPR_BTSGA_Y_FRONT ), MN( SPR_BTSGA_Y_PILLAR ), MN( 0x0 ), MN( SPR_BTSGA_MGLV_X_REAR ), MN( SPR_BTSGA_X_FRONT ), MN( SPR_BTSGA_X_PILLAR ), MN( 0x0 ), MN( SPR_BTSGA_MGLV_Y_REAR ), MN( SPR_BTSGA_Y_FRONT ), MN( SPR_BTSGA_Y_PILLAR ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_archgirder_heads[] = { MN( SPR_BTGEN_RAIL_X_SLOPE_UP ), MN( SPR_BTGEN_RAIL_Y_SLOPE_UP ), MN( SPR_BTGEN_RAIL_X_SLOPE_DOWN ), MN( SPR_BTGEN_RAIL_Y_SLOPE_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_X_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_Y_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_X_UP ), MN( SPR_BTGEN_RAIL_RAMP_Y_UP ), MW( SPR_BTGEN_ROAD_X_SLOPE_UP ), MW( SPR_BTGEN_ROAD_Y_SLOPE_UP ), MW( SPR_BTGEN_ROAD_X_SLOPE_DOWN ), MW( SPR_BTGEN_ROAD_Y_SLOPE_DOWN ), MW( SPR_BTGEN_ROAD_RAMP_X_DOWN ), MW( SPR_BTGEN_ROAD_RAMP_Y_DOWN ), MW( SPR_BTGEN_ROAD_RAMP_X_UP ), MW( SPR_BTGEN_ROAD_RAMP_Y_UP ), MW( SPR_BTGEN_MONO_X_SLOPE_UP ), MW( SPR_BTGEN_MONO_Y_SLOPE_UP ), MW( SPR_BTGEN_MONO_X_SLOPE_DOWN ), MW( SPR_BTGEN_MONO_Y_SLOPE_DOWN ), MW( SPR_BTGEN_MONO_RAMP_X_DOWN ), MW( SPR_BTGEN_MONO_RAMP_Y_DOWN ), MW( SPR_BTGEN_MONO_RAMP_X_UP ), MW( SPR_BTGEN_MONO_RAMP_Y_UP ), MW( SPR_BTGEN_MGLV_X_SLOPE_UP ), MW( SPR_BTGEN_MGLV_Y_SLOPE_UP ), MW( SPR_BTGEN_MGLV_X_SLOPE_DOWN ), MW( SPR_BTGEN_MGLV_Y_SLOPE_DOWN ), MW( SPR_BTGEN_MGLV_RAMP_X_DOWN ), MW( SPR_BTGEN_MGLV_RAMP_Y_DOWN ), MW( SPR_BTGEN_MGLV_RAMP_X_UP ), MW( SPR_BTGEN_MGLV_RAMP_Y_UP ), }; static const PalSpriteID _bridge_sprite_table_concrete_suspended_A[] = { MC( SPR_BTSUS_RAIL_X_REAR_TILE_A ), MC( SPR_BTSUS_X_FRONT_TILE_A ), MC( SPR_BTSUS_X_PILLAR_TILE_A ), MN( 0x0 ), MC( SPR_BTSUS_RAIL_Y_REAR_TILE_A ), MC( SPR_BTSUS_Y_FRONT_TILE_A ), MC( SPR_BTSUS_Y_PILLAR_TILE_A ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_X_REAR_TILE_A ), MC( SPR_BTSUS_X_FRONT_TILE_A ), MC( SPR_BTSUS_X_PILLAR_TILE_A ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_Y_REAR_TILE_A ), MC( SPR_BTSUS_Y_FRONT_TILE_A ), MC( SPR_BTSUS_Y_PILLAR_TILE_A ), MN( 0x0 ), MC( SPR_BTSUS_MONO_X_REAR_TILE_A ), MC( SPR_BTSUS_X_FRONT_TILE_A ), MC( SPR_BTSUS_X_PILLAR_TILE_A ), MN( 0x0 ), MC( SPR_BTSUS_MONO_Y_REAR_TILE_A ), MC( SPR_BTSUS_Y_FRONT_TILE_A ), MC( SPR_BTSUS_Y_PILLAR_TILE_A ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_X_REAR_TILE_A ), MC( SPR_BTSUS_X_FRONT_TILE_A ), MC( SPR_BTSUS_X_PILLAR_TILE_A ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_Y_REAR_TILE_A ), MC( SPR_BTSUS_Y_FRONT_TILE_A ), MC( SPR_BTSUS_Y_PILLAR_TILE_A ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_concrete_suspended_B[] = { MC( SPR_BTSUS_RAIL_X_REAR_TILE_B ), MC( SPR_BTSUS_X_FRONT_TILE_B ), MC( SPR_BTSUS_X_PILLAR_TILE_B ), MN( 0x0 ), MC( SPR_BTSUS_RAIL_Y_REAR_TILE_B ), MC( SPR_BTSUS_Y_FRONT_TILE_B ), MC( SPR_BTSUS_Y_PILLAR_TILE_B ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_X_REAR_TILE_B ), MC( SPR_BTSUS_X_FRONT_TILE_B ), MC( SPR_BTSUS_X_PILLAR_TILE_B ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_Y_REAR_TILE_B ), MC( SPR_BTSUS_Y_FRONT_TILE_B ), MC( SPR_BTSUS_Y_PILLAR_TILE_B ), MN( 0x0 ), MC( SPR_BTSUS_MONO_X_REAR_TILE_B ), MC( SPR_BTSUS_X_FRONT_TILE_B ), MC( SPR_BTSUS_X_PILLAR_TILE_B ), MN( 0x0 ), MC( SPR_BTSUS_MONO_Y_REAR_TILE_B ), MC( SPR_BTSUS_Y_FRONT_TILE_B ), MC( SPR_BTSUS_Y_PILLAR_TILE_B ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_X_REAR_TILE_B ), MC( SPR_BTSUS_X_FRONT_TILE_B ), MC( SPR_BTSUS_X_PILLAR_TILE_B ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_Y_REAR_TILE_B ), MC( SPR_BTSUS_Y_FRONT_TILE_B ), MC( SPR_BTSUS_Y_PILLAR_TILE_B ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_concrete_suspended_C[] = { MC( SPR_BTSUS_RAIL_X_REAR_TILE_C ), MC( SPR_BTSUS_X_FRONT_TILE_C ), MC( SPR_BTSUS_X_PILLAR_TILE_C ), MN( 0x0 ), MC( SPR_BTSUS_RAIL_Y_REAR_TILE_C ), MC( SPR_BTSUS_Y_FRONT_TILE_C ), MC( SPR_BTSUS_Y_PILLAR_TILE_C ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_X_REAR_TILE_C ), MC( SPR_BTSUS_X_FRONT_TILE_C ), MC( SPR_BTSUS_X_PILLAR_TILE_C ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_Y_REAR_TILE_C ), MC( SPR_BTSUS_Y_FRONT_TILE_C ), MC( SPR_BTSUS_Y_PILLAR_TILE_C ), MN( 0x0 ), MC( SPR_BTSUS_MONO_X_REAR_TILE_C ), MC( SPR_BTSUS_X_FRONT_TILE_C ), MC( SPR_BTSUS_X_PILLAR_TILE_C ), MN( 0x0 ), MC( SPR_BTSUS_MONO_Y_REAR_TILE_C ), MC( SPR_BTSUS_Y_FRONT_TILE_C ), MC( SPR_BTSUS_Y_PILLAR_TILE_C ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_X_REAR_TILE_C ), MC( SPR_BTSUS_X_FRONT_TILE_C ), MC( SPR_BTSUS_X_PILLAR_TILE_C ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_Y_REAR_TILE_C ), MC( SPR_BTSUS_Y_FRONT_TILE_C ), MC( SPR_BTSUS_Y_PILLAR_TILE_C ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_concrete_suspended_D[] = { MC( SPR_BTSUS_RAIL_X_REAR_TILE_D ), MC( SPR_BTSUS_X_FRONT_TILE_D ), MC( SPR_BTSUS_X_PILLAR_TILE_D ), MN( 0x0 ), MC( SPR_BTSUS_RAIL_Y_REAR_TILE_D ), MC( SPR_BTSUS_Y_FRONT_TILE_D ), MC( SPR_BTSUS_Y_PILLAR_TILE_D ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_X_REAR_TILE_D ), MC( SPR_BTSUS_X_FRONT_TILE_D ), MC( SPR_BTSUS_X_PILLAR_TILE_D ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_Y_REAR_TILE_D ), MC( SPR_BTSUS_Y_FRONT_TILE_D ), MC( SPR_BTSUS_Y_PILLAR_TILE_D ), MN( 0x0 ), MC( SPR_BTSUS_MONO_X_REAR_TILE_D ), MC( SPR_BTSUS_X_FRONT_TILE_D ), MC( SPR_BTSUS_X_PILLAR_TILE_D ), MN( 0x0 ), MC( SPR_BTSUS_MONO_Y_REAR_TILE_D ), MC( SPR_BTSUS_Y_FRONT_TILE_D ), MC( SPR_BTSUS_Y_PILLAR_TILE_D ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_X_REAR_TILE_D ), MC( SPR_BTSUS_X_FRONT_TILE_D ), MC( SPR_BTSUS_X_PILLAR_TILE_D ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_Y_REAR_TILE_D ), MC( SPR_BTSUS_Y_FRONT_TILE_D ), MC( SPR_BTSUS_Y_PILLAR_TILE_D ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_concrete_suspended_E[] = { MC( SPR_BTSUS_RAIL_X_REAR_TILE_E ), MC( SPR_BTSUS_X_FRONT_TILE_E ), MC( SPR_BTSUS_X_PILLAR_TILE_E ), MN( 0x0 ), MC( SPR_BTSUS_RAIL_Y_REAR_TILE_E ), MC( SPR_BTSUS_Y_FRONT_TILE_E ), MC( SPR_BTSUS_Y_PILLAR_TILE_E ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_X_REAR_TILE_E ), MC( SPR_BTSUS_X_FRONT_TILE_E ), MC( SPR_BTSUS_X_PILLAR_TILE_E ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_Y_REAR_TILE_E ), MC( SPR_BTSUS_Y_FRONT_TILE_E ), MC( SPR_BTSUS_Y_PILLAR_TILE_E ), MN( 0x0 ), MC( SPR_BTSUS_MONO_X_REAR_TILE_E ), MC( SPR_BTSUS_X_FRONT_TILE_E ), MC( SPR_BTSUS_X_PILLAR_TILE_E ), MN( 0x0 ), MC( SPR_BTSUS_MONO_Y_REAR_TILE_E ), MC( SPR_BTSUS_Y_FRONT_TILE_E ), MC( SPR_BTSUS_Y_PILLAR_TILE_E ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_X_REAR_TILE_E ), MC( SPR_BTSUS_X_FRONT_TILE_E ), MC( SPR_BTSUS_X_PILLAR_TILE_E ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_Y_REAR_TILE_E ), MC( SPR_BTSUS_Y_FRONT_TILE_E ), MC( SPR_BTSUS_Y_PILLAR_TILE_E ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_concrete_suspended_F[] = { MC( SPR_BTSUS_RAIL_X_REAR_TILE_F ), MC( SPR_BTSUS_X_FRONT ), MN( 0x0 ), MN( 0x0 ), MC( SPR_BTSUS_RAIL_Y_REAR_TILE_F ), MC( SPR_BTSUS_Y_FRONT ), MN( 0x0 ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_X_REAR_TILE_F ), MC( SPR_BTSUS_X_FRONT ), MN( 0x0 ), MN( 0x0 ), MC( SPR_BTSUS_ROAD_Y_REAR_TILE_F ), MC( SPR_BTSUS_Y_FRONT ), MN( 0x0 ), MN( 0x0 ), MC( SPR_BTSUS_MONO_X_REAR_TILE_F ), MC( SPR_BTSUS_X_FRONT ), MN( 0x0 ), MN( 0x0 ), MC( SPR_BTSUS_MONO_Y_REAR_TILE_F ), MC( SPR_BTSUS_Y_FRONT ), MN( 0x0 ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_X_REAR_TILE_F ), MC( SPR_BTSUS_X_FRONT ), MN( 0x0 ), MN( 0x0 ), MC( SPR_BTSUS_MGLV_Y_REAR_TILE_F ), MC( SPR_BTSUS_Y_FRONT ), MN( 0x0 ), MN( 0x0 ), }; static const PalSpriteID _bridge_sprite_table_concrete_suspended_heads[] = { MN( SPR_BTGEN_RAIL_X_SLOPE_UP ), MN( SPR_BTGEN_RAIL_Y_SLOPE_UP ), MN( SPR_BTGEN_RAIL_X_SLOPE_DOWN ), MN( SPR_BTGEN_RAIL_Y_SLOPE_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_X_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_Y_DOWN ), MN( SPR_BTGEN_RAIL_RAMP_X_UP ), MN( SPR_BTGEN_RAIL_RAMP_Y_UP ), MC( SPR_BTGEN_ROAD_X_SLOPE_UP ), MC( SPR_BTGEN_ROAD_Y_SLOPE_UP ), MC( SPR_BTGEN_ROAD_X_SLOPE_DOWN ), MC( SPR_BTGEN_ROAD_Y_SLOPE_DOWN ), MC( SPR_BTGEN_ROAD_RAMP_X_DOWN ), MC( SPR_BTGEN_ROAD_RAMP_Y_DOWN ), MC( SPR_BTGEN_ROAD_RAMP_X_UP ), MC( SPR_BTGEN_ROAD_RAMP_Y_UP ), MC( SPR_BTGEN_MONO_X_SLOPE_UP ), MC( SPR_BTGEN_MONO_Y_SLOPE_UP ), MC( SPR_BTGEN_MONO_X_SLOPE_DOWN ), MC( SPR_BTGEN_MONO_Y_SLOPE_DOWN ), MC( SPR_BTGEN_MONO_RAMP_X_DOWN ), MC( SPR_BTGEN_MONO_RAMP_Y_DOWN ), MC( SPR_BTGEN_MONO_RAMP_X_UP ), MC( SPR_BTGEN_MONO_RAMP_Y_UP ), MC( SPR_BTGEN_MGLV_X_SLOPE_UP ), MC( SPR_BTGEN_MGLV_Y_SLOPE_UP ), MC( SPR_BTGEN_MGLV_X_SLOPE_DOWN ), MC( SPR_BTGEN_MGLV_Y_SLOPE_DOWN ), MC( SPR_BTGEN_MGLV_RAMP_X_DOWN ), MC( SPR_BTGEN_MGLV_RAMP_Y_DOWN ), MC( SPR_BTGEN_MGLV_RAMP_X_UP ), MC( SPR_BTGEN_MGLV_RAMP_Y_UP ), }; static const PalSpriteID _bridge_sprite_table_9_0[] = { { 0x9F9, PAL_NONE }, { 0x9FD, PAL_NONE }, { 0x9C9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9FA, PAL_NONE }, { 0x9FE, PAL_NONE }, { 0x9CA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9FB, PAL_NONE }, { 0x9FD, PAL_NONE }, { 0x9C9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x9FC, PAL_NONE }, { 0x9FE, PAL_NONE }, { 0x9CA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x110A, PAL_NONE }, { 0x9FD, PAL_NONE }, { 0x9C9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x110B, PAL_NONE }, { 0x9FE, PAL_NONE }, { 0x9CA, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1132, PAL_NONE }, { 0x9FD, PAL_NONE }, { 0x9C9, PAL_NONE }, { 0x0, PAL_NONE }, { 0x1133, PAL_NONE }, { 0x9FE, PAL_NONE }, { 0x9CA, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_10_0[] = { { 0xA0B, PAL_NONE }, { 0xA01, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA0C, PAL_NONE }, { 0xA02, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA11, PAL_NONE }, { 0xA01, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA12, PAL_NONE }, { 0xA02, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA17, PAL_NONE }, { 0xA01, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA18, PAL_NONE }, { 0xA02, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1D, PAL_NONE }, { 0xA01, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1E, PAL_NONE }, { 0xA02, PAL_NONE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_10_1[] = { { 0xA09, PAL_NONE }, { 0x9FF, PAL_NONE }, { 0xA05, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA0E, PAL_NONE }, { 0xA04, PAL_NONE }, { 0xA08, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA0F, PAL_NONE }, { 0x9FF, PAL_NONE }, { 0xA05, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA14, PAL_NONE }, { 0xA04, PAL_NONE }, { 0xA08, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA15, PAL_NONE }, { 0x9FF, PAL_NONE }, { 0xA05, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1A, PAL_NONE }, { 0xA04, PAL_NONE }, { 0xA08, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1B, PAL_NONE }, { 0x9FF, PAL_NONE }, { 0xA05, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA20, PAL_NONE }, { 0xA04, PAL_NONE }, { 0xA08, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_10_2[] = { { 0xA0A, PAL_NONE }, { 0xA00, PAL_NONE }, { 0xA06, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA0D, PAL_NONE }, { 0xA03, PAL_NONE }, { 0xA07, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA10, PAL_NONE }, { 0xA00, PAL_NONE }, { 0xA06, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA13, PAL_NONE }, { 0xA03, PAL_NONE }, { 0xA07, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA16, PAL_NONE }, { 0xA00, PAL_NONE }, { 0xA06, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA19, PAL_NONE }, { 0xA03, PAL_NONE }, { 0xA07, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1C, PAL_NONE }, { 0xA00, PAL_NONE }, { 0xA06, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1F, PAL_NONE }, { 0xA03, PAL_NONE }, { 0xA07, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_11_0[] = { { 0xA0B, PALETTE_TO_STRUCT_YELLOW }, { 0xA01, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA0C, PALETTE_TO_STRUCT_YELLOW }, { 0xA02, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA11, PALETTE_TO_STRUCT_YELLOW }, { 0xA01, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA12, PALETTE_TO_STRUCT_YELLOW }, { 0xA02, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA17, PALETTE_TO_STRUCT_YELLOW }, { 0xA01, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA18, PALETTE_TO_STRUCT_YELLOW }, { 0xA02, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1D, PALETTE_TO_STRUCT_YELLOW }, { 0xA01, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1E, PALETTE_TO_STRUCT_YELLOW }, { 0xA02, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_11_1[] = { { 0xA09, PALETTE_TO_STRUCT_YELLOW }, { 0x9FF, PALETTE_TO_STRUCT_YELLOW }, { 0xA05, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA0E, PALETTE_TO_STRUCT_YELLOW }, { 0xA04, PALETTE_TO_STRUCT_YELLOW }, { 0xA08, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA0F, PALETTE_TO_STRUCT_YELLOW }, { 0x9FF, PALETTE_TO_STRUCT_YELLOW }, { 0xA05, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA14, PALETTE_TO_STRUCT_YELLOW }, { 0xA04, PALETTE_TO_STRUCT_YELLOW }, { 0xA08, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA15, PALETTE_TO_STRUCT_YELLOW }, { 0x9FF, PALETTE_TO_STRUCT_YELLOW }, { 0xA05, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA1A, PALETTE_TO_STRUCT_YELLOW }, { 0xA04, PALETTE_TO_STRUCT_YELLOW }, { 0xA08, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA1B, PALETTE_TO_STRUCT_YELLOW }, { 0x9FF, PALETTE_TO_STRUCT_YELLOW }, { 0xA05, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA20, PALETTE_TO_STRUCT_YELLOW }, { 0xA04, PALETTE_TO_STRUCT_YELLOW }, { 0xA08, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_11_2[] = { { 0xA0A, PALETTE_TO_STRUCT_YELLOW }, { 0xA00, PALETTE_TO_STRUCT_YELLOW }, { 0xA06, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA0D, PALETTE_TO_STRUCT_YELLOW }, { 0xA03, PALETTE_TO_STRUCT_YELLOW }, { 0xA07, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA10, PALETTE_TO_STRUCT_YELLOW }, { 0xA00, PALETTE_TO_STRUCT_YELLOW }, { 0xA06, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA13, PALETTE_TO_STRUCT_YELLOW }, { 0xA03, PALETTE_TO_STRUCT_YELLOW }, { 0xA07, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA16, PALETTE_TO_STRUCT_YELLOW }, { 0xA00, PALETTE_TO_STRUCT_YELLOW }, { 0xA06, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA19, PALETTE_TO_STRUCT_YELLOW }, { 0xA03, PALETTE_TO_STRUCT_YELLOW }, { 0xA07, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA1C, PALETTE_TO_STRUCT_YELLOW }, { 0xA00, PALETTE_TO_STRUCT_YELLOW }, { 0xA06, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, { 0xA1F, PALETTE_TO_STRUCT_YELLOW }, { 0xA03, PALETTE_TO_STRUCT_YELLOW }, { 0xA07, PALETTE_TO_STRUCT_YELLOW }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_12_0[] = { { 0xA0B, PALETTE_TO_STRUCT_CONCRETE }, { 0xA01, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA0C, PALETTE_TO_STRUCT_CONCRETE }, { 0xA02, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA11, PALETTE_TO_STRUCT_CONCRETE }, { 0xA01, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA12, PALETTE_TO_STRUCT_CONCRETE }, { 0xA02, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA17, PALETTE_TO_STRUCT_CONCRETE }, { 0xA01, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA18, PALETTE_TO_STRUCT_CONCRETE }, { 0xA02, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1D, PALETTE_TO_STRUCT_CONCRETE }, { 0xA01, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, { 0xA1E, PALETTE_TO_STRUCT_CONCRETE }, { 0xA02, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_12_1[] = { { 0xA09, PALETTE_TO_STRUCT_CONCRETE }, { 0x9FF, PALETTE_TO_STRUCT_CONCRETE }, { 0xA05, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA0E, PALETTE_TO_STRUCT_CONCRETE }, { 0xA04, PALETTE_TO_STRUCT_CONCRETE }, { 0xA08, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA0F, PALETTE_TO_STRUCT_CONCRETE }, { 0x9FF, PALETTE_TO_STRUCT_CONCRETE }, { 0xA05, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA14, PALETTE_TO_STRUCT_CONCRETE }, { 0xA04, PALETTE_TO_STRUCT_CONCRETE }, { 0xA08, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA15, PALETTE_TO_STRUCT_CONCRETE }, { 0x9FF, PALETTE_TO_STRUCT_CONCRETE }, { 0xA05, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA1A, PALETTE_TO_STRUCT_CONCRETE }, { 0xA04, PALETTE_TO_STRUCT_CONCRETE }, { 0xA08, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA1B, PALETTE_TO_STRUCT_CONCRETE }, { 0x9FF, PALETTE_TO_STRUCT_CONCRETE }, { 0xA05, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA20, PALETTE_TO_STRUCT_CONCRETE }, { 0xA04, PALETTE_TO_STRUCT_CONCRETE }, { 0xA08, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, }; static const PalSpriteID _bridge_sprite_table_12_2[] = { { 0xA0A, PALETTE_TO_STRUCT_CONCRETE }, { 0xA00, PALETTE_TO_STRUCT_CONCRETE }, { 0xA06, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA0D, PALETTE_TO_STRUCT_CONCRETE }, { 0xA03, PALETTE_TO_STRUCT_CONCRETE }, { 0xA07, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA10, PALETTE_TO_STRUCT_CONCRETE }, { 0xA00, PALETTE_TO_STRUCT_CONCRETE }, { 0xA06, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA13, PALETTE_TO_STRUCT_CONCRETE }, { 0xA03, PALETTE_TO_STRUCT_CONCRETE }, { 0xA07, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA16, PALETTE_TO_STRUCT_CONCRETE }, { 0xA00, PALETTE_TO_STRUCT_CONCRETE }, { 0xA06, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA19, PALETTE_TO_STRUCT_CONCRETE }, { 0xA03, PALETTE_TO_STRUCT_CONCRETE }, { 0xA07, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA1C, PALETTE_TO_STRUCT_CONCRETE }, { 0xA00, PALETTE_TO_STRUCT_CONCRETE }, { 0xA06, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, { 0xA1F, PALETTE_TO_STRUCT_CONCRETE }, { 0xA03, PALETTE_TO_STRUCT_CONCRETE }, { 0xA07, PALETTE_TO_STRUCT_CONCRETE }, { 0x0, PAL_NONE }, }; static const PalSpriteID * const _bridge_sprite_table_archgirder[] = { _bridge_sprite_table_archgirder_middle, _bridge_sprite_table_archgirder_middle, _bridge_sprite_table_archgirder_middle, _bridge_sprite_table_archgirder_middle, _bridge_sprite_table_archgirder_middle, _bridge_sprite_table_archgirder_middle, _bridge_sprite_table_archgirder_heads, }; static const PalSpriteID * const _bridge_sprite_table_4[] = { _bridge_sprite_table_4_0, _bridge_sprite_table_4_1, _bridge_sprite_table_4_2, _bridge_sprite_table_4_3, _bridge_sprite_table_4_4, _bridge_sprite_table_4_5, _bridge_sprite_table_4_6, }; static const PalSpriteID * const _bridge_sprite_table_5[] = { _bridge_sprite_table_5_0, _bridge_sprite_table_5_1, _bridge_sprite_table_5_2, _bridge_sprite_table_5_3, _bridge_sprite_table_5_4, _bridge_sprite_table_5_5, _bridge_sprite_table_5_6, }; static const PalSpriteID * const _bridge_sprite_table_concrete_suspended[] = { _bridge_sprite_table_concrete_suspended_A, _bridge_sprite_table_concrete_suspended_B, _bridge_sprite_table_concrete_suspended_C, _bridge_sprite_table_concrete_suspended_D, _bridge_sprite_table_concrete_suspended_E, _bridge_sprite_table_concrete_suspended_F, _bridge_sprite_table_concrete_suspended_heads, }; static const PalSpriteID * const _bridge_sprite_table_6[] = { _bridge_sprite_table_6_0, _bridge_sprite_table_6_1, _bridge_sprite_table_6_2, _bridge_sprite_table_6_2, _bridge_sprite_table_6_2, _bridge_sprite_table_6_2, _bridge_sprite_table_6_3, }; static const PalSpriteID * const _bridge_sprite_table_7[] = { _bridge_sprite_table_7_0, _bridge_sprite_table_7_1, _bridge_sprite_table_7_2, _bridge_sprite_table_7_2, _bridge_sprite_table_7_2, _bridge_sprite_table_7_2, _bridge_sprite_table_7_3, }; static const PalSpriteID * const _bridge_sprite_table_8[] = { _bridge_sprite_table_8_0, _bridge_sprite_table_8_1, _bridge_sprite_table_8_2, _bridge_sprite_table_8_2, _bridge_sprite_table_8_2, _bridge_sprite_table_8_2, _bridge_sprite_table_8_3, }; static const PalSpriteID * const _bridge_sprite_table_wood[] = { _bridge_sprite_table_wood_middle, _bridge_sprite_table_wood_middle, _bridge_sprite_table_wood_middle, _bridge_sprite_table_wood_middle, _bridge_sprite_table_wood_middle, _bridge_sprite_table_wood_middle, _bridge_sprite_table_wood_heads, }; static const PalSpriteID * const _bridge_sprite_table_concrete[] = { _bridge_sprite_table_concrete_middle, _bridge_sprite_table_concrete_middle, _bridge_sprite_table_concrete_middle, _bridge_sprite_table_concrete_middle, _bridge_sprite_table_concrete_middle, _bridge_sprite_table_concrete_middle, _bridge_sprite_table_concrete_heads, }; static const PalSpriteID * const _bridge_sprite_table_9[] = { _bridge_sprite_table_9_0, _bridge_sprite_table_9_0, _bridge_sprite_table_9_0, _bridge_sprite_table_9_0, _bridge_sprite_table_9_0, _bridge_sprite_table_9_0, _bridge_sprite_table_4_6, }; static const PalSpriteID * const _bridge_sprite_table_10[] = { _bridge_sprite_table_10_0, _bridge_sprite_table_10_1, _bridge_sprite_table_10_2, _bridge_sprite_table_10_2, _bridge_sprite_table_10_2, _bridge_sprite_table_10_2, _bridge_sprite_table_4_6, }; static const PalSpriteID * const _bridge_sprite_table_11[] = { _bridge_sprite_table_11_0, _bridge_sprite_table_11_1, _bridge_sprite_table_11_2, _bridge_sprite_table_11_2, _bridge_sprite_table_11_2, _bridge_sprite_table_11_2, _bridge_sprite_table_5_6, }; static const PalSpriteID * const _bridge_sprite_table_12[] = { _bridge_sprite_table_12_0, _bridge_sprite_table_12_1, _bridge_sprite_table_12_2, _bridge_sprite_table_12_2, _bridge_sprite_table_12_2, _bridge_sprite_table_12_2, _bridge_sprite_table_concrete_suspended_heads, }; static const PalSpriteID * const * const _bridge_sprite_table[MAX_BRIDGES] = { _bridge_sprite_table_wood, _bridge_sprite_table_concrete, _bridge_sprite_table_archgirder, _bridge_sprite_table_concrete_suspended, _bridge_sprite_table_4, _bridge_sprite_table_5, _bridge_sprite_table_6, _bridge_sprite_table_7, _bridge_sprite_table_8, _bridge_sprite_table_9, _bridge_sprite_table_10, _bridge_sprite_table_11, _bridge_sprite_table_12 }; /** * Describes the data that defines each bridge in the game * @param y year of availability * @param mnl minimum length (not counting bridge heads) * @param mxl maximum length (not counting bridge heads) * @param p price multiplier * @param mxs maximum speed allowed (1 unit = 1/1.6 mph = 1 km-ish/h) * @param spr sprite to use in purchase GUI * @param plt palette for the sprite in purchase GUI * @param dsc description of the bridge in purchase GUI * @param nrl description of the rail bridge in query tool * @param nrd description of the road bridge in query tool */ #define MBR(y, mnl, mxl, p, mxs, spr, plt, dsc, nrl, nrd) \ {y, mnl, mxl, p, mxs, spr, plt, dsc, { nrl, nrd }, NULL, 0} const BridgeSpec _orig_bridge[] = { /* year of availability | minimum length | | maximum length | | | price multiplier | | | | maximum speed | | | | | sprite to use in GUI | | | | | | palette in GUI string with description name on rail name on road | | | | */ MBR( 0, 0, 0xFFFF, 80, 32, 0xA24, PAL_NONE, STR_BRIDGE_NAME_WOODEN, STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN, STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN), MBR( 0, 0, 2, 112, 48, 0xA26, PALETTE_TO_STRUCT_RED, STR_BRIDGE_NAME_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE), MBR(1930, 0, 5, 144, 64, 0xA25, PAL_NONE, STR_BRIDGE_NAME_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL), MBR( 0, 2, 10, 168, 80, 0xA22, PALETTE_TO_STRUCT_CONCRETE, STR_BRIDGE_NAME_SUSPENSION_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE), MBR(1930, 3, 0xFFFF, 185, 96, 0xA22, PAL_NONE, STR_BRIDGE_NAME_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL), MBR(1930, 3, 0xFFFF, 192, 112, 0xA22, PALETTE_TO_STRUCT_YELLOW, STR_BRIDGE_NAME_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL), MBR(1930, 3, 7, 224, 160, 0xA23, PAL_NONE, STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL), MBR(1930, 3, 8, 232, 208, 0xA23, PALETTE_TO_STRUCT_BROWN, STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL), MBR(1930, 3, 9, 248, 240, 0xA23, PALETTE_TO_STRUCT_RED, STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL), MBR(1930, 0, 2, 240, 256, 0xA27, PAL_NONE, STR_BRIDGE_NAME_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL), MBR(1995, 2, 0xFFFF, 255, 320, 0xA28, PAL_NONE, STR_BRIDGE_NAME_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL), MBR(2005, 2, 0xFFFF, 380, 512, 0xA28, PALETTE_TO_STRUCT_YELLOW, STR_BRIDGE_NAME_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL), MBR(2010, 2, 0xFFFF, 510, 608, 0xA28, PALETTE_TO_STRUCT_CONCRETE, STR_BRIDGE_TUBULAR_SILICON, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL) }; #undef MBR #undef MN #undef MR #undef MW #undef MC openttd-1.5.3/src/table/newgrf_debug_data.h0000644000000000000000000005711512627373436017377 0ustar rootroot/* $Id: newgrf_debug_data.h 27048 2014-10-28 00:51:51Z peter1138 $ */ /* * 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 newgrf_debug_data.h Data 'tables' for NewGRF debugging. */ #include "../newgrf_house.h" #include "../newgrf_engine.h" /* Helper for filling property tables */ #define NIP(prop, base, variable, type, name) { name, cpp_offsetof(base, variable), cpp_sizeof(base, variable), prop, type } #define NIP_END() { NULL, 0, 0, 0, 0 } /* Helper for filling callback tables */ #define NIC(cb_id, base, variable, bit) { #cb_id, cpp_offsetof(base, variable), cpp_sizeof(base, variable), bit, cb_id } #define NIC_END() { NULL, 0, 0, 0, 0 } /* Helper for filling variable tables */ #define NIV(var, name) { name, var } #define NIV_END() { NULL, 0 } /*** NewGRF Vehicles ***/ #define NICV(cb_id, bit) NIC(cb_id, Engine, info.callback_mask, bit) static const NICallback _nic_vehicles[] = { NICV(CBID_VEHICLE_VISUAL_EFFECT, CBM_VEHICLE_VISUAL_EFFECT), NICV(CBID_VEHICLE_LENGTH, CBM_VEHICLE_LENGTH), NICV(CBID_VEHICLE_LOAD_AMOUNT, CBM_VEHICLE_LOAD_AMOUNT), NICV(CBID_VEHICLE_REFIT_CAPACITY, CBM_VEHICLE_REFIT_CAPACITY), NICV(CBID_VEHICLE_ARTIC_ENGINE, CBM_VEHICLE_ARTIC_ENGINE), NICV(CBID_VEHICLE_CARGO_SUFFIX, CBM_VEHICLE_CARGO_SUFFIX), NICV(CBID_TRAIN_ALLOW_WAGON_ATTACH, CBM_NO_BIT), NICV(CBID_VEHICLE_ADDITIONAL_TEXT, CBM_NO_BIT), NICV(CBID_VEHICLE_COLOUR_MAPPING, CBM_VEHICLE_COLOUR_REMAP), NICV(CBID_VEHICLE_START_STOP_CHECK, CBM_NO_BIT), NICV(CBID_VEHICLE_32DAY_CALLBACK, CBM_NO_BIT), NICV(CBID_VEHICLE_SOUND_EFFECT, CBM_VEHICLE_SOUND_EFFECT), NICV(CBID_VEHICLE_AUTOREPLACE_SELECTION, CBM_NO_BIT), NICV(CBID_VEHICLE_MODIFY_PROPERTY, CBM_NO_BIT), NIC_END() }; static const NIVariable _niv_vehicles[] = { NIV(0x40, "position in consist and length"), NIV(0x41, "position and length of chain of same vehicles"), NIV(0x42, "transported cargo types"), NIV(0x43, "player info"), NIV(0x44, "aircraft info"), NIV(0x45, "curvature info"), NIV(0x46, "motion counter"), NIV(0x47, "vehicle cargo info"), NIV(0x48, "vehicle type info"), NIV(0x49, "year of construction"), NIV(0x4A, "current rail type info"), NIV(0x4B, "long date of last service"), NIV(0x4C, "current max speed"), NIV(0x4D, "position in articulated vehicle"), NIV(0x60, "count vehicle id occurrences"), // 0x61 not useful, since it requires register 0x10F NIV(0x62, "Curvature/position difference to other vehicle"), NIV_END() }; class NIHVehicle : public NIHelper { bool IsInspectable(uint index) const { return Vehicle::Get(index)->GetGRF() != NULL; } uint GetParent(uint index) const { const Vehicle *first = Vehicle::Get(index)->First(); return GetInspectWindowNumber(GetGrfSpecFeature(first->type), first->index); } const void *GetInstance(uint index)const { return Vehicle::Get(index); } const void *GetSpec(uint index) const { return Vehicle::Get(index)->GetEngine(); } void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_VEHICLE_NAME, index); } uint32 GetGRFID(uint index) const { return Vehicle::Get(index)->GetGRFID(); } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { Vehicle *v = Vehicle::Get(index); VehicleResolverObject ro(v->engine_type, v, VehicleResolverObject::WO_CACHED); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_vehicle = { NULL, _nic_vehicles, _niv_vehicles, new NIHVehicle(), }; /*** NewGRF station (tiles) ***/ #define NICS(cb_id, bit) NIC(cb_id, StationSpec, callback_mask, bit) static const NICallback _nic_stations[] = { NICS(CBID_STATION_AVAILABILITY, CBM_STATION_AVAIL), NICS(CBID_STATION_SPRITE_LAYOUT, CBM_STATION_SPRITE_LAYOUT), NICS(CBID_STATION_TILE_LAYOUT, CBM_NO_BIT), NICS(CBID_STATION_ANIM_START_STOP, CBM_NO_BIT), NICS(CBID_STATION_ANIM_NEXT_FRAME, CBM_STATION_ANIMATION_NEXT_FRAME), NICS(CBID_STATION_ANIMATION_SPEED, CBM_STATION_ANIMATION_SPEED), NICS(CBID_STATION_LAND_SLOPE_CHECK, CBM_STATION_SLOPE_CHECK), NIC_END() }; static const NIVariable _niv_stations[] = { NIV(0x40, "platform info and relative position"), NIV(0x41, "platform info and relative position for individually built sections"), NIV(0x42, "terrain and track type"), NIV(0x43, "player info"), NIV(0x44, "path signalling info"), NIV(0x45, "rail continuation info"), NIV(0x46, "platform info and relative position from middle"), NIV(0x47, "platform info and relative position from middle for individually built sections"), NIV(0x48, "bitmask of accepted cargoes"), NIV(0x49, "platform info and relative position of same-direction section"), NIV(0x4A, "current animation frame"), NIV(0x60, "amount of cargo waiting"), NIV(0x61, "time since last cargo pickup"), NIV(0x62, "rating of cargo"), NIV(0x63, "time spent on route"), NIV(0x64, "information about last vehicle picking cargo up"), NIV(0x65, "amount of cargo acceptance"), NIV(0x66, "animation frame of nearby tile"), NIV(0x67, "land info of nearby tiles"), NIV(0x68, "station info of nearby tiles"), NIV(0x69, "information about cargo accepted in the past"), NIV_END() }; class NIHStation : public NIHelper { bool IsInspectable(uint index) const { return GetStationSpec(index) != NULL; } uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); } const void *GetInstance(uint index)const { return NULL; } const void *GetSpec(uint index) const { return GetStationSpec(index); } void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? GetStationSpec(index)->grf_prop.grffile->grfid : 0; } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { StationResolverObject ro(GetStationSpec(index), Station::GetByTile(index), index); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_station = { NULL, _nic_stations, _niv_stations, new NIHStation(), }; /*** NewGRF house tiles ***/ #define NICH(cb_id, bit) NIC(cb_id, HouseSpec, callback_mask, bit) static const NICallback _nic_house[] = { NICH(CBID_HOUSE_ALLOW_CONSTRUCTION, CBM_HOUSE_ALLOW_CONSTRUCTION), NICH(CBID_HOUSE_ANIMATION_NEXT_FRAME, CBM_HOUSE_ANIMATION_NEXT_FRAME), NICH(CBID_HOUSE_ANIMATION_START_STOP, CBM_HOUSE_ANIMATION_START_STOP), NICH(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE), NICH(CBID_HOUSE_COLOUR, CBM_HOUSE_COLOUR), NICH(CBID_HOUSE_CARGO_ACCEPTANCE, CBM_HOUSE_CARGO_ACCEPTANCE), NICH(CBID_HOUSE_ANIMATION_SPEED, CBM_HOUSE_ANIMATION_SPEED), NICH(CBID_HOUSE_DESTRUCTION, CBM_HOUSE_DESTRUCTION), NICH(CBID_HOUSE_ACCEPT_CARGO, CBM_HOUSE_ACCEPT_CARGO), NICH(CBID_HOUSE_PRODUCE_CARGO, CBM_HOUSE_PRODUCE_CARGO), NICH(CBID_HOUSE_DENY_DESTRUCTION, CBM_HOUSE_DENY_DESTRUCTION), NICH(CBID_HOUSE_WATCHED_CARGO_ACCEPTED, CBM_NO_BIT), NICH(CBID_HOUSE_CUSTOM_NAME, CBM_NO_BIT), NICH(CBID_HOUSE_DRAW_FOUNDATIONS, CBM_HOUSE_DRAW_FOUNDATIONS), NICH(CBID_HOUSE_AUTOSLOPE, CBM_HOUSE_AUTOSLOPE), NIC_END() }; static const NIVariable _niv_house[] = { NIV(0x40, "construction state of tile and pseudo-random value"), NIV(0x41, "age of building in years"), NIV(0x42, "town zone"), NIV(0x43, "terrain type"), NIV(0x44, "building counts"), NIV(0x45, "town expansion bits"), NIV(0x46, "current animation frame"), NIV(0x47, "xy coordinate of the building"), NIV(0x60, "other building counts (old house type)"), NIV(0x61, "other building counts (new house type)"), NIV(0x62, "land info of nearby tiles"), NIV(0x63, "current animation frame of nearby house tile"), NIV(0x64, "cargo acceptance history of nearby stations"), NIV(0x65, "distance of nearest house matching a given criterion"), NIV(0x66, "class and ID of nearby house tile"), NIV(0x67, "GRFID of nearby house tile"), NIV_END() }; class NIHHouse : public NIHelper { bool IsInspectable(uint index) const { return HouseSpec::Get(GetHouseType(index))->grf_prop.grffile != NULL; } uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, GetTownIndex(index)); } const void *GetInstance(uint index)const { return NULL; } const void *GetSpec(uint index) const { return HouseSpec::Get(GetHouseType(index)); } void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_TOWN_NAME, GetTownIndex(index), index); } uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? HouseSpec::Get(GetHouseType(index))->grf_prop.grffile->grfid : 0; } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { HouseResolverObject ro(GetHouseType(index), index, Town::GetByTile(index)); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_house = { NULL, _nic_house, _niv_house, new NIHHouse(), }; /*** NewGRF industry tiles ***/ #define NICIT(cb_id, bit) NIC(cb_id, IndustryTileSpec, callback_mask, bit) static const NICallback _nic_industrytiles[] = { NICIT(CBID_INDTILE_ANIM_START_STOP, CBM_NO_BIT), NICIT(CBID_INDTILE_ANIM_NEXT_FRAME, CBM_INDT_ANIM_NEXT_FRAME), NICIT(CBID_INDTILE_ANIMATION_SPEED, CBM_INDT_ANIM_SPEED), NICIT(CBID_INDTILE_CARGO_ACCEPTANCE, CBM_INDT_CARGO_ACCEPTANCE), NICIT(CBID_INDTILE_ACCEPT_CARGO, CBM_INDT_ACCEPT_CARGO), NICIT(CBID_INDTILE_SHAPE_CHECK, CBM_INDT_SHAPE_CHECK), NICIT(CBID_INDTILE_DRAW_FOUNDATIONS, CBM_INDT_DRAW_FOUNDATIONS), NICIT(CBID_INDTILE_AUTOSLOPE, CBM_INDT_AUTOSLOPE), NIC_END() }; static const NIVariable _niv_industrytiles[] = { NIV(0x40, "construction state of tile"), NIV(0x41, "ground type"), NIV(0x42, "current town zone in nearest town"), NIV(0x43, "relative position"), NIV(0x44, "animation frame"), NIV(0x60, "land info of nearby tiles"), NIV(0x61, "animation stage of nearby tiles"), NIV(0x62, "get industry or airport tile ID at offset"), NIV_END() }; class NIHIndustryTile : public NIHelper { bool IsInspectable(uint index) const { return GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile != NULL; } uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_INDUSTRIES, GetIndustryIndex(index)); } const void *GetInstance(uint index)const { return NULL; } const void *GetSpec(uint index) const { return GetIndustryTileSpec(GetIndustryGfx(index)); } void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_INDUSTRY_NAME, GetIndustryIndex(index), index); } uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? GetIndustryTileSpec(GetIndustryGfx(index))->grf_prop.grffile->grfid : 0; } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { IndustryTileResolverObject ro(GetIndustryGfx(index), index, Industry::GetByTile(index)); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_industrytile = { NULL, _nic_industrytiles, _niv_industrytiles, new NIHIndustryTile(), }; /*** NewGRF industries ***/ static const NIProperty _nip_industries[] = { NIP(0x10, Industry, produced_cargo[0], NIT_CARGO, "produced cargo 0"), NIP(0x10, Industry, produced_cargo[1], NIT_CARGO, "produced cargo 1"), NIP(0x11, Industry, accepts_cargo[0], NIT_CARGO, "accepted cargo 0"), NIP(0x11, Industry, accepts_cargo[1], NIT_CARGO, "accepted cargo 1"), NIP(0x11, Industry, accepts_cargo[2], NIT_CARGO, "accepted cargo 2"), NIP_END() }; #define NICI(cb_id, bit) NIC(cb_id, IndustrySpec, callback_mask, bit) static const NICallback _nic_industries[] = { NICI(CBID_INDUSTRY_PROBABILITY, CBM_IND_PROBABILITY), NICI(CBID_INDUSTRY_LOCATION, CBM_IND_LOCATION), NICI(CBID_INDUSTRY_PRODUCTION_CHANGE, CBM_IND_PRODUCTION_CHANGE), NICI(CBID_INDUSTRY_MONTHLYPROD_CHANGE, CBM_IND_MONTHLYPROD_CHANGE), NICI(CBID_INDUSTRY_CARGO_SUFFIX, CBM_IND_CARGO_SUFFIX), NICI(CBID_INDUSTRY_FUND_MORE_TEXT, CBM_IND_FUND_MORE_TEXT), NICI(CBID_INDUSTRY_WINDOW_MORE_TEXT, CBM_IND_WINDOW_MORE_TEXT), NICI(CBID_INDUSTRY_SPECIAL_EFFECT, CBM_IND_SPECIAL_EFFECT), NICI(CBID_INDUSTRY_REFUSE_CARGO, CBM_IND_REFUSE_CARGO), NICI(CBID_INDUSTRY_DECIDE_COLOUR, CBM_IND_DECIDE_COLOUR), NICI(CBID_INDUSTRY_INPUT_CARGO_TYPES, CBM_IND_INPUT_CARGO_TYPES), NICI(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, CBM_IND_OUTPUT_CARGO_TYPES), NICI(CBID_INDUSTRY_PROD_CHANGE_BUILD, CBM_IND_PROD_CHANGE_BUILD), NIC_END() }; static const NIVariable _niv_industries[] = { NIV(0x40, "waiting cargo 0"), NIV(0x41, "waiting cargo 1"), NIV(0x42, "waiting cargo 2"), NIV(0x43, "distance to closest dry/land tile"), NIV(0x44, "layout number"), NIV(0x45, "player info"), NIV(0x46, "industry construction date"), NIV(0x60, "get industry tile ID at offset"), NIV(0x61, "get random tile bits at offset"), NIV(0x62, "land info of nearby tiles"), NIV(0x63, "animation stage of nearby tiles"), NIV(0x64, "distance on nearest industry with given type"), NIV(0x65, "get town zone and Manhattan distance of closest town"), NIV(0x66, "get square of Euclidean distance of closes town"), NIV(0x67, "count of industry and distance of closest instance"), NIV(0x68, "count of industry and distance of closest instance with layout filter"), NIV_END() }; class NIHIndustry : public NIHelper { bool IsInspectable(uint index) const { return GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile != NULL; } uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Industry::Get(index)->town->index); } const void *GetInstance(uint index)const { return Industry::Get(index); } const void *GetSpec(uint index) const { return GetIndustrySpec(Industry::Get(index)->type); } void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_INDUSTRY_NAME, index); } uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? GetIndustrySpec(Industry::Get(index)->type)->grf_prop.grffile->grfid : 0; } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { Industry *i = Industry::Get(index); IndustriesResolverObject ro(i->location.tile, i, i->type); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } uint GetPSASize(uint index, uint32 grfid) const { return cpp_lengthof(PersistentStorage, storage); } const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const { const Industry *i = (const Industry *)this->GetInstance(index); if (i->psa == NULL) return NULL; return (int32 *)(&i->psa->storage); } }; static const NIFeature _nif_industry = { _nip_industries, _nic_industries, _niv_industries, new NIHIndustry(), }; /*** NewGRF objects ***/ #define NICO(cb_id, bit) NIC(cb_id, ObjectSpec, callback_mask, bit) static const NICallback _nic_objects[] = { NICO(CBID_OBJECT_LAND_SLOPE_CHECK, CBM_OBJ_SLOPE_CHECK), NICO(CBID_OBJECT_ANIMATION_NEXT_FRAME, CBM_OBJ_ANIMATION_NEXT_FRAME), NICO(CBID_OBJECT_ANIMATION_START_STOP, CBM_NO_BIT), NICO(CBID_OBJECT_ANIMATION_SPEED, CBM_OBJ_ANIMATION_SPEED), NICO(CBID_OBJECT_COLOUR, CBM_OBJ_COLOUR), NICO(CBID_OBJECT_FUND_MORE_TEXT, CBM_OBJ_FUND_MORE_TEXT), NICO(CBID_OBJECT_AUTOSLOPE, CBM_OBJ_AUTOSLOPE), NIC_END() }; static const NIVariable _niv_objects[] = { NIV(0x40, "relative position"), NIV(0x41, "tile information"), NIV(0x42, "construction date"), NIV(0x43, "animation counter"), NIV(0x44, "object founder"), NIV(0x45, "get town zone and Manhattan distance of closest town"), NIV(0x46, "get square of Euclidean distance of closes town"), NIV(0x47, "colour"), NIV(0x48, "view"), NIV(0x60, "get object ID at offset"), NIV(0x61, "get random tile bits at offset"), NIV(0x62, "land info of nearby tiles"), NIV(0x63, "animation stage of nearby tiles"), NIV(0x64, "distance on nearest object with given type"), NIV_END() }; class NIHObject : public NIHelper { bool IsInspectable(uint index) const { return ObjectSpec::GetByTile(index)->grf_prop.grffile != NULL; } uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Object::GetByTile(index)->town->index); } const void *GetInstance(uint index)const { return Object::GetByTile(index); } const void *GetSpec(uint index) const { return ObjectSpec::GetByTile(index); } void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT, INVALID_STRING_ID, index); } uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? ObjectSpec::GetByTile(index)->grf_prop.grffile->grfid : 0; } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { ObjectResolverObject ro(ObjectSpec::GetByTile(index), Object::GetByTile(index), index); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_object = { NULL, _nic_objects, _niv_objects, new NIHObject(), }; /*** NewGRF rail types ***/ static const NIVariable _niv_railtypes[] = { NIV(0x40, "terrain type"), NIV(0x41, "enhanced tunnels"), NIV(0x42, "level crossing status"), NIV(0x43, "construction date"), NIV(0x44, "town zone"), NIV_END() }; class NIHRailType : public NIHelper { bool IsInspectable(uint index) const { return true; } uint GetParent(uint index) const { return UINT32_MAX; } const void *GetInstance(uint index)const { return NULL; } const void *GetSpec(uint index) const { return NULL; } void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE, INVALID_STRING_ID, index); } uint32 GetGRFID(uint index) const { return 0; } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { /* There is no unique GRFFile for the tile. Multiple GRFs can define different parts of the railtype. * However, currently the NewGRF Debug GUI does not display variables depending on the GRF (like 0x7F) anyway. */ RailTypeResolverObject ro(NULL, index, TCX_NORMAL, RTSG_END); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_railtype = { NULL, NULL, _niv_railtypes, new NIHRailType(), }; /*** NewGRF airport tiles ***/ #define NICAT(cb_id, bit) NIC(cb_id, AirportTileSpec, callback_mask, bit) static const NICallback _nic_airporttiles[] = { NICAT(CBID_AIRPTILE_DRAW_FOUNDATIONS, CBM_AIRT_DRAW_FOUNDATIONS), NICAT(CBID_AIRPTILE_ANIM_START_STOP, CBM_NO_BIT), NICAT(CBID_AIRPTILE_ANIM_NEXT_FRAME, CBM_AIRT_ANIM_NEXT_FRAME), NICAT(CBID_AIRPTILE_ANIMATION_SPEED, CBM_AIRT_ANIM_SPEED), NIC_END() }; class NIHAirportTile : public NIHelper { bool IsInspectable(uint index) const { return AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile != NULL; } uint GetParent(uint index) const { return GetInspectWindowNumber(GSF_FAKE_TOWNS, Station::GetByTile(index)->town->index); } const void *GetInstance(uint index)const { return NULL; } const void *GetSpec(uint index) const { return AirportTileSpec::Get(GetAirportGfx(index)); } void SetStringParameters(uint index) const { this->SetObjectAtStringParameters(STR_STATION_NAME, GetStationIndex(index), index); } uint32 GetGRFID(uint index) const { return (this->IsInspectable(index)) ? AirportTileSpec::Get(GetAirportGfx(index))->grf_prop.grffile->grfid : 0; } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { AirportTileResolverObject ro(AirportTileSpec::GetByTile(index), index, Station::GetByTile(index)); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } }; static const NIFeature _nif_airporttile = { NULL, _nic_airporttiles, _niv_industrytiles, // Yes, they share this (at least now) new NIHAirportTile(), }; /*** NewGRF towns ***/ static const NIVariable _niv_towns[] = { NIV(0x40, "larger town effect on this town"), NIV(0x41, "town index"), NIV(0x82, "population"), NIV(0x94, "zone radius 0"), NIV(0x96, "zone radius 1"), NIV(0x98, "zone radius 2"), NIV(0x9A, "zone radius 3"), NIV(0x9C, "zone radius 4"), NIV(0xB6, "number of buildings"), NIV_END() }; class NIHTown : public NIHelper { bool IsInspectable(uint index) const { return Town::IsValidID(index); } uint GetParent(uint index) const { return UINT32_MAX; } const void *GetInstance(uint index)const { return Town::Get(index); } const void *GetSpec(uint index) const { return NULL; } void SetStringParameters(uint index) const { this->SetSimpleStringParameters(STR_TOWN_NAME, index); } uint32 GetGRFID(uint index) const { return 0; } bool PSAWithParameter() const { return true; } uint GetPSASize(uint index, uint32 grfid) const { return cpp_lengthof(PersistentStorage, storage); } /* virtual */ uint Resolve(uint index, uint var, uint param, bool *avail) const { TownResolverObject ro(NULL, Town::Get(index), true); return ro.GetScope(VSG_SCOPE_SELF)->GetVariable(var, param, avail); } const int32 *GetPSAFirstPosition(uint index, uint32 grfid) const { Town *t = Town::Get(index); std::list::iterator iter; for (iter = t->psa_list.begin(); iter != t->psa_list.end(); iter++) { if ((*iter)->grfid == grfid) return (int32 *)(&(*iter)->storage[0]); } return NULL; } }; static const NIFeature _nif_town = { NULL, NULL, _niv_towns, new NIHTown(), }; /** Table with all NIFeatures. */ static const NIFeature * const _nifeatures[] = { &_nif_vehicle, // GSF_TRAINS &_nif_vehicle, // GSF_ROADVEHICLES &_nif_vehicle, // GSF_SHIPS &_nif_vehicle, // GSF_AIRCRAFT &_nif_station, // GSF_STATIONS NULL, // GSF_CANALS (no callbacks/action2 implemented) NULL, // GSF_BRIDGES (no callbacks/action2) &_nif_house, // GSF_HOUSES NULL, // GSF_GLOBALVAR (has no "physical" objects) &_nif_industrytile, // GSF_INDUSTRYTILES &_nif_industry, // GSF_INDUSTRIES NULL, // GSF_CARGOES (has no "physical" objects) NULL, // GSF_SOUNDFX (has no "physical" objects) NULL, // GSF_AIRPORTS (feature not implemented) NULL, // GSF_SIGNALS (feature not implemented) &_nif_object, // GSF_OBJECTS &_nif_railtype, // GSF_RAILTYPES &_nif_airporttile, // GSF_AIRPORTTILES &_nif_town, // GSF_FAKE_TOWNS }; assert_compile(lengthof(_nifeatures) == GSF_FAKE_END); openttd-1.5.3/src/table/water_land.h0000644000000000000000000001277512627373436016073 0ustar rootroot/* $Id: water_land.h 22646 2011-07-10 13:04:04Z frosch $ */ /* * 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 water_land.h Sprites to use and how to display them for water tiles (depots/locks). */ /** * Constructor macro for an image without a palette in a DrawTileSeqStruct array. * @param dx Offset in x direction * @param dy Offset in y direction * @param dz Offset in z direction * @param sx Size in x direction * @param sy Size in y direction * @param sz Size in z direction * @param img Sprite to draw */ #define TILE_SEQ_LINE(dx, dy, dz, sx, sy, sz, img) { dx, dy, dz, sx, sy, sz, {img, PAL_NONE} }, /** Constructor macro for a terminating DrawTileSeqStruct entry in an array */ #define TILE_SEQ_END() { (int8)0x80, 0, 0, 0, 0, 0, {0, 0} } /** * Constructor macro of a DrawTileSprites structure * @param img Ground sprite without palette of the tile * @param dtss Sequence child sprites of the tile */ #define TILE_SPRITE_LINE(img, dtss) { {img, PAL_NONE}, dtss }, static const DrawTileSeqStruct _shipdepot_display_seq_1[] = { TILE_SEQ_LINE( 0, 15, 0, 16, 1, 0x14, 0xFE8 | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _shipdepot_display_seq_2[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 1, 0x14, 0xFEA) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 0x14, 0xFE6 | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _shipdepot_display_seq_3[] = { TILE_SEQ_LINE( 15, 0, 0, 1, 0x10, 0x14, 0xFE9 | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _shipdepot_display_seq_4[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 16, 0x14, 0xFEB) TILE_SEQ_LINE( 15, 0, 0, 1, 16, 0x14, 0xFE7 | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSprites _shipdepot_display_data[][DEPOT_PART_END] = { { // AXIS_X TILE_SPRITE_LINE(0xFDD, _shipdepot_display_seq_1) // DEPOT_PART_NORTH TILE_SPRITE_LINE(0xFDD, _shipdepot_display_seq_2) // DEPOT_PART_SOUTH }, { // AXIS_Y TILE_SPRITE_LINE(0xFDD, _shipdepot_display_seq_3) // DEPOT_PART_NORTH TILE_SPRITE_LINE(0xFDD, _shipdepot_display_seq_4) // DEPOT_PART_SOUTH }, }; static const DrawTileSeqStruct _lock_display_seq_0[] = { TILE_SEQ_LINE( 0, 0, 0, 0x10, 1, 0x14, 0 + 1) TILE_SEQ_LINE( 0, 0xF, 0, 0x10, 1, 0x14, 4 + 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_1[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 0x10, 0x14, 0) TILE_SEQ_LINE( 0xF, 0, 0, 1, 0x10, 0x14, 4) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_2[] = { TILE_SEQ_LINE( 0, 0, 0, 0x10, 1, 0x14, 0 + 2) TILE_SEQ_LINE( 0, 0xF, 0, 0x10, 1, 0x14, 4 + 2) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_3[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 0x10, 0x14, 0 + 3) TILE_SEQ_LINE( 0xF, 0, 0, 1, 0x10, 0x14, 4 + 3) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_0b[] = { TILE_SEQ_LINE( 0, 0, 0, 0x10, 1, 0x14, 8 + 1) TILE_SEQ_LINE( 0, 0xF, 0, 0x10, 1, 0x14, 12 + 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_1b[] = { TILE_SEQ_LINE( 0, 0, 0, 0x1, 0x10, 0x14, 8) TILE_SEQ_LINE( 0xF, 0, 0, 0x1, 0x10, 0x14, 12) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_2b[] = { TILE_SEQ_LINE( 0, 0, 0, 0x10, 1, 0x14, 8 + 2) TILE_SEQ_LINE( 0, 0xF, 0, 0x10, 1, 0x14, 12 + 2) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_3b[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 0x10, 0x14, 8 + 3) TILE_SEQ_LINE( 0xF, 0, 0, 1, 0x10, 0x14, 12 + 3) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_0t[] = { TILE_SEQ_LINE( 0, 0, 0, 0x10, 1, 0x14, 16 + 1) TILE_SEQ_LINE( 0, 0xF, 0, 0x10, 1, 0x14, 20 + 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_1t[] = { TILE_SEQ_LINE( 0, 0, 0, 0x1, 0x10, 0x14, 16) TILE_SEQ_LINE( 0xF, 0, 0, 0x1, 0x10, 0x14, 20) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_2t[] = { TILE_SEQ_LINE( 0, 0, 0, 0x10, 1, 0x14, 16 + 2) TILE_SEQ_LINE( 0, 0xF, 0, 0x10, 1, 0x14, 20 + 2) TILE_SEQ_END() }; static const DrawTileSeqStruct _lock_display_seq_3t[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 0x10, 0x14, 16 + 3) TILE_SEQ_LINE( 0xF, 0, 0, 1, 0x10, 0x14, 20 + 3) TILE_SEQ_END() }; static const DrawTileSprites _lock_display_data[][DIAGDIR_END] = { { // LOCK_PART_MIDDLE TILE_SPRITE_LINE(1, _lock_display_seq_0) // NE TILE_SPRITE_LINE(0, _lock_display_seq_1) // SE TILE_SPRITE_LINE(2, _lock_display_seq_2) // SW TILE_SPRITE_LINE(3, _lock_display_seq_3) // NW }, { // LOCK_PART_LOWER TILE_SPRITE_LINE(0xFDD, _lock_display_seq_0b) // NE TILE_SPRITE_LINE(0xFDD, _lock_display_seq_1b) // SE TILE_SPRITE_LINE(0xFDD, _lock_display_seq_2b) // SW TILE_SPRITE_LINE(0xFDD, _lock_display_seq_3b) // NW }, { // LOCK_PART_UPPER TILE_SPRITE_LINE(0xFDD, _lock_display_seq_0t) // NE TILE_SPRITE_LINE(0xFDD, _lock_display_seq_1t) // SE TILE_SPRITE_LINE(0xFDD, _lock_display_seq_2t) // SW TILE_SPRITE_LINE(0xFDD, _lock_display_seq_3t) // NW }, }; #undef TILE_SEQ_LINE #undef TILE_SEQ_END #undef TILE_SPRITE_LINE openttd-1.5.3/src/table/town_land.h0000644000000000000000000067246612627373436015751 0ustar rootroot/* $Id: town_land.h 25312 2013-06-01 07:44:53Z rubidium $ */ /* * 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 town_land.h Sprites to use and how to display them for town tiles. */ /** * Writes the data into the Town Tile Drawing Struct * @param s1 The first sprite of the building, mostly the ground sprite * @param p1 The first sprite's palette of the building, mostly the ground sprite * @param s2 The second sprite of the building. * @param p2 The second sprite's palette of the building. * @param sx The x-position of the sprite within the tile * @param sy the y-position of the sprite within the tile * @param w the width of the sprite * @param h the height of the sprite * @param dz the virtual height of the sprite * @param p set to 1 if a lift is present () * @see DrawBuildingsTileStruct */ #define M(s1, p1, s2, p2, sx, sy, w, h, dz, p) { { s1, p1 }, { s2, p2 }, sx, sy, w, h, dz, p} /** structure of houses graphics*/ static const DrawBuildingsTileStruct _town_draw_tile_data[] = { M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58d, PAL_NONE, 0, 0, 14, 14, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58e, PAL_NONE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58f, PAL_NONE, 0, 0, 14, 14, 60, 0), M( 0x590, PAL_NONE, 0x58f, PAL_NONE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58d, PAL_NONE, 0, 0, 14, 14, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58e, PAL_NONE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x591, PAL_NONE, 0, 0, 14, 14, 60, 0), M( 0x590, PAL_NONE, 0x591, PAL_NONE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58d, PALETTE_TO_STRUCT_WHITE, 0, 0, 14, 14, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58e, PALETTE_TO_STRUCT_WHITE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x591, PALETTE_TO_STRUCT_WHITE, 0, 0, 14, 14, 60, 0), M( 0x590, PAL_NONE, 0x591, PALETTE_TO_STRUCT_WHITE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58d, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 14, 14, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x58e, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x591, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 14, 14, 60, 0), M( 0x590, PAL_NONE, 0x591, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 14, 14, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x592, PAL_NONE, 0, 0, 14, 16, 11, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x593, PAL_NONE, 0, 0, 14, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x594, PAL_NONE, 0, 0, 14, 16, 33, 0), M( 0x595, PAL_NONE, 0x594, PAL_NONE, 0, 0, 14, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x592, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 11, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x593, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x594, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 33, 0), M( 0x595, PAL_NONE, 0x594, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x592, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 16, 16, 11, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x593, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 16, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x594, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 16, 16, 33, 0), M( 0x595, PAL_NONE, 0x594, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 16, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x592, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 11, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x593, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x594, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 33, 0), M( 0x595, PAL_NONE, 0x594, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 33, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x596, PAL_NONE, 0, 0, 12, 12, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x597, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( 0x599, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x596, PAL_NONE, 0, 0, 12, 12, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x597, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( 0x599, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x596, PAL_NONE, 0, 0, 12, 12, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x597, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( 0x599, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x596, PAL_NONE, 0, 0, 12, 12, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x597, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( 0x599, PAL_NONE, 0x598, PAL_NONE, 0, 0, 12, 12, 17, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59a, PAL_NONE, 0, 0, 14, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59b, PAL_NONE, 0, 0, 14, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59c, PAL_NONE, 0, 0, 14, 16, 35, 0), M( 0x59d, PAL_NONE, 0x59c, PAL_NONE, 0, 0, 14, 16, 35, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59a, PALETTE_CHURCH_RED, 0, 0, 14, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59b, PALETTE_CHURCH_RED, 0, 0, 14, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59c, PALETTE_CHURCH_RED, 0, 0, 14, 16, 35, 0), M( 0x59d, PAL_NONE, 0x59c, PALETTE_CHURCH_RED, 0, 0, 14, 16, 35, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59a, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59b, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59c, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 35, 0), M( 0x59d, PAL_NONE, 0x59c, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 35, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59a, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59b, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x59c, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 35, 0), M( 0x59d, PAL_NONE, 0x59c, PALETTE_CHURCH_CREAM, 0, 0, 14, 16, 35, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5a2, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a0, PAL_NONE, 0, 0, 15, 15, 5, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a1, PAL_NONE, 0, 0, 15, 15, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11d9, PAL_NONE, 0, 0, 15, 15, 53, 1), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a4, PAL_NONE, 0, 0, 16, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a5, PAL_NONE, 0, 0, 16, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a6, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5a7, PAL_NONE, 0x5a6, PAL_NONE, 0, 0, 16, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a4, PAL_NONE, 0, 0, 16, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a5, PAL_NONE, 0, 0, 16, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a6, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5a7, PAL_NONE, 0x5a6, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5dd, PAL_NONE, 0x5de, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5df, PAL_NONE, 0x5e0, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5e1, PAL_NONE, 0x5e2, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5e1, PAL_NONE, 0x5e2, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5dd, PAL_NONE, 0x5de, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5df, PAL_NONE, 0x5e0, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5e1, PAL_NONE, 0x5e2, PAL_NONE, 0, 0, 16, 16, 16, 0), M( 0x5e1, PAL_NONE, 0x5e2, PAL_NONE, 0, 0, 16, 16, 16, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a8, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a9, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a8, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a9, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a8, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a9, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a8, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5a9, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5aa, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ab, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ac, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ab, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ac, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ab, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ac, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ab, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ac, PAL_NONE, 0, 0, 16, 16, 38, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ad, PAL_NONE, 0, 0, 16, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ae, PAL_NONE, 6, 5, 3, 6, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x0, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5af, PAL_NONE, 3, 3, 9, 9, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b0, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M(SPR_FLAT_GRASS_TILE, PAL_NONE, 0x5b1, PAL_NONE, 0, 0, 16, 16, 15, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b2, PAL_NONE, 0, 0, 16, 16, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b3, PAL_NONE, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b4, PAL_NONE, 0, 0, 16, 16, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b4, PAL_NONE, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b2, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b3, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b4, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b4, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b2, PALETTE_TO_STRUCT_RED, 0, 0, 16, 16, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b3, PALETTE_TO_STRUCT_RED, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b4, PALETTE_TO_STRUCT_RED, 0, 0, 16, 16, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b4, PALETTE_TO_STRUCT_RED, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b2, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 8, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b3, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b4, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b4, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b5, PAL_NONE, 1, 3, 14, 11, 7, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b6, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b5, PAL_NONE, 1, 3, 14, 11, 7, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b6, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b5, PAL_NONE, 1, 3, 14, 11, 7, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b6, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b5, PAL_NONE, 1, 3, 14, 11, 7, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b6, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5b7, PAL_NONE, 1, 3, 14, 11, 53, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b8, PAL_NONE, 3, 1, 11, 14, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b9, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b8, PAL_NONE, 3, 1, 11, 14, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b9, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b8, PAL_NONE, 3, 1, 11, 14, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b9, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b8, PAL_NONE, 3, 1, 11, 14, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5b9, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5ba, PAL_NONE, 3, 1, 11, 14, 28, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bb, PAL_NONE, 2, 0, 13, 16, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bc, PAL_NONE, 2, 0, 13, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bd, PAL_NONE, 2, 0, 13, 16, 46, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5bd, PAL_NONE, 2, 0, 13, 16, 46, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bb, PAL_NONE, 2, 0, 13, 16, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bc, PAL_NONE, 2, 0, 13, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bd, PAL_NONE, 2, 0, 13, 16, 46, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5bd, PAL_NONE, 2, 0, 13, 16, 46, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bb, PALETTE_TO_STRUCT_BLUE, 2, 0, 13, 16, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bc, PALETTE_TO_STRUCT_BLUE, 2, 0, 13, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bd, PALETTE_TO_STRUCT_BLUE, 2, 0, 13, 16, 46, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5bd, PALETTE_TO_STRUCT_BLUE, 2, 0, 13, 16, 46, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bb, PALETTE_TO_STRUCT_WHITE, 2, 0, 13, 16, 6, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bc, PALETTE_TO_STRUCT_WHITE, 2, 0, 13, 16, 45, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bd, PALETTE_TO_STRUCT_WHITE, 2, 0, 13, 16, 46, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5bd, PALETTE_TO_STRUCT_WHITE, 2, 0, 13, 16, 46, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5be, PALETTE_TO_RED, 2, 0, 13, 16, 13, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bf, PALETTE_TO_RED, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c0, PALETTE_TO_RED, 2, 0, 13, 16, 110, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c0, PALETTE_TO_RED, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5be, PALETTE_TO_BLUE, 2, 0, 13, 16, 13, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bf, PALETTE_TO_BLUE, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c0, PALETTE_TO_BLUE, 2, 0, 13, 16, 110, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c0, PALETTE_TO_BLUE, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5be, PALETTE_TO_ORANGE, 2, 0, 13, 16, 13, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bf, PALETTE_TO_ORANGE, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c0, PALETTE_TO_ORANGE, 2, 0, 13, 16, 110, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c0, PALETTE_TO_ORANGE, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5be, PALETTE_TO_GREEN, 2, 0, 13, 16, 13, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5bf, PALETTE_TO_GREEN, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c0, PALETTE_TO_GREEN, 2, 0, 13, 16, 110, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c0, PALETTE_TO_GREEN, 2, 0, 13, 16, 110, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c1, PAL_NONE, 1, 2, 15, 12, 4, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c2, PAL_NONE, 1, 2, 15, 12, 24, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c1, PAL_NONE, 1, 2, 15, 12, 4, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c2, PAL_NONE, 1, 2, 15, 12, 24, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c1, PAL_NONE, 1, 2, 15, 12, 4, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c2, PAL_NONE, 1, 2, 15, 12, 24, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c1, PAL_NONE, 1, 2, 15, 12, 4, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c2, PAL_NONE, 1, 2, 15, 12, 24, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c3, PAL_NONE, 1, 2, 15, 12, 31, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c4, PAL_NONE, 1, 0, 14, 15, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c5, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c4, PAL_NONE, 1, 0, 14, 15, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c5, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c4, PAL_NONE, 1, 0, 14, 15, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c5, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c4, PAL_NONE, 1, 0, 14, 15, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c5, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x5c6, PAL_NONE, 1, 0, 14, 15, 42, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_N, PAL_NONE, 0x5cb, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_E, PAL_NONE, 0x5cc, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_W, PAL_NONE, 0x5cd, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_GRND_STADIUM_S, PAL_NONE, 0x5ce, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5d4, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d3, PAL_NONE, 0x5d4, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d3, PAL_NONE, 0x5d4, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d3, PAL_NONE, 0x5d4, PAL_NONE, 0, 0, 16, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5d6, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d5, PAL_NONE, 0x5d6, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d5, PAL_NONE, 0x5d6, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d5, PAL_NONE, 0x5d6, PAL_NONE, 0, 0, 16, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5d0, PAL_NONE, 0, 0, 16, 16, 21, 0), M( 0x5cf, PAL_NONE, 0x5d0, PAL_NONE, 0, 0, 16, 16, 21, 0), M( 0x5cf, PAL_NONE, 0x5d0, PAL_NONE, 0, 0, 16, 16, 21, 0), M( 0x5cf, PAL_NONE, 0x5d0, PAL_NONE, 0, 0, 16, 16, 21, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x5d2, PAL_NONE, 0, 0, 16, 16, 11, 0), M( 0x5d1, PAL_NONE, 0x5d2, PAL_NONE, 0, 0, 16, 16, 11, 0), M( 0x5d1, PAL_NONE, 0x5d2, PAL_NONE, 0, 0, 16, 16, 11, 0), M( 0x5d1, PAL_NONE, 0x5d2, PAL_NONE, 0, 0, 16, 16, 11, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d7, PAL_NONE, 0x5d8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5d9, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5da, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5db, PAL_NONE, 0x5dc, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5db, PAL_NONE, 0x5dc, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x622, PAL_NONE, 0x623, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x624, PAL_NONE, 0x625, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x626, PAL_NONE, 0x627, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x626, PAL_NONE, 0x627, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5e3, PAL_NONE, 0x5e4, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5e5, PAL_NONE, 0x5e6, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5e7, PAL_NONE, 0x5e8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5e7, PAL_NONE, 0x5e8, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5e9, PAL_NONE, 0x5ea, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5eb, PAL_NONE, 0x5ec, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5ed, PAL_NONE, 0x5ee, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5ed, PAL_NONE, 0x5ee, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5ef, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f0, PAL_NONE, 0x5f1, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f2, PAL_NONE, 0x5f3, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f2, PAL_NONE, 0x5f3, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5ef, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f0, PAL_NONE, 0x5f1, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f2, PAL_NONE, 0x5f3, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f2, PAL_NONE, 0x5f3, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f4, PAL_NONE, 0x5f5, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f6, PAL_NONE, 0x5f7, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f8, PAL_NONE, 0x5f9, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f8, PAL_NONE, 0x5f9, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f4, PAL_NONE, 0x5f5, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f6, PAL_NONE, 0x5f7, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f8, PAL_NONE, 0x5f9, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5f8, PAL_NONE, 0x5f9, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x5fa, PAL_NONE, 0x5fb, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x5fc, PAL_NONE, 0x5fd, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x5fe, PAL_NONE, 0x5ff, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x5fe, PAL_NONE, 0x5ff, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x5fa, PAL_NONE, 0x5fb, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x5fc, PAL_NONE, 0x5fd, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x5fe, PAL_NONE, 0x5ff, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x5fe, PAL_NONE, 0x5ff, PAL_NONE, 0, 0, 16, 16, 85, 0), M( 0x60a, PAL_NONE, 0x60b, PAL_NONE, 0, 0, 16, 16, 95, 0), M( 0x60c, PAL_NONE, 0x60d, PAL_NONE, 0, 0, 16, 16, 95, 0), M( 0x60e, PAL_NONE, 0x60f, PAL_NONE, 0, 0, 16, 16, 95, 0), M( 0x60e, PAL_NONE, 0x60f, PAL_NONE, 0, 0, 16, 16, 95, 0), M( 0x60a, PAL_NONE, 0x60b, PAL_NONE, 0, 0, 16, 16, 95, 0), M( 0x60c, PAL_NONE, 0x60d, PAL_NONE, 0, 0, 16, 16, 95, 0), M( 0x60e, PAL_NONE, 0x60f, PAL_NONE, 0, 0, 16, 16, 95, 0), M( 0x60e, PAL_NONE, 0x60f, PAL_NONE, 0, 0, 16, 16, 95, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x600, PAL_NONE, 0x601, PAL_NONE, 0, 0, 16, 16, 55, 0), M( 0x600, PAL_NONE, 0x601, PAL_NONE, 0, 0, 16, 16, 55, 0), M( 0x600, PAL_NONE, 0x601, PAL_NONE, 0, 0, 16, 16, 55, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x600, PALETTE_TO_STRUCT_WHITE, 0x601, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 55, 0), M( 0x600, PALETTE_TO_STRUCT_WHITE, 0x601, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 55, 0), M( 0x600, PALETTE_TO_STRUCT_WHITE, 0x601, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 55, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x602, PAL_NONE, 0x603, PAL_NONE, 0, 0, 16, 16, 42, 0), M( 0x602, PAL_NONE, 0x603, PAL_NONE, 0, 0, 16, 16, 42, 0), M( 0x602, PAL_NONE, 0x603, PAL_NONE, 0, 0, 16, 16, 42, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x602, PALETTE_TO_STRUCT_CONCRETE, 0x603, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 16, 16, 42, 0), M( 0x602, PALETTE_TO_STRUCT_CONCRETE, 0x603, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 16, 16, 42, 0), M( 0x602, PALETTE_TO_STRUCT_CONCRETE, 0x603, PALETTE_TO_STRUCT_CONCRETE, 0, 0, 16, 16, 42, 0), M( 0x604, PAL_NONE, 0x605, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x606, PAL_NONE, 0x607, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x604, PAL_NONE, 0x605, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x606, PAL_NONE, 0x607, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x604, PAL_NONE, 0x605, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x606, PAL_NONE, 0x607, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x604, PAL_NONE, 0x605, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x606, PAL_NONE, 0x607, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( 0x608, PAL_NONE, 0x609, PAL_NONE, 0, 0, 16, 16, 88, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x610, PAL_NONE, 0x611, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x612, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x612, PAL_NONE, 0x616, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x613, PAL_NONE, 0x617, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x614, PAL_NONE, 0x618, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x615, PAL_NONE, 0x619, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61c, PAL_NONE, 0x61d, PAL_NONE, 0, 0, 16, 16, 100, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61c, PAL_NONE, 0x61d, PAL_NONE, 0, 0, 16, 16, 100, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61c, PAL_NONE, 0x61d, PAL_NONE, 0, 0, 16, 16, 100, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61a, PAL_NONE, 0x61b, PAL_NONE, 0, 0, 16, 16, 100, 0), M( 0x61c, PAL_NONE, 0x61d, PAL_NONE, 0, 0, 16, 16, 100, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x61e, PAL_NONE, 0x61f, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x61e, PAL_NONE, 0x61f, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x61e, PAL_NONE, 0x61f, PAL_NONE, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x61e, PALETTE_TO_STRUCT_WHITE, 0x61f, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 25, 0), M( 0x61e, PALETTE_TO_STRUCT_WHITE, 0x61f, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 25, 0), M( 0x61e, PALETTE_TO_STRUCT_WHITE, 0x61f, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x620, PAL_NONE, 0x621, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x620, PAL_NONE, 0x621, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x620, PAL_NONE, 0x621, PAL_NONE, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x620, PALETTE_TO_CREAM, 0x621, PALETTE_TO_CREAM, 0, 0, 16, 16, 25, 0), M( 0x620, PALETTE_TO_CREAM, 0x621, PALETTE_TO_CREAM, 0, 0, 16, 16, 25, 0), M( 0x620, PALETTE_TO_CREAM, 0x621, PALETTE_TO_CREAM, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x11da, PAL_NONE, 0x11db, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11da, PAL_NONE, 0x11db, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11da, PAL_NONE, 0x11db, PAL_NONE, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x11da, PALETTE_TO_STRUCT_WHITE, 0x11db, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 25, 0), M( 0x11da, PALETTE_TO_STRUCT_WHITE, 0x11db, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 25, 0), M( 0x11da, PALETTE_TO_STRUCT_WHITE, 0x11db, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x11dc, PAL_NONE, 0x11dd, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11dc, PAL_NONE, 0x11dd, PAL_NONE, 0, 0, 16, 16, 25, 0), M( 0x11dc, PAL_NONE, 0x11dd, PAL_NONE, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x11dc, PALETTE_TO_CREAM, 0x11dd, PALETTE_TO_CREAM, 0, 0, 16, 16, 25, 0), M( 0x11dc, PALETTE_TO_CREAM, 0x11dd, PALETTE_TO_CREAM, 0, 0, 16, 16, 25, 0), M( 0x11dc, PALETTE_TO_CREAM, 0x11dd, PALETTE_TO_CREAM, 0, 0, 16, 16, 25, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 22, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1134, PAL_NONE, 0x1135, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1136, PAL_NONE, 0x1137, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113b, PAL_NONE, 0x113c, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1138, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113d, PAL_NONE, 0x113e, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1139, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113f, PAL_NONE, 0x1140, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x113a, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1141, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x1147, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x1147, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x1147, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1144, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1145, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1146, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x1147, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1142, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x114b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x114b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x114b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1148, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1149, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1143, PAL_NONE, 0x114b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x114c, PAL_NONE, 0x1150, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( 0x114c, PAL_NONE, 0x1150, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( 0x114c, PAL_NONE, 0x1150, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( 0x114c, PAL_NONE, 0x1150, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x114d, PAL_NONE, 0x1151, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( 0x114d, PAL_NONE, 0x1151, PALETTE_TO_PINK, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( 0x114d, PAL_NONE, 0x1151, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114e, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x114f, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1150, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( 0x114d, PAL_NONE, 0x1151, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1155, PAL_NONE, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x1155, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1155, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x1155, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1155, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x1155, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1155, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x1155, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11de, PAL_NONE, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x11de, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11de, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x11de, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11de, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x11de, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1153, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1154, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11de, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1152, PAL_NONE, 0x11de, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1159, PAL_NONE, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x1159, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1159, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x1159, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1159, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x1159, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1159, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x1159, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11df, PAL_NONE, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x11df, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11df, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x11df, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11df, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x11df, PALETTE_TO_CREAM, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1157, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1158, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11df, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( 0x1156, PAL_NONE, 0x11df, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x115d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115d, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x115d, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115d, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x115d, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115d, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x115d, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e0, PAL_NONE, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x11e0, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e0, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x11e0, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e0, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x11e0, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115b, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x115c, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e0, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x115a, PAL_NONE, 0x11e0, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1160, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1161, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1162, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x115e, PAL_NONE, 0x1162, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1160, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1161, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1162, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x115e, PAL_NONE, 0x1162, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1166, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1167, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1168, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1164, PAL_NONE, 0x1168, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1166, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1167, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1168, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1164, PAL_NONE, 0x1168, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1160, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1161, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1162, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x115f, PAL_NONE, 0x1163, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1160, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1161, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1162, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x115f, PAL_NONE, 0x1163, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1166, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1167, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1168, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1165, PAL_NONE, 0x1169, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1166, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1167, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1168, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x1165, PAL_NONE, 0x1169, PAL_NONE, 0, 0, 16, 16, 20, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x116d, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116b, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x116c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116a, PAL_NONE, 0x11e2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x1171, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116f, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1170, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x116e, PAL_NONE, 0x11e3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1172, PAL_NONE, 0x1175, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( 0x1172, PAL_NONE, 0x1175, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( 0x1172, PAL_NONE, 0x1175, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( 0x1172, PAL_NONE, 0x1175, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x11e4, PAL_NONE, 0x11e5, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( 0x11e4, PAL_NONE, 0x11e5, PALETTE_TO_BROWN, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( 0x11e4, PAL_NONE, 0x11e5, PALETTE_TO_CREAM, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1173, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1174, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1175, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( 0x11e4, PAL_NONE, 0x11e5, PALETTE_TO_GREY, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1176, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e6, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 60, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117b, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117c, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1177, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1179, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e7, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( 0x1178, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117a, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e8, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x117f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x117f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117f, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x117f, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117f, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x117f, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e1, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11e1, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e1, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11e1, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e1, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11e1, PALETTE_TO_STRUCT_BROWN, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117d, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x117e, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11e1, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M(SPR_CONCRETE_GROUND, PAL_NONE, 0x11e1, PALETTE_TO_STRUCT_WHITE, 0, 0, 16, 16, 50, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1184, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1184, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1184, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1184, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x11e9, PALETTE_TO_DARK_GREEN, 0, 0, 16, 16, 60, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x11e9, PALETTE_TO_ORANGE, 0, 0, 16, 16, 60, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x11e9, PALETTE_TO_BROWN, 0, 0, 16, 16, 60, 0), M( 0x1180, PAL_NONE, 0x1181, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x1182, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1183, PAL_NONE, 0x11e9, PALETTE_TO_GREY, 0, 0, 16, 16, 60, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x118b, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x118b, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x118b, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x118b, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118c, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118c, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118c, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118c, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x11ea, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x11ea, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x11ea, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1187, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x1189, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1185, PAL_NONE, 0x11ea, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x11eb, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x11eb, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x11eb, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x1188, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x118a, PAL_NONE, 0, 0, 16, 16, 10, 0), M( 0x1186, PAL_NONE, 0x11eb, PAL_NONE, 0, 0, 16, 16, 10, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ec, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ee, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ec, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ee, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ec, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ee, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ec, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ed, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ee, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ef, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f1, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ef, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f1, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ef, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f1, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ef, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f1, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f4, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f4, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f4, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f2, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f3, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f4, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f5, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f5, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f5, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f6, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f6, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f6, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f7, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f7, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f7, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f8, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f8, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f8, PAL_NONE, 0, 0, 16, 16, 20, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f9, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fb, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f9, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fb, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f9, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fb, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11f9, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fa, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fb, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fc, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fd, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ff, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fd, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ff, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fd, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ff, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fd, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11fe, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x11ff, PAL_NONE, 0, 0, 16, 16, 40, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1200, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1202, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1200, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1202, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1200, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1202, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1200, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1201, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1202, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1203, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1205, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1203, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1205, PALETTE_TO_PINK, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1203, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1205, PALETTE_TO_YELLOW, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1203, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1204, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1205, PALETTE_TO_RED, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1206, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120a, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1206, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120a, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1206, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120a, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1206, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1208, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120a, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1207, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120b, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1207, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120b, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1207, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120b, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1207, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1209, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120b, PAL_NONE, 0, 0, 16, 16, 80, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120c, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120e, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120c, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120e, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120c, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120e, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120c, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120d, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120e, PAL_NONE, 0, 0, 16, 16, 60, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1211, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1211, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1211, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x120f, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1210, PAL_NONE, 0, 0, 16, 16, 50, 0), M( SPR_FLAT_BARE_LAND, PAL_NONE, 0x1211, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1213, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1214, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1214, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1215, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1213, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1214, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1214, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1215, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1213, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1214, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1214, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1215, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1213, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1214, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1214, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1215, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1216, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1218, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1216, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1218, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1216, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1218, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1216, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1217, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1218, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1219, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1219, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1219, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1219, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1220, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1220, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1221, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121f, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1220, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1220, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1221, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x121f, PALETTE_TO_MAUVE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1220, PALETTE_TO_MAUVE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1220, PALETTE_TO_MAUVE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1221, PALETTE_TO_MAUVE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x121f, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1220, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1220, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1221, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1222, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1223, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1223, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1224, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1222, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1223, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1223, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1224, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1222, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1223, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1223, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1224, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1222, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1223, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1223, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1224, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1225, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1226, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1226, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1227, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1225, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1226, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1226, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1227, PALETTE_TO_PINK, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1225, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1226, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1226, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1227, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1225, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1226, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1226, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1227, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1228, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1228, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1228, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1228, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1229, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x122f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1230, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1230, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1230, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x122e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1230, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1231, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1233, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1231, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1233, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1231, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1233, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1231, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1232, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1233, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1234, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1236, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1234, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1236, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1234, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1236, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1234, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1235, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1236, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1237, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1239, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1237, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1239, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1237, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1239, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1237, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1238, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1239, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123b, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x123c, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123d, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123e, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x123f, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1240, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1242, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1240, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1242, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1240, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1242, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1240, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1241, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1242, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1256, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1256, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1256, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1256, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1256, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1256, PALETTE_TO_PALE_GREEN, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1256, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1256, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1256, PALETTE_TO_RED, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1256, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1256, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x1256, PALETTE_TO_CREAM, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1257, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1259, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1257, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1259, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1257, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1259, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1257, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1258, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY1, PAL_NONE, 0x1259, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x0, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), M(SPR_GRND_HOUSE_TOY2, PAL_NONE, 0x125a, PAL_NONE, 0, 0, 16, 16, 50, 0), }; #undef M /** Make sure we have the right number of elements: 4 variants * 4 build stages for each house */ assert_compile(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4); /** * Describes the data that defines each house in the game * @param mnd introduction year of the house * @param mxd last year it can be built * @param p population * @param rc cost multiplier for removing it * @param bn building name * @param rr rating decrease if removed * @param mg mail generation multiplier * @param ca1 acceptance for 1st CargoID * @param ca2 acceptance for 2nd CargoID * @param ca3 acceptance for 3rd CargoID * @param bf building flags (size, stadium etc...) * @param ba building availability (zone, climate...) * @param cg1 1st CargoID available * @param cg2 2nd CargoID available * @param cg3 3rd CargoID available * @see HouseSpec */ #define MS(mnd, mxd, p, rc, bn, rr, mg, ca1, ca2, ca3, bf, ba, cg1, cg2, cg3) \ {mnd, mxd, p, rc, bn, rr, mg, {ca1, ca2, ca3}, {cg1, cg2, cg3}, bf, ba, true, \ GRFFileProps(INVALID_HOUSE_ID), 0, {0, 0, 0, 0}, 16, NO_EXTRA_FLAG, HOUSE_NO_CLASS, {0, 2, 0, 0}, 0, 0, 0} /** House specifications from original data */ static const HouseSpec _original_house_specs[] = { /** * remove_rating_decrease * | mail_generation * min_year | | 1st CargoID acceptance * | max_year | | | 2nd CargoID acceptance * | | population | | | | 3th CargoID acceptance * | | | removal_cost | | | | | * | | | | building_name | | | | | * | | | | | | | | | | * | | | | | | | | | | * +-building_flags | | | | | | | | * +-building_availability | | | | | | | * +-cargoID accepted | | | | | | | | * | | | | | | | | | | | */ MS(1963, MAX_YEAR, 187, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 70, 8, 3, 4, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 00 MS(1957, MAX_YEAR, 85, 140, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1, 130, 55, 8, 3, 4, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 01 MS(1968, MAX_YEAR, 40, 100, STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1, 90, 20, 8, 3, 1, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 02 MS( 0, MAX_YEAR, 5, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0, BUILDING_IS_CHURCH | TILE_SIZE_1x1, HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 03 MS(1975, MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1, 160, 85, 10, 4, 6, BUILDING_IS_ANIMATED | TILE_SIZE_1x1, HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 04 MS(1975, MAX_YEAR, 220, 160, STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1, 160, 85, 10, 4, 6, BUILDING_IS_ANIMATED | TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON5, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 05 MS( 0, MAX_YEAR, 30, 80, STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1, 80, 12, 4, 1, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 06 MS(1959, MAX_YEAR, 140, 180, STR_TOWN_BUILDING_NAME_HOTEL_1, 150, 22, 6, 1, 2, TILE_SIZE_1x2, HZ_TEMP | HZ_ZON5 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 07 MS(1959, MAX_YEAR, 0, 180, STR_TOWN_BUILDING_NAME_HOTEL_1, 150, 22, 6, 1, 2, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 08 MS(1945, MAX_YEAR, 0, 65, STR_TOWN_BUILDING_NAME_STATUE_1, 40, 0, 2, 0, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 09 MS(1945, MAX_YEAR, 0, 65, STR_TOWN_BUILDING_NAME_FOUNTAIN_1, 40, 0, 2, 0, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0A MS( 0, MAX_YEAR, 0, 60, STR_TOWN_BUILDING_NAME_PARK_1, 75, 0, 2, 0, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0B MS(1935, MAX_YEAR, 0, 60, STR_TOWN_BUILDING_NAME_PARK_1, 75, 0, 2, 0, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0C MS(1951, MAX_YEAR, 150, 130, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2, 110, 65, 8, 2, 4, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0D MS(1930, 1960, 95, 110, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0E MS(1930, 1960, 95, 105, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 0F MS(1930, 1960, 95, 107, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 100, 48, 6, 2, 3, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 10 MS(1977, MAX_YEAR, 130, 200, STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1, 150, 50, 10, 3, 6, TILE_SIZE_1x1, HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 11 MS(1983, MAX_YEAR, 6, 145, STR_TOWN_BUILDING_NAME_WAREHOUSE_1, 110, 10, 6, 3, 8, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 12 MS(1985, MAX_YEAR, 110, 155, STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3, 110, 55, 6, 2, 6, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 13 MS( 0, MAX_YEAR, 65, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, BUILDING_IS_STADIUM | TILE_SIZE_2x2, HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 14 MS( 0, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 15 MS( 0, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 16 MS( 0, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_1, 300, 5, 4, 0, 0, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 17 MS( 0, 1951, 15, 70, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1, 75, 6, 3, 1, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 18 MS( 0, 1952, 12, 75, STR_TOWN_BUILDING_NAME_COTTAGES_1, 75, 7, 3, 1, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 19 MS(1931, MAX_YEAR, 13, 71, STR_TOWN_BUILDING_NAME_HOUSES_1, 75, 8, 3, 1, 0, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1A MS(1935, MAX_YEAR, 100, 135, STR_TOWN_BUILDING_NAME_FLATS_1, 100, 35, 7, 2, 2, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1B MS(1963, MAX_YEAR, 170, 145, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2, 170, 50, 8, 3, 3, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1C MS( 0, 1955, 100, 132, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2, 135, 40, 6, 2, 3, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1D MS(1973, MAX_YEAR, 180, 155, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3, 180, 64, 8, 3, 3, TILE_SIZE_1x1, HZ_TEMP | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1E MS( 0, MAX_YEAR, 35, 220, STR_TOWN_BUILDING_NAME_THEATER_1, 230, 23, 8, 2, 2, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 1F MS(1958, MAX_YEAR, 65, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, BUILDING_IS_STADIUM | TILE_SIZE_2x2, HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 20 MS(1958, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 21 MS(1958, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 22 MS(1958, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_STADIUM_2, 300, 5, 4, 0, 0, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 23 MS(2000, MAX_YEAR, 140, 170, STR_TOWN_BUILDING_NAME_OFFICES_1, 250, 65, 8, 3, 2, TILE_SIZE_1x1, HZ_TEMP | HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 24 MS( 0, 1960, 15, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 25 MS( 0, 1960, 15, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 26 MS(1945, MAX_YEAR, 35, 210, STR_TOWN_BUILDING_NAME_CINEMA_1, 230, 23, 8, 2, 2, TILE_SIZE_1x1, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 27 MS(1983, MAX_YEAR, 180, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, TILE_SIZE_2x2, HZ_TEMP | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 |HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 28 MS(1983, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 29 MS(1983, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2A MS(1983, MAX_YEAR, 0, 250, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1, 300, 5, 8, 2, 3, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 2B MS( 0, MAX_YEAR, 80, 100, STR_TOWN_BUILDING_NAME_FLATS_1, 90, 20, 5, 2, 2, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2C MS( 0, MAX_YEAR, 80, 100, STR_TOWN_BUILDING_NAME_FLATS_1, 90, 20, 5, 2, 2, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2D MS( 0, MAX_YEAR, 16, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2E MS( 0, MAX_YEAR, 16, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 2F MS( 0, 1963, 14, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 30 MS( 0, 1963, 14, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 70, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 31 MS(1966, MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 120, 60, 8, 3, 4, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 32 MS(1966, MAX_YEAR, 135, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 120, 60, 8, 3, 4, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 33 MS(1970, MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 70, 9, 3, 4, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 34 MS(1970, MAX_YEAR, 170, 170, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 70, 9, 3, 4, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 35 MS(1974, MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 10, 3, 5, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 36 MS(1974, MAX_YEAR, 210, 200, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 10, 3, 5, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 37 MS( 0, MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_HOUSES_2, 60, 5, 2, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 38 MS( 0, MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_HOUSES_2, 60, 5, 2, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 39 MS( 0, MAX_YEAR, 25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 80, 20, 3, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3A MS( 0, MAX_YEAR, 25, 100, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 80, 20, 3, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3B MS( 0, MAX_YEAR, 6, 85, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0, BUILDING_IS_CHURCH | TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3C MS( 0, MAX_YEAR, 6, 85, STR_TOWN_BUILDING_NAME_CHURCH_1, 230, 2, 2, 0, 0, BUILDING_IS_CHURCH | TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 3D MS( 0, MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3E MS( 0, MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 1, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 3F MS( 0, 1960, 90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 110, 45, 6, 2, 3, TILE_SIZE_1x1, HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 40 MS( 0, 1960, 90, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 110, 45, 6, 2, 3, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 41 MS(1972, MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 3, TILE_SIZE_1x2, HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 42 MS(1972, MAX_YEAR, 0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 2, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 43 MS(1972, MAX_YEAR, 140, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 3, TILE_SIZE_1x2, HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 44 MS(1972, MAX_YEAR, 0, 160, STR_TOWN_BUILDING_NAME_HOTEL_1, 160, 25, 6, 1, 2, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 45 MS(1963, MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 105, 50, 7, 2, 3, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 46 MS(1963, MAX_YEAR, 105, 130, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 105, 50, 7, 2, 3, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 47 MS(1978, MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 135, 75, 9, 3, 4, TILE_SIZE_1x1, HZ_SUBARTC_BELOW | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 48 MS(1978, MAX_YEAR, 190, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 135, 75, 9, 3, 4, TILE_SIZE_1x1, HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 49 MS(1967, MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, TILE_SIZE_2x1, HZ_SUBARTC_BELOW| HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4A MS(1967, MAX_YEAR, 0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4B MS(1967, MAX_YEAR, 250, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, TILE_SIZE_2x1, HZ_SUBARTC_ABOVE | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4C MS(1967, MAX_YEAR, 0, 140, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 200, 60, 7, 2, 2, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 4D MS( 0, MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4E MS( 0, MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 4F MS( 0, MAX_YEAR, 16, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 5, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 50 MS( 0, MAX_YEAR, 7, 30, STR_TOWN_BUILDING_NAME_HOUSES_2, 30, 4, 3, 1, 1, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 51 MS( 0, MAX_YEAR, 45, 130, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 15, 6, 2, 1, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 52 MS( 0, MAX_YEAR, 8, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 200, 3, 2, 0, 0, BUILDING_IS_CHURCH | TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 53 MS( 0, MAX_YEAR, 18, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 7, 3, 1, 2, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2, CT_PASSENGERS, CT_MAIL, CT_FOOD), // 54 MS(1973, MAX_YEAR, 90, 110, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 24, 6, 2, 1, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 55 MS(1962, MAX_YEAR, 120, 120, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 25, 6, 2, 1, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 56 MS(1984, MAX_YEAR, 250, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 8, 3, 4, TILE_SIZE_2x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 57 MS(1984, MAX_YEAR, 0, 190, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 140, 80, 8, 3, 4, TILE_NO_FLAG, HZ_SUBTROPIC, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 58 MS( 0, MAX_YEAR, 80, 110, STR_TOWN_BUILDING_NAME_FLATS_1, 95, 23, 6, 2, 1, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 59 MS(1993, MAX_YEAR, 180, 180, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 150, 90, 8, 3, 4, TILE_SIZE_1x1, HZ_SUBTROPIC | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_GOODS), // 5A MS( 0, MAX_YEAR, 8, 90, STR_TOWN_BUILDING_NAME_CHURCH_1, 200, 3, 2, 0, 0, BUILDING_IS_CHURCH | TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5B MS( 0, MAX_YEAR, 18, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 90, 5, 6, 2, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5C MS( 0, MAX_YEAR, 7, 70, STR_TOWN_BUILDING_NAME_HOUSES_2, 50, 3, 3, 1, 1, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5D MS( 0, MAX_YEAR, 15, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5E MS( 0, MAX_YEAR, 17, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 5F MS( 0, MAX_YEAR, 19, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 60 MS( 0, MAX_YEAR, 21, 80, STR_TOWN_BUILDING_NAME_HOUSES_2, 75, 6, 3, 1, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 61 MS( 0, MAX_YEAR, 75, 160, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 20, 8, 4, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 62 MS( 0, MAX_YEAR, 35, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 9, 4, 1, 2, TILE_SIZE_1x2, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 63 MS( 0, MAX_YEAR, 0, 90, STR_TOWN_BUILDING_NAME_HOUSES_2, 80, 0, 4, 1, 2, TILE_NO_FLAG, HZ_NOZNS, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 64 MS( 0, MAX_YEAR, 85, 150, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 18, 8, 4, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 65 MS( 0, MAX_YEAR, 11, 60, STR_TOWN_BUILDING_NAME_IGLOO_1, 45, 3, 3, 1, 1, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 66 MS( 0, MAX_YEAR, 10, 60, STR_TOWN_BUILDING_NAME_TEPEES_1, 45, 3, 3, 1, 1, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 67 MS( 0, MAX_YEAR, 67, 140, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 130, 22, 8, 4, 4, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 68 MS( 0, MAX_YEAR, 86, 145, STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1, 130, 23, 8, 4, 4, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 69 MS( 0, MAX_YEAR, 95, 165, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, 130, 28, 8, 4, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6A MS( 0, MAX_YEAR, 30, 90, STR_TOWN_BUILDING_NAME_STATUE_1, 70, 10, 4, 1, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6B MS( 0, MAX_YEAR, 25, 75, STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1, 65, 8, 3, 1, 2, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_CANDY), // 6C MS( 0, MAX_YEAR, 18, 85, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1, 95, 7, 3, 2, 4, TILE_SIZE_1x1, HZ_TOYLND | HZ_ZON5 | HZ_ZON4 | HZ_ZON3 | HZ_ZON2 | HZ_ZON1, CT_PASSENGERS, CT_MAIL, CT_FIZZY_DRINKS), // 6D }; #undef MS /** Make sure we have the right number of elements: one entry for each house */ assert_compile(lengthof(_original_house_specs) == NEW_HOUSE_OFFSET); openttd-1.5.3/src/table/airport_defaults.h0000644000000000000000000003266512627373436017322 0ustar rootroot/* $Id: airport_defaults.h 23415 2011-12-03 23:40:46Z michi_cc $ */ /* * 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 airport_defaults.h Tables with default values for airports and airport tiles. */ #ifndef AIRPORT_DEFAULTS_H #define AIRPORT_DEFAULTS_H /** * Definition of an airport tiles layout. * @param x offset x of this tile * @param y offset y of this tile * @param m StationGfx of the tile * @see _airport_specs * @see AirportTileTable */ #define MK(x, y, m) {{x, y}, m} /** * Terminator of airport tiles layout definition */ #define MKEND {{-0x80, 0}, 0} /** Tiles for Country Airfield (small) */ static AirportTileTable _tile_table_country_0[] = { MK(0, 0, APT_SMALL_BUILDING_1), MK(1, 0, APT_SMALL_BUILDING_2), MK(2, 0, APT_SMALL_BUILDING_3), MK(3, 0, APT_SMALL_DEPOT_SE), MK(0, 1, APT_GRASS_FENCE_NE_FLAG), MK(1, 1, APT_GRASS_1), MK(2, 1, APT_GRASS_2), MK(3, 1, APT_GRASS_FENCE_SW), MK(0, 2, APT_RUNWAY_SMALL_FAR_END), MK(1, 2, APT_RUNWAY_SMALL_MIDDLE), MK(2, 2, APT_RUNWAY_SMALL_MIDDLE), MK(3, 2, APT_RUNWAY_SMALL_NEAR_END), MKEND }; static AirportTileTable *_tile_table_country[] = { _tile_table_country_0, }; /** Tiles for Commuter Airfield (small) */ static AirportTileTable _tile_table_commuter_0[] = { MK(0, 0, APT_TOWER), MK(1, 0, APT_BUILDING_3), MK(2, 0, APT_HELIPAD_2_FENCE_NW), MK(3, 0, APT_HELIPAD_2_FENCE_NW), MK(4, 0, APT_DEPOT_SE), MK(0, 1, APT_APRON_FENCE_NE), MK(1, 1, APT_APRON), MK(2, 1, APT_APRON), MK(3, 1, APT_APRON), MK(4, 1, APT_APRON_FENCE_SW), MK(0, 2, APT_APRON_FENCE_NE), MK(1, 2, APT_STAND), MK(2, 2, APT_STAND), MK(3, 2, APT_STAND), MK(4, 2, APT_APRON_FENCE_SW), MK(0, 3, APT_RUNWAY_END_FENCE_SE), MK(1, 3, APT_RUNWAY_2), MK(2, 3, APT_RUNWAY_2), MK(3, 3, APT_RUNWAY_2), MK(4, 3, APT_RUNWAY_END_FENCE_SE), MKEND }; static AirportTileTable *_tile_table_commuter[] = { _tile_table_commuter_0, }; /** Tiles for City Airport (large) */ static AirportTileTable _tile_table_city_0[] = { MK(0, 0, APT_BUILDING_1), MK(1, 0, APT_APRON_FENCE_NW), MK(2, 0, APT_STAND_1), MK(3, 0, APT_APRON_FENCE_NW), MK(4, 0, APT_APRON_FENCE_NW), MK(5, 0, APT_DEPOT_SE), MK(0, 1, APT_BUILDING_2), MK(1, 1, APT_PIER), MK(2, 1, APT_ROUND_TERMINAL), MK(3, 1, APT_STAND_PIER_NE), MK(4, 1, APT_APRON), MK(5, 1, APT_APRON_FENCE_SW), MK(0, 2, APT_BUILDING_3), MK(1, 2, APT_STAND), MK(2, 2, APT_PIER_NW_NE), MK(3, 2, APT_APRON_S), MK(4, 2, APT_APRON_HOR), MK(5, 2, APT_APRON_N_FENCE_SW), MK(0, 3, APT_RADIO_TOWER_FENCE_NE), MK(1, 3, APT_APRON_W), MK(2, 3, APT_APRON_VER_CROSSING_S), MK(3, 3, APT_APRON_HOR_CROSSING_E), MK(4, 3, APT_ARPON_N), MK(5, 3, APT_TOWER_FENCE_SW), MK(0, 4, APT_EMPTY_FENCE_NE), MK(1, 4, APT_APRON_S), MK(2, 4, APT_APRON_HOR_CROSSING_W), MK(3, 4, APT_APRON_VER_CROSSING_N), MK(4, 4, APT_APRON_E), MK(5, 4, APT_RADAR_GRASS_FENCE_SW), MK(0, 5, APT_RUNWAY_END_FENCE_SE), MK(1, 5, APT_RUNWAY_1), MK(2, 5, APT_RUNWAY_2), MK(3, 5, APT_RUNWAY_3), MK(4, 5, APT_RUNWAY_4), MK(5, 5, APT_RUNWAY_END_FENCE_SE), MKEND }; static AirportTileTable *_tile_table_city[] = { _tile_table_city_0, }; /** Tiles for Metropolitain Airport (large) - 2 runways */ static AirportTileTable _tile_table_metropolitan_0[] = { MK(0, 0, APT_BUILDING_1), MK(1, 0, APT_APRON_FENCE_NW), MK(2, 0, APT_STAND_1), MK(3, 0, APT_APRON_FENCE_NW), MK(4, 0, APT_APRON_FENCE_NW), MK(5, 0, APT_DEPOT_SE), MK(0, 1, APT_BUILDING_2), MK(1, 1, APT_PIER), MK(2, 1, APT_ROUND_TERMINAL), MK(3, 1, APT_STAND_PIER_NE), MK(4, 1, APT_APRON), MK(5, 1, APT_APRON_FENCE_SW), MK(0, 2, APT_BUILDING_3), MK(1, 2, APT_STAND), MK(2, 2, APT_PIER_NW_NE), MK(3, 2, APT_APRON_S), MK(4, 2, APT_APRON_HOR), MK(5, 2, APT_APRON_N_FENCE_SW), MK(0, 3, APT_RADAR_FENCE_NE), MK(1, 3, APT_APRON), MK(2, 3, APT_APRON), MK(3, 3, APT_APRON), MK(4, 3, APT_APRON), MK(5, 3, APT_TOWER_FENCE_SW), MK(0, 4, APT_RUNWAY_END), MK(1, 4, APT_RUNWAY_5), MK(2, 4, APT_RUNWAY_5), MK(3, 4, APT_RUNWAY_5), MK(4, 4, APT_RUNWAY_5), MK(5, 4, APT_RUNWAY_END), MK(0, 5, APT_RUNWAY_END_FENCE_SE), MK(1, 5, APT_RUNWAY_2), MK(2, 5, APT_RUNWAY_2), MK(3, 5, APT_RUNWAY_2), MK(4, 5, APT_RUNWAY_2), MK(5, 5, APT_RUNWAY_END_FENCE_SE), MKEND }; static AirportTileTable *_tile_table_metropolitan[] = { _tile_table_metropolitan_0, }; /** Tiles for International Airport (large) - 2 runways */ static AirportTileTable _tile_table_international_0[] = { MK(0, 0, APT_RUNWAY_END_FENCE_NW), MK(1, 0, APT_RUNWAY_FENCE_NW), MK(2, 0, APT_RUNWAY_FENCE_NW), MK(3, 0, APT_RUNWAY_FENCE_NW), MK(4, 0, APT_RUNWAY_FENCE_NW), MK(5, 0, APT_RUNWAY_FENCE_NW), MK(6, 0, APT_RUNWAY_END_FENCE_NW), MK(0, 1, APT_RADIO_TOWER_FENCE_NE), MK(1, 1, APT_APRON), MK(2, 1, APT_APRON), MK(3, 1, APT_APRON), MK(4, 1, APT_APRON), MK(5, 1, APT_APRON), MK(6, 1, APT_DEPOT_SE), MK(0, 2, APT_BUILDING_3), MK(1, 2, APT_APRON), MK(2, 2, APT_STAND), MK(3, 2, APT_BUILDING_2), MK(4, 2, APT_STAND), MK(5, 2, APT_APRON), MK(6, 2, APT_APRON_FENCE_SW), MK(0, 3, APT_DEPOT_SE), MK(1, 3, APT_APRON), MK(2, 3, APT_STAND), MK(3, 3, APT_BUILDING_2), MK(4, 3, APT_STAND), MK(5, 3, APT_APRON), MK(6, 3, APT_HELIPAD_1), MK(0, 4, APT_APRON_FENCE_NE), MK(1, 4, APT_APRON), MK(2, 4, APT_STAND), MK(3, 4, APT_TOWER), MK(4, 4, APT_STAND), MK(5, 4, APT_APRON), MK(6, 4, APT_HELIPAD_1), MK(0, 5, APT_APRON_FENCE_NE), MK(1, 5, APT_APRON), MK(2, 5, APT_APRON), MK(3, 5, APT_APRON), MK(4, 5, APT_APRON), MK(5, 5, APT_APRON), MK(6, 5, APT_RADAR_FENCE_SW), MK(0, 6, APT_RUNWAY_END_FENCE_SE), MK(1, 6, APT_RUNWAY_2), MK(2, 6, APT_RUNWAY_2), MK(3, 6, APT_RUNWAY_2), MK(4, 6, APT_RUNWAY_2), MK(5, 6, APT_RUNWAY_2), MK(6, 6, APT_RUNWAY_END_FENCE_SE), MKEND }; static AirportTileTable *_tile_table_international[] = { _tile_table_international_0, }; /** Tiles for International Airport (large) - 2 runways */ static AirportTileTable _tile_table_intercontinental_0[] = { MK(0, 0, APT_RADAR_FENCE_NE), MK(1, 0, APT_RUNWAY_END_FENCE_NE_NW), MK(2, 0, APT_RUNWAY_FENCE_NW), MK(3, 0, APT_RUNWAY_FENCE_NW), MK(4, 0, APT_RUNWAY_FENCE_NW), MK(5, 0, APT_RUNWAY_FENCE_NW), MK(6, 0, APT_RUNWAY_FENCE_NW), MK(7, 0, APT_RUNWAY_FENCE_NW), MK(8, 0, APT_RUNWAY_END_FENCE_NW_SW), MK(0, 1, APT_RUNWAY_END_FENCE_NE_NW), MK(1, 1, APT_RUNWAY_2), MK(2, 1, APT_RUNWAY_2), MK(3, 1, APT_RUNWAY_2), MK(4, 1, APT_RUNWAY_2), MK(5, 1, APT_RUNWAY_2), MK(6, 1, APT_RUNWAY_2), MK(7, 1, APT_RUNWAY_END_FENCE_SE_SW), MK(8, 1, APT_APRON_FENCE_NE_SW), MK(0, 2, APT_APRON_FENCE_NE_SW), MK(1, 2, APT_EMPTY), MK(2, 2, APT_APRON_FENCE_NE), MK(3, 2, APT_APRON), MK(4, 2, APT_APRON), MK(5, 2, APT_APRON), MK(6, 2, APT_APRON), MK(7, 2, APT_RADIO_TOWER_FENCE_NE), MK(8, 2, APT_APRON_FENCE_NE_SW), MK(0, 3, APT_APRON_FENCE_NE), MK(1, 3, APT_APRON_HALF_EAST), MK(2, 3, APT_APRON_FENCE_NE), MK(3, 3, APT_TOWER), MK(4, 3, APT_HELIPAD_2), MK(5, 3, APT_HELIPAD_2), MK(6, 3, APT_APRON), MK(7, 3, APT_APRON_FENCE_NW), MK(8, 3, APT_APRON_FENCE_SW), MK(0, 4, APT_APRON_FENCE_NE), MK(1, 4, APT_APRON), MK(2, 4, APT_APRON), MK(3, 4, APT_STAND), MK(4, 4, APT_BUILDING_1), MK(5, 4, APT_STAND), MK(6, 4, APT_APRON), MK(7, 4, APT_LOW_BUILDING), MK(8, 4, APT_DEPOT_SE), MK(0, 5, APT_DEPOT_SE), MK(1, 5, APT_LOW_BUILDING), MK(2, 5, APT_APRON), MK(3, 5, APT_STAND), MK(4, 5, APT_BUILDING_2), MK(5, 5, APT_STAND), MK(6, 5, APT_APRON), MK(7, 5, APT_APRON), MK(8, 5, APT_APRON_FENCE_SW), MK(0, 6, APT_APRON_FENCE_NE), MK(1, 6, APT_APRON), MK(2, 6, APT_APRON), MK(3, 6, APT_STAND), MK(4, 6, APT_BUILDING_3), MK(5, 6, APT_STAND), MK(6, 6, APT_APRON), MK(7, 6, APT_APRON), MK(8, 6, APT_APRON_FENCE_SW), MK(0, 7, APT_APRON_FENCE_NE), MK(1, 7, APT_APRON_FENCE_SE), MK(2, 7, APT_APRON), MK(3, 7, APT_STAND), MK(4, 7, APT_ROUND_TERMINAL), MK(5, 7, APT_STAND), MK(6, 7, APT_APRON_FENCE_SW), MK(7, 7, APT_APRON_HALF_WEST), MK(8, 7, APT_APRON_FENCE_SW), MK(0, 8, APT_APRON_FENCE_NE), MK(1, 8, APT_GRASS_FENCE_NE_FLAG_2), MK(2, 8, APT_APRON_FENCE_NE), MK(3, 8, APT_APRON), MK(4, 8, APT_APRON), MK(5, 8, APT_APRON), MK(6, 8, APT_APRON_FENCE_SW), MK(7, 8, APT_EMPTY), MK(8, 8, APT_APRON_FENCE_NE_SW), MK(0, 9, APT_APRON_FENCE_NE), MK(1, 9, APT_RUNWAY_END_FENCE_NE_NW), MK(2, 9, APT_RUNWAY_FENCE_NW), MK(3, 9, APT_RUNWAY_FENCE_NW), MK(4, 9, APT_RUNWAY_FENCE_NW), MK(5, 9, APT_RUNWAY_FENCE_NW), MK(6, 9, APT_RUNWAY_FENCE_NW), MK(7, 9, APT_RUNWAY_FENCE_NW), MK(8, 9, APT_RUNWAY_END_FENCE_SE_SW), MK(0, 10, APT_RUNWAY_END_FENCE_NE_SE), MK(1, 10, APT_RUNWAY_2), MK(2, 10, APT_RUNWAY_2), MK(3, 10, APT_RUNWAY_2), MK(4, 10, APT_RUNWAY_2), MK(5, 10, APT_RUNWAY_2), MK(6, 10, APT_RUNWAY_2), MK(7, 10, APT_RUNWAY_END_FENCE_SE_SW), MK(8, 10, APT_EMPTY), MKEND }; static AirportTileTable *_tile_table_intercontinental[] = { _tile_table_intercontinental_0, }; /** Tiles for Heliport */ static AirportTileTable _tile_table_heliport_0[] = { MK(0, 0, APT_HELIPORT), MKEND }; static AirportTileTable *_tile_table_heliport[] = { _tile_table_heliport_0, }; /** Tiles for Helidepot */ static AirportTileTable _tile_table_helidepot_0[] = { MK(0, 0, APT_LOW_BUILDING_FENCE_N), MK(1, 0, APT_DEPOT_SE), MK(0, 1, APT_HELIPAD_2_FENCE_NE_SE), MK(1, 1, APT_APRON_FENCE_SE_SW), MKEND }; static AirportTileTable *_tile_table_helidepot[] = { _tile_table_helidepot_0, }; /** Tiles for Helistation */ static AirportTileTable _tile_table_helistation_0[] = { MK(0, 0, APT_DEPOT_SE), MK(1, 0, APT_LOW_BUILDING_FENCE_NW), MK(2, 0, APT_HELIPAD_3_FENCE_NW), MK(3, 0, APT_HELIPAD_3_FENCE_NW_SW), MK(0, 1, APT_APRON_FENCE_NE_SE), MK(1, 1, APT_APRON_FENCE_SE), MK(2, 1, APT_APRON_FENCE_SE), MK(3, 1, APT_HELIPAD_3_FENCE_SE_SW), MKEND }; static AirportTileTable *_tile_table_helistation[] = { _tile_table_helistation_0, }; static Direction _default_airports_rotation[] = { DIR_N, }; #undef MK #undef MKEND /** General AirportSpec definition. */ #define AS_GENERIC(fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, enabled) \ {fsm, att, rot, att_len, depot_tbl, num_depots, size_x, size_y, noise, catchment, min_year, max_year, name, ttdpatch_type, class_id, preview, maint_cost, enabled, GRFFileProps(AT_INVALID)} /** AirportSpec definition for airports without any depot. */ #define AS_ND(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \ AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), NULL, 0, \ size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, true) /** AirportSpec definition for airports with at least one depot. */ #define AS(ap_name, size_x, size_y, min_year, max_year, catchment, noise, maint_cost, ttdpatch_type, class_id, name, preview) \ AS_GENERIC(&_airportfta_##ap_name, _tile_table_##ap_name, _default_airports_rotation, lengthof(_tile_table_##ap_name), _airport_depots_##ap_name, lengthof(_airport_depots_##ap_name), \ size_x, size_y, noise, catchment, min_year, max_year, maint_cost, ttdpatch_type, class_id, name, preview, true) /* The helidepot and helistation have ATP_TTDP_SMALL because they are at ground level */ extern const AirportSpec _origin_airport_specs[] = { AS(country, 4, 3, 0, 1959, 4, 3, 7, ATP_TTDP_SMALL, APC_SMALL, STR_AIRPORT_SMALL, SPR_AIRPORT_PREVIEW_SMALL), AS(city, 6, 6, 1955, MAX_YEAR, 5, 5, 24, ATP_TTDP_LARGE, APC_LARGE, STR_AIRPORT_CITY, SPR_AIRPORT_PREVIEW_LARGE), AS_ND(heliport, 1, 1, 1963, MAX_YEAR, 4, 1, 4, ATP_TTDP_HELIPORT, APC_HELIPORT, STR_AIRPORT_HELIPORT, SPR_AIRPORT_PREVIEW_HELIPORT), AS(metropolitan, 6, 6, 1980, MAX_YEAR, 6, 8, 28, ATP_TTDP_LARGE, APC_LARGE, STR_AIRPORT_METRO, SPR_AIRPORT_PREVIEW_METROPOLITAN), AS(international, 7, 7, 1990, MAX_YEAR, 8, 17, 42, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERNATIONAL, SPR_AIRPORT_PREVIEW_INTERNATIONAL), AS(commuter, 5, 4, 1983, MAX_YEAR, 4, 4, 20, ATP_TTDP_SMALL, APC_SMALL, STR_AIRPORT_COMMUTER, SPR_AIRPORT_PREVIEW_COMMUTER), AS(helidepot, 2, 2, 1976, MAX_YEAR, 4, 2, 7, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELIDEPOT, SPR_AIRPORT_PREVIEW_HELIDEPOT), AS(intercontinental, 9, 11, 2002, MAX_YEAR, 10, 25, 72, ATP_TTDP_LARGE, APC_HUB, STR_AIRPORT_INTERCONTINENTAL, SPR_AIRPORT_PREVIEW_INTERCONTINENTAL), AS(helistation, 4, 2, 1980, MAX_YEAR, 4, 3, 14, ATP_TTDP_SMALL, APC_HELIPORT, STR_AIRPORT_HELISTATION, SPR_AIRPORT_PREVIEW_HELISTATION), AS_GENERIC(&_airportfta_oilrig, NULL, _default_airports_rotation, 0, NULL, 0, 1, 1, 0, 4, 0, 0, 0, ATP_TTDP_OILRIG, APC_HELIPORT, STR_NULL, 0, false), }; assert_compile(NEW_AIRPORT_OFFSET == lengthof(_origin_airport_specs)); AirportSpec AirportSpec::dummy = AS_GENERIC(&_airportfta_dummy, NULL, _default_airports_rotation, 0, NULL, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR, 0, ATP_TTDP_LARGE, APC_BEGIN, STR_NULL, 0, false); #undef AS #undef AS_ND #undef AS_GENERIC #endif /* AIRPORT_DEFAULTS_H */ openttd-1.5.3/src/table/train_cmd.h0000644000000000000000000000506212627373436015702 0ustar rootroot/* $Id: train_cmd.h 26130 2013-11-26 16:08:58Z rubidium $ */ /* * 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 train_cmd.h Sprites to use for trains. */ static const SpriteID _engine_sprite_base[] = { 0x0B59, 0x0B61, 0x0B69, 0x0BE1, 0x0B71, 0x0B75, 0x0B7D, 0x0B7D, 0x0B85, 0x0B85, 0x0B8D, 0x0B8D, 0x0BC9, 0x0BD1, 0x0BD9, 0x0BE9, 0x0BED, 0x0BED, 0x0BF5, 0x0BF9, 0x0B79, 0x0B9D, 0x0B9D, 0x0B95, 0x0B95, 0x0BA5, 0x0BA9, 0x0BA9, 0x0BC1, 0x0BC5, 0x0BB1, 0x0BB9, 0x0BB9, 0x0AAD, 0x0AB1, 0x0AB5, 0x0AB9, 0x0ABD, 0x0AC1, 0x0AC9, 0x0ACD, 0x0AD5, 0x0AD1, 0x0AD9, 0x0AC5, 0x0AD1, 0x0AD5, 0x0AF9, 0x0AFD, 0x0B05, 0x0AB9, 0x0AC1, 0x0AC9, 0x0AD1, 0x0AD9, 0x0AE1, 0x0AE5, 0x0AE9, 0x0AF1, 0x0AF9, 0x0B0D, 0x0B11, 0x0B15, 0x0B19, 0x0B1D, 0x0B21, 0x0B29, 0x0B2D, 0x0B35, 0x0B31, 0x0B39, 0x0B25, 0x0B31, 0x0B35, }; /* For how many directions do we have sprites? (8 or 4; if 4, the other 4 * directions are symmetric. */ static const byte _engine_sprite_and[] = { 7, 7, 7, 7, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 7, 7, 3, 7, 3, 7, 7, 7, 7, 3, 7, 7, 3, 3, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, }; /* Non-zero for multihead trains. */ static const byte _engine_sprite_add[] = { 0, 0, 0, 0, 0, 0, 0, 4, 0, 4, 0, 4, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4, 0, 4, 0, 0, 4, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; static const byte _wagon_full_adder[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, 0, 0, 24, 24, 24, 24, 0, 0, 32, 32, 0, 4, 4, 4, 4, 4, 4, 4, 0, 0, 4, 4, 4, 0, 44, 0, 0, 0, 0, 24, 24, 24, 24, 0, 0, 32, 32 }; assert_compile(lengthof(_engine_sprite_base) == lengthof(_engine_sprite_and)); assert_compile(lengthof(_engine_sprite_base) == lengthof(_engine_sprite_add)); assert_compile(lengthof(_engine_sprite_base) == lengthof(_wagon_full_adder)); openttd-1.5.3/src/table/engines.h0000644000000000000000000014522312627373436015376 0ustar rootroot/* $Id: engines.h 25115 2013-03-22 21:27:13Z frosch $ */ /* * 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 table/engines.h * This file contains all the data for vehicles */ #ifndef ENGINES_H #define ENGINES_H /** * Writes the properties of a train into the EngineInfo struct. * @see EngineInfo * @param a base introduction date (days since 1920-01-01) * @param b decay speed * @param c life length (years) * @param d base life (years) * @param e cargo type * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ #define MT(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_FLIPS, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /** * Writes the properties of a train carriage into the EngineInfo struct. * @param a base introduction date (days since 1920-01-01) * @param b decay speed * @param c life length (years) * @param d base life (years) * @param e cargo type * @param f Bitmask of the climates * @see MT * @note the 5 between b and f is the load amount */ #define MW(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 1 << EF_RAIL_FLIPS, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /** * Writes the properties of a road vehicle into the EngineInfo struct. * @see EngineInfo * @param a base introduction date (days since 1920-01-01) * @param b decay speed * @param c life length (years) * @param d base life (years) * @param e cargo type * @param f Bitmask of the climates * @note the 5 between b and f is the load amount */ #define MR(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 5, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /** * Writes the properties of a ship into the EngineInfo struct. * @param a base introduction date (days since 1920-01-01) * @param b decay speed * @param c life length (years) * @param d base life (years) * @param e cargo type * @param f Bitmask of the climates * @note the 10 between b and f is the load amount */ #define MS(a, b, c, d, e, f) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 10, f, e, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /** * Writes the properties of an aeroplane into the EngineInfo struct. * @param a base introduction date (days since 1920-01-01) * @param b decay speed * @param c life length (years) * @param d base life (years) * @param e Bitmask of the climates * @note the 20 between b and e is the load amount */ #define MA(a, b, c, d, e) { DAYS_TILL_ORIGINAL_BASE_YEAR + a, c, d, b, 20, e, CT_INVALID, 0, 8, 0, 0, 0, STR_EMPTY, CARGO_AGING_TICKS } /* Climates * T = Temperate * A = Sub-Arctic * S = Sub-Tropic * Y = Toyland */ #define T 1 #define A 2 #define S 4 #define Y 8 static const EngineInfo _orig_engine_info[] = { /* base_intro base_life * | decay_speed cargo_type * | | lifelength | climates * | | | | | | */ MT( 1827, 20, 15, 30, 0 , T ), // 0 Kirby Paul Tank (Steam) MT( 12784, 20, 22, 30, 0 , A|S ), // 1 MJS 250 (Diesel) MT( 9497, 20, 20, 50, 0 , Y), // 2 Ploddyphut Choo-Choo MT( 11688, 20, 20, 30, 0 , Y), // 3 Powernaut Choo-Choo MT( 16802, 20, 20, 30, 0 , Y), // 4 Mightymover Choo-Choo MT( 18993, 20, 20, 30, 0 , Y), // 5 Ploddyphut Diesel MT( 20820, 20, 20, 30, 0 , Y), // 6 Powernaut Diesel MT( 8766, 20, 20, 30, 0 , A|S ), // 7 Wills 2-8-0 (Steam) MT( 5114, 20, 21, 30, 0 , T ), // 8 Chaney 'Jubilee' (Steam) MT( 5479, 20, 20, 30, 0 , T ), // 9 Ginzu 'A4' (Steam) MT( 12419, 20, 23, 25, 0 , T ), // 10 SH '8P' (Steam) MT( 13149, 20, 12, 30, CT_PASSENGERS , T ), // 11 Manley-Morel DMU (Diesel) MT( 23376, 20, 15, 35, CT_PASSENGERS , T ), // 12 'Dash' (Diesel) MT( 14976, 20, 18, 28, 0 , T ), // 13 SH/Hendry '25' (Diesel) MT( 14245, 20, 20, 30, 0 , T ), // 14 UU '37' (Diesel) MT( 15341, 20, 22, 33, 0 , T ), // 15 Floss '47' (Diesel) MT( 14976, 20, 20, 25, 0 , A|S ), // 16 CS 4000 (Diesel) MT( 16437, 20, 20, 30, 0 , A|S ), // 17 CS 2400 (Diesel) MT( 18993, 20, 22, 30, 0 , A|S ), // 18 Centennial (Diesel) MT( 13880, 20, 22, 30, 0 , A|S ), // 19 Kelling 3100 (Diesel) MT( 20454, 20, 22, 30, 0 , A|S ), // 20 Turner Turbo (Diesel) MT( 16071, 20, 22, 30, 0 , A|S ), // 21 MJS 1000 (Diesel) MT( 20820, 20, 20, 25, CT_MAIL , T ), // 22 SH '125' (Diesel) MT( 16437, 20, 23, 30, 0 , T ), // 23 SH '30' (Electric) MT( 19359, 20, 23, 80, 0 , T ), // 24 SH '40' (Electric) MT( 23376, 20, 25, 30, 0 , T ), // 25 'T.I.M.' (Electric) MT( 26298, 20, 25, 50, 0 , T ), // 26 'AsiaStar' (Electric) MW( 1827, 20, 20, 50, CT_PASSENGERS , T|A|S|Y), // 27 Passenger Carriage MW( 1827, 20, 20, 50, CT_MAIL , T|A|S|Y), // 28 Mail Van MW( 1827, 20, 20, 50, CT_COAL , T|A ), // 29 Coal Truck MW( 1827, 20, 20, 50, CT_OIL , T|A|S ), // 30 Oil Tanker MW( 1827, 20, 20, 50, CT_LIVESTOCK , T|A ), // 31 Livestock Van MW( 1827, 20, 20, 50, CT_GOODS , T|A|S ), // 32 Goods Van MW( 1827, 20, 20, 50, CT_GRAIN , T|A|S ), // 33 Grain Hopper MW( 1827, 20, 20, 50, CT_WOOD , T|A|S ), // 34 Wood Truck MW( 1827, 20, 20, 50, CT_IRON_ORE , T ), // 35 Iron Ore Hopper MW( 1827, 20, 20, 50, CT_STEEL , T ), // 36 Steel Truck MW( 1827, 20, 20, 50, CT_VALUABLES , T|A|S ), // 37 Armoured Van MW( 1827, 20, 20, 50, CT_FOOD , A|S ), // 38 Food Van MW( 1827, 20, 20, 50, CT_PAPER , A ), // 39 Paper Truck MW( 1827, 20, 20, 50, CT_COPPER_ORE , S ), // 40 Copper Ore Hopper MW( 1827, 20, 20, 50, CT_WATER , S ), // 41 Water Tanker MW( 1827, 20, 20, 50, CT_FRUIT , S ), // 42 Fruit Truck MW( 1827, 20, 20, 50, CT_RUBBER , S ), // 43 Rubber Truck MW( 1827, 20, 20, 50, CT_SUGAR , Y), // 44 Sugar Truck MW( 1827, 20, 20, 50, CT_COTTON_CANDY, Y), // 45 Candyfloss Hopper MW( 1827, 20, 20, 50, CT_TOFFEE , Y), // 46 Toffee Hopper MW( 1827, 20, 20, 50, CT_BUBBLES , Y), // 47 Bubble Van MW( 1827, 20, 20, 50, CT_COLA , Y), // 48 Cola Tanker MW( 1827, 20, 20, 50, CT_CANDY , Y), // 49 Sweet Van MW( 1827, 20, 20, 50, CT_TOYS , Y), // 50 Toy Van MW( 1827, 20, 20, 50, CT_BATTERIES , Y), // 51 Battery Truck MW( 1827, 20, 20, 50, CT_FIZZY_DRINKS, Y), // 52 Fizzy Drink Truck MW( 1827, 20, 20, 50, CT_PLASTIC , Y), // 53 Plastic Truck MT( 28490, 20, 20, 50, 0 , T|A|S ), // 54 'X2001' (Electric) MT( 31047, 20, 20, 50, CT_PASSENGERS , T|A|S ), // 55 'Millennium Z1' (Electric) MT( 28855, 20, 20, 50, 0 , Y), // 56 Wizzowow Z99 MW( 1827, 20, 20, 50, CT_PASSENGERS , T|A|S|Y), // 57 Passenger Carriage MW( 1827, 20, 20, 50, CT_MAIL , T|A|S|Y), // 58 Mail Van MW( 1827, 20, 20, 50, CT_COAL , T|A ), // 59 Coal Truck MW( 1827, 20, 20, 50, CT_OIL , T|A|S ), // 60 Oil Tanker MW( 1827, 20, 20, 50, CT_LIVESTOCK , T|A ), // 61 Livestock Van MW( 1827, 20, 20, 50, CT_GOODS , T|A|S ), // 62 Goods Van MW( 1827, 20, 20, 50, CT_GRAIN , T|A|S ), // 63 Grain Hopper MW( 1827, 20, 20, 50, CT_WOOD , T|A|S ), // 64 Wood Truck MW( 1827, 20, 20, 50, CT_IRON_ORE , T ), // 65 Iron Ore Hopper MW( 1827, 20, 20, 50, CT_STEEL , T ), // 66 Steel Truck MW( 1827, 20, 20, 50, CT_VALUABLES , T|A|S ), // 67 Armoured Van MW( 1827, 20, 20, 50, CT_FOOD , A|S ), // 68 Food Van MW( 1827, 20, 20, 50, CT_PAPER , A ), // 69 Paper Truck MW( 1827, 20, 20, 50, CT_COPPER_ORE , S ), // 70 Copper Ore Hopper MW( 1827, 20, 20, 50, CT_WATER , S ), // 71 Water Tanker MW( 1827, 20, 20, 50, CT_FRUIT , S ), // 72 Fruit Truck MW( 1827, 20, 20, 50, CT_RUBBER , S ), // 73 Rubber Truck MW( 1827, 20, 20, 50, CT_SUGAR , Y), // 74 Sugar Truck MW( 1827, 20, 20, 50, CT_COTTON_CANDY, Y), // 75 Candyfloss Hopper MW( 1827, 20, 20, 50, CT_TOFFEE , Y), // 76 Toffee Hopper MW( 1827, 20, 20, 50, CT_BUBBLES , Y), // 77 Bubble Van MW( 1827, 20, 20, 50, CT_COLA , Y), // 78 Cola Tanker MW( 1827, 20, 20, 50, CT_CANDY , Y), // 79 Sweet Van MW( 1827, 20, 20, 50, CT_TOYS , Y), // 80 Toy Van MW( 1827, 20, 20, 50, CT_BATTERIES , Y), // 81 Battery Truck MW( 1827, 20, 20, 50, CT_FIZZY_DRINKS, Y), // 82 Fizzy Drink Truck MW( 1827, 20, 20, 50, CT_PLASTIC , Y), // 83 Plastic Truck MT( 36525, 20, 20, 50, 0 , T|A|S ), // 84 Lev1 'Leviathan' (Electric) MT( 39447, 20, 20, 50, 0 , T|A|S ), // 85 Lev2 'Cyclops' (Electric) MT( 42004, 20, 20, 50, 0 , T|A|S ), // 86 Lev3 'Pegasus' (Electric) MT( 42735, 20, 20, 50, 0 , T|A|S ), // 87 Lev4 'Chimaera' (Electric) MT( 36891, 20, 20, 60, 0 , Y), // 88 Wizzowow Rocketeer MW( 1827, 20, 20, 50, CT_PASSENGERS , T|A|S|Y), // 89 Passenger Carriage MW( 1827, 20, 20, 50, CT_MAIL , T|A|S|Y), // 90 Mail Van MW( 1827, 20, 20, 50, CT_COAL , T|A ), // 91 Coal Truck MW( 1827, 20, 20, 50, CT_OIL , T|A|S ), // 92 Oil Tanker MW( 1827, 20, 20, 50, CT_LIVESTOCK , T|A ), // 93 Livestock Van MW( 1827, 20, 20, 50, CT_GOODS , T|A|S ), // 94 Goods Van MW( 1827, 20, 20, 50, CT_GRAIN , T|A|S ), // 95 Grain Hopper MW( 1827, 20, 20, 50, CT_WOOD , T|A|S ), // 96 Wood Truck MW( 1827, 20, 20, 50, CT_IRON_ORE , T ), // 97 Iron Ore Hopper MW( 1827, 20, 20, 50, CT_STEEL , T ), // 98 Steel Truck MW( 1827, 20, 20, 50, CT_VALUABLES , T|A|S ), // 99 Armoured Van MW( 1827, 20, 20, 50, CT_FOOD , A|S ), // 100 Food Van MW( 1827, 20, 20, 50, CT_PAPER , A ), // 101 Paper Truck MW( 1827, 20, 20, 50, CT_COPPER_ORE , S ), // 102 Copper Ore Hopper MW( 1827, 20, 20, 50, CT_WATER , S ), // 103 Water Tanker MW( 1827, 20, 20, 50, CT_FRUIT , S ), // 104 Fruit Truck MW( 1827, 20, 20, 50, CT_RUBBER , S ), // 105 Rubber Truck MW( 1827, 20, 20, 50, CT_SUGAR , Y), // 106 Sugar Truck MW( 1827, 20, 20, 50, CT_COTTON_CANDY, Y), // 107 Candyfloss Hopper MW( 1827, 20, 20, 50, CT_TOFFEE , Y), // 108 Toffee Hopper MW( 1827, 20, 20, 50, CT_BUBBLES , Y), // 109 Bubble Van MW( 1827, 20, 20, 50, CT_COLA , Y), // 110 Cola Tanker MW( 1827, 20, 20, 50, CT_CANDY , Y), // 111 Sweet Van MW( 1827, 20, 20, 50, CT_TOYS , Y), // 112 Toy Van MW( 1827, 20, 20, 50, CT_BATTERIES , Y), // 113 Battery Truck MW( 1827, 20, 20, 50, CT_FIZZY_DRINKS, Y), // 114 Fizzy Drink Truck MW( 1827, 20, 20, 50, CT_PLASTIC , Y), // 115 Plastic Truck MR( 3378, 20, 12, 40, CT_PASSENGERS , T|A|S ), // 116 MPS Regal Bus MR( 16071, 20, 15, 30, CT_PASSENGERS , T|A|S ), // 117 Hereford Leopard Bus MR( 24107, 20, 15, 40, CT_PASSENGERS , T|A|S ), // 118 Foster Bus MR( 32142, 20, 15, 80, CT_PASSENGERS , T|A|S ), // 119 Foster MkII Superbus MR( 9132, 20, 15, 40, CT_PASSENGERS , Y), // 120 Ploddyphut MkI Bus MR( 18993, 20, 15, 40, CT_PASSENGERS , Y), // 121 Ploddyphut MkII Bus MR( 32873, 20, 15, 80, CT_PASSENGERS , Y), // 122 Ploddyphut MkIII Bus MR( 5479, 20, 15, 55, CT_COAL , T|A ), // 123 Balogh Coal Truck MR( 20089, 20, 15, 55, CT_COAL , T|A ), // 124 Uhl Coal Truck MR( 33969, 20, 15, 85, CT_COAL , T|A ), // 125 DW Coal Truck MR( 5479, 20, 15, 55, CT_MAIL , T|A|S ), // 126 MPS Mail Truck MR( 21550, 20, 15, 55, CT_MAIL , T|A|S ), // 127 Reynard Mail Truck MR( 35795, 20, 15, 85, CT_MAIL , T|A|S ), // 128 Perry Mail Truck MR( 5479, 20, 15, 55, CT_MAIL , Y), // 129 MightyMover Mail Truck MR( 21550, 20, 15, 55, CT_MAIL , Y), // 130 Powernaught Mail Truck MR( 35795, 20, 15, 85, CT_MAIL , Y), // 131 Wizzowow Mail Truck MR( 5479, 20, 15, 55, CT_OIL , T|A|S ), // 132 Witcombe Oil Tanker MR( 19359, 20, 15, 55, CT_OIL , T|A|S ), // 133 Foster Oil Tanker MR( 31047, 20, 15, 85, CT_OIL , T|A|S ), // 134 Perry Oil Tanker MR( 5479, 20, 15, 55, CT_LIVESTOCK , T|A ), // 135 Talbott Livestock Van MR( 21915, 20, 15, 55, CT_LIVESTOCK , T|A ), // 136 Uhl Livestock Van MR( 37256, 20, 15, 85, CT_LIVESTOCK , T|A ), // 137 Foster Livestock Van MR( 5479, 20, 15, 55, CT_GOODS , T|A|S ), // 138 Balogh Goods Truck MR( 19724, 20, 15, 55, CT_GOODS , T|A|S ), // 139 Craighead Goods Truck MR( 31047, 20, 15, 85, CT_GOODS , T|A|S ), // 140 Goss Goods Truck MR( 5479, 20, 15, 55, CT_GRAIN , T|A|S ), // 141 Hereford Grain Truck MR( 21185, 20, 15, 55, CT_GRAIN , T|A|S ), // 142 Thomas Grain Truck MR( 32873, 20, 15, 85, CT_GRAIN , T|A|S ), // 143 Goss Grain Truck MR( 5479, 20, 15, 55, CT_WOOD , T|A|S ), // 144 Witcombe Wood Truck MR( 19724, 20, 15, 55, CT_WOOD , T|A|S ), // 145 Foster Wood Truck MR( 35430, 20, 15, 85, CT_WOOD , T|A|S ), // 146 Moreland Wood Truck MR( 5479, 20, 15, 55, CT_IRON_ORE , T ), // 147 MPS Iron Ore Truck MR( 20820, 20, 15, 55, CT_IRON_ORE , T ), // 148 Uhl Iron Ore Truck MR( 33238, 20, 15, 85, CT_IRON_ORE , T ), // 149 Chippy Iron Ore Truck MR( 5479, 20, 15, 55, CT_STEEL , T ), // 150 Balogh Steel Truck MR( 21185, 20, 15, 55, CT_STEEL , T ), // 151 Uhl Steel Truck MR( 31777, 20, 15, 85, CT_STEEL , T ), // 152 Kelling Steel Truck MR( 5479, 20, 15, 55, CT_VALUABLES , T|A|S ), // 153 Balogh Armoured Truck MR( 22281, 20, 15, 55, CT_VALUABLES , T|A|S ), // 154 Uhl Armoured Truck MR( 33603, 20, 15, 85, CT_VALUABLES , T|A|S ), // 155 Foster Armoured Truck MR( 5479, 20, 15, 55, CT_FOOD , A|S ), // 156 Foster Food Van MR( 18628, 20, 15, 55, CT_FOOD , A|S ), // 157 Perry Food Van MR( 30681, 20, 15, 85, CT_FOOD , A|S ), // 158 Chippy Food Van MR( 5479, 20, 15, 55, CT_PAPER , A ), // 159 Uhl Paper Truck MR( 21185, 20, 15, 55, CT_PAPER , A ), // 160 Balogh Paper Truck MR( 31777, 20, 15, 85, CT_PAPER , A ), // 161 MPS Paper Truck MR( 5479, 20, 15, 55, CT_COPPER_ORE , S ), // 162 MPS Copper Ore Truck MR( 20820, 20, 15, 55, CT_COPPER_ORE , S ), // 163 Uhl Copper Ore Truck MR( 33238, 20, 15, 85, CT_COPPER_ORE , S ), // 164 Goss Copper Ore Truck MR( 5479, 20, 15, 55, CT_WATER , S ), // 165 Uhl Water Tanker MR( 20970, 20, 15, 55, CT_WATER , S ), // 166 Balogh Water Tanker MR( 33388, 20, 15, 85, CT_WATER , S ), // 167 MPS Water Tanker MR( 5479, 20, 15, 55, CT_FRUIT , S ), // 168 Balogh Fruit Truck MR( 21335, 20, 15, 55, CT_FRUIT , S ), // 169 Uhl Fruit Truck MR( 33753, 20, 15, 85, CT_FRUIT , S ), // 170 Kelling Fruit Truck MR( 5479, 20, 15, 55, CT_RUBBER , S ), // 171 Balogh Rubber Truck MR( 20604, 20, 15, 55, CT_RUBBER , S ), // 172 Uhl Rubber Truck MR( 33023, 20, 15, 85, CT_RUBBER , S ), // 173 RMT Rubber Truck MR( 5479, 20, 15, 55, CT_SUGAR , Y), // 174 MightyMover Sugar Truck MR( 19724, 20, 15, 55, CT_SUGAR , Y), // 175 Powernaught Sugar Truck MR( 33238, 20, 15, 85, CT_SUGAR , Y), // 176 Wizzowow Sugar Truck MR( 5479, 20, 15, 55, CT_COLA , Y), // 177 MightyMover Cola Truck MR( 20089, 20, 15, 55, CT_COLA , Y), // 178 Powernaught Cola Truck MR( 33603, 20, 15, 85, CT_COLA , Y), // 179 Wizzowow Cola Truck MR( 5479, 20, 15, 55, CT_COTTON_CANDY, Y), // 180 MightyMover Candyfloss Truck MR( 20454, 20, 15, 55, CT_COTTON_CANDY, Y), // 181 Powernaught Candyfloss Truck MR( 33969, 20, 15, 85, CT_COTTON_CANDY, Y), // 182 Wizzowow Candyfloss Truck MR( 5479, 20, 15, 55, CT_TOFFEE , Y), // 183 MightyMover Toffee Truck MR( 20820, 20, 15, 55, CT_TOFFEE , Y), // 184 Powernaught Toffee Truck MR( 34334, 20, 15, 85, CT_TOFFEE , Y), // 185 Wizzowow Toffee Truck MR( 5479, 20, 15, 55, CT_TOYS , Y), // 186 MightyMover Toy Van MR( 21185, 20, 15, 55, CT_TOYS , Y), // 187 Powernaught Toy Van MR( 34699, 20, 15, 85, CT_TOYS , Y), // 188 Wizzowow Toy Van MR( 5479, 20, 15, 55, CT_CANDY , Y), // 189 MightyMover Sweet Truck MR( 21550, 20, 15, 55, CT_CANDY , Y), // 190 Powernaught Sweet Truck MR( 35064, 20, 15, 85, CT_CANDY , Y), // 191 Wizzowow Sweet Truck MR( 5479, 20, 15, 55, CT_BATTERIES , Y), // 192 MightyMover Battery Truck MR( 19874, 20, 15, 55, CT_BATTERIES , Y), // 193 Powernaught Battery Truck MR( 35430, 20, 15, 85, CT_BATTERIES , Y), // 194 Wizzowow Battery Truck MR( 5479, 20, 15, 55, CT_FIZZY_DRINKS, Y), // 195 MightyMover Fizzy Drink Truck MR( 20239, 20, 15, 55, CT_FIZZY_DRINKS, Y), // 196 Powernaught Fizzy Drink Truck MR( 35795, 20, 15, 85, CT_FIZZY_DRINKS, Y), // 197 Wizzowow Fizzy Drink Truck MR( 5479, 20, 15, 55, CT_PLASTIC , Y), // 198 MightyMover Plastic Truck MR( 20604, 20, 15, 55, CT_PLASTIC , Y), // 199 Powernaught Plastic Truck MR( 32873, 20, 15, 85, CT_PLASTIC , Y), // 200 Wizzowow Plastic Truck MR( 5479, 20, 15, 55, CT_BUBBLES , Y), // 201 MightyMover Bubble Truck MR( 20970, 20, 15, 55, CT_BUBBLES , Y), // 202 Powernaught Bubble Truck MR( 33023, 20, 15, 85, CT_BUBBLES , Y), // 203 Wizzowow Bubble Truck MS( 2922, 5, 30, 50, CT_OIL , T|A|S ), // 204 MPS Oil Tanker MS( 17167, 5, 30, 90, CT_OIL , T|A|S ), // 205 CS-Inc. Oil Tanker MS( 2192, 5, 30, 55, CT_PASSENGERS , T|A|S ), // 206 MPS Passenger Ferry MS( 18628, 5, 30, 90, CT_PASSENGERS , T|A|S ), // 207 FFP Passenger Ferry MS( 17257, 10, 25, 90, CT_PASSENGERS , T|A|S ), // 208 Bakewell 300 Hovercraft MS( 9587, 5, 30, 40, CT_PASSENGERS , Y), // 209 Chugger-Chug Passenger Ferry MS( 20544, 5, 30, 90, CT_PASSENGERS , Y), // 210 Shivershake Passenger Ferry MS( 2557, 5, 30, 55, CT_GOODS , T|A|S ), // 211 Yate Cargo ship MS( 19724, 5, 30, 98, CT_GOODS , T|A|S ), // 212 Bakewell Cargo ship MS( 9587, 5, 30, 45, CT_GOODS , Y), // 213 Mightymover Cargo ship MS( 22371, 5, 30, 90, CT_GOODS , Y), // 214 Powernaut Cargo ship MA( 2922, 20, 20, 20, T|A|S ), // 215 Sampson U52 MA( 9922, 20, 24, 20, T|A|S ), // 216 Coleman Count MA( 12659, 20, 18, 20, T|A|S ), // 217 FFP Dart MA( 17652, 20, 25, 35, T|A|S ), // 218 Yate Haugan MA( 4929, 20, 30, 30, T|A|S ), // 219 Bakewell Cotswald LB-3 MA( 13695, 20, 23, 25, T|A|S ), // 220 Bakewell Luckett LB-8 MA( 16341, 20, 26, 30, T|A|S ), // 221 Bakewell Luckett LB-9 MA( 21395, 20, 25, 30, T|A|S ), // 222 Bakewell Luckett LB80 MA( 18263, 20, 20, 30, T|A|S ), // 223 Bakewell Luckett LB-10 MA( 25233, 20, 25, 30, T|A|S ), // 224 Bakewell Luckett LB-11 MA( 15371, 20, 22, 25, T|A|S ), // 225 Yate Aerospace YAC 1-11 MA( 15461, 20, 25, 25, T|A|S ), // 226 Darwin 100 MA( 16952, 20, 22, 25, T|A|S ), // 227 Darwin 200 MA( 17227, 20, 25, 30, T|A|S ), // 228 Darwin 300 MA( 22371, 20, 25, 35, T|A|S ), // 229 Darwin 400 MA( 22341, 20, 25, 30, T|A|S ), // 230 Darwin 500 MA( 27209, 20, 25, 30, T|A|S ), // 231 Darwin 600 MA( 17988, 20, 20, 30, T|A|S ), // 232 Guru Galaxy MA( 18993, 20, 24, 35, T|A|S ), // 233 Airtaxi A21 MA( 22401, 20, 24, 30, T|A|S ), // 234 Airtaxi A31 MA( 24472, 20, 24, 30, T|A|S ), // 235 Airtaxi A32 MA( 26724, 20, 24, 30, T|A|S ), // 236 Airtaxi A33 MA( 22005, 20, 25, 30, T|A|S ), // 237 Yate Aerospace YAe46 MA( 24107, 20, 20, 35, T|A|S ), // 238 Dinger 100 MA( 29310, 20, 25, 60, T|A|S ), // 239 AirTaxi A34-1000 MA( 35520, 20, 22, 30, T|A|S ), // 240 Yate Z-Shuttle MA( 36981, 20, 22, 30, T|A|S ), // 241 Kelling K1 MA( 38807, 20, 22, 50, T|A|S ), // 242 Kelling K6 MA( 42094, 20, 25, 30, T|A|S ), // 243 Kelling K7 MA( 44651, 20, 23, 30, T|A|S ), // 244 Darwin 700 MA( 40268, 20, 25, 30, T|A|S ), // 245 FFP Hyperdart 2 MA( 33693, 20, 25, 50, T|A|S ), // 246 Dinger 200 MA( 32963, 20, 20, 60, T|A|S ), // 247 Dinger 1000 MA( 9222, 20, 20, 35, Y), // 248 Ploddyphut 100 MA( 12874, 20, 20, 35, Y), // 249 Ploddyphut 500 MA( 16892, 20, 20, 35, Y), // 250 Flashbang X1 MA( 21275, 20, 20, 99, Y), // 251 Juggerplane M1 MA( 23832, 20, 20, 99, Y), // 252 Flashbang Wizzer MA( 13575, 20, 20, 40, T|A|S ), // 253 Tricario Helicopter MA( 28215, 20, 20, 30, T|A|S ), // 254 Guru X2 Helicopter MA( 13575, 20, 20, 99, Y), // 255 Powernaut Helicopter }; #undef Y #undef S #undef A #undef T #undef MT #undef MW #undef MR #undef MS #undef MA /** * Writes the properties of a rail vehicle into the RailVehicleInfo struct. * @see RailVehicleInfo * @param a image_index * @param b type * @param c cost_factor * @param d max_speed (1 unit = 1/1.6 mph = 1 km-ish/h) * @param e power (hp) * @param f weight (tons) * @param g running_cost * @param h running_cost_class * @param i capacity (persons, bags, tons, pieces, items, cubic metres, ...) * @param j railtype * @param k engclass * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Air drag value depends on the top speed of the vehicle. */ #define RVI(a, b, c, d, e, f, g, h, i, j, k) { a, b, c, {j}, d, e, f, g, h, k, i, 0, 0, 0, VE_DEFAULT, 0, 76, 0, 0 } #define M RAILVEH_MULTIHEAD #define W RAILVEH_WAGON #define G RAILVEH_SINGLEHEAD #define S EC_STEAM #define D EC_DIESEL #define E EC_ELECTRIC #define N EC_MONORAIL #define V EC_MAGLEV /* Wagons always have engine type 0, i.e. steam. */ #define A EC_STEAM #define R RAILTYPE_RAIL #define C RAILTYPE_ELECTRIC #define O RAILTYPE_MONO #define L RAILTYPE_MAGLEV #define RC_S PR_RUNNING_TRAIN_STEAM #define RC_D PR_RUNNING_TRAIN_DIESEL #define RC_E PR_RUNNING_TRAIN_ELECTRIC #define RC_W INVALID_PRICE static const RailVehicleInfo _orig_rail_vehicle_info[] = { /* image_index max_speed running_cost engclass * | type | power | running_cost_class * | | cost_factor | weight | | capacity * | | | | | | | | | railtype * | | | | | | | | | | | */ /* Rail */ RVI( 2, G, 7, 64, 300, 47, 50, RC_S, 0, R, S), // 0 Kirby Paul Tank (Steam) RVI(19, G, 8, 80, 600, 65, 65, RC_D, 0, R, D), // 1 MJS 250 (Diesel) RVI( 2, G, 10, 72, 400, 85, 90, RC_S, 0, R, S), // 2 Ploddyphut Choo-Choo RVI( 0, G, 15, 96, 900, 130, 130, RC_S, 0, R, S), // 3 Powernaut Choo-Choo RVI( 1, G, 19, 112, 1000, 140, 145, RC_S, 0, R, S), // 4 Mightymover Choo-Choo RVI(12, G, 16, 120, 1400, 95, 125, RC_D, 0, R, D), // 5 Ploddyphut Diesel RVI(14, G, 20, 152, 2000, 120, 135, RC_D, 0, R, D), // 6 Powernaut Diesel RVI( 3, G, 14, 88, 1100, 145, 130, RC_S, 0, R, S), // 7 Wills 2-8-0 (Steam) RVI( 0, G, 13, 112, 1000, 131, 120, RC_S, 0, R, S), // 8 Chaney 'Jubilee' (Steam) RVI( 1, G, 19, 128, 1200, 162, 140, RC_S, 0, R, S), // 9 Ginzu 'A4' (Steam) RVI( 0, G, 22, 144, 1600, 170, 130, RC_S, 0, R, S), // 10 SH '8P' (Steam) RVI( 8, M, 11, 112, 600, 32, 85, RC_D, 38, R, D), // 11 Manley-Morel DMU (Diesel) RVI(10, M, 14, 120, 700, 38, 70, RC_D, 40, R, D), // 12 'Dash' (Diesel) RVI( 4, G, 15, 128, 1250, 72, 95, RC_D, 0, R, D), // 13 SH/Hendry '25' (Diesel) RVI( 5, G, 17, 144, 1750, 101, 120, RC_D, 0, R, D), // 14 UU '37' (Diesel) RVI( 4, G, 18, 160, 2580, 112, 140, RC_D, 0, R, D), // 15 Floss '47' (Diesel) RVI(14, G, 23, 96, 4000, 150, 135, RC_D, 0, R, D), // 16 CS 4000 (Diesel) RVI(12, G, 16, 112, 2400, 120, 105, RC_D, 0, R, D), // 17 CS 2400 (Diesel) RVI(13, G, 30, 112, 6600, 207, 155, RC_D, 0, R, D), // 18 Centennial (Diesel) RVI(15, G, 18, 104, 1500, 110, 105, RC_D, 0, R, D), // 19 Kelling 3100 (Diesel) RVI(16, M, 35, 160, 3500, 95, 205, RC_D, 0, R, D), // 20 Turner Turbo (Diesel) RVI(18, G, 21, 104, 2200, 120, 145, RC_D, 0, R, D), // 21 MJS 1000 (Diesel) RVI( 6, M, 20, 200, 4500, 70, 190, RC_D, 4, R, D), // 22 SH '125' (Diesel) RVI(20, G, 26, 160, 3600, 84, 180, RC_E, 0, C, E), // 23 SH '30' (Electric) RVI(20, G, 30, 176, 5000, 82, 205, RC_E, 0, C, E), // 24 SH '40' (Electric) RVI(21, M, 40, 240, 7000, 90, 240, RC_E, 0, C, E), // 25 'T.I.M.' (Electric) RVI(23, M, 43, 264, 8000, 95, 250, RC_E, 0, C, E), // 26 'AsiaStar' (Electric) RVI(33, W, 247, 0, 0, 25, 0, RC_W, 40, R, A), // 27 Passenger Carriage RVI(35, W, 228, 0, 0, 21, 0, RC_W, 30, R, A), // 28 Mail Van RVI(34, W, 176, 0, 0, 18, 0, RC_W, 30, R, A), // 29 Coal Truck RVI(36, W, 200, 0, 0, 24, 0, RC_W, 30, R, A), // 30 Oil Tanker RVI(37, W, 192, 0, 0, 20, 0, RC_W, 25, R, A), // 31 Livestock Van RVI(38, W, 190, 0, 0, 21, 0, RC_W, 25, R, A), // 32 Goods Van RVI(39, W, 182, 0, 0, 19, 0, RC_W, 30, R, A), // 33 Grain Hopper RVI(40, W, 181, 0, 0, 16, 0, RC_W, 30, R, A), // 34 Wood Truck RVI(41, W, 179, 0, 0, 19, 0, RC_W, 30, R, A), // 35 Iron Ore Hopper RVI(42, W, 196, 0, 0, 18, 0, RC_W, 20, R, A), // 36 Steel Truck RVI(43, W, 255, 0, 0, 30, 0, RC_W, 20, R, A), // 37 Armoured Van RVI(44, W, 191, 0, 0, 22, 0, RC_W, 25, R, A), // 38 Food Van RVI(45, W, 196, 0, 0, 18, 0, RC_W, 20, R, A), // 39 Paper Truck RVI(46, W, 179, 0, 0, 19, 0, RC_W, 30, R, A), // 40 Copper Ore Hopper RVI(47, W, 199, 0, 0, 25, 0, RC_W, 25, R, A), // 41 Water Tanker RVI(48, W, 182, 0, 0, 18, 0, RC_W, 25, R, A), // 42 Fruit Truck RVI(49, W, 185, 0, 0, 19, 0, RC_W, 21, R, A), // 43 Rubber Truck RVI(50, W, 176, 0, 0, 19, 0, RC_W, 30, R, A), // 44 Sugar Truck RVI(51, W, 178, 0, 0, 20, 0, RC_W, 30, R, A), // 45 Candyfloss Hopper RVI(52, W, 192, 0, 0, 20, 0, RC_W, 30, R, A), // 46 Toffee Hopper RVI(53, W, 190, 0, 0, 21, 0, RC_W, 20, R, A), // 47 Bubble Van RVI(54, W, 182, 0, 0, 24, 0, RC_W, 25, R, A), // 48 Cola Tanker RVI(55, W, 181, 0, 0, 21, 0, RC_W, 25, R, A), // 49 Sweet Van RVI(56, W, 183, 0, 0, 21, 0, RC_W, 20, R, A), // 50 Toy Van RVI(57, W, 196, 0, 0, 18, 0, RC_W, 22, R, A), // 51 Battery Truck RVI(58, W, 193, 0, 0, 18, 0, RC_W, 25, R, A), // 52 Fizzy Drink Truck RVI(59, W, 191, 0, 0, 18, 0, RC_W, 30, R, A), // 53 Plastic Truck /* Monorail */ RVI(25, G, 52, 304, 9000, 95, 230, RC_E, 0, O, N), // 54 'X2001' (Electric) RVI(26, M, 60, 336, 10000, 85, 240, RC_E, 25, O, N), // 55 'Millennium Z1' (Electric) RVI(26, G, 53, 320, 5000, 95, 230, RC_E, 0, O, N), // 56 Wizzowow Z99 RVI(60, W, 247, 0, 0, 25, 0, RC_W, 45, O, A), // 57 Passenger Carriage RVI(62, W, 228, 0, 0, 21, 0, RC_W, 35, O, A), // 58 Mail Van RVI(61, W, 176, 0, 0, 18, 0, RC_W, 35, O, A), // 59 Coal Truck RVI(63, W, 200, 0, 0, 24, 0, RC_W, 35, O, A), // 60 Oil Tanker RVI(64, W, 192, 0, 0, 20, 0, RC_W, 30, O, A), // 61 Livestock Van RVI(65, W, 190, 0, 0, 21, 0, RC_W, 30, O, A), // 62 Goods Van RVI(66, W, 182, 0, 0, 19, 0, RC_W, 35, O, A), // 63 Grain Hopper RVI(67, W, 181, 0, 0, 16, 0, RC_W, 35, O, A), // 64 Wood Truck RVI(68, W, 179, 0, 0, 19, 0, RC_W, 35, O, A), // 65 Iron Ore Hopper RVI(69, W, 196, 0, 0, 18, 0, RC_W, 25, O, A), // 66 Steel Truck RVI(70, W, 255, 0, 0, 30, 0, RC_W, 25, O, A), // 67 Armoured Van RVI(71, W, 191, 0, 0, 22, 0, RC_W, 30, O, A), // 68 Food Van RVI(72, W, 196, 0, 0, 18, 0, RC_W, 25, O, A), // 69 Paper Truck RVI(73, W, 179, 0, 0, 19, 0, RC_W, 35, O, A), // 70 Copper Ore Hopper RVI(47, W, 199, 0, 0, 25, 0, RC_W, 30, O, A), // 71 Water Tanker RVI(48, W, 182, 0, 0, 18, 0, RC_W, 30, O, A), // 72 Fruit Truck RVI(49, W, 185, 0, 0, 19, 0, RC_W, 26, O, A), // 73 Rubber Truck RVI(50, W, 176, 0, 0, 19, 0, RC_W, 35, O, A), // 74 Sugar Truck RVI(51, W, 178, 0, 0, 20, 0, RC_W, 35, O, A), // 75 Candyfloss Hopper RVI(52, W, 192, 0, 0, 20, 0, RC_W, 35, O, A), // 76 Toffee Hopper RVI(53, W, 190, 0, 0, 21, 0, RC_W, 25, O, A), // 77 Bubble Van RVI(54, W, 182, 0, 0, 24, 0, RC_W, 30, O, A), // 78 Cola Tanker RVI(55, W, 181, 0, 0, 21, 0, RC_W, 30, O, A), // 79 Sweet Van RVI(56, W, 183, 0, 0, 21, 0, RC_W, 25, O, A), // 80 Toy Van RVI(57, W, 196, 0, 0, 18, 0, RC_W, 27, O, A), // 81 Battery Truck RVI(58, W, 193, 0, 0, 18, 0, RC_W, 30, O, A), // 82 Fizzy Drink Truck RVI(59, W, 191, 0, 0, 18, 0, RC_W, 35, O, A), // 83 Plastic Truck /* Maglev */ RVI(28, G, 70, 400, 10000, 105, 250, RC_E, 0, L, V), // 84 Lev1 'Leviathan' (Electric) RVI(29, G, 74, 448, 12000, 120, 253, RC_E, 0, L, V), // 85 Lev2 'Cyclops' (Electric) RVI(30, G, 82, 480, 15000, 130, 254, RC_E, 0, L, V), // 86 Lev3 'Pegasus' (Electric) RVI(31, M, 95, 640, 20000, 150, 255, RC_E, 0, L, V), // 87 Lev4 'Chimaera' (Electric) RVI(28, G, 70, 480, 10000, 120, 250, RC_E, 0, L, V), // 88 Wizzowow Rocketeer RVI(60, W, 247, 0, 0, 25, 0, RC_W, 47, L, A), // 89 Passenger Carriage RVI(62, W, 228, 0, 0, 21, 0, RC_W, 37, L, A), // 90 Mail Van RVI(61, W, 176, 0, 0, 18, 0, RC_W, 37, L, A), // 91 Coal Truck RVI(63, W, 200, 0, 0, 24, 0, RC_W, 37, L, A), // 92 Oil Tanker RVI(64, W, 192, 0, 0, 20, 0, RC_W, 32, L, A), // 93 Livestock Van RVI(65, W, 190, 0, 0, 21, 0, RC_W, 32, L, A), // 94 Goods Van RVI(66, W, 182, 0, 0, 19, 0, RC_W, 37, L, A), // 95 Grain Hopper RVI(67, W, 181, 0, 0, 16, 0, RC_W, 37, L, A), // 96 Wood Truck RVI(68, W, 179, 0, 0, 19, 0, RC_W, 37, L, A), // 97 Iron Ore Hopper RVI(69, W, 196, 0, 0, 18, 0, RC_W, 27, L, A), // 98 Steel Truck RVI(70, W, 255, 0, 0, 30, 0, RC_W, 27, L, A), // 99 Armoured Van RVI(71, W, 191, 0, 0, 22, 0, RC_W, 32, L, A), // 100 Food Van RVI(72, W, 196, 0, 0, 18, 0, RC_W, 27, L, A), // 101 Paper Truck RVI(73, W, 179, 0, 0, 19, 0, RC_W, 37, L, A), // 102 Copper Ore Hopper RVI(47, W, 199, 0, 0, 25, 0, RC_W, 32, L, A), // 103 Water Tanker RVI(48, W, 182, 0, 0, 18, 0, RC_W, 32, L, A), // 104 Fruit Truck RVI(49, W, 185, 0, 0, 19, 0, RC_W, 28, L, A), // 105 Rubber Truck RVI(50, W, 176, 0, 0, 19, 0, RC_W, 37, L, A), // 106 Sugar Truck RVI(51, W, 178, 0, 0, 20, 0, RC_W, 37, L, A), // 107 Candyfloss Hopper RVI(52, W, 192, 0, 0, 20, 0, RC_W, 37, L, A), // 108 Toffee Hopper RVI(53, W, 190, 0, 0, 21, 0, RC_W, 27, L, A), // 109 Bubble Van RVI(54, W, 182, 0, 0, 24, 0, RC_W, 32, L, A), // 110 Cola Tanker RVI(55, W, 181, 0, 0, 21, 0, RC_W, 32, L, A), // 111 Sweet Van RVI(56, W, 183, 0, 0, 21, 0, RC_W, 27, L, A), // 112 Toy Van RVI(57, W, 196, 0, 0, 18, 0, RC_W, 29, L, A), // 113 Battery Truck RVI(58, W, 193, 0, 0, 18, 0, RC_W, 32, L, A), // 114 Fizzy Drink Truck RVI(59, W, 191, 0, 0, 18, 0, RC_W, 37, L, A), // 115 Plastic Truck }; #undef RC_W #undef RC_E #undef RC_D #undef RC_S #undef L #undef O #undef C #undef R #undef V #undef N #undef E #undef D #undef S #undef G #undef W #undef M #undef RVI /** * Writes the properties of a ship into the ShipVehicleInfo struct. * @see ShipVehicleInfo * @param a image_index * @param b cost_factor * @param c max_speed (1 unit = 1/3.2 mph = 0.5 km-ish/h) * @param d capacity (persons, bags, tons, pieces, items, cubic metres, ...) * @param e running_cost * @param f sound effect * @param g refittable */ #define SVI(a, b, c, d, e, f, g) { a, b, c, d, e, f, g, VE_DEFAULT, 0, 0 } static const ShipVehicleInfo _orig_ship_vehicle_info[] = { /* image_index capacity refittable * | cost_factor running_cost | * | | max_speed | sfx | * | | | | | | | */ SVI( 1, 160, 48, 220, 140, SND_06_SHIP_HORN, 0 ), // 0 MPS Oil Tanker SVI( 1, 176, 80, 350, 125, SND_06_SHIP_HORN, 0 ), // 1 CS-Inc. Oil Tanker SVI( 2, 96, 64, 100, 90, SND_07_FERRY_HORN, 0 ), // 2 MPS Passenger Ferry SVI( 2, 112, 128, 130, 80, SND_07_FERRY_HORN, 0 ), // 3 FFP Passenger Ferry SVI( 3, 148, 224, 100, 190, SND_07_FERRY_HORN, 0 ), // 4 Bakewell 300 Hovercraft SVI( 2, 96, 64, 100, 90, SND_07_FERRY_HORN, 0 ), // 5 Chugger-Chug Passenger Ferry SVI( 2, 112, 128, 130, 80, SND_07_FERRY_HORN, 0 ), // 6 Shivershake Passenger Ferry SVI( 0, 128, 48, 160, 150, SND_06_SHIP_HORN, 1 ), // 7 Yate Cargo ship SVI( 0, 144, 80, 190, 113, SND_06_SHIP_HORN, 1 ), // 8 Bakewell Cargo ship SVI( 0, 128, 48, 160, 150, SND_06_SHIP_HORN, 1 ), // 9 Mightymover Cargo ship SVI( 0, 144, 80, 190, 113, SND_06_SHIP_HORN, 1 ), // 10 Powernaut Cargo ship }; #undef SVI /** * Writes the properties of an aircraft into the AircraftVehicleInfo struct. * @see AircraftVehicleInfo * @param a image_index * @param b cost_factor * @param c running_Cost * @param d subtype (bit 0 - plane, bit 1 - large plane) * @param e sound effect * @param f acceleration (1 unit = 3/8 mph/tick = 3/5 km-ish/h/tick) (stays the same in the variable) * @param g max_speed (1 unit = 8 mph = 12.8 km-ish/h) (is converted to km-ish/h by the macro) * @param h mail_capacity (bags) * @param i passenger_capacity (persons) */ #define AVI(a, b, c, d, e, f, g, h, i) { a, b, c, d, e, f, (g * 128) / 10, h, i, 0 } #define H AIR_HELI #define P AIR_CTOL #define J AIR_CTOL | AIR_FAST static const AircraftVehicleInfo _orig_aircraft_vehicle_info[] = { /* image_index sfx acceleration * | cost_factor | | max_speed * | | running_cost | | mail_capacity * | | | subtype | | | | passenger_capacity * | | | | | | | | | */ AVI( 1, 14, 85, P, SND_08_PLANE_TAKE_OFF, 18, 37, 4, 25 ), // 0 Sampson U52 AVI( 0, 15, 100, P, SND_08_PLANE_TAKE_OFF, 20, 37, 8, 65 ), // 1 Coleman Count AVI( 2, 16, 130, J, SND_09_JET, 35, 74, 10, 90 ), // 2 FFP Dart AVI( 8, 75, 250, J, SND_3B_JET_OVERHEAD, 50, 181, 20, 100 ), // 3 Yate Haugan AVI( 5, 15, 98, P, SND_08_PLANE_TAKE_OFF, 20, 37, 6, 30 ), // 4 Bakewell Cotswald LB-3 AVI( 6, 18, 240, J, SND_09_JET, 40, 74, 30, 200 ), // 5 Bakewell Luckett LB-8 AVI( 2, 17, 150, P, SND_09_JET, 35, 74, 15, 100 ), // 6 Bakewell Luckett LB-9 AVI( 2, 18, 245, J, SND_09_JET, 40, 74, 30, 150 ), // 7 Bakewell Luckett LB80 AVI( 3, 19, 192, J, SND_09_JET, 40, 74, 40, 220 ), // 8 Bakewell Luckett LB-10 AVI( 3, 20, 190, J, SND_09_JET, 40, 74, 25, 230 ), // 9 Bakewell Luckett LB-11 AVI( 2, 16, 135, J, SND_09_JET, 35, 74, 10, 95 ), // 10 Yate Aerospace YAC 1-11 AVI( 2, 18, 240, J, SND_09_JET, 40, 74, 35, 170 ), // 11 Darwin 100 AVI( 4, 17, 155, J, SND_09_JET, 40, 74, 15, 110 ), // 12 Darwin 200 AVI( 7, 30, 253, J, SND_3D_ANOTHER_JET_OVERHEAD, 40, 74, 50, 300 ), // 13 Darwin 300 AVI( 4, 18, 210, J, SND_09_JET, 40, 74, 25, 200 ), // 14 Darwin 400 AVI( 4, 19, 220, J, SND_09_JET, 40, 74, 25, 240 ), // 15 Darwin 500 AVI( 4, 27, 230, J, SND_09_JET, 40, 74, 40, 260 ), // 16 Darwin 600 AVI( 3, 25, 225, J, SND_09_JET, 40, 74, 35, 240 ), // 17 Guru Galaxy AVI( 4, 20, 235, J, SND_09_JET, 40, 74, 30, 260 ), // 18 Airtaxi A21 AVI( 4, 19, 220, J, SND_09_JET, 40, 74, 25, 210 ), // 19 Airtaxi A31 AVI( 4, 18, 170, J, SND_09_JET, 40, 74, 20, 160 ), // 20 Airtaxi A32 AVI( 4, 26, 210, J, SND_09_JET, 40, 74, 20, 220 ), // 21 Airtaxi A33 AVI( 6, 16, 125, P, SND_09_JET, 50, 74, 10, 80 ), // 22 Yate Aerospace YAe46 AVI( 2, 17, 145, P, SND_09_JET, 40, 74, 10, 85 ), // 23 Dinger 100 AVI( 11, 16, 130, P, SND_09_JET, 40, 74, 10, 75 ), // 24 AirTaxi A34-1000 AVI( 10, 16, 149, P, SND_09_JET, 40, 74, 10, 85 ), // 25 Yate Z-Shuttle AVI( 15, 17, 170, P, SND_09_JET, 40, 74, 18, 65 ), // 26 Kelling K1 AVI( 12, 18, 210, J, SND_09_JET, 40, 74, 25, 110 ), // 27 Kelling K6 AVI( 13, 20, 230, J, SND_09_JET, 40, 74, 60, 180 ), // 28 Kelling K7 AVI( 14, 21, 220, J, SND_09_JET, 40, 74, 65, 150 ), // 29 Darwin 700 AVI( 16, 19, 160, J, SND_09_JET, 40, 181, 45, 85 ), // 30 FFP Hyperdart 2 AVI( 17, 24, 248, J, SND_3D_ANOTHER_JET_OVERHEAD, 40, 74, 80, 400 ), // 31 Dinger 200 AVI( 18, 80, 251, J, SND_3B_JET_OVERHEAD, 50, 181, 45, 130 ), // 32 Dinger 1000 AVI( 20, 13, 85, P, SND_45_PLANE_CRASHING, 18, 37, 5, 25 ), // 33 Ploddyphut 100 AVI( 21, 18, 100, P, SND_46_PLANE_ENGINE_SPUTTERING, 20, 37, 9, 60 ), // 34 Ploddyphut 500 AVI( 22, 25, 140, P, SND_09_JET, 40, 74, 12, 90 ), // 35 Flashbang X1 AVI( 23, 32, 220, J, SND_3D_ANOTHER_JET_OVERHEAD, 40, 74, 40, 200 ), // 36 Juggerplane M1 AVI( 24, 80, 255, J, SND_3B_JET_OVERHEAD, 50, 181, 30, 100 ), // 37 Flashbang Wizzer AVI( 9, 15, 81, H, SND_09_JET, 20, 25, 15, 40 ), // 38 Tricario Helicopter AVI( 19, 17, 77, H, SND_09_JET, 20, 40, 20, 55 ), // 39 Guru X2 Helicopter AVI( 25, 15, 80, H, SND_09_JET, 20, 25, 10, 40 ), // 40 Powernaut Helicopter }; #undef J #undef P #undef H #undef AVI /** * Writes the properties of a road vehicle into the RoadVehicleInfo struct. * @see RoadVehicleInfo * @param a image_index * @param b cost_factor * @param c running_cost * @param d sound effect * @param e max_speed (1 unit = 1/3.2 mph = 0.5 km-ish/h) * @param f capacity (persons, bags, tons, pieces, items, cubic metres, ...) * @param g weight (1/4 ton) * @param h power (10 hp) * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76 * Air drag value depends on the top speed of the vehicle. */ #define ROV(a, b, c, d, e, f, g, h) { a, b, c, PR_RUNNING_ROADVEH, d, e, f, g, h, 76, 0, VE_DEFAULT, 0 } static const RoadVehicleInfo _orig_road_vehicle_info[] = { /* image_index sfx max_speed power * | cost_factor | | capacity | * | | running_cost | | weight * | | | | | | | |*/ ROV( 0, 120, 91, SND_19_BUS_START_PULL_AWAY, 112, 31, 42, 9), // 0 MPS Regal Bus ROV( 17, 140, 128, SND_1C_TRUCK_START_2, 176, 35, 60, 12), // 1 Hereford Leopard Bus ROV( 17, 150, 178, SND_1B_TRUCK_START, 224, 37, 70, 15), // 2 Foster Bus ROV( 34, 160, 240, SND_1B_TRUCK_START, 255, 40, 100, 25), // 3 Foster MkII Superbus ROV( 51, 120, 91, SND_3C_COMEDY_CAR, 112, 30, 42, 9), // 4 Ploddyphut MkI Bus ROV( 51, 140, 171, SND_3E_COMEDY_CAR_2, 192, 35, 60, 15), // 5 Ploddyphut MkII Bus ROV( 51, 160, 240, SND_3C_COMEDY_CAR, 240, 38, 90, 25), // 6 Ploddyphut MkIII Bus ROV( 1, 108, 90, SND_19_BUS_START_PULL_AWAY, 96, 20, 38, 12), // 7 Balogh Coal Truck ROV( 18, 128, 168, SND_19_BUS_START_PULL_AWAY, 176, 25, 48, 22), // 8 Uhl Coal Truck ROV( 35, 138, 240, SND_19_BUS_START_PULL_AWAY, 224, 28, 69, 45), // 9 DW Coal Truck ROV( 2, 115, 90, SND_19_BUS_START_PULL_AWAY, 96, 22, 38, 12), // 10 MPS Mail Truck ROV( 19, 135, 168, SND_19_BUS_START_PULL_AWAY, 176, 28, 48, 22), // 11 Reynard Mail Truck ROV( 36, 145, 240, SND_19_BUS_START_PULL_AWAY, 224, 30, 69, 45), // 12 Perry Mail Truck ROV( 57, 115, 90, SND_3E_COMEDY_CAR_2, 96, 22, 38, 12), // 13 MightyMover Mail Truck ROV( 57, 135, 168, SND_3C_COMEDY_CAR, 176, 28, 48, 22), // 14 Powernaught Mail Truck ROV( 57, 145, 240, SND_3E_COMEDY_CAR_2, 224, 30, 69, 45), // 15 Wizzowow Mail Truck ROV( 3, 110, 90, SND_19_BUS_START_PULL_AWAY, 96, 21, 38, 12), // 16 Witcombe Oil Tanker ROV( 20, 140, 168, SND_19_BUS_START_PULL_AWAY, 176, 25, 48, 22), // 17 Foster Oil Tanker ROV( 37, 150, 240, SND_19_BUS_START_PULL_AWAY, 224, 27, 69, 45), // 18 Perry Oil Tanker ROV( 4, 105, 90, SND_19_BUS_START_PULL_AWAY, 96, 14, 38, 12), // 19 Talbott Livestock Van ROV( 21, 130, 168, SND_19_BUS_START_PULL_AWAY, 176, 16, 48, 22), // 20 Uhl Livestock Van ROV( 38, 140, 240, SND_19_BUS_START_PULL_AWAY, 224, 18, 69, 45), // 21 Foster Livestock Van ROV( 5, 107, 90, SND_19_BUS_START_PULL_AWAY, 96, 14, 38, 12), // 22 Balogh Goods Truck ROV( 22, 130, 168, SND_19_BUS_START_PULL_AWAY, 176, 16, 48, 22), // 23 Craighead Goods Truck ROV( 39, 140, 240, SND_19_BUS_START_PULL_AWAY, 224, 18, 69, 45), // 24 Goss Goods Truck ROV( 6, 114, 90, SND_19_BUS_START_PULL_AWAY, 96, 20, 38, 12), // 25 Hereford Grain Truck ROV( 23, 133, 168, SND_19_BUS_START_PULL_AWAY, 176, 25, 48, 22), // 26 Thomas Grain Truck ROV( 40, 143, 240, SND_19_BUS_START_PULL_AWAY, 224, 30, 69, 45), // 27 Goss Grain Truck ROV( 7, 118, 90, SND_19_BUS_START_PULL_AWAY, 96, 20, 38, 12), // 28 Witcombe Wood Truck ROV( 24, 137, 168, SND_19_BUS_START_PULL_AWAY, 176, 22, 48, 22), // 29 Foster Wood Truck ROV( 41, 147, 240, SND_19_BUS_START_PULL_AWAY, 224, 24, 69, 45), // 30 Moreland Wood Truck ROV( 8, 121, 90, SND_19_BUS_START_PULL_AWAY, 96, 22, 38, 12), // 31 MPS Iron Ore Truck ROV( 25, 140, 168, SND_19_BUS_START_PULL_AWAY, 176, 25, 48, 22), // 32 Uhl Iron Ore Truck ROV( 42, 150, 240, SND_19_BUS_START_PULL_AWAY, 224, 27, 69, 45), // 33 Chippy Iron Ore Truck ROV( 9, 112, 90, SND_19_BUS_START_PULL_AWAY, 96, 15, 38, 12), // 34 Balogh Steel Truck ROV( 26, 135, 168, SND_19_BUS_START_PULL_AWAY, 176, 18, 48, 22), // 35 Uhl Steel Truck ROV( 43, 145, 240, SND_19_BUS_START_PULL_AWAY, 224, 20, 69, 45), // 36 Kelling Steel Truck ROV( 10, 145, 90, SND_19_BUS_START_PULL_AWAY, 96, 12, 38, 12), // 37 Balogh Armoured Truck ROV( 27, 170, 168, SND_19_BUS_START_PULL_AWAY, 176, 15, 48, 22), // 38 Uhl Armoured Truck ROV( 44, 180, 240, SND_19_BUS_START_PULL_AWAY, 224, 16, 69, 45), // 39 Foster Armoured Truck ROV( 11, 112, 90, SND_19_BUS_START_PULL_AWAY, 96, 17, 38, 12), // 40 Foster Food Van ROV( 28, 134, 168, SND_19_BUS_START_PULL_AWAY, 176, 20, 48, 22), // 41 Perry Food Van ROV( 45, 144, 240, SND_19_BUS_START_PULL_AWAY, 224, 22, 69, 45), // 42 Chippy Food Van ROV( 12, 112, 90, SND_19_BUS_START_PULL_AWAY, 96, 15, 38, 12), // 43 Uhl Paper Truck ROV( 29, 135, 168, SND_19_BUS_START_PULL_AWAY, 176, 18, 48, 22), // 44 Balogh Paper Truck ROV( 46, 145, 240, SND_19_BUS_START_PULL_AWAY, 224, 20, 69, 45), // 45 MPS Paper Truck ROV( 13, 121, 90, SND_19_BUS_START_PULL_AWAY, 96, 22, 38, 12), // 46 MPS Copper Ore Truck ROV( 30, 140, 168, SND_19_BUS_START_PULL_AWAY, 176, 25, 48, 22), // 47 Uhl Copper Ore Truck ROV( 47, 150, 240, SND_19_BUS_START_PULL_AWAY, 224, 27, 69, 45), // 48 Goss Copper Ore Truck ROV( 14, 111, 90, SND_19_BUS_START_PULL_AWAY, 96, 21, 38, 12), // 49 Uhl Water Tanker ROV( 31, 141, 168, SND_19_BUS_START_PULL_AWAY, 176, 25, 48, 22), // 50 Balogh Water Tanker ROV( 48, 151, 240, SND_19_BUS_START_PULL_AWAY, 224, 27, 69, 45), // 51 MPS Water Tanker ROV( 15, 118, 90, SND_19_BUS_START_PULL_AWAY, 96, 18, 38, 12), // 52 Balogh Fruit Truck ROV( 32, 148, 168, SND_19_BUS_START_PULL_AWAY, 176, 20, 48, 22), // 53 Uhl Fruit Truck ROV( 49, 158, 240, SND_19_BUS_START_PULL_AWAY, 224, 23, 69, 45), // 54 Kelling Fruit Truck ROV( 16, 117, 90, SND_19_BUS_START_PULL_AWAY, 96, 17, 38, 12), // 55 Balogh Rubber Truck ROV( 33, 147, 168, SND_19_BUS_START_PULL_AWAY, 176, 19, 48, 22), // 56 Uhl Rubber Truck ROV( 50, 157, 240, SND_19_BUS_START_PULL_AWAY, 224, 22, 69, 45), // 57 RMT Rubber Truck ROV( 52, 117, 90, SND_3F_COMEDY_CAR_3, 96, 17, 38, 12), // 58 MightyMover Sugar Truck ROV( 52, 147, 168, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 176, 19, 48, 22), // 59 Powernaught Sugar Truck ROV( 52, 157, 240, SND_3F_COMEDY_CAR_3, 224, 22, 69, 45), // 60 Wizzowow Sugar Truck ROV( 53, 117, 90, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 96, 17, 38, 12), // 61 MightyMover Cola Truck ROV( 53, 147, 168, SND_3F_COMEDY_CAR_3, 176, 19, 48, 22), // 62 Powernaught Cola Truck ROV( 53, 157, 240, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 224, 22, 69, 45), // 63 Wizzowow Cola Truck ROV( 54, 117, 90, SND_3F_COMEDY_CAR_3, 96, 17, 38, 12), // 64 MightyMover Candyfloss Truck ROV( 54, 147, 168, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 176, 19, 48, 22), // 65 Powernaught Candyfloss Truck ROV( 54, 157, 240, SND_3F_COMEDY_CAR_3, 224, 22, 69, 45), // 66 Wizzowow Candyfloss Truck ROV( 55, 117, 90, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 96, 17, 38, 12), // 67 MightyMover Toffee Truck ROV( 55, 147, 168, SND_3F_COMEDY_CAR_3, 176, 19, 48, 22), // 68 Powernaught Toffee Truck ROV( 55, 157, 240, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 224, 22, 69, 45), // 69 Wizzowow Toffee Truck ROV( 56, 117, 90, SND_3F_COMEDY_CAR_3, 96, 17, 38, 12), // 70 MightyMover Toy Van ROV( 56, 147, 168, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 176, 19, 48, 22), // 71 Powernaught Toy Van ROV( 56, 157, 240, SND_3F_COMEDY_CAR_3, 224, 22, 69, 45), // 72 Wizzowow Toy Van ROV( 58, 117, 90, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 96, 17, 38, 12), // 73 MightyMover Sweet Truck ROV( 58, 147, 168, SND_3F_COMEDY_CAR_3, 176, 19, 48, 22), // 74 Powernaught Sweet Truck ROV( 58, 157, 240, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 224, 22, 69, 45), // 75 Wizzowow Sweet Truck ROV( 59, 117, 90, SND_3F_COMEDY_CAR_3, 96, 17, 38, 12), // 76 MightyMover Battery Truck ROV( 59, 147, 168, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 176, 19, 48, 22), // 77 Powernaught Battery Truck ROV( 59, 157, 240, SND_3F_COMEDY_CAR_3, 224, 22, 69, 45), // 78 Wizzowow Battery Truck ROV( 60, 117, 90, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 96, 17, 38, 12), // 79 MightyMover Fizzy Drink Truck ROV( 60, 147, 168, SND_3F_COMEDY_CAR_3, 176, 19, 48, 22), // 80 Powernaught Fizzy Drink Truck ROV( 60, 157, 240, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 224, 22, 69, 45), // 81 Wizzowow Fizzy Drink Truck ROV( 61, 117, 90, SND_3F_COMEDY_CAR_3, 96, 17, 38, 12), // 82 MightyMover Plastic Truck ROV( 61, 147, 168, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 176, 19, 48, 22), // 83 Powernaught Plastic Truck ROV( 61, 157, 240, SND_3F_COMEDY_CAR_3, 224, 22, 69, 45), // 84 Wizzowow Plastic Truck ROV( 62, 117, 90, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 96, 17, 38, 12), // 85 MightyMover Bubble Truck ROV( 62, 147, 168, SND_3F_COMEDY_CAR_3, 176, 19, 48, 22), // 86 Powernaught Bubble Truck ROV( 62, 157, 240, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, 224, 22, 69, 45), // 87 Wizzowow Bubble Truck }; #undef ROV #endif /* ENGINES_H */ openttd-1.5.3/src/table/palettes.h0000644000000000000000000002142412627373436015563 0ustar rootroot/* $Id: palettes.h 24111 2012-04-10 20:16:51Z rubidium $ */ /* * 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 palettes.h The colour translation of the GRF palettes. */ #include "../core/endian_type.hpp" #define M(r, g, b) Colour(r, g, b) /** Colour palette (DOS) */ static const Palette _palette = { { /* transparent */ Colour(0, 0, 0, 0), /* grey scale */ M( 16, 16, 16), M( 32, 32, 32), M( 48, 48, 48), M( 65, 64, 65), M( 82, 80, 82), M( 98, 101, 98), M(115, 117, 115), /* regular colours */ M(131, 133, 131), M(148, 149, 148), M(168, 168, 168), M(184, 184, 184), M(200, 200, 200), M(216, 216, 216), M(232, 232, 232), M(252, 252, 252), M( 52, 60, 72), M( 68, 76, 92), M( 88, 96, 112), M(108, 116, 132), M(132, 140, 152), M(156, 160, 172), M(176, 184, 196), M(204, 208, 220), M( 48, 44, 4), M( 64, 60, 12), M( 80, 76, 20), M( 96, 92, 28), M(120, 120, 64), M(148, 148, 100), M(176, 176, 132), M(204, 204, 168), M( 72, 44, 4), M( 88, 60, 20), M(104, 80, 44), M(124, 104, 72), M(152, 132, 92), M(184, 160, 120), M(212, 188, 148), M(244, 220, 176), M( 64, 0, 4), M( 88, 4, 16), M(112, 16, 32), M(136, 32, 52), M(160, 56, 76), M(188, 84, 108), M(204, 104, 124), M(220, 132, 144), M(236, 156, 164), M(252, 188, 192), M(252, 212, 0), M(252, 232, 60), M(252, 248, 128), M( 76, 40, 0), M( 96, 60, 8), M(116, 88, 28), M(136, 116, 56), M(156, 136, 80), M(176, 156, 108), M(196, 180, 136), M( 68, 24, 0), M( 96, 44, 4), M(128, 68, 8), M(156, 96, 16), M(184, 120, 24), M(212, 156, 32), M(232, 184, 16), M(252, 212, 0), M(252, 248, 128), M(252, 252, 192), M( 32, 4, 0), M( 64, 20, 8), M( 84, 28, 16), M(108, 44, 28), M(128, 56, 40), M(148, 72, 56), M(168, 92, 76), M(184, 108, 88), M(196, 128, 108), M(212, 148, 128), M( 8, 52, 0), M( 16, 64, 0), M( 32, 80, 4), M( 48, 96, 4), M( 64, 112, 12), M( 84, 132, 20), M(104, 148, 28), M(128, 168, 44), M( 28, 52, 24), M( 44, 68, 32), M( 60, 88, 48), M( 80, 104, 60), M(104, 124, 76), M(128, 148, 92), M(152, 176, 108), M(180, 204, 124), M( 16, 52, 24), M( 32, 72, 44), M( 56, 96, 72), M( 76, 116, 88), M( 96, 136, 108), M(120, 164, 136), M(152, 192, 168), M(184, 220, 200), M( 32, 24, 0), M( 56, 28, 0), M( 72, 40, 4), M( 88, 52, 12), M(104, 64, 24), M(124, 84, 44), M(140, 108, 64), M(160, 128, 88), M( 76, 40, 16), M( 96, 52, 24), M(116, 68, 40), M(136, 84, 56), M(164, 96, 64), M(184, 112, 80), M(204, 128, 96), M(212, 148, 112), M(224, 168, 128), M(236, 188, 148), M( 80, 28, 4), M(100, 40, 20), M(120, 56, 40), M(140, 76, 64), M(160, 100, 96), M(184, 136, 136), M( 36, 40, 68), M( 48, 52, 84), M( 64, 64, 100), M( 80, 80, 116), M(100, 100, 136), M(132, 132, 164), M(172, 172, 192), M(212, 212, 224), M( 40, 20, 112), M( 64, 44, 144), M( 88, 64, 172), M(104, 76, 196), M(120, 88, 224), M(140, 104, 252), M(160, 136, 252), M(188, 168, 252), M( 0, 24, 108), M( 0, 36, 132), M( 0, 52, 160), M( 0, 72, 184), M( 0, 96, 212), M( 24, 120, 220), M( 56, 144, 232), M( 88, 168, 240), M(128, 196, 252), M(188, 224, 252), M( 16, 64, 96), M( 24, 80, 108), M( 40, 96, 120), M( 52, 112, 132), M( 80, 140, 160), M(116, 172, 192), M(156, 204, 220), M(204, 240, 252), M(172, 52, 52), M(212, 52, 52), M(252, 52, 52), M(252, 100, 88), M(252, 144, 124), M(252, 184, 160), M(252, 216, 200), M(252, 244, 236), M( 72, 20, 112), M( 92, 44, 140), M(112, 68, 168), M(140, 100, 196), M(168, 136, 224), M(204, 180, 252), M(204, 180, 252), M(232, 208, 252), M( 60, 0, 0), M( 92, 0, 0), M(128, 0, 0), M(160, 0, 0), M(196, 0, 0), M(224, 0, 0), M(252, 0, 0), M(252, 80, 0), M(252, 108, 0), M(252, 136, 0), M(252, 164, 0), M(252, 192, 0), M(252, 220, 0), M(252, 252, 0), M(204, 136, 8), M(228, 144, 4), M(252, 156, 0), M(252, 176, 48), M(252, 196, 100), M(252, 216, 152), M( 8, 24, 88), M( 12, 36, 104), M( 20, 52, 124), M( 28, 68, 140), M( 40, 92, 164), M( 56, 120, 188), M( 72, 152, 216), M(100, 172, 224), M( 92, 156, 52), M(108, 176, 64), M(124, 200, 76), M(144, 224, 92), M(224, 244, 252), M(204, 240, 252), M(180, 220, 236), M(132, 188, 216), M( 88, 152, 172), /* unused pink */ M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), M(212, 0, 212), /* Palette animated colours (filled with data from #ExtraPaletteValues) */ M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0), /* pure white */ M(252, 252, 252) }, 0, // First dirty 256 // Dirty count }; /** Description of the length of the palette cycle animations */ static const uint EPV_CYCLES_DARK_WATER = 5; ///< length of the dark blue water animation static const uint EPV_CYCLES_LIGHTHOUSE = 4; ///< length of the lighthouse/stadium animation static const uint EPV_CYCLES_OIL_REFINERY = 7; ///< length of the oil refinery's fire animation static const uint EPV_CYCLES_FIZZY_DRINK = 5; ///< length of the fizzy drinks animation static const uint EPV_CYCLES_GLITTER_WATER = 15; ///< length of the glittery water animation /** Description of tables for the palette animation */ struct ExtraPaletteValues { Colour dark_water[EPV_CYCLES_DARK_WATER]; ///< dark blue water Colour dark_water_toyland[EPV_CYCLES_DARK_WATER]; ///< dark blue water Toyland Colour lighthouse[EPV_CYCLES_LIGHTHOUSE]; ///< lighthouse & stadium Colour oil_refinery[EPV_CYCLES_OIL_REFINERY]; ///< oil refinery Colour fizzy_drink[EPV_CYCLES_FIZZY_DRINK]; ///< fizzy drinks Colour glitter_water[EPV_CYCLES_GLITTER_WATER]; ///< glittery water Colour glitter_water_toyland[EPV_CYCLES_GLITTER_WATER]; ///< glittery water Toyland }; /** Actual palette animation tables */ static const ExtraPaletteValues _extra_palette_values = { /* dark blue water */ { M( 32, 68, 112), M( 36, 72, 116), M( 40, 76, 120), M( 44, 80, 124), M( 48, 84, 128) }, /* dark blue water Toyland */ { M( 28, 108, 124), M( 32, 112, 128), M( 36, 116, 132), M( 40, 120, 136), M( 44, 124, 140) }, /* lighthouse & stadium */ { M(240, 208, 0), M( 0, 0, 0), M( 0, 0, 0), M( 0, 0, 0) }, /* oil refinery */ { M(252, 60, 0), M(252, 84, 0), M(252, 108, 0), M(252, 124, 0), M(252, 148, 0), M(252, 172, 0), M(252, 196, 0) }, /* fizzy drinks */ { M( 76, 24, 8), M(108, 44, 24), M(144, 72, 52), M(176, 108, 84), M(212, 148, 128) }, /* glittery water */ { M(216, 244, 252), M(172, 208, 224), M(132, 172, 196), M(100, 132, 168), M( 72, 100, 144), M( 72, 100, 144), M( 72, 100, 144), M( 72, 100, 144), M( 72, 100, 144), M( 72, 100, 144), M( 72, 100, 144), M( 72, 100, 144), M(100, 132, 168), M(132, 172, 196), M(172, 208, 224) }, /* glittery water Toyland */ { M(216, 244, 252), M(180, 220, 232), M(148, 200, 216), M(116, 180, 196), M( 92, 164, 184), M( 92, 164, 184), M( 92, 164, 184), M( 92, 164, 184), M( 92, 164, 184), M( 92, 164, 184), M( 92, 164, 184), M( 92, 164, 184), M(116, 180, 196), M(148, 200, 216), M(180, 220, 232) } }; #undef M /** Colour mapping for the TextColours. */ static const byte _string_colourmap[17] = { 150, // TC_BLUE 12, // TC_SILVER 189, // TC_GOLD 184, // TC_RED 174, // TC_PURPLE 30, // TC_LIGHT_BROWN 195, // TC_ORANGE 209, // TC_GREEN 68, // TC_YELLOW 95, // TC_DARK_GREEN 79, // TC_CREAM 116, // TC_BROWN 15, // TC_WHITE 152, // TC_LIGHT_BLUE 6, // TC_GREY 133, // TC_DARK_BLUE 1, // TC_BLACK }; openttd-1.5.3/src/table/road_land.h0000644000000000000000000001755712627373436015701 0ustar rootroot/* $Id: road_land.h 19056 2010-02-07 22:22:54Z peter1138 $ */ /* * 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 road_land.h Sprite constructs for road depots. */ #define TILE_SEQ_LINE(img, pal, dx, dy, sx, sy) { dx, dy, 0, sx, sy, 20, {img, pal} }, #define TILE_SEQ_END() { (int8)0x80, 0, 0, 0, 0, 0, {0, 0} } static const DrawTileSeqStruct _road_depot_NE[] = { TILE_SEQ_LINE(0x584 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 15, 16, 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _road_depot_SE[] = { TILE_SEQ_LINE(0x580 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 1, 16) TILE_SEQ_LINE(0x581 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 15, 0, 1, 16) TILE_SEQ_END() }; static const DrawTileSeqStruct _road_depot_SW[] = { TILE_SEQ_LINE(0x582 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 1) TILE_SEQ_LINE(0x583 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 15, 16, 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _road_depot_NW[] = { TILE_SEQ_LINE(0x585 | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 15, 0, 1, 16) TILE_SEQ_END() }; static const DrawTileSprites _road_depot[] = { { {0xA4A, PAL_NONE}, _road_depot_NE }, { {0xA4A, PAL_NONE}, _road_depot_SE }, { {0xA4A, PAL_NONE}, _road_depot_SW }, { {0xA4A, PAL_NONE}, _road_depot_NW } }; static const DrawTileSeqStruct _tram_depot_NE[] = { TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x35) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 15, 16, 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _tram_depot_SE[] = { TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x31) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 1, 16) TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x32) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 15, 0, 1, 16) TILE_SEQ_END() }; static const DrawTileSeqStruct _tram_depot_SW[] = { TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x33) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 0, 16, 1) TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x34) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 0, 15, 16, 1) TILE_SEQ_END() }; static const DrawTileSeqStruct _tram_depot_NW[] = { TILE_SEQ_LINE((SPR_TRAMWAY_BASE + 0x36) | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE, 15, 0, 1, 16) TILE_SEQ_END() }; static const DrawTileSprites _tram_depot[] = { { {0xA4A, PAL_NONE}, _tram_depot_NE }, { {0xA4A, PAL_NONE}, _tram_depot_SE }, { {0xA4A, PAL_NONE}, _tram_depot_SW }, { {0xA4A, PAL_NONE}, _tram_depot_NW } }; /* Sprite layout for level crossings. The SpriteIDs are actually offsets * from the base SpriteID returned from the NewGRF sprite resolver. */ static const DrawTileSeqStruct _crossing_layout_ALL[] = { TILE_SEQ_LINE(2, PAL_NONE, 0, 0, 3, 3) TILE_SEQ_LINE(4, PAL_NONE, 0, 13, 3, 3) TILE_SEQ_LINE(6, PAL_NONE, 13, 0, 3, 3) TILE_SEQ_LINE(8, PAL_NONE, 13, 13, 3, 3) TILE_SEQ_END() }; static const DrawTileSprites _crossing_layout = { {0, PAL_NONE}, _crossing_layout_ALL }; #undef TILE_SEQ_LINE #undef TILE_SEQ_END static const SpriteID _road_tile_sprites_1[16] = { 0, 0x546, 0x545, 0x53B, 0x544, 0x534, 0x53E, 0x539, 0x543, 0x53C, 0x535, 0x538, 0x53D, 0x537, 0x53A, 0x536 }; static const SpriteID _road_frontwire_sprites_1[16] = { 0, 0x54, 0x55, 0x5B, 0x54, 0x54, 0x5E, 0x5A, 0x55, 0x5C, 0x55, 0x58, 0x5D, 0x57, 0x59, 0x56 }; static const SpriteID _road_backpole_sprites_1[16] = { 0, 0x38, 0x39, 0x40, 0x38, 0x38, 0x43, 0x3E, 0x39, 0x41, 0x39, 0x3C, 0x42, 0x3B, 0x3D, 0x3A }; #define MAKELINE(a, b, c) { a, b, c }, #define ENDLINE { 0, 0, 0 } static const DrawRoadTileStruct _roadside_nothing[] = { ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_3[] = { MAKELINE(0x57f, 1, 8) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_5[] = { MAKELINE(0x57f, 1, 8) MAKELINE(0x57e, 14, 8) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_6[] = { MAKELINE(0x57e, 8, 1) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_7[] = { MAKELINE(0x57f, 1, 8) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_9[] = { MAKELINE(0x57f, 8, 14) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_10[] = { MAKELINE(0x57f, 8, 14) MAKELINE(0x57e, 8, 1) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_11[] = { MAKELINE(0x57f, 8, 14) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_12[] = { MAKELINE(0x57e, 8, 1) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_13[] = { MAKELINE(0x57e, 14, 8) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_14[] = { MAKELINE(0x57e, 8, 1) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_19[] = { MAKELINE(0x1212, 0, 2) MAKELINE(0x1212, 3, 9) MAKELINE(0x1212, 10, 12) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_21[] = { MAKELINE(0x1212, 0, 2) MAKELINE(0x1212, 0, 10) MAKELINE(0x1212, 12, 2) MAKELINE(0x1212, 12, 10) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_22[] = { MAKELINE(0x1212, 10, 0) MAKELINE(0x1212, 3, 3) MAKELINE(0x1212, 0, 10) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_23[] = { MAKELINE(0x1212, 0, 2) MAKELINE(0x1212, 0, 10) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_25[] = { MAKELINE(0x1212, 12, 2) MAKELINE(0x1212, 9, 9) MAKELINE(0x1212, 2, 12) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_26[] = { MAKELINE(0x1212, 2, 0) MAKELINE(0x1212, 10, 0) MAKELINE(0x1212, 2, 12) MAKELINE(0x1212, 10, 12) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_27[] = { MAKELINE(0x1212, 2, 12) MAKELINE(0x1212, 10, 12) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_28[] = { MAKELINE(0x1212, 2, 0) MAKELINE(0x1212, 9, 3) MAKELINE(0x1212, 12, 10) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_29[] = { MAKELINE(0x1212, 12, 2) MAKELINE(0x1212, 12, 10) ENDLINE }; static const DrawRoadTileStruct _road_display_datas2_30[] = { MAKELINE(0x1212, 2, 0) MAKELINE(0x1212, 10, 0) ENDLINE }; #undef MAKELINE #undef ENDLINE static const DrawRoadTileStruct * const _roadside_none[] = { _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing, _roadside_nothing }; static const DrawRoadTileStruct * const _roadside_lamps[] = { _roadside_nothing, _roadside_nothing, _roadside_nothing, _road_display_datas2_3, _roadside_nothing, _road_display_datas2_5, _road_display_datas2_6, _road_display_datas2_7, _roadside_nothing, _road_display_datas2_9, _road_display_datas2_10, _road_display_datas2_11, _road_display_datas2_12, _road_display_datas2_13, _road_display_datas2_14, _roadside_nothing, }; static const DrawRoadTileStruct * const _roadside_trees[] = { _roadside_nothing, _roadside_nothing, _roadside_nothing, _road_display_datas2_19, _roadside_nothing, _road_display_datas2_21, _road_display_datas2_22, _road_display_datas2_23, _roadside_nothing, _road_display_datas2_25, _road_display_datas2_26, _road_display_datas2_27, _road_display_datas2_28, _road_display_datas2_29, _road_display_datas2_30, _roadside_nothing, }; static const DrawRoadTileStruct * const * const _road_display_table[] = { _roadside_none, _roadside_none, _roadside_none, _roadside_lamps, _roadside_none, _roadside_trees, }; openttd-1.5.3/src/table/build_industry.h0000644000000000000000000021467012627373436017011 0ustar rootroot/* $Id: build_industry.h 27137 2015-02-06 21:54:19Z frosch $ */ /* * 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 build_industry.h Tables with default industry layouts and behaviours. */ #ifndef BUILD_INDUSTRY_H #define BUILD_INDUSTRY_H /** * Definition of an industry tiles layout. * @param x offset x of this tile * @param y offset y of this tile * @param m index of the tile. * @see _industry_specs * @see IndustryTileTable */ #define MK(x, y, m) {{x, y}, m} /** * Terminator of industry tiles layout definition */ #define MKEND {{-0x80, 0}, 0} static const IndustryTileTable _tile_table_coal_mine_0[] = { MK(1, 1, 0), MK(1, 2, 2), MK(0, 0, 5), MK(1, 0, 6), MK(2, 0, 3), MK(2, 2, 3), MKEND }; static const IndustryTileTable _tile_table_coal_mine_1[] = { MK(1, 1, 0), MK(1, 2, 2), MK(2, 0, 0), MK(2, 1, 2), MK(1, 0, 3), MK(0, 0, 3), MK(0, 1, 4), MK(0, 2, 4), MK(2, 2, 4), MKEND }; static const IndustryTileTable _tile_table_coal_mine_2[] = { MK(0, 0, 0), MK(0, 1, 2), MK(0, 2, 5), MK(1, 0, 3), MK(1, 1, 3), MK(1, 2, 6), MKEND }; static const IndustryTileTable _tile_table_coal_mine_3[] = { MK(0, 1, 0), MK(0, 2, 2), MK(0, 3, 4), MK(1, 0, 5), MK(1, 1, 0), MK(1, 2, 2), MK(1, 3, 3), MK(2, 0, 6), MK(2, 1, 4), MK(2, 2, 3), MKEND }; static const IndustryTileTable * const _tile_table_coal_mine[] = { _tile_table_coal_mine_0, _tile_table_coal_mine_1, _tile_table_coal_mine_2, _tile_table_coal_mine_3, }; static const IndustryTileTable _tile_table_power_station_0[] = { MK(0, 0, 7), MK(0, 1, 9), MK(1, 0, 7), MK(1, 1, 8), MK(2, 0, 7), MK(2, 1, 8), MK(3, 0, 10), MK(3, 1, 10), MKEND }; static const IndustryTileTable _tile_table_power_station_1[] = { MK(0, 1, 7), MK(0, 2, 7), MK(1, 0, 8), MK(1, 1, 8), MK(1, 2, 7), MK(2, 0, 9), MK(2, 1, 10), MK(2, 2, 9), MKEND }; static const IndustryTileTable _tile_table_power_station_2[] = { MK(0, 0, 7), MK(0, 1, 7), MK(1, 0, 9), MK(1, 1, 8), MK(2, 0, 10), MK(2, 1, 9), MKEND }; static const IndustryTileTable * const _tile_table_power_station[] = { _tile_table_power_station_0, _tile_table_power_station_1, _tile_table_power_station_2, }; static const IndustryTileTable _tile_table_sawmill_0[] = { MK(1, 0, 14), MK(1, 1, 12), MK(1, 2, 11), MK(2, 0, 14), MK(2, 1, 13), MK(0, 0, 15), MK(0, 1, 15), MK(0, 2, 12), MKEND }; static const IndustryTileTable _tile_table_sawmill_1[] = { MK(0, 0, 15), MK(0, 1, 11), MK(0, 2, 14), MK(1, 0, 15), MK(1, 1, 13), MK(1, 2, 12), MK(2, 0, 11), MK(2, 1, 13), MKEND }; static const IndustryTileTable * const _tile_table_sawmill[] = { _tile_table_sawmill_0, _tile_table_sawmill_1, }; static const IndustryTileTable _tile_table_forest_0[] = { MK(0, 0, 16), MK(0, 1, 16), MK(0, 2, 16), MK(0, 3, 16), MK(1, 0, 16), MK(1, 1, 16), MK(1, 2, 16), MK(1, 3, 16), MK(2, 0, 16), MK(2, 1, 16), MK(2, 2, 16), MK(2, 3, 16), MK(3, 0, 16), MK(3, 1, 16), MK(3, 2, 16), MK(3, 3, 16), MK(1, 4, 16), MK(2, 4, 16), MKEND }; static const IndustryTileTable _tile_table_forest_1[] = { MK(0, 0, 16), MK(1, 0, 16), MK(2, 0, 16), MK(3, 0, 16), MK(4, 0, 16), MK(0, 1, 16), MK(1, 1, 16), MK(2, 1, 16), MK(3, 1, 16), MK(4, 1, 16), MK(0, 2, 16), MK(1, 2, 16), MK(2, 2, 16), MK(3, 2, 16), MK(4, 2, 16), MK(0, 3, 16), MK(1, 3, 16), MK(2, 3, 16), MK(3, 3, 16), MK(4, 3, 16), MK(1, 4, 16), MK(2, 4, 16), MK(3, 4, 16), MKEND }; static const IndustryTileTable * const _tile_table_forest[] = { _tile_table_forest_0, _tile_table_forest_1, }; static const IndustryTileTable _tile_table_oil_refinery_0[] = { MK(0, 0, 20), MK(0, 1, 21), MK(0, 2, 22), MK(0, 3, 21), MK(1, 0, 20), MK(1, 1, 19), MK(1, 2, 22), MK(1, 3, 20), MK(2, 1, 18), MK(2, 2, 18), MK(2, 3, 18), MK(3, 2, 18), MK(3, 3, 18), MK(2, 0, 23), MK(3, 1, 23), MKEND }; static const IndustryTileTable _tile_table_oil_refinery_1[] = { MK(0, 0, 18), MK(0, 1, 18), MK(0, 2, 21), MK(0, 3, 22), MK(0, 4, 20), MK(1, 0, 18), MK(1, 1, 18), MK(1, 2, 19), MK(1, 3, 20), MK(2, 0, 18), MK(2, 1, 18), MK(2, 2, 19), MK(2, 3, 22), MK(1, 4, 23), MK(2, 4, 23), MKEND }; static const IndustryTileTable * const _tile_table_oil_refinery[] = { _tile_table_oil_refinery_0, _tile_table_oil_refinery_1, }; static const IndustryTileTable _tile_table_oil_rig_0[] = { MK(0, 0, 24), MK(0, 1, 24), MK(0, 2, 25), MK(1, 0, 26), MK(1, 1, 27), MK(1, 2, 28), MK(-4, -4, 255), MK(-4, -3, 255), MK(-4, -2, 255), MK(-4, -1, 255), MK(-4, 0, 255), MK(-4, 1, 255), MK(-4, 2, 255), MK(-4, 3, 255), MK(-4, 4, 255), MK(-4, 5, 255), MK(-4, 6, 255), MK(-3, 6, 255), MK(-2, 6, 255), MK(-1, 6, 255), MK(0, 6, 255), MK(1, 6, 255), MK(2, 6, 255), MK(3, 6, 255), MK(4, 6, 255), MK(5, 6, 255), MK(5, 5, 255), MK(5, 4, 255), MK(5, 3, 255), MK(5, 2, 255), MK(5, 1, 255), MK(5, 0, 255), MK(5, -1, 255), MK(5, -2, 255), MK(5, -3, 255), MK(5, -4, 255), MK(4, -4, 255), MK(3, -4, 255), MK(2, -4, 255), MK(1, -4, 255), MK(0, -4, 255), MK(-1, -4, 255), MK(-2, -4, 255), MK(-3, -4, 255), MK(2, 0, 255), MKEND }; static const IndustryTileTable * const _tile_table_oil_rig[] = { _tile_table_oil_rig_0, }; static const IndustryTileTable _tile_table_factory_0[] = { MK(0, 0, 39), MK(0, 1, 40), MK(1, 0, 41), MK(1, 1, 42), MK(0, 2, 39), MK(0, 3, 40), MK(1, 2, 41), MK(1, 3, 42), MK(2, 1, 39), MK(2, 2, 40), MK(3, 1, 41), MK(3, 2, 42), MKEND }; static const IndustryTileTable _tile_table_factory_1[] = { MK(0, 0, 39), MK(0, 1, 40), MK(1, 0, 41), MK(1, 1, 42), MK(2, 0, 39), MK(2, 1, 40), MK(3, 0, 41), MK(3, 1, 42), MK(1, 2, 39), MK(1, 3, 40), MK(2, 2, 41), MK(2, 3, 42), MKEND }; static const IndustryTileTable * const _tile_table_factory[] = { _tile_table_factory_0, _tile_table_factory_1, }; static const IndustryTileTable _tile_table_printing_works_0[] = { MK(0, 0, 43), MK(0, 1, 44), MK(1, 0, 45), MK(1, 1, 46), MK(0, 2, 43), MK(0, 3, 44), MK(1, 2, 45), MK(1, 3, 46), MK(2, 1, 43), MK(2, 2, 44), MK(3, 1, 45), MK(3, 2, 46), MKEND }; static const IndustryTileTable _tile_table_printing_works_1[] = { MK(0, 0, 43), MK(0, 1, 44), MK(1, 0, 45), MK(1, 1, 46), MK(2, 0, 43), MK(2, 1, 44), MK(3, 0, 45), MK(3, 1, 46), MK(1, 2, 43), MK(1, 3, 44), MK(2, 2, 45), MK(2, 3, 46), MKEND }; static const IndustryTileTable * const _tile_table_printing_works[] = { _tile_table_printing_works_0, _tile_table_printing_works_1, }; static const IndustryTileTable _tile_table_steel_mill_0[] = { MK(2, 1, 52), MK(2, 2, 53), MK(3, 1, 54), MK(3, 2, 55), MK(0, 0, 56), MK(1, 0, 57), MK(0, 1, 56), MK(1, 1, 57), MK(0, 2, 56), MK(1, 2, 57), MK(2, 0, 56), MK(3, 0, 57), MKEND }; static const IndustryTileTable _tile_table_steel_mill_1[] = { MK(0, 0, 52), MK(0, 1, 53), MK(1, 0, 54), MK(1, 1, 55), MK(2, 0, 52), MK(2, 1, 53), MK(3, 0, 54), MK(3, 1, 55), MK(0, 2, 56), MK(1, 2, 57), MK(2, 2, 56), MK(3, 2, 57), MK(1, 3, 56), MK(2, 3, 57), MKEND }; static const IndustryTileTable * const _tile_table_steel_mill[] = { _tile_table_steel_mill_0, _tile_table_steel_mill_1, }; static const IndustryTileTable _tile_table_farm_0[] = { MK(1, 0, 33), MK(1, 1, 34), MK(1, 2, 36), MK(0, 0, 37), MK(0, 1, 37), MK(0, 2, 36), MK(2, 0, 35), MK(2, 1, 38), MK(2, 2, 38), MKEND }; static const IndustryTileTable _tile_table_farm_1[] = { MK(1, 1, 33), MK(1, 2, 34), MK(0, 0, 35), MK(0, 1, 36), MK(0, 2, 36), MK(0, 3, 35), MK(1, 0, 37), MK(1, 3, 38), MK(2, 0, 37), MK(2, 1, 37), MK(2, 2, 38), MK(2, 3, 38), MKEND }; static const IndustryTileTable _tile_table_farm_2[] = { MK(2, 0, 33), MK(2, 1, 34), MK(0, 0, 36), MK(0, 1, 36), MK(0, 2, 37), MK(0, 3, 37), MK(1, 0, 35), MK(1, 1, 38), MK(1, 2, 38), MK(1, 3, 37), MK(2, 2, 37), MK(2, 3, 35), MKEND }; static const IndustryTileTable * const _tile_table_farm[] = { _tile_table_farm_0, _tile_table_farm_1, _tile_table_farm_2, }; static const IndustryTileTable _tile_table_copper_mine_0[] = { MK(0, 0, 47), MK(0, 1, 49), MK(0, 2, 51), MK(1, 0, 47), MK(1, 1, 49), MK(1, 2, 50), MK(2, 0, 51), MK(2, 1, 51), MKEND }; static const IndustryTileTable _tile_table_copper_mine_1[] = { MK(0, 0, 50), MK(0, 1, 47), MK(0, 2, 49), MK(1, 0, 47), MK(1, 1, 49), MK(1, 2, 51), MK(2, 0, 51), MK(2, 1, 47), MK(2, 2, 49), MKEND }; static const IndustryTileTable * const _tile_table_copper_mine[] = { _tile_table_copper_mine_0, _tile_table_copper_mine_1, }; static const IndustryTileTable _tile_table_oil_well_0[] = { MK(0, 0, 29), MK(1, 0, 29), MK(2, 0, 29), MK(0, 1, 29), MK(0, 2, 29), MKEND }; static const IndustryTileTable _tile_table_oil_well_1[] = { MK(0, 0, 29), MK(1, 0, 29), MK(1, 1, 29), MK(2, 2, 29), MK(2, 3, 29), MKEND }; static const IndustryTileTable * const _tile_table_oil_well[] = { _tile_table_oil_well_0, _tile_table_oil_well_1, }; static const IndustryTileTable _tile_table_bank_0[] = { MK(0, 0, 58), MK(1, 0, 59), MKEND }; static const IndustryTileTable * const _tile_table_bank[] = { _tile_table_bank_0, }; static const IndustryTileTable _tile_table_food_process_0[] = { MK(0, 0, 60), MK(1, 0, 60), MK(2, 0, 60), MK(0, 1, 60), MK(1, 1, 60), MK(2, 1, 60), MK(0, 2, 61), MK(1, 2, 61), MK(2, 2, 63), MK(0, 3, 62), MK(1, 3, 62), MK(2, 3, 63), MKEND }; static const IndustryTileTable _tile_table_food_process_1[] = { MK(0, 0, 61), MK(1, 0, 60), MK(2, 0, 61), MK(3, 0, 61), MK(0, 1, 62), MK(1, 1, 63), MK(2, 1, 63), MK(3, 1, 63), MK(0, 2, 60), MK(1, 2, 60), MK(2, 2, 60), MK(3, 2, 60), MK(0, 3, 62), MK(1, 3, 62), MKEND }; static const IndustryTileTable * const _tile_table_food_process[] = { _tile_table_food_process_0, _tile_table_food_process_1, }; static const IndustryTileTable _tile_table_paper_mill_0[] = { MK(0, 0, 64), MK(1, 0, 65), MK(2, 0, 66), MK(3, 0, 67), MK(0, 1, 68), MK(1, 1, 69), MK(2, 1, 67), MK(3, 1, 67), MK(0, 2, 66), MK(1, 2, 71), MK(2, 2, 71), MK(3, 2, 70), MKEND }; static const IndustryTileTable * const _tile_table_paper_mill[] = { _tile_table_paper_mill_0, }; static const IndustryTileTable _tile_table_gold_mine_0[] = { MK(0, 0, 72), MK(0, 1, 73), MK(0, 2, 74), MK(0, 3, 75), MK(1, 0, 76), MK(1, 1, 77), MK(1, 2, 78), MK(1, 3, 79), MK(2, 0, 80), MK(2, 1, 81), MK(2, 2, 82), MK(2, 3, 83), MK(3, 0, 84), MK(3, 1, 85), MK(3, 2, 86), MK(3, 3, 87), MKEND }; static const IndustryTileTable * const _tile_table_gold_mine[] = { _tile_table_gold_mine_0, }; static const IndustryTileTable _tile_table_bank2_0[] = { MK(0, 0, 89), MK(1, 0, 90), MKEND }; static const IndustryTileTable * const _tile_table_bank2[] = { _tile_table_bank2_0, }; static const IndustryTileTable _tile_table_diamond_mine_0[] = { MK(0, 0, 91), MK(0, 1, 92), MK(0, 2, 93), MK(1, 0, 94), MK(1, 1, 95), MK(1, 2, 96), MK(2, 0, 97), MK(2, 1, 98), MK(2, 2, 99), MKEND }; static const IndustryTileTable * const _tile_table_diamond_mine[] = { _tile_table_diamond_mine_0, }; static const IndustryTileTable _tile_table_iron_mine_0[] = { MK(0, 0, 100), MK(0, 1, 101), MK(0, 2, 102), MK(0, 3, 103), MK(1, 0, 104), MK(1, 1, 105), MK(1, 2, 106), MK(1, 3, 107), MK(2, 0, 108), MK(2, 1, 109), MK(2, 2, 110), MK(2, 3, 111), MK(3, 0, 112), MK(3, 1, 113), MK(3, 2, 114), MK(3, 3, 115), MKEND }; static const IndustryTileTable * const _tile_table_iron_mine[] = { _tile_table_iron_mine_0, }; static const IndustryTileTable _tile_table_fruit_plantation_0[] = { MK(0, 0, 116), MK(0, 1, 116), MK(0, 2, 116), MK(0, 3, 116), MK(1, 0, 116), MK(1, 1, 116), MK(1, 2, 116), MK(1, 3, 116), MK(2, 0, 116), MK(2, 1, 116), MK(2, 2, 116), MK(2, 3, 116), MK(3, 0, 116), MK(3, 1, 116), MK(3, 2, 116), MK(3, 3, 116), MK(4, 0, 116), MK(4, 1, 116), MK(4, 2, 116), MK(4, 3, 116), MKEND }; static const IndustryTileTable * const _tile_table_fruit_plantation[] = { _tile_table_fruit_plantation_0, }; static const IndustryTileTable _tile_table_rubber_plantation_0[] = { MK(0, 0, 117), MK(0, 1, 117), MK(0, 2, 117), MK(0, 3, 117), MK(1, 0, 117), MK(1, 1, 117), MK(1, 2, 117), MK(1, 3, 117), MK(2, 0, 117), MK(2, 1, 117), MK(2, 2, 117), MK(2, 3, 117), MK(3, 0, 117), MK(3, 1, 117), MK(3, 2, 117), MK(3, 3, 117), MK(4, 0, 117), MK(4, 1, 117), MK(4, 2, 117), MK(4, 3, 117), MKEND }; static const IndustryTileTable * const _tile_table_rubber_plantation[] = { _tile_table_rubber_plantation_0, }; static const IndustryTileTable _tile_table_water_supply_0[] = { MK(0, 0, 118), MK(0, 1, 119), MK(1, 0, 118), MK(1, 1, 119), MKEND }; static const IndustryTileTable * const _tile_table_water_supply[] = { _tile_table_water_supply_0, }; static const IndustryTileTable _tile_table_water_tower_0[] = { MK(0, 0, 120), MKEND }; static const IndustryTileTable * const _tile_table_water_tower[] = { _tile_table_water_tower_0, }; static const IndustryTileTable _tile_table_factory2_0[] = { MK(0, 0, 121), MK(0, 1, 122), MK(1, 0, 123), MK(1, 1, 124), MK(0, 2, 121), MK(0, 3, 122), MK(1, 2, 123), MK(1, 3, 124), MKEND }; static const IndustryTileTable _tile_table_factory2_1[] = { MK(0, 0, 121), MK(0, 1, 122), MK(1, 0, 123), MK(1, 1, 124), MK(2, 0, 121), MK(2, 1, 122), MK(3, 0, 123), MK(3, 1, 124), MKEND }; static const IndustryTileTable * const _tile_table_factory2[] = { _tile_table_factory2_0, _tile_table_factory2_1, }; static const IndustryTileTable _tile_table_farm2_0[] = { MK(1, 0, 33), MK(1, 1, 34), MK(1, 2, 36), MK(0, 0, 37), MK(0, 1, 37), MK(0, 2, 36), MK(2, 0, 35), MK(2, 1, 38), MK(2, 2, 38), MKEND }; static const IndustryTileTable _tile_table_farm2_1[] = { MK(1, 1, 33), MK(1, 2, 34), MK(0, 0, 35), MK(0, 1, 36), MK(0, 2, 36), MK(0, 3, 35), MK(1, 0, 37), MK(1, 3, 38), MK(2, 0, 37), MK(2, 1, 37), MK(2, 2, 38), MK(2, 3, 38), MKEND }; static const IndustryTileTable _tile_table_farm2_2[] = { MK(2, 0, 33), MK(2, 1, 34), MK(0, 0, 36), MK(0, 1, 36), MK(0, 2, 37), MK(0, 3, 37), MK(1, 0, 35), MK(1, 1, 38), MK(1, 2, 38), MK(1, 3, 37), MK(2, 2, 37), MK(2, 3, 35), MKEND }; static const IndustryTileTable * const _tile_table_farm2[] = { _tile_table_farm2_0, _tile_table_farm2_1, _tile_table_farm2_2, }; static const IndustryTileTable _tile_table_lumber_mill_0[] = { MK(0, 0, 125), MK(0, 1, 126), MK(1, 0, 127), MK(1, 1, 128), MKEND }; static const IndustryTileTable * const _tile_table_lumber_mill[] = { _tile_table_lumber_mill_0, }; static const IndustryTileTable _tile_table_cotton_candy_0[] = { MK(0, 0, 129), MK(0, 1, 129), MK(0, 2, 129), MK(0, 3, 129), MK(1, 0, 129), MK(1, 1, 129), MK(1, 2, 129), MK(1, 3, 129), MK(2, 0, 129), MK(2, 1, 129), MK(2, 2, 129), MK(2, 3, 129), MK(3, 0, 129), MK(3, 1, 129), MK(3, 2, 129), MK(3, 3, 129), MK(1, 4, 129), MK(2, 4, 129), MKEND }; static const IndustryTileTable _tile_table_cotton_candy_1[] = { MK(0, 0, 129), MK(1, 0, 129), MK(2, 0, 129), MK(3, 0, 129), MK(4, 0, 129), MK(0, 1, 129), MK(1, 1, 129), MK(2, 1, 129), MK(3, 1, 129), MK(4, 1, 129), MK(0, 2, 129), MK(1, 2, 129), MK(2, 2, 129), MK(3, 2, 129), MK(4, 2, 129), MK(0, 3, 129), MK(1, 3, 129), MK(2, 3, 129), MK(3, 3, 129), MK(4, 3, 129), MK(1, 4, 129), MK(2, 4, 129), MK(3, 4, 129), MKEND }; static const IndustryTileTable * const _tile_table_cotton_candy[] = { _tile_table_cotton_candy_0, _tile_table_cotton_candy_1, }; static const IndustryTileTable _tile_table_candy_factory_0[] = { MK(0, 0, 131), MK(0, 1, 132), MK(1, 0, 133), MK(1, 1, 134), MK(0, 2, 131), MK(0, 3, 132), MK(1, 2, 133), MK(1, 3, 134), MK(2, 1, 131), MK(2, 2, 132), MK(3, 1, 133), MK(3, 2, 134), MKEND }; static const IndustryTileTable _tile_table_candy_factory_1[] = { MK(0, 0, 131), MK(0, 1, 132), MK(1, 0, 133), MK(1, 1, 134), MK(2, 0, 131), MK(2, 1, 132), MK(3, 0, 133), MK(3, 1, 134), MK(1, 2, 131), MK(1, 3, 132), MK(2, 2, 133), MK(2, 3, 134), MKEND }; static const IndustryTileTable * const _tile_table_candy_factory[] = { _tile_table_candy_factory_0, _tile_table_candy_factory_1, }; static const IndustryTileTable _tile_table_battery_farm_0[] = { MK(0, 0, 135), MK(0, 1, 135), MK(0, 2, 135), MK(0, 3, 135), MK(1, 0, 135), MK(1, 1, 135), MK(1, 2, 135), MK(1, 3, 135), MK(2, 0, 135), MK(2, 1, 135), MK(2, 2, 135), MK(2, 3, 135), MK(3, 0, 135), MK(3, 1, 135), MK(3, 2, 135), MK(3, 3, 135), MK(4, 0, 135), MK(4, 1, 135), MK(4, 2, 135), MK(4, 3, 135), MKEND }; static const IndustryTileTable * const _tile_table_battery_farm[] = { _tile_table_battery_farm_0, }; static const IndustryTileTable _tile_table_cola_wells_0[] = { MK(0, 0, 137), MK(0, 1, 137), MK(0, 2, 137), MK(1, 0, 137), MK(1, 1, 137), MK(1, 2, 137), MK(2, 1, 137), MK(2, 2, 137), MKEND }; static const IndustryTileTable _tile_table_cola_wells_1[] = { MK(0, 1, 137), MK(0, 2, 137), MK(0, 3, 137), MK(1, 0, 137), MK(1, 1, 137), MK(1, 2, 137), MK(2, 1, 137), MKEND }; static const IndustryTileTable * const _tile_table_cola_wells[] = { _tile_table_cola_wells_0, _tile_table_cola_wells_1, }; static const IndustryTileTable _tile_table_toy_shop_0[] = { MK(0, 0, 138), MK(0, 1, 139), MK(1, 0, 140), MK(1, 1, 141), MKEND }; static const IndustryTileTable * const _tile_table_toy_shop[] = { _tile_table_toy_shop_0, }; static const IndustryTileTable _tile_table_toy_factory_0[] = { MK(0, 0, 147), MK(0, 1, 142), MK(1, 0, 147), MK(1, 1, 143), MK(2, 0, 147), MK(2, 1, 144), MK(3, 0, 146), MK(3, 1, 145), MKEND }; static const IndustryTileTable * const _tile_table_toy_factory[] = { _tile_table_toy_factory_0, }; static const IndustryTileTable _tile_table_plastic_fountain_0[] = { MK(0, 0, 148), MK(0, 1, 151), MK(0, 2, 154), MKEND }; static const IndustryTileTable _tile_table_plastic_fountain_1[] = { MK(0, 0, 148), MK(1, 0, 151), MK(2, 0, 154), MKEND }; static const IndustryTileTable * const _tile_table_plastic_fountain[] = { _tile_table_plastic_fountain_0, _tile_table_plastic_fountain_1, }; static const IndustryTileTable _tile_table_fizzy_drink_0[] = { MK(0, 0, 156), MK(0, 1, 157), MK(1, 0, 158), MK(1, 1, 159), MKEND }; static const IndustryTileTable * const _tile_table_fizzy_drink[] = { _tile_table_fizzy_drink_0, }; static const IndustryTileTable _tile_table_bubble_generator_0[] = { MK(0, 0, 163), MK(0, 1, 160), MK(1, 0, 163), MK(1, 1, 161), MK(2, 0, 163), MK(2, 1, 162), MK(0, 2, 163), MK(0, 3, 160), MK(1, 2, 163), MK(1, 3, 161), MK(2, 2, 163), MK(2, 3, 162), MKEND }; static const IndustryTileTable * const _tile_table_bubble_generator[] = { _tile_table_bubble_generator_0, }; static const IndustryTileTable _tile_table_toffee_quarry_0[] = { MK(0, 0, 164), MK(1, 0, 165), MK(2, 0, 166), MKEND }; static const IndustryTileTable * const _tile_table_toffee_quarry[] = { _tile_table_toffee_quarry_0, }; static const IndustryTileTable _tile_table_sugar_mine_0[] = { MK(0, 0, 167), MK(0, 1, 168), MK(1, 0, 169), MK(1, 1, 170), MK(2, 0, 171), MK(2, 1, 172), MK(3, 0, 173), MK(3, 1, 174), MKEND }; static const IndustryTileTable * const _tile_table_sugar_mine[] = { _tile_table_sugar_mine_0, }; #undef MK #undef MKEND /** Array with saw sound, for sawmill */ static const uint8 _sawmill_sounds[] = { SND_28_SAWMILL }; /** Array with whistle sound, for factory */ static const uint8 _factory_sounds[] = { SND_03_FACTORY_WHISTLE }; /** Array with 3 animal sounds, for farms */ static const uint8 _farm_sounds[] = { SND_24_SHEEP, SND_25_COW, SND_26_HORSE }; /** Array with... hem... a sound of toyland */ static const uint8 _plastic_mine_sounds[] = { SND_33_PLASTIC_MINE }; enum IndustryTypes { IT_COAL_MINE = 0, IT_POWER_STATION = 1, IT_SAWMILL = 2, IT_FOREST = 3, IT_OIL_REFINERY = 4, IT_OIL_RIG = 5, IT_FACTORY = 6, IT_PRINTING_WORKS = 7, IT_STEEL_MILL = 8, IT_FARM = 9, IT_COPPER_MINE = 10, IT_OIL_WELL = 11, IT_BANK_TEMP = 12, IT_FOOD_PROCESS = 13, IT_PAPER_MILL = 14, IT_GOLD_MINE = 15, IT_BANK_TROPIC_ARCTIC = 16, IT_DIAMOND_MINE = 17, IT_IRON_MINE = 18, IT_FRUIT_PLANTATION = 19, IT_RUBBER_PLANTATION = 20, IT_WATER_SUPPLY = 21, IT_WATER_TOWER = 22, IT_FACTORY_2 = 23, IT_FARM_2 = 24, IT_LUMBER_MILL = 25, IT_COTTON_CANDY = 26, IT_CANDY_FACTORY = 27, IT_BATTERY_FARM = 28, IT_COLA_WELLS = 29, IT_TOY_SHOP = 30, IT_TOY_FACTORY = 31, IT_PLASTIC_FOUNTAINS = 32, IT_FIZZY_DRINK_FACTORY = 33, IT_BUBBLE_GENERATOR = 34, IT_TOFFEE_QUARRY = 35, IT_SUGAR_MINE = 36, IT_END, }; /** * Writes the properties of an industry into the IndustrySpec struct. * @param tbl tile table * @param sndc number of sounds * @param snd sounds table * @param d cost multiplier * @param pc prospecting chance * @param ai1 appear chance ingame - temperate * @param ai2 appear chance ingame - arctic * @param ai3 appear chance ingame - tropic * @param ai4 appear chance ingame - toyland * @param ag1 appear chance random creation - temperate * @param ag2 appear chance random creation - arctic * @param ag3 appear chance random creation - tropic * @param ag4 appear chance random creation - toyland * @param col map colour * @param c1 industry proximity refusal - 1st * @param c2 industry proximity refusal - 2nd * @param c3 industry proximity refusal - 3th * @param proc check procedure index * @param p1 produce cargo 1 * @param r1 rate of production 1 * @param p2 produce cargo 2 * @param r2 rate of production 1 * @param m minimum cargo moved to station * @param a1 accepted cargo 1 * @param im1 input multiplier for cargo 1 * @param a2 accepted cargo 2 * @param im2 input multiplier for cargo 2 * @param a3 accepted cargo 3 * @param im3 input multiplier for cargo 3 * @param pr industry life (actually, the same as extractive, organic, processing in ttdpatch's specs) * @param clim climate availability * @param bev industry behaviour * @param in name * @param intx text while building * @param s1 text for closure * @param s2 text for production up * @param s3 text for production down */ #define MI(tbl, sndc, snd, d, pc, ai1, ai2, ai3, ai4, ag1, ag2, ag3, ag4, col, \ c1, c2, c3, proc, p1, r1, p2, r2, m, a1, im1, a2, im2, a3, im3, pr, clim, bev, in, intx, s1, s2, s3) \ {tbl, lengthof(tbl), d, 0, pc, {c1, c2, c3}, proc, {p1, p2}, {r1, r2}, m, \ {a1, a2, a3}, {{im1, 0}, {im2, 0}, {im3, 0}}, pr, clim, bev, col, in, intx, s1, s2, s3, STR_UNDEFINED, {ai1, ai2, ai3, ai4}, {ag1, ag2, ag3, ag4}, \ sndc, snd, 0, 0, true, GRFFileProps(INVALID_INDUSTRYTYPE)} /* Format: tile table count and sounds table cost multiplier appear chances(4ingame, 4random) map colour cannot be close to these industries (3 times) check proc (produced cargo + rate) (twice) minimum cargo moved to station 3 accepted cargo and their corresponding input multiplier industry life climate availability industry behaviours industry name building text messages : Closure production up production down */ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { MI(_tile_table_coal_mine, 0, NULL, 210, 0xB3333333, 2, 3, 0, 0, 8, 8, 0, 0, 1, IT_POWER_STATION, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COAL, 15, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TEMPERATE | 1 << LT_ARCTIC, INDUSTRYBEH_CAN_SUBSIDENCE, STR_INDUSTRY_NAME_COAL_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_power_station, 0, NULL, 240, 0xFFFFFFFF, 2, 2, 0, 0, 5, 5, 0, 0, 184, IT_COAL_MINE, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_INVALID, 0, CT_INVALID, 0, 5, CT_COAL, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_BLACK_HOLE, 1 << LT_TEMPERATE | 1 << LT_ARCTIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_POWER_STATION, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_sawmill, 1, _sawmill_sounds, 224, 0xFFFFFFFF, 2, 0, 0, 0, 5, 0, 0, 0, 194, IT_FOREST, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_GOODS, 0, CT_INVALID, 0, 5, CT_WOOD, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TEMPERATE, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_SAWMILL, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_forest, 0, NULL, 200, 0xBFFFFFFF, 3, 4, 0, 0, 5, 5, 0, 0, 86, IT_SAWMILL, IT_PAPER_MILL, IT_INVALID, CHECK_FOREST, CT_WOOD, 13, CT_INVALID, 0, 30, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_ORGANIC, 1 << LT_TEMPERATE | 1 << LT_ARCTIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_FOREST, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), MI(_tile_table_oil_refinery, 0, NULL, 244, 0xFFFFFFFF, 2, 2, 2, 0, 4, 4, 4, 0, 191, IT_OIL_RIG, IT_INVALID, IT_INVALID, CHECK_REFINERY, CT_GOODS, 0, CT_INVALID, 0, 5, CT_OIL, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TEMPERATE | 1 << LT_ARCTIC | 1 << LT_TROPIC, INDUSTRYBEH_AIRPLANE_ATTACKS, STR_INDUSTRY_NAME_OIL_REFINERY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_oil_rig, 0, NULL, 240, 0x99999999, 6, 0, 0, 0, 0, 0, 0, 0, 152, IT_OIL_REFINERY, IT_INVALID, IT_INVALID, CHECK_OIL_RIG, CT_OIL, 15, CT_PASSENGERS, 2, 5, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, 0, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TEMPERATE, INDUSTRYBEH_BUILT_ONWATER | INDUSTRYBEH_AFTER_1960 | INDUSTRYBEH_AI_AIRSHIP_ROUTES, STR_INDUSTRY_NAME_OIL_RIG, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_factory, 1, _factory_sounds, 208, 0xFFFFFFFF, 2, 0, 0, 0, 5, 0, 0, 0, 174, IT_FARM, IT_STEEL_MILL, IT_INVALID, CHECK_NOTHING, CT_GOODS, 0, CT_INVALID, 0, 5, CT_LIVESTOCK, 256, CT_GRAIN, 256, CT_STEEL, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TEMPERATE, INDUSTRYBEH_CHOPPER_ATTACKS, STR_INDUSTRY_NAME_FACTORY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_printing_works, 1, _factory_sounds, 208, 0xFFFFFFFF, 0, 2, 0, 0, 0, 5, 0, 0, 174, IT_PAPER_MILL, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_GOODS, 0, CT_INVALID, 0, 5, CT_PAPER, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_ARCTIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_PRINTING_WORKS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_steel_mill, 0, NULL, 215, 0xFFFFFFFF, 2, 0, 0, 0, 5, 0, 0, 0, 10, IT_IRON_MINE, IT_FACTORY, IT_INVALID, CHECK_NOTHING, CT_STEEL, 0, CT_INVALID, 0, 5, CT_IRON_ORE, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TEMPERATE, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_STEEL_MILL, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_farm, 3, _farm_sounds, 250, 0xD9999999, 2, 4, 0, 0, 9, 9, 0, 0, 48, IT_FACTORY, IT_FOOD_PROCESS, IT_INVALID, CHECK_FARM, CT_GRAIN, 10, CT_LIVESTOCK, 10, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_ORGANIC, 1 << LT_TEMPERATE | 1 << LT_ARCTIC, INDUSTRYBEH_PLANT_FIELDS | INDUSTRYBEH_PLANT_ON_BUILT, STR_INDUSTRY_NAME_FARM, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), MI(_tile_table_copper_mine, 0, NULL, 205, 0xB3333333, 0, 0, 3, 0, 0, 0, 4, 0, 10, IT_FACTORY_2, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COPPER_ORE, 10, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TROPIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_COPPER_ORE_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_oil_well, 0, NULL, 220, 0x99999999, 0, 5, 3, 0, 4, 5, 5, 0, 152, IT_OIL_REFINERY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_OIL, 12, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TEMPERATE | 1 << LT_ARCTIC | 1 << LT_TROPIC, INDUSTRYBEH_DONT_INCR_PROD | INDUSTRYBEH_BEFORE_1950, STR_INDUSTRY_NAME_OIL_WELLS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_bank, 0, NULL, 255, 0xA6666666, 7, 0, 0, 0, 0, 0, 0, 0, 15, IT_BANK_TEMP, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_VALUABLES, 6, CT_INVALID, 0, 5, CT_VALUABLES, 0, CT_INVALID, 0, CT_INVALID, 0, INDUSTRYLIFE_BLACK_HOLE, 1 << LT_TEMPERATE, INDUSTRYBEH_TOWN1200_MORE, STR_INDUSTRY_NAME_BANK, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_food_process, 0, NULL, 206, 0xFFFFFFFF, 0, 2, 2, 0, 0, 3, 4, 0, 55, IT_FRUIT_PLANTATION, IT_FARM, IT_FARM_2, CHECK_NOTHING, CT_FOOD, 0, CT_INVALID, 0, 5, CT_FRUIT, 256, CT_MAIZE, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_ARCTIC | 1 << LT_TROPIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_paper_mill, 1, _sawmill_sounds, 227, 0xFFFFFFFF, 0, 2, 0, 0, 0, 5, 0, 0, 10, IT_FOREST, IT_PRINTING_WORKS, IT_INVALID, CHECK_NOTHING, CT_PAPER, 0, CT_INVALID, 0, 5, CT_WOOD, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_ARCTIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_PAPER_MILL, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_gold_mine, 0, NULL, 208, 0x99999999, 0, 3, 0, 0, 0, 4, 0, 0, 194, IT_BANK_TROPIC_ARCTIC, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_GOLD, 7, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_ARCTIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_GOLD_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_bank2, 0, NULL, 151, 0xA6666666, 0, 3, 3, 0, 0, 6, 5, 0, 15, IT_GOLD_MINE, IT_DIAMOND_MINE, IT_INVALID, CHECK_NOTHING, CT_INVALID, 0, CT_INVALID, 0, 5, CT_GOLD, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_BLACK_HOLE, 1 << LT_ARCTIC | 1 << LT_TROPIC, INDUSTRYBEH_ONLY_INTOWN, STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_diamond_mine, 0, NULL, 213, 0x99999999, 0, 0, 3, 0, 0, 0, 4, 0, 184, IT_BANK_TROPIC_ARCTIC, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_DIAMONDS, 7, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TROPIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_DIAMOND_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_iron_mine, 0, NULL, 220, 0xB3333333, 2, 0, 0, 0, 5, 0, 0, 0, 55, IT_STEEL_MILL, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_IRON_ORE, 10, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TEMPERATE, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_IRON_ORE_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_fruit_plantation, 0, NULL, 225, 0xBFFFFFFF, 0, 0, 2, 0, 0, 0, 4, 0, 86, IT_FOOD_PROCESS, IT_INVALID, IT_INVALID, CHECK_PLANTATION, CT_FRUIT, 10, CT_INVALID, 0, 15, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_ORGANIC, 1 << LT_TROPIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_FRUIT_PLANTATION, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), MI(_tile_table_rubber_plantation, 0, NULL, 218, 0xBFFFFFFF, 0, 0, 3, 0, 0, 0, 4, 0, 39, IT_FACTORY_2, IT_INVALID, IT_INVALID, CHECK_PLANTATION, CT_RUBBER, 10, CT_INVALID, 0, 15, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_ORGANIC, 1 << LT_TROPIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_RUBBER_PLANTATION, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), MI(_tile_table_water_supply, 0, NULL, 199, 0xB3333333, 0, 0, 3, 0, 0, 0, 4, 0, 37, IT_WATER_TOWER, IT_INVALID, IT_INVALID, CHECK_WATER, CT_WATER, 12, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TROPIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_WATER_SUPPLY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_water_tower, 0, NULL, 115, 0xFFFFFFFF, 0, 0, 4, 0, 0, 0, 8, 0, 208, IT_WATER_SUPPLY, IT_INVALID, IT_INVALID, CHECK_WATER, CT_INVALID, 0, CT_INVALID, 0, 5, CT_WATER, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_BLACK_HOLE, 1 << LT_TROPIC, INDUSTRYBEH_ONLY_INTOWN, STR_INDUSTRY_NAME_WATER_TOWER, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_factory2, 1, _factory_sounds, 208, 0xFFFFFFFF, 0, 0, 2, 0, 0, 0, 4, 0, 174, IT_RUBBER_PLANTATION, IT_COPPER_MINE, IT_LUMBER_MILL, CHECK_PLANTATION, CT_GOODS, 0, CT_INVALID, 0, 5, CT_RUBBER, 256, CT_COPPER_ORE, 256, CT_WOOD, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TROPIC, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_FACTORY_2, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_farm2, 0, NULL, 250, 0xD9999999, 0, 0, 1, 0, 0, 0, 2, 0, 48, IT_FOOD_PROCESS, IT_INVALID, IT_INVALID, CHECK_PLANTATION, CT_MAIZE, 11, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_ORGANIC, 1 << LT_TROPIC, INDUSTRYBEH_PLANT_FIELDS | INDUSTRYBEH_PLANT_ON_BUILT, STR_INDUSTRY_NAME_FARM_2, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), MI(_tile_table_lumber_mill, 0, NULL, 135, 0xFFFFFFFF, 0, 0, 0, 0, 0, 0, 0, 0, 194, IT_FACTORY_2, IT_INVALID, IT_INVALID, CHECK_LUMBERMILL, CT_WOOD, 0, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TROPIC, INDUSTRYBEH_CUT_TREES, STR_INDUSTRY_NAME_LUMBER_MILL, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_cotton_candy, 0, NULL, 195, 0xBFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 5, 48, IT_CANDY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COTTON_CANDY, 13, CT_INVALID, 0, 30, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_ORGANIC, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_COTTON_CANDY_FOREST, STR_NEWS_INDUSTRY_PLANTED, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_candy_factory, 0, NULL, 206, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 5, 174, IT_COTTON_CANDY, IT_TOFFEE_QUARRY, IT_SUGAR_MINE, CHECK_NOTHING, CT_CANDY, 0, CT_INVALID, 0, 5, CT_SUGAR, 256, CT_TOFFEE, 256, CT_COTTON_CANDY, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_CANDY_FACTORY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_battery_farm, 0, NULL, 187, 0xB3333333, 0, 0, 0, 3, 0, 0, 0, 4, 39, IT_TOY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_BATTERIES, 11, CT_INVALID, 0, 30, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_ORGANIC, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_BATTERY_FARM, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM), MI(_tile_table_cola_wells, 0, NULL, 193, 0x99999999, 0, 0, 0, 3, 0, 0, 0, 5, 55, IT_FIZZY_DRINK_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_COLA, 12, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_COLA_WELLS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_toy_shop, 0, NULL, 133, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 4, 208, IT_TOY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_INVALID, 0, CT_INVALID, 0, 5, CT_TOYS, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_BLACK_HOLE, 1 << LT_TOYLAND, INDUSTRYBEH_ONLY_NEARTOWN, STR_INDUSTRY_NAME_TOY_SHOP, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_toy_factory, 0, NULL, 163, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 5, 10, IT_PLASTIC_FOUNTAINS, IT_BATTERY_FARM, IT_TOY_SHOP, CHECK_NOTHING, CT_TOYS, 0, CT_INVALID, 0, 5, CT_PLASTIC, 256, CT_BATTERIES, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_TOY_FACTORY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_plastic_fountain, 1, _plastic_mine_sounds, 192, 0xA6666666, 0, 0, 0, 3, 0, 0, 0, 5, 37, IT_TOY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_PLASTIC, 14, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_fizzy_drink, 0, NULL, 177, 0xFFFFFFFF, 0, 0, 0, 3, 0, 0, 0, 4, 184, IT_COLA_WELLS, IT_BUBBLE_GENERATOR, IT_INVALID, CHECK_NOTHING, CT_FIZZY_DRINKS, 0, CT_INVALID, 0, 5, CT_COLA, 256, CT_BUBBLES, 256, CT_INVALID, 256, INDUSTRYLIFE_PROCESSING, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_bubble_generator, 0, NULL, 203, 0xB3333333, 0, 0, 0, 3, 0, 0, 0, 5, 152, IT_FIZZY_DRINK_FACTORY, IT_INVALID, IT_INVALID, CHECK_BUBBLEGEN, CT_BUBBLES, 13, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_BUBBLE_GENERATOR, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_toffee_quarry, 0, NULL, 213, 0xCCCCCCCC, 0, 0, 0, 3, 0, 0, 0, 5, 194, IT_CANDY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_TOFFEE, 10, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_TOFFEE_QUARRY, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), MI(_tile_table_sugar_mine, 0, NULL, 210, 0xBFFFFFFF, 0, 0, 0, 2, 0, 0, 0, 4, 15, IT_CANDY_FACTORY, IT_INVALID, IT_INVALID, CHECK_NOTHING, CT_SUGAR, 11, CT_INVALID, 0, 5, CT_INVALID, 256, CT_INVALID, 256, CT_INVALID, 256, INDUSTRYLIFE_EXTRACTIVE, 1 << LT_TOYLAND, INDUSTRYBEH_NONE, STR_INDUSTRY_NAME_SUGAR_MINE, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL), }; #undef MI /** * Writes the properties of an industry tile into the IndustryTileSpec struct. * @param ca1 acceptance of first cargo * @param c1 first type of cargo accepted for this tile * @param ca2 acceptance of second cargo * @param c2 second cargo * @param ca3 acceptance of third cargo * @param c3 and third cargo. Those three are in an array * @param sl slope refused upon choosing a place to build * @param a1 animation frame on production * @param a2 next frame of animation * @param a3 chooses between animation or construction state */ #define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) {{c1, c2, c3}, {ca1, ca2, ca3}, sl, a1, a2, a3, 0, {0, ANIM_STATUS_NO_ANIMATION, 2, 0}, INDTILE_SPECIAL_NONE, true, GRFFileProps(INVALID_INDUSTRYTILE)} static const IndustryTileSpec _origin_industry_tile_specs[NEW_INDUSTRYTILEOFFSET] = { /* Coal Mine */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, true), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Power Station */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_COAL, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Sawmill */ MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Forest Artic, temperate */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, 17, INDUSTRYTILE_NOANIM, false), ///< Chopping forest MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, 16, false), ///< Growing forest /* Oil refinery */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_OIL, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Oil Rig */ MT(0, CT_INVALID, 8, CT_PASSENGERS, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_MAIL, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Oil Wells artic, temperate and sub-tropical */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, true ), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, true ), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, true ), /* Farm tropic, arctic and temperate */ MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Factory temperate */ MT(8, CT_GRAIN, 8, CT_LIVESTOCK, 8, CT_STEEL, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_GRAIN, 8, CT_LIVESTOCK, 8, CT_STEEL, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_GRAIN, 8, CT_LIVESTOCK, 8, CT_STEEL, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_GRAIN, 8, CT_LIVESTOCK, 8, CT_STEEL, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Printing works */ MT(0, CT_INVALID, 8, CT_PAPER, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_PAPER, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_PAPER, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_PAPER, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Copper ore mine */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, true ), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Steel mill */ MT(1, CT_PASSENGERS, 8, CT_IRON_ORE, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_IRON_ORE, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_IRON_ORE, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_IRON_ORE, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_IRON_ORE, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_IRON_ORE, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Bank temperate*/ MT(1, CT_PASSENGERS, 8, CT_VALUABLES, 0, CT_INVALID, SLOPE_E, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(1, CT_PASSENGERS, 8, CT_VALUABLES, 0, CT_INVALID, SLOPE_S, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Food processing plant, tropic and arctic. CT_MAIZE or CT_WHEAT, CT_LIVESTOCK or CT_FRUIT*/ MT(8, CT_MAIZE, 8, CT_LIVESTOCK, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_MAIZE, 8, CT_LIVESTOCK, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_MAIZE, 8, CT_LIVESTOCK, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_MAIZE, 8, CT_LIVESTOCK, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Paper mill */ MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_WOOD, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Gold mine */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, true), /* Bank Sub Arctic */ MT(0, CT_INVALID, 8, CT_GOLD, 0, CT_INVALID, SLOPE_E, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_GOLD, 0, CT_INVALID, SLOPE_S, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Diamond mine */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Iron ore Mine */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Fruit plantation */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Rubber plantation */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Water supply */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Water tower */ MT(0, CT_INVALID, 8, CT_WATER, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Factory (sub-tropical) */ MT(8, CT_COPPER_ORE, 8, CT_RUBBER, 8, CT_WOOD, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_COPPER_ORE, 8, CT_RUBBER, 8, CT_WOOD, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_COPPER_ORE, 8, CT_RUBBER, 8, CT_WOOD, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_COPPER_ORE, 8, CT_RUBBER, 8, CT_WOOD, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Lumber mill */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Candyfloss forest */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, 130, INDUSTRYTILE_NOANIM, false), ///< Chopping candyfloss MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, 129, false), ///< Growing candyfloss /* Sweet factory */ MT(8, CT_COTTON_CANDY, 8, CT_TOFFEE, 8, CT_SUGAR, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_COTTON_CANDY, 8, CT_TOFFEE, 8, CT_SUGAR, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_COTTON_CANDY, 8, CT_TOFFEE, 8, CT_SUGAR, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_COTTON_CANDY, 8, CT_TOFFEE, 8, CT_SUGAR, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Battery farm */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, 136, INDUSTRYTILE_NOANIM, false), ///< Reaping batteries MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, 135, false), ///< Growing batteries /* Cola wells */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Toy shop */ MT(0, CT_INVALID, 8, CT_TOYS, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_TOYS, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_TOYS, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 8, CT_TOYS, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Toy factory */ MT(8, CT_BATTERIES, 8, CT_PLASTIC, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BATTERIES, 8, CT_PLASTIC, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BATTERIES, 8, CT_PLASTIC, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BATTERIES, 8, CT_PLASTIC, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BATTERIES, 8, CT_PLASTIC, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BATTERIES, 8, CT_PLASTIC, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Plastic Fountain */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Fizzy drink factory */ MT(8, CT_BUBBLES, 8, CT_COLA, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BUBBLES, 8, CT_COLA, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BUBBLES, 8, CT_COLA, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(8, CT_BUBBLES, 8, CT_COLA, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Bubble generator */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Toffee quarry */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), /* Sugar mine */ MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), MT(0, CT_INVALID, 0, CT_INVALID, 0, CT_INVALID, SLOPE_STEEP, INDUSTRYTILE_NOANIM, INDUSTRYTILE_NOANIM, false), }; #undef MT #endif /* BUILD_INDUSTRY_H */ openttd-1.5.3/src/table/object_land.h0000644000000000000000000001433612627373436016212 0ustar rootroot/* $Id: object_land.h 27183 2015-03-13 19:42:49Z rubidium $ */ /* * 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 object_land.h Sprites to use and how to display them for object tiles. */ #define TILE_SEQ_LINE(sz, img) { 0, 0, 0, 16, 16, sz, {img, PAL_NONE} }, #define TILE_SEQ_END() { (int8)0x80, 0, 0, 0, 0, 0, {0, 0} } static const DrawTileSeqStruct _object_nothing[] = { TILE_SEQ_END() }; static const DrawTileSeqStruct _object_transmitter_seq[] = { { 7, 7, 0, 2, 2, 70, {SPR_TRANSMITTER, PAL_NONE}}, TILE_SEQ_END() }; static const DrawTileSeqStruct _object_lighthouse_seq[] = { { 4, 4, 0, 7, 7, 61, {SPR_LIGHTHOUSE, PAL_NONE}}, TILE_SEQ_END() }; static const DrawTileSeqStruct _object_statue_seq[] = { { 0, 0, 0, 16, 16, 25, {SPR_STATUE_COMPANY | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE}}, TILE_SEQ_END() }; static const DrawTileSeqStruct _object_owned_land_seq[] = { { 8, 8, 0, 1, 1, 6, {SPR_BOUGHT_LAND | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE}}, TILE_SEQ_END() }; extern const DrawTileSprites _objects[] = { { { SPR_FLAT_2_THIRD_GRASS_TILE, PAL_NONE }, _object_transmitter_seq }, { { SPR_FLAT_2_THIRD_GRASS_TILE, PAL_NONE }, _object_lighthouse_seq }, { { SPR_CONCRETE_GROUND, PAL_NONE }, _object_statue_seq }, { { SPR_FLAT_BARE_LAND, PAL_NONE }, _object_owned_land_seq }, }; static const DrawTileSeqStruct _object_hq_medium_north[] = { TILE_SEQ_LINE(20, SPR_MEDIUMHQ_NORTH_WALL | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_medium_east[] = { TILE_SEQ_LINE(20, SPR_MEDIUMHQ_EAST_WALL | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_medium_west[] = { TILE_SEQ_LINE(20, SPR_MEDIUMHQ_WEST_WALL | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_large_north[] = { TILE_SEQ_LINE(50, SPR_LARGEHQ_NORTH_BUILD | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_large_east[] = { TILE_SEQ_LINE(50, SPR_LARGEHQ_EAST_BUILD | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_large_west[] = { TILE_SEQ_LINE(50, SPR_LARGEHQ_WEST_BUILD | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_huge_north[] = { TILE_SEQ_LINE(60, SPR_HUGEHQ_NORTH_BUILD | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_huge_east[] = { TILE_SEQ_LINE(60, SPR_HUGEHQ_EAST_BUILD | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _object_hq_huge_west[] = { TILE_SEQ_LINE(60, SPR_HUGEHQ_WEST_BUILD | (1 << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; #undef TILE_SEQ_LINE #undef TILE_SEQ_END #define TILE_SPRITE_LINE(img, dtss) { {img | (1 << PALETTE_MODIFIER_COLOUR), PAL_NONE}, dtss }, static const DrawTileSprites _object_hq[] = { TILE_SPRITE_LINE(SPR_TINYHQ_NORTH, _object_nothing) TILE_SPRITE_LINE(SPR_TINYHQ_WEST, _object_nothing) TILE_SPRITE_LINE(SPR_TINYHQ_EAST, _object_nothing) TILE_SPRITE_LINE(SPR_TINYHQ_SOUTH, _object_nothing) TILE_SPRITE_LINE(SPR_SMALLHQ_NORTH, _object_nothing) TILE_SPRITE_LINE(SPR_SMALLHQ_WEST, _object_nothing) TILE_SPRITE_LINE(SPR_SMALLHQ_EAST, _object_nothing) TILE_SPRITE_LINE(SPR_SMALLHQ_SOUTH, _object_nothing) TILE_SPRITE_LINE(SPR_MEDIUMHQ_NORTH, _object_hq_medium_north) TILE_SPRITE_LINE(SPR_MEDIUMHQ_WEST, _object_hq_medium_west) TILE_SPRITE_LINE(SPR_MEDIUMHQ_EAST, _object_hq_medium_east) TILE_SPRITE_LINE(SPR_MEDIUMHQ_SOUTH, _object_nothing) TILE_SPRITE_LINE(SPR_LARGEHQ_NORTH_GROUND, _object_hq_large_north) TILE_SPRITE_LINE(SPR_LARGEHQ_WEST_GROUND, _object_hq_large_west) TILE_SPRITE_LINE(SPR_LARGEHQ_EAST_GROUND, _object_hq_large_east) TILE_SPRITE_LINE(SPR_LARGEHQ_SOUTH, _object_nothing) TILE_SPRITE_LINE(SPR_HUGEHQ_NORTH_GROUND, _object_hq_huge_north) TILE_SPRITE_LINE(SPR_HUGEHQ_WEST_GROUND, _object_hq_huge_west) TILE_SPRITE_LINE(SPR_HUGEHQ_EAST_GROUND, _object_hq_huge_east) TILE_SPRITE_LINE(SPR_HUGEHQ_SOUTH, _object_nothing) }; #undef TILE_SPRITE_LINE #define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) { GRFFilePropsBase<2>(), INVALID_OBJECT_CLASS, name, climate, size, build_cost_multiplier, clear_cost_multiplier, 0, MAX_DAY + 1, flags, {0, 0, 0, 0}, 0, height, 1, gen_amount, true } /* Climates * T = Temperate * A = Sub-Arctic * S = Sub-Tropic * Y = Toyland */ #define T 1 #define A 2 #define S 4 #define Y 8 /** Specification of the original object structures. */ extern const ObjectSpec _original_objects[] = { M(STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER, 0x11, 0, 0, 10, T|A|S , 15, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT), M(STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE, 0x11, 0, 0, 8, T|A , 8, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_SCENEDIT | OBJECT_FLAG_SCALE_BY_WATER), M(STR_TOWN_BUILDING_NAME_STATUE_1, 0x11, 0, 0, 5, T|S|A|Y, 0, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_ONLY_IN_SCENEDIT), // Yes, we disallow building this everywhere. Happens in "special" case! M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND, 0x11, 10, 10, 0, T|S|A|Y, 0, OBJECT_FLAG_AUTOREMOVE | OBJECT_FLAG_ONLY_IN_GAME | OBJECT_FLAG_CLEAR_INCOME | OBJECT_FLAG_HAS_NO_FOUNDATION ), // Only non-silly use case is to use it when you cannot build a station, so disallow bridges M(STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS, 0x22, 0, 0, 7, T|S|A|Y, 0, OBJECT_FLAG_CANNOT_REMOVE | OBJECT_FLAG_ONLY_IN_GAME), }; #undef M #undef Y #undef S #undef A #undef T openttd-1.5.3/src/table/station_land.h0000644000000000000000000014267512627373436016435 0ustar rootroot/* $Id: station_land.h 23010 2011-10-07 07:56:30Z planetmaker $ */ /* * 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 station_land.h Sprites to use and how to display them for station tiles. */ /** * Constructor macro for an image without a palette in a DrawTileSeqStruct array. * @param dx Offset in x direction * @param dy Offset in y direction * @param dz Offset in z direction * @param sx Size in x direction * @param sy Size in y direction * @param sz Size in z direction * @param img Sprite to draw */ #define TILE_SEQ_LINE(dx, dy, dz, sx, sy, sz, img) TILE_SEQ_LINE_PAL(dx, dy, dz, sx, sy, sz, img, PAL_NONE) /** * Constructor macro for an image with a palette in a DrawTileSeqStruct array. * @param dx Offset in x direction * @param dy Offset in y direction * @param dz Offset in z direction * @param sx Size in x direction * @param sy Size in y direction * @param sz Size in z direction * @param img Sprite to draw * @param pal Palette sprite */ #define TILE_SEQ_LINE_PAL(dx, dy, dz, sx, sy, sz, img, pal) { dx, dy, dz, sx, sy, sz, {img, pal} }, /** * Constructor macro for an image without bounding box. * @param dx Screen X offset from parent sprite * @param dy Screen Y offset from parent sprite * @param img Sprite to draw * @param pal Palette sprite */ #define TILE_SEQ_CHILD(dx, dy, img, pal) TILE_SEQ_LINE_PAL(dx, dy, (int8)0x80, 0, 0, 0, img, pal) /** * Constructor macro for additional ground sprites. * These need to be at the front of a DrawTileSeqStruct sequence. * @param dx Offset in x direction * @param dy Offset in y direction * @param dz Offset in z direction * @param img Sprite to draw */ #define TILE_SEQ_GROUND(dx, dy, dz, img) TILE_SEQ_CHILD(2 * (dy - dx), dx + dy - dz, img, PAL_NONE) /** Constructor macro for a terminating DrawTileSeqStruct entry in an array */ #define TILE_SEQ_END() { (int8)0x80, 0, 0, 0, 0, 0, {0, 0} } static const DrawTileSeqStruct _station_display_nothing[] = { TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_0[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 5, 2, SPR_RAIL_PLATFORM_X_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 11, 0, 16, 5, 2, SPR_RAIL_PLATFORM_X_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_1[] = { TILE_SEQ_LINE( 0, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_Y_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(11, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_Y_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_2[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 5, 2, SPR_RAIL_PLATFORM_BUILDING_X | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 11, 0, 16, 5, 2, SPR_RAIL_PLATFORM_X_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_3[] = { TILE_SEQ_LINE( 0, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_BUILDING_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(11, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_Y_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_4[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 5, 7, SPR_RAIL_PLATFORM_PILLARS_X_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 11, 0, 16, 5, 2, SPR_RAIL_PLATFORM_X_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 16, 16, 16, 10, SPR_RAIL_ROOF_STRUCTURE_X_TILE_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_CHILD( 0, 0, SPR_RAIL_ROOF_GLASS_X_TILE_A | (1U << PALETTE_MODIFIER_TRANSPARENT), PALETTE_TO_TRANSPARENT) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_5[] = { TILE_SEQ_LINE( 0, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_PILLARS_Y_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(11, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_Y_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 16, 16, 16, 10, SPR_RAIL_ROOF_STRUCTURE_Y_TILE_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_CHILD( 0, 0, SPR_RAIL_ROOF_GLASS_Y_TILE_A | (1U << PALETTE_MODIFIER_TRANSPARENT), PALETTE_TO_TRANSPARENT) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_6[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 5, 2, SPR_RAIL_PLATFORM_X_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 11, 0, 16, 5, 2, SPR_RAIL_PLATFORM_PILLARS_X_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 16, 16, 16, 10, SPR_RAIL_ROOF_STRUCTURE_X_TILE_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_CHILD( 0, 0, SPR_RAIL_ROOF_GLASS_X_TILE_B | (1U << PALETTE_MODIFIER_TRANSPARENT), PALETTE_TO_TRANSPARENT) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_7[] = { TILE_SEQ_LINE( 0, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_Y_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(11, 0, 0, 5, 16, 2, SPR_RAIL_PLATFORM_PILLARS_Y_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 16, 16, 16, 10, SPR_RAIL_ROOF_STRUCTURE_Y_TILE_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_CHILD( 0, 0, SPR_RAIL_ROOF_GLASS_Y_TILE_B | (1U << PALETTE_MODIFIER_TRANSPARENT), PALETTE_TO_TRANSPARENT) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_fence_nw[] = { TILE_SEQ_GROUND( 0, 0, 0, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences north TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_fence_ne[] = { TILE_SEQ_GROUND( 0, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_fence_sw[] = { TILE_SEQ_GROUND(15, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences west TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_fence_se[] = { TILE_SEQ_GROUND( 0, 15, 0, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_terminal_a[] = { TILE_SEQ_LINE( 2, 0, 0, 11, 16, 40, SPR_AIRPORT_TERMINAL_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_tower_fence_sw[] = { TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_TOWER | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_concourse[] = { TILE_SEQ_LINE( 0, 1, 0, 14, 14, 30, SPR_AIRPORT_CONCOURSE | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_terminal_b[] = { TILE_SEQ_LINE( 3, 3, 0, 10, 11, 35, SPR_AIRPORT_TERMINAL_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_terminal_c[] = { TILE_SEQ_LINE( 0, 3, 0, 16, 11, 40, SPR_AIRPORT_TERMINAL_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_hangar_se[] = { TILE_SEQ_LINE(14, 0, 0, 2, 17, 28, SPR_AIRPORT_HANGAR_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 2, 17, 28, SPR_AIRPORT_HANGAR_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_jetway_1[] = { TILE_SEQ_LINE( 7, 11, 0, 3, 3, 14, SPR_AIRPORT_JETWAY_1 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_jetway_2[] = { TILE_SEQ_LINE( 2, 7, 0, 3, 3, 14, SPR_AIRPORT_JETWAY_2 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_jetway_3[] = { TILE_SEQ_LINE( 3, 2, 0, 3, 3, 14, SPR_AIRPORT_JETWAY_3 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_passenger_tunnel[] = { TILE_SEQ_LINE( 0, 8, 0, 14, 3, 14, SPR_AIRPORT_PASSENGER_TUNNEL | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_1_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_1) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_2_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_2) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_3_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_3) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_4_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_4) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_5_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_5) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_6_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_6) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_7_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_7) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_8_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_8) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_9_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_9) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_10_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_A) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_11_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_B) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_12_fence_sw[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_C) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_transmitter_fence_ne[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 70, SPR_TRANSMITTER) TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_terminal_c_2[] = { TILE_SEQ_LINE( 0, 0, 0, 15, 15, 30, SPR_AIRFIELD_TERM_C_BUILD | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_flag_1_fence_ne[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 4, 11, 0, 1, 1, 20, SPR_AIRFIELD_WIND_1 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_flag_2_fence_ne[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 4, 11, 0, 1, 1, 20, SPR_AIRFIELD_WIND_2 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_flag_3_fence_ne[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 4, 11, 0, 1, 1, 20, SPR_AIRFIELD_WIND_3 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_flag_4_fence_ne[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 4, 11, 0, 1, 1, 20, SPR_AIRFIELD_WIND_4 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_small_depot_se[] = { TILE_SEQ_LINE(14, 0, 0, 2, 17, 28, SPR_AIRFIELD_HANGAR_FRONT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 2, 17, 28, SPR_AIRFIELD_HANGAR_REAR | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_heliport[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 16, 60, SPR_HELIPORT | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_67[] = { TILE_SEQ_LINE( 0, 15, 0, 13, 1, 10, SPR_TRUCK_STOP_NE_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(13, 0, 0, 3, 16, 10, SPR_TRUCK_STOP_NE_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 2, 0, 0, 11, 1, 10, SPR_TRUCK_STOP_NE_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_68[] = { TILE_SEQ_LINE(15, 3, 0, 1, 13, 10, SPR_TRUCK_STOP_SE_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 16, 3, 10, SPR_TRUCK_STOP_SE_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 3, 0, 1, 11, 10, SPR_TRUCK_STOP_SE_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_69[] = { TILE_SEQ_LINE( 3, 0, 0, 13, 1, 10, SPR_TRUCK_STOP_SW_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 3, 16, 10, SPR_TRUCK_STOP_SW_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 3, 15, 0, 11, 1, 10, SPR_TRUCK_STOP_SW_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_70[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 13, 10, SPR_TRUCK_STOP_NW_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 13, 0, 16, 3, 10, SPR_TRUCK_STOP_NW_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(15, 2, 0, 1, 11, 10, SPR_TRUCK_STOP_NW_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_71[] = { TILE_SEQ_LINE( 2, 0, 0, 11, 1, 10, SPR_BUS_STOP_NE_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(13, 0, 0, 3, 16, 10, SPR_BUS_STOP_NE_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 13, 0, 13, 3, 10, SPR_BUS_STOP_NE_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_72[] = { TILE_SEQ_LINE( 0, 3, 0, 1, 11, 10, SPR_BUS_STOP_SE_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 16, 3, 10, SPR_BUS_STOP_SE_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(13, 3, 0, 3, 13, 10, SPR_BUS_STOP_SE_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_73[] = { TILE_SEQ_LINE( 3, 15, 0, 11, 1, 10, SPR_BUS_STOP_SW_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 3, 16, 10, SPR_BUS_STOP_SW_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 3, 0, 0, 13, 3, 10, SPR_BUS_STOP_SW_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_74[] = { TILE_SEQ_LINE(15, 2, 0, 1, 11, 10, SPR_BUS_STOP_NW_BUILD_A | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 13, 0, 16, 3, 10, SPR_BUS_STOP_NW_BUILD_B | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 3, 13, 10, SPR_BUS_STOP_NW_BUILD_C | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_76[] = { TILE_SEQ_LINE( 0, 4, 0, 16, 8, 8, SPR_DOCK_SLOPE_NE | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_77[] = { TILE_SEQ_LINE( 4, 0, 0, 8, 16, 8, SPR_DOCK_SLOPE_SE | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_78[] = { TILE_SEQ_LINE( 0, 4, 0, 16, 8, 8, SPR_DOCK_SLOPE_SW | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_79[] = { TILE_SEQ_LINE( 4, 0, 0, 8, 16, 8, SPR_DOCK_SLOPE_NW | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_80[] = { TILE_SEQ_LINE( 0, 4, 0, 16, 8, 8, SPR_DOCK_FLAT_X | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_81[] = { TILE_SEQ_LINE( 4, 0, 0, 8, 16, 8, SPR_DOCK_FLAT_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* Buoy, which will _always_ drown under the ship */ static const DrawTileSeqStruct _station_display_datas_82[] = { TILE_SEQ_LINE( 4, -1, 0, 0, 0, 0, SPR_IMG_BUOY) TILE_SEQ_END() }; /* control tower without fence */ static const DrawTileSeqStruct _station_display_tower[] = { TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_TOWER | (1U << PALETTE_MODIFIER_COLOUR)) // control tower TILE_SEQ_END() }; /* turning radar with fences on north -- needs 12 tiles *BEGIN */ static const DrawTileSeqStruct _station_display_radar_1_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_1) // turning radar TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_2_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_2) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_3_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_3) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_4_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_4) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_5_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_5) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_6_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_6) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_7_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_7) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_8_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_8) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_9_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_9) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_10_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_A) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_11_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_B) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_12_fence_ne[] = { TILE_SEQ_LINE(7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_C) TILE_SEQ_LINE(0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* END */ /* helipad for international airport */ static const DrawTileSeqStruct _station_display_helipad_fence_sw[] = { TILE_SEQ_LINE(10, 6, 0, 0, 0, 0, SPR_AIRPORT_HELIPAD) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences bottom TILE_SEQ_END() }; /* helipad for commuter airport */ static const DrawTileSeqStruct _station_display_helipad_fence_nw[] = { TILE_SEQ_LINE(10, 6, 0, 0, 0, 0, SPR_AIRPORT_HELIPAD) TILE_SEQ_LINE( 0, 0, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences left TILE_SEQ_END() }; /* helipad for continental airport */ static const DrawTileSeqStruct _station_display_helipad[] = { TILE_SEQ_LINE(10, 6, 0, 0, 0, 0, SPR_AIRPORT_HELIPAD) TILE_SEQ_END() }; /* asphalt tile with fences in north and south */ static const DrawTileSeqStruct _station_display_fence_ne_sw[] = { TILE_SEQ_GROUND( 0, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_GROUND(15, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* runway tiles with 2 corner fences */ static const DrawTileSeqStruct _station_display_fence_nw_sw[] = { TILE_SEQ_GROUND( 0, 0, 0, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences north TILE_SEQ_GROUND(15, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences west TILE_SEQ_END() }; /* runway tiles with 2 corner fences */ static const DrawTileSeqStruct _station_display_fence_se_sw[] = { TILE_SEQ_GROUND(15, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences west TILE_SEQ_GROUND( 0, 15, 0, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; /* runway tiles with 2 corner fences */ static const DrawTileSeqStruct _station_display_fence_ne_nw[] = { TILE_SEQ_GROUND( 0, 0, 0, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences north TILE_SEQ_GROUND( 0, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences east TILE_SEQ_END() }; /* runway tiles with 2 corner fences */ static const DrawTileSeqStruct _station_display_fence_ne_se[] = { TILE_SEQ_GROUND( 0, 0, 0, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences east TILE_SEQ_GROUND( 0, 15, 0, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; /* helipad tiles with 2 corner fences top+right */ static const DrawTileSeqStruct _station_display_helipad_fence_NE_SE[] = { TILE_SEQ_LINE(10, 6, 0, 0, 0, 0, SPR_AIRPORT_HELIPAD) TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences east TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; /* helidepot office with fences top + left */ static const DrawTileSeqStruct _station_display_low_building_fence_ne_nw[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences left TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences east TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_HELIDEPOT_OFFICE | (1U << PALETTE_MODIFIER_COLOUR)) // helidepot office TILE_SEQ_END() }; /* West facing hangar */ static const DrawTileSeqStruct _station_display_hangar_sw[] = { TILE_SEQ_LINE(14, 0, 0, 2, 17, 28, SPR_NEWHANGAR_W | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 2, 17, 28, SPR_NEWHANGAR_W_WALL | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* North facing hangar */ static const DrawTileSeqStruct _station_display_hangar_nw[] = { TILE_SEQ_LINE(14, 0, 0, 2, 16, 28, SPR_NEWHANGAR_N | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* East facing hangar */ static const DrawTileSeqStruct _station_display_hangar_ne[] = { TILE_SEQ_LINE(14, 0, 0, 2, 16, 28, SPR_NEWHANGAR_E | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* helipad for district airport NS */ static const DrawTileSeqStruct _station_display_helipad_fence_se_sw[] = { TILE_SEQ_LINE(10, 6, 0, 0, 0, 0, SPR_AIRPORT_HELIPAD) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences bottom TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences right TILE_SEQ_END() }; /* helipad for district airport NS */ static const DrawTileSeqStruct _station_display_helipad_fence_se[] = { TILE_SEQ_LINE(10, 6, 0, 0, 0, 0, SPR_AIRPORT_HELIPAD) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; /* helidepot office with fence north */ static const DrawTileSeqStruct _station_display_low_building_fence_nw[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences north TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_HELIDEPOT_OFFICE | (1U << PALETTE_MODIFIER_COLOUR)) // helidepot office TILE_SEQ_END() }; /* helidepot office with fence east */ static const DrawTileSeqStruct _station_display_low_building_fence_ne[] = { TILE_SEQ_LINE( 0, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences east TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_HELIDEPOT_OFFICE | (1U << PALETTE_MODIFIER_COLOUR)) // helidepot office TILE_SEQ_END() }; /* helidepot office with fence west */ static const DrawTileSeqStruct _station_display_low_building_fence_sw[] = { TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences west TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_HELIDEPOT_OFFICE | (1U << PALETTE_MODIFIER_COLOUR)) // helidepot office TILE_SEQ_END() }; /* helidepot office with fence south */ static const DrawTileSeqStruct _station_display_low_building_fence_se[] = { TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_HELIDEPOT_OFFICE | (1U << PALETTE_MODIFIER_COLOUR)) // helidepot office TILE_SEQ_END() }; /* helipad for district airport EW*/ static const DrawTileSeqStruct _station_display_helipad_fence_nw_sw[] = { TILE_SEQ_LINE(10, 6, 0, 0, 0, 0, SPR_AIRPORT_HELIPAD) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences west TILE_SEQ_LINE( 0, 0, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences north TILE_SEQ_END() }; /* turning radar with fences on south -- needs 12 tiles *BEGIN */ static const DrawTileSeqStruct _station_display_radar_1_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_1) // turning radar TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_2_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_2) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_3_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_3) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_4_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_4) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_5_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_5) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_6_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_6) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_7_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_7) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_8_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_8) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_9_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_9) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_10_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_A) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_11_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_B) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_radar_12_fence_se[] = { TILE_SEQ_LINE( 7, 7, 0, 2, 2, 8, SPR_AIRPORT_RADAR_C) TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; /* END */ /* helipad for helistation */ static const DrawTileSeqStruct _station_display_newhelipad_fence_se_sw[] = { TILE_SEQ_LINE( 0, 1, 2, 0, 0, 0, SPR_NEWHELIPAD) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences west TILE_SEQ_LINE( 0, 15, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences south TILE_SEQ_END() }; /* helipad for helistation */ static const DrawTileSeqStruct _station_display_newhelipad_fence_nw_sw[] = { TILE_SEQ_LINE( 0, 1, 2, 0, 0, 0, SPR_NEWHELIPAD) TILE_SEQ_LINE(15, 0, 0, 1, 16, 6, SPR_AIRPORT_FENCE_Y | (1U << PALETTE_MODIFIER_COLOUR)) // fences west TILE_SEQ_LINE( 0, 0, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences north TILE_SEQ_END() }; /* helipad for helistation */ static const DrawTileSeqStruct _station_display_newhelipad_fence_nw[] = { TILE_SEQ_LINE( 0, 1, 2, 0, 0, 0, SPR_NEWHELIPAD) TILE_SEQ_LINE( 0, 0, 0, 16, 1, 6, SPR_AIRPORT_FENCE_X | (1U << PALETTE_MODIFIER_COLOUR)) // fences north TILE_SEQ_END() }; /* helidepot office without fence */ static const DrawTileSeqStruct _station_display_low_building[] = { TILE_SEQ_LINE( 3, 3, 0, 10, 10, 60, SPR_AIRPORT_HELIDEPOT_OFFICE | (1U << PALETTE_MODIFIER_COLOUR)) // helidepot office TILE_SEQ_END() }; /* half grass half SPR_AIRPORT_APRON */ static const DrawTileSeqStruct _station_display_grass_west[] = { TILE_SEQ_LINE(0, 0, 0, 0, 0, 0, SPR_GRASS_LEFT) TILE_SEQ_END() }; /* half grass half SPR_AIRPORT_APRON */ static const DrawTileSeqStruct _station_display_grass_east[] = { TILE_SEQ_LINE(0, 0, 0, 0, 0, 0, SPR_GRASS_RIGHT) TILE_SEQ_END() }; /* drive-through truck stop X */ static const DrawTileSeqStruct _station_display_datas_0168[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_X_W | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_TRUCK_STOP_DT_X_E | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* drive-through truck stop Y */ static const DrawTileSeqStruct _station_display_datas_0169[] = { TILE_SEQ_LINE(13, 0, 0, 3, 16, 16, SPR_TRUCK_STOP_DT_Y_W | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 3, 16, 16, SPR_TRUCK_STOP_DT_Y_E | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* drive-through bus stop X */ static const DrawTileSeqStruct _station_display_datas_0170[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 3, 16, SPR_BUS_STOP_DT_X_W | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 13, 0, 16, 3, 16, SPR_BUS_STOP_DT_X_E | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; /* drive-through bus stop Y */ static const DrawTileSeqStruct _station_display_datas_0171[] = { TILE_SEQ_LINE(13, 0, 0, 3, 16, 16, SPR_BUS_STOP_DT_Y_W | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 0, 0, 3, 16, 16, SPR_BUS_STOP_DT_Y_E | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_waypoint_X[] = { TILE_SEQ_LINE( 0, 0, 0, 16, 5, 23, SPR_WAYPOINT_X_1 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE( 0, 11, 0, 16, 5, 23, SPR_WAYPOINT_X_2 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; static const DrawTileSeqStruct _station_display_datas_waypoint_Y[] = { TILE_SEQ_LINE( 0, 0, 0, 5, 16, 23, SPR_WAYPOINT_Y_1 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_LINE(11, 0, 0, 5, 16, 23, SPR_WAYPOINT_Y_2 | (1U << PALETTE_MODIFIER_COLOUR)) TILE_SEQ_END() }; #undef TILE_SEQ_END #undef TILE_SEQ_LINE #undef TILE_SEQ_LINE_PAL #undef TILE_SEQ_CHILD #undef TILE_SEQ_GROUND /** * Constructor macro of a DrawTileSprites structure * @param img Ground sprite without palette of the tile * @param dtss Sequence child sprites of the tile */ #define TILE_SPRITE_LINE(img, dtss) { {img, PAL_NONE}, dtss }, #define TILE_SPRITE_NULL() { {0, 0}, NULL }, extern const DrawTileSprites _station_display_datas_rail[] = { TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_0) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_1) TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_2) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_3) TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_4) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_5) TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_6) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_7) }; static const DrawTileSprites _station_display_datas_airport[] = { TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_nothing) // APT_APRON TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_fence_nw) // APT_APRON_FENCE_NW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_fence_sw) // APT_APRON_FENCE_SW TILE_SPRITE_LINE(SPR_AIRPORT_AIRCRAFT_STAND, _station_display_nothing) // APT_STAND TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_NS_WEST, _station_display_nothing) // APT_APRON_W TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_EW_SOUTH, _station_display_nothing) // APT_APRON_S TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_XING_SOUTH, _station_display_nothing) // APT_APRON_VER_CROSSING_S TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_XING_WEST, _station_display_nothing) // APT_APRON_HOR_CROSSING_W TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_NS_CTR, _station_display_nothing) // APT_APRON_VER_CROSSING_N TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_XING_EAST, _station_display_nothing) // APT_APRON_HOR_CROSSING_E TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_NS_EAST, _station_display_nothing) // APT_APRON_E TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_EW_NORTH, _station_display_nothing) // APT_ARPON_N TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_EW_CTR, _station_display_nothing) // APT_APRON_HOR TILE_SPRITE_LINE(SPR_AIRPORT_TAXIWAY_EW_NORTH, _station_display_fence_sw) // APT_APRON_N_FENCE_SW TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_EXIT_A, _station_display_fence_se) // APT_RUNWAY_1 TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_EXIT_B, _station_display_fence_se) // APT_RUNWAY_2 TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_EXIT_C, _station_display_fence_se) // APT_RUNWAY_3 TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_EXIT_D, _station_display_fence_se) // APT_RUNWAY_4 TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_END, _station_display_fence_se) // APT_RUNWAY_END_FENCE_SE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_terminal_a) // APT_BUILDING_2 TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_tower_fence_sw) // APT_TOWER_FENCE_SW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_concourse) // APT_ROUND_TERMINAL TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_datas_terminal_b) // APT_BUILDING_3 TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_datas_terminal_c) // APT_BUILDING_1 TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_hangar_se) // APT_DEPOT_SE TILE_SPRITE_LINE(SPR_AIRPORT_AIRCRAFT_STAND, _station_display_jetway_1) // APT_STAND_1 TILE_SPRITE_LINE(SPR_AIRPORT_AIRCRAFT_STAND, _station_display_jetway_2) // APT_STAND_PIER_NE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_jetway_3) // APT_PIER_NW_NE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_passenger_tunnel) // APT_PIER TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_nothing) // APT_EMPTY TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_fence_ne) // APT_EMPTY_FENCE_NE TILE_SPRITE_NULL() // APT_RADAR_GRASS_FENCE_SW TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_transmitter_fence_ne) // APT_RADIO_TOWER_FENCE_NE TILE_SPRITE_LINE(SPR_AIRFIELD_TERM_A, _station_display_nothing) // APT_SMALL_BUILDING_3 TILE_SPRITE_LINE(SPR_AIRFIELD_TERM_B, _station_display_nothing) // APT_SMALL_BUILDING_2 TILE_SPRITE_LINE(SPR_AIRFIELD_TERM_C_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_terminal_c_2) // APT_SMALL_BUILDING_1 TILE_SPRITE_LINE(SPR_AIRFIELD_APRON_A, _station_display_fence_sw) // APT_GRASS_FENCE_SW TILE_SPRITE_LINE(SPR_AIRFIELD_APRON_B, _station_display_nothing) // APT_GRASS_2 TILE_SPRITE_LINE(SPR_AIRFIELD_APRON_C, _station_display_nothing) // APT_GRASS_1 TILE_SPRITE_NULL() // APT_GRASS_FENCE_NE_FLAG TILE_SPRITE_LINE(SPR_AIRFIELD_RUNWAY_NEAR_END, _station_display_fence_se) // APT_RUNWAY_SMALL_NEAR_END TILE_SPRITE_LINE(SPR_AIRFIELD_RUNWAY_MIDDLE, _station_display_fence_se) // APT_RUNWAY_SMALL_MIDDLE TILE_SPRITE_LINE(SPR_AIRFIELD_RUNWAY_FAR_END, _station_display_fence_se) // APT_RUNWAY_SMALL_FAR_END TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_small_depot_se) // APT_SMALL_DEPOT_SE TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_heliport) // APT_HELIPORT TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_END, _station_display_nothing) // APT_RUNWAY_END TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_EXIT_B, _station_display_nothing) // APT_RUNWAY_5 TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_tower) // APT_TOWER TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_fence_ne) // APT_APRON_FENCE_NE TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_END, _station_display_fence_nw) // APT_RUNWAY_END_FENCE_NW TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_EXIT_B, _station_display_fence_nw) // APT_RUNWAY_FENCE_NW TILE_SPRITE_NULL() // APT_RADAR_FENCE_SW TILE_SPRITE_NULL() // APT_RADAR_FENCE_NE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_helipad_fence_sw) // APT_HELIPAD_1 TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_helipad_fence_nw) // APT_HELIPAD_2_FENCE_NW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_helipad) // APT_HELIPAD_2 TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_fence_ne_sw) // APT_APRON_FENCE_NE_SW TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_END, _station_display_fence_nw_sw) // APT_RUNWAY_END_FENCE_NW_SW TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_END, _station_display_fence_se_sw) // APT_RUNWAY_END_FENCE_SE_SW TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_END, _station_display_fence_ne_nw) // APT_RUNWAY_END_FENCE_NE_NW TILE_SPRITE_LINE(SPR_AIRPORT_RUNWAY_END, _station_display_fence_ne_se) // APT_RUNWAY_END_FENCE_NE_SE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_helipad_fence_NE_SE) // APT_HELIPAD_2_FENCE_NE_SE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_fence_se_sw) // APT_APRON_FENCE_SE_SW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_low_building_fence_ne_nw) // APT_LOW_BUILDING_FENCE_N TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_low_building_fence_nw) // APT_LOW_BUILDING_FENCE_NW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_fence_se) // APT_APRON_FENCE_SE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_newhelipad_fence_se_sw) // APT_HELIPAD_3_FENCE_SE_SW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_newhelipad_fence_nw_sw) // APT_HELIPAD_3_FENCE_NW_SW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_newhelipad_fence_nw) // APT_HELIPAD_3_FENCE_NW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_low_building) // APT_LOW_BUILDING TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_fence_ne_se) // APT_APRON_FENCE_NE_SE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_grass_west) // APT_APRON_HALF_EAST TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_grass_east) // APT_APRON_HALF_WEST TILE_SPRITE_NULL() // APT_GRASS_FENCE_NE_FLAG_2 }; static const DrawTileSprites _station_display_datas_airport_radar_grass_fence_sw[] = { TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_1_fence_sw) // APT_RADAR_GRASS_FENCE_SW TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_2_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_3_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_4_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_5_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_6_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_7_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_8_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_9_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_10_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_11_fence_sw) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_radar_12_fence_sw) }; static const DrawTileSprites _station_display_datas_airport_flag_grass_fence_ne[] = { TILE_SPRITE_LINE(SPR_AIRFIELD_APRON_D, _station_display_flag_1_fence_ne) // APT_GRASS_FENCE_NE_FLAG TILE_SPRITE_LINE(SPR_AIRFIELD_APRON_D, _station_display_flag_2_fence_ne) TILE_SPRITE_LINE(SPR_AIRFIELD_APRON_D, _station_display_flag_3_fence_ne) TILE_SPRITE_LINE(SPR_AIRFIELD_APRON_D, _station_display_flag_4_fence_ne) }; static const DrawTileSprites _station_display_datas_airport_radar_fence_sw[] = { TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_1_fence_sw) // APT_RADAR_FENCE_SW TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_2_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_3_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_4_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_5_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_6_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_7_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_8_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_9_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_10_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_11_fence_sw) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_12_fence_sw) }; static const DrawTileSprites _station_display_datas_airport_radar_fence_ne[] = { TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_1_fence_ne) // APT_RADAR_FENCE_NE TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_2_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_3_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_4_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_5_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_6_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_7_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_8_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_9_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_10_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_11_fence_ne) TILE_SPRITE_LINE(SPR_AIRPORT_APRON, _station_display_radar_12_fence_ne) }; static const DrawTileSprites _station_display_datas_airport_flag_grass_fence_ne_2[] = { TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_flag_1_fence_ne) // APT_GRASS_FENCE_NE_FLAG_2 TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_flag_2_fence_ne) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_flag_3_fence_ne) TILE_SPRITE_LINE(SPR_FLAT_GRASS_TILE, _station_display_flag_4_fence_ne) }; static const DrawTileSprites _station_display_datas_truck[] = { TILE_SPRITE_LINE(SPR_TRUCK_STOP_NE_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_67) TILE_SPRITE_LINE(SPR_TRUCK_STOP_SE_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_68) TILE_SPRITE_LINE(SPR_TRUCK_STOP_SW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_69) TILE_SPRITE_LINE(SPR_TRUCK_STOP_NW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_70) TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0168) TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0169) }; static const DrawTileSprites _station_display_datas_bus[] = { TILE_SPRITE_LINE(SPR_BUS_STOP_NE_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_71) TILE_SPRITE_LINE(SPR_BUS_STOP_SE_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_72) TILE_SPRITE_LINE(SPR_BUS_STOP_SW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_73) TILE_SPRITE_LINE(SPR_BUS_STOP_NW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_74) TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0170) TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0171) }; static const DrawTileSprites _station_display_datas_oilrig[] = { TILE_SPRITE_LINE(SPR_FLAT_WATER_TILE, _station_display_nothing) }; static const DrawTileSprites _station_display_datas_dock[] = { TILE_SPRITE_LINE(SPR_SHORE_BASE + SLOPE_SW, _station_display_datas_76) TILE_SPRITE_LINE(SPR_SHORE_BASE + SLOPE_NW, _station_display_datas_77) TILE_SPRITE_LINE(SPR_SHORE_BASE + SLOPE_NE, _station_display_datas_78) TILE_SPRITE_LINE(SPR_SHORE_BASE + SLOPE_SE, _station_display_datas_79) TILE_SPRITE_LINE(SPR_FLAT_WATER_TILE, _station_display_datas_80) TILE_SPRITE_LINE(SPR_FLAT_WATER_TILE, _station_display_datas_81) }; static const DrawTileSprites _station_display_datas_buoy[] = { TILE_SPRITE_LINE(SPR_FLAT_WATER_TILE, _station_display_datas_82) }; static const DrawTileSprites _station_display_datas_waypoint[] = { TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_waypoint_X) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_waypoint_Y) TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_waypoint_X) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_waypoint_Y) TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_waypoint_X) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_waypoint_Y) TILE_SPRITE_LINE(SPR_RAIL_TRACK_X, _station_display_datas_waypoint_X) TILE_SPRITE_LINE(SPR_RAIL_TRACK_Y, _station_display_datas_waypoint_Y) }; #undef TILE_SPRITE_LINE #undef TILE_SPRITE_NULL /* Default waypoint is also drawn as fallback for NewGRF waypoints. * As these are drawn/build like stations, they may use the same number of layouts. */ assert_compile(lengthof(_station_display_datas_rail) == lengthof(_station_display_datas_waypoint)); static const DrawTileSprites * const _station_display_datas[] = { _station_display_datas_rail, _station_display_datas_airport, _station_display_datas_truck, _station_display_datas_bus, _station_display_datas_oilrig, _station_display_datas_dock, _station_display_datas_buoy, _station_display_datas_waypoint, }; openttd-1.5.3/src/table/cargo_const.h0000644000000000000000000002512612627373436016246 0ustar rootroot/* $Id: cargo_const.h 23862 2012-01-28 14:12:42Z frosch $ */ /* * 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 cargo_const.h Table of all default cargo types */ /** Construction macro for a #CargoSpec structure. */ #define MK(bt, label, c, e, f, g, h, fr, te, ks1, ks2, ks3, ks4, ks5, l, m, cmult) \ {bt, label, c, c, e, cmult, f, {g, h}, fr, te, 0, 0, ks1, ks2, ks3, ks4, ks5, l, m, NULL, NULL, 0} /** Cargo types available by default. */ static const CargoSpec _default_cargo[] = { MK( 0, 'PASS', 152, 1, 3185, 0, 24, false, TE_PASSENGERS, STR_CARGO_PLURAL_PASSENGERS, STR_CARGO_SINGULAR_PASSENGER, STR_PASSENGERS, STR_QUANTITY_PASSENGERS, STR_ABBREV_PASSENGERS, SPR_CARGO_PASSENGER, CC_PASSENGERS, 0x400), MK( 1, 'COAL', 6, 16, 5916, 7, 255, true, TE_NONE, STR_CARGO_PLURAL_COAL, STR_CARGO_SINGULAR_COAL, STR_TONS, STR_QUANTITY_COAL, STR_ABBREV_COAL, SPR_CARGO_COAL, CC_BULK, 0x100), MK( 2, 'MAIL', 15, 4, 4550, 20, 90, false, TE_MAIL, STR_CARGO_PLURAL_MAIL, STR_CARGO_SINGULAR_MAIL, STR_BAGS, STR_QUANTITY_MAIL, STR_ABBREV_MAIL, SPR_CARGO_MAIL, CC_MAIL, 0x200), /* Oil in temperate and arctic */ MK( 3, 'OIL_', 174, 16, 4437, 25, 255, true, TE_NONE, STR_CARGO_PLURAL_OIL, STR_CARGO_SINGULAR_OIL, STR_LITERS, STR_QUANTITY_OIL, STR_ABBREV_OIL, SPR_CARGO_OIL, CC_LIQUID, 0x100), /* Oil in subtropic */ MK( 3, 'OIL_', 174, 16, 4892, 25, 255, true, TE_NONE, STR_CARGO_PLURAL_OIL, STR_CARGO_SINGULAR_OIL, STR_LITERS, STR_QUANTITY_OIL, STR_ABBREV_OIL, SPR_CARGO_OIL, CC_LIQUID, 0x100), MK( 4, 'LVST', 208, 3, 4322, 4, 18, true, TE_NONE, STR_CARGO_PLURAL_LIVESTOCK, STR_CARGO_SINGULAR_LIVESTOCK, STR_ITEMS, STR_QUANTITY_LIVESTOCK, STR_ABBREV_LIVESTOCK, SPR_CARGO_LIVESTOCK, CC_PIECE_GOODS, 0x100), MK( 5, 'GOOD', 194, 8, 6144, 5, 28, true, TE_GOODS, STR_CARGO_PLURAL_GOODS, STR_CARGO_SINGULAR_GOODS, STR_CRATES, STR_QUANTITY_GOODS, STR_ABBREV_GOODS, SPR_CARGO_GOODS, CC_EXPRESS, 0x200), MK( 6, 'GRAI', 191, 16, 4778, 4, 40, true, TE_NONE, STR_CARGO_PLURAL_GRAIN, STR_CARGO_SINGULAR_GRAIN, STR_TONS, STR_QUANTITY_GRAIN, STR_ABBREV_GRAIN, SPR_CARGO_GRAIN, CC_BULK, 0x100), MK( 6, 'WHEA', 191, 16, 4778, 4, 40, true, TE_NONE, STR_CARGO_PLURAL_WHEAT, STR_CARGO_SINGULAR_WHEAT, STR_TONS, STR_QUANTITY_WHEAT, STR_ABBREV_WHEAT, SPR_CARGO_GRAIN, CC_BULK, 0x100), MK( 6, 'MAIZ', 191, 16, 4322, 4, 40, true, TE_NONE, STR_CARGO_PLURAL_MAIZE, STR_CARGO_SINGULAR_MAIZE, STR_TONS, STR_QUANTITY_MAIZE, STR_ABBREV_MAIZE, SPR_CARGO_GRAIN, CC_BULK, 0x100), /* Wood in temperate and arctic */ MK( 7, 'WOOD', 84, 16, 5005, 15, 255, true, TE_NONE, STR_CARGO_PLURAL_WOOD, STR_CARGO_SINGULAR_WOOD, STR_TONS, STR_QUANTITY_WOOD, STR_ABBREV_WOOD, SPR_CARGO_WOOD, CC_PIECE_GOODS, 0x100), /* Wood in subtropic */ MK( 7, 'WOOD', 84, 16, 7964, 15, 255, true, TE_NONE, STR_CARGO_PLURAL_WOOD, STR_CARGO_SINGULAR_WOOD, STR_TONS, STR_QUANTITY_WOOD, STR_ABBREV_WOOD, SPR_CARGO_WOOD, CC_PIECE_GOODS, 0x100), MK( 8, 'IORE', 184, 16, 5120, 9, 255, true, TE_NONE, STR_CARGO_PLURAL_IRON_ORE, STR_CARGO_SINGULAR_IRON_ORE, STR_TONS, STR_QUANTITY_IRON_ORE, STR_ABBREV_IRON_ORE, SPR_CARGO_IRON_ORE, CC_BULK, 0x100), MK( 9, 'STEL', 10, 16, 5688, 7, 255, true, TE_NONE, STR_CARGO_PLURAL_STEEL, STR_CARGO_SINGULAR_STEEL, STR_TONS, STR_QUANTITY_STEEL, STR_ABBREV_STEEL, SPR_CARGO_STEEL, CC_PIECE_GOODS, 0x100), MK( 10, 'VALU', 202, 2, 7509, 1, 32, true, TE_NONE, STR_CARGO_PLURAL_VALUABLES, STR_CARGO_SINGULAR_VALUABLES, STR_BAGS, STR_QUANTITY_VALUABLES, STR_ABBREV_VALUABLES, SPR_CARGO_VALUES_GOLD, CC_ARMOURED, 0x100), MK( 10, 'GOLD', 202, 8, 5802, 10, 40, true, TE_NONE, STR_CARGO_PLURAL_GOLD, STR_CARGO_SINGULAR_GOLD, STR_BAGS, STR_QUANTITY_GOLD, STR_ABBREV_GOLD, SPR_CARGO_VALUES_GOLD, CC_ARMOURED, 0x100), MK( 10, 'DIAM', 202, 2, 5802, 10, 255, true, TE_NONE, STR_CARGO_PLURAL_DIAMONDS, STR_CARGO_SINGULAR_DIAMOND, STR_BAGS, STR_QUANTITY_DIAMONDS, STR_ABBREV_DIAMONDS, SPR_CARGO_DIAMONDS, CC_ARMOURED, 0x100), MK( 11, 'PAPR', 10, 16, 5461, 7, 60, true, TE_NONE, STR_CARGO_PLURAL_PAPER, STR_CARGO_SINGULAR_PAPER, STR_TONS, STR_QUANTITY_PAPER, STR_ABBREV_PAPER, SPR_CARGO_PAPER, CC_PIECE_GOODS, 0x100), MK( 12, 'FOOD', 48, 16, 5688, 0, 30, true, TE_FOOD, STR_CARGO_PLURAL_FOOD, STR_CARGO_SINGULAR_FOOD, STR_TONS, STR_QUANTITY_FOOD, STR_ABBREV_FOOD, SPR_CARGO_FOOD, CC_EXPRESS | CC_REFRIGERATED, 0x100), MK( 13, 'FRUT', 208, 16, 4209, 0, 15, true, TE_NONE, STR_CARGO_PLURAL_FRUIT, STR_CARGO_SINGULAR_FRUIT, STR_TONS, STR_QUANTITY_FRUIT, STR_ABBREV_FRUIT, SPR_CARGO_FRUIT, CC_BULK | CC_REFRIGERATED, 0x100), MK( 14, 'CORE', 184, 16, 4892, 12, 255, true, TE_NONE, STR_CARGO_PLURAL_COPPER_ORE, STR_CARGO_SINGULAR_COPPER_ORE, STR_TONS, STR_QUANTITY_COPPER_ORE, STR_ABBREV_COPPER_ORE, SPR_CARGO_COPPER_ORE, CC_BULK, 0x100), MK( 15, 'WATR', 10, 16, 4664, 20, 80, true, TE_WATER, STR_CARGO_PLURAL_WATER, STR_CARGO_SINGULAR_WATER, STR_LITERS, STR_QUANTITY_WATER, STR_ABBREV_WATER, SPR_CARGO_WATERCOLA, CC_LIQUID, 0x100), MK( 16, 'RUBR', 6, 16, 4437, 2, 20, true, TE_NONE, STR_CARGO_PLURAL_RUBBER, STR_CARGO_SINGULAR_RUBBER, STR_LITERS, STR_QUANTITY_RUBBER, STR_ABBREV_RUBBER, SPR_CARGO_RUBBER, CC_LIQUID, 0x100), MK( 17, 'SUGR', 6, 16, 4437, 20, 255, true, TE_NONE, STR_CARGO_PLURAL_SUGAR, STR_CARGO_SINGULAR_SUGAR, STR_TONS, STR_QUANTITY_SUGAR, STR_ABBREV_SUGAR, SPR_CARGO_SUGAR, CC_BULK, 0x100), MK( 18, 'TOYS', 174, 2, 5574, 25, 255, true, TE_NONE, STR_CARGO_PLURAL_TOYS, STR_CARGO_SINGULAR_TOY, STR_ITEMS, STR_QUANTITY_TOYS, STR_ABBREV_TOYS, SPR_CARGO_TOYS, CC_PIECE_GOODS, 0x100), MK( 19, 'BATT', 208, 4, 4322, 2, 30, true, TE_NONE, STR_CARGO_PLURAL_BATTERIES, STR_CARGO_SINGULAR_BATTERY, STR_ITEMS, STR_QUANTITY_BATTERIES, STR_ABBREV_BATTERIES, SPR_CARGO_BATTERIES, CC_PIECE_GOODS, 0x100), MK( 20, 'SWET', 194, 5, 6144, 8, 40, true, TE_GOODS, STR_CARGO_PLURAL_CANDY, STR_CARGO_SINGULAR_CANDY, STR_BAGS, STR_QUANTITY_SWEETS, STR_ABBREV_SWEETS, SPR_CARGO_CANDY, CC_EXPRESS, 0x200), MK( 21, 'TOFF', 191, 16, 4778, 14, 60, true, TE_NONE, STR_CARGO_PLURAL_TOFFEE, STR_CARGO_SINGULAR_TOFFEE, STR_TONS, STR_QUANTITY_TOFFEE, STR_ABBREV_TOFFEE, SPR_CARGO_TOFFEE, CC_BULK, 0x100), MK( 22, 'COLA', 84, 16, 4892, 5, 75, true, TE_NONE, STR_CARGO_PLURAL_COLA, STR_CARGO_SINGULAR_COLA, STR_LITERS, STR_QUANTITY_COLA, STR_ABBREV_COLA, SPR_CARGO_WATERCOLA, CC_LIQUID, 0x100), MK( 23, 'CTCD', 184, 16, 5005, 10, 25, true, TE_NONE, STR_CARGO_PLURAL_COTTON_CANDY, STR_CARGO_SINGULAR_COTTON_CANDY, STR_TONS, STR_QUANTITY_CANDYFLOSS, STR_ABBREV_CANDYFLOSS, SPR_CARGO_COTTONCANDY, CC_BULK, 0x100), MK( 24, 'BUBL', 10, 1, 5077, 20, 80, true, TE_NONE, STR_CARGO_PLURAL_BUBBLES, STR_CARGO_SINGULAR_BUBBLE, STR_ITEMS, STR_QUANTITY_BUBBLES, STR_ABBREV_BUBBLES, SPR_CARGO_BUBBLES, CC_PIECE_GOODS, 0x100), MK( 25, 'PLST', 202, 16, 4664, 30, 255, true, TE_NONE, STR_CARGO_PLURAL_PLASTIC, STR_CARGO_SINGULAR_PLASTIC, STR_LITERS, STR_QUANTITY_PLASTIC, STR_ABBREV_PLASTIC, SPR_CARGO_PLASTIC, CC_LIQUID, 0x100), MK( 26, 'FZDR', 48, 2, 6250, 30, 50, true, TE_FOOD, STR_CARGO_PLURAL_FIZZY_DRINKS, STR_CARGO_SINGULAR_FIZZY_DRINK, STR_ITEMS, STR_QUANTITY_FIZZY_DRINKS, STR_ABBREV_FIZZY_DRINKS, SPR_CARGO_FIZZYDRINK, CC_PIECE_GOODS, 0x100), /* Void slot in temperate */ MK( 0xFF, 0, 1, 0, 5688, 0, 30, true, TE_NONE, STR_CARGO_PLURAL_NOTHING, STR_CARGO_SINGULAR_NOTHING, STR_TONS, STR_QUANTITY_NOTHING, STR_ABBREV_NOTHING, SPR_ASCII_SPACE, CC_NOAVAILABLE, 0x100), /* Void slot in arctic */ MK( 0xFF, 0, 184, 0, 5120, 9, 255, true, TE_NONE, STR_CARGO_PLURAL_NOTHING, STR_CARGO_SINGULAR_NOTHING, STR_TONS, STR_QUANTITY_NOTHING, STR_ABBREV_NOTHING, SPR_ASCII_SPACE, CC_NOAVAILABLE, 0x100), }; /** Table of cargo types available in each climate, by default */ static const CargoLabel _default_climate_cargo[NUM_LANDSCAPE][12] = { { 'PASS', 'COAL', 'MAIL', 'OIL_', 'LVST', 'GOOD', 'GRAI', 'WOOD', 'IORE', 'STEL', 'VALU', 33, }, { 'PASS', 'COAL', 'MAIL', 'OIL_', 'LVST', 'GOOD', 'WHEA', 'WOOD', 34, 'PAPR', 'GOLD', 'FOOD', }, { 'PASS', 'RUBR', 'MAIL', 4, 'FRUT', 'GOOD', 'MAIZ', 11, 'CORE', 'WATR', 'DIAM', 'FOOD', }, { 'PASS', 'SUGR', 'MAIL', 'TOYS', 'BATT', 'SWET', 'TOFF', 'COLA', 'CTCD', 'BUBL', 'PLST', 'FZDR', }, }; openttd-1.5.3/src/table/pricebase.h0000644000000000000000000001703012627373436015675 0ustar rootroot/* $Id: pricebase.h 23931 2012-02-11 22:43:39Z michi_cc $ */ /* * 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 pricebase.h Price Bases */ extern const PriceBaseSpec _price_base_specs[] = { { 100, PCAT_NONE, GSF_END, INVALID_PRICE }, ///< PR_STATION_VALUE { 100, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_RAIL { 95, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_ROAD { 65, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_SIGNALS { 275, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_BRIDGE { 600, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_DEPOT_TRAIN { 500, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_DEPOT_ROAD { 700, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_DEPOT_SHIP { 450, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_TUNNEL { 200, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_STATION_RAIL { 180, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_STATION_RAIL_LENGTH { 600, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_STATION_AIRPORT { 200, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_STATION_BUS { 200, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_STATION_TRUCK { 350, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_STATION_DOCK { 400000, PCAT_CONSTRUCTION, GSF_TRAINS, INVALID_PRICE }, ///< PR_BUILD_VEHICLE_TRAIN { 2000, PCAT_CONSTRUCTION, GSF_TRAINS, INVALID_PRICE }, ///< PR_BUILD_VEHICLE_WAGON { 700000, PCAT_CONSTRUCTION, GSF_AIRCRAFT, INVALID_PRICE }, ///< PR_BUILD_VEHICLE_AIRCRAFT { 14000, PCAT_CONSTRUCTION, GSF_ROADVEHICLES, INVALID_PRICE }, ///< PR_BUILD_VEHICLE_ROAD { 65000, PCAT_CONSTRUCTION, GSF_SHIPS, INVALID_PRICE }, ///< PR_BUILD_VEHICLE_SHIP { 20, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_TREES { 250, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_TERRAFORM { 20, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_GRASS { 40, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_ROUGH { 200, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_ROCKS { 500, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_FIELDS { 20, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_TREES { -70, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_RAIL { 10, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_SIGNALS { 50, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_BRIDGE { 80, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_DEPOT_TRAIN { 80, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_DEPOT_ROAD { 90, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_DEPOT_SHIP { 30, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_TUNNEL { 10000, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_WATER { 50, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_STATION_RAIL { 30, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_STATION_AIRPORT { 50, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_STATION_BUS { 50, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_STATION_TRUCK { 55, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_STATION_DOCK { 1600, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_HOUSE { 40, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_CLEAR_ROAD { 5600, PCAT_RUNNING, GSF_TRAINS, INVALID_PRICE }, ///< PR_RUNNING_TRAIN_STEAM { 5200, PCAT_RUNNING, GSF_TRAINS, INVALID_PRICE }, ///< PR_RUNNING_TRAIN_DIESEL { 4800, PCAT_RUNNING, GSF_TRAINS, INVALID_PRICE }, ///< PR_RUNNING_TRAIN_ELECTRIC { 9600, PCAT_RUNNING, GSF_AIRCRAFT, INVALID_PRICE }, ///< PR_RUNNING_AIRCRAFT { 1600, PCAT_RUNNING, GSF_ROADVEHICLES, INVALID_PRICE }, ///< PR_RUNNING_ROADVEH { 5600, PCAT_RUNNING, GSF_SHIPS, INVALID_PRICE }, ///< PR_RUNNING_SHIP {1000000, PCAT_CONSTRUCTION, GSF_END, INVALID_PRICE }, ///< PR_BUILD_INDUSTRY { 1600, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_HOUSE }, ///< PR_CLEAR_INDUSTRY { 40, PCAT_CONSTRUCTION, GSF_OBJECTS, PR_CLEAR_ROUGH }, ///< PR_BUILD_OBJECT { 40, PCAT_CONSTRUCTION, GSF_OBJECTS, PR_CLEAR_ROUGH }, ///< PR_CLEAR_OBJECT { 600, PCAT_CONSTRUCTION, GSF_END, PR_BUILD_DEPOT_TRAIN }, ///< PR_BUILD_WAYPOINT_RAIL { 80, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_DEPOT_TRAIN }, ///< PR_CLEAR_WAYPOINT_RAIL { 350, PCAT_CONSTRUCTION, GSF_END, PR_BUILD_STATION_DOCK }, ///< PR_BUILD_WAYPOINT_BUOY { 50, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_STATION_TRUCK}, ///< PR_CLEAR_WAYPOINT_BUOY {1000000, PCAT_CONSTRUCTION, GSF_END, PR_BUILD_INDUSTRY }, ///< PR_TOWN_ACTION { 250, PCAT_CONSTRUCTION, GSF_END, PR_TERRAFORM }, ///< PR_BUILD_FOUNDATION {8000000, PCAT_CONSTRUCTION, GSF_END, PR_BUILD_INDUSTRY }, ///< PR_BUILD_INDUSTRY_RAW {1000000, PCAT_CONSTRUCTION, GSF_END, PR_BUILD_INDUSTRY }, ///< PR_BUILD_TOWN { 5000, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_WATER }, ///< PR_BUILD_CANAL { 5000, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_WATER }, ///< PR_CLEAR_CANAL { 10000, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_WATER }, ///< PR_BUILD_AQUEDUCT { 2000, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_BRIDGE }, ///< PR_CLEAR_AQUEDUCT { 7500, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_WATER }, ///< PR_BUILD_LOCK { 2000, PCAT_CONSTRUCTION, GSF_END, PR_CLEAR_WATER }, ///< PR_CLEAR_LOCK { 10, PCAT_RUNNING, GSF_END, PR_BUILD_RAIL }, ///< PR_INFRASTRUCTURE_RAIL { 10, PCAT_RUNNING, GSF_END, PR_BUILD_ROAD }, ///< PR_INFRASTRUCTURE_ROAD { 8, PCAT_RUNNING, GSF_END, PR_BUILD_CANAL }, ///< PR_INFRASTRUCTURE_WATER { 100, PCAT_RUNNING, GSF_END, PR_STATION_VALUE }, ///< PR_INFRASTRUCTURE_STATION { 5000, PCAT_RUNNING, GSF_END, PR_BUILD_STATION_AIRPORT}, ///< PR_INFRASTRUCTURE_AIRPORT }; assert_compile(lengthof(_price_base_specs) == PR_END); openttd-1.5.3/src/table/animcursors.h0000644000000000000000000000602512627373436016307 0ustar rootroot/* $Id: animcursors.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 animcursors.h * This file defines all the the animated cursors. * Animated cursors consist of the number of sprites that are * displayed in a round-robin manner. Each sprite also has a time * associated that indicates how many ticks the corresponding sprite * is to be displayed. */ /** * Creates two array entries that define one * status of the cursor. * @param Sprite The Sprite to be displayed * @param display_time The Number of ticks to display the sprite */ #define ANIM_CURSOR_LINE(Sprite, display_time) { Sprite, display_time }, /** * This indicates the termination of the cursor list */ #define ANIM_CURSOR_END() ANIM_CURSOR_LINE(AnimCursor::LAST, 0) /** * Animated cursor elements for demolition */ static const AnimCursor _demolish_animcursor[] = { ANIM_CURSOR_LINE(SPR_CURSOR_DEMOLISH_FIRST, 8) ANIM_CURSOR_LINE(SPR_CURSOR_DEMOLISH_1, 8) ANIM_CURSOR_LINE(SPR_CURSOR_DEMOLISH_2, 8) ANIM_CURSOR_LINE(SPR_CURSOR_DEMOLISH_LAST, 8) ANIM_CURSOR_END() }; /** * Animated cursor elements for lower land */ static const AnimCursor _lower_land_animcursor[] = { ANIM_CURSOR_LINE(SPR_CURSOR_LOWERLAND_FIRST, 10) ANIM_CURSOR_LINE(SPR_CURSOR_LOWERLAND_1, 10) ANIM_CURSOR_LINE(SPR_CURSOR_LOWERLAND_LAST, 29) ANIM_CURSOR_END() }; /** * Animated cursor elements for raise land */ static const AnimCursor _raise_land_animcursor[] = { ANIM_CURSOR_LINE(SPR_CURSOR_RAISELAND_FIRST, 10) ANIM_CURSOR_LINE(SPR_CURSOR_RAISELAND_1, 10) ANIM_CURSOR_LINE(SPR_CURSOR_RAISELAND_LAST, 29) ANIM_CURSOR_END() }; /** * Animated cursor elements for the goto icon */ static const AnimCursor _order_goto_animcursor[] = { ANIM_CURSOR_LINE(SPR_CURSOR_PICKSTATION_FIRST, 10) ANIM_CURSOR_LINE(SPR_CURSOR_PICKSTATION_1, 10) ANIM_CURSOR_LINE(SPR_CURSOR_PICKSTATION_LAST, 29) ANIM_CURSOR_END() }; /** * Animated cursor elements for the build signal icon */ static const AnimCursor _build_signals_animcursor[] = { ANIM_CURSOR_LINE(SPR_CURSOR_BUILDSIGNALS_FIRST, 20) ANIM_CURSOR_LINE(SPR_CURSOR_BUILDSIGNALS_LAST, 20) ANIM_CURSOR_END() }; /** * This is an array of pointers to all the animated cursor * definitions we have above. This is the only thing that is * accessed directly from other files */ static const AnimCursor * const _animcursors[] = { _demolish_animcursor, _lower_land_animcursor, _raise_land_animcursor, _order_goto_animcursor, _build_signals_animcursor }; openttd-1.5.3/src/table/settings.h.postamble0000644000000000000000000000000012627373436017552 0ustar rootrootopenttd-1.5.3/src/table/elrail_data.h0000644000000000000000000004347612627373436016216 0ustar rootroot/* $Id: elrail_data.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 elrail_data.h Stores all the data for overhead wire and pylon drawing. * @see elrail.c */ #ifndef ELRAIL_DATA_H #define ELRAIL_DATA_H /** * Tile Location group. * This defines whether the X and or Y coordinate of a tile is even */ enum TLG { XEVEN_YEVEN = 0, XEVEN_YODD = 1, XODD_YEVEN = 2, XODD_YODD = 3, TLG_END }; /** * When determining the pylon configuration on the edge, two tiles are taken * into account: the tile being drawn itself (the home tile, the one in * ti->tile), and the neighbouring tile */ enum TileSource { TS_HOME = 0, TS_NEIGHBOUR = 1, TS_END }; static const uint NUM_TRACKS_AT_PCP = 6; /** Which PPPs are possible at all on a given PCP */ static const byte AllowedPPPonPCP[DIAGDIR_END] = { 1 << DIR_N | 1 << DIR_E | 1 << DIR_SE | 1 << DIR_S | 1 << DIR_W | 1 << DIR_NW, 1 << DIR_N | 1 << DIR_NE | 1 << DIR_E | 1 << DIR_S | 1 << DIR_SW | 1 << DIR_W, 1 << DIR_N | 1 << DIR_E | 1 << DIR_SE | 1 << DIR_S | 1 << DIR_W | 1 << DIR_NW, 1 << DIR_N | 1 << DIR_NE | 1 << DIR_E | 1 << DIR_S | 1 << DIR_SW | 1 << DIR_W, }; /** * Which of the PPPs are inside the tile. For the two PPPs on the tile border * the following system is used: if you rotate the PCP so that it is in the * north, the eastern PPP belongs to the tile. */ static const byte OwnedPPPonPCP[DIAGDIR_END] = { 1 << DIR_SE | 1 << DIR_S | 1 << DIR_SW | 1 << DIR_W, 1 << DIR_N | 1 << DIR_SW | 1 << DIR_W | 1 << DIR_NW, 1 << DIR_N | 1 << DIR_NE | 1 << DIR_E | 1 << DIR_NW, 1 << DIR_NE | 1 << DIR_E | 1 << DIR_SE | 1 << DIR_S }; /** Maps a track bit onto two PCP positions */ static const DiagDirection PCPpositions[TRACK_END][2] = { {DIAGDIR_NE, DIAGDIR_SW}, // X {DIAGDIR_SE, DIAGDIR_NW}, // Y {DIAGDIR_NW, DIAGDIR_NE}, // UPPER {DIAGDIR_SE, DIAGDIR_SW}, // LOWER {DIAGDIR_SW, DIAGDIR_NW}, // LEFT {DIAGDIR_NE, DIAGDIR_SE}, // RIGHT }; #define PCP_NOT_ON_TRACK 0xFF /** * Preferred points of each trackbit. Those are the ones perpendicular to the * track, plus the point in extension of the track (to mark end-of-track). PCPs * which are not on either end of the track are fully preferred. * @see PCPpositions */ static const byte PreferredPPPofTrackAtPCP[TRACK_END][DIAGDIR_END] = { { // X 1 << DIR_NE | 1 << DIR_SE | 1 << DIR_NW, // NE PCP_NOT_ON_TRACK, // SE 1 << DIR_SE | 1 << DIR_SW | 1 << DIR_NW, // SW PCP_NOT_ON_TRACK // NE }, { // Y PCP_NOT_ON_TRACK, 1 << DIR_NE | 1 << DIR_SE | 1 << DIR_SW, PCP_NOT_ON_TRACK, 1 << DIR_SW | 1 << DIR_NW | 1 << DIR_NE }, { // UPPER 1 << DIR_E | 1 << DIR_N | 1 << DIR_S, PCP_NOT_ON_TRACK, PCP_NOT_ON_TRACK, 1 << DIR_W | 1 << DIR_N | 1 << DIR_S }, { // LOWER PCP_NOT_ON_TRACK, 1 << DIR_E | 1 << DIR_N | 1 << DIR_S, 1 << DIR_W | 1 << DIR_N | 1 << DIR_S, PCP_NOT_ON_TRACK }, { // LEFT PCP_NOT_ON_TRACK, PCP_NOT_ON_TRACK, 1 << DIR_S | 1 << DIR_E | 1 << DIR_W, 1 << DIR_N | 1 << DIR_E | 1 << DIR_W }, { // RIGHT 1 << DIR_N | 1 << DIR_E | 1 << DIR_W, 1 << DIR_S | 1 << DIR_E | 1 << DIR_W, PCP_NOT_ON_TRACK, PCP_NOT_ON_TRACK } }; #undef PCP_NOT_ON_TRACK #define NUM_IGNORE_GROUPS 3 #define IGNORE_NONE 0xFF /** * In case we have a straight line, we place pylon only every two tiles, * so there are certain tiles which we ignore. A straight line is found if * we have exactly two PPPs. */ static const byte IgnoredPCP[NUM_IGNORE_GROUPS][TLG_END][DIAGDIR_END] = { { // Ignore group 1, X and Y tracks { // X even, Y even IGNORE_NONE, 1 << DIR_NE | 1 << DIR_SW, 1 << DIR_NW | 1 << DIR_SE, IGNORE_NONE }, { // X even, Y odd IGNORE_NONE, IGNORE_NONE, 1 << DIR_NW | 1 << DIR_SE, 1 << DIR_NE | 1 << DIR_SW }, { // X odd, Y even 1 << DIR_NW | 1 << DIR_SE, 1 << DIR_NE | 1 << DIR_SW, IGNORE_NONE, IGNORE_NONE }, { // X odd, Y odd 1 << DIR_NW | 1 << DIR_SE, IGNORE_NONE, IGNORE_NONE, 1 << DIR_NE | 1 << DIR_SW } }, { // Ignore group 2, LEFT and RIGHT tracks { 1 << DIR_E | 1 << DIR_W, IGNORE_NONE, IGNORE_NONE, 1 << DIR_E | 1 << DIR_W }, { IGNORE_NONE, 1 << DIR_E | 1 << DIR_W, 1 << DIR_E | 1 << DIR_W, IGNORE_NONE }, { IGNORE_NONE, 1 << DIR_E | 1 << DIR_W, 1 << DIR_E | 1 << DIR_W, IGNORE_NONE }, { 1 << DIR_E | 1 << DIR_W, IGNORE_NONE, IGNORE_NONE, 1 << DIR_E | 1 << DIR_W } }, { // Ignore group 3, UPPER and LOWER tracks { 1 << DIR_N | 1 << DIR_S, 1 << DIR_N | 1 << DIR_S, IGNORE_NONE, IGNORE_NONE }, { IGNORE_NONE, IGNORE_NONE, 1 << DIR_N | 1 << DIR_S, 1 << DIR_N | 1 << DIR_S }, { IGNORE_NONE, IGNORE_NONE, 1 << DIR_N | 1 << DIR_S , 1 << DIR_N | 1 << DIR_S }, { 1 << DIR_N | 1 << DIR_S, 1 << DIR_N | 1 << DIR_S, IGNORE_NONE, IGNORE_NONE } } }; #undef NO_IGNORE /** Which pylons can definitely NOT be built */ static const byte DisallowedPPPofTrackAtPCP[TRACK_END][DIAGDIR_END] = { {1 << DIR_SW | 1 << DIR_NE, 0, 1 << DIR_SW | 1 << DIR_NE, 0 }, // X {0, 1 << DIR_NW | 1 << DIR_SE, 0, 1 << DIR_NW | 1 << DIR_SE}, // Y {1 << DIR_W | 1 << DIR_E, 0, 0, 1 << DIR_W | 1 << DIR_E }, // UPPER {0, 1 << DIR_W | 1 << DIR_E, 1 << DIR_W | 1 << DIR_E, 0 }, // LOWER {0, 0, 1 << DIR_S | 1 << DIR_N, 1 << DIR_N | 1 << DIR_S }, // LEFT {1 << DIR_S | 1 << DIR_N, 1 << DIR_S | 1 << DIR_N, 0, 0, }, // RIGHT }; /* This array stores which track bits can meet at a tile edge */ static const Track TracksAtPCP[DIAGDIR_END][NUM_TRACKS_AT_PCP] = { {TRACK_X, TRACK_X, TRACK_UPPER, TRACK_LOWER, TRACK_LEFT, TRACK_RIGHT}, {TRACK_Y, TRACK_Y, TRACK_UPPER, TRACK_LOWER, TRACK_LEFT, TRACK_RIGHT}, {TRACK_X, TRACK_X, TRACK_UPPER, TRACK_LOWER, TRACK_LEFT, TRACK_RIGHT}, {TRACK_Y, TRACK_Y, TRACK_UPPER, TRACK_LOWER, TRACK_LEFT, TRACK_RIGHT}, }; /* takes each of the 6 track bits from the array above and * assigns it to the home tile or neighbour tile */ static const TileSource TrackSourceTile[DIAGDIR_END][NUM_TRACKS_AT_PCP] = { {TS_HOME, TS_NEIGHBOUR, TS_HOME , TS_NEIGHBOUR, TS_NEIGHBOUR, TS_HOME }, {TS_HOME, TS_NEIGHBOUR, TS_NEIGHBOUR, TS_HOME , TS_NEIGHBOUR, TS_HOME }, {TS_HOME, TS_NEIGHBOUR, TS_NEIGHBOUR, TS_HOME , TS_HOME , TS_NEIGHBOUR}, {TS_HOME, TS_NEIGHBOUR, TS_HOME , TS_NEIGHBOUR, TS_HOME , TS_NEIGHBOUR}, }; /* Several PPPs maybe exist, here they are sorted in order of preference. */ static const Direction PPPorder[DIAGDIR_END][TLG_END][DIR_END] = { // X - Y { // PCP 0 {DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_E, DIR_S, DIR_W}, // evn - evn {DIR_NE, DIR_SE, DIR_SW, DIR_NW, DIR_S, DIR_W, DIR_N, DIR_E}, // evn - odd {DIR_SW, DIR_NW, DIR_NE, DIR_SE, DIR_S, DIR_W, DIR_N, DIR_E}, // odd - evn {DIR_SW, DIR_SE, DIR_NE, DIR_NW, DIR_N, DIR_E, DIR_S, DIR_W}, // odd - odd }, {// PCP 1 {DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_S, DIR_E, DIR_N, DIR_W}, // evn - evn {DIR_NE, DIR_SE, DIR_SW, DIR_NW, DIR_N, DIR_W, DIR_S, DIR_E}, // evn - odd {DIR_SW, DIR_NW, DIR_NE, DIR_SE, DIR_N, DIR_W, DIR_S, DIR_E}, // odd - evn {DIR_SW, DIR_SE, DIR_NE, DIR_NW, DIR_S, DIR_E, DIR_N, DIR_W}, // odd - odd }, {// PCP 2 {DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_S, DIR_W, DIR_N, DIR_E}, // evn - evn {DIR_NE, DIR_SE, DIR_SW, DIR_NW, DIR_N, DIR_E, DIR_S, DIR_W}, // evn - odd {DIR_SW, DIR_NW, DIR_NE, DIR_SE, DIR_N, DIR_E, DIR_S, DIR_W}, // odd - evn {DIR_SW, DIR_SE, DIR_NE, DIR_NW, DIR_S, DIR_W, DIR_N, DIR_E}, // odd - odd }, {// PCP 3 {DIR_NE, DIR_NW, DIR_SE, DIR_SW, DIR_N, DIR_W, DIR_S, DIR_E}, // evn - evn {DIR_NE, DIR_SE, DIR_SW, DIR_NW, DIR_S, DIR_E, DIR_N, DIR_W}, // evn - odd {DIR_SW, DIR_NW, DIR_NE, DIR_SE, DIR_S, DIR_E, DIR_N, DIR_W}, // odd - evn {DIR_SW, DIR_SE, DIR_NE, DIR_NW, DIR_N, DIR_W, DIR_S, DIR_E}, // odd - odd } }; /* Geometric placement of the PCP relative to the tile origin */ static const int8 x_pcp_offsets[DIAGDIR_END] = {0, 8, 16, 8}; static const int8 y_pcp_offsets[DIAGDIR_END] = {8, 16, 8, 0}; /* Geometric placement of the PPP relative to the PCP*/ static const int8 x_ppp_offsets[DIR_END] = {-2, -4, -2, 0, 2, 4, 2, 0}; static const int8 y_ppp_offsets[DIR_END] = {-2, 0, 2, 4, 2, 0, -2, -4}; /** * Offset for pylon sprites from the base pylon sprite. */ enum PylonSpriteOffset { PSO_Y_NE, PSO_Y_SW, PSO_X_NW, PSO_X_SE, PSO_EW_N, PSO_EW_S, PSO_NS_W, PSO_NS_E, }; /* The type of pylon to draw at each PPP */ static const uint8 pylon_sprites[] = { PSO_EW_N, PSO_Y_NE, PSO_NS_E, PSO_X_SE, PSO_EW_S, PSO_Y_SW, PSO_NS_W, PSO_X_NW, }; /** * Offset for wire sprites from the base wire sprite. */ enum WireSpriteOffset { WSO_X_SHORT, WSO_Y_SHORT, WSO_EW_SHORT, WSO_NS_SHORT, WSO_X_SHORT_DOWN, WSO_Y_SHORT_UP, WSO_X_SHORT_UP, WSO_Y_SHORT_DOWN, WSO_X_SW, WSO_Y_SE, WSO_EW_E, WSO_NS_S, WSO_X_SW_DOWN, WSO_Y_SE_UP, WSO_X_SW_UP, WSO_Y_SE_DOWN, WSO_X_NE, WSO_Y_NW, WSO_EW_W, WSO_NS_N, WSO_X_NE_DOWN, WSO_Y_NW_UP, WSO_X_NE_UP, WSO_Y_NW_DOWN, WSO_ENTRANCE_NE, WSO_ENTRANCE_SE, WSO_ENTRANCE_SW, WSO_ENTRANCE_NW, }; struct SortableSpriteStruct { uint8 image_offset; int8 x_offset; int8 y_offset; int8 x_size; int8 y_size; int8 z_size; int8 z_offset; }; /** Distance between wire and rail */ static const uint ELRAIL_ELEVATION = 10; /** Wires that a draw one level higher than the north corner. */ static const uint ELRAIL_ELEVRAISE = ELRAIL_ELEVATION + TILE_HEIGHT; static const SortableSpriteStruct CatenarySpriteData[] = { /* X direction * Flat tiles: * Wires */ { WSO_X_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! 0: Wire in X direction, pylon on the SW end only { WSO_X_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! 1: Wire in X direction, pylon on the NE end { WSO_X_SHORT, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! 2: Wire in X direction, pylon on both ends /* "up" tiles * Wires */ { WSO_X_SW_UP, 0, 7, 15, 8, 1, ELRAIL_ELEVRAISE }, //! 3: Wire in X pitch up, pylon on the SW end only { WSO_X_NE_UP, 0, 7, 15, 8, 1, ELRAIL_ELEVRAISE }, //! 4: Wire in X pitch up, pylon on the NE end { WSO_X_SHORT_UP, 0, 7, 15, 8, 1, ELRAIL_ELEVRAISE }, //! 5: Wire in X pitch up, pylon on both ends /* "down" tiles * Wires */ { WSO_X_SW_DOWN, 0, 7, 15, 8, 1, ELRAIL_ELEVATION }, //! 6: Wire in X pitch down, pylon on the SW end { WSO_X_NE_DOWN, 0, 7, 15, 8, 1, ELRAIL_ELEVATION }, //! 7: Wire in X pitch down, pylon on the NE end { WSO_X_SHORT_DOWN, 0, 7, 15, 8, 1, ELRAIL_ELEVATION }, //! 8: Wire in X pitch down, pylon on both ends /* Y direction * Flat tiles: * Wires */ { WSO_Y_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! 9: Wire in Y direction, pylon on the SE end only { WSO_Y_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //!10: Wire in Y direction, pylon on the NW end { WSO_Y_SHORT, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //!11: Wire in Y direction, pylon on both ends /* "up" tiles * Wires */ { WSO_Y_SE_UP, 7, 0, 8, 15, 1, ELRAIL_ELEVRAISE }, //!12: Wire in Y pitch up, pylon on the SE end only { WSO_Y_NW_UP, 7, 0, 8, 15, 1, ELRAIL_ELEVRAISE }, //!13: Wire in Y pitch up, pylon on the NW end { WSO_Y_SHORT_UP, 7, 0, 8, 15, 1, ELRAIL_ELEVRAISE }, //!14: Wire in Y pitch up, pylon on both ends /* "down" tiles * Wires */ { WSO_Y_SE_DOWN, 7, 0, 8, 15, 1, ELRAIL_ELEVATION }, //!15: Wire in Y pitch down, pylon on the SE end { WSO_Y_NW_DOWN, 7, 0, 8, 15, 1, ELRAIL_ELEVATION }, //!16: Wire in Y pitch down, pylon on the NW end { WSO_Y_SHORT_DOWN, 7, 0, 8, 15, 1, ELRAIL_ELEVATION }, //!17: Wire in Y pitch down, pylon on both ends /* NS Direction */ { WSO_NS_SHORT, 8, 0, 8, 8, 1, ELRAIL_ELEVATION }, //!18: LEFT trackbit wire, pylon on both ends { WSO_NS_SHORT, 0, 8, 8, 8, 1, ELRAIL_ELEVATION }, //!19: RIGHT trackbit wire, pylon on both ends { WSO_NS_N, 8, 0, 8, 8, 1, ELRAIL_ELEVATION }, //!20: LEFT trackbit wire, pylon on N end { WSO_NS_N, 0, 8, 8, 8, 1, ELRAIL_ELEVATION }, //!21: RIGHT trackbit wire, pylon on N end { WSO_NS_S, 8, 0, 8, 8, 1, ELRAIL_ELEVATION }, //!22: LEFT trackbit wire, pylon on S end { WSO_NS_S, 0, 8, 8, 8, 1, ELRAIL_ELEVATION }, //!23: RIGHT trackbit wire, pylon on S end /* EW Direction */ { WSO_EW_SHORT, 7, 0, 1, 1, 1, ELRAIL_ELEVATION }, //!24: UPPER trackbit wire, pylon on both ends { WSO_EW_SHORT, 15, 8, 3, 3, 1, ELRAIL_ELEVATION }, //!25: LOWER trackbit wire, pylon on both ends { WSO_EW_W, 7, 0, 1, 1, 1, ELRAIL_ELEVATION }, //!28: UPPER trackbit wire, pylon on both ends { WSO_EW_W, 15, 8, 3, 3, 1, ELRAIL_ELEVATION }, //!29: LOWER trackbit wire, pylon on both ends { WSO_EW_E, 7, 0, 1, 1, 1, ELRAIL_ELEVATION }, //!32: UPPER trackbit wire, pylon on both ends { WSO_EW_E, 15, 8, 3, 3, 1, ELRAIL_ELEVATION } //!33: LOWER trackbit wire, pylon on both ends }; static const SortableSpriteStruct CatenarySpriteData_Depot[] = { { WSO_ENTRANCE_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE depot exit { WSO_ENTRANCE_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! Wire for SE depot exit { WSO_ENTRANCE_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW depot exit { WSO_ENTRANCE_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW depot exit }; static const SortableSpriteStruct CatenarySpriteData_Tunnel[] = { { WSO_ENTRANCE_NE, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for NE tunnel exit { WSO_ENTRANCE_SE, 7, 0, 1, 15, 1, ELRAIL_ELEVATION }, //! Wire for SE tunnel exit { WSO_ENTRANCE_SW, 0, 7, 15, 1, 1, ELRAIL_ELEVATION }, //! Wire for SW tunnel exit { WSO_ENTRANCE_NW, 7, 0, 1, 15, 1, ELRAIL_ELEVATION } //! Wire for NW tunnel exit }; /** * Refers to a certain element of the catenary. * Identifiers for Wires: *
  1. Direction of the wire
  2. *
  3. Slope of the tile for diagonals, placement inside the track for horiz/vertical pieces
  4. *
  5. Place where a pylon shoule be
* Identifiers for Pylons: *
  1. Direction of the wire
  2. *
  3. Slope of the tile
  4. *
  5. Position of the Pylon relative to the track
  6. *
  7. Position of the Pylon inside the tile
*/ enum CatenarySprite { WIRE_X_FLAT_SW, WIRE_X_FLAT_NE, WIRE_X_FLAT_BOTH, WIRE_X_UP_SW, WIRE_X_UP_NE, WIRE_X_UP_BOTH, WIRE_X_DOWN_SW, WIRE_X_DOWN_NE, WIRE_X_DOWN_BOTH, WIRE_Y_FLAT_SE, WIRE_Y_FLAT_NW, WIRE_Y_FLAT_BOTH, WIRE_Y_UP_SE, WIRE_Y_UP_NW, WIRE_Y_UP_BOTH, WIRE_Y_DOWN_SE, WIRE_Y_DOWN_NW, WIRE_Y_DOWN_BOTH, WIRE_NS_W_BOTH, WIRE_NS_E_BOTH, WIRE_NS_W_N, WIRE_NS_E_N, WIRE_NS_W_S, WIRE_NS_E_S, WIRE_EW_N_BOTH, WIRE_EW_S_BOTH, WIRE_EW_N_W, WIRE_EW_S_W, WIRE_EW_N_E, WIRE_EW_S_E, INVALID_CATENARY = 0xFF }; /* Selects a Wire (with white and grey ends) depending on whether: * a) none (should never happen) * b) the first * c) the second * d) both * PCP exists.*/ static const CatenarySprite Wires[5][TRACK_END][4] = { { // Tileh == 0 {INVALID_CATENARY, WIRE_X_FLAT_NE, WIRE_X_FLAT_SW, WIRE_X_FLAT_BOTH}, {INVALID_CATENARY, WIRE_Y_FLAT_SE, WIRE_Y_FLAT_NW, WIRE_Y_FLAT_BOTH}, {INVALID_CATENARY, WIRE_EW_N_W, WIRE_EW_N_E, WIRE_EW_N_BOTH}, {INVALID_CATENARY, WIRE_EW_S_E, WIRE_EW_S_W, WIRE_EW_S_BOTH}, {INVALID_CATENARY, WIRE_NS_W_S, WIRE_NS_W_N, WIRE_NS_W_BOTH}, {INVALID_CATENARY, WIRE_NS_E_N, WIRE_NS_E_S, WIRE_NS_E_BOTH}, }, { // Tileh == 3 {INVALID_CATENARY, WIRE_X_UP_NE, WIRE_X_UP_SW, WIRE_X_UP_BOTH}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, }, { // Tileh == 6 {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, WIRE_Y_UP_SE, WIRE_Y_UP_NW, WIRE_Y_UP_BOTH}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, }, { // Tileh == 9 {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, WIRE_Y_DOWN_SE, WIRE_Y_DOWN_NW, WIRE_Y_DOWN_BOTH}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, }, { // Tileh == 12 {INVALID_CATENARY, WIRE_X_DOWN_NE, WIRE_X_DOWN_SW, WIRE_X_DOWN_BOTH}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, {INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY, INVALID_CATENARY}, } }; #endif /* ELRAIL_DATA_H */ openttd-1.5.3/src/table/window_settings.ini0000644000000000000000000000307512627373436017523 0ustar rootroot; $Id: window_settings.ini 25295 2013-05-26 19:30:31Z frosch $ ; ; 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 . ; [pre-amble] static const SettingDesc _window_settings[] = { [post-amble] }; [templates] SDT_BOOL = SDT_BOOL($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat), SDT_END = SDT_END() [defaults] base = WindowDesc flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC guiflags = 0 interval = 0 str = STR_NULL strhelp = STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT strval = STR_NULL proc = NULL load = NULL from = 0 to = SL_MAX_VERSION cat = SC_ADVANCED [SDT_BOOL] var = pref_sticky def = false [SDT_VAR] var = pref_width type = SLE_INT16 def = 0 min = 0 max = 32000 [SDT_VAR] var = pref_height type = SLE_INT16 def = 0 min = 0 max = 32000 [SDT_END] }; openttd-1.5.3/src/table/strgen_tables.h0000644000000000000000000003261012627373436016575 0ustar rootroot/* $Id: strgen_tables.h 26050 2013-11-22 21:43:47Z rubidium $ */ /* * 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 table/strgen_tables.h Tables of commands for strgen */ #include "../core/enum_type.hpp" enum CmdFlags { C_NONE = 0x0, ///< Nothing special about this command C_DONTCOUNT = 0x1, ///< These commands aren't counted for comparison C_CASE = 0x2, ///< These commands support cases C_GENDER = 0x4, ///< These commands support genders }; DECLARE_ENUM_AS_BIT_SET(CmdFlags) struct Buffer; typedef void (*ParseCmdProc)(Buffer *buffer, char *buf, int value); struct CmdStruct { const char *cmd; ParseCmdProc proc; long value; uint8 consumes; CmdFlags flags; }; extern void EmitSingleChar(Buffer *buffer, char *buf, int value); extern void EmitPlural(Buffer *buffer, char *buf, int value); extern void EmitGender(Buffer *buffer, char *buf, int value); static const CmdStruct _cmd_structs[] = { /* Font size */ {"TINY_FONT", EmitSingleChar, SCC_TINYFONT, 0, C_NONE}, {"BIG_FONT", EmitSingleChar, SCC_BIGFONT, 0, C_NONE}, /* Colours */ {"BLUE", EmitSingleChar, SCC_BLUE, 0, C_DONTCOUNT}, {"SILVER", EmitSingleChar, SCC_SILVER, 0, C_DONTCOUNT}, {"GOLD", EmitSingleChar, SCC_GOLD, 0, C_DONTCOUNT}, {"RED", EmitSingleChar, SCC_RED, 0, C_DONTCOUNT}, {"PURPLE", EmitSingleChar, SCC_PURPLE, 0, C_DONTCOUNT}, {"LTBROWN", EmitSingleChar, SCC_LTBROWN, 0, C_DONTCOUNT}, {"ORANGE", EmitSingleChar, SCC_ORANGE, 0, C_DONTCOUNT}, {"GREEN", EmitSingleChar, SCC_GREEN, 0, C_DONTCOUNT}, {"YELLOW", EmitSingleChar, SCC_YELLOW, 0, C_DONTCOUNT}, {"DKGREEN", EmitSingleChar, SCC_DKGREEN, 0, C_DONTCOUNT}, {"CREAM", EmitSingleChar, SCC_CREAM, 0, C_DONTCOUNT}, {"BROWN", EmitSingleChar, SCC_BROWN, 0, C_DONTCOUNT}, {"WHITE", EmitSingleChar, SCC_WHITE, 0, C_DONTCOUNT}, {"LTBLUE", EmitSingleChar, SCC_LTBLUE, 0, C_DONTCOUNT}, {"GRAY", EmitSingleChar, SCC_GRAY, 0, C_DONTCOUNT}, {"DKBLUE", EmitSingleChar, SCC_DKBLUE, 0, C_DONTCOUNT}, {"BLACK", EmitSingleChar, SCC_BLACK, 0, C_DONTCOUNT}, {"REV", EmitSingleChar, SCC_REVISION, 0, C_NONE}, // openttd revision string {"STRING1", EmitSingleChar, SCC_STRING1, 2, C_CASE | C_GENDER}, // included string that consumes the string id and ONE argument {"STRING2", EmitSingleChar, SCC_STRING2, 3, C_CASE | C_GENDER}, // included string that consumes the string id and TWO arguments {"STRING3", EmitSingleChar, SCC_STRING3, 4, C_CASE | C_GENDER}, // included string that consumes the string id and THREE arguments {"STRING4", EmitSingleChar, SCC_STRING4, 5, C_CASE | C_GENDER}, // included string that consumes the string id and FOUR arguments {"STRING5", EmitSingleChar, SCC_STRING5, 6, C_CASE | C_GENDER}, // included string that consumes the string id and FIVE arguments {"STRING6", EmitSingleChar, SCC_STRING6, 7, C_CASE | C_GENDER}, // included string that consumes the string id and SIX arguments {"STRING7", EmitSingleChar, SCC_STRING7, 8, C_CASE | C_GENDER}, // included string that consumes the string id and SEVEN arguments {"STATION_FEATURES", EmitSingleChar, SCC_STATION_FEATURES, 1, C_NONE}, // station features string, icons of the features {"INDUSTRY", EmitSingleChar, SCC_INDUSTRY_NAME, 1, C_CASE | C_GENDER}, // industry, takes an industry #, can have cases {"CARGO_LONG", EmitSingleChar, SCC_CARGO_LONG, 2, C_NONE | C_GENDER}, {"CARGO_SHORT", EmitSingleChar, SCC_CARGO_SHORT, 2, C_NONE}, // short cargo description, only ### tons, or ### litres {"CARGO_TINY", EmitSingleChar, SCC_CARGO_TINY, 2, C_NONE}, // tiny cargo description with only the amount, not a specifier for the amount or the actual cargo name {"CARGO_LIST", EmitSingleChar, SCC_CARGO_LIST, 1, C_CASE}, {"POWER", EmitSingleChar, SCC_POWER, 1, C_NONE}, {"VOLUME_LONG", EmitSingleChar, SCC_VOLUME_LONG, 1, C_NONE}, {"VOLUME_SHORT", EmitSingleChar, SCC_VOLUME_SHORT, 1, C_NONE}, {"WEIGHT_LONG", EmitSingleChar, SCC_WEIGHT_LONG, 1, C_NONE}, {"WEIGHT_SHORT", EmitSingleChar, SCC_WEIGHT_SHORT, 1, C_NONE}, {"FORCE", EmitSingleChar, SCC_FORCE, 1, C_NONE}, {"VELOCITY", EmitSingleChar, SCC_VELOCITY, 1, C_NONE}, {"HEIGHT", EmitSingleChar, SCC_HEIGHT, 1, C_NONE}, {"P", EmitPlural, 0, 0, C_DONTCOUNT}, // plural specifier {"G", EmitGender, 0, 0, C_DONTCOUNT}, // gender specifier {"DATE_TINY", EmitSingleChar, SCC_DATE_TINY, 1, C_NONE}, {"DATE_SHORT", EmitSingleChar, SCC_DATE_SHORT, 1, C_CASE}, {"DATE_LONG", EmitSingleChar, SCC_DATE_LONG, 1, C_CASE}, {"DATE_ISO", EmitSingleChar, SCC_DATE_ISO, 1, C_NONE}, {"STRING", EmitSingleChar, SCC_STRING, 1, C_CASE | C_GENDER}, {"RAW_STRING", EmitSingleChar, SCC_RAW_STRING_POINTER, 1, C_NONE | C_GENDER}, /* Numbers */ {"COMMA", EmitSingleChar, SCC_COMMA, 1, C_NONE}, // Number with comma {"DECIMAL", EmitSingleChar, SCC_DECIMAL, 2, C_NONE}, // Number with comma and fractional part. Second parameter is number of fractional digits, first parameter is number times 10**(second parameter). {"NUM", EmitSingleChar, SCC_NUM, 1, C_NONE}, // Signed number {"ZEROFILL_NUM", EmitSingleChar, SCC_ZEROFILL_NUM, 2, C_NONE}, // Unsigned number with zero fill, e.g. "02". First parameter is number, second minimum length {"BYTES", EmitSingleChar, SCC_BYTES, 1, C_NONE}, // Unsigned number with "bytes", i.e. "1.02 MiB or 123 KiB" {"HEX", EmitSingleChar, SCC_HEX, 1, C_NONE}, // Hexadecimally printed number {"CURRENCY_LONG", EmitSingleChar, SCC_CURRENCY_LONG, 1, C_NONE}, {"CURRENCY_SHORT", EmitSingleChar, SCC_CURRENCY_SHORT, 1, C_NONE}, // compact currency {"WAYPOINT", EmitSingleChar, SCC_WAYPOINT_NAME, 1, C_NONE | C_GENDER}, // waypoint name {"STATION", EmitSingleChar, SCC_STATION_NAME, 1, C_NONE | C_GENDER}, {"DEPOT", EmitSingleChar, SCC_DEPOT_NAME, 2, C_NONE | C_GENDER}, {"TOWN", EmitSingleChar, SCC_TOWN_NAME, 1, C_NONE | C_GENDER}, {"GROUP", EmitSingleChar, SCC_GROUP_NAME, 1, C_NONE | C_GENDER}, {"SIGN", EmitSingleChar, SCC_SIGN_NAME, 1, C_NONE | C_GENDER}, {"ENGINE", EmitSingleChar, SCC_ENGINE_NAME, 1, C_NONE | C_GENDER}, {"VEHICLE", EmitSingleChar, SCC_VEHICLE_NAME, 1, C_NONE | C_GENDER}, {"COMPANY", EmitSingleChar, SCC_COMPANY_NAME, 1, C_NONE | C_GENDER}, {"COMPANY_NUM", EmitSingleChar, SCC_COMPANY_NUM, 1, C_NONE}, {"PRESIDENT_NAME", EmitSingleChar, SCC_PRESIDENT_NAME, 1, C_NONE | C_GENDER}, {"", EmitSingleChar, '\n', 0, C_DONTCOUNT}, {"{", EmitSingleChar, '{', 0, C_DONTCOUNT}, {"UP_ARROW", EmitSingleChar, SCC_UP_ARROW, 0, C_DONTCOUNT}, {"SMALL_UP_ARROW", EmitSingleChar, SCC_SMALL_UP_ARROW, 0, C_DONTCOUNT}, {"SMALL_DOWN_ARROW", EmitSingleChar, SCC_SMALL_DOWN_ARROW, 0, C_DONTCOUNT}, {"TRAIN", EmitSingleChar, SCC_TRAIN, 0, C_DONTCOUNT}, {"LORRY", EmitSingleChar, SCC_LORRY, 0, C_DONTCOUNT}, {"BUS", EmitSingleChar, SCC_BUS, 0, C_DONTCOUNT}, {"PLANE", EmitSingleChar, SCC_PLANE, 0, C_DONTCOUNT}, {"SHIP", EmitSingleChar, SCC_SHIP, 0, C_DONTCOUNT}, {"NBSP", EmitSingleChar, 0xA0, 0, C_DONTCOUNT}, {"COPYRIGHT", EmitSingleChar, 0xA9, 0, C_DONTCOUNT}, {"DOWN_ARROW", EmitSingleChar, SCC_DOWN_ARROW, 0, C_DONTCOUNT}, {"CHECKMARK", EmitSingleChar, SCC_CHECKMARK, 0, C_DONTCOUNT}, {"CROSS", EmitSingleChar, SCC_CROSS, 0, C_DONTCOUNT}, {"RIGHT_ARROW", EmitSingleChar, SCC_RIGHT_ARROW, 0, C_DONTCOUNT}, {"SMALL_LEFT_ARROW", EmitSingleChar, SCC_LESS_THAN, 0, C_DONTCOUNT}, {"SMALL_RIGHT_ARROW", EmitSingleChar, SCC_GREATER_THAN, 0, C_DONTCOUNT}, /* The following are directional formatting codes used to get the RTL strings right: * http://www.unicode.org/unicode/reports/tr9/#Directional_Formatting_Codes */ {"LRM", EmitSingleChar, CHAR_TD_LRM, 0, C_DONTCOUNT}, {"RLM", EmitSingleChar, CHAR_TD_RLM, 0, C_DONTCOUNT}, {"LRE", EmitSingleChar, CHAR_TD_LRE, 0, C_DONTCOUNT}, {"RLE", EmitSingleChar, CHAR_TD_RLE, 0, C_DONTCOUNT}, {"LRO", EmitSingleChar, CHAR_TD_LRO, 0, C_DONTCOUNT}, {"RLO", EmitSingleChar, CHAR_TD_RLO, 0, C_DONTCOUNT}, {"PDF", EmitSingleChar, CHAR_TD_PDF, 0, C_DONTCOUNT}, }; /** Description of a plural form */ struct PluralForm { int plural_count; ///< The number of plural forms const char *description; ///< Human readable description of the form const char *names; ///< Plural names }; /** The maximum number of plurals. */ static const int MAX_PLURALS = 5; /** All plural forms used */ static const PluralForm _plural_forms[] = { { 2, "Two forms: special case for 1.", "\"1\" \"other\"" }, { 1, "Only one form.", "\"other\"" }, { 2, "Two forms: special case for 0 to 1.", "\"0..1\" \"other\"" }, { 3, "Three forms: special cases for 0, and numbers ending in 1 except when ending in 11.", "\"1,21,31,...\" \"other\" \"0\"" }, { 5, "Five forms: special cases for 1, 2, 3 to 6, and 7 to 10.", "\"1\" \"2\" \"3..6\" \"7..10\" \"other\"" }, { 3, "Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 9 except when ending in 12 to 19.", "\"1,21,31,...\" \"2..9,22..29,32..39,...\" \"other\"" }, { 3, "Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 4 except when ending in 12 to 14.", "\"1,21,31,...\" \"2..4,22..24,32..34,...\" \"other\"" }, { 3, "Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14.", "\"1\" \"2..4,22..24,32..34,...\" \"other\"" }, { 4, "Four forms: special cases for numbers ending in 01, 02, and 03 to 04.", "\"1,101,201,...\" \"2,102,202,...\" \"3..4,103..104,203..204,...\" \"other\"" }, { 2, "Two forms: special case for numbers ending in 1 except when ending in 11.", "\"1,21,31,...\" \"other\"" }, { 3, "Three forms: special cases for 1, and 2 to 4.", "\"1\" \"2..4\" \"other\"" }, { 2, "Two forms: cases for numbers ending with a consonant, and with a vowel.", "\"yeong,il,sam,yuk,chil,pal\" \"i,sa,o,gu\"" }, { 4, "Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.", "\"1\" \"0,2..10,102..110,202..210,...\" \"11..19,111..119,211..219,...\" \"other\"" }, { 4, "Four forms: special cases for 1 and 11, 2 and 12, 3..10 and 13..19.", "\"1,11\" \"2,12\" \"3..10,13..19\" \"other\"" }, }; /* Flags: * 0 = nothing * t = translator editable * l = ltr/rtl choice * p = plural choice * d = separator char (replace spaces with {NBSP}) * x1 = hexadecimal number of 1 byte * x2 = hexadecimal number of 2 bytes * g = gender * c = cases * a = array, i.e. list of strings */ /** All pragmas used */ static const char * const _pragmas[][4] = { /* name flags default description */ { "name", "0", "", "English name for the language" }, { "ownname", "t", "", "Localised name for the language" }, { "isocode", "0", "", "ISO code for the language" }, { "plural", "tp", "0", "Plural form to use" }, { "textdir", "tl", "ltr", "Text direction. Either ltr (left-to-right) or rtl (right-to-left)" }, { "digitsep", "td", ",", "Digit grouping separator for non-currency numbers" }, { "digitsepcur", "td", ",", "Digit grouping separator for currency numbers" }, { "decimalsep", "td", ".", "Decimal separator" }, { "winlangid", "x2", "0x0000", "Language ID for Windows" }, { "grflangid", "x1", "0x00", "Language ID for NewGRFs" }, { "gender", "tag", "", "List of genders" }, { "case", "tac", "", "List of cases" }, }; openttd-1.5.3/src/table/autorail.h0000644000000000000000000001466312627373436015571 0ustar rootroot/* $Id: autorail.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 autorail.h Highlight/sprite information for autorail. */ /* Rail selection types (directions): * / \ / \ / \ / \ / \ / \ * / /\ /\ \ /===\ / \ /| \ / |\ * \/ / \ \/ \ / \===/ \| / \ |/ * \ / \ / \ / \ / \ / \ / * 0 1 2 3 4 5 */ /* mark invalid tiles red */ #define RED(c) -c /* table maps each of the six rail directions and tileh combinations to a sprite * invalid entries are required to make sure that this array can be quickly accessed */ static const int _AutorailTilehSprite[][6] = { /* type 0 1 2 3 4 5 */ { 0, 8, 16, 25, 34, 42 }, // tileh = 0 { 5, 13, RED(22), RED(31), 35, 42 }, // tileh = 1 { 5, 10, 16, 26, RED(38), RED(46) }, // tileh = 2 { 5, 9, RED(23), 26, 35, RED(46) }, // tileh = 3 { 2, 10, RED(19), RED(28), 34, 43 }, // tileh = 4 { 1, 9, 17, 26, 35, 43 }, // tileh = 5 { 1, 10, RED(20), 26, RED(38), 43 }, // tileh = 6 { 1, 9, 17, 26, 35, 43 }, // tileh = 7 { 2, 13, 17, 25, RED(40), RED(48) }, // tileh = 8 { 1, 13, 17, RED(32), 35, RED(48) }, // tileh = 9 { 1, 9, 17, 26, 35, 43 }, // tileh = 10 { 1, 9, 17, 26, 35, 43 }, // tileh = 11 { 2, 9, 17, RED(29), RED(40), 43 }, // tileh = 12 { 1, 9, 17, 26, 35, 43 }, // tileh = 13 { 1, 9, 17, 26, 35, 43 }, // tileh = 14 { 0, 1, 2, 3, 4, 5 }, // invalid (15) { 0, 1, 2, 3, 4, 5 }, // invalid (16) { 0, 1, 2, 3, 4, 5 }, // invalid (17) { 0, 1, 2, 3, 4, 5 }, // invalid (18) { 0, 1, 2, 3, 4, 5 }, // invalid (19) { 0, 1, 2, 3, 4, 5 }, // invalid (20) { 0, 1, 2, 3, 4, 5 }, // invalid (21) { 0, 1, 2, 3, 4, 5 }, // invalid (22) { 6, 11, 17, 27, RED(39), RED(47) }, // tileh = 23 { 0, 1, 2, 3, 4, 5 }, // invalid (24) { 0, 1, 2, 3, 4, 5 }, // invalid (25) { 0, 1, 2, 3, 4, 5 }, // invalid (26) { 7, 15, RED(24), RED(33), 36, 44 }, // tileh = 27 { 0, 1, 2, 3, 4, 5 }, // invalid (28) { 3, 14, 18, 26, RED(41), RED(49) }, // tileh = 29 { 4, 12, RED(21), RED(30), 37, 45 } // tileh = 30 }; #undef RED /* maps each pixel of a tile (16x16) to a selection type * (0,0) is the top corner, (16,16) the bottom corner */ static const HighLightStyle _autorail_piece[][16] = { { HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR }, { HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR }, { HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR }, { HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR }, { HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR }, { HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_HU, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR, HT_DIR_VR }, { HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y }, { HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_X, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y }, { HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_X, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y }, { HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y, HT_DIR_Y }, { HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL }, { HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL }, { HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL }, { HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL }, { HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL }, { HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_VL, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_X, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL, HT_DIR_HL } }; openttd-1.5.3/src/table/control_codes.h0000644000000000000000000001510212627373436016573 0ustar rootroot/* $Id: control_codes.h 26244 2014-01-12 18:01:33Z frosch $ */ /* * 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 control_codes.h Control codes that are embedded in the translation strings. */ #ifndef CONTROL_CODES_H #define CONTROL_CODES_H /** * List of string control codes used for string formatting, displaying, and * by strgen to generate the language files. */ enum StringControlCode { SCC_CONTROL_START = 0xE000, SCC_CONTROL_END = 0xE1FF, SCC_SPRITE_START = 0xE200, SCC_SPRITE_END = SCC_SPRITE_START + 0xFF, /* This must be the first entry. It's encoded in strings that are saved. */ SCC_ENCODED = SCC_CONTROL_START, /* Display control codes */ SCC_TINYFONT, ///< Switch to small font SCC_BIGFONT, ///< Switch to large font /* Formatting control codes */ SCC_REVISION, SCC_COMPANY_NUM, SCC_STATION_FEATURES, SCC_INDUSTRY_NAME, SCC_WAYPOINT_NAME, SCC_STATION_NAME, SCC_DEPOT_NAME, SCC_TOWN_NAME, SCC_GROUP_NAME, SCC_VEHICLE_NAME, SCC_SIGN_NAME, SCC_COMPANY_NAME, SCC_PRESIDENT_NAME, SCC_ENGINE_NAME, SCC_CURRENCY_SHORT, SCC_CURRENCY_LONG, SCC_CARGO_LONG, SCC_CARGO_SHORT, SCC_CARGO_TINY, SCC_CARGO_LIST, SCC_POWER, SCC_VOLUME_LONG, SCC_VOLUME_SHORT, SCC_WEIGHT_LONG, SCC_WEIGHT_SHORT, SCC_FORCE, SCC_VELOCITY, SCC_HEIGHT, SCC_DATE_TINY, SCC_DATE_SHORT, SCC_DATE_LONG, SCC_DATE_ISO, /* Must be consecutive */ SCC_STRING1, SCC_STRING2, SCC_STRING3, SCC_STRING4, SCC_STRING5, SCC_STRING6, SCC_STRING7, SCC_STRING, SCC_COMMA, SCC_DECIMAL, SCC_NUM, SCC_ZEROFILL_NUM, SCC_HEX, SCC_BYTES, SCC_RAW_STRING_POINTER, SCC_PLURAL_LIST, SCC_GENDER_LIST, SCC_GENDER_INDEX, SCC_ARG_INDEX, SCC_SET_CASE, SCC_SWITCH_CASE, /* Colour codes */ SCC_BLUE, SCC_SILVER, SCC_GOLD, SCC_RED, SCC_PURPLE, SCC_LTBROWN, SCC_ORANGE, SCC_GREEN, SCC_YELLOW, SCC_DKGREEN, SCC_CREAM, SCC_BROWN, SCC_WHITE, SCC_LTBLUE, SCC_GRAY, SCC_DKBLUE, SCC_BLACK, SCC_PREVIOUS_COLOUR, /** * The next variables are part of a NewGRF subsystem for creating text strings. * It uses a "stack" of bytes and reads from there. */ SCC_NEWGRF_FIRST, SCC_NEWGRF_PRINT_DWORD_SIGNED = SCC_NEWGRF_FIRST, ///< Read 4 bytes from the stack SCC_NEWGRF_PRINT_WORD_SIGNED, ///< Read 2 bytes from the stack as signed value SCC_NEWGRF_PRINT_BYTE_SIGNED, ///< Read 1 byte from the stack as signed value SCC_NEWGRF_PRINT_WORD_UNSIGNED, ///< Read 2 bytes from the stack as unsigned value SCC_NEWGRF_PRINT_DWORD_CURRENCY, ///< Read 4 bytes from the stack as currency SCC_NEWGRF_PRINT_WORD_STRING_ID, ///< Read 2 bytes from the stack as String ID SCC_NEWGRF_PRINT_WORD_DATE_LONG, ///< Read 2 bytes from the stack as base 1920 date SCC_NEWGRF_PRINT_WORD_DATE_SHORT, ///< Read 2 bytes from the stack as base 1920 date SCC_NEWGRF_PRINT_WORD_SPEED, ///< Read 2 bytes from the stack as signed speed SCC_NEWGRF_PRINT_WORD_VOLUME_LONG, ///< Read 2 bytes from the stack as long signed volume SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG, ///< Read 2 bytes from the stack as long unsigned weight SCC_NEWGRF_PRINT_WORD_STATION_NAME, ///< Read 2 bytes from the stack as station name SCC_NEWGRF_PRINT_QWORD_CURRENCY, ///< Read 8 bytes from the stack as currency SCC_NEWGRF_PRINT_BYTE_HEX, ///< Read 1 byte from the stack and print it as hex SCC_NEWGRF_PRINT_WORD_HEX, ///< Read 2 bytes from the stack and print it as hex SCC_NEWGRF_PRINT_DWORD_HEX, ///< Read 4 bytes from the stack and print it as hex SCC_NEWGRF_PRINT_QWORD_HEX, ///< Read 8 bytes from the stack and print it as hex SCC_NEWGRF_PRINT_DWORD_DATE_LONG, ///< Read 4 bytes from the stack as base 0 date SCC_NEWGRF_PRINT_DWORD_DATE_SHORT, ///< Read 4 bytes from the stack as base 0 date SCC_NEWGRF_PRINT_WORD_POWER, ///< Read 2 bytes from the stack as unsigned power SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT, ///< Read 2 bytes from the stack as short signed volume SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT, ///< Read 2 bytes from the stack as short unsigned weight SCC_NEWGRF_PRINT_WORD_CARGO_LONG, ///< Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount SCC_NEWGRF_PRINT_WORD_CARGO_SHORT, ///< Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount SCC_NEWGRF_PRINT_WORD_CARGO_TINY, ///< Read 2 + 2 bytes from the stack as cargo type (translated) and unsigned cargo amount SCC_NEWGRF_PUSH_WORD, ///< Pushes 2 bytes onto the stack SCC_NEWGRF_UNPRINT, ///< "Unprints" the given number of bytes from the string SCC_NEWGRF_DISCARD_WORD, ///< Discard the next two bytes SCC_NEWGRF_ROTATE_TOP_4_WORDS, ///< Rotate the top 4 words of the stack (W4 W1 W2 W3) SCC_NEWGRF_LAST = SCC_NEWGRF_ROTATE_TOP_4_WORDS, SCC_NEWGRF_STRINL, ///< Inline another string at the current position, StringID is encoded in the string /* Special printable symbols. * These are mapped to the original glyphs */ SCC_LESS_THAN = SCC_SPRITE_START + 0x3C, SCC_GREATER_THAN = SCC_SPRITE_START + 0x3E, SCC_UP_ARROW = SCC_SPRITE_START + 0xA0, SCC_DOWN_ARROW = SCC_SPRITE_START + 0xAA, SCC_CHECKMARK = SCC_SPRITE_START + 0xAC, SCC_CROSS = SCC_SPRITE_START + 0xAD, SCC_RIGHT_ARROW = SCC_SPRITE_START + 0xAF, SCC_TRAIN = SCC_SPRITE_START + 0xB4, SCC_LORRY = SCC_SPRITE_START + 0xB5, SCC_BUS = SCC_SPRITE_START + 0xB6, SCC_PLANE = SCC_SPRITE_START + 0xB7, SCC_SHIP = SCC_SPRITE_START + 0xB8, SCC_SUPERSCRIPT_M1 = SCC_SPRITE_START + 0xB9, SCC_SMALL_UP_ARROW = SCC_SPRITE_START + 0xBC, SCC_SMALL_DOWN_ARROW = SCC_SPRITE_START + 0xBD, }; #endif /* CONTROL_CODES_H */ openttd-1.5.3/src/table/clear_land.h0000644000000000000000000000430612627373436016026 0ustar rootroot/* $Id: clear_land.h 23188 2011-11-11 18:01:41Z yexo $ */ /* * 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 clear_land.h Tables with sprites for clear land and fences. */ static const SpriteID _landscape_clear_sprites_rough[8] = { SPR_FLAT_ROUGH_LAND, SPR_FLAT_ROUGH_LAND_1, SPR_FLAT_ROUGH_LAND_2, SPR_FLAT_ROUGH_LAND_3, SPR_FLAT_ROUGH_LAND_4, SPR_FLAT_ROUGH_LAND, SPR_FLAT_ROUGH_LAND_1, SPR_FLAT_ROUGH_LAND_2, }; static const byte _fence_mod_by_tileh_sw[32] = { 0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 0, 0, 2, 4, 4, 0, 2, 4, 2, 0, 2, 4, 0, }; static const byte _fence_mod_by_tileh_se[32] = { 1, 1, 5, 5, 3, 3, 1, 1, 1, 1, 5, 5, 3, 3, 1, 1, 1, 1, 5, 5, 3, 3, 1, 5, 1, 1, 5, 5, 3, 3, 3, 1, }; static const byte _fence_mod_by_tileh_ne[32] = { 0, 0, 0, 0, 4, 4, 4, 4, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 2, 2, 2, 2, 0, 2, 4, 0, }; static const byte _fence_mod_by_tileh_nw[32] = { 1, 5, 1, 5, 1, 5, 1, 5, 3, 1, 3, 1, 3, 1, 3, 1, 1, 5, 1, 5, 1, 5, 1, 5, 3, 1, 3, 5, 3, 3, 3, 1, }; static const SpriteID _clear_land_fence_sprites[7] = { SPR_HEDGE_BUSHES, SPR_HEDGE_BUSHES_WITH_GATE, SPR_HEDGE_FENCE, SPR_HEDGE_BLOOMBUSH_YELLOW, SPR_HEDGE_BLOOMBUSH_RED, SPR_HEDGE_STONE, }; static const SpriteID _clear_land_sprites_farmland[16] = { SPR_FARMLAND_BARE, SPR_FARMLAND_STATE_1, SPR_FARMLAND_STATE_2, SPR_FARMLAND_STATE_3, SPR_FARMLAND_STATE_4, SPR_FARMLAND_STATE_5, SPR_FARMLAND_STATE_6, SPR_FARMLAND_STATE_7, SPR_FARMLAND_HAYPACKS, }; static const SpriteID _clear_land_sprites_snow_desert[8] = { SPR_FLAT_1_QUART_SNOW_DESERT_TILE, SPR_FLAT_2_QUART_SNOW_DESERT_TILE, SPR_FLAT_3_QUART_SNOW_DESERT_TILE, SPR_FLAT_SNOW_DESERT_TILE, }; openttd-1.5.3/src/table/heightmap_colours.h0000644000000000000000000002042012627373436017451 0ustar rootroot/* $Id: heightmap_colours.h 26930 2014-09-27 14:51:34Z rubidium $ */ /* * 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 heightmap_colours.h The colour tables for heightmaps. */ /** Height map colours for the green colour scheme, ordered by height. */ static const uint32 _green_map_heights[] = { MKCOLOUR(0x59595958), MKCOLOUR(0x59595958), MKCOLOUR(0x59595959), MKCOLOUR(0x5959595A), MKCOLOUR(0x59595A59), MKCOLOUR(0x59595A5A), MKCOLOUR(0x595A5959), MKCOLOUR(0x595A595A), MKCOLOUR(0x595A5A59), MKCOLOUR(0x595A5A5A), MKCOLOUR(0x5A595959), MKCOLOUR(0x5A59595A), MKCOLOUR(0x5A595A59), MKCOLOUR(0x5A595A5A), MKCOLOUR(0x5A5A5959), MKCOLOUR(0x5A5A595A), MKCOLOUR(0x5A5A5A59), MKCOLOUR(0x5A5A5A5A), MKCOLOUR(0x5A5A5A5B), MKCOLOUR(0x5A5A5B5A), MKCOLOUR(0x5A5A5B5B), MKCOLOUR(0x5A5B5A5A), MKCOLOUR(0x5A5B5A5B), MKCOLOUR(0x5A5B5B5A), MKCOLOUR(0x5A5B5B5B), MKCOLOUR(0x5B5A5A5A), MKCOLOUR(0x5B5A5A5B), MKCOLOUR(0x5B5A5B5A), MKCOLOUR(0x5B5A5B5B), MKCOLOUR(0x5B5B5A5A), MKCOLOUR(0x5B5B5A5B), MKCOLOUR(0x5B5B5B5B), MKCOLOUR(0x5B5B5B5C), MKCOLOUR(0x5B5B5C5B), MKCOLOUR(0x5B5B5C5C), MKCOLOUR(0x5B5C5B5B), MKCOLOUR(0x5B5C5B5C), MKCOLOUR(0x5B5C5C5B), MKCOLOUR(0x5B5C5C5C), MKCOLOUR(0x5C5B5B5B), MKCOLOUR(0x5C5B5B5C), MKCOLOUR(0x5C5B5C5B), MKCOLOUR(0x5C5B5C5C), MKCOLOUR(0x5C5C5B5B), MKCOLOUR(0x5C5C5B5C), MKCOLOUR(0x5C5C5C5C), MKCOLOUR(0x5C5C5C5D), MKCOLOUR(0x5C5C5D5C), MKCOLOUR(0x5C5C5D5D), MKCOLOUR(0x5C5D5C5C), MKCOLOUR(0x5C5D5C5D), MKCOLOUR(0x5C5D5D5C), MKCOLOUR(0x5C5D5D5D), MKCOLOUR(0x5D5C5C5C), MKCOLOUR(0x5D5C5C5D), MKCOLOUR(0x5D5C5D5C), MKCOLOUR(0x5D5C5D5D), MKCOLOUR(0x5D5D5C5C), MKCOLOUR(0x5D5D5C5D), MKCOLOUR(0x5D5D5D5D), MKCOLOUR(0x5D5D5D5E), MKCOLOUR(0x5D5D5E5D), MKCOLOUR(0x5D5D5E5E), MKCOLOUR(0x5D5E5D5D), MKCOLOUR(0x5D5E5D5E), MKCOLOUR(0x5D5E5E5D), MKCOLOUR(0x5D5E5E5E), MKCOLOUR(0x5E5D5D5D), MKCOLOUR(0x5E5D5D5E), MKCOLOUR(0x5E5D5E5D), MKCOLOUR(0x5E5D5E5E), MKCOLOUR(0x5E5D5D5D), MKCOLOUR(0x5E5D5D5E), MKCOLOUR(0x5E5E5E5E), MKCOLOUR(0x5E5E5E5F), MKCOLOUR(0x5E5E5F5E), MKCOLOUR(0x5E5E5F5F), MKCOLOUR(0x5E5F5E5E), MKCOLOUR(0x5E5F5E5F), MKCOLOUR(0x5E5F5F5E), MKCOLOUR(0x5E5F5F5F), MKCOLOUR(0x5F5E5E5E), MKCOLOUR(0x5F5E5E5F), MKCOLOUR(0x5F5E5F5E), MKCOLOUR(0x5F5E5F5F), MKCOLOUR(0x5F5F5E5E), MKCOLOUR(0x5F5F5E5F), MKCOLOUR(0x5F5F5F5F), MKCOLOUR(0x5F5F5F1F), MKCOLOUR(0x5F5F1F5F), MKCOLOUR(0x5F5F1F1F), MKCOLOUR(0x5F1F5F1F), MKCOLOUR(0x5F1F1F1F), MKCOLOUR(0x1F5F5F5F), MKCOLOUR(0x1F5F5F1F), MKCOLOUR(0x1F5F1F5F), MKCOLOUR(0x1F5F1F1F), MKCOLOUR(0x1F1F5F5F), MKCOLOUR(0x1F1F5F1F), MKCOLOUR(0x1F1F1F5F), MKCOLOUR(0x1F1F1F1F), MKCOLOUR(0x1F1F1F27), MKCOLOUR(0x1F1F271F), MKCOLOUR(0x1F1F2727), MKCOLOUR(0x1F271F1F), MKCOLOUR(0x1F271F27), MKCOLOUR(0x1F272727), MKCOLOUR(0x271F1F1F), MKCOLOUR(0x271F1F27), MKCOLOUR(0x271F271F), MKCOLOUR(0x271F2727), MKCOLOUR(0x27271F1F), MKCOLOUR(0x27271F27), MKCOLOUR(0x2727271F), MKCOLOUR(0x27272727), }; /** Height map colours for the dark green colour scheme, ordered by height. */ static const uint32 _dark_green_map_heights[] = { MKCOLOUR(0x60606060), MKCOLOUR(0x60606061), MKCOLOUR(0x60606160), MKCOLOUR(0x60606161), MKCOLOUR(0x60616060), MKCOLOUR(0x60616061), MKCOLOUR(0x60616160), MKCOLOUR(0x60616161), MKCOLOUR(0x61606060), MKCOLOUR(0x61606061), MKCOLOUR(0x61606160), MKCOLOUR(0x61606161), MKCOLOUR(0x61616060), MKCOLOUR(0x61616061), MKCOLOUR(0x61616160), MKCOLOUR(0x61616161), MKCOLOUR(0x61616162), MKCOLOUR(0x61616261), MKCOLOUR(0x61616262), MKCOLOUR(0x61626161), MKCOLOUR(0x61626162), MKCOLOUR(0x61626261), MKCOLOUR(0x61626262), MKCOLOUR(0x62616161), MKCOLOUR(0x62616162), MKCOLOUR(0x62616261), MKCOLOUR(0x62616262), MKCOLOUR(0x62626161), MKCOLOUR(0x62626162), MKCOLOUR(0x62626261), MKCOLOUR(0x62626262), MKCOLOUR(0x62626263), MKCOLOUR(0x62626362), MKCOLOUR(0x62626363), MKCOLOUR(0x62636262), MKCOLOUR(0x62636263), MKCOLOUR(0x62636362), MKCOLOUR(0x62636363), MKCOLOUR(0x63626262), MKCOLOUR(0x63626263), MKCOLOUR(0x63626362), MKCOLOUR(0x63626363), MKCOLOUR(0x63636262), MKCOLOUR(0x63636263), MKCOLOUR(0x63636362), MKCOLOUR(0x63636363), MKCOLOUR(0x63636364), MKCOLOUR(0x63636463), MKCOLOUR(0x63636464), MKCOLOUR(0x63646363), MKCOLOUR(0x63646364), MKCOLOUR(0x63646463), MKCOLOUR(0x63646464), MKCOLOUR(0x64636363), MKCOLOUR(0x64636364), MKCOLOUR(0x64636463), MKCOLOUR(0x64636464), MKCOLOUR(0x64646363), MKCOLOUR(0x64646364), MKCOLOUR(0x64646463), MKCOLOUR(0x64646464), MKCOLOUR(0x64646465), MKCOLOUR(0x64646564), MKCOLOUR(0x64646565), MKCOLOUR(0x64656464), MKCOLOUR(0x64656465), MKCOLOUR(0x64656564), MKCOLOUR(0x64656565), MKCOLOUR(0x65646464), MKCOLOUR(0x65646465), MKCOLOUR(0x65646564), MKCOLOUR(0x65646565), MKCOLOUR(0x65656464), MKCOLOUR(0x65656465), MKCOLOUR(0x65656564), MKCOLOUR(0x65656565), MKCOLOUR(0x65656566), MKCOLOUR(0x65656665), MKCOLOUR(0x65656666), MKCOLOUR(0x65666565), MKCOLOUR(0x65666566), MKCOLOUR(0x65666665), MKCOLOUR(0x65666666), MKCOLOUR(0x66656565), MKCOLOUR(0x66656566), MKCOLOUR(0x66656665), MKCOLOUR(0x66656666), MKCOLOUR(0x66666565), MKCOLOUR(0x66666566), MKCOLOUR(0x66666665), MKCOLOUR(0x66666666), MKCOLOUR(0x66666667), MKCOLOUR(0x66666766), MKCOLOUR(0x66666767), MKCOLOUR(0x66676666), MKCOLOUR(0x66676667), MKCOLOUR(0x66676766), MKCOLOUR(0x66676767), MKCOLOUR(0x67676767), }; /** Height map colours for the violet colour scheme, ordered by height. */ static const uint32 _violet_map_heights[] = { MKCOLOUR(0x80808080), MKCOLOUR(0x80808081), MKCOLOUR(0x80808180), MKCOLOUR(0x80808181), MKCOLOUR(0x80818080), MKCOLOUR(0x80818081), MKCOLOUR(0x80818180), MKCOLOUR(0x80818181), MKCOLOUR(0x81808080), MKCOLOUR(0x81808081), MKCOLOUR(0x81808180), MKCOLOUR(0x81808181), MKCOLOUR(0x81818080), MKCOLOUR(0x81818081), MKCOLOUR(0x81818180), MKCOLOUR(0x81818181), MKCOLOUR(0x81818182), MKCOLOUR(0x81818281), MKCOLOUR(0x81818282), MKCOLOUR(0x81828181), MKCOLOUR(0x81828182), MKCOLOUR(0x81828281), MKCOLOUR(0x81828282), MKCOLOUR(0x82818181), MKCOLOUR(0x82818182), MKCOLOUR(0x82818281), MKCOLOUR(0x82818282), MKCOLOUR(0x82828181), MKCOLOUR(0x82828182), MKCOLOUR(0x82828281), MKCOLOUR(0x82828282), MKCOLOUR(0x82828283), MKCOLOUR(0x82828382), MKCOLOUR(0x82828383), MKCOLOUR(0x82838282), MKCOLOUR(0x82838283), MKCOLOUR(0x82838382), MKCOLOUR(0x82838383), MKCOLOUR(0x83828282), MKCOLOUR(0x83828283), MKCOLOUR(0x83828382), MKCOLOUR(0x83828383), MKCOLOUR(0x83838282), MKCOLOUR(0x83838283), MKCOLOUR(0x83838382), MKCOLOUR(0x83838383), MKCOLOUR(0x83838384), MKCOLOUR(0x83838483), MKCOLOUR(0x83838484), MKCOLOUR(0x83848383), MKCOLOUR(0x83848384), MKCOLOUR(0x83848483), MKCOLOUR(0x83848484), MKCOLOUR(0x84838383), MKCOLOUR(0x84838384), MKCOLOUR(0x84838483), MKCOLOUR(0x84838484), MKCOLOUR(0x84848383), MKCOLOUR(0x84848384), MKCOLOUR(0x84848483), MKCOLOUR(0x84848484), MKCOLOUR(0x84848485), MKCOLOUR(0x84848584), MKCOLOUR(0x84848585), MKCOLOUR(0x84858484), MKCOLOUR(0x84858485), MKCOLOUR(0x84858584), MKCOLOUR(0x84858585), MKCOLOUR(0x85848484), MKCOLOUR(0x85848485), MKCOLOUR(0x85848584), MKCOLOUR(0x85848585), MKCOLOUR(0x85858484), MKCOLOUR(0x85858485), MKCOLOUR(0x85858584), MKCOLOUR(0x85858585), MKCOLOUR(0x85858586), MKCOLOUR(0x85858685), MKCOLOUR(0x85858686), MKCOLOUR(0x85868585), MKCOLOUR(0x85868586), MKCOLOUR(0x85868685), MKCOLOUR(0x85868686), MKCOLOUR(0x85868585), MKCOLOUR(0x85868586), MKCOLOUR(0x85868685), MKCOLOUR(0x85868686), MKCOLOUR(0x86868585), MKCOLOUR(0x86868586), MKCOLOUR(0x86868685), MKCOLOUR(0x86868686), MKCOLOUR(0x86868687), MKCOLOUR(0x86868786), MKCOLOUR(0x86868787), MKCOLOUR(0x86878686), MKCOLOUR(0x86878687), MKCOLOUR(0x86878786), MKCOLOUR(0x86878787), MKCOLOUR(0x87868686), MKCOLOUR(0x87868687), MKCOLOUR(0x87868786), MKCOLOUR(0x87868787), MKCOLOUR(0x87878686), MKCOLOUR(0x87878687), MKCOLOUR(0x87878786), MKCOLOUR(0x87878787), }; openttd-1.5.3/src/pbs.h0000644000000000000000000000506712627373442013441 0ustar rootroot/* $Id: pbs.h 24905 2013-01-11 07:39:25Z peter1138 $ */ /* * 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 pbs.h PBS support routines */ #ifndef PBS_H #define PBS_H #include "tile_type.h" #include "direction_type.h" #include "track_type.h" #include "vehicle_type.h" TrackBits GetReservedTrackbits(TileIndex t); void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b); bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations = true); void UnreserveRailTrack(TileIndex tile, Track t); /** This struct contains information about the end of a reserved path. */ struct PBSTileInfo { TileIndex tile; ///< Tile the path ends, INVALID_TILE if no valid path was found. Trackdir trackdir; ///< The reserved trackdir on the tile. bool okay; ///< True if tile is a safe waiting position, false otherwise. /** * Create an empty PBSTileInfo. */ PBSTileInfo() : tile(INVALID_TILE), trackdir(INVALID_TRACKDIR), okay(false) {} /** * Create a PBSTileInfo with given tile, track direction and safe waiting position information. * @param _t The tile where the path ends. * @param _td The reserved track dir on the tile. * @param _okay Whether the tile is a safe waiting point or not. */ PBSTileInfo(TileIndex _t, Trackdir _td, bool _okay) : tile(_t), trackdir(_td), okay(_okay) {} }; PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res = NULL); bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg = false); bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg = false); Train *GetTrainForReservation(TileIndex tile, Track track); /** * Check whether some of tracks is reserved on a tile. * * @param tile the tile * @param tracks the tracks to test * @return true if at least on of tracks is reserved */ static inline bool HasReservedTracks(TileIndex tile, TrackBits tracks) { return (GetReservedTrackbits(tile) & tracks) != TRACK_BIT_NONE; } #endif /* PBS_H */ openttd-1.5.3/src/console.cpp0000644000000000000000000003502212627373445014647 0ustar rootroot/* $Id: console.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 console.cpp Handling of the in-game console. */ #include "stdafx.h" #include "console_internal.h" #include "network/network.h" #include "network/network_func.h" #include "network/network_admin.h" #include "debug.h" #include "console_func.h" #include "settings_type.h" #include #include "safeguards.h" static const uint ICON_TOKEN_COUNT = 20; ///< Maximum number of tokens in one command /* console parser */ IConsoleCmd *_iconsole_cmds; ///< list of registered commands IConsoleAlias *_iconsole_aliases; ///< list of registered aliases FILE *_iconsole_output_file; void IConsoleInit() { _iconsole_output_file = NULL; #ifdef ENABLE_NETWORK /* Initialize network only variables */ _redirect_console_to_client = INVALID_CLIENT_ID; _redirect_console_to_admin = INVALID_ADMIN_ID; #endif IConsoleGUIInit(); IConsoleStdLibRegister(); } static void IConsoleWriteToLogFile(const char *string) { if (_iconsole_output_file != NULL) { /* if there is an console output file ... also print it there */ const char *header = GetLogPrefix(); if ((strlen(header) != 0 && fwrite(header, strlen(header), 1, _iconsole_output_file) != 1) || fwrite(string, strlen(string), 1, _iconsole_output_file) != 1 || fwrite("\n", 1, 1, _iconsole_output_file) != 1) { fclose(_iconsole_output_file); _iconsole_output_file = NULL; IConsolePrintF(CC_DEFAULT, "cannot write to log file"); } } } bool CloseConsoleLogIfActive() { if (_iconsole_output_file != NULL) { IConsolePrintF(CC_DEFAULT, "file output complete"); fclose(_iconsole_output_file); _iconsole_output_file = NULL; return true; } return false; } void IConsoleFree() { IConsoleGUIFree(); CloseConsoleLogIfActive(); } /** * Handle the printing of text entered into the console or redirected there * by any other means. Text can be redirected to other clients in a network game * as well as to a logfile. If the network server is a dedicated server, all activities * are also logged. All lines to print are added to a temporary buffer which can be * used as a history to print them onscreen * @param colour_code the colour of the command. Red in case of errors, etc. * @param string the message entered or output on the console (notice, error, etc.) */ void IConsolePrint(TextColour colour_code, const char *string) { assert(IsValidConsoleColour(colour_code)); char *str; #ifdef ENABLE_NETWORK if (_redirect_console_to_client != INVALID_CLIENT_ID) { /* Redirect the string to the client */ NetworkServerSendRcon(_redirect_console_to_client, colour_code, string); return; } if (_redirect_console_to_admin != INVALID_ADMIN_ID) { NetworkServerSendAdminRcon(_redirect_console_to_admin, colour_code, string); return; } #endif /* Create a copy of the string, strip if of colours and invalid * characters and (when applicable) assign it to the console buffer */ str = stredup(string); str_strip_colours(str); str_validate(str, str + strlen(str)); if (_network_dedicated) { #ifdef ENABLE_NETWORK NetworkAdminConsole("console", str); #endif /* ENABLE_NETWORK */ fprintf(stdout, "%s%s\n", GetLogPrefix(), str); fflush(stdout); IConsoleWriteToLogFile(str); free(str); // free duplicated string since it's not used anymore return; } IConsoleWriteToLogFile(str); IConsoleGUIPrint(colour_code, str); } /** * Handle the printing of text entered into the console or redirected there * by any other means. Uses printf() style format, for more information look * at IConsolePrint() */ void CDECL IConsolePrintF(TextColour colour_code, const char *format, ...) { assert(IsValidConsoleColour(colour_code)); va_list va; char buf[ICON_MAX_STREAMSIZE]; va_start(va, format); vseprintf(buf, lastof(buf), format, va); va_end(va); IConsolePrint(colour_code, buf); } /** * It is possible to print debugging information to the console, * which is achieved by using this function. Can only be used by * debug() in debug.cpp. You need at least a level 2 (developer) for debugging * messages to show up * @param dbg debugging category * @param string debugging message */ void IConsoleDebug(const char *dbg, const char *string) { if (_settings_client.gui.developer <= 1) return; IConsolePrintF(CC_DEBUG, "dbg: [%s] %s", dbg, string); } /** * It is possible to print warnings to the console. These are mostly * errors or mishaps, but non-fatal. You need at least a level 1 (developer) for * debugging messages to show up */ void IConsoleWarning(const char *string) { if (_settings_client.gui.developer == 0) return; IConsolePrintF(CC_WARNING, "WARNING: %s", string); } /** * It is possible to print error information to the console. This can include * game errors, or errors in general you would want the user to notice */ void IConsoleError(const char *string) { IConsolePrintF(CC_ERROR, "ERROR: %s", string); } /** * Change a string into its number representation. Supports * decimal and hexadecimal numbers as well as 'on'/'off' 'true'/'false' * @param *value the variable a successful conversion will be put in * @param *arg the string to be converted * @return Return true on success or false on failure */ bool GetArgumentInteger(uint32 *value, const char *arg) { char *endptr; if (strcmp(arg, "on") == 0 || strcmp(arg, "true") == 0) { *value = 1; return true; } if (strcmp(arg, "off") == 0 || strcmp(arg, "false") == 0) { *value = 0; return true; } *value = strtoul(arg, &endptr, 0); return arg != endptr; } /** * Add an item to an alphabetically sorted list. * @param base first item of the list * @param item_new the item to add */ template void IConsoleAddSorted(T **base, T *item_new) { if (*base == NULL) { *base = item_new; return; } T *item_before = NULL; T *item = *base; /* The list is alphabetically sorted, insert the new item at the correct location */ while (item != NULL) { if (strcmp(item->name, item_new->name) > 0) break; // insert here item_before = item; item = item->next; } if (item_before == NULL) { *base = item_new; } else { item_before->next = item_new; } item_new->next = item; } /** * Remove underscores from a string; the string will be modified! * @param name The string to remove the underscores from. * @return #name. */ char *RemoveUnderscores(char *name) { char *q = name; for (const char *p = name; *p != '\0'; p++) { if (*p != '_') *q++ = *p; } *q = '\0'; return name; } /** * Register a new command to be used in the console * @param name name of the command that will be used * @param proc function that will be called upon execution of command */ void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook) { IConsoleCmd *item_new = MallocT(1); item_new->name = RemoveUnderscores(stredup(name)); item_new->next = NULL; item_new->proc = proc; item_new->hook = hook; IConsoleAddSorted(&_iconsole_cmds, item_new); } /** * Find the command pointed to by its string * @param name command to be found * @return return Cmdstruct of the found command, or NULL on failure */ IConsoleCmd *IConsoleCmdGet(const char *name) { IConsoleCmd *item; for (item = _iconsole_cmds; item != NULL; item = item->next) { if (strcmp(item->name, name) == 0) return item; } return NULL; } /** * Register a an alias for an already existing command in the console * @param name name of the alias that will be used * @param cmd name of the command that 'name' will be alias of */ void IConsoleAliasRegister(const char *name, const char *cmd) { if (IConsoleAliasGet(name) != NULL) { IConsoleError("an alias with this name already exists; insertion aborted"); return; } char *new_alias = RemoveUnderscores(stredup(name)); char *cmd_aliased = stredup(cmd); IConsoleAlias *item_new = MallocT(1); item_new->next = NULL; item_new->cmdline = cmd_aliased; item_new->name = new_alias; IConsoleAddSorted(&_iconsole_aliases, item_new); } /** * Find the alias pointed to by its string * @param name alias to be found * @return return Aliasstruct of the found alias, or NULL on failure */ IConsoleAlias *IConsoleAliasGet(const char *name) { IConsoleAlias *item; for (item = _iconsole_aliases; item != NULL; item = item->next) { if (strcmp(item->name, name) == 0) return item; } return NULL; } /** * An alias is just another name for a command, or for more commands * Execute it as well. * @param *alias is the alias of the command * @param tokencount the number of parameters passed * @param *tokens are the parameters given to the original command (0 is the first param) */ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT]) { char alias_buffer[ICON_MAX_STREAMSIZE] = { '\0' }; char *alias_stream = alias_buffer; DEBUG(console, 6, "Requested command is an alias; parsing..."); for (const char *cmdptr = alias->cmdline; *cmdptr != '\0'; cmdptr++) { switch (*cmdptr) { case '\'': // ' will double for "" alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); break; case ';': // Cmd separator; execute previous and start new command IConsoleCmdExec(alias_buffer); alias_stream = alias_buffer; *alias_stream = '\0'; // Make sure the new command is terminated. cmdptr++; break; case '%': // Some or all parameters cmdptr++; switch (*cmdptr) { case '+': { // All parameters separated: "[param 1]" "[param 2]" for (uint i = 0; i != tokencount; i++) { if (i != 0) alias_stream = strecpy(alias_stream, " ", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, tokens[i], lastof(alias_buffer)); alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); } break; } case '!': { // Merge the parameters to one: "[param 1] [param 2] [param 3...]" alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); for (uint i = 0; i != tokencount; i++) { if (i != 0) alias_stream = strecpy(alias_stream, " ", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, tokens[i], lastof(alias_buffer)); } alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); break; } default: { // One specific parameter: %A = [param 1] %B = [param 2] ... int param = *cmdptr - 'A'; if (param < 0 || param >= tokencount) { IConsoleError("too many or wrong amount of parameters passed to alias, aborting"); IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline); return; } alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); alias_stream = strecpy(alias_stream, tokens[param], lastof(alias_buffer)); alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); break; } } break; default: *alias_stream++ = *cmdptr; *alias_stream = '\0'; break; } if (alias_stream >= lastof(alias_buffer) - 1) { IConsoleError("Requested alias execution would overflow execution buffer"); return; } } IConsoleCmdExec(alias_buffer); } /** * Execute a given command passed to us. First chop it up into * individual tokens (separated by spaces), then execute it if possible * @param cmdstr string to be parsed and executed */ void IConsoleCmdExec(const char *cmdstr) { const char *cmdptr; char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE]; uint t_index, tstream_i; bool longtoken = false; bool foundtoken = false; if (cmdstr[0] == '#') return; // comments for (cmdptr = cmdstr; *cmdptr != '\0'; cmdptr++) { if (!IsValidChar(*cmdptr, CS_ALPHANUMERAL)) { IConsoleError("command contains malformed characters, aborting"); IConsolePrintF(CC_ERROR, "ERROR: command was: '%s'", cmdstr); return; } } DEBUG(console, 4, "Executing cmdline: '%s'", cmdstr); memset(&tokens, 0, sizeof(tokens)); memset(&tokenstream, 0, sizeof(tokenstream)); /* 1. Split up commandline into tokens, separated by spaces, commands * enclosed in "" are taken as one token. We can only go as far as the amount * of characters in our stream or the max amount of tokens we can handle */ for (cmdptr = cmdstr, t_index = 0, tstream_i = 0; *cmdptr != '\0'; cmdptr++) { if (t_index >= lengthof(tokens) || tstream_i >= lengthof(tokenstream)) break; switch (*cmdptr) { case ' ': // Token separator if (!foundtoken) break; if (longtoken) { tokenstream[tstream_i] = *cmdptr; } else { tokenstream[tstream_i] = '\0'; foundtoken = false; } tstream_i++; break; case '"': // Tokens enclosed in "" are one token longtoken = !longtoken; if (!foundtoken) { tokens[t_index++] = &tokenstream[tstream_i]; foundtoken = true; } break; case '\\': // Escape character for "" if (cmdptr[1] == '"' && tstream_i + 1 < lengthof(tokenstream)) { tokenstream[tstream_i++] = *++cmdptr; break; } /* FALL THROUGH */ default: // Normal character tokenstream[tstream_i++] = *cmdptr; if (!foundtoken) { tokens[t_index++] = &tokenstream[tstream_i - 1]; foundtoken = true; } break; } } for (uint i = 0; tokens[i] != NULL; i++) { DEBUG(console, 8, "Token %d is: '%s'", i, tokens[i]); } if (StrEmpty(tokens[0])) return; // don't execute empty commands /* 2. Determine type of command (cmd or alias) and execute * First try commands, then aliases. Execute * the found action taking into account its hooking code */ RemoveUnderscores(tokens[0]); IConsoleCmd *cmd = IConsoleCmdGet(tokens[0]); if (cmd != NULL) { ConsoleHookResult chr = (cmd->hook == NULL ? CHR_ALLOW : cmd->hook(true)); switch (chr) { case CHR_ALLOW: if (!cmd->proc(t_index, tokens)) { // index started with 0 cmd->proc(0, NULL); // if command failed, give help } return; case CHR_DISALLOW: return; case CHR_HIDE: break; } } t_index--; IConsoleAlias *alias = IConsoleAliasGet(tokens[0]); if (alias != NULL) { IConsoleAliasExec(alias, t_index, &tokens[1]); return; } IConsoleError("command not found"); } openttd-1.5.3/src/object.h0000644000000000000000000000207712627373441014120 0ustar rootroot/* $Id: object.h 21846 2011-01-18 23:09:43Z rubidium $ */ /* * 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 object.h Functions related to objects. */ #ifndef OBJECT_H #define OBJECT_H #include "tile_type.h" #include "company_type.h" #include "object_type.h" void UpdateCompanyHQ(TileIndex tile, uint score); void BuildObject(ObjectType type, TileIndex tile, CompanyID owner = OWNER_NONE, struct Town *town = NULL, uint8 view = 0); void PlaceProc_Object(TileIndex tile); void ShowBuildObjectPicker(struct Window *w); #endif /* OBJECT_H */ openttd-1.5.3/src/settings_func.h0000644000000000000000000000377712627373435015540 0ustar rootroot/* $Id: settings_func.h 25291 2013-05-26 19:27:22Z frosch $ */ /* * 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 settings_func.h Functions related to setting/changing the settings. */ #ifndef SETTINGS_FUNC_H #define SETTINGS_FUNC_H #include "core/smallvec_type.hpp" #include "company_type.h" struct IniFile; void IConsoleSetSetting(const char *name, const char *value, bool force_newgame = false); void IConsoleSetSetting(const char *name, int32 value); void IConsoleGetSetting(const char *name, bool force_newgame = false); void IConsoleListSettings(const char *prefilter); void LoadFromConfig(bool minimal = false); void SaveToConfig(); void CheckConfig(); void IniLoadWindowSettings(IniFile *ini, const char *grpname, void *desc); void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc); /* Functions to load and save NewGRF settings to a separate * configuration file, used for presets. */ typedef AutoFreeSmallVector GRFPresetList; void GetGRFPresetList(GRFPresetList *list); struct GRFConfig *LoadGRFPresetFromConfig(const char *config_name); void SaveGRFPresetToConfig(const char *config_name, struct GRFConfig *config); void DeleteGRFPresetFromConfig(const char *config_name); uint GetCompanySettingIndex(const char *name); void SetDefaultCompanySettings(CompanyID cid); #if defined(ENABLE_NETWORK) void SyncCompanySettings(); #else /* ENABLE_NETWORK */ static inline void SyncCompanySettings() {} #endif /* ENABLE_NETWORK */ #endif /* SETTINGS_FUNC_H */ openttd-1.5.3/src/gfxinit.cpp0000644000000000000000000003634412627373436014665 0ustar rootroot/* $Id: gfxinit.cpp 26919 2014-09-25 16:04:02Z peter1138 $ */ /* * 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 gfxinit.cpp Initializing of the (GRF) graphics. */ #include "stdafx.h" #include "fios.h" #include "newgrf.h" #include "3rdparty/md5/md5.h" #include "fontcache.h" #include "gfx_func.h" #include "transparency.h" #include "blitter/factory.hpp" #include "video/video_driver.hpp" #include "window_func.h" /* The type of set we're replacing */ #define SET_TYPE "graphics" #include "base_media_func.h" #include "table/sprites.h" #include "safeguards.h" /** Whether the given NewGRFs must get a palette remap from windows to DOS or not. */ bool _palette_remap_grf[MAX_FILE_SLOTS]; #include "table/landscape_sprite.h" /** Offsets for loading the different "replacement" sprites in the files. */ static const SpriteID * const _landscape_spriteindexes[] = { _landscape_spriteindexes_arctic, _landscape_spriteindexes_tropic, _landscape_spriteindexes_toyland, }; /** * Load an old fashioned GRF file. * @param filename The name of the file to open. * @param load_index The offset of the first sprite. * @param file_index The Fio offset to load the file in. * @return The number of loaded sprites. */ static uint LoadGrfFile(const char *filename, uint load_index, int file_index) { uint load_index_org = load_index; uint sprite_id = 0; FioOpenFile(file_index, filename, BASESET_DIR); DEBUG(sprite, 2, "Reading grf-file '%s'", filename); byte container_ver = GetGRFContainerVersion(); if (container_ver == 0) usererror("Base grf '%s' is corrupt", filename); ReadGRFSpriteOffsets(container_ver); if (container_ver >= 2) { /* Read compression. */ byte compression = FioReadByte(); if (compression != 0) usererror("Unsupported compression format"); } while (LoadNextSprite(load_index, file_index, sprite_id, container_ver)) { load_index++; sprite_id++; if (load_index >= MAX_SPRITES) { usererror("Too many sprites. Recompile with higher MAX_SPRITES value or remove some custom GRF files."); } } DEBUG(sprite, 2, "Currently %i sprites are loaded", load_index); return load_index - load_index_org; } /** * Load an old fashioned GRF file to replace already loaded sprites. * @param filename The name of the file to open. * @param index_tlb The offsets of each of the sprites. * @param file_index The Fio offset to load the file in. * @return The number of loaded sprites. */ static void LoadGrfFileIndexed(const char *filename, const SpriteID *index_tbl, int file_index) { uint start; uint sprite_id = 0; FioOpenFile(file_index, filename, BASESET_DIR); DEBUG(sprite, 2, "Reading indexed grf-file '%s'", filename); byte container_ver = GetGRFContainerVersion(); if (container_ver == 0) usererror("Base grf '%s' is corrupt", filename); ReadGRFSpriteOffsets(container_ver); if (container_ver >= 2) { /* Read compression. */ byte compression = FioReadByte(); if (compression != 0) usererror("Unsupported compression format"); } while ((start = *index_tbl++) != END) { uint end = *index_tbl++; do { bool b = LoadNextSprite(start, file_index, sprite_id, container_ver); assert(b); sprite_id++; } while (++start <= end); } } /** * Checks whether the MD5 checksums of the files are correct. * * @note Also checks sample.cat and other required non-NewGRF GRFs for corruption. */ void CheckExternalFiles() { if (BaseGraphics::GetUsedSet() == NULL || BaseSounds::GetUsedSet() == NULL) return; const GraphicsSet *used_set = BaseGraphics::GetUsedSet(); DEBUG(grf, 1, "Using the %s base graphics set", used_set->name); static const size_t ERROR_MESSAGE_LENGTH = 256; static const size_t MISSING_FILE_MESSAGE_LENGTH = 128; /* Allocate for a message for each missing file and for one error * message per set. */ char error_msg[MISSING_FILE_MESSAGE_LENGTH * (GraphicsSet::NUM_FILES + SoundsSet::NUM_FILES) + 2 * ERROR_MESSAGE_LENGTH]; error_msg[0] = '\0'; char *add_pos = error_msg; const char *last = lastof(error_msg); if (used_set->GetNumInvalid() != 0) { /* Not all files were loaded successfully, see which ones */ add_pos += seprintf(add_pos, last, "Trying to load graphics set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of readme.txt.\n\nThe following files are corrupted or missing:\n", used_set->name); for (uint i = 0; i < GraphicsSet::NUM_FILES; i++) { MD5File::ChecksumResult res = GraphicsSet::CheckMD5(&used_set->files[i], BASESET_DIR); if (res != MD5File::CR_MATCH) add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", used_set->files[i].filename, res == MD5File::CR_MISMATCH ? "corrupt" : "missing", used_set->files[i].missing_warning); } add_pos += seprintf(add_pos, last, "\n"); } const SoundsSet *sounds_set = BaseSounds::GetUsedSet(); if (sounds_set->GetNumInvalid() != 0) { add_pos += seprintf(add_pos, last, "Trying to load sound set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of readme.txt.\n\nThe following files are corrupted or missing:\n", sounds_set->name); assert_compile(SoundsSet::NUM_FILES == 1); /* No need to loop each file, as long as there is only a single * sound file. */ add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", sounds_set->files->filename, SoundsSet::CheckMD5(sounds_set->files, BASESET_DIR) == MD5File::CR_MISMATCH ? "corrupt" : "missing", sounds_set->files->missing_warning); } if (add_pos != error_msg) ShowInfoF("%s", error_msg); } /** Actually load the sprite tables. */ static void LoadSpriteTables() { memset(_palette_remap_grf, 0, sizeof(_palette_remap_grf)); uint i = FIRST_GRF_SLOT; const GraphicsSet *used_set = BaseGraphics::GetUsedSet(); _palette_remap_grf[i] = (PAL_DOS != used_set->palette); LoadGrfFile(used_set->files[GFT_BASE].filename, 0, i++); /* * The second basic file always starts at the given location and does * contain a different amount of sprites depending on the "type"; DOS * has a few sprites less. However, we do not care about those missing * sprites as they are not shown anyway (logos in intro game). */ _palette_remap_grf[i] = (PAL_DOS != used_set->palette); LoadGrfFile(used_set->files[GFT_LOGOS].filename, 4793, i++); /* * Load additional sprites for climates other than temperate. * This overwrites some of the temperate sprites, such as foundations * and the ground sprites. */ if (_settings_game.game_creation.landscape != LT_TEMPERATE) { _palette_remap_grf[i] = (PAL_DOS != used_set->palette); LoadGrfFileIndexed( used_set->files[GFT_ARCTIC + _settings_game.game_creation.landscape - 1].filename, _landscape_spriteindexes[_settings_game.game_creation.landscape - 1], i++ ); } /* Initialize the unicode to sprite mapping table */ InitializeUnicodeGlyphMap(); /* * Load the base NewGRF with OTTD required graphics as first NewGRF. * However, we do not want it to show up in the list of used NewGRFs, * so we have to manually add it, and then remove it later. */ GRFConfig *top = _grfconfig; GRFConfig *master = new GRFConfig(used_set->files[GFT_EXTRA].filename); /* We know the palette of the base set, so if the base NewGRF is not * setting one, use the palette of the base set and not the global * one which might be the wrong palette for this base NewGRF. * The value set here might be overridden via action14 later. */ switch (used_set->palette) { case PAL_DOS: master->palette |= GRFP_GRF_DOS; break; case PAL_WINDOWS: master->palette |= GRFP_GRF_WINDOWS; break; default: break; } FillGRFDetails(master, false, BASESET_DIR); ClrBit(master->flags, GCF_INIT_ONLY); master->next = top; _grfconfig = master; LoadNewGRF(SPR_NEWGRFS_BASE, i); /* Free and remove the top element. */ delete master; _grfconfig = top; } /** * Check blitter needed by NewGRF config and switch if needed. * @return False when nothing changed, true otherwise. */ static bool SwitchNewGRFBlitter() { /* Never switch if the blitter was specified by the user. */ if (!_blitter_autodetected) return false; /* Null driver => dedicated server => do nothing. */ if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return false; /* Get preferred depth. * - depth_wanted_by_base: Depth required by the baseset, i.e. the majority of the sprites. * - depth_wanted_by_grf: Depth required by some NewGRF. * Both can force using a 32bpp blitter. depth_wanted_by_base is used to select * between multiple 32bpp blitters, which perform differently with 8bpp sprites. */ uint depth_wanted_by_base = BaseGraphics::GetUsedSet()->blitter == BLT_32BPP ? 32 : 8; uint depth_wanted_by_grf = _support8bpp == S8BPP_NONE ? 32 : 8; for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND || HasBit(c->flags, GCF_INIT_ONLY)) continue; if (c->palette & GRFP_BLT_32BPP) depth_wanted_by_grf = 32; } /* Search the best blitter. */ static const struct { const char *name; uint animation; ///< 0: no support, 1: do support, 2: both uint min_base_depth, max_base_depth, min_grf_depth, max_grf_depth; } replacement_blitters[] = { #ifdef WITH_SSE { "32bpp-sse4", 0, 32, 32, 8, 32 }, { "32bpp-ssse3", 0, 32, 32, 8, 32 }, { "32bpp-sse2", 0, 32, 32, 8, 32 }, { "32bpp-sse4-anim", 1, 32, 32, 8, 32 }, #endif { "8bpp-optimized", 2, 8, 8, 8, 8 }, { "32bpp-optimized", 0, 8, 32, 8, 32 }, { "32bpp-anim", 1, 8, 32, 8, 32 }, }; const bool animation_wanted = HasBit(_display_opt, DO_FULL_ANIMATION); const char *cur_blitter = BlitterFactory::GetCurrentBlitter()->GetName(); for (uint i = 0; i < lengthof(replacement_blitters); i++) { if (animation_wanted && (replacement_blitters[i].animation == 0)) continue; if (!animation_wanted && (replacement_blitters[i].animation == 1)) continue; if (!IsInsideMM(depth_wanted_by_base, replacement_blitters[i].min_base_depth, replacement_blitters[i].max_base_depth + 1)) continue; if (!IsInsideMM(depth_wanted_by_grf, replacement_blitters[i].min_grf_depth, replacement_blitters[i].max_grf_depth + 1)) continue; const char *repl_blitter = replacement_blitters[i].name; if (strcmp(repl_blitter, cur_blitter) == 0) return false; if (BlitterFactory::GetBlitterFactory(repl_blitter) == NULL) continue; DEBUG(misc, 1, "Switching blitter from '%s' to '%s'... ", cur_blitter, repl_blitter); Blitter *new_blitter = BlitterFactory::SelectBlitter(repl_blitter); if (new_blitter == NULL) NOT_REACHED(); DEBUG(misc, 1, "Successfully switched to %s.", repl_blitter); break; } if (!VideoDriver::GetInstance()->AfterBlitterChange()) { /* Failed to switch blitter, let's hope we can return to the old one. */ if (BlitterFactory::SelectBlitter(cur_blitter) == NULL || !VideoDriver::GetInstance()->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config"); } return true; } /** Check whether we still use the right blitter, or use another (better) one. */ void CheckBlitter() { if (!SwitchNewGRFBlitter()) return; ClearFontCache(); GfxClearSpriteCache(); ReInitAllWindows(); } /** Initialise and load all the sprites. */ void GfxLoadSprites() { DEBUG(sprite, 2, "Loading sprite set %d", _settings_game.game_creation.landscape); SwitchNewGRFBlitter(); ClearFontCache(); GfxInitSpriteMem(); LoadSpriteTables(); GfxInitPalettes(); UpdateCursorSize(); } bool GraphicsSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename) { bool ret = this->BaseSet::FillSetDetails(ini, path, full_filename, false); if (ret) { IniGroup *metadata = ini->GetGroup("metadata"); IniItem *item; fetch_metadata("palette"); this->palette = (*item->value == 'D' || *item->value == 'd') ? PAL_DOS : PAL_WINDOWS; /* Get optional blitter information. */ item = metadata->GetItem("blitter", false); this->blitter = (item != NULL && *item->value == '3') ? BLT_32BPP : BLT_8BPP; } return ret; } /** * Calculate and check the MD5 hash of the supplied GRF. * @param file The file get the hash of. * @param subdir The sub directory to get the files from. * @return * - #CR_MATCH if the MD5 hash matches * - #CR_MISMATCH if the MD5 does not match * - #CR_NO_FILE if the file misses */ /* static */ MD5File::ChecksumResult GraphicsSet::CheckMD5(const MD5File *file, Subdirectory subdir) { size_t size = 0; FILE *f = FioFOpenFile(file->filename, "rb", subdir, &size); if (f == NULL) return MD5File::CR_NO_FILE; size_t max = GRFGetSizeOfDataSection(f); FioFCloseFile(f); return file->CheckMD5(subdir, max); } /** * Calculate and check the MD5 hash of the supplied filename. * @param subdir The sub directory to get the files from * @param max_size Only calculate the hash for this many bytes from the file start. * @return * - #CR_MATCH if the MD5 hash matches * - #CR_MISMATCH if the MD5 does not match * - #CR_NO_FILE if the file misses */ MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir, size_t max_size) const { size_t size; FILE *f = FioFOpenFile(this->filename, "rb", subdir, &size); if (f == NULL) return CR_NO_FILE; size = min(size, max_size); Md5 checksum; uint8 buffer[1024]; uint8 digest[16]; size_t len; while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { size -= len; checksum.Append(buffer, len); } FioFCloseFile(f); checksum.Finish(digest); return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH; } /** Names corresponding to the GraphicsFileType */ static const char * const _graphics_file_names[] = { "base", "logos", "arctic", "tropical", "toyland", "extra" }; /** Implementation */ template /* static */ const char * const *BaseSet::file_names = _graphics_file_names; template /* static */ bool BaseMedia::DetermineBestSet() { if (BaseMedia::used_set != NULL) return true; const Tbase_set *best = NULL; for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { /* Skip unusable sets */ if (c->GetNumMissing() != 0) continue; if (best == NULL || (best->fallback && !c->fallback) || best->valid_files < c->valid_files || (best->valid_files == c->valid_files && ( (best->shortname == c->shortname && best->version < c->version) || (best->palette != PAL_DOS && c->palette == PAL_DOS)))) { best = c; } } BaseMedia::used_set = best; return BaseMedia::used_set != NULL; } template /* static */ const char *BaseMedia::GetExtension() { return ".obg"; // OpenTTD Base Graphics } INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia, GraphicsSet) openttd-1.5.3/src/depot_type.h0000644000000000000000000000173312627373446015031 0ustar rootroot/* $Id: depot_type.h 22411 2011-05-02 17:42:12Z rubidium $ */ /* * 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 depot_type.h Header files for depots (not hangars) */ #ifndef DEPOT_TYPE_H #define DEPOT_TYPE_H typedef uint16 DepotID; ///< Type for the unique identifier of depots. struct Depot; static const uint MAX_LENGTH_DEPOT_NAME_CHARS = 32; ///< The maximum length of a depot name in characters including '\0' #endif /* DEPOT_TYPE_H */ openttd-1.5.3/src/console_type.h0000644000000000000000000000331312627373442015350 0ustar rootroot/* $Id: console_type.h 23595 2011-12-19 17:48:04Z rubidium $ */ /* * 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 console_type.h Globally used console related types. */ #ifndef CONSOLE_TYPE_H #define CONSOLE_TYPE_H #include "gfx_type.h" /** Modes of the in-game console. */ enum IConsoleModes { ICONSOLE_FULL, ///< In-game console is closed. ICONSOLE_OPENED, ///< In-game console is opened, upper 1/3 of the screen. ICONSOLE_CLOSED, ///< In-game console is opened, whole screen. }; /* Colours of the console messages. */ static const TextColour CC_DEFAULT = TC_SILVER; ///< Default colour of the console. static const TextColour CC_ERROR = TC_RED; ///< Colour for error lines. static const TextColour CC_WARNING = TC_LIGHT_BLUE; ///< Colour for warning lines. static const TextColour CC_INFO = TC_YELLOW; ///< Colour for information lines. static const TextColour CC_DEBUG = TC_LIGHT_BROWN; ///< Colour for debug output. static const TextColour CC_COMMAND = TC_GOLD; ///< Colour for the console's commands. static const TextColour CC_WHITE = TC_WHITE; ///< White console lines for various things such as the welcome. #endif /* CONSOLE_TYPE_H */ openttd-1.5.3/src/roadveh_gui.cpp0000644000000000000000000001242312627373445015501 0ustar rootroot/* $Id: roadveh_gui.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 roadveh_gui.cpp GUI for road vehicles. */ #include "stdafx.h" #include "roadveh.h" #include "window_gui.h" #include "strings_func.h" #include "vehicle_func.h" #include "string_func.h" #include "zoom_func.h" #include "table/strings.h" #include "safeguards.h" /** * Draw the details for the given vehicle at the given position * * @param v current vehicle * @param left The left most coordinate to draw * @param right The right most coordinate to draw * @param y The y coordinate */ void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y) { uint y_offset = v->HasArticulatedPart() ? ScaleGUITrad(15) : 0; // Draw the first line below the sprite of an articulated RV instead of after it. StringID str; Money feeder_share = 0; SetDParam(0, v->engine_type); SetDParam(1, v->build_year); SetDParam(2, v->value); DrawString(left, right, y + y_offset, STR_VEHICLE_INFO_BUILT_VALUE); if (v->HasArticulatedPart()) { CargoArray max_cargo; StringID subtype_text[NUM_CARGO]; char capacity[512]; memset(subtype_text, 0, sizeof(subtype_text)); for (const Vehicle *u = v; u != NULL; u = u->Next()) { max_cargo[u->cargo_type] += u->cargo_cap; if (u->cargo_cap > 0) { StringID text = GetCargoSubtypeText(u); if (text != STR_EMPTY) subtype_text[u->cargo_type] = text; } } GetString(capacity, STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY, lastof(capacity)); bool first = true; for (CargoID i = 0; i < NUM_CARGO; i++) { if (max_cargo[i] > 0) { char buffer[128]; SetDParam(0, i); SetDParam(1, max_cargo[i]); GetString(buffer, STR_JUST_CARGO, lastof(buffer)); if (!first) strecat(capacity, ", ", lastof(capacity)); strecat(capacity, buffer, lastof(capacity)); if (subtype_text[i] != 0) { GetString(buffer, subtype_text[i], lastof(buffer)); strecat(capacity, buffer, lastof(capacity)); } first = false; } } DrawString(left, right, y + FONT_HEIGHT_NORMAL + y_offset, capacity, TC_BLUE); for (const Vehicle *u = v; u != NULL; u = u->Next()) { if (u->cargo_cap == 0) continue; str = STR_VEHICLE_DETAILS_CARGO_EMPTY; if (u->cargo.StoredCount() > 0) { SetDParam(0, u->cargo_type); SetDParam(1, u->cargo.StoredCount()); SetDParam(2, u->cargo.Source()); str = STR_VEHICLE_DETAILS_CARGO_FROM; feeder_share += u->cargo.FeederShare(); } DrawString(left, right, y + 2 * FONT_HEIGHT_NORMAL + 1 + y_offset, str); y_offset += FONT_HEIGHT_NORMAL + 1; } y_offset -= FONT_HEIGHT_NORMAL + 1; } else { SetDParam(0, v->cargo_type); SetDParam(1, v->cargo_cap); SetDParam(4, GetCargoSubtypeText(v)); DrawString(left, right, y + FONT_HEIGHT_NORMAL + y_offset, STR_VEHICLE_INFO_CAPACITY); str = STR_VEHICLE_DETAILS_CARGO_EMPTY; if (v->cargo.StoredCount() > 0) { SetDParam(0, v->cargo_type); SetDParam(1, v->cargo.StoredCount()); SetDParam(2, v->cargo.Source()); str = STR_VEHICLE_DETAILS_CARGO_FROM; feeder_share += v->cargo.FeederShare(); } DrawString(left, right, y + 2 * FONT_HEIGHT_NORMAL + 1 + y_offset, str); } /* Draw Transfer credits text */ SetDParam(0, feeder_share); DrawString(left, right, y + 3 * FONT_HEIGHT_NORMAL + 3 + y_offset, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE); } /** * Draws an image of a road vehicle chain * @param v Front vehicle * @param left The minimum horizontal position * @param right The maximum horizontal position * @param y Vertical position to draw at * @param selection Selected vehicle to draw a frame around * @param skip Number of pixels to skip at the front (for scrolling) */ void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip) { bool rtl = _current_text_dir == TD_RTL; Direction dir = rtl ? DIR_E : DIR_W; const RoadVehicle *u = RoadVehicle::From(v); DrawPixelInfo tmp_dpi, *old_dpi; int max_width = right - left + 1; if (!FillDrawPixelInfo(&tmp_dpi, left, y, max_width, ScaleGUITrad(14))) return; old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; int px = rtl ? max_width + skip : -skip; for (; u != NULL && (rtl ? px > 0 : px < max_width); u = u->Next()) { Point offset; int width = u->GetDisplayImageWidth(&offset); if (rtl ? px + width > 0 : px - width < max_width) { PaletteID pal = (u->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(u); DrawSprite(u->GetImage(dir, image_type), pal, px + (rtl ? -offset.x : offset.x), ScaleGUITrad(6) + offset.y); } px += rtl ? -width : width; } if (v->index == selection) { DrawFrameRect((rtl ? px : 0), 0, (rtl ? max_width : px) - 1, ScaleGUITrad(13) - 1, COLOUR_WHITE, FR_BORDERONLY); } _cur_dpi = old_dpi; } openttd-1.5.3/src/tree_map.h0000644000000000000000000002257712627373435014460 0ustar rootroot/* $Id: tree_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 tree_map.h Map accessors for tree tiles. */ #ifndef TREE_MAP_H #define TREE_MAP_H #include "tile_map.h" /** * List of tree types along all landscape types. * * This enumeration contains a list of the different tree types along * all landscape types. The values for the enumerations may be used for * offsets from the grfs files. These points to the start of * the tree list for a landscape. See the TREE_COUNT_* enumerations * for the amount of different trees for a specific landscape. */ enum TreeType { TREE_TEMPERATE = 0x00, ///< temperate tree TREE_SUB_ARCTIC = 0x0C, ///< tree on a sub_arctic landscape TREE_RAINFOREST = 0x14, ///< tree on the 'green part' on a sub-tropical map TREE_CACTUS = 0x1B, ///< a cactus for the 'desert part' on a sub-tropical map TREE_SUB_TROPICAL = 0x1C, ///< tree on a sub-tropical map, non-rainforest, non-desert TREE_TOYLAND = 0x20, ///< tree on a toyland map TREE_INVALID = 0xFF, ///< An invalid tree }; /* Counts the number of tree types for each landscape. * * This list contains the counts of different tree types for each landscape. This list contains * 5 entries instead of 4 (as there are only 4 landscape types) as the sub tropic landscape * has two types of area, one for normal trees and one only for cacti. */ static const uint TREE_COUNT_TEMPERATE = TREE_SUB_ARCTIC - TREE_TEMPERATE; ///< number of tree types on a temperate map. static const uint TREE_COUNT_SUB_ARCTIC = TREE_RAINFOREST - TREE_SUB_ARCTIC; ///< number of tree types on a sub arctic map. static const uint TREE_COUNT_RAINFOREST = TREE_CACTUS - TREE_RAINFOREST; ///< number of tree types for the 'rainforest part' of a sub-tropic map. static const uint TREE_COUNT_SUB_TROPICAL = TREE_TOYLAND - TREE_SUB_TROPICAL; ///< number of tree types for the 'sub-tropic part' of a sub-tropic map. static const uint TREE_COUNT_TOYLAND = 9; ///< number of tree types on a toyland map. /** * Enumeration for ground types of tiles with trees. * * This enumeration defines the ground types for tiles with trees on it. */ enum TreeGround { TREE_GROUND_GRASS = 0, ///< normal grass TREE_GROUND_ROUGH = 1, ///< some rough tile TREE_GROUND_SNOW_DESERT = 2, ///< a desert or snow tile, depend on landscape TREE_GROUND_SHORE = 3, ///< shore TREE_GROUND_ROUGH_SNOW = 4, ///< A snow tile that is rough underneath. }; /** * Returns the treetype of a tile. * * This function returns the treetype of a given tile. As there are more * possible treetypes for a tile in a game as the enumeration #TreeType defines * this function may be return a value which isn't catch by an entry of the * enumeration #TreeType. But there is no problem known about it. * * @param t The tile to get the treetype from * @return The treetype of the given tile with trees * @pre Tile t must be of type MP_TREES */ static inline TreeType GetTreeType(TileIndex t) { assert(IsTileType(t, MP_TREES)); return (TreeType)_m[t].m3; } /** * Returns the groundtype for tree tiles. * * This function returns the groundtype of a tile with trees. * * @param t The tile to get the groundtype from * @return The groundtype of the tile * @pre Tile must be of type MP_TREES */ static inline TreeGround GetTreeGround(TileIndex t) { assert(IsTileType(t, MP_TREES)); return (TreeGround)GB(_m[t].m2, 6, 3); } /** * Returns the 'density' of a tile with trees. * * This function returns the density of a tile which got trees. Note * that this value doesn't count the number of trees on a tile, use * #GetTreeCount instead. This function instead returns some kind of * groundtype of the tile. As the map-array is finite in size and * the informations about the trees must be saved somehow other * informations about a tile must be saved somewhere encoded in the * tile. So this function returns the density of a tile for sub arctic * and sub tropical games. This means for sub arctic the type of snowline * (0 to 3 for all 4 types of snowtiles) and for sub tropical the value * 3 for a desert (and 0 for non-desert). The function name is not read as * "get the tree density of a tile" but "get the density of a tile which got trees". * * @param t The tile to get the 'density' * @pre Tile must be of type MP_TREES * @see GetTreeCount */ static inline uint GetTreeDensity(TileIndex t) { assert(IsTileType(t, MP_TREES)); return GB(_m[t].m2, 4, 2); } /** * Set the density and ground type of a tile with trees. * * This functions saves the ground type and the density which belongs to it * for a given tile. * * @param t The tile to set the density and ground type * @param g The ground type to save * @param d The density to save with * @pre Tile must be of type MP_TREES */ static inline void SetTreeGroundDensity(TileIndex t, TreeGround g, uint d) { assert(IsTileType(t, MP_TREES)); // XXX incomplete SB(_m[t].m2, 4, 2, d); SB(_m[t].m2, 6, 3, g); } /** * Returns the number of trees on a tile. * * This function returns the number of trees of a tile (1-4). * The tile must be contains at least one tree or be more specific: it must be * of type MP_TREES. * * @param t The index to get the number of trees * @return The number of trees (1-4) * @pre Tile must be of type MP_TREES */ static inline uint GetTreeCount(TileIndex t) { assert(IsTileType(t, MP_TREES)); return GB(_m[t].m5, 6, 2) + 1; } /** * Add a amount to the tree-count value of a tile with trees. * * This function add a value to the tree-count value of a tile. This * value may be negative to reduce the tree-counter. If the resulting * value reach 0 it doesn't get converted to a "normal" tile. * * @param t The tile to change the tree amount * @param c The value to add (or reduce) on the tree-count value * @pre Tile must be of type MP_TREES */ static inline void AddTreeCount(TileIndex t, int c) { assert(IsTileType(t, MP_TREES)); // XXX incomplete _m[t].m5 += c << 6; } /** * Returns the tree growth status. * * This function returns the tree growth status of a tile with trees. * * @param t The tile to get the tree growth status * @return The tree growth status * @pre Tile must be of type MP_TREES */ static inline uint GetTreeGrowth(TileIndex t) { assert(IsTileType(t, MP_TREES)); return GB(_m[t].m5, 0, 3); } /** * Add a value to the tree growth status. * * This function adds a value to the tree grow status of a tile. * * @param t The tile to add the value on * @param a The value to add on the tree growth status * @pre Tile must be of type MP_TREES */ static inline void AddTreeGrowth(TileIndex t, int a) { assert(IsTileType(t, MP_TREES)); // XXX incomplete _m[t].m5 += a; } /** * Sets the tree growth status of a tile. * * This function sets the tree growth status of a tile directly with * the given value. * * @param t The tile to change the tree growth status * @param g The new value * @pre Tile must be of type MP_TREES */ static inline void SetTreeGrowth(TileIndex t, uint g) { assert(IsTileType(t, MP_TREES)); // XXX incomplete SB(_m[t].m5, 0, 3, g); } /** * Get the tick counter of a tree tile. * * Returns the saved tick counter of a given tile. * * @param t The tile to get the counter value from * @pre Tile must be of type MP_TREES */ static inline uint GetTreeCounter(TileIndex t) { assert(IsTileType(t, MP_TREES)); return GB(_m[t].m2, 0, 4); } /** * Add a value on the tick counter of a tree-tile * * This function adds a value on the tick counter of a tree-tile. * * @param t The tile to add the value on * @param a The value to add on the tick counter * @pre Tile must be of type MP_TREES */ static inline void AddTreeCounter(TileIndex t, int a) { assert(IsTileType(t, MP_TREES)); // XXX incomplete _m[t].m2 += a; } /** * Set the tick counter for a tree-tile * * This function sets directly the tick counter for a tree-tile. * * @param t The tile to set the tick counter * @param c The new tick counter value * @pre Tile must be of type MP_TREES */ static inline void SetTreeCounter(TileIndex t, uint c) { assert(IsTileType(t, MP_TREES)); // XXX incomplete SB(_m[t].m2, 0, 4, c); } /** * Make a tree-tile. * * This functions change the tile to a tile with trees and all informations which belongs to it. * * @param t The tile to make a tree-tile from * @param type The type of the tree * @param count the number of trees * @param growth the growth status * @param ground the ground type * @param density the density (not the number of trees) */ static inline void MakeTree(TileIndex t, TreeType type, uint count, uint growth, TreeGround ground, uint density) { SetTileType(t, MP_TREES); SetTileOwner(t, OWNER_NONE); _m[t].m2 = ground << 6 | density << 4 | 0; _m[t].m3 = type; _m[t].m4 = 0 << 5 | 0 << 2; _m[t].m5 = count << 6 | growth; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } #endif /* TREE_MAP_H */ openttd-1.5.3/src/settings_type.h0000644000000000000000000011771212627373436015562 0ustar rootroot/* $Id: settings_type.h 27144 2015-02-12 20:00:23Z frosch $ */ /* * 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 settings_type.h Types related to global configuration settings. */ #ifndef SETTINGS_TYPE_H #define SETTINGS_TYPE_H #include "date_type.h" #include "town_type.h" #include "transport_type.h" #include "network/core/config.h" #include "company_type.h" #include "cargotype.h" #include "linkgraph/linkgraph_type.h" #include "zoom_type.h" #include "openttd.h" /** Settings profiles and highscore tables. */ enum SettingsProfile { SP_BEGIN = 0, SP_EASY = SP_BEGIN, ///< Easy difficulty. SP_MEDIUM, ///< Medium difficulty. SP_HARD, ///< Hard difficulty. SP_END, ///< End of setting profiles. SP_CUSTOM = SP_END, ///< No profile, special "custom" highscore. SP_SAVED_HIGHSCORE_END, ///< End of saved highscore tables. SP_MULTIPLAYER = SP_SAVED_HIGHSCORE_END, ///< Special "multiplayer" highscore. Not saved, always specific to the current game. SP_HIGHSCORE_END, ///< End of highscore tables. }; /** Available industry map generation densities. */ enum IndustryDensity { ID_FUND_ONLY, ///< The game does not build industries. ID_MINIMAL, ///< Start with just the industries that must be present. ID_VERY_LOW, ///< Very few industries at game start. ID_LOW, ///< Few industries at game start. ID_NORMAL, ///< Normal amount of industries at game start. ID_HIGH, ///< Many industries at game start. ID_END, ///< Number of industry density settings. }; /** Settings related to the difficulty of the game */ struct DifficultySettings { byte max_no_competitors; ///< the number of competitors (AIs) byte number_towns; ///< the amount of towns byte industry_density; ///< The industry density. @see IndustryDensity uint32 max_loan; ///< the maximum initial loan byte initial_interest; ///< amount of interest (to pay over the loan) byte vehicle_costs; ///< amount of money spent on vehicle running cost byte competitor_speed; ///< the speed at which the AI builds byte vehicle_breakdowns; ///< likelihood of vehicles breaking down byte subsidy_multiplier; ///< amount of subsidy byte construction_cost; ///< how expensive is building byte terrain_type; ///< the mountainousness of the landscape byte quantity_sea_lakes; ///< the amount of seas/lakes bool economy; ///< how volatile is the economy bool line_reverse_mode; ///< reversing at stations or not bool disasters; ///< are disasters enabled byte town_council_tolerance; ///< minimum required town ratings to be allowed to demolish stuff }; /** Settings related to the GUI and other stuff that is not saved in the savegame. */ struct GUISettings { bool sg_full_load_any; ///< new full load calculation, any cargo must be full read from pre v93 savegames bool lost_vehicle_warn; ///< if a vehicle can't find its destination, show a warning uint8 order_review_system; ///< perform order reviews on vehicles bool vehicle_income_warn; ///< if a vehicle isn't generating income, show a warning bool show_finances; ///< show finances at end of year bool sg_new_nonstop; ///< ttdpatch compatible nonstop handling read from pre v93 savegames bool new_nonstop; ///< ttdpatch compatible nonstop handling uint8 stop_location; ///< what is the default stop location of trains? uint8 auto_scrolling; ///< scroll when moving mouse to the edge (see #ViewportAutoscrolling) byte errmsg_duration; ///< duration of error message uint16 hover_delay_ms; ///< time required to activate a hover event, in milliseconds bool link_terraform_toolbar; ///< display terraform toolbar when displaying rail, road, water and airport toolbars uint8 smallmap_land_colour; ///< colour used for land and heightmap at the smallmap bool reverse_scroll; ///< right-Click-Scrolling scrolls in the opposite direction bool smooth_scroll; ///< smooth scroll viewports bool measure_tooltip; ///< show a permanent tooltip when dragging tools byte liveries; ///< options for displaying company liveries, 0=none, 1=self, 2=all bool prefer_teamchat; ///< choose the chat message target with , true=all clients, false=your team uint8 advanced_vehicle_list; ///< use the "advanced" vehicle list uint8 loading_indicators; ///< show loading indicators uint8 default_rail_type; ///< the default rail type for the rail GUI uint8 toolbar_pos; ///< position of toolbars, 0=left, 1=center, 2=right uint8 statusbar_pos; ///< position of statusbar, 0=left, 1=center, 2=right uint8 window_snap_radius; ///< windows snap at each other if closer than this uint8 window_soft_limit; ///< soft limit of maximum number of non-stickied non-vital windows (0 = no limit) ZoomLevelByte zoom_min; ///< minimum zoom out level ZoomLevelByte zoom_max; ///< maximum zoom out level bool disable_unsuitable_building; ///< disable infrastructure building when no suitable vehicles are available byte autosave; ///< how often should we do autosaves? bool threaded_saves; ///< should we do threaded saves? bool keep_all_autosave; ///< name the autosave in a different way bool autosave_on_exit; ///< save an autosave when you quit the game, but do not ask "Do you really want to quit?" uint8 date_format_in_default_names; ///< should the default savegame/screenshot name use long dates (31th Dec 2008), short dates (31-12-2008) or ISO dates (2008-12-31) byte max_num_autosaves; ///< controls how many autosavegames are made before the game starts to overwrite (names them 0 to max_num_autosaves - 1) bool population_in_label; ///< show the population of a town in his label? uint8 right_mouse_btn_emulation; ///< should we emulate right mouse clicking? uint8 scrollwheel_scrolling; ///< scrolling using the scroll wheel? uint8 scrollwheel_multiplier; ///< how much 'wheel' per incoming event from the OS? bool timetable_arrival_departure; ///< show arrivals and departures in vehicle timetables bool left_mouse_btn_scrolling; ///< left mouse button scroll bool pause_on_newgame; ///< whether to start new games paused or not bool enable_signal_gui; ///< show the signal GUI when the signal button is pressed Year coloured_news_year; ///< when does newspaper become coloured? bool timetable_in_ticks; ///< whether to show the timetable in ticks rather than days bool quick_goto; ///< Allow quick access to 'goto button' in vehicle orders window bool auto_euro; ///< automatically switch to euro in 2002 byte drag_signals_density; ///< many signals density bool drag_signals_fixed_distance; ///< keep fixed distance between signals when dragging Year semaphore_build_before; ///< build semaphore signals automatically before this year byte news_message_timeout; ///< how much longer than the news message "age" should we keep the message in the history bool show_track_reservation; ///< highlight reserved tracks. uint8 default_signal_type; ///< the signal type to build by default. uint8 cycle_signal_types; ///< what signal types to cycle with the build signal tool. byte station_numtracks; ///< the number of platforms to default on for rail stations byte station_platlength; ///< the platform length, in tiles, for rail stations bool station_dragdrop; ///< whether drag and drop is enabled for stations bool station_show_coverage; ///< whether to highlight coverage area bool persistent_buildingtools; ///< keep the building tools active after usage bool expenses_layout; ///< layout of expenses window uint32 last_newgrf_count; ///< the numbers of NewGRFs we found during the last scan byte missing_strings_threshold; ///< the number of missing strings before showing the warning uint8 graph_line_thickness; ///< the thickness of the lines in the various graph guis uint8 osk_activation; ///< Mouse gesture to trigger the OSK. uint16 console_backlog_timeout; ///< the minimum amount of time items should be in the console backlog before they will be removed in ~3 seconds granularity. uint16 console_backlog_length; ///< the minimum amount of items in the console backlog before items will be removed. uint8 station_gui_group_order; ///< the order of grouping cargo entries in the station gui uint8 station_gui_sort_by; ///< sort cargo entries in the station gui by station name or amount uint8 station_gui_sort_order; ///< the sort order of entries in the station gui - ascending or descending #ifdef ENABLE_NETWORK uint16 network_chat_box_width_pct; ///< width of the chat box in percent uint8 network_chat_box_height; ///< height of the chat box in lines uint16 network_chat_timeout; ///< timeout of chat messages in seconds #endif uint8 developer; ///< print non-fatal warnings in console (>= 1), copy debug output to console (== 2) bool show_date_in_logs; ///< whether to show dates in console logs bool newgrf_developer_tools; ///< activate NewGRF developer tools and allow modifying NewGRFs in an existing game bool ai_developer_tools; ///< activate AI developer tools bool scenario_developer; ///< activate scenario developer: allow modifying NewGRFs in an existing game uint8 settings_restriction_mode; ///< selected restriction mode in adv. settings GUI. @see RestrictionMode bool newgrf_show_old_versions; ///< whether to show old versions in the NewGRF list uint8 newgrf_default_palette; ///< default palette to use for NewGRFs without action 14 palette information /** * Returns true when the user has sufficient privileges to edit newgrfs on a running game * @return whether the user has sufficient privileges to edit newgrfs in an existing game */ bool UserIsAllowedToChangeNewGRFs() const { return this->scenario_developer || this->newgrf_developer_tools; } }; /** Settings related to sound effects. */ struct SoundSettings { bool news_ticker; ///< Play a ticker sound when a news item is published. bool news_full; ///< Play sound effects associated to certain news types. bool new_year; ///< Play sound on new year, summarising the performance during the last year. bool confirm; ///< Play sound effect on succesful constructions or other actions. bool click_beep; ///< Beep on a random selection of buttons. bool disaster; ///< Play disaster and accident sounds. bool vehicle; ///< Play vehicle sound effects. bool ambient; ///< Play ambient, industry and town sounds. }; /** Settings related to music. */ struct MusicSettings { byte playlist; ///< The playlist (number) to play byte music_vol; ///< The requested music volume byte effect_vol; ///< The requested effects volume byte custom_1[33]; ///< The order of the first custom playlist byte custom_2[33]; ///< The order of the second custom playlist bool playing; ///< Whether music is playing bool shuffle; ///< Whether to shuffle the music }; /** Settings related to currency/unit systems. */ struct LocaleSettings { byte currency; ///< currency we currently use byte units_velocity; ///< unit system for velocity byte units_power; ///< unit system for power byte units_weight; ///< unit system for weight byte units_volume; ///< unit system for volume byte units_force; ///< unit system for force byte units_height; ///< unit system for height char *digit_group_separator; ///< thousand separator for non-currencies char *digit_group_separator_currency; ///< thousand separator for currencies char *digit_decimal_separator; ///< decimal separator }; /** Settings related to news */ struct NewsSettings { uint8 arrival_player; ///< NewsDisplay of vehicles arriving at new stations of current player uint8 arrival_other; ///< NewsDisplay of vehicles arriving at new stations of other players uint8 accident; ///< NewsDisplay of accidents that occur uint8 company_info; ///< NewsDisplay of general company information uint8 open; ///< NewsDisplay on new industry constructions uint8 close; ///< NewsDisplay about closing industries uint8 economy; ///< NewsDisplay on economical changes uint8 production_player; ///< NewsDisplay of production changes of industries affecting current player uint8 production_other; ///< NewsDisplay of production changes of industries affecting competitors uint8 production_nobody; ///< NewsDisplay of production changes of industries affecting no one uint8 advice; ///< NewsDisplay on advice affecting the player's vehicles uint8 new_vehicles; ///< NewsDisplay of new vehicles becoming available uint8 acceptance; ///< NewsDisplay on changes affecting the acceptance of cargo at stations uint8 subsidies; ///< NewsDisplay of changes on subsidies uint8 general; ///< NewsDisplay of other topics }; /** All settings related to the network. */ struct NetworkSettings { #ifdef ENABLE_NETWORK uint16 sync_freq; ///< how often do we check whether we are still in-sync uint8 frame_freq; ///< how often do we send commands to the clients uint16 commands_per_frame; ///< how many commands may be sent each frame_freq frames? uint16 max_commands_in_queue; ///< how many commands may there be in the incoming queue before dropping the connection? uint16 bytes_per_frame; ///< how many bytes may, over a long period, be received per frame? uint16 bytes_per_frame_burst; ///< how many bytes may, over a short period, be received? uint16 max_init_time; ///< maximum amount of time, in game ticks, a client may take to initiate joining uint16 max_join_time; ///< maximum amount of time, in game ticks, a client may take to sync up during joining uint16 max_download_time; ///< maximum amount of time, in game ticks, a client may take to download the map uint16 max_password_time; ///< maximum amount of time, in game ticks, a client may take to enter the password uint16 max_lag_time; ///< maximum amount of time, in game ticks, a client may be lagging behind the server bool pause_on_join; ///< pause the game when people join uint16 server_port; ///< port the server listens on uint16 server_admin_port; ///< port the server listens on for the admin network bool server_admin_chat; ///< allow private chat for the server to be distributed to the admin network char server_name[NETWORK_NAME_LENGTH]; ///< name of the server char server_password[NETWORK_PASSWORD_LENGTH]; ///< password for joining this server char rcon_password[NETWORK_PASSWORD_LENGTH]; ///< password for rconsole (server side) char admin_password[NETWORK_PASSWORD_LENGTH]; ///< password for the admin network bool server_advertise; ///< advertise the server to the masterserver uint8 lan_internet; ///< search on the LAN or internet for servers char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< name of the player (as client) char default_company_pass[NETWORK_PASSWORD_LENGTH]; ///< default password for new companies in encrypted form char connect_to_ip[NETWORK_HOSTNAME_LENGTH]; ///< default for the "Add server" query char network_id[NETWORK_SERVER_ID_LENGTH]; ///< network ID for servers bool autoclean_companies; ///< automatically remove companies that are not in use uint8 autoclean_unprotected; ///< remove passwordless companies after this many months uint8 autoclean_protected; ///< remove the password from passworded companies after this many months uint8 autoclean_novehicles; ///< remove companies with no vehicles after this many months uint8 max_companies; ///< maximum amount of companies uint8 max_clients; ///< maximum amount of clients uint8 max_spectators; ///< maximum amount of spectators Year restart_game_year; ///< year the server restarts uint8 min_active_clients; ///< minimum amount of active clients to unpause the game uint8 server_lang; ///< language of the server bool reload_cfg; ///< reload the config file before restarting char last_host[NETWORK_HOSTNAME_LENGTH]; ///< IP address of the last joined server uint16 last_port; ///< port of the last joined server bool no_http_content_downloads; ///< do not do content downloads over HTTP #else /* ENABLE_NETWORK */ #endif }; /** Settings related to the creation of games. */ struct GameCreationSettings { uint32 generation_seed; ///< noise seed for world generation Year starting_year; ///< starting date uint8 map_x; ///< X size of map uint8 map_y; ///< Y size of map byte land_generator; ///< the landscape generator byte oil_refinery_limit; ///< distance oil refineries allowed from map edge byte snow_line_height; ///< the configured snow line height byte tgen_smoothness; ///< how rough is the terrain from 0-3 byte tree_placer; ///< the tree placer algorithm byte heightmap_rotation; ///< rotation director for the heightmap byte se_flat_world_height; ///< land height a flat world gets in SE byte town_name; ///< the town name generator used for town names byte landscape; ///< the landscape we're currently in byte water_borders; ///< bitset of the borders that are water uint16 custom_town_number; ///< manually entered number of towns byte variety; ///< variety level applied to TGP byte custom_sea_level; ///< manually entered percentage of water in the map byte min_river_length; ///< the minimum river length byte river_route_random; ///< the amount of randomicity for the route finding byte amount_of_rivers; ///< the amount of rivers }; /** Settings related to construction in-game */ struct ConstructionSettings { uint8 max_heightlevel; ///< maximum allowed heightlevel bool build_on_slopes; ///< allow building on slopes bool autoslope; ///< allow terraforming under things uint16 max_bridge_length; ///< maximum length of bridges byte max_bridge_height; ///< maximum height of bridges uint16 max_tunnel_length; ///< maximum length of tunnels byte train_signal_side; ///< show signals on left / driving / right side bool extra_dynamite; ///< extra dynamite bool road_stop_on_town_road; ///< allow building of drive-through road stops on town owned roads bool road_stop_on_competitor_road; ///< allow building of drive-through road stops on roads owned by competitors uint8 raw_industry_construction; ///< type of (raw) industry construction (none, "normal", prospecting) uint8 industry_platform; ///< the amount of flat land around an industry bool freeform_edges; ///< allow terraforming the tiles at the map edges uint8 extra_tree_placement; ///< (dis)allow building extra trees in-game uint8 command_pause_level; ///< level/amount of commands that can't be executed while paused uint32 terraform_per_64k_frames; ///< how many tile heights may, over a long period, be terraformed per 65536 frames? uint16 terraform_frame_burst; ///< how many tile heights may, over a short period, be terraformed? uint32 clear_per_64k_frames; ///< how many tiles may, over a long period, be cleared per 65536 frames? uint16 clear_frame_burst; ///< how many tiles may, over a short period, be cleared? uint32 tree_per_64k_frames; ///< how many trees may, over a long period, be planted per 65536 frames? uint16 tree_frame_burst; ///< how many trees may, over a short period, be planted? }; /** Settings related to the AI. */ struct AISettings { bool ai_in_multiplayer; ///< so we allow AIs in multiplayer bool ai_disable_veh_train; ///< disable types for AI bool ai_disable_veh_roadveh; ///< disable types for AI bool ai_disable_veh_aircraft; ///< disable types for AI bool ai_disable_veh_ship; ///< disable types for AI }; /** Settings related to scripts. */ struct ScriptSettings { uint8 settings_profile; ///< difficulty profile to set initial settings of scripts, esp. random AIs uint32 script_max_opcode_till_suspend; ///< max opcode calls till scripts will suspend }; /** Settings related to the old pathfinder. */ struct OPFSettings { uint16 pf_maxlength; ///< maximum length when searching for a train route for new pathfinder byte pf_maxdepth; ///< maximum recursion depth when searching for a train route for new pathfinder }; /** Settings related to the new pathfinder. */ struct NPFSettings { /** * The maximum amount of search nodes a single NPF run should take. This * limit should make sure performance stays at acceptable levels at the cost * of not being perfect anymore. */ uint32 npf_max_search_nodes; uint32 maximum_go_to_depot_penalty; ///< What is the maximum penalty that may be endured for going to a depot uint32 npf_rail_firstred_penalty; ///< the penalty for when the first signal is red (and it is not an exit or combo signal) uint32 npf_rail_firstred_exit_penalty; ///< the penalty for when the first signal is red (and it is an exit or combo signal) uint32 npf_rail_lastred_penalty; ///< the penalty for when the last signal is red uint32 npf_rail_station_penalty; ///< the penalty for station tiles uint32 npf_rail_slope_penalty; ///< the penalty for sloping upwards uint32 npf_rail_curve_penalty; ///< the penalty for curves uint32 npf_rail_depot_reverse_penalty; ///< the penalty for reversing in depots uint32 npf_rail_pbs_cross_penalty; ///< the penalty for crossing a reserved rail track uint32 npf_rail_pbs_signal_back_penalty; ///< the penalty for passing a pbs signal from the backside uint32 npf_buoy_penalty; ///< the penalty for going over (through) a buoy uint32 npf_water_curve_penalty; ///< the penalty for curves uint32 npf_road_curve_penalty; ///< the penalty for curves uint32 npf_crossing_penalty; ///< the penalty for level crossings uint32 npf_road_drive_through_penalty; ///< the penalty for going through a drive-through road stop uint32 npf_road_dt_occupied_penalty; ///< the penalty multiplied by the fill percentage of a drive-through road stop uint32 npf_road_bay_occupied_penalty; ///< the penalty multiplied by the fill percentage of a road bay }; /** Settings related to the yet another pathfinder. */ struct YAPFSettings { bool disable_node_optimization; ///< whether to use exit-dir instead of trackdir in node key uint32 max_search_nodes; ///< stop path-finding when this number of nodes visited uint32 maximum_go_to_depot_penalty; ///< What is the maximum penalty that may be endured for going to a depot bool ship_use_yapf; ///< use YAPF for ships bool road_use_yapf; ///< use YAPF for road bool rail_use_yapf; ///< use YAPF for rail uint32 road_slope_penalty; ///< penalty for up-hill slope uint32 road_curve_penalty; ///< penalty for curves uint32 road_crossing_penalty; ///< penalty for level crossing uint32 road_stop_penalty; ///< penalty for going through a drive-through road stop uint32 road_stop_occupied_penalty; ///< penalty multiplied by the fill percentage of a drive-through road stop uint32 road_stop_bay_occupied_penalty; ///< penalty multiplied by the fill percentage of a road bay bool rail_firstred_twoway_eol; ///< treat first red two-way signal as dead end uint32 rail_firstred_penalty; ///< penalty for first red signal uint32 rail_firstred_exit_penalty; ///< penalty for first red exit signal uint32 rail_lastred_penalty; ///< penalty for last red signal uint32 rail_lastred_exit_penalty; ///< penalty for last red exit signal uint32 rail_station_penalty; ///< penalty for non-target station tile uint32 rail_slope_penalty; ///< penalty for up-hill slope uint32 rail_curve45_penalty; ///< penalty for curve uint32 rail_curve90_penalty; ///< penalty for 90-deg curve uint32 rail_depot_reverse_penalty; ///< penalty for reversing in the depot uint32 rail_crossing_penalty; ///< penalty for level crossing uint32 rail_look_ahead_max_signals; ///< max. number of signals taken into consideration in look-ahead load balancer int32 rail_look_ahead_signal_p0; ///< constant in polynomial penalty function int32 rail_look_ahead_signal_p1; ///< constant in polynomial penalty function int32 rail_look_ahead_signal_p2; ///< constant in polynomial penalty function uint32 rail_pbs_cross_penalty; ///< penalty for crossing a reserved tile uint32 rail_pbs_station_penalty; ///< penalty for crossing a reserved station tile uint32 rail_pbs_signal_back_penalty; ///< penalty for passing a pbs signal from the backside uint32 rail_doubleslip_penalty; ///< penalty for passing a double slip switch uint32 rail_longer_platform_penalty; ///< penalty for longer station platform than train uint32 rail_longer_platform_per_tile_penalty; ///< penalty for longer station platform than train (per tile) uint32 rail_shorter_platform_penalty; ///< penalty for shorter station platform than train uint32 rail_shorter_platform_per_tile_penalty; ///< penalty for shorter station platform than train (per tile) }; /** Settings related to all pathfinders. */ struct PathfinderSettings { uint8 pathfinder_for_trains; ///< the pathfinder to use for trains uint8 pathfinder_for_roadvehs; ///< the pathfinder to use for roadvehicles uint8 pathfinder_for_ships; ///< the pathfinder to use for ships bool new_pathfinding_all; ///< use the newest pathfinding algorithm for all bool roadveh_queue; ///< buggy road vehicle queueing bool forbid_90_deg; ///< forbid trains to make 90 deg turns bool reverse_at_signals; ///< whether to reverse at signals at all byte wait_oneway_signal; ///< waitingtime in days before a oneway signal byte wait_twoway_signal; ///< waitingtime in days before a twoway signal bool reserve_paths; ///< always reserve paths regardless of signal type. byte wait_for_pbs_path; ///< how long to wait for a path reservation. byte path_backoff_interval; ///< ticks between checks for a free path. OPFSettings opf; ///< pathfinder settings for the old pathfinder NPFSettings npf; ///< pathfinder settings for the new pathfinder YAPFSettings yapf; ///< pathfinder settings for the yet another pathfinder }; /** Settings related to orders. */ struct OrderSettings { bool improved_load; ///< improved loading algorithm bool gradual_loading; ///< load vehicles gradually bool selectgoods; ///< only send the goods to station if a train has been there bool no_servicing_if_no_breakdowns; ///< don't send vehicles to depot when breakdowns are disabled bool serviceathelipad; ///< service helicopters at helipads automatically (no need to send to depot) }; /** Settings related to vehicles. */ struct VehicleSettings { uint8 max_train_length; ///< maximum length for trains uint8 smoke_amount; ///< amount of smoke/sparks locomotives produce uint8 train_acceleration_model; ///< realistic acceleration for trains uint8 roadveh_acceleration_model; ///< realistic acceleration for road vehicles uint8 train_slope_steepness; ///< Steepness of hills for trains when using realistic acceleration uint8 roadveh_slope_steepness; ///< Steepness of hills for road vehicles when using realistic acceleration bool wagon_speed_limits; ///< enable wagon speed limits bool disable_elrails; ///< when true, the elrails are disabled UnitID max_trains; ///< max trains in game per company UnitID max_roadveh; ///< max trucks in game per company UnitID max_aircraft; ///< max planes in game per company UnitID max_ships; ///< max ships in game per company uint8 plane_speed; ///< divisor for speed of aircraft uint8 freight_trains; ///< value to multiply the weight of cargo by bool dynamic_engines; ///< enable dynamic allocation of engine data bool never_expire_vehicles; ///< never expire vehicles byte extend_vehicle_life; ///< extend vehicle life by this many years byte road_side; ///< the side of the road vehicles drive on uint8 plane_crashes; ///< number of plane crashes, 0 = none, 1 = reduced, 2 = normal }; /** Settings related to the economy. */ struct EconomySettings { bool inflation; ///< disable inflation bool bribe; ///< enable bribing the local authority bool smooth_economy; ///< smooth economy bool allow_shares; ///< allow the buying/selling of shares uint8 feeder_payment_share; ///< percentage of leg payment to virtually pay in feeder systems byte dist_local_authority; ///< distance for town local authority, default 20 bool exclusive_rights; ///< allow buying exclusive rights bool fund_buildings; ///< allow funding new buildings bool fund_roads; ///< allow funding local road reconstruction bool give_money; ///< allow giving other companies money bool mod_road_rebuild; ///< roadworks remove unnecessary RoadBits bool multiple_industry_per_town; ///< allow many industries of the same type per town uint8 town_growth_rate; ///< town growth rate uint8 larger_towns; ///< the number of cities to build. These start off larger and grow twice as fast uint8 initial_city_size; ///< multiplier for the initial size of the cities compared to towns TownLayoutByte town_layout; ///< select town layout, @see TownLayout bool allow_town_roads; ///< towns are allowed to build roads (always allowed when generating world / in SE) TownFoundingByte found_town; ///< town founding, @see TownFounding bool station_noise_level; ///< build new airports when the town noise level is still within accepted limits uint16 town_noise_population[3]; ///< population to base decision on noise evaluation (@see town_council_tolerance) bool allow_town_level_crossings; ///< towns are allowed to build level crossings bool infrastructure_maintenance; ///< enable monthly maintenance fee for owner infrastructure }; struct LinkGraphSettings { uint16 recalc_time; ///< time (in days) for recalculating each link graph component. uint16 recalc_interval; ///< time (in days) between subsequent checks for link graphs to be calculated. DistributionTypeByte distribution_pax; ///< distribution type for passengers DistributionTypeByte distribution_mail; ///< distribution type for mail DistributionTypeByte distribution_armoured; ///< distribution type for armoured cargo class DistributionTypeByte distribution_default; ///< distribution type for all other goods uint8 accuracy; ///< accuracy when calculating things on the link graph. low accuracy => low running time uint8 demand_size; ///< influence of supply ("station size") on the demand function uint8 demand_distance; ///< influence of distance between stations on the demand function uint8 short_path_saturation; ///< percentage up to which short paths are saturated before saturating most capacious paths inline DistributionType GetDistributionType(CargoID cargo) const { if (IsCargoInClass(cargo, CC_PASSENGERS)) return this->distribution_pax; if (IsCargoInClass(cargo, CC_MAIL)) return this->distribution_mail; if (IsCargoInClass(cargo, CC_ARMOURED)) return this->distribution_armoured; return this->distribution_default; } }; /** Settings related to stations. */ struct StationSettings { bool modified_catchment; ///< different-size catchment areas bool adjacent_stations; ///< allow stations to be built directly adjacent to other stations bool distant_join_stations; ///< allow to join non-adjacent stations bool never_expire_airports; ///< never expire airports byte station_spread; ///< amount a station may spread }; /** Default settings for vehicles. */ struct VehicleDefaultSettings { bool servint_ispercent; ///< service intervals are in percents uint16 servint_trains; ///< service interval for trains uint16 servint_roadveh; ///< service interval for road vehicles uint16 servint_aircraft; ///< service interval for aircraft uint16 servint_ships; ///< service interval for ships }; /** Settings that can be set per company. */ struct CompanySettings { bool engine_renew; ///< is autorenew enabled int16 engine_renew_months; ///< months before/after the maximum vehicle age a vehicle should be renewed uint32 engine_renew_money; ///< minimum amount of money before autorenew is used bool renew_keep_length; ///< sell some wagons if after autoreplace the train is longer than before VehicleDefaultSettings vehicle; ///< default settings for vehicles }; /** All settings together for the game. */ struct GameSettings { DifficultySettings difficulty; ///< settings related to the difficulty GameCreationSettings game_creation; ///< settings used during the creation of a game (map) ConstructionSettings construction; ///< construction of things in-game AISettings ai; ///< what may the AI do? ScriptSettings script; ///< settings for scripts class AIConfig *ai_config[MAX_COMPANIES]; ///< settings per company class GameConfig *game_config; ///< settings for gamescript PathfinderSettings pf; ///< settings for all pathfinders OrderSettings order; ///< settings related to orders VehicleSettings vehicle; ///< options for vehicles EconomySettings economy; ///< settings to change the economy LinkGraphSettings linkgraph; ///< settings for link graph calculations StationSettings station; ///< settings related to station management LocaleSettings locale; ///< settings related to used currency/unit system in the current game }; /** All settings that are only important for the local client. */ struct ClientSettings { GUISettings gui; ///< settings related to the GUI NetworkSettings network; ///< settings related to the network CompanySettings company; ///< default values for per-company settings SoundSettings sound; ///< sound effect settings MusicSettings music; ///< settings related to music/sound NewsSettings news_display; ///< news display settings. }; /** The current settings for this game. */ extern ClientSettings _settings_client; /** The current settings for this game. */ extern GameSettings _settings_game; /** The settings values that are used for new games and/or modified in config file. */ extern GameSettings _settings_newgame; /** Old vehicle settings, which were game settings before, and are company settings now. (Needed for savegame conversion) */ extern VehicleDefaultSettings _old_vds; /** * Get the settings-object applicable for the current situation: the newgame settings * when we're in the main menu and otherwise the settings of the current game. */ static inline GameSettings &GetGameSettings() { return (_game_mode == GM_MENU) ? _settings_newgame : _settings_game; } #endif /* SETTINGS_TYPE_H */ openttd-1.5.3/src/cargotype.h0000644000000000000000000001535212627373442014650 0ustar rootroot/* $Id: cargotype.h 24915 2013-01-14 21:16:56Z smatz $ */ /* * 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 cargotype.h Types/functions related to cargoes. */ #ifndef CARGOTYPE_H #define CARGOTYPE_H #include "economy_type.h" #include "cargo_type.h" #include "gfx_type.h" #include "strings_type.h" #include "landscape_type.h" /** Globally unique label of a cargo type. */ typedef uint32 CargoLabel; /** Town growth effect when delivering cargo. */ enum TownEffect { TE_BEGIN = 0, TE_NONE = TE_BEGIN, ///< Cargo has no effect. TE_PASSENGERS, ///< Cargo behaves passenger-like. TE_MAIL, ///< Cargo behaves mail-like. TE_GOODS, ///< Cargo behaves goods/candy-like. TE_WATER, ///< Cargo behaves water-like. TE_FOOD, ///< Cargo behaves food/fizzy-drinks-like. TE_END, ///< End of town effects. NUM_TE = TE_END, ///< Amount of town effects. }; /** Cargo classes. */ enum CargoClass { CC_NOAVAILABLE = 0, ///< No cargo class has been specified CC_PASSENGERS = 1 << 0, ///< Passengers CC_MAIL = 1 << 1, ///< Mail CC_EXPRESS = 1 << 2, ///< Express cargo (Goods, Food, Candy, but also possible for passengers) CC_ARMOURED = 1 << 3, ///< Armoured cargo (Valuables, Gold, Diamonds) CC_BULK = 1 << 4, ///< Bulk cargo (Coal, Grain etc., Ores, Fruit) CC_PIECE_GOODS = 1 << 5, ///< Piece goods (Livestock, Wood, Steel, Paper) CC_LIQUID = 1 << 6, ///< Liquids (Oil, Water, Rubber) CC_REFRIGERATED = 1 << 7, ///< Refrigerated cargo (Food, Fruit) CC_HAZARDOUS = 1 << 8, ///< Hazardous cargo (Nuclear Fuel, Explosives, etc.) CC_COVERED = 1 << 9, ///< Covered/Sheltered Freight (Transportation in Box Vans, Silo Wagons, etc.) CC_SPECIAL = 1 << 15, ///< Special bit used for livery refit tricks instead of normal cargoes. }; static const byte INVALID_CARGO = 0xFF; ///< Constant representing invalid cargo /** Specification of a cargo type. */ struct CargoSpec { uint8 bitnum; ///< Cargo bit number, is #INVALID_CARGO for a non-used spec. CargoLabel label; ///< Unique label of the cargo type. uint8 legend_colour; uint8 rating_colour; uint8 weight; ///< Weight of a single unit of this cargo type in 1/16 ton (62.5 kg). uint16 multiplier; ///< Capacity multiplier for vehicles. (8 fractional bits) uint16 initial_payment; uint8 transit_days[2]; bool is_freight; ///< Cargo type is considered to be freight (affects train freight multiplier). TownEffect town_effect; ///< The effect that delivering this cargo type has on towns. Also affects destination of subsidies. uint16 multipliertowngrowth; ///< Size of the effect. uint8 callback_mask; ///< Bitmask of cargo callbacks that have to be called StringID name; ///< Name of this type of cargo. StringID name_single; ///< Name of a single entity of this type of cargo. StringID units_volume; ///< Name of a single unit of cargo of this type. StringID quantifier; ///< Text for multiple units of cargo of this type. StringID abbrev; ///< Two letter abbreviation for this cargo type. SpriteID sprite; ///< Icon to display this cargo type, may be \c 0xFFF (which means to resolve an action123 chain). uint16 classes; ///< Classes of this cargo type. @see CargoClass const struct GRFFile *grffile; ///< NewGRF where #group belongs to. const struct SpriteGroup *group; Money current_payment; /** * Determines index of this cargospec * @return index (in the CargoSpec::array array) */ inline CargoID Index() const { return this - CargoSpec::array; } /** * Tests for validity of this cargospec * @return is this cargospec valid? * @note assert(cs->IsValid()) can be triggered when GRF config is modified */ inline bool IsValid() const { return this->bitnum != INVALID_CARGO; } /** * Total number of cargospecs, both valid and invalid * @return length of CargoSpec::array */ static inline size_t GetArraySize() { return lengthof(CargoSpec::array); } /** * Retrieve cargo details for the given cargo ID * @param index ID of cargo * @pre index is a valid cargo ID */ static inline CargoSpec *Get(size_t index) { assert(index < lengthof(CargoSpec::array)); return &CargoSpec::array[index]; } SpriteID GetCargoIcon() const; private: static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs friend void SetupCargoForClimate(LandscapeID l); }; extern uint32 _cargo_mask; extern uint32 _standard_cargo_mask; void SetupCargoForClimate(LandscapeID l); CargoID GetCargoIDByLabel(CargoLabel cl); CargoID GetCargoIDByBitnum(uint8 bitnum); void InitializeSortedCargoSpecs(); extern const CargoSpec *_sorted_cargo_specs[NUM_CARGO]; extern uint8 _sorted_cargo_specs_size; extern uint8 _sorted_standard_cargo_specs_size; /** * Does cargo \a c have cargo class \a cc? * @param c Cargo type. * @param cc Cargo class. * @return The type fits in the class. */ static inline bool IsCargoInClass(CargoID c, CargoClass cc) { return (CargoSpec::Get(c)->classes & cc) != 0; } #define FOR_ALL_CARGOSPECS_FROM(var, start) for (size_t cargospec_index = start; var = NULL, cargospec_index < CargoSpec::GetArraySize(); cargospec_index++) \ if ((var = CargoSpec::Get(cargospec_index))->IsValid()) #define FOR_ALL_CARGOSPECS(var) FOR_ALL_CARGOSPECS_FROM(var, 0) #define FOR_EACH_SET_CARGO_ID(var, cargo_bits) FOR_EACH_SET_BIT_EX(CargoID, var, uint, cargo_bits) /** * Loop header for iterating over cargoes, sorted by name. This includes phony cargoes like regearing cargoes. * @param var Reference getting the cargospec. * @see CargoSpec */ #define FOR_ALL_SORTED_CARGOSPECS(var) for (uint8 index = 0; index < _sorted_cargo_specs_size && (var = _sorted_cargo_specs[index], true) ; index++) /** * Loop header for iterating over 'real' cargoes, sorted by name. Phony cargoes like regearing cargoes are skipped. * @param var Reference getting the cargospec. * @see CargoSpec */ #define FOR_ALL_SORTED_STANDARD_CARGOSPECS(var) for (uint8 index = 0; index < _sorted_standard_cargo_specs_size && (var = _sorted_cargo_specs[index], true); index++) #endif /* CARGOTYPE_H */ openttd-1.5.3/src/music_gui.cpp0000644000000000000000000006574412627373441015203 0ustar rootroot/* $Id: music_gui.cpp 27003 2014-10-12 18:41:53Z rubidium $ */ /* * 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 music_gui.cpp GUI for the music playback. */ #include "stdafx.h" #include "openttd.h" #include "base_media_base.h" #include "music/music_driver.hpp" #include "window_gui.h" #include "strings_func.h" #include "window_func.h" #include "sound_func.h" #include "gfx_func.h" #include "core/random_func.hpp" #include "error.h" #include "core/geometry_func.hpp" #include "string_func.h" #include "settings_type.h" #include "widgets/music_widget.h" #include "table/strings.h" #include "table/sprites.h" #include "safeguards.h" /** * Get the name of the song. * @param index of the song. * @return the name of the song. */ static const char *GetSongName(int index) { return BaseMusic::GetUsedSet()->song_name[index]; } /** * Get the track number of the song. * @param index of the song. * @return the track number of the song. */ static int GetTrackNumber(int index) { return BaseMusic::GetUsedSet()->track_nr[index]; } /** The currently played song */ static byte _music_wnd_cursong = 1; /** Whether a song is currently played */ static bool _song_is_active = false; /** Indices of the songs in the current playlist */ static byte _cur_playlist[NUM_SONGS_PLAYLIST + 1]; /** Indices of all songs */ static byte _playlist_all[NUM_SONGS_AVAILABLE + 1]; /** Indices of all old style songs */ static byte _playlist_old_style[NUM_SONGS_CLASS + 1]; /** Indices of all new style songs */ static byte _playlist_new_style[NUM_SONGS_CLASS + 1]; /** Indices of all ezy street songs */ static byte _playlist_ezy_street[NUM_SONGS_CLASS + 1]; assert_compile(lengthof(_settings_client.music.custom_1) == NUM_SONGS_PLAYLIST + 1); assert_compile(lengthof(_settings_client.music.custom_2) == NUM_SONGS_PLAYLIST + 1); /** The different playlists that can be played. */ static byte * const _playlists[] = { _playlist_all, _playlist_old_style, _playlist_new_style, _playlist_ezy_street, _settings_client.music.custom_1, _settings_client.music.custom_2, }; /** * Validate a playlist. * @param playlist The playlist to validate. * @param last The last location in the list. */ void ValidatePlaylist(byte *playlist, byte *last) { while (*playlist != 0 && playlist <= last) { /* Song indices are saved off-by-one so 0 is "nothing". */ if (*playlist <= NUM_SONGS_AVAILABLE && !StrEmpty(GetSongName(*playlist - 1))) { playlist++; continue; } for (byte *p = playlist; *p != 0 && p <= last; p++) { p[0] = p[1]; } } /* Make sure the list is null terminated. */ *last = 0; } /** Initialize the playlists */ void InitializeMusic() { uint j = 0; for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { if (StrEmpty(GetSongName(i))) continue; _playlist_all[j++] = i + 1; } /* Terminate the list */ _playlist_all[j] = 0; /* Now make the 'styled' playlists */ for (uint k = 0; k < NUM_SONG_CLASSES; k++) { j = 0; for (uint i = 0; i < NUM_SONGS_CLASS; i++) { int id = k * NUM_SONGS_CLASS + i + 1; if (StrEmpty(GetSongName(id))) continue; _playlists[k + 1][j++] = id + 1; } /* Terminate the list */ _playlists[k + 1][j] = 0; } ValidatePlaylist(_settings_client.music.custom_1, lastof(_settings_client.music.custom_1)); ValidatePlaylist(_settings_client.music.custom_2, lastof(_settings_client.music.custom_2)); if (BaseMusic::GetUsedSet()->num_available < _music_wnd_cursong) { /* If there are less songs than the currently played song, * just pause and reset to no song. */ _music_wnd_cursong = 0; _song_is_active = false; } } static void SkipToPrevSong() { byte *b = _cur_playlist; byte *p = b; byte t; if (b[0] == 0) return; // empty playlist do p++; while (p[0] != 0); // find the end t = *--p; // and copy the bytes while (p != b) { p--; p[1] = p[0]; } *b = t; _song_is_active = false; } static void SkipToNextSong() { byte *b = _cur_playlist; byte t; t = b[0]; if (t != 0) { while (b[1] != 0) { b[0] = b[1]; b++; } b[0] = t; } _song_is_active = false; } static void MusicVolumeChanged(byte new_vol) { MusicDriver::GetInstance()->SetVolume(new_vol); } static void DoPlaySong() { char filename[MAX_PATH]; if (FioFindFullPath(filename, lastof(filename), BASESET_DIR, BaseMusic::GetUsedSet()->files[_music_wnd_cursong - 1].filename) == NULL) { FioFindFullPath(filename, lastof(filename), OLD_GM_DIR, BaseMusic::GetUsedSet()->files[_music_wnd_cursong - 1].filename); } MusicDriver::GetInstance()->PlaySong(filename); SetWindowDirty(WC_MUSIC_WINDOW, 0); } static void DoStopMusic() { MusicDriver::GetInstance()->StopSong(); SetWindowDirty(WC_MUSIC_WINDOW, 0); } static void SelectSongToPlay() { uint i = 0; uint j = 0; memset(_cur_playlist, 0, sizeof(_cur_playlist)); do { /* File is the index into the file table of the music set. The play list uses 0 as 'no entry', * so we need to subtract 1. In case of 'no entry' (file = -1), just skip adding it outright. */ int file = _playlists[_settings_client.music.playlist][i] - 1; if (file >= 0) { const char *filename = BaseMusic::GetUsedSet()->files[file].filename; /* We are now checking for the existence of that file prior * to add it to the list of available songs */ if (!StrEmpty(filename) && FioCheckFileExists(filename, BASESET_DIR)) { _cur_playlist[j] = _playlists[_settings_client.music.playlist][i]; j++; } } } while (_playlists[_settings_client.music.playlist][++i] != 0 && j < lengthof(_cur_playlist) - 1); /* Do not shuffle when on the intro-start window, as the song to play has to be the original TTD Theme*/ if (_settings_client.music.shuffle && _game_mode != GM_MENU) { i = 500; do { uint32 r = InteractiveRandom(); byte *a = &_cur_playlist[GB(r, 0, 5)]; byte *b = &_cur_playlist[GB(r, 8, 5)]; if (*a != 0 && *b != 0) { byte t = *a; *a = *b; *b = t; } } while (--i); } } static void StopMusic() { _music_wnd_cursong = 0; DoStopMusic(); _song_is_active = false; SetWindowWidgetDirty(WC_MUSIC_WINDOW, 0, 9); } static void PlayPlaylistSong() { if (_cur_playlist[0] == 0) { SelectSongToPlay(); /* if there is not songs in the playlist, it may indicate * no file on the gm folder, or even no gm folder. * Stop the playback, then */ if (_cur_playlist[0] == 0) { _song_is_active = false; _music_wnd_cursong = 0; _settings_client.music.playing = false; return; } } _music_wnd_cursong = _cur_playlist[0]; DoPlaySong(); _song_is_active = true; SetWindowWidgetDirty(WC_MUSIC_WINDOW, 0, 9); } void ResetMusic() { _music_wnd_cursong = 1; DoPlaySong(); } void MusicLoop() { if (!_settings_client.music.playing && _song_is_active) { StopMusic(); } else if (_settings_client.music.playing && !_song_is_active) { PlayPlaylistSong(); } if (!_song_is_active) return; if (!MusicDriver::GetInstance()->IsSongPlaying()) { if (_game_mode != GM_MENU) { StopMusic(); SkipToNextSong(); PlayPlaylistSong(); } else { ResetMusic(); } } } static void SelectPlaylist(byte list) { _settings_client.music.playlist = list; InvalidateWindowData(WC_MUSIC_TRACK_SELECTION, 0); InvalidateWindowData(WC_MUSIC_WINDOW, 0); } struct MusicTrackSelectionWindow : public Window { MusicTrackSelectionWindow(WindowDesc *desc, WindowNumber number) : Window(desc) { this->InitNested(number); this->LowerWidget(WID_MTS_LIST_LEFT); this->LowerWidget(WID_MTS_LIST_RIGHT); this->SetWidgetDisabledState(WID_MTS_CLEAR, _settings_client.music.playlist <= 3); this->LowerWidget(WID_MTS_ALL + _settings_client.music.playlist); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_MTS_PLAYLIST: SetDParam(0, STR_MUSIC_PLAYLIST_ALL + _settings_client.music.playlist); 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; for (int i = 0; i < 6; i++) { this->SetWidgetLoweredState(WID_MTS_ALL + i, i == _settings_client.music.playlist); } this->SetWidgetDisabledState(WID_MTS_CLEAR, _settings_client.music.playlist <= 3); this->SetDirty(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_MTS_PLAYLIST: { Dimension d = {0, 0}; for (int i = 0; i < 6; i++) { SetDParam(0, STR_MUSIC_PLAYLIST_ALL + i); d = maxdim(d, GetStringBoundingBox(STR_PLAYLIST_PROGRAM)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_MTS_LIST_LEFT: case WID_MTS_LIST_RIGHT: { Dimension d = {0, 0}; for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { const char *song_name = GetSongName(i); if (StrEmpty(song_name)) continue; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, GetSongName(i)); Dimension d2 = GetStringBoundingBox(STR_PLAYLIST_TRACK_NAME); d.width = max(d.width, d2.width); d.height += d2.height; } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_MTS_LIST_LEFT: { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); int y = r.top + WD_FRAMERECT_TOP; for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { const char *song_name = GetSongName(i); if (StrEmpty(song_name)) continue; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, song_name); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME); y += FONT_HEIGHT_SMALL; } break; } case WID_MTS_LIST_RIGHT: { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); int y = r.top + WD_FRAMERECT_TOP; for (const byte *p = _playlists[_settings_client.music.playlist]; *p != 0; p++) { uint i = *p - 1; SetDParam(0, GetTrackNumber(i)); SetDParam(1, 2); SetDParamStr(2, GetSongName(i)); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_PLAYLIST_TRACK_NAME); y += FONT_HEIGHT_SMALL; } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_MTS_LIST_LEFT: { // add to playlist int y = this->GetRowFromWidget(pt.y, widget, 0, FONT_HEIGHT_SMALL); if (_settings_client.music.playlist < 4) return; if (!IsInsideMM(y, 0, BaseMusic::GetUsedSet()->num_available)) return; byte *p = _playlists[_settings_client.music.playlist]; for (uint i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) { if (p[i] == 0) { /* Find the actual song number */ for (uint j = 0; j < NUM_SONGS_AVAILABLE; j++) { if (GetTrackNumber(j) == y + 1) { p[i] = j + 1; break; } } p[i + 1] = 0; this->SetDirty(); SelectSongToPlay(); break; } } break; } case WID_MTS_LIST_RIGHT: { // remove from playlist int y = this->GetRowFromWidget(pt.y, widget, 0, FONT_HEIGHT_SMALL); if (_settings_client.music.playlist < 4) return; if (!IsInsideMM(y, 0, NUM_SONGS_PLAYLIST)) return; byte *p = _playlists[_settings_client.music.playlist]; for (uint i = y; i != NUM_SONGS_PLAYLIST - 1; i++) { p[i] = p[i + 1]; } this->SetDirty(); SelectSongToPlay(); break; } case WID_MTS_CLEAR: // clear for (uint i = 0; _playlists[_settings_client.music.playlist][i] != 0; i++) _playlists[_settings_client.music.playlist][i] = 0; this->SetDirty(); StopMusic(); SelectSongToPlay(); break; case WID_MTS_ALL: case WID_MTS_OLD: case WID_MTS_NEW: case WID_MTS_EZY: case WID_MTS_CUSTOM1: case WID_MTS_CUSTOM2: // set playlist SelectPlaylist(widget - WID_MTS_ALL); StopMusic(); SelectSongToPlay(); break; } } }; static const NWidgetPart _nested_music_track_selection_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_PLAYLIST_MUSIC_PROGRAM_SELECTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2), /* Left panel. */ NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_PLAYLIST_TRACK_INDEX, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_LEFT), SetMinimalSize(180, 194), SetDataTip(0x0, STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), /* Middle buttons. */ NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetMinimalSize(60, 30), // Space above the first button from the title bar. NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_ALL), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_OLD), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_NEW), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_EZY), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM1), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_MTS_CUSTOM2), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED), NWidget(NWID_SPACER), SetMinimalSize(0, 16), // Space above 'clear' button NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_MTS_CLEAR), SetFill(1, 0), SetDataTip(STR_PLAYLIST_CLEAR, STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), /* Right panel. */ NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_GREY, WID_MTS_PLAYLIST), SetDataTip(STR_PLAYLIST_PROGRAM, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY, WID_MTS_LIST_RIGHT), SetMinimalSize(180, 194), SetDataTip(0x0, STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _music_track_selection_desc( WDP_AUTO, "music_track", 0, 0, WC_MUSIC_TRACK_SELECTION, WC_NONE, 0, _nested_music_track_selection_widgets, lengthof(_nested_music_track_selection_widgets) ); static void ShowMusicTrackSelection() { AllocateWindowDescFront(&_music_track_selection_desc, 0); } struct MusicWindow : public Window { static const int slider_width = 3; MusicWindow(WindowDesc *desc, WindowNumber number) : Window(desc) { this->InitNested(number); this->LowerWidget(_settings_client.music.playlist + WID_M_ALL); this->SetWidgetLoweredState(WID_M_SHUFFLE, _settings_client.music.shuffle); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { /* Make sure that WID_M_SHUFFLE and WID_M_PROGRAMME have the same size. * This can't be done by using NC_EQUALSIZE as the WID_M_INFO is * between those widgets and of different size. */ case WID_M_SHUFFLE: case WID_M_PROGRAMME: { Dimension d = maxdim(GetStringBoundingBox(STR_MUSIC_PROGRAM), GetStringBoundingBox(STR_MUSIC_SHUFFLE)); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_M_TRACK_NR: { Dimension d = GetStringBoundingBox(STR_MUSIC_TRACK_NONE); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } case WID_M_TRACK_NAME: { Dimension d = GetStringBoundingBox(STR_MUSIC_TITLE_NONE); for (uint i = 0; i < NUM_SONGS_AVAILABLE; i++) { SetDParamStr(0, GetSongName(i)); d = maxdim(d, GetStringBoundingBox(STR_MUSIC_TITLE_NAME)); } d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } /* Hack-ish: set the proper widget data; only needs to be done once * per (Re)Init as that's the only time the language changes. */ case WID_M_PREV: this->GetWidget(WID_M_PREV)->widget_data = _current_text_dir == TD_RTL ? SPR_IMG_SKIP_TO_NEXT : SPR_IMG_SKIP_TO_PREV; break; case WID_M_NEXT: this->GetWidget(WID_M_NEXT)->widget_data = _current_text_dir == TD_RTL ? SPR_IMG_SKIP_TO_PREV : SPR_IMG_SKIP_TO_NEXT; break; case WID_M_PLAY: this->GetWidget(WID_M_PLAY)->widget_data = _current_text_dir == TD_RTL ? SPR_IMG_PLAY_MUSIC_RTL : SPR_IMG_PLAY_MUSIC; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_M_TRACK_NR: { GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK); StringID str = STR_MUSIC_TRACK_NONE; if (_song_is_active != 0 && _music_wnd_cursong != 0) { SetDParam(0, GetTrackNumber(_music_wnd_cursong - 1)); SetDParam(1, 2); str = STR_MUSIC_TRACK_DIGIT; } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str); break; } case WID_M_TRACK_NAME: { GfxFillRect(r.left, r.top + 1, r.right - 1, r.bottom, PC_BLACK); StringID str = STR_MUSIC_TITLE_NONE; if (_song_is_active != 0 && _music_wnd_cursong != 0) { str = STR_MUSIC_TITLE_NAME; SetDParamStr(0, GetSongName(_music_wnd_cursong - 1)); } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_FROMSTRING, SA_HOR_CENTER); break; } case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: { DrawFrameRect(r.left, r.top + 2, r.right, r.bottom - 2, COLOUR_GREY, FR_LOWERED); byte volume = (widget == WID_M_MUSIC_VOL) ? _settings_client.music.music_vol : _settings_client.music.effect_vol; int x = (volume * (r.right - r.left) / 127); if (_current_text_dir == TD_RTL) { x = r.right - x; } else { x += r.left; } DrawFrameRect(x, r.top, x + slider_width, r.bottom, COLOUR_GREY, FR_NONE); 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; for (int i = 0; i < 6; i++) { this->SetWidgetLoweredState(WID_M_ALL + i, i == _settings_client.music.playlist); } this->SetDirty(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_M_PREV: // skip to prev if (!_song_is_active) return; SkipToPrevSong(); this->SetDirty(); break; case WID_M_NEXT: // skip to next if (!_song_is_active) return; SkipToNextSong(); this->SetDirty(); break; case WID_M_STOP: // stop playing _settings_client.music.playing = false; break; case WID_M_PLAY: // start playing _settings_client.music.playing = true; break; case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: { // volume sliders int x = pt.x - this->GetWidget(widget)->pos_x; byte *vol = (widget == WID_M_MUSIC_VOL) ? &_settings_client.music.music_vol : &_settings_client.music.effect_vol; byte new_vol = x * 127 / this->GetWidget(widget)->current_x; if (_current_text_dir == TD_RTL) new_vol = 127 - new_vol; if (new_vol != *vol) { *vol = new_vol; if (widget == WID_M_MUSIC_VOL) MusicVolumeChanged(new_vol); this->SetDirty(); } _left_button_clicked = false; break; } case WID_M_SHUFFLE: // toggle shuffle _settings_client.music.shuffle ^= 1; this->SetWidgetLoweredState(WID_M_SHUFFLE, _settings_client.music.shuffle); this->SetWidgetDirty(WID_M_SHUFFLE); StopMusic(); SelectSongToPlay(); this->SetDirty(); break; case WID_M_PROGRAMME: // show track selection ShowMusicTrackSelection(); break; case WID_M_ALL: case WID_M_OLD: case WID_M_NEW: case WID_M_EZY: case WID_M_CUSTOM1: case WID_M_CUSTOM2: // playlist SelectPlaylist(widget - WID_M_ALL); StopMusic(); SelectSongToPlay(); this->SetDirty(); break; } } }; static const NWidgetPart _nested_music_window_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MUSIC_JAZZ_JUKEBOX_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY, -1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_PREV), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_SKIP_TO_PREV, STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_NEXT), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_SKIP_TO_NEXT, STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_STOP), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_STOP_MUSIC, STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_M_PLAY), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_PLAY_MUSIC, STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, -1), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_M_SLIDERS), NWidget(NWID_HORIZONTAL), SetPIP(20, 20, 20), NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetFill(1, 0), SetDataTip(STR_MUSIC_MUSIC_VOLUME, STR_NULL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_M_MUSIC_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetDataTip(0x0, STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC), NWidget(NWID_HORIZONTAL), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MIN, STR_NULL), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MAX, STR_NULL), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetFill(1, 0), SetDataTip(STR_MUSIC_EFFECTS_VOLUME, STR_NULL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_M_EFFECT_VOL), SetMinimalSize(67, 0), SetMinimalTextLines(1, 0), SetFill(1, 0), SetDataTip(0x0, STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC), NWidget(NWID_HORIZONTAL), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MIN, STR_NULL), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MARKER, STR_NULL), SetFill(1, 0), NWidget(WWT_LABEL, COLOUR_GREY, -1), SetDataTip(STR_MUSIC_RULER_MAX, STR_NULL), EndContainer(), EndContainer(), EndContainer(), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_M_BACKGROUND), NWidget(NWID_HORIZONTAL), SetPIP(6, 0, 6), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_SHUFFLE), SetMinimalSize(50, 8), SetDataTip(STR_MUSIC_SHUFFLE, STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), NWidget(NWID_VERTICAL), SetPadding(0, 0, 3, 3), NWidget(WWT_LABEL, COLOUR_GREY, WID_M_TRACK), SetFill(0, 0), SetDataTip(STR_MUSIC_TRACK, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NR), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPadding(0, 3, 3, 0), NWidget(WWT_LABEL, COLOUR_GREY, WID_M_TRACK_TITLE), SetFill(1, 0), SetDataTip(STR_MUSIC_XTITLE, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY, WID_M_TRACK_NAME), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_M_PROGRAMME), SetMinimalSize(50, 8), SetDataTip(STR_MUSIC_PROGRAM, STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_ALL), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_ALL, STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_OLD), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_OLD_STYLE, STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_NEW), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_NEW_STYLE, STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_EZY), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_EZY_STREET, STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_CUSTOM1), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_1, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_M_CUSTOM2), SetFill(1, 0), SetDataTip(STR_MUSIC_PLAYLIST_CUSTOM_2, STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED), EndContainer(), }; static WindowDesc _music_window_desc( WDP_AUTO, "music", 0, 0, WC_MUSIC_WINDOW, WC_NONE, 0, _nested_music_window_widgets, lengthof(_nested_music_window_widgets) ); void ShowMusicWindow() { if (BaseMusic::GetUsedSet()->num_available == 0) ShowErrorMessage(STR_ERROR_NO_SONGS, INVALID_STRING_ID, WL_WARNING); AllocateWindowDescFront(&_music_window_desc, 0); } openttd-1.5.3/src/safeguards.h0000644000000000000000000000514312627373441014773 0ustar rootroot/* $Id: safeguards.h 26651 2014-06-17 19:01:45Z rubidium $ */ /* * 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 safeguards.h A number of safeguards to prevent using unsafe methods. * * Unsafe methods are, for example, strndup and strncpy because they may leave the * string without a null termination, but also strdup and strndup because they can * return NULL and then all strdups would need to be guarded against that instead * of using the current MallocT/ReallocT/CallocT technique of just giving the user * an error that too much memory was used instead of spreading that code though * the whole code base. */ #ifndef SAFEGUARDS_H #define SAFEGUARDS_H /* Use MallocT instead. */ #define malloc SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use MallocT instead. */ #define calloc SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use ReallocT instead. */ #define realloc SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use stredup instead. */ #define strdup SAFEGUARD_DO_NOT_USE_THIS_METHOD #define strndup SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use strecpy instead. */ #define strcpy SAFEGUARD_DO_NOT_USE_THIS_METHOD #define strncpy SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use strecat instead. */ #define strcat SAFEGUARD_DO_NOT_USE_THIS_METHOD #define strncat SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use seprintf instead. */ #define sprintf SAFEGUARD_DO_NOT_USE_THIS_METHOD #define snprintf SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use vseprintf instead. */ #define vsprintf SAFEGUARD_DO_NOT_USE_THIS_METHOD #define vsnprintf SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use fgets instead. */ #define gets SAFEGUARD_DO_NOT_USE_THIS_METHOD /* No clear replacement. */ #define strtok SAFEGUARD_DO_NOT_USE_THIS_METHOD /* Use our own templated implementation instead of a macro or function with only one type. */ #ifdef min #undef min #endif /* Use our own templated implementation instead of a macro or function with only one type. */ #ifdef max #undef max #endif /* Use our own templated implementation instead of a macro or function with only one type. */ #ifdef abs #undef abs #endif #endif /* SAFEGUARDS_H */ openttd-1.5.3/src/vehiclelist.cpp0000644000000000000000000001241712627373435015522 0ustar rootroot/* $Id: vehiclelist.cpp 26679 2014-07-08 20:07:21Z frosch $ */ /* * 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 vehiclelist.cpp Lists of vehicles. */ #include "stdafx.h" #include "train.h" #include "vehiclelist.h" #include "group.h" #include "safeguards.h" /** * Pack a VehicleListIdentifier in a single uint32. * @return The packed identifier. */ uint32 VehicleListIdentifier::Pack() const { byte c = this->company == OWNER_NONE ? 0xF : (byte)this->company; assert(c < (1 << 4)); assert(this->vtype < (1 << 2)); assert(this->index < (1 << 20)); assert(this->type < VLT_END); assert_compile(VLT_END <= (1 << 3)); return c << 28 | this->type << 23 | this->vtype << 26 | this->index; } /** * Unpack a VehicleListIdentifier from a single uint32. * @param data The data to unpack. * @return true iff the data was valid (enough). */ bool VehicleListIdentifier::Unpack(uint32 data) { byte c = GB(data, 28, 4); this->company = c == 0xF ? OWNER_NONE : (CompanyID)c; this->type = (VehicleListType)GB(data, 23, 3); this->vtype = (VehicleType)GB(data, 26, 2); this->index = GB(data, 0, 20); return this->type < VLT_END; } /** * Decode a packed vehicle list identifier into a new one. * @param data The data to unpack. */ VehicleListIdentifier::VehicleListIdentifier(uint32 data) { bool ret = this->Unpack(data); assert(ret); } /** * Generate a list of vehicles inside a depot. * @param type Type of vehicle * @param tile The tile the depot is located on * @param engines Pointer to list to add vehicles to * @param wagons Pointer to list to add wagons to (can be NULL) * @param individual_wagons If true add every wagon to \a wagons which is not attached to an engine. If false only add the first wagon of every row. */ void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engines, VehicleList *wagons, bool individual_wagons) { engines->Clear(); if (wagons != NULL && wagons != engines) wagons->Clear(); const Vehicle *v; FOR_ALL_VEHICLES(v) { /* General tests for all vehicle types */ if (v->type != type) continue; if (v->tile != tile) continue; switch (type) { case VEH_TRAIN: { const Train *t = Train::From(v); if (t->IsArticulatedPart() || t->IsRearDualheaded()) continue; if (t->track != TRACK_BIT_DEPOT) continue; if (wagons != NULL && t->First()->IsFreeWagon()) { if (individual_wagons || t->IsFreeWagon()) *wagons->Append() = t; continue; } break; } default: if (!v->IsInDepot()) continue; break; } if (!v->IsPrimaryVehicle()) continue; *engines->Append() = v; } /* Ensure the lists are not wasting too much space. If the lists are fresh * (i.e. built within a command) then this will actually do nothing. */ engines->Compact(); if (wagons != NULL && wagons != engines) wagons->Compact(); } /** * Generate a list of vehicles based on window type. * @param list Pointer to list to add vehicles to * @param vli The identifier of this vehicle list. * @return false if invalid list is requested */ bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &vli) { list->Clear(); const Vehicle *v; switch (vli.type) { case VL_STATION_LIST: FOR_ALL_VEHICLES(v) { if (v->type == vli.vtype && v->IsPrimaryVehicle()) { const Order *order; FOR_VEHICLE_ORDERS(v, order) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) && order->GetDestination() == vli.index) { *list->Append() = v; break; } } } } break; case VL_SHARED_ORDERS: /* Add all vehicles from this vehicle's shared order list */ v = Vehicle::GetIfValid(vli.index); if (v == NULL || v->type != vli.vtype || !v->IsPrimaryVehicle()) return false; for (; v != NULL; v = v->NextShared()) { *list->Append() = v; } break; case VL_GROUP_LIST: if (vli.index != ALL_GROUP) { FOR_ALL_VEHICLES(v) { if (v->type == vli.vtype && v->IsPrimaryVehicle() && v->owner == vli.company && GroupIsInGroup(v->group_id, vli.index)) { *list->Append() = v; } } break; } /* FALL THROUGH */ case VL_STANDARD: FOR_ALL_VEHICLES(v) { if (v->type == vli.vtype && v->owner == vli.company && v->IsPrimaryVehicle()) { *list->Append() = v; } } break; case VL_DEPOT_LIST: FOR_ALL_VEHICLES(v) { if (v->type == vli.vtype && v->IsPrimaryVehicle()) { const Order *order; FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_GOTO_DEPOT) && !(order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && order->GetDestination() == vli.index) { *list->Append() = v; break; } } } } break; default: return false; } list->Compact(); return true; } openttd-1.5.3/src/command_type.h0000644000000000000000000004773112627373434015341 0ustar rootroot/* $Id: command_type.h 26802 2014-09-07 16:12:58Z alberth $ */ /* * 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 command_type.h Types related to commands. */ #ifndef COMMAND_TYPE_H #define COMMAND_TYPE_H #include "economy_type.h" #include "strings_type.h" #include "tile_type.h" struct GRFFile; /** * Common return value for all commands. Wraps the cost and * a possible error message/state together. */ class CommandCost { ExpensesType expense_type; ///< the type of expence as shown on the finances view Money cost; ///< The cost of this action StringID message; ///< Warning message for when success is unset bool success; ///< Whether the comment went fine up to this moment const GRFFile *textref_stack_grffile; ///< NewGRF providing the #TextRefStack content. uint textref_stack_size; ///< Number of uint32 values to put on the #TextRefStack for the error message. static uint32 textref_stack[16]; public: /** * Creates a command cost return with no cost and no error */ CommandCost() : expense_type(INVALID_EXPENSES), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {} /** * Creates a command return value the is failed with the given message */ explicit CommandCost(StringID msg) : expense_type(INVALID_EXPENSES), cost(0), message(msg), success(false), textref_stack_grffile(NULL), textref_stack_size(0) {} /** * Creates a command cost with given expense type and start cost of 0 * @param ex_t the expense type */ explicit CommandCost(ExpensesType ex_t) : expense_type(ex_t), cost(0), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {} /** * Creates a command return value with the given start cost and expense type * @param ex_t the expense type * @param cst the initial cost of this command */ CommandCost(ExpensesType ex_t, const Money &cst) : expense_type(ex_t), cost(cst), message(INVALID_STRING_ID), success(true), textref_stack_grffile(NULL), textref_stack_size(0) {} /** * Adds the given cost to the cost of the command. * @param cost the cost to add */ inline void AddCost(const Money &cost) { this->cost += cost; } void AddCost(const CommandCost &cmd_cost); /** * Multiplies the cost of the command by the given factor. * @param factor factor to multiply the costs with */ inline void MultiplyCost(int factor) { this->cost *= factor; } /** * The costs as made up to this moment * @return the costs */ inline Money GetCost() const { return this->cost; } /** * The expense type of the cost * @return the expense type */ inline ExpensesType GetExpensesType() const { return this->expense_type; } /** * Makes this #CommandCost behave like an error command. * @param message The error message. */ void MakeError(StringID message) { assert(message != INVALID_STRING_ID); this->success = false; this->message = message; } void UseTextRefStack(const GRFFile *grffile, uint num_registers); /** * Returns the NewGRF providing the #TextRefStack of the error message. * @return the NewGRF. */ const GRFFile *GetTextRefStackGRF() const { return this->textref_stack_grffile; } /** * Returns the number of uint32 values for the #TextRefStack of the error message. * @return number of uint32 values. */ uint GetTextRefStackSize() const { return this->textref_stack_size; } /** * Returns a pointer to the values for the #TextRefStack of the error message. * @return uint32 values for the #TextRefStack */ const uint32 *GetTextRefStack() const { return textref_stack; } /** * Returns the error message of a command * @return the error message, if succeeded #INVALID_STRING_ID */ StringID GetErrorMessage() const { if (this->success) return INVALID_STRING_ID; return this->message; } /** * Did this command succeed? * @return true if and only if it succeeded */ inline bool Succeeded() const { return this->success; } /** * Did this command fail? * @return true if and only if it failed */ inline bool Failed() const { return !this->success; } }; /** * List of commands. * * This enum defines all possible commands which can be executed to the game * engine. Observing the game like the query-tool or checking the profit of a * vehicle don't result in a command which should be executed in the engine * nor send to the server in a network game. * * @see _command_proc_table */ enum Commands { CMD_BUILD_RAILROAD_TRACK, ///< build a rail track CMD_REMOVE_RAILROAD_TRACK, ///< remove a rail track CMD_BUILD_SINGLE_RAIL, ///< build a single rail track CMD_REMOVE_SINGLE_RAIL, ///< remove a single rail track CMD_LANDSCAPE_CLEAR, ///< demolish a tile CMD_BUILD_BRIDGE, ///< build a bridge CMD_BUILD_RAIL_STATION, ///< build a rail station CMD_BUILD_TRAIN_DEPOT, ///< build a train depot CMD_BUILD_SIGNALS, ///< build a signal CMD_REMOVE_SIGNALS, ///< remove a signal CMD_TERRAFORM_LAND, ///< terraform a tile CMD_BUILD_OBJECT, ///< build an object CMD_BUILD_TUNNEL, ///< build a tunnel CMD_REMOVE_FROM_RAIL_STATION, ///< remove a (rectangle of) tiles from a rail station CMD_CONVERT_RAIL, ///< convert a rail type CMD_BUILD_RAIL_WAYPOINT, ///< build a waypoint CMD_RENAME_WAYPOINT, ///< rename a waypoint CMD_REMOVE_FROM_RAIL_WAYPOINT, ///< remove a (rectangle of) tiles from a rail waypoint CMD_BUILD_ROAD_STOP, ///< build a road stop CMD_REMOVE_ROAD_STOP, ///< remove a road stop CMD_BUILD_LONG_ROAD, ///< build a complete road (not a "half" one) CMD_REMOVE_LONG_ROAD, ///< remove a complete road (not a "half" one) CMD_BUILD_ROAD, ///< build a "half" road CMD_BUILD_ROAD_DEPOT, ///< build a road depot CMD_BUILD_AIRPORT, ///< build an airport CMD_BUILD_DOCK, ///< build a dock CMD_BUILD_SHIP_DEPOT, ///< build a ship depot CMD_BUILD_BUOY, ///< build a buoy CMD_PLANT_TREE, ///< plant a tree CMD_BUILD_VEHICLE, ///< build a vehicle CMD_SELL_VEHICLE, ///< sell a vehicle CMD_REFIT_VEHICLE, ///< refit the cargo space of a vehicle CMD_SEND_VEHICLE_TO_DEPOT, ///< send a vehicle to a depot CMD_SET_VEHICLE_VISIBILITY, ///< hide or unhide a vehicle in the build vehicle and autoreplace GUIs CMD_MOVE_RAIL_VEHICLE, ///< move a rail vehicle (in the depot) CMD_FORCE_TRAIN_PROCEED, ///< proceed a train to pass a red signal CMD_REVERSE_TRAIN_DIRECTION, ///< turn a train around CMD_CLEAR_ORDER_BACKUP, ///< clear the order backup of a given user/tile CMD_MODIFY_ORDER, ///< modify an order (like set full-load) CMD_SKIP_TO_ORDER, ///< skip an order to the next of specific one CMD_DELETE_ORDER, ///< delete an order CMD_INSERT_ORDER, ///< insert a new order CMD_CHANGE_SERVICE_INT, ///< change the server interval of a vehicle CMD_BUILD_INDUSTRY, ///< build a new industry CMD_SET_COMPANY_MANAGER_FACE, ///< set the manager's face of the company CMD_SET_COMPANY_COLOUR, ///< set the colour of the company CMD_INCREASE_LOAN, ///< increase the loan from the bank CMD_DECREASE_LOAN, ///< decrease the loan from the bank CMD_WANT_ENGINE_PREVIEW, ///< confirm the preview of an engine CMD_RENAME_VEHICLE, ///< rename a whole vehicle CMD_RENAME_ENGINE, ///< rename a engine (in the engine list) CMD_RENAME_COMPANY, ///< change the company name CMD_RENAME_PRESIDENT, ///< change the president name CMD_RENAME_STATION, ///< rename a station CMD_RENAME_DEPOT, ///< rename a depot CMD_PLACE_SIGN, ///< place a sign CMD_RENAME_SIGN, ///< rename a sign CMD_TURN_ROADVEH, ///< turn a road vehicle around CMD_PAUSE, ///< pause the game CMD_BUY_SHARE_IN_COMPANY, ///< buy a share from a company CMD_SELL_SHARE_IN_COMPANY, ///< sell a share from a company CMD_BUY_COMPANY, ///< buy a company which is bankrupt CMD_FOUND_TOWN, ///< found a town CMD_RENAME_TOWN, ///< rename a town CMD_DO_TOWN_ACTION, ///< do a action from the town detail window (like advertises or bribe) CMD_TOWN_CARGO_GOAL, ///< set the goal of a cargo for a town CMD_TOWN_GROWTH_RATE, ///< set the town growth rate CMD_TOWN_SET_TEXT, ///< set the custom text of a town CMD_EXPAND_TOWN, ///< expand a town CMD_DELETE_TOWN, ///< delete a town CMD_ORDER_REFIT, ///< change the refit information of an order (for "goto depot" ) CMD_CLONE_ORDER, ///< clone (and share) an order CMD_CLEAR_AREA, ///< clear an area CMD_MONEY_CHEAT, ///< do the money cheat CMD_CHANGE_BANK_BALANCE, ///< change bank balance to charge costs or give money from a GS CMD_BUILD_CANAL, ///< build a canal CMD_CREATE_SUBSIDY, ///< create a new subsidy CMD_COMPANY_CTRL, ///< used in multiplayer to create a new companies etc. CMD_CUSTOM_NEWS_ITEM, ///< create a custom news message CMD_CREATE_GOAL, ///< create a new goal CMD_REMOVE_GOAL, ///< remove a goal CMD_SET_GOAL_TEXT, ///< update goal text of a goal CMD_SET_GOAL_PROGRESS, ///< update goal progress text of a goal CMD_SET_GOAL_COMPLETED, ///< update goal completed status of a goal CMD_GOAL_QUESTION, ///< ask a goal related question CMD_GOAL_QUESTION_ANSWER, ///< answer(s) to CMD_GOAL_QUESTION CMD_CREATE_STORY_PAGE, ///< create a new story page CMD_CREATE_STORY_PAGE_ELEMENT, ///< create a new story page element CMD_UPDATE_STORY_PAGE_ELEMENT, ///< update a story page element CMD_SET_STORY_PAGE_TITLE, ///< update title of a story page CMD_SET_STORY_PAGE_DATE, ///< update date of a story page CMD_SHOW_STORY_PAGE, ///< show a story page CMD_REMOVE_STORY_PAGE, ///< remove a story page CMD_REMOVE_STORY_PAGE_ELEMENT, ///< remove a story page element CMD_LEVEL_LAND, ///< level land CMD_BUILD_LOCK, ///< build a lock CMD_BUILD_SIGNAL_TRACK, ///< add signals along a track (by dragging) CMD_REMOVE_SIGNAL_TRACK, ///< remove signals along a track (by dragging) CMD_GIVE_MONEY, ///< give money to another company CMD_CHANGE_SETTING, ///< change a setting CMD_CHANGE_COMPANY_SETTING, ///< change a company setting CMD_SET_AUTOREPLACE, ///< set an autoreplace entry CMD_CLONE_VEHICLE, ///< clone a vehicle CMD_START_STOP_VEHICLE, ///< start or stop a vehicle CMD_MASS_START_STOP, ///< start/stop all vehicles (in a depot) CMD_AUTOREPLACE_VEHICLE, ///< replace/renew a vehicle while it is in a depot CMD_DEPOT_SELL_ALL_VEHICLES, ///< sell all vehicles which are in a given depot CMD_DEPOT_MASS_AUTOREPLACE, ///< force the autoreplace to take action in a given depot CMD_CREATE_GROUP, ///< create a new group CMD_DELETE_GROUP, ///< delete a group CMD_ALTER_GROUP, ///< alter a group CMD_ADD_VEHICLE_GROUP, ///< add a vehicle to a group CMD_ADD_SHARED_VEHICLE_GROUP, ///< add all other shared vehicles to a group which are missing CMD_REMOVE_ALL_VEHICLES_GROUP, ///< remove all vehicles from a group CMD_SET_GROUP_REPLACE_PROTECTION, ///< set the autoreplace-protection for a group CMD_MOVE_ORDER, ///< move an order 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_SET_TIMETABLE_START, ///< set the date that a timetable should start CMD_OPEN_CLOSE_AIRPORT, ///< open/close an airport to incoming aircraft CMD_END, ///< Must ALWAYS be on the end of this list!! (period) }; /** * List of flags for a command. * * This enums defines some flags which can be used for the commands. */ enum DoCommandFlag { DC_NONE = 0x000, ///< no flag is set DC_EXEC = 0x001, ///< execute the given command DC_AUTO = 0x002, ///< don't allow building on structures DC_QUERY_COST = 0x004, ///< query cost only, don't build. DC_NO_WATER = 0x008, ///< don't allow building on water DC_NO_RAIL_OVERLAP = 0x010, ///< don't allow overlap of rails (used in buildrail) DC_NO_TEST_TOWN_RATING = 0x020, ///< town rating does not disallow you from building DC_BANKRUPT = 0x040, ///< company bankrupts, skip money check, skip vehicle on tile check in some cases DC_AUTOREPLACE = 0x080, ///< autoreplace/autorenew is in progress, this shall disable vehicle limits when building, and ignore certain restrictions when undoing things (like vehicle attach callback) DC_NO_CARGO_CAP_CHECK = 0x100, ///< when autoreplace/autorenew is in progress, this shall prevent truncating the amount of cargo in the vehicle to prevent testing the command to remove cargo DC_ALL_TILES = 0x200, ///< allow this command also on MP_VOID tiles DC_NO_MODIFY_TOWN_RATING = 0x400, ///< do not change town rating DC_FORCE_CLEAR_TILE = 0x800, ///< do not only remove the object on the tile, but also clear any water left on it }; DECLARE_ENUM_AS_BIT_SET(DoCommandFlag) /** * Used to combine a StringID with the command. * * This macro can be used to add a StringID (the error message to show) on a command-id * (CMD_xxx). Use the binary or-operator "|" to combine the command with the result from * this macro. * * @param x The StringID to combine with a command-id */ #define CMD_MSG(x) ((x) << 16) /** * Defines some flags. * * This enumeration defines some flags which are binary-or'ed on a command. */ enum FlaggedCommands { CMD_NETWORK_COMMAND = 0x0100, ///< execute the command without sending it on the network CMD_FLAGS_MASK = 0xFF00, ///< mask for all command flags CMD_ID_MASK = 0x00FF, ///< mask for the command ID }; /** * Command flags for the command table _command_proc_table. * * This enumeration defines flags for the _command_proc_table. */ enum CommandFlags { CMD_SERVER = 0x001, ///< the command can only be initiated by the server CMD_SPECTATOR = 0x002, ///< the command may be initiated by a spectator CMD_OFFLINE = 0x004, ///< the command cannot be executed in a multiplayer game; single-player only CMD_AUTO = 0x008, ///< set the DC_AUTO flag on this command CMD_ALL_TILES = 0x010, ///< allow this command also on MP_VOID tiles CMD_NO_TEST = 0x020, ///< the command's output may differ between test and execute due to town rating changes etc. CMD_NO_WATER = 0x040, ///< set the DC_NO_WATER flag on this command CMD_CLIENT_ID = 0x080, ///< set p2 with the ClientID of the sending client. CMD_DEITY = 0x100, ///< the command may be executed by COMPANY_DEITY CMD_STR_CTRL = 0x200, ///< the command's string may contain control strings }; DECLARE_ENUM_AS_BIT_SET(CommandFlags) /** Types of commands we have. */ enum CommandType { CMDT_LANDSCAPE_CONSTRUCTION, ///< Construction and destruction of objects on the map. CMDT_VEHICLE_CONSTRUCTION, ///< Construction, modification (incl. refit) and destruction of vehicles. CMDT_MONEY_MANAGEMENT, ///< Management of money, i.e. loans and shares. CMDT_VEHICLE_MANAGEMENT, ///< Stopping, starting, sending to depot, turning around, replace orders etc. CMDT_ROUTE_MANAGEMENT, ///< Modifications to route management (orders, groups, etc). CMDT_OTHER_MANAGEMENT, ///< Renaming stuff, changing company colours, placing signs, etc. CMDT_COMPANY_SETTING, ///< Changing settings related to a company. CMDT_SERVER_SETTING, ///< Pausing/removing companies/server settings. CMDT_CHEAT, ///< A cheat of some sorts. CMDT_END, ///< Magic end marker. }; /** Different command pause levels. */ enum CommandPauseLevel { CMDPL_NO_ACTIONS, ///< No user actions may be executed. CMDPL_NO_CONSTRUCTION, ///< No construction actions may be executed. CMDPL_NO_LANDSCAPING, ///< No landscaping actions may be executed. CMDPL_ALL_ACTIONS, ///< All actions may be executed. }; /** * Defines the callback type for all command handler functions. * * This type defines the function header for all functions which handles a CMD_* command. * A command handler use the parameters to act according to the meaning of the command. * The tile parameter defines the tile to perform an action on. * The flag parameter is filled with flags from the DC_* enumeration. The parameters * p1 and p2 are filled with parameters for the command like "which road type", "which * order" or "direction". Each function should mentioned in there doxygen comments * the usage of these parameters. * * @param tile The tile to apply a command on * @param flags Flags for the command, from the DC_* enumeration * @param p1 Additional data for the command * @param p2 Additional data for the command * @param text Additional text * @return The CommandCost of the command, which can be succeeded or failed. */ typedef CommandCost CommandProc(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text); /** * Define a command with the flags which belongs to it. * * This struct connect a command handler function with the flags created with * the #CMD_AUTO, #CMD_OFFLINE and #CMD_SERVER values. */ struct Command { CommandProc *proc; ///< The procedure to actually executing const char *name; ///< A human readable name for the procedure CommandFlags flags; ///< The (command) flags to that apply to this command CommandType type; ///< The type of command. }; /** * Define a callback function for the client, after the command is finished. * * Functions of this type are called after the command is finished. The parameters * are from the #CommandProc callback type. The boolean parameter indicates if the * command succeeded or failed. * * @param result The result of the executed command * @param tile The tile of the command action * @param p1 Additional data of the command * @param p1 Additional data of the command * @see CommandProc */ typedef void CommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2); /** * Structure for buffering the build command when selecting a station to join. */ struct CommandContainer { TileIndex tile; ///< tile command being executed on. uint32 p1; ///< parameter p1. uint32 p2; ///< parameter p2. uint32 cmd; ///< command being executed. CommandCallback *callback; ///< any callback function executed upon successful completion of the command. char text[32 * MAX_CHAR_LENGTH]; ///< possible text sent for name changes etc, in bytes including '\0'. }; #endif /* COMMAND_TYPE_H */ openttd-1.5.3/src/misc/0000755000000000000000000000000012627373436013432 5ustar rootrootopenttd-1.5.3/src/misc/dbg_helpers.h0000644000000000000000000001205412627373436016063 0ustar rootroot/* $Id: dbg_helpers.h 20603 2010-08-23 22:03:36Z rubidium $ */ /* * 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 dbg_helpers.h Functions to be used for debug printings. */ #ifndef DBG_HELPERS_H #define DBG_HELPERS_H #include #include #include "str.hpp" #include "../direction_type.h" #include "../signal_type.h" #include "../tile_type.h" #include "../track_type.h" /** Helper template class that provides C array length and item type */ template struct ArrayT; /** Helper template class that provides C array length and item type */ template struct ArrayT { static const size_t length = N; typedef T item_t; }; /** * Helper template function that returns item of array at given index * or t_unk when index is out of bounds. */ template inline typename ArrayT::item_t ItemAtT(E idx, const T &t, typename ArrayT::item_t t_unk) { if ((size_t)idx >= ArrayT::length) { return t_unk; } return t[idx]; } /** * Helper template function that returns item of array at given index * or t_inv when index == idx_inv * or t_unk when index is out of bounds. */ template inline typename ArrayT::item_t ItemAtT(E idx, const T &t, typename ArrayT::item_t t_unk, E idx_inv, typename ArrayT::item_t t_inv) { if ((size_t)idx < ArrayT::length) { return t[idx]; } if (idx == idx_inv) { return t_inv; } return t_unk; } /** * Helper template function that returns compound bitfield name that is * concatenation of names of each set bit in the given value * or t_inv when index == idx_inv * or t_unk when index is out of bounds. */ template inline CStrA ComposeNameT(E value, T &t, const char *t_unk, E val_inv, const char *name_inv) { CStrA out; if (value == val_inv) { out = name_inv; } else if (value == 0) { out = ""; } else { for (size_t i = 0; i < ArrayT::length; i++) { if ((value & (1 << i)) == 0) continue; out.AddFormat("%s%s", (out.Size() > 0 ? "+" : ""), (const char*)t[i]); value &= ~(E)(1 << i); } if (value != 0) out.AddFormat("%s%s", (out.Size() > 0 ? "+" : ""), t_unk); } return out.Transfer(); } CStrA ValueStr(Trackdir td); CStrA ValueStr(TrackdirBits td_bits); CStrA ValueStr(DiagDirection dd); CStrA ValueStr(SignalType t); /** Class that represents the dump-into-string target. */ struct DumpTarget { /** Used as a key into map of known object instances. */ struct KnownStructKey { size_t m_type_id; const void *m_ptr; KnownStructKey(size_t type_id, const void *ptr) : m_type_id(type_id) , m_ptr(ptr) {} KnownStructKey(const KnownStructKey &src) { m_type_id = src.m_type_id; m_ptr = src.m_ptr; } bool operator < (const KnownStructKey &other) const { if ((size_t)m_ptr < (size_t)other.m_ptr) return true; if ((size_t)m_ptr > (size_t)other.m_ptr) return false; if (m_type_id < other.m_type_id) return true; return false; } }; typedef std::map KNOWN_NAMES; CStrA m_out; ///< the output string int m_indent; ///< current indent/nesting level std::stack m_cur_struct; ///< here we will track the current structure name KNOWN_NAMES m_known_names; ///< map of known object instances and their structured names DumpTarget() : m_indent(0) {} static size_t& LastTypeId(); CStrA GetCurrentStructName(); bool FindKnownName(size_t type_id, const void *ptr, CStrA &name); void WriteIndent(); void CDECL WriteLine(const char *format, ...) WARN_FORMAT(2, 3); void WriteValue(const char *name, const char *value_str); void WriteTile(const char *name, TileIndex t); /** Dump given enum value (as a number and as named value) */ template void WriteEnumT(const char *name, E e) { WriteValue(name, ValueStr(e).Data()); } void BeginStruct(size_t type_id, const char *name, const void *ptr); void EndStruct(); /** Dump nested object (or only its name if this instance is already known). */ template void WriteStructT(const char *name, const S *s) { static size_t type_id = ++LastTypeId(); if (s == NULL) { /* No need to dump NULL struct. */ WriteLine("%s = ", name); return; } CStrA known_as; if (FindKnownName(type_id, s, known_as)) { /* We already know this one, no need to dump it. */ WriteLine("%s = known_as.%s", name, known_as.Data()); } else { /* Still unknown, dump it */ BeginStruct(type_id, name, s); s->Dump(*this); EndStruct(); } } }; #endif /* DBG_HELPERS_H */ openttd-1.5.3/src/misc/countedptr.hpp0000644000000000000000000001226012627373436016333 0ustar rootroot/* $Id: countedptr.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 countedptr.hpp CCountedPtr - smart pointer implementation. */ #ifndef COUNTEDPTR_HPP #define COUNTEDPTR_HPP /** * CCountedPtr - simple reference counting smart pointer. * * One of the standard ways how to maintain object's lifetime. * * See http://ootips.org/yonat/4dev/smart-pointers.html for more * general info about smart pointers. * * This class implements ref-counted pointer for objects/interfaces that * support AddRef() and Release() methods. */ template class CCountedPtr { /** redefine the template argument to make it visible for derived classes */ public: typedef Tcls_ Tcls; protected: /** here we hold our pointer to the target */ Tcls *m_pT; public: /** default (NULL) construct or construct from a raw pointer */ inline CCountedPtr(Tcls *pObj = NULL) : m_pT(pObj) {AddRef();} /** copy constructor (invoked also when initializing from another smart ptr) */ inline CCountedPtr(const CCountedPtr& src) : m_pT(src.m_pT) {AddRef();} /** destructor releasing the reference */ inline ~CCountedPtr() {Release();} protected: /** add one ref to the underlaying object */ inline void AddRef() {if (m_pT != NULL) m_pT->AddRef();} public: /** release smart pointer (and decrement ref count) if not null */ inline void Release() {if (m_pT != NULL) {Tcls *pT = m_pT; m_pT = NULL; pT->Release();}} /** dereference of smart pointer - const way */ inline const Tcls *operator -> () const {assert(m_pT != NULL); return m_pT;} /** dereference of smart pointer - non const way */ inline Tcls *operator -> () {assert(m_pT != NULL); return m_pT;} /** raw pointer casting operator - const way */ inline operator const Tcls*() const {assert(m_pT == NULL); return m_pT;} /** raw pointer casting operator - non-const way */ inline operator Tcls*() {return m_pT;} /** operator & to support output arguments */ inline Tcls** operator &() {assert(m_pT == NULL); return &m_pT;} /** assignment operator from raw ptr */ inline CCountedPtr& operator = (Tcls *pT) {Assign(pT); return *this;} /** assignment operator from another smart ptr */ inline CCountedPtr& operator = (const CCountedPtr& src) {Assign(src.m_pT); return *this;} /** assignment operator helper */ inline void Assign(Tcls *pT); /** one way how to test for NULL value */ inline bool IsNull() const {return m_pT == NULL;} /** another way how to test for NULL value */ //inline bool operator == (const CCountedPtr& sp) const {return m_pT == sp.m_pT;} /** yet another way how to test for NULL value */ //inline bool operator != (const CCountedPtr& sp) const {return m_pT != sp.m_pT;} /** assign pointer w/o incrementing ref count */ inline void Attach(Tcls *pT) {Release(); m_pT = pT;} /** detach pointer w/o decrementing ref count */ inline Tcls *Detach() {Tcls *pT = m_pT; m_pT = NULL; return pT;} }; template inline void CCountedPtr::Assign(Tcls *pT) { /* if they are the same, we do nothing */ if (pT != m_pT) { if (pT != NULL) pT->AddRef(); // AddRef new pointer if any Tcls *pTold = m_pT; // save original ptr m_pT = pT; // update m_pT to new value if (pTold != NULL) pTold->Release(); // release old ptr if any } } /** * Adapter wrapper for CCountedPtr like classes that can't be used directly by stl * collections as item type. For example CCountedPtr has overloaded operator & which * prevents using CCountedPtr in stl collections (i.e. std::list >) */ template struct AdaptT { T m_t; /** construct by wrapping the given object */ AdaptT(const T &t) : m_t(t) {} /** assignment operator */ T& operator = (const T &t) { m_t = t; return t; } /** type-cast operator (used when AdaptT is used instead of T) */ operator T& () { return m_t; } /** const type-cast operator (used when AdaptT is used instead of const T) */ operator const T& () const { return m_t; } }; /** * Simple counted object. Use it as base of your struct/class if you want to use * basic reference counting. Your struct/class will destroy and free itself when * last reference to it is released (using Release() method). The initial reference * count (when it is created) is zero (don't forget AddRef() at least one time if * not using CCountedPtr. * * @see misc/countedobj.cpp for implementation. */ struct SimpleCountedObject { int32 m_ref_cnt; SimpleCountedObject() : m_ref_cnt(0) {} virtual ~SimpleCountedObject() {} virtual int32 AddRef(); virtual int32 Release(); virtual void FinalRelease() {}; }; #endif /* COUNTEDPTR_HPP */ openttd-1.5.3/src/misc/countedobj.cpp0000644000000000000000000000176012627373436016276 0ustar rootroot/* $Id: countedobj.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 countedobj.cpp Support for reference counted objects. */ #include "../stdafx.h" #include "countedptr.hpp" #include "../safeguards.h" int32 SimpleCountedObject::AddRef() { return ++m_ref_cnt; } int32 SimpleCountedObject::Release() { int32 res = --m_ref_cnt; assert(res >= 0); if (res == 0) { FinalRelease(); delete this; } return res; } openttd-1.5.3/src/misc/binaryheap.hpp0000644000000000000000000001637312627373436016277 0ustar rootroot/* $Id: binaryheap.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 binaryheap.hpp Binary heap implementation. */ #ifndef BINARYHEAP_HPP #define BINARYHEAP_HPP #include "../core/alloc_func.hpp" /** Enable it if you suspect binary heap doesn't work well */ #define BINARYHEAP_CHECK 0 #if BINARYHEAP_CHECK /** Check for consistency. */ #define CHECK_CONSISTY() this->CheckConsistency() #else /** Don't check for consistency. */ #define CHECK_CONSISTY() ; #endif /** * Binary Heap as C++ template. * A carrier which keeps its items automatically holds the smallest item at * the first position. The order of items is maintained by using a binary tree. * The implementation is used for priority queue's. * * @par Usage information: * Item of the binary heap should support the 'lower-than' operator '<'. * It is used for comparing items before moving them to their position. * * @par * This binary heap allocates just the space for item pointers. The items * are allocated elsewhere. * * @par Implementation notes: * Internally the first item is never used, because that simplifies the * implementation. * * @par * For further information about the Binary Heap algorithm, see * http://www.policyalmanac.org/games/binaryHeaps.htm * * @tparam T Type of the items stored in the binary heap */ template class CBinaryHeapT { private: uint items; ///< Number of items in the heap uint capacity; ///< Maximum number of items the heap can hold T **data; ///< The pointer to the heap item pointers public: /** * Create a binary heap. * @param max_items The limit of the heap */ explicit CBinaryHeapT(uint max_items) : items(0) , capacity(max_items) { this->data = MallocT(max_items + 1); } ~CBinaryHeapT() { this->Clear(); free(this->data); this->data = NULL; } protected: /** * Get position for fixing a gap (downwards). * The gap is moved downwards in the binary tree until it * is in order again. * * @param gap The position of the gap * @param item The proposed item for filling the gap * @return The (gap)position where the item fits */ inline uint HeapifyDown(uint gap, T *item) { assert(gap != 0); /* The first child of the gap is at [parent * 2] */ uint child = gap * 2; /* while children are valid */ while (child <= this->items) { /* choose the smaller child */ if (child < this->items && *this->data[child + 1] < *this->data[child]) { child++; } /* is it smaller than our parent? */ if (!(*this->data[child] < *item)) { /* the smaller child is still bigger or same as parent => we are done */ break; } /* if smaller child is smaller than parent, it will become new parent */ this->data[gap] = this->data[child]; gap = child; /* where do we have our new children? */ child = gap * 2; } return gap; } /** * Get position for fixing a gap (upwards). * The gap is moved upwards in the binary tree until the * is in order again. * * @param gap The position of the gap * @param item The proposed item for filling the gap * @return The (gap)position where the item fits */ inline uint HeapifyUp(uint gap, T *item) { assert(gap != 0); uint parent; while (gap > 1) { /* compare [gap] with its parent */ parent = gap / 2; if (!(*item < *this->data[parent])) { /* we don't need to continue upstairs */ break; } this->data[gap] = this->data[parent]; gap = parent; } return gap; } #if BINARYHEAP_CHECK /** Verify the heap consistency */ inline void CheckConsistency() { for (uint child = 2; child <= this->items; child++) { uint parent = child / 2; assert(!(*this->data[child] < *this->data[parent])); } } #endif public: /** * Get the number of items stored in the priority queue. * * @return The number of items in the queue */ inline uint Length() const { return this->items; } /** * Test if the priority queue is empty. * * @return True if empty */ inline bool IsEmpty() const { return this->items == 0; } /** * Test if the priority queue is full. * * @return True if full. */ inline bool IsFull() const { return this->items >= this->capacity; } /** * Get the smallest item in the binary tree. * * @return The smallest item, or throw assert if empty. */ inline T *Begin() { assert(!this->IsEmpty()); return this->data[1]; } /** * Get the LAST item in the binary tree. * * @note The last item is not necessary the biggest! * * @return The last item */ inline T *End() { return this->data[1 + this->items]; } /** * Insert new item into the priority queue, maintaining heap order. * * @param new_item The pointer to the new item */ inline void Include(T *new_item) { if (this->IsFull()) { assert(this->capacity < UINT_MAX / 2); this->capacity *= 2; this->data = ReallocT(this->data, this->capacity + 1); } /* Make place for new item. A gap is now at the end of the tree. */ uint gap = this->HeapifyUp(++items, new_item); this->data[gap] = new_item; CHECK_CONSISTY(); } /** * Remove and return the smallest (and also first) item * from the priority queue. * * @return The pointer to the removed item */ inline T *Shift() { assert(!this->IsEmpty()); T *first = this->Begin(); this->items--; /* at index 1 we have a gap now */ T *last = this->End(); uint gap = this->HeapifyDown(1, last); /* move last item to the proper place */ if (!this->IsEmpty()) this->data[gap] = last; CHECK_CONSISTY(); return first; } /** * Remove item at given index from the priority queue. * * @param index The position of the item in the heap */ inline void Remove(uint index) { if (index < this->items) { assert(index != 0); this->items--; /* at position index we have a gap now */ T *last = this->End(); /* Fix binary tree up and downwards */ uint gap = this->HeapifyUp(index, last); gap = this->HeapifyDown(gap, last); /* move last item to the proper place */ if (!this->IsEmpty()) this->data[gap] = last; } else { assert(index == this->items); this->items--; } CHECK_CONSISTY(); } /** * Search for an item in the priority queue. * Matching is done by comparing address of the * item. * * @param item The reference to the item * @return The index of the item or zero if not found */ inline uint FindIndex(const T &item) const { if (this->IsEmpty()) return 0; for (T **ppI = this->data + 1, **ppLast = ppI + this->items; ppI <= ppLast; ppI++) { if (*ppI == &item) { return ppI - this->data; } } return 0; } /** * Make the priority queue empty. * All remaining items will remain untouched. */ inline void Clear() { this->items = 0; } }; #endif /* BINARYHEAP_HPP */ openttd-1.5.3/src/misc/fixedsizearray.hpp0000644000000000000000000001057612627373436017205 0ustar rootroot/* $Id: fixedsizearray.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 fixedsizearray.hpp A fixed size array that doesn't create items until needed. */ #ifndef FIXEDSIZEARRAY_HPP #define FIXEDSIZEARRAY_HPP #include "../core/alloc_func.hpp" /** * fixed size array * Upon construction it preallocates fixed size block of memory * for all items, but doesn't construct them. Item's construction * is delayed. */ template struct FixedSizeArray { protected: /** header for fixed size array */ struct ArrayHeader { uint items; ///< number of items in the array uint reference_count; ///< block reference counter (used by copy constructor and by destructor) }; /* make constants visible from outside */ static const uint Tsize = sizeof(T); ///< size of item static const uint HeaderSize = sizeof(ArrayHeader); ///< size of header /** * the only member of fixed size array is pointer to the block * of C array of items. Header can be found on the offset -sizeof(ArrayHeader). */ T *data; /** return reference to the array header (non-const) */ inline ArrayHeader& Hdr() { return *(ArrayHeader*)(((byte*)data) - HeaderSize); } /** return reference to the array header (const) */ inline const ArrayHeader& Hdr() const { return *(ArrayHeader*)(((byte*)data) - HeaderSize); } /** return reference to the block reference counter */ inline uint& RefCnt() { return Hdr().reference_count; } /** return reference to number of used items */ inline uint& SizeRef() { return Hdr().items; } public: /** Default constructor. Preallocate space for items and header, then initialize header. */ FixedSizeArray() { /* Ensure the size won't overflow. */ assert_compile(C < (SIZE_MAX - HeaderSize) / Tsize); /* allocate block for header + items (don't construct items) */ data = (T*)((MallocT(HeaderSize + C * Tsize)) + HeaderSize); SizeRef() = 0; // initial number of items RefCnt() = 1; // initial reference counter } /** Copy constructor. Preallocate space for items and header, then initialize header. */ FixedSizeArray(const FixedSizeArray& src) { /* share block (header + items) with the source array */ data = src.data; RefCnt()++; // now we share block with the source } /** destroy remaining items and free the memory block */ ~FixedSizeArray() { /* release one reference to the shared block */ if ((--RefCnt()) > 0) return; // and return if there is still some owner Clear(); /* free the memory block occupied by items */ free(((byte*)data) - HeaderSize); data = NULL; } /** Clear (destroy) all items */ inline void Clear() { /* Walk through all allocated items backward and destroy them * Note: this->Length() can be zero. In that case data[this->Length() - 1] is evaluated unsigned * on some compilers with some architectures. (e.g. gcc with x86) */ for (T *pItem = this->data + this->Length() - 1; pItem >= this->data; pItem--) { pItem->~T(); } /* number of items become zero */ SizeRef() = 0; } /** return number of used items */ inline uint Length() const { return Hdr().items; } /** return true if array is full */ inline bool IsFull() const { return Length() >= C; } /** return true if array is empty */ inline bool IsEmpty() const { return Length() <= 0; } /** add (allocate), but don't construct item */ inline T *Append() { assert(!IsFull()); return &data[SizeRef()++]; } /** add and construct item using default constructor */ inline T *AppendC() { T *item = Append(); new(item)T; return item; } /** return item by index (non-const version) */ inline T& operator [] (uint index) { assert(index < Length()); return data[index]; } /** return item by index (const version) */ inline const T& operator [] (uint index) const { assert(index < Length()); return data[index]; } }; #endif /* FIXEDSIZEARRAY_HPP */ openttd-1.5.3/src/misc/dbg_helpers.cpp0000644000000000000000000001152212627373436016415 0ustar rootroot/* $Id: dbg_helpers.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 dbg_helpers.cpp Helpers for outputting debug information. */ #include "../stdafx.h" #include "../rail_map.h" #include "dbg_helpers.h" #include "../safeguards.h" /** Trackdir & TrackdirBits short names. */ static const char * const trackdir_names[] = { "NE", "SE", "UE", "LE", "LS", "RS", "rne", "rse", "SW", "NW", "UW", "LW", "LN", "RN", "rsw", "rnw", }; /** Return name of given Trackdir. */ CStrA ValueStr(Trackdir td) { CStrA out; out.Format("%d (%s)", td, ItemAtT(td, trackdir_names, "UNK", INVALID_TRACKDIR, "INV")); return out.Transfer(); } /** Return composed name of given TrackdirBits. */ CStrA ValueStr(TrackdirBits td_bits) { CStrA out; out.Format("%d (%s)", td_bits, ComposeNameT(td_bits, trackdir_names, "UNK", INVALID_TRACKDIR_BIT, "INV").Data()); return out.Transfer(); } /** DiagDirection short names. */ static const char * const diagdir_names[] = { "NE", "SE", "SW", "NW", }; /** Return name of given DiagDirection. */ CStrA ValueStr(DiagDirection dd) { CStrA out; out.Format("%d (%s)", dd, ItemAtT(dd, diagdir_names, "UNK", INVALID_DIAGDIR, "INV")); return out.Transfer(); } /** SignalType short names. */ static const char * const signal_type_names[] = { "NORMAL", "ENTRY", "EXIT", "COMBO", "PBS", "NOENTRY", }; /** Return name of given SignalType. */ CStrA ValueStr(SignalType t) { CStrA out; out.Format("%d (%s)", t, ItemAtT(t, signal_type_names, "UNK")); return out.Transfer(); } /** Translate TileIndex into string. */ CStrA TileStr(TileIndex tile) { CStrA out; out.Format("0x%04X (%d, %d)", tile, TileX(tile), TileY(tile)); return out.Transfer(); } /** * Keep track of the last assigned type_id. Used for anti-recursion. *static*/ size_t& DumpTarget::LastTypeId() { static size_t last_type_id = 0; return last_type_id; } /** Return structured name of the current class/structure. */ CStrA DumpTarget::GetCurrentStructName() { CStrA out; if (!m_cur_struct.empty()) { /* we are inside some named struct, return its name */ out = m_cur_struct.top(); } return out.Transfer(); } /** * Find the given instance in our anti-recursion repository. * Return true and set name when object was found. */ bool DumpTarget::FindKnownName(size_t type_id, const void *ptr, CStrA &name) { KNOWN_NAMES::const_iterator it = m_known_names.find(KnownStructKey(type_id, ptr)); if (it != m_known_names.end()) { /* we have found it */ name = (*it).second; return true; } return false; } /** Write some leading spaces into the output. */ void DumpTarget::WriteIndent() { int num_spaces = 2 * m_indent; if (num_spaces > 0) { memset(m_out.GrowSizeNC(num_spaces), ' ', num_spaces); } } /** Write a line with indent at the beginning and at the end. */ void DumpTarget::WriteLine(const char *format, ...) { WriteIndent(); va_list args; va_start(args, format); m_out.AddFormatL(format, args); va_end(args); m_out.AppendStr("\n"); } /** Write 'name = value' with indent and new-line. */ void DumpTarget::WriteValue(const char *name, const char *value_str) { WriteIndent(); m_out.AddFormat("%s = %s\n", name, value_str); } /** Write name & TileIndex to the output. */ void DumpTarget::WriteTile(const char *name, TileIndex tile) { WriteIndent(); m_out.AddFormat("%s = %s\n", name, TileStr(tile).Data()); } /** * Open new structure (one level deeper than the current one) 'name = {'. */ void DumpTarget::BeginStruct(size_t type_id, const char *name, const void *ptr) { /* make composite name */ CStrA cur_name = GetCurrentStructName().Transfer(); if (cur_name.Size() > 0) { /* add name delimiter (we use structured names) */ cur_name.AppendStr("."); } cur_name.AppendStr(name); /* put the name onto stack (as current struct name) */ m_cur_struct.push(cur_name); /* put it also to the map of known structures */ m_known_names.insert(KNOWN_NAMES::value_type(KnownStructKey(type_id, ptr), cur_name)); WriteIndent(); m_out.AddFormat("%s = {\n", name); m_indent++; } /** * Close structure '}'. */ void DumpTarget::EndStruct() { m_indent--; WriteIndent(); m_out.AddFormat("}\n"); /* remove current struct name from the stack */ m_cur_struct.pop(); } /** Just to silence an unsilencable GCC 4.4+ warning */ /* static */ ByteBlob::BlobHeader ByteBlob::hdrEmpty[] = {{0, 0}, {0, 0}}; openttd-1.5.3/src/misc/getoptdata.h0000644000000000000000000001053512627373436015743 0ustar rootroot/* $Id: getoptdata.h 23245 2011-11-17 21:18:24Z rubidium $ */ /* * 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 getoptdata.h Library for parsing command-line options. */ #ifndef GETOPTDATA_H #define GETOPTDATA_H /** Flags of an option. */ enum OptionDataFlags { ODF_NO_VALUE, ///< A plain option (no value attached to it). ODF_HAS_VALUE, ///< An option with a value. ODF_OPTIONAL_VALUE, ///< An option with an optional value. ODF_END, ///< Terminator (data is not parsed further). }; /** Data of an option. */ struct OptionData { byte id; ///< Unique identification of this option data, often the same as #shortname. char shortname; ///< Short option letter if available, else use \c '\0'. uint16 flags; ///< Option data flags. @see OptionDataFlags const char *longname; ///< Long option name including '-'/'--' prefix, use \c NULL if not available. }; /** Data storage for parsing command line options. */ struct GetOptData { char *opt; ///< Option value, if available (else \c NULL). int numleft; ///< Number of arguments left in #argv. char **argv; ///< Remaining command line arguments. const OptionData *options; ///< Command line option descriptions. char *cont; ///< Next call to #MyGetOpt should start here (in the middle of an argument). /** * Constructor of the data store. * @param argc Number of command line arguments, excluding the program name. * @param argv Command line arguments, excluding the program name. * @param options Command line option descriptions. */ GetOptData(int argc, char **argv, const OptionData *options) : opt(NULL), numleft(argc), argv(argv), options(options), cont(NULL) { } int GetOpt(); }; /** * General macro for creating an option. * @param id Identification of the option. * @param shortname Short option name. Use \c '\0' if not used. * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. * @param flags Flags of the option. */ #define GETOPT_GENERAL(id, shortname, longname, flags) { id, shortname, flags, longname } /** * Short option without value. * @param shortname Short option name. Use \c '\0' if not used. * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. */ #define GETOPT_NOVAL(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_NO_VALUE) /** * Short option with value. * @param shortname Short option name. Use \c '\0' if not used. * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. */ #define GETOPT_VALUE(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_HAS_VALUE) /** * Short option with optional value. * @param shortname Short option name. Use \c '\0' if not used. * @param longname Long option name including leading '-' or '--'. Use \c NULL if not used. * @note Options with optional values are hopelessly ambiguous, eg "-opt -value", avoid them. */ #define GETOPT_OPTVAL(shortname, longname) GETOPT_GENERAL(shortname, shortname, longname, ODF_OPTIONAL_VALUE) /** * Short option without value. * @param shortname Short option name. Use \c '\0' if not used. */ #define GETOPT_SHORT_NOVAL(shortname) GETOPT_NOVAL(shortname, NULL) /** * Short option with value. * @param shortname Short option name. Use \c '\0' if not used. */ #define GETOPT_SHORT_VALUE(shortname) GETOPT_VALUE(shortname, NULL) /** * Short option with optional value. * @param shortname Short option name. Use \c '\0' if not used. * @note Options with optional values are hopelessly ambiguous, eg "-opt -value", avoid them. */ #define GETOPT_SHORT_OPTVAL(shortname) GETOPT_OPTVAL(shortname, NULL) /** Option terminator. */ #define GETOPT_END() { '\0', '\0', ODF_END, NULL} #endif /* GETOPTDATA_H */ openttd-1.5.3/src/misc/getoptdata.cpp0000644000000000000000000000535212627373436016277 0ustar rootroot/* $Id: getoptdata.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 getoptdata.cpp Library for parsing command line options. */ #include "../stdafx.h" #include "getoptdata.h" #include "../safeguards.h" /** * Find the next option. * @return Function returns one * - An option letter if it found another option. * - -1 if option processing is finished. Inspect #argv and #numleft to find the command line arguments. * - -2 if an error was encountered. */ int GetOptData::GetOpt() { const OptionData *odata; char *s = this->cont; if (s == NULL) { if (this->numleft == 0) return -1; // No arguments left -> finished. s = this->argv[0]; if (*s != '-') return -1; // No leading '-' -> not an option -> finished. this->argv++; this->numleft--; /* Is it a long option? */ for (odata = this->options; odata->flags != ODF_END; odata++) { if (odata->longname != NULL && !strcmp(odata->longname, s)) { // Long options always use the entire argument. this->cont = NULL; goto set_optval; } } s++; // Skip leading '-'. } /* Is it a short option? */ for (odata = this->options; odata->flags != ODF_END; odata++) { if (odata->shortname != '\0' && *s == odata->shortname) { this->cont = (s[1] != '\0') ? s + 1 : NULL; set_optval: // Handle option value of *odata . this->opt = NULL; switch (odata->flags) { case ODF_NO_VALUE: return odata->id; case ODF_HAS_VALUE: case ODF_OPTIONAL_VALUE: if (this->cont != NULL) { // Remainder of the argument is the option value. this->opt = this->cont; this->cont = NULL; return odata->id; } /* No more arguments, either return an error or a value-less option. */ if (this->numleft == 0) return (odata->flags == ODF_HAS_VALUE) ? -2 : odata->id; /* Next argument looks like another option, let's not return it as option value. */ if (odata->flags == ODF_OPTIONAL_VALUE && this->argv[0][0] == '-') return odata->id; this->opt = this->argv[0]; // Next argument is the option value. this->argv++; this->numleft--; return odata->id; default: NOT_REACHED(); } } } return -2; // No other ways to interpret the text -> error. } openttd-1.5.3/src/misc/str.hpp0000644000000000000000000000701712627373436014760 0ustar rootroot/* $Id: str.hpp 26506 2014-04-24 19:51:45Z rubidium $ */ /* * 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 str.hpp String formating? */ #ifndef STR_HPP #define STR_HPP #include #include #include "blob.hpp" #include "../core/math_func.hpp" #include "../string_func.h" /** Blob based case sensitive ANSI/UTF-8 string */ struct CStrA : public CBlobT { typedef CBlobT base; ///< base class /** Create an empty CStrT */ inline CStrA() { } /** Copy constructor */ inline CStrA(const CStrA &src) : base(src) { base::FixTail(); } /** Take over ownership constructor */ inline CStrA(const OnTransfer& ot) : base(ot) { } /** Grow the actual buffer and fix the trailing zero at the end. */ inline char *GrowSizeNC(uint count) { char *ret = base::GrowSizeNC(count); base::FixTail(); return ret; } /** Append zero-ended C string. */ inline void AppendStr(const char *str) { if (!StrEmpty(str)) { base::AppendRaw(str, strlen(str)); base::FixTail(); } } /** Append another CStrA. */ inline void Append(const CStrA &src) { if (src.Length() > 0) { base::AppendRaw(src); base::FixTail(); } } /** Assignment from C string. */ inline CStrA &operator = (const char *src) { base::Clear(); AppendStr(src); return *this; } /** Assignment from another CStrA. */ inline CStrA &operator = (const CStrA &src) { if (&src != this) { base::Clear(); base::AppendRaw(src.Data(), src.Size()); base::FixTail(); } return *this; } /** Lower-than operator (to support stl collections) */ inline bool operator < (const CStrA &other) const { return strcmp(base::Data(), other.Data()) < 0; } /** Add formated string (like vsprintf) at the end of existing contents. */ int AddFormatL(const char *format, va_list args) { size_t addSize = max(strlen(format), 16); addSize += addSize / 2; int ret; int err = 0; for (;;) { char *buf = MakeFreeSpace(addSize); ret = vseprintf(buf, buf + base::GetReserve() - 1, format, args); if (ret >= (int)base::GetReserve()) { /* Greater return than given count means needed buffer size. */ addSize = ret + 1; continue; } if (ret >= 0) { /* success */ break; } err = errno; if (err != ERANGE && err != ENOENT && err != 0) { /* some strange failure */ break; } /* small buffer (M$ implementation) */ addSize *= 2; } if (ret > 0) { GrowSizeNC(ret); } else { base::FixTail(); } return ret; } /** Add formated string (like sprintf) at the end of existing contents. */ int CDECL WARN_FORMAT(2, 3) AddFormat(const char *format, ...) { va_list args; va_start(args, format); int ret = AddFormatL(format, args); va_end(args); return ret; } /** Assign formated string (like sprintf). */ int CDECL WARN_FORMAT(2, 3) Format(const char *format, ...) { base::Free(); va_list args; va_start(args, format); int ret = AddFormatL(format, args); va_end(args); return ret; } }; #endif /* STR_HPP */ openttd-1.5.3/src/misc/hashtable.hpp0000644000000000000000000001631612627373436016105 0ustar rootroot/* $Id: hashtable.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 hashtable.hpp Hash table support. */ #ifndef HASHTABLE_HPP #define HASHTABLE_HPP #include "../core/math_func.hpp" template struct CHashTableSlotT { typedef typename Titem_::Key Key; // make Titem_::Key a property of HashTable Titem_ *m_pFirst; inline CHashTableSlotT() : m_pFirst(NULL) {} /** hash table slot helper - clears the slot by simple forgetting its items */ inline void Clear() {m_pFirst = NULL;} /** hash table slot helper - linear search for item with given key through the given blob - const version */ inline const Titem_ *Find(const Key& key) const { for (const Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { if (pItem->GetKey() == key) { /* we have found the item, return it */ return pItem; } } return NULL; } /** hash table slot helper - linear search for item with given key through the given blob - non-const version */ inline Titem_ *Find(const Key& key) { for (Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { if (pItem->GetKey() == key) { /* we have found the item, return it */ return pItem; } } return NULL; } /** hash table slot helper - add new item to the slot */ inline void Attach(Titem_& new_item) { assert(new_item.GetHashNext() == NULL); new_item.SetHashNext(m_pFirst); m_pFirst = &new_item; } /** hash table slot helper - remove item from a slot */ inline bool Detach(Titem_& item_to_remove) { if (m_pFirst == &item_to_remove) { m_pFirst = item_to_remove.GetHashNext(); item_to_remove.SetHashNext(NULL); return true; } Titem_ *pItem = m_pFirst; for (;;) { if (pItem == NULL) { return false; } Titem_ *pNextItem = pItem->GetHashNext(); if (pNextItem == &item_to_remove) break; pItem = pNextItem; } pItem->SetHashNext(item_to_remove.GetHashNext()); item_to_remove.SetHashNext(NULL); return true; } /** hash table slot helper - remove and return item from a slot */ inline Titem_ *Detach(const Key& key) { /* do we have any items? */ if (m_pFirst == NULL) { return NULL; } /* is it our first item? */ if (m_pFirst->GetKey() == key) { Titem_& ret_item = *m_pFirst; m_pFirst = m_pFirst->GetHashNext(); ret_item.SetHashNext(NULL); return &ret_item; } /* find it in the following items */ Titem_ *pPrev = m_pFirst; for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) { if (pItem->GetKey() == key) { /* we have found the item, unlink and return it */ pPrev->SetHashNext(pItem->GetHashNext()); pItem->SetHashNext(NULL); return pItem; } } return NULL; } }; /** * class CHashTableT - simple hash table * of pointers allocated elsewhere. * * Supports: Add/Find/Remove of Titems. * * Your Titem must meet some extra requirements to be CHashTableT * compliant: * - its constructor/destructor (if any) must be public * - if the copying of item requires an extra resource management, * you must define also copy constructor * - must support nested type (struct, class or typedef) Titem::Key * that defines the type of key class for that item * - must support public method: * const Key& GetKey() const; // return the item's key object * * In addition, the Titem::Key class must support: * - public method that calculates key's hash: * int CalcHash() const; * - public 'equality' operator to compare the key with another one * bool operator == (const Key& other) const; */ template class CHashTableT { public: typedef Titem_ Titem; // make Titem_ visible from outside of class typedef typename Titem_::Key Tkey; // make Titem_::Key a property of HashTable static const int Thash_bits = Thash_bits_; // publish num of hash bits static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits protected: /** * each slot contains pointer to the first item in the list, * Titem contains pointer to the next item - GetHashNext(), SetHashNext() */ typedef CHashTableSlotT Slot; Slot m_slots[Tcapacity]; // here we store our data (array of blobs) int m_num_items; // item counter public: /* default constructor */ inline CHashTableT() : m_num_items(0) { } protected: /** static helper - return hash for the given key modulo number of slots */ inline static int CalcHash(const Tkey& key) { int32 hash = key.CalcHash(); if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31)); if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31)); if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31)); if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31)); hash &= (1 << Thash_bits) - 1; return hash; } /** static helper - return hash for the given item modulo number of slots */ inline static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());} public: /** item count */ inline int Count() const {return m_num_items;} /** simple clear - forget all items - used by CSegmentCostCacheT.Flush() */ inline void Clear() {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();} /** const item search */ const Titem_ *Find(const Tkey& key) const { int hash = CalcHash(key); const Slot& slot = m_slots[hash]; const Titem_ *item = slot.Find(key); return item; } /** non-const item search */ Titem_ *Find(const Tkey& key) { int hash = CalcHash(key); Slot& slot = m_slots[hash]; Titem_ *item = slot.Find(key); return item; } /** non-const item search & optional removal (if found) */ Titem_ *TryPop(const Tkey& key) { int hash = CalcHash(key); Slot& slot = m_slots[hash]; Titem_ *item = slot.Detach(key); if (item != NULL) { m_num_items--; } return item; } /** non-const item search & removal */ Titem_& Pop(const Tkey& key) { Titem_ *item = TryPop(key); assert(item != NULL); return *item; } /** non-const item search & optional removal (if found) */ bool TryPop(Titem_& item) { const Tkey& key = item.GetKey(); int hash = CalcHash(key); Slot& slot = m_slots[hash]; bool ret = slot.Detach(item); if (ret) { m_num_items--; } return ret; } /** non-const item search & removal */ void Pop(Titem_& item) { bool ret = TryPop(item); assert(ret); } /** add one item - copy it from the given item */ void Push(Titem_& new_item) { int hash = CalcHash(new_item); Slot& slot = m_slots[hash]; assert(slot.Find(new_item.GetKey()) == NULL); slot.Attach(new_item); m_num_items++; } }; #endif /* HASHTABLE_HPP */ openttd-1.5.3/src/misc/array.hpp0000644000000000000000000000575012627373436015270 0ustar rootroot/* $Id: array.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 array.hpp Array without an explicit maximum size. */ #ifndef ARRAY_HPP #define ARRAY_HPP #include "fixedsizearray.hpp" #include "str.hpp" /** * Flexible array with size limit. Implemented as fixed size * array of fixed size arrays */ template class SmallArray { protected: typedef FixedSizeArray SubArray; ///< inner array typedef FixedSizeArray SuperArray; ///< outer array static const uint Tcapacity = B * N; ///< total max number of items SuperArray data; ///< array of arrays of items /** return first sub-array with free space for new item */ inline SubArray& FirstFreeSubArray() { uint super_size = data.Length(); if (super_size > 0) { SubArray& s = data[super_size - 1]; if (!s.IsFull()) return s; } return *data.AppendC(); } public: /** implicit constructor */ inline SmallArray() { } /** Clear (destroy) all items */ inline void Clear() {data.Clear();} /** Return actual number of items */ inline uint Length() const { uint super_size = data.Length(); if (super_size == 0) return 0; uint sub_size = data[super_size - 1].Length(); return (super_size - 1) * B + sub_size; } /** return true if array is empty */ inline bool IsEmpty() { return data.IsEmpty(); } /** return true if array is full */ inline bool IsFull() { return data.IsFull() && data[N - 1].IsFull(); } /** allocate but not construct new item */ inline T *Append() { return FirstFreeSubArray().Append(); } /** allocate and construct new item */ inline T *AppendC() { return FirstFreeSubArray().AppendC(); } /** indexed access (non-const) */ inline T& operator [] (uint index) { const SubArray& s = data[index / B]; T& item = s[index % B]; return item; } /** indexed access (const) */ inline const T& operator [] (uint index) const { const SubArray& s = data[index / B]; const T& item = s[index % B]; return item; } /** * Helper for creating a human readable output of this data. * @param dmp The location to dump to. */ template void Dump(D &dmp) const { dmp.WriteLine("capacity = %d", Tcapacity); uint num_items = Length(); dmp.WriteLine("num_items = %d", num_items); CStrA name; for (uint i = 0; i < num_items; i++) { const T& item = (*this)[i]; name.Format("item[%d]", i); dmp.WriteStructT(name.Data(), &item); } } }; #endif /* ARRAY_HPP */ openttd-1.5.3/src/misc/blob.hpp0000644000000000000000000002655612627373436015077 0ustar rootroot/* $Id: blob.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 blob.hpp Support for storing random binary data. */ #ifndef BLOB_HPP #define BLOB_HPP #include "../core/alloc_func.hpp" /** * Base class for simple binary blobs. * Item is byte. * The word 'simple' means: * - no configurable allocator type (always made from heap) * - no smart deallocation - deallocation must be called from the same * module (DLL) where the blob was allocated * - no configurable allocation policy (how big blocks should be allocated) * - no extra ownership policy (i.e. 'copy on write') when blob is copied * - no thread synchronization at all * * Internal member layout: * 1. The only class member is pointer to the first item (see union). * 2. Allocated block contains the blob header (see BlobHeader) followed by the raw byte data. * Always, when it allocates memory the allocated size is: * sizeof(BlobHeader) + * 3. Two 'virtual' members (items and capacity) are stored in the BlobHeader at beginning * of the allocated block. * 4. The pointer of the union pobsize_ts behind the header (to the first data byte). * When memory block is allocated, the sizeof(BlobHeader) it added to it. * 5. Benefits of this layout: * - items are accessed in the simplest possible way - just dereferencing the pointer, * which is good for performance (assuming that data are accessed most often). * - sizeof(blob) is the same as the size of any other pointer * 6. Drawbacks of this layout: * - the fact that a pointer to the allocated block is adjusted by sizeof(BlobHeader) before * it is stored can lead to several confusions: * - it is not a common pattern so the implementation code is bit harder to read. * - valgrind may generate a warning that the allocated block is lost (not accessible). */ class ByteBlob { protected: /** header of the allocated memory block */ struct BlobHeader { size_t items; ///< actual blob size in bytes size_t capacity; ///< maximum (allocated) size in bytes }; /** type used as class member */ union { byte *data; ///< ptr to the first byte of data BlobHeader *header; ///< ptr just after the BlobHeader holding items and capacity }; private: /** * Just to silence an unsilencable GCC 4.4+ warning * Note: This cannot be 'const' as we do a lot of 'hdrEmpty[0]->items += 0;' and 'hdrEmpty[0]->capacity += 0;' * after const_casting. */ static BlobHeader hdrEmpty[]; public: static const size_t tail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end static const size_t header_size = sizeof(BlobHeader); /** default constructor - initializes empty blob */ inline ByteBlob() { InitEmpty(); } /** copy constructor */ inline ByteBlob(const ByteBlob &src) { InitEmpty(); AppendRaw(src); } /** move constructor - take ownership of blob data */ inline ByteBlob(BlobHeader * const & src) { assert(src != NULL); header = src; *const_cast(&src) = NULL; } /** destructor */ inline ~ByteBlob() { Free(); } protected: /** all allocation should happen here */ static inline BlobHeader *RawAlloc(size_t num_bytes) { return (BlobHeader*)MallocT(num_bytes); } /** * Return header pointer to the static BlobHeader with * both items and capacity containing zero */ static inline BlobHeader *Zero() { return const_cast(&ByteBlob::hdrEmpty[1]); } /** simple allocation policy - can be optimized later */ static inline size_t AllocPolicy(size_t min_alloc) { if (min_alloc < (1 << 9)) { if (min_alloc < (1 << 5)) return (1 << 5); return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9); } if (min_alloc < (1 << 15)) { if (min_alloc < (1 << 11)) return (1 << 11); return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15); } if (min_alloc < (1 << 20)) { if (min_alloc < (1 << 17)) return (1 << 17); return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20); } min_alloc = (min_alloc | ((1 << 20) - 1)) + 1; return min_alloc; } /** all deallocations should happen here */ static inline void RawFree(BlobHeader *p) { /* Just to silence an unsilencable GCC 4.4+ warning. */ assert(p != ByteBlob::hdrEmpty); /* In case GCC warns about the following, see GCC's PR38509 why it is bogus. */ free(p); } /** initialize the empty blob */ inline void InitEmpty() { header = Zero(); } /** initialize blob by attaching it to the given header followed by data */ inline void Init(BlobHeader *src) { header = &src[1]; } /** blob header accessor - use it rather than using the pointer arithmetics directly - non-const version */ inline BlobHeader& Hdr() { return *(header - 1); } /** blob header accessor - use it rather than using the pointer arithmetics directly - const version */ inline const BlobHeader& Hdr() const { return *(header - 1); } /** return reference to the actual blob size - used when the size needs to be modified */ inline size_t& LengthRef() { return Hdr().items; } public: /** return true if blob doesn't contain valid data */ inline bool IsEmpty() const { return Length() == 0; } /** return the number of valid data bytes in the blob */ inline size_t Length() const { return Hdr().items; } /** return the current blob capacity in bytes */ inline size_t Capacity() const { return Hdr().capacity; } /** return pointer to the first byte of data - non-const version */ inline byte *Begin() { return data; } /** return pointer to the first byte of data - const version */ inline const byte *Begin() const { return data; } /** invalidate blob's data - doesn't free buffer */ inline void Clear() { LengthRef() = 0; } /** free the blob's memory */ inline void Free() { if (Capacity() > 0) { RawFree(&Hdr()); InitEmpty(); } } /** append new bytes at the end of existing data bytes - reallocates if necessary */ inline void AppendRaw(const void *p, size_t num_bytes) { assert(p != NULL); if (num_bytes > 0) { memcpy(Append(num_bytes), p, num_bytes); } } /** append bytes from given source blob to the end of existing data bytes - reallocates if necessary */ inline void AppendRaw(const ByteBlob& src) { if (!src.IsEmpty()) { memcpy(Append(src.Length()), src.Begin(), src.Length()); } } /** * Reallocate if there is no free space for num_bytes bytes. * @return pointer to the new data to be added */ inline byte *Prepare(size_t num_bytes) { size_t new_size = Length() + num_bytes; if (new_size > Capacity()) SmartAlloc(new_size); return data + Length(); } /** * Increase Length() by num_bytes. * @return pointer to the new data added */ inline byte *Append(size_t num_bytes) { byte *pNewData = Prepare(num_bytes); LengthRef() += num_bytes; return pNewData; } /** reallocate blob data if needed */ void SmartAlloc(size_t new_size) { if (Capacity() >= new_size) return; /* calculate minimum block size we need to allocate * and ask allocation policy for some reasonable block size */ assert(new_size < SIZE_MAX - header_size - tail_reserve); new_size = AllocPolicy(header_size + new_size + tail_reserve); /* allocate new block and setup header */ BlobHeader *tmp = RawAlloc(new_size); tmp->items = Length(); tmp->capacity = new_size - (header_size + tail_reserve); /* copy existing data */ if (tmp->items != 0) { memcpy(tmp + 1, data, tmp->items); } /* replace our block with new one */ if (Capacity() > 0) { RawFree(&Hdr()); } Init(tmp); } /** fixing the four bytes at the end of blob data - useful when blob is used to hold string */ inline void FixTail() const { if (Capacity() > 0) { byte *p = &data[Length()]; for (uint i = 0; i < tail_reserve; i++) { p[i] = 0; } } } }; /** * Blob - simple dynamic T array. T (template argument) is a placeholder for any type. * T can be any integral type, pointer, or structure. Using Blob instead of just plain C array * simplifies the resource management in several ways: * 1. When adding new item(s) it automatically grows capacity if needed. * 2. When variable of type Blob comes out of scope it automatically frees the data buffer. * 3. Takes care about the actual data size (number of used items). * 4. Dynamically constructs only used items (as opposite of static array which constructs all items) */ template class CBlobT : public ByteBlob { /* make template arguments public: */ public: typedef ByteBlob base; static const size_t type_size = sizeof(T); struct OnTransfer { typename base::BlobHeader *header; OnTransfer(const OnTransfer& src) : header(src.header) {assert(src.header != NULL); *const_cast(&src.header) = NULL;} OnTransfer(CBlobT& src) : header(src.header) {src.InitEmpty();} ~OnTransfer() {assert(header == NULL);} }; /** Default constructor - makes new Blob ready to accept any data */ inline CBlobT() : base() {} /** Take ownership constructor */ inline CBlobT(const OnTransfer& ot) : base(ot.header) {} /** Destructor - ensures that allocated memory (if any) is freed */ inline ~CBlobT() { Free(); } /** Check the validity of item index (only in debug mode) */ inline void CheckIdx(size_t index) const { assert(index < Size()); } /** Return pointer to the first data item - non-const version */ inline T *Data() { return (T*)base::Begin(); } /** Return pointer to the first data item - const version */ inline const T *Data() const { return (const T*)base::Begin(); } /** Return pointer to the index-th data item - non-const version */ inline T *Data(size_t index) { CheckIdx(index); return (Data() + index); } /** Return pointer to the index-th data item - const version */ inline const T *Data(size_t index) const { CheckIdx(index); return (Data() + index); } /** Return number of items in the Blob */ inline size_t Size() const { return (base::Length() / type_size); } /** Return total number of items that can fit in the Blob without buffer reallocation */ inline size_t MaxSize() const { return (base::Capacity() / type_size); } /** Return number of additional items that can fit in the Blob without buffer reallocation */ inline size_t GetReserve() const { return ((base::Capacity() - base::Length()) / type_size); } /** Grow number of data items in Blob by given number - doesn't construct items */ inline T *GrowSizeNC(size_t num_items) { return (T*)base::Append(num_items * type_size); } /** * Ensures that given number of items can be added to the end of Blob. Returns pointer to the * first free (unused) item */ inline T *MakeFreeSpace(size_t num_items) { return (T*)base::Prepare(num_items * type_size); } inline OnTransfer Transfer() { return OnTransfer(*this); } }; #endif /* BLOB_HPP */ openttd-1.5.3/src/group_gui.cpp0000644000000000000000000010615612627373442015211 0ustar rootroot/* $Id: group_gui.cpp 26960 2014-10-05 11:20:02Z peter1138 $ */ /* * 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 group_gui.cpp GUI for the group window. */ #include "stdafx.h" #include "textbuf_gui.h" #include "command_func.h" #include "vehicle_gui.h" #include "vehicle_base.h" #include "string_func.h" #include "strings_func.h" #include "window_func.h" #include "vehicle_func.h" #include "autoreplace_gui.h" #include "company_func.h" #include "widgets/dropdown_func.h" #include "tilehighlight_func.h" #include "vehicle_gui_base.h" #include "core/geometry_func.hpp" #include "company_base.h" #include "widgets/group_widget.h" #include "table/sprites.h" #include "safeguards.h" static const int LEVEL_WIDTH = 10; ///< Indenting width of a sub-group in pixels typedef GUIList GUIGroupList; static const NWidgetPart _nested_group_widgets[] = { NWidget(NWID_HORIZONTAL), // Window header NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_GL_CAPTION), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), /* left part */ NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), SetFill(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_ALL_VEHICLES), SetFill(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_DEFAULT_VEHICLES), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_GROUP), SetMatrixDataTip(1, 0, STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP), SetFill(1, 0), SetResize(0, 1), SetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_GROUP_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_CREATE_GROUP), SetFill(0, 1), SetDataTip(SPR_GROUP_CREATE_TRAIN, STR_GROUP_CREATE_TOOLTIP), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_DELETE_GROUP), SetFill(0, 1), SetDataTip(SPR_GROUP_DELETE_TRAIN, STR_GROUP_DELETE_TOOLTIP), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_RENAME_GROUP), SetFill(0, 1), SetDataTip(SPR_GROUP_RENAME_TRAIN, STR_GROUP_RENAME_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_REPLACE_PROTECTION), SetFill(0, 1), SetDataTip(SPR_GROUP_REPLACE_OFF_TRAIN, STR_GROUP_REPLACE_PROTECTION_TOOLTIP), EndContainer(), EndContainer(), /* right part */ NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetMinimalSize(81, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetMinimalSize(167, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_VEHICLE), SetMinimalSize(248, 0), SetMatrixDataTip(1, 0, STR_NULL), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_VEHICLE_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1), SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), EndContainer(), }; class VehicleGroupWindow : public BaseVehicleListWindow { private: /* Columns in the group list */ enum ListColumns { VGC_NAME, ///< Group name. VGC_PROTECT, ///< Autoreplace protect icon. VGC_AUTOREPLACE, ///< Autoreplace active icon. VGC_PROFIT, ///< Profit icon. VGC_NUMBER, ///< Number of vehicles in the group. VGC_END }; VehicleID vehicle_sel; ///< Selected vehicle GroupID group_sel; ///< Selected group (for drag/drop) GroupID group_rename; ///< Group being renamed, INVALID_GROUP if none GroupID group_over; ///< Group over which a vehicle is dragged, INVALID_GROUP if none GroupID group_confirm; ///< Group awaiting delete confirmation GUIGroupList groups; ///< List of groups uint tiny_step_height; ///< Step height for the group list Scrollbar *group_sb; SmallVector indents; ///< Indentation levels Dimension column_size[VGC_END]; ///< Size of the columns in the group list. void AddParents(GUIGroupList *source, GroupID parent, int indent) { for (const Group **g = source->Begin(); g != source->End(); g++) { if ((*g)->parent == parent) { *this->groups.Append() = *g; *this->indents.Append() = indent; AddParents(source, (*g)->index, indent + 1); } } } /** Sort the groups by their name */ static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b) { static const Group *last_group[2] = { NULL, NULL }; static char last_name[2][64] = { "", "" }; if (*a != last_group[0]) { last_group[0] = *a; SetDParam(0, (*a)->index); GetString(last_name[0], STR_GROUP_NAME, lastof(last_name[0])); } if (*b != last_group[1]) { last_group[1] = *b; SetDParam(0, (*b)->index); GetString(last_name[1], STR_GROUP_NAME, lastof(last_name[1])); } int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). if (r == 0) return (*a)->index - (*b)->index; return r; } /** * (Re)Build the group list. * * @param owner The owner of the window */ void BuildGroupList(Owner owner) { if (!this->groups.NeedRebuild()) return; this->groups.Clear(); this->indents.Clear(); GUIGroupList list; const Group *g; FOR_ALL_GROUPS(g) { if (g->owner == owner && g->vehicle_type == this->vli.vtype) { *list.Append() = g; } } list.ForceResort(); list.Sort(&GroupNameSorter); AddParents(&list, INVALID_GROUP, 0); this->groups.Compact(); this->groups.RebuildDone(); } /** * Compute tiny_step_height and column_size * @return Total width required for the group list. */ uint ComputeGroupInfoSize() { this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype)); this->column_size[VGC_NAME].width = max(170u, this->column_size[VGC_NAME].width); this->tiny_step_height = this->column_size[VGC_NAME].height; this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROTECT].height); this->column_size[VGC_AUTOREPLACE] = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height); this->column_size[VGC_PROFIT].width = 0; this->column_size[VGC_PROFIT].height = 0; static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT}; for (uint i = 0; i < lengthof(profit_sprites); i++) { Dimension d = GetSpriteSize(profit_sprites[i]); this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d); } this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_PROFIT].height); SetDParamMaxValue(0, GroupStatistics::Get(this->vli.company, ALL_GROUP, this->vli.vtype).num_vehicle, 3, FS_SMALL); this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_TINY_COMMA); this->tiny_step_height = max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); this->tiny_step_height += WD_MATRIX_TOP; return WD_FRAMERECT_LEFT + 8 + this->column_size[VGC_NAME].width + 8 + this->column_size[VGC_PROTECT].width + 2 + this->column_size[VGC_AUTOREPLACE].width + 2 + this->column_size[VGC_PROFIT].width + 2 + this->column_size[VGC_NUMBER].width + 2 + WD_FRAMERECT_RIGHT; } /** * Draw a row in the group list. * @param y Top of the row. * @param left Left of the row. * @param right Right of the row. * @param g_id Group to list. * @param indent Indentation level. * @param protection Whether autoreplace protection is set. */ void DrawGroupInfo(int y, int left, int right, GroupID g_id, int indent = 0, bool protection = false) const { /* Highlight the group if a vehicle is dragged over it */ if (g_id == this->group_over) { GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][7]); } if (g_id == NEW_GROUP) return; /* draw the selected group in white, else we draw it in black */ TextColour colour = g_id == this->vli.index ? TC_WHITE : TC_BLACK; const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype); bool rtl = _current_text_dir == TD_RTL; /* draw group name */ StringID str; if (IsAllGroupID(g_id)) { str = STR_GROUP_ALL_TRAINS + this->vli.vtype; } else if (IsDefaultGroupID(g_id)) { str = STR_GROUP_DEFAULT_TRAINS + this->vli.vtype; } else { SetDParam(0, g_id); str = STR_GROUP_NAME; } int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width + 1 : left + WD_FRAMERECT_LEFT + 8; DrawString(x + indent * LEVEL_WIDTH, x + this->column_size[VGC_NAME].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour); /* draw autoreplace protection */ x = rtl ? x - 8 - this->column_size[VGC_PROTECT].width : x + 8 + this->column_size[VGC_NAME].width; if (protection) DrawSprite(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROTECT].height) / 2); /* draw autoreplace status */ x = rtl ? x - 2 - this->column_size[VGC_AUTOREPLACE].width : x + 2 + this->column_size[VGC_PROTECT].width; if (stats.autoreplace_defined) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, stats.autoreplace_finished ? PALETTE_CRASH : PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_AUTOREPLACE].height) / 2); /* draw the profit icon */ x = rtl ? x - 2 - this->column_size[VGC_PROFIT].width : x + 2 + this->column_size[VGC_AUTOREPLACE].width; SpriteID spr; if (stats.num_profit_vehicle == 0) { spr = SPR_PROFIT_NA; } else if (stats.profit_last_year < 0) { spr = SPR_PROFIT_NEGATIVE; } else if (stats.profit_last_year < 10000 * stats.num_profit_vehicle) { // TODO magic number spr = SPR_PROFIT_SOME; } else { spr = SPR_PROFIT_LOT; } DrawSprite(spr, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROFIT].height) / 2); /* draw the number of vehicles of the group */ x = rtl ? x - 2 - this->column_size[VGC_NUMBER].width : x + 2 + this->column_size[VGC_PROFIT].width; SetDParam(0, stats.num_vehicle); DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_TINY_COMMA, colour, SA_RIGHT | SA_FORCE); } /** * Mark the widget containing the currently highlighted group as dirty. */ void DirtyHighlightedGroupWidget() { if (this->group_over == INVALID_GROUP) return; if (IsAllGroupID(this->group_over)) { this->SetWidgetDirty(WID_GL_ALL_VEHICLES); } else if (IsDefaultGroupID(this->group_over)) { this->SetWidgetDirty(WID_GL_DEFAULT_VEHICLES); } else { this->SetWidgetDirty(WID_GL_LIST_GROUP); } } public: VehicleGroupWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR); this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR); switch (this->vli.vtype) { default: NOT_REACHED(); case VEH_TRAIN: this->sorting = &_sorting.train; break; case VEH_ROAD: this->sorting = &_sorting.roadveh; break; case VEH_SHIP: this->sorting = &_sorting.ship; break; case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break; } this->vli.index = ALL_GROUP; this->vehicle_sel = INVALID_VEHICLE; this->group_sel = INVALID_GROUP; this->group_rename = INVALID_GROUP; this->group_over = INVALID_GROUP; this->vehicles.SetListing(*this->sorting); this->vehicles.ForceRebuild(); this->vehicles.NeedResort(); this->BuildVehicleList(); this->SortVehicleList(); this->groups.ForceRebuild(); this->groups.NeedResort(); this->BuildGroupList(vli.company); this->GetWidget(WID_GL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype; this->GetWidget(WID_GL_LIST_VEHICLE)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype; this->GetWidget(WID_GL_CREATE_GROUP)->widget_data += this->vli.vtype; this->GetWidget(WID_GL_RENAME_GROUP)->widget_data += this->vli.vtype; this->GetWidget(WID_GL_DELETE_GROUP)->widget_data += this->vli.vtype; this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data += this->vli.vtype; this->FinishInitNested(window_number); this->owner = vli.company; } ~VehicleGroupWindow() { *this->sorting = this->vehicles.GetListing(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_GL_LIST_GROUP: { size->width = this->ComputeGroupInfoSize(); resize->height = this->tiny_step_height; /* Minimum height is the height of the list widget minus all and default vehicles... */ size->height = 4 * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height) - 2 * this->tiny_step_height; /* ... minus the buttons at the bottom ... */ uint max_icon_height = GetSpriteSize(this->GetWidget(WID_GL_CREATE_GROUP)->widget_data).height; max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_RENAME_GROUP)->widget_data).height); max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_DELETE_GROUP)->widget_data).height); max_icon_height = max(max_icon_height, GetSpriteSize(this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data).height); /* Get a multiple of tiny_step_height of that amount */ size->height = Ceil(size->height - max_icon_height, tiny_step_height); break; } case WID_GL_ALL_VEHICLES: case WID_GL_DEFAULT_VEHICLES: size->width = this->ComputeGroupInfoSize(); size->height = this->tiny_step_height; break; case WID_GL_SORT_BY_ORDER: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_GL_LIST_VEHICLE: this->ComputeGroupInfoSize(); resize->height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height); size->height = 4 * resize->height; break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: { Dimension d = this->GetActionDropdownSize(true, true); d.height += padding.height; d.width += padding.width; *size = maxdim(*size, d); 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 (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->vehicles.ForceRebuild(); this->groups.ForceRebuild(); } else { this->vehicles.ForceResort(); this->groups.ForceResort(); } /* Process ID-invalidation in command-scope as well */ if (this->group_rename != INVALID_GROUP && !Group::IsValidID(this->group_rename)) { DeleteWindowByClass(WC_QUERY_STRING); this->group_rename = INVALID_GROUP; } if (!(IsAllGroupID(this->vli.index) || IsDefaultGroupID(this->vli.index) || Group::IsValidID(this->vli.index))) { this->vli.index = ALL_GROUP; HideDropDownMenu(this); } this->SetDirty(); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_GL_AVAILABLE_VEHICLES: SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype); break; case WID_GL_CAPTION: /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption * We list all vehicles or ungrouped vehicles */ if (IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index)) { SetDParam(0, STR_COMPANY_NAME); SetDParam(1, this->vli.company); SetDParam(2, this->vehicles.Length()); SetDParam(3, this->vehicles.Length()); } else { const Group *g = Group::Get(this->vli.index); SetDParam(0, STR_GROUP_NAME); SetDParam(1, g->index); SetDParam(2, g->statistics.num_vehicle); SetDParam(3, g->statistics.num_vehicle); } break; } } virtual void OnPaint() { /* If we select the all vehicles, this->list will contain all vehicles of the owner * else this->list will contain all vehicles which belong to the selected group */ this->BuildVehicleList(); this->SortVehicleList(); this->BuildGroupList(this->owner); this->group_sb->SetCount(this->groups.Length()); this->vscroll->SetCount(this->vehicles.Length()); /* The drop down menu is out, *but* it may not be used, retract it. */ if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) { this->RaiseWidget(WID_GL_MANAGE_VEHICLES_DROPDOWN); HideDropDownMenu(this); } /* Disable all lists management button when the list is empty */ this->SetWidgetsDisabledState(this->vehicles.Length() == 0 || _local_company != this->vli.company, WID_GL_STOP_ALL, WID_GL_START_ALL, WID_GL_MANAGE_VEHICLES_DROPDOWN, WIDGET_LIST_END); /* Disable the group specific function when we select the default group or all vehicles */ this->SetWidgetsDisabledState(IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index) || _local_company != this->vli.company, WID_GL_DELETE_GROUP, WID_GL_RENAME_GROUP, WID_GL_REPLACE_PROTECTION, WIDGET_LIST_END); /* Disable remaining buttons for non-local companies * Needed while changing _local_company, eg. by cheats * All procedures (eg. move vehicle to another group) * verify, whether you are the owner of the vehicle, * so it doesn't have to be disabled */ this->SetWidgetsDisabledState(_local_company != this->vli.company, WID_GL_CREATE_GROUP, WID_GL_AVAILABLE_VEHICLES, WIDGET_LIST_END); /* If not a default group and the group has replace protection, show an enabled replace sprite. */ uint16 protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN; if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && Group::Get(this->vli.index)->replace_protection) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN; this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype; /* Set text of sort by dropdown */ this->GetWidget(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()]; this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_GL_ALL_VEHICLES: DrawGroupInfo(r.top + WD_FRAMERECT_TOP, r.left, r.right, ALL_GROUP); break; case WID_GL_DEFAULT_VEHICLES: DrawGroupInfo(r.top + WD_FRAMERECT_TOP, r.left, r.right, DEFAULT_GROUP); break; case WID_GL_LIST_GROUP: { int y1 = r.top + WD_FRAMERECT_TOP; int max = min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.Length()); for (int i = this->group_sb->GetPosition(); i < max; ++i) { const Group *g = this->groups[i]; assert(g->owner == this->owner); DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i], g->replace_protection); y1 += this->tiny_step_height; } if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.Length()) { DrawGroupInfo(y1, r.left, r.right, NEW_GROUP); } break; } case WID_GL_SORT_BY_ORDER: this->DrawSortButtonState(WID_GL_SORT_BY_ORDER, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; case WID_GL_LIST_VEHICLE: if (this->vli.index != ALL_GROUP) { /* Mark vehicles which are in sub-groups */ int y = r.top; uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehicles.Length()); for (uint i = this->vscroll->GetPosition(); i < max; ++i) { const Vehicle *v = this->vehicles[i]; if (v->group_id != this->vli.index) { GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 2, _colour_gradient[COLOUR_GREY][3], FILLRECT_CHECKER); } y += this->resize.step_height; } } this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r); break; } } static void DeleteGroupCallback(Window *win, bool confirmed) { if (confirmed) { VehicleGroupWindow *w = (VehicleGroupWindow*)win; w->vli.index = ALL_GROUP; DoCommandP(0, w->group_confirm, 0, CMD_DELETE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_DELETE)); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending this->vehicles.ToggleSortOrder(); this->SetDirty(); break; case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10)); return; case WID_GL_ALL_VEHICLES: // All vehicles button if (!IsAllGroupID(this->vli.index)) { this->vli.index = ALL_GROUP; this->vehicles.ForceRebuild(); this->SetDirty(); } break; case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button if (!IsDefaultGroupID(this->vli.index)) { this->vli.index = DEFAULT_GROUP; this->vehicles.ForceRebuild(); this->SetDirty(); } break; case WID_GL_LIST_GROUP: { // Matrix Group uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); if (id_g >= this->groups.Length()) return; this->group_sel = this->vli.index = this->groups[id_g]->index; SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); this->vehicles.ForceRebuild(); this->SetDirty(); break; } case WID_GL_LIST_VEHICLE: { // Matrix Vehicle uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); if (id_v >= this->vehicles.Length()) return; // click out of list bound const Vehicle *v = this->vehicles[id_v]; if (VehicleClicked(v)) break; this->vehicle_sel = v->index; int image = v->GetImage(_current_text_dir == TD_RTL ? DIR_E : DIR_W, EIT_IN_LIST); SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this); _cursor.vehchain = true; this->SetDirty(); break; } case WID_GL_CREATE_GROUP: { // Create a new group DoCommandP(0, this->vli.vtype, 0, CMD_CREATE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_CREATE), CcCreateGroup); break; } case WID_GL_DELETE_GROUP: { // Delete the selected group this->group_confirm = this->vli.index; ShowQuery(STR_QUERY_GROUP_DELETE_CAPTION, STR_GROUP_DELETE_QUERY_TEXT, this, DeleteGroupCallback); break; } case WID_GL_RENAME_GROUP: // Rename the selected roup this->ShowRenameGroupWindow(this->vli.index, false); break; case WID_GL_AVAILABLE_VEHICLES: ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype); break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: { DropDownList *list = this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index)); ShowDropDownList(this, list, 0, WID_GL_MANAGE_VEHICLES_DROPDOWN); break; } case WID_GL_START_ALL: case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list DoCommandP(0, (1 << 1) | (widget == WID_GL_START_ALL ? (1 << 0) : 0), this->vli.Pack(), CMD_MASS_START_STOP); break; } case WID_GL_REPLACE_PROTECTION: { const Group *g = Group::GetIfValid(this->vli.index); if (g != NULL) { DoCommandP(0, this->vli.index, !g->replace_protection | (_ctrl_pressed << 1), CMD_SET_GROUP_REPLACE_PROTECTION); } break; } } } void OnDragDrop_Group(Point pt, int widget) { const Group *g = Group::Get(this->group_sel); switch (widget) { case WID_GL_ALL_VEHICLES: // All vehicles case WID_GL_DEFAULT_VEHICLES: // Ungroupd vehicles if (g->parent != INVALID_GROUP) { DoCommandP(0, this->group_sel | (1 << 16), INVALID_GROUP, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_SET_PARENT)); } this->group_sel = INVALID_GROUP; this->group_over = INVALID_GROUP; this->SetDirty(); break; case WID_GL_LIST_GROUP: { // Matrix group uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); GroupID new_g = id_g >= this->groups.Length() ? INVALID_GROUP : this->groups[id_g]->index; if (this->group_sel != new_g && g->parent != new_g) { DoCommandP(0, this->group_sel | (1 << 16), new_g, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_SET_PARENT)); } this->group_sel = INVALID_GROUP; this->group_over = INVALID_GROUP; this->SetDirty(); break; } } } void OnDragDrop_Vehicle(Point pt, int widget) { switch (widget) { case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE)); this->vehicle_sel = INVALID_VEHICLE; this->group_over = INVALID_GROUP; this->SetDirty(); break; case WID_GL_LIST_GROUP: { // Matrix group const VehicleID vindex = this->vehicle_sel; this->vehicle_sel = INVALID_VEHICLE; this->group_over = INVALID_GROUP; this->SetDirty(); uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); GroupID new_g = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; DoCommandP(0, new_g, vindex | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : NULL); break; } case WID_GL_LIST_VEHICLE: { // Matrix vehicle const VehicleID vindex = this->vehicle_sel; this->vehicle_sel = INVALID_VEHICLE; this->group_over = INVALID_GROUP; this->SetDirty(); uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_VEHICLE); if (id_v >= this->vehicles.Length()) return; // click out of list bound const Vehicle *v = this->vehicles[id_v]; if (!VehicleClicked(v) && vindex == v->index) { ShowVehicleViewWindow(v); } break; } } } virtual void OnDragDrop(Point pt, int widget) { if (this->vehicle_sel != INVALID_VEHICLE) OnDragDrop_Vehicle(pt, widget); if (this->group_sel != INVALID_GROUP) OnDragDrop_Group(pt, widget); _cursor.vehchain = false; } virtual void OnQueryTextFinished(char *str) { if (str != NULL) DoCommandP(0, this->group_rename, 0, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), NULL, str); this->group_rename = INVALID_GROUP; } virtual void OnResize() { this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP); this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE); } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_GL_SORT_BY_DROPDOWN: this->vehicles.SetSortType(index); break; case WID_GL_MANAGE_VEHICLES_DROPDOWN: assert(this->vehicles.Length() != 0); switch (index) { case ADI_REPLACE: // Replace window ShowReplaceGroupVehicleWindow(this->vli.index, this->vli.vtype); break; case ADI_SERVICE: // Send for servicing case ADI_DEPOT: { // Send to Depots DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : 0U), this->vli.Pack(), GetCmdSendToDepot(this->vli.vtype)); break; } case ADI_ADD_SHARED: // Add shared Vehicles assert(Group::IsValidID(this->vli.index)); DoCommandP(0, this->vli.index, this->vli.vtype, CMD_ADD_SHARED_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE)); break; case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group assert(Group::IsValidID(this->vli.index)); DoCommandP(0, this->vli.index, 0, CMD_REMOVE_ALL_VEHICLES_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES)); break; default: NOT_REACHED(); } break; default: NOT_REACHED(); } this->SetDirty(); } virtual void OnTick() { if (_pause_mode != PM_UNPAUSED) return; if (this->groups.NeedResort() || this->vehicles.NeedResort()) { this->SetDirty(); } } virtual void OnPlaceObjectAbort() { /* abort drag & drop */ this->vehicle_sel = INVALID_VEHICLE; this->DirtyHighlightedGroupWidget(); this->group_over = INVALID_GROUP; this->SetWidgetDirty(WID_GL_LIST_VEHICLE); } virtual void OnMouseDrag(Point pt, int widget) { if (this->vehicle_sel == INVALID_VEHICLE && this->group_sel == INVALID_GROUP) return; /* A vehicle is dragged over... */ GroupID new_group_over = INVALID_GROUP; switch (widget) { case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group. new_group_over = DEFAULT_GROUP; break; case WID_GL_LIST_GROUP: { // ... the list of custom groups. uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); new_group_over = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index; break; } } /* Do not highlight when dragging over the current group */ if (this->vehicle_sel != INVALID_VEHICLE) { if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = INVALID_GROUP; } else if (this->group_sel != INVALID_GROUP) { if (this->group_sel == new_group_over || Group::Get(this->group_sel)->parent == new_group_over) new_group_over = INVALID_GROUP; } /* Mark widgets as dirty if the group changed. */ if (new_group_over != this->group_over) { this->DirtyHighlightedGroupWidget(); this->group_over = new_group_over; this->DirtyHighlightedGroupWidget(); } } void ShowRenameGroupWindow(GroupID group, bool empty) { assert(Group::IsValidID(group)); this->group_rename = group; /* Show empty query for new groups */ StringID str = STR_EMPTY; if (!empty) { SetDParam(0, group); str = STR_GROUP_NAME; } ShowQueryString(str, STR_GROUP_RENAME_CAPTION, MAX_LENGTH_GROUP_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); } /** * Tests whether a given vehicle is selected in the window, and unselects it if necessary. * Called when the vehicle is deleted. * @param vehicle Vehicle that is going to be deleted */ void UnselectVehicle(VehicleID vehicle) { if (this->vehicle_sel == vehicle) ResetObjectToPlace(); } }; static WindowDesc _other_group_desc( WDP_AUTO, "list_groups", 460, 246, WC_INVALID, WC_NONE, 0, _nested_group_widgets, lengthof(_nested_group_widgets) ); static WindowDesc _train_group_desc( WDP_AUTO, "list_groups_train", 525, 246, WC_TRAINS_LIST, WC_NONE, 0, _nested_group_widgets, lengthof(_nested_group_widgets) ); /** * Show the group window for the given company and vehicle type. * @param company The company to show the window for. * @param vehicle_type The type of vehicle to show it for. */ void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type) { if (!Company::IsValidID(company)) return; WindowNumber num = VehicleListIdentifier(VL_GROUP_LIST, vehicle_type, company).Pack(); if (vehicle_type == VEH_TRAIN) { AllocateWindowDescFront(&_train_group_desc, num); } else { _other_group_desc.cls = GetWindowClassForVehicleType(vehicle_type); AllocateWindowDescFront(&_other_group_desc, num); } } /** * Finds a group list window determined by vehicle type and owner * @param vt vehicle type * @param owner owner of groups * @return pointer to VehicleGroupWindow, NULL if not found */ static inline VehicleGroupWindow *FindVehicleGroupWindow(VehicleType vt, Owner owner) { return (VehicleGroupWindow *)FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).Pack()); } /** * Opens a 'Rename group' window for newly created group * @param success did command succeed? * @param tile unused * @param p1 vehicle type * @param p2 unused * @see CmdCreateGroup */ void CcCreateGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; assert(p1 <= VEH_AIRCRAFT); VehicleGroupWindow *w = FindVehicleGroupWindow((VehicleType)p1, _current_company); if (w != NULL) w->ShowRenameGroupWindow(_new_group_id, true); } /** * Open rename window after adding a vehicle to a new group via drag and drop. * @param success Did command succeed? * @param tile Unused. * @param p1 Unused. * @param p2 Bit 0-19: Vehicle ID. */ void CcAddVehicleNewGroup(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; assert(Vehicle::IsValidID(GB(p2, 0, 20))); CcCreateGroup(result, 0, Vehicle::Get(GB(p2, 0, 20))->type, 0); } /** * Removes the highlight of a vehicle in a group window * @param *v Vehicle to remove all highlights from */ void DeleteGroupHighlightOfVehicle(const Vehicle *v) { /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either * If that is the case, we can skip looping though the windows and save time */ if (_special_mouse_mode != WSM_DRAGDROP) return; VehicleGroupWindow *w = FindVehicleGroupWindow(v->type, v->owner); if (w != NULL) w->UnselectVehicle(v->index); } openttd-1.5.3/src/newgrf_properties.h0000644000000000000000000000763512627373435016426 0ustar rootroot/* $Id: newgrf_properties.h 23504 2011-12-13 00:43:35Z michi_cc $ */ /* * 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 newgrf_properties.h Properties of NewGRF Action 0. */ #ifndef NEWGRF_PROPERTIES_H #define NEWGRF_PROPERTIES_H /** * List of NewGRF properties used in Action 0 or Callback 0x36 (CBID_VEHICLE_MODIFY_PROPERTY). * Names are formatted as PROP__ * @todo Currently the list only contains properties which are used more than once in the code. I.e. they are available for callback 0x36. */ enum PropertyID { PROP_VEHICLE_LOAD_AMOUNT = 0x07, ///< Loading speed PROP_TRAIN_SPEED = 0x09, ///< Max. speed: 1 unit = 1/1.6 mph = 1 km-ish/h PROP_TRAIN_POWER = 0x0B, ///< Power in hp (if dualheaded: sum of both vehicles) PROP_TRAIN_RUNNING_COST_FACTOR = 0x0D, ///< Yearly runningcost (if dualheaded: sum of both vehicles) PROP_TRAIN_CARGO_CAPACITY = 0x14, ///< Capacity (if dualheaded: for each single vehicle) PROP_TRAIN_WEIGHT = 0x16, ///< Weight in t (if dualheaded: for each single vehicle) PROP_TRAIN_COST_FACTOR = 0x17, ///< Purchase cost (if dualheaded: sum of both vehicles) PROP_TRAIN_TRACTIVE_EFFORT = 0x1F, ///< Tractive effort coefficient in 1/256 PROP_TRAIN_SHORTEN_FACTOR = 0x21, ///< Shorter vehicles PROP_TRAIN_USER_DATA = 0x25, ///< User defined data for vehicle variable 0x42 PROP_TRAIN_CARGO_AGE_PERIOD = 0x2B, ///< Number of ticks before carried cargo is aged PROP_ROADVEH_RUNNING_COST_FACTOR = 0x09, ///< Yearly runningcost PROP_ROADVEH_CARGO_CAPACITY = 0x0F, ///< Capacity PROP_ROADVEH_COST_FACTOR = 0x11, ///< Purchase cost PROP_ROADVEH_POWER = 0x13, ///< Power in 10 HP PROP_ROADVEH_WEIGHT = 0x14, ///< Weight in 1/4 t PROP_ROADVEH_SPEED = 0x15, ///< Max. speed: 1 unit = 1/0.8 mph = 2 km-ish/h PROP_ROADVEH_TRACTIVE_EFFORT = 0x18, ///< Tractive effort coefficient in 1/256 PROP_ROADVEH_CARGO_AGE_PERIOD = 0x22, ///< Number of ticks before carried cargo is aged PROP_ROADVEH_SHORTEN_FACTOR = 0x23, ///< Shorter vehicles PROP_SHIP_COST_FACTOR = 0x0A, ///< Purchase cost PROP_SHIP_SPEED = 0x0B, ///< Max. speed: 1 unit = 1/3.2 mph = 0.5 km-ish/h PROP_SHIP_CARGO_CAPACITY = 0x0D, ///< Capacity PROP_SHIP_RUNNING_COST_FACTOR = 0x0F, ///< Yearly runningcost PROP_SHIP_CARGO_AGE_PERIOD = 0x1D, ///< Number of ticks before carried cargo is aged PROP_AIRCRAFT_COST_FACTOR = 0x0B, ///< Purchase cost PROP_AIRCRAFT_SPEED = 0x0C, ///< Max. speed: 1 unit = 8 mph = 12.8 km-ish/h PROP_AIRCRAFT_RUNNING_COST_FACTOR = 0x0E, ///< Yearly runningcost PROP_AIRCRAFT_PASSENGER_CAPACITY = 0x0F, ///< Passenger Capacity PROP_AIRCRAFT_MAIL_CAPACITY = 0x11, ///< Mail Capacity PROP_AIRCRAFT_CARGO_AGE_PERIOD = 0x1C, ///< Number of ticks before carried cargo is aged PROP_AIRCRAFT_RANGE = 0x1F, ///< Aircraft range }; #endif /* NEWGRF_PROPERTIES_H */ openttd-1.5.3/src/waypoint_func.h0000644000000000000000000000207712627373441015537 0ustar rootroot/* $Id: waypoint_func.h 21890 2011-01-22 14:52:20Z rubidium $ */ /* * 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 waypoint_func.h Functions related to waypoints. */ #ifndef WAYPOINT_FUNC_H #define WAYPOINT_FUNC_H #include "rail_type.h" #include "command_type.h" #include "station_type.h" CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags); Axis GetAxisForNewWaypoint(TileIndex tile); void ShowWaypointWindow(const Waypoint *wp); void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype); #endif /* WAYPOINT_FUNC_H */ openttd-1.5.3/src/order_func.h0000644000000000000000000000340412627373433014774 0ustar rootroot/* $Id: order_func.h 24995 2013-02-14 17:06:49Z rubidium $ */ /* * 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 order_func.h Functions related to orders. */ #ifndef ORDER_FUNC_H #define ORDER_FUNC_H #include "order_type.h" #include "vehicle_type.h" #include "company_type.h" /* Functions */ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination); void InvalidateVehicleOrder(const Vehicle *v, int data); void CheckOrders(const Vehicle*); void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist = false, bool reset_order_indices = true); bool ProcessOrders(Vehicle *v); bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth = 0, bool pbs_look_ahead = false); VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v); uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0); void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int y, bool selected, bool timetable, int left, int middle, int right); #define MIN_SERVINT_PERCENT 5 #define MAX_SERVINT_PERCENT 90 #define MIN_SERVINT_DAYS 30 #define MAX_SERVINT_DAYS 800 uint16 GetServiceIntervalClamped(uint interval, bool ispercent); #endif /* ORDER_FUNC_H */ openttd-1.5.3/src/textfile_type.h0000644000000000000000000000204712627373445015540 0ustar rootroot/* $Id: textfile_type.h 25338 2013-06-09 09:25:22Z rubidium $ */ /* * 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 textfile_type.h Types related to textfiles. */ #ifndef TEXTFILE_TYPE_H #define TEXTFILE_TYPE_H /** Additional text files accompanying Tar archives */ enum TextfileType { TFT_BEGIN, TFT_README = TFT_BEGIN, ///< NewGRF readme TFT_CHANGELOG, ///< NewGRF changelog TFT_LICENSE, ///< NewGRF license TFT_END, }; DECLARE_POSTFIX_INCREMENT(TextfileType) #endif /* TEXTFILE_TYPE_H */ openttd-1.5.3/src/signs.cpp0000644000000000000000000000303512627373442014324 0ustar rootroot/* $Id: signs.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 signs.cpp Handling of signs. */ #include "stdafx.h" #include "landscape.h" #include "signs_base.h" #include "signs_func.h" #include "strings_func.h" #include "core/pool_func.hpp" #include "table/strings.h" #include "safeguards.h" /** Initialize the sign-pool */ SignPool _sign_pool("Sign"); INSTANTIATE_POOL_METHODS(Sign) /** * Creates a new sign */ Sign::Sign(Owner owner) { this->owner = owner; } /** Destroy the sign */ Sign::~Sign() { free(this->name); if (CleaningPool()) return; DeleteRenameSignWindow(this->index); } /** * Update the coordinate of one sign */ void Sign::UpdateVirtCoord() { Point pt = RemapCoords(this->x, this->y, this->z); SetDParam(0, this->index); this->sign.UpdatePosition(pt.x, pt.y - 6 * ZOOM_LVL_BASE, STR_WHITE_SIGN); } /** Update the coordinates of all signs */ void UpdateAllSignVirtCoords() { Sign *si; FOR_ALL_SIGNS(si) { si->UpdateVirtCoord(); } } openttd-1.5.3/src/autoreplace_func.h0000644000000000000000000001030612627373435016166 0ustar rootroot/* $Id: autoreplace_func.h 24136 2012-04-17 19:44:02Z michi_cc $ */ /* * 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 autoreplace_func.h Functions related to autoreplacing. */ #ifndef AUTOREPLACE_FUNC_H #define AUTOREPLACE_FUNC_H #include "command_type.h" #include "company_base.h" void RemoveAllEngineReplacement(EngineRenewList *erl); EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old = NULL); CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags); CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, DoCommandFlag flags); /** * Remove all engine replacement settings for the given company. * @param c the company. */ static inline void RemoveAllEngineReplacementForCompany(Company *c) { RemoveAllEngineReplacement(&c->engine_renew_list); } /** * Retrieve the engine replacement for the given company and original engine type. * @param c company. * @param engine Engine type. * @param group The group related to this replacement. * @param[out] replace_when_old Set to true if the replacement should be done when old. * @return The engine type to replace with, or INVALID_ENGINE if no * replacement is in the list. */ static inline EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group, bool *replace_when_old = NULL) { return EngineReplacement(c->engine_renew_list, engine, group, replace_when_old); } /** * Check if a company has a replacement set up for the given engine. * @param c Company. * @param engine Engine type to be replaced. * @param group The group related to this replacement. * @return true if a replacement was set up, false otherwise. */ static inline bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group) { return EngineReplacementForCompany(c, engine, group) != INVALID_ENGINE; } /** * Check if a company has a replacement set up for the given engine when it gets old. * @param c Company. * @param engine Engine type to be replaced. * @param group The group related to this replacement. * @return True if a replacement when old was set up, false otherwise. */ static inline bool EngineHasReplacementWhenOldForCompany(const Company *c, EngineID engine, GroupID group) { bool replace_when_old; EngineReplacement(c->engine_renew_list, engine, group, &replace_when_old); return replace_when_old; } /** * Add an engine replacement for the company. * @param c Company. * @param old_engine The original engine type. * @param new_engine The replacement engine type. * @param group The group related to this replacement. * @param replace_when_old Replace when old or always? * @param flags The calling command flags. * @return 0 on success, CMD_ERROR on failure. */ static inline CommandCost AddEngineReplacementForCompany(Company *c, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags) { return AddEngineReplacement(&c->engine_renew_list, old_engine, new_engine, group, replace_when_old, flags); } /** * Remove an engine replacement for the company. * @param c Company. * @param engine The original engine type. * @param group The group related to this replacement. * @param flags The calling command flags. * @return 0 on success, CMD_ERROR on failure. */ static inline CommandCost RemoveEngineReplacementForCompany(Company *c, EngineID engine, GroupID group, DoCommandFlag flags) { return RemoveEngineReplacement(&c->engine_renew_list, engine, group, flags); } bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company); #endif /* AUTOREPLACE_FUNC_H */ openttd-1.5.3/src/newgrf_sound.cpp0000644000000000000000000001444112627373443015705 0ustar rootroot/* $Id: newgrf_sound.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_sound.cpp Handling NewGRF provided sounds. */ #include "stdafx.h" #include "engine_base.h" #include "newgrf.h" #include "newgrf_engine.h" #include "newgrf_sound.h" #include "vehicle_base.h" #include "sound_func.h" #include "fileio_func.h" #include "debug.h" #include "settings_type.h" #include "safeguards.h" static SmallVector _sounds; /** * Allocate sound slots. * @param num Number of slots to allocate. * @return First allocated slot. */ SoundEntry *AllocateSound(uint num) { SoundEntry *sound = _sounds.Append(num); MemSetT(sound, 0, num); return sound; } void InitializeSoundPool() { _sounds.Clear(); /* Copy original sound data to the pool */ SndCopyToPool(); } SoundEntry *GetSound(SoundID index) { if (index >= _sounds.Length()) return NULL; return &_sounds[index]; } uint GetNumSounds() { return _sounds.Length(); } /** * Extract meta data from a NewGRF sound. * @param sound Sound to load. * @return True if a valid sound was loaded. */ bool LoadNewGRFSound(SoundEntry *sound) { if (sound->file_offset == SIZE_MAX || sound->file_slot == 0) return false; FioSeekToFile(sound->file_slot, sound->file_offset); /* Skip ID for container version >= 2 as we only look at the first * entry and ignore any further entries with the same ID. */ if (sound->grf_container_ver >= 2) FioReadDword(); /* Format: '\0' */ uint32 num = sound->grf_container_ver >= 2 ? FioReadDword() : FioReadWord(); if (FioReadByte() != 0xFF) return false; if (FioReadByte() != 0xFF) return false; uint8 name_len = FioReadByte(); char *name = AllocaM(char, name_len + 1); FioReadBlock(name, name_len + 1); /* Test string termination */ if (name[name_len] != 0) { DEBUG(grf, 2, "LoadNewGRFSound [%s]: Name not properly terminated", FioGetFilename(sound->file_slot)); return false; } DEBUG(grf, 2, "LoadNewGRFSound [%s]: Sound name '%s'...", FioGetFilename(sound->file_slot), name); if (FioReadDword() != BSWAP32('RIFF')) { DEBUG(grf, 1, "LoadNewGRFSound [%s]: Missing RIFF header", FioGetFilename(sound->file_slot)); return false; } uint32 total_size = FioReadDword(); uint header_size = 11; if (sound->grf_container_ver >= 2) header_size++; // The first FF in the sprite is only counted for container version >= 2. if (total_size + name_len + header_size > num) { DEBUG(grf, 1, "LoadNewGRFSound [%s]: RIFF was truncated", FioGetFilename(sound->file_slot)); return false; } if (FioReadDword() != BSWAP32('WAVE')) { DEBUG(grf, 1, "LoadNewGRFSound [%s]: Invalid RIFF type", FioGetFilename(sound->file_slot)); return false; } while (total_size >= 8) { uint32 tag = FioReadDword(); uint32 size = FioReadDword(); total_size -= 8; if (total_size < size) { DEBUG(grf, 1, "LoadNewGRFSound [%s]: Invalid RIFF", FioGetFilename(sound->file_slot)); return false; } total_size -= size; switch (tag) { case ' tmf': // 'fmt ' /* Audio format, must be 1 (PCM) */ if (size < 16 || FioReadWord() != 1) { DEBUG(grf, 1, "LoadGRFSound [%s]: Invalid audio format", FioGetFilename(sound->file_slot)); return false; } sound->channels = FioReadWord(); sound->rate = FioReadDword(); FioReadDword(); FioReadWord(); sound->bits_per_sample = FioReadWord(); /* The rest will be skipped */ size -= 16; break; case 'atad': // 'data' sound->file_size = size; sound->file_offset = FioGetPos(); DEBUG(grf, 2, "LoadNewGRFSound [%s]: channels %u, sample rate %u, bits per sample %u, length %u", FioGetFilename(sound->file_slot), sound->channels, sound->rate, sound->bits_per_sample, size); return true; // the fmt chunk has to appear before data, so we are finished default: /* Skip unknown chunks */ break; } /* Skip rest of chunk */ if (size > 0) FioSkipBytes(size); } DEBUG(grf, 1, "LoadNewGRFSound [%s]: RIFF does not contain any sound data", FioGetFilename(sound->file_slot)); /* Clear everything that was read */ MemSetT(sound, 0); return false; } /** * Checks whether a NewGRF wants to play a different vehicle sound effect. * @param v Vehicle to play sound effect for. * @param event Trigger for the sound effect. * @return false if the default sound effect shall be played instead. */ bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event) { if (!_settings_client.sound.vehicle) return true; const GRFFile *file = v->GetGRF(); uint16 callback; /* If the engine has no GRF ID associated it can't ever play any new sounds */ if (file == NULL) return false; /* Check that the vehicle type uses the sound effect callback */ if (!HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_SOUND_EFFECT)) return false; callback = GetVehicleCallback(CBID_VEHICLE_SOUND_EFFECT, event, 0, v->engine_type, v); /* Play default sound if callback fails */ if (callback == CALLBACK_FAILED) return false; if (callback >= ORIGINAL_SAMPLE_COUNT) { callback -= ORIGINAL_SAMPLE_COUNT; /* Play no sound if result is out of range */ if (callback > file->num_sounds) return true; callback += file->sound_offset; } assert(callback < GetNumSounds()); SndPlayVehicleFx(callback, v); return true; } /** * Play a NewGRF sound effect at the location of a specific tile. * @param file NewGRF triggering the sound effect. * @param sound_id Sound effect the NewGRF wants to play. * @param tile Location of the effect. */ void PlayTileSound(const GRFFile *file, SoundID sound_id, TileIndex tile) { if (sound_id >= ORIGINAL_SAMPLE_COUNT) { sound_id -= ORIGINAL_SAMPLE_COUNT; if (sound_id > file->num_sounds) return; sound_id += file->sound_offset; } assert(sound_id < GetNumSounds()); SndPlayTileFx(sound_id, tile); } openttd-1.5.3/src/string_func.h0000644000000000000000000001726712627373442015203 0ustar rootroot/* $Id: string_func.h 26513 2014-04-25 19:25:38Z frosch $ */ /* * 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 string_func.h Functions related to low-level strings. * * @note Be aware of "dangerous" string functions; string functions that * have behaviour that could easily cause buffer overruns and such: * - strncpy: does not '\0' terminate when input string is longer than * the size of the output string. Use strecpy instead. * - [v]snprintf: returns the length of the string as it would be written * when the output is large enough, so it can be more than the size of * the buffer and than can underflow size_t (uint-ish) which makes all * subsequent snprintf alikes write outside of the buffer. Use * [v]seprintf instead; it will return the number of bytes actually * added so no [v]seprintf will cause outside of bounds writes. * - [v]sprintf: does not bounds checking: use [v]seprintf instead. */ #ifndef STRING_FUNC_H #define STRING_FUNC_H #include #include "core/bitmath_func.hpp" #include "string_type.h" char *strecat(char *dst, const char *src, const char *last); char *strecpy(char *dst, const char *src, const char *last); char *stredup(const char *src, const char *last = NULL); int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4); int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap); char *CDECL str_fmt(const char *str, ...) WARN_FORMAT(1, 2); void str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); void ValidateString(const char *str); void str_fix_scc_encoded(char *str, const char *last); void str_strip_colours(char *str); bool strtolower(char *str); bool StrValid(const char *str, const char *last); /** * Check if a string buffer is empty. * * @param s The pointer to the first element of the buffer * @return true if the buffer starts with the terminating null-character or * if the given pointer points to NULL else return false */ static inline bool StrEmpty(const char *s) { return s == NULL || s[0] == '\0'; } /** * Get the length of a string, within a limited buffer. * * @param str The pointer to the first element of the buffer * @param maxlen The maximum size of the buffer * @return The length of the string */ static inline size_t ttd_strnlen(const char *str, size_t maxlen) { const char *t; for (t = str; (size_t)(t - str) < maxlen && *t != '\0'; t++) {} return t - str; } char *md5sumToString(char *buf, const char *last, const uint8 md5sum[16]); bool IsValidChar(WChar key, CharSetFilter afilter); size_t Utf8Decode(WChar *c, const char *s); size_t Utf8Encode(char *buf, WChar c); size_t Utf8TrimString(char *s, size_t maxlen); static inline WChar Utf8Consume(const char **s) { WChar c; *s += Utf8Decode(&c, *s); return c; } /** * Return the length of a UTF-8 encoded character. * @param c Unicode character. * @return Length of UTF-8 encoding for character. */ static inline int8 Utf8CharLen(WChar c) { if (c < 0x80) return 1; if (c < 0x800) return 2; if (c < 0x10000) return 3; if (c < 0x110000) return 4; /* Invalid valid, we encode as a '?' */ return 1; } /** * Return the length of an UTF-8 encoded value based on a single char. This * char should be the first byte of the UTF-8 encoding. If not, or encoding * is invalid, return value is 0 * @param c char to query length of * @return requested size */ static inline int8 Utf8EncodedCharLen(char c) { if (GB(c, 3, 5) == 0x1E) return 4; if (GB(c, 4, 4) == 0x0E) return 3; if (GB(c, 5, 3) == 0x06) return 2; if (GB(c, 7, 1) == 0x00) return 1; /* Invalid UTF8 start encoding */ return 0; } /* Check if the given character is part of a UTF8 sequence */ static inline bool IsUtf8Part(char c) { return GB(c, 6, 2) == 2; } /** * Retrieve the previous UNICODE character in an UTF-8 encoded string. * @param s char pointer pointing to (the first char of) the next character * @return a pointer in 's' to the previous UNICODE character's first byte * @note The function should not be used to determine the length of the previous * encoded char because it might be an invalid/corrupt start-sequence */ static inline char *Utf8PrevChar(char *s) { char *ret = s; while (IsUtf8Part(*--ret)) {} return ret; } static inline const char *Utf8PrevChar(const char *s) { const char *ret = s; while (IsUtf8Part(*--ret)) {} return ret; } size_t Utf8StringLength(const char *s); /** * Is the given character a lead surrogate code point? * @param c The character to test. * @return True if the character is a lead surrogate code point. */ static inline bool Utf16IsLeadSurrogate(uint c) { return c >= 0xD800 && c <= 0xDBFF; } /** * Is the given character a lead surrogate code point? * @param c The character to test. * @return True if the character is a lead surrogate code point. */ static inline bool Utf16IsTrailSurrogate(uint c) { return c >= 0xDC00 && c <= 0xDFFF; } /** * Convert an UTF-16 surrogate pair to the corresponding Unicode character. * @param lead Lead surrogate code point. * @param trail Trail surrogate code point. * @return Decoded Unicode character. */ static inline WChar Utf16DecodeSurrogate(uint lead, uint trail) { return 0x10000 + (((lead - 0xD800) << 10) | (trail - 0xDC00)); } /** * Decode an UTF-16 character. * @param c Pointer to one or two UTF-16 code points. * @return Decoded Unicode character. */ static inline WChar Utf16DecodeChar(const uint16 *c) { if (Utf16IsLeadSurrogate(c[0])) { return Utf16DecodeSurrogate(c[0], c[1]); } else { return *c; } } /** * Is the given character a text direction character. * @param c The character to test. * @return true iff the character is used to influence * the text direction. */ static inline bool IsTextDirectionChar(WChar c) { switch (c) { case CHAR_TD_LRM: case CHAR_TD_RLM: case CHAR_TD_LRE: case CHAR_TD_RLE: case CHAR_TD_LRO: case CHAR_TD_RLO: case CHAR_TD_PDF: return true; default: return false; } } static inline bool IsPrintable(WChar c) { if (c < 0x20) return false; if (c < 0xE000) return true; if (c < 0xE200) return false; return true; } /** * Check whether UNICODE character is whitespace or not, i.e. whether * this is a potential line-break character. * @param c UNICODE character to check * @return a boolean value whether 'c' is a whitespace character or not * @see http://www.fileformat.info/info/unicode/category/Zs/list.htm */ static inline bool IsWhitespace(WChar c) { return c == 0x0020 /* SPACE */ || c == 0x3000; /* IDEOGRAPHIC SPACE */ } /* Needed for NetBSD version (so feature) testing */ #if defined(__NetBSD__) || defined(__FreeBSD__) #include #endif /* strcasestr is available for _GNU_SOURCE, BSD and some Apple */ #if defined(_GNU_SOURCE) || (defined(__BSD_VISIBLE) && __BSD_VISIBLE) || (defined(__APPLE__) && (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))) || defined(_NETBSD_SOURCE) # undef DEFINE_STRCASESTR #else # define DEFINE_STRCASESTR char *strcasestr(const char *haystack, const char *needle); #endif /* strcasestr is available */ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front = false); #endif /* STRING_FUNC_H */ openttd-1.5.3/src/townname_type.h0000644000000000000000000000314512627373435015543 0ustar rootroot/* $Id: townname_type.h 26313 2014-02-06 21:06:59Z rubidium $ */ /* * 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 townname_type.h * Definition of structures used for generating town names. */ #ifndef TOWNNAME_TYPE_H #define TOWNNAME_TYPE_H #include "newgrf_townname.h" #include "town_type.h" #include #include typedef std::set TownNames; /** * Struct holding a parameters used to generate town name. * Speeds things up a bit because these values are computed only once per name generation. */ struct TownNameParams { uint32 grfid; ///< newgrf ID (0 if not used) uint16 type; ///< town name style /** * Initializes this struct from language ID * @param town_name town name 'language' ID */ TownNameParams(byte town_name) { extern int _nb_orig_names; bool grf = town_name >= _nb_orig_names; this->grfid = grf ? GetGRFTownNameId(town_name - _nb_orig_names) : 0; this->type = grf ? GetGRFTownNameType(town_name - _nb_orig_names) : SPECSTR_TOWNNAME_START + town_name; } TownNameParams(const Town *t); }; #endif /* TOWNNAME_TYPE_H */ openttd-1.5.3/src/news_type.h0000644000000000000000000001714612627373442014673 0ustar rootroot/* $Id: news_type.h 24843 2012-12-23 21:07:12Z frosch $ */ /* * 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 news_type.h Types related to news. */ #ifndef NEWS_TYPE_H #define NEWS_TYPE_H #include "core/enum_type.hpp" #include "date_type.h" #include "strings_type.h" #include "sound_type.h" /** Constants in the message options window. */ enum MessageOptionsSpace { MOS_WIDG_PER_SETTING = 4, ///< Number of widgets needed for each news category, starting at widget #WID_MO_START_OPTION. MOS_LEFT_EDGE = 6, ///< Number of pixels between left edge of the window and the options buttons column. MOS_COLUMN_SPACING = 4, ///< Number of pixels between the buttons and the description columns. MOS_RIGHT_EDGE = 6, ///< Number of pixels between right edge of the window and the options descriptions column. MOS_BUTTON_SPACE = 10, ///< Additional space in the button with the option value (for better looks). MOS_ABOVE_GLOBAL_SETTINGS = 6, ///< Number of vertical pixels between the categories and the global options. MOS_BOTTOM_EDGE = 6, ///< Number of pixels between bottom edge of the window and bottom of the global options. }; /** * Type of news. */ enum NewsType { NT_ARRIVAL_COMPANY, ///< First vehicle arrived for company NT_ARRIVAL_OTHER, ///< First vehicle arrived for competitor NT_ACCIDENT, ///< An accident or disaster has occurred NT_COMPANY_INFO, ///< Company info (new companies, bankruptcy messages) NT_INDUSTRY_OPEN, ///< Opening of industries NT_INDUSTRY_CLOSE, ///< Closing of industries NT_ECONOMY, ///< Economic changes (recession, industry up/dowm) NT_INDUSTRY_COMPANY,///< Production changes of industry serviced by local company NT_INDUSTRY_OTHER, ///< Production changes of industry serviced by competitor(s) NT_INDUSTRY_NOBODY, ///< Other industry production changes NT_ADVICE, ///< Bits of news about vehicles of the company NT_NEW_VEHICLES, ///< New vehicle has become available NT_ACCEPTANCE, ///< A type of cargo is (no longer) accepted NT_SUBSIDIES, ///< News about subsidies (announcements, expirations, acceptance) NT_GENERAL, ///< General news (from towns) NT_END, ///< end-of-array marker }; /** * References to objects in news. * * @warning * Be careful! * Vehicles are a special case, as news are kept when vehicles are autoreplaced/renewed. * You have to make sure, #ChangeVehicleNews catches the DParams of your message. * This is NOT ensured by the references. */ enum NewsReferenceType { NR_NONE, ///< Empty reference NR_TILE, ///< Reference tile. Scroll to tile when clicking on the news. NR_VEHICLE, ///< Reference vehicle. Scroll to vehicle when clicking on the news. Delete news when vehicle is deleted. NR_STATION, ///< Reference station. Scroll to station when clicking on the news. Delete news when station is deleted. NR_INDUSTRY, ///< Reference industry. Scroll to industry when clicking on the news. Delete news when industry is deleted. NR_TOWN, ///< Reference town. Scroll to town when clicking on the news. NR_ENGINE, ///< Reference engine. }; /** * Various OR-able news-item flags. * @note #NF_INCOLOUR is set automatically if needed. */ enum NewsFlag { NFB_INCOLOUR = 0, ///< News item is shown in colour (otherwise it is shown in black & white). NFB_NO_TRANSPARENT = 1, ///< News item disables transparency in the viewport. NFB_SHADE = 2, ///< News item uses shaded colours. NFB_WINDOW_LAYOUT = 3, ///< First bit for window layout. NFB_WINDOW_LAYOUT_COUNT = 3, ///< Number of bits for window layout. NFB_VEHICLE_PARAM0 = 6, ///< String param 0 contains a vehicle ID. (special autoreplace behaviour) NF_INCOLOUR = 1 << NFB_INCOLOUR, ///< Bit value for coloured news. NF_NO_TRANSPARENT = 1 << NFB_NO_TRANSPARENT, ///< Bit value for disabling transparency. NF_SHADE = 1 << NFB_SHADE, ///< Bit value for enabling shading. NF_VEHICLE_PARAM0 = 1 << NFB_VEHICLE_PARAM0, ///< Bit value for specifying that string param 0 contains a vehicle ID. (special autoreplace behaviour) NF_THIN = 0 << NFB_WINDOW_LAYOUT, ///< Thin news item. (Newspaper with headline and viewport) NF_SMALL = 1 << NFB_WINDOW_LAYOUT, ///< Small news item. (Information window with text and viewport) NF_NORMAL = 2 << NFB_WINDOW_LAYOUT, ///< Normal news item. (Newspaper with text only) NF_VEHICLE = 3 << NFB_WINDOW_LAYOUT, ///< Vehicle news item. (new engine available) NF_COMPANY = 4 << NFB_WINDOW_LAYOUT, ///< Company news item. (Newspaper with face) }; DECLARE_ENUM_AS_BIT_SET(NewsFlag) /** * News display options */ enum NewsDisplay { ND_OFF, ///< Only show a reminder in the status bar ND_SUMMARY, ///< Show ticker ND_FULL, ///< Show newspaper }; /** * Per-NewsType data */ struct NewsTypeData { const char * const name; ///< Name const byte age; ///< Maximum age of news items (in days) const SoundFx sound; ///< Sound /** * Construct this entry. * @param name The name of the type. * @param age The maximum age for these messages. * @param sound The sound to play. */ NewsTypeData(const char *name, byte age, SoundFx sound) : name(name), age(age), sound(sound) { } NewsDisplay GetDisplay() const; }; /** Information about a single item of news. */ struct NewsItem { NewsItem *prev; ///< Previous news item NewsItem *next; ///< Next news item StringID string_id; ///< Message text Date date; ///< Date of the news NewsType type; ///< Type of the news NewsFlag flags; ///< NewsFlags bits @see NewsFlag NewsReferenceType reftype1; ///< Type of ref1 NewsReferenceType reftype2; ///< Type of ref2 uint32 ref1; ///< Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleteing the news when the object is deleted. uint32 ref2; ///< Reference 2 to some object: Used for scrolling after clicking on the news, and for deleteing the news when the object is deleted. void *free_data; ///< Data to be freed when the news item has reached its end. ~NewsItem() { free(this->free_data); } uint64 params[10]; ///< Parameters for string resolving. }; /** * Data that needs to be stored for company news messages. * The problem with company news messages are the custom name * of the companies and the fact that the company data is reset, * resulting in wrong names and such. */ struct CompanyNewsInformation { char company_name[64]; ///< The name of the company char president_name[64]; ///< The name of the president char other_company_name[64]; ///< The name of the company taking over this one uint32 face; ///< The face of the president byte colour; ///< The colour related to the company void FillData(const struct Company *c, const struct Company *other = NULL); }; #endif /* NEWS_TYPE_H */ openttd-1.5.3/src/airport_gui.cpp0000644000000000000000000005264512627373435015542 0ustar rootroot/* $Id: airport_gui.cpp 27163 2015-02-22 15:26:27Z frosch $ */ /* * 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 airport_gui.cpp The GUI for airports. */ #include "stdafx.h" #include "window_gui.h" #include "station_gui.h" #include "terraform_gui.h" #include "sound_func.h" #include "window_func.h" #include "strings_func.h" #include "viewport_func.h" #include "company_func.h" #include "tilehighlight_func.h" #include "company_base.h" #include "station_type.h" #include "newgrf_airport.h" #include "newgrf_callbacks.h" #include "widgets/dropdown_type.h" #include "core/geometry_func.hpp" #include "hotkeys.h" #include "vehicle_func.h" #include "gui.h" #include "widgets/airport_widget.h" #include "safeguards.h" static AirportClassID _selected_airport_class; ///< the currently visible airport class static int _selected_airport_index; ///< the index of the selected airport in the current class or -1 static byte _selected_airport_layout; ///< selected airport layout number. static void ShowBuildAirportPicker(Window *parent); SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout); void CcBuildAirport(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } /** * Place an airport. * @param tile Position to put the new airport. */ static void PlaceAirport(TileIndex tile) { if (_selected_airport_index == -1) return; uint32 p2 = _ctrl_pressed; SB(p2, 16, 16, INVALID_STATION); // no station to join uint32 p1 = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex(); p1 |= _selected_airport_layout << 8; CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_AIRPORT | CMD_MSG(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE), CcBuildAirport, "" }; ShowSelectStationIfNeeded(cmdcont, TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE)); } /** Airport build toolbar window handler. */ struct BuildAirToolbarWindow : Window { int last_user_action; // Last started user action. BuildAirToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); this->last_user_action = WIDGET_LIST_END; } ~BuildAirToolbarWindow() { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } /** * 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; if (!CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) delete this; } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_AT_AIRPORT: if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) { ShowBuildAirportPicker(this); this->last_user_action = widget; } break; case WID_AT_DEMOLISH: HandlePlacePushButton(this, WID_AT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_user_action = widget; break; default: break; } } virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_user_action) { case WID_AT_AIRPORT: PlaceAirport(tile); break; case WID_AT_DEMOLISH: PlaceProc_DemolishArea(tile); break; default: NOT_REACHED(); } } 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 && select_proc == DDSP_DEMOLISH_AREA) { GUIPlaceProcDragXY(select_proc, start_tile, end_tile); } } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); DeleteWindowById(WC_BUILD_STATION, TRANSPORT_AIR); DeleteWindowById(WC_SELECT_STATION, 0); } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the BuildAirToolbarWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState AirportToolbarGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) return ES_NOT_HANDLED; Window *w = ShowBuildAirToolbar(); if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } static Hotkey airtoolbar_hotkeys[] = { Hotkey('1', "airport", WID_AT_AIRPORT), Hotkey('2', "demolish", WID_AT_DEMOLISH), HOTKEY_LIST_END }; HotkeyList BuildAirToolbarWindow::hotkeys("airtoolbar", airtoolbar_hotkeys, AirportToolbarGlobalHotkeys); static const NWidgetPart _nested_air_toolbar_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_AIRPORT), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_AIRPORT, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), EndContainer(), }; static WindowDesc _air_toolbar_desc( WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_air_toolbar_widgets, lengthof(_nested_air_toolbar_widgets), &BuildAirToolbarWindow::hotkeys ); /** * Open the build airport toolbar window * * If the terraform toolbar is linked to the toolbar, that window is also opened. * * @return newly opened airport toolbar, or NULL if the toolbar could not be opened. */ Window *ShowBuildAirToolbar() { if (!Company::IsValidID(_local_company)) return NULL; DeleteWindowByClass(WC_BUILD_TOOLBAR); return AllocateWindowDescFront(&_air_toolbar_desc, TRANSPORT_AIR); } class BuildAirportWindow : public PickerWindowBase { SpriteID preview_sprite; ///< Cached airport preview sprite. int line_height; Scrollbar *vscroll; /** Build a dropdown list of available airport classes */ static DropDownList *BuildAirportClassDropDown() { DropDownList *list = new DropDownList(); for (uint i = 0; i < AirportClass::GetClassCount(); i++) { *list->Append() = new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false); } return list; } public: BuildAirportWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_AP_SCROLLBAR); this->vscroll->SetCapacity(5); this->vscroll->SetPosition(0); this->FinishInitNested(TRANSPORT_AIR); this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); this->OnInvalidateData(); /* Ensure airport class is valid (changing NewGRFs). */ _selected_airport_class = Clamp(_selected_airport_class, APC_BEGIN, (AirportClassID)(AirportClass::GetClassCount() - 1)); const AirportClass *ac = AirportClass::Get(_selected_airport_class); this->vscroll->SetCount(ac->GetSpecCount()); /* Ensure the airport index is valid for this class (changing NewGRFs). */ _selected_airport_index = Clamp(_selected_airport_index, -1, ac->GetSpecCount() - 1); /* Only when no valid airport was selected, we want to select the first airport. */ bool selectFirstAirport = true; if (_selected_airport_index != -1) { const AirportSpec *as = ac->GetSpec(_selected_airport_index); if (as->IsAvailable()) { /* Ensure the airport layout is valid. */ _selected_airport_layout = Clamp(_selected_airport_layout, 0, as->num_table - 1); selectFirstAirport = false; this->UpdateSelectSize(); } } if (selectFirstAirport) this->SelectFirstAvailableAirport(true); } virtual ~BuildAirportWindow() { DeleteWindowById(WC_SELECT_STATION, 0); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AP_CLASS_DROPDOWN: SetDParam(0, AirportClass::Get(_selected_airport_class)->name); break; case WID_AP_LAYOUT_NUM: SetDParam(0, STR_EMPTY); if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_LAYOUT_NAME); if (string != STR_UNDEFINED) { SetDParam(0, string); } else if (as->num_table > 1) { SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME); SetDParam(1, _selected_airport_layout + 1); } } break; default: break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_AP_CLASS_DROPDOWN: { Dimension d = {0, 0}; for (uint i = 0; i < AirportClass::GetClassCount(); i++) { SetDParam(0, AirportClass::Get((AirportClassID)i)->name); d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_AP_AIRPORT_LIST: { for (int i = 0; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; size->width = max(size->width, GetStringBoundingBox(as->name).width); } this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 5 * this->line_height; break; } case WID_AP_AIRPORT_SPRITE: for (int i = 0; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; for (byte layout = 0; layout < as->num_table; layout++) { SpriteID sprite = GetCustomAirportSprite(as, layout); if (sprite != 0) { Dimension d = GetSpriteSize(sprite); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(d, *size); } } } break; case WID_AP_EXTRA_TEXT: for (int i = NEW_AIRPORT_OFFSET; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; for (byte layout = 0; layout < as->num_table; layout++) { StringID string = GetAirportTextCallback(as, layout, CBID_AIRPORT_ADDITIONAL_TEXT); if (string == STR_UNDEFINED) continue; /* STR_BLACK_STRING is used to start the string with {BLACK} */ SetDParam(0, string); Dimension d = GetStringMultiLineBoundingBox(STR_BLACK_STRING, *size); *size = maxdim(d, *size); } } break; default: break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_AP_AIRPORT_LIST: { int y = r.top; AirportClass *apclass = AirportClass::Get(_selected_airport_class); for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < apclass->GetSpecCount(); i++) { const AirportSpec *as = apclass->GetSpec(i); if (!as->IsAvailable()) { GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER); } DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); y += this->line_height; } break; } case WID_AP_AIRPORT_SPRITE: if (this->preview_sprite != 0) { Dimension d = GetSpriteSize(this->preview_sprite); DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), (r.left + r.right - d.width) / 2, (r.top + r.bottom - d.height) / 2); } break; case WID_AP_EXTRA_TEXT: if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT); if (string != STR_UNDEFINED) { SetDParam(0, string); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING); } } break; } } virtual void OnPaint() { this->DrawWidgets(); uint16 top = this->GetWidget(WID_AP_BTN_DOHILIGHT)->pos_y + this->GetWidget(WID_AP_BTN_DOHILIGHT)->current_y + WD_PAR_VSEP_NORMAL; NWidgetBase *panel_nwi = this->GetWidget(WID_AP_BOTTOMPANEL); int right = panel_nwi->pos_x + panel_nwi->current_x; int bottom = panel_nwi->pos_y + panel_nwi->current_y; if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; /* only show the station (airport) noise, if the noise option is activated */ if (_settings_game.economy.station_noise_level) { /* show the noise of the selected airport */ SetDParam(0, as->noise_level); DrawString(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_STATION_BUILD_NOISE); top += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; } /* strings such as 'Size' and 'Coverage Area' */ top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; } /* Resize background if the window is too small. * Never make the window smaller to avoid oscillating if the size change affects the acceptance. * (This is the case, if making the window bigger moves the mouse into the window.) */ if (top > bottom) { ResizeWindow(this, 0, top - bottom, false); } } void SelectOtherAirport(int airport_index) { _selected_airport_index = airport_index; _selected_airport_layout = 0; this->UpdateSelectSize(); this->SetDirty(); } void UpdateSelectSize() { if (_selected_airport_index == -1) { SetTileSelectSize(1, 1); this->DisableWidget(WID_AP_LAYOUT_DECREASE); this->DisableWidget(WID_AP_LAYOUT_INCREASE); } else { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); int w = as->size_x; int h = as->size_y; Direction rotation = as->rotation[_selected_airport_layout]; if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); SetTileSelectSize(w, h); this->preview_sprite = GetCustomAirportSprite(as, _selected_airport_layout); this->SetWidgetDisabledState(WID_AP_LAYOUT_DECREASE, _selected_airport_layout == 0); this->SetWidgetDisabledState(WID_AP_LAYOUT_INCREASE, _selected_airport_layout + 1 >= as->num_table); int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_AP_CLASS_DROPDOWN: ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class, WID_AP_CLASS_DROPDOWN); break; case WID_AP_AIRPORT_LIST: { int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; if (num_clicked >= this->vscroll->GetCount()) break; const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); break; } case WID_AP_BTN_DONTHILIGHT: case WID_AP_BTN_DOHILIGHT: _settings_client.gui.station_show_coverage = (widget != WID_AP_BTN_DONTHILIGHT); this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); this->SetDirty(); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->UpdateSelectSize(); break; case WID_AP_LAYOUT_DECREASE: _selected_airport_layout--; this->UpdateSelectSize(); this->SetDirty(); break; case WID_AP_LAYOUT_INCREASE: _selected_airport_layout++; this->UpdateSelectSize(); this->SetDirty(); break; } } /** * Select the first available airport. * @param change_class If true, change the class if no airport in the current * class is available. */ void SelectFirstAvailableAirport(bool change_class) { /* First try to select an airport in the selected class. */ AirportClass *sel_apclass = AirportClass::Get(_selected_airport_class); for (uint i = 0; i < sel_apclass->GetSpecCount(); i++) { const AirportSpec *as = sel_apclass->GetSpec(i); if (as->IsAvailable()) { this->SelectOtherAirport(i); return; } } if (change_class) { /* If that fails, select the first available airport * from a random class. */ for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) { AirportClass *apclass = AirportClass::Get(j); for (uint i = 0; i < apclass->GetSpecCount(); i++) { const AirportSpec *as = apclass->GetSpec(i); if (as->IsAvailable()) { _selected_airport_class = j; this->SelectOtherAirport(i); return; } } } } /* If all airports are unavailable, select nothing. */ this->SelectOtherAirport(-1); } virtual void OnDropdownSelect(int widget, int index) { assert(widget == WID_AP_CLASS_DROPDOWN); _selected_airport_class = (AirportClassID)index; this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount()); this->SelectFirstAvailableAirport(false); } virtual void OnTick() { CheckRedrawStationCoverage(this); } }; static const NWidgetPart _nested_build_airport_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), EndContainer(), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), EndContainer(), /* Bottom panel. */ NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL), SetPIP(2, 2, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), SetFill(1, 0), EndContainer(), }; static WindowDesc _build_airport_desc( WDP_AUTO, "build_station_air", 0, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_airport_widgets, lengthof(_nested_build_airport_widgets) ); static void ShowBuildAirportPicker(Window *parent) { new BuildAirportWindow(&_build_airport_desc, parent); } void InitializeAirportGui() { _selected_airport_class = APC_BEGIN; _selected_airport_index = -1; } openttd-1.5.3/src/engine_func.h0000644000000000000000000000257412627373435015137 0ustar rootroot/* $Id: engine_func.h 26849 2014-09-18 19:53:22Z alberth $ */ /* * 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 engine_func.h Functions related to engines. */ #ifndef ENGINE_FUNC_H #define ENGINE_FUNC_H #include "engine_type.h" #include "vehicle_type.h" #include "company_type.h" void SetupEngines(); void StartupEngines(); void CheckEngines(); /* Original engine data counts and offsets */ extern const uint8 _engine_counts[4]; extern const uint8 _engine_offsets[4]; bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company); bool IsEngineRefittable(EngineID engine); void GetArticulatedVehicleCargoesAndRefits(EngineID engine, CargoArray *cargoes, uint32 *refits); void SetYearEngineAgingStops(); void StartupOneEngine(Engine *e, Date aging_date); uint GetTotalCapacityOfArticulatedParts(EngineID engine); #endif /* ENGINE_FUNC_H */ openttd-1.5.3/src/zoom_func.h0000644000000000000000000000474612627373435014661 0ustar rootroot/* $Id: zoom_func.h 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 zoom_func.h Functions related to zooming. */ #ifndef ZOOM_FUNC_H #define ZOOM_FUNC_H #include "zoom_type.h" /** * Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_NORMAL) * When shifting right, value is rounded up * @param value value to shift * @param zoom zoom level to shift to * @return shifted value */ static inline int ScaleByZoom(int value, ZoomLevel zoom) { assert(zoom >= 0); return value << zoom; } /** * Scale by zoom level, usually shift right (when zoom > ZOOM_LVL_NORMAL) * When shifting right, value is rounded up * @param value value to shift * @param zoom zoom level to shift to * @return shifted value */ static inline int UnScaleByZoom(int value, ZoomLevel zoom) { assert(zoom >= 0); return (value + (1 << zoom) - 1) >> zoom; } /** * Scale by zoom level, usually shift left (when zoom > ZOOM_LVL_NORMAL) * @param value value to shift * @param zoom zoom level to shift to * @return shifted value */ static inline int ScaleByZoomLower(int value, ZoomLevel zoom) { assert(zoom >= 0); return value << zoom; } /** * Scale by zoom level, usually shift right (when zoom > ZOOM_LVL_NORMAL) * @param value value to shift * @param zoom zoom level to shift to * @return shifted value */ static inline int UnScaleByZoomLower(int value, ZoomLevel zoom) { assert(zoom >= 0); return value >> zoom; } /** * Short-hand to apply GUI zoom level. * @param value Pixel amount at #ZOOM_LVL_BEGIN (full zoom in). * @return value Pixel amount at #ZOOM_LVL_GUI. */ static inline int UnScaleGUI(int value) { return UnScaleByZoom(value, ZOOM_LVL_GUI); } /** * Scale traditional pixel dimensions to GUI zoom level. * @param value Pixel amount at 1x zoom level. * @return value Pixel amount at #ZOOM_LVL_GUI. */ static inline int ScaleGUITrad(int value) { return UnScaleGUI(value * ZOOM_LVL_BASE); } #endif /* ZOOM_FUNC_H */ openttd-1.5.3/src/newgrf_cargo.cpp0000644000000000000000000000705212627373435015651 0ustar rootroot/* $Id: newgrf_cargo.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_cargo.cpp Implementation of NewGRF cargoes. */ #include "stdafx.h" #include "debug.h" #include "newgrf_spritegroup.h" #include "safeguards.h" /** Resolver of cargo. */ struct CargoResolverObject : public ResolverObject { CargoResolverObject(const CargoSpec *cs, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; }; /* virtual */ const SpriteGroup *CargoResolverObject::ResolveReal(const RealSpriteGroup *group) const { /* Cargo action 2s should always have only 1 "loaded" state, but some * times things don't follow the spec... */ if (group->num_loaded > 0) return group->loaded[0]; if (group->num_loading > 0) return group->loading[0]; return NULL; } /** * Constructor of the cargo resolver. * @param cs Cargo being resolved. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ CargoResolverObject::CargoResolverObject(const CargoSpec *cs, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(cs->grffile, callback, callback_param1, callback_param2) { this->root_spritegroup = cs->group; } /** * Get the custom sprite for the given cargo type. * @param cs Cargo being queried. * @return Custom sprite to draw, or \c 0 if not available. */ SpriteID GetCustomCargoSprite(const CargoSpec *cs) { CargoResolverObject object(cs); const SpriteGroup *group = object.Resolve(); if (group == NULL) return 0; return group->GetResult(); } uint16 GetCargoCallback(CallbackID callback, uint32 param1, uint32 param2, const CargoSpec *cs) { CargoResolverObject object(cs, callback, param1, param2); return object.ResolveCallback(); } /** * Translate a GRF-local cargo slot/bitnum into a CargoID. * @param cargo GRF-local cargo slot/bitnum. * @param grffile Originating GRF file. * @param usebit Defines the meaning of \a cargo for GRF version < 7. * If true, then \a cargo is a bitnum. If false, then \a cargo is a cargoslot. * For GRF version >= 7 \a cargo is always a translated cargo bit. * @return CargoID or CT_INVALID if the cargo is not available. */ CargoID GetCargoTranslation(uint8 cargo, const GRFFile *grffile, bool usebit) { /* Pre-version 7 uses the 'climate dependent' ID in callbacks and properties, i.e. cargo is the cargo ID */ if (grffile->grf_version < 7 && !usebit) return cargo; /* Other cases use (possibly translated) cargobits */ if (grffile->cargo_list.Length() > 0) { /* ...and the cargo is in bounds, then get the cargo ID for * the label */ if (cargo < grffile->cargo_list.Length()) return GetCargoIDByLabel(grffile->cargo_list[cargo]); } else { /* Else the cargo value is a 'climate independent' 'bitnum' */ return GetCargoIDByBitnum(cargo); } return CT_INVALID; } openttd-1.5.3/src/industry_map.h0000644000000000000000000002121312627373433015362 0ustar rootroot/* $Id: industry_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 industry_map.h Accessors for industries */ #ifndef INDUSTRY_MAP_H #define INDUSTRY_MAP_H #include "industrytype.h" #include "water_map.h" /** * The following enums are indices used to know what to draw for this industry tile. * They all are pointing toward array _industry_draw_tile_data, in table/industry_land.h * How to calculate the correct position ? GFXid << 2 | IndustryStage (0 to 3) */ enum IndustryGraphics { GFX_COAL_MINE_TOWER_NOT_ANIMATED = 0, GFX_COAL_MINE_TOWER_ANIMATED = 1, GFX_POWERPLANT_CHIMNEY = 8, GFX_POWERPLANT_SPARKS = 10, GFX_OILRIG_1 = 24, GFX_OILRIG_2 = 25, GFX_OILRIG_3 = 26, GFX_OILRIG_4 = 27, GFX_OILRIG_5 = 28, GFX_OILWELL_NOT_ANIMATED = 29, GFX_OILWELL_ANIMATED_1 = 30, GFX_OILWELL_ANIMATED_2 = 31, GFX_OILWELL_ANIMATED_3 = 32, GFX_COPPER_MINE_TOWER_NOT_ANIMATED = 47, GFX_COPPER_MINE_TOWER_ANIMATED = 48, GFX_COPPER_MINE_CHIMNEY = 49, GFX_GOLD_MINE_TOWER_NOT_ANIMATED = 79, GFX_GOLD_MINE_TOWER_ANIMATED = 88, GFX_TOY_FACTORY = 143, GFX_PLASTIC_FOUNTAIN_ANIMATED_1 = 148, GFX_PLASTIC_FOUNTAIN_ANIMATED_2 = 149, GFX_PLASTIC_FOUNTAIN_ANIMATED_3 = 150, GFX_PLASTIC_FOUNTAIN_ANIMATED_4 = 151, GFX_PLASTIC_FOUNTAIN_ANIMATED_5 = 152, GFX_PLASTIC_FOUNTAIN_ANIMATED_6 = 153, GFX_PLASTIC_FOUNTAIN_ANIMATED_7 = 154, GFX_PLASTIC_FOUNTAIN_ANIMATED_8 = 155, GFX_BUBBLE_GENERATOR = 161, GFX_BUBBLE_CATCHER = 162, GFX_TOFFEE_QUARY = 165, GFX_SUGAR_MINE_SIEVE = 174, GFX_WATERTILE_SPECIALCHECK = 255, ///< not really a tile, but rather a very special check }; /** * Get the industry ID of the given tile * @param t the tile to get the industry ID from * @pre IsTileType(t, MP_INDUSTRY) * @return the industry ID */ static inline IndustryID GetIndustryIndex(TileIndex t) { assert(IsTileType(t, MP_INDUSTRY)); return _m[t].m2; } /** * Is this industry tile fully built? * @param t the tile to analyze * @pre IsTileType(t, MP_INDUSTRY) * @return true if and only if the industry tile is fully built */ static inline bool IsIndustryCompleted(TileIndex t) { assert(IsTileType(t, MP_INDUSTRY)); return HasBit(_m[t].m1, 7); } IndustryType GetIndustryType(TileIndex tile); /** * Set if the industry that owns the tile as under construction or not * @param tile the tile to query * @pre IsTileType(tile, MP_INDUSTRY) */ static inline void SetIndustryCompleted(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); SB(_m[tile].m1, 7, 1, 1); } /** * Returns the industry construction stage of the specified tile * @param tile the tile to query * @pre IsTileType(tile, MP_INDUSTRY) * @return the construction stage */ static inline byte GetIndustryConstructionStage(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); return IsIndustryCompleted(tile) ? (byte)INDUSTRY_COMPLETED : GB(_m[tile].m1, 0, 2); } /** * Sets the industry construction stage of the specified tile * @param tile the tile to query * @param value the new construction stage * @pre IsTileType(tile, MP_INDUSTRY) */ static inline void SetIndustryConstructionStage(TileIndex tile, byte value) { assert(IsTileType(tile, MP_INDUSTRY)); SB(_m[tile].m1, 0, 2, value); } /** * Get the industry graphics ID for the given industry tile as * stored in the without translation. * @param t the tile to get the gfx for * @pre IsTileType(t, MP_INDUSTRY) * @return the gfx ID */ static inline IndustryGfx GetCleanIndustryGfx(TileIndex t) { assert(IsTileType(t, MP_INDUSTRY)); return _m[t].m5 | (GB(_me[t].m6, 2, 1) << 8); } /** * Get the industry graphics ID for the given industry tile * @param t the tile to get the gfx for * @pre IsTileType(t, MP_INDUSTRY) * @return the gfx ID */ static inline IndustryGfx GetIndustryGfx(TileIndex t) { assert(IsTileType(t, MP_INDUSTRY)); return GetTranslatedIndustryTileID(GetCleanIndustryGfx(t)); } /** * Set the industry graphics ID for the given industry tile * @param t the tile to set the gfx for * @pre IsTileType(t, MP_INDUSTRY) * @param gfx the graphics ID */ static inline void SetIndustryGfx(TileIndex t, IndustryGfx gfx) { assert(IsTileType(t, MP_INDUSTRY)); _m[t].m5 = GB(gfx, 0, 8); SB(_me[t].m6, 2, 1, GB(gfx, 8, 1)); } /** * Returns this industry tile's construction counter value * @param tile the tile to query * @pre IsTileType(tile, MP_INDUSTRY) * @return the construction counter */ static inline byte GetIndustryConstructionCounter(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); return GB(_m[tile].m1, 2, 2); } /** * Sets this industry tile's construction counter value * @param tile the tile to query * @param value the new value for the construction counter * @pre IsTileType(tile, MP_INDUSTRY) */ static inline void SetIndustryConstructionCounter(TileIndex tile, byte value) { assert(IsTileType(tile, MP_INDUSTRY)); SB(_m[tile].m1, 2, 2, value); } /** * Reset the construction stage counter of the industry, * as well as the completion bit. * In fact, it is the same as restarting construction frmo ground up * @param tile the tile to query * @pre IsTileType(tile, MP_INDUSTRY) */ static inline void ResetIndustryConstructionStage(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); SB(_m[tile].m1, 0, 4, 0); SB(_m[tile].m1, 7, 1, 0); } /** * Get the animation loop number * @param tile the tile to get the animation loop number of * @pre IsTileType(tile, MP_INDUSTRY) */ static inline byte GetIndustryAnimationLoop(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); return _m[tile].m4; } /** * Set the animation loop number * @param tile the tile to set the animation loop number of * @param count the new animation frame number * @pre IsTileType(tile, MP_INDUSTRY) */ static inline void SetIndustryAnimationLoop(TileIndex tile, byte count) { assert(IsTileType(tile, MP_INDUSTRY)); _m[tile].m4 = count; } /** * Get the random bits for this tile. * Used for grf callbacks * @param tile TileIndex of the tile to query * @pre IsTileType(tile, MP_INDUSTRY) * @return requested bits */ static inline byte GetIndustryRandomBits(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); return _m[tile].m3; } /** * Set the random bits for this tile. * Used for grf callbacks * @param tile TileIndex of the tile to query * @param bits the random bits * @pre IsTileType(tile, MP_INDUSTRY) */ static inline void SetIndustryRandomBits(TileIndex tile, byte bits) { assert(IsTileType(tile, MP_INDUSTRY)); _m[tile].m3 = bits; } /** * Get the activated triggers bits for this industry tile * Used for grf callbacks * @param tile TileIndex of the tile to query * @pre IsTileType(tile, MP_INDUSTRY) * @return requested triggers */ static inline byte GetIndustryTriggers(TileIndex tile) { assert(IsTileType(tile, MP_INDUSTRY)); return GB(_me[tile].m6, 3, 3); } /** * Set the activated triggers bits for this industry tile * Used for grf callbacks * @param tile TileIndex of the tile to query * @param triggers the triggers to set * @pre IsTileType(tile, MP_INDUSTRY) */ static inline void SetIndustryTriggers(TileIndex tile, byte triggers) { assert(IsTileType(tile, MP_INDUSTRY)); SB(_me[tile].m6, 3, 3, triggers); } /** * Make the given tile an industry tile * @param t the tile to make an industry tile * @param index the industry this tile belongs to * @param gfx the graphics to use for the tile * @param random the random value * @param wc the water class for this industry; only useful when build on water */ static inline void MakeIndustry(TileIndex t, IndustryID index, IndustryGfx gfx, uint8 random, WaterClass wc) { SetTileType(t, MP_INDUSTRY); _m[t].m1 = 0; _m[t].m2 = index; SetIndustryRandomBits(t, random); // m3 _m[t].m4 = 0; SetIndustryGfx(t, gfx); // m5, part of m6 SetIndustryTriggers(t, 0); // rest of m6 SetWaterClass(t, wc); _me[t].m7 = 0; } #endif /* INDUSTRY_MAP_H */ openttd-1.5.3/src/road_map.cpp0000644000000000000000000000471512627373435014773 0ustar rootroot/* $Id: road_map.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 road_map.cpp Complex road accessors. */ #include "stdafx.h" #include "station_map.h" #include "tunnelbridge_map.h" #include "safeguards.h" /** * Returns the RoadBits on an arbitrary tile * Special behaviour: * - road depots: entrance is treated as road piece * - road tunnels: entrance is treated as road piece * - bridge ramps: start of the ramp is treated as road piece * - bridge middle parts: bridge itself is ignored * * If straight_tunnel_bridge_entrance is set a ROAD_X or ROAD_Y * for bridge ramps and tunnel entrances is returned depending * on the orientation of the tunnel or bridge. * @param tile the tile to get the road bits for * @param rt the road type to get the road bits form * @param straight_tunnel_bridge_entrance whether to return straight road bits for tunnels/bridges. * @return the road bits of the given tile */ RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge_entrance) { if (!HasTileRoadType(tile, rt)) return ROAD_NONE; switch (GetTileType(tile)) { case MP_ROAD: switch (GetRoadTileType(tile)) { default: case ROAD_TILE_NORMAL: return GetRoadBits(tile, rt); case ROAD_TILE_CROSSING: return GetCrossingRoadBits(tile); case ROAD_TILE_DEPOT: return DiagDirToRoadBits(GetRoadDepotDirection(tile)); } case MP_STATION: if (!IsRoadStopTile(tile)) return ROAD_NONE; if (IsDriveThroughStopTile(tile)) return (GetRoadStopDir(tile) == DIAGDIR_NE) ? ROAD_X : ROAD_Y; return DiagDirToRoadBits(GetRoadStopDir(tile)); case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return ROAD_NONE; return straight_tunnel_bridge_entrance ? AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) : DiagDirToRoadBits(ReverseDiagDir(GetTunnelBridgeDirection(tile))); default: return ROAD_NONE; } } openttd-1.5.3/src/waypoint_base.h0000644000000000000000000000461512627373436015522 0ustar rootroot/* $Id: waypoint_base.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 waypoint_base.h Base of waypoints. */ #ifndef WAYPOINT_BASE_H #define WAYPOINT_BASE_H #include "base_station_base.h" /** Representation of a waypoint. */ struct Waypoint FINAL : SpecializedStation { uint16 town_cn; ///< The N-1th waypoint for this town (consecutive number) /** * Create a waypoint at the given tile. * @param tile The location of the waypoint. */ Waypoint(TileIndex tile = INVALID_TILE) : SpecializedStation(tile) { } ~Waypoint(); void UpdateVirtCoord(); /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const { return IsRailWaypointTile(tile) && GetStationIndex(tile) == this->index; } /* virtual */ uint32 GetNewGRFVariable(const struct ResolverObject &object, byte variable, byte parameter, bool *available) const; /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const { return 1; } /* virtual */ uint GetPlatformLength(TileIndex tile) const { return 1; } /** * Is this a single tile waypoint? * @return true if it is. */ inline bool IsSingleTile() const { return (this->facilities & FACIL_TRAIN) != 0 && this->train_station.w == 1 && this->train_station.h == 1; } /** * Is the "type" of waypoint the same as the given waypoint, * i.e. are both a rail waypoint or are both a buoy? * @param wp The waypoint to compare to. * @return true iff their types are equal. */ inline bool IsOfType(const Waypoint *wp) const { return this->string_id == wp->string_id; } }; /** * Iterate over all waypoints. * @param var The variable used for iteration. */ #define FOR_ALL_WAYPOINTS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Waypoint, var) #endif /* WAYPOINT_BASE_H */ openttd-1.5.3/src/tunnelbridge_map.h0000644000000000000000000001017012627373446016167 0ustar rootroot/* $Id: tunnelbridge_map.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 tunnelbridge_map.h Functions that have tunnels and bridges in common */ #ifndef TUNNELBRIDGE_MAP_H #define TUNNELBRIDGE_MAP_H #include "bridge_map.h" #include "tunnel_map.h" /** * Get the direction pointing to the other end. * * Tunnel: Get the direction facing into the tunnel * Bridge: Get the direction pointing onto the bridge * @param t The tile to analyze * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return the above mentioned direction */ static inline DiagDirection GetTunnelBridgeDirection(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); return (DiagDirection)GB(_m[t].m5, 0, 2); } /** * Tunnel: Get the transport type of the tunnel (road or rail) * Bridge: Get the transport type of the bridge's ramp * @param t The tile to analyze * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return the transport type in the tunnel/bridge */ static inline TransportType GetTunnelBridgeTransportType(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); return (TransportType)GB(_m[t].m5, 2, 2); } /** * Tunnel: Is this tunnel entrance in a snowy or desert area? * Bridge: Does the bridge ramp lie in a snow or desert area? * @param t The tile to analyze * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return true if and only if the tile is in a snowy/desert area */ static inline bool HasTunnelBridgeSnowOrDesert(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); return HasBit(_me[t].m7, 5); } /** * Tunnel: Places this tunnel entrance in a snowy or desert area, or takes it out of there. * Bridge: Sets whether the bridge ramp lies in a snow or desert area. * @param t the tunnel entrance / bridge ramp tile * @param snow_or_desert is the entrance/ramp in snow or desert (true), when * not in snow and not in desert false * @pre IsTileType(t, MP_TUNNELBRIDGE) */ static inline void SetTunnelBridgeSnowOrDesert(TileIndex t, bool snow_or_desert) { assert(IsTileType(t, MP_TUNNELBRIDGE)); SB(_me[t].m7, 5, 1, snow_or_desert); } /** * Determines type of the wormhole and returns its other end * @param t one end * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return other end */ static inline TileIndex GetOtherTunnelBridgeEnd(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); return IsTunnel(t) ? GetOtherTunnelEnd(t) : GetOtherBridgeEnd(t); } /** * Get the reservation state of the rail tunnel/bridge * @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL * @param t the tile * @return reservation state */ static inline bool HasTunnelBridgeReservation(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL); return HasBit(_m[t].m5, 4); } /** * Set the reservation state of the rail tunnel/bridge * @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL * @param t the tile * @param b the reservation state */ static inline void SetTunnelBridgeReservation(TileIndex t, bool b) { assert(IsTileType(t, MP_TUNNELBRIDGE)); assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL); SB(_m[t].m5, 4, 1, b ? 1 : 0); } /** * Get the reserved track bits for a rail tunnel/bridge * @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL * @param t the tile * @return reserved track bits */ static inline TrackBits GetTunnelBridgeReservationTrackBits(TileIndex t) { return HasTunnelBridgeReservation(t) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE; } #endif /* TUNNELBRIDGE_MAP_H */ openttd-1.5.3/src/signs_base.h0000644000000000000000000000261512627373442014766 0ustar rootroot/* $Id: signs_base.h 23104 2011-11-04 11:09:06Z rubidium $ */ /* * 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 signs_base.h Base class for signs. */ #ifndef SIGNS_BASE_H #define SIGNS_BASE_H #include "signs_type.h" #include "viewport_type.h" #include "core/pool_type.hpp" #include "company_type.h" typedef Pool SignPool; extern SignPool _sign_pool; struct Sign : SignPool::PoolItem<&_sign_pool> { char *name; ViewportSign sign; int32 x; int32 y; int32 z; OwnerByte owner; // placed by this company. Anyone can delete them though. OWNER_NONE for gray signs from old games. Sign(Owner owner = INVALID_OWNER); ~Sign(); void UpdateVirtCoord(); }; #define FOR_ALL_SIGNS_FROM(var, start) FOR_ALL_ITEMS_FROM(Sign, sign_index, var, start) #define FOR_ALL_SIGNS(var) FOR_ALL_SIGNS_FROM(var, 0) #endif /* SIGNS_BASE_H */ openttd-1.5.3/src/clear_func.h0000644000000000000000000000160712627373441014751 0ustar rootroot/* $Id: clear_func.h 23168 2011-11-08 19:48:47Z yexo $ */ /* * 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 clear_func.h Functions related to clear (MP_CLEAR) land. */ #ifndef CLEAR_FUNC_H #define CLEAR_FUNC_H #include "tile_cmd.h" void DrawHillyLandTile(const TileInfo *ti); void DrawClearLandTile(const TileInfo *ti, byte set); #endif /* CLEAR_FUNC_H */ openttd-1.5.3/src/window.cpp0000644000000000000000000033015312627373441014513 0ustar rootroot/* $Id: window.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 window.cpp Windowing system, widgets and events */ #include "stdafx.h" #include #include "company_func.h" #include "gfx_func.h" #include "console_func.h" #include "console_gui.h" #include "viewport_func.h" #include "progress.h" #include "blitter/factory.hpp" #include "zoom_func.h" #include "vehicle_base.h" #include "window_func.h" #include "tilehighlight_func.h" #include "network/network.h" #include "querystring_gui.h" #include "widgets/dropdown_func.h" #include "strings_func.h" #include "settings_type.h" #include "settings_func.h" #include "ini_type.h" #include "newgrf_debug.h" #include "hotkeys.h" #include "toolbar_gui.h" #include "statusbar_gui.h" #include "error.h" #include "game/game.hpp" #include "video/video_driver.hpp" #include "safeguards.h" /** Values for _settings_client.gui.auto_scrolling */ enum ViewportAutoscrolling { VA_DISABLED, //!< Do not autoscroll when mouse is at edge of viewport. VA_MAIN_VIEWPORT_FULLSCREEN, //!< Scroll main viewport at edge when using fullscreen. VA_MAIN_VIEWPORT, //!< Scroll main viewport at edge. VA_EVERY_VIEWPORT, //!< Scroll all viewports at their edges. }; static Point _drag_delta; ///< delta between mouse cursor and upper left corner of dragged window static Window *_mouseover_last_w = NULL; ///< Window of the last #MOUSEOVER event. static Window *_last_scroll_window = NULL; ///< Window of the last scroll event. /** List of windows opened at the screen sorted from the front. */ Window *_z_front_window = NULL; /** List of windows opened at the screen sorted from the back. */ Window *_z_back_window = NULL; /** If false, highlight is white, otherwise the by the widget defined colour. */ bool _window_highlight_colour = false; /* * Window that currently has focus. - The main purpose is to generate * #FocusLost events, not to give next window in z-order focus when a * window is closed. */ Window *_focused_window; Point _cursorpos_drag_start; int _scrollbar_start_pos; int _scrollbar_size; byte _scroller_click_timeout = 0; bool _scrolling_viewport; ///< A viewport is being scrolled with the mouse. bool _mouse_hovering; ///< The mouse is hovering over the same point. SpecialMouseMode _special_mouse_mode; ///< Mode of the mouse. /** * List of all WindowDescs. * This is a pointer to ensure initialisation order with the various static WindowDesc instances. */ static SmallVector *_window_descs = NULL; /** Config file to store WindowDesc */ char *_windows_file; /** Window description constructor. */ WindowDesc::WindowDesc(WindowPosition def_pos, const char *ini_key, int16 def_width_trad, int16 def_height_trad, WindowClass window_class, WindowClass parent_class, uint32 flags, const NWidgetPart *nwid_parts, int16 nwid_length, HotkeyList *hotkeys) : default_pos(def_pos), cls(window_class), parent_cls(parent_class), ini_key(ini_key), flags(flags), nwid_parts(nwid_parts), nwid_length(nwid_length), hotkeys(hotkeys), pref_sticky(false), pref_width(0), pref_height(0), default_width_trad(def_width_trad), default_height_trad(def_height_trad) { if (_window_descs == NULL) _window_descs = new SmallVector(); *_window_descs->Append() = this; } WindowDesc::~WindowDesc() { _window_descs->Erase(_window_descs->Find(this)); } /** * Determine default width of window. * This is either a stored user preferred size, or the build-in default. * @return Width in pixels. */ int16 WindowDesc::GetDefaultWidth() const { return this->pref_width != 0 ? this->pref_width : ScaleGUITrad(this->default_width_trad); } /** * Determine default height of window. * This is either a stored user preferred size, or the build-in default. * @return Height in pixels. */ int16 WindowDesc::GetDefaultHeight() const { return this->pref_height != 0 ? this->pref_height : ScaleGUITrad(this->default_height_trad); } /** * Load all WindowDesc settings from _windows_file. */ void WindowDesc::LoadFromConfig() { IniFile *ini = new IniFile(); ini->LoadFromDisk(_windows_file, BASE_DIR); for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { if ((*it)->ini_key == NULL) continue; IniLoadWindowSettings(ini, (*it)->ini_key, *it); } delete ini; } /** * Sort WindowDesc by ini_key. */ static int CDECL DescSorter(WindowDesc * const *a, WindowDesc * const *b) { if ((*a)->ini_key != NULL && (*b)->ini_key != NULL) return strcmp((*a)->ini_key, (*b)->ini_key); return ((*b)->ini_key != NULL ? 1 : 0) - ((*a)->ini_key != NULL ? 1 : 0); } /** * Save all WindowDesc settings to _windows_file. */ void WindowDesc::SaveToConfig() { /* Sort the stuff to get a nice ini file on first write */ QSortT(_window_descs->Begin(), _window_descs->Length(), DescSorter); IniFile *ini = new IniFile(); ini->LoadFromDisk(_windows_file, BASE_DIR); for (WindowDesc **it = _window_descs->Begin(); it != _window_descs->End(); ++it) { if ((*it)->ini_key == NULL) continue; IniSaveWindowSettings(ini, (*it)->ini_key, *it); } ini->SaveToDisk(_windows_file); delete ini; } /** * Read default values from WindowDesc configuration an apply them to the window. */ void Window::ApplyDefaults() { if (this->nested_root != NULL && this->nested_root->GetWidgetOfType(WWT_STICKYBOX) != NULL) { if (this->window_desc->pref_sticky) this->flags |= WF_STICKY; } else { /* There is no stickybox; clear the preference in case someone tried to be funny */ this->window_desc->pref_sticky = false; } } /** * Compute the row of a widget that a user clicked in. * @param clickpos Vertical position of the mouse click. * @param widget Widget number of the widget clicked in. * @param padding Amount of empty space between the widget edge and the top of the first row. * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. * @note The widget does not know where a list printed at the widget ends, so below a list is not a wrong position. */ int Window::GetRowFromWidget(int clickpos, int widget, int padding, int line_height) const { const NWidgetBase *wid = this->GetWidget(widget); if (line_height < 0) line_height = wid->resize_y; if (clickpos < (int)wid->pos_y + padding) return INT_MAX; return (clickpos - (int)wid->pos_y - padding) / line_height; } /** * Disable the highlighted status of all widgets. */ void Window::DisableAllWidgetHighlight() { for (uint i = 0; i < this->nested_array_size; i++) { NWidgetBase *nwid = this->GetWidget(i); if (nwid == NULL) continue; if (nwid->IsHighlighted()) { nwid->SetHighlighted(TC_INVALID); this->SetWidgetDirty(i); } } CLRBITS(this->flags, WF_HIGHLIGHTED); } /** * Sets the highlighted status of a widget. * @param widget_index index of this widget in the window * @param highlighted_colour Colour of highlight, or TC_INVALID to disable. */ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour) { assert(widget_index < this->nested_array_size); NWidgetBase *nwid = this->GetWidget(widget_index); if (nwid == NULL) return; nwid->SetHighlighted(highlighted_colour); this->SetWidgetDirty(widget_index); if (highlighted_colour != TC_INVALID) { /* If we set a highlight, the window has a highlight */ this->flags |= WF_HIGHLIGHTED; } else { /* If we disable a highlight, check all widgets if anyone still has a highlight */ bool valid = false; for (uint i = 0; i < this->nested_array_size; i++) { NWidgetBase *nwid = this->GetWidget(i); if (nwid == NULL) continue; if (!nwid->IsHighlighted()) continue; valid = true; } /* If nobody has a highlight, disable the flag on the window */ if (!valid) CLRBITS(this->flags, WF_HIGHLIGHTED); } } /** * Gets the highlighted status of a widget. * @param widget_index index of this widget in the window * @return status of the widget ie: highlighted = true, not highlighted = false */ bool Window::IsWidgetHighlighted(byte widget_index) const { assert(widget_index < this->nested_array_size); const NWidgetBase *nwid = this->GetWidget(widget_index); if (nwid == NULL) return false; return nwid->IsHighlighted(); } /** * A dropdown window associated to this window has been closed. * @param pt the point inside the window the mouse resides on after closure. * @param widget the widget (button) that the dropdown is associated with. * @param index the element in the dropdown that is selected. * @param instant_close whether the dropdown was configured to close on mouse up. */ void Window::OnDropdownClose(Point pt, int widget, int index, bool instant_close) { if (widget < 0) return; if (instant_close) { /* Send event for selected option if we're still * on the parent button of the dropdown (behaviour of the dropdowns in the main toolbar). */ if (GetWidgetFromPos(this, pt.x, pt.y) == widget) { this->OnDropdownSelect(widget, index); } } /* Raise the dropdown button */ NWidgetCore *nwi2 = this->GetWidget(widget); if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) { nwi2->disp_flags &= ~ND_DROPDOWN_ACTIVE; } else { this->RaiseWidget(widget); } this->SetWidgetDirty(widget); } /** * Return the Scrollbar to a widget index. * @param widnum Scrollbar widget index * @return Scrollbar to the widget */ const Scrollbar *Window::GetScrollbar(uint widnum) const { return this->GetWidget(widnum); } /** * Return the Scrollbar to a widget index. * @param widnum Scrollbar widget index * @return Scrollbar to the widget */ Scrollbar *Window::GetScrollbar(uint widnum) { return this->GetWidget(widnum); } /** * Return the querystring associated to a editbox. * @param widnum Editbox widget index * @return QueryString or NULL. */ const QueryString *Window::GetQueryString(uint widnum) const { const SmallMap::Pair *query = this->querystrings.Find(widnum); return query != this->querystrings.End() ? query->second : NULL; } /** * Return the querystring associated to a editbox. * @param widnum Editbox widget index * @return QueryString or NULL. */ QueryString *Window::GetQueryString(uint widnum) { SmallMap::Pair *query = this->querystrings.Find(widnum); return query != this->querystrings.End() ? query->second : NULL; } /** * Get the current input text if an edit box has the focus. * @return The currently focused input text or NULL if no input focused. */ /* virtual */ const char *Window::GetFocusedText() const { if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetText(); } return NULL; } /** * Get the string at the caret if an edit box has the focus. * @return The text at the caret or NULL if no edit box is focused. */ /* virtual */ const char *Window::GetCaret() const { if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetCaret(); } return NULL; } /** * Get the range of the currently marked input text. * @param[out] length Length of the marked text. * @return Pointer to the start of the marked text or NULL if no text is marked. */ /* virtual */ const char *Window::GetMarkedText(size_t *length) const { if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetMarkedText(length); } return NULL; } /** * Get the current caret position if an edit box has the focus. * @return Top-left location of the caret, relative to the window. */ /* virtual */ Point Window::GetCaretPosition() const { if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetCaretPosition(this, this->nested_focus->index); } Point pt = {0, 0}; return pt; } /** * Get the bounding rectangle for a text range if an edit box has the focus. * @param from Start of the string range. * @param to End of the string range. * @return Rectangle encompassing the string range, relative to the window. */ /* virtual */ Rect Window::GetTextBoundingRect(const char *from, const char *to) const { if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetBoundingRect(this, this->nested_focus->index, from, to); } Rect r = {0, 0, 0, 0}; return r; } /** * Get the character that is rendered at a position by the focused edit box. * @param pt The position to test. * @return Pointer to the character at the position or NULL if no character is at the position. */ /* virtual */ const char *Window::GetTextCharacterAtPosition(const Point &pt) const { if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) { return this->GetQueryString(this->nested_focus->index)->GetCharAtPosition(this, this->nested_focus->index, pt); } return NULL; } /** * Set the window that has the focus * @param w The window to set the focus on */ void SetFocusedWindow(Window *w) { if (_focused_window == w) return; /* Invalidate focused widget */ if (_focused_window != NULL) { if (_focused_window->nested_focus != NULL) _focused_window->nested_focus->SetDirty(_focused_window); } /* Remember which window was previously focused */ Window *old_focused = _focused_window; _focused_window = w; /* So we can inform it that it lost focus */ if (old_focused != NULL) old_focused->OnFocusLost(); if (_focused_window != NULL) _focused_window->OnFocus(); } /** * Check if an edit box is in global focus. That is if focused window * has a edit box as focused widget, or if a console is focused. * @return returns true if an edit box is in global focus or if the focused window is a console, else false */ bool EditBoxInGlobalFocus() { if (_focused_window == NULL) return false; /* The console does not have an edit box so a special case is needed. */ if (_focused_window->window_class == WC_CONSOLE) return true; return _focused_window->nested_focus != NULL && _focused_window->nested_focus->type == WWT_EDITBOX; } /** * Makes no widget on this window have focus. The function however doesn't change which window has focus. */ void Window::UnfocusFocusedWidget() { if (this->nested_focus != NULL) { if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ this->nested_focus->SetDirty(this); this->nested_focus = NULL; } } /** * Set focus within this window to the given widget. The function however doesn't change which window has focus. * @param widget_index Index of the widget in the window to set the focus to. * @return Focus has changed. */ bool Window::SetFocusedWidget(int widget_index) { /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ if ((uint)widget_index >= this->nested_array_size) return false; assert(this->nested_array[widget_index] != NULL); // Setting focus to a non-existing widget is a bad idea. if (this->nested_focus != NULL) { if (this->GetWidget(widget_index) == this->nested_focus) return false; /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ this->nested_focus->SetDirty(this); if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); } this->nested_focus = this->GetWidget(widget_index); return true; } /** * Called when window looses focus */ void Window::OnFocusLost() { if (this->nested_focus != NULL && this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); } /** * Sets the enabled/disabled status of a list of widgets. * By default, widgets are enabled. * On certain conditions, they have to be disabled. * @param disab_stat status to use ie: disabled = true, enabled = false * @param widgets list of widgets ended by WIDGET_LIST_END */ void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...) { va_list wdg_list; va_start(wdg_list, widgets); while (widgets != WIDGET_LIST_END) { SetWidgetDisabledState(widgets, disab_stat); widgets = va_arg(wdg_list, int); } va_end(wdg_list); } /** * Sets the lowered/raised status of a list of widgets. * @param lowered_stat status to use ie: lowered = true, raised = false * @param widgets list of widgets ended by WIDGET_LIST_END */ void CDECL Window::SetWidgetsLoweredState(bool lowered_stat, int widgets, ...) { va_list wdg_list; va_start(wdg_list, widgets); while (widgets != WIDGET_LIST_END) { SetWidgetLoweredState(widgets, lowered_stat); widgets = va_arg(wdg_list, int); } va_end(wdg_list); } /** * Raise the buttons of the window. * @param autoraise Raise only the push buttons of the window. */ void Window::RaiseButtons(bool autoraise) { for (uint i = 0; i < this->nested_array_size; i++) { if (this->nested_array[i] == NULL) continue; WidgetType type = this->nested_array[i]->type; if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { this->RaiseWidget(i); this->SetWidgetDirty(i); } } /* Special widgets without widget index */ NWidgetCore *wid = this->nested_root != NULL ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : NULL; if (wid != NULL) { wid->SetLowered(false); wid->SetDirty(this); } } /** * Invalidate a widget, i.e. mark it as being changed and in need of redraw. * @param widget_index the widget to redraw. */ void Window::SetWidgetDirty(byte widget_index) const { /* Sometimes this function is called before the window is even fully initialized */ if (this->nested_array == NULL) return; this->nested_array[widget_index]->SetDirty(this); } /** * A hotkey has been pressed. * @param hotkey Hotkey index, by default a widget index of a button or editbox. * @return #ES_HANDLED if the key press has been handled, and the hotkey is not unavailable for some reason. */ EventState Window::OnHotkey(int hotkey) { if (hotkey < 0) return ES_NOT_HANDLED; NWidgetCore *nw = this->GetWidget(hotkey); if (nw == NULL || nw->IsDisabled()) return ES_NOT_HANDLED; if (nw->type == WWT_EDITBOX) { if (this->IsShaded()) return ES_NOT_HANDLED; /* Focus editbox */ this->SetFocusedWidget(hotkey); SetFocusedWindow(this); } else { /* Click button */ this->OnClick(Point(), hotkey, 1); } return ES_HANDLED; } /** * Do all things to make a button look clicked and mark it to be * unclicked in a few ticks. * @param widget the widget to "click" */ void Window::HandleButtonClick(byte widget) { this->LowerWidget(widget); this->SetTimeout(); this->SetWidgetDirty(widget); } static void StartWindowDrag(Window *w); static void StartWindowSizing(Window *w, bool to_left); /** * Dispatch left mouse-button (possibly double) click in window. * @param w Window to dispatch event in * @param x X coordinate of the click * @param y Y coordinate of the click * @param click_count Number of fast consecutive clicks at same position */ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count) { NWidgetCore *nw = w->nested_root->GetWidgetFromPos(x, y); WidgetType widget_type = (nw != NULL) ? nw->type : WWT_EMPTY; bool focused_widget_changed = false; /* If clicked on a window that previously did dot have focus */ if (_focused_window != w && // We already have focus, right? (w->window_desc->flags & WDF_NO_FOCUS) == 0 && // Don't lose focus to toolbars widget_type != WWT_CLOSEBOX) { // Don't change focused window if 'X' (close button) was clicked focused_widget_changed = true; SetFocusedWindow(w); } if (nw == NULL) return; // exit if clicked outside of widgets /* don't allow any interaction if the button has been disabled */ if (nw->IsDisabled()) return; int widget_index = nw->index; ///< Index of the widget /* Clicked on a widget that is not disabled. * So unless the clicked widget is the caption bar, change focus to this widget. * Exception: In the OSK we always want the editbox to stay focussed. */ if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) { /* focused_widget_changed is 'now' only true if the window this widget * is in gained focus. In that case it must remain true, also if the * local widget focus did not change. As such it's the logical-or of * both changed states. * * If this is not preserved, then the OSK window would be opened when * a user has the edit box focused and then click on another window and * then back again on the edit box (to type some text). */ focused_widget_changed |= w->SetFocusedWidget(widget_index); } /* Close any child drop down menus. If the button pressed was the drop down * list's own button, then we should not process the click any further. */ if (HideDropDownMenu(w) == widget_index && widget_index >= 0) return; if ((widget_type & ~WWB_PUSHBUTTON) < WWT_LAST && (widget_type & WWB_PUSHBUTTON)) w->HandleButtonClick(widget_index); Point pt = { x, y }; switch (widget_type) { case NWID_VSCROLLBAR: case NWID_HSCROLLBAR: ScrollbarClickHandler(w, nw, x, y); break; case WWT_EDITBOX: { QueryString *query = w->GetQueryString(widget_index); if (query != NULL) query->ClickEditBox(w, pt, widget_index, click_count, focused_widget_changed); break; } case WWT_CLOSEBOX: // 'X' delete w; return; case WWT_CAPTION: // 'Title bar' StartWindowDrag(w); return; case WWT_RESIZEBOX: /* When the resize widget is on the left size of the window * we assume that that button is used to resize to the left. */ StartWindowSizing(w, (int)nw->pos_x < (w->width / 2)); nw->SetDirty(w); return; case WWT_DEFSIZEBOX: { if (_ctrl_pressed) { w->window_desc->pref_width = w->width; w->window_desc->pref_height = w->height; } else { int16 def_width = max(min(w->window_desc->GetDefaultWidth(), _screen.width), w->nested_root->smallest_x); int16 def_height = max(min(w->window_desc->GetDefaultHeight(), _screen.height - 50), w->nested_root->smallest_y); int dx = (w->resize.step_width == 0) ? 0 : def_width - w->width; int dy = (w->resize.step_height == 0) ? 0 : def_height - w->height; /* dx and dy has to go by step.. calculate it. * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ if (w->resize.step_width > 1) dx -= dx % (int)w->resize.step_width; if (w->resize.step_height > 1) dy -= dy % (int)w->resize.step_height; ResizeWindow(w, dx, dy, false); } nw->SetLowered(true); nw->SetDirty(w); w->SetTimeout(); break; } case WWT_DEBUGBOX: w->ShowNewGRFInspectWindow(); break; case WWT_SHADEBOX: nw->SetDirty(w); w->SetShaded(!w->IsShaded()); return; case WWT_STICKYBOX: w->flags ^= WF_STICKY; nw->SetDirty(w); if (_ctrl_pressed) w->window_desc->pref_sticky = (w->flags & WF_STICKY) != 0; return; default: break; } /* Widget has no index, so the window is not interested in it. */ if (widget_index < 0) return; /* Check if the widget is highlighted; if so, disable highlight and dispatch an event to the GameScript */ if (w->IsWidgetHighlighted(widget_index)) { w->SetWidgetHighlight(widget_index, TC_INVALID); Game::NewEvent(new ScriptEventWindowWidgetClick((ScriptWindow::WindowClass)w->window_class, w->window_number, widget_index)); } w->OnClick(pt, widget_index, click_count); } /** * Dispatch right mouse-button click in window. * @param w Window to dispatch event in * @param x X coordinate of the click * @param y Y coordinate of the click */ static void DispatchRightClickEvent(Window *w, int x, int y) { NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); if (wid == NULL) return; /* No widget to handle, or the window is not interested in it. */ if (wid->index >= 0) { Point pt = { x, y }; if (w->OnRightClick(pt, wid->index)) return; } if (_settings_client.gui.hover_delay_ms == 0 && wid->tool_tip != 0) GuiShowTooltips(w, wid->tool_tip, 0, NULL, TCC_RIGHT_CLICK); } /** * Dispatch hover of the mouse over a window. * @param w Window to dispatch event in. * @param x X coordinate of the click. * @param y Y coordinate of the click. */ static void DispatchHoverEvent(Window *w, int x, int y) { NWidgetCore *wid = w->nested_root->GetWidgetFromPos(x, y); /* No widget to handle */ if (wid == NULL) return; /* Show the tooltip if there is any */ if (wid->tool_tip != 0) { GuiShowTooltips(w, wid->tool_tip); return; } /* Widget has no index, so the window is not interested in it. */ if (wid->index < 0) return; Point pt = { x, y }; w->OnHover(pt, wid->index); } /** * Dispatch the mousewheel-action to the window. * The window will scroll any compatible scrollbars if the mouse is pointed over the bar or its contents * @param w Window * @param nwid the widget where the scrollwheel was used * @param wheel scroll up or down */ static void DispatchMouseWheelEvent(Window *w, NWidgetCore *nwid, int wheel) { if (nwid == NULL) return; /* Using wheel on caption/shade-box shades or unshades the window. */ if (nwid->type == WWT_CAPTION || nwid->type == WWT_SHADEBOX) { w->SetShaded(wheel < 0); return; } /* Wheeling a vertical scrollbar. */ if (nwid->type == NWID_VSCROLLBAR) { NWidgetScrollbar *sb = static_cast(nwid); if (sb->GetCount() > sb->GetCapacity()) { sb->UpdatePosition(wheel); w->SetDirty(); } return; } /* Scroll the widget attached to the scrollbar. */ Scrollbar *sb = (nwid->scrollbar_index >= 0 ? w->GetScrollbar(nwid->scrollbar_index) : NULL); if (sb != NULL && sb->GetCount() > sb->GetCapacity()) { sb->UpdatePosition(wheel); w->SetDirty(); } } /** * Returns whether a window may be shown or not. * @param w The window to consider. * @return True iff it may be shown, otherwise false. */ static bool MayBeShown(const Window *w) { /* If we're not modal, everything is okay. */ if (!HasModalProgress()) return true; switch (w->window_class) { case WC_MAIN_WINDOW: ///< The background, i.e. the game. case WC_MODAL_PROGRESS: ///< The actual progress window. case WC_CONFIRM_POPUP_QUERY: ///< The abort window. return true; default: return false; } } /** * Generate repaint events for the visible part of window w within the rectangle. * * The function goes recursively upwards in the window stack, and splits the rectangle * into multiple pieces at the window edges, so obscured parts are not redrawn. * * @param w Window that needs to be repainted * @param left Left edge of the rectangle that should be repainted * @param top Top edge of the rectangle that should be repainted * @param right Right edge of the rectangle that should be repainted * @param bottom Bottom edge of the rectangle that should be repainted */ static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) { const Window *v; FOR_ALL_WINDOWS_FROM_BACK_FROM(v, w->z_front) { if (MayBeShown(v) && right > v->left && bottom > v->top && left < v->left + v->width && top < v->top + v->height) { /* v and rectangle intersect with each other */ int x; if (left < (x = v->left)) { DrawOverlappedWindow(w, left, top, x, bottom); DrawOverlappedWindow(w, x, top, right, bottom); return; } if (right > (x = v->left + v->width)) { DrawOverlappedWindow(w, left, top, x, bottom); DrawOverlappedWindow(w, x, top, right, bottom); return; } if (top < (x = v->top)) { DrawOverlappedWindow(w, left, top, right, x); DrawOverlappedWindow(w, left, x, right, bottom); return; } if (bottom > (x = v->top + v->height)) { DrawOverlappedWindow(w, left, top, right, x); DrawOverlappedWindow(w, left, x, right, bottom); return; } return; } } /* Setup blitter, and dispatch a repaint event to window *wz */ DrawPixelInfo *dp = _cur_dpi; dp->width = right - left; dp->height = bottom - top; dp->left = left - w->left; dp->top = top - w->top; dp->pitch = _screen.pitch; dp->dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(_screen.dst_ptr, left, top); dp->zoom = ZOOM_LVL_NORMAL; w->OnPaint(); } /** * From a rectangle that needs redrawing, find the windows that intersect with the rectangle. * These windows should be re-painted. * @param left Left edge of the rectangle that should be repainted * @param top Top edge of the rectangle that should be repainted * @param right Right edge of the rectangle that should be repainted * @param bottom Bottom edge of the rectangle that should be repainted */ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) { Window *w; DrawPixelInfo bk; _cur_dpi = &bk; FOR_ALL_WINDOWS_FROM_BACK(w) { if (MayBeShown(w) && right > w->left && bottom > w->top && left < w->left + w->width && top < w->top + w->height) { /* Window w intersects with the rectangle => needs repaint */ DrawOverlappedWindow(w, left, top, right, bottom); } } } /** * Mark entire window as dirty (in need of re-paint) * @ingroup dirty */ void Window::SetDirty() const { SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height); } /** * Re-initialize a window, and optionally change its size. * @param rx Horizontal resize of the window. * @param ry Vertical resize of the window. * @note For just resizing the window, use #ResizeWindow instead. */ void Window::ReInit(int rx, int ry) { this->SetDirty(); // Mark whole current window as dirty. /* Save current size. */ int window_width = this->width; int window_height = this->height; this->OnInit(); /* Re-initialize the window from the ground up. No need to change the nested_array, as all widgets stay where they are. */ this->nested_root->SetupSmallestSize(this, false); this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); this->width = this->nested_root->smallest_x; this->height = this->nested_root->smallest_y; this->resize.step_width = this->nested_root->resize_x; this->resize.step_height = this->nested_root->resize_y; /* Resize as close to the original size + requested resize as possible. */ window_width = max(window_width + rx, this->width); window_height = max(window_height + ry, this->height); int dx = (this->resize.step_width == 0) ? 0 : window_width - this->width; int dy = (this->resize.step_height == 0) ? 0 : window_height - this->height; /* dx and dy has to go by step.. calculate it. * The cast to int is necessary else dx/dy are implicitly casted to unsigned int, which won't work. */ if (this->resize.step_width > 1) dx -= dx % (int)this->resize.step_width; if (this->resize.step_height > 1) dy -= dy % (int)this->resize.step_height; ResizeWindow(this, dx, dy); /* ResizeWindow() does this->SetDirty() already, no need to do it again here. */ } /** * Set the shaded state of the window to \a make_shaded. * @param make_shaded If \c true, shade the window (roll up until just the title bar is visible), else unshade/unroll the window to its original size. * @note The method uses #Window::ReInit(), thus after the call, the whole window should be considered changed. */ void Window::SetShaded(bool make_shaded) { if (this->shade_select == NULL) return; int desired = make_shaded ? SZSP_HORIZONTAL : 0; if (this->shade_select->shown_plane != desired) { if (make_shaded) { if (this->nested_focus != NULL) this->UnfocusFocusedWidget(); this->unshaded_size.width = this->width; this->unshaded_size.height = this->height; this->shade_select->SetDisplayedPlane(desired); this->ReInit(0, -this->height); } else { this->shade_select->SetDisplayedPlane(desired); int dx = ((int)this->unshaded_size.width > this->width) ? (int)this->unshaded_size.width - this->width : 0; int dy = ((int)this->unshaded_size.height > this->height) ? (int)this->unshaded_size.height - this->height : 0; this->ReInit(dx, dy); } } } /** * Find the Window whose parent pointer points to this window * @param w parent Window to find child of * @param wc Window class of the window to remove; #WC_INVALID if class does not matter * @return a Window pointer that is the child of \a w, or \c NULL otherwise */ static Window *FindChildWindow(const Window *w, WindowClass wc) { Window *v; FOR_ALL_WINDOWS_FROM_BACK(v) { if ((wc == WC_INVALID || wc == v->window_class) && v->parent == w) return v; } return NULL; } /** * Delete all children a window might have in a head-recursive manner * @param wc Window class of the window to remove; #WC_INVALID if class does not matter */ void Window::DeleteChildWindows(WindowClass wc) const { Window *child = FindChildWindow(this, wc); while (child != NULL) { delete child; child = FindChildWindow(this, wc); } } /** * Remove window and all its child windows from the window stack. */ Window::~Window() { if (_thd.window_class == this->window_class && _thd.window_number == this->window_number) { ResetObjectToPlace(); } /* Prevent Mouseover() from resetting mouse-over coordinates on a non-existing window */ if (_mouseover_last_w == this) _mouseover_last_w = NULL; /* We can't scroll the window when it's closed. */ if (_last_scroll_window == this) _last_scroll_window = NULL; /* Make sure we don't try to access this window as the focused window when it doesn't exist anymore. */ if (_focused_window == this) { this->OnFocusLost(); _focused_window = NULL; } this->DeleteChildWindows(); if (this->viewport != NULL) DeleteWindowViewport(this); this->SetDirty(); free(this->nested_array); // Contents is released through deletion of #nested_root. delete this->nested_root; /* * Make fairly sure that this is written, and not "optimized" away. * The delete operator is overwritten to not delete it; the deletion * happens at a later moment in time after the window has been * removed from the list of windows to prevent issues with items * being removed during the iteration as not one but more windows * may be removed by a single call to ~Window by means of the * DeleteChildWindows function. */ const_cast(this->window_class) = WC_INVALID; } /** * Find a window by its class and window number * @param cls Window class * @param number Number of the window within the window class * @return Pointer to the found window, or \c NULL if not available */ Window *FindWindowById(WindowClass cls, WindowNumber number) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls && w->window_number == number) return w; } return NULL; } /** * Find any window by its class. Useful when searching for a window that uses * the window number as a #WindowType, like #WC_SEND_NETWORK_MSG. * @param cls Window class * @return Pointer to the found window, or \c NULL if not available */ Window *FindWindowByClass(WindowClass cls) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls) return w; } return NULL; } /** * Delete a window by its class and window number (if it is open). * @param cls Window class * @param number Number of the window within the window class * @param force force deletion; if false don't delete when stickied */ void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) { Window *w = FindWindowById(cls, number); if (force || w == NULL || (w->flags & WF_STICKY) == 0) { delete w; } } /** * Delete all windows of a given class * @param cls Window class of windows to delete */ void DeleteWindowByClass(WindowClass cls) { Window *w; restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls) { delete w; goto restart_search; } } } /** * Delete all windows of a company. We identify windows of a company * by looking at the caption colour. If it is equal to the company ID * then we say the window belongs to the company and should be deleted * @param id company identifier */ void DeleteCompanyWindows(CompanyID id) { Window *w; restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->owner == id) { delete w; goto restart_search; } } /* Also delete the company specific windows that don't have a company-colour. */ DeleteWindowById(WC_BUY_COMPANY, id); } /** * Change the owner of all the windows one company can take over from another * company in the case of a company merger. Do not change ownership of windows * that need to be deleted once takeover is complete * @param old_owner original owner of the window * @param new_owner the new owner of the window */ void ChangeWindowOwner(Owner old_owner, Owner new_owner) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->owner != old_owner) continue; switch (w->window_class) { case WC_COMPANY_COLOUR: case WC_FINANCES: case WC_STATION_LIST: case WC_TRAINS_LIST: case WC_ROADVEH_LIST: case WC_SHIPS_LIST: case WC_AIRCRAFT_LIST: case WC_BUY_COMPANY: case WC_COMPANY: case WC_COMPANY_INFRASTRUCTURE: case WC_VEHICLE_ORDERS: // Changing owner would also require changing WindowDesc, which is not possible; however keeping the old one crashes because of missing widgets etc.. See ShowOrdersWindow(). continue; default: w->owner = new_owner; break; } } } static void BringWindowToFront(Window *w); /** * Find a window and make it the relative top-window on the screen. * The window gets unshaded if it was shaded, and a white border is drawn at its edges for a brief period of time to visualize its "activation". * @param cls WindowClass of the window to activate * @param number WindowNumber of the window to activate * @return a pointer to the window thus activated */ Window *BringWindowToFrontById(WindowClass cls, WindowNumber number) { Window *w = FindWindowById(cls, number); if (w != NULL) { if (w->IsShaded()) w->SetShaded(false); // Restore original window size if it was shaded. w->SetWhiteBorder(); BringWindowToFront(w); w->SetDirty(); } return w; } static inline bool IsVitalWindow(const Window *w) { switch (w->window_class) { case WC_MAIN_TOOLBAR: case WC_STATUS_BAR: case WC_NEWS_WINDOW: case WC_SEND_NETWORK_MSG: return true; default: return false; } } /** * Get the z-priority for a given window. This is used in comparison with other z-priority values; * a window with a given z-priority will appear above other windows with a lower value, and below * those with a higher one (the ordering within z-priorities is arbitrary). * @param w The window to get the z-priority for * @pre w->window_class != WC_INVALID * @return The window's z-priority */ static uint GetWindowZPriority(const Window *w) { assert(w->window_class != WC_INVALID); uint z_priority = 0; switch (w->window_class) { case WC_ENDSCREEN: ++z_priority; case WC_HIGHSCORE: ++z_priority; case WC_TOOLTIPS: ++z_priority; case WC_DROPDOWN_MENU: ++z_priority; case WC_MAIN_TOOLBAR: case WC_STATUS_BAR: ++z_priority; case WC_OSK: ++z_priority; case WC_QUERY_STRING: case WC_SEND_NETWORK_MSG: ++z_priority; case WC_ERRMSG: case WC_CONFIRM_POPUP_QUERY: case WC_MODAL_PROGRESS: case WC_NETWORK_STATUS_WINDOW: case WC_SAVE_PRESET: ++z_priority; case WC_GENERATE_LANDSCAPE: case WC_SAVELOAD: case WC_GAME_OPTIONS: case WC_CUSTOM_CURRENCY: case WC_NETWORK_WINDOW: case WC_GRF_PARAMETERS: case WC_AI_LIST: case WC_AI_SETTINGS: case WC_TEXTFILE: ++z_priority; case WC_CONSOLE: ++z_priority; case WC_NEWS_WINDOW: ++z_priority; default: ++z_priority; case WC_MAIN_WINDOW: return z_priority; } } /** * Adds a window to the z-ordering, according to its z-priority. * @param w Window to add */ static void AddWindowToZOrdering(Window *w) { assert(w->z_front == NULL && w->z_back == NULL); if (_z_front_window == NULL) { /* It's the only window. */ _z_front_window = _z_back_window = w; w->z_front = w->z_back = NULL; } else { /* Search down the z-ordering for its location. */ Window *v = _z_front_window; uint last_z_priority = UINT_MAX; while (v != NULL && (v->window_class == WC_INVALID || GetWindowZPriority(v) > GetWindowZPriority(w))) { if (v->window_class != WC_INVALID) { /* Sanity check z-ordering, while we're at it. */ assert(last_z_priority >= GetWindowZPriority(v)); last_z_priority = GetWindowZPriority(v); } v = v->z_back; } if (v == NULL) { /* It's the new back window. */ w->z_front = _z_back_window; w->z_back = NULL; _z_back_window->z_back = w; _z_back_window = w; } else if (v == _z_front_window) { /* It's the new front window. */ w->z_front = NULL; w->z_back = _z_front_window; _z_front_window->z_front = w; _z_front_window = w; } else { /* It's somewhere else in the z-ordering. */ w->z_front = v->z_front; w->z_back = v; v->z_front->z_back = w; v->z_front = w; } } } /** * Removes a window from the z-ordering. * @param w Window to remove */ static void RemoveWindowFromZOrdering(Window *w) { if (w->z_front == NULL) { assert(_z_front_window == w); _z_front_window = w->z_back; } else { w->z_front->z_back = w->z_back; } if (w->z_back == NULL) { assert(_z_back_window == w); _z_back_window = w->z_front; } else { w->z_back->z_front = w->z_front; } w->z_front = w->z_back = NULL; } /** * On clicking on a window, make it the frontmost window of all windows with an equal * or lower z-priority. The window is marked dirty for a repaint * @param w window that is put into the relative foreground */ static void BringWindowToFront(Window *w) { RemoveWindowFromZOrdering(w); AddWindowToZOrdering(w); w->SetDirty(); } /** * Initializes the data (except the position and initial size) of a new Window. * @param desc Window description. * @param window_number Number being assigned to the new window * @return Window pointer of the newly created window * @pre If nested widgets are used (\a widget is \c NULL), #nested_root and #nested_array_size must be initialized. * In addition, #nested_array is either \c NULL, or already initialized. */ void Window::InitializeData(WindowNumber window_number) { /* Set up window properties; some of them are needed to set up smallest size below */ this->window_class = this->window_desc->cls; this->SetWhiteBorder(); if (this->window_desc->default_pos == WDP_CENTER) this->flags |= WF_CENTERED; this->owner = INVALID_OWNER; this->nested_focus = NULL; this->window_number = window_number; this->OnInit(); /* Initialize nested widget tree. */ if (this->nested_array == NULL) { this->nested_array = CallocT(this->nested_array_size); this->nested_root->SetupSmallestSize(this, true); } else { this->nested_root->SetupSmallestSize(this, false); } /* Initialize to smallest size. */ this->nested_root->AssignSizePosition(ST_SMALLEST, 0, 0, this->nested_root->smallest_x, this->nested_root->smallest_y, _current_text_dir == TD_RTL); /* Further set up window properties, * this->left, this->top, this->width, this->height, this->resize.width, and this->resize.height are initialized later. */ this->resize.step_width = this->nested_root->resize_x; this->resize.step_height = this->nested_root->resize_y; /* Give focus to the opened window unless a text box * of focused window has focus (so we don't interrupt typing). But if the new * window has a text box, then take focus anyway. */ if (!EditBoxInGlobalFocus() || this->nested_root->GetWidgetOfType(WWT_EDITBOX) != NULL) SetFocusedWindow(this); /* Insert the window into the correct location in the z-ordering. */ AddWindowToZOrdering(this); } /** * Set the position and smallest size of the window. * @param x Offset in pixels from the left of the screen of the new window. * @param y Offset in pixels from the top of the screen of the new window. * @param sm_width Smallest width in pixels of the window. * @param sm_height Smallest height in pixels of the window. */ void Window::InitializePositionSize(int x, int y, int sm_width, int sm_height) { this->left = x; this->top = y; this->width = sm_width; this->height = sm_height; } /** * Resize window towards the default size. * Prior to construction, a position for the new window (for its default size) * has been found with LocalGetWindowPlacement(). Initially, the window is * constructed with minimal size. Resizing the window to its default size is * done here. * @param def_width default width in pixels of the window * @param def_height default height in pixels of the window * @see Window::Window(), Window::InitializeData(), Window::InitializePositionSize() */ void Window::FindWindowPlacementAndResize(int def_width, int def_height) { def_width = max(def_width, this->width); // Don't allow default size to be smaller than smallest size def_height = max(def_height, this->height); /* Try to make windows smaller when our window is too small. * w->(width|height) is normally the same as min_(width|height), * but this way the GUIs can be made a little more dynamic; * one can use the same spec for multiple windows and those * can then determine the real minimum size of the window. */ if (this->width != def_width || this->height != def_height) { /* Think about the overlapping toolbars when determining the minimum window size */ int free_height = _screen.height; const Window *wt = FindWindowById(WC_STATUS_BAR, 0); if (wt != NULL) free_height -= wt->height; wt = FindWindowById(WC_MAIN_TOOLBAR, 0); if (wt != NULL) free_height -= wt->height; int enlarge_x = max(min(def_width - this->width, _screen.width - this->width), 0); int enlarge_y = max(min(def_height - this->height, free_height - this->height), 0); /* X and Y has to go by step.. calculate it. * The cast to int is necessary else x/y are implicitly casted to * unsigned int, which won't work. */ if (this->resize.step_width > 1) enlarge_x -= enlarge_x % (int)this->resize.step_width; if (this->resize.step_height > 1) enlarge_y -= enlarge_y % (int)this->resize.step_height; ResizeWindow(this, enlarge_x, enlarge_y); /* ResizeWindow() calls this->OnResize(). */ } else { /* Always call OnResize; that way the scrollbars and matrices get initialized. */ this->OnResize(); } int nx = this->left; int ny = this->top; if (nx + this->width > _screen.width) nx -= (nx + this->width - _screen.width); const Window *wt = FindWindowById(WC_MAIN_TOOLBAR, 0); ny = max(ny, (wt == NULL || this == wt || this->top == 0) ? 0 : wt->height); nx = max(nx, 0); if (this->viewport != NULL) { this->viewport->left += nx - this->left; this->viewport->top += ny - this->top; } this->left = nx; this->top = ny; this->SetDirty(); } /** * Decide whether a given rectangle is a good place to open a completely visible new window. * The new window should be within screen borders, and not overlap with another already * existing window (except for the main window in the background). * @param left Left edge of the rectangle * @param top Top edge of the rectangle * @param width Width of the rectangle * @param height Height of the rectangle * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window * @return Boolean indication that the rectangle is a good place for the new window */ static bool IsGoodAutoPlace1(int left, int top, int width, int height, Point &pos) { int right = width + left; int bottom = height + top; const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); if (left < 0 || (main_toolbar != NULL && top < main_toolbar->height) || right > _screen.width || bottom > _screen.height) return false; /* Make sure it is not obscured by any window. */ const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == WC_MAIN_WINDOW) continue; if (right > w->left && w->left + w->width > left && bottom > w->top && w->top + w->height > top) { return false; } } pos.x = left; pos.y = top; return true; } /** * Decide whether a given rectangle is a good place to open a mostly visible new window. * The new window should be mostly within screen borders, and not overlap with another already * existing window (except for the main window in the background). * @param left Left edge of the rectangle * @param top Top edge of the rectangle * @param width Width of the rectangle * @param height Height of the rectangle * @param pos If rectangle is good, use this parameter to return the top-left corner of the new window * @return Boolean indication that the rectangle is a good place for the new window */ static bool IsGoodAutoPlace2(int left, int top, int width, int height, Point &pos) { /* Left part of the rectangle may be at most 1/4 off-screen, * right part of the rectangle may be at most 1/2 off-screen */ if (left < -(width >> 2) || left > _screen.width - (width >> 1)) return false; /* Bottom part of the rectangle may be at most 1/4 off-screen */ if (top < 22 || top > _screen.height - (height >> 2)) return false; /* Make sure it is not obscured by any window. */ const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == WC_MAIN_WINDOW) continue; if (left + width > w->left && w->left + w->width > left && top + height > w->top && w->top + w->height > top) { return false; } } pos.x = left; pos.y = top; return true; } /** * Find a good place for opening a new window of a given width and height. * @param width Width of the new window * @param height Height of the new window * @return Top-left coordinate of the new window */ static Point GetAutoPlacePosition(int width, int height) { Point pt; /* First attempt, try top-left of the screen */ const Window *main_toolbar = FindWindowByClass(WC_MAIN_TOOLBAR); if (IsGoodAutoPlace1(0, main_toolbar != NULL ? main_toolbar->height + 2 : 2, width, height, pt)) return pt; /* Second attempt, try around all existing windows with a distance of 2 pixels. * The new window must be entirely on-screen, and not overlap with an existing window. * Eight starting points are tried, two at each corner. */ const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == WC_MAIN_WINDOW) continue; if (IsGoodAutoPlace1(w->left + w->width + 2, w->top, width, height, pt)) return pt; if (IsGoodAutoPlace1(w->left - width - 2, w->top, width, height, pt)) return pt; if (IsGoodAutoPlace1(w->left, w->top + w->height + 2, width, height, pt)) return pt; if (IsGoodAutoPlace1(w->left, w->top - height - 2, width, height, pt)) return pt; if (IsGoodAutoPlace1(w->left + w->width + 2, w->top + w->height - height, width, height, pt)) return pt; if (IsGoodAutoPlace1(w->left - width - 2, w->top + w->height - height, width, height, pt)) return pt; if (IsGoodAutoPlace1(w->left + w->width - width, w->top + w->height + 2, width, height, pt)) return pt; if (IsGoodAutoPlace1(w->left + w->width - width, w->top - height - 2, width, height, pt)) return pt; } /* Third attempt, try around all existing windows with a distance of 2 pixels. * The new window may be partly off-screen, and must not overlap with an existing window. * Only four starting points are tried. */ FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == WC_MAIN_WINDOW) continue; if (IsGoodAutoPlace2(w->left + w->width + 2, w->top, width, height, pt)) return pt; if (IsGoodAutoPlace2(w->left - width - 2, w->top, width, height, pt)) return pt; if (IsGoodAutoPlace2(w->left, w->top + w->height + 2, width, height, pt)) return pt; if (IsGoodAutoPlace2(w->left, w->top - height - 2, width, height, pt)) return pt; } /* Fourth and final attempt, put window at diagonal starting from (0, 24), try multiples * of (+5, +5) */ int left = 0, top = 24; restart: FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->left == left && w->top == top) { left += 5; top += 5; goto restart; } } pt.x = left; pt.y = top; return pt; } /** * Computer the position of the top-left corner of a window to be opened right * under the toolbar. * @param window_width the width of the window to get the position for * @return Coordinate of the top-left corner of the new window. */ Point GetToolbarAlignedWindowPosition(int window_width) { const Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); assert(w != NULL); Point pt = { _current_text_dir == TD_RTL ? w->left : (w->left + w->width) - window_width, w->top + w->height }; return pt; } /** * Compute the position of the top-left corner of a new window that is opened. * * By default position a child window at an offset of 10/10 of its parent. * With the exception of WC_BUILD_TOOLBAR (build railway/roads/ship docks/airports) * and WC_SCEN_LAND_GEN (landscaping). Whose child window has an offset of 0/toolbar-height of * its parent. So it's exactly under the parent toolbar and no buttons will be covered. * However if it falls too extremely outside window positions, reposition * it to an automatic place. * * @param *desc The pointer to the WindowDesc to be created. * @param sm_width Smallest width of the window. * @param sm_height Smallest height of the window. * @param window_number The window number of the new window. * * @return Coordinate of the top-left corner of the new window. */ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number) { Point pt; const Window *w; int16 default_width = max(desc->GetDefaultWidth(), sm_width); int16 default_height = max(desc->GetDefaultHeight(), sm_height); if (desc->parent_cls != 0 /* WC_MAIN_WINDOW */ && (w = FindWindowById(desc->parent_cls, window_number)) != NULL && w->left < _screen.width - 20 && w->left > -60 && w->top < _screen.height - 20) { pt.x = w->left + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? 0 : 10); if (pt.x > _screen.width + 10 - default_width) { pt.x = (_screen.width + 10 - default_width) - 20; } pt.y = w->top + ((desc->parent_cls == WC_BUILD_TOOLBAR || desc->parent_cls == WC_SCEN_LAND_GEN) ? w->height : 10); return pt; } switch (desc->default_pos) { case WDP_ALIGN_TOOLBAR: // Align to the toolbar return GetToolbarAlignedWindowPosition(default_width); case WDP_AUTO: // Find a good automatic position for the window return GetAutoPlacePosition(default_width, default_height); case WDP_CENTER: // Centre the window horizontally pt.x = (_screen.width - default_width) / 2; pt.y = (_screen.height - default_height) / 2; break; case WDP_MANUAL: pt.x = 0; pt.y = 0; break; default: NOT_REACHED(); } return pt; } /* virtual */ Point Window::OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { return LocalGetWindowPlacement(this->window_desc, sm_width, sm_height, window_number); } /** * Perform the first part of the initialization of a nested widget tree. * Construct a nested widget tree in #nested_root, and optionally fill the #nested_array array to provide quick access to the uninitialized widgets. * This is mainly useful for setting very basic properties. * @param fill_nested Fill the #nested_array (enabling is expensive!). * @note Filling the nested array requires an additional traversal through the nested widget tree, and is best performed by #FinishInitNested rather than here. */ void Window::CreateNestedTree(bool fill_nested) { int biggest_index = -1; this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_parts, this->window_desc->nwid_length, &biggest_index, &this->shade_select); this->nested_array_size = (uint)(biggest_index + 1); if (fill_nested) { this->nested_array = CallocT(this->nested_array_size); this->nested_root->FillNestedArray(this->nested_array, this->nested_array_size); } } /** * Perform the second part of the initialization of a nested widget tree. * @param window_number Number of the new window. */ void Window::FinishInitNested(WindowNumber window_number) { this->InitializeData(window_number); this->ApplyDefaults(); Point pt = this->OnInitialPosition(this->nested_root->smallest_x, this->nested_root->smallest_y, window_number); this->InitializePositionSize(pt.x, pt.y, this->nested_root->smallest_x, this->nested_root->smallest_y); this->FindWindowPlacementAndResize(this->window_desc->GetDefaultWidth(), this->window_desc->GetDefaultHeight()); } /** * Perform complete initialization of the #Window with nested widgets, to allow use. * @param window_number Number of the new window. */ void Window::InitNested(WindowNumber window_number) { this->CreateNestedTree(false); this->FinishInitNested(window_number); } /** * Empty constructor, initialization has been moved to #InitNested() called from the constructor of the derived class. * @param desc The description of the window. */ Window::Window(WindowDesc *desc) : window_desc(desc), scrolling_scrollbar(-1) { } /** * Do a search for a window at specific coordinates. For this we start * at the topmost window, obviously and work our way down to the bottom * @param x position x to query * @param y position y to query * @return a pointer to the found window if any, NULL otherwise */ Window *FindWindowFromPt(int x, int y) { Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) { return w; } } return NULL; } /** * (re)initialize the windowing system */ void InitWindowSystem() { IConsoleClose(); _z_back_window = NULL; _z_front_window = NULL; _focused_window = NULL; _mouseover_last_w = NULL; _last_scroll_window = NULL; _scrolling_viewport = false; _mouse_hovering = false; NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. NWidgetScrollbar::InvalidateDimensionCache(); ShowFirstError(); } /** * Close down the windowing system */ void UnInitWindowSystem() { UnshowCriticalError(); Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; for (w = _z_front_window; w != NULL; /* nothing */) { Window *to_del = w; w = w->z_back; free(to_del); } _z_front_window = NULL; _z_back_window = NULL; } /** * Reset the windowing system, by means of shutting it down followed by re-initialization */ void ResetWindowSystem() { UnInitWindowSystem(); InitWindowSystem(); _thd.Reset(); } static void DecreaseWindowCounters() { Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (_scroller_click_timeout == 0) { /* Unclick scrollbar buttons if they are pressed. */ for (uint i = 0; i < w->nested_array_size; i++) { NWidgetBase *nwid = w->nested_array[i]; if (nwid != NULL && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { NWidgetScrollbar *sb = static_cast(nwid); if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); w->scrolling_scrollbar = -1; sb->SetDirty(w); } } } } /* Handle editboxes */ for (SmallMap::Pair *it = w->querystrings.Begin(); it != w->querystrings.End(); ++it) { it->second->HandleEditBox(w, it->first); } w->OnMouseLoop(); } FOR_ALL_WINDOWS_FROM_FRONT(w) { if ((w->flags & WF_TIMEOUT) && --w->timeout_timer == 0) { CLRBITS(w->flags, WF_TIMEOUT); w->OnTimeout(); w->RaiseButtons(true); } } } static void HandlePlacePresize() { if (_special_mouse_mode != WSM_PRESIZE) return; Window *w = _thd.GetCallbackWnd(); if (w == NULL) return; Point pt = GetTileBelowCursor(); if (pt.x == -1) { _thd.selend.x = -1; return; } w->OnPlacePresize(pt, TileVirtXY(pt.x, pt.y)); } /** * Handle dragging and dropping in mouse dragging mode (#WSM_DRAGDROP). * @return State of handling the event. */ static EventState HandleMouseDragDrop() { if (_special_mouse_mode != WSM_DRAGDROP) return ES_NOT_HANDLED; if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; // Dragging, but the mouse did not move. Window *w = _thd.GetCallbackWnd(); if (w != NULL) { /* Send an event in client coordinates. */ Point pt; pt.x = _cursor.pos.x - w->left; pt.y = _cursor.pos.y - w->top; if (_left_button_down) { w->OnMouseDrag(pt, GetWidgetFromPos(w, pt.x, pt.y)); } else { w->OnDragDrop(pt, GetWidgetFromPos(w, pt.x, pt.y)); } } if (!_left_button_down) ResetObjectToPlace(); // Button released, finished dragging. return ES_HANDLED; } /** Report position of the mouse to the underlying window. */ static void HandleMouseOver() { Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); /* We changed window, put a MOUSEOVER event to the last window */ if (_mouseover_last_w != NULL && _mouseover_last_w != w) { /* Reset mouse-over coordinates of previous window */ Point pt = { -1, -1 }; _mouseover_last_w->OnMouseOver(pt, 0); } /* _mouseover_last_w will get reset when the window is deleted, see DeleteWindow() */ _mouseover_last_w = w; if (w != NULL) { /* send an event in client coordinates. */ Point pt = { _cursor.pos.x - w->left, _cursor.pos.y - w->top }; const NWidgetCore *widget = w->nested_root->GetWidgetFromPos(pt.x, pt.y); if (widget != NULL) w->OnMouseOver(pt, widget->index); } } /** The minimum number of pixels of the title bar must be visible in both the X or Y direction */ static const int MIN_VISIBLE_TITLE_BAR = 13; /** Direction for moving the window. */ enum PreventHideDirection { PHD_UP, ///< Above v is a safe position. PHD_DOWN, ///< Below v is a safe position. }; /** * Do not allow hiding of the rectangle with base coordinates \a nx and \a ny behind window \a v. * If needed, move the window base coordinates to keep it visible. * @param nx Base horizontal coordinate of the rectangle. * @param ny Base vertical coordinate of the rectangle. * @param rect Rectangle that must stay visible for #MIN_VISIBLE_TITLE_BAR pixels (horizontally, vertically, or both) * @param v Window lying in front of the rectangle. * @param px Previous horizontal base coordinate. * @param dir If no room horizontally, move the rectangle to the indicated position. */ static void PreventHiding(int *nx, int *ny, const Rect &rect, const Window *v, int px, PreventHideDirection dir) { if (v == NULL) return; int v_bottom = v->top + v->height; int v_right = v->left + v->width; int safe_y = (dir == PHD_UP) ? (v->top - MIN_VISIBLE_TITLE_BAR - rect.top) : (v_bottom + MIN_VISIBLE_TITLE_BAR - rect.bottom); // Compute safe vertical position. if (*ny + rect.top <= v->top - MIN_VISIBLE_TITLE_BAR) return; // Above v is enough space if (*ny + rect.bottom >= v_bottom + MIN_VISIBLE_TITLE_BAR) return; // Below v is enough space /* Vertically, the rectangle is hidden behind v. */ if (*nx + rect.left + MIN_VISIBLE_TITLE_BAR < v->left) { // At left of v. if (v->left < MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // But enough room, force it to a safe position. return; } if (*nx + rect.right - MIN_VISIBLE_TITLE_BAR > v_right) { // At right of v. if (v_right > _screen.width - MIN_VISIBLE_TITLE_BAR) *ny = safe_y; // Not enough room, force it to a safe position. return; } /* Horizontally also hidden, force movement to a safe area. */ if (px + rect.left < v->left && v->left >= MIN_VISIBLE_TITLE_BAR) { // Coming from the left, and enough room there. *nx = v->left - MIN_VISIBLE_TITLE_BAR - rect.left; } else if (px + rect.right > v_right && v_right <= _screen.width - MIN_VISIBLE_TITLE_BAR) { // Coming from the right, and enough room there. *nx = v_right + MIN_VISIBLE_TITLE_BAR - rect.right; } else { *ny = safe_y; } } /** * Make sure at least a part of the caption bar is still visible by moving * the window if necessary. * @param w The window to check. * @param nx The proposed new x-location of the window. * @param ny The proposed new y-location of the window. */ static void EnsureVisibleCaption(Window *w, int nx, int ny) { /* Search for the title bar rectangle. */ Rect caption_rect; const NWidgetBase *caption = w->nested_root->GetWidgetOfType(WWT_CAPTION); if (caption != NULL) { caption_rect.left = caption->pos_x; caption_rect.right = caption->pos_x + caption->current_x; caption_rect.top = caption->pos_y; caption_rect.bottom = caption->pos_y + caption->current_y; /* Make sure the window doesn't leave the screen */ nx = Clamp(nx, MIN_VISIBLE_TITLE_BAR - caption_rect.right, _screen.width - MIN_VISIBLE_TITLE_BAR - caption_rect.left); ny = Clamp(ny, 0, _screen.height - MIN_VISIBLE_TITLE_BAR); /* Make sure the title bar isn't hidden behind the main tool bar or the status bar. */ PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_MAIN_TOOLBAR, 0), w->left, PHD_DOWN); PreventHiding(&nx, &ny, caption_rect, FindWindowById(WC_STATUS_BAR, 0), w->left, PHD_UP); } if (w->viewport != NULL) { w->viewport->left += nx - w->left; w->viewport->top += ny - w->top; } w->left = nx; w->top = ny; } /** * Resize the window. * Update all the widgets of a window based on their resize flags * Both the areas of the old window and the new sized window are set dirty * ensuring proper redrawal. * @param w Window to resize * @param delta_x Delta x-size of changed window (positive if larger, etc.) * @param delta_y Delta y-size of changed window * @param clamp_to_screen Whether to make sure the whole window stays visible */ void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen) { if (delta_x != 0 || delta_y != 0) { if (clamp_to_screen) { /* Determine the new right/bottom position. If that is outside of the bounds of * the resolution clamp it in such a manner that it stays within the bounds. */ int new_right = w->left + w->width + delta_x; int new_bottom = w->top + w->height + delta_y; if (new_right >= (int)_cur_resolution.width) delta_x -= Ceil(new_right - _cur_resolution.width, max(1U, w->nested_root->resize_x)); if (new_bottom >= (int)_cur_resolution.height) delta_y -= Ceil(new_bottom - _cur_resolution.height, max(1U, w->nested_root->resize_y)); } w->SetDirty(); uint new_xinc = max(0, (w->nested_root->resize_x == 0) ? 0 : (int)(w->nested_root->current_x - w->nested_root->smallest_x) + delta_x); uint new_yinc = max(0, (w->nested_root->resize_y == 0) ? 0 : (int)(w->nested_root->current_y - w->nested_root->smallest_y) + delta_y); assert(w->nested_root->resize_x == 0 || new_xinc % w->nested_root->resize_x == 0); assert(w->nested_root->resize_y == 0 || new_yinc % w->nested_root->resize_y == 0); w->nested_root->AssignSizePosition(ST_RESIZE, 0, 0, w->nested_root->smallest_x + new_xinc, w->nested_root->smallest_y + new_yinc, _current_text_dir == TD_RTL); w->width = w->nested_root->current_x; w->height = w->nested_root->current_y; } EnsureVisibleCaption(w, w->left, w->top); /* Always call OnResize to make sure everything is initialised correctly if it needs to be. */ w->OnResize(); w->SetDirty(); } /** * Return the top of the main view available for general use. * @return Uppermost vertical coordinate available. * @note Above the upper y coordinate is often the main toolbar. */ int GetMainViewTop() { Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); return (w == NULL) ? 0 : w->top + w->height; } /** * Return the bottom of the main view available for general use. * @return The vertical coordinate of the first unusable row, so 'top + height <= bottom' gives the correct result. * @note At and below the bottom y coordinate is often the status bar. */ int GetMainViewBottom() { Window *w = FindWindowById(WC_STATUS_BAR, 0); return (w == NULL) ? _screen.height : w->top; } static bool _dragging_window; ///< A window is being dragged or resized. /** * Handle dragging/resizing of a window. * @return State of handling the event. */ static EventState HandleWindowDragging() { /* Get out immediately if no window is being dragged at all. */ if (!_dragging_window) return ES_NOT_HANDLED; /* If button still down, but cursor hasn't moved, there is nothing to do. */ if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; /* Otherwise find the window... */ Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->flags & WF_DRAGGING) { /* Stop the dragging if the left mouse button was released */ if (!_left_button_down) { w->flags &= ~WF_DRAGGING; break; } w->SetDirty(); int x = _cursor.pos.x + _drag_delta.x; int y = _cursor.pos.y + _drag_delta.y; int nx = x; int ny = y; if (_settings_client.gui.window_snap_radius != 0) { const Window *v; int hsnap = _settings_client.gui.window_snap_radius; int vsnap = _settings_client.gui.window_snap_radius; int delta; FOR_ALL_WINDOWS_FROM_BACK(v) { if (v == w) continue; // Don't snap at yourself if (y + w->height > v->top && y < v->top + v->height) { /* Your left border <-> other right border */ delta = abs(v->left + v->width - x); if (delta <= hsnap) { nx = v->left + v->width; hsnap = delta; } /* Your right border <-> other left border */ delta = abs(v->left - x - w->width); if (delta <= hsnap) { nx = v->left - w->width; hsnap = delta; } } if (w->top + w->height >= v->top && w->top <= v->top + v->height) { /* Your left border <-> other left border */ delta = abs(v->left - x); if (delta <= hsnap) { nx = v->left; hsnap = delta; } /* Your right border <-> other right border */ delta = abs(v->left + v->width - x - w->width); if (delta <= hsnap) { nx = v->left + v->width - w->width; hsnap = delta; } } if (x + w->width > v->left && x < v->left + v->width) { /* Your top border <-> other bottom border */ delta = abs(v->top + v->height - y); if (delta <= vsnap) { ny = v->top + v->height; vsnap = delta; } /* Your bottom border <-> other top border */ delta = abs(v->top - y - w->height); if (delta <= vsnap) { ny = v->top - w->height; vsnap = delta; } } if (w->left + w->width >= v->left && w->left <= v->left + v->width) { /* Your top border <-> other top border */ delta = abs(v->top - y); if (delta <= vsnap) { ny = v->top; vsnap = delta; } /* Your bottom border <-> other bottom border */ delta = abs(v->top + v->height - y - w->height); if (delta <= vsnap) { ny = v->top + v->height - w->height; vsnap = delta; } } } } EnsureVisibleCaption(w, nx, ny); w->SetDirty(); return ES_HANDLED; } else if (w->flags & WF_SIZING) { /* Stop the sizing if the left mouse button was released */ if (!_left_button_down) { w->flags &= ~WF_SIZING; w->SetDirty(); break; } /* Compute difference in pixels between cursor position and reference point in the window. * If resizing the left edge of the window, moving to the left makes the window bigger not smaller. */ int x, y = _cursor.pos.y - _drag_delta.y; if (w->flags & WF_SIZING_LEFT) { x = _drag_delta.x - _cursor.pos.x; } else { x = _cursor.pos.x - _drag_delta.x; } /* resize.step_width and/or resize.step_height may be 0, which means no resize is possible. */ if (w->resize.step_width == 0) x = 0; if (w->resize.step_height == 0) y = 0; /* Check the resize button won't go past the bottom of the screen */ if (w->top + w->height + y > _screen.height) { y = _screen.height - w->height - w->top; } /* X and Y has to go by step.. calculate it. * The cast to int is necessary else x/y are implicitly casted to * unsigned int, which won't work. */ if (w->resize.step_width > 1) x -= x % (int)w->resize.step_width; if (w->resize.step_height > 1) y -= y % (int)w->resize.step_height; /* Check that we don't go below the minimum set size */ if ((int)w->width + x < (int)w->nested_root->smallest_x) { x = w->nested_root->smallest_x - w->width; } if ((int)w->height + y < (int)w->nested_root->smallest_y) { y = w->nested_root->smallest_y - w->height; } /* Window already on size */ if (x == 0 && y == 0) return ES_HANDLED; /* Now find the new cursor pos.. this is NOT _cursor, because we move in steps. */ _drag_delta.y += y; if ((w->flags & WF_SIZING_LEFT) && x != 0) { _drag_delta.x -= x; // x > 0 -> window gets longer -> left-edge moves to left -> subtract x to get new position. w->SetDirty(); w->left -= x; // If dragging left edge, move left window edge in opposite direction by the same amount. /* ResizeWindow() below ensures marking new position as dirty. */ } else { _drag_delta.x += x; } /* ResizeWindow sets both pre- and after-size to dirty for redrawal */ ResizeWindow(w, x, y); return ES_HANDLED; } } _dragging_window = false; return ES_HANDLED; } /** * Start window dragging * @param w Window to start dragging */ static void StartWindowDrag(Window *w) { w->flags |= WF_DRAGGING; w->flags &= ~WF_CENTERED; _dragging_window = true; _drag_delta.x = w->left - _cursor.pos.x; _drag_delta.y = w->top - _cursor.pos.y; BringWindowToFront(w); DeleteWindowById(WC_DROPDOWN_MENU, 0); } /** * Start resizing a window. * @param w Window to start resizing. * @param to_left Whether to drag towards the left or not */ static void StartWindowSizing(Window *w, bool to_left) { w->flags |= to_left ? WF_SIZING_LEFT : WF_SIZING_RIGHT; w->flags &= ~WF_CENTERED; _dragging_window = true; _drag_delta.x = _cursor.pos.x; _drag_delta.y = _cursor.pos.y; BringWindowToFront(w); DeleteWindowById(WC_DROPDOWN_MENU, 0); } /** * handle scrollbar scrolling with the mouse. * @return State of handling the event. */ static EventState HandleScrollbarScrolling() { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->scrolling_scrollbar >= 0) { /* Abort if no button is clicked any more. */ if (!_left_button_down) { w->scrolling_scrollbar = -1; w->SetDirty(); return ES_HANDLED; } int i; NWidgetScrollbar *sb = w->GetWidget(w->scrolling_scrollbar); bool rtl = false; if (sb->type == NWID_HSCROLLBAR) { i = _cursor.pos.x - _cursorpos_drag_start.x; rtl = _current_text_dir == TD_RTL; } else { i = _cursor.pos.y - _cursorpos_drag_start.y; } if (sb->disp_flags & ND_SCROLLBAR_BTN) { if (_scroller_click_timeout == 1) { _scroller_click_timeout = 3; sb->UpdatePosition(rtl == HasBit(sb->disp_flags, NDB_SCROLLBAR_UP) ? 1 : -1); w->SetDirty(); } return ES_HANDLED; } /* Find the item we want to move to and make sure it's inside bounds. */ int pos = min(max(0, i + _scrollbar_start_pos) * sb->GetCount() / _scrollbar_size, max(0, sb->GetCount() - sb->GetCapacity())); if (rtl) pos = max(0, sb->GetCount() - sb->GetCapacity() - pos); if (pos != sb->GetPosition()) { sb->SetPosition(pos); w->SetDirty(); } return ES_HANDLED; } } return ES_NOT_HANDLED; } /** * Handle viewport scrolling with the mouse. * @return State of handling the event. */ static EventState HandleViewportScroll() { bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); if (!_scrolling_viewport) return ES_NOT_HANDLED; /* When we don't have a last scroll window we are starting to scroll. * When the last scroll window and this are not the same we went * outside of the window and should not left-mouse scroll anymore. */ if (_last_scroll_window == NULL) _last_scroll_window = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); if (_last_scroll_window == NULL || !(_right_button_down || scrollwheel_scrolling || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down))) { _cursor.fix_at = false; _scrolling_viewport = false; _last_scroll_window = NULL; return ES_NOT_HANDLED; } if (_last_scroll_window == FindWindowById(WC_MAIN_WINDOW, 0) && _last_scroll_window->viewport->follow_vehicle != INVALID_VEHICLE) { /* If the main window is following a vehicle, then first let go of it! */ const Vehicle *veh = Vehicle::Get(_last_scroll_window->viewport->follow_vehicle); ScrollMainWindowTo(veh->x_pos, veh->y_pos, veh->z_pos, true); // This also resets follow_vehicle return ES_NOT_HANDLED; } Point delta; if (_settings_client.gui.reverse_scroll || (_settings_client.gui.left_mouse_btn_scrolling && _left_button_down)) { delta.x = -_cursor.delta.x; delta.y = -_cursor.delta.y; } else { delta.x = _cursor.delta.x; delta.y = _cursor.delta.y; } if (scrollwheel_scrolling) { /* We are using scrollwheels for scrolling */ delta.x = _cursor.h_wheel; delta.y = _cursor.v_wheel; _cursor.v_wheel = 0; _cursor.h_wheel = 0; } /* Create a scroll-event and send it to the window */ if (delta.x != 0 || delta.y != 0) _last_scroll_window->OnScroll(delta); _cursor.delta.x = 0; _cursor.delta.y = 0; return ES_HANDLED; } /** * Check if a window can be made relative top-most window, and if so do * it. If a window does not obscure any other windows, it will not * be brought to the foreground. Also if the only obscuring windows * are so-called system-windows, the window will not be moved. * The function will return false when a child window of this window is a * modal-popup; function returns a false and child window gets a white border * @param w Window to bring relatively on-top * @return false if the window has an active modal child, true otherwise */ static bool MaybeBringWindowToFront(Window *w) { bool bring_to_front = false; if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || w->window_class == WC_TOOLTIPS || w->window_class == WC_DROPDOWN_MENU) { return true; } /* Use unshaded window size rather than current size for shaded windows. */ int w_width = w->width; int w_height = w->height; if (w->IsShaded()) { w_width = w->unshaded_size.width; w_height = w->unshaded_size.height; } Window *u; FOR_ALL_WINDOWS_FROM_BACK_FROM(u, w->z_front) { /* A modal child will prevent the activation of the parent window */ if (u->parent == w && (u->window_desc->flags & WDF_MODAL)) { u->SetWhiteBorder(); u->SetDirty(); return false; } if (u->window_class == WC_MAIN_WINDOW || IsVitalWindow(u) || u->window_class == WC_TOOLTIPS || u->window_class == WC_DROPDOWN_MENU) { continue; } /* Window sizes don't interfere, leave z-order alone */ if (w->left + w_width <= u->left || u->left + u->width <= w->left || w->top + w_height <= u->top || u->top + u->height <= w->top) { continue; } bring_to_front = true; } if (bring_to_front) BringWindowToFront(w); return true; } /** * Process keypress for editbox widget. * @param wid Editbox widget. * @param key the Unicode value of the key. * @param keycode the untranslated key code including shift state. * @return #ES_HANDLED if the key press has been handled and no other * window should receive the event. */ EventState Window::HandleEditBoxKey(int wid, WChar key, uint16 keycode) { QueryString *query = this->GetQueryString(wid); if (query == NULL) return ES_NOT_HANDLED; int action = QueryString::ACTION_NOTHING; switch (query->text.HandleKeyPress(key, keycode)) { case HKPR_EDITING: this->SetWidgetDirty(wid); this->OnEditboxChanged(wid); break; case HKPR_CURSOR: this->SetWidgetDirty(wid); /* For the OSK also invalidate the parent window */ if (this->window_class == WC_OSK) this->InvalidateData(); break; case HKPR_CONFIRM: if (this->window_class == WC_OSK) { this->OnClick(Point(), WID_OSK_OK, 1); } else if (query->ok_button >= 0) { this->OnClick(Point(), query->ok_button, 1); } else { action = query->ok_button; } break; case HKPR_CANCEL: if (this->window_class == WC_OSK) { this->OnClick(Point(), WID_OSK_CANCEL, 1); } else if (query->cancel_button >= 0) { this->OnClick(Point(), query->cancel_button, 1); } else { action = query->cancel_button; } break; case HKPR_NOT_HANDLED: return ES_NOT_HANDLED; default: break; } switch (action) { case QueryString::ACTION_DESELECT: this->UnfocusFocusedWidget(); break; case QueryString::ACTION_CLEAR: if (query->text.bytes <= 1) { /* If already empty, unfocus instead */ this->UnfocusFocusedWidget(); } else { query->text.DeleteAll(); this->SetWidgetDirty(wid); this->OnEditboxChanged(wid); } break; default: break; } return ES_HANDLED; } /** * Handle keyboard input. * @param keycode Virtual keycode of the key. * @param key Unicode character of the key. */ void HandleKeypress(uint keycode, WChar key) { /* World generation is multithreaded and messes with companies. * But there is no company related window open anyway, so _current_company is not used. */ assert(HasModalProgress() || IsLocalCompany()); /* * The Unicode standard defines an area called the private use area. Code points in this * area are reserved for private use and thus not portable between systems. For instance, * Apple defines code points for the arrow keys in this area, but these are only printable * on a system running OS X. We don't want these keys to show up in text fields and such, * and thus we have to clear the unicode character when we encounter such a key. */ if (key >= 0xE000 && key <= 0xF8FF) key = 0; /* * If both key and keycode is zero, we don't bother to process the event. */ if (key == 0 && keycode == 0) return; /* Check if the focused window has a focused editbox */ if (EditBoxInGlobalFocus()) { /* All input will in this case go to the focused editbox */ if (_focused_window->window_class == WC_CONSOLE) { if (_focused_window->OnKeyPress(key, keycode) == ES_HANDLED) return; } else { if (_focused_window->HandleEditBoxKey(_focused_window->nested_focus->index, key, keycode) == ES_HANDLED) return; } } /* Call the event, start with the uppermost window, but ignore the toolbar. */ Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (w->window_class == WC_MAIN_TOOLBAR) continue; if (w->window_desc->hotkeys != NULL) { int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; } if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; } w = FindWindowById(WC_MAIN_TOOLBAR, 0); /* When there is no toolbar w is null, check for that */ if (w != NULL) { if (w->window_desc->hotkeys != NULL) { int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); if (hotkey >= 0 && w->OnHotkey(hotkey) == ES_HANDLED) return; } if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; } HandleGlobalHotkeys(key, keycode); } /** * State of CONTROL key has changed */ void HandleCtrlChanged() { /* Call the event, start with the uppermost window. */ Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (w->OnCTRLStateChange() == ES_HANDLED) return; } } /** * Insert a text string at the cursor position into the edit box widget. * @param wid Edit box widget. * @param str Text string to insert. */ /* virtual */ void Window::InsertTextString(int wid, const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) { QueryString *query = this->GetQueryString(wid); if (query == NULL) return; if (query->text.InsertString(str, marked, caret, insert_location, replacement_end) || marked) { this->SetWidgetDirty(wid); this->OnEditboxChanged(wid); } } /** * Handle text input. * @param str Text string to input. * @param marked Is the input a marked composition string from an IME? * @param caret Move the caret to this point in the insertion string. */ void HandleTextInput(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) { if (!EditBoxInGlobalFocus()) return; _focused_window->InsertTextString(_focused_window->window_class == WC_CONSOLE ? 0 : _focused_window->nested_focus->index, str, marked, caret, insert_location, replacement_end); } /** * Local counter that is incremented each time an mouse input event is detected. * The counter is used to stop auto-scrolling. * @see HandleAutoscroll() * @see HandleMouseEvents() */ static int _input_events_this_tick = 0; /** * If needed and switched on, perform auto scrolling (automatically * moving window contents when mouse is near edge of the window). */ static void HandleAutoscroll() { if (_game_mode == GM_MENU || HasModalProgress()) return; if (_settings_client.gui.auto_scrolling == VA_DISABLED) return; if (_settings_client.gui.auto_scrolling == VA_MAIN_VIEWPORT_FULLSCREEN && !_fullscreen) return; int x = _cursor.pos.x; int y = _cursor.pos.y; Window *w = FindWindowFromPt(x, y); if (w == NULL || w->flags & WF_DISABLE_VP_SCROLL) return; if (_settings_client.gui.auto_scrolling != VA_EVERY_VIEWPORT && w->window_class != WC_MAIN_WINDOW) return; ViewPort *vp = IsPtInWindowViewport(w, x, y); if (vp == NULL) return; x -= vp->left; y -= vp->top; /* here allows scrolling in both x and y axis */ #define scrollspeed 3 if (x - 15 < 0) { w->viewport->dest_scrollpos_x += ScaleByZoom((x - 15) * scrollspeed, vp->zoom); } else if (15 - (vp->width - x) > 0) { w->viewport->dest_scrollpos_x += ScaleByZoom((15 - (vp->width - x)) * scrollspeed, vp->zoom); } if (y - 15 < 0) { w->viewport->dest_scrollpos_y += ScaleByZoom((y - 15) * scrollspeed, vp->zoom); } else if (15 - (vp->height - y) > 0) { w->viewport->dest_scrollpos_y += ScaleByZoom((15 - (vp->height - y)) * scrollspeed, vp->zoom); } #undef scrollspeed } enum MouseClick { MC_NONE = 0, MC_LEFT, MC_RIGHT, MC_DOUBLE_LEFT, MC_HOVER, MAX_OFFSET_DOUBLE_CLICK = 5, ///< How much the mouse is allowed to move to call it a double click TIME_BETWEEN_DOUBLE_CLICK = 500, ///< Time between 2 left clicks before it becoming a double click, in ms MAX_OFFSET_HOVER = 5, ///< Maximum mouse movement before stopping a hover event. }; extern EventState VpHandlePlaceSizingDrag(); static void ScrollMainViewport(int x, int y) { if (_game_mode != GM_MENU) { Window *w = FindWindowById(WC_MAIN_WINDOW, 0); assert(w); w->viewport->dest_scrollpos_x += ScaleByZoom(x, w->viewport->zoom); w->viewport->dest_scrollpos_y += ScaleByZoom(y, w->viewport->zoom); } } /** * Describes all the different arrow key combinations the game allows * when it is in scrolling mode. * The real arrow keys are bitwise numbered as * 1 = left * 2 = up * 4 = right * 8 = down */ static const int8 scrollamt[16][2] = { { 0, 0}, ///< no key specified {-2, 0}, ///< 1 : left { 0, -2}, ///< 2 : up {-2, -1}, ///< 3 : left + up { 2, 0}, ///< 4 : right { 0, 0}, ///< 5 : left + right = nothing { 2, -1}, ///< 6 : right + up { 0, -2}, ///< 7 : right + left + up = up { 0, 2}, ///< 8 : down {-2, 1}, ///< 9 : down + left { 0, 0}, ///< 10 : down + up = nothing {-2, 0}, ///< 11 : left + up + down = left { 2, 1}, ///< 12 : down + right { 0, 2}, ///< 13 : left + right + down = down { 2, 0}, ///< 14 : right + up + down = right { 0, 0}, ///< 15 : left + up + right + down = nothing }; static void HandleKeyScrolling() { /* * Check that any of the dirkeys is pressed and that the focused window * doesn't have an edit-box as focused widget. */ if (_dirkeys && !EditBoxInGlobalFocus()) { int factor = _shift_pressed ? 50 : 10; ScrollMainViewport(scrollamt[_dirkeys][0] * factor, scrollamt[_dirkeys][1] * factor); } } static void MouseLoop(MouseClick click, int mousewheel) { /* World generation is multithreaded and messes with companies. * But there is no company related window open anyway, so _current_company is not used. */ assert(HasModalProgress() || IsLocalCompany()); HandlePlacePresize(); UpdateTileSelection(); if (VpHandlePlaceSizingDrag() == ES_HANDLED) return; if (HandleMouseDragDrop() == ES_HANDLED) return; if (HandleWindowDragging() == ES_HANDLED) return; if (HandleScrollbarScrolling() == ES_HANDLED) return; if (HandleViewportScroll() == ES_HANDLED) return; HandleMouseOver(); bool scrollwheel_scrolling = _settings_client.gui.scrollwheel_scrolling == 1 && (_cursor.v_wheel != 0 || _cursor.h_wheel != 0); if (click == MC_NONE && mousewheel == 0 && !scrollwheel_scrolling) return; int x = _cursor.pos.x; int y = _cursor.pos.y; Window *w = FindWindowFromPt(x, y); if (w == NULL) return; if (click != MC_HOVER && !MaybeBringWindowToFront(w)) return; ViewPort *vp = IsPtInWindowViewport(w, x, y); /* Don't allow any action in a viewport if either in menu or when having a modal progress window */ if (vp != NULL && (_game_mode == GM_MENU || HasModalProgress())) return; if (mousewheel != 0) { /* Send mousewheel event to window */ w->OnMouseWheel(mousewheel); /* Dispatch a MouseWheelEvent for widgets if it is not a viewport */ if (vp == NULL) DispatchMouseWheelEvent(w, w->nested_root->GetWidgetFromPos(x - w->left, y - w->top), mousewheel); } if (vp != NULL) { if (scrollwheel_scrolling) click = MC_RIGHT; // we are using the scrollwheel in a viewport, so we emulate right mouse button switch (click) { case MC_DOUBLE_LEFT: case MC_LEFT: DEBUG(misc, 2, "Cursor: 0x%X (%d)", _cursor.sprite, _cursor.sprite); if (!HandleViewportClicked(vp, x, y) && !(w->flags & WF_DISABLE_VP_SCROLL) && _settings_client.gui.left_mouse_btn_scrolling) { _scrolling_viewport = true; _cursor.fix_at = false; } break; case MC_RIGHT: if (!(w->flags & WF_DISABLE_VP_SCROLL)) { _scrolling_viewport = true; _cursor.fix_at = true; /* clear 2D scrolling caches before we start a 2D scroll */ _cursor.h_wheel = 0; _cursor.v_wheel = 0; } break; default: break; } } else { switch (click) { case MC_LEFT: case MC_DOUBLE_LEFT: DispatchLeftClickEvent(w, x - w->left, y - w->top, click == MC_DOUBLE_LEFT ? 2 : 1); break; default: if (!scrollwheel_scrolling || w == NULL || w->window_class != WC_SMALLMAP) break; /* We try to use the scrollwheel to scroll since we didn't touch any of the buttons. * Simulate a right button click so we can get started. */ /* FALL THROUGH */ case MC_RIGHT: DispatchRightClickEvent(w, x - w->left, y - w->top); break; case MC_HOVER: DispatchHoverEvent(w, x - w->left, y - w->top); break; } } } /** * Handle a mouse event from the video driver */ void HandleMouseEvents() { /* World generation is multithreaded and messes with companies. * But there is no company related window open anyway, so _current_company is not used. */ assert(HasModalProgress() || IsLocalCompany()); static int double_click_time = 0; static Point double_click_pos = {0, 0}; /* Mouse event? */ MouseClick click = MC_NONE; if (_left_button_down && !_left_button_clicked) { click = MC_LEFT; if (double_click_time != 0 && _realtime_tick - double_click_time < TIME_BETWEEN_DOUBLE_CLICK && double_click_pos.x != 0 && abs(_cursor.pos.x - double_click_pos.x) < MAX_OFFSET_DOUBLE_CLICK && double_click_pos.y != 0 && abs(_cursor.pos.y - double_click_pos.y) < MAX_OFFSET_DOUBLE_CLICK) { click = MC_DOUBLE_LEFT; } double_click_time = _realtime_tick; double_click_pos = _cursor.pos; _left_button_clicked = true; _input_events_this_tick++; } else if (_right_button_clicked) { _right_button_clicked = false; click = MC_RIGHT; _input_events_this_tick++; } int mousewheel = 0; if (_cursor.wheel) { mousewheel = _cursor.wheel; _cursor.wheel = 0; _input_events_this_tick++; } static uint32 hover_time = 0; static Point hover_pos = {0, 0}; if (_settings_client.gui.hover_delay_ms > 0) { if (!_cursor.in_window || click != MC_NONE || mousewheel != 0 || _left_button_down || _right_button_down || hover_pos.x == 0 || abs(_cursor.pos.x - hover_pos.x) >= MAX_OFFSET_HOVER || hover_pos.y == 0 || abs(_cursor.pos.y - hover_pos.y) >= MAX_OFFSET_HOVER) { hover_pos = _cursor.pos; hover_time = _realtime_tick; _mouse_hovering = false; } else { if (hover_time != 0 && _realtime_tick > hover_time + _settings_client.gui.hover_delay_ms) { click = MC_HOVER; _input_events_this_tick++; _mouse_hovering = true; } } } /* Handle sprite picker before any GUI interaction */ if (_newgrf_debug_sprite_picker.mode == SPM_REDRAW && _newgrf_debug_sprite_picker.click_time != _realtime_tick) { /* Next realtime tick? Then redraw has finished */ _newgrf_debug_sprite_picker.mode = SPM_NONE; InvalidateWindowData(WC_SPRITE_ALIGNER, 0, 1); } if (click == MC_LEFT && _newgrf_debug_sprite_picker.mode == SPM_WAIT_CLICK) { /* Mark whole screen dirty, and wait for the next realtime tick, when drawing is finished. */ Blitter *blitter = BlitterFactory::GetCurrentBlitter(); _newgrf_debug_sprite_picker.clicked_pixel = blitter->MoveTo(_screen.dst_ptr, _cursor.pos.x, _cursor.pos.y); _newgrf_debug_sprite_picker.click_time = _realtime_tick; _newgrf_debug_sprite_picker.sprites.Clear(); _newgrf_debug_sprite_picker.mode = SPM_REDRAW; MarkWholeScreenDirty(); } else { MouseLoop(click, mousewheel); } /* We have moved the mouse the required distance, * no need to move it at any later time. */ _cursor.delta.x = 0; _cursor.delta.y = 0; } /** * Check the soft limit of deletable (non vital, non sticky) windows. */ static void CheckSoftLimit() { if (_settings_client.gui.window_soft_limit == 0) return; for (;;) { uint deletable_count = 0; Window *w, *last_deletable = NULL; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || (w->flags & WF_STICKY)) continue; last_deletable = w; deletable_count++; } /* We've not reached the soft limit yet. */ if (deletable_count <= _settings_client.gui.window_soft_limit) break; assert(last_deletable != NULL); delete last_deletable; } } /** * Regular call from the global game loop */ void InputLoop() { /* World generation is multithreaded and messes with companies. * But there is no company related window open anyway, so _current_company is not used. */ assert(HasModalProgress() || IsLocalCompany()); CheckSoftLimit(); HandleKeyScrolling(); /* Do the actual free of the deleted windows. */ for (Window *v = _z_front_window; v != NULL; /* nothing */) { Window *w = v; v = v->z_back; if (w->window_class != WC_INVALID) continue; RemoveWindowFromZOrdering(w); free(w); } if (_scroller_click_timeout != 0) _scroller_click_timeout--; DecreaseWindowCounters(); if (_input_events_this_tick != 0) { /* The input loop is called only once per GameLoop() - so we can clear the counter here */ _input_events_this_tick = 0; /* there were some inputs this tick, don't scroll ??? */ return; } /* HandleMouseEvents was already called for this tick */ HandleMouseEvents(); HandleAutoscroll(); } /** * Update the continuously changing contents of the windows, such as the viewports */ void UpdateWindows() { Window *w; static int highlight_timer = 1; if (--highlight_timer == 0) { highlight_timer = 15; _window_highlight_colour = !_window_highlight_colour; } FOR_ALL_WINDOWS_FROM_FRONT(w) { w->ProcessScheduledInvalidations(); w->ProcessHighlightedInvalidations(); } static int we4_timer = 0; int t = we4_timer + 1; if (t >= 100) { FOR_ALL_WINDOWS_FROM_FRONT(w) { w->OnHundredthTick(); } t = 0; } we4_timer = t; FOR_ALL_WINDOWS_FROM_FRONT(w) { if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) { CLRBITS(w->flags, WF_WHITE_BORDER); w->SetDirty(); } } DrawDirtyBlocks(); FOR_ALL_WINDOWS_FROM_BACK(w) { /* Update viewport only if window is not shaded. */ if (w->viewport != NULL && !w->IsShaded()) UpdateViewportPosition(w); } NetworkDrawChatMessage(); /* Redraw mouse cursor in case it was hidden */ DrawMouseCursor(); } /** * Mark window as dirty (in need of repainting) * @param cls Window class * @param number Window number in that class */ void SetWindowDirty(WindowClass cls, WindowNumber number) { const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls && w->window_number == number) w->SetDirty(); } } /** * Mark a particular widget in a particular window as dirty (in need of repainting) * @param cls Window class * @param number Window number in that class * @param widget_index Index number of the widget that needs repainting */ void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index) { const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls && w->window_number == number) { w->SetWidgetDirty(widget_index); } } } /** * Mark all windows of a particular class as dirty (in need of repainting) * @param cls Window class */ void SetWindowClassesDirty(WindowClass cls) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls) w->SetDirty(); } } /** * Mark this window's data as invalid (in need of re-computing) * @param data The data to invalidate with * @param gui_scope Whether the function is called from GUI scope. */ void Window::InvalidateData(int data, bool gui_scope) { this->SetDirty(); if (!gui_scope) { /* Schedule GUI-scope invalidation for next redraw. */ *this->scheduled_invalidation_data.Append() = data; } this->OnInvalidateData(data, gui_scope); } /** * Process all scheduled invalidations. */ void Window::ProcessScheduledInvalidations() { for (int *data = this->scheduled_invalidation_data.Begin(); this->window_class != WC_INVALID && data != this->scheduled_invalidation_data.End(); data++) { this->OnInvalidateData(*data, true); } this->scheduled_invalidation_data.Clear(); } /** * Process all invalidation of highlighted widgets. */ void Window::ProcessHighlightedInvalidations() { if ((this->flags & WF_HIGHLIGHTED) == 0) return; for (uint i = 0; i < this->nested_array_size; i++) { if (this->IsWidgetHighlighted(i)) this->SetWidgetDirty(i); } } /** * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing) * * Note that by default the invalidation is not considered to be called from GUI scope. * That means only a part of invalidation is executed immediately. The rest is scheduled for the next redraw. * The asynchronous execution is important to prevent GUI code being executed from command scope. * When not in GUI-scope: * - OnInvalidateData() may not do test-runs on commands, as they might affect the execution of * the command which triggered the invalidation. (town rating and such) * - OnInvalidateData() may not rely on _current_company == _local_company. * This implies that no NewGRF callbacks may be run. * * However, when invalidations are scheduled, then multiple calls may be scheduled before execution starts. Earlier scheduled * invalidations may be called with invalidation-data, which is already invalid at the point of execution. * That means some stuff requires to be executed immediately in command scope, while not everything may be executed in command * scope. While GUI-scope calls have no restrictions on what they may do, they cannot assume the game to still be in the state * when the invalidation was scheduled; passed IDs may have got invalid in the mean time. * * Finally, note that invalidations triggered from commands or the game loop result in OnInvalidateData() being called twice. * Once in command-scope, once in GUI-scope. So make sure to not process differential-changes twice. * * @param cls Window class * @param number Window number within the class * @param data The data to invalidate with * @param gui_scope Whether the call is done from GUI scope */ void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls && w->window_number == number) { w->InvalidateData(data, gui_scope); } } } /** * Mark window data of all windows of a given class as invalid (in need of re-computing) * Note that by default the invalidation is not considered to be called from GUI scope. * See InvalidateWindowData() for details on GUI-scope vs. command-scope. * @param cls Window class * @param data The data to invalidate with * @param gui_scope Whether the call is done from GUI scope */ void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class == cls) { w->InvalidateData(data, gui_scope); } } } /** * Dispatch WE_TICK event over all windows */ void CallWindowTickEvent() { Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { w->OnTick(); } } /** * Try to delete a non-vital window. * Non-vital windows are windows other than the game selection, main toolbar, * status bar, toolbar menu, and tooltip windows. Stickied windows are also * considered vital. */ void DeleteNonVitalWindows() { Window *w; restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_SELECT_GAME && w->window_class != WC_MAIN_TOOLBAR && w->window_class != WC_STATUS_BAR && w->window_class != WC_TOOLTIPS && (w->flags & WF_STICKY) == 0) { // do not delete windows which are 'pinned' delete w; goto restart_search; } } } /** * It is possible that a stickied window gets to a position where the * 'close' button is outside the gaming area. You cannot close it then; except * with this function. It closes all windows calling the standard function, * then, does a little hacked loop of closing all stickied windows. Note * that standard windows (status bar, etc.) are not stickied, so these aren't affected */ void DeleteAllNonVitalWindows() { Window *w; /* Delete every window except for stickied ones, then sticky ones as well */ DeleteNonVitalWindows(); restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->flags & WF_STICKY) { delete w; goto restart_search; } } } /** * Delete all windows that are used for construction of vehicle etc. * Once done with that invalidate the others to ensure they get refreshed too. */ void DeleteConstructionWindows() { Window *w; restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_desc->flags & WDF_CONSTRUCTION) { delete w; goto restart_search; } } FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); } /** Delete all always on-top windows to get an empty screen */ void HideVitalWindows() { DeleteWindowById(WC_MAIN_TOOLBAR, 0); DeleteWindowById(WC_STATUS_BAR, 0); } /** Re-initialize all windows. */ void ReInitAllWindows() { NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. NWidgetScrollbar::InvalidateDimensionCache(); extern void InitDepotWindowBlockSizes(); InitDepotWindowBlockSizes(); Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { w->ReInit(); } #ifdef ENABLE_NETWORK void NetworkReInitChatBoxSize(); NetworkReInitChatBoxSize(); #endif /* Make sure essential parts of all windows are visible */ RelocateAllWindows(_cur_resolution.width, _cur_resolution.height); MarkWholeScreenDirty(); } /** * (Re)position a window at the screen. * @param w Window structure of the window, may also be \c NULL. * @param clss The class of the window to position. * @param setting The actual setting used for the window's position. * @return X coordinate of left edge of the repositioned window. */ static int PositionWindow(Window *w, WindowClass clss, int setting) { if (w == NULL || w->window_class != clss) { w = FindWindowById(clss, 0); } if (w == NULL) return 0; int old_left = w->left; switch (setting) { case 1: w->left = (_screen.width - w->width) / 2; break; case 2: w->left = _screen.width - w->width; break; default: w->left = 0; break; } if (w->viewport != NULL) w->viewport->left += w->left - old_left; SetDirtyBlocks(0, w->top, _screen.width, w->top + w->height); // invalidate the whole row return w->left; } /** * (Re)position main toolbar window at the screen. * @param w Window structure of the main toolbar window, may also be \c NULL. * @return X coordinate of left edge of the repositioned toolbar window. */ int PositionMainToolbar(Window *w) { DEBUG(misc, 5, "Repositioning Main Toolbar..."); return PositionWindow(w, WC_MAIN_TOOLBAR, _settings_client.gui.toolbar_pos); } /** * (Re)position statusbar window at the screen. * @param w Window structure of the statusbar window, may also be \c NULL. * @return X coordinate of left edge of the repositioned statusbar. */ int PositionStatusbar(Window *w) { DEBUG(misc, 5, "Repositioning statusbar..."); return PositionWindow(w, WC_STATUS_BAR, _settings_client.gui.statusbar_pos); } /** * (Re)position news message window at the screen. * @param w Window structure of the news message window, may also be \c NULL. * @return X coordinate of left edge of the repositioned news message. */ int PositionNewsMessage(Window *w) { DEBUG(misc, 5, "Repositioning news message..."); return PositionWindow(w, WC_NEWS_WINDOW, _settings_client.gui.statusbar_pos); } /** * (Re)position network chat window at the screen. * @param w Window structure of the network chat window, may also be \c NULL. * @return X coordinate of left edge of the repositioned network chat window. */ int PositionNetworkChatWindow(Window *w) { DEBUG(misc, 5, "Repositioning network chat window..."); return PositionWindow(w, WC_SEND_NETWORK_MSG, _settings_client.gui.statusbar_pos); } /** * Switches viewports following vehicles, which get autoreplaced * @param from_index the old vehicle ID * @param to_index the new vehicle ID */ void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->viewport != NULL && w->viewport->follow_vehicle == from_index) { w->viewport->follow_vehicle = to_index; w->SetDirty(); } } } /** * Relocate all windows to fit the new size of the game application screen * @param neww New width of the game application screen * @param newh New height of the game application screen. */ void RelocateAllWindows(int neww, int newh) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { int left, top; /* XXX - this probably needs something more sane. For example specifying * in a 'backup'-desc that the window should always be centered. */ switch (w->window_class) { case WC_MAIN_WINDOW: case WC_BOOTSTRAP: ResizeWindow(w, neww, newh); continue; case WC_MAIN_TOOLBAR: ResizeWindow(w, min(neww, _toolbar_width) - w->width, 0, false); top = w->top; left = PositionMainToolbar(w); // changes toolbar orientation break; case WC_NEWS_WINDOW: top = newh - w->height; left = PositionNewsMessage(w); break; case WC_STATUS_BAR: ResizeWindow(w, min(neww, _toolbar_width) - w->width, 0, false); top = newh - w->height; left = PositionStatusbar(w); break; case WC_SEND_NETWORK_MSG: ResizeWindow(w, min(neww, _toolbar_width) - w->width, 0, false); top = newh - w->height - FindWindowById(WC_STATUS_BAR, 0)->height; left = PositionNetworkChatWindow(w); break; case WC_CONSOLE: IConsoleResize(w); continue; default: { if (w->flags & WF_CENTERED) { top = (newh - w->height) >> 1; left = (neww - w->width) >> 1; break; } left = w->left; if (left + (w->width >> 1) >= neww) left = neww - w->width; if (left < 0) left = 0; top = w->top; if (top + (w->height >> 1) >= newh) top = newh - w->height; break; } } EnsureVisibleCaption(w, left, top); } } /** * Destructor of the base class PickerWindowBase * Main utility is to stop the base Window destructor from triggering * a free while the child will already be free, in this case by the ResetObjectToPlace(). */ PickerWindowBase::~PickerWindowBase() { this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child ResetObjectToPlace(); } openttd-1.5.3/src/signs_func.h0000644000000000000000000000211512627373442015002 0ustar rootroot/* $Id: signs_func.h 20516 2010-08-16 16:15:22Z terkhen $ */ /* * 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 signs_func.h Functions related to signs. */ #ifndef SIGNS_FUNC_H #define SIGNS_FUNC_H #include "signs_type.h" #include "tile_type.h" struct Window; extern SignID _new_sign_id; void UpdateAllSignVirtCoords(); void PlaceProc_Sign(TileIndex tile); /* signs_gui.cpp */ void ShowRenameSignWindow(const Sign *si); void HandleClickOnSign(const Sign *si); void DeleteRenameSignWindow(SignID sign); Window *ShowSignList(); #endif /* SIGNS_FUNC_H */ openttd-1.5.3/src/tunnelbridge_cmd.cpp0000644000000000000000000021235112627373435016513 0ustar rootroot/* $Id: tunnelbridge_cmd.cpp 27350 2015-07-30 18:50:39Z frosch $ */ /* * 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 tunnelbridge_cmd.cpp * This file deals with tunnels and bridges (non-gui stuff) * @todo separate this file into two */ #include "stdafx.h" #include "newgrf_object.h" #include "viewport_func.h" #include "cmd_helper.h" #include "command_func.h" #include "town.h" #include "train.h" #include "ship.h" #include "roadveh.h" #include "pathfinder/yapf/yapf_cache.h" #include "newgrf_sound.h" #include "autoslope.h" #include "tunnelbridge_map.h" #include "strings_func.h" #include "date_func.h" #include "clear_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "tunnelbridge.h" #include "cheat_type.h" #include "elrail_func.h" #include "pbs.h" #include "company_base.h" #include "newgrf_railtype.h" #include "object_base.h" #include "water.h" #include "company_gui.h" #include "table/strings.h" #include "table/bridge_land.h" #include "safeguards.h" BridgeSpec _bridge[MAX_BRIDGES]; ///< The specification of all bridges. TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from the tunnel build command for GUI purposes. /** Z position of the bridge sprites relative to bridge height (downwards) */ static const int BRIDGE_Z_START = 3; /** * Mark bridge tiles dirty. * Note: The bridge does not need to exist, everything is passed via parameters. * @param begin Start tile. * @param end End tile. * @param direction Direction from \a begin to \a end. * @param bridge_height Bridge height level. */ void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height) { TileIndexDiff delta = TileOffsByDiagDir(direction); for (TileIndex t = begin; t != end; t += delta) { MarkTileDirtyByTile(t, bridge_height - TileHeight(t)); } MarkTileDirtyByTile(end); } /** * Mark bridge tiles dirty. * @param tile Bridge head. */ void MarkBridgeDirty(TileIndex tile) { MarkBridgeDirty(tile, GetOtherTunnelBridgeEnd(tile), GetTunnelBridgeDirection(tile), GetBridgeHeight(tile)); } /** Reset the data been eventually changed by the grf loaded. */ void ResetBridges() { /* First, free sprite table data */ for (BridgeType i = 0; i < MAX_BRIDGES; i++) { if (_bridge[i].sprite_table != NULL) { for (BridgePieces j = BRIDGE_PIECE_NORTH; j < BRIDGE_PIECE_INVALID; j++) free(_bridge[i].sprite_table[j]); free(_bridge[i].sprite_table); } } /* Then, wipe out current bridges */ memset(&_bridge, 0, sizeof(_bridge)); /* And finally, reinstall default data */ memcpy(&_bridge, &_orig_bridge, sizeof(_orig_bridge)); } /** * Calculate the price factor for building a long bridge. * Basically the cost delta is 1,1, 1, 2,2, 3,3,3, 4,4,4,4, 5,5,5,5,5, 6,6,6,6,6,6, 7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8, * @param length Length of the bridge. * @return Price factor for the bridge. */ int CalcBridgeLenCostFactor(int length) { if (length < 2) return length; length -= 2; int sum = 2; for (int delta = 1;; delta++) { for (int count = 0; count < delta; count++) { if (length == 0) return sum; sum += delta; length--; } } } /** * Get the foundation for a bridge. * @param tileh The slope to build the bridge on. * @param axis The axis of the bridge entrance. * @return The foundation required. */ Foundation GetBridgeFoundation(Slope tileh, Axis axis) { if (tileh == SLOPE_FLAT || ((tileh == SLOPE_NE || tileh == SLOPE_SW) && axis == AXIS_X) || ((tileh == SLOPE_NW || tileh == SLOPE_SE) && axis == AXIS_Y)) return FOUNDATION_NONE; return (HasSlopeHighestCorner(tileh) ? InclinedFoundation(axis) : FlatteningFoundation(tileh)); } /** * Determines if the track on a bridge ramp is flat or goes up/down. * * @param tileh Slope of the tile under the bridge head * @param axis Orientation of bridge * @return true iff the track is flat. */ bool HasBridgeFlatRamp(Slope tileh, Axis axis) { ApplyFoundationToSlope(GetBridgeFoundation(tileh, axis), &tileh); /* If the foundation slope is flat the bridge has a non-flat ramp and vice versa. */ return (tileh != SLOPE_FLAT); } static inline const PalSpriteID *GetBridgeSpriteTable(int index, BridgePieces table) { const BridgeSpec *bridge = GetBridgeSpec(index); assert(table < BRIDGE_PIECE_INVALID); if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) { return _bridge_sprite_table[index][table]; } else { return bridge->sprite_table[table]; } } /** * Determines the foundation for the north bridge head, and tests if the resulting slope is valid. * * @param axis Axis of the bridge * @param tileh Slope of the tile under the north bridge head; returns slope on top of foundation * @param z TileZ corresponding to tileh, gets modified as well * @return Error or cost for bridge foundation */ static CommandCost CheckBridgeSlopeNorth(Axis axis, Slope *tileh, int *z) { Foundation f = GetBridgeFoundation(*tileh, axis); *z += ApplyFoundationToSlope(f, tileh); Slope valid_inclined = (axis == AXIS_X ? SLOPE_NE : SLOPE_NW); if ((*tileh != SLOPE_FLAT) && (*tileh != valid_inclined)) return CMD_ERROR; if (f == FOUNDATION_NONE) return CommandCost(); return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } /** * Determines the foundation for the south bridge head, and tests if the resulting slope is valid. * * @param axis Axis of the bridge * @param tileh Slope of the tile under the south bridge head; returns slope on top of foundation * @param z TileZ corresponding to tileh, gets modified as well * @return Error or cost for bridge foundation */ static CommandCost CheckBridgeSlopeSouth(Axis axis, Slope *tileh, int *z) { Foundation f = GetBridgeFoundation(*tileh, axis); *z += ApplyFoundationToSlope(f, tileh); Slope valid_inclined = (axis == AXIS_X ? SLOPE_SW : SLOPE_SE); if ((*tileh != SLOPE_FLAT) && (*tileh != valid_inclined)) return CMD_ERROR; if (f == FOUNDATION_NONE) return CommandCost(); return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } /** * Is a bridge of the specified type and length available? * @param bridge_type Wanted type of bridge. * @param bridge_len Wanted length of the bridge. * @return A succeeded (the requested bridge is available) or failed (it cannot be built) command. */ CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlag flags) { if (flags & DC_QUERY_COST) { if (bridge_len <= _settings_game.construction.max_bridge_length) return CommandCost(); return_cmd_error(STR_ERROR_BRIDGE_TOO_LONG); } if (bridge_type >= MAX_BRIDGES) return CMD_ERROR; const BridgeSpec *b = GetBridgeSpec(bridge_type); if (b->avail_year > _cur_year) return CMD_ERROR; uint max = min(b->max_length, _settings_game.construction.max_bridge_length); if (b->min_length > bridge_len) return CMD_ERROR; if (bridge_len <= max) return CommandCost(); return_cmd_error(STR_ERROR_BRIDGE_TOO_LONG); } /** * Build a Bridge * @param end_tile end tile * @param flags type of operation * @param p1 packed start tile coords (~ dx) * @param p2 various bitstuffed elements * - p2 = (bit 0- 7) - bridge type (hi bh) * - p2 = (bit 8-11) - rail type or road types. * - p2 = (bit 15-16) - transport type. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CompanyID company = _current_company; RailType railtype = INVALID_RAILTYPE; RoadTypes roadtypes = ROADTYPES_NONE; /* unpack parameters */ BridgeType bridge_type = GB(p2, 0, 8); if (!IsValidTile(p1)) return_cmd_error(STR_ERROR_BRIDGE_THROUGH_MAP_BORDER); TransportType transport_type = Extract(p2); /* type of bridge */ switch (transport_type) { case TRANSPORT_ROAD: roadtypes = Extract(p2); if (!HasExactlyOneBit(roadtypes) || !HasRoadTypesAvail(company, roadtypes)) return CMD_ERROR; break; case TRANSPORT_RAIL: railtype = Extract(p2); if (!ValParamRailtype(railtype)) return CMD_ERROR; break; case TRANSPORT_WATER: break; default: /* Airports don't have bridges. */ return CMD_ERROR; } TileIndex tile_start = p1; TileIndex tile_end = end_tile; if (company == OWNER_DEITY) { if (transport_type != TRANSPORT_ROAD) return CMD_ERROR; const Town *town = CalcClosestTownFromTile(tile_start); company = OWNER_TOWN; /* If we are not within a town, we are not owned by the town */ if (town == NULL || DistanceSquare(tile_start, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { company = OWNER_NONE; } } if (tile_start == tile_end) { return_cmd_error(STR_ERROR_CAN_T_START_AND_END_ON); } Axis direction; if (TileX(tile_start) == TileX(tile_end)) { direction = AXIS_Y; } else if (TileY(tile_start) == TileY(tile_end)) { direction = AXIS_X; } else { return_cmd_error(STR_ERROR_START_AND_END_MUST_BE_IN); } if (tile_end < tile_start) Swap(tile_start, tile_end); uint bridge_len = GetTunnelBridgeLength(tile_start, tile_end); if (transport_type != TRANSPORT_WATER) { /* set and test bridge length, availability */ CommandCost ret = CheckBridgeAvailability(bridge_type, bridge_len, flags); if (ret.Failed()) return ret; } else { if (bridge_len > _settings_game.construction.max_bridge_length) return_cmd_error(STR_ERROR_BRIDGE_TOO_LONG); } int z_start; int z_end; Slope tileh_start = GetTileSlope(tile_start, &z_start); Slope tileh_end = GetTileSlope(tile_end, &z_end); bool pbs_reservation = false; CommandCost terraform_cost_north = CheckBridgeSlopeNorth(direction, &tileh_start, &z_start); CommandCost terraform_cost_south = CheckBridgeSlopeSouth(direction, &tileh_end, &z_end); /* Aqueducts can't be built of flat land. */ if (transport_type == TRANSPORT_WATER && (tileh_start == SLOPE_FLAT || tileh_end == SLOPE_FLAT)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); if (z_start != z_end) return_cmd_error(STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT); CommandCost cost(EXPENSES_CONSTRUCTION); Owner owner; bool is_new_owner; if (IsBridgeTile(tile_start) && IsBridgeTile(tile_end) && GetOtherBridgeEnd(tile_start) == tile_end && GetTunnelBridgeTransportType(tile_start) == transport_type) { /* Replace a current bridge. */ /* If this is a railway bridge, make sure the railtypes match. */ if (transport_type == TRANSPORT_RAIL && GetRailType(tile_start) != railtype) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } /* Do not replace town bridges with lower speed bridges, unless in scenario editor. */ if (!(flags & DC_QUERY_COST) && IsTileOwner(tile_start, OWNER_TOWN) && GetBridgeSpec(bridge_type)->speed < GetBridgeSpec(GetBridgeType(tile_start))->speed && _game_mode != GM_EDITOR) { Town *t = ClosestTownFromTile(tile_start, UINT_MAX); if (t == NULL) { return CMD_ERROR; } else { SetDParam(0, t->index); return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS); } } /* Do not replace the bridge with the same bridge type. */ if (!(flags & DC_QUERY_COST) && (bridge_type == GetBridgeType(tile_start)) && (transport_type != TRANSPORT_ROAD || (roadtypes & ~GetRoadTypes(tile_start)) == 0)) { return_cmd_error(STR_ERROR_ALREADY_BUILT); } /* Do not allow replacing another company's bridges. */ if (!IsTileOwner(tile_start, company) && !IsTileOwner(tile_start, OWNER_TOWN) && !IsTileOwner(tile_start, OWNER_NONE)) { return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER); } cost.AddCost((bridge_len + 1) * _price[PR_CLEAR_BRIDGE]); // The cost of clearing the current bridge. owner = GetTileOwner(tile_start); /* If bridge belonged to bankrupt company, it has a new owner now */ is_new_owner = (owner == OWNER_NONE); if (is_new_owner) owner = company; switch (transport_type) { case TRANSPORT_RAIL: /* Keep the reservation, the path stays valid. */ pbs_reservation = HasTunnelBridgeReservation(tile_start); break; case TRANSPORT_ROAD: /* Do not remove road types when upgrading a bridge */ roadtypes |= GetRoadTypes(tile_start); break; default: break; } } else { /* Build a new bridge. */ bool allow_on_slopes = (_settings_game.construction.build_on_slopes && transport_type != TRANSPORT_WATER); /* Try and clear the start landscape */ CommandCost ret = DoCommand(tile_start, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost = ret; if (terraform_cost_north.Failed() || (terraform_cost_north.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); cost.AddCost(terraform_cost_north); /* Try and clear the end landscape */ ret = DoCommand(tile_end, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); /* false - end tile slope check */ if (terraform_cost_south.Failed() || (terraform_cost_south.GetCost() != 0 && !allow_on_slopes)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); cost.AddCost(terraform_cost_south); const TileIndex heads[] = {tile_start, tile_end}; for (int i = 0; i < 2; i++) { if (IsBridgeAbove(heads[i])) { TileIndex north_head = GetNorthernBridgeEnd(heads[i]); if (direction == GetBridgeAxis(heads[i])) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); if (z_start + 1 == GetBridgeHeight(north_head)) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } } } TileIndexDiff delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) { if (GetTileMaxZ(tile) > z_start) return_cmd_error(STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN); if (z_start >= (GetTileZ(tile) + _settings_game.construction.max_bridge_height)) { /* * Disallow too high bridges. * Properly rendering a map where very high bridges (might) exist is expensive. * See http://www.tt-forums.net/viewtopic.php?f=33&t=40844&start=980#p1131762 * for a detailed discussion. z_start here is one heightlevel below the bridge level. */ return_cmd_error(STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN); } if (IsBridgeAbove(tile)) { /* Disallow crossing bridges for the time being */ return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } switch (GetTileType(tile)) { case MP_WATER: if (!IsWater(tile) && !IsCoast(tile)) goto not_valid_below; break; case MP_RAILWAY: if (!IsPlainRail(tile)) goto not_valid_below; break; case MP_ROAD: if (IsRoadDepot(tile)) goto not_valid_below; break; case MP_TUNNELBRIDGE: if (IsTunnel(tile)) break; if (direction == DiagDirToAxis(GetTunnelBridgeDirection(tile))) goto not_valid_below; if (z_start < GetBridgeHeight(tile)) goto not_valid_below; break; case MP_OBJECT: { const ObjectSpec *spec = ObjectSpec::GetByTile(tile); if ((spec->flags & OBJECT_FLAG_ALLOW_UNDER_BRIDGE) == 0) goto not_valid_below; if (GetTileMaxZ(tile) + spec->height > z_start) goto not_valid_below; break; } case MP_CLEAR: break; default: not_valid_below:; /* try and clear the middle landscape */ ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); break; } if (flags & DC_EXEC) { /* We do this here because when replacing a bridge with another * type calling SetBridgeMiddle isn't needed. After all, the * tile already has the has_bridge_above bits set. */ SetBridgeMiddle(tile, direction); } } owner = company; is_new_owner = true; } /* do the drill? */ if (flags & DC_EXEC) { DiagDirection dir = AxisToDiagDir(direction); Company *c = Company::GetIfValid(company); switch (transport_type) { case TRANSPORT_RAIL: /* Add to company infrastructure count if required. */ if (is_new_owner && c != NULL) c->infrastructure.rail[railtype] += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype); MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype); SetTunnelBridgeReservation(tile_start, pbs_reservation); SetTunnelBridgeReservation(tile_end, pbs_reservation); break; case TRANSPORT_ROAD: { RoadTypes prev_roadtypes = IsBridgeTile(tile_start) ? GetRoadTypes(tile_start) : ROADTYPES_NONE; if (is_new_owner) { /* Also give unowned present roadtypes to new owner */ if (HasBit(prev_roadtypes, ROADTYPE_ROAD) && GetRoadOwner(tile_start, ROADTYPE_ROAD) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_ROAD); if (HasBit(prev_roadtypes, ROADTYPE_TRAM) && GetRoadOwner(tile_start, ROADTYPE_TRAM) == OWNER_NONE) ClrBit(prev_roadtypes, ROADTYPE_TRAM); } if (c != NULL) { /* Add all new road types to the company infrastructure counter. */ RoadType new_rt; FOR_EACH_SET_ROADTYPE(new_rt, roadtypes ^ prev_roadtypes) { /* A full diagonal road tile has two road bits. */ c->infrastructure.road[new_rt] += (bridge_len + 2) * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; } } Owner owner_road = HasBit(prev_roadtypes, ROADTYPE_ROAD) ? GetRoadOwner(tile_start, ROADTYPE_ROAD) : company; Owner owner_tram = HasBit(prev_roadtypes, ROADTYPE_TRAM) ? GetRoadOwner(tile_start, ROADTYPE_TRAM) : company; MakeRoadBridgeRamp(tile_start, owner, owner_road, owner_tram, bridge_type, dir, roadtypes); MakeRoadBridgeRamp(tile_end, owner, owner_road, owner_tram, bridge_type, ReverseDiagDir(dir), roadtypes); break; } case TRANSPORT_WATER: if (is_new_owner && c != NULL) c->infrastructure.water += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; MakeAqueductBridgeRamp(tile_start, owner, dir); MakeAqueductBridgeRamp(tile_end, owner, ReverseDiagDir(dir)); break; default: NOT_REACHED(); } /* Mark all tiles dirty */ MarkBridgeDirty(tile_start, tile_end, AxisToDiagDir(direction), z_start); DirtyCompanyInfrastructureWindows(company); } if ((flags & DC_EXEC) && transport_type == TRANSPORT_RAIL) { Track track = AxisToTrack(direction); AddSideToSignalBuffer(tile_start, INVALID_DIAGDIR, company); YapfNotifyTrackLayoutChange(tile_start, track); } /* for human player that builds the bridge he gets a selection to choose from bridges (DC_QUERY_COST) * It's unnecessary to execute this command every time for every bridge. So it is done only * and cost is computed in "bridge_gui.c". For AI, Towns this has to be of course calculated */ Company *c = Company::GetIfValid(company); if (!(flags & DC_QUERY_COST) || (c != NULL && c->is_ai)) { bridge_len += 2; // begin and end tiles/ramps switch (transport_type) { case TRANSPORT_ROAD: cost.AddCost(bridge_len * _price[PR_BUILD_ROAD] * 2 * CountBits(roadtypes)); break; case TRANSPORT_RAIL: cost.AddCost(bridge_len * RailBuildCost(railtype)); break; default: break; } if (c != NULL) bridge_len = CalcBridgeLenCostFactor(bridge_len); if (transport_type != TRANSPORT_WATER) { cost.AddCost((int64)bridge_len * _price[PR_BUILD_BRIDGE] * GetBridgeSpec(bridge_type)->price >> 8); } else { /* Aqueducts use a separate base cost. */ cost.AddCost((int64)bridge_len * _price[PR_BUILD_AQUEDUCT]); } } return cost; } /** * Build Tunnel. * @param start_tile start tile of tunnel * @param flags type of operation * @param p1 bit 0-3 railtype or roadtypes * bit 8-9 transport type * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CompanyID company = _current_company; TransportType transport_type = Extract(p1); RailType railtype = INVALID_RAILTYPE; RoadTypes rts = ROADTYPES_NONE; _build_tunnel_endtile = 0; switch (transport_type) { case TRANSPORT_RAIL: railtype = Extract(p1); if (!ValParamRailtype(railtype)) return CMD_ERROR; break; case TRANSPORT_ROAD: rts = Extract(p1); if (!HasExactlyOneBit(rts) || !HasRoadTypesAvail(company, rts)) return CMD_ERROR; break; default: return CMD_ERROR; } if (company == OWNER_DEITY) { if (transport_type != TRANSPORT_ROAD) return CMD_ERROR; const Town *town = CalcClosestTownFromTile(start_tile); company = OWNER_TOWN; /* If we are not within a town, we are not owned by the town */ if (town == NULL || DistanceSquare(start_tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { company = OWNER_NONE; } } int start_z; int end_z; Slope start_tileh = GetTileSlope(start_tile, &start_z); DiagDirection direction = GetInclinedSlopeDirection(start_tileh); if (direction == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL); if (HasTileWaterGround(start_tile)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER); CommandCost ret = DoCommand(start_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; /* XXX - do NOT change 'ret' in the loop, as it is used as the price * for the clearing of the entrance of the tunnel. Assigning it to * cost before the loop will yield different costs depending on start- * position, because of increased-cost-by-length: 'cost += cost >> 3' */ TileIndexDiff delta = TileOffsByDiagDir(direction); DiagDirection tunnel_in_way_dir; if (DiagDirToAxis(direction) == AXIS_Y) { tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE; } else { tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW; } TileIndex end_tile = start_tile; /* Tile shift coefficient. Will decrease for very long tunnels to avoid exponential growth of price*/ int tiles_coef = 3; /* Number of tiles from start of tunnel */ int tiles = 0; /* Number of tiles at which the cost increase coefficient per tile is halved */ int tiles_bump = 25; CommandCost cost(EXPENSES_CONSTRUCTION); Slope end_tileh; for (;;) { end_tile += delta; if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER); end_tileh = GetTileSlope(end_tile, &end_z); if (start_z == end_z) break; if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) { return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY); } tiles++; if (tiles == tiles_bump) { tiles_coef++; tiles_bump *= 2; } cost.AddCost(_price[PR_BUILD_TUNNEL]); cost.AddCost(cost.GetCost() >> tiles_coef); // add a multiplier for longer tunnels } /* Add the cost of the entrance */ cost.AddCost(_price[PR_BUILD_TUNNEL]); cost.AddCost(ret); /* if the command fails from here on we want the end tile to be highlighted */ _build_tunnel_endtile = end_tile; if (tiles > _settings_game.construction.max_tunnel_length) return_cmd_error(STR_ERROR_TUNNEL_TOO_LONG); if (HasTileWaterGround(end_tile)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER); /* Clear the tile in any case */ ret = DoCommand(end_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return_cmd_error(STR_ERROR_UNABLE_TO_EXCAVATE_LAND); cost.AddCost(ret); /* slope of end tile must be complementary to the slope of the start tile */ if (end_tileh != ComplementSlope(start_tileh)) { /* Mark the tile as already cleared for the terraform command. * Do this for all tiles (like trees), not only objects. */ ClearedObjectArea *coa = FindClearedObject(end_tile); if (coa == NULL) { coa = _cleared_object_areas.Append(); coa->first_tile = end_tile; coa->area = TileArea(end_tile, 1, 1); } /* Hide the tile from the terraforming command */ TileIndex old_first_tile = coa->first_tile; coa->first_tile = INVALID_TILE; ret = DoCommand(end_tile, end_tileh & start_tileh, 0, flags, CMD_TERRAFORM_LAND); coa->first_tile = old_first_tile; if (ret.Failed()) return_cmd_error(STR_ERROR_UNABLE_TO_EXCAVATE_LAND); cost.AddCost(ret); } cost.AddCost(_price[PR_BUILD_TUNNEL]); /* Pay for the rail/road in the tunnel including entrances */ switch (transport_type) { case TRANSPORT_ROAD: cost.AddCost((tiles + 2) * _price[PR_BUILD_ROAD] * 2); break; case TRANSPORT_RAIL: cost.AddCost((tiles + 2) * RailBuildCost(railtype)); break; default: NOT_REACHED(); } if (flags & DC_EXEC) { Company *c = Company::GetIfValid(company); uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; if (transport_type == TRANSPORT_RAIL) { if (!IsTunnelTile(start_tile) && c != NULL) c->infrastructure.rail[railtype] += num_pieces; MakeRailTunnel(start_tile, company, direction, railtype); MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype); AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company); YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction)); } else { if (c != NULL) { RoadType rt; FOR_EACH_SET_ROADTYPE(rt, rts ^ (IsTunnelTile(start_tile) ? GetRoadTypes(start_tile) : ROADTYPES_NONE)) { c->infrastructure.road[rt] += num_pieces * 2; // A full diagonal road has two road bits. } } MakeRoadTunnel(start_tile, company, direction, rts); MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), rts); } DirtyCompanyInfrastructureWindows(company); } return cost; } /** * Are we allowed to remove the tunnel or bridge at \a tile? * @param tile End point of the tunnel or bridge. * @return A succeeded command if the tunnel or bridge may be removed, a failed command otherwise. */ static inline CommandCost CheckAllowRemoveTunnelBridge(TileIndex tile) { /* Floods can remove anything as well as the scenario editor */ if (_current_company == OWNER_WATER || _game_mode == GM_EDITOR) return CommandCost(); switch (GetTunnelBridgeTransportType(tile)) { case TRANSPORT_ROAD: { RoadTypes rts = GetRoadTypes(tile); Owner road_owner = _current_company; Owner tram_owner = _current_company; if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); /* We can remove unowned road and if the town allows it */ if (road_owner == OWNER_TOWN && _current_company != OWNER_TOWN && !(_settings_game.construction.extra_dynamite || _cheats.magic_bulldozer.value)) { /* Town does not allow */ return CheckTileOwnership(tile); } if (road_owner == OWNER_NONE || road_owner == OWNER_TOWN) road_owner = _current_company; if (tram_owner == OWNER_NONE) tram_owner = _current_company; CommandCost ret = CheckOwnership(road_owner, tile); if (ret.Succeeded()) ret = CheckOwnership(tram_owner, tile); return ret; } case TRANSPORT_RAIL: return CheckOwnership(GetTileOwner(tile)); case TRANSPORT_WATER: { /* Always allow to remove aqueducts without owner. */ Owner aqueduct_owner = GetTileOwner(tile); if (aqueduct_owner == OWNER_NONE) aqueduct_owner = _current_company; return CheckOwnership(aqueduct_owner); } default: NOT_REACHED(); } } /** * Remove a tunnel from the game, update town rating, etc. * @param tile Tile containing one of the endpoints of the tunnel. * @param flags Command flags. * @return Succeeded or failed command. */ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags) { CommandCost ret = CheckAllowRemoveTunnelBridge(tile); if (ret.Failed()) return ret; TileIndex endtile = GetOtherTunnelEnd(tile); ret = TunnelBridgeIsFree(tile, endtile); if (ret.Failed()) return ret; _build_tunnel_endtile = endtile; Town *t = NULL; if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) { t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating /* Check if you are allowed to remove the tunnel owned by a town * Removal depends on difficulty settings */ CommandCost ret = CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE); if (ret.Failed()) return ret; } /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until * you have a "Poor" (0) town rating */ if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) { ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags); } uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles. if (flags & DC_EXEC) { if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { /* We first need to request values before calling DoClearSquare */ DiagDirection dir = GetTunnelBridgeDirection(tile); Track track = DiagDirToDiagTrack(dir); Owner owner = GetTileOwner(tile); Train *v = NULL; if (HasTunnelBridgeReservation(tile)) { v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } if (Company::IsValidID(owner)) { Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(owner); } DoClearSquare(tile); DoClearSquare(endtile); /* cannot use INVALID_DIAGDIR for signal update because the tunnel doesn't exist anymore */ AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner); AddSideToSignalBuffer(endtile, dir, owner); YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); if (v != NULL) TryPathReserve(v); } else { RoadType rt; FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { /* A full diagonal road tile has two road bits. */ Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(c->index); } } DoClearSquare(tile); DoClearSquare(endtile); } } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len); } /** * Remove a bridge from the game, update town rating, etc. * @param tile Tile containing one of the endpoints of the bridge. * @param flags Command flags. * @return Succeeded or failed command. */ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags) { CommandCost ret = CheckAllowRemoveTunnelBridge(tile); if (ret.Failed()) return ret; TileIndex endtile = GetOtherBridgeEnd(tile); ret = TunnelBridgeIsFree(tile, endtile); if (ret.Failed()) return ret; DiagDirection direction = GetTunnelBridgeDirection(tile); TileIndexDiff delta = TileOffsByDiagDir(direction); Town *t = NULL; if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) { t = ClosestTownFromTile(tile, UINT_MAX); // town penalty rating /* Check if you are allowed to remove the bridge owned by a town * Removal depends on difficulty settings */ CommandCost ret = CheckforTownRating(flags, t, TUNNELBRIDGE_REMOVE); if (ret.Failed()) return ret; } /* checks if the owner is town then decrease town rating by RATING_TUNNEL_BRIDGE_DOWN_STEP until * you have a "Poor" (0) town rating */ if (IsTileOwner(tile, OWNER_TOWN) && _game_mode != GM_EDITOR) { ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags); } Money base_cost = (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) ? _price[PR_CLEAR_BRIDGE] : _price[PR_CLEAR_AQUEDUCT]; uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles. if (flags & DC_EXEC) { /* read this value before actual removal of bridge */ bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL; Owner owner = GetTileOwner(tile); int height = GetBridgeHeight(tile); Train *v = NULL; if (rail && HasTunnelBridgeReservation(tile)) { v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction)); if (v != NULL) FreeTrainTrackReservation(v); } /* Update company infrastructure counts. */ if (rail) { if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; } else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) { RoadType rt; FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { /* A full diagonal road tile has two road bits. */ c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(c->index); } } } else { // Aqueduct if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.water -= len * TUNNELBRIDGE_TRACKBIT_FACTOR; } DirtyCompanyInfrastructureWindows(owner); DoClearSquare(tile); DoClearSquare(endtile); for (TileIndex c = tile + delta; c != endtile; c += delta) { /* do not let trees appear from 'nowhere' after removing bridge */ if (IsNormalRoadTile(c) && GetRoadside(c) == ROADSIDE_TREES) { int minz = GetTileMaxZ(c) + 3; if (height < minz) SetRoadside(c, ROADSIDE_PAVED); } ClearBridgeMiddle(c); MarkTileDirtyByTile(c, height - TileHeight(c)); } if (rail) { /* cannot use INVALID_DIAGDIR for signal update because the bridge doesn't exist anymore */ AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner); AddSideToSignalBuffer(endtile, direction, owner); Track track = DiagDirToDiagTrack(direction); YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); if (v != NULL) TryPathReserve(v, true); } } return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost); } /** * Remove a tunnel or a bridge from the game. * @param tile Tile containing one of the endpoints. * @param flags Command flags. * @return Succeeded or failed command. */ static CommandCost ClearTile_TunnelBridge(TileIndex tile, DoCommandFlag flags) { if (IsTunnel(tile)) { if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST); return DoClearTunnel(tile, flags); } else { // IsBridge(tile) if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); return DoClearBridge(tile, flags); } } /** * Draw a single pillar sprite. * @param psid Pillarsprite * @param x Pillar X * @param y Pillar Y * @param z Pillar Z * @param w Bounding box size in X direction * @param h Bounding box size in Y direction * @param subsprite Optional subsprite for drawing halfpillars */ static inline void DrawPillar(const PalSpriteID *psid, int x, int y, int z, int w, int h, const SubSprite *subsprite) { static const int PILLAR_Z_OFFSET = TILE_HEIGHT - BRIDGE_Z_START; ///< Start offset of pillar wrt. bridge (downwards) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, w, h, BB_HEIGHT_UNDER_BRIDGE - PILLAR_Z_OFFSET, z, IsTransparencySet(TO_BRIDGES), 0, 0, -PILLAR_Z_OFFSET, subsprite); } /** * Draw two bridge pillars (north and south). * @param z_bottom Bottom Z * @param z_top Top Z * @param psid Pillarsprite * @param x Pillar X * @param y Pillar Y * @param w Bounding box size in X direction * @param h Bounding box size in Y direction * @return Reached Z at the bottom */ static int DrawPillarColumn(int z_bottom, int z_top, const PalSpriteID *psid, int x, int y, int w, int h) { int cur_z; for (cur_z = z_top; cur_z >= z_bottom; cur_z -= TILE_HEIGHT) { DrawPillar(psid, x, y, cur_z, w, h, NULL); } return cur_z; } /** * Draws the pillars under high bridges. * * @param psid Image and palette of a bridge pillar. * @param ti #TileInfo of current bridge-middle-tile. * @param axis Orientation of bridge. * @param drawfarpillar Whether to draw the pillar at the back * @param x Sprite X position of front pillar. * @param y Sprite Y position of front pillar. * @param z_bridge Absolute height of bridge bottom. */ static void DrawBridgePillars(const PalSpriteID *psid, const TileInfo *ti, Axis axis, bool drawfarpillar, int x, int y, int z_bridge) { static const int bounding_box_size[2] = {16, 2}; ///< bounding box size of pillars along bridge direction static const int back_pillar_offset[2] = { 0, 9}; ///< sprite position offset of back facing pillar static const int INF = 1000; ///< big number compared to sprite size static const SubSprite half_pillar_sub_sprite[2][2] = { { { -14, -INF, INF, INF }, { -INF, -INF, -15, INF } }, // X axis, north and south { { -INF, -INF, 15, INF }, { 16, -INF, INF, INF } }, // Y axis, north and south }; if (psid->sprite == 0) return; /* Determine ground height under pillars */ DiagDirection south_dir = AxisToDiagDir(axis); int z_front_north = ti->z; int z_back_north = ti->z; int z_front_south = ti->z; int z_back_south = ti->z; GetSlopePixelZOnEdge(ti->tileh, south_dir, &z_front_south, &z_back_south); GetSlopePixelZOnEdge(ti->tileh, ReverseDiagDir(south_dir), &z_front_north, &z_back_north); /* Shared height of pillars */ int z_front = max(z_front_north, z_front_south); int z_back = max(z_back_north, z_back_south); /* x and y size of bounding-box of pillars */ int w = bounding_box_size[axis]; int h = bounding_box_size[OtherAxis(axis)]; /* sprite position of back facing pillar */ int x_back = x - back_pillar_offset[axis]; int y_back = y - back_pillar_offset[OtherAxis(axis)]; /* Draw front pillars */ int bottom_z = DrawPillarColumn(z_front, z_bridge, psid, x, y, w, h); if (z_front_north < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]); if (z_front_south < z_front) DrawPillar(psid, x, y, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]); /* Draw back pillars, skip top two parts, which are hidden by the bridge */ int z_bridge_back = z_bridge - 2 * (int)TILE_HEIGHT; if (drawfarpillar && (z_back_north <= z_bridge_back || z_back_south <= z_bridge_back)) { bottom_z = DrawPillarColumn(z_back, z_bridge_back, psid, x_back, y_back, w, h); if (z_back_north < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][0]); if (z_back_south < z_back) DrawPillar(psid, x_back, y_back, bottom_z, w, h, &half_pillar_sub_sprite[axis][1]); } } /** * Draws the trambits over an already drawn (lower end) of a bridge. * @param x the x of the bridge * @param y the y of the bridge * @param z the z of the bridge * @param offset number representing whether to level or sloped and the direction * @param overlay do we want to still see the road? * @param head are we drawing bridge head? */ static void DrawBridgeTramBits(int x, int y, int z, int offset, bool overlay, bool head) { static const SpriteID tram_offsets[2][6] = { { 107, 108, 109, 110, 111, 112 }, { 4, 5, 15, 16, 17, 18 } }; static const SpriteID back_offsets[6] = { 95, 96, 99, 102, 100, 101 }; static const SpriteID front_offsets[6] = { 97, 98, 103, 106, 104, 105 }; static const uint size_x[6] = { 1, 16, 16, 1, 16, 1 }; static const uint size_y[6] = { 16, 1, 1, 16, 1, 16 }; static const uint front_bb_offset_x[6] = { 15, 0, 0, 15, 0, 15 }; static const uint front_bb_offset_y[6] = { 0, 15, 15, 0, 15, 0 }; /* The sprites under the vehicles are drawn as SpriteCombine. StartSpriteCombine() has already been called * The bounding boxes here are the same as for bridge front/roof */ if (head || !IsInvisibilitySet(TO_BRIDGES)) { AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + tram_offsets[overlay][offset], PAL_NONE, x, y, size_x[offset], size_y[offset], 0x28, z, !head && IsTransparencySet(TO_BRIDGES)); } /* Do not draw catenary if it is set invisible */ if (!IsInvisibilitySet(TO_CATENARY)) { AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + back_offsets[offset], PAL_NONE, x, y, size_x[offset], size_y[offset], 0x28, z, IsTransparencySet(TO_CATENARY)); } /* Start a new SpriteCombine for the front part */ EndSpriteCombine(); StartSpriteCombine(); /* For sloped sprites the bounding box needs to be higher, as the pylons stop on a higher point */ if (!IsInvisibilitySet(TO_CATENARY)) { AddSortableSpriteToDraw(SPR_TRAMWAY_BASE + front_offsets[offset], PAL_NONE, x, y, size_x[offset] + front_bb_offset_x[offset], size_y[offset] + front_bb_offset_y[offset], 0x28, z, IsTransparencySet(TO_CATENARY), front_bb_offset_x[offset], front_bb_offset_y[offset]); } } /** * Draws a tunnel of bridge tile. * For tunnels, this is rather simple, as you only need to draw the entrance. * Bridges are a bit more complex. base_offset is where the sprite selection comes into play * and it works a bit like a bitmask.

For bridge heads: * @param ti TileInfo of the structure to draw *

  • Bit 0: direction
  • *
  • Bit 1: northern or southern heads
  • *
  • Bit 2: Set if the bridge head is sloped
  • *
  • Bit 3 and more: Railtype Specific subset
  • *
* Please note that in this code, "roads" are treated as railtype 1, whilst the real railtypes are 0, 2 and 3 */ static void DrawTile_TunnelBridge(TileInfo *ti) { TransportType transport_type = GetTunnelBridgeTransportType(ti->tile); DiagDirection tunnelbridge_direction = GetTunnelBridgeDirection(ti->tile); if (IsTunnel(ti->tile)) { /* Front view of tunnel bounding boxes: * * 122223 <- BB_Z_SEPARATOR * 1 3 * 1 3 1,3 = empty helper BB * 1 3 2 = SpriteCombine of tunnel-roof and catenary (tram & elrail) * */ static const int _tunnel_BB[4][12] = { /* tunnnel-roof | Z-separator | tram-catenary * w h bb_x bb_y| x y w h |bb_x bb_y w h */ { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // NE { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // SE { 1, 0, -15, -14, 0, 15, 16, 1, 0, 1, 16, 15 }, // SW { 0, 1, -14, -15, 15, 0, 1, 16, 1, 0, 15, 16 }, // NW }; const int *BB_data = _tunnel_BB[tunnelbridge_direction]; bool catenary = false; SpriteID image; SpriteID railtype_overlay = 0; if (transport_type == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); image = rti->base_sprites.tunnel; if (rti->UsesOverlay()) { /* Check if the railtype has custom tunnel portals. */ railtype_overlay = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL_PORTAL); if (railtype_overlay != 0) image = SPR_RAILTYPE_TUNNEL_BASE; // Draw blank grass tunnel base. } } else { image = SPR_TUNNEL_ENTRY_REAR_ROAD; } if (HasTunnelBridgeSnowOrDesert(ti->tile)) image += railtype_overlay != 0 ? 8 : 32; image += tunnelbridge_direction * 2; DrawGroundSprite(image, PAL_NONE); if (transport_type == TRANSPORT_ROAD) { RoadTypes rts = GetRoadTypes(ti->tile); if (HasBit(rts, ROADTYPE_TRAM)) { static const SpriteID tunnel_sprites[2][4] = { { 28, 78, 79, 27 }, { 5, 76, 77, 4 } }; DrawGroundSprite(SPR_TRAMWAY_BASE + tunnel_sprites[rts - ROADTYPES_TRAM][tunnelbridge_direction], PAL_NONE); /* Do not draw wires if they are invisible */ if (!IsInvisibilitySet(TO_CATENARY)) { catenary = true; StartSpriteCombine(); AddSortableSpriteToDraw(SPR_TRAMWAY_TUNNEL_WIRES + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, BB_data[10], BB_data[11], TILE_HEIGHT, ti->z, IsTransparencySet(TO_CATENARY), BB_data[8], BB_data[9], BB_Z_SEPARATOR); } } } else { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); if (rti->UsesOverlay()) { SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_TUNNEL); if (surface != 0) DrawGroundSprite(surface + tunnelbridge_direction, PAL_NONE); } /* PBS debugging, draw reserved tracks darker */ if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) { if (rti->UsesOverlay()) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); DrawGroundSprite(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH); } else { DrawGroundSprite(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH); } } if (HasCatenaryDrawn(GetRailType(ti->tile))) { /* Maybe draw pylons on the entry side */ DrawCatenary(ti); catenary = true; StartSpriteCombine(); /* Draw wire above the ramp */ DrawCatenaryOnTunnel(ti); } } if (railtype_overlay != 0 && !catenary) StartSpriteCombine(); AddSortableSpriteToDraw(image + 1, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR); /* Draw railtype tunnel portal overlay if defined. */ if (railtype_overlay != 0) AddSortableSpriteToDraw(railtype_overlay + tunnelbridge_direction, PAL_NONE, ti->x + TILE_SIZE - 1, ti->y + TILE_SIZE - 1, BB_data[0], BB_data[1], TILE_HEIGHT, ti->z, false, BB_data[2], BB_data[3], BB_Z_SEPARATOR); if (catenary || railtype_overlay != 0) EndSpriteCombine(); /* Add helper BB for sprite sorting that separates the tunnel from things beside of it. */ AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x, ti->y, BB_data[6], BB_data[7], TILE_HEIGHT, ti->z); AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, ti->x + BB_data[4], ti->y + BB_data[5], BB_data[6], BB_data[7], TILE_HEIGHT, ti->z); DrawBridgeMiddle(ti); } else { // IsBridge(ti->tile) const PalSpriteID *psid; int base_offset; bool ice = HasTunnelBridgeSnowOrDesert(ti->tile); if (transport_type == TRANSPORT_RAIL) { base_offset = GetRailTypeInfo(GetRailType(ti->tile))->bridge_offset; assert(base_offset != 8); // This one is used for roads } else { base_offset = 8; } /* as the lower 3 bits are used for other stuff, make sure they are clear */ assert( (base_offset & 0x07) == 0x00); DrawFoundation(ti, GetBridgeFoundation(ti->tileh, DiagDirToAxis(tunnelbridge_direction))); /* HACK Wizardry to convert the bridge ramp direction into a sprite offset */ base_offset += (6 - tunnelbridge_direction) % 4; /* Table number BRIDGE_PIECE_HEAD always refers to the bridge heads for any bridge type */ if (transport_type != TRANSPORT_WATER) { if (ti->tileh == SLOPE_FLAT) base_offset += 4; // sloped bridge head psid = &GetBridgeSpriteTable(GetBridgeType(ti->tile), BRIDGE_PIECE_HEAD)[base_offset]; } else { psid = _aqueduct_sprites + base_offset; } if (!ice) { TileIndex next = ti->tile + TileOffsByDiagDir(tunnelbridge_direction); if (ti->tileh != SLOPE_FLAT && ti->z == 0 && HasTileWaterClass(next) && GetWaterClass(next) == WATER_CLASS_SEA) { DrawShoreTile(ti->tileh); } else { DrawClearLandTile(ti, 3); } } else { DrawGroundSprite(SPR_FLAT_SNOW_DESERT_TILE + SlopeToSpriteOffset(ti->tileh), PAL_NONE); } /* draw ramp */ /* Draw Trambits and PBS Reservation as SpriteCombine */ if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine(); /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on * it doesn't disappear behind it */ /* Bridge heads are drawn solid no matter how invisibility/transparency is set */ AddSortableSpriteToDraw(psid->sprite, psid->pal, ti->x, ti->y, 16, 16, ti->tileh == SLOPE_FLAT ? 0 : 8, ti->z); if (transport_type == TRANSPORT_ROAD) { RoadTypes rts = GetRoadTypes(ti->tile); if (HasBit(rts, ROADTYPE_TRAM)) { uint offset = tunnelbridge_direction; int z = ti->z; if (ti->tileh != SLOPE_FLAT) { offset = (offset + 1) & 1; z += TILE_HEIGHT; } else { offset += 2; } /* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */ DrawBridgeTramBits(ti->x, ti->y, z, offset, HasBit(rts, ROADTYPE_ROAD), true); } EndSpriteCombine(); } else if (transport_type == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); if (rti->UsesOverlay()) { SpriteID surface = GetCustomRailSprite(rti, ti->tile, RTSG_BRIDGE); if (surface != 0) { if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { AddSortableSpriteToDraw(surface + ((DiagDirToAxis(tunnelbridge_direction) == AXIS_X) ? RTBO_X : RTBO_Y), PAL_NONE, ti->x, ti->y, 16, 16, 0, ti->z + 8); } else { AddSortableSpriteToDraw(surface + RTBO_SLOPE + tunnelbridge_direction, PAL_NONE, ti->x, ti->y, 16, 16, 8, ti->z); } } /* Don't fallback to non-overlay sprite -- the spec states that * if an overlay is present then the bridge surface must be * present. */ } /* PBS debugging, draw reserved tracks darker */ if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) { if (rti->UsesOverlay()) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { AddSortableSpriteToDraw(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8); } else { AddSortableSpriteToDraw(overlay + RTO_SLOPE_NE + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z); } } else { if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) { AddSortableSpriteToDraw(DiagDirToAxis(tunnelbridge_direction) == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 8); } else { AddSortableSpriteToDraw(rti->base_sprites.single_sloped + tunnelbridge_direction, PALETTE_CRASH, ti->x, ti->y, 16, 16, 8, ti->z); } } } EndSpriteCombine(); if (HasCatenaryDrawn(GetRailType(ti->tile))) { DrawCatenary(ti); } } DrawBridgeMiddle(ti); } } /** * Compute bridge piece. Computes the bridge piece to display depending on the position inside the bridge. * bridges pieces sequence (middle parts). * Note that it is not covering the bridge heads, which are always referenced by the same sprite table. * bridge len 1: BRIDGE_PIECE_NORTH * bridge len 2: BRIDGE_PIECE_NORTH BRIDGE_PIECE_SOUTH * bridge len 3: BRIDGE_PIECE_NORTH BRIDGE_PIECE_MIDDLE_ODD BRIDGE_PIECE_SOUTH * bridge len 4: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH * bridge len 5: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_MIDDLE_EVEN BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH * bridge len 6: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH * bridge len 7: BRIDGE_PIECE_NORTH BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_MIDDLE_ODD BRIDGE_PIECE_INNER_NORTH BRIDGE_PIECE_INNER_SOUTH BRIDGE_PIECE_SOUTH * #0 - always as first, #1 - always as last (if len>1) * #2,#3 are to pair in order * for odd bridges: #5 is going in the bridge middle if on even position, #4 on odd (counting from 0) * @param north Northernmost tile of bridge * @param south Southernmost tile of bridge * @return Index of bridge piece */ static BridgePieces CalcBridgePiece(uint north, uint south) { if (north == 1) { return BRIDGE_PIECE_NORTH; } else if (south == 1) { return BRIDGE_PIECE_SOUTH; } else if (north < south) { return north & 1 ? BRIDGE_PIECE_INNER_SOUTH : BRIDGE_PIECE_INNER_NORTH; } else if (north > south) { return south & 1 ? BRIDGE_PIECE_INNER_NORTH : BRIDGE_PIECE_INNER_SOUTH; } else { return north & 1 ? BRIDGE_PIECE_MIDDLE_EVEN : BRIDGE_PIECE_MIDDLE_ODD; } } /** * Draw the middle bits of a bridge. * @param ti Tile information of the tile to draw it on. */ void DrawBridgeMiddle(const TileInfo *ti) { /* Sectional view of bridge bounding boxes: * * 1 2 1,2 = SpriteCombine of Bridge front/(back&floor) and TramCatenary * 1 2 3 = empty helper BB * 1 7 2 4,5 = pillars under higher bridges * 1 6 88888 6 2 6 = elrail-pylons * 1 6 88888 6 2 7 = elrail-wire * 1 6 88888 6 2 <- TILE_HEIGHT 8 = rail-vehicle on bridge * 3333333333333 <- BB_Z_SEPARATOR * <- unused * 4 5 <- BB_HEIGHT_UNDER_BRIDGE * 4 5 * 4 5 * */ if (!IsBridgeAbove(ti->tile)) return; TileIndex rampnorth = GetNorthernBridgeEnd(ti->tile); TileIndex rampsouth = GetSouthernBridgeEnd(ti->tile); TransportType transport_type = GetTunnelBridgeTransportType(rampsouth); Axis axis = GetBridgeAxis(ti->tile); BridgePieces piece = CalcBridgePiece( GetTunnelBridgeLength(ti->tile, rampnorth) + 1, GetTunnelBridgeLength(ti->tile, rampsouth) + 1 ); const PalSpriteID *psid; bool drawfarpillar; if (transport_type != TRANSPORT_WATER) { BridgeType type = GetBridgeType(rampsouth); drawfarpillar = !HasBit(GetBridgeSpec(type)->flags, 0); uint base_offset; if (transport_type == TRANSPORT_RAIL) { base_offset = GetRailTypeInfo(GetRailType(rampsouth))->bridge_offset; } else { base_offset = 8; } psid = base_offset + GetBridgeSpriteTable(type, piece); } else { drawfarpillar = true; psid = _aqueduct_sprites; } if (axis != AXIS_X) psid += 4; int x = ti->x; int y = ti->y; uint bridge_z = GetBridgePixelHeight(rampsouth); int z = bridge_z - BRIDGE_Z_START; /* Add a bounding box that separates the bridge from things below it. */ AddSortableSpriteToDraw(SPR_EMPTY_BOUNDING_BOX, PAL_NONE, x, y, 16, 16, 1, bridge_z - TILE_HEIGHT + BB_Z_SEPARATOR); /* Draw Trambits as SpriteCombine */ if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine(); /* Draw floor and far part of bridge*/ if (!IsInvisibilitySet(TO_BRIDGES)) { if (axis == AXIS_X) { AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 1, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START); } else { AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 1, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 0, BRIDGE_Z_START); } } psid++; if (transport_type == TRANSPORT_ROAD) { RoadTypes rts = GetRoadTypes(rampsouth); if (HasBit(rts, ROADTYPE_TRAM)) { /* DrawBridgeTramBits() calls EndSpriteCombine() and StartSpriteCombine() */ DrawBridgeTramBits(x, y, bridge_z, axis ^ 1, HasBit(rts, ROADTYPE_ROAD), false); } else { EndSpriteCombine(); StartSpriteCombine(); } } else if (transport_type == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(rampsouth)); if (rti->UsesOverlay() && !IsInvisibilitySet(TO_BRIDGES)) { SpriteID surface = GetCustomRailSprite(rti, rampsouth, RTSG_BRIDGE, TCX_ON_BRIDGE); if (surface != 0) { AddSortableSpriteToDraw(surface + axis, PAL_NONE, x, y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES)); } } if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth)) { if (rti->UsesOverlay()) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES)); } else { AddSortableSpriteToDraw(axis == AXIS_X ? rti->base_sprites.single_x : rti->base_sprites.single_y, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES)); } } EndSpriteCombine(); if (HasCatenaryDrawn(GetRailType(rampsouth))) { DrawCatenaryOnBridge(ti); } } /* draw roof, the component of the bridge which is logically between the vehicle and the camera */ if (!IsInvisibilitySet(TO_BRIDGES)) { if (axis == AXIS_X) { y += 12; if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 16, 4, 0x28, z, IsTransparencySet(TO_BRIDGES), 0, 3, BRIDGE_Z_START); } else { x += 12; if (psid->sprite & SPRITE_MASK) AddSortableSpriteToDraw(psid->sprite, psid->pal, x, y, 4, 16, 0x28, z, IsTransparencySet(TO_BRIDGES), 3, 0, BRIDGE_Z_START); } } /* Draw TramFront as SpriteCombine */ if (transport_type == TRANSPORT_ROAD) EndSpriteCombine(); /* Do not draw anything more if bridges are invisible */ if (IsInvisibilitySet(TO_BRIDGES)) return; psid++; if (ti->z + 5 == z) { /* draw poles below for small bridges */ if (psid->sprite != 0) { SpriteID image = psid->sprite; SpriteID pal = psid->pal; if (IsTransparencySet(TO_BRIDGES)) { SetBit(image, PALETTE_MODIFIER_TRANSPARENT); pal = PALETTE_TO_TRANSPARENT; } DrawGroundSpriteAt(image, pal, x - ti->x, y - ti->y, z - ti->z); } } else { /* draw pillars below for high bridges */ DrawBridgePillars(psid, ti, axis, drawfarpillar, x, y, z); } } static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y) { int z; Slope tileh = GetTilePixelSlope(tile, &z); x &= 0xF; y &= 0xF; if (IsTunnel(tile)) { uint pos = (DiagDirToAxis(GetTunnelBridgeDirection(tile)) == AXIS_X ? y : x); /* In the tunnel entrance? */ if (5 <= pos && pos <= 10) return z; } else { // IsBridge(tile) DiagDirection dir = GetTunnelBridgeDirection(tile); uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x); z += ApplyPixelFoundationToSlope(GetBridgeFoundation(tileh, DiagDirToAxis(dir)), &tileh); /* On the bridge ramp? */ if (5 <= pos && pos <= 10) { int delta; if (tileh != SLOPE_FLAT) return z + TILE_HEIGHT; switch (dir) { default: NOT_REACHED(); case DIAGDIR_NE: delta = (TILE_SIZE - 1 - x) / 2; break; case DIAGDIR_SE: delta = y / 2; break; case DIAGDIR_SW: delta = x / 2; break; case DIAGDIR_NW: delta = (TILE_SIZE - 1 - y) / 2; break; } return z + 1 + delta; } } return z + GetPartialPixelZ(x, y, tileh); } static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh) { return IsTunnel(tile) ? FOUNDATION_NONE : GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(tile))); } static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td) { TransportType tt = GetTunnelBridgeTransportType(tile); if (IsTunnel(tile)) { td->str = (tt == TRANSPORT_RAIL) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD; } else { // IsBridge(tile) td->str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt]; } td->owner[0] = GetTileOwner(tile); Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; RoadTypes rts = GetRoadTypes(tile); if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); /* Is there a mix of owners? */ if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { uint i = 1; if (road_owner != INVALID_OWNER) { td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; td->owner[i] = road_owner; i++; } if (tram_owner != INVALID_OWNER) { td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; td->owner[i] = tram_owner; } } if (tt == TRANSPORT_RAIL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); td->rail_speed = rti->max_speed; if (!IsTunnel(tile)) { uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed; if (td->rail_speed == 0 || spd < td->rail_speed) { td->rail_speed = spd; } } } else if (tt == TRANSPORT_ROAD && !IsTunnel(tile)) { td->road_speed = GetBridgeSpec(GetBridgeType(tile))->speed; } } static void TileLoop_TunnelBridge(TileIndex tile) { bool snow_or_desert = HasTunnelBridgeSnowOrDesert(tile); switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: { /* As long as we do not have a snow density, we want to use the density * from the entry edge. For tunnels this is the lowest point for bridges the highest point. * (Independent of foundations) */ int z = IsBridge(tile) ? GetTileMaxZ(tile) : GetTileZ(tile); if (snow_or_desert != (z > GetSnowLine())) { SetTunnelBridgeSnowOrDesert(tile, !snow_or_desert); MarkTileDirtyByTile(tile); } break; } case LT_TROPIC: if (GetTropicZone(tile) == TROPICZONE_DESERT && !snow_or_desert) { SetTunnelBridgeSnowOrDesert(tile, true); MarkTileDirtyByTile(tile); } break; default: break; } } static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { TransportType transport_type = GetTunnelBridgeTransportType(tile); if (transport_type != mode || (transport_type == TRANSPORT_ROAD && (GetRoadTypes(tile) & sub_mode) == 0)) return 0; DiagDirection dir = GetTunnelBridgeDirection(tile); if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0; return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE); } static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner) { TileIndex other_end = GetOtherTunnelBridgeEnd(tile); /* Set number of pieces to zero if it's the southern tile as we * don't want to update the infrastructure counts twice. */ uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0; for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { /* Update all roadtypes, no matter if they are present */ if (GetRoadOwner(tile, rt) == old_owner) { if (HasBit(GetRoadTypes(tile), rt)) { /* Update company infrastructure counts. A full diagonal road tile has two road bits. * No need to dirty windows here, we'll redraw the whole screen anyway. */ Company::Get(old_owner)->infrastructure.road[rt] -= num_pieces * 2; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_pieces * 2; } SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } if (!IsTileOwner(tile, old_owner)) return; /* Update company infrastructure counts for rail and water as well. * No need to dirty windows here, we'll redraw the whole screen anyway. */ TransportType tt = GetTunnelBridgeTransportType(tile); Company *old = Company::Get(old_owner); if (tt == TRANSPORT_RAIL) { old->infrastructure.rail[GetRailType(tile)] -= num_pieces; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces; } else if (tt == TRANSPORT_WATER) { old->infrastructure.water -= num_pieces; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces; } if (new_owner != INVALID_OWNER) { SetTileOwner(tile, new_owner); } else { if (tt == TRANSPORT_RAIL) { /* Since all of our vehicles have been removed, it is safe to remove the rail * bridge / tunnel. */ CommandCost ret = DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); assert(ret.Succeeded()); } else { /* In any other case, we can safely reassign the ownership to OWNER_NONE. */ SetTileOwner(tile, OWNER_NONE); } } } /** * Frame when the 'enter tunnel' sound should be played. This is the second * frame on a tile, so the sound is played shortly after entering the tunnel * tile, while the vehicle is still visible. */ static const byte TUNNEL_SOUND_FRAME = 1; /** * Frame when a vehicle should be hidden in a tunnel with a certain direction. * This differs per direction, because of visibility / bounding box issues. * Note that direction, in this case, is the direction leading into the tunnel. * When entering a tunnel, hide the vehicle when it reaches the given frame. * When leaving a tunnel, show the vehicle when it is one frame further * to the 'outside', i.e. at (TILE_SIZE-1) - (frame) + 1 */ extern const byte _tunnel_visibility_frame[DIAGDIR_END] = {12, 8, 8, 12}; static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y) { int z = GetSlopePixelZ(x, y) - v->z_pos; if (abs(z) > 2) return VETSB_CANNOT_ENTER; /* Direction into the wormhole */ const DiagDirection dir = GetTunnelBridgeDirection(tile); /* Direction of the vehicle */ const DiagDirection vdir = DirToDiagDir(v->direction); /* New position of the vehicle on the tile */ byte pos = (DiagDirToAxis(vdir) == AXIS_X ? x : y) & TILE_UNIT_MASK; /* Number of units moved by the vehicle since entering the tile */ byte frame = (vdir == DIAGDIR_NE || vdir == DIAGDIR_NW) ? TILE_SIZE - 1 - pos : pos; if (IsTunnel(tile)) { if (v->type == VEH_TRAIN) { Train *t = Train::From(v); if (t->track != TRACK_BIT_WORMHOLE && dir == vdir) { if (t->IsFrontEngine() && frame == TUNNEL_SOUND_FRAME) { if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) { SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v); } return VETSB_CONTINUE; } if (frame == _tunnel_visibility_frame[dir]) { t->tile = tile; t->track = TRACK_BIT_WORMHOLE; t->vehstatus |= VS_HIDDEN; return VETSB_ENTERED_WORMHOLE; } } if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) { /* We're at the tunnel exit ?? */ t->tile = tile; t->track = DiagDirToDiagTrackBits(vdir); assert(t->track); t->vehstatus &= ~VS_HIDDEN; return VETSB_ENTERED_WORMHOLE; } } else if (v->type == VEH_ROAD) { RoadVehicle *rv = RoadVehicle::From(v); /* Enter tunnel? */ if (rv->state != RVSB_WORMHOLE && dir == vdir) { if (frame == _tunnel_visibility_frame[dir]) { /* Frame should be equal to the next frame number in the RV's movement */ assert(frame == rv->frame + 1); rv->tile = tile; rv->state = RVSB_WORMHOLE; rv->vehstatus |= VS_HIDDEN; return VETSB_ENTERED_WORMHOLE; } else { return VETSB_CONTINUE; } } /* We're at the tunnel exit ?? */ if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) { rv->tile = tile; rv->state = DiagDirToDiagTrackdir(vdir); rv->frame = frame; rv->vehstatus &= ~VS_HIDDEN; return VETSB_ENTERED_WORMHOLE; } } } else { // IsBridge(tile) if (v->type != VEH_SHIP) { /* modify speed of vehicle */ uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed; if (v->type == VEH_ROAD) spd *= 2; Vehicle *first = v->First(); first->cur_speed = min(first->cur_speed, spd); } if (vdir == dir) { /* Vehicle enters bridge at the last frame inside this tile. */ if (frame != TILE_SIZE - 1) return VETSB_CONTINUE; switch (v->type) { case VEH_TRAIN: { Train *t = Train::From(v); t->track = TRACK_BIT_WORMHOLE; ClrBit(t->gv_flags, GVF_GOINGUP_BIT); ClrBit(t->gv_flags, GVF_GOINGDOWN_BIT); break; } case VEH_ROAD: { RoadVehicle *rv = RoadVehicle::From(v); rv->state = RVSB_WORMHOLE; /* There are no slopes inside bridges / tunnels. */ ClrBit(rv->gv_flags, GVF_GOINGUP_BIT); ClrBit(rv->gv_flags, GVF_GOINGDOWN_BIT); break; } case VEH_SHIP: Ship::From(v)->state = TRACK_BIT_WORMHOLE; break; default: NOT_REACHED(); } return VETSB_ENTERED_WORMHOLE; } else if (vdir == ReverseDiagDir(dir)) { v->tile = tile; switch (v->type) { case VEH_TRAIN: { Train *t = Train::From(v); if (t->track == TRACK_BIT_WORMHOLE) { t->track = DiagDirToDiagTrackBits(vdir); return VETSB_ENTERED_WORMHOLE; } break; } case VEH_ROAD: { RoadVehicle *rv = RoadVehicle::From(v); if (rv->state == RVSB_WORMHOLE) { rv->state = DiagDirToDiagTrackdir(vdir); rv->frame = 0; return VETSB_ENTERED_WORMHOLE; } break; } case VEH_SHIP: { Ship *ship = Ship::From(v); if (ship->state == TRACK_BIT_WORMHOLE) { ship->state = DiagDirToDiagTrackBits(vdir); return VETSB_ENTERED_WORMHOLE; } break; } default: NOT_REACHED(); } } } return VETSB_CONTINUE; } static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() && IsBridge(tile) && GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) { DiagDirection direction = GetTunnelBridgeDirection(tile); Axis axis = DiagDirToAxis(direction); CommandCost res; int z_old; Slope tileh_old = GetTileSlope(tile, &z_old); /* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */ if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) { CheckBridgeSlopeSouth(axis, &tileh_old, &z_old); res = CheckBridgeSlopeSouth(axis, &tileh_new, &z_new); } else { CheckBridgeSlopeNorth(axis, &tileh_old, &z_old); res = CheckBridgeSlopeNorth(axis, &tileh_new, &z_new); } /* Surface slope is valid and remains unchanged? */ if (res.Succeeded() && (z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } extern const TileTypeProcs _tile_type_tunnelbridge_procs = { DrawTile_TunnelBridge, // draw_tile_proc GetSlopePixelZ_TunnelBridge, // get_slope_z_proc ClearTile_TunnelBridge, // clear_tile_proc NULL, // add_accepted_cargo_proc GetTileDesc_TunnelBridge, // get_tile_desc_proc GetTileTrackStatus_TunnelBridge, // get_tile_track_status_proc NULL, // click_tile_proc NULL, // animate_tile_proc TileLoop_TunnelBridge, // tile_loop_proc ChangeTileOwner_TunnelBridge, // change_tile_owner_proc NULL, // add_produced_cargo_proc VehicleEnter_TunnelBridge, // vehicle_enter_tile_proc GetFoundation_TunnelBridge, // get_foundation_proc TerraformTile_TunnelBridge, // terraform_tile_proc }; openttd-1.5.3/src/textfile_gui.h0000644000000000000000000000462112627373442015340 0ustar rootroot/* $Id: textfile_gui.h 25816 2013-10-06 11:29:14Z frosch $ */ /* * 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 textfile_gui.h GUI functions related to textfiles. */ #ifndef TEXTFILE_GUI_H #define TEXTFILE_GUI_H #include "fileio_type.h" #include "strings_func.h" #include "textfile_type.h" #include "window_gui.h" const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filename); /** Window for displaying a textfile */ struct TextfileWindow : public Window, MissingGlyphSearcher { TextfileType file_type; ///< Type of textfile to view. Scrollbar *vscroll; ///< Vertical scrollbar. Scrollbar *hscroll; ///< Horizontal scrollbar. char *text; ///< Lines of text from the NewGRF's textfile. SmallVector lines; ///< #text, split into lines in a table with lines. uint search_iterator; ///< Iterator for the font check search. static const int TOP_SPACING = WD_FRAMETEXT_TOP; ///< Additional spacing at the top of the #WID_TF_BACKGROUND widget. static const int BOTTOM_SPACING = WD_FRAMETEXT_BOTTOM; ///< Additional spacing at the bottom of the #WID_TF_BACKGROUND widget. TextfileWindow(TextfileType file_type); virtual ~TextfileWindow(); virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize); virtual void OnClick(Point pt, int widget, int click_count); virtual void DrawWidget(const Rect &r, int widget) const; virtual void OnResize(); virtual void Reset(); virtual FontSize DefaultSize(); virtual const char *NextString(); virtual bool Monospace(); virtual void SetFontNames(FreeTypeSettings *settings, const char *font_name); virtual void LoadTextfile(const char *textfile, Subdirectory dir); private: uint GetContentHeight(); void SetupScrollbars(); }; #endif /* TEXTFILE_GUI_H */ openttd-1.5.3/src/newgrf_canal.h0000644000000000000000000000302512627373442015273 0ustar rootroot/* $Id: newgrf_canal.h 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 newgrf_canal.h Handling of NewGRF canals. */ #ifndef NEWGRF_CANAL_H #define NEWGRF_CANAL_H #include "newgrf.h" #include "tile_type.h" /** Flags controlling the display of canals. */ enum CanalFeatureFlag { CFF_HAS_FLAT_SPRITE = 0, ///< Additional flat ground sprite in the beginning. }; /** Information about a water feature. */ struct WaterFeature { const SpriteGroup *group; ///< Sprite group to start resolving. const GRFFile *grffile; ///< NewGRF where 'group' belongs to. uint8 callback_mask; ///< Bitmask of canal callbacks that have to be called. uint8 flags; ///< Flags controlling display. }; /** Table of canal 'feature' sprite groups */ extern WaterFeature _water_feature[CF_END]; SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile); uint GetCanalSpriteOffset(CanalFeature feature, TileIndex tile, uint cur_offset); #endif /* NEWGRF_CANAL_H */ openttd-1.5.3/src/bridge.h0000644000000000000000000000555512627373434014114 0ustar rootroot/* $Id: bridge.h 22413 2011-05-02 20:59:54Z rubidium $ */ /* * 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 bridge.h Header file for bridges */ #ifndef BRIDGE_H #define BRIDGE_H #include "gfx_type.h" #include "tile_cmd.h" /** * This enum is related to the definition of bridge pieces, * which is used to determine the proper sprite table to use * while drawing a given bridge part. */ enum BridgePieces { BRIDGE_PIECE_NORTH = 0, BRIDGE_PIECE_SOUTH, BRIDGE_PIECE_INNER_NORTH, BRIDGE_PIECE_INNER_SOUTH, BRIDGE_PIECE_MIDDLE_ODD, BRIDGE_PIECE_MIDDLE_EVEN, BRIDGE_PIECE_HEAD, BRIDGE_PIECE_INVALID, }; DECLARE_POSTFIX_INCREMENT(BridgePieces) static const uint MAX_BRIDGES = 13; ///< Maximal number of available bridge specs. typedef uint BridgeType; ///< Bridge spec number. /** * Struct containing information about a single bridge type */ struct BridgeSpec { Year avail_year; ///< the year where it becomes available byte min_length; ///< the minimum length (not counting start and end tile) uint16 max_length; ///< the maximum length (not counting start and end tile) uint16 price; ///< the price multiplier uint16 speed; ///< maximum travel speed (1 unit = 1/1.6 mph = 1 km-ish/h) SpriteID sprite; ///< the sprite which is used in the GUI PaletteID pal; ///< the palette which is used in the GUI StringID material; ///< the string that contains the bridge description StringID transport_name[2]; ///< description of the bridge, when built for road or rail PalSpriteID **sprite_table; ///< table of sprites for drawing the bridge byte flags; ///< bit 0 set: disable drawing of far pillars. }; extern BridgeSpec _bridge[MAX_BRIDGES]; Foundation GetBridgeFoundation(Slope tileh, Axis axis); bool HasBridgeFlatRamp(Slope tileh, Axis axis); /** * Get the specification of a bridge type. * @param i The type of bridge to get the specification for. * @return The specification. */ static inline const BridgeSpec *GetBridgeSpec(BridgeType i) { assert(i < lengthof(_bridge)); return &_bridge[i]; } void DrawBridgeMiddle(const TileInfo *ti); CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlag flags = DC_NONE); int CalcBridgeLenCostFactor(int x); void ResetBridges(); #endif /* BRIDGE_H */ openttd-1.5.3/src/newgrf_engine.h0000644000000000000000000001266012627373441015466 0ustar rootroot/* $Id: newgrf_engine.h 26388 2014-03-03 20:02:31Z frosch $ */ /* * 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 newgrf_engine.h Functions for NewGRF engines. */ #ifndef NEWGRF_ENGINE_H #define NEWGRF_ENGINE_H #include "direction_type.h" #include "newgrf_callbacks.h" #include "newgrf_properties.h" #include "vehicle_type.h" #include "engine_type.h" #include "gfx_type.h" #include "newgrf_spritegroup.h" /** Resolver for a vehicle scope. */ struct VehicleScopeResolver : public ScopeResolver { const struct Vehicle *v; ///< The vehicle being resolved. EngineID self_type; ///< Type of the vehicle. bool info_view; ///< Indicates if the item is being drawn in an info window. VehicleScopeResolver(ResolverObject &ro, EngineID engine_type, const Vehicle *v, bool info_view); void SetVehicle(const Vehicle *v) { this->v = v; } /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; /* virtual */ uint32 GetTriggers() const; /* virtual */ void SetTriggers(int triggers) const; }; /** Resolver for a vehicle (chain) */ struct VehicleResolverObject : public ResolverObject { /** Application of 'wagon overrides'. */ enum WagonOverride { WO_NONE, //!< Resolve no wagon overrides. WO_UNCACHED, //!< Resolve wagon overrides. WO_CACHED, //!< Resolve wagon overrides using TrainCache::cached_override. WO_SELF, //!< Resolve self-override (helicopter rotors and such). }; VehicleScopeResolver self_scope; ///< Scope resolver for the indicated vehicle. VehicleScopeResolver parent_scope; ///< Scope resolver for its parent vehicle. VehicleScopeResolver relative_scope; ///< Scope resolver for an other vehicle in the chain. byte cached_relative_count; ///< Relative position of the other vehicle. VehicleResolverObject(EngineID engine_type, const Vehicle *v, WagonOverride wagon_override, bool info_view = false, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0); /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; }; static const uint TRAININFO_DEFAULT_VEHICLE_WIDTH = 29; static const uint ROADVEHINFO_DEFAULT_VEHICLE_WIDTH = 32; static const uint VEHICLEINFO_FULL_VEHICLE_WIDTH = 32; void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const struct SpriteGroup *group, EngineID *train_id, uint trains); const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, EngineID overriding_engine); void SetCustomEngineSprites(EngineID engine, byte cargo, const struct SpriteGroup *group); SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type); SpriteID GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type); #define GetCustomRotorSprite(v, i, image_type) GetRotorOverrideSprite(v->engine_type, v, i, image_type) #define GetCustomRotorIcon(et, image_type) GetRotorOverrideSprite(et, NULL, true, image_type) /* Forward declaration of GRFFile, to avoid unnecessary inclusion of newgrf.h * elsewhere... */ struct GRFFile; void SetEngineGRF(EngineID engine, const struct GRFFile *file); uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v); uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent); bool UsesWagonOverride(const Vehicle *v); #define GetCustomVehicleSprite(v, direction, image_type) GetCustomEngineSprite(v->engine_type, v, direction, image_type) #define GetCustomVehicleIcon(et, direction, image_type) GetCustomEngineSprite(et, NULL, direction, image_type) /* Handler to Evaluate callback 36. If the callback fails (i.e. most of the * time) orig_value is returned */ uint GetVehicleProperty(const Vehicle *v, PropertyID property, uint orig_value); uint GetEngineProperty(EngineID engine, PropertyID property, uint orig_value, const Vehicle *v = NULL); enum VehicleTrigger { VEHICLE_TRIGGER_NEW_CARGO = 0x01, /* Externally triggered only for the first vehicle in chain */ VEHICLE_TRIGGER_DEPOT = 0x02, /* Externally triggered only for the first vehicle in chain, only if whole chain is empty */ VEHICLE_TRIGGER_EMPTY = 0x04, /* Not triggered externally (called for the whole chain if we got NEW_CARGO) */ VEHICLE_TRIGGER_ANY_NEW_CARGO = 0x08, /* Externally triggered for each vehicle in chain */ VEHICLE_TRIGGER_CALLBACK_32 = 0x10, }; void TriggerVehicle(Vehicle *veh, VehicleTrigger trigger); void UnloadWagonOverrides(Engine *e); void AlterVehicleListOrder(EngineID engine, uint target); void CommitVehicleListOrderChanges(); EngineID GetNewEngineID(const GRFFile *file, VehicleType type, uint16 internal_id); #endif /* NEWGRF_ENGINE_H */ openttd-1.5.3/src/newgrf_object.cpp0000644000000000000000000004541112627373435016025 0ustar rootroot/* $Id: newgrf_object.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_object.cpp Handling of object NewGRFs. */ #include "stdafx.h" #include "company_base.h" #include "company_func.h" #include "debug.h" #include "genworld.h" #include "newgrf_class_func.h" #include "newgrf_object.h" #include "newgrf_sound.h" #include "object_base.h" #include "object_map.h" #include "tile_cmd.h" #include "town.h" #include "water.h" #include "newgrf_animation_base.h" #include "safeguards.h" /** The override manager for our objects. */ ObjectOverrideManager _object_mngr(NEW_OBJECT_OFFSET, NUM_OBJECTS, INVALID_OBJECT_TYPE); extern const ObjectSpec _original_objects[NEW_OBJECT_OFFSET]; /** All the object specifications. */ ObjectSpec _object_specs[NUM_OBJECTS]; /** * Get the specification associated with a specific ObjectType. * @param index The object type to fetch. * @return The specification. */ /* static */ const ObjectSpec *ObjectSpec::Get(ObjectType index) { assert(index < NUM_OBJECTS); return &_object_specs[index]; } /** * Get the specification associated with a tile. * @param tile The tile to fetch the data for. * @return The specification. */ /* static */ const ObjectSpec *ObjectSpec::GetByTile(TileIndex tile) { return ObjectSpec::Get(GetObjectType(tile)); } /** * Check whether the object might be available at some point in this game with the current game mode. * @return true if it might be available. */ bool ObjectSpec::IsEverAvailable() const { return this->enabled && HasBit(this->climate, _settings_game.game_creation.landscape) && (this->flags & ((_game_mode != GM_EDITOR && !_generating_world) ? OBJECT_FLAG_ONLY_IN_SCENEDIT : OBJECT_FLAG_ONLY_IN_GAME)) == 0; } /** * Check whether the object was available at some point in the past or present in this game with the current game mode. * @return true if it was ever or is available. */ bool ObjectSpec::WasEverAvailable() const { return this->IsEverAvailable() && _date > this->introduction_date; } /** * Check whether the object is available at this time. * @return true if it is available. */ bool ObjectSpec::IsAvailable() const { return this->WasEverAvailable() && (_date < this->end_of_life_date || this->end_of_life_date < this->introduction_date + 365); } /** * Gets the index of this spec. * @return The index. */ uint ObjectSpec::Index() const { return this - _object_specs; } /** This function initialize the spec arrays of objects. */ void ResetObjects() { /* Clean the pool. */ MemSetT(_object_specs, 0, lengthof(_object_specs)); /* And add our originals. */ MemCpyT(_object_specs, _original_objects, lengthof(_original_objects)); for (uint16 i = 0; i < lengthof(_original_objects); i++) { _object_specs[i].grf_prop.local_id = i; } } template /* static */ void NewGRFClass::InsertDefaults() { ObjectClassID cls = ObjectClass::Allocate('LTHS'); ObjectClass::Get(cls)->name = STR_OBJECT_CLASS_LTHS; _object_specs[OBJECT_LIGHTHOUSE].cls_id = cls; ObjectClass::Assign(&_object_specs[OBJECT_LIGHTHOUSE]); cls = ObjectClass::Allocate('TRNS'); ObjectClass::Get(cls)->name = STR_OBJECT_CLASS_TRNS; _object_specs[OBJECT_TRANSMITTER].cls_id = cls; ObjectClass::Assign(&_object_specs[OBJECT_TRANSMITTER]); } template bool NewGRFClass::IsUIAvailable(uint index) const { return this->GetSpec(index)->IsEverAvailable(); } INSTANTIATE_NEWGRF_CLASS_METHODS(ObjectClass, ObjectSpec, ObjectClassID, OBJECT_CLASS_MAX) /** * Constructor of an object scope resolver. * @param ro Surrounding resolver. * @param obj Object being resolved. * @param tile %Tile of the object. * @param view View of the object. */ ObjectScopeResolver::ObjectScopeResolver(ResolverObject &ro, Object *obj, TileIndex tile, uint8 view) : ScopeResolver(ro) { this->obj = obj; this->tile = tile; this->view = view; } /* virtual */ uint32 ObjectScopeResolver::GetRandomBits() const { return IsValidTile(this->tile) && IsTileType(this->tile, MP_OBJECT) ? GetObjectRandomBits(this->tile) : 0; } /** * Make an analysis of a tile and get the object type. * @param tile TileIndex of the tile to query * @param cur_grfid GRFID of the current callback chain * @return value encoded as per NFO specs */ static uint32 GetObjectIDAtOffset(TileIndex tile, uint32 cur_grfid) { if (!IsTileType(tile, MP_OBJECT)) { return 0xFFFF; } const Object *o = Object::GetByTile(tile); const ObjectSpec *spec = ObjectSpec::Get(o->type); /* Default objects have no associated NewGRF file */ if (spec->grf_prop.grffile == NULL) { return 0xFFFE; // Defined in another grf file } if (spec->grf_prop.grffile->grfid == cur_grfid) { // same object, same grf ? return spec->grf_prop.local_id | o->view << 16; } return 0xFFFE; // Defined in another grf file } /** * Based on newhouses equivalent, but adapted for newobjects * @param parameter from callback. It's in fact a pair of coordinates * @param tile TileIndex from which the callback was initiated * @param index of the object been queried for * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8. * @return a construction of bits obeying the newgrf format */ static uint32 GetNearbyObjectTileInformation(byte parameter, TileIndex tile, ObjectID index, bool grf_version8) { if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required bool is_same_object = (IsTileType(tile, MP_OBJECT) && GetObjectIndex(tile) == index); return GetNearbyTileInformation(tile, grf_version8) | (is_same_object ? 1 : 0) << 8; } /** * Get the closest object of a given type. * @param tile The tile to start searching from. * @param type The type of the object to search for. * @param current The current object (to ignore). * @return The distance to the closest object. */ static uint32 GetClosestObject(TileIndex tile, ObjectType type, const Object *current) { uint32 best_dist = UINT32_MAX; const Object *o; FOR_ALL_OBJECTS(o) { if (o->type != type || o == current) continue; best_dist = min(best_dist, DistanceManhattan(tile, o->location.tile)); } return best_dist; } /** * Implementation of var 65 * @param local_id Parameter given to the callback, which is the set id, or the local id, in our terminology. * @param grfid The object's GRFID. * @param tile The tile to look from. * @param current Object for which the inquiry is made * @return The formatted answer to the callback : rr(reserved) cc(count) dddd(manhattan distance of closest sister) */ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, TileIndex tile, const Object *current) { uint32 grf_id = GetRegister(0x100); // Get the GRFID of the definition to look for in register 100h uint32 idx; /* Determine what will be the object type to look for */ switch (grf_id) { case 0: // this is a default object type idx = local_id; break; case 0xFFFFFFFF: // current grf grf_id = grfid; /* FALL THROUGH */ default: // use the grfid specified in register 100h idx = _object_mngr.GetID(local_id, grf_id); break; } /* If the object type is invalid, there is none and the closest is far away. */ if (idx >= NUM_OBJECTS) return 0 | 0xFFFF; return Object::GetTypeCount(idx) << 16 | min(GetClosestObject(tile, idx, current), 0xFFFF); } /** Used by the resolver to get values for feature 0F deterministic spritegroups. */ /* virtual */ uint32 ObjectScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { /* We get the town from the object, or we calculate the closest * town if we need to when there's no object. */ const Town *t = NULL; if (this->obj == NULL) { switch (variable) { /* Allow these when there's no object. */ case 0x41: case 0x60: case 0x61: case 0x62: case 0x64: break; /* Allow these, but find the closest town. */ case 0x45: case 0x46: if (!IsValidTile(this->tile)) goto unhandled; t = ClosestTownFromTile(this->tile, UINT_MAX); break; /* Construction date */ case 0x42: return _date; /* Object founder information */ case 0x44: return _current_company; /* Object view */ case 0x48: return this->view; /* * Disallow the rest: * 0x40: Relative position is passed as parameter during construction. * 0x43: Animation counter is only for actual tiles. * 0x47: Object colour is only valid when its built. * 0x63: Animation counter of nearby tile, see above. */ default: goto unhandled; } /* If there's an invalid tile, then we don't have enough information at all. */ if (!IsValidTile(this->tile)) goto unhandled; } else { t = this->obj->town; } switch (variable) { /* Relative position. */ case 0x40: { uint offset = this->tile - this->obj->location.tile; uint offset_x = TileX(offset); uint offset_y = TileY(offset); return offset_y << 20 | offset_x << 16 | offset_y << 8 | offset_x; } /* Tile information. */ case 0x41: return GetTileSlope(this->tile) << 8 | GetTerrainType(this->tile); /* Construction date */ case 0x42: return this->obj->build_date; /* Animation counter */ case 0x43: return GetAnimationFrame(this->tile); /* Object founder information */ case 0x44: return GetTileOwner(this->tile); /* Get town zone and Manhattan distance of closest town */ case 0x45: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceManhattan(this->tile, t->xy), 0xFFFF); /* Get square of Euclidian distance of closes town */ case 0x46: return GetTownRadiusGroup(t, this->tile) << 16 | min(DistanceSquare(this->tile, t->xy), 0xFFFF); /* Object colour */ case 0x47: return this->obj->colour; /* Object view */ case 0x48: return this->obj->view; /* Get object ID at offset param */ case 0x60: return GetObjectIDAtOffset(GetNearbyTile(parameter, this->tile), this->ro.grffile->grfid); /* Get random tile bits at offset param */ case 0x61: { TileIndex tile = GetNearbyTile(parameter, this->tile); return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetObjectRandomBits(tile) : 0; } /* Land info of nearby tiles */ case 0x62: return GetNearbyObjectTileInformation(parameter, this->tile, this->obj == NULL ? INVALID_OBJECT : this->obj->index, this->ro.grffile->grf_version >= 8); /* Animation counter of nearby tile */ case 0x63: { TileIndex tile = GetNearbyTile(parameter, this->tile); return (IsTileType(tile, MP_OBJECT) && Object::GetByTile(tile) == this->obj) ? GetAnimationFrame(tile) : 0; } /* Count of object, distance of closest instance */ case 0x64: return GetCountAndDistanceOfClosestInstance(parameter, this->ro.grffile->grfid, this->tile, this->obj); } unhandled: DEBUG(grf, 1, "Unhandled object variable 0x%X", variable); *available = false; return UINT_MAX; } /** * Constructor of the object resolver. * @param obj Object being resolved. * @param tile %Tile of the object. * @param view View of the object. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ ObjectResolverObject::ObjectResolverObject(const ObjectSpec *spec, Object *obj, TileIndex tile, uint8 view, CallbackID callback, uint32 param1, uint32 param2) : ResolverObject(spec->grf_prop.grffile, callback, param1, param2), object_scope(*this, obj, tile, view) { this->town_scope = NULL; this->root_spritegroup = (obj == NULL && spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] != NULL) ? spec->grf_prop.spritegroup[CT_PURCHASE_OBJECT] : spec->grf_prop.spritegroup[0]; } ObjectResolverObject::~ObjectResolverObject() { delete this->town_scope; } /** * Get the town resolver scope that belongs to this object resolver. * On the first call, the town scope is created (if possible). * @return Town scope, if available. */ TownScopeResolver *ObjectResolverObject::GetTown() { if (this->town_scope == NULL) { Town *t; if (this->object_scope.obj != NULL) { t = this->object_scope.obj->town; } else { t = ClosestTownFromTile(this->object_scope.tile, UINT_MAX); } if (t == NULL) return NULL; this->town_scope = new TownScopeResolver(*this, t, this->object_scope.obj == NULL); } return this->town_scope; } /** * Perform a callback for an object. * @param callback The callback to perform. * @param param1 The first parameter to pass to the NewGRF. * @param param2 The second parameter to pass to the NewGRF. * @param spec The specification of the object / the entry point. * @param o The object to call the callback for. * @param tile The tile the callback is called for. * @param view The view of the object (only used when o == NULL). * @return The result of the callback. */ uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view) { ObjectResolverObject object(spec, o, tile, view, callback, param1, param2); return object.ResolveCallback(); } /** * Draw an group of sprites on the map. * @param ti Information about the tile to draw on. * @param group The group of sprites to draw. * @param spec Object spec to draw. */ static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, const ObjectSpec *spec) { const DrawTileSprites *dts = group->ProcessRegisters(NULL); PaletteID palette = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START) + Object::GetByTile(ti->tile)->colour; SpriteID image = dts->ground.sprite; PaletteID pal = dts->ground.pal; if (GB(image, 0, SPRITE_WIDTH) != 0) { /* If the ground sprite is the default flat water sprite, draw also canal/river borders * Do not do this if the tile's WaterClass is 'land'. */ if ((image == SPR_FLAT_WATER_TILE || spec->flags & OBJECT_FLAG_DRAW_WATER) && IsTileOnWater(ti->tile)) { DrawWaterClassGround(ti); } else { DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette)); } } DrawNewGRFTileSeq(ti, dts, TO_STRUCTURES, 0, palette); } /** * Draw an object on the map. * @param ti Information about the tile to draw on. * @param spec Object spec to draw. */ void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec) { Object *o = Object::GetByTile(ti->tile); ObjectResolverObject object(spec, o, ti->tile); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->type != SGT_TILELAYOUT) return; DrawTileLayout(ti, (const TileLayoutSpriteGroup *)group, spec); } /** * Draw representation of an object (tile) for GUI purposes. * @param x Position x of image. * @param y Position y of image. * @param spec Object spec to draw. * @param view The object's view. */ void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view) { ObjectResolverObject object(spec, NULL, INVALID_TILE, view); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->type != SGT_TILELAYOUT) return; const DrawTileSprites *dts = ((const TileLayoutSpriteGroup *)group)->ProcessRegisters(NULL); PaletteID palette; if (Company::IsValidID(_local_company)) { /* Get the colours of our company! */ if (spec->flags & OBJECT_FLAG_2CC_COLOUR) { const Livery *l = Company::Get(_local_company)->livery; palette = SPR_2CCMAP_BASE + l->colour1 + l->colour2 * 16; } else { palette = COMPANY_SPRITE_COLOUR(_local_company); } } else { /* There's no company, so just take the base palette. */ palette = (spec->flags & OBJECT_FLAG_2CC_COLOUR) ? SPR_2CCMAP_BASE : PALETTE_RECOLOUR_START; } SpriteID image = dts->ground.sprite; PaletteID pal = dts->ground.pal; if (GB(image, 0, SPRITE_WIDTH) != 0) { DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y); } DrawNewGRFTileSeqInGUI(x, y, dts, 0, palette); } /** * Perform a callback for an object. * @param callback The callback to perform. * @param param1 The first parameter to pass to the NewGRF. * @param param2 The second parameter to pass to the NewGRF. * @param spec The specification of the object / the entry point. * @param o The object to call the callback for. * @param tile The tile the callback is called for. * @param extra_data Ignored. * @return The result of the callback. */ uint16 StubGetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, int extra_data) { return GetObjectCallback(callback, param1, param2, spec, o, tile); } /** Helper class for animation control. */ struct ObjectAnimationBase : public AnimationBase { static const CallbackID cb_animation_speed = CBID_OBJECT_ANIMATION_SPEED; static const CallbackID cb_animation_next_frame = CBID_OBJECT_ANIMATION_NEXT_FRAME; static const ObjectCallbackMask cbm_animation_speed = CBM_OBJ_ANIMATION_SPEED; static const ObjectCallbackMask cbm_animation_next_frame = CBM_OBJ_ANIMATION_NEXT_FRAME; }; /** * Handle the animation of the object tile. * @param tile The tile to animate. */ void AnimateNewObjectTile(TileIndex tile) { const ObjectSpec *spec = ObjectSpec::GetByTile(tile); if (spec == NULL || !(spec->flags & OBJECT_FLAG_ANIMATION)) return; ObjectAnimationBase::AnimateTile(spec, Object::GetByTile(tile), tile, (spec->flags & OBJECT_FLAG_ANIM_RANDOM_BITS) != 0); } /** * Trigger the update of animation on a single tile. * @param o The object that got triggered. * @param tile The location of the triggered tile. * @param trigger The trigger that is triggered. * @param spec The spec associated with the object. */ void TriggerObjectTileAnimation(Object *o, TileIndex tile, ObjectAnimationTrigger trigger, const ObjectSpec *spec) { if (!HasBit(spec->animation.triggers, trigger)) return; ObjectAnimationBase::ChangeAnimationFrame(CBID_OBJECT_ANIMATION_START_STOP, spec, o, tile, Random(), trigger); } /** * Trigger the update of animation on a whole object. * @param o The object that got triggered. * @param trigger The trigger that is triggered. * @param spec The spec associated with the object. */ void TriggerObjectAnimation(Object *o, ObjectAnimationTrigger trigger, const ObjectSpec *spec) { if (!HasBit(spec->animation.triggers, trigger)) return; TILE_AREA_LOOP(tile, o->location) { TriggerObjectTileAnimation(o, tile, trigger, spec); } } openttd-1.5.3/src/gfx_func.h0000644000000000000000000002302412627373434014446 0ustar rootroot/* $Id: gfx_func.h 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 gfx_func.h Functions related to the gfx engine. */ /** * @defgroup dirty Dirty * * Handles the repaint of some part of the screen. * * Some places in the code are called functions which makes something "dirty". * This has nothing to do with making a Tile or Window darker or less visible. * This term comes from memory caching and is used to define an object must * be repaint. If some data of an object (like a Tile, Window, Vehicle, whatever) * are changed which are so extensive the object must be repaint its marked * as "dirty". The video driver repaint this object instead of the whole screen * (this is btw. also possible if needed). This is used to avoid a * flickering of the screen by the video driver constantly repainting it. * * This whole mechanism is controlled by an rectangle defined in #_invalid_rect. This * rectangle defines the area on the screen which must be repaint. If a new object * needs to be repainted this rectangle is extended to 'catch' the object on the * screen. At some point (which is normally uninteresting for patch writers) this * rectangle is send to the video drivers method * VideoDriver::MakeDirty and it is truncated back to an empty rectangle. At some * later point (which is uninteresting, too) the video driver * repaints all these saved rectangle instead of the whole screen and drop the * rectangle informations. Then a new round begins by marking objects "dirty". * * @see VideoDriver::MakeDirty * @see _invalid_rect * @see _screen */ #ifndef GFX_FUNC_H #define GFX_FUNC_H #include "gfx_type.h" #include "strings_type.h" #include "string_type.h" void GameLoop(); void CreateConsole(); extern byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down extern bool _fullscreen; extern byte _support8bpp; extern CursorVars _cursor; extern bool _ctrl_pressed; ///< Is Ctrl pressed? extern bool _shift_pressed; ///< Is Shift pressed? extern byte _fast_forward; extern bool _left_button_down; extern bool _left_button_clicked; extern bool _right_button_down; extern bool _right_button_clicked; extern DrawPixelInfo _screen; extern bool _screen_disable_anim; ///< Disable palette animation (important for 32bpp-anim blitter during giant screenshot) extern int _num_resolutions; extern Dimension _resolutions[32]; extern Dimension _cur_resolution; extern Palette _cur_palette; ///< Current palette void HandleKeypress(uint keycode, WChar key); void HandleTextInput(const char *str, bool marked = false, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL); void HandleCtrlChanged(); void HandleMouseEvents(); void CSleep(int milliseconds); void UpdateWindows(); void DrawMouseCursor(); void ScreenSizeChanged(); void GameSizeChanged(); void UndrawMouseCursor(); /** Size of the buffer used for drawing strings. */ static const int DRAW_STRING_BUFFER = 2048; void RedrawScreenRect(int left, int top, int right, int bottom); void GfxScroll(int left, int top, int width, int height, int xo, int yo); Dimension GetSpriteSize(SpriteID sprid, Point *offset = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); void DrawSpriteViewport(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL); void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub = NULL, ZoomLevel zoom = ZOOM_LVL_GUI); /** How to align the to-be drawn text. */ enum StringAlignment { SA_LEFT = 0 << 0, ///< Left align the text. SA_HOR_CENTER = 1 << 0, ///< Horizontally center the text. SA_RIGHT = 2 << 0, ///< Right align the text (must be a single bit). SA_HOR_MASK = 3 << 0, ///< Mask for horizontal alignment. SA_TOP = 0 << 2, ///< Top align the text. SA_VERT_CENTER = 1 << 2, ///< Vertically center the text. SA_BOTTOM = 2 << 2, ///< Bottom align the text. SA_VERT_MASK = 3 << 2, ///< Mask for vertical alignment. SA_CENTER = SA_HOR_CENTER | SA_VERT_CENTER, ///< Center both horizontally and vertically. SA_FORCE = 1 << 4, ///< Force the alignment, i.e. don't swap for RTL languages. }; DECLARE_ENUM_AS_BIT_SET(StringAlignment) int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); void DrawCharCentered(uint32 c, int x, int y, TextColour colour); void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE); void GfxDrawLine(int left, int top, int right, int bottom, int colour, int width = 1, int dash = 0); void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); Dimension GetStringBoundingBox(const char *str, FontSize start_fontsize = FS_NORMAL); Dimension GetStringBoundingBox(StringID strid); int GetStringHeight(const char *str, int maxw, FontSize fontsize = FS_NORMAL); int GetStringHeight(StringID str, int maxw); int GetStringLineCount(StringID str, int maxw); Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion); Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &suggestion); void LoadStringWidthTable(bool monospace = false); Point GetCharPosInString(const char *str, const char *ch, FontSize start_fontsize = FS_NORMAL); const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize = FS_NORMAL); void DrawDirtyBlocks(); void SetDirtyBlocks(int left, int top, int right, int bottom); void MarkWholeScreenDirty(); void GfxInitPalettes(); void CheckBlitter(); bool FillDrawPixelInfo(DrawPixelInfo *n, int left, int top, int width, int height); /* window.cpp */ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom); void SetMouseCursor(CursorID cursor, PaletteID pal); void SetAnimatedMouseCursor(const AnimCursor *table); void CursorTick(); void UpdateCursorSize(); bool ChangeResInGame(int w, int h); void SortResolutions(int count); bool ToggleFullScreen(bool fs); /* gfx.cpp */ byte GetCharacterWidth(FontSize size, uint32 key); byte GetDigitWidth(FontSize size = FS_NORMAL); void GetBroadestDigit(uint *front, uint *next, FontSize size = FS_NORMAL); int GetCharacterHeight(FontSize size); /** Height of characters in the small (#FS_SMALL) font. */ #define FONT_HEIGHT_SMALL (GetCharacterHeight(FS_SMALL)) /** Height of characters in the normal (#FS_NORMAL) font. */ #define FONT_HEIGHT_NORMAL (GetCharacterHeight(FS_NORMAL)) /** Height of characters in the large (#FS_LARGE) font. */ #define FONT_HEIGHT_LARGE (GetCharacterHeight(FS_LARGE)) /** Height of characters in the large (#FS_MONO) font. */ #define FONT_HEIGHT_MONO (GetCharacterHeight(FS_MONO)) extern DrawPixelInfo *_cur_dpi; TextColour GetContrastColour(uint8 background); /** * All 16 colour gradients * 8 colours per gradient from darkest (0) to lightest (7) */ extern byte _colour_gradient[COLOUR_END][8]; extern bool _palette_remap_grf[]; /** * Return the colour for a particular greyscale level. * @param level Intensity, 0 = black, 15 = white * @return colour */ #define GREY_SCALE(level) (level) static const uint8 PC_BLACK = GREY_SCALE(1); ///< Black palette colour. static const uint8 PC_DARK_GREY = GREY_SCALE(6); ///< Dark grey palette colour. static const uint8 PC_GREY = GREY_SCALE(10); ///< Grey palette colour. static const uint8 PC_WHITE = GREY_SCALE(15); ///< White palette colour. static const uint8 PC_VERY_DARK_RED = 0xB2; ///< Almost-black red palette colour. static const uint8 PC_DARK_RED = 0xB4; ///< Dark red palette colour. static const uint8 PC_RED = 0xB8; ///< Red palette colour. static const uint8 PC_VERY_DARK_BROWN = 0x56; ///< Almost-black brown palette colour. static const uint8 PC_ORANGE = 0xC2; ///< Orange palette colour. static const uint8 PC_YELLOW = 0xBF; ///< Yellow palette colour. static const uint8 PC_LIGHT_YELLOW = 0x44; ///< Light yellow palette colour. static const uint8 PC_VERY_LIGHT_YELLOW = 0x45; ///< Almost-white yellow palette colour. static const uint8 PC_GREEN = 0xD0; ///< Green palette colour. static const uint8 PC_DARK_BLUE = 0x9D; ///< Dark blue palette colour. static const uint8 PC_LIGHT_BLUE = 0x98; ///< Light blue palette colour. #endif /* GFX_FUNC_H */ openttd-1.5.3/src/cargo_type.h0000644000000000000000000000746012627373442015010 0ustar rootroot/* $Id: cargo_type.h 23826 2012-01-20 20:18:19Z rubidium $ */ /* * 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 cargo_type.h Types related to cargoes... */ #ifndef CARGO_TYPE_H #define CARGO_TYPE_H #include "core/enum_type.hpp" /** * Cargo slots to indicate a cargo type within a game. * Numbers are re-used between different climates. * @see CargoTypes */ typedef byte CargoID; /** Available types of cargo */ enum CargoTypes { /* Temperate */ CT_PASSENGERS = 0, CT_COAL = 1, CT_MAIL = 2, CT_OIL = 3, CT_LIVESTOCK = 4, CT_GOODS = 5, CT_GRAIN = 6, CT_WOOD = 7, CT_IRON_ORE = 8, CT_STEEL = 9, CT_VALUABLES = 10, /* Arctic */ CT_WHEAT = 6, CT_HILLY_UNUSED = 8, CT_PAPER = 9, CT_GOLD = 10, CT_FOOD = 11, /* Tropic */ CT_RUBBER = 1, CT_FRUIT = 4, CT_MAIZE = 6, CT_COPPER_ORE = 8, CT_WATER = 9, CT_DIAMONDS = 10, /* Toyland */ CT_SUGAR = 1, CT_TOYS = 3, CT_BATTERIES = 4, CT_CANDY = 5, CT_TOFFEE = 6, CT_COLA = 7, CT_COTTON_CANDY = 8, CT_BUBBLES = 9, CT_PLASTIC = 10, CT_FIZZY_DRINKS = 11, NUM_CARGO = 32, ///< Maximal number of cargo types in a game. CT_AUTO_REFIT = 0xFD, ///< Automatically choose cargo type when doing auto refitting. CT_NO_REFIT = 0xFE, ///< Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-new). CT_INVALID = 0xFF, ///< Invalid cargo type. }; /** Class for storing amounts of cargo */ struct CargoArray { private: uint amount[NUM_CARGO]; ///< Amount of each type of cargo. public: /** Default constructor. */ inline CargoArray() { this->Clear(); } /** Reset all entries. */ inline void Clear() { memset(this->amount, 0, sizeof(this->amount)); } /** * Read/write access to an amount of a specific cargo type. * @param cargo Cargo type to access. */ inline uint &operator[](CargoID cargo) { return this->amount[cargo]; } /** * Read-only access to an amount of a specific cargo type. * @param cargo Cargo type to access. */ inline const uint &operator[](CargoID cargo) const { return this->amount[cargo]; } /** * Get the sum of all cargo amounts. * @return The sum. */ template inline const T GetSum() const { T ret = 0; for (size_t i = 0; i < lengthof(this->amount); i++) { ret += this->amount[i]; } return ret; } /** * Get the amount of cargos that have an amount. * @return The amount. */ inline byte GetCount() const { byte count = 0; for (size_t i = 0; i < lengthof(this->amount); i++) { if (this->amount[i] != 0) count++; } return count; } }; /** Types of cargo source and destination */ enum SourceType { ST_INDUSTRY, ///< Source/destination is an industry ST_TOWN, ///< Source/destination is a town ST_HEADQUARTERS, ///< Source/destination are company headquarters }; typedef SimpleTinyEnumT SourceTypeByte; ///< The SourceType packed into a byte for savegame purposes. typedef uint16 SourceID; ///< Contains either industry ID, town ID or company ID (or INVALID_SOURCE) static const SourceID INVALID_SOURCE = 0xFFFF; ///< Invalid/unknown index of source #endif /* CARGO_TYPE_H */ openttd-1.5.3/src/cmd_helper.h0000644000000000000000000000276712627373435014765 0ustar rootroot/* $Id: cmd_helper.h 23742 2012-01-03 21:58:26Z rubidium $ */ /* * 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 cmd_helper.h Helper functions to extract data from command parameters. */ #ifndef CMD_HELPER_H #define CMD_HELPER_H #include "core/enum_type.hpp" #include "core/bitmath_func.hpp" /** * Extracts a given type from a value. * @tparam T The type of data we're looking for. * @tparam S The offset in the data. * @tparam N The amount of bits to read. * @tparam U The type of data passed to us. * @param v The data to extract the value from. */ template static inline T Extract(U v) { /* Check if there are enough bits in v */ assert_tcompile(N == EnumPropsT::num_bits); assert_tcompile(S + N <= sizeof(U) * 8); assert_tcompile(EnumPropsT::end <= (1 << N)); U masked = GB(v, S, N); return IsInsideMM(masked, EnumPropsT::begin, EnumPropsT::end) ? (T)masked : EnumPropsT::invalid; } #endif /* CMD_HELPER_H */ openttd-1.5.3/src/train.h0000644000000000000000000002721512627373446013775 0ustar rootroot/* $Id: train.h 26317 2014-02-07 23:48:56Z frosch $ */ /* * 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 train.h Base for the train class. */ #ifndef TRAIN_H #define TRAIN_H #include "core/enum_type.hpp" #include "newgrf_engine.h" #include "cargotype.h" #include "rail.h" #include "engine_base.h" #include "rail_map.h" #include "ground_vehicle.hpp" struct Train; /** Rail vehicle flags. */ enum VehicleRailFlags { VRF_REVERSING = 0, VRF_POWEREDWAGON = 3, ///< Wagon is powered. VRF_REVERSE_DIRECTION = 4, ///< Reverse the visible direction of the vehicle. VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL = 6, ///< Electric train engine is allowed to run on normal rail. */ VRF_TOGGLE_REVERSE = 7, ///< Used for vehicle var 0xFE bit 8 (toggled each time the train is reversed, accurate for first vehicle only). VRF_TRAIN_STUCK = 8, ///< Train can't get a path reservation. VRF_LEAVING_STATION = 9, ///< Train is just leaving a station. }; /** Modes for ignoring signals. */ enum TrainForceProceeding { TFP_NONE = 0, ///< Normal operation. TFP_STUCK = 1, ///< Proceed till next signal, but ignore being stuck till then. This includes force leaving depots. TFP_SIGNAL = 2, ///< Ignore next signal, after the signal ignore being stuck. }; typedef SimpleTinyEnumT TrainForceProceedingByte; /** Flags for Train::ConsistChanged */ enum ConsistChangeFlags { CCF_LENGTH = 0x01, ///< Allow vehicles to change length. CCF_CAPACITY = 0x02, ///< Allow vehicles to change capacity. CCF_TRACK = 0, ///< Valid changes while vehicle is driving, and possibly changing tracks. CCF_LOADUNLOAD = 0, ///< Valid changes while vehicle is loading/unloading. CCF_AUTOREFIT = CCF_CAPACITY, ///< Valid changes for autorefitting in stations. CCF_REFIT = CCF_LENGTH | CCF_CAPACITY, ///< Valid changes for refitting in a depot. CCF_ARRANGE = CCF_LENGTH | CCF_CAPACITY, ///< Valid changes for arranging the consist in a depot. CCF_SAVELOAD = CCF_LENGTH, ///< Valid changes when loading a savegame. (Everything that is not stored in the save.) }; DECLARE_ENUM_AS_BIT_SET(ConsistChangeFlags) byte FreightWagonMult(CargoID cargo); void CheckTrainsLengths(); void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR); bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false); int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length); void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); /** Variables that are cached to improve performance and such */ struct TrainCache { /* Cached wagon override spritegroup */ const struct SpriteGroup *cached_override; /* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */ bool cached_tilt; ///< train can tilt; feature provides a bonus in curves byte user_def_data; ///< Cached property 0x25. Can be set by Callback 0x36. /* cached max. speed / acceleration data */ int cached_max_curve_speed; ///< max consist speed limited by curves }; /** * 'Train' is either a loco or a wagon. */ struct Train FINAL : public GroundVehicle { TrainCache tcache; /* Link between the two ends of a multiheaded engine */ Train *other_multiheaded_part; uint16 crash_anim_pos; ///< Crash animation counter. uint16 flags; TrackBitsByte track; TrainForceProceedingByte force_proceed; RailTypeByte railtype; RailTypes compatible_railtypes; /** Ticks waiting in front of a signal, ticks being stuck or a counter for forced proceeding through signals. */ uint16 wait_counter; /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ Train() : GroundVehicleBase() {} /** We want to 'destruct' the right class. */ virtual ~Train() { this->PreDestructor(); } friend struct GroundVehicle; // GroundVehicle needs to use the acceleration functions defined at Train. void MarkDirty(); void UpdateDeltaXY(Direction direction); ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; } void PlayLeaveStationSound() const; bool IsPrimaryVehicle() const { return this->IsFrontEngine(); } SpriteID GetImage(Direction direction, EngineImageType image_type) const; int GetDisplaySpeed() const { return this->gcache.last_speed; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } Money GetRunningCost() const; int GetDisplayImageWidth(Point *offset = NULL) const; bool IsInDepot() const { return this->track == TRACK_BIT_DEPOT; } bool Tick(); void OnNewDay(); uint Crash(bool flooded = false); Trackdir GetVehicleTrackdir() const; TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); void ReserveTrackUnderConsist() const; int GetCurveSpeedLimit() const; void ConsistChanged(ConsistChangeFlags allowed_changes); int UpdateSpeed(); void UpdateAcceleration(); int GetCurrentMaxSpeed() const; /** * Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist. * @return Next vehicle in the consist. */ inline Train *GetNextUnit() const { Train *v = this->GetNextVehicle(); if (v != NULL && v->IsRearDualheaded()) v = v->GetNextVehicle(); return v; } /** * Get the previous real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist. * @return Previous vehicle in the consist. */ inline Train *GetPrevUnit() { Train *v = this->GetPrevVehicle(); if (v != NULL && v->IsRearDualheaded()) v = v->GetPrevVehicle(); return v; } /** * Calculate the offset from this vehicle's center to the following center taking the vehicle lengths into account. * @return Offset from center to center. */ int CalcNextVehicleOffset() const { /* For vehicles with odd lengths the part before the center will be one unit * longer than the part after the center. This means we have to round up the * length of the next vehicle but may not round the length of the current * vehicle. */ return this->gcache.cached_veh_length / 2 + (this->Next() != NULL ? this->Next()->gcache.cached_veh_length + 1 : 0) / 2; } protected: // These functions should not be called outside acceleration code. /** * Allows to know the power value that this vehicle will use. * @return Power value from the engine in HP, or zero if the vehicle is not powered. */ inline uint16 GetPower() const { /* Power is not added for articulated parts */ if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) { uint16 power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power); /* Halve power for multiheaded parts */ if (this->IsMultiheaded()) power /= 2; return power; } return 0; } /** * Returns a value if this articulated part is powered. * @return Power value from the articulated part in HP, or zero if it is not powered. */ inline uint16 GetPoweredPartPower(const Train *head) const { /* For powered wagons the engine defines the type of engine (i.e. railtype) */ if (HasBit(this->flags, VRF_POWEREDWAGON) && HasPowerOnRail(head->railtype, GetRailType(this->tile))) { return RailVehInfo(this->gcache.first_engine)->pow_wag_power; } return 0; } /** * Allows to know the weight value that this vehicle will use. * @return Weight value from the engine in tonnes. */ inline uint16 GetWeight() const { uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.StoredCount() * FreightWagonMult(this->cargo_type)) / 16; /* Vehicle weight is not added for articulated parts. */ if (!this->IsArticulatedPart()) { weight += GetVehicleProperty(this, PROP_TRAIN_WEIGHT, RailVehInfo(this->engine_type)->weight); } /* Powered wagons have extra weight added. */ if (HasBit(this->flags, VRF_POWEREDWAGON)) { weight += RailVehInfo(this->gcache.first_engine)->pow_wag_weight; } return weight; } /** * Allows to know the tractive effort value that this vehicle will use. * @return Tractive effort value from the engine. */ inline byte GetTractiveEffort() const { return GetVehicleProperty(this, PROP_TRAIN_TRACTIVE_EFFORT, RailVehInfo(this->engine_type)->tractive_effort); } /** * Gets the area used for calculating air drag. * @return Area of the engine in m^2. */ inline byte GetAirDragArea() const { /* Air drag is higher in tunnels due to the limited cross-section. */ return (this->track == TRACK_BIT_WORMHOLE && this->vehstatus & VS_HIDDEN) ? 28 : 14; } /** * Gets the air drag coefficient of this vehicle. * @return Air drag value from the engine. */ inline byte GetAirDrag() const { return RailVehInfo(this->engine_type)->air_drag; } /** * Checks the current acceleration status of this vehicle. * @return Acceleration status. */ inline AccelStatus GetAccelerationStatus() const { return (this->vehstatus & VS_STOPPED) || HasBit(this->flags, VRF_REVERSING) || HasBit(this->flags, VRF_TRAIN_STUCK) ? AS_BRAKE : AS_ACCEL; } /** * Calculates the current speed of this vehicle. * @return Current speed in km/h-ish. */ inline uint16 GetCurrentSpeed() const { return this->cur_speed; } /** * Returns the rolling friction coefficient of this vehicle. * @return Rolling friction coefficient in [1e-4]. */ inline uint32 GetRollingFriction() const { /* Rolling friction for steel on steel is between 0.1% and 0.2%. * The friction coefficient increases with speed in a way that * it doubles at 512 km/h, triples at 1024 km/h and so on. */ return 15 * (512 + this->GetCurrentSpeed()) / 512; } /** * Allows to know the acceleration type of a vehicle. * @return Acceleration type of the vehicle. */ inline int GetAccelerationType() const { return GetRailTypeInfo(this->railtype)->acceleration_type; } /** * Returns the slope steepness used by this vehicle. * @return Slope steepness used by the vehicle. */ inline uint32 GetSlopeSteepness() const { return _settings_game.vehicle.train_slope_steepness; } /** * Gets the maximum speed allowed by the track for this vehicle. * @return Maximum speed allowed. */ inline uint16 GetMaxTrackSpeed() const { return GetRailTypeInfo(GetRailType(this->tile))->max_speed; } /** * Checks if the vehicle is at a tile that can be sloped. * @return True if the tile can be sloped. */ inline bool TileMayHaveSlopedTrack() const { /* Any track that isn't TRACK_BIT_X or TRACK_BIT_Y cannot be sloped. */ return this->track == TRACK_BIT_X || this->track == TRACK_BIT_Y; } /** * Trains can always use the faster algorithm because they * have always the same direction as the track under them. * @return false */ inline bool HasToUseGetSlopePixelZ() { return false; } }; #define FOR_ALL_TRAINS(var) FOR_ALL_VEHICLES_OF_TYPE(Train, var) #endif /* TRAIN_H */ openttd-1.5.3/src/signs_type.h0000644000000000000000000000201512627373442015027 0ustar rootroot/* $Id: signs_type.h 22406 2011-05-01 19:51:52Z rubidium $ */ /* * 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 signs_type.h Types related to signs */ #ifndef SIGNS_TYPE_H #define SIGNS_TYPE_H /** The type of the IDs of signs. */ typedef uint16 SignID; struct Sign; static const SignID INVALID_SIGN = 0xFFFF; ///< Sentinel for an invalid sign. static const uint MAX_LENGTH_SIGN_NAME_CHARS = 32; ///< The maximum length of a sign name in characters including '\0' #endif /* SIGNS_TYPE_H */ openttd-1.5.3/src/heightmap.h0000644000000000000000000000232312627373441014612 0ustar rootroot/* $Id: heightmap.h 21845 2011-01-18 22:31:06Z rubidium $ */ /* * 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 heightmap.h Functions related to creating heightmaps from files. */ #ifndef HEIGHTMAP_H #define HEIGHTMAP_H /** * Order of these enums has to be the same as in lang/english.txt * Otherwise you will get inconsistent behaviour. */ enum HeightmapRotation { HM_COUNTER_CLOCKWISE, ///< Rotate the map counter clockwise 45 degrees HM_CLOCKWISE, ///< Rotate the map clockwise 45 degrees }; bool GetHeightmapDimensions(char *filename, uint *x, uint *y); void LoadHeightmap(char *filename); void FlatEmptyWorld(byte tile_height); void FixSlopes(); #endif /* HEIGHTMAP_H */ openttd-1.5.3/src/order_type.h0000644000000000000000000001515012627373433015023 0ustar rootroot/* $Id: order_type.h 25735 2013-08-20 20:05:31Z fonsinchen $ */ /* * 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 order_type.h Types related to orders. */ #ifndef ORDER_TYPE_H #define ORDER_TYPE_H #include "core/enum_type.hpp" typedef byte VehicleOrderID; ///< The index of an order within its current vehicle (not pool related) typedef uint16 OrderID; typedef uint16 OrderListID; typedef uint16 DestinationID; /** Invalid vehicle order index (sentinel) */ static const VehicleOrderID INVALID_VEH_ORDER_ID = 0xFF; /** Last valid VehicleOrderID. */ static const VehicleOrderID MAX_VEH_ORDER_ID = INVALID_VEH_ORDER_ID - 1; /** Invalid order (sentinel) */ static const OrderID INVALID_ORDER = 0xFFFF; /** * Maximum number of orders in implicit-only lists before we start searching * harder for duplicates. */ static const uint IMPLICIT_ORDER_ONLY_CAP = 32; /** Order types */ enum OrderType { OT_BEGIN = 0, OT_NOTHING = 0, OT_GOTO_STATION = 1, OT_GOTO_DEPOT = 2, OT_LOADING = 3, OT_LEAVESTATION = 4, OT_DUMMY = 5, OT_GOTO_WAYPOINT = 6, OT_CONDITIONAL = 7, OT_IMPLICIT = 8, OT_END }; /** It needs to be 8bits, because we save and load it as such */ typedef SimpleTinyEnumT OrderTypeByte; /** * Flags related to the unloading order. */ enum OrderUnloadFlags { OUF_UNLOAD_IF_POSSIBLE = 0, ///< Unload all cargo that the station accepts. OUFB_UNLOAD = 1 << 0, ///< Force unloading all cargo onto the platform, possibly not getting paid. OUFB_TRANSFER = 1 << 1, ///< Transfer all cargo onto the platform. OUFB_NO_UNLOAD = 1 << 2, ///< Totally no unloading will be done. }; /** * Flags related to the loading order. */ enum OrderLoadFlags { OLF_LOAD_IF_POSSIBLE = 0, ///< Load as long as there is cargo that fits in the train. OLFB_FULL_LOAD = 1 << 1, ///< Full load all cargoes of the consist. OLF_FULL_LOAD_ANY = 3, ///< Full load a single cargo of the consist. OLFB_NO_LOAD = 4, ///< Do not load anything. }; /** * Non-stop order flags. */ enum OrderNonStopFlags { ONSF_STOP_EVERYWHERE = 0, ///< The vehicle will stop at any station it passes and the destination. ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS = 1, ///< The vehicle will not stop at any stations it passes except the destination. ONSF_NO_STOP_AT_DESTINATION_STATION = 2, ///< The vehicle will stop at any station it passes except the destination. ONSF_NO_STOP_AT_ANY_STATION = 3, ///< The vehicle will not stop at any stations it passes including the destination. ONSF_END }; /** * Where to stop the trains. */ enum OrderStopLocation { OSL_PLATFORM_NEAR_END = 0, ///< Stop at the near end of the platform OSL_PLATFORM_MIDDLE = 1, ///< Stop at the middle of the platform OSL_PLATFORM_FAR_END = 2, ///< Stop at the far end of the platform OSL_END }; /** * Reasons that could cause us to go to the depot. */ enum OrderDepotTypeFlags { ODTF_MANUAL = 0, ///< Manually initiated order. ODTFB_SERVICE = 1 << 0, ///< This depot order is because of the servicing limit. ODTFB_PART_OF_ORDERS = 1 << 1, ///< This depot order is because of a regular order. }; /** * Actions that can be performed when the vehicle enters the depot. */ enum OrderDepotActionFlags { ODATF_SERVICE_ONLY = 0, ///< Only service the vehicle. ODATFB_HALT = 1 << 0, ///< Service the vehicle and then halt it. ODATFB_NEAREST_DEPOT = 1 << 1, ///< Send the vehicle to the nearest depot. }; DECLARE_ENUM_AS_BIT_SET(OrderDepotActionFlags) /** * Variables (of a vehicle) to 'cause' skipping on. */ enum OrderConditionVariable { OCV_LOAD_PERCENTAGE, ///< Skip based on the amount of load OCV_RELIABILITY, ///< Skip based on the reliability OCV_MAX_SPEED, ///< Skip based on the maximum speed OCV_AGE, ///< Skip based on the age OCV_REQUIRES_SERVICE, ///< Skip when the vehicle requires service OCV_UNCONDITIONALLY, ///< Always skip OCV_REMAINING_LIFETIME, ///< Skip based on the remaining lifetime OCV_END }; /** * Comparator for the skip reasoning. */ enum OrderConditionComparator { OCC_EQUALS, ///< Skip if both values are equal OCC_NOT_EQUALS, ///< Skip if both values are not equal OCC_LESS_THAN, ///< Skip if the value is less than the limit OCC_LESS_EQUALS, ///< Skip if the value is less or equal to the limit OCC_MORE_THAN, ///< Skip if the value is more than the limit OCC_MORE_EQUALS, ///< Skip if the value is more or equal to the limit OCC_IS_TRUE, ///< Skip if the variable is true OCC_IS_FALSE, ///< Skip if the variable is false OCC_END }; /** * Enumeration for the data to set in #CmdModifyOrder. */ enum ModifyOrderFlags { MOF_NON_STOP, ///< Passes an OrderNonStopFlags. MOF_STOP_LOCATION, ///< Passes an OrderStopLocation. MOF_UNLOAD, ///< Passes an OrderUnloadType. MOF_LOAD, ///< Passes an OrderLoadType MOF_DEPOT_ACTION, ///< Selects the OrderDepotAction MOF_COND_VARIABLE, ///< A conditional variable changes. MOF_COND_COMPARATOR, ///< A comparator changes. MOF_COND_VALUE, ///< The value to set the condition to. MOF_COND_DESTINATION,///< Change the destination of a conditional order. MOF_END }; template <> struct EnumPropsT : MakeEnumPropsT {}; /** * Depot action to switch to when doing a #MOF_DEPOT_ACTION. */ enum OrderDepotAction { DA_ALWAYS_GO, ///< Always go to the depot DA_SERVICE, ///< Service only if needed DA_STOP, ///< Go to the depot and stop there DA_END }; /** * Enumeration for the data to set in #CmdChangeTimetable. */ enum ModifyTimetableFlags { MTF_WAIT_TIME, ///< Set wait time. MTF_TRAVEL_TIME, ///< Set travel time. MTF_TRAVEL_SPEED, ///< Set max travel speed. MTF_END }; template <> struct EnumPropsT : MakeEnumPropsT {}; /** Clone actions. */ enum CloneOptions { CO_SHARE = 0, CO_COPY = 1, CO_UNSHARE = 2 }; struct Order; struct OrderList; #endif /* ORDER_TYPE_H */ openttd-1.5.3/src/group_gui.h0000644000000000000000000000170412627373435014651 0ustar rootroot/* $Id: group_gui.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 group_gui.h Functions/definitions that have something to do with groups. */ #ifndef GROUP_GUI_H #define GROUP_GUI_H #include "company_type.h" #include "vehicle_type.h" void ShowCompanyGroup(CompanyID company, VehicleType veh); void DeleteGroupHighlightOfVehicle(const Vehicle *v); #endif /* GROUP_GUI_H */ openttd-1.5.3/src/order_backup.h0000644000000000000000000000605612627373435015316 0ustar rootroot/* $Id: order_backup.h 24444 2012-07-29 16:45:34Z frosch $ */ /* * 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 order_backup.h Functions related to order backups. */ #ifndef ORDER_BACKUP_H #define ORDER_BACKUP_H #include "core/pool_type.hpp" #include "group_type.h" #include "tile_type.h" #include "vehicle_type.h" #include "base_consist.h" /** Unique identifier for an order backup. */ typedef uint8 OrderBackupID; struct OrderBackup; /** The pool type for order backups. */ typedef Pool OrderBackupPool; /** The pool with order backups. */ extern OrderBackupPool _order_backup_pool; /** Flag to pass to the vehicle construction command when an order should be preserved. */ static const uint32 MAKE_ORDER_BACKUP_FLAG = 1U << 31; /** * Data for backing up an order of a vehicle so it can be * restored after a vehicle is rebuilt in the same depot. */ struct OrderBackup : OrderBackupPool::PoolItem<&_order_backup_pool>, BaseConsist { private: friend const struct SaveLoad *GetOrderBackupDescription(); ///< Saving and loading of order backups. friend void Load_BKOR(); ///< Creating empty orders upon savegame loading. uint32 user; ///< The user that requested the backup. TileIndex tile; ///< Tile of the depot where the order was changed. GroupID group; ///< The group the vehicle was part of. const Vehicle *clone; ///< Vehicle this vehicle was a clone of. Order *orders; ///< The actual orders if the vehicle was not a clone. /** Creation for savegame restoration. */ OrderBackup() {} OrderBackup(const Vehicle *v, uint32 user); void DoRestore(Vehicle *v); public: ~OrderBackup(); static void Backup(const Vehicle *v, uint32 user); static void Restore(Vehicle *v, uint32 user); static void ResetOfUser(TileIndex tile, uint32 user); static void ResetUser(uint32 user); static void Reset(TileIndex tile = INVALID_TILE, bool from_gui = true); static void ClearGroup(GroupID group); static void ClearVehicle(const Vehicle *v); static void RemoveOrder(OrderType type, DestinationID destination); }; /** * Iterator over all order backups from a given ID. * @param var The variable to iterate with. * @param start The start of the iteration. */ #define FOR_ALL_ORDER_BACKUPS_FROM(var, start) FOR_ALL_ITEMS_FROM(OrderBackup, order_backup_index, var, start) /** * Iterator over all order backups. * @param var The variable to iterate with. */ #define FOR_ALL_ORDER_BACKUPS(var) FOR_ALL_ORDER_BACKUPS_FROM(var, 0) #endif /* ORDER_BACKUP_H */ openttd-1.5.3/src/tilearea_type.h0000644000000000000000000001464412627373441015504 0ustar rootroot/* $Id: tilearea_type.h 26289 2014-02-02 14:53:26Z fonsinchen $ */ /* * 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 tilearea_type.h Type for storing the 'area' of something uses on the map. */ #ifndef TILEAREA_TYPE_H #define TILEAREA_TYPE_H #include "map_func.h" /** Represents the covered area of e.g. a rail station */ struct OrthogonalTileArea { TileIndex tile; ///< The base tile of the area uint16 w; ///< The width of the area uint16 h; ///< The height of the area /** * Construct this tile area with some set values * @param tile the base tile * @param w the width * @param h the height */ OrthogonalTileArea(TileIndex tile = INVALID_TILE, uint8 w = 0, uint8 h = 0) : tile(tile), w(w), h(h) { } OrthogonalTileArea(TileIndex start, TileIndex end); void Add(TileIndex to_add); /** * Clears the 'tile area', i.e. make the tile invalid. */ void Clear() { this->tile = INVALID_TILE; this->w = 0; this->h = 0; } bool Intersects(const OrthogonalTileArea &ta) const; bool Contains(TileIndex tile) const; void ClampToMap(); /** * Get the center tile. * @return The tile at the center, or just north of it. */ TileIndex GetCenterTile() const { return TILE_ADDXY(this->tile, this->w / 2, this->h / 2); } }; /** Represents a diagonal tile area. */ struct DiagonalTileArea { TileIndex tile; ///< Base tile of the area int16 a; ///< Extent in diagonal "x" direction (may be negative to signify the area stretches to the left) int16 b; ///< Extent in diagonal "y" direction (may be negative to signify the area stretches upwards) /** * Construct this tile area with some set values. * @param tile The base tile. * @param a The "x" extent. * @param b The "y" estent. */ DiagonalTileArea(TileIndex tile = INVALID_TILE, int8 a = 0, int8 b = 0) : tile(tile), a(a), b(b) { } DiagonalTileArea(TileIndex start, TileIndex end); /** * Clears the TileArea by making the tile invalid and setting a and b to 0. */ void Clear() { this->tile = INVALID_TILE; this->a = 0; this->b = 0; } bool Contains(TileIndex tile) const; }; /** Shorthand for the much more common orthogonal tile area. */ typedef OrthogonalTileArea TileArea; /** Base class for tile iterators. */ class TileIterator { protected: TileIndex tile; ///< The current tile we are at. /** * Initialise the iterator starting at this tile. * @param tile The tile we start iterating from. */ TileIterator(TileIndex tile = INVALID_TILE) : tile(tile) { } public: /** Some compilers really like this. */ virtual ~TileIterator() { } /** * Get the tile we are currently at. * @return The tile we are at, or INVALID_TILE when we're done. */ inline operator TileIndex () const { return this->tile; } /** * Move ourselves to the next tile in the rectangle on the map. */ virtual TileIterator& operator ++() = 0; /** * Allocate a new iterator that is a copy of this one. */ virtual TileIterator *Clone() const = 0; }; /** Iterator to iterate over a tile area (rectangle) of the map. */ class OrthogonalTileIterator : public TileIterator { private: int w; ///< The width of the iterated area. int x; ///< The current 'x' position in the rectangle. int y; ///< The current 'y' position in the rectangle. public: /** * Construct the iterator. * @param ta Area, i.e. begin point and width/height of to-be-iterated area. */ OrthogonalTileIterator(const OrthogonalTileArea &ta) : TileIterator(ta.w == 0 || ta.h == 0 ? INVALID_TILE : ta.tile), w(ta.w), x(ta.w), y(ta.h) { } /** * Construct the iterator. * @param corner1 Tile from where to begin iterating. * @param corner2 Tile where to end the iterating. */ OrthogonalTileIterator(TileIndex corner1, TileIndex corner2) { *this = OrthogonalTileIterator(OrthogonalTileArea(corner1, corner2)); } /** * Move ourselves to the next tile in the rectangle on the map. */ inline TileIterator& operator ++() { assert(this->tile != INVALID_TILE); if (--this->x > 0) { this->tile++; } else if (--this->y > 0) { this->x = this->w; this->tile += TileDiffXY(1, 1) - this->w; } else { this->tile = INVALID_TILE; } return *this; } virtual TileIterator *Clone() const { return new OrthogonalTileIterator(*this); } }; /** Iterator to iterate over a diagonal area of the map. */ class DiagonalTileIterator : public TileIterator { private: uint base_x; ///< The base tile x coordinate from where the iterating happens. uint base_y; ///< The base tile y coordinate from where the iterating happens. int a_cur; ///< The current (rotated) x coordinate of the iteration. int b_cur; ///< The current (rotated) y coordinate of the iteration. int a_max; ///< The (rotated) x coordinate of the end of the iteration. int b_max; ///< The (rotated) y coordinate of the end of the iteration. public: /** * Construct the iterator. * @param ta Area, i.e. begin point and (diagonal) width/height of to-be-iterated area. */ DiagonalTileIterator(const DiagonalTileArea &ta) : TileIterator(ta.tile), base_x(TileX(ta.tile)), base_y(TileY(ta.tile)), a_cur(0), b_cur(0), a_max(ta.a), b_max(ta.b) { } /** * Construct the iterator. * @param corner1 Tile from where to begin iterating. * @param corner2 Tile where to end the iterating. */ DiagonalTileIterator(TileIndex corner1, TileIndex corner2) { *this = DiagonalTileIterator(DiagonalTileArea(corner1, corner2)); } TileIterator& operator ++(); virtual TileIterator *Clone() const { return new DiagonalTileIterator(*this); } }; /** * A loop which iterates over the tiles of a TileArea. * @param var The name of the variable which contains the current tile. * This variable will be allocated in this \c for of this loop. * @param ta The tile area to search over. */ #define TILE_AREA_LOOP(var, ta) for (OrthogonalTileIterator var(ta); var != INVALID_TILE; ++var) #endif /* TILEAREA_TYPE_H */ openttd-1.5.3/src/story_gui.cpp0000644000000000000000000005624512627373442015240 0ustar rootroot/* $Id: story_gui.cpp 27086 2014-12-18 18:22:23Z alberth $ */ /* * 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 story_gui.cpp GUI for stories. */ #include "stdafx.h" #include "window_gui.h" #include "strings_func.h" #include "date_func.h" #include "gui.h" #include "story_base.h" #include "core/geometry_func.hpp" #include "company_func.h" #include "command_func.h" #include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" #include "sortlist_type.h" #include "goal_base.h" #include "viewport_func.h" #include "window_func.h" #include "company_base.h" #include "widgets/story_widget.h" #include "table/strings.h" #include "table/sprites.h" #include "safeguards.h" typedef GUIList GUIStoryPageList; typedef GUIList GUIStoryPageElementList; struct StoryBookWindow : Window { protected: Scrollbar *vscroll; ///< Scrollbar of the page text. GUIStoryPageList story_pages; ///< Sorted list of pages. GUIStoryPageElementList story_page_elements; ///< Sorted list of page elements that belong to the current page. StoryPageID selected_page_id; ///< Pool index of selected page. char selected_generic_title[255]; ///< If the selected page doesn't have a custom title, this buffer is used to store a generic page title. static GUIStoryPageList::SortFunction * const page_sorter_funcs[]; static GUIStoryPageElementList::SortFunction * const page_element_sorter_funcs[]; /** (Re)Build story page list. */ void BuildStoryPageList() { if (this->story_pages.NeedRebuild()) { this->story_pages.Clear(); const StoryPage *p; FOR_ALL_STORY_PAGES(p) { if (this->IsPageAvailable(p)) { *this->story_pages.Append() = p; } } this->story_pages.Compact(); this->story_pages.RebuildDone(); } this->story_pages.Sort(); } /** Sort story pages by order value. */ static int CDECL PageOrderSorter(const StoryPage * const *a, const StoryPage * const *b) { return (*a)->sort_value - (*b)->sort_value; } /** (Re)Build story page element list. */ void BuildStoryPageElementList() { if (this->story_page_elements.NeedRebuild()) { this->story_page_elements.Clear(); const StoryPage *p = GetSelPage(); if (p != NULL) { const StoryPageElement *pe; FOR_ALL_STORY_PAGE_ELEMENTS(pe) { if (pe->page == p->index) { *this->story_page_elements.Append() = pe; } } } this->story_page_elements.Compact(); this->story_page_elements.RebuildDone(); } this->story_page_elements.Sort(); } /** Sort story page elements by order value. */ static int CDECL PageElementOrderSorter(const StoryPageElement * const *a, const StoryPageElement * const *b) { return (*a)->sort_value - (*b)->sort_value; } /* * Checks if a given page should be visible in the story book. * @param page The page to check. * @return True if the page should be visible, otherwise false. */ bool IsPageAvailable(const StoryPage *page) const { return page->company == INVALID_COMPANY || page->company == this->window_number; } /** * Get instance of selected page. * @return Instance of selected page or NULL if no page is selected. */ StoryPage *GetSelPage() const { if (!_story_page_pool.IsValidID(selected_page_id)) return NULL; return _story_page_pool.Get(selected_page_id); } /** * Get the page number of selected page. * @return Number of available pages before to the selected one, or -1 if no page is selected. */ int GetSelPageNum() const { int page_number = 0; for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { const StoryPage *p = *iter; if (p->index == this->selected_page_id) { return page_number; } page_number++; } return -1; } /** * Check if the selected page is also the first available page. */ bool IsFirstPageSelected() { /* Verify that the selected page exist. */ if (!_story_page_pool.IsValidID(this->selected_page_id)) return false; return (*this->story_pages.Begin())->index == this->selected_page_id; } /** * Check if the selected page is also the last available page. */ bool IsLastPageSelected() { /* Verify that the selected page exist. */ if (!_story_page_pool.IsValidID(this->selected_page_id)) return false; if (this->story_pages.Length() <= 1) return true; const StoryPage *last = *(this->story_pages.End() - 1); return last->index == this->selected_page_id; } /** * Updates the content of selected page. */ void RefreshSelectedPage() { /* Generate generic title if selected page have no custom title. */ StoryPage *page = this->GetSelPage(); if (page != NULL && page->title == NULL) { SetDParam(0, GetSelPageNum() + 1); GetString(selected_generic_title, STR_STORY_BOOK_GENERIC_PAGE_ITEM, lastof(selected_generic_title)); } this->story_page_elements.ForceRebuild(); this->BuildStoryPageElementList(); this->vscroll->SetCount(this->GetContentHeight()); this->SetWidgetDirty(WID_SB_SCROLLBAR); this->SetWidgetDirty(WID_SB_SEL_PAGE); this->SetWidgetDirty(WID_SB_PAGE_PANEL); } /** * Selects the previous available page before the currently selected page. */ void SelectPrevPage() { if (!_story_page_pool.IsValidID(this->selected_page_id)) return; /* Find the last available page which is previous to the current selected page. */ const StoryPage *last_available; last_available = NULL; for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { const StoryPage *p = *iter; if (p->index == this->selected_page_id) { if (last_available == NULL) return; // No previous page available. this->SetSelectedPage(last_available->index); return; } last_available = p; } } /** * Selects the next available page after the currently selected page. */ void SelectNextPage() { if (!_story_page_pool.IsValidID(this->selected_page_id)) return; /* Find selected page. */ for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { const StoryPage *p = *iter; if (p->index == this->selected_page_id) { /* Select the page after selected page. */ iter++; if (iter != this->story_pages.End()) { this->SetSelectedPage((*iter)->index); } return; } } } /** * Builds the page selector drop down list. */ DropDownList *BuildDropDownList() const { DropDownList *list = new DropDownList(); uint16 page_num = 1; for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { const StoryPage *p = *iter; bool current_page = p->index == this->selected_page_id; DropDownListStringItem *item = NULL; if (p->title != NULL) { item = new DropDownListCharStringItem(p->title, p->index, current_page); } else { /* No custom title => use a generic page title with page number. */ DropDownListParamStringItem *str_item = new DropDownListParamStringItem(STR_STORY_BOOK_GENERIC_PAGE_ITEM, p->index, current_page); str_item->SetParam(0, page_num); item = str_item; } *list->Append() = item; page_num++; } /* Check if list is empty. */ if (list->Length() == 0) { delete list; list = NULL; } return list; } /** * Get the width available for displaying content on the page panel. */ uint GetAvailablePageContentWidth() { return this->GetWidget(WID_SB_PAGE_PANEL)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMERECT_RIGHT; } /** * Counts how many pixels of height that are used by Date and Title * (excluding marginal after Title, as each body element has * an empty row before the elment). * @param max_width Available width to display content. * @return the height in pixels. */ uint GetHeadHeight(int max_width) const { StoryPage *page = this->GetSelPage(); if (page == NULL) return 0; int height = 0; /* Title lines */ height += FONT_HEIGHT_NORMAL; // Date always use exactly one line. SetDParamStr(0, page->title != NULL ? page->title : this->selected_generic_title); height += GetStringHeight(STR_STORY_BOOK_TITLE, max_width); return height; } /** * Decides which sprite to display for a given page element. * @param pe The page element. * @return The SpriteID of the sprite to display. * @pre pe.type must be SPET_GOAL or SPET_LOCATION. */ SpriteID GetPageElementSprite(const StoryPageElement &pe) const { switch (pe.type) { case SPET_GOAL: { Goal *g = Goal::Get((GoalID) pe.referenced_id); if (g == NULL) return SPR_IMG_GOAL_BROKEN_REF; return g->completed ? SPR_IMG_GOAL_COMPLETED : SPR_IMG_GOAL; } case SPET_LOCATION: return SPR_IMG_VIEW_LOCATION; default: NOT_REACHED(); } } /** * Get the height in pixels used by a page element. * @param pe The story page element. * @param max_width Available width to display content. * @return the height in pixels. */ uint GetPageElementHeight(const StoryPageElement &pe, int max_width) { switch (pe.type) { case SPET_TEXT: SetDParamStr(0, pe.text); return GetStringHeight(STR_BLACK_RAW_STRING, max_width); break; case SPET_GOAL: case SPET_LOCATION: { Dimension sprite_dim = GetSpriteSize(GetPageElementSprite(pe)); return sprite_dim.height; break; } default: NOT_REACHED(); } return 0; } /** * Get the total height of the content displayed * in this window. * @return the height in pixels */ uint GetContentHeight() { StoryPage *page = this->GetSelPage(); if (page == NULL) return 0; int max_width = GetAvailablePageContentWidth(); uint element_vertical_dist = FONT_HEIGHT_NORMAL; /* Head */ uint height = GetHeadHeight(max_width); /* Body */ for (const StoryPageElement **iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { const StoryPageElement *pe = *iter; height += element_vertical_dist; height += GetPageElementHeight(*pe, max_width); } return height; } /** * Draws a page element that is composed of a sprite to the left and a single line of * text after that. These page elements are generally clickable and are thus called * action elements. * @param y_offset Current y_offset which will get updated when this method has completed its drawing. * @param width Width of the region available for drawing. * @param line_height Height of one line of text. * @param action_sprite The sprite to draw. * @param string_id The string id to draw. * @return the number of lines. */ void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite, StringID string_id = STR_JUST_RAW_STRING) const { Dimension sprite_dim = GetSpriteSize(action_sprite); uint element_height = max(sprite_dim.height, (uint)line_height); uint sprite_top = y_offset + (element_height - sprite_dim.height) / 2; uint text_top = y_offset + (element_height - line_height) / 2; DrawSprite(action_sprite, PAL_NONE, 0, sprite_top); DrawString(sprite_dim.width + WD_FRAMETEXT_LEFT, width, text_top, string_id, TC_BLACK); y_offset += element_height; } /** * Internal event handler for when a page element is clicked. * @param pe The clicked page element. */ void OnPageElementClick(const StoryPageElement& pe) { switch (pe.type) { case SPET_TEXT: /* Do nothing. */ break; case SPET_LOCATION: if (_ctrl_pressed) { ShowExtraViewPortWindow((TileIndex)pe.referenced_id); } else { ScrollMainWindowToTile((TileIndex)pe.referenced_id); } break; case SPET_GOAL: ShowGoalsList((CompanyID)this->window_number); break; default: NOT_REACHED(); } } public: StoryBookWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR); this->vscroll->SetStepSize(FONT_HEIGHT_NORMAL); /* Initalize page sort. */ this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs); this->story_pages.ForceRebuild(); this->BuildStoryPageList(); this->story_page_elements.SetSortFuncs(StoryBookWindow::page_element_sorter_funcs); /* story_page_elements will get built by SetSelectedPage */ this->FinishInitNested(window_number); this->owner = (Owner)this->window_number; /* Initialize selected vars. */ this->selected_generic_title[0] = '\0'; this->selected_page_id = INVALID_STORY_PAGE; this->OnInvalidateData(-1); } /** * Updates the disabled state of the prev/next buttons. */ void UpdatePrevNextDisabledState() { this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.Length() == 0 || this->IsFirstPageSelected()); this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.Length() == 0 || this->IsLastPageSelected()); this->SetWidgetDirty(WID_SB_PREV_PAGE); this->SetWidgetDirty(WID_SB_NEXT_PAGE); } /** * Sets the selected page. * @param page_index pool index of the page to select. */ void SetSelectedPage(uint16 page_index) { if (this->selected_page_id != page_index) { this->selected_page_id = page_index; this->RefreshSelectedPage(); this->UpdatePrevNextDisabledState(); } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_SB_SEL_PAGE: { StoryPage *page = this->GetSelPage(); SetDParamStr(0, page != NULL && page->title != NULL ? page->title : this->selected_generic_title); break; } case WID_SB_CAPTION: if (this->window_number == INVALID_COMPANY) { SetDParam(0, STR_STORY_BOOK_SPECTATOR_CAPTION); } else { SetDParam(0, STR_STORY_BOOK_CAPTION); SetDParam(1, this->window_number); } break; } } virtual void OnPaint() { /* Detect if content has changed height. This can happen if a * multi-line text contains eg. {COMPANY} and that company is * renamed. */ if (this->vscroll->GetCount() != this->GetContentHeight()) { this->vscroll->SetCount(this->GetContentHeight()); this->SetWidgetDirty(WID_SB_SCROLLBAR); this->SetWidgetDirty(WID_SB_PAGE_PANEL); } this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_SB_PAGE_PANEL) return; StoryPage *page = this->GetSelPage(); if (page == NULL) return; const int x = r.left + WD_FRAMETEXT_LEFT; const int y = r.top + WD_FRAMETEXT_TOP; const int right = r.right - WD_FRAMETEXT_RIGHT; const int bottom = r.bottom - WD_FRAMETEXT_BOTTOM; /* Set up a clipping region for the panel. */ DrawPixelInfo tmp_dpi; if (!FillDrawPixelInfo(&tmp_dpi, x, y, right - x + 1, bottom - y + 1)) return; DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; /* Draw content (now coordinates given to Draw** are local to the new clipping region). */ int line_height = FONT_HEIGHT_NORMAL; int y_offset = - this->vscroll->GetPosition(); /* Date */ if (page->date != INVALID_DATE) { SetDParam(0, page->date); DrawString(0, right - x, y_offset, STR_JUST_DATE_LONG, TC_BLACK); } y_offset += line_height; /* Title */ SetDParamStr(0, page->title != NULL ? page->title : this->selected_generic_title); y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER); /* Page elements */ for (const StoryPageElement *const*iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { const StoryPageElement *const pe = *iter; y_offset += line_height; // margin to previous element switch (pe->type) { case SPET_TEXT: SetDParamStr(0, pe->text); y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_LEFT); break; case SPET_GOAL: { Goal *g = Goal::Get((GoalID) pe->referenced_id); StringID string_id = g == NULL ? STR_STORY_BOOK_INVALID_GOAL_REF : STR_JUST_RAW_STRING; if (g != NULL) SetDParamStr(0, g->text); DrawActionElement(y_offset, right - x, line_height, GetPageElementSprite(*pe), string_id); break; } case SPET_LOCATION: SetDParamStr(0, pe->text); DrawActionElement(y_offset, right - x, line_height, GetPageElementSprite(*pe)); break; default: NOT_REACHED(); } } /* Restore clipping region. */ _cur_dpi = old_dpi; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return; Dimension d; d.height = FONT_HEIGHT_NORMAL; d.width = 0; switch (widget) { case WID_SB_SEL_PAGE: { /* Get max title width. */ for (uint16 i = 0; i < this->story_pages.Length(); i++) { const StoryPage *s = this->story_pages[i]; if (s->title != NULL) { SetDParamStr(0, s->title); } else { SetDParamStr(0, this->selected_generic_title); } Dimension title_d = GetStringBoundingBox(STR_BLACK_RAW_STRING); if (title_d.width > d.width) { d.width = title_d.width; } } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_SB_PAGE_PANEL: { d.height *= 5; d.height += padding.height + WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; *size = maxdim(*size, d); break; } } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_SB_PAGE_PANEL, WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM); this->vscroll->SetCount(this->GetContentHeight()); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_SB_SEL_PAGE: { DropDownList *list = this->BuildDropDownList(); if (list != NULL) { /* Get the index of selected page. */ int selected = 0; for (uint16 i = 0; i < this->story_pages.Length(); i++) { const StoryPage *p = this->story_pages[i]; if (p->index == this->selected_page_id) break; selected++; } ShowDropDownList(this, list, selected, widget); } break; } case WID_SB_PREV_PAGE: this->SelectPrevPage(); break; case WID_SB_NEXT_PAGE: this->SelectNextPage(); break; case WID_SB_PAGE_PANEL: { uint clicked_y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SB_PAGE_PANEL, WD_FRAMETEXT_TOP); uint max_width = GetAvailablePageContentWidth(); /* Skip head rows. */ uint head_height = this->GetHeadHeight(max_width); if (clicked_y < head_height) return; /* Detect if a page element was clicked. */ uint y = head_height; uint element_vertical_dist = FONT_HEIGHT_NORMAL; for (const StoryPageElement *const*iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { const StoryPageElement *const pe = *iter; y += element_vertical_dist; // margin row uint content_height = GetPageElementHeight(*pe, max_width); if (clicked_y >= y && clicked_y < y + content_height) { this->OnPageElementClick(*pe); return; } y += content_height; } } } } virtual void OnDropdownSelect(int widget, int index) { if (widget != WID_SB_SEL_PAGE) return; /* index (which is set in BuildDropDownList) is the page id. */ this->SetSelectedPage(index); } /** * Some data on this window has become invalid. * @param data Information about the changed data. * -1 Rebuild page list and refresh current page; * >= 0 Id of the page that needs to be refreshed. If it is not the current page, nothing happens. * @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; /* If added/removed page, force rebuild. Sort order never change so just a * re-sort is never needed. */ if (data == -1) { this->story_pages.ForceRebuild(); this->BuildStoryPageList(); /* Was the last page removed? */ if (this->story_pages.Length() == 0) { this->selected_generic_title[0] = '\0'; } /* Verify page selection. */ if (!_story_page_pool.IsValidID(this->selected_page_id)) { this->selected_page_id = INVALID_STORY_PAGE; } if (this->selected_page_id == INVALID_STORY_PAGE && this->story_pages.Length() > 0) { /* No page is selected, but there exist at least one available. * => Select first page. */ this->SetSelectedPage(this->story_pages[0]->index); } this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.Length() == 0); this->SetWidgetDirty(WID_SB_SEL_PAGE); this->UpdatePrevNextDisabledState(); } else if (data >= 0 && this->selected_page_id == data) { this->RefreshSelectedPage(); } } }; GUIStoryPageList::SortFunction * const StoryBookWindow::page_sorter_funcs[] = { &PageOrderSorter, }; GUIStoryPageElementList::SortFunction * const StoryBookWindow::page_element_sorter_funcs[] = { &PageElementOrderSorter, }; static const NWidgetPart _nested_story_book_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(NWID_HORIZONTAL), SetFill(1, 1), NWidget(NWID_VERTICAL), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_BROWN, WID_SB_PAGE_PANEL), SetResize(1, 1), SetScrollbar(WID_SB_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_PREV_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetDataTip(STR_STORY_BOOK_PREV_PAGE, STR_STORY_BOOK_PREV_PAGE_TOOLTIP), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_BROWN, WID_SB_SEL_PAGE), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_BLACK_RAW_STRING, STR_STORY_BOOK_SEL_PAGE_TOOLTIP), SetResize(1, 0), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_NEXT_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetDataTip(STR_STORY_BOOK_NEXT_PAGE, STR_STORY_BOOK_NEXT_PAGE_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetFill(0, 1), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SB_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), }; static WindowDesc _story_book_desc( WDP_CENTER, "view_story", 400, 300, WC_STORY_BOOK, WC_NONE, 0, _nested_story_book_widgets, lengthof(_nested_story_book_widgets) ); /** * Raise or create the story book window for \a company, at page \a page_id. * @param company 'Owner' of the story book, may be #INVALID_COMPANY. * @param page_id Page to open, may be #INVALID_STORY_PAGE. */ void ShowStoryBook(CompanyID company, uint16 page_id) { if (!Company::IsValidID(company)) company = (CompanyID)INVALID_COMPANY; StoryBookWindow *w = AllocateWindowDescFront(&_story_book_desc, company, true); if (page_id != INVALID_STORY_PAGE) w->SetSelectedPage(page_id); } openttd-1.5.3/src/effectvehicle_base.h0000644000000000000000000000340012627373435016432 0ustar rootroot/* $Id: effectvehicle_base.h 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 effectvehicle_base.h Base class for all effect vehicles. */ #ifndef EFFECTVEHICLE_BASE_H #define EFFECTVEHICLE_BASE_H #include "vehicle_base.h" #include "transparency.h" /** * A special vehicle is one of the following: * - smoke * - electric sparks for trains * - explosions * - bulldozer (road works) * - bubbles (industry) */ struct EffectVehicle FINAL : public SpecializedVehicle { uint16 animation_state; ///< State primarily used to change the graphics/behaviour. byte animation_substate; ///< Sub state to time the change of the graphics/behaviour. /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ EffectVehicle() : SpecializedVehicleBase() {} /** We want to 'destruct' the right class. */ virtual ~EffectVehicle() {} void UpdateDeltaXY(Direction direction); bool Tick(); TransparencyOption GetTransparencyOption() const; }; /** * Iterate over disaster vehicles. * @param var The variable used to iterate over. */ #define FOR_ALL_EFFECTVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(EffectVehicle, var) #endif /* EFFECTVEHICLE_BASE_H */ openttd-1.5.3/src/road_internal.h0000644000000000000000000000212212627373434015464 0ustar rootroot/* $Id: road_internal.h 21846 2011-01-18 23:09:43Z rubidium $ */ /* * 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 road_internal.h Functions used internally by the roads. */ #ifndef ROAD_INTERNAL_H #define ROAD_INTERNAL_H #include "tile_cmd.h" #include "road_type.h" RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb); CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadType rt, DoCommandFlag flags, bool town_check = true); void DrawTramCatenary(const TileInfo *ti, RoadBits tram); #endif /* ROAD_INTERNAL_H */ openttd-1.5.3/src/ground_vehicle.hpp0000644000000000000000000003414612627373441016211 0ustar rootroot/* $Id: ground_vehicle.hpp 26888 2014-09-21 12:44:38Z rubidium $ */ /* * 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 ground_vehicle.hpp Base class and functions for all vehicles that move through ground. */ #ifndef GROUND_VEHICLE_HPP #define GROUND_VEHICLE_HPP #include "vehicle_base.h" #include "vehicle_gui.h" #include "landscape.h" #include "window_func.h" #include "widgets/vehicle_widget.h" /** What is the status of our acceleration? */ enum AccelStatus { AS_ACCEL, ///< We want to go faster, if possible of course. AS_BRAKE, ///< We want to stop. }; /** * Cached, frequently calculated values. * All of these values except cached_slope_resistance are set only for the first part of a vehicle. */ struct GroundVehicleCache { /* Cached acceleration values, recalculated when the cargo on a vehicle changes (in addition to the conditions below) */ uint32 cached_weight; ///< Total weight of the consist (valid only for the first engine). uint32 cached_slope_resistance; ///< Resistance caused by weight when this vehicle part is at a slope. uint32 cached_max_te; ///< Maximum tractive effort of consist (valid only for the first engine). uint16 cached_axle_resistance; ///< Resistance caused by the axles of the vehicle (valid only for the first engine). /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */ uint16 cached_max_track_speed; ///< Maximum consist speed limited by track type (valid only for the first engine). uint32 cached_power; ///< Total power of the consist (valid only for the first engine). uint32 cached_air_drag; ///< Air drag coefficient of the vehicle (valid only for the first engine). /* Cached NewGRF values, recalculated on load and each time a vehicle is added to/removed from the consist. */ uint16 cached_total_length; ///< Length of the whole vehicle (valid only for the first engine). EngineID first_engine; ///< Cached EngineID of the front vehicle. INVALID_ENGINE for the front vehicle itself. uint8 cached_veh_length; ///< Length of this vehicle in units of 1/VEHICLE_LENGTH of normal length. It is cached because this can be set by a callback. /* Cached UI information. */ uint16 last_speed; ///< The last speed we did display, so we only have to redraw when this changes. }; /** Ground vehicle flags. */ enum GroundVehicleFlags { GVF_GOINGUP_BIT = 0, ///< Vehicle is currently going uphill. (Cached track information for acceleration) GVF_GOINGDOWN_BIT = 1, ///< Vehicle is currently going downhill. (Cached track information for acceleration) GVF_SUPPRESS_IMPLICIT_ORDERS = 2, ///< Disable insertion and removal of automatic orders until the vehicle completes the real order. }; /** * Base class for all vehicles that move through ground. * * Child classes must define all of the following functions. * These functions are not defined as pure virtual functions at this class to improve performance. * * virtual uint16 GetPower() const = 0; * virtual uint16 GetPoweredPartPower(const T *head) const = 0; * virtual uint16 GetWeight() const = 0; * virtual byte GetTractiveEffort() const = 0; * virtual byte GetAirDrag() const = 0; * virtual byte GetAirDragArea() const = 0; * virtual AccelStatus GetAccelerationStatus() const = 0; * virtual uint16 GetCurrentSpeed() const = 0; * virtual uint32 GetRollingFriction() const = 0; * virtual int GetAccelerationType() const = 0; * virtual int32 GetSlopeSteepness() const = 0; * virtual int GetDisplayMaxSpeed() const = 0; * virtual uint16 GetMaxTrackSpeed() const = 0; * virtual bool TileMayHaveSlopedTrack() const = 0; */ template struct GroundVehicle : public SpecializedVehicle { GroundVehicleCache gcache; ///< Cache of often calculated values. uint16 gv_flags; ///< @see GroundVehicleFlags. typedef GroundVehicle GroundVehicleBase; ///< Our type /** * The constructor at SpecializedVehicle must be called. */ GroundVehicle() : SpecializedVehicle() {} void PowerChanged(); void CargoChanged(); int GetAcceleration() const; bool IsChainInDepot() const; /** * Common code executed for crashed ground vehicles * @param flooded was this vehicle flooded? * @return number of victims */ /* virtual */ uint Crash(bool flooded) { /* Crashed vehicles aren't going up or down */ for (T *v = T::From(this); v != NULL; v = v->Next()) { ClrBit(v->gv_flags, GVF_GOINGUP_BIT); ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT); } return this->Vehicle::Crash(flooded); } /** * Calculates the total slope resistance for this vehicle. * @return Slope resistance. */ inline int64 GetSlopeResistance() const { int64 incl = 0; for (const T *u = T::From(this); u != NULL; u = u->Next()) { if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) { incl += u->gcache.cached_slope_resistance; } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) { incl -= u->gcache.cached_slope_resistance; } } return incl; } /** * Updates vehicle's Z position and inclination. * Used when the vehicle entered given tile. * @pre The vehicle has to be at (or near to) a border of the tile, * directed towards tile centre */ inline void UpdateZPositionAndInclination() { this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos); ClrBit(this->gv_flags, GVF_GOINGUP_BIT); ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT); if (T::From(this)->TileMayHaveSlopedTrack()) { /* To check whether the current tile is sloped, and in which * direction it is sloped, we get the 'z' at the center of * the tile (middle_z) and the edge of the tile (old_z), * which we then can compare. */ int middle_z = GetSlopePixelZ((this->x_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2), (this->y_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2)); if (middle_z != this->z_pos) { SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT); } } } /** * Updates vehicle's Z position. * Inclination can't change in the middle of a tile. * The faster code is used for trains and road vehicles unless they are * reversing on a sloped tile. */ inline void UpdateZPosition() { #if 0 /* The following code does this: */ if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) { switch (this->direction) { case DIR_NE: this->z_pos += (this->x_pos & 1); break; case DIR_SW: this->z_pos += (this->x_pos & 1) ^ 1; break; case DIR_NW: this->z_pos += (this->y_pos & 1); break; case DIR_SE: this->z_pos += (this->y_pos & 1) ^ 1; break; default: break; } } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) { switch (this->direction) { case DIR_NE: this->z_pos -= (this->x_pos & 1); break; case DIR_SW: this->z_pos -= (this->x_pos & 1) ^ 1; break; case DIR_NW: this->z_pos -= (this->y_pos & 1); break; case DIR_SE: this->z_pos -= (this->y_pos & 1) ^ 1; break; default: break; } } /* But gcc 4.4.5 isn't able to nicely optimise it, and the resulting * code is full of conditional jumps. */ #endif /* Vehicle's Z position can change only if it has GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set. * Furthermore, if this function is called once every time the vehicle's position changes, * we know the Z position changes by +/-1 at certain moments - when x_pos, y_pos is odd/even, * depending on orientation of the slope and vehicle's direction */ if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) { if (T::From(this)->HasToUseGetSlopePixelZ()) { /* In some cases, we have to use GetSlopePixelZ() */ this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos); return; } /* DirToDiagDir() is a simple right shift */ DiagDirection dir = DirToDiagDir(this->direction); /* Read variables, so the compiler knows the access doesn't trap */ int8 x_pos = this->x_pos; int8 y_pos = this->y_pos; /* DiagDirToAxis() is a simple mask */ int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos; /* We need only the least significant bit */ d &= 1; /* Conditional "^ 1". Optimised to "(dir - 1) <= 1". */ d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE); /* Subtraction instead of addition because we are testing for GVF_GOINGUP_BIT. * GVF_GOINGUP_BIT is used because it's bit 0, so simple AND can be used, * without any shift */ this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d; } assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos)); } /** * Checks if the vehicle is in a slope and sets the required flags in that case. * @param new_tile True if the vehicle reached a new tile. * @param update_delta Indicates to also update the delta. * @return Old height of the vehicle. */ inline int UpdateInclination(bool new_tile, bool update_delta) { int old_z = this->z_pos; if (new_tile) { this->UpdateZPositionAndInclination(); } else { this->UpdateZPosition(); } this->UpdateViewport(true, update_delta); return old_z; } /** * Set front engine state. */ inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); } /** * Remove the front engine state. */ inline void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); } /** * Set a vehicle to be an articulated part. */ inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); } /** * Clear a vehicle from being an articulated part. */ inline void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); } /** * Set a vehicle to be a wagon. */ inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); } /** * Clear wagon property. */ inline void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); } /** * Set engine status. */ inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); } /** * Clear engine status. */ inline void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); } /** * Set a vehicle as a free wagon. */ inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); } /** * Clear a vehicle from being a free wagon. */ inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); } /** * Set a vehicle as a multiheaded engine. */ inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); } /** * Clear multiheaded engine property. */ inline void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); } /** * Check if the vehicle is a free wagon (got no engine in front of it). * @return Returns true if the vehicle is a free wagon. */ inline bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); } /** * Check if a vehicle is an engine (can be first in a consist). * @return Returns true if vehicle is an engine. */ inline bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); } /** * Check if a vehicle is a wagon. * @return Returns true if vehicle is a wagon. */ inline bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); } /** * Check if the vehicle is a multiheaded engine. * @return Returns true if the vehicle is a multiheaded engine. */ inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); } /** * Tell if we are dealing with the rear end of a multiheaded engine. * @return True if the engine is the rear part of a dualheaded engine. */ inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); } /** * Update the GUI variant of the current speed of the vehicle. * Also mark the widget dirty when that is needed, i.e. when * the speed of this vehicle has changed. */ inline void SetLastSpeed() { if (this->cur_speed != this->gcache.last_speed) { SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); this->gcache.last_speed = this->cur_speed; } } protected: /** * Update the speed of the vehicle. * * It updates the cur_speed and subspeed variables depending on the state * of the vehicle; in this case the current acceleration, minimum and * maximum speeds of the vehicle. It returns the distance that that the * vehicle can drive this tick. #Vehicle::GetAdvanceDistance() determines * the distance to drive before moving a step on the map. * @param accel The acceleration we would like to give this vehicle. * @param min_speed The minimum speed here, in vehicle specific units. * @param max_speed The maximum speed here, in vehicle specific units. * @return Distance to drive. */ inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed) { uint spd = this->subspeed + accel; this->subspeed = (byte)spd; /* When we are going faster than the maximum speed, reduce the speed * somewhat gradually. But never lower than the maximum speed. */ int tempmax = max_speed; if (this->cur_speed > max_speed) { tempmax = max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed); } /* Enforce a maximum and minimum speed. Normally we would use something like * Clamp for this, but in this case min_speed might be below the maximum speed * threshold for some reason. That makes acceleration fail and assertions * happen in Clamp. So make it explicit that min_speed overrules the maximum * speed by explicit ordering of min and max. */ this->cur_speed = spd = max(min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed); int scaled_spd = this->GetAdvanceSpeed(spd); scaled_spd += this->progress; this->progress = 0; // set later in *Handler or *Controller return scaled_spd; } }; #endif /* GROUND_VEHICLE_HPP */ openttd-1.5.3/src/ship.h0000644000000000000000000000453512627373435013621 0ustar rootroot/* $Id: ship.h 26546 2014-05-01 14:48:44Z fonsinchen $ */ /* * 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 ship.h Base for ships. */ #ifndef SHIP_H #define SHIP_H #include "vehicle_base.h" #include "water_map.h" void GetShipSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); WaterClass GetEffectiveWaterClass(TileIndex tile); /** * All ships have this type. */ struct Ship FINAL : public SpecializedVehicle { TrackBitsByte state; ///< The "track" the ship is following. /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ Ship() : SpecializedVehicleBase() {} /** We want to 'destruct' the right class. */ virtual ~Ship() { this->PreDestructor(); } void MarkDirty(); void UpdateDeltaXY(Direction direction); ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_SHIP_INC : EXPENSES_SHIP_RUN; } void PlayLeaveStationSound() const; bool IsPrimaryVehicle() const { return true; } SpriteID GetImage(Direction direction, EngineImageType image_type) const; int GetDisplaySpeed() const { return this->cur_speed / 2; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; } int GetCurrentMaxSpeed() const { return min(this->vcache.cached_max_speed, this->current_order.GetMaxSpeed() * 2); } Money GetRunningCost() const; bool IsInDepot() const { return this->state == TRACK_BIT_DEPOT; } bool Tick(); void OnNewDay(); Trackdir GetVehicleTrackdir() const; TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); void UpdateCache(); }; /** * Iterate over all ships. * @param var The variable used for iteration. */ #define FOR_ALL_SHIPS(var) FOR_ALL_VEHICLES_OF_TYPE(Ship, var) #endif /* SHIP_H */ openttd-1.5.3/src/newgrf_config.h0000644000000000000000000002654012627373442015471 0ustar rootroot/* $Id: newgrf_config.h 26612 2014-05-24 19:13:34Z alberth $ */ /* * 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 newgrf_config.h Functions to find and configure NewGRFs. */ #ifndef NEWGRF_CONFIG_H #define NEWGRF_CONFIG_H #include "strings_type.h" #include "core/alloc_type.hpp" #include "core/smallmap_type.hpp" #include "misc/countedptr.hpp" #include "fileio_type.h" #include "textfile_type.h" /** GRF config bit flags */ enum GCF_Flags { GCF_SYSTEM, ///< GRF file is an openttd-internal system grf GCF_UNSAFE, ///< GRF file is unsafe for static usage GCF_STATIC, ///< GRF file is used statically (can be used in any MP game) GCF_COMPATIBLE, ///< GRF file does not exactly match the requested GRF (different MD5SUM), but grfid matches) GCF_COPY, ///< The data is copied from a grf in _all_grfs GCF_INIT_ONLY, ///< GRF file is processed up to GLS_INIT GCF_RESERVED, ///< GRF file passed GLS_RESERVE stage GCF_INVALID, ///< GRF is unusable with this version of OpenTTD }; /** Status of GRF */ enum GRFStatus { GCS_UNKNOWN, ///< The status of this grf file is unknown GCS_DISABLED, ///< GRF file is disabled GCS_NOT_FOUND, ///< GRF file was not found in the local cache GCS_INITIALISED, ///< GRF file has been initialised GCS_ACTIVATED, ///< GRF file has been activated }; /** Encountered GRF bugs */ enum GRFBugs { GBUG_VEH_LENGTH, ///< Length of rail vehicle changes when not inside a depot GBUG_VEH_REFIT, ///< Articulated vehicles carry different cargoes resp. are differently refittable than specified in purchase list GBUG_VEH_POWERED_WAGON, ///< Powered wagon changed poweredness state when not inside a depot GBUG_UNKNOWN_CB_RESULT, ///< A callback returned an unknown/invalid result GBUG_VEH_CAPACITY, ///< Capacity of vehicle changes when not refitting or arranging }; /** Status of post-gameload GRF compatibility check */ enum GRFListCompatibility { GLC_ALL_GOOD, ///< All GRF needed by game are present GLC_COMPATIBLE, ///< Compatible (eg. the same ID, but different checksum) GRF found in at least one case GLC_NOT_FOUND, ///< At least one GRF couldn't be found (higher priority than GLC_COMPATIBLE) }; /** Information that can/has to be stored about a GRF's palette. */ enum GRFPalette { GRFP_USE_BIT = 0, ///< The bit used for storing the palette to use. GRFP_GRF_OFFSET = 2, ///< The offset of the GRFP_GRF data. GRFP_GRF_SIZE = 2, ///< The size of the GRFP_GRF data. GRFP_BLT_OFFSET = 4, ///< The offset of the GRFP_BLT data. GRFP_BLT_SIZE = 1, ///< The size of the GRFP_BLT data. GRFP_USE_DOS = 0x0, ///< The palette state is set to use the DOS palette. GRFP_USE_WINDOWS = 0x1, ///< The palette state is set to use the Windows palette. GRFP_USE_MASK = 0x1, ///< Bitmask to get only the use palette use states. GRFP_GRF_UNSET = 0x0 << GRFP_GRF_OFFSET, ///< The NewGRF provided no information. GRFP_GRF_DOS = 0x1 << GRFP_GRF_OFFSET, ///< The NewGRF says the DOS palette can be used. GRFP_GRF_WINDOWS = 0x2 << GRFP_GRF_OFFSET, ///< The NewGRF says the Windows palette can be used. GRFP_GRF_ANY = GRFP_GRF_DOS | GRFP_GRF_WINDOWS, ///< The NewGRF says any palette can be used. GRFP_GRF_MASK = GRFP_GRF_ANY, ///< Bitmask to get only the NewGRF supplied information. GRFP_BLT_UNSET = 0x0 << GRFP_BLT_OFFSET, ///< The NewGRF provided no information or doesn't care about a 32 bpp blitter. GRFP_BLT_32BPP = 0x1 << GRFP_BLT_OFFSET, ///< The NewGRF prefers a 32 bpp blitter. GRFP_BLT_MASK = GRFP_BLT_32BPP, ///< Bitmask to only get the blitter information. }; /** Basic data to distinguish a GRF. Used in the server list window */ struct GRFIdentifier { uint32 grfid; ///< GRF ID (defined by Action 0x08) uint8 md5sum[16]; ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF) /** * Does the identification match the provided values? * @param grfid Expected grfid. * @param md5sum Expected md5sum, may be \c NULL (in which case, do not check it). * @return the object has the provided grfid and md5sum. */ inline bool HasGrfIdentifier(uint32 grfid, const uint8 *md5sum) const { if (this->grfid != grfid) return false; if (md5sum == NULL) return true; return memcmp(md5sum, this->md5sum, sizeof(this->md5sum)) == 0; } }; /** Information about why GRF had problems during initialisation */ struct GRFError : ZeroedMemoryAllocator { GRFError(StringID severity, StringID message = 0); GRFError(const GRFError &error); ~GRFError(); char *custom_message; ///< Custom message (if present) char *data; ///< Additional data for message and custom_message StringID message; ///< Default message StringID severity; ///< Info / Warning / Error / Fatal uint32 param_value[2]; ///< Values of GRF parameters to show for message and custom_message }; /** The possible types of a newgrf parameter. */ enum GRFParameterType { PTYPE_UINT_ENUM, ///< The parameter allows a range of numbers, each of which can have a special name PTYPE_BOOL, ///< The parameter is either 0 or 1 PTYPE_END, ///< Invalid parameter type }; /** Information about one grf parameter. */ struct GRFParameterInfo { GRFParameterInfo(uint nr); GRFParameterInfo(GRFParameterInfo &info); ~GRFParameterInfo(); struct GRFText *name; ///< The name of this parameter struct GRFText *desc; ///< The description of this parameter GRFParameterType type; ///< The type of this parameter uint32 min_value; ///< The minimal value this parameter can have uint32 max_value; ///< The maximal value of this parameter uint32 def_value; ///< Default value of this parameter byte param_nr; ///< GRF parameter to store content in byte first_bit; ///< First bit to use in the GRF parameter byte num_bit; ///< Number of bits to use for this parameter SmallMap value_names; ///< Names for each value. bool complete_labels; ///< True if all values have a label. uint32 GetValue(struct GRFConfig *config) const; void SetValue(struct GRFConfig *config, uint32 value); void Finalize(); }; /** Reference counted wrapper around a GRFText pointer. */ struct GRFTextWrapper : public SimpleCountedObject { struct GRFText *text; ///< The actual text GRFTextWrapper(); ~GRFTextWrapper(); }; /** Information about GRF, used in the game and (part of it) in savegames */ struct GRFConfig : ZeroedMemoryAllocator { GRFConfig(const char *filename = NULL); GRFConfig(const GRFConfig &config); ~GRFConfig(); GRFIdentifier ident; ///< grfid and md5sum to uniquely identify newgrfs uint8 original_md5sum[16]; ///< MD5 checksum of original file if only a 'compatible' file was loaded char *filename; ///< Filename - either with or without full path GRFTextWrapper *name; ///< NOSAVE: GRF name (Action 0x08) GRFTextWrapper *info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08) GRFTextWrapper *url; ///< NOSAVE: URL belonging to this GRF. GRFError *error; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B) uint32 version; ///< NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown uint32 min_loadable_version; ///< NOSAVE: Minimum compatible version a NewGRF can define uint8 flags; ///< NOSAVE: GCF_Flags, bitset GRFStatus status; ///< NOSAVE: GRFStatus, enum uint32 grf_bugs; ///< NOSAVE: bugs in this GRF in this run, @see enum GRFBugs uint32 param[0x80]; ///< GRF parameters uint8 num_params; ///< Number of used parameters uint8 num_valid_params; ///< NOSAVE: Number of valid parameters (action 0x14) uint8 palette; ///< GRFPalette, bitset SmallVector param_info; ///< NOSAVE: extra information about the parameters bool has_param_defaults; ///< NOSAVE: did this newgrf specify any defaults for it's parameters struct GRFConfig *next; ///< NOSAVE: Next item in the linked list void CopyParams(const GRFConfig &src); bool IsOpenTTDBaseGRF() const; const char *GetTextfile(TextfileType type) const; const char *GetName() const; const char *GetDescription() const; const char *GetURL() const; void SetParameterDefaults(); void SetSuitablePalette(); void FinalizeParameterInfo(); }; /** Method to find GRFs using FindGRFConfig */ enum FindGRFConfigMode { FGCM_EXACT, ///< Only find Grfs matching md5sum FGCM_COMPATIBLE, ///< Find best compatible Grf wrt. desired_version FGCM_NEWEST, ///< Find newest Grf FGCM_NEWEST_VALID,///< Find newest Grf, ignoring Grfs with GCF_INVALID set FGCM_ANY, ///< Use first found }; extern GRFConfig *_all_grfs; ///< First item in list of all scanned NewGRFs extern GRFConfig *_grfconfig; ///< First item in list of current GRF set up extern GRFConfig *_grfconfig_newgame; ///< First item in list of default GRF set up extern GRFConfig *_grfconfig_static; ///< First item in list of static GRF set up /** Callback for NewGRF scanning. */ struct NewGRFScanCallback { /** Make sure the right destructor gets called. */ virtual ~NewGRFScanCallback() {} /** Called whenever the NewGRF scan completed. */ virtual void OnNewGRFsScanned() = 0; }; size_t GRFGetSizeOfDataSection(FILE *f); void ScanNewGRFFiles(NewGRFScanCallback *callback); void CheckForMissingSprites(); const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum = NULL, uint32 desired_version = 0); GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask = 0xFFFFFFFF); GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only); void AppendStaticGRFConfigs(GRFConfig **dst); void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el); void ClearGRFConfigList(GRFConfig **config); void ResetGRFConfig(bool defaults); GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig); bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir = NEWGRF_DIR); char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last); /* In newgrf_gui.cpp */ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config); #ifdef ENABLE_NETWORK /** For communication about GRFs over the network */ #define UNKNOWN_GRF_NAME_PLACEHOLDER "" GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create); #endif /* ENABLE_NETWORK */ void UpdateNewGRFScanStatus(uint num, const char *name); bool UpdateNewGRFConfigPalette(int32 p1 = 0); #endif /* NEWGRF_CONFIG_H */ openttd-1.5.3/src/newgrf_sound.h0000644000000000000000000000356212627373441015352 0ustar rootroot/* $Id: newgrf_sound.h 24052 2012-03-19 22:55:29Z frosch $ */ /* * 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 newgrf_sound.h Functions related to NewGRF provided sounds. */ #ifndef NEWGRF_SOUND_H #define NEWGRF_SOUND_H #include "sound_type.h" #include "tile_type.h" #include "vehicle_type.h" /** Events at which a sound might be played. */ enum VehicleSoundEvent { VSE_START = 1, ///< Vehicle starting, i.e. leaving, the station. VSE_TUNNEL = 2, ///< Train entering a tunnel. VSE_BREAKDOWN = 3, ///< Vehicle breaking down. VSE_RUNNING = 4, ///< Vehicle running normally. VSE_TOUCHDOWN = 5, ///< Whenever a plane touches down. VSE_VISUAL_EFFECT = 6, ///< Vehicle visual effect (steam, diesel smoke or electric spark) is shown. VSE_RUNNING_16 = 7, ///< Every 16 ticks while the vehicle is running (speed > 0). VSE_STOPPED_16 = 8, ///< Every 16 ticks while the vehicle is stopped (speed == 0). VSE_LOAD_UNLOAD = 9, ///< Whenever cargo payment is made for a vehicle. }; SoundEntry *AllocateSound(uint num); void InitializeSoundPool(); bool LoadNewGRFSound(SoundEntry *sound); SoundEntry *GetSound(SoundID sound_id); uint GetNumSounds(); bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event); void PlayTileSound(const struct GRFFile *file, SoundID sound_id, TileIndex tile); #endif /* NEWGRF_SOUND_H */ openttd-1.5.3/src/road_cmd.cpp0000644000000000000000000017645012627373435014767 0ustar rootroot/* $Id: road_cmd.cpp 27350 2015-07-30 18:50:39Z frosch $ */ /* * 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 road_cmd.cpp Commands related to road tiles. */ #include "stdafx.h" #include "cmd_helper.h" #include "road_internal.h" #include "viewport_func.h" #include "command_func.h" #include "pathfinder/yapf/yapf_cache.h" #include "depot_base.h" #include "newgrf.h" #include "autoslope.h" #include "tunnelbridge_map.h" #include "strings_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "tunnelbridge.h" #include "cheat_type.h" #include "effectvehicle_func.h" #include "effectvehicle_base.h" #include "elrail_func.h" #include "roadveh.h" #include "town.h" #include "company_base.h" #include "core/random_func.hpp" #include "newgrf_railtype.h" #include "date_func.h" #include "genworld.h" #include "company_gui.h" #include "table/strings.h" #include "safeguards.h" /** * Verify whether a road vehicle is available. * @return \c true if at least one road vehicle is available, \c false if not */ bool RoadVehiclesAreBuilt() { const RoadVehicle *rv; FOR_ALL_ROADVEHICLES(rv) return true; return false; } /** Invalid RoadBits on slopes. */ static const RoadBits _invalid_tileh_slopes_road[2][15] = { /* The inverse of the mixable RoadBits on a leveled slope */ { ROAD_NONE, // SLOPE_FLAT ROAD_NE | ROAD_SE, // SLOPE_W ROAD_NE | ROAD_NW, // SLOPE_S ROAD_NE, // SLOPE_SW ROAD_NW | ROAD_SW, // SLOPE_E ROAD_NONE, // SLOPE_EW ROAD_NW, // SLOPE_SE ROAD_NONE, // SLOPE_WSE ROAD_SE | ROAD_SW, // SLOPE_N ROAD_SE, // SLOPE_NW ROAD_NONE, // SLOPE_NS ROAD_NONE, // SLOPE_ENW ROAD_SW, // SLOPE_NE ROAD_NONE, // SLOPE_SEN ROAD_NONE // SLOPE_NWS }, /* The inverse of the allowed straight roads on a slope * (with and without a foundation). */ { ROAD_NONE, // SLOPE_FLAT ROAD_NONE, // SLOPE_W Foundation ROAD_NONE, // SLOPE_S Foundation ROAD_Y, // SLOPE_SW ROAD_NONE, // SLOPE_E Foundation ROAD_ALL, // SLOPE_EW ROAD_X, // SLOPE_SE ROAD_ALL, // SLOPE_WSE ROAD_NONE, // SLOPE_N Foundation ROAD_X, // SLOPE_NW ROAD_ALL, // SLOPE_NS ROAD_ALL, // SLOPE_ENW ROAD_Y, // SLOPE_NE ROAD_ALL, // SLOPE_SEN ROAD_ALL // SLOPE_NW } }; static Foundation GetRoadFoundation(Slope tileh, RoadBits bits); /** * Is it allowed to remove the given road bits from the given tile? * @param tile the tile to remove the road from * @param remove the roadbits that are going to be removed * @param owner the actual owner of the roadbits of the tile * @param rt the road type to remove the bits from * @param flags command flags * @param town_check Shall the town rating checked/affected * @return A succeeded command when it is allowed to remove the road bits, a failed command otherwise. */ CommandCost CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, RoadType rt, DoCommandFlag flags, bool town_check) { if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return CommandCost(); /* Water can always flood and towns can always remove "normal" road pieces. * Towns are not be allowed to remove non "normal" road pieces, like tram * tracks as that would result in trams that cannot turn. */ if (_current_company == OWNER_WATER || (rt == ROADTYPE_ROAD && !Company::IsValidID(_current_company))) return CommandCost(); /* Only do the special processing if the road is owned * by a town */ if (owner != OWNER_TOWN) { if (owner == OWNER_NONE) return CommandCost(); CommandCost ret = CheckOwnership(owner); return ret; } if (!town_check) return CommandCost(); if (_cheats.magic_bulldozer.value) return CommandCost(); Town *t = ClosestTownFromTile(tile, UINT_MAX); if (t == NULL) return CommandCost(); /* check if you're allowed to remove the street owned by a town * removal allowance depends on difficulty setting */ CommandCost ret = CheckforTownRating(flags, t, ROAD_REMOVE); if (ret.Failed()) return ret; /* Get a bitmask of which neighbouring roads has a tile */ RoadBits n = ROAD_NONE; RoadBits present = GetAnyRoadBits(tile, rt); if ((present & ROAD_NE) && (GetAnyRoadBits(TILE_ADDXY(tile, -1, 0), rt) & ROAD_SW)) n |= ROAD_NE; if ((present & ROAD_SE) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, 1), rt) & ROAD_NW)) n |= ROAD_SE; if ((present & ROAD_SW) && (GetAnyRoadBits(TILE_ADDXY(tile, 1, 0), rt) & ROAD_NE)) n |= ROAD_SW; if ((present & ROAD_NW) && (GetAnyRoadBits(TILE_ADDXY(tile, 0, -1), rt) & ROAD_SE)) n |= ROAD_NW; int rating_decrease = RATING_ROAD_DOWN_STEP_EDGE; /* If 0 or 1 bits are set in n, or if no bits that match the bits to remove, * then allow it */ if (KillFirstBit(n) != ROAD_NONE && (n & remove) != ROAD_NONE) { /* you can remove all kind of roads with extra dynamite */ if (!_settings_game.construction.extra_dynamite) { SetDParam(0, t->index); return_cmd_error(STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS); } rating_decrease = RATING_ROAD_DOWN_STEP_INNER; } ChangeTownRating(t, rating_decrease, RATING_ROAD_MINIMUM, flags); return CommandCost(); } /** * Delete a piece of road. * @param tile tile where to remove road from * @param flags operation to perform * @param pieces roadbits to remove * @param rt roadtype to remove * @param crossing_check should we check if there is a tram track when we are removing road from crossing? * @param town_check should we check if the town allows removal? */ static CommandCost RemoveRoad(TileIndex tile, DoCommandFlag flags, RoadBits pieces, RoadType rt, bool crossing_check, bool town_check = true) { RoadTypes rts = GetRoadTypes(tile); /* The tile doesn't have the given road type */ if (!HasBit(rts, rt)) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); switch (GetTileType(tile)) { case MP_ROAD: { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; break; } case MP_STATION: { if (!IsDriveThroughStopTile(tile)) return CMD_ERROR; CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; break; } case MP_TUNNELBRIDGE: { if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR; CommandCost ret = TunnelBridgeIsFree(tile, GetOtherTunnelBridgeEnd(tile)); if (ret.Failed()) return ret; break; } default: return CMD_ERROR; } CommandCost ret = CheckAllowRemoveRoad(tile, pieces, GetRoadOwner(tile, rt), rt, flags, town_check); if (ret.Failed()) return ret; if (!IsTileType(tile, MP_ROAD)) { /* If it's the last roadtype, just clear the whole tile */ if (rts == RoadTypeToRoadTypes(rt)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); CommandCost cost(EXPENSES_CONSTRUCTION); if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* Removing any roadbit in the bridge axis removes the roadtype (that's the behaviour remove-long-roads needs) */ if ((AxisToRoadBits(DiagDirToAxis(GetTunnelBridgeDirection(tile))) & pieces) == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); TileIndex other_end = GetOtherTunnelBridgeEnd(tile); /* Pay for *every* tile of the bridge or tunnel */ uint len = GetTunnelBridgeLength(other_end, tile) + 2; cost.AddCost(len * _price[PR_CLEAR_ROAD]); if (flags & DC_EXEC) { Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { /* A full diagonal road tile has two road bits. */ c->infrastructure.road[rt] -= len * 2 * TUNNELBRIDGE_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(c->index); } SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt)); SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt)); /* If the owner of the bridge sells all its road, also move the ownership * to the owner of the other roadtype, unless the bridge owner is a town. */ RoadType other_rt = (rt == ROADTYPE_ROAD) ? ROADTYPE_TRAM : ROADTYPE_ROAD; Owner other_owner = GetRoadOwner(tile, other_rt); if (!IsTileOwner(tile, other_owner) && !IsTileOwner(tile, OWNER_TOWN)) { SetTileOwner(tile, other_owner); SetTileOwner(other_end, other_owner); } /* Mark tiles dirty that have been repaved */ if (IsBridge(tile)) { MarkBridgeDirty(tile); } else { MarkTileDirtyByTile(tile); MarkTileDirtyByTile(other_end); } } } else { assert(IsDriveThroughStopTile(tile)); cost.AddCost(_price[PR_CLEAR_ROAD] * 2); if (flags & DC_EXEC) { Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { /* A full diagonal road tile has two road bits. */ c->infrastructure.road[rt] -= 2; DirtyCompanyInfrastructureWindows(c->index); } SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt)); MarkTileDirtyByTile(tile); } } return cost; } switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { Slope tileh = GetTileSlope(tile); /* Steep slopes behave the same as slopes with one corner raised. */ if (IsSteepSlope(tileh)) { tileh = SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh)); } RoadBits present = GetRoadBits(tile, rt); const RoadBits other = GetOtherRoadBits(tile, rt); const Foundation f = GetRoadFoundation(tileh, present); if (HasRoadWorks(tile) && _current_company != OWNER_WATER) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS); /* Autocomplete to a straight road * @li if the bits of the other roadtypes result in another foundation * @li if build on slopes is disabled */ if ((IsStraightRoad(other) && (other & _invalid_tileh_slopes_road[0][tileh & SLOPE_ELEVATED]) != ROAD_NONE) || (tileh != SLOPE_FLAT && !_settings_game.construction.build_on_slopes)) { pieces |= MirrorRoadBits(pieces); } /* limit the bits to delete to the existing bits. */ pieces &= present; if (pieces == ROAD_NONE) return_cmd_error(rt == ROADTYPE_TRAM ? STR_ERROR_THERE_IS_NO_TRAMWAY : STR_ERROR_THERE_IS_NO_ROAD); /* Now set present what it will be after the remove */ present ^= pieces; /* Check for invalid RoadBit combinations on slopes */ if (tileh != SLOPE_FLAT && present != ROAD_NONE && (present & _invalid_tileh_slopes_road[0][tileh & SLOPE_ELEVATED]) == present) { return CMD_ERROR; } if (flags & DC_EXEC) { if (HasRoadWorks(tile)) { /* flooding tile with road works, don't forget to remove the effect vehicle too */ assert(_current_company == OWNER_WATER); EffectVehicle *v; FOR_ALL_EFFECTVEHICLES(v) { if (TileVirtXY(v->x_pos, v->y_pos) == tile) { delete v; } } } Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { c->infrastructure.road[rt] -= CountBits(pieces); DirtyCompanyInfrastructureWindows(c->index); } if (present == ROAD_NONE) { RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); if (rts == ROADTYPES_NONE) { /* Includes MarkTileDirtyByTile() */ DoClearSquare(tile); } else { if (rt == ROADTYPE_ROAD && IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) { /* Update nearest-town index */ const Town *town = CalcClosestTownFromTile(tile); SetTownIndex(tile, town == NULL ? (TownID)INVALID_TOWN : town->index); } SetRoadBits(tile, ROAD_NONE, rt); SetRoadTypes(tile, rts); MarkTileDirtyByTile(tile); } } else { /* When bits are removed, you *always* end up with something that * is not a complete straight road tile. However, trams do not have * onewayness, so they cannot remove it either. */ if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE); SetRoadBits(tile, present, rt); MarkTileDirtyByTile(tile); } } CommandCost cost(EXPENSES_CONSTRUCTION, CountBits(pieces) * _price[PR_CLEAR_ROAD]); /* If we build a foundation we have to pay for it. */ if (f == FOUNDATION_NONE && GetRoadFoundation(tileh, present) != FOUNDATION_NONE) cost.AddCost(_price[PR_BUILD_FOUNDATION]); return cost; } case ROAD_TILE_CROSSING: { if (pieces & ComplementRoadBits(GetCrossingRoadBits(tile))) { return CMD_ERROR; } /* Don't allow road to be removed from the crossing when there is tram; * we can't draw the crossing without roadbits ;) */ if (rt == ROADTYPE_ROAD && HasTileRoadType(tile, ROADTYPE_TRAM) && (flags & DC_EXEC || crossing_check)) return CMD_ERROR; if (flags & DC_EXEC) { Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { /* A full diagonal road tile has two road bits. */ c->infrastructure.road[rt] -= 2; DirtyCompanyInfrastructureWindows(c->index); } Track railtrack = GetCrossingRailTrack(tile); RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt)); if (rts == ROADTYPES_NONE) { TrackBits tracks = GetCrossingRailBits(tile); bool reserved = HasCrossingReservation(tile); MakeRailNormal(tile, GetTileOwner(tile), tracks, GetRailType(tile)); if (reserved) SetTrackReservation(tile, tracks); /* Update rail count for level crossings. The plain track should still be accounted * for, so only subtract the difference to the level crossing cost. */ c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { c->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR - 1; DirtyCompanyInfrastructureWindows(c->index); } } else { SetRoadTypes(tile, rts); } MarkTileDirtyByTile(tile); YapfNotifyTrackLayoutChange(tile, railtrack); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROAD] * 2); } default: case ROAD_TILE_DEPOT: return CMD_ERROR; } } /** * Calculate the costs for roads on slopes * Aside modify the RoadBits to fit on the slopes * * @note The RoadBits are modified too! * @param tileh The current slope * @param pieces The RoadBits we want to add * @param existing The existent RoadBits of the current type * @param other The other existent RoadBits * @return The costs for these RoadBits on this slope */ static CommandCost CheckRoadSlope(Slope tileh, RoadBits *pieces, RoadBits existing, RoadBits other) { /* Remove already build pieces */ CLRBITS(*pieces, existing); /* If we can't build anything stop here */ if (*pieces == ROAD_NONE) return CMD_ERROR; /* All RoadBit combos are valid on flat land */ if (tileh == SLOPE_FLAT) return CommandCost(); /* Steep slopes behave the same as slopes with one corner raised. */ if (IsSteepSlope(tileh)) { tileh = SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh)); } /* Save the merge of all bits of the current type */ RoadBits type_bits = existing | *pieces; /* Roads on slopes */ if (_settings_game.construction.build_on_slopes && (_invalid_tileh_slopes_road[0][tileh] & (other | type_bits)) == ROAD_NONE) { /* If we add leveling we've got to pay for it */ if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); return CommandCost(); } /* Autocomplete uphill roads */ *pieces |= MirrorRoadBits(*pieces); type_bits = existing | *pieces; /* Uphill roads */ if (IsStraightRoad(type_bits) && (other == type_bits || other == ROAD_NONE) && (_invalid_tileh_slopes_road[1][tileh] & (other | type_bits)) == ROAD_NONE) { /* Slopes with foundation ? */ if (IsSlopeWithOneCornerRaised(tileh)) { /* Prevent build on slopes if it isn't allowed */ if (_settings_game.construction.build_on_slopes) { /* If we add foundation we've got to pay for it */ if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); return CommandCost(); } } else { if (HasExactlyOneBit(existing) && GetRoadFoundation(tileh, existing) == FOUNDATION_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); return CommandCost(); } } return CMD_ERROR; } /** * Build a piece of road. * @param tile tile where to build road * @param flags operation to perform * @param p1 bit 0..3 road pieces to build (RoadBits) * bit 4..5 road type * bit 6..7 disallowed directions to toggle * @param p2 the town that is building the road (0 if not applicable) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CompanyID company = _current_company; CommandCost cost(EXPENSES_CONSTRUCTION); RoadBits existing = ROAD_NONE; RoadBits other_bits = ROAD_NONE; /* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero * if a non-company is building the road */ if ((Company::IsValidID(company) && p2 != 0) || (company == OWNER_TOWN && !Town::IsValidID(p2)) || (company == OWNER_DEITY && p2 != 0)) return CMD_ERROR; if (company != OWNER_TOWN) { const Town *town = CalcClosestTownFromTile(tile); p2 = (town != NULL) ? town->index : (TownID)INVALID_TOWN; if (company == OWNER_DEITY) { company = OWNER_TOWN; /* If we are not within a town, we are not owned by the town */ if (town == NULL || DistanceSquare(tile, town->xy) > town->cache.squared_town_zone_radius[HZB_TOWN_EDGE]) { company = OWNER_NONE; } } } RoadBits pieces = Extract(p1); /* do not allow building 'zero' road bits, code wouldn't handle it */ if (pieces == ROAD_NONE) return CMD_ERROR; RoadType rt = Extract(p1); if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; DisallowedRoadDirections toggle_drd = Extract(p1); Slope tileh = GetTileSlope(tile); bool need_to_clear = false; switch (GetTileType(tile)) { case MP_ROAD: switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS); other_bits = GetOtherRoadBits(tile, rt); if (!HasTileRoadType(tile, rt)) break; existing = GetRoadBits(tile, rt); bool crossing = !IsStraightRoad(existing | pieces); if (rt != ROADTYPE_TRAM && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) { /* Junctions cannot be one-way */ return_cmd_error(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); } if ((existing & pieces) == pieces) { /* We only want to set the (dis)allowed road directions */ if (toggle_drd != DRD_NONE && rt != ROADTYPE_TRAM) { if (crossing) return_cmd_error(STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION); Owner owner = GetRoadOwner(tile, ROADTYPE_ROAD); if (owner != OWNER_NONE) { CommandCost ret = CheckOwnership(owner, tile); if (ret.Failed()) return ret; } DisallowedRoadDirections dis_existing = GetDisallowedRoadDirections(tile); DisallowedRoadDirections dis_new = dis_existing ^ toggle_drd; /* We allow removing disallowed directions to break up * deadlocks, but adding them can break articulated * vehicles. As such, only when less is disallowed, * i.e. bits are removed, we skip the vehicle check. */ if (CountBits(dis_existing) <= CountBits(dis_new)) { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; } /* Ignore half built tiles */ if ((flags & DC_EXEC) && rt != ROADTYPE_TRAM && IsStraightRoad(existing)) { SetDisallowedRoadDirections(tile, dis_new); MarkTileDirtyByTile(tile); } return CommandCost(); } return_cmd_error(STR_ERROR_ALREADY_BUILT); } /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ if (rt == ROADTYPE_TRAM && HasExactlyOneBit(existing)) { Owner owner = GetRoadOwner(tile, rt); if (Company::IsValidID(owner)) { CommandCost ret = CheckOwnership(owner); if (ret.Failed()) return ret; } } break; } case ROAD_TILE_CROSSING: other_bits = GetCrossingRoadBits(tile); if (pieces & ComplementRoadBits(other_bits)) goto do_clear; pieces = other_bits; // we need to pay for both roadbits if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); break; case ROAD_TILE_DEPOT: if ((GetAnyRoadBits(tile, rt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); goto do_clear; default: NOT_REACHED(); } break; case MP_RAILWAY: { if (IsSteepSlope(tileh)) { return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } /* Level crossings may only be built on these slopes */ if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) { return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear; if (RailNoLevelCrossings(GetRailType(tile))) { return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); } Axis roaddir; switch (GetTrackBits(tile)) { case TRACK_BIT_X: if (pieces & ROAD_X) goto do_clear; roaddir = AXIS_Y; break; case TRACK_BIT_Y: if (pieces & ROAD_Y) goto do_clear; roaddir = AXIS_X; break; default: goto do_clear; } CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; if (flags & DC_EXEC) { Track railtrack = AxisToTrack(OtherAxis(roaddir)); YapfNotifyTrackLayoutChange(tile, railtrack); /* Update company infrastructure counts. A level crossing has two road bits. */ Company *c = Company::GetIfValid(company); if (c != NULL) { c->infrastructure.road[rt] += 2; if (rt != ROADTYPE_ROAD) c->infrastructure.road[ROADTYPE_ROAD] += 2; DirtyCompanyInfrastructureWindows(company); } /* Update rail count for level crossings. The plain track is already * counted, so only add the difference to the level crossing cost. */ c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { c->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR - 1; DirtyCompanyInfrastructureWindows(c->index); } /* Always add road to the roadtypes (can't draw without it) */ bool reserved = HasBit(GetRailReservationTrackBits(tile), railtrack); MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), RoadTypeToRoadTypes(rt) | ROADTYPES_ROAD, p2); SetCrossingReservation(tile, reserved); UpdateLevelCrossing(tile, false); MarkTileDirtyByTile(tile); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_ROAD] * (rt == ROADTYPE_ROAD ? 2 : 4)); } case MP_STATION: { if ((GetAnyRoadBits(tile, rt) & pieces) == pieces) return_cmd_error(STR_ERROR_ALREADY_BUILT); if (!IsDriveThroughStopTile(tile)) goto do_clear; RoadBits curbits = AxisToRoadBits(DiagDirToAxis(GetRoadStopDir(tile))); if (pieces & ~curbits) goto do_clear; pieces = curbits; // we need to pay for both roadbits if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); break; } case MP_TUNNELBRIDGE: { if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) goto do_clear; /* Only allow building the outern roadbit, so building long roads stops at existing bridges */ if (MirrorRoadBits(DiagDirToRoadBits(GetTunnelBridgeDirection(tile))) != pieces) goto do_clear; if (HasTileRoadType(tile, rt)) return_cmd_error(STR_ERROR_ALREADY_BUILT); /* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */ CommandCost ret = TunnelBridgeIsFree(tile, GetOtherTunnelBridgeEnd(tile)); if (ret.Failed()) return ret; break; } default: { do_clear:; need_to_clear = true; break; } } if (need_to_clear) { CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); } if (other_bits != pieces) { /* Check the foundation/slopes when adding road/tram bits */ CommandCost ret = CheckRoadSlope(tileh, &pieces, existing, other_bits); /* Return an error if we need to build a foundation (ret != 0) but the * current setting is turned off */ if (ret.Failed() || (ret.GetCost() != 0 && !_settings_game.construction.build_on_slopes)) { return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } cost.AddCost(ret); } if (!need_to_clear) { if (IsTileType(tile, MP_ROAD)) { /* Don't put the pieces that already exist */ pieces &= ComplementRoadBits(existing); /* Check if new road bits will have the same foundation as other existing road types */ if (IsNormalRoad(tile)) { Slope slope = GetTileSlope(tile); Foundation found_new = GetRoadFoundation(slope, pieces | existing); /* Test if all other roadtypes can be built at that foundation */ for (RoadType rtest = ROADTYPE_ROAD; rtest < ROADTYPE_END; rtest++) { if (rtest != rt) { // check only other road types RoadBits bits = GetRoadBits(tile, rtest); /* do not check if there are not road bits of given type */ if (bits != ROAD_NONE && GetRoadFoundation(slope, bits) != found_new) { return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } } } } } CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; } uint num_pieces = (!need_to_clear && IsTileType(tile, MP_TUNNELBRIDGE)) ? /* There are 2 pieces on *every* tile of the bridge or tunnel */ 2 * (GetTunnelBridgeLength(GetOtherTunnelBridgeEnd(tile), tile) + 2) : /* Count pieces */ CountBits(pieces); cost.AddCost(num_pieces * _price[PR_BUILD_ROAD]); if (flags & DC_EXEC) { switch (GetTileType(tile)) { case MP_ROAD: { RoadTileType rtt = GetRoadTileType(tile); if (existing == ROAD_NONE || rtt == ROAD_TILE_CROSSING) { SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); SetRoadOwner(tile, rt, company); if (rt == ROADTYPE_ROAD) SetTownIndex(tile, p2); } if (rtt != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rt); break; } case MP_TUNNELBRIDGE: { TileIndex other_end = GetOtherTunnelBridgeEnd(tile); SetRoadTypes(other_end, GetRoadTypes(other_end) | RoadTypeToRoadTypes(rt)); SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); SetRoadOwner(other_end, rt, company); SetRoadOwner(tile, rt, company); /* Mark tiles dirty that have been repaved */ if (IsBridge(tile)) { MarkBridgeDirty(tile); } else { MarkTileDirtyByTile(other_end); MarkTileDirtyByTile(tile); } break; } case MP_STATION: assert(IsDriveThroughStopTile(tile)); SetRoadTypes(tile, GetRoadTypes(tile) | RoadTypeToRoadTypes(rt)); SetRoadOwner(tile, rt, company); break; default: MakeRoadNormal(tile, pieces, RoadTypeToRoadTypes(rt), p2, company, company); break; } /* Update company infrastructure count. */ Company *c = Company::GetIfValid(GetRoadOwner(tile, rt)); if (c != NULL) { if (IsTileType(tile, MP_TUNNELBRIDGE)) num_pieces *= TUNNELBRIDGE_TRACKBIT_FACTOR; c->infrastructure.road[rt] += num_pieces; DirtyCompanyInfrastructureWindows(c->index); } if (rt != ROADTYPE_TRAM && IsNormalRoadTile(tile)) { existing |= pieces; SetDisallowedRoadDirections(tile, IsStraightRoad(existing) ? GetDisallowedRoadDirections(tile) ^ toggle_drd : DRD_NONE); } MarkTileDirtyByTile(tile); } return cost; } /** * Checks whether a road or tram connection can be found when building a new road or tram. * @param tile Tile at which the road being built will end. * @param rt Roadtype of the road being built. * @param dir Direction that the road is following. * @return True if the next tile at dir direction is suitable for being connected directly by a second roadbit at the end of the road being built. */ static bool CanConnectToRoad(TileIndex tile, RoadType rt, DiagDirection dir) { RoadBits bits = GetAnyRoadBits(tile + TileOffsByDiagDir(dir), rt, false); return (bits & DiagDirToRoadBits(ReverseDiagDir(dir))) != 0; } /** * Build a long piece of road. * @param start_tile start tile of drag (the building cost will appear over this tile) * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1). Only used if bit 6 is set or if we are building a single tile * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2). Only used if bit 6 is set or if we are building a single tile * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) * - p2 = (bit 3 + 4) - road type * - p2 = (bit 5) - set road direction * - p2 = (bit 6) - defines two different behaviors for this command: * - 0 = Build up to an obstacle. Do not build the first and last roadbits unless they can be connected to something, or if we are building a single tile * - 1 = Fail if an obstacle is found. Always take into account bit 0 and 1. This behavior is used for scripts * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { DisallowedRoadDirections drd = DRD_NORTHBOUND; if (p1 >= MapSize()) return CMD_ERROR; TileIndex end_tile = p1; RoadType rt = Extract(p2); if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; Axis axis = Extract(p2); /* Only drag in X or Y direction dictated by the direction variable */ if (axis == AXIS_X && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis if (axis == AXIS_Y && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis DiagDirection dir = AxisToDiagDir(axis); /* Swap direction, also the half-tile drag var (bit 0 and 1) */ if (start_tile > end_tile || (start_tile == end_tile && HasBit(p2, 0))) { dir = ReverseDiagDir(dir); p2 ^= 3; drd = DRD_SOUTHBOUND; } /* On the X-axis, we have to swap the initial bits, so they * will be interpreted correctly in the GTTS. Furthermore * when you just 'click' on one tile to build them. */ if ((axis == AXIS_Y) == (start_tile == end_tile && HasBit(p2, 0) == HasBit(p2, 1))) drd ^= DRD_BOTH; /* No disallowed direction bits have to be toggled */ if (!HasBit(p2, 5)) drd = DRD_NONE; CommandCost cost(EXPENSES_CONSTRUCTION); CommandCost last_error = CMD_ERROR; TileIndex tile = start_tile; bool had_bridge = false; bool had_tunnel = false; bool had_success = false; bool is_ai = HasBit(p2, 6); /* Start tile is the first tile clicked by the user. */ for (;;) { RoadBits bits = AxisToRoadBits(axis); /* Determine which road parts should be built. */ if (!is_ai && start_tile != end_tile) { /* Only build the first and last roadbit if they can connect to something. */ if (tile == end_tile && !CanConnectToRoad(tile, rt, dir)) { bits = DiagDirToRoadBits(ReverseDiagDir(dir)); } else if (tile == start_tile && !CanConnectToRoad(tile, rt, ReverseDiagDir(dir))) { bits = DiagDirToRoadBits(dir); } } else { /* Road parts only have to be built at the start tile or at the end tile. */ if (tile == end_tile && !HasBit(p2, 1)) bits &= DiagDirToRoadBits(ReverseDiagDir(dir)); if (tile == start_tile && HasBit(p2, 0)) bits &= DiagDirToRoadBits(dir); } CommandCost ret = DoCommand(tile, drd << 6 | rt << 4 | bits, 0, flags, CMD_BUILD_ROAD); if (ret.Failed()) { last_error = ret; if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT) { if (is_ai) return last_error; break; } } else { had_success = true; /* Only pay for the upgrade on one side of the bridges and tunnels */ if (IsTileType(tile, MP_TUNNELBRIDGE)) { if (IsBridge(tile)) { if (!had_bridge || GetTunnelBridgeDirection(tile) == dir) { cost.AddCost(ret); } had_bridge = true; } else { // IsTunnel(tile) if (!had_tunnel || GetTunnelBridgeDirection(tile) == dir) { cost.AddCost(ret); } had_tunnel = true; } } else { cost.AddCost(ret); } } if (tile == end_tile) break; tile += TileOffsByDiagDir(dir); } return had_success ? cost : last_error; } /** * Remove a long piece of road. * @param start_tile start tile of drag * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1) * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2) * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4) * - p2 = (bit 3 + 4) - road type * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRemoveLongRoad(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CommandCost cost(EXPENSES_CONSTRUCTION); if (p1 >= MapSize()) return CMD_ERROR; TileIndex end_tile = p1; RoadType rt = Extract(p2); if (!IsValidRoadType(rt)) return CMD_ERROR; Axis axis = Extract(p2); /* Only drag in X or Y direction dictated by the direction variable */ if (axis == AXIS_X && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis if (axis == AXIS_Y && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis /* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */ if (start_tile > end_tile || (start_tile == end_tile && HasBit(p2, 0))) { TileIndex t = start_tile; start_tile = end_tile; end_tile = t; p2 ^= IsInsideMM(p2 & 3, 1, 3) ? 3 : 0; } Money money = GetAvailableMoneyForCommand(); TileIndex tile = start_tile; CommandCost last_error = CMD_ERROR; bool had_success = false; /* Start tile is the small number. */ for (;;) { RoadBits bits = AxisToRoadBits(axis); if (tile == end_tile && !HasBit(p2, 1)) bits &= ROAD_NW | ROAD_NE; if (tile == start_tile && HasBit(p2, 0)) bits &= ROAD_SE | ROAD_SW; /* try to remove the halves. */ if (bits != 0) { CommandCost ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rt, true); if (ret.Succeeded()) { if (flags & DC_EXEC) { money -= ret.GetCost(); if (money < 0) { _additional_cash_required = DoCommand(start_tile, end_tile, p2, flags & ~DC_EXEC, CMD_REMOVE_LONG_ROAD).GetCost(); return cost; } RemoveRoad(tile, flags, bits, rt, true, false); } cost.AddCost(ret); had_success = true; } else { /* Ownership errors are more important. */ if (last_error.GetErrorMessage() != STR_ERROR_OWNED_BY) last_error = ret; } } if (tile == end_tile) break; tile += (axis == AXIS_Y) ? TileDiffXY(0, 1) : TileDiffXY(1, 0); } return had_success ? cost : last_error; } /** * Build a road depot. * @param tile tile where to build the depot * @param flags operation to perform * @param p1 bit 0..1 entrance direction (DiagDirection) * bit 2..3 road type * @param p2 unused * @param text unused * @return the cost of this operation or an error * * @todo When checking for the tile slope, * distinguish between "Flat land required" and "land sloped in wrong direction" */ CommandCost CmdBuildRoadDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { DiagDirection dir = Extract(p1); RoadType rt = Extract(p1); if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR; Slope tileh = GetTileSlope(tile); if (tileh != SLOPE_FLAT && ( !_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh) )) { return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); } CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (cost.Failed()) return cost; if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); if (!Depot::CanAllocateItem()) return CMD_ERROR; if (flags & DC_EXEC) { Depot *dep = new Depot(tile); dep->build_date = _date; /* A road depot has two road bits. */ Company::Get(_current_company)->infrastructure.road[rt] += 2; DirtyCompanyInfrastructureWindows(_current_company); MakeRoadDepot(tile, _current_company, dep->index, dir, rt); MarkTileDirtyByTile(tile); MakeDefaultName(dep); } cost.AddCost(_price[PR_BUILD_DEPOT_ROAD]); return cost; } static CommandCost RemoveRoadDepot(TileIndex tile, DoCommandFlag flags) { if (_current_company != OWNER_WATER) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; if (flags & DC_EXEC) { Company *c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { /* A road depot has two road bits. */ c->infrastructure.road[FIND_FIRST_BIT(GetRoadTypes(tile))] -= 2; DirtyCompanyInfrastructureWindows(c->index); } delete Depot::GetByTile(tile); DoClearSquare(tile); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_ROAD]); } static CommandCost ClearTile_Road(TileIndex tile, DoCommandFlag flags) { switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { RoadBits b = GetAllRoadBits(tile); /* Clear the road if only one piece is on the tile OR we are not using the DC_AUTO flag */ if ((HasExactlyOneBit(b) && GetRoadBits(tile, ROADTYPE_TRAM) == ROAD_NONE) || !(flags & DC_AUTO)) { CommandCost ret(EXPENSES_CONSTRUCTION); RoadType rt; FOR_EACH_SET_ROADTYPE(rt, GetRoadTypes(tile)) { CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rt), rt, true); if (tmp_ret.Failed()) return tmp_ret; ret.AddCost(tmp_ret); } return ret; } return_cmd_error(STR_ERROR_MUST_REMOVE_ROAD_FIRST); } case ROAD_TILE_CROSSING: { RoadTypes rts = GetRoadTypes(tile); CommandCost ret(EXPENSES_CONSTRUCTION); if (flags & DC_AUTO) return_cmd_error(STR_ERROR_MUST_REMOVE_ROAD_FIRST); /* Must iterate over the roadtypes in a reverse manner because * tram tracks must be removed before the road bits. */ RoadType rt = ROADTYPE_TRAM; do { if (HasBit(rts, rt)) { CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rt, false); if (tmp_ret.Failed()) return tmp_ret; ret.AddCost(tmp_ret); } } while (rt-- != ROADTYPE_ROAD); if (flags & DC_EXEC) { DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } return ret; } default: case ROAD_TILE_DEPOT: if (flags & DC_AUTO) { return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); } return RemoveRoadDepot(tile, flags); } } struct DrawRoadTileStruct { uint16 image; byte subcoord_x; byte subcoord_y; }; #include "table/road_land.h" /** * Get the foundationtype of a RoadBits Slope combination * * @param tileh The Slope part * @param bits The RoadBits part * @return The resulting Foundation */ static Foundation GetRoadFoundation(Slope tileh, RoadBits bits) { /* Flat land and land without a road doesn't require a foundation */ if (tileh == SLOPE_FLAT || bits == ROAD_NONE) return FOUNDATION_NONE; /* Steep slopes behave the same as slopes with one corner raised. */ if (IsSteepSlope(tileh)) { tileh = SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh)); } /* Leveled RoadBits on a slope */ if ((_invalid_tileh_slopes_road[0][tileh] & bits) == ROAD_NONE) return FOUNDATION_LEVELED; /* Straight roads without foundation on a slope */ if (!IsSlopeWithOneCornerRaised(tileh) && (_invalid_tileh_slopes_road[1][tileh] & bits) == ROAD_NONE) return FOUNDATION_NONE; /* Roads on steep Slopes or on Slopes with one corner raised */ return (bits == ROAD_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y); } const byte _road_sloped_sprites[14] = { 0, 0, 2, 0, 0, 1, 0, 0, 3, 0, 0, 0, 0, 0 }; /** * Should the road be drawn as a unpaved snow/desert road? * By default, roads are always drawn as unpaved if they are on desert or * above the snow line, but NewGRFs can override this for desert. * * @param tile The tile the road is on * @param roadside What sort of road this is * @return True if snow/desert road sprites should be used. */ static bool DrawRoadAsSnowDesert(TileIndex tile, Roadside roadside) { return (IsOnSnow(tile) && !(_settings_game.game_creation.landscape == LT_TROPIC && HasGrfMiscBit(GMB_DESERT_PAVED_ROADS) && roadside != ROADSIDE_BARREN && roadside != ROADSIDE_GRASS && roadside != ROADSIDE_GRASS_ROAD_WORKS)); } /** * Draws the catenary for the given tile * @param ti information about the tile (slopes, height etc) * @param tram the roadbits for the tram */ void DrawTramCatenary(const TileInfo *ti, RoadBits tram) { /* Do not draw catenary if it is invisible */ if (IsInvisibilitySet(TO_CATENARY)) return; /* Don't draw the catenary under a low bridge */ if (IsBridgeAbove(ti->tile) && !IsTransparencySet(TO_CATENARY)) { int height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile)); if (height <= GetTileMaxZ(ti->tile) + 1) return; } SpriteID front; SpriteID back; if (ti->tileh != SLOPE_FLAT) { back = SPR_TRAMWAY_BACK_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1]; front = SPR_TRAMWAY_FRONT_WIRES_SLOPED + _road_sloped_sprites[ti->tileh - 1]; } else { back = SPR_TRAMWAY_BASE + _road_backpole_sprites_1[tram]; front = SPR_TRAMWAY_BASE + _road_frontwire_sprites_1[tram]; } AddSortableSpriteToDraw(back, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); AddSortableSpriteToDraw(front, PAL_NONE, ti->x, ti->y, 16, 16, TILE_HEIGHT + BB_HEIGHT_UNDER_BRIDGE, ti->z, IsTransparencySet(TO_CATENARY)); } /** * Draws details on/around the road * @param img the sprite to draw * @param ti the tile to draw on * @param dx the offset from the top of the BB of the tile * @param dy the offset from the top of the BB of the tile * @param h the height of the sprite to draw */ static void DrawRoadDetail(SpriteID img, const TileInfo *ti, int dx, int dy, int h) { int x = ti->x | dx; int y = ti->y | dy; int z = ti->z; if (ti->tileh != SLOPE_FLAT) z = GetSlopePixelZ(x, y); AddSortableSpriteToDraw(img, PAL_NONE, x, y, 2, 2, h, z); } /** * Draw ground sprite and road pieces * @param ti TileInfo */ static void DrawRoadBits(TileInfo *ti) { RoadBits road = GetRoadBits(ti->tile, ROADTYPE_ROAD); RoadBits tram = GetRoadBits(ti->tile, ROADTYPE_TRAM); SpriteID image = 0; PaletteID pal = PAL_NONE; if (ti->tileh != SLOPE_FLAT) { DrawFoundation(ti, GetRoadFoundation(ti->tileh, road | tram)); /* DrawFoundation() modifies ti. * Default sloped sprites.. */ if (ti->tileh != SLOPE_FLAT) image = _road_sloped_sprites[ti->tileh - 1] + SPR_ROAD_SLOPE_START; } if (image == 0) image = _road_tile_sprites_1[road != ROAD_NONE ? road : tram]; Roadside roadside = GetRoadside(ti->tile); if (DrawRoadAsSnowDesert(ti->tile, roadside)) { image += 19; } else { switch (roadside) { case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break; case ROADSIDE_GRASS: break; case ROADSIDE_GRASS_ROAD_WORKS: break; default: image -= 19; break; // Paved } } DrawGroundSprite(image, pal); /* For tram we overlay the road graphics with either tram tracks only * (when there is actual road beneath the trams) or with tram tracks * and some dirts which hides the road graphics */ if (tram != ROAD_NONE) { if (ti->tileh != SLOPE_FLAT) { image = _road_sloped_sprites[ti->tileh - 1] + SPR_TRAMWAY_SLOPED_OFFSET; } else { image = _road_tile_sprites_1[tram] - SPR_ROAD_Y; } image += (road == ROAD_NONE) ? SPR_TRAMWAY_TRAM : SPR_TRAMWAY_OVERLAY; DrawGroundSprite(image, pal); } if (road != ROAD_NONE) { DisallowedRoadDirections drd = GetDisallowedRoadDirections(ti->tile); if (drd != DRD_NONE) { DrawGroundSpriteAt(SPR_ONEWAY_BASE + drd - 1 + ((road == ROAD_X) ? 0 : 3), PAL_NONE, 8, 8, GetPartialPixelZ(8, 8, ti->tileh)); } } if (HasRoadWorks(ti->tile)) { /* Road works */ DrawGroundSprite((road | tram) & ROAD_X ? SPR_EXCAVATION_X : SPR_EXCAVATION_Y, PAL_NONE); return; } if (tram != ROAD_NONE) DrawTramCatenary(ti, tram); /* Return if full detail is disabled, or we are zoomed fully out. */ if (!HasBit(_display_opt, DO_FULL_DETAIL) || _cur_dpi->zoom > ZOOM_LVL_DETAIL) return; /* Do not draw details (street lights, trees) under low bridge */ if (IsBridgeAbove(ti->tile) && (roadside == ROADSIDE_TREES || roadside == ROADSIDE_STREET_LIGHTS)) { int height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile)); int minz = GetTileMaxZ(ti->tile) + 2; if (roadside == ROADSIDE_TREES) minz++; if (height < minz) return; } /* If there are no road bits, return, as there is nothing left to do */ if (HasAtMostOneBit(road)) return; /* Draw extra details. */ for (const DrawRoadTileStruct *drts = _road_display_table[roadside][road | tram]; drts->image != 0; drts++) { DrawRoadDetail(drts->image, ti, drts->subcoord_x, drts->subcoord_y, 0x10); } } /** Tile callback function for rendering a road tile to the screen */ static void DrawTile_Road(TileInfo *ti) { switch (GetRoadTileType(ti->tile)) { case ROAD_TILE_NORMAL: DrawRoadBits(ti); break; case ROAD_TILE_CROSSING: { if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); PaletteID pal = PAL_NONE; const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); if (rti->UsesOverlay()) { Axis axis = GetCrossingRailAxis(ti->tile); SpriteID road = SPR_ROAD_Y + axis; Roadside roadside = GetRoadside(ti->tile); if (DrawRoadAsSnowDesert(ti->tile, roadside)) { road += 19; } else { switch (roadside) { case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break; case ROADSIDE_GRASS: break; default: road -= 19; break; // Paved } } DrawGroundSprite(road, pal); SpriteID rail = GetCustomRailSprite(rti, ti->tile, RTSG_CROSSING) + axis; /* Draw tracks, but draw PBS reserved tracks darker. */ pal = (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile)) ? PALETTE_CRASH : PAL_NONE; DrawGroundSprite(rail, pal); DrawRailTileSeq(ti, &_crossing_layout, TO_CATENARY, rail, 0, PAL_NONE); } else { SpriteID image = rti->base_sprites.crossing; if (GetCrossingRoadAxis(ti->tile) == AXIS_X) image++; if (IsCrossingBarred(ti->tile)) image += 2; Roadside roadside = GetRoadside(ti->tile); if (DrawRoadAsSnowDesert(ti->tile, roadside)) { image += 8; } else { switch (roadside) { case ROADSIDE_BARREN: pal = PALETTE_TO_BARE_LAND; break; case ROADSIDE_GRASS: break; default: image += 4; break; // Paved } } DrawGroundSprite(image, pal); /* PBS debugging, draw reserved tracks darker */ if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasCrossingReservation(ti->tile)) { DrawGroundSprite(GetCrossingRoadAxis(ti->tile) == AXIS_Y ? GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_x : GetRailTypeInfo(GetRailType(ti->tile))->base_sprites.single_y, PALETTE_CRASH); } } if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) { DrawGroundSprite(SPR_TRAMWAY_OVERLAY + (GetCrossingRoadAxis(ti->tile) ^ 1), pal); DrawTramCatenary(ti, GetCrossingRoadBits(ti->tile)); } if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti); break; } default: case ROAD_TILE_DEPOT: { if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); PaletteID palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)); const DrawTileSprites *dts; if (HasTileRoadType(ti->tile, ROADTYPE_TRAM)) { dts = &_tram_depot[GetRoadDepotDirection(ti->tile)]; } else { dts = &_road_depot[GetRoadDepotDirection(ti->tile)]; } DrawGroundSprite(dts->ground.sprite, PAL_NONE); DrawOrigTileSeq(ti, dts, TO_BUILDINGS, palette); break; } } DrawBridgeMiddle(ti); } /** * Draw the road depot sprite. * @param x The x offset to draw at. * @param y The y offset to draw at. * @param dir The direction the depot must be facing. * @param rt The road type of the depot to draw. */ void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt) { PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); const DrawTileSprites *dts = (rt == ROADTYPE_TRAM) ? &_tram_depot[dir] : &_road_depot[dir]; DrawSprite(dts->ground.sprite, PAL_NONE, x, y); DrawOrigTileSeqInGUI(x, y, dts, palette); } /** * Updates cached nearest town for all road tiles * @param invalidate are we just invalidating cached data? * @pre invalidate == true implies _generating_world == true */ void UpdateNearestTownForRoadTiles(bool invalidate) { assert(!invalidate || _generating_world); for (TileIndex t = 0; t < MapSize(); t++) { if (IsTileType(t, MP_ROAD) && !IsRoadDepot(t) && !HasTownOwnedRoad(t)) { TownID tid = (TownID)INVALID_TOWN; if (!invalidate) { const Town *town = CalcClosestTownFromTile(t); if (town != NULL) tid = town->index; } SetTownIndex(t, tid); } } } static int GetSlopePixelZ_Road(TileIndex tile, uint x, uint y) { if (IsNormalRoad(tile)) { int z; Slope tileh = GetTilePixelSlope(tile, &z); if (tileh == SLOPE_FLAT) return z; Foundation f = GetRoadFoundation(tileh, GetAllRoadBits(tile)); z += ApplyPixelFoundationToSlope(f, &tileh); return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh); } else { return GetTileMaxPixelZ(tile); } } static Foundation GetFoundation_Road(TileIndex tile, Slope tileh) { if (IsNormalRoad(tile)) { return GetRoadFoundation(tileh, GetAllRoadBits(tile)); } else { return FlatteningFoundation(tileh); } } static const Roadside _town_road_types[][2] = { { ROADSIDE_GRASS, ROADSIDE_GRASS }, { ROADSIDE_PAVED, ROADSIDE_PAVED }, { ROADSIDE_PAVED, ROADSIDE_PAVED }, { ROADSIDE_TREES, ROADSIDE_TREES }, { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED } }; static const Roadside _town_road_types_2[][2] = { { ROADSIDE_GRASS, ROADSIDE_GRASS }, { ROADSIDE_PAVED, ROADSIDE_PAVED }, { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }, { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED }, { ROADSIDE_STREET_LIGHTS, ROADSIDE_PAVED } }; static void TileLoop_Road(TileIndex tile) { switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: if (IsOnSnow(tile) != (GetTileZ(tile) > GetSnowLine())) { ToggleSnow(tile); MarkTileDirtyByTile(tile); } break; case LT_TROPIC: if (GetTropicZone(tile) == TROPICZONE_DESERT && !IsOnDesert(tile)) { ToggleDesert(tile); MarkTileDirtyByTile(tile); } break; } if (IsRoadDepot(tile)) return; const Town *t = ClosestTownFromTile(tile, UINT_MAX); if (!HasRoadWorks(tile)) { HouseZonesBits grp = HZB_TOWN_EDGE; if (t != NULL) { grp = GetTownRadiusGroup(t, tile); /* Show an animation to indicate road work */ if (t->road_build_months != 0 && (DistanceManhattan(t->xy, tile) < 8 || grp != HZB_TOWN_EDGE) && IsNormalRoad(tile) && !HasAtMostOneBit(GetAllRoadBits(tile))) { if (GetFoundationSlope(tile) == SLOPE_FLAT && EnsureNoVehicleOnGround(tile).Succeeded() && Chance16(1, 40)) { StartRoadWorks(tile); if (_settings_client.sound.ambient) SndPlayTileFx(SND_21_JACKHAMMER, tile); CreateEffectVehicleAbove( TileX(tile) * TILE_SIZE + 7, TileY(tile) * TILE_SIZE + 7, 0, EV_BULLDOZER); MarkTileDirtyByTile(tile); return; } } } { /* Adjust road ground type depending on 'grp' (grp is the distance to the center) */ const Roadside *new_rs = (_settings_game.game_creation.landscape == LT_TOYLAND) ? _town_road_types_2[grp] : _town_road_types[grp]; Roadside cur_rs = GetRoadside(tile); /* We have our desired type, do nothing */ if (cur_rs == new_rs[0]) return; /* We have the pre-type of the desired type, switch to the desired type */ if (cur_rs == new_rs[1]) { cur_rs = new_rs[0]; /* We have barren land, install the pre-type */ } else if (cur_rs == ROADSIDE_BARREN) { cur_rs = new_rs[1]; /* We're totally off limits, remove any installation and make barren land */ } else { cur_rs = ROADSIDE_BARREN; } SetRoadside(tile, cur_rs); MarkTileDirtyByTile(tile); } } else if (IncreaseRoadWorksCounter(tile)) { TerminateRoadWorks(tile); if (_settings_game.economy.mod_road_rebuild) { /* Generate a nicer town surface */ const RoadBits old_rb = GetAnyRoadBits(tile, ROADTYPE_ROAD); const RoadBits new_rb = CleanUpRoadBits(tile, old_rb); if (old_rb != new_rb) { RemoveRoad(tile, DC_EXEC | DC_AUTO | DC_NO_WATER, (old_rb ^ new_rb), ROADTYPE_ROAD, true); } } MarkTileDirtyByTile(tile); } } static bool ClickTile_Road(TileIndex tile) { if (!IsRoadDepot(tile)) return false; ShowDepotWindow(tile, VEH_ROAD); return true; } /* Converts RoadBits to TrackBits */ static const TrackBits _road_trackbits[16] = { TRACK_BIT_NONE, // ROAD_NONE TRACK_BIT_NONE, // ROAD_NW TRACK_BIT_NONE, // ROAD_SW TRACK_BIT_LEFT, // ROAD_W TRACK_BIT_NONE, // ROAD_SE TRACK_BIT_Y, // ROAD_Y TRACK_BIT_LOWER, // ROAD_S TRACK_BIT_LEFT | TRACK_BIT_LOWER | TRACK_BIT_Y, // ROAD_Y | ROAD_SW TRACK_BIT_NONE, // ROAD_NE TRACK_BIT_UPPER, // ROAD_N TRACK_BIT_X, // ROAD_X TRACK_BIT_LEFT | TRACK_BIT_UPPER | TRACK_BIT_X, // ROAD_X | ROAD_NW TRACK_BIT_RIGHT, // ROAD_E TRACK_BIT_RIGHT | TRACK_BIT_UPPER | TRACK_BIT_Y, // ROAD_Y | ROAD_NE TRACK_BIT_RIGHT | TRACK_BIT_LOWER | TRACK_BIT_X, // ROAD_X | ROAD_SE TRACK_BIT_ALL, // ROAD_ALL }; static TrackStatus GetTileTrackStatus_Road(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { TrackdirBits trackdirbits = TRACKDIR_BIT_NONE; TrackdirBits red_signals = TRACKDIR_BIT_NONE; // crossing barred switch (mode) { case TRANSPORT_RAIL: if (IsLevelCrossing(tile)) trackdirbits = TrackBitsToTrackdirBits(GetCrossingRailBits(tile)); break; case TRANSPORT_ROAD: if ((GetRoadTypes(tile) & sub_mode) == 0) break; switch (GetRoadTileType(tile)) { case ROAD_TILE_NORMAL: { const uint drd_to_multiplier[DRD_END] = { 0x101, 0x100, 0x1, 0x0 }; RoadType rt = (RoadType)FindFirstBit(sub_mode); RoadBits bits = GetRoadBits(tile, rt); /* no roadbit at this side of tile, return 0 */ if (side != INVALID_DIAGDIR && (DiagDirToRoadBits(side) & bits) == 0) break; uint multiplier = drd_to_multiplier[rt == ROADTYPE_TRAM ? DRD_NONE : GetDisallowedRoadDirections(tile)]; if (!HasRoadWorks(tile)) trackdirbits = (TrackdirBits)(_road_trackbits[bits] * multiplier); break; } case ROAD_TILE_CROSSING: { Axis axis = GetCrossingRoadAxis(tile); if (side != INVALID_DIAGDIR && axis != DiagDirToAxis(side)) break; trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(axis)); if (IsCrossingBarred(tile)) red_signals = trackdirbits; break; } default: case ROAD_TILE_DEPOT: { DiagDirection dir = GetRoadDepotDirection(tile); if (side != INVALID_DIAGDIR && side != dir) break; trackdirbits = TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)); break; } } break; default: break; } return CombineTrackStatus(trackdirbits, red_signals); } static const StringID _road_tile_strings[] = { STR_LAI_ROAD_DESCRIPTION_ROAD, STR_LAI_ROAD_DESCRIPTION_ROAD, STR_LAI_ROAD_DESCRIPTION_ROAD, STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS, STR_LAI_ROAD_DESCRIPTION_ROAD, STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD, STR_LAI_ROAD_DESCRIPTION_ROAD, STR_LAI_ROAD_DESCRIPTION_ROAD, }; static void GetTileDesc_Road(TileIndex tile, TileDesc *td) { Owner rail_owner = INVALID_OWNER; Owner road_owner = INVALID_OWNER; Owner tram_owner = INVALID_OWNER; switch (GetRoadTileType(tile)) { case ROAD_TILE_CROSSING: { td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING; RoadTypes rts = GetRoadTypes(tile); rail_owner = GetTileOwner(tile); if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); td->rail_speed = rti->max_speed; break; } case ROAD_TILE_DEPOT: td->str = STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT; road_owner = GetTileOwner(tile); // Tile has only one owner, roadtype does not matter td->build_date = Depot::GetByTile(tile)->build_date; break; default: { RoadTypes rts = GetRoadTypes(tile); td->str = (HasBit(rts, ROADTYPE_ROAD) ? _road_tile_strings[GetRoadside(tile)] : STR_LAI_ROAD_DESCRIPTION_TRAMWAY); if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); break; } } /* Now we have to discover, if the tile has only one owner or many: * - Find a first_owner of the tile. (Currently road or tram must be present, but this will break when the third type becomes available) * - Compare the found owner with the other owners, and test if they differ. * Note: If road exists it will be the first_owner. */ Owner first_owner = (road_owner == INVALID_OWNER ? tram_owner : road_owner); bool mixed_owners = (tram_owner != INVALID_OWNER && tram_owner != first_owner) || (rail_owner != INVALID_OWNER && rail_owner != first_owner); if (mixed_owners) { /* Multiple owners */ td->owner_type[0] = (rail_owner == INVALID_OWNER ? STR_NULL : STR_LAND_AREA_INFORMATION_RAIL_OWNER); td->owner[0] = rail_owner; td->owner_type[1] = (road_owner == INVALID_OWNER ? STR_NULL : STR_LAND_AREA_INFORMATION_ROAD_OWNER); td->owner[1] = road_owner; td->owner_type[2] = (tram_owner == INVALID_OWNER ? STR_NULL : STR_LAND_AREA_INFORMATION_TRAM_OWNER); td->owner[2] = tram_owner; } else { /* One to rule them all */ td->owner[0] = first_owner; } } /** * Given the direction the road depot is pointing, this is the direction the * vehicle should be travelling in in order to enter the depot. */ static const byte _roadveh_enter_depot_dir[4] = { TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_X_NE, TRACKDIR_Y_SE }; static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y) { switch (GetRoadTileType(tile)) { case ROAD_TILE_DEPOT: { if (v->type != VEH_ROAD) break; RoadVehicle *rv = RoadVehicle::From(v); if (rv->frame == RVC_DEPOT_STOP_FRAME && _roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == rv->state) { rv->state = RVSB_IN_DEPOT; rv->vehstatus |= VS_HIDDEN; rv->direction = ReverseDir(rv->direction); if (rv->Next() == NULL) VehicleEnterDepot(rv->First()); rv->tile = tile; InvalidateWindowData(WC_VEHICLE_DEPOT, rv->tile); return VETSB_ENTERED_WORMHOLE; } break; } default: break; } return VETSB_CONTINUE; } static void ChangeTileOwner_Road(TileIndex tile, Owner old_owner, Owner new_owner) { if (IsRoadDepot(tile)) { if (GetTileOwner(tile) == old_owner) { if (new_owner == INVALID_OWNER) { DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); } else { /* A road depot has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ RoadType rt = (RoadType)FIND_FIRST_BIT(GetRoadTypes(tile)); Company::Get(old_owner)->infrastructure.road[rt] -= 2; Company::Get(new_owner)->infrastructure.road[rt] += 2; SetTileOwner(tile, new_owner); for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { if (GetRoadOwner(tile, rt) == old_owner) { SetRoadOwner(tile, rt, new_owner); } } } } return; } for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) { /* Update all roadtypes, no matter if they are present */ if (GetRoadOwner(tile, rt) == old_owner) { if (HasTileRoadType(tile, rt)) { /* A level crossing has two road bits. No need to dirty windows here, we'll redraw the whole screen anyway. */ uint num_bits = IsLevelCrossing(tile) ? 2 : CountBits(GetRoadBits(tile, rt)); Company::Get(old_owner)->infrastructure.road[rt] -= num_bits; if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.road[rt] += num_bits; } SetRoadOwner(tile, rt, new_owner == INVALID_OWNER ? OWNER_NONE : new_owner); } } if (IsLevelCrossing(tile)) { if (GetTileOwner(tile) == old_owner) { if (new_owner == INVALID_OWNER) { DoCommand(tile, 0, GetCrossingRailTrack(tile), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL); } else { /* Update infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */ Company::Get(old_owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR; Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += LEVELCROSSING_TRACKBIT_FACTOR; SetTileOwner(tile, new_owner); } } } } static CommandCost TerraformTile_Road(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) { switch (GetRoadTileType(tile)) { case ROAD_TILE_CROSSING: if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) && HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); break; case ROAD_TILE_DEPOT: if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); break; case ROAD_TILE_NORMAL: { RoadBits bits = GetAllRoadBits(tile); RoadBits bits_copy = bits; /* Check if the slope-road_bits combination is valid at all, i.e. it is safe to call GetRoadFoundation(). */ if (CheckRoadSlope(tileh_new, &bits_copy, ROAD_NONE, ROAD_NONE).Succeeded()) { /* CheckRoadSlope() sometimes changes the road_bits, if it does not agree with them. */ if (bits == bits_copy) { int z_old; Slope tileh_old = GetTileSlope(tile, &z_old); /* Get the slope on top of the foundation */ z_old += ApplyFoundationToSlope(GetRoadFoundation(tileh_old, bits), &tileh_old); z_new += ApplyFoundationToSlope(GetRoadFoundation(tileh_new, bits), &tileh_new); /* The surface slope must not be changed */ if ((z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } } break; } default: NOT_REACHED(); } } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } /** Tile callback functions for road tiles */ extern const TileTypeProcs _tile_type_road_procs = { DrawTile_Road, // draw_tile_proc GetSlopePixelZ_Road, // get_slope_z_proc ClearTile_Road, // clear_tile_proc NULL, // add_accepted_cargo_proc GetTileDesc_Road, // get_tile_desc_proc GetTileTrackStatus_Road, // get_tile_track_status_proc ClickTile_Road, // click_tile_proc NULL, // animate_tile_proc TileLoop_Road, // tile_loop_proc ChangeTileOwner_Road, // change_tile_owner_proc NULL, // add_produced_cargo_proc VehicleEnter_Road, // vehicle_enter_tile_proc GetFoundation_Road, // get_foundation_proc TerraformTile_Road, // terraform_tile_proc }; openttd-1.5.3/src/void_map.h0000644000000000000000000000203712627373435014447 0ustar rootroot/* $Id: void_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 void_map.h Map accessors for void tiles. */ #ifndef VOID_MAP_H #define VOID_MAP_H #include "tile_map.h" /** * Make a nice void tile ;) * @param t the tile to make void */ static inline void MakeVoid(TileIndex t) { SetTileType(t, MP_VOID); SetTileHeight(t, 0); _m[t].m1 = 0; _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = 0; _me[t].m6 = 0; _me[t].m7 = 0; } #endif /* VOID_MAP_H */ openttd-1.5.3/src/newgrf_house.h0000644000000000000000000001067412627373436015353 0ustar rootroot/* $Id: newgrf_house.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 newgrf_house.h Functions related to NewGRF houses. */ #ifndef NEWGRF_HOUSE_H #define NEWGRF_HOUSE_H #include "newgrf_callbacks.h" #include "tile_cmd.h" #include "house_type.h" #include "newgrf_spritegroup.h" #include "newgrf_town.h" /** Scope resolver for houses. */ struct HouseScopeResolver : public ScopeResolver { HouseID house_id; ///< Type of house being queried. TileIndex tile; ///< Tile of this house. Town *town; ///< Town of this house. bool not_yet_constructed; ///< True for construction check. uint16 initial_random_bits; ///< Random bits during construction checks. uint32 watched_cargo_triggers; ///< Cargo types that triggered the watched cargo callback. HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town, bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers); /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; /* virtual */ uint32 GetTriggers() const; /* virtual */ void SetTriggers(int triggers) const; }; /** Resolver object to be used for houses (feature 07 spritegroups). */ struct HouseResolverObject : public ResolverObject { HouseScopeResolver house_scope; TownScopeResolver town_scope; HouseResolverObject(HouseID house_id, TileIndex tile, Town *town, CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0, bool not_yet_constructed = false, uint8 initial_random_bits = 0, uint32 watched_cargo_triggers = 0); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &this->house_scope; case VSG_SCOPE_PARENT: return &this->town_scope; default: return ResolverObject::GetScope(scope, relative); } } }; /** * Makes class IDs unique to each GRF file. * Houses can be assigned class IDs which are only comparable within the GRF * file they were defined in. This mapping ensures that if two houses have the * same class as defined by the GRF file, the classes are different within the * game. An array of HouseClassMapping structs is created, and the array index * of the struct that matches both the GRF ID and the class ID is the class ID * used in the game. * * Although similar to the HouseIDMapping struct above, this serves a different * purpose. Since the class ID is not saved anywhere, this mapping does not * need to be persistent; it just needs to keep class ids unique. */ struct HouseClassMapping { uint32 grfid; ///< The GRF ID of the file this class belongs to uint8 class_id; ///< The class id within the grf file }; HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid); void InitializeBuildingCounts(); void IncreaseBuildingCount(Town *t, HouseID house_id); void DecreaseBuildingCount(Town *t, HouseID house_id); void DrawNewHouseTile(TileInfo *ti, HouseID house_id); void AnimateNewHouseTile(TileIndex tile); void AnimateNewHouseConstruction(TileIndex tile); uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed = false, uint8 initial_random_bits = 0, uint32 watched_cargo_triggers = 0); void WatchedCargoCallback(TileIndex tile, uint32 trigger_cargoes); bool CanDeleteHouse(TileIndex tile); bool NewHouseTileLoop(TileIndex tile); enum HouseTrigger { /* The tile of the house has been triggered during the tileloop. */ HOUSE_TRIGGER_TILE_LOOP = 0x01, /* * The top tile of a (multitile) building has been triggered during and all * the tileloop other tiles of the same building get the same random value. */ HOUSE_TRIGGER_TILE_LOOP_TOP = 0x02, }; void TriggerHouse(TileIndex t, HouseTrigger trigger); #endif /* NEWGRF_HOUSE_H */ openttd-1.5.3/src/station_gui.h0000644000000000000000000000270612627373435015201 0ustar rootroot/* $Id: station_gui.h 26083 2013-11-24 14:29:32Z rubidium $ */ /* * 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 station_gui.h Contains enums and function declarations connected with stations GUI */ #ifndef STATION_GUI_H #define STATION_GUI_H #include "command_type.h" #include "tilearea_type.h" #include "window_type.h" /** Types of cargo to display for station coverage. */ enum StationCoverageType { SCT_PASSENGERS_ONLY, ///< Draw only passenger class cargoes. SCT_NON_PASSENGERS_ONLY, ///< Draw all non-passenger class cargoes. SCT_ALL, ///< Draw all cargoes. }; int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies); void CheckRedrawStationCoverage(const Window *w); void ShowSelectStationIfNeeded(const CommandContainer &cmd, TileArea ta); void ShowSelectWaypointIfNeeded(const CommandContainer &cmd, TileArea ta); #endif /* STATION_GUI_H */ openttd-1.5.3/src/elrail_func.h0000644000000000000000000000273412627373445015141 0ustar rootroot/* $Id: elrail_func.h 21845 2011-01-18 22:31:06Z rubidium $ */ /* * 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 elrail_func.h header file for electrified rail specific functions */ #ifndef ELRAIL_FUNC_H #define ELRAIL_FUNC_H #include "rail.h" #include "tile_cmd.h" #include "transparency.h" /** * Test if a rail type has catenary * @param rt Rail type to test */ static inline bool HasCatenary(RailType rt) { return HasBit(GetRailTypeInfo(rt)->flags, RTF_CATENARY); } /** * Test if we should draw rail catenary * @param rt Rail type to test */ static inline bool HasCatenaryDrawn(RailType rt) { return HasCatenary(rt) && !IsInvisibilitySet(TO_CATENARY) && !_settings_game.vehicle.disable_elrails; } void DrawCatenary(const TileInfo *ti); void DrawCatenaryOnTunnel(const TileInfo *ti); void DrawCatenaryOnBridge(const TileInfo *ti); bool SettingsDisableElrail(int32 p1); ///< _settings_game.disable_elrail callback #endif /* ELRAIL_FUNC_H */ openttd-1.5.3/src/newgrf_station.cpp0000644000000000000000000011014312627373442016231 0ustar rootroot/* $Id: newgrf_station.cpp 26580 2014-05-11 18:02:11Z rubidium $ */ /* * 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 newgrf_station.cpp Functions for dealing with station classes and custom stations. */ #include "stdafx.h" #include "debug.h" #include "station_base.h" #include "waypoint_base.h" #include "roadstop_base.h" #include "newgrf_cargo.h" #include "newgrf_station.h" #include "newgrf_spritegroup.h" #include "newgrf_sound.h" #include "newgrf_railtype.h" #include "town.h" #include "newgrf_town.h" #include "company_func.h" #include "tunnelbridge_map.h" #include "newgrf_animation_base.h" #include "newgrf_class_func.h" #include "safeguards.h" template /* static */ void NewGRFClass::InsertDefaults() { /* Set up initial data */ classes[0].global_id = 'DFLT'; classes[0].name = STR_STATION_CLASS_DFLT; classes[0].Insert(NULL); classes[1].global_id = 'WAYP'; classes[1].name = STR_STATION_CLASS_WAYP; classes[1].Insert(NULL); } template bool NewGRFClass::IsUIAvailable(uint index) const { return true; } INSTANTIATE_NEWGRF_CLASS_METHODS(StationClass, StationSpec, StationClassID, STAT_CLASS_MAX) static const uint NUM_STATIONSSPECS_PER_STATION = 255; ///< Maximum number of parts per station. enum TriggerArea { TA_TILE, TA_PLATFORM, TA_WHOLE, }; struct ETileArea : TileArea { ETileArea(const BaseStation *st, TileIndex tile, TriggerArea ta) { switch (ta) { default: NOT_REACHED(); case TA_TILE: this->tile = tile; this->w = 1; this->h = 1; break; case TA_PLATFORM: { TileIndex start, end; Axis axis = GetRailStationAxis(tile); TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis)); for (end = tile; IsRailStationTile(end + delta) && IsCompatibleTrainStationTile(end + delta, tile); end += delta) { /* Nothing */ } for (start = tile; IsRailStationTile(start - delta) && IsCompatibleTrainStationTile(start - delta, tile); start -= delta) { /* Nothing */ } this->tile = start; this->w = TileX(end) - TileX(start) + 1; this->h = TileY(end) - TileY(start) + 1; break; } case TA_WHOLE: st->GetTileArea(this, Station::IsExpected(st) ? STATION_RAIL : STATION_WAYPOINT); break; } } }; /** * Evaluate a tile's position within a station, and return the result in a bit-stuffed format. * if not centered: .TNLcCpP, if centered: .TNL..CP * - T = Tile layout number (#GetStationGfx) * - N = Number of platforms * - L = Length of platforms * - C = Current platform number from start, c = from end * - P = Position along platform from start, p = from end * . * if centered, C/P start from the centre and c/p are not available. * @return Platform information in bit-stuffed format. */ uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, int y, bool centred) { uint32 retval = 0; if (axis == AXIS_X) { Swap(platforms, length); Swap(x, y); } if (centred) { x -= platforms / 2; y -= length / 2; x = Clamp(x, -8, 7); y = Clamp(y, -8, 7); SB(retval, 0, 4, y & 0xF); SB(retval, 4, 4, x & 0xF); } else { SB(retval, 0, 4, min(15, y)); SB(retval, 4, 4, min(15, length - y - 1)); SB(retval, 8, 4, min(15, x)); SB(retval, 12, 4, min(15, platforms - x - 1)); } SB(retval, 16, 4, min(15, length)); SB(retval, 20, 4, min(15, platforms)); SB(retval, 24, 4, tile); return retval; } /** * Find the end of a railway station, from the \a tile, in the direction of \a delta. * @param tile Start tile. * @param delta Movement direction. * @param check_type Stop when the custom station type changes. * @param check_axis Stop when the station direction changes. * @return Found end of the railway station. */ static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis) { byte orig_type = 0; Axis orig_axis = AXIS_X; StationID sid = GetStationIndex(tile); if (check_type) orig_type = GetCustomStationSpecIndex(tile); if (check_axis) orig_axis = GetRailStationAxis(tile); for (;;) { TileIndex new_tile = TILE_ADD(tile, delta); if (!IsTileType(new_tile, MP_STATION) || GetStationIndex(new_tile) != sid) break; if (!HasStationRail(new_tile)) break; if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break; if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break; tile = new_tile; } return tile; } static uint32 GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_axis, bool centred) { int tx = TileX(tile); int ty = TileY(tile); int sx = TileX(FindRailStationEnd(tile, TileDiffXY(-1, 0), check_type, check_axis)); int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), check_type, check_axis)); int ex = TileX(FindRailStationEnd(tile, TileDiffXY( 1, 0), check_type, check_axis)) + 1; int ey = TileY(FindRailStationEnd(tile, TileDiffXY( 0, 1), check_type, check_axis)) + 1; tx -= sx; ex -= sx; ty -= sy; ey -= sy; return GetPlatformInfo(GetRailStationAxis(tile), GetStationGfx(tile), ex, ey, tx, ty, centred); } static uint32 GetRailContinuationInfo(TileIndex tile) { /* Tile offsets and exit dirs for X axis */ static const Direction x_dir[8] = { DIR_SW, DIR_NE, DIR_SE, DIR_NW, DIR_S, DIR_E, DIR_W, DIR_N }; static const DiagDirection x_exits[8] = { DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SW, DIAGDIR_NE }; /* Tile offsets and exit dirs for Y axis */ static const Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N }; static const DiagDirection y_exits[8] = { DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SE, DIAGDIR_NW }; Axis axis = GetRailStationAxis(tile); /* Choose appropriate lookup table to use */ const Direction *dir = axis == AXIS_X ? x_dir : y_dir; const DiagDirection *diagdir = axis == AXIS_X ? x_exits : y_exits; uint32 res = 0; uint i; for (i = 0; i < lengthof(x_dir); i++, dir++, diagdir++) { TileIndex neighbour_tile = tile + TileOffsByDir(*dir); TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(neighbour_tile, TRANSPORT_RAIL, 0)); if (trackbits != TRACK_BIT_NONE) { /* If there is any track on the tile, set the bit in the second byte */ SetBit(res, i + 8); /* With tunnels and bridges the tile has tracks, but they are not necessarily connected * with the next tile because the ramp is not going in the right direction. */ if (IsTileType(neighbour_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(neighbour_tile) != *diagdir) { continue; } /* If any track reaches our exit direction, set the bit in the lower byte */ if (trackbits & DiagdirReachesTracks(*diagdir)) SetBit(res, i); } } return res; } /* Station Resolver Functions */ /* virtual */ uint32 StationScopeResolver::GetRandomBits() const { return (this->st == NULL ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16); } /* virtual */ uint32 StationScopeResolver::GetTriggers() const { return this->st == NULL ? 0 : this->st->waiting_triggers; } /* virtual */ void StationScopeResolver::SetTriggers(int triggers) const { BaseStation *st = const_cast(this->st); assert(st != NULL); st->waiting_triggers = triggers; } /** * Station variable cache * This caches 'expensive' station variable lookups which iterate over * several tiles that may be called multiple times per Resolve(). */ static struct { uint32 v40; uint32 v41; uint32 v45; uint32 v46; uint32 v47; uint32 v49; uint8 valid; ///< Bits indicating what variable is valid (for each bit, \c 0 is invalid, \c 1 is valid). } _svc; /** * Get the town scope associated with a station, if it exists. * On the first call, the town scope is created (if possible). * @return Town scope, if available. */ TownScopeResolver *StationResolverObject::GetTown() { if (this->town_scope == NULL) { Town *t = NULL; if (this->station_scope.st != NULL) { t = this->station_scope.st->town; } else if (this->station_scope.tile != INVALID_TILE) { t = ClosestTownFromTile(this->station_scope.tile, UINT_MAX); } if (t == NULL) return NULL; this->town_scope = new TownScopeResolver(*this, t, this->station_scope.st == NULL); } return this->town_scope; } /* virtual */ uint32 StationScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { if (this->st == NULL) { /* Station does not exist, so we're in a purchase list or the land slope check callback. */ switch (variable) { case 0x40: case 0x41: case 0x46: case 0x47: case 0x49: return 0x2110000; // Platforms, tracks & position case 0x42: return 0; // Rail type (XXX Get current type from GUI?) case 0x43: return GetCompanyInfo(_current_company); // Station owner case 0x44: return 2; // PBS status case 0x67: // Land info of nearby tile if (this->axis != INVALID_AXIS && this->tile != INVALID_TILE) { TileIndex tile = this->tile; if (parameter != 0) tile = GetNearbyTile(parameter, tile, true, this->axis); // only perform if it is required Slope tileh = GetTileSlope(tile); bool swap = (this->axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E)); return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0); } break; case 0xFA: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Build date, clamped to a 16 bit value } *available = false; return UINT_MAX; } switch (variable) { /* Calculated station variables */ case 0x40: if (!HasBit(_svc.valid, 0)) { _svc.v40 = GetPlatformInfoHelper(this->tile, false, false, false); SetBit(_svc.valid, 0); } return _svc.v40; case 0x41: if (!HasBit(_svc.valid, 1)) { _svc.v41 = GetPlatformInfoHelper(this->tile, true, false, false); SetBit(_svc.valid, 1); } return _svc.v41; case 0x42: return GetTerrainType(this->tile) | (GetReverseRailTypeTranslation(GetRailType(this->tile), this->statspec->grf_prop.grffile) << 8); case 0x43: return GetCompanyInfo(this->st->owner); // Station owner case 0x44: return HasStationReservation(this->tile) ? 7 : 4; // PBS status case 0x45: if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(this->tile); SetBit(_svc.valid, 2); } return _svc.v45; case 0x46: if (!HasBit(_svc.valid, 3)) { _svc.v46 = GetPlatformInfoHelper(this->tile, false, false, true); SetBit(_svc.valid, 3); } return _svc.v46; case 0x47: if (!HasBit(_svc.valid, 4)) { _svc.v47 = GetPlatformInfoHelper(this->tile, true, false, true); SetBit(_svc.valid, 4); } return _svc.v47; case 0x49: if (!HasBit(_svc.valid, 5)) { _svc.v49 = GetPlatformInfoHelper(this->tile, false, true, false); SetBit(_svc.valid, 5); } return _svc.v49; case 0x4A: // Animation frame of tile return GetAnimationFrame(this->tile); /* Variables which use the parameter */ /* Variables 0x60 to 0x65 and 0x69 are handled separately below */ case 0x66: { // Animation frame of nearby tile TileIndex tile = this->tile; if (parameter != 0) tile = GetNearbyTile(parameter, tile); return this->st->TileBelongsToRailStation(tile) ? GetAnimationFrame(tile) : UINT_MAX; } case 0x67: { // Land info of nearby tile Axis axis = GetRailStationAxis(this->tile); TileIndex tile = this->tile; if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required Slope tileh = GetTileSlope(tile); bool swap = (axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E)); return GetNearbyTileInformation(tile, this->ro.grffile->grf_version >= 8) ^ (swap ? SLOPE_EW : 0); } case 0x68: { // Station info of nearby tiles TileIndex nearby_tile = GetNearbyTile(parameter, this->tile); if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF; uint32 grfid = this->st->speclist[GetCustomStationSpecIndex(this->tile)].grfid; bool perpendicular = GetRailStationAxis(this->tile) != GetRailStationAxis(nearby_tile); bool same_station = this->st->TileBelongsToRailStation(nearby_tile); uint32 res = GB(GetStationGfx(nearby_tile), 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10; if (IsCustomStationSpecIndex(nearby_tile)) { const StationSpecList ssl = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)]; res |= 1 << (ssl.grfid != grfid ? 9 : 8) | ssl.localidx; } return res; } /* General station variables */ case 0x82: return 50; case 0x84: return this->st->string_id; case 0x86: return 0; case 0xF0: return this->st->facilities; case 0xFA: return Clamp(this->st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); } return this->st->GetNewGRFVariable(this->ro, variable, parameter, available); } uint32 Station::GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const { switch (variable) { case 0x48: { // Accepted cargo types CargoID cargo_type; uint32 value = 0; for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) { if (HasBit(this->goods[cargo_type].status, GoodsEntry::GES_ACCEPTANCE)) SetBit(value, cargo_type); } return value; } case 0x8A: return this->had_vehicle_of_type; case 0xF1: return (this->airport.tile != INVALID_TILE) ? this->airport.GetSpec()->ttd_airport_type : ATP_TTDP_LARGE; case 0xF2: return (this->truck_stops != NULL) ? this->truck_stops->status : 0; case 0xF3: return (this->bus_stops != NULL) ? this->bus_stops->status : 0; case 0xF6: return this->airport.flags; case 0xF7: return GB(this->airport.flags, 8, 8); } /* Handle cargo variables with parameter, 0x60 to 0x65 and 0x69 */ if ((variable >= 0x60 && variable <= 0x65) || variable == 0x69) { CargoID c = GetCargoTranslation(parameter, object.grffile); if (c == CT_INVALID) { switch (variable) { case 0x62: return 0xFFFFFFFF; case 0x64: return 0xFF00; default: return 0; } } const GoodsEntry *ge = &this->goods[c]; switch (variable) { case 0x60: return min(ge->cargo.TotalCount(), 4095); case 0x61: return ge->HasVehicleEverTriedLoading() ? ge->time_since_pickup : 0; case 0x62: return ge->HasRating() ? ge->rating : 0xFFFFFFFF; case 0x63: return ge->cargo.DaysInTransit(); case 0x64: return ge->HasVehicleEverTriedLoading() ? ge->last_speed | (ge->last_age << 8) : 0xFF00; case 0x65: return GB(ge->status, GoodsEntry::GES_ACCEPTANCE, 1) << 3; case 0x69: { assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 1 == (int)GoodsEntry::GES_LAST_MONTH); assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 2 == (int)GoodsEntry::GES_CURRENT_MONTH); assert_compile((int)GoodsEntry::GES_EVER_ACCEPTED + 3 == (int)GoodsEntry::GES_ACCEPTED_BIGTICK); return GB(ge->status, GoodsEntry::GES_EVER_ACCEPTED, 4); } } } /* Handle cargo variables (deprecated) */ if (variable >= 0x8C && variable <= 0xEC) { const GoodsEntry *g = &this->goods[GB(variable - 0x8C, 3, 4)]; switch (GB(variable - 0x8C, 0, 3)) { case 0: return g->cargo.TotalCount(); case 1: return GB(min(g->cargo.TotalCount(), 4095), 0, 4) | (GB(g->status, GoodsEntry::GES_ACCEPTANCE, 1) << 7); case 2: return g->time_since_pickup; case 3: return g->rating; case 4: return g->cargo.Source(); case 5: return g->cargo.DaysInTransit(); case 6: return g->last_speed; case 7: return g->last_age; } } DEBUG(grf, 1, "Unhandled station variable 0x%X", variable); *available = false; return UINT_MAX; } uint32 Waypoint::GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const { switch (variable) { case 0x48: return 0; // Accepted cargo types case 0x8A: return HVOT_WAYPOINT; case 0xF1: return 0; // airport type case 0xF2: return 0; // truck stop status case 0xF3: return 0; // bus stop status case 0xF6: return 0; // airport flags case 0xF7: return 0; // airport flags cont. } /* Handle cargo variables with parameter, 0x60 to 0x65 */ if (variable >= 0x60 && variable <= 0x65) { return 0; } /* Handle cargo variables (deprecated) */ if (variable >= 0x8C && variable <= 0xEC) { switch (GB(variable - 0x8C, 0, 3)) { case 3: return INITIAL_STATION_RATING; case 4: return INVALID_STATION; default: return 0; } } DEBUG(grf, 1, "Unhandled station variable 0x%X", variable); *available = false; return UINT_MAX; } /* virtual */ const SpriteGroup *StationResolverObject::ResolveReal(const RealSpriteGroup *group) const { if (this->station_scope.st == NULL || this->station_scope.statspec->cls_id == STAT_CLASS_WAYP) { return group->loading[0]; } uint cargo = 0; const Station *st = Station::From(this->station_scope.st); switch (this->station_scope.cargo_type) { case CT_INVALID: case CT_DEFAULT_NA: case CT_PURCHASE: cargo = 0; break; case CT_DEFAULT: for (CargoID cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) { cargo += st->goods[cargo_type].cargo.TotalCount(); } break; default: cargo = st->goods[this->station_scope.cargo_type].cargo.TotalCount(); break; } if (HasBit(this->station_scope.statspec->flags, SSF_DIV_BY_STATION_SIZE)) cargo /= (st->train_station.w + st->train_station.h); cargo = min(0xfff, cargo); if (cargo > this->station_scope.statspec->cargo_threshold) { if (group->num_loading > 0) { uint set = ((cargo - this->station_scope.statspec->cargo_threshold) * group->num_loading) / (4096 - this->station_scope.statspec->cargo_threshold); return group->loading[set]; } } else { if (group->num_loaded > 0) { uint set = (cargo * group->num_loaded) / (this->station_scope.statspec->cargo_threshold + 1); return group->loaded[set]; } } return group->loading[0]; } /** * Resolver for stations. * @param statspec Station (type) specification. * @param st Instance of the station. * @param tile %Tile of the station. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseStation *st, TileIndex tile, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(statspec->grf_prop.grffile, callback, callback_param1, callback_param2), station_scope(*this, statspec, st, tile), town_scope(NULL) { /* Invalidate all cached vars */ _svc.valid = 0; CargoID ctype = CT_DEFAULT_NA; if (this->station_scope.st == NULL) { /* No station, so we are in a purchase list */ ctype = CT_PURCHASE; } else if (Station::IsExpected(this->station_scope.st)) { const Station *st = Station::From(this->station_scope.st); /* Pick the first cargo that we have waiting */ const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { if (this->station_scope.statspec->grf_prop.spritegroup[cs->Index()] != NULL && st->goods[cs->Index()].cargo.TotalCount() > 0) { ctype = cs->Index(); break; } } } if (this->station_scope.statspec->grf_prop.spritegroup[ctype] == NULL) { ctype = CT_DEFAULT; } /* Remember the cargo type we've picked */ this->station_scope.cargo_type = ctype; this->root_spritegroup = this->station_scope.statspec->grf_prop.spritegroup[this->station_scope.cargo_type]; } StationResolverObject::~StationResolverObject() { delete this->town_scope; } /** * Constructor for station scopes. * @param ro Surrounding resolver. * @param statspec Station (type) specification. * @param st Instance of the station. * @param tile %Tile of the station. */ StationScopeResolver::StationScopeResolver(ResolverObject &ro, const StationSpec *statspec, BaseStation *st, TileIndex tile) : ScopeResolver(ro) { this->tile = tile; this->st = st; this->statspec = statspec; this->cargo_type = CT_INVALID; this->axis = INVALID_AXIS; } /** * Resolve sprites for drawing a station tile. * @param statspec Station spec * @param st Station (NULL in GUI) * @param tile Station tile being drawn (INVALID_TILE in GUI) * @param var10 Value to put in variable 10; normally 0; 1 when resolving the groundsprite and SSF_SEPARATE_GROUND is set. * @return First sprite of the Action 1 spriteset to use, minus an offset of 0x42D to accommodate for weird NewGRF specs. */ SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32 var10) { StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, var10); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->type != SGT_RESULT) return 0; return group->GetResult() - 0x42D; } /** * Resolve the sprites for custom station foundations. * @param statspec Station spec * @param st Station * @param tile Station tile being drawn * @param layout Spritelayout as returned by previous callback * @param edge_info Information about northern tile edges; whether they need foundations or merge into adjacent tile's foundations. * @return First sprite of a set of foundation sprites for various slopes, or 0 if default foundations shall be drawn. */ SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info) { /* callback_param1 == 2 means we are resolving the foundation sprites. */ StationResolverObject object(statspec, st, tile, CBID_NO_CALLBACK, 2, layout | (edge_info << 16)); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->type != SGT_RESULT) return 0; /* Note: SpriteGroup::Resolve zeroes all registers, so register 0x100 is initialised to 0. (compatibility) */ return group->GetResult() + GetRegister(0x100); } uint16 GetStationCallback(CallbackID callback, uint32 param1, uint32 param2, const StationSpec *statspec, BaseStation *st, TileIndex tile) { StationResolverObject object(statspec, st, tile, callback, param1, param2); return object.ResolveCallback(); } /** * Check the slope of a tile of a new station. * @param north_tile Norther tile of the station rect. * @param cur_tile Tile to check. * @param statspec Station spec. * @param axis Axis of the new station. * @param plat_len Platform length. * @param numtracks Number of platforms. * @return Succeeded or failed command. */ CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, byte plat_len, byte numtracks) { TileIndexDiff diff = cur_tile - north_tile; Slope slope = GetTileSlope(cur_tile); StationResolverObject object(statspec, NULL, cur_tile, CBID_STATION_LAND_SLOPE_CHECK, (slope << 4) | (slope ^ (axis == AXIS_Y && HasBit(slope, CORNER_W) != HasBit(slope, CORNER_E) ? SLOPE_EW : 0)), (numtracks << 24) | (plat_len << 16) | (axis == AXIS_Y ? TileX(diff) << 8 | TileY(diff) : TileY(diff) << 8 | TileX(diff))); object.station_scope.axis = axis; uint16 cb_res = object.ResolveCallback(); /* Failed callback means success. */ if (cb_res == CALLBACK_FAILED) return CommandCost(); /* The meaning of bit 10 is inverted for a grf version < 8. */ if (statspec->grf_prop.grffile->grf_version < 8) ToggleBit(cb_res, 10); return GetErrorMessageFromLocationCallbackResult(cb_res, statspec->grf_prop.grffile, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } /** * Allocate a StationSpec to a Station. This is called once per build operation. * @param statspec StationSpec to allocate. * @param st Station to allocate it to. * @param exec Whether to actually allocate the spec. * @return Index within the Station's spec list, or -1 if the allocation failed. */ int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec) { uint i; if (statspec == NULL || st == NULL) return 0; for (i = 1; i < st->num_specs && i < NUM_STATIONSSPECS_PER_STATION; i++) { if (st->speclist[i].spec == NULL && st->speclist[i].grfid == 0) break; } if (i == NUM_STATIONSSPECS_PER_STATION) { /* As final effort when the spec list is already full... * try to find the same spec and return that one. This might * result in slightly "wrong" (as per specs) looking stations, * but it's fairly unlikely that one reaches the limit anyways. */ for (i = 1; i < st->num_specs && i < NUM_STATIONSSPECS_PER_STATION; i++) { if (st->speclist[i].spec == statspec) return i; } return -1; } if (exec) { if (i >= st->num_specs) { st->num_specs = i + 1; st->speclist = ReallocT(st->speclist, st->num_specs); if (st->num_specs == 2) { /* Initial allocation */ st->speclist[0].spec = NULL; st->speclist[0].grfid = 0; st->speclist[0].localidx = 0; } } st->speclist[i].spec = statspec; st->speclist[i].grfid = statspec->grf_prop.grffile->grfid; st->speclist[i].localidx = statspec->grf_prop.local_id; StationUpdateCachedTriggers(st); } return i; } /** * Deallocate a StationSpec from a Station. Called when removing a single station tile. * @param st Station to work with. * @param specindex Index of the custom station within the Station's spec list. * @return Indicates whether the StationSpec was deallocated. */ void DeallocateSpecFromStation(BaseStation *st, byte specindex) { /* specindex of 0 (default) is never freeable */ if (specindex == 0) return; ETileArea area = ETileArea(st, INVALID_TILE, TA_WHOLE); /* Check all tiles over the station to check if the specindex is still in use */ TILE_AREA_LOOP(tile, area) { if (st->TileBelongsToRailStation(tile) && GetCustomStationSpecIndex(tile) == specindex) { return; } } /* This specindex is no longer in use, so deallocate it */ st->speclist[specindex].spec = NULL; st->speclist[specindex].grfid = 0; st->speclist[specindex].localidx = 0; /* If this was the highest spec index, reallocate */ if (specindex == st->num_specs - 1) { for (; st->speclist[st->num_specs - 1].grfid == 0 && st->num_specs > 1; st->num_specs--) {} if (st->num_specs > 1) { st->speclist = ReallocT(st->speclist, st->num_specs); } else { free(st->speclist); st->num_specs = 0; st->speclist = NULL; st->cached_anim_triggers = 0; st->cached_cargo_triggers = 0; return; } } StationUpdateCachedTriggers(st); } /** * Draw representation of a station tile for GUI purposes. * @param x Position x of image. * @param y Position y of image. * @param axis Axis. * @param railtype Rail type. * @param sclass, station Type of station. * @param station station ID * @return True if the tile was drawn (allows for fallback to default graphic) */ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station) { const DrawTileSprites *sprites = NULL; const RailtypeInfo *rti = GetRailTypeInfo(railtype); PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); uint tile = 2; const StationSpec *statspec = StationClass::Get(sclass)->GetSpec(station); if (statspec == NULL) return false; if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) { uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0x2110000, 0, statspec, NULL, INVALID_TILE); if (callback != CALLBACK_FAILED) tile = callback; } uint32 total_offset = rti->GetRailtypeSpriteOffset(); uint32 relocation = 0; uint32 ground_relocation = 0; const NewGRFSpriteLayout *layout = NULL; DrawTileSprites tmp_rail_layout; if (statspec->renderdata == NULL) { sprites = GetStationTileLayout(STATION_RAIL, tile + axis); } else { layout = &statspec->renderdata[(tile < statspec->tiles) ? tile + axis : (uint)axis]; if (!layout->NeedsPreprocessing()) { sprites = layout; layout = NULL; } } if (layout != NULL) { /* Sprite layout which needs preprocessing */ bool separate_ground = HasBit(statspec->flags, SSF_SEPARATE_GROUND); uint32 var10_values = layout->PrepareLayout(total_offset, rti->fallback_railtype, 0, 0, separate_ground); uint8 var10; FOR_EACH_SET_BIT(var10, var10_values) { uint32 var10_relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE, var10); layout->ProcessRegisters(var10, var10_relocation, separate_ground); } tmp_rail_layout.seq = layout->GetLayout(&tmp_rail_layout.ground); sprites = &tmp_rail_layout; total_offset = 0; } else { /* Simple sprite layout */ ground_relocation = relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE, 0); if (HasBit(sprites->ground.sprite, SPRITE_MODIFIER_CUSTOM_SPRITE)) { ground_relocation = GetCustomStationRelocation(statspec, NULL, INVALID_TILE, 1); } ground_relocation += rti->fallback_railtype; } SpriteID image = sprites->ground.sprite; PaletteID pal = sprites->ground.pal; RailTrackOffset overlay_offset; if (rti->UsesOverlay() && SplitGroundSpriteForOverlay(NULL, &image, &overlay_offset)) { SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND); DrawSprite(image, PAL_NONE, x, y); DrawSprite(ground + overlay_offset, PAL_NONE, x, y); } else { image += HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? ground_relocation : total_offset; if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += ground_relocation; DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y); } DrawRailTileSeqInGUI(x, y, sprites, total_offset, relocation, palette); return true; } const StationSpec *GetStationSpec(TileIndex t) { if (!IsCustomStationSpecIndex(t)) return NULL; const BaseStation *st = BaseStation::GetByTile(t); uint specindex = GetCustomStationSpecIndex(t); return specindex < st->num_specs ? st->speclist[specindex].spec : NULL; } /** * Check whether a rail station tile is NOT traversable. * @param tile %Tile to test. * @return Station tile is blocked. * @note This could be cached (during build) in the map array to save on all the dereferencing. */ bool IsStationTileBlocked(TileIndex tile) { const StationSpec *statspec = GetStationSpec(tile); return statspec != NULL && HasBit(statspec->blocked, GetStationGfx(tile)); } /** * Check if a rail station tile shall have pylons when electrified. * @param tile %Tile to test. * @return Tile shall have pylons. * @note This could be cached (during build) in the map array to save on all the dereferencing. */ bool CanStationTileHavePylons(TileIndex tile) { const StationSpec *statspec = GetStationSpec(tile); uint gfx = GetStationGfx(tile); /* Default stations do not draw pylons under roofs (gfx >= 4) */ return statspec != NULL ? HasBit(statspec->pylons, gfx) : gfx < 4; } /** * Check if a rail station tile shall have wires when electrified. * @param tile %Tile to test. * @return Tile shall have wires. * @note This could be cached (during build) in the map array to save on all the dereferencing. */ bool CanStationTileHaveWires(TileIndex tile) { const StationSpec *statspec = GetStationSpec(tile); return statspec == NULL || !HasBit(statspec->wires, GetStationGfx(tile)); } /** Wrapper for animation control, see #GetStationCallback. */ uint16 GetAnimStationCallback(CallbackID callback, uint32 param1, uint32 param2, const StationSpec *statspec, BaseStation *st, TileIndex tile, int extra_data) { return GetStationCallback(callback, param1, param2, statspec, st, tile); } /** Helper class for animation control. */ struct StationAnimationBase : public AnimationBase { static const CallbackID cb_animation_speed = CBID_STATION_ANIMATION_SPEED; static const CallbackID cb_animation_next_frame = CBID_STATION_ANIM_NEXT_FRAME; static const StationCallbackMask cbm_animation_speed = CBM_STATION_ANIMATION_SPEED; static const StationCallbackMask cbm_animation_next_frame = CBM_STATION_ANIMATION_NEXT_FRAME; }; void AnimateStationTile(TileIndex tile) { const StationSpec *ss = GetStationSpec(tile); if (ss == NULL) return; StationAnimationBase::AnimateTile(ss, BaseStation::GetByTile(tile), tile, HasBit(ss->flags, SSF_CB141_RANDOM_BITS)); } void TriggerStationAnimation(BaseStation *st, TileIndex tile, StationAnimationTrigger trigger, CargoID cargo_type) { /* List of coverage areas for each animation trigger */ static const TriggerArea tas[] = { TA_TILE, TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_WHOLE }; /* Get Station if it wasn't supplied */ if (st == NULL) st = BaseStation::GetByTile(tile); /* Check the cached animation trigger bitmask to see if we need * to bother with any further processing. */ if (!HasBit(st->cached_anim_triggers, trigger)) return; uint16 random_bits = Random(); ETileArea area = ETileArea(st, tile, tas[trigger]); /* Check all tiles over the station to check if the specindex is still in use */ TILE_AREA_LOOP(tile, area) { if (st->TileBelongsToRailStation(tile)) { const StationSpec *ss = GetStationSpec(tile); if (ss != NULL && HasBit(ss->animation.triggers, trigger)) { CargoID cargo; if (cargo_type == CT_INVALID) { cargo = CT_INVALID; } else { cargo = ss->grf_prop.grffile->cargo_map[cargo_type]; } StationAnimationBase::ChangeAnimationFrame(CBID_STATION_ANIM_START_STOP, ss, st, tile, (random_bits << 16) | Random(), (uint8)trigger | (cargo << 8)); } } } } /** * Trigger station randomisation * @param st station being triggered * @param tile specific tile of platform to trigger * @param trigger trigger type * @param cargo_type cargo type causing trigger */ void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoID cargo_type) { /* List of coverage areas for each animation trigger */ static const TriggerArea tas[] = { TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM }; /* Get Station if it wasn't supplied */ if (st == NULL) st = Station::GetByTile(tile); /* Check the cached cargo trigger bitmask to see if we need * to bother with any further processing. */ if (st->cached_cargo_triggers == 0) return; if (cargo_type != CT_INVALID && !HasBit(st->cached_cargo_triggers, cargo_type)) return; uint32 whole_reseed = 0; ETileArea area = ETileArea(st, tile, tas[trigger]); uint32 empty_mask = 0; if (trigger == SRT_CARGO_TAKEN) { /* Create a bitmask of completely empty cargo types to be matched */ for (CargoID i = 0; i < NUM_CARGO; i++) { if (st->goods[i].cargo.TotalCount() == 0) { SetBit(empty_mask, i); } } } /* Convert trigger to bit */ uint8 trigger_bit = 1 << trigger; /* Check all tiles over the station to check if the specindex is still in use */ TILE_AREA_LOOP(tile, area) { if (st->TileBelongsToRailStation(tile)) { const StationSpec *ss = GetStationSpec(tile); if (ss == NULL) continue; /* Cargo taken "will only be triggered if all of those * cargo types have no more cargo waiting." */ if (trigger == SRT_CARGO_TAKEN) { if ((ss->cargo_triggers & ~empty_mask) != 0) continue; } if (cargo_type == CT_INVALID || HasBit(ss->cargo_triggers, cargo_type)) { StationResolverObject object(ss, st, tile, CBID_RANDOM_TRIGGER, 0); object.trigger = trigger_bit; const SpriteGroup *group = object.Resolve(); if (group == NULL) continue; uint32 reseed = object.GetReseedSum(); if (reseed != 0) { whole_reseed |= reseed; reseed >>= 16; /* Set individual tile random bits */ uint8 random_bits = GetStationTileRandomBits(tile); random_bits &= ~reseed; random_bits |= Random() & reseed; SetStationTileRandomBits(tile, random_bits); MarkTileDirtyByTile(tile); } } } } /* Update whole station random bits */ if ((whole_reseed & 0xFFFF) != 0) { st->random_bits &= ~whole_reseed; st->random_bits |= Random() & whole_reseed; } } /** * Update the cached animation trigger bitmask for a station. * @param st Station to update. */ void StationUpdateCachedTriggers(BaseStation *st) { st->cached_anim_triggers = 0; st->cached_cargo_triggers = 0; /* Combine animation trigger bitmask for all station specs * of this station. */ for (uint i = 0; i < st->num_specs; i++) { const StationSpec *ss = st->speclist[i].spec; if (ss != NULL) { st->cached_anim_triggers |= ss->animation.triggers; st->cached_cargo_triggers |= ss->cargo_triggers; } } } openttd-1.5.3/src/progress.cpp0000644000000000000000000000314512627373445015052 0ustar rootroot/* $Id: progress.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 progress.cpp Functions for modal progress windows. */ #include "stdafx.h" #include "thread/thread.h" #include "safeguards.h" /** Are we in a modal progress or not? */ bool _in_modal_progress = false; bool _first_in_modal_loop = false; /** Rights for the performing work. */ ThreadMutex *_modal_progress_work_mutex = ThreadMutex::New(); /** Rights for the painting. */ ThreadMutex *_modal_progress_paint_mutex = ThreadMutex::New(); /** * Set the modal progress state. * @note Makes IsFirstModalProgressLoop return true for the next call. * @param state The new state; are we modal or not? */ void SetModalProgress(bool state) { _in_modal_progress = state; _first_in_modal_loop = true; } /** * Check whether this is the first modal progress loop. * @note Set by SetModalProgress, unset by calling this method. * @return True if this is the first loop. */ bool IsFirstModalProgressLoop() { bool ret = _first_in_modal_loop; _first_in_modal_loop = false; return ret; } openttd-1.5.3/src/newgrf_cargo.h0000644000000000000000000000246312627373435015317 0ustar rootroot/* $Id: newgrf_cargo.h 24273 2012-05-25 17:23:19Z frosch $ */ /* * 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 newgrf_cargo.h Cargo support for NewGRFs. */ #ifndef NEWGRF_CARGO_H #define NEWGRF_CARGO_H #include "newgrf_callbacks.h" #include "cargo_type.h" #include "gfx_type.h" static const CargoID CT_DEFAULT = NUM_CARGO + 0; static const CargoID CT_PURCHASE = NUM_CARGO + 1; static const CargoID CT_DEFAULT_NA = NUM_CARGO + 2; /* Forward declarations of structs used */ struct CargoSpec; struct GRFFile; SpriteID GetCustomCargoSprite(const CargoSpec *cs); uint16 GetCargoCallback(CallbackID callback, uint32 param1, uint32 param2, const CargoSpec *cs); CargoID GetCargoTranslation(uint8 cargo, const GRFFile *grffile, bool usebit = false); #endif /* NEWGRF_CARGO_H */ openttd-1.5.3/src/textbuf_gui.h0000644000000000000000000000364212627373435015201 0ustar rootroot/* $Id: textbuf_gui.h 24323 2012-06-04 15:29:37Z frosch $ */ /* * 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 textbuf_gui.h Stuff related to the text buffer GUI. */ #ifndef TEXTBUF_GUI_H #define TEXTBUF_GUI_H #include "window_type.h" #include "string_type.h" #include "strings_type.h" /** Flags used in ShowQueryString() call */ enum QueryStringFlags { QSF_NONE = 0, QSF_ACCEPT_UNCHANGED = 0x01, ///< return success even when the text didn't change QSF_ENABLE_DEFAULT = 0x02, ///< enable the 'Default' button ("\0" is returned) QSF_LEN_IN_CHARS = 0x04, ///< the length of the string is counted in characters }; DECLARE_ENUM_AS_BIT_SET(QueryStringFlags) /** Callback procedure for the ShowQuery method. */ typedef void QueryCallbackProc(Window*, bool); void ShowQueryString(StringID str, StringID caption, uint max_len, Window *parent, CharSetFilter afilter, QueryStringFlags flags); void ShowQuery(StringID caption, StringID message, Window *w, QueryCallbackProc *callback); /** The number of 'characters' on the on-screen keyboard. */ static const uint OSK_KEYBOARD_ENTRIES = 50; /** * The number of characters has to be OSK_KEYBOARD_ENTRIES. However, these * have to be UTF-8 encoded, which means up to 4 bytes per character. * Furthermore the string needs to be '\0'-terminated. */ extern char _keyboard_opt[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; #endif /* TEXTBUF_GUI_H */ openttd-1.5.3/src/fios.h0000644000000000000000000001261612627373445013616 0ustar rootroot/* $Id: fios.h 26489 2014-04-23 21:23:21Z rubidium $ */ /* * 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 fios.h Declarations for savegames operations */ #ifndef FIOS_H #define FIOS_H #include "gfx_type.h" #include "company_base.h" #include "newgrf_config.h" #include "network/core/tcp_content.h" typedef SmallMap CompanyPropertiesMap; /** * Container for loading in mode SL_LOAD_CHECK. */ struct LoadCheckData { bool checkable; ///< True if the savegame could be checked by SL_LOAD_CHECK. (Old savegames are not checkable.) StringID error; ///< Error message from loading. INVALID_STRING_ID if no error. char *error_data; ///< Data to pass to SetDParamStr when displaying #error. uint32 map_size_x, map_size_y; Date current_date; GameSettings settings; CompanyPropertiesMap companies; ///< Company information. GRFConfig *grfconfig; ///< NewGrf configuration from save. GRFListCompatibility grf_compatibility; ///< Summary state of NewGrfs, whether missing files or only compatible found. struct LoggedAction *gamelog_action; ///< Gamelog actions uint gamelog_actions; ///< Number of gamelog actions LoadCheckData() : error_data(NULL), grfconfig(NULL), grf_compatibility(GLC_NOT_FOUND), gamelog_action(NULL), gamelog_actions(0) { this->Clear(); } /** * Don't leak memory at program exit */ ~LoadCheckData() { this->Clear(); } /** * Check whether loading the game resulted in errors. * @return true if errors were encountered. */ bool HasErrors() { return this->checkable && this->error != INVALID_STRING_ID; } /** * Check whether the game uses any NewGrfs. * @return true if NewGrfs are used. */ bool HasNewGrfs() { return this->checkable && this->error == INVALID_STRING_ID && this->grfconfig != NULL; } void Clear(); }; extern LoadCheckData _load_check_data; enum FileSlots { /** * Slot used for the GRF scanning and such. This slot cannot be reused * as it will otherwise cause issues when pressing "rescan directories". * It can furthermore not be larger than LAST_GRF_SLOT as that complicates * the testing for "too much NewGRFs". */ CONFIG_SLOT = 0, /** Slot for the sound. */ SOUND_SLOT = 1, /** First slot usable for (New)GRFs used during the game. */ FIRST_GRF_SLOT = 2, /** Last slot usable for (New)GRFs used during the game. */ LAST_GRF_SLOT = 63, /** Maximum number of slots. */ MAX_FILE_SLOTS = 64 }; /** Mode of the file dialogue window. */ enum SaveLoadDialogMode { SLD_LOAD_GAME, ///< Load a game. SLD_LOAD_SCENARIO, ///< Load a scenario. SLD_SAVE_GAME, ///< Save a game. SLD_SAVE_SCENARIO, ///< Save a scenario. SLD_LOAD_HEIGHTMAP, ///< Load a heightmap. SLD_SAVE_HEIGHTMAP, ///< Save a heightmap. }; /** The different types of files that the system knows about. */ enum FileType { FT_NONE, ///< nothing to do FT_SAVEGAME, ///< old or new savegame FT_SCENARIO, ///< old or new scenario FT_HEIGHTMAP, ///< heightmap file }; enum FiosType { FIOS_TYPE_DRIVE, FIOS_TYPE_PARENT, FIOS_TYPE_DIR, FIOS_TYPE_FILE, FIOS_TYPE_OLDFILE, FIOS_TYPE_SCENARIO, FIOS_TYPE_OLD_SCENARIO, FIOS_TYPE_DIRECT, FIOS_TYPE_PNG, FIOS_TYPE_BMP, FIOS_TYPE_INVALID = 255, }; /** Deals with finding savegames */ struct FiosItem { FiosType type; uint64 mtime; char title[64]; char name[MAX_PATH]; }; /** Deals with the type of the savegame, independent of extension */ struct SmallFiosItem { int mode; ///< savegame/scenario type (old, new) FileType filetype; ///< what type of file are we dealing with char name[MAX_PATH]; ///< name char title[255]; ///< internal name of the game }; enum SortingBits { SORT_ASCENDING = 0, SORT_DESCENDING = 1, SORT_BY_DATE = 0, SORT_BY_NAME = 2 }; DECLARE_ENUM_AS_BIT_SET(SortingBits) /* Variables to display file lists */ extern SmallVector _fios_items; extern SmallFiosItem _file_to_saveload; extern SaveLoadDialogMode _saveload_mode; extern SortingBits _savegame_sort_order; void ShowSaveLoadDialog(SaveLoadDialogMode mode); void FiosGetSavegameList(SaveLoadDialogMode mode); void FiosGetScenarioList(SaveLoadDialogMode mode); void FiosGetHeightmapList(SaveLoadDialogMode mode); void FiosFreeSavegameList(); const char *FiosBrowseTo(const FiosItem *item); StringID FiosGetDescText(const char **path, uint64 *total_free); bool FiosDelete(const char *name); void FiosMakeHeightmapName(char *buf, const char *name, const char *last); void FiosMakeSavegameName(char *buf, const char *name, const char *last); FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last); int CDECL CompareFiosItems(const FiosItem *a, const FiosItem *b); extern const TextColour _fios_colours[]; void BuildFileList(); void SetFiosType(const byte fiostype); #endif /* FIOS_H */ openttd-1.5.3/src/elrail.cpp0000644000000000000000000006273112627373445014464 0ustar rootroot/* $Id: elrail.cpp 26879 2014-09-21 11:24:51Z rubidium $ */ /* * 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 elrail.cpp * This file deals with displaying wires and pylons for electric railways. *

Basics

* *

Tile Types

* * We have two different types of tiles in the drawing code: * Normal Railway Tiles (NRTs) which can have more than one track on it, and * Special Railways tiles (SRTs) which have only one track (like crossings, depots * stations, etc). * *

Location Categories

* * All tiles are categorized into three location groups (TLG): * Group 0: Tiles with both an even X coordinate and an even Y coordinate * Group 1: Tiles with an even X and an odd Y coordinate * Group 2: Tiles with an odd X and an even Y coordinate * Group 3: Tiles with both an odd X and Y coordinate. * *

Pylon Points

*

Control Points

* A Pylon Control Point (PCP) is a position where a wire (or rather two) * is mounted onto a pylon. * Each NRT does contain 4 PCPs which are bitmapped to a byte * variable and are represented by the DiagDirection enum * * Each track ends on two PCPs and thus requires one pylon on each end. However, * there is one exception: Straight-and-level tracks only have one pylon every * other tile. * * Now on each edge there are two PCPs: One from each adjacent tile. Both PCPs * are merged using an OR operation (i. e. if one tile needs a PCP at the position * in question, both tiles get it). * *

Position Points

* A Pylon Position Point (PPP) is a position where a pylon is located on the * ground. Each PCP owns 8 in (45 degree steps) PPPs that are located around * it. PPPs are represented using the Direction enum. Each track bit has PPPs * that are impossible (because the pylon would be situated on the track) and * some that are preferred (because the pylon would be rectangular to the track). * * @image html elrail_tile.png * @image html elrail_track.png * */ #include "stdafx.h" #include "station_map.h" #include "viewport_func.h" #include "train.h" #include "rail_gui.h" #include "tunnelbridge_map.h" #include "tunnelbridge.h" #include "elrail_func.h" #include "company_base.h" #include "newgrf_railtype.h" #include "table/elrail_data.h" #include "safeguards.h" /** * Get the tile location group of a tile. * @param t The tile to get the tile location group of. * @return The tile location group. */ static inline TLG GetTLG(TileIndex t) { return (TLG)((HasBit(TileX(t), 0) << 1) + HasBit(TileY(t), 0)); } /** * Finds which Electrified Rail Bits are present on a given tile. * @param t tile to check * @param override pointer to PCP override, can be NULL * @return trackbits of tile if it is electrified */ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override) { switch (GetTileType(t)) { case MP_RAILWAY: if (!HasCatenary(GetRailType(t))) return TRACK_BIT_NONE; switch (GetRailTileType(t)) { case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS: return GetTrackBits(t); default: return TRACK_BIT_NONE; } break; case MP_TUNNELBRIDGE: if (!HasCatenary(GetRailType(t))) return TRACK_BIT_NONE; if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) { *override = 1 << GetTunnelBridgeDirection(t); } return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)); case MP_ROAD: if (!IsLevelCrossing(t)) return TRACK_BIT_NONE; if (!HasCatenary(GetRailType(t))) return TRACK_BIT_NONE; return GetCrossingRailBits(t); case MP_STATION: if (!HasStationRail(t)) return TRACK_BIT_NONE; if (!HasCatenary(GetRailType(t))) return TRACK_BIT_NONE; return TrackToTrackBits(GetRailStationTrack(t)); default: return TRACK_BIT_NONE; } } /** * Masks out track bits when neighbouring tiles are unelectrified. */ static TrackBits MaskWireBits(TileIndex t, TrackBits tracks) { if (!IsPlainRailTile(t)) return tracks; TrackdirBits neighbour_tdb = TRACKDIR_BIT_NONE; for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) { /* If the neighbour tile is either not electrified or has no tracks that can be reached * from this tile, mark all trackdirs that can be reached from the neighbour tile * as needing no catenary. We make an exception for blocked station tiles with a matching * axis that still display wires to preserve visual continuity. */ TileIndex next_tile = TileAddByDiagDir(t, d); RailType rt = GetTileRailType(next_tile); if (rt == INVALID_RAILTYPE || !HasCatenary(rt) || ((TrackStatusToTrackBits(GetTileTrackStatus(next_tile, TRANSPORT_RAIL, 0)) & DiagdirReachesTracks(d)) == TRACK_BIT_NONE && (!HasStationTileRail(next_tile) || GetRailStationAxis(next_tile) != DiagDirToAxis(d) || !CanStationTileHaveWires(next_tile)))) { neighbour_tdb |= DiagdirReachesTrackdirs(ReverseDiagDir(d)); } } /* If the tracks from either a diagonal crossing or don't overlap, both * trackdirs have to be marked to mask the corresponding track bit. Else * one marked trackdir is enough the mask the track bit. */ TrackBits mask; if (tracks == TRACK_BIT_CROSS || !TracksOverlap(tracks)) { /* If the tracks form either a diagonal crossing or don't overlap, both * trackdirs have to be marked to mask the corresponding track bit. */ mask = ~(TrackBits)((neighbour_tdb & (neighbour_tdb >> 8)) & TRACK_BIT_MASK); /* If that results in no masked tracks and it is not a diagonal crossing, * require only one marked trackdir to mask. */ if (tracks != TRACK_BIT_CROSS && (mask & TRACK_BIT_MASK) == TRACK_BIT_MASK) mask = ~TrackdirBitsToTrackBits(neighbour_tdb); } else { /* Require only one marked trackdir to mask the track. */ mask = ~TrackdirBitsToTrackBits(neighbour_tdb); /* If that results in an empty set, require both trackdirs for diagonal track. */ if ((tracks & mask) == TRACK_BIT_NONE) { if ((neighbour_tdb & TRACKDIR_BIT_X_NE) == 0 || (neighbour_tdb & TRACKDIR_BIT_X_SW) == 0) mask |= TRACK_BIT_X; if ((neighbour_tdb & TRACKDIR_BIT_Y_NW) == 0 || (neighbour_tdb & TRACKDIR_BIT_Y_SE) == 0) mask |= TRACK_BIT_Y; /* If that still is not enough, require both trackdirs for any track. */ if ((tracks & mask) == TRACK_BIT_NONE) mask = ~(TrackBits)((neighbour_tdb & (neighbour_tdb >> 8)) & TRACK_BIT_MASK); } } /* Mask the tracks only if at least one track bit would remain. */ return (tracks & mask) != TRACK_BIT_NONE ? tracks & mask : tracks; } /** * Get the base wire sprite to use. */ static inline SpriteID GetWireBase(TileIndex tile, TileContext context = TCX_NORMAL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); SpriteID wires = GetCustomRailSprite(rti, tile, RTSG_WIRES, context); return wires == 0 ? SPR_WIRE_BASE : wires; } /** * Get the base pylon sprite to use. */ static inline SpriteID GetPylonBase(TileIndex tile, TileContext context = TCX_NORMAL) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); SpriteID pylons = GetCustomRailSprite(rti, tile, RTSG_PYLONS, context); return pylons == 0 ? SPR_PYLON_BASE : pylons; } /** * Corrects the tileh for certain tile types. Returns an effective tileh for the track on the tile. * @param tile The tile to analyse * @param *tileh the tileh */ static void AdjustTileh(TileIndex tile, Slope *tileh) { if (IsTileType(tile, MP_TUNNELBRIDGE)) { if (IsTunnel(tile)) { *tileh = SLOPE_STEEP; // XXX - Hack to make tunnel entrances to always have a pylon } else if (*tileh != SLOPE_FLAT) { *tileh = SLOPE_FLAT; } else { *tileh = InclinedSlope(GetTunnelBridgeDirection(tile)); } } } /** * Returns the Z position of a Pylon Control Point. * * @param tile The tile the pylon should stand on. * @param PCPpos The PCP of the tile. * @return The Z position of the PCP. */ static int GetPCPElevation(TileIndex tile, DiagDirection PCPpos) { /* The elevation of the "pylon"-sprite should be the elevation at the PCP. * PCPs are always on a tile edge. * * This position can be outside of the tile, i.e. ?_pcp_offset == TILE_SIZE > TILE_SIZE - 1. * So we have to move it inside the tile, because if the neighboured tile has a foundation, * that does not smoothly connect to the current tile, we will get a wrong elevation from GetSlopePixelZ(). * * When we move the position inside the tile, we will get a wrong elevation if we have a slope. * To catch all cases we round the Z position to the next (TILE_HEIGHT / 2). * This will return the correct elevation for slopes and will also detect non-continuous elevation on edges. * * Also note that the result of GetSlopePixelZ() is very special on bridge-ramps. */ int z = GetSlopePixelZ(TileX(tile) * TILE_SIZE + min(x_pcp_offsets[PCPpos], TILE_SIZE - 1), TileY(tile) * TILE_SIZE + min(y_pcp_offsets[PCPpos], TILE_SIZE - 1)); return (z + 2) & ~3; // this means z = (z + TILE_HEIGHT / 4) / (TILE_HEIGHT / 2) * (TILE_HEIGHT / 2); } /** * Draws wires on a tunnel tile * * DrawTile_TunnelBridge() calls this function to draw the wires as SpriteCombine with the tunnel roof. * * @param ti The Tileinfo to draw the tile for */ void DrawCatenaryOnTunnel(const TileInfo *ti) { /* xmin, ymin, xmax + 1, ymax + 1 of BB */ static const int _tunnel_wire_BB[4][4] = { { 0, 1, 16, 15 }, // NE { 1, 0, 15, 16 }, // SE { 0, 1, 16, 15 }, // SW { 1, 0, 15, 16 }, // NW }; DiagDirection dir = GetTunnelBridgeDirection(ti->tile); SpriteID wire_base = GetWireBase(ti->tile); const SortableSpriteStruct *sss = &CatenarySpriteData_Tunnel[dir]; const int *BB_data = _tunnel_wire_BB[dir]; AddSortableSpriteToDraw( wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, BB_data[2] - sss->x_offset, BB_data[3] - sss->y_offset, BB_Z_SEPARATOR - sss->z_offset + 1, GetTilePixelZ(ti->tile) + sss->z_offset, IsTransparencySet(TO_CATENARY), BB_data[0] - sss->x_offset, BB_data[1] - sss->y_offset, BB_Z_SEPARATOR - sss->z_offset ); } /** * Draws wires and, if required, pylons on a given tile * @param ti The Tileinfo to draw the tile for */ static void DrawCatenaryRailway(const TileInfo *ti) { /* Pylons are placed on a tile edge, so we need to take into account * the track configuration of 2 adjacent tiles. trackconfig[0] stores the * current tile (home tile) while [1] holds the neighbour */ TrackBits trackconfig[TS_END]; TrackBits wireconfig[TS_END]; bool isflat[TS_END]; /* Note that ti->tileh has already been adjusted for Foundations */ Slope tileh[TS_END] = { ti->tileh, SLOPE_FLAT }; /* Half tile slopes coincide only with horizontal/vertical track. * Faking a flat slope results in the correct sprites on positions. */ Corner halftile_corner = CORNER_INVALID; if (IsHalftileSlope(tileh[TS_HOME])) { halftile_corner = GetHalftileSlopeCorner(tileh[TS_HOME]); tileh[TS_HOME] = SLOPE_FLAT; } TLG tlg = GetTLG(ti->tile); byte PCPstatus = 0; byte OverridePCP = 0; byte PPPpreferred[DIAGDIR_END]; byte PPPallowed[DIAGDIR_END]; /* Find which rail bits are present, and select the override points. * We don't draw a pylon: * 1) INSIDE a tunnel (we wouldn't see it anyway) * 2) on the "far" end of a bridge head (the one that connects to bridge middle), * because that one is drawn on the bridge. Exception is for length 0 bridges * which have no middle tiles */ trackconfig[TS_HOME] = GetRailTrackBitsUniversal(ti->tile, &OverridePCP); wireconfig[TS_HOME] = MaskWireBits(ti->tile, trackconfig[TS_HOME]); /* If a track bit is present that is not in the main direction, the track is level */ isflat[TS_HOME] = ((trackconfig[TS_HOME] & (TRACK_BIT_HORZ | TRACK_BIT_VERT)) != 0); AdjustTileh(ti->tile, &tileh[TS_HOME]); SpriteID pylon_normal = GetPylonBase(ti->tile); SpriteID pylon_halftile = (halftile_corner != CORNER_INVALID) ? GetPylonBase(ti->tile, TCX_UPPER_HALFTILE) : pylon_normal; for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) { static const uint edge_corners[] = { 1 << CORNER_N | 1 << CORNER_E, // DIAGDIR_NE 1 << CORNER_S | 1 << CORNER_E, // DIAGDIR_SE 1 << CORNER_S | 1 << CORNER_W, // DIAGDIR_SW 1 << CORNER_N | 1 << CORNER_W, // DIAGDIR_NW }; SpriteID pylon_base = (halftile_corner != CORNER_INVALID && HasBit(edge_corners[i], halftile_corner)) ? pylon_halftile : pylon_normal; TileIndex neighbour = ti->tile + TileOffsByDiagDir(i); int elevation = GetPCPElevation(ti->tile, i); /* Here's one of the main headaches. GetTileSlope does not correct for possibly * existing foundataions, so we do have to do that manually later on.*/ tileh[TS_NEIGHBOUR] = GetTileSlope(neighbour); trackconfig[TS_NEIGHBOUR] = GetRailTrackBitsUniversal(neighbour, NULL); wireconfig[TS_NEIGHBOUR] = MaskWireBits(neighbour, trackconfig[TS_NEIGHBOUR]); if (IsTunnelTile(neighbour) && i != GetTunnelBridgeDirection(neighbour)) wireconfig[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] = TRACK_BIT_NONE; /* Ignore station tiles that allow neither wires nor pylons. */ if (IsRailStationTile(neighbour) && !CanStationTileHavePylons(neighbour) && !CanStationTileHaveWires(neighbour)) wireconfig[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] = TRACK_BIT_NONE; /* If the neighboured tile does not smoothly connect to the current tile (because of a foundation), * we have to draw all pillars on the current tile. */ if (elevation != GetPCPElevation(neighbour, ReverseDiagDir(i))) wireconfig[TS_NEIGHBOUR] = trackconfig[TS_NEIGHBOUR] = TRACK_BIT_NONE; isflat[TS_NEIGHBOUR] = ((trackconfig[TS_NEIGHBOUR] & (TRACK_BIT_HORZ | TRACK_BIT_VERT)) != 0); PPPpreferred[i] = 0xFF; // We start with preferring everything (end-of-line in any direction) PPPallowed[i] = AllowedPPPonPCP[i]; /* We cycle through all the existing tracks at a PCP and see what * PPPs we want to have, or may not have at all */ for (uint k = 0; k < NUM_TRACKS_AT_PCP; k++) { /* Next to us, we have a bridge head, don't worry about that one, if it shows away from us */ if (TrackSourceTile[i][k] == TS_NEIGHBOUR && IsBridgeTile(neighbour) && GetTunnelBridgeDirection(neighbour) == ReverseDiagDir(i)) { continue; } /* We check whether the track in question (k) is present in the tile * (TrackSourceTile) */ DiagDirection PCPpos = i; if (HasBit(wireconfig[TrackSourceTile[i][k]], TracksAtPCP[i][k])) { /* track found, if track is in the neighbour tile, adjust the number * of the PCP for preferred/allowed determination*/ PCPpos = (TrackSourceTile[i][k] == TS_HOME) ? i : ReverseDiagDir(i); SetBit(PCPstatus, i); // This PCP is in use PPPpreferred[i] &= PreferredPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos]; } if (HasBit(trackconfig[TrackSourceTile[i][k]], TracksAtPCP[i][k])) { PPPallowed[i] &= ~DisallowedPPPofTrackAtPCP[TracksAtPCP[i][k]][PCPpos]; } } /* Deactivate all PPPs if PCP is not used */ if (!HasBit(PCPstatus, i)) { PPPpreferred[i] = 0; PPPallowed[i] = 0; } Foundation foundation = FOUNDATION_NONE; /* Station and road crossings are always "flat", so adjust the tileh accordingly */ if (IsTileType(neighbour, MP_STATION) || IsTileType(neighbour, MP_ROAD)) tileh[TS_NEIGHBOUR] = SLOPE_FLAT; /* Read the foundations if they are present, and adjust the tileh */ if (trackconfig[TS_NEIGHBOUR] != TRACK_BIT_NONE && IsTileType(neighbour, MP_RAILWAY) && HasCatenary(GetRailType(neighbour))) foundation = GetRailFoundation(tileh[TS_NEIGHBOUR], trackconfig[TS_NEIGHBOUR]); if (IsBridgeTile(neighbour)) { foundation = GetBridgeFoundation(tileh[TS_NEIGHBOUR], DiagDirToAxis(GetTunnelBridgeDirection(neighbour))); } ApplyFoundationToSlope(foundation, &tileh[TS_NEIGHBOUR]); /* Half tile slopes coincide only with horizontal/vertical track. * Faking a flat slope results in the correct sprites on positions. */ if (IsHalftileSlope(tileh[TS_NEIGHBOUR])) tileh[TS_NEIGHBOUR] = SLOPE_FLAT; AdjustTileh(neighbour, &tileh[TS_NEIGHBOUR]); /* If we have a straight (and level) track, we want a pylon only every 2 tiles * Delete the PCP if this is the case. * Level means that the slope is the same, or the track is flat */ if (tileh[TS_HOME] == tileh[TS_NEIGHBOUR] || (isflat[TS_HOME] && isflat[TS_NEIGHBOUR])) { for (uint k = 0; k < NUM_IGNORE_GROUPS; k++) { if (PPPpreferred[i] == IgnoredPCP[k][tlg][i]) ClrBit(PCPstatus, i); } } /* Now decide where we draw our pylons. First try the preferred PPPs, but they may not exist. * In that case, we try the any of the allowed ones. if they don't exist either, don't draw * anything. Note that the preferred PPPs still contain the end-of-line markers. * Remove those (simply by ANDing with allowed, since these markers are never allowed) */ if ((PPPallowed[i] & PPPpreferred[i]) != 0) PPPallowed[i] &= PPPpreferred[i]; if (IsBridgeAbove(ti->tile)) { Track bridgetrack = GetBridgeAxis(ti->tile) == AXIS_X ? TRACK_X : TRACK_Y; int height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile)); if ((height <= GetTileMaxZ(ti->tile) + 1) && (i == PCPpositions[bridgetrack][0] || i == PCPpositions[bridgetrack][1])) { SetBit(OverridePCP, i); } } if (PPPallowed[i] != 0 && HasBit(PCPstatus, i) && !HasBit(OverridePCP, i) && (!IsRailStationTile(ti->tile) || CanStationTileHavePylons(ti->tile))) { for (Direction k = DIR_BEGIN; k < DIR_END; k++) { byte temp = PPPorder[i][GetTLG(ti->tile)][k]; if (HasBit(PPPallowed[i], temp)) { uint x = ti->x + x_pcp_offsets[i] + x_ppp_offsets[temp]; uint y = ti->y + y_pcp_offsets[i] + y_ppp_offsets[temp]; /* Don't build the pylon if it would be outside the tile */ if (!HasBit(OwnedPPPonPCP[i], temp)) { /* We have a neighbour that will draw it, bail out */ if (trackconfig[TS_NEIGHBOUR] != TRACK_BIT_NONE) break; continue; // No neighbour, go looking for a better position } AddSortableSpriteToDraw(pylon_base + pylon_sprites[temp], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, elevation, IsTransparencySet(TO_CATENARY), -1, -1); break; // We already have drawn a pylon, bail out } } } } /* The wire above the tunnel is drawn together with the tunnel-roof (see DrawCatenaryOnTunnel()) */ if (IsTunnelTile(ti->tile)) return; /* Don't draw a wire under a low bridge */ if (IsBridgeAbove(ti->tile) && !IsTransparencySet(TO_BRIDGES)) { int height = GetBridgeHeight(GetNorthernBridgeEnd(ti->tile)); if (height <= GetTileMaxZ(ti->tile) + 1) return; } /* Don't draw a wire if the station tile does not want any */ if (IsRailStationTile(ti->tile) && !CanStationTileHaveWires(ti->tile)) return; SpriteID wire_normal = GetWireBase(ti->tile); SpriteID wire_halftile = (halftile_corner != CORNER_INVALID) ? GetWireBase(ti->tile, TCX_UPPER_HALFTILE) : wire_normal; Track halftile_track; switch (halftile_corner) { case CORNER_W: halftile_track = TRACK_LEFT; break; case CORNER_S: halftile_track = TRACK_LOWER; break; case CORNER_E: halftile_track = TRACK_RIGHT; break; case CORNER_N: halftile_track = TRACK_UPPER; break; default: halftile_track = INVALID_TRACK; break; } /* Drawing of pylons is finished, now draw the wires */ Track t; FOR_EACH_SET_TRACK(t, wireconfig[TS_HOME]) { SpriteID wire_base = (t == halftile_track) ? wire_halftile : wire_normal; byte PCPconfig = HasBit(PCPstatus, PCPpositions[t][0]) + (HasBit(PCPstatus, PCPpositions[t][1]) << 1); const SortableSpriteStruct *sss; int tileh_selector = !(tileh[TS_HOME] % 3) * tileh[TS_HOME] / 3; // tileh for the slopes, 0 otherwise assert(PCPconfig != 0); // We have a pylon on neither end of the wire, that doesn't work (since we have no sprites for that) assert(!IsSteepSlope(tileh[TS_HOME])); sss = &CatenarySpriteData[Wires[tileh_selector][t][PCPconfig]]; /* * The "wire"-sprite position is inside the tile, i.e. 0 <= sss->?_offset < TILE_SIZE. * Therefore it is safe to use GetSlopePixelZ() for the elevation. * Also note that the result of GetSlopePixelZ() is very special for bridge-ramps. */ AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, sss->x_size, sss->y_size, sss->z_size, GetSlopePixelZ(ti->x + sss->x_offset, ti->y + sss->y_offset) + sss->z_offset, IsTransparencySet(TO_CATENARY)); } } /** * Draws wires on a tunnel tile * * DrawTile_TunnelBridge() calls this function to draw the wires on the bridge. * * @param ti The Tileinfo to draw the tile for */ void DrawCatenaryOnBridge(const TileInfo *ti) { TileIndex end = GetSouthernBridgeEnd(ti->tile); TileIndex start = GetOtherBridgeEnd(end); uint length = GetTunnelBridgeLength(start, end); uint num = GetTunnelBridgeLength(ti->tile, start) + 1; uint height; const SortableSpriteStruct *sss; Axis axis = GetBridgeAxis(ti->tile); TLG tlg = GetTLG(ti->tile); CatenarySprite offset = (CatenarySprite)(axis == AXIS_X ? 0 : WIRE_Y_FLAT_BOTH - WIRE_X_FLAT_BOTH); if ((length % 2) && num == length) { /* Draw the "short" wire on the southern end of the bridge * only needed if the length of the bridge is odd */ sss = &CatenarySpriteData[WIRE_X_FLAT_BOTH + offset]; } else { /* Draw "long" wires on all other tiles of the bridge (one pylon every two tiles) */ sss = &CatenarySpriteData[WIRE_X_FLAT_SW + (num % 2) + offset]; } height = GetBridgePixelHeight(end); SpriteID wire_base = GetWireBase(end, TCX_ON_BRIDGE); AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, sss->x_size, sss->y_size, sss->z_size, height + sss->z_offset, IsTransparencySet(TO_CATENARY) ); SpriteID pylon_base = GetPylonBase(end, TCX_ON_BRIDGE); /* Finished with wires, draw pylons * every other tile needs a pylon on the northern end */ if (num % 2) { DiagDirection PCPpos = (axis == AXIS_X ? DIAGDIR_NE : DIAGDIR_NW); Direction PPPpos = (axis == AXIS_X ? DIR_NW : DIR_NE); if (HasBit(tlg, (axis == AXIS_X ? 0 : 1))) PPPpos = ReverseDir(PPPpos); uint x = ti->x + x_pcp_offsets[PCPpos] + x_ppp_offsets[PPPpos]; uint y = ti->y + y_pcp_offsets[PCPpos] + y_ppp_offsets[PPPpos]; AddSortableSpriteToDraw(pylon_base + pylon_sprites[PPPpos], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, height, IsTransparencySet(TO_CATENARY), -1, -1); } /* need a pylon on the southern end of the bridge */ if (GetTunnelBridgeLength(ti->tile, start) + 1 == length) { DiagDirection PCPpos = (axis == AXIS_X ? DIAGDIR_SW : DIAGDIR_SE); Direction PPPpos = (axis == AXIS_X ? DIR_NW : DIR_NE); if (HasBit(tlg, (axis == AXIS_X ? 0 : 1))) PPPpos = ReverseDir(PPPpos); uint x = ti->x + x_pcp_offsets[PCPpos] + x_ppp_offsets[PPPpos]; uint y = ti->y + y_pcp_offsets[PCPpos] + y_ppp_offsets[PPPpos]; AddSortableSpriteToDraw(pylon_base + pylon_sprites[PPPpos], PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, height, IsTransparencySet(TO_CATENARY), -1, -1); } } /** * Draws overhead wires and pylons for electric railways. * @param ti The TileInfo struct of the tile being drawn * @see DrawCatenaryRailway */ void DrawCatenary(const TileInfo *ti) { switch (GetTileType(ti->tile)) { case MP_RAILWAY: if (IsRailDepot(ti->tile)) { const SortableSpriteStruct *sss = &CatenarySpriteData_Depot[GetRailDepotDirection(ti->tile)]; SpriteID wire_base = GetWireBase(ti->tile); /* This wire is not visible with the default depot sprites */ AddSortableSpriteToDraw( wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, sss->x_size, sss->y_size, sss->z_size, GetTileMaxPixelZ(ti->tile) + sss->z_offset, IsTransparencySet(TO_CATENARY) ); return; } break; case MP_TUNNELBRIDGE: case MP_ROAD: case MP_STATION: break; default: return; } DrawCatenaryRailway(ti); } bool SettingsDisableElrail(int32 p1) { Company *c; Train *t; bool disable = (p1 != 0); /* we will now walk through all electric train engines and change their railtypes if it is the wrong one*/ const RailType old_railtype = disable ? RAILTYPE_ELECTRIC : RAILTYPE_RAIL; const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC; /* walk through all train engines */ Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { RailVehicleInfo *rv_info = &e->u.rail; /* if it is an electric rail engine and its railtype is the wrong one */ if (rv_info->engclass == 2 && rv_info->railtype == old_railtype) { /* change it to the proper one */ rv_info->railtype = new_railtype; } } /* when disabling elrails, make sure that all existing trains can run on * normal rail too */ if (disable) { FOR_ALL_TRAINS(t) { if (t->railtype == RAILTYPE_ELECTRIC) { /* this railroad vehicle is now compatible only with elrail, * so add there also normal rail compatibility */ t->compatible_railtypes |= RAILTYPES_RAIL; t->railtype = RAILTYPE_RAIL; SetBit(t->flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL); } } } /* Fix the total power and acceleration for trains */ FOR_ALL_TRAINS(t) { /* power and acceleration is cached only for front engines */ if (t->IsFrontEngine()) { t->ConsistChanged(CCF_TRACK); } } FOR_ALL_COMPANIES(c) c->avail_railtypes = GetCompanyRailtypes(c->index); /* This resets the _last_built_railtype, which will be invalid for electric * rails. It may have unintended consequences if that function is ever * extended, though. */ ReinitGuiAfterToggleElrail(disable); return true; } openttd-1.5.3/src/rail_gui.cpp0000644000000000000000000023717412627373435015013 0ustar rootroot/* $Id: rail_gui.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 rail_gui.cpp %File for dealing with rail construction user interface */ #include "stdafx.h" #include "gui.h" #include "window_gui.h" #include "station_gui.h" #include "terraform_gui.h" #include "viewport_func.h" #include "command_func.h" #include "waypoint_func.h" #include "newgrf_station.h" #include "company_base.h" #include "strings_func.h" #include "window_func.h" #include "date_func.h" #include "sound_func.h" #include "company_func.h" #include "widgets/dropdown_type.h" #include "tunnelbridge.h" #include "tilehighlight_func.h" #include "spritecache.h" #include "core/geometry_func.hpp" #include "hotkeys.h" #include "engine_base.h" #include "vehicle_func.h" #include "zoom_func.h" #include "rail_gui.h" #include "station_map.h" #include "tunnelbridge_map.h" #include "widgets/rail_widget.h" #include "safeguards.h" static RailType _cur_railtype; ///< Rail type of the current build-rail toolbar. static bool _remove_button_clicked; ///< Flag whether 'remove' toggle-button is currently enabled static DiagDirection _build_depot_direction; ///< Currently selected depot direction static byte _waypoint_count = 1; ///< Number of waypoint types static byte _cur_waypoint_type; ///< Currently selected waypoint type static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI) static SignalType _cur_signal_type; ///< set the signal type (for signal GUI) /* Map the setting: default_signal_type to the corresponding signal type */ static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY}; struct RailStationGUISettings { Axis orientation; ///< Currently selected rail station orientation bool newstations; ///< Are custom station definitions available? StationClassID station_class; ///< Currently selected custom station class (if newstations is \c true ) byte station_type; ///< %Station type within the currently selected custom station class (if newstations is \c true ) byte station_count; ///< Number of custom stations (if newstations is \c true ) }; static RailStationGUISettings _railstation; ///< Settings of the station builder GUI static void HandleStationPlacement(TileIndex start, TileIndex end); static void ShowBuildTrainDepotPicker(Window *parent); static void ShowBuildWaypointPicker(Window *parent); static void ShowStationBuilder(Window *parent); static void ShowSignalBuilder(Window *parent); /** * Check whether a station type can be build. * @return true if building is allowed. */ static bool IsStationAvailable(const StationSpec *statspec) { if (statspec == NULL || !HasBit(statspec->callback_mask, CBM_STATION_AVAIL)) return true; uint16 cb_res = GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE); if (cb_res == CALLBACK_FAILED) return true; return Convert8bitBooleanCallback(statspec->grf_prop.grffile, CBID_STATION_AVAILABILITY, cb_res); } void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile); } static void GenericPlaceRail(TileIndex tile, int cmd) { DoCommandP(tile, _cur_railtype, cmd, _remove_button_clicked ? CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), CcPlaySound1E); } /** * Try to add an additional rail-track at the entrance of a depot * @param tile Tile to use for adding the rail-track * @param dir Direction to check for already present tracks * @param track Track to add * @see CcRailDepot() */ static void PlaceExtraDepotRail(TileIndex tile, DiagDirection dir, Track track) { if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return; if ((GetTrackBits(tile) & DiagdirReachesTracks(dir)) == 0) return; DoCommandP(tile, _cur_railtype, track, CMD_BUILD_SINGLE_RAIL); } /** Additional pieces of track to add at the entrance of a depot. */ static const Track _place_depot_extra_track[12] = { TRACK_LEFT, TRACK_UPPER, TRACK_UPPER, TRACK_RIGHT, // First additional track for directions 0..3 TRACK_X, TRACK_Y, TRACK_X, TRACK_Y, // Second additional track TRACK_LOWER, TRACK_LEFT, TRACK_RIGHT, TRACK_LOWER, // Third additional track }; /** Direction to check for existing track pieces. */ static const DiagDirection _place_depot_extra_dir[12] = { DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW, DIAGDIR_NE, }; void CcRailDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; DiagDirection dir = (DiagDirection)p2; if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); tile += TileOffsByDiagDir(dir); if (IsTileType(tile, MP_RAILWAY)) { PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir], _place_depot_extra_track[dir]); PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 4], _place_depot_extra_track[dir + 4]); PlaceExtraDepotRail(tile, _place_depot_extra_dir[dir + 8], _place_depot_extra_track[dir + 8]); } } /** * Place a rail waypoint. * @param tile Position to start dragging a waypoint. */ static void PlaceRail_Waypoint(TileIndex tile) { if (_remove_button_clicked) { VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION); return; } Axis axis = GetAxisForNewWaypoint(tile); if (IsValidAxis(axis)) { /* Valid tile for waypoints */ VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_FIX_X : VPM_FIX_Y, DDSP_BUILD_STATION); } else { /* Tile where we can't build rail waypoints. This is always going to fail, * but provides the user with a proper error message. */ DoCommandP(tile, 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT)); } } void CcStation(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile); /* Only close the station builder window if the default station and non persistent building is chosen. */ if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0 && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } /** * Place a rail station. * @param tile Position to place or start dragging a station. */ static void PlaceRail_Station(TileIndex tile) { if (_remove_button_clicked) { VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION); VpSetPlaceSizingLimit(-1); } else if (_settings_client.gui.station_dragdrop) { VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION); VpSetPlaceSizingLimit(_settings_game.station.station_spread); } else { uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24; uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; int w = _settings_client.gui.station_numtracks; int h = _settings_client.gui.station_platlength; if (!_railstation.orientation) Swap(w, h); CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; ShowSelectStationIfNeeded(cmdcont, TileArea(tile, w, h)); } } /** * Build a new signal or edit/remove a present signal, use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp * * @param tile The tile where the signal will build or edit */ static void GenericPlaceSignals(TileIndex tile) { TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)); if (trackbits & TRACK_BIT_VERT) { // N-S direction trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT; } if (trackbits & TRACK_BIT_HORZ) { // E-W direction trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER; } Track track = FindFirstTrack(trackbits); if (_remove_button_clicked) { DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E); } else { const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); /* Map the setting cycle_signal_types to the lower and upper allowed signal type. */ static const uint cycle_bounds[] = {SIGTYPE_NORMAL | (SIGTYPE_LAST_NOPBS << 3), SIGTYPE_PBS | (SIGTYPE_LAST << 3), SIGTYPE_NORMAL | (SIGTYPE_LAST << 3)}; /* various bitstuffed elements for CmdBuildSingleSignal() */ uint32 p1 = track; if (w != NULL) { /* signal GUI is used */ SB(p1, 3, 1, _ctrl_pressed); SB(p1, 4, 1, _cur_signal_variant); SB(p1, 5, 3, _cur_signal_type); SB(p1, 8, 1, _convert_signal_button); SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); } else { SB(p1, 3, 1, _ctrl_pressed); SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC)); SB(p1, 5, 3, _default_signal_type[_settings_client.gui.default_signal_type]); SB(p1, 8, 1, 0); SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]); } DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS | CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), CcPlaySound1E); } } /** * Start placing a rail bridge. * @param tile Position of the first tile of the bridge. * @param w Rail toolbar window. */ static void PlaceRail_Bridge(TileIndex tile, Window *w) { if (IsBridgeTile(tile)) { TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); Point pt = {0, 0}; w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); } else { VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); } } /** Command callback for building a tunnel */ void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded()) { if (_settings_client.sound.confirm) SndPlayTileFx(SND_20_SPLAT_RAIL, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } else { SetRedErrorSquare(_build_tunnel_endtile); } } /** * Toggles state of the Remove button of Build rail toolbar * @param w window the button belongs to */ static void ToggleRailButton_Remove(Window *w) { DeleteWindowById(WC_SELECT_STATION, 0); w->ToggleWidgetLoweredState(WID_RAT_REMOVE); w->SetWidgetDirty(WID_RAT_REMOVE); _remove_button_clicked = w->IsWidgetLowered(WID_RAT_REMOVE); SetSelectionRed(_remove_button_clicked); } /** * Updates the Remove button because of Ctrl state change * @param w window the button belongs to * @return true iff the remove button was changed */ static bool RailToolbar_CtrlChanged(Window *w) { if (w->IsWidgetDisabled(WID_RAT_REMOVE)) return false; /* allow ctrl to switch remove mode only for these widgets */ for (uint i = WID_RAT_BUILD_NS; i <= WID_RAT_BUILD_STATION; i++) { if ((i <= WID_RAT_AUTORAIL || i >= WID_RAT_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) { ToggleRailButton_Remove(w); return true; } } return false; } /** * The "remove"-button click proc of the build-rail toolbar. * @param w Build-rail toolbar window * @see BuildRailToolbarWindow::OnClick() */ static void BuildRailClick_Remove(Window *w) { if (w->IsWidgetDisabled(WID_RAT_REMOVE)) return; ToggleRailButton_Remove(w); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); /* handle station builder */ if (w->IsWidgetLowered(WID_RAT_BUILD_STATION)) { if (_remove_button_clicked) { /* starting drag & drop remove */ if (!_settings_client.gui.station_dragdrop) { SetTileSelectSize(1, 1); } else { VpSetPlaceSizingLimit(-1); } } else { /* starting station build mode */ if (!_settings_client.gui.station_dragdrop) { int x = _settings_client.gui.station_numtracks; int y = _settings_client.gui.station_platlength; if (_railstation.orientation == 0) Swap(x, y); SetTileSelectSize(x, y); } else { VpSetPlaceSizingLimit(_settings_game.station.station_spread); } } } } static void DoRailroadTrack(int mode) { DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), _remove_button_clicked ? CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) : CMD_BUILD_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK), CcPlaySound1E); } static void HandleAutodirPlacement() { int trackstat = _thd.drawstyle & HT_DIR_MASK; // 0..5 if (_thd.drawstyle & HT_RAIL) { // one tile case GenericPlaceRail(TileVirtXY(_thd.selend.x, _thd.selend.y), trackstat); return; } DoRailroadTrack(trackstat); } /** * Build new signals or remove signals or (if only one tile marked) edit a signal. * * If one tile marked abort and use GenericPlaceSignals() * else use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp to build many signals */ static void HandleAutoSignalPlacement() { uint32 p2 = GB(_thd.drawstyle, 0, 3); // 0..5 if ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT) { // one tile case GenericPlaceSignals(TileVirtXY(_thd.selend.x, _thd.selend.y)); return; } const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); if (w != NULL) { /* signal GUI is used */ SB(p2, 3, 1, 0); SB(p2, 4, 1, _cur_signal_variant); SB(p2, 6, 1, _ctrl_pressed); SB(p2, 7, 3, _cur_signal_type); SB(p2, 24, 8, _settings_client.gui.drag_signals_density); SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance); } else { SB(p2, 3, 1, 0); SB(p2, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC)); SB(p2, 6, 1, _ctrl_pressed); SB(p2, 7, 3, _default_signal_type[_settings_client.gui.default_signal_type]); SB(p2, 24, 8, _settings_client.gui.drag_signals_density); SB(p2, 10, 1, !_settings_client.gui.drag_signals_fixed_distance); } /* _settings_client.gui.drag_signals_density is given as a parameter such that each user * in a network game can specify his/her own signal density */ DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), p2, _remove_button_clicked ? CMD_REMOVE_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM) : CMD_BUILD_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE), CcPlaySound1E); } /** Rail toolbar management class. */ struct BuildRailToolbarWindow : Window { RailType railtype; ///< Rail type to build. int last_user_action; ///< Last started user action. BuildRailToolbarWindow(WindowDesc *desc, RailType railtype) : Window(desc) { this->InitNested(TRANSPORT_RAIL); this->SetupRailToolbar(railtype); this->DisableWidget(WID_RAT_REMOVE); this->last_user_action = WIDGET_LIST_END; if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); } ~BuildRailToolbarWindow() { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } /** * 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; if (!CanBuildVehicleInfrastructure(VEH_TRAIN)) delete this; } /** * Configures the rail toolbar for railtype given * @param railtype the railtype to display */ void SetupRailToolbar(RailType railtype) { this->railtype = railtype; const RailtypeInfo *rti = GetRailTypeInfo(railtype); assert(railtype < RAILTYPE_END); this->GetWidget(WID_RAT_BUILD_NS)->widget_data = rti->gui_sprites.build_ns_rail; this->GetWidget(WID_RAT_BUILD_X)->widget_data = rti->gui_sprites.build_x_rail; this->GetWidget(WID_RAT_BUILD_EW)->widget_data = rti->gui_sprites.build_ew_rail; this->GetWidget(WID_RAT_BUILD_Y)->widget_data = rti->gui_sprites.build_y_rail; this->GetWidget(WID_RAT_AUTORAIL)->widget_data = rti->gui_sprites.auto_rail; this->GetWidget(WID_RAT_BUILD_DEPOT)->widget_data = rti->gui_sprites.build_depot; this->GetWidget(WID_RAT_CONVERT_RAIL)->widget_data = rti->gui_sprites.convert_rail; this->GetWidget(WID_RAT_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel; } /** * Switch to another rail type. * @param railtype New rail type. */ void ModifyRailType(RailType railtype) { this->SetupRailToolbar(railtype); this->ReInit(); } void UpdateRemoveWidgetStatus(int clicked_widget) { switch (clicked_widget) { case WID_RAT_REMOVE: /* If it is the removal button that has been clicked, do nothing, * as it is up to the other buttons to drive removal status */ return; case WID_RAT_BUILD_NS: case WID_RAT_BUILD_X: case WID_RAT_BUILD_EW: case WID_RAT_BUILD_Y: case WID_RAT_AUTORAIL: case WID_RAT_BUILD_WAYPOINT: case WID_RAT_BUILD_STATION: case WID_RAT_BUILD_SIGNALS: /* Removal button is enabled only if the rail/signal/waypoint/station * button is still lowered. Once raised, it has to be disabled */ this->SetWidgetDisabledState(WID_RAT_REMOVE, !this->IsWidgetLowered(clicked_widget)); break; default: /* When any other buttons than rail/signal/waypoint/station, raise and * disable the removal button */ this->DisableWidget(WID_RAT_REMOVE); this->RaiseWidget(WID_RAT_REMOVE); break; } } virtual void SetStringParameters(int widget) const { if (widget == WID_RAT_CAPTION) { const RailtypeInfo *rti = GetRailTypeInfo(this->railtype); if (rti->max_speed > 0) { SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY); SetDParam(1, rti->strings.toolbar_caption); SetDParam(2, rti->max_speed); } else { SetDParam(0, rti->strings.toolbar_caption); } } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget < WID_RAT_BUILD_NS) return; _remove_button_clicked = false; switch (widget) { case WID_RAT_BUILD_NS: HandlePlacePushButton(this, WID_RAT_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL); this->last_user_action = widget; break; case WID_RAT_BUILD_X: HandlePlacePushButton(this, WID_RAT_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X); this->last_user_action = widget; break; case WID_RAT_BUILD_EW: HandlePlacePushButton(this, WID_RAT_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL); this->last_user_action = widget; break; case WID_RAT_BUILD_Y: HandlePlacePushButton(this, WID_RAT_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y); this->last_user_action = widget; break; case WID_RAT_AUTORAIL: HandlePlacePushButton(this, WID_RAT_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, HT_RAIL); this->last_user_action = widget; break; case WID_RAT_DEMOLISH: HandlePlacePushButton(this, WID_RAT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_user_action = widget; break; case WID_RAT_BUILD_DEPOT: if (HandlePlacePushButton(this, WID_RAT_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT)) { ShowBuildTrainDepotPicker(this); this->last_user_action = widget; } break; case WID_RAT_BUILD_WAYPOINT: this->last_user_action = widget; _waypoint_count = StationClass::Get(STAT_CLASS_WAYP)->GetSpecCount(); if (HandlePlacePushButton(this, WID_RAT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT) && _waypoint_count > 1) { ShowBuildWaypointPicker(this); } break; case WID_RAT_BUILD_STATION: if (HandlePlacePushButton(this, WID_RAT_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT)) { ShowStationBuilder(this); this->last_user_action = widget; } break; case WID_RAT_BUILD_SIGNALS: { this->last_user_action = widget; bool started = HandlePlacePushButton(this, WID_RAT_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT); if (started && _settings_client.gui.enable_signal_gui != _ctrl_pressed) { ShowSignalBuilder(this); } break; } case WID_RAT_BUILD_BRIDGE: HandlePlacePushButton(this, WID_RAT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT); this->last_user_action = widget; break; case WID_RAT_BUILD_TUNNEL: HandlePlacePushButton(this, WID_RAT_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, HT_SPECIAL); this->last_user_action = widget; break; case WID_RAT_REMOVE: BuildRailClick_Remove(this); break; case WID_RAT_CONVERT_RAIL: HandlePlacePushButton(this, WID_RAT_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, HT_RECT | HT_DIAGONAL); this->last_user_action = widget; break; default: NOT_REACHED(); } this->UpdateRemoveWidgetStatus(widget); if (_ctrl_pressed) RailToolbar_CtrlChanged(this); } virtual EventState OnHotkey(int hotkey) { MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection return Window::OnHotkey(hotkey); } virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_user_action) { case WID_RAT_BUILD_NS: VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); break; case WID_RAT_BUILD_X: VpStartPlaceSizing(tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL); break; case WID_RAT_BUILD_EW: VpStartPlaceSizing(tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); break; case WID_RAT_BUILD_Y: VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL); break; case WID_RAT_AUTORAIL: VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL); break; case WID_RAT_DEMOLISH: PlaceProc_DemolishArea(tile); break; case WID_RAT_BUILD_DEPOT: DoCommandP(tile, _cur_railtype, _build_depot_direction, CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), CcRailDepot); break; case WID_RAT_BUILD_WAYPOINT: PlaceRail_Waypoint(tile); break; case WID_RAT_BUILD_STATION: PlaceRail_Station(tile); break; case WID_RAT_BUILD_SIGNALS: VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS); break; case WID_RAT_BUILD_BRIDGE: PlaceRail_Bridge(tile, this); break; case WID_RAT_BUILD_TUNNEL: DoCommandP(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel); break; case WID_RAT_CONVERT_RAIL: VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL); break; default: NOT_REACHED(); } } virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) { /* no dragging if you have pressed the convert button */ if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(WID_RAT_BUILD_SIGNALS)) return; 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) { default: NOT_REACHED(); case DDSP_BUILD_BRIDGE: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype); break; case DDSP_PLACE_RAIL: HandleAutodirPlacement(); break; case DDSP_BUILD_SIGNALS: HandleAutoSignalPlacement(); break; case DDSP_DEMOLISH_AREA: GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; case DDSP_CONVERT_RAIL: DoCommandP(end_tile, start_tile, _cur_railtype | (_ctrl_pressed ? 0x10 : 0), CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10); break; case DDSP_REMOVE_STATION: case DDSP_BUILD_STATION: if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) { /* Station */ if (_remove_button_clicked) { DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E); } else { HandleStationPlacement(start_tile, end_tile); } } else { /* Waypoint */ if (_remove_button_clicked) { DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E); } else { TileArea ta(start_tile, end_tile); uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24; uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16; CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, "" }; ShowSelectWaypointIfNeeded(cmdcont, ta); } } break; } } } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); this->DisableWidget(WID_RAT_REMOVE); this->SetWidgetDirty(WID_RAT_REMOVE); DeleteWindowById(WC_BUILD_SIGNAL, TRANSPORT_RAIL); DeleteWindowById(WC_BUILD_STATION, TRANSPORT_RAIL); DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_RAIL); DeleteWindowById(WC_BUILD_WAYPOINT, TRANSPORT_RAIL); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); } virtual void OnPlacePresize(Point pt, TileIndex tile) { DoCommand(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); } virtual EventState OnCTRLStateChange() { /* do not toggle Remove button by Ctrl when placing station */ if (!this->IsWidgetLowered(WID_RAT_BUILD_STATION) && !this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT) && RailToolbar_CtrlChanged(this)) return ES_HANDLED; return ES_NOT_HANDLED; } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the BuildRailToolbarWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState RailToolbarGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL || !CanBuildVehicleInfrastructure(VEH_TRAIN)) return ES_NOT_HANDLED; extern RailType _last_built_railtype; Window *w = ShowBuildRailToolbar(_last_built_railtype); if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } const uint16 _railtoolbar_autorail_keys[] = {'5', 'A' | WKC_GLOBAL_HOTKEY, 0}; static Hotkey railtoolbar_hotkeys[] = { Hotkey('1', "build_ns", WID_RAT_BUILD_NS), Hotkey('2', "build_x", WID_RAT_BUILD_X), Hotkey('3', "build_ew", WID_RAT_BUILD_EW), Hotkey('4', "build_y", WID_RAT_BUILD_Y), Hotkey(_railtoolbar_autorail_keys, "autorail", WID_RAT_AUTORAIL), Hotkey('6', "demolish", WID_RAT_DEMOLISH), Hotkey('7', "depot", WID_RAT_BUILD_DEPOT), Hotkey('8', "waypoint", WID_RAT_BUILD_WAYPOINT), Hotkey('9', "station", WID_RAT_BUILD_STATION), Hotkey('S', "signal", WID_RAT_BUILD_SIGNALS), Hotkey('B', "bridge", WID_RAT_BUILD_BRIDGE), Hotkey('T', "tunnel", WID_RAT_BUILD_TUNNEL), Hotkey('R', "remove", WID_RAT_REMOVE), Hotkey('C', "convert", WID_RAT_CONVERT_RAIL), HOTKEY_LIST_END }; HotkeyList BuildRailToolbarWindow::hotkeys("railtoolbar", railtoolbar_hotkeys, RailToolbarGlobalHotkeys); static const NWidgetPart _nested_build_rail_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_RAT_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_NS), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_X), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_EW), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_EW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_Y), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_AUTORAIL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_DEPOT), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DEPOT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_WAYPOINT), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_STATION), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_SIGNALS), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_SIGNALS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_BUILD_TUNNEL), SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_RAT_CONVERT_RAIL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL), EndContainer(), }; static WindowDesc _build_rail_desc( WDP_ALIGN_TOOLBAR, "toolbar_rail", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_rail_widgets, lengthof(_nested_build_rail_widgets), &BuildRailToolbarWindow::hotkeys ); /** * Open the build rail toolbar window for a specific rail type. * * If the terraform toolbar is linked to the toolbar, that window is also opened. * * @param railtype Rail type to open the window for * @return newly opened rail toolbar, or NULL if the toolbar could not be opened. */ Window *ShowBuildRailToolbar(RailType railtype) { if (!Company::IsValidID(_local_company)) return NULL; if (!ValParamRailtype(railtype)) return NULL; DeleteWindowByClass(WC_BUILD_TOOLBAR); _cur_railtype = railtype; _remove_button_clicked = false; return new BuildRailToolbarWindow(&_build_rail_desc, railtype); } /* TODO: For custom stations, respect their allowed platforms/lengths bitmasks! * --pasky */ static void HandleStationPlacement(TileIndex start, TileIndex end) { TileArea ta(start, end); uint numtracks = ta.w; uint platlength = ta.h; if (_railstation.orientation == AXIS_X) Swap(numtracks, platlength); uint32 p1 = _cur_railtype | _railstation.orientation << 4 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24; uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16; CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" }; ShowSelectStationIfNeeded(cmdcont, ta); } struct BuildRailStationWindow : public PickerWindowBase { private: uint line_height; ///< Height of a single line in the newstation selection matrix (#WID_BRAS_NEWST_LIST widget). uint coverage_height; ///< Height of the coverage texts. Scrollbar *vscroll; ///< Vertical scrollbar of the new station list. Scrollbar *vscroll2; ///< Vertical scrollbar of the matrix with new stations. /** * Verify whether the currently selected station size is allowed after selecting a new station class/type. * If not, change the station size variables ( _settings_client.gui.station_numtracks and _settings_client.gui.station_platlength ). * @param statspec Specification of the new station class/type */ void CheckSelectedSize(const StationSpec *statspec) { if (statspec == NULL || _settings_client.gui.station_dragdrop) return; /* If current number of tracks is not allowed, make it as big as possible */ if (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); _settings_client.gui.station_numtracks = 1; if (statspec->disallowed_platforms != UINT8_MAX) { while (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { _settings_client.gui.station_numtracks++; } this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); } } if (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); _settings_client.gui.station_platlength = 1; if (statspec->disallowed_lengths != UINT8_MAX) { while (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { _settings_client.gui.station_platlength++; } this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); } } } public: BuildRailStationWindow(WindowDesc *desc, Window *parent, bool newstation) : PickerWindowBase(desc, parent) { this->coverage_height = 2 * FONT_HEIGHT_NORMAL + 3 * WD_PAR_VSEP_NORMAL; this->vscroll = NULL; _railstation.newstations = newstation; this->CreateNestedTree(); NWidgetStacked *newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_ADDITIONS); newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_MATRIX); newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_DEFSIZE); newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); newst_additions = this->GetWidget(WID_BRAS_SHOW_NEWST_RESIZE); newst_additions->SetDisplayedPlane(newstation ? 0 : SZSP_NONE); if (newstation) { this->vscroll = this->GetScrollbar(WID_BRAS_NEWST_SCROLL); this->vscroll2 = this->GetScrollbar(WID_BRAS_MATRIX_SCROLL); } this->FinishInitNested(TRANSPORT_RAIL); this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); if (_settings_client.gui.station_dragdrop) { this->LowerWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); } else { this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); } this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage); this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage); if (!newstation || _railstation.station_class >= (int)StationClass::GetClassCount()) { /* New stations are not available or changed, so ensure the default station * type is 'selected'. */ _railstation.station_class = STAT_CLASS_DFLT; _railstation.station_type = 0; this->vscroll2 = NULL; } if (newstation) { _railstation.station_count = StationClass::Get(_railstation.station_class)->GetSpecCount(); _railstation.station_type = min(_railstation.station_type, _railstation.station_count - 1); int count = 0; for (uint i = 0; i < StationClass::GetClassCount(); i++) { if (i == STAT_CLASS_WAYP) continue; count++; } this->vscroll->SetCount(count); this->vscroll->SetPosition(Clamp(_railstation.station_class - 2, 0, max(this->vscroll->GetCount() - this->vscroll->GetCapacity(), 0))); NWidgetMatrix *matrix = this->GetWidget(WID_BRAS_MATRIX); matrix->SetScrollbar(this->vscroll2); matrix->SetCount(_railstation.station_count); matrix->SetClicked(_railstation.station_type); } } virtual ~BuildRailStationWindow() { DeleteWindowById(WC_SELECT_STATION, 0); } virtual void OnPaint() { bool newstations = _railstation.newstations; const StationSpec *statspec = newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; if (_settings_client.gui.station_dragdrop) { SetTileSelectSize(1, 1); } else { int x = _settings_client.gui.station_numtracks; int y = _settings_client.gui.station_platlength; if (_railstation.orientation == AXIS_X) Swap(x, y); if (!_remove_button_clicked) { SetTileSelectSize(x, y); } } int rad = (_settings_game.station.modified_catchment) ? CA_TRAIN : CA_UNMODIFIED; if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); for (uint bits = 0; bits < 7; bits++) { bool disable = bits >= _settings_game.station.station_spread; if (statspec == NULL) { this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_NUM_1, disable); this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_LEN_1, disable); } else { this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable); this->SetWidgetDisabledState(bits + WID_BRAS_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths, bits) || disable); } } this->DrawWidgets(); /* 'Accepts' and 'Supplies' texts. */ NWidgetBase *cov = this->GetWidget(WID_BRAS_COVERAGE_TEXTS); int top = cov->pos_y + WD_PAR_VSEP_NORMAL; int left = cov->pos_x + WD_FRAMERECT_LEFT; int right = cov->pos_x + cov->current_x - WD_FRAMERECT_RIGHT; int bottom = cov->pos_y + cov->current_y; top = DrawStationCoverageAreaText(left, right, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; top = DrawStationCoverageAreaText(left, right, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; /* Resize background if the window is too small. * Never make the window smaller to avoid oscillating if the size change affects the acceptance. * (This is the case, if making the window bigger moves the mouse into the window.) */ if (top > bottom) { this->coverage_height += top - bottom; this->ReInit(); } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_BRAS_NEWST_LIST: { Dimension d = {0, 0}; for (uint i = 0; i < StationClass::GetClassCount(); i++) { if (i == STAT_CLASS_WAYP) continue; d = maxdim(d, GetStringBoundingBox(StationClass::Get((StationClassID)i)->name)); } size->width = max(size->width, d.width + padding.width); this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 5 * this->line_height; resize->height = this->line_height; break; } case WID_BRAS_SHOW_NEWST_TYPE: { if (!_railstation.newstations) { size->width = 0; size->height = 0; break; } /* If newstations exist, compute the non-zero minimal size. */ Dimension d = {0, 0}; StringID str = this->GetWidget(widget)->widget_data; for (StationClassID statclass = STAT_CLASS_BEGIN; statclass < (StationClassID)StationClass::GetClassCount(); statclass++) { if (statclass == STAT_CLASS_WAYP) continue; StationClass *stclass = StationClass::Get(statclass); for (uint16 j = 0; j < stclass->GetSpecCount(); j++) { const StationSpec *statspec = stclass->GetSpec(j); SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); d = maxdim(d, GetStringBoundingBox(str)); } } size->width = max(size->width, d.width + padding.width); break; } case WID_BRAS_PLATFORM_DIR_X: case WID_BRAS_PLATFORM_DIR_Y: case WID_BRAS_IMAGE: size->width = ScaleGUITrad(64) + 2; size->height = ScaleGUITrad(58) + 2; break; case WID_BRAS_COVERAGE_TEXTS: size->height = this->coverage_height; break; case WID_BRAS_MATRIX: fill->height = 1; resize->height = 1; break; } } virtual void DrawWidget(const Rect &r, int widget) const { DrawPixelInfo tmp_dpi; switch (GB(widget, 0, 16)) { case WID_BRAS_PLATFORM_DIR_X: /* Set up a clipping area for the '/' station preview */ if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; int x = ScaleGUITrad(31) + 1; int y = r.bottom - r.top - ScaleGUITrad(31); if (!DrawStationTile(x, y, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) { StationPickerDrawSprite(x, y, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2); } _cur_dpi = old_dpi; } break; case WID_BRAS_PLATFORM_DIR_Y: /* Set up a clipping area for the '\' station preview */ if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; int x = ScaleGUITrad(31) + 1; int y = r.bottom - r.top - ScaleGUITrad(31); if (!DrawStationTile(x, y, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) { StationPickerDrawSprite(x, y, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3); } _cur_dpi = old_dpi; } break; case WID_BRAS_NEWST_LIST: { uint statclass = 0; uint row = 0; for (uint i = 0; i < StationClass::GetClassCount(); i++) { if (i == STAT_CLASS_WAYP) continue; if (this->vscroll->IsVisible(statclass)) { DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, row * this->line_height + r.top + WD_MATRIX_TOP, StationClass::Get((StationClassID)i)->name, (StationClassID)i == _railstation.station_class ? TC_WHITE : TC_BLACK); row++; } statclass++; } break; } case WID_BRAS_IMAGE: { byte type = GB(widget, 16, 16); assert(type < _railstation.station_count); /* Check station availability callback */ const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(type); if (!IsStationAvailable(statspec)) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); } /* Set up a clipping area for the station preview. */ if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; int x = ScaleGUITrad(31) + 1; int y = r.bottom - r.top - ScaleGUITrad(31); if (!DrawStationTile(x, y, _cur_railtype, _railstation.orientation, _railstation.station_class, type)) { StationPickerDrawSprite(x, y, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2 + _railstation.orientation); } _cur_dpi = old_dpi; } break; } } } virtual void OnResize() { if (this->vscroll != NULL) { // New stations available. this->vscroll->SetCapacityFromWidget(this, WID_BRAS_NEWST_LIST); } } virtual void SetStringParameters(int widget) const { if (widget == WID_BRAS_SHOW_NEWST_TYPE) { const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type); SetDParam(0, (statspec != NULL && statspec->name != 0) ? statspec->name : STR_STATION_CLASS_DFLT); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (GB(widget, 0, 16)) { case WID_BRAS_PLATFORM_DIR_X: case WID_BRAS_PLATFORM_DIR_Y: this->RaiseWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); _railstation.orientation = (Axis)(widget - WID_BRAS_PLATFORM_DIR_X); this->LowerWidget(_railstation.orientation + WID_BRAS_PLATFORM_DIR_X); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); break; case WID_BRAS_PLATFORM_NUM_1: case WID_BRAS_PLATFORM_NUM_2: case WID_BRAS_PLATFORM_NUM_3: case WID_BRAS_PLATFORM_NUM_4: case WID_BRAS_PLATFORM_NUM_5: case WID_BRAS_PLATFORM_NUM_6: case WID_BRAS_PLATFORM_NUM_7: { this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); _settings_client.gui.station_numtracks = widget - WID_BRAS_PLATFORM_NUM_BEGIN; _settings_client.gui.station_dragdrop = false; _settings_client.gui.station_dragdrop = false; const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { /* The previously selected number of platforms in invalid */ for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_lengths, i)) { this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); _settings_client.gui.station_platlength = i + 1; break; } } } this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); break; } case WID_BRAS_PLATFORM_LEN_1: case WID_BRAS_PLATFORM_LEN_2: case WID_BRAS_PLATFORM_LEN_3: case WID_BRAS_PLATFORM_LEN_4: case WID_BRAS_PLATFORM_LEN_5: case WID_BRAS_PLATFORM_LEN_6: case WID_BRAS_PLATFORM_LEN_7: { this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP); _settings_client.gui.station_platlength = widget - WID_BRAS_PLATFORM_LEN_BEGIN; _settings_client.gui.station_dragdrop = false; _settings_client.gui.station_dragdrop = false; const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { /* The previously selected number of tracks in invalid */ for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_platforms, i)) { this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); _settings_client.gui.station_numtracks = i + 1; break; } } } this->LowerWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); this->LowerWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); break; } case WID_BRAS_PLATFORM_DRAG_N_DROP: { _settings_client.gui.station_dragdrop ^= true; this->ToggleWidgetLoweredState(WID_BRAS_PLATFORM_DRAG_N_DROP); /* get the first allowed length/number of platforms */ const StationSpec *statspec = _railstation.newstations ? StationClass::Get(_railstation.station_class)->GetSpec(_railstation.station_type) : NULL; if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) { for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_lengths, i)) { this->RaiseWidget(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN); _settings_client.gui.station_platlength = i + 1; break; } } } if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) { for (uint i = 0; i < 7; i++) { if (!HasBit(statspec->disallowed_platforms, i)) { this->RaiseWidget(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN); _settings_client.gui.station_numtracks = i + 1; break; } } } this->SetWidgetLoweredState(_settings_client.gui.station_numtracks + WID_BRAS_PLATFORM_NUM_BEGIN, !_settings_client.gui.station_dragdrop); this->SetWidgetLoweredState(_settings_client.gui.station_platlength + WID_BRAS_PLATFORM_LEN_BEGIN, !_settings_client.gui.station_dragdrop); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); break; } case WID_BRAS_HIGHLIGHT_OFF: case WID_BRAS_HIGHLIGHT_ON: _settings_client.gui.station_show_coverage = (widget != WID_BRAS_HIGHLIGHT_OFF); this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage); this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); break; case WID_BRAS_NEWST_LIST: { int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST, 0, this->line_height); if (y >= (int)StationClass::GetClassCount()) return; for (uint i = 0; i < StationClass::GetClassCount(); i++) { if (i == STAT_CLASS_WAYP) continue; if (y == 0) { if (_railstation.station_class != (StationClassID)i) { _railstation.station_class = (StationClassID)i; StationClass *stclass = StationClass::Get(_railstation.station_class); _railstation.station_count = stclass->GetSpecCount(); _railstation.station_type = min((int)_railstation.station_type, max(0, (int)_railstation.station_count - 1)); this->CheckSelectedSize(stclass->GetSpec(_railstation.station_type)); NWidgetMatrix *matrix = this->GetWidget(WID_BRAS_MATRIX); matrix->SetCount(_railstation.station_count); matrix->SetClicked(_railstation.station_type); } if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); break; } y--; } break; } case WID_BRAS_IMAGE: { int y = GB(widget, 16, 16); if (y >= _railstation.station_count) return; /* Check station availability callback */ const StationSpec *statspec = StationClass::Get(_railstation.station_class)->GetSpec(y); if (!IsStationAvailable(statspec)) return; _railstation.station_type = y; this->CheckSelectedSize(statspec); this->GetWidget(WID_BRAS_MATRIX)->SetClicked(_railstation.station_type); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); break; } } } virtual void OnTick() { CheckRedrawStationCoverage(this); } }; static const NWidgetPart _nested_station_builder_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_DEFSIZE), NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_ADDITIONS), NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), SetPadding(2, 0, 1, 0), NWidget(WWT_MATRIX, COLOUR_GREY, WID_BRAS_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_STATION_BUILD_STATION_CLASS_TOOLTIP), SetScrollbar(WID_BRAS_NEWST_SCROLL), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BRAS_NEWST_SCROLL), EndContainer(), EndContainer(), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_X), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_Y), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), EndContainer(), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BRAS_SHOW_NEWST_TYPE), SetMinimalSize(144, 11), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(1, 2, 4, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL), SetPadding(0, 2, 0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_NUM_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH, STR_NULL), SetPadding(2, 2, 0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_LEN_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP), NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), EndContainer(), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_OFF), SetMinimalSize(60, 12), SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_ON), SetMinimalSize(60, 12), SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_MATRIX), /* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */ NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BRAS_MATRIX_SCROLL), NWidget(NWID_HORIZONTAL), NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRAS_MATRIX), SetScrollbar(WID_BRAS_MATRIX_SCROLL), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRAS_IMAGE), SetMinimalSize(66, 60), SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BRAS_MATRIX_SCROLL), EndContainer(), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BRAS_MATRIX_SCROLL), EndContainer(), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BRAS_COVERAGE_TEXTS), SetFill(1, 1), SetResize(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_RESIZE), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), EndContainer(), EndContainer(), EndContainer(), EndContainer(), }; /** High level window description of the station-build window (default & newGRF) */ static WindowDesc _station_builder_desc( WDP_AUTO, "build_station_rail", 350, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets) ); /** Open station build window */ static void ShowStationBuilder(Window *parent) { bool newstations = StationClass::GetClassCount() > 2 || StationClass::Get(STAT_CLASS_DFLT)->GetSpecCount() != 1; new BuildRailStationWindow(&_station_builder_desc, parent, newstations); } struct BuildSignalWindow : public PickerWindowBase { private: Dimension sig_sprite_size; ///< Maximum size of signal GUI sprites. int sig_sprite_bottom_offset; ///< Maximum extent of signal GUI sprite from reference point towards bottom. /** * Draw dynamic a signal-sprite in a button in the signal GUI * Draw the sprite +1px to the right and down if the button is lowered * * @param widget_index index of this widget in the window * @param image the sprite to draw */ void DrawSignalSprite(byte widget_index, SpriteID image) const { Point offset; Dimension sprite_size = GetSpriteSize(image, &offset); const NWidgetBase *widget = this->GetWidget(widget_index); int x = widget->pos_x - offset.x + (widget->current_x - sprite_size.width + offset.x) / 2; // centered int y = widget->pos_y - sig_sprite_bottom_offset + WD_IMGBTN_TOP + (widget->current_y - WD_IMGBTN_TOP - WD_IMGBTN_BOTTOM + sig_sprite_size.height) / 2; // aligned to bottom DrawSprite(image, PAL_NONE, x + this->IsWidgetLowered(widget_index), y + this->IsWidgetLowered(widget_index)); } public: BuildSignalWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->InitNested(TRANSPORT_RAIL); this->OnInvalidateData(); } ~BuildSignalWindow() { _convert_signal_button = false; } virtual void OnInit() { /* Calculate maximum signal sprite size. */ this->sig_sprite_size.width = 0; this->sig_sprite_size.height = 0; this->sig_sprite_bottom_offset = 0; const RailtypeInfo *rti = GetRailTypeInfo(_cur_railtype); for (uint type = SIGTYPE_NORMAL; type < SIGTYPE_END; type++) { for (uint variant = SIG_ELECTRIC; variant <= SIG_SEMAPHORE; variant++) { for (uint lowered = 0; lowered < 2; lowered++) { Point offset; Dimension sprite_size = GetSpriteSize(rti->gui_sprites.signals[type][variant][lowered], &offset); this->sig_sprite_bottom_offset = max(this->sig_sprite_bottom_offset, sprite_size.height); this->sig_sprite_size.width = max(this->sig_sprite_size.width, sprite_size.width - offset.x); this->sig_sprite_size.height = max(this->sig_sprite_size.height, sprite_size.height - offset.y); } } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_BS_DRAG_SIGNALS_DENSITY_LABEL) { /* Two digits for signals density. */ size->width = max(size->width, 2 * GetDigitWidth() + padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT); } else if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { size->width = max(size->width, this->sig_sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT); size->height = max(size->height, this->sig_sprite_size.height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_BS_DRAG_SIGNALS_DENSITY_LABEL: SetDParam(0, _settings_client.gui.drag_signals_density); break; } } virtual void DrawWidget(const Rect &r, int widget) const { if (IsInsideMM(widget, WID_BS_SEMAPHORE_NORM, WID_BS_ELECTRIC_PBS_OWAY + 1)) { /* Extract signal from widget number. */ int type = (widget - WID_BS_SEMAPHORE_NORM) % SIGTYPE_END; int var = SIG_SEMAPHORE - (widget - WID_BS_SEMAPHORE_NORM) / SIGTYPE_END; // SignalVariant order is reversed compared to the widgets. SpriteID sprite = GetRailTypeInfo(_cur_railtype)->gui_sprites.signals[type][var][this->IsWidgetLowered(widget)]; this->DrawSignalSprite(widget, sprite); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BS_SEMAPHORE_NORM: case WID_BS_SEMAPHORE_ENTRY: case WID_BS_SEMAPHORE_EXIT: case WID_BS_SEMAPHORE_COMBO: case WID_BS_SEMAPHORE_PBS: case WID_BS_SEMAPHORE_PBS_OWAY: case WID_BS_ELECTRIC_NORM: case WID_BS_ELECTRIC_ENTRY: case WID_BS_ELECTRIC_EXIT: case WID_BS_ELECTRIC_COMBO: case WID_BS_ELECTRIC_PBS: case WID_BS_ELECTRIC_PBS_OWAY: this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); _cur_signal_type = (SignalType)((uint)((widget - WID_BS_SEMAPHORE_NORM) % (SIGTYPE_LAST + 1))); _cur_signal_variant = widget >= WID_BS_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE; /* If 'remove' button of rail build toolbar is active, disable it. */ if (_remove_button_clicked) { Window *w = FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL); if (w != NULL) ToggleRailButton_Remove(w); } break; case WID_BS_CONVERT: _convert_signal_button = !_convert_signal_button; break; case WID_BS_DRAG_SIGNALS_DENSITY_DECREASE: if (_settings_client.gui.drag_signals_density > 1) { _settings_client.gui.drag_signals_density--; SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_SETTINGS); } break; case WID_BS_DRAG_SIGNALS_DENSITY_INCREASE: if (_settings_client.gui.drag_signals_density < 20) { _settings_client.gui.drag_signals_density++; SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_SETTINGS); } break; default: break; } this->InvalidateData(); } /** * 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->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); this->SetWidgetLoweredState(WID_BS_CONVERT, _convert_signal_button); this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1); this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20); } }; /** Nested widget definition of the build signal window */ static const NWidgetPart _nested_signal_builder_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_SIGNAL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_BS_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BS_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BS_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), EndContainer(), EndContainer(), EndContainer(), }; /** Signal selection window description */ static WindowDesc _signal_builder_desc( WDP_AUTO, "build_signal", 0, 0, WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_signal_builder_widgets, lengthof(_nested_signal_builder_widgets) ); /** * Open the signal selection window */ static void ShowSignalBuilder(Window *parent) { new BuildSignalWindow(&_signal_builder_desc, parent); } struct BuildRailDepotWindow : public PickerWindowBase { BuildRailDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->InitNested(TRANSPORT_RAIL); this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (!IsInsideMM(widget, WID_BRAD_DEPOT_NE, WID_BRAD_DEPOT_NW + 1)) return; size->width = ScaleGUITrad(64) + 2; size->height = ScaleGUITrad(48) + 2; } virtual void DrawWidget(const Rect &r, int widget) const { if (!IsInsideMM(widget, WID_BRAD_DEPOT_NE, WID_BRAD_DEPOT_NW + 1)) return; DrawTrainDepotSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), widget - WID_BRAD_DEPOT_NE + DIAGDIR_NE, _cur_railtype); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BRAD_DEPOT_NE: case WID_BRAD_DEPOT_SE: case WID_BRAD_DEPOT_SW: case WID_BRAD_DEPOT_NW: this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); _build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE); this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); break; } } }; /** Nested widget definition of the build rail depot window */ static const NWidgetPart _nested_build_depot_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(NWID_HORIZONTAL_LTR), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), EndContainer(), }; static WindowDesc _build_depot_desc( WDP_AUTO, NULL, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets) ); static void ShowBuildTrainDepotPicker(Window *parent) { new BuildRailDepotWindow(&_build_depot_desc, parent); } struct BuildRailWaypointWindow : PickerWindowBase { BuildRailWaypointWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->CreateNestedTree(); NWidgetMatrix *matrix = this->GetWidget(WID_BRW_WAYPOINT_MATRIX); matrix->SetScrollbar(this->GetScrollbar(WID_BRW_SCROLL)); this->FinishInitNested(TRANSPORT_RAIL); matrix->SetCount(_waypoint_count); matrix->SetClicked(_cur_waypoint_type); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_BRW_WAYPOINT_MATRIX: /* Three blobs high and wide. */ size->width += resize->width * 2; size->height += resize->height * 2; /* Resizing in X direction only at blob size, but at pixel level in Y. */ resize->height = 1; break; case WID_BRW_WAYPOINT: size->width = ScaleGUITrad(64) + 2; size->height = ScaleGUITrad(58) + 2; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (GB(widget, 0, 16)) { case WID_BRW_WAYPOINT: { byte type = GB(widget, 16, 16); const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(type); DrawWaypointSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), type, _cur_railtype); if (!IsStationAvailable(statspec)) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); } } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (GB(widget, 0, 16)) { case WID_BRW_WAYPOINT: { byte type = GB(widget, 16, 16); this->GetWidget(WID_BRW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type); /* Check station availability callback */ const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(type); if (!IsStationAvailable(statspec)) return; _cur_waypoint_type = type; this->GetWidget(WID_BRW_WAYPOINT_MATRIX)->SetClicked(_cur_waypoint_type); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); break; } } } }; /** Nested widget definition for the build NewGRF rail waypoint window */ static const NWidgetPart _nested_build_waypoint_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WAYPOINT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT_MATRIX), SetPIP(3, 2, 3), SetScrollbar(WID_BRW_SCROLL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRW_WAYPOINT), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), SetScrollbar(WID_BRW_SCROLL), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BRW_SCROLL), NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), EndContainer(), EndContainer(), }; static WindowDesc _build_waypoint_desc( WDP_AUTO, "build_waypoint", 0, 0, WC_BUILD_WAYPOINT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_waypoint_widgets, lengthof(_nested_build_waypoint_widgets) ); static void ShowBuildWaypointPicker(Window *parent) { new BuildRailWaypointWindow(&_build_waypoint_desc, parent); } /** * Initialize rail building GUI settings */ void InitializeRailGui() { _build_depot_direction = DIAGDIR_NW; } /** * Re-initialize rail-build toolbar after toggling support for electric trains * @param disable Boolean whether electric trains are disabled (removed from the game) */ void ReinitGuiAfterToggleElrail(bool disable) { extern RailType _last_built_railtype; if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) { _last_built_railtype = _cur_railtype = RAILTYPE_RAIL; BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); if (w != NULL) w->ModifyRailType(_cur_railtype); } MarkWholeScreenDirty(); } /** Set the initial (default) railtype to use */ static void SetDefaultRailGui() { if (_local_company == COMPANY_SPECTATOR || !Company::IsValidID(_local_company)) return; extern RailType _last_built_railtype; RailType rt = (RailType)(_settings_client.gui.default_rail_type + RAILTYPE_END); if (rt == DEF_RAILTYPE_MOST_USED) { /* Find the most used rail type */ RailType count[RAILTYPE_END]; memset(count, 0, sizeof(count)); for (TileIndex t = 0; t < MapSize(); t++) { if (IsTileType(t, MP_RAILWAY) || IsLevelCrossingTile(t) || HasStationTileRail(t) || (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL)) { count[GetRailType(t)]++; } } rt = RAILTYPE_RAIL; for (RailType r = RAILTYPE_ELECTRIC; r < RAILTYPE_END; r++) { if (count[r] >= count[rt]) rt = r; } /* No rail, just get the first available one */ if (count[rt] == 0) rt = DEF_RAILTYPE_FIRST; } switch (rt) { case DEF_RAILTYPE_FIRST: rt = RAILTYPE_RAIL; while (rt < RAILTYPE_END && !HasRailtypeAvail(_local_company, rt)) rt++; break; case DEF_RAILTYPE_LAST: rt = GetBestRailtype(_local_company); break; default: break; } _last_built_railtype = _cur_railtype = rt; BuildRailToolbarWindow *w = dynamic_cast(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)); if (w != NULL) w->ModifyRailType(_cur_railtype); } /** * Updates the current signal variant used in the signal GUI * to the one adequate to current year. * @param p needed to be called when a setting changes * @return success, needed for settings */ bool ResetSignalVariant(int32 p) { SignalVariant new_variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC); if (new_variant != _cur_signal_variant) { Window *w = FindWindowById(WC_BUILD_SIGNAL, 0); if (w != NULL) { w->SetDirty(); w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? WID_BS_ELECTRIC_NORM : WID_BS_SEMAPHORE_NORM) + _cur_signal_type); } _cur_signal_variant = new_variant; } return true; } /** * Resets the rail GUI - sets default railtype to build * and resets the signal GUI */ void InitializeRailGUI() { SetDefaultRailGui(); _convert_signal_button = false; _cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type]; ResetSignalVariant(); } /** * Create a drop down list for all the rail types of the local company. * @param for_replacement Whether this list is for the replacement window. * @return The populated and sorted #DropDownList. */ DropDownList *GetRailTypeDropDownList(bool for_replacement) { RailTypes used_railtypes = RAILTYPES_NONE; /* 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; used_railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes; } /* Get the date introduced railtypes as well. */ used_railtypes = AddDateIntroducedRailTypes(used_railtypes, MAX_DAY); const Company *c = Company::Get(_local_company); DropDownList *list = new DropDownList(); RailType rt; FOR_ALL_SORTED_RAILTYPES(rt) { /* If it's not used ever, don't show it to the user. */ if (!HasBit(used_railtypes, rt)) continue; const RailtypeInfo *rti = GetRailTypeInfo(rt); StringID str = for_replacement ? rti->strings.replace_text : (rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING); DropDownListParamStringItem *item = new DropDownListParamStringItem(str, rt, !HasBit(c->avail_railtypes, rt)); item->SetParam(0, rti->strings.menu_text); item->SetParam(1, rti->max_speed); *list->Append() = item; } return list; } openttd-1.5.3/src/ai/0000755000000000000000000000000012627373441013064 5ustar rootrootopenttd-1.5.3/src/ai/ai_core.cpp0000644000000000000000000002642712627373441015204 0ustar rootroot/* $Id: ai_core.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 ai_core.cpp Implementation of AI. */ #include "../stdafx.h" #include "../core/backup_type.hpp" #include "../core/bitmath_func.hpp" #include "../company_base.h" #include "../company_func.h" #include "../network/network.h" #include "../window_func.h" #include "ai_scanner.hpp" #include "ai_instance.hpp" #include "ai_config.hpp" #include "ai_info.hpp" #include "ai.hpp" #include "../safeguards.h" /* static */ uint AI::frame_counter = 0; /* static */ AIScannerInfo *AI::scanner_info = NULL; /* static */ AIScannerLibrary *AI::scanner_library = NULL; /* static */ bool AI::CanStartNew() { /* Only allow new AIs on the server and only when that is allowed in multiplayer */ return !_networking || (_network_server && _settings_game.ai.ai_in_multiplayer); } /* static */ void AI::StartNew(CompanyID company, bool rerandomise_ai) { assert(Company::IsValidID(company)); /* Clients shouldn't start AIs */ if (_networking && !_network_server) return; AIConfig *config = AIConfig::GetConfig(company, AIConfig::SSS_FORCE_GAME); AIInfo *info = config->GetInfo(); if (info == NULL || (rerandomise_ai && config->IsRandom())) { info = AI::scanner_info->SelectRandomAI(); assert(info != NULL); /* Load default data and store the name in the settings */ config->Change(info->GetName(), -1, false, true); } config->AnchorUnchangeableSettings(); Backup cur_company(_current_company, company, FILE_LINE); Company *c = Company::Get(company); c->ai_info = info; assert(c->ai_instance == NULL); c->ai_instance = new AIInstance(); c->ai_instance->Initialize(info); cur_company.Restore(); InvalidateWindowData(WC_AI_DEBUG, 0, -1); return; } /* static */ void AI::GameLoop() { /* If we are in networking, only servers run this function, and that only if it is allowed */ if (_networking && (!_network_server || !_settings_game.ai.ai_in_multiplayer)) return; /* The speed with which AIs go, is limited by the 'competitor_speed' */ AI::frame_counter++; assert(_settings_game.difficulty.competitor_speed <= 4); if ((AI::frame_counter & ((1 << (4 - _settings_game.difficulty.competitor_speed)) - 1)) != 0) return; Backup cur_company(_current_company, FILE_LINE); const Company *c; FOR_ALL_COMPANIES(c) { if (c->is_ai) { cur_company.Change(c->index); c->ai_instance->GameLoop(); } } cur_company.Restore(); /* Occasionally collect garbage; every 255 ticks do one company. * Effectively collecting garbage once every two months per AI. */ if ((AI::frame_counter & 255) == 0) { CompanyID cid = (CompanyID)GB(AI::frame_counter, 8, 4); if (Company::IsValidAiID(cid)) Company::Get(cid)->ai_instance->CollectGarbage(); } } /* static */ uint AI::GetTick() { return AI::frame_counter; } /* static */ void AI::Stop(CompanyID company) { if (_networking && !_network_server) return; Backup cur_company(_current_company, company, FILE_LINE); Company *c = Company::Get(company); delete c->ai_instance; c->ai_instance = NULL; c->ai_info = NULL; cur_company.Restore(); InvalidateWindowData(WC_AI_DEBUG, 0, -1); DeleteWindowById(WC_AI_SETTINGS, company); } /* static */ void AI::Pause(CompanyID company) { /* The reason why dedicated servers are forbidden to execute this * command is not because it is unsafe, but because there is no way * for the server owner to unpause the script again. */ if (_network_dedicated) return; Backup cur_company(_current_company, company, FILE_LINE); Company::Get(company)->ai_instance->Pause(); cur_company.Restore(); } /* static */ void AI::Unpause(CompanyID company) { Backup cur_company(_current_company, company, FILE_LINE); Company::Get(company)->ai_instance->Unpause(); cur_company.Restore(); } /* static */ bool AI::IsPaused(CompanyID company) { Backup cur_company(_current_company, company, FILE_LINE); bool paused = Company::Get(company)->ai_instance->IsPaused(); cur_company.Restore(); return paused; } /* static */ void AI::KillAll() { /* It might happen there are no companies .. than we have nothing to loop */ if (Company::GetPoolSize() == 0) return; const Company *c; FOR_ALL_COMPANIES(c) { if (c->is_ai) AI::Stop(c->index); } } /* static */ void AI::Initialize() { if (AI::scanner_info != NULL) AI::Uninitialize(true); AI::frame_counter = 0; if (AI::scanner_info == NULL) { TarScanner::DoScan(TarScanner::AI); AI::scanner_info = new AIScannerInfo(); AI::scanner_info->Initialize(); AI::scanner_library = new AIScannerLibrary(); AI::scanner_library->Initialize(); } } /* static */ void AI::Uninitialize(bool keepConfig) { AI::KillAll(); if (keepConfig) { /* Run a rescan, which indexes all AIInfos again, and check if we can * still load all the AIS, while keeping the configs in place */ Rescan(); } else { delete AI::scanner_info; delete AI::scanner_library; AI::scanner_info = NULL; AI::scanner_library = NULL; for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (_settings_game.ai_config[c] != NULL) { delete _settings_game.ai_config[c]; _settings_game.ai_config[c] = NULL; } if (_settings_newgame.ai_config[c] != NULL) { delete _settings_newgame.ai_config[c]; _settings_newgame.ai_config[c] = NULL; } } } } /* static */ void AI::ResetConfig() { /* Check for both newgame as current game if we can reload the AIInfo inside * the AIConfig. If not, remove the AI from the list (which will assign * a random new AI on reload). */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (_settings_game.ai_config[c] != NULL && _settings_game.ai_config[c]->HasScript()) { if (!_settings_game.ai_config[c]->ResetInfo(true)) { DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_game.ai_config[c]->GetName()); _settings_game.ai_config[c]->Change(NULL); if (Company::IsValidAiID(c)) { /* The code belonging to an already running AI was deleted. We can only do * one thing here to keep everything sane and that is kill the AI. After * killing the offending AI we start a random other one in it's place, just * like what would happen if the AI was missing during loading. */ AI::Stop(c); AI::StartNew(c, false); } } else if (Company::IsValidAiID(c)) { /* Update the reference in the Company struct. */ Company::Get(c)->ai_info = _settings_game.ai_config[c]->GetInfo(); } } if (_settings_newgame.ai_config[c] != NULL && _settings_newgame.ai_config[c]->HasScript()) { if (!_settings_newgame.ai_config[c]->ResetInfo(false)) { DEBUG(script, 0, "After a reload, the AI by the name '%s' was no longer found, and removed from the list.", _settings_newgame.ai_config[c]->GetName()); _settings_newgame.ai_config[c]->Change(NULL); } } } } /* static */ void AI::NewEvent(CompanyID company, ScriptEvent *event) { /* AddRef() and Release() need to be called at least once, so do it here */ event->AddRef(); /* Clients should ignore events */ if (_networking && !_network_server) { event->Release(); return; } /* Only AIs can have an event-queue */ if (!Company::IsValidAiID(company)) { event->Release(); return; } /* Queue the event */ Backup cur_company(_current_company, company, FILE_LINE); Company::Get(_current_company)->ai_instance->InsertEvent(event); cur_company.Restore(); event->Release(); } /* static */ void AI::BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company) { /* AddRef() and Release() need to be called at least once, so do it here */ event->AddRef(); /* Clients should ignore events */ if (_networking && !_network_server) { event->Release(); return; } /* Try to send the event to all AIs */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (c != skip_company) AI::NewEvent(c, event); } event->Release(); } /* static */ void AI::Save(CompanyID company) { if (!_networking || _network_server) { Company *c = Company::GetIfValid(company); assert(c != NULL && c->ai_instance != NULL); Backup cur_company(_current_company, company, FILE_LINE); c->ai_instance->Save(); cur_company.Restore(); } else { AIInstance::SaveEmpty(); } } /* static */ void AI::Load(CompanyID company, int version) { if (!_networking || _network_server) { Company *c = Company::GetIfValid(company); assert(c != NULL && c->ai_instance != NULL); Backup cur_company(_current_company, company, FILE_LINE); c->ai_instance->Load(version); cur_company.Restore(); } else { /* Read, but ignore, the load data */ AIInstance::LoadEmpty(); } } /* static */ int AI::GetStartNextTime() { /* Find the first company which doesn't exist yet */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (!Company::IsValidID(c)) return AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->GetSetting("start_date"); } /* Currently no AI can be started, check again in a year. */ return DAYS_IN_YEAR; } /* static */ char *AI::GetConsoleList(char *p, const char *last, bool newest_only) { return AI::scanner_info->GetConsoleList(p, last, newest_only); } /* static */ char *AI::GetConsoleLibraryList(char *p, const char *last) { return AI::scanner_library->GetConsoleList(p, last, true); } /* static */ const ScriptInfoList *AI::GetInfoList() { return AI::scanner_info->GetInfoList(); } /* static */ const ScriptInfoList *AI::GetUniqueInfoList() { return AI::scanner_info->GetUniqueInfoList(); } /* static */ AIInfo *AI::FindInfo(const char *name, int version, bool force_exact_match) { return AI::scanner_info->FindInfo(name, version, force_exact_match); } /* static */ AILibrary *AI::FindLibrary(const char *library, int version) { return AI::scanner_library->FindLibrary(library, version); } /* static */ void AI::Rescan() { TarScanner::DoScan(TarScanner::AI); AI::scanner_info->RescanDir(); AI::scanner_library->RescanDir(); ResetConfig(); InvalidateWindowData(WC_AI_LIST, 0, 1); SetWindowClassesDirty(WC_AI_DEBUG); InvalidateWindowClassesData(WC_AI_SETTINGS); } #if defined(ENABLE_NETWORK) /** * Check whether we have an AI (library) with the exact characteristics as ci. * @param ci the characteristics to search on (shortname and md5sum) * @param md5sum whether to check the MD5 checksum * @return true iff we have an AI (library) matching. */ /* static */ bool AI::HasAI(const ContentInfo *ci, bool md5sum) { return AI::scanner_info->HasScript(ci, md5sum); } /* static */ bool AI::HasAILibrary(const ContentInfo *ci, bool md5sum) { return AI::scanner_library->HasScript(ci, md5sum); } #endif /* defined(ENABLE_NETWORK) */ /* static */ AIScannerInfo *AI::GetScannerInfo() { return AI::scanner_info; } /* static */ AIScannerLibrary *AI::GetScannerLibrary() { return AI::scanner_library; } openttd-1.5.3/src/ai/ai_gui.cpp0000644000000000000000000016171512627373441015040 0ustar rootroot/* $Id: ai_gui.cpp 27187 2015-03-15 12:19:58Z frosch $ */ /* * 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 ai_gui.cpp %Window for configuring the AIs */ #include "../stdafx.h" #include "../table/sprites.h" #include "../error.h" #include "../settings_gui.h" #include "../querystring_gui.h" #include "../stringfilter_type.h" #include "../company_base.h" #include "../company_gui.h" #include "../strings_func.h" #include "../window_func.h" #include "../gfx_func.h" #include "../command_func.h" #include "../network/network.h" #include "../settings_func.h" #include "../network/network_content.h" #include "../textfile_gui.h" #include "../widgets/dropdown_type.h" #include "../widgets/dropdown_func.h" #include "../hotkeys.h" #include "ai.hpp" #include "ai_gui.hpp" #include "../script/api/script_log.hpp" #include "ai_config.hpp" #include "ai_info.hpp" #include "ai_instance.hpp" #include "../game/game.hpp" #include "../game/game_config.hpp" #include "../game/game_info.hpp" #include "../game/game_instance.hpp" #include "table/strings.h" #include #include "../safeguards.h" static ScriptConfig *GetConfig(CompanyID slot) { if (slot == OWNER_DEITY) return GameConfig::GetConfig(); return AIConfig::GetConfig(slot); } /** * Window that let you choose an available AI. */ struct AIListWindow : public Window { const ScriptInfoList *info_list; ///< The list of Scripts. int selected; ///< The currently selected Script. CompanyID slot; ///< The company we're selecting a new Script for. int line_height; ///< Height of a row in the matrix widget. Scrollbar *vscroll; ///< Cache of the vertical scrollbar. /** * Constructor for the window. * @param desc The description of the window. * @param slot The company we're changing the AI for. */ AIListWindow(WindowDesc *desc, CompanyID slot) : Window(desc), slot(slot) { if (slot == OWNER_DEITY) { this->info_list = Game::GetUniqueInfoList(); } else { this->info_list = AI::GetUniqueInfoList(); } this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_AIL_SCROLLBAR); this->FinishInitNested(); // Initializes 'this->line_height' as side effect. this->vscroll->SetCount((int)this->info_list->size() + 1); /* Try if we can find the currently selected AI */ this->selected = -1; if (GetConfig(slot)->HasScript()) { ScriptInfo *info = GetConfig(slot)->GetInfo(); int i = 0; for (ScriptInfoList::const_iterator it = this->info_list->begin(); it != this->info_list->end(); it++, i++) { if ((*it).second == info) { this->selected = i; break; } } } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AIL_CAPTION: SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_LIST_CAPTION_GAMESCRIPT : STR_AI_LIST_CAPTION_AI); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_AIL_LIST) { this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->width = 1; resize->height = this->line_height; size->height = 5 * this->line_height; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_AIL_LIST: { /* Draw a list of all available AIs. */ int y = this->GetWidget(WID_AIL_LIST)->pos_y; /* First AI in the list is hardcoded to random */ if (this->vscroll->IsVisible(0)) { DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_LEFT, y + WD_MATRIX_TOP, this->slot == OWNER_DEITY ? STR_AI_CONFIG_NONE : STR_AI_CONFIG_RANDOM_AI, this->selected == -1 ? TC_WHITE : TC_ORANGE); y += this->line_height; } ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 1; it != this->info_list->end(); i++, it++) { if (this->vscroll->IsVisible(i)) { DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, (*it).second->GetName(), (this->selected == i - 1) ? TC_WHITE : TC_ORANGE); y += this->line_height; } } break; } case WID_AIL_INFO_BG: { AIInfo *selected_info = NULL; ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 1; selected_info == NULL && it != this->info_list->end(); i++, it++) { if (this->selected == i - 1) selected_info = static_cast((*it).second); } /* Some info about the currently selected AI. */ if (selected_info != NULL) { int y = r.top + WD_FRAMERECT_TOP; SetDParamStr(0, selected_info->GetAuthor()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_AUTHOR); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; SetDParam(0, selected_info->GetVersion()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_VERSION); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; if (selected_info->GetURL() != NULL) { SetDParamStr(0, selected_info->GetURL()); DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_AI_LIST_URL); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; } SetDParamStr(0, selected_info->GetDescription()); DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_FRAMERECT_BOTTOM, STR_JUST_RAW_STRING, TC_WHITE); } break; } } } /** * Changes the AI of the current slot. */ void ChangeAI() { if (this->selected == -1) { GetConfig(slot)->Change(NULL); } else { ScriptInfoList::const_iterator it = this->info_list->begin(); for (int i = 0; i < this->selected; i++) it++; GetConfig(slot)->Change((*it).second->GetName(), (*it).second->GetVersion()); } InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_AI); InvalidateWindowClassesData(WC_AI_SETTINGS); DeleteWindowByClass(WC_QUERY_STRING); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_AIL_LIST: { // Select one of the AIs int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_AIL_LIST, 0, this->line_height) - 1; if (sel < (int)this->info_list->size()) { this->selected = sel; this->SetDirty(); if (click_count > 1) { this->ChangeAI(); delete this; } } break; } case WID_AIL_ACCEPT: { this->ChangeAI(); delete this; break; } case WID_AIL_CANCEL: delete this; break; } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_AIL_LIST); } /** * 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 (_game_mode == GM_NORMAL && Company::IsValidID(this->slot)) { delete this; return; } if (!gui_scope) return; this->vscroll->SetCount((int)this->info_list->size() + 1); /* selected goes from -1 .. length of ai list - 1. */ this->selected = min(this->selected, this->vscroll->GetCount() - 2); } }; /** Widgets for the AI list window. */ static const NWidgetPart _nested_ai_list_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_AIL_CAPTION), SetDataTip(STR_AI_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIL_LIST), SetMinimalSize(188, 112), SetFill(1, 1), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_AI_LIST_TOOLTIP), SetScrollbar(WID_AIL_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIL_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIL_INFO_BG), SetMinimalTextLines(8, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIL_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_LIST_ACCEPT, STR_AI_LIST_ACCEPT_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_LIST_CANCEL, STR_AI_LIST_CANCEL_TOOLTIP), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), EndContainer(), }; /** Window definition for the ai list window. */ static WindowDesc _ai_list_desc( WDP_CENTER, "settings_script_list", 200, 234, WC_AI_LIST, WC_NONE, 0, _nested_ai_list_widgets, lengthof(_nested_ai_list_widgets) ); /** * Open the AI list window to chose an AI for the given company slot. * @param slot The slot to change the AI of. */ static void ShowAIListWindow(CompanyID slot) { DeleteWindowByClass(WC_AI_LIST); new AIListWindow(&_ai_list_desc, slot); } /** * Window for settings the parameters of an AI. */ struct AISettingsWindow : public Window { CompanyID slot; ///< The currently show company's setting. ScriptConfig *ai_config; ///< The configuration we're modifying. int clicked_button; ///< The button we clicked. bool clicked_increase; ///< Whether we clicked the increase or decrease button. bool clicked_dropdown; ///< Whether the dropdown is open. bool closing_dropdown; ///< True, if the dropdown list is currently closing. int timeout; ///< Timeout for unclicking the button. int clicked_row; ///< The clicked row of settings. int line_height; ///< Height of a row in the matrix widget. Scrollbar *vscroll; ///< Cache of the vertical scrollbar. typedef std::vector VisibleSettingsList; VisibleSettingsList visible_settings; ///< List of visible AI settings /** * Constructor for the window. * @param desc The description of the window. * @param slot The company we're changing the settings for. */ AISettingsWindow(WindowDesc *desc, CompanyID slot) : Window(desc), slot(slot), clicked_button(-1), clicked_dropdown(false), closing_dropdown(false), timeout(0) { this->ai_config = GetConfig(slot); this->RebuildVisibleSettings(); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_AIS_SCROLLBAR); this->FinishInitNested(slot); // Initializes 'this->line_height' as side effect. this->SetWidgetDisabledState(WID_AIS_RESET, _game_mode != GM_MENU && Company::IsValidID(this->slot)); this->vscroll->SetCount((int)this->visible_settings.size()); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AIS_CAPTION: SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_SETTINGS_CAPTION_GAMESCRIPT : STR_AI_SETTINGS_CAPTION_AI); break; } } /** * Rebuilds the list of visible settings. AI settings with the flag * AICONFIG_AI_DEVELOPER set will only be visible if the game setting * gui.ai_developer_tools is enabled. */ void RebuildVisibleSettings() { visible_settings.clear(); ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); for (; it != this->ai_config->GetConfigList()->end(); it++) { bool no_hide = (it->flags & SCRIPTCONFIG_DEVELOPER) == 0; if (no_hide || _settings_client.gui.ai_developer_tools) { visible_settings.push_back(&(*it)); } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_AIS_BACKGROUND) { this->line_height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->width = 1; resize->height = this->line_height; size->height = 5 * this->line_height; } } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_AIS_BACKGROUND) return; ScriptConfig *config = this->ai_config; VisibleSettingsList::const_iterator it = this->visible_settings.begin(); int i = 0; for (; !this->vscroll->IsVisible(i); i++) it++; bool rtl = _current_text_dir == TD_RTL; uint buttons_left = rtl ? r.right - SETTING_BUTTON_WIDTH - 3 : r.left + 4; uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : SETTING_BUTTON_WIDTH + 8); uint text_right = r.right - (rtl ? SETTING_BUTTON_WIDTH + 8 : WD_FRAMERECT_RIGHT); int y = r.top; int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2; int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; for (; this->vscroll->IsVisible(i) && it != visible_settings.end(); i++, it++) { const ScriptConfigItem &config_item = **it; int current_value = config->GetSetting((config_item).name); bool editable = _game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot)) || (config_item.flags & SCRIPTCONFIG_INGAME) != 0; StringID str; TextColour colour; uint idx = 0; if (StrEmpty(config_item.description)) { if (!strcmp(config_item.name, "start_date")) { /* Build-in translation */ str = STR_AI_SETTINGS_START_DELAY; colour = TC_LIGHT_BLUE; } else { str = STR_JUST_STRING; colour = TC_ORANGE; } } else { str = STR_AI_SETTINGS_SETTING; colour = TC_LIGHT_BLUE; SetDParamStr(idx++, config_item.description); } if ((config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0) { DrawBoolButton(buttons_left, y + button_y_offset, current_value != 0, editable); SetDParam(idx++, current_value == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON); } else { if (config_item.complete_labels) { DrawDropDownButton(buttons_left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && clicked_dropdown, editable); } else { DrawArrowButtons(buttons_left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, editable && current_value > config_item.min_value, editable && current_value < config_item.max_value); } if (config_item.labels != NULL && config_item.labels->Contains(current_value)) { SetDParam(idx++, STR_JUST_RAW_STRING); SetDParamStr(idx++, config_item.labels->Find(current_value)->second); } else { SetDParam(idx++, STR_JUST_INT); SetDParam(idx++, current_value); } } DrawString(text_left, text_right, y + text_y_offset, str, colour); y += this->line_height; } } virtual void OnPaint() { if (this->closing_dropdown) { this->closing_dropdown = false; this->clicked_dropdown = false; } this->DrawWidgets(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_AIS_BACKGROUND: { const NWidgetBase *wid = this->GetWidget(WID_AIS_BACKGROUND); int num = (pt.y - wid->pos_y) / this->line_height + this->vscroll->GetPosition(); if (num >= (int)this->visible_settings.size()) break; VisibleSettingsList::const_iterator it = this->visible_settings.begin(); for (int i = 0; i < num; i++) it++; const ScriptConfigItem config_item = **it; if (_game_mode == GM_NORMAL && ((this->slot == OWNER_DEITY) || Company::IsValidID(this->slot)) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return; if (this->clicked_row != num) { DeleteChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); this->clicked_row = num; this->clicked_dropdown = false; } bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0; int x = pt.x - wid->pos_x; if (_current_text_dir == TD_RTL) x = wid->current_x - 1 - x; x -= 4; /* One of the arrows is clicked (or green/red rect in case of bool value) */ int old_val = this->ai_config->GetSetting(config_item.name); if (!bool_item && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && config_item.complete_labels) { if (this->clicked_dropdown) { /* unclick the dropdown */ HideDropDownMenu(this); this->clicked_dropdown = false; this->closing_dropdown = false; } else { const NWidgetBase *wid = this->GetWidget(WID_AIS_BACKGROUND); int rel_y = (pt.y - (int)wid->pos_y) % this->line_height; Rect wi_rect; wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x); wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1; wi_rect.top = pt.y - rel_y + (this->line_height - SETTING_BUTTON_HEIGHT) / 2; wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1; /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */ if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) { this->clicked_dropdown = true; this->closing_dropdown = false; DropDownList *list = new DropDownList(); for (int i = config_item.min_value; i <= config_item.max_value; i++) { *list->Append() = new DropDownListCharStringItem(config_item.labels->Find(i)->second, i, false); } ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true); } } } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) { int new_val = old_val; if (bool_item) { new_val = !new_val; } else if (x >= SETTING_BUTTON_WIDTH / 2) { /* Increase button clicked */ new_val += config_item.step_size; if (new_val > config_item.max_value) new_val = config_item.max_value; this->clicked_increase = true; } else { /* Decrease button clicked */ new_val -= config_item.step_size; if (new_val < config_item.min_value) new_val = config_item.min_value; this->clicked_increase = false; } if (new_val != old_val) { this->ai_config->SetSetting(config_item.name, new_val); this->clicked_button = num; this->timeout = 5; } } else if (!bool_item && !config_item.complete_labels) { /* Display a query box so users can enter a custom value. */ SetDParam(0, old_val); ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE); } this->SetDirty(); break; } case WID_AIS_ACCEPT: delete this; break; case WID_AIS_RESET: if (_game_mode == GM_MENU || !Company::IsValidID(this->slot)) { this->ai_config->ResetSettings(); this->SetDirty(); } break; } } virtual void OnQueryTextFinished(char *str) { if (StrEmpty(str)) return; ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); for (int i = 0; i < this->clicked_row; i++) it++; if (_game_mode == GM_NORMAL && ((this->slot == OWNER_DEITY) || Company::IsValidID(this->slot)) && (it->flags & SCRIPTCONFIG_INGAME) == 0) return; int32 value = atoi(str); this->ai_config->SetSetting((*it).name, value); this->SetDirty(); } virtual void OnDropdownSelect(int widget, int index) { assert(this->clicked_dropdown); ScriptConfigItemList::const_iterator it = this->ai_config->GetConfigList()->begin(); for (int i = 0; i < this->clicked_row; i++) it++; if (_game_mode == GM_NORMAL && ((this->slot == OWNER_DEITY) || Company::IsValidID(this->slot)) && (it->flags & SCRIPTCONFIG_INGAME) == 0) return; this->ai_config->SetSetting((*it).name, index); this->SetDirty(); } virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) { /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether * the same dropdown button was clicked again, and then not open the dropdown again. * So, we only remember that it was closed, and process it on the next OnPaint, which is * after OnClick. */ assert(this->clicked_dropdown); this->closing_dropdown = true; this->SetDirty(); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_AIS_BACKGROUND); } virtual void OnTick() { if (--this->timeout == 0) { this->clicked_button = -1; this->SetDirty(); } } /** * 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) { this->RebuildVisibleSettings(); } }; /** Widgets for the AI settings window. */ static const NWidgetPart _nested_ai_settings_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_AIS_CAPTION), SetDataTip(STR_AI_SETTINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIS_BACKGROUND), SetMinimalSize(188, 182), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_AIS_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIS_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIS_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_AIS_RESET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_SETTINGS_RESET, STR_NULL), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), EndContainer(), }; /** Window definition for the AI settings window. */ static WindowDesc _ai_settings_desc( WDP_CENTER, "settings_script", 500, 208, WC_AI_SETTINGS, WC_NONE, 0, _nested_ai_settings_widgets, lengthof(_nested_ai_settings_widgets) ); /** * Open the AI settings window to change the AI settings for an AI. * @param slot The CompanyID of the AI to change the settings. */ static void ShowAISettingsWindow(CompanyID slot) { DeleteWindowByClass(WC_AI_LIST); DeleteWindowByClass(WC_AI_SETTINGS); new AISettingsWindow(&_ai_settings_desc, slot); } /** Window for displaying the textfile of a AI. */ struct ScriptTextfileWindow : public TextfileWindow { CompanyID slot; ///< View the textfile of this CompanyID slot. ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot) { const char *textfile = GetConfig(slot)->GetTextfile(file_type, slot); this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR); } /* virtual */ void SetStringParameters(int widget) const { if (widget == WID_TF_CAPTION) { SetDParam(0, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI); SetDParamStr(1, GetConfig(slot)->GetName()); } } }; /** * Open the AI version of the textfile window. * @param file_type The type of textfile to display. * @param slot The slot the Script is using. */ void ShowScriptTextfileWindow(TextfileType file_type, CompanyID slot) { DeleteWindowByClass(WC_TEXTFILE); new ScriptTextfileWindow(file_type, slot); } /** Widgets for the configure AI window. */ static const NWidgetPart _nested_ai_config_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIC_BACKGROUND), NWidget(NWID_VERTICAL), SetPIP(4, 4, 4), NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE), SetFill(0, 1), SetDataTip(AWV_DECREASE, STR_NULL), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE), SetFill(0, 1), SetDataTip(AWV_INCREASE, STR_NULL), NWidget(NWID_SPACER), SetMinimalSize(6, 0), NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS, STR_NULL), SetFill(1, 0), SetPadding(1, 0, 0, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP), EndContainer(), EndContainer(), NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_AI, STR_NULL), SetPadding(0, 5, 0, 5), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_LIST), SetMinimalSize(288, 112), SetFill(1, 0), SetMatrixDataTip(1, 8, STR_AI_CONFIG_AILIST_TOOLTIP), SetScrollbar(WID_AIC_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_AIC_SCROLLBAR), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 9), NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_GAMESCRIPT, STR_NULL), SetPadding(0, 5, 4, 5), NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CHANGE, STR_AI_CONFIG_CHANGE_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CLOSE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 0), SetMinimalSize(279, 12), SetPadding(0, 7, 9, 7), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), EndContainer(), }; /** Window definition for the configure AI window. */ static WindowDesc _ai_config_desc( WDP_CENTER, "settings_script_config", 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, _nested_ai_config_widgets, lengthof(_nested_ai_config_widgets) ); /** * Window to configure which AIs will start. */ struct AIConfigWindow : public Window { CompanyID selected_slot; ///< The currently selected AI slot or \c INVALID_COMPANY. int line_height; ///< Height of a single AI-name line. Scrollbar *vscroll; ///< Cache of the vertical scrollbar. AIConfigWindow() : Window(&_ai_config_desc) { this->InitNested(WN_GAME_OPTIONS_AI); // Initializes 'this->line_height' as a side effect. this->vscroll = this->GetScrollbar(WID_AIC_SCROLLBAR); this->selected_slot = INVALID_COMPANY; NWidgetCore *nwi = this->GetWidget(WID_AIC_LIST); this->vscroll->SetCapacity(nwi->current_y / this->line_height); this->vscroll->SetCount(MAX_COMPANIES); this->OnInvalidateData(0); } ~AIConfigWindow() { DeleteWindowByClass(WC_AI_LIST); DeleteWindowByClass(WC_AI_SETTINGS); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AIC_NUMBER: SetDParam(0, GetGameSettings().difficulty.max_no_competitors); break; case WID_AIC_CHANGE: switch (selected_slot) { case OWNER_DEITY: SetDParam(0, STR_AI_CONFIG_CHANGE_GAMESCRIPT); break; case INVALID_COMPANY: SetDParam(0, STR_AI_CONFIG_CHANGE_NONE); break; default: SetDParam(0, STR_AI_CONFIG_CHANGE_AI); break; } break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_AIC_GAMELIST: this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 1 * this->line_height; break; case WID_AIC_LIST: this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 8 * this->line_height; break; } } /** * Can the AI config in the given company slot be edited? * @param slot The slot to query. * @return True if and only if the given AI Config slot can e edited. */ static bool IsEditable(CompanyID slot) { if (slot == OWNER_DEITY) return _game_mode != GM_NORMAL || Game::GetInstance() != NULL; if (_game_mode != GM_NORMAL) { return slot > 0 && slot <= GetGameSettings().difficulty.max_no_competitors; } if (Company::IsValidID(slot) || slot < 0) return false; int max_slot = GetGameSettings().difficulty.max_no_competitors; for (CompanyID cid = COMPANY_FIRST; cid < (CompanyID)max_slot && cid < MAX_COMPANIES; cid++) { if (Company::IsValidHumanID(cid)) max_slot++; } return slot < max_slot; } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_AIC_GAMELIST: { StringID text = STR_AI_CONFIG_NONE; if (GameConfig::GetConfig()->GetInfo() != NULL) { SetDParamStr(0, GameConfig::GetConfig()->GetInfo()->GetName()); text = STR_JUST_RAW_STRING; } DrawString(r.left + 10, r.right - 10, r.top + WD_MATRIX_TOP, text, (this->selected_slot == OWNER_DEITY) ? TC_WHITE : (IsEditable(OWNER_DEITY) ? TC_ORANGE : TC_SILVER)); break; } case WID_AIC_LIST: { int y = r.top; for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < MAX_COMPANIES; i++) { StringID text; if ((_game_mode != GM_NORMAL && i == 0) || (_game_mode == GM_NORMAL && Company::IsValidHumanID(i))) { text = STR_AI_CONFIG_HUMAN_PLAYER; } else if (AIConfig::GetConfig((CompanyID)i)->GetInfo() != NULL) { SetDParamStr(0, AIConfig::GetConfig((CompanyID)i)->GetInfo()->GetName()); text = STR_JUST_RAW_STRING; } else { text = STR_AI_CONFIG_RANDOM_AI; } DrawString(r.left + 10, r.right - 10, y + WD_MATRIX_TOP, text, (this->selected_slot == i) ? TC_WHITE : (IsEditable((CompanyID)i) ? TC_ORANGE : TC_SILVER)); y += this->line_height; } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget >= WID_AIC_TEXTFILE && widget < WID_AIC_TEXTFILE + TFT_END) { if (this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot) == NULL) return; ShowScriptTextfileWindow((TextfileType)(widget - WID_AIC_TEXTFILE), this->selected_slot); return; } switch (widget) { case WID_AIC_DECREASE: case WID_AIC_INCREASE: { int new_value; if (widget == WID_AIC_DECREASE) { new_value = max(0, GetGameSettings().difficulty.max_no_competitors - 1); } else { new_value = min(MAX_COMPANIES - 1, GetGameSettings().difficulty.max_no_competitors + 1); } IConsoleSetSetting("difficulty.max_no_competitors", new_value); this->InvalidateData(); break; } case WID_AIC_GAMELIST: { this->selected_slot = OWNER_DEITY; this->InvalidateData(); if (click_count > 1 && this->selected_slot != INVALID_COMPANY && _game_mode != GM_NORMAL) ShowAIListWindow((CompanyID)this->selected_slot); break; } case WID_AIC_LIST: { // Select a slot this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height); this->InvalidateData(); if (click_count > 1 && this->selected_slot != INVALID_COMPANY) ShowAIListWindow((CompanyID)this->selected_slot); break; } case WID_AIC_MOVE_UP: if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot - 1))) { Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot - 1]); this->selected_slot--; this->vscroll->ScrollTowards(this->selected_slot); this->InvalidateData(); } break; case WID_AIC_MOVE_DOWN: if (IsEditable(this->selected_slot) && IsEditable((CompanyID)(this->selected_slot + 1))) { Swap(GetGameSettings().ai_config[this->selected_slot], GetGameSettings().ai_config[this->selected_slot + 1]); this->selected_slot++; this->vscroll->ScrollTowards(this->selected_slot); this->InvalidateData(); } break; case WID_AIC_CHANGE: // choose other AI ShowAIListWindow((CompanyID)this->selected_slot); break; case WID_AIC_CONFIGURE: // change the settings for an AI ShowAISettingsWindow((CompanyID)this->selected_slot); break; case WID_AIC_CLOSE: delete this; break; case WID_AIC_CONTENT_DOWNLOAD: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else { #if defined(ENABLE_NETWORK) ShowNetworkContentListWindow(NULL, CONTENT_TYPE_AI); _network_content_client.RequestContentList(CONTENT_TYPE_GAME); #endif } 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 (!IsEditable(this->selected_slot)) { this->selected_slot = INVALID_COMPANY; } if (!gui_scope) return; this->SetWidgetDisabledState(WID_AIC_DECREASE, GetGameSettings().difficulty.max_no_competitors == 0); this->SetWidgetDisabledState(WID_AIC_INCREASE, GetGameSettings().difficulty.max_no_competitors == MAX_COMPANIES - 1); this->SetWidgetDisabledState(WID_AIC_CHANGE, (this->selected_slot == OWNER_DEITY && _game_mode == GM_NORMAL) || this->selected_slot == INVALID_COMPANY); this->SetWidgetDisabledState(WID_AIC_CONFIGURE, this->selected_slot == INVALID_COMPANY || GetConfig(this->selected_slot)->GetConfigList()->size() == 0); this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == OWNER_DEITY || this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot - 1))); this->SetWidgetDisabledState(WID_AIC_MOVE_DOWN, this->selected_slot == OWNER_DEITY || this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot + 1))); for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { this->SetWidgetDisabledState(WID_AIC_TEXTFILE + tft, this->selected_slot == INVALID_COMPANY || (GetConfig(this->selected_slot)->GetTextfile(tft, this->selected_slot) == NULL)); } } }; /** Open the AI config window. */ void ShowAIConfigWindow() { DeleteWindowByClass(WC_GAME_OPTIONS); new AIConfigWindow(); } /** * Set the widget colour of a button based on the * state of the script. (dead or alive) * @param button the button to update. * @param dead true if the script is dead, otherwise false. * @param paused true if the script is paused, otherwise false. * @return true if the colour was changed and the window need to be marked as dirty. */ static bool SetScriptButtonColour(NWidgetCore &button, bool dead, bool paused) { /* Dead scripts are indicated with red background and * paused scripts are indicated with yellow background. */ Colours colour = dead ? COLOUR_RED : (paused ? COLOUR_YELLOW : COLOUR_GREY); if (button.colour != colour) { button.colour = colour; return true; } return false; } /** * Window with everything an AI prints via ScriptLog. */ struct AIDebugWindow : public Window { static const int top_offset; ///< Offset of the text at the top of the WID_AID_LOG_PANEL. static const int bottom_offset; ///< Offset of the text at the bottom of the WID_AID_LOG_PANEL. static const uint MAX_BREAK_STR_STRING_LENGTH = 256; ///< Maximum length of the break string. static CompanyID ai_debug_company; ///< The AI that is (was last) being debugged. int redraw_timer; ///< Timer for redrawing the window, otherwise it'll happen every tick. int last_vscroll_pos; ///< Last position of the scrolling. bool autoscroll; ///< Whether automatically scrolling should be enabled or not. bool show_break_box; ///< Whether the break/debug box is visible. static bool break_check_enabled; ///< Stop an AI when it prints a matching string static char break_string[MAX_BREAK_STR_STRING_LENGTH]; ///< The string to match to the AI output QueryString break_editbox; ///< Break editbox static StringFilter break_string_filter; ///< Log filter for break. static bool case_sensitive_break_check; ///< Is the matching done case-sensitive int highlight_row; ///< The output row that matches the given string, or -1 Scrollbar *vscroll; ///< Cache of the vertical scrollbar. ScriptLog::LogData *GetLogPointer() const { if (ai_debug_company == OWNER_DEITY) return (ScriptLog::LogData *)Game::GetInstance()->GetLogPointer(); return (ScriptLog::LogData *)Company::Get(ai_debug_company)->ai_instance->GetLogPointer(); } /** * Check whether the currently selected AI/GS is dead. * @return true if dead. */ bool IsDead() const { if (ai_debug_company == OWNER_DEITY) { GameInstance *game = Game::GetInstance(); return game == NULL || game->IsDead(); } return !Company::IsValidAiID(ai_debug_company) || Company::Get(ai_debug_company)->ai_instance->IsDead(); } /** * Check whether a company is a valid AI company or GS. * @param company Company to check for validity. * @return true if company is valid for debugging. */ bool IsValidDebugCompany(CompanyID company) const { switch (company) { case INVALID_COMPANY: return false; case OWNER_DEITY: return Game::GetInstance() != NULL; default: return Company::IsValidAiID(company); } } /** * Ensure that \c ai_debug_company refers to a valid AI company or GS, or is set to #INVALID_COMPANY. * If no valid company is selected, it selects the first valid AI or GS if any. */ void SelectValidDebugCompany() { /* Check if the currently selected company is still active. */ if (this->IsValidDebugCompany(ai_debug_company)) return; ai_debug_company = INVALID_COMPANY; const Company *c; FOR_ALL_COMPANIES(c) { if (c->is_ai) { ChangeToAI(c->index); return; } } /* If no AI is available, see if there is a game script. */ if (Game::GetInstance() != NULL) ChangeToAI(OWNER_DEITY); } /** * Constructor for the window. * @param desc The description of the window. * @param number The window number (actually unused). */ AIDebugWindow(WindowDesc *desc, WindowNumber number) : Window(desc), break_editbox(MAX_BREAK_STR_STRING_LENGTH) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_AID_SCROLLBAR); this->show_break_box = _settings_client.gui.ai_developer_tools; this->GetWidget(WID_AID_BREAK_STRING_WIDGETS)->SetDisplayedPlane(this->show_break_box ? 0 : SZSP_HORIZONTAL); this->FinishInitNested(number); if (!this->show_break_box) break_check_enabled = false; this->last_vscroll_pos = 0; this->autoscroll = true; this->highlight_row = -1; this->querystrings[WID_AID_BREAK_STR_EDIT_BOX] = &this->break_editbox; SetWidgetsDisabledState(!this->show_break_box, WID_AID_BREAK_STR_ON_OFF_BTN, WID_AID_BREAK_STR_EDIT_BOX, WID_AID_MATCH_CASE_BTN, WIDGET_LIST_END); /* Restore the break string value from static variable */ this->break_editbox.text.Assign(this->break_string); this->SelectValidDebugCompany(); this->InvalidateData(-1); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_AID_LOG_PANEL) { resize->height = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; size->height = 14 * resize->height + this->top_offset + this->bottom_offset; } } virtual void OnPaint() { this->SelectValidDebugCompany(); /* Draw standard stuff */ this->DrawWidgets(); if (this->IsShaded()) return; // Don't draw anything when the window is shaded. bool dirty = false; /* Paint the company icons */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { NWidgetCore *button = this->GetWidget(i + WID_AID_COMPANY_BUTTON_START); bool valid = Company::IsValidAiID(i); /* Check whether the validity of the company changed */ dirty |= (button->IsDisabled() == valid); /* Mark dead/paused AIs by setting the background colour. */ bool dead = valid && Company::Get(i)->ai_instance->IsDead(); bool paused = valid && Company::Get(i)->ai_instance->IsPaused(); /* Re-paint if the button was updated. * (note that it is intentional that SetScriptButtonColour is always called) */ dirty |= SetScriptButtonColour(*button, dead, paused); /* Draw company icon only for valid AI companies */ if (!valid) continue; byte offset = (i == ai_debug_company) ? 1 : 0; DrawCompanyIcon(i, button->pos_x + button->current_x / 2 - 7 + offset, this->GetWidget(WID_AID_COMPANY_BUTTON_START + i)->pos_y + 2 + offset); } /* Set button colour for Game Script. */ GameInstance *game = Game::GetInstance(); bool valid = game != NULL; bool dead = valid && game->IsDead(); bool paused = valid && game->IsPaused(); NWidgetCore *button = this->GetWidget(WID_AID_SCRIPT_GAME); dirty |= (button->IsDisabled() == valid) || SetScriptButtonColour(*button, dead, paused); if (dirty) this->InvalidateData(-1); /* If there are no active companies, don't display anything else. */ if (ai_debug_company == INVALID_COMPANY) return; ScriptLog::LogData *log = this->GetLogPointer(); int scroll_count = (log == NULL) ? 0 : log->used; if (this->vscroll->GetCount() != scroll_count) { this->vscroll->SetCount(scroll_count); /* We need a repaint */ this->SetWidgetDirty(WID_AID_SCROLLBAR); } if (log == NULL) return; /* Detect when the user scrolls the window. Enable autoscroll when the * bottom-most line becomes visible. */ if (this->last_vscroll_pos != this->vscroll->GetPosition()) { this->autoscroll = this->vscroll->GetPosition() >= log->used - this->vscroll->GetCapacity(); } if (this->autoscroll) { int scroll_pos = max(0, log->used - this->vscroll->GetCapacity()); if (scroll_pos != this->vscroll->GetPosition()) { this->vscroll->SetPosition(scroll_pos); /* We need a repaint */ this->SetWidgetDirty(WID_AID_SCROLLBAR); this->SetWidgetDirty(WID_AID_LOG_PANEL); } } this->last_vscroll_pos = this->vscroll->GetPosition(); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_AID_NAME_TEXT: if (ai_debug_company == OWNER_DEITY) { const GameInfo *info = Game::GetInfo(); assert(info != NULL); SetDParam(0, STR_AI_DEBUG_NAME_AND_VERSION); SetDParamStr(1, info->GetName()); SetDParam(2, info->GetVersion()); } else if (ai_debug_company == INVALID_COMPANY || !Company::IsValidAiID(ai_debug_company)) { SetDParam(0, STR_EMPTY); } else { const AIInfo *info = Company::Get(ai_debug_company)->ai_info; assert(info != NULL); SetDParam(0, STR_AI_DEBUG_NAME_AND_VERSION); SetDParamStr(1, info->GetName()); SetDParam(2, info->GetVersion()); } break; } } virtual void DrawWidget(const Rect &r, int widget) const { if (ai_debug_company == INVALID_COMPANY) return; switch (widget) { case WID_AID_LOG_PANEL: { ScriptLog::LogData *log = this->GetLogPointer(); if (log == NULL) return; int y = this->top_offset; for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < log->used; i++) { int pos = (i + log->pos + 1 - log->used + log->count) % log->count; if (log->lines[pos] == NULL) break; TextColour colour; switch (log->type[pos]) { case ScriptLog::LOG_SQ_INFO: colour = TC_BLACK; break; case ScriptLog::LOG_SQ_ERROR: colour = TC_RED; break; case ScriptLog::LOG_INFO: colour = TC_BLACK; break; case ScriptLog::LOG_WARNING: colour = TC_YELLOW; break; case ScriptLog::LOG_ERROR: colour = TC_RED; break; default: colour = TC_BLACK; break; } /* Check if the current line should be highlighted */ if (pos == this->highlight_row) { GfxFillRect(r.left + 1, r.top + y, r.right - 1, r.top + y + this->resize.step_height - WD_PAR_VSEP_NORMAL, PC_BLACK); if (colour == TC_BLACK) colour = TC_WHITE; // Make black text readable by inverting it to white. } DrawString(r.left + 7, r.right - 7, r.top + y, log->lines[pos], colour, SA_LEFT | SA_FORCE); y += this->resize.step_height; } break; } } } /** * Change all settings to select another AI. * @param show_ai The new AI to show. */ void ChangeToAI(CompanyID show_ai) { if (!this->IsValidDebugCompany(show_ai)) return; ai_debug_company = show_ai; this->highlight_row = -1; // The highlight of one AI make little sense for another AI. /* Close AI settings window to prevent confusion */ DeleteWindowByClass(WC_AI_SETTINGS); this->InvalidateData(-1); this->autoscroll = true; this->last_vscroll_pos = this->vscroll->GetPosition(); } virtual void OnClick(Point pt, int widget, int click_count) { /* Also called for hotkeys, so check for disabledness */ if (this->IsWidgetDisabled(widget)) return; /* Check which button is clicked */ if (IsInsideMM(widget, WID_AID_COMPANY_BUTTON_START, WID_AID_COMPANY_BUTTON_END + 1)) { ChangeToAI((CompanyID)(widget - WID_AID_COMPANY_BUTTON_START)); } switch (widget) { case WID_AID_SCRIPT_GAME: ChangeToAI(OWNER_DEITY); break; case WID_AID_RELOAD_TOGGLE: if (ai_debug_company == OWNER_DEITY) break; /* First kill the company of the AI, then start a new one. This should start the current AI again */ DoCommandP(0, 2 | ai_debug_company << 16, CRR_MANUAL, CMD_COMPANY_CTRL); DoCommandP(0, 1 | ai_debug_company << 16, 0, CMD_COMPANY_CTRL); break; case WID_AID_SETTINGS: ShowAISettingsWindow(ai_debug_company); break; case WID_AID_BREAK_STR_ON_OFF_BTN: this->break_check_enabled = !this->break_check_enabled; this->InvalidateData(-1); break; case WID_AID_MATCH_CASE_BTN: this->case_sensitive_break_check = !this->case_sensitive_break_check; this->InvalidateData(-1); break; case WID_AID_CONTINUE_BTN: /* Unpause current AI / game script and mark the corresponding script button dirty. */ if (!this->IsDead()) { if (ai_debug_company == OWNER_DEITY) { Game::Unpause(); } else { AI::Unpause(ai_debug_company); } } /* If the last AI/Game Script is unpaused, unpause the game too. */ if ((_pause_mode & PM_PAUSED_NORMAL) == PM_PAUSED_NORMAL) { bool all_unpaused = !Game::IsPaused(); if (all_unpaused) { Company *c; FOR_ALL_COMPANIES(c) { if (c->is_ai && AI::IsPaused(c->index)) { all_unpaused = false; break; } } if (all_unpaused) { /* All scripts have been unpaused => unpause the game. */ DoCommandP(0, PM_PAUSED_NORMAL, 0, CMD_PAUSE); } } } this->highlight_row = -1; this->InvalidateData(-1); break; } } virtual void OnEditboxChanged(int wid) { if (wid == WID_AID_BREAK_STR_EDIT_BOX) { /* Save the current string to static member so it can be restored next time the window is opened. */ strecpy(this->break_string, this->break_editbox.text.buf, lastof(this->break_string)); break_string_filter.SetFilterTerm(this->break_string); } } /** * Some data on this window has become invalid. * @param data Information about the changed data. * This is the company ID of the AI/GS which wrote a new log message, or -1 in other cases. * @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 the log message is related to the active company tab, check the break string. * This needs to be done in gameloop-scope, so the AI is suspended immediately. */ if (!gui_scope && data == ai_debug_company && this->IsValidDebugCompany(ai_debug_company) && this->break_check_enabled && !this->break_string_filter.IsEmpty()) { /* Get the log instance of the active company */ ScriptLog::LogData *log = this->GetLogPointer(); if (log != NULL) { this->break_string_filter.ResetState(); this->break_string_filter.AddLine(log->lines[log->pos]); if (this->break_string_filter.GetState()) { /* Pause execution of script. */ if (!this->IsDead()) { if (ai_debug_company == OWNER_DEITY) { Game::Pause(); } else { AI::Pause(ai_debug_company); } } /* Pause the game. */ if ((_pause_mode & PM_PAUSED_NORMAL) == PM_UNPAUSED) { DoCommandP(0, PM_PAUSED_NORMAL, 1, CMD_PAUSE); } /* Highlight row that matched */ this->highlight_row = log->pos; } } } if (!gui_scope) return; this->SelectValidDebugCompany(); ScriptLog::LogData *log = ai_debug_company != INVALID_COMPANY ? this->GetLogPointer() : NULL; this->vscroll->SetCount((log == NULL) ? 0 : log->used); /* Update company buttons */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { this->SetWidgetDisabledState(i + WID_AID_COMPANY_BUTTON_START, !Company::IsValidAiID(i)); this->SetWidgetLoweredState(i + WID_AID_COMPANY_BUTTON_START, ai_debug_company == i); } this->SetWidgetDisabledState(WID_AID_SCRIPT_GAME, Game::GetGameInstance() == NULL); this->SetWidgetLoweredState(WID_AID_SCRIPT_GAME, ai_debug_company == OWNER_DEITY); this->SetWidgetLoweredState(WID_AID_BREAK_STR_ON_OFF_BTN, this->break_check_enabled); this->SetWidgetLoweredState(WID_AID_MATCH_CASE_BTN, this->case_sensitive_break_check); this->SetWidgetDisabledState(WID_AID_SETTINGS, ai_debug_company == INVALID_COMPANY); this->SetWidgetDisabledState(WID_AID_RELOAD_TOGGLE, ai_debug_company == INVALID_COMPANY || ai_debug_company == OWNER_DEITY); this->SetWidgetDisabledState(WID_AID_CONTINUE_BTN, ai_debug_company == INVALID_COMPANY || (ai_debug_company == OWNER_DEITY ? !Game::IsPaused() : !AI::IsPaused(ai_debug_company))); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_AID_LOG_PANEL); } static HotkeyList hotkeys; }; const int AIDebugWindow::top_offset = WD_FRAMERECT_TOP + 2; const int AIDebugWindow::bottom_offset = WD_FRAMERECT_BOTTOM; CompanyID AIDebugWindow::ai_debug_company = INVALID_COMPANY; char AIDebugWindow::break_string[MAX_BREAK_STR_STRING_LENGTH] = ""; bool AIDebugWindow::break_check_enabled = true; bool AIDebugWindow::case_sensitive_break_check = false; StringFilter AIDebugWindow::break_string_filter(&AIDebugWindow::case_sensitive_break_check); /** Make a number of rows with buttons for each company for the AI debug window. */ NWidgetBase *MakeCompanyButtonRowsAIDebug(int *biggest_index) { return MakeCompanyButtonRows(biggest_index, WID_AID_COMPANY_BUTTON_START, WID_AID_COMPANY_BUTTON_END, 8, STR_AI_DEBUG_SELECT_AI_TOOLTIP); } /** * Handler for global hotkeys of the AIDebugWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState AIDebugGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; Window *w = ShowAIDebugWindow(INVALID_COMPANY); if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } static Hotkey aidebug_hotkeys[] = { Hotkey('1', "company_1", WID_AID_COMPANY_BUTTON_START), Hotkey('2', "company_2", WID_AID_COMPANY_BUTTON_START + 1), Hotkey('3', "company_3", WID_AID_COMPANY_BUTTON_START + 2), Hotkey('4', "company_4", WID_AID_COMPANY_BUTTON_START + 3), Hotkey('5', "company_5", WID_AID_COMPANY_BUTTON_START + 4), Hotkey('6', "company_6", WID_AID_COMPANY_BUTTON_START + 5), Hotkey('7', "company_7", WID_AID_COMPANY_BUTTON_START + 6), Hotkey('8', "company_8", WID_AID_COMPANY_BUTTON_START + 7), Hotkey('9', "company_9", WID_AID_COMPANY_BUTTON_START + 8), Hotkey((uint16)0, "company_10", WID_AID_COMPANY_BUTTON_START + 9), Hotkey((uint16)0, "company_11", WID_AID_COMPANY_BUTTON_START + 10), Hotkey((uint16)0, "company_12", WID_AID_COMPANY_BUTTON_START + 11), Hotkey((uint16)0, "company_13", WID_AID_COMPANY_BUTTON_START + 12), Hotkey((uint16)0, "company_14", WID_AID_COMPANY_BUTTON_START + 13), Hotkey((uint16)0, "company_15", WID_AID_COMPANY_BUTTON_START + 14), Hotkey('S', "settings", WID_AID_SETTINGS), Hotkey('0', "game_script", WID_AID_SCRIPT_GAME), Hotkey((uint16)0, "reload", WID_AID_RELOAD_TOGGLE), Hotkey('B', "break_toggle", WID_AID_BREAK_STR_ON_OFF_BTN), Hotkey('F', "break_string", WID_AID_BREAK_STR_EDIT_BOX), Hotkey('C', "match_case", WID_AID_MATCH_CASE_BTN), Hotkey(WKC_RETURN, "continue", WID_AID_CONTINUE_BTN), HOTKEY_LIST_END }; HotkeyList AIDebugWindow::hotkeys("aidebug", aidebug_hotkeys, AIDebugGlobalHotkeys); /** Widgets for the AI debug window. */ static const NWidgetPart _nested_ai_debug_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_AI_DEBUG, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_AID_VIEW), NWidgetFunction(MakeCompanyButtonRowsAIDebug), SetPadding(0, 2, 1, 2), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AID_SCRIPT_GAME), SetMinimalSize(100, 20), SetResize(1, 0), SetDataTip(STR_AI_GAME_SCRIPT, STR_AI_GAME_SCRIPT_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AID_NAME_TEXT), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING, STR_AI_DEBUG_NAME_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_AID_SETTINGS), SetMinimalSize(100, 20), SetDataTip(STR_AI_DEBUG_SETTINGS, STR_AI_DEBUG_SETTINGS_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_AID_RELOAD_TOGGLE), SetMinimalSize(100, 20), SetDataTip(STR_AI_DEBUG_RELOAD, STR_AI_DEBUG_RELOAD_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), /* Log panel */ NWidget(WWT_PANEL, COLOUR_GREY, WID_AID_LOG_PANEL), SetMinimalSize(287, 180), SetResize(1, 1), SetScrollbar(WID_AID_SCROLLBAR), EndContainer(), /* Break string widgets */ NWidget(NWID_SELECTION, INVALID_COLOUR, WID_AID_BREAK_STRING_WIDGETS), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_AID_BREAK_STR_ON_OFF_BTN), SetFill(0, 1), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), NWidget(WWT_LABEL, COLOUR_GREY), SetPadding(2, 2, 2, 4), SetDataTip(STR_AI_DEBUG_BREAK_ON_LABEL, 0x0), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_AID_BREAK_STR_EDIT_BOX), SetFill(1, 1), SetResize(1, 0), SetPadding(2, 2, 2, 2), SetDataTip(STR_AI_DEBUG_BREAK_STR_OSKTITLE, STR_AI_DEBUG_BREAK_STR_TOOLTIP), EndContainer(), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AID_MATCH_CASE_BTN), SetMinimalSize(100, 0), SetFill(0, 1), SetDataTip(STR_AI_DEBUG_MATCH_CASE, STR_AI_DEBUG_MATCH_CASE_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_AID_CONTINUE_BTN), SetMinimalSize(100, 0), SetFill(0, 1), SetDataTip(STR_AI_DEBUG_CONTINUE, STR_AI_DEBUG_CONTINUE_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AID_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), }; /** Window definition for the AI debug window. */ static WindowDesc _ai_debug_desc( WDP_AUTO, "script_debug", 600, 450, WC_AI_DEBUG, WC_NONE, 0, _nested_ai_debug_widgets, lengthof(_nested_ai_debug_widgets), &AIDebugWindow::hotkeys ); /** * Open the AI debug window and select the given company. * @param show_company Display debug information about this AI company. */ Window *ShowAIDebugWindow(CompanyID show_company) { if (!_networking || _network_server) { AIDebugWindow *w = (AIDebugWindow *)BringWindowToFrontById(WC_AI_DEBUG, 0); if (w == NULL) w = new AIDebugWindow(&_ai_debug_desc, 0); if (show_company != INVALID_COMPANY) w->ChangeToAI(show_company); return w; } else { ShowErrorMessage(STR_ERROR_AI_DEBUG_SERVER_ONLY, INVALID_STRING_ID, WL_INFO); } return NULL; } /** * Reset the AI windows to their initial state. */ void InitializeAIGui() { AIDebugWindow::ai_debug_company = INVALID_COMPANY; } /** Open the AI debug window if one of the AI scripts has crashed. */ void ShowAIDebugWindowIfAIError() { /* Network clients can't debug AIs. */ if (_networking && !_network_server) return; Company *c; FOR_ALL_COMPANIES(c) { if (c->is_ai && c->ai_instance->IsDead()) { ShowAIDebugWindow(c->index); break; } } GameInstance *g = Game::GetGameInstance(); if (g != NULL && g->IsDead()) { ShowAIDebugWindow(OWNER_DEITY); } } openttd-1.5.3/src/ai/ai_config.hpp0000644000000000000000000000351712627373441015521 0ustar rootroot/* $Id: ai_config.hpp 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 ai_config.hpp AIConfig stores the configuration settings of every AI. */ #ifndef AI_CONFIG_HPP #define AI_CONFIG_HPP #include "../script/script_config.hpp" #include "../company_type.h" class AIConfig : public ScriptConfig { public: /** * Get the config of a company. */ static AIConfig *GetConfig(CompanyID company, ScriptSettingSource source = SSS_DEFAULT); AIConfig() : ScriptConfig() {} AIConfig(const AIConfig *config) : ScriptConfig(config) {} class AIInfo *GetInfo() const; /* virtual */ int GetSetting(const char *name) const; /* virtual */ void SetSetting(const char *name, int value); /** * When ever the AI Scanner is reloaded, all infos become invalid. This * function tells AIConfig about this. * @param force_exact_match If true try to find the exact same version * as specified. If false any version is ok. * @return \c true if the reset was successful, \c false if the AI was no longer * found. */ bool ResetInfo(bool force_exact_match); protected: /* virtual */ void PushExtraConfigList(); /* virtual */ void ClearConfigList(); /* virtual */ ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match); }; #endif /* AI_CONFIG_HPP */ openttd-1.5.3/src/ai/ai_gui.hpp0000644000000000000000000000166112627373441015036 0ustar rootroot/* $Id: ai_gui.hpp 24554 2012-09-23 14:37:59Z zuu $ */ /* * 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 ai_gui.hpp %Window for configuring the AIs */ #ifndef AI_GUI_HPP #define AI_GUI_HPP #include "../company_type.h" Window* ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY); void ShowAIConfigWindow(); void ShowAIDebugWindowIfAIError(); void InitializeAIGui(); #endif /* AI_GUI_HPP */ openttd-1.5.3/src/ai/ai_instance.hpp0000644000000000000000000000263412627373441016057 0ustar rootroot/* $Id: ai_instance.hpp 24468 2012-08-13 19:22:26Z yexo $ */ /* * 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 ai_instance.hpp The AIInstance tracks an AI. */ #ifndef AI_INSTANCE_HPP #define AI_INSTANCE_HPP #include "../script/script_instance.hpp" /** Runtime information about an AI like a pointer to the squirrel vm and the current state. */ class AIInstance : public ScriptInstance { public: AIInstance(); /** * Initialize the AI and prepare it for its first run. * @param info The AI to create the instance of. */ void Initialize(class AIInfo *info); /* virtual */ int GetSetting(const char *name); /* virtual */ ScriptInfo *FindLibrary(const char *library, int version); private: /* virtual */ void RegisterAPI(); /* virtual */ void Died(); /* virtual */ CommandCallback *GetDoCommandCallback(); /* virtual */ void LoadDummyScript(); }; #endif /* AI_INSTANCE_HPP */ openttd-1.5.3/src/ai/ai_instance.cpp0000644000000000000000000002445212627373441016054 0ustar rootroot/* $Id: ai_instance.cpp 26893 2014-09-21 16:20:48Z fonsinchen $ */ /* * 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 ai_instance.cpp Implementation of AIInstance. */ #include "../stdafx.h" #include "../debug.h" #include "../error.h" #include "../script/squirrel_class.hpp" #include "ai_config.hpp" #include "ai_gui.hpp" #include "ai.hpp" #include "../script/script_storage.hpp" #include "ai_info.hpp" #include "ai_instance.hpp" /* Manually include the Text glue. */ #include "../script/api/template/template_text.hpp.sq" /* Convert all AI related classes to Squirrel data. * Note: this line is a marker in squirrel_export.sh. Do not change! */ #include "../script/api/ai/ai_accounting.hpp.sq" #include "../script/api/ai/ai_airport.hpp.sq" #include "../script/api/ai/ai_base.hpp.sq" #include "../script/api/ai/ai_basestation.hpp.sq" #include "../script/api/ai/ai_bridge.hpp.sq" #include "../script/api/ai/ai_bridgelist.hpp.sq" #include "../script/api/ai/ai_cargo.hpp.sq" #include "../script/api/ai/ai_cargolist.hpp.sq" #include "../script/api/ai/ai_company.hpp.sq" #include "../script/api/ai/ai_controller.hpp.sq" #include "../script/api/ai/ai_date.hpp.sq" #include "../script/api/ai/ai_depotlist.hpp.sq" #include "../script/api/ai/ai_engine.hpp.sq" #include "../script/api/ai/ai_enginelist.hpp.sq" #include "../script/api/ai/ai_error.hpp.sq" #include "../script/api/ai/ai_event.hpp.sq" #include "../script/api/ai/ai_event_types.hpp.sq" #include "../script/api/ai/ai_execmode.hpp.sq" #include "../script/api/ai/ai_gamesettings.hpp.sq" #include "../script/api/ai/ai_group.hpp.sq" #include "../script/api/ai/ai_grouplist.hpp.sq" #include "../script/api/ai/ai_industry.hpp.sq" #include "../script/api/ai/ai_industrylist.hpp.sq" #include "../script/api/ai/ai_industrytype.hpp.sq" #include "../script/api/ai/ai_industrytypelist.hpp.sq" #include "../script/api/ai/ai_infrastructure.hpp.sq" #include "../script/api/ai/ai_list.hpp.sq" #include "../script/api/ai/ai_log.hpp.sq" #include "../script/api/ai/ai_map.hpp.sq" #include "../script/api/ai/ai_marine.hpp.sq" #include "../script/api/ai/ai_order.hpp.sq" #include "../script/api/ai/ai_rail.hpp.sq" #include "../script/api/ai/ai_railtypelist.hpp.sq" #include "../script/api/ai/ai_road.hpp.sq" #include "../script/api/ai/ai_sign.hpp.sq" #include "../script/api/ai/ai_signlist.hpp.sq" #include "../script/api/ai/ai_station.hpp.sq" #include "../script/api/ai/ai_stationlist.hpp.sq" #include "../script/api/ai/ai_subsidy.hpp.sq" #include "../script/api/ai/ai_subsidylist.hpp.sq" #include "../script/api/ai/ai_testmode.hpp.sq" #include "../script/api/ai/ai_tile.hpp.sq" #include "../script/api/ai/ai_tilelist.hpp.sq" #include "../script/api/ai/ai_town.hpp.sq" #include "../script/api/ai/ai_townlist.hpp.sq" #include "../script/api/ai/ai_tunnel.hpp.sq" #include "../script/api/ai/ai_vehicle.hpp.sq" #include "../script/api/ai/ai_vehiclelist.hpp.sq" #include "../script/api/ai/ai_waypoint.hpp.sq" #include "../script/api/ai/ai_waypointlist.hpp.sq" #include "../company_base.h" #include "../company_func.h" #include "../safeguards.h" AIInstance::AIInstance() : ScriptInstance("AI") {} void AIInstance::Initialize(AIInfo *info) { this->versionAPI = info->GetAPIVersion(); /* Register the AIController (including the "import" command) */ SQAIController_Register(this->engine); ScriptInstance::Initialize(info->GetMainScript(), info->GetInstanceName(), _current_company); } void AIInstance::RegisterAPI() { ScriptInstance::RegisterAPI(); /* Register all classes */ SQAIList_Register(this->engine); SQAIAccounting_Register(this->engine); SQAIAirport_Register(this->engine); SQAIBase_Register(this->engine); SQAIBaseStation_Register(this->engine); SQAIBridge_Register(this->engine); SQAIBridgeList_Register(this->engine); SQAIBridgeList_Length_Register(this->engine); SQAICargo_Register(this->engine); SQAICargoList_Register(this->engine); SQAICargoList_IndustryAccepting_Register(this->engine); SQAICargoList_IndustryProducing_Register(this->engine); SQAICargoList_StationAccepting_Register(this->engine); SQAICompany_Register(this->engine); SQAIDate_Register(this->engine); SQAIDepotList_Register(this->engine); SQAIEngine_Register(this->engine); SQAIEngineList_Register(this->engine); SQAIError_Register(this->engine); SQAIEvent_Register(this->engine); SQAIEventAircraftDestTooFar_Register(this->engine); SQAIEventCompanyAskMerger_Register(this->engine); SQAIEventCompanyBankrupt_Register(this->engine); SQAIEventCompanyInTrouble_Register(this->engine); SQAIEventCompanyMerger_Register(this->engine); SQAIEventCompanyNew_Register(this->engine); SQAIEventCompanyTown_Register(this->engine); SQAIEventController_Register(this->engine); SQAIEventDisasterZeppelinerCleared_Register(this->engine); SQAIEventDisasterZeppelinerCrashed_Register(this->engine); SQAIEventEngineAvailable_Register(this->engine); SQAIEventEnginePreview_Register(this->engine); SQAIEventExclusiveTransportRights_Register(this->engine); SQAIEventIndustryClose_Register(this->engine); SQAIEventIndustryOpen_Register(this->engine); SQAIEventRoadReconstruction_Register(this->engine); SQAIEventStationFirstVehicle_Register(this->engine); SQAIEventSubsidyAwarded_Register(this->engine); SQAIEventSubsidyExpired_Register(this->engine); SQAIEventSubsidyOffer_Register(this->engine); SQAIEventSubsidyOfferExpired_Register(this->engine); SQAIEventTownFounded_Register(this->engine); SQAIEventVehicleCrashed_Register(this->engine); SQAIEventVehicleLost_Register(this->engine); SQAIEventVehicleUnprofitable_Register(this->engine); SQAIEventVehicleWaitingInDepot_Register(this->engine); SQAIExecMode_Register(this->engine); SQAIGameSettings_Register(this->engine); SQAIGroup_Register(this->engine); SQAIGroupList_Register(this->engine); SQAIIndustry_Register(this->engine); SQAIIndustryList_Register(this->engine); SQAIIndustryList_CargoAccepting_Register(this->engine); SQAIIndustryList_CargoProducing_Register(this->engine); SQAIIndustryType_Register(this->engine); SQAIIndustryTypeList_Register(this->engine); SQAIInfrastructure_Register(this->engine); SQAILog_Register(this->engine); SQAIMap_Register(this->engine); SQAIMarine_Register(this->engine); SQAIOrder_Register(this->engine); SQAIRail_Register(this->engine); SQAIRailTypeList_Register(this->engine); SQAIRoad_Register(this->engine); SQAISign_Register(this->engine); SQAISignList_Register(this->engine); SQAIStation_Register(this->engine); SQAIStationList_Register(this->engine); SQAIStationList_Cargo_Register(this->engine); SQAIStationList_CargoPlanned_Register(this->engine); SQAIStationList_CargoPlannedByFrom_Register(this->engine); SQAIStationList_CargoPlannedByVia_Register(this->engine); SQAIStationList_CargoPlannedFromByVia_Register(this->engine); SQAIStationList_CargoPlannedViaByFrom_Register(this->engine); SQAIStationList_CargoWaiting_Register(this->engine); SQAIStationList_CargoWaitingByFrom_Register(this->engine); SQAIStationList_CargoWaitingByVia_Register(this->engine); SQAIStationList_CargoWaitingFromByVia_Register(this->engine); SQAIStationList_CargoWaitingViaByFrom_Register(this->engine); SQAIStationList_Vehicle_Register(this->engine); SQAISubsidy_Register(this->engine); SQAISubsidyList_Register(this->engine); SQAITestMode_Register(this->engine); SQAITile_Register(this->engine); SQAITileList_Register(this->engine); SQAITileList_IndustryAccepting_Register(this->engine); SQAITileList_IndustryProducing_Register(this->engine); SQAITileList_StationType_Register(this->engine); SQAITown_Register(this->engine); SQAITownEffectList_Register(this->engine); SQAITownList_Register(this->engine); SQAITunnel_Register(this->engine); SQAIVehicle_Register(this->engine); SQAIVehicleList_Register(this->engine); SQAIVehicleList_DefaultGroup_Register(this->engine); SQAIVehicleList_Depot_Register(this->engine); SQAIVehicleList_Group_Register(this->engine); SQAIVehicleList_SharedOrders_Register(this->engine); SQAIVehicleList_Station_Register(this->engine); SQAIWaypoint_Register(this->engine); SQAIWaypointList_Register(this->engine); SQAIWaypointList_Vehicle_Register(this->engine); if (!this->LoadCompatibilityScripts(this->versionAPI, AI_DIR)) this->Died(); } void AIInstance::Died() { ScriptInstance::Died(); ShowAIDebugWindow(_current_company); const AIInfo *info = AIConfig::GetConfig(_current_company, AIConfig::SSS_FORCE_GAME)->GetInfo(); if (info != NULL) { ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING); if (info->GetURL() != NULL) { ScriptLog::Info("Please report the error to the following URL:"); ScriptLog::Info(info->GetURL()); } } } void AIInstance::LoadDummyScript() { extern void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type); Script_CreateDummy(this->engine->GetVM(), STR_ERROR_AI_NO_AI_FOUND, "AI"); } int AIInstance::GetSetting(const char *name) { return AIConfig::GetConfig(_current_company)->GetSetting(name); } ScriptInfo *AIInstance::FindLibrary(const char *library, int version) { return (ScriptInfo *)AI::FindLibrary(library, version); } /** * DoCommand callback function for all commands executed by AIs. * @param result The result of the command. * @param tile The tile on which the command was executed. * @param p1 p1 as given to DoCommandPInternal. * @param p2 p2 as given to DoCommandPInternal. */ void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { /* * The company might not exist anymore. Check for this. * The command checks are not useful since this callback * is also called when the command fails, which is does * when the company does not exist anymore. */ const Company *c = Company::GetIfValid(_current_company); if (c == NULL || c->ai_instance == NULL) return; c->ai_instance->DoCommandCallback(result, tile, p1, p2); c->ai_instance->Continue(); } CommandCallback *AIInstance::GetDoCommandCallback() { return &CcAI; } openttd-1.5.3/src/ai/ai_info.cpp0000644000000000000000000001457612627373441015211 0ustar rootroot/* $Id: ai_info.cpp 26774 2014-09-06 17:46:56Z rubidium $ */ /* * 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 ai_info.cpp Implementation of AIInfo and AILibrary */ #include "../stdafx.h" #include "../script/squirrel_class.hpp" #include "ai_info.hpp" #include "ai_scanner.hpp" #include "../debug.h" #include "../string_func.h" #include "../rev.h" #include "../safeguards.h" /** * Check if the API version provided by the AI is supported. * @param api_version The API version as provided by the AI. */ static bool CheckAPIVersion(const char *api_version) { return strcmp(api_version, "0.7") == 0 || strcmp(api_version, "1.0") == 0 || strcmp(api_version, "1.1") == 0 || strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 || strcmp(api_version, "1.5") == 0; } #if defined(WIN32) #undef GetClassName #endif /* WIN32 */ template <> const char *GetClassName() { return "AIInfo"; } /* static */ void AIInfo::RegisterAPI(Squirrel *engine) { /* Create the AIInfo class, and add the RegisterAI function */ DefSQClass SQAIInfo("AIInfo"); SQAIInfo.PreRegister(engine); SQAIInfo.AddConstructor(engine, "x"); SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddSetting, "AddSetting"); SQAIInfo.DefSQAdvancedMethod(engine, &AIInfo::AddLabels, "AddLabels"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER"); /* Pre 1.2 had an AI prefix */ SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "AICONFIG_NONE"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "AICONFIG_RANDOM"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "AICONFIG_BOOLEAN"); SQAIInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "AICONFIG_INGAME"); SQAIInfo.PostRegister(engine); engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx"); engine->AddMethod("RegisterDummyAI", &AIInfo::DummyConstructor, 2, "tx"); } /* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm) { /* Get the AIInfo */ SQUserPointer instance = NULL; if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, 0)) || instance == NULL) return sq_throwerror(vm, "Pass an instance of a child class of AIInfo to RegisterAI"); AIInfo *info = (AIInfo *)instance; SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; ScriptConfigItem config = _start_date_config; config.name = stredup(config.name); config.description = stredup(config.description); info->config_list.push_front(config); if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) { if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; } else { info->min_loadable_version = info->GetVersion(); } /* When there is an UseAsRandomAI function, call it. */ if (info->engine->MethodExists(*info->SQ_instance, "UseAsRandomAI")) { if (!info->engine->CallBoolMethod(*info->SQ_instance, "UseAsRandomAI", &info->use_as_random, MAX_GET_OPS)) return SQ_ERROR; } else { info->use_as_random = true; } /* Try to get the API version the AI is written for. */ if (info->engine->MethodExists(*info->SQ_instance, "GetAPIVersion")) { if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; if (!CheckAPIVersion(info->api_version)) { DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); return SQ_ERROR; } } else { info->api_version = stredup("0.7"); } /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ sq_setinstanceup(vm, 2, NULL); /* Register the AI to the base system */ info->GetScanner()->RegisterScript(info); return 0; } /* static */ SQInteger AIInfo::DummyConstructor(HSQUIRRELVM vm) { /* Get the AIInfo */ SQUserPointer instance; sq_getinstanceup(vm, 2, &instance, 0); AIInfo *info = (AIInfo *)instance; info->api_version = NULL; SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; char buf[8]; seprintf(buf, lastof(buf), "%d.%d", GB(_openttd_newgrf_version, 28, 4), GB(_openttd_newgrf_version, 24, 4)); info->api_version = stredup(buf); /* Remove the link to the real instance, else it might get deleted by RegisterAI() */ sq_setinstanceup(vm, 2, NULL); /* Register the AI to the base system */ static_cast(info->GetScanner())->SetDummyAI(info); return 0; } AIInfo::AIInfo() : min_loadable_version(0), use_as_random(false), api_version(NULL) { } AIInfo::~AIInfo() { free(this->api_version); } bool AIInfo::CanLoadFromVersion(int version) const { if (version == -1) return true; return version >= this->min_loadable_version && version <= this->GetVersion(); } AILibrary::~AILibrary() { free(this->category); } /* static */ void AILibrary::RegisterAPI(Squirrel *engine) { /* Create the AILibrary class, and add the RegisterLibrary function */ engine->AddClassBegin("AILibrary"); engine->AddClassEnd(); engine->AddMethod("RegisterLibrary", &AILibrary::Constructor, 2, "tx"); } /* static */ SQInteger AILibrary::Constructor(HSQUIRRELVM vm) { /* Create a new library */ AILibrary *library = new AILibrary(); SQInteger res = ScriptInfo::Constructor(vm, library); if (res != 0) { delete library; return res; } /* Cache the category */ if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { delete library; return SQ_ERROR; } /* Register the Library to the base system */ library->GetScanner()->RegisterScript(library); return 0; } openttd-1.5.3/src/ai/ai_info.hpp0000644000000000000000000000462312627373441015206 0ustar rootroot/* $Id: ai_info.hpp 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 ai_info.hpp AIInfo keeps track of all information of an AI, like Author, Description, ... */ #ifndef AI_INFO_HPP #define AI_INFO_HPP #include "../script/script_info.hpp" /** All static information from an AI like name, version, etc. */ class AIInfo : public ScriptInfo { public: AIInfo(); ~AIInfo(); /** * Register the functions of this class. */ static void RegisterAPI(Squirrel *engine); /** * Create an AI, using this AIInfo as start-template. */ static SQInteger Constructor(HSQUIRRELVM vm); /** * Create a dummy-AI. */ static SQInteger DummyConstructor(HSQUIRRELVM vm); /** * Check if we can start this AI. */ bool CanLoadFromVersion(int version) const; /** * Use this AI as a random AI. */ bool UseAsRandomAI() const { return this->use_as_random; } /** * Get the API version this AI is written for. */ const char *GetAPIVersion() const { return this->api_version; } private: int min_loadable_version; ///< The AI can load savegame data if the version is equal or greater than this. bool use_as_random; ///< Should this AI be used when the user wants a "random AI"? const char *api_version; ///< API version used by this AI. }; /** All static information from an AI library like name, version, etc. */ class AILibrary : public ScriptInfo { public: AILibrary() : ScriptInfo(), category(NULL) {}; ~AILibrary(); /** * Register the functions of this class. */ static void RegisterAPI(Squirrel *engine); /** * Create an AI, using this AIInfo as start-template. */ static SQInteger Constructor(HSQUIRRELVM vm); /** * Get the category this library is in. */ const char *GetCategory() const { return this->category; } private: const char *category; ///< The category this library is in. }; #endif /* AI_INFO_HPP */ openttd-1.5.3/src/ai/ai.hpp0000644000000000000000000001311012627373441014162 0ustar rootroot/* $Id: ai.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 ai.hpp Base functions for all AIs. */ #ifndef AI_HPP #define AI_HPP #include "../script/api/script_event_types.hpp" #include "../core/string_compare_type.hpp" #include "ai_scanner.hpp" #include /** A list that maps AI names to their AIInfo object. */ typedef std::map ScriptInfoList; /** * Main AI class. Contains all functions needed to start, stop, save and load AIs. */ class AI { public: /** * The default months AIs start after each other. */ enum StartNext { START_NEXT_EASY = DAYS_IN_YEAR * 2, START_NEXT_MEDIUM = DAYS_IN_YEAR, START_NEXT_HARD = DAYS_IN_YEAR / 2, START_NEXT_MIN = 1, START_NEXT_MAX = 3600, START_NEXT_DEVIATION = 60, }; /** * Is it possible to start a new AI company? * @return True if a new AI company can be started. */ static bool CanStartNew(); /** * Start a new AI company. * @param company At which slot the AI company should start. * @param rerandomise_ai Whether to rerandomise the configured AI. */ static void StartNew(CompanyID company, bool rerandomise_ai = true); /** * Called every game-tick to let AIs do something. */ static void GameLoop(); /** * Get the current AI tick. */ static uint GetTick(); /** * Stop a company to be controlled by an AI. * @param company The company from which the AI needs to detach. * @pre Company::IsValidAiID(company) */ static void Stop(CompanyID company); /** * Suspend the AI and then pause execution of the script. The script * will not be resumed from its suspended state until the script has * been unpaused. * @param company The company for which the AI should be paused. * @pre Company::IsValidAiID(company) */ static void Pause(CompanyID company); /** * Resume execution of the AI. This function will not actually execute * the script, but set a flag so that the script is executed my the usual * mechanism that executes the script. * @param company The company for which the AI should be unpaused. * @pre Company::IsValidAiID(company) */ static void Unpause(CompanyID company); /** * Checks if the AI is paused. * @param company The company for which to check if the AI is paused. * @pre Company::IsValidAiID(company) * @return true if the AI is paused, otherwise false. */ static bool IsPaused(CompanyID company); /** * Kill any and all AIs we manage. */ static void KillAll(); /** * Initialize the AI system. */ static void Initialize(); /** * Uninitialize the AI system * @param keepConfig Should we keep AIConfigs, or can we free that memory? */ static void Uninitialize(bool keepConfig); /** * Reset all AIConfigs, and make them reload their AIInfo. * If the AIInfo could no longer be found, an error is reported to the user. */ static void ResetConfig(); /** * Queue a new event for an AI. */ static void NewEvent(CompanyID company, ScriptEvent *event); /** * Broadcast a new event to all active AIs. */ static void BroadcastNewEvent(ScriptEvent *event, CompanyID skip_company = MAX_COMPANIES); /** * Save data from an AI to a savegame. */ static void Save(CompanyID company); /** * Load data for an AI from a savegame. */ static void Load(CompanyID company, int version); /** * Get the number of days before the next AI should start. */ static int GetStartNextTime(); /** Wrapper function for AIScanner::GetAIConsoleList */ static char *GetConsoleList(char *p, const char *last, bool newest_only = false); /** Wrapper function for AIScanner::GetAIConsoleLibraryList */ static char *GetConsoleLibraryList(char *p, const char *last); /** Wrapper function for AIScanner::GetAIInfoList */ static const ScriptInfoList *GetInfoList(); /** Wrapper function for AIScanner::GetUniqueAIInfoList */ static const ScriptInfoList *GetUniqueInfoList(); /** Wrapper function for AIScanner::FindInfo */ static class AIInfo *FindInfo(const char *name, int version, bool force_exact_match); /** Wrapper function for AIScanner::FindLibrary */ static class AILibrary *FindLibrary(const char *library, int version); /** * Rescans all searchpaths for available AIs. If a used AI is no longer * found it is removed from the config. */ static void Rescan(); /** Gets the ScriptScanner instance that is used to find AIs */ static AIScannerInfo *GetScannerInfo(); /** Gets the ScriptScanner instance that is used to find AI Libraries */ static AIScannerLibrary *GetScannerLibrary(); #if defined(ENABLE_NETWORK) /** Wrapper function for AIScanner::HasAI */ static bool HasAI(const struct ContentInfo *ci, bool md5sum); static bool HasAILibrary(const ContentInfo *ci, bool md5sum); #endif private: static uint frame_counter; ///< Tick counter for the AI code static class AIScannerInfo *scanner_info; ///< ScriptScanner instance that is used to find AIs static class AIScannerLibrary *scanner_library; ///< ScriptScanner instance that is used to find AI Libraries }; #endif /* AI_HPP */ openttd-1.5.3/src/ai/ai_config.cpp0000644000000000000000000000667012627373441015517 0ustar rootroot/* $Id: ai_config.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 ai_config.cpp Implementation of AIConfig. */ #include "../stdafx.h" #include "../settings_type.h" #include "../string_func.h" #include "ai.hpp" #include "ai_config.hpp" #include "ai_info.hpp" #include "../safeguards.h" /** Configuration for AI start date, every AI has this setting. */ ScriptConfigItem _start_date_config = { "start_date", "", // STR_AI_SETTINGS_START_DELAY AI::START_NEXT_MIN, AI::START_NEXT_MAX, AI::START_NEXT_MEDIUM, AI::START_NEXT_EASY, AI::START_NEXT_MEDIUM, AI::START_NEXT_HARD, AI::START_NEXT_DEVIATION, 30, SCRIPTCONFIG_NONE, NULL, false }; /* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source) { AIConfig **config; if (source == SSS_FORCE_NEWGAME || (source == SSS_DEFAULT && _game_mode == GM_MENU)) { config = &_settings_newgame.ai_config[company]; } else { config = &_settings_game.ai_config[company]; } if (*config == NULL) *config = new AIConfig(); return *config; } class AIInfo *AIConfig::GetInfo() const { return static_cast(ScriptConfig::GetInfo()); } ScriptInfo *AIConfig::FindInfo(const char *name, int version, bool force_exact_match) { return static_cast(AI::FindInfo(name, version, force_exact_match)); } bool AIConfig::ResetInfo(bool force_exact_match) { this->info = (ScriptInfo *)AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); return this->info != NULL; } void AIConfig::PushExtraConfigList() { this->config_list->push_back(_start_date_config); } void AIConfig::ClearConfigList() { /* The special casing for start_date is here to ensure that the * start_date setting won't change even if you chose another Script. */ int start_date = this->GetSetting("start_date"); ScriptConfig::ClearConfigList(); this->SetSetting("start_date", start_date); } int AIConfig::GetSetting(const char *name) const { if (this->info == NULL) { SettingValueList::const_iterator it = this->settings.find(name); if (it == this->settings.end()) { assert(strcmp("start_date", name) == 0); switch (GetGameSettings().script.settings_profile) { case SP_EASY: return AI::START_NEXT_EASY; case SP_MEDIUM: return AI::START_NEXT_MEDIUM; case SP_HARD: return AI::START_NEXT_HARD; case SP_CUSTOM: return AI::START_NEXT_MEDIUM; default: NOT_REACHED(); } } return (*it).second; } return ScriptConfig::GetSetting(name); } void AIConfig::SetSetting(const char *name, int value) { if (this->info == NULL) { if (strcmp("start_date", name) != 0) return; value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX); SettingValueList::iterator it = this->settings.find(name); if (it != this->settings.end()) { (*it).second = value; } else { this->settings[stredup(name)] = value; } return; } ScriptConfig::SetSetting(name, value); } openttd-1.5.3/src/ai/ai_scanner.cpp0000644000000000000000000001203512627373441015673 0ustar rootroot/* $Id: ai_scanner.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 ai_scanner.cpp allows scanning AI scripts */ #include "../stdafx.h" #include "../debug.h" #include "../network/network.h" #include "../core/random_func.hpp" #include "../script/squirrel_class.hpp" #include "ai_info.hpp" #include "ai_scanner.hpp" #include "../safeguards.h" AIScannerInfo::AIScannerInfo() : ScriptScanner(), info_dummy(NULL) { } void AIScannerInfo::Initialize() { ScriptScanner::Initialize("AIScanner"); /* Create the dummy AI */ free(this->main_script); this->main_script = stredup("%_dummy"); extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir); Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai"); } void AIScannerInfo::SetDummyAI(class AIInfo *info) { this->info_dummy = info; } AIScannerInfo::~AIScannerInfo() { delete this->info_dummy; } void AIScannerInfo::GetScriptName(ScriptInfo *info, char *name, const char *last) { seprintf(name, last, "%s", info->GetName()); } void AIScannerInfo::RegisterAPI(class Squirrel *engine) { AIInfo::RegisterAPI(engine); } AIInfo *AIScannerInfo::SelectRandomAI() const { uint num_random_ais = 0; for (ScriptInfoList::const_iterator it = this->info_single_list.begin(); it != this->info_single_list.end(); it++) { AIInfo *i = static_cast((*it).second); if (i->UseAsRandomAI()) num_random_ais++; } if (num_random_ais == 0) { DEBUG(script, 0, "No suitable AI found, loading 'dummy' AI."); return this->info_dummy; } /* Find a random AI */ uint pos; if (_networking) { pos = InteractiveRandomRange(num_random_ais); } else { pos = RandomRange(num_random_ais); } /* Find the Nth item from the array */ ScriptInfoList::const_iterator it = this->info_single_list.begin(); #define GetAIInfo(it) static_cast((*it).second) while (!GetAIInfo(it)->UseAsRandomAI()) it++; for (; pos > 0; pos--) { it++; while (!GetAIInfo(it)->UseAsRandomAI()) it++; } return GetAIInfo(it); #undef GetAIInfo } AIInfo *AIScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match) { if (this->info_list.size() == 0) return NULL; if (nameParam == NULL) return NULL; char ai_name[1024]; strecpy(ai_name, nameParam, lastof(ai_name)); strtolower(ai_name); AIInfo *info = NULL; int version = -1; if (versionParam == -1) { /* We want to load the latest version of this AI; so find it */ if (this->info_single_list.find(ai_name) != this->info_single_list.end()) return static_cast(this->info_single_list[ai_name]); /* If we didn't find a match AI, maybe the user included a version */ char *e = strrchr(ai_name, '.'); if (e == NULL) return NULL; *e = '\0'; e++; versionParam = atoi(e); /* FALL THROUGH, like we were calling this function with a version. */ } if (force_exact_match) { /* Try to find a direct 'name.version' match */ char ai_name_tmp[1024]; seprintf(ai_name_tmp, lastof(ai_name_tmp), "%s.%d", ai_name, versionParam); strtolower(ai_name_tmp); if (this->info_list.find(ai_name_tmp) != this->info_list.end()) return static_cast(this->info_list[ai_name_tmp]); } /* See if there is a compatible AI which goes by that name, with the highest * version which allows loading the requested version */ ScriptInfoList::iterator it = this->info_list.begin(); for (; it != this->info_list.end(); it++) { AIInfo *i = static_cast((*it).second); if (strcasecmp(ai_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) { version = (*it).second->GetVersion(); info = i; } } return info; } void AIScannerLibrary::Initialize() { ScriptScanner::Initialize("AIScanner"); } void AIScannerLibrary::GetScriptName(ScriptInfo *info, char *name, const char *last) { AILibrary *library = static_cast(info); seprintf(name, last, "%s.%s", library->GetCategory(), library->GetInstanceName()); } void AIScannerLibrary::RegisterAPI(class Squirrel *engine) { AILibrary::RegisterAPI(engine); } AILibrary *AIScannerLibrary::FindLibrary(const char *library, int version) { /* Internally we store libraries as 'library.version' */ char library_name[1024]; seprintf(library_name, lastof(library_name), "%s.%d", library, version); strtolower(library_name); /* Check if the library + version exists */ ScriptInfoList::iterator iter = this->info_list.find(library_name); if (iter == this->info_list.end()) return NULL; return static_cast((*iter).second); } openttd-1.5.3/src/ai/ai_scanner.hpp0000644000000000000000000000524512627373441015705 0ustar rootroot/* $Id: ai_scanner.hpp 26487 2014-04-23 21:16:58Z rubidium $ */ /* * 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 ai_scanner.hpp declarations of the class for AI scanner */ #ifndef AI_SCANNER_HPP #define AI_SCANNER_HPP #include "../script/script_scanner.hpp" class AIScannerInfo : public ScriptScanner { public: AIScannerInfo(); ~AIScannerInfo(); /* virtual */ void Initialize(); /** * Select a random AI. * @return A random AI from the pool. */ class AIInfo *SelectRandomAI() const; /** * Check if we have an AI by name and version available in our list. * @param nameParam The name of the AI. * @param versionParam The version of the AI, or -1 if you want the latest. * @param force_exact_match Only match name+version, never latest. * @return NULL if no match found, otherwise the AI that matched. */ class AIInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match); /** * Set the Dummy AI. */ void SetDummyAI(class AIInfo *info); protected: /* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last); /* virtual */ const char *GetFileName() const { return PATHSEP "info.nut"; } /* virtual */ Subdirectory GetDirectory() const { return AI_DIR; } /* virtual */ const char *GetScannerName() const { return "AIs"; } /* virtual */ void RegisterAPI(class Squirrel *engine); private: AIInfo *info_dummy; ///< The dummy AI. }; class AIScannerLibrary : public ScriptScanner { public: /* virtual */ void Initialize(); /** * Find a library in the pool. * @param library The library name to find. * @param version The version the library should have. * @return The library if found, NULL otherwise. */ class AILibrary *FindLibrary(const char *library, int version); protected: /* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last); /* virtual */ const char *GetFileName() const { return PATHSEP "library.nut"; } /* virtual */ Subdirectory GetDirectory() const { return AI_LIBRARY_DIR; } /* virtual */ const char *GetScannerName() const { return "AI Libraries"; } /* virtual */ void RegisterAPI(class Squirrel *engine); }; #endif /* AI_SCANNER_HPP */ openttd-1.5.3/src/subsidy.cpp0000644000000000000000000004472512627373441014675 0ustar rootroot/* $Id: subsidy.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 subsidy.cpp Handling of subsidies. */ #include "stdafx.h" #include "company_func.h" #include "industry.h" #include "town.h" #include "news_func.h" #include "ai/ai.hpp" #include "station_base.h" #include "strings_func.h" #include "window_func.h" #include "subsidy_base.h" #include "subsidy_func.h" #include "core/pool_func.hpp" #include "core/random_func.hpp" #include "game/game.hpp" #include "command_func.h" #include "string_func.h" #include "table/strings.h" #include "safeguards.h" SubsidyPool _subsidy_pool("Subsidy"); ///< Pool for the subsidies. INSTANTIATE_POOL_METHODS(Subsidy) /** * Marks subsidy as awarded, creates news and AI event * @param company awarded company */ void Subsidy::AwardTo(CompanyID company) { assert(!this->IsAwarded()); this->awarded = company; this->remaining = SUBSIDY_CONTRACT_MONTHS; char company_name[MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH]; SetDParam(0, company); GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); char *cn = stredup(company_name); /* Add a news item */ Pair reftype = SetupSubsidyDecodeParam(this, false); InjectDParam(1); SetDParamStr(0, cn); AddNewsItem( STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, this->src, (NewsReferenceType)reftype.b, this->dst, cn ); AI::BroadcastNewEvent(new ScriptEventSubsidyAwarded(this->index)); Game::NewEvent(new ScriptEventSubsidyAwarded(this->index)); InvalidateWindowData(WC_SUBSIDIES_LIST, 0); } /** * Setup the string parameters for printing the subsidy at the screen, and compute the news reference for the subsidy. * @param s %Subsidy being printed. * @param mode Unit of cargo used, \c true means general name, \c false means singular form. * @return Reference of the subsidy in the news system. */ Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode) { NewsReferenceType reftype1 = NR_NONE; NewsReferenceType reftype2 = NR_NONE; /* if mode is false, use the singular form */ const CargoSpec *cs = CargoSpec::Get(s->cargo_type); SetDParam(0, mode ? cs->name : cs->name_single); switch (s->src_type) { case ST_INDUSTRY: reftype1 = NR_INDUSTRY; SetDParam(1, STR_INDUSTRY_NAME); break; case ST_TOWN: reftype1 = NR_TOWN; SetDParam(1, STR_TOWN_NAME); break; default: NOT_REACHED(); } SetDParam(2, s->src); switch (s->dst_type) { case ST_INDUSTRY: reftype2 = NR_INDUSTRY; SetDParam(4, STR_INDUSTRY_NAME); break; case ST_TOWN: reftype2 = NR_TOWN; SetDParam(4, STR_TOWN_NAME); break; default: NOT_REACHED(); } SetDParam(5, s->dst); Pair p; p.a = reftype1; p.b = reftype2; return p; } /** * Sets a flag indicating that given town/industry is part of subsidised route. * @param type is it a town or an industry? * @param index index of town/industry * @param flag flag to set */ static inline void SetPartOfSubsidyFlag(SourceType type, SourceID index, PartOfSubsidy flag) { switch (type) { case ST_INDUSTRY: Industry::Get(index)->part_of_subsidy |= flag; return; case ST_TOWN: Town::Get(index)->cache.part_of_subsidy |= flag; return; default: NOT_REACHED(); } } /** Perform a full rebuild of the subsidies cache. */ void RebuildSubsidisedSourceAndDestinationCache() { Town *t; FOR_ALL_TOWNS(t) t->cache.part_of_subsidy = POS_NONE; Industry *i; FOR_ALL_INDUSTRIES(i) i->part_of_subsidy = POS_NONE; const Subsidy *s; FOR_ALL_SUBSIDIES(s) { SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC); SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST); } } /** * Delete the subsidies associated with a given cargo source type and id. * @param type Cargo source type of the id. * @param index Id to remove. */ void DeleteSubsidyWith(SourceType type, SourceID index) { bool dirty = false; Subsidy *s; FOR_ALL_SUBSIDIES(s) { if ((s->src_type == type && s->src == index) || (s->dst_type == type && s->dst == index)) { delete s; dirty = true; } } if (dirty) { InvalidateWindowData(WC_SUBSIDIES_LIST, 0); RebuildSubsidisedSourceAndDestinationCache(); } } /** * Check whether a specific subsidy already exists. * @param cargo Cargo type. * @param src_type Type of source of the cargo, affects interpretation of \a src. * @param src Id of the source. * @param dst_type Type of the destination of the cargo, affects interpretation of \a dst. * @param dst Id of the destination. * @return \c true if the subsidy already exists, \c false if not. */ static bool CheckSubsidyDuplicate(CargoID cargo, SourceType src_type, SourceID src, SourceType dst_type, SourceID dst) { const Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (s->cargo_type == cargo && s->src_type == src_type && s->src == src && s->dst_type == dst_type && s->dst == dst) { return true; } } return false; } /** * Checks if the source and destination of a subsidy are inside the distance limit. * @param src_type Type of \a src. * @param src Index of source. * @param dst_type Type of \a dst. * @param dst Index of destination. * @return True if they are inside the distance limit. */ static bool CheckSubsidyDistance(SourceType src_type, SourceID src, SourceType dst_type, SourceID dst) { TileIndex tile_src = (src_type == ST_TOWN) ? Town::Get(src)->xy : Industry::Get(src)->location.tile; TileIndex tile_dst = (dst_type == ST_TOWN) ? Town::Get(dst)->xy : Industry::Get(dst)->location.tile; return (DistanceManhattan(tile_src, tile_dst) <= SUBSIDY_MAX_DISTANCE); } /** * Creates a subsidy with the given parameters. * @param cid Subsidised cargo. * @param src_type Type of \a src. * @param src Index of source. * @param dst_type Type of \a dst. * @param dst Index of destination. */ void CreateSubsidy(CargoID cid, SourceType src_type, SourceID src, SourceType dst_type, SourceID dst) { Subsidy *s = new Subsidy(); s->cargo_type = cid; s->src_type = src_type; s->src = src; s->dst_type = dst_type; s->dst = dst; s->remaining = SUBSIDY_OFFER_MONTHS; s->awarded = INVALID_COMPANY; Pair reftype = SetupSubsidyDecodeParam(s, false); AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC); SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST); AI::BroadcastNewEvent(new ScriptEventSubsidyOffer(s->index)); Game::NewEvent(new ScriptEventSubsidyOffer(s->index)); InvalidateWindowData(WC_SUBSIDIES_LIST, 0); } /** * Create a new subsidy. * @param tile unused. * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 7) - SourceType of source. * - p1 = (bit 8 - 23) - SourceID of source. * - p1 = (bit 24 - 31) - CargoID of subsidy. * @param p2 various bitstuffed elements * - p2 = (bit 0 - 7) - SourceType of destination. * - p2 = (bit 8 - 23) - SourceID of destination. * @param text unused. * @return the cost of this operation or an error */ CommandCost CmdCreateSubsidy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (!Subsidy::CanAllocateItem()) return CMD_ERROR; CargoID cid = GB(p1, 24, 8); SourceType src_type = (SourceType)GB(p1, 0, 8); SourceID src = GB(p1, 8, 16); SourceType dst_type = (SourceType)GB(p2, 0, 8); SourceID dst = GB(p2, 8, 16); if (_current_company != OWNER_DEITY) return CMD_ERROR; if (cid >= NUM_CARGO || !::CargoSpec::Get(cid)->IsValid()) return CMD_ERROR; switch (src_type) { case ST_TOWN: if (!Town::IsValidID(src)) return CMD_ERROR; break; case ST_INDUSTRY: if (!Industry::IsValidID(src)) return CMD_ERROR; break; default: return CMD_ERROR; } switch (dst_type) { case ST_TOWN: if (!Town::IsValidID(dst)) return CMD_ERROR; break; case ST_INDUSTRY: if (!Industry::IsValidID(dst)) return CMD_ERROR; break; default: return CMD_ERROR; } if (flags & DC_EXEC) { CreateSubsidy(cid, src_type, src, dst_type, dst); } return CommandCost(); } /** * Tries to create a passenger subsidy between two towns. * @return True iff the subsidy was created. */ bool FindSubsidyPassengerRoute() { if (!Subsidy::CanAllocateItem()) return false; const Town *src = Town::GetRandom(); if (src->cache.population < SUBSIDY_PAX_MIN_POPULATION || src->GetPercentTransported(CT_PASSENGERS) > SUBSIDY_MAX_PCT_TRANSPORTED) { return false; } const Town *dst = Town::GetRandom(); if (dst->cache.population < SUBSIDY_PAX_MIN_POPULATION || src == dst) { return false; } if (DistanceManhattan(src->xy, dst->xy) > SUBSIDY_MAX_DISTANCE) return false; if (CheckSubsidyDuplicate(CT_PASSENGERS, ST_TOWN, src->index, ST_TOWN, dst->index)) return false; CreateSubsidy(CT_PASSENGERS, ST_TOWN, src->index, ST_TOWN, dst->index); return true; } bool FindSubsidyCargoDestination(CargoID cid, SourceType src_type, SourceID src); /** * Tries to create a cargo subsidy with a town as source. * @return True iff the subsidy was created. */ bool FindSubsidyTownCargoRoute() { if (!Subsidy::CanAllocateItem()) return false; SourceType src_type = ST_TOWN; /* Select a random town. */ const Town *src_town = Town::GetRandom(); uint32 town_cargo_produced = src_town->cargo_produced; /* Passenger subsidies are not handled here. */ ClrBit(town_cargo_produced, CT_PASSENGERS); /* No cargo produced at all? */ if (town_cargo_produced == 0) return false; /* Choose a random cargo that is produced in the town. */ uint8 cargo_number = RandomRange(CountBits(town_cargo_produced)); CargoID cid; FOR_EACH_SET_CARGO_ID(cid, town_cargo_produced) { if (cargo_number == 0) break; cargo_number--; } /* Avoid using invalid NewGRF cargoes. */ if (!CargoSpec::Get(cid)->IsValid() || _settings_game.linkgraph.GetDistributionType(cid) != DT_MANUAL) { return false; } /* Quit if the percentage transported is large enough. */ if (src_town->GetPercentTransported(cid) > SUBSIDY_MAX_PCT_TRANSPORTED) return false; SourceID src = src_town->index; return FindSubsidyCargoDestination(cid, src_type, src); } /** * Tries to create a cargo subsidy with an industry as source. * @return True iff the subsidy was created. */ bool FindSubsidyIndustryCargoRoute() { if (!Subsidy::CanAllocateItem()) return false; SourceType src_type = ST_INDUSTRY; /* Select a random industry. */ const Industry *src_ind = Industry::GetRandom(); if (src_ind == NULL) return false; uint trans, total; CargoID cid; /* Randomize cargo type */ if (src_ind->produced_cargo[1] != CT_INVALID && HasBit(Random(), 0)) { cid = src_ind->produced_cargo[1]; trans = src_ind->last_month_pct_transported[1]; total = src_ind->last_month_production[1]; } else { cid = src_ind->produced_cargo[0]; trans = src_ind->last_month_pct_transported[0]; total = src_ind->last_month_production[0]; } /* Quit if no production in this industry * or if the pct transported is already large enough * or if the cargo is automatically distributed */ if (total == 0 || trans > SUBSIDY_MAX_PCT_TRANSPORTED || cid == CT_INVALID || _settings_game.linkgraph.GetDistributionType(cid) != DT_MANUAL) { return false; } SourceID src = src_ind->index; return FindSubsidyCargoDestination(cid, src_type, src); } /** * Tries to find a suitable destination for the given source and cargo. * @param cid Subsidized cargo. * @param src_type Type of \a src. * @param src Index of source. * @return True iff the subsidy was created. */ bool FindSubsidyCargoDestination(CargoID cid, SourceType src_type, SourceID src) { /* Choose a random destination. Only consider towns if they can accept the cargo. */ SourceType dst_type = (HasBit(_town_cargoes_accepted, cid) && Chance16(1, 2)) ? ST_TOWN : ST_INDUSTRY; SourceID dst; switch (dst_type) { case ST_TOWN: { /* Select a random town. */ const Town *dst_town = Town::GetRandom(); /* Check if the town can accept this cargo. */ if (!HasBit(dst_town->cargo_accepted_total, cid)) return false; dst = dst_town->index; break; } case ST_INDUSTRY: { /* Select a random industry. */ const Industry *dst_ind = Industry::GetRandom(); /* The industry must accept the cargo */ if (dst_ind == NULL || (cid != dst_ind->accepts_cargo[0] && cid != dst_ind->accepts_cargo[1] && cid != dst_ind->accepts_cargo[2])) { return false; } dst = dst_ind->index; break; } default: NOT_REACHED(); } /* Check that the source and the destination are not the same. */ if (src_type == dst_type && src == dst) return false; /* Check distance between source and destination. */ if (!CheckSubsidyDistance(src_type, src, dst_type, dst)) return false; /* Avoid duplicate subsidies. */ if (CheckSubsidyDuplicate(cid, src_type, src, dst_type, dst)) return false; CreateSubsidy(cid, src_type, src, dst_type, dst); return true; } /** Perform the monthly update of open subsidies, and try to create a new one. */ void SubsidyMonthlyLoop() { bool modified = false; Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (--s->remaining == 0) { if (!s->IsAwarded()) { Pair reftype = SetupSubsidyDecodeParam(s, true); AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); AI::BroadcastNewEvent(new ScriptEventSubsidyOfferExpired(s->index)); Game::NewEvent(new ScriptEventSubsidyOfferExpired(s->index)); } else { if (s->awarded == _local_company) { Pair reftype = SetupSubsidyDecodeParam(s, true); AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); } AI::BroadcastNewEvent(new ScriptEventSubsidyExpired(s->index)); Game::NewEvent(new ScriptEventSubsidyExpired(s->index)); } delete s; modified = true; } } if (modified) { RebuildSubsidisedSourceAndDestinationCache(); } else if (_settings_game.linkgraph.distribution_pax != DT_MANUAL && _settings_game.linkgraph.distribution_mail != DT_MANUAL && _settings_game.linkgraph.distribution_armoured != DT_MANUAL && _settings_game.linkgraph.distribution_default != DT_MANUAL) { /* Return early if there are no manually distributed cargoes and if we * don't need to invalidate the subsidies window. */ return; } bool passenger_subsidy = false; bool town_subsidy = false; bool industry_subsidy = false; int random_chance = RandomRange(16); if (random_chance < 2 && _settings_game.linkgraph.distribution_pax == DT_MANUAL) { /* There is a 1/8 chance each month of generating a passenger subsidy. */ int n = 1000; do { passenger_subsidy = FindSubsidyPassengerRoute(); } while (!passenger_subsidy && n--); } else if (random_chance == 2) { /* Cargo subsidies with a town as a source have a 1/16 chance. */ int n = 1000; do { town_subsidy = FindSubsidyTownCargoRoute(); } while (!town_subsidy && n--); } else if (random_chance == 3) { /* Cargo subsidies with an industry as a source have a 1/16 chance. */ int n = 1000; do { industry_subsidy = FindSubsidyIndustryCargoRoute(); } while (!industry_subsidy && n--); } modified |= passenger_subsidy || town_subsidy || industry_subsidy; if (modified) InvalidateWindowData(WC_SUBSIDIES_LIST, 0); } /** * Tests whether given delivery is subsidised and possibly awards the subsidy to delivering company * @param cargo_type type of cargo * @param company company delivering the cargo * @param src_type type of \a src * @param src index of source * @param st station where the cargo is delivered to * @return is the delivery subsidised? */ bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st) { /* If the source isn't subsidised, don't continue */ if (src == INVALID_SOURCE) return false; switch (src_type) { case ST_INDUSTRY: if (!(Industry::Get(src)->part_of_subsidy & POS_SRC)) return false; break; case ST_TOWN: if (!(Town::Get(src)->cache.part_of_subsidy & POS_SRC)) return false; break; default: return false; } /* Remember all towns near this station (at least one house in its catchment radius) * which are destination of subsidised path. Do that only if needed */ SmallVector towns_near; if (!st->rect.IsEmpty()) { Subsidy *s; FOR_ALL_SUBSIDIES(s) { /* Don't create the cache if there is no applicable subsidy with town as destination */ if (s->dst_type != ST_TOWN) continue; if (s->cargo_type != cargo_type || s->src_type != src_type || s->src != src) continue; if (s->IsAwarded() && s->awarded != company) continue; Rect rect = st->GetCatchmentRect(); for (int y = rect.top; y <= rect.bottom; y++) { for (int x = rect.left; x <= rect.right; x++) { TileIndex tile = TileXY(x, y); if (!IsTileType(tile, MP_HOUSE)) continue; const Town *t = Town::GetByTile(tile); if (t->cache.part_of_subsidy & POS_DST) towns_near.Include(t); } } break; } } bool subsidised = false; /* Check if there's a (new) subsidy that applies. There can be more subsidies triggered by this delivery! * Think about the case that subsidies are A->B and A->C and station has both B and C in its catchment area */ Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (s->cargo_type == cargo_type && s->src_type == src_type && s->src == src && (!s->IsAwarded() || s->awarded == company)) { switch (s->dst_type) { case ST_INDUSTRY: for (const Industry * const *ip = st->industries_near.Begin(); ip != st->industries_near.End(); ip++) { if (s->dst == (*ip)->index) { assert((*ip)->part_of_subsidy & POS_DST); subsidised = true; if (!s->IsAwarded()) s->AwardTo(company); } } break; case ST_TOWN: for (const Town * const *tp = towns_near.Begin(); tp != towns_near.End(); tp++) { if (s->dst == (*tp)->index) { assert((*tp)->cache.part_of_subsidy & POS_DST); subsidised = true; if (!s->IsAwarded()) s->AwardTo(company); } } break; default: NOT_REACHED(); } } } return subsidised; } openttd-1.5.3/src/rev.cpp.in0000644000000000000000000000611512627373442014404 0ustar rootroot/* $Id: rev.cpp.in 27462 2015-12-01 19:36:48Z frosch $ */ /* * 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 rev.cpp Autogenerated file with the revision and such of OpenTTD. */ #include "stdafx.h" #include "core/bitmath_func.hpp" #include "rev.h" #include "safeguards.h" /** * Is this version of OpenTTD a release version? * @return True if it is a release version. */ bool IsReleasedVersion() { return HasBit(_openttd_newgrf_version, 19); } /** * The text version of OpenTTD's revision. * This will be either "..[-RC]", * "r[M][-]" or "norev000". * * The major, minor and build are the numbers that describe releases of * OpenTTD (like 0.5.3). "-RC" is used to flag release candidates. * * The revision number is fairly straight forward. The M is to show that * the binary is made from modified source code. The branch shows the * branch the revision is of and will not be there when it is trunk. * * norev000 is for non-releases that are made on systems without * subversion or sources that are not a checkout of subversion. */ const char _openttd_revision[] = "!!VERSION!!"; /** * The text version of OpenTTD's build date. * Updating the build date in this file is the safest as it generally gets * updated for each revision in contrary to most other files that only see * updates when they are actually changed themselves. */ const char _openttd_build_date[] = __DATE__ " " __TIME__; /** * Let us know if current build was modified. This detection * works even in the case when revision string is overridden by * --revision argument. * Value 0 means no modification, 1 is for unknown state * (compiling from sources without any version control software) * and 2 is for modified revision. */ const byte _openttd_revision_modified = !!MODIFIED!!; /** * The NewGRF revision of OTTD: * bits meaning. * 28-31 major version * 24-27 minor version * 20-23 build * 19 1 if it is a release, 0 if it is not. * 0-18 revision number; 0 for releases and when the revision is unknown. * * The 19th bit is there so the development/betas/alpha, etc. leading to a * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ const uint32 _openttd_newgrf_version = 1 << 28 | 5 << 24 | 3 << 20 | 1 << 19 | (!!REVISION!! & ((1 << 19) - 1)); #ifdef __MORPHOS__ /** * Variable used by MorphOS to show the version. */ extern const char morphos_versions_tag[] = "$VER: OpenTTD !!VERSION!! (!!DATE!!) OpenTTD Team [MorphOS, PowerPC]"; #endif openttd-1.5.3/src/rail_cmd.cpp0000644000000000000000000033232012627373446014761 0ustar rootroot/* $Id: rail_cmd.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 rail_cmd.cpp Handling of rail tiles. */ #include "stdafx.h" #include "cmd_helper.h" #include "viewport_func.h" #include "command_func.h" #include "depot_base.h" #include "pathfinder/yapf/yapf_cache.h" #include "newgrf_debug.h" #include "newgrf_railtype.h" #include "train.h" #include "autoslope.h" #include "water.h" #include "tunnelbridge_map.h" #include "vehicle_func.h" #include "sound_func.h" #include "tunnelbridge.h" #include "elrail_func.h" #include "town.h" #include "pbs.h" #include "company_base.h" #include "core/backup_type.hpp" #include "date_func.h" #include "strings_func.h" #include "company_gui.h" #include "object_map.h" #include "table/strings.h" #include "table/railtypes.h" #include "table/track_land.h" #include "safeguards.h" /** Helper type for lists/vectors of trains */ typedef SmallVector TrainList; RailtypeInfo _railtypes[RAILTYPE_END]; RailType _sorted_railtypes[RAILTYPE_END]; uint8 _sorted_railtypes_size; assert_compile(sizeof(_original_railtypes) <= sizeof(_railtypes)); /** Enum holding the signal offset in the sprite sheet according to the side it is representing. */ enum SignalOffsets { SIGNAL_TO_SOUTHWEST, SIGNAL_TO_NORTHEAST, SIGNAL_TO_SOUTHEAST, SIGNAL_TO_NORTHWEST, SIGNAL_TO_EAST, SIGNAL_TO_WEST, SIGNAL_TO_SOUTH, SIGNAL_TO_NORTH, }; /** * Reset all rail type information to its default values. */ void ResetRailTypes() { memset(_railtypes, 0, sizeof(_railtypes)); memcpy(_railtypes, _original_railtypes, sizeof(_original_railtypes)); } void ResolveRailTypeGUISprites(RailtypeInfo *rti) { SpriteID cursors_base = GetCustomRailSprite(rti, INVALID_TILE, RTSG_CURSORS); if (cursors_base != 0) { rti->gui_sprites.build_ns_rail = cursors_base + 0; rti->gui_sprites.build_x_rail = cursors_base + 1; rti->gui_sprites.build_ew_rail = cursors_base + 2; rti->gui_sprites.build_y_rail = cursors_base + 3; rti->gui_sprites.auto_rail = cursors_base + 4; rti->gui_sprites.build_depot = cursors_base + 5; rti->gui_sprites.build_tunnel = cursors_base + 6; rti->gui_sprites.convert_rail = cursors_base + 7; rti->cursor.rail_ns = cursors_base + 8; rti->cursor.rail_swne = cursors_base + 9; rti->cursor.rail_ew = cursors_base + 10; rti->cursor.rail_nwse = cursors_base + 11; rti->cursor.autorail = cursors_base + 12; rti->cursor.depot = cursors_base + 13; rti->cursor.tunnel = cursors_base + 14; rti->cursor.convert = cursors_base + 15; } /* Array of default GUI signal sprite numbers. */ const SpriteID _signal_lookup[2][SIGTYPE_END] = { {SPR_IMG_SIGNAL_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_EXIT, SPR_IMG_SIGNAL_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_PBS, SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY}, {SPR_IMG_SIGNAL_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_EXIT, SPR_IMG_SIGNAL_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_PBS, SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY}, }; for (SignalType type = SIGTYPE_NORMAL; type < SIGTYPE_END; type = (SignalType)(type + 1)) { for (SignalVariant var = SIG_ELECTRIC; var <= SIG_SEMAPHORE; var = (SignalVariant)(var + 1)) { SpriteID red = GetCustomSignalSprite(rti, INVALID_TILE, type, var, SIGNAL_STATE_RED, true); SpriteID green = GetCustomSignalSprite(rti, INVALID_TILE, type, var, SIGNAL_STATE_GREEN, true); rti->gui_sprites.signals[type][var][0] = (red != 0) ? red + SIGNAL_TO_SOUTH : _signal_lookup[var][type]; rti->gui_sprites.signals[type][var][1] = (green != 0) ? green + SIGNAL_TO_SOUTH : _signal_lookup[var][type] + 1; } } } /** * Compare railtypes based on their sorting order. * @param first The railtype to compare to. * @param second The railtype to compare. * @return True iff the first should be sorted before the second. */ static int CDECL CompareRailTypes(const RailType *first, const RailType *second) { return GetRailTypeInfo(*first)->sorting_order - GetRailTypeInfo(*second)->sorting_order; } /** * Resolve sprites of custom rail types */ void InitRailTypes() { for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { RailtypeInfo *rti = &_railtypes[rt]; ResolveRailTypeGUISprites(rti); } _sorted_railtypes_size = 0; for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { if (_railtypes[rt].label != 0) { _sorted_railtypes[_sorted_railtypes_size++] = rt; } } QSortT(_sorted_railtypes, _sorted_railtypes_size, CompareRailTypes); } /** * Allocate a new rail type label */ RailType AllocateRailType(RailTypeLabel label) { for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { RailtypeInfo *rti = &_railtypes[rt]; if (rti->label == 0) { /* Set up new rail type */ memcpy(rti, &_railtypes[RAILTYPE_RAIL], sizeof(*rti)); rti->label = label; /* Clear alternate label list. Can't use Reset() here as that would free * the data pointer of RAILTYPE_RAIL and not our new rail type. */ new (&rti->alternate_labels) RailTypeLabelList; /* Make us compatible with ourself. */ rti->powered_railtypes = (RailTypes)(1 << rt); rti->compatible_railtypes = (RailTypes)(1 << rt); /* We also introduce ourself. */ rti->introduces_railtypes = (RailTypes)(1 << rt); /* Default sort order; order of allocation, but with some * offsets so it's easier for NewGRF to pick a spot without * changing the order of other (original) rail types. * The << is so you can place other railtypes in between the * other railtypes, the 7 is to be able to place something * before the first (default) rail type. */ rti->sorting_order = rt << 4 | 7; return rt; } } return INVALID_RAILTYPE; } static const byte _track_sloped_sprites[14] = { 14, 15, 22, 13, 0, 21, 17, 12, 23, 0, 18, 20, 19, 16 }; /* 4 * --------- * |\ /| * | \ 1/ | * | \ / | * | \ / | * 16| \ |32 * | / \2 | * | / \ | * | / \ | * |/ \| * --------- * 8 */ /* MAP2 byte: abcd???? => Signal On? Same coding as map3lo * MAP3LO byte: abcd???? => Signal Exists? * a and b are for diagonals, upper and left, * one for each direction. (ie a == NE->SW, b == * SW->NE, or v.v., I don't know. b and c are * similar for lower and right. * MAP2 byte: ????abcd => Type of ground. * MAP3LO byte: ????abcd => Type of rail. * MAP5: 00abcdef => rail * 01abcdef => rail w/ signals * 10uuuuuu => unused * 11uuuudd => rail depot */ /** * Tests if a vehicle interacts with the specified track. * All track bits interact except parallel #TRACK_BIT_HORZ or #TRACK_BIT_VERT. * * @param tile The tile. * @param track The track. * @return Succeeded command (no train found), or a failed command (a train was found). */ static CommandCost EnsureNoTrainOnTrack(TileIndex tile, Track track) { TrackBits rail_bits = TrackToTrackBits(track); return EnsureNoTrainOnTrackBits(tile, rail_bits); } /** * Check that the new track bits may be built. * @param tile %Tile to build on. * @param to_build New track bits. * @param flags Flags of the operation. * @return Succeeded or failed command. */ static CommandCost CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags) { if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION); /* So, we have a tile with tracks on it (and possibly signals). Let's see * what tracks first */ TrackBits current = GetTrackBits(tile); // The current track layout. TrackBits future = current | to_build; // The track layout we want to build. /* Are we really building something new? */ if (current == future) { /* Nothing new is being built */ return_cmd_error(STR_ERROR_ALREADY_BUILT); } /* Let's see if we may build this */ if ((flags & DC_NO_RAIL_OVERLAP) || HasSignals(tile)) { /* If we are not allowed to overlap (flag is on for ai companies or we have * signals on the tile), check that */ if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) { return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST); } } /* Normally, we may overlap and any combination is valid */ return CommandCost(); } /** Valid TrackBits on a specific (non-steep)-slope without foundation */ static const TrackBits _valid_tracks_without_foundation[15] = { TRACK_BIT_ALL, TRACK_BIT_RIGHT, TRACK_BIT_UPPER, TRACK_BIT_X, TRACK_BIT_LEFT, TRACK_BIT_NONE, TRACK_BIT_Y, TRACK_BIT_LOWER, TRACK_BIT_LOWER, TRACK_BIT_Y, TRACK_BIT_NONE, TRACK_BIT_LEFT, TRACK_BIT_X, TRACK_BIT_UPPER, TRACK_BIT_RIGHT, }; /** Valid TrackBits on a specific (non-steep)-slope with leveled foundation */ static const TrackBits _valid_tracks_on_leveled_foundation[15] = { TRACK_BIT_NONE, TRACK_BIT_LEFT, TRACK_BIT_LOWER, TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_LEFT, TRACK_BIT_RIGHT, TRACK_BIT_ALL, TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_RIGHT, TRACK_BIT_ALL, TRACK_BIT_UPPER, TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_LEFT, TRACK_BIT_ALL, TRACK_BIT_ALL, TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT, TRACK_BIT_ALL, TRACK_BIT_ALL }; /** * Checks if a track combination is valid on a specific slope and returns the needed foundation. * * @param tileh Tile slope. * @param bits Trackbits. * @return Needed foundation or FOUNDATION_INVALID if track/slope combination is not allowed. */ Foundation GetRailFoundation(Slope tileh, TrackBits bits) { if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE; if (IsSteepSlope(tileh)) { /* Test for inclined foundations */ if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X; if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y; /* Get higher track */ Corner highest_corner = GetHighestSlopeCorner(tileh); TrackBits higher_track = CornerToTrackBits(highest_corner); /* Only higher track? */ if (bits == higher_track) return HalftileFoundation(highest_corner); /* Overlap with higher track? */ if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID; /* either lower track or both higher and lower track */ return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER); } else { if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE; bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0); Corner track_corner; switch (bits) { case TRACK_BIT_LEFT: track_corner = CORNER_W; break; case TRACK_BIT_LOWER: track_corner = CORNER_S; break; case TRACK_BIT_RIGHT: track_corner = CORNER_E; break; case TRACK_BIT_UPPER: track_corner = CORNER_N; break; case TRACK_BIT_HORZ: if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N); if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S); return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID); case TRACK_BIT_VERT: if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W); if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E); return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID); case TRACK_BIT_X: if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_X; return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID); case TRACK_BIT_Y: if (IsSlopeWithOneCornerRaised(tileh)) return FOUNDATION_INCLINED_Y; return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID); default: return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID); } /* Single diagonal track */ /* Track must be at least valid on leveled foundation */ if (!valid_on_leveled) return FOUNDATION_INVALID; /* If slope has three raised corners, build leveled foundation */ if (IsSlopeWithThreeCornersRaised(tileh)) return FOUNDATION_LEVELED; /* If neighboured corners of track_corner are lowered, build halftile foundation */ if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner); /* else special anti-zig-zag foundation */ return SpecialRailFoundation(track_corner); } } /** * Tests if a track can be build on a tile. * * @param tileh Tile slope. * @param rail_bits Tracks to build. * @param existing Tracks already built. * @param tile Tile (used for water test) * @return Error message or cost for foundation building. */ static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile) { /* don't allow building on the lower side of a coast */ if (GetFloodingBehaviour(tile) != FLOOD_NONE) { if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER); } Foundation f_new = GetRailFoundation(tileh, rail_bits | existing); /* check track/slope combination */ if ((f_new == FOUNDATION_INVALID) || ((f_new != FOUNDATION_NONE) && (!_settings_game.construction.build_on_slopes))) { return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } Foundation f_old = GetRailFoundation(tileh, existing); return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0); } /* Validate functions for rail building */ static inline bool ValParamTrackOrientation(Track track) { return IsValidTrack(track); } /** * Build a single piece of rail * @param tile tile to build on * @param flags operation to perform * @param p1 railtype of being built piece (normal, mono, maglev) * @param p2 rail track to build * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { RailType railtype = Extract(p1); Track track = Extract(p2); CommandCost cost(EXPENSES_CONSTRUCTION); if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR; Slope tileh = GetTileSlope(tile); TrackBits trackbit = TrackToTrackBits(track); switch (GetTileType(tile)) { case MP_RAILWAY: { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; if (!IsPlainRail(tile)) return CMD_ERROR; if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION); ret = CheckTrackCombination(tile, trackbit, flags); if (ret.Succeeded()) ret = EnsureNoTrainOnTrack(tile, track); if (ret.Failed()) return ret; ret = CheckRailSlope(tileh, trackbit, GetTrackBits(tile), tile); if (ret.Failed()) return ret; cost.AddCost(ret); /* If the rail types don't match, try to convert only if engines of * the new rail type are not powered on the present rail type and engines of * the present rail type are powered on the new rail type. */ if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) { if (HasPowerOnRail(GetRailType(tile), railtype)) { ret = DoCommand(tile, tile, railtype, flags, CMD_CONVERT_RAIL); if (ret.Failed()) return ret; cost.AddCost(ret); } else { return CMD_ERROR; } } if (flags & DC_EXEC) { SetRailGroundType(tile, RAIL_GROUND_BARREN); TrackBits bits = GetTrackBits(tile); SetTrackBits(tile, bits | trackbit); /* Subtract old infrastructure count. */ uint pieces = CountBits(bits); if (TracksOverlap(bits)) pieces *= pieces; Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= pieces; /* Add new infrastructure count. */ pieces = CountBits(bits | trackbit); if (TracksOverlap(bits | trackbit)) pieces *= pieces; Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += pieces; DirtyCompanyInfrastructureWindows(GetTileOwner(tile)); } break; } case MP_ROAD: { /* Level crossings may only be built on these slopes */ if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; if (IsNormalRoad(tile)) { if (HasRoadWorks(tile)) return_cmd_error(STR_ERROR_ROAD_WORKS_IN_PROGRESS); if (GetDisallowedRoadDirections(tile) != DRD_NONE) return_cmd_error(STR_ERROR_CROSSING_ON_ONEWAY_ROAD); if (RailNoLevelCrossings(railtype)) return_cmd_error(STR_ERROR_CROSSING_DISALLOWED); RoadTypes roadtypes = GetRoadTypes(tile); RoadBits road = GetRoadBits(tile, ROADTYPE_ROAD); RoadBits tram = GetRoadBits(tile, ROADTYPE_TRAM); if ((track == TRACK_X && ((road | tram) & ROAD_X) == 0) || (track == TRACK_Y && ((road | tram) & ROAD_Y) == 0)) { Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD); Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM); /* Disallow breaking end-of-line of someone else * so trams can still reverse on this tile. */ if (Company::IsValidID(tram_owner) && HasExactlyOneBit(tram)) { CommandCost ret = CheckOwnership(tram_owner); if (ret.Failed()) return ret; } /* Crossings must always have a road... */ uint num_new_road_pieces = 2 - CountBits(road); if (road == ROAD_NONE) road_owner = _current_company; roadtypes |= ROADTYPES_ROAD; /* ...but tram is not required. */ uint num_new_tram_pieces = (tram != ROAD_NONE) ? 2 - CountBits(tram) : 0; cost.AddCost((num_new_road_pieces + num_new_tram_pieces) * _price[PR_BUILD_ROAD]); if (flags & DC_EXEC) { MakeRoadCrossing(tile, road_owner, tram_owner, _current_company, (track == TRACK_X ? AXIS_Y : AXIS_X), railtype, roadtypes, GetTownIndex(tile)); UpdateLevelCrossing(tile, false); Company::Get(_current_company)->infrastructure.rail[railtype] += LEVELCROSSING_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(_current_company); if (num_new_road_pieces > 0 && Company::IsValidID(road_owner)) { Company::Get(road_owner)->infrastructure.road[ROADTYPE_ROAD] += num_new_road_pieces; DirtyCompanyInfrastructureWindows(road_owner); } if (num_new_tram_pieces > 0 && Company::IsValidID(tram_owner)) { Company::Get(tram_owner)->infrastructure.road[ROADTYPE_TRAM] += num_new_tram_pieces; DirtyCompanyInfrastructureWindows(tram_owner); } } break; } } if (IsLevelCrossing(tile) && GetCrossingRailBits(tile) == trackbit) { return_cmd_error(STR_ERROR_ALREADY_BUILT); } /* FALL THROUGH */ } default: { /* Will there be flat water on the lower halftile? */ bool water_ground = IsTileType(tile, MP_WATER) && IsSlopeWithOneCornerRaised(tileh); CommandCost ret = CheckRailSlope(tileh, trackbit, TRACK_BIT_NONE, tile); if (ret.Failed()) return ret; cost.AddCost(ret); ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); if (water_ground) { cost.AddCost(-_price[PR_CLEAR_WATER]); cost.AddCost(_price[PR_CLEAR_ROUGH]); } if (flags & DC_EXEC) { MakeRailNormal(tile, _current_company, trackbit, railtype); if (water_ground) SetRailGroundType(tile, RAIL_GROUND_WATER); Company::Get(_current_company)->infrastructure.rail[railtype]++; DirtyCompanyInfrastructureWindows(_current_company); } break; } } if (flags & DC_EXEC) { MarkTileDirtyByTile(tile); AddTrackToSignalBuffer(tile, track, _current_company); YapfNotifyTrackLayoutChange(tile, track); } cost.AddCost(RailBuildCost(railtype)); return cost; } /** * Remove a single piece of track * @param tile tile to remove track from * @param flags operation to perform * @param p1 unused * @param p2 rail orientation * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Track track = Extract(p2); CommandCost cost(EXPENSES_CONSTRUCTION); bool crossing = false; if (!ValParamTrackOrientation(track)) return CMD_ERROR; TrackBits trackbit = TrackToTrackBits(track); /* Need to read tile owner now because it may change when the rail is removed * Also, in case of floods, _current_company != owner * There may be invalid tiletype even in exec run (when removing long track), * so do not call GetTileOwner(tile) in any case here */ Owner owner = INVALID_OWNER; Train *v = NULL; switch (GetTileType(tile)) { case MP_ROAD: { if (!IsLevelCrossing(tile) || GetCrossingRailBits(tile) != trackbit) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); if (_current_company != OWNER_WATER) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } if (!(flags & DC_BANKRUPT)) { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; } cost.AddCost(RailClearCost(GetRailType(tile))); if (flags & DC_EXEC) { if (HasReservedTracks(tile, trackbit)) { v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } owner = GetTileOwner(tile); Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= LEVELCROSSING_TRACKBIT_FACTOR; DirtyCompanyInfrastructureWindows(owner); MakeRoadNormal(tile, GetCrossingRoadBits(tile), GetRoadTypes(tile), GetTownIndex(tile), GetRoadOwner(tile, ROADTYPE_ROAD), GetRoadOwner(tile, ROADTYPE_TRAM)); DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile); } break; } case MP_RAILWAY: { TrackBits present; /* There are no rails present at depots. */ if (!IsPlainRail(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); if (_current_company != OWNER_WATER) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } CommandCost ret = EnsureNoTrainOnTrack(tile, track); if (ret.Failed()) return ret; present = GetTrackBits(tile); if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true; cost.AddCost(RailClearCost(GetRailType(tile))); /* Charge extra to remove signals on the track, if they are there */ if (HasSignalOnTrack(tile, track)) { cost.AddCost(DoCommand(tile, track, 0, flags, CMD_REMOVE_SIGNALS)); } if (flags & DC_EXEC) { if (HasReservedTracks(tile, trackbit)) { v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } owner = GetTileOwner(tile); /* Subtract old infrastructure count. */ uint pieces = CountBits(present); if (TracksOverlap(present)) pieces *= pieces; Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= pieces; /* Add new infrastructure count. */ present ^= trackbit; pieces = CountBits(present); if (TracksOverlap(present)) pieces *= pieces; Company::Get(owner)->infrastructure.rail[GetRailType(tile)] += pieces; DirtyCompanyInfrastructureWindows(owner); if (present == 0) { Slope tileh = GetTileSlope(tile); /* If there is flat water on the lower halftile, convert the tile to shore so the water remains */ if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)) { MakeShore(tile); } else { DoClearSquare(tile); } DeleteNewGRFInspectWindow(GSF_RAILTYPES, tile); } else { SetTrackBits(tile, present); SetTrackReservation(tile, GetRailReservationTrackBits(tile) & present); } } break; } default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); } if (flags & DC_EXEC) { /* if we got that far, 'owner' variable is set correctly */ assert(Company::IsValidID(owner)); MarkTileDirtyByTile(tile); if (crossing) { /* crossing is set when only TRACK_BIT_X and TRACK_BIT_Y are set. As we * are removing one of these pieces, we'll need to update signals for * both directions explicitly, as after the track is removed it won't * 'connect' with the other piece. */ AddTrackToSignalBuffer(tile, TRACK_X, owner); AddTrackToSignalBuffer(tile, TRACK_Y, owner); YapfNotifyTrackLayoutChange(tile, TRACK_X); YapfNotifyTrackLayoutChange(tile, TRACK_Y); } else { AddTrackToSignalBuffer(tile, track, owner); YapfNotifyTrackLayoutChange(tile, track); } if (v != NULL) TryPathReserve(v, true); } return cost; } /** * Called from water_cmd if a non-flat rail-tile gets flooded and should be converted to shore. * The function floods the lower halftile, if the tile has a halftile foundation. * * @param t The tile to flood. * @return true if something was flooded. */ bool FloodHalftile(TileIndex t) { assert(IsPlainRailTile(t)); bool flooded = false; if (GetRailGroundType(t) == RAIL_GROUND_WATER) return flooded; Slope tileh = GetTileSlope(t); TrackBits rail_bits = GetTrackBits(t); if (IsSlopeWithOneCornerRaised(tileh)) { TrackBits lower_track = CornerToTrackBits(OppositeCorner(GetHighestSlopeCorner(tileh))); TrackBits to_remove = lower_track & rail_bits; if (to_remove != 0) { Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); flooded = DoCommand(t, 0, FIND_FIRST_BIT(to_remove), DC_EXEC, CMD_REMOVE_SINGLE_RAIL).Succeeded(); cur_company.Restore(); if (!flooded) return flooded; // not yet floodable rail_bits = rail_bits & ~to_remove; if (rail_bits == 0) { MakeShore(t); MarkTileDirtyByTile(t); return flooded; } } if (IsNonContinuousFoundation(GetRailFoundation(tileh, rail_bits))) { flooded = true; SetRailGroundType(t, RAIL_GROUND_WATER); MarkTileDirtyByTile(t); } } else { /* Make shore on steep slopes and 'three-corners-raised'-slopes. */ if (ApplyFoundationToSlope(GetRailFoundation(tileh, rail_bits), &tileh) == 0) { if (IsSteepSlope(tileh) || IsSlopeWithThreeCornersRaised(tileh)) { flooded = true; SetRailGroundType(t, RAIL_GROUND_WATER); MarkTileDirtyByTile(t); } } } return flooded; } static const TileIndexDiffC _trackdelta[] = { { -1, 0 }, { 0, 1 }, { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, 1 }, { 0, 0 }, { 0, 0 }, { 1, 0 }, { 0, -1 }, { 0, -1 }, { 1, 0 }, { 0, -1 }, { -1, 0 }, { 0, 0 }, { 0, 0 } }; static CommandCost ValidateAutoDrag(Trackdir *trackdir, TileIndex start, TileIndex end) { int x = TileX(start); int y = TileY(start); int ex = TileX(end); int ey = TileY(end); if (!ValParamTrackOrientation(TrackdirToTrack(*trackdir))) return CMD_ERROR; /* calculate delta x,y from start to end tile */ int dx = ex - x; int dy = ey - y; /* calculate delta x,y for the first direction */ int trdx = _trackdelta[*trackdir].x; int trdy = _trackdelta[*trackdir].y; if (!IsDiagonalTrackdir(*trackdir)) { trdx += _trackdelta[*trackdir ^ 1].x; trdy += _trackdelta[*trackdir ^ 1].y; } /* validate the direction */ while ((trdx <= 0 && dx > 0) || (trdx >= 0 && dx < 0) || (trdy <= 0 && dy > 0) || (trdy >= 0 && dy < 0)) { if (!HasBit(*trackdir, 3)) { // first direction is invalid, try the other SetBit(*trackdir, 3); // reverse the direction trdx = -trdx; trdy = -trdy; } else { // other direction is invalid too, invalid drag return CMD_ERROR; } } /* (for diagonal tracks, this is already made sure of by above test), but: * for non-diagonal tracks, check if the start and end tile are on 1 line */ if (!IsDiagonalTrackdir(*trackdir)) { trdx = _trackdelta[*trackdir].x; trdy = _trackdelta[*trackdir].y; if (abs(dx) != abs(dy) && abs(dx) + abs(trdy) != abs(dy) + abs(trdx)) return CMD_ERROR; } return CommandCost(); } /** * Build or remove a stretch of railroad tracks. * @param tile start tile of drag * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0-3) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev), only used for building * - p2 = (bit 4-6) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 7) - 0 = build, 1 = remove tracks * - p2 = (bit 8) - 0 = build up to an obstacle, 1 = fail if an obstacle is found (used for AIs). * @param text unused * @return the cost of this operation or an error */ static CommandCost CmdRailTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CommandCost total_cost(EXPENSES_CONSTRUCTION); Track track = Extract(p2); bool remove = HasBit(p2, 7); RailType railtype = Extract(p2); if ((!remove && !ValParamRailtype(railtype)) || !ValParamTrackOrientation(track)) return CMD_ERROR; if (p1 >= MapSize()) return CMD_ERROR; TileIndex end_tile = p1; Trackdir trackdir = TrackToTrackdir(track); CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile); if (ret.Failed()) return ret; bool had_success = false; CommandCost last_error = CMD_ERROR; for (;;) { CommandCost ret = DoCommand(tile, remove ? 0 : railtype, TrackdirToTrack(trackdir), flags, remove ? CMD_REMOVE_SINGLE_RAIL : CMD_BUILD_SINGLE_RAIL); if (ret.Failed()) { last_error = ret; if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) { if (HasBit(p2, 8)) return last_error; break; } /* Ownership errors are more important. */ if (last_error.GetErrorMessage() == STR_ERROR_OWNED_BY && remove) break; } else { had_success = true; total_cost.AddCost(ret); } if (tile == end_tile) break; tile += ToTileIndexDiff(_trackdelta[trackdir]); /* toggle railbit for the non-diagonal tracks */ if (!IsDiagonalTrackdir(trackdir)) ToggleBit(trackdir, 0); } if (had_success) return total_cost; return last_error; } /** * Build rail on a stretch of track. * Stub for the unified rail builder/remover * @param tile start tile of drag * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0-3) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev) * - p2 = (bit 4-6) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 7) - 0 = build, 1 = remove tracks * @param text unused * @return the cost of this operation or an error * @see CmdRailTrackHelper */ CommandCost CmdBuildRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { return CmdRailTrackHelper(tile, flags, p1, ClrBit(p2, 7), text); } /** * Build rail on a stretch of track. * Stub for the unified rail builder/remover * @param tile start tile of drag * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0-3) - railroad type normal/maglev (0 = normal, 1 = mono, 2 = maglev), only used for building * - p2 = (bit 4-6) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 7) - 0 = build, 1 = remove tracks * @param text unused * @return the cost of this operation or an error * @see CmdRailTrackHelper */ CommandCost CmdRemoveRailroadTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { return CmdRailTrackHelper(tile, flags, p1, SetBit(p2, 7), text); } /** * Build a train depot * @param tile position of the train depot * @param flags operation to perform * @param p1 rail type * @param p2 bit 0..1 entrance direction (DiagDirection) * @param text unused * @return the cost of this operation or an error * * @todo When checking for the tile slope, * distinguish between "Flat land required" and "land sloped in wrong direction" */ CommandCost CmdBuildTrainDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* check railtype and valid direction for depot (0 through 3), 4 in total */ RailType railtype = Extract(p1); if (!ValParamRailtype(railtype)) return CMD_ERROR; Slope tileh = GetTileSlope(tile); DiagDirection dir = Extract(p2); /* Prohibit construction if * The tile is non-flat AND * 1) build-on-slopes is disabled * 2) the tile is steep i.e. spans two height levels * 3) the exit points in the wrong direction */ if (tileh != SLOPE_FLAT && ( !_settings_game.construction.build_on_slopes || !CanBuildDepotByTileh(dir, tileh) )) { return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); } CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (cost.Failed()) return cost; if (IsBridgeAbove(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); if (!Depot::CanAllocateItem()) return CMD_ERROR; if (flags & DC_EXEC) { Depot *d = new Depot(tile); d->build_date = _date; MakeRailDepot(tile, _current_company, d->index, dir, railtype); MarkTileDirtyByTile(tile); MakeDefaultName(d); Company::Get(_current_company)->infrastructure.rail[railtype]++; DirtyCompanyInfrastructureWindows(_current_company); AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_company); YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir)); } cost.AddCost(_price[PR_BUILD_DEPOT_TRAIN]); cost.AddCost(RailBuildCost(railtype)); return cost; } /** * Build signals, alternate between double/single, signal/semaphore, * pre/exit/combo-signals, and what-else not. If the rail piece does not * have any signals, bit 4 (cycle signal-type) is ignored * @param tile tile where to build the signals * @param flags operation to perform * @param p1 various bitstuffed elements * - p1 = (bit 0-2) - track-orientation, valid values: 0-5 (Track enum) * - p1 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal or (for bit 7) toggle variant (CTRL-toggle) * - p1 = (bit 4) - 0 = signals, 1 = semaphores * - p1 = (bit 5-7) - type of the signal, for valid values see enum SignalType in rail_map.h * - p1 = (bit 8) - convert the present signal type and variant * - p1 = (bit 9-11)- start cycle from this signal type * - p1 = (bit 12-14)-wrap around after this signal type * - p1 = (bit 15-16)-cycle the signal direction this many times * - p1 = (bit 17) - 1 = don't modify an existing signal but don't fail either, 0 = always set new signal type * @param p2 used for CmdBuildManySignals() to copy direction of first signal * @param text unused * @return the cost of this operation or an error * @todo p2 should be replaced by two bits for "along" and "against" the track. */ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Track track = Extract(p1); bool ctrl_pressed = HasBit(p1, 3); // was the CTRL button pressed SignalVariant sigvar = (ctrl_pressed ^ HasBit(p1, 4)) ? SIG_SEMAPHORE : SIG_ELECTRIC; // the signal variant of the new signal SignalType sigtype = Extract(p1); // the signal type of the new signal bool convert_signal = HasBit(p1, 8); // convert button pressed SignalType cycle_start = Extract(p1); SignalType cycle_stop = Extract(p1); uint num_dir_cycle = GB(p1, 15, 2); if (sigtype > SIGTYPE_LAST) return CMD_ERROR; if (cycle_start > cycle_stop || cycle_stop > SIGTYPE_LAST) return CMD_ERROR; /* You can only build signals on plain rail tiles, and the selected track must exist */ if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) { return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); } /* Protect against invalid signal copying */ if (p2 != 0 && (p2 & SignalOnTrack(track)) == 0) return CMD_ERROR; CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; /* See if this is a valid track combination for signals (no overlap) */ if (TracksOverlap(GetTrackBits(tile))) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); /* In case we don't want to change an existing signal, return without error. */ if (HasBit(p1, 17) && HasSignalOnTrack(tile, track)) return CommandCost(); /* you can not convert a signal if no signal is on track */ if (convert_signal && !HasSignalOnTrack(tile, track)) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); CommandCost cost; if (!HasSignalOnTrack(tile, track)) { /* build new signals */ cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]); } else { if (p2 != 0 && sigvar != GetSignalVariant(tile, track)) { /* convert signals <-> semaphores */ cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]); } else if (convert_signal) { /* convert button pressed */ if (ctrl_pressed || GetSignalVariant(tile, track) != sigvar) { /* convert electric <-> semaphore */ cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] + _price[PR_CLEAR_SIGNALS]); } else { /* it is free to change signal type: normal-pre-exit-combo */ cost = CommandCost(); } } else { /* it is free to change orientation/pre-exit-combo signals */ cost = CommandCost(); } } if (flags & DC_EXEC) { Train *v = NULL; /* The new/changed signal could block our path. As this can lead to * stale reservations, we clear the path reservation here and try * to redo it later on. */ if (HasReservedTracks(tile, TrackToTrackBits(track))) { v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } if (!HasSignals(tile)) { /* there are no signals at all on this tile yet */ SetHasSignals(tile, true); SetSignalStates(tile, 0xF); // all signals are on SetPresentSignals(tile, 0); // no signals built by default SetSignalType(tile, track, sigtype); SetSignalVariant(tile, track, sigvar); } /* Subtract old signal infrastructure count. */ Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile)); if (p2 == 0) { if (!HasSignalOnTrack(tile, track)) { /* build new signals */ SetPresentSignals(tile, GetPresentSignals(tile) | (IsPbsSignal(sigtype) ? KillFirstBit(SignalOnTrack(track)) : SignalOnTrack(track))); SetSignalType(tile, track, sigtype); SetSignalVariant(tile, track, sigvar); while (num_dir_cycle-- > 0) CycleSignalSide(tile, track); } else { if (convert_signal) { /* convert signal button pressed */ if (ctrl_pressed) { /* toggle the present signal variant: SIG_ELECTRIC <-> SIG_SEMAPHORE */ SetSignalVariant(tile, track, (GetSignalVariant(tile, track) == SIG_ELECTRIC) ? SIG_SEMAPHORE : SIG_ELECTRIC); /* Query current signal type so the check for PBS signals below works. */ sigtype = GetSignalType(tile, track); } else { /* convert the present signal to the chosen type and variant */ SetSignalType(tile, track, sigtype); SetSignalVariant(tile, track, sigvar); if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) { SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track))); } } } else if (ctrl_pressed) { /* cycle between cycle_start and cycle_end */ sigtype = (SignalType)(GetSignalType(tile, track) + 1); if (sigtype < cycle_start || sigtype > cycle_stop) sigtype = cycle_start; SetSignalType(tile, track, sigtype); if (IsPbsSignal(sigtype) && (GetPresentSignals(tile) & SignalOnTrack(track)) == SignalOnTrack(track)) { SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | KillFirstBit(SignalOnTrack(track))); } } else { /* cycle the signal side: both -> left -> right -> both -> ... */ CycleSignalSide(tile, track); /* Query current signal type so the check for PBS signals below works. */ sigtype = GetSignalType(tile, track); } } } else { /* If CmdBuildManySignals is called with copying signals, just copy the * direction of the first signal given as parameter by CmdBuildManySignals */ SetPresentSignals(tile, (GetPresentSignals(tile) & ~SignalOnTrack(track)) | (p2 & SignalOnTrack(track))); SetSignalVariant(tile, track, sigvar); SetSignalType(tile, track, sigtype); } /* Add new signal infrastructure count. */ Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile)); DirtyCompanyInfrastructureWindows(GetTileOwner(tile)); if (IsPbsSignal(sigtype)) { /* PBS signals should show red unless they are on reserved tiles without a train. */ uint mask = GetPresentSignals(tile) & SignalOnTrack(track); SetSignalStates(tile, (GetSignalStates(tile) & ~mask) | ((HasBit(GetRailReservationTrackBits(tile), track) && EnsureNoVehicleOnGround(tile).Succeeded() ? UINT_MAX : 0) & mask)); } MarkTileDirtyByTile(tile); AddTrackToSignalBuffer(tile, track, _current_company); YapfNotifyTrackLayoutChange(tile, track); if (v != NULL) { /* Extend the train's path if it's not stopped or loading, or not at a safe position. */ if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) || !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) { TryPathReserve(v, true); } } } return cost; } static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove) { tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]); if (tile == INVALID_TILE) return false; /* Check for track bits on the new tile */ TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)); if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false; trackdirbits &= TrackdirReachesTrackdirs(trackdir); /* No track bits, must stop */ if (trackdirbits == TRACKDIR_BIT_NONE) return false; /* Get the first track dir */ trackdir = RemoveFirstTrackdir(&trackdirbits); /* Any left? It's a junction so we stop */ if (trackdirbits != TRACKDIR_BIT_NONE) return false; switch (GetTileType(tile)) { case MP_RAILWAY: if (IsRailDepot(tile)) return false; if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false; signal_ctr++; if (IsDiagonalTrackdir(trackdir)) { signal_ctr++; /* Ensure signal_ctr even so X and Y pieces get signals */ ClrBit(signal_ctr, 0); } return true; case MP_ROAD: if (!IsLevelCrossing(tile)) return false; signal_ctr += 2; return true; case MP_TUNNELBRIDGE: { TileIndex orig_tile = tile; // backup old value if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false; if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false; /* Skip to end of tunnel or bridge * note that tile is a parameter by reference, so it must be updated */ tile = GetOtherTunnelBridgeEnd(tile); signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2; return true; } default: return false; } } /** * Build many signals by dragging; AutoSignals * @param tile start tile of drag * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0- 2) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) * - p2 = (bit 4) - 0 = signals, 1 = semaphores * - p2 = (bit 5) - 0 = build, 1 = remove signals * - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill * - p2 = (bit 7- 9) - default signal type * - p2 = (bit 10) - 0 = keep fixed distance, 1 = minimise gaps between signals * - p2 = (bit 24-31) - user defined signals_density * @param text unused * @return the cost of this operation or an error */ static CommandCost CmdSignalTrackHelper(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CommandCost total_cost(EXPENSES_CONSTRUCTION); TileIndex start_tile = tile; Track track = Extract(p2); bool mode = HasBit(p2, 3); bool semaphores = HasBit(p2, 4); bool remove = HasBit(p2, 5); bool autofill = HasBit(p2, 6); bool minimise_gaps = HasBit(p2, 10); byte signal_density = GB(p2, 24, 8); if (p1 >= MapSize() || !ValParamTrackOrientation(track)) return CMD_ERROR; TileIndex end_tile = p1; if (signal_density == 0 || signal_density > 20) return CMD_ERROR; if (!IsPlainRailTile(tile)) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); /* for vertical/horizontal tracks, double the given signals density * since the original amount will be too dense (shorter tracks) */ signal_density *= 2; Trackdir trackdir = TrackToTrackdir(track); CommandCost ret = ValidateAutoDrag(&trackdir, tile, end_tile); if (ret.Failed()) return ret; track = TrackdirToTrack(trackdir); // trackdir might have changed, keep track in sync Trackdir start_trackdir = trackdir; /* Must start on a valid track to be able to avoid loops */ if (!HasTrack(tile, track)) return CMD_ERROR; SignalType sigtype = (SignalType)GB(p2, 7, 3); if (sigtype > SIGTYPE_LAST) return CMD_ERROR; byte signals; /* copy the signal-style of the first rail-piece if existing */ if (HasSignalOnTrack(tile, track)) { signals = GetPresentSignals(tile) & SignalOnTrack(track); assert(signals != 0); /* copy signal/semaphores style (independent of CTRL) */ semaphores = GetSignalVariant(tile, track) != SIG_ELECTRIC; sigtype = GetSignalType(tile, track); /* Don't but copy entry or exit-signal type */ if (sigtype == SIGTYPE_ENTRY || sigtype == SIGTYPE_EXIT) sigtype = SIGTYPE_NORMAL; } else { // no signals exist, drag a two-way signal stretch signals = IsPbsSignal(sigtype) ? SignalAlongTrackdir(trackdir) : SignalOnTrack(track); } byte signal_dir = 0; if (signals & SignalAlongTrackdir(trackdir)) SetBit(signal_dir, 0); if (signals & SignalAgainstTrackdir(trackdir)) SetBit(signal_dir, 1); /* signal_ctr - amount of tiles already processed * last_used_ctr - amount of tiles before previously placed signal * signals_density - setting to put signal on every Nth tile (double space on |, -- tracks) * last_suitable_ctr - amount of tiles before last possible signal place * last_suitable_tile - last tile where it is possible to place a signal * last_suitable_trackdir - trackdir of the last tile ********** * trackdir - trackdir to build with autorail * semaphores - semaphores or signals * signals - is there a signal/semaphore on the first tile, copy its style (two-way/single-way) * and convert all others to semaphore/signal * remove - 1 remove signals, 0 build signals */ int signal_ctr = 0; int last_used_ctr = INT_MIN; // initially INT_MIN to force building/removing at the first tile int last_suitable_ctr = 0; TileIndex last_suitable_tile = INVALID_TILE; Trackdir last_suitable_trackdir = INVALID_TRACKDIR; CommandCost last_error = CMD_ERROR; bool had_success = false; for (;;) { /* only build/remove signals with the specified density */ if (remove || minimise_gaps || signal_ctr % signal_density == 0) { uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3); SB(p1, 3, 1, mode); SB(p1, 4, 1, semaphores); SB(p1, 5, 3, sigtype); if (!remove && signal_ctr == 0) SetBit(p1, 17); /* Pick the correct orientation for the track direction */ signals = 0; if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir); if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir); /* Test tiles in between for suitability as well if minimising gaps. */ bool test_only = !remove && minimise_gaps && signal_ctr < (last_used_ctr + signal_density); CommandCost ret = DoCommand(tile, p1, signals, test_only ? flags & ~DC_EXEC : flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); if (ret.Succeeded()) { /* Remember last track piece where we can place a signal. */ last_suitable_ctr = signal_ctr; last_suitable_tile = tile; last_suitable_trackdir = trackdir; } else if (!test_only && last_suitable_tile != INVALID_TILE) { /* If a signal can't be placed, place it at the last possible position. */ SB(p1, 0, 3, TrackdirToTrack(last_suitable_trackdir)); ClrBit(p1, 17); /* Pick the correct orientation for the track direction. */ signals = 0; if (HasBit(signal_dir, 0)) signals |= SignalAlongTrackdir(last_suitable_trackdir); if (HasBit(signal_dir, 1)) signals |= SignalAgainstTrackdir(last_suitable_trackdir); ret = DoCommand(last_suitable_tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); } /* Collect cost. */ if (!test_only) { /* Be user-friendly and try placing signals as much as possible */ if (ret.Succeeded()) { had_success = true; total_cost.AddCost(ret); last_used_ctr = last_suitable_ctr; last_suitable_tile = INVALID_TILE; } else { /* The "No railway" error is the least important one. */ if (ret.GetErrorMessage() != STR_ERROR_THERE_IS_NO_RAILROAD_TRACK || last_error.GetErrorMessage() == INVALID_STRING_ID) { last_error = ret; } } } } if (autofill) { if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break; /* Prevent possible loops */ if (tile == start_tile && trackdir == start_trackdir) break; } else { if (tile == end_tile) break; tile += ToTileIndexDiff(_trackdelta[trackdir]); signal_ctr++; /* toggle railbit for the non-diagonal tracks (|, -- tracks) */ if (IsDiagonalTrackdir(trackdir)) { signal_ctr++; } else { ToggleBit(trackdir, 0); } } } return had_success ? total_cost : last_error; } /** * Build signals on a stretch of track. * Stub for the unified signal builder/remover * @param tile start tile of drag * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0- 2) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) * - p2 = (bit 4) - 0 = signals, 1 = semaphores * - p2 = (bit 5) - 0 = build, 1 = remove signals * - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill * - p2 = (bit 7- 9) - default signal type * - p2 = (bit 24-31) - user defined signals_density * @param text unused * @return the cost of this operation or an error * @see CmdSignalTrackHelper */ CommandCost CmdBuildSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { return CmdSignalTrackHelper(tile, flags, p1, p2, text); } /** * Remove signals * @param tile coordinates where signal is being deleted from * @param flags operation to perform * @param p1 various bitstuffed elements, only track information is used * - (bit 0- 2) - track-orientation, valid values: 0-5 (Track enum) * - (bit 3) - override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) * - (bit 4) - 0 = signals, 1 = semaphores * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRemoveSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Track track = Extract(p1); if (!ValParamTrackOrientation(track) || !IsPlainRailTile(tile) || !HasTrack(tile, track)) { return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK); } if (!HasSignalOnTrack(tile, track)) { return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS); } /* Only water can remove signals from anyone */ if (_current_company != OWNER_WATER) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } /* Do it? */ if (flags & DC_EXEC) { Train *v = NULL; if (HasReservedTracks(tile, TrackToTrackBits(track))) { v = GetTrainForReservation(tile, track); } else if (IsPbsSignal(GetSignalType(tile, track))) { /* PBS signal, might be the end of a path reservation. */ Trackdir td = TrackToTrackdir(track); for (int i = 0; v == NULL && i < 2; i++, td = ReverseTrackdir(td)) { /* Only test the active signal side. */ if (!HasSignalOnTrackdir(tile, ReverseTrackdir(td))) continue; TileIndex next = TileAddByDiagDir(tile, TrackdirToExitdir(td)); TrackBits tracks = TrackdirBitsToTrackBits(TrackdirReachesTrackdirs(td)); if (HasReservedTracks(next, tracks)) { v = GetTrainForReservation(next, TrackBitsToTrack(GetReservedTrackbits(next) & tracks)); } } } Company::Get(GetTileOwner(tile))->infrastructure.signal -= CountBits(GetPresentSignals(tile)); SetPresentSignals(tile, GetPresentSignals(tile) & ~SignalOnTrack(track)); Company::Get(GetTileOwner(tile))->infrastructure.signal += CountBits(GetPresentSignals(tile)); DirtyCompanyInfrastructureWindows(GetTileOwner(tile)); /* removed last signal from tile? */ if (GetPresentSignals(tile) == 0) { SetSignalStates(tile, 0); SetHasSignals(tile, false); SetSignalVariant(tile, INVALID_TRACK, SIG_ELECTRIC); // remove any possible semaphores } AddTrackToSignalBuffer(tile, track, GetTileOwner(tile)); YapfNotifyTrackLayoutChange(tile, track); if (v != NULL) TryPathReserve(v, false); MarkTileDirtyByTile(tile); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_SIGNALS]); } /** * Remove signals on a stretch of track. * Stub for the unified signal builder/remover * @param tile start tile of drag * @param flags operation to perform * @param p1 end tile of drag * @param p2 various bitstuffed elements * - p2 = (bit 0- 2) - track-orientation, valid values: 0-5 (Track enum) * - p2 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) * - p2 = (bit 4) - 0 = signals, 1 = semaphores * - p2 = (bit 5) - 0 = build, 1 = remove signals * - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill * - p2 = (bit 7- 9) - default signal type * - p2 = (bit 24-31) - user defined signals_density * @param text unused * @return the cost of this operation or an error * @see CmdSignalTrackHelper */ CommandCost CmdRemoveSignalTrack(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { return CmdSignalTrackHelper(tile, flags, p1, SetBit(p2, 5), text); // bit 5 is remove bit } /** Update power of train under which is the railtype being converted */ static Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data) { if (v->type != VEH_TRAIN) return NULL; TrainList *affected_trains = static_cast(data); affected_trains->Include(Train::From(v)->First()); return NULL; } /** * Convert one rail type to the other. You can convert normal rail to * monorail/maglev easily or vice-versa. * @param tile end tile of rail conversion drag * @param flags operation to perform * @param p1 start tile of drag * @param p2 various bitstuffed elements: * - p2 = (bit 0- 3) new railtype to convert to. * - p2 = (bit 4) build diagonally or not. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { RailType totype = Extract(p2); TileIndex area_start = p1; TileIndex area_end = tile; bool diagonal = HasBit(p2, 4); if (!ValParamRailtype(totype)) return CMD_ERROR; if (area_start >= MapSize()) return CMD_ERROR; TrainList affected_trains; CommandCost cost(EXPENSES_CONSTRUCTION); CommandCost error = CommandCost(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK); // by default, there is no track to convert. TileIterator *iter = diagonal ? (TileIterator *)new DiagonalTileIterator(area_start, area_end) : new OrthogonalTileIterator(area_start, area_end); for (; (tile = *iter) != INVALID_TILE; ++(*iter)) { TileType tt = GetTileType(tile); /* Check if there is any track on tile */ switch (tt) { case MP_RAILWAY: break; case MP_STATION: if (!HasStationRail(tile)) continue; break; case MP_ROAD: if (!IsLevelCrossing(tile)) continue; if (RailNoLevelCrossings(totype)) { error.MakeError(STR_ERROR_CROSSING_DISALLOWED); continue; } break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue; break; default: continue; } /* Original railtype we are converting from */ RailType type = GetRailType(tile); /* Converting to the same type or converting 'hidden' elrail -> rail */ if (type == totype || (_settings_game.vehicle.disable_elrails && totype == RAILTYPE_RAIL && type == RAILTYPE_ELECTRIC)) continue; /* Trying to convert other's rail */ CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) { error = ret; continue; } SmallVector vehicles_affected; /* Vehicle on the tile when not converting Rail <-> ElRail * Tunnels and bridges have special check later */ if (tt != MP_TUNNELBRIDGE) { if (!IsCompatibleRail(type, totype)) { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) { error = ret; continue; } } if (flags & DC_EXEC) { // we can safely convert, too TrackBits reserved = GetReservedTrackbits(tile); Track track; while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) { Train *v = GetTrainForReservation(tile, track); if (v != NULL && !HasPowerOnRail(v->railtype, totype)) { /* No power on new rail type, reroute. */ FreeTrainTrackReservation(v); *vehicles_affected.Append() = v; } } /* Update the company infrastructure counters. */ if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) { Company *c = Company::Get(GetTileOwner(tile)); uint num_pieces = IsLevelCrossingTile(tile) ? LEVELCROSSING_TRACKBIT_FACTOR : 1; if (IsPlainRailTile(tile)) { TrackBits bits = GetTrackBits(tile); num_pieces = CountBits(bits); if (TracksOverlap(bits)) num_pieces *= num_pieces; } c->infrastructure.rail[type] -= num_pieces; c->infrastructure.rail[totype] += num_pieces; DirtyCompanyInfrastructureWindows(c->index); } SetRailType(tile, totype); MarkTileDirtyByTile(tile); /* update power of train on this tile */ FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc); } } switch (tt) { case MP_RAILWAY: switch (GetRailTileType(tile)) { case RAIL_TILE_DEPOT: if (flags & DC_EXEC) { /* notify YAPF about the track layout change */ YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile)); /* Update build vehicle window related to this depot */ InvalidateWindowData(WC_VEHICLE_DEPOT, tile); InvalidateWindowData(WC_BUILD_VEHICLE, tile); } cost.AddCost(RailConvertCost(type, totype)); break; default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS if (flags & DC_EXEC) { /* notify YAPF about the track layout change */ TrackBits tracks = GetTrackBits(tile); while (tracks != TRACK_BIT_NONE) { YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks)); } } cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile))); break; } break; case MP_TUNNELBRIDGE: { TileIndex endtile = GetOtherTunnelBridgeEnd(tile); /* If both ends of tunnel/bridge are in the range, do not try to convert twice - * it would cause assert because of different test and exec runs */ if (endtile < tile) { if (diagonal) { if (DiagonalTileArea(area_start, area_end).Contains(endtile)) continue; } else { if (OrthogonalTileArea(area_start, area_end).Contains(endtile)) continue; } } /* When not converting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */ if (!IsCompatibleRail(GetRailType(tile), totype)) { CommandCost ret = TunnelBridgeIsFree(tile, endtile); if (ret.Failed()) { error = ret; continue; } } if (flags & DC_EXEC) { Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile)); if (HasTunnelBridgeReservation(tile)) { Train *v = GetTrainForReservation(tile, track); if (v != NULL && !HasPowerOnRail(v->railtype, totype)) { /* No power on new rail type, reroute. */ FreeTrainTrackReservation(v); *vehicles_affected.Append() = v; } } /* Update the company infrastructure counters. */ uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR; Company *c = Company::Get(GetTileOwner(tile)); c->infrastructure.rail[GetRailType(tile)] -= num_pieces; c->infrastructure.rail[totype] += num_pieces; DirtyCompanyInfrastructureWindows(c->index); SetRailType(tile, totype); SetRailType(endtile, totype); FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc); FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc); YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(endtile, track); if (IsBridge(tile)) { MarkBridgeDirty(tile); } else { MarkTileDirtyByTile(tile); MarkTileDirtyByTile(endtile); } } cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype)); break; } default: // MP_STATION, MP_ROAD if (flags & DC_EXEC) { Track track = ((tt == MP_STATION) ? GetRailStationTrack(tile) : GetCrossingRailTrack(tile)); YapfNotifyTrackLayoutChange(tile, track); } cost.AddCost(RailConvertCost(type, totype)); break; } for (uint i = 0; i < vehicles_affected.Length(); ++i) { TryPathReserve(vehicles_affected[i], true); } } if (flags & DC_EXEC) { /* Railtype changed, update trains as when entering different track */ for (Train **v = affected_trains.Begin(); v != affected_trains.End(); v++) { (*v)->ConsistChanged(CCF_TRACK); } } delete iter; return (cost.GetCost() == 0) ? error : cost; } static CommandCost RemoveTrainDepot(TileIndex tile, DoCommandFlag flags) { if (_current_company != OWNER_WATER) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; if (flags & DC_EXEC) { /* read variables before the depot is removed */ DiagDirection dir = GetRailDepotDirection(tile); Owner owner = GetTileOwner(tile); Train *v = NULL; if (HasDepotReservation(tile)) { v = GetTrainForReservation(tile, DiagDirToDiagTrack(dir)); if (v != NULL) FreeTrainTrackReservation(v); } Company::Get(owner)->infrastructure.rail[GetRailType(tile)]--; DirtyCompanyInfrastructureWindows(owner); delete Depot::GetByTile(tile); DoClearSquare(tile); AddSideToSignalBuffer(tile, dir, owner); YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir)); if (v != NULL) TryPathReserve(v, true); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_TRAIN]); } static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags) { CommandCost cost(EXPENSES_CONSTRUCTION); if (flags & DC_AUTO) { if (!IsTileOwner(tile, _current_company)) { return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER); } if (IsPlainRail(tile)) { return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK); } else { return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); } } switch (GetRailTileType(tile)) { case RAIL_TILE_SIGNALS: case RAIL_TILE_NORMAL: { Slope tileh = GetTileSlope(tile); /* Is there flat water on the lower halftile that gets cleared expensively? */ bool water_ground = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh)); TrackBits tracks = GetTrackBits(tile); while (tracks != TRACK_BIT_NONE) { Track track = RemoveFirstTrack(&tracks); CommandCost ret = DoCommand(tile, 0, track, flags, CMD_REMOVE_SINGLE_RAIL); if (ret.Failed()) return ret; cost.AddCost(ret); } /* When bankrupting, don't make water dirty, there could be a ship on lower halftile. * Same holds for non-companies clearing the tile, e.g. disasters. */ if (water_ground && !(flags & DC_BANKRUPT) && Company::IsValidID(_current_company)) { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; /* The track was removed, and left a coast tile. Now also clear the water. */ if (flags & DC_EXEC) DoClearSquare(tile); cost.AddCost(_price[PR_CLEAR_WATER]); } return cost; } case RAIL_TILE_DEPOT: return RemoveTrainDepot(tile, flags); default: return CMD_ERROR; } } /** * Get surface height in point (x,y) * On tiles with halftile foundations move (x,y) to a safe point wrt. track */ static uint GetSaveSlopeZ(uint x, uint y, Track track) { switch (track) { case TRACK_UPPER: x &= ~0xF; y &= ~0xF; break; case TRACK_LOWER: x |= 0xF; y |= 0xF; break; case TRACK_LEFT: x |= 0xF; y &= ~0xF; break; case TRACK_RIGHT: x &= ~0xF; y |= 0xF; break; default: break; } return GetSlopePixelZ(x, y); } static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos) { bool side; switch (_settings_game.construction.train_signal_side) { case 0: side = false; break; // left case 2: side = true; break; // right default: side = _settings_game.vehicle.road_side != 0; break; // driving side } static const Point SignalPositions[2][12] = { { // Signals on the left side /* LEFT LEFT RIGHT RIGHT UPPER UPPER */ { 8, 5}, {14, 1}, { 1, 14}, { 9, 11}, { 1, 0}, { 3, 10}, /* LOWER LOWER X X Y Y */ {11, 4}, {14, 14}, {11, 3}, { 4, 13}, { 3, 4}, {11, 13} }, { // Signals on the right side /* LEFT LEFT RIGHT RIGHT UPPER UPPER */ {14, 1}, {12, 10}, { 4, 6}, { 1, 14}, {10, 4}, { 0, 1}, /* LOWER LOWER X X Y Y */ {14, 14}, { 5, 12}, {11, 13}, { 4, 3}, {13, 4}, { 3, 11} } }; uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x; uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y; SignalType type = GetSignalType(tile, track); SignalVariant variant = GetSignalVariant(tile, track); SpriteID sprite = GetCustomSignalSprite(rti, tile, type, variant, condition); if (sprite != 0) { sprite += image; } else { /* Normal electric signals are stored in a different sprite block than all other signals. */ sprite = (type == SIGTYPE_NORMAL && variant == SIG_ELECTRIC) ? SPR_ORIGINAL_SIGNALS_BASE : SPR_SIGNALS_BASE - 16; sprite += type * 16 + variant * 64 + image * 2 + condition + (type > SIGTYPE_LAST_NOPBS ? 64 : 0); } AddSortableSpriteToDraw(sprite, PAL_NONE, x, y, 1, 1, BB_HEIGHT_UNDER_BRIDGE, GetSaveSlopeZ(x, y, track)); } static uint32 _drawtile_track_palette; static void DrawTrackFence_NW(const TileInfo *ti, SpriteID base_image) { RailFenceOffset rfo = RFO_FLAT_X; if (ti->tileh & SLOPE_NW) rfo = (ti->tileh & SLOPE_W) ? RFO_SLOPE_SW : RFO_SLOPE_NE; AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette, ti->x, ti->y + 1, 16, 1, 4, ti->z); } static void DrawTrackFence_SE(const TileInfo *ti, SpriteID base_image) { RailFenceOffset rfo = RFO_FLAT_X; if (ti->tileh & SLOPE_SE) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SW : RFO_SLOPE_NE; AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette, ti->x, ti->y + TILE_SIZE - 1, 16, 1, 4, ti->z); } static void DrawTrackFence_NW_SE(const TileInfo *ti, SpriteID base_image) { DrawTrackFence_NW(ti, base_image); DrawTrackFence_SE(ti, base_image); } static void DrawTrackFence_NE(const TileInfo *ti, SpriteID base_image) { RailFenceOffset rfo = RFO_FLAT_Y; if (ti->tileh & SLOPE_NE) rfo = (ti->tileh & SLOPE_E) ? RFO_SLOPE_SE : RFO_SLOPE_NW; AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette, ti->x + 1, ti->y, 1, 16, 4, ti->z); } static void DrawTrackFence_SW(const TileInfo *ti, SpriteID base_image) { RailFenceOffset rfo = RFO_FLAT_Y; if (ti->tileh & SLOPE_SW) rfo = (ti->tileh & SLOPE_S) ? RFO_SLOPE_SE : RFO_SLOPE_NW; AddSortableSpriteToDraw(base_image + rfo, _drawtile_track_palette, ti->x + TILE_SIZE - 1, ti->y, 1, 16, 4, ti->z); } static void DrawTrackFence_NE_SW(const TileInfo *ti, SpriteID base_image) { DrawTrackFence_NE(ti, base_image); DrawTrackFence_SW(ti, base_image); } /** * Draw fence at eastern side of track. */ static void DrawTrackFence_NS_1(const TileInfo *ti, SpriteID base_image) { int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_W); AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette, ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z); } /** * Draw fence at western side of track. */ static void DrawTrackFence_NS_2(const TileInfo *ti, SpriteID base_image) { int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_E); AddSortableSpriteToDraw(base_image + RFO_FLAT_VERT, _drawtile_track_palette, ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z); } /** * Draw fence at southern side of track. */ static void DrawTrackFence_WE_1(const TileInfo *ti, SpriteID base_image) { int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_N); AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette, ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z); } /** * Draw fence at northern side of track. */ static void DrawTrackFence_WE_2(const TileInfo *ti, SpriteID base_image) { int z = ti->z + GetSlopePixelZInCorner(RemoveHalftileSlope(ti->tileh), CORNER_S); AddSortableSpriteToDraw(base_image + RFO_FLAT_HORZ, _drawtile_track_palette, ti->x + TILE_SIZE / 2, ti->y + TILE_SIZE / 2, 1, 1, 4, z); } static void DrawTrackDetails(const TileInfo *ti, const RailtypeInfo *rti) { /* Base sprite for track fences. * Note: Halftile slopes only have fences on the upper part. */ SpriteID base_image = GetCustomRailSprite(rti, ti->tile, RTSG_FENCES, IsHalftileSlope(ti->tileh) ? TCX_UPPER_HALFTILE : TCX_NORMAL); if (base_image == 0) base_image = SPR_TRACK_FENCE_FLAT_X; switch (GetRailGroundType(ti->tile)) { case RAIL_GROUND_FENCE_NW: DrawTrackFence_NW(ti, base_image); break; case RAIL_GROUND_FENCE_SE: DrawTrackFence_SE(ti, base_image); break; case RAIL_GROUND_FENCE_SENW: DrawTrackFence_NW_SE(ti, base_image); break; case RAIL_GROUND_FENCE_NE: DrawTrackFence_NE(ti, base_image); break; case RAIL_GROUND_FENCE_SW: DrawTrackFence_SW(ti, base_image); break; case RAIL_GROUND_FENCE_NESW: DrawTrackFence_NE_SW(ti, base_image); break; case RAIL_GROUND_FENCE_VERT1: DrawTrackFence_NS_1(ti, base_image); break; case RAIL_GROUND_FENCE_VERT2: DrawTrackFence_NS_2(ti, base_image); break; case RAIL_GROUND_FENCE_HORIZ1: DrawTrackFence_WE_1(ti, base_image); break; case RAIL_GROUND_FENCE_HORIZ2: DrawTrackFence_WE_2(ti, base_image); break; case RAIL_GROUND_WATER: { Corner track_corner; if (IsHalftileSlope(ti->tileh)) { /* Steep slope or one-corner-raised slope with halftile foundation */ track_corner = GetHalftileSlopeCorner(ti->tileh); } else { /* Three-corner-raised slope */ track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh))); } switch (track_corner) { case CORNER_W: DrawTrackFence_NS_1(ti, base_image); break; case CORNER_S: DrawTrackFence_WE_2(ti, base_image); break; case CORNER_E: DrawTrackFence_NS_2(ti, base_image); break; case CORNER_N: DrawTrackFence_WE_1(ti, base_image); break; default: NOT_REACHED(); } break; } default: break; } } /* SubSprite for drawing the track halftile of 'three-corners-raised'-sloped rail sprites. */ static const int INF = 1000; // big number compared to tilesprite size static const SubSprite _halftile_sub_sprite[4] = { { -INF , -INF , 32 - 33, INF }, // CORNER_W, clip 33 pixels from right { -INF , 0 + 7, INF , INF }, // CORNER_S, clip 7 pixels from top { -31 + 33, -INF , INF , INF }, // CORNER_E, clip 33 pixels from left { -INF , -INF , INF , 30 - 23 } // CORNER_N, clip 23 pixels from bottom }; static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInfo *ti, Slope s) { DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0); } static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti) { RailGroundType rgt = GetRailGroundType(ti->tile); Foundation f = GetRailFoundation(ti->tileh, track); Corner halftile_corner = CORNER_INVALID; if (IsNonContinuousFoundation(f)) { /* Save halftile corner */ halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f)); /* Draw lower part first */ track &= ~CornerToTrackBits(halftile_corner); f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE); } DrawFoundation(ti, f); /* DrawFoundation modifies ti */ /* Draw ground */ if (rgt == RAIL_GROUND_WATER) { if (track != TRACK_BIT_NONE || IsSteepSlope(ti->tileh)) { /* three-corner-raised slope or steep slope with track on upper part */ DrawShoreTile(ti->tileh); } else { /* single-corner-raised slope with track on upper part */ DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE); } } else { SpriteID image; switch (rgt) { case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break; case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break; default: image = SPR_FLAT_GRASS_TILE; break; } image += SlopeToSpriteOffset(ti->tileh); DrawGroundSprite(image, PAL_NONE); } SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND); TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE; if (track == TRACK_BIT_NONE) { /* Half-tile foundation, no track here? */ } else if (ti->tileh == SLOPE_NW && track == TRACK_BIT_Y) { DrawGroundSprite(ground + RTO_SLOPE_NW, PAL_NONE); if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 9, PALETTE_CRASH); } else if (ti->tileh == SLOPE_NE && track == TRACK_BIT_X) { DrawGroundSprite(ground + RTO_SLOPE_NE, PAL_NONE); if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 6, PALETTE_CRASH); } else if (ti->tileh == SLOPE_SE && track == TRACK_BIT_Y) { DrawGroundSprite(ground + RTO_SLOPE_SE, PAL_NONE); if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 7, PALETTE_CRASH); } else if (ti->tileh == SLOPE_SW && track == TRACK_BIT_X) { DrawGroundSprite(ground + RTO_SLOPE_SW, PAL_NONE); if (pbs != TRACK_BIT_NONE) DrawGroundSprite(overlay + 8, PALETTE_CRASH); } else { switch (track) { /* Draw single ground sprite when not overlapping. No track overlay * is necessary for these sprites. */ case TRACK_BIT_X: DrawGroundSprite(ground + RTO_X, PAL_NONE); break; case TRACK_BIT_Y: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break; case TRACK_BIT_UPPER: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); break; case TRACK_BIT_LOWER: DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break; case TRACK_BIT_RIGHT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); break; case TRACK_BIT_LEFT: DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break; case TRACK_BIT_CROSS: DrawGroundSprite(ground + RTO_CROSSING_XY, PAL_NONE); break; case TRACK_BIT_HORZ: DrawTrackSprite(ground + RTO_N, PAL_NONE, ti, SLOPE_N); DrawTrackSprite(ground + RTO_S, PAL_NONE, ti, SLOPE_S); break; case TRACK_BIT_VERT: DrawTrackSprite(ground + RTO_E, PAL_NONE, ti, SLOPE_E); DrawTrackSprite(ground + RTO_W, PAL_NONE, ti, SLOPE_W); break; default: /* We're drawing a junction tile */ if ((track & TRACK_BIT_3WAY_NE) == 0) { DrawGroundSprite(ground + RTO_JUNCTION_SW, PAL_NONE); } else if ((track & TRACK_BIT_3WAY_SW) == 0) { DrawGroundSprite(ground + RTO_JUNCTION_NE, PAL_NONE); } else if ((track & TRACK_BIT_3WAY_NW) == 0) { DrawGroundSprite(ground + RTO_JUNCTION_SE, PAL_NONE); } else if ((track & TRACK_BIT_3WAY_SE) == 0) { DrawGroundSprite(ground + RTO_JUNCTION_NW, PAL_NONE); } else { DrawGroundSprite(ground + RTO_JUNCTION_NSEW, PAL_NONE); } /* Mask out PBS bits as we shall draw them afterwards anyway. */ track &= ~pbs; /* Draw regular track bits */ if (track & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PAL_NONE); if (track & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PAL_NONE); if (track & TRACK_BIT_UPPER) DrawGroundSprite(overlay + RTO_N, PAL_NONE); if (track & TRACK_BIT_LOWER) DrawGroundSprite(overlay + RTO_S, PAL_NONE); if (track & TRACK_BIT_RIGHT) DrawGroundSprite(overlay + RTO_E, PAL_NONE); if (track & TRACK_BIT_LEFT) DrawGroundSprite(overlay + RTO_W, PAL_NONE); } /* Draw reserved track bits */ if (pbs & TRACK_BIT_X) DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); if (pbs & TRACK_BIT_Y) DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); if (pbs & TRACK_BIT_UPPER) DrawTrackSprite(overlay + RTO_N, PALETTE_CRASH, ti, SLOPE_N); if (pbs & TRACK_BIT_LOWER) DrawTrackSprite(overlay + RTO_S, PALETTE_CRASH, ti, SLOPE_S); if (pbs & TRACK_BIT_RIGHT) DrawTrackSprite(overlay + RTO_E, PALETTE_CRASH, ti, SLOPE_E); if (pbs & TRACK_BIT_LEFT) DrawTrackSprite(overlay + RTO_W, PALETTE_CRASH, ti, SLOPE_W); } if (IsValidCorner(halftile_corner)) { DrawFoundation(ti, HalftileFoundation(halftile_corner)); overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY, TCX_UPPER_HALFTILE); ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND, TCX_UPPER_HALFTILE); /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */ Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner)); SpriteID image; switch (rgt) { case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break; case RAIL_GROUND_ICE_DESERT: case RAIL_GROUND_HALF_SNOW: image = SPR_FLAT_SNOW_DESERT_TILE; break; default: image = SPR_FLAT_GRASS_TILE; break; } image += SlopeToSpriteOffset(fake_slope); DrawGroundSprite(image, PAL_NONE, &(_halftile_sub_sprite[halftile_corner])); track = CornerToTrackBits(halftile_corner); int offset; switch (track) { default: NOT_REACHED(); case TRACK_BIT_UPPER: offset = RTO_N; break; case TRACK_BIT_LOWER: offset = RTO_S; break; case TRACK_BIT_RIGHT: offset = RTO_E; break; case TRACK_BIT_LEFT: offset = RTO_W; break; } DrawTrackSprite(ground + offset, PAL_NONE, ti, fake_slope); if (_settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, track)) { DrawTrackSprite(overlay + offset, PALETTE_CRASH, ti, fake_slope); } } } /** * Draw ground sprite and track bits * @param ti TileInfo * @param track TrackBits to draw */ static void DrawTrackBits(TileInfo *ti, TrackBits track) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); if (rti->UsesOverlay()) { DrawTrackBitsOverlay(ti, track, rti); return; } RailGroundType rgt = GetRailGroundType(ti->tile); Foundation f = GetRailFoundation(ti->tileh, track); Corner halftile_corner = CORNER_INVALID; if (IsNonContinuousFoundation(f)) { /* Save halftile corner */ halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f)); /* Draw lower part first */ track &= ~CornerToTrackBits(halftile_corner); f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE); } DrawFoundation(ti, f); /* DrawFoundation modifies ti */ SpriteID image; PaletteID pal = PAL_NONE; const SubSprite *sub = NULL; bool junction = false; /* Select the sprite to use. */ if (track == 0) { /* Clear ground (only track on halftile foundation) */ if (rgt == RAIL_GROUND_WATER) { if (IsSteepSlope(ti->tileh)) { DrawShoreTile(ti->tileh); image = 0; } else { image = SPR_FLAT_WATER_TILE; } } else { switch (rgt) { case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break; case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOW_DESERT_TILE; break; default: image = SPR_FLAT_GRASS_TILE; break; } image += SlopeToSpriteOffset(ti->tileh); } } else { if (ti->tileh != SLOPE_FLAT) { /* track on non-flat ground */ image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y; } else { /* track on flat ground */ (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) || (image++, track == TRACK_BIT_X) || (image++, track == TRACK_BIT_UPPER) || (image++, track == TRACK_BIT_LOWER) || (image++, track == TRACK_BIT_RIGHT) || (image++, track == TRACK_BIT_LEFT) || (image++, track == TRACK_BIT_CROSS) || (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) || (image++, track == TRACK_BIT_VERT) || (junction = true, false) || (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) || (image++, (track & TRACK_BIT_3WAY_SW) == 0) || (image++, (track & TRACK_BIT_3WAY_NW) == 0) || (image++, (track & TRACK_BIT_3WAY_SE) == 0) || (image++, true); } switch (rgt) { case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break; case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break; case RAIL_GROUND_WATER: { /* three-corner-raised slope */ DrawShoreTile(ti->tileh); Corner track_corner = OppositeCorner(GetHighestSlopeCorner(ComplementSlope(ti->tileh))); sub = &(_halftile_sub_sprite[track_corner]); break; } default: break; } } if (image != 0) DrawGroundSprite(image, pal, sub); /* Draw track pieces individually for junction tiles */ if (junction) { if (track & TRACK_BIT_X) DrawGroundSprite(rti->base_sprites.single_x, PAL_NONE); if (track & TRACK_BIT_Y) DrawGroundSprite(rti->base_sprites.single_y, PAL_NONE); if (track & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PAL_NONE); if (track & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PAL_NONE); if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE); if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE); } /* PBS debugging, draw reserved tracks darker */ if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) { /* Get reservation, but mask track on halftile slope */ TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track; if (pbs & TRACK_BIT_X) { if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) { DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); } else { DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH); } } if (pbs & TRACK_BIT_Y) { if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) { DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); } else { DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH); } } if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -(int)TILE_HEIGHT : 0); if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -(int)TILE_HEIGHT : 0); if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -(int)TILE_HEIGHT : 0); if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -(int)TILE_HEIGHT : 0); } if (IsValidCorner(halftile_corner)) { DrawFoundation(ti, HalftileFoundation(halftile_corner)); /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */ Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner)); image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y; pal = PAL_NONE; switch (rgt) { case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break; case RAIL_GROUND_ICE_DESERT: case RAIL_GROUND_HALF_SNOW: image += rti->snow_offset; break; // higher part has snow in this case too default: break; } DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner])); if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) { static const byte _corner_to_track_sprite[] = {3, 1, 2, 0}; DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -(int)TILE_HEIGHT); } } } static void DrawSignals(TileIndex tile, TrackBits rails, const RailtypeInfo *rti) { #define MAYBE_DRAW_SIGNAL(x, y, z, t) if (IsSignalPresent(tile, x)) DrawSingleSignal(tile, rti, t, GetSingleSignalState(tile, x), y, z) if (!(rails & TRACK_BIT_Y)) { if (!(rails & TRACK_BIT_X)) { if (rails & TRACK_BIT_LEFT) { MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTH, 0, TRACK_LEFT); MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTH, 1, TRACK_LEFT); } if (rails & TRACK_BIT_RIGHT) { MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_NORTH, 2, TRACK_RIGHT); MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_SOUTH, 3, TRACK_RIGHT); } if (rails & TRACK_BIT_UPPER) { MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_WEST, 4, TRACK_UPPER); MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_EAST, 5, TRACK_UPPER); } if (rails & TRACK_BIT_LOWER) { MAYBE_DRAW_SIGNAL(1, SIGNAL_TO_WEST, 6, TRACK_LOWER); MAYBE_DRAW_SIGNAL(0, SIGNAL_TO_EAST, 7, TRACK_LOWER); } } else { MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHWEST, 8, TRACK_X); MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHEAST, 9, TRACK_X); } } else { MAYBE_DRAW_SIGNAL(3, SIGNAL_TO_SOUTHEAST, 10, TRACK_Y); MAYBE_DRAW_SIGNAL(2, SIGNAL_TO_NORTHWEST, 11, TRACK_Y); } } static void DrawTile_Track(TileInfo *ti) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); _drawtile_track_palette = COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)); if (IsPlainRail(ti->tile)) { TrackBits rails = GetTrackBits(ti->tile); DrawTrackBits(ti, rails); if (HasBit(_display_opt, DO_FULL_DETAIL)) DrawTrackDetails(ti, rti); if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti); if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails, rti); } else { /* draw depot */ const DrawTileSprites *dts; PaletteID pal = PAL_NONE; SpriteID relocation; if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); if (IsInvisibilitySet(TO_BUILDINGS)) { /* Draw rail instead of depot */ dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)]; } else { dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)]; } SpriteID image; if (rti->UsesOverlay()) { image = SPR_FLAT_GRASS_TILE; } else { image = dts->ground.sprite; if (image != SPR_FLAT_GRASS_TILE) image += rti->GetRailtypeSpriteOffset(); } /* adjust ground tile for desert * don't adjust for snow, because snow in depots looks weird */ if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) { if (image != SPR_FLAT_GRASS_TILE) { image += rti->snow_offset; // tile with tracks } else { image = SPR_FLAT_SNOW_DESERT_TILE; // flat ground } } DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette)); if (rti->UsesOverlay()) { SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND); switch (GetRailDepotDirection(ti->tile)) { case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH case DIAGDIR_SW: DrawGroundSprite(ground + RTO_X, PAL_NONE); break; case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH case DIAGDIR_SE: DrawGroundSprite(ground + RTO_Y, PAL_NONE); break; default: break; } if (_settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) { SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY); switch (GetRailDepotDirection(ti->tile)) { case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH case DIAGDIR_SW: DrawGroundSprite(overlay + RTO_X, PALETTE_CRASH); break; case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH case DIAGDIR_SE: DrawGroundSprite(overlay + RTO_Y, PALETTE_CRASH); break; default: break; } } } else { /* PBS debugging, draw reserved tracks darker */ if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) { switch (GetRailDepotDirection(ti->tile)) { case DIAGDIR_NE: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break; case DIAGDIR_NW: if (!IsInvisibilitySet(TO_BUILDINGS)) break; // else FALL THROUGH case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break; default: break; } } } int depot_sprite = GetCustomRailSprite(rti, ti->tile, RTSG_DEPOT); relocation = depot_sprite != 0 ? depot_sprite - SPR_RAIL_DEPOT_SE_1 : rti->GetRailtypeSpriteOffset(); if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti); DrawRailTileSeq(ti, dts, TO_BUILDINGS, relocation, 0, _drawtile_track_palette); } DrawBridgeMiddle(ti); } void DrawTrainDepotSprite(int x, int y, int dir, RailType railtype) { const DrawTileSprites *dts = &_depot_gfx_table[dir]; const RailtypeInfo *rti = GetRailTypeInfo(railtype); SpriteID image = rti->UsesOverlay() ? SPR_FLAT_GRASS_TILE : dts->ground.sprite; uint32 offset = rti->GetRailtypeSpriteOffset(); if (image != SPR_FLAT_GRASS_TILE) image += offset; PaletteID palette = COMPANY_SPRITE_COLOUR(_local_company); DrawSprite(image, PAL_NONE, x, y); if (rti->UsesOverlay()) { SpriteID ground = GetCustomRailSprite(rti, INVALID_TILE, RTSG_GROUND); switch (dir) { case DIAGDIR_SW: DrawSprite(ground + RTO_X, PAL_NONE, x, y); break; case DIAGDIR_SE: DrawSprite(ground + RTO_Y, PAL_NONE, x, y); break; default: break; } } int depot_sprite = GetCustomRailSprite(rti, INVALID_TILE, RTSG_DEPOT); if (depot_sprite != 0) offset = depot_sprite - SPR_RAIL_DEPOT_SE_1; DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette); } static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y) { if (IsPlainRail(tile)) { int z; Slope tileh = GetTilePixelSlope(tile, &z); if (tileh == SLOPE_FLAT) return z; z += ApplyPixelFoundationToSlope(GetRailFoundation(tileh, GetTrackBits(tile)), &tileh); return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh); } else { return GetTileMaxPixelZ(tile); } } static Foundation GetFoundation_Track(TileIndex tile, Slope tileh) { return IsPlainRail(tile) ? GetRailFoundation(tileh, GetTrackBits(tile)) : FlatteningFoundation(tileh); } static void TileLoop_Track(TileIndex tile) { RailGroundType old_ground = GetRailGroundType(tile); RailGroundType new_ground; if (old_ground == RAIL_GROUND_WATER) { TileLoop_Water(tile); return; } switch (_settings_game.game_creation.landscape) { case LT_ARCTIC: { int z; Slope slope = GetTileSlope(tile, &z); bool half = false; /* for non-flat track, use lower part of track * in other cases, use the highest part with track */ if (IsPlainRail(tile)) { TrackBits track = GetTrackBits(tile); Foundation f = GetRailFoundation(slope, track); switch (f) { case FOUNDATION_NONE: /* no foundation - is the track on the upper side of three corners raised tile? */ if (IsSlopeWithThreeCornersRaised(slope)) z++; break; case FOUNDATION_INCLINED_X: case FOUNDATION_INCLINED_Y: /* sloped track - is it on a steep slope? */ if (IsSteepSlope(slope)) z++; break; case FOUNDATION_STEEP_LOWER: /* only lower part of steep slope */ z++; break; default: /* if it is a steep slope, then there is a track on higher part */ if (IsSteepSlope(slope)) z++; z++; break; } half = IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1); } else { /* is the depot on a non-flat tile? */ if (slope != SLOPE_FLAT) z++; } /* 'z' is now the lowest part of the highest track bit - * for sloped track, it is 'z' of lower part * for two track bits, it is 'z' of higher track bit * For non-continuous foundations (and STEEP_BOTH), 'half' is set */ if (z > GetSnowLine()) { if (half && z - GetSnowLine() == 1) { /* track on non-continuous foundation, lower part is not under snow */ new_ground = RAIL_GROUND_HALF_SNOW; } else { new_ground = RAIL_GROUND_ICE_DESERT; } goto set_ground; } break; } case LT_TROPIC: if (GetTropicZone(tile) == TROPICZONE_DESERT) { new_ground = RAIL_GROUND_ICE_DESERT; goto set_ground; } break; } new_ground = RAIL_GROUND_GRASS; if (IsPlainRail(tile) && old_ground != RAIL_GROUND_BARREN) { // wait until bottom is green /* determine direction of fence */ TrackBits rail = GetTrackBits(tile); Owner owner = GetTileOwner(tile); byte fences = 0; for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) { static const TrackBits dir_to_trackbits[DIAGDIR_END] = {TRACK_BIT_3WAY_NE, TRACK_BIT_3WAY_SE, TRACK_BIT_3WAY_SW, TRACK_BIT_3WAY_NW}; /* Track bit on this edge => no fence. */ if ((rail & dir_to_trackbits[d]) != TRACK_BIT_NONE) continue; TileIndex tile2 = tile + TileOffsByDiagDir(d); /* Show fences if it's a house, industry, object, road, tunnelbridge or not owned by us. */ if (!IsValidTile(tile2) || IsTileType(tile2, MP_HOUSE) || IsTileType(tile2, MP_INDUSTRY) || IsTileType(tile2, MP_ROAD) || (IsTileType(tile2, MP_OBJECT) && !IsObjectType(tile2, OBJECT_OWNED_LAND)) || IsTileType(tile2, MP_TUNNELBRIDGE) || !IsTileOwner(tile2, owner)) { fences |= 1 << d; } } switch (fences) { case 0: break; case (1 << DIAGDIR_NE): new_ground = RAIL_GROUND_FENCE_NE; break; case (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_SE; break; case (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_SW; break; case (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_NW; break; case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_NESW; break; case (1 << DIAGDIR_SE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_SENW; break; case (1 << DIAGDIR_NE) | (1 << DIAGDIR_SE): new_ground = RAIL_GROUND_FENCE_VERT1; break; case (1 << DIAGDIR_NE) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_HORIZ2; break; case (1 << DIAGDIR_SE) | (1 << DIAGDIR_SW): new_ground = RAIL_GROUND_FENCE_HORIZ1; break; case (1 << DIAGDIR_SW) | (1 << DIAGDIR_NW): new_ground = RAIL_GROUND_FENCE_VERT2; break; default: NOT_REACHED(); } } set_ground: if (old_ground != new_ground) { SetRailGroundType(tile, new_ground); MarkTileDirtyByTile(tile); } } static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { /* Case of half tile slope with water. */ if (mode == TRANSPORT_WATER && IsPlainRail(tile) && GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(GetTileSlope(tile))) { TrackBits tb = GetTrackBits(tile); switch (tb) { default: NOT_REACHED(); case TRACK_BIT_UPPER: tb = TRACK_BIT_LOWER; break; case TRACK_BIT_LOWER: tb = TRACK_BIT_UPPER; break; case TRACK_BIT_LEFT: tb = TRACK_BIT_RIGHT; break; case TRACK_BIT_RIGHT: tb = TRACK_BIT_LEFT; break; } return CombineTrackStatus(TrackBitsToTrackdirBits(tb), TRACKDIR_BIT_NONE); } if (mode != TRANSPORT_RAIL) return 0; TrackBits trackbits = TRACK_BIT_NONE; TrackdirBits red_signals = TRACKDIR_BIT_NONE; switch (GetRailTileType(tile)) { default: NOT_REACHED(); case RAIL_TILE_NORMAL: trackbits = GetTrackBits(tile); break; case RAIL_TILE_SIGNALS: { trackbits = GetTrackBits(tile); byte a = GetPresentSignals(tile); uint b = GetSignalStates(tile); b &= a; /* When signals are not present (in neither direction), * we pretend them to be green. Otherwise, it depends on * the signal type. For signals that are only active from * one side, we set the missing signals explicitly to * `green'. Otherwise, they implicitly become `red'. */ if (!IsOnewaySignal(tile, TRACK_UPPER) || (a & SignalOnTrack(TRACK_UPPER)) == 0) b |= ~a & SignalOnTrack(TRACK_UPPER); if (!IsOnewaySignal(tile, TRACK_LOWER) || (a & SignalOnTrack(TRACK_LOWER)) == 0) b |= ~a & SignalOnTrack(TRACK_LOWER); if ((b & 0x8) == 0) red_signals |= (TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E); if ((b & 0x4) == 0) red_signals |= (TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_UPPER_W); if ((b & 0x2) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_E); if ((b & 0x1) == 0) red_signals |= (TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_W); break; } case RAIL_TILE_DEPOT: { DiagDirection dir = GetRailDepotDirection(tile); if (side != INVALID_DIAGDIR && side != dir) break; trackbits = DiagDirToDiagTrackBits(dir); break; } } return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals); } static bool ClickTile_Track(TileIndex tile) { if (!IsRailDepot(tile)) return false; ShowDepotWindow(tile, VEH_TRAIN); return true; } static void GetTileDesc_Track(TileIndex tile, TileDesc *td) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); td->rail_speed = rti->max_speed; td->owner[0] = GetTileOwner(tile); SetDParamX(td->dparam, 0, rti->strings.name); switch (GetRailTileType(tile)) { case RAIL_TILE_NORMAL: td->str = STR_LAI_RAIL_DESCRIPTION_TRACK; break; case RAIL_TILE_SIGNALS: { static const StringID signal_type[6][6] = { { STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS }, { STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS }, { STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS }, { STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS }, { STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS }, { STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS, STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS } }; SignalType primary_signal; SignalType secondary_signal; if (HasSignalOnTrack(tile, TRACK_UPPER)) { primary_signal = GetSignalType(tile, TRACK_UPPER); secondary_signal = HasSignalOnTrack(tile, TRACK_LOWER) ? GetSignalType(tile, TRACK_LOWER) : primary_signal; } else { secondary_signal = primary_signal = GetSignalType(tile, TRACK_LOWER); } td->str = signal_type[secondary_signal][primary_signal]; break; } case RAIL_TILE_DEPOT: td->str = STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT; if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) { if (td->rail_speed > 0) { td->rail_speed = min(td->rail_speed, 61); } else { td->rail_speed = 61; } } td->build_date = Depot::GetByTile(tile)->build_date; break; default: NOT_REACHED(); } } static void ChangeTileOwner_Track(TileIndex tile, Owner old_owner, Owner new_owner) { if (!IsTileOwner(tile, old_owner)) return; if (new_owner != INVALID_OWNER) { /* Update company infrastructure counts. No need to dirty windows here, we'll redraw the whole screen anyway. */ uint num_pieces = 1; if (IsPlainRail(tile)) { TrackBits bits = GetTrackBits(tile); num_pieces = CountBits(bits); if (TracksOverlap(bits)) num_pieces *= num_pieces; } RailType rt = GetRailType(tile); Company::Get(old_owner)->infrastructure.rail[rt] -= num_pieces; Company::Get(new_owner)->infrastructure.rail[rt] += num_pieces; if (HasSignals(tile)) { uint num_sigs = CountBits(GetPresentSignals(tile)); Company::Get(old_owner)->infrastructure.signal -= num_sigs; Company::Get(new_owner)->infrastructure.signal += num_sigs; } SetTileOwner(tile, new_owner); } else { DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); } } static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 }; static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 }; static const int8 _deltacoord_leaveoffset[8] = { -1, 0, 1, 0, /* x */ 0, 1, 0, -1 /* y */ }; /** * Compute number of ticks when next wagon will leave a depot. * Negative means next wagon should have left depot n ticks before. * @param v vehicle outside (leaving) the depot * @return number of ticks when the next wagon will leave */ int TicksToLeaveDepot(const Train *v) { DiagDirection dir = GetRailDepotDirection(v->tile); int length = v->CalcNextVehicleOffset(); switch (dir) { case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1))); case DIAGDIR_SE: return -((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) + (length + 1))); case DIAGDIR_SW: return -((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) + (length + 1))); default: case DIAGDIR_NW: return ((int)(v->y_pos & 0x0F) - ((_fractcoords_enter[dir] >> 4) - (length + 1))); } return 0; // make compilers happy } /** * Tile callback routine when vehicle enters tile * @see vehicle_enter_tile_proc */ static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int x, int y) { /* this routine applies only to trains in depot tiles */ if (u->type != VEH_TRAIN || !IsRailDepotTile(tile)) return VETSB_CONTINUE; Train *v = Train::From(u); /* depot direction */ DiagDirection dir = GetRailDepotDirection(tile); /* Calculate the point where the following wagon should be activated. */ int length = v->CalcNextVehicleOffset(); byte fract_coord_leave = ((_fractcoords_enter[dir] & 0x0F) + // x (length + 1) * _deltacoord_leaveoffset[dir]) + (((_fractcoords_enter[dir] >> 4) + // y ((length + 1) * _deltacoord_leaveoffset[dir + 4])) << 4); byte fract_coord = (x & 0xF) + ((y & 0xF) << 4); if (_fractcoords_behind[dir] == fract_coord) { /* make sure a train is not entering the tile from behind */ return VETSB_CANNOT_ENTER; } else if (_fractcoords_enter[dir] == fract_coord) { if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) { /* enter the depot */ v->track = TRACK_BIT_DEPOT, v->vehstatus |= VS_HIDDEN; // hide it v->direction = ReverseDir(v->direction); if (v->Next() == NULL) VehicleEnterDepot(v->First()); v->tile = tile; InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); return VETSB_ENTERED_WORMHOLE; } } else if (fract_coord_leave == fract_coord) { if (DiagDirToDir(dir) == v->direction) { /* leave the depot? */ if ((v = v->Next()) != NULL) { v->vehstatus &= ~VS_HIDDEN; v->track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y); } } } return VETSB_CONTINUE; } /** * Tests if autoslope is allowed. * * @param tile The tile. * @param flags Terraform command flags. * @param z_old Old TileZ. * @param tileh_old Old TileSlope. * @param z_new New TileZ. * @param tileh_new New TileSlope. * @param rail_bits Trackbits. */ static CommandCost TestAutoslopeOnRailTile(TileIndex tile, uint flags, int z_old, Slope tileh_old, int z_new, Slope tileh_new, TrackBits rail_bits) { if (!_settings_game.construction.build_on_slopes || !AutoslopeEnabled()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK); /* Is the slope-rail_bits combination valid in general? I.e. is it safe to call GetRailFoundation() ? */ if (CheckRailSlope(tileh_new, rail_bits, TRACK_BIT_NONE, tile).Failed()) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK); /* Get the slopes on top of the foundations */ z_old += ApplyFoundationToSlope(GetRailFoundation(tileh_old, rail_bits), &tileh_old); z_new += ApplyFoundationToSlope(GetRailFoundation(tileh_new, rail_bits), &tileh_new); Corner track_corner; switch (rail_bits) { case TRACK_BIT_LEFT: track_corner = CORNER_W; break; case TRACK_BIT_LOWER: track_corner = CORNER_S; break; case TRACK_BIT_RIGHT: track_corner = CORNER_E; break; case TRACK_BIT_UPPER: track_corner = CORNER_N; break; /* Surface slope must not be changed */ default: if (z_old != z_new || tileh_old != tileh_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK); return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } /* The height of the track_corner must not be changed. The rest ensures GetRailFoundation() already. */ z_old += GetSlopeZInCorner(RemoveHalftileSlope(tileh_old), track_corner); z_new += GetSlopeZInCorner(RemoveHalftileSlope(tileh_new), track_corner); if (z_old != z_new) return_cmd_error(STR_ERROR_MUST_REMOVE_RAILROAD_TRACK); CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); /* Make the ground dirty, if surface slope has changed */ if (tileh_old != tileh_new) { /* If there is flat water on the lower halftile add the cost for clearing it */ if (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)) cost.AddCost(_price[PR_CLEAR_WATER]); if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN); } return cost; } /** * Test-procedure for HasVehicleOnPos to check for a ship. */ static Vehicle *EnsureNoShipProc(Vehicle *v, void *data) { return v->type == VEH_SHIP ? v : NULL; } static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { int z_old; Slope tileh_old = GetTileSlope(tile, &z_old); if (IsPlainRail(tile)) { TrackBits rail_bits = GetTrackBits(tile); /* Is there flat water on the lower halftile that must be cleared expensively? */ bool was_water = (GetRailGroundType(tile) == RAIL_GROUND_WATER && IsSlopeWithOneCornerRaised(tileh_old)); /* Allow clearing the water only if there is no ship */ if (was_water && HasVehicleOnPos(tile, NULL, &EnsureNoShipProc)) return_cmd_error(STR_ERROR_SHIP_IN_THE_WAY); /* First test autoslope. However if it succeeds we still have to test the rest, because non-autoslope terraforming is cheaper. */ CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits); /* When there is only a single horizontal/vertical track, one corner can be terraformed. */ Corner allowed_corner; switch (rail_bits) { case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break; case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break; case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break; case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break; default: return autoslope_result; } Foundation f_old = GetRailFoundation(tileh_old, rail_bits); /* Do not allow terraforming if allowed_corner is part of anti-zig-zag foundations */ if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result; /* Everything is valid, which only changes allowed_corner */ for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) { if (allowed_corner == corner) continue; if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result; } /* Make the ground dirty */ if ((flags & DC_EXEC) != 0) SetRailGroundType(tile, RAIL_GROUND_BARREN); /* allow terraforming */ return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price[PR_CLEAR_WATER] : (Money)0); } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() && AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) { return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } extern const TileTypeProcs _tile_type_rail_procs = { DrawTile_Track, // draw_tile_proc GetSlopePixelZ_Track, // get_slope_z_proc ClearTile_Track, // clear_tile_proc NULL, // add_accepted_cargo_proc GetTileDesc_Track, // get_tile_desc_proc GetTileTrackStatus_Track, // get_tile_track_status_proc ClickTile_Track, // click_tile_proc NULL, // animate_tile_proc TileLoop_Track, // tile_loop_proc ChangeTileOwner_Track, // change_tile_owner_proc NULL, // add_produced_cargo_proc VehicleEnter_Track, // vehicle_enter_tile_proc GetFoundation_Track, // get_foundation_proc TerraformTile_Track, // terraform_tile_proc }; openttd-1.5.3/src/transparency_gui.cpp0000644000000000000000000001536112627373441016562 0ustar rootroot/* $Id: transparency_gui.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 transparency_gui.cpp The transparency GUI. */ #include "stdafx.h" #include "window_gui.h" #include "transparency.h" #include "sound_func.h" #include "settings_type.h" #include "widgets/transparency_widget.h" #include "table/sprites.h" #include "table/strings.h" #include "safeguards.h" TransparencyOptionBits _transparency_opt; ///< The bits that should be transparent. TransparencyOptionBits _transparency_lock; ///< Prevent these bits from flipping with X. TransparencyOptionBits _invisibility_opt; ///< The bits that should be invisible. byte _display_opt; ///< What do we want to draw/do? class TransparenciesWindow : public Window { public: TransparenciesWindow(WindowDesc *desc, int window_number) : Window(desc) { this->InitNested(window_number); } virtual void OnPaint() { this->OnInvalidateData(0); // Must be sure that the widgets show the transparency variable changes, also when we use shortcuts. this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_TT_SIGNS: case WID_TT_TREES: case WID_TT_HOUSES: case WID_TT_INDUSTRIES: case WID_TT_BUILDINGS: case WID_TT_BRIDGES: case WID_TT_STRUCTURES: case WID_TT_CATENARY: case WID_TT_LOADING: { uint i = widget - WID_TT_BEGIN; if (HasBit(_transparency_lock, i)) DrawSprite(SPR_LOCK, PAL_NONE, r.left + 1, r.top + 1); break; } case WID_TT_BUTTONS: for (uint i = WID_TT_BEGIN; i < WID_TT_END; i++) { if (i == WID_TT_LOADING) continue; // Do not draw button for invisible loading indicators. const NWidgetBase *wi = this->GetWidget(i); DrawFrameRect(wi->pos_x + 1, r.top + 2, wi->pos_x + wi->current_x - 2, r.bottom - 2, COLOUR_PALE_GREEN, HasBit(_invisibility_opt, i - WID_TT_BEGIN) ? FR_LOWERED : FR_NONE); } break; } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget >= WID_TT_BEGIN && widget < WID_TT_END) { if (_ctrl_pressed) { /* toggle the bit of the transparencies lock variable */ ToggleTransparencyLock((TransparencyOption)(widget - WID_TT_BEGIN)); this->SetDirty(); } else { /* toggle the bit of the transparencies variable and play a sound */ ToggleTransparency((TransparencyOption)(widget - WID_TT_BEGIN)); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); MarkWholeScreenDirty(); } } else if (widget == WID_TT_BUTTONS) { uint i; for (i = WID_TT_BEGIN; i < WID_TT_END; i++) { const NWidgetBase *nwid = this->GetWidget(i); if (IsInsideBS(pt.x, nwid->pos_x, nwid->current_x)) { break; } } if (i == WID_TT_LOADING || i == WID_TT_END) return; ToggleInvisibility((TransparencyOption)(i - WID_TT_BEGIN)); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); /* Redraw whole screen only if transparency is set */ if (IsTransparencySet((TransparencyOption)(i - WID_TT_BEGIN))) { MarkWholeScreenDirty(); } else { this->SetWidgetDirty(WID_TT_BUTTONS); } } } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { Point pt = GetToolbarAlignedWindowPosition(sm_width); pt.y += 2 * (sm_height - this->GetWidget(WID_TT_BUTTONS)->current_y); return pt; } /** * 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; for (uint i = WID_TT_BEGIN; i < WID_TT_END; i++) { this->SetWidgetLoweredState(i, IsTransparencySet((TransparencyOption)(i - WID_TT_BEGIN))); } } }; static const NWidgetPart _nested_transparency_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TRANSPARENCY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_SIGNS), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SIGN, STR_TRANSPARENT_SIGNS_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_TREES), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_PLANTTREES, STR_TRANSPARENT_TREES_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_HOUSES), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TOWN, STR_TRANSPARENT_HOUSES_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_INDUSTRIES), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_INDUSTRY, STR_TRANSPARENT_INDUSTRIES_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_BUILDINGS), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_LIST, STR_TRANSPARENT_BUILDINGS_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_BRIDGES), SetMinimalSize(43, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BRIDGE, STR_TRANSPARENT_BRIDGES_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_STRUCTURES), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRANSMITTER, STR_TRANSPARENT_STRUCTURES_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_CATENARY), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_BUILD_X_ELRAIL, STR_TRANSPARENT_CATENARY_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_TT_LOADING), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_TRANSPARENT_LOADING_TOOLTIP), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 1), EndContainer(), EndContainer(), /* Panel with 'invisibility' buttons. */ NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_TT_BUTTONS), SetMinimalSize(219, 13), SetDataTip(0x0, STR_TRANSPARENT_INVISIBLE_TOOLTIP), EndContainer(), }; static WindowDesc _transparency_desc( WDP_MANUAL, "toolbar_transparency", 0, 0, WC_TRANSPARENCY_TOOLBAR, WC_NONE, 0, _nested_transparency_widgets, lengthof(_nested_transparency_widgets) ); /** * Show the transparency toolbar. */ void ShowTransparencyToolbar() { AllocateWindowDescFront(&_transparency_desc, 0); } openttd-1.5.3/src/group_cmd.cpp0000644000000000000000000005042312627373435015165 0ustar rootroot/* $Id: group_cmd.cpp 27090 2014-12-24 16:49:57Z frosch $ */ /* * 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 group_cmd.cpp Handling of the engine groups */ #include "stdafx.h" #include "cmd_helper.h" #include "command_func.h" #include "train.h" #include "vehiclelist.h" #include "vehicle_func.h" #include "autoreplace_base.h" #include "autoreplace_func.h" #include "string_func.h" #include "company_func.h" #include "core/pool_func.hpp" #include "order_backup.h" #include "table/strings.h" #include "safeguards.h" GroupID _new_group_id; GroupPool _group_pool("Group"); INSTANTIATE_POOL_METHODS(Group) GroupStatistics::GroupStatistics() { this->num_engines = CallocT(Engine::GetPoolSize()); } GroupStatistics::~GroupStatistics() { free(this->num_engines); } /** * Clear all caches. */ void GroupStatistics::Clear() { this->num_vehicle = 0; this->num_profit_vehicle = 0; this->profit_last_year = 0; /* This is also called when NewGRF change. So the number of engines might have changed. Reallocate. */ free(this->num_engines); this->num_engines = CallocT(Engine::GetPoolSize()); } /** * Returns the GroupStatistics for a specific group. * @param company Owner of the group. * @param id_g GroupID of the group. * @param type VehicleType of the vehicles in the group. * @return Statistics for the group. */ /* static */ GroupStatistics &GroupStatistics::Get(CompanyID company, GroupID id_g, VehicleType type) { if (Group::IsValidID(id_g)) { Group *g = Group::Get(id_g); assert(g->owner == company); assert(g->vehicle_type == type); return g->statistics; } if (IsDefaultGroupID(id_g)) return Company::Get(company)->group_default[type]; if (IsAllGroupID(id_g)) return Company::Get(company)->group_all[type]; NOT_REACHED(); } /** * Returns the GroupStatistic for the group of a vehicle. * @param v Vehicle. * @return GroupStatistics for the group of the vehicle. */ /* static */ GroupStatistics &GroupStatistics::Get(const Vehicle *v) { return GroupStatistics::Get(v->owner, v->group_id, v->type); } /** * Returns the GroupStatistic for the ALL_GROUPO of a vehicle type. * @param v Vehicle. * @return GroupStatistics for the ALL_GROUP of the vehicle type. */ /* static */ GroupStatistics &GroupStatistics::GetAllGroup(const Vehicle *v) { return GroupStatistics::Get(v->owner, ALL_GROUP, v->type); } /** * Update all caches after loading a game, changing NewGRF etc.. */ /* static */ void GroupStatistics::UpdateAfterLoad() { /* Set up the engine count for all companies */ Company *c; FOR_ALL_COMPANIES(c) { for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) { c->group_all[type].Clear(); c->group_default[type].Clear(); } } /* Recalculate */ Group *g; FOR_ALL_GROUPS(g) { g->statistics.Clear(); } const Vehicle *v; FOR_ALL_VEHICLES(v) { if (!v->IsEngineCountable()) continue; GroupStatistics::CountEngine(v, 1); if (v->IsPrimaryVehicle()) GroupStatistics::CountVehicle(v, 1); } FOR_ALL_COMPANIES(c) { GroupStatistics::UpdateAutoreplace(c->index); } } /** * Update num_vehicle when adding or removing a vehicle. * @param v Vehicle to count. * @param delta +1 to add, -1 to remove. */ /* static */ void GroupStatistics::CountVehicle(const Vehicle *v, int delta) { assert(delta == 1 || delta == -1); GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v); GroupStatistics &stats = GroupStatistics::Get(v); stats_all.num_vehicle += delta; stats.num_vehicle += delta; if (v->age > VEHICLE_PROFIT_MIN_AGE) { stats_all.num_profit_vehicle += delta; stats_all.profit_last_year += v->GetDisplayProfitLastYear() * delta; stats.num_profit_vehicle += delta; stats.profit_last_year += v->GetDisplayProfitLastYear() * delta; } } /** * Update num_engines when adding/removing an engine. * @param v Engine to count. * @param delta +1 to add, -1 to remove. */ /* static */ void GroupStatistics::CountEngine(const Vehicle *v, int delta) { assert(delta == 1 || delta == -1); GroupStatistics::GetAllGroup(v).num_engines[v->engine_type] += delta; GroupStatistics::Get(v).num_engines[v->engine_type] += delta; } /** * Add a vehicle to the profit sum of its group. */ /* static */ void GroupStatistics::VehicleReachedProfitAge(const Vehicle *v) { GroupStatistics &stats_all = GroupStatistics::GetAllGroup(v); GroupStatistics &stats = GroupStatistics::Get(v); stats_all.num_profit_vehicle++; stats_all.profit_last_year += v->GetDisplayProfitLastYear(); stats.num_profit_vehicle++; stats.profit_last_year += v->GetDisplayProfitLastYear(); } /** * Recompute the profits for all groups. */ /* static */ void GroupStatistics::UpdateProfits() { /* Set up the engine count for all companies */ Company *c; FOR_ALL_COMPANIES(c) { for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) { c->group_all[type].ClearProfits(); c->group_default[type].ClearProfits(); } } /* Recalculate */ Group *g; FOR_ALL_GROUPS(g) { g->statistics.ClearProfits(); } const Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->IsPrimaryVehicle() && v->age > VEHICLE_PROFIT_MIN_AGE) GroupStatistics::VehicleReachedProfitAge(v); } } /** * Update autoreplace_defined and autoreplace_finished of all statistics of a company. * @param company Company to update statistics for. */ /* static */ void GroupStatistics::UpdateAutoreplace(CompanyID company) { /* Set up the engine count for all companies */ Company *c = Company::Get(company); for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) { c->group_all[type].ClearAutoreplace(); c->group_default[type].ClearAutoreplace(); } /* Recalculate */ Group *g; FOR_ALL_GROUPS(g) { if (g->owner != company) continue; g->statistics.ClearAutoreplace(); } for (EngineRenewList erl = c->engine_renew_list; erl != NULL; erl = erl->next) { const Engine *e = Engine::Get(erl->from); GroupStatistics &stats = GroupStatistics::Get(company, erl->group_id, e->type); if (!stats.autoreplace_defined) { stats.autoreplace_defined = true; stats.autoreplace_finished = true; } if (stats.num_engines[erl->from] > 0) stats.autoreplace_finished = false; } } /** * Update the num engines of a groupID. Decrease the old one and increase the new one * @note called in SetTrainGroupID and UpdateTrainGroupID * @param v Vehicle we have to update * @param old_g index of the old group * @param new_g index of the new group */ static inline void UpdateNumEngineGroup(const Vehicle *v, GroupID old_g, GroupID new_g) { if (old_g != new_g) { /* Decrease the num engines in the old group */ GroupStatistics::Get(v->owner, old_g, v->type).num_engines[v->engine_type]--; /* Increase the num engines in the new group */ GroupStatistics::Get(v->owner, new_g, v->type).num_engines[v->engine_type]++; } } Group::Group(Owner owner) { this->owner = owner; } Group::~Group() { free(this->name); } /** * Create a new vehicle group. * @param tile unused * @param flags type of operation * @param p1 vehicle type * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleType vt = Extract(p1); if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR; if (!Group::CanAllocateItem()) return CMD_ERROR; if (flags & DC_EXEC) { Group *g = new Group(_current_company); g->replace_protection = false; g->vehicle_type = vt; g->parent = INVALID_GROUP; _new_group_id = g->index; InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack()); } return CommandCost(); } /** * Add all vehicles in the given group to the default group and then deletes the group. * @param tile unused * @param flags type of operation * @param p1 index of array group * - p1 bit 0-15 : GroupID * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Group *g = Group::GetIfValid(p1); if (g == NULL || g->owner != _current_company) return CMD_ERROR; /* Remove all vehicles from the group */ DoCommand(0, p1, 0, flags, CMD_REMOVE_ALL_VEHICLES_GROUP); /* Delete sub-groups */ Group *gp; FOR_ALL_GROUPS(gp) { if (gp->parent == g->index) { DoCommand(0, gp->index, 0, flags, CMD_DELETE_GROUP); } } if (flags & DC_EXEC) { /* Update backupped orders if needed */ OrderBackup::ClearGroup(g->index); /* If we set an autoreplace for the group we delete, remove it. */ if (_current_company < MAX_COMPANIES) { Company *c; EngineRenew *er; c = Company::Get(_current_company); FOR_ALL_ENGINE_RENEWS(er) { if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags); } } VehicleType vt = g->vehicle_type; /* Delete the Replace Vehicle Windows */ DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type); delete g; InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack()); } return CommandCost(); } static bool IsUniqueGroupNameForVehicleType(const char *name, VehicleType type) { const Group *g; FOR_ALL_GROUPS(g) { if (g->name != NULL && g->vehicle_type == type && strcmp(g->name, name) == 0) return false; } return true; } /** * Alter a group * @param tile unused * @param flags type of operation * @param p1 index of array group * - p1 bit 0-15 : GroupID * - p1 bit 16: 0 - Rename grouop * 1 - Set group parent * @param p2 parent group index * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Group *g = Group::GetIfValid(GB(p1, 0, 16)); if (g == NULL || g->owner != _current_company) return CMD_ERROR; if (!HasBit(p1, 16)) { /* Rename group */ bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR; if (!IsUniqueGroupNameForVehicleType(text, g->vehicle_type)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { /* Delete the old name */ free(g->name); /* Assign the new one */ g->name = reset ? NULL : stredup(text); } } else { /* Set group parent */ const Group *pg = Group::GetIfValid(GB(p2, 0, 16)); if (pg != NULL) { if (pg->owner != _current_company) return CMD_ERROR; if (pg->vehicle_type != g->vehicle_type) return CMD_ERROR; /* Ensure request parent isn't child of group. * This is the only place that infinite loops are prevented. */ if (GroupIsInGroup(pg->index, g->index)) return CMD_ERROR; } if (flags & DC_EXEC) { g->parent = (pg == NULL) ? INVALID_GROUP : pg->index; } } if (flags & DC_EXEC) { SetWindowDirty(WC_REPLACE_VEHICLE, g->vehicle_type); InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack()); } return CommandCost(); } /** * Do add a vehicle to a group. * @param v Vehicle to add. * @param new_g Group to add to. */ static void AddVehicleToGroup(Vehicle *v, GroupID new_g) { GroupStatistics::CountVehicle(v, -1); switch (v->type) { default: NOT_REACHED(); case VEH_TRAIN: SetTrainGroupID(Train::From(v), new_g); break; case VEH_ROAD: case VEH_SHIP: case VEH_AIRCRAFT: if (v->IsEngineCountable()) UpdateNumEngineGroup(v, v->group_id, new_g); v->group_id = new_g; break; } GroupStatistics::CountVehicle(v, 1); } /** * Add a vehicle to a group * @param tile unused * @param flags type of operation * @param p1 index of array group * - p1 bit 0-15 : GroupID * @param p2 vehicle to add to a group * - p2 bit 0-19 : VehicleID * - p2 bit 31 : Add shared vehicles as well. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(GB(p2, 0, 20)); GroupID new_g = p1; if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g) && new_g != NEW_GROUP)) return CMD_ERROR; if (Group::IsValidID(new_g)) { Group *g = Group::Get(new_g); if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR; } if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR; if (new_g == NEW_GROUP) { /* Create new group. */ CommandCost ret = CmdCreateGroup(0, flags, v->type, 0, NULL); if (ret.Failed()) return ret; new_g = _new_group_id; } if (flags & DC_EXEC) { AddVehicleToGroup(v, new_g); if (HasBit(p2, 31)) { /* Add vehicles in the shared order list as well. */ for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) { if (v2->group_id != new_g) AddVehicleToGroup(v2, new_g); } } GroupStatistics::UpdateAutoreplace(v->owner); /* Update the Replace Vehicle Windows */ SetWindowDirty(WC_REPLACE_VEHICLE, v->type); InvalidateWindowData(GetWindowClassForVehicleType(v->type), VehicleListIdentifier(VL_GROUP_LIST, v->type, _current_company).Pack()); } return CommandCost(); } /** * Add all shared vehicles of all vehicles from a group * @param tile unused * @param flags type of operation * @param p1 index of group array * - p1 bit 0-15 : GroupID * @param p2 type of vehicles * @param text unused * @return the cost of this operation or an error */ CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleType type = Extract(p2); GroupID id_g = p1; if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR; if (flags & DC_EXEC) { Vehicle *v; /* Find the first front engine which belong to the group id_g * then add all shared vehicles of this front engine to the group id_g */ FOR_ALL_VEHICLES(v) { if (v->type == type && v->IsPrimaryVehicle()) { if (v->group_id != id_g) continue; /* For each shared vehicles add it to the group */ for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) { if (v2->group_id != id_g) DoCommand(tile, id_g, v2->index, flags, CMD_ADD_VEHICLE_GROUP, text); } } } InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack()); } return CommandCost(); } /** * Remove all vehicles from a group * @param tile unused * @param flags type of operation * @param p1 index of group array * - p1 bit 0-15 : GroupID * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { GroupID old_g = p1; Group *g = Group::GetIfValid(old_g); if (g == NULL || g->owner != _current_company) return CMD_ERROR; if (flags & DC_EXEC) { Vehicle *v; /* Find each Vehicle that belongs to the group old_g and add it to the default group */ FOR_ALL_VEHICLES(v) { if (v->IsPrimaryVehicle()) { if (v->group_id != old_g) continue; /* Add The Vehicle to the default group */ DoCommand(tile, DEFAULT_GROUP, v->index, flags, CMD_ADD_VEHICLE_GROUP, text); } } InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack()); } return CommandCost(); } /** * Set replace protection for a group and its sub-groups. * @param g initial group. * @param protect 1 to set or 0 to clear protection. */ static void SetGroupReplaceProtection(Group *g, bool protect) { g->replace_protection = protect; Group *pg; FOR_ALL_GROUPS(pg) { if (pg->parent == g->index) SetGroupReplaceProtection(pg, protect); } } /** * (Un)set global replace protection from a group * @param tile unused * @param flags type of operation * @param p1 index of group array * - p1 bit 0-15 : GroupID * @param p2 * - p2 bit 0 : 1 to set or 0 to clear protection. * - p2 bit 1 : 1 to apply to sub-groups. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Group *g = Group::GetIfValid(p1); if (g == NULL || g->owner != _current_company) return CMD_ERROR; if (flags & DC_EXEC) { if (HasBit(p2, 1)) { SetGroupReplaceProtection(g, HasBit(p2, 0)); } else { g->replace_protection = HasBit(p2, 0); } SetWindowDirty(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack()); InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type); } return CommandCost(); } /** * Decrease the num_vehicle variable before delete an front engine from a group * @note Called in CmdSellRailWagon and DeleteLasWagon, * @param v FrontEngine of the train we want to remove. */ void RemoveVehicleFromGroup(const Vehicle *v) { if (!v->IsPrimaryVehicle()) return; if (!IsDefaultGroupID(v->group_id)) GroupStatistics::CountVehicle(v, -1); } /** * Affect the groupID of a train to new_g. * @note called in CmdAddVehicleGroup and CmdMoveRailVehicle * @param v First vehicle of the chain. * @param new_g index of array group */ void SetTrainGroupID(Train *v, GroupID new_g) { if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return; assert(v->IsFrontEngine() || IsDefaultGroupID(new_g)); for (Vehicle *u = v; u != NULL; u = u->Next()) { if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g); u->group_id = new_g; } /* Update the Replace Vehicle Windows */ GroupStatistics::UpdateAutoreplace(v->owner); SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN); } /** * Recalculates the groupID of a train. Should be called each time a vehicle is added * to/removed from the chain,. * @note this needs to be called too for 'wagon chains' (in the depot, without an engine) * @note Called in CmdBuildRailVehicle, CmdBuildRailWagon, CmdMoveRailVehicle, CmdSellRailWagon * @param v First vehicle of the chain. */ void UpdateTrainGroupID(Train *v) { assert(v->IsFrontEngine() || v->IsFreeWagon()); GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP; for (Vehicle *u = v; u != NULL; u = u->Next()) { if (u->IsEngineCountable()) UpdateNumEngineGroup(u, u->group_id, new_g); u->group_id = new_g; } /* Update the Replace Vehicle Windows */ GroupStatistics::UpdateAutoreplace(v->owner); SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN); } /** * Get the number of engines with EngineID id_e in the group with GroupID * id_g and its sub-groups. * @param company The company the group belongs to * @param id_g The GroupID of the group used * @param id_e The EngineID of the engine to count * @return The number of engines with EngineID id_e in the group */ uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e) { uint count = 0; const Engine *e = Engine::Get(id_e); const Group *g; FOR_ALL_GROUPS(g) { if (g->parent == id_g) count += GetGroupNumEngines(company, g->index, id_e); } return count + GroupStatistics::Get(company, id_g, e->type).num_engines[id_e]; } void RemoveAllGroupsForCompany(const CompanyID company) { Group *g; FOR_ALL_GROUPS(g) { if (company == g->owner) delete g; } } /** * Test if GroupID group is a descendant of (or is) GroupID search * @param search The GroupID to search in * @param group The GroupID to search for * @return True iff group is search or a descendant of search */ bool GroupIsInGroup(GroupID search, GroupID group) { if (!Group::IsValidID(search)) return search == group; do { if (search == group) return true; search = Group::Get(search)->parent; } while (search != INVALID_GROUP); return false; } openttd-1.5.3/src/road_gui.h0000644000000000000000000000177212627373445014450 0ustar rootroot/* $Id: road_gui.h 21887 2011-01-22 10:10:03Z rubidium $ */ /* * 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 road_gui.h Functions/types related to the road GUIs. */ #ifndef ROAD_GUI_H #define ROAD_GUI_H #include "road_type.h" #include "tile_type.h" #include "direction_type.h" struct Window *ShowBuildRoadToolbar(RoadType roadtype); struct Window *ShowBuildRoadScenToolbar(); void ConnectRoadToStructure(TileIndex tile, DiagDirection direction); #endif /* ROAD_GUI_H */ openttd-1.5.3/src/cpu.h0000644000000000000000000000270612627373435013443 0ustar rootroot/* $Id: cpu.h 26207 2014-01-02 18:52:54Z rubidium $ */ /* * 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 cpu.h Functions related to CPU specific instructions. */ #ifndef CPU_H #define CPU_H /** * Get the tick counter from the CPU (high precision timing). * @return The count. */ uint64 ottd_rdtsc(); /** * Get the CPUID information from the CPU. * @param info The retrieved info. All zeros on architectures without CPUID. * @param type The information this instruction should retrieve. */ void ottd_cpuid(int info[4], int type); /** * Check whether the current CPU has the given flag. * @param type The type to be passing to cpuid (usually 1). * @param index The index in the returned info array. * @param bit The bit index that needs to be set. * @return The value of the bit, or false when there is no CPUID or the type is not available. */ bool HasCPUIDFlag(uint type, uint index, uint bit); #endif /* CPU_H */ openttd-1.5.3/src/game/0000755000000000000000000000000012627373442013405 5ustar rootrootopenttd-1.5.3/src/game/game_scanner.cpp0000644000000000000000000000732112627373442016536 0ustar rootroot/* $Id: game_scanner.cpp 26487 2014-04-23 21:16:58Z rubidium $ */ /* * 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 game_scanner.cpp allows scanning Game scripts */ #include "../stdafx.h" #include "../script/squirrel_class.hpp" #include "game_info.hpp" #include "game_scanner.hpp" #include "../safeguards.h" void GameScannerInfo::Initialize() { ScriptScanner::Initialize("GSScanner"); } void GameScannerInfo::GetScriptName(ScriptInfo *info, char *name, const char *last) { seprintf(name, last, "%s", info->GetName()); } void GameScannerInfo::RegisterAPI(class Squirrel *engine) { GameInfo::RegisterAPI(engine); } GameInfo *GameScannerInfo::FindInfo(const char *nameParam, int versionParam, bool force_exact_match) { if (this->info_list.size() == 0) return NULL; if (nameParam == NULL) return NULL; char game_name[1024]; strecpy(game_name, nameParam, lastof(game_name)); strtolower(game_name); GameInfo *info = NULL; int version = -1; if (versionParam == -1) { /* We want to load the latest version of this Game script; so find it */ if (this->info_single_list.find(game_name) != this->info_single_list.end()) return static_cast(this->info_single_list[game_name]); /* If we didn't find a match Game script, maybe the user included a version */ char *e = strrchr(game_name, '.'); if (e == NULL) return NULL; *e = '\0'; e++; versionParam = atoi(e); /* FALL THROUGH, like we were calling this function with a version. */ } if (force_exact_match) { /* Try to find a direct 'name.version' match */ char game_name_tmp[1024]; seprintf(game_name_tmp, lastof(game_name_tmp), "%s.%d", game_name, versionParam); strtolower(game_name_tmp); if (this->info_list.find(game_name_tmp) != this->info_list.end()) return static_cast(this->info_list[game_name_tmp]); } /* See if there is a compatible Game script which goes by that name, with the highest * version which allows loading the requested version */ ScriptInfoList::iterator it = this->info_list.begin(); for (; it != this->info_list.end(); it++) { GameInfo *i = static_cast((*it).second); if (strcasecmp(game_name, i->GetName()) == 0 && i->CanLoadFromVersion(versionParam) && (version == -1 || i->GetVersion() > version)) { version = (*it).second->GetVersion(); info = i; } } return info; } void GameScannerLibrary::Initialize() { ScriptScanner::Initialize("GSScanner"); } void GameScannerLibrary::GetScriptName(ScriptInfo *info, char *name, const char *last) { GameLibrary *library = static_cast(info); seprintf(name, last, "%s.%s", library->GetCategory(), library->GetInstanceName()); } void GameScannerLibrary::RegisterAPI(class Squirrel *engine) { GameLibrary::RegisterAPI(engine); } GameLibrary *GameScannerLibrary::FindLibrary(const char *library, int version) { /* Internally we store libraries as 'library.version' */ char library_name[1024]; seprintf(library_name, lastof(library_name), "%s.%d", library, version); strtolower(library_name); /* Check if the library + version exists */ ScriptInfoList::iterator iter = this->info_list.find(library_name); if (iter == this->info_list.end()) return NULL; return static_cast((*iter).second); } openttd-1.5.3/src/game/game_config.cpp0000644000000000000000000000325012627373442016347 0ustar rootroot/* $Id: game_config.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 game_config.cpp Implementation of GameConfig. */ #include "../stdafx.h" #include "../settings_type.h" #include "game.hpp" #include "game_config.hpp" #include "game_info.hpp" #include "../safeguards.h" /* static */ GameConfig *GameConfig::GetConfig(ScriptSettingSource source) { GameConfig **config; if (source == SSS_FORCE_NEWGAME || (source == SSS_DEFAULT && _game_mode == GM_MENU)) { config = &_settings_newgame.game_config; } else { config = &_settings_game.game_config; } if (*config == NULL) *config = new GameConfig(); return *config; } class GameInfo *GameConfig::GetInfo() const { return static_cast(ScriptConfig::GetInfo()); } ScriptInfo *GameConfig::FindInfo(const char *name, int version, bool force_exact_match) { return static_cast(Game::FindInfo(name, version, force_exact_match)); } bool GameConfig::ResetInfo(bool force_exact_match) { this->info = (ScriptInfo *)Game::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); return this->info != NULL; } openttd-1.5.3/src/game/game_scanner.hpp0000644000000000000000000000472312627373442016546 0ustar rootroot/* $Id: game_scanner.hpp 26487 2014-04-23 21:16:58Z rubidium $ */ /* * 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 game_scanner.hpp declarations of the class for Game scanner */ #ifndef GAME_SCANNER_HPP #define GAME_SCANNER_HPP #include "../script/script_scanner.hpp" class GameScannerInfo : public ScriptScanner { public: /* virtual */ void Initialize(); /** * Check if we have a game by name and version available in our list. * @param nameParam The name of the game script. * @param versionParam The version of the game script, or -1 if you want the latest. * @param force_exact_match Only match name+version, never latest. * @return NULL if no match found, otherwise the game script that matched. */ class GameInfo *FindInfo(const char *nameParam, int versionParam, bool force_exact_match); protected: /* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last); /* virtual */ const char *GetFileName() const { return PATHSEP "info.nut"; } /* virtual */ Subdirectory GetDirectory() const { return GAME_DIR; } /* virtual */ const char *GetScannerName() const { return "Game Scripts"; } /* virtual */ void RegisterAPI(class Squirrel *engine); }; class GameScannerLibrary : public ScriptScanner { public: /* virtual */ void Initialize(); /** * Find a library in the pool. * @param library The library name to find. * @param version The version the library should have. * @return The library if found, NULL otherwise. */ class GameLibrary *FindLibrary(const char *library, int version); protected: /* virtual */ void GetScriptName(ScriptInfo *info, char *name, const char *last); /* virtual */ const char *GetFileName() const { return PATHSEP "library.nut"; } /* virtual */ Subdirectory GetDirectory() const { return GAME_LIBRARY_DIR; } /* virtual */ const char *GetScannerName() const { return "GS Libraries"; } /* virtual */ void RegisterAPI(class Squirrel *engine); }; #endif /* GAME_SCANNER_HPP */ openttd-1.5.3/src/game/game_core.cpp0000644000000000000000000001714312627373442016040 0ustar rootroot/* $Id: game_core.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 game_core.cpp Implementation of Game. */ #include "../stdafx.h" #include "../core/backup_type.hpp" #include "../company_base.h" #include "../company_func.h" #include "../network/network.h" #include "../window_func.h" #include "game.hpp" #include "game_scanner.hpp" #include "game_config.hpp" #include "game_instance.hpp" #include "game_info.hpp" #include "../safeguards.h" /* static */ uint Game::frame_counter = 0; /* static */ GameInfo *Game::info = NULL; /* static */ GameInstance *Game::instance = NULL; /* static */ GameScannerInfo *Game::scanner_info = NULL; /* static */ GameScannerLibrary *Game::scanner_library = NULL; /* static */ void Game::GameLoop() { if (_networking && !_network_server) return; if (Game::instance == NULL) return; Game::frame_counter++; Backup cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); Game::instance->GameLoop(); cur_company.Restore(); /* Occasionally collect garbage */ if ((Game::frame_counter & 255) == 0) { Game::instance->CollectGarbage(); } } /* static */ void Game::Initialize() { if (Game::instance != NULL) Game::Uninitialize(true); Game::frame_counter = 0; if (Game::scanner_info == NULL) { TarScanner::DoScan(TarScanner::GAME); Game::scanner_info = new GameScannerInfo(); Game::scanner_info->Initialize(); Game::scanner_library = new GameScannerLibrary(); Game::scanner_library->Initialize(); } } /* static */ void Game::StartNew() { if (Game::instance != NULL) return; /* Clients shouldn't start GameScripts */ if (_networking && !_network_server) return; GameConfig *config = GameConfig::GetConfig(GameConfig::SSS_FORCE_GAME); GameInfo *info = config->GetInfo(); if (info == NULL) return; config->AnchorUnchangeableSettings(); Backup cur_company(_current_company, FILE_LINE); cur_company.Change(OWNER_DEITY); Game::info = info; Game::instance = new GameInstance(); Game::instance->Initialize(info); cur_company.Restore(); InvalidateWindowData(WC_AI_DEBUG, 0, -1); } /* static */ void Game::Uninitialize(bool keepConfig) { Backup cur_company(_current_company, FILE_LINE); delete Game::instance; Game::instance = NULL; Game::info = NULL; cur_company.Restore(); if (keepConfig) { Rescan(); } else { delete Game::scanner_info; delete Game::scanner_library; Game::scanner_info = NULL; Game::scanner_library = NULL; if (_settings_game.game_config != NULL) { delete _settings_game.game_config; _settings_game.game_config = NULL; } if (_settings_newgame.game_config != NULL) { delete _settings_newgame.game_config; _settings_newgame.game_config = NULL; } } } /* static */ void Game::Pause() { if (Game::instance != NULL) Game::instance->Pause(); } /* static */ void Game::Unpause() { if (Game::instance != NULL) Game::instance->Unpause(); } /* static */ bool Game::IsPaused() { return Game::instance != NULL? Game::instance->IsPaused() : false; } /* static */ void Game::NewEvent(ScriptEvent *event) { /* AddRef() and Release() need to be called at least once, so do it here */ event->AddRef(); /* Clients should ignore events */ if (_networking && !_network_server) { event->Release(); return; } /* Check if Game instance is alive */ if (Game::instance == NULL) { event->Release(); return; } /* Queue the event */ Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->InsertEvent(event); cur_company.Restore(); event->Release(); } /* static */ void Game::ResetConfig() { /* Check for both newgame as current game if we can reload the GameInfo inside * the GameConfig. If not, remove the Game from the list. */ if (_settings_game.game_config != NULL && _settings_game.game_config->HasScript()) { if (!_settings_game.game_config->ResetInfo(true)) { DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_game.game_config->GetName()); _settings_game.game_config->Change(NULL); if (Game::instance != NULL) { delete Game::instance; Game::instance = NULL; Game::info = NULL; } } else if (Game::instance != NULL) { Game::info = _settings_game.game_config->GetInfo(); } } if (_settings_newgame.game_config != NULL && _settings_newgame.game_config->HasScript()) { if (!_settings_newgame.game_config->ResetInfo(false)) { DEBUG(script, 0, "After a reload, the GameScript by the name '%s' was no longer found, and removed from the list.", _settings_newgame.game_config->GetName()); _settings_newgame.game_config->Change(NULL); } } } /* static */ void Game::Rescan() { TarScanner::DoScan(TarScanner::GAME); Game::scanner_info->RescanDir(); Game::scanner_library->RescanDir(); ResetConfig(); InvalidateWindowData(WC_AI_LIST, 0, 1); SetWindowClassesDirty(WC_AI_DEBUG); InvalidateWindowClassesData(WC_AI_SETTINGS); } /* static */ void Game::Save() { if (Game::instance != NULL && (!_networking || _network_server)) { Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->Save(); cur_company.Restore(); } else { GameInstance::SaveEmpty(); } } /* static */ void Game::Load(int version) { if (Game::instance != NULL && (!_networking || _network_server)) { Backup cur_company(_current_company, OWNER_DEITY, FILE_LINE); Game::instance->Load(version); cur_company.Restore(); } else { /* Read, but ignore, the load data */ GameInstance::LoadEmpty(); } } /* static */ char *Game::GetConsoleList(char *p, const char *last, bool newest_only) { return Game::scanner_info->GetConsoleList(p, last, newest_only); } /* static */ char *Game::GetConsoleLibraryList(char *p, const char *last) { return Game::scanner_library->GetConsoleList(p, last, true); } /* static */ const ScriptInfoList *Game::GetInfoList() { return Game::scanner_info->GetInfoList(); } /* static */ const ScriptInfoList *Game::GetUniqueInfoList() { return Game::scanner_info->GetUniqueInfoList(); } /* static */ GameInfo *Game::FindInfo(const char *name, int version, bool force_exact_match) { return Game::scanner_info->FindInfo(name, version, force_exact_match); } /* static */ GameLibrary *Game::FindLibrary(const char *library, int version) { return Game::scanner_library->FindLibrary(library, version); } #if defined(ENABLE_NETWORK) /** * Check whether we have an Game (library) with the exact characteristics as ci. * @param ci the characteristics to search on (shortname and md5sum) * @param md5sum whether to check the MD5 checksum * @return true iff we have an Game (library) matching. */ /* static */ bool Game::HasGame(const ContentInfo *ci, bool md5sum) { return Game::scanner_info->HasScript(ci, md5sum); } /* static */ bool Game::HasGameLibrary(const ContentInfo *ci, bool md5sum) { return Game::scanner_library->HasScript(ci, md5sum); } #endif /* defined(ENABLE_NETWORK) */ /* static */ GameScannerInfo *Game::GetScannerInfo() { return Game::scanner_info; } /* static */ GameScannerLibrary *Game::GetScannerLibrary() { return Game::scanner_library; } openttd-1.5.3/src/game/game_instance.cpp0000644000000000000000000002444112627373442016713 0ustar rootroot/* $Id: game_instance.cpp 26893 2014-09-21 16:20:48Z fonsinchen $ */ /* * 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 game_instance.cpp Implementation of GameInstance. */ #include "../stdafx.h" #include "../error.h" #include "../script/squirrel_class.hpp" #include "../script/script_storage.hpp" #include "../ai/ai_gui.hpp" #include "game_config.hpp" #include "game_info.hpp" #include "game_instance.hpp" #include "game_text.hpp" #include "game.hpp" /* Convert all Game related classes to Squirrel data. * Note: this line is a marker in squirrel_export.sh. Do not change! */ #include "../script/api/game/game_accounting.hpp.sq" #include "../script/api/game/game_admin.hpp.sq" #include "../script/api/game/game_airport.hpp.sq" #include "../script/api/game/game_base.hpp.sq" #include "../script/api/game/game_basestation.hpp.sq" #include "../script/api/game/game_bridge.hpp.sq" #include "../script/api/game/game_bridgelist.hpp.sq" #include "../script/api/game/game_cargo.hpp.sq" #include "../script/api/game/game_cargolist.hpp.sq" #include "../script/api/game/game_cargomonitor.hpp.sq" #include "../script/api/game/game_company.hpp.sq" #include "../script/api/game/game_companymode.hpp.sq" #include "../script/api/game/game_controller.hpp.sq" #include "../script/api/game/game_date.hpp.sq" #include "../script/api/game/game_depotlist.hpp.sq" #include "../script/api/game/game_engine.hpp.sq" #include "../script/api/game/game_enginelist.hpp.sq" #include "../script/api/game/game_error.hpp.sq" #include "../script/api/game/game_event.hpp.sq" #include "../script/api/game/game_event_types.hpp.sq" #include "../script/api/game/game_execmode.hpp.sq" #include "../script/api/game/game_game.hpp.sq" #include "../script/api/game/game_gamesettings.hpp.sq" #include "../script/api/game/game_goal.hpp.sq" #include "../script/api/game/game_industry.hpp.sq" #include "../script/api/game/game_industrylist.hpp.sq" #include "../script/api/game/game_industrytype.hpp.sq" #include "../script/api/game/game_industrytypelist.hpp.sq" #include "../script/api/game/game_infrastructure.hpp.sq" #include "../script/api/game/game_list.hpp.sq" #include "../script/api/game/game_log.hpp.sq" #include "../script/api/game/game_map.hpp.sq" #include "../script/api/game/game_marine.hpp.sq" #include "../script/api/game/game_news.hpp.sq" #include "../script/api/game/game_order.hpp.sq" #include "../script/api/game/game_rail.hpp.sq" #include "../script/api/game/game_railtypelist.hpp.sq" #include "../script/api/game/game_road.hpp.sq" #include "../script/api/game/game_sign.hpp.sq" #include "../script/api/game/game_signlist.hpp.sq" #include "../script/api/game/game_station.hpp.sq" #include "../script/api/game/game_stationlist.hpp.sq" #include "../script/api/game/game_story_page.hpp.sq" #include "../script/api/game/game_storypageelementlist.hpp.sq" #include "../script/api/game/game_storypagelist.hpp.sq" #include "../script/api/game/game_subsidy.hpp.sq" #include "../script/api/game/game_subsidylist.hpp.sq" #include "../script/api/game/game_testmode.hpp.sq" #include "../script/api/game/game_text.hpp.sq" #include "../script/api/game/game_tile.hpp.sq" #include "../script/api/game/game_tilelist.hpp.sq" #include "../script/api/game/game_town.hpp.sq" #include "../script/api/game/game_townlist.hpp.sq" #include "../script/api/game/game_tunnel.hpp.sq" #include "../script/api/game/game_vehicle.hpp.sq" #include "../script/api/game/game_vehiclelist.hpp.sq" #include "../script/api/game/game_viewport.hpp.sq" #include "../script/api/game/game_waypoint.hpp.sq" #include "../script/api/game/game_waypointlist.hpp.sq" #include "../script/api/game/game_window.hpp.sq" #include "../safeguards.h" GameInstance::GameInstance() : ScriptInstance("GS") {} void GameInstance::Initialize(GameInfo *info) { this->versionAPI = info->GetAPIVersion(); /* Register the GameController */ SQGSController_Register(this->engine); ScriptInstance::Initialize(info->GetMainScript(), info->GetInstanceName(), OWNER_DEITY); } void GameInstance::RegisterAPI() { ScriptInstance::RegisterAPI(); /* Register all classes */ SQGSList_Register(this->engine); SQGSAccounting_Register(this->engine); SQGSAdmin_Register(this->engine); SQGSAirport_Register(this->engine); SQGSBase_Register(this->engine); SQGSBaseStation_Register(this->engine); SQGSBridge_Register(this->engine); SQGSBridgeList_Register(this->engine); SQGSBridgeList_Length_Register(this->engine); SQGSCargo_Register(this->engine); SQGSCargoList_Register(this->engine); SQGSCargoList_IndustryAccepting_Register(this->engine); SQGSCargoList_IndustryProducing_Register(this->engine); SQGSCargoList_StationAccepting_Register(this->engine); SQGSCargoMonitor_Register(this->engine); SQGSCompany_Register(this->engine); SQGSCompanyMode_Register(this->engine); SQGSDate_Register(this->engine); SQGSDepotList_Register(this->engine); SQGSEngine_Register(this->engine); SQGSEngineList_Register(this->engine); SQGSError_Register(this->engine); SQGSEvent_Register(this->engine); SQGSEventAdminPort_Register(this->engine); SQGSEventCompanyBankrupt_Register(this->engine); SQGSEventCompanyInTrouble_Register(this->engine); SQGSEventCompanyMerger_Register(this->engine); SQGSEventCompanyNew_Register(this->engine); SQGSEventCompanyTown_Register(this->engine); SQGSEventController_Register(this->engine); SQGSEventExclusiveTransportRights_Register(this->engine); SQGSEventGoalQuestionAnswer_Register(this->engine); SQGSEventIndustryClose_Register(this->engine); SQGSEventIndustryOpen_Register(this->engine); SQGSEventRoadReconstruction_Register(this->engine); SQGSEventStationFirstVehicle_Register(this->engine); SQGSEventSubsidyAwarded_Register(this->engine); SQGSEventSubsidyExpired_Register(this->engine); SQGSEventSubsidyOffer_Register(this->engine); SQGSEventSubsidyOfferExpired_Register(this->engine); SQGSEventTownFounded_Register(this->engine); SQGSEventVehicleCrashed_Register(this->engine); SQGSEventWindowWidgetClick_Register(this->engine); SQGSExecMode_Register(this->engine); SQGSGame_Register(this->engine); SQGSGameSettings_Register(this->engine); SQGSGoal_Register(this->engine); SQGSIndustry_Register(this->engine); SQGSIndustryList_Register(this->engine); SQGSIndustryList_CargoAccepting_Register(this->engine); SQGSIndustryList_CargoProducing_Register(this->engine); SQGSIndustryType_Register(this->engine); SQGSIndustryTypeList_Register(this->engine); SQGSInfrastructure_Register(this->engine); SQGSLog_Register(this->engine); SQGSMap_Register(this->engine); SQGSMarine_Register(this->engine); SQGSNews_Register(this->engine); SQGSOrder_Register(this->engine); SQGSRail_Register(this->engine); SQGSRailTypeList_Register(this->engine); SQGSRoad_Register(this->engine); SQGSSign_Register(this->engine); SQGSSignList_Register(this->engine); SQGSStation_Register(this->engine); SQGSStationList_Register(this->engine); SQGSStationList_Cargo_Register(this->engine); SQGSStationList_CargoPlanned_Register(this->engine); SQGSStationList_CargoPlannedByFrom_Register(this->engine); SQGSStationList_CargoPlannedByVia_Register(this->engine); SQGSStationList_CargoPlannedFromByVia_Register(this->engine); SQGSStationList_CargoPlannedViaByFrom_Register(this->engine); SQGSStationList_CargoWaiting_Register(this->engine); SQGSStationList_CargoWaitingByFrom_Register(this->engine); SQGSStationList_CargoWaitingByVia_Register(this->engine); SQGSStationList_CargoWaitingFromByVia_Register(this->engine); SQGSStationList_CargoWaitingViaByFrom_Register(this->engine); SQGSStationList_Vehicle_Register(this->engine); SQGSStoryPage_Register(this->engine); SQGSStoryPageElementList_Register(this->engine); SQGSStoryPageList_Register(this->engine); SQGSSubsidy_Register(this->engine); SQGSSubsidyList_Register(this->engine); SQGSTestMode_Register(this->engine); SQGSText_Register(this->engine); SQGSTile_Register(this->engine); SQGSTileList_Register(this->engine); SQGSTileList_IndustryAccepting_Register(this->engine); SQGSTileList_IndustryProducing_Register(this->engine); SQGSTileList_StationType_Register(this->engine); SQGSTown_Register(this->engine); SQGSTownEffectList_Register(this->engine); SQGSTownList_Register(this->engine); SQGSTunnel_Register(this->engine); SQGSVehicle_Register(this->engine); SQGSVehicleList_Register(this->engine); SQGSVehicleList_Depot_Register(this->engine); SQGSVehicleList_SharedOrders_Register(this->engine); SQGSVehicleList_Station_Register(this->engine); SQGSViewport_Register(this->engine); SQGSWaypoint_Register(this->engine); SQGSWaypointList_Register(this->engine); SQGSWaypointList_Vehicle_Register(this->engine); SQGSWindow_Register(this->engine); RegisterGameTranslation(this->engine); if (!this->LoadCompatibilityScripts(this->versionAPI, GAME_DIR)) this->Died(); } int GameInstance::GetSetting(const char *name) { return GameConfig::GetConfig()->GetSetting(name); } ScriptInfo *GameInstance::FindLibrary(const char *library, int version) { return (ScriptInfo *)Game::FindLibrary(library, version); } void GameInstance::Died() { ScriptInstance::Died(); ShowAIDebugWindow(OWNER_DEITY); const GameInfo *info = Game::GetInfo(); if (info != NULL) { ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, WL_WARNING); if (info->GetURL() != NULL) { ScriptLog::Info("Please report the error to the following URL:"); ScriptLog::Info(info->GetURL()); } } } /** * DoCommand callback function for all commands executed by Game Scripts. * @param result The result of the command. * @param tile The tile on which the command was executed. * @param p1 p1 as given to DoCommandPInternal. * @param p2 p2 as given to DoCommandPInternal. */ void CcGame(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { Game::GetGameInstance()->DoCommandCallback(result, tile, p1, p2); Game::GetGameInstance()->Continue(); } CommandCallback *GameInstance::GetDoCommandCallback() { return &CcGame; } openttd-1.5.3/src/game/game.hpp0000644000000000000000000001040212627373442015024 0ustar rootroot/* $Id: game.hpp 25114 2013-03-22 21:21:45Z frosch $ */ /* * 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 game.hpp Base functions for all Games. */ #ifndef GAME_HPP #define GAME_HPP #include "../core/string_compare_type.hpp" #include "game_scanner.hpp" #include /** A list that maps AI names to their AIInfo object. */ typedef std::map ScriptInfoList; #include "../script/api/script_event_types.hpp" /** * Main Game class. Contains all functions needed to start, stop, save and load Game Scripts. */ class Game { public: /** * Called every game-tick to let Game do something. */ static void GameLoop(); /** * Initialize the Game system. */ static void Initialize(); /** * Start up a new GameScript. */ static void StartNew(); /** * Uninitialize the Game system. */ static void Uninitialize(bool keepConfig); /** * Suspends the Game Script and then pause the execution of the script. The * script will not be resumed from its suspended state until the script * has been unpaused. */ static void Pause(); /** * Resume execution of the Game Script. This function will not actually execute * the script, but set a flag so that the script is executed my the usual * mechanism that executes the script. */ static void Unpause(); /** * Checks if the Game Script is paused. * @return true if the Game Script is paused, otherwise false. */ static bool IsPaused(); /** * Queue a new event for a Game Script. */ static void NewEvent(class ScriptEvent *event); /** * Get the current GameScript instance. */ static class GameInstance *GetGameInstance() { return Game::instance; } /** * Get the current GameInfo. */ static class GameInfo *GetInfo() { return Game::info; } static void Rescan(); static void ResetConfig(); /** * Save data from a GameScript to a savegame. */ static void Save(); /** * Load data for a GameScript from a savegame. */ static void Load(int version); /** Wrapper function for GameScanner::GetConsoleList */ static char *GetConsoleList(char *p, const char *last, bool newest_only = false); /** Wrapper function for GameScanner::GetConsoleLibraryList */ static char *GetConsoleLibraryList(char *p, const char *last); /** Wrapper function for GameScanner::GetInfoList */ static const ScriptInfoList *GetInfoList(); /** Wrapper function for GameScanner::GetUniqueInfoList */ static const ScriptInfoList *GetUniqueInfoList(); /** Wrapper function for GameScannerInfo::FindInfo */ static class GameInfo *FindInfo(const char *name, int version, bool force_exact_match); /** Wrapper function for GameScanner::FindLibrary */ static class GameLibrary *FindLibrary(const char *library, int version); /** * Get the current active instance. */ static class GameInstance *GetInstance() { return Game::instance; } #if defined(ENABLE_NETWORK) /** Wrapper function for GameScanner::HasGame */ static bool HasGame(const struct ContentInfo *ci, bool md5sum); static bool HasGameLibrary(const ContentInfo *ci, bool md5sum); #endif /** Gets the ScriptScanner instance that is used to find Game scripts */ static GameScannerInfo *GetScannerInfo(); /** Gets the ScriptScanner instance that is used to find Game Libraries */ static GameScannerLibrary *GetScannerLibrary(); private: static uint frame_counter; ///< Tick counter for the Game code. static class GameInstance *instance; ///< Instance to the current active Game. static class GameScannerInfo *scanner_info; ///< Scanner for Game scripts. static class GameScannerLibrary *scanner_library; ///< Scanner for GS Libraries. static class GameInfo *info; ///< Current selected GameInfo. }; #endif /* GAME_HPP */ openttd-1.5.3/src/game/game_config.hpp0000644000000000000000000000317112627373442016356 0ustar rootroot/* $Id: game_config.hpp 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 game_config.hpp GameConfig stores the configuration settings of every Game. */ #ifndef GAME_CONFIG_HPP #define GAME_CONFIG_HPP #include "../script/script_config.hpp" class GameConfig : public ScriptConfig { public: /** * Get the config of a company. */ static GameConfig *GetConfig(ScriptSettingSource source = SSS_DEFAULT); GameConfig() : ScriptConfig() {} GameConfig(const GameConfig *config) : ScriptConfig(config) {} class GameInfo *GetInfo() const; /** * When ever the Game Scanner is reloaded, all infos become invalid. This * function tells GameConfig about this. * @param force_exact_match If true try to find the exact same version * as specified. If false any version is ok. * @return \c true if the reset was successful, \c false if the Game was no longer * found. */ bool ResetInfo(bool force_exact_match); protected: /* virtual */ ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match); }; #endif /* GAME_CONFIG_HPP */ openttd-1.5.3/src/game/game_info.cpp0000644000000000000000000001176712627373442016051 0ustar rootroot/* $Id: game_info.cpp 26774 2014-09-06 17:46:56Z rubidium $ */ /* * 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 game_info.cpp Implementation of GameInfo */ #include "../stdafx.h" #include "../script/squirrel_class.hpp" #include "game_info.hpp" #include "game_scanner.hpp" #include "../debug.h" #include "../safeguards.h" /** * Check if the API version provided by the Game is supported. * @param api_version The API version as provided by the Game. */ static bool CheckAPIVersion(const char *api_version) { return strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 || strcmp(api_version, "1.5") == 0; } #if defined(WIN32) #undef GetClassName #endif /* WIN32 */ template <> const char *GetClassName() { return "GSInfo"; } /* static */ void GameInfo::RegisterAPI(Squirrel *engine) { /* Create the GSInfo class, and add the RegisterGS function */ DefSQClass SQGSInfo("GSInfo"); SQGSInfo.PreRegister(engine); SQGSInfo.AddConstructor(engine, "x"); SQGSInfo.DefSQAdvancedMethod(engine, &GameInfo::AddSetting, "AddSetting"); SQGSInfo.DefSQAdvancedMethod(engine, &GameInfo::AddLabels, "AddLabels"); SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_NONE, "CONFIG_NONE"); SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_RANDOM, "CONFIG_RANDOM"); SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_BOOLEAN, "CONFIG_BOOLEAN"); SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_INGAME, "CONFIG_INGAME"); SQGSInfo.DefSQConst(engine, SCRIPTCONFIG_DEVELOPER, "CONFIG_DEVELOPER"); SQGSInfo.PostRegister(engine); engine->AddMethod("RegisterGS", &GameInfo::Constructor, 2, "tx"); } /* static */ SQInteger GameInfo::Constructor(HSQUIRRELVM vm) { /* Get the GameInfo */ SQUserPointer instance = NULL; if (SQ_FAILED(sq_getinstanceup(vm, 2, &instance, 0)) || instance == NULL) return sq_throwerror(vm, "Pass an instance of a child class of GameInfo to RegisterGame"); GameInfo *info = (GameInfo *)instance; SQInteger res = ScriptInfo::Constructor(vm, info); if (res != 0) return res; if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) { if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; } else { info->min_loadable_version = info->GetVersion(); } /* When there is an IsSelectable function, call it. */ if (info->engine->MethodExists(*info->SQ_instance, "IsDeveloperOnly")) { if (!info->engine->CallBoolMethod(*info->SQ_instance, "IsDeveloperOnly", &info->is_developer_only, MAX_GET_OPS)) return SQ_ERROR; } else { info->is_developer_only = false; } /* Try to get the API version the AI is written for. */ if (!info->CheckMethod("GetAPIVersion")) return SQ_ERROR; if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAPIVersion", &info->api_version, MAX_GET_OPS)) return SQ_ERROR; if (!CheckAPIVersion(info->api_version)) { DEBUG(script, 1, "Loading info.nut from (%s.%d): GetAPIVersion returned invalid version", info->GetName(), info->GetVersion()); return SQ_ERROR; } /* Remove the link to the real instance, else it might get deleted by RegisterGame() */ sq_setinstanceup(vm, 2, NULL); /* Register the Game to the base system */ info->GetScanner()->RegisterScript(info); return 0; } GameInfo::GameInfo() : min_loadable_version(0), is_developer_only(false), api_version(NULL) { } GameInfo::~GameInfo() { free(this->api_version); } bool GameInfo::CanLoadFromVersion(int version) const { if (version == -1) return true; return version >= this->min_loadable_version && version <= this->GetVersion(); } GameLibrary::~GameLibrary() { free(this->category); } /* static */ void GameLibrary::RegisterAPI(Squirrel *engine) { /* Create the GameLibrary class, and add the RegisterLibrary function */ engine->AddClassBegin("GSLibrary"); engine->AddClassEnd(); engine->AddMethod("RegisterLibrary", &GameLibrary::Constructor, 2, "tx"); } /* static */ SQInteger GameLibrary::Constructor(HSQUIRRELVM vm) { /* Create a new library */ GameLibrary *library = new GameLibrary(); SQInteger res = ScriptInfo::Constructor(vm, library); if (res != 0) { delete library; return res; } /* Cache the category */ if (!library->CheckMethod("GetCategory") || !library->engine->CallStringMethodStrdup(*library->SQ_instance, "GetCategory", &library->category, MAX_GET_OPS)) { delete library; return SQ_ERROR; } /* Register the Library to the base system */ library->GetScanner()->RegisterScript(library); return 0; } openttd-1.5.3/src/game/game_text.hpp0000644000000000000000000000370512627373442016100 0ustar rootroot/* $Id: game_text.hpp 25818 2013-10-06 12:13:20Z frosch $ */ /* * 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 game_text.hpp Base functions regarding game texts. */ #ifndef GAME_TEXT_HPP #define GAME_TEXT_HPP #include "../core/smallvec_type.hpp" /** The tab we place our strings in. */ static const uint GAME_TEXT_TAB = 18; const char *GetGameStringPtr(uint id); void RegisterGameTranslation(class Squirrel *engine); void ReconsiderGameScriptLanguage(); /** Container for the raw (unencoded) language strings of a language. */ struct LanguageStrings { const char *language; ///< Name of the language (base filename). StringList lines; ///< The lines of the file to pass into the parser/encoder. LanguageStrings(const char *language, const char *end = NULL); ~LanguageStrings(); }; /** Container for all the game strings. */ struct GameStrings { uint version; ///< The version of the language strings. LanguageStrings *cur_language; ///< The current (compiled) language. AutoDeleteSmallVector raw_strings; ///< The raw strings per language, first must be English/the master language!. AutoDeleteSmallVector compiled_strings; ///< The compiled strings per language, first must be English/the master language!. StringList string_names; ///< The names of the compiled strings. void Compile(); }; #endif /* GAME_TEXT_HPP */ openttd-1.5.3/src/game/game_info.hpp0000644000000000000000000000451312627373442016045 0ustar rootroot/* $Id: game_info.hpp 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 game_info.hpp GameInfo keeps track of all information of an Game, like Author, Description, ... */ #ifndef GAME_INFO_HPP #define GAME_INFO_HPP #include "../script/script_info.hpp" /** All static information from an Game like name, version, etc. */ class GameInfo : public ScriptInfo { public: GameInfo(); ~GameInfo(); /** * Register the functions of this class. */ static void RegisterAPI(Squirrel *engine); /** * Create an Game, using this GameInfo as start-template. */ static SQInteger Constructor(HSQUIRRELVM vm); /** * Check if we can start this Game. */ bool CanLoadFromVersion(int version) const; /** * Get the API version this Game is written for. */ const char *GetAPIVersion() const { return this->api_version; } /* virtual */ bool IsDeveloperOnly() const { return this->is_developer_only; } private: int min_loadable_version; ///< The Game can load savegame data if the version is equal or greater than this. bool is_developer_only; ///< Is the script selectable by non-developers? const char *api_version; ///< API version used by this Game. }; /** All static information from an Game library like name, version, etc. */ class GameLibrary : public ScriptInfo { public: GameLibrary() : ScriptInfo(), category(NULL) {}; ~GameLibrary(); /** * Register the functions of this class. */ static void RegisterAPI(Squirrel *engine); /** * Create an GSLibrary, using this GSInfo as start-template. */ static SQInteger Constructor(HSQUIRRELVM vm); /** * Get the category this library is in. */ const char *GetCategory() const { return this->category; } private: const char *category; ///< The category this library is in. }; #endif /* GAME_INFO_HPP */ openttd-1.5.3/src/game/game_text.cpp0000644000000000000000000002430112627373442016066 0ustar rootroot/* $Id: game_text.cpp 26774 2014-09-06 17:46:56Z rubidium $ */ /* * 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 game_text.cpp Implementation of handling translated strings. */ #include "../stdafx.h" #include "../strgen/strgen.h" #include "../debug.h" #include "../fileio_func.h" #include "../tar_type.h" #include "../script/squirrel_class.hpp" #include "../strings_func.h" #include "game_text.hpp" #include "game.hpp" #include "game_info.hpp" #include "table/strings.h" #include #include "../safeguards.h" void CDECL strgen_warning(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); DEBUG(script, 0, "%s:%d: warning: %s", _file, _cur_line, buf); _warnings++; } void CDECL strgen_error(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); DEBUG(script, 0, "%s:%d: error: %s", _file, _cur_line, buf); _errors++; } void NORETURN CDECL strgen_fatal(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); DEBUG(script, 0, "%s:%d: FATAL: %s", _file, _cur_line, buf); throw std::exception(); } /** * Create a new container for language strings. * @param language The language name. * @param end If not NULL, terminate \a language at this position. */ LanguageStrings::LanguageStrings(const char *language, const char *end) { this->language = stredup(language, end != NULL ? end - 1 : NULL); } /** Free everything. */ LanguageStrings::~LanguageStrings() { free(this->language); } /** * Read all the raw language strings from the given file. * @param file The file to read from. * @return The raw strings, or NULL upon error. */ LanguageStrings *ReadRawLanguageStrings(const char *file) { LanguageStrings *ret = NULL; FILE *fh = NULL; try { size_t to_read; fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); if (fh == NULL) { return NULL; } const char *langname = strrchr(file, PATHSEPCHAR); if (langname == NULL) { langname = file; } else { langname++; } /* Check for invalid empty filename */ if (*langname == '.' || *langname == 0) { fclose(fh); return NULL; } ret = new LanguageStrings(langname, strchr(langname, '.')); char buffer[2048]; while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != NULL) { size_t len = strlen(buffer); /* Remove trailing spaces/newlines from the string. */ size_t i = len; while (i > 0 && (buffer[i - 1] == '\r' || buffer[i - 1] == '\n' || buffer[i - 1] == ' ')) i--; buffer[i] = '\0'; *ret->lines.Append() = stredup(buffer, buffer + to_read - 1); if (len > to_read) { to_read = 0; } else { to_read -= len; } } fclose(fh); return ret; } catch (...) { if (fh != NULL) fclose(fh); delete ret; return NULL; } } /** A reader that simply reads using fopen. */ struct StringListReader : StringReader { const char * const *p; ///< The current location of the iteration. const char * const *end; ///< The end of the iteration. /** * Create the reader. * @param data The data to fill during reading. * @param file The file we are reading. * @param master Are we reading the master file? * @param translation Are we reading a translation? */ StringListReader(StringData &data, const LanguageStrings *strings, bool master, bool translation) : StringReader(data, strings->language, master, translation), p(strings->lines.Begin()), end(strings->lines.End()) { } /* virtual */ char *ReadLine(char *buffer, const char *last) { if (this->p == this->end) return NULL; strecpy(buffer, *this->p, last); this->p++; return buffer; } }; /** Class for writing an encoded language. */ struct TranslationWriter : LanguageWriter { StringList *strings; ///< The encoded strings. /** * Writer for the encoded data. * @param strings The string table to add the strings to. */ TranslationWriter(StringList *strings) : strings(strings) { } void WriteHeader(const LanguagePackHeader *header) { /* We don't use the header. */ } void Finalise() { /* Nothing to do. */ } void WriteLength(uint length) { /* We don't write the length. */ } void Write(const byte *buffer, size_t length) { char *dest = MallocT(length + 1); memcpy(dest, buffer, length); dest[length] = '\0'; *this->strings->Append() = dest; } }; /** Class for writing the string IDs. */ struct StringNameWriter : HeaderWriter { StringList *strings; ///< The string names. /** * Writer for the string names. * @param strings The string table to add the strings to. */ StringNameWriter(StringList *strings) : strings(strings) { } void WriteStringID(const char *name, int stringid) { if (stringid == (int)this->strings->Length()) *this->strings->Append() = stredup(name); } void Finalise(const StringData &data) { /* Nothing to do. */ } }; /** * Scanner to find language files in a GameScript directory. */ class LanguageScanner : protected FileScanner { private: GameStrings *gs; char *exclude; public: /** Initialise */ LanguageScanner(GameStrings *gs, const char *exclude) : gs(gs), exclude(stredup(exclude)) {} ~LanguageScanner() { free(exclude); } /** * Scan. */ void Scan(const char *directory) { this->FileScanner::Scan(".txt", directory, false); } /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { if (strcmp(filename, exclude) == 0) return true; *gs->raw_strings.Append() = ReadRawLanguageStrings(filename); return true; } }; /** * Load all translations that we know of. * @return Container with all (compiled) translations. */ GameStrings *LoadTranslations() { const GameInfo *info = Game::GetInfo(); char filename[512]; strecpy(filename, info->GetMainScript(), lastof(filename)); char *e = strrchr(filename, PATHSEPCHAR); if (e == NULL) return NULL; e++; // Make 'e' point after the PATHSEPCHAR strecpy(e, "lang" PATHSEP "english.txt", lastof(filename)); if (!FioCheckFileExists(filename, GAME_DIR)) return NULL; GameStrings *gs = new GameStrings(); try { *gs->raw_strings.Append() = ReadRawLanguageStrings(filename); /* Scan for other language files */ LanguageScanner scanner(gs, filename); strecpy(e, "lang" PATHSEP, lastof(filename)); size_t len = strlen(filename); const char *tar_filename = info->GetTarFile(); TarList::iterator iter; if (tar_filename != NULL && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) { /* The main script is in a tar file, so find all files that * are in the same tar and add them to the langfile scanner. */ TarFileList::iterator tar; FOR_ALL_TARS(tar, GAME_DIR) { /* Not in the same tar. */ if (tar->second.tar_filename != iter->first) continue; /* Check the path and extension. */ if (tar->first.size() <= len || tar->first.compare(0, len, filename) != 0) continue; if (tar->first.compare(tar->first.size() - 4, 4, ".txt") != 0) continue; scanner.AddFile(tar->first.c_str(), 0, tar_filename); } } else { /* Scan filesystem */ scanner.Scan(filename); } gs->Compile(); return gs; } catch (...) { delete gs; return NULL; } } /** Compile the language. */ void GameStrings::Compile() { StringData data(1); StringListReader master_reader(data, this->raw_strings[0], true, false); master_reader.ParseFile(); if (_errors != 0) throw std::exception(); this->version = data.Version(); StringNameWriter id_writer(&this->string_names); id_writer.WriteHeader(data); for (LanguageStrings **p = this->raw_strings.Begin(); p != this->raw_strings.End(); p++) { data.FreeTranslation(); StringListReader translation_reader(data, *p, false, strcmp((*p)->language, "english") != 0); translation_reader.ParseFile(); if (_errors != 0) throw std::exception(); LanguageStrings *compiled = *this->compiled_strings.Append() = new LanguageStrings((*p)->language); TranslationWriter writer(&compiled->lines); writer.WriteLang(data); } } /** The currently loaded game strings. */ GameStrings *_current_data = NULL; /** * Get the string pointer of a particular game string. * @param id The ID of the game string. * @return The encoded string. */ const char *GetGameStringPtr(uint id) { if (id >= _current_data->cur_language->lines.Length()) return GetStringPtr(STR_UNDEFINED); return _current_data->cur_language->lines[id]; } /** * Register the current translation to the Squirrel engine. * @param engine The engine to update/ */ void RegisterGameTranslation(Squirrel *engine) { delete _current_data; _current_data = LoadTranslations(); if (_current_data == NULL) return; HSQUIRRELVM vm = engine->GetVM(); sq_pushroottable(vm); sq_pushstring(vm, "GSText", -1); if (SQ_FAILED(sq_get(vm, -2))) return; int idx = 0; for (const char * const *p = _current_data->string_names.Begin(); p != _current_data->string_names.End(); p++, idx++) { sq_pushstring(vm, *p, -1); sq_pushinteger(vm, idx); sq_rawset(vm, -3); } sq_pop(vm, 2); ReconsiderGameScriptLanguage(); } /** * Reconsider the game script language, so we use the right one. */ void ReconsiderGameScriptLanguage() { if (_current_data == NULL) return; char temp[MAX_PATH]; strecpy(temp, _current_language->file, lastof(temp)); /* Remove the extension */ char *l = strrchr(temp, '.'); assert(l != NULL); *l = '\0'; /* Skip the path */ char *language = strrchr(temp, PATHSEPCHAR); assert(language != NULL); language++; for (LanguageStrings **p = _current_data->compiled_strings.Begin(); p != _current_data->compiled_strings.End(); p++) { if (strcmp((*p)->language, language) == 0) { _current_data->cur_language = *p; return; } } _current_data->cur_language = _current_data->compiled_strings[0]; } openttd-1.5.3/src/game/game_instance.hpp0000644000000000000000000000266612627373442016725 0ustar rootroot/* $Id: game_instance.hpp 23737 2012-01-03 20:37:56Z truebrain $ */ /* * 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 game_instance.hpp The GameInstance tracks games. */ #ifndef GAME_INSTANCE_HPP #define GAME_INSTANCE_HPP #include "../script/script_instance.hpp" /** Runtime information about a game script like a pointer to the squirrel vm and the current state. */ class GameInstance : public ScriptInstance { public: GameInstance(); /** * Initialize the script and prepare it for its first run. * @param info The GameInfo to start. */ void Initialize(class GameInfo *info); /* virtual */ int GetSetting(const char *name); /* virtual */ ScriptInfo *FindLibrary(const char *library, int version); private: /* virtual */ void RegisterAPI(); /* virtual */ void Died(); /* virtual */ CommandCallback *GetDoCommandCallback(); /* virtual */ void LoadDummyScript() {} }; #endif /* GAME_INSTANCE_HPP */ openttd-1.5.3/src/road.cpp0000644000000000000000000001116212627373442014126 0ustar rootroot/* $Id: road.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 road.cpp Generic road related functions. */ #include "stdafx.h" #include "rail_map.h" #include "road_map.h" #include "water_map.h" #include "genworld.h" #include "company_func.h" #include "company_base.h" #include "engine_base.h" #include "date_func.h" #include "landscape.h" #include "safeguards.h" /** * Return if the tile is a valid tile for a crossing. * * @param tile the current tile * @param ax the axis of the road over the rail * @return true if it is a valid tile */ static bool IsPossibleCrossing(const TileIndex tile, Axis ax) { return (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == RAIL_TILE_NORMAL && GetTrackBits(tile) == (ax == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X) && GetFoundationSlope(tile) == SLOPE_FLAT); } /** * Clean up unnecessary RoadBits of a planed tile. * @param tile current tile * @param org_rb planed RoadBits * @return optimised RoadBits */ RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb) { if (!IsValidTile(tile)) return ROAD_NONE; for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { const TileIndex neighbor_tile = TileAddByDiagDir(tile, dir); /* Get the Roadbit pointing to the neighbor_tile */ const RoadBits target_rb = DiagDirToRoadBits(dir); /* If the roadbit is in the current plan */ if (org_rb & target_rb) { bool connective = false; const RoadBits mirrored_rb = MirrorRoadBits(target_rb); if (IsValidTile(neighbor_tile)) { switch (GetTileType(neighbor_tile)) { /* Always connective ones */ case MP_CLEAR: case MP_TREES: connective = true; break; /* The conditionally connective ones */ case MP_TUNNELBRIDGE: case MP_STATION: case MP_ROAD: if (IsNormalRoadTile(neighbor_tile)) { /* Always connective */ connective = true; } else { const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, ROADTYPE_ROAD) | GetAnyRoadBits(neighbor_tile, ROADTYPE_TRAM); /* Accept only connective tiles */ connective = (neighbor_rb & mirrored_rb) != ROAD_NONE; } break; case MP_RAILWAY: connective = IsPossibleCrossing(neighbor_tile, DiagDirToAxis(dir)); break; case MP_WATER: /* Check for real water tile */ connective = !IsWater(neighbor_tile); break; /* The definitely not connective ones */ default: break; } } /* If the neighbor tile is inconnective, remove the planed road connection to it */ if (!connective) org_rb ^= target_rb; } } return org_rb; } /** * Finds out, whether given company has all given RoadTypes available * @param company ID of company * @param rts RoadTypes to test * @return true if company has all requested RoadTypes available */ bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts) { RoadTypes avail_roadtypes; if (company == OWNER_DEITY || company == OWNER_TOWN || _game_mode == GM_EDITOR || _generating_world) { avail_roadtypes = ROADTYPES_ROAD; } else { Company *c = Company::GetIfValid(company); if (c == NULL) return false; avail_roadtypes = (RoadTypes)c->avail_roadtypes | ROADTYPES_ROAD; // road is available for always for everybody } return (rts & ~avail_roadtypes) == 0; } /** * Validate functions for rail building. * @param rt road type to check. * @return true if the current company may build the road. */ bool ValParamRoadType(const RoadType rt) { return HasRoadTypesAvail(_current_company, RoadTypeToRoadTypes(rt)); } /** * Get the road types the given company can build. * @param company the company to get the roadtypes for. * @return the road types. */ RoadTypes GetCompanyRoadtypes(CompanyID company) { RoadTypes rt = ROADTYPES_NONE; Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { const EngineInfo *ei = &e->info; if (HasBit(ei->climates, _settings_game.game_creation.landscape) && (HasBit(e->company_avail, company) || _date >= e->intro_date + DAYS_IN_YEAR)) { SetBit(rt, HasBit(ei->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); } } return rt; } openttd-1.5.3/src/waypoint_gui.cpp0000644000000000000000000001506612627373435015730 0ustar rootroot/* $Id: waypoint_gui.cpp 27030 2014-10-21 19:16:47Z rubidium $ */ /* * 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 waypoint_gui.cpp Handling of waypoints gui. */ #include "stdafx.h" #include "window_gui.h" #include "gui.h" #include "textbuf_gui.h" #include "vehiclelist.h" #include "vehicle_gui.h" #include "viewport_func.h" #include "strings_func.h" #include "command_func.h" #include "company_func.h" #include "company_base.h" #include "window_func.h" #include "waypoint_base.h" #include "widgets/waypoint_widget.h" #include "table/strings.h" #include "safeguards.h" /** GUI for accessing waypoints and buoys. */ struct WaypointWindow : Window { private: VehicleType vt; ///< Vehicle type using the waypoint. Waypoint *wp; ///< Waypoint displayed by the window. /** * Get the center tile of the waypoint. * @return The center tile if the waypoint exists, otherwise the tile with the waypoint name. */ TileIndex GetCenterTile() const { if (!this->wp->IsInUse()) return this->wp->xy; TileArea ta; this->wp->GetTileArea(&ta, this->vt == VEH_TRAIN ? STATION_WAYPOINT : STATION_BUOY); return ta.GetCenterTile(); } public: /** * Construct the window. * @param desc The description of the window. * @param window_number The window number, in this case the waypoint's ID. */ WaypointWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->wp = Waypoint::Get(window_number); this->vt = (wp->string_id == STR_SV_STNAME_WAYPOINT) ? VEH_TRAIN : VEH_SHIP; this->CreateNestedTree(); if (this->vt == VEH_TRAIN) { this->GetWidget(WID_W_SHOW_VEHICLES)->SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP); this->GetWidget(WID_W_CENTER_VIEW)->tool_tip = STR_WAYPOINT_VIEW_CENTER_TOOLTIP; this->GetWidget(WID_W_RENAME)->tool_tip = STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME; } this->FinishInitNested(window_number); this->owner = this->wp->owner; this->flags |= WF_DISABLE_VP_SCROLL; NWidgetViewport *nvp = this->GetWidget(WID_W_VIEWPORT); nvp->InitializeViewport(this, this->GetCenterTile(), ZOOM_LVL_VIEWPORT); this->OnInvalidateData(0); } ~WaypointWindow() { DeleteWindowById(GetWindowClassForVehicleType(this->vt), VehicleListIdentifier(VL_STATION_LIST, this->vt, this->owner, this->window_number).Pack(), false); } virtual void SetStringParameters(int widget) const { if (widget == WID_W_CAPTION) SetDParam(0, this->wp->index); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_W_CENTER_VIEW: // scroll to location if (_ctrl_pressed) { ShowExtraViewPortWindow(this->GetCenterTile()); } else { ScrollMainWindowToTile(this->GetCenterTile()); } break; case WID_W_RENAME: // rename SetDParam(0, this->wp->index); ShowQueryString(STR_WAYPOINT_NAME, STR_EDIT_WAYPOINT_NAME, MAX_LENGTH_STATION_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); break; case WID_W_SHOW_VEHICLES: // show list of vehicles having this waypoint in their orders ShowVehicleListWindow(this->wp->owner, this->vt, this->wp->index); 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; /* You can only change your own waypoints */ this->SetWidgetDisabledState(WID_W_RENAME, !this->wp->IsInUse() || (this->wp->owner != _local_company && this->wp->owner != OWNER_NONE)); /* Disable the widget for waypoints with no use */ this->SetWidgetDisabledState(WID_W_SHOW_VEHICLES, !this->wp->IsInUse()); ScrollWindowToTile(this->GetCenterTile(), this, true); } virtual void OnResize() { if (this->viewport != NULL) { NWidgetViewport *nvp = this->GetWidget(WID_W_VIEWPORT); nvp->UpdateViewportCoordinates(this); this->wp->UpdateVirtCoord(); ScrollWindowToTile(this->GetCenterTile(), this, true); // Re-center viewport. } } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; DoCommandP(0, this->window_number, 0, CMD_RENAME_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME), NULL, str); } }; /** The widgets of the waypoint view. */ static const NWidgetPart _nested_waypoint_view_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_W_CAPTION), SetDataTip(STR_WAYPOINT_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_INSET, COLOUR_GREY), SetPadding(2, 2, 2, 2), NWidget(NWID_VIEWPORT, COLOUR_GREY, WID_W_VIEWPORT), SetMinimalSize(256, 88), SetPadding(1, 1, 1, 1), SetResize(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_W_CENTER_VIEW), SetMinimalSize(100, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_BUOY_VIEW_CENTER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_W_RENAME), SetMinimalSize(100, 12), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_RENAME, STR_BUOY_VIEW_CHANGE_BUOY_NAME), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_W_SHOW_VEHICLES), SetMinimalSize(15, 12), SetDataTip(STR_SHIP, STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; /** The description of the waypoint view. */ static WindowDesc _waypoint_view_desc( WDP_AUTO, "view_waypoint", 260, 118, WC_WAYPOINT_VIEW, WC_NONE, 0, _nested_waypoint_view_widgets, lengthof(_nested_waypoint_view_widgets) ); /** * Show the window for the given waypoint. * @param wp The waypoint to show the window for. */ void ShowWaypointWindow(const Waypoint *wp) { AllocateWindowDescFront(&_waypoint_view_desc, wp->index); } openttd-1.5.3/src/newgrf_callbacks.h0000644000000000000000000004415112627373441016140 0ustar rootroot/* $Id: newgrf_callbacks.h 26747 2014-08-17 14:53:11Z frosch $ */ /* * 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 newgrf_callbacks.h Callbacks that NewGRFs could implement. */ #ifndef NEWGRF_CALLBACKS_H #define NEWGRF_CALLBACKS_H /** * List of implemented NewGRF callbacks. * Most of these callbacks are only triggered when the corresponding * bit is set in the callback flags/trigger for a vehicle, house, * industry, etc. * Names are formatted as CBID__ */ enum CallbackID { /** Set when using the callback resolve system, but not to resolve a callback. */ CBID_NO_CALLBACK = 0x00, /** Set when calling a randomizing trigger (almost undocumented). */ CBID_RANDOM_TRIGGER = 0x01, /* There are no callbacks 0x02 - 0x0F. */ /** Visual effects and wagon power. */ CBID_VEHICLE_VISUAL_EFFECT = 0x10, // 8 bit callback /** Vehicle length, returns the amount of 1/8's the vehicle is shorter for trains and RVs. */ CBID_VEHICLE_LENGTH = 0x11, /** Determine the amount of cargo to load per unit of time when using gradual loading. */ CBID_VEHICLE_LOAD_AMOUNT = 0x12, // 8 bit callback /** Determine whether a newstation should be made available to build. */ CBID_STATION_AVAILABILITY = 0x13, // 8 bit callback /** Choose a sprite layout to draw, instead of the standard 0-7 range. */ CBID_STATION_SPRITE_LAYOUT = 0x14, /** * Refit capacity, the passed vehicle needs to have its ->cargo_type set to * the cargo we are refitting to, returns the new cargo capacity. */ CBID_VEHICLE_REFIT_CAPACITY = 0x15, // 15 bit callback /** Builds articulated engines for trains and RVs. */ CBID_VEHICLE_ARTIC_ENGINE = 0x16, // 8 bit callback for grf version < 8 /** Determine whether the house can be built on the specified tile. */ CBID_HOUSE_ALLOW_CONSTRUCTION = 0x17, // 8 bit callback /** AI construction/purchase selection */ CBID_GENERIC_AI_PURCHASE_SELECTION = 0x18, // 8 bit callback, implemented for stations only /** Determine the cargo "suffixes" for each refit possibility of a cargo. */ CBID_VEHICLE_CARGO_SUFFIX = 0x19, /** Determine the next animation frame for a house. */ CBID_HOUSE_ANIMATION_NEXT_FRAME = 0x1A, // 15 bit callback /** Called for periodically starting or stopping the animation. */ CBID_HOUSE_ANIMATION_START_STOP = 0x1B, // 15 bit callback /** Called whenever the construction state of a house changes. */ CBID_HOUSE_CONSTRUCTION_STATE_CHANGE = 0x1C, // 15 bit callback /** Determine whether a wagon can be attached to an already existing train. */ CBID_TRAIN_ALLOW_WAGON_ATTACH = 0x1D, /** Called to determine the colour of a town building. */ CBID_HOUSE_COLOUR = 0x1E, // 15 bit callback /** Called to decide how much cargo a town building can accept. */ CBID_HOUSE_CARGO_ACCEPTANCE = 0x1F, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ CBID_HOUSE_ANIMATION_SPEED = 0x20, // 8 bit callback /** Called periodically to determine if a house should be destroyed. */ CBID_HOUSE_DESTRUCTION = 0x21, // 8 bit callback /** Called to determine if the given industry type is available. For grf version >= 8 also a probability can be returned. */ CBID_INDUSTRY_PROBABILITY = 0x22, // 15 bit callback /** * This callback is called from vehicle purchase lists. It returns a value to be * used as a custom string ID in the 0xD000 range. */ CBID_VEHICLE_ADDITIONAL_TEXT = 0x23, /** Called when building a station to customize the tile layout */ CBID_STATION_TILE_LAYOUT = 0x24, // 15 bit callback /** Called for periodically starting or stopping the animation. */ CBID_INDTILE_ANIM_START_STOP = 0x25, // 15 bit callback /** Called to determine industry tile next animation frame. */ CBID_INDTILE_ANIM_NEXT_FRAME = 0x26, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ CBID_INDTILE_ANIMATION_SPEED = 0x27, // 8 bit callback /** Called to determine if the given industry can be built on specific area. */ CBID_INDUSTRY_LOCATION = 0x28, // 15 bit callback /** Called on production changes, so it can be adjusted. */ CBID_INDUSTRY_PRODUCTION_CHANGE = 0x29, // 15 bit callback /** Called to determine which cargoes a town building should accept. */ CBID_HOUSE_ACCEPT_CARGO = 0x2A, // 15 bit callback /** Called to query the cargo acceptance of the industry tile */ CBID_INDTILE_CARGO_ACCEPTANCE = 0x2B, // 15 bit callback /** Called to determine which cargoes an industry should accept. */ CBID_INDTILE_ACCEPT_CARGO = 0x2C, // 15 bit callback /** * Called to determine if a specific colour map should be used for a vehicle * instead of the default livery. */ CBID_VEHICLE_COLOUR_MAPPING = 0x2D, // 15 bit callback /** Called to determine how much cargo a town building produces. */ CBID_HOUSE_PRODUCE_CARGO = 0x2E, // 15 bit callback /** Called to determine if the given industry tile can be built on specific tile. */ CBID_INDTILE_SHAPE_CHECK = 0x2F, // 15 bit callback /** Called to determine the type (if any) of foundation to draw for industry tile. */ CBID_INDTILE_DRAW_FOUNDATIONS = 0x30, // 15 bit callback /** * Called when the company (or AI) tries to start or stop a vehicle. Mainly * used for preventing a vehicle from leaving the depot. */ CBID_VEHICLE_START_STOP_CHECK = 0x31, // 15 bit callback, but 0xFF test is done with 8 bit /** Called for every vehicle every 32 days (not all on same date though). */ CBID_VEHICLE_32DAY_CALLBACK = 0x32, // 2 bit callback /** Called to play a special sound effect */ CBID_VEHICLE_SOUND_EFFECT = 0x33, // 15 bit callback /** Return the vehicles this given vehicle can be "upgraded" to. */ CBID_VEHICLE_AUTOREPLACE_SELECTION = 0x34, // 15 bit callback, not implemented /** Called monthly on production changes, so it can be adjusted more frequently */ CBID_INDUSTRY_MONTHLYPROD_CHANGE = 0x35, // 15 bit callback /** * Called to modify various vehicle properties. Callback parameter 1 * specifies the property index, as used in Action 0, to change. */ CBID_VEHICLE_MODIFY_PROPERTY = 0x36, // 8/15 bit depends on queried property /** Called to determine text to display after cargo name */ CBID_INDUSTRY_CARGO_SUFFIX = 0x37, // 15 bit callback, but 0xFF test is done with 8 bit /** Called to determine more text in the fund industry window */ CBID_INDUSTRY_FUND_MORE_TEXT = 0x38, // 15 bit callback /** Called to calculate the income of delivered cargo */ CBID_CARGO_PROFIT_CALC = 0x39, // 15 bit callback /** Called to determine more text in the industry window */ CBID_INDUSTRY_WINDOW_MORE_TEXT = 0x3A, // 15 bit callback /** Called to determine industry special effects */ CBID_INDUSTRY_SPECIAL_EFFECT = 0x3B, // 15 bit callback /** Called to determine if industry can alter the ground below industry tile */ CBID_INDTILE_AUTOSLOPE = 0x3C, // 15 bit callback /** Called to determine if the industry can still accept or refuse more cargo arrival */ CBID_INDUSTRY_REFUSE_CARGO = 0x3D, // 15 bit callback /* There are no callbacks 0x3E - 0x13F */ /** Called for periodically starting or stopping the animation. */ CBID_STATION_ANIM_START_STOP = 0x140, // 15 bit callback /** Called to determine station tile next animation frame. */ CBID_STATION_ANIM_NEXT_FRAME = 0x141, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ CBID_STATION_ANIMATION_SPEED = 0x142, // 8 bit callback /** Called to determine whether a town building can be destroyed. */ CBID_HOUSE_DENY_DESTRUCTION = 0x143, // 15 bit callback /** Select an ambient sound to play for a given type of tile. */ CBID_SOUNDS_AMBIENT_EFFECT = 0x144, // 15 bit callback /** Called to calculate part of a station rating. */ CBID_CARGO_STATION_RATING_CALC = 0x145, // 15 bit callback /** Allow signal sprites to be replaced dynamically. */ CBID_NEW_SIGNALS_SPRITE_DRAW = 0x146, // 15 bit callback, not implemented /** Add an offset to the default sprite numbers to show another sprite. */ CBID_CANALS_SPRITE_OFFSET = 0x147, // 15 bit callback /** Called when a cargo type specified in property 20 is accepted. */ CBID_HOUSE_WATCHED_CARGO_ACCEPTED = 0x148, // 15 bit callback /** Callback done for each tile of a station to check the slope. */ CBID_STATION_LAND_SLOPE_CHECK = 0x149, // 15 bit callback /** Called to determine the colour of an industry. */ CBID_INDUSTRY_DECIDE_COLOUR = 0x14A, // 4 bit callback /** Customize the input cargo types of a newly build industry. */ CBID_INDUSTRY_INPUT_CARGO_TYPES = 0x14B, // 8 bit callback /** Customize the output cargo types of a newly build industry. */ CBID_INDUSTRY_OUTPUT_CARGO_TYPES = 0x14C, // 8 bit callback /** Called on the Get Tile Description for an house tile. */ CBID_HOUSE_CUSTOM_NAME = 0x14D, // 15 bit callback /** Called to determine the type (if any) of foundation to draw for house tile. */ CBID_HOUSE_DRAW_FOUNDATIONS = 0x14E, // 15 bit callback /** Called to determine if one can alter the ground below a house tile */ CBID_HOUSE_AUTOSLOPE = 0x14F, // 15 bit callback /** Called to determine the type (if any) of foundation to draw for an airport tile. */ CBID_AIRPTILE_DRAW_FOUNDATIONS = 0x150, // 15 bit callback /** Called for periodically starting or stopping the animation. */ CBID_AIRPTILE_ANIM_START_STOP = 0x152, // 15 bit callback /** Called to determine airport tile next animation frame. */ CBID_AIRPTILE_ANIM_NEXT_FRAME = 0x153, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ CBID_AIRPTILE_ANIMATION_SPEED = 0x154, // 8 bit callback /** * This callback is called from airport list. It returns a value to be * used as a custom string ID in the 0xD000 range. */ CBID_AIRPORT_ADDITIONAL_TEXT = 0x155, // 15 bit callback /** Called to determine text to show as airport layout name. */ CBID_AIRPORT_LAYOUT_NAME = 0x156, // 15 bit callback /** Callback done for each tile of an object to check the slope. */ CBID_OBJECT_LAND_SLOPE_CHECK = 0x157, // 15 bit callback /** Determine the next animation frame for a house. */ CBID_OBJECT_ANIMATION_NEXT_FRAME = 0x158, // 15 bit callback /** Called for periodically starting or stopping the animation. */ CBID_OBJECT_ANIMATION_START_STOP = 0x159, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ CBID_OBJECT_ANIMATION_SPEED = 0x15A, // 8 bit callback /** Called to determine the colour of a town building. */ CBID_OBJECT_COLOUR = 0x15B, // 15 bit callback /** Called to determine more text in the fund object window */ CBID_OBJECT_FUND_MORE_TEXT = 0x15C, // 15 bit callback /** Called to determine if one can alter the ground below an object tile */ CBID_OBJECT_AUTOSLOPE = 0x15D, // 15 bit callback /** Called to determine the cost factor for refitting a vehicle. */ CBID_VEHICLE_REFIT_COST = 0x15E, // 15 bit callback /** Called when industry is built to set initial production level. */ CBID_INDUSTRY_PROD_CHANGE_BUILD = 0x15F, // 15 bit callback /** Called to spawn visual effects for vehicles. */ CBID_VEHICLE_SPAWN_VISUAL_EFFECT = 0x160, // 15 bit callback }; /** * Callback masks for vehicles, indicates which callbacks are used by a vehicle. * Some callbacks are always used and don't have a mask. */ enum VehicleCallbackMask { CBM_VEHICLE_VISUAL_EFFECT = 0, ///< Visual effects and wagon power (trains, road vehicles and ships) CBM_VEHICLE_LENGTH = 1, ///< Vehicle length (trains and road vehicles) CBM_VEHICLE_LOAD_AMOUNT = 2, ///< Load amount CBM_VEHICLE_REFIT_CAPACITY = 3, ///< Cargo capacity after refit CBM_VEHICLE_ARTIC_ENGINE = 4, ///< Add articulated engines (trains and road vehicles) CBM_VEHICLE_CARGO_SUFFIX = 5, ///< Show suffix after cargo name CBM_VEHICLE_COLOUR_REMAP = 6, ///< Change colour mapping of vehicle CBM_VEHICLE_SOUND_EFFECT = 7, ///< Vehicle uses custom sound effects }; /** * Callback masks for stations. */ enum StationCallbackMask { CBM_STATION_AVAIL = 0, ///< Availability of station in construction window CBM_STATION_SPRITE_LAYOUT = 1, ///< Use callback to select a sprite layout to use CBM_STATION_ANIMATION_NEXT_FRAME = 2, ///< Use a custom next frame callback CBM_STATION_ANIMATION_SPEED = 3, ///< Customize the animation speed of the station CBM_STATION_SLOPE_CHECK = 4, ///< Check slope of new station tiles }; /** * Callback masks for houses. */ enum HouseCallbackMask { CBM_HOUSE_ALLOW_CONSTRUCTION = 0, ///< decide whether the house can be built on a given tile CBM_HOUSE_ANIMATION_NEXT_FRAME = 1, ///< decides next animation frame CBM_HOUSE_ANIMATION_START_STOP = 2, ///< periodically start/stop the animation CBM_HOUSE_CONSTRUCTION_STATE_CHANGE = 3, ///< change animation when construction state changes CBM_HOUSE_COLOUR = 4, ///< decide the colour of the building CBM_HOUSE_CARGO_ACCEPTANCE = 5, ///< decides amount of cargo acceptance CBM_HOUSE_ANIMATION_SPEED = 6, ///< decides animation speed CBM_HOUSE_DESTRUCTION = 7, ///< trigger destruction of building CBM_HOUSE_ACCEPT_CARGO = 8, ///< decides accepted types CBM_HOUSE_PRODUCE_CARGO = 9, ///< custom cargo production CBM_HOUSE_DENY_DESTRUCTION = 10, ///< conditional protection CBM_HOUSE_DRAW_FOUNDATIONS = 11, ///< decides if default foundations need to be drawn CBM_HOUSE_AUTOSLOPE = 12, ///< decides allowance of autosloping }; /** * Callback masks for canals. */ enum CanalCallbackMask { CBM_CANAL_SPRITE_OFFSET = 0, ///< Enable add sprite offset callback }; /** * Callback masks for cargoes. */ enum CargoCallbackMask { CBM_CARGO_PROFIT_CALC = 0, ///< custom profit calculation CBM_CARGO_STATION_RATING_CALC = 1, ///< custom station rating for this cargo type }; /** * Callback masks for Industries */ enum IndustryCallbackMask { CBM_IND_PROBABILITY = 0, ///< industry availability/probability callback CBM_IND_PRODUCTION_CARGO_ARRIVAL = 1, ///< call production callback when cargo arrives at the industry CBM_IND_PRODUCTION_256_TICKS = 2, ///< call production callback every 256 ticks CBM_IND_LOCATION = 3, ///< check industry construction on given area CBM_IND_PRODUCTION_CHANGE = 4, ///< controls random production change CBM_IND_MONTHLYPROD_CHANGE = 5, ///< controls monthly random production change CBM_IND_CARGO_SUFFIX = 6, ///< cargo sub-type display CBM_IND_FUND_MORE_TEXT = 7, ///< additional text in fund window CBM_IND_WINDOW_MORE_TEXT = 8, ///< additional text in industry window CBM_IND_SPECIAL_EFFECT = 9, ///< control special effects CBM_IND_REFUSE_CARGO = 10, ///< option out of accepting cargo CBM_IND_DECIDE_COLOUR = 11, ///< give a custom colour to newly build industries CBM_IND_INPUT_CARGO_TYPES = 12, ///< customize the cargoes the industry requires CBM_IND_OUTPUT_CARGO_TYPES = 13, ///< customize the cargoes the industry produces CBM_IND_PROD_CHANGE_BUILD = 14, ///< initialise production level on construction }; /** * Callback masks for industry tiles */ enum IndustryTileCallbackMask { CBM_INDT_ANIM_NEXT_FRAME = 0, ///< decides next animation frame CBM_INDT_ANIM_SPEED = 1, ///< decides animation speed CBM_INDT_CARGO_ACCEPTANCE = 2, ///< decides amount of cargo acceptance CBM_INDT_ACCEPT_CARGO = 3, ///< decides accepted types CBM_INDT_SHAPE_CHECK = 4, ///< decides slope suitability CBM_INDT_DRAW_FOUNDATIONS = 5, ///< decides if default foundations need to be drawn CBM_INDT_AUTOSLOPE = 6, ///< decides allowance of autosloping }; /** * Callback masks for objects */ enum ObjectCallbackMask { CBM_OBJ_SLOPE_CHECK = 0, ///< decides slope suitability CBM_OBJ_ANIMATION_NEXT_FRAME = 1, ///< decides next animation frame CBM_OBJ_ANIMATION_SPEED = 2, ///< decides animation speed CBM_OBJ_COLOUR = 3, ///< decide the colour of the building CBM_OBJ_FUND_MORE_TEXT = 4, ///< additional text in fund window CBM_OBJ_AUTOSLOPE = 5, ///< decides allowance of autosloping }; /** * Callback masks for airport tiles */ enum AirportTileCallbackMask { CBM_AIRT_ANIM_NEXT_FRAME = 0, ///< decides next animation frame CBM_AIRT_ANIM_SPEED = 1, ///< decides animation speed CBM_AIRT_SHAPE_CHECK = 4, ///< decides slope suitability CBM_AIRT_DRAW_FOUNDATIONS = 5, ///< decides if default foundations need to be drawn CBM_AIRT_AUTOSLOPE = 6, ///< decides allowance of autosloping }; /** * Different values for Callback result evaluations */ static const uint CALLBACK_FAILED = 0xFFFF; ///< Result of a failed callback. static const uint CALLBACK_HOUSEPRODCARGO_END = 0x20FF; ///< Sentinel indicating that the loop for CBID_HOUSE_PRODUCE_CARGO has ended #endif /* NEWGRF_CALLBACKS_H */ openttd-1.5.3/src/stringfilter.cpp0000644000000000000000000000706612627373446015731 0ustar rootroot/* $Id: stringfilter.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 stringfilter.cpp Searching and filtering using a stringterm. */ #include "stdafx.h" #include "string_func.h" #include "strings_func.h" #include "stringfilter_type.h" #include "gfx_func.h" #include "safeguards.h" static const WChar STATE_WHITESPACE = ' '; static const WChar STATE_WORD = 'w'; static const WChar STATE_QUOTE1 = '\''; static const WChar STATE_QUOTE2 = '"'; /** * Set the term to filter on. * @param str Filter term */ void StringFilter::SetFilterTerm(const char *str) { this->word_index.Reset(); this->word_matches = 0; free(this->filter_buffer); assert(str != NULL); char *dest = MallocT(strlen(str) + 1); this->filter_buffer = dest; WChar state = STATE_WHITESPACE; const char *pos = str; WordState *word = NULL; size_t len; for (;; pos += len) { WChar c; len = Utf8Decode(&c, pos); if (c == 0 || (state == STATE_WORD && IsWhitespace(c))) { /* Finish word */ if (word != NULL) { *(dest++) = '\0'; word = NULL; } state = STATE_WHITESPACE; if (c != 0) continue; else break; } if (state == STATE_WHITESPACE) { /* Skip whitespace */ if (IsWhitespace(c)) continue; state = STATE_WORD; } if (c == STATE_QUOTE1 || c == STATE_QUOTE2) { if (state == c) { /* Stop quoting */ state = STATE_WORD; continue; } else if (state == STATE_WORD) { /* Start quoting */ state = c; continue; } } /* Add to word */ if (word == NULL) { word = this->word_index.Append(); word->start = dest; word->match = false; } memcpy(dest, pos, len); dest += len; } } /** * Reset the matching state to process a new item. */ void StringFilter::ResetState() { this->word_matches = 0; const WordState *end = this->word_index.End(); for (WordState *it = this->word_index.Begin(); it != end; ++it) { it->match = false; } } /** * Pass another text line from the current item to the filter. * * You can call this multiple times for a single item, if the filter shall apply to multiple things. * Before processing the next item you have to call ResetState(). * * @param str Another line from the item. */ void StringFilter::AddLine(const char *str) { if (str == NULL) return; bool match_case = this->case_sensitive != NULL && *this->case_sensitive; const WordState *end = this->word_index.End(); for (WordState *it = this->word_index.Begin(); it != end; ++it) { if (!it->match) { if ((match_case ? strstr(str, it->start) : strcasestr(str, it->start)) != NULL) { it->match = true; this->word_matches++; } } } } /** * Pass another text line from the current item to the filter. * * You can call this multiple times for a single item, if the filter shall apply to multiple things. * Before processing the next item you have to call ResetState(). * * @param str Another line from the item. */ void StringFilter::AddLine(StringID str) { char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); AddLine(buffer); } openttd-1.5.3/src/ini.cpp0000644000000000000000000001063312627373435013764 0ustar rootroot/* $Id: ini.cpp 27430 2015-11-01 11:55:45Z frosch $ */ /* * 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 ini.cpp Definition of the IniItem class, related to reading/writing '*.ini' files. */ #include "stdafx.h" #include "debug.h" #include "ini_type.h" #include "string_func.h" #include "fileio_func.h" #if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L) || (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 500) # include #endif #ifdef WIN32 # include # include # include "core/mem_func.hpp" #endif #include "safeguards.h" /** * Create a new ini file with given group names. * @param list_group_names A \c NULL terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST */ IniFile::IniFile(const char * const *list_group_names) : IniLoadFile(list_group_names) { } /** * Save the Ini file's data to the disk. * @param filename the file to save to. * @return true if saving succeeded. */ bool IniFile::SaveToDisk(const char *filename) { /* * First write the configuration to a (temporary) file and then rename * that file. This to prevent that when OpenTTD crashes during the save * you end up with a truncated configuration file. */ char file_new[MAX_PATH]; strecpy(file_new, filename, lastof(file_new)); strecat(file_new, ".new", lastof(file_new)); FILE *f = fopen(file_new, "w"); if (f == NULL) return false; for (const IniGroup *group = this->group; group != NULL; group = group->next) { if (group->comment) fputs(group->comment, f); fprintf(f, "[%s]\n", group->name); for (const IniItem *item = group->item; item != NULL; item = item->next) { if (item->comment != NULL) fputs(item->comment, f); /* protect item->name with quotes if needed */ if (strchr(item->name, ' ') != NULL || item->name[0] == '[') { fprintf(f, "\"%s\"", item->name); } else { fprintf(f, "%s", item->name); } fprintf(f, " = %s\n", item->value == NULL ? "" : item->value); } } if (this->comment) fputs(this->comment, f); /* * POSIX (and friends) do not guarantee that when a file is closed it is * flushed to the disk. So we manually flush it do disk if we have the * APIs to do so. We only need to flush the data as the metadata itself * (modification date etc.) is not important to us; only the real data is. */ #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 int ret = fdatasync(fileno(f)); fclose(f); if (ret != 0) return false; #else fclose(f); #endif #if defined(WIN32) || defined(WIN64) /* _tcsncpy = strcpy is TCHAR is char, but isn't when TCHAR is wchar. */ #undef strncpy /* Allocate space for one more \0 character. */ TCHAR tfilename[MAX_PATH + 1], tfile_new[MAX_PATH + 1]; _tcsncpy(tfilename, OTTD2FS(filename), MAX_PATH); _tcsncpy(tfile_new, OTTD2FS(file_new), MAX_PATH); /* SHFileOperation wants a double '\0' terminated string. */ tfilename[MAX_PATH - 1] = '\0'; tfile_new[MAX_PATH - 1] = '\0'; tfilename[_tcslen(tfilename) + 1] = '\0'; tfile_new[_tcslen(tfile_new) + 1] = '\0'; /* Rename file without any user confirmation. */ SHFILEOPSTRUCT shfopt; MemSetT(&shfopt, 0); shfopt.wFunc = FO_MOVE; shfopt.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI | FOF_SILENT; shfopt.pFrom = tfile_new; shfopt.pTo = tfilename; SHFileOperation(&shfopt); #else if (rename(file_new, filename) < 0) { DEBUG(misc, 0, "Renaming %s to %s failed; configuration not saved", file_new, filename); } #endif return true; } /* virtual */ FILE *IniFile::OpenFile(const char *filename, Subdirectory subdir, size_t *size) { /* Open the text file in binary mode to prevent end-of-line translations * done by ftell() and friends, as defined by K&R. */ return FioFOpenFile(filename, "rb", subdir, size); } /* virtual */ void IniFile::ReportFileError(const char * const pre, const char * const buffer, const char * const post) { ShowInfoF("%s%s%s", pre, buffer, post); } openttd-1.5.3/src/rev.h0000644000000000000000000000167512627373435013454 0ustar rootroot/* $Id: rev.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 rev.h declaration of OTTD revision dependent variables */ #ifndef REV_H #define REV_H extern const char _openttd_revision[]; extern const char _openttd_build_date[]; extern const byte _openttd_revision_modified; extern const uint32 _openttd_newgrf_version; bool IsReleasedVersion(); #endif /* REV_H */ openttd-1.5.3/src/station_base.h0000644000000000000000000004252612627373435015333 0ustar rootroot/* $Id: station_base.h 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 station_base.h Base classes/functions for stations. */ #ifndef STATION_BASE_H #define STATION_BASE_H #include "core/random_func.hpp" #include "base_station_base.h" #include "newgrf_airport.h" #include "cargopacket.h" #include "industry_type.h" #include "linkgraph/linkgraph_type.h" #include "newgrf_storage.h" #include typedef Pool StationPool; extern StationPool _station_pool; static const byte INITIAL_STATION_RATING = 175; /** * Flow statistics telling how much flow should be sent along a link. This is * done by creating "flow shares" and using std::map's upper_bound() method to * look them up with a random number. A flow share is the difference between a * key in a map and the previous key. So one key in the map doesn't actually * mean anything by itself. */ class FlowStat { public: typedef std::map SharesMap; static const SharesMap empty_sharesmap; /** * Invalid constructor. This can't be called as a FlowStat must not be * empty. However, the constructor must be defined and reachable for * FlwoStat to be used in a std::map. */ inline FlowStat() {NOT_REACHED();} /** * Create a FlowStat with an initial entry. * @param st Station the initial entry refers to. * @param flow Amount of flow for the initial entry. * @param restricted If the flow to be added is restricted. */ inline FlowStat(StationID st, uint flow, bool restricted = false) { assert(flow > 0); this->shares[flow] = st; this->unrestricted = restricted ? 0 : flow; } /** * Add some flow to the end of the shares map. Only do that if you know * that the station isn't in the map yet. Anything else may lead to * inconsistencies. * @param st Remote station. * @param flow Amount of flow to be added. * @param restricted If the flow to be added is restricted. */ inline void AppendShare(StationID st, uint flow, bool restricted = false) { assert(flow > 0); this->shares[(--this->shares.end())->first + flow] = st; if (!restricted) this->unrestricted += flow; } uint GetShare(StationID st) const; void ChangeShare(StationID st, int flow); void RestrictShare(StationID st); void ReleaseShare(StationID st); void ScaleToMonthly(uint runtime); /** * Get the actual shares as a const pointer so that they can be iterated * over. * @return Actual shares. */ inline const SharesMap *GetShares() const { return &this->shares; } /** * Return total amount of unrestricted shares. * @return Amount of unrestricted shares. */ inline uint GetUnrestricted() const { return this->unrestricted; } /** * Swap the shares maps, and thus the content of this FlowStat with the * other one. * @param other FlowStat to swap with. */ inline void SwapShares(FlowStat &other) { this->shares.swap(other.shares); Swap(this->unrestricted, other.unrestricted); } /** * Get a station a package can be routed to. This done by drawing a * random number between 0 and sum_shares and then looking that up in * the map with lower_bound. So each share gets selected with a * probability dependent on its flow. Do include restricted flows here. * @param is_restricted Output if a restricted flow was chosen. * @return A station ID from the shares map. */ inline StationID GetViaWithRestricted(bool &is_restricted) const { assert(!this->shares.empty()); uint rand = RandomRange((--this->shares.end())->first); is_restricted = rand >= this->unrestricted; return this->shares.upper_bound(rand)->second; } /** * Get a station a package can be routed to. This done by drawing a * random number between 0 and sum_shares and then looking that up in * the map with lower_bound. So each share gets selected with a * probability dependent on its flow. Don't include restricted flows. * @return A station ID from the shares map. */ inline StationID GetVia() const { assert(!this->shares.empty()); return this->unrestricted > 0 ? this->shares.upper_bound(RandomRange(this->unrestricted))->second : INVALID_STATION; } StationID GetVia(StationID excluded, StationID excluded2 = INVALID_STATION) const; void Invalidate(); private: SharesMap shares; ///< Shares of flow to be sent via specified station (or consumed locally). uint unrestricted; ///< Limit for unrestricted shares. }; /** Flow descriptions by origin stations. */ class FlowStatMap : public std::map { public: uint GetFlow() const; uint GetFlowVia(StationID via) const; uint GetFlowFrom(StationID from) const; uint GetFlowFromVia(StationID from, StationID via) const; void AddFlow(StationID origin, StationID via, uint amount); void PassOnFlow(StationID origin, StationID via, uint amount); StationIDStack DeleteFlows(StationID via); void RestrictFlows(StationID via); void ReleaseFlows(StationID via); void FinalizeLocalConsumption(StationID self); }; /** * Stores station stats for a single cargo. */ struct GoodsEntry { /** Status of this cargo for the station. */ enum GoodsEntryStatus { /** * Set when the station accepts the cargo currently for final deliveries. * It is updated every STATION_ACCEPTANCE_TICKS ticks by checking surrounding tiles for acceptance >= 8/8. */ GES_ACCEPTANCE, /** * This indicates whether a cargo has a rating at the station. * Set when cargo was ever waiting at the station. * It is set when cargo supplied by surrounding tiles is moved to the station, or when * arriving vehicles unload/transfer cargo without it being a final delivery. * * This flag is cleared after 255 * STATION_RATING_TICKS of not having seen a pickup. */ GES_RATING, /** * Set when a vehicle ever delivered cargo to the station for final delivery. * This flag is never cleared. */ GES_EVER_ACCEPTED, /** * Set when cargo was delivered for final delivery last month. * This flag is set to the value of GES_CURRENT_MONTH at the start of each month. */ GES_LAST_MONTH, /** * Set when cargo was delivered for final delivery this month. * This flag is reset on the beginning of every month. */ GES_CURRENT_MONTH, /** * Set when cargo was delivered for final delivery during the current STATION_ACCEPTANCE_TICKS interval. * This flag is reset every STATION_ACCEPTANCE_TICKS ticks. */ GES_ACCEPTED_BIGTICK, }; GoodsEntry() : status(0), time_since_pickup(255), rating(INITIAL_STATION_RATING), last_speed(0), last_age(255), amount_fract(0), link_graph(INVALID_LINK_GRAPH), node(INVALID_NODE), max_waiting_cargo(0) {} byte status; ///< Status of this cargo, see #GoodsEntryStatus. /** * Number of rating-intervals (up to 255) since the last vehicle tried to load this cargo. * The unit used is STATION_RATING_TICKS. * This does not imply there was any cargo to load. */ byte time_since_pickup; byte rating; ///< %Station rating for this cargo. /** * Maximum speed (up to 255) of the last vehicle that tried to load this cargo. * This does not imply there was any cargo to load. * The unit used is a special vehicle-specific speed unit for station ratings. * - Trains: km-ish/h * - RV: km-ish/h * - Ships: 0.5 * km-ish/h * - Aircraft: 8 * mph */ byte last_speed; /** * Age in years (up to 255) of the last vehicle that tried to load this cargo. * This does not imply there was any cargo to load. */ byte last_age; byte amount_fract; ///< Fractional part of the amount in the cargo list StationCargoList cargo; ///< The cargo packets of cargo waiting in this station LinkGraphID link_graph; ///< Link graph this station belongs to. NodeID node; ///< ID of node in link graph referring to this goods entry. FlowStatMap flows; ///< Planned flows through this station. uint max_waiting_cargo; ///< Max cargo from this station waiting at any station. /** * Reports whether a vehicle has ever tried to load the cargo at this station. * This does not imply that there was cargo available for loading. Refer to GES_RATING for that. * @return true if vehicle tried to load. */ bool HasVehicleEverTriedLoading() const { return this->last_speed != 0; } /** * Does this cargo have a rating at this station? * @return true if the cargo has a rating, i.e. cargo has been moved to the station. */ inline bool HasRating() const { return HasBit(this->status, GES_RATING); } /** * Get the best next hop for a cargo packet from station source. * @param source Source of the packet. * @return The chosen next hop or INVALID_STATION if none was found. */ inline StationID GetVia(StationID source) const { FlowStatMap::const_iterator flow_it(this->flows.find(source)); return flow_it != this->flows.end() ? flow_it->second.GetVia() : INVALID_STATION; } /** * Get the best next hop for a cargo packet from station source, optionally * excluding one or two stations. * @param source Source of the packet. * @param excluded If this station would be chosen choose the second best one instead. * @param excluded2 Second station to be excluded, if != INVALID_STATION. * @return The chosen next hop or INVALID_STATION if none was found. */ inline StationID GetVia(StationID source, StationID excluded, StationID excluded2 = INVALID_STATION) const { FlowStatMap::const_iterator flow_it(this->flows.find(source)); return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded, excluded2) : INVALID_STATION; } }; /** All airport-related information. Only valid if tile != INVALID_TILE. */ struct Airport : public TileArea { Airport() : TileArea(INVALID_TILE, 0, 0) {} uint64 flags; ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32 byte type; ///< Type of this airport, @see AirportTypes byte layout; ///< Airport layout number. DirectionByte rotation; ///< How this airport is rotated. PersistentStorage *psa; ///< Persistent storage for NewGRF airports. /** * Get the AirportSpec that from the airport type of this airport. If there * is no airport (\c tile == INVALID_TILE) then return the dummy AirportSpec. * @return The AirportSpec for this airport. */ const AirportSpec *GetSpec() const { if (this->tile == INVALID_TILE) return &AirportSpec::dummy; return AirportSpec::Get(this->type); } /** * Get the finite-state machine for this airport or the finite-state machine * for the dummy airport in case this isn't an airport. * @pre this->type < NEW_AIRPORT_OFFSET. * @return The state machine for this airport. */ const AirportFTAClass *GetFTA() const { return this->GetSpec()->fsm; } /** Check if this airport has at least one hangar. */ inline bool HasHangar() const { return this->GetSpec()->nof_depots > 0; } /** * Add the tileoffset to the base tile of this airport but rotate it first. * The base tile is the northernmost tile of this airport. This function * helps to make sure that getting the tile of a hangar works even for * rotated airport layouts without requiring a rotated array of hangar tiles. * @param tidc The tilediff to add to the airport tile. * @return The tile of this airport plus the rotated offset. */ inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const { const AirportSpec *as = this->GetSpec(); switch (this->rotation) { case DIR_N: return this->tile + ToTileIndexDiff(tidc); case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x); case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y); case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x); default: NOT_REACHED(); } } /** * Get the first tile of the given hangar. * @param hangar_num The hangar to get the location of. * @pre hangar_num < GetNumHangars(). * @return A tile with the given hangar. */ inline TileIndex GetHangarTile(uint hangar_num) const { const AirportSpec *as = this->GetSpec(); for (uint i = 0; i < as->nof_depots; i++) { if (as->depot_table[i].hangar_num == hangar_num) { return this->GetRotatedTileFromOffset(as->depot_table[i].ti); } } NOT_REACHED(); } /** * Get the exit direction of the hangar at a specific tile. * @param tile The tile to query. * @pre IsHangarTile(tile). * @return The exit direction of the hangar, taking airport rotation into account. */ inline Direction GetHangarExitDirection(TileIndex tile) const { const AirportSpec *as = this->GetSpec(); const HangarTileTable *htt = GetHangarDataByTile(tile); return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0])); } /** * Get the hangar number of the hangar at a specific tile. * @param tile The tile to query. * @pre IsHangarTile(tile). * @return The hangar number of the hangar at the given tile. */ inline uint GetHangarNum(TileIndex tile) const { const HangarTileTable *htt = GetHangarDataByTile(tile); return htt->hangar_num; } /** Get the number of hangars on this airport. */ inline uint GetNumHangars() const { uint num = 0; uint counted = 0; const AirportSpec *as = this->GetSpec(); for (uint i = 0; i < as->nof_depots; i++) { if (!HasBit(counted, as->depot_table[i].hangar_num)) { num++; SetBit(counted, as->depot_table[i].hangar_num); } } return num; } private: /** * Retrieve hangar information of a hangar at a given tile. * @param tile %Tile containing the hangar. * @return The requested hangar information. * @pre The \a tile must be at a hangar tile at an airport. */ inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const { const AirportSpec *as = this->GetSpec(); for (uint i = 0; i < as->nof_depots; i++) { if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) { return as->depot_table + i; } } NOT_REACHED(); } }; typedef SmallVector IndustryVector; /** Station data structure */ struct Station FINAL : SpecializedStation { public: RoadStop *GetPrimaryRoadStop(RoadStopType type) const { return type == ROADSTOP_BUS ? bus_stops : truck_stops; } RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const; RoadStop *bus_stops; ///< All the road stops TileArea bus_station; ///< Tile area the bus 'station' part covers RoadStop *truck_stops; ///< All the truck stops TileArea truck_station; ///< Tile area the truck 'station' part covers Airport airport; ///< Tile area the airport covers TileIndex dock_tile; ///< The location of the dock IndustryType indtype; ///< Industry type to get the name from StationHadVehicleOfTypeByte had_vehicle_of_type; byte time_since_load; byte time_since_unload; byte last_vehicle_type; std::list loading_vehicles; GoodsEntry goods[NUM_CARGO]; ///< Goods at this station uint32 always_accepted; ///< Bitmask of always accepted cargo types (by houses, HQs, industry tiles when industry doesn't accept cargo) IndustryVector industries_near; ///< Cached list of industries near the station that can accept cargo, @see DeliverGoodsToIndustry() Station(TileIndex tile = INVALID_TILE); ~Station(); void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy); void MarkTilesDirty(bool cargo_change) const; void UpdateVirtCoord(); /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const; /* virtual */ uint GetPlatformLength(TileIndex tile) const; void RecomputeIndustriesNear(); static void RecomputeIndustriesNearForAll(); uint GetCatchmentRadius() const; Rect GetCatchmentRect() const; /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const { return IsRailStationTile(tile) && GetStationIndex(tile) == this->index; } inline bool TileBelongsToAirport(TileIndex tile) const { return IsAirportTile(tile) && GetStationIndex(tile) == this->index; } /* virtual */ uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const; /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; }; #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var) /** Iterator to iterate over all tiles belonging to an airport. */ class AirportTileIterator : public OrthogonalTileIterator { private: const Station *st; ///< The station the airport is a part of. public: /** * Construct the iterator. * @param ta Area, i.e. begin point and width/height of to-be-iterated area. */ AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st) { if (!st->TileBelongsToAirport(this->tile)) ++(*this); } inline TileIterator& operator ++() { (*this).OrthogonalTileIterator::operator++(); while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) { (*this).OrthogonalTileIterator::operator++(); } return *this; } virtual TileIterator *Clone() const { return new AirportTileIterator(*this); } }; #endif /* STATION_BASE_H */ openttd-1.5.3/src/textfile_gui.cpp0000644000000000000000000003104212627373435015672 0ustar rootroot/* $Id: textfile_gui.cpp 27035 2014-10-23 10:49:19Z matthijs $ */ /* * 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 textfile_gui.cpp Implementation of textfile window. */ #include "stdafx.h" #include "fileio_func.h" #include "fontcache.h" #include "gfx_type.h" #include "gfx_func.h" #include "string_func.h" #include "textfile_gui.h" #include "widgets/misc_widget.h" #include "table/strings.h" #if defined(WITH_ZLIB) #include #endif #if defined(WITH_LZMA) #include #endif #include "safeguards.h" /** Widgets for the textfile window. */ static const NWidgetPart _nested_textfile_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_TF_CAPTION), SetDataTip(STR_NULL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_TEXTBTN, COLOUR_MAUVE, WID_TF_WRAPTEXT), SetDataTip(STR_TEXTFILE_WRAP_TEXT, STR_TEXTFILE_WRAP_TEXT_TOOLTIP), NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_MAUVE, WID_TF_BACKGROUND), SetMinimalSize(200, 125), SetResize(1, 12), SetScrollbar(WID_TF_VSCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_TF_VSCROLLBAR), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HSCROLLBAR, COLOUR_MAUVE, WID_TF_HSCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), EndContainer(), }; /** Window definition for the textfile window */ static WindowDesc _textfile_desc( WDP_CENTER, "textfile", 630, 460, WC_TEXTFILE, WC_NONE, 0, _nested_textfile_widgets, lengthof(_nested_textfile_widgets) ); TextfileWindow::TextfileWindow(TextfileType file_type) : Window(&_textfile_desc), file_type(file_type) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_TF_VSCROLLBAR); this->hscroll = this->GetScrollbar(WID_TF_HSCROLLBAR); this->FinishInitNested(); this->GetWidget(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); this->hscroll->SetStepSize(10); // Speed up horizontal scrollbar this->vscroll->SetStepSize(FONT_HEIGHT_MONO); } /* virtual */ TextfileWindow::~TextfileWindow() { free(this->text); } /** * Get the total height of the content displayed in this window, if wrapping is disabled. * @return the height in pixels */ uint TextfileWindow::GetContentHeight() { int max_width = this->GetWidget(WID_TF_BACKGROUND)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMERECT_RIGHT; uint height = 0; for (uint i = 0; i < this->lines.Length(); i++) { height += GetStringHeight(this->lines[i], max_width, FS_MONO); } return height; } /* virtual */ void TextfileWindow::UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_TF_BACKGROUND: resize->height = 1; size->height = 4 * resize->height + TOP_SPACING + BOTTOM_SPACING; // At least 4 lines are visible. size->width = max(200u, size->width); // At least 200 pixels wide. break; } } /** Set scrollbars to the right lengths. */ void TextfileWindow::SetupScrollbars() { if (IsWidgetLowered(WID_TF_WRAPTEXT)) { this->vscroll->SetCount(this->GetContentHeight()); this->hscroll->SetCount(0); } else { uint max_length = 0; for (uint i = 0; i < this->lines.Length(); i++) { max_length = max(max_length, GetStringBoundingBox(this->lines[i], FS_MONO).width); } this->vscroll->SetCount(this->lines.Length() * FONT_HEIGHT_MONO); this->hscroll->SetCount(max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); } this->SetWidgetDisabledState(WID_TF_HSCROLLBAR, IsWidgetLowered(WID_TF_WRAPTEXT)); } /* virtual */ void TextfileWindow::OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_TF_WRAPTEXT: this->ToggleWidgetLoweredState(WID_TF_WRAPTEXT); this->SetupScrollbars(); this->InvalidateData(); break; } } /* virtual */ void TextfileWindow::DrawWidget(const Rect &r, int widget) const { if (widget != WID_TF_BACKGROUND) return; const int x = r.left + WD_FRAMETEXT_LEFT; const int y = r.top + WD_FRAMETEXT_TOP; const int right = r.right - WD_FRAMETEXT_RIGHT; const int bottom = r.bottom - WD_FRAMETEXT_BOTTOM; DrawPixelInfo new_dpi; if (!FillDrawPixelInfo(&new_dpi, x, y, right - x + 1, bottom - y + 1)) return; DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &new_dpi; /* Draw content (now coordinates given to DrawString* are local to the new clipping region). */ int line_height = FONT_HEIGHT_MONO; int y_offset = -this->vscroll->GetPosition(); for (uint i = 0; i < this->lines.Length(); i++) { if (IsWidgetLowered(WID_TF_WRAPTEXT)) { y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, this->lines[i], TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO); } else { DrawString(-this->hscroll->GetPosition(), right - x, y_offset, this->lines[i], TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO); y_offset += line_height; // margin to previous element } } _cur_dpi = old_dpi; } /* virtual */ void TextfileWindow::OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND, TOP_SPACING + BOTTOM_SPACING); this->hscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND); this->SetupScrollbars(); } /* virtual */ void TextfileWindow::Reset() { this->search_iterator = 0; } /* virtual */ FontSize TextfileWindow::DefaultSize() { return FS_MONO; } /* virtual */ const char *TextfileWindow::NextString() { if (this->search_iterator >= this->lines.Length()) return NULL; return this->lines[this->search_iterator++]; } /* virtual */ bool TextfileWindow::Monospace() { return true; } /* virtual */ void TextfileWindow::SetFontNames(FreeTypeSettings *settings, const char *font_name) { #ifdef WITH_FREETYPE strecpy(settings->mono.font, font_name, lastof(settings->mono.font)); #endif /* WITH_FREETYPE */ } #if defined(WITH_ZLIB) /** * Do an in-memory gunzip operation. This works on a raw deflate stream, * or a file with gzip or zlib header. * @param bufp A pointer to a buffer containing the input data. This * buffer will be freed and replaced by a buffer containing * the uncompressed data. * @param sizep A pointer to the buffer size. Before the call, the value * pointed to should contain the size of the input buffer. * After the call, it contains the size of the uncompressed * data. * * When decompressing fails, *bufp is set to NULL and *sizep to 0. The * compressed buffer passed in is still freed in this case. */ static void Gunzip(byte **bufp, size_t *sizep) { static const int BLOCKSIZE = 8192; byte *buf = NULL; size_t alloc_size = 0; z_stream z; int res; memset(&z, 0, sizeof(z)); z.next_in = *bufp; z.avail_in = *sizep; /* window size = 15, add 32 to enable gzip or zlib header processing */ res = inflateInit2(&z, 15 + 32); /* Z_BUF_ERROR just means we need more space */ while (res == Z_OK || (res == Z_BUF_ERROR && z.avail_out == 0)) { /* When we get here, we're either just starting, or * inflate is out of output space - allocate more */ alloc_size += BLOCKSIZE; z.avail_out += BLOCKSIZE; buf = ReallocT(buf, alloc_size); z.next_out = buf + alloc_size - z.avail_out; res = inflate(&z, Z_FINISH); } free(*bufp); inflateEnd(&z); if (res == Z_STREAM_END) { *bufp = buf; *sizep = alloc_size - z.avail_out; } else { /* Something went wrong */ *bufp = NULL; *sizep = 0; free(buf); } } #endif #if defined(WITH_LZMA) /** * Do an in-memory xunzip operation. This works on a .xz or (legacy) * .lzma file. * @param bufp A pointer to a buffer containing the input data. This * buffer will be freed and replaced by a buffer containing * the uncompressed data. * @param sizep A pointer to the buffer size. Before the call, the value * pointed to should contain the size of the input buffer. * After the call, it contains the size of the uncompressed * data. * * When decompressing fails, *bufp is set to NULL and *sizep to 0. The * compressed buffer passed in is still freed in this case. */ static void Xunzip(byte **bufp, size_t *sizep) { static const int BLOCKSIZE = 8192; byte *buf = NULL; size_t alloc_size = 0; lzma_stream z = LZMA_STREAM_INIT; int res; z.next_in = *bufp; z.avail_in = *sizep; res = lzma_auto_decoder(&z, UINT64_MAX, LZMA_CONCATENATED); /* Z_BUF_ERROR just means we need more space */ while (res == LZMA_OK || (res == LZMA_BUF_ERROR && z.avail_out == 0)) { /* When we get here, we're either just starting, or * inflate is out of output space - allocate more */ alloc_size += BLOCKSIZE; z.avail_out += BLOCKSIZE; buf = ReallocT(buf, alloc_size); z.next_out = buf + alloc_size - z.avail_out; res = lzma_code(&z, LZMA_FINISH); } free(*bufp); lzma_end(&z); if (res == LZMA_STREAM_END) { *bufp = buf; *sizep = alloc_size - z.avail_out; } else { /* Something went wrong */ *bufp = NULL; *sizep = 0; free(buf); } } #endif /** * Loads the textfile text from file and setup #lines. */ /* virtual */ void TextfileWindow::LoadTextfile(const char *textfile, Subdirectory dir) { if (textfile == NULL) return; this->lines.Clear(); /* Get text from file */ size_t filesize; FILE *handle = FioFOpenFile(textfile, "rb", dir, &filesize); if (handle == NULL) return; this->text = ReallocT(this->text, filesize); size_t read = fread(this->text, 1, filesize, handle); fclose(handle); if (read != filesize) return; #if defined(WITH_ZLIB) || defined(WITH_LZMA) const char *suffix = strrchr(textfile, '.'); if (suffix == NULL) return; #endif #if defined(WITH_ZLIB) /* In-place gunzip */ if (strcmp(suffix, ".gz") == 0) Gunzip((byte**)&this->text, &filesize); #endif #if defined(WITH_LZMA) /* In-place xunzip */ if (strcmp(suffix, ".xz") == 0) Xunzip((byte**)&this->text, &filesize); #endif if (!this->text) return; /* Add space for trailing \0 */ this->text = ReallocT(this->text, filesize + 1); this->text[filesize] = '\0'; /* Replace tabs and line feeds with a space since str_validate removes those. */ for (char *p = this->text; *p != '\0'; p++) { if (*p == '\t' || *p == '\r') *p = ' '; } /* Check for the byte-order-mark, and skip it if needed. */ char *p = this->text + (strncmp("\xEF\xBB\xBF", this->text, 3) == 0 ? 3 : 0); /* Make sure the string is a valid UTF-8 sequence. */ str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE); /* Split the string on newlines. */ *this->lines.Append() = p; for (; *p != '\0'; p++) { if (*p == '\n') { *p = '\0'; *this->lines.Append() = p + 1; } } CheckForMissingGlyphs(true, this); } /** * Search a textfile file next to the given content. * @param type The type of the textfile to search for. * @param dir The subdirectory to search in. * @param filename The filename of the content to look for. * @return The path to the textfile, \c NULL otherwise. */ const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filename) { static const char * const prefixes[] = { "readme", "changelog", "license", }; assert_compile(lengthof(prefixes) == TFT_END); const char *prefix = prefixes[type]; if (filename == NULL) return NULL; static char file_path[MAX_PATH]; strecpy(file_path, filename, lastof(file_path)); char *slash = strrchr(file_path, PATHSEPCHAR); if (slash == NULL) return NULL; static const char * const exts[] = { "txt", #if defined(WITH_ZLIB) "txt.gz", #endif #if defined(WITH_LZMA) "txt.xz", #endif }; for (size_t i = 0; i < lengthof(exts); i++) { seprintf(slash + 1, lastof(file_path), "%s_%s.%s", prefix, GetCurrentLanguageIsoCode(), exts[i]); if (FioCheckFileExists(file_path, dir)) return file_path; seprintf(slash + 1, lastof(file_path), "%s_%.2s.%s", prefix, GetCurrentLanguageIsoCode(), exts[i]); if (FioCheckFileExists(file_path, dir)) return file_path; seprintf(slash + 1, lastof(file_path), "%s.%s", prefix, exts[i]); if (FioCheckFileExists(file_path, dir)) return file_path; } return NULL; } openttd-1.5.3/src/object_gui.cpp0000644000000000000000000004617612627373442015330 0ustar rootroot/* $Id: object_gui.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 object_gui.cpp The GUI for objects. */ #include "stdafx.h" #include "command_func.h" #include "newgrf.h" #include "newgrf_object.h" #include "newgrf_text.h" #include "strings_func.h" #include "viewport_func.h" #include "window_gui.h" #include "window_func.h" #include "zoom_func.h" #include "widgets/object_widget.h" #include "table/strings.h" #include "safeguards.h" static ObjectClassID _selected_object_class; ///< the currently visible object class static int _selected_object_index; ///< the index of the selected object in the current class or -1 static uint8 _selected_object_view; ///< the view of the selected object /** The window used for building objects. */ class BuildObjectWindow : public PickerWindowBase { static const int OBJECT_MARGIN = 4; ///< The margin (in pixels) around an object. int line_height; ///< The height of a single line. int info_height; ///< The height of the info box. Scrollbar *vscroll; ///< The scrollbar. /** Scroll #WID_BO_CLASS_LIST so that the selected object class is visible. */ void EnsureSelectedObjectClassIsVisible() { uint pos = 0; for (int i = 0; i < _selected_object_class; i++) { if (ObjectClass::Get((ObjectClassID) i)->GetUISpecCount() == 0) continue; pos++; } this->vscroll->ScrollTowards(pos); } /** * Tests whether the previously selected object can be selected. * @return \c true if the selected object is available, \c false otherwise. */ bool CanRestoreSelectedObject() { if (_selected_object_index == -1) return false; ObjectClass *sel_objclass = ObjectClass::Get(_selected_object_class); if ((int)sel_objclass->GetSpecCount() <= _selected_object_index) return false; return sel_objclass->GetSpec(_selected_object_index)->IsAvailable(); } /** * Calculate the number of columns of the #WID_BO_SELECT_MATRIX widget. * @return Number of columns in the matrix. */ uint GetMatrixColumnCount() { const NWidgetBase *matrix = this->GetWidget(WID_BO_SELECT_MATRIX); return 1 + (matrix->current_x - matrix->smallest_x) / matrix->resize_x; } public: BuildObjectWindow(WindowDesc *desc, Window *w) : PickerWindowBase(desc, w), info_height(1) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_BO_SCROLLBAR); this->FinishInitNested(0); this->vscroll->SetPosition(0); this->vscroll->SetCount(ObjectClass::GetUIClassCount()); NWidgetMatrix *matrix = this->GetWidget(WID_BO_SELECT_MATRIX); matrix->SetScrollbar(this->GetScrollbar(WID_BO_SELECT_SCROLL)); this->SelectOtherClass(_selected_object_class); if (this->CanRestoreSelectedObject()) { this->SelectOtherObject(_selected_object_index); } else { this->SelectFirstAvailableObject(true); } assert(ObjectClass::Get(_selected_object_class)->GetUISpecCount() > 0); // object GUI should be disables elsewise this->EnsureSelectedObjectClassIsVisible(); this->GetWidget(WID_BO_OBJECT_MATRIX)->SetCount(4); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_BO_OBJECT_NAME: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); SetDParam(0, spec != NULL ? spec->name : STR_EMPTY); break; } case WID_BO_OBJECT_SIZE: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); int size = spec == NULL ? 0 : spec->size; SetDParam(0, GB(size, HasBit(_selected_object_view, 0) ? 4 : 0, 4)); SetDParam(1, GB(size, HasBit(_selected_object_view, 0) ? 0 : 4, 4)); break; } default: break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_BO_CLASS_LIST: { for (uint i = 0; i < ObjectClass::GetClassCount(); i++) { ObjectClass *objclass = ObjectClass::Get((ObjectClassID)i); if (objclass->GetUISpecCount() == 0) continue; size->width = max(size->width, GetStringBoundingBox(objclass->name).width); } size->width += padding.width; this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->height = this->line_height; size->height = 5 * this->line_height; break; } case WID_BO_OBJECT_NAME: case WID_BO_OBJECT_SIZE: /* We do not want the window to resize when selecting objects; better clip texts */ size->width = 0; break; case WID_BO_OBJECT_MATRIX: { /* Get the right amount of buttons based on the current spec. */ const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); if (spec != NULL) { if (spec->views >= 2) size->width += resize->width; if (spec->views >= 4) size->height += resize->height; } resize->width = 0; resize->height = 0; break; } case WID_BO_OBJECT_SPRITE: { bool two_wide = false; // Whether there will be two widgets next to each other in the matrix or not. int height[2] = {0, 0}; // The height for the different views; in this case views 1/2 and 4. /* Get the height and view information. */ for (int i = 0; i < NUM_OBJECTS; i++) { const ObjectSpec *spec = ObjectSpec::Get(i); if (!spec->IsEverAvailable()) continue; two_wide |= spec->views >= 2; height[spec->views / 4] = max(ObjectSpec::Get(i)->height, height[spec->views / 4]); } /* Determine the pixel heights. */ for (size_t i = 0; i < lengthof(height); i++) { height[i] *= ScaleGUITrad(TILE_HEIGHT); height[i] += ScaleGUITrad(TILE_PIXELS) + 2 * OBJECT_MARGIN; } /* Now determine the size of the minimum widgets. When there are two columns, then * we want these columns to be slightly less wide. When there are two rows, then * determine the size of the widgets based on the maximum size for a single row * of widgets, or just the twice the widget height of the two row ones. */ size->height = max(height[0], height[1] * 2 + 2); if (two_wide) { size->width = (3 * ScaleGUITrad(TILE_PIXELS) + 2 * OBJECT_MARGIN) * 2 + 2; } else { size->width = 4 * ScaleGUITrad(TILE_PIXELS) + 2 * OBJECT_MARGIN; } /* Get the right size for the single widget based on the current spec. */ const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); if (spec != NULL) { if (spec->views >= 2) size->width = size->width / 2 - 1; if (spec->views >= 4) size->height = size->height / 2 - 1; } break; } case WID_BO_INFO: size->height = this->info_height; break; case WID_BO_SELECT_MATRIX: fill->height = 1; resize->height = 1; break; case WID_BO_SELECT_IMAGE: size->width = ScaleGUITrad(64) + 2; size->height = ScaleGUITrad(58) + 2; break; default: break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (GB(widget, 0, 16)) { case WID_BO_CLASS_LIST: { int y = r.top; uint pos = 0; for (uint i = 0; i < ObjectClass::GetClassCount(); i++) { ObjectClass *objclass = ObjectClass::Get((ObjectClassID)i); if (objclass->GetUISpecCount() == 0) continue; if (!this->vscroll->IsVisible(pos++)) continue; DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, objclass->name, ((int)i == _selected_object_class) ? TC_WHITE : TC_BLACK); y += this->line_height; } break; } case WID_BO_OBJECT_SPRITE: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); if (spec == NULL) break; /* Height of the selection matrix. * Depending on the number of views, the matrix has a 1x1, 1x2, 2x1 or 2x2 layout. To make the previews * look nice in all layouts, we use the 4x4 layout (smallest previews) as starting point. For the bigger * previews in the layouts with less views we add space homogeneously on all sides, so the 4x4 preview-rectangle * is centered in the 2x1, 1x2 resp. 1x1 buttons. */ uint matrix_height = this->GetWidget(WID_BO_OBJECT_MATRIX)->current_y; DrawPixelInfo tmp_dpi; /* Set up a clipping area for the preview. */ if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; if (spec->grf_prop.grffile == NULL) { extern const DrawTileSprites _objects[]; const DrawTileSprites *dts = &_objects[spec->grf_prop.local_id]; DrawOrigTileSeqInGUI((r.right - r.left) / 2 - 1, (r.bottom - r.top + matrix_height / 2) / 2 - OBJECT_MARGIN - ScaleGUITrad(TILE_PIXELS), dts, PAL_NONE); } else { DrawNewObjectTileInGUI((r.right - r.left) / 2 - 1, (r.bottom - r.top + matrix_height / 2) / 2 - OBJECT_MARGIN - ScaleGUITrad(TILE_PIXELS), spec, GB(widget, 16, 16)); } _cur_dpi = old_dpi; } break; } case WID_BO_SELECT_IMAGE: { ObjectClass *objclass = ObjectClass::Get(_selected_object_class); int obj_index = objclass->GetIndexFromUI(GB(widget, 16, 16)); if (obj_index < 0) break; const ObjectSpec *spec = objclass->GetSpec(obj_index); if (spec == NULL) break; if (!spec->IsAvailable()) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK, FILLRECT_CHECKER); } DrawPixelInfo tmp_dpi; /* Set up a clipping area for the preview. */ if (FillDrawPixelInfo(&tmp_dpi, r.left + 1, r.top, (r.right - 1) - (r.left + 1) + 1, r.bottom - r.top + 1)) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; if (spec->grf_prop.grffile == NULL) { extern const DrawTileSprites _objects[]; const DrawTileSprites *dts = &_objects[spec->grf_prop.local_id]; DrawOrigTileSeqInGUI((r.right - r.left) / 2 - 1, r.bottom - r.top - OBJECT_MARGIN - ScaleGUITrad(TILE_PIXELS), dts, PAL_NONE); } else { DrawNewObjectTileInGUI((r.right - r.left) / 2 - 1, r.bottom - r.top - OBJECT_MARGIN - ScaleGUITrad(TILE_PIXELS), spec, min(_selected_object_view, spec->views - 1)); } _cur_dpi = old_dpi; } break; } case WID_BO_INFO: { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); if (spec == NULL) break; /* Get the extra message for the GUI */ if (HasBit(spec->callback_mask, CBM_OBJ_FUND_MORE_TEXT)) { uint16 callback_res = GetObjectCallback(CBID_OBJECT_FUND_MORE_TEXT, 0, 0, spec, NULL, INVALID_TILE, _selected_object_view); if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { if (callback_res > 0x400) { ErrorUnknownCallbackResult(spec->grf_prop.grffile->grfid, CBID_OBJECT_FUND_MORE_TEXT, callback_res); } else { StringID message = GetGRFStringID(spec->grf_prop.grffile->grfid, 0xD000 + callback_res); if (message != STR_NULL && message != STR_UNDEFINED) { StartTextRefStackUsage(spec->grf_prop.grffile, 6); /* Use all the available space left from where we stand up to the * end of the window. We ALSO enlarge the window if needed, so we * can 'go' wild with the bottom of the window. */ int y = DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, message, TC_ORANGE) - r.top; StopTextRefStackUsage(); if (y > this->info_height) { BuildObjectWindow *bow = const_cast(this); bow->info_height = y + 2; bow->ReInit(); } } } } } } } } /** * Select the specified object class. * @param object_class_index Object class index to select. */ void SelectOtherClass(ObjectClassID object_class_index) { _selected_object_class = object_class_index; this->GetWidget(WID_BO_SELECT_MATRIX)->SetCount(ObjectClass::Get(_selected_object_class)->GetUISpecCount()); } /** * Select the specified object in #_selected_object_class class. * @param object_index Object index to select, \c -1 means select nothing. */ void SelectOtherObject(int object_index) { _selected_object_index = object_index; if (_selected_object_index != -1) { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); _selected_object_view = min(_selected_object_view, spec->views - 1); this->ReInit(); } else { _selected_object_view = 0; } this->GetWidget(WID_BO_OBJECT_MATRIX)->SetClicked(_selected_object_view); this->GetWidget(WID_BO_SELECT_MATRIX)->SetClicked(_selected_object_index != -1 ? ObjectClass::Get(_selected_object_class)->GetUIFromIndex(_selected_object_index) : -1); this->UpdateSelectSize(); this->SetDirty(); } void UpdateSelectSize() { if (_selected_object_index == -1) { SetTileSelectSize(1, 1); } else { const ObjectSpec *spec = ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index); int w = GB(spec->size, HasBit(_selected_object_view, 0) ? 4 : 0, 4); int h = GB(spec->size, HasBit(_selected_object_view, 0) ? 0 : 4, 4); SetTileSelectSize(w, h); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_BO_CLASS_LIST); } virtual void OnClick(Point pt, int widget, int click_count) { switch (GB(widget, 0, 16)) { case WID_BO_CLASS_LIST: { int num_clicked = this->vscroll->GetPosition() + (pt.y - this->nested_array[widget]->pos_y) / this->line_height; if (num_clicked >= (int)ObjectClass::GetUIClassCount()) break; this->SelectOtherClass(ObjectClass::GetUIClass(num_clicked)); this->SelectFirstAvailableObject(false); break; } case WID_BO_SELECT_IMAGE: { ObjectClass *objclass = ObjectClass::Get(_selected_object_class); int num_clicked = objclass->GetIndexFromUI(GB(widget, 16, 16)); if (num_clicked >= 0 && objclass->GetSpec(num_clicked)->IsAvailable()) this->SelectOtherObject(num_clicked); break; } case WID_BO_OBJECT_SPRITE: if (_selected_object_index != -1) { _selected_object_view = GB(widget, 16, 16); this->GetWidget(WID_BO_OBJECT_MATRIX)->SetClicked(_selected_object_view); this->UpdateSelectSize(); this->SetDirty(); } break; } } /** * Select the first available object. * @param change_class If true, change the class if no object in the current * class is available. */ void SelectFirstAvailableObject(bool change_class) { /* First try to select an object in the selected class. */ ObjectClass *sel_objclass = ObjectClass::Get(_selected_object_class); for (uint i = 0; i < sel_objclass->GetSpecCount(); i++) { const ObjectSpec *spec = sel_objclass->GetSpec(i); if (spec->IsAvailable()) { this->SelectOtherObject(i); return; } } if (change_class) { /* If that fails, select the first available object * from a random class. */ for (ObjectClassID j = OBJECT_CLASS_BEGIN; j < OBJECT_CLASS_MAX; j++) { ObjectClass *objclass = ObjectClass::Get(j); for (uint i = 0; i < objclass->GetSpecCount(); i++) { const ObjectSpec *spec = objclass->GetSpec(i); if (spec->IsAvailable()) { this->SelectOtherClass(j); this->SelectOtherObject(i); return; } } } } /* If all objects are unavailable, select nothing... */ if (ObjectClass::Get(_selected_object_class)->GetUISpecCount() == 0) { /* ... but make sure that the class is not empty. */ for (ObjectClassID j = OBJECT_CLASS_BEGIN; j < OBJECT_CLASS_MAX; j++) { if (ObjectClass::Get(j)->GetUISpecCount() > 0) { this->SelectOtherClass(j); break; } } } this->SelectOtherObject(-1); } }; static const NWidgetPart _nested_build_object_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_OBJECT_BUILD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_HORIZONTAL), SetPadding(2, 0, 0, 0), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 5), NWidget(WWT_MATRIX, COLOUR_GREY, WID_BO_CLASS_LIST), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_OBJECT_BUILD_CLASS_TOOLTIP), SetScrollbar(WID_BO_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BO_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 0, 5), NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BO_OBJECT_MATRIX), SetPIP(0, 2, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BO_OBJECT_SPRITE), SetDataTip(0x0, STR_OBJECT_BUILD_PREVIEW_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_NAME), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(2, 5, 2, 5), NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_SIZE), SetDataTip(STR_OBJECT_BUILD_SIZE, STR_NULL), SetPadding(2, 5, 2, 5), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BO_SELECT_SCROLL), NWidget(NWID_HORIZONTAL), NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BO_SELECT_MATRIX), SetFill(0, 1), SetPIP(0, 2, 0), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BO_SELECT_IMAGE), SetMinimalSize(66, 60), SetDataTip(0x0, STR_OBJECT_BUILD_TOOLTIP), SetFill(0, 0), SetResize(0, 0), SetScrollbar(WID_BO_SELECT_SCROLL), EndContainer(), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BO_SELECT_SCROLL), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BO_INFO), SetPadding(2, 5, 0, 5), SetFill(1, 0), SetResize(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _build_object_desc( WDP_AUTO, "build_object", 0, 0, WC_BUILD_OBJECT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_object_widgets, lengthof(_nested_build_object_widgets) ); /** * Show our object picker. * @param w The toolbar window we're associated with. */ void ShowBuildObjectPicker(Window *w) { new BuildObjectWindow(&_build_object_desc, w); } /** Reset all data of the object GUI. */ void InitializeObjectGui() { _selected_object_class = (ObjectClassID)0; } /** * PlaceProc function, called when someone pressed the button if the * object-tool is selected * @param tile on which to place the object */ void PlaceProc_Object(TileIndex tile) { DoCommandP(tile, ObjectClass::Get(_selected_object_class)->GetSpec(_selected_object_index)->Index(), _selected_object_view, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_OBJECT), CcTerraform); } openttd-1.5.3/src/hotkeys.cpp0000644000000000000000000002325312627373435014675 0ustar rootroot/* $Id: hotkeys.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 hotkeys.cpp Implementation of hotkey related functions */ #include "stdafx.h" #include "openttd.h" #include "hotkeys.h" #include "ini_type.h" #include "string_func.h" #include "window_gui.h" #include "safeguards.h" char *_hotkeys_file; /** * List of all HotkeyLists. * This is a pointer to ensure initialisation order with the various static HotkeyList instances. */ static SmallVector *_hotkey_lists = NULL; /** String representation of a keycode */ struct KeycodeNames { const char *name; ///< Name of the keycode WindowKeyCodes keycode; ///< The keycode }; /** Array of non-standard keycodes that can be used in the hotkeys config file. */ static const KeycodeNames _keycode_to_name[] = { {"SHIFT", WKC_SHIFT}, {"CTRL", WKC_CTRL}, {"ALT", WKC_ALT}, {"META", WKC_META}, {"GLOBAL", WKC_GLOBAL_HOTKEY}, {"ESC", WKC_ESC}, {"DEL", WKC_DELETE}, {"RETURN", WKC_RETURN}, {"BACKQUOTE", WKC_BACKQUOTE}, {"F1", WKC_F1}, {"F2", WKC_F2}, {"F3", WKC_F3}, {"F4", WKC_F4}, {"F5", WKC_F5}, {"F6", WKC_F6}, {"F7", WKC_F7}, {"F8", WKC_F8}, {"F9", WKC_F9}, {"F10", WKC_F10}, {"F11", WKC_F11}, {"F12", WKC_F12}, {"PAUSE", WKC_PAUSE}, {"COMMA", WKC_COMMA}, {"NUM_PLUS", WKC_NUM_PLUS}, {"NUM_MINUS", WKC_NUM_MINUS}, {"=", WKC_EQUALS}, {"-", WKC_MINUS}, }; /** * Try to parse a single part of a keycode. * @param start Start of the string to parse. * @param end End of the string to parse. * @return A keycode if a match is found or 0. */ static uint16 ParseCode(const char *start, const char *end) { assert(start <= end); while (start < end && *start == ' ') start++; while (end > start && *end == ' ') end--; for (uint i = 0; i < lengthof(_keycode_to_name); i++) { if (strlen(_keycode_to_name[i].name) == (size_t)(end - start) && strncasecmp(start, _keycode_to_name[i].name, end - start) == 0) { return _keycode_to_name[i].keycode; } } if (end - start == 1) { if (*start >= 'a' && *start <= 'z') return *start - ('a'-'A'); /* Ignore invalid keycodes */ if (*(const uint8 *)start < 128) return *start; } return 0; } /** * Parse a string representation of a keycode. * @param start Start of the input. * @param end End of the input. * @return A valid keycode or 0. */ static uint16 ParseKeycode(const char *start, const char *end) { assert(start <= end); uint16 keycode = 0; for (;;) { const char *cur = start; while (*cur != '+' && cur != end) cur++; uint16 code = ParseCode(start, cur); if (code == 0) return 0; if (code & WKC_SPECIAL_KEYS) { /* Some completely wrong keycode we don't support. */ if (code & ~WKC_SPECIAL_KEYS) return 0; keycode |= code; } else { /* Ignore the code if it has more then 1 letter. */ if (keycode & ~WKC_SPECIAL_KEYS) return 0; keycode |= code; } if (cur == end) break; assert(cur < end); start = cur + 1; } return keycode; } /** * Parse a string to the keycodes it represents * @param hotkey The hotkey object to add the keycodes to * @param value The string to parse */ static void ParseHotkeys(Hotkey *hotkey, const char *value) { const char *start = value; while (*start != '\0') { const char *end = start; while (*end != '\0' && *end != ',') end++; uint16 keycode = ParseKeycode(start, end); if (keycode != 0) hotkey->AddKeycode(keycode); start = (*end == ',') ? end + 1: end; } } /** * Convert a hotkey to it's string representation so it can be written to the * config file. Separate parts of the keycode (like "CTRL" and "F1" are split * by a '+'. * @param keycode The keycode to convert to a string. * @return A string representation of this keycode. * @note The return value is a static buffer, stredup the result before calling * this function again. */ static const char *KeycodeToString(uint16 keycode) { static char buf[32]; buf[0] = '\0'; bool first = true; if (keycode & WKC_GLOBAL_HOTKEY) { strecat(buf, "GLOBAL", lastof(buf)); first = false; } if (keycode & WKC_SHIFT) { if (!first) strecat(buf, "+", lastof(buf)); strecat(buf, "SHIFT", lastof(buf)); first = false; } if (keycode & WKC_CTRL) { if (!first) strecat(buf, "+", lastof(buf)); strecat(buf, "CTRL", lastof(buf)); first = false; } if (keycode & WKC_ALT) { if (!first) strecat(buf, "+", lastof(buf)); strecat(buf, "ALT", lastof(buf)); first = false; } if (keycode & WKC_META) { if (!first) strecat(buf, "+", lastof(buf)); strecat(buf, "META", lastof(buf)); first = false; } if (!first) strecat(buf, "+", lastof(buf)); keycode = keycode & ~WKC_SPECIAL_KEYS; for (uint i = 0; i < lengthof(_keycode_to_name); i++) { if (_keycode_to_name[i].keycode == keycode) { strecat(buf, _keycode_to_name[i].name, lastof(buf)); return buf; } } assert(keycode < 128); char key[2]; key[0] = keycode; key[1] = '\0'; strecat(buf, key, lastof(buf)); return buf; } /** * Convert all keycodes attached to a hotkey to a single string. If multiple * keycodes are attached to the hotkey they are split by a comma. * @param hotkey The keycodes of this hotkey need to be converted to a string. * @return A string representation of all keycodes. * @note The return value is a static buffer, stredup the result before calling * this function again. */ const char *SaveKeycodes(const Hotkey *hotkey) { static char buf[128]; buf[0] = '\0'; for (uint i = 0; i < hotkey->keycodes.Length(); i++) { const char *str = KeycodeToString(hotkey->keycodes[i]); if (i > 0) strecat(buf, ",", lastof(buf)); strecat(buf, str, lastof(buf)); } return buf; } /** * Create a new Hotkey object with a single default keycode. * @param default_keycode The default keycode for this hotkey. * @param name The name of this hotkey. * @param num Number of this hotkey, should be unique within the hotkey list. */ Hotkey::Hotkey(uint16 default_keycode, const char *name, int num) : name(name), num(num) { if (default_keycode != 0) this->AddKeycode(default_keycode); } /** * Create a new Hotkey object with multiple default keycodes. * @param default_keycodes An array of default keycodes terminated with 0. * @param name The name of this hotkey. * @param num Number of this hotkey, should be unique within the hotkey list. */ Hotkey::Hotkey(const uint16 *default_keycodes, const char *name, int num) : name(name), num(num) { const uint16 *keycode = default_keycodes; while (*keycode != 0) { this->AddKeycode(*keycode); keycode++; } } /** * Add a keycode to this hotkey, from now that keycode will be matched * in addition to any previously added keycodes. * @param keycode The keycode to add. */ void Hotkey::AddKeycode(uint16 keycode) { this->keycodes.Include(keycode); } HotkeyList::HotkeyList(const char *ini_group, Hotkey *items, GlobalHotkeyHandlerFunc global_hotkey_handler) : global_hotkey_handler(global_hotkey_handler), ini_group(ini_group), items(items) { if (_hotkey_lists == NULL) _hotkey_lists = new SmallVector(); *_hotkey_lists->Append() = this; } HotkeyList::~HotkeyList() { _hotkey_lists->Erase(_hotkey_lists->Find(this)); } /** * Load HotkeyList from IniFile. * @param ini IniFile to load from. */ void HotkeyList::Load(IniFile *ini) { IniGroup *group = ini->GetGroup(this->ini_group); for (Hotkey *hotkey = this->items; hotkey->name != NULL; ++hotkey) { IniItem *item = group->GetItem(hotkey->name, false); if (item != NULL) { hotkey->keycodes.Clear(); if (item->value != NULL) ParseHotkeys(hotkey, item->value); } } } /** * Save HotkeyList to IniFile. * @param ini IniFile to save to. */ void HotkeyList::Save(IniFile *ini) const { IniGroup *group = ini->GetGroup(this->ini_group); for (const Hotkey *hotkey = this->items; hotkey->name != NULL; ++hotkey) { IniItem *item = group->GetItem(hotkey->name, true); item->SetValue(SaveKeycodes(hotkey)); } } /** * Check if a keycode is bound to something. * @param keycode The keycode that was pressed * @param global_only Limit the search to hotkeys defined as 'global'. * @return The number of the matching hotkey or -1. */ int HotkeyList::CheckMatch(uint16 keycode, bool global_only) const { for (const Hotkey *list = this->items; list->name != NULL; ++list) { if (list->keycodes.Contains(keycode | WKC_GLOBAL_HOTKEY) || (!global_only && list->keycodes.Contains(keycode))) { return list->num; } } return -1; } static void SaveLoadHotkeys(bool save) { IniFile *ini = new IniFile(); ini->LoadFromDisk(_hotkeys_file, BASE_DIR); for (HotkeyList **list = _hotkey_lists->Begin(); list != _hotkey_lists->End(); ++list) { if (save) { (*list)->Save(ini); } else { (*list)->Load(ini); } } if (save) ini->SaveToDisk(_hotkeys_file); delete ini; } /** Load the hotkeys from the config file */ void LoadHotkeysFromConfig() { SaveLoadHotkeys(false); } /** Save the hotkeys to the config file */ void SaveHotkeysToConfig() { SaveLoadHotkeys(true); } void HandleGlobalHotkeys(WChar key, uint16 keycode) { for (HotkeyList **list = _hotkey_lists->Begin(); list != _hotkey_lists->End(); ++list) { if ((*list)->global_hotkey_handler == NULL) continue; int hotkey = (*list)->CheckMatch(keycode, true); if (hotkey >= 0 && ((*list)->global_hotkey_handler(hotkey) == ES_HANDLED)) return; } } openttd-1.5.3/src/direction_func.h0000644000000000000000000001713012627373436015645 0ustar rootroot/* $Id: direction_func.h 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 direction_func.h Different functions related to conversions between directions. */ #ifndef DIRECTION_FUNC_H #define DIRECTION_FUNC_H #include "direction_type.h" /** * Checks if an integer value is a valid DiagDirection * * @param d The value to check * @return True if the value belongs to a DiagDirection, else false */ static inline bool IsValidDiagDirection(DiagDirection d) { return d < DIAGDIR_END; } /** * Checks if an integer value is a valid Direction * * @param d The value to check * @return True if the value belongs to a Direction, else false */ static inline bool IsValidDirection(Direction d) { return d < DIR_END; } /** * Checks if an integer value is a valid Axis * * @param d The value to check * @return True if the value belongs to an Axis, else false */ static inline bool IsValidAxis(Axis d) { return d < AXIS_END; } /** * Return the reverse of a direction * * @param d The direction to get the reverse from * @return The reverse Direction */ static inline Direction ReverseDir(Direction d) { assert(IsValidDirection(d)); return (Direction)(4 ^ d); } /** * Calculate the difference between two directions * * @param d0 The first direction as the base * @param d1 The second direction as the offset from the base * @return The difference how the second direction drifts of the first one. */ static inline DirDiff DirDifference(Direction d0, Direction d1) { assert(IsValidDirection(d0)); assert(IsValidDirection(d1)); /* Cast to uint so compiler can use bitmask. If the difference is negative * and we used int instead of uint, further "+ 8" would have to be added. */ return (DirDiff)((uint)(d0 - d1) % 8); } /** * Applies two differences together * * This function adds two differences together and returns the resulting * difference. So adding two DIRDIFF_REVERSE together results in the * DIRDIFF_SAME difference. * * @param d The first difference * @param delta The second difference to add on * @return The resulting difference */ static inline DirDiff ChangeDirDiff(DirDiff d, DirDiff delta) { /* Cast to uint so compiler can use bitmask. Result can never be negative. */ return (DirDiff)((uint)(d + delta) % 8); } /** * Change a direction by a given difference * * This functions returns a new direction of the given direction * which is rotated by the given difference. * * @param d The direction to get a new direction from * @param delta The offset/drift applied to the direction * @return The new direction */ static inline Direction ChangeDir(Direction d, DirDiff delta) { assert(IsValidDirection(d)); /* Cast to uint so compiler can use bitmask. Result can never be negative. */ return (Direction)((uint)(d + delta) % 8); } /** * Returns the reverse direction of the given DiagDirection * * @param d The DiagDirection to get the reverse from * @return The reverse direction */ static inline DiagDirection ReverseDiagDir(DiagDirection d) { assert(IsValidDiagDirection(d)); return (DiagDirection)(2 ^ d); } /** * Calculate the difference between two DiagDirection values * * @param d0 The first direction as the base * @param d1 The second direction as the offset from the base * @return The difference how the second direction drifts of the first one. */ static inline DiagDirDiff DiagDirDifference(DiagDirection d0, DiagDirection d1) { assert(IsValidDiagDirection(d0)); assert(IsValidDiagDirection(d1)); /* Cast to uint so compiler can use bitmask. Result can never be negative. */ return (DiagDirDiff)((uint)(d0 - d1) % 4); } /** * Applies a difference on a DiagDirection * * This function applies a difference on a DiagDirection and returns * the new DiagDirection. * * @param d The DiagDirection * @param delta The difference to apply on * @return The new direction which was calculated */ static inline DiagDirection ChangeDiagDir(DiagDirection d, DiagDirDiff delta) { assert(IsValidDiagDirection(d)); /* Cast to uint so compiler can use bitmask. Result can never be negative. */ return (DiagDirection)((uint)(d + delta) % 4); } /** * Convert a Direction to a DiagDirection. * * This function can be used to convert the 8-way Direction to * the 4-way DiagDirection. If the direction cannot be mapped its * "rounded clockwise". So DIR_N becomes DIAGDIR_NE. * * @param dir The direction to convert * @return The resulting DiagDirection, maybe "rounded clockwise". */ static inline DiagDirection DirToDiagDir(Direction dir) { assert(IsValidDirection(dir)); return (DiagDirection)(dir >> 1); } /** * Convert a DiagDirection to a Direction. * * This function can be used to convert the 4-way DiagDirection * to the 8-way Direction. As 4-way are less than 8-way not all * possible directions can be calculated. * * @param dir The direction to convert * @return The resulting Direction */ static inline Direction DiagDirToDir(DiagDirection dir) { assert(IsValidDiagDirection(dir)); return (Direction)(dir * 2 + 1); } /** * Select the other axis as provided. * * This is basically the not-operator for the axis. * * @param a The given axis * @return The other axis */ static inline Axis OtherAxis(Axis a) { assert(IsValidAxis(a)); return (Axis)(a ^ 1); } /** * Convert a DiagDirection to the axis. * * This function returns the axis which belongs to the given * DiagDirection. The axis X belongs to the DiagDirection * north-east and south-west. * * @param d The DiagDirection * @return The axis which belongs to the direction */ static inline Axis DiagDirToAxis(DiagDirection d) { assert(IsValidDiagDirection(d)); return (Axis)(d & 1); } /** * Converts an Axis to a DiagDirection * * This function returns the DiagDirection which * belongs to the axis. As 2 directions are mapped to an axis * this function returns the one which points to south, * either south-west (on X axis) or south-east (on Y axis) * * @param a The axis * @return The direction pointed to south */ static inline DiagDirection AxisToDiagDir(Axis a) { assert(IsValidAxis(a)); return (DiagDirection)(2 - a); } /** * Converts an Axis to a Direction * * This function returns the Direction which * belongs to the axis. As 2 directions are mapped to an axis * this function returns the one which points to south, * either south-west (on X axis) or south-east (on Y axis) * * @param a The axis * @return The direction pointed to south */ static inline Direction AxisToDirection(Axis a) { assert(IsValidAxis(a)); return (Direction)(5 - 2 * a); } /** * Convert an axis and a flag for north/south into a DiagDirection * @param xy axis to convert * @param ns north -> 0, south -> 1 * @return the desired DiagDirection */ static inline DiagDirection XYNSToDiagDir(Axis xy, uint ns) { assert(IsValidAxis(xy)); return (DiagDirection)(xy * 3 ^ ns * 2); } /** * Checks if a given Direction is diagonal. * * @param dir The given direction. * @return True if the direction is diagonal. */ static inline bool IsDiagonalDirection(Direction dir) { assert(IsValidDirection(dir)); return (dir & 1) != 0; } #endif /* DIRECTION_FUNC_H */ openttd-1.5.3/src/economy_func.h0000644000000000000000000000366212627373435015342 0ustar rootroot/* $Id: economy_func.h 24565 2012-10-01 19:31:55Z frosch $ */ /* * 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 economy_func.h Functions related to the economy. */ #ifndef ECONOMY_FUNC_H #define ECONOMY_FUNC_H #include "economy_type.h" #include "station_type.h" #include "cargo_type.h" #include "vehicle_type.h" #include "company_type.h" void ResetPriceBaseMultipliers(); void SetPriceBaseMultiplier(Price price, int factor); extern const ScoreInfo _score_info[]; extern int _score_part[MAX_COMPANIES][SCORE_END]; extern Economy _economy; /* Prices and also the fractional part. */ extern Prices _price; int UpdateCompanyRatingAndValue(Company *c, bool update); void StartupIndustryDailyChanges(bool init_counter); Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type); uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations); void PrepareUnload(Vehicle *front_v); void LoadUnloadStation(Station *st); Money GetPrice(Price index, uint cost_factor, const struct GRFFile *grf_file, int shift = 0); void InitializeEconomy(); void RecomputePrices(); bool AddInflation(bool check_year = true); /** * Is the economy in recession? * @return \c True if economy is in recession, \c false otherwise. */ static inline bool EconomyIsInRecession() { return _economy.fluct <= 0; } #endif /* ECONOMY_FUNC_H */ openttd-1.5.3/src/subsidy_base.h0000644000000000000000000000567512627373435015340 0ustar rootroot/* $Id: subsidy_base.h 23704 2012-01-01 17:22:32Z alberth $ */ /* * 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 subsidy_base.h %Subsidy base class. */ #ifndef SUBSIDY_BASE_H #define SUBSIDY_BASE_H #include "cargo_type.h" #include "company_type.h" #include "subsidy_type.h" #include "core/pool_type.hpp" typedef Pool SubsidyPool; extern SubsidyPool _subsidy_pool; /** Struct about subsidies, offered and awarded */ struct Subsidy : SubsidyPool::PoolItem<&_subsidy_pool> { CargoID cargo_type; ///< Cargo type involved in this subsidy, CT_INVALID for invalid subsidy byte remaining; ///< Remaining months when this subsidy is valid CompanyByte awarded; ///< Subsidy is awarded to this company; INVALID_COMPANY if it's not awarded to anyone SourceTypeByte src_type; ///< Source of subsidised path (ST_INDUSTRY or ST_TOWN) SourceTypeByte dst_type; ///< Destination of subsidised path (ST_INDUSTRY or ST_TOWN) SourceID src; ///< Index of source. Either TownID or IndustryID SourceID dst; ///< Index of destination. Either TownID or IndustryID /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) */ inline Subsidy() { } /** * (Empty) destructor has to be defined else operator delete might be called with NULL parameter */ inline ~Subsidy() { } /** * Tests whether this subsidy has been awarded to someone * @return is this subsidy awarded? */ inline bool IsAwarded() const { return this->awarded != INVALID_COMPANY; } void AwardTo(CompanyID company); }; /** Constants related to subsidies */ static const uint SUBSIDY_OFFER_MONTHS = 12; ///< Duration of subsidy offer static const uint SUBSIDY_CONTRACT_MONTHS = 12; ///< Duration of subsidy after awarding static const uint SUBSIDY_PAX_MIN_POPULATION = 400; ///< Min. population of towns for subsidised pax route static const uint SUBSIDY_CARGO_MIN_POPULATION = 900; ///< Min. population of destination town for cargo route static const uint SUBSIDY_MAX_PCT_TRANSPORTED = 42; ///< Subsidy will be created only for towns/industries with less % transported static const uint SUBSIDY_MAX_DISTANCE = 70; ///< Max. length of subsidised route (DistanceManhattan) #define FOR_ALL_SUBSIDIES_FROM(var, start) FOR_ALL_ITEMS_FROM(Subsidy, subsidy_index, var, start) #define FOR_ALL_SUBSIDIES(var) FOR_ALL_SUBSIDIES_FROM(var, 0) #endif /* SUBSIDY_BASE_H */ openttd-1.5.3/src/tunnelbridge.h0000644000000000000000000000262712627373442015336 0ustar rootroot/* $Id: tunnelbridge.h 27157 2015-02-22 14:01:24Z frosch $ */ /* * 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 tunnelbridge.h Header file for things common for tunnels and bridges */ #ifndef TUNNELBRIDGE_H #define TUNNELBRIDGE_H #include "map_func.h" void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height); void MarkBridgeDirty(TileIndex tile); /** * Calculates the length of a tunnel or a bridge (without end tiles) * @param begin The begin of the tunnel or bridge. * @param end The end of the tunnel or bridge. * @return length of bridge/tunnel middle */ static inline uint GetTunnelBridgeLength(TileIndex begin, TileIndex end) { int x1 = TileX(begin); int y1 = TileY(begin); int x2 = TileX(end); int y2 = TileY(end); return abs(x2 + y2 - x1 - y1) - 1; } extern TileIndex _build_tunnel_endtile; #endif /* TUNNELBRIDGE_H */ openttd-1.5.3/src/road_type.h0000644000000000000000000000650312627373435014641 0ustar rootroot/* $Id: road_type.h 23595 2011-12-19 17:48:04Z rubidium $ */ /* * 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 road_type.h Enums and other types related to roads. */ #ifndef ROAD_TYPE_H #define ROAD_TYPE_H #include "core/enum_type.hpp" /** * The different roadtypes we support * * @note currently only ROADTYPE_ROAD and ROADTYPE_TRAM are supported. */ enum RoadType { ROADTYPE_BEGIN = 0, ///< Used for iterations ROADTYPE_ROAD = 0, ///< Basic road type ROADTYPE_TRAM = 1, ///< Trams ROADTYPE_END, ///< Used for iterations INVALID_ROADTYPE = 0xFF, ///< flag for invalid roadtype }; DECLARE_POSTFIX_INCREMENT(RoadType) template <> struct EnumPropsT : MakeEnumPropsT {}; /** * The different roadtypes we support, but then a bitmask of them * @note currently only roadtypes with ROADTYPE_ROAD and ROADTYPE_TRAM are supported. */ enum RoadTypes { ROADTYPES_NONE = 0, ///< No roadtypes ROADTYPES_ROAD = 1 << ROADTYPE_ROAD, ///< Road ROADTYPES_TRAM = 1 << ROADTYPE_TRAM, ///< Trams ROADTYPES_ALL = ROADTYPES_ROAD | ROADTYPES_TRAM, ///< Road + trams ROADTYPES_END, ///< Used for iterations? INVALID_ROADTYPES = 0xFF, ///< Invalid roadtypes }; DECLARE_ENUM_AS_BIT_SET(RoadTypes) template <> struct EnumPropsT : MakeEnumPropsT {}; typedef SimpleTinyEnumT RoadTypesByte; /** * Enumeration for the road parts on a tile. * * This enumeration defines the possible road parts which * can be build on a tile. */ enum RoadBits { ROAD_NONE = 0U, ///< No road-part is build ROAD_NW = 1U, ///< North-west part ROAD_SW = 2U, ///< South-west part ROAD_SE = 4U, ///< South-east part ROAD_NE = 8U, ///< North-east part ROAD_X = ROAD_SW | ROAD_NE, ///< Full road along the x-axis (south-west + north-east) ROAD_Y = ROAD_NW | ROAD_SE, ///< Full road along the y-axis (north-west + south-east) ROAD_N = ROAD_NE | ROAD_NW, ///< Road at the two northern edges ROAD_E = ROAD_NE | ROAD_SE, ///< Road at the two eastern edges ROAD_S = ROAD_SE | ROAD_SW, ///< Road at the two southern edges ROAD_W = ROAD_NW | ROAD_SW, ///< Road at the two western edges ROAD_ALL = ROAD_X | ROAD_Y, ///< Full 4-way crossing ROAD_END = ROAD_ALL + 1, ///< Out-of-range roadbits, used for iterations }; DECLARE_ENUM_AS_BIT_SET(RoadBits) template <> struct EnumPropsT : MakeEnumPropsT {}; #endif /* ROAD_TYPE_H */ openttd-1.5.3/src/stdafx.h0000644000000000000000000004204012627373435014140 0ustar rootroot/* $Id: stdafx.h 27109 2015-01-02 19:50:43Z rubidium $ */ /* * 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 stdafx.h Definition of base types and functions in a cross-platform compatible way. */ #ifndef STDAFX_H #define STDAFX_H #if defined(__APPLE__) #include "os/macosx/osx_stdafx.h" #endif /* __APPLE__ */ #if defined(__BEOS__) || defined(__HAIKU__) #include #include #define _GNU_SOURCE #define TROUBLED_INTS #include #elif defined(__NDS__) #include #define TROUBLED_INTS #endif /* It seems that we need to include stdint.h before anything else * We need INT64_MAX, which for most systems comes from stdint.h. However, MSVC * does not have stdint.h and apparently neither does MorphOS. * For OSX the inclusion is already done in osx_stdafx.h. */ #if !defined(__APPLE__) && (!defined(_MSC_VER) || _MSC_VER >= 1600) && !defined(__MORPHOS__) #if defined(SUNOS) /* SunOS/Solaris does not have stdint.h, but inttypes.h defines everything * stdint.h defines and we need. */ #include #else #define __STDC_LIMIT_MACROS #include #endif #endif /* The conditions for these constants to be available are way too messy; so check them one by one */ #if !defined(UINT64_MAX) #define UINT64_MAX (18446744073709551615ULL) #endif #if !defined(INT64_MAX) #define INT64_MAX (9223372036854775807LL) #endif #if !defined(INT64_MIN) #define INT64_MIN (-INT64_MAX - 1) #endif #if !defined(UINT32_MAX) #define UINT32_MAX (4294967295U) #endif #if !defined(INT32_MAX) #define INT32_MAX (2147483647) #endif #if !defined(INT32_MIN) #define INT32_MIN (-INT32_MAX - 1) #endif #if !defined(UINT16_MAX) #define UINT16_MAX (65535U) #endif #if !defined(INT16_MAX) #define INT16_MAX (32767) #endif #if !defined(INT16_MIN) #define INT16_MIN (-INT16_MAX - 1) #endif #if !defined(UINT8_MAX) #define UINT8_MAX (255) #endif #if !defined(INT8_MAX) #define INT8_MAX (127) #endif #if !defined(INT8_MIN) #define INT8_MIN (-INT8_MAX - 1) #endif #include #include #include #include #include #include #ifndef SIZE_MAX #define SIZE_MAX ((size_t)-1) #endif #if defined(UNIX) || defined(__MINGW32__) #include #endif #if defined(__OS2__) #include #define strcasecmp stricmp #endif #if defined(PSP) #include #include #include #endif #if defined(SUNOS) || defined(HPUX) #include #endif #if defined(__MORPHOS__) /* MorphOS defines certain Amiga defines per default, we undefine them * here to make the rest of source less messy and more clear what is * required for morphos and what for AmigaOS */ #if defined(amigaos) #undef amigaos #endif #if defined(__amigaos__) #undef __amigaos__ # endif #if defined(__AMIGA__) #undef __AMIGA__ #endif #if defined(AMIGA) #undef AMIGA #endif #if defined(amiga) #undef amiga #endif /* Act like we already included this file, as it somehow gives linkage problems * (mismatch linkage of C++ and C between this include and unistd.h). */ #define CLIB_USERGROUP_PROTOS_H #endif /* __MORPHOS__ */ #if defined(PSP) /* PSP can only have 10 file-descriptors open at any given time, but this * switch only limits reads via the Fio system. So keep 2 fds free for things * like saving a game. */ #define LIMITED_FDS 8 #define printf pspDebugScreenPrintf #endif /* PSP */ /* Stuff for GCC */ #if defined(__GNUC__) #define NORETURN __attribute__ ((noreturn)) #define CDECL #define __int64 long long #define GCC_PACK __attribute__((packed)) /* Warn about functions using 'printf' format syntax. First argument determines which parameter * is the format string, second argument is start of values passed to printf. */ #define WARN_FORMAT(string, args) __attribute__ ((format (printf, string, args))) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) #define FINAL final #else #define FINAL #endif #endif /* __GNUC__ */ #if defined(__WATCOMC__) #define NORETURN #define CDECL #define GCC_PACK #define WARN_FORMAT(string, args) #define FINAL #include #endif /* __WATCOMC__ */ #if defined(__MINGW32__) || defined(__CYGWIN__) #include // alloca() #endif #if defined(WIN32) #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #endif /* Stuff for MSVC */ #if defined(_MSC_VER) #pragma once #ifdef _WIN64 /* No 64-bit Windows below XP, so we can safely assume it as the target platform. */ #define NTDDI_VERSION NTDDI_WINXP // Windows XP #define _WIN32_WINNT 0x501 // Windows XP #define _WIN32_WINDOWS 0x501 // Windows XP #define WINVER 0x0501 // Windows XP #define _WIN32_IE_ 0x0600 // 6.0 (XP+) #else /* Define a win32 target platform, to override defaults of the SDK * We need to define NTDDI version for Vista SDK, but win2k is minimum */ #define NTDDI_VERSION NTDDI_WIN2K // Windows 2000 #define _WIN32_WINNT 0x0500 // Windows 2000 #define _WIN32_WINDOWS 0x400 // Windows 95 #if !defined(WINCE) #define WINVER 0x0400 // Windows NT 4.0 / Windows 95 #endif #define _WIN32_IE_ 0x0401 // 4.01 (win98 and NT4SP5+) #endif #define NOMINMAX // Disable min/max macros in windows.h. #pragma warning(disable: 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data #pragma warning(disable: 4761) // integral size mismatch in argument : conversion supplied #pragma warning(disable: 4200) // nonstandard extension used : zero-sized array in struct/union #pragma warning(disable: 4355) // 'this' : used in base member initializer list #if (_MSC_VER < 1400) // MSVC 2005 safety checks #error "Only MSVC 2005 or higher are supported. MSVC 2003 and earlier are not! Upgrade your compiler." #endif /* (_MSC_VER < 1400) */ #pragma warning(disable: 4291) // no matching operator delete found; memory will not be freed if initialization throws an exception (reason: our overloaded functions never throw an exception) #pragma warning(disable: 4996) // 'function': was declared deprecated #define _CRT_SECURE_NO_DEPRECATE // all deprecated 'unsafe string functions #pragma warning(disable: 6308) // code analyzer: 'realloc' might return null pointer: assigning null pointer to 't_ptr', which is passed as an argument to 'realloc', will cause the original memory block to be leaked #pragma warning(disable: 6011) // code analyzer: Dereferencing NULL pointer 'pfGetAddrInfo': Lines: 995, 996, 998, 999, 1001 #pragma warning(disable: 6326) // code analyzer: potential comparison of a constant with another constant #pragma warning(disable: 6031) // code analyzer: Return value ignored: 'ReadFile' #pragma warning(disable: 6255) // code analyzer: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead #pragma warning(disable: 6246) // code analyzer: Local declaration of 'statspec' hides declaration of the same name in outer scope. For additional information, see previous declaration at ... #if (_MSC_VER == 1500) // Addresses item #13 on http://blogs.msdn.com/b/vcblog/archive/2008/08/11/tr1-fixes-in-vc9-sp1.aspx, for Visual Studio 2008 #define _DO_NOT_DECLARE_INTERLOCKED_INTRINSICS_IN_MEMORY #include #endif #include // alloca() #define NORETURN __declspec(noreturn) #define inline __forceinline #if !defined(WINCE) #define CDECL _cdecl #endif #define GCC_PACK #define WARN_FORMAT(string, args) #define FINAL sealed #if defined(WINCE) int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap); #endif #if defined(WIN32) && !defined(_WIN64) && !defined(WIN64) #if !defined(_W64) #define _W64 #endif typedef _W64 int INT_PTR, *PINT_PTR; typedef _W64 unsigned int UINT_PTR, *PUINT_PTR; #endif /* WIN32 && !_WIN64 && !WIN64 */ #if defined(_WIN64) || defined(WIN64) #define fseek _fseeki64 #endif /* _WIN64 || WIN64 */ /* This is needed to zlib uses the stdcall calling convention on visual studio */ #if defined(WITH_ZLIB) || defined(WITH_PNG) #if !defined(ZLIB_WINAPI) #define ZLIB_WINAPI #endif #endif #if defined(WINCE) #define strcasecmp _stricmp #define strncasecmp _strnicmp #undef DEBUG #else #define strcasecmp stricmp #define strncasecmp strnicmp #endif #define strtoull _strtoui64 /* MSVC doesn't have these :( */ #define S_ISDIR(mode) (mode & S_IFDIR) #define S_ISREG(mode) (mode & S_IFREG) #endif /* defined(_MSC_VER) */ #if defined(DOS) /* The DOS port does not have all signals/signal functions. */ #define strsignal(sig) "" /* Use 'no floating point' for bus errors; SIGBUS does not exist * for DOS, SIGNOFP for other platforms. So it's fairly safe * to interchange those. */ #define SIGBUS SIGNOFP #endif #if defined(WINCE) #define stredup _stredup #endif /* WINCE */ /* NOTE: the string returned by these functions is only valid until the next * call to the same function and is not thread- or reentrancy-safe */ #if !defined(STRGEN) && !defined(SETTINGSGEN) #if defined(WIN32) || defined(WIN64) char *getcwd(char *buf, size_t size); #include #include /* XXX - WinCE without MSVCRT doesn't support wfopen, so it seems */ #if !defined(WINCE) namespace std { using ::_tfopen; } #define fopen(file, mode) _tfopen(OTTD2FS(file), _T(mode)) #define unlink(file) _tunlink(OTTD2FS(file)) #endif /* WINCE */ const char *FS2OTTD(const TCHAR *name); const TCHAR *OTTD2FS(const char *name, bool console_cp = false); #else #define fopen(file, mode) fopen(OTTD2FS(file), mode) const char *FS2OTTD(const char *name); const char *OTTD2FS(const char *name); #endif /* WIN32 */ #endif /* STRGEN || SETTINGSGEN */ #if defined(WIN32) || defined(WIN64) || defined(__OS2__) && !defined(__INNOTEK_LIBC__) #define PATHSEP "\\" #define PATHSEPCHAR '\\' #else #define PATHSEP "/" #define PATHSEPCHAR '/' #endif /* MSVCRT of course has to have a different syntax for long long *sigh* */ #if defined(_MSC_VER) || defined(__MINGW32__) #define OTTD_PRINTF64 "%I64d" #define OTTD_PRINTFHEX64 "%I64x" #define PRINTF_SIZE "%Iu" #else #define OTTD_PRINTF64 "%lld" #define OTTD_PRINTFHEX64 "%llx" #define PRINTF_SIZE "%zu" #endif typedef unsigned char byte; /* This is already defined in unix, but not in QNX Neutrino (6.x)*/ #if (!defined(UNIX) && !defined(__CYGWIN__) && !defined(__BEOS__) && !defined(__HAIKU__) && !defined(__MORPHOS__)) || defined(__QNXNTO__) typedef unsigned int uint; #endif #if defined(TROUBLED_INTS) /* NDS'/BeOS'/Haiku's types for uint32/int32 are based on longs, which causes * trouble all over the place in OpenTTD. */ #define uint32 uint32_ugly_hack #define int32 int32_ugly_hack typedef unsigned int uint32_ugly_hack; typedef signed int int32_ugly_hack; #else typedef unsigned char uint8; typedef signed char int8; typedef unsigned short uint16; typedef signed short int16; typedef unsigned int uint32; typedef signed int int32; typedef unsigned __int64 uint64; typedef signed __int64 int64; #endif /* !TROUBLED_INTS */ #if !defined(WITH_PERSONAL_DIR) #define PERSONAL_DIR "" #endif /* Compile time assertions. Prefer c++0x static_assert(). * Older compilers cannot evaluate some expressions at compile time, * typically when templates are involved, try assert_tcompile() in those cases. */ #if defined(__STDCXX_VERSION__) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(static_assert) /* __STDCXX_VERSION__ is c++0x feature macro, __GXX_EXPERIMENTAL_CXX0X__ is used by gcc, __GXX_EXPERIMENTAL_CPP0X__ by icc */ #define assert_compile(expr) static_assert(expr, #expr ) #define assert_tcompile(expr) assert_compile(expr) #elif defined(__OS2__) /* Disabled for OS/2 */ #define assert_compile(expr) #define assert_tcompile(expr) assert_compile(expr) #else #define assert_compile(expr) typedef int __ct_assert__[1 - 2 * !(expr)] #define assert_tcompile(expr) assert(expr) #endif /* Check if the types have the bitsizes like we are using them */ assert_compile(sizeof(uint64) == 8); assert_compile(sizeof(uint32) == 4); assert_compile(sizeof(uint16) == 2); assert_compile(sizeof(uint8) == 1); assert_compile(SIZE_MAX >= UINT32_MAX); #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 #define M_PI 3.14159265358979323846 #endif /* M_PI_2 */ /** * Return the length of an fixed size array. * Unlike sizeof this function returns the number of elements * of the given type. * * @param x The pointer to the first element of the array * @return The number of elements */ #define lengthof(x) (sizeof(x) / sizeof(x[0])) /** * Get the end element of an fixed size array. * * @param x The pointer to the first element of the array * @return The pointer past to the last element of the array */ #define endof(x) (&x[lengthof(x)]) /** * Get the last element of an fixed size array. * * @param x The pointer to the first element of the array * @return The pointer to the last element of the array */ #define lastof(x) (&x[lengthof(x) - 1]) #define cpp_offsetof(s, m) (((size_t)&reinterpret_cast((((s*)(char*)8)->m))) - 8) #if !defined(offsetof) #define offsetof(s, m) cpp_offsetof(s, m) #endif /* offsetof */ /** * Gets the size of a variable within a class. * @param base The class the variable is in. * @param variable The variable to get the size of. * @return the size of the variable */ #define cpp_sizeof(base, variable) (sizeof(((base*)8)->variable)) /** * Gets the length of an array variable within a class. * @param base The class the variable is in. * @param variable The array variable to get the size of. * @return the length of the array */ #define cpp_lengthof(base, variable) (cpp_sizeof(base, variable) / cpp_sizeof(base, variable[0])) /* take care of some name clashes on MacOS */ #if defined(__APPLE__) #define GetString OTTD_GetString #define DrawString OTTD_DrawString #define CloseConnection OTTD_CloseConnection #endif /* __APPLE__ */ void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2); void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); #define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__) /* For non-debug builds with assertions enabled use the special assertion handler: * - For MSVC: NDEBUG is set for all release builds and WITH_ASSERT overrides the disabling of asserts. * - For non MSVC: NDEBUG is set when assertions are disables, _DEBUG is set for non-release builds. */ #if (defined(_MSC_VER) && defined(NDEBUG) && defined(WITH_ASSERT)) || (!defined(_MSC_VER) && !defined(NDEBUG) && !defined(_DEBUG)) #undef assert #define assert(expression) if (!(expression)) error("Assertion failed at line %i of %s: %s", __LINE__, __FILE__, #expression); #endif /* Asserts are enabled if NDEBUG isn't defined, or if we are using MSVC and WITH_ASSERT is defined. */ #if !defined(NDEBUG) || (defined(_MSC_VER) && defined(WITH_ASSERT)) #define OTTD_ASSERT #endif #if defined(MORPHOS) || defined(__NDS__) || defined(__DJGPP__) /* MorphOS and NDS don't have C++ conformant _stricmp... */ #define _stricmp stricmp #elif defined(OPENBSD) /* OpenBSD uses strcasecmp(3) */ #define _stricmp strcasecmp #endif #if defined(MAX_PATH) /* It's already defined, no need to override */ #elif defined(PATH_MAX) && PATH_MAX > 0 /* Use the value from PATH_MAX, if it exists */ #define MAX_PATH PATH_MAX #else /* If all else fails, hardcode something :( */ #define MAX_PATH 260 #endif /** * Version of the standard free that accepts const pointers. * @param ptr The data to free. */ static inline void free(const void *ptr) { free(const_cast(ptr)); } /** * The largest value that can be entered in a variable * @param type the type of the variable */ #define MAX_UVALUE(type) ((type)~(type)0) #if defined(_MSC_VER) && !defined(_DEBUG) #define IGNORE_UNINITIALIZED_WARNING_START __pragma(warning(push)) __pragma(warning(disable:4700)) #define IGNORE_UNINITIALIZED_WARNING_STOP __pragma(warning(pop)) #elif defined(__GNUC__) && !defined(_DEBUG) #define HELPER0(x) #x #define HELPER1(x) HELPER0(GCC diagnostic ignored x) #define HELPER2(y) HELPER1(#y) #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) #define IGNORE_UNINITIALIZED_WARNING_START \ _Pragma("GCC diagnostic push") \ _Pragma(HELPER2(-Wuninitialized)) \ _Pragma(HELPER2(-Wmaybe-uninitialized)) #define IGNORE_UNINITIALIZED_WARNING_STOP _Pragma("GCC diagnostic pop") #endif #endif #ifndef IGNORE_UNINITIALIZED_WARNING_START #define IGNORE_UNINITIALIZED_WARNING_START #define IGNORE_UNINITIALIZED_WARNING_STOP #endif #endif /* STDAFX_H */ openttd-1.5.3/src/window_func.h0000644000000000000000000000423312627373441015170 0ustar rootroot/* $Id: window_func.h 25681 2013-08-05 20:37:14Z michi_cc $ */ /* * 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 window_func.h %Window functions not directly related to making/drawing windows. */ #ifndef WINDOW_FUNC_H #define WINDOW_FUNC_H #include "window_type.h" #include "company_type.h" #include "core/geometry_type.hpp" Window *FindWindowById(WindowClass cls, WindowNumber number); Window *FindWindowByClass(WindowClass cls); void ChangeWindowOwner(Owner old_owner, Owner new_owner); void ResizeWindow(Window *w, int x, int y, bool clamp_to_screen = true); int PositionMainToolbar(Window *w); int PositionStatusbar(Window *w); int PositionNewsMessage(Window *w); int PositionNetworkChatWindow(Window *w); int GetMainViewTop(); int GetMainViewBottom(); void InitWindowSystem(); void UnInitWindowSystem(); void ResetWindowSystem(); void SetupColoursAndInitialWindow(); void InputLoop(); void InvalidateWindowData(WindowClass cls, WindowNumber number, int data = 0, bool gui_scope = false); void InvalidateWindowClassesData(WindowClass cls, int data = 0, bool gui_scope = false); void DeleteNonVitalWindows(); void DeleteAllNonVitalWindows(); void DeleteConstructionWindows(); void HideVitalWindows(); void ShowVitalWindows(); void ReInitAllWindows(); void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index); void SetWindowDirty(WindowClass cls, WindowNumber number); void SetWindowClassesDirty(WindowClass cls); void DeleteWindowById(WindowClass cls, WindowNumber number, bool force = true); void DeleteWindowByClass(WindowClass cls); bool EditBoxInGlobalFocus(); Point GetCaretPosition(); #endif /* WINDOW_FUNC_H */ openttd-1.5.3/src/cpu.cpp0000644000000000000000000001112112627373442013763 0ustar rootroot/* $Id: cpu.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cpu.cpp OS/CPU/compiler dependent CPU specific calls. */ #include "stdafx.h" #include "core/bitmath_func.hpp" #include "safeguards.h" #undef RDTSC_AVAILABLE /* rdtsc for MSC_VER, uses simple inline assembly, or _rdtsc * from external win64.asm because VS2005 does not support inline assembly */ #if defined(_MSC_VER) && !defined(RDTSC_AVAILABLE) && !defined(WINCE) #include uint64 ottd_rdtsc() { return __rdtsc(); } #define RDTSC_AVAILABLE #endif /* rdtsc for OS/2. Hopefully this works, who knows */ #if defined (__WATCOMC__) && !defined(RDTSC_AVAILABLE) unsigned __int64 ottd_rdtsc(); # pragma aux ottd_rdtsc = 0x0F 0x31 value [edx eax] parm nomemory modify exact [edx eax] nomemory; # define RDTSC_AVAILABLE #endif /* rdtsc for all other *nix-en (hopefully). Use GCC syntax */ #if (defined(__i386__) || defined(__x86_64__)) && !defined(__DJGPP__) && !defined(RDTSC_AVAILABLE) uint64 ottd_rdtsc() { uint32 high, low; __asm__ __volatile__ ("rdtsc" : "=a" (low), "=d" (high)); return ((uint64)high << 32) | low; } # define RDTSC_AVAILABLE #endif /* rdtsc for PPC which has this not */ #if (defined(__POWERPC__) || defined(__powerpc__)) && !defined(RDTSC_AVAILABLE) uint64 ottd_rdtsc() { uint32 high = 0, high2 = 0, low; /* PPC does not have rdtsc, so we cheat by reading the two 32-bit time-counters * it has, 'Move From Time Base (Upper)'. Since these are two reads, in the * very unlikely event that the lower part overflows to the upper part while we * read it; we double-check and reread the registers */ asm volatile ( "mftbu %0\n" "mftb %1\n" "mftbu %2\n" "cmpw %3,%4\n" "bne- $-16\n" : "=r" (high), "=r" (low), "=r" (high2) : "0" (high), "2" (high2) ); return ((uint64)high << 32) | low; } # define RDTSC_AVAILABLE #endif /* In all other cases we have no support for rdtsc. No major issue, * you just won't be able to profile your code with TIC()/TOC() */ #if !defined(RDTSC_AVAILABLE) /* MSVC (in case of WinCE) can't handle #warning */ # if !defined(_MSC_VER) #warning "(non-fatal) No support for rdtsc(), you won't be able to profile with TIC/TOC" # endif uint64 ottd_rdtsc() {return 0;} #endif /** * Definitions for CPU detection: * * MSVC offers cpu information while gcc only implements in gcc 4.8 * __builtin_cpu_supports and friends * http://msdn.microsoft.com/library/vstudio/hskdteyh%28v=vs.100%29.aspx * http://gcc.gnu.org/onlinedocs/gcc/X86-Built-in-Functions.html * * Other platforms/architectures don't have CPUID, so zero the info and then * most (if not all) of the features are set as if they do not exist. */ #if defined(_MSC_VER) void ottd_cpuid(int info[4], int type) { __cpuid(info, type); } #elif defined(__x86_64__) || defined(__i386) void ottd_cpuid(int info[4], int type) { #if defined(__i386) && defined(__PIC__) /* The easy variant would be just cpuid, however... ebx is being used by the GOT (Global Offset Table) * in case of PIC; * clobbering ebx is no alternative: some compiler versions don't like this * and will issue an error message like * "can't find a register in class 'BREG' while reloading 'asm'" */ __asm__ __volatile__ ( "xchgl %%ebx, %1 \n\t" "cpuid \n\t" "xchgl %%ebx, %1 \n\t" : "=a" (info[0]), "=r" (info[1]), "=c" (info[2]), "=d" (info[3]) /* It is safe to write "=r" for (info[1]) as in case that PIC is enabled for i386, * the compiler will not choose EBX as target register (but something else). */ : "a" (type) ); #else __asm__ __volatile__ ( "cpuid \n\t" : "=a" (info[0]), "=b" (info[1]), "=c" (info[2]), "=d" (info[3]) : "a" (type) ); #endif /* i386 PIC */ } #else void ottd_cpuid(int info[4], int type) { info[0] = info[1] = info[2] = info[3] = 0; } #endif bool HasCPUIDFlag(uint type, uint index, uint bit) { int cpu_info[4] = {-1}; ottd_cpuid(cpu_info, 0); uint max_info_type = cpu_info[0]; if (max_info_type < type) return false; ottd_cpuid(cpu_info, type); return HasBit(cpu_info[index], bit); } openttd-1.5.3/src/console_func.h0000644000000000000000000000256212627373442015327 0ustar rootroot/* $Id: console_func.h 21707 2011-01-03 20:54:20Z rubidium $ */ /* * 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 console_func.h Console functions used outside of the console code. */ #ifndef CONSOLE_FUNC_H #define CONSOLE_FUNC_H #include "console_type.h" /* console modes */ extern IConsoleModes _iconsole_mode; /* console functions */ void IConsoleInit(); void IConsoleFree(); void IConsoleClose(); /* console output */ void IConsolePrint(TextColour colour_code, const char *string); void CDECL IConsolePrintF(TextColour colour_code, const char *format, ...) WARN_FORMAT(2, 3); void IConsoleDebug(const char *dbg, const char *string); void IConsoleWarning(const char *string); void IConsoleError(const char *string); /* Parser */ void IConsoleCmdExec(const char *cmdstr); bool IsValidConsoleColour(TextColour c); #endif /* CONSOLE_FUNC_H */ openttd-1.5.3/src/newgrf.h0000644000000000000000000001425512627373442014144 0ustar rootroot/* $Id: newgrf.h 27214 2015-03-31 18:45:30Z frosch $ */ /* * 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 newgrf.h Base for the NewGRF implementation. */ #ifndef NEWGRF_H #define NEWGRF_H #include "cargotype.h" #include "rail_type.h" #include "fileio_type.h" #include "core/bitmath_func.hpp" #include "core/alloc_type.hpp" #include "core/smallvec_type.hpp" /** * List of different canal 'features'. * Each feature gets an entry in the canal spritegroup table */ enum CanalFeature { CF_WATERSLOPE, CF_LOCKS, CF_DIKES, CF_ICON, CF_DOCKS, CF_RIVER_SLOPE, CF_RIVER_EDGE, CF_RIVER_GUI, CF_BUOY, CF_END, }; /** Canal properties local to the NewGRF */ struct CanalProperties { uint8 callback_mask; ///< Bitmask of canal callbacks that have to be called. uint8 flags; ///< Flags controlling display. }; enum GrfLoadingStage { GLS_FILESCAN, GLS_SAFETYSCAN, GLS_LABELSCAN, GLS_INIT, GLS_RESERVE, GLS_ACTIVATION, GLS_END, }; DECLARE_POSTFIX_INCREMENT(GrfLoadingStage) enum GrfMiscBit { GMB_DESERT_TREES_FIELDS = 0, // Unsupported. GMB_DESERT_PAVED_ROADS = 1, GMB_FIELD_BOUNDING_BOX = 2, // Unsupported. GMB_TRAIN_WIDTH_32_PIXELS = 3, ///< Use 32 pixels per train vehicle in depot gui and vehicle details. Never set in the global variable; @see GRFFile::traininfo_vehicle_width GMB_AMBIENT_SOUND_CALLBACK = 4, GMB_CATENARY_ON_3RD_TRACK = 5, // Unsupported. GMB_SECOND_ROCKY_TILE_SET = 6, }; enum GrfSpecFeature { GSF_TRAINS, GSF_ROADVEHICLES, GSF_SHIPS, GSF_AIRCRAFT, GSF_STATIONS, GSF_CANALS, GSF_BRIDGES, GSF_HOUSES, GSF_GLOBALVAR, GSF_INDUSTRYTILES, GSF_INDUSTRIES, GSF_CARGOES, GSF_SOUNDFX, GSF_AIRPORTS, GSF_SIGNALS, GSF_OBJECTS, GSF_RAILTYPES, GSF_AIRPORTTILES, GSF_END, GSF_FAKE_TOWNS = GSF_END, ///< Fake town GrfSpecFeature for NewGRF debugging (parent scope) GSF_FAKE_END, ///< End of the fake features GSF_INVALID = 0xFF, ///< An invalid spec feature }; static const uint32 INVALID_GRFID = 0xFFFFFFFF; struct GRFLabel { byte label; uint32 nfo_line; size_t pos; struct GRFLabel *next; }; /** Dynamic data of a loaded NewGRF */ struct GRFFile : ZeroedMemoryAllocator { char *filename; bool is_ottdfile; uint32 grfid; byte grf_version; uint sound_offset; uint16 num_sounds; struct StationSpec **stations; struct HouseSpec **housespec; struct IndustrySpec **industryspec; struct IndustryTileSpec **indtspec; struct ObjectSpec **objectspec; struct AirportSpec **airportspec; struct AirportTileSpec **airtspec; uint32 param[0x80]; uint param_end; ///< one more than the highest set parameter GRFLabel *label; ///< Pointer to the first label. This is a linked list, not an array. SmallVector cargo_list; ///< Cargo translation table (local ID -> label) uint8 cargo_map[NUM_CARGO]; ///< Inverse cargo translation table (CargoID -> local ID) SmallVector railtype_list; ///< Railtype translation table RailTypeByte railtype_map[RAILTYPE_END]; CanalProperties canal_local_properties[CF_END]; ///< Canal properties as set by this NewGRF struct LanguageMap *language_map; ///< Mappings related to the languages. int traininfo_vehicle_pitch; ///< Vertical offset for draing train images in depot GUI and vehicle details uint traininfo_vehicle_width; ///< Width (in pixels) of a 8/8 train vehicle in depot GUI and vehicle details uint32 grf_features; ///< Bitset of GrfSpecFeature the grf uses PriceMultipliers price_base_multipliers; ///< Price base multipliers as set by the grf. GRFFile(const struct GRFConfig *config); ~GRFFile(); /** Get GRF Parameter with range checking */ uint32 GetParam(uint number) const { /* Note: We implicitly test for number < lengthof(this->param) and return 0 for invalid parameters. * In fact this is the more important test, as param is zeroed anyway. */ assert(this->param_end <= lengthof(this->param)); return (number < this->param_end) ? this->param[number] : 0; } }; enum ShoreReplacement { SHORE_REPLACE_NONE, ///< No shore sprites were replaced. SHORE_REPLACE_ACTION_5, ///< Shore sprites were replaced by Action5. SHORE_REPLACE_ACTION_A, ///< Shore sprites were replaced by ActionA (using grass tiles for the corner-shores). SHORE_REPLACE_ONLY_NEW, ///< Only corner-shores were loaded by Action5 (openttd(w/d).grf only). }; struct GRFLoadedFeatures { bool has_2CC; ///< Set if any vehicle is loaded which uses 2cc (two company colours). uint64 used_liveries; ///< Bitmask of #LiveryScheme used by the defined engines. bool has_newhouses; ///< Set if there are any newhouses loaded. bool has_newindustries; ///< Set if there are any newindustries loaded. ShoreReplacement shore; ///< It which way shore sprites were replaced. }; /** * Check for grf miscellaneous bits * @param bit The bit to check. * @return Whether the bit is set. */ static inline bool HasGrfMiscBit(GrfMiscBit bit) { extern byte _misc_grf_features; return HasBit(_misc_grf_features, bit); } /* Indicates which are the newgrf features currently loaded ingame */ extern GRFLoadedFeatures _loaded_newgrf_features; byte GetGRFContainerVersion(); void LoadNewGRFFile(struct GRFConfig *config, uint file_index, GrfLoadingStage stage, Subdirectory subdir); void LoadNewGRF(uint load_index, uint file_index); void ReloadNewGRFData(); // in saveload/afterload.cpp void ResetNewGRFData(); void ResetPersistentNewGRFData(); void CDECL grfmsg(int severity, const char *str, ...) WARN_FORMAT(2, 3); bool GetGlobalVariable(byte param, uint32 *value, const GRFFile *grffile); StringID MapGRFStringID(uint32 grfid, StringID str); void ShowNewGRFError(); #endif /* NEWGRF_H */ openttd-1.5.3/src/gamelog.h0000644000000000000000000000456112627373435014270 0ustar rootroot/* $Id: gamelog.h 23901 2012-02-05 15:51:13Z smatz $ */ /* * 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 gamelog.h Functions to be called to log possibly unsafe game events */ #ifndef GAMELOG_H #define GAMELOG_H #include "newgrf_config.h" /** The actions we log. */ enum GamelogActionType { GLAT_START, ///< Game created GLAT_LOAD, ///< Game loaded GLAT_GRF, ///< GRF changed GLAT_CHEAT, ///< Cheat was used GLAT_SETTING, ///< Setting changed GLAT_GRFBUG, ///< GRF bug was triggered GLAT_EMERGENCY, ///< Emergency savegame GLAT_END, ///< So we know how many GLATs are there GLAT_NONE = 0xFF, ///< No logging active; in savegames, end of list }; void GamelogStartAction(GamelogActionType at); void GamelogStopAction(); void GamelogFree(struct LoggedAction *gamelog_action, uint gamelog_actions); void GamelogReset(); /** * Callback for printing text. * @param s The string to print. */ typedef void GamelogPrintProc(const char *s); void GamelogPrint(GamelogPrintProc *proc); // needed for WIN32 / WINCE crash.log void GamelogPrintDebug(int level); void GamelogPrintConsole(); void GamelogEmergency(); bool GamelogTestEmergency(); void GamelogRevision(); void GamelogMode(); void GamelogOldver(); void GamelogSetting(const char *name, int32 oldval, int32 newval); void GamelogGRFUpdate(const GRFConfig *oldg, const GRFConfig *newg); void GamelogGRFAddList(const GRFConfig *newg); void GamelogGRFRemove(uint32 grfid); void GamelogGRFAdd(const GRFConfig *newg); void GamelogGRFCompatible(const GRFIdentifier *newg); void GamelogTestRevision(); void GamelogTestMode(); bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id); void GamelogInfo(struct LoggedAction *gamelog_action, uint gamelog_actions, uint32 *last_ottd_rev, byte *ever_modified, bool *removed_newgrfs); #endif /* GAMELOG_H */ openttd-1.5.3/src/spritecache.h0000644000000000000000000000407312627373442015143 0ustar rootroot/* $Id: spritecache.h 23887 2012-02-04 13:29:04Z michi_cc $ */ /* * 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 spritecache.h Functions to cache sprites in memory. */ #ifndef SPRITECACHE_H #define SPRITECACHE_H #include "gfx_type.h" /** Data structure describing a sprite. */ struct Sprite { uint16 height; ///< Height of the sprite. uint16 width; ///< Width of the sprite. int16 x_offs; ///< Number of pixels to shift the sprite to the right. int16 y_offs; ///< Number of pixels to shift the sprite downwards. byte data[]; ///< Sprite data. }; extern uint _sprite_cache_size; typedef void *AllocatorProc(size_t size); void *GetRawSprite(SpriteID sprite, SpriteType type, AllocatorProc *allocator = NULL); bool SpriteExists(SpriteID sprite); SpriteType GetSpriteType(SpriteID sprite); uint GetOriginFileSlot(SpriteID sprite); uint GetMaxSpriteID(); static inline const Sprite *GetSprite(SpriteID sprite, SpriteType type) { assert(type != ST_RECOLOUR); return (Sprite*)GetRawSprite(sprite, type); } static inline const byte *GetNonSprite(SpriteID sprite, SpriteType type) { assert(type == ST_RECOLOUR); return (byte*)GetRawSprite(sprite, type); } void GfxInitSpriteMem(); void GfxClearSpriteCache(); void IncreaseSpriteLRU(); void ReadGRFSpriteOffsets(byte container_version); size_t GetGRFSpriteOffset(uint32 id); bool LoadNextSprite(int load_index, byte file_index, uint file_sprite_id, byte container_version); bool SkipSpriteData(byte type, uint16 num); void DupSprite(SpriteID old_spr, SpriteID new_spr); #endif /* SPRITECACHE_H */ openttd-1.5.3/src/map_type.h0000644000000000000000000000627412627373441014473 0ustar rootroot/* $Id: map_type.h 27132 2015-02-01 12:25:51Z frosch $ */ /* * 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 map_type.h Types related to maps. */ #ifndef MAP_TYPE_H #define MAP_TYPE_H /** * Data that is stored per tile. Also used TileExtended for this. * Look at docs/landscape.html for the exact meaning of the members. */ struct Tile { byte type; ///< The type (bits 4..7), bridges (2..3), rainforest/desert (0..1) byte height; ///< The height of the northern corner. uint16 m2; ///< Primarily used for indices to towns, industries and stations byte m1; ///< Primarily used for ownership information byte m3; ///< General purpose byte m4; ///< General purpose byte m5; ///< General purpose }; assert_compile(sizeof(Tile) == 8); /** * Data that is stored per tile. Also used Tile for this. * Look at docs/landscape.html for the exact meaning of the members. */ struct TileExtended { byte m6; ///< General purpose byte m7; ///< Primarily used for newgrf support }; /** * An offset value between to tiles. * * This value is used for the difference between * to tiles. It can be added to a tileindex to get * the resulting tileindex of the start tile applied * with this saved difference. * * @see TileDiffXY(int, int) */ typedef int32 TileIndexDiff; /** * A pair-construct of a TileIndexDiff. * * This can be used to save the difference between to * tiles as a pair of x and y value. */ struct TileIndexDiffC { int16 x; ///< The x value of the coordinate int16 y; ///< The y value of the coordinate }; /** Minimal and maximal map width and height */ static const uint MIN_MAP_SIZE_BITS = 6; ///< Minimal size of map is equal to 2 ^ MIN_MAP_SIZE_BITS static const uint MAX_MAP_SIZE_BITS = 12; ///< Maximal size of map is equal to 2 ^ MAX_MAP_SIZE_BITS static const uint MIN_MAP_SIZE = 1 << MIN_MAP_SIZE_BITS; ///< Minimal map size = 64 static const uint MAX_MAP_SIZE = 1 << MAX_MAP_SIZE_BITS; ///< Maximal map size = 4096 /** * Approximation of the length of a straight track, relative to a diagonal * track (ie the size of a tile side). * * #defined instead of const so it can * stay integer. (no runtime float operations) Is this needed? * Watch out! There are _no_ brackets around here, to prevent intermediate * rounding! Be careful when using this! * This value should be sqrt(2)/2 ~ 0.7071 */ #define STRAIGHT_TRACK_LENGTH 7071/10000 /** Argument for CmdLevelLand describing what to do. */ enum LevelMode { LM_LEVEL, ///< Level the land. LM_LOWER, ///< Lower the land. LM_RAISE, ///< Raise the land. }; #endif /* MAP_TYPE_H */ openttd-1.5.3/src/cheat_gui.cpp0000644000000000000000000003432212627373435015136 0ustar rootroot/* $Id: cheat_gui.cpp 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 cheat_gui.cpp GUI related to cheating. */ #include "stdafx.h" #include "command_func.h" #include "cheat_type.h" #include "company_base.h" #include "company_func.h" #include "date_func.h" #include "saveload/saveload.h" #include "textbuf_gui.h" #include "window_gui.h" #include "string_func.h" #include "strings_func.h" #include "window_func.h" #include "rail_gui.h" #include "settings_gui.h" #include "company_gui.h" #include "linkgraph/linkgraphschedule.h" #include "map_func.h" #include "tile_map.h" #include "newgrf.h" #include "error.h" #include "widgets/cheat_widget.h" #include "table/sprites.h" #include "safeguards.h" /** * The 'amount' to cheat with. * This variable is semantically a constant value, but because the cheat * code requires to be able to write to the variable it is not constified. */ static int32 _money_cheat_amount = 10000000; /** * Handle cheating of money. * Note that the amount of money of a company must be changed through a command * rather than by setting a variable. Since the cheat data structure expects a * variable, the amount of given/taken money is used for this purpose. * @param p1 not used. * @param p2 is -1 or +1 (down/up) * @return Amount of money cheat. */ static int32 ClickMoneyCheat(int32 p1, int32 p2) { DoCommandP(0, (uint32)(p2 * _money_cheat_amount), 0, CMD_MONEY_CHEAT); return _money_cheat_amount; } /** * Handle changing of company. * @param p1 company to set to * @param p2 is -1 or +1 (down/up) * @return The new company. */ static int32 ClickChangeCompanyCheat(int32 p1, int32 p2) { while ((uint)p1 < Company::GetPoolSize()) { if (Company::IsValidID((CompanyID)p1)) { SetLocalCompany((CompanyID)p1); return _local_company; } p1 += p2; } return _local_company; } /** * Allow (or disallow) changing production of all industries. * @param p1 new value * @param p2 unused * @return New value allowing change of industry production. */ static int32 ClickSetProdCheat(int32 p1, int32 p2) { _cheats.setup_prod.value = (p1 != 0); InvalidateWindowClassesData(WC_INDUSTRY_VIEW); return _cheats.setup_prod.value; } extern void EnginesMonthlyLoop(); /** * Handle changing of the current year. * @param p1 Unused. * @param p2 +1 (increase) or -1 (decrease). * @return New year. */ static int32 ClickChangeDateCheat(int32 p1, int32 p2) { YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); p1 = Clamp(p1, MIN_YEAR, MAX_YEAR); if (p1 == _cur_year) return _cur_year; Date new_date = ConvertYMDToDate(p1, ymd.month, ymd.day); LinkGraphSchedule::instance.ShiftDates(new_date - _date); SetDate(new_date, _date_fract); EnginesMonthlyLoop(); SetWindowDirty(WC_STATUS_BAR, 0); InvalidateWindowClassesData(WC_BUILD_STATION, 0); InvalidateWindowClassesData(WC_BUILD_OBJECT, 0); ResetSignalVariant(); return _cur_year; } /** * Allow (or disallow) a change of the maximum allowed heightlevel. * @param p1 new value * @param p2 unused * @return New value (or unchanged old value) of the maximum * allowed heightlevel value. */ static int32 ClickChangeMaxHlCheat(int32 p1, int32 p2) { p1 = Clamp(p1, MIN_MAX_HEIGHTLEVEL, MAX_MAX_HEIGHTLEVEL); /* Check if at least one mountain on the map is higher than the new value. * If yes, disallow the change. */ for (TileIndex t = 0; t < MapSize(); t++) { if ((int32)TileHeight(t) > p1) { ShowErrorMessage(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN, INVALID_STRING_ID, WL_ERROR); /* Return old, unchanged value */ return _settings_game.construction.max_heightlevel; } } /* Execute the change and reload GRF Data */ _settings_game.construction.max_heightlevel = p1; ReloadNewGRFData(); /* The smallmap uses an index from heightlevels to colours. Trigger rebuilding it. */ InvalidateWindowClassesData(WC_SMALLMAP, 2); return _settings_game.construction.max_heightlevel; } /** Available cheats. */ enum CheatNumbers { CHT_MONEY, ///< Change amount of money. CHT_CHANGE_COMPANY, ///< Switch company. CHT_EXTRA_DYNAMITE, ///< Dynamite anything. CHT_CROSSINGTUNNELS, ///< Allow tunnels to cross each other. CHT_NO_JETCRASH, ///< Disable jet-airplane crashes. CHT_SETUP_PROD, ///< Allow manually editing of industry production. CHT_EDIT_MAX_HL, ///< Edit maximum allowed heightlevel CHT_CHANGE_DATE, ///< Do time traveling. CHT_NUM_CHEATS, ///< Number of cheats. }; /** * Signature of handler function when user clicks at a cheat. * @param p1 The new value. * @param p2 Change direction (+1, +1), \c 0 for boolean settings. */ typedef int32 CheckButtonClick(int32 p1, int32 p2); /** Information of a cheat. */ struct CheatEntry { VarType type; ///< type of selector StringID str; ///< string with descriptive text void *variable; ///< pointer to the variable bool *been_used; ///< has this cheat been used before? CheckButtonClick *proc;///< procedure }; /** * The available cheats. * Order matches with the values of #CheatNumbers */ static const CheatEntry _cheats_ui[] = { {SLE_INT32, STR_CHEAT_MONEY, &_money_cheat_amount, &_cheats.money.been_used, &ClickMoneyCheat }, {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 }, {SLE_BOOL, STR_CHEAT_NO_JETCRASH, &_cheats.no_jetcrash.value, &_cheats.no_jetcrash.been_used, NULL }, {SLE_BOOL, STR_CHEAT_SETUP_PROD, &_cheats.setup_prod.value, &_cheats.setup_prod.been_used, &ClickSetProdCheat }, {SLE_UINT8, STR_CHEAT_EDIT_MAX_HL, &_settings_game.construction.max_heightlevel, &_cheats.edit_max_hl.been_used, &ClickChangeMaxHlCheat }, {SLE_INT32, STR_CHEAT_CHANGE_DATE, &_cur_year, &_cheats.change_date.been_used, &ClickChangeDateCheat }, }; assert_compile(CHT_NUM_CHEATS == lengthof(_cheats_ui)); /** Widget definitions of the cheat GUI. */ static const NWidgetPart _nested_cheat_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CHEATS, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_C_PANEL), SetDataTip(0x0, STR_CHEATS_TOOLTIP), EndContainer(), }; /** GUI for the cheats. */ struct CheatWindow : Window { int clicked; int header_height; int clicked_widget; uint line_height; int box_width; CheatWindow(WindowDesc *desc) : Window(desc) { this->box_width = GetSpriteSize(SPR_BOX_EMPTY).width; this->InitNested(); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_C_PANEL) return; int y = r.top + WD_FRAMERECT_TOP + this->header_height; DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, y, STR_CHEATS_WARNING, TC_FROMSTRING, SA_CENTER); bool rtl = _current_text_dir == TD_RTL; uint box_left = rtl ? r.right - this->box_width - 5 : r.left + 5; uint button_left = rtl ? r.right - this->box_width - 10 - SETTING_BUTTON_WIDTH : r.left + this->box_width + 10; uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : 20 + this->box_width + SETTING_BUTTON_WIDTH); uint text_right = r.right - (rtl ? 20 + this->box_width + SETTING_BUTTON_WIDTH : WD_FRAMERECT_RIGHT); int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; int icon_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2; for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, box_left, y + icon_y_offset + 2); switch (ce->type) { case SLE_BOOL: { bool on = (*(bool*)ce->variable); DrawBoolButton(button_left, y + icon_y_offset, on, true); SetDParam(0, on ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); break; } default: { int32 val = (int32)ReadValue(ce->variable, ce->type); char buf[512]; /* Draw [<][>] boxes for settings of an integer-type */ DrawArrowButtons(button_left, y + icon_y_offset, COLOUR_YELLOW, clicked - (i * 2), true, true); switch (ce->str) { /* Display date for change date cheat */ case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break; /* Draw coloured flag for change company cheat */ case STR_CHEAT_CHANGE_COMPANY: { SetDParam(0, val + 1); GetString(buf, STR_CHEAT_CHANGE_COMPANY, lastof(buf)); uint offset = 10 + GetStringBoundingBox(buf).width; DrawCompanyIcon(_local_company, rtl ? text_right - offset - 10 : text_left + offset, y + icon_y_offset + 2); break; } default: SetDParam(0, val); } break; } } DrawString(text_left, text_right, y + text_y_offset, ce->str); y += this->line_height; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_C_PANEL) return; uint width = 0; for (int i = 0; i != lengthof(_cheats_ui); i++) { const CheatEntry *ce = &_cheats_ui[i]; switch (ce->type) { case SLE_BOOL: SetDParam(0, STR_CONFIG_SETTING_ON); width = max(width, GetStringBoundingBox(ce->str).width); SetDParam(0, STR_CONFIG_SETTING_OFF); width = max(width, GetStringBoundingBox(ce->str).width); break; default: switch (ce->str) { /* Display date for change date cheat */ case STR_CHEAT_CHANGE_DATE: SetDParam(0, ConvertYMDToDate(MAX_YEAR, 11, 31)); width = max(width, GetStringBoundingBox(ce->str).width); break; /* Draw coloured flag for change company cheat */ case STR_CHEAT_CHANGE_COMPANY: SetDParamMaxValue(0, MAX_COMPANIES); width = max(width, GetStringBoundingBox(ce->str).width + 10 + 10); break; default: SetDParam(0, INT64_MAX); width = max(width, GetStringBoundingBox(ce->str).width); break; } break; } } this->line_height = max(GetSpriteSize(SPR_BOX_CHECKED).height, GetSpriteSize(SPR_BOX_EMPTY).height); this->line_height = max(this->line_height, SETTING_BUTTON_HEIGHT); this->line_height = max(this->line_height, FONT_HEIGHT_NORMAL) + WD_PAR_VSEP_NORMAL; size->width = width + 20 + this->box_width + SETTING_BUTTON_WIDTH /* stuff on the left */ + 10 /* extra spacing on right */; this->header_height = GetStringHeight(STR_CHEATS_WARNING, size->width - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT) + WD_PAR_VSEP_WIDE; size->height = this->header_height + WD_FRAMERECT_TOP + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_BOTTOM + this->line_height * lengthof(_cheats_ui); } virtual void OnClick(Point pt, int widget, int click_count) { const NWidgetBase *wid = this->GetWidget(WID_C_PANEL); uint btn = (pt.y - wid->pos_y - WD_FRAMERECT_TOP - this->header_height) / this->line_height; int x = pt.x - wid->pos_x; bool rtl = _current_text_dir == TD_RTL; if (rtl) x = wid->current_x - x; if (btn >= lengthof(_cheats_ui)) return; const CheatEntry *ce = &_cheats_ui[btn]; int value = (int32)ReadValue(ce->variable, ce->type); int oldvalue = value; if (btn == CHT_CHANGE_DATE && x >= 20 + this->box_width + SETTING_BUTTON_WIDTH) { /* Click at the date text directly. */ clicked_widget = CHT_CHANGE_DATE; SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_CHEAT_CHANGE_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); return; } else if (btn == CHT_EDIT_MAX_HL && x >= 20 + this->box_width + SETTING_BUTTON_WIDTH) { clicked_widget = CHT_EDIT_MAX_HL; SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); return; } /* Not clicking a button? */ if (!IsInsideMM(x, 10 + this->box_width, 10 + this->box_width + SETTING_BUTTON_WIDTH)) return; *ce->been_used = true; switch (ce->type) { case SLE_BOOL: value ^= 1; if (ce->proc != NULL) ce->proc(value, 0); break; default: /* Take whatever the function returns */ value = ce->proc(value + ((x >= 20 + SETTING_BUTTON_WIDTH / 2) ? 1 : -1), (x >= 10 + this->box_width + SETTING_BUTTON_WIDTH / 2) ? 1 : -1); /* The first cheat (money), doesn't return a different value. */ if (value != oldvalue || btn == CHT_MONEY) this->clicked = btn * 2 + 1 + ((x >= 10 + this->box_width + SETTING_BUTTON_WIDTH / 2) != rtl ? 1 : 0); break; } if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value); this->SetTimeout(); this->SetDirty(); } virtual void OnTimeout() { this->clicked = 0; this->SetDirty(); } virtual void OnQueryTextFinished(char *str) { /* Was 'cancel' pressed or nothing entered? */ if (str == NULL || StrEmpty(str)) return; const CheatEntry *ce = &_cheats_ui[clicked_widget]; int oldvalue = (int32)ReadValue(ce->variable, ce->type); int value = atoi(str); *ce->been_used = true; value = ce->proc(value, value - oldvalue); if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value); this->SetDirty(); } }; /** Window description of the cheats GUI. */ static WindowDesc _cheats_desc( WDP_AUTO, "cheats", 0, 0, WC_CHEATS, WC_NONE, 0, _nested_cheat_widgets, lengthof(_nested_cheat_widgets) ); /** Open cheat window. */ void ShowCheatWindow() { DeleteWindowById(WC_CHEATS, 0); new CheatWindow(&_cheats_desc); } openttd-1.5.3/src/language.h0000644000000000000000000001165312627373442014436 0ustar rootroot/* $Id: language.h 23585 2011-12-17 23:16:16Z rubidium $ */ /* * 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 language.h Information about languages and their files. */ #ifndef LANGUAGE_H #define LANGUAGE_H #include "core/smallvec_type.hpp" #ifdef WITH_ICU #include #endif /* WITH_ICU */ static const uint8 CASE_GENDER_LEN = 16; ///< The (maximum) length of a case/gender string. static const uint8 MAX_NUM_GENDERS = 8; ///< Maximum number of supported genders. static const uint8 MAX_NUM_CASES = 16; ///< Maximum number of supported cases. static const uint TAB_SIZE_OFFSET = 0; ///< The offset for the tab size. static const uint TAB_SIZE_BITS = 11; ///< The number of bits used for the tab size. static const uint TAB_SIZE = 1 << TAB_SIZE_BITS; ///< The number of values in a tab. static const uint TAB_COUNT_OFFSET = TAB_SIZE_BITS; ///< The offset for the tab count. static const uint TAB_COUNT_BITS = 5; ///< The number of bits used for the amount of tabs. static const uint TAB_COUNT = 1 << TAB_COUNT_BITS; ///< The amount of tabs. /** Header of a language file. */ struct LanguagePackHeader { static const uint32 IDENT = 0x474E414C; ///< Identifier for OpenTTD language files, big endian for "LANG" uint32 ident; ///< 32-bits identifier uint32 version; ///< 32-bits of auto generated version info which is basically a hash of strings.h char name[32]; ///< the international name of this language char own_name[32]; ///< the localized name of this language char isocode[16]; ///< the ISO code for the language (not country code) uint16 offsets[TAB_COUNT]; ///< the offsets /** Thousand separator used for anything not currencies */ char digit_group_separator[8]; /** Thousand separator used for currencies */ char digit_group_separator_currency[8]; /** Decimal separator */ char digit_decimal_separator[8]; uint16 missing; ///< number of missing strings. byte plural_form; ///< plural form index byte text_dir; ///< default direction of the text /** * Windows language ID: * Windows cannot and will not convert isocodes to something it can use to * determine whether a font can be used for the language or not. As a result * of that we need to pass the language id via strgen to OpenTTD to tell * what language it is in "Windows". The ID is the 'locale identifier' on: * http://msdn.microsoft.com/en-us/library/ms776294.aspx */ uint16 winlangid; ///< windows language id uint8 newgrflangid; ///< newgrf language id uint8 num_genders; ///< the number of genders of this language uint8 num_cases; ///< the number of cases of this language byte pad[3]; ///< pad header to be a multiple of 4 char genders[MAX_NUM_GENDERS][CASE_GENDER_LEN]; ///< the genders used by this translation char cases[MAX_NUM_CASES][CASE_GENDER_LEN]; ///< the cases used by this translation bool IsValid() const; /** * Get the index for the given gender. * @param gender_str The string representation of the gender. * @return The index of the gender, or MAX_NUM_GENDERS when the gender is unknown. */ uint8 GetGenderIndex(const char *gender_str) const { for (uint8 i = 0; i < MAX_NUM_GENDERS; i++) { if (strcmp(gender_str, this->genders[i]) == 0) return i; } return MAX_NUM_GENDERS; } /** * Get the index for the given case. * @param case_str The string representation of the case. * @return The index of the case, or MAX_NUM_CASES when the case is unknown. */ uint8 GetCaseIndex(const char *case_str) const { for (uint8 i = 0; i < MAX_NUM_CASES; i++) { if (strcmp(case_str, this->cases[i]) == 0) return i; } return MAX_NUM_CASES; } }; /** Make sure the size is right. */ assert_compile(sizeof(LanguagePackHeader) % 4 == 0); /** Metadata about a single language. */ struct LanguageMetadata : public LanguagePackHeader { char file[MAX_PATH]; ///< Name of the file we read this data from. }; /** Type for the list of language meta data. */ typedef SmallVector LanguageList; /** The actual list of language meta data. */ extern LanguageList _languages; /** The currently loaded language. */ extern const LanguageMetadata *_current_language; #ifdef WITH_ICU extern Collator *_current_collator; #endif /* WITH_ICU */ bool ReadLanguagePack(const LanguageMetadata *lang); const LanguageMetadata *GetLanguage(byte newgrflangid); #endif /* LANGUAGE_H */ openttd-1.5.3/src/gfx_layout.cpp0000644000000000000000000006030612627373442015366 0ustar rootroot/* $Id: gfx_layout.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 gfx_layout.cpp Handling of laying out text. */ #include "stdafx.h" #include "gfx_layout.h" #include "string_func.h" #include "strings_func.h" #include "debug.h" #include "table/control_codes.h" #ifdef WITH_ICU #include #endif /* WITH_ICU */ #include "safeguards.h" /** Cache of ParagraphLayout lines. */ Layouter::LineCache *Layouter::linecache; /** Cache of Font instances. */ Layouter::FontColourMap Layouter::fonts[FS_END]; /** * Construct a new font. * @param size The font size to use for this font. * @param colour The colour to draw this font in. */ Font::Font(FontSize size, TextColour colour) : fc(FontCache::Get(size)), colour(colour) { assert(size < FS_END); } #ifdef WITH_ICU /* Implementation details of LEFontInstance */ le_int32 Font::getUnitsPerEM() const { return this->fc->GetUnitsPerEM(); } le_int32 Font::getAscent() const { return this->fc->GetAscender(); } le_int32 Font::getDescent() const { return -this->fc->GetDescender(); } le_int32 Font::getLeading() const { return this->fc->GetHeight(); } float Font::getXPixelsPerEm() const { return (float)this->fc->GetHeight(); } float Font::getYPixelsPerEm() const { return (float)this->fc->GetHeight(); } float Font::getScaleFactorX() const { return 1.0f; } float Font::getScaleFactorY() const { return 1.0f; } const void *Font::getFontTable(LETag tableTag) const { size_t length; return this->getFontTable(tableTag, length); } const void *Font::getFontTable(LETag tableTag, size_t &length) const { return this->fc->GetFontTable(tableTag, length); } LEGlyphID Font::mapCharToGlyph(LEUnicode32 ch) const { if (IsTextDirectionChar(ch)) return 0; return this->fc->MapCharToGlyph(ch); } void Font::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const { advance.fX = glyph == 0xFFFF ? 0 : this->fc->GetGlyphWidth(glyph); advance.fY = 0; } le_bool Font::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const { return FALSE; } static size_t AppendToBuffer(UChar *buff, const UChar *buffer_last, WChar c) { /* Transform from UTF-32 to internal ICU format of UTF-16. */ int32 length = 0; UErrorCode err = U_ZERO_ERROR; u_strFromUTF32(buff, buffer_last - buff, &length, (UChar32*)&c, 1, &err); return length; } /** * Wrapper for doing layouts with ICU. */ class ICUParagraphLayout : public AutoDeleteSmallVector, public ParagraphLayouter { ParagraphLayout *p; ///< The actual ICU paragraph layout. public: /** Helper for GetLayouter, to get the right type. */ typedef UChar CharType; /** Helper for GetLayouter, to get whether the layouter supports RTL. */ static const bool SUPPORTS_RTL = true; /** Visual run contains data about the bit of text with the same font. */ class ICUVisualRun : public ParagraphLayouter::VisualRun { const ParagraphLayout::VisualRun *vr; ///< The actual ICU vr. public: ICUVisualRun(const ParagraphLayout::VisualRun *vr) : vr(vr) { } const Font *GetFont() const { return (const Font*)vr->getFont(); } int GetGlyphCount() const { return vr->getGlyphCount(); } const GlyphID *GetGlyphs() const { return vr->getGlyphs(); } const float *GetPositions() const { return vr->getPositions(); } int GetLeading() const { return vr->getLeading(); } const int *GetGlyphToCharMap() const { return vr->getGlyphToCharMap(); } }; /** A single line worth of VisualRuns. */ class ICULine : public AutoDeleteSmallVector, public ParagraphLayouter::Line { ParagraphLayout::Line *l; ///< The actual ICU line. public: ICULine(ParagraphLayout::Line *l) : l(l) { for (int i = 0; i < l->countRuns(); i++) { *this->Append() = new ICUVisualRun(l->getVisualRun(i)); } } ~ICULine() { delete l; } int GetLeading() const { return l->getLeading(); } int GetWidth() const { return l->getWidth(); } int CountRuns() const { return l->countRuns(); } const ParagraphLayouter::VisualRun *GetVisualRun(int run) const { return *this->Get(run); } int GetInternalCharLength(WChar c) const { /* ICU uses UTF-16 internally which means we need to account for surrogate pairs. */ return Utf8CharLen(c) < 4 ? 1 : 2; } }; ICUParagraphLayout(ParagraphLayout *p) : p(p) { } ~ICUParagraphLayout() { delete p; } void Reflow() { p->reflow(); } ParagraphLayouter::Line *NextLine(int max_width) { ParagraphLayout::Line *l = p->nextLine(max_width); return l == NULL ? NULL : new ICULine(l); } }; static ParagraphLayouter *GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping) { int32 length = buff_end - buff; if (length == 0) { /* ICU's ParagraphLayout cannot handle empty strings, so fake one. */ buff[0] = ' '; length = 1; fontMapping.End()[-1].first++; } /* Fill ICU's FontRuns with the right data. */ FontRuns runs(fontMapping.Length()); for (FontMap::iterator iter = fontMapping.Begin(); iter != fontMapping.End(); iter++) { runs.add(iter->second, iter->first); } LEErrorCode status = LE_NO_ERROR; /* ParagraphLayout does not copy "buff", so it must stay valid. * "runs" is copied according to the ICU source, but the documentation does not specify anything, so this might break somewhen. */ ParagraphLayout *p = new ParagraphLayout(buff, length, &runs, NULL, NULL, NULL, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, false, status); if (status != LE_NO_ERROR) { delete p; return NULL; } return new ICUParagraphLayout(p); } #endif /* WITH_ICU */ /*** Paragraph layout ***/ /** * Class handling the splitting of a paragraph of text into lines and * visual runs. * * One constructs this class with the text that needs to be split into * lines. Then nextLine is called with the maximum width until NULL is * returned. Each nextLine call creates VisualRuns which contain the * length of text that are to be drawn with the same font. In other * words, the result of this class is a list of sub strings with their * font. The sub strings are then already fully laid out, and only * need actual drawing. * * The positions in a visual run are sequential pairs of X,Y of the * begin of each of the glyphs plus an extra pair to mark the end. * * @note This variant does not handle left-to-right properly. This * is supported in the one ParagraphLayout coming from ICU. */ class FallbackParagraphLayout : public ParagraphLayouter { public: /** Helper for GetLayouter, to get the right type. */ typedef WChar CharType; /** Helper for GetLayouter, to get whether the layouter supports RTL. */ static const bool SUPPORTS_RTL = false; /** Visual run contains data about the bit of text with the same font. */ class FallbackVisualRun : public ParagraphLayouter::VisualRun { Font *font; ///< The font used to layout these. GlyphID *glyphs; ///< The glyphs we're drawing. float *positions; ///< The positions of the glyphs. int *glyph_to_char; ///< The char index of the glyphs. int glyph_count; ///< The number of glyphs. public: FallbackVisualRun(Font *font, const WChar *chars, int glyph_count, int x); ~FallbackVisualRun(); const Font *GetFont() const; int GetGlyphCount() const; const GlyphID *GetGlyphs() const; const float *GetPositions() const; int GetLeading() const; const int *GetGlyphToCharMap() const; }; /** A single line worth of VisualRuns. */ class FallbackLine : public AutoDeleteSmallVector, public ParagraphLayouter::Line { public: int GetLeading() const; int GetWidth() const; int CountRuns() const; const ParagraphLayouter::VisualRun *GetVisualRun(int run) const; int GetInternalCharLength(WChar c) const { return 1; } }; const WChar *buffer_begin; ///< Begin of the buffer. const WChar *buffer; ///< The current location in the buffer. FontMap &runs; ///< The fonts we have to use for this paragraph. FallbackParagraphLayout(WChar *buffer, int length, FontMap &runs); void Reflow(); const ParagraphLayouter::Line *NextLine(int max_width); }; /** * Create the visual run. * @param font The font to use for this run. * @param chars The characters to use for this run. * @param char_count The number of characters in this run. * @param x The initial x position for this run. */ FallbackParagraphLayout::FallbackVisualRun::FallbackVisualRun(Font *font, const WChar *chars, int char_count, int x) : font(font), glyph_count(char_count) { this->glyphs = MallocT(this->glyph_count); this->glyph_to_char = MallocT(this->glyph_count); /* Positions contains the location of the begin of each of the glyphs, and the end of the last one. */ this->positions = MallocT(this->glyph_count * 2 + 2); this->positions[0] = x; this->positions[1] = 0; for (int i = 0; i < this->glyph_count; i++) { this->glyphs[i] = font->fc->MapCharToGlyph(chars[i]); this->positions[2 * i + 2] = this->positions[2 * i] + font->fc->GetGlyphWidth(this->glyphs[i]); this->positions[2 * i + 3] = 0; this->glyph_to_char[i] = i; } } /** Free all data. */ FallbackParagraphLayout::FallbackVisualRun::~FallbackVisualRun() { free(this->positions); free(this->glyph_to_char); free(this->glyphs); } /** * Get the font associated with this run. * @return The font. */ const Font *FallbackParagraphLayout::FallbackVisualRun::GetFont() const { return this->font; } /** * Get the number of glyphs in this run. * @return The number of glyphs. */ int FallbackParagraphLayout::FallbackVisualRun::GetGlyphCount() const { return this->glyph_count; } /** * Get the glyphs of this run. * @return The glyphs. */ const GlyphID *FallbackParagraphLayout::FallbackVisualRun::GetGlyphs() const { return this->glyphs; } /** * Get the positions of this run. * @return The positions. */ const float *FallbackParagraphLayout::FallbackVisualRun::GetPositions() const { return this->positions; } /** * Get the glyph-to-character map for this visual run. * @return The glyph-to-character map. */ const int *FallbackParagraphLayout::FallbackVisualRun::GetGlyphToCharMap() const { return this->glyph_to_char; } /** * Get the height of this font. * @return The height of the font. */ int FallbackParagraphLayout::FallbackVisualRun::GetLeading() const { return this->GetFont()->fc->GetHeight(); } /** * Get the height of the line. * @return The maximum height of the line. */ int FallbackParagraphLayout::FallbackLine::GetLeading() const { int leading = 0; for (const FallbackVisualRun * const *run = this->Begin(); run != this->End(); run++) { leading = max(leading, (*run)->GetLeading()); } return leading; } /** * Get the width of this line. * @return The width of the line. */ int FallbackParagraphLayout::FallbackLine::GetWidth() const { if (this->Length() == 0) return 0; /* * The last X position of a run contains is the end of that run. * Since there is no left-to-right support, taking this value of * the last run gives us the end of the line and thus the width. */ const ParagraphLayouter::VisualRun *run = this->GetVisualRun(this->CountRuns() - 1); return (int)run->GetPositions()[run->GetGlyphCount() * 2]; } /** * Get the number of runs in this line. * @return The number of runs. */ int FallbackParagraphLayout::FallbackLine::CountRuns() const { return this->Length(); } /** * Get a specific visual run. * @return The visual run. */ const ParagraphLayouter::VisualRun *FallbackParagraphLayout::FallbackLine::GetVisualRun(int run) const { return *this->Get(run); } /** * Create a new paragraph layouter. * @param buffer The characters of the paragraph. * @param length The length of the paragraph. * @param runs The font mapping of this paragraph. */ FallbackParagraphLayout::FallbackParagraphLayout(WChar *buffer, int length, FontMap &runs) : buffer_begin(buffer), buffer(buffer), runs(runs) { assert(runs.End()[-1].first == length); } /** * Reset the position to the start of the paragraph. */ void FallbackParagraphLayout::Reflow() { this->buffer = this->buffer_begin; } /** * Construct a new line with a maximum width. * @param max_width The maximum width of the string. * @return A Line, or NULL when at the end of the paragraph. */ const ParagraphLayouter::Line *FallbackParagraphLayout::NextLine(int max_width) { /* Simple idea: * - split a line at a newline character, or at a space where we can break a line. * - split for a visual run whenever a new line happens, or the font changes. */ if (this->buffer == NULL) return NULL; FallbackLine *l = new FallbackLine(); if (*this->buffer == '\0') { /* Only a newline. */ this->buffer = NULL; *l->Append() = new FallbackVisualRun(this->runs.Begin()->second, this->buffer, 0, 0); return l; } const WChar *begin = this->buffer; const WChar *last_space = NULL; const WChar *last_char = begin; int width = 0; int offset = this->buffer - this->buffer_begin; FontMap::iterator iter = this->runs.Begin(); while (iter->first <= offset) { iter++; assert(iter != this->runs.End()); } const FontCache *fc = iter->second->fc; const WChar *next_run = this->buffer_begin + iter->first; for (;;) { WChar c = *this->buffer; last_char = this->buffer; if (c == '\0') { this->buffer = NULL; break; } if (this->buffer == next_run) { int w = l->GetWidth(); *l->Append() = new FallbackVisualRun(iter->second, begin, this->buffer - begin, w); iter++; assert(iter != this->runs.End()); next_run = this->buffer_begin + iter->first; begin = this->buffer; last_space = NULL; } if (IsWhitespace(c)) last_space = this->buffer; if (IsPrintable(c) && !IsTextDirectionChar(c)) { int char_width = GetCharacterWidth(fc->GetSize(), c); width += char_width; if (width > max_width) { /* The string is longer than maximum width so we need to decide * what to do with it. */ if (width == char_width) { /* The character is wider than allowed width; don't know * what to do with this case... bail out! */ this->buffer = NULL; return l; } if (last_space == NULL) { /* No space has been found. Just terminate at our current * location. This usually happens for languages that do not * require spaces in strings, like Chinese, Japanese and * Korean. For other languages terminating mid-word might * not be the best, but terminating the whole string instead * of continuing the word at the next line is worse. */ last_char = this->buffer; } else { /* A space is found; perfect place to terminate */ this->buffer = last_space + 1; last_char = last_space; } break; } } this->buffer++; } if (l->Length() == 0 || last_char - begin != 0) { int w = l->GetWidth(); *l->Append() = new FallbackVisualRun(iter->second, begin, last_char - begin, w); } return l; } /** * Appand a wide character to the internal buffer. * @param buff The buffer to append to. * @param buffer_last The end of the buffer. * @param c The character to add. * @return The number of buffer spaces that were used. */ static size_t AppendToBuffer(WChar *buff, const WChar *buffer_last, WChar c) { *buff = c; return 1; } /** * Get the actual ParagraphLayout for the given buffer. * @param buff The begin of the buffer. * @param buff_end The location after the last element in the buffer. * @param fontMapping THe mapping of the fonts. * @return The ParagraphLayout instance. */ static FallbackParagraphLayout *GetParagraphLayout(WChar *buff, WChar *buff_end, FontMap &fontMapping) { return new FallbackParagraphLayout(buff, buff_end - buff, fontMapping); } /** * Helper for getting a ParagraphLayouter of the given type. * * @note In case no ParagraphLayouter could be constructed, line.layout will be NULL. * @param line The cache item to store our layouter in. * @param str The string to create a layouter for. * @param state The state of the font and color. * @tparam T The type of layouter we want. */ template static inline void GetLayouter(Layouter::LineCacheItem &line, const char *&str, FontState &state) { if (line.buffer != NULL) free(line.buffer); typename T::CharType *buff_begin = MallocT(DRAW_STRING_BUFFER); const typename T::CharType *buffer_last = buff_begin + DRAW_STRING_BUFFER; typename T::CharType *buff = buff_begin; FontMap &fontMapping = line.runs; Font *f = Layouter::GetFont(state.fontsize, state.cur_colour); line.buffer = buff_begin; /* * Go through the whole string while adding Font instances to the font map * whenever the font changes, and convert the wide characters into a format * usable by ParagraphLayout. */ for (; buff < buffer_last;) { WChar c = Utf8Consume(const_cast(&str)); if (c == '\0' || c == '\n') { break; } else if (c >= SCC_BLUE && c <= SCC_BLACK) { state.SetColour((TextColour)(c - SCC_BLUE)); } else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour. state.SetPreviousColour(); } else if (c == SCC_TINYFONT) { state.SetFontSize(FS_SMALL); } else if (c == SCC_BIGFONT) { state.SetFontSize(FS_LARGE); } else { /* Filter out text direction characters that shouldn't be drawn, and * will not be handled in the fallback non ICU case because they are * mostly needed for RTL languages which need more ICU support. */ if (!T::SUPPORTS_RTL && IsTextDirectionChar(c)) continue; buff += AppendToBuffer(buff, buffer_last, c); continue; } if (!fontMapping.Contains(buff - buff_begin)) { fontMapping.Insert(buff - buff_begin, f); } f = Layouter::GetFont(state.fontsize, state.cur_colour); } /* Better safe than sorry. */ *buff = '\0'; if (!fontMapping.Contains(buff - buff_begin)) { fontMapping.Insert(buff - buff_begin, f); } line.layout = GetParagraphLayout(buff_begin, buff, fontMapping); line.state_after = state; } /** * Create a new layouter. * @param str The string to create the layout for. * @param maxw The maximum width. * @param colour The colour of the font. * @param fontsize The size of font to use. */ Layouter::Layouter(const char *str, int maxw, TextColour colour, FontSize fontsize) : string(str) { FontState state(colour, fontsize); WChar c = 0; do { /* Scan string for end of line */ const char *lineend = str; for (;;) { size_t len = Utf8Decode(&c, lineend); if (c == '\0' || c == '\n') break; lineend += len; } LineCacheItem& line = GetCachedParagraphLayout(str, lineend - str, state); if (line.layout != NULL) { /* Line is in cache */ str = lineend + 1; state = line.state_after; line.layout->Reflow(); } else { /* Line is new, layout it */ #ifdef WITH_ICU FontState old_state = state; const char *old_str = str; GetLayouter(line, str, state); if (line.layout == NULL) { static bool warned = false; if (!warned) { DEBUG(misc, 0, "ICU layouter bailed on the font. Falling back to the fallback layouter"); warned = true; } state = old_state; str = old_str; GetLayouter(line, str, state); } #else GetLayouter(line, str, state); #endif } /* Copy all lines into a local cache so we can reuse them later on more easily. */ const ParagraphLayouter::Line *l; while ((l = line.layout->NextLine(maxw)) != NULL) { *this->Append() = l; } } while (c != '\0'); } /** * Get the boundaries of this paragraph. * @return The boundaries. */ Dimension Layouter::GetBounds() { Dimension d = { 0, 0 }; for (const ParagraphLayouter::Line **l = this->Begin(); l != this->End(); l++) { d.width = max(d.width, (*l)->GetWidth()); d.height += (*l)->GetLeading(); } return d; } /** * Get the position of a character in the layout. * @param ch Character to get the position of. * @return Upper left corner of the character relative to the start of the string. * @note Will only work right for single-line strings. */ Point Layouter::GetCharPosition(const char *ch) const { /* Find the code point index which corresponds to the char * pointer into our UTF-8 source string. */ size_t index = 0; const char *str = this->string; while (str < ch) { WChar c; size_t len = Utf8Decode(&c, str); if (c == '\0' || c == '\n') break; str += len; index += (*this->Begin())->GetInternalCharLength(c); } if (str == ch) { /* Valid character. */ const ParagraphLayouter::Line *line = *this->Begin(); /* Pointer to the end-of-string/line marker? Return total line width. */ if (*ch == '\0' || *ch == '\n') { Point p = { line->GetWidth(), 0 }; return p; } /* Scan all runs until we've found our code point index. */ for (int run_index = 0; run_index < line->CountRuns(); run_index++) { const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); for (int i = 0; i < run->GetGlyphCount(); i++) { /* Matching glyph? Return position. */ if ((size_t)run->GetGlyphToCharMap()[i] == index) { Point p = { (int)run->GetPositions()[i * 2], (int)run->GetPositions()[i * 2 + 1] }; return p; } } } } Point p = { 0, 0 }; return p; } /** * Get the character that is at a position. * @param x Position in the string. * @return Pointer to the character at the position or NULL if no character is at the position. */ const char *Layouter::GetCharAtPosition(int x) const { const ParagraphLayouter::Line *line = *this->Begin(); for (int run_index = 0; run_index < line->CountRuns(); run_index++) { const ParagraphLayouter::VisualRun *run = line->GetVisualRun(run_index); for (int i = 0; i < run->GetGlyphCount(); i++) { /* Not a valid glyph (empty). */ if (run->GetGlyphs()[i] == 0xFFFF) continue; int begin_x = (int)run->GetPositions()[i * 2]; int end_x = (int)run->GetPositions()[i * 2 + 2]; if (IsInsideMM(x, begin_x, end_x)) { /* Found our glyph, now convert to UTF-8 string index. */ size_t index = run->GetGlyphToCharMap()[i]; size_t cur_idx = 0; for (const char *str = this->string; *str != '\0'; ) { if (cur_idx == index) return str; WChar c = Utf8Consume(&str); cur_idx += line->GetInternalCharLength(c); } } } } return NULL; } /** * Get a static font instance. */ Font *Layouter::GetFont(FontSize size, TextColour colour) { FontColourMap::iterator it = fonts[size].Find(colour); if (it != fonts[size].End()) return it->second; Font *f = new Font(size, colour); *fonts[size].Append() = FontColourMap::Pair(colour, f); return f; } /** * Reset cached font information. * @param size Font size to reset. */ void Layouter::ResetFontCache(FontSize size) { for (FontColourMap::iterator it = fonts[size].Begin(); it != fonts[size].End(); ++it) { delete it->second; } fonts[size].Clear(); /* We must reset the linecache since it references the just freed fonts */ ResetLineCache(); } /** * Get reference to cache item. * If the item does not exist yet, it is default constructed. * @param str Source string of the line (including colour and font size codes). * @param len Length of \a str in bytes (no termination). * @param state State of the font at the beginning of the line. * @return Reference to cache item. */ Layouter::LineCacheItem &Layouter::GetCachedParagraphLayout(const char *str, size_t len, const FontState &state) { if (linecache == NULL) { /* Create linecache on first access to avoid trouble with initialisation order of static variables. */ linecache = new LineCache(); } LineCacheKey key; key.state_before = state; key.str.assign(str, len); return (*linecache)[key]; } /** * Clear line cache. */ void Layouter::ResetLineCache() { if (linecache != NULL) linecache->clear(); } /** * Reduce the size of linecache if necessary to prevent infinite growth. */ void Layouter::ReduceLineCache() { if (linecache != NULL) { /* TODO LRU cache would be fancy, but not exactly necessary */ if (linecache->size() > 4096) ResetLineCache(); } } openttd-1.5.3/src/order_backup.cpp0000644000000000000000000002101512627373442015637 0ustar rootroot/* $Id: order_backup.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 order_backup.cpp Handling of order backups. */ #include "stdafx.h" #include "command_func.h" #include "core/pool_func.hpp" #include "network/network.h" #include "network/network_func.h" #include "order_backup.h" #include "vehicle_base.h" #include "window_func.h" #include "station_map.h" #include "safeguards.h" OrderBackupPool _order_backup_pool("BackupOrder"); INSTANTIATE_POOL_METHODS(OrderBackup) /** Free everything that is allocated. */ OrderBackup::~OrderBackup() { if (CleaningPool()) return; Order *o = this->orders; while (o != NULL) { Order *next = o->next; delete o; o = next; } } /** * Create an order backup for the given vehicle. * @param v The vehicle to make a backup of. * @param user The user that is requesting the backup. */ OrderBackup::OrderBackup(const Vehicle *v, uint32 user) { this->user = user; this->tile = v->tile; this->group = v->group_id; this->CopyConsistPropertiesFrom(v); /* If we have shared orders, store the vehicle we share the order with. */ if (v->IsOrderListShared()) { this->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared(); } else { /* Else copy the orders */ Order **tail = &this->orders; /* Count the number of orders */ const Order *order; FOR_VEHICLE_ORDERS(v, order) { Order *copy = new Order(); copy->AssignOrder(*order); *tail = copy; tail = ©->next; } } } /** * Restore the data of this order to the given vehicle. * @param v The vehicle to restore to. */ void OrderBackup::DoRestore(Vehicle *v) { /* If we had shared orders, recover that */ if (this->clone != NULL) { DoCommand(0, v->index | CO_SHARE << 30, this->clone->index, DC_EXEC, CMD_CLONE_ORDER); } else if (this->orders != NULL && OrderList::CanAllocateItem()) { v->orders.list = new OrderList(this->orders, v); this->orders = NULL; /* Make sure buoys/oil rigs are updated in the station list. */ InvalidateWindowClassesData(WC_STATION_LIST, 0); } v->CopyConsistPropertiesFrom(this); /* Make sure orders are in range */ v->UpdateRealOrderIndex(); if (v->cur_implicit_order_index >= v->GetNumOrders()) v->cur_implicit_order_index = v->cur_real_order_index; /* Restore vehicle group */ DoCommand(0, this->group, v->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP); } /** * Create an order backup for the given vehicle. * @param v The vehicle to make a backup of. * @param user The user that is requesting the backup. * @note Will automatically remove any previous backups of this user. */ /* static */ void OrderBackup::Backup(const Vehicle *v, uint32 user) { /* Don't use reset as that broadcasts over the network to reset the variable, * which is what we are doing at the moment. */ OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { if (ob->user == user) delete ob; } if (OrderBackup::CanAllocateItem()) { new OrderBackup(v, user); } } /** * Restore the data of this order to the given vehicle. * @param v The vehicle to restore to. * @param user The user that built the vehicle, thus wants to restore. * @note After restoration the backup will automatically be removed. */ /* static */ void OrderBackup::Restore(Vehicle *v, uint32 user) { OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { if (v->tile != ob->tile || ob->user != user) continue; ob->DoRestore(v); delete ob; } } /** * Reset an OrderBackup given a tile and user. * @param tile The tile associated with the OrderBackup. * @param user The user associated with the OrderBackup. * @note Must not be used from the GUI! */ /* static */ void OrderBackup::ResetOfUser(TileIndex tile, uint32 user) { OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { if (ob->user == user && (ob->tile == tile || tile == INVALID_TILE)) delete ob; } } /** * Clear an OrderBackup * @param tile Tile related to the to-be-cleared OrderBackup. * @param flags For command. * @param p1 Unused. * @param p2 User that had the OrderBackup. * @param text Unused. * @return The cost of this operation or an error. */ CommandCost CmdClearOrderBackup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* No need to check anything. If the tile or user don't exist we just ignore it. */ if (flags & DC_EXEC) OrderBackup::ResetOfUser(tile == 0 ? INVALID_TILE : tile, p2); return CommandCost(); } /** * Reset an user's OrderBackup if needed. * @param user The user associated with the OrderBackup. * @pre _network_server. * @note Must not be used from a command. */ /* static */ void OrderBackup::ResetUser(uint32 user) { assert(_network_server); OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { /* If it's not an backup of us, so ignore it. */ if (ob->user != user) continue; DoCommandP(0, 0, user, CMD_CLEAR_ORDER_BACKUP); return; } } /** * Reset the OrderBackups from GUI/game logic. * @param t The tile of the order backup. * @param from_gui Whether the call came from the GUI, i.e. whether * it must be synced over the network. */ /* static */ void OrderBackup::Reset(TileIndex t, bool from_gui) { /* The user has CLIENT_ID_SERVER as default when network play is not active, * but compiled it. A network client has its own variable for the unique * client/user identifier. Finally if networking isn't compiled in the * default is just plain and simple: 0. */ #ifdef ENABLE_NETWORK uint32 user = _networking && !_network_server ? _network_own_client_id : CLIENT_ID_SERVER; #else uint32 user = 0; #endif OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { /* If it's not an backup of us, so ignore it. */ if (ob->user != user) continue; /* If it's not for our chosen tile either, ignore it. */ if (t != INVALID_TILE && t != ob->tile) continue; if (from_gui) { /* We need to circumvent the "prevention" from this command being executed * while the game is paused, so use the internal method. Nor do we want * this command to get its cost estimated when shift is pressed. */ DoCommandPInternal(ob->tile, 0, user, CMD_CLEAR_ORDER_BACKUP, NULL, NULL, true, false); } else { /* The command came from the game logic, i.e. the clearing of a tile. * In that case we have no need to actually sync this, just do it. */ delete ob; } } } /** * Clear the group of all backups having this group ID. * @param group The group to clear. */ /* static */ void OrderBackup::ClearGroup(GroupID group) { OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { if (ob->group == group) ob->group = DEFAULT_GROUP; } } /** * Clear/update the (clone) vehicle from an order backup. * @param v The vehicle to clear. * @pre v != NULL * @note If it is not possible to set another vehicle as clone * "example", then this backed up order will be removed. */ /* static */ void OrderBackup::ClearVehicle(const Vehicle *v) { assert(v != NULL); OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { if (ob->clone == v) { /* Get another item in the shared list. */ ob->clone = (v->FirstShared() == v) ? v->NextShared() : v->FirstShared(); /* But if that isn't there, remove it. */ if (ob->clone == NULL) delete ob; } } } /** * Removes an order from all vehicles. Triggers when, say, a station is removed. * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]). * @param destination The destination. Can be a StationID, DepotID or WaypointID. */ /* static */ void OrderBackup::RemoveOrder(OrderType type, DestinationID destination) { OrderBackup *ob; FOR_ALL_ORDER_BACKUPS(ob) { for (Order *order = ob->orders; order != NULL; order = order->next) { OrderType ot = order->GetType(); if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue; if (ot == OT_IMPLICIT || (IsHangarTile(ob->tile) && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION; if (ot == type && order->GetDestination() == destination) { /* Remove the order backup! If a station/depot gets removed, we can't/shouldn't restore those broken orders. */ delete ob; break; } } } } openttd-1.5.3/src/tile_cmd.h0000644000000000000000000002155012627373434014431 0ustar rootroot/* $Id: tile_cmd.h 26277 2014-01-26 13:50:10Z frosch $ */ /* * 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 tile_cmd.h Generic 'commands' that can be performed on all tiles. */ #ifndef TILE_CMD_H #define TILE_CMD_H #include "command_type.h" #include "vehicle_type.h" #include "cargo_type.h" #include "track_type.h" #include "tile_map.h" /** The returned bits of VehicleEnterTile. */ enum VehicleEnterTileStatus { VETS_ENTERED_STATION = 1, ///< The vehicle entered a station VETS_ENTERED_WORMHOLE = 2, ///< The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/tunnel) VETS_CANNOT_ENTER = 3, ///< The vehicle cannot enter the tile /** * Shift the VehicleEnterTileStatus this many bits * to the right to get the station ID when * VETS_ENTERED_STATION is set */ VETS_STATION_ID_OFFSET = 8, VETS_STATION_MASK = 0xFFFF << VETS_STATION_ID_OFFSET, /** Bit sets of the above specified bits */ VETSB_CONTINUE = 0, ///< The vehicle can continue normally VETSB_ENTERED_STATION = 1 << VETS_ENTERED_STATION, ///< The vehicle entered a station VETSB_ENTERED_WORMHOLE = 1 << VETS_ENTERED_WORMHOLE, ///< The vehicle either entered a bridge, tunnel or depot tile (this includes the last tile of the bridge/tunnel) VETSB_CANNOT_ENTER = 1 << VETS_CANNOT_ENTER, ///< The vehicle cannot enter the tile }; DECLARE_ENUM_AS_BIT_SET(VehicleEnterTileStatus) /** Tile information, used while rendering the tile */ struct TileInfo { uint x; ///< X position of the tile in unit coordinates uint y; ///< Y position of the tile in unit coordinates Slope tileh; ///< Slope of the tile TileIndex tile; ///< Tile index int z; ///< Height }; /** Tile description for the 'land area information' tool */ struct TileDesc { StringID str; ///< Description of the tile Owner owner[4]; ///< Name of the owner(s) StringID owner_type[4]; ///< Type of each owner Date build_date; ///< Date of construction of tile contents StringID station_class; ///< Class of station StringID station_name; ///< Type of station within the class StringID airport_class; ///< Name of the airport class StringID airport_name; ///< Name of the airport StringID airport_tile_name; ///< Name of the airport tile const char *grf; ///< newGRF used for the tile contents uint64 dparam[2]; ///< Parameters of the \a str string uint16 rail_speed; ///< Speed limit of rail (bridges and track) uint16 road_speed; ///< Speed limit of road (bridges) }; /** * Tile callback function signature for drawing a tile and its contents to the screen * @param ti Information about the tile to draw */ typedef void DrawTileProc(TileInfo *ti); typedef int GetSlopeZProc(TileIndex tile, uint x, uint y); typedef CommandCost ClearTileProc(TileIndex tile, DoCommandFlag flags); /** * Tile callback function signature for obtaining cargo acceptance of a tile * @param tile Tile queried for its accepted cargo * @param acceptance Storage destination of the cargo acceptance in 1/8 * @param always_accepted Bitmask of always accepted cargo types */ typedef void AddAcceptedCargoProc(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted); /** * Tile callback function signature for obtaining a tile description * @param tile Tile being queried * @param td Storage pointer for returned tile description */ typedef void GetTileDescProc(TileIndex tile, TileDesc *td); /** * Tile callback function signature for getting the possible tracks * that can be taken on a given tile by a given transport. * * The return value contains the existing trackdirs and signal states. * * see track_func.h for usage of TrackStatus. * * @param tile the tile to get the track status from * @param mode the mode of transportation * @param sub_mode used to differentiate between different kinds within the mode * @return the track status information */ typedef TrackStatus GetTileTrackStatusProc(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side); /** * Tile callback function signature for obtaining the produced cargo of a tile. * @param tile Tile being queried * @param produced Destination array for produced cargo */ typedef void AddProducedCargoProc(TileIndex tile, CargoArray &produced); typedef bool ClickTileProc(TileIndex tile); typedef void AnimateTileProc(TileIndex tile); typedef void TileLoopProc(TileIndex tile); typedef void ChangeTileOwnerProc(TileIndex tile, Owner old_owner, Owner new_owner); /** @see VehicleEnterTileStatus to see what the return values mean */ typedef VehicleEnterTileStatus VehicleEnterTileProc(Vehicle *v, TileIndex tile, int x, int y); typedef Foundation GetFoundationProc(TileIndex tile, Slope tileh); /** * Tile callback function signature of the terraforming callback. * * The function is called when a tile is affected by a terraforming operation. * It has to check if terraforming of the tile is allowed and return extra terraform-cost that depend on the tiletype. * With DC_EXEC in \a flags it has to perform tiletype-specific actions (like clearing land etc., but not the terraforming itself). * * @note The terraforming has not yet taken place. So GetTileZ() and GetTileSlope() refer to the landscape before the terraforming operation. * * @param tile The involved tile. * @param flags Command flags passed to the terraform command (DC_EXEC, DC_QUERY_COST, etc.). * @param z_new TileZ after terraforming. * @param tileh_new Slope after terraforming. * @return Error code or extra cost for terraforming (like clearing land, building foundations, etc., but not the terraforming itself.) */ typedef CommandCost TerraformTileProc(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new); /** * Set of callback functions for performing tile operations of a given tile type. * @see TileType */ struct TileTypeProcs { DrawTileProc *draw_tile_proc; ///< Called to render the tile and its contents to the screen GetSlopeZProc *get_slope_z_proc; ClearTileProc *clear_tile_proc; AddAcceptedCargoProc *add_accepted_cargo_proc; ///< Adds accepted cargo of the tile to cargo array supplied as parameter GetTileDescProc *get_tile_desc_proc; ///< Get a description of a tile (for the 'land area information' tool) GetTileTrackStatusProc *get_tile_track_status_proc; ///< Get available tracks and status of a tile ClickTileProc *click_tile_proc; ///< Called when tile is clicked AnimateTileProc *animate_tile_proc; TileLoopProc *tile_loop_proc; ChangeTileOwnerProc *change_tile_owner_proc; AddProducedCargoProc *add_produced_cargo_proc; ///< Adds produced cargo of the tile to cargo array supplied as parameter VehicleEnterTileProc *vehicle_enter_tile_proc; ///< Called when a vehicle enters a tile GetFoundationProc *get_foundation_proc; TerraformTileProc *terraform_tile_proc; ///< Called when a terraforming operation is about to take place }; extern const TileTypeProcs * const _tile_type_procs[16]; TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side = INVALID_DIAGDIR); VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y); void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner); void GetTileDesc(TileIndex tile, TileDesc *td); static inline void AddAcceptedCargo(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted) { AddAcceptedCargoProc *proc = _tile_type_procs[GetTileType(tile)]->add_accepted_cargo_proc; if (proc == NULL) return; uint32 dummy = 0; // use dummy bitmask so there don't need to be several 'always_accepted != NULL' checks proc(tile, acceptance, always_accepted == NULL ? &dummy : always_accepted); } static inline void AddProducedCargo(TileIndex tile, CargoArray &produced) { AddProducedCargoProc *proc = _tile_type_procs[GetTileType(tile)]->add_produced_cargo_proc; if (proc == NULL) return; proc(tile, produced); } static inline void AnimateTile(TileIndex tile) { AnimateTileProc *proc = _tile_type_procs[GetTileType(tile)]->animate_tile_proc; assert(proc != NULL); proc(tile); } static inline bool ClickTile(TileIndex tile) { ClickTileProc *proc = _tile_type_procs[GetTileType(tile)]->click_tile_proc; if (proc == NULL) return false; return proc(tile); } #endif /* TILE_CMD_H */ openttd-1.5.3/src/string_base.h0000644000000000000000000000423112627373442015145 0ustar rootroot/* $Id: string_base.h 25653 2013-08-05 20:35:31Z michi_cc $ */ /* * 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 . */ #ifndef STRING_BASE_H #define STRING_BASE_H #include "string_type.h" /** Class for iterating over different kind of parts of a string. */ class StringIterator { public: /** Type of the iterator. */ enum IterType { ITER_CHARACTER, ///< Iterate over characters (or more exactly grapheme clusters). ITER_WORD, ///< Iterate over words. }; /** Sentinel to indicate end-of-iteration. */ static const size_t END = SIZE_MAX; /** * Create a new iterator instance. * @return New iterator instance. */ static StringIterator *Create(); virtual ~StringIterator() {} /** * Set a new iteration string. Must also be called if the string contents * changed. The cursor is reset to the start of the string. * @param s New string. */ virtual void SetString(const char *s) = 0; /** * Change the current string cursor. * @param p New cursor position. * @return Actual new cursor position at the next valid character boundary. * @pre p has to be inside the current string. */ virtual size_t SetCurPosition(size_t pos) = 0; /** * Advance the cursor by one iteration unit. * @return New cursor position (in bytes) or #END if the cursor is already at the end of the string. */ virtual size_t Next(IterType what = ITER_CHARACTER) = 0; /** * Move the cursor back by one iteration unit. * @return New cursor position (in bytes) or #END if the cursor is already at the start of the string. */ virtual size_t Prev(IterType what = ITER_CHARACTER) = 0; protected: StringIterator() {} }; #endif /* STRING_BASE_H */ openttd-1.5.3/src/sound_type.h0000644000000000000000000000720512627373443015043 0ustar rootroot/* $Id: sound_type.h 26425 2014-03-23 21:56:48Z frosch $ */ /* * 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 sound_type.h Types related to sounds. */ #ifndef SOUND_TYPE_H #define SOUND_TYPE_H struct SoundEntry { uint8 file_slot; size_t file_offset; size_t file_size; uint16 rate; uint8 bits_per_sample; uint8 channels; uint8 volume; uint8 priority; byte grf_container_ver; ///< NewGRF container version if the sound is from a NewGRF. }; /** * Sound effects from baseset. * * This enum contains the sound effects from the sound baseset. * For hysterical raisins the order of sound effects in the baseset * is different to the order they are referenced in TTD/NewGRF. * - The first two sound effects from the baseset are inserted at position 39. * (see translation table _sound_idx) * - The order in the enum is the order using in TTD/NewGRF. * - The naming of the enum values includes the position in the baseset. * That is, for sound effects 0x02 to 0x28 the naming is off-by-two. */ enum SoundFx { SND_BEGIN = 0, SND_02_SPLAT_WATER = 0, ///< Water construction. SND_03_FACTORY_WHISTLE, SND_04_TRAIN, SND_05_TRAIN_THROUGH_TUNNEL, SND_06_SHIP_HORN, SND_07_FERRY_HORN, SND_08_PLANE_TAKE_OFF, SND_09_JET, SND_0A_TRAIN_HORN, SND_0B_MINING_MACHINERY, SND_0C_ELECTRIC_SPARK, SND_0D_STEAM, SND_0E_LEVEL_CROSSING, SND_0F_VEHICLE_BREAKDOWN, SND_10_TRAIN_BREAKDOWN, SND_11_CRASH, SND_12_EXPLOSION, // 16 == 0x10 SND_13_BIG_CRASH, SND_14_CASHTILL, SND_15_BEEP, // 19 == 0x13 SND_16_MORSE, // 20 == 0x14 SND_17_SKID_PLANE, SND_18_HELICOPTER, SND_19_BUS_START_PULL_AWAY, SND_1A_BUS_START_PULL_AWAY_WITH_HORN, SND_1B_TRUCK_START, SND_1C_TRUCK_START_2, SND_1D_APPLAUSE, SND_1E_OOOOH, SND_1F_SPLAT_OTHER, ///< Non-water non-rail construction. SND_20_SPLAT_RAIL, ///< Rail construction. SND_21_JACKHAMMER, SND_22_CAR_HORN, SND_23_CAR_HORN_2, SND_24_SHEEP, SND_25_COW, SND_26_HORSE, SND_27_BLACKSMITH_ANVIL, SND_28_SAWMILL, // 38 == 0x26 ! SND_00_GOOD_YEAR, // 39 == 0x27 ! SND_01_BAD_YEAR, // 40 == 0x28 ! SND_29_RIP, // 41 == 0x29 ! SND_2A_EXTRACT_AND_POP, SND_2B_COMEDY_HIT, SND_2C_MACHINERY, SND_2D_RIP_2, SND_2E_EXTRACT_AND_POP, SND_2F_POP, SND_30_CARTOON_SOUND, SND_31_EXTRACT, SND_32_POP_2, SND_33_PLASTIC_MINE, SND_34_WIND, SND_35_COMEDY_BREAKDOWN, SND_36_CARTOON_CRASH, SND_37_BALLOON_SQUEAK, SND_38_CHAINSAW, SND_39_HEAVY_WIND, SND_3A_COMEDY_BREAKDOWN_2, SND_3B_JET_OVERHEAD, SND_3C_COMEDY_CAR, SND_3D_ANOTHER_JET_OVERHEAD, SND_3E_COMEDY_CAR_2, SND_3F_COMEDY_CAR_3, SND_40_COMEDY_CAR_START_AND_PULL_AWAY, SND_41_MAGLEV, SND_42_LOON_BIRD, SND_43_LION, SND_44_MONKEYS, SND_45_PLANE_CRASHING, SND_46_PLANE_ENGINE_SPUTTERING, SND_47_MAGLEV_2, SND_48_DISTANT_BIRD, // 72 == 0x48 SND_END }; /** The number of sounds in the original sample.cat */ static const uint ORIGINAL_SAMPLE_COUNT = 73; typedef uint16 SoundID; #endif /* SOUND_TYPE_H */ openttd-1.5.3/src/effectvehicle_func.h0000644000000000000000000000367612627373441016467 0ustar rootroot/* $Id: effectvehicle_func.h 22505 2011-05-28 09:45:12Z frosch $ */ /* * 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 effectvehicle_func.h Functions related to effect vehicles. */ #ifndef EFFECTVEHICLE_FUNC_H #define EFFECTVEHICLE_FUNC_H #include "vehicle_type.h" /** Effect vehicle types */ enum EffectVehicleType { EV_CHIMNEY_SMOKE = 0, ///< Smoke of power plant (industry). EV_STEAM_SMOKE = 1, ///< Smoke of steam engines. EV_DIESEL_SMOKE = 2, ///< Smoke of diesel engines. EV_ELECTRIC_SPARK = 3, ///< Sparcs of electric engines. EV_CRASH_SMOKE = 4, ///< Smoke of disasters. EV_EXPLOSION_LARGE = 5, ///< Various explosions. EV_BREAKDOWN_SMOKE = 6, ///< Smoke of broken vehicles except aircraft. EV_EXPLOSION_SMALL = 7, ///< Various explosions. EV_BULLDOZER = 8, ///< Bulldozer at roadworks. EV_BUBBLE = 9, ///< Bubble of bubble generator (industry). EV_BREAKDOWN_SMOKE_AIRCRAFT = 10, ///< Smoke of broken aircraft. EV_COPPER_MINE_SMOKE = 11, ///< Smoke at copper mine. EV_END }; EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type); EffectVehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type); EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type); #endif /* EFFECTVEHICLE_FUNC_H */ openttd-1.5.3/src/viewport_type.h0000644000000000000000000001204012627373446015566 0ustar rootroot/* $Id: viewport_type.h 27271 2015-05-08 17:30:07Z frosch $ */ /* * 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 viewport_type.h Types related to viewports. */ #ifndef VIEWPORT_TYPE_H #define VIEWPORT_TYPE_H #include "zoom_type.h" #include "strings_type.h" #include "table/strings.h" class LinkGraphOverlay; /** * Data structure for viewport, display of a part of the world */ struct ViewPort { int left; ///< Screen coordinate left egde of the viewport int top; ///< Screen coordinate top edge of the viewport int width; ///< Screen width of the viewport int height; ///< Screen height of the viewport int virtual_left; ///< Virtual left coordinate int virtual_top; ///< Virtual top coordinate int virtual_width; ///< width << zoom int virtual_height; ///< height << zoom ZoomLevel zoom; ///< The zoom level of the viewport. LinkGraphOverlay *overlay; }; /** Margins for the viewport sign */ enum ViewportSignMargin { VPSM_LEFT = 1, ///< Left margin VPSM_RIGHT = 1, ///< Right margin VPSM_TOP = 1, ///< Top margin VPSM_BOTTOM = 1, ///< Bottom margin }; /** Location information about a sign as seen on the viewport */ struct ViewportSign { int32 center; ///< The center position of the sign int32 top; ///< The top of the sign uint16 width_normal; ///< The width when not zoomed out (normal font) uint16 width_small; ///< The width when zoomed out (small font) void UpdatePosition(int center, int top, StringID str, StringID str_small = STR_NULL); void MarkDirty(ZoomLevel maxzoom = ZOOM_LVL_MAX) const; }; /** * Directions of zooming. * @see DoZoomInOutWindow */ enum ZoomStateChange { ZOOM_IN = 0, ///< Zoom in (get more detailed view). ZOOM_OUT = 1, ///< Zoom out (get helicopter view). ZOOM_NONE = 2, ///< Hack, used to update the button status. }; /** * Some values for constructing bounding boxes (BB). The Z positions under bridges are: * z=0..5 Everything that can be built under low bridges. * z=6 reserved, currently unused. * z=7 Z separator between bridge/tunnel and the things under/above it. */ static const uint BB_HEIGHT_UNDER_BRIDGE = 6; ///< Everything that can be built under low bridges, must not exceed this Z height. static const uint BB_Z_SEPARATOR = 7; ///< Separates the bridge/tunnel from the things under/above it. /** Viewport place method (type of highlighted area and placed objects) */ enum ViewportPlaceMethod { VPM_X_OR_Y = 0, ///< drag in X or Y direction VPM_FIX_X = 1, ///< drag only in X axis VPM_FIX_Y = 2, ///< drag only in Y axis VPM_X_AND_Y = 3, ///< area of land in X and Y directions VPM_X_AND_Y_LIMITED = 4, ///< area of land of limited size VPM_FIX_HORIZONTAL = 5, ///< drag only in horizontal direction VPM_FIX_VERTICAL = 6, ///< drag only in vertical direction VPM_X_LIMITED = 7, ///< Drag only in X axis with limited size VPM_Y_LIMITED = 8, ///< Drag only in Y axis with limited size VPM_RAILDIRS = 0x40, ///< all rail directions VPM_SIGNALDIRS = 0x80, ///< similar to VMP_RAILDIRS, but with different cursor }; DECLARE_ENUM_AS_BIT_SET(ViewportPlaceMethod) /** * Drag and drop selection process, or, what to do with an area of land when * you've selected it. */ enum ViewportDragDropSelectionProcess { DDSP_DEMOLISH_AREA, ///< Clear area DDSP_RAISE_AND_LEVEL_AREA, ///< Raise / level area DDSP_LOWER_AND_LEVEL_AREA, ///< Lower / level area DDSP_LEVEL_AREA, ///< Level area DDSP_CREATE_DESERT, ///< Fill area with desert DDSP_CREATE_ROCKS, ///< Fill area with rocks DDSP_CREATE_WATER, ///< Create a canal DDSP_CREATE_RIVER, ///< Create rivers DDSP_PLANT_TREES, ///< Plant trees DDSP_BUILD_BRIDGE, ///< Bridge placement /* Rail specific actions */ DDSP_PLACE_RAIL, ///< Rail placement DDSP_BUILD_SIGNALS, ///< Signal placement DDSP_BUILD_STATION, ///< Station placement DDSP_REMOVE_STATION, ///< Station removal DDSP_CONVERT_RAIL, ///< Rail conversion /* Road specific actions */ DDSP_PLACE_ROAD_X_DIR, ///< Road placement (X axis) DDSP_PLACE_ROAD_Y_DIR, ///< Road placement (Y axis) DDSP_PLACE_AUTOROAD, ///< Road placement (auto) DDSP_BUILD_BUSSTOP, ///< Road stop placement (buses) DDSP_BUILD_TRUCKSTOP, ///< Road stop placement (trucks) DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses) DDSP_REMOVE_TRUCKSTOP, ///< Road stop removal (trucks) }; #endif /* VIEWPORT_TYPE_H */ openttd-1.5.3/src/newgrf_object.h0000644000000000000000000001604012627373433015464 0ustar rootroot/* $Id: newgrf_object.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 newgrf_object.h Functions related to NewGRF objects. */ #ifndef NEWGRF_OBJECT_H #define NEWGRF_OBJECT_H #include "newgrf_callbacks.h" #include "newgrf_spritegroup.h" #include "newgrf_town.h" #include "economy_func.h" #include "date_type.h" #include "object_type.h" #include "newgrf_animation_type.h" #include "newgrf_class.h" #include "newgrf_commons.h" /** Various object behaviours. */ enum ObjectFlags { OBJECT_FLAG_NONE = 0, ///< Just nothing. OBJECT_FLAG_ONLY_IN_SCENEDIT = 1 << 0, ///< Object can only be constructed in the scenario editor. OBJECT_FLAG_CANNOT_REMOVE = 1 << 1, ///< Object can not be removed. OBJECT_FLAG_AUTOREMOVE = 1 << 2, ///< Object get automatically removed (like "owned land"). OBJECT_FLAG_BUILT_ON_WATER = 1 << 3, ///< Object can be built on water (not required). OBJECT_FLAG_CLEAR_INCOME = 1 << 4, ///< When object is cleared a positive income is generated instead of a cost. OBJECT_FLAG_HAS_NO_FOUNDATION = 1 << 5, ///< Do not display foundations when on a slope. OBJECT_FLAG_ANIMATION = 1 << 6, ///< Object has animated tiles. OBJECT_FLAG_ONLY_IN_GAME = 1 << 7, ///< Object can only be built in game. OBJECT_FLAG_2CC_COLOUR = 1 << 8, ///< Object wants 2CC colour mapping. OBJECT_FLAG_NOT_ON_LAND = 1 << 9, ///< Object can not be on land, implicitly sets #OBJECT_FLAG_BUILT_ON_WATER. OBJECT_FLAG_DRAW_WATER = 1 << 10, ///< Object wants to be drawn on water. OBJECT_FLAG_ALLOW_UNDER_BRIDGE = 1 << 11, ///< Object can built under a bridge. OBJECT_FLAG_ANIM_RANDOM_BITS = 1 << 12, ///< Object wants random bits in "next animation frame" callback. OBJECT_FLAG_SCALE_BY_WATER = 1 << 13, ///< Object count is roughly scaled by water amount at edges. }; DECLARE_ENUM_AS_BIT_SET(ObjectFlags) void ResetObjects(); /** Class IDs for objects. */ enum ObjectClassID { OBJECT_CLASS_BEGIN = 0, ///< The lowest valid value OBJECT_CLASS_MAX = 0xFF, ///< Maximum number of classes. INVALID_OBJECT_CLASS = 0xFF, ///< Class for the less fortunate. }; /** Allow incrementing of ObjectClassID variables */ DECLARE_POSTFIX_INCREMENT(ObjectClassID) /** An object that isn't use for transport, industries or houses. * @note If you change this struct, adopt the initialization of * default objects in table/object_land.h */ struct ObjectSpec { /* 2 because of the "normal" and "buy" sprite stacks. */ GRFFilePropsBase<2> grf_prop; ///< Properties related the the grf file ObjectClassID cls_id; ///< The class to which this spec belongs. StringID name; ///< The name for this object. uint8 climate; ///< In which climates is this object available? uint8 size; ///< The size of this objects; low nibble for X, high nibble for Y. uint8 build_cost_multiplier; ///< Build cost multiplier per tile. uint8 clear_cost_multiplier; ///< Clear cost multiplier per tile. Date introduction_date; ///< From when can this object be built. Date end_of_life_date; ///< When can't this object be built anymore. ObjectFlags flags; ///< Flags/settings related to the object. AnimationInfo animation; ///< Information about the animation. uint16 callback_mask; ///< Bitmask of requested/allowed callbacks. uint8 height; ///< The height of this structure, in heightlevels; max MAX_TILE_HEIGHT. uint8 views; ///< The number of views. uint8 generate_amount; ///< Number of objects which are attempted to be generated per 256^2 map during world generation. bool enabled; ///< Is this spec enabled? /** * Get the cost for building a structure of this type. * @return The cost for building. */ Money GetBuildCost() const { return GetPrice(PR_BUILD_OBJECT, this->build_cost_multiplier, this->grf_prop.grffile, 0); } /** * Get the cost for clearing a structure of this type. * @return The cost for clearing. */ Money GetClearCost() const { return GetPrice(PR_CLEAR_OBJECT, this->clear_cost_multiplier, this->grf_prop.grffile, 0); } bool IsEverAvailable() const; bool WasEverAvailable() const; bool IsAvailable() const; uint Index() const; static const ObjectSpec *Get(ObjectType index); static const ObjectSpec *GetByTile(TileIndex tile); }; /** Object scope resolver. */ struct ObjectScopeResolver : public ScopeResolver { struct Object *obj; ///< The object the callback is ran for. TileIndex tile; ///< The tile related to the object. uint8 view; ///< The view of the object. ObjectScopeResolver(ResolverObject &ro, Object *obj, TileIndex tile, uint8 view = 0); /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; }; /** A resolver object to be used with feature 0F spritegroups. */ struct ObjectResolverObject : public ResolverObject { ObjectScopeResolver object_scope; ///< The object scope resolver. TownScopeResolver *town_scope; ///< The town scope resolver (created on the first call). ObjectResolverObject(const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view = 0, CallbackID callback = CBID_NO_CALLBACK, uint32 param1 = 0, uint32 param2 = 0); ~ObjectResolverObject(); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &this->object_scope; case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); if (tsr != NULL) return tsr; /* FALL-THROUGH */ } default: return ResolverObject::GetScope(scope, relative); } } private: TownScopeResolver *GetTown(); }; /** Struct containing information relating to object classes. */ typedef NewGRFClass ObjectClass; /** Mapping of purchase for objects. */ static const CargoID CT_PURCHASE_OBJECT = 1; uint16 GetObjectCallback(CallbackID callback, uint32 param1, uint32 param2, const ObjectSpec *spec, Object *o, TileIndex tile, uint8 view = 0); void DrawNewObjectTile(TileInfo *ti, const ObjectSpec *spec); void DrawNewObjectTileInGUI(int x, int y, const ObjectSpec *spec, uint8 view); void AnimateNewObjectTile(TileIndex tile); void TriggerObjectTileAnimation(Object *o, TileIndex tile, ObjectAnimationTrigger trigger, const ObjectSpec *spec); void TriggerObjectAnimation(Object *o, ObjectAnimationTrigger trigger, const ObjectSpec *spec); #endif /* NEWGRF_OBJECT_H */ openttd-1.5.3/src/viewport_sprite_sorter.h0000644000000000000000000000540212627373441017510 0ustar rootroot/* $Id: viewport_sprite_sorter.h 26205 2014-01-02 16:48:16Z rubidium $ */ /* * 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 viewport_sprite_sorter.h Types related to sprite sorting. */ #include "stdafx.h" #include "core/smallvec_type.hpp" #include "gfx_type.h" #ifndef VIEWPORT_SPRITE_SORTER_H #define VIEWPORT_SPRITE_SORTER_H /** Parent sprite that should be drawn */ struct ParentSpriteToDraw { /* Block of 16B loadable in xmm register */ int32 xmin; ///< minimal world X coordinate of bounding box int32 ymin; ///< minimal world Y coordinate of bounding box int32 zmin; ///< minimal world Z coordinate of bounding box int32 x; ///< screen X coordinate of sprite /* Second block of 16B loadable in xmm register */ int32 xmax; ///< maximal world X coordinate of bounding box int32 ymax; ///< maximal world Y coordinate of bounding box int32 zmax; ///< maximal world Z coordinate of bounding box int32 y; ///< screen Y coordinate of sprite SpriteID image; ///< sprite to draw PaletteID pal; ///< palette to use const SubSprite *sub; ///< only draw a rectangular part of the sprite int32 left; ///< minimal screen X coordinate of sprite (= x + sprite->x_offs), reference point for child sprites int32 top; ///< minimal screen Y coordinate of sprite (= y + sprite->y_offs), reference point for child sprites int first_child; ///< the first child to draw. bool comparison_done; ///< Used during sprite sorting: true if sprite has been compared with all other sprites }; typedef SmallVector ParentSpriteToSortVector; /** Type for method for checking whether a viewport sprite sorter exists. */ typedef bool (*VpSorterChecker)(); /** Type for the actual viewport sprite sorter. */ typedef void (*VpSpriteSorter)(ParentSpriteToSortVector *psd); #ifdef WITH_SSE bool ViewportSortParentSpritesSSE41Checker(); void ViewportSortParentSpritesSSE41(ParentSpriteToSortVector *psdv); #endif void InitializeSpriteSorter(); #endif /* VIEWPORT_SPRITE_SORTER_H */ openttd-1.5.3/src/water_cmd.cpp0000644000000000000000000012312512627373442015151 0ustar rootroot/* $Id: water_cmd.cpp 27272 2015-05-08 17:32:57Z frosch $ */ /* * 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 water_cmd.cpp Handling of water tiles. */ #include "stdafx.h" #include "cmd_helper.h" #include "landscape.h" #include "viewport_func.h" #include "command_func.h" #include "town.h" #include "news_func.h" #include "depot_base.h" #include "depot_func.h" #include "water.h" #include "industry_map.h" #include "newgrf_canal.h" #include "strings_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "company_func.h" #include "clear_map.h" #include "tree_map.h" #include "aircraft.h" #include "effectvehicle_func.h" #include "tunnelbridge_map.h" #include "station_base.h" #include "ai/ai.hpp" #include "game/game.hpp" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "date_func.h" #include "company_base.h" #include "company_gui.h" #include "newgrf_generic.h" #include "table/strings.h" #include "safeguards.h" /** * Describes from which directions a specific slope can be flooded (if the tile is floodable at all). */ static const uint8 _flood_from_dirs[] = { (1 << DIR_NW) | (1 << DIR_SW) | (1 << DIR_SE) | (1 << DIR_NE), // SLOPE_FLAT (1 << DIR_NE) | (1 << DIR_SE), // SLOPE_W (1 << DIR_NW) | (1 << DIR_NE), // SLOPE_S (1 << DIR_NE), // SLOPE_SW (1 << DIR_NW) | (1 << DIR_SW), // SLOPE_E 0, // SLOPE_EW (1 << DIR_NW), // SLOPE_SE (1 << DIR_N ) | (1 << DIR_NW) | (1 << DIR_NE), // SLOPE_WSE, SLOPE_STEEP_S (1 << DIR_SW) | (1 << DIR_SE), // SLOPE_N (1 << DIR_SE), // SLOPE_NW 0, // SLOPE_NS (1 << DIR_E ) | (1 << DIR_NE) | (1 << DIR_SE), // SLOPE_NWS, SLOPE_STEEP_W (1 << DIR_SW), // SLOPE_NE (1 << DIR_S ) | (1 << DIR_SW) | (1 << DIR_SE), // SLOPE_ENW, SLOPE_STEEP_N (1 << DIR_W ) | (1 << DIR_SW) | (1 << DIR_NW), // SLOPE_SEN, SLOPE_STEEP_E }; /** * Marks tile dirty if it is a canal or river tile. * Called to avoid glitches when flooding tiles next to canal tile. * * @param tile tile to check */ static inline void MarkTileDirtyIfCanalOrRiver(TileIndex tile) { if (IsTileType(tile, MP_WATER) && (IsCanal(tile) || IsRiver(tile))) MarkTileDirtyByTile(tile); } /** * Marks the tiles around a tile as dirty, if they are canals or rivers. * * @param tile The center of the tile where all other tiles are marked as dirty * @ingroup dirty */ static void MarkCanalsAndRiversAroundDirty(TileIndex tile) { for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) { MarkTileDirtyIfCanalOrRiver(tile + TileOffsByDir(dir)); } } /** * Build a ship depot. * @param tile tile where ship depot is built * @param flags type of operation * @param p1 bit 0 depot orientation (Axis) * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildShipDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Axis axis = Extract(p1); TileIndex tile2 = tile + (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); if (!HasTileWaterGround(tile) || !HasTileWaterGround(tile2)) { return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER); } if (IsBridgeAbove(tile) || IsBridgeAbove(tile2)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); if (!IsTileFlat(tile) || !IsTileFlat(tile2)) { /* Prevent depots on rapids */ return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } if (!Depot::CanAllocateItem()) return CMD_ERROR; WaterClass wc1 = GetWaterClass(tile); WaterClass wc2 = GetWaterClass(tile2); CommandCost cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_DEPOT_SHIP]); bool add_cost = !IsWaterTile(tile); CommandCost ret = DoCommand(tile, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; if (add_cost) { cost.AddCost(ret); } add_cost = !IsWaterTile(tile2); ret = DoCommand(tile2, 0, 0, flags | DC_AUTO, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; if (add_cost) { cost.AddCost(ret); } if (flags & DC_EXEC) { Depot *depot = new Depot(tile); depot->build_date = _date; if (wc1 == WATER_CLASS_CANAL || wc2 == WATER_CLASS_CANAL) { /* Update infrastructure counts after the unconditional clear earlier. */ Company::Get(_current_company)->infrastructure.water += wc1 == WATER_CLASS_CANAL && wc2 == WATER_CLASS_CANAL ? 2 : 1; } Company::Get(_current_company)->infrastructure.water += 2 * LOCK_DEPOT_TILE_FACTOR; DirtyCompanyInfrastructureWindows(_current_company); MakeShipDepot(tile, _current_company, depot->index, DEPOT_PART_NORTH, axis, wc1); MakeShipDepot(tile2, _current_company, depot->index, DEPOT_PART_SOUTH, axis, wc2); MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile2); MakeDefaultName(depot); } return cost; } void MakeWaterKeepingClass(TileIndex tile, Owner o) { WaterClass wc = GetWaterClass(tile); /* Autoslope might turn an originally canal or river tile into land */ int z; Slope slope = GetTileSlope(tile, &z); if (slope != SLOPE_FLAT) { if (wc == WATER_CLASS_CANAL) { /* If we clear the canal, we have to remove it from the infrastructure count as well. */ Company *c = Company::GetIfValid(o); if (c != NULL) { c->infrastructure.water--; DirtyCompanyInfrastructureWindows(c->index); } /* Sloped canals are locks and no natural water remains whatever the slope direction */ wc = WATER_CLASS_INVALID; } /* Only river water should be restored on appropriate slopes. Other water would be invalid on slopes */ if (wc != WATER_CLASS_RIVER || GetInclinedSlopeDirection(slope) == INVALID_DIAGDIR) { wc = WATER_CLASS_INVALID; } } if (wc == WATER_CLASS_SEA && z > 0) { /* Update company infrastructure count. */ Company *c = Company::GetIfValid(o); if (c != NULL) { c->infrastructure.water++; DirtyCompanyInfrastructureWindows(c->index); } wc = WATER_CLASS_CANAL; } /* Zero map array and terminate animation */ DoClearSquare(tile); /* Maybe change to water */ switch (wc) { case WATER_CLASS_SEA: MakeSea(tile); break; case WATER_CLASS_CANAL: MakeCanal(tile, o, Random()); break; case WATER_CLASS_RIVER: MakeRiver(tile, Random()); break; default: break; } MarkTileDirtyByTile(tile); } static CommandCost RemoveShipDepot(TileIndex tile, DoCommandFlag flags) { if (!IsShipDepot(tile)) return CMD_ERROR; CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; TileIndex tile2 = GetOtherShipDepotTile(tile); /* do not check for ship on tile when company goes bankrupt */ if (!(flags & DC_BANKRUPT)) { CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2); if (ret.Failed()) return ret; } if (flags & DC_EXEC) { delete Depot::GetByTile(tile); Company *c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { c->infrastructure.water -= 2 * LOCK_DEPOT_TILE_FACTOR; DirtyCompanyInfrastructureWindows(c->index); } MakeWaterKeepingClass(tile, GetTileOwner(tile)); MakeWaterKeepingClass(tile2, GetTileOwner(tile2)); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_DEPOT_SHIP]); } /** * Builds a lock. * @param tile Central tile of the lock. * @param dir Uphill direction. * @param flags Operation to perform. * @return The cost in case of success, or an error code if it failed. */ static CommandCost DoBuildLock(TileIndex tile, DiagDirection dir, DoCommandFlag flags) { CommandCost cost(EXPENSES_CONSTRUCTION); int delta = TileOffsByDiagDir(dir); CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta); if (ret.Failed()) return ret; /* middle tile */ WaterClass wc_middle = IsWaterTile(tile) ? GetWaterClass(tile) : WATER_CLASS_CANAL; ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); /* lower tile */ if (!IsWaterTile(tile - delta)) { ret = DoCommand(tile - delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); cost.AddCost(_price[PR_BUILD_CANAL]); } if (!IsTileFlat(tile - delta)) { return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } WaterClass wc_lower = IsWaterTile(tile - delta) ? GetWaterClass(tile - delta) : WATER_CLASS_CANAL; /* upper tile */ if (!IsWaterTile(tile + delta)) { ret = DoCommand(tile + delta, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); cost.AddCost(_price[PR_BUILD_CANAL]); } if (!IsTileFlat(tile + delta)) { return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); } WaterClass wc_upper = IsWaterTile(tile + delta) ? GetWaterClass(tile + delta) : WATER_CLASS_CANAL; if (IsBridgeAbove(tile) || IsBridgeAbove(tile - delta) || IsBridgeAbove(tile + delta)) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } if (flags & DC_EXEC) { /* Update company infrastructure counts. */ Company *c = Company::GetIfValid(_current_company); if (c != NULL) { /* Counts for the water. */ if (!IsWaterTile(tile - delta)) c->infrastructure.water++; if (!IsWaterTile(tile + delta)) c->infrastructure.water++; /* Count for the lock itself. */ c->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock is three tiles. DirtyCompanyInfrastructureWindows(_current_company); } MakeLock(tile, _current_company, dir, wc_lower, wc_upper, wc_middle); MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile - delta); MarkTileDirtyByTile(tile + delta); MarkCanalsAndRiversAroundDirty(tile - delta); MarkCanalsAndRiversAroundDirty(tile + delta); } cost.AddCost(_price[PR_BUILD_LOCK]); return cost; } /** * Remove a lock. * @param tile Central tile of the lock. * @param flags Operation to perform. * @return The cost in case of success, or an error code if it failed. */ static CommandCost RemoveLock(TileIndex tile, DoCommandFlag flags) { if (GetTileOwner(tile) != OWNER_NONE) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } TileIndexDiff delta = TileOffsByDiagDir(GetLockDirection(tile)); /* make sure no vehicle is on the tile. */ CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile + delta); if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile - delta); if (ret.Failed()) return ret; if (flags & DC_EXEC) { /* Remove middle part from company infrastructure count. */ Company *c = Company::GetIfValid(GetTileOwner(tile)); if (c != NULL) { c->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // three parts of the lock. DirtyCompanyInfrastructureWindows(c->index); } if (GetWaterClass(tile) == WATER_CLASS_RIVER) { MakeRiver(tile, Random()); } else { DoClearSquare(tile); } MakeWaterKeepingClass(tile + delta, GetTileOwner(tile + delta)); MakeWaterKeepingClass(tile - delta, GetTileOwner(tile - delta)); MarkCanalsAndRiversAroundDirty(tile); MarkCanalsAndRiversAroundDirty(tile - delta); MarkCanalsAndRiversAroundDirty(tile + delta); } return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_LOCK]); } /** * Builds a lock. * @param tile tile where to place the lock * @param flags type of operation * @param p1 unused * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildLock(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile)); if (dir == INVALID_DIAGDIR) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); return DoBuildLock(tile, dir, flags); } /** Callback to create non-desert around a river tile. */ bool RiverModifyDesertZone(TileIndex tile, void *) { if (GetTropicZone(tile) == TROPICZONE_DESERT) SetTropicZone(tile, TROPICZONE_NORMAL); return false; } /** * Build a piece of canal. * @param tile end tile of stretch-dragging * @param flags type of operation * @param p1 start tile of stretch-dragging * @param p2 waterclass to build. sea and river can only be built in scenario editor * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { WaterClass wc = Extract(p2); if (p1 >= MapSize() || wc == WATER_CLASS_INVALID) return CMD_ERROR; /* Outside of the editor you can only build canals, not oceans */ if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR; TileArea ta(tile, p1); /* Outside the editor you can only drag canals, and not areas */ if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR; CommandCost cost(EXPENSES_CONSTRUCTION); TILE_AREA_LOOP(tile, ta) { CommandCost ret; Slope slope = GetTileSlope(tile); if (slope != SLOPE_FLAT && (wc != WATER_CLASS_RIVER || !IsInclinedSlope(slope))) { return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); } /* can't make water of water! */ if (IsTileType(tile, MP_WATER) && (!IsTileOwner(tile, OWNER_WATER) || wc == WATER_CLASS_SEA)) continue; bool water = IsWaterTile(tile); ret = DoCommand(tile, 0, 0, flags | DC_FORCE_CLEAR_TILE, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; if (!water) cost.AddCost(ret); if (flags & DC_EXEC) { switch (wc) { case WATER_CLASS_RIVER: MakeRiver(tile, Random()); if (_game_mode == GM_EDITOR) { TileIndex tile2 = tile; CircularTileSearch(&tile2, 5, RiverModifyDesertZone, NULL); } break; case WATER_CLASS_SEA: if (TileHeight(tile) == 0) { MakeSea(tile); break; } /* FALL THROUGH */ default: MakeCanal(tile, _current_company, Random()); if (Company::IsValidID(_current_company)) { Company::Get(_current_company)->infrastructure.water++; DirtyCompanyInfrastructureWindows(_current_company); } break; } MarkTileDirtyByTile(tile); MarkCanalsAndRiversAroundDirty(tile); } cost.AddCost(_price[PR_BUILD_CANAL]); } if (cost.GetCost() == 0) { return_cmd_error(STR_ERROR_ALREADY_BUILT); } else { return cost; } } static CommandCost ClearTile_Water(TileIndex tile, DoCommandFlag flags) { switch (GetWaterTileType(tile)) { case WATER_TILE_CLEAR: { if (flags & DC_NO_WATER) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER); Money base_cost = IsCanal(tile) ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]; /* Make sure freeform edges are allowed or it's not an edge tile. */ if (!_settings_game.construction.freeform_edges && (!IsInsideMM(TileX(tile), 1, MapMaxX() - 1) || !IsInsideMM(TileY(tile), 1, MapMaxY() - 1))) { return_cmd_error(STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP); } /* Make sure no vehicle is on the tile */ CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; Owner owner = GetTileOwner(tile); if (owner != OWNER_WATER && owner != OWNER_NONE) { CommandCost ret = CheckTileOwnership(tile); if (ret.Failed()) return ret; } if (flags & DC_EXEC) { if (IsCanal(tile) && Company::IsValidID(owner)) { Company::Get(owner)->infrastructure.water--; DirtyCompanyInfrastructureWindows(owner); } DoClearSquare(tile); MarkCanalsAndRiversAroundDirty(tile); } return CommandCost(EXPENSES_CONSTRUCTION, base_cost); } case WATER_TILE_COAST: { Slope slope = GetTileSlope(tile); /* Make sure no vehicle is on the tile */ CommandCost ret = EnsureNoVehicleOnGround(tile); if (ret.Failed()) return ret; if (flags & DC_EXEC) { DoClearSquare(tile); MarkCanalsAndRiversAroundDirty(tile); } if (IsSlopeWithOneCornerRaised(slope)) { return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_WATER]); } else { return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_ROUGH]); } } case WATER_TILE_LOCK: { static const TileIndexDiffC _lock_tomiddle_offs[][DIAGDIR_END] = { /* NE SE SW NW */ { { 0, 0}, {0, 0}, { 0, 0}, {0, 0} }, // LOCK_PART_MIDDLE { {-1, 0}, {0, 1}, { 1, 0}, {0, -1} }, // LOCK_PART_LOWER { { 1, 0}, {0, -1}, {-1, 0}, {0, 1} }, // LOCK_PART_UPPER }; if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); if (_current_company == OWNER_WATER) return CMD_ERROR; /* move to the middle tile.. */ return RemoveLock(tile + ToTileIndexDiff(_lock_tomiddle_offs[GetLockPart(tile)][GetLockDirection(tile)]), flags); } case WATER_TILE_DEPOT: if (flags & DC_AUTO) return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); return RemoveShipDepot(tile, flags); default: NOT_REACHED(); } } /** * return true if a tile is a water tile wrt. a certain direction. * * @param tile The tile of interest. * @param from The direction of interest. * @return true iff the tile is water in the view of 'from'. * */ bool IsWateredTile(TileIndex tile, Direction from) { switch (GetTileType(tile)) { case MP_WATER: switch (GetWaterTileType(tile)) { default: NOT_REACHED(); case WATER_TILE_DEPOT: case WATER_TILE_CLEAR: return true; case WATER_TILE_LOCK: return DiagDirToAxis(GetLockDirection(tile)) == DiagDirToAxis(DirToDiagDir(from)); case WATER_TILE_COAST: switch (GetTileSlope(tile)) { case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE); case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW); case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW); case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE); default: return false; } } case MP_RAILWAY: if (GetRailGroundType(tile) == RAIL_GROUND_WATER) { assert(IsPlainRail(tile)); switch (GetTileSlope(tile)) { case SLOPE_W: return (from == DIR_SE) || (from == DIR_E) || (from == DIR_NE); case SLOPE_S: return (from == DIR_NE) || (from == DIR_N) || (from == DIR_NW); case SLOPE_E: return (from == DIR_NW) || (from == DIR_W) || (from == DIR_SW); case SLOPE_N: return (from == DIR_SW) || (from == DIR_S) || (from == DIR_SE); default: return false; } } return false; case MP_STATION: if (IsOilRig(tile)) { /* Do not draw waterborders inside of industries. * Note: There is no easy way to detect the industry of an oilrig tile. */ TileIndex src_tile = tile + TileOffsByDir(from); if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) || (IsTileType(src_tile, MP_INDUSTRY))) return true; return IsTileOnWater(tile); } return (IsDock(tile) && IsTileFlat(tile)) || IsBuoy(tile); case MP_INDUSTRY: { /* Do not draw waterborders inside of industries. * Note: There is no easy way to detect the industry of an oilrig tile. */ TileIndex src_tile = tile + TileOffsByDir(from); if ((IsTileType(src_tile, MP_STATION) && IsOilRig(src_tile)) || (IsTileType(src_tile, MP_INDUSTRY) && GetIndustryIndex(src_tile) == GetIndustryIndex(tile))) return true; return IsTileOnWater(tile); } case MP_OBJECT: return IsTileOnWater(tile); case MP_TUNNELBRIDGE: return GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER && ReverseDiagDir(GetTunnelBridgeDirection(tile)) == DirToDiagDir(from); case MP_VOID: return true; // consider map border as water, esp. for rivers default: return false; } } /** * Draw a water sprite, potentially with a NewGRF-modified sprite offset. * @param base Sprite base. * @param offset Sprite offset. * @param feature The type of sprite that is drawn. * @param tile Tile index to draw. */ static void DrawWaterSprite(SpriteID base, uint offset, CanalFeature feature, TileIndex tile) { if (base != SPR_FLAT_WATER_TILE) { /* Only call offset callback if the sprite is NewGRF-provided. */ offset = GetCanalSpriteOffset(feature, tile, offset); } DrawGroundSprite(base + offset, PAL_NONE); } /** * Draw canal or river edges. * @param canal True if canal edges should be drawn, false for river edges. * @param offset Sprite offset. * @param tile Tile to draw. */ static void DrawWaterEdges(bool canal, uint offset, TileIndex tile) { CanalFeature feature; SpriteID base = 0; if (canal) { feature = CF_DIKES; base = GetCanalSprite(CF_DIKES, tile); if (base == 0) base = SPR_CANAL_DIKES_BASE; } else { feature = CF_RIVER_EDGE; base = GetCanalSprite(CF_RIVER_EDGE, tile); if (base == 0) return; // Don't draw if no sprites provided. } uint wa; /* determine the edges around with water. */ wa = IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0; wa += IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1; wa += IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2; wa += IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3; if (!(wa & 1)) DrawWaterSprite(base, offset, feature, tile); if (!(wa & 2)) DrawWaterSprite(base, offset + 1, feature, tile); if (!(wa & 4)) DrawWaterSprite(base, offset + 2, feature, tile); if (!(wa & 8)) DrawWaterSprite(base, offset + 3, feature, tile); /* right corner */ switch (wa & 0x03) { case 0: DrawWaterSprite(base, offset + 4, feature, tile); break; case 3: if (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W)) DrawWaterSprite(base, offset + 8, feature, tile); break; } /* bottom corner */ switch (wa & 0x06) { case 0: DrawWaterSprite(base, offset + 5, feature, tile); break; case 6: if (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N)) DrawWaterSprite(base, offset + 9, feature, tile); break; } /* left corner */ switch (wa & 0x0C) { case 0: DrawWaterSprite(base, offset + 6, feature, tile); break; case 12: if (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E)) DrawWaterSprite(base, offset + 10, feature, tile); break; } /* upper corner */ switch (wa & 0x09) { case 0: DrawWaterSprite(base, offset + 7, feature, tile); break; case 9: if (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S)) DrawWaterSprite(base, offset + 11, feature, tile); break; } } /** Draw a plain sea water tile with no edges */ static void DrawSeaWater(TileIndex tile) { DrawGroundSprite(SPR_FLAT_WATER_TILE, PAL_NONE); } /** draw a canal styled water tile with dikes around */ static void DrawCanalWater(TileIndex tile) { SpriteID image = SPR_FLAT_WATER_TILE; if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) { /* First water slope sprite is flat water. */ image = GetCanalSprite(CF_WATERSLOPE, tile); if (image == 0) image = SPR_FLAT_WATER_TILE; } DrawWaterSprite(image, 0, CF_WATERSLOPE, tile); DrawWaterEdges(true, 0, tile); } #include "table/water_land.h" /** * Draw a build sprite sequence for water tiles. * If buildings are invisible, nothing will be drawn. * @param ti Tile info. * @param dtss Sprite sequence to draw. * @param base Base sprite. * @param offset Additional sprite offset. * @param palette Palette to use. */ static void DrawWaterTileStruct(const TileInfo *ti, const DrawTileSeqStruct *dtss, SpriteID base, uint offset, PaletteID palette, CanalFeature feature) { /* Don't draw if buildings are invisible. */ if (IsInvisibilitySet(TO_BUILDINGS)) return; for (; !dtss->IsTerminator(); dtss++) { uint tile_offs = offset + dtss->image.sprite; if (feature < CF_END) tile_offs = GetCanalSpriteOffset(feature, ti->tile, tile_offs); AddSortableSpriteToDraw(base + tile_offs, palette, ti->x + dtss->delta_x, ti->y + dtss->delta_y, dtss->size_x, dtss->size_y, dtss->size_z, ti->z + dtss->delta_z, IsTransparencySet(TO_BUILDINGS)); } } /** Draw a lock tile. */ static void DrawWaterLock(const TileInfo *ti) { int part = GetLockPart(ti->tile); const DrawTileSprites &dts = _lock_display_data[part][GetLockDirection(ti->tile)]; /* Draw ground sprite. */ SpriteID image = dts.ground.sprite; SpriteID water_base = GetCanalSprite(CF_WATERSLOPE, ti->tile); if (water_base == 0) { /* Use default sprites. */ water_base = SPR_CANALS_BASE; } else if (HasBit(_water_feature[CF_WATERSLOPE].flags, CFF_HAS_FLAT_SPRITE)) { /* NewGRF supplies a flat sprite as first sprite. */ if (image == SPR_FLAT_WATER_TILE) { image = water_base; } else { image++; } } if (image < 5) image += water_base; DrawGroundSprite(image, PAL_NONE); /* Draw structures. */ uint zoffs = 0; SpriteID base = GetCanalSprite(CF_LOCKS, ti->tile); if (base == 0) { /* If no custom graphics, use defaults. */ base = SPR_LOCK_BASE; uint8 z_threshold = part == LOCK_PART_UPPER ? 8 : 0; zoffs = ti->z > z_threshold ? 24 : 0; } DrawWaterTileStruct(ti, dts.seq, base, zoffs, PAL_NONE, CF_LOCKS); } /** Draw a ship depot tile. */ static void DrawWaterDepot(const TileInfo *ti) { DrawWaterClassGround(ti); DrawWaterTileStruct(ti, _shipdepot_display_data[GetShipDepotAxis(ti->tile)][GetShipDepotPart(ti->tile)].seq, 0, 0, COMPANY_SPRITE_COLOUR(GetTileOwner(ti->tile)), CF_END); } static void DrawRiverWater(const TileInfo *ti) { SpriteID image = SPR_FLAT_WATER_TILE; uint offset = 0; uint edges_offset = 0; if (ti->tileh != SLOPE_FLAT || HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE)) { image = GetCanalSprite(CF_RIVER_SLOPE, ti->tile); if (image == 0) { switch (ti->tileh) { case SLOPE_NW: image = SPR_WATER_SLOPE_Y_DOWN; break; case SLOPE_SW: image = SPR_WATER_SLOPE_X_UP; break; case SLOPE_SE: image = SPR_WATER_SLOPE_Y_UP; break; case SLOPE_NE: image = SPR_WATER_SLOPE_X_DOWN; break; default: image = SPR_FLAT_WATER_TILE; break; } } else { /* Flag bit 0 indicates that the first sprite is flat water. */ offset = HasBit(_water_feature[CF_RIVER_SLOPE].flags, CFF_HAS_FLAT_SPRITE) ? 1 : 0; switch (ti->tileh) { case SLOPE_SE: edges_offset += 12; break; case SLOPE_NE: offset += 1; edges_offset += 24; break; case SLOPE_SW: offset += 2; edges_offset += 36; break; case SLOPE_NW: offset += 3; edges_offset += 48; break; default: offset = 0; break; } offset = GetCanalSpriteOffset(CF_RIVER_SLOPE, ti->tile, offset); } } DrawGroundSprite(image + offset, PAL_NONE); /* Draw river edges if available. */ DrawWaterEdges(false, edges_offset, ti->tile); } void DrawShoreTile(Slope tileh) { /* Converts the enum Slope into an offset based on SPR_SHORE_BASE. * This allows to calculate the proper sprite to display for this Slope */ static const byte tileh_to_shoresprite[32] = { 0, 1, 2, 3, 4, 16, 6, 7, 8, 9, 17, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10, 15, 0, }; assert(!IsHalftileSlope(tileh)); // Halftile slopes need to get handled earlier. assert(tileh != SLOPE_FLAT); // Shore is never flat assert((tileh != SLOPE_EW) && (tileh != SLOPE_NS)); // No suitable sprites for current flooding behaviour DrawGroundSprite(SPR_SHORE_BASE + tileh_to_shoresprite[tileh], PAL_NONE); } void DrawWaterClassGround(const TileInfo *ti) { switch (GetWaterClass(ti->tile)) { case WATER_CLASS_SEA: DrawSeaWater(ti->tile); break; case WATER_CLASS_CANAL: DrawCanalWater(ti->tile); break; case WATER_CLASS_RIVER: DrawRiverWater(ti); break; default: NOT_REACHED(); } } static void DrawTile_Water(TileInfo *ti) { switch (GetWaterTileType(ti->tile)) { case WATER_TILE_CLEAR: DrawWaterClassGround(ti); DrawBridgeMiddle(ti); break; case WATER_TILE_COAST: { DrawShoreTile(ti->tileh); DrawBridgeMiddle(ti); break; } case WATER_TILE_LOCK: DrawWaterLock(ti); break; case WATER_TILE_DEPOT: DrawWaterDepot(ti); break; } } void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part) { const DrawTileSprites &dts = _shipdepot_display_data[axis][part]; DrawSprite(dts.ground.sprite, dts.ground.pal, x, y); DrawOrigTileSeqInGUI(x, y, &dts, COMPANY_SPRITE_COLOUR(_local_company)); } static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y) { int z; Slope tileh = GetTilePixelSlope(tile, &z); return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh); } static Foundation GetFoundation_Water(TileIndex tile, Slope tileh) { return FOUNDATION_NONE; } static void GetTileDesc_Water(TileIndex tile, TileDesc *td) { switch (GetWaterTileType(tile)) { case WATER_TILE_CLEAR: switch (GetWaterClass(tile)) { case WATER_CLASS_SEA: td->str = STR_LAI_WATER_DESCRIPTION_WATER; break; case WATER_CLASS_CANAL: td->str = STR_LAI_WATER_DESCRIPTION_CANAL; break; case WATER_CLASS_RIVER: td->str = STR_LAI_WATER_DESCRIPTION_RIVER; break; default: NOT_REACHED(); break; } break; case WATER_TILE_COAST: td->str = STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK; break; case WATER_TILE_LOCK : td->str = STR_LAI_WATER_DESCRIPTION_LOCK; break; case WATER_TILE_DEPOT: td->str = STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT; td->build_date = Depot::GetByTile(tile)->build_date; break; default: NOT_REACHED(); break; } td->owner[0] = GetTileOwner(tile); } /** * Handle the flooding of a vehicle. This sets the vehicle state to crashed, * creates a newsitem and dirties the necessary windows. * @param v The vehicle to flood. */ static void FloodVehicle(Vehicle *v) { uint pass = v->Crash(true); AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED)); Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, ScriptEventVehicleCrashed::CRASH_FLOODED)); SetDParam(0, pass); AddVehicleNewsItem(STR_NEWS_DISASTER_FLOOD_VEHICLE, NT_ACCIDENT, v->index); CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v); } /** * Flood a vehicle if we are allowed to flood it, i.e. when it is on the ground. * @param v The vehicle to test for flooding. * @param data The z of level to flood. * @return NULL as we always want to remove everything. */ static Vehicle *FloodVehicleProc(Vehicle *v, void *data) { if ((v->vehstatus & VS_CRASHED) != 0) return NULL; switch (v->type) { default: break; case VEH_AIRCRAFT: { if (!IsAirportTile(v->tile) || GetTileMaxZ(v->tile) != 0) break; if (v->subtype == AIR_SHADOW) break; /* We compare v->z_pos against delta_z + 1 because the shadow * is at delta_z and the actual aircraft at delta_z + 1. */ const Station *st = Station::GetByTile(v->tile); const AirportFTAClass *airport = st->airport.GetFTA(); if (v->z_pos != airport->delta_z + 1) break; FloodVehicle(v); break; } case VEH_TRAIN: case VEH_ROAD: { int z = *(int*)data; if (v->z_pos > z) break; FloodVehicle(v->First()); break; } } return NULL; } /** * Finds a vehicle to flood. * It does not find vehicles that are already crashed on bridges, i.e. flooded. * @param tile the tile where to find a vehicle to flood */ static void FloodVehicles(TileIndex tile) { int z = 0; if (IsAirportTile(tile)) { const Station *st = Station::GetByTile(tile); TILE_AREA_LOOP(tile, st->airport) { if (st->TileBelongsToAirport(tile)) FindVehicleOnPos(tile, &z, &FloodVehicleProc); } /* No vehicle could be flooded on this airport anymore */ return; } if (!IsBridgeTile(tile)) { FindVehicleOnPos(tile, &z, &FloodVehicleProc); return; } TileIndex end = GetOtherBridgeEnd(tile); z = GetBridgePixelHeight(tile); FindVehicleOnPos(tile, &z, &FloodVehicleProc); FindVehicleOnPos(end, &z, &FloodVehicleProc); } /** * Returns the behaviour of a tile during flooding. * * @return Behaviour of the tile */ FloodingBehaviour GetFloodingBehaviour(TileIndex tile) { /* FLOOD_ACTIVE: 'single-corner-raised'-coast, sea, sea-shipdepots, sea-buoys, sea-docks (water part), rail with flooded halftile, sea-water-industries, sea-oilrigs * FLOOD_DRYUP: coast with more than one corner raised, coast with rail-track, coast with trees * FLOOD_PASSIVE: (not used) * FLOOD_NONE: canals, rivers, everything else */ switch (GetTileType(tile)) { case MP_WATER: if (IsCoast(tile)) { Slope tileh = GetTileSlope(tile); return (IsSlopeWithOneCornerRaised(tileh) ? FLOOD_ACTIVE : FLOOD_DRYUP); } /* FALL THROUGH */ case MP_STATION: case MP_INDUSTRY: case MP_OBJECT: return (GetWaterClass(tile) == WATER_CLASS_SEA) ? FLOOD_ACTIVE : FLOOD_NONE; case MP_RAILWAY: if (GetRailGroundType(tile) == RAIL_GROUND_WATER) { return (IsSlopeWithOneCornerRaised(GetTileSlope(tile)) ? FLOOD_ACTIVE : FLOOD_DRYUP); } return FLOOD_NONE; case MP_TREES: return (GetTreeGround(tile) == TREE_GROUND_SHORE ? FLOOD_DRYUP : FLOOD_NONE); default: return FLOOD_NONE; } } /** * Floods a tile. */ void DoFloodTile(TileIndex target) { assert(!IsTileType(target, MP_WATER)); bool flooded = false; // Will be set to true if something is changed. Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); Slope tileh = GetTileSlope(target); if (tileh != SLOPE_FLAT) { /* make coast.. */ switch (GetTileType(target)) { case MP_RAILWAY: { if (!IsPlainRail(target)) break; FloodVehicles(target); flooded = FloodHalftile(target); break; } case MP_TREES: if (!IsSlopeWithOneCornerRaised(tileh)) { SetTreeGroundDensity(target, TREE_GROUND_SHORE, 3); MarkTileDirtyByTile(target); flooded = true; break; } /* FALL THROUGH */ case MP_CLEAR: if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) { MakeShore(target); MarkTileDirtyByTile(target); flooded = true; } break; default: break; } } else { /* Flood vehicles */ FloodVehicles(target); /* flood flat tile */ if (DoCommand(target, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) { MakeSea(target); MarkTileDirtyByTile(target); flooded = true; } } if (flooded) { /* Mark surrounding canal tiles dirty too to avoid glitches */ MarkCanalsAndRiversAroundDirty(target); /* update signals if needed */ UpdateSignalsInBuffer(); } cur_company.Restore(); } /** * Drys a tile up. */ static void DoDryUp(TileIndex tile) { Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); switch (GetTileType(tile)) { case MP_RAILWAY: assert(IsPlainRail(tile)); assert(GetRailGroundType(tile) == RAIL_GROUND_WATER); RailGroundType new_ground; switch (GetTrackBits(tile)) { case TRACK_BIT_UPPER: new_ground = RAIL_GROUND_FENCE_HORIZ1; break; case TRACK_BIT_LOWER: new_ground = RAIL_GROUND_FENCE_HORIZ2; break; case TRACK_BIT_LEFT: new_ground = RAIL_GROUND_FENCE_VERT1; break; case TRACK_BIT_RIGHT: new_ground = RAIL_GROUND_FENCE_VERT2; break; default: NOT_REACHED(); } SetRailGroundType(tile, new_ground); MarkTileDirtyByTile(tile); break; case MP_TREES: SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3); MarkTileDirtyByTile(tile); break; case MP_WATER: assert(IsCoast(tile)); if (DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR).Succeeded()) { MakeClear(tile, CLEAR_GRASS, 3); MarkTileDirtyByTile(tile); } break; default: NOT_REACHED(); } cur_company.Restore(); } /** * Let a water tile floods its diagonal adjoining tiles * called from tunnelbridge_cmd, and by TileLoop_Industry() and TileLoop_Track() * * @param tile the water/shore tile that floods */ void TileLoop_Water(TileIndex tile) { if (IsTileType(tile, MP_WATER)) AmbientSoundEffect(tile); switch (GetFloodingBehaviour(tile)) { case FLOOD_ACTIVE: for (Direction dir = DIR_BEGIN; dir < DIR_END; dir++) { TileIndex dest = tile + TileOffsByDir(dir); if (!IsValidTile(dest)) continue; /* do not try to flood water tiles - increases performance a lot */ if (IsTileType(dest, MP_WATER)) continue; /* TREE_GROUND_SHORE is the sign of a previous flood. */ if (IsTileType(dest, MP_TREES) && GetTreeGround(dest) == TREE_GROUND_SHORE) continue; int z_dest; Slope slope_dest = GetFoundationSlope(dest, &z_dest) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP; if (z_dest > 0) continue; if (!HasBit(_flood_from_dirs[slope_dest], ReverseDir(dir))) continue; DoFloodTile(dest); } break; case FLOOD_DRYUP: { Slope slope_here = GetFoundationSlope(tile) & ~SLOPE_HALFTILE_MASK & ~SLOPE_STEEP; uint dir; FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope_here]) { TileIndex dest = tile + TileOffsByDir((Direction)dir); if (!IsValidTile(dest)) continue; FloodingBehaviour dest_behaviour = GetFloodingBehaviour(dest); if ((dest_behaviour == FLOOD_ACTIVE) || (dest_behaviour == FLOOD_PASSIVE)) return; } DoDryUp(tile); break; } default: return; } } void ConvertGroundTilesIntoWaterTiles() { int z; for (TileIndex tile = 0; tile < MapSize(); ++tile) { Slope slope = GetTileSlope(tile, &z); if (IsTileType(tile, MP_CLEAR) && z == 0) { /* Make both water for tiles at level 0 * and make shore, as that looks much better * during the generation. */ switch (slope) { case SLOPE_FLAT: MakeSea(tile); break; case SLOPE_N: case SLOPE_E: case SLOPE_S: case SLOPE_W: MakeShore(tile); break; default: uint dir; FOR_EACH_SET_BIT(dir, _flood_from_dirs[slope & ~SLOPE_STEEP]) { TileIndex dest = TILE_ADD(tile, TileOffsByDir((Direction)dir)); Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP; if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest)) { MakeShore(tile); break; } } break; } } } } static TrackStatus GetTileTrackStatus_Water(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { static const byte coast_tracks[] = {0, 32, 4, 0, 16, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0}; TrackBits ts; if (mode != TRANSPORT_WATER) return 0; switch (GetWaterTileType(tile)) { case WATER_TILE_CLEAR: ts = IsTileFlat(tile) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break; case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile) & 0xF]; break; case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break; case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break; default: return 0; } if (TileX(tile) == 0) { /* NE border: remove tracks that connects NE tile edge */ ts &= ~(TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT); } if (TileY(tile) == 0) { /* NW border: remove tracks that connects NW tile edge */ ts &= ~(TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER); } return CombineTrackStatus(TrackBitsToTrackdirBits(ts), TRACKDIR_BIT_NONE); } static bool ClickTile_Water(TileIndex tile) { if (GetWaterTileType(tile) == WATER_TILE_DEPOT) { ShowDepotWindow(GetShipDepotNorthTile(tile), VEH_SHIP); return true; } return false; } static void ChangeTileOwner_Water(TileIndex tile, Owner old_owner, Owner new_owner) { if (!IsTileOwner(tile, old_owner)) return; bool is_lock_middle = IsLock(tile) && GetLockPart(tile) == LOCK_PART_MIDDLE; /* No need to dirty company windows here, we'll redraw the whole screen anyway. */ if (is_lock_middle) Company::Get(old_owner)->infrastructure.water -= 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts. if (new_owner != INVALID_OWNER) { if (is_lock_middle) Company::Get(new_owner)->infrastructure.water += 3 * LOCK_DEPOT_TILE_FACTOR; // Lock has three parts. /* Only subtract from the old owner here if the new owner is valid, * otherwise we clear ship depots and canal water below. */ if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) { Company::Get(old_owner)->infrastructure.water--; Company::Get(new_owner)->infrastructure.water++; } if (IsShipDepot(tile)) { Company::Get(old_owner)->infrastructure.water -= LOCK_DEPOT_TILE_FACTOR; Company::Get(new_owner)->infrastructure.water += LOCK_DEPOT_TILE_FACTOR; } SetTileOwner(tile, new_owner); return; } /* Remove depot */ if (IsShipDepot(tile)) DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); /* Set owner of canals and locks ... and also canal under dock there was before. * Check if the new owner after removing depot isn't OWNER_WATER. */ if (IsTileOwner(tile, old_owner)) { if (GetWaterClass(tile) == WATER_CLASS_CANAL && !is_lock_middle) Company::Get(old_owner)->infrastructure.water--; SetTileOwner(tile, OWNER_NONE); } } static VehicleEnterTileStatus VehicleEnter_Water(Vehicle *v, TileIndex tile, int x, int y) { return VETSB_CONTINUE; } static CommandCost TerraformTile_Water(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { /* Canals can't be terraformed */ if (IsWaterTile(tile) && IsCanal(tile)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST); return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } extern const TileTypeProcs _tile_type_water_procs = { DrawTile_Water, // draw_tile_proc GetSlopePixelZ_Water, // get_slope_z_proc ClearTile_Water, // clear_tile_proc NULL, // add_accepted_cargo_proc GetTileDesc_Water, // get_tile_desc_proc GetTileTrackStatus_Water, // get_tile_track_status_proc ClickTile_Water, // click_tile_proc NULL, // animate_tile_proc TileLoop_Water, // tile_loop_proc ChangeTileOwner_Water, // change_tile_owner_proc NULL, // add_produced_cargo_proc VehicleEnter_Water, // vehicle_enter_tile_proc GetFoundation_Water, // get_foundation_proc TerraformTile_Water, // terraform_tile_proc }; openttd-1.5.3/src/music.cpp0000644000000000000000000000713312627373442014324 0ustar rootroot/* $Id: music.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 music.cpp The songs that OpenTTD knows. */ #include "stdafx.h" /** The type of set we're replacing */ #define SET_TYPE "music" #include "base_media_func.h" #include "safeguards.h" INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia, MusicSet) /** Names corresponding to the music set's files */ static const char * const _music_file_names[] = { "theme", "old_0", "old_1", "old_2", "old_3", "old_4", "old_5", "old_6", "old_7", "old_8", "old_9", "new_0", "new_1", "new_2", "new_3", "new_4", "new_5", "new_6", "new_7", "new_8", "new_9", "ezy_0", "ezy_1", "ezy_2", "ezy_3", "ezy_4", "ezy_5", "ezy_6", "ezy_7", "ezy_8", "ezy_9", }; /** Make sure we aren't messing things up. */ assert_compile(lengthof(_music_file_names) == NUM_SONGS_AVAILABLE); template /* static */ const char * const *BaseSet::file_names = _music_file_names; template /* static */ const char *BaseMedia::GetExtension() { return ".obm"; // OpenTTD Base Music } template /* static */ bool BaseMedia::DetermineBestSet() { if (BaseMedia::used_set != NULL) return true; const Tbase_set *best = NULL; for (const Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { if (c->GetNumMissing() != 0) continue; if (best == NULL || (best->fallback && !c->fallback) || best->valid_files < c->valid_files || (best->valid_files == c->valid_files && (best->shortname == c->shortname && best->version < c->version))) { best = c; } } BaseMedia::used_set = best; return BaseMedia::used_set != NULL; } bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename) { bool ret = this->BaseSet::FillSetDetails(ini, path, full_filename); if (ret) { this->num_available = 0; IniGroup *names = ini->GetGroup("names"); for (uint i = 0, j = 1; i < lengthof(this->song_name); i++) { const char *filename = this->files[i].filename; if (names == NULL || StrEmpty(filename)) { this->song_name[i][0] = '\0'; continue; } IniItem *item = NULL; /* As we possibly add a path to the filename and we compare * on the filename with the path as in the .obm, we need to * keep stripping path elements until we find a match. */ for (const char *p = filename; p != NULL; p = strchr(p, PATHSEPCHAR)) { /* Remove possible double path separator characters from * the beginning, so we don't start reading e.g. root. */ while (*p == PATHSEPCHAR) p++; item = names->GetItem(p, false); if (item != NULL && !StrEmpty(item->value)) break; } if (item == NULL || StrEmpty(item->value)) { DEBUG(grf, 0, "Base music set song name missing: %s", filename); return false; } strecpy(this->song_name[i], item->value, lastof(this->song_name[i])); this->track_nr[i] = j++; this->num_available++; } } return ret; } openttd-1.5.3/src/depot_base.h0000644000000000000000000000331312627373442014752 0ustar rootroot/* $Id: depot_base.h 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 depot_base.h Base for all depots (except hangars) */ #ifndef DEPOT_BASE_H #define DEPOT_BASE_H #include "depot_map.h" #include "core/pool_type.hpp" typedef Pool DepotPool; extern DepotPool _depot_pool; struct Depot : DepotPool::PoolItem<&_depot_pool> { Town *town; char *name; TileIndex xy; uint16 town_cn; ///< The N-1th depot for this town (consecutive number) Date build_date; ///< Date of construction Depot(TileIndex xy = INVALID_TILE) : xy(xy) {} ~Depot(); static inline Depot *GetByTile(TileIndex tile) { return Depot::Get(GetDepotIndex(tile)); } /** * Is the "type" of depot the same as the given depot, * i.e. are both a rail, road or ship depots? * @param d The depot to compare to. * @return true iff their types are equal. */ inline bool IsOfType(const Depot *d) const { return GetTileType(d->xy) == GetTileType(this->xy); } }; #define FOR_ALL_DEPOTS_FROM(var, start) FOR_ALL_ITEMS_FROM(Depot, depot_index, var, start) #define FOR_ALL_DEPOTS(var) FOR_ALL_DEPOTS_FROM(var, 0) #endif /* DEPOT_BASE_H */ openttd-1.5.3/src/error.h0000644000000000000000000000577712627373435014020 0ustar rootroot/* $Id: error.h 26241 2014-01-12 18:00:39Z frosch $ */ /* * 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 error.h Functions related to errors. */ #ifndef ERROR_H #define ERROR_H #include "strings_type.h" #include "company_type.h" #include "core/geometry_type.hpp" struct GRFFile; /** Message severity/type */ enum WarningLevel { WL_INFO, ///< Used for DoCommand-like (and some non-fatal AI GUI) errors/information WL_WARNING, ///< Other information WL_ERROR, ///< Errors (eg. saving/loading failed) WL_CRITICAL, ///< Critical errors, the MessageBox is shown in all cases }; /** The data of the error message. */ class ErrorMessageData { protected: uint duration; ///< Length of display of the message. 0 means forever, uint64 decode_params[20]; ///< Parameters of the message strings. const char *strings[20]; ///< Copies of raw strings that were used. const GRFFile *textref_stack_grffile; ///< NewGRF that filled the #TextRefStack for the error message. uint textref_stack_size; ///< Number of uint32 values to put on the #TextRefStack for the error message. uint32 textref_stack[16]; ///< Values to put on the #TextRefStack for the error message. StringID summary_msg; ///< General error message showed in first line. Must be valid. StringID detailed_msg; ///< Detailed error message showed in second line. Can be #INVALID_STRING_ID. Point position; ///< Position of the error message window. CompanyID face; ///< Company belonging to the face being shown. #INVALID_COMPANY if no face present. public: ErrorMessageData(const ErrorMessageData &data); ~ErrorMessageData(); ErrorMessageData(StringID summary_msg, StringID detailed_msg, uint duration = 0, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = NULL, uint textref_stack_size = 0, const uint32 *textref_stack = NULL); /** Check whether error window shall display a company manager face */ bool HasFace() const { return face != INVALID_COMPANY; } void SetDParam(uint n, uint64 v); void SetDParamStr(uint n, const char *str); void CopyOutDParams(); }; void ScheduleErrorMessage(const ErrorMessageData &data); void ShowErrorMessage(StringID summary_msg, StringID detailed_msg, WarningLevel wl, int x = 0, int y = 0, const GRFFile *textref_stack_grffile = NULL, uint textref_stack_size = 0, const uint32 *textref_stack = NULL); void ClearErrorMessages(); void ShowFirstError(); void UnshowCriticalError(); #endif /* ERROR_H */ openttd-1.5.3/src/disaster_vehicle.cpp0000644000000000000000000007244312627373442016527 0ustar rootroot/* $Id: disaster_vehicle.cpp 27087 2014-12-21 20:49:15Z rubidium $ */ /* * 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 disaster_vehicle.cpp * * All disaster/easter egg vehicles are handled here. * The general flow of control for the disaster vehicles is as follows: *
    *
  1. Initialize the disaster in a disaster specific way (eg start position, * possible target, etc.) Disaster_XXX_Init() function *
  2. Add a subtype to a disaster, which is an index into the function array * that handles the vehicle's ticks. *
  3. Run the disaster vehicles each tick until their target has been reached, * this happens in the DisasterTick_XXX() functions. In here, a vehicle's * state is kept by v->current_order.dest variable. Each achieved sub-target * will increase this value, and the last one will remove the disaster itself *
*/ #include "stdafx.h" #include "aircraft.h" #include "disaster_vehicle.h" #include "industry.h" #include "station_base.h" #include "command_func.h" #include "news_func.h" #include "town.h" #include "company_func.h" #include "strings_func.h" #include "date_func.h" #include "viewport_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "effectvehicle_func.h" #include "roadveh.h" #include "ai/ai.hpp" #include "game/game.hpp" #include "company_base.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "table/strings.h" #include "safeguards.h" /** Delay counter for considering the next disaster. */ uint16 _disaster_delay; static void DisasterClearSquare(TileIndex tile) { if (EnsureNoVehicleOnGround(tile).Failed()) return; switch (GetTileType(tile)) { case MP_RAILWAY: if (Company::IsHumanID(GetTileOwner(tile)) && !IsRailDepot(tile)) { Backup cur_company(_current_company, OWNER_WATER, FILE_LINE); DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); /* update signals in buffer */ UpdateSignalsInBuffer(); } break; case MP_HOUSE: { Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); cur_company.Restore(); break; } case MP_TREES: case MP_CLEAR: DoClearSquare(tile); break; default: break; } } static const SpriteID _disaster_images_1[] = {SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP, SPR_BLIMP}; static const SpriteID _disaster_images_2[] = {SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT, SPR_UFO_SMALL_SCOUT}; static const SpriteID _disaster_images_3[] = {SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15, SPR_F_15}; static const SpriteID _disaster_images_4[] = {SPR_SUB_SMALL_NE, SPR_SUB_SMALL_NE, SPR_SUB_SMALL_SE, SPR_SUB_SMALL_SE, SPR_SUB_SMALL_SW, SPR_SUB_SMALL_SW, SPR_SUB_SMALL_NW, SPR_SUB_SMALL_NW}; static const SpriteID _disaster_images_5[] = {SPR_SUB_LARGE_NE, SPR_SUB_LARGE_NE, SPR_SUB_LARGE_SE, SPR_SUB_LARGE_SE, SPR_SUB_LARGE_SW, SPR_SUB_LARGE_SW, SPR_SUB_LARGE_NW, SPR_SUB_LARGE_NW}; static const SpriteID _disaster_images_6[] = {SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER, SPR_UFO_HARVESTER}; static const SpriteID _disaster_images_7[] = {SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER, SPR_XCOM_SKYRANGER}; static const SpriteID _disaster_images_8[] = {SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A, SPR_AH_64A}; static const SpriteID _disaster_images_9[] = {SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1, SPR_ROTOR_MOVING_1}; static const SpriteID * const _disaster_images[] = { _disaster_images_1, _disaster_images_1, ///< zeppeliner and zeppeliner shadow _disaster_images_2, _disaster_images_2, ///< small ufo and small ufo shadow _disaster_images_3, _disaster_images_3, ///< combat aircraft and shadow _disaster_images_8, _disaster_images_8, _disaster_images_9, ///< combat helicopter, shadow and rotor _disaster_images_6, _disaster_images_6, ///< big ufo and shadow _disaster_images_7, _disaster_images_7, ///< skyranger and shadow _disaster_images_4, _disaster_images_5, ///< small and big submarine sprites }; void DisasterVehicle::UpdateImage() { SpriteID img = this->image_override; if (img == 0) img = _disaster_images[this->subtype][this->direction]; this->cur_image = img; } /** * Construct the disaster vehicle. * @param x The X coordinate. * @param y The Y coordinate. * @param direction The direction the vehicle is facing. * @param subtype The sub type of vehicle. * @param big_ufo_destroyer_target The target for the UFO destroyer. */ DisasterVehicle::DisasterVehicle(int x, int y, Direction direction, DisasterSubType subtype, VehicleID big_ufo_destroyer_target) : SpecializedVehicleBase(), big_ufo_destroyer_target(big_ufo_destroyer_target) { this->vehstatus = VS_UNCLICKABLE; this->x_pos = x; this->y_pos = y; switch (subtype) { case ST_ZEPPELINER: case ST_SMALL_UFO: case ST_AIRPLANE: case ST_HELICOPTER: case ST_BIG_UFO: case ST_BIG_UFO_DESTROYER: GetAircraftFlightLevelBounds(this, &this->z_pos, NULL); break; case ST_HELICOPTER_ROTORS: GetAircraftFlightLevelBounds(this, &this->z_pos, NULL); this->z_pos += ROTOR_Z_OFFSET; break; case ST_SMALL_SUBMARINE: case ST_BIG_SUBMARINE: this->z_pos = 0; break; case ST_ZEPPELINER_SHADOW: case ST_SMALL_UFO_SHADOW: case ST_AIRPLANE_SHADOW: case ST_HELICOPTER_SHADOW: case ST_BIG_UFO_SHADOW: case ST_BIG_UFO_DESTROYER_SHADOW: this->z_pos = 0; this->vehstatus |= VS_SHADOW; break; } this->direction = direction; this->tile = TileVirtXY(x, y); this->subtype = subtype; this->UpdateDeltaXY(INVALID_DIR); this->owner = OWNER_NONE; this->image_override = 0; this->current_order.Free(); this->UpdateImage(); this->UpdatePositionAndViewport(); } /** * Update the position of the vehicle. * @param x The new X-coordinate. * @param y The new Y-coordinate. * @param z The new Z-coordinate. */ void DisasterVehicle::UpdatePosition(int x, int y, int z) { this->x_pos = x; this->y_pos = y; this->z_pos = z; this->tile = TileVirtXY(x, y); this->UpdateImage(); this->UpdatePositionAndViewport(); DisasterVehicle *u = this->Next(); if (u != NULL) { int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); int safe_y = Clamp(y - 1, 0, MapMaxY() * TILE_SIZE); u->x_pos = x; u->y_pos = y - 1 - (max(z - GetSlopePixelZ(safe_x, safe_y), 0) >> 3); safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE); u->z_pos = GetSlopePixelZ(safe_x, safe_y); u->direction = this->direction; u->UpdateImage(); u->UpdatePositionAndViewport(); if ((u = u->Next()) != NULL) { u->x_pos = x; u->y_pos = y; u->z_pos = z + ROTOR_Z_OFFSET; u->UpdatePositionAndViewport(); } } } /** * Zeppeliner handling, v->current_order.dest states: * 0: Zeppeliner initialization has found a small airport, go there and crash * 1: Create crash and animate falling down for extra dramatic effect * 2: Create more smoke and leave debris on ground * 2: Clear the runway after some time and remove crashed zeppeliner * If not airport was found, only state 0 is reached until zeppeliner leaves map */ static bool DisasterTick_Zeppeliner(DisasterVehicle *v) { v->tick_counter++; if (v->current_order.GetDestination() < 2) { if (HasBit(v->tick_counter, 0)) return true; GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); if (v->current_order.GetDestination() == 1) { if (++v->age == 38) { v->current_order.SetDestination(2); v->age = 0; } if (GB(v->tick_counter, 0, 3) == 0) CreateEffectVehicleRel(v, 0, -17, 2, EV_CRASH_SMOKE); } else if (v->current_order.GetDestination() == 0) { if (IsValidTile(v->tile) && IsAirportTile(v->tile)) { v->current_order.SetDestination(1); v->age = 0; SetDParam(0, GetStationIndex(v->tile)); AddVehicleNewsItem(STR_NEWS_DISASTER_ZEPPELIN, NT_ACCIDENT, v->index); // Delete the news, when the zeppelin is gone AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCrashed(GetStationIndex(v->tile))); } } if (v->y_pos >= (int)((MapSizeY() + 9) * TILE_SIZE - 1)) { delete v; return false; } return true; } if (v->current_order.GetDestination() > 2) { if (++v->age <= 13320) return true; if (IsValidTile(v->tile) && IsAirportTile(v->tile)) { Station *st = Station::GetByTile(v->tile); CLRBITS(st->airport.flags, RUNWAY_IN_block); AI::NewEvent(GetTileOwner(v->tile), new ScriptEventDisasterZeppelinerCleared(st->index)); } v->UpdatePosition(v->x_pos, v->y_pos, GetAircraftFlightLevel(v)); delete v; return false; } int x = v->x_pos; int y = v->y_pos; int z = GetSlopePixelZ(x, y); if (z < v->z_pos) z = v->z_pos - 1; v->UpdatePosition(x, y, z); if (++v->age == 1) { CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v); v->image_override = SPR_BLIMP_CRASHING; } else if (v->age == 70) { v->image_override = SPR_BLIMP_CRASHED; } else if (v->age <= 300) { if (GB(v->tick_counter, 0, 3) == 0) { uint32 r = Random(); CreateEffectVehicleRel(v, GB(r, 0, 4) - 7, GB(r, 4, 4) - 7, GB(r, 8, 3) + 5, EV_EXPLOSION_SMALL); } } else if (v->age == 350) { v->current_order.SetDestination(3); v->age = 0; } if (IsValidTile(v->tile) && IsAirportTile(v->tile)) { SETBITS(Station::GetByTile(v->tile)->airport.flags, RUNWAY_IN_block); } return true; } /** * (Small) Ufo handling, v->current_order.dest states: * 0: Fly around to the middle of the map, then randomly, after a while target a road vehicle * 1: Home in on a road vehicle and crash it >:) * If not road vehicle was found, only state 0 is used and Ufo disappears after a while */ static bool DisasterTick_Ufo(DisasterVehicle *v) { v->image_override = (HasBit(++v->tick_counter, 3)) ? SPR_UFO_SMALL_SCOUT_DARKER : SPR_UFO_SMALL_SCOUT; if (v->current_order.GetDestination() == 0) { /* Fly around randomly */ int x = TileX(v->dest_tile) * TILE_SIZE; int y = TileY(v->dest_tile) * TILE_SIZE; if (Delta(x, v->x_pos) + Delta(y, v->y_pos) >= (int)TILE_SIZE) { v->direction = GetDirectionTowards(v, x, y); GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); return true; } if (++v->age < 6) { v->dest_tile = RandomTile(); return true; } v->current_order.SetDestination(1); uint n = 0; // Total number of targetable road vehicles. RoadVehicle *u; FOR_ALL_ROADVEHICLES(u) { if (u->IsFrontEngine()) n++; } if (n == 0) { /* If there are no targetable road vehicles, destroy the UFO. */ delete v; return false; } n = RandomRange(n); // Choose one of them. FOR_ALL_ROADVEHICLES(u) { /* Find (n+1)-th road vehicle. */ if (u->IsFrontEngine() && (n-- == 0)) break; } /* Target it. */ v->dest_tile = u->index; v->age = 0; return true; } else { /* Target a vehicle */ RoadVehicle *u = RoadVehicle::Get(v->dest_tile); assert(u != NULL && u->type == VEH_ROAD && u->IsFrontEngine()); uint dist = Delta(v->x_pos, u->x_pos) + Delta(v->y_pos, u->y_pos); if (dist < TILE_SIZE && !(u->vehstatus & VS_HIDDEN) && u->breakdown_ctr == 0) { u->breakdown_ctr = 3; u->breakdown_delay = 140; } v->direction = GetDirectionTowards(v, u->x_pos, u->y_pos); GetNewVehiclePosResult gp = GetNewVehiclePos(v); int z = v->z_pos; if (dist <= TILE_SIZE && z > u->z_pos) z--; v->UpdatePosition(gp.x, gp.y, z); if (z <= u->z_pos && (u->vehstatus & VS_HIDDEN) == 0) { v->age++; if (u->crashed_ctr == 0) { u->Crash(); AddVehicleNewsItem(STR_NEWS_DISASTER_SMALL_UFO, NT_ACCIDENT, u->index); // delete the news, when the roadvehicle is gone AI::NewEvent(u->owner, new ScriptEventVehicleCrashed(u->index, u->tile, ScriptEventVehicleCrashed::CRASH_RV_UFO)); Game::NewEvent(new ScriptEventVehicleCrashed(u->index, u->tile, ScriptEventVehicleCrashed::CRASH_RV_UFO)); } } /* Destroy? */ if (v->age > 50) { CreateEffectVehicleRel(v, 0, 7, 8, EV_EXPLOSION_LARGE); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v); delete v; return false; } } return true; } static void DestructIndustry(Industry *i) { for (TileIndex tile = 0; tile != MapSize(); tile++) { if (i->TileBelongsToIndustry(tile)) { ResetIndustryConstructionStage(tile); MarkTileDirtyByTile(tile); } } } /** * Aircraft handling, v->current_order.dest states: * 0: Fly towards the targeted industry * 1: If within 15 tiles, fire away rockets and destroy industry * 2: Industry explosions * 3: Fly out of the map * If the industry was removed in the meantime just fly to the end of the map. * @param v The disaster vehicle. * @param image_override The image at the time the aircraft is firing. * @param leave_at_top True iff the vehicle leaves the map at the north side. * @param news_message The string that's used as news message. * @param industry_flag Only attack industries that have this flag set. */ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16 image_override, bool leave_at_top, StringID news_message, IndustryBehaviour industry_flag) { v->tick_counter++; v->image_override = (v->current_order.GetDestination() == 1 && HasBit(v->tick_counter, 2)) ? image_override : 0; GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); if ((leave_at_top && gp.x < (-10 * (int)TILE_SIZE)) || (!leave_at_top && gp.x > (int)(MapSizeX() * TILE_SIZE + 9 * TILE_SIZE) - 1)) { delete v; return false; } if (v->current_order.GetDestination() == 2) { if (GB(v->tick_counter, 0, 2) == 0) { Industry *i = Industry::Get(v->dest_tile); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid int x = TileX(i->location.tile) * TILE_SIZE; int y = TileY(i->location.tile) * TILE_SIZE; uint32 r = Random(); CreateEffectVehicleAbove( GB(r, 0, 6) + x, GB(r, 6, 6) + y, GB(r, 12, 4), EV_EXPLOSION_SMALL); if (++v->age >= 55) v->current_order.SetDestination(3); } } else if (v->current_order.GetDestination() == 1) { if (++v->age == 112) { v->current_order.SetDestination(2); v->age = 0; Industry *i = Industry::Get(v->dest_tile); // Industry destructor calls ReleaseDisastersTargetingIndustry, so this is valid DestructIndustry(i); SetDParam(0, i->town->index); AddIndustryNewsItem(news_message, NT_ACCIDENT, i->index); // delete the news, when the industry closes if (_settings_client.sound.disaster) SndPlayTileFx(SND_12_EXPLOSION, i->location.tile); } } else if (v->current_order.GetDestination() == 0) { int x = v->x_pos + ((leave_at_top ? -15 : 15) * TILE_SIZE); int y = v->y_pos; if ((uint)x > MapMaxX() * TILE_SIZE - 1) return true; TileIndex tile = TileVirtXY(x, y); if (!IsTileType(tile, MP_INDUSTRY)) return true; IndustryID ind = GetIndustryIndex(tile); v->dest_tile = ind; if (GetIndustrySpec(Industry::Get(ind)->type)->behaviour & industry_flag) { v->current_order.SetDestination(1); v->age = 0; } } return true; } /** Airplane handling. */ static bool DisasterTick_Airplane(DisasterVehicle *v) { return DisasterTick_Aircraft(v, SPR_F_15_FIRING, true, STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY, INDUSTRYBEH_AIRPLANE_ATTACKS); } /** Helicopter handling. */ static bool DisasterTick_Helicopter(DisasterVehicle *v) { return DisasterTick_Aircraft(v, SPR_AH_64A_FIRING, false, STR_NEWS_DISASTER_HELICOPTER_FACTORY, INDUSTRYBEH_CHOPPER_ATTACKS); } /** Helicopter rotor blades; keep these spinning */ static bool DisasterTick_Helicopter_Rotors(DisasterVehicle *v) { v->tick_counter++; if (HasBit(v->tick_counter, 0)) return true; if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1; v->UpdatePositionAndViewport(); return true; } /** * (Big) Ufo handling, v->current_order.dest states: * 0: Fly around to the middle of the map, then randomly for a while and home in on a piece of rail * 1: Land there and breakdown all trains in a radius of 12 tiles; and now we wait... * because as soon as the Ufo lands, a fighter jet, a Skyranger, is called to clear up the mess */ static bool DisasterTick_Big_Ufo(DisasterVehicle *v) { v->tick_counter++; if (v->current_order.GetDestination() == 1) { int x = TileX(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2; int y = TileY(v->dest_tile) * TILE_SIZE + TILE_SIZE / 2; if (Delta(v->x_pos, x) + Delta(v->y_pos, y) >= 8) { v->direction = GetDirectionTowards(v, x, y); GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); return true; } if (!IsValidTile(v->dest_tile)) { /* Make sure we don't land outside the map. */ delete v; return false; } int z = GetSlopePixelZ(v->x_pos, v->y_pos); if (z < v->z_pos) { v->UpdatePosition(v->x_pos, v->y_pos, v->z_pos - 1); return true; } v->current_order.SetDestination(2); Vehicle *target; FOR_ALL_VEHICLES(target) { if (target->IsGroundVehicle()) { if (Delta(target->x_pos, v->x_pos) + Delta(target->y_pos, v->y_pos) <= 12 * (int)TILE_SIZE) { target->breakdown_ctr = 5; target->breakdown_delay = 0xF0; } } } Town *t = ClosestTownFromTile(v->dest_tile, UINT_MAX); SetDParam(0, t->index); AddTileNewsItem(STR_NEWS_DISASTER_BIG_UFO, NT_ACCIDENT, v->tile); if (!Vehicle::CanAllocateItem(2)) { delete v; return false; } DisasterVehicle *u = new DisasterVehicle(-6 * (int)TILE_SIZE, v->y_pos, DIR_SW, ST_BIG_UFO_DESTROYER, v->index); DisasterVehicle *w = new DisasterVehicle(-6 * (int)TILE_SIZE, v->y_pos, DIR_SW, ST_BIG_UFO_DESTROYER_SHADOW); u->SetNext(w); } else if (v->current_order.GetDestination() == 0) { int x = TileX(v->dest_tile) * TILE_SIZE; int y = TileY(v->dest_tile) * TILE_SIZE; if (Delta(x, v->x_pos) + Delta(y, v->y_pos) >= (int)TILE_SIZE) { v->direction = GetDirectionTowards(v, x, y); GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); return true; } if (++v->age < 6) { v->dest_tile = RandomTile(); return true; } v->current_order.SetDestination(1); TileIndex tile_org = RandomTile(); TileIndex tile = tile_org; do { if (IsPlainRailTile(tile) && Company::IsHumanID(GetTileOwner(tile))) { break; } tile = TILE_MASK(tile + 1); } while (tile != tile_org); v->dest_tile = tile; v->age = 0; } return true; } /** * Skyranger destroying (Big) Ufo handling, v->current_order.dest states: * 0: Home in on landed Ufo and shoot it down */ static bool DisasterTick_Big_Ufo_Destroyer(DisasterVehicle *v) { v->tick_counter++; GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, GetAircraftFlightLevel(v)); if (gp.x > (int)(MapSizeX() * TILE_SIZE + 9 * TILE_SIZE) - 1) { delete v; return false; } if (v->current_order.GetDestination() == 0) { Vehicle *u = Vehicle::Get(v->big_ufo_destroyer_target); if (Delta(v->x_pos, u->x_pos) > (int)TILE_SIZE) return true; v->current_order.SetDestination(1); CreateEffectVehicleRel(u, 0, 7, 8, EV_EXPLOSION_LARGE); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, u); delete u; for (int i = 0; i != 80; i++) { uint32 r = Random(); CreateEffectVehicleAbove( GB(r, 0, 6) + v->x_pos - 32, GB(r, 5, 6) + v->y_pos - 32, 0, EV_EXPLOSION_SMALL); } for (int dy = -3; dy < 3; dy++) { for (int dx = -3; dx < 3; dx++) { TileIndex tile = TileAddWrap(v->tile, dx, dy); if (tile != INVALID_TILE) DisasterClearSquare(tile); } } } return true; } /** * Submarine, v->current_order.dest states: * Unused, just float around aimlessly and pop up at different places, turning around */ static bool DisasterTick_Submarine(DisasterVehicle *v) { v->tick_counter++; if (++v->age > 8880) { delete v; return false; } if (!HasBit(v->tick_counter, 0)) return true; TileIndex tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction)); if (IsValidTile(tile)) { TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); if (trackbits == TRACK_BIT_ALL && !Chance16(1, 90)) { GetNewVehiclePosResult gp = GetNewVehiclePos(v); v->UpdatePosition(gp.x, gp.y, v->z_pos); return true; } } v->direction = ChangeDir(v->direction, GB(Random(), 0, 1) ? DIRDIFF_90RIGHT : DIRDIFF_90LEFT); return true; } static bool DisasterTick_NULL(DisasterVehicle *v) { return true; } typedef bool DisasterVehicleTickProc(DisasterVehicle *v); static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = { DisasterTick_Zeppeliner, DisasterTick_NULL, DisasterTick_Ufo, DisasterTick_NULL, DisasterTick_Airplane, DisasterTick_NULL, DisasterTick_Helicopter, DisasterTick_NULL, DisasterTick_Helicopter_Rotors, DisasterTick_Big_Ufo, DisasterTick_NULL, DisasterTick_Big_Ufo_Destroyer, DisasterTick_NULL, DisasterTick_Submarine, DisasterTick_Submarine, }; bool DisasterVehicle::Tick() { return _disastervehicle_tick_procs[this->subtype](this); } typedef void DisasterInitProc(); /** * Zeppeliner which crashes on a small airport if one found, * otherwise crashes on a random tile */ static void Disaster_Zeppeliner_Init() { if (!Vehicle::CanAllocateItem(2)) return; /* Pick a random place, unless we find a small airport */ int x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2; Station *st; FOR_ALL_STATIONS(st) { if (st->airport.tile != INVALID_TILE && (st->airport.type == AT_SMALL || st->airport.type == AT_LARGE)) { x = (TileX(st->airport.tile) + 2) * TILE_SIZE; break; } } DisasterVehicle *v = new DisasterVehicle(x, 0, DIR_SE, ST_ZEPPELINER); /* Allocate shadow */ DisasterVehicle *u = new DisasterVehicle(x, 0, DIR_SE, ST_ZEPPELINER_SHADOW); v->SetNext(u); } /** * Ufo which flies around aimlessly from the middle of the map a bit * until it locates a road vehicle which it targets and then destroys */ static void Disaster_Small_Ufo_Init() { if (!Vehicle::CanAllocateItem(2)) return; int x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2; DisasterVehicle *v = new DisasterVehicle(x, 0, DIR_SE, ST_SMALL_UFO); v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2); /* Allocate shadow */ DisasterVehicle *u = new DisasterVehicle(x, 0, DIR_SE, ST_SMALL_UFO_SHADOW); v->SetNext(u); } /* Combat airplane which destroys an oil refinery */ static void Disaster_Airplane_Init() { if (!Vehicle::CanAllocateItem(2)) return; Industry *i, *found = NULL; FOR_ALL_INDUSTRIES(i) { if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_AIRPLANE_ATTACKS) && (found == NULL || Chance16(1, 2))) { found = i; } } if (found == NULL) return; /* Start from the bottom (south side) of the map */ int x = (MapSizeX() + 9) * TILE_SIZE - 1; int y = TileY(found->location.tile) * TILE_SIZE + 37; DisasterVehicle *v = new DisasterVehicle(x, y, DIR_NE, ST_AIRPLANE); DisasterVehicle *u = new DisasterVehicle(x, y, DIR_NE, ST_AIRPLANE_SHADOW); v->SetNext(u); } /** Combat helicopter that destroys a factory */ static void Disaster_Helicopter_Init() { if (!Vehicle::CanAllocateItem(3)) return; Industry *i, *found = NULL; FOR_ALL_INDUSTRIES(i) { if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_CHOPPER_ATTACKS) && (found == NULL || Chance16(1, 2))) { found = i; } } if (found == NULL) return; int x = -16 * (int)TILE_SIZE; int y = TileY(found->location.tile) * TILE_SIZE + 37; DisasterVehicle *v = new DisasterVehicle(x, y, DIR_SW, ST_HELICOPTER); DisasterVehicle *u = new DisasterVehicle(x, y, DIR_SW, ST_HELICOPTER_SHADOW); v->SetNext(u); DisasterVehicle *w = new DisasterVehicle(x, y, DIR_SW, ST_HELICOPTER_ROTORS); u->SetNext(w); } /* Big Ufo which lands on a piece of rail and will consequently be shot * down by a combat airplane, destroying the surroundings */ static void Disaster_Big_Ufo_Init() { if (!Vehicle::CanAllocateItem(2)) return; int x = TileX(Random()) * TILE_SIZE + TILE_SIZE / 2; int y = MapMaxX() * TILE_SIZE - 1; DisasterVehicle *v = new DisasterVehicle(x, y, DIR_NW, ST_BIG_UFO); v->dest_tile = TileXY(MapSizeX() / 2, MapSizeY() / 2); /* Allocate shadow */ DisasterVehicle *u = new DisasterVehicle(x, y, DIR_NW, ST_BIG_UFO_SHADOW); v->SetNext(u); } static void Disaster_Submarine_Init(DisasterSubType subtype) { if (!Vehicle::CanAllocateItem()) return; int y; Direction dir; uint32 r = Random(); int x = TileX(r) * TILE_SIZE + TILE_SIZE / 2; if (HasBit(r, 31)) { y = MapMaxY() * TILE_SIZE - TILE_SIZE / 2 - 1; dir = DIR_NW; } else { y = TILE_SIZE / 2; if (_settings_game.construction.freeform_edges) y += TILE_SIZE; dir = DIR_SE; } if (!IsWaterTile(TileVirtXY(x, y))) return; new DisasterVehicle(x, y, dir, subtype); } /* Curious submarine #1, just floats around */ static void Disaster_Small_Submarine_Init() { Disaster_Submarine_Init(ST_SMALL_SUBMARINE); } /* Curious submarine #2, just floats around */ static void Disaster_Big_Submarine_Init() { Disaster_Submarine_Init(ST_BIG_SUBMARINE); } /** * Coal mine catastrophe, destroys a stretch of 30 tiles of * land in a certain direction */ static void Disaster_CoalMine_Init() { int index = GB(Random(), 0, 4); uint m; for (m = 0; m < 15; m++) { const Industry *i; FOR_ALL_INDUSTRIES(i) { if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_CAN_SUBSIDENCE) && --index < 0) { SetDParam(0, i->town->index); AddTileNewsItem(STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE, NT_ACCIDENT, i->location.tile + TileDiffXY(1, 1)); // keep the news, even when the mine closes { TileIndex tile = i->location.tile; TileIndexDiff step = TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2)); for (uint n = 0; n < 30; n++) { DisasterClearSquare(tile); tile += step; if (!IsValidTile(tile)) break; } } return; } } } } struct Disaster { DisasterInitProc *init_proc; ///< The init function for this disaster. Year min_year; ///< The first year this disaster will occur. Year max_year; ///< The last year this disaster will occur. }; static const Disaster _disasters[] = { {Disaster_Zeppeliner_Init, 1930, 1955}, // zeppeliner {Disaster_Small_Ufo_Init, 1940, 1970}, // ufo (small) {Disaster_Airplane_Init, 1960, 1990}, // airplane {Disaster_Helicopter_Init, 1970, 2000}, // helicopter {Disaster_Big_Ufo_Init, 2000, 2100}, // ufo (big) {Disaster_Small_Submarine_Init, 1940, 1965}, // submarine (small) {Disaster_Big_Submarine_Init, 1975, 2010}, // submarine (big) {Disaster_CoalMine_Init, 1950, 1985}, // coalmine }; static void DoDisaster() { byte buf[lengthof(_disasters)]; byte j = 0; for (size_t i = 0; i != lengthof(_disasters); i++) { if (_cur_year >= _disasters[i].min_year && _cur_year < _disasters[i].max_year) buf[j++] = (byte)i; } if (j == 0) return; _disasters[buf[RandomRange(j)]].init_proc(); } static void ResetDisasterDelay() { _disaster_delay = GB(Random(), 0, 9) + 730; } void DisasterDailyLoop() { if (--_disaster_delay != 0) return; ResetDisasterDelay(); if (_settings_game.difficulty.disasters != 0) DoDisaster(); } void StartupDisasters() { ResetDisasterDelay(); } /** * Marks all disasters targeting this industry in such a way * they won't call Industry::Get(v->dest_tile) on invalid industry anymore. * @param i deleted industry */ void ReleaseDisastersTargetingIndustry(IndustryID i) { DisasterVehicle *v; FOR_ALL_DISASTERVEHICLES(v) { /* primary disaster vehicles that have chosen target */ if (v->subtype == ST_AIRPLANE || v->subtype == ST_HELICOPTER) { /* if it has chosen target, and it is this industry (yes, dest_tile is IndustryID here), set order to "leaving map peacefully" */ if (v->current_order.GetDestination() > 0 && v->dest_tile == i) v->current_order.SetDestination(3); } } } /** * Notify disasters that we are about to delete a vehicle. So make them head elsewhere. * @param vehicle deleted vehicle */ void ReleaseDisastersTargetingVehicle(VehicleID vehicle) { DisasterVehicle *v; FOR_ALL_DISASTERVEHICLES(v) { /* primary disaster vehicles that have chosen target */ if (v->subtype == ST_SMALL_UFO) { if (v->current_order.GetDestination() != 0 && v->dest_tile == vehicle) { /* Revert to target-searching */ v->current_order.SetDestination(0); v->dest_tile = RandomTile(); GetAircraftFlightLevelBounds(v, &v->z_pos, NULL); v->age = 0; } } } } void DisasterVehicle::UpdateDeltaXY(Direction direction) { this->x_offs = -1; this->y_offs = -1; this->x_extent = 2; this->y_extent = 2; this->z_extent = 5; } openttd-1.5.3/src/dedicated.cpp0000644000000000000000000000432112627373442015106 0ustar rootroot/* $Id: dedicated.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 dedicated.cpp Forking support for dedicated servers. */ #include "stdafx.h" #ifdef ENABLE_NETWORK char *_log_file = NULL; ///< File to reroute output of a forked OpenTTD to FILE *_log_fd = NULL; ///< File to reroute output of a forked OpenTTD to #if defined(UNIX) && !defined(__MORPHOS__) #include #include "safeguards.h" #if (defined(SUNOS) && !defined(_LP64) && !defined(_I32LPx)) || defined(__HAIKU__) /* Solaris has, in certain situation, pid_t defined as long, while in other * cases it has it defined as int... this handles all cases nicely. * Haiku has also defined pid_t as a long. */ # define PRINTF_PID_T "%ld" #else # define PRINTF_PID_T "%d" #endif void DedicatedFork() { /* Fork the program */ pid_t pid = fork(); switch (pid) { case -1: perror("Unable to fork"); exit(1); case 0: { // We're the child /* Open the log-file to log all stuff too */ _log_fd = fopen(_log_file, "a"); if (_log_fd == NULL) { perror("Unable to open logfile"); exit(1); } /* Redirect stdout and stderr to log-file */ if (dup2(fileno(_log_fd), fileno(stdout)) == -1) { perror("Rerouting stdout"); exit(1); } if (dup2(fileno(_log_fd), fileno(stderr)) == -1) { perror("Rerouting stderr"); exit(1); } break; } default: /* We're the parent */ printf("Loading dedicated server...\n"); printf(" - Forked to background with pid " PRINTF_PID_T "\n", pid); exit(0); } } #endif #else /** Empty helper function call for NOT(UNIX and not MORPHOS) systems */ void DedicatedFork() {} #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/company_cmd.cpp0000644000000000000000000010777512627373435015514 0ustar rootroot/* $Id: company_cmd.cpp 26802 2014-09-07 16:12:58Z alberth $ */ /* * 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 company_cmd.cpp Handling of companies. */ #include "stdafx.h" #include "company_base.h" #include "company_func.h" #include "company_gui.h" #include "town.h" #include "news_func.h" #include "cmd_helper.h" #include "command_func.h" #include "network/network.h" #include "network/network_func.h" #include "network/network_base.h" #include "network/network_admin.h" #include "ai/ai.hpp" #include "company_manager_face.h" #include "window_func.h" #include "strings_func.h" #include "date_func.h" #include "sound_func.h" #include "rail.h" #include "core/pool_func.hpp" #include "settings_func.h" #include "vehicle_base.h" #include "vehicle_func.h" #include "smallmap_gui.h" #include "game/game.hpp" #include "goal_base.h" #include "story_base.h" #include "table/strings.h" #include "safeguards.h" void ClearEnginesHiddenFlagOfCompany(CompanyID cid); CompanyByte _local_company; ///< Company controlled by the human player at this client. Can also be #COMPANY_SPECTATOR. CompanyByte _current_company; ///< Company currently doing an action. Colours _company_colours[MAX_COMPANIES]; ///< NOSAVE: can be determined from company structs. CompanyManagerFace _company_manager_face; ///< for company manager face storage in openttd.cfg uint _next_competitor_start; ///< the number of ticks before the next AI is started uint _cur_company_tick_index; ///< used to generate a name for one company that doesn't have a name yet per tick CompanyPool _company_pool("Company"); ///< Pool of companies. INSTANTIATE_POOL_METHODS(Company) /** * Constructor. * @param name_1 Name of the company. * @param is_ai A computer program is running for this company. */ Company::Company(uint16 name_1, bool is_ai) { this->name_1 = name_1; this->location_of_HQ = INVALID_TILE; this->is_ai = is_ai; this->terraform_limit = _settings_game.construction.terraform_frame_burst << 16; this->clear_limit = _settings_game.construction.clear_frame_burst << 16; this->tree_limit = _settings_game.construction.tree_frame_burst << 16; for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR; InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, INVALID_COMPANY); } /** Destructor. */ Company::~Company() { if (CleaningPool()) return; DeleteCompanyWindows(this->index); } /** * Invalidating some stuff after removing item from the pool. * @param index index of deleted item */ void Company::PostDestructor(size_t index) { InvalidateWindowData(WC_GRAPH_LEGEND, 0, (int)index); InvalidateWindowData(WC_PERFORMANCE_DETAIL, 0, (int)index); InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0); InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); /* If the currently shown error message has this company in it, then close it. */ InvalidateWindowData(WC_ERRMSG, 0); } /** * Sets the local company and updates the settings that are set on a * per-company basis to reflect the core's state in the GUI. * @param new_company the new company * @pre Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE */ void SetLocalCompany(CompanyID new_company) { /* company could also be COMPANY_SPECTATOR or OWNER_NONE */ assert(Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE); #ifdef ENABLE_NETWORK /* Delete the chat window, if you were team chatting. */ InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_TEAM, _local_company); #endif assert(IsLocalCompany()); _current_company = _local_company = new_company; /* Delete any construction windows... */ DeleteConstructionWindows(); /* ... and redraw the whole screen. */ MarkWholeScreenDirty(); InvalidateWindowClassesData(WC_SIGN_LIST, -1); } /** * Get the colour for DrawString-subroutines which matches the colour of the company. * @param company Company to get the colour of. * @return Colour of \a company. */ TextColour GetDrawStringCompanyColour(CompanyID company) { if (!Company::IsValidID(company)) return (TextColour)_colour_gradient[COLOUR_WHITE][4] | TC_IS_PALETTE_COLOUR; return (TextColour)_colour_gradient[_company_colours[company]][4] | TC_IS_PALETTE_COLOUR; } /** * Draw the icon of a company. * @param c Company that needs its icon drawn. * @param x Horizontal coordinate of the icon. * @param y Vertical coordinate of the icon. */ void DrawCompanyIcon(CompanyID c, int x, int y) { DrawSprite(SPR_COMPANY_ICON, COMPANY_SPRITE_COLOUR(c), x, y); } /** * Checks whether a company manager's face is a valid encoding. * Unused bits are not enforced to be 0. * @param cmf the fact to check * @return true if and only if the face is valid */ static bool IsValidCompanyManagerFace(CompanyManagerFace cmf) { if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_GEN_ETHN, GE_WM)) return false; GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM); bool has_moustache = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0; bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0; bool has_glasses = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0; if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_EYE_COLOUR, ge)) return false; for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) { switch (cmfv) { case CMFV_MOUSTACHE: if (!has_moustache) continue; break; case CMFV_LIPS: // FALL THROUGH case CMFV_NOSE: if (has_moustache) continue; break; case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break; case CMFV_GLASSES: if (!has_glasses) continue; break; default: break; } if (!AreCompanyManagerFaceBitsValid(cmf, cmfv, ge)) return false; } return true; } /** * Refresh all windows owned by a company. * @param company Company that changed, and needs its windows refreshed. */ void InvalidateCompanyWindows(const Company *company) { CompanyID cid = company->index; if (cid == _local_company) SetWindowDirty(WC_STATUS_BAR, 0); SetWindowDirty(WC_FINANCES, cid); } /** * Verify whether the company can pay the bill. * @param cost [inout] Money to pay, is changed to an error if the company does not have enough money. * @return Function returns \c true if the company has enough money, else it returns \c false. */ bool CheckCompanyHasMoney(CommandCost &cost) { if (cost.GetCost() > 0) { const Company *c = Company::GetIfValid(_current_company); if (c != NULL && cost.GetCost() > c->money) { SetDParam(0, cost.GetCost()); cost.MakeError(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY); return false; } } return true; } /** * Deduct costs of a command from the money of a company. * @param c Company to pay the bill. * @param cost Money to pay. */ static void SubtractMoneyFromAnyCompany(Company *c, CommandCost cost) { if (cost.GetCost() == 0) return; assert(cost.GetExpensesType() != INVALID_EXPENSES); c->money -= cost.GetCost(); c->yearly_expenses[0][cost.GetExpensesType()] += cost.GetCost(); if (HasBit(1 << EXPENSES_TRAIN_INC | 1 << EXPENSES_ROADVEH_INC | 1 << EXPENSES_AIRCRAFT_INC | 1 << EXPENSES_SHIP_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())) { c->cur_economy.expenses -= cost.GetCost(); } InvalidateCompanyWindows(c); } /** * Subtract money from the #_current_company, if the company is valid. * @param cost Money to pay. */ void SubtractMoneyFromCompany(CommandCost cost) { Company *c = Company::GetIfValid(_current_company); if (c != NULL) SubtractMoneyFromAnyCompany(c, cost); } /** * Subtract money from a company, including the money fraction. * @param company Company paying the bill. * @param cst Cost of a command. */ void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cst) { Company *c = Company::Get(company); byte m = c->money_fraction; Money cost = cst.GetCost(); c->money_fraction = m - (byte)cost; cost >>= 8; if (c->money_fraction > m) cost++; if (cost != 0) SubtractMoneyFromAnyCompany(c, CommandCost(cst.GetExpensesType(), cost)); } /** Update the landscaping limits per company. */ void UpdateLandscapingLimits() { Company *c; FOR_ALL_COMPANIES(c) { c->terraform_limit = min(c->terraform_limit + _settings_game.construction.terraform_per_64k_frames, (uint32)_settings_game.construction.terraform_frame_burst << 16); c->clear_limit = min(c->clear_limit + _settings_game.construction.clear_per_64k_frames, (uint32)_settings_game.construction.clear_frame_burst << 16); c->tree_limit = min(c->tree_limit + _settings_game.construction.tree_per_64k_frames, (uint32)_settings_game.construction.tree_frame_burst << 16); } } /** * Set the right DParams to get the name of an owner. * @param owner the owner to get the name of. * @param tile optional tile to get the right town. * @pre if tile == 0, then owner can't be OWNER_TOWN. */ void GetNameOfOwner(Owner owner, TileIndex tile) { SetDParam(2, owner); if (owner != OWNER_TOWN) { if (!Company::IsValidID(owner)) { SetDParam(0, STR_COMPANY_SOMEONE); } else { SetDParam(0, STR_COMPANY_NAME); SetDParam(1, owner); } } else { assert(tile != 0); const Town *t = ClosestTownFromTile(tile, UINT_MAX); SetDParam(0, STR_TOWN_NAME); SetDParam(1, t->index); } } /** * Check whether the current owner owns something. * If that isn't the case an appropriate error will be given. * @param owner the owner of the thing to check. * @param tile optional tile to get the right town. * @pre if tile == 0 then the owner can't be OWNER_TOWN. * @return A succeeded command iff it's owned by the current company, else a failed command. */ CommandCost CheckOwnership(Owner owner, TileIndex tile) { assert(owner < OWNER_END); assert(owner != OWNER_TOWN || tile != 0); if (owner == _current_company) return CommandCost(); GetNameOfOwner(owner, tile); return_cmd_error(STR_ERROR_OWNED_BY); } /** * Check whether the current owner owns the stuff on * the given tile. If that isn't the case an * appropriate error will be given. * @param tile the tile to check. * @return A succeeded command iff it's owned by the current company, else a failed command. */ CommandCost CheckTileOwnership(TileIndex tile) { Owner owner = GetTileOwner(tile); assert(owner < OWNER_END); if (owner == _current_company) return CommandCost(); /* no need to get the name of the owner unless we're the local company (saves some time) */ if (IsLocalCompany()) GetNameOfOwner(owner, tile); return_cmd_error(STR_ERROR_OWNED_BY); } /** * Generate the name of a company from the last build coordinate. * @param c Company to give a name. */ static void GenerateCompanyName(Company *c) { /* Reserve space for extra unicode character. We need to do this to be able * to detect too long company name. */ char buffer[(MAX_LENGTH_COMPANY_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; if (c->name_1 != STR_SV_UNNAMED) return; if (c->last_build_coordinate == 0) return; Town *t = ClosestTownFromTile(c->last_build_coordinate, UINT_MAX); StringID str; uint32 strp; if (t->name == NULL && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) { str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_COMPANY_NAME_START; strp = t->townnameparts; verify_name:; /* No companies must have this name already */ Company *cc; FOR_ALL_COMPANIES(cc) { if (cc->name_1 == str && cc->name_2 == strp) goto bad_town_name; } GetString(buffer, str, lastof(buffer)); if (Utf8StringLength(buffer) >= MAX_LENGTH_COMPANY_NAME_CHARS) goto bad_town_name; set_name:; c->name_1 = str; c->name_2 = strp; MarkWholeScreenDirty(); if (c->is_ai) { CompanyNewsInformation *cni = MallocT(1); cni->FillData(c); SetDParam(0, STR_NEWS_COMPANY_LAUNCH_TITLE); SetDParam(1, STR_NEWS_COMPANY_LAUNCH_DESCRIPTION); SetDParamStr(2, cni->company_name); SetDParam(3, t->index); AddNewsItem(STR_MESSAGE_NEWS_FORMAT, NT_COMPANY_INFO, NF_COMPANY, NR_TILE, c->last_build_coordinate, NR_NONE, UINT32_MAX, cni); } return; } bad_town_name:; if (c->president_name_1 == SPECSTR_PRESIDENT_NAME) { str = SPECSTR_ANDCO_NAME; strp = c->president_name_2; goto set_name; } else { str = SPECSTR_ANDCO_NAME; strp = Random(); goto verify_name; } } /** Sorting weights for the company colours. */ static const byte _colour_sort[COLOUR_END] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1}; /** Similar colours, so we can try to prevent same coloured companies. */ static const Colours _similar_colour[COLOUR_END][2] = { { COLOUR_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_DARK_BLUE { COLOUR_GREEN, COLOUR_DARK_GREEN }, // COLOUR_PALE_GREEN { INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_PINK { COLOUR_ORANGE, INVALID_COLOUR }, // COLOUR_YELLOW { INVALID_COLOUR, INVALID_COLOUR }, // COLOUR_RED { COLOUR_DARK_BLUE, COLOUR_BLUE }, // COLOUR_LIGHT_BLUE { COLOUR_PALE_GREEN, COLOUR_DARK_GREEN }, // COLOUR_GREEN { COLOUR_PALE_GREEN, COLOUR_GREEN }, // COLOUR_DARK_GREEN { COLOUR_DARK_BLUE, COLOUR_LIGHT_BLUE }, // COLOUR_BLUE { COLOUR_BROWN, COLOUR_ORANGE }, // COLOUR_CREAM { COLOUR_PURPLE, INVALID_COLOUR }, // COLOUR_MAUVE { COLOUR_MAUVE, INVALID_COLOUR }, // COLOUR_PURPLE { COLOUR_YELLOW, COLOUR_CREAM }, // COLOUR_ORANGE { COLOUR_CREAM, INVALID_COLOUR }, // COLOUR_BROWN { COLOUR_WHITE, INVALID_COLOUR }, // COLOUR_GREY { COLOUR_GREY, INVALID_COLOUR }, // COLOUR_WHITE }; /** * Generate a company colour. * @return Generated company colour. */ static Colours GenerateCompanyColour() { Colours colours[COLOUR_END]; /* Initialize array */ for (uint i = 0; i < COLOUR_END; i++) colours[i] = (Colours)i; /* And randomize it */ for (uint i = 0; i < 100; i++) { uint r = Random(); Swap(colours[GB(r, 0, 4)], colours[GB(r, 4, 4)]); } /* Bubble sort it according to the values in table 1 */ for (uint i = 0; i < COLOUR_END; i++) { for (uint j = 1; j < COLOUR_END; j++) { if (_colour_sort[colours[j - 1]] < _colour_sort[colours[j]]) { Swap(colours[j - 1], colours[j]); } } } /* Move the colours that look similar to each company's colour to the side */ Company *c; FOR_ALL_COMPANIES(c) { Colours pcolour = (Colours)c->colour; for (uint i = 0; i < COLOUR_END; i++) { if (colours[i] == pcolour) { colours[i] = INVALID_COLOUR; break; } } for (uint j = 0; j < 2; j++) { Colours similar = _similar_colour[pcolour][j]; if (similar == INVALID_COLOUR) break; for (uint i = 1; i < COLOUR_END; i++) { if (colours[i - 1] == similar) Swap(colours[i - 1], colours[i]); } } } /* Return the first available colour */ for (uint i = 0; i < COLOUR_END; i++) { if (colours[i] != INVALID_COLOUR) return colours[i]; } NOT_REACHED(); } /** * Generate a random president name of a company. * @param c Company that needs a new president name. */ static void GeneratePresidentName(Company *c) { for (;;) { restart:; c->president_name_2 = Random(); c->president_name_1 = SPECSTR_PRESIDENT_NAME; /* Reserve space for extra unicode character. We need to do this to be able * to detect too long president name. */ char buffer[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; SetDParam(0, c->index); GetString(buffer, STR_PRESIDENT_NAME, lastof(buffer)); if (Utf8StringLength(buffer) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) continue; Company *cc; FOR_ALL_COMPANIES(cc) { if (c != cc) { /* Reserve extra space so even overlength president names can be compared. */ char buffer2[(MAX_LENGTH_PRESIDENT_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; SetDParam(0, cc->index); GetString(buffer2, STR_PRESIDENT_NAME, lastof(buffer2)); if (strcmp(buffer2, buffer) == 0) goto restart; } } return; } } /** * Reset the livery schemes to the company's primary colour. * This is used on loading games without livery information and on new company start up. * @param c Company to reset. */ void ResetCompanyLivery(Company *c) { for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) { c->livery[scheme].in_use = false; c->livery[scheme].colour1 = c->colour; c->livery[scheme].colour2 = c->colour; } } /** * Create a new company and sets all company variables default values * * @param is_ai is an AI company? * @param company CompanyID to use for the new company * @return the company struct */ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) { if (!Company::CanAllocateItem()) return NULL; /* we have to generate colour before this company is valid */ Colours colour = GenerateCompanyColour(); Company *c; if (company == INVALID_COMPANY) { c = new Company(STR_SV_UNNAMED, is_ai); } else { if (Company::IsValidID(company)) return NULL; c = new (company) Company(STR_SV_UNNAMED, is_ai); } c->colour = colour; ResetCompanyLivery(c); _company_colours[c->index] = (Colours)c->colour; c->money = c->current_loan = (100000ll * _economy.inflation_prices >> 16) / 50000 * 50000; c->share_owners[0] = c->share_owners[1] = c->share_owners[2] = c->share_owners[3] = INVALID_OWNER; c->avail_railtypes = GetCompanyRailtypes(c->index); c->avail_roadtypes = GetCompanyRoadtypes(c->index); c->inaugurated_year = _cur_year; RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false, false); // create a random company manager face SetDefaultCompanySettings(c->index); ClearEnginesHiddenFlagOfCompany(c->index); GeneratePresidentName(c); SetWindowDirty(WC_GRAPH_LEGEND, 0); SetWindowClassesDirty(WC_CLIENT_LIST_POPUP); SetWindowDirty(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); BuildOwnerLegend(); InvalidateWindowData(WC_SMALLMAP, 0, 1); if (is_ai && (!_networking || _network_server)) AI::StartNew(c->index); AI::BroadcastNewEvent(new ScriptEventCompanyNew(c->index), c->index); Game::NewEvent(new ScriptEventCompanyNew(c->index)); return c; } /** Start the next competitor now. */ void StartupCompanies() { _next_competitor_start = 0; } /** Start a new competitor company if possible. */ static void MaybeStartNewCompany() { #ifdef ENABLE_NETWORK if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return; #endif /* ENABLE_NETWORK */ Company *c; /* count number of competitors */ uint n = 0; FOR_ALL_COMPANIES(c) { if (c->is_ai) n++; } if (n < (uint)_settings_game.difficulty.max_no_competitors) { /* Send a command to all clients to start up a new AI. * Works fine for Multiplayer and Singleplayer */ DoCommandP(0, 1 | INVALID_COMPANY << 16, 0, CMD_COMPANY_CTRL); } } /** Initialize the pool of companies. */ void InitializeCompanies() { _cur_company_tick_index = 0; } /** * May company \a cbig buy company \a csmall? * @param cbig Company buying \a csmall. * @param csmall Company getting bought. * @return Return \c true if it is allowed. */ bool MayCompanyTakeOver(CompanyID cbig, CompanyID csmall) { const Company *c1 = Company::Get(cbig); const Company *c2 = Company::Get(csmall); /* Do the combined vehicle counts stay within the limits? */ return c1->group_all[VEH_TRAIN].num_vehicle + c2->group_all[VEH_TRAIN].num_vehicle <= _settings_game.vehicle.max_trains && c1->group_all[VEH_ROAD].num_vehicle + c2->group_all[VEH_ROAD].num_vehicle <= _settings_game.vehicle.max_roadveh && c1->group_all[VEH_SHIP].num_vehicle + c2->group_all[VEH_SHIP].num_vehicle <= _settings_game.vehicle.max_ships && c1->group_all[VEH_AIRCRAFT].num_vehicle + c2->group_all[VEH_AIRCRAFT].num_vehicle <= _settings_game.vehicle.max_aircraft; } /** * Handle the bankruptcy take over of a company. * Companies going bankrupt will ask the other companies in order of their * performance rating, so better performing companies get the 'do you want to * merge with Y' question earlier. The question will then stay till either the * company has gone bankrupt or got merged with a company. * * @param c the company that is going bankrupt. */ static void HandleBankruptcyTakeover(Company *c) { /* Amount of time out for each company to take over a company; * Timeout is a quarter (3 months of 30 days) divided over the * number of companies. The minimum number of days in a quarter * is 90: 31 in January, 28 in February and 31 in March. * Note that the company going bankrupt can't buy itself. */ static const int TAKE_OVER_TIMEOUT = 3 * 30 * DAY_TICKS / (MAX_COMPANIES - 1); assert(c->bankrupt_asked != 0); /* We're currently asking some company to buy 'us' */ if (c->bankrupt_timeout != 0) { c->bankrupt_timeout -= MAX_COMPANIES; if (c->bankrupt_timeout > 0) return; c->bankrupt_timeout = 0; return; } /* Did we ask everyone for bankruptcy? If so, bail out. */ if (c->bankrupt_asked == MAX_UVALUE(CompanyMask)) return; Company *c2, *best = NULL; int32 best_performance = -1; /* Ask the company with the highest performance history first */ FOR_ALL_COMPANIES(c2) { if (c2->bankrupt_asked == 0 && // Don't ask companies going bankrupt themselves !HasBit(c->bankrupt_asked, c2->index) && best_performance < c2->old_economy[1].performance_history && MayCompanyTakeOver(c2->index, c->index)) { best_performance = c2->old_economy[1].performance_history; best = c2; } } /* Asked all companies? */ if (best_performance == -1) { c->bankrupt_asked = MAX_UVALUE(CompanyMask); return; } SetBit(c->bankrupt_asked, best->index); c->bankrupt_timeout = TAKE_OVER_TIMEOUT; if (best->is_ai) { AI::NewEvent(best->index, new ScriptEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value))); } else if (IsInteractiveCompany(best->index)) { ShowBuyCompanyDialog(c->index); } } /** Called every tick for updating some company info. */ void OnTick_Companies() { if (_game_mode == GM_EDITOR) return; Company *c = Company::GetIfValid(_cur_company_tick_index); if (c != NULL) { if (c->name_1 != 0) GenerateCompanyName(c); if (c->bankrupt_asked != 0) HandleBankruptcyTakeover(c); } if (_next_competitor_start == 0) { _next_competitor_start = AI::GetStartNextTime() * DAY_TICKS; } if (AI::CanStartNew() && _game_mode != GM_MENU && --_next_competitor_start == 0) { MaybeStartNewCompany(); } _cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES; } /** * A year has passed, update the economic data of all companies, and perhaps show the * financial overview window of the local company. */ void CompaniesYearlyLoop() { Company *c; /* Copy statistics */ FOR_ALL_COMPANIES(c) { memmove(&c->yearly_expenses[1], &c->yearly_expenses[0], sizeof(c->yearly_expenses) - sizeof(c->yearly_expenses[0])); memset(&c->yearly_expenses[0], 0, sizeof(c->yearly_expenses[0])); SetWindowDirty(WC_FINANCES, c->index); } if (_settings_client.gui.show_finances && _local_company != COMPANY_SPECTATOR) { ShowCompanyFinances(_local_company); c = Company::Get(_local_company); if (c->num_valid_stat_ent > 5 && c->old_economy[0].performance_history < c->old_economy[4].performance_history) { if (_settings_client.sound.new_year) SndPlayFx(SND_01_BAD_YEAR); } else { if (_settings_client.sound.new_year) SndPlayFx(SND_00_GOOD_YEAR); } } } /** * Fill the CompanyNewsInformation struct with the required data. * @param c the current company. * @param other the other company (use \c NULL if not relevant). */ void CompanyNewsInformation::FillData(const Company *c, const Company *other) { SetDParam(0, c->index); GetString(this->company_name, STR_COMPANY_NAME, lastof(this->company_name)); if (other == NULL) { *this->other_company_name = '\0'; } else { SetDParam(0, other->index); GetString(this->other_company_name, STR_COMPANY_NAME, lastof(this->other_company_name)); c = other; } SetDParam(0, c->index); GetString(this->president_name, STR_PRESIDENT_NAME_MANAGER, lastof(this->president_name)); this->colour = c->colour; this->face = c->face; } /** * Called whenever company related information changes in order to notify admins. * @param company The company data changed of. */ void CompanyAdminUpdate(const Company *company) { #ifdef ENABLE_NETWORK if (_network_server) NetworkAdminCompanyUpdate(company); #endif /* ENABLE_NETWORK */ } /** * Called whenever a company is removed in order to notify admins. * @param company_id The company that was removed. * @param reason The reason the company was removed. */ void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason) { #ifdef ENABLE_NETWORK if (_network_server) NetworkAdminCompanyRemove(company_id, (AdminCompanyRemoveReason)reason); #endif /* ENABLE_NETWORK */ } /** * Control the companies: add, delete, etc. * @param tile unused * @param flags operation to perform * @param p1 various functionality * - bits 0..15: * = 0 - create a new company * = 1 - create a new AI company * = 2 - delete a company * - bits 16..24: CompanyID * @param p2 ClientID * @param text unused * @return the cost of this operation or an error */ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0); CompanyID company_id = (CompanyID)GB(p1, 16, 8); #ifdef ENABLE_NETWORK ClientID client_id = (ClientID)p2; #endif /* ENABLE_NETWORK */ switch (GB(p1, 0, 16)) { case 0: { // Create a new company /* This command is only executed in a multiplayer game */ if (!_networking) return CMD_ERROR; #ifdef ENABLE_NETWORK /* Has the network client a correct ClientIndex? */ if (!(flags & DC_EXEC)) return CommandCost(); NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); #ifndef DEBUG_DUMP_COMMANDS /* When replaying the client ID is not a valid client; there * are actually no clients at all. However, the company has to * be created, otherwise we cannot rerun the game properly. * So only allow a NULL client info in that case. */ if (ci == NULL) return CommandCost(); #endif /* NOT DEBUG_DUMP_COMMANDS */ /* Delete multiplayer progress bar */ DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); Company *c = DoStartupNewCompany(false); /* A new company could not be created, revert to being a spectator */ if (c == NULL) { if (_network_server) { ci->client_playas = COMPANY_SPECTATOR; NetworkUpdateClientInfo(ci->client_id); } break; } /* This is the client (or non-dedicated server) who wants a new company */ if (client_id == _network_own_client_id) { assert(_local_company == COMPANY_SPECTATOR); SetLocalCompany(c->index); if (!StrEmpty(_settings_client.network.default_company_pass)) { NetworkChangeCompanyPassword(_local_company, _settings_client.network.default_company_pass); } /* Now that we have a new company, broadcast our company settings to * all clients so everything is in sync */ SyncCompanySettings(); MarkWholeScreenDirty(); } NetworkServerNewCompany(c, ci); #endif /* ENABLE_NETWORK */ break; } case 1: { // Make a new AI company if (!(flags & DC_EXEC)) return CommandCost(); if (company_id != INVALID_COMPANY && (company_id >= MAX_COMPANIES || Company::IsValidID(company_id))) return CMD_ERROR; Company *c = DoStartupNewCompany(true, company_id); #ifdef ENABLE_NETWORK if (c != NULL) NetworkServerNewCompany(c, NULL); #endif /* ENABLE_NETWORK */ break; } case 2: { // Delete a company CompanyRemoveReason reason = (CompanyRemoveReason)GB(p2, 0, 2); if (reason >= CRR_END) return CMD_ERROR; Company *c = Company::GetIfValid(company_id); if (c == NULL) return CMD_ERROR; if (!(flags & DC_EXEC)) return CommandCost(); /* Delete any open window of the company */ DeleteCompanyWindows(c->index); CompanyNewsInformation *cni = MallocT(1); cni->FillData(c); /* Show the bankrupt news */ SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE); SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION); SetDParamStr(2, cni->company_name); AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, cni); /* Remove the company */ ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER); if (c->is_ai) AI::Stop(c->index); CompanyID c_index = c->index; delete c; AI::BroadcastNewEvent(new ScriptEventCompanyBankrupt(c_index)); Game::NewEvent(new ScriptEventCompanyBankrupt(c_index)); CompanyAdminRemove(c_index, (CompanyRemoveReason)reason); if (StoryPage::GetNumItems() == 0 || Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); break; } default: return CMD_ERROR; } InvalidateWindowClassesData(WC_GAME_OPTIONS); InvalidateWindowClassesData(WC_AI_SETTINGS); InvalidateWindowClassesData(WC_AI_LIST); return CommandCost(); } /** * Change the company manager's face. * @param tile unused * @param flags operation to perform * @param p1 unused * @param p2 face bitmasked * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSetCompanyManagerFace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CompanyManagerFace cmf = (CompanyManagerFace)p2; if (!IsValidCompanyManagerFace(cmf)) return CMD_ERROR; if (flags & DC_EXEC) { Company::Get(_current_company)->face = cmf; MarkWholeScreenDirty(); } return CommandCost(); } /** * Change the company's company-colour * @param tile unused * @param flags operation to perform * @param p1 bitstuffed: * p1 bits 0-7 scheme to set * p1 bits 8-9 set in use state or first/second colour * @param p2 new colour for vehicles, property, etc. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Colours colour = Extract(p2); LiveryScheme scheme = Extract(p1); byte state = GB(p1, 8, 2); if (scheme >= LS_END || state >= 3 || colour == INVALID_COLOUR) return CMD_ERROR; Company *c = Company::Get(_current_company); /* Ensure no two companies have the same primary colour */ if (scheme == LS_DEFAULT && state == 0) { const Company *cc; FOR_ALL_COMPANIES(cc) { if (cc != c && cc->colour == colour) return CMD_ERROR; } } if (flags & DC_EXEC) { switch (state) { case 0: c->livery[scheme].colour1 = colour; /* If setting the first colour of the default scheme, adjust the * original and cached company colours too. */ if (scheme == LS_DEFAULT) { _company_colours[_current_company] = colour; c->colour = colour; CompanyAdminUpdate(c); } break; case 1: c->livery[scheme].colour2 = colour; break; case 2: c->livery[scheme].in_use = colour != 0; /* Now handle setting the default scheme's in_use flag. * This is different to the other schemes, as it signifies if any * scheme is active at all. If this flag is not set, then no * processing of vehicle types occurs at all, and only the default * colours will be used. */ /* If enabling a scheme, set the default scheme to be in use too */ if (colour != 0) { c->livery[LS_DEFAULT].in_use = true; break; } /* Else loop through all schemes to see if any are left enabled. * If not, disable the default scheme too. */ c->livery[LS_DEFAULT].in_use = false; for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) { if (c->livery[scheme].in_use) { c->livery[LS_DEFAULT].in_use = true; break; } } break; default: break; } ResetVehicleColourMap(); MarkWholeScreenDirty(); /* All graph related to companies use the company colour. */ InvalidateWindowData(WC_INCOME_GRAPH, 0); InvalidateWindowData(WC_OPERATING_PROFIT, 0); InvalidateWindowData(WC_DELIVERED_CARGO, 0); InvalidateWindowData(WC_PERFORMANCE_HISTORY, 0); InvalidateWindowData(WC_COMPANY_VALUE, 0); InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); /* The smallmap owner view also stores the company colours. */ BuildOwnerLegend(); InvalidateWindowData(WC_SMALLMAP, 0, 1); /* Company colour data is indirectly cached. */ Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == _current_company) v->InvalidateNewGRFCache(); } extern void UpdateObjectColours(const Company *c); UpdateObjectColours(c); } return CommandCost(); } /** * Is the given name in use as name of a company? * @param name Name to search. * @return \c true if the name us unique (that is, not in use), else \c false. */ static bool IsUniqueCompanyName(const char *name) { const Company *c; FOR_ALL_COMPANIES(c) { if (c->name != NULL && strcmp(c->name, name) == 0) return false; } return true; } /** * Change the name of the company. * @param tile unused * @param flags operation to perform * @param p1 unused * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_COMPANY_NAME_CHARS) return CMD_ERROR; if (!IsUniqueCompanyName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { Company *c = Company::Get(_current_company); free(c->name); c->name = reset ? NULL : stredup(text); MarkWholeScreenDirty(); CompanyAdminUpdate(c); } return CommandCost(); } /** * Is the given name in use as president name of a company? * @param name Name to search. * @return \c true if the name us unique (that is, not in use), else \c false. */ static bool IsUniquePresidentName(const char *name) { const Company *c; FOR_ALL_COMPANIES(c) { if (c->president_name != NULL && strcmp(c->president_name, name) == 0) return false; } return true; } /** * Change the name of the president. * @param tile unused * @param flags operation to perform * @param p1 unused * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenamePresident(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_PRESIDENT_NAME_CHARS) return CMD_ERROR; if (!IsUniquePresidentName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { Company *c = Company::Get(_current_company); free(c->president_name); if (reset) { c->president_name = NULL; } else { c->president_name = stredup(text); if (c->name_1 == STR_SV_UNNAMED && c->name == NULL) { char buf[80]; seprintf(buf, lastof(buf), "%s Transport", text); DoCommand(0, 0, 0, DC_EXEC, CMD_RENAME_COMPANY, buf); } } MarkWholeScreenDirty(); CompanyAdminUpdate(c); } return CommandCost(); } /** * Get the service interval for the given company and vehicle type. * @param c The company, or NULL for client-default settings. * @param type The vehicle type to get the interval for. * @return The service interval. */ int CompanyServiceInterval(const Company *c, VehicleType type) { const VehicleDefaultSettings *vds = (c == NULL) ? &_settings_client.company.vehicle : &c->settings.vehicle; switch (type) { default: NOT_REACHED(); case VEH_TRAIN: return vds->servint_trains; case VEH_ROAD: return vds->servint_roadveh; case VEH_AIRCRAFT: return vds->servint_aircraft; case VEH_SHIP: return vds->servint_ships; } } openttd-1.5.3/src/aircraft.h0000644000000000000000000001430612627373441014443 0ustar rootroot/* $Id: aircraft.h 26866 2014-09-21 06:35:34Z rubidium $ */ /* * 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 aircraft.h Base for aircraft. */ #ifndef AIRCRAFT_H #define AIRCRAFT_H #include "station_map.h" #include "vehicle_base.h" /** * Base values for flight levels above ground level for 'normal' flight and holding patterns. * Due to speed and direction, the actual flight level may be higher. */ enum AircraftFlyingAltitude { AIRCRAFT_MIN_FLYING_ALTITUDE = 120, ///< Minimum flying altitude above tile. AIRCRAFT_MAX_FLYING_ALTITUDE = 360, ///< Maximum 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. }; struct Aircraft; /** An aircraft can be one of those types. */ enum AircraftSubType { AIR_HELICOPTER = 0, ///< an helicopter AIR_AIRCRAFT = 2, ///< an airplane AIR_SHADOW = 4, ///< shadow of the aircraft AIR_ROTOR = 6, ///< rotor of an helicopter }; /** Flags for air vehicles; shared with disaster vehicles. */ enum AirVehicleFlags { VAF_DEST_TOO_FAR = 0, ///< Next destination is too far away. /* The next two flags are to prevent stair climbing of the aircraft. The idea is that the aircraft * will ascend or descend multiple flight levels at a time instead of following the contours of the * landscape at a fixed altitude. This only has effect when there are more than 15 height levels. */ VAF_IN_MAX_HEIGHT_CORRECTION = 1, ///< The vehicle is currently lowering its altitude because it hit the upper bound. VAF_IN_MIN_HEIGHT_CORRECTION = 2, ///< The vehicle is currently raising its altitude because it hit the lower bound. }; static const int ROTOR_Z_OFFSET = 5; ///< Z Offset between helicopter- and rotorsprite. void HandleAircraftEnterHangar(Aircraft *v); void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); void UpdateAirplanesOnNewStation(const Station *st); void UpdateAircraftCache(Aircraft *v, bool update_range = false); void AircraftLeaveHangar(Aircraft *v, Direction exit_dir); void AircraftNextAirportPos_and_Order(Aircraft *v); void SetAircraftPosition(Aircraft *v, int x, int y, int z); void GetAircraftFlightLevelBounds(const Vehicle *v, int *min, int *max); template int GetAircraftFlightLevel(T *v, bool takeoff = false); /** Variables that are cached to improve performance and such. */ struct AircraftCache { uint32 cached_max_range_sqr; ///< Cached squared maximum range. uint16 cached_max_range; ///< Cached maximum range. }; /** * Aircraft, helicopters, rotors and their shadows belong to this class. */ struct Aircraft FINAL : public SpecializedVehicle { uint16 crashed_counter; ///< Timer for handling crash animations. byte pos; ///< Next desired position of the aircraft. byte previous_pos; ///< Previous desired position of the aircraft. StationID targetairport; ///< Airport to go to next. byte state; ///< State of the airport. @see AirportMovementStates DirectionByte last_direction; 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. byte flags; ///< Aircraft flags. @see AirVehicleFlags AircraftCache acache; /** 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. */ virtual ~Aircraft() { this->PreDestructor(); } void MarkDirty(); void UpdateDeltaXY(Direction direction); ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; } bool IsPrimaryVehicle() const { return this->IsNormalAircraft(); } SpriteID GetImage(Direction direction, EngineImageType image_type) const; int GetDisplaySpeed() const { return this->cur_speed; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } int GetSpeedOldUnits() const { return this->vcache.cached_max_speed * 10 / 128; } int GetCurrentMaxSpeed() const { return this->GetSpeedOldUnits(); } Money GetRunningCost() const; bool IsInDepot() const { assert(this->IsPrimaryVehicle()); return (this->vehstatus & VS_HIDDEN) != 0 && IsHangarTile(this->tile); } bool Tick(); void OnNewDay(); uint Crash(bool flooded = false); TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); /** * Check if the aircraft type is a normal flying device; eg * not a rotor or a shadow * @return Returns true if the aircraft is a helicopter/airplane and * false if it is a shadow or a rotor */ inline bool IsNormalAircraft() const { /* To be fully correct the commented out functionality is the proper one, * but since value can only be 0 or 2, it is sufficient to only check <= 2 * return (this->subtype == AIR_HELICOPTER) || (this->subtype == AIR_AIRCRAFT); */ return this->subtype <= AIR_AIRCRAFT; } /** * Get the range of this aircraft. * @return Range in tiles or 0 if unlimited range. */ uint16 GetRange() const { return this->acache.cached_max_range; } }; /** * Macro for iterating over all aircrafts. */ #define FOR_ALL_AIRCRAFT(var) FOR_ALL_VEHICLES_OF_TYPE(Aircraft, var) SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type); Station *GetTargetAirportIfValid(const Aircraft *v); #endif /* AIRCRAFT_H */ openttd-1.5.3/src/gfx_type.h0000644000000000000000000002320112627373435014472 0ustar rootroot/* $Id: gfx_type.h 27167 2015-02-22 23:06:45Z frosch $ */ /* * 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 gfx_type.h Types related to the graphics and/or input devices. */ #ifndef GFX_TYPE_H #define GFX_TYPE_H #include "core/endian_type.hpp" #include "core/geometry_type.hpp" #include "zoom_type.h" typedef uint32 SpriteID; ///< The number of a sprite, without mapping bits and colourtables typedef uint32 PaletteID; ///< The number of the palette typedef uint32 CursorID; ///< The number of the cursor (sprite) /** Combination of a palette sprite and a 'real' sprite */ struct PalSpriteID { SpriteID sprite; ///< The 'real' sprite PaletteID pal; ///< The palette (use \c PAL_NONE) if not needed) }; enum WindowKeyCodes { WKC_SHIFT = 0x8000, WKC_CTRL = 0x4000, WKC_ALT = 0x2000, WKC_META = 0x1000, WKC_GLOBAL_HOTKEY = 0x0800, ///< Fake keycode bit to indicate global hotkeys WKC_SPECIAL_KEYS = WKC_SHIFT | WKC_CTRL | WKC_ALT | WKC_META | WKC_GLOBAL_HOTKEY, /* Special ones */ WKC_NONE = 0, WKC_ESC = 1, WKC_BACKSPACE = 2, WKC_INSERT = 3, WKC_DELETE = 4, WKC_PAGEUP = 5, WKC_PAGEDOWN = 6, WKC_END = 7, WKC_HOME = 8, /* Arrow keys */ WKC_LEFT = 9, WKC_UP = 10, WKC_RIGHT = 11, WKC_DOWN = 12, /* Return & tab */ WKC_RETURN = 13, WKC_TAB = 14, /* Space */ WKC_SPACE = 32, /* Function keys */ WKC_F1 = 33, WKC_F2 = 34, WKC_F3 = 35, WKC_F4 = 36, WKC_F5 = 37, WKC_F6 = 38, WKC_F7 = 39, WKC_F8 = 40, WKC_F9 = 41, WKC_F10 = 42, WKC_F11 = 43, WKC_F12 = 44, /* Backquote is the key left of "1" * we only store this key here, no matter what character is really mapped to it * on a particular keyboard. (US keyboard: ` and ~ ; German keyboard: ^ and °) */ WKC_BACKQUOTE = 45, WKC_PAUSE = 46, /* 0-9 are mapped to 48-57 * A-Z are mapped to 65-90 * a-z are mapped to 97-122 */ /* Numerical keyboard */ WKC_NUM_DIV = 138, WKC_NUM_MUL = 139, WKC_NUM_MINUS = 140, WKC_NUM_PLUS = 141, WKC_NUM_ENTER = 142, WKC_NUM_DECIMAL = 143, /* Other keys */ WKC_SLASH = 144, ///< / Forward slash WKC_SEMICOLON = 145, ///< ; Semicolon WKC_EQUALS = 146, ///< = Equals WKC_L_BRACKET = 147, ///< [ Left square bracket WKC_BACKSLASH = 148, ///< \ Backslash WKC_R_BRACKET = 149, ///< ] Right square bracket WKC_SINGLEQUOTE = 150, ///< ' Single quote WKC_COMMA = 151, ///< , Comma WKC_PERIOD = 152, ///< . Period WKC_MINUS = 153, ///< - Minus }; /** A single sprite of a list of animated cursors */ struct AnimCursor { static const CursorID LAST = MAX_UVALUE(CursorID); CursorID sprite; ///< Must be set to LAST_ANIM when it is the last sprite of the loop byte display_time; ///< Amount of ticks this sprite will be shown }; /** Collection of variables for cursor-display and -animation */ struct CursorVars { Point pos, size, offs, delta; ///< position, size, offset from top-left, and movement Point draw_pos, draw_size; ///< position and size bounding-box for drawing int short_vehicle_offset; ///< offset of the X for short vehicles CursorID sprite; ///< current image of cursor PaletteID pal; int wheel; ///< mouse wheel movement /* We need two different vars to keep track of how far the scrollwheel moved. * OSX uses this for scrolling around the map. */ int v_wheel; int h_wheel; const AnimCursor *animate_list; ///< in case of animated cursor, list of frames const AnimCursor *animate_cur; ///< in case of animated cursor, current frame uint animate_timeout; ///< in case of animated cursor, number of ticks to show the current cursor bool visible; ///< cursor is visible bool dirty; ///< the rect occupied by the mouse is dirty (redraw) bool fix_at; ///< mouse is moving, but cursor is not (used for scrolling) bool in_window; ///< mouse inside this window, determines drawing logic bool vehchain; ///< vehicle chain is dragged bool UpdateCursorPosition(int x, int y, bool queued_warp); private: bool queued_warp; Point last_position; }; /** Data about how and where to blit pixels. */ struct DrawPixelInfo { void *dst_ptr; int left, top, width, height; int pitch; ZoomLevel zoom; }; /** Structure to access the alpha, red, green, and blue channels from a 32 bit number. */ union Colour { uint32 data; ///< Conversion of the channel information to a 32 bit number. struct { #if TTD_ENDIAN == TTD_BIG_ENDIAN uint8 a, r, g, b; ///< colour channels in BE order #else uint8 b, g, r, a; ///< colour channels in LE order #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ }; /** * Create a new colour. * @param r The channel for the red colour. * @param g The channel for the green colour. * @param b The channel for the blue colour. * @param a The channel for the alpha/transparency. */ Colour(uint8 r, uint8 g, uint8 b, uint8 a = 0xFF) : #if TTD_ENDIAN == TTD_BIG_ENDIAN a(a), r(r), g(g), b(b) #else b(b), g(g), r(r), a(a) #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ { } /** * Create a new colour. * @param The colour in the correct packed format. */ Colour(uint data = 0) : data(data) { } }; assert_compile(sizeof(Colour) == sizeof(uint32)); /** Available font sizes */ enum FontSize { FS_NORMAL, ///< Index of the normal font in the font tables. FS_SMALL, ///< Index of the small font in the font tables. FS_LARGE, ///< Index of the large font in the font tables. FS_MONO, ///< Index of the monospaced font in the font tables. FS_END, FS_BEGIN = FS_NORMAL, ///< First font. }; DECLARE_POSTFIX_INCREMENT(FontSize) /** * Used to only draw a part of the sprite. * Draw the subsprite in the rect (sprite_x_offset + left, sprite_y_offset + top) to (sprite_x_offset + right, sprite_y_offset + bottom). * Both corners are included in the drawing area. */ struct SubSprite { int left, top, right, bottom; }; enum Colours { COLOUR_BEGIN, COLOUR_DARK_BLUE = COLOUR_BEGIN, COLOUR_PALE_GREEN, COLOUR_PINK, COLOUR_YELLOW, COLOUR_RED, COLOUR_LIGHT_BLUE, COLOUR_GREEN, COLOUR_DARK_GREEN, COLOUR_BLUE, COLOUR_CREAM, COLOUR_MAUVE, COLOUR_PURPLE, COLOUR_ORANGE, COLOUR_BROWN, COLOUR_GREY, COLOUR_WHITE, COLOUR_END, INVALID_COLOUR = 0xFF, }; template <> struct EnumPropsT : MakeEnumPropsT {}; /** Colour of the strings, see _string_colourmap in table/palettes.h or docs/ottd-colourtext-palette.png */ enum TextColour { TC_BEGIN = 0x00, TC_FROMSTRING = 0x00, TC_BLUE = 0x00, TC_SILVER = 0x01, TC_GOLD = 0x02, TC_RED = 0x03, TC_PURPLE = 0x04, TC_LIGHT_BROWN = 0x05, TC_ORANGE = 0x06, TC_GREEN = 0x07, TC_YELLOW = 0x08, TC_DARK_GREEN = 0x09, TC_CREAM = 0x0A, TC_BROWN = 0x0B, TC_WHITE = 0x0C, TC_LIGHT_BLUE = 0x0D, TC_GREY = 0x0E, TC_DARK_BLUE = 0x0F, TC_BLACK = 0x10, TC_END, TC_INVALID = 0xFF, TC_IS_PALETTE_COLOUR = 0x100, ///< Colour value is already a real palette colour index, not an index of a StringColour. TC_NO_SHADE = 0x200, ///< Do not add shading to this text colour. }; DECLARE_ENUM_AS_BIT_SET(TextColour) /** Defines a few values that are related to animations using palette changes */ enum PaletteAnimationSizes { PALETTE_ANIM_SIZE = 28, ///< number of animated colours PALETTE_ANIM_START = 227, ///< Index in the _palettes array from which all animations are taking places (table/palettes.h) }; /** Define the operation GfxFillRect performs */ enum FillRectMode { FILLRECT_OPAQUE, ///< Fill rectangle with a single colour FILLRECT_CHECKER, ///< Draw only every second pixel, used for greying-out FILLRECT_RECOLOUR, ///< Apply a recolour sprite to the screen content }; /** Palettes OpenTTD supports. */ enum PaletteType { PAL_DOS, ///< Use the DOS palette. PAL_WINDOWS, ///< Use the Windows palette. PAL_AUTODETECT, ///< Automatically detect the palette based on the graphics pack. MAX_PAL = 2, ///< The number of palettes. }; /** Types of sprites that might be loaded */ enum SpriteType { ST_NORMAL = 0, ///< The most basic (normal) sprite ST_MAPGEN = 1, ///< Special sprite for the map generator ST_FONT = 2, ///< A sprite used for fonts ST_RECOLOUR = 3, ///< Recolour sprite ST_INVALID = 4, ///< Pseudosprite or other unusable sprite, used only internally }; /** The number of milliseconds per game tick. */ static const uint MILLISECONDS_PER_TICK = 30; /** Information about the currently used palette. */ struct Palette { Colour palette[256]; ///< Current palette. Entry 0 has to be always fully transparent! int first_dirty; ///< The first dirty element. int count_dirty; ///< The number of dirty elements. }; /** Modes for 8bpp support */ enum Support8bpp { S8BPP_NONE = 0, ///< No support for 8bpp by OS or hardware, force 32bpp blitters. S8BPP_SYSTEM, ///< No 8bpp support by hardware, do not try to use 8bpp video modes or hardware palettes. S8BPP_HARDWARE, ///< Full 8bpp support by OS and hardware. }; #endif /* GFX_TYPE_H */ openttd-1.5.3/src/slope_func.h0000644000000000000000000002501412627373433015004 0ustar rootroot/* $Id: slope_func.h 23106 2011-11-04 11:30:37Z rubidium $ */ /* * 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 slope_func.h Functions related to slopes. */ #ifndef SLOPE_FUNC_H #define SLOPE_FUNC_H #include "core/math_func.hpp" #include "slope_type.h" #include "direction_type.h" #include "tile_type.h" /** * Rangecheck for Corner enumeration. * * @param corner A #Corner. * @return true iff corner is in a valid range. */ static inline bool IsValidCorner(Corner corner) { return IsInsideMM(corner, 0, CORNER_END); } /** * Checks if a slope is steep. * * @param s The given #Slope. * @return True if the slope is steep, else false. */ static inline bool IsSteepSlope(Slope s) { return (s & SLOPE_STEEP) != 0; } /** * Checks for non-continuous slope on halftile foundations. * * @param s The given #Slope. * @return True if the slope is non-continuous, else false. */ static inline bool IsHalftileSlope(Slope s) { return (s & SLOPE_HALFTILE) != 0; } /** * Removes a halftile slope from a slope * * Non-halftile slopes remain unmodified. * * @param s A #Slope. * @return The slope s without its halftile slope. */ static inline Slope RemoveHalftileSlope(Slope s) { return s & ~SLOPE_HALFTILE_MASK; } /** * Return the complement of a slope. * * This method returns the complement of a slope. The complement of a * slope is a slope with raised corner which aren't raised in the given * slope. * * @pre The slope must neither be steep nor a halftile slope. * @param s The #Slope to get the complement. * @return a complement Slope of the given slope. */ static inline Slope ComplementSlope(Slope s) { assert(!IsSteepSlope(s) && !IsHalftileSlope(s)); return s ^ SLOPE_ELEVATED; } /** * Tests if a specific slope has exactly one corner raised. * * @param s The #Slope * @return true iff exactly one corner is raised */ static inline bool IsSlopeWithOneCornerRaised(Slope s) { return (s == SLOPE_W) || (s == SLOPE_S) || (s == SLOPE_E) || (s == SLOPE_N); } /** * Returns the slope with a specific corner raised. * * @param corner The #Corner. * @return The #Slope with corner "corner" raised. */ static inline Slope SlopeWithOneCornerRaised(Corner corner) { assert(IsValidCorner(corner)); return (Slope)(1 << corner); } /** * Tests if a slope has a highest corner (i.e. one corner raised or a steep slope). * * Note: A halftile slope is ignored. * * @param s The #Slope. * @return true iff the slope has a highest corner. */ static inline bool HasSlopeHighestCorner(Slope s) { s = RemoveHalftileSlope(s); return IsSteepSlope(s) || IsSlopeWithOneCornerRaised(s); } /** * Returns the highest corner of a slope (one corner raised or a steep slope). * * @pre The slope must be a slope with one corner raised or a steep slope. A halftile slope is ignored. * @param s The #Slope. * @return Highest corner. */ static inline Corner GetHighestSlopeCorner(Slope s) { switch (RemoveHalftileSlope(s)) { case SLOPE_W: case SLOPE_STEEP_W: return CORNER_W; case SLOPE_S: case SLOPE_STEEP_S: return CORNER_S; case SLOPE_E: case SLOPE_STEEP_E: return CORNER_E; case SLOPE_N: case SLOPE_STEEP_N: return CORNER_N; default: NOT_REACHED(); } } /** * Returns the leveled halftile of a halftile slope. * * @pre The slope must be a halftile slope. * @param s The #Slope. * @return The corner of the leveled halftile. */ static inline Corner GetHalftileSlopeCorner(Slope s) { assert(IsHalftileSlope(s)); return (Corner)((s >> 6) & 3); } /** * Returns the height of the highest corner of a slope relative to TileZ (= minimal height) * * @param s The #Slope. * @return Relative height of highest corner. */ static inline int GetSlopeMaxZ(Slope s) { if (s == SLOPE_FLAT) return 0; if (IsSteepSlope(s)) return 2; return 1; } /** * Returns the height of the highest corner of a slope relative to TileZ (= minimal height) * * @param s The #Slope. * @return Relative height of highest corner. */ static inline int GetSlopeMaxPixelZ(Slope s) { return GetSlopeMaxZ(s) * TILE_HEIGHT; } /** * Returns the opposite corner. * * @param corner A #Corner. * @return The opposite corner to "corner". */ static inline Corner OppositeCorner(Corner corner) { return (Corner)(corner ^ 2); } /** * Tests if a specific slope has exactly three corners raised. * * @param s The #Slope * @return true iff exactly three corners are raised */ static inline bool IsSlopeWithThreeCornersRaised(Slope s) { return !IsHalftileSlope(s) && !IsSteepSlope(s) && IsSlopeWithOneCornerRaised(ComplementSlope(s)); } /** * Returns the slope with all except one corner raised. * * @param corner The #Corner. * @return The #Slope with all corners but "corner" raised. */ static inline Slope SlopeWithThreeCornersRaised(Corner corner) { return ComplementSlope(SlopeWithOneCornerRaised(corner)); } /** * Returns a specific steep slope * * @param corner A #Corner. * @return The steep #Slope with "corner" as highest corner. */ static inline Slope SteepSlope(Corner corner) { return SLOPE_STEEP | SlopeWithThreeCornersRaised(OppositeCorner(corner)); } /** * Tests if a specific slope is an inclined slope. * * @param s The #Slope * @return true iff the slope is inclined. */ static inline bool IsInclinedSlope(Slope s) { return (s == SLOPE_NW) || (s == SLOPE_SW) || (s == SLOPE_SE) || (s == SLOPE_NE); } /** * Returns the direction of an inclined slope. * * @param s A #Slope * @return The direction the slope goes up in. Or INVALID_DIAGDIR if the slope is not an inclined slope. */ static inline DiagDirection GetInclinedSlopeDirection(Slope s) { switch (s) { case SLOPE_NE: return DIAGDIR_NE; case SLOPE_SE: return DIAGDIR_SE; case SLOPE_SW: return DIAGDIR_SW; case SLOPE_NW: return DIAGDIR_NW; default: return INVALID_DIAGDIR; } } /** * Returns the slope that is inclined in a specific direction. * * @param dir A #DiagDirection * @return The #Slope that goes up in direction dir. */ static inline Slope InclinedSlope(DiagDirection dir) { switch (dir) { case DIAGDIR_NE: return SLOPE_NE; case DIAGDIR_SE: return SLOPE_SE; case DIAGDIR_SW: return SLOPE_SW; case DIAGDIR_NW: return SLOPE_NW; default: NOT_REACHED(); } } /** * Adds a halftile slope to a slope. * * @param s #Slope without a halftile slope. * @param corner The #Corner of the halftile. * @return The #Slope s with the halftile slope added. */ static inline Slope HalftileSlope(Slope s, Corner corner) { assert(IsValidCorner(corner)); return (Slope)(s | SLOPE_HALFTILE | (corner << 6)); } /** * Tests for FOUNDATION_NONE. * * @param f Maybe a #Foundation. * @return true iff f is a foundation. */ static inline bool IsFoundation(Foundation f) { return f != FOUNDATION_NONE; } /** * Tests if the foundation is a leveled foundation. * * @param f The #Foundation. * @return true iff f is a leveled foundation. */ static inline bool IsLeveledFoundation(Foundation f) { return f == FOUNDATION_LEVELED; } /** * Tests if the foundation is an inclined foundation. * * @param f The #Foundation. * @return true iff f is an inclined foundation. */ static inline bool IsInclinedFoundation(Foundation f) { return (f == FOUNDATION_INCLINED_X) || (f == FOUNDATION_INCLINED_Y); } /** * Tests if a foundation is a non-continuous foundation, i.e. halftile-foundation or FOUNDATION_STEEP_BOTH. * * @param f The #Foundation. * @return true iff f is a non-continuous foundation */ static inline bool IsNonContinuousFoundation(Foundation f) { return IsInsideMM(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1); } /** * Returns the halftile corner of a halftile-foundation * * @pre f != FOUNDATION_STEEP_BOTH * * @param f The #Foundation. * @return The #Corner with track. */ static inline Corner GetHalftileFoundationCorner(Foundation f) { assert(IsInsideMM(f, FOUNDATION_HALFTILE_W, FOUNDATION_HALFTILE_N + 1)); return (Corner)(f - FOUNDATION_HALFTILE_W); } /** * Tests if a foundation is a special rail foundation for single horizontal/vertical track. * * @param f The #Foundation. * @return true iff f is a special rail foundation for single horizontal/vertical track. */ static inline bool IsSpecialRailFoundation(Foundation f) { return IsInsideMM(f, FOUNDATION_RAIL_W, FOUNDATION_RAIL_N + 1); } /** * Returns the track corner of a special rail foundation * * @param f The #Foundation. * @return The #Corner with track. */ static inline Corner GetRailFoundationCorner(Foundation f) { assert(IsSpecialRailFoundation(f)); return (Corner)(f - FOUNDATION_RAIL_W); } /** * Returns the foundation needed to flatten a slope. * The returned foundation is either FOUNDATION_NONE if the tile was already flat, or FOUNDATION_LEVELED. * * @param s The current #Slope. * @return The needed #Foundation. */ static inline Foundation FlatteningFoundation(Slope s) { return (s == SLOPE_FLAT ? FOUNDATION_NONE : FOUNDATION_LEVELED); } /** * Returns the along a specific axis inclined foundation. * * @param axis The #Axis. * @return The needed #Foundation. */ static inline Foundation InclinedFoundation(Axis axis) { return (axis == AXIS_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y); } /** * Returns the halftile foundation for single horizontal/vertical track. * * @param corner The #Corner with the track. * @return The wanted #Foundation. */ static inline Foundation HalftileFoundation(Corner corner) { assert(IsValidCorner(corner)); return (Foundation)(FOUNDATION_HALFTILE_W + corner); } /** * Returns the special rail foundation for single horizontal/vertical track. * * @param corner The #Corner with the track. * @return The wanted #Foundation. */ static inline Foundation SpecialRailFoundation(Corner corner) { assert(IsValidCorner(corner)); return (Foundation)(FOUNDATION_RAIL_W + corner); } /** * Returns the #Sprite offset for a given #Slope. * * @param s The #Slope to get the offset for. * @return The sprite offset for this #Slope. */ static inline uint SlopeToSpriteOffset(Slope s) { extern const byte _slope_to_sprite_offset[32]; return _slope_to_sprite_offset[s]; } #endif /* SLOPE_FUNC_H */ openttd-1.5.3/src/date_type.h0000644000000000000000000001151412627373441014624 0ustar rootroot/* $Id: date_type.h 25260 2013-05-19 14:26:14Z rubidium $ */ /* * 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 date_type.h Types related to the dates in OpenTTD. */ #ifndef DATE_TYPE_H #define DATE_TYPE_H typedef int32 Date; ///< The type to store our dates in typedef uint16 DateFract; ///< The fraction of a date we're in, i.e. the number of ticks since the last date changeover typedef int32 Ticks; ///< The type to store ticks in typedef int32 Year; ///< Type for the year, note: 0 based, i.e. starts at the year 0. typedef uint8 Month; ///< Type for the month, note: 0 based, i.e. 0 = January, 11 = December. typedef uint8 Day; ///< Type for the day of the month, note: 1 based, first day of a month is 1. /** * 1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885. On * an overflow the new day begun and 65535 / 885 = 74. * 1 tick is approximately 30 ms. * 1 day is thus about 2 seconds (74 * 30 = 2220) on a machine that can run OpenTTD normally */ static const int DAY_TICKS = 74; ///< ticks per day static const int DAYS_IN_YEAR = 365; ///< days per year static const int DAYS_IN_LEAP_YEAR = 366; ///< sometimes, you need one day more... static const int STATION_RATING_TICKS = 185; ///< cycle duration for updating station rating static const int STATION_ACCEPTANCE_TICKS = 250; ///< cycle duration for updating station acceptance static const int STATION_LINKGRAPH_TICKS = 504; ///< cycle duration for cleaning dead links static const int CARGO_AGING_TICKS = 185; ///< cycle duration for aging cargo static const int INDUSTRY_PRODUCE_TICKS = 256; ///< cycle duration for industry production static const int TOWN_GROWTH_TICKS = 70; ///< cycle duration for towns trying to grow. (this originates from the size of the town array in TTD static const int INDUSTRY_CUT_TREE_TICKS = INDUSTRY_PRODUCE_TICKS * 2; ///< cycle duration for lumber mill's extra action /* * ORIGINAL_BASE_YEAR, ORIGINAL_MAX_YEAR and DAYS_TILL_ORIGINAL_BASE_YEAR are * primarily used for loading newgrf and savegame data and returning some * newgrf (callback) functions that were in the original (TTD) inherited * format, where '_date == 0' meant that it was 1920-01-01. */ /** The minimum starting year/base year of the original TTD */ static const Year ORIGINAL_BASE_YEAR = 1920; /** The original ending year */ static const Year ORIGINAL_END_YEAR = 2051; /** The maximum year of the original TTD */ static const Year ORIGINAL_MAX_YEAR = 2090; /** * Calculate the number of leap years till a given year. * * Each passed leap year adds one day to the 'day count'. * * A special case for the year 0 as no year has been passed, * but '(year - 1) / 4' does not yield '-1' to counteract the * '+1' at the end of the formula as divisions round to zero. * * @param year the year to get the leap years till. * @return the number of leap years. */ #define LEAP_YEARS_TILL(year) ((year) == 0 ? 0 : ((year) - 1) / 4 - ((year) - 1) / 100 + ((year) - 1) / 400 + 1) /** * Calculate the date of the first day of a given year. * @param year the year to get the first day of. * @return the date. */ #define DAYS_TILL(year) (DAYS_IN_YEAR * (year) + LEAP_YEARS_TILL(year)) /** * The offset in days from the '_date == 0' till * 'ConvertYMDToDate(ORIGINAL_BASE_YEAR, 0, 1)' */ #define DAYS_TILL_ORIGINAL_BASE_YEAR DAYS_TILL(ORIGINAL_BASE_YEAR) /** The absolute minimum & maximum years in OTTD */ static const Year MIN_YEAR = 0; /** The default starting year */ static const Year DEF_START_YEAR = 1950; /** * MAX_YEAR, nicely rounded value of the number of years that can * be encoded in a single 32 bits date, about 2^31 / 366 years. */ static const Year MAX_YEAR = 5000000; /** The number of days till the last day */ #define MAX_DAY (DAYS_TILL(MAX_YEAR + 1) - 1) /** * Data structure to convert between Date and triplet (year, month, and day). * @see ConvertDateToYMD(), ConvertYMDToDate() */ struct YearMonthDay { Year year; ///< Year (0...) Month month; ///< Month (0..11) Day day; ///< Day (1..31) }; static const Year INVALID_YEAR = -1; ///< Representation of an invalid year static const Date INVALID_DATE = -1; ///< Representation of an invalid date static const Ticks INVALID_TICKS = -1; ///< Representation of an invalid number of ticks #endif /* DATE_TYPE_H */ openttd-1.5.3/src/goal_type.h0000644000000000000000000000325512627373442014635 0ustar rootroot/* $Id: goal_type.h 26012 2013-11-16 17:41:57Z zuu $ */ /* * 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 goal_type.h basic types related to goals */ #ifndef GOAL_TYPE_H #define GOAL_TYPE_H #include "core/enum_type.hpp" static const uint32 GOAL_QUESTION_BUTTON_COUNT = 18; ///< Amount of buttons available. static const byte GOAL_QUESTION_TYPE_COUNT = 4; ///< Amount of question types. /** Types of goal destinations */ enum GoalType { GT_NONE, ///< Destination is not linked GT_TILE, ///< Destination is a tile GT_INDUSTRY, ///< Destination is an industry GT_TOWN, ///< Destination is a town GT_COMPANY, ///< Destination is a company GT_STORY_PAGE, ///< Destination is a story page }; typedef SimpleTinyEnumT GoalTypeByte; ///< The GoalType packed into a byte for savegame purposes. typedef uint32 GoalTypeID; ///< Contains either tile, industry ID, town ID or company ID (or INVALID_GOALTYPE) static const GoalTypeID INVALID_GOALTYPE = 0xFFFFFFFF; ///< Invalid/unknown index of GoalType typedef uint16 GoalID; ///< ID of a goal struct Goal; extern GoalID _new_goal_id; #endif /* GOAL_TYPE_H */ openttd-1.5.3/src/aircraft_cmd.cpp0000644000000000000000000020375612627373435015635 0ustar rootroot/* $Id: aircraft_cmd.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 aircraft_cmd.cpp * This file deals with aircraft and airport movements functionalities */ #include "stdafx.h" #include "aircraft.h" #include "landscape.h" #include "news_func.h" #include "newgrf_engine.h" #include "newgrf_sound.h" #include "spritecache.h" #include "strings_func.h" #include "command_func.h" #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "cheat_type.h" #include "company_base.h" #include "ai/ai.hpp" #include "game/game.hpp" #include "company_func.h" #include "effectvehicle_func.h" #include "station_base.h" #include "engine_base.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "zoom_func.h" #include "disaster_vehicle.h" #include "table/strings.h" #include "safeguards.h" void Aircraft::UpdateDeltaXY(Direction direction) { this->x_offs = -1; this->y_offs = -1; this->x_extent = 2; this->y_extent = 2; switch (this->subtype) { default: NOT_REACHED(); case AIR_AIRCRAFT: case AIR_HELICOPTER: switch (this->state) { default: break; case ENDTAKEOFF: case LANDING: case HELILANDING: case FLYING: this->x_extent = 24; this->y_extent = 24; break; } this->z_extent = 5; break; case AIR_SHADOW: this->z_extent = 1; this->x_offs = 0; this->y_offs = 0; break; case AIR_ROTOR: this->z_extent = 1; break; } } static bool AirportMove(Aircraft *v, const AirportFTAClass *apc); static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc); static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc); static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc); static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc); static void CrashAirplane(Aircraft *v); static const SpriteID _aircraft_sprite[] = { 0x0EB5, 0x0EBD, 0x0EC5, 0x0ECD, 0x0ED5, 0x0EDD, 0x0E9D, 0x0EA5, 0x0EAD, 0x0EE5, 0x0F05, 0x0F0D, 0x0F15, 0x0F1D, 0x0F25, 0x0F2D, 0x0EED, 0x0EF5, 0x0EFD, 0x0F35, 0x0E9D, 0x0EA5, 0x0EAD, 0x0EB5, 0x0EBD, 0x0EC5 }; template <> bool IsValidImageIndex(uint8 image_index) { return image_index < lengthof(_aircraft_sprite); } /** Helicopter rotor animation states */ enum HelicopterRotorStates { HRS_ROTOR_STOPPED, HRS_ROTOR_MOVING_1, HRS_ROTOR_MOVING_2, HRS_ROTOR_MOVING_3, }; /** * Find the nearest hangar to v * INVALID_STATION is returned, if the company does not have any suitable * airports (like helipads only) * @param v vehicle looking for a hangar * @return the StationID if one is found, otherwise, INVALID_STATION */ static StationID FindNearestHangar(const Aircraft *v) { const Station *st; uint best = 0; StationID index = INVALID_STATION; TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos); const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type); FOR_ALL_STATIONS(st) { if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT)) continue; const AirportFTAClass *afc = st->airport.GetFTA(); if (!st->airport.HasHangar() || ( /* don't crash the plane if we know it can't land at the airport */ (afc->flags & AirportFTAClass::SHORT_STRIP) && (avi->subtype & AIR_FAST) && !_cheats.no_jetcrash.value)) { continue; } /* v->tile can't be used here, when aircraft is flying v->tile is set to 0 */ uint distance = DistanceSquare(vtile, st->airport.tile); if (v->acache.cached_max_range_sqr != 0) { /* Check if our current destination can be reached from the depot airport. */ const Station *cur_dest = GetTargetAirportIfValid(v); if (cur_dest != NULL && DistanceSquare(st->airport.tile, cur_dest->airport.tile) > v->acache.cached_max_range_sqr) continue; } if (distance < best || index == INVALID_STATION) { best = distance; index = st->index; } } return index; } SpriteID Aircraft::GetImage(Direction direction, EngineImageType image_type) const { uint8 spritenum = this->spritenum; if (is_custom_sprite(spritenum)) { SpriteID sprite = GetCustomVehicleSprite(this, direction, image_type); if (sprite != 0) return sprite; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); return direction + _aircraft_sprite[spritenum]; } SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type) { assert(v->subtype == AIR_HELICOPTER); const Aircraft *w = v->Next()->Next(); if (is_custom_sprite(v->spritenum)) { SpriteID sprite = GetCustomRotorSprite(v, false, image_type); if (sprite != 0) return sprite; } /* Return standard rotor sprites if there are no custom sprites for this helicopter */ return SPR_ROTOR_STOPPED + w->state; } static SpriteID GetAircraftIcon(EngineID engine, EngineImageType image_type) { const Engine *e = Engine::Get(engine); uint8 spritenum = e->u.air.image_index; if (is_custom_sprite(spritenum)) { SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type); if (sprite != 0) return sprite; spritenum = e->original_image_index; } assert(IsValidImageIndex(spritenum)); return DIR_W + _aircraft_sprite[spritenum]; } void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { SpriteID sprite = GetAircraftIcon(engine, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); preferred_x = Clamp(preferred_x, left - UnScaleGUI(real_sprite->x_offs), right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); DrawSprite(sprite, pal, preferred_x, y); if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) { SpriteID rotor_sprite = GetCustomRotorIcon(engine, image_type); if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED; DrawSprite(rotor_sprite, PAL_NONE, preferred_x, y - ScaleGUITrad(5)); } } /** * Get the size of the sprite of an aircraft sprite heading west (used for lists). * @param engine The engine to get the sprite from. * @param[out] width The width of the sprite. * @param[out] height The height of the sprite. * @param[out] xoffs Number of pixels to shift the sprite to the right. * @param[out] yoffs Number of pixels to shift the sprite downwards. * @param image_type Context the sprite is used in. */ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) { const Sprite *spr = GetSprite(GetAircraftIcon(engine, image_type), ST_NORMAL); width = UnScaleGUI(spr->width); height = UnScaleGUI(spr->height); xoffs = UnScaleGUI(spr->x_offs); yoffs = UnScaleGUI(spr->y_offs); } /** * Build an aircraft. * @param tile tile of the depot where aircraft is built. * @param flags type of operation. * @param e the engine to build. * @param data unused. * @param ret[out] the vehicle that has been built. * @return the cost of this operation or an error. */ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret) { const AircraftVehicleInfo *avi = &e->u.air; const Station *st = Station::GetByTile(tile); /* Prevent building aircraft types at places which can't handle them */ if (!CanVehicleUseStation(e->index, st)) return CMD_ERROR; /* Make sure all aircraft end up in the first tile of the hangar. */ tile = st->airport.GetHangarTile(st->airport.GetHangarNum(tile)); if (flags & DC_EXEC) { Aircraft *v = new Aircraft(); // aircraft Aircraft *u = new Aircraft(); // shadow *ret = v; v->direction = DIR_SE; v->owner = u->owner = _current_company; v->tile = tile; uint x = TileX(tile) * TILE_SIZE + 5; uint y = TileY(tile) * TILE_SIZE + 3; v->x_pos = u->x_pos = x; v->y_pos = u->y_pos = y; u->z_pos = GetSlopePixelZ(x, y); v->z_pos = u->z_pos + 1; v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_SHADOW; v->spritenum = avi->image_index; v->cargo_cap = avi->passenger_capacity; v->refit_cap = 0; u->cargo_cap = avi->mail_capacity; u->refit_cap = 0; v->cargo_type = e->GetDefaultCargoType(); u->cargo_type = CT_MAIL; v->name = NULL; v->last_station_visited = INVALID_STATION; v->last_loading_station = INVALID_STATION; v->acceleration = avi->acceleration; v->engine_type = e->index; u->engine_type = e->index; v->subtype = (avi->subtype & AIR_CTOL ? AIR_AIRCRAFT : AIR_HELICOPTER); v->UpdateDeltaXY(INVALID_DIR); u->subtype = AIR_SHADOW; u->UpdateDeltaXY(INVALID_DIR); v->reliability = e->reliability; v->reliability_spd_dec = e->reliability_spd_dec; v->max_age = e->GetLifeLengthInDays(); _new_vehicle_id = v->index; v->pos = GetVehiclePosOnBuild(tile); v->state = HANGAR; v->previous_pos = v->pos; v->targetairport = GetStationIndex(tile); v->SetNext(u); v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft); v->date_of_last_service = _date; v->build_year = u->build_year = _cur_year; v->cur_image = u->cur_image = SPR_IMG_QUERY; v->random_bits = VehicleRandomBits(); u->random_bits = VehicleRandomBits(); v->vehicle_flags = 0; if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); v->InvalidateNewGRFCacheOfChain(); v->cargo_cap = e->DetermineCapacity(v, &u->cargo_cap); v->InvalidateNewGRFCacheOfChain(); UpdateAircraftCache(v, true); v->UpdatePosition(); u->UpdatePosition(); /* Aircraft with 3 vehicles (chopper)? */ if (v->subtype == AIR_HELICOPTER) { Aircraft *w = new Aircraft(); w->engine_type = e->index; w->direction = DIR_N; w->owner = _current_company; w->x_pos = v->x_pos; w->y_pos = v->y_pos; w->z_pos = v->z_pos + ROTOR_Z_OFFSET; w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE; w->spritenum = 0xFF; w->subtype = AIR_ROTOR; w->cur_image = SPR_ROTOR_STOPPED; w->random_bits = VehicleRandomBits(); /* Use rotor's air.state to store the rotor animation frame */ w->state = HRS_ROTOR_STOPPED; w->UpdateDeltaXY(INVALID_DIR); u->SetNext(w); w->UpdatePosition(); } } return CommandCost(); } bool Aircraft::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { const Station *st = GetTargetAirportIfValid(this); /* If the station is not a valid airport or if it has no hangars */ if (st == NULL || !st->airport.HasHangar()) { /* the aircraft has to search for a hangar on its own */ StationID station = FindNearestHangar(this); if (station == INVALID_STATION) return false; st = Station::Get(station); } if (location != NULL) *location = st->xy; if (destination != NULL) *destination = st->index; return true; } static void CheckIfAircraftNeedsService(Aircraft *v) { if (Company::Get(v->owner)->settings.vehicle.servint_aircraft == 0 || !v->NeedsAutomaticServicing()) return; if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } /* When we're parsing conditional orders and the like * we don't want to consider going to a depot too. */ if (!v->current_order.IsType(OT_GOTO_DEPOT) && !v->current_order.IsType(OT_GOTO_STATION)) return; const Station *st = Station::Get(v->current_order.GetDestination()); assert(st != NULL); /* only goto depot if the target airport has a depot */ if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) { v->current_order.MakeGoToDepot(st->index, ODTFB_SERVICE); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } else if (v->current_order.IsType(OT_GOTO_DEPOT)) { v->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } } Money Aircraft::GetRunningCost() const { const Engine *e = this->GetEngine(); uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->u.air.running_cost); return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF()); } void Aircraft::OnNewDay() { if (!this->IsNormalAircraft()) return; if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this); CheckOrders(this); CheckVehicleBreakdown(this); AgeVehicle(this); CheckIfAircraftNeedsService(this); if (this->running_ticks == 0) return; CommandCost cost(EXPENSES_AIRCRAFT_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS)); this->profit_this_year -= cost.GetCost(); this->running_ticks = 0; SubtractMoneyFromCompanyFract(this->owner, cost); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); SetWindowClassesDirty(WC_AIRCRAFT_LIST); } static void HelicopterTickHandler(Aircraft *v) { Aircraft *u = v->Next()->Next(); if (u->vehstatus & VS_HIDDEN) return; /* if true, helicopter rotors do not rotate. This should only be the case if a helicopter is * loading/unloading at a terminal or stopped */ if (v->current_order.IsType(OT_LOADING) || (v->vehstatus & VS_STOPPED)) { if (u->cur_speed != 0) { u->cur_speed++; if (u->cur_speed >= 0x80 && u->state == HRS_ROTOR_MOVING_3) { u->cur_speed = 0; } } } else { if (u->cur_speed == 0) { u->cur_speed = 0x70; } if (u->cur_speed >= 0x50) { u->cur_speed--; } } int tick = ++u->tick_counter; int spd = u->cur_speed >> 4; SpriteID img; if (spd == 0) { u->state = HRS_ROTOR_STOPPED; img = GetRotorImage(v, EIT_ON_MAP); if (u->cur_image == img) return; } else if (tick >= spd) { u->tick_counter = 0; u->state++; if (u->state > HRS_ROTOR_MOVING_3) u->state = HRS_ROTOR_MOVING_1; img = GetRotorImage(v, EIT_ON_MAP); } else { return; } u->cur_image = img; u->UpdatePositionAndViewport(); } /** * Set aircraft position. * @param v Aircraft to position. * @param x New X position. * @param y New y position. * @param z New z position. */ void SetAircraftPosition(Aircraft *v, int x, int y, int z) { v->x_pos = x; v->y_pos = y; v->z_pos = z; v->UpdatePosition(); v->UpdateViewport(true, false); if (v->subtype == AIR_HELICOPTER) v->Next()->Next()->cur_image = GetRotorImage(v, EIT_ON_MAP); Aircraft *u = v->Next(); int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); int safe_y = Clamp(y - 1, 0, MapMaxY() * TILE_SIZE); u->x_pos = x; u->y_pos = y - ((v->z_pos - GetSlopePixelZ(safe_x, safe_y)) >> 3); safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE); u->z_pos = GetSlopePixelZ(safe_x, safe_y); u->cur_image = v->cur_image; u->UpdatePositionAndViewport(); u = u->Next(); if (u != NULL) { u->x_pos = x; u->y_pos = y; u->z_pos = z + ROTOR_Z_OFFSET; u->UpdatePositionAndViewport(); } } /** * Handle Aircraft specific tasks when an Aircraft enters a hangar * @param *v Vehicle that enters the hangar */ void HandleAircraftEnterHangar(Aircraft *v) { v->subspeed = 0; v->progress = 0; Aircraft *u = v->Next(); u->vehstatus |= VS_HIDDEN; u = u->Next(); if (u != NULL) { u->vehstatus |= VS_HIDDEN; u->cur_speed = 0; } SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); } static void PlayAircraftSound(const Vehicle *v) { if (!PlayVehicleSound(v, VSE_START)) { SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v); } } /** * Update cached values of an aircraft. * Currently caches callback 36 max speed. * @param v Vehicle * @param update_range Update the aircraft range. */ void UpdateAircraftCache(Aircraft *v, bool update_range) { uint max_speed = GetVehicleProperty(v, PROP_AIRCRAFT_SPEED, 0); if (max_speed != 0) { /* Convert from original units to km-ish/h */ max_speed = (max_speed * 128) / 10; v->vcache.cached_max_speed = max_speed; } else { /* Use the default max speed of the vehicle. */ v->vcache.cached_max_speed = AircraftVehInfo(v->engine_type)->max_speed; } /* Update cargo aging period. */ v->vcache.cached_cargo_age_period = GetVehicleProperty(v, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(v->engine_type)->cargo_age_period); Aircraft *u = v->Next(); // Shadow for mail u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_AIRCRAFT_CARGO_AGE_PERIOD, EngInfo(u->engine_type)->cargo_age_period); /* Update aircraft range. */ if (update_range) { v->acache.cached_max_range = GetVehicleProperty(v, PROP_AIRCRAFT_RANGE, AircraftVehInfo(v->engine_type)->max_range); /* Squared it now so we don't have to do it later all the time. */ v->acache.cached_max_range_sqr = v->acache.cached_max_range * v->acache.cached_max_range; } } /** * Special velocities for aircraft */ enum AircraftSpeedLimits { SPEED_LIMIT_TAXI = 50, ///< Maximum speed of an aircraft while taxiing SPEED_LIMIT_APPROACH = 230, ///< Maximum speed of an aircraft on finals SPEED_LIMIT_BROKEN = 320, ///< Maximum speed of an aircraft that is broken SPEED_LIMIT_HOLD = 425, ///< Maximum speed of an aircraft that flies the holding pattern SPEED_LIMIT_NONE = 0xFFFF, ///< No environmental speed limit. Speed limit is type dependent }; /** * Sets the new speed for an aircraft * @param v The vehicle for which the speed should be obtained * @param speed_limit The maximum speed the vehicle may have. * @param hard_limit If true, the limit is directly enforced, otherwise the plane is slowed down gradually * @return The number of position updates needed within the tick */ static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE, bool hard_limit = true) { /** * 'acceleration' has the unit 3/8 mph/tick. This function is called twice per tick. * So the speed amount we need to accelerate is: * acceleration * 3 / 16 mph = acceleration * 3 / 16 * 16 / 10 km-ish/h * = acceleration * 3 / 10 * 256 * (km-ish/h / 256) * ~ acceleration * 77 (km-ish/h / 256) */ uint spd = v->acceleration * 77; byte t; /* Adjust speed limits by plane speed factor to prevent taxiing * and take-off speeds being too low. */ speed_limit *= _settings_game.vehicle.plane_speed; if (v->vcache.cached_max_speed < speed_limit) { if (v->cur_speed < speed_limit) hard_limit = false; speed_limit = v->vcache.cached_max_speed; } v->subspeed = (t = v->subspeed) + (byte)spd; /* Aircraft's current speed is used twice so that very fast planes are * forced to slow down rapidly in the short distance needed. The magic * value 16384 was determined to give similar results to the old speed/48 * method at slower speeds. This also results in less reduction at slow * speeds to that aircraft do not get to taxi speed straight after * touchdown. */ if (!hard_limit && v->cur_speed > speed_limit) { speed_limit = v->cur_speed - max(1, ((v->cur_speed * v->cur_speed) / 16384) / _settings_game.vehicle.plane_speed); } 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); /* 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, WID_VV_START_STOP); } /* Adjust distance moved by plane speed setting */ if (_settings_game.vehicle.plane_speed > 1) spd /= _settings_game.vehicle.plane_speed; /* Convert direction-independent speed into direction-dependent speed. (old movement method) */ spd = v->GetOldAdvanceSpeed(spd); spd += v->progress; v->progress = (byte)spd; return spd >> 8; } /** * Get the tile height below the aircraft. * This function is needed because aircraft can leave the mapborders. * * @param v The vehicle to get the height for. * @return The height in pixels from 'z_pos' 0. */ int GetTileHeightBelowAircraft(const Vehicle *v) { int safe_x = Clamp(v->x_pos, 0, MapMaxX() * TILE_SIZE); int safe_y = Clamp(v->y_pos, 0, MapMaxY() * TILE_SIZE); return TileHeight(TileVirtXY(safe_x, safe_y)) * TILE_HEIGHT; } /** * Get the 'flight level' bounds, in pixels from 'z_pos' 0 for a particular * vehicle for normal flight situation. * When the maximum is reached the vehicle should consider descending. * When the minimum is reached the vehicle should consider ascending. * * @param v The vehicle to get the flight levels for. * @param [out] min_level The minimum bounds for flight level. * @param [out] max_level The maximum bounds for flight level. */ void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_level) { int base_altitude = GetTileHeightBelowAircraft(v); if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->subtype == AIR_HELICOPTER) { base_altitude += HELICOPTER_HOLD_MAX_FLYING_ALTITUDE - PLANE_HOLD_MAX_FLYING_ALTITUDE; } /* Make sure eastbound and westbound planes do not "crash" into each * other by providing them with vertical separation */ switch (v->direction) { case DIR_N: case DIR_NE: case DIR_E: case DIR_SE: base_altitude += 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, 0); if (min_level != NULL) *min_level = base_altitude + AIRCRAFT_MIN_FLYING_ALTITUDE; if (max_level != NULL) *max_level = base_altitude + AIRCRAFT_MAX_FLYING_ALTITUDE; } /** * Gets the maximum 'flight level' for the holding pattern of the aircraft, * in pixels 'z_pos' 0, depending on terrain below.. * * @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. */ int GetAircraftHoldMaxAltitude(const Aircraft *v) { int tile_height = GetTileHeightBelowAircraft(v); return tile_height + ((v->subtype == AIR_HELICOPTER) ? HELICOPTER_HOLD_MAX_FLYING_ALTITUDE : PLANE_HOLD_MAX_FLYING_ALTITUDE); } template int GetAircraftFlightLevel(T *v, bool takeoff) { /* Aircraft is in flight. We want to enforce it being somewhere * between the minimum and the maximum allowed altitude. */ int aircraft_min_altitude; int aircraft_max_altitude; GetAircraftFlightLevelBounds(v, &aircraft_min_altitude, &aircraft_max_altitude); int aircraft_middle_altitude = (aircraft_min_altitude + aircraft_max_altitude) / 2; /* If those assumptions would be violated, aircrafts would behave fairly strange. */ assert(aircraft_min_altitude < aircraft_middle_altitude); assert(aircraft_middle_altitude < aircraft_max_altitude); int z = v->z_pos; if (z < aircraft_min_altitude || (HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z < aircraft_middle_altitude)) { /* Ascend. 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. */ SetBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION); z += takeoff ? 2 : 1; } else if (!takeoff && (z > aircraft_max_altitude || (HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z > aircraft_middle_altitude))) { /* Descend lower. You are an aircraft, not an space ship. * And again, don't stop correcting altitude too early. */ SetBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION); z--; } else if (HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z >= aircraft_middle_altitude) { /* Now, we have corrected altitude enough. */ ClrBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION); } else if (HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z <= aircraft_middle_altitude) { /* Now, we have corrected altitude enough. */ ClrBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION); } return z; } template int GetAircraftFlightLevel(DisasterVehicle *v, bool takeoff); /** * Find the entry point to an airport depending on direction which * the airport is being approached from. Each airport can have up to * four entry points for its approach system so that approaching * aircraft do not fly through each other or are forced to do 180 * degree turns during the approach. The arrivals are grouped into * four sectors dependent on the DiagDirection from which the airport * is approached. * * @param v The vehicle that is approaching the airport * @param apc The Airport Class being approached. * @param rotation The rotation of the airport. * @return The index of the entry point */ static byte AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, Direction rotation) { assert(v != NULL); assert(apc != NULL); /* In the case the station doesn't exit anymore, set target tile 0. * It doesn't hurt much, aircraft will go to next order, nearest hangar * or it will simply crash in next tick */ TileIndex tile = 0; const Station *st = Station::GetIfValid(v->targetairport); if (st != NULL) { /* Make sure we don't go to INVALID_TILE if the airport has been removed. */ tile = (st->airport.tile != INVALID_TILE) ? st->airport.tile : st->xy; } int delta_x = v->x_pos - TileX(tile) * TILE_SIZE; int delta_y = v->y_pos - TileY(tile) * TILE_SIZE; DiagDirection dir; if (abs(delta_y) < abs(delta_x)) { /* We are northeast or southwest of the airport */ dir = delta_x < 0 ? DIAGDIR_NE : DIAGDIR_SW; } else { /* We are northwest or southeast of the airport */ dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE; } dir = ChangeDiagDir(dir, DiagDirDifference(DIAGDIR_NE, DirToDiagDir(rotation))); return apc->entry_points[dir]; } static void MaybeCrashAirplane(Aircraft *v); /** * Controls the movement of an aircraft. This function actually moves the vehicle * on the map and takes care of minor things like sound playback. * @todo De-mystify the cur_speed values for helicopter rotors. * @param v The vehicle that is moved. Must be the first vehicle of the chain * @return Whether the position requested by the State Machine has been reached */ static bool AircraftController(Aircraft *v) { int count; /* NULL if station is invalid */ const Station *st = Station::GetIfValid(v->targetairport); /* INVALID_TILE if there is no station */ TileIndex tile = INVALID_TILE; Direction rotation = DIR_N; uint size_x = 1, size_y = 1; if (st != NULL) { if (st->airport.tile != INVALID_TILE) { tile = st->airport.tile; rotation = st->airport.rotation; size_x = st->airport.w; size_y = st->airport.h; } else { tile = st->xy; } } /* DUMMY if there is no station or no airport */ const AirportFTAClass *afc = tile == INVALID_TILE ? GetAirport(AT_DUMMY) : st->airport.GetFTA(); /* prevent going to INVALID_TILE if airport is deleted. */ if (st == NULL || st->airport.tile == INVALID_TILE) { /* Jump into our "holding pattern" state machine if possible */ if (v->pos >= afc->nofelements) { v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N); } else if (v->targetairport != v->current_order.GetDestination()) { /* If not possible, just get out of here fast */ v->state = FLYING; UpdateAircraftCache(v); AircraftNextAirportPos_and_Order(v); /* get aircraft back on running altitude */ SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlightLevel(v)); return false; } } /* get airport moving data */ const AirportMovingData amd = RotateAirportMovingData(afc->MovingData(v->pos), rotation, size_x, size_y); int x = TileX(tile) * TILE_SIZE; int y = TileY(tile) * TILE_SIZE; /* Helicopter raise */ if (amd.flag & AMED_HELI_RAISE) { Aircraft *u = v->Next()->Next(); /* Make sure the rotors don't rotate too fast */ if (u->cur_speed > 32) { v->cur_speed = 0; if (--u->cur_speed == 32) { if (!PlayVehicleSound(v, VSE_START)) { SndPlayVehicleFx(SND_18_HELICOPTER, v); } } } else { u->cur_speed = 32; count = UpdateAircraftSpeed(v); if (count > 0) { v->tile = 0; int z_dest; GetAircraftFlightLevelBounds(v, &z_dest, NULL); /* Reached altitude? */ if (v->z_pos >= z_dest) { v->cur_speed = 0; return true; } SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, z_dest)); } } return false; } /* Helicopter landing. */ if (amd.flag & AMED_HELI_LOWER) { if (st == NULL) { /* FIXME - AircraftController -> if station no longer exists, do not land * helicopter will circle until sign disappears, then go to next order * what to do when it is the only order left, right now it just stays in 1 place */ v->state = FLYING; UpdateAircraftCache(v); AircraftNextAirportPos_and_Order(v); return false; } /* Vehicle is now at the airport. */ v->tile = tile; /* Find altitude of landing position. */ int z = GetSlopePixelZ(x, y) + 1 + afc->delta_z; if (z == v->z_pos) { Vehicle *u = v->Next()->Next(); /* Increase speed of rotors. When speed is 80, we've landed. */ if (u->cur_speed >= 80) return true; u->cur_speed += 4; } else { count = UpdateAircraftSpeed(v); if (count > 0) { if (v->z_pos > z) { SetAircraftPosition(v, v->x_pos, v->y_pos, max(v->z_pos - count, z)); } else { SetAircraftPosition(v, v->x_pos, v->y_pos, min(v->z_pos + count, z)); } } } return false; } /* Get distance from destination pos to current pos. */ uint dist = abs(x + amd.x - v->x_pos) + abs(y + amd.y - v->y_pos); /* Need exact position? */ if (!(amd.flag & AMED_EXACTPOS) && dist <= (amd.flag & AMED_SLOWTURN ? 8U : 4U)) return true; /* At final pos? */ if (dist == 0) { /* Change direction smoothly to final direction. */ DirDiff dirdiff = DirDifference(amd.direction, v->direction); /* if distance is 0, and plane points in right direction, no point in calling * UpdateAircraftSpeed(). So do it only afterwards */ if (dirdiff == DIRDIFF_SAME) { v->cur_speed = 0; return true; } if (!UpdateAircraftSpeed(v, SPEED_LIMIT_TAXI)) return false; v->direction = ChangeDir(v->direction, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT); v->cur_speed >>= 1; SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); return false; } if (amd.flag & AMED_BRAKE && v->cur_speed > SPEED_LIMIT_TAXI * _settings_game.vehicle.plane_speed) { MaybeCrashAirplane(v); if ((v->vehstatus & VS_CRASHED) != 0) return false; } uint speed_limit = SPEED_LIMIT_TAXI; bool hard_limit = true; if (amd.flag & AMED_NOSPDCLAMP) speed_limit = SPEED_LIMIT_NONE; if (amd.flag & AMED_HOLD) { speed_limit = SPEED_LIMIT_HOLD; hard_limit = false; } if (amd.flag & AMED_LAND) { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; } if (amd.flag & AMED_BRAKE) { speed_limit = SPEED_LIMIT_TAXI; hard_limit = false; } count = UpdateAircraftSpeed(v, speed_limit, hard_limit); if (count == 0) return false; if (v->turn_counter != 0) v->turn_counter--; do { GetNewVehiclePosResult gp; if (dist < 4 || (amd.flag & AMED_LAND)) { /* move vehicle one pixel towards target */ gp.x = (v->x_pos != (x + amd.x)) ? v->x_pos + ((x + amd.x > v->x_pos) ? 1 : -1) : v->x_pos; gp.y = (v->y_pos != (y + amd.y)) ? v->y_pos + ((y + amd.y > v->y_pos) ? 1 : -1) : v->y_pos; /* Oilrigs must keep v->tile as st->airport.tile, since the landing pad is in a non-airport tile */ gp.new_tile = (st->airport.type == AT_OILRIG) ? st->airport.tile : TileVirtXY(gp.x, gp.y); } else { /* Turn. Do it slowly if in the air. */ Direction newdir = GetDirectionTowards(v, x + amd.x, y + amd.y); if (newdir != v->direction) { if (amd.flag & AMED_SLOWTURN && v->number_consecutive_turns < 8 && v->subtype == AIR_AIRCRAFT) { if (v->turn_counter == 0 || newdir == v->last_direction) { if (newdir == v->last_direction) { v->number_consecutive_turns = 0; } else { v->number_consecutive_turns++; } v->turn_counter = 2 * _settings_game.vehicle.plane_speed; v->last_direction = v->direction; v->direction = newdir; } /* Move vehicle. */ gp = GetNewVehiclePos(v); } else { v->cur_speed >>= 1; v->direction = newdir; /* When leaving a terminal an aircraft often goes to a position * directly in front of it. If it would move while turning it * would need an two extra turns to end up at the correct position. * To make it easier just disallow all moving while turning as * long as an aircraft is on the ground. */ gp.x = v->x_pos; gp.y = v->y_pos; gp.new_tile = gp.old_tile = v->tile; } } else { v->number_consecutive_turns = 0; /* Move vehicle. */ gp = GetNewVehiclePos(v); } } v->tile = gp.new_tile; /* If vehicle is in the air, use tile coordinate 0. */ if (amd.flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0; /* Adjust Z for land or takeoff? */ int z = v->z_pos; if (amd.flag & AMED_TAKEOFF) { z = GetAircraftFlightLevel(v, true); } else if (amd.flag & AMED_HOLD) { /* Let the plane drop from normal flight altitude to holding pattern altitude */ if (z > GetAircraftHoldMaxAltitude(v)) z--; } else if ((amd.flag & AMED_SLOWTURN) && (amd.flag & AMED_NOSPDCLAMP)) { z = GetAircraftFlightLevel(v); } if (amd.flag & AMED_LAND) { if (st->airport.tile == INVALID_TILE) { /* Airport has been removed, abort the landing procedure */ v->state = FLYING; UpdateAircraftCache(v); AircraftNextAirportPos_and_Order(v); /* get aircraft back on running altitude */ SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlightLevel(v)); continue; } int curz = GetSlopePixelZ(x + amd.x, y + amd.y) + 1; /* We're not flying below our destination, right? */ assert(curz <= z); int t = max(1U, dist - 4); int delta = z - curz; /* Only start lowering when we're sufficiently close for a 1:1 glide */ if (delta >= t) { z -= CeilDiv(z - curz, t); } if (z < curz) z = curz; } /* We've landed. Decrease speed when we're reaching end of runway. */ if (amd.flag & AMED_BRAKE) { int curz = GetSlopePixelZ(x, y) + 1; if (z > curz) { z--; } else if (z < curz) { z++; } } SetAircraftPosition(v, gp.x, gp.y, z); } while (--count != 0); return false; } /** * Handle crashed aircraft \a v. * @param v Crashed aircraft. */ static bool HandleCrashedAircraft(Aircraft *v) { v->crashed_counter += 3; Station *st = GetTargetAirportIfValid(v); /* make aircraft crash down to the ground */ if (v->crashed_counter < 500 && st == NULL && ((v->crashed_counter % 3) == 0) ) { int z = GetSlopePixelZ(Clamp(v->x_pos, 0, MapMaxX() * TILE_SIZE), Clamp(v->y_pos, 0, MapMaxY() * TILE_SIZE)); v->z_pos -= 1; if (v->z_pos == z) { v->crashed_counter = 500; v->z_pos++; } } if (v->crashed_counter < 650) { uint32 r; if (Chance16R(1, 32, r)) { static const DirDiff delta[] = { DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT }; v->direction = ChangeDir(v->direction, delta[GB(r, 16, 2)]); SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); r = Random(); CreateEffectVehicleRel(v, GB(r, 0, 4) - 4, GB(r, 4, 4) - 4, GB(r, 8, 4), EV_EXPLOSION_SMALL); } } else if (v->crashed_counter >= 10000) { /* remove rubble of crashed airplane */ /* clear runway-in on all airports, set by crashing plane * small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc. * but they all share the same number */ if (st != NULL) { CLRBITS(st->airport.flags, RUNWAY_IN_block); CLRBITS(st->airport.flags, RUNWAY_IN_OUT_block); // commuter airport CLRBITS(st->airport.flags, RUNWAY_IN2_block); // intercontinental } delete v; return false; } return true; } /** * Handle smoke of broken aircraft. * @param v Aircraft * @param mode Is this the non-first call for this vehicle in this tick? */ static void HandleAircraftSmoke(Aircraft *v, bool mode) { static const struct { int8 x; int8 y; } smoke_pos[] = { { 5, 5 }, { 6, 0 }, { 5, -5 }, { 0, -6 }, { -5, -5 }, { -6, 0 }, { -5, 5 }, { 0, 6 } }; if (!(v->vehstatus & VS_AIRCRAFT_BROKEN)) return; /* Stop smoking when landed */ if (v->cur_speed < 10) { v->vehstatus &= ~VS_AIRCRAFT_BROKEN; v->breakdown_ctr = 0; return; } /* Spawn effect et most once per Tick, i.e. !mode */ if (!mode && (v->tick_counter & 0x0F) == 0) { CreateEffectVehicleRel(v, smoke_pos[v->direction].x, smoke_pos[v->direction].y, 2, EV_BREAKDOWN_SMOKE_AIRCRAFT ); } } void HandleMissingAircraftOrders(Aircraft *v) { /* * We do not have an order. This can be divided into two cases: * 1) we are heading to an invalid station. In this case we must * find another airport to go to. If there is nowhere to go, * we will destroy the aircraft as it otherwise will enter * the holding pattern for the first airport, which can cause * the plane to go into an undefined state when building an * airport with the same StationID. * 2) we are (still) heading to a (still) valid airport, then we * can continue going there. This can happen when you are * changing the aircraft's orders while in-flight or in for * example a depot. However, when we have a current order to * go to a depot, we have to keep that order so the aircraft * actually stops. */ const Station *st = GetTargetAirportIfValid(v); if (st == NULL) { Backup cur_company(_current_company, v->owner, FILE_LINE); CommandCost ret = DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_SEND_VEHICLE_TO_DEPOT); cur_company.Restore(); if (ret.Failed()) CrashAirplane(v); } else if (!v->current_order.IsType(OT_GOTO_DEPOT)) { v->current_order.Free(); } } TileIndex Aircraft::GetOrderStationLocation(StationID station) { /* Orders are changed in flight, ensure going to the right station. */ if (this->state == FLYING) { AircraftNextAirportPos_and_Order(this); } /* Aircraft do not use dest-tile */ return 0; } void Aircraft::MarkDirty() { this->colourmap = PAL_NONE; this->UpdateViewport(true, false); if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this, EIT_ON_MAP); } uint Aircraft::Crash(bool flooded) { uint pass = Vehicle::Crash(flooded) + 2; // pilots this->crashed_counter = flooded ? 9000 : 0; // max 10000, disappear pretty fast when flooded return pass; } /** * Bring the aircraft in a crashed state, create the explosion animation, and create a news item about the crash. * @param v Aircraft that crashed. */ static void CrashAirplane(Aircraft *v) { CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE); uint pass = v->Crash(); SetDParam(0, pass); v->cargo.Truncate(); v->Next()->cargo.Truncate(); const Station *st = GetTargetAirportIfValid(v); StringID newsitem; if (st == NULL) { newsitem = STR_NEWS_PLANE_CRASH_OUT_OF_FUEL; } else { SetDParam(1, st->index); newsitem = STR_NEWS_AIRCRAFT_CRASH; } AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, v->tile, st == NULL ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING)); Game::NewEvent(new ScriptEventVehicleCrashed(v->index, v->tile, st == NULL ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING)); AddVehicleNewsItem(newsitem, NT_ACCIDENT, v->index, st != NULL ? st->index : INVALID_STATION); ModifyStationRatingAround(v->tile, v->owner, -160, 30); if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v); } /** * Decide whether aircraft \a v should crash. * @param v Aircraft to test. */ static void MaybeCrashAirplane(Aircraft *v) { if (_settings_game.vehicle.plane_crashes == 0) return; 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); if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) && (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) { prob /= 20; } else { prob /= 1500; } if (GB(Random(), 0, 22) > prob) return; /* Crash the airplane. Remove all goods stored at the station. */ for (CargoID i = 0; i < NUM_CARGO; i++) { st->goods[i].rating = 1; st->goods[i].cargo.Truncate(); } CrashAirplane(v); } /** * Aircraft arrives at a terminal. If it is the first aircraft, throw a party. * Start loading cargo. * @param v Aircraft that arrived. */ static void AircraftEntersTerminal(Aircraft *v) { if (v->current_order.IsType(OT_GOTO_DEPOT)) return; 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)) { st->had_vehicle_of_type |= HVOT_AIRCRAFT; SetDParam(0, st->index); /* show newsitem of celebrating citizens */ AddVehicleNewsItem( STR_NEWS_FIRST_AIRCRAFT_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index ); AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index)); Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index)); } v->BeginLoading(); } /** * Aircraft touched down at the landing strip. * @param v Aircraft that landed. */ static void AircraftLandAirplane(Aircraft *v) { v->UpdateDeltaXY(INVALID_DIR); if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) { SndPlayVehicleFx(SND_17_SKID_PLANE, v); } } /** set the right pos when heading to other airports after takeoff */ void AircraftNextAirportPos_and_Order(Aircraft *v) { if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT)) { v->targetairport = v->current_order.GetDestination(); } const Station *st = GetTargetAirportIfValid(v); const AirportFTAClass *apc = st == NULL ? GetAirport(AT_DUMMY) : st->airport.GetFTA(); Direction rotation = st == NULL ? DIR_N : st->airport.rotation; v->pos = v->previous_pos = AircraftGetEntryPoint(v, apc, rotation); } /** * Aircraft is about to leave the hangar. * @param v Aircraft leaving. * @param exit_dir The direction the vehicle leaves the hangar. * @note This function is called in AfterLoadGame for old savegames, so don't rely * on any data to be valid, especially don't rely on the fact that the vehicle * is actually on the ground inside a depot. */ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir) { v->cur_speed = 0; v->subspeed = 0; v->progress = 0; v->direction = exit_dir; v->vehstatus &= ~VS_HIDDEN; { Vehicle *u = v->Next(); u->vehstatus &= ~VS_HIDDEN; /* Rotor blades */ u = u->Next(); if (u != NULL) { u->vehstatus &= ~VS_HIDDEN; u->cur_speed = 80; } } VehicleServiceInDepot(v); SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); SetWindowClassesDirty(WC_AIRCRAFT_LIST); } //////////////////////////////////////////////////////////////////////////////// /////////////////// AIRCRAFT MOVEMENT SCHEME //////////////////////////////// //////////////////////////////////////////////////////////////////////////////// static void AircraftEventHandler_EnterTerminal(Aircraft *v, const AirportFTAClass *apc) { AircraftEntersTerminal(v); v->state = apc->layout[v->pos].heading; } /** * Aircraft arrived in an airport hangar. * @param v Aircraft in the hangar. * @param apc Airport description containing the hangar. */ static void AircraftEventHandler_EnterHangar(Aircraft *v, const AirportFTAClass *apc) { VehicleEnterDepot(v); v->state = apc->layout[v->pos].heading; } /** * Handle aircraft movement/decision making in an airport hangar. * @param v Aircraft in the hangar. * @param apc Airport description containing the hangar. */ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *apc) { /* if we just arrived, execute EnterHangar first */ if (v->previous_pos != v->pos) { AircraftEventHandler_EnterHangar(v, apc); return; } /* if we were sent to the depot, stay there */ if (v->current_order.IsType(OT_GOTO_DEPOT) && (v->vehstatus & VS_STOPPED)) { v->current_order.Free(); return; } if (!v->current_order.IsType(OT_GOTO_STATION) && !v->current_order.IsType(OT_GOTO_DEPOT)) return; /* We are leaving a hangar, but have to go to the exact same one; re-enter */ if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetDestination() == v->targetairport) { VehicleEnterDepot(v); return; } /* if the block of the next position is busy, stay put */ if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; /* We are already at the target airport, we need to find a terminal */ if (v->current_order.GetDestination() == v->targetairport) { /* FindFreeTerminal: * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */ if (v->subtype == AIR_HELICOPTER) { if (!AirportFindFreeHelipad(v, apc)) return; // helicopter } else { if (!AirportFindFreeTerminal(v, apc)) return; // airplane } } else { // Else prepare for launch. /* airplane goto state takeoff, helicopter to helitakeoff */ v->state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; } const Station *st = Station::GetByTile(v->tile); AircraftLeaveHangar(v, st->airport.GetHangarExitDirection(v->tile)); AirportMove(v, apc); } /** At one of the Airport's Terminals */ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *apc) { /* if we just arrived, execute EnterTerminal first */ if (v->previous_pos != v->pos) { AircraftEventHandler_EnterTerminal(v, apc); /* on an airport with helipads, a helicopter will always land there * and get serviced at the same time - setting */ if (_settings_game.order.serviceathelipad) { if (v->subtype == AIR_HELICOPTER && apc->num_helipads > 0) { /* an excerpt of ServiceAircraft, without the invisibility stuff */ v->date_of_last_service = _date; v->breakdowns_since_last_service = 0; v->reliability = v->GetEngine()->reliability; SetWindowDirty(WC_VEHICLE_DETAILS, v->index); } } return; } if (v->current_order.IsType(OT_NOTHING)) return; /* if the block of the next position is busy, stay put */ if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; /* airport-road is free. We either have to go to another airport, or to the hangar * ---> start moving */ bool go_to_hangar = false; switch (v->current_order.GetType()) { case OT_GOTO_STATION: // ready to fly to another airport break; case OT_GOTO_DEPOT: // visit hangar for servicing, sale, etc. go_to_hangar = v->current_order.GetDestination() == v->targetairport; break; case OT_CONDITIONAL: /* In case of a conditional order we just have to wait a tick * longer, so the conditional order can actually be processed; * we should not clear the order as that makes us go nowhere. */ return; default: // orders have been deleted (no orders), goto depot and don't bother us v->current_order.Free(); go_to_hangar = Station::Get(v->targetairport)->airport.HasHangar(); } if (go_to_hangar) { v->state = HANGAR; } else { /* airplane goto state takeoff, helicopter to helitakeoff */ v->state = (v->subtype == AIR_HELICOPTER) ? HELITAKEOFF : TAKEOFF; } AirportMove(v, apc); } static void AircraftEventHandler_General(Aircraft *v, const AirportFTAClass *apc) { error("OK, you shouldn't be here, check your Airport Scheme!"); } static void AircraftEventHandler_TakeOff(Aircraft *v, const AirportFTAClass *apc) { PlayAircraftSound(v); // play takeoffsound for airplanes v->state = STARTTAKEOFF; } static void AircraftEventHandler_StartTakeOff(Aircraft *v, const AirportFTAClass *apc) { v->state = ENDTAKEOFF; v->UpdateDeltaXY(INVALID_DIR); } static void AircraftEventHandler_EndTakeOff(Aircraft *v, const AirportFTAClass *apc) { v->state = FLYING; /* get the next position to go to, differs per airport */ AircraftNextAirportPos_and_Order(v); } static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass *apc) { v->state = FLYING; v->UpdateDeltaXY(INVALID_DIR); /* get the next position to go to, differs per airport */ AircraftNextAirportPos_and_Order(v); /* Send the helicopter to a hangar if needed for replacement */ if (v->NeedsAutomaticServicing()) { Backup cur_company(_current_company, v->owner, FILE_LINE); DoCommand(v->tile, v->index | DEPOT_SERVICE | DEPOT_LOCATE_HANGAR, 0, DC_EXEC, CMD_SEND_VEHICLE_TO_DEPOT); cur_company.Restore(); } } static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc) { Station *st = Station::Get(v->targetairport); /* Runway busy, not allowed to use this airstation or closed, circle. */ if (CanVehicleUseStation(v, st) && (st->owner == OWNER_NONE || st->owner == v->owner) && !(st->airport.flags & AIRPORT_CLOSED_block)) { /* {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 */ byte landingtype = (v->subtype == AIR_HELICOPTER) ? HELILANDING : LANDING; const AirportFTA *current = apc->layout[v->pos].next; while (current != NULL) { if (current->heading == landingtype) { /* save speed before, since if AirportHasBlock is false, it resets them to 0 * we don't want that for plane in air * hack for speed thingie */ uint16 tcur_speed = v->cur_speed; uint16 tsubspeed = v->subspeed; if (!AirportHasBlock(v, current, apc)) { v->state = landingtype; // LANDING / HELILANDING /* it's a bit dirty, but I need to set position to next position, otherwise * if there are multiple runways, plane won't know which one it took (because * they all have heading LANDING). And also occupy that block! */ v->pos = current->next_position; SETBITS(st->airport.flags, apc->layout[v->pos].block); return; } v->cur_speed = tcur_speed; v->subspeed = tsubspeed; } current = current->next; } } v->state = FLYING; v->pos = apc->layout[v->pos].next_position; } static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *apc) { v->state = ENDLANDING; AircraftLandAirplane(v); // maybe crash airplane /* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */ if (v->NeedsAutomaticServicing()) { Backup cur_company(_current_company, v->owner, FILE_LINE); DoCommand(v->tile, v->index | DEPOT_SERVICE, 0, DC_EXEC, CMD_SEND_VEHICLE_TO_DEPOT); cur_company.Restore(); } } static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *apc) { v->state = HELIENDLANDING; v->UpdateDeltaXY(INVALID_DIR); } static void AircraftEventHandler_EndLanding(Aircraft *v, const AirportFTAClass *apc) { /* next block busy, don't do a thing, just wait */ if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; /* if going to terminal (OT_GOTO_STATION) choose one * 1. in case all terminals are busy AirportFindFreeTerminal() returns false or * 2. not going for terminal (but depot, no order), * --> get out of the way to the hangar. */ if (v->current_order.IsType(OT_GOTO_STATION)) { if (AirportFindFreeTerminal(v, apc)) return; } v->state = HANGAR; } static void AircraftEventHandler_HeliEndLanding(Aircraft *v, const AirportFTAClass *apc) { /* next block busy, don't do a thing, just wait */ if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; /* if going to helipad (OT_GOTO_STATION) choose one. If airport doesn't have helipads, choose terminal * 1. in case all terminals/helipads are busy (AirportFindFreeHelipad() returns false) or * 2. not going for terminal (but depot, no order), * --> get out of the way to the hangar IF there are terminals on the airport. * --> else TAKEOFF * the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes * must go to a hangar. */ if (v->current_order.IsType(OT_GOTO_STATION)) { if (AirportFindFreeHelipad(v, apc)) return; } v->state = Station::Get(v->targetairport)->airport.HasHangar() ? HANGAR : HELITAKEOFF; } /** * Signature of the aircraft handler function. * @param v Aircraft to handle. * @param apc Airport state machine. */ typedef void AircraftStateHandler(Aircraft *v, const AirportFTAClass *apc); /** Array of handler functions for each target of the aircraft. */ static AircraftStateHandler * const _aircraft_state_handlers[] = { AircraftEventHandler_General, // TO_ALL = 0 AircraftEventHandler_InHangar, // HANGAR = 1 AircraftEventHandler_AtTerminal, // TERM1 = 2 AircraftEventHandler_AtTerminal, // TERM2 = 3 AircraftEventHandler_AtTerminal, // TERM3 = 4 AircraftEventHandler_AtTerminal, // TERM4 = 5 AircraftEventHandler_AtTerminal, // TERM5 = 6 AircraftEventHandler_AtTerminal, // TERM6 = 7 AircraftEventHandler_AtTerminal, // HELIPAD1 = 8 AircraftEventHandler_AtTerminal, // HELIPAD2 = 9 AircraftEventHandler_TakeOff, // TAKEOFF = 10 AircraftEventHandler_StartTakeOff, // STARTTAKEOFF = 11 AircraftEventHandler_EndTakeOff, // ENDTAKEOFF = 12 AircraftEventHandler_HeliTakeOff, // HELITAKEOFF = 13 AircraftEventHandler_Flying, // FLYING = 14 AircraftEventHandler_Landing, // LANDING = 15 AircraftEventHandler_EndLanding, // ENDLANDING = 16 AircraftEventHandler_HeliLanding, // HELILANDING = 17 AircraftEventHandler_HeliEndLanding, // HELIENDLANDING = 18 AircraftEventHandler_AtTerminal, // TERM7 = 19 AircraftEventHandler_AtTerminal, // TERM8 = 20 AircraftEventHandler_AtTerminal, // HELIPAD3 = 21 }; static void AirportClearBlock(const Aircraft *v, const AirportFTAClass *apc) { /* we have left the previous block, and entered the new one. Free the previous block */ if (apc->layout[v->previous_pos].block != apc->layout[v->pos].block) { Station *st = Station::Get(v->targetairport); CLRBITS(st->airport.flags, apc->layout[v->previous_pos].block); } } static void AirportGoToNextPosition(Aircraft *v) { /* if aircraft is not in position, wait until it is */ if (!AircraftController(v)) return; const AirportFTAClass *apc = Station::Get(v->targetairport)->airport.GetFTA(); AirportClearBlock(v, apc); AirportMove(v, apc); // move aircraft to next position } /* gets pos from vehicle and next orders */ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc) { /* error handling */ if (v->pos >= apc->nofelements) { DEBUG(misc, 0, "[Ap] position %d is not valid for current airport. Max position is %d", v->pos, apc->nofelements-1); assert(v->pos < apc->nofelements); } const AirportFTA *current = &apc->layout[v->pos]; /* we have arrived in an important state (eg terminal, hangar, etc.) */ if (current->heading == v->state) { byte prev_pos = v->pos; // location could be changed in state, so save it before-hand byte prev_state = v->state; _aircraft_state_handlers[v->state](v, apc); if (v->state != FLYING) v->previous_pos = prev_pos; if (v->state != prev_state || v->pos != prev_pos) UpdateAircraftCache(v); return true; } v->previous_pos = v->pos; // save previous location /* there is only one choice to move to */ if (current->next == NULL) { if (AirportSetBlocks(v, current, apc)) { v->pos = current->next_position; UpdateAircraftCache(v); } // move to next position return false; } /* there are more choices to choose from, choose the one that * matches our heading */ do { if (v->state == current->heading || current->heading == TO_ALL) { if (AirportSetBlocks(v, current, apc)) { v->pos = current->next_position; UpdateAircraftCache(v); } // move to next position return false; } current = current->next; } while (current != NULL); DEBUG(misc, 0, "[Ap] cannot move further on Airport! (pos %d state %d) for vehicle %d", v->pos, v->state, v->index); NOT_REACHED(); } /** returns true if the road ahead is busy, eg. you must wait before proceeding. */ static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc) { const AirportFTA *reference = &apc->layout[v->pos]; const AirportFTA *next = &apc->layout[current_pos->next_position]; /* same block, then of course we can move */ if (apc->layout[current_pos->position].block != next->block) { const Station *st = Station::Get(v->targetairport); uint64 airport_flags = next->block; /* check additional possible extra blocks */ if (current_pos != reference && current_pos->block != NOTHING_block) { airport_flags |= current_pos->block; } if (st->airport.flags & airport_flags) { v->cur_speed = 0; v->subspeed = 0; return true; } } return false; } /** * "reserve" a block for the plane * @param v airplane that requires the operation * @param current_pos of the vehicle in the list of blocks * @param apc airport on which block is requsted to be set * @returns true on success. Eg, next block was free and we have occupied it */ static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc) { const AirportFTA *next = &apc->layout[current_pos->next_position]; const AirportFTA *reference = &apc->layout[v->pos]; /* if the next position is in another block, check it and wait until it is free */ if ((apc->layout[current_pos->position].block & next->block) != next->block) { uint64 airport_flags = next->block; /* search for all all elements in the list with the same state, and blocks != N * this means more blocks should be checked/set */ const AirportFTA *current = current_pos; if (current == reference) current = current->next; while (current != NULL) { if (current->heading == current_pos->heading && current->block != 0) { airport_flags |= current->block; break; } current = current->next; } /* if the block to be checked is in the next position, then exclude that from * checking, because it has been set by the airplane before */ if (current_pos->block == next->block) airport_flags ^= next->block; Station *st = Station::Get(v->targetairport); if (st->airport.flags & airport_flags) { v->cur_speed = 0; v->subspeed = 0; return false; } if (next->block != NOTHING_block) { SETBITS(st->airport.flags, airport_flags); // occupy next block } } return true; } /** * Combination of aircraft state for going to a certain terminal and the * airport flag for that terminal block. */ struct MovementTerminalMapping { AirportMovementStates state; ///< Aircraft movement state when going to this terminal. uint64 airport_flag; ///< Bitmask in the airport flags that need to be free for this terminal. }; /** A list of all valid terminals and their associated blocks. */ static const MovementTerminalMapping _airport_terminal_mapping[] = { {TERM1, TERM1_block}, {TERM2, TERM2_block}, {TERM3, TERM3_block}, {TERM4, TERM4_block}, {TERM5, TERM5_block}, {TERM6, TERM6_block}, {TERM7, TERM7_block}, {TERM8, TERM8_block}, {HELIPAD1, HELIPAD1_block}, {HELIPAD2, HELIPAD2_block}, {HELIPAD3, HELIPAD3_block}, }; /** * Find a free terminal or helipad, and if available, assign it. * @param v Aircraft looking for a free terminal or helipad. * @param i First terminal to examine. * @param last_terminal Terminal number to stop examining. * @return A terminal or helipad has been found, and has been assigned to the aircraft. */ static bool FreeTerminal(Aircraft *v, byte i, byte last_terminal) { assert(last_terminal <= lengthof(_airport_terminal_mapping)); Station *st = Station::Get(v->targetairport); for (; i < last_terminal; i++) { if ((st->airport.flags & _airport_terminal_mapping[i].airport_flag) == 0) { /* TERMINAL# HELIPAD# */ v->state = _airport_terminal_mapping[i].state; // start moving to that terminal/helipad SETBITS(st->airport.flags, _airport_terminal_mapping[i].airport_flag); // occupy terminal/helipad return true; } } return false; } /** * Get the number of terminals at the airport. * @param afc Airport description. * @return Number of terminals. */ static uint GetNumTerminals(const AirportFTAClass *apc) { uint num = 0; for (uint i = apc->terminals[0]; i > 0; i--) num += apc->terminals[i]; return num; } /** * Find a free terminal, and assign it if available. * @param v Aircraft to handle. * @param apc Airport state machine. * @return Found a free terminal and assigned it. */ static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc) { /* example of more terminalgroups * {0,HANGAR,NOTHING_block,1}, {0,255,TERM_GROUP1_block,0}, {0,255,TERM_GROUP2_ENTER_block,1}, {0,0,N,1}, * Heading 255 denotes a group. We see 2 groups here: * 1. group 0 -- TERM_GROUP1_block (check block) * 2. group 1 -- TERM_GROUP2_ENTER_block (check block) * First in line is checked first, group 0. If the block (TERM_GROUP1_block) is free, it * looks at the corresponding terminals of that group. If no free ones are found, other * possible groups are checked (in this case group 1, since that is after group 0). If that * fails, then attempt fails and plane waits */ if (apc->terminals[0] > 1) { const Station *st = Station::Get(v->targetairport); const AirportFTA *temp = apc->layout[v->pos].next; while (temp != NULL) { if (temp->heading == 255) { if (!(st->airport.flags & temp->block)) { /* read which group do we want to go to? * (the first free group) */ uint target_group = temp->next_position + 1; /* at what terminal does the group start? * that means, sum up all terminals of * groups with lower number */ uint group_start = 0; for (uint i = 1; i < target_group; i++) { group_start += apc->terminals[i]; } uint group_end = group_start + apc->terminals[target_group]; if (FreeTerminal(v, group_start, group_end)) return true; } } else { /* once the heading isn't 255, we've exhausted the possible blocks. * So we cannot move */ return false; } temp = temp->next; } } /* if there is only 1 terminalgroup, all terminals are checked (starting from 0 to max) */ return FreeTerminal(v, 0, GetNumTerminals(apc)); } /** * Find a free helipad, and assign it if available. * @param v Aircraft to handle. * @param apc Airport state machine. * @return Found a free helipad and assigned it. */ static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc) { /* if an airport doesn't have helipads, use terminals */ if (apc->num_helipads == 0) return AirportFindFreeTerminal(v, apc); /* only 1 helicoptergroup, check all helipads * The blocks for helipads start after the last terminal (MAX_TERMINALS) */ return FreeTerminal(v, MAX_TERMINALS, apc->num_helipads + MAX_TERMINALS); } /** * Handle the 'dest too far' flag and the corresponding news message for aircraft. * @param v The aircraft. * @param too_far True if the current destination is too far away. */ static void AircraftHandleDestTooFar(Aircraft *v, bool too_far) { if (too_far) { if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) { SetBit(v->flags, VAF_DEST_TOO_FAR); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); AI::NewEvent(v->owner, new ScriptEventAircraftDestTooFar(v->index)); if (v->owner == _local_company) { /* Post a news message. */ SetDParam(0, v->index); AddVehicleAdviceNewsItem(STR_NEWS_AIRCRAFT_DEST_TOO_FAR, v->index); } } return; } if (HasBit(v->flags, VAF_DEST_TOO_FAR)) { /* Not too far anymore, clear flag and message. */ ClrBit(v->flags, VAF_DEST_TOO_FAR); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); DeleteVehicleNews(v->index, STR_NEWS_AIRCRAFT_DEST_TOO_FAR); } } static bool AircraftEventHandler(Aircraft *v, int loop) { if (v->vehstatus & VS_CRASHED) { return HandleCrashedAircraft(v); } if (v->vehstatus & VS_STOPPED) return true; v->HandleBreakdown(); HandleAircraftSmoke(v, loop != 0); ProcessOrders(v); v->HandleLoading(loop != 0); if (v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_LEAVESTATION)) return true; if (v->state >= ENDTAKEOFF && v->state <= HELIENDLANDING) { /* If we are flying, unconditionally clear the 'dest too far' state. */ AircraftHandleDestTooFar(v, false); } else if (v->acache.cached_max_range_sqr != 0) { /* Check the distance to the next destination. This code works because the target * airport is only updated after take off and not on the ground. */ Station *cur_st = Station::GetIfValid(v->targetairport); Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination()) : NULL; if (cur_st != NULL && cur_st->airport.tile != INVALID_TILE && next_st != NULL && next_st->airport.tile != INVALID_TILE) { uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile); AircraftHandleDestTooFar(v, dist > v->acache.cached_max_range_sqr); } } if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) AirportGoToNextPosition(v); return true; } bool Aircraft::Tick() { if (!this->IsNormalAircraft()) return true; this->tick_counter++; if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; if (this->subtype == AIR_HELICOPTER) HelicopterTickHandler(this); this->current_order_time++; for (uint i = 0; i != 2; i++) { /* stop if the aircraft was deleted */ if (!AircraftEventHandler(this, i)) return false; } return true; } /** * Returns aircraft's target station if v->target_airport * is a valid station with airport. * @param v vehicle to get target airport for * @return pointer to target station, NULL if invalid */ Station *GetTargetAirportIfValid(const Aircraft *v) { assert(v->type == VEH_AIRCRAFT); Station *st = Station::GetIfValid(v->targetairport); if (st == NULL) return NULL; return st->airport.tile == INVALID_TILE ? NULL : st; } /** * Updates the status of the Aircraft heading or in the station * @param st Station been updated */ void UpdateAirplanesOnNewStation(const Station *st) { /* only 1 station is updated per function call, so it is enough to get entry_point once */ const AirportFTAClass *ap = st->airport.GetFTA(); Direction rotation = st->airport.tile == INVALID_TILE ? DIR_N : st->airport.rotation; Aircraft *v; FOR_ALL_AIRCRAFT(v) { if (!v->IsNormalAircraft() || v->targetairport != st->index) continue; assert(v->state == FLYING); v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation); UpdateAircraftCache(v); } } openttd-1.5.3/src/bridge_map.cpp0000644000000000000000000000457712627373435015310 0ustar rootroot/* $Id: bridge_map.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 bridge_map.cpp Map accessor functions for bridges. */ #include "stdafx.h" #include "landscape.h" #include "tunnelbridge_map.h" #include "safeguards.h" /** * Finds the end of a bridge in the specified direction starting at a middle tile * @param tile the bridge tile to find the bridge ramp for * @param dir the direction to search in */ static TileIndex GetBridgeEnd(TileIndex tile, DiagDirection dir) { TileIndexDiff delta = TileOffsByDiagDir(dir); dir = ReverseDiagDir(dir); do { tile += delta; } while (!IsBridgeTile(tile) || GetTunnelBridgeDirection(tile) != dir); return tile; } /** * Finds the northern end of a bridge starting at a middle tile * @param t the bridge tile to find the bridge ramp for */ TileIndex GetNorthernBridgeEnd(TileIndex t) { return GetBridgeEnd(t, ReverseDiagDir(AxisToDiagDir(GetBridgeAxis(t)))); } /** * Finds the southern end of a bridge starting at a middle tile * @param t the bridge tile to find the bridge ramp for */ TileIndex GetSouthernBridgeEnd(TileIndex t) { return GetBridgeEnd(t, AxisToDiagDir(GetBridgeAxis(t))); } /** * Starting at one bridge end finds the other bridge end * @param t the bridge ramp tile to find the other bridge ramp for */ TileIndex GetOtherBridgeEnd(TileIndex tile) { assert(IsBridgeTile(tile)); return GetBridgeEnd(tile, GetTunnelBridgeDirection(tile)); } /** * Get the height ('z') of a bridge. * @param tile the bridge ramp tile to get the bridge height from * @return the height of the bridge. */ int GetBridgeHeight(TileIndex t) { int h; Slope tileh = GetTileSlope(t, &h); Foundation f = GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(t))); /* one height level extra for the ramp */ return h + 1 + ApplyFoundationToSlope(f, &tileh); } openttd-1.5.3/src/vehicle_gui.h0000644000000000000000000001052012627373442015126 0ustar rootroot/* $Id: vehicle_gui.h 24839 2012-12-23 01:00:25Z michi_cc $ */ /* * 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 vehicle_gui.h Functions related to the vehicle's GUIs. */ #ifndef VEHICLE_GUI_H #define VEHICLE_GUI_H #include "window_type.h" #include "vehicle_type.h" #include "order_type.h" #include "station_type.h" #include "engine_type.h" #include "company_type.h" void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit = false); /** The tabs in the train details window */ enum TrainDetailsWindowTabs { TDW_TAB_CARGO = 0, ///< Tab with cargo carried by the vehicles TDW_TAB_INFO, ///< Tab with name and value of the vehicles TDW_TAB_CAPACITY, ///< Tab with cargo capacity of the vehicles TDW_TAB_TOTALS, ///< Tab with sum of total cargo transported }; /** Special values for vehicle-related windows for the data parameter of #InvalidateWindowData. */ enum VehicleInvalidateWindowData { VIWD_REMOVE_ALL_ORDERS = -1, ///< Removed / replaced all orders (after deleting / sharing). VIWD_MODIFY_ORDERS = -2, ///< Other order modifications. VIWD_CONSIST_CHANGED = -3, ///< Vehicle composition was changed. VIWD_AUTOREPLACE = -4, ///< Autoreplace replaced the vehicle. }; int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number); void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip, VehicleID drag_dest = INVALID_VEHICLE); void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip = 0); void DrawShipImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type); void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type); void ShowBuildVehicleWindow(TileIndex tile, VehicleType type); uint ShowRefitOptionsList(int left, int right, int y, EngineID engine); StringID GetCargoSubtypeText(const Vehicle *v); void ShowVehicleListWindow(const Vehicle *v); void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type); void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station); void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile); /** * Get the height of a single vehicle in the GUIs. * @param type the vehicle type to look at * @return the height */ static inline uint GetVehicleHeight(VehicleType type) { return (type == VEH_TRAIN || type == VEH_ROAD) ? 14 : 24; } int GetVehicleWidth(Vehicle *v, EngineImageType image_type); /** Dimensions of a cell in the purchase/depot windows. */ struct VehicleCellSize { uint height; ///< Vehicle cell height. uint extend_left; ///< Extend of the cell to the left. uint extend_right; ///< Extend of the cell to the right. }; VehicleCellSize GetVehicleImageCellSize(VehicleType type, EngineImageType image_type); /** * Get WindowClass for vehicle list of given vehicle type * @param vt vehicle type to check * @return corresponding window class * @note works only for company buildable vehicle types */ static inline WindowClass GetWindowClassForVehicleType(VehicleType vt) { switch (vt) { default: NOT_REACHED(); case VEH_TRAIN: return WC_TRAINS_LIST; case VEH_ROAD: return WC_ROADVEH_LIST; case VEH_SHIP: return WC_SHIPS_LIST; case VEH_AIRCRAFT: return WC_AIRCRAFT_LIST; } } /* Unified window procedure */ void ShowVehicleViewWindow(const Vehicle *v); bool VehicleClicked(const Vehicle *v); void StartStopVehicle(const Vehicle *v, bool texteffect); Vehicle *CheckClickOnVehicle(const struct ViewPort *vp, int x, int y); void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip); #endif /* VEHICLE_GUI_H */ openttd-1.5.3/src/misc_gui.cpp0000644000000000000000000012477112627373445015016 0ustar rootroot/* $Id: misc_gui.cpp 27194 2015-03-17 22:08:48Z frosch $ */ /* * 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 misc_gui.cpp GUIs for a number of misc windows. */ #include "stdafx.h" #include "debug.h" #include "landscape.h" #include "error.h" #include "gui.h" #include "command_func.h" #include "company_func.h" #include "town.h" #include "string_func.h" #include "company_base.h" #include "texteff.hpp" #include "strings_func.h" #include "window_func.h" #include "querystring_gui.h" #include "core/geometry_func.hpp" #include "newgrf_debug.h" #include "zoom_func.h" #include "widgets/misc_widget.h" #include "table/strings.h" #include "safeguards.h" /** Method to open the OSK. */ enum OskActivation { OSKA_DISABLED, ///< The OSK shall not be activated at all. OSKA_DOUBLE_CLICK, ///< Double click on the edit box opens OSK. OSKA_SINGLE_CLICK, ///< Single click after focus click opens OSK. OSKA_IMMEDIATELY, ///< Focusing click already opens OSK. }; static const NWidgetPart _nested_land_info_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_LAND_AREA_INFORMATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEBUGBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_LI_BACKGROUND), EndContainer(), }; static WindowDesc _land_info_desc( WDP_AUTO, "land_info", 0, 0, WC_LAND_INFO, WC_NONE, 0, _nested_land_info_widgets, lengthof(_nested_land_info_widgets) ); class LandInfoWindow : public Window { enum LandInfoLines { LAND_INFO_CENTERED_LINES = 32, ///< Up to 32 centered lines (arbitrary limit) LAND_INFO_MULTICENTER_LINE = LAND_INFO_CENTERED_LINES, ///< One multicenter line LAND_INFO_LINE_END, }; static const uint LAND_INFO_LINE_BUFF_SIZE = 512; public: char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE]; TileIndex tile; virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_LI_BACKGROUND) return; uint y = r.top + WD_TEXTPANEL_TOP; for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { if (StrEmpty(this->landinfo_data[i])) break; DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, this->landinfo_data[i], i == 0 ? TC_LIGHT_BLUE : TC_FROMSTRING, SA_HOR_CENTER); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; if (i == 0) y += 4; } if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, r.bottom - WD_TEXTPANEL_BOTTOM, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER); } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_LI_BACKGROUND) return; size->height = WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) { if (StrEmpty(this->landinfo_data[i])) break; uint width = GetStringBoundingBox(this->landinfo_data[i]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; size->width = max(size->width, width); size->height += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; if (i == 0) size->height += 4; } if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) { uint width = GetStringBoundingBox(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]).width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; size->width = max(size->width, min(300u, width)); SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]); size->height += GetStringHeight(STR_JUST_RAW_STRING, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT); } } LandInfoWindow(TileIndex tile) : Window(&_land_info_desc), tile(tile) { this->InitNested(); #if defined(_DEBUG) # define LANDINFOD_LEVEL 0 #else # define LANDINFOD_LEVEL 1 #endif DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile)); DEBUG(misc, LANDINFOD_LEVEL, "type = %#x", _m[tile].type); DEBUG(misc, LANDINFOD_LEVEL, "height = %#x", _m[tile].height); DEBUG(misc, LANDINFOD_LEVEL, "m1 = %#x", _m[tile].m1); DEBUG(misc, LANDINFOD_LEVEL, "m2 = %#x", _m[tile].m2); DEBUG(misc, LANDINFOD_LEVEL, "m3 = %#x", _m[tile].m3); DEBUG(misc, LANDINFOD_LEVEL, "m4 = %#x", _m[tile].m4); DEBUG(misc, LANDINFOD_LEVEL, "m5 = %#x", _m[tile].m5); DEBUG(misc, LANDINFOD_LEVEL, "m6 = %#x", _me[tile].m6); DEBUG(misc, LANDINFOD_LEVEL, "m7 = %#x", _me[tile].m7); #undef LANDINFOD_LEVEL } virtual void OnInit() { Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); /* Because build_date is not set yet in every TileDesc, we make sure it is empty */ TileDesc td; td.build_date = INVALID_DATE; /* Most tiles have only one owner, but * - drivethrough roadstops can be build on town owned roads (up to 2 owners) and * - roads can have up to four owners (railroad, road, tram, 3rd-roadtype "highway"). */ td.owner_type[0] = STR_LAND_AREA_INFORMATION_OWNER; // At least one owner is displayed, though it might be "N/A". td.owner_type[1] = STR_NULL; // STR_NULL results in skipping the owner td.owner_type[2] = STR_NULL; td.owner_type[3] = STR_NULL; td.owner[0] = OWNER_NONE; td.owner[1] = OWNER_NONE; td.owner[2] = OWNER_NONE; td.owner[3] = OWNER_NONE; td.station_class = STR_NULL; td.station_name = STR_NULL; td.airport_class = STR_NULL; td.airport_name = STR_NULL; td.airport_tile_name = STR_NULL; td.rail_speed = 0; td.road_speed = 0; td.grf = NULL; CargoArray acceptance; AddAcceptedCargo(tile, acceptance, NULL); GetTileDesc(tile, &td); uint line_nr = 0; /* Tiletype */ SetDParam(0, td.dparam[0]); GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr])); line_nr++; /* Up to four owners */ for (uint i = 0; i < 4; i++) { if (td.owner_type[i] == STR_NULL) continue; SetDParam(0, STR_LAND_AREA_INFORMATION_OWNER_N_A); if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) GetNameOfOwner(td.owner[i], tile); GetString(this->landinfo_data[line_nr], td.owner_type[i], lastof(this->landinfo_data[line_nr])); line_nr++; } /* Cost to clear/revenue when cleared */ StringID str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A; Company *c = Company::GetIfValid(_local_company); if (c != NULL) { Money old_money = c->money; c->money = INT64_MAX; assert(_current_company == _local_company); CommandCost costclear = DoCommand(tile, 0, 0, DC_NONE, CMD_LANDSCAPE_CLEAR); c->money = old_money; if (costclear.Succeeded()) { Money cost = costclear.GetCost(); if (cost < 0) { cost = -cost; // Negate negative cost to a positive revenue str = STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED; } else { str = STR_LAND_AREA_INFORMATION_COST_TO_CLEAR; } SetDParam(0, cost); } } GetString(this->landinfo_data[line_nr], str, lastof(this->landinfo_data[line_nr])); line_nr++; /* Location */ char tmp[16]; seprintf(tmp, lastof(tmp), "0x%.4X", tile); SetDParam(0, TileX(tile)); SetDParam(1, TileY(tile)); SetDParam(2, GetTileZ(tile)); SetDParamStr(3, tmp); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LANDINFO_COORDS, lastof(this->landinfo_data[line_nr])); line_nr++; /* Local authority */ SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); if (t != NULL) { SetDParam(0, STR_TOWN_NAME); SetDParam(1, t->index); } GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY, lastof(this->landinfo_data[line_nr])); line_nr++; /* Build date */ if (td.build_date != INVALID_DATE) { SetDParam(0, td.build_date); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_BUILD_DATE, lastof(this->landinfo_data[line_nr])); line_nr++; } /* Station class */ if (td.station_class != STR_NULL) { SetDParam(0, td.station_class); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_CLASS, lastof(this->landinfo_data[line_nr])); line_nr++; } /* Station type name */ if (td.station_name != STR_NULL) { SetDParam(0, td.station_name); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_STATION_TYPE, lastof(this->landinfo_data[line_nr])); line_nr++; } /* Airport class */ if (td.airport_class != STR_NULL) { SetDParam(0, td.airport_class); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_CLASS, lastof(this->landinfo_data[line_nr])); line_nr++; } /* Airport name */ if (td.airport_name != STR_NULL) { SetDParam(0, td.airport_name); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORT_NAME, lastof(this->landinfo_data[line_nr])); line_nr++; } /* Airport tile name */ if (td.airport_tile_name != STR_NULL) { SetDParam(0, td.airport_tile_name); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME, lastof(this->landinfo_data[line_nr])); line_nr++; } /* Rail speed limit */ if (td.rail_speed != 0) { SetDParam(0, td.rail_speed); GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); line_nr++; } /* Road speed limit */ if (td.road_speed != 0) { SetDParam(0, td.road_speed); GetString(this->landinfo_data[line_nr], STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT, lastof(this->landinfo_data[line_nr])); line_nr++; } /* NewGRF name */ if (td.grf != NULL) { SetDParamStr(0, td.grf); GetString(this->landinfo_data[line_nr], STR_LAND_AREA_INFORMATION_NEWGRF_NAME, lastof(this->landinfo_data[line_nr])); line_nr++; } assert(line_nr < LAND_INFO_CENTERED_LINES); /* Mark last line empty */ this->landinfo_data[line_nr][0] = '\0'; /* Cargo acceptance is displayed in a extra multiline */ char *strp = GetString(this->landinfo_data[LAND_INFO_MULTICENTER_LINE], STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); bool found = false; for (CargoID i = 0; i < NUM_CARGO; ++i) { if (acceptance[i] > 0) { /* Add a comma between each item. */ if (found) { *strp++ = ','; *strp++ = ' '; } found = true; /* If the accepted value is less than 8, show it in 1/8:ths */ if (acceptance[i] < 8) { SetDParam(0, acceptance[i]); SetDParam(1, CargoSpec::Get(i)->name); strp = GetString(strp, STR_LAND_AREA_INFORMATION_CARGO_EIGHTS, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); } else { strp = GetString(strp, CargoSpec::Get(i)->name, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])); } } } if (!found) this->landinfo_data[LAND_INFO_MULTICENTER_LINE][0] = '\0'; } virtual bool IsNewGRFInspectable() const { return ::IsNewGRFInspectable(GetGrfSpecFeature(this->tile), this->tile); } virtual void ShowNewGRFInspectWindow() const { ::ShowNewGRFInspectWindow(GetGrfSpecFeature(this->tile), this->tile); } /** * 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; switch (data) { case 1: /* ReInit, "debug" sprite might have changed */ this->ReInit(); break; } } }; /** * Show land information window. * @param tile The tile to show information about. */ void ShowLandInfo(TileIndex tile) { DeleteWindowById(WC_LAND_INFO, 0); new LandInfoWindow(tile); } static const NWidgetPart _nested_about_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_ABOUT_OPENTTD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(4, 2, 4), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_ORIGINAL_COPYRIGHT, STR_NULL), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_VERSION, STR_NULL), NWidget(WWT_FRAME, COLOUR_GREY), SetPadding(0, 5, 1, 5), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_A_SCROLLING_TEXT), EndContainer(), NWidget(WWT_LABEL, COLOUR_GREY, WID_A_WEBSITE), SetDataTip(STR_BLACK_RAW_STRING, STR_NULL), NWidget(WWT_LABEL, COLOUR_GREY), SetDataTip(STR_ABOUT_COPYRIGHT_OPENTTD, STR_NULL), EndContainer(), }; static WindowDesc _about_desc( WDP_CENTER, NULL, 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, _nested_about_widgets, lengthof(_nested_about_widgets) ); static const char * const _credits[] = { "Original design by Chris Sawyer", "Original graphics by Simon Foster", "", "The OpenTTD team (in alphabetical order):", " Albert Hofkamp (Alberth) - GUI expert (since 0.7)", " Matthijs Kooijman (blathijs) - Pathfinder-guru, Debian port (since 0.3)", " Ulf Hermann (fonsinchen) - Cargo Distribution (since 1.3)", " Christoph Elsenhans (frosch) - General coding (since 0.6)", " Lo\xC3\xAF""c Guilloux (glx) - General / Windows Expert (since 0.4.5)", " Michael Lutz (michi_cc) - Path based signals (since 0.7)", " Owen Rudge (orudge) - Forum host, OS/2 port (since 0.1)", " Peter Nelson (peter1138) - Spiritual descendant from NewGRF gods (since 0.4.5)", " Ingo von Borstel (planetmaker) - General, Support (since 1.1)", " Remko Bijker (Rubidium) - Lead coder and way more (since 0.4.5)", " Jos\xC3\xA9 Soler (Terkhen) - General coding (since 1.0)", " Leif Linse (Zuu) - AI/Game Script (since 1.2)", "", "Inactive Developers:", " Jean-Fran\xC3\xA7ois Claeys (Belugas) - GUI, NewGRF and more (0.4.5 - 1.0)", " Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles (0.3 - 0.7)", " Victor Fischer (Celestar) - Programming everywhere you need him to (0.3 - 0.6)", " Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;) (0.4.5 - 0.6)", " Jonathan Coome (Maedhros) - High priest of the NewGRF Temple (0.5 - 0.6)", " Attila B\xC3\xA1n (MiHaMiX) - Developer WebTranslator 1 and 2 (0.3 - 0.5)", " Zden\xC4\x9Bk Sojka (SmatZ) - Bug finder and fixer (0.6 - 1.3)", " Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5)", " Patric Stout (TrueBrain) - NoAI, NoGo, Network (0.3 - 1.2), sys op (active)", " Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3)", "", "Retired Developers:", " Tam\xC3\xA1s Farag\xC3\xB3 (Darkvater) - Ex-Lead coder (0.3 - 0.5)", " Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3 - 0.3)", " Emil Djupfeld (egladil) - MacOSX (0.4.5 - 0.6)", " Simon Sasburg (HackyKid) - Many bugfixes (0.4 - 0.4.5)", " Ludvig Strigeus (ludde) - Original author of OpenTTD, main coder (0.1 - 0.3)", " Cian Duffy (MYOB) - BeOS port / manual writing (0.1 - 0.3)", " Petr Baudi\xC5\xA1 (pasky) - Many patches, NewGRF support (0.3 - 0.3)", " Benedikt Br\xC3\xBCggemeier (skidd13) - Bug fixer and code reworker (0.6 - 0.7)", " Serge Paquet (vurlix) - 2nd contributor after ludde (0.1 - 0.3)", "", "Special thanks go out to:", " Josef Drexler - For his great work on TTDPatch", " Marcin Grzegorczyk - Track foundations and for describing TTD internals", " Stefan Mei\xC3\x9Fner (sign_de) - For his work on the console", " Mike Ragsdale - OpenTTD installer", " Christian Rosentreter (tokai) - MorphOS / AmigaOS port", " Richard Kempton (richK) - additional airports, initial TGP implementation", " Emperor Jake - titlegame", "", " Alberto Demichelis - Squirrel scripting language \xC2\xA9 2003-2008", " L. Peter Deutsch - MD5 implementation \xC2\xA9 1999, 2000, 2002", " Michael Blunck - Pre-signals and semaphores \xC2\xA9 2003", " George - Canal/Lock graphics \xC2\xA9 2003-2004", " Andrew Parkhouse (andythenorth) - River graphics", " David Dallaston (Pikka) - Tram tracks", " All Translators - Who made OpenTTD a truly international game", " Bug Reporters - Without whom OpenTTD would still be full of bugs!", "", "", "And last but not least:", " Chris Sawyer - For an amazing game!" }; struct AboutWindow : public Window { int text_position; ///< The top of the scrolling text byte counter; ///< Used to scroll the text every 5 ticks int line_height; ///< The height of a single line static const int num_visible_lines = 19; ///< The number of lines visible simultaneously AboutWindow() : Window(&_about_desc) { this->InitNested(WN_GAME_OPTIONS_ABOUT); this->counter = 5; this->text_position = this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y + this->GetWidget(WID_A_SCROLLING_TEXT)->current_y; } virtual void SetStringParameters(int widget) const { if (widget == WID_A_WEBSITE) SetDParamStr(0, "Website: http://www.openttd.org"); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_A_SCROLLING_TEXT) return; this->line_height = FONT_HEIGHT_NORMAL; Dimension d; d.height = this->line_height * num_visible_lines; d.width = 0; for (uint i = 0; i < lengthof(_credits); i++) { d.width = max(d.width, GetStringBoundingBox(_credits[i]).width); } *size = maxdim(*size, d); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_A_SCROLLING_TEXT) return; int y = this->text_position; /* Show all scrolling _credits */ for (uint i = 0; i < lengthof(_credits); i++) { if (y >= r.top + 7 && y < r.bottom - this->line_height) { DrawString(r.left, r.right, y, _credits[i], TC_BLACK, SA_LEFT | SA_FORCE); } y += this->line_height; } } virtual void OnTick() { if (--this->counter == 0) { this->counter = 5; this->text_position--; /* If the last text has scrolled start a new from the start */ if (this->text_position < (int)(this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y - lengthof(_credits) * this->line_height)) { this->text_position = this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y + this->GetWidget(WID_A_SCROLLING_TEXT)->current_y; } this->SetDirty(); } } }; void ShowAboutWindow() { DeleteWindowByClass(WC_GAME_OPTIONS); new AboutWindow(); } /** * Display estimated costs. * @param cost Estimated cost (or income if negative). * @param x X position of the notification window. * @param y Y position of the notification window. */ void ShowEstimatedCostOrIncome(Money cost, int x, int y) { StringID msg = STR_MESSAGE_ESTIMATED_COST; if (cost < 0) { cost = -cost; msg = STR_MESSAGE_ESTIMATED_INCOME; } SetDParam(0, cost); ShowErrorMessage(msg, INVALID_STRING_ID, WL_INFO, x, y); } /** * Display animated income or costs on the map. * @param x World X position of the animation location. * @param y World Y position of the animation location. * @param z World Z position of the animation location. * @param cost Estimated cost (or income if negative). */ void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost) { Point pt = RemapCoords(x, y, z); StringID msg = STR_INCOME_FLOAT_COST; if (cost < 0) { cost = -cost; msg = STR_INCOME_FLOAT_INCOME; } SetDParam(0, cost); AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); } /** * Display animated feeder income. * @param x World X position of the animation location. * @param y World Y position of the animation location. * @param z World Z position of the animation location. * @param transfer Estimated feeder income. * @param income Real income from goods being delivered to their final destination. */ void ShowFeederIncomeAnimation(int x, int y, int z, Money transfer, Money income) { Point pt = RemapCoords(x, y, z); SetDParam(0, transfer); if (income == 0) { AddTextEffect(STR_FEEDER, pt.x, pt.y, DAY_TICKS, TE_RISING); } else { StringID msg = STR_FEEDER_COST; if (income < 0) { income = -income; msg = STR_FEEDER_INCOME; } SetDParam(1, income); AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); } } /** * Display vehicle loading indicators. * @param x World X position of the animation location. * @param y World Y position of the animation location. * @param z World Z position of the animation location. * @param percent Estimated feeder income. * @param string String which is drawn on the map. * @return TextEffectID to be used for future updates of the loading indicators. */ TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID string) { Point pt = RemapCoords(x, y, z); assert(string != STR_NULL); SetDParam(0, percent); return AddTextEffect(string, pt.x, pt.y, 0, TE_STATIC); } /** * Update vehicle loading indicators. * @param te_id TextEffectID to be updated. * @param string String wich is printed. */ void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID string) { assert(string != STR_NULL); SetDParam(0, percent); UpdateTextEffect(te_id, string); } /** * Hide vehicle loading indicators. * @param *te_id TextEffectID which is supposed to be hidden. */ void HideFillingPercent(TextEffectID *te_id) { if (*te_id == INVALID_TE_ID) return; RemoveTextEffect(*te_id); *te_id = INVALID_TE_ID; } static const NWidgetPart _nested_tooltips_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_TT_BACKGROUND), SetMinimalSize(200, 32), EndContainer(), }; static WindowDesc _tool_tips_desc( WDP_MANUAL, NULL, 0, 0, // Coordinates and sizes are not used, WC_TOOLTIPS, WC_NONE, WDF_NO_FOCUS, _nested_tooltips_widgets, lengthof(_nested_tooltips_widgets) ); /** Window for displaying a tooltip. */ struct TooltipsWindow : public Window { StringID string_id; ///< String to display as tooltip. byte paramcount; ///< Number of string parameters in #string_id. uint64 params[5]; ///< The string parameters. TooltipCloseCondition close_cond; ///< Condition for closing the window. TooltipsWindow(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip) : Window(&_tool_tips_desc) { this->parent = parent; this->string_id = str; assert_compile(sizeof(this->params[0]) == sizeof(params[0])); assert(paramcount <= lengthof(this->params)); memcpy(this->params, params, sizeof(this->params[0]) * paramcount); this->paramcount = paramcount; this->close_cond = close_tooltip; this->InitNested(); CLRBITS(this->flags, WF_WHITE_BORDER); } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { /* Find the free screen space between the main toolbar at the top, and the statusbar at the bottom. * Add a fixed distance 2 so the tooltip floats free from both bars. */ int scr_top = GetMainViewTop() + 2; int scr_bot = GetMainViewBottom() - 2; Point pt; /* Correctly position the tooltip position, watch out for window and cursor size * Clamp value to below main toolbar and above statusbar. If tooltip would * go below window, flip it so it is shown above the cursor */ pt.y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, scr_top, scr_bot); if (pt.y + sm_height > scr_bot) pt.y = min(_cursor.pos.y + _cursor.offs.y - 5, scr_bot) - sm_height; pt.x = sm_width >= _screen.width ? 0 : Clamp(_cursor.pos.x - (sm_width >> 1), 0, _screen.width - sm_width); return pt; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { /* There is only one widget. */ for (uint i = 0; i != this->paramcount; i++) SetDParam(i, this->params[i]); size->width = min(GetStringBoundingBox(this->string_id).width, ScaleGUITrad(194)); size->height = GetStringHeight(this->string_id, size->width); /* Increase slightly to have some space around the box. */ size->width += 2 + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; size->height += 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; } virtual void DrawWidget(const Rect &r, int widget) const { /* There is only one widget. */ GfxFillRect(r.left, r.top, r.right, r.bottom, PC_BLACK); GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_LIGHT_YELLOW); for (uint arg = 0; arg < this->paramcount; arg++) { SetDParam(arg, this->params[arg]); } DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->string_id, TC_FROMSTRING, SA_CENTER); } virtual void OnMouseLoop() { /* Always close tooltips when the cursor is not in our window. */ if (!_cursor.in_window) { delete this; return; } /* We can show tooltips while dragging tools. These are shown as long as * we are dragging the tool. Normal tooltips work with hover or rmb. */ switch (this->close_cond) { case TCC_RIGHT_CLICK: if (!_right_button_down) delete this; break; case TCC_LEFT_CLICK: if (!_left_button_down) delete this; break; case TCC_HOVER: if (!_mouse_hovering) delete this; break; } } }; /** * Shows a tooltip * @param parent The window this tooltip is related to. * @param str String to be displayed * @param paramcount number of params to deal with * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip * @param use_left_mouse_button close the tooltip when the left (true) or right (false) mouse button is released */ void GuiShowTooltips(Window *parent, StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_tooltip) { DeleteWindowById(WC_TOOLTIPS, 0); if (str == STR_NULL) return; new TooltipsWindow(parent, str, paramcount, params, close_tooltip); } void QueryString::HandleEditBox(Window *w, int wid) { if (w->IsWidgetGloballyFocused(wid) && this->text.HandleCaret()) { w->SetWidgetDirty(wid); /* For the OSK also invalidate the parent window */ if (w->window_class == WC_OSK) w->InvalidateData(); } } void QueryString::DrawEditBox(const Window *w, int wid) const { const NWidgetLeaf *wi = w->GetWidget(wid); assert((wi->type & WWT_MASK) == WWT_EDITBOX); bool rtl = _current_text_dir == TD_RTL; Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; int clearbtn_left = wi->pos_x + (rtl ? 0 : wi->current_x - clearbtn_width); int clearbtn_right = wi->pos_x + (rtl ? clearbtn_width : wi->current_x) - 1; int left = wi->pos_x + (rtl ? clearbtn_width : 0); int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; int top = wi->pos_y; int bottom = wi->pos_y + wi->current_y - 1; DrawFrameRect(clearbtn_left, top, clearbtn_right, bottom, wi->colour, wi->IsLowered() ? FR_LOWERED : FR_NONE); DrawSprite(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT, PAL_NONE, clearbtn_left + WD_IMGBTN_LEFT + (wi->IsLowered() ? 1 : 0), (top + bottom - sprite_size.height) / 2 + (wi->IsLowered() ? 1 : 0)); if (this->text.bytes == 1) GfxFillRect(clearbtn_left + 1, top + 1, clearbtn_right - 1, bottom - 1, _colour_gradient[wi->colour & 0xF][2], FILLRECT_CHECKER); DrawFrameRect(left, top, right, bottom, wi->colour, FR_LOWERED | FR_DARKENED); GfxFillRect(left + 1, top + 1, right - 1, bottom - 1, PC_BLACK); /* Limit the drawing of the string inside the widget boundaries */ DrawPixelInfo dpi; if (!FillDrawPixelInfo(&dpi, left + WD_FRAMERECT_LEFT, top + WD_FRAMERECT_TOP, right - left - WD_FRAMERECT_RIGHT, bottom - top - WD_FRAMERECT_BOTTOM)) return; DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &dpi; /* We will take the current widget length as maximum width, with a small * space reserved at the end for the caret to show */ const Textbuf *tb = &this->text; int delta = min(0, (right - left) - tb->pixels - 10); if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; /* If we have a marked area, draw a background highlight. */ if (tb->marklength != 0) GfxFillRect(delta + tb->markxoffs, 0, delta + tb->markxoffs + tb->marklength - 1, bottom - top, PC_GREY); DrawString(delta, tb->pixels, 0, tb->buf, TC_YELLOW); bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid); if (focussed && tb->caret) { int caret_width = GetStringBoundingBox("_").width; DrawString(tb->caretxoffs + delta, tb->caretxoffs + delta + caret_width, 0, "_", TC_WHITE); } _cur_dpi = old_dpi; } /** * Get the current caret position. * @param w Window the edit box is in. * @param wid Widget index. * @return Top-left location of the caret, relative to the window. */ Point QueryString::GetCaretPosition(const Window *w, int wid) const { const NWidgetLeaf *wi = w->GetWidget(wid); assert((wi->type & WWT_MASK) == WWT_EDITBOX); bool rtl = _current_text_dir == TD_RTL; Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; int left = wi->pos_x + (rtl ? clearbtn_width : 0); int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; /* Clamp caret position to be inside out current width. */ const Textbuf *tb = &this->text; int delta = min(0, (right - left) - tb->pixels - 10); if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; Point pt = {left + WD_FRAMERECT_LEFT + tb->caretxoffs + delta, wi->pos_y + WD_FRAMERECT_TOP}; return pt; } /** * Get the bounding rectangle for a range of the query string. * @param w Window the edit box is in. * @param wid Widget index. * @param from Start of the string range. * @param to End of the string range. * @return Rectangle encompassing the string range, relative to the window. */ Rect QueryString::GetBoundingRect(const Window *w, int wid, const char *from, const char *to) const { const NWidgetLeaf *wi = w->GetWidget(wid); assert((wi->type & WWT_MASK) == WWT_EDITBOX); bool rtl = _current_text_dir == TD_RTL; Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; int left = wi->pos_x + (rtl ? clearbtn_width : 0); int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; int top = wi->pos_y + WD_FRAMERECT_TOP; int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; /* Clamp caret position to be inside our current width. */ const Textbuf *tb = &this->text; int delta = min(0, (right - left) - tb->pixels - 10); if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; /* Get location of first and last character. */ Point p1 = GetCharPosInString(tb->buf, from, FS_NORMAL); Point p2 = from != to ? GetCharPosInString(tb->buf, to, FS_NORMAL) : p1; Rect r = { Clamp(left + p1.x + delta + WD_FRAMERECT_LEFT, left, right), top, Clamp(left + p2.x + delta + WD_FRAMERECT_LEFT, left, right - WD_FRAMERECT_RIGHT), bottom }; return r; } /** * Get the character that is rendered at a position. * @param w Window the edit box is in. * @param wid Widget index. * @param pt Position to test. * @return Pointer to the character at the position or NULL if no character is at the position. */ const char *QueryString::GetCharAtPosition(const Window *w, int wid, const Point &pt) const { const NWidgetLeaf *wi = w->GetWidget(wid); assert((wi->type & WWT_MASK) == WWT_EDITBOX); bool rtl = _current_text_dir == TD_RTL; Dimension sprite_size = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT); int clearbtn_width = sprite_size.width + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; int left = wi->pos_x + (rtl ? clearbtn_width : 0); int right = wi->pos_x + (rtl ? wi->current_x : wi->current_x - clearbtn_width) - 1; int top = wi->pos_y + WD_FRAMERECT_TOP; int bottom = wi->pos_y + wi->current_y - 1 - WD_FRAMERECT_BOTTOM; if (!IsInsideMM(pt.y, top, bottom)) return NULL; /* Clamp caret position to be inside our current width. */ const Textbuf *tb = &this->text; int delta = min(0, (right - left) - tb->pixels - 10); if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs; return ::GetCharAtPosition(tb->buf, pt.x - delta - left); } void QueryString::ClickEditBox(Window *w, Point pt, int wid, int click_count, bool focus_changed) { const NWidgetLeaf *wi = w->GetWidget(wid); assert((wi->type & WWT_MASK) == WWT_EDITBOX); bool rtl = _current_text_dir == TD_RTL; int clearbtn_width = GetSpriteSize(rtl ? SPR_IMG_DELETE_RIGHT : SPR_IMG_DELETE_LEFT).width; int clearbtn_left = wi->pos_x + (rtl ? 0 : wi->current_x - clearbtn_width); if (IsInsideBS(pt.x, clearbtn_left, clearbtn_width)) { if (this->text.bytes > 1) { this->text.DeleteAll(); w->HandleButtonClick(wid); w->OnEditboxChanged(wid); } return; } if (w->window_class != WC_OSK && _settings_client.gui.osk_activation != OSKA_DISABLED && (!focus_changed || _settings_client.gui.osk_activation == OSKA_IMMEDIATELY) && (click_count == 2 || _settings_client.gui.osk_activation != OSKA_DOUBLE_CLICK)) { /* Open the OSK window */ ShowOnScreenKeyboard(w, wid); } } /** Class for the string query window. */ struct QueryStringWindow : public Window { QueryString editbox; ///< Editbox. QueryStringFlags flags; ///< Flags controlling behaviour of the window. QueryStringWindow(StringID str, StringID caption, uint max_bytes, uint max_chars, WindowDesc *desc, Window *parent, CharSetFilter afilter, QueryStringFlags flags) : Window(desc), editbox(max_bytes, max_chars) { char *last_of = &this->editbox.text.buf[this->editbox.text.max_bytes - 1]; GetString(this->editbox.text.buf, str, last_of); str_validate(this->editbox.text.buf, last_of, SVS_NONE); /* Make sure the name isn't too long for the text buffer in the number of * characters (not bytes). max_chars also counts the '\0' characters. */ while (Utf8StringLength(this->editbox.text.buf) + 1 > this->editbox.text.max_chars) { *Utf8PrevChar(this->editbox.text.buf + strlen(this->editbox.text.buf)) = '\0'; } this->editbox.text.UpdateSize(); if ((flags & QSF_ACCEPT_UNCHANGED) == 0) this->editbox.orig = stredup(this->editbox.text.buf); this->querystrings[WID_QS_TEXT] = &this->editbox; this->editbox.caption = caption; this->editbox.cancel_button = WID_QS_CANCEL; this->editbox.ok_button = WID_QS_OK; this->editbox.text.afilter = afilter; this->flags = flags; this->InitNested(WN_QUERY_STRING); this->parent = parent; this->SetFocusedWidget(WID_QS_TEXT); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_QS_DEFAULT && (this->flags & QSF_ENABLE_DEFAULT) == 0) { /* We don't want this widget to show! */ fill->width = 0; resize->width = 0; size->width = 0; } } virtual void SetStringParameters(int widget) const { if (widget == WID_QS_CAPTION) SetDParam(0, this->editbox.caption); } void OnOk() { if (this->editbox.orig == NULL || strcmp(this->editbox.text.buf, this->editbox.orig) != 0) { /* If the parent is NULL, the editbox is handled by general function * HandleOnEditText */ if (this->parent != NULL) { this->parent->OnQueryTextFinished(this->editbox.text.buf); } else { HandleOnEditText(this->editbox.text.buf); } this->editbox.handled = true; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_QS_DEFAULT: this->editbox.text.DeleteAll(); /* FALL THROUGH */ case WID_QS_OK: this->OnOk(); /* FALL THROUGH */ case WID_QS_CANCEL: delete this; break; } } ~QueryStringWindow() { if (!this->editbox.handled && this->parent != NULL) { Window *parent = this->parent; this->parent = NULL; // so parent doesn't try to delete us again parent->OnQueryTextFinished(NULL); } } }; static const NWidgetPart _nested_query_string_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_QS_CAPTION), SetDataTip(STR_WHITE_STRING, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_QS_TEXT), SetMinimalSize(256, 12), SetFill(1, 1), SetPadding(2, 2, 2, 2), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_DEFAULT), SetMinimalSize(87, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_DEFAULT, STR_NULL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_CANCEL), SetMinimalSize(86, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_QS_OK), SetMinimalSize(87, 12), SetFill(1, 1), SetDataTip(STR_BUTTON_OK, STR_NULL), EndContainer(), }; static WindowDesc _query_string_desc( WDP_CENTER, "query_string", 0, 0, WC_QUERY_STRING, WC_NONE, 0, _nested_query_string_widgets, lengthof(_nested_query_string_widgets) ); /** * Show a query popup window with a textbox in it. * @param str StringID for the text shown in the textbox * @param caption StringID of text shown in caption of querywindow * @param maxsize maximum size in bytes or characters (including terminating '\0') depending on flags * @param parent pointer to a Window that will handle the events (ok/cancel) of this * window. If NULL, results are handled by global function HandleOnEditText * @param afilter filters out unwanted character input * @param flags various flags, @see QueryStringFlags */ void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags) { DeleteWindowByClass(WC_QUERY_STRING); new QueryStringWindow(str, caption, ((flags & QSF_LEN_IN_CHARS) ? MAX_CHAR_LENGTH : 1) * maxsize, maxsize, &_query_string_desc, parent, afilter, flags); } /** * Window used for asking the user a YES/NO question. */ struct QueryWindow : public Window { QueryCallbackProc *proc; ///< callback function executed on closing of popup. Window* points to parent, bool is true if 'yes' clicked, false otherwise uint64 params[10]; ///< local copy of _decode_parameters StringID message; ///< message shown for query window StringID caption; ///< title of window QueryWindow(WindowDesc *desc, StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) : Window(desc) { /* Create a backup of the variadic arguments to strings because it will be * overridden pretty often. We will copy these back for drawing */ CopyOutDParam(this->params, 0, lengthof(this->params)); this->caption = caption; this->message = message; this->proc = callback; this->InitNested(WN_CONFIRM_POPUP_QUERY); this->parent = parent; this->left = parent->left + (parent->width / 2) - (this->width / 2); this->top = parent->top + (parent->height / 2) - (this->height / 2); } ~QueryWindow() { if (this->proc != NULL) this->proc(this->parent, false); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_Q_CAPTION: CopyInDParam(1, this->params, lengthof(this->params)); SetDParam(0, this->caption); break; case WID_Q_TEXT: CopyInDParam(0, this->params, lengthof(this->params)); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_Q_TEXT) return; Dimension d = GetStringMultiLineBoundingBox(this->message, *size); d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = d; } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_Q_TEXT) return; DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, this->message, TC_FROMSTRING, SA_CENTER); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_Q_YES: { /* in the Generate New World window, clicking 'Yes' causes * DeleteNonVitalWindows() to be called - we shouldn't be in a window then */ QueryCallbackProc *proc = this->proc; Window *parent = this->parent; /* Prevent the destructor calling the callback function */ this->proc = NULL; delete this; if (proc != NULL) { proc(parent, true); proc = NULL; } break; } case WID_Q_NO: delete this; break; } } virtual EventState OnKeyPress(WChar key, uint16 keycode) { /* ESC closes the window, Enter confirms the action */ switch (keycode) { case WKC_RETURN: case WKC_NUM_ENTER: if (this->proc != NULL) { this->proc(this->parent, true); this->proc = NULL; } /* FALL THROUGH */ case WKC_ESC: delete this; return ES_HANDLED; } return ES_NOT_HANDLED; } }; static const NWidgetPart _nested_query_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_RED), NWidget(WWT_CAPTION, COLOUR_RED, WID_Q_CAPTION), SetDataTip(STR_JUST_STRING, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_RED), SetPIP(8, 15, 8), NWidget(WWT_TEXT, COLOUR_RED, WID_Q_TEXT), SetMinimalSize(200, 12), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(20, 29, 20), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_NO), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_QUIT_NO, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_Q_YES), SetMinimalSize(71, 12), SetFill(1, 1), SetDataTip(STR_QUIT_YES, STR_NULL), EndContainer(), EndContainer(), }; static WindowDesc _query_desc( WDP_CENTER, NULL, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, WDF_MODAL, _nested_query_widgets, lengthof(_nested_query_widgets) ); /** * Show a modal confirmation window with standard 'yes' and 'no' buttons * The window is aligned to the centre of its parent. * @param caption string shown as window caption * @param message string that will be shown for the window * @param parent pointer to parent window, if this pointer is NULL the parent becomes * the main window WC_MAIN_WINDOW * @param callback callback function pointer to set in the window descriptor */ void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback) { if (parent == NULL) parent = FindWindowById(WC_MAIN_WINDOW, 0); const Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { if (w->window_class != WC_CONFIRM_POPUP_QUERY) continue; const QueryWindow *qw = (const QueryWindow *)w; if (qw->parent != parent || qw->proc != callback) continue; delete qw; break; } new QueryWindow(&_query_desc, caption, message, parent, callback); } openttd-1.5.3/src/fileio_func.h0000644000000000000000000001316112627373441015130 0ustar rootroot/* $Id: fileio_func.h 26489 2014-04-23 21:23:21Z rubidium $ */ /* * 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 fileio_func.h Functions for Standard In/Out file operations */ #ifndef FILEIO_FUNC_H #define FILEIO_FUNC_H #include "core/enum_type.hpp" #include "fileio_type.h" void FioSeekTo(size_t pos, int mode); void FioSeekToFile(uint8 slot, size_t pos); size_t FioGetPos(); const char *FioGetFilename(uint8 slot); byte FioReadByte(); uint16 FioReadWord(); uint32 FioReadDword(); void FioCloseAll(); void FioOpenFile(int slot, const char *filename, Subdirectory subdir); void FioReadBlock(void *ptr, size_t size); void FioSkipBytes(int n); /** * The search paths OpenTTD could search through. * At least one of the slots has to be filled with a path. * NULL paths tell that there is no such path for the * current operating system. */ extern const char *_searchpaths[NUM_SEARCHPATHS]; /** * Checks whether the given search path is a valid search path * @param sp the search path to check * @return true if the search path is valid */ static inline bool IsValidSearchPath(Searchpath sp) { return sp < NUM_SEARCHPATHS && _searchpaths[sp] != NULL; } /** Iterator for all the search paths */ #define FOR_ALL_SEARCHPATHS(sp) for (sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) if (IsValidSearchPath(sp)) void FioFCloseFile(FILE *f); FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize = NULL); bool FioCheckFileExists(const char *filename, Subdirectory subdir); char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory subdir, const char *filename); char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename); char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirectory subdir); char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir); const char *FiosGetScreenshotDir(); void SanitizeFilename(char *filename); bool AppendPathSeparator(char *buf, const char *last); void DeterminePaths(const char *exe); void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); bool FileExists(const char *filename); const char *FioTarFirstDir(const char *tarname, Subdirectory subdir); void FioTarAddLink(const char *src, const char *dest, Subdirectory subdir); bool ExtractTar(const char *tar_filename, Subdirectory subdir); extern const char *_personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. /** Helper for scanning for files with a given name */ class FileScanner { protected: Subdirectory subdir; ///< The current sub directory we are searching through public: /** Destruct the proper one... */ virtual ~FileScanner() {} uint Scan(const char *extension, Subdirectory sd, bool tars = true, bool recursive = true); uint Scan(const char *extension, const char *directory, bool recursive = true); /** * Add a file with the given filename. * @param filename the full path to the file to read * @param basepath_length amount of characters to chop of before to get a * filename relative to the search path. * @param tar_filename the name of the tar file the file is read from. * @return true if the file is added. */ virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) = 0; }; /** Helper for scanning for files with tar as extension */ class TarScanner : FileScanner { uint DoScan(Subdirectory sd); public: /** The mode of tar scanning. */ enum Mode { NONE = 0, ///< Scan nothing. BASESET = 1 << 0, ///< Scan for base sets. NEWGRF = 1 << 1, ///< Scan for non-base sets. AI = 1 << 2, ///< Scan for AIs and its libraries. SCENARIO = 1 << 3, ///< Scan for scenarios and heightmaps. GAME = 1 << 4, ///< Scan for game scripts. ALL = BASESET | NEWGRF | AI | SCENARIO | GAME, ///< Scan for everything. }; /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = NULL); bool AddFile(Subdirectory sd, const char *filename); /** Do the scan for Tars. */ static uint DoScan(TarScanner::Mode mode); }; DECLARE_ENUM_AS_BIT_SET(TarScanner::Mode) /* Implementation of opendir/readdir/closedir for Windows */ #if defined(WIN32) struct DIR; struct dirent { // XXX - only d_name implemented TCHAR *d_name; // name of found file /* little hack which will point to parent DIR struct which will * save us a call to GetFileAttributes if we want information * about the file (for example in function fio_bla) */ DIR *dir; }; DIR *opendir(const TCHAR *path); struct dirent *readdir(DIR *d); int closedir(DIR *d); #else /* Use system-supplied opendir/readdir/closedir functions */ # include # include #endif /* defined(WIN32) */ /** * A wrapper around opendir() which will convert the string from * OPENTTD encoding to that of the filesystem. For all purposes this * function behaves the same as the original opendir function * @param path string to open directory of * @return DIR pointer */ static inline DIR *ttd_opendir(const char *path) { return opendir(OTTD2FS(path)); } #endif /* FILEIO_FUNC_H */ openttd-1.5.3/src/viewport.cpp0000644000000000000000000033607212627373442015072 0ustar rootroot/* $Id: viewport.cpp 27271 2015-05-08 17:30:07Z frosch $ */ /* * 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 viewport.cpp Handling of all viewports. * * \verbatim * The in-game coordinate system looks like this * * * * ^ Z * * | * * | * * | * * | * * / \ * * / \ * * / \ * * / \ * * X < > Y * * \endverbatim */ /** * @defgroup vp_column_row Rows and columns in the viewport * * Columns are vertical sections of the viewport that are half a tile wide. * The origin, i.e. column 0, is through the northern and southern most tile. * This means that the column of e.g. Tile(0, 0) and Tile(100, 100) are in * column number 0. The negative columns are towards the left of the screen, * or towards the west, whereas the positive ones are towards respectively * the right and east. * With half a tile wide is meant that the next column of tiles directly west * or east of the centre line are respectively column -1 and 1. Their tile * centers are only half a tile from the center of their adjoining tile when * looking only at the X-coordinate. * * \verbatim * ╳ * * ╱ ╲ * * ╳ 0 ╳ * * ╱ ╲ ╱ ╲ * * ╳-1 ╳ 1 ╳ * * ╱ ╲ ╱ ╲ ╱ ╲ * * ╳-2 ╳ 0 ╳ 2 ╳ * * ╲ ╱ ╲ ╱ ╲ ╱ * * ╳-1 ╳ 1 ╳ * * ╲ ╱ ╲ ╱ * * ╳ 0 ╳ * * ╲ ╱ * * ╳ * * \endverbatim * * * Rows are horizontal sections of the viewport, also half a tile wide. * This time the nothern most tile on the map defines 0 and * everything south of that has a positive number. */ #include "stdafx.h" #include "landscape.h" #include "viewport_func.h" #include "station_base.h" #include "waypoint_base.h" #include "town.h" #include "signs_base.h" #include "signs_func.h" #include "vehicle_base.h" #include "vehicle_gui.h" #include "blitter/factory.hpp" #include "strings_func.h" #include "zoom_func.h" #include "vehicle_func.h" #include "company_func.h" #include "waypoint_func.h" #include "window_func.h" #include "tilehighlight_func.h" #include "window_gui.h" #include "linkgraph/linkgraph_gui.h" #include "viewport_sprite_sorter.h" #include "bridge_map.h" #include #include "table/strings.h" #include "table/palettes.h" #include "safeguards.h" Point _tile_fract_coords; static const int MAX_TILE_EXTENT_LEFT = ZOOM_LVL_BASE * TILE_PIXELS; ///< Maximum left extent of tile relative to north corner. static const int MAX_TILE_EXTENT_RIGHT = ZOOM_LVL_BASE * TILE_PIXELS; ///< Maximum right extent of tile relative to north corner. static const int MAX_TILE_EXTENT_TOP = ZOOM_LVL_BASE * MAX_BUILDING_PIXELS; ///< Maximum top extent of tile relative to north corner (not considering bridges). static const int MAX_TILE_EXTENT_BOTTOM = ZOOM_LVL_BASE * (TILE_PIXELS + 2 * TILE_HEIGHT); ///< Maximum bottom extent of tile relative to north corner (worst case: #SLOPE_STEEP_N). struct StringSpriteToDraw { StringID string; Colours colour; int32 x; int32 y; uint64 params[2]; uint16 width; }; struct TileSpriteToDraw { SpriteID image; PaletteID pal; const SubSprite *sub; ///< only draw a rectangular part of the sprite int32 x; ///< screen X coordinate of sprite int32 y; ///< screen Y coordinate of sprite }; struct ChildScreenSpriteToDraw { SpriteID image; PaletteID pal; const SubSprite *sub; ///< only draw a rectangular part of the sprite int32 x; int32 y; int next; ///< next child to draw (-1 at the end) }; /** Enumeration of multi-part foundations */ enum FoundationPart { FOUNDATION_PART_NONE = 0xFF, ///< Neither foundation nor groundsprite drawn yet. FOUNDATION_PART_NORMAL = 0, ///< First part (normal foundation or no foundation) FOUNDATION_PART_HALFTILE = 1, ///< Second part (halftile foundation) FOUNDATION_PART_END }; /** * Mode of "sprite combining" * @see StartSpriteCombine */ enum SpriteCombineMode { SPRITE_COMBINE_NONE, ///< Every #AddSortableSpriteToDraw start its own bounding box SPRITE_COMBINE_PENDING, ///< %Sprite combining will start with the next unclipped sprite. SPRITE_COMBINE_ACTIVE, ///< %Sprite combining is active. #AddSortableSpriteToDraw outputs child sprites. }; typedef SmallVector TileSpriteToDrawVector; typedef SmallVector StringSpriteToDrawVector; typedef SmallVector ParentSpriteToDrawVector; typedef SmallVector ChildScreenSpriteToDrawVector; /** Data structure storing rendering information */ struct ViewportDrawer { DrawPixelInfo dpi; StringSpriteToDrawVector string_sprites_to_draw; TileSpriteToDrawVector tile_sprites_to_draw; ParentSpriteToDrawVector parent_sprites_to_draw; ParentSpriteToSortVector parent_sprites_to_sort; ///< Parent sprite pointer array used for sorting ChildScreenSpriteToDrawVector child_screen_sprites_to_draw; int *last_child; SpriteCombineMode combine_sprites; ///< Current mode of "sprite combining". @see StartSpriteCombine int foundation[FOUNDATION_PART_END]; ///< Foundation sprites (index into parent_sprites_to_draw). FoundationPart foundation_part; ///< Currently active foundation for ground sprite drawing. int *last_foundation_child[FOUNDATION_PART_END]; ///< Tail of ChildSprite list of the foundations. (index into child_screen_sprites_to_draw) Point foundation_offset[FOUNDATION_PART_END]; ///< Pixel offset for ground sprites on the foundations. }; static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom); static ViewportDrawer _vd; TileHighlightData _thd; static TileInfo *_cur_ti; bool _draw_bounding_boxes = false; bool _draw_dirty_blocks = false; uint _dirty_block_colour = 0; static VpSpriteSorter _vp_sprite_sorter = NULL; static Point MapXYZToViewport(const ViewPort *vp, int x, int y, int z) { Point p = RemapCoords(x, y, z); p.x -= vp->virtual_width / 2; p.y -= vp->virtual_height / 2; return p; } void DeleteWindowViewport(Window *w) { if (w->viewport == NULL) return; delete w->viewport->overlay; free(w->viewport); w->viewport = NULL; } /** * Initialize viewport of the window for use. * @param w Window to use/display the viewport in * @param x Offset of left edge of viewport with respect to left edge window \a w * @param y Offset of top edge of viewport with respect to top edge window \a w * @param width Width of the viewport * @param height Height of the viewport * @param follow_flags Flags controlling the viewport. * - If bit 31 is set, the lower 20 bits are the vehicle that the viewport should follow. * - If bit 31 is clear, it is a #TileIndex. * @param zoom Zoomlevel to display */ void InitializeWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom) { assert(w->viewport == NULL); ViewportData *vp = CallocT(1); vp->left = x + w->left; vp->top = y + w->top; vp->width = width; vp->height = height; vp->zoom = static_cast(Clamp(zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); vp->virtual_width = ScaleByZoom(width, zoom); vp->virtual_height = ScaleByZoom(height, zoom); Point pt; if (follow_flags & 0x80000000) { const Vehicle *veh; vp->follow_vehicle = (VehicleID)(follow_flags & 0xFFFFF); veh = Vehicle::Get(vp->follow_vehicle); pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos); } else { uint x = TileX(follow_flags) * TILE_SIZE; uint y = TileY(follow_flags) * TILE_SIZE; vp->follow_vehicle = INVALID_VEHICLE; pt = MapXYZToViewport(vp, x, y, GetSlopePixelZ(x, y)); } vp->scrollpos_x = pt.x; vp->scrollpos_y = pt.y; vp->dest_scrollpos_x = pt.x; vp->dest_scrollpos_y = pt.y; vp->overlay = NULL; w->viewport = vp; vp->virtual_left = 0; // pt.x; vp->virtual_top = 0; // pt.y; } static Point _vp_move_offs; static void DoSetViewportPosition(const Window *w, int left, int top, int width, int height) { FOR_ALL_WINDOWS_FROM_BACK_FROM(w, w) { if (left + width > w->left && w->left + w->width > left && top + height > w->top && w->top + w->height > top) { if (left < w->left) { DoSetViewportPosition(w, left, top, w->left - left, height); DoSetViewportPosition(w, left + (w->left - left), top, width - (w->left - left), height); return; } if (left + width > w->left + w->width) { DoSetViewportPosition(w, left, top, (w->left + w->width - left), height); DoSetViewportPosition(w, left + (w->left + w->width - left), top, width - (w->left + w->width - left), height); return; } if (top < w->top) { DoSetViewportPosition(w, left, top, width, (w->top - top)); DoSetViewportPosition(w, left, top + (w->top - top), width, height - (w->top - top)); return; } if (top + height > w->top + w->height) { DoSetViewportPosition(w, left, top, width, (w->top + w->height - top)); DoSetViewportPosition(w, left, top + (w->top + w->height - top), width, height - (w->top + w->height - top)); return; } return; } } { int xo = _vp_move_offs.x; int yo = _vp_move_offs.y; if (abs(xo) >= width || abs(yo) >= height) { /* fully_outside */ RedrawScreenRect(left, top, left + width, top + height); return; } GfxScroll(left, top, width, height, xo, yo); if (xo > 0) { RedrawScreenRect(left, top, xo + left, top + height); left += xo; width -= xo; } else if (xo < 0) { RedrawScreenRect(left + width + xo, top, left + width, top + height); width += xo; } if (yo > 0) { RedrawScreenRect(left, top, width + left, top + yo); } else if (yo < 0) { RedrawScreenRect(left, top + height + yo, width + left, top + height); } } } static void SetViewportPosition(Window *w, int x, int y) { ViewPort *vp = w->viewport; int old_left = vp->virtual_left; int old_top = vp->virtual_top; int i; int left, top, width, height; vp->virtual_left = x; vp->virtual_top = y; /* Viewport is bound to its left top corner, so it must be rounded down (UnScaleByZoomLower) * else glitch described in FS#1412 will happen (offset by 1 pixel with zoom level > NORMAL) */ old_left = UnScaleByZoomLower(old_left, vp->zoom); old_top = UnScaleByZoomLower(old_top, vp->zoom); x = UnScaleByZoomLower(x, vp->zoom); y = UnScaleByZoomLower(y, vp->zoom); old_left -= x; old_top -= y; if (old_top == 0 && old_left == 0) return; _vp_move_offs.x = old_left; _vp_move_offs.y = old_top; left = vp->left; top = vp->top; width = vp->width; height = vp->height; if (left < 0) { width += left; left = 0; } i = left + width - _screen.width; if (i >= 0) width -= i; if (width > 0) { if (top < 0) { height += top; top = 0; } i = top + height - _screen.height; if (i >= 0) height -= i; if (height > 0) DoSetViewportPosition(w->z_front, left, top, width, height); } } /** * Is a xy position inside the viewport of the window? * @param w Window to examine its viewport * @param x X coordinate of the xy position * @param y Y coordinate of the xy position * @return Pointer to the viewport if the xy position is in the viewport of the window, * otherwise \c NULL is returned. */ ViewPort *IsPtInWindowViewport(const Window *w, int x, int y) { ViewPort *vp = w->viewport; if (vp != NULL && IsInsideMM(x, vp->left, vp->left + vp->width) && IsInsideMM(y, vp->top, vp->top + vp->height)) return vp; return NULL; } /** * Translate screen coordinate in a viewport to a tile coordinate * @param vp Viewport that contains the (\a x, \a y) screen coordinate * @param x Screen x coordinate * @param y Screen y coordinate * @param clamp_to_map Clamp the coordinate outside of the map to the closest tile within the map. * @return Tile coordinate */ Point TranslateXYToTileCoord(const ViewPort *vp, int x, int y, bool clamp_to_map) { Point pt; int a, b; int z; if ( (uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) { Point pt = {-1, -1}; return pt; } x = (ScaleByZoom(x, vp->zoom) + vp->virtual_left) >> (2 + ZOOM_LVL_SHIFT); y = (ScaleByZoom(y, vp->zoom) + vp->virtual_top) >> (1 + ZOOM_LVL_SHIFT); a = y - x; b = y + x; if (clamp_to_map) { /* Bring the coordinates near to a valid range. This is mostly due to the * tiles on the north side of the map possibly being drawn too high due to * the extra height levels. So at the top we allow a number of extra tiles. * This number is based on the tile height and pixels. */ int extra_tiles = CeilDiv(_settings_game.construction.max_heightlevel * TILE_HEIGHT, TILE_PIXELS); a = Clamp(a, -extra_tiles * TILE_SIZE, MapMaxX() * TILE_SIZE - 1); b = Clamp(b, -extra_tiles * TILE_SIZE, MapMaxY() * TILE_SIZE - 1); } /* (a, b) is the X/Y-world coordinate that belongs to (x,y) if the landscape would be completely flat on height 0. * Now find the Z-world coordinate by fix point iteration. * This is a bit tricky because the tile height is non-continuous at foundations. * The clicked point should be approached from the back, otherwise there are regions that are not clickable. * (FOUNDATION_HALFTILE_LOWER on SLOPE_STEEP_S hides north halftile completely) * So give it a z-malus of 4 in the first iterations. */ z = 0; int min_coord = _settings_game.construction.freeform_edges ? TILE_SIZE : 0; for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(a + max(z, 4) - 4, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + max(z, 4) - 4, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; for (int malus = 3; malus > 0; malus--) z = GetSlopePixelZ(Clamp(a + max(z, malus) - malus, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + max(z, malus) - malus, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; for (int i = 0; i < 5; i++) z = GetSlopePixelZ(Clamp(a + z, min_coord, MapMaxX() * TILE_SIZE - 1), Clamp(b + z, min_coord, MapMaxY() * TILE_SIZE - 1)) / 2; if (clamp_to_map) { pt.x = Clamp(a + z, min_coord, MapMaxX() * TILE_SIZE - 1); pt.y = Clamp(b + z, min_coord, MapMaxY() * TILE_SIZE - 1); } else { pt.x = a + z; pt.y = b + z; } return pt; } /* When used for zooming, check area below current coordinates (x,y) * and return the tile of the zoomed out/in position (zoom_x, zoom_y) * when you just want the tile, make x = zoom_x and y = zoom_y */ static Point GetTileFromScreenXY(int x, int y, int zoom_x, int zoom_y) { Window *w; ViewPort *vp; Point pt; if ( (w = FindWindowFromPt(x, y)) != NULL && (vp = IsPtInWindowViewport(w, x, y)) != NULL) return TranslateXYToTileCoord(vp, zoom_x, zoom_y); pt.y = pt.x = -1; return pt; } Point GetTileBelowCursor() { return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, _cursor.pos.x, _cursor.pos.y); } Point GetTileZoomCenterWindow(bool in, Window * w) { int x, y; ViewPort *vp = w->viewport; if (in) { x = ((_cursor.pos.x - vp->left) >> 1) + (vp->width >> 2); y = ((_cursor.pos.y - vp->top) >> 1) + (vp->height >> 2); } else { x = vp->width - (_cursor.pos.x - vp->left); y = vp->height - (_cursor.pos.y - vp->top); } /* Get the tile below the cursor and center on the zoomed-out center */ return GetTileFromScreenXY(_cursor.pos.x, _cursor.pos.y, x + vp->left, y + vp->top); } /** * Update the status of the zoom-buttons according to the zoom-level * of the viewport. This will update their status and invalidate accordingly * @param w Window pointer to the window that has the zoom buttons * @param vp pointer to the viewport whose zoom-level the buttons represent * @param widget_zoom_in widget index for window with zoom-in button * @param widget_zoom_out widget index for window with zoom-out button */ void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte widget_zoom_out) { w->SetWidgetDisabledState(widget_zoom_in, vp->zoom <= _settings_client.gui.zoom_min); w->SetWidgetDirty(widget_zoom_in); w->SetWidgetDisabledState(widget_zoom_out, vp->zoom >= _settings_client.gui.zoom_max); w->SetWidgetDirty(widget_zoom_out); } /** * Schedules a tile sprite for drawing. * * @param image the image to draw. * @param pal the provided palette. * @param x position x (world coordinates) of the sprite. * @param y position y (world coordinates) of the sprite. * @param z position z (world coordinates) of the sprite. * @param sub Only draw a part of the sprite. * @param extra_offs_x Pixel X offset for the sprite position. * @param extra_offs_y Pixel Y offset for the sprite position. */ static void AddTileSpriteToDraw(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0) { assert((image & SPRITE_MASK) < MAX_SPRITES); TileSpriteToDraw *ts = _vd.tile_sprites_to_draw.Append(); ts->image = image; ts->pal = pal; ts->sub = sub; Point pt = RemapCoords(x, y, z); ts->x = pt.x + extra_offs_x; ts->y = pt.y + extra_offs_y; } /** * Adds a child sprite to the active foundation. * * The pixel offset of the sprite relative to the ParentSprite is the sum of the offset passed to OffsetGroundSprite() and extra_offs_?. * * @param image the image to draw. * @param pal the provided palette. * @param sub Only draw a part of the sprite. * @param foundation_part Foundation part. * @param extra_offs_x Pixel X offset for the sprite position. * @param extra_offs_y Pixel Y offset for the sprite position. */ static void AddChildSpriteToFoundation(SpriteID image, PaletteID pal, const SubSprite *sub, FoundationPart foundation_part, int extra_offs_x, int extra_offs_y) { assert(IsInsideMM(foundation_part, 0, FOUNDATION_PART_END)); assert(_vd.foundation[foundation_part] != -1); Point offs = _vd.foundation_offset[foundation_part]; /* Change the active ChildSprite list to the one of the foundation */ int *old_child = _vd.last_child; _vd.last_child = _vd.last_foundation_child[foundation_part]; AddChildSpriteScreen(image, pal, offs.x + extra_offs_x, offs.y + extra_offs_y, false, sub, false); /* Switch back to last ChildSprite list */ _vd.last_child = old_child; } /** * Draws a ground sprite at a specific world-coordinate relative to the current tile. * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. * * @param image the image to draw. * @param pal the provided palette. * @param x position x (world coordinates) of the sprite relative to current tile. * @param y position y (world coordinates) of the sprite relative to current tile. * @param z position z (world coordinates) of the sprite relative to current tile. * @param sub Only draw a part of the sprite. * @param extra_offs_x Pixel X offset for the sprite position. * @param extra_offs_y Pixel Y offset for the sprite position. */ void DrawGroundSpriteAt(SpriteID image, PaletteID pal, int32 x, int32 y, int z, const SubSprite *sub, int extra_offs_x, int extra_offs_y) { /* Switch to first foundation part, if no foundation was drawn */ if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL; if (_vd.foundation[_vd.foundation_part] != -1) { Point pt = RemapCoords(x, y, z); AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, pt.x + extra_offs_x * ZOOM_LVL_BASE, pt.y + extra_offs_y * ZOOM_LVL_BASE); } else { AddTileSpriteToDraw(image, pal, _cur_ti->x + x, _cur_ti->y + y, _cur_ti->z + z, sub, extra_offs_x * ZOOM_LVL_BASE, extra_offs_y * ZOOM_LVL_BASE); } } /** * Draws a ground sprite for the current tile. * If the current tile is drawn on top of a foundation the sprite is added as child sprite to the "foundation"-ParentSprite. * * @param image the image to draw. * @param pal the provided palette. * @param sub Only draw a part of the sprite. * @param extra_offs_x Pixel X offset for the sprite position. * @param extra_offs_y Pixel Y offset for the sprite position. */ void DrawGroundSprite(SpriteID image, PaletteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y) { DrawGroundSpriteAt(image, pal, 0, 0, 0, sub, extra_offs_x, extra_offs_y); } /** * Called when a foundation has been drawn for the current tile. * Successive ground sprites for the current tile will be drawn as child sprites of the "foundation"-ParentSprite, not as TileSprites. * * @param x sprite x-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. * @param y sprite y-offset (screen coordinates) of ground sprites relative to the "foundation"-ParentSprite. */ void OffsetGroundSprite(int x, int y) { /* Switch to next foundation part */ switch (_vd.foundation_part) { case FOUNDATION_PART_NONE: _vd.foundation_part = FOUNDATION_PART_NORMAL; break; case FOUNDATION_PART_NORMAL: _vd.foundation_part = FOUNDATION_PART_HALFTILE; break; default: NOT_REACHED(); } /* _vd.last_child == NULL if foundation sprite was clipped by the viewport bounds */ if (_vd.last_child != NULL) _vd.foundation[_vd.foundation_part] = _vd.parent_sprites_to_draw.Length() - 1; _vd.foundation_offset[_vd.foundation_part].x = x * ZOOM_LVL_BASE; _vd.foundation_offset[_vd.foundation_part].y = y * ZOOM_LVL_BASE; _vd.last_foundation_child[_vd.foundation_part] = _vd.last_child; } /** * Adds a child sprite to a parent sprite. * In contrast to "AddChildSpriteScreen()" the sprite position is in world coordinates * * @param image the image to draw. * @param pal the provided palette. * @param x position x of the sprite. * @param y position y of the sprite. * @param z position z of the sprite. * @param sub Only draw a part of the sprite. */ static void AddCombinedSprite(SpriteID image, PaletteID pal, int x, int y, int z, const SubSprite *sub) { Point pt = RemapCoords(x, y, z); const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL); if (pt.x + spr->x_offs >= _vd.dpi.left + _vd.dpi.width || pt.x + spr->x_offs + spr->width <= _vd.dpi.left || pt.y + spr->y_offs >= _vd.dpi.top + _vd.dpi.height || pt.y + spr->y_offs + spr->height <= _vd.dpi.top) return; const ParentSpriteToDraw *pstd = _vd.parent_sprites_to_draw.End() - 1; AddChildSpriteScreen(image, pal, pt.x - pstd->left, pt.y - pstd->top, false, sub, false); } /** * Draw a (transparent) sprite at given coordinates with a given bounding box. * The bounding box extends from (x + bb_offset_x, y + bb_offset_y, z + bb_offset_z) to (x + w - 1, y + h - 1, z + dz - 1), both corners included. * Bounding boxes with bb_offset_x == w or bb_offset_y == h or bb_offset_z == dz are allowed and produce thin slices. * * @note Bounding boxes are normally specified with bb_offset_x = bb_offset_y = bb_offset_z = 0. The extent of the bounding box in negative direction is * defined by the sprite offset in the grf file. * However if modifying the sprite offsets is not suitable (e.g. when using existing graphics), the bounding box can be tuned by bb_offset. * * @pre w >= bb_offset_x, h >= bb_offset_y, dz >= bb_offset_z. Else w, h or dz are ignored. * * @param image the image to combine and draw, * @param pal the provided palette, * @param x position X (world) of the sprite, * @param y position Y (world) of the sprite, * @param w bounding box extent towards positive X (world), * @param h bounding box extent towards positive Y (world), * @param dz bounding box extent towards positive Z (world), * @param z position Z (world) of the sprite, * @param transparent if true, switch the palette between the provided palette and the transparent palette, * @param bb_offset_x bounding box extent towards negative X (world), * @param bb_offset_y bounding box extent towards negative Y (world), * @param bb_offset_z bounding box extent towards negative Z (world) * @param sub Only draw a part of the sprite. */ void AddSortableSpriteToDraw(SpriteID image, PaletteID pal, int x, int y, int w, int h, int dz, int z, bool transparent, int bb_offset_x, int bb_offset_y, int bb_offset_z, const SubSprite *sub) { int32 left, right, top, bottom; assert((image & SPRITE_MASK) < MAX_SPRITES); /* make the sprites transparent with the right palette */ if (transparent) { SetBit(image, PALETTE_MODIFIER_TRANSPARENT); pal = PALETTE_TO_TRANSPARENT; } if (_vd.combine_sprites == SPRITE_COMBINE_ACTIVE) { AddCombinedSprite(image, pal, x, y, z, sub); return; } _vd.last_child = NULL; Point pt = RemapCoords(x, y, z); int tmp_left, tmp_top, tmp_x = pt.x, tmp_y = pt.y; /* Compute screen extents of sprite */ if (image == SPR_EMPTY_BOUNDING_BOX) { left = tmp_left = RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x; right = RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1; top = tmp_top = RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y; bottom = RemapCoords(x + w , y + h , z + bb_offset_z).y + 1; } else { const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL); left = tmp_left = (pt.x += spr->x_offs); right = (pt.x + spr->width ); top = tmp_top = (pt.y += spr->y_offs); bottom = (pt.y + spr->height); } if (_draw_bounding_boxes && (image != SPR_EMPTY_BOUNDING_BOX)) { /* Compute maximal extents of sprite and its bounding box */ left = min(left , RemapCoords(x + w , y + bb_offset_y, z + bb_offset_z).x); right = max(right , RemapCoords(x + bb_offset_x, y + h , z + bb_offset_z).x + 1); top = min(top , RemapCoords(x + bb_offset_x, y + bb_offset_y, z + dz ).y); bottom = max(bottom, RemapCoords(x + w , y + h , z + bb_offset_z).y + 1); } /* Do not add the sprite to the viewport, if it is outside */ if (left >= _vd.dpi.left + _vd.dpi.width || right <= _vd.dpi.left || top >= _vd.dpi.top + _vd.dpi.height || bottom <= _vd.dpi.top) { return; } ParentSpriteToDraw *ps = _vd.parent_sprites_to_draw.Append(); ps->x = tmp_x; ps->y = tmp_y; ps->left = tmp_left; ps->top = tmp_top; ps->image = image; ps->pal = pal; ps->sub = sub; ps->xmin = x + bb_offset_x; ps->xmax = x + max(bb_offset_x, w) - 1; ps->ymin = y + bb_offset_y; ps->ymax = y + max(bb_offset_y, h) - 1; ps->zmin = z + bb_offset_z; ps->zmax = z + max(bb_offset_z, dz) - 1; ps->comparison_done = false; ps->first_child = -1; _vd.last_child = &ps->first_child; if (_vd.combine_sprites == SPRITE_COMBINE_PENDING) _vd.combine_sprites = SPRITE_COMBINE_ACTIVE; } /** * Starts a block of sprites, which are "combined" into a single bounding box. * * Subsequent calls to #AddSortableSpriteToDraw will be drawn into the same bounding box. * That is: The first sprite that is not clipped by the viewport defines the bounding box, and * the following sprites will be child sprites to that one. * * That implies: * - The drawing order is definite. No other sprites will be sorted between those of the block. * - You have to provide a valid bounding box for all sprites, * as you won't know which one is the first non-clipped one. * Preferable you use the same bounding box for all. * - You cannot use #AddChildSpriteScreen inside the block, as its result will be indefinite. * * The block is terminated by #EndSpriteCombine. * * You cannot nest "combined" blocks. */ void StartSpriteCombine() { assert(_vd.combine_sprites == SPRITE_COMBINE_NONE); _vd.combine_sprites = SPRITE_COMBINE_PENDING; } /** * Terminates a block of sprites started by #StartSpriteCombine. * Take a look there for details. */ void EndSpriteCombine() { assert(_vd.combine_sprites != SPRITE_COMBINE_NONE); _vd.combine_sprites = SPRITE_COMBINE_NONE; } /** * Check if the parameter "check" is inside the interval between * begin and end, including both begin and end. * @note Whether \c begin or \c end is the biggest does not matter. * This method will account for that. * @param begin The begin of the interval. * @param end The end of the interval. * @param check The value to check. */ static bool IsInRangeInclusive(int begin, int end, int check) { if (begin > end) Swap(begin, end); return begin <= check && check <= end; } /** * Checks whether a point is inside the selected a diagonal rectangle given by _thd.size and _thd.pos * @param x The x coordinate of the point to be checked. * @param y The y coordinate of the point to be checked. * @return True if the point is inside the rectangle, else false. */ bool IsInsideRotatedRectangle(int x, int y) { int dist_a = (_thd.size.x + _thd.size.y); // Rotated coordinate system for selected rectangle. int dist_b = (_thd.size.x - _thd.size.y); // We don't have to divide by 2. It's all relative! int a = ((x - _thd.pos.x) + (y - _thd.pos.y)); // Rotated coordinate system for the point under scrutiny. int b = ((x - _thd.pos.x) - (y - _thd.pos.y)); /* Check if a and b are between 0 and dist_a or dist_b respectively. */ return IsInRangeInclusive(dist_a, 0, a) && IsInRangeInclusive(dist_b, 0, b); } /** * Add a child sprite to a parent sprite. * * @param image the image to draw. * @param pal the provided palette. * @param x sprite x-offset (screen coordinates) relative to parent sprite. * @param y sprite y-offset (screen coordinates) relative to parent sprite. * @param transparent if true, switch the palette between the provided palette and the transparent palette, * @param sub Only draw a part of the sprite. */ void AddChildSpriteScreen(SpriteID image, PaletteID pal, int x, int y, bool transparent, const SubSprite *sub, bool scale) { assert((image & SPRITE_MASK) < MAX_SPRITES); /* If the ParentSprite was clipped by the viewport bounds, do not draw the ChildSprites either */ if (_vd.last_child == NULL) return; /* make the sprites transparent with the right palette */ if (transparent) { SetBit(image, PALETTE_MODIFIER_TRANSPARENT); pal = PALETTE_TO_TRANSPARENT; } *_vd.last_child = _vd.child_screen_sprites_to_draw.Length(); ChildScreenSpriteToDraw *cs = _vd.child_screen_sprites_to_draw.Append(); cs->image = image; cs->pal = pal; cs->sub = sub; cs->x = scale ? x * ZOOM_LVL_BASE : x; cs->y = scale ? y * ZOOM_LVL_BASE : y; cs->next = -1; /* Append the sprite to the active ChildSprite list. * If the active ParentSprite is a foundation, update last_foundation_child as well. * Note: ChildSprites of foundations are NOT sequential in the vector, as selection sprites are added at last. */ if (_vd.last_foundation_child[0] == _vd.last_child) _vd.last_foundation_child[0] = &cs->next; if (_vd.last_foundation_child[1] == _vd.last_child) _vd.last_foundation_child[1] = &cs->next; _vd.last_child = &cs->next; } static void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, Colours colour, uint16 width) { assert(width != 0); StringSpriteToDraw *ss = _vd.string_sprites_to_draw.Append(); ss->string = string; ss->x = x; ss->y = y; ss->params[0] = params_1; ss->params[1] = params_2; ss->width = width; ss->colour = colour; } /** * Draws sprites between ground sprite and everything above. * * The sprite is either drawn as TileSprite or as ChildSprite of the active foundation. * * @param image the image to draw. * @param pal the provided palette. * @param ti TileInfo Tile that is being drawn * @param z_offset Z offset relative to the groundsprite. Only used for the sprite position, not for sprite sorting. * @param foundation_part Foundation part the sprite belongs to. */ static void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part) { /* FIXME: This is not totally valid for some autorail highlights that extend over the edges of the tile. */ if (_vd.foundation[foundation_part] == -1) { /* draw on real ground */ AddTileSpriteToDraw(image, pal, ti->x, ti->y, ti->z + z_offset); } else { /* draw on top of foundation */ AddChildSpriteToFoundation(image, pal, NULL, foundation_part, 0, -z_offset * ZOOM_LVL_BASE); } } /** * Draws a selection rectangle on a tile. * * @param ti TileInfo Tile that is being drawn * @param pal Palette to apply. */ static void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal) { if (!IsValidTile(ti->tile)) return; SpriteID sel; if (IsHalftileSlope(ti->tileh)) { Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); SpriteID sel2 = SPR_HALFTILE_SELECTION_FLAT + halftile_corner; DrawSelectionSprite(sel2, pal, ti, 7 + TILE_HEIGHT, FOUNDATION_PART_HALFTILE); Corner opposite_corner = OppositeCorner(halftile_corner); if (IsSteepSlope(ti->tileh)) { sel = SPR_HALFTILE_SELECTION_DOWN; } else { sel = ((ti->tileh & SlopeWithOneCornerRaised(opposite_corner)) != 0 ? SPR_HALFTILE_SELECTION_UP : SPR_HALFTILE_SELECTION_FLAT); } sel += opposite_corner; } else { sel = SPR_SELECT_TILE + SlopeToSpriteOffset(ti->tileh); } DrawSelectionSprite(sel, pal, ti, 7, FOUNDATION_PART_NORMAL); } static bool IsPartOfAutoLine(int px, int py) { px -= _thd.selstart.x; py -= _thd.selstart.y; if ((_thd.drawstyle & HT_DRAG_MASK) != HT_LINE) return false; switch (_thd.drawstyle & HT_DIR_MASK) { case HT_DIR_X: return py == 0; // x direction case HT_DIR_Y: return px == 0; // y direction case HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper case HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower case HT_DIR_VL: return px == py || px == py + 16; // vertical left case HT_DIR_VR: return px == py || px == py - 16; // vertical right default: NOT_REACHED(); } } /* [direction][side] */ static const HighLightStyle _autorail_type[6][2] = { { HT_DIR_X, HT_DIR_X }, { HT_DIR_Y, HT_DIR_Y }, { HT_DIR_HU, HT_DIR_HL }, { HT_DIR_HL, HT_DIR_HU }, { HT_DIR_VL, HT_DIR_VR }, { HT_DIR_VR, HT_DIR_VL } }; #include "table/autorail.h" /** * Draws autorail highlights. * * @param *ti TileInfo Tile that is being drawn * @param autorail_type Offset into _AutorailTilehSprite[][] */ static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type) { SpriteID image; PaletteID pal; int offset; FoundationPart foundation_part = FOUNDATION_PART_NORMAL; Slope autorail_tileh = RemoveHalftileSlope(ti->tileh); if (IsHalftileSlope(ti->tileh)) { static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U }; Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); if (autorail_type != _lower_rail[halftile_corner]) { foundation_part = FOUNDATION_PART_HALFTILE; /* Here we draw the highlights of the "three-corners-raised"-slope. That looks ok to me. */ autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner)); } } offset = _AutorailTilehSprite[autorail_tileh][autorail_type]; if (offset >= 0) { image = SPR_AUTORAIL_BASE + offset; pal = PAL_NONE; } else { image = SPR_AUTORAIL_BASE - offset; pal = PALETTE_SEL_TILE_RED; } DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part); } /** * Checks if the specified tile is selected and if so draws selection using correct selectionstyle. * @param *ti TileInfo Tile that is being drawn */ static void DrawTileSelection(const TileInfo *ti) { /* Draw a red error square? */ bool is_redsq = _thd.redsq == ti->tile; if (is_redsq) DrawTileSelectionRect(ti, PALETTE_TILE_RED_PULSATING); /* No tile selection active? */ if ((_thd.drawstyle & HT_DRAG_MASK) == HT_NONE) return; if (_thd.diagonal) { // We're drawing a 45 degrees rotated (diagonal) rectangle if (IsInsideRotatedRectangle((int)ti->x, (int)ti->y)) goto draw_inner; return; } /* Inside the inner area? */ if (IsInsideBS(ti->x, _thd.pos.x, _thd.size.x) && IsInsideBS(ti->y, _thd.pos.y, _thd.size.y)) { draw_inner: if (_thd.drawstyle & HT_RECT) { if (!is_redsq) DrawTileSelectionRect(ti, _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE); } else if (_thd.drawstyle & HT_POINT) { /* Figure out the Z coordinate for the single dot. */ int z = 0; FoundationPart foundation_part = FOUNDATION_PART_NORMAL; if (ti->tileh & SLOPE_N) { z += TILE_HEIGHT; if (RemoveHalftileSlope(ti->tileh) == SLOPE_STEEP_N) z += TILE_HEIGHT; } if (IsHalftileSlope(ti->tileh)) { Corner halftile_corner = GetHalftileSlopeCorner(ti->tileh); if ((halftile_corner == CORNER_W) || (halftile_corner == CORNER_E)) z += TILE_HEIGHT; if (halftile_corner != CORNER_S) { foundation_part = FOUNDATION_PART_HALFTILE; if (IsSteepSlope(ti->tileh)) z -= TILE_HEIGHT; } } DrawSelectionSprite(_cur_dpi->zoom <= ZOOM_LVL_DETAIL ? SPR_DOT : SPR_DOT_SMALL, PAL_NONE, ti, z, foundation_part); } else if (_thd.drawstyle & HT_RAIL) { /* autorail highlight piece under cursor */ HighLightStyle type = _thd.drawstyle & HT_DIR_MASK; assert(type < HT_DIR_END); DrawAutorailSelection(ti, _autorail_type[type][0]); } else if (IsPartOfAutoLine(ti->x, ti->y)) { /* autorail highlighting long line */ HighLightStyle dir = _thd.drawstyle & HT_DIR_MASK; uint side; if (dir == HT_DIR_X || dir == HT_DIR_Y) { side = 0; } else { TileIndex start = TileVirtXY(_thd.selstart.x, _thd.selstart.y); side = Delta(Delta(TileX(start), TileX(ti->tile)), Delta(TileY(start), TileY(ti->tile))); } DrawAutorailSelection(ti, _autorail_type[dir][side]); } return; } /* Check if it's inside the outer area? */ if (!is_redsq && _thd.outersize.x > 0 && IsInsideBS(ti->x, _thd.pos.x + _thd.offs.x, _thd.size.x + _thd.outersize.x) && IsInsideBS(ti->y, _thd.pos.y + _thd.offs.y, _thd.size.y + _thd.outersize.y)) { /* Draw a blue rect. */ DrawTileSelectionRect(ti, PALETTE_SEL_TILE_BLUE); return; } } /** * Returns the y coordinate in the viewport coordinate system where the given * tile is painted. * @param tile Any tile. * @return The viewport y coordinate where the tile is painted. */ static int GetViewportY(Point tile) { /* Each increment in X or Y direction moves down by half a tile, i.e. TILE_PIXELS / 2. */ return (tile.y * (int)(TILE_PIXELS / 2) + tile.x * (int)(TILE_PIXELS / 2) - TilePixelHeightOutsideMap(tile.x, tile.y)) << ZOOM_LVL_SHIFT; } /** * Add the landscape to the viewport, i.e. all ground tiles and buildings. */ static void ViewportAddLandscape() { assert(_vd.dpi.top <= _vd.dpi.top + _vd.dpi.height); assert(_vd.dpi.left <= _vd.dpi.left + _vd.dpi.width); Point upper_left = InverseRemapCoords(_vd.dpi.left, _vd.dpi.top); Point upper_right = InverseRemapCoords(_vd.dpi.left + _vd.dpi.width, _vd.dpi.top); /* Transformations between tile coordinates and viewport rows/columns: See vp_column_row * column = y - x * row = x + y * x = (row - column) / 2 * y = (row + column) / 2 * Note: (row, columns) pairs are only valid, if they are both even or both odd. */ /* Columns overlap with neighbouring columns by a half tile. * - Left column is column of upper_left (rounded down) and one column to the left. * - Right column is column of upper_right (rounded up) and one column to the right. * Note: Integer-division does not round down for negative numbers, so ensure rounding with another increment/decrement. */ int left_column = (upper_left.y - upper_left.x) / (int)TILE_SIZE - 2; int right_column = (upper_right.y - upper_right.x) / (int)TILE_SIZE + 2; int potential_bridge_height = ZOOM_LVL_BASE * TILE_HEIGHT * _settings_game.construction.max_bridge_height; /* Rows overlap with neighbouring rows by a half tile. * The first row that could possibly be visible is the row above upper_left (if it is at height 0). * Due to integer-division not rounding down for negative numbers, we need another decrement. */ int row = (upper_left.x + upper_left.y) / (int)TILE_SIZE - 2; bool last_row = false; for (; !last_row; row++) { last_row = true; for (int column = left_column; column <= right_column; column++) { /* Valid row/column? */ if ((row + column) % 2 != 0) continue; Point tilecoord; tilecoord.x = (row - column) / 2; tilecoord.y = (row + column) / 2; assert(column == tilecoord.y - tilecoord.x); assert(row == tilecoord.y + tilecoord.x); TileType tile_type; TileInfo tile_info; _cur_ti = &tile_info; tile_info.x = tilecoord.x * TILE_SIZE; // FIXME tile_info should use signed integers tile_info.y = tilecoord.y * TILE_SIZE; if (IsInsideBS(tilecoord.x, 0, MapSizeX()) && IsInsideBS(tilecoord.y, 0, MapSizeY())) { /* This includes the south border at MapMaxX / MapMaxY. When terraforming we still draw tile selections there. */ tile_info.tile = TileXY(tilecoord.x, tilecoord.y); tile_type = GetTileType(tile_info.tile); } else { tile_info.tile = INVALID_TILE; tile_type = MP_VOID; } if (tile_type != MP_VOID) { /* We are inside the map => paint landscape. */ tile_info.tileh = GetTilePixelSlope(tile_info.tile, &tile_info.z); } else { /* We are outside the map => paint black. */ tile_info.tileh = GetTilePixelSlopeOutsideMap(tilecoord.x, tilecoord.y, &tile_info.z); } int viewport_y = GetViewportY(tilecoord); if (viewport_y + MAX_TILE_EXTENT_BOTTOM < _vd.dpi.top) { /* The tile in this column is not visible yet. * Tiles in other columns may be visible, but we need more rows in any case. */ last_row = false; continue; } int min_visible_height = viewport_y - (_vd.dpi.top + _vd.dpi.height); bool tile_visible = min_visible_height <= 0; if (tile_type != MP_VOID) { /* Is tile with buildings visible? */ if (min_visible_height < MAX_TILE_EXTENT_TOP) tile_visible = true; if (IsBridgeAbove(tile_info.tile)) { /* Is the bridge visible? */ TileIndex bridge_tile = GetNorthernBridgeEnd(tile_info.tile); int bridge_height = ZOOM_LVL_BASE * (GetBridgePixelHeight(bridge_tile) - TilePixelHeight(tile_info.tile)); if (min_visible_height < bridge_height + MAX_TILE_EXTENT_TOP) tile_visible = true; } /* Would a higher bridge on a more southern tile be visible? * If yes, we need to loop over more rows to possibly find one. */ if (min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false; } else { /* Outside of map. If we are on the north border of the map, there may still be a bridge visible, * so we need to loop over more rows to possibly find one. */ if ((tilecoord.x <= 0 || tilecoord.y <= 0) && min_visible_height < potential_bridge_height + MAX_TILE_EXTENT_TOP) last_row = false; } if (tile_visible) { last_row = false; _vd.foundation_part = FOUNDATION_PART_NONE; _vd.foundation[0] = -1; _vd.foundation[1] = -1; _vd.last_foundation_child[0] = NULL; _vd.last_foundation_child[1] = NULL; _tile_type_procs[tile_type]->draw_tile_proc(&tile_info); if (tile_info.tile != INVALID_TILE) DrawTileSelection(&tile_info); } } } } /** * Add a string to draw in the viewport * @param dpi current viewport area * @param small_from Zoomlevel from when the small font should be used * @param sign sign position and dimension * @param string_normal String for normal and 2x zoom level * @param string_small String for 4x and 8x zoom level * @param string_small_shadow Shadow string for 4x and 8x zoom level; or #STR_NULL if no shadow * @param colour colour of the sign background; or INVALID_COLOUR if transparent */ void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const ViewportSign *sign, StringID string_normal, StringID string_small, StringID string_small_shadow, uint64 params_1, uint64 params_2, Colours colour) { bool small = dpi->zoom >= small_from; int left = dpi->left; int top = dpi->top; int right = left + dpi->width; int bottom = top + dpi->height; int sign_height = ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM, dpi->zoom); int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom); if (bottom < sign->top || top > sign->top + sign_height || right < sign->center - sign_half_width || left > sign->center + sign_half_width) { return; } if (!small) { AddStringToDraw(sign->center - sign_half_width, sign->top, string_normal, params_1, params_2, colour, sign->width_normal); } else { int shadow_offset = 0; if (string_small_shadow != STR_NULL) { shadow_offset = 4; AddStringToDraw(sign->center - sign_half_width + shadow_offset, sign->top, string_small_shadow, params_1, params_2, INVALID_COLOUR, sign->width_small); } AddStringToDraw(sign->center - sign_half_width, sign->top - shadow_offset, string_small, params_1, params_2, colour, sign->width_small | 0x8000); } } static void ViewportAddTownNames(DrawPixelInfo *dpi) { if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES) || _game_mode == GM_MENU) return; const Town *t; FOR_ALL_TOWNS(t) { ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &t->cache.sign, _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_VIEWPORT_TOWN, STR_VIEWPORT_TOWN_TINY_WHITE, STR_VIEWPORT_TOWN_TINY_BLACK, t->index, t->cache.population); } } static void ViewportAddStationNames(DrawPixelInfo *dpi) { if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || _game_mode == GM_MENU) return; const BaseStation *st; FOR_ALL_BASE_STATIONS(st) { /* Check whether the base station is a station or a waypoint */ bool is_station = Station::IsExpected(st); /* Don't draw if the display options are disabled */ if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; /* Don't draw if station is owned by another company and competitor station names are hidden. Stations owned by none are never ignored. */ if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &st->sign, is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT, (is_station ? STR_VIEWPORT_STATION : STR_VIEWPORT_WAYPOINT) + 1, STR_NULL, st->index, st->facilities, (st->owner == OWNER_NONE || !st->IsInUse()) ? COLOUR_GREY : _company_colours[st->owner]); } } static void ViewportAddSigns(DrawPixelInfo *dpi) { /* Signs are turned off or are invisible */ if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS)) return; const Sign *si; FOR_ALL_SIGNS(si) { /* Don't draw if sign is owned by another company and competitor signs should be hidden. * Note: It is intentional that also signs owned by OWNER_NONE are hidden. Bankrupt * companies can leave OWNER_NONE signs after them. */ if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; ViewportAddString(dpi, ZOOM_LVL_OUT_16X, &si->sign, STR_WHITE_SIGN, (IsTransparencySet(TO_SIGNS) || si->owner == OWNER_DEITY) ? STR_VIEWPORT_SIGN_SMALL_WHITE : STR_VIEWPORT_SIGN_SMALL_BLACK, STR_NULL, si->index, 0, (si->owner == OWNER_NONE) ? COLOUR_GREY : (si->owner == OWNER_DEITY ? INVALID_COLOUR : _company_colours[si->owner])); } } /** * Update the position of the viewport sign. * @param center the (preferred) center of the viewport sign * @param top the new top of the sign * @param str the string to show in the sign * @param str_small the string to show when zoomed out. STR_NULL means same as \a str */ void ViewportSign::UpdatePosition(int center, int top, StringID str, StringID str_small) { if (this->width_normal != 0) this->MarkDirty(); this->top = top; char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); this->width_normal = VPSM_LEFT + Align(GetStringBoundingBox(buffer).width, 2) + VPSM_RIGHT; this->center = center; /* zoomed out version */ if (str_small != STR_NULL) { GetString(buffer, str_small, lastof(buffer)); } this->width_small = VPSM_LEFT + Align(GetStringBoundingBox(buffer, FS_SMALL).width, 2) + VPSM_RIGHT; this->MarkDirty(); } /** * Mark the sign dirty in all viewports. * @param maxzoom Maximum %ZoomLevel at which the text is visible. * * @ingroup dirty */ void ViewportSign::MarkDirty(ZoomLevel maxzoom) const { Rect zoomlevels[ZOOM_LVL_COUNT]; for (ZoomLevel zoom = ZOOM_LVL_BEGIN; zoom != ZOOM_LVL_END; zoom++) { /* FIXME: This doesn't switch to width_small when appropriate. */ zoomlevels[zoom].left = this->center - ScaleByZoom(this->width_normal / 2 + 1, zoom); zoomlevels[zoom].top = this->top - ScaleByZoom(1, zoom); zoomlevels[zoom].right = this->center + ScaleByZoom(this->width_normal / 2 + 1, zoom); zoomlevels[zoom].bottom = this->top + ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM + 1, zoom); } Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { ViewPort *vp = w->viewport; if (vp != NULL && vp->zoom <= maxzoom) { assert(vp->width != 0); Rect &zl = zoomlevels[vp->zoom]; MarkViewportDirty(vp, zl.left, zl.top, zl.right, zl.bottom); } } } static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv) { const TileSpriteToDraw *tsend = tstdv->End(); for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) { DrawSpriteViewport(ts->image, ts->pal, ts->x, ts->y, ts->sub); } } /** This fallback sprite checker always exists. */ static bool ViewportSortParentSpritesChecker() { return true; } /** Sort parent sprites pointer array */ static void ViewportSortParentSprites(ParentSpriteToSortVector *psdv) { ParentSpriteToDraw **psdvend = psdv->End(); ParentSpriteToDraw **psd = psdv->Begin(); while (psd != psdvend) { ParentSpriteToDraw *ps = *psd; if (ps->comparison_done) { psd++; continue; } ps->comparison_done = true; for (ParentSpriteToDraw **psd2 = psd + 1; psd2 != psdvend; psd2++) { ParentSpriteToDraw *ps2 = *psd2; if (ps2->comparison_done) continue; /* Decide which comparator to use, based on whether the bounding * boxes overlap */ if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X? ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y? ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z? /* Use X+Y+Z as the sorting order, so sprites closer to the bottom of * the screen and with higher Z elevation, are drawn in front. * Here X,Y,Z are the coordinates of the "center of mass" of the sprite, * i.e. X=(left+right)/2, etc. * However, since we only care about order, don't actually divide / 2 */ if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <= ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) { continue; } } else { /* We only change the order, if it is definite. * I.e. every single order of X, Y, Z says ps2 is behind ps or they overlap. * That is: If one partial order says ps behind ps2, do not change the order. */ if (ps->xmax < ps2->xmin || ps->ymax < ps2->ymin || ps->zmax < ps2->zmin) { continue; } } /* Move ps2 in front of ps */ ParentSpriteToDraw *temp = ps2; for (ParentSpriteToDraw **psd3 = psd2; psd3 > psd; psd3--) { *psd3 = *(psd3 - 1); } *psd = temp; } } } static void ViewportDrawParentSprites(const ParentSpriteToSortVector *psd, const ChildScreenSpriteToDrawVector *csstdv) { const ParentSpriteToDraw * const *psd_end = psd->End(); for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { const ParentSpriteToDraw *ps = *it; if (ps->image != SPR_EMPTY_BOUNDING_BOX) DrawSpriteViewport(ps->image, ps->pal, ps->x, ps->y, ps->sub); int child_idx = ps->first_child; while (child_idx >= 0) { const ChildScreenSpriteToDraw *cs = csstdv->Get(child_idx); child_idx = cs->next; DrawSpriteViewport(cs->image, cs->pal, ps->left + cs->x, ps->top + cs->y, cs->sub); } } } /** * Draws the bounding boxes of all ParentSprites * @param psd Array of ParentSprites */ static void ViewportDrawBoundingBoxes(const ParentSpriteToSortVector *psd) { const ParentSpriteToDraw * const *psd_end = psd->End(); for (const ParentSpriteToDraw * const *it = psd->Begin(); it != psd_end; it++) { const ParentSpriteToDraw *ps = *it; Point pt1 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmax + 1); // top front corner Point pt2 = RemapCoords(ps->xmin , ps->ymax + 1, ps->zmax + 1); // top left corner Point pt3 = RemapCoords(ps->xmax + 1, ps->ymin , ps->zmax + 1); // top right corner Point pt4 = RemapCoords(ps->xmax + 1, ps->ymax + 1, ps->zmin ); // bottom front corner DrawBox( pt1.x, pt1.y, pt2.x - pt1.x, pt2.y - pt1.y, pt3.x - pt1.x, pt3.y - pt1.y, pt4.x - pt1.x, pt4.y - pt1.y); } } /** * Draw/colour the blocks that have been redrawn. */ static void ViewportDrawDirtyBlocks() { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); const DrawPixelInfo *dpi = _cur_dpi; void *dst; int right = UnScaleByZoom(dpi->width, dpi->zoom); int bottom = UnScaleByZoom(dpi->height, dpi->zoom); int colour = _string_colourmap[_dirty_block_colour & 0xF]; dst = dpi->dst_ptr; byte bo = UnScaleByZoom(dpi->left + dpi->top, dpi->zoom) & 1; do { for (int i = (bo ^= 1); i < right; i += 2) blitter->SetPixel(dst, i, 0, (uint8)colour); dst = blitter->MoveTo(dst, 0, 1); } while (--bottom > 0); } static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *sstdv) { const StringSpriteToDraw *ssend = sstdv->End(); for (const StringSpriteToDraw *ss = sstdv->Begin(); ss != ssend; ++ss) { TextColour colour = TC_BLACK; bool small = HasBit(ss->width, 15); int w = GB(ss->width, 0, 15); int x = UnScaleByZoom(ss->x, zoom); int y = UnScaleByZoom(ss->y, zoom); int h = VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM; SetDParam(0, ss->params[0]); SetDParam(1, ss->params[1]); if (ss->colour != INVALID_COLOUR) { /* Do not draw signs nor station names if they are set invisible */ if (IsInvisibilitySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) continue; if (IsTransparencySet(TO_SIGNS) && ss->string != STR_WHITE_SIGN) { /* Don't draw the rectangle. * Real colours need the TC_IS_PALETTE_COLOUR flag. * Otherwise colours from _string_colourmap are assumed. */ colour = (TextColour)_colour_gradient[ss->colour][6] | TC_IS_PALETTE_COLOUR; } else { /* Draw the rectangle if 'transparent station signs' is off, * or if we are drawing a general text sign (STR_WHITE_SIGN). */ DrawFrameRect( x, y, x + w, y + h, ss->colour, IsTransparencySet(TO_SIGNS) ? FR_TRANSPARENT : FR_NONE ); } } DrawString(x + VPSM_LEFT, x + w - 1 - VPSM_RIGHT, y + VPSM_TOP, ss->string, colour, SA_HOR_CENTER); } } void ViewportDoDraw(const ViewPort *vp, int left, int top, int right, int bottom) { DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &_vd.dpi; _vd.dpi.zoom = vp->zoom; int mask = ScaleByZoom(-1, vp->zoom); _vd.combine_sprites = SPRITE_COMBINE_NONE; _vd.dpi.width = (right - left) & mask; _vd.dpi.height = (bottom - top) & mask; _vd.dpi.left = left & mask; _vd.dpi.top = top & mask; _vd.dpi.pitch = old_dpi->pitch; _vd.last_child = NULL; int x = UnScaleByZoom(_vd.dpi.left - (vp->virtual_left & mask), vp->zoom) + vp->left; int y = UnScaleByZoom(_vd.dpi.top - (vp->virtual_top & mask), vp->zoom) + vp->top; _vd.dpi.dst_ptr = BlitterFactory::GetCurrentBlitter()->MoveTo(old_dpi->dst_ptr, x - old_dpi->left, y - old_dpi->top); ViewportAddLandscape(); ViewportAddVehicles(&_vd.dpi); ViewportAddTownNames(&_vd.dpi); ViewportAddStationNames(&_vd.dpi); ViewportAddSigns(&_vd.dpi); DrawTextEffects(&_vd.dpi); if (_vd.tile_sprites_to_draw.Length() != 0) ViewportDrawTileSprites(&_vd.tile_sprites_to_draw); ParentSpriteToDraw *psd_end = _vd.parent_sprites_to_draw.End(); for (ParentSpriteToDraw *it = _vd.parent_sprites_to_draw.Begin(); it != psd_end; it++) { *_vd.parent_sprites_to_sort.Append() = it; } _vp_sprite_sorter(&_vd.parent_sprites_to_sort); ViewportDrawParentSprites(&_vd.parent_sprites_to_sort, &_vd.child_screen_sprites_to_draw); if (_draw_bounding_boxes) ViewportDrawBoundingBoxes(&_vd.parent_sprites_to_sort); if (_draw_dirty_blocks) ViewportDrawDirtyBlocks(); DrawPixelInfo dp = _vd.dpi; ZoomLevel zoom = _vd.dpi.zoom; dp.zoom = ZOOM_LVL_NORMAL; dp.width = UnScaleByZoom(dp.width, zoom); dp.height = UnScaleByZoom(dp.height, zoom); _cur_dpi = &dp; if (vp->overlay != NULL && vp->overlay->GetCargoMask() != 0 && vp->overlay->GetCompanyMask() != 0) { /* translate to window coordinates */ dp.left = x; dp.top = y; vp->overlay->Draw(&dp); } if (_vd.string_sprites_to_draw.Length() != 0) { /* translate to world coordinates */ dp.left = UnScaleByZoom(_vd.dpi.left, zoom); dp.top = UnScaleByZoom(_vd.dpi.top, zoom); ViewportDrawStrings(zoom, &_vd.string_sprites_to_draw); } _cur_dpi = old_dpi; _vd.string_sprites_to_draw.Clear(); _vd.tile_sprites_to_draw.Clear(); _vd.parent_sprites_to_draw.Clear(); _vd.parent_sprites_to_sort.Clear(); _vd.child_screen_sprites_to_draw.Clear(); } /** * Make sure we don't draw a too big area at a time. * If we do, the sprite memory will overflow. */ static void ViewportDrawChk(const ViewPort *vp, int left, int top, int right, int bottom) { if (ScaleByZoom(bottom - top, vp->zoom) * ScaleByZoom(right - left, vp->zoom) > 180000 * ZOOM_LVL_BASE * ZOOM_LVL_BASE) { if ((bottom - top) > (right - left)) { int t = (top + bottom) >> 1; ViewportDrawChk(vp, left, top, right, t); ViewportDrawChk(vp, left, t, right, bottom); } else { int t = (left + right) >> 1; ViewportDrawChk(vp, left, top, t, bottom); ViewportDrawChk(vp, t, top, right, bottom); } } else { ViewportDoDraw(vp, ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left, ScaleByZoom(top - vp->top, vp->zoom) + vp->virtual_top, ScaleByZoom(right - vp->left, vp->zoom) + vp->virtual_left, ScaleByZoom(bottom - vp->top, vp->zoom) + vp->virtual_top ); } } static inline void ViewportDraw(const ViewPort *vp, int left, int top, int right, int bottom) { if (right <= vp->left || bottom <= vp->top) return; if (left >= vp->left + vp->width) return; if (left < vp->left) left = vp->left; if (right > vp->left + vp->width) right = vp->left + vp->width; if (top >= vp->top + vp->height) return; if (top < vp->top) top = vp->top; if (bottom > vp->top + vp->height) bottom = vp->top + vp->height; ViewportDrawChk(vp, left, top, right, bottom); } /** * Draw the viewport of this window. */ void Window::DrawViewport() const { DrawPixelInfo *dpi = _cur_dpi; dpi->left += this->left; dpi->top += this->top; ViewportDraw(this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height); dpi->left -= this->left; dpi->top -= this->top; } /** * Continue criteria for the SearchMapEdge function. * @param iter Value to check. * @param iter_limit Maximum value for the iter * @param sy Screen y coordinate calculated for the tile at hand * @param sy_limit Limit to the screen y coordinate * @return True when we should continue searching. */ typedef bool ContinueMapEdgeSearch(int iter, int iter_limit, int sy, int sy_limit); /** Continue criteria for searching a no-longer-visible tile in negative direction, starting at some tile. */ static inline bool ContinueLowerMapEdgeSearch(int iter, int iter_limit, int sy, int sy_limit) { return iter > 0 && sy > sy_limit; } /** Continue criteria for searching a no-longer-visible tile in positive direction, starting at some tile. */ static inline bool ContinueUpperMapEdgeSearch(int iter, int iter_limit, int sy, int sy_limit) { return iter < iter_limit && sy < sy_limit; } /** * Searches, starting at the given tile, by applying the given offset to iter, for a no longer visible tile. * The whole sense of this function is keeping the to-be-written code small, thus it is a little bit abstracted * so the same function can be used for both the X and Y locations. As such a reference to one of the elements * in curr_tile was needed. * @param curr_tile A tile * @param iter Reference to either the X or Y of curr_tile. * @param iter_limit Upper search limit for the iter value. * @param offset Search in steps of this size * @param sy_limit Search limit to be passed to the criteria * @param continue_criteria Search as long as this criteria is true * @return The final value of iter. */ static int SearchMapEdge(Point &curr_tile, int &iter, int iter_limit, int offset, int sy_limit, ContinueMapEdgeSearch continue_criteria) { int sy; do { iter = Clamp(iter + offset, 0, iter_limit); sy = GetViewportY(curr_tile); } while (continue_criteria(iter, iter_limit, sy, sy_limit)); return iter; } /** * Determine the clamping of either the X or Y coordinate to the map. * @param curr_tile A tile * @param iter Reference to either the X or Y of curr_tile. * @param iter_limit Upper search limit for the iter value. * @param start Start value for the iteration. * @param other_ref Reference to the opposite axis in curr_tile than of iter. * @param other_value Start value for of the opposite axis * @param vp_value Value of the viewport location in the opposite axis as for iter. * @param other_limit Limit for the other value, so if iter is X, then other_limit is for Y. * @param vp_top Top of the viewport. * @param vp_bottom Bottom of the viewport. * @return Clamped version of vp_value. */ static inline int ClampXYToMap(Point &curr_tile, int &iter, int iter_limit, int start, int &other_ref, int other_value, int vp_value, int other_limit, int vp_top, int vp_bottom) { bool upper_edge = other_value < _settings_game.construction.max_heightlevel / 4; /* * First get an estimate of the tiles relevant for us at that edge. Relevant in the sense * "at least close to the visible area". Thus, we don't look at exactly each tile, inspecting * e.g. every tenth should be enough. After all, the desired screen limit is set such that * the bordermost tiles are painted in the middle of the screen when one hits the limit, * i.e. it is no harm if there is some small error in that calculation */ other_ref = upper_edge ? 0 : other_limit; iter = start; int min_iter = SearchMapEdge(curr_tile, iter, iter_limit, upper_edge ? -10 : +10, vp_top, upper_edge ? ContinueLowerMapEdgeSearch : ContinueUpperMapEdgeSearch); iter = start; int max_iter = SearchMapEdge(curr_tile, iter, iter_limit, upper_edge ? +10 : -10, vp_bottom, upper_edge ? ContinueUpperMapEdgeSearch : ContinueLowerMapEdgeSearch); max_iter = min(max_iter + _settings_game.construction.max_heightlevel / 4, iter_limit); min_iter = min(min_iter, max_iter); /* Now, calculate the highest heightlevel of these tiles. Again just as an estimate. */ int max_heightlevel_at_edge = 0; for (iter = min_iter; iter <= max_iter; iter += 10) { max_heightlevel_at_edge = max(max_heightlevel_at_edge, (int)TileHeight(TileXY(curr_tile.x, curr_tile.y))); } /* Based on that heightlevel, calculate the limit. For the upper edge a tile with height zero would * get a limit of zero, on the other side it depends on the number of tiles along the axis. */ return upper_edge ? max(vp_value, -max_heightlevel_at_edge * (int)(TILE_HEIGHT * 2 * ZOOM_LVL_BASE)) : min(vp_value, (other_limit * TILE_SIZE * 4 - max_heightlevel_at_edge * TILE_HEIGHT * 2) * ZOOM_LVL_BASE); } static inline void ClampViewportToMap(const ViewPort *vp, int &x, int &y) { int original_y = y; /* Centre of the viewport is hot spot */ x += vp->virtual_width / 2; y += vp->virtual_height / 2; /* Convert viewport coordinates to map coordinates * Calculation is scaled by 4 to avoid rounding errors */ int vx = -x + y * 2; int vy = x + y * 2; /* Find out which tile corresponds to (vx,vy) if one assumes height zero. The cast is necessary to prevent C++ from * converting the result to an uint, which gives an overflow instead of a negative result... */ int tx = vx / (int)(TILE_SIZE * 4 * ZOOM_LVL_BASE); int ty = vy / (int)(TILE_SIZE * 4 * ZOOM_LVL_BASE); Point curr_tile; vx = ClampXYToMap(curr_tile, curr_tile.y, MapMaxY(), ty, curr_tile.x, tx, vx, MapMaxX(), original_y, original_y + vp->virtual_height); vy = ClampXYToMap(curr_tile, curr_tile.x, MapMaxX(), tx, curr_tile.y, ty, vy, MapMaxY(), original_y, original_y + vp->virtual_height); /* Convert map coordinates to viewport coordinates */ x = (-vx + vy) / 2; y = ( vx + vy) / 4; /* Remove centering */ x -= vp->virtual_width / 2; y -= vp->virtual_height / 2; } /** * Update the viewport position being displayed. * @param w %Window owning the viewport. */ void UpdateViewportPosition(Window *w) { const ViewPort *vp = w->viewport; if (w->viewport->follow_vehicle != INVALID_VEHICLE) { const Vehicle *veh = Vehicle::Get(w->viewport->follow_vehicle); Point pt = MapXYZToViewport(vp, veh->x_pos, veh->y_pos, veh->z_pos); w->viewport->scrollpos_x = pt.x; w->viewport->scrollpos_y = pt.y; SetViewportPosition(w, pt.x, pt.y); } else { /* Ensure the destination location is within the map */ ClampViewportToMap(vp, w->viewport->dest_scrollpos_x, w->viewport->dest_scrollpos_y); int delta_x = w->viewport->dest_scrollpos_x - w->viewport->scrollpos_x; int delta_y = w->viewport->dest_scrollpos_y - w->viewport->scrollpos_y; bool update_overlay = false; if (delta_x != 0 || delta_y != 0) { if (_settings_client.gui.smooth_scroll) { int max_scroll = ScaleByMapSize1D(512 * ZOOM_LVL_BASE); /* Not at our desired position yet... */ w->viewport->scrollpos_x += Clamp(delta_x / 4, -max_scroll, max_scroll); w->viewport->scrollpos_y += Clamp(delta_y / 4, -max_scroll, max_scroll); } else { w->viewport->scrollpos_x = w->viewport->dest_scrollpos_x; w->viewport->scrollpos_y = w->viewport->dest_scrollpos_y; } update_overlay = (w->viewport->scrollpos_x == w->viewport->dest_scrollpos_x && w->viewport->scrollpos_y == w->viewport->dest_scrollpos_y); } ClampViewportToMap(vp, w->viewport->scrollpos_x, w->viewport->scrollpos_y); SetViewportPosition(w, w->viewport->scrollpos_x, w->viewport->scrollpos_y); if (update_overlay) RebuildViewportOverlay(w); } } /** * Marks a viewport as dirty for repaint if it displays (a part of) the area the needs to be repainted. * @param vp The viewport to mark as dirty * @param left Left edge of area to repaint * @param top Top edge of area to repaint * @param right Right edge of area to repaint * @param bottom Bottom edge of area to repaint * @ingroup dirty */ static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom) { /* Rounding wrt. zoom-out level */ right += (1 << vp->zoom) - 1; bottom += (1 << vp->zoom) - 1; right -= vp->virtual_left; if (right <= 0) return; bottom -= vp->virtual_top; if (bottom <= 0) return; left = max(0, left - vp->virtual_left); if (left >= vp->virtual_width) return; top = max(0, top - vp->virtual_top); if (top >= vp->virtual_height) return; SetDirtyBlocks( UnScaleByZoomLower(left, vp->zoom) + vp->left, UnScaleByZoomLower(top, vp->zoom) + vp->top, UnScaleByZoom(right, vp->zoom) + vp->left + 1, UnScaleByZoom(bottom, vp->zoom) + vp->top + 1 ); } /** * Mark all viewports that display an area as dirty (in need of repaint). * @param left Left edge of area to repaint. (viewport coordinates, that is wrt. #ZOOM_LVL_NORMAL) * @param top Top edge of area to repaint. (viewport coordinates, that is wrt. #ZOOM_LVL_NORMAL) * @param right Right edge of area to repaint. (viewport coordinates, that is wrt. #ZOOM_LVL_NORMAL) * @param bottom Bottom edge of area to repaint. (viewport coordinates, that is wrt. #ZOOM_LVL_NORMAL) * @ingroup dirty */ void MarkAllViewportsDirty(int left, int top, int right, int bottom) { Window *w; FOR_ALL_WINDOWS_FROM_BACK(w) { ViewPort *vp = w->viewport; if (vp != NULL) { assert(vp->width != 0); MarkViewportDirty(vp, left, top, right, bottom); } } } void ConstrainAllViewportsZoom() { Window *w; FOR_ALL_WINDOWS_FROM_FRONT(w) { if (w->viewport == NULL) continue; ZoomLevel zoom = static_cast(Clamp(w->viewport->zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); if (zoom != w->viewport->zoom) { while (w->viewport->zoom < zoom) DoZoomInOutWindow(ZOOM_OUT, w); while (w->viewport->zoom > zoom) DoZoomInOutWindow(ZOOM_IN, w); } } } /** * Mark a tile given by its index dirty for repaint. * @param tile The tile to mark dirty. * @param bridge_level_offset Height of bridge on tile to also mark dirty. (Height level relative to north corner.) * @ingroup dirty */ void MarkTileDirtyByTile(TileIndex tile, int bridge_level_offset) { Point pt = RemapCoords(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, TilePixelHeight(tile)); MarkAllViewportsDirty( pt.x - MAX_TILE_EXTENT_LEFT, pt.y - MAX_TILE_EXTENT_TOP - ZOOM_LVL_BASE * TILE_HEIGHT * bridge_level_offset, pt.x + MAX_TILE_EXTENT_RIGHT, pt.y + MAX_TILE_EXTENT_BOTTOM); } /** * Mark a (virtual) tile outside the map dirty for repaint. * @param x Tile X position. * @param y Tile Y position. * @ingroup dirty */ void MarkTileDirtyByTileOutsideMap(int x, int y) { Point pt = RemapCoords(x * TILE_SIZE, y * TILE_SIZE, TilePixelHeightOutsideMap(x, y)); MarkAllViewportsDirty( pt.x - MAX_TILE_EXTENT_LEFT, pt.y, // no buildings outside of map pt.x + MAX_TILE_EXTENT_RIGHT, pt.y + MAX_TILE_EXTENT_BOTTOM); } /** * Marks the selected tiles as dirty. * * This function marks the selected tiles as dirty for repaint * * @ingroup dirty */ static void SetSelectionTilesDirty() { int x_size = _thd.size.x; int y_size = _thd.size.y; if (!_thd.diagonal) { // Selecting in a straight rectangle (or a single square) int x_start = _thd.pos.x; int y_start = _thd.pos.y; if (_thd.outersize.x != 0) { x_size += _thd.outersize.x; x_start += _thd.offs.x; y_size += _thd.outersize.y; y_start += _thd.offs.y; } x_size -= TILE_SIZE; y_size -= TILE_SIZE; assert(x_size >= 0); assert(y_size >= 0); int x_end = Clamp(x_start + x_size, 0, MapSizeX() * TILE_SIZE - TILE_SIZE); int y_end = Clamp(y_start + y_size, 0, MapSizeY() * TILE_SIZE - TILE_SIZE); x_start = Clamp(x_start, 0, MapSizeX() * TILE_SIZE - TILE_SIZE); y_start = Clamp(y_start, 0, MapSizeY() * TILE_SIZE - TILE_SIZE); /* make sure everything is multiple of TILE_SIZE */ assert((x_end | y_end | x_start | y_start) % TILE_SIZE == 0); /* How it works: * Suppose we have to mark dirty rectangle of 3x4 tiles: * x * xxx * xxxxx * xxxxx * xxx * x * This algorithm marks dirty columns of tiles, so it is done in 3+4-1 steps: * 1) x 2) x * xxx Oxx * Oxxxx xOxxx * xxxxx Oxxxx * xxx xxx * x x * And so forth... */ int top_x = x_end; // coordinates of top dirty tile int top_y = y_start; int bot_x = top_x; // coordinates of bottom dirty tile int bot_y = top_y; do { /* topmost dirty point */ TileIndex top_tile = TileVirtXY(top_x, top_y); Point top = RemapCoords(top_x, top_y, GetTileMaxPixelZ(top_tile)); /* bottommost point */ TileIndex bottom_tile = TileVirtXY(bot_x, bot_y); Point bot = RemapCoords(bot_x + TILE_SIZE, bot_y + TILE_SIZE, GetTilePixelZ(bottom_tile)); // bottommost point /* the 'x' coordinate of 'top' and 'bot' is the same (and always in the same distance from tile middle), * tile height/slope affects only the 'y' on-screen coordinate! */ int l = top.x - TILE_PIXELS * ZOOM_LVL_BASE; // 'x' coordinate of left side of the dirty rectangle int t = top.y; // 'y' coordinate of top side of the dirty rectangle int r = top.x + TILE_PIXELS * ZOOM_LVL_BASE; // 'x' coordinate of right side of the dirty rectangle int b = bot.y; // 'y' coordinate of bottom side of the dirty rectangle static const int OVERLAY_WIDTH = 4 * ZOOM_LVL_BASE; // part of selection sprites is drawn outside the selected area (in particular: terraforming) /* For halftile foundations on SLOPE_STEEP_S the sprite extents some more towards the top */ MarkAllViewportsDirty(l - OVERLAY_WIDTH, t - OVERLAY_WIDTH - TILE_HEIGHT * ZOOM_LVL_BASE, r + OVERLAY_WIDTH, b + OVERLAY_WIDTH); /* haven't we reached the topmost tile yet? */ if (top_x != x_start) { top_x -= TILE_SIZE; } else { top_y += TILE_SIZE; } /* the way the bottom tile changes is different when we reach the bottommost tile */ if (bot_y != y_end) { bot_y += TILE_SIZE; } else { bot_x -= TILE_SIZE; } } while (bot_x >= top_x); } else { // Selecting in a 45 degrees rotated (diagonal) rectangle. /* a_size, b_size describe a rectangle with rotated coordinates */ int a_size = x_size + y_size, b_size = x_size - y_size; int interval_a = a_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE; int interval_b = b_size < 0 ? -(int)TILE_SIZE : (int)TILE_SIZE; for (int a = -interval_a; a != a_size + interval_a; a += interval_a) { for (int b = -interval_b; b != b_size + interval_b; b += interval_b) { uint x = (_thd.pos.x + (a + b) / 2) / TILE_SIZE; uint y = (_thd.pos.y + (a - b) / 2) / TILE_SIZE; if (x < MapMaxX() && y < MapMaxY()) { MarkTileDirtyByTile(TileXY(x, y)); } } } } } void SetSelectionRed(bool b) { _thd.make_square_red = b; SetSelectionTilesDirty(); } /** * Test whether a sign is below the mouse * @param vp the clicked viewport * @param x X position of click * @param y Y position of click * @param sign the sign to check * @return true if the sign was hit */ static bool CheckClickOnViewportSign(const ViewPort *vp, int x, int y, const ViewportSign *sign) { bool small = (vp->zoom >= ZOOM_LVL_OUT_16X); int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom); int sign_height = ScaleByZoom(VPSM_TOP + (small ? FONT_HEIGHT_SMALL : FONT_HEIGHT_NORMAL) + VPSM_BOTTOM, vp->zoom); x = ScaleByZoom(x - vp->left, vp->zoom) + vp->virtual_left; y = ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top; return y >= sign->top && y < sign->top + sign_height && x >= sign->center - sign_half_width && x < sign->center + sign_half_width; } static bool CheckClickOnTown(const ViewPort *vp, int x, int y) { if (!HasBit(_display_opt, DO_SHOW_TOWN_NAMES)) return false; const Town *t; FOR_ALL_TOWNS(t) { if (CheckClickOnViewportSign(vp, x, y, &t->cache.sign)) { ShowTownViewWindow(t->index); return true; } } return false; } static bool CheckClickOnStation(const ViewPort *vp, int x, int y) { if (!(HasBit(_display_opt, DO_SHOW_STATION_NAMES) || HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)) || IsInvisibilitySet(TO_SIGNS)) return false; const BaseStation *st; FOR_ALL_BASE_STATIONS(st) { /* Check whether the base station is a station or a waypoint */ bool is_station = Station::IsExpected(st); /* Don't check if the display options are disabled */ if (!HasBit(_display_opt, is_station ? DO_SHOW_STATION_NAMES : DO_SHOW_WAYPOINT_NAMES)) continue; /* Don't check if competitor signs are not shown and the sign isn't owned by the local company */ if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != st->owner && st->owner != OWNER_NONE) continue; if (CheckClickOnViewportSign(vp, x, y, &st->sign)) { if (is_station) { ShowStationViewWindow(st->index); } else { ShowWaypointWindow(Waypoint::From(st)); } return true; } } return false; } static bool CheckClickOnSign(const ViewPort *vp, int x, int y) { /* Signs are turned off, or they are transparent and invisibility is ON, or company is a spectator */ if (!HasBit(_display_opt, DO_SHOW_SIGNS) || IsInvisibilitySet(TO_SIGNS) || _local_company == COMPANY_SPECTATOR) return false; const Sign *si; FOR_ALL_SIGNS(si) { /* If competitor signs are hidden, don't check signs that aren't owned by local company */ if (!HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS) && _local_company != si->owner && si->owner != OWNER_DEITY) continue; if (si->owner == OWNER_DEITY && _game_mode != GM_EDITOR) continue; if (CheckClickOnViewportSign(vp, x, y, &si->sign)) { HandleClickOnSign(si); return true; } } return false; } static bool CheckClickOnLandscape(const ViewPort *vp, int x, int y) { Point pt = TranslateXYToTileCoord(vp, x, y); if (pt.x != -1) return ClickTile(TileVirtXY(pt.x, pt.y)); return true; } static void PlaceObject() { Point pt; Window *w; pt = GetTileBelowCursor(); if (pt.x == -1) return; if ((_thd.place_mode & HT_DRAG_MASK) == HT_POINT) { pt.x += TILE_SIZE / 2; pt.y += TILE_SIZE / 2; } _tile_fract_coords.x = pt.x & TILE_UNIT_MASK; _tile_fract_coords.y = pt.y & TILE_UNIT_MASK; w = _thd.GetCallbackWnd(); if (w != NULL) w->OnPlaceObject(pt, TileVirtXY(pt.x, pt.y)); } bool HandleViewportClicked(const ViewPort *vp, int x, int y) { const Vehicle *v = CheckClickOnVehicle(vp, x, y); if (_thd.place_mode & HT_VEHICLE) { if (v != NULL && VehicleClicked(v)) return true; } /* Vehicle placement mode already handled above. */ if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { PlaceObject(); return true; } if (CheckClickOnTown(vp, x, y)) return true; if (CheckClickOnStation(vp, x, y)) return true; if (CheckClickOnSign(vp, x, y)) return true; bool result = CheckClickOnLandscape(vp, x, y); if (v != NULL) { DEBUG(misc, 2, "Vehicle %d (index %d) at %p", v->unitnumber, v->index, v); if (IsCompanyBuildableVehicleType(v)) { v = v->First(); if (_ctrl_pressed && v->owner == _local_company) { StartStopVehicle(v, true); } else { ShowVehicleViewWindow(v); } } return true; } return result; } void RebuildViewportOverlay(Window *w) { if (w->viewport->overlay != NULL && w->viewport->overlay->GetCompanyMask() != 0 && w->viewport->overlay->GetCargoMask() != 0) { w->viewport->overlay->RebuildCache(); w->SetDirty(); } } /** * Scrolls the viewport in a window to a given location. * @param x Desired x location of the map to scroll to (world coordinate). * @param y Desired y location of the map to scroll to (world coordinate). * @param z Desired z location of the map to scroll to (world coordinate). Use \c -1 to scroll to the height of the map at the \a x, \a y location. * @param w %Window containing the viewport. * @param instant Jump to the location instead of slowly moving to it. * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). */ bool ScrollWindowTo(int x, int y, int z, Window *w, bool instant) { /* The slope cannot be acquired outside of the map, so make sure we are always within the map. */ if (z == -1) { if ( x >= 0 && x <= (int)MapSizeX() * (int)TILE_SIZE - 1 && y >= 0 && y <= (int)MapSizeY() * (int)TILE_SIZE - 1) { z = GetSlopePixelZ(x, y); } else { z = TileHeightOutsideMap(x / (int)TILE_SIZE, y / (int)TILE_SIZE); } } Point pt = MapXYZToViewport(w->viewport, x, y, z); w->viewport->follow_vehicle = INVALID_VEHICLE; if (w->viewport->dest_scrollpos_x == pt.x && w->viewport->dest_scrollpos_y == pt.y) return false; if (instant) { w->viewport->scrollpos_x = pt.x; w->viewport->scrollpos_y = pt.y; RebuildViewportOverlay(w); } w->viewport->dest_scrollpos_x = pt.x; w->viewport->dest_scrollpos_y = pt.y; return true; } /** * Scrolls the viewport in a window to a given location. * @param tile Desired tile to center on. * @param w %Window containing the viewport. * @param instant Jump to the location instead of slowly moving to it. * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). */ bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant) { return ScrollWindowTo(TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE, -1, w, instant); } /** * Scrolls the viewport of the main window to a given location. * @param tile Desired tile to center on. * @param instant Jump to the location instead of slowly moving to it. * @return Destination of the viewport was changed (to activate other actions when the viewport is already at the desired position). */ bool ScrollMainWindowToTile(TileIndex tile, bool instant) { return ScrollMainWindowTo(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, -1, instant); } /** * Set a tile to display a red error square. * @param tile Tile that should show the red error square. */ void SetRedErrorSquare(TileIndex tile) { TileIndex old; old = _thd.redsq; _thd.redsq = tile; if (tile != old) { if (tile != INVALID_TILE) MarkTileDirtyByTile(tile); if (old != INVALID_TILE) MarkTileDirtyByTile(old); } } /** * Highlight \a w by \a h tiles at the cursor. * @param w Width of the highlighted tiles rectangle. * @param h Height of the highlighted tiles rectangle. */ void SetTileSelectSize(int w, int h) { _thd.new_size.x = w * TILE_SIZE; _thd.new_size.y = h * TILE_SIZE; _thd.new_outersize.x = 0; _thd.new_outersize.y = 0; } void SetTileSelectBigSize(int ox, int oy, int sx, int sy) { _thd.offs.x = ox * TILE_SIZE; _thd.offs.y = oy * TILE_SIZE; _thd.new_outersize.x = sx * TILE_SIZE; _thd.new_outersize.y = sy * TILE_SIZE; } /** returns the best autorail highlight type from map coordinates */ static HighLightStyle GetAutorailHT(int x, int y) { return HT_RAIL | _autorail_piece[x & TILE_UNIT_MASK][y & TILE_UNIT_MASK]; } /** * Reset tile highlighting. */ void TileHighlightData::Reset() { this->pos.x = 0; this->pos.y = 0; this->new_pos.x = 0; this->new_pos.y = 0; } /** * Is the user dragging a 'diagonal rectangle'? * @return User is dragging a rotated rectangle. */ bool TileHighlightData::IsDraggingDiagonal() { return (this->place_mode & HT_DIAGONAL) != 0 && _ctrl_pressed && _left_button_down; } /** * Get the window that started the current highlighting. * @return The window that requested the current tile highlighting, or \c NULL if not available. */ Window *TileHighlightData::GetCallbackWnd() { return FindWindowById(this->window_class, this->window_number); } /** * Updates tile highlighting for all cases. * Uses _thd.selstart and _thd.selend and _thd.place_mode (set elsewhere) to determine _thd.pos and _thd.size * Also drawstyle is determined. Uses _thd.new.* as a buffer and calls SetSelectionTilesDirty() twice, * Once for the old and once for the new selection. * _thd is TileHighlightData, found in viewport.h */ void UpdateTileSelection() { int x1; int y1; HighLightStyle new_drawstyle = HT_NONE; bool new_diagonal = false; if ((_thd.place_mode & HT_DRAG_MASK) == HT_SPECIAL) { x1 = _thd.selend.x; y1 = _thd.selend.y; if (x1 != -1) { int x2 = _thd.selstart.x & ~TILE_UNIT_MASK; int y2 = _thd.selstart.y & ~TILE_UNIT_MASK; x1 &= ~TILE_UNIT_MASK; y1 &= ~TILE_UNIT_MASK; if (_thd.IsDraggingDiagonal()) { new_diagonal = true; } else { if (x1 >= x2) Swap(x1, x2); if (y1 >= y2) Swap(y1, y2); } _thd.new_pos.x = x1; _thd.new_pos.y = y1; _thd.new_size.x = x2 - x1; _thd.new_size.y = y2 - y1; if (!new_diagonal) { _thd.new_size.x += TILE_SIZE; _thd.new_size.y += TILE_SIZE; } new_drawstyle = _thd.next_drawstyle; } } else if ((_thd.place_mode & HT_DRAG_MASK) != HT_NONE) { Point pt = GetTileBelowCursor(); x1 = pt.x; y1 = pt.y; if (x1 != -1) { switch (_thd.place_mode & HT_DRAG_MASK) { case HT_RECT: new_drawstyle = HT_RECT; break; case HT_POINT: new_drawstyle = HT_POINT; x1 += TILE_SIZE / 2; y1 += TILE_SIZE / 2; break; case HT_RAIL: /* Draw one highlighted tile in any direction */ new_drawstyle = GetAutorailHT(pt.x, pt.y); break; case HT_LINE: switch (_thd.place_mode & HT_DIR_MASK) { case HT_DIR_X: new_drawstyle = HT_LINE | HT_DIR_X; break; case HT_DIR_Y: new_drawstyle = HT_LINE | HT_DIR_Y; break; case HT_DIR_HU: case HT_DIR_HL: new_drawstyle = (pt.x & TILE_UNIT_MASK) + (pt.y & TILE_UNIT_MASK) <= TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; break; case HT_DIR_VL: case HT_DIR_VR: new_drawstyle = (pt.x & TILE_UNIT_MASK) > (pt.y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; break; default: NOT_REACHED(); } _thd.selstart.x = x1 & ~TILE_UNIT_MASK; _thd.selstart.y = y1 & ~TILE_UNIT_MASK; break; default: NOT_REACHED(); break; } _thd.new_pos.x = x1 & ~TILE_UNIT_MASK; _thd.new_pos.y = y1 & ~TILE_UNIT_MASK; } } /* redraw selection */ if (_thd.drawstyle != new_drawstyle || _thd.pos.x != _thd.new_pos.x || _thd.pos.y != _thd.new_pos.y || _thd.size.x != _thd.new_size.x || _thd.size.y != _thd.new_size.y || _thd.outersize.x != _thd.new_outersize.x || _thd.outersize.y != _thd.new_outersize.y || _thd.diagonal != new_diagonal) { /* Clear the old tile selection? */ if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); _thd.drawstyle = new_drawstyle; _thd.pos = _thd.new_pos; _thd.size = _thd.new_size; _thd.outersize = _thd.new_outersize; _thd.diagonal = new_diagonal; _thd.dirty = 0xff; /* Draw the new tile selection? */ if ((new_drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); } } /** * Displays the measurement tooltips when selecting multiple tiles * @param str String to be displayed * @param paramcount number of params to deal with * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip * @param close_cond Condition for closing this tooltip. */ static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond = TCC_LEFT_CLICK) { if (!_settings_client.gui.measure_tooltip) return; GuiShowTooltips(_thd.GetCallbackWnd(), str, paramcount, params, close_cond); } /** highlighting tiles while only going over them with the mouse */ void VpStartPlaceSizing(TileIndex tile, ViewportPlaceMethod method, ViewportDragDropSelectionProcess process) { _thd.select_method = method; _thd.select_proc = process; _thd.selend.x = TileX(tile) * TILE_SIZE; _thd.selstart.x = TileX(tile) * TILE_SIZE; _thd.selend.y = TileY(tile) * TILE_SIZE; _thd.selstart.y = TileY(tile) * TILE_SIZE; /* Needed so several things (road, autoroad, bridges, ...) are placed correctly. * In effect, placement starts from the centre of a tile */ if (method == VPM_X_OR_Y || method == VPM_FIX_X || method == VPM_FIX_Y) { _thd.selend.x += TILE_SIZE / 2; _thd.selend.y += TILE_SIZE / 2; _thd.selstart.x += TILE_SIZE / 2; _thd.selstart.y += TILE_SIZE / 2; } HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); if ((_thd.place_mode & HT_DRAG_MASK) == HT_RECT) { _thd.place_mode = HT_SPECIAL | others; _thd.next_drawstyle = HT_RECT | others; } else if (_thd.place_mode & (HT_RAIL | HT_LINE)) { _thd.place_mode = HT_SPECIAL | others; _thd.next_drawstyle = _thd.drawstyle | others; } else { _thd.place_mode = HT_SPECIAL | others; _thd.next_drawstyle = HT_POINT | others; } _special_mouse_mode = WSM_SIZING; } void VpSetPlaceSizingLimit(int limit) { _thd.sizelimit = limit; } /** * Highlights all tiles between a set of two tiles. Used in dock and tunnel placement * @param from TileIndex of the first tile to highlight * @param to TileIndex of the last tile to highlight */ void VpSetPresizeRange(TileIndex from, TileIndex to) { uint64 distance = DistanceManhattan(from, to) + 1; _thd.selend.x = TileX(to) * TILE_SIZE; _thd.selend.y = TileY(to) * TILE_SIZE; _thd.selstart.x = TileX(from) * TILE_SIZE; _thd.selstart.y = TileY(from) * TILE_SIZE; _thd.next_drawstyle = HT_RECT; /* show measurement only if there is any length to speak of */ if (distance > 1) ShowMeasurementTooltips(STR_MEASURE_LENGTH, 1, &distance, TCC_HOVER); } static void VpStartPreSizing() { _thd.selend.x = -1; _special_mouse_mode = WSM_PRESIZE; } /** * returns information about the 2x1 piece to be build. * The lower bits (0-3) are the track type. */ static HighLightStyle Check2x1AutoRail(int mode) { int fxpy = _tile_fract_coords.x + _tile_fract_coords.y; int sxpy = (_thd.selend.x & TILE_UNIT_MASK) + (_thd.selend.y & TILE_UNIT_MASK); int fxmy = _tile_fract_coords.x - _tile_fract_coords.y; int sxmy = (_thd.selend.x & TILE_UNIT_MASK) - (_thd.selend.y & TILE_UNIT_MASK); switch (mode) { default: NOT_REACHED(); case 0: // end piece is lower right if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL; if (fxmy < -3 && sxmy > 3) return HT_DIR_VR; return HT_DIR_Y; case 1: if (fxmy > 3 && sxmy < -3) return HT_DIR_VL; if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU; return HT_DIR_Y; case 2: if (fxmy > 3 && sxmy < -3) return HT_DIR_VL; if (fxpy >= 20 && sxpy <= 12) return HT_DIR_HL; return HT_DIR_X; case 3: if (fxmy < -3 && sxmy > 3) return HT_DIR_VR; if (fxpy <= 12 && sxpy >= 20) return HT_DIR_HU; return HT_DIR_X; } } /** * Check if the direction of start and end tile should be swapped based on * the dragging-style. Default directions are: * in the case of a line (HT_RAIL, HT_LINE): DIR_NE, DIR_NW, DIR_N, DIR_E * in the case of a rect (HT_RECT, HT_POINT): DIR_S, DIR_E * For example dragging a rectangle area from south to north should be swapped to * north-south (DIR_S) to obtain the same results with less code. This is what * the return value signifies. * @param style HighLightStyle dragging style * @param start_tile start tile of drag * @param end_tile end tile of drag * @return boolean value which when true means start/end should be swapped */ static bool SwapDirection(HighLightStyle style, TileIndex start_tile, TileIndex end_tile) { uint start_x = TileX(start_tile); uint start_y = TileY(start_tile); uint end_x = TileX(end_tile); uint end_y = TileY(end_tile); switch (style & HT_DRAG_MASK) { case HT_RAIL: case HT_LINE: return (end_x > start_x || (end_x == start_x && end_y > start_y)); case HT_RECT: case HT_POINT: return (end_x != start_x && end_y < start_y); default: NOT_REACHED(); } return false; } /** * Calculates height difference between one tile and another. * Multiplies the result to suit the standard given by #TILE_HEIGHT_STEP. * * To correctly get the height difference we need the direction we are dragging * in, as well as with what kind of tool we are dragging. For example a horizontal * autorail tool that starts in bottom and ends at the top of a tile will need the * maximum of SW, S and SE, N corners respectively. This is handled by the lookup table below * See #_tileoffs_by_dir in map.cpp for the direction enums if you can't figure out the values yourself. * @param style Highlighting style of the drag. This includes direction and style (autorail, rect, etc.) * @param distance Number of tiles dragged, important for horizontal/vertical drags, ignored for others. * @param start_tile Start tile of the drag operation. * @param end_tile End tile of the drag operation. * @return Height difference between two tiles. The tile measurement tool utilizes this value in its tooltip. */ static int CalcHeightdiff(HighLightStyle style, uint distance, TileIndex start_tile, TileIndex end_tile) { bool swap = SwapDirection(style, start_tile, end_tile); uint h0, h1; // Start height and end height. if (start_tile == end_tile) return 0; if (swap) Swap(start_tile, end_tile); switch (style & HT_DRAG_MASK) { case HT_RECT: { static const TileIndexDiffC heightdiff_area_by_dir[] = { /* Start */ {1, 0}, /* Dragging east */ {0, 0}, // Dragging south /* End */ {0, 1}, /* Dragging east */ {1, 1} // Dragging south }; /* In the case of an area we can determine whether we were dragging south or * east by checking the X-coordinates of the tiles */ byte style_t = (byte)(TileX(end_tile) > TileX(start_tile)); start_tile = TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_area_by_dir[style_t])); end_tile = TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_area_by_dir[2 + style_t])); /* FALL THROUGH */ } case HT_POINT: h0 = TileHeight(start_tile); h1 = TileHeight(end_tile); break; default: { // All other types, this is mostly only line/autorail static const HighLightStyle flip_style_direction[] = { HT_DIR_X, HT_DIR_Y, HT_DIR_HL, HT_DIR_HU, HT_DIR_VR, HT_DIR_VL }; static const TileIndexDiffC heightdiff_line_by_dir[] = { /* Start */ {1, 0}, {1, 1}, /* HT_DIR_X */ {0, 1}, {1, 1}, // HT_DIR_Y /* Start */ {1, 0}, {0, 0}, /* HT_DIR_HU */ {1, 0}, {1, 1}, // HT_DIR_HL /* Start */ {1, 0}, {1, 1}, /* HT_DIR_VL */ {0, 1}, {1, 1}, // HT_DIR_VR /* Start */ {0, 1}, {0, 0}, /* HT_DIR_X */ {1, 0}, {0, 0}, // HT_DIR_Y /* End */ {0, 1}, {0, 0}, /* HT_DIR_HU */ {1, 1}, {0, 1}, // HT_DIR_HL /* End */ {1, 0}, {0, 0}, /* HT_DIR_VL */ {0, 0}, {0, 1}, // HT_DIR_VR }; distance %= 2; // we're only interested if the distance is even or uneven style &= HT_DIR_MASK; /* To handle autorail, we do some magic to be able to use a lookup table. * Firstly if we drag the other way around, we switch start&end, and if needed * also flip the drag-position. Eg if it was on the left, and the distance is even * that means the end, which is now the start is on the right */ if (swap && distance == 0) style = flip_style_direction[style]; /* Use lookup table for start-tile based on HighLightStyle direction */ byte style_t = style * 2; assert(style_t < lengthof(heightdiff_line_by_dir) - 13); h0 = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t]))); uint ht = TileHeight(TILE_ADD(start_tile, ToTileIndexDiff(heightdiff_line_by_dir[style_t + 1]))); h0 = max(h0, ht); /* Use lookup table for end-tile based on HighLightStyle direction * flip around side (lower/upper, left/right) based on distance */ if (distance == 0) style_t = flip_style_direction[style] * 2; assert(style_t < lengthof(heightdiff_line_by_dir) - 13); h1 = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t]))); ht = TileHeight(TILE_ADD(end_tile, ToTileIndexDiff(heightdiff_line_by_dir[12 + style_t + 1]))); h1 = max(h1, ht); break; } } if (swap) Swap(h0, h1); return (int)(h1 - h0) * TILE_HEIGHT_STEP; } static const StringID measure_strings_length[] = {STR_NULL, STR_MEASURE_LENGTH, STR_MEASURE_LENGTH_HEIGHTDIFF}; /** * Check for underflowing the map. * @param test the variable to test for underflowing * @param other the other variable to update to keep the line * @param mult the constant to multiply the difference by for \c other */ static void CheckUnderflow(int &test, int &other, int mult) { if (test >= 0) return; other += mult * test; test = 0; } /** * Check for overflowing the map. * @param test the variable to test for overflowing * @param other the other variable to update to keep the line * @param max the maximum value for the \c test variable * @param mult the constant to multiply the difference by for \c other */ static void CheckOverflow(int &test, int &other, int max, int mult) { if (test <= max) return; other += mult * (test - max); test = max; } /** while dragging */ static void CalcRaildirsDrawstyle(int x, int y, int method) { HighLightStyle b; int dx = _thd.selstart.x - (_thd.selend.x & ~TILE_UNIT_MASK); int dy = _thd.selstart.y - (_thd.selend.y & ~TILE_UNIT_MASK); uint w = abs(dx) + TILE_SIZE; uint h = abs(dy) + TILE_SIZE; if (method & ~(VPM_RAILDIRS | VPM_SIGNALDIRS)) { /* We 'force' a selection direction; first four rail buttons. */ method &= ~(VPM_RAILDIRS | VPM_SIGNALDIRS); int raw_dx = _thd.selstart.x - _thd.selend.x; int raw_dy = _thd.selstart.y - _thd.selend.y; switch (method) { case VPM_FIX_X: b = HT_LINE | HT_DIR_Y; x = _thd.selstart.x; break; case VPM_FIX_Y: b = HT_LINE | HT_DIR_X; y = _thd.selstart.y; break; case VPM_FIX_HORIZONTAL: if (dx == -dy) { /* We are on a straight horizontal line. Determine the 'rail' * to build based the sub tile location. */ b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; } else { /* We are not on a straight line. Determine the rail to build * based on whether we are above or below it. */ b = dx + dy >= (int)TILE_SIZE ? HT_LINE | HT_DIR_HU : HT_LINE | HT_DIR_HL; /* Calculate where a horizontal line through the start point and * a vertical line from the selected end point intersect and * use that point as the end point. */ int offset = (raw_dx - raw_dy) / 2; x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK); y = _thd.selstart.y + (offset & ~TILE_UNIT_MASK); /* 'Build' the last half rail tile if needed */ if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { if (dx + dy >= (int)TILE_SIZE) { x += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE; } else { y += (dx + dy < 0) ? (int)TILE_SIZE : -(int)TILE_SIZE; } } /* Make sure we do not overflow the map! */ CheckUnderflow(x, y, 1); CheckUnderflow(y, x, 1); CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, 1); CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, 1); assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE)); } break; case VPM_FIX_VERTICAL: if (dx == dy) { /* We are on a straight vertical line. Determine the 'rail' * to build based the sub tile location. */ b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; } else { /* We are not on a straight line. Determine the rail to build * based on whether we are left or right from it. */ b = dx < dy ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; /* Calculate where a vertical line through the start point and * a horizontal line from the selected end point intersect and * use that point as the end point. */ int offset = (raw_dx + raw_dy + (int)TILE_SIZE) / 2; x = _thd.selstart.x - (offset & ~TILE_UNIT_MASK); y = _thd.selstart.y - (offset & ~TILE_UNIT_MASK); /* 'Build' the last half rail tile if needed */ if ((offset & TILE_UNIT_MASK) > (TILE_SIZE / 2)) { if (dx - dy < 0) { y += (dx > dy) ? (int)TILE_SIZE : -(int)TILE_SIZE; } else { x += (dx < dy) ? (int)TILE_SIZE : -(int)TILE_SIZE; } } /* Make sure we do not overflow the map! */ CheckUnderflow(x, y, -1); CheckUnderflow(y, x, -1); CheckOverflow(x, y, (MapMaxX() - 1) * TILE_SIZE, -1); CheckOverflow(y, x, (MapMaxY() - 1) * TILE_SIZE, -1); assert(x >= 0 && y >= 0 && x <= (int)(MapMaxX() * TILE_SIZE) && y <= (int)(MapMaxY() * TILE_SIZE)); } break; default: NOT_REACHED(); } } else if (TileVirtXY(_thd.selstart.x, _thd.selstart.y) == TileVirtXY(x, y)) { // check if we're only within one tile if (method & VPM_RAILDIRS) { b = GetAutorailHT(x, y); } else { // rect for autosignals on one tile b = HT_RECT; } } else if (h == TILE_SIZE) { // Is this in X direction? if (dx == (int)TILE_SIZE) { // 2x1 special handling b = (Check2x1AutoRail(3)) | HT_LINE; } else if (dx == -(int)TILE_SIZE) { b = (Check2x1AutoRail(2)) | HT_LINE; } else { b = HT_LINE | HT_DIR_X; } y = _thd.selstart.y; } else if (w == TILE_SIZE) { // Or Y direction? if (dy == (int)TILE_SIZE) { // 2x1 special handling b = (Check2x1AutoRail(1)) | HT_LINE; } else if (dy == -(int)TILE_SIZE) { // 2x1 other direction b = (Check2x1AutoRail(0)) | HT_LINE; } else { b = HT_LINE | HT_DIR_Y; } x = _thd.selstart.x; } else if (w > h * 2) { // still count as x dir? b = HT_LINE | HT_DIR_X; y = _thd.selstart.y; } else if (h > w * 2) { // still count as y dir? b = HT_LINE | HT_DIR_Y; x = _thd.selstart.x; } else { // complicated direction int d = w - h; _thd.selend.x = _thd.selend.x & ~TILE_UNIT_MASK; _thd.selend.y = _thd.selend.y & ~TILE_UNIT_MASK; /* four cases. */ if (x > _thd.selstart.x) { if (y > _thd.selstart.y) { /* south */ if (d == 0) { b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; } else if (d >= 0) { x = _thd.selstart.x + h; b = HT_LINE | HT_DIR_VL; } else { y = _thd.selstart.y + w; b = HT_LINE | HT_DIR_VR; } } else { /* west */ if (d == 0) { b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; } else if (d >= 0) { x = _thd.selstart.x + h; b = HT_LINE | HT_DIR_HL; } else { y = _thd.selstart.y - w; b = HT_LINE | HT_DIR_HU; } } } else { if (y > _thd.selstart.y) { /* east */ if (d == 0) { b = (x & TILE_UNIT_MASK) + (y & TILE_UNIT_MASK) >= TILE_SIZE ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU; } else if (d >= 0) { x = _thd.selstart.x - h; b = HT_LINE | HT_DIR_HU; } else { y = _thd.selstart.y + w; b = HT_LINE | HT_DIR_HL; } } else { /* north */ if (d == 0) { b = (x & TILE_UNIT_MASK) > (y & TILE_UNIT_MASK) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR; } else if (d >= 0) { x = _thd.selstart.x - h; b = HT_LINE | HT_DIR_VR; } else { y = _thd.selstart.y - w; b = HT_LINE | HT_DIR_VL; } } } } if (_settings_client.gui.measure_tooltip) { TileIndex t0 = TileVirtXY(_thd.selstart.x, _thd.selstart.y); TileIndex t1 = TileVirtXY(x, y); uint distance = DistanceManhattan(t0, t1) + 1; byte index = 0; uint64 params[2]; if (distance != 1) { int heightdiff = CalcHeightdiff(b, distance, t0, t1); /* If we are showing a tooltip for horizontal or vertical drags, * 2 tiles have a length of 1. To bias towards the ceiling we add * one before division. It feels more natural to count 3 lengths as 2 */ if ((b & HT_DIR_MASK) != HT_DIR_X && (b & HT_DIR_MASK) != HT_DIR_Y) { distance = CeilDiv(distance, 2); } params[index++] = distance; if (heightdiff != 0) params[index++] = heightdiff; } ShowMeasurementTooltips(measure_strings_length[index], index, params); } _thd.selend.x = x; _thd.selend.y = y; _thd.next_drawstyle = b; } /** * Selects tiles while dragging * @param x X coordinate of end of selection * @param y Y coordinate of end of selection * @param method modifies the way tiles are selected. Possible * methods are VPM_* in viewport.h */ void VpSelectTilesWithMethod(int x, int y, ViewportPlaceMethod method) { int sx, sy; HighLightStyle style; if (x == -1) { _thd.selend.x = -1; return; } /* Special handling of drag in any (8-way) direction */ if (method & (VPM_RAILDIRS | VPM_SIGNALDIRS)) { _thd.selend.x = x; _thd.selend.y = y; CalcRaildirsDrawstyle(x, y, method); return; } /* Needed so level-land is placed correctly */ if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_POINT) { x += TILE_SIZE / 2; y += TILE_SIZE / 2; } sx = _thd.selstart.x; sy = _thd.selstart.y; int limit = 0; switch (method) { case VPM_X_OR_Y: // drag in X or Y direction if (abs(sy - y) < abs(sx - x)) { y = sy; style = HT_DIR_X; } else { x = sx; style = HT_DIR_Y; } goto calc_heightdiff_single_direction; case VPM_X_LIMITED: // Drag in X direction (limited size). limit = (_thd.sizelimit - 1) * TILE_SIZE; /* FALL THROUGH */ case VPM_FIX_X: // drag in Y direction x = sx; style = HT_DIR_Y; goto calc_heightdiff_single_direction; case VPM_Y_LIMITED: // Drag in Y direction (limited size). limit = (_thd.sizelimit - 1) * TILE_SIZE; /* FALL THROUGH */ case VPM_FIX_Y: // drag in X direction y = sy; style = HT_DIR_X; calc_heightdiff_single_direction:; if (limit > 0) { x = sx + Clamp(x - sx, -limit, limit); y = sy + Clamp(y - sy, -limit, limit); } if (_settings_client.gui.measure_tooltip) { TileIndex t0 = TileVirtXY(sx, sy); TileIndex t1 = TileVirtXY(x, y); uint distance = DistanceManhattan(t0, t1) + 1; byte index = 0; uint64 params[2]; if (distance != 1) { /* With current code passing a HT_LINE style to calculate the height * difference is enough. However if/when a point-tool is created * with this method, function should be called with new_style (below) * instead of HT_LINE | style case HT_POINT is handled specially * new_style := (_thd.next_drawstyle & HT_RECT) ? HT_LINE | style : _thd.next_drawstyle; */ int heightdiff = CalcHeightdiff(HT_LINE | style, 0, t0, t1); params[index++] = distance; if (heightdiff != 0) params[index++] = heightdiff; } ShowMeasurementTooltips(measure_strings_length[index], index, params); } break; case VPM_X_AND_Y_LIMITED: // Drag an X by Y constrained rect area. limit = (_thd.sizelimit - 1) * TILE_SIZE; x = sx + Clamp(x - sx, -limit, limit); y = sy + Clamp(y - sy, -limit, limit); /* FALL THROUGH */ case VPM_X_AND_Y: // drag an X by Y area if (_settings_client.gui.measure_tooltip) { static const StringID measure_strings_area[] = { STR_NULL, STR_NULL, STR_MEASURE_AREA, STR_MEASURE_AREA_HEIGHTDIFF }; TileIndex t0 = TileVirtXY(sx, sy); TileIndex t1 = TileVirtXY(x, y); uint dx = Delta(TileX(t0), TileX(t1)) + 1; uint dy = Delta(TileY(t0), TileY(t1)) + 1; byte index = 0; uint64 params[3]; /* If dragging an area (eg dynamite tool) and it is actually a single * row/column, change the type to 'line' to get proper calculation for height */ style = (HighLightStyle)_thd.next_drawstyle; if (_thd.IsDraggingDiagonal()) { /* Determine the "area" of the diagonal dragged selection. * We assume the area is the number of tiles along the X * edge and the number of tiles along the Y edge. However, * multiplying these two numbers does not give the exact * number of tiles; basically we are counting the black * squares on a chess board and ignore the white ones to * make the tile counts at the edges match up. There is no * other way to make a proper count though. * * First convert to the rotated coordinate system. */ int dist_x = TileX(t0) - TileX(t1); int dist_y = TileY(t0) - TileY(t1); int a_max = dist_x + dist_y; int b_max = dist_y - dist_x; /* Now determine the size along the edge, but due to the * chess board principle this counts double. */ a_max = abs(a_max + (a_max > 0 ? 2 : -2)) / 2; b_max = abs(b_max + (b_max > 0 ? 2 : -2)) / 2; /* We get a 1x1 on normal 2x1 rectangles, due to it being * a seen as two sides. As the result for actual building * will be the same as non-diagonal dragging revert to that * behaviour to give it a more normally looking size. */ if (a_max != 1 || b_max != 1) { dx = a_max; dy = b_max; } } else if (style & HT_RECT) { if (dx == 1) { style = HT_LINE | HT_DIR_Y; } else if (dy == 1) { style = HT_LINE | HT_DIR_X; } } if (dx != 1 || dy != 1) { int heightdiff = CalcHeightdiff(style, 0, t0, t1); params[index++] = dx - (style & HT_POINT ? 1 : 0); params[index++] = dy - (style & HT_POINT ? 1 : 0); if (heightdiff != 0) params[index++] = heightdiff; } ShowMeasurementTooltips(measure_strings_area[index], index, params); } break; default: NOT_REACHED(); } _thd.selend.x = x; _thd.selend.y = y; } /** * Handle the mouse while dragging for placement/resizing. * @return State of handling the event. */ EventState VpHandlePlaceSizingDrag() { if (_special_mouse_mode != WSM_SIZING) return ES_NOT_HANDLED; /* stop drag mode if the window has been closed */ Window *w = _thd.GetCallbackWnd(); if (w == NULL) { ResetObjectToPlace(); return ES_HANDLED; } /* while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() ) */ if (_left_button_down) { w->OnPlaceDrag(_thd.select_method, _thd.select_proc, GetTileBelowCursor()); return ES_HANDLED; } /* mouse button released.. * keep the selected tool, but reset it to the original mode. */ _special_mouse_mode = WSM_NONE; HighLightStyle others = _thd.place_mode & ~(HT_DRAG_MASK | HT_DIR_MASK); if ((_thd.next_drawstyle & HT_DRAG_MASK) == HT_RECT) { _thd.place_mode = HT_RECT | others; } else if (_thd.select_method & VPM_SIGNALDIRS) { _thd.place_mode = HT_RECT | others; } else if (_thd.select_method & VPM_RAILDIRS) { _thd.place_mode = (_thd.select_method & ~VPM_RAILDIRS) ? _thd.next_drawstyle : (HT_RAIL | others); } else { _thd.place_mode = HT_POINT | others; } SetTileSelectSize(1, 1); w->OnPlaceMouseUp(_thd.select_method, _thd.select_proc, _thd.selend, TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y)); return ES_HANDLED; } void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w) { SetObjectToPlace(icon, pal, mode, w->window_class, w->window_number); } #include "table/animcursors.h" void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num) { if (_thd.window_class != WC_INVALID) { /* Undo clicking on button and drag & drop */ Window *w = _thd.GetCallbackWnd(); /* Call the abort function, but set the window class to something * that will never be used to avoid infinite loops. Setting it to * the 'next' window class must not be done because recursion into * this function might in some cases reset the newly set object to * place or not properly reset the original selection. */ _thd.window_class = WC_INVALID; if (w != NULL) w->OnPlaceObjectAbort(); } /* Mark the old selection dirty, in case the selection shape or colour changes */ if ((_thd.drawstyle & HT_DRAG_MASK) != HT_NONE) SetSelectionTilesDirty(); SetTileSelectSize(1, 1); _thd.make_square_red = false; if (mode == HT_DRAG) { // HT_DRAG is for dragdropping trains in the depot window mode = HT_NONE; _special_mouse_mode = WSM_DRAGDROP; } else { _special_mouse_mode = WSM_NONE; } _thd.place_mode = mode; _thd.window_class = window_class; _thd.window_number = window_num; if ((mode & HT_DRAG_MASK) == HT_SPECIAL) { // special tools, like tunnels or docks start with presizing mode VpStartPreSizing(); } if ((icon & ANIMCURSOR_FLAG) != 0) { SetAnimatedMouseCursor(_animcursors[icon & ~ANIMCURSOR_FLAG]); } else { SetMouseCursor(icon, pal); } } void ResetObjectToPlace() { SetObjectToPlace(SPR_CURSOR_MOUSE, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); } Point GetViewportStationMiddle(const ViewPort *vp, const Station *st) { int x = TileX(st->xy) * TILE_SIZE; int y = TileY(st->xy) * TILE_SIZE; int z = GetSlopePixelZ(Clamp(x, 0, MapSizeX() * TILE_SIZE - 1), Clamp(y, 0, MapSizeY() * TILE_SIZE - 1)); Point p = RemapCoords(x, y, z); p.x = UnScaleByZoom(p.x - vp->virtual_left, vp->zoom) + vp->left; p.y = UnScaleByZoom(p.y - vp->virtual_top, vp->zoom) + vp->top; return p; } /** Helper class for getting the best sprite sorter. */ struct ViewportSSCSS { VpSorterChecker fct_checker; ///< The check function. VpSpriteSorter fct_sorter; ///< The sorting function. }; /** List of sorters ordered from best to worst. */ static ViewportSSCSS _vp_sprite_sorters[] = { #ifdef WITH_SSE { &ViewportSortParentSpritesSSE41Checker, &ViewportSortParentSpritesSSE41 }, #endif { &ViewportSortParentSpritesChecker, &ViewportSortParentSprites } }; /** Choose the "best" sprite sorter and set _vp_sprite_sorter. */ void InitializeSpriteSorter() { for (uint i = 0; i < lengthof(_vp_sprite_sorters); i++) { if (_vp_sprite_sorters[i].fct_checker()) { _vp_sprite_sorter = _vp_sprite_sorters[i].fct_sorter; break; } } assert(_vp_sprite_sorter != NULL); } openttd-1.5.3/src/vehicle_base.h0000644000000000000000000011534112627373441015262 0ustar rootroot/* $Id: vehicle_base.h 26864 2014-09-20 15:46:44Z rubidium $ */ /* * 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 vehicle_base.h Base class for all vehicles. */ #ifndef VEHICLE_BASE_H #define VEHICLE_BASE_H #include "core/smallmap_type.hpp" #include "track_type.h" #include "command_type.h" #include "order_base.h" #include "cargopacket.h" #include "texteff.hpp" #include "engine_type.h" #include "order_func.h" #include "transport_type.h" #include "group_type.h" #include "base_consist.h" #include #include /** Vehicle status bits in #Vehicle::vehstatus. */ enum VehStatus { VS_HIDDEN = 0x01, ///< Vehicle is not visible. VS_STOPPED = 0x02, ///< Vehicle is stopped by the player. VS_UNCLICKABLE = 0x04, ///< Vehicle is not clickable by the user (shadow vehicles). VS_DEFPAL = 0x08, ///< Use default vehicle palette. @see DoDrawVehicle VS_TRAIN_SLOWING = 0x10, ///< Train is slowing down. VS_SHADOW = 0x20, ///< Vehicle is a shadow vehicle. VS_AIRCRAFT_BROKEN = 0x40, ///< Aircraft is broken down. VS_CRASHED = 0x80, ///< Vehicle is crashed. }; /** Bit numbers in #Vehicle::vehicle_flags. */ enum VehicleFlags { VF_LOADING_FINISHED, ///< Vehicle has finished loading. VF_CARGO_UNLOADING, ///< Vehicle is unloading cargo. VF_BUILT_AS_PROTOTYPE, ///< Vehicle is a prototype (accepted as exclusive preview). VF_TIMETABLE_STARTED, ///< Whether the vehicle has started running on the timetable yet. VF_AUTOFILL_TIMETABLE, ///< Whether the vehicle should fill in the timetable automatically. VF_AUTOFILL_PRES_WAIT_TIME, ///< Whether non-destructive auto-fill should preserve waiting times VF_STOP_LOADING, ///< Don't load anymore during the next load cycle. VF_PATHFINDER_LOST, ///< Vehicle's pathfinder is lost. VF_SERVINT_IS_CUSTOM, ///< Service interval is custom. VF_SERVINT_IS_PERCENT, ///< Service interval is percent. }; /** Bit numbers used to indicate which of the #NewGRFCache values are valid. */ enum NewGRFCacheValidValues { NCVV_POSITION_CONSIST_LENGTH = 0, ///< This bit will be set if the NewGRF var 40 currently stored is valid. NCVV_POSITION_SAME_ID_LENGTH = 1, ///< This bit will be set if the NewGRF var 41 currently stored is valid. NCVV_CONSIST_CARGO_INFORMATION = 2, ///< This bit will be set if the NewGRF var 42 currently stored is valid. NCVV_COMPANY_INFORMATION = 3, ///< This bit will be set if the NewGRF var 43 currently stored is valid. NCVV_POSITION_IN_VEHICLE = 4, ///< This bit will be set if the NewGRF var 4D currently stored is valid. NCVV_END, ///< End of the bits. }; /** Cached often queried (NewGRF) values */ struct NewGRFCache { /* Values calculated when they are requested for the first time after invalidating the NewGRF cache. */ uint32 position_consist_length; ///< Cache for NewGRF var 40. uint32 position_same_id_length; ///< Cache for NewGRF var 41. uint32 consist_cargo_information; ///< Cache for NewGRF var 42. (Note: The cargotype is untranslated in the cache because the accessing GRF is yet unknown.) uint32 company_information; ///< Cache for NewGRF var 43. uint32 position_in_vehicle; ///< Cache for NewGRF var 4D. uint8 cache_valid; ///< Bitset that indicates which cache values are valid. }; /** Meaning of the various bits of the visual effect. */ enum VisualEffect { VE_OFFSET_START = 0, ///< First bit that contains the offset (0 = front, 8 = centre, 15 = rear) VE_OFFSET_COUNT = 4, ///< Number of bits used for the offset VE_OFFSET_CENTRE = 8, ///< Value of offset corresponding to a position above the centre of the vehicle VE_TYPE_START = 4, ///< First bit used for the type of effect VE_TYPE_COUNT = 2, ///< Number of bits used for the effect type VE_TYPE_DEFAULT = 0, ///< Use default from engine class VE_TYPE_STEAM = 1, ///< Steam plumes VE_TYPE_DIESEL = 2, ///< Diesel fumes VE_TYPE_ELECTRIC = 3, ///< Electric sparks VE_DISABLE_EFFECT = 6, ///< Flag to disable visual effect VE_ADVANCED_EFFECT = VE_DISABLE_EFFECT, ///< Flag for advanced effects VE_DISABLE_WAGON_POWER = 7, ///< Flag to disable wagon power VE_DEFAULT = 0xFF, ///< Default value to indicate that visual effect should be based on engine class }; /** Models for spawning visual effects. */ enum VisualEffectSpawnModel { VESM_NONE = 0, ///< No visual effect VESM_STEAM, ///< Steam model VESM_DIESEL, ///< Diesel model VESM_ELECTRIC, ///< Electric model VESM_END }; /** * Enum to handle ground vehicle subtypes. * This is defined here instead of at #GroundVehicle because some common function require access to these flags. * Do not access it directly unless you have to. Use the subtype access functions. */ enum GroundVehicleSubtypeFlags { GVSF_FRONT = 0, ///< Leading engine of a consist. GVSF_ARTICULATED_PART = 1, ///< Articulated part of an engine. GVSF_WAGON = 2, ///< Wagon (not used for road vehicles). GVSF_ENGINE = 3, ///< Engine that can be front engine, but might be placed behind another engine (not used for road vehicles). GVSF_FREE_WAGON = 4, ///< First in a wagon chain (in depot) (not used for road vehicles). GVSF_MULTIHEADED = 5, ///< Engine is multiheaded (not used for road vehicles). }; /** Cached often queried values common to all vehicles. */ struct VehicleCache { uint16 cached_max_speed; ///< Maximum speed of the consist (minimum of the max speed of all vehicles in the consist). uint16 cached_cargo_age_period; ///< Number of ticks before carried cargo is aged. byte cached_vis_effect; ///< Visual effect to show (see #VisualEffect) }; /** A vehicle pool for a little over 1 million vehicles. */ typedef Pool VehiclePool; extern VehiclePool _vehicle_pool; /* Some declarations of functions, so we can make them friendly */ struct SaveLoad; struct GroundVehicleCache; extern const SaveLoad *GetVehicleDescription(VehicleType vt); struct LoadgameState; extern bool LoadOldVehicle(LoadgameState *ls, int num); extern void FixOldVehicles(); struct GRFFile; /** * Simulated cargo type and capacity for prediction of future links. */ struct RefitDesc { CargoID cargo; ///< Cargo type the vehicle will be carrying. uint16 capacity; ///< Capacity the vehicle will have. uint16 remaining; ///< Capacity remaining from before the previous refit. RefitDesc(CargoID cargo, uint16 capacity, uint16 remaining) : cargo(cargo), capacity(capacity), remaining(remaining) {} }; /** %Vehicle data structure. */ struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist { private: typedef std::list RefitList; typedef std::map CapacitiesMap; Vehicle *next; ///< pointer to the next vehicle in the chain Vehicle *previous; ///< NOSAVE: pointer to the previous vehicle in the chain Vehicle *first; ///< NOSAVE: pointer to the first vehicle in the chain Vehicle *next_shared; ///< pointer to the next vehicle that shares the order Vehicle *previous_shared; ///< NOSAVE: pointer to the previous vehicle in the shared order chain public: friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code friend void FixOldVehicles(); friend void AfterLoadVehicles(bool part_of_load); ///< So we can set the #previous and #first pointers while loading friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading TileIndex tile; ///< Current tile index /** * Heading for this tile. * For airports and train stations this tile does not necessarily belong to the destination station, * but it can be used for heuristic purposes to estimate the distance. */ TileIndex dest_tile; Money profit_this_year; ///< Profit this year << 8, low 8 bits are fract Money profit_last_year; ///< Profit last year << 8, low 8 bits are fract Money value; ///< Value of the vehicle CargoPayment *cargo_payment; ///< The cargo payment we're currently in Rect coord; ///< NOSAVE: Graphical bounding box of the vehicle, i.e. what to redraw on moves. Vehicle *hash_viewport_next; ///< NOSAVE: Next vehicle in the visual location hash. Vehicle **hash_viewport_prev; ///< NOSAVE: Previous vehicle in the visual location hash. Vehicle *hash_tile_next; ///< NOSAVE: Next vehicle in the tile location hash. Vehicle **hash_tile_prev; ///< NOSAVE: Previous vehicle in the tile location hash. Vehicle **hash_tile_current; ///< NOSAVE: Cache of the current hash chain. SpriteID colourmap; ///< NOSAVE: cached colour mapping /* Related to age and service time */ Year build_year; ///< Year the vehicle has been built. Date age; ///< Age in days Date max_age; ///< Maximum age Date date_of_last_service; ///< Last date the vehicle had a service at a depot. uint16 reliability; ///< Reliability. uint16 reliability_spd_dec; ///< Reliability decrease speed. byte breakdown_ctr; ///< Counter for managing breakdown events. @see Vehicle::HandleBreakdown byte breakdown_delay; ///< Counter for managing breakdown length. byte breakdowns_since_last_service; ///< Counter for the amount of breakdowns. byte breakdown_chance; ///< Current chance of breakdowns. int32 x_pos; ///< x coordinate. int32 y_pos; ///< y coordinate. int32 z_pos; ///< z coordinate. DirectionByte direction; ///< facing OwnerByte owner; ///< Which company owns the vehicle? /** * currently displayed sprite index * 0xfd == custom sprite, 0xfe == custom second head sprite * 0xff == reserved for another custom sprite */ byte spritenum; SpriteID cur_image; ///< sprite number for this vehicle byte x_extent; ///< x-extent of vehicle bounding box byte y_extent; ///< y-extent of vehicle bounding box byte z_extent; ///< z-extent of vehicle bounding box int8 x_bb_offs; ///< x offset of vehicle bounding box int8 y_bb_offs; ///< y offset of vehicle bounding box int8 x_offs; ///< x offset for vehicle sprite int8 y_offs; ///< y offset for vehicle sprite EngineID engine_type; ///< The type of engine used for this vehicle. TextEffectID fill_percent_te_id; ///< a text-effect id to a loading indicator object UnitID unitnumber; ///< unit number, for display purposes only uint16 cur_speed; ///< current speed byte subspeed; ///< fractional speed byte acceleration; ///< used by train & aircraft uint32 motion_counter; ///< counter to occasionally play a vehicle sound. byte progress; ///< The percentage (if divided by 256) this vehicle already crossed the tile unit. byte random_bits; ///< Bits used for determining which randomized variational spritegroups to use when drawing. byte waiting_triggers; ///< Triggers to be yet matched before rerandomizing the random bits. StationID last_station_visited; ///< The last station we stopped at. StationID last_loading_station; ///< Last station the vehicle has stopped at and could possibly leave from with any cargo loaded. CargoID cargo_type; ///< type of cargo this vehicle is carrying byte cargo_subtype; ///< Used for livery refits (NewGRF variations) uint16 cargo_cap; ///< total capacity uint16 refit_cap; ///< Capacity left over from before last refit. VehicleCargoList cargo; ///< The cargo this vehicle is carrying uint16 cargo_age_counter; ///< Ticks till cargo is aged next. byte day_counter; ///< Increased by one for each day byte tick_counter; ///< Increased by one for each tick byte running_ticks; ///< Number of ticks this vehicle was not stopped this day byte vehstatus; ///< Status Order current_order; ///< The current order (+ status, like: loading) union { OrderList *list; ///< Pointer to the order list for this vehicle Order *old; ///< Only used during conversion of old save games } orders; ///< The orders currently assigned to the vehicle. uint16 load_unload_ticks; ///< Ticks to wait before starting next cycle. GroupID group_id; ///< Index of group Pool array byte subtype; ///< subtype (Filled with values from #EffectVehicles/#TrainSubTypes/#AircraftSubTypes) NewGRFCache grf_cache; ///< Cache of often used calculated NewGRF values VehicleCache vcache; ///< Cache of often used vehicle values. Vehicle(VehicleType type = VEH_INVALID); void PreDestructor(); /** We want to 'destruct' the right class. */ virtual ~Vehicle(); void BeginLoading(); void CancelReservation(StationID next, Station *st); void LeaveStation(); GroundVehicleCache *GetGroundVehicleCache(); const GroundVehicleCache *GetGroundVehicleCache() const; uint16 &GetGroundVehicleFlags(); const uint16 &GetGroundVehicleFlags() const; void DeleteUnreachedImplicitOrders(); void HandleLoading(bool mode = false); void GetConsistFreeCapacities(SmallMap &capacities) const; uint GetConsistTotalCapacity() const; /** * Marks the vehicles to be redrawn and updates cached variables * * This method marks the area of the vehicle on the screen as dirty. * It can be use to repaint the vehicle. * * @ingroup dirty */ virtual void MarkDirty() {} /** * Updates the x and y offsets and the size of the sprite used * for this vehicle. * @param direction the direction the vehicle is facing */ virtual void UpdateDeltaXY(Direction direction) {} /** * Determines the effective direction-specific vehicle movement speed. * * This method belongs to the old vehicle movement method: * A vehicle moves a step every 256 progress units. * The vehicle speed is scaled by 3/4 when moving in X or Y direction due to the longer distance. * * However, this method is slightly wrong in corners, as the leftover progress is not scaled correctly * when changing movement direction. #GetAdvanceSpeed() and #GetAdvanceDistance() are better wrt. this. * * @param speed Direction-independent unscaled speed. * @return speed scaled by movement direction. 256 units are required for each movement step. */ inline uint GetOldAdvanceSpeed(uint speed) { return (this->direction & 1) ? speed : speed * 3 / 4; } /** * Determines the effective vehicle movement speed. * * Together with #GetAdvanceDistance() this function is a replacement for #GetOldAdvanceSpeed(). * * A vehicle progresses independent of it's movement direction. * However different amounts of "progress" are needed for moving a step in a specific direction. * That way the leftover progress does not need any adaption when changing movement direction. * * @param speed Direction-independent unscaled speed. * @return speed, scaled to match #GetAdvanceDistance(). */ static inline uint GetAdvanceSpeed(uint speed) { return speed * 3 / 4; } /** * Determines the vehicle "progress" needed for moving a step. * * Together with #GetAdvanceSpeed() this function is a replacement for #GetOldAdvanceSpeed(). * * @return distance to drive for a movement step on the map. */ inline uint GetAdvanceDistance() { return (this->direction & 1) ? 192 : 256; } /** * Sets the expense type associated to this vehicle type * @param income whether this is income or (running) expenses of the vehicle */ virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; } /** * Play the sound associated with leaving the station */ virtual void PlayLeaveStationSound() const {} /** * Whether this is the primary vehicle in the chain. */ virtual bool IsPrimaryVehicle() const { return false; } const Engine *GetEngine() const; /** * Gets the sprite to show for the given direction * @param direction the direction the vehicle is facing * @return the sprite for the given vehicle in the given direction */ virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; } const GRFFile *GetGRF() const; uint32 GetGRFID() const; /** * Invalidates cached NewGRF variables * @see InvalidateNewGRFCacheOfChain */ inline void InvalidateNewGRFCache() { this->grf_cache.cache_valid = 0; } /** * Invalidates cached NewGRF variables of all vehicles in the chain (after the current vehicle) * @see InvalidateNewGRFCache */ inline void InvalidateNewGRFCacheOfChain() { for (Vehicle *u = this; u != NULL; u = u->Next()) { u->InvalidateNewGRFCache(); } } /** * Check if the vehicle is a ground vehicle. * @return True iff the vehicle is a train or a road vehicle. */ inline bool IsGroundVehicle() const { return this->type == VEH_TRAIN || this->type == VEH_ROAD; } /** * Gets the speed in km-ish/h that can be sent into SetDParam for string processing. * @return the vehicle's speed */ virtual int GetDisplaySpeed() const { return 0; } /** * Gets the maximum speed in km-ish/h that can be sent into SetDParam for string processing. * @return the vehicle's maximum speed */ virtual int GetDisplayMaxSpeed() const { return 0; } /** * Calculates the maximum speed of the vehicle under its current conditions. * @return Current maximum speed in native units. */ virtual int GetCurrentMaxSpeed() const { return 0; } /** * Gets the running cost of a vehicle * @return the vehicle's running cost */ virtual Money GetRunningCost() const { return 0; } /** * Check whether the vehicle is in the depot. * @return true if and only if the vehicle is in the depot. */ virtual bool IsInDepot() const { return false; } /** * Check whether the whole vehicle chain is in the depot. * @return true if and only if the whole chain is in the depot. */ virtual bool IsChainInDepot() const { return this->IsInDepot(); } /** * Check whether the vehicle is in the depot *and* stopped. * @return true if and only if the vehicle is in the depot and stopped. */ bool IsStoppedInDepot() const { assert(this == this->First()); /* Free wagons have no VS_STOPPED state */ if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false; return this->IsChainInDepot(); } /** * Calls the tick handler of the vehicle * @return is this vehicle still valid? */ virtual bool Tick() { return true; }; /** * Calls the new day handler of the vehicle */ virtual void OnNewDay() {}; /** * Crash the (whole) vehicle chain. * @param flooded whether the cause of the crash is flooding or not. * @return the number of lost souls. */ virtual uint Crash(bool flooded = false); /** * Returns the Trackdir on which the vehicle is currently located. * Works for trains and ships. * Currently works only sortof for road vehicles, since they have a fuzzy * concept of being "on" a trackdir. Dunno really what it returns for a road * vehicle that is halfway a tile, never really understood that part. For road * vehicles that are at the beginning or end of the tile, should just return * the diagonal trackdir on which they are driving. I _think_. * For other vehicles types, or vehicles with no clear trackdir (such as those * in depots), returns 0xFF. * @return the trackdir of the vehicle */ virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; } /** * Gets the running cost of a vehicle that can be sent into SetDParam for string processing. * @return the vehicle's running cost */ Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); } /** * Gets the profit vehicle had this year. It can be sent into SetDParam for string processing. * @return the vehicle's profit this year */ Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); } /** * Gets the profit vehicle had last year. It can be sent into SetDParam for string processing. * @return the vehicle's profit last year */ Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); } void SetNext(Vehicle *next); /** * Get the next vehicle of this vehicle. * @note articulated parts are also counted as vehicles. * @return the next vehicle or NULL when there isn't a next vehicle. */ inline Vehicle *Next() const { return this->next; } /** * Get the previous vehicle of this vehicle. * @note articulated parts are also counted as vehicles. * @return the previous vehicle or NULL when there isn't a previous vehicle. */ inline Vehicle *Previous() const { return this->previous; } /** * Get the first vehicle of this vehicle chain. * @return the first vehicle of the chain. */ inline Vehicle *First() const { return this->first; } /** * Get the last vehicle of this vehicle chain. * @return the last vehicle of the chain. */ inline Vehicle *Last() { Vehicle *v = this; while (v->Next() != NULL) v = v->Next(); return v; } /** * Get the last vehicle of this vehicle chain. * @return the last vehicle of the chain. */ inline const Vehicle *Last() const { const Vehicle *v = this; while (v->Next() != NULL) v = v->Next(); return v; } /** * Get the vehicle at offset \a n of this vehicle chain. * @param n Offset from the current vehicle. * @return The new vehicle or NULL if the offset is out-of-bounds. */ inline Vehicle *Move(int n) { Vehicle *v = this; if (n < 0) { for (int i = 0; i != n && v != NULL; i--) v = v->Previous(); } else { for (int i = 0; i != n && v != NULL; i++) v = v->Next(); } return v; } /** * Get the vehicle at offset \a n of this vehicle chain. * @param n Offset from the current vehicle. * @return The new vehicle or NULL if the offset is out-of-bounds. */ inline const Vehicle *Move(int n) const { const Vehicle *v = this; if (n < 0) { for (int i = 0; i != n && v != NULL; i--) v = v->Previous(); } else { for (int i = 0; i != n && v != NULL; i++) v = v->Next(); } return v; } /** * Get the first order of the vehicles order list. * @return first order of order list. */ inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); } void AddToShared(Vehicle *shared_chain); void RemoveFromShared(); /** * Get the next vehicle of the shared vehicle chain. * @return the next shared vehicle or NULL when there isn't a next vehicle. */ inline Vehicle *NextShared() const { return this->next_shared; } /** * Get the previous vehicle of the shared vehicle chain * @return the previous shared vehicle or NULL when there isn't a previous vehicle. */ inline Vehicle *PreviousShared() const { return this->previous_shared; } /** * Get the first vehicle of this vehicle chain. * @return the first vehicle of the chain. */ inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); } /** * Check if we share our orders with another vehicle. * @return true if there are other vehicles sharing the same order */ inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); } /** * Get the number of orders this vehicle has. * @return the number of orders this vehicle has. */ inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); } /** * Get the number of manually added orders this vehicle has. * @return the number of manually added orders this vehicle has. */ inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); } /** * Get the next station the vehicle will stop at. * @return ID of the next station the vehicle will stop at or INVALID_STATION. */ inline StationIDStack GetNextStoppingStation() const { return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this); } void ResetRefitCaps(); /** * Copy certain configurations and statistics of a vehicle after successful autoreplace/renew * The function shall copy everything that cannot be copied by a command (like orders / group etc), * and that shall not be resetted for the new vehicle. * @param src The old vehicle */ inline void CopyVehicleConfigAndStatistics(const Vehicle *src) { this->CopyConsistPropertiesFrom(src); this->unitnumber = src->unitnumber; this->current_order = src->current_order; this->dest_tile = src->dest_tile; this->profit_this_year = src->profit_this_year; this->profit_last_year = src->profit_last_year; } bool HandleBreakdown(); bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const; bool NeedsServicing() const; bool NeedsAutomaticServicing() const; /** * Determine the location for the station where the vehicle goes to next. * Things done for example are allocating slots in a road stop or exact * location of the platform is determined for ships. * @param station the station to make the next location of the vehicle. * @return the location (tile) to aim for. */ virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; } /** * Find the closest depot for this vehicle and tell us the location, * DestinationID and whether we should reverse. * @param location where do we go to? * @param destination what hangar do we go to? * @param reverse should the vehicle be reversed? * @return true if a depot could be found. */ virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; } CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command); void UpdateVisualEffect(bool allow_power_change = true); void ShowVisualEffect() const; void UpdatePosition(); void UpdateViewport(bool dirty); void UpdatePositionAndViewport(); void MarkAllViewportsDirty() const; inline uint16 GetServiceInterval() const { return this->service_interval; } inline void SetServiceInterval(uint16 interval) { this->service_interval = interval; } inline bool ServiceIntervalIsCustom() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM); } inline bool ServiceIntervalIsPercent() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT); } inline void SetServiceIntervalIsCustom(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_CUSTOM, 1, on); } inline void SetServiceIntervalIsPercent(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_PERCENT, 1, on); } private: /** * Advance cur_real_order_index to the next real order. * cur_implicit_order_index is not touched. */ void SkipToNextRealOrderIndex() { if (this->GetNumManualOrders() > 0) { /* Advance to next real order */ do { this->cur_real_order_index++; if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0; } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)); } else { this->cur_real_order_index = 0; } } public: /** * Increments cur_implicit_order_index, keeps care of the wrap-around and invalidates the GUI. * cur_real_order_index is incremented as well, if needed. * Note: current_order is not invalidated. */ void IncrementImplicitOrderIndex() { if (this->cur_implicit_order_index == this->cur_real_order_index) { /* Increment real order index as well */ this->SkipToNextRealOrderIndex(); } assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders()); /* Advance to next implicit order */ do { this->cur_implicit_order_index++; if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0; } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT)); InvalidateVehicleOrder(this, 0); } /** * Advanced cur_real_order_index to the next real order, keeps care of the wrap-around and invalidates the GUI. * cur_implicit_order_index is incremented as well, if it was equal to cur_real_order_index, i.e. cur_real_order_index is skipped * but not any implicit orders. * Note: current_order is not invalidated. */ void IncrementRealOrderIndex() { if (this->cur_implicit_order_index == this->cur_real_order_index) { /* Increment both real and implicit order */ this->IncrementImplicitOrderIndex(); } else { /* Increment real order only */ this->SkipToNextRealOrderIndex(); InvalidateVehicleOrder(this, 0); } } /** * Skip implicit orders until cur_real_order_index is a non-implicit order. */ void UpdateRealOrderIndex() { /* Make sure the index is valid */ if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0; if (this->GetNumManualOrders() > 0) { /* Advance to next real order */ while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) { this->cur_real_order_index++; if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0; } } else { this->cur_real_order_index = 0; } } /** * Returns order 'index' of a vehicle or NULL when it doesn't exists * @param index the order to fetch * @return the found (or not) order */ inline Order *GetOrder(int index) const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index); } /** * Returns the last order of a vehicle, or NULL if it doesn't exists * @return last order of a vehicle, if available */ inline Order *GetLastOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder(); } bool IsEngineCountable() const; bool HasEngineType() const; bool HasDepotOrder() const; void HandlePathfindingResult(bool path_found); /** * Check if the vehicle is a front engine. * @return Returns true if the vehicle is a front engine. */ inline bool IsFrontEngine() const { return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT); } /** * Check if the vehicle is an articulated part of an engine. * @return Returns true if the vehicle is an articulated part. */ inline bool IsArticulatedPart() const { return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART); } /** * Check if an engine has an articulated part. * @return True if the engine has an articulated part. */ inline bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); } /** * Get the next part of an articulated engine. * @return Next part of the articulated engine. * @pre The vehicle is an articulated engine. */ inline Vehicle *GetNextArticulatedPart() const { assert(this->HasArticulatedPart()); return this->Next(); } /** * Get the first part of an articulated engine. * @return First part of the engine. */ inline Vehicle *GetFirstEnginePart() { Vehicle *v = this; while (v->IsArticulatedPart()) v = v->Previous(); return v; } /** * Get the first part of an articulated engine. * @return First part of the engine. */ inline const Vehicle *GetFirstEnginePart() const { const Vehicle *v = this; while (v->IsArticulatedPart()) v = v->Previous(); return v; } /** * Get the last part of an articulated engine. * @return Last part of the engine. */ inline Vehicle *GetLastEnginePart() { Vehicle *v = this; while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart(); return v; } /** * Get the next real (non-articulated part) vehicle in the consist. * @return Next vehicle in the consist. */ inline Vehicle *GetNextVehicle() const { const Vehicle *v = this; while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart(); /* v now contains the last articulated part in the engine */ return v->Next(); } /** * Get the previous real (non-articulated part) vehicle in the consist. * @return Previous vehicle in the consist. */ inline Vehicle *GetPrevVehicle() const { Vehicle *v = this->Previous(); while (v != NULL && v->IsArticulatedPart()) v = v->Previous(); return v; } }; /** * Iterate over all vehicles from a given point. * @param var The variable used to iterate over. * @param start The vehicle to start the iteration at. */ #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start) /** * Iterate over all vehicles. * @param var The variable used to iterate over. */ #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0) /** * Class defining several overloaded accessors so we don't * have to cast vehicle types that often */ template struct SpecializedVehicle : public Vehicle { static const VehicleType EXPECTED_TYPE = Type; ///< Specialized type typedef SpecializedVehicle SpecializedVehicleBase; ///< Our type /** * Set vehicle type correctly */ inline SpecializedVehicle() : Vehicle(Type) { } /** * Get the first vehicle in the chain * @return first vehicle in the chain */ inline T *First() const { return (T *)this->Vehicle::First(); } /** * Get the last vehicle in the chain * @return last vehicle in the chain */ inline T *Last() { return (T *)this->Vehicle::Last(); } /** * Get the last vehicle in the chain * @return last vehicle in the chain */ inline const T *Last() const { return (const T *)this->Vehicle::Last(); } /** * Get next vehicle in the chain * @return next vehicle in the chain */ inline T *Next() const { return (T *)this->Vehicle::Next(); } /** * Get previous vehicle in the chain * @return previous vehicle in the chain */ inline T *Previous() const { return (T *)this->Vehicle::Previous(); } /** * Get the next part of an articulated engine. * @return Next part of the articulated engine. * @pre The vehicle is an articulated engine. */ inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); } /** * Get the next part of an articulated engine. * @return Next part of the articulated engine. * @pre The vehicle is an articulated engine. */ inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); } /** * Get the first part of an articulated engine. * @return First part of the engine. */ inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); } /** * Get the first part of an articulated engine. * @return First part of the engine. */ inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); } /** * Get the last part of an articulated engine. * @return Last part of the engine. */ inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); } /** * Get the next real (non-articulated part) vehicle in the consist. * @return Next vehicle in the consist. */ inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); } /** * Get the previous real (non-articulated part) vehicle in the consist. * @return Previous vehicle in the consist. */ inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); } /** * Tests whether given index is a valid index for vehicle of this type * @param index tested index * @return is this index valid index of T? */ static inline bool IsValidID(size_t index) { return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type; } /** * Gets vehicle with given index * @return pointer to vehicle with given index casted to T * */ static inline T *Get(size_t index) { return (T *)Vehicle::Get(index); } /** * Returns vehicle if the index is a valid index for this vehicle type * @return pointer to vehicle with given index if it's a vehicle of this type */ static inline T *GetIfValid(size_t index) { return IsValidID(index) ? Get(index) : NULL; } /** * Converts a Vehicle to SpecializedVehicle with type checking. * @param v Vehicle pointer * @return pointer to SpecializedVehicle */ static inline T *From(Vehicle *v) { assert(v->type == Type); return (T *)v; } /** * Converts a const Vehicle to const SpecializedVehicle with type checking. * @param v Vehicle pointer * @return pointer to SpecializedVehicle */ static inline const T *From(const Vehicle *v) { assert(v->type == Type); return (const T *)v; } /** * Update vehicle sprite- and position caches * @param force_update Force updating the vehicle on the viewport. * @param update_delta Also update the delta? */ inline void UpdateViewport(bool force_update, bool update_delta) { /* Explicitly choose method to call to prevent vtable dereference - * it gives ~3% runtime improvements in games with many vehicles */ if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction); SpriteID old_image = this->cur_image; this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP); if (force_update || this->cur_image != old_image) this->Vehicle::UpdateViewport(true); } }; /** * Iterate over all vehicles of a particular type. * @param name The type of vehicle to iterate over. * @param var The variable used to iterate over. */ #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE) /** Generates sequence of free UnitID numbers */ struct FreeUnitIDGenerator { bool *cache; ///< array of occupied unit id numbers UnitID maxid; ///< maximum ID at the moment of constructor call UnitID curid; ///< last ID returned; 0 if none FreeUnitIDGenerator(VehicleType type, CompanyID owner); UnitID NextID(); /** Releases allocated memory */ ~FreeUnitIDGenerator() { free(this->cache); } }; /** Sentinel for an invalid coordinate. */ static const int32 INVALID_COORD = 0x7fffffff; #endif /* VEHICLE_BASE_H */ openttd-1.5.3/src/driver.h0000644000000000000000000000766612627373442014157 0ustar rootroot/* $Id: driver.h 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 driver.h Base for all drivers (video, sound, music, etc). */ #ifndef DRIVER_H #define DRIVER_H #include "core/enum_type.hpp" #include "core/string_compare_type.hpp" #include const char *GetDriverParam(const char * const *parm, const char *name); bool GetDriverParamBool(const char * const *parm, const char *name); int GetDriverParamInt(const char * const *parm, const char *name, int def); /** A driver for communicating with the user. */ class Driver { public: /** * Start this driver. * @param parm Parameters passed to the driver. * @return NULL if everything went okay, otherwise an error message. */ virtual const char *Start(const char * const *parm) = 0; /** * Stop this driver. */ virtual void Stop() = 0; virtual ~Driver() { } /** The type of driver */ enum Type { DT_BEGIN = 0, ///< Helper for iteration DT_MUSIC = 0, ///< A music driver, needs to be before sound to properly shut down extmidi forked music players DT_SOUND, ///< A sound driver DT_VIDEO, ///< A video driver DT_END, ///< Helper for iteration }; /** * Get the name of this driver. * @return The name of the driver. */ virtual const char *GetName() const = 0; }; DECLARE_POSTFIX_INCREMENT(Driver::Type) /** Base for all driver factories. */ class DriverFactoryBase { private: friend class MusicDriver; friend class SoundDriver; friend class VideoDriver; Driver::Type type; ///< The type of driver. int priority; ///< The priority of this factory. const char *name; ///< The name of the drivers of this factory. const char *description; ///< The description of this driver. typedef std::map Drivers; ///< Type for a map of drivers. /** * Get the map with drivers. */ static Drivers &GetDrivers() { static Drivers &s_drivers = *new Drivers(); return s_drivers; } /** * Get the active driver for the given type. * @param type The type to get the driver for. * @return The active driver. */ static Driver **GetActiveDriver(Driver::Type type) { static Driver *s_driver[3] = { NULL, NULL, NULL }; return &s_driver[type]; } /** * Get the driver type name. * @param type The type of driver to get the name of. * @return The name of the type. */ static const char *GetDriverTypeName(Driver::Type type) { static const char * const driver_type_name[] = { "music", "sound", "video" }; return driver_type_name[type]; } static bool SelectDriverImpl(const char *name, Driver::Type type); protected: DriverFactoryBase(Driver::Type type, int priority, const char *name, const char *description); virtual ~DriverFactoryBase(); public: /** * Shuts down all active drivers */ static void ShutdownDrivers() { for (Driver::Type dt = Driver::DT_BEGIN; dt < Driver::DT_END; dt++) { Driver *driver = *GetActiveDriver(dt); if (driver != NULL) driver->Stop(); } } static void SelectDriver(const char *name, Driver::Type type); static char *GetDriversInfo(char *p, const char *last); /** * Get a nice description of the driver-class. * @return The description. */ const char *GetDescription() const { return this->description; } /** * Create an instance of this driver-class. * @return The instance. */ virtual Driver *CreateInstance() const = 0; }; #endif /* DRIVER_H */ openttd-1.5.3/src/water.h0000644000000000000000000000376012627373435013777 0ustar rootroot/* $Id: water.h 25229 2013-05-06 20:48:18Z planetmaker $ */ /* * 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 water.h Functions related to water (management) */ #ifndef WATER_H #define WATER_H #include "water_map.h" #include "economy_func.h" /** * Describes the behaviour of a tile during flooding. */ enum FloodingBehaviour { FLOOD_NONE, ///< The tile does not flood neighboured tiles. FLOOD_ACTIVE, ///< The tile floods neighboured tiles. FLOOD_PASSIVE, ///< The tile does not actively flood neighboured tiles, but it prevents them from drying up. FLOOD_DRYUP, ///< The tile drys up if it is not constantly flooded from neighboured tiles. }; FloodingBehaviour GetFloodingBehaviour(TileIndex tile); void TileLoop_Water(TileIndex tile); bool FloodHalftile(TileIndex t); void DoFloodTile(TileIndex target); void ConvertGroundTilesIntoWaterTiles(); void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part); void DrawWaterClassGround(const struct TileInfo *ti); void DrawShoreTile(Slope tileh); void MakeWaterKeepingClass(TileIndex tile, Owner o); bool RiverModifyDesertZone(TileIndex tile, void *data); bool IsWateredTile(TileIndex tile, Direction from); /** * Calculates the maintenance cost of a number of canal tiles. * @param num Number of canal tiles. * @return Total cost. */ static inline Money CanalMaintenanceCost(uint32 num) { return (_price[PR_INFRASTRUCTURE_WATER] * num * (1 + IntSqrt(num))) >> 6; // 6 bits scaling. } #endif /* WATER_H */ openttd-1.5.3/src/object_type.h0000644000000000000000000000344112627373435015160 0ustar rootroot/* $Id: object_type.h 25844 2013-10-12 16:35:50Z frosch $ */ /* * 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 object_type.h Types related to object tiles. */ #ifndef OBJECT_TYPE_H #define OBJECT_TYPE_H /** Types of objects. */ typedef uint16 ObjectType; static const ObjectType OBJECT_TRANSMITTER = 0; ///< The large antenna static const ObjectType OBJECT_LIGHTHOUSE = 1; ///< The nice lighthouse static const ObjectType OBJECT_STATUE = 2; ///< Statue in towns static const ObjectType OBJECT_OWNED_LAND = 3; ///< Owned land 'flag' static const ObjectType OBJECT_HQ = 4; ///< HeadQuarter of a player static const ObjectType NUM_OBJECTS_PER_GRF = 255; ///< Number of supported objects per NewGRF; limited to 255 to allow extending Action3 with an extended byte later on. static const ObjectType NEW_OBJECT_OFFSET = 5; ///< Offset for new objects static const ObjectType NUM_OBJECTS = 64000; ///< Number of supported objects overall static const ObjectType INVALID_OBJECT_TYPE = 0xFFFF; ///< An invalid object /** Unique identifier for an object. */ typedef uint32 ObjectID; struct Object; struct ObjectSpec; static const ObjectID INVALID_OBJECT = 0xFFFFFFFF; ///< An invalid object #endif /* OBJECT_TYPE_H */ openttd-1.5.3/src/newgrf_canal.cpp0000644000000000000000000001422212627373446015633 0ustar rootroot/* $Id: newgrf_canal.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_canal.cpp Implementation of NewGRF canals. */ #include "stdafx.h" #include "debug.h" #include "newgrf_spritegroup.h" #include "newgrf_canal.h" #include "water.h" #include "water_map.h" #include "safeguards.h" /** Table of canal 'feature' sprite groups */ WaterFeature _water_feature[CF_END]; /** Scope resolver of a canal tile. */ struct CanalScopeResolver : public ScopeResolver { TileIndex tile; ///< Tile containing the canal. CanalScopeResolver(ResolverObject &ro, TileIndex tile); /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; }; /** Resolver object for canals. */ struct CanalResolverObject : public ResolverObject { CanalScopeResolver canal_scope; CanalResolverObject(CanalFeature feature, TileIndex tile, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &this->canal_scope; default: return ResolverObject::GetScope(scope, relative); } } /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; }; /* virtual */ uint32 CanalScopeResolver::GetRandomBits() const { /* Return random bits only for water tiles, not station tiles */ return IsTileType(this->tile, MP_WATER) ? GetWaterTileRandomBits(this->tile) : 0; } /* virtual */ uint32 CanalScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { switch (variable) { /* Height of tile */ case 0x80: { int z = GetTileZ(this->tile); /* Return consistent height within locks */ if (IsTileType(this->tile, MP_WATER) && IsLock(this->tile) && GetLockPart(this->tile) == LOCK_PART_UPPER) z--; return z; } /* Terrain type */ case 0x81: return GetTerrainType(this->tile); /* Dike map: Connectivity info for river and canal tiles * * Assignment of bits to directions defined in agreement with * http://projects.tt-forums.net/projects/ttdpatch/repository/revisions/2367/entry/trunk/patches/water.asm#L879 * 7 * 3 0 * 6 * 4 * 2 1 * 5 */ case 0x82: { uint32 connectivity = (!IsWateredTile(TILE_ADDXY(tile, -1, 0), DIR_SW) << 0) // NE + (!IsWateredTile(TILE_ADDXY(tile, 0, 1), DIR_NW) << 1) // SE + (!IsWateredTile(TILE_ADDXY(tile, 1, 0), DIR_NE) << 2) // SW + (!IsWateredTile(TILE_ADDXY(tile, 0, -1), DIR_SE) << 3) // NW + (!IsWateredTile(TILE_ADDXY(tile, -1, 1), DIR_W) << 4) // E + (!IsWateredTile(TILE_ADDXY(tile, 1, 1), DIR_N) << 5) // S + (!IsWateredTile(TILE_ADDXY(tile, 1, -1), DIR_E) << 6) // W + (!IsWateredTile(TILE_ADDXY(tile, -1, -1), DIR_S) << 7); // N return connectivity; } /* Random data for river or canal tiles, otherwise zero */ case 0x83: return IsTileType(this->tile, MP_WATER) ? GetWaterTileRandomBits(this->tile) : 0; } DEBUG(grf, 1, "Unhandled canal variable 0x%02X", variable); *available = false; return UINT_MAX; } /* virtual */ const SpriteGroup *CanalResolverObject::ResolveReal(const RealSpriteGroup *group) const { if (group->num_loaded == 0) return NULL; return group->loaded[0]; } CanalScopeResolver::CanalScopeResolver(ResolverObject &ro, TileIndex tile) : ScopeResolver(ro) { this->tile = tile; } /** * Canal resolver constructor. * @param feature Which canal feature we want. * @param tile Tile index of canal. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ CanalResolverObject::CanalResolverObject(CanalFeature feature, TileIndex tile, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(_water_feature[feature].grffile, callback, callback_param1, callback_param2), canal_scope(*this, tile) { this->root_spritegroup = _water_feature[feature].group; } /** * Lookup the base sprite to use for a canal. * @param feature Which canal feature we want. * @param tile Tile index of canal, if appropriate. * @return Base sprite returned by GRF, or \c 0 if none. */ SpriteID GetCanalSprite(CanalFeature feature, TileIndex tile) { CanalResolverObject object(feature, tile); const SpriteGroup *group = object.Resolve(); if (group == NULL) return 0; return group->GetResult(); } /** * Run a specific callback for canals. * @param callback Callback ID. * @param param1 Callback parameter 1. * @param param2 Callback parameter 2. * @param feature For which feature to run the callback. * @param tile Tile index of canal. * @return Callback result or #CALLBACK_FAILED if the callback failed. */ static uint16 GetCanalCallback(CallbackID callback, uint32 param1, uint32 param2, CanalFeature feature, TileIndex tile) { CanalResolverObject object(feature, tile, callback, param1, param2); return object.ResolveCallback(); } /** * Get the new sprite offset for a water tile. * @param tile Tile index of the canal/water tile. * @param feature For which feature to get the new sprite offset. * @param cur_offset Current sprite offset. * @return New sprite offset. */ uint GetCanalSpriteOffset(CanalFeature feature, TileIndex tile, uint cur_offset) { if (HasBit(_water_feature[feature].callback_mask, CBM_CANAL_SPRITE_OFFSET)) { uint16 cb = GetCanalCallback(CBID_CANALS_SPRITE_OFFSET, cur_offset, 0, feature, tile); if (cb != CALLBACK_FAILED) return cur_offset + cb; } return cur_offset; } openttd-1.5.3/src/fios.cpp0000644000000000000000000005177212627373435014156 0ustar rootroot/* $Id: fios.cpp 26554 2014-05-03 15:45:54Z alberth $ */ /* * 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 fios.cpp * This file contains functions for building file lists for the save/load dialogs. */ #include "stdafx.h" #include "fios.h" #include "fileio_func.h" #include "tar_type.h" #include "screenshot.h" #include "string_func.h" #include #ifndef WIN32 # include #endif /* WIN32 */ #include "table/strings.h" #include "safeguards.h" /* Variables to display file lists */ SmallVector _fios_items; static char *_fios_path; static const char *_fios_path_last; SmallFiosItem _file_to_saveload; SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; /* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */ extern bool FiosIsRoot(const char *path); extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb); extern bool FiosIsHiddenFile(const struct dirent *ent); extern void FiosGetDrives(); extern bool FiosGetDiskFreeSpace(const char *path, uint64 *tot); /* get the name of an oldstyle savegame */ extern void GetOldSaveGameName(const char *file, char *title, const char *last); /** * Compare two FiosItem's. Used with sort when sorting the file list. * @param da A pointer to the first FiosItem to compare. * @param db A pointer to the second FiosItem to compare. * @return -1, 0 or 1, depending on how the two items should be sorted. */ int CDECL CompareFiosItems(const FiosItem *da, const FiosItem *db) { int r = 0; if ((_savegame_sort_order & SORT_BY_NAME) == 0 && da->mtime != db->mtime) { r = da->mtime < db->mtime ? -1 : 1; } else { r = strcasecmp(da->title, db->title); } if (_savegame_sort_order & SORT_DESCENDING) r = -r; return r; } /** Free the list of savegames. */ void FiosFreeSavegameList() { _fios_items.Clear(); _fios_items.Compact(); } /** * Get descriptive texts. Returns the path and free space * left on the device * @param path string describing the path * @param total_free total free space in megabytes, optional (can be NULL) * @return StringID describing the path (free space or failure) */ StringID FiosGetDescText(const char **path, uint64 *total_free) { *path = _fios_path; return FiosGetDiskFreeSpace(*path, total_free) ? STR_SAVELOAD_BYTES_FREE : STR_ERROR_UNABLE_TO_READ_DRIVE; } /** * Browse to a new path based on the passed \a item, starting at #_fios_path. * @param *item Item telling us what to do. * @return A filename w/path if we reached a file, otherwise \c NULL. */ const char *FiosBrowseTo(const FiosItem *item) { switch (item->type) { case FIOS_TYPE_DRIVE: #if defined(WINCE) seprintf(_fios_path, _fios_path_last, PATHSEP ""); #elif defined(WIN32) || defined(__OS2__) seprintf(_fios_path, _fios_path_last, "%c:" PATHSEP, item->title[0]); #endif /* FALL THROUGH */ case FIOS_TYPE_INVALID: break; case FIOS_TYPE_PARENT: { /* Check for possible NULL ptr (not required for UNIXes, but AmigaOS-alikes) */ char *s = strrchr(_fios_path, PATHSEPCHAR); if (s != NULL && s != _fios_path) { s[0] = '\0'; // Remove last path separator character, so we can go up one level. } s = strrchr(_fios_path, PATHSEPCHAR); if (s != NULL) { s[1] = '\0'; // go up a directory #if defined(__MORPHOS__) || defined(__AMIGAOS__) /* On MorphOS or AmigaOS paths look like: "Volume:directory/subdirectory" */ } else if ((s = strrchr(_fios_path, ':')) != NULL) { s[1] = '\0'; #endif } break; } case FIOS_TYPE_DIR: strecat(_fios_path, item->name, _fios_path_last); strecat(_fios_path, PATHSEP, _fios_path_last); break; case FIOS_TYPE_DIRECT: seprintf(_fios_path, _fios_path_last, "%s", item->name); break; case FIOS_TYPE_FILE: case FIOS_TYPE_OLDFILE: case FIOS_TYPE_SCENARIO: case FIOS_TYPE_OLD_SCENARIO: case FIOS_TYPE_PNG: case FIOS_TYPE_BMP: return item->name; } return NULL; } /** * Construct a filename from its components in destination buffer \a buf. * @param buf Destination buffer. * @param path Directory path, may be \c NULL. * @param name Filename. * @param ext Filename extension (use \c "" for no extension). * @param last Last element of buffer \a buf. */ static void FiosMakeFilename(char *buf, const char *path, const char *name, const char *ext, const char *last) { const char *period; /* Don't append the extension if it is already there */ period = strrchr(name, '.'); if (period != NULL && strcasecmp(period, ext) == 0) ext = ""; #if defined(__MORPHOS__) || defined(__AMIGAOS__) if (path != NULL) { unsigned char sepchar = path[(strlen(path) - 1)]; if (sepchar != ':' && sepchar != '/') { seprintf(buf, last, "%s" PATHSEP "%s%s", path, name, ext); } else { seprintf(buf, last, "%s%s%s", path, name, ext); } } else { seprintf(buf, last, "%s%s", name, ext); } #else seprintf(buf, last, "%s" PATHSEP "%s%s", path, name, ext); #endif } /** * Make a save game or scenario filename from a name. * @param buf Destination buffer for saving the filename. * @param name Name of the file. * @param last Last element of buffer \a buf. */ void FiosMakeSavegameName(char *buf, const char *name, const char *last) { const char *extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav"; FiosMakeFilename(buf, _fios_path, name, extension, last); } /** * Construct a filename for a height map. * @param buf Destination buffer. * @param name Filename. * @param last Last element of buffer \a buf. */ void FiosMakeHeightmapName(char *buf, const char *name, const char *last) { char ext[5]; ext[0] = '.'; strecpy(ext + 1, GetCurrentScreenshotExtension(), lastof(ext)); FiosMakeFilename(buf, _fios_path, name, ext, last); } /** * Delete a file. * @param name Filename to delete. * @return Whether the file deletion was successful. */ bool FiosDelete(const char *name) { char filename[512]; FiosMakeSavegameName(filename, name, lastof(filename)); return unlink(filename) == 0; } typedef FiosType fios_getlist_callback_proc(SaveLoadDialogMode mode, const char *filename, const char *ext, char *title, const char *last); /** * Scanner to scan for a particular type of FIOS file. */ class FiosFileScanner : public FileScanner { SaveLoadDialogMode mode; ///< The mode we want to search for fios_getlist_callback_proc *callback_proc; ///< Callback to check whether the file may be added public: /** * Create the scanner * @param mode The mode we are in. Some modes don't allow 'parent'. * @param callback_proc The function that is called where you need to do the filtering. */ FiosFileScanner(SaveLoadDialogMode mode, fios_getlist_callback_proc *callback_proc) : mode(mode), callback_proc(callback_proc) {} /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); }; /** * Try to add a fios item set with the given filename. * @param filename the full path to the file to read * @param basepath_length amount of characters to chop of before to get a relative filename * @return true if the file is added. */ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { const char *ext = strrchr(filename, '.'); if (ext == NULL) return false; char fios_title[64]; fios_title[0] = '\0'; // reset the title; FiosType type = this->callback_proc(this->mode, filename, ext, fios_title, lastof(fios_title)); if (type == FIOS_TYPE_INVALID) return false; for (const FiosItem *fios = _fios_items.Begin(); fios != _fios_items.End(); fios++) { if (strcmp(fios->name, filename) == 0) return false; } FiosItem *fios = _fios_items.Append(); #ifdef WIN32 struct _stat sb; if (_tstat(OTTD2FS(filename), &sb) == 0) { #else struct stat sb; if (stat(filename, &sb) == 0) { #endif fios->mtime = sb.st_mtime; } else { fios->mtime = 0; } fios->type = type; strecpy(fios->name, filename, lastof(fios->name)); /* If the file doesn't have a title, use its filename */ const char *t = fios_title; if (StrEmpty(fios_title)) { t = strrchr(filename, PATHSEPCHAR); t = (t == NULL) ? filename : (t + 1); } strecpy(fios->title, t, lastof(fios->title)); str_validate(fios->title, lastof(fios->title)); return true; } /** * Fill the list of the files in a directory, according to some arbitrary rule. * @param mode The mode we are in. Some modes don't allow 'parent'. * @param callback_proc The function that is called where you need to do the filtering. * @param subdir The directory from where to start (global) searching. */ static void FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc *callback_proc, Subdirectory subdir) { struct stat sb; struct dirent *dirent; DIR *dir; FiosItem *fios; int sort_start; char d_name[sizeof(fios->name)]; _fios_items.Clear(); /* A parent directory link exists if we are not in the root directory */ if (!FiosIsRoot(_fios_path)) { fios = _fios_items.Append(); fios->type = FIOS_TYPE_PARENT; fios->mtime = 0; strecpy(fios->name, "..", lastof(fios->name)); strecpy(fios->title, ".. (Parent directory)", lastof(fios->title)); } /* Show subdirectories */ if ((dir = ttd_opendir(_fios_path)) != NULL) { while ((dirent = readdir(dir)) != NULL) { strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name)); /* found file must be directory, but not '.' or '..' */ if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) && (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) && strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) { fios = _fios_items.Append(); fios->type = FIOS_TYPE_DIR; fios->mtime = 0; strecpy(fios->name, d_name, lastof(fios->name)); seprintf(fios->title, lastof(fios->title), "%s" PATHSEP " (Directory)", d_name); str_validate(fios->title, lastof(fios->title)); } } closedir(dir); } /* Sort the subdirs always by name, ascending, remember user-sorting order */ { SortingBits order = _savegame_sort_order; _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING; QSortT(_fios_items.Begin(), _fios_items.Length(), CompareFiosItems); _savegame_sort_order = order; } /* This is where to start sorting for the filenames */ sort_start = _fios_items.Length(); /* Show files */ FiosFileScanner scanner(mode, callback_proc); if (subdir == NO_DIRECTORY) { scanner.Scan(NULL, _fios_path, false); } else { scanner.Scan(NULL, subdir, true, true); } QSortT(_fios_items.Get(sort_start), _fios_items.Length() - sort_start, CompareFiosItems); /* Show drives */ FiosGetDrives(); _fios_items.Compact(); } /** * Get the title of a file, which (if exists) is stored in a file named * the same as the data file but with '.title' added to it. * @param file filename to get the title for * @param title the title buffer to fill * @param last the last element in the title buffer * @param subdir the sub directory to search in */ static void GetFileTitle(const char *file, char *title, const char *last, Subdirectory subdir) { char buf[MAX_PATH]; strecpy(buf, file, lastof(buf)); strecat(buf, ".title", lastof(buf)); FILE *f = FioFOpenFile(buf, "r", subdir); if (f == NULL) return; size_t read = fread(title, 1, last - title, f); assert(title + read <= last); title[read] = '\0'; str_validate(title, last); FioFCloseFile(f); } /** * Callback for FiosGetFileList. It tells if a file is a savegame or not. * @param mode Save/load mode. * @param file Name of the file to check. * @param ext A pointer to the extension identifier inside file * @param title Buffer if a callback wants to lookup the title of the file; NULL to skip the lookup * @param last Last available byte in buffer (to prevent buffer overflows); not used when title == NULL * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a savegame * @see FiosGetFileList * @see FiosGetSavegameList */ FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last) { /* Show savegame files * .SAV OpenTTD saved game * .SS1 Transport Tycoon Deluxe preset game * .SV1 Transport Tycoon Deluxe (Patch) saved game * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */ /* Don't crash if we supply no extension */ if (ext == NULL) return FIOS_TYPE_INVALID; if (strcasecmp(ext, ".sav") == 0) { GetFileTitle(file, title, last, SAVE_DIR); return FIOS_TYPE_FILE; } if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) { if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 || strcasecmp(ext, ".sv2") == 0) { if (title != NULL) GetOldSaveGameName(file, title, last); return FIOS_TYPE_OLDFILE; } } return FIOS_TYPE_INVALID; } /** * Get a list of savegames. * @param mode Save/load mode. * @see FiosGetFileList */ void FiosGetSavegameList(SaveLoadDialogMode mode) { static char *fios_save_path = NULL; static char *fios_save_path_last = NULL; if (fios_save_path == NULL) { fios_save_path = MallocT(MAX_PATH); fios_save_path_last = fios_save_path + MAX_PATH - 1; FioGetDirectory(fios_save_path, fios_save_path_last, SAVE_DIR); } _fios_path = fios_save_path; _fios_path_last = fios_save_path_last; FiosGetFileList(mode, &FiosGetSavegameListCallback, NO_DIRECTORY); } /** * Callback for FiosGetFileList. It tells if a file is a scenario or not. * @param mode Save/load mode. * @param file Name of the file to check. * @param ext A pointer to the extension identifier inside file * @param title Buffer if a callback wants to lookup the title of the file * @param last Last available byte in buffer (to prevent buffer overflows) * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a scenario * @see FiosGetFileList * @see FiosGetScenarioList */ static FiosType FiosGetScenarioListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last) { /* Show scenario files * .SCN OpenTTD style scenario file * .SV0 Transport Tycoon Deluxe (Patch) scenario * .SS0 Transport Tycoon Deluxe preset scenario */ if (strcasecmp(ext, ".scn") == 0) { GetFileTitle(file, title, last, SCENARIO_DIR); return FIOS_TYPE_SCENARIO; } if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) { if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) { GetOldSaveGameName(file, title, last); return FIOS_TYPE_OLD_SCENARIO; } } return FIOS_TYPE_INVALID; } /** * Get a list of scenarios. * @param mode Save/load mode. * @see FiosGetFileList */ void FiosGetScenarioList(SaveLoadDialogMode mode) { static char *fios_scn_path = NULL; static char *fios_scn_path_last = NULL; /* Copy the default path on first run or on 'New Game' */ if (fios_scn_path == NULL) { fios_scn_path = MallocT(MAX_PATH); fios_scn_path_last = fios_scn_path + MAX_PATH - 1; FioGetDirectory(fios_scn_path, fios_scn_path_last, SCENARIO_DIR); } _fios_path = fios_scn_path; _fios_path_last = fios_scn_path_last; char base_path[MAX_PATH]; FioGetDirectory(base_path, lastof(base_path), SCENARIO_DIR); FiosGetFileList(mode, &FiosGetScenarioListCallback, (mode == SLD_LOAD_SCENARIO && strcmp(base_path, _fios_path) == 0) ? SCENARIO_DIR : NO_DIRECTORY); } static FiosType FiosGetHeightmapListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last) { /* Show heightmap files * .PNG PNG Based heightmap files * .BMP BMP Based heightmap files */ FiosType type = FIOS_TYPE_INVALID; #ifdef WITH_PNG if (strcasecmp(ext, ".png") == 0) type = FIOS_TYPE_PNG; #endif /* WITH_PNG */ if (strcasecmp(ext, ".bmp") == 0) type = FIOS_TYPE_BMP; if (type == FIOS_TYPE_INVALID) return FIOS_TYPE_INVALID; TarFileList::iterator it = _tar_filelist[SCENARIO_DIR].find(file); if (it != _tar_filelist[SCENARIO_DIR].end()) { /* If the file is in a tar and that tar is not in a heightmap * directory we are for sure not supposed to see it. * Examples of this are pngs part of documentation within * collections of NewGRFs or 32 bpp graphics replacement PNGs. */ bool match = false; Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { char buf[MAX_PATH]; FioAppendDirectory(buf, lastof(buf), sp, HEIGHTMAP_DIR); if (strncmp(buf, it->second.tar_filename, strlen(buf)) == 0) { match = true; break; } } if (!match) return FIOS_TYPE_INVALID; } GetFileTitle(file, title, last, HEIGHTMAP_DIR); return type; } /** * Get a list of heightmaps. * @param mode Save/load mode. */ void FiosGetHeightmapList(SaveLoadDialogMode mode) { static char *fios_hmap_path = NULL; static char *fios_hmap_path_last = NULL; if (fios_hmap_path == NULL) { fios_hmap_path = MallocT(MAX_PATH); fios_hmap_path_last = fios_hmap_path + MAX_PATH - 1; FioGetDirectory(fios_hmap_path, fios_hmap_path_last, HEIGHTMAP_DIR); } _fios_path = fios_hmap_path; _fios_path_last = fios_hmap_path_last; char base_path[MAX_PATH]; FioGetDirectory(base_path, lastof(base_path), HEIGHTMAP_DIR); FiosGetFileList(mode, &FiosGetHeightmapListCallback, strcmp(base_path, _fios_path) == 0 ? HEIGHTMAP_DIR : NO_DIRECTORY); } /** * Get the directory for screenshots. * @return path to screenshots */ const char *FiosGetScreenshotDir() { static char *fios_screenshot_path = NULL; if (fios_screenshot_path == NULL) { fios_screenshot_path = MallocT(MAX_PATH); FioGetDirectory(fios_screenshot_path, fios_screenshot_path + MAX_PATH - 1, SCREENSHOT_DIR); } return fios_screenshot_path; } #if defined(ENABLE_NETWORK) #include "network/network_content.h" #include "3rdparty/md5/md5.h" /** Basic data to distinguish a scenario. Used in the server list window */ struct ScenarioIdentifier { uint32 scenid; ///< ID for the scenario (generated by content). uint8 md5sum[16]; ///< MD5 checksum of file. char filename[MAX_PATH]; ///< filename of the file. bool operator == (const ScenarioIdentifier &other) const { return this->scenid == other.scenid && memcmp(this->md5sum, other.md5sum, sizeof(this->md5sum)) == 0; } bool operator != (const ScenarioIdentifier &other) const { return !(*this == other); } }; /** * Scanner to find the unique IDs of scenarios */ class ScenarioScanner : protected FileScanner, public SmallVector { bool scanned; ///< Whether we've already scanned public: /** Initialise */ ScenarioScanner() : scanned(false) {} /** * Scan, but only if it's needed. * @param rescan whether to force scanning even when it's not necessary */ void Scan(bool rescan) { if (this->scanned && !rescan) return; this->FileScanner::Scan(".id", SCENARIO_DIR, true, true); this->scanned = true; } /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { FILE *f = FioFOpenFile(filename, "r", SCENARIO_DIR); if (f == NULL) return false; ScenarioIdentifier id; int fret = fscanf(f, "%i", &id.scenid); FioFCloseFile(f); if (fret != 1) return false; strecpy(id.filename, filename, lastof(id.filename)); Md5 checksum; uint8 buffer[1024]; char basename[MAX_PATH]; ///< \a filename without the extension. size_t len, size; /* open the scenario file, but first get the name. * This is safe as we check on extension which * must always exist. */ strecpy(basename, filename, lastof(basename)); *strrchr(basename, '.') = '\0'; f = FioFOpenFile(basename, "rb", SCENARIO_DIR, &size); if (f == NULL) return false; /* calculate md5sum */ while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { size -= len; checksum.Append(buffer, len); } checksum.Finish(id.md5sum); FioFCloseFile(f); this->Include(id); return true; } }; /** Scanner for scenarios */ static ScenarioScanner _scanner; /** * Find a given scenario based on its unique ID. * @param ci The content info to compare it to. * @param md5sum Whether to look at the md5sum or the id. * @return The filename of the file, else \c NULL. */ const char *FindScenario(const ContentInfo *ci, bool md5sum) { _scanner.Scan(false); for (ScenarioIdentifier *id = _scanner.Begin(); id != _scanner.End(); id++) { if (md5sum ? (memcmp(id->md5sum, ci->md5sum, sizeof(id->md5sum)) == 0) : (id->scenid == ci->unique_id)) { return id->filename; } } return NULL; } /** * Check whether we've got a given scenario based on its unique ID. * @param ci The content info to compare it to. * @param md5sum Whether to look at the md5sum or the id. * @return True iff we've got the scenario. */ bool HasScenario(const ContentInfo *ci, bool md5sum) { return (FindScenario(ci, md5sum) != NULL); } /** * Force a (re)scan of the scenarios. */ void ScanScenarios() { _scanner.Scan(true); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/station_map.h0000644000000000000000000004516712627373446015204 0ustar rootroot/* $Id: station_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 station_map.h Maps accessors for stations. */ #ifndef STATION_MAP_H #define STATION_MAP_H #include "rail_map.h" #include "road_map.h" #include "water_map.h" #include "station_func.h" #include "rail.h" typedef byte StationGfx; ///< Index of station graphics. @see _station_display_datas /** * Get StationID from a tile * @param t Tile to query station ID from * @pre IsTileType(t, MP_STATION) * @return Station ID of the station at \a t */ static inline StationID GetStationIndex(TileIndex t) { assert(IsTileType(t, MP_STATION)); return (StationID)_m[t].m2; } static const int GFX_DOCK_BASE_WATER_PART = 4; ///< The offset for the water parts. static const int GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET = 4; ///< The offset for the drive through parts. /** * Get the station type of this tile * @param t the tile to query * @pre IsTileType(t, MP_STATION) * @return the station type */ static inline StationType GetStationType(TileIndex t) { assert(IsTileType(t, MP_STATION)); return (StationType)GB(_me[t].m6, 3, 3); } /** * Get the road stop type of this tile * @param t the tile to query * @pre GetStationType(t) == STATION_TRUCK || GetStationType(t) == STATION_BUS * @return the road stop type */ static inline RoadStopType GetRoadStopType(TileIndex t) { assert(GetStationType(t) == STATION_TRUCK || GetStationType(t) == STATION_BUS); return GetStationType(t) == STATION_TRUCK ? ROADSTOP_TRUCK : ROADSTOP_BUS; } /** * Get the station graphics of this tile * @param t the tile to query * @pre IsTileType(t, MP_STATION) * @return the station graphics */ static inline StationGfx GetStationGfx(TileIndex t) { assert(IsTileType(t, MP_STATION)); return _m[t].m5; } /** * Set the station graphics of this tile * @param t the tile to update * @param gfx the new graphics * @pre IsTileType(t, MP_STATION) */ static inline void SetStationGfx(TileIndex t, StationGfx gfx) { assert(IsTileType(t, MP_STATION)); _m[t].m5 = gfx; } /** * Is this station tile a rail station? * @param t the tile to get the information from * @pre IsTileType(t, MP_STATION) * @return true if and only if the tile is a rail station */ static inline bool IsRailStation(TileIndex t) { return GetStationType(t) == STATION_RAIL; } /** * Is this tile a station tile and a rail station? * @param t the tile to get the information from * @return true if and only if the tile is a rail station */ static inline bool IsRailStationTile(TileIndex t) { return IsTileType(t, MP_STATION) && IsRailStation(t); } /** * Is this station tile a rail waypoint? * @param t the tile to get the information from * @pre IsTileType(t, MP_STATION) * @return true if and only if the tile is a rail waypoint */ static inline bool IsRailWaypoint(TileIndex t) { return GetStationType(t) == STATION_WAYPOINT; } /** * Is this tile a station tile and a rail waypoint? * @param t the tile to get the information from * @return true if and only if the tile is a rail waypoint */ static inline bool IsRailWaypointTile(TileIndex t) { return IsTileType(t, MP_STATION) && IsRailWaypoint(t); } /** * Has this station tile a rail? In other words, is this station * tile a rail station or rail waypoint? * @param t the tile to check * @pre IsTileType(t, MP_STATION) * @return true if and only if the tile has rail */ static inline bool HasStationRail(TileIndex t) { return IsRailStation(t) || IsRailWaypoint(t); } /** * Has this station tile a rail? In other words, is this station * tile a rail station or rail waypoint? * @param t the tile to check * @return true if and only if the tile is a station tile and has rail */ static inline bool HasStationTileRail(TileIndex t) { return IsTileType(t, MP_STATION) && HasStationRail(t); } /** * Is this station tile an airport? * @param t the tile to get the information from * @pre IsTileType(t, MP_STATION) * @return true if and only if the tile is an airport */ static inline bool IsAirport(TileIndex t) { return GetStationType(t) == STATION_AIRPORT; } /** * Is this tile a station tile and an airport tile? * @param t the tile to get the information from * @return true if and only if the tile is an airport */ static inline bool IsAirportTile(TileIndex t) { return IsTileType(t, MP_STATION) && IsAirport(t); } bool IsHangar(TileIndex t); /** * Is the station at \a t a truck stop? * @param t Tile to check * @pre IsTileType(t, MP_STATION) * @return \c true if station is a truck stop, \c false otherwise */ static inline bool IsTruckStop(TileIndex t) { return GetStationType(t) == STATION_TRUCK; } /** * Is the station at \a t a bus stop? * @param t Tile to check * @pre IsTileType(t, MP_STATION) * @return \c true if station is a bus stop, \c false otherwise */ static inline bool IsBusStop(TileIndex t) { return GetStationType(t) == STATION_BUS; } /** * Is the station at \a t a road station? * @param t Tile to check * @pre IsTileType(t, MP_STATION) * @return \c true if station at the tile is a bus top or a truck stop, \c false otherwise */ static inline bool IsRoadStop(TileIndex t) { assert(IsTileType(t, MP_STATION)); return IsTruckStop(t) || IsBusStop(t); } /** * Is tile \a t a road stop station? * @param t Tile to check * @return \c true if the tile is a station tile and a road stop */ static inline bool IsRoadStopTile(TileIndex t) { return IsTileType(t, MP_STATION) && IsRoadStop(t); } /** * Is tile \a t a standard (non-drive through) road stop station? * @param t Tile to check * @return \c true if the tile is a station tile and a standard road stop */ static inline bool IsStandardRoadStopTile(TileIndex t) { return IsRoadStopTile(t) && GetStationGfx(t) < GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET; } /** * Is tile \a t a drive through road stop station? * @param t Tile to check * @return \c true if the tile is a station tile and a drive through road stop */ static inline bool IsDriveThroughStopTile(TileIndex t) { return IsRoadStopTile(t) && GetStationGfx(t) >= GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET; } /** * Get the station graphics of this airport tile * @param t the tile to query * @pre IsAirport(t) * @return the station graphics */ static inline StationGfx GetAirportGfx(TileIndex t) { assert(IsAirport(t)); extern StationGfx GetTranslatedAirportTileID(StationGfx gfx); return GetTranslatedAirportTileID(GetStationGfx(t)); } /** * Gets the direction the road stop entrance points towards. * @param t the tile of the road stop * @pre IsRoadStopTile(t) * @return the direction of the entrance */ static inline DiagDirection GetRoadStopDir(TileIndex t) { StationGfx gfx = GetStationGfx(t); assert(IsRoadStopTile(t)); if (gfx < GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET) { return (DiagDirection)(gfx); } else { return (DiagDirection)(gfx - GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET); } } /** * Is tile \a t part of an oilrig? * @param t Tile to check * @pre IsTileType(t, MP_STATION) * @return \c true if the tile is an oilrig tile */ static inline bool IsOilRig(TileIndex t) { return GetStationType(t) == STATION_OILRIG; } /** * Is tile \a t a dock tile? * @param t Tile to check * @pre IsTileType(t, MP_STATION) * @return \c true if the tile is a dock */ static inline bool IsDock(TileIndex t) { return GetStationType(t) == STATION_DOCK; } /** * Is tile \a t a dock tile? * @param t Tile to check * @return \c true if the tile is a dock */ static inline bool IsDockTile(TileIndex t) { return IsTileType(t, MP_STATION) && GetStationType(t) == STATION_DOCK; } /** * Is tile \a t a buoy tile? * @param t Tile to check * @pre IsTileType(t, MP_STATION) * @return \c true if the tile is a buoy */ static inline bool IsBuoy(TileIndex t) { return GetStationType(t) == STATION_BUOY; } /** * Is tile \a t a buoy tile? * @param t Tile to check * @return \c true if the tile is a buoy */ static inline bool IsBuoyTile(TileIndex t) { return IsTileType(t, MP_STATION) && IsBuoy(t); } /** * Is tile \a t an hangar tile? * @param t Tile to check * @return \c true if the tile is an hangar */ static inline bool IsHangarTile(TileIndex t) { return IsTileType(t, MP_STATION) && IsHangar(t); } /** * Get the rail direction of a rail station. * @param t Tile to query * @pre HasStationRail(t) * @return The direction of the rails on tile \a t. */ static inline Axis GetRailStationAxis(TileIndex t) { assert(HasStationRail(t)); return HasBit(GetStationGfx(t), 0) ? AXIS_Y : AXIS_X; } /** * Get the rail track of a rail station tile. * @param t Tile to query * @pre HasStationRail(t) * @return The rail track of the rails on tile \a t. */ static inline Track GetRailStationTrack(TileIndex t) { return AxisToTrack(GetRailStationAxis(t)); } /** * Get the trackbits of a rail station tile. * @param t Tile to query * @pre HasStationRail(t) * @return The trackbits of the rails on tile \a t. */ static inline TrackBits GetRailStationTrackBits(TileIndex t) { return AxisToTrackBits(GetRailStationAxis(t)); } /** * Check if a tile is a valid continuation to a railstation tile. * The tile \a test_tile is a valid continuation to \a station_tile, if all of the following are true: * \li \a test_tile is a rail station tile * \li the railtype of \a test_tile is compatible with the railtype of \a station_tile * \li the tracks on \a test_tile and \a station_tile are in the same direction * \li both tiles belong to the same station * \li \a test_tile is not blocked (@see IsStationTileBlocked) * @param test_tile Tile to test * @param station_tile Station tile to compare with * @pre IsRailStationTile(station_tile) * @return true if the two tiles are compatible */ static inline bool IsCompatibleTrainStationTile(TileIndex test_tile, TileIndex station_tile) { assert(IsRailStationTile(station_tile)); return IsRailStationTile(test_tile) && IsCompatibleRail(GetRailType(test_tile), GetRailType(station_tile)) && GetRailStationAxis(test_tile) == GetRailStationAxis(station_tile) && GetStationIndex(test_tile) == GetStationIndex(station_tile) && !IsStationTileBlocked(test_tile); } /** * Get the reservation state of the rail station * @pre HasStationRail(t) * @param t the station tile * @return reservation state */ static inline bool HasStationReservation(TileIndex t) { assert(HasStationRail(t)); return HasBit(_me[t].m6, 2); } /** * Set the reservation state of the rail station * @pre HasStationRail(t) * @param t the station tile * @param b the reservation state */ static inline void SetRailStationReservation(TileIndex t, bool b) { assert(HasStationRail(t)); SB(_me[t].m6, 2, 1, b ? 1 : 0); } /** * Get the reserved track bits for a waypoint * @pre HasStationRail(t) * @param t the tile * @return reserved track bits */ static inline TrackBits GetStationReservationTrackBits(TileIndex t) { return HasStationReservation(t) ? GetRailStationTrackBits(t) : TRACK_BIT_NONE; } /** * Get the direction of a dock. * @param t Tile to query * @pre IsDock(t) * @pre \a t is the land part of the dock * @return The direction of the dock on tile \a t. */ static inline DiagDirection GetDockDirection(TileIndex t) { StationGfx gfx = GetStationGfx(t); assert(IsDock(t) && gfx < GFX_DOCK_BASE_WATER_PART); return (DiagDirection)(gfx); } /** * Get the tileoffset from this tile a ship should target to get to this dock. * @param t Tile to query * @pre IsTileType(t, MP_STATION) * @pre IsBuoy(t) || IsOilRig(t) || IsDock(t) * @return The offset from this tile that should be used as destination for ships. */ static inline TileIndexDiffC GetDockOffset(TileIndex t) { static const TileIndexDiffC buoy_offset = {0, 0}; static const TileIndexDiffC oilrig_offset = {2, 0}; static const TileIndexDiffC dock_offset[DIAGDIR_END] = { {-2, 0}, { 0, 2}, { 2, 0}, { 0, -2}, }; assert(IsTileType(t, MP_STATION)); if (IsBuoy(t)) return buoy_offset; if (IsOilRig(t)) return oilrig_offset; assert(IsDock(t)); return dock_offset[GetDockDirection(t)]; } /** * Is there a custom rail station spec on this tile? * @param t Tile to query * @pre HasStationTileRail(t) * @return True if this station is part of a newgrf station. */ static inline bool IsCustomStationSpecIndex(TileIndex t) { assert(HasStationTileRail(t)); return _m[t].m4 != 0; } /** * Set the custom station spec for this tile. * @param t Tile to set the stationspec of. * @param specindex The new spec. * @pre HasStationTileRail(t) */ static inline void SetCustomStationSpecIndex(TileIndex t, byte specindex) { assert(HasStationTileRail(t)); _m[t].m4 = specindex; } /** * Get the custom station spec for this tile. * @param t Tile to query * @pre HasStationTileRail(t) * @return The custom station spec of this tile. */ static inline uint GetCustomStationSpecIndex(TileIndex t) { assert(HasStationTileRail(t)); return _m[t].m4; } /** * Set the random bits for a station tile. * @param t Tile to set random bits for. * @param random_bits The random bits. * @pre IsTileType(t, MP_STATION) */ static inline void SetStationTileRandomBits(TileIndex t, byte random_bits) { assert(IsTileType(t, MP_STATION)); SB(_m[t].m3, 4, 4, random_bits); } /** * Get the random bits of a station tile. * @param t Tile to query * @pre IsTileType(t, MP_STATION) * @return The random bits for this station tile. */ static inline byte GetStationTileRandomBits(TileIndex t) { assert(IsTileType(t, MP_STATION)); return GB(_m[t].m3, 4, 4); } /** * Make the given tile a station tile. * @param t the tile to make a station tile * @param o the owner of the station * @param sid the station to which this tile belongs * @param st the type this station tile * @param section the StationGfx to be used for this tile * @param wc The water class of the station */ static inline void MakeStation(TileIndex t, Owner o, StationID sid, StationType st, byte section, WaterClass wc = WATER_CLASS_INVALID) { SetTileType(t, MP_STATION); SetTileOwner(t, o); SetWaterClass(t, wc); _m[t].m2 = sid; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = section; SB(_me[t].m6, 2, 1, 0); SB(_me[t].m6, 3, 3, st); _me[t].m7 = 0; } /** * Make the given tile a rail station tile. * @param t the tile to make a rail station tile * @param o the owner of the station * @param sid the station to which this tile belongs * @param a the axis of this tile * @param section the StationGfx to be used for this tile * @param rt the railtype of this tile */ static inline void MakeRailStation(TileIndex t, Owner o, StationID sid, Axis a, byte section, RailType rt) { MakeStation(t, o, sid, STATION_RAIL, section + a); SetRailType(t, rt); SetRailStationReservation(t, false); } /** * Make the given tile a rail waypoint tile. * @param t the tile to make a rail waypoint * @param o the owner of the waypoint * @param sid the waypoint to which this tile belongs * @param a the axis of this tile * @param section the StationGfx to be used for this tile * @param rt the railtype of this tile */ static inline void MakeRailWaypoint(TileIndex t, Owner o, StationID sid, Axis a, byte section, RailType rt) { MakeStation(t, o, sid, STATION_WAYPOINT, section + a); SetRailType(t, rt); SetRailStationReservation(t, false); } /** * Make the given tile a roadstop tile. * @param t the tile to make a roadstop * @param o the owner of the roadstop * @param sid the station to which this tile belongs * @param rst the type of roadstop to make this tile * @param rt the roadtypes on this tile * @param d the direction of the roadstop */ static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopType rst, RoadTypes rt, DiagDirection d) { MakeStation(t, o, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), d); SetRoadTypes(t, rt); SetRoadOwner(t, ROADTYPE_ROAD, o); SetRoadOwner(t, ROADTYPE_TRAM, o); } /** * Make the given tile a drivethrough roadstop tile. * @param t the tile to make a roadstop * @param station the owner of the roadstop * @param road the owner of the road * @param tram the owner of the tram * @param sid the station to which this tile belongs * @param rst the type of roadstop to make this tile * @param rt the roadtypes on this tile * @param a the direction of the roadstop */ static inline void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, RoadStopType rst, RoadTypes rt, Axis a) { MakeStation(t, station, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + a); SetRoadTypes(t, rt); SetRoadOwner(t, ROADTYPE_ROAD, road); SetRoadOwner(t, ROADTYPE_TRAM, tram); } /** * Make the given tile an airport tile. * @param t the tile to make a airport * @param o the owner of the airport * @param sid the station to which this tile belongs * @param section the StationGfx to be used for this tile * @param wc the type of water on this tile */ static inline void MakeAirport(TileIndex t, Owner o, StationID sid, byte section, WaterClass wc) { MakeStation(t, o, sid, STATION_AIRPORT, section, wc); } /** * Make the given tile a buoy tile. * @param t the tile to make a buoy * @param sid the station to which this tile belongs * @param wc the type of water on this tile */ static inline void MakeBuoy(TileIndex t, StationID sid, WaterClass wc) { /* Make the owner of the buoy tile the same as the current owner of the * water tile. In this way, we can reset the owner of the water to its * original state when the buoy gets removed. */ MakeStation(t, GetTileOwner(t), sid, STATION_BUOY, 0, wc); } /** * Make the given tile a dock tile. * @param t the tile to make a dock * @param o the owner of the dock * @param sid the station to which this tile belongs * @param d the direction of the dock * @param wc the type of water on this tile */ static inline void MakeDock(TileIndex t, Owner o, StationID sid, DiagDirection d, WaterClass wc) { MakeStation(t, o, sid, STATION_DOCK, d); MakeStation(t + TileOffsByDiagDir(d), o, sid, STATION_DOCK, GFX_DOCK_BASE_WATER_PART + DiagDirToAxis(d), wc); } /** * Make the given tile an oilrig tile. * @param t the tile to make an oilrig * @param sid the station to which this tile belongs * @param wc the type of water on this tile */ static inline void MakeOilrig(TileIndex t, StationID sid, WaterClass wc) { MakeStation(t, OWNER_NONE, sid, STATION_OILRIG, 0, wc); } #endif /* STATION_MAP_H */ openttd-1.5.3/src/autoreplace_cmd.cpp0000644000000000000000000007527112627373435016345 0ustar rootroot/* $Id: autoreplace_cmd.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 autoreplace_cmd.cpp Deals with autoreplace execution but not the setup */ #include "stdafx.h" #include "company_func.h" #include "train.h" #include "command_func.h" #include "engine_func.h" #include "vehicle_func.h" #include "autoreplace_func.h" #include "autoreplace_gui.h" #include "articulated_vehicles.h" #include "core/random_func.hpp" #include "table/strings.h" #include "safeguards.h" extern void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index); extern void ChangeVehicleNews(VehicleID from_index, VehicleID to_index); extern void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index); /** * Figure out if two engines got at least one type of cargo in common (refitting if needed) * @param engine_a one of the EngineIDs * @param engine_b the other EngineID * @param type the type of the engines * @return true if they can both carry the same type of cargo (or at least one of them got no capacity at all) */ static bool EnginesHaveCargoInCommon(EngineID engine_a, EngineID engine_b) { uint32 available_cargoes_a = GetUnionOfArticulatedRefitMasks(engine_a, true); uint32 available_cargoes_b = GetUnionOfArticulatedRefitMasks(engine_b, true); return (available_cargoes_a == 0 || available_cargoes_b == 0 || (available_cargoes_a & available_cargoes_b) != 0); } /** * Checks some basic properties whether autoreplace is allowed * @param from Origin engine * @param to Destination engine * @param company Company to check for * @return true if autoreplace is allowed */ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company) { assert(Engine::IsValidID(from) && Engine::IsValidID(to)); /* we can't replace an engine into itself (that would be autorenew) */ if (from == to) return false; const Engine *e_from = Engine::Get(from); const Engine *e_to = Engine::Get(to); VehicleType type = e_from->type; /* check that the new vehicle type is available to the company and its type is the same as the original one */ if (!IsEngineBuildable(to, type, company)) return false; switch (type) { case VEH_TRAIN: { /* make sure the railtypes are compatible */ if ((GetRailTypeInfo(e_from->u.rail.railtype)->compatible_railtypes & GetRailTypeInfo(e_to->u.rail.railtype)->compatible_railtypes) == 0) return false; /* make sure we do not replace wagons with engines or vice versa */ if ((e_from->u.rail.railveh_type == RAILVEH_WAGON) != (e_to->u.rail.railveh_type == RAILVEH_WAGON)) return false; break; } case VEH_ROAD: /* make sure that we do not replace a tram with a normal road vehicles or vice versa */ if (HasBit(e_from->info.misc_flags, EF_ROAD_TRAM) != HasBit(e_to->info.misc_flags, EF_ROAD_TRAM)) return false; break; case VEH_AIRCRAFT: /* make sure that we do not replace a plane with a helicopter or vice versa */ if ((e_from->u.air.subtype & AIR_CTOL) != (e_to->u.air.subtype & AIR_CTOL)) return false; break; default: break; } /* the engines needs to be able to carry the same cargo */ return EnginesHaveCargoInCommon(from, to); } /** * Check the capacity of all vehicles in a chain and spread cargo if needed. * @param v The vehicle to check. * @pre You can only do this if the consist is not loading or unloading. It * must not carry reserved cargo, nor cargo to be unloaded or transferred. */ void CheckCargoCapacity(Vehicle *v) { assert(v == NULL || v->First() == v); for (Vehicle *src = v; src != NULL; src = src->Next()) { assert(src->cargo.TotalCount() == src->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); /* Do we need to more cargo away? */ if (src->cargo.TotalCount() <= src->cargo_cap) continue; /* We need to move a particular amount. Try that on the other vehicles. */ uint to_spread = src->cargo.TotalCount() - src->cargo_cap; for (Vehicle *dest = v; dest != NULL && to_spread != 0; dest = dest->Next()) { assert(dest->cargo.TotalCount() == dest->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); if (dest->cargo.TotalCount() >= dest->cargo_cap || dest->cargo_type != src->cargo_type) continue; uint amount = min(to_spread, dest->cargo_cap - dest->cargo.TotalCount()); src->cargo.Shift(amount, &dest->cargo); to_spread -= amount; } /* Any left-overs will be thrown away, but not their feeder share. */ if (src->cargo_cap < src->cargo.TotalCount()) src->cargo.Truncate(src->cargo.TotalCount() - src->cargo_cap); } } /** * Transfer cargo from a single (articulated )old vehicle to the new vehicle chain * @param old_veh Old vehicle that will be sold * @param new_head Head of the completely constructed new vehicle chain * @param part_of_chain The vehicle is part of a train * @pre You can only do this if both consists are not loading or unloading. * They must not carry reserved cargo, nor cargo to be unloaded or * transferred. */ static void TransferCargo(Vehicle *old_veh, Vehicle *new_head, bool part_of_chain) { assert(!part_of_chain || new_head->IsPrimaryVehicle()); /* Loop through source parts */ for (Vehicle *src = old_veh; src != NULL; src = src->Next()) { assert(src->cargo.TotalCount() == src->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); if (!part_of_chain && src->type == VEH_TRAIN && src != old_veh && src != Train::From(old_veh)->other_multiheaded_part && !src->IsArticulatedPart()) { /* Skip vehicles, which do not belong to old_veh */ src = src->GetLastEnginePart(); continue; } if (src->cargo_type >= NUM_CARGO || src->cargo.TotalCount() == 0) continue; /* Find free space in the new chain */ for (Vehicle *dest = new_head; dest != NULL && src->cargo.TotalCount() > 0; dest = dest->Next()) { assert(dest->cargo.TotalCount() == dest->cargo.ActionCount(VehicleCargoList::MTA_KEEP)); if (!part_of_chain && dest->type == VEH_TRAIN && dest != new_head && dest != Train::From(new_head)->other_multiheaded_part && !dest->IsArticulatedPart()) { /* Skip vehicles, which do not belong to new_head */ dest = dest->GetLastEnginePart(); continue; } if (dest->cargo_type != src->cargo_type) continue; uint amount = min(src->cargo.TotalCount(), dest->cargo_cap - dest->cargo.TotalCount()); if (amount <= 0) continue; src->cargo.Shift(amount, &dest->cargo); } } /* Update train weight etc., the old vehicle will be sold anyway */ if (part_of_chain && new_head->type == VEH_TRAIN) Train::From(new_head)->ConsistChanged(CCF_LOADUNLOAD); } /** * Tests whether refit orders that applied to v will also apply to the new vehicle type * @param v The vehicle to be replaced * @param engine_type The type we want to replace with * @return true iff all refit orders stay valid */ static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_type) { uint32 union_refit_mask_a = GetUnionOfArticulatedRefitMasks(v->engine_type, false); uint32 union_refit_mask_b = GetUnionOfArticulatedRefitMasks(engine_type, false); const Order *o; const Vehicle *u = (v->type == VEH_TRAIN) ? v->First() : v; FOR_VEHICLE_ORDERS(u, o) { if (!o->IsRefit() || o->IsAutoRefit()) continue; CargoID cargo_type = o->GetRefitCargo(); if (!HasBit(union_refit_mask_a, cargo_type)) continue; if (!HasBit(union_refit_mask_b, cargo_type)) return false; } return true; } /** * Function to find what type of cargo to refit to when autoreplacing * @param *v Original vehicle that is being replaced. * @param engine_type The EngineID of the vehicle that is being replaced to * @param part_of_chain The vehicle is part of a train * @return The cargo type to replace to * CT_NO_REFIT is returned if no refit is needed * CT_INVALID is returned when both old and new vehicle got cargo capacity and refitting the new one to the old one's cargo type isn't possible */ static CargoID GetNewCargoTypeForReplace(Vehicle *v, EngineID engine_type, bool part_of_chain) { uint32 available_cargo_types, union_mask; GetArticulatedRefitMasks(engine_type, true, &union_mask, &available_cargo_types); if (union_mask == 0) return CT_NO_REFIT; // Don't try to refit an engine with no cargo capacity CargoID cargo_type; if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) return CT_INVALID; // We cannot refit to mixed cargoes in an automated way if (cargo_type == CT_INVALID) { if (v->type != VEH_TRAIN) return CT_NO_REFIT; // If the vehicle does not carry anything at all, every replacement is fine. if (!part_of_chain) return CT_NO_REFIT; /* the old engine didn't have cargo capacity, but the new one does * now we will figure out what cargo the train is carrying and refit to fit this */ for (v = v->First(); v != NULL; v = v->Next()) { if (!v->GetEngine()->CanCarryCargo()) continue; /* Now we found a cargo type being carried on the train and we will see if it is possible to carry to this one */ if (HasBit(available_cargo_types, v->cargo_type)) return v->cargo_type; } return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one } else { if (!HasBit(available_cargo_types, cargo_type)) return CT_INVALID; // We can't refit the vehicle to carry the cargo we want if (part_of_chain && !VerifyAutoreplaceRefitForOrders(v, engine_type)) return CT_INVALID; // Some refit orders lose their effect return cargo_type; } } /** * Get the EngineID of the replacement for a vehicle * @param v The vehicle to find a replacement for * @param c The vehicle's owner (it's faster to forward the pointer than refinding it) * @param always_replace Always replace, even if not old. * @param [out] e the EngineID of the replacement. INVALID_ENGINE if no replacement is found * @return Error if the engine to build is not available */ static CommandCost GetNewEngineType(const Vehicle *v, const Company *c, bool always_replace, EngineID &e) { assert(v->type != VEH_TRAIN || !v->IsArticulatedPart()); e = INVALID_ENGINE; if (v->type == VEH_TRAIN && Train::From(v)->IsRearDualheaded()) { /* we build the rear ends of multiheaded trains with the front ones */ return CommandCost(); } bool replace_when_old; e = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old); if (!always_replace && replace_when_old && !v->NeedsAutorenewing(c, false)) e = INVALID_ENGINE; /* Autoreplace, if engine is available */ if (e != INVALID_ENGINE && IsEngineBuildable(e, v->type, _current_company)) { return CommandCost(); } /* Autorenew if needed */ if (v->NeedsAutorenewing(c)) e = v->engine_type; /* Nothing to do or all is fine? */ if (e == INVALID_ENGINE || IsEngineBuildable(e, v->type, _current_company)) return CommandCost(); /* The engine we need is not available. Report error to user */ return CommandCost(STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE + v->type); } /** * Builds and refits a replacement vehicle * Important: The old vehicle is still in the original vehicle chain (used for determining the cargo when the old vehicle did not carry anything, but the new one does) * @param old_veh A single (articulated/multiheaded) vehicle that shall be replaced. * @param new_vehicle Returns the newly build and refitted vehicle * @param part_of_chain The vehicle is part of a train * @return cost or error */ static CommandCost BuildReplacementVehicle(Vehicle *old_veh, Vehicle **new_vehicle, bool part_of_chain) { *new_vehicle = NULL; /* Shall the vehicle be replaced? */ const Company *c = Company::Get(_current_company); EngineID e; CommandCost cost = GetNewEngineType(old_veh, c, true, e); if (cost.Failed()) return cost; if (e == INVALID_ENGINE) return CommandCost(); // neither autoreplace is set, nor autorenew is triggered /* Does it need to be refitted */ CargoID refit_cargo = GetNewCargoTypeForReplace(old_veh, e, part_of_chain); if (refit_cargo == CT_INVALID) return CommandCost(); // incompatible cargoes /* Build the new vehicle */ cost = DoCommand(old_veh->tile, e, 0, DC_EXEC | DC_AUTOREPLACE, GetCmdBuildVeh(old_veh)); if (cost.Failed()) return cost; Vehicle *new_veh = Vehicle::Get(_new_vehicle_id); *new_vehicle = new_veh; /* Refit the vehicle if needed */ if (refit_cargo != CT_NO_REFIT) { byte subtype = GetBestFittingSubType(old_veh, new_veh, refit_cargo); cost.AddCost(DoCommand(0, new_veh->index, refit_cargo | (subtype << 8), DC_EXEC, GetCmdRefitVeh(new_veh))); assert(cost.Succeeded()); // This should be ensured by GetNewCargoTypeForReplace() } /* Try to reverse the vehicle, but do not care if it fails as the new type might not be reversible */ if (new_veh->type == VEH_TRAIN && HasBit(Train::From(old_veh)->flags, VRF_REVERSE_DIRECTION)) { DoCommand(0, new_veh->index, true, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); } return cost; } /** * Issue a start/stop command * @param v a vehicle * @param evaluate_callback shall the start/stop callback be evaluated? * @return success or error */ static inline CommandCost CmdStartStopVehicle(const Vehicle *v, bool evaluate_callback) { return DoCommand(0, v->index, evaluate_callback ? 1 : 0, DC_EXEC | DC_AUTOREPLACE, CMD_START_STOP_VEHICLE); } /** * Issue a train vehicle move command * @param v The vehicle to move * @param after The vehicle to insert 'v' after, or NULL to start new chain * @param flags the command flags to use * @param whole_chain move all vehicles following 'v' (true), or only 'v' (false) * @return success or error */ static inline CommandCost CmdMoveVehicle(const Vehicle *v, const Vehicle *after, DoCommandFlag flags, bool whole_chain) { return DoCommand(0, v->index | (whole_chain ? 1 : 0) << 20, after != NULL ? after->index : INVALID_VEHICLE, flags | DC_NO_CARGO_CAP_CHECK, CMD_MOVE_RAIL_VEHICLE); } /** * Copy head specific things to the new vehicle chain after it was successfully constructed * @param old_head The old front vehicle (no wagons attached anymore) * @param new_head The new head of the completely replaced vehicle chain * @param flags the command flags to use */ static CommandCost CopyHeadSpecificThings(Vehicle *old_head, Vehicle *new_head, DoCommandFlag flags) { CommandCost cost = CommandCost(); /* Share orders */ if (cost.Succeeded() && old_head != new_head) cost.AddCost(DoCommand(0, new_head->index | CO_SHARE << 30, old_head->index, DC_EXEC, CMD_CLONE_ORDER)); /* Copy group membership */ if (cost.Succeeded() && old_head != new_head) cost.AddCost(DoCommand(0, old_head->group_id, new_head->index, DC_EXEC, CMD_ADD_VEHICLE_GROUP)); /* Perform start/stop check whether the new vehicle suits newgrf restrictions etc. */ if (cost.Succeeded()) { /* Start the vehicle, might be denied by certain things */ assert((new_head->vehstatus & VS_STOPPED) != 0); cost.AddCost(CmdStartStopVehicle(new_head, true)); /* Stop the vehicle again, but do not care about evil newgrfs allowing starting but not stopping :p */ if (cost.Succeeded()) cost.AddCost(CmdStartStopVehicle(new_head, false)); } /* Last do those things which do never fail (resp. we do not care about), but which are not undo-able */ if (cost.Succeeded() && old_head != new_head && (flags & DC_EXEC) != 0) { /* Copy other things which cannot be copied by a command and which shall not stay resetted from the build vehicle command */ new_head->CopyVehicleConfigAndStatistics(old_head); /* Switch vehicle windows/news to the new vehicle, so they are not closed/deleted when the old vehicle is sold */ ChangeVehicleViewports(old_head->index, new_head->index); ChangeVehicleViewWindow(old_head->index, new_head->index); ChangeVehicleNews(old_head->index, new_head->index); } return cost; } /** * Replace a single unit in a free wagon chain * @param single_unit vehicle to let autoreplace/renew operator on * @param flags command flags * @param nothing_to_do is set to 'false' when something was done (only valid when not failed) * @return cost or error */ static CommandCost ReplaceFreeUnit(Vehicle **single_unit, DoCommandFlag flags, bool *nothing_to_do) { Train *old_v = Train::From(*single_unit); assert(!old_v->IsArticulatedPart() && !old_v->IsRearDualheaded()); CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); /* Build and refit replacement vehicle */ Vehicle *new_v = NULL; cost.AddCost(BuildReplacementVehicle(old_v, &new_v, false)); /* Was a new vehicle constructed? */ if (cost.Succeeded() && new_v != NULL) { *nothing_to_do = false; if ((flags & DC_EXEC) != 0) { /* Move the new vehicle behind the old */ CmdMoveVehicle(new_v, old_v, DC_EXEC, false); /* Take over cargo * Note: We do only transfer cargo from the old to the new vehicle. * I.e. we do not transfer remaining cargo to other vehicles. * Else you would also need to consider moving cargo to other free chains, * or doing the same in ReplaceChain(), which would be quite troublesome. */ TransferCargo(old_v, new_v, false); *single_unit = new_v; } /* Sell the old vehicle */ cost.AddCost(DoCommand(0, old_v->index, 0, flags, GetCmdSellVeh(old_v))); /* If we are not in DC_EXEC undo everything */ if ((flags & DC_EXEC) == 0) { DoCommand(0, new_v->index, 0, DC_EXEC, GetCmdSellVeh(new_v)); } } return cost; } /** * Replace a whole vehicle chain * @param chain vehicle chain to let autoreplace/renew operator on * @param flags command flags * @param wagon_removal remove wagons when the resulting chain occupies more tiles than the old did * @param nothing_to_do is set to 'false' when something was done (only valid when not failed) * @return cost or error */ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon_removal, bool *nothing_to_do) { Vehicle *old_head = *chain; assert(old_head->IsPrimaryVehicle()); CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); if (old_head->type == VEH_TRAIN) { /* Store the length of the old vehicle chain, rounded up to whole tiles */ uint16 old_total_length = CeilDiv(Train::From(old_head)->gcache.cached_total_length, TILE_SIZE) * TILE_SIZE; int num_units = 0; ///< Number of units in the chain for (Train *w = Train::From(old_head); w != NULL; w = w->GetNextUnit()) num_units++; Train **old_vehs = CallocT(num_units); ///< Will store vehicles of the old chain in their order Train **new_vehs = CallocT(num_units); ///< New vehicles corresponding to old_vehs or NULL if no replacement Money *new_costs = MallocT(num_units); ///< Costs for buying and refitting the new vehicles /* Collect vehicles and build replacements * Note: The replacement vehicles can only successfully build as long as the old vehicles are still in their chain */ int i; Train *w; for (w = Train::From(old_head), i = 0; w != NULL; w = w->GetNextUnit(), i++) { assert(i < num_units); old_vehs[i] = w; CommandCost ret = BuildReplacementVehicle(old_vehs[i], (Vehicle**)&new_vehs[i], true); cost.AddCost(ret); if (cost.Failed()) break; new_costs[i] = ret.GetCost(); if (new_vehs[i] != NULL) *nothing_to_do = false; } Train *new_head = (new_vehs[0] != NULL ? new_vehs[0] : old_vehs[0]); /* Note: When autoreplace has already failed here, old_vehs[] is not completely initialized. But it is also not needed. */ if (cost.Succeeded()) { /* Separate the head, so we can start constructing the new chain */ Train *second = Train::From(old_head)->GetNextUnit(); if (second != NULL) cost.AddCost(CmdMoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true)); assert(Train::From(new_head)->GetNextUnit() == NULL); /* Append engines to the new chain * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time. * That way we also have less trouble when exceeding the unitnumber limit. * OTOH the vehicle attach callback is more expensive this way :s */ Train *last_engine = NULL; ///< Shall store the last engine unit after this step if (cost.Succeeded()) { for (int i = num_units - 1; i > 0; i--) { Train *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]); if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) continue; if (new_vehs[i] != NULL) { /* Move the old engine to a separate row with DC_AUTOREPLACE. Else * moving the wagon in front may fail later due to unitnumber limit. * (We have to attach wagons without DC_AUTOREPLACE.) */ CmdMoveVehicle(old_vehs[i], NULL, DC_EXEC | DC_AUTOREPLACE, false); } if (last_engine == NULL) last_engine = append; cost.AddCost(CmdMoveVehicle(append, new_head, DC_EXEC, false)); if (cost.Failed()) break; } if (last_engine == NULL) last_engine = new_head; } /* When wagon removal is enabled and the new engines without any wagons are already longer than the old, we have to fail */ if (cost.Succeeded() && wagon_removal && new_head->gcache.cached_total_length > old_total_length) cost = CommandCost(STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT); /* Append/insert wagons into the new vehicle chain * We do this from back to front, so we can stop when wagon removal or maximum train length (i.e. from mammoth-train setting) is triggered. */ if (cost.Succeeded()) { for (int i = num_units - 1; i > 0; i--) { assert(last_engine != NULL); Vehicle *append = (new_vehs[i] != NULL ? new_vehs[i] : old_vehs[i]); if (RailVehInfo(append->engine_type)->railveh_type == RAILVEH_WAGON) { /* Insert wagon after 'last_engine' */ CommandCost res = CmdMoveVehicle(append, last_engine, DC_EXEC, false); /* When we allow removal of wagons, either the move failing due * to the train becoming too long, or the train becoming longer * would move the vehicle to the empty vehicle chain. */ if (wagon_removal && (res.Failed() ? res.GetErrorMessage() == STR_ERROR_TRAIN_TOO_LONG : new_head->gcache.cached_total_length > old_total_length)) { CmdMoveVehicle(append, NULL, DC_EXEC | DC_AUTOREPLACE, false); break; } cost.AddCost(res); if (cost.Failed()) break; } else { /* We have reached 'last_engine', continue with the next engine towards the front */ assert(append == last_engine); last_engine = last_engine->GetPrevUnit(); } } } /* Sell superfluous new vehicles that could not be inserted. */ if (cost.Succeeded() && wagon_removal) { assert(new_head->gcache.cached_total_length <= _settings_game.vehicle.max_train_length * TILE_SIZE); for (int i = 1; i < num_units; i++) { Vehicle *wagon = new_vehs[i]; if (wagon == NULL) continue; if (wagon->First() == new_head) break; assert(RailVehInfo(wagon->engine_type)->railveh_type == RAILVEH_WAGON); /* Sell wagon */ CommandCost ret = DoCommand(0, wagon->index, 0, DC_EXEC, GetCmdSellVeh(wagon)); assert(ret.Succeeded()); new_vehs[i] = NULL; /* Revert the money subtraction when the vehicle was built. * This value is different from the sell value, esp. because of refitting */ cost.AddCost(-new_costs[i]); } } /* The new vehicle chain is constructed, now take over orders and everything... */ if (cost.Succeeded()) cost.AddCost(CopyHeadSpecificThings(old_head, new_head, flags)); if (cost.Succeeded()) { /* Success ! */ if ((flags & DC_EXEC) != 0 && new_head != old_head) { *chain = new_head; } /* Transfer cargo of old vehicles and sell them */ for (int i = 0; i < num_units; i++) { Vehicle *w = old_vehs[i]; /* Is the vehicle again part of the new chain? * Note: We cannot test 'new_vehs[i] != NULL' as wagon removal might cause to remove both */ if (w->First() == new_head) continue; if ((flags & DC_EXEC) != 0) TransferCargo(w, new_head, true); /* Sell the vehicle. * Note: This might temporarly construct new trains, so use DC_AUTOREPLACE to prevent * it from failing due to engine limits. */ cost.AddCost(DoCommand(0, w->index, 0, flags | DC_AUTOREPLACE, GetCmdSellVeh(w))); if ((flags & DC_EXEC) != 0) { old_vehs[i] = NULL; if (i == 0) old_head = NULL; } } if ((flags & DC_EXEC) != 0) CheckCargoCapacity(new_head); } /* If we are not in DC_EXEC undo everything, i.e. rearrange old vehicles. * We do this from back to front, so that the head of the temporary vehicle chain does not change all the time. * Note: The vehicle attach callback is disabled here :) */ if ((flags & DC_EXEC) == 0) { /* Separate the head, so we can reattach the old vehicles */ Train *second = Train::From(old_head)->GetNextUnit(); if (second != NULL) CmdMoveVehicle(second, NULL, DC_EXEC | DC_AUTOREPLACE, true); assert(Train::From(old_head)->GetNextUnit() == NULL); for (int i = num_units - 1; i > 0; i--) { CommandCost ret = CmdMoveVehicle(old_vehs[i], old_head, DC_EXEC | DC_AUTOREPLACE, false); assert(ret.Succeeded()); } } } /* Finally undo buying of new vehicles */ if ((flags & DC_EXEC) == 0) { for (int i = num_units - 1; i >= 0; i--) { if (new_vehs[i] != NULL) { DoCommand(0, new_vehs[i]->index, 0, DC_EXEC, GetCmdSellVeh(new_vehs[i])); new_vehs[i] = NULL; } } } free(old_vehs); free(new_vehs); free(new_costs); } else { /* Build and refit replacement vehicle */ Vehicle *new_head = NULL; cost.AddCost(BuildReplacementVehicle(old_head, &new_head, true)); /* Was a new vehicle constructed? */ if (cost.Succeeded() && new_head != NULL) { *nothing_to_do = false; /* The new vehicle is constructed, now take over orders and everything... */ cost.AddCost(CopyHeadSpecificThings(old_head, new_head, flags)); if (cost.Succeeded()) { /* The new vehicle is constructed, now take over cargo */ if ((flags & DC_EXEC) != 0) { TransferCargo(old_head, new_head, true); *chain = new_head; } /* Sell the old vehicle */ cost.AddCost(DoCommand(0, old_head->index, 0, flags, GetCmdSellVeh(old_head))); } /* If we are not in DC_EXEC undo everything */ if ((flags & DC_EXEC) == 0) { DoCommand(0, new_head->index, 0, DC_EXEC, GetCmdSellVeh(new_head)); } } } return cost; } /** * Autoreplaces a vehicle * Trains are replaced as a whole chain, free wagons in depot are replaced on their own * @param tile not used * @param flags type of operation * @param p1 Index of vehicle * @param p2 not used * @param text unused * @return the cost of this operation or an error */ CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (!v->IsChainInDepot()) return CMD_ERROR; if (v->vehstatus & VS_CRASHED) return CMD_ERROR; bool free_wagon = false; if (v->type == VEH_TRAIN) { Train *t = Train::From(v); if (t->IsArticulatedPart() || t->IsRearDualheaded()) return CMD_ERROR; free_wagon = !t->IsFrontEngine(); if (free_wagon && t->First()->IsFrontEngine()) return CMD_ERROR; } else { if (!v->IsPrimaryVehicle()) return CMD_ERROR; } const Company *c = Company::Get(_current_company); bool wagon_removal = c->settings.renew_keep_length; /* Test whether any replacement is set, before issuing a whole lot of commands that would end in nothing changed */ Vehicle *w = v; bool any_replacements = false; while (w != NULL) { EngineID e; CommandCost cost = GetNewEngineType(w, c, false, e); if (cost.Failed()) return cost; any_replacements |= (e != INVALID_ENGINE); w = (!free_wagon && w->type == VEH_TRAIN ? Train::From(w)->GetNextUnit() : NULL); } CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0); bool nothing_to_do = true; if (any_replacements) { bool was_stopped = free_wagon || ((v->vehstatus & VS_STOPPED) != 0); /* Stop the vehicle */ if (!was_stopped) cost.AddCost(CmdStartStopVehicle(v, true)); if (cost.Failed()) return cost; assert(free_wagon || v->IsStoppedInDepot()); /* We have to construct the new vehicle chain to test whether it is valid. * Vehicle construction needs random bits, so we have to save the random seeds * to prevent desyncs and to replay newgrf callbacks during DC_EXEC */ SavedRandomSeeds saved_seeds; SaveRandomSeeds(&saved_seeds); if (free_wagon) { cost.AddCost(ReplaceFreeUnit(&v, flags & ~DC_EXEC, ¬hing_to_do)); } else { cost.AddCost(ReplaceChain(&v, flags & ~DC_EXEC, wagon_removal, ¬hing_to_do)); } RestoreRandomSeeds(saved_seeds); if (cost.Succeeded() && (flags & DC_EXEC) != 0) { CommandCost ret; if (free_wagon) { ret = ReplaceFreeUnit(&v, flags, ¬hing_to_do); } else { ret = ReplaceChain(&v, flags, wagon_removal, ¬hing_to_do); } assert(ret.Succeeded() && ret.GetCost() == cost.GetCost()); } /* Restart the vehicle */ if (!was_stopped) cost.AddCost(CmdStartStopVehicle(v, false)); } if (cost.Succeeded() && nothing_to_do) cost = CommandCost(STR_ERROR_AUTOREPLACE_NOTHING_TO_DO); return cost; } /** * Change engine renewal parameters * @param tile unused * @param flags operation to perform * @param p1 packed data * - bit 0 = replace when engine gets old? * - bits 16-31 = engine group * @param p2 packed data * - bits 0-15 = old engine type * - bits 16-31 = new engine type * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSetAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Company *c = Company::GetIfValid(_current_company); if (c == NULL) return CMD_ERROR; EngineID old_engine_type = GB(p2, 0, 16); EngineID new_engine_type = GB(p2, 16, 16); GroupID id_g = GB(p1, 16, 16); CommandCost cost; if (Group::IsValidID(id_g) ? Group::Get(id_g)->owner != _current_company : !IsAllGroupID(id_g) && !IsDefaultGroupID(id_g)) return CMD_ERROR; if (!Engine::IsValidID(old_engine_type)) return CMD_ERROR; if (new_engine_type != INVALID_ENGINE) { if (!Engine::IsValidID(new_engine_type)) return CMD_ERROR; if (!CheckAutoreplaceValidity(old_engine_type, new_engine_type, _current_company)) return CMD_ERROR; cost = AddEngineReplacementForCompany(c, old_engine_type, new_engine_type, id_g, HasBit(p1, 0), flags); } else { cost = RemoveEngineReplacementForCompany(c, old_engine_type, id_g, flags); } if (flags & DC_EXEC) { GroupStatistics::UpdateAutoreplace(_current_company); if (IsLocalCompany()) SetWindowDirty(WC_REPLACE_VEHICLE, Engine::Get(old_engine_type)->type); } if ((flags & DC_EXEC) && IsLocalCompany()) InvalidateAutoreplaceWindow(old_engine_type, id_g); return cost; } openttd-1.5.3/src/openttd.h0000644000000000000000000000633612627373435014334 0ustar rootroot/* $Id: openttd.h 25506 2013-06-28 21:11:35Z rubidium $ */ /* * 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 openttd.h Some generic types. */ #ifndef OPENTTD_H #define OPENTTD_H #include "core/enum_type.hpp" /** Mode which defines the state of the game. */ enum GameMode { GM_MENU, GM_NORMAL, GM_EDITOR, GM_BOOTSTRAP }; /** Mode which defines what mode we're switching to. */ enum SwitchMode { SM_NONE, SM_NEWGAME, ///< New Game --> 'Random game'. SM_RESTARTGAME, ///< Restart --> 'Random game' with current settings. SM_EDITOR, ///< Switch to scenario editor. SM_LOAD_GAME, ///< Load game, Play Scenario. SM_MENU, ///< Switch to game intro menu. SM_SAVE_GAME, ///< Save game. SM_SAVE_HEIGHTMAP, ///< Save heightmap. SM_GENRANDLAND, ///< Generate random land within scenario editor. SM_LOAD_SCENARIO, ///< Load scenario from scenario editor. SM_START_HEIGHTMAP, ///< Load a heightmap and start a new game from it. SM_LOAD_HEIGHTMAP, ///< Load heightmap from scenario editor. }; /** Display Options */ enum DisplayOptions { DO_SHOW_TOWN_NAMES = 0, ///< Display town names. DO_SHOW_STATION_NAMES = 1, ///< Display station names. DO_SHOW_SIGNS = 2, ///< Display signs. DO_FULL_ANIMATION = 3, ///< Perform palette animation. DO_FULL_DETAIL = 5, ///< Also draw details of track and roads. DO_SHOW_WAYPOINT_NAMES = 6, ///< Display waypoint names. DO_SHOW_COMPETITOR_SIGNS = 7, ///< Display signs, station names and waypoint names of opponent companies. Buoys and oilrig-stations are always shown, even if this option is turned off. }; extern GameMode _game_mode; extern SwitchMode _switch_mode; extern bool _exit_game; /** Modes of pausing we've got */ enum PauseMode { PM_UNPAUSED = 0, ///< A normal unpaused game PM_PAUSED_NORMAL = 1 << 0, ///< A game normally paused PM_PAUSED_SAVELOAD = 1 << 1, ///< A game paused for saving/loading PM_PAUSED_JOIN = 1 << 2, ///< A game paused for 'pause_on_join' PM_PAUSED_ERROR = 1 << 3, ///< A game paused because a (critical) error PM_PAUSED_ACTIVE_CLIENTS = 1 << 4, ///< A game paused for 'min_active_clients' PM_PAUSED_GAME_SCRIPT = 1 << 5, ///< A game paused by a game script /** Pause mode bits when paused for network reasons. */ PMB_PAUSED_NETWORK = PM_PAUSED_ACTIVE_CLIENTS | PM_PAUSED_JOIN, }; DECLARE_ENUM_AS_BIT_SET(PauseMode) typedef SimpleTinyEnumT PauseModeByte; /** The current pause mode */ extern PauseModeByte _pause_mode; void AskExitGame(); void AskExitToGameMenu(); int openttd_main(int argc, char *argv[]); void HandleExitGameRequest(); void SwitchToMode(SwitchMode new_mode); #endif /* OPENTTD_H */ openttd-1.5.3/src/toolbar_gui.h0000644000000000000000000000157112627373442015157 0ustar rootroot/* $Id: toolbar_gui.h 27146 2015-02-13 21:13:45Z frosch $ */ /* * 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 toolbar_gui.h Stuff related to the (main) toolbar. */ #ifndef TOOLBAR_GUI_H #define TOOLBAR_GUI_H void AllocateToolbar(); void ToggleBoundingBoxes(); void ToggleDirtyBlocks(); extern uint _toolbar_width; #endif /* TOOLBAR_GUI_H */ openttd-1.5.3/src/rail_gui.h0000644000000000000000000000205712627373441014443 0ustar rootroot/* $Id: rail_gui.h 21867 2011-01-20 12:40:04Z rubidium $ */ /* * 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 rail_gui.h Functions/types etc. related to the rail GUI. */ #ifndef RAIL_GUI_H #define RAIL_GUI_H #include "rail_type.h" #include "widgets/dropdown_type.h" struct Window *ShowBuildRailToolbar(RailType railtype); void ReinitGuiAfterToggleElrail(bool disable); bool ResetSignalVariant(int32 = 0); void InitializeRailGUI(); DropDownList *GetRailTypeDropDownList(bool for_replacement = false); #endif /* RAIL_GUI_H */ openttd-1.5.3/src/vehicle_gui_base.h0000644000000000000000000000433712627373441016130 0ustar rootroot/* $Id: vehicle_gui_base.h 25287 2013-05-26 19:23:42Z frosch $ */ /* * 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 vehicle_gui_base.h Functions/classes shared between the different vehicle list GUIs. */ #ifndef VEHICLE_GUI_BASE_H #define VEHICLE_GUI_BASE_H #include "sortlist_type.h" #include "vehiclelist.h" #include "window_gui.h" #include "widgets/dropdown_type.h" typedef GUIList GUIVehicleList; struct BaseVehicleListWindow : public Window { GUIVehicleList vehicles; ///< The list of vehicles Listing *sorting; ///< Pointer to the vehicle type related sorting. byte unitnumber_digits; ///< The number of digits of the highest unit number Scrollbar *vscroll; VehicleListIdentifier vli; ///< Identifier of the vehicle list we want to currently show. enum ActionDropdownItem { ADI_REPLACE, ADI_SERVICE, ADI_DEPOT, ADI_ADD_SHARED, ADI_REMOVE_ALL, }; static const StringID vehicle_depot_name[]; static const StringID vehicle_sorter_names[]; static GUIVehicleList::SortFunction * const vehicle_sorter_funcs[]; BaseVehicleListWindow(WindowDesc *desc, WindowNumber wno) : Window(desc), vli(wno) { this->vehicles.SetSortFuncs(this->vehicle_sorter_funcs); } void DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const; void SortVehicleList(); void BuildVehicleList(); Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group); DropDownList *BuildActionDropdownList(bool show_autoreplace, bool show_group); }; uint GetVehicleListHeight(VehicleType type, uint divisor = 1); struct Sorting { Listing aircraft; Listing roadveh; Listing ship; Listing train; }; extern Sorting _sorting; #endif /* VEHICLE_GUI_BASE_H */ openttd-1.5.3/src/strings_type.h0000644000000000000000000000550612627373435015407 0ustar rootroot/* $Id: strings_type.h 26525 2014-04-27 15:13:46Z frosch $ */ /* * 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 strings_type.h Types related to strings. */ #ifndef STRINGS_TYPE_H #define STRINGS_TYPE_H /** * Numeric value that represents a string, independent of the selected language. */ typedef uint16 StringID; static const StringID INVALID_STRING_ID = 0xFFFF; ///< Constant representing an invalid string static const int MAX_CHAR_LENGTH = 4; ///< Max. length of UTF-8 encoded unicode character static const uint MAX_LANG = 0x7F; ///< Maximum number of languages supported by the game, and the NewGRF specs /** Directions a text can go to */ enum TextDirection { TD_LTR, ///< Text is written left-to-right by default TD_RTL, ///< Text is written right-to-left by default }; /** Special string constants */ enum SpecialStrings { /* special strings for town names. the town name is generated dynamically on request. */ SPECSTR_TOWNNAME_START = 0x20C0, SPECSTR_TOWNNAME_ENGLISH = SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_FRENCH, SPECSTR_TOWNNAME_GERMAN, SPECSTR_TOWNNAME_AMERICAN, SPECSTR_TOWNNAME_LATIN, SPECSTR_TOWNNAME_SILLY, SPECSTR_TOWNNAME_SWEDISH, SPECSTR_TOWNNAME_DUTCH, SPECSTR_TOWNNAME_FINNISH, SPECSTR_TOWNNAME_POLISH, SPECSTR_TOWNNAME_SLOVAK, SPECSTR_TOWNNAME_NORWEGIAN, SPECSTR_TOWNNAME_HUNGARIAN, SPECSTR_TOWNNAME_AUSTRIAN, SPECSTR_TOWNNAME_ROMANIAN, SPECSTR_TOWNNAME_CZECH, SPECSTR_TOWNNAME_SWISS, SPECSTR_TOWNNAME_DANISH, SPECSTR_TOWNNAME_TURKISH, SPECSTR_TOWNNAME_ITALIAN, SPECSTR_TOWNNAME_CATALAN, SPECSTR_TOWNNAME_LAST = SPECSTR_TOWNNAME_CATALAN, /* special strings for company names on the form "TownName transport". */ SPECSTR_COMPANY_NAME_START = 0x70EA, SPECSTR_COMPANY_NAME_LAST = SPECSTR_COMPANY_NAME_START + SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START, SPECSTR_SILLY_NAME = 0x70E5, SPECSTR_ANDCO_NAME = 0x70E6, SPECSTR_PRESIDENT_NAME = 0x70E7, /* reserve MAX_LANG strings for the *.lng files */ SPECSTR_LANGUAGE_START = 0x7100, SPECSTR_LANGUAGE_END = SPECSTR_LANGUAGE_START + MAX_LANG - 1, /* reserve 32 strings for various screen resolutions */ SPECSTR_RESOLUTION_START = SPECSTR_LANGUAGE_END + 1, SPECSTR_RESOLUTION_END = SPECSTR_RESOLUTION_START + 0x1F, }; #endif /* STRINGS_TYPE_H */ openttd-1.5.3/src/newgrf_debug.h0000644000000000000000000000351112627373441015302 0ustar rootroot/* $Id: newgrf_debug.h 25946 2013-11-07 18:17:21Z frosch $ */ /* * 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 newgrf_debug.h Functions/types related to NewGRF debugging. */ #ifndef NEWGRF_DEBUG_H #define NEWGRF_DEBUG_H #include "newgrf.h" #include "core/smallvec_type.hpp" #include "tile_type.h" #include "vehicle_type.h" /** Current state of spritepicker */ enum NewGrfDebugSpritePickerMode { SPM_NONE, SPM_WAIT_CLICK, SPM_REDRAW, }; /** Spritepicker of SpriteAligner */ struct NewGrfDebugSpritePicker { NewGrfDebugSpritePickerMode mode; ///< Current state void *clicked_pixel; ///< Clicked pixel (pointer to blitter buffer) uint32 click_time; ///< Realtime tick when clicked to detect next frame SmallVector sprites; ///< Sprites found }; extern NewGrfDebugSpritePicker _newgrf_debug_sprite_picker; bool IsNewGRFInspectable(GrfSpecFeature feature, uint index); void ShowNewGRFInspectWindow(GrfSpecFeature feature, uint index, const uint32 grfid = 0); void InvalidateNewGRFInspectWindow(GrfSpecFeature feature, uint index); void DeleteNewGRFInspectWindow(GrfSpecFeature feature, uint index); GrfSpecFeature GetGrfSpecFeature(TileIndex tile); GrfSpecFeature GetGrfSpecFeature(VehicleType type); void ShowSpriteAlignerWindow(); #endif /* NEWGRF_DEBUG_H */ openttd-1.5.3/src/news_func.h0000644000000000000000000000520312627373442014634 0ustar rootroot/* $Id: news_func.h 24845 2012-12-23 21:08:42Z frosch $ */ /* * 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 news_func.h Functions related to news. */ #ifndef NEWS_FUNC_H #define NEWS_FUNC_H #include "news_type.h" #include "vehicle_type.h" #include "station_type.h" #include "industry_type.h" void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1 = NR_NONE, uint32 ref1 = UINT32_MAX, NewsReferenceType reftype2 = NR_NONE, uint32 ref2 = UINT32_MAX, void *free_data = NULL); static inline void AddCompanyNewsItem(StringID string, CompanyNewsInformation *cni) { AddNewsItem(string, NT_COMPANY_INFO, NF_COMPANY, NR_NONE, UINT32_MAX, NR_NONE, UINT32_MAX, cni); } /** * Adds a newsitem referencing a vehicle. * * @warning The DParams may not reference the vehicle due to autoreplace stuff. See AddVehicleAdviceNewsItem for how that can be done. */ static inline void AddVehicleNewsItem(StringID string, NewsType type, VehicleID vehicle, StationID station = INVALID_STATION) { AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_VEHICLE, vehicle, station == INVALID_STATION ? NR_NONE : NR_STATION, station); } /** * Adds a vehicle-advice news item. * * @warning DParam 0 must reference the vehicle! */ static inline void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle) { AddNewsItem(string, NT_ADVICE, NF_INCOLOUR | NF_SMALL | NF_VEHICLE_PARAM0, NR_VEHICLE, vehicle); } static inline void AddTileNewsItem(StringID string, NewsType type, TileIndex tile, void *free_data = NULL) { AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_TILE, tile, NR_NONE, UINT32_MAX, free_data); } static inline void AddIndustryNewsItem(StringID string, NewsType type, IndustryID industry) { AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_INDUSTRY, industry); } void NewsLoop(); void InitNewsItemStructs(); extern const NewsItem *_statusbar_news_item; void DeleteInvalidEngineNews(); void DeleteVehicleNews(VehicleID vid, StringID news); void DeleteStationNews(StationID sid); void DeleteIndustryNews(IndustryID iid); #endif /* NEWS_FUNC_H */ openttd-1.5.3/src/progress.h0000644000000000000000000000236212627373446014520 0ustar rootroot/* $Id: progress.h 22820 2011-08-24 12:18:53Z rubidium $ */ /* * 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 progress.h Functions related to modal progress. */ #ifndef PROGRESS_H #define PROGRESS_H #include "thread/thread.h" static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws /** * Check if we are currently in a modal progress state. * @return Are we in the modal state? */ static inline bool HasModalProgress() { extern bool _in_modal_progress; return _in_modal_progress; } bool IsFirstModalProgressLoop(); void SetModalProgress(bool state); extern class ThreadMutex *_modal_progress_work_mutex; extern class ThreadMutex *_modal_progress_paint_mutex; #endif /* PROGRESS_H */ openttd-1.5.3/src/signs_cmd.cpp0000644000000000000000000001015212627373442015145 0ustar rootroot/* $Id: signs_cmd.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 signs_cmd.cpp Handling of sign related commands. */ #include "stdafx.h" #include "landscape.h" #include "company_func.h" #include "signs_base.h" #include "signs_func.h" #include "command_func.h" #include "tilehighlight_func.h" #include "window_func.h" #include "string_func.h" #include "table/strings.h" #include "safeguards.h" /** The last built sign. */ SignID _new_sign_id; /** * Place a sign at the given coordinates. Ownership of sign has * no effect whatsoever except for the colour the sign gets for easy recognition, * but everybody is able to rename/remove it. * @param tile tile to place sign at * @param flags type of operation * @param p1 unused * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdPlaceSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* Try to locate a new sign */ if (!Sign::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_SIGNS); /* Check sign text length if any */ if (!StrEmpty(text) && Utf8StringLength(text) >= MAX_LENGTH_SIGN_NAME_CHARS) return CMD_ERROR; /* When we execute, really make the sign */ if (flags & DC_EXEC) { Sign *si = new Sign(_game_mode == GM_EDITOR ? OWNER_DEITY : _current_company); int x = TileX(tile) * TILE_SIZE; int y = TileY(tile) * TILE_SIZE; si->x = x; si->y = y; si->z = GetSlopePixelZ(x, y); if (!StrEmpty(text)) { si->name = stredup(text); } si->UpdateVirtCoord(); InvalidateWindowData(WC_SIGN_LIST, 0, 0); _new_sign_id = si->index; } return CommandCost(); } /** * Rename a sign. If the new name of the sign is empty, we assume * the user wanted to delete it. So delete it. Ownership of signs * has no meaning/effect whatsoever except for eyecandy * @param tile unused * @param flags type of operation * @param p1 index of the sign to be renamed/removed * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Sign *si = Sign::GetIfValid(p1); if (si == NULL) return CMD_ERROR; if (si->owner == OWNER_DEITY && _current_company != OWNER_DEITY && _game_mode != GM_EDITOR) return CMD_ERROR; /* Rename the signs when empty, otherwise remove it */ if (!StrEmpty(text)) { if (Utf8StringLength(text) >= MAX_LENGTH_SIGN_NAME_CHARS) return CMD_ERROR; if (flags & DC_EXEC) { /* Delete the old name */ free(si->name); /* Assign the new one */ si->name = stredup(text); if (_game_mode != GM_EDITOR) si->owner = _current_company; si->UpdateVirtCoord(); InvalidateWindowData(WC_SIGN_LIST, 0, 1); } } else { // Delete sign if (flags & DC_EXEC) { si->sign.MarkDirty(); delete si; InvalidateWindowData(WC_SIGN_LIST, 0, 0); } } return CommandCost(); } /** * Callback function that is called after a sign is placed * @param result of the operation * @param tile unused * @param p1 unused * @param p2 unused */ void CcPlaceSign(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; ShowRenameSignWindow(Sign::Get(_new_sign_id)); ResetObjectToPlace(); } /** * * PlaceProc function, called when someone pressed the button if the * sign-tool is selected * @param tile on which to place the sign */ void PlaceProc_Sign(TileIndex tile) { DoCommandP(tile, 0, 0, CMD_PLACE_SIGN | CMD_MSG(STR_ERROR_CAN_T_PLACE_SIGN_HERE), CcPlaceSign); } openttd-1.5.3/src/window_type.h0000644000000000000000000003473112627373441015224 0ustar rootroot/* $Id: window_type.h 26610 2014-05-24 19:11:20Z alberth $ */ /* * 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 window_type.h Types related to windows */ #ifndef WINDOW_TYPE_H #define WINDOW_TYPE_H /** %Window numbers. */ enum WindowNumberEnum { WN_GAME_OPTIONS_AI = 0, ///< AI settings. WN_GAME_OPTIONS_ABOUT, ///< About window. WN_GAME_OPTIONS_NEWGRF_STATE, ///< NewGRF settings. WN_GAME_OPTIONS_GAME_OPTIONS, ///< Game options. WN_GAME_OPTIONS_GAME_SETTINGS, ///< Game settings. WN_QUERY_STRING = 0, ///< Query string. WN_QUERY_STRING_SIGN, ///< Query string for signs. WN_CONFIRM_POPUP_QUERY = 0, ///< Query popup confirm. WN_CONFIRM_POPUP_QUERY_BOOTSTRAP, ///< Query popup confirm for bootstrap. WN_NETWORK_WINDOW_GAME = 0, ///< Network game window. WN_NETWORK_WINDOW_LOBBY, ///< Network lobby window. WN_NETWORK_WINDOW_CONTENT_LIST, ///< Network content list. WN_NETWORK_WINDOW_START, ///< Network start server. WN_NETWORK_STATUS_WINDOW_JOIN = 0, ///< Network join status. WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD, ///< Network content download status. }; /** %Window classes. */ enum WindowClass { WC_NONE, ///< No window, redirects to WC_MAIN_WINDOW. /** * Main window; %Window numbers: * - 0 = #MainWidgets */ WC_MAIN_WINDOW = WC_NONE, /** * Main toolbar (the long bar at the top); %Window numbers: * - 0 = #ToolbarNormalWidgets * - 0 = #ToolbarEditorWidgets */ WC_MAIN_TOOLBAR, /** * Statusbar (at the bottom of your screen); %Window numbers: * - 0 = #StatusbarWidgets */ WC_STATUS_BAR, /** * Build toolbar; %Window numbers: * - #TRANSPORT_RAIL = #RailToolbarWidgets * - #TRANSPORT_AIR = #AirportToolbarWidgets * - #TRANSPORT_WATER = #DockToolbarWidgets * - #TRANSPORT_ROAD = #RoadToolbarWidgets */ WC_BUILD_TOOLBAR, /** * Scenario build toolbar; %Window numbers: * - #TRANSPORT_WATER = #DockToolbarWidgets * - #TRANSPORT_ROAD = #RoadToolbarWidgets */ WC_SCEN_BUILD_TOOLBAR, /** * Build trees toolbar; %Window numbers: * - 0 = #BuildTreesWidgets */ WC_BUILD_TREES, /** * Transparency toolbar; %Window numbers: * - 0 = #TransparencyToolbarWidgets */ WC_TRANSPARENCY_TOOLBAR, /** * Build signal toolbar; %Window numbers: * - #TRANSPORT_RAIL = #BuildSignalWidgets */ WC_BUILD_SIGNAL, /** * Small map; %Window numbers: * - 0 = #SmallMapWidgets */ WC_SMALLMAP, /** * Error message; %Window numbers: * - 0 = #ErrorMessageWidgets */ WC_ERRMSG, /** * Tooltip window; %Window numbers: * - 0 = #ToolTipsWidgets */ WC_TOOLTIPS, /** * Query string window; %Window numbers: * - #WN_QUERY_STRING = #QueryStringWidgets * - #WN_QUERY_STRING_SIGN = #QueryEditSignWidgets */ WC_QUERY_STRING, /** * Popup with confirm question; %Window numbers: * - #WN_CONFIRM_POPUP_QUERY = #QueryWidgets * - #WN_CONFIRM_POPUP_QUERY_BOOTSTRAP = #BootstrapAskForDownloadWidgets */ WC_CONFIRM_POPUP_QUERY, /** * Popup with a set of buttons, designed to ask the user a question * from a GameScript. %Window numbers: * - uniqueid = #GoalQuestionWidgets */ WC_GOAL_QUESTION, /** * Saveload window; %Window numbers: * - 0 = #SaveLoadWidgets */ WC_SAVELOAD, /** * Land info window; %Window numbers: * - 0 = #LandInfoWidgets */ WC_LAND_INFO, /** * Drop down menu; %Window numbers: * - 0 = #DropdownMenuWidgets */ WC_DROPDOWN_MENU, /** * On Screen Keyboard; %Window numbers: * - 0 = #OnScreenKeyboardWidgets */ WC_OSK, /** * Set date; %Window numbers: * - #VehicleID = #SetDateWidgets */ WC_SET_DATE, /** * AI settings; %Window numbers: * - 0 = #AISettingsWidgets */ WC_AI_SETTINGS, /** * NewGRF parameters; %Window numbers: * - 0 = #NewGRFParametersWidgets */ WC_GRF_PARAMETERS, /** * textfile; %Window numbers: * - 0 = #TextfileWidgets */ WC_TEXTFILE, /** * Town authority; %Window numbers: * - #TownID = #TownAuthorityWidgets */ WC_TOWN_AUTHORITY, /** * Vehicle details; %Window numbers: * - #VehicleID = #VehicleDetailsWidgets */ WC_VEHICLE_DETAILS, /** * Vehicle refit; %Window numbers: * - #VehicleID = #VehicleRefitWidgets */ WC_VEHICLE_REFIT, /** * Vehicle orders; %Window numbers: * - #VehicleID = #OrderWidgets */ WC_VEHICLE_ORDERS, /** * Replace vehicle window; %Window numbers: * - #VehicleType = #ReplaceVehicleWidgets */ WC_REPLACE_VEHICLE, /** * Vehicle timetable; %Window numbers: * - #VehicleID = #VehicleTimetableWidgets */ WC_VEHICLE_TIMETABLE, /** * Company colour selection; %Window numbers: * - #CompanyID = #SelectCompanyLiveryWidgets */ WC_COMPANY_COLOUR, /** * Alter company face window; %Window numbers: * - #CompanyID = #SelectCompanyManagerFaceWidgets */ WC_COMPANY_MANAGER_FACE, /** * Select station (when joining stations); %Window numbers: * - 0 = #JoinStationWidgets */ WC_SELECT_STATION, /** * News window; %Window numbers: * - 0 = #NewsWidgets */ WC_NEWS_WINDOW, /** * Town directory; %Window numbers: * - 0 = #TownDirectoryWidgets */ WC_TOWN_DIRECTORY, /** * Subsidies list; %Window numbers: * - 0 = #SubsidyListWidgets */ WC_SUBSIDIES_LIST, /** * Industry directory; %Window numbers: * - 0 = #IndustryDirectoryWidgets */ WC_INDUSTRY_DIRECTORY, /** * News history list; %Window numbers: * - 0 = #MessageHistoryWidgets */ WC_MESSAGE_HISTORY, /** * Sign list; %Window numbers: * - 0 = #SignListWidgets */ WC_SIGN_LIST, /** * AI list; %Window numbers: * - 0 = #AIListWidgets */ WC_AI_LIST, /** * Goals list; %Window numbers: * - 0 ; #GoalListWidgets */ WC_GOALS_LIST, /** * Story book; %Window numbers: * - CompanyID = #StoryBookWidgets */ WC_STORY_BOOK, /** * Station list; %Window numbers: * - #CompanyID = #StationListWidgets */ WC_STATION_LIST, /** * Trains list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_TRAINS_LIST, /** * Road vehicle list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_ROADVEH_LIST, /** * Ships list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_SHIPS_LIST, /** * Aircraft list; %Window numbers: * - Packed value = #GroupListWidgets / #VehicleListWidgets */ WC_AIRCRAFT_LIST, /** * Town view; %Window numbers: * - #TownID = #TownViewWidgets */ WC_TOWN_VIEW, /** * Vehicle view; %Window numbers: * - #VehicleID = #VehicleViewWidgets */ WC_VEHICLE_VIEW, /** * Station view; %Window numbers: * - #StationID = #StationViewWidgets */ WC_STATION_VIEW, /** * Depot view; %Window numbers: * - #TileIndex = #DepotWidgets */ WC_VEHICLE_DEPOT, /** * Waypoint view; %Window numbers: * - #WaypointID = #WaypointWidgets */ WC_WAYPOINT_VIEW, /** * Industry view; %Window numbers: * - #IndustryID = #IndustryViewWidgets */ WC_INDUSTRY_VIEW, /** * Company view; %Window numbers: * - #CompanyID = #CompanyWidgets */ WC_COMPANY, /** * Build object; %Window numbers: * - 0 = #BuildObjectWidgets */ WC_BUILD_OBJECT, /** * Build vehicle; %Window numbers: * - #VehicleType = #BuildVehicleWidgets * - #TileIndex = #BuildVehicleWidgets */ WC_BUILD_VEHICLE, /** * Build bridge; %Window numbers: * - #TransportType = #BuildBridgeSelectionWidgets */ WC_BUILD_BRIDGE, /** * Build station; %Window numbers: * - #TRANSPORT_AIR = #AirportPickerWidgets * - #TRANSPORT_WATER = #DockToolbarWidgets * - #TRANSPORT_RAIL = #BuildRailStationWidgets */ WC_BUILD_STATION, /** * Build bus station; %Window numbers: * - #TRANSPORT_ROAD = #BuildRoadStationWidgets */ WC_BUS_STATION, /** * Build truck station; %Window numbers: * - #TRANSPORT_ROAD = #BuildRoadStationWidgets */ WC_TRUCK_STATION, /** * Build depot; %Window numbers: * - #TRANSPORT_WATER = #BuildDockDepotWidgets * - #TRANSPORT_RAIL = #BuildRailDepotWidgets * - #TRANSPORT_ROAD = #BuildRoadDepotWidgets */ WC_BUILD_DEPOT, /** * Build waypoint; %Window numbers: * - #TRANSPORT_RAIL = #BuildRailWaypointWidgets */ WC_BUILD_WAYPOINT, /** * Found a town; %Window numbers: * - 0 = #TownFoundingWidgets */ WC_FOUND_TOWN, /** * Build industry; %Window numbers: * - 0 = #DynamicPlaceIndustriesWidgets */ WC_BUILD_INDUSTRY, /** * Select game window; %Window numbers: * - 0 = #SelectGameIntroWidgets */ WC_SELECT_GAME, /** * Landscape generation (in Scenario Editor); %Window numbers: * - 0 = #TerraformToolbarWidgets * - 0 = #EditorTerraformToolbarWidgets */ WC_SCEN_LAND_GEN, /** * Generate landscape (newgame); %Window numbers: * - GLWM_SCENARIO = #CreateScenarioWidgets * - #GenenerateLandscapeWindowMode = #GenerateLandscapeWidgets */ WC_GENERATE_LANDSCAPE, /** * Progress report of landscape generation; %Window numbers: * - 0 = #GenerationProgressWidgets * - 1 = #ScanProgressWidgets */ WC_MODAL_PROGRESS, /** * Network window; %Window numbers: * - #WN_NETWORK_WINDOW_GAME = #NetworkGameWidgets * - #WN_NETWORK_WINDOW_LOBBY = #NetworkLobbyWidgets * - #WN_NETWORK_WINDOW_CONTENT_LIST = #NetworkContentListWidgets * - #WN_NETWORK_WINDOW_START = #NetworkStartServerWidgets */ WC_NETWORK_WINDOW, /** * Client list; %Window numbers: * - 0 = #ClientListWidgets */ WC_CLIENT_LIST, /** * Popup for the client list; %Window numbers: * - #ClientID = #ClientListPopupWidgets */ WC_CLIENT_LIST_POPUP, /** * Network status window; %Window numbers: * - #WN_NETWORK_STATUS_WINDOW_JOIN = #NetworkJoinStatusWidgets * - #WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD = #NetworkContentDownloadStatusWidgets */ WC_NETWORK_STATUS_WINDOW, /** * Chatbox; %Window numbers: * - #DestType = #NetWorkChatWidgets */ WC_SEND_NETWORK_MSG, /** * Company password query; %Window numbers: * - 0 = #NetworkCompanyPasswordWidgets */ WC_COMPANY_PASSWORD_WINDOW, /** * Industry cargoes chain; %Window numbers: * - 0 = #IndustryCargoesWidgets */ WC_INDUSTRY_CARGOES, /** * Legend for graphs; %Window numbers: * - 0 = #GraphLegendWidgets */ WC_GRAPH_LEGEND, /** * Finances of a company; %Window numbers: * - #CompanyID = #CompanyWidgets */ WC_FINANCES, /** * Income graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_INCOME_GRAPH, /** * Operating profit graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_OPERATING_PROFIT, /** * Delivered cargo graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_DELIVERED_CARGO, /** * Performance history graph; %Window numbers: * - 0 = #PerformanceHistoryGraphWidgets */ WC_PERFORMANCE_HISTORY, /** * Company value graph; %Window numbers: * - 0 = #CompanyValueWidgets */ WC_COMPANY_VALUE, /** * Company league window; %Window numbers: * - 0 = #CompanyLeagueWidgets */ WC_COMPANY_LEAGUE, /** * Payment rates graph; %Window numbers: * - 0 = #CargoPaymentRatesWidgets */ WC_PAYMENT_RATES, /** * Performance detail window; %Window numbers: * - 0 = #PerformanceRatingDetailsWidgets */ WC_PERFORMANCE_DETAIL, /** * Company infrastructure overview; %Window numbers: * - #CompanyID = #CompanyInfrastructureWidgets */ WC_COMPANY_INFRASTRUCTURE, /** * Buyout company (merger); %Window numbers: * - #CompanyID = #BuyCompanyWidgets */ WC_BUY_COMPANY, /** * Engine preview window; %Window numbers: * - #EngineID = #EnginePreviewWidgets */ WC_ENGINE_PREVIEW, /** * Music window; %Window numbers: * - 0 = #MusicWidgets */ WC_MUSIC_WINDOW, /** * Music track selection; %Window numbers: * - 0 = MusicTrackSelectionWidgets */ WC_MUSIC_TRACK_SELECTION, /** * Game options window; %Window numbers: * - #WN_GAME_OPTIONS_AI = #AIConfigWidgets * - #WN_GAME_OPTIONS_ABOUT = #AboutWidgets * - #WN_GAME_OPTIONS_NEWGRF_STATE = #NewGRFStateWidgets * - #WN_GAME_OPTIONS_GAME_OPTIONS = #GameOptionsWidgets * - #WN_GAME_OPTIONS_GAME_SETTINGS = #GameSettingsWidgets */ WC_GAME_OPTIONS, /** * Custom currency; %Window numbers: * - 0 = #CustomCurrencyWidgets */ WC_CUSTOM_CURRENCY, /** * Cheat window; %Window numbers: * - 0 = #CheatWidgets */ WC_CHEATS, /** * Extra viewport; %Window numbers: * - Ascending value = #ExtraViewportWidgets */ WC_EXTRA_VIEW_PORT, /** * Console; %Window numbers: * - 0 = #ConsoleWidgets */ WC_CONSOLE, /** * Bootstrap; %Window numbers: * - 0 = #BootstrapBackgroundWidgets */ WC_BOOTSTRAP, /** * Highscore; %Window numbers: * - 0 = #HighscoreWidgets */ WC_HIGHSCORE, /** * Endscreen; %Window numbers: * - 0 = #HighscoreWidgets */ WC_ENDSCREEN, /** * AI debug window; %Window numbers: * - 0 = #AIDebugWidgets */ WC_AI_DEBUG, /** * NewGRF inspect (debug); %Window numbers: * - Packed value = #NewGRFInspectWidgets */ WC_NEWGRF_INSPECT, /** * Sprite aligner (debug); %Window numbers: * - 0 = #SpriteAlignerWidgets */ WC_SPRITE_ALIGNER, /** * Linkgraph legend; %Window numbers: * - 0 = #LinkGraphWidgets */ WC_LINKGRAPH_LEGEND, /** * Save preset; %Window numbers: * - 0 = #SavePresetWidgets */ WC_SAVE_PRESET, WC_INVALID = 0xFFFF, ///< Invalid window. }; /** Data value for #Window::OnInvalidateData() of windows with class #WC_GAME_OPTIONS. */ enum GameOptionsInvalidationData { GOID_DEFAULT = 0, GOID_NEWGRF_RESCANNED, ///< NewGRFs were just rescanned. GOID_NEWGRF_LIST_EDITED, ///< List of active NewGRFs is being edited. GOID_NEWGRF_PRESET_LOADED, ///< A NewGRF preset was picked. }; struct Window; /** Number to differentiate different windows of the same class */ typedef int32 WindowNumber; /** State of handling an event. */ enum EventState { ES_HANDLED, ///< The passed event is handled. ES_NOT_HANDLED, ///< The passed event is not handled. }; #endif /* WINDOW_TYPE_H */ openttd-1.5.3/src/cargotype.cpp0000644000000000000000000001323412627373442015200 0ustar rootroot/* $Id: cargotype.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cargotype.cpp Implementation of cargoes. */ #include "stdafx.h" #include "cargotype.h" #include "newgrf_cargo.h" #include "string_func.h" #include "strings_func.h" #include "core/sort_func.hpp" #include "table/sprites.h" #include "table/strings.h" #include "table/cargo_const.h" #include "safeguards.h" CargoSpec CargoSpec::array[NUM_CARGO]; /** * Bitmask of cargo types available. This includes phony cargoes like regearing cargoes. * Initialized during a call to #SetupCargoForClimate. */ uint32 _cargo_mask; /** * Bitmask of real cargo types available. Phony cargoes like regearing cargoes are excluded. */ uint32 _standard_cargo_mask; /** * Set up the default cargo types for the given landscape type. * @param l Landscape */ void SetupCargoForClimate(LandscapeID l) { assert(l < lengthof(_default_climate_cargo)); /* Reset and disable all cargo types */ memset(CargoSpec::array, 0, sizeof(CargoSpec::array)); for (CargoID i = 0; i < lengthof(CargoSpec::array); i++) { CargoSpec::Get(i)->bitnum = INVALID_CARGO; /* Set defaults for newer properties, which old GRFs do not know */ CargoSpec::Get(i)->multiplier = 0x100; } _cargo_mask = 0; for (CargoID i = 0; i < lengthof(_default_climate_cargo[l]); i++) { CargoLabel cl = _default_climate_cargo[l][i]; /* Bzzt: check if cl is just an index into the cargo table */ if (cl < lengthof(_default_cargo)) { /* Copy the indexed cargo */ CargoSpec *cargo = CargoSpec::Get(i); *cargo = _default_cargo[cl]; if (cargo->bitnum != INVALID_CARGO) SetBit(_cargo_mask, i); continue; } /* Loop through each of the default cargo types to see if * the label matches */ for (uint j = 0; j < lengthof(_default_cargo); j++) { if (_default_cargo[j].label == cl) { *CargoSpec::Get(i) = _default_cargo[j]; /* Populate the available cargo mask */ SetBit(_cargo_mask, i); break; } } } } /** * Get the cargo ID by cargo label. * @param cl Cargo type to get. * @return ID number if the cargo exists, else #CT_INVALID */ CargoID GetCargoIDByLabel(CargoLabel cl) { const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { if (cs->label == cl) return cs->Index(); } /* No matching label was found, so it is invalid */ return CT_INVALID; } /** * Find the CargoID of a 'bitnum' value. * @param bitnum 'bitnum' to find. * @return First CargoID with the given bitnum, or #CT_INVALID if not found or if the provided \a bitnum is invalid. */ CargoID GetCargoIDByBitnum(uint8 bitnum) { if (bitnum == INVALID_CARGO) return CT_INVALID; const CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { if (cs->bitnum == bitnum) return cs->Index(); } /* No matching label was found, so it is invalid */ return CT_INVALID; } /** * Get sprite for showing cargo of this type. * @return Sprite number to use. */ SpriteID CargoSpec::GetCargoIcon() const { SpriteID sprite = this->sprite; if (sprite == 0xFFFF) { /* A value of 0xFFFF indicates we should draw a custom icon */ sprite = GetCustomCargoSprite(this); } if (sprite == 0) sprite = SPR_CARGO_GOODS; return sprite; } const CargoSpec *_sorted_cargo_specs[NUM_CARGO]; ///< Cargo specifications sorted alphabetically by name. uint8 _sorted_cargo_specs_size; ///< Number of cargo specifications stored at the _sorted_cargo_specs array (including special cargoes). uint8 _sorted_standard_cargo_specs_size; ///< Number of standard cargo specifications stored at the _sorted_cargo_specs array. /** Sort cargo specifications by their name. */ static int CDECL CargoSpecNameSorter(const CargoSpec * const *a, const CargoSpec * const *b) { static char a_name[64]; static char b_name[64]; GetString(a_name, (*a)->name, lastof(a_name)); GetString(b_name, (*b)->name, lastof(b_name)); int res = strnatcmp(a_name, b_name); // Sort by name (natural sorting). /* If the names are equal, sort by cargo bitnum. */ return (res != 0) ? res : ((*a)->bitnum - (*b)->bitnum); } /** Sort cargo specifications by their cargo class. */ static int CDECL CargoSpecClassSorter(const CargoSpec * const *a, const CargoSpec * const *b) { int res = ((*b)->classes & CC_PASSENGERS) - ((*a)->classes & CC_PASSENGERS); if (res == 0) { res = ((*b)->classes & CC_MAIL) - ((*a)->classes & CC_MAIL); if (res == 0) { res = ((*a)->classes & CC_SPECIAL) - ((*b)->classes & CC_SPECIAL); if (res == 0) { return CargoSpecNameSorter(a, b); } } } return res; } /** Initialize the list of sorted cargo specifications. */ void InitializeSortedCargoSpecs() { _sorted_cargo_specs_size = 0; const CargoSpec *cargo; /* Add each cargo spec to the list. */ FOR_ALL_CARGOSPECS(cargo) { _sorted_cargo_specs[_sorted_cargo_specs_size] = cargo; _sorted_cargo_specs_size++; } /* Sort cargo specifications by cargo class and name. */ QSortT(_sorted_cargo_specs, _sorted_cargo_specs_size, &CargoSpecClassSorter); _standard_cargo_mask = 0; _sorted_standard_cargo_specs_size = 0; FOR_ALL_SORTED_CARGOSPECS(cargo) { if (cargo->classes & CC_SPECIAL) break; _sorted_standard_cargo_specs_size++; SetBit(_standard_cargo_mask, cargo->Index()); } } openttd-1.5.3/src/cargomonitor.cpp0000644000000000000000000001375212627373442015713 0ustar rootroot/* $Id: cargomonitor.cpp 26685 2014-07-12 17:04:14Z alberth $ */ /* * 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 cargomonitor.cpp Implementation of the cargo transport monitoring. */ #include "stdafx.h" #include "cargomonitor.h" #include "station_base.h" #include "safeguards.h" CargoMonitorMap _cargo_pickups; ///< Map of monitored pick-ups to the amount since last query/activation. CargoMonitorMap _cargo_deliveries; ///< Map of monitored deliveries to the amount since last query/activation. /** * Helper method for #ClearCargoPickupMonitoring and #ClearCargoDeliveryMonitoring. * Clears all monitors that belong to the specified company or all if #INVALID_OWNER * is specified as company. * @param cargo_monitor_map reference to the cargo monitor map to operate on. * @param company company to clear cargo monitors for or #INVALID_OWNER if all cargo monitors should be cleared. */ static void ClearCargoMonitoring(CargoMonitorMap &cargo_monitor_map, CompanyID company = INVALID_OWNER) { if (company == INVALID_OWNER) { cargo_monitor_map.clear(); return; } CargoMonitorMap::iterator next; for (CargoMonitorMap::iterator it = cargo_monitor_map.begin(); it != cargo_monitor_map.end(); it = next) { next = it; next++; if (DecodeMonitorCompany(it->first) == company) { cargo_monitor_map.erase(it); } } } /** * Clear all pick-up cargo monitors. * @param company clear all pick-up monitors for this company or if #INVALID_OWNER * is passed, all pick-up monitors are cleared regardless of company. */ void ClearCargoPickupMonitoring(CompanyID company) { ClearCargoMonitoring(_cargo_pickups, company); } /** * Clear all delivery cargo monitors. * @param company clear all delivery monitors for this company or if #INVALID_OWNER * is passed, all delivery monitors are cleared regardless of company. */ void ClearCargoDeliveryMonitoring(CompanyID company) { ClearCargoMonitoring(_cargo_deliveries, company); } /** * Get and reset the amount associated with a cargo monitor. * @param[in,out] monitor_map Monitoring map to search (and reset for the queried entry). * @param monitor Cargo monitor to query/reset. * @param keep_monitoring After returning from this call, continue monitoring. * @return Amount collected since last query/activation for the monitored combination. */ static int32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bool keep_monitoring) { CargoMonitorMap::iterator iter = monitor_map.find(monitor); if (iter == monitor_map.end()) { if (keep_monitoring) { std::pair p(monitor, 0); monitor_map.insert(p); } return 0; } else { int32 result = iter->second; iter->second = 0; if (!keep_monitoring) monitor_map.erase(iter); return result; } } /** * Get the amount of cargo delivered for the given cargo monitor since activation or last query. * @param monitor Cargo monitor to query. * @param keep_monitoring After returning from this call, continue monitoring. * @return Amount of delivered cargo for the monitored combination. */ int32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring) { return GetAmount(_cargo_deliveries, monitor, keep_monitoring); } /** * Get the amount of cargo picked up for the given cargo monitor since activation or last query. * @param monitor Monitoring number to query. * @param keep_monitoring After returning from this call, continue monitoring. * @return Amount of picked up cargo for the monitored combination. * @note Cargo pick up is counted on final delivery, to prevent users getting credit for picking up cargo without delivering it. */ int32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring) { return GetAmount(_cargo_pickups, monitor, keep_monitoring); } /** * Cargo was delivered to its final destination, update the pickup and delivery maps. * @param cargo_type type of cargo. * @param company company delivering the cargo. * @param amount Amount of cargo delivered. * @param src_type type of \a src. * @param src index of source. * @param st station where the cargo is delivered to. */ void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st) { if (amount == 0) return; if (src != INVALID_SOURCE) { /* Handle pickup update. */ switch (src_type) { case ST_INDUSTRY: { CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, src); CargoMonitorMap::iterator iter = _cargo_pickups.find(num); if (iter != _cargo_pickups.end()) iter->second += amount; break; } case ST_TOWN: { CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, src); CargoMonitorMap::iterator iter = _cargo_pickups.find(num); if (iter != _cargo_pickups.end()) iter->second += amount; break; } default: break; } } /* Handle delivery. * Note that delivery in the right area is sufficient to prevent trouble with neighbouring industries or houses. */ /* Town delivery. */ CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, st->town->index); CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); if (iter != _cargo_deliveries.end()) iter->second += amount; /* Industry delivery. */ for (const Industry * const *ip = st->industries_near.Begin(); ip != st->industries_near.End(); ip++) { CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, (*ip)->index); CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); if (iter != _cargo_deliveries.end()) iter->second += amount; } } openttd-1.5.3/src/autoslope.h0000644000000000000000000000366512627373442014672 0ustar rootroot/* $Id: autoslope.h 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 autoslope.h Functions related to autoslope. */ #ifndef AUTOSLOPE_H #define AUTOSLOPE_H #include "company_func.h" #include "depot_func.h" #include "tile_map.h" /** * Autoslope check for tiles with an entrance on an edge. * E.g. depots and non-drive-through-road-stops. * * The test succeeds if the slope is not steep and at least one corner of the entrance edge is on the TileMaxZ() level. * * @note The test does not check if autoslope is enabled at all. * * @param tile The tile. * @param z_new New TileZ. * @param tileh_new New TileSlope. * @param entrance Entrance edge. * @return true iff terraforming is allowed. */ static inline bool AutoslopeCheckForEntranceEdge(TileIndex tile, int z_new, Slope tileh_new, DiagDirection entrance) { if (GetTileMaxZ(tile) != z_new + GetSlopeMaxZ(tileh_new)) return false; return ((tileh_new == SLOPE_FLAT) || CanBuildDepotByTileh(entrance, tileh_new)); } /** * Tests if autoslope is enabled for _current_company. * * Autoslope is disabled for town/industry construction. * * @return true iff autoslope is enabled. */ static inline bool AutoslopeEnabled() { return (_settings_game.construction.autoslope && (_current_company < MAX_COMPANIES || (_current_company == OWNER_NONE && _game_mode == GM_EDITOR))); } #endif /* AUTOSLOPE_H */ openttd-1.5.3/src/newgrf_gui.cpp0000644000000000000000000025357412627373442015354 0ustar rootroot/* $Id: newgrf_gui.cpp 26954 2014-10-04 18:19:22Z peter1138 $ */ /* * 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 newgrf_gui.cpp GUI to change NewGRF settings. */ #include "stdafx.h" #include "error.h" #include "settings_gui.h" #include "newgrf.h" #include "strings_func.h" #include "window_func.h" #include "gamelog.h" #include "settings_type.h" #include "settings_func.h" #include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" #include "network/network.h" #include "network/network_content.h" #include "sortlist_type.h" #include "stringfilter_type.h" #include "querystring_gui.h" #include "core/geometry_func.hpp" #include "newgrf_text.h" #include "textfile_gui.h" #include "tilehighlight_func.h" #include "fios.h" #include "widgets/newgrf_widget.h" #include "widgets/misc_widget.h" #include "table/sprites.h" #include #include "safeguards.h" /* Maximum number of NewGRFs that may be loaded. Six reserved slots are: * 0 - config, 1 - sound, 2 - base, 3 - logos, 4 - climate, 5 - extra */ static const int MAX_NEWGRFS = MAX_FILE_SLOTS - 6; /** * Show the first NewGRF error we can find. */ void ShowNewGRFError() { /* Do not show errors when entering the main screen */ if (_game_mode == GM_MENU) return; for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) { /* We only want to show fatal errors */ if (c->error == NULL || c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL) continue; SetDParam (0, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING); SetDParamStr(1, c->error->custom_message); SetDParamStr(2, c->filename); SetDParamStr(3, c->error->data); for (uint i = 0; i < lengthof(c->error->param_value); i++) { SetDParam(4 + i, c->error->param_value[i]); } ShowErrorMessage(STR_NEWGRF_ERROR_FATAL_POPUP, INVALID_STRING_ID, WL_CRITICAL); break; } } static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint right, uint bottom, bool show_params) { if (c->error != NULL) { char message[512]; SetDParamStr(0, c->error->custom_message); // is skipped by built-in messages SetDParamStr(1, c->filename); SetDParamStr(2, c->error->data); for (uint i = 0; i < lengthof(c->error->param_value); i++) { SetDParam(3 + i, c->error->param_value[i]); } GetString(message, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING, lastof(message)); SetDParamStr(0, message); y = DrawStringMultiLine(x, right, y, bottom, c->error->severity); } /* Draw filename or not if it is not known (GRF sent over internet) */ if (c->filename != NULL) { SetDParamStr(0, c->filename); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_FILENAME); } /* Prepare and draw GRF ID */ char buff[256]; seprintf(buff, lastof(buff), "%08X", BSWAP32(c->ident.grfid)); SetDParamStr(0, buff); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_GRF_ID); if ((_settings_client.gui.newgrf_developer_tools || _settings_client.gui.newgrf_show_old_versions) && c->version != 0) { SetDParam(0, c->version); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_VERSION); } if ((_settings_client.gui.newgrf_developer_tools || _settings_client.gui.newgrf_show_old_versions) && c->min_loadable_version != 0) { SetDParam(0, c->min_loadable_version); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_MIN_VERSION); } /* Prepare and draw MD5 sum */ md5sumToString(buff, lastof(buff), c->ident.md5sum); SetDParamStr(0, buff); y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_MD5SUM); /* Show GRF parameter list */ if (show_params) { if (c->num_params > 0) { GRFBuildParamList(buff, c, lastof(buff)); SetDParam(0, STR_JUST_RAW_STRING); SetDParamStr(1, buff); } else { SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE); } y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PARAMETER); /* Draw the palette of the NewGRF */ if (c->palette & GRFP_BLT_32BPP) { SetDParamStr(0, (c->palette & GRFP_USE_WINDOWS) ? "Legacy (W) / 32 bpp" : "Default (D) / 32 bpp"); } else { SetDParamStr(0, (c->palette & GRFP_USE_WINDOWS) ? "Legacy (W)" : "Default (D)"); } y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PALETTE); } /* Show flags */ if (c->status == GCS_NOT_FOUND) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NOT_FOUND); if (c->status == GCS_DISABLED) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_DISABLED); if (HasBit(c->flags, GCF_INVALID)) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_INCOMPATIBLE); if (HasBit(c->flags, GCF_COMPATIBLE)) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_COMPATIBLE_LOADED); /* Draw GRF info if it exists */ if (!StrEmpty(c->GetDescription())) { SetDParamStr(0, c->GetDescription()); y = DrawStringMultiLine(x, right, y, bottom, STR_BLACK_RAW_STRING); } else { y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NO_INFO); } } /** * Window for setting the parameters of a NewGRF. */ struct NewGRFParametersWindow : public Window { static GRFParameterInfo dummy_parameter_info; ///< Dummy info in case a newgrf didn't provide info about some parameter. GRFConfig *grf_config; ///< Set the parameters of this GRFConfig. uint clicked_button; ///< The row in which a button was clicked or UINT_MAX. bool clicked_increase; ///< True if the increase button was clicked, false for the decrease button. bool clicked_dropdown; ///< Whether the dropdown is open. bool closing_dropdown; ///< True, if the dropdown list is currently closing. int timeout; ///< How long before we unpress the last-pressed button? uint clicked_row; ///< The selected parameter int line_height; ///< Height of a row in the matrix widget. Scrollbar *vscroll; bool action14present; ///< True if action14 information is present. bool editable; ///< Allow editing parameters. NewGRFParametersWindow(WindowDesc *desc, GRFConfig *c, bool editable) : Window(desc), grf_config(c), clicked_button(UINT_MAX), clicked_dropdown(false), closing_dropdown(false), timeout(0), clicked_row(UINT_MAX), editable(editable) { this->action14present = (c->num_valid_params != lengthof(c->param) || c->param_info.Length() != 0); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NP_SCROLLBAR); this->GetWidget(WID_NP_SHOW_NUMPAR)->SetDisplayedPlane(this->action14present ? SZSP_HORIZONTAL : 0); this->GetWidget(WID_NP_SHOW_DESCRIPTION)->SetDisplayedPlane(this->action14present ? 0 : SZSP_HORIZONTAL); this->FinishInitNested(); // Initializes 'this->line_height' as side effect. this->SetWidgetDisabledState(WID_NP_RESET, !this->editable); this->InvalidateData(); } /** * Get a dummy parameter-info object with default information. * @param nr The param number that should be changed. * @return GRFParameterInfo with dummy information about the given parameter. */ static GRFParameterInfo *GetDummyParameterInfo(uint nr) { dummy_parameter_info.param_nr = nr; return &dummy_parameter_info; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_NP_NUMPAR_DEC: case WID_NP_NUMPAR_INC: { size->width = max(SETTING_BUTTON_WIDTH / 2, FONT_HEIGHT_NORMAL); size->height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL); break; } case WID_NP_NUMPAR: { SetDParamMaxValue(0, lengthof(this->grf_config->param)); Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_NP_BACKGROUND: this->line_height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; resize->width = 1; resize->height = this->line_height; size->height = 5 * this->line_height; break; case WID_NP_DESCRIPTION: /* Minimum size of 4 lines. The 500 is the default size of the window. */ Dimension suggestion = {500 - WD_FRAMERECT_LEFT - WD_FRAMERECT_RIGHT, FONT_HEIGHT_NORMAL * 4 + WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM}; for (uint i = 0; i < this->grf_config->param_info.Length(); i++) { const GRFParameterInfo *par_info = this->grf_config->param_info[i]; if (par_info == NULL) continue; const char *desc = GetGRFStringFromGRFText(par_info->desc); if (desc == NULL) continue; Dimension d = GetStringMultiLineBoundingBox(desc, suggestion); d.height += WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM; suggestion = maxdim(d, suggestion); } size->height = suggestion.height; break; } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_NP_NUMPAR: SetDParam(0, this->vscroll->GetCount()); break; } } virtual void DrawWidget(const Rect &r, int widget) const { if (widget == WID_NP_DESCRIPTION) { const GRFParameterInfo *par_info = (this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL; if (par_info == NULL) return; const char *desc = GetGRFStringFromGRFText(par_info->desc); if (desc == NULL) return; DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_TEXTPANEL_TOP, r.bottom - WD_TEXTPANEL_BOTTOM, desc, TC_BLACK); return; } else if (widget != WID_NP_BACKGROUND) { return; } bool rtl = _current_text_dir == TD_RTL; uint buttons_left = rtl ? r.right - SETTING_BUTTON_WIDTH - 3 : r.left + 4; uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : SETTING_BUTTON_WIDTH + 8); uint text_right = r.right - (rtl ? SETTING_BUTTON_WIDTH + 8 : WD_FRAMERECT_RIGHT); int y = r.top; int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2; int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < this->vscroll->GetCount(); i++) { GRFParameterInfo *par_info = (i < this->grf_config->param_info.Length()) ? this->grf_config->param_info[i] : NULL; if (par_info == NULL) par_info = GetDummyParameterInfo(i); uint32 current_value = par_info->GetValue(this->grf_config); bool selected = (i == this->clicked_row); if (par_info->type == PTYPE_BOOL) { DrawBoolButton(buttons_left, y + button_y_offset, current_value != 0, this->editable); SetDParam(2, par_info->GetValue(this->grf_config) == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON); } else if (par_info->type == PTYPE_UINT_ENUM) { if (par_info->complete_labels) { DrawDropDownButton(buttons_left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && this->clicked_dropdown, this->editable); } else { DrawArrowButtons(buttons_left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, this->editable && current_value > par_info->min_value, this->editable && current_value < par_info->max_value); } SetDParam(2, STR_JUST_INT); SetDParam(3, current_value); if (par_info->value_names.Contains(current_value)) { const char *label = GetGRFStringFromGRFText(par_info->value_names.Find(current_value)->second); if (label != NULL) { SetDParam(2, STR_JUST_RAW_STRING); SetDParamStr(3, label); } } } const char *name = GetGRFStringFromGRFText(par_info->name); if (name != NULL) { SetDParam(0, STR_JUST_RAW_STRING); SetDParamStr(1, name); } else { SetDParam(0, STR_NEWGRF_PARAMETERS_DEFAULT_NAME); SetDParam(1, i + 1); } DrawString(text_left, text_right, y + text_y_offset, STR_NEWGRF_PARAMETERS_SETTING, selected ? TC_WHITE : TC_LIGHT_BLUE); y += this->line_height; } } virtual void OnPaint() { if (this->closing_dropdown) { this->closing_dropdown = false; this->clicked_dropdown = false; } this->DrawWidgets(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_NP_NUMPAR_DEC: if (this->editable && !this->action14present && this->grf_config->num_params > 0) { this->grf_config->num_params--; this->InvalidateData(); SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE); } break; case WID_NP_NUMPAR_INC: { GRFConfig *c = this->grf_config; if (this->editable && !this->action14present && c->num_params < c->num_valid_params) { c->param[c->num_params++] = 0; this->InvalidateData(); SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE); } break; } case WID_NP_BACKGROUND: { if (!this->editable) break; uint num = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NP_BACKGROUND); if (num >= this->vscroll->GetCount()) break; if (this->clicked_row != num) { DeleteChildWindows(WC_QUERY_STRING); HideDropDownMenu(this); this->clicked_row = num; this->clicked_dropdown = false; } const NWidgetBase *wid = this->GetWidget(WID_NP_BACKGROUND); int x = pt.x - wid->pos_x; if (_current_text_dir == TD_RTL) x = wid->current_x - 1 - x; x -= 4; GRFParameterInfo *par_info = (num < this->grf_config->param_info.Length()) ? this->grf_config->param_info[num] : NULL; if (par_info == NULL) par_info = GetDummyParameterInfo(num); /* One of the arrows is clicked */ uint32 old_val = par_info->GetValue(this->grf_config); if (par_info->type != PTYPE_BOOL && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && par_info->complete_labels) { if (this->clicked_dropdown) { /* unclick the dropdown */ HideDropDownMenu(this); this->clicked_dropdown = false; this->closing_dropdown = false; } else { const NWidgetBase *wid = this->GetWidget(WID_NP_BACKGROUND); int rel_y = (pt.y - (int)wid->pos_y) % this->line_height; Rect wi_rect; wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x);; wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1; wi_rect.top = pt.y - rel_y + (this->line_height - SETTING_BUTTON_HEIGHT) / 2; wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1; /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */ if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) { this->clicked_dropdown = true; this->closing_dropdown = false; DropDownList *list = new DropDownList(); for (uint32 i = par_info->min_value; i <= par_info->max_value; i++) { *list->Append() = new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info->value_names.Find(i)->second), i, false); } ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true); } } } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) { uint32 val = old_val; if (par_info->type == PTYPE_BOOL) { val = !val; } else { if (x >= SETTING_BUTTON_WIDTH / 2) { /* Increase button clicked */ if (val < par_info->max_value) val++; this->clicked_increase = true; } else { /* Decrease button clicked */ if (val > par_info->min_value) val--; this->clicked_increase = false; } } if (val != old_val) { par_info->SetValue(this->grf_config, val); this->clicked_button = num; this->timeout = 5; } } else if (par_info->type == PTYPE_UINT_ENUM && !par_info->complete_labels && click_count >= 2) { /* Display a query box so users can enter a custom value. */ SetDParam(0, old_val); ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE); } this->SetDirty(); break; } case WID_NP_RESET: if (!this->editable) break; this->grf_config->SetParameterDefaults(); this->InvalidateData(); SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE); break; case WID_NP_ACCEPT: delete this; break; } } virtual void OnQueryTextFinished(char *str) { if (StrEmpty(str)) return; int32 value = atoi(str); GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL; if (par_info == NULL) par_info = GetDummyParameterInfo(this->clicked_row); uint32 val = Clamp(value, par_info->min_value, par_info->max_value); par_info->SetValue(this->grf_config, val); this->SetDirty(); } virtual void OnDropdownSelect(int widget, int index) { assert(this->clicked_dropdown); GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL; if (par_info == NULL) par_info = GetDummyParameterInfo(this->clicked_row); par_info->SetValue(this->grf_config, index); this->SetDirty(); } virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) { /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether * the same dropdown button was clicked again, and then not open the dropdown again. * So, we only remember that it was closed, and process it on the next OnPaint, which is * after OnClick. */ assert(this->clicked_dropdown); this->closing_dropdown = true; this->SetDirty(); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_NP_BACKGROUND); } /** * 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; if (!this->action14present) { this->SetWidgetDisabledState(WID_NP_NUMPAR_DEC, !this->editable || this->grf_config->num_params == 0); this->SetWidgetDisabledState(WID_NP_NUMPAR_INC, !this->editable || this->grf_config->num_params >= this->grf_config->num_valid_params); } this->vscroll->SetCount(this->action14present ? this->grf_config->num_valid_params : this->grf_config->num_params); if (this->clicked_row != UINT_MAX && this->clicked_row >= this->vscroll->GetCount()) { this->clicked_row = UINT_MAX; DeleteChildWindows(WC_QUERY_STRING); } } virtual void OnTick() { if (--this->timeout == 0) { this->clicked_button = UINT_MAX; this->SetDirty(); } } }; GRFParameterInfo NewGRFParametersWindow::dummy_parameter_info(0); static const NWidgetPart _nested_newgrf_parameter_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_PARAMETERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_NUMPAR), NWidget(WWT_PANEL, COLOUR_MAUVE), SetResize(1, 0), SetFill(1, 0), SetPIP(4, 0, 4), NWidget(NWID_HORIZONTAL), SetPIP(4, 0, 4), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_NP_NUMPAR_DEC), SetMinimalSize(12, 12), SetDataTip(AWV_DECREASE, STR_NULL), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_NP_NUMPAR_INC), SetMinimalSize(12, 12), SetDataTip(AWV_INCREASE, STR_NULL), NWidget(WWT_TEXT, COLOUR_MAUVE, WID_NP_NUMPAR), SetResize(1, 0), SetFill(1, 0), SetPadding(0, 0, 0, 4), SetDataTip(STR_NEWGRF_PARAMETERS_NUM_PARAM, STR_NULL), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_NP_BACKGROUND), SetMinimalSize(188, 182), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_NP_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NP_SCROLLBAR), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_DESCRIPTION), NWidget(WWT_PANEL, COLOUR_MAUVE, WID_NP_DESCRIPTION), SetResize(1, 0), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_CLOSE, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_RESET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_RESET, STR_NEWGRF_PARAMETERS_RESET_TOOLTIP), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), EndContainer(), }; /** Window definition for the change grf parameters window */ static WindowDesc _newgrf_parameters_desc( WDP_CENTER, "settings_newgrf_config", 500, 208, WC_GRF_PARAMETERS, WC_NONE, 0, _nested_newgrf_parameter_widgets, lengthof(_nested_newgrf_parameter_widgets) ); static void OpenGRFParameterWindow(GRFConfig *c, bool editable) { DeleteWindowByClass(WC_GRF_PARAMETERS); new NewGRFParametersWindow(&_newgrf_parameters_desc, c, editable); } /** Window for displaying the textfile of a NewGRF. */ struct NewGRFTextfileWindow : public TextfileWindow { const GRFConfig *grf_config; ///< View the textfile of this GRFConfig. NewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c) : TextfileWindow(file_type), grf_config(c) { const char *textfile = this->grf_config->GetTextfile(file_type); this->LoadTextfile(textfile, NEWGRF_DIR); } /* virtual */ void SetStringParameters(int widget) const { if (widget == WID_TF_CAPTION) { SetDParam(0, STR_CONTENT_TYPE_NEWGRF); SetDParamStr(1, this->grf_config->GetName()); } } }; void ShowNewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c) { DeleteWindowByClass(WC_TEXTFILE); new NewGRFTextfileWindow(file_type, c); } static GRFPresetList _grf_preset_list; ///< List of known NewGRF presets. @see GetGRFPresetList class DropDownListPresetItem : public DropDownListItem { public: DropDownListPresetItem(int result) : DropDownListItem(result, false) {} virtual ~DropDownListPresetItem() {} bool Selectable() const { return true; } void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const { DrawString(left + 2, right + 2, top, _grf_preset_list[this->result], sel ? TC_WHITE : TC_BLACK); } }; typedef std::map GrfIdMap; ///< Map of grfid to the grf config. /** * Add all grf configs from \a c into the map. * @param c Grf list to add. * @param grfid_map Map to add them to. */ static void FillGrfidMap(const GRFConfig *c, GrfIdMap *grfid_map) { while (c != NULL) { std::pair p(c->ident.grfid, c); grfid_map->insert(p); c = c->next; } } static void NewGRFConfirmationCallback(Window *w, bool confirmed); static void ShowSavePresetWindow(const char *initial_text); /** * Window for showing NewGRF files */ struct NewGRFWindow : public Window, NewGRFScanCallback { typedef GUIList GUIGRFConfigList; static const uint EDITBOX_MAX_SIZE = 50; static Listing last_sorting; ///< Default sorting of #GUIGRFConfigList. static Filtering last_filtering; ///< Default filtering of #GUIGRFConfigList. static GUIGRFConfigList::SortFunction * const sorter_funcs[]; ///< Sort functions of the #GUIGRFConfigList. static GUIGRFConfigList::FilterFunction * const filter_funcs[]; ///< Filter functions of the #GUIGRFConfigList. GUIGRFConfigList avails; ///< Available (non-active) grfs. const GRFConfig *avail_sel; ///< Currently selected available grf. \c NULL is none is selected. int avail_pos; ///< Index of #avail_sel if existing, else \c -1. StringFilter string_filter; ///< Filter for available grf. QueryString filter_editbox; ///< Filter editbox; GRFConfig *actives; ///< Temporary active grf list to which changes are made. GRFConfig *active_sel; ///< Selected active grf item. GRFConfig **orig_list; ///< List active grfs in the game. Used as initial value, may be updated by the window. bool editable; ///< Is the window editable? bool show_params; ///< Are the grf-parameters shown in the info-panel? bool execute; ///< On pressing 'apply changes' are grf changes applied immediately, or only list is updated. int preset; ///< Selected preset or \c -1 if none selected. int active_over; ///< Active GRF item over which another one is dragged, \c -1 if none. Scrollbar *vscroll; Scrollbar *vscroll2; NewGRFWindow(WindowDesc *desc, bool editable, bool show_params, bool execute, GRFConfig **orig_list) : Window(desc), filter_editbox(EDITBOX_MAX_SIZE) { this->avail_sel = NULL; this->avail_pos = -1; this->active_sel = NULL; this->actives = NULL; this->orig_list = orig_list; this->editable = editable; this->execute = execute; this->show_params = show_params; this->preset = -1; this->active_over = -1; CopyGRFConfigList(&this->actives, *orig_list, false); GetGRFPresetList(&_grf_preset_list); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NS_SCROLLBAR); this->vscroll2 = this->GetScrollbar(WID_NS_SCROLL2BAR); this->GetWidget(WID_NS_SHOW_REMOVE)->SetDisplayedPlane(this->editable ? 0 : 1); this->GetWidget(WID_NS_SHOW_APPLY)->SetDisplayedPlane(this->editable ? 0 : this->show_params ? 1 : SZSP_HORIZONTAL); this->FinishInitNested(WN_GAME_OPTIONS_NEWGRF_STATE); this->querystrings[WID_NS_FILTER] = &this->filter_editbox; this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; if (editable) { this->SetFocusedWidget(WID_NS_FILTER); } else { this->DisableWidget(WID_NS_FILTER); } this->avails.SetListing(this->last_sorting); this->avails.SetFiltering(this->last_filtering); this->avails.SetSortFuncs(this->sorter_funcs); this->avails.SetFilterFuncs(this->filter_funcs); this->avails.ForceRebuild(); this->OnInvalidateData(GOID_NEWGRF_LIST_EDITED); } ~NewGRFWindow() { DeleteWindowByClass(WC_GRF_PARAMETERS); DeleteWindowByClass(WC_TEXTFILE); DeleteWindowByClass(WC_SAVE_PRESET); if (this->editable && !this->execute) { CopyGRFConfigList(this->orig_list, this->actives, true); ResetGRFConfig(false); ReloadNewGRFData(); } /* Remove the temporary copy of grf-list used in window */ ClearGRFConfigList(&this->actives); _grf_preset_list.Clear(); } /** * Test whether the currently active set of NewGRFs can be upgraded with the available NewGRFs. * @return Whether an upgrade is possible. */ bool CanUpgradeCurrent() { GrfIdMap grfid_map; FillGrfidMap(this->actives, &grfid_map); for (const GRFConfig *a = _all_grfs; a != NULL; a = a->next) { GrfIdMap::const_iterator iter = grfid_map.find(a->ident.grfid); if (iter != grfid_map.end() && a->version > iter->second->version) return true; } return false; } /** Upgrade the currently active set of NewGRFs. */ void UpgradeCurrent() { GrfIdMap grfid_map; FillGrfidMap(this->actives, &grfid_map); for (const GRFConfig *a = _all_grfs; a != NULL; a = a->next) { GrfIdMap::iterator iter = grfid_map.find(a->ident.grfid); if (iter == grfid_map.end() || iter->second->version >= a->version) continue; GRFConfig **c = &this->actives; while (*c != iter->second) c = &(*c)->next; GRFConfig *d = new GRFConfig(*a); d->next = (*c)->next; d->CopyParams(**c); if (this->active_sel == *c) this->active_sel = NULL; delete *c; *c = d; iter->second = d; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_NS_FILE_LIST: { Dimension d = maxdim(GetSpriteSize(SPR_SQUARE), GetSpriteSize(SPR_WARNING_SIGN)); resize->height = max(d.height + 2U, FONT_HEIGHT_NORMAL + 2U); size->height = max(size->height, WD_FRAMERECT_TOP + 6 * resize->height + WD_FRAMERECT_BOTTOM); break; } case WID_NS_AVAIL_LIST: resize->height = max(12, FONT_HEIGHT_NORMAL + 2); size->height = max(size->height, WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM); break; case WID_NS_NEWGRF_INFO_TITLE: { Dimension dim = GetStringBoundingBox(STR_NEWGRF_SETTINGS_INFO_TITLE); size->height = max(size->height, dim.height + WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM); size->width = max(size->width, dim.width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); break; } case WID_NS_NEWGRF_INFO: size->height = max(size->height, WD_FRAMERECT_TOP + 10 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM + padding.height + 2); break; case WID_NS_PRESET_LIST: { Dimension d = GetStringBoundingBox(STR_NUM_CUSTOM); for (uint i = 0; i < _grf_preset_list.Length(); i++) { if (_grf_preset_list[i] != NULL) { SetDParamStr(0, _grf_preset_list[i]); d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING)); } } d.width += padding.width; *size = maxdim(d, *size); break; } case WID_NS_CONTENT_DOWNLOAD: case WID_NS_CONTENT_DOWNLOAD2: { Dimension d = GetStringBoundingBox(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON); *size = maxdim(d, GetStringBoundingBox(STR_INTRO_ONLINE_CONTENT)); size->width += padding.width; size->height += padding.height; break; } } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST); this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_NS_PRESET_LIST: if (this->preset == -1) { SetDParam(0, STR_NUM_CUSTOM); } else { SetDParam(0, STR_JUST_RAW_STRING); SetDParamStr(1, _grf_preset_list[this->preset]); } break; } } /** * Pick the palette for the sprite of the grf to display. * @param c grf to display. * @return Palette for the sprite. */ inline PaletteID GetPalette(const GRFConfig *c) const { PaletteID pal; /* Pick a colour */ switch (c->status) { case GCS_NOT_FOUND: case GCS_DISABLED: pal = PALETTE_TO_RED; break; case GCS_ACTIVATED: pal = PALETTE_TO_GREEN; break; default: pal = PALETTE_TO_BLUE; break; } /* Do not show a "not-failure" colour when it actually failed to load */ if (pal != PALETTE_TO_RED) { if (HasBit(c->flags, GCF_STATIC)) { pal = PALETTE_TO_GREY; } else if (HasBit(c->flags, GCF_COMPATIBLE)) { pal = PALETTE_TO_ORANGE; } } return pal; } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_NS_FILE_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); uint step_height = this->GetWidget(WID_NS_FILE_LIST)->resize_y; uint y = r.top + WD_FRAMERECT_TOP; Dimension square = GetSpriteSize(SPR_SQUARE); Dimension warning = GetSpriteSize(SPR_WARNING_SIGN); int square_offset_y = (step_height - square.height) / 2; int warning_offset_y = (step_height - warning.height) / 2; int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2; bool rtl = _current_text_dir == TD_RTL; uint text_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.left + square.width + 15; uint text_right = rtl ? r.right - square.width - 15 : r.right - WD_FRAMERECT_RIGHT; uint square_left = rtl ? r.right - square.width - 5 : r.left + 5; uint warning_left = rtl ? r.right - square.width - warning.width - 10 : r.left + square.width + 10; int i = 0; for (const GRFConfig *c = this->actives; c != NULL; c = c->next, i++) { if (this->vscroll->IsVisible(i)) { const char *text = c->GetName(); bool h = (this->active_sel == c); PaletteID pal = this->GetPalette(c); if (h) { GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 1, PC_DARK_BLUE); } else if (i == this->active_over) { /* Get index of current selection. */ int active_sel_pos = 0; for (GRFConfig *c = this->actives; c != NULL && c != this->active_sel; c = c->next, active_sel_pos++) {} if (active_sel_pos != this->active_over) { uint top = this->active_over < active_sel_pos ? y + 1 : y + step_height - 2; GfxFillRect(r.left + WD_FRAMERECT_LEFT, top - 1, r.right - WD_FRAMERECT_RIGHT, top + 1, PC_GREY); } } DrawSprite(SPR_SQUARE, pal, square_left, y + square_offset_y); if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, y + warning_offset_y); uint txtoffset = c->error == NULL ? 0 : warning.width; DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), y + offset_y, text, h ? TC_WHITE : TC_ORANGE); y += step_height; } } if (i == this->active_over && this->vscroll->IsVisible(i)) { // Highlight is after the last GRF entry. GfxFillRect(r.left + WD_FRAMERECT_LEFT, y, r.right - WD_FRAMERECT_RIGHT, y + 2, PC_GREY); } break; } case WID_NS_AVAIL_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, this->active_over == -2 ? PC_DARK_GREY : PC_BLACK); uint step_height = this->GetWidget(WID_NS_AVAIL_LIST)->resize_y; int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2; uint y = r.top + WD_FRAMERECT_TOP; uint min_index = this->vscroll2->GetPosition(); uint max_index = min(min_index + this->vscroll2->GetCapacity(), this->avails.Length()); for (uint i = min_index; i < max_index; i++) { const GRFConfig *c = this->avails[i]; bool h = (c == this->avail_sel); const char *text = c->GetName(); if (h) GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 1, PC_DARK_BLUE); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + offset_y, text, h ? TC_WHITE : TC_SILVER); y += step_height; } break; } case WID_NS_NEWGRF_INFO_TITLE: /* Create the nice grayish rectangle at the details top. */ GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_DARK_BLUE); DrawString(r.left, r.right, (r.top + r.bottom - FONT_HEIGHT_NORMAL) / 2, STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_HOR_CENTER); break; case WID_NS_NEWGRF_INFO: { const GRFConfig *selected = this->active_sel; if (selected == NULL) selected = this->avail_sel; if (selected != NULL) { ShowNewGRFInfo(selected, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, r.right - WD_FRAMERECT_RIGHT, r.bottom - WD_FRAMERECT_BOTTOM, this->show_params); } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_END) { if (this->active_sel == NULL && this->avail_sel == NULL) return; ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != NULL ? this->active_sel : this->avail_sel); return; } switch (widget) { case WID_NS_PRESET_LIST: { DropDownList *list = new DropDownList(); /* Add 'None' option for clearing list */ *list->Append() = new DropDownListStringItem(STR_NONE, -1, false); for (uint i = 0; i < _grf_preset_list.Length(); i++) { if (_grf_preset_list[i] != NULL) { *list->Append() = new DropDownListPresetItem(i); } } this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window ShowDropDownList(this, list, this->preset, WID_NS_PRESET_LIST); break; } case WID_NS_OPEN_URL: { const GRFConfig *c = (this->avail_sel == NULL) ? this->active_sel : this->avail_sel; extern void OpenBrowser(const char *url); OpenBrowser(c->GetURL()); break; } case WID_NS_PRESET_SAVE: ShowSavePresetWindow((this->preset == -1) ? NULL : _grf_preset_list[this->preset]); break; case WID_NS_PRESET_DELETE: if (this->preset == -1) return; DeleteGRFPresetFromConfig(_grf_preset_list[this->preset]); GetGRFPresetList(&_grf_preset_list); this->preset = -1; this->InvalidateData(); this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window break; case WID_NS_MOVE_UP: { // Move GRF up if (this->active_sel == NULL || !this->editable) break; int pos = 0; for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next, pos++) { GRFConfig *c = *pc; if (c->next == this->active_sel) { c->next = this->active_sel->next; this->active_sel->next = c; *pc = this->active_sel; break; } } this->vscroll->ScrollTowards(pos); this->preset = -1; this->InvalidateData(); break; } case WID_NS_MOVE_DOWN: { // Move GRF down if (this->active_sel == NULL || !this->editable) break; int pos = 1; // Start at 1 as we swap the selected newgrf with the next one for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next, pos++) { GRFConfig *c = *pc; if (c == this->active_sel) { *pc = c->next; c->next = c->next->next; (*pc)->next = c; break; } } this->vscroll->ScrollTowards(pos); this->preset = -1; this->InvalidateData(); break; } case WID_NS_FILE_LIST: { // Select an active GRF. ResetObjectToPlace(); uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST); GRFConfig *c; for (c = this->actives; c != NULL && i > 0; c = c->next, i--) {} if (this->active_sel != c) DeleteWindowByClass(WC_GRF_PARAMETERS); this->active_sel = c; this->avail_sel = NULL; this->avail_pos = -1; this->InvalidateData(); if (click_count == 1) { if (this->editable && this->active_sel != NULL) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); break; } /* FALL THROUGH, with double click. */ } case WID_NS_REMOVE: { // Remove GRF if (this->active_sel == NULL || !this->editable) break; DeleteWindowByClass(WC_GRF_PARAMETERS); /* Choose the next GRF file to be the selected file. */ GRFConfig *newsel = this->active_sel->next; for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next) { GRFConfig *c = *pc; /* If the new selection is empty (i.e. we're deleting the last item * in the list, pick the file just before the selected file */ if (newsel == NULL && c->next == this->active_sel) newsel = c; if (c == this->active_sel) { if (newsel == c) newsel = NULL; *pc = c->next; delete c; break; } } this->active_sel = newsel; this->preset = -1; this->avail_pos = -1; this->avail_sel = NULL; this->avails.ForceRebuild(); this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; } case WID_NS_UPGRADE: { // Upgrade GRF. if (!this->editable || this->actives == NULL) break; UpgradeCurrent(); this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; } case WID_NS_AVAIL_LIST: { // Select a non-active GRF. ResetObjectToPlace(); uint i = this->vscroll2->GetScrolledRowFromWidget(pt.y, this, WID_NS_AVAIL_LIST); this->active_sel = NULL; DeleteWindowByClass(WC_GRF_PARAMETERS); if (i < this->avails.Length()) { this->avail_sel = this->avails[i]; this->avail_pos = i; } this->InvalidateData(); if (click_count == 1) { if (this->editable && this->avail_sel != NULL && !HasBit(this->avail_sel->flags, GCF_INVALID)) SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); break; } /* FALL THROUGH, with double click. */ } case WID_NS_ADD: if (this->avail_sel == NULL || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) break; this->AddGRFToActive(); break; case WID_NS_APPLY_CHANGES: // Apply changes made to GRF list if (!this->editable) break; if (this->execute) { ShowQuery( STR_NEWGRF_POPUP_CAUTION_CAPTION, STR_NEWGRF_CONFIRMATION_TEXT, this, NewGRFConfirmationCallback ); } else { CopyGRFConfigList(this->orig_list, this->actives, true); ResetGRFConfig(false); ReloadNewGRFData(); } this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window break; case WID_NS_VIEW_PARAMETERS: case WID_NS_SET_PARAMETERS: { // Edit parameters if (this->active_sel == NULL || !this->show_params || this->active_sel->num_valid_params == 0) break; OpenGRFParameterWindow(this->active_sel, this->editable); break; } case WID_NS_TOGGLE_PALETTE: if (this->active_sel != NULL && this->editable) { this->active_sel->palette ^= GRFP_USE_MASK; this->SetDirty(); } break; case WID_NS_CONTENT_DOWNLOAD: case WID_NS_CONTENT_DOWNLOAD2: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else { #if defined(ENABLE_NETWORK) this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window ShowMissingContentWindow(this->actives); #endif } break; case WID_NS_RESCAN_FILES: case WID_NS_RESCAN_FILES2: ScanNewGRFFiles(this); break; } } virtual void OnNewGRFsScanned() { this->avail_sel = NULL; this->avail_pos = -1; this->avails.ForceRebuild(); this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window this->DeleteChildWindows(WC_TEXTFILE); // Remove the view textfile window } virtual void OnDropdownSelect(int widget, int index) { if (!this->editable) return; ClearGRFConfigList(&this->actives); this->preset = index; if (index != -1) { this->actives = LoadGRFPresetFromConfig(_grf_preset_list[index]); } this->avails.ForceRebuild(); ResetObjectToPlace(); DeleteWindowByClass(WC_GRF_PARAMETERS); this->active_sel = NULL; this->InvalidateData(GOID_NEWGRF_PRESET_LOADED); } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; SaveGRFPresetToConfig(str, this->actives); GetGRFPresetList(&_grf_preset_list); /* Switch to this preset */ for (uint i = 0; i < _grf_preset_list.Length(); i++) { if (_grf_preset_list[i] != NULL && strcmp(_grf_preset_list[i], str) == 0) { this->preset = i; break; } } this->InvalidateData(); } /** * Some data on this window has become invalid. * @param data Information about the changed data. @see GameOptionsInvalidationData * @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; switch (data) { default: /* Nothing important to do */ break; case GOID_NEWGRF_RESCANNED: /* Search the list for items that are now found and mark them as such. */ for (GRFConfig **l = &this->actives; *l != NULL; l = &(*l)->next) { GRFConfig *c = *l; bool compatible = HasBit(c->flags, GCF_COMPATIBLE); if (c->status != GCS_NOT_FOUND && !compatible) continue; const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? c->original_md5sum : c->ident.md5sum); if (f == NULL || HasBit(f->flags, GCF_INVALID)) continue; *l = new GRFConfig(*f); (*l)->next = c->next; if (active_sel == c) active_sel = *l; delete c; } this->avails.ForceRebuild(); /* FALL THROUGH */ case GOID_NEWGRF_LIST_EDITED: this->preset = -1; /* FALL THROUGH */ case GOID_NEWGRF_PRESET_LOADED: { /* Update scrollbars */ int i = 0; for (const GRFConfig *c = this->actives; c != NULL; c = c->next, i++) {} this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling. if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos); break; } } this->BuildAvailables(); this->SetWidgetsDisabledState(!this->editable, WID_NS_PRESET_LIST, WID_NS_APPLY_CHANGES, WID_NS_TOGGLE_PALETTE, WIDGET_LIST_END ); this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == NULL || HasBit(this->avail_sel->flags, GCF_INVALID)); this->SetWidgetDisabledState(WID_NS_UPGRADE, !this->editable || this->actives == NULL || !this->CanUpgradeCurrent()); bool disable_all = this->active_sel == NULL || !this->editable; this->SetWidgetsDisabledState(disable_all, WID_NS_REMOVE, WID_NS_MOVE_UP, WID_NS_MOVE_DOWN, WIDGET_LIST_END ); const GRFConfig *c = (this->avail_sel == NULL) ? this->active_sel : this->avail_sel; for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, c == NULL || c->GetTextfile(tft) == NULL); } this->SetWidgetDisabledState(WID_NS_OPEN_URL, c == NULL || StrEmpty(c->GetURL())); this->SetWidgetDisabledState(WID_NS_SET_PARAMETERS, !this->show_params || this->active_sel == NULL || this->active_sel->num_valid_params == 0); this->SetWidgetDisabledState(WID_NS_VIEW_PARAMETERS, !this->show_params || this->active_sel == NULL || this->active_sel->num_valid_params == 0); this->SetWidgetDisabledState(WID_NS_TOGGLE_PALETTE, disable_all || (!(_settings_client.gui.newgrf_developer_tools || _settings_client.gui.scenario_developer) && ((c->palette & GRFP_GRF_MASK) != GRFP_GRF_UNSET))); if (!disable_all) { /* All widgets are now enabled, so disable widgets we can't use */ if (this->active_sel == this->actives) this->DisableWidget(WID_NS_MOVE_UP); if (this->active_sel->next == NULL) this->DisableWidget(WID_NS_MOVE_DOWN); if (this->active_sel->IsOpenTTDBaseGRF()) this->DisableWidget(WID_NS_REMOVE); } this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1); bool has_missing = false; bool has_compatible = false; for (const GRFConfig *c = this->actives; !has_missing && c != NULL; c = c->next) { has_missing |= c->status == GCS_NOT_FOUND; has_compatible |= HasBit(c->flags, GCF_COMPATIBLE); } uint32 widget_data; StringID tool_tip; if (has_missing || has_compatible) { widget_data = STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON; tool_tip = STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP; } else { widget_data = STR_INTRO_ONLINE_CONTENT; tool_tip = STR_INTRO_TOOLTIP_ONLINE_CONTENT; } this->GetWidget(WID_NS_CONTENT_DOWNLOAD)->widget_data = widget_data; this->GetWidget(WID_NS_CONTENT_DOWNLOAD)->tool_tip = tool_tip; this->GetWidget(WID_NS_CONTENT_DOWNLOAD2)->widget_data = widget_data; this->GetWidget(WID_NS_CONTENT_DOWNLOAD2)->tool_tip = tool_tip; this->SetWidgetDisabledState(WID_NS_PRESET_SAVE, has_missing); } virtual EventState OnKeyPress(WChar key, uint16 keycode) { if (!this->editable) return ES_NOT_HANDLED; switch (keycode) { case WKC_UP: /* scroll up by one */ if (this->avail_pos > 0) this->avail_pos--; break; case WKC_DOWN: /* scroll down by one */ if (this->avail_pos < (int)this->avails.Length() - 1) this->avail_pos++; break; case WKC_PAGEUP: /* scroll up a page */ this->avail_pos = (this->avail_pos < this->vscroll2->GetCapacity()) ? 0 : this->avail_pos - this->vscroll2->GetCapacity(); break; case WKC_PAGEDOWN: /* scroll down a page */ this->avail_pos = min(this->avail_pos + this->vscroll2->GetCapacity(), (int)this->avails.Length() - 1); break; case WKC_HOME: /* jump to beginning */ this->avail_pos = 0; break; case WKC_END: /* jump to end */ this->avail_pos = this->avails.Length() - 1; break; default: return ES_NOT_HANDLED; } if (this->avails.Length() == 0) this->avail_pos = -1; if (this->avail_pos >= 0) { this->avail_sel = this->avails[this->avail_pos]; this->vscroll2->ScrollTowards(this->avail_pos); this->InvalidateData(0); } return ES_HANDLED; } virtual void OnEditboxChanged(int wid) { if (!this->editable) return; string_filter.SetFilterTerm(this->filter_editbox.text.buf); this->avails.SetFilterState(!string_filter.IsEmpty()); this->avails.ForceRebuild(); this->InvalidateData(0); } virtual void OnDragDrop(Point pt, int widget) { if (!this->editable) return; if (widget == WID_NS_FILE_LIST) { if (this->active_sel != NULL) { /* Get pointer to the selected file in the active list. */ int from_pos = 0; GRFConfig **from_prev; for (from_prev = &this->actives; *from_prev != this->active_sel; from_prev = &(*from_prev)->next, from_pos++) {} /* Gets the drag-and-drop destination offset. Ignore the last dummy line. */ int to_pos = min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST), this->vscroll->GetCount() - 2); if (to_pos != from_pos) { // Don't move NewGRF file over itself. /* Get pointer to destination position. */ GRFConfig **to_prev = &this->actives; for (int i = from_pos < to_pos ? -1 : 0; *to_prev != NULL && i < to_pos; to_prev = &(*to_prev)->next, i++) {} /* Detach NewGRF file from its original position. */ *from_prev = this->active_sel->next; /* Attach NewGRF file to its new position. */ this->active_sel->next = *to_prev; *to_prev = this->active_sel; this->vscroll->ScrollTowards(to_pos); this->preset = -1; this->InvalidateData(); } } else if (this->avail_sel != NULL) { int to_pos = min(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST), this->vscroll->GetCount() - 1); this->AddGRFToActive(to_pos); } } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != NULL) { /* Remove active NewGRF file by dragging it over available list. */ Point dummy = {-1, -1}; this->OnClick(dummy, WID_NS_REMOVE, 1); } ResetObjectToPlace(); if (this->active_over != -1) { /* End of drag-and-drop, hide dragged destination highlight. */ this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST); this->active_over = -1; } } virtual void OnMouseDrag(Point pt, int widget) { if (!this->editable) return; if (widget == WID_NS_FILE_LIST && (this->active_sel != NULL || this->avail_sel != NULL)) { /* An NewGRF file is dragged over the active list. */ int to_pos = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST); /* Skip the last dummy line if the source is from the active list. */ to_pos = min(to_pos, this->vscroll->GetCount() - (this->active_sel != NULL ? 2 : 1)); if (to_pos != this->active_over) { this->active_over = to_pos; this->SetWidgetDirty(WID_NS_FILE_LIST); } } else if (widget == WID_NS_AVAIL_LIST && this->active_sel != NULL) { this->active_over = -2; this->SetWidgetDirty(WID_NS_AVAIL_LIST); } else if (this->active_over != -1) { this->SetWidgetDirty(this->active_over == -2 ? WID_NS_AVAIL_LIST : WID_NS_FILE_LIST); this->active_over = -1; } } private: /** Sort grfs by name. */ static int CDECL NameSorter(const GRFConfig * const *a, const GRFConfig * const *b) { int i = strnatcmp((*a)->GetName(), (*b)->GetName(), true); // Sort by name (natural sorting). if (i != 0) return i; i = (*a)->version - (*b)->version; if (i != 0) return i; return memcmp((*a)->ident.md5sum, (*b)->ident.md5sum, lengthof((*b)->ident.md5sum)); } /** Filter grfs by tags/name */ static bool CDECL TagNameFilter(const GRFConfig * const *a, StringFilter &filter) { filter.ResetState(); filter.AddLine((*a)->GetName()); filter.AddLine((*a)->filename); filter.AddLine((*a)->GetDescription()); return filter.GetState();; } void BuildAvailables() { if (!this->avails.NeedRebuild()) return; this->avails.Clear(); for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) { bool found = false; for (const GRFConfig *grf = this->actives; grf != NULL && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum); if (found) continue; if (_settings_client.gui.newgrf_show_old_versions) { *this->avails.Append() = c; } else { const GRFConfig *best = FindGRFConfig(c->ident.grfid, HasBit(c->flags, GCF_INVALID) ? FGCM_NEWEST : FGCM_NEWEST_VALID); /* * If the best version is 0, then all NewGRF with this GRF ID * have version 0, so for backward compatibility reasons we * want to show them all. * If we are the best version, then we definitely want to * show that NewGRF!. */ if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum)) { *this->avails.Append() = c; } } } this->avails.Filter(this->string_filter); this->avails.Compact(); this->avails.RebuildDone(); this->avails.Sort(); if (this->avail_sel != NULL) { this->avail_pos = this->avails.FindIndex(this->avail_sel); if (this->avail_pos < 0) this->avail_sel = NULL; } this->vscroll2->SetCount(this->avails.Length()); // Update the scrollbar } /** * Insert a GRF into the active list. * @param ins_pos Insert GRF at this position. * @return True if the GRF was successfully added. */ bool AddGRFToActive(int ins_pos = -1) { if (this->avail_sel == NULL || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) return false; int count = 0; GRFConfig **entry = NULL; GRFConfig **list; /* Find last entry in the list, checking for duplicate grfid on the way */ for (list = &this->actives; *list != NULL; list = &(*list)->next, ins_pos--) { if (ins_pos == 0) entry = list; // Insert position? Save. if ((*list)->ident.grfid == this->avail_sel->ident.grfid) { ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO); return false; } count++; } if (entry == NULL) entry = list; if (count >= MAX_NEWGRFS) { ShowErrorMessage(STR_NEWGRF_TOO_MANY_NEWGRFS, INVALID_STRING_ID, WL_INFO); return false; } GRFConfig *c = new GRFConfig(*this->avail_sel); // Copy GRF details from scanned list. c->SetParameterDefaults(); /* Insert GRF config to configuration list. */ c->next = *entry; *entry = c; /* Select next (or previous, if last one) item in the list. */ int new_pos = this->avail_pos + 1; if (new_pos >= (int)this->avails.Length()) new_pos = this->avail_pos - 1; this->avail_pos = new_pos; if (new_pos >= 0) this->avail_sel = this->avails[new_pos]; this->avails.ForceRebuild(); this->InvalidateData(GOID_NEWGRF_LIST_EDITED); return true; } }; #if defined(ENABLE_NETWORK) /** * Show the content list window with all missing grfs from the given list. * @param list The list of grfs to check for missing / not exactly matching ones. */ void ShowMissingContentWindow(const GRFConfig *list) { /* Only show the things in the current list, or everything when nothing's selected */ ContentVector cv; for (const GRFConfig *c = list; c != NULL; c = c->next) { if (c->status != GCS_NOT_FOUND && !HasBit(c->flags, GCF_COMPATIBLE)) continue; ContentInfo *ci = new ContentInfo(); ci->type = CONTENT_TYPE_NEWGRF; ci->state = ContentInfo::DOES_NOT_EXIST; strecpy(ci->name, c->GetName(), lastof(ci->name)); ci->unique_id = BSWAP32(c->ident.grfid); memcpy(ci->md5sum, HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum, sizeof(ci->md5sum)); *cv.Append() = ci; } ShowNetworkContentListWindow(cv.Length() == 0 ? NULL : &cv, CONTENT_TYPE_NEWGRF); } #endif Listing NewGRFWindow::last_sorting = {false, 0}; Filtering NewGRFWindow::last_filtering = {false, 0}; NewGRFWindow::GUIGRFConfigList::SortFunction * const NewGRFWindow::sorter_funcs[] = { &NameSorter, }; NewGRFWindow::GUIGRFConfigList::FilterFunction * const NewGRFWindow::filter_funcs[] = { &TagNameFilter, }; /** * Custom nested widget container for the NewGRF gui. * Depending on the space in the gui, it uses either * - two column mode, put the #acs and the #avs underneath each other and the #info next to it, or * - three column mode, put the #avs, #acs, and #info each in its own column. */ class NWidgetNewGRFDisplay : public NWidgetContainer { public: static const uint INTER_LIST_SPACING; ///< Empty vertical space between both lists in the 2 column mode. static const uint INTER_COLUMN_SPACING; ///< Empty horizontal space between two columns. static const uint MAX_EXTRA_INFO_WIDTH; ///< Maximal additional width given to the panel. static const uint MIN_EXTRA_FOR_3_COLUMNS; ///< Minimal additional width needed before switching to 3 columns. NWidgetBase *avs; ///< Widget with the available grfs list and buttons. NWidgetBase *acs; ///< Widget with the active grfs list and buttons. NWidgetBase *inf; ///< Info panel. bool editable; ///< Editable status of the parent NewGRF window (if \c false, drop all widgets that make the window editable). NWidgetNewGRFDisplay(NWidgetBase *avs, NWidgetBase *acs, NWidgetBase *inf) : NWidgetContainer(NWID_HORIZONTAL) { this->avs = avs; this->acs = acs; this->inf = inf; this->Add(this->avs); this->Add(this->acs); this->Add(this->inf); this->editable = true; // Temporary setting, 'real' value is set in SetupSmallestSize(). } virtual void SetupSmallestSize(Window *w, bool init_array) { /* Copy state flag from the window. */ assert(dynamic_cast(w) != NULL); NewGRFWindow *ngw = (NewGRFWindow *)w; this->editable = ngw->editable; this->avs->SetupSmallestSize(w, init_array); this->acs->SetupSmallestSize(w, init_array); this->inf->SetupSmallestSize(w, init_array); uint min_avs_width = this->avs->smallest_x + this->avs->padding_left + this->avs->padding_right; uint min_acs_width = this->acs->smallest_x + this->acs->padding_left + this->acs->padding_right; uint min_inf_width = this->inf->smallest_x + this->inf->padding_left + this->inf->padding_right; uint min_avs_height = this->avs->smallest_y + this->avs->padding_top + this->avs->padding_bottom; uint min_acs_height = this->acs->smallest_y + this->acs->padding_top + this->acs->padding_bottom; uint min_inf_height = this->inf->smallest_y + this->inf->padding_top + this->inf->padding_bottom; /* Smallest window is in two column mode. */ this->smallest_x = max(min_avs_width, min_acs_width) + INTER_COLUMN_SPACING + min_inf_width; this->smallest_y = max(min_inf_height, min_acs_height + INTER_LIST_SPACING + min_avs_height); /* Filling. */ this->fill_x = LeastCommonMultiple(this->avs->fill_x, this->acs->fill_x); if (this->inf->fill_x > 0 && (this->fill_x == 0 || this->fill_x > this->inf->fill_x)) this->fill_x = this->inf->fill_x; this->fill_y = this->avs->fill_y; if (this->acs->fill_y > 0 && (this->fill_y == 0 || this->fill_y > this->acs->fill_y)) this->fill_y = this->acs->fill_y; this->fill_y = LeastCommonMultiple(this->fill_y, this->inf->fill_y); /* Resizing. */ this->resize_x = LeastCommonMultiple(this->avs->resize_x, this->acs->resize_x); if (this->inf->resize_x > 0 && (this->resize_x == 0 || this->resize_x > this->inf->resize_x)) this->resize_x = this->inf->resize_x; this->resize_y = this->avs->resize_y; if (this->acs->resize_y > 0 && (this->resize_y == 0 || this->resize_y > this->acs->resize_y)) this->resize_y = this->acs->resize_y; this->resize_y = LeastCommonMultiple(this->resize_y, this->inf->resize_y); /* Make sure the height suits the 3 column (resp. not-editable) format; the 2 column format can easily fill space between the lists */ this->smallest_y = ComputeMaxSize(min_acs_height, this->smallest_y + this->resize_y - 1, this->resize_y); } virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { this->StoreSizePosition(sizing, x, y, given_width, given_height); uint min_avs_width = this->avs->smallest_x + this->avs->padding_left + this->avs->padding_right; uint min_acs_width = this->acs->smallest_x + this->acs->padding_left + this->acs->padding_right; uint min_inf_width = this->inf->smallest_x + this->inf->padding_left + this->inf->padding_right; uint min_list_width = max(min_avs_width, min_acs_width); // Smallest width of the lists such that they have equal width (incl padding). uint avs_extra_width = min_list_width - min_avs_width; // Additional width needed for avs to reach min_list_width. uint acs_extra_width = min_list_width - min_acs_width; // Additional width needed for acs to reach min_list_width. /* Use 2 or 3 columns? */ uint min_three_columns = min_avs_width + min_acs_width + min_inf_width + 2 * INTER_COLUMN_SPACING; uint min_two_columns = min_list_width + min_inf_width + INTER_COLUMN_SPACING; bool use_three_columns = this->editable && (min_three_columns + MIN_EXTRA_FOR_3_COLUMNS <= given_width); /* Info panel is a separate column in both modes. Compute its width first. */ uint extra_width, inf_width; if (use_three_columns) { extra_width = given_width - min_three_columns; inf_width = min(MAX_EXTRA_INFO_WIDTH, extra_width / 2); } else { extra_width = given_width - min_two_columns; inf_width = min(MAX_EXTRA_INFO_WIDTH, extra_width / 2); } inf_width = ComputeMaxSize(this->inf->smallest_x, this->inf->smallest_x + inf_width, this->inf->GetHorizontalStepSize(sizing)); extra_width -= inf_width - this->inf->smallest_x; uint inf_height = ComputeMaxSize(this->inf->smallest_y, given_height, this->inf->GetVerticalStepSize(sizing)); if (use_three_columns) { /* Three column display, first make both lists equally wide, then divide whatever is left between both lists. * Only keep track of what avs gets, all other space goes to acs. */ uint avs_width = min(avs_extra_width, extra_width); extra_width -= avs_width; extra_width -= min(acs_extra_width, extra_width); avs_width += extra_width / 2; avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_width, this->avs->GetHorizontalStepSize(sizing)); uint acs_width = given_width - // Remaining space, including horizontal padding. inf_width - this->inf->padding_left - this->inf->padding_right - avs_width - this->avs->padding_left - this->avs->padding_right - 2 * INTER_COLUMN_SPACING; acs_width = ComputeMaxSize(min_acs_width, acs_width, this->acs->GetHorizontalStepSize(sizing)) - this->acs->padding_left - this->acs->padding_right; /* Never use fill_y on these; the minimal size is chosen, so that the 3 column view looks nice */ uint avs_height = ComputeMaxSize(this->avs->smallest_y, given_height, this->avs->resize_y); uint acs_height = ComputeMaxSize(this->acs->smallest_y, given_height, this->acs->resize_y); /* Assign size and position to the children. */ if (rtl) { x += this->inf->padding_left; this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl); x += inf_width + this->inf->padding_right + INTER_COLUMN_SPACING; } else { x += this->avs->padding_left; this->avs->AssignSizePosition(sizing, x, y + this->avs->padding_top, avs_width, avs_height, rtl); x += avs_width + this->avs->padding_right + INTER_COLUMN_SPACING; } x += this->acs->padding_left; this->acs->AssignSizePosition(sizing, x, y + this->acs->padding_top, acs_width, acs_height, rtl); x += acs_width + this->acs->padding_right + INTER_COLUMN_SPACING; if (rtl) { x += this->avs->padding_left; this->avs->AssignSizePosition(sizing, x, y + this->avs->padding_top, avs_width, avs_height, rtl); } else { x += this->inf->padding_left; this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl); } } else { /* Two columns, all space in extra_width goes to both lists. Since the lists are underneath each other, * the column is min_list_width wide at least. */ uint avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_extra_width + extra_width, this->avs->GetHorizontalStepSize(sizing)); uint acs_width = ComputeMaxSize(this->acs->smallest_x, this->acs->smallest_x + acs_extra_width + extra_width, this->acs->GetHorizontalStepSize(sizing)); uint min_avs_height = (!this->editable) ? 0 : this->avs->smallest_y + this->avs->padding_top + this->avs->padding_bottom + INTER_LIST_SPACING; uint min_acs_height = this->acs->smallest_y + this->acs->padding_top + this->acs->padding_bottom; uint extra_height = given_height - min_acs_height - min_avs_height; /* Never use fill_y on these; instead use the INTER_LIST_SPACING as filler */ uint avs_height = ComputeMaxSize(this->avs->smallest_y, this->avs->smallest_y + extra_height / 2, this->avs->resize_y); if (this->editable) extra_height -= avs_height - this->avs->smallest_y; uint acs_height = ComputeMaxSize(this->acs->smallest_y, this->acs->smallest_y + extra_height, this->acs->resize_y); /* Assign size and position to the children. */ if (rtl) { x += this->inf->padding_left; this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl); x += inf_width + this->inf->padding_right + INTER_COLUMN_SPACING; this->acs->AssignSizePosition(sizing, x + this->acs->padding_left, y + this->acs->padding_top, acs_width, acs_height, rtl); if (this->editable) { this->avs->AssignSizePosition(sizing, x + this->avs->padding_left, y + given_height - avs_height - this->avs->padding_bottom, avs_width, avs_height, rtl); } else { this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl); } } else { this->acs->AssignSizePosition(sizing, x + this->acs->padding_left, y + this->acs->padding_top, acs_width, acs_height, rtl); if (this->editable) { this->avs->AssignSizePosition(sizing, x + this->avs->padding_left, y + given_height - avs_height - this->avs->padding_bottom, avs_width, avs_height, rtl); } else { this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl); } uint dx = this->acs->current_x + this->acs->padding_left + this->acs->padding_right; if (this->editable) { dx = max(dx, this->avs->current_x + this->avs->padding_left + this->avs->padding_right); } x += dx + INTER_COLUMN_SPACING + this->inf->padding_left; this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl); } } } virtual NWidgetCore *GetWidgetFromPos(int x, int y) { if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : NULL; if (nw == NULL) nw = this->acs->GetWidgetFromPos(x, y); if (nw == NULL) nw = this->inf->GetWidgetFromPos(x, y); return nw; } virtual void Draw(const Window *w) { if (this->editable) this->avs->Draw(w); this->acs->Draw(w); this->inf->Draw(w); } }; const uint NWidgetNewGRFDisplay::INTER_LIST_SPACING = WD_RESIZEBOX_WIDTH + 1; const uint NWidgetNewGRFDisplay::INTER_COLUMN_SPACING = WD_RESIZEBOX_WIDTH; const uint NWidgetNewGRFDisplay::MAX_EXTRA_INFO_WIDTH = 150; const uint NWidgetNewGRFDisplay::MIN_EXTRA_FOR_3_COLUMNS = 50; static const NWidgetPart _nested_newgrf_actives_widgets[] = { /* Left side, presets. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXT, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_SELECT_PRESET, STR_NULL), SetPadding(0, WD_FRAMETEXT_RIGHT, 0, 0), NWidget(WWT_DROPDOWN, COLOUR_YELLOW, WID_NS_PRESET_LIST), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING, STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_SAVE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_PRESET_SAVE, STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_DELETE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_PRESET_DELETE, STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, WD_RESIZEBOX_WIDTH), SetResize(1, 0), SetFill(1, 0), NWidget(WWT_PANEL, COLOUR_MAUVE), NWidget(WWT_LABEL, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_ACTIVE_LIST, STR_NULL), SetFill(1, 0), SetResize(1, 0), SetPadding(3, WD_FRAMETEXT_RIGHT, 0, WD_FRAMETEXT_LEFT), /* Left side, active grfs. */ NWidget(NWID_HORIZONTAL), SetPadding(0, 2, 0, 2), NWidget(WWT_PANEL, COLOUR_MAUVE), NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_FILE_LIST), SetMinimalSize(100, 1), SetPadding(2, 2, 2, 2), SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLLBAR), SetDataTip(STR_NULL, STR_NEWGRF_SETTINGS_FILE_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NS_SCROLLBAR), EndContainer(), /* Buttons. */ NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_REMOVE), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPadding(2, 2, 2, 2), SetPIP(0, WD_RESIZEBOX_WIDTH, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_REMOVE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_REMOVE, STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP), NWidget(NWID_VERTICAL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_UP), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_MOVEUP, STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_DOWN), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_MOVEDOWN, STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_UPGRADE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_UPGRADE, STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPadding(2, 2, 2, 2), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES2), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD2), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), EndContainer(), EndContainer(), EndContainer(), }; static const NWidgetPart _nested_newgrf_availables_widgets[] = { NWidget(WWT_PANEL, COLOUR_MAUVE), NWidget(WWT_LABEL, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_INACTIVE_LIST, STR_NULL), SetFill(1, 0), SetResize(1, 0), SetPadding(3, WD_FRAMETEXT_RIGHT, 0, WD_FRAMETEXT_LEFT), /* Left side, available grfs, filter edit box. */ NWidget(NWID_HORIZONTAL), SetPadding(WD_TEXTPANEL_TOP, 0, WD_TEXTPANEL_BOTTOM, 0), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_NEWGRF_FILTER_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_NS_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), /* Left side, available grfs. */ NWidget(NWID_HORIZONTAL), SetPadding(0, 2, 0, 2), NWidget(WWT_PANEL, COLOUR_MAUVE), NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_AVAIL_LIST), SetMinimalSize(100, 1), SetPadding(2, 2, 2, 2), SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLL2BAR), EndContainer(), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NS_SCROLL2BAR), EndContainer(), /* Left side, available grfs, buttons. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPadding(2, 2, 2, 2), SetPIP(0, WD_RESIZEBOX_WIDTH, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_ADD), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_ADD, STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP), NWidget(NWID_VERTICAL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), EndContainer(), EndContainer(), EndContainer(), }; static const NWidgetPart _nested_newgrf_infopanel_widgets[] = { /* Right side, info panel. */ NWidget(NWID_VERTICAL), SetPadding(0, 0, 2, 0), NWidget(WWT_PANEL, COLOUR_MAUVE), SetPadding(0, 0, 2, 0), NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO_TITLE), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO), SetFill(1, 1), SetResize(1, 1), SetMinimalSize(150, 100), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_OPEN_URL), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_APPLY), /* Right side, buttons. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WD_RESIZEBOX_WIDTH, 0), NWidget(NWID_VERTICAL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_SET_PARAMETERS), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_TOGGLE_PALETTE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_TOGGLE_PALETTE, STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_APPLY_CHANGES), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_APPLY_CHANGES, STR_NULL), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_VIEW_PARAMETERS), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_SHOW_PARAMETERS, STR_NULL), EndContainer(), }; /** Construct nested container widget for managing the lists and the info panel of the NewGRF GUI. */ NWidgetBase* NewGRFDisplay(int *biggest_index) { NWidgetBase *avs = MakeNWidgets(_nested_newgrf_availables_widgets, lengthof(_nested_newgrf_availables_widgets), biggest_index, NULL); int biggest2; NWidgetBase *acs = MakeNWidgets(_nested_newgrf_actives_widgets, lengthof(_nested_newgrf_actives_widgets), &biggest2, NULL); *biggest_index = max(*biggest_index, biggest2); NWidgetBase *inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, lengthof(_nested_newgrf_infopanel_widgets), &biggest2, NULL); *biggest_index = max(*biggest_index, biggest2); return new NWidgetNewGRFDisplay(avs, acs, inf); } /* Widget definition of the manage newgrfs window */ static const NWidgetPart _nested_newgrf_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), EndContainer(), NWidget(WWT_PANEL, COLOUR_MAUVE), NWidgetFunction(NewGRFDisplay), SetPadding(WD_RESIZEBOX_WIDTH, WD_RESIZEBOX_WIDTH, 2, WD_RESIZEBOX_WIDTH), /* Resize button. */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), EndContainer(), EndContainer(), }; /* Window definition of the manage newgrfs window */ static WindowDesc _newgrf_desc( WDP_CENTER, "settings_newgrf", 300, 263, WC_GAME_OPTIONS, WC_NONE, 0, _nested_newgrf_widgets, lengthof(_nested_newgrf_widgets) ); /** * Callback function for the newgrf 'apply changes' confirmation window * @param w Window which is calling this callback * @param confirmed boolean value, true when yes was clicked, false otherwise */ static void NewGRFConfirmationCallback(Window *w, bool confirmed) { if (confirmed) { DeleteWindowByClass(WC_GRF_PARAMETERS); NewGRFWindow *nw = dynamic_cast(w); GamelogStartAction(GLAT_GRF); GamelogGRFUpdate(_grfconfig, nw->actives); // log GRF changes CopyGRFConfigList(nw->orig_list, nw->actives, false); ReloadNewGRFData(); GamelogStopAction(); /* Show new, updated list */ GRFConfig *c; int i = 0; for (c = nw->actives; c != NULL && c != nw->active_sel; c = c->next, i++) {} CopyGRFConfigList(&nw->actives, *nw->orig_list, false); for (c = nw->actives; c != NULL && i > 0; c = c->next, i--) {} nw->active_sel = c; nw->avails.ForceRebuild(); w->InvalidateData(); ReInitAllWindows(); DeleteWindowByClass(WC_BUILD_OBJECT); } } /** * Setup the NewGRF gui * @param editable allow the user to make changes to the grfconfig in the window * @param show_params show information about what parameters are set for the grf files * @param exec_changes if changes are made to the list (editable is true), apply these * changes immediately or only update the list * @param config pointer to a linked-list of grfconfig's that will be shown */ void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config) { DeleteWindowByClass(WC_GAME_OPTIONS); new NewGRFWindow(&_newgrf_desc, editable, show_params, exec_changes, config); } /** Widget parts of the save preset window. */ static const NWidgetPart _nested_save_preset_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_SAVE_PRESET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), NWidget(WWT_INSET, COLOUR_GREY, WID_SVP_PRESET_LIST), SetPadding(2, 1, 0, 2), SetDataTip(0x0, STR_SAVE_PRESET_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SVP_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SVP_SCROLLBAR), EndContainer(), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SVP_EDITBOX), SetPadding(3, 2, 2, 2), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_SAVE_PRESET_TITLE, STR_SAVE_PRESET_EDITBOX_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_CANCEL), SetDataTip(STR_SAVE_PRESET_CANCEL, STR_SAVE_PRESET_CANCEL_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SVP_SAVE), SetDataTip(STR_SAVE_PRESET_SAVE, STR_SAVE_PRESET_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; /** Window description of the preset save window. */ static WindowDesc _save_preset_desc( WDP_CENTER, "save_preset", 140, 110, WC_SAVE_PRESET, WC_GAME_OPTIONS, WDF_MODAL, _nested_save_preset_widgets, lengthof(_nested_save_preset_widgets) ); /** Class for the save preset window. */ struct SavePresetWindow : public Window { QueryString presetname_editbox; ///< Edit box of the save preset. GRFPresetList presets; ///< Available presets. Scrollbar *vscroll; ///< Pointer to the scrollbar widget. int selected; ///< Selected entry in the preset list, or \c -1 if none selected. /** * Constructor of the save preset window. * @param initial_text Initial text to display in the edit box, or \c NULL. */ SavePresetWindow(const char *initial_text) : Window(&_save_preset_desc), presetname_editbox(32) { GetGRFPresetList(&this->presets); this->selected = -1; if (initial_text != NULL) { for (uint i = 0; i < this->presets.Length(); i++) { if (!strcmp(initial_text, this->presets[i])) { this->selected = i; break; } } } this->querystrings[WID_SVP_EDITBOX] = &this->presetname_editbox; this->presetname_editbox.ok_button = WID_SVP_SAVE; this->presetname_editbox.cancel_button = WID_SVP_CANCEL; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_SVP_SCROLLBAR); this->FinishInitNested(0); this->vscroll->SetCount(this->presets.Length()); this->SetFocusedWidget(WID_SVP_EDITBOX); if (initial_text != NULL) this->presetname_editbox.text.Assign(initial_text); } ~SavePresetWindow() { } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SVP_PRESET_LIST: { resize->height = FONT_HEIGHT_NORMAL + 2U; size->height = 0; for (uint i = 0; i < this->presets.Length(); i++) { Dimension d = GetStringBoundingBox(this->presets[i]); size->width = max(size->width, d.width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); resize->height = max(resize->height, d.height); } size->height = ClampU(this->presets.Length(), 5, 20) * resize->height + 1; break; } } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_SVP_PRESET_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK); uint step_height = this->GetWidget(WID_SVP_PRESET_LIST)->resize_y; int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2; uint y = r.top + WD_FRAMERECT_TOP; uint min_index = this->vscroll->GetPosition(); uint max_index = min(min_index + this->vscroll->GetCapacity(), this->presets.Length()); for (uint i = min_index; i < max_index; i++) { if ((int)i == this->selected) GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 2, PC_DARK_BLUE); const char *text = this->presets[i]; DrawString(r.left + WD_FRAMERECT_LEFT, r.right, y + offset_y, text, ((int)i == this->selected) ? TC_WHITE : TC_SILVER); y += step_height; } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_SVP_PRESET_LIST: { uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SVP_PRESET_LIST); if (row < this->presets.Length()) { this->selected = row; this->presetname_editbox.text.Assign(this->presets[row]); this->SetWidgetDirty(WID_SVP_PRESET_LIST); this->SetWidgetDirty(WID_SVP_EDITBOX); } break; } case WID_SVP_CANCEL: delete this; break; case WID_SVP_SAVE: { Window *w = FindWindowById(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE); if (w != NULL && !StrEmpty(this->presetname_editbox.text.buf)) w->OnQueryTextFinished(this->presetname_editbox.text.buf); delete this; break; } } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_SVP_PRESET_LIST); } }; /** * Open the window for saving a preset. * @param initial_text Initial text to display in the edit box, or \c NULL. */ static void ShowSavePresetWindow(const char *initial_text) { DeleteWindowByClass(WC_SAVE_PRESET); new SavePresetWindow(initial_text); } /** Widgets for the progress window. */ static const NWidgetPart _nested_scan_progress_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NEWGRF_SCAN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), SetPIP(20, 0, 20), NWidget(NWID_VERTICAL), SetPIP(11, 8, 11), NWidget(WWT_LABEL, INVALID_COLOUR), SetDataTip(STR_NEWGRF_SCAN_MESSAGE, STR_NULL), SetFill(1, 0), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_BAR), SetFill(1, 0), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_TEXT), SetFill(1, 0), EndContainer(), EndContainer(), EndContainer(), }; /** Description of the widgets and other settings of the window. */ static WindowDesc _scan_progress_desc( WDP_CENTER, NULL, 0, 0, WC_MODAL_PROGRESS, WC_NONE, 0, _nested_scan_progress_widgets, lengthof(_nested_scan_progress_widgets) ); /** Window for showing the progress of NewGRF scanning. */ struct ScanProgressWindow : public Window { char *last_name; ///< The name of the last 'seen' NewGRF. int scanned; ///< The number of NewGRFs that we have seen. /** Create the window. */ ScanProgressWindow() : Window(&_scan_progress_desc), last_name(NULL), scanned(0) { this->InitNested(1); } /** Free the last name buffer. */ ~ScanProgressWindow() { free(last_name); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SP_PROGRESS_BAR: { SetDParamMaxValue(0, 100); *size = GetStringBoundingBox(STR_GENERATION_PROGRESS); /* We need some spacing for the 'border' */ size->height += 8; size->width += 8; break; } case WID_SP_PROGRESS_TEXT: SetDParamMaxDigits(0, 4); SetDParamMaxDigits(1, 4); /* We really don't know the width. We could determine it by scanning the NewGRFs, * but this is the status window for scanning them... */ size->width = max(400U, GetStringBoundingBox(STR_NEWGRF_SCAN_STATUS).width); size->height = FONT_HEIGHT_NORMAL * 2 + WD_PAR_VSEP_NORMAL; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_SP_PROGRESS_BAR: { /* Draw the % complete with a bar and a text */ DrawFrameRect(r.left, r.top, r.right, r.bottom, COLOUR_GREY, FR_BORDERONLY); uint percent = scanned * 100 / max(1U, _settings_client.gui.last_newgrf_count); DrawFrameRect(r.left + 1, r.top + 1, (int)((r.right - r.left - 2) * percent / 100) + r.left + 1, r.bottom - 1, COLOUR_MAUVE, FR_NONE); SetDParam(0, percent); DrawString(r.left, r.right, r.top + 5, STR_GENERATION_PROGRESS, TC_FROMSTRING, SA_HOR_CENTER); break; } case WID_SP_PROGRESS_TEXT: SetDParam(0, this->scanned); SetDParam(1, _settings_client.gui.last_newgrf_count); DrawString(r.left, r.right, r.top, STR_NEWGRF_SCAN_STATUS, TC_FROMSTRING, SA_HOR_CENTER); DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL, this->last_name == NULL ? "" : this->last_name, TC_BLACK, SA_HOR_CENTER); break; } } /** * Update the NewGRF scan status. * @param num The number of NewGRFs scanned so far. * @param name The name of the last scanned NewGRF. */ void UpdateNewGRFScanStatus(uint num, const char *name) { free(this->last_name); if (name == NULL) { char buf[256]; GetString(buf, STR_NEWGRF_SCAN_ARCHIVES, lastof(buf)); this->last_name = stredup(buf); } else { this->last_name = stredup(name); } this->scanned = num; if (num > _settings_client.gui.last_newgrf_count) _settings_client.gui.last_newgrf_count = num; this->SetDirty(); } }; /** * Update the NewGRF scan status. * @param num The number of NewGRFs scanned so far. * @param name The name of the last scanned NewGRF. */ void UpdateNewGRFScanStatus(uint num, const char *name) { ScanProgressWindow *w = dynamic_cast(FindWindowByClass(WC_MODAL_PROGRESS)); if (w == NULL) w = new ScanProgressWindow(); w->UpdateNewGRFScanStatus(num, name); } openttd-1.5.3/src/strgen/0000755000000000000000000000000012627373435014000 5ustar rootrootopenttd-1.5.3/src/strgen/strgen.h0000644000000000000000000001134312627373435015455 0ustar rootroot/* $Id: strgen.h 26511 2014-04-25 17:43:09Z rubidium $ */ /* * 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 strgen.h Structures related to strgen. */ #ifndef STRGEN_H #define STRGEN_H #include "../language.h" /** Container for the different cases of a string. */ struct Case { int caseidx; ///< The index of the case. char *string; ///< The translation of the case. Case *next; ///< The next, chained, case. Case(int caseidx, const char *string, Case *next); ~Case(); }; /** Information about a single string. */ struct LangString { char *name; ///< Name of the string. char *english; ///< English text. char *translated; ///< Translated text. uint16 hash_next; ///< Next hash entry. uint16 index; ///< The index in the language file. int line; ///< Line of string in source-file. Case *translated_case; ///< Cases of the translation. LangString(const char *name, const char *english, int index, int line); ~LangString(); void FreeTranslation(); }; /** Information about the currently known strings. */ struct StringData { LangString **strings; ///< Array of all known strings. uint16 *hash_heads; ///< Hash table for the strings. size_t tabs; ///< The number of 'tabs' of strings. size_t max_strings; ///< The maximum number of strings. int next_string_id; ///< The next string ID to allocate. StringData(size_t tabs); ~StringData(); void FreeTranslation(); uint HashStr(const char *s) const; void Add(const char *s, LangString *ls); LangString *Find(const char *s); uint VersionHashStr(uint hash, const char *s) const; uint Version() const; uint CountInUse(uint tab) const; }; /** Helper for reading strings. */ struct StringReader { StringData &data; ///< The data to fill during reading. const char *file; ///< The file we are reading. bool master; ///< Are we reading the master file? bool translation; ///< Are we reading a translation, implies !master. However, the base translation will have this false. StringReader(StringData &data, const char *file, bool master, bool translation); virtual ~StringReader(); void HandleString(char *str); /** * Read a single line from the source of strings. * @param buffer The buffer to read the data in to. * @param last The last element in the buffer. * @return The buffer, or NULL if at the end of the file. */ virtual char *ReadLine(char *buffer, const char *last) = 0; /** * Handle the pragma of the file. * @param str The pragma string to parse. */ virtual void HandlePragma(char *str); /** * Start parsing the file. */ virtual void ParseFile(); }; /** Base class for writing the header, i.e. the STR_XXX to numeric value. */ struct HeaderWriter { /** * Write the string ID. * @param name The name of the string. * @param stringid The ID of the string. */ virtual void WriteStringID(const char *name, int stringid) = 0; /** * Finalise writing the file. * @param data The data about the string. */ virtual void Finalise(const StringData &data) = 0; /** Especially destroy the subclasses. */ virtual ~HeaderWriter() {}; void WriteHeader(const StringData &data); }; /** Base class for all language writers. */ struct LanguageWriter { /** * Write the header metadata. The multi-byte integers are already converted to * the little endian format. * @param header The header to write. */ virtual void WriteHeader(const LanguagePackHeader *header) = 0; /** * Write a number of bytes. * @param buffer The buffer to write. * @param length The amount of byte to write. */ virtual void Write(const byte *buffer, size_t length) = 0; /** * Finalise writing the file. */ virtual void Finalise() = 0; /** Especially destroy the subclasses. */ virtual ~LanguageWriter() {} virtual void WriteLength(uint length); virtual void WriteLang(const StringData &data); }; void CDECL strgen_warning(const char *s, ...) WARN_FORMAT(1, 2); void CDECL strgen_error(const char *s, ...) WARN_FORMAT(1, 2); void NORETURN CDECL strgen_fatal(const char *s, ...) WARN_FORMAT(1, 2); char *ParseWord(char **buf); extern const char *_file; extern int _cur_line; extern int _errors, _warnings, _show_todo; extern LanguagePackHeader _lang; #endif /* STRGEN_H */ openttd-1.5.3/src/strgen/strgen_base.cpp0000644000000000000000000006552012627373435017010 0ustar rootroot/* $Id: strgen_base.cpp 26511 2014-04-25 17:43:09Z rubidium $ */ /* * 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 strgen_base.cpp Tool to create computer readable (stand-alone) translation files. */ #include "../stdafx.h" #include "../core/endian_func.hpp" #include "../string_func.h" #include "../table/control_codes.h" #include "strgen.h" #include "../table/strgen_tables.h" #include "../safeguards.h" /* Compiles a list of strings into a compiled string list */ static bool _translated; ///< Whether the current language is not the master language static bool _translation; ///< Is the current file actually a translation or not const char *_file = "(unknown file)"; ///< The filename of the input, so we can refer to it in errors/warnings int _cur_line; ///< The current line we're parsing in the input file int _errors, _warnings, _show_todo; LanguagePackHeader _lang; ///< Header information about a language. static const ptrdiff_t MAX_COMMAND_PARAM_SIZE = 100; ///< Maximum size of every command block, not counting the name of the command itself static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei); /** * Create a new case. * @param caseidx The index of the case. * @param string The translation of the case. * @param next The next chained case. */ Case::Case(int caseidx, const char *string, Case *next) : caseidx(caseidx), string(stredup(string)), next(next) { } /** Free everything we allocated. */ Case::~Case() { free(this->string); delete this->next; } /** * Create a new string. * @param name The name of the string. * @param english The english "translation" of the string. * @param index The index in the string table. * @param line The line this string was found on. */ LangString::LangString(const char *name, const char *english, int index, int line) : name(stredup(name)), english(stredup(english)), translated(NULL), hash_next(0), index(index), line(line), translated_case(NULL) { } /** Free everything we allocated. */ LangString::~LangString() { free(this->name); free(this->english); free(this->translated); delete this->translated_case; } /** Free all data related to the translation. */ void LangString::FreeTranslation() { free(this->translated); this->translated = NULL; delete this->translated_case; this->translated_case = NULL; } /** * Create a new string data container. * @param max_strings The maximum number of strings. */ StringData::StringData(size_t tabs) : tabs(tabs), max_strings(tabs * TAB_SIZE) { this->strings = CallocT(max_strings); this->hash_heads = CallocT(max_strings); this->next_string_id = 0; } /** Free everything we allocated. */ StringData::~StringData() { for (size_t i = 0; i < this->max_strings; i++) delete this->strings[i]; free(this->strings); free(this->hash_heads); } /** Free all data related to the translation. */ void StringData::FreeTranslation() { for (size_t i = 0; i < this->max_strings; i++) { LangString *ls = this->strings[i]; if (ls != NULL) ls->FreeTranslation(); } } /** * Create a hash of the string for finding them back quickly. * @param s The string to hash. * @return The hashed string. */ uint StringData::HashStr(const char *s) const { uint hash = 0; for (; *s != '\0'; s++) hash = ROL(hash, 3) ^ *s; return hash % this->max_strings; } /** * Add a newly created LangString. * @param s The name of the string. * @param ls The string to add. */ void StringData::Add(const char *s, LangString *ls) { uint hash = this->HashStr(s); ls->hash_next = this->hash_heads[hash]; /* Off-by-one for hash find. */ this->hash_heads[hash] = ls->index + 1; this->strings[ls->index] = ls; } /** * Find a LangString based on the string name. * @param s The string name to search on. * @return The LangString or NULL if it is not known. */ LangString *StringData::Find(const char *s) { int idx = this->hash_heads[this->HashStr(s)]; while (--idx >= 0) { LangString *ls = this->strings[idx]; if (strcmp(ls->name, s) == 0) return ls; idx = ls->hash_next; } return NULL; } /** * Create a compound hash. * @param hash The hash to add the string hash to. * @param s The string hash. * @return The new hash. */ uint StringData::VersionHashStr(uint hash, const char *s) const { for (; *s != '\0'; s++) { hash = ROL(hash, 3) ^ *s; hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1); } return hash; } /** * Make a hash of the file to get a unique "version number" * @return The version number. */ uint StringData::Version() const { uint hash = 0; for (size_t i = 0; i < this->max_strings; i++) { const LangString *ls = this->strings[i]; if (ls != NULL) { const CmdStruct *cs; const char *s; char buf[MAX_COMMAND_PARAM_SIZE]; int argno; int casei; s = ls->name; hash ^= i * 0x717239; hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1); hash = this->VersionHashStr(hash, s + 1); s = ls->english; while ((cs = ParseCommandString(&s, buf, &argno, &casei)) != NULL) { if (cs->flags & C_DONTCOUNT) continue; hash ^= (cs - _cmd_structs) * 0x1234567; hash = (hash & 1 ? hash >> 1 ^ 0xF00BAA4 : hash >> 1); } } } return hash; } /** * Count the number of tab elements that are in use. * @param tab The tab to count the elements of. */ uint StringData::CountInUse(uint tab) const { int i; for (i = TAB_SIZE; --i >= 0;) if (this->strings[(tab * TAB_SIZE) + i] != NULL) break; return i + 1; } static const char *_cur_ident; struct CmdPair { const CmdStruct *a; const char *v; }; struct ParsedCommandStruct { uint np; CmdPair pairs[32]; const CmdStruct *cmd[32]; // ordered by param # }; /* Used when generating some advanced commands. */ static ParsedCommandStruct _cur_pcs; static int _cur_argidx; /** The buffer for writing a single string. */ struct Buffer : SmallVector { /** * Convenience method for adding a byte. * @param value The value to add. */ void AppendByte(byte value) { *this->Append() = value; } /** * Add an Unicode character encoded in UTF-8 to the buffer. * @param value The character to add. */ void AppendUtf8(uint32 value) { if (value < 0x80) { *this->Append() = value; } else if (value < 0x800) { *this->Append() = 0xC0 + GB(value, 6, 5); *this->Append() = 0x80 + GB(value, 0, 6); } else if (value < 0x10000) { *this->Append() = 0xE0 + GB(value, 12, 4); *this->Append() = 0x80 + GB(value, 6, 6); *this->Append() = 0x80 + GB(value, 0, 6); } else if (value < 0x110000) { *this->Append() = 0xF0 + GB(value, 18, 3); *this->Append() = 0x80 + GB(value, 12, 6); *this->Append() = 0x80 + GB(value, 6, 6); *this->Append() = 0x80 + GB(value, 0, 6); } else { strgen_warning("Invalid unicode value U+0x%X", value); } } }; size_t Utf8Validate(const char *s) { uint32 c; if (!HasBit(s[0], 7)) { /* 1 byte */ return 1; } else if (GB(s[0], 5, 3) == 6 && IsUtf8Part(s[1])) { /* 2 bytes */ c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6); if (c >= 0x80) return 2; } else if (GB(s[0], 4, 4) == 14 && IsUtf8Part(s[1]) && IsUtf8Part(s[2])) { /* 3 bytes */ c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6); if (c >= 0x800) return 3; } else if (GB(s[0], 3, 5) == 30 && IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) { /* 4 bytes */ c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6); if (c >= 0x10000 && c <= 0x10FFFF) return 4; } return 0; } void EmitSingleChar(Buffer *buffer, char *buf, int value) { if (*buf != '\0') strgen_warning("Ignoring trailing letters in command"); buffer->AppendUtf8(value); } /* The plural specifier looks like * {NUM} {PLURAL -1 passenger passengers} then it picks either passenger/passengers depending on the count in NUM */ /* This is encoded like * CommandByte {Length of each string} {each string} */ bool ParseRelNum(char **buf, int *value, int *offset) { const char *s = *buf; char *end; bool rel = false; while (*s == ' ' || *s == '\t') s++; if (*s == '+') { rel = true; s++; } int v = strtol(s, &end, 0); if (end == s) return false; if (rel || v < 0) { *value += v; } else { *value = v; } if (offset != NULL && *end == ':') { /* Take the Nth within */ s = end + 1; *offset = strtol(s, &end, 0); if (end == s) return false; } *buf = end; return true; } /* Parse out the next word, or NULL */ char *ParseWord(char **buf) { char *s = *buf, *r; while (*s == ' ' || *s == '\t') s++; if (*s == '\0') return NULL; if (*s == '"') { r = ++s; /* parse until next " or NUL */ for (;;) { if (*s == '\0') break; if (*s == '"') { *s++ = '\0'; break; } s++; } } else { /* proceed until whitespace or NUL */ r = s; for (;;) { if (*s == '\0') break; if (*s == ' ' || *s == '\t') { *s++ = '\0'; break; } s++; } } *buf = s; return r; } /* Forward declaration */ static int TranslateArgumentIdx(int arg, int offset = 0); static void EmitWordList(Buffer *buffer, const char * const *words, uint nw) { buffer->AppendByte(nw); for (uint i = 0; i < nw; i++) buffer->AppendByte((uint)strlen(words[i]) + 1); for (uint i = 0; i < nw; i++) { for (uint j = 0; words[i][j] != '\0'; j++) buffer->AppendByte(words[i][j]); buffer->AppendByte(0); } } void EmitPlural(Buffer *buffer, char *buf, int value) { int argidx = _cur_argidx; int offset = 0; int expected = _plural_forms[_lang.plural_form].plural_count; const char **words = AllocaM(const char *, max(expected, MAX_PLURALS)); int nw = 0; /* Parse out the number, if one exists. Otherwise default to prev arg. */ if (!ParseRelNum(&buf, &argidx, &offset)) argidx--; /* Parse each string */ for (nw = 0; nw < MAX_PLURALS; nw++) { words[nw] = ParseWord(&buf); if (words[nw] == NULL) break; } if (nw == 0) { strgen_fatal("%s: No plural words", _cur_ident); } if (expected != nw) { if (_translated) { strgen_fatal("%s: Invalid number of plural forms. Expecting %d, found %d.", _cur_ident, expected, nw); } else { if ((_show_todo & 2) != 0) strgen_warning("'%s' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident); if (nw > expected) { nw = expected; } else { for (; nw < expected; nw++) { words[nw] = words[nw - 1]; } } } } buffer->AppendUtf8(SCC_PLURAL_LIST); buffer->AppendByte(_lang.plural_form); buffer->AppendByte(TranslateArgumentIdx(argidx, offset)); EmitWordList(buffer, words, nw); } void EmitGender(Buffer *buffer, char *buf, int value) { int argidx = _cur_argidx; int offset = 0; uint nw; if (buf[0] == '=') { buf++; /* This is a {G=DER} command */ nw = _lang.GetGenderIndex(buf); if (nw >= MAX_NUM_GENDERS) strgen_fatal("G argument '%s' invalid", buf); /* now nw contains the gender index */ buffer->AppendUtf8(SCC_GENDER_INDEX); buffer->AppendByte(nw); } else { const char *words[MAX_NUM_GENDERS]; /* This is a {G 0 foo bar two} command. * If no relative number exists, default to +0 */ if (!ParseRelNum(&buf, &argidx, &offset)) {} const CmdStruct *cmd = _cur_pcs.cmd[argidx]; if (cmd == NULL || (cmd->flags & C_GENDER) == 0) { strgen_fatal("Command '%s' can't have a gender", cmd == NULL ? "" : cmd->cmd); } for (nw = 0; nw < MAX_NUM_GENDERS; nw++) { words[nw] = ParseWord(&buf); if (words[nw] == NULL) break; } if (nw != _lang.num_genders) strgen_fatal("Bad # of arguments for gender command"); assert(IsInsideBS(cmd->value, SCC_CONTROL_START, UINT8_MAX)); buffer->AppendUtf8(SCC_GENDER_LIST); buffer->AppendByte(TranslateArgumentIdx(argidx, offset)); EmitWordList(buffer, words, nw); } } static const CmdStruct *FindCmd(const char *s, int len) { for (const CmdStruct *cs = _cmd_structs; cs != endof(_cmd_structs); cs++) { if (strncmp(cs->cmd, s, len) == 0 && cs->cmd[len] == '\0') return cs; } return NULL; } static uint ResolveCaseName(const char *str, size_t len) { /* First get a clean copy of only the case name, then resolve it. */ char case_str[CASE_GENDER_LEN]; len = min(lengthof(case_str) - 1, len); memcpy(case_str, str, len); case_str[len] = '\0'; uint8 case_idx = _lang.GetCaseIndex(case_str); if (case_idx >= MAX_NUM_CASES) strgen_fatal("Invalid case-name '%s'", case_str); return case_idx + 1; } /* returns NULL on eof * else returns command struct */ static const CmdStruct *ParseCommandString(const char **str, char *param, int *argno, int *casei) { const char *s = *str, *start; char c; *argno = -1; *casei = -1; /* Scan to the next command, exit if there's no next command. */ for (; *s != '{'; s++) { if (*s == '\0') return NULL; } s++; // Skip past the { if (*s >= '0' && *s <= '9') { char *end; *argno = strtoul(s, &end, 0); if (*end != ':') strgen_fatal("missing arg #"); s = end + 1; } /* parse command name */ start = s; do { c = *s++; } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); const CmdStruct *cmd = FindCmd(start, s - start - 1); if (cmd == NULL) { strgen_error("Undefined command '%.*s'", (int)(s - start - 1), start); return NULL; } if (c == '.') { const char *casep = s; if (!(cmd->flags & C_CASE)) { strgen_fatal("Command '%s' can't have a case", cmd->cmd); } do { c = *s++; } while (c != '}' && c != ' ' && c != '\0'); *casei = ResolveCaseName(casep, s - casep - 1); } if (c == '\0') { strgen_error("Missing } from command '%s'", start); return NULL; } if (c != '}') { if (c == '=') s--; /* copy params */ start = s; for (;;) { c = *s++; if (c == '}') break; if (c == '\0') { strgen_error("Missing } from command '%s'", start); return NULL; } if (s - start == MAX_COMMAND_PARAM_SIZE) error("param command too long"); *param++ = c; } } *param = '\0'; *str = s; return cmd; } /** * Prepare reading. * @param data The data to fill during reading. * @param file The file we are reading. * @param master Are we reading the master file? * @param translation Are we reading a translation? */ StringReader::StringReader(StringData &data, const char *file, bool master, bool translation) : data(data), file(stredup(file)), master(master), translation(translation) { } /** Make sure the right reader gets freed. */ StringReader::~StringReader() { free(file); } static void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool warnings) { char param[MAX_COMMAND_PARAM_SIZE]; int argno; int argidx = 0; int casei; memset(p, 0, sizeof(*p)); for (;;) { /* read until next command from a. */ const CmdStruct *ar = ParseCommandString(&s, param, &argno, &casei); if (ar == NULL) break; /* Sanity checking */ if (argno != -1 && ar->consumes == 0) strgen_fatal("Non consumer param can't have a paramindex"); if (ar->consumes) { if (argno != -1) argidx = argno; if (argidx < 0 || (uint)argidx >= lengthof(p->cmd)) strgen_fatal("invalid param idx %d", argidx); if (p->cmd[argidx] != NULL && p->cmd[argidx] != ar) strgen_fatal("duplicate param idx %d", argidx); p->cmd[argidx++] = ar; } else if (!(ar->flags & C_DONTCOUNT)) { // Ignore some of them if (p->np >= lengthof(p->pairs)) strgen_fatal("too many commands in string, max " PRINTF_SIZE, lengthof(p->pairs)); p->pairs[p->np].a = ar; p->pairs[p->np].v = param[0] != '\0' ? stredup(param) : ""; p->np++; } } } static const CmdStruct *TranslateCmdForCompare(const CmdStruct *a) { if (a == NULL) return NULL; if (strcmp(a->cmd, "STRING1") == 0 || strcmp(a->cmd, "STRING2") == 0 || strcmp(a->cmd, "STRING3") == 0 || strcmp(a->cmd, "STRING4") == 0 || strcmp(a->cmd, "STRING5") == 0 || strcmp(a->cmd, "STRING6") == 0 || strcmp(a->cmd, "STRING7") == 0 || strcmp(a->cmd, "RAW_STRING") == 0) { return FindCmd("STRING", 6); } return a; } static bool CheckCommandsMatch(char *a, char *b, const char *name) { /* If we're not translating, i.e. we're compiling the base language, * it is pointless to do all these checks as it'll always be correct. * After all, all checks are based on the base language. */ if (!_translation) return true; ParsedCommandStruct templ; ParsedCommandStruct lang; bool result = true; ExtractCommandString(&templ, b, true); ExtractCommandString(&lang, a, true); /* For each string in templ, see if we find it in lang */ if (templ.np != lang.np) { strgen_warning("%s: template string and language string have a different # of commands", name); result = false; } for (uint i = 0; i < templ.np; i++) { /* see if we find it in lang, and zero it out */ bool found = false; for (uint j = 0; j < lang.np; j++) { if (templ.pairs[i].a == lang.pairs[j].a && strcmp(templ.pairs[i].v, lang.pairs[j].v) == 0) { /* it was found in both. zero it out from lang so we don't find it again */ lang.pairs[j].a = NULL; found = true; break; } } if (!found) { strgen_warning("%s: command '%s' exists in template file but not in language file", name, templ.pairs[i].a->cmd); result = false; } } /* if we reach here, all non consumer commands match up. * Check if the non consumer commands match up also. */ for (uint i = 0; i < lengthof(templ.cmd); i++) { if (TranslateCmdForCompare(templ.cmd[i]) != lang.cmd[i]) { strgen_warning("%s: Param idx #%d '%s' doesn't match with template command '%s'", name, i, lang.cmd[i] == NULL ? "" : TranslateCmdForCompare(lang.cmd[i])->cmd, templ.cmd[i] == NULL ? "" : templ.cmd[i]->cmd); result = false; } } return result; } void StringReader::HandleString(char *str) { if (*str == '#') { if (str[1] == '#' && str[2] != '#') this->HandlePragma(str + 2); return; } /* Ignore comments & blank lines */ if (*str == ';' || *str == ' ' || *str == '\0') return; char *s = strchr(str, ':'); if (s == NULL) { strgen_error("Line has no ':' delimiter"); return; } char *t; /* Trim spaces. * After this str points to the command name, and s points to the command contents */ for (t = s; t > str && (t[-1] == ' ' || t[-1] == '\t'); t--) {} *t = 0; s++; /* Check string is valid UTF-8 */ const char *tmp; for (tmp = s; *tmp != '\0';) { size_t len = Utf8Validate(tmp); if (len == 0) strgen_fatal("Invalid UTF-8 sequence in '%s'", s); WChar c; Utf8Decode(&c, tmp); if (c <= 0x001F || // ASCII control character range c == 0x200B || // Zero width space (c >= 0xE000 && c <= 0xF8FF) || // Private range (c >= 0xFFF0 && c <= 0xFFFF)) { // Specials range strgen_fatal("Unwanted UTF-8 character U+%04X in sequence '%s'", c, s); } tmp += len; } /* Check if the string has a case.. * The syntax for cases is IDENTNAME.case */ char *casep = strchr(str, '.'); if (casep != NULL) *casep++ = '\0'; /* Check if this string already exists.. */ LangString *ent = this->data.Find(str); if (this->master) { if (casep != NULL) { strgen_error("Cases in the base translation are not supported."); return; } if (ent != NULL) { strgen_error("String name '%s' is used multiple times", str); return; } if (this->data.strings[this->data.next_string_id] != NULL) { strgen_error("String ID 0x%X for '%s' already in use by '%s'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name); return; } /* Allocate a new LangString */ this->data.Add(str, new LangString(str, s, this->data.next_string_id++, _cur_line)); } else { if (ent == NULL) { strgen_warning("String name '%s' does not exist in master file", str); return; } if (ent->translated && casep == NULL) { strgen_error("String name '%s' is used multiple times", str); return; } /* make sure that the commands match */ if (!CheckCommandsMatch(s, ent->english, str)) return; if (casep != NULL) { ent->translated_case = new Case(ResolveCaseName(casep, strlen(casep)), s, ent->translated_case); } else { ent->translated = stredup(s); /* If the string was translated, use the line from the * translated language so errors in the translated file * are properly referenced to. */ ent->line = _cur_line; } } } void StringReader::HandlePragma(char *str) { if (!memcmp(str, "plural ", 7)) { _lang.plural_form = atoi(str + 7); if (_lang.plural_form >= lengthof(_plural_forms)) { strgen_fatal("Invalid pluralform %d", _lang.plural_form); } } else { strgen_fatal("unknown pragma '%s'", str); } } static void rstrip(char *buf) { size_t i = strlen(buf); while (i > 0 && (buf[i - 1] == '\r' || buf[i - 1] == '\n' || buf[i - 1] == ' ')) i--; buf[i] = '\0'; } void StringReader::ParseFile() { char buf[2048]; _warnings = _errors = 0; _translation = this->master || this->translation; _file = this->file; /* For each new file we parse, reset the genders, and language codes. */ MemSetT(&_lang, 0); strecpy(_lang.digit_group_separator, ",", lastof(_lang.digit_group_separator)); strecpy(_lang.digit_group_separator_currency, ",", lastof(_lang.digit_group_separator_currency)); strecpy(_lang.digit_decimal_separator, ".", lastof(_lang.digit_decimal_separator)); _cur_line = 1; while (this->ReadLine(buf, lastof(buf)) != NULL) { rstrip(buf); this->HandleString(buf); _cur_line++; } } /** * Write the header information. * @param data The data about the string. */ void HeaderWriter::WriteHeader(const StringData &data) { int last = 0; for (size_t i = 0; i < data.max_strings; i++) { if (data.strings[i] != NULL) { this->WriteStringID(data.strings[i]->name, (int)i); last = (int)i; } } this->WriteStringID("STR_LAST_STRINGID", last); } static int TranslateArgumentIdx(int argidx, int offset) { int sum; if (argidx < 0 || (uint)argidx >= lengthof(_cur_pcs.cmd)) { strgen_fatal("invalid argidx %d", argidx); } const CmdStruct *cs = _cur_pcs.cmd[argidx]; if (cs != NULL && cs->consumes <= offset) { strgen_fatal("invalid argidx offset %d:%d", argidx, offset); } if (_cur_pcs.cmd[argidx] == NULL) { strgen_fatal("no command for this argidx %d", argidx); } for (int i = sum = 0; i < argidx; i++) { const CmdStruct *cs = _cur_pcs.cmd[i]; sum += (cs != NULL) ? cs->consumes : 1; } return sum + offset; } static void PutArgidxCommand(Buffer *buffer) { buffer->AppendUtf8(SCC_ARG_INDEX); buffer->AppendByte(TranslateArgumentIdx(_cur_argidx)); } static void PutCommandString(Buffer *buffer, const char *str) { _cur_argidx = 0; while (*str != '\0') { /* Process characters as they are until we encounter a { */ if (*str != '{') { buffer->AppendByte(*str++); continue; } char param[MAX_COMMAND_PARAM_SIZE]; int argno; int casei; const CmdStruct *cs = ParseCommandString(&str, param, &argno, &casei); if (cs == NULL) break; if (casei != -1) { buffer->AppendUtf8(SCC_SET_CASE); // {SET_CASE} buffer->AppendByte(casei); } /* For params that consume values, we need to handle the argindex properly */ if (cs->consumes > 0) { /* Check if we need to output a move-param command */ if (argno != -1 && argno != _cur_argidx) { _cur_argidx = argno; PutArgidxCommand(buffer); } /* Output the one from the master string... it's always accurate. */ cs = _cur_pcs.cmd[_cur_argidx++]; if (cs == NULL) { strgen_fatal("%s: No argument exists at position %d", _cur_ident, _cur_argidx - 1); } } cs->proc(buffer, param, cs->value); } } /** * Write the length as a simple gamma. * @param length The number to write. */ void LanguageWriter::WriteLength(uint length) { char buffer[2]; int offs = 0; if (length >= 0x4000) { strgen_fatal("string too long"); } if (length >= 0xC0) { buffer[offs++] = (length >> 8) | 0xC0; } buffer[offs++] = length & 0xFF; this->Write((byte*)buffer, offs); } /** * Actually write the language. * @param data The data about the string. */ void LanguageWriter::WriteLang(const StringData &data) { uint *in_use = AllocaM(uint, data.tabs); for (size_t tab = 0; tab < data.tabs; tab++) { uint n = data.CountInUse((uint)tab); in_use[tab] = n; _lang.offsets[tab] = TO_LE16(n); for (uint j = 0; j != in_use[tab]; j++) { const LangString *ls = data.strings[(tab * TAB_SIZE) + j]; if (ls != NULL && ls->translated == NULL) _lang.missing++; } } _lang.ident = TO_LE32(LanguagePackHeader::IDENT); _lang.version = TO_LE32(data.Version()); _lang.missing = TO_LE16(_lang.missing); _lang.winlangid = TO_LE16(_lang.winlangid); this->WriteHeader(&_lang); Buffer buffer; for (size_t tab = 0; tab < data.tabs; tab++) { for (uint j = 0; j != in_use[tab]; j++) { const LangString *ls = data.strings[(tab * TAB_SIZE) + j]; const Case *casep; const char *cmdp; /* For undefined strings, just set that it's an empty string */ if (ls == NULL) { this->WriteLength(0); continue; } _cur_ident = ls->name; _cur_line = ls->line; /* Produce a message if a string doesn't have a translation. */ if (_show_todo > 0 && ls->translated == NULL) { if ((_show_todo & 2) != 0) { strgen_warning("'%s' is untranslated", ls->name); } if ((_show_todo & 1) != 0) { const char *s = " "; while (*s != '\0') buffer.AppendByte(*s++); } } /* Extract the strings and stuff from the english command string */ ExtractCommandString(&_cur_pcs, ls->english, false); if (ls->translated_case != NULL || ls->translated != NULL) { casep = ls->translated_case; cmdp = ls->translated; } else { casep = NULL; cmdp = ls->english; } _translated = cmdp != ls->english; if (casep != NULL) { const Case *c; uint num; /* Need to output a case-switch. * It has this format * <0x9E> * Each LEN is printed using 2 bytes in big endian order. */ buffer.AppendUtf8(SCC_SWITCH_CASE); /* Count the number of cases */ for (num = 0, c = casep; c; c = c->next) num++; buffer.AppendByte(num); /* Write each case */ for (c = casep; c != NULL; c = c->next) { buffer.AppendByte(c->caseidx); /* Make some space for the 16-bit length */ uint pos = buffer.Length(); buffer.AppendByte(0); buffer.AppendByte(0); /* Write string */ PutCommandString(&buffer, c->string); buffer.AppendByte(0); // terminate with a zero /* Fill in the length */ uint size = buffer.Length() - (pos + 2); buffer[pos + 0] = GB(size, 8, 8); buffer[pos + 1] = GB(size, 0, 8); } } if (cmdp != NULL) PutCommandString(&buffer, cmdp); this->WriteLength(buffer.Length()); this->Write(buffer.Begin(), buffer.Length()); buffer.Clear(); } } } openttd-1.5.3/src/strgen/strgen.cpp0000644000000000000000000004137612627373435016021 0ustar rootroot/* $Id: strgen.cpp 26521 2014-04-26 20:55:08Z rubidium $ */ /* * 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 strgen.cpp Tool to create computer readable (stand-alone) translation files. */ #include "../stdafx.h" #include "../core/endian_func.hpp" #include "../string_func.h" #include "../strings_type.h" #include "../misc/getoptdata.h" #include "../table/control_codes.h" #include "strgen.h" #include #include #if (!defined(WIN32) && !defined(WIN64)) || defined(__CYGWIN__) #include #include #endif #if defined WIN32 || defined __WATCOMC__ #include #endif /* WIN32 || __WATCOMC__ */ #ifdef __MORPHOS__ #ifdef stderr #undef stderr #endif #define stderr stdout #endif /* __MORPHOS__ */ #include "../table/strgen_tables.h" #include "../safeguards.h" #ifdef _MSC_VER # define LINE_NUM_FMT(s) "%s (%d): warning: %s (" s ")\n" #else # define LINE_NUM_FMT(s) "%s:%d: " s ": %s\n" #endif void CDECL strgen_warning(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); fprintf(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, buf); _warnings++; } void CDECL strgen_error(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); fprintf(stderr, LINE_NUM_FMT("error"), _file, _cur_line, buf); _errors++; } void NORETURN CDECL strgen_fatal(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); fprintf(stderr, LINE_NUM_FMT("FATAL"), _file, _cur_line, buf); #ifdef _MSC_VER fprintf(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, "language is not compiled"); #endif throw std::exception(); } void NORETURN CDECL error(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vseprintf(buf, lastof(buf), s, va); va_end(va); fprintf(stderr, LINE_NUM_FMT("FATAL"), _file, _cur_line, buf); #ifdef _MSC_VER fprintf(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, "language is not compiled"); #endif exit(2); } /** A reader that simply reads using fopen. */ struct FileStringReader : StringReader { FILE *fh; ///< The file we are reading. /** * Create the reader. * @param data The data to fill during reading. * @param file The file we are reading. * @param master Are we reading the master file? * @param translation Are we reading a translation? */ FileStringReader(StringData &data, const char *file, bool master, bool translation) : StringReader(data, file, master, translation) { this->fh = fopen(file, "rb"); if (this->fh == NULL) error("Could not open %s", file); } /** Free/close the file. */ virtual ~FileStringReader() { fclose(this->fh); } /* virtual */ char *ReadLine(char *buffer, const char *last) { return fgets(buffer, ClampToU16(last - buffer + 1), this->fh); } /* virtual */ void HandlePragma(char *str); /* virtual */ void ParseFile() { this->StringReader::ParseFile(); if (StrEmpty(_lang.name) || StrEmpty(_lang.own_name) || StrEmpty(_lang.isocode)) { error("Language must include ##name, ##ownname and ##isocode"); } } }; void FileStringReader::HandlePragma(char *str) { if (!memcmp(str, "id ", 3)) { this->data.next_string_id = strtoul(str + 3, NULL, 0); } else if (!memcmp(str, "name ", 5)) { strecpy(_lang.name, str + 5, lastof(_lang.name)); } else if (!memcmp(str, "ownname ", 8)) { strecpy(_lang.own_name, str + 8, lastof(_lang.own_name)); } else if (!memcmp(str, "isocode ", 8)) { strecpy(_lang.isocode, str + 8, lastof(_lang.isocode)); } else if (!memcmp(str, "textdir ", 8)) { if (!memcmp(str + 8, "ltr", 3)) { _lang.text_dir = TD_LTR; } else if (!memcmp(str + 8, "rtl", 3)) { _lang.text_dir = TD_RTL; } else { error("Invalid textdir %s", str + 8); } } else if (!memcmp(str, "digitsep ", 9)) { str += 9; strecpy(_lang.digit_group_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str, lastof(_lang.digit_group_separator)); } else if (!memcmp(str, "digitsepcur ", 12)) { str += 12; strecpy(_lang.digit_group_separator_currency, strcmp(str, "{NBSP}") == 0 ? NBSP : str, lastof(_lang.digit_group_separator_currency)); } else if (!memcmp(str, "decimalsep ", 11)) { str += 11; strecpy(_lang.digit_decimal_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str, lastof(_lang.digit_decimal_separator)); } else if (!memcmp(str, "winlangid ", 10)) { const char *buf = str + 10; long langid = strtol(buf, NULL, 16); if (langid > (long)UINT16_MAX || langid < 0) { error("Invalid winlangid %s", buf); } _lang.winlangid = (uint16)langid; } else if (!memcmp(str, "grflangid ", 10)) { const char *buf = str + 10; long langid = strtol(buf, NULL, 16); if (langid >= 0x7F || langid < 0) { error("Invalid grflangid %s", buf); } _lang.newgrflangid = (uint8)langid; } else if (!memcmp(str, "gender ", 7)) { if (this->master) error("Genders are not allowed in the base translation."); char *buf = str + 7; for (;;) { const char *s = ParseWord(&buf); if (s == NULL) break; if (_lang.num_genders >= MAX_NUM_GENDERS) error("Too many genders, max %d", MAX_NUM_GENDERS); strecpy(_lang.genders[_lang.num_genders], s, lastof(_lang.genders[_lang.num_genders])); _lang.num_genders++; } } else if (!memcmp(str, "case ", 5)) { if (this->master) error("Cases are not allowed in the base translation."); char *buf = str + 5; for (;;) { const char *s = ParseWord(&buf); if (s == NULL) break; if (_lang.num_cases >= MAX_NUM_CASES) error("Too many cases, max %d", MAX_NUM_CASES); strecpy(_lang.cases[_lang.num_cases], s, lastof(_lang.cases[_lang.num_cases])); _lang.num_cases++; } } else { StringReader::HandlePragma(str); } } bool CompareFiles(const char *n1, const char *n2) { FILE *f2 = fopen(n2, "rb"); if (f2 == NULL) return false; FILE *f1 = fopen(n1, "rb"); if (f1 == NULL) error("can't open %s", n1); size_t l1, l2; do { char b1[4096]; char b2[4096]; l1 = fread(b1, 1, sizeof(b1), f1); l2 = fread(b2, 1, sizeof(b2), f2); if (l1 != l2 || memcmp(b1, b2, l1)) { fclose(f2); fclose(f1); return false; } } while (l1 != 0); fclose(f2); fclose(f1); return true; } /** Base class for writing data to disk. */ struct FileWriter { FILE *fh; ///< The file handle we're writing to. const char *filename; ///< The file name we're writing to. /** * Open a file to write to. * @param filename The file to open. */ FileWriter(const char *filename) { this->filename = stredup(filename); this->fh = fopen(this->filename, "wb"); if (this->fh == NULL) { error("Could not open %s", this->filename); } } /** Finalise the writing. */ void Finalise() { fclose(this->fh); this->fh = NULL; } /** Make sure the file is closed. */ virtual ~FileWriter() { /* If we weren't closed an exception was thrown, so remove the temporary file. */ if (fh != NULL) { fclose(this->fh); unlink(this->filename); } free(this->filename); } }; struct HeaderFileWriter : HeaderWriter, FileWriter { /** The real file name we eventually want to write to. */ const char *real_filename; /** The previous string ID that was printed. */ int prev; /** * Open a file to write to. * @param filename The file to open. */ HeaderFileWriter(const char *filename) : FileWriter("tmp.xxx"), real_filename(stredup(filename)), prev(0) { fprintf(this->fh, "/* This file is automatically generated. Do not modify */\n\n"); fprintf(this->fh, "#ifndef TABLE_STRINGS_H\n"); fprintf(this->fh, "#define TABLE_STRINGS_H\n"); } /** Free the filename. */ ~HeaderFileWriter() { free(real_filename); } void WriteStringID(const char *name, int stringid) { if (prev + 1 != stringid) fprintf(this->fh, "\n"); fprintf(this->fh, "static const StringID %s = 0x%X;\n", name, stringid); prev = stringid; } void Finalise(const StringData &data) { /* Find the plural form with the most amount of cases. */ int max_plural_forms = 0; for (uint i = 0; i < lengthof(_plural_forms); i++) { max_plural_forms = max(max_plural_forms, _plural_forms[i].plural_count); } fprintf(this->fh, "\n" "static const uint LANGUAGE_PACK_VERSION = 0x%X;\n" "static const uint LANGUAGE_MAX_PLURAL = %d;\n" "static const uint LANGUAGE_MAX_PLURAL_FORMS = %d;\n\n", (uint)data.Version(), (uint)lengthof(_plural_forms), max_plural_forms ); fprintf(this->fh, "#endif /* TABLE_STRINGS_H */\n"); this->FileWriter::Finalise(); if (CompareFiles(this->filename, this->real_filename)) { /* files are equal. tmp.xxx is not needed */ unlink(this->filename); } else { /* else rename tmp.xxx into filename */ #if defined(WIN32) || defined(WIN64) unlink(this->real_filename); #endif if (rename(this->filename, this->real_filename) == -1) error("rename() failed"); } } }; /** Class for writing a language to disk. */ struct LanguageFileWriter : LanguageWriter, FileWriter { /** * Open a file to write to. * @param filename The file to open. */ LanguageFileWriter(const char *filename) : FileWriter(filename) { } void WriteHeader(const LanguagePackHeader *header) { this->Write((const byte *)header, sizeof(*header)); } void Finalise() { if (fputc(0, this->fh) == EOF) { error("Could not write to %s", this->filename); } this->FileWriter::Finalise(); } void Write(const byte *buffer, size_t length) { if (fwrite(buffer, sizeof(*buffer), length, this->fh) != length) { error("Could not write to %s", this->filename); } } }; /** Multi-OS mkdirectory function */ static inline void ottd_mkdir(const char *directory) { /* Ignore directory creation errors; they'll surface later on, and most * of the time they are 'directory already exists' errors anyhow. */ #if defined(WIN32) || defined(__WATCOMC__) mkdir(directory); #else mkdir(directory, 0755); #endif } /** * Create a path consisting of an already existing path, a possible * path separator and the filename. The separator is only appended if the path * does not already end with a separator */ static inline char *mkpath(char *buf, const char *last, const char *path, const char *file) { strecpy(buf, path, last); // copy directory into buffer char *p = strchr(buf, '\0'); // add path separator if necessary if (p[-1] != PATHSEPCHAR && p != last) *p++ = PATHSEPCHAR; strecpy(p, file, last); // concatenate filename at end of buffer return buf; } #if defined(__MINGW32__) /** * On MingW, it is common that both / as \ are accepted in the * params. To go with those flow, we rewrite all incoming / * simply to \, so internally we can safely assume \. */ static inline char *replace_pathsep(char *s) { for (char *c = s; *c != '\0'; c++) if (*c == '/') *c = '\\'; return s; } #else static inline char *replace_pathsep(char *s) { return s; } #endif /** Options of strgen. */ static const OptionData _opts[] = { GETOPT_NOVAL( 'v', "--version"), GETOPT_GENERAL('C', '\0', "-export-commands", ODF_NO_VALUE), GETOPT_GENERAL('L', '\0', "-export-plurals", ODF_NO_VALUE), GETOPT_GENERAL('P', '\0', "-export-pragmas", ODF_NO_VALUE), GETOPT_NOVAL( 't', "--todo"), GETOPT_NOVAL( 'w', "--warning"), GETOPT_NOVAL( 'h', "--help"), GETOPT_GENERAL('h', '?', NULL, ODF_NO_VALUE), GETOPT_VALUE( 's', "--source_dir"), GETOPT_VALUE( 'd', "--dest_dir"), GETOPT_END(), }; int CDECL main(int argc, char *argv[]) { char pathbuf[MAX_PATH]; const char *src_dir = "."; const char *dest_dir = NULL; GetOptData mgo(argc - 1, argv + 1, _opts); for (;;) { int i = mgo.GetOpt(); if (i == -1) break; switch (i) { case 'v': puts("$Revision: 26521 $"); return 0; case 'C': printf("args\tflags\tcommand\treplacement\n"); for (const CmdStruct *cs = _cmd_structs; cs < endof(_cmd_structs); cs++) { char flags; if (cs->proc == EmitGender) { flags = 'g'; // Command needs number of parameters defined by number of genders } else if (cs->proc == EmitPlural) { flags = 'p'; // Command needs number of parameters defined by plural value } else if (cs->flags & C_DONTCOUNT) { flags = 'i'; // Command may be in the translation when it is not in base } else { flags = '0'; // Command needs no parameters } printf("%i\t%c\t\"%s\"\t\"%s\"\n", cs->consumes, flags, cs->cmd, strstr(cs->cmd, "STRING") ? "STRING" : cs->cmd); } return 0; case 'L': printf("count\tdescription\tnames\n"); for (const PluralForm *pf = _plural_forms; pf < endof(_plural_forms); pf++) { printf("%i\t\"%s\"\t%s\n", pf->plural_count, pf->description, pf->names); } return 0; case 'P': printf("name\tflags\tdefault\tdescription\n"); for (size_t i = 0; i < lengthof(_pragmas); i++) { printf("\"%s\"\t%s\t\"%s\"\t\"%s\"\n", _pragmas[i][0], _pragmas[i][1], _pragmas[i][2], _pragmas[i][3]); } return 0; case 't': _show_todo |= 1; break; case 'w': _show_todo |= 2; break; case 'h': puts( "strgen - $Revision: 26521 $\n" " -v | --version print version information and exit\n" " -t | --todo replace any untranslated strings with ''\n" " -w | --warning print a warning for any untranslated strings\n" " -h | -? | --help print this help message and exit\n" " -s | --source_dir search for english.txt in the specified directory\n" " -d | --dest_dir put output file in the specified directory, create if needed\n" " -export-commands export all commands and exit\n" " -export-plurals export all plural forms and exit\n" " -export-pragmas export all pragmas and exit\n" " Run without parameters and strgen will search for english.txt and parse it,\n" " creating strings.h. Passing an argument, strgen will translate that language\n" " file using english.txt as a reference and output .lng." ); return 0; case 's': src_dir = replace_pathsep(mgo.opt); break; case 'd': dest_dir = replace_pathsep(mgo.opt); break; case -2: fprintf(stderr, "Invalid arguments\n"); return 0; } } if (dest_dir == NULL) dest_dir = src_dir; // if dest_dir is not specified, it equals src_dir try { /* strgen has two modes of operation. If no (free) arguments are passed * strgen generates strings.h to the destination directory. If it is supplied * with a (free) parameter the program will translate that language to destination * directory. As input english.txt is parsed from the source directory */ if (mgo.numleft == 0) { mkpath(pathbuf, lastof(pathbuf), src_dir, "english.txt"); /* parse master file */ StringData data(TAB_COUNT); FileStringReader master_reader(data, pathbuf, true, false); master_reader.ParseFile(); if (_errors != 0) return 1; /* write strings.h */ ottd_mkdir(dest_dir); mkpath(pathbuf, lastof(pathbuf), dest_dir, "strings.h"); HeaderFileWriter writer(pathbuf); writer.WriteHeader(data); writer.Finalise(data); } else if (mgo.numleft >= 1) { char *r; mkpath(pathbuf, lastof(pathbuf), src_dir, "english.txt"); StringData data(TAB_COUNT); /* parse master file and check if target file is correct */ FileStringReader master_reader(data, pathbuf, true, false); master_reader.ParseFile(); for (int i = 0; i < mgo.numleft; i++) { data.FreeTranslation(); const char *translation = replace_pathsep(mgo.argv[i]); const char *file = strrchr(translation, PATHSEPCHAR); FileStringReader translation_reader(data, translation, false, file == NULL || strcmp(file + 1, "english.txt") != 0); translation_reader.ParseFile(); // target file if (_errors != 0) return 1; /* get the targetfile, strip any directories and append to destination path */ r = strrchr(mgo.argv[i], PATHSEPCHAR); mkpath(pathbuf, lastof(pathbuf), dest_dir, (r != NULL) ? &r[1] : mgo.argv[i]); /* rename the .txt (input-extension) to .lng */ r = strrchr(pathbuf, '.'); if (r == NULL || strcmp(r, ".txt") != 0) r = strchr(pathbuf, '\0'); strecpy(r, ".lng", lastof(pathbuf)); LanguageFileWriter writer(pathbuf); writer.WriteLang(data); writer.Finalise(); /* if showing warnings, print a summary of the language */ if ((_show_todo & 2) != 0) { fprintf(stdout, "%d warnings and %d errors for %s\n", _warnings, _errors, pathbuf); } } } } catch (...) { return 2; } return 0; } openttd-1.5.3/src/ship_gui.cpp0000644000000000000000000000575012627373435015020 0ustar rootroot/* $Id: ship_gui.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 ship_gui.cpp GUI for ships. */ #include "stdafx.h" #include "vehicle_base.h" #include "window_gui.h" #include "gfx_func.h" #include "vehicle_gui.h" #include "strings_func.h" #include "vehicle_func.h" #include "spritecache.h" #include "zoom_func.h" #include "table/strings.h" #include "safeguards.h" /** * Draws an image of a ship * @param v Front vehicle * @param left The minimum horizontal position * @param right The maximum horizontal position * @param y Vertical position to draw at * @param selection Selected vehicle to draw a frame around */ void DrawShipImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type) { bool rtl = _current_text_dir == TD_RTL; SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); int width = UnScaleGUI(real_sprite->width); int x_offs = UnScaleGUI(real_sprite->x_offs); int x = rtl ? right - width - x_offs : left - x_offs; y += ScaleGUITrad(10); DrawSprite(sprite, GetVehiclePalette(v), x, y); if (v->index == selection) { x += x_offs; y += UnScaleGUI(real_sprite->y_offs); DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(real_sprite->height) + 1, COLOUR_WHITE, FR_BORDERONLY); } } /** * Draw the details for the given vehicle at the given position * * @param v current vehicle * @param left The left most coordinate to draw * @param right The right most coordinate to draw * @param y The y coordinate */ void DrawShipDetails(const Vehicle *v, int left, int right, int y) { SetDParam(0, v->engine_type); SetDParam(1, v->build_year); SetDParam(2, v->value); DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE); SetDParam(0, v->cargo_type); SetDParam(1, v->cargo_cap); SetDParam(4, GetCargoSubtypeText(v)); DrawString(left, right, y + FONT_HEIGHT_NORMAL, STR_VEHICLE_INFO_CAPACITY); StringID str = STR_VEHICLE_DETAILS_CARGO_EMPTY; if (v->cargo.StoredCount() > 0) { SetDParam(0, v->cargo_type); SetDParam(1, v->cargo.StoredCount()); SetDParam(2, v->cargo.Source()); str = STR_VEHICLE_DETAILS_CARGO_FROM; } DrawString(left, right, y + 2 * FONT_HEIGHT_NORMAL + 1, str); /* Draw Transfer credits text */ SetDParam(0, v->cargo.FeederShare()); DrawString(left, right, y + 3 * FONT_HEIGHT_NORMAL + 3, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE); } openttd-1.5.3/src/engine_gui.cpp0000644000000000000000000002664512627373442015326 0ustar rootroot/* $Id: engine_gui.cpp 26934 2014-09-28 09:21:51Z peter1138 $ */ /* * 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 engine_gui.cpp GUI to show engine related information. */ #include "stdafx.h" #include "window_gui.h" #include "engine_base.h" #include "command_func.h" #include "strings_func.h" #include "engine_gui.h" #include "articulated_vehicles.h" #include "vehicle_func.h" #include "company_func.h" #include "rail.h" #include "settings_type.h" #include "train.h" #include "roadveh.h" #include "ship.h" #include "aircraft.h" #include "widgets/engine_widget.h" #include "table/strings.h" #include "safeguards.h" /** * Return the category of an engine. * @param engine Engine to examine. * @return String describing the category ("road veh", "train". "airplane", or "ship") of the engine. */ StringID GetEngineCategoryName(EngineID engine) { const Engine *e = Engine::Get(engine); switch (e->type) { default: NOT_REACHED(); case VEH_ROAD: return STR_ENGINE_PREVIEW_ROAD_VEHICLE; case VEH_AIRCRAFT: return STR_ENGINE_PREVIEW_AIRCRAFT; case VEH_SHIP: return STR_ENGINE_PREVIEW_SHIP; case VEH_TRAIN: return GetRailTypeInfo(e->u.rail.railtype)->strings.new_loco; } } static const NWidgetPart _nested_engine_preview_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_ENGINE_PREVIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_EP_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_EP_NO), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_EP_YES), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 8), EndContainer(), }; struct EnginePreviewWindow : Window { int vehicle_space; // The space to show the vehicle image EnginePreviewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); /* There is no way to recover the window; so disallow closure via DEL; unless SHIFT+DEL */ this->flags |= WF_STICKY; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_EP_QUESTION) return; /* Get size of engine sprite, on loan from depot_gui.cpp */ EngineID engine = this->window_number; EngineImageType image_type = EIT_PURCHASE; uint x, y; int x_offs, y_offs; const Engine *e = Engine::Get(engine); switch (e->type) { default: NOT_REACHED(); case VEH_TRAIN: GetTrainSpriteSize( engine, x, y, x_offs, y_offs, image_type); break; case VEH_ROAD: GetRoadVehSpriteSize( engine, x, y, x_offs, y_offs, image_type); break; case VEH_SHIP: GetShipSpriteSize( engine, x, y, x_offs, y_offs, image_type); break; case VEH_AIRCRAFT: GetAircraftSpriteSize(engine, x, y, x_offs, y_offs, image_type); break; } this->vehicle_space = max(40, y - y_offs); size->width = max(size->width, x - x_offs); SetDParam(0, GetEngineCategoryName(engine)); size->height = GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, size->width) + WD_PAR_VSEP_WIDE + FONT_HEIGHT_NORMAL + this->vehicle_space; SetDParam(0, engine); size->height += GetStringHeight(GetEngineInfoString(engine), size->width); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_EP_QUESTION) return; EngineID engine = this->window_number; SetDParam(0, GetEngineCategoryName(engine)); int y = r.top + GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, r.right - r.top + 1); y = DrawStringMultiLine(r.left, r.right, r.top, y, STR_ENGINE_PREVIEW_MESSAGE, TC_FROMSTRING, SA_CENTER) + WD_PAR_VSEP_WIDE; SetDParam(0, engine); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_ENGINE_NAME, TC_BLACK, SA_HOR_CENTER); y += FONT_HEIGHT_NORMAL; DrawVehicleEngine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, this->width >> 1, y + this->vehicle_space / 2, engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW); y += this->vehicle_space; DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_EP_YES: DoCommandP(0, this->window_number, 0, CMD_WANT_ENGINE_PREVIEW); /* FALL THROUGH */ case WID_EP_NO: delete this; break; } } virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (!gui_scope) return; EngineID engine = this->window_number; if (Engine::Get(engine)->preview_company != _local_company) delete this; } }; static WindowDesc _engine_preview_desc( WDP_CENTER, "engine_preview", 0, 0, WC_ENGINE_PREVIEW, WC_NONE, WDF_CONSTRUCTION, _nested_engine_preview_widgets, lengthof(_nested_engine_preview_widgets) ); void ShowEnginePreviewWindow(EngineID engine) { AllocateWindowDescFront(&_engine_preview_desc, engine); } /** * Get the capacity of an engine with articulated parts. * @param engine The engine to get the capacity of. * @return The capacity. */ uint GetTotalCapacityOfArticulatedParts(EngineID engine) { CargoArray cap = GetCapacityOfArticulatedParts(engine); return cap.GetSum(); } static StringID GetTrainEngineInfoString(const Engine *e) { SetDParam(0, e->GetCost()); SetDParam(2, e->GetDisplayMaxSpeed()); SetDParam(3, e->GetPower()); SetDParam(1, e->GetDisplayWeight()); SetDParam(7, e->GetDisplayMaxTractiveEffort()); SetDParam(4, e->GetRunningCost()); uint capacity = GetTotalCapacityOfArticulatedParts(e->index); if (capacity != 0) { SetDParam(5, e->GetDefaultCargoType()); SetDParam(6, capacity); } else { SetDParam(5, CT_INVALID); } return (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(e->u.rail.railtype)->acceleration_type != 2) ? STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE : STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER; } static StringID GetAircraftEngineInfoString(const Engine *e) { CargoID cargo = e->GetDefaultCargoType(); uint16 mail_capacity; uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); uint16 range = e->GetRange(); uint i = 0; SetDParam(i++, e->GetCost()); SetDParam(i++, e->GetDisplayMaxSpeed()); if (range > 0) SetDParam(i++, range); SetDParam(i++, cargo); SetDParam(i++, capacity); if (mail_capacity > 0) { SetDParam(i++, CT_MAIL); SetDParam(i++, mail_capacity); SetDParam(i++, e->GetRunningCost()); return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST; } else { SetDParam(i++, e->GetRunningCost()); return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST; } } static StringID GetRoadVehEngineInfoString(const Engine *e) { if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) { SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayMaxSpeed()); uint capacity = GetTotalCapacityOfArticulatedParts(e->index); if (capacity != 0) { SetDParam(2, e->GetDefaultCargoType()); SetDParam(3, capacity); } else { SetDParam(2, CT_INVALID); } SetDParam(4, e->GetRunningCost()); return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST; } else { SetDParam(0, e->GetCost()); SetDParam(2, e->GetDisplayMaxSpeed()); SetDParam(3, e->GetPower()); SetDParam(1, e->GetDisplayWeight()); SetDParam(7, e->GetDisplayMaxTractiveEffort()); SetDParam(4, e->GetRunningCost()); uint capacity = GetTotalCapacityOfArticulatedParts(e->index); if (capacity != 0) { SetDParam(5, e->GetDefaultCargoType()); SetDParam(6, capacity); } else { SetDParam(5, CT_INVALID); } return STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE; } } static StringID GetShipEngineInfoString(const Engine *e) { SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayMaxSpeed()); SetDParam(2, e->GetDefaultCargoType()); SetDParam(3, e->GetDisplayDefaultCapacity()); SetDParam(4, e->GetRunningCost()); return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST; } /** * Get a multi-line string with some technical data, describing the engine. * @param engine Engine to describe. * @return String describing the engine. * @post \c DParam array is set up for printing the string. */ StringID GetEngineInfoString(EngineID engine) { const Engine *e = Engine::Get(engine); switch (e->type) { case VEH_TRAIN: return GetTrainEngineInfoString(e); case VEH_ROAD: return GetRoadVehEngineInfoString(e); case VEH_SHIP: return GetShipEngineInfoString(e); case VEH_AIRCRAFT: return GetAircraftEngineInfoString(e); default: NOT_REACHED(); } } /** * Draw an engine. * @param left Minimum horizontal position to use for drawing the engine * @param right Maximum horizontal position to use for drawing the engine * @param preferred_x Horizontal position to use for drawing the engine. * @param y Vertical position to use for drawing the engine. * @param engine Engine to draw. * @param pal Palette to use for drawing. */ void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { const Engine *e = Engine::Get(engine); switch (e->type) { case VEH_TRAIN: DrawTrainEngine(left, right, preferred_x, y, engine, pal, image_type); break; case VEH_ROAD: DrawRoadVehEngine(left, right, preferred_x, y, engine, pal, image_type); break; case VEH_SHIP: DrawShipEngine(left, right, preferred_x, y, engine, pal, image_type); break; case VEH_AIRCRAFT: DrawAircraftEngine(left, right, preferred_x, y, engine, pal, image_type); break; default: NOT_REACHED(); } } /** * Sort all items using quick sort and given 'CompareItems' function * @param el list to be sorted * @param compare function for evaluation of the quicksort */ void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare) { uint size = el->Length(); /* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems) * generally, do not sort if there are less than 2 items */ if (size < 2) return; QSortT(el->Begin(), size, compare); } /** * Sort selected range of items (on indices @ ) * @param el list to be sorted * @param compare function for evaluation of the quicksort * @param begin start of sorting * @param num_items count of items to be sorted */ void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items) { if (num_items < 2) return; assert(begin < el->Length()); assert(begin + num_items <= el->Length()); QSortT(el->Get(begin), num_items, compare); } openttd-1.5.3/src/core/0000755000000000000000000000000012627373435013426 5ustar rootrootopenttd-1.5.3/src/core/random_func.hpp0000644000000000000000000001173512627373435016441 0ustar rootroot/* $Id: random_func.hpp 25893 2013-10-20 14:48:08Z fonsinchen $ */ /* * 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 random_func.hpp Pseudo random number generator. */ #ifndef RANDOM_FUNC_HPP #define RANDOM_FUNC_HPP #if defined(__APPLE__) /* Apple already has Random declared */ #define Random OTTD_Random #endif /* __APPLE__ */ /** * Structure to encapsulate the pseudo random number generators. */ struct Randomizer { /** The state of the randomizer */ uint32 state[2]; uint32 Next(); uint32 Next(uint32 limit); void SetSeed(uint32 seed); }; extern Randomizer _random; ///< Random used in the game state calculations extern Randomizer _interactive_random; ///< Random used every else where is does not (directly) influence the game state /** Stores the state of all random number generators */ struct SavedRandomSeeds { Randomizer random; Randomizer interactive_random; }; /** * Saves the current seeds * @param storage Storage for saving */ static inline void SaveRandomSeeds(SavedRandomSeeds *storage) { storage->random = _random; storage->interactive_random = _interactive_random; } /** * Restores previously saved seeds * @param storage Storage where SaveRandomSeeds() stored th seeds */ static inline void RestoreRandomSeeds(const SavedRandomSeeds &storage) { _random = storage.random; _interactive_random = storage.interactive_random; } void SetRandomSeed(uint32 seed); #ifdef RANDOM_DEBUG #ifdef __APPLE__ #define OTTD_Random() DoRandom(__LINE__, __FILE__) #else #define Random() DoRandom(__LINE__, __FILE__) #endif uint32 DoRandom(int line, const char *file); #define RandomRange(limit) DoRandomRange(limit, __LINE__, __FILE__) uint32 DoRandomRange(uint32 limit, int line, const char *file); #else static inline uint32 Random() { return _random.Next(); } /** * Pick a random number between 0 and \a limit - 1, inclusive. That means 0 * can be returned and \a limit - 1 can be returned, but \a limit can not be * returned. * @param limit Limit for the range to be picked from. * @return A random number in [0,\a limit). */ static inline uint32 RandomRange(uint32 limit) { return _random.Next(limit); } #endif static inline uint32 InteractiveRandom() { return _interactive_random.Next(); } static inline uint32 InteractiveRandomRange(uint32 limit) { return _interactive_random.Next(limit); } /** * Checks if a given randomize-number is below a given probability. * * This function is used to check if the given probability by the fraction of (a/b) * is greater than low 16 bits of the given randomize-number r. * * Do not use this function twice on the same random 16 bits as it will yield * the same result. One can use a random number for two calls to Chance16I, * where one call sends the low 16 bits and the other the high 16 bits. * * @param a The numerator of the fraction * @param b The denominator of the fraction, must of course not be null * @param r The given randomize-number * @return True if the probability given by r is less or equal to (a/b) */ static inline bool Chance16I(const uint a, const uint b, const uint32 r) { assert(b != 0); return (((uint16)r * b + b / 2) >> 16) < a; } /** * Flips a coin with given probability. * * This function returns true with (a/b) probability. * * @see Chance16I() * @param a The nominator of the fraction * @param b The denominator of the fraction * @return True with (a/b) probability */ #ifdef RANDOM_DEBUG #define Chance16(a, b) Chance16I(a, b, DoRandom(__LINE__, __FILE__)) #else static inline bool Chance16(const uint a, const uint b) { return Chance16I(a, b, Random()); } #endif /* RANDOM_DEBUG */ /** * Flips a coin with a given probability and saves the randomize-number in a variable. * * This function uses the same parameters as Chance16. The third parameter * must be a variable the randomize-number from Random() is saved in. * * The low 16 bits of r will already be used and can therefore not be passed to * Chance16I. One can only send the high 16 bits to Chance16I. * * @see Chance16I() * @param a The numerator of the fraction * @param b The denominator of the fraction * @param r The variable to save the randomize-number from Random() * @return True in (a/b) percent */ #ifdef RANDOM_DEBUG #define Chance16R(a, b, r) (r = DoRandom(__LINE__, __FILE__), Chance16I(a, b, r)) #else static inline bool Chance16R(const uint a, const uint b, uint32 &r) { r = Random(); return Chance16I(a, b, r); } #endif /* RANDOM_DEBUG */ #endif /* RANDOM_FUNC_HPP */ openttd-1.5.3/src/core/smallmap_type.hpp0000644000000000000000000001026612627373435017013 0ustar rootroot/* $Id: smallmap_type.hpp 24741 2012-11-14 22:50:30Z frosch $ */ /* * 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 smallmap_type.hpp Simple mapping class targeted for small sets of data. Stored data shall be POD ("Plain Old Data")! */ #ifndef SMALLMAP_TYPE_HPP #define SMALLMAP_TYPE_HPP #include "smallvec_type.hpp" #include "sort_func.hpp" /** * Simple pair of data. Both types have to be POD ("Plain Old Data")! * @tparam T Key type. * @tparam U Value type. */ template struct SmallPair { T first; U second; /** Initializes this Pair with data */ inline SmallPair(const T &first, const U &second) : first(first), second(second) { } }; /** * Implementation of simple mapping class. Both types have to be POD ("Plain Old Data")! * It has inherited accessors from SmallVector(). * @tparam T Key type. * @tparam U Value type. * @tparam S Unit of allocation. * * @see SmallVector */ template struct SmallMap : SmallVector, S> { typedef ::SmallPair Pair; typedef Pair *iterator; typedef const Pair *const_iterator; /** Creates new SmallMap. Data are initialized in SmallVector constructor */ inline SmallMap() { } /** Data are freed in SmallVector destructor */ inline ~SmallMap() { } /** * Finds given key in this map * @param key key to find * @return &Pair(key, data) if found, this->End() if not */ inline const Pair *Find(const T &key) const { for (uint i = 0; i < this->items; i++) { if (key == this->data[i].first) return &this->data[i]; } return this->End(); } /** * Finds given key in this map * @param key key to find * @return &Pair(key, data) if found, this->End() if not */ inline Pair *Find(const T &key) { for (uint i = 0; i < this->items; i++) { if (key == this->data[i].first) return &this->data[i]; } return this->End(); } /** * Tests whether a key is assigned in this map. * @param key key to test * @return true iff the item is present */ inline bool Contains(const T &key) const { return this->Find(key) != this->End(); } /** * Removes given pair from this map * @param pair pair to remove * @note it has to be pointer to pair in this map. It is overwritten by the last item. */ inline void Erase(Pair *pair) { assert(pair >= this->Begin() && pair < this->End()); *pair = this->data[--this->items]; } /** * Removes given key from this map * @param key key to remove * @return true iff the key was found * @note last item is moved to its place, so don't increase your iterator if true is returned! */ inline bool Erase(const T &key) { for (uint i = 0; i < this->items; i++) { if (key == this->data[i].first) { this->data[i] = this->data[--this->items]; return true; } } return false; } /** * Adds new item to this map. * @param key key * @param data data * @return true iff the key wasn't already present */ inline bool Insert(const T &key, const U &data) { if (this->Contains(key)) return false; Pair *n = this->Append(); n->first = key; n->second = data; return true; } /** * Returns data belonging to this key * @param key key * @return data belonging to this key * @note if this key wasn't present, new entry is created */ inline U &operator[](const T &key) { for (uint i = 0; i < this->items; i++) { if (key == this->data[i].first) return this->data[i].second; } Pair *n = this->Append(); n->first = key; return n->second; } inline void SortByKey() { QSortT(this->Begin(), this->items, KeySorter); } static int CDECL KeySorter(const Pair *a, const Pair *b) { return a->first - b->first; } }; #endif /* SMALLMAP_TYPE_HPP */ openttd-1.5.3/src/core/geometry_type.hpp0000644000000000000000000000314012627373435017031 0ustar rootroot/* $Id: geometry_type.hpp 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 geometry_type.hpp All geometry types in OpenTTD. */ #ifndef GEOMETRY_TYPE_HPP #define GEOMETRY_TYPE_HPP #if defined(__AMIGA__) /* AmigaOS already has a Point declared */ #define Point OTTD_Point #endif /* __AMIGA__ */ #if defined(__APPLE__) /* Mac OS X already has both Rect and Point declared */ #define Rect OTTD_Rect #define Point OTTD_Point #endif /* __APPLE__ */ /** Coordinates of a point in 2D */ struct Point { int x; int y; }; /** Dimensions (a width and height) of a rectangle in 2D */ struct Dimension { uint width; uint height; }; /** Specification of a rectangle with absolute coordinates of all edges */ struct Rect { int left; int top; int right; int bottom; }; /** * Specification of a rectangle with an absolute top-left coordinate and a * (relative) width/height */ struct PointDimension { int x; int y; int width; int height; }; /** A pair of two integers */ struct Pair { int a; int b; }; #endif /* GEOMETRY_TYPE_HPP */ openttd-1.5.3/src/core/pool_type.hpp0000644000000000000000000002314012627373435016151 0ustar rootroot/* $Id: pool_type.hpp 26333 2014-02-11 20:34:48Z frosch $ */ /* * 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 pool_type.hpp Defintion of Pool, structure used to access PoolItems, and PoolItem, base structure for Vehicle, Town, and other indexed items. */ #ifndef POOL_TYPE_HPP #define POOL_TYPE_HPP #include "smallvec_type.hpp" #include "enum_type.hpp" /** Various types of a pool. */ enum PoolType { PT_NONE = 0x00, ///< No pool is selected. PT_NORMAL = 0x01, ///< Normal pool containing game objects. PT_NCLIENT = 0x02, ///< Network client pools. PT_NADMIN = 0x04, ///< Network admin pool. PT_DATA = 0x08, ///< NewGRF or other data, that is not reset together with normal pools. PT_ALL = 0x0F, ///< All pool types. }; DECLARE_ENUM_AS_BIT_SET(PoolType) typedef SmallVector PoolVector; ///< Vector of pointers to PoolBase /** Base class for base of all pools. */ struct PoolBase { const PoolType type; ///< Type of this pool. /** * Function used to access the vector of all pools. * @return pointer to vector of all pools */ static PoolVector *GetPools() { static PoolVector *pools = new PoolVector(); return pools; } static void Clean(PoolType); /** * Constructor registers this object in the pool vector. * @param pt type of this pool. */ PoolBase(PoolType pt) : type(pt) { *PoolBase::GetPools()->Append() = this; } virtual ~PoolBase(); /** * Virtual method that deletes all items in the pool. */ virtual void CleanPool() = 0; private: /** * Dummy private copy constructor to prevent compilers from * copying the structure, which fails due to GetPools(). */ PoolBase(const PoolBase &other); }; /** * Base class for all pools. * @tparam Titem Type of the class/struct that is going to be pooled * @tparam Tindex Type of the index for this pool * @tparam Tgrowth_step Size of growths; if the pool is full increase the size by this amount * @tparam Tmax_size Maximum size of the pool * @tparam Tpool_type Type of this pool * @tparam Tcache Whether to perform 'alloc' caching, i.e. don't actually free/malloc just reuse the memory * @tparam Tzero Whether to zero the memory * @warning when Tcache is enabled *all* instances of this pool's item must be of the same size. */ template struct Pool : PoolBase { /* Ensure Tmax_size is within the bounds of Tindex. */ assert_compile((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0); static const size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside const char * const name; ///< Name of this pool size_t size; ///< Current allocated size size_t first_free; ///< No item with index lower than this is free (doesn't say anything about this one!) size_t first_unused; ///< This and all higher indexes are free (doesn't say anything about first_unused-1 !) size_t items; ///< Number of used indexes (non-NULL) #ifdef OTTD_ASSERT size_t checked; ///< Number of items we checked for #endif /* OTTD_ASSERT */ bool cleaning; ///< True if cleaning pool (deleting all items) Titem **data; ///< Pointer to array of pointers to Titem Pool(const char *name); virtual void CleanPool(); /** * Returns Titem with given index * @param index of item to get * @return pointer to Titem * @pre index < this->first_unused */ inline Titem *Get(size_t index) { assert(index < this->first_unused); return this->data[index]; } /** * Tests whether given index can be used to get valid (non-NULL) Titem * @param index index to examine * @return true if PoolItem::Get(index) will return non-NULL pointer */ inline bool IsValidID(size_t index) { return index < this->first_unused && this->Get(index) != NULL; } /** * Tests whether we can allocate 'n' items * @param n number of items we want to allocate * @return true if 'n' items can be allocated */ inline bool CanAllocate(size_t n = 1) { bool ret = this->items <= Tmax_size - n; #ifdef OTTD_ASSERT this->checked = ret ? n : 0; #endif /* OTTD_ASSERT */ return ret; } /** * Base class for all PoolItems * @tparam Tpool The pool this item is going to be part of */ template *Tpool> struct PoolItem { Tindex index; ///< Index of this pool item /** * Allocates space for new Titem * @param size size of Titem * @return pointer to allocated memory * @note can never fail (return NULL), use CanAllocate() to check first! */ inline void *operator new(size_t size) { return Tpool->GetNew(size); } /** * Marks Titem as free. Its memory is released * @param p memory to free * @note the item has to be allocated in the pool! */ inline void operator delete(void *p) { if (p == NULL) return; Titem *pn = (Titem *)p; assert(pn == Tpool->Get(pn->index)); Tpool->FreeItem(pn->index); } /** * Allocates space for new Titem with given index * @param size size of Titem * @param index index of item * @return pointer to allocated memory * @note can never fail (return NULL), use CanAllocate() to check first! * @pre index has to be unused! Else it will crash */ inline void *operator new(size_t size, size_t index) { return Tpool->GetNew(size, index); } /** * Allocates space for new Titem at given memory address * @param size size of Titem * @param ptr where are we allocating the item? * @return pointer to allocated memory (== ptr) * @note use of this is strongly discouraged * @pre the memory must not be allocated in the Pool! */ inline void *operator new(size_t size, void *ptr) { for (size_t i = 0; i < Tpool->first_unused; i++) { /* Don't allow creating new objects over existing. * Even if we called the destructor and reused this memory, * we don't know whether 'size' and size of currently allocated * memory are the same (because of possible inheritance). * Use { size_t index = item->index; delete item; new (index) item; } * instead to make sure destructor is called and no memory leaks. */ assert(ptr != Tpool->data[i]); } return ptr; } /** Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function() */ /** * Tests whether we can allocate 'n' items * @param n number of items we want to allocate * @return true if 'n' items can be allocated */ static inline bool CanAllocateItem(size_t n = 1) { return Tpool->CanAllocate(n); } /** * Returns current state of pool cleaning - yes or no * @return true iff we are cleaning the pool now */ static inline bool CleaningPool() { return Tpool->cleaning; } /** * Tests whether given index can be used to get valid (non-NULL) Titem * @param index index to examine * @return true if PoolItem::Get(index) will return non-NULL pointer */ static inline bool IsValidID(size_t index) { return Tpool->IsValidID(index); } /** * Returns Titem with given index * @param index of item to get * @return pointer to Titem * @pre index < this->first_unused */ static inline Titem *Get(size_t index) { return Tpool->Get(index); } /** * Returns Titem with given index * @param index of item to get * @return pointer to Titem * @note returns NULL for invalid index */ static inline Titem *GetIfValid(size_t index) { return index < Tpool->first_unused ? Tpool->Get(index) : NULL; } /** * Returns first unused index. Useful when iterating over * all pool items. * @return first unused index */ static inline size_t GetPoolSize() { return Tpool->first_unused; } /** * Returns number of valid items in the pool * @return number of valid items in the pool */ static inline size_t GetNumItems() { return Tpool->items; } /** * Dummy function called after destructor of each member. * If you want to use it, override it in PoolItem's subclass. * @param index index of deleted item * @note when this function is called, PoolItem::Get(index) == NULL. * @note it's called only when !CleaningPool() */ static inline void PostDestructor(size_t index) { } }; private: static const size_t NO_FREE_ITEM = MAX_UVALUE(size_t); ///< Constant to indicate we can't allocate any more items /** * Helper struct to cache 'freed' PoolItems so we * do not need to allocate them again. */ struct AllocCache { /** The next in our 'cache' */ AllocCache *next; }; /** Cache of freed pointers */ AllocCache *alloc_cache; void *AllocateItem(size_t size, size_t index); void ResizeFor(size_t index); size_t FindFirstFree(); void *GetNew(size_t size); void *GetNew(size_t size, size_t index); void FreeItem(size_t index); }; #define FOR_ALL_ITEMS_FROM(type, iter, var, start) \ for (size_t iter = start; var = NULL, iter < type::GetPoolSize(); iter++) \ if ((var = type::Get(iter)) != NULL) #define FOR_ALL_ITEMS(type, iter, var) FOR_ALL_ITEMS_FROM(type, iter, var, 0) #endif /* POOL_TYPE_HPP */ openttd-1.5.3/src/core/alloc_func.cpp0000644000000000000000000000237412627373435016245 0ustar rootroot/* $Id: alloc_func.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 alloc_func.cpp Functions to 'handle' memory allocation errors */ #include "../stdafx.h" #include "../safeguards.h" /** * Function to exit with an error message after malloc() or calloc() have failed * @param size number of bytes we tried to allocate */ void NORETURN MallocError(size_t size) { error("Out of memory. Cannot allocate " PRINTF_SIZE " bytes", size); } /** * Function to exit with an error message after realloc() have failed * @param size number of bytes we tried to allocate */ void NORETURN ReallocError(size_t size) { error("Out of memory. Cannot reallocate " PRINTF_SIZE " bytes", size); } openttd-1.5.3/src/core/enum_type.hpp0000644000000000000000000001545012627373435016151 0ustar rootroot/* $Id: enum_type.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 enum_type.hpp Type (helpers) for enums */ #ifndef ENUM_TYPE_HPP #define ENUM_TYPE_HPP /** Some enums need to have allowed incrementing (i.e. StationClassID) */ #define DECLARE_POSTFIX_INCREMENT(type) \ inline type operator ++(type& e, int) \ { \ type e_org = e; \ e = (type)((int)e + 1); \ return e_org; \ } \ inline type operator --(type& e, int) \ { \ type e_org = e; \ e = (type)((int)e - 1); \ return e_org; \ } /** Operators to allow to work with enum as with type safe bit set in C++ */ # define DECLARE_ENUM_AS_BIT_SET(mask_t) \ inline mask_t operator | (mask_t m1, mask_t m2) {return (mask_t)((int)m1 | m2);} \ inline mask_t operator & (mask_t m1, mask_t m2) {return (mask_t)((int)m1 & m2);} \ inline mask_t operator ^ (mask_t m1, mask_t m2) {return (mask_t)((int)m1 ^ m2);} \ inline mask_t& operator |= (mask_t& m1, mask_t m2) {m1 = m1 | m2; return m1;} \ inline mask_t& operator &= (mask_t& m1, mask_t m2) {m1 = m1 & m2; return m1;} \ inline mask_t& operator ^= (mask_t& m1, mask_t m2) {m1 = m1 ^ m2; return m1;} \ inline mask_t operator ~(mask_t m) {return (mask_t)(~(int)m);} /** * Informative template class exposing basic enumeration properties used by several * other templates below. Here we have only forward declaration. For each enum type * we will create specialization derived from MakeEnumPropsT<>. * i.e.: * template <> struct EnumPropsT : MakeEnumPropsT {}; * followed by: * typedef TinyEnumT TrackByte; */ template struct EnumPropsT; /** * Helper template class that makes basic properties of given enumeration type visible * from outsize. It is used as base class of several EnumPropsT specializations each * dedicated to one of commonly used enumeration types. * @param Tenum_t enumeration type that you want to describe * @param Tstorage_t what storage type would be sufficient (i.e. byte) * @param Tbegin first valid value from the contiguous range (i.e. TRACK_BEGIN) * @param Tend one past the last valid value from the contiguous range (i.e. TRACK_END) * @param Tinvalid value used as invalid value marker (i.e. INVALID_TRACK) * @param Tnum_bits Number of bits for storing the enum in command parameters */ template struct MakeEnumPropsT { typedef Tenum_t type; ///< enum type (i.e. Trackdir) typedef Tstorage_t storage; ///< storage type (i.e. byte) static const Tenum_t begin = Tbegin; ///< lowest valid value (i.e. TRACKDIR_BEGIN) static const Tenum_t end = Tend; ///< one after the last valid value (i.e. TRACKDIR_END) static const Tenum_t invalid = Tinvalid; ///< what value is used as invalid value (i.e. INVALID_TRACKDIR) static const uint num_bits = Tnum_bits; ///< Number of bits for storing the enum in command parameters }; /** * In some cases we use byte or uint16 to store values that are defined as enum. It is * necessary in order to control the sizeof() such values. Some compilers make enum * the same size as int (4 or 8 bytes instead of 1 or 2). As a consequence the strict * compiler type - checking causes errors like: * 'HasPowerOnRail' : cannot convert parameter 1 from 'byte' to 'RailType' when * u->u.rail.railtype is passed as argument or type RailType. In such cases it is better * to teach the compiler that u->u.rail.railtype is to be treated as RailType. */ template struct TinyEnumT; /** The general declaration of TinyEnumT<> (above) */ template struct TinyEnumT { typedef Tenum_t enum_type; ///< expose our enumeration type (i.e. Trackdir) to outside typedef EnumPropsT Props; ///< make easier access to our enumeration properties typedef typename Props::storage storage_type; ///< small storage type static const enum_type begin = Props::begin; ///< enum beginning (i.e. TRACKDIR_BEGIN) static const enum_type end = Props::end; ///< enum end (i.e. TRACKDIR_END) static const enum_type invalid = Props::invalid;///< invalid value (i.e. INVALID_TRACKDIR) storage_type m_val; ///< here we hold the actual value in small (i.e. byte) form /** Cast operator - invoked then the value is assigned to the Tenum_t type */ inline operator enum_type () const { return (enum_type)m_val; } /** Assignment operator (from Tenum_t type) */ inline TinyEnumT& operator = (enum_type e) { m_val = (storage_type)e; return *this; } /** Assignment operator (from Tenum_t type) */ inline TinyEnumT& operator = (uint u) { m_val = (storage_type)u; return *this; } /** postfix ++ operator on tiny type */ inline TinyEnumT operator ++ (int) { TinyEnumT org = *this; if (++m_val >= end) m_val -= (storage_type)(end - begin); return org; } /** prefix ++ operator on tiny type */ inline TinyEnumT& operator ++ () { if (++m_val >= end) m_val -= (storage_type)(end - begin); return *this; } }; /** Template of struct holding enum types (on most archs, enums are stored in an int32). No math operators are provided. */ template struct SimpleTinyEnumT { storage_type m_val; ///< here we hold the actual value in small (i.e. byte) form /** Cast operator - invoked then the value is assigned to the storage_type */ inline operator enum_type () const { return (enum_type)this->m_val; } /** Assignment operator (from enum_type) */ inline SimpleTinyEnumT &operator = (enum_type e) { this->m_val = (storage_type)e; return *this; } /** Assignment operator (from general uint) */ inline SimpleTinyEnumT &operator = (uint u) { this->m_val = (storage_type)u; return *this; } /** Bit math (or) assignment operator (from enum_type) */ inline SimpleTinyEnumT &operator |= (enum_type e) { this->m_val = (storage_type)((enum_type)this->m_val | e); return *this; } /** Bit math (and) assignment operator (from enum_type) */ inline SimpleTinyEnumT &operator &= (enum_type e) { this->m_val = (storage_type)((enum_type)this->m_val & e); return *this; } }; #endif /* ENUM_TYPE_HPP */ openttd-1.5.3/src/core/mem_func.hpp0000644000000000000000000000571012627373435015733 0ustar rootroot/* $Id: mem_func.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 mem_func.hpp Functions related to memory operations. */ #ifndef MEM_FUNC_HPP #define MEM_FUNC_HPP #include "math_func.hpp" /** * Type-safe version of memcpy(). * * @param destination Pointer to the destination buffer * @param source Pointer to the source buffer * @param num number of items to be copied. (!not number of bytes!) */ template static inline void MemCpyT(T *destination, const T *source, size_t num = 1) { memcpy(destination, source, num * sizeof(T)); } /** * Type-safe version of memmove(). * * @param destination Pointer to the destination buffer * @param source Pointer to the source buffer * @param num number of items to be copied. (!not number of bytes!) */ template static inline void MemMoveT(T *destination, const T *source, size_t num = 1) { memmove(destination, source, num * sizeof(T)); } /** * Type-safe version of memset(). * * @param ptr Pointer to the destination buffer * @param value Value to be set * @param num number of items to be set (!not number of bytes!) */ template static inline void MemSetT(T *ptr, byte value, size_t num = 1) { memset(ptr, value, num * sizeof(T)); } /** * Type-safe version of memcmp(). * * @param ptr1 Pointer to the first buffer * @param ptr2 Pointer to the second buffer * @param num Number of items to compare. (!not number of bytes!) * @return an int value indicating the relationship between the content of the two buffers */ template static inline int MemCmpT(const T *ptr1, const T *ptr2, size_t num = 1) { return memcmp(ptr1, ptr2, num * sizeof(T)); } /** * Type safe memory reverse operation. * Reverse a block of memory in steps given by the * type of the pointers. * * @param ptr1 Start-pointer to the block of memory. * @param ptr2 End-pointer to the block of memory. */ template static inline void MemReverseT(T *ptr1, T *ptr2) { assert(ptr1 != NULL && ptr2 != NULL); assert(ptr1 < ptr2); do { Swap(*ptr1, *ptr2); } while (++ptr1 < --ptr2); } /** * Type safe memory reverse operation (overloaded) * * @param ptr Pointer to the block of memory. * @param num The number of items we want to reverse. */ template static inline void MemReverseT(T *ptr, size_t num) { assert(ptr != NULL); MemReverseT(ptr, ptr + (num - 1)); } #endif /* MEM_FUNC_HPP */ openttd-1.5.3/src/core/geometry_func.cpp0000644000000000000000000000224412627373435017002 0ustar rootroot/* $Id: geometry_func.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 geometry_func.cpp Geometry functions. */ #include "../stdafx.h" #include "geometry_func.hpp" #include "math_func.hpp" #include "../safeguards.h" /** * Compute bounding box of both dimensions. * @param d1 First dimension. * @param d2 Second dimension. * @return The bounding box of both dimensions, the smallest dimension that surrounds both arguments. */ Dimension maxdim(const Dimension &d1, const Dimension &d2) { Dimension d; d.width = max(d1.width, d2.width); d.height = max(d1.height, d2.height); return d; } openttd-1.5.3/src/core/math_func.cpp0000644000000000000000000000513212627373435016077 0ustar rootroot/* $Id: math_func.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 math_func.cpp Math functions. */ #include "../stdafx.h" #include "math_func.hpp" #include "../safeguards.h" /** * Compute least common multiple (lcm) of arguments \a a and \a b, the smallest * integer value that is a multiple of both \a a and \a b. * @param a First number. * @param b second number. * @return Least common multiple of values \a a and \a b. * * @note This function only works for non-negative values of \a a and \a b. */ int LeastCommonMultiple(int a, int b) { if (a == 0 || b == 0) return 0; // By definition. if (a == 1 || a == b) return b; if (b == 1) return a; return a * b / GreatestCommonDivisor(a, b); } /** * Compute greatest common divisor (gcd) of \a a and \a b. * @param a First number. * @param b second number. * @return Greatest common divisor of \a a and \a b. */ int GreatestCommonDivisor(int a, int b) { while (b != 0) { int t = b; b = a % b; a = t; } return a; } /** * 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; } /** * 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; } openttd-1.5.3/src/core/random_func.cpp0000644000000000000000000000504712627373435016433 0ustar rootroot/* $Id: random_func.cpp 27049 2014-10-28 11:32:19Z peter1138 $ */ /* * 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 random_func.cpp Implementation of the pseudo random generator. */ #include "../stdafx.h" #include "random_func.hpp" #include "bitmath_func.hpp" #ifdef RANDOM_DEBUG #include "../network/network.h" #include "../network/network_server.h" #include "../network/network_internal.h" #include "../company_func.h" #include "../fileio_func.h" #include "../date_func.h" #endif /* RANDOM_DEBUG */ #include "../safeguards.h" Randomizer _random, _interactive_random; /** * Generate the next pseudo random number * @return the random number */ uint32 Randomizer::Next() { const uint32 s = this->state[0]; const uint32 t = this->state[1]; this->state[0] = s + ROR(t ^ 0x1234567F, 7) + 1; return this->state[1] = ROR(s, 3) - 1; } /** * Generate the next pseudo random number scaled to \a limit, excluding \a limit * itself. * @param limit Limit of the range to be generated from. * @return Random number in [0,\a limit) */ uint32 Randomizer::Next(uint32 limit) { return ((uint64)this->Next() * (uint64)limit) >> 32; } /** * (Re)set the state of the random number generator. * @param seed the new state */ void Randomizer::SetSeed(uint32 seed) { this->state[0] = seed; this->state[1] = seed; } /** * (Re)set the state of the random number generators. * @param seed the new state */ void SetRandomSeed(uint32 seed) { _random.SetSeed(seed); _interactive_random.SetSeed(seed * 0x1234567); } #ifdef RANDOM_DEBUG uint32 DoRandom(int line, const char *file) { if (_networking && (!_network_server || (NetworkClientSocket::IsValidID(0) && NetworkClientSocket::Get(0)->status != NetworkClientSocket::STATUS_INACTIVE))) { DEBUG(random, 0, "%08x; %02x; %04x; %02x; %s:%d", _date, _date_fract, _frame_counter, (byte)_current_company, file, line); } return _random.Next(); } uint32 DoRandomRange(uint32 limit, int line, const char *file) { return ((uint64)DoRandom(line, file) * (uint64)limit) >> 32; } #endif /* RANDOM_DEBUG */ openttd-1.5.3/src/core/string_compare_type.hpp0000644000000000000000000000225312627373435020216 0ustar rootroot/* $Id: string_compare_type.hpp 22411 2011-05-02 17:42:12Z rubidium $ */ /* * 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 string_compare_type.hpp Comparator class for "const char *" so it can be used as a key for std::map */ #ifndef STRING_COMPARE_TYPE_HPP #define STRING_COMPARE_TYPE_HPP /** Comparator for strings. */ struct StringCompare { /** * Compare two strings. * @param a The first string. * @param b The second string. * @return True is the first string is deemed "lower" than the second string. */ bool operator () (const char *a, const char *b) const { return strcmp(a, b) < 0; } }; #endif /* STRING_COMPARE_TYPE_HPP */ openttd-1.5.3/src/core/pool_func.hpp0000644000000000000000000001422112627373435016123 0ustar rootroot/* $Id: pool_func.hpp 26057 2013-11-23 13:12:19Z rubidium $ */ /* * 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 pool_func.hpp Some methods of Pool are placed here in order to reduce compilation time and binary size. */ #ifndef POOL_FUNC_HPP #define POOL_FUNC_HPP #include "alloc_func.hpp" #include "mem_func.hpp" #include "pool_type.hpp" /** * Helper for defining the method's signature. * @param type The return type of the method. */ #define DEFINE_POOL_METHOD(type) \ template \ type Pool /** * Create a clean pool. * @param name The name for the pool. */ DEFINE_POOL_METHOD(inline)::Pool(const char *name) : PoolBase(Tpool_type), name(name), size(0), first_free(0), first_unused(0), items(0), #ifdef OTTD_ASSERT checked(0), #endif /* OTTD_ASSERT */ cleaning(false), data(NULL), alloc_cache(NULL) { } /** * Resizes the pool so 'index' can be addressed * @param index index we will allocate later * @pre index >= this->size * @pre index < Tmax_size */ DEFINE_POOL_METHOD(inline void)::ResizeFor(size_t index) { assert(index >= this->size); assert(index < Tmax_size); size_t new_size = min(Tmax_size, Align(index + 1, Tgrowth_step)); this->data = ReallocT(this->data, new_size); MemSetT(this->data + this->size, 0, new_size - this->size); this->size = new_size; } /** * Searches for first free index * @return first free index, NO_FREE_ITEM on failure */ DEFINE_POOL_METHOD(inline size_t)::FindFirstFree() { size_t index = this->first_free; for (; index < this->first_unused; index++) { if (this->data[index] == NULL) return index; } if (index < this->size) { return index; } assert(index == this->size); assert(this->first_unused == this->size); if (index < Tmax_size) { this->ResizeFor(index); return index; } assert(this->items == Tmax_size); return NO_FREE_ITEM; } /** * Makes given index valid * @param size size of item * @param index index of item * @pre index < this->size * @pre this->Get(index) == NULL */ DEFINE_POOL_METHOD(inline void *)::AllocateItem(size_t size, size_t index) { assert(this->data[index] == NULL); this->first_unused = max(this->first_unused, index + 1); this->items++; Titem *item; if (Tcache && this->alloc_cache != NULL) { assert(sizeof(Titem) == size); item = (Titem *)this->alloc_cache; this->alloc_cache = this->alloc_cache->next; if (Tzero) { /* Explicitly casting to (void *) prevents a clang warning - * we are actually memsetting a (not-yet-constructed) object */ memset((void *)item, 0, sizeof(Titem)); } } else if (Tzero) { item = (Titem *)CallocT(size); } else { item = (Titem *)MallocT(size); } this->data[index] = item; item->index = (uint)index; return item; } /** * Allocates new item * @param size size of item * @return pointer to allocated item * @note error() on failure! (no free item) */ DEFINE_POOL_METHOD(void *)::GetNew(size_t size) { size_t index = this->FindFirstFree(); #ifdef OTTD_ASSERT assert(this->checked != 0); this->checked--; #endif /* OTTD_ASSERT */ if (index == NO_FREE_ITEM) { error("%s: no more free items", this->name); } this->first_free = index + 1; return this->AllocateItem(size, index); } /** * Allocates new item with given index * @param size size of item * @param index index of item * @return pointer to allocated item * @note usererror() on failure! (index out of range or already used) */ DEFINE_POOL_METHOD(void *)::GetNew(size_t size, size_t index) { if (index >= Tmax_size) { usererror("failed loading savegame: %s index " PRINTF_SIZE " out of range (" PRINTF_SIZE ")", this->name, index, Tmax_size); } if (index >= this->size) this->ResizeFor(index); if (this->data[index] != NULL) { usererror("failed loading savegame: %s index " PRINTF_SIZE " already in use", this->name, index); } return this->AllocateItem(size, index); } /** * Deallocates memory used by this index and marks item as free * @param index item to deallocate * @pre unit is allocated (non-NULL) * @note 'delete NULL' doesn't cause call of this function, so it is safe */ DEFINE_POOL_METHOD(void)::FreeItem(size_t index) { assert(index < this->size); assert(this->data[index] != NULL); if (Tcache) { AllocCache *ac = (AllocCache *)this->data[index]; ac->next = this->alloc_cache; this->alloc_cache = ac; } else { free(this->data[index]); } this->data[index] = NULL; this->first_free = min(this->first_free, index); this->items--; if (!this->cleaning) Titem::PostDestructor(index); } /** Destroys all items in the pool and resets all member variables. */ DEFINE_POOL_METHOD(void)::CleanPool() { this->cleaning = true; for (size_t i = 0; i < this->first_unused; i++) { delete this->Get(i); // 'delete NULL;' is very valid } assert(this->items == 0); free(this->data); this->first_unused = this->first_free = this->size = 0; this->data = NULL; this->cleaning = false; if (Tcache) { while (this->alloc_cache != NULL) { AllocCache *ac = this->alloc_cache; this->alloc_cache = ac->next; free(ac); } } } #undef DEFINE_POOL_METHOD /** * Force instantiation of pool methods so we don't get linker errors. * Only methods accessed from methods defined in pool.hpp need to be * forcefully instantiated. */ #define INSTANTIATE_POOL_METHODS(name) \ template void * name ## Pool::GetNew(size_t size); \ template void * name ## Pool::GetNew(size_t size, size_t index); \ template void name ## Pool::FreeItem(size_t index); \ template void name ## Pool::CleanPool(); #endif /* POOL_FUNC_HPP */ openttd-1.5.3/src/core/multimap.hpp0000644000000000000000000003301112627373435015765 0ustar rootroot/* $Id: multimap.hpp 25371 2013-06-09 13:18:37Z rubidium $ */ /* * 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 template class MultiMap; /** * STL-style iterator for MultiMap. * @tparam Tmap_iter Iterator type for the map in the MultiMap. * @tparam Tlist_iter Iterator type for the lists in the MultiMap. * @tparam Tkey Key type of the MultiMap. * @tparam Tvalue Value type of the MultMap. * @tparam Tcompare Comparator type for keys of the MultiMap. */ template class MultiMapIterator { protected: friend class MultiMap; typedef MultiMapIterator Self; Tlist_iter list_iter; ///< Iterator pointing to current position in the current list of items with equal keys. Tmap_iter map_iter; ///< Iterator pointing to the position of the current list of items with equal keys in the map. /** * Flag to show that the iterator has just "walked" a step in the map. * We cannot check the current list for that as we might have reached end() of the map. In that case we'd need to * set list_iter to some sort of "invalid" state, but that's impossible as operator== yields undefined behaviour * if the iterators don't belong to the same list and there is no list at end(). So if we created a static empty * list and an "invalid" iterator in that we could not determine if the iterator is invalid while it's valid. We * can also not determine if the map iterator is valid while we don't have the map; so in the end it's easiest to * just introduce an extra flag. */ bool list_valid; public: /** * Simple, dangerous constructor to allow later assignment with operator=. */ MultiMapIterator() : list_valid(false) {} /** * Constructor to allow possibly const iterators to be assigned from possibly * non-const map iterators. You can assign end() like this. * @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const). * @param mi One such iterator. */ template MultiMapIterator(Tnon_const mi) : map_iter(mi), list_valid(false) {} /** * Constructor to allow specifying an exact position in map and list. You cannot * construct end() like this as the constructor will actually check li and mi->second * for list_valid. * @param mi Iterator in the map. * @param li Iterator in the list. */ MultiMapIterator(Tmap_iter mi, Tlist_iter li) : list_iter(li), map_iter(mi) { this->list_valid = (this->list_iter != this->map_iter->second.begin()); } /** * Assignment iterator like constructor with the same signature. * @tparam Tnon_const Iterator type assignable to Tmap_iter (which might be const). * @param mi One such iterator. * @return This iterator. */ template Self &operator=(Tnon_const mi) { this->map_iter = mi; this->list_valid = false; return *this; } /** * Dereference operator. Works just like usual STL operator*() on various containers. * Doesn't do a lot of checks for sanity, just like STL. * @return The value associated with the item this iterator points to. */ Tvalue &operator*() const { assert(!this->map_iter->second.empty()); return this->list_valid ? this->list_iter.operator*() : this->map_iter->second.begin().operator*(); } /** * Same as operator*(), but returns a pointer. * @return Pointer to the value this iterator points to. */ Tvalue *operator->() const { assert(!this->map_iter->second.empty()); return this->list_valid ? this->list_iter.operator->() : this->map_iter->second.begin().operator->(); } inline const Tmap_iter &GetMapIter() const { return this->map_iter; } inline const Tlist_iter &GetListIter() const { return this->list_iter; } inline bool ListValid() const { return this->list_valid; } const Tkey &GetKey() const { return this->map_iter->first; } /** * Prefix increment operator. Increment the iterator and set it to the * next item in the MultiMap. This either increments the list iterator * or the map iterator and sets list_valid accordingly. * @return This iterator after incrementing. */ Self &operator++() { assert(!this->map_iter->second.empty()); if (this->list_valid) { if (++this->list_iter == this->map_iter->second.end()) { ++this->map_iter; this->list_valid = false; } } else { this->list_iter = ++(this->map_iter->second.begin()); if (this->list_iter == this->map_iter->second.end()) { ++this->map_iter; } else { this->list_valid = true; } } return *this; } /** * Postfix increment operator. Same as prefix increment, but return the * previous state. * @param dummy param to mark postfix. * @return This iterator before incrementing. */ Self operator++(int) { Self tmp = *this; this->operator++(); return tmp; } /** * Prefix decrement operator. Decrement the iterator and set it to the * previous item in the MultiMap. * @return This iterator after decrementing. */ Self &operator--() { assert(!this->map_iter->second.empty()); if (!this->list_valid) { --this->map_iter; this->list_iter = this->map_iter->second.end(); assert(!this->map_iter->second.empty()); } this->list_valid = (--this->list_iter != this->map_iter->second.begin()); return *this; } /** * Postfix decrement operator. Same as prefix decrement, but return the * previous state. * @param dummy param to mark postfix. * @return This iterator before decrementing. */ Self operator--(int) { Self tmp = *this; this->operator--(); return tmp; } }; /* Generic comparison functions for const/non-const MultiMap iterators and map iterators */ /** * Compare two MultiMap iterators. Iterators are equal if * 1. Their map iterators are equal. * 2. They agree about list_valid. * 3. If list_valid they agree about list_iter. * Lots of template parameters to make all possible const and non-const types of MultiMap iterators * (on maps with const and non-const values) comparable to each other. * @param iter1 First iterator to compare. * @param iter2 Second iterator to compare. * @return If iter1 and iter2 are equal. */ template bool operator==(const MultiMapIterator &iter1, const MultiMapIterator &iter2) { if (iter1.GetMapIter() != iter2.GetMapIter()) return false; if (!iter1.ListValid()) return !iter2.ListValid(); return iter2.ListValid() ? iter1.GetListIter() == iter2.GetListIter() : false; } /** * Inverse of operator==(). * Lots of template parameters to make all possible const and non-const types of MultiMap iterators * (on maps with const and non-const values) comparable to each other. * @param iter1 First iterator to compare. * @param iter2 Second iterator to compare. * @return If iter1 and iter2 are not equal. */ template bool operator!=(const MultiMapIterator &iter1, const MultiMapIterator &iter2) { return !(iter1 == iter2); } /** * Check if a MultiMap iterator is at the begin of a list pointed to by the given map iterator. * Lots of template parameters to make all possible const and non-const types of MultiMap iterators * (on maps with const and non-const values) comparable to all possible types of map iterators. * @param iter1 MultiMap iterator. * @param iter2 Map iterator. * @return If iter1 points to the begin of the list pointed to by iter2. */ template bool operator==(const MultiMapIterator &iter1, const Tmap_iter2 &iter2) { return !iter1.ListValid() && iter1.GetMapIter() == iter2; } /** * Inverse of operator==() with same signature. * @param iter1 MultiMap iterator. * @param iter2 Map iterator. * @return If iter1 doesn't point to the begin of the list pointed to by iter2. */ template bool operator!=(const MultiMapIterator &iter1, const Tmap_iter2 &iter2) { return iter1.ListValid() || iter1.GetMapIter() != iter2; } /** * Same as operator==() with reversed order of arguments. * @param iter2 Map iterator. * @param iter1 MultiMap iterator. * @return If iter1 points to the begin of the list pointed to by iter2. */ template bool operator==(const Tmap_iter2 &iter2, const MultiMapIterator &iter1) { return !iter1.ListValid() && iter1.GetMapIter() == iter2; } /** * Same as operator!=() with reversed order of arguments. * @param iter2 Map iterator. * @param iter1 MultiMap iterator. * @return If iter1 doesn't point to the begin of the list pointed to by iter2. */ template bool operator!=(const Tmap_iter2 &iter2, const MultiMapIterator &iter1) { return iter1.ListValid() || iter1.GetMapIter() != iter2; } /** * Hand-rolled multimap as map of lists. Behaves mostly like a list, but is sorted * by Tkey so that you can easily look up ranges of equal keys. Those ranges are * internally ordered in a deterministic way (contrary to STL multimap). All * STL-compatible members are named in STL style, all others are named in OpenTTD * style. */ template > class MultiMap : public std::map, Tcompare > { public: typedef typename std::list List; typedef typename List::iterator ListIterator; typedef typename List::const_iterator ConstListIterator; typedef typename std::map Map; typedef typename Map::iterator MapIterator; typedef typename Map::const_iterator ConstMapIterator; typedef MultiMapIterator iterator; typedef MultiMapIterator const_iterator; /** * Erase the value pointed to by an iterator. The iterator may be invalid afterwards. * @param it Iterator pointing at some value. * @return Iterator to the element after the deleted one (or invalid). */ iterator erase(iterator it) { List &list = it.map_iter->second; assert(!list.empty()); if (it.list_valid) { it.list_iter = list.erase(it.list_iter); /* This can't be the first list element as otherwise list_valid would have * to be false. So the list cannot be empty here. */ if (it.list_iter == list.end()) { ++it.map_iter; it.list_valid = false; } } else { list.erase(list.begin()); if (list.empty()) this->Map::erase(it.map_iter++); } return it; } /** * Insert a value at the end of the range with the specified key. * @param key Key to be inserted at. * @param val Value to be inserted. */ void Insert(const Tkey &key, const Tvalue &val) { List &list = (*this)[key]; list.push_back(val); assert(!list.empty()); } /** * Count all items in this MultiMap. This involves iterating over the map. * @return Number of items in the MultiMap. */ size_t size() const { size_t ret = 0; for (ConstMapIterator it = this->Map::begin(); it != this->Map::end(); ++it) { ret += it->second.size(); } return ret; } /** * Count the number of ranges with equal keys in this MultiMap. * @return Number of ranges with equal keys. */ size_t MapSize() const { return this->Map::size(); } /** * Get a pair of iterators specifying a range of items with equal keys. * @param key Key to look for. * @return Range of items with given key. */ std::pair equal_range(const Tkey &key) { MapIterator begin(this->lower_bound(key)); if (begin != this->Map::end() && begin->first == key) { MapIterator end = begin; return std::make_pair(begin, ++end); } return std::make_pair(begin, begin); } /** * Get a pair of constant iterators specifying a range of items with equal keys. * @param key Key to look for. * @return Constant range of items with given key. */ std::pair equal_range(const Tkey &key) const { ConstMapIterator begin(this->lower_bound(key)); if (begin != this->Map::end() && begin->first == key) { ConstMapIterator end = begin; return std::make_pair(begin, ++end); } return std::make_pair(begin, begin); } }; #endif /* MULTIMAP_HPP */ openttd-1.5.3/src/core/endian_func.hpp0000644000000000000000000000354012627373435016412 0ustar rootroot/* $Id: endian_func.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 endian_func.hpp Function to handling different endian machines. */ #ifndef ENDIAN_FUNC_HPP #define ENDIAN_FUNC_HPP #include "endian_type.hpp" #include "bitmath_func.hpp" /* Setup alignment and conversion macros */ #if TTD_ENDIAN == TTD_BIG_ENDIAN #define FROM_BE16(x) (x) #define FROM_BE32(x) (x) #define TO_BE16(x) (x) #define TO_BE32(x) (x) #define TO_BE32X(x) (x) #define FROM_LE16(x) BSWAP16(x) #define FROM_LE32(x) BSWAP32(x) #define TO_LE16(x) BSWAP16(x) #define TO_LE32(x) BSWAP32(x) #define TO_LE32X(x) BSWAP32(x) #else #define FROM_BE16(x) BSWAP16(x) #define FROM_BE32(x) BSWAP32(x) #define TO_BE16(x) BSWAP16(x) #define TO_BE32(x) BSWAP32(x) #define TO_BE32X(x) BSWAP32(x) #define FROM_LE16(x) (x) #define FROM_LE32(x) (x) #define TO_LE16(x) (x) #define TO_LE32(x) (x) #define TO_LE32X(x) (x) #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ static inline uint16 ReadLE16Aligned(const void *x) { return FROM_LE16(*(const uint16*)x); } static inline uint16 ReadLE16Unaligned(const void *x) { #if OTTD_ALIGNMENT == 1 return ((const byte*)x)[0] | ((const byte*)x)[1] << 8; #else return FROM_LE16(*(const uint16*)x); #endif /* OTTD_ALIGNMENT == 1 */ } #endif /* ENDIAN_FUNC_HPP */ openttd-1.5.3/src/core/bitmath_func.cpp0000644000000000000000000000516412627373435016603 0ustar rootroot/* $Id: bitmath_func.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 bitmath_func.cpp Functions related to bit mathematics. */ #include "../stdafx.h" #include "bitmath_func.hpp" #include "../safeguards.h" const uint8 _ffb_64[64] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, }; /** * Search the first set bit in a 32 bit variable. * * This algorithm is a static implementation of a log * congruence search algorithm. It checks the first half * if there is a bit set search there further. And this * way further. If no bit is set return 0. * * @param x The value to search * @return The position of the first bit set */ uint8 FindFirstBit(uint32 x) { if (x == 0) return 0; /* The macro FIND_FIRST_BIT is better to use when your x is not more than 128. */ uint8 pos = 0; if ((x & 0x0000ffff) == 0) { x >>= 16; pos += 16; } if ((x & 0x000000ff) == 0) { x >>= 8; pos += 8; } if ((x & 0x0000000f) == 0) { x >>= 4; pos += 4; } if ((x & 0x00000003) == 0) { x >>= 2; pos += 2; } if ((x & 0x00000001) == 0) { pos += 1; } return pos; } /** * Search the last set bit in a 64 bit variable. * * This algorithm is a static implementation of a log * congruence search algorithm. It checks the second half * if there is a bit set search there further. And this * way further. If no bit is set return 0. * * @param x The value to search * @return The position of the last bit set */ uint8 FindLastBit(uint64 x) { if (x == 0) return 0; uint8 pos = 0; if ((x & 0xffffffff00000000ULL) != 0) { x >>= 32; pos += 32; } if ((x & 0x00000000ffff0000ULL) != 0) { x >>= 16; pos += 16; } if ((x & 0x000000000000ff00ULL) != 0) { x >>= 8; pos += 8; } if ((x & 0x00000000000000f0ULL) != 0) { x >>= 4; pos += 4; } if ((x & 0x000000000000000cULL) != 0) { x >>= 2; pos += 2; } if ((x & 0x0000000000000002ULL) != 0) { pos += 1; } return pos; } openttd-1.5.3/src/core/pool_func.cpp0000644000000000000000000000261112627373435016116 0ustar rootroot/* $Id: pool_func.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 pool_func.cpp Implementation of PoolBase methods. */ #include "../stdafx.h" #include "pool_type.hpp" #include "../safeguards.h" /** * Destructor removes this object from the pool vector and * deletes the vector itself if this was the last item removed. */ /* virtual */ PoolBase::~PoolBase() { PoolVector *pools = PoolBase::GetPools(); pools->Erase(pools->Find(this)); if (pools->Length() == 0) delete pools; } /** * Clean all pools of given type. * @param pt pool types to clean. */ /* static */ void PoolBase::Clean(PoolType pt) { PoolVector *pools = PoolBase::GetPools(); PoolBase **end = pools->End(); for (PoolBase **ppool = pools->Begin(); ppool != end; ppool++) { PoolBase *pool = *ppool; if (pool->type & pt) pool->CleanPool(); } } openttd-1.5.3/src/core/alloc_func.hpp0000644000000000000000000001157412627373435016254 0ustar rootroot/* $Id: alloc_func.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 alloc_func.hpp Functions related to the allocation of memory */ #ifndef ALLOC_FUNC_HPP #define ALLOC_FUNC_HPP /* * Functions to exit badly with an error message. * It has to be linked so the error messages are not * duplicated in each object file making the final * binary needlessly large. */ void NORETURN MallocError(size_t size); void NORETURN ReallocError(size_t size); /** * Checks whether allocating memory would overflow size_t. * * @param element_size Size of the structure to allocate. * @param num_elements Number of elements to allocate. */ static inline void CheckAllocationConstraints(size_t element_size, size_t num_elements) { if (num_elements > SIZE_MAX / element_size) MallocError(SIZE_MAX); } /** * Checks whether allocating memory would overflow size_t. * * @tparam T Structure to allocate. * @param num_elements Number of elements to allocate. */ template static inline void CheckAllocationConstraints(size_t num_elements) { CheckAllocationConstraints(sizeof(T), num_elements); } /** * Simplified allocation function that allocates the specified number of * elements of the given type. It also explicitly casts it to the requested * type. * @note throws an error when there is no memory anymore. * @note the memory contains garbage data (i.e. possibly non-zero values). * @tparam T the type of the variable(s) to allocation. * @param num_elements the number of elements to allocate of the given type. * @return NULL when num_elements == 0, non-NULL otherwise. */ template static inline T *MallocT(size_t num_elements) { /* * MorphOS cannot handle 0 elements allocations, or rather that always * returns NULL. So we do that for *all* allocations, thus causing it * to behave the same on all OSes. */ if (num_elements == 0) return NULL; /* Ensure the size does not overflow. */ CheckAllocationConstraints(num_elements); T *t_ptr = (T*)malloc(num_elements * sizeof(T)); if (t_ptr == NULL) MallocError(num_elements * sizeof(T)); return t_ptr; } /** * Simplified allocation function that allocates the specified number of * elements of the given type. It also explicitly casts it to the requested * type. * @note throws an error when there is no memory anymore. * @note the memory contains all zero values. * @tparam T the type of the variable(s) to allocation. * @param num_elements the number of elements to allocate of the given type. * @return NULL when num_elements == 0, non-NULL otherwise. */ template static inline T *CallocT(size_t num_elements) { /* * MorphOS cannot handle 0 elements allocations, or rather that always * returns NULL. So we do that for *all* allocations, thus causing it * to behave the same on all OSes. */ if (num_elements == 0) return NULL; T *t_ptr = (T*)calloc(num_elements, sizeof(T)); if (t_ptr == NULL) MallocError(num_elements * sizeof(T)); return t_ptr; } /** * Simplified reallocation function that allocates the specified number of * elements of the given type. It also explicitly casts it to the requested * type. It extends/shrinks the memory allocation given in t_ptr. * @note throws an error when there is no memory anymore. * @note the pointer to the data may change, but the data will remain valid. * @tparam T the type of the variable(s) to allocation. * @param t_ptr the previous allocation to extend/shrink. * @param num_elements the number of elements to allocate of the given type. * @return NULL when num_elements == 0, non-NULL otherwise. */ template static inline T *ReallocT(T *t_ptr, size_t num_elements) { /* * MorphOS cannot handle 0 elements allocations, or rather that always * returns NULL. So we do that for *all* allocations, thus causing it * to behave the same on all OSes. */ if (num_elements == 0) { free(t_ptr); return NULL; } /* Ensure the size does not overflow. */ CheckAllocationConstraints(num_elements); t_ptr = (T*)realloc(t_ptr, num_elements * sizeof(T)); if (t_ptr == NULL) ReallocError(num_elements * sizeof(T)); return t_ptr; } /** alloca() has to be called in the parent function, so define AllocaM() as a macro */ #define AllocaM(T, num_elements) \ (CheckAllocationConstraints(num_elements), \ (T*)alloca((num_elements) * sizeof(T))) #endif /* ALLOC_FUNC_HPP */ openttd-1.5.3/src/core/geometry_func.hpp0000644000000000000000000000155512627373435017013 0ustar rootroot/* $Id: geometry_func.hpp 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 geometry_func.hpp Geometry functions. */ #ifndef GEOMETRY_FUNC_HPP #define GEOMETRY_FUNC_HPP #include "geometry_type.hpp" Dimension maxdim(const Dimension &d1, const Dimension &d2); #endif /* GEOMETRY_FUNC_HPP */ openttd-1.5.3/src/core/math_func.hpp0000644000000000000000000002270712627373435016113 0ustar rootroot/* $Id: math_func.hpp 26651 2014-06-17 19:01:45Z rubidium $ */ /* * 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 math_func.hpp Integer math functions */ #ifndef MATH_FUNC_HPP #define MATH_FUNC_HPP /** * Returns the maximum of two values. * * This function returns the greater value of two given values. * If they are equal the value of a is returned. * * @param a The first value * @param b The second value * @return The greater value or a if equals */ template static inline T max(const T a, const T b) { return (a >= b) ? a : b; } /** * Returns the minimum of two values. * * This function returns the smaller value of two given values. * If they are equal the value of b is returned. * * @param a The first value * @param b The second value * @return The smaller value or b if equals */ template static inline T min(const T a, const T b) { return (a < b) ? a : b; } /** * Returns the minimum of two integer. * * This function returns the smaller value of two given integers. * * @param a The first integer * @param b The second integer * @return The smaller value */ static inline int min(const int a, const int b) { return min(a, b); } /** * Returns the minimum of two unsigned integers. * * This function returns the smaller value of two given unsigned integers. * * @param a The first unsigned integer * @param b The second unsigned integer * @return The smaller value */ static inline uint minu(const uint a, const uint b) { return min(a, b); } /** * Returns the absolute value of (scalar) variable. * * @note assumes variable to be signed * @param a The value we want to unsign * @return The unsigned value */ template static inline T abs(const T a) { return (a < (T)0) ? -a : a; } /** * Return the smallest multiple of n equal or greater than x * * @note n must be a power of 2 * @param x The min value * @param n The base of the number we are searching * @return The smallest multiple of n equal or greater than x */ template static inline T Align(const T x, uint n) { assert((n & (n - 1)) == 0 && n != 0); n--; return (T)((x + n) & ~((T)n)); } /** * Return the smallest multiple of n equal or greater than x * Applies to pointers only * * @note n must be a power of 2 * @param x The min value * @param n The base of the number we are searching * @return The smallest multiple of n equal or greater than x * @see Align() */ template static inline T *AlignPtr(T *x, uint n) { assert_compile(sizeof(size_t) == sizeof(void *)); return (T *)Align((size_t)x, n); } /** * Clamp a value between an interval. * * This function returns a value which is between the given interval of * min and max. If the given value is in this interval the value itself * is returned otherwise the border of the interval is returned, according * which side of the interval was 'left'. * * @note The min value must be less or equal of max or you get some * unexpected results. * @param a The value to clamp/truncate. * @param min The minimum of the interval. * @param max the maximum of the interval. * @returns A value between min and max which is closest to a. * @see ClampU(uint, uint, uint) * @see Clamp(int, int, int) */ template static inline T Clamp(const T a, const T min, const T max) { assert(min <= max); if (a <= min) return min; if (a >= max) return max; return a; } /** * Clamp an integer between an interval. * * This function returns a value which is between the given interval of * min and max. If the given value is in this interval the value itself * is returned otherwise the border of the interval is returned, according * which side of the interval was 'left'. * * @note The min value must be less or equal of max or you get some * unexpected results. * @param a The value to clamp/truncate. * @param min The minimum of the interval. * @param max the maximum of the interval. * @returns A value between min and max which is closest to a. * @see ClampU(uint, uint, uint) */ static inline int Clamp(const int a, const int min, const int max) { return Clamp(a, min, max); } /** * Clamp an unsigned integer between an interval. * * This function returns a value which is between the given interval of * min and max. If the given value is in this interval the value itself * is returned otherwise the border of the interval is returned, according * which side of the interval was 'left'. * * @note The min value must be less or equal of max or you get some * unexpected results. * @param a The value to clamp/truncate. * @param min The minimum of the interval. * @param max the maximum of the interval. * @returns A value between min and max which is closest to a. * @see Clamp(int, int, int) */ static inline uint ClampU(const uint a, const uint min, const uint max) { return Clamp(a, min, max); } /** * Reduce a signed 64-bit int to a signed 32-bit one * * This function clamps a 64-bit integer to a 32-bit integer. * If the 64-bit value is smaller than the smallest 32-bit integer * value 0x80000000 this value is returned (the left one bit is the sign bit). * If the 64-bit value is greater than the greatest 32-bit integer value 0x7FFFFFFF * this value is returned. In all other cases the 64-bit value 'fits' in a * 32-bits integer field and so the value is casted to int32 and returned. * * @param a The 64-bit value to clamps * @return The 64-bit value reduced to a 32-bit value * @see Clamp(int, int, int) */ static inline int32 ClampToI32(const int64 a) { return (int32)Clamp(a, INT32_MIN, INT32_MAX); } /** * Reduce an unsigned 64-bit int to an unsigned 16-bit one * * @param a The 64-bit value to clamp * @return The 64-bit value reduced to a 16-bit value * @see ClampU(uint, uint, uint) */ static inline uint16 ClampToU16(const uint64 a) { /* MSVC thinks, in its infinite wisdom, that int min(int, int) is a better * match for min(uint64, uint) than uint64 min(uint64, uint64). As such we * need to cast the UINT16_MAX to prevent MSVC from displaying its * infinite loads of warnings. */ return (uint16)min(a, (uint64)UINT16_MAX); } /** * Returns the (absolute) difference between two (scalar) variables * * @param a The first scalar * @param b The second scalar * @return The absolute difference between the given scalars */ template static inline T Delta(const T a, const T b) { return (a < b) ? b - a : a - b; } /** * Checks if a value is between a window started at some base point. * * This function checks if the value x is between the value of base * and base+size. If x equals base this returns true. If x equals * base+size this returns false. * * @param x The value to check * @param base The base value of the interval * @param size The size of the interval * @return True if the value is in the interval, false else. */ template static inline bool IsInsideBS(const T x, const uint base, const uint size) { return (uint)(x - base) < size; } /** * Checks if a value is in an interval. * * Returns true if a value is in the interval of [min, max). * * @param x The value to check * @param min The minimum of the interval * @param max The maximum of the interval * @see IsInsideBS() */ template static inline bool IsInsideMM(const T x, const uint min, const uint max) { return (uint)(x - min) < (max - min); } /** * Type safe swap operation * @param a variable to swap with b * @param b variable to swap with a */ template static inline void Swap(T &a, T &b) { T t = a; a = b; b = t; } /** * Converts a "fract" value 0..255 to "percent" value 0..100 * @param i value to convert, range 0..255 * @return value in range 0..100 */ static inline uint ToPercent8(uint i) { assert(i < 256); return i * 101 >> 8; } /** * Converts a "fract" value 0..65535 to "percent" value 0..100 * @param i value to convert, range 0..65535 * @return value in range 0..100 */ static inline uint ToPercent16(uint i) { assert(i < 65536); return i * 101 >> 16; } 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. * @param a Numerator * @param b Denominator * @return Quotient, rounded up */ static inline uint CeilDiv(uint a, uint b) { return (a + b - 1) / b; } /** * Computes ceil(a / b) * b for non-negative a and b. * @param a Numerator * @param b Denominator * @return a rounded up to the nearest multiple of b. */ static inline uint Ceil(uint a, uint b) { return CeilDiv(a, b) * b; } /** * Computes round(a / b) for signed a and unsigned b. * @param a Numerator * @param b Denominator * @return Quotient, rounded to nearest */ static inline int RoundDivSU(int a, uint b) { if (a > 0) { /* 0.5 is rounded to 1 */ return (a + (int)b / 2) / (int)b; } else { /* -0.5 is rounded to 0 */ return (a - ((int)b - 1) / 2) / (int)b; } } uint32 IntSqrt(uint32 num); #endif /* MATH_FUNC_HPP */ openttd-1.5.3/src/core/alloc_type.hpp0000644000000000000000000001316212627373435016275 0ustar rootroot/* $Id: alloc_type.hpp 23880 2012-02-04 13:28:35Z michi_cc $ */ /* * 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 alloc_type.hpp Helper types related to the allocation of memory */ #ifndef ALLOC_TYPE_HPP #define ALLOC_TYPE_HPP #include "alloc_func.hpp" /** * A small 'wrapper' for allocations that can be done on most OSes on the * stack, but are just too large to fit in the stack on devices with a small * stack such as the NDS. * So when it is possible a stack allocation is made, otherwise a heap * allocation is made and this is freed once the struct goes out of scope. * @param T the type to make the allocation for * @param length the amount of items to allocate */ template struct SmallStackSafeStackAlloc { #if !defined(__NDS__) /** Storing the data on the stack */ T data[length]; #else /** Storing it on the heap */ T *data; /** The length (in elements) of data in this allocator. */ size_t len; /** Allocating the memory */ SmallStackSafeStackAlloc() : data(MallocT(length)), len(length) {} /** And freeing when it goes out of scope */ ~SmallStackSafeStackAlloc() { free(data); } #endif /** * Gets a pointer to the data stored in this wrapper. * @return the pointer. */ inline operator T *() { return data; } /** * Gets a pointer to the data stored in this wrapper. * @return the pointer. */ inline T *operator -> () { return data; } /** * Gets a pointer to the last data element stored in this wrapper. * @note needed because endof does not work properly for pointers. * @return the 'endof' pointer. */ inline T *EndOf() { #if !defined(__NDS__) return endof(data); #else return &data[len]; #endif } }; /** * A reusable buffer that can be used for places that temporary allocate * a bit of memory and do that very often, or for places where static * memory is allocated that might need to be reallocated sometimes. * * Every time Allocate or ZeroAllocate is called previous results of both * functions will become invalid. */ template class ReusableBuffer { private: T *buffer; ///< The real data buffer size_t count; ///< Number of T elements in the buffer public: /** Create a new buffer */ ReusableBuffer() : buffer(NULL), count(0) {} /** Clear the buffer */ ~ReusableBuffer() { free(this->buffer); } /** * Get buffer of at least count times T. * @note the buffer might be bigger * @note calling this function invalidates any previous buffers given * @param count the minimum buffer size * @return the buffer */ T *Allocate(size_t count) { if (this->count < count) { free(this->buffer); this->buffer = MallocT(count); this->count = count; } return this->buffer; } /** * Get buffer of at least count times T with zeroed memory. * @note the buffer might be bigger * @note calling this function invalidates any previous buffers given * @param count the minimum buffer size * @return the buffer */ T *ZeroAllocate(size_t count) { if (this->count < count) { free(this->buffer); this->buffer = CallocT(count); this->count = count; } else { memset(this->buffer, 0, sizeof(T) * count); } return this->buffer; } /** * Get the currently allocated buffer. * @return the buffer */ inline const T *GetBuffer() const { return this->buffer; } }; /** * Base class that provides memory initialization on dynamically created objects. * All allocated memory will be zeroed. */ class ZeroedMemoryAllocator { public: ZeroedMemoryAllocator() {} virtual ~ZeroedMemoryAllocator() {} /** * Memory allocator for a single class instance. * @param size the amount of bytes to allocate. * @return the given amounts of bytes zeroed. */ inline void *operator new(size_t size) { return CallocT(size); } /** * Memory allocator for an array of class instances. * @param size the amount of bytes to allocate. * @return the given amounts of bytes zeroed. */ inline void *operator new[](size_t size) { return CallocT(size); } /** * Memory release for a single class instance. * @param ptr the memory to free. */ inline void operator delete(void *ptr) { free(ptr); } /** * Memory release for an array of class instances. * @param ptr the memory to free. */ inline void operator delete[](void *ptr) { free(ptr); } }; /** * A smart pointer class that free()'s the pointer on destruction. * @tparam T Storage type. */ template class AutoFreePtr { T *ptr; ///< Stored pointer. public: AutoFreePtr(T *ptr) : ptr(ptr) {} ~AutoFreePtr() { free(this->ptr); } /** * Take ownership of a new pointer and free the old one if needed. * @param ptr NEw pointer. */ inline void Assign(T *ptr) { free(this->ptr); this->ptr = ptr; } /** Dereference pointer. */ inline T *operator ->() { return this->ptr; } /** Dereference pointer. */ inline const T *operator ->() const { return this->ptr; } /** Cast to underlaying regular pointer. */ inline operator T *() { return this->ptr; } /** Cast to underlaying regular pointer. */ inline operator const T *() const { return this->ptr; } }; #endif /* ALLOC_TYPE_HPP */ openttd-1.5.3/src/core/sort_func.hpp0000644000000000000000000000472212627373435016146 0ustar rootroot/* $Id: sort_func.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 sort_func.hpp Functions related to sorting operations. */ #ifndef SORT_FUNC_HPP #define SORT_FUNC_HPP #include "mem_func.hpp" /** * Type safe qsort() * * @note Use this sort for irregular sorted data. * * @param base Pointer to the first element of the array to be sorted. * @param num Number of elements in the array pointed by base. * @param comparator Function that compares two elements. * @param desc Sort descending. */ template static inline void QSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false) { if (num < 2) return; qsort(base, num, sizeof(T), (int (CDECL *)(const void *, const void *))comparator); if (desc) MemReverseT(base, num); } /** * Type safe Gnome Sort. * * This is a slightly modified Gnome search. The basic * Gnome search tries to sort already sorted list parts. * The modification skips these. * * @note Use this sort for presorted / regular sorted data. * * @param base Pointer to the first element of the array to be sorted. * @param num Number of elements in the array pointed by base. * @param comparator Function that compares two elements. * @param desc Sort descending. */ template static inline void GSortT(T *base, uint num, int (CDECL *comparator)(const T*, const T*), bool desc = false) { if (num < 2) return; assert(base != NULL); assert(comparator != NULL); T *a = base; T *b = base + 1; uint offset = 0; while (num > 1) { const int diff = comparator(a, b); if ((!desc && diff <= 0) || (desc && diff >= 0)) { if (offset != 0) { /* Jump back to the last direction switch point */ a += offset; b += offset; offset = 0; continue; } a++; b++; num--; } else { Swap(*a, *b); if (a == base) continue; a--; b--; offset++; } } } #endif /* SORT_FUNC_HPP */ openttd-1.5.3/src/core/smallvec_type.hpp0000644000000000000000000002270412627373435017013 0ustar rootroot/* $Id: smallvec_type.hpp 25043 2013-02-24 16:43:24Z frosch $ */ /* * 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 smallvec_type.hpp Simple vector class that allows allocating an item without the need to copy this->data needlessly. */ #ifndef SMALLVEC_TYPE_HPP #define SMALLVEC_TYPE_HPP #include "alloc_func.hpp" #include "mem_func.hpp" /** * Simple vector template class. * * @note There are no asserts in the class so you have * to care about that you grab an item which is * inside the list. * * @tparam T The type of the items stored * @tparam S The steps of allocation */ template class SmallVector { protected: T *data; ///< The pointer to the first item uint items; ///< The number of items stored uint capacity; ///< The available space for storing items public: SmallVector() : data(NULL), items(0), capacity(0) { } /** * Copy constructor. * @param other The other vector to copy. */ SmallVector(const SmallVector &other) : data(NULL), items(0), capacity(0) { this->Assign(other); } /** * Generic copy constructor. * @param other The other vector to copy. */ template SmallVector(const SmallVector &other) : data(NULL), items(0), capacity(0) { this->Assign(other); } /** * Assignment. * @param other The other vector to assign. */ SmallVector &operator=(const SmallVector &other) { this->Assign(other); return *this; } /** * Generic assignment. * @param other The other vector to assign. */ template SmallVector &operator=(const SmallVector &other) { this->Assign(other); return *this; } ~SmallVector() { free(this->data); } /** * Assign items from other vector. */ template inline void Assign(const SmallVector &other) { if ((const void *)&other == (void *)this) return; this->Clear(); if (other.Length() > 0) MemCpyT(this->Append(other.Length()), other.Begin(), other.Length()); } /** * Remove all items from the list. */ inline void Clear() { /* In fact we just reset the item counter avoiding the need to * probably reallocate the same amount of memory the list was * previously using. */ this->items = 0; } /** * Remove all items from the list and free allocated memory. */ inline void Reset() { this->items = 0; this->capacity = 0; free(data); data = NULL; } /** * Compact the list down to the smallest block size boundary. */ inline void Compact() { uint capacity = Align(this->items, S); if (capacity >= this->capacity) return; this->capacity = capacity; this->data = ReallocT(this->data, this->capacity); } /** * Append an item and return it. * @param to_add the number of items to append * @return pointer to newly allocated item */ inline T *Append(uint to_add = 1) { uint begin = this->items; this->items += to_add; if (this->items > this->capacity) { this->capacity = Align(this->items, S); this->data = ReallocT(this->data, this->capacity); } return &this->data[begin]; } /** * Set the size of the vector, effectively truncating items from the end or appending uninitialised ones. * @param num_items Target size. */ inline void Resize(uint num_items) { this->items = num_items; if (this->items > this->capacity) { this->capacity = Align(this->items, S); this->data = ReallocT(this->data, this->capacity); } } /** * Search for the first occurrence of an item. * The '!=' operator of T is used for comparison. * @param item Item to search for * @return The position of the item, or End() when not present */ inline const T *Find(const T &item) const { const T *pos = this->Begin(); const T *end = this->End(); while (pos != end && *pos != item) pos++; return pos; } /** * Search for the first occurrence of an item. * The '!=' operator of T is used for comparison. * @param item Item to search for * @return The position of the item, or End() when not present */ inline T *Find(const T &item) { T *pos = this->Begin(); const T *end = this->End(); while (pos != end && *pos != item) pos++; return pos; } /** * Search for the first occurrence of an item. * The '!=' operator of T is used for comparison. * @param item Item to search for * @return The position of the item, or -1 when not present */ inline int FindIndex(const T &item) const { int index = 0; const T *pos = this->Begin(); const T *end = this->End(); while (pos != end && *pos != item) { pos++; index++; } return pos == end ? -1 : index; } /** * Tests whether a item is present in the vector. * The '!=' operator of T is used for comparison. * @param item Item to test for * @return true iff the item is present */ inline bool Contains(const T &item) const { return this->Find(item) != this->End(); } /** * Removes given item from this vector * @param item item to remove * @note it has to be pointer to item in this map. It is overwritten by the last item. */ inline void Erase(T *item) { assert(item >= this->Begin() && item < this->End()); *item = this->data[--this->items]; } /** * Remove items from the vector while preserving the order of other items. * @param pos First item to remove. * @param count Number of consecutive items to remove. */ void ErasePreservingOrder(uint pos, uint count = 1) { if (count == 0) return; assert(pos < this->items); assert(pos + count <= this->items); this->items -= count; uint to_move = this->items - pos; if (to_move > 0) MemMoveT(this->data + pos, this->data + pos + count, to_move); } /** * Tests whether a item is present in the vector, and appends it to the end if not. * The '!=' operator of T is used for comparison. * @param item Item to test for * @return true iff the item is was already present */ inline bool Include(const T &item) { bool is_member = this->Contains(item); if (!is_member) *this->Append() = item; return is_member; } /** * Get the number of items in the list. */ inline uint Length() const { return this->items; } /** * Get the pointer to the first item (const) * * @return the pointer to the first item */ inline const T *Begin() const { return this->data; } /** * Get the pointer to the first item * * @return the pointer to the first item */ inline T *Begin() { return this->data; } /** * Get the pointer behind the last valid item (const) * * @return the pointer behind the last valid item */ inline const T *End() const { return &this->data[this->items]; } /** * Get the pointer behind the last valid item * * @return the pointer behind the last valid item */ inline T *End() { return &this->data[this->items]; } /** * Get the pointer to item "number" (const) * * @param index the position of the item * @return the pointer to the item */ inline const T *Get(uint index) const { /* Allow access to the 'first invalid' item */ assert(index <= this->items); return &this->data[index]; } /** * Get the pointer to item "number" * * @param index the position of the item * @return the pointer to the item */ inline T *Get(uint index) { /* Allow access to the 'first invalid' item */ assert(index <= this->items); return &this->data[index]; } /** * Get item "number" (const) * * @param index the position of the item * @return the item */ inline const T &operator[](uint index) const { assert(index < this->items); return this->data[index]; } /** * Get item "number" * * @param index the position of the item * @return the item */ inline T &operator[](uint index) { assert(index < this->items); return this->data[index]; } }; /** * Simple vector template class, with automatic free. * * @note There are no asserts in the class so you have * to care about that you grab an item which is * inside the list. * * @param T The type of the items stored, must be a pointer * @param S The steps of allocation */ template class AutoFreeSmallVector : public SmallVector { public: ~AutoFreeSmallVector() { this->Clear(); } /** * Remove all items from the list. */ inline void Clear() { for (uint i = 0; i < this->items; i++) { free(this->data[i]); } this->items = 0; } }; /** * Simple vector template class, with automatic delete. * * @note There are no asserts in the class so you have * to care about that you grab an item which is * inside the list. * * @param T The type of the items stored, must be a pointer * @param S The steps of allocation */ template class AutoDeleteSmallVector : public SmallVector { public: ~AutoDeleteSmallVector() { this->Clear(); } /** * Remove all items from the list. */ inline void Clear() { for (uint i = 0; i < this->items; i++) { delete this->data[i]; } this->items = 0; } }; typedef AutoFreeSmallVector StringList; ///< Type for a list of strings. #endif /* SMALLVEC_TYPE_HPP */ openttd-1.5.3/src/core/bitmath_func.hpp0000644000000000000000000003073512627373435016612 0ustar rootroot/* $Id: bitmath_func.hpp 25685 2013-08-05 20:37:29Z michi_cc $ */ /* * 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 bitmath_func.hpp Functions related to bit mathematics. */ #ifndef BITMATH_FUNC_HPP #define BITMATH_FUNC_HPP /** * Fetch \a n bits from \a x, started at bit \a s. * * This function can be used to fetch \a n bits from the value \a x. The * \a s value set the start position to read. The start position is * count from the LSB and starts at \c 0. The result starts at a * LSB, as this isn't just an and-bitmask but also some * bit-shifting operations. GB(0xFF, 2, 1) will so * return 0x01 (0000 0001) instead of * 0x04 (0000 0100). * * @param x The value to read some bits. * @param s The start position to read some bits. * @param n The number of bits to read. * @pre n < sizeof(T) * 8 * @pre s + n <= sizeof(T) * 8 * @return The selected bits, aligned to a LSB. */ template static inline uint GB(const T x, const uint8 s, const uint8 n) { return (x >> s) & (((T)1U << n) - 1); } /** * Set \a n bits in \a x starting at bit \a s to \a d * * This function sets \a n bits from \a x which started as bit \a s to the value of * \a d. The parameters \a x, \a s and \a n works the same as the parameters of * #GB. The result is saved in \a x again. Unused bits in the window * provided by n are set to 0 if the value of \a d isn't "big" enough. * This is not a bug, its a feature. * * @note Parameter \a x must be a variable as the result is saved there. * @note To avoid unexpected results the value of \a d should not use more * space as the provided space of \a n bits (log2) * @param x The variable to change some bits * @param s The start position for the new bits * @param n The size/window for the new bits * @param d The actually new bits to save in the defined position. * @pre n < sizeof(T) * 8 * @pre s + n <= sizeof(T) * 8 * @return The new value of \a x */ template static inline T SB(T &x, const uint8 s, const uint8 n, const U d) { x &= (T)(~((((T)1U << n) - 1) << s)); x |= (T)(d << s); return x; } /** * Add \a i to \a n bits of \a x starting at bit \a s. * * This adds the value of \a i on \a n bits of \a x starting at bit \a s. The parameters \a x, * \a s, \a i are similar to #GB. Besides, \ a x must be a variable as the result are * saved there. An overflow does not affect the following bits of the given * bit window and is simply ignored. * * @note Parameter x must be a variable as the result is saved there. * @param x The variable to add some bits at some position * @param s The start position of the addition * @param n The size/window for the addition * @pre n < sizeof(T) * 8 * @pre s + n <= sizeof(T) * 8 * @param i The value to add at the given start position in the given window. * @return The new value of \a x */ template static inline T AB(T &x, const uint8 s, const uint8 n, const U i) { const T mask = ((((T)1U << n) - 1) << s); x = (T)((x & ~mask) | ((x + (i << s)) & mask)); return x; } /** * Checks if a bit in a value is set. * * This function checks if a bit inside a value is set or not. * The \a y value specific the position of the bit, started at the * LSB and count from \c 0. * * @param x The value to check * @param y The position of the bit to check, started from the LSB * @pre y < sizeof(T) * 8 * @return True if the bit is set, false else. */ template static inline bool HasBit(const T x, const uint8 y) { return (x & ((T)1U << y)) != 0; } /** * Set a bit in a variable. * * This function sets a bit in a variable. The variable is changed * and the value is also returned. Parameter y defines the bit and * starts at the LSB with 0. * * @param x The variable to set a bit * @param y The bit position to set * @pre y < sizeof(T) * 8 * @return The new value of the old value with the bit set */ template static inline T SetBit(T &x, const uint8 y) { return x = (T)(x | ((T)1U << y)); } /** * Sets several bits in a variable. * * This macro sets several bits in a variable. The bits to set are provided * by a value. The new value is also returned. * * @param x The variable to set some bits * @param y The value with set bits for setting them in the variable * @return The new value of x */ #define SETBITS(x, y) ((x) |= (y)) /** * Clears a bit in a variable. * * This function clears a bit in a variable. The variable is * changed and the value is also returned. Parameter y defines the bit * to clear and starts at the LSB with 0. * * @param x The variable to clear the bit * @param y The bit position to clear * @pre y < sizeof(T) * 8 * @return The new value of the old value with the bit cleared */ template static inline T ClrBit(T &x, const uint8 y) { return x = (T)(x & ~((T)1U << y)); } /** * Clears several bits in a variable. * * This macro clears several bits in a variable. The bits to clear are * provided by a value. The new value is also returned. * * @param x The variable to clear some bits * @param y The value with set bits for clearing them in the variable * @return The new value of x */ #define CLRBITS(x, y) ((x) &= ~(y)) /** * Toggles a bit in a variable. * * This function toggles a bit in a variable. The variable is * changed and the value is also returned. Parameter y defines the bit * to toggle and starts at the LSB with 0. * * @param x The variable to toggle the bit * @param y The bit position to toggle * @pre y < sizeof(T) * 8 * @return The new value of the old value with the bit toggled */ template static inline T ToggleBit(T &x, const uint8 y) { return x = (T)(x ^ ((T)1U << y)); } /** Lookup table to check which bit is set in a 6 bit variable */ extern const uint8 _ffb_64[64]; /** * Returns the first non-zero bit in a 6-bit value (from right). * * Returns the position of the first bit that is not zero, counted from the * LSB. Ie, 110100 returns 2, 000001 returns 0, etc. When x == 0 returns * 0. * * @param x The 6-bit value to check the first zero-bit * @return The first position of a bit started from the LSB or 0 if x is 0. */ #define FIND_FIRST_BIT(x) _ffb_64[(x)] /** * Finds the position of the first non-zero bit in an integer. * * This function returns the position of the first bit set in the * integer. It does only check the bits of the bitmask * 0x3F3F (0011111100111111) and checks only the * bits of the bitmask 0x3F00 if and only if the * lower part 0x00FF is 0. This results the bits at 0x00C0 must * be also zero to check the bits at 0x3F00. * * @param value The value to check the first bits * @return The position of the first bit which is set * @see FIND_FIRST_BIT */ static inline uint8 FindFirstBit2x64(const int value) { if ((value & 0xFF) == 0) { return FIND_FIRST_BIT((value >> 8) & 0x3F) + 8; } else { return FIND_FIRST_BIT(value & 0x3F); } } uint8 FindFirstBit(uint32 x); uint8 FindLastBit(uint64 x); /** * Clear the first bit in an integer. * * This function returns a value where the first bit (from LSB) * is cleared. * So, 110100 returns 110000, 000001 returns 000000, etc. * * @param value The value to clear the first bit * @return The new value with the first bit cleared */ template static inline T KillFirstBit(T value) { return value &= (T)(value - 1); } /** * Counts the number of set bits in a variable. * * @param value the value to count the number of bits in. * @return the number of bits. */ template static inline uint CountBits(T value) { uint num; /* This loop is only called once for every bit set by clearing the lowest * bit in each loop. The number of bits is therefore equal to the number of * times the loop was called. It was found at the following website: * http://graphics.stanford.edu/~seander/bithacks.html */ for (num = 0; value != 0; num++) { value &= (T)(value - 1); } return num; } /** * Test whether \a value has exactly 1 bit set * * @param value the value to test. * @return does \a value have exactly 1 bit set? */ template static inline bool HasExactlyOneBit(T value) { return value != 0 && (value & (value - 1)) == 0; } /** * Test whether \a value has at most 1 bit set * * @param value the value to test. * @return does \a value have at most 1 bit set? */ template static inline bool HasAtMostOneBit(T value) { return (value & (value - 1)) == 0; } /** * ROtate \a x Left by \a n * * @note Assumes a byte has 8 bits * @param x The value which we want to rotate * @param n The number how many we want to rotate * @pre n < sizeof(T) * 8 * @return A bit rotated number */ template static inline T ROL(const T x, const uint8 n) { return (T)(x << n | x >> (sizeof(x) * 8 - n)); } /** * ROtate \a x Right by \a n * * @note Assumes a byte has 8 bits * @param x The value which we want to rotate * @param n The number how many we want to rotate * @pre n < sizeof(T) * 8 * @return A bit rotated number */ template static inline T ROR(const T x, const uint8 n) { return (T)(x >> n | x << (sizeof(x) * 8 - n)); } /** * Do an operation for each set bit in a value. * * This macros is used to do an operation for each set * bit in a variable. The second parameter is a * variable that is used as the bit position counter. * The fourth parameter is an expression of the bits * we need to iterate over. This expression will be * evaluated once. * * @param Tbitpos_type Type of the position counter variable. * @param bitpos_var The position counter variable. * @param Tbitset_type Type of the bitset value. * @param bitset_value The bitset value which we check for bits. * * @see FOR_EACH_SET_BIT */ #define FOR_EACH_SET_BIT_EX(Tbitpos_type, bitpos_var, Tbitset_type, bitset_value) \ for ( \ Tbitset_type ___FESBE_bits = (bitpos_var = (Tbitpos_type)0, bitset_value); \ ___FESBE_bits != (Tbitset_type)0; \ ___FESBE_bits = (Tbitset_type)(___FESBE_bits >> 1), bitpos_var++ \ ) \ if ((___FESBE_bits & 1) != 0) /** * Do an operation for each set set bit in a value. * * This macros is used to do an operation for each set * bit in a variable. The first parameter is a variable * that is used as the bit position counter. * The second parameter is an expression of the bits * we need to iterate over. This expression will be * evaluated once. * * @param bitpos_var The position counter variable. * @param bitset_value The value which we check for set bits. */ #define FOR_EACH_SET_BIT(bitpos_var, bitset_value) FOR_EACH_SET_BIT_EX(uint, bitpos_var, uint, bitset_value) #if defined(__APPLE__) /* Make endian swapping use Apple's macros to increase speed * (since it will use hardware swapping if available). * Even though they should return uint16 and uint32, we get * warnings if we don't cast those (why?) */ #define BSWAP32(x) ((uint32)CFSwapInt32(x)) #define BSWAP16(x) ((uint16)CFSwapInt16(x)) #elif defined(_MSC_VER) /* MSVC has intrinsics for swapping, resulting in faster code */ #define BSWAP32(x) (_byteswap_ulong(x)) #define BSWAP16(x) (_byteswap_ushort(x)) #else /** * Perform a 32 bits endianness bitswap on x. * @param x the variable to bitswap * @return the bitswapped value. */ static inline uint32 BSWAP32(uint32 x) { #if !defined(__ICC) && defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && __GNUC_MINOR__ >= 3)) /* GCC >= 4.3 provides a builtin, resulting in faster code */ return (uint32)__builtin_bswap32((int32)x); #else return ((x >> 24) & 0xFF) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | ((x << 24) & 0xFF000000); #endif /* defined(__GNUC__) */ } /** * Perform a 16 bits endianness bitswap on x. * @param x the variable to bitswap * @return the bitswapped value. */ static inline uint16 BSWAP16(uint16 x) { return (x >> 8) | (x << 8); } #endif /* __APPLE__ */ #endif /* BITMATH_FUNC_HPP */ openttd-1.5.3/src/core/endian_type.hpp0000644000000000000000000000310612627373435016436 0ustar rootroot/* $Id: endian_type.hpp 22411 2011-05-02 17:42:12Z rubidium $ */ /* * 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 endian_type.hpp Definition of various endian-dependant macros. */ #ifndef ENDIAN_TYPE_HPP #define ENDIAN_TYPE_HPP #if defined(ARM) || defined(__arm__) || defined(__alpha__) /** The architecture requires aligned access. */ #define OTTD_ALIGNMENT 1 #else /** The architecture does not require aligned access. */ #define OTTD_ALIGNMENT 0 #endif /** Little endian builds use this for TTD_ENDIAN. */ #define TTD_LITTLE_ENDIAN 0 /** Big endian builds use this for TTD_ENDIAN. */ #define TTD_BIG_ENDIAN 1 /* Windows has always LITTLE_ENDIAN */ #if defined(WIN32) || defined(__OS2__) || defined(WIN64) #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) #include "endian_host.h" #else #include "endian_target.h" #endif #endif /* WIN32 || __OS2__ || WIN64 */ #endif /* ENDIAN_TYPE_HPP */ openttd-1.5.3/src/core/backup_type.hpp0000644000000000000000000001011412627373435016442 0ustar rootroot/* $Id: backup_type.hpp 19931 2010-06-05 12:16:12Z frosch $ */ /* * 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 backup_type.hpp Class for backupping variables and making sure they are restored later. */ #ifndef BACKUP_TYPE_HPP #define BACKUP_TYPE_HPP #include "../debug.h" /** * Class to backup a specific variable and restore it later. * The variable is not restored automatically, but assertions make sure it is restored. * You have to call either Trash() or Restore() exactly once. */ template struct Backup { /** * Backup variable. * @param original Variable to backup. * @param file Filename for debug output. Use FILE_LINE macro. * @param line Linenumber for debug output. Use FILE_LINE macro. */ Backup(T &original, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line) {} /** * Backup variable and switch to new value. * @param original Variable to backup. * @param new_value New value for variable. * @param file Filename for debug output. Use FILE_LINE macro. * @param line Linenumber for debug output. Use FILE_LINE macro. */ template Backup(T &original, const U &new_value, const char * const file, const int line) : original(original), valid(true), original_value(original), file(file), line(line) { /* Note: We use a separate typename U, so type conversions are handled by assignment operator. */ original = new_value; } /** * Check whether the variable was restored on object destruction. */ ~Backup() { /* Check whether restoration was done */ if (this->valid) { /* We cannot assert here, as missing restoration is 'normal' when exceptions are thrown. * Exceptions are especially used to abort world generation. */ DEBUG(misc, 0, "%s:%d: Backupped value was not restored!", this->file, this->line); this->Restore(); } } /** * Checks whether the variable was already restored. * @return true if variable has already been restored. */ bool IsValid() const { return this->valid; } /** * Returns the backupped value. * @return value from the backup. */ const T &GetOriginalValue() const { assert(this->valid); return original_value; } /** * Change the value of the variable. * While this does not touch the backup at all, it ensures that the variable is only modified while backupped. * @param new_value New value for variable. */ template void Change(const U &new_value) { /* Note: We use a separate typename U, so type conversions are handled by assignment operator. */ assert(this->valid); original = new_value; } /** * Revert the variable to its original value, but do not mark it as restored. */ void Revert() { assert(this->valid); this->original = this->original_value; } /** * Trash the backup. The variable shall not be restored anymore. */ void Trash() { assert(this->valid); this->valid = false; } /** * Restore the variable. */ void Restore() { this->Revert(); this->Trash(); } /** * Update the backup. * That is trash the old value and make the current value of the variable the value to be restored later. */ void Update() { assert(this->valid); this->original_value = this->original; } /** * Check whether the variable is currently equals the backup. * @return true if equal */ bool Verify() const { assert(this->valid); return this->original_value == this->original; } private: T &original; bool valid; T original_value; const char * const file; const int line; }; #endif /* BACKUP_TYPE_HPP */ openttd-1.5.3/src/core/smallstack_type.hpp0000644000000000000000000002105112627373435017335 0ustar rootroot/* $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 smallstack_type.hpp Minimal stack that uses a pool to avoid pointers and doesn't allocate any heap memory if there is only one valid item. */ #ifndef SMALLSTACK_TYPE_HPP #define SMALLSTACK_TYPE_HPP #include "smallvec_type.hpp" #include "../thread/thread.h" /** * A simplified pool which stores values instead of pointers and doesn't * redefine operator new/delete. It also never zeroes memory and always reuses * it. */ template class SimplePool { public: inline SimplePool() : first_unused(0), first_free(0), mutex(ThreadMutex::New()) {} inline ~SimplePool() { delete this->mutex; } /** * Get the mutex. We don't lock the mutex in the pool methods as the * SmallStack isn't necessarily in a consistent state after each method. * @return Mutex. */ inline ThreadMutex *GetMutex() { return this->mutex; } /** * Get the item at position index. * @return Item at index. */ inline Titem &Get(Tindex index) { return this->data[index]; } /** * Create a new item and return its index. * @return Index of new item. */ inline Tindex Create() { Tindex index = this->FindFirstFree(); if (index < Tmax_size) { this->data[index].valid = true; this->first_free = index + 1; this->first_unused = max(this->first_unused, this->first_free); } return index; } /** * Destroy (or rather invalidate) the item at the given index. * @param index Index of item to be destroyed. */ inline void Destroy(Tindex index) { this->data[index].valid = false; this->first_free = min(this->first_free, index); } private: inline Tindex FindFirstFree() { Tindex index = this->first_free; for (; index < this->first_unused; index++) { if (!this->data[index].valid) return index; } if (index >= this->data.Length() && index < Tmax_size) { this->data.Resize(index + 1); } return index; } struct SimplePoolPoolItem : public Titem { bool valid; }; Tindex first_unused; Tindex first_free; ThreadMutex *mutex; SmallVector data; }; /** * Base class for SmallStack. We cannot add this into SmallStack itself as * certain compilers don't like it. */ template struct SmallStackItem { Tindex next; ///< Pool index of next item. Titem value; ///< Value of current item. /** * Create a new item. * @param value Value of the item. * @param next Next item in the stack. */ inline SmallStackItem(const Titem &value, Tindex next) : next(next), value(value) {} }; /** * Minimal stack that uses a pool to avoid pointers. It has some peculiar * properties that make it useful for passing around lists of IDs but not much * else: * 1. It always includes an invalid item as bottom. * 2. It doesn't have a deep copy operation but uses smart pointers instead. * Every copy is thus implicitly shared. * 3. Its items are immutable. * 4. Due to 2. and 3. memory management can be done by "branch counting". * Whenever you copy a smallstack, the first item on the heap increases its * branch_count, signifying that there are multiple items "in front" of it. * When deleting a stack items are deleted up to the point where * branch_count > 0. * 5. You can choose your own index type, so that you can align it with your * value type. E.G. value types of 16 bits length like to be combined with * index types of the same length. * 6. All accesses to the underlying pool are guarded by a mutex and atomic in * the sense that the mutex stays locked until the pool has reacquired a * consistent state. This means that even though a common data structure is * used the SmallStack is still reentrant. * @tparam Titem Value type to be used. * @tparam Tindex Index type to use for the pool. * @tparam Tinvalid Invalid item to keep at the bottom of each stack. * @tparam Tgrowth_step Growth step for pool. * @tparam Tmax_size Maximum size for pool. */ template class SmallStack : public SmallStackItem { public: typedef SmallStackItem Item; /** * SmallStack item that can be kept in a pool. */ struct PooledSmallStack : public Item { Tindex branch_count; ///< Number of branches in the tree structure this item is parent of }; typedef SimplePool SmallStackPool; /** * Constructor for a stack with one or two items in it. * @param value Initial item. If not missing or Tinvalid there will be Tinvalid below it. */ inline SmallStack(const Titem &value = Tinvalid) : Item(value, Tmax_size) {} /** * Remove the head of stack and all other items members that are unique to it. */ inline ~SmallStack() { /* Pop() locks the mutex and after each pop the pool is consistent.*/ while (this->next != Tmax_size) this->Pop(); } /** * Shallow copy the stack, marking the first item as branched. * @param other Stack to copy from */ inline SmallStack(const SmallStack &other) : Item(other) { this->Branch(); } /** * Shallow copy the stack, marking the first item as branched. * @param other Stack to copy from * @return This smallstack. */ inline SmallStack &operator=(const SmallStack &other) { if (this == &other) return *this; while (this->next != Tmax_size) this->Pop(); this->next = other.next; this->value = other.value; /* Deleting and branching are independent operations, so it's fine to * acquire separate locks for them. */ this->Branch(); return *this; } /** * Pushes a new item onto the stack if there is still space in the * underlying pool. Otherwise the topmost item's value gets overwritten. * @param item Item to be pushed. */ inline void Push(const Titem &item) { if (this->value != Tinvalid) { ThreadMutexLocker lock(_pool.GetMutex()); Tindex new_item = _pool.Create(); if (new_item != Tmax_size) { PooledSmallStack &pushed = _pool.Get(new_item); pushed.value = this->value; pushed.next = this->next; pushed.branch_count = 0; this->next = new_item; } } this->value = item; } /** * Pop an item from the stack. * @return Current top of stack. */ inline Titem Pop() { Titem ret = this->value; if (this->next == Tmax_size) { this->value = Tinvalid; } else { ThreadMutexLocker lock(_pool.GetMutex()); PooledSmallStack &popped = _pool.Get(this->next); this->value = popped.value; if (popped.branch_count == 0) { _pool.Destroy(this->next); } else { --popped.branch_count; /* We can't use Branch() here as we already have the mutex.*/ if (popped.next != Tmax_size) { ++(_pool.Get(popped.next).branch_count); } } /* Accessing popped here is no problem as the pool will only set * the validity flag, not actually delete the item, on Destroy(). * It's impossible for another thread to acquire the same item in * the mean time because of the mutex. */ this->next = popped.next; } return ret; } /** * Check if the stack is empty. * @return If the stack is empty. */ inline bool IsEmpty() const { return this->value == Tinvalid && this->next == Tmax_size; } /** * Check if the given item is contained in the stack. * @param item Item to look for. * @return If the item is in the stack. */ inline bool Contains(const Titem &item) const { if (item == Tinvalid || item == this->value) return true; if (this->next != Tmax_size) { ThreadMutexLocker lock(_pool.GetMutex()); const SmallStack *in_list = this; do { in_list = static_cast( static_cast(&_pool.Get(in_list->next))); if (in_list->value == item) return true; } while (in_list->next != Tmax_size); } return false; } protected: static SmallStackPool _pool; /** * Create a branch in the pool if necessary. */ inline void Branch() { if (this->next != Tmax_size) { ThreadMutexLocker lock(_pool.GetMutex()); ++(_pool.Get(this->next).branch_count); } } }; #endif openttd-1.5.3/src/core/overflowsafe_type.hpp0000644000000000000000000002504112627373435017704 0ustar rootroot/* $Id: overflowsafe_type.hpp 26685 2014-07-12 17:04:14Z alberth $ */ /* * 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 overflowsafe_type.hpp An overflow safe integer-like type. */ #ifndef OVERFLOWSAFE_TYPE_HPP #define OVERFLOWSAFE_TYPE_HPP #include "math_func.hpp" /** * Overflow safe template for integers, i.e. integers that will never overflow * you multiply the maximum value with 2, or add 2, or subtract something from * the minimum value, etc. * @param T the type these integers are stored with. * @param T_MAX the maximum value for the integers. * @param T_MIN the minimum value for the integers. */ template class OverflowSafeInt { private: /** The non-overflow safe backend to store the value in. */ T m_value; public: OverflowSafeInt() : m_value(0) { } OverflowSafeInt(const OverflowSafeInt& other) { this->m_value = other.m_value; } OverflowSafeInt(const int64 int_) { this->m_value = int_; } inline OverflowSafeInt& operator = (const OverflowSafeInt& other) { this->m_value = other.m_value; return *this; } inline OverflowSafeInt operator - () const { return OverflowSafeInt(-this->m_value); } /** * Safe implementation of addition. * @param other the amount to add * @note when the addition would yield more than T_MAX (or less than T_MIN), * it will be T_MAX (respectively T_MIN). */ inline OverflowSafeInt& operator += (const OverflowSafeInt& other) { if ((T_MAX - abs(other.m_value)) < abs(this->m_value) && (this->m_value < 0) == (other.m_value < 0)) { this->m_value = (this->m_value < 0) ? T_MIN : T_MAX ; } else { this->m_value += other.m_value; } return *this; } /* Operators for addition and subtraction */ inline OverflowSafeInt operator + (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result += other; return result; } inline OverflowSafeInt operator + (const int other) const { OverflowSafeInt result = *this; result += (int64)other; return result; } inline OverflowSafeInt operator + (const uint other) const { OverflowSafeInt result = *this; result += (int64)other; return result; } inline OverflowSafeInt& operator -= (const OverflowSafeInt& other) { return *this += (-other); } inline OverflowSafeInt operator - (const OverflowSafeInt& other) const { OverflowSafeInt result = *this; result -= other; return result; } inline OverflowSafeInt operator - (const int other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; } inline OverflowSafeInt operator - (const uint other) const { OverflowSafeInt result = *this; result -= (int64)other; return result; } inline OverflowSafeInt& operator ++ () { return *this += 1; } inline OverflowSafeInt& operator -- () { return *this += -1; } inline OverflowSafeInt operator ++ (int) { OverflowSafeInt org = *this; *this += 1; return org; } inline OverflowSafeInt operator -- (int) { OverflowSafeInt org = *this; *this += -1; return org; } /** * Safe implementation of multiplication. * @param factor the factor to multiply this with. * @note when the multiplication would yield more than T_MAX (or less than T_MIN), * it will be T_MAX (respectively T_MIN). */ inline OverflowSafeInt& operator *= (const int factor) { if (factor != 0 && (T_MAX / abs(factor)) < abs(this->m_value)) { this->m_value = ((this->m_value < 0) == (factor < 0)) ? T_MAX : T_MIN ; } else { this->m_value *= factor ; } return *this; } /* Operators for multiplication */ inline OverflowSafeInt operator * (const int64 factor) const { OverflowSafeInt result = *this; result *= factor; return result; } inline OverflowSafeInt operator * (const int factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; } inline OverflowSafeInt operator * (const uint factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; } inline OverflowSafeInt operator * (const uint16 factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; } inline OverflowSafeInt operator * (const byte factor) const { OverflowSafeInt result = *this; result *= (int64)factor; return result; } /* Operators for division */ inline OverflowSafeInt& operator /= (const int64 divisor) { this->m_value /= divisor; return *this; } inline OverflowSafeInt operator / (const OverflowSafeInt& divisor) const { OverflowSafeInt result = *this; result /= divisor.m_value; return result; } inline OverflowSafeInt operator / (const int divisor) const { OverflowSafeInt result = *this; result /= divisor; return result; } inline OverflowSafeInt operator / (const uint divisor) const { OverflowSafeInt result = *this; result /= (int)divisor; return result; } /* Operators for modulo */ inline OverflowSafeInt& operator %= (const int divisor) { this->m_value %= divisor; return *this; } inline OverflowSafeInt operator % (const int divisor) const { OverflowSafeInt result = *this; result %= divisor; return result; } /* Operators for shifting */ inline OverflowSafeInt& operator <<= (const int shift) { this->m_value <<= shift; return *this; } inline OverflowSafeInt operator << (const int shift) const { OverflowSafeInt result = *this; result <<= shift; return result; } inline OverflowSafeInt& operator >>= (const int shift) { this->m_value >>= shift; return *this; } inline OverflowSafeInt operator >> (const int shift) const { OverflowSafeInt result = *this; result >>= shift; return result; } /* Operators for (in)equality when comparing overflow safe ints */ inline bool operator == (const OverflowSafeInt& other) const { return this->m_value == other.m_value; } inline bool operator != (const OverflowSafeInt& other) const { return !(*this == other); } inline bool operator > (const OverflowSafeInt& other) const { return this->m_value > other.m_value; } inline bool operator >= (const OverflowSafeInt& other) const { return this->m_value >= other.m_value; } inline bool operator < (const OverflowSafeInt& other) const { return !(*this >= other); } inline bool operator <= (const OverflowSafeInt& other) const { return !(*this > other); } /* Operators for (in)equality when comparing non-overflow safe ints */ inline bool operator == (const int other) const { return this->m_value == other; } inline bool operator != (const int other) const { return !(*this == other); } inline bool operator > (const int other) const { return this->m_value > other; } inline bool operator >= (const int other) const { return this->m_value >= other; } inline bool operator < (const int other) const { return !(*this >= other); } inline bool operator <= (const int other) const { return !(*this > other); } inline operator int64 () const { return this->m_value; } }; /* Sometimes we got int64 operator OverflowSafeInt instead of vice versa. Handle that properly */ template inline OverflowSafeInt operator + (int64 a, OverflowSafeInt b) { return b + a; } template inline OverflowSafeInt operator - (int64 a, OverflowSafeInt b) { return -b + a; } template inline OverflowSafeInt operator * (int64 a, OverflowSafeInt b) { return b * a; } template inline OverflowSafeInt operator / (int64 a, OverflowSafeInt b) { return (OverflowSafeInt)a / (int)b; } /* Sometimes we got int operator OverflowSafeInt instead of vice versa. Handle that properly */ template inline OverflowSafeInt operator + (int a, OverflowSafeInt b) { return b + a; } template inline OverflowSafeInt operator - (int a, OverflowSafeInt b) { return -b + a; } template inline OverflowSafeInt operator * (int a, OverflowSafeInt b) { return b * a; } template inline OverflowSafeInt operator / (int a, OverflowSafeInt b) { return (OverflowSafeInt)a / (int)b; } /* Sometimes we got uint operator OverflowSafeInt instead of vice versa. Handle that properly */ template inline OverflowSafeInt operator + (uint a, OverflowSafeInt b) { return b + a; } template inline OverflowSafeInt operator - (uint a, OverflowSafeInt b) { return -b + a; } template inline OverflowSafeInt operator * (uint a, OverflowSafeInt b) { return b * a; } template inline OverflowSafeInt operator / (uint a, OverflowSafeInt b) { return (OverflowSafeInt)a / (int)b; } /* Sometimes we got byte operator OverflowSafeInt instead of vice versa. Handle that properly */ template inline OverflowSafeInt operator + (byte a, OverflowSafeInt b) { return b + (uint)a; } template inline OverflowSafeInt operator - (byte a, OverflowSafeInt b) { return -b + (uint)a; } template inline OverflowSafeInt operator * (byte a, OverflowSafeInt b) { return b * (uint)a; } template inline OverflowSafeInt operator / (byte a, OverflowSafeInt b) { return (OverflowSafeInt)a / (int)b; } typedef OverflowSafeInt OverflowSafeInt64; typedef OverflowSafeInt OverflowSafeInt32; #endif /* OVERFLOWSAFE_TYPE_HPP */ openttd-1.5.3/src/core/smallmatrix_type.hpp0000644000000000000000000002072512627373435017543 0ustar rootroot/* $Id: smallmatrix_type.hpp 25256 2013-05-19 14:06:26Z rubidium $ */ /* * 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 smallmatrix_type.hpp Simple matrix class that allows allocating an item without the need to copy this->data needlessly. */ #ifndef SMALLMATRIX_TYPE_HPP #define SMALLMATRIX_TYPE_HPP #include "alloc_func.hpp" #include "mem_func.hpp" /** * Simple matrix template class. * * Allocating a matrix in one piece reduces overhead in allocations compared * with allocating a vector of vectors and saves some pointer dereferencing. * However, you can only get rectangular matrixes like this and if you're * changing their height very often performance will probably be worse than * with a vector of vectors, due to more frequent copying of memory blocks. * * No iterators are provided as iterating the columns would require persistent * column objects. Those do not exist. Providing iterators with transient * column objects would tie each iterator to a column object, thus replacing * previously retrieved columns when iterating and defeating the point of * iteration. * * It's expected that the items don't need to be constructed or deleted by the * container. Only memory allocation and deallocation is performed. This is the * same for all openttd "SmallContainer" classes. * * @tparam T The type of the items stored */ template class SmallMatrix { protected: T *data; ///< The pointer to the first item uint width; ///< Number of items over first axis uint height; ///< Number of items over second axis uint capacity; ///< The available space for storing items public: SmallMatrix() : data(NULL), width(0), height(0), capacity(0) {} /** * Copy constructor. * @param other The other matrix to copy. */ SmallMatrix(const SmallMatrix &other) : data(NULL), width(0), height(0), capacity(0) { this->Assign(other); } ~SmallMatrix() { free(this->data); } /** * Assignment. * @param other The other matrix to assign. */ SmallMatrix &operator=(const SmallMatrix &other) { this->Assign(other); return *this; } /** * Assign items from other vector. */ inline void Assign(const SmallMatrix &other) { if (&other == this) return; this->height = other.Height(); this->width = other.Width(); uint num_items = this->width * this->height; if (num_items > this->capacity) { this->capacity = num_items; free(this->data); this->data = MallocT(num_items); MemCpyT(this->data, other[0], num_items); } else if (num_items > 0) { MemCpyT(this->data, other[0], num_items); } } /** * Remove all rows from the matrix. */ inline void Clear() { /* In fact we just reset the width avoiding the need to * probably reallocate the same amount of memory the matrix was * previously using. */ this->width = 0; } /** * Remove all items from the list and free allocated memory. */ inline void Reset() { this->height = 0; this->width = 0; this->capacity = 0; free(this->data); this->data = NULL; } /** * Compact the matrix down to the smallest possible size. */ inline void Compact() { uint capacity = this->height * this->width; if (capacity >= this->capacity) return; this->capacity = capacity; this->data = ReallocT(this->data, this->capacity); } /** * Erase a column, replacing it with the last one. * @param x Position of the column. */ void EraseColumn(uint x) { if (x < --this->width) { MemCpyT(this->data + x * this->height, this->data + this->width * this->height, this->height); } } /** * Remove columns from the matrix while preserving the order of other columns. * @param x First column to remove. * @param count Number of consecutive columns to remove. */ void EraseColumnPreservingOrder(uint x, uint count = 1) { if (count == 0) return; assert(x < this->width); assert(x + count <= this->width); this->width -= count; uint to_move = (this->width - x) * this->height; if (to_move > 0) { MemMoveT(this->data + x * this->height, this->data + (x + count) * this->height, to_move); } } /** * Erase a row, replacing it with the last one. * @param x Position of the row. */ void EraseRow(uint y) { if (y < this->height - 1) { for (uint x = 0; x < this->width; ++x) { this->data[x * this->height + y] = this->data[(x + 1) * this->height - 1]; } } this->Resize(this->width, this->height - 1); } /** * Remove columns from the matrix while preserving the order of other columns. * @param x First column to remove. * @param count Number of consecutive columns to remove. */ void EraseRowPreservingOrder(uint y, uint count = 1) { if (this->height > count + y) { for (uint x = 0; x < this->width; ++x) { MemMoveT(this->data + x * this->height + y, this->data + x * this->height + y + count, this->height - count - y); } } this->Resize(this->width, this->height - count); } /** * Append rows. * @param to_add Number of rows to append. */ inline void AppendRow(uint to_add = 1) { this->Resize(this->width, to_add + this->height); } /** * Append rows. * @param to_add Number of rows to append. */ inline void AppendColumn(uint to_add = 1) { this->Resize(to_add + this->width, this->height); } /** * Set the size to a specific width and height, preserving item positions * as far as possible in the process. * @param width Target width. * @param height Target height. */ inline void Resize(uint new_width, uint new_height) { uint new_capacity = new_width * new_height; T *new_data = NULL; void (*copy)(T *dest, const T *src, size_t count) = NULL; if (new_capacity > this->capacity) { /* If the data doesn't fit into current capacity, resize and copy ... */ new_data = MallocT(new_capacity); copy = &MemCpyT; } else { /* ... otherwise just move the columns around, if necessary. */ new_data = this->data; copy = &MemMoveT; } if (this->height != new_height || new_data != this->data) { if (this->height > 0) { if (new_height > this->height) { /* If matrix is growing, copy from the back to avoid * overwriting uncopied data. */ for (uint x = this->width; x > 0; --x) { if (x * new_height > new_capacity) continue; (*copy)(new_data + (x - 1) * new_height, this->data + (x - 1) * this->height, min(this->height, new_height)); } } else { /* If matrix is shrinking copy from the front. */ for (uint x = 0; x < this->width; ++x) { if ((x + 1) * new_height > new_capacity) break; (*copy)(new_data + x * new_height, this->data + x * this->height, min(this->height, new_height)); } } } this->height = new_height; if (new_data != this->data) { free(this->data); this->data = new_data; this->capacity = new_capacity; } } this->width = new_width; } inline uint Height() const { return this->height; } inline uint Width() const { return this->width; } /** * Get item x/y (const). * * @param x X-position of the item. * @param y Y-position of the item. * @return Item at specified position. */ inline const T &Get(uint x, uint y) const { assert(x < this->width && y < this->height); return this->data[x * this->height + y]; } /** * Get item x/y. * * @param x X-position of the item. * @param y Y-position of the item. * @return Item at specified position. */ inline T &Get(uint x, uint y) { assert(x < this->width && y < this->height); return this->data[x * this->height + y]; } /** * Get column "number" (const) * * @param X Position of the column. * @return Column at "number". */ inline const T *operator[](uint x) const { assert(x < this->width); return this->data + x * this->height; } /** * Get column "number" (const) * * @param X Position of the column. * @return Column at "number". */ inline T *operator[](uint x) { assert(x < this->width); return this->data + x * this->height; } }; #endif /* SMALLMATRIX_TYPE_HPP */ openttd-1.5.3/src/engine_base.h0000644000000000000000000001570212627373435015113 0ustar rootroot/* $Id: engine_base.h 26802 2014-09-07 16:12:58Z alberth $ */ /* * 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 engine_base.h Base class for engines. */ #ifndef ENGINE_BASE_H #define ENGINE_BASE_H #include "engine_type.h" #include "vehicle_type.h" #include "core/pool_type.hpp" #include "newgrf_commons.h" typedef Pool EnginePool; extern EnginePool _engine_pool; struct Engine : EnginePool::PoolItem<&_engine_pool> { char *name; ///< Custom name of engine. Date intro_date; ///< Date of introduction of the engine. Date age; uint16 reliability; ///< Current reliability of the engine. uint16 reliability_spd_dec; ///< Speed of reliability decay between services (per day). uint16 reliability_start; ///< Initial reliability of the engine. uint16 reliability_max; ///< Maximal reliability of the engine. uint16 reliability_final; ///< Final reliability of the engine. uint16 duration_phase_1; ///< First reliability phase in months, increasing reliability from #reliability_start to #reliability_max. uint16 duration_phase_2; ///< Second reliability phase in months, keeping #reliability_max. uint16 duration_phase_3; ///< Third reliability phase on months, decaying to #reliability_final. byte flags; ///< Flags of the engine. @see EngineFlags CompanyMask preview_asked; ///< Bit for each company which has already been offered a preview. CompanyByte preview_company;///< Company which is currently being offered a preview \c INVALID_COMPANY means no company. byte preview_wait; ///< Daily countdown timer for timeout of offering the engine to the #preview_company company. CompanyMask company_avail; ///< Bit for each company whether the engine is available for that company. CompanyMask company_hidden; ///< Bit for each company whether the engine is normally hidden in the build gui for that company. uint8 original_image_index; ///< Original vehicle image index, thus the image index of the overridden vehicle VehicleType type; ///< %Vehicle type, ie #VEH_ROAD, #VEH_TRAIN, etc. EngineInfo info; union { RailVehicleInfo rail; RoadVehicleInfo road; ShipVehicleInfo ship; AircraftVehicleInfo air; } u; /* NewGRF related data */ /** * Properties related the the grf file. * NUM_CARGO real cargo plus two pseudo cargo sprite groups. * Used for obtaining the sprite offset of custom sprites, and for * evaluating callbacks. */ GRFFilePropsBase grf_prop; uint16 overrides_count; struct WagonOverride *overrides; uint16 list_position; Engine(); Engine(VehicleType type, EngineID base); ~Engine(); bool IsEnabled() const; /** * Determines the default cargo type of an engine. * * Usually a valid cargo is returned, even though the vehicle has zero capacity, and can therefore not carry anything. But the cargotype is still used * for livery selection etc.. * * Vehicles with CT_INVALID as default cargo are usually not available, but it can appear as default cargo of articulated parts. * * @return The default cargo type. * @see CanCarryCargo */ CargoID GetDefaultCargoType() const { return this->info.cargo_type; } uint DetermineCapacity(const Vehicle *v, uint16 *mail_capacity = NULL) const; bool CanCarryCargo() const; /** * Determines the default cargo capacity of an engine for display purposes. * * For planes carrying both passenger and mail this is the passenger capacity. * For multiheaded engines this is the capacity of both heads. * For articulated engines use GetCapacityOfArticulatedParts * * @param mail_capacity returns secondary cargo (mail) capacity of aircraft * @return The default capacity * @see GetDefaultCargoType */ uint GetDisplayDefaultCapacity(uint16 *mail_capacity = NULL) const { return this->DetermineCapacity(NULL, mail_capacity); } Money GetRunningCost() const; Money GetCost() const; uint GetDisplayMaxSpeed() const; uint GetPower() const; uint GetDisplayWeight() const; uint GetDisplayMaxTractiveEffort() const; Date GetLifeLengthInDays() const; uint16 GetRange() const; /** * Check whether the engine is hidden in the GUI for the given company. * @param c Company to check. * @return \c true iff the engine is hidden in the GUI for the given company. */ inline bool IsHidden(CompanyByte c) const { return c < MAX_COMPANIES && HasBit(this->company_hidden, c); } /** * Check if the engine is a ground vehicle. * @return True iff the engine is a train or a road vehicle. */ inline bool IsGroundVehicle() const { return this->type == VEH_TRAIN || this->type == VEH_ROAD; } /** * Retrieve the NewGRF the engine is tied to. * This is the GRF providing the Action 3. * @return NewGRF associated to the engine. */ const GRFFile *GetGRF() const { return this->grf_prop.grffile; } uint32 GetGRFID() const; }; struct EngineIDMapping { uint32 grfid; ///< The GRF ID of the file the entity belongs to uint16 internal_id; ///< The internal ID within the GRF file VehicleTypeByte type; ///< The engine type uint8 substitute_id; ///< The (original) entity ID to use if this GRF is not available (currently not used) }; /** * Stores the mapping of EngineID to the internal id of newgrfs. * Note: This is not part of Engine, as the data in the EngineOverrideManager and the engine pool get resetted in different cases. */ struct EngineOverrideManager : SmallVector { static const uint NUM_DEFAULT_ENGINES; ///< Number of default entries void ResetToDefaultMapping(); EngineID GetID(VehicleType type, uint16 grf_local_id, uint32 grfid); static bool ResetToCurrentNewGRFConfig(); }; extern EngineOverrideManager _engine_mngr; #define FOR_ALL_ENGINES_FROM(var, start) FOR_ALL_ITEMS_FROM(Engine, engine_index, var, start) #define FOR_ALL_ENGINES(var) FOR_ALL_ENGINES_FROM(var, 0) #define FOR_ALL_ENGINES_OF_TYPE(e, engine_type) FOR_ALL_ENGINES(e) if (e->type == engine_type) static inline const EngineInfo *EngInfo(EngineID e) { return &Engine::Get(e)->info; } static inline const RailVehicleInfo *RailVehInfo(EngineID e) { return &Engine::Get(e)->u.rail; } static inline const RoadVehicleInfo *RoadVehInfo(EngineID e) { return &Engine::Get(e)->u.road; } static inline const ShipVehicleInfo *ShipVehInfo(EngineID e) { return &Engine::Get(e)->u.ship; } static inline const AircraftVehicleInfo *AircraftVehInfo(EngineID e) { return &Engine::Get(e)->u.air; } #endif /* ENGINE_BASE_H */ openttd-1.5.3/src/newgrf_spritegroup.cpp0000644000000000000000000003006612627373435017142 0ustar rootroot/* $Id: newgrf_spritegroup.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_spritegroup.cpp Handling of primarily NewGRF action 2. */ #include "stdafx.h" #include "debug.h" #include "newgrf_spritegroup.h" #include "core/pool_func.hpp" #include "safeguards.h" SpriteGroupPool _spritegroup_pool("SpriteGroup"); INSTANTIATE_POOL_METHODS(SpriteGroup) TemporaryStorageArray _temp_store; /** * ResolverObject (re)entry point. * This cannot be made a call to a virtual function because virtual functions * do not like NULL and checking for NULL *everywhere* is more cumbersome than * this little helper function. * @param group the group to resolve for * @param object information needed to resolve the group * @param top_level true if this is a top-level SpriteGroup, false if used nested in another SpriteGroup. * @return the resolved group */ /* static */ const SpriteGroup *SpriteGroup::Resolve(const SpriteGroup *group, ResolverObject &object, bool top_level) { if (group == NULL) return NULL; if (top_level) { _temp_store.ClearChanges(); } return group->Resolve(object); } RealSpriteGroup::~RealSpriteGroup() { free(this->loaded); free(this->loading); } DeterministicSpriteGroup::~DeterministicSpriteGroup() { free(this->adjusts); free(this->ranges); } RandomizedSpriteGroup::~RandomizedSpriteGroup() { free(this->groups); } static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *scope, byte variable, uint32 parameter, bool *available) { /* First handle variables common with Action7/9/D */ uint32 value; if (GetGlobalVariable(variable, &value, object.grffile)) return value; /* Non-common variable */ switch (variable) { case 0x0C: return object.callback; case 0x10: return object.callback_param1; case 0x18: return object.callback_param2; case 0x1C: return object.last_value; case 0x5F: return (scope->GetRandomBits() << 8) | scope->GetTriggers(); case 0x7D: return _temp_store.GetValue(parameter); case 0x7F: if (object.grffile == NULL) return 0; return object.grffile->GetParam(parameter); /* Not a common variable, so evaluate the feature specific variables */ default: return scope->GetVariable(variable, parameter, available); } } ScopeResolver::ScopeResolver(ResolverObject &ro) : ro(ro) { } ScopeResolver::~ScopeResolver() {} /** * Get a few random bits. Default implementation has no random bits. * @return Random bits. */ /* virtual */ uint32 ScopeResolver::GetRandomBits() const { return 0; } /** * Get the triggers. Base class returns \c 0 to prevent trouble. * @return The triggers. */ /* virtual */ uint32 ScopeResolver::GetTriggers() const { return 0; } /** * Set the triggers. Base class implementation does nothing. * @param triggers Triggers to set. */ /* virtual */ void ScopeResolver::SetTriggers(int triggers) const {} /** * Get a variable value. Default implementation has no available variables. * @param variable Variable to read * @param parameter Parameter for 60+x variables * @param[out] available Set to false, in case the variable does not exist. * @return Value */ /* virtual */ uint32 ScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { DEBUG(grf, 1, "Unhandled scope variable 0x%X", variable); *available = false; return UINT_MAX; } /** * Store a value into the persistent storage area (PSA). Default implementation does nothing (for newgrf classes without storage). * @param pos Position to store into. * @param value Value to store. */ /* virtual */ void ScopeResolver::StorePSA(uint reg, int32 value) {} /** * Resolver constructor. * @param grffile NewGRF file associated with the object (or \c NULL if none). * @param callback Callback code being resolved (default value is #CBID_NO_CALLBACK). * @param callback_param1 First parameter (var 10) of the callback (only used when \a callback is also set). * @param callback_param2 Second parameter (var 18) of the callback (only used when \a callback is also set). */ ResolverObject::ResolverObject(const GRFFile *grffile, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : default_scope(*this) { this->callback = callback; this->callback_param1 = callback_param1; this->callback_param2 = callback_param2; this->ResetState(); this->grffile = grffile; this->root_spritegroup = NULL; } ResolverObject::~ResolverObject() {} /** * Get the real sprites of the grf. * @param group Group to get. * @return The available sprite group. */ /* virtual */ const SpriteGroup *ResolverObject::ResolveReal(const RealSpriteGroup *group) const { return NULL; } /** * Get a resolver for the \a scope. * @param scope Scope to return. * @param relative Additional parameter for #VSG_SCOPE_RELATIVE. * @return The resolver for the requested scope. */ /* virtual */ ScopeResolver *ResolverObject::GetScope(VarSpriteGroupScope scope, byte relative) { return &this->default_scope; } /** * Rotate val rot times to the right * @param val the value to rotate * @param rot the amount of times to rotate * @return the rotated value */ static uint32 RotateRight(uint32 val, uint32 rot) { /* Do not rotate more than necessary */ rot %= 32; return (val >> rot) | (val << (32 - rot)); } /* Evaluate an adjustment for a variable of the given size. * U is the unsigned type and S is the signed type to use. */ template static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ScopeResolver *scope, U last_value, uint32 value) { value >>= adjust->shift_num; value &= adjust->and_mask; if (adjust->type != DSGA_TYPE_NONE) value += (S)adjust->add_val; switch (adjust->type) { case DSGA_TYPE_DIV: value /= (S)adjust->divmod_val; break; case DSGA_TYPE_MOD: value %= (U)adjust->divmod_val; break; case DSGA_TYPE_NONE: break; } switch (adjust->operation) { case DSGA_OP_ADD: return last_value + value; case DSGA_OP_SUB: return last_value - value; case DSGA_OP_SMIN: return min((S)last_value, (S)value); case DSGA_OP_SMAX: return max((S)last_value, (S)value); case DSGA_OP_UMIN: return min((U)last_value, (U)value); case DSGA_OP_UMAX: return max((U)last_value, (U)value); case DSGA_OP_SDIV: return value == 0 ? (S)last_value : (S)last_value / (S)value; case DSGA_OP_SMOD: return value == 0 ? (S)last_value : (S)last_value % (S)value; case DSGA_OP_UDIV: return value == 0 ? (U)last_value : (U)last_value / (U)value; case DSGA_OP_UMOD: return value == 0 ? (U)last_value : (U)last_value % (U)value; case DSGA_OP_MUL: return last_value * value; case DSGA_OP_AND: return last_value & value; case DSGA_OP_OR: return last_value | value; case DSGA_OP_XOR: return last_value ^ value; case DSGA_OP_STO: _temp_store.StoreValue((U)value, (S)last_value); return last_value; case DSGA_OP_RST: return value; case DSGA_OP_STOP: scope->StorePSA((U)value, (S)last_value); return last_value; case DSGA_OP_ROR: return RotateRight(last_value, value); case DSGA_OP_SCMP: return ((S)last_value == (S)value) ? 1 : ((S)last_value < (S)value ? 0 : 2); case DSGA_OP_UCMP: return ((U)last_value == (U)value) ? 1 : ((U)last_value < (U)value ? 0 : 2); case DSGA_OP_SHL: return (uint32)(U)last_value << ((U)value & 0x1F); // Same behaviour as in ParamSet, mask 'value' to 5 bits, which should behave the same on all architectures. case DSGA_OP_SHR: return (uint32)(U)last_value >> ((U)value & 0x1F); case DSGA_OP_SAR: return (int32)(S)last_value >> ((U)value & 0x1F); default: return value; } } const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) const { uint32 last_value = 0; uint32 value = 0; uint i; ScopeResolver *scope = object.GetScope(this->var_scope); for (i = 0; i < this->num_adjusts; i++) { DeterministicSpriteGroupAdjust *adjust = &this->adjusts[i]; /* Try to get the variable. We shall assume it is available, unless told otherwise. */ bool available = true; if (adjust->variable == 0x7E) { const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust->subroutine, object, false); if (subgroup == NULL) { value = CALLBACK_FAILED; } else { value = subgroup->GetCallbackResult(); } /* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */ } else if (adjust->variable == 0x7B) { value = GetVariable(object, scope, adjust->parameter, last_value, &available); } else { value = GetVariable(object, scope, adjust->variable, adjust->parameter, &available); } if (!available) { /* Unsupported variable: skip further processing and return either * the group from the first range or the default group. */ return SpriteGroup::Resolve(this->num_ranges > 0 ? this->ranges[0].group : this->default_group, object, false); } switch (this->size) { case DSG_SIZE_BYTE: value = EvalAdjustT (adjust, scope, last_value, value); break; case DSG_SIZE_WORD: value = EvalAdjustT(adjust, scope, last_value, value); break; case DSG_SIZE_DWORD: value = EvalAdjustT(adjust, scope, last_value, value); break; default: NOT_REACHED(); } last_value = value; } object.last_value = last_value; if (this->num_ranges == 0) { /* nvar == 0 is a special case -- we turn our value into a callback result */ if (value != CALLBACK_FAILED) value = GB(value, 0, 15); static CallbackResultSpriteGroup nvarzero(0, true); nvarzero.result = value; return &nvarzero; } for (i = 0; i < this->num_ranges; i++) { if (this->ranges[i].low <= value && value <= this->ranges[i].high) { return SpriteGroup::Resolve(this->ranges[i].group, object, false); } } return SpriteGroup::Resolve(this->default_group, object, false); } const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const { ScopeResolver *scope = object.GetScope(this->var_scope, this->count); if (object.trigger != 0) { /* Handle triggers */ /* Magic code that may or may not do the right things... */ byte waiting_triggers = scope->GetTriggers(); byte match = this->triggers & (waiting_triggers | object.trigger); bool res = (this->cmp_mode == RSG_CMP_ANY) ? (match != 0) : (match == this->triggers); if (res) { waiting_triggers &= ~match; object.reseed[this->var_scope] |= (this->num_groups - 1) << this->lowest_randbit; } else { waiting_triggers |= object.trigger; } scope->SetTriggers(waiting_triggers); } uint32 mask = (this->num_groups - 1) << this->lowest_randbit; byte index = (scope->GetRandomBits() & mask) >> this->lowest_randbit; return SpriteGroup::Resolve(this->groups[index], object, false); } const SpriteGroup *RealSpriteGroup::Resolve(ResolverObject &object) const { return object.ResolveReal(this); } /** * Process registers and the construction stage into the sprite layout. * The passed construction stage might get reset to zero, if it gets incorporated into the layout * during the preprocessing. * @param [in, out] stage Construction stage (0-3), or NULL if not applicable. * @return sprite layout to draw. */ const DrawTileSprites *TileLayoutSpriteGroup::ProcessRegisters(uint8 *stage) const { if (!this->dts.NeedsPreprocessing()) { if (stage != NULL && this->dts.consistent_max_offset > 0) *stage = GetConstructionStageOffset(*stage, this->dts.consistent_max_offset); return &this->dts; } static DrawTileSprites result; uint8 actual_stage = stage != NULL ? *stage : 0; this->dts.PrepareLayout(0, 0, 0, actual_stage, false); this->dts.ProcessRegisters(0, 0, false); result.seq = this->dts.GetLayout(&result.ground); /* Stage has been processed by PrepareLayout(), set it to zero. */ if (stage != NULL) *stage = 0; return &result; } openttd-1.5.3/src/news_gui.h0000644000000000000000000000146412627373446014476 0ustar rootroot/* $Id: news_gui.h 24842 2012-12-23 21:06:37Z frosch $ */ /* * 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 news_gui.h GUI functions related to the news. */ #ifndef NEWS_GUI_H #define NEWS_GUI_H void ShowLastNewsMessage(); void ShowMessageHistory(); #endif /* NEWS_GUI_H */ openttd-1.5.3/src/tilematrix_type.hpp0000644000000000000000000000770712627373435016445 0ustar rootroot/* $Id: tilematrix_type.hpp 23735 2012-01-03 20:26:05Z rubidium $ */ /* * 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 tilematrix_type.hpp Template for storing a value per area of the map. */ #ifndef TILEMATRIX_TYPE_HPP #define TILEMATRIX_TYPE_HPP #include "core/alloc_func.hpp" #include "tilearea_type.h" /** * A simple matrix that stores one value per N*N square of the map. * Storage is only allocated for the part of the map that has values * assigned. * * @note No constructor is called for newly allocated values, you * have to do this yourself if needed. * @tparam T The type of the stored items. * @tparam N Grid size. */ template class TileMatrix { /** Allocates space for a new tile in the matrix. * @param tile Tile to add. */ void AllocateStorage(TileIndex tile) { uint old_left = TileX(this->area.tile) / N; uint old_top = TileY(this->area.tile) / N; uint old_w = this->area.w / N; uint old_h = this->area.h / N; /* Add the square the tile is in to the tile area. We do this * by adding top-left and bottom-right of the square. */ uint grid_x = (TileX(tile) / N) * N; uint grid_y = (TileY(tile) / N) * N; this->area.Add(TileXY(grid_x, grid_y)); this->area.Add(TileXY(grid_x + N - 1, grid_y + N - 1)); /* Allocate new storage. */ T *new_data = CallocT(this->area.w / N * this->area.h / N); if (old_w > 0) { /* Copy old data if present. */ uint offs_x = old_left - TileX(this->area.tile) / N; uint offs_y = old_top - TileY(this->area.tile) / N; for (uint row = 0; row < old_h; row++) { MemCpyT(&new_data[(row + offs_y) * this->area.w / N + offs_x], &this->data[row * old_w], old_w); } } free(this->data); this->data = new_data; } public: static const uint GRID = N; TileArea area; ///< Area covered by the matrix. T *data; ///< Pointer to data array. TileMatrix() : area(INVALID_TILE, 0, 0), data(NULL) {} ~TileMatrix() { free(this->data); } /** * Get the total covered area. * @return The area covered by the matrix. */ const TileArea& GetArea() const { return this->area; } /** * Get the area of the matrix square that contains a specific tile. * @param The tile to get the map area for. * @param extend Extend the area by this many squares on all sides. * @return Tile area containing the tile. */ static TileArea GetAreaForTile(TileIndex tile, uint extend = 0) { uint tile_x = (TileX(tile) / N) * N; uint tile_y = (TileY(tile) / N) * N; uint w = N, h = N; w += min(extend * N, tile_x); h += min(extend * N, tile_y); tile_x -= min(extend * N, tile_x); tile_y -= min(extend * N, tile_y); w += min(extend * N, MapSizeX() - tile_x - w); h += min(extend * N, MapSizeY() - tile_y - h); return TileArea(TileXY(tile_x, tile_y), w, h); } /** * Extend the coverage area to include a tile. * @param tile The tile to include. */ void Add(TileIndex tile) { if (!this->area.Contains(tile)) { this->AllocateStorage(tile); } } /** * Get the value associated to a tile index. * @param tile The tile to get the value for. * @return Pointer to the value. */ T *Get(TileIndex tile) { this->Add(tile); tile -= this->area.tile; uint x = TileX(tile) / N; uint y = TileY(tile) / N; return &this->data[y * this->area.w / N + x]; } /** Array access operator, see #Get. */ inline T &operator[](TileIndex tile) { return *this->Get(tile); } }; #endif /* TILEMATRIX_TYPE_HPP */ openttd-1.5.3/src/depot.cpp0000644000000000000000000000327712627373435014326 0ustar rootroot/* $Id: depot.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 depot.cpp Handling of depots. */ #include "stdafx.h" #include "depot_base.h" #include "order_backup.h" #include "order_func.h" #include "window_func.h" #include "core/pool_func.hpp" #include "vehicle_gui.h" #include "vehiclelist.h" #include "safeguards.h" /** All our depots tucked away in a pool. */ DepotPool _depot_pool("Depot"); INSTANTIATE_POOL_METHODS(Depot) /** * Clean up a depot */ Depot::~Depot() { if (CleaningPool()) return; if (!IsDepotTile(this->xy) || GetDepotIndex(this->xy) != this->index) { /* It can happen there is no depot here anymore (TTO/TTD savegames) */ return; } /* Clear the order backup. */ OrderBackup::Reset(this->xy, false); /* Clear the depot from all order-lists */ RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index); /* Delete the depot-window */ DeleteWindowById(WC_VEHICLE_DEPOT, this->xy); /* Delete the depot list */ VehicleType vt = GetDepotVehicleType(this->xy); DeleteWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_DEPOT_LIST, vt, GetTileOwner(this->xy), this->index).Pack()); } openttd-1.5.3/src/tunnel_map.h0000644000000000000000000000501212627373442015005 0ustar rootroot/* $Id: tunnel_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 tunnel_map.h Map accessors for tunnels. */ #ifndef TUNNEL_MAP_H #define TUNNEL_MAP_H #include "road_map.h" /** * Is this a tunnel (entrance)? * @param t the tile that might be a tunnel * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return true if and only if this tile is a tunnel (entrance) */ static inline bool IsTunnel(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); return !HasBit(_m[t].m5, 7); } /** * Is this a tunnel (entrance)? * @param t the tile that might be a tunnel * @return true if and only if this tile is a tunnel (entrance) */ static inline bool IsTunnelTile(TileIndex t) { return IsTileType(t, MP_TUNNELBRIDGE) && IsTunnel(t); } TileIndex GetOtherTunnelEnd(TileIndex); bool IsTunnelInWay(TileIndex, int z); bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir); /** * Makes a road tunnel entrance * @param t the entrance of the tunnel * @param o the owner of the entrance * @param d the direction facing out of the tunnel * @param r the road type used in the tunnel */ static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadTypes r) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = TRANSPORT_ROAD << 2 | d; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; SetRoadOwner(t, ROADTYPE_ROAD, o); if (o != OWNER_TOWN) SetRoadOwner(t, ROADTYPE_TRAM, o); SetRoadTypes(t, r); } /** * Makes a rail tunnel entrance * @param t the entrance of the tunnel * @param o the owner of the entrance * @param d the direction facing out of the tunnel * @param r the rail type used in the tunnel */ static inline void MakeRailTunnel(TileIndex t, Owner o, DiagDirection d, RailType r) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); _m[t].m2 = 0; _m[t].m3 = r; _m[t].m4 = 0; _m[t].m5 = TRANSPORT_RAIL << 2 | d; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } #endif /* TUNNEL_MAP_H */ openttd-1.5.3/src/timetable_cmd.cpp0000644000000000000000000004144712627373443016004 0ustar rootroot/* $Id: timetable_cmd.cpp 27348 2015-07-30 18:45:29Z frosch $ */ /* * 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 timetable_cmd.cpp Commands related to time tabling. */ #include "stdafx.h" #include "command_func.h" #include "company_func.h" #include "date_func.h" #include "window_func.h" #include "vehicle_base.h" #include "cmd_helper.h" #include "core/sort_func.hpp" #include "table/strings.h" #include "safeguards.h" /** * Change/update a particular timetable entry. * @param v The vehicle to change the timetable of. * @param order_number The index of the timetable in the order list. * @param val The new data of the timetable entry. * @param mtf Which part of the timetable entry to change. * @param timetabled If the new value is explicitly timetabled. */ static void ChangeTimetable(Vehicle *v, VehicleOrderID order_number, uint16 val, ModifyTimetableFlags mtf, bool timetabled) { Order *order = v->GetOrder(order_number); int total_delta = 0; int timetable_delta = 0; switch (mtf) { case MTF_WAIT_TIME: total_delta = val - order->GetWaitTime(); timetable_delta = (timetabled ? val : 0) - order->GetTimetabledWait(); order->SetWaitTime(val); order->SetWaitTimetabled(timetabled); break; case MTF_TRAVEL_TIME: total_delta = val - order->GetTravelTime(); timetable_delta = (timetabled ? val : 0) - order->GetTimetabledTravel(); order->SetTravelTime(val); order->SetTravelTimetabled(timetabled); break; case MTF_TRAVEL_SPEED: order->SetMaxSpeed(val); break; default: NOT_REACHED(); } v->orders.list->UpdateTotalDuration(total_delta); v->orders.list->UpdateTimetableDuration(timetable_delta); for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { if (v->cur_real_order_index == order_number && v->current_order.Equals(*order)) { switch (mtf) { case MTF_WAIT_TIME: v->current_order.SetWaitTime(val); v->current_order.SetWaitTimetabled(timetabled); break; case MTF_TRAVEL_TIME: v->current_order.SetTravelTime(val); v->current_order.SetTravelTimetabled(timetabled); break; case MTF_TRAVEL_SPEED: v->current_order.SetMaxSpeed(val); break; default: NOT_REACHED(); } } SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } } /** * Change timetable data of an order. * @param tile Not used. * @param flags Operation to perform. * @param p1 Various bitstuffed elements * - p1 = (bit 0-19) - Vehicle with the orders to change. * - p1 = (bit 20-27) - Order index to modify. * - p1 = (bit 28-29) - Timetable data to change (@see ModifyTimetableFlags) * @param p2 The amount of time to wait. * - p2 = (bit 0-15) - The data to modify as specified by p1 bits 28-29. * 0 to clear times, UINT16_MAX to clear speed limit. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdChangeTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh = GB(p1, 0, 20); Vehicle *v = Vehicle::GetIfValid(veh); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; VehicleOrderID order_number = GB(p1, 20, 8); Order *order = v->GetOrder(order_number); if (order == NULL || order->IsType(OT_IMPLICIT)) return CMD_ERROR; ModifyTimetableFlags mtf = Extract(p1); if (mtf >= MTF_END) return CMD_ERROR; int wait_time = order->GetWaitTime(); int travel_time = order->GetTravelTime(); int max_speed = order->GetMaxSpeed(); switch (mtf) { case MTF_WAIT_TIME: wait_time = GB(p2, 0, 16); break; case MTF_TRAVEL_TIME: travel_time = GB(p2, 0, 16); break; case MTF_TRAVEL_SPEED: max_speed = GB(p2, 0, 16); if (max_speed == 0) max_speed = UINT16_MAX; // Disable speed limit. break; default: NOT_REACHED(); } if (wait_time != order->GetWaitTime()) { switch (order->GetType()) { case OT_GOTO_STATION: if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return_cmd_error(STR_ERROR_TIMETABLE_NOT_STOPPING_HERE); break; case OT_CONDITIONAL: break; default: return_cmd_error(STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS); } } if (travel_time != order->GetTravelTime() && order->IsType(OT_CONDITIONAL)) return CMD_ERROR; if (max_speed != order->GetMaxSpeed() && (order->IsType(OT_CONDITIONAL) || v->type == VEH_AIRCRAFT)) return CMD_ERROR; if (flags & DC_EXEC) { switch (mtf) { case MTF_WAIT_TIME: /* Set time if changing the value or confirming an estimated time as timetabled. */ if (wait_time != order->GetWaitTime() || (wait_time > 0 && !order->IsWaitTimetabled())) { ChangeTimetable(v, order_number, wait_time, MTF_WAIT_TIME, wait_time > 0); } break; case MTF_TRAVEL_TIME: /* Set time if changing the value or confirming an estimated time as timetabled. */ if (travel_time != order->GetTravelTime() || (travel_time > 0 && !order->IsTravelTimetabled())) { ChangeTimetable(v, order_number, travel_time, MTF_TRAVEL_TIME, travel_time > 0); } break; case MTF_TRAVEL_SPEED: if (max_speed != order->GetMaxSpeed()) { ChangeTimetable(v, order_number, max_speed, MTF_TRAVEL_SPEED, max_speed != UINT16_MAX); } break; default: break; } } return CommandCost(); } /** * Clear the lateness counter to make the vehicle on time. * @param tile Not used. * @param flags Operation to perform. * @param p1 Various bitstuffed elements * - p1 = (bit 0-19) - Vehicle with the orders to change. * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSetVehicleOnTime(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh = GB(p1, 0, 20); Vehicle *v = Vehicle::GetIfValid(veh); if (v == NULL || !v->IsPrimaryVehicle() || v->orders.list == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (flags & DC_EXEC) { v->lateness_counter = 0; SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } return CommandCost(); } /** * Order vehicles based on their timetable. The vehicles will be sorted in order * they would reach the first station. * * @param ap First Vehicle pointer. * @param bp Second Vehicle pointer. * @return Comparison value. */ static int CDECL VehicleTimetableSorter(Vehicle * const *ap, Vehicle * const *bp) { const Vehicle *a = *ap; const Vehicle *b = *bp; VehicleOrderID a_order = a->cur_real_order_index; VehicleOrderID b_order = b->cur_real_order_index; int j = (int)b_order - (int)a_order; /* Are we currently at an ordered station (un)loading? */ bool a_load = a->current_order.IsType(OT_LOADING) && a->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE; bool b_load = b->current_order.IsType(OT_LOADING) && b->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE; /* If the current order is not loading at the ordered station, decrease the order index by one since we have * not yet arrived at the station (and thus the timetable entry; still in the travelling of the previous one). * Since the ?_order variables are unsigned the -1 will flow under and place the vehicles going to order #0 at * the begin of the list with vehicles arriving at #0. */ if (!a_load) a_order--; if (!b_load) b_order--; /* First check the order index that accounted for loading, then just the raw one. */ int i = (int)b_order - (int)a_order; if (i != 0) return i; if (j != 0) return j; /* Look at the time we spent in this order; the higher, the closer to its destination. */ i = b->current_order_time - a->current_order_time; if (i != 0) return i; /* If all else is equal, use some unique index to sort it the same way. */ return b->unitnumber - a->unitnumber; } /** * Set the start date of the timetable. * @param tile Not used. * @param flags Operation to perform. * @param p2 Various bitstuffed elements * - p2 = (bit 0-19) - Vehicle ID. * - p2 = (bit 20) - Set to 1 to set timetable start for all vehicles sharing this order * @param p2 The timetable start date. * @param text Not used. * @return The error or cost of the operation. */ CommandCost CmdSetTimetableStart(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { bool timetable_all = HasBit(p1, 20); Vehicle *v = Vehicle::GetIfValid(GB(p1, 0, 20)); if (v == NULL || !v->IsPrimaryVehicle() || v->orders.list == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; /* Don't let a timetable start more than 15 years into the future or 1 year in the past. */ Date start_date = (Date)p2; if (start_date < 0 || start_date > MAX_DAY) return CMD_ERROR; if (start_date - _date > 15 * DAYS_IN_LEAP_YEAR) return CMD_ERROR; if (_date - start_date > DAYS_IN_LEAP_YEAR) return CMD_ERROR; if (timetable_all && !v->orders.list->IsCompleteTimetable()) return CMD_ERROR; if (flags & DC_EXEC) { SmallVector vehs; if (timetable_all) { for (Vehicle *w = v->orders.list->GetFirstSharedVehicle(); w != NULL; w = w->NextShared()) { *vehs.Append() = w; } } else { *vehs.Append() = v; } int total_duration = v->orders.list->GetTimetableTotalDuration(); int num_vehs = vehs.Length(); if (num_vehs >= 2) { QSortT(vehs.Begin(), vehs.Length(), &VehicleTimetableSorter); } int base = vehs.FindIndex(v); for (Vehicle **viter = vehs.Begin(); viter != vehs.End(); viter++) { int idx = (viter - vehs.Begin()) - base; Vehicle *w = *viter; w->lateness_counter = 0; ClrBit(w->vehicle_flags, VF_TIMETABLE_STARTED); /* Do multiplication, then division to reduce rounding errors. */ w->timetable_start = start_date + idx * total_duration / num_vehs / DAY_TICKS; SetWindowDirty(WC_VEHICLE_TIMETABLE, w->index); } } return CommandCost(); } /** * Start or stop filling the timetable automatically from the time the vehicle * actually takes to complete it. When starting to autofill the current times * are cleared and the timetable will start again from scratch. * @param tile Not used. * @param flags Operation to perform. * @param p1 Vehicle index. * @param p2 Various bitstuffed elements * - p2 = (bit 0) - Set to 1 to enable, 0 to disable autofill. * - p2 = (bit 1) - Set to 1 to preserve waiting times in non-destructive mode * @param text unused * @return the cost of this operation or an error */ CommandCost CmdAutofillTimetable(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh = GB(p1, 0, 20); Vehicle *v = Vehicle::GetIfValid(veh); if (v == NULL || !v->IsPrimaryVehicle() || v->orders.list == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (flags & DC_EXEC) { if (HasBit(p2, 0)) { /* Start autofilling the timetable, which clears the * "timetable has started" bit. Times are not cleared anymore, but are * overwritten when the order is reached now. */ SetBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v->vehicle_flags, VF_TIMETABLE_STARTED); /* Overwrite waiting times only if they got longer */ if (HasBit(p2, 1)) SetBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); v->timetable_start = 0; v->lateness_counter = 0; } else { ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) { if (v2 != v) { /* Stop autofilling; only one vehicle at a time can perform autofill */ ClrBit(v2->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v2->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } SetWindowDirty(WC_VEHICLE_TIMETABLE, v2->index); } } return CommandCost(); } /** * Update the timetable for the vehicle. * @param v The vehicle to update the timetable for. * @param travelling Whether we just travelled or waited at a station. */ void UpdateVehicleTimetable(Vehicle *v, bool travelling) { uint time_taken = v->current_order_time; v->current_order_time = 0; if (v->current_order.IsType(OT_IMPLICIT)) return; // no timetabling of auto orders if (v->cur_real_order_index >= v->GetNumOrders()) return; Order *real_current_order = v->GetOrder(v->cur_real_order_index); VehicleOrderID first_manual_order = 0; for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_IMPLICIT); o = o->next) { ++first_manual_order; } bool just_started = false; /* This vehicle is arriving at the first destination in the timetable. */ if (v->cur_real_order_index == first_manual_order && travelling) { /* If the start date hasn't been set, or it was set automatically when * the vehicle last arrived at the first destination, update it to the * current time. Otherwise set the late counter appropriately to when * the vehicle should have arrived. */ just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED); if (v->timetable_start != 0) { v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract; v->timetable_start = 0; } SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED); SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return; bool autofilling = HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); bool remeasure_wait_time = !real_current_order->IsWaitTimetabled() || (autofilling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)); if (travelling && remeasure_wait_time) { /* We just finished travelling and want to remeasure the loading time, * so do not apply any restrictions for the loading to finish. */ v->current_order.SetWaitTime(0); } if (just_started) return; /* Before modifying waiting times, check whether we want to preserve bigger ones. */ if (!real_current_order->IsType(OT_CONDITIONAL) && (travelling || time_taken > real_current_order->GetWaitTime() || remeasure_wait_time)) { /* Round the time taken up to the nearest day, as this will avoid * confusion for people who are timetabling in days, and can be * adjusted later by people who aren't. * For trains/aircraft multiple movement cycles are done in one * tick. This makes it possible to leave the station and process * e.g. a depot order in the same tick, causing it to not fill * the timetable entry like is done for road vehicles/ships. * Thus always make sure at least one tick is used between the * processing of different orders when filling the timetable. */ uint time_to_set = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS; if (travelling && (autofilling || !real_current_order->IsTravelTimetabled())) { ChangeTimetable(v, v->cur_real_order_index, time_to_set, MTF_TRAVEL_TIME, autofilling); } else if (!travelling && (autofilling || !real_current_order->IsWaitTimetabled())) { ChangeTimetable(v, v->cur_real_order_index, time_to_set, MTF_WAIT_TIME, autofilling); } } if (v->cur_real_order_index == first_manual_order && travelling) { /* If we just started we would have returned earlier and have not reached * this code. So obviously, we have completed our round: So turn autofill * off again. */ ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } if (autofilling) return; uint timetabled = travelling ? real_current_order->GetTimetabledTravel() : real_current_order->GetTimetabledWait(); /* Vehicles will wait at stations if they arrive early even if they are not * timetabled to wait there, so make sure the lateness counter is updated * when this happens. */ if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return; v->lateness_counter -= (timetabled - time_taken); /* When we are more late than this timetabled bit takes we (somewhat expensively) * check how many ticks the (fully filled) timetable has. If a timetable cycle is * shorter than the amount of ticks we are late we reduce the lateness by the * length of a full cycle till lateness is less than the length of a timetable * cycle. When the timetable isn't fully filled the cycle will be INVALID_TICKS. */ if (v->lateness_counter > (int)timetabled) { Ticks cycle = v->orders.list->GetTimetableTotalDuration(); if (cycle != INVALID_TICKS && v->lateness_counter > cycle) { v->lateness_counter %= cycle; } } for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } } openttd-1.5.3/src/gamelog_internal.h0000644000000000000000000000647012627373435016165 0ustar rootroot/* $Id: gamelog_internal.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 gamelog_internal.h Declaration shared among gamelog.cpp and saveload/gamelog_sl.cpp */ #ifndef GAMELOG_INTERNAL_H #define GAMELOG_INTERNAL_H #include "network/core/config.h" #include "gamelog.h" /** Type of logged change */ enum GamelogChangeType { GLCT_MODE, ///< Scenario editor x Game, different landscape GLCT_REVISION, ///< Changed game revision string GLCT_OLDVER, ///< Loaded from savegame without logged data GLCT_SETTING, ///< Non-networksafe setting value changed GLCT_GRFADD, ///< Removed GRF GLCT_GRFREM, ///< Added GRF GLCT_GRFCOMPAT, ///< Loading compatible GRF GLCT_GRFPARAM, ///< GRF parameter changed GLCT_GRFMOVE, ///< GRF order changed GLCT_GRFBUG, ///< GRF bug triggered GLCT_EMERGENCY, ///< Emergency savegame GLCT_END, ///< So we know how many GLCTs are there GLCT_NONE = 0xFF, ///< In savegames, end of list }; /** Contains information about one logged change */ struct LoggedChange { GamelogChangeType ct; ///< Type of change logged in this struct union { struct { byte mode; ///< new game mode - Editor x Game byte landscape; ///< landscape (temperate, arctic, ...) } mode; struct { char text[NETWORK_REVISION_LENGTH]; ///< revision string, _openttd_revision uint32 newgrf; ///< _openttd_newgrf_version uint16 slver; ///< _sl_version byte modified; ///< _openttd_revision_modified } revision; struct { uint32 type; ///< type of savegame, @see SavegameType uint32 version; ///< major and minor version OR ttdp version } oldver; GRFIdentifier grfadd; ///< ID and md5sum of added GRF struct { uint32 grfid; ///< ID of removed GRF } grfrem; GRFIdentifier grfcompat; ///< ID and new md5sum of changed GRF struct { uint32 grfid; ///< ID of GRF with changed parameters } grfparam; struct { uint32 grfid; ///< ID of moved GRF int32 offset; ///< offset, positive = move down } grfmove; struct { char *name; ///< name of the setting int32 oldval; ///< old value int32 newval; ///< new value } setting; struct { uint64 data; ///< additional data uint32 grfid; ///< ID of problematic GRF byte bug; ///< type of bug, @see enum GRFBugs } grfbug; }; }; /** Contains information about one logged action that caused at least one logged change */ struct LoggedAction { LoggedChange *change; ///< First logged change in this action uint32 changes; ///< Number of changes in this action GamelogActionType at; ///< Type of action uint16 tick; ///< Tick when it happened }; extern LoggedAction *_gamelog_action; extern uint _gamelog_actions; #endif /* GAMELOG_INTERNAL_H */ openttd-1.5.3/src/string_type.h0000644000000000000000000000532512627373442015221 0ustar rootroot/* $Id: string_type.h 23940 2012-02-12 19:46:40Z smatz $ */ /* * 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 string_type.h Types for strings. */ #ifndef STRING_TYPE_H #define STRING_TYPE_H #include "core/enum_type.hpp" /** A non-breaking space. */ #define NBSP "\xC2\xA0" /** A left-to-right marker, marks the next character as left-to-right. */ #define LRM "\xE2\x80\x8E" /** * Valid filter types for IsValidChar. */ enum CharSetFilter { CS_ALPHANUMERAL, ///< Both numeric and alphabetic and spaces and stuff CS_NUMERAL, ///< Only numeric ones CS_NUMERAL_SPACE, ///< Only numbers and spaces CS_ALPHA, ///< Only alphabetic values CS_HEXADECIMAL, ///< Only hexadecimal characters }; /** Type for wide characters, i.e. non-UTF8 encoded unicode characters. */ typedef uint32 WChar; /* The following are directional formatting codes used to get the LTR and RTL strings right: * http://www.unicode.org/unicode/reports/tr9/#Directional_Formatting_Codes */ static const WChar CHAR_TD_LRM = 0x200E; ///< The next character acts like a left-to-right character. static const WChar CHAR_TD_RLM = 0x200F; ///< The next character acts like a right-to-left character. static const WChar CHAR_TD_LRE = 0x202A; ///< The following text is embedded left-to-right. static const WChar CHAR_TD_RLE = 0x202B; ///< The following text is embedded right-to-left. static const WChar CHAR_TD_LRO = 0x202D; ///< Force the following characters to be treated as left-to-right characters. static const WChar CHAR_TD_RLO = 0x202E; ///< Force the following characters to be treated as right-to-left characters. static const WChar CHAR_TD_PDF = 0x202C; ///< Restore the text-direction state to before the last LRE, RLE, LRO or RLO. /** Settings for the string validation. */ enum StringValidationSettings { SVS_NONE = 0, ///< Allow nothing and replace nothing. SVS_REPLACE_WITH_QUESTION_MARK = 1 << 0, ///< Replace the unknown/bad bits with question marks. SVS_ALLOW_NEWLINE = 1 << 1, ///< Allow newlines. SVS_ALLOW_CONTROL_CODE = 1 << 2, ///< Allow the special control codes. }; DECLARE_ENUM_AS_BIT_SET(StringValidationSettings) #endif /* STRING_TYPE_H */ openttd-1.5.3/src/group_type.h0000644000000000000000000000241612627373445015050 0ustar rootroot/* $Id: group_type.h 24139 2012-04-17 19:44:16Z michi_cc $ */ /* * 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 group_type.h Types of a group. */ #ifndef GROUP_TYPE_H #define GROUP_TYPE_H typedef uint16 GroupID; ///< Type for all group identifiers. static const GroupID NEW_GROUP = 0xFFFC; ///< Sentinel for a to-be-created group. static const GroupID ALL_GROUP = 0xFFFD; ///< All vehicles are in this group. static const GroupID DEFAULT_GROUP = 0xFFFE; ///< Ungrouped vehicles are in this group. static const GroupID INVALID_GROUP = 0xFFFF; ///< Sentinel for invalid groups. static const uint MAX_LENGTH_GROUP_NAME_CHARS = 32; ///< The maximum length of a group name in characters including '\0' struct Group; #endif /* GROUP_TYPE_H */ openttd-1.5.3/src/company_base.h0000644000000000000000000001645512627373433015320 0ustar rootroot/* $Id: company_base.h 26081 2013-11-24 09:52:35Z rubidium $ */ /* * 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 company_base.h Definition of stuff that is very close to a company, like the company struct itself. */ #ifndef COMPANY_BASE_H #define COMPANY_BASE_H #include "road_type.h" #include "livery.h" #include "autoreplace_type.h" #include "tile_type.h" #include "settings_type.h" #include "group.h" /** Statistics about the economy. */ struct CompanyEconomyEntry { Money income; ///< The amount of income. Money expenses; ///< The amount of expenses. CargoArray delivered_cargo; ///< The amount of delivered cargo. int32 performance_history; ///< Company score (scale 0-1000) Money company_value; ///< The value of the company. }; struct CompanyInfrastructure { uint32 road[ROADTYPE_END]; ///< Count of company owned track bits for each road type. uint32 signal; ///< Count of company owned signals. uint32 rail[RAILTYPE_END]; ///< Count of company owned track bits for each rail type. uint32 water; ///< Count of company owned track bits for canals. uint32 station; ///< Count of company owned station tiles. uint32 airport; ///< Count of company owned airports. /** Get total sum of all owned track bits. */ uint32 GetRailTotal() const { uint32 total = 0; for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) total += this->rail[rt]; return total; } }; typedef Pool CompanyPool; extern CompanyPool _company_pool; /** Statically loadable part of Company pool item */ struct CompanyProperties { uint32 name_2; ///< Parameter of #name_1. uint16 name_1; ///< Name of the company if the user did not change it. char *name; ///< Name of the company if the user changed it. uint16 president_name_1; ///< Name of the president if the user did not change it. uint32 president_name_2; ///< Parameter of #president_name_1 char *president_name; ///< Name of the president if the user changed it. CompanyManagerFace face; ///< Face description of the president. Money money; ///< Money owned by the company. byte money_fraction; ///< Fraction of money of the company, too small to represent in #money. Money current_loan; ///< Amount of money borrowed from the bank. byte colour; ///< Company colour. RailTypes avail_railtypes; ///< Rail types available to the company. byte block_preview; ///< Number of quarters that the company is not allowed to get new exclusive engine previews (see CompaniesGenStatistics). TileIndex location_of_HQ; ///< Northern tile of HQ; #INVALID_TILE when there is none. TileIndex last_build_coordinate; ///< Coordinate of the last build thing by this company. OwnerByte share_owners[4]; ///< Owners of the 4 shares of the company. #INVALID_OWNER if nobody has bought them yet. Year inaugurated_year; ///< Year of starting the company. byte months_of_bankruptcy; ///< Number of months that the company is unable to pay its debts CompanyMask bankrupt_asked; ///< which companies were asked about buying it? int16 bankrupt_timeout; ///< If bigger than \c 0, amount of time to wait for an answer on an offer to buy this company. Money bankrupt_value; uint32 terraform_limit; ///< Amount of tileheights we can (still) terraform (times 65536). uint32 clear_limit; ///< Amount of tiles we can (still) clear (times 65536). uint32 tree_limit; ///< Amount of trees we can (still) plant (times 65536). /** * If \c true, the company is (also) controlled by the computer (a NoAI program). * @note It is possible that the user is also participating in such a company. */ bool is_ai; Money yearly_expenses[3][EXPENSES_END]; ///< Expenses of the company for the last three years, in every #Expenses category. CompanyEconomyEntry cur_economy; ///< Economic data of the company of this quarter. CompanyEconomyEntry old_economy[MAX_HISTORY_QUARTERS]; ///< Economic data of the company of the last #MAX_HISTORY_QUARTERS quarters. byte num_valid_stat_ent; ///< Number of valid statistical entries in #old_economy. CompanyProperties() : name(NULL), president_name(NULL) {} ~CompanyProperties() { free(this->name); free(this->president_name); } }; struct Company : CompanyPool::PoolItem<&_company_pool>, CompanyProperties { Company(uint16 name_1 = 0, bool is_ai = false); ~Company(); Livery livery[LS_END]; RoadTypes avail_roadtypes; ///< Road types available to this company. class AIInstance *ai_instance; class AIInfo *ai_info; EngineRenewList engine_renew_list; ///< Engine renewals of this company. CompanySettings settings; ///< settings specific for each company GroupStatistics group_all[VEH_COMPANY_END]; ///< NOSAVE: Statistics for the ALL_GROUP group. GroupStatistics group_default[VEH_COMPANY_END]; ///< NOSAVE: Statistics for the DEFAULT_GROUP group. CompanyInfrastructure infrastructure; ///< NOSAVE: Counts of company owned infrastructure. /** * Is this company a valid company, controlled by the computer (a NoAI program)? * @param index Index in the pool. * @return \c true if it is a valid, computer controlled company, else \c false. */ static inline bool IsValidAiID(size_t index) { const Company *c = Company::GetIfValid(index); return c != NULL && c->is_ai; } /** * Is this company a valid company, not controlled by a NoAI program? * @param index Index in the pool. * @return \c true if it is a valid, human controlled company, else \c false. * @note If you know that \a index refers to a valid company, you can use #IsHumanID() instead. */ static inline bool IsValidHumanID(size_t index) { const Company *c = Company::GetIfValid(index); return c != NULL && !c->is_ai; } /** * Is this company a company not controlled by a NoAI program? * @param index Index in the pool. * @return \c true if it is a human controlled company, else \c false. * @pre \a index must be a valid CompanyID. * @note If you don't know whether \a index refers to a valid company, you should use #IsValidHumanID() instead. */ static inline bool IsHumanID(size_t index) { return !Company::Get(index)->is_ai; } static void PostDestructor(size_t index); }; #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) Money CalculateCompanyValue(const Company *c, bool including_loan = true); extern uint _next_competitor_start; extern uint _cur_company_tick_index; #endif /* COMPANY_BASE_H */ openttd-1.5.3/src/fios_gui.cpp0000644000000000000000000007170112627373445015015 0ustar rootroot/* $Id: fios_gui.cpp 26960 2014-10-05 11:20:02Z peter1138 $ */ /* * 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 fios_gui.cpp GUIs for loading/saving games, scenarios, heightmaps, ... */ #include "stdafx.h" #include "saveload/saveload.h" #include "error.h" #include "gui.h" #include "gfx_func.h" #include "command_func.h" #include "network/network.h" #include "network/network_content.h" #include "strings_func.h" #include "fileio_func.h" #include "fios.h" #include "window_func.h" #include "tilehighlight_func.h" #include "querystring_gui.h" #include "engine_func.h" #include "landscape_type.h" #include "date_func.h" #include "core/geometry_func.hpp" #include "gamelog.h" #include "widgets/fios_widget.h" #include "table/sprites.h" #include "table/strings.h" #include "safeguards.h" SaveLoadDialogMode _saveload_mode; LoadCheckData _load_check_data; ///< Data loaded from save during SL_LOAD_CHECK. static bool _fios_path_changed; static bool _savegame_sort_dirty; /** * Reset read data. */ void LoadCheckData::Clear() { this->checkable = false; this->error = INVALID_STRING_ID; free(this->error_data); this->error_data = NULL; this->map_size_x = this->map_size_y = 256; // Default for old savegames which do not store mapsize. this->current_date = 0; memset(&this->settings, 0, sizeof(this->settings)); const CompanyPropertiesMap::iterator end = this->companies.End(); for (CompanyPropertiesMap::iterator it = this->companies.Begin(); it != end; it++) { delete it->second; } companies.Clear(); GamelogFree(this->gamelog_action, this->gamelog_actions); this->gamelog_action = NULL; this->gamelog_actions = 0; ClearGRFConfigList(&this->grfconfig); } /** Load game/scenario with optional content download */ static const NWidgetPart _nested_load_dialog_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetFill(1, 1), SetPadding(2, 1, 2, 2), SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SL_CONTENT_DOWNLOAD_SEL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_CONTENT_DOWNLOAD), SetResize(1, 0), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), EndContainer(), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SL_DETAILS), SetResize(1, 1), SetFill(1, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_MISSING_NEWGRFS), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_NEWGRF_INFO), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_BUTTON), SetDataTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_TOOLTIP), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), EndContainer(), }; /** Load heightmap with content download */ static const NWidgetPart _nested_load_heightmap_dialog_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetFill(1, 1), SetPadding(2, 1, 2, 2), SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_CONTENT_DOWNLOAD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_BUTTON), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), EndContainer(), }; /** Save game/scenario */ static const NWidgetPart _nested_save_dialog_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetPadding(2, 1, 0, 2), SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR), EndContainer(), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_SAVE_OSK_TITLE), SetPadding(3, 2, 2, 2), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_SAVELOAD_OSKTITLE, STR_SAVELOAD_EDITBOX_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_DELETE_SELECTION), SetDataTip(STR_SAVELOAD_DELETE_BUTTON, STR_SAVELOAD_DELETE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SL_DETAILS), SetResize(1, 1), SetFill(1, 1), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetResize(1, 0), SetFill(1, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), EndContainer(), }; /** Colours for fios types, indexed by #FiosType. */ const TextColour _fios_colours[] = { TC_LIGHT_BLUE, TC_DARK_GREEN, TC_DARK_GREEN, TC_ORANGE, TC_LIGHT_BROWN, TC_ORANGE, TC_LIGHT_BROWN, TC_ORANGE, TC_ORANGE, TC_YELLOW }; void BuildFileList() { _fios_path_changed = true; FiosFreeSavegameList(); switch (_saveload_mode) { case SLD_LOAD_SCENARIO: case SLD_SAVE_SCENARIO: FiosGetScenarioList(_saveload_mode); break; case SLD_SAVE_HEIGHTMAP: case SLD_LOAD_HEIGHTMAP: FiosGetHeightmapList(_saveload_mode); break; default: FiosGetSavegameList(_saveload_mode); break; } /* Invalidate saveload window */ InvalidateWindowData(WC_SAVELOAD, 0, 2, true); } static void MakeSortedSaveGameList() { uint sort_start = 0; uint sort_end = 0; /* Directories are always above the files (FIOS_TYPE_DIR) * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE) * Only sort savegames/scenarios, not directories */ for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) { switch (item->type) { case FIOS_TYPE_DIR: sort_start++; break; case FIOS_TYPE_PARENT: sort_start++; break; case FIOS_TYPE_DRIVE: sort_end++; break; default: break; } } uint s_amount = _fios_items.Length() - sort_start - sort_end; QSortT(_fios_items.Get(sort_start), s_amount, CompareFiosItems); } struct SaveLoadWindow : public Window { private: QueryString filename_editbox; ///< Filename editbox. FiosItem o_dir; const FiosItem *selected; Scrollbar *vscroll; public: /** Generate a default save filename. */ void GenerateFileName() { GenerateDefaultSaveName(this->filename_editbox.text.buf, &this->filename_editbox.text.buf[this->filename_editbox.text.max_bytes - 1]); this->filename_editbox.text.UpdateSize(); } SaveLoadWindow(WindowDesc *desc, SaveLoadDialogMode mode) : Window(desc), filename_editbox(64) { static const StringID saveload_captions[] = { STR_SAVELOAD_LOAD_CAPTION, STR_SAVELOAD_LOAD_SCENARIO, STR_SAVELOAD_SAVE_CAPTION, STR_SAVELOAD_SAVE_SCENARIO, STR_SAVELOAD_LOAD_HEIGHTMAP, STR_SAVELOAD_SAVE_HEIGHTMAP, }; assert((uint)mode < lengthof(saveload_captions)); /* Use an array to define what will be the current file type being handled * by current file mode */ switch (mode) { case SLD_SAVE_GAME: this->GenerateFileName(); break; case SLD_SAVE_HEIGHTMAP: case SLD_SAVE_SCENARIO: this->filename_editbox.text.Assign("UNNAMED"); break; default: break; } this->querystrings[WID_SL_SAVE_OSK_TITLE] = &this->filename_editbox; this->filename_editbox.ok_button = WID_SL_SAVE_GAME; this->CreateNestedTree(true); if (mode == SLD_LOAD_GAME) this->GetWidget(WID_SL_CONTENT_DOWNLOAD_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL); this->GetWidget(WID_SL_CAPTION)->widget_data = saveload_captions[mode]; this->vscroll = this->GetScrollbar(WID_SL_SCROLLBAR); this->FinishInitNested(0); this->LowerWidget(WID_SL_DRIVES_DIRECTORIES_LIST); /* pause is only used in single-player, non-editor mode, non-menu mode. It * will be unpaused in the WE_DESTROY event handler. */ if (_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR) { DoCommandP(0, PM_PAUSED_SAVELOAD, 1, CMD_PAUSE); } SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); this->OnInvalidateData(0); ResetObjectToPlace(); o_dir.type = FIOS_TYPE_DIRECT; switch (_saveload_mode) { case SLD_SAVE_GAME: case SLD_LOAD_GAME: FioGetDirectory(o_dir.name, lastof(o_dir.name), SAVE_DIR); break; case SLD_SAVE_SCENARIO: case SLD_LOAD_SCENARIO: FioGetDirectory(o_dir.name, lastof(o_dir.name), SCENARIO_DIR); break; case SLD_SAVE_HEIGHTMAP: case SLD_LOAD_HEIGHTMAP: FioGetDirectory(o_dir.name, lastof(o_dir.name), HEIGHTMAP_DIR); break; default: strecpy(o_dir.name, _personal_dir, lastof(o_dir.name)); } /* Focus the edit box by default in the save windows */ if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP) { this->SetFocusedWidget(WID_SL_SAVE_OSK_TITLE); } } virtual ~SaveLoadWindow() { /* pause is only used in single-player, non-editor mode, non menu mode */ if (!_networking && _game_mode != GM_EDITOR && _game_mode != GM_MENU) { DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE); } FiosFreeSavegameList(); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_SL_SORT_BYNAME: case WID_SL_SORT_BYDATE: if (((_savegame_sort_order & SORT_BY_NAME) != 0) == (widget == WID_SL_SORT_BYNAME)) { this->DrawSortButtonState(widget, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP); } break; case WID_SL_BACKGROUND: { static const char *path = NULL; static StringID str = STR_ERROR_UNABLE_TO_READ_DRIVE; static uint64 tot = 0; if (_fios_path_changed) { str = FiosGetDescText(&path, &tot); _fios_path_changed = false; } if (str != STR_ERROR_UNABLE_TO_READ_DRIVE) SetDParam(0, tot); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP, str); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, path, TC_BLACK); break; } case WID_SL_DRIVES_DIRECTORIES_LIST: { GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK); uint y = r.top + WD_FRAMERECT_TOP; for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) { const FiosItem *item = _fios_items.Get(pos); if (item == this->selected) { GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_BLUE); } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, item->title, _fios_colours[item->type]); y += this->resize.step_height; if (y >= this->vscroll->GetCapacity() * this->resize.step_height + r.top + WD_FRAMERECT_TOP) break; } break; } case WID_SL_DETAILS: { GfxFillRect(r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, r.right - WD_FRAMERECT_RIGHT, r.top + FONT_HEIGHT_NORMAL * 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, PC_GREY); DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL / 2 + WD_FRAMERECT_TOP, STR_SAVELOAD_DETAIL_CAPTION, TC_FROMSTRING, SA_HOR_CENTER); if (this->selected == NULL) break; uint y = r.top + FONT_HEIGHT_NORMAL * 2 + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; uint y_max = r.bottom - FONT_HEIGHT_NORMAL - WD_FRAMERECT_BOTTOM; if (y > y_max) break; if (!_load_check_data.checkable) { /* Old savegame, no information available */ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_NOT_AVAILABLE); y += FONT_HEIGHT_NORMAL; } else if (_load_check_data.error != INVALID_STRING_ID) { /* Incompatible / broken savegame */ SetDParamStr(0, _load_check_data.error_data); y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom - WD_FRAMERECT_BOTTOM, _load_check_data.error, TC_RED); } else { /* Mapsize */ SetDParam(0, _load_check_data.map_size_x); SetDParam(1, _load_check_data.map_size_y); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE); y += FONT_HEIGHT_NORMAL; if (y > y_max) break; /* Climate */ byte landscape = _load_check_data.settings.game_creation.landscape; if (landscape < NUM_LANDSCAPE) { SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + landscape); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); y += FONT_HEIGHT_NORMAL; } y += WD_PAR_VSEP_NORMAL; if (y > y_max) break; /* Start date (if available) */ if (_load_check_data.settings.game_creation.starting_year != 0) { SetDParam(0, ConvertYMDToDate(_load_check_data.settings.game_creation.starting_year, 0, 1)); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE); y += FONT_HEIGHT_NORMAL; } if (y > y_max) break; /* Hide current date for scenarios */ if (_saveload_mode != SLD_LOAD_SCENARIO && _saveload_mode != SLD_SAVE_SCENARIO) { /* Current date */ SetDParam(0, _load_check_data.current_date); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE); y += FONT_HEIGHT_NORMAL; } /* Hide the NewGRF stuff when saving. We also hide the button. */ if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) { y += WD_PAR_VSEP_NORMAL; if (y > y_max) break; /* NewGrf compatibility */ SetDParam(0, _load_check_data.grfconfig == NULL ? STR_NEWGRF_LIST_NONE : STR_NEWGRF_LIST_ALL_FOUND + _load_check_data.grf_compatibility); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_GRFSTATUS); y += FONT_HEIGHT_NORMAL; } if (y > y_max) break; /* Hide the company stuff for scenarios */ if (_saveload_mode != SLD_LOAD_SCENARIO && _saveload_mode != SLD_SAVE_SCENARIO) { y += FONT_HEIGHT_NORMAL; if (y > y_max) break; /* Companies / AIs */ CompanyPropertiesMap::const_iterator end = _load_check_data.companies.End(); for (CompanyPropertiesMap::const_iterator it = _load_check_data.companies.Begin(); it != end; it++) { SetDParam(0, it->first + 1); const CompanyProperties &c = *it->second; if (c.name != NULL) { SetDParam(1, STR_JUST_RAW_STRING); SetDParamStr(2, c.name); } else { SetDParam(1, c.name_1); SetDParam(2, c.name_2); } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_COMPANY_INDEX); y += FONT_HEIGHT_NORMAL; if (y > y_max) break; } } } break; } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SL_BACKGROUND: size->height = 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; case WID_SL_DRIVES_DIRECTORIES_LIST: resize->height = FONT_HEIGHT_NORMAL; size->height = resize->height * 10 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; case WID_SL_SORT_BYNAME: case WID_SL_SORT_BYDATE: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } } } virtual void OnPaint() { if (_savegame_sort_dirty) { _savegame_sort_dirty = false; MakeSortedSaveGameList(); } this->vscroll->SetCount(_fios_items.Length()); this->DrawWidgets(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_SL_SORT_BYNAME: // Sort save names by name _savegame_sort_order = (_savegame_sort_order == SORT_BY_NAME) ? SORT_BY_NAME | SORT_DESCENDING : SORT_BY_NAME; _savegame_sort_dirty = true; this->SetDirty(); break; case WID_SL_SORT_BYDATE: // Sort save names by date _savegame_sort_order = (_savegame_sort_order == SORT_BY_DATE) ? SORT_BY_DATE | SORT_DESCENDING : SORT_BY_DATE; _savegame_sort_dirty = true; this->SetDirty(); break; case WID_SL_HOME_BUTTON: // OpenTTD 'button', jumps to OpenTTD directory FiosBrowseTo(&o_dir); this->InvalidateData(); break; case WID_SL_LOAD_BUTTON: if (this->selected != NULL && !_load_check_data.HasErrors()) { const char *name = FiosBrowseTo(this->selected); SetFiosType(this->selected->type); strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name)); strecpy(_file_to_saveload.title, this->selected->title, lastof(_file_to_saveload.title)); if (_saveload_mode == SLD_LOAD_HEIGHTMAP) { delete this; ShowHeightmapLoad(); } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) { _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME; ClearErrorMessages(); delete this; } } break; case WID_SL_NEWGRF_INFO: if (_load_check_data.HasNewGrfs()) { ShowNewGRFSettings(false, false, false, &_load_check_data.grfconfig); } break; case WID_SL_MISSING_NEWGRFS: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else if (_load_check_data.HasNewGrfs()) { #if defined(ENABLE_NETWORK) ShowMissingContentWindow(_load_check_data.grfconfig); #endif } break; case WID_SL_DRIVES_DIRECTORIES_LIST: { // Click the listbox int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WD_FRAMERECT_TOP); if (y == INT_MAX) return; const FiosItem *file = _fios_items.Get(y); const char *name = FiosBrowseTo(file); if (name != NULL) { if (click_count == 1) { if (this->selected != file) { this->selected = file; _load_check_data.Clear(); if (file->type == FIOS_TYPE_FILE || file->type == FIOS_TYPE_SCENARIO) { SaveOrLoad(name, SL_LOAD_CHECK, NO_DIRECTORY, false); } this->InvalidateData(1); } if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP) { /* Copy clicked name to editbox */ this->filename_editbox.text.Assign(file->title); this->SetWidgetDirty(WID_SL_SAVE_OSK_TITLE); } } else if (!_load_check_data.HasErrors()) { this->selected = file; if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) { this->OnClick(pt, WID_SL_LOAD_BUTTON, 1); } else if (_saveload_mode == SLD_LOAD_HEIGHTMAP) { SetFiosType(file->type); strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name)); strecpy(_file_to_saveload.title, file->title, lastof(_file_to_saveload.title)); delete this; ShowHeightmapLoad(); } } } else { /* Changed directory, need refresh. */ this->InvalidateData(); } break; } case WID_SL_CONTENT_DOWNLOAD: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else { #if defined(ENABLE_NETWORK) switch (_saveload_mode) { default: NOT_REACHED(); case SLD_LOAD_SCENARIO: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_SCENARIO); break; case SLD_LOAD_HEIGHTMAP: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_HEIGHTMAP); break; } #endif } break; case WID_SL_DELETE_SELECTION: // Delete break; case WID_SL_SAVE_GAME: // Save game /* Note, this is also called via the OSK; and we need to lower the button. */ this->HandleButtonClick(WID_SL_SAVE_GAME); break; } } virtual EventState OnKeyPress(WChar key, uint16 keycode) { if (keycode == WKC_ESC) { delete this; return ES_HANDLED; } return ES_NOT_HANDLED; } virtual void OnTimeout() { /* This test protects against using widgets 11 and 12 which are only available * in those saveload modes. */ if (!(_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP)) return; if (this->IsWidgetLowered(WID_SL_DELETE_SELECTION)) { // Delete button clicked if (!FiosDelete(this->filename_editbox.text.buf)) { ShowErrorMessage(STR_ERROR_UNABLE_TO_DELETE_FILE, INVALID_STRING_ID, WL_ERROR); } else { this->InvalidateData(); /* Reset file name to current date on successful delete */ if (_saveload_mode == SLD_SAVE_GAME) GenerateFileName(); } } else if (this->IsWidgetLowered(WID_SL_SAVE_GAME)) { // Save button clicked if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) { _switch_mode = SM_SAVE_GAME; FiosMakeSavegameName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name)); } else { _switch_mode = SM_SAVE_HEIGHTMAP; FiosMakeHeightmapName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name)); } /* In the editor set up the vehicle engines correctly (date might have changed) */ if (_game_mode == GM_EDITOR) StartupEngines(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_SL_DRIVES_DIRECTORIES_LIST); } /** * 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) { switch (data) { case 0: /* Rescan files */ this->selected = NULL; _load_check_data.Clear(); if (!gui_scope) break; BuildFileList(); /* FALL THROUGH */ case 1: /* Selection changes */ if (!gui_scope) break; if (_saveload_mode == SLD_LOAD_HEIGHTMAP) { this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == NULL || _load_check_data.HasErrors()); } if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) { this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == NULL || _load_check_data.HasErrors() || !(!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs())); this->SetWidgetDisabledState(WID_SL_NEWGRF_INFO, !_load_check_data.HasNewGrfs()); this->SetWidgetDisabledState(WID_SL_MISSING_NEWGRFS, !_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility == GLC_ALL_GOOD); } break; case 2: /* _fios_items changed */ this->vscroll->SetCount(_fios_items.Length()); this->selected = NULL; _load_check_data.Clear(); break; } } }; /** Load game/scenario */ static WindowDesc _load_dialog_desc( WDP_CENTER, "load_game", 500, 294, WC_SAVELOAD, WC_NONE, 0, _nested_load_dialog_widgets, lengthof(_nested_load_dialog_widgets) ); /** Load heightmap */ static WindowDesc _load_heightmap_dialog_desc( WDP_CENTER, "load_heightmap", 257, 320, WC_SAVELOAD, WC_NONE, 0, _nested_load_heightmap_dialog_widgets, lengthof(_nested_load_heightmap_dialog_widgets) ); /** Save game/scenario */ static WindowDesc _save_dialog_desc( WDP_CENTER, "save_game", 500, 294, WC_SAVELOAD, WC_NONE, 0, _nested_save_dialog_widgets, lengthof(_nested_save_dialog_widgets) ); /** * These values are used to convert the file/operations mode into a corresponding file type. * So each entry, as expressed by the related comment, is based on the enum */ static const FileType _file_modetotype[] = { FT_SAVEGAME, // used for SLD_LOAD_GAME FT_SCENARIO, // used for SLD_LOAD_SCENARIO FT_SAVEGAME, // used for SLD_SAVE_GAME FT_SCENARIO, // used for SLD_SAVE_SCENARIO FT_HEIGHTMAP, // used for SLD_LOAD_HEIGHTMAP FT_HEIGHTMAP, // used for SLD_SAVE_HEIGHTMAP }; /** * Launch save/load dialog in the given mode. * @param mode Save/load mode. */ void ShowSaveLoadDialog(SaveLoadDialogMode mode) { DeleteWindowById(WC_SAVELOAD, 0); WindowDesc *sld; switch (mode) { case SLD_SAVE_GAME: case SLD_SAVE_SCENARIO: case SLD_SAVE_HEIGHTMAP: sld = &_save_dialog_desc; break; case SLD_LOAD_HEIGHTMAP: sld = &_load_heightmap_dialog_desc; break; default: sld = &_load_dialog_desc; break; } _saveload_mode = mode; _file_to_saveload.filetype = _file_modetotype[mode]; new SaveLoadWindow(sld, mode); } void SetFiosType(const byte fiostype) { switch (fiostype) { case FIOS_TYPE_FILE: case FIOS_TYPE_SCENARIO: _file_to_saveload.mode = SL_LOAD; break; case FIOS_TYPE_OLDFILE: case FIOS_TYPE_OLD_SCENARIO: _file_to_saveload.mode = SL_OLD_LOAD; break; #ifdef WITH_PNG case FIOS_TYPE_PNG: _file_to_saveload.mode = SL_PNG; break; #endif /* WITH_PNG */ case FIOS_TYPE_BMP: _file_to_saveload.mode = SL_BMP; break; default: _file_to_saveload.mode = SL_INVALID; break; } } openttd-1.5.3/src/road_map.h0000644000000000000000000004005312627373441014430 0ustar rootroot/* $Id: road_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 road_map.h Map accessors for roads. */ #ifndef ROAD_MAP_H #define ROAD_MAP_H #include "track_func.h" #include "depot_type.h" #include "rail_type.h" #include "road_func.h" #include "tile_map.h" /** The different types of road tiles. */ enum RoadTileType { ROAD_TILE_NORMAL, ///< Normal road ROAD_TILE_CROSSING, ///< Level crossing ROAD_TILE_DEPOT, ///< Depot (one entrance) }; /** * Get the type of the road tile. * @param t Tile to query. * @pre IsTileType(t, MP_ROAD) * @return The road tile type. */ static inline RoadTileType GetRoadTileType(TileIndex t) { assert(IsTileType(t, MP_ROAD)); return (RoadTileType)GB(_m[t].m5, 6, 2); } /** * Return whether a tile is a normal road. * @param t Tile to query. * @pre IsTileType(t, MP_ROAD) * @return True if normal road. */ static inline bool IsNormalRoad(TileIndex t) { return GetRoadTileType(t) == ROAD_TILE_NORMAL; } /** * Return whether a tile is a normal road tile. * @param t Tile to query. * @return True if normal road tile. */ static inline bool IsNormalRoadTile(TileIndex t) { return IsTileType(t, MP_ROAD) && IsNormalRoad(t); } /** * Return whether a tile is a level crossing. * @param t Tile to query. * @pre IsTileType(t, MP_ROAD) * @return True if level crossing. */ static inline bool IsLevelCrossing(TileIndex t) { return GetRoadTileType(t) == ROAD_TILE_CROSSING; } /** * Return whether a tile is a level crossing tile. * @param t Tile to query. * @return True if level crossing tile. */ static inline bool IsLevelCrossingTile(TileIndex t) { return IsTileType(t, MP_ROAD) && IsLevelCrossing(t); } /** * Return whether a tile is a road depot. * @param t Tile to query. * @pre IsTileType(t, MP_ROAD) * @return True if road depot. */ static inline bool IsRoadDepot(TileIndex t) { return GetRoadTileType(t) == ROAD_TILE_DEPOT; } /** * Return whether a tile is a road depot tile. * @param t Tile to query. * @return True if road depot tile. */ static inline bool IsRoadDepotTile(TileIndex t) { return IsTileType(t, MP_ROAD) && IsRoadDepot(t); } /** * Get the present road bits for a specific road type. * @param t The tile to query. * @param rt Road type. * @pre IsNormalRoad(t) * @return The present road bits for the road type. */ static inline RoadBits GetRoadBits(TileIndex t, RoadType rt) { assert(IsNormalRoad(t)); switch (rt) { default: NOT_REACHED(); case ROADTYPE_ROAD: return (RoadBits)GB(_m[t].m5, 0, 4); case ROADTYPE_TRAM: return (RoadBits)GB(_m[t].m3, 0, 4); } } /** * Get all RoadBits set on a tile except from the given RoadType * * @param t The tile from which we want to get the RoadBits * @param rt The RoadType which we exclude from the querry * @return all set RoadBits of the tile which are not from the given RoadType */ static inline RoadBits GetOtherRoadBits(TileIndex t, RoadType rt) { return GetRoadBits(t, rt == ROADTYPE_ROAD ? ROADTYPE_TRAM : ROADTYPE_ROAD); } /** * Get all set RoadBits on the given tile * * @param tile The tile from which we want to get the RoadBits * @return all set RoadBits of the tile */ static inline RoadBits GetAllRoadBits(TileIndex tile) { return GetRoadBits(tile, ROADTYPE_ROAD) | GetRoadBits(tile, ROADTYPE_TRAM); } /** * Set the present road bits for a specific road type. * @param t The tile to change. * @param r The new road bits. * @param rt Road type. * @pre IsNormalRoad(t) */ static inline void SetRoadBits(TileIndex t, RoadBits r, RoadType rt) { assert(IsNormalRoad(t)); // XXX incomplete switch (rt) { default: NOT_REACHED(); case ROADTYPE_ROAD: SB(_m[t].m5, 0, 4, r); break; case ROADTYPE_TRAM: SB(_m[t].m3, 0, 4, r); break; } } /** * Get the present road types of a tile. * @param t The tile to query. * @return Present road types. */ static inline RoadTypes GetRoadTypes(TileIndex t) { return (RoadTypes)GB(_me[t].m7, 6, 2); } /** * Set the present road types of a tile. * @param t The tile to change. * @param rt The new road types. */ static inline void SetRoadTypes(TileIndex t, RoadTypes rt) { assert(IsTileType(t, MP_ROAD) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)); SB(_me[t].m7, 6, 2, rt); } /** * Check if a tile has a specific road type. * @param t The tile to check. * @param rt Road type to check. * @return True if the tile has the specified road type. */ static inline bool HasTileRoadType(TileIndex t, RoadType rt) { return HasBit(GetRoadTypes(t), rt); } /** * Get the owner of a specific road type. * @param t The tile to query. * @param rt The road type to get the owner of. * @return Owner of the given road type. */ static inline Owner GetRoadOwner(TileIndex t, RoadType rt) { assert(IsTileType(t, MP_ROAD) || IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE)); switch (rt) { default: NOT_REACHED(); case ROADTYPE_ROAD: return (Owner)GB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5); case ROADTYPE_TRAM: { /* Trams don't need OWNER_TOWN, and remapping OWNER_NONE * to OWNER_TOWN makes it use one bit less */ Owner o = (Owner)GB(_m[t].m3, 4, 4); return o == OWNER_TOWN ? OWNER_NONE : o; } } } /** * Set the owner of a specific road type. * @param t The tile to change. * @param rt The road type to change the owner of. * @param o New owner of the given road type. */ static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o) { switch (rt) { default: NOT_REACHED(); case ROADTYPE_ROAD: SB(IsNormalRoadTile(t) ? _m[t].m1 : _me[t].m7, 0, 5, o); break; case ROADTYPE_TRAM: SB(_m[t].m3, 4, 4, o == OWNER_NONE ? OWNER_TOWN : o); break; } } /** * Check if a specific road type is owned by an owner. * @param t The tile to query. * @param rt The road type to compare the owner of. * @param o Owner to compare with. * @pre HasTileRoadType(t, rt) * @return True if the road type is owned by the given owner. */ static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o) { assert(HasTileRoadType(t, rt)); return (GetRoadOwner(t, rt) == o); } /** * Checks if given tile has town owned road * @param t tile to check * @pre IsTileType(t, MP_ROAD) * @return true iff tile has road and the road is owned by a town */ static inline bool HasTownOwnedRoad(TileIndex t) { return HasTileRoadType(t, ROADTYPE_ROAD) && IsRoadOwner(t, ROADTYPE_ROAD, OWNER_TOWN); } /** Which directions are disallowed ? */ enum DisallowedRoadDirections { DRD_NONE, ///< None of the directions are disallowed DRD_SOUTHBOUND, ///< All southbound traffic is disallowed DRD_NORTHBOUND, ///< All northbound traffic is disallowed DRD_BOTH, ///< All directions are disallowed DRD_END, ///< Sentinel }; DECLARE_ENUM_AS_BIT_SET(DisallowedRoadDirections) /** Helper information for extract tool. */ template <> struct EnumPropsT : MakeEnumPropsT {}; /** * Gets the disallowed directions * @param t the tile to get the directions from * @return the disallowed directions */ static inline DisallowedRoadDirections GetDisallowedRoadDirections(TileIndex t) { assert(IsNormalRoad(t)); return (DisallowedRoadDirections)GB(_m[t].m5, 4, 2); } /** * Sets the disallowed directions * @param t the tile to set the directions for * @param drd the disallowed directions */ static inline void SetDisallowedRoadDirections(TileIndex t, DisallowedRoadDirections drd) { assert(IsNormalRoad(t)); assert(drd < DRD_END); SB(_m[t].m5, 4, 2, drd); } /** * Get the road axis of a level crossing. * @param t The tile to query. * @pre IsLevelCrossing(t) * @return The axis of the road. */ static inline Axis GetCrossingRoadAxis(TileIndex t) { assert(IsLevelCrossing(t)); return (Axis)GB(_m[t].m5, 0, 1); } /** * Get the rail axis of a level crossing. * @param t The tile to query. * @pre IsLevelCrossing(t) * @return The axis of the rail. */ static inline Axis GetCrossingRailAxis(TileIndex t) { assert(IsLevelCrossing(t)); return OtherAxis((Axis)GetCrossingRoadAxis(t)); } /** * Get the road bits of a level crossing. * @param tile The tile to query. * @return The present road bits. */ static inline RoadBits GetCrossingRoadBits(TileIndex tile) { return GetCrossingRoadAxis(tile) == AXIS_X ? ROAD_X : ROAD_Y; } /** * Get the rail track of a level crossing. * @param tile The tile to query. * @return The rail track. */ static inline Track GetCrossingRailTrack(TileIndex tile) { return AxisToTrack(GetCrossingRailAxis(tile)); } /** * Get the rail track bits of a level crossing. * @param tile The tile to query. * @return The rail track bits. */ static inline TrackBits GetCrossingRailBits(TileIndex tile) { return AxisToTrackBits(GetCrossingRailAxis(tile)); } /** * Get the reservation state of the rail crossing * @param t the crossing tile * @return reservation state * @pre IsLevelCrossingTile(t) */ static inline bool HasCrossingReservation(TileIndex t) { assert(IsLevelCrossingTile(t)); return HasBit(_m[t].m5, 4); } /** * Set the reservation state of the rail crossing * @note Works for both waypoints and rail depots * @param t the crossing tile * @param b the reservation state * @pre IsLevelCrossingTile(t) */ static inline void SetCrossingReservation(TileIndex t, bool b) { assert(IsLevelCrossingTile(t)); SB(_m[t].m5, 4, 1, b ? 1 : 0); } /** * Get the reserved track bits for a rail crossing * @param t the tile * @pre IsLevelCrossingTile(t) * @return reserved track bits */ static inline TrackBits GetCrossingReservationTrackBits(TileIndex t) { return HasCrossingReservation(t) ? GetCrossingRailBits(t) : TRACK_BIT_NONE; } /** * Check if the level crossing is barred. * @param t The tile to query. * @pre IsLevelCrossing(t) * @return True if the level crossing is barred. */ static inline bool IsCrossingBarred(TileIndex t) { assert(IsLevelCrossing(t)); return HasBit(_m[t].m5, 5); } /** * Set the bar state of a level crossing. * @param t The tile to modify. * @param barred True if the crossing should be barred, false otherwise. * @pre IsLevelCrossing(t) */ static inline void SetCrossingBarred(TileIndex t, bool barred) { assert(IsLevelCrossing(t)); SB(_m[t].m5, 5, 1, barred ? 1 : 0); } /** * Unbar a level crossing. * @param t The tile to change. */ static inline void UnbarCrossing(TileIndex t) { SetCrossingBarred(t, false); } /** * Bar a level crossing. * @param t The tile to change. */ static inline void BarCrossing(TileIndex t) { SetCrossingBarred(t, true); } /** Check if a road tile has snow/desert. */ #define IsOnDesert IsOnSnow /** * Check if a road tile has snow/desert. * @param t The tile to query. * @return True if the tile has snow/desert. */ static inline bool IsOnSnow(TileIndex t) { return HasBit(_me[t].m7, 5); } /** Toggle the snow/desert state of a road tile. */ #define ToggleDesert ToggleSnow /** * Toggle the snow/desert state of a road tile. * @param t The tile to change. */ static inline void ToggleSnow(TileIndex t) { ToggleBit(_me[t].m7, 5); } /** The possible road side decorations. */ enum Roadside { ROADSIDE_BARREN = 0, ///< Road on barren land ROADSIDE_GRASS = 1, ///< Road on grass ROADSIDE_PAVED = 2, ///< Road with paved sidewalks ROADSIDE_STREET_LIGHTS = 3, ///< Road with street lights on paved sidewalks ROADSIDE_TREES = 5, ///< Road with trees on paved sidewalks ROADSIDE_GRASS_ROAD_WORKS = 6, ///< Road on grass with road works ROADSIDE_PAVED_ROAD_WORKS = 7, ///< Road with sidewalks and road works }; /** * Get the decorations of a road. * @param tile The tile to query. * @return The road decoration of the tile. */ static inline Roadside GetRoadside(TileIndex tile) { return (Roadside)GB(_me[tile].m6, 3, 3); } /** * Set the decorations of a road. * @param tile The tile to change. * @param s The new road decoration of the tile. */ static inline void SetRoadside(TileIndex tile, Roadside s) { SB(_me[tile].m6, 3, 3, s); } /** * Check if a tile has road works. * @param t The tile to check. * @return True if the tile has road works in progress. */ static inline bool HasRoadWorks(TileIndex t) { return GetRoadside(t) >= ROADSIDE_GRASS_ROAD_WORKS; } /** * Increase the progress counter of road works. * @param t The tile to modify. * @return True if the road works are in the last stage. */ static inline bool IncreaseRoadWorksCounter(TileIndex t) { AB(_me[t].m7, 0, 4, 1); return GB(_me[t].m7, 0, 4) == 15; } /** * Start road works on a tile. * @param t The tile to start the work on. * @pre !HasRoadWorks(t) */ static inline void StartRoadWorks(TileIndex t) { assert(!HasRoadWorks(t)); /* Remove any trees or lamps in case or roadwork */ switch (GetRoadside(t)) { case ROADSIDE_BARREN: case ROADSIDE_GRASS: SetRoadside(t, ROADSIDE_GRASS_ROAD_WORKS); break; default: SetRoadside(t, ROADSIDE_PAVED_ROAD_WORKS); break; } } /** * Terminate road works on a tile. * @param t Tile to stop the road works on. * @pre HasRoadWorks(t) */ static inline void TerminateRoadWorks(TileIndex t) { assert(HasRoadWorks(t)); SetRoadside(t, (Roadside)(GetRoadside(t) - ROADSIDE_GRASS_ROAD_WORKS + ROADSIDE_GRASS)); /* Stop the counter */ SB(_me[t].m7, 0, 4, 0); } /** * Get the direction of the exit of a road depot. * @param t The tile to query. * @return Diagonal direction of the depot exit. */ static inline DiagDirection GetRoadDepotDirection(TileIndex t) { assert(IsRoadDepot(t)); return (DiagDirection)GB(_m[t].m5, 0, 2); } RoadBits GetAnyRoadBits(TileIndex tile, RoadType rt, bool straight_tunnel_bridge_entrance = false); /** * Make a normal road tile. * @param t Tile to make a normal road. * @param bits Road bits to set for all present road types. * @param rot New present road types. * @param town Town ID if the road is a town-owned road. * @param road New owner of road. * @param tram New owner of tram tracks. */ static inline void MakeRoadNormal(TileIndex t, RoadBits bits, RoadTypes rot, TownID town, Owner road, Owner tram) { SetTileType(t, MP_ROAD); SetTileOwner(t, road); _m[t].m2 = town; _m[t].m3 = (HasBit(rot, ROADTYPE_TRAM) ? bits : 0); _m[t].m4 = 0; _m[t].m5 = (HasBit(rot, ROADTYPE_ROAD) ? bits : 0) | ROAD_TILE_NORMAL << 6; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = rot << 6; SetRoadOwner(t, ROADTYPE_TRAM, tram); } /** * Make a level crossing. * @param t Tile to make a level crossing. * @param road New owner of road. * @param tram New owner of tram tracks. * @param rail New owner of the rail track. * @param roaddir Axis of the road. * @param rat New rail type. * @param rot New present road types. * @param town Town ID if the road is a town-owned road. */ static inline void MakeRoadCrossing(TileIndex t, Owner road, Owner tram, Owner rail, Axis roaddir, RailType rat, RoadTypes rot, uint town) { SetTileType(t, MP_ROAD); SetTileOwner(t, rail); _m[t].m2 = town; _m[t].m3 = rat; _m[t].m4 = 0; _m[t].m5 = ROAD_TILE_CROSSING << 6 | roaddir; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = rot << 6 | road; SetRoadOwner(t, ROADTYPE_TRAM, tram); } /** * Make a road depot. * @param t Tile to make a level crossing. * @param owner New owner of the depot. * @param did New depot ID. * @param dir Direction of the depot exit. * @param rt Road type of the depot. */ static inline void MakeRoadDepot(TileIndex t, Owner owner, DepotID did, DiagDirection dir, RoadType rt) { SetTileType(t, MP_ROAD); SetTileOwner(t, owner); _m[t].m2 = did; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = ROAD_TILE_DEPOT << 6 | dir; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = RoadTypeToRoadTypes(rt) << 6 | owner; SetRoadOwner(t, ROADTYPE_TRAM, owner); } #endif /* ROAD_MAP_H */ openttd-1.5.3/src/road_gui.cpp0000644000000000000000000012507212627373441014777 0ustar rootroot/* $Id: road_gui.cpp 27163 2015-02-22 15:26:27Z frosch $ */ /* * 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 road_gui.cpp GUI for building roads. */ #include "stdafx.h" #include "gui.h" #include "window_gui.h" #include "station_gui.h" #include "terraform_gui.h" #include "viewport_func.h" #include "command_func.h" #include "road_cmd.h" #include "station_func.h" #include "window_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "company_func.h" #include "tunnelbridge.h" #include "tunnelbridge_map.h" #include "tilehighlight_func.h" #include "company_base.h" #include "hotkeys.h" #include "road_gui.h" #include "zoom_func.h" #include "widgets/road_widget.h" #include "table/strings.h" #include "safeguards.h" static void ShowRVStationPicker(Window *parent, RoadStopType rs); static void ShowRoadDepotPicker(Window *parent); static bool _remove_button_clicked; static bool _one_way_button_clicked; /** * Define the values of the RoadFlags * @see CmdBuildLongRoad */ enum RoadFlags { RF_NONE = 0x00, RF_START_HALFROAD_Y = 0x01, // The start tile in Y-dir should have only a half road RF_END_HALFROAD_Y = 0x02, // The end tile in Y-dir should have only a half road RF_DIR_Y = 0x04, // The direction is Y-dir RF_DIR_X = RF_NONE, // Dummy; Dir X is set when RF_DIR_Y is not set RF_START_HALFROAD_X = 0x08, // The start tile in X-dir should have only a half road RF_END_HALFROAD_X = 0x10, // The end tile in X-dir should have only a half road }; DECLARE_ENUM_AS_BIT_SET(RoadFlags) static RoadFlags _place_road_flag; static RoadType _cur_roadtype; static DiagDirection _road_depot_orientation; static DiagDirection _road_station_picker_orientation; void CcPlaySound1D(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); } /** * Callback to start placing a bridge. * @param tile Start tile of the bridge. */ static void PlaceRoad_Bridge(TileIndex tile, Window *w) { if (IsBridgeTile(tile)) { TileIndex other_tile = GetOtherTunnelBridgeEnd(tile); Point pt = {0, 0}; w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile); } else { VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE); } } /** * Callback executed after a build road tunnel command has been called. * * @param result Whether the build succeeded. * @param start_tile Starting tile of the tunnel. * @param p1 bit 0-3 railtype or roadtypes * bit 8-9 transport type * @param p2 unused */ void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p1, uint32 p2) { if (result.Succeeded()) { if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, start_tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(start_tile)); ConnectRoadToStructure(start_tile, start_direction); TileIndex end_tile = GetOtherTunnelBridgeEnd(start_tile); DiagDirection end_direction = ReverseDiagDir(GetTunnelBridgeDirection(end_tile)); ConnectRoadToStructure(end_tile, end_direction); } else { SetRedErrorSquare(_build_tunnel_endtile); } } /** Structure holding information per roadtype for several functions */ struct RoadTypeInfo { StringID err_build_road; ///< Building a normal piece of road StringID err_remove_road; ///< Removing a normal piece of road StringID err_depot; ///< Building a depot StringID err_build_station[2]; ///< Building a bus or truck station StringID err_remove_station[2]; ///< Removing of a bus or truck station StringID picker_title[2]; ///< Title for the station picker for bus or truck stations StringID picker_tooltip[2]; ///< Tooltip for the station picker for bus or truck stations SpriteID cursor_nesw; ///< Cursor for building NE and SW bits SpriteID cursor_nwse; ///< Cursor for building NW and SE bits SpriteID cursor_autoroad; ///< Cursor for building autoroad }; /** What errors/cursors must be shown for several types of roads */ static const RoadTypeInfo _road_type_infos[] = { { STR_ERROR_CAN_T_BUILD_ROAD_HERE, STR_ERROR_CAN_T_REMOVE_ROAD_FROM, STR_ERROR_CAN_T_BUILD_ROAD_DEPOT, { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION }, { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION }, { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION }, { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP }, SPR_CURSOR_ROAD_NESW, SPR_CURSOR_ROAD_NWSE, SPR_CURSOR_AUTOROAD, }, { STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE, STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM, STR_ERROR_CAN_T_BUILD_TRAM_DEPOT, { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION }, { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION }, { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION }, { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP }, SPR_CURSOR_TRAMWAY_NESW, SPR_CURSOR_TRAMWAY_NWSE, SPR_CURSOR_AUTOTRAM, }, }; /** * If required, connects a new structure to an existing road or tram by building the missing roadbit. * @param tile Tile containing the structure to connect. * @param direction Direction to check. */ void ConnectRoadToStructure(TileIndex tile, DiagDirection direction) { tile += TileOffsByDiagDir(direction); /* if there is a roadpiece just outside of the station entrance, build a connecting route */ if (IsNormalRoadTile(tile)) { if (GetRoadBits(tile, _cur_roadtype) != ROAD_NONE) { DoCommandP(tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0, CMD_BUILD_ROAD); } } } void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; DiagDirection dir = (DiagDirection)GB(p1, 0, 2); if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); ConnectRoadToStructure(tile, dir); } /** * Command callback for building road stops. * @param result Result of the build road stop command. * @param tile Start tile. * @param p1 bit 0..7: Width of the road stop. * bit 8..15: Length of the road stop. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * bit 1: 0 For normal stops, 1 for drive-through. * bit 2..3: The roadtypes. * bit 5: Allow stations directly adjacent to other stations. * bit 6..7: Entrance direction (#DiagDirection). * bit 16..31: Station ID to join (NEW_STATION if build new one). * @see CmdBuildRoadStop */ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; DiagDirection dir = (DiagDirection)GB(p2, 6, 2); if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); TileArea roadstop_area(tile, GB(p1, 0, 8), GB(p1, 8, 8)); TILE_AREA_LOOP(cur_tile, roadstop_area) { ConnectRoadToStructure(cur_tile, dir); /* For a drive-through road stop build connecting road for other entrance. */ if (HasBit(p2, 1)) ConnectRoadToStructure(cur_tile, ReverseDiagDir(dir)); } } /** * Place a new road stop. * @param start_tile First tile of the area. * @param end_tile Last tile of the area. * @param p2 bit 0: 0 For bus stops, 1 for truck stops. * bit 2..3: The roadtypes. * bit 5: Allow stations directly adjacent to other stations. * @param cmd Command to use. * @see CcRoadStop() */ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, uint32 cmd) { uint8 ddir = _road_station_picker_orientation; SB(p2, 16, 16, INVALID_STATION); // no station to join if (ddir >= DIAGDIR_END) { SetBit(p2, 1); // It's a drive-through stop. ddir -= DIAGDIR_END; // Adjust picker result to actual direction. } p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7. TileArea ta(start_tile, end_tile); CommandContainer cmdcont = { ta.tile, ta.w | ta.h << 8, p2, cmd, CcRoadStop, "" }; ShowSelectStationIfNeeded(cmdcont, ta); } /** * Callback for placing a bus station. * @param tile Position to place the station. */ static void PlaceRoad_BusStation(TileIndex tile) { if (_remove_button_clicked) { VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP); } else { if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop. VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP); } else { VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP); } VpSetPlaceSizingLimit(_settings_game.station.station_spread); } } /** * Callback for placing a truck station. * @param tile Position to place the station. */ static void PlaceRoad_TruckStation(TileIndex tile) { if (_remove_button_clicked) { VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP); } else { if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop. VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP); } else { VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP); } VpSetPlaceSizingLimit(_settings_game.station.station_spread); } } typedef void OnButtonClick(Window *w); /** * Toggles state of the Remove button of Build road toolbar * @param w window the button belongs to */ static void ToggleRoadButton_Remove(Window *w) { w->ToggleWidgetLoweredState(WID_ROT_REMOVE); w->SetWidgetDirty(WID_ROT_REMOVE); _remove_button_clicked = w->IsWidgetLowered(WID_ROT_REMOVE); SetSelectionRed(_remove_button_clicked); } /** * Updates the Remove button because of Ctrl state change * @param w window the button belongs to * @return true iff the remove button was changed */ static bool RoadToolbar_CtrlChanged(Window *w) { if (w->IsWidgetDisabled(WID_ROT_REMOVE)) return false; /* allow ctrl to switch remove mode only for these widgets */ for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_AUTOROAD; i++) { if (w->IsWidgetLowered(i)) { ToggleRoadButton_Remove(w); return true; } } return false; } /** Road toolbar window handler. */ struct BuildRoadToolbarWindow : Window { int last_started_action; ///< Last started user action. BuildRoadToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); this->SetWidgetsDisabledState(true, WID_ROT_REMOVE, WID_ROT_ONE_WAY, WIDGET_LIST_END); this->OnInvalidateData(); this->last_started_action = WIDGET_LIST_END; if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); } ~BuildRoadToolbarWindow() { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } /** * 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; bool can_build = CanBuildVehicleInfrastructure(VEH_ROAD); this->SetWidgetsDisabledState(!can_build, WID_ROT_DEPOT, WID_ROT_BUS_STATION, WID_ROT_TRUCK_STATION, WIDGET_LIST_END); if (!can_build) { DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD); DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD); DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD); } } /** * Update the remove button lowered state of the road toolbar * * @param clicked_widget The widget which the client clicked just now */ void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget) { /* The remove and the one way button state is driven * by the other buttons so they don't act on themselves. * Both are only valid if they are able to apply as options. */ switch (clicked_widget) { case WID_ROT_REMOVE: this->RaiseWidget(WID_ROT_ONE_WAY); this->SetWidgetDirty(WID_ROT_ONE_WAY); break; case WID_ROT_ONE_WAY: this->RaiseWidget(WID_ROT_REMOVE); this->SetWidgetDirty(WID_ROT_REMOVE); break; case WID_ROT_BUS_STATION: case WID_ROT_TRUCK_STATION: this->DisableWidget(WID_ROT_ONE_WAY); this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget)); break; case WID_ROT_ROAD_X: case WID_ROT_ROAD_Y: case WID_ROT_AUTOROAD: this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget), WID_ROT_REMOVE, WID_ROT_ONE_WAY, WIDGET_LIST_END); break; default: /* When any other buttons than road/station, raise and * disable the removal button */ this->SetWidgetsDisabledState(true, WID_ROT_REMOVE, WID_ROT_ONE_WAY, WIDGET_LIST_END); this->SetWidgetsLoweredState(false, WID_ROT_REMOVE, WID_ROT_ONE_WAY, WIDGET_LIST_END); break; } } virtual void OnClick(Point pt, int widget, int click_count) { _remove_button_clicked = false; _one_way_button_clicked = false; switch (widget) { case WID_ROT_ROAD_X: HandlePlacePushButton(this, WID_ROT_ROAD_X, _road_type_infos[_cur_roadtype].cursor_nwse, HT_RECT); this->last_started_action = widget; break; case WID_ROT_ROAD_Y: HandlePlacePushButton(this, WID_ROT_ROAD_Y, _road_type_infos[_cur_roadtype].cursor_nesw, HT_RECT); this->last_started_action = widget; break; case WID_ROT_AUTOROAD: HandlePlacePushButton(this, WID_ROT_AUTOROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT); this->last_started_action = widget; break; case WID_ROT_DEMOLISH: HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_started_action = widget; break; case WID_ROT_DEPOT: if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) { ShowRoadDepotPicker(this); this->last_started_action = widget; } break; case WID_ROT_BUS_STATION: if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) { ShowRVStationPicker(this, ROADSTOP_BUS); this->last_started_action = widget; } break; case WID_ROT_TRUCK_STATION: if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return; if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) { ShowRVStationPicker(this, ROADSTOP_TRUCK); this->last_started_action = widget; } break; case WID_ROT_ONE_WAY: if (this->IsWidgetDisabled(WID_ROT_ONE_WAY)) return; this->SetDirty(); this->ToggleWidgetLoweredState(WID_ROT_ONE_WAY); SetSelectionRed(false); break; case WID_ROT_BUILD_BRIDGE: HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT); this->last_started_action = widget; break; case WID_ROT_BUILD_TUNNEL: HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, HT_SPECIAL); this->last_started_action = widget; break; case WID_ROT_REMOVE: if (this->IsWidgetDisabled(WID_ROT_REMOVE)) return; DeleteWindowById(WC_SELECT_STATION, 0); ToggleRoadButton_Remove(this); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); break; default: NOT_REACHED(); } this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget); if (_ctrl_pressed) RoadToolbar_CtrlChanged(this); } virtual EventState OnHotkey(int hotkey) { MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection return Window::OnHotkey(hotkey); } virtual void OnPlaceObject(Point pt, TileIndex tile) { _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); switch (this->last_started_action) { case WID_ROT_ROAD_X: _place_road_flag = RF_DIR_X; if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X; VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_ROAD_X_DIR); break; case WID_ROT_ROAD_Y: _place_road_flag = RF_DIR_Y; if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y; VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_ROAD_Y_DIR); break; case WID_ROT_AUTOROAD: _place_road_flag = RF_NONE; if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X; if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y; VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD); break; case WID_ROT_DEMOLISH: PlaceProc_DemolishArea(tile); break; case WID_ROT_DEPOT: DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0, CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); break; case WID_ROT_BUS_STATION: PlaceRoad_BusStation(tile); break; case WID_ROT_TRUCK_STATION: PlaceRoad_TruckStation(tile); break; case WID_ROT_BUILD_BRIDGE: PlaceRoad_Bridge(tile, this); break; case WID_ROT_BUILD_TUNNEL: DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel); break; default: NOT_REACHED(); } } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); this->SetWidgetsDisabledState(true, WID_ROT_REMOVE, WID_ROT_ONE_WAY, WIDGET_LIST_END); this->SetWidgetDirty(WID_ROT_REMOVE); this->SetWidgetDirty(WID_ROT_ONE_WAY); DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD); DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD); DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); } virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) { /* Here we update the end tile flags * of the road placement actions. * At first we reset the end halfroad * bits and if needed we set them again. */ switch (select_proc) { case DDSP_PLACE_ROAD_X_DIR: _place_road_flag &= ~RF_END_HALFROAD_X; if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X; break; case DDSP_PLACE_ROAD_Y_DIR: _place_road_flag &= ~RF_END_HALFROAD_Y; if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y; break; case DDSP_PLACE_AUTOROAD: _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X); if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y; if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X; /* For autoroad we need to update the * direction of the road */ if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y && ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) || (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) { /* Set dir = X */ _place_road_flag &= ~RF_DIR_Y; } else { /* Set dir = Y */ _place_road_flag |= RF_DIR_Y; } break; default: break; } 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) { default: NOT_REACHED(); case DDSP_BUILD_BRIDGE: if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype)); break; case DDSP_DEMOLISH_AREA: GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; case DDSP_PLACE_ROAD_X_DIR: case DDSP_PLACE_ROAD_Y_DIR: case DDSP_PLACE_AUTOROAD: /* Flag description: * Use the first three bits (0x07) if dir == Y * else use the last 2 bits (X dir has * not the 3rd bit set) */ _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3)); DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), _remove_button_clicked ? CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) : CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D); break; case DDSP_BUILD_BUSSTOP: PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS])); break; case DDSP_BUILD_TRUCKSTOP: PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_TRUCK])); break; case DDSP_REMOVE_BUSSTOP: { TileArea ta(start_tile, end_tile); DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D); break; } case DDSP_REMOVE_TRUCKSTOP: { TileArea ta(start_tile, end_tile); DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D); break; } } } } virtual void OnPlacePresize(Point pt, TileIndex tile) { DoCommand(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL); VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile); } virtual EventState OnCTRLStateChange() { if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED; return ES_NOT_HANDLED; } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the BuildRoadToolbarWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState RoadToolbarGlobalHotkeys(int hotkey) { Window *w = NULL; switch (_game_mode) { case GM_NORMAL: { extern RoadType _last_built_roadtype; w = ShowBuildRoadToolbar(_last_built_roadtype); break; } case GM_EDITOR: w = ShowBuildRoadScenToolbar(); break; default: break; } if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } static Hotkey roadtoolbar_hotkeys[] = { Hotkey('1', "build_x", WID_ROT_ROAD_X), Hotkey('2', "build_y", WID_ROT_ROAD_Y), Hotkey('3', "autoroad", WID_ROT_AUTOROAD), Hotkey('4', "demolish", WID_ROT_DEMOLISH), Hotkey('5', "depot", WID_ROT_DEPOT), Hotkey('6', "bus_station", WID_ROT_BUS_STATION), Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION), Hotkey('8', "oneway", WID_ROT_ONE_WAY), Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE), Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL), Hotkey('R', "remove", WID_ROT_REMOVE), HOTKEY_LIST_END }; HotkeyList BuildRoadToolbarWindow::hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys); static const NWidgetPart _nested_build_road_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), EndContainer(), }; static WindowDesc _build_road_desc( WDP_ALIGN_TOOLBAR, "toolbar_road", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_road_widgets, lengthof(_nested_build_road_widgets), &BuildRoadToolbarWindow::hotkeys ); static const NWidgetPart _nested_build_tramway_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetMinimalSize(0, 0), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS), EndContainer(), }; static WindowDesc _build_tramway_desc( WDP_ALIGN_TOOLBAR, "toolbar_tramway", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_tramway_widgets, lengthof(_nested_build_tramway_widgets), &BuildRoadToolbarWindow::hotkeys ); /** * Open the build road toolbar window * * If the terraform toolbar is linked to the toolbar, that window is also opened. * * @return newly opened road toolbar, or NULL if the toolbar could not be opened. */ Window *ShowBuildRoadToolbar(RoadType roadtype) { if (!Company::IsValidID(_local_company)) return NULL; _cur_roadtype = roadtype; DeleteWindowByClass(WC_BUILD_TOOLBAR); return AllocateWindowDescFront(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD); } static const NWidgetPart _nested_build_road_scen_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE), SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD), EndContainer(), }; static WindowDesc _build_road_scen_desc( WDP_AUTO, "toolbar_road_scen", 0, 0, WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets), &BuildRoadToolbarWindow::hotkeys ); /** * Show the road building toolbar in the scenario editor. * @return The just opened toolbar, or \c NULL if the toolbar was already open. */ Window *ShowBuildRoadScenToolbar() { _cur_roadtype = ROADTYPE_ROAD; return AllocateWindowDescFront(&_build_road_scen_desc, TRANSPORT_ROAD); } struct BuildRoadDepotWindow : public PickerWindowBase { BuildRoadDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->CreateNestedTree(); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); if ( _cur_roadtype == ROADTYPE_TRAM) { this->GetWidget(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION; for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; } this->FinishInitNested(TRANSPORT_ROAD); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return; size->width = ScaleGUITrad(64) + 2; size->height = ScaleGUITrad(48) + 2; } virtual void DrawWidget(const Rect &r, int widget) const { if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return; DrawRoadDepotSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), (DiagDirection)(widget - WID_BROD_DEPOT_NE + DIAGDIR_NE), _cur_roadtype); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BROD_DEPOT_NW: case WID_BROD_DEPOT_NE: case WID_BROD_DEPOT_SW: case WID_BROD_DEPOT_SE: this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); break; default: break; } } }; static const NWidgetPart _nested_build_road_depot_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(NWID_HORIZONTAL_LTR), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), EndContainer(), }; static WindowDesc _build_road_depot_desc( WDP_AUTO, NULL, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_road_depot_widgets, lengthof(_nested_build_road_depot_widgets) ); static void ShowRoadDepotPicker(Window *parent) { new BuildRoadDepotWindow(&_build_road_depot_desc, parent); } struct BuildRoadStationWindow : public PickerWindowBase { BuildRoadStationWindow(WindowDesc *desc, Window *parent, RoadStopType rs) : PickerWindowBase(desc, parent) { this->CreateNestedTree(); /* Trams don't have non-drivethrough stations */ if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) { _road_station_picker_orientation = DIAGDIR_END; } this->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM, WID_BROS_STATION_NE, WID_BROS_STATION_SE, WID_BROS_STATION_SW, WID_BROS_STATION_NW, WIDGET_LIST_END); this->GetWidget(WID_BROS_CAPTION)->widget_data = _road_type_infos[_cur_roadtype].picker_title[rs]; for (uint i = WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) this->GetWidget(i)->tool_tip = _road_type_infos[_cur_roadtype].picker_tooltip[rs]; this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); this->FinishInitNested(TRANSPORT_ROAD); this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION; } virtual ~BuildRoadStationWindow() { DeleteWindowById(WC_SELECT_STATION, 0); } virtual void OnPaint() { this->DrawWidgets(); int rad = _settings_game.station.modified_catchment ? ((this->window_class == WC_BUS_STATION) ? CA_BUS : CA_TRUCK) : CA_UNMODIFIED; if (_settings_client.gui.station_show_coverage) { SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); } else { SetTileSelectSize(1, 1); } /* 'Accepts' and 'Supplies' texts. */ StationCoverageType sct = (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY; int top = this->GetWidget(WID_BROS_LT_ON)->pos_y + this->GetWidget(WID_BROS_LT_ON)->current_y + WD_PAR_VSEP_NORMAL; NWidgetBase *back_nwi = this->GetWidget(WID_BROS_BACKGROUND); int right = back_nwi->pos_x + back_nwi->current_x; int bottom = back_nwi->pos_y + back_nwi->current_y; top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, false) + WD_PAR_VSEP_NORMAL; top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, true) + WD_PAR_VSEP_NORMAL; /* Resize background if the window is too small. * Never make the window smaller to avoid oscillating if the size change affects the acceptance. * (This is the case, if making the window bigger moves the mouse into the window.) */ if (top > bottom) { ResizeWindow(this, 0, top - bottom); } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return; size->width = ScaleGUITrad(64) + 2; size->height = ScaleGUITrad(48) + 2; } virtual void DrawWidget(const Rect &r, int widget) const { if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return; StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK; StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BROS_STATION_NE: case WID_BROS_STATION_SE: case WID_BROS_STATION_SW: case WID_BROS_STATION_NW: case WID_BROS_STATION_X: case WID_BROS_STATION_Y: this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); _road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE); this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); DeleteWindowById(WC_SELECT_STATION, 0); break; case WID_BROS_LT_OFF: case WID_BROS_LT_ON: this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); _settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF); this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); break; default: break; } } virtual void OnTick() { CheckRedrawStationCoverage(this); } }; /** Widget definition of the build road station window */ static const NWidgetPart _nested_rv_station_picker_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND), NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetMinimalSize(66, 50), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetMinimalSize(66, 50), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), EndContainer(), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetMinimalSize(66, 50), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetMinimalSize(66, 50), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), EndContainer(), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12), SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12), SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), EndContainer(), }; static WindowDesc _rv_station_picker_desc( WDP_AUTO, NULL, 0, 0, WC_BUS_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_rv_station_picker_widgets, lengthof(_nested_rv_station_picker_widgets) ); static void ShowRVStationPicker(Window *parent, RoadStopType rs) { new BuildRoadStationWindow(&_rv_station_picker_desc, parent, rs); } void InitializeRoadGui() { _road_depot_orientation = DIAGDIR_NW; _road_station_picker_orientation = DIAGDIR_NW; } openttd-1.5.3/src/misc.cpp0000644000000000000000000000604512627373442014140 0ustar rootroot/* $Id: misc.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 misc.cpp Misc functions that shouldn't be here. */ #include "stdafx.h" #include "landscape.h" #include "news_func.h" #include "ai/ai.hpp" #include "ai/ai_gui.hpp" #include "newgrf.h" #include "newgrf_house.h" #include "economy_func.h" #include "date_func.h" #include "texteff.hpp" #include "gfx_func.h" #include "gamelog.h" #include "animated_tile_func.h" #include "tilehighlight_func.h" #include "network/network_func.h" #include "window_func.h" #include "core/pool_type.hpp" #include "game/game.hpp" #include "linkgraph/linkgraphschedule.h" #include "safeguards.h" extern TileIndex _cur_tileloop_tile; extern void MakeNewgameSettingsLive(); void InitializeSound(); void InitializeMusic(); void InitializeVehicles(); void InitializeRailGui(); void InitializeRoadGui(); void InitializeAirportGui(); void InitializeDockGui(); void InitializeObjectGui(); void InitializeIndustries(); void InitializeObjects(); void InitializeTrees(); void InitializeCompanies(); void InitializeCheats(); void InitializeNPF(); void InitializeOldNames(); void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings) { /* Make sure there isn't any window that can influence anything * related to the new game we're about to start/load. */ UnInitWindowSystem(); AllocateMap(size_x, size_y); _pause_mode = PM_UNPAUSED; _fast_forward = 0; _tick_counter = 0; _cur_tileloop_tile = 1; _thd.redsq = INVALID_TILE; if (reset_settings) MakeNewgameSettingsLive(); if (reset_date) { SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0); InitializeOldNames(); } LinkGraphSchedule::Clear(); PoolBase::Clean(PT_NORMAL); ResetPersistentNewGRFData(); InitializeSound(); InitializeMusic(); InitializeVehicles(); InitNewsItemStructs(); InitializeLandscape(); InitializeRailGui(); InitializeRoadGui(); InitializeAirportGui(); InitializeDockGui(); InitializeObjectGui(); InitializeAIGui(); InitializeTrees(); InitializeIndustries(); InitializeObjects(); InitializeBuildingCounts(); InitializeNPF(); InitializeCompanies(); AI::Initialize(); Game::Initialize(); InitializeCheats(); InitTextEffects(); #ifdef ENABLE_NETWORK NetworkInitChatMessage(); #endif /* ENABLE_NETWORK */ InitializeAnimatedTiles(); InitializeEconomy(); ResetObjectToPlace(); GamelogReset(); GamelogStartAction(GLAT_START); GamelogRevision(); GamelogMode(); GamelogGRFAddList(_grfconfig); GamelogStopAction(); } openttd-1.5.3/src/vehicle.cpp0000644000000000000000000027436712627373435014644 0ustar rootroot/* $Id: vehicle.cpp 27270 2015-05-08 17:23:55Z frosch $ */ /* * 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 vehicle.cpp Base implementations of all vehicles. */ #include "stdafx.h" #include "error.h" #include "roadveh.h" #include "ship.h" #include "spritecache.h" #include "timetable.h" #include "viewport_func.h" #include "news_func.h" #include "command_func.h" #include "company_func.h" #include "train.h" #include "aircraft.h" #include "newgrf_debug.h" #include "newgrf_sound.h" #include "newgrf_station.h" #include "group_gui.h" #include "strings_func.h" #include "zoom_func.h" #include "date_func.h" #include "vehicle_func.h" #include "autoreplace_func.h" #include "autoreplace_gui.h" #include "station_base.h" #include "ai/ai.hpp" #include "depot_func.h" #include "network/network.h" #include "core/pool_func.hpp" #include "economy_base.h" #include "articulated_vehicles.h" #include "roadstop_base.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "order_backup.h" #include "sound_func.h" #include "effectvehicle_func.h" #include "effectvehicle_base.h" #include "vehiclelist.h" #include "bridge_map.h" #include "tunnel_map.h" #include "depot_map.h" #include "gamelog.h" #include "linkgraph/linkgraph.h" #include "linkgraph/refresh.h" #include "table/strings.h" #include "safeguards.h" #define GEN_HASH(x, y) ((GB((y), 6 + ZOOM_LVL_SHIFT, 6) << 6) + GB((x), 7 + ZOOM_LVL_SHIFT, 6)) VehicleID _new_vehicle_id; uint16 _returned_refit_capacity; ///< Stores the capacity after a refit operation. uint16 _returned_mail_refit_capacity; ///< Stores the mail capacity after a refit operation (Aircraft only). /** The pool with all our precious vehicles. */ VehiclePool _vehicle_pool("Vehicle"); INSTANTIATE_POOL_METHODS(Vehicle) /** * Function to tell if a vehicle needs to be autorenewed * @param *c The vehicle owner * @param use_renew_setting Should the company renew setting be considered? * @return true if the vehicle is old enough for replacement */ bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const { /* We can always generate the Company pointer when we have the vehicle. * However this takes time and since the Company pointer is often present * when this function is called then it's faster to pass the pointer as an * argument rather than finding it again. */ assert(c == Company::Get(this->owner)); if (use_renew_setting && !c->settings.engine_renew) return false; if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false; /* Only engines need renewing */ if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false; return true; } /** * Service a vehicle and all subsequent vehicles in the consist * * @param *v The vehicle or vehicle chain being serviced */ void VehicleServiceInDepot(Vehicle *v) { assert(v != NULL); SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated do { v->date_of_last_service = _date; v->breakdowns_since_last_service = 0; v->reliability = v->GetEngine()->reliability; /* Prevent vehicles from breaking down directly after exiting the depot. */ v->breakdown_chance /= 4; v = v->Next(); } while (v != NULL && v->HasEngineType()); } /** * Check if the vehicle needs to go to a depot in near future (if a opportunity presents itself) for service or replacement. * * @see NeedsAutomaticServicing() * @return true if the vehicle should go to a depot if a opportunity presents itself. */ bool Vehicle::NeedsServicing() const { /* Stopped or crashed vehicles will not move, as such making unmovable * vehicles to go for service is lame. */ if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false; /* Are we ready for the next service cycle? */ const Company *c = Company::Get(this->owner); if (this->ServiceIntervalIsPercent() ? (this->reliability >= this->GetEngine()->reliability * (100 - this->GetServiceInterval()) / 100) : (this->date_of_last_service + this->GetServiceInterval() >= _date)) { return false; } /* If we're servicing anyway, because we have not disabled servicing when * there are no breakdowns or we are playing with breakdowns, bail out. */ if (!_settings_game.order.no_servicing_if_no_breakdowns || _settings_game.difficulty.vehicle_breakdowns != 0) { return true; } /* Test whether there is some pending autoreplace. * Note: We do this after the service-interval test. * There are a lot more reasons for autoreplace to fail than we can test here reasonably. */ bool pending_replace = false; Money needed_money = c->settings.engine_renew_money; if (needed_money > c->money) return false; for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) { bool replace_when_old = false; EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old); /* Check engine availability */ if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue; /* Is the vehicle old if we are not always replacing? */ if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue; /* Check refittability */ uint32 available_cargo_types, union_mask; GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types); /* Is there anything to refit? */ if (union_mask != 0) { CargoID cargo_type; /* We cannot refit to mixed cargoes in an automated way */ if (IsArticulatedVehicleCarryingDifferentCargoes(v, &cargo_type)) continue; /* Did the old vehicle carry anything? */ if (cargo_type != CT_INVALID) { /* We can't refit the vehicle to carry the cargo we want */ if (!HasBit(available_cargo_types, cargo_type)) continue; } } /* Check money. * We want 2*(the price of the new vehicle) without looking at the value of the vehicle we are going to sell. */ pending_replace = true; needed_money += 2 * Engine::Get(new_engine)->GetCost(); if (needed_money > c->money) return false; } return pending_replace; } /** * Checks if the current order should be interrupted for a service-in-depot order. * @see NeedsServicing() * @return true if the current order should be interrupted. */ bool Vehicle::NeedsAutomaticServicing() const { if (this->HasDepotOrder()) return false; if (this->current_order.IsType(OT_LOADING)) return false; if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotOrderType() != ODTFB_SERVICE) return false; return NeedsServicing(); } uint Vehicle::Crash(bool flooded) { assert((this->vehstatus & VS_CRASHED) == 0); assert(this->Previous() == NULL); // IsPrimaryVehicle fails for free-wagon-chains uint pass = 0; /* Stop the vehicle. */ if (this->IsPrimaryVehicle()) this->vehstatus |= VS_STOPPED; /* crash all wagons, and count passengers */ for (Vehicle *v = this; v != NULL; v = v->Next()) { /* We do not transfer reserver cargo back, so TotalCount() instead of StoredCount() */ if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.TotalCount(); v->vehstatus |= VS_CRASHED; v->MarkAllViewportsDirty(); } /* Dirty some windows */ InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); SetWindowDirty(WC_VEHICLE_DEPOT, this->tile); delete this->cargo_payment; this->cargo_payment = NULL; return RandomRange(pass + 1); // Randomise deceased passengers. } /** * Displays a "NewGrf Bug" error message for a engine, and pauses the game if not networking. * @param engine The engine that caused the problem * @param part1 Part 1 of the error message, taking the grfname as parameter 1 * @param part2 Part 2 of the error message, taking the engine as parameter 2 * @param bug_type Flag to check and set in grfconfig * @param critical Shall the "OpenTTD might crash"-message be shown when the player tries to unpause? */ void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical) { const Engine *e = Engine::Get(engine); GRFConfig *grfconfig = GetGRFConfig(e->GetGRFID()); /* Missing GRF. Nothing useful can be done in this situation. */ if (grfconfig == NULL) return; if (!HasBit(grfconfig->grf_bugs, bug_type)) { SetBit(grfconfig->grf_bugs, bug_type); SetDParamStr(0, grfconfig->GetName()); SetDParam(1, engine); ShowErrorMessage(part1, part2, WL_CRITICAL); if (!_networking) DoCommand(0, critical ? PM_PAUSED_ERROR : PM_PAUSED_NORMAL, 1, DC_EXEC, CMD_PAUSE); } /* debug output */ char buffer[512]; SetDParamStr(0, grfconfig->GetName()); GetString(buffer, part1, lastof(buffer)); DEBUG(grf, 0, "%s", buffer + 3); SetDParam(1, engine); GetString(buffer, part2, lastof(buffer)); DEBUG(grf, 0, "%s", buffer + 3); } /** * Logs a bug in GRF and shows a warning message if this * is for the first time this happened. * @param u first vehicle of chain */ void VehicleLengthChanged(const Vehicle *u) { /* show a warning once for each engine in whole game and once for each GRF after each game load */ const Engine *engine = u->GetEngine(); uint32 grfid = engine->grf_prop.grffile->grfid; GRFConfig *grfconfig = GetGRFConfig(grfid); if (GamelogGRFBugReverse(grfid, engine->grf_prop.local_id) || !HasBit(grfconfig->grf_bugs, GBUG_VEH_LENGTH)) { ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_VEHICLE_LENGTH, GBUG_VEH_LENGTH, true); } } /** * Vehicle constructor. * @param type Type of the new vehicle. */ Vehicle::Vehicle(VehicleType type) { this->type = type; this->coord.left = INVALID_COORD; this->group_id = DEFAULT_GROUP; this->fill_percent_te_id = INVALID_TE_ID; this->first = this; this->colourmap = PAL_NONE; this->cargo_age_counter = 1; this->last_station_visited = INVALID_STATION; this->last_loading_station = INVALID_STATION; } /** * Get a value for a vehicle's random_bits. * @return A random value from 0 to 255. */ byte VehicleRandomBits() { return GB(Random(), 0, 8); } /* Size of the hash, 6 = 64 x 64, 7 = 128 x 128. Larger sizes will (in theory) reduce hash * lookup times at the expense of memory usage. */ const int HASH_BITS = 7; const int HASH_SIZE = 1 << HASH_BITS; const int HASH_MASK = HASH_SIZE - 1; const int TOTAL_HASH_SIZE = 1 << (HASH_BITS * 2); const int TOTAL_HASH_MASK = TOTAL_HASH_SIZE - 1; /* Resolution of the hash, 0 = 1*1 tile, 1 = 2*2 tiles, 2 = 4*4 tiles, etc. * Profiling results show that 0 is fastest. */ const int HASH_RES = 0; static Vehicle *_vehicle_tile_hash[TOTAL_HASH_SIZE]; static Vehicle *VehicleFromTileHash(int xl, int yl, int xu, int yu, void *data, VehicleFromPosProc *proc, bool find_first) { for (int y = yl; ; y = (y + (1 << HASH_BITS)) & (HASH_MASK << HASH_BITS)) { for (int x = xl; ; x = (x + 1) & HASH_MASK) { Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; for (; v != NULL; v = v->hash_tile_next) { Vehicle *a = proc(v, data); if (find_first && a != NULL) return a; } if (x == xu) break; } if (y == yu) break; } return NULL; } /** * Helper function for FindVehicleOnPos/HasVehicleOnPos. * @note Do not call this function directly! * @param x The X location on the map * @param y The Y location on the map * @param data Arbitrary data passed to proc * @param proc The proc that determines whether a vehicle will be "found". * @param find_first Whether to return on the first found or iterate over * all vehicles * @return the best matching or first vehicle (depending on find_first). */ static Vehicle *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc, bool find_first) { const int COLL_DIST = 6; /* Hash area to scan is from xl,yl to xu,yu */ int xl = GB((x - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS); int xu = GB((x + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS); int yl = GB((y - COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS; int yu = GB((y + COLL_DIST) / TILE_SIZE, HASH_RES, HASH_BITS) << HASH_BITS; return VehicleFromTileHash(xl, yl, xu, yu, data, proc, find_first); } /** * Find a vehicle from a specific location. It will call proc for ALL vehicles * on the tile and YOU must make SURE that the "best one" is stored in the * data value and is ALWAYS the same regardless of the order of the vehicles * where proc was called on! * When you fail to do this properly you create an almost untraceable DESYNC! * @note The return value of proc will be ignored. * @note Use this when you have the intention that all vehicles * should be iterated over. * @param x The X location on the map * @param y The Y location on the map * @param data Arbitrary data passed to proc * @param proc The proc that determines whether a vehicle will be "found". */ void FindVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc) { VehicleFromPosXY(x, y, data, proc, false); } /** * Checks whether a vehicle in on a specific location. It will call proc for * vehicles until it returns non-NULL. * @note Use FindVehicleOnPosXY when you have the intention that all vehicles * should be iterated over. * @param x The X location on the map * @param y The Y location on the map * @param data Arbitrary data passed to proc * @param proc The proc that determines whether a vehicle will be "found". * @return True if proc returned non-NULL. */ bool HasVehicleOnPosXY(int x, int y, void *data, VehicleFromPosProc *proc) { return VehicleFromPosXY(x, y, data, proc, true) != NULL; } /** * Helper function for FindVehicleOnPos/HasVehicleOnPos. * @note Do not call this function directly! * @param tile The location on the map * @param data Arbitrary data passed to \a proc. * @param proc The proc that determines whether a vehicle will be "found". * @param find_first Whether to return on the first found or iterate over * all vehicles * @return the best matching or first vehicle (depending on find_first). */ static Vehicle *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc, bool find_first) { int x = GB(TileX(tile), HASH_RES, HASH_BITS); int y = GB(TileY(tile), HASH_RES, HASH_BITS) << HASH_BITS; Vehicle *v = _vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; for (; v != NULL; v = v->hash_tile_next) { if (v->tile != tile) continue; Vehicle *a = proc(v, data); if (find_first && a != NULL) return a; } return NULL; } /** * Find a vehicle from a specific location. It will call \a proc for ALL vehicles * on the tile and YOU must make SURE that the "best one" is stored in the * data value and is ALWAYS the same regardless of the order of the vehicles * where proc was called on! * When you fail to do this properly you create an almost untraceable DESYNC! * @note The return value of \a proc will be ignored. * @note Use this function when you have the intention that all vehicles * should be iterated over. * @param tile The location on the map * @param data Arbitrary data passed to \a proc. * @param proc The proc that determines whether a vehicle will be "found". */ void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) { VehicleFromPos(tile, data, proc, false); } /** * Checks whether a vehicle is on a specific location. It will call \a proc for * vehicles until it returns non-NULL. * @note Use #FindVehicleOnPos when you have the intention that all vehicles * should be iterated over. * @param tile The location on the map * @param data Arbitrary data passed to \a proc. * @param proc The \a proc that determines whether a vehicle will be "found". * @return True if proc returned non-NULL. */ bool HasVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc) { return VehicleFromPos(tile, data, proc, true) != NULL; } /** * Callback that returns 'real' vehicles lower or at height \c *(int*)data . * @param v Vehicle to examine. * @param data Pointer to height data. * @return \a v if conditions are met, else \c NULL. */ static Vehicle *EnsureNoVehicleProcZ(Vehicle *v, void *data) { int z = *(int*)data; if (v->type == VEH_DISASTER || (v->type == VEH_AIRCRAFT && v->subtype == AIR_SHADOW)) return NULL; if (v->z_pos > z) return NULL; return v; } /** * Ensure there is no vehicle at the ground at the given position. * @param tile Position to examine. * @return Succeeded command (ground is free) or failed command (a vehicle is found). */ CommandCost EnsureNoVehicleOnGround(TileIndex tile) { int z = GetTileMaxPixelZ(tile); /* Value v is not safe in MP games, however, it is used to generate a local * error message only (which may be different for different machines). * Such a message does not affect MP synchronisation. */ Vehicle *v = VehicleFromPos(tile, &z, &EnsureNoVehicleProcZ, true); if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); return CommandCost(); } /** Procedure called for every vehicle found in tunnel/bridge in the hash map */ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data) { if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL; if (v == (const Vehicle *)data) return NULL; return v; } /** * Finds vehicle in tunnel / bridge * @param tile first end * @param endtile second end * @param ignore Ignore this vehicle when searching * @return Succeeded command (if tunnel/bridge is free) or failed command (if a vehicle is using the tunnel/bridge). */ CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore) { /* Value v is not safe in MP games, however, it is used to generate a local * error message only (which may be different for different machines). * Such a message does not affect MP synchronisation. */ Vehicle *v = VehicleFromPos(tile, const_cast(ignore), &GetVehicleTunnelBridgeProc, true); if (v == NULL) v = VehicleFromPos(endtile, const_cast(ignore), &GetVehicleTunnelBridgeProc, true); if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); return CommandCost(); } static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data) { TrackBits rail_bits = *(TrackBits *)data; if (v->type != VEH_TRAIN) return NULL; Train *t = Train::From(v); if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL; return v; } /** * Tests if a vehicle interacts with the specified track bits. * All track bits interact except parallel #TRACK_BIT_HORZ or #TRACK_BIT_VERT. * * @param tile The tile. * @param track_bits The track bits. * @return \c true if no train that interacts, is found. \c false if a train is found. */ CommandCost EnsureNoTrainOnTrackBits(TileIndex tile, TrackBits track_bits) { /* Value v is not safe in MP games, however, it is used to generate a local * error message only (which may be different for different machines). * Such a message does not affect MP synchronisation. */ Vehicle *v = VehicleFromPos(tile, &track_bits, &EnsureNoTrainOnTrackProc, true); if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type); return CommandCost(); } static void UpdateVehicleTileHash(Vehicle *v, bool remove) { Vehicle **old_hash = v->hash_tile_current; Vehicle **new_hash; if (remove) { new_hash = NULL; } else { int x = GB(TileX(v->tile), HASH_RES, HASH_BITS); int y = GB(TileY(v->tile), HASH_RES, HASH_BITS) << HASH_BITS; new_hash = &_vehicle_tile_hash[(x + y) & TOTAL_HASH_MASK]; } if (old_hash == new_hash) return; /* Remove from the old position in the hash table */ if (old_hash != NULL) { if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = v->hash_tile_prev; *v->hash_tile_prev = v->hash_tile_next; } /* Insert vehicle at beginning of the new position in the hash table */ if (new_hash != NULL) { v->hash_tile_next = *new_hash; if (v->hash_tile_next != NULL) v->hash_tile_next->hash_tile_prev = &v->hash_tile_next; v->hash_tile_prev = new_hash; *new_hash = v; } /* Remember current hash position */ v->hash_tile_current = new_hash; } static Vehicle *_vehicle_viewport_hash[0x1000]; static void UpdateVehicleViewportHash(Vehicle *v, int x, int y) { Vehicle **old_hash, **new_hash; int old_x = v->coord.left; int old_y = v->coord.top; new_hash = (x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(x, y)]; old_hash = (old_x == INVALID_COORD) ? NULL : &_vehicle_viewport_hash[GEN_HASH(old_x, old_y)]; if (old_hash == new_hash) return; /* remove from hash table? */ if (old_hash != NULL) { if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = v->hash_viewport_prev; *v->hash_viewport_prev = v->hash_viewport_next; } /* insert into hash table? */ if (new_hash != NULL) { v->hash_viewport_next = *new_hash; if (v->hash_viewport_next != NULL) v->hash_viewport_next->hash_viewport_prev = &v->hash_viewport_next; v->hash_viewport_prev = new_hash; *new_hash = v; } } void ResetVehicleHash() { Vehicle *v; FOR_ALL_VEHICLES(v) { v->hash_tile_current = NULL; } memset(_vehicle_viewport_hash, 0, sizeof(_vehicle_viewport_hash)); memset(_vehicle_tile_hash, 0, sizeof(_vehicle_tile_hash)); } void ResetVehicleColourMap() { Vehicle *v; FOR_ALL_VEHICLES(v) { v->colourmap = PAL_NONE; } } /** * List of vehicles that should check for autoreplace this tick. * Mapping of vehicle -> leave depot immediately after autoreplace. */ typedef SmallMap AutoreplaceMap; static AutoreplaceMap _vehicles_to_autoreplace; void InitializeVehicles() { _vehicles_to_autoreplace.Reset(); ResetVehicleHash(); } uint CountVehiclesInChain(const Vehicle *v) { uint count = 0; do count++; while ((v = v->Next()) != NULL); return count; } /** * Check if a vehicle is counted in num_engines in each company struct * @return true if the vehicle is counted in num_engines */ bool Vehicle::IsEngineCountable() const { switch (this->type) { case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); // don't count plane shadows and helicopter rotors case VEH_TRAIN: return !this->IsArticulatedPart() && // tenders and other articulated parts !Train::From(this)->IsRearDualheaded(); // rear parts of multiheaded engines case VEH_ROAD: return RoadVehicle::From(this)->IsFrontEngine(); case VEH_SHIP: return true; default: return false; // Only count company buildable vehicles } } /** * Check whether Vehicle::engine_type has any meaning. * @return true if the vehicle has a useable engine type. */ bool Vehicle::HasEngineType() const { switch (this->type) { case VEH_AIRCRAFT: return Aircraft::From(this)->IsNormalAircraft(); case VEH_TRAIN: case VEH_ROAD: case VEH_SHIP: return true; default: return false; } } /** * Retrieves the engine of the vehicle. * @return Engine of the vehicle. * @pre HasEngineType() == true */ const Engine *Vehicle::GetEngine() const { return Engine::Get(this->engine_type); } /** * Retrieve the NewGRF the vehicle is tied to. * This is the GRF providing the Action 3 for the engine type. * @return NewGRF associated to the vehicle. */ const GRFFile *Vehicle::GetGRF() const { return this->GetEngine()->GetGRF(); } /** * Retrieve the GRF ID of the NewGRF the vehicle is tied to. * This is the GRF providing the Action 3 for the engine type. * @return GRF ID of the associated NewGRF. */ uint32 Vehicle::GetGRFID() const { return this->GetEngine()->GetGRFID(); } /** * Handle the pathfinding result, especially the lost status. * If the vehicle is now lost and wasn't previously fire an * event to the AIs and a news message to the user. If the * vehicle is not lost anymore remove the news message. * @param path_found Whether the vehicle has a path to its destination. */ void Vehicle::HandlePathfindingResult(bool path_found) { if (path_found) { /* Route found, is the vehicle marked with "lost" flag? */ if (!HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return; /* Clear the flag as the PF's problem was solved. */ ClrBit(this->vehicle_flags, VF_PATHFINDER_LOST); /* Delete the news item. */ DeleteVehicleNews(this->index, STR_NEWS_VEHICLE_IS_LOST); return; } /* Were we already lost? */ if (HasBit(this->vehicle_flags, VF_PATHFINDER_LOST)) return; /* It is first time the problem occurred, set the "lost" flag. */ SetBit(this->vehicle_flags, VF_PATHFINDER_LOST); /* Notify user about the event. */ AI::NewEvent(this->owner, new ScriptEventVehicleLost(this->index)); if (_settings_client.gui.lost_vehicle_warn && this->owner == _local_company) { SetDParam(0, this->index); AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_LOST, this->index); } } /** Destroy all stuff that (still) needs the virtual functions to work properly */ void Vehicle::PreDestructor() { if (CleaningPool()) return; if (Station::IsValidID(this->last_station_visited)) { Station *st = Station::Get(this->last_station_visited); st->loading_vehicles.remove(this); HideFillingPercent(&this->fill_percent_te_id); this->CancelReservation(INVALID_STATION, st); delete this->cargo_payment; } if (this->IsEngineCountable()) { GroupStatistics::CountEngine(this, -1); if (this->IsPrimaryVehicle()) GroupStatistics::CountVehicle(this, -1); GroupStatistics::UpdateAutoreplace(this->owner); if (this->owner == _local_company) InvalidateAutoreplaceWindow(this->engine_type, this->group_id); DeleteGroupHighlightOfVehicle(this); } if (this->type == VEH_AIRCRAFT && this->IsPrimaryVehicle()) { Aircraft *a = Aircraft::From(this); Station *st = GetTargetAirportIfValid(a); if (st != NULL) { const AirportFTA *layout = st->airport.GetFTA()->layout; CLRBITS(st->airport.flags, layout[a->previous_pos].block | layout[a->pos].block); } } if (this->type == VEH_ROAD && this->IsPrimaryVehicle()) { RoadVehicle *v = RoadVehicle::From(this); if (!(v->vehstatus & VS_CRASHED) && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) { /* Leave the drive through roadstop, when you have not already left it. */ RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v); } } if (this->Previous() == NULL) { InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile); } if (this->IsPrimaryVehicle()) { DeleteWindowById(WC_VEHICLE_VIEW, this->index); DeleteWindowById(WC_VEHICLE_ORDERS, this->index); DeleteWindowById(WC_VEHICLE_REFIT, this->index); DeleteWindowById(WC_VEHICLE_DETAILS, this->index); DeleteWindowById(WC_VEHICLE_TIMETABLE, this->index); SetWindowDirty(WC_COMPANY, this->owner); OrderBackup::ClearVehicle(this); } InvalidateWindowClassesData(GetWindowClassForVehicleType(this->type), 0); this->cargo.Truncate(); DeleteVehicleOrders(this); DeleteDepotHighlightOfVehicle(this); extern void StopGlobalFollowVehicle(const Vehicle *v); StopGlobalFollowVehicle(this); ReleaseDisastersTargetingVehicle(this->index); } Vehicle::~Vehicle() { if (CleaningPool()) { this->cargo.OnCleanPool(); return; } /* sometimes, eg. for disaster vehicles, when company bankrupts, when removing crashed/flooded vehicles, * it may happen that vehicle chain is deleted when visible */ if (!(this->vehstatus & VS_HIDDEN)) this->MarkAllViewportsDirty(); Vehicle *v = this->Next(); this->SetNext(NULL); delete v; UpdateVehicleTileHash(this, true); UpdateVehicleViewportHash(this, INVALID_COORD, 0); DeleteVehicleNews(this->index, INVALID_STRING_ID); DeleteNewGRFInspectWindow(GetGrfSpecFeature(this->type), this->index); } /** * Adds a vehicle to the list of vehicles that visited a depot this tick * @param *v vehicle to add */ void VehicleEnteredDepotThisTick(Vehicle *v) { /* Vehicle should stop in the depot if it was in 'stopping' state */ _vehicles_to_autoreplace[v] = !(v->vehstatus & VS_STOPPED); /* We ALWAYS set the stopped state. Even when the vehicle does not plan on * stopping in the depot, so we stop it to ensure that it will not reserve * the path out of the depot before we might autoreplace it to a different * engine. The new engine would not own the reserved path we store that we * stopped the vehicle, so autoreplace can start it again */ v->vehstatus |= VS_STOPPED; } /** * Increases the day counter for all vehicles and calls 1-day and 32-day handlers. * Each tick, it processes vehicles with "index % DAY_TICKS == _date_fract", * so each day, all vehicles are processes in DAY_TICKS steps. */ static void RunVehicleDayProc() { if (_game_mode != GM_NORMAL) return; /* Run the day_proc for every DAY_TICKS vehicle starting at _date_fract. */ for (size_t i = _date_fract; i < Vehicle::GetPoolSize(); i += DAY_TICKS) { Vehicle *v = Vehicle::Get(i); if (v == NULL) continue; /* Call the 32-day callback if needed */ if ((v->day_counter & 0x1F) == 0 && v->HasEngineType()) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_32DAY_CALLBACK, 0, 0, v->engine_type, v); if (callback != CALLBACK_FAILED) { if (HasBit(callback, 0)) { TriggerVehicle(v, VEHICLE_TRIGGER_CALLBACK_32); // Trigger vehicle trigger 10 } /* After a vehicle trigger, the graphics and properties of the vehicle could change. * Note: MarkDirty also invalidates the palette, which is the meaning of bit 1. So, nothing special there. */ if (callback != 0) v->First()->MarkDirty(); if (callback & ~3) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_32DAY_CALLBACK, callback); } } /* This is called once per day for each vehicle, but not in the first tick of the day */ v->OnNewDay(); } } void CallVehicleTicks() { _vehicles_to_autoreplace.Clear(); RunVehicleDayProc(); Station *st; FOR_ALL_STATIONS(st) LoadUnloadStation(st); Vehicle *v; FOR_ALL_VEHICLES(v) { /* Vehicle could be deleted in this tick */ if (!v->Tick()) { assert(Vehicle::Get(vehicle_index) == NULL); continue; } assert(Vehicle::Get(vehicle_index) == v); switch (v->type) { default: break; case VEH_TRAIN: case VEH_ROAD: case VEH_AIRCRAFT: case VEH_SHIP: { Vehicle *front = v->First(); if (v->vcache.cached_cargo_age_period != 0) { v->cargo_age_counter = min(v->cargo_age_counter, v->vcache.cached_cargo_age_period); if (--v->cargo_age_counter == 0) { v->cargo.AgeCargo(); v->cargo_age_counter = v->vcache.cached_cargo_age_period; } } /* Do not play any sound when crashed */ if (front->vehstatus & VS_CRASHED) continue; /* Do not play any sound when in depot or tunnel */ if (v->vehstatus & VS_HIDDEN) continue; /* Do not play any sound when stopped */ if ((front->vehstatus & VS_STOPPED) && (front->type != VEH_TRAIN || front->cur_speed == 0)) continue; /* Check vehicle type specifics */ switch (v->type) { case VEH_TRAIN: if (Train::From(v)->IsWagon()) continue; break; case VEH_ROAD: if (!RoadVehicle::From(v)->IsFrontEngine()) continue; break; case VEH_AIRCRAFT: if (!Aircraft::From(v)->IsNormalAircraft()) continue; break; default: break; } v->motion_counter += front->cur_speed; /* Play a running sound if the motion counter passes 256 (Do we not skip sounds?) */ if (GB(v->motion_counter, 0, 8) < front->cur_speed) PlayVehicleSound(v, VSE_RUNNING); /* Play an alternating running sound every 16 ticks */ if (GB(v->tick_counter, 0, 4) == 0) { /* Play running sound when speed > 0 and not braking */ bool running = (front->cur_speed > 0) && !(front->vehstatus & (VS_STOPPED | VS_TRAIN_SLOWING)); PlayVehicleSound(v, running ? VSE_RUNNING_16 : VSE_STOPPED_16); } break; } } } Backup cur_company(_current_company, FILE_LINE); for (AutoreplaceMap::iterator it = _vehicles_to_autoreplace.Begin(); it != _vehicles_to_autoreplace.End(); it++) { v = it->first; /* Autoreplace needs the current company set as the vehicle owner */ cur_company.Change(v->owner); /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick() * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that * they are already leaving the depot again before being replaced. */ if (it->second) v->vehstatus &= ~VS_STOPPED; /* Store the position of the effect as the vehicle pointer will become invalid later */ int x = v->x_pos; int y = v->y_pos; int z = v->z_pos; const Company *c = Company::Get(_current_company); SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money)); CommandCost res = DoCommand(0, v->index, 0, DC_EXEC, CMD_AUTOREPLACE_VEHICLE); SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -(Money)c->settings.engine_renew_money)); if (!IsLocalCompany()) continue; if (res.Succeeded()) { ShowCostOrIncomeAnimation(x, y, z, res.GetCost()); continue; } StringID error_message = res.GetErrorMessage(); if (error_message == STR_ERROR_AUTOREPLACE_NOTHING_TO_DO || error_message == INVALID_STRING_ID) continue; if (error_message == STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY) error_message = STR_ERROR_AUTOREPLACE_MONEY_LIMIT; StringID message; if (error_message == STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT) { message = error_message; } else { message = STR_NEWS_VEHICLE_AUTORENEW_FAILED; } SetDParam(0, v->index); SetDParam(1, error_message); AddVehicleAdviceNewsItem(message, v->index); } cur_company.Restore(); } /** * Add vehicle sprite for drawing to the screen. * @param v Vehicle to draw. */ static void DoDrawVehicle(const Vehicle *v) { SpriteID image = v->cur_image; PaletteID pal = PAL_NONE; if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); /* Check whether the vehicle shall be transparent due to the game state */ bool shadowed = (v->vehstatus & VS_SHADOW) != 0; if (v->type == VEH_EFFECT) { /* Check whether the vehicle shall be transparent/invisible due to GUI settings. * However, transparent smoke and bubbles look weird, so always hide them. */ TransparencyOption to = EffectVehicle::From(v)->GetTransparencyOption(); if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return; } AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs, v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs); } /** * Add the vehicle sprites that should be drawn at a part of the screen. * @param dpi Rectangle being drawn. */ void ViewportAddVehicles(DrawPixelInfo *dpi) { /* The bounding rectangle */ const int l = dpi->left; const int r = dpi->left + dpi->width; const int t = dpi->top; const int b = dpi->top + dpi->height; /* The hash area to scan */ int xl, xu, yl, yu; if (dpi->width + (70 * ZOOM_LVL_BASE) < (1 << (7 + 6 + ZOOM_LVL_SHIFT))) { xl = GB(l - (70 * ZOOM_LVL_BASE), 7 + ZOOM_LVL_SHIFT, 6); xu = GB(r, 7 + ZOOM_LVL_SHIFT, 6); } else { /* scan whole hash row */ xl = 0; xu = 0x3F; } if (dpi->height + (70 * ZOOM_LVL_BASE) < (1 << (6 + 6 + ZOOM_LVL_SHIFT))) { yl = GB(t - (70 * ZOOM_LVL_BASE), 6 + ZOOM_LVL_SHIFT, 6) << 6; yu = GB(b, 6 + ZOOM_LVL_SHIFT, 6) << 6; } else { /* scan whole column */ yl = 0; yu = 0x3F << 6; } for (int y = yl;; y = (y + (1 << 6)) & (0x3F << 6)) { for (int x = xl;; x = (x + 1) & 0x3F) { const Vehicle *v = _vehicle_viewport_hash[x + y]; // already masked & 0xFFF while (v != NULL) { if (!(v->vehstatus & VS_HIDDEN) && l <= v->coord.right && t <= v->coord.bottom && r >= v->coord.left && b >= v->coord.top) { DoDrawVehicle(v); } v = v->hash_viewport_next; } if (x == xu) break; } if (y == yu) break; } } /** * Find the vehicle close to the clicked coordinates. * @param vp Viewport clicked in. * @param x X coordinate in the viewport. * @param y Y coordinate in the viewport. * @return Closest vehicle, or \c NULL if none found. */ Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y) { Vehicle *found = NULL, *v; uint dist, best_dist = UINT_MAX; if ((uint)(x -= vp->left) >= (uint)vp->width || (uint)(y -= vp->top) >= (uint)vp->height) return NULL; x = ScaleByZoom(x, vp->zoom) + vp->virtual_left; y = ScaleByZoom(y, vp->zoom) + vp->virtual_top; FOR_ALL_VEHICLES(v) { if ((v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0 && x >= v->coord.left && x <= v->coord.right && y >= v->coord.top && y <= v->coord.bottom) { dist = max( abs(((v->coord.left + v->coord.right) >> 1) - x), abs(((v->coord.top + v->coord.bottom) >> 1) - y) ); if (dist < best_dist) { found = v; best_dist = dist; } } } return found; } /** * Decrease the value of a vehicle. * @param v %Vehicle to devaluate. */ void DecreaseVehicleValue(Vehicle *v) { v->value -= v->value >> 8; SetWindowDirty(WC_VEHICLE_DETAILS, v->index); } static const byte _breakdown_chance[64] = { 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 19, 21, 25, 28, 31, 34, 37, 40, 44, 48, 52, 56, 60, 64, 68, 72, 80, 90, 100, 110, 120, 130, 140, 150, 170, 190, 210, 230, 250, 250, 250, }; void CheckVehicleBreakdown(Vehicle *v) { int rel, rel_old; /* decrease reliability */ v->reliability = rel = max((rel_old = v->reliability) - v->reliability_spd_dec, 0); if ((rel_old >> 8) != (rel >> 8)) SetWindowDirty(WC_VEHICLE_DETAILS, v->index); if (v->breakdown_ctr != 0 || (v->vehstatus & VS_STOPPED) || _settings_game.difficulty.vehicle_breakdowns < 1 || v->cur_speed < 5 || _game_mode == GM_MENU) { return; } uint32 r = Random(); /* increase chance of failure */ int chance = v->breakdown_chance + 1; if (Chance16I(1, 25, r)) chance += 25; v->breakdown_chance = min(255, chance); /* calculate reliability value to use in comparison */ rel = v->reliability; if (v->type == VEH_SHIP) rel += 0x6666; /* reduced breakdowns? */ if (_settings_game.difficulty.vehicle_breakdowns == 1) rel += 0x6666; /* check if to break down */ if (_breakdown_chance[(uint)min(rel, 0xffff) >> 10] <= v->breakdown_chance) { v->breakdown_ctr = GB(r, 16, 6) + 0x3F; v->breakdown_delay = GB(r, 24, 7) + 0x80; v->breakdown_chance = 0; } } /** * Handle all of the aspects of a vehicle breakdown * This includes adding smoke and sounds, and ending the breakdown when appropriate. * @return true iff the vehicle is stopped because of a breakdown * @note This function always returns false for aircraft, since these never stop for breakdowns */ bool Vehicle::HandleBreakdown() { /* Possible states for Vehicle::breakdown_ctr * 0 - vehicle is running normally * 1 - vehicle is currently broken down * 2 - vehicle is going to break down now * >2 - vehicle is counting down to the actual breakdown event */ switch (this->breakdown_ctr) { case 0: return false; case 2: this->breakdown_ctr = 1; if (this->breakdowns_since_last_service != 255) { this->breakdowns_since_last_service++; } if (this->type == VEH_AIRCRAFT) { /* Aircraft just need this flag, the rest is handled elsewhere */ this->vehstatus |= VS_AIRCRAFT_BROKEN; } else { this->cur_speed = 0; if (!PlayVehicleSound(this, VSE_BREAKDOWN)) { bool train_or_ship = this->type == VEH_TRAIN || this->type == VEH_SHIP; SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ? (train_or_ship ? SND_10_TRAIN_BREAKDOWN : SND_0F_VEHICLE_BREAKDOWN) : (train_or_ship ? SND_3A_COMEDY_BREAKDOWN_2 : SND_35_COMEDY_BREAKDOWN), this); } if (!(this->vehstatus & VS_HIDDEN) && !HasBit(EngInfo(this->engine_type)->misc_flags, EF_NO_BREAKDOWN_SMOKE)) { EffectVehicle *u = CreateEffectVehicleRel(this, 4, 4, 5, EV_BREAKDOWN_SMOKE); if (u != NULL) u->animation_state = this->breakdown_delay * 2; } } this->MarkDirty(); // Update graphics after speed is zeroed SetWindowDirty(WC_VEHICLE_VIEW, this->index); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); /* FALL THROUGH */ case 1: /* Aircraft breakdowns end only when arriving at the airport */ if (this->type == VEH_AIRCRAFT) return false; /* For trains this function is called twice per tick, so decrease v->breakdown_delay at half the rate */ if ((this->tick_counter & (this->type == VEH_TRAIN ? 3 : 1)) == 0) { if (--this->breakdown_delay == 0) { this->breakdown_ctr = 0; this->MarkDirty(); SetWindowDirty(WC_VEHICLE_VIEW, this->index); } } return true; default: if (!this->current_order.IsType(OT_LOADING)) this->breakdown_ctr--; return false; } } /** * Update age of a vehicle. * @param v Vehicle to update. */ void AgeVehicle(Vehicle *v) { if (v->age < MAX_DAY) { v->age++; if (v->IsPrimaryVehicle() && v->age == VEHICLE_PROFIT_MIN_AGE + 1) GroupStatistics::VehicleReachedProfitAge(v); } if (!v->IsPrimaryVehicle() && (v->type != VEH_TRAIN || !Train::From(v)->IsEngine())) return; int age = v->age - v->max_age; if (age == DAYS_IN_LEAP_YEAR * 0 || age == DAYS_IN_LEAP_YEAR * 1 || age == DAYS_IN_LEAP_YEAR * 2 || age == DAYS_IN_LEAP_YEAR * 3 || age == DAYS_IN_LEAP_YEAR * 4) { v->reliability_spd_dec <<= 1; } SetWindowDirty(WC_VEHICLE_DETAILS, v->index); /* Don't warn about non-primary or not ours vehicles or vehicles that are crashed */ if (v->Previous() != NULL || v->owner != _local_company || (v->vehstatus & VS_CRASHED) != 0) return; /* Don't warn if a renew is active */ if (Company::Get(v->owner)->settings.engine_renew && v->GetEngine()->company_avail != 0) return; StringID str; if (age == -DAYS_IN_LEAP_YEAR) { str = STR_NEWS_VEHICLE_IS_GETTING_OLD; } else if (age == 0) { str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD; } else if (age > 0 && (age % DAYS_IN_LEAP_YEAR) == 0) { str = STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND; } else { return; } SetDParam(0, v->index); AddVehicleAdviceNewsItem(str, v->index); } /** * Calculates how full a vehicle is. * @param front The front vehicle of the consist to check. * @param colour The string to show depending on if we are unloading or loading * @return A percentage of how full the Vehicle is. */ uint8 CalcPercentVehicleFilled(const Vehicle *front, StringID *colour) { int count = 0; int max = 0; int cars = 0; int unloading = 0; bool loading = false; bool is_loading = front->current_order.IsType(OT_LOADING); /* The station may be NULL when the (colour) string does not need to be set. */ const Station *st = Station::GetIfValid(front->last_station_visited); assert(colour == NULL || (st != NULL && is_loading)); bool order_no_load = is_loading && (front->current_order.GetLoadType() & OLFB_NO_LOAD); bool order_full_load = is_loading && (front->current_order.GetLoadType() & OLFB_FULL_LOAD); /* Count up max and used */ for (const Vehicle *v = front; v != NULL; v = v->Next()) { count += v->cargo.StoredCount(); max += v->cargo_cap; if (v->cargo_cap != 0 && colour != NULL) { unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0; loading |= !order_no_load && (order_full_load || st->goods[v->cargo_type].HasRating()) && !HasBit(v->vehicle_flags, VF_LOADING_FINISHED) && !HasBit(v->vehicle_flags, VF_STOP_LOADING); cars++; } } if (colour != NULL) { if (unloading == 0 && loading) { *colour = STR_PERCENT_UP; } else if (unloading == 0 && !loading) { *colour = STR_PERCENT_NONE; } else if (cars == unloading || !loading) { *colour = STR_PERCENT_DOWN; } else { *colour = STR_PERCENT_UP_DOWN; } } /* Train without capacity */ if (max == 0) return 100; /* Return the percentage */ return (count * 100) / max; } /** * Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it, etc. * @param v Vehicle that entered a depot. */ void VehicleEnterDepot(Vehicle *v) { /* Always work with the front of the vehicle */ assert(v == v->First()); switch (v->type) { case VEH_TRAIN: { Train *t = Train::From(v); SetWindowClassesDirty(WC_TRAINS_LIST); /* Clear path reservation */ SetDepotReservation(t->tile, false); if (_settings_client.gui.show_track_reservation) MarkTileDirtyByTile(t->tile); UpdateSignalsOnSegment(t->tile, INVALID_DIAGDIR, t->owner); t->wait_counter = 0; t->force_proceed = TFP_NONE; ClrBit(t->flags, VRF_TOGGLE_REVERSE); t->ConsistChanged(CCF_ARRANGE); break; } case VEH_ROAD: SetWindowClassesDirty(WC_ROADVEH_LIST); break; case VEH_SHIP: { SetWindowClassesDirty(WC_SHIPS_LIST); Ship *ship = Ship::From(v); ship->state = TRACK_BIT_DEPOT; ship->UpdateCache(); ship->UpdateViewport(true, true); SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); break; } case VEH_AIRCRAFT: SetWindowClassesDirty(WC_AIRCRAFT_LIST); HandleAircraftEnterHangar(Aircraft::From(v)); break; default: NOT_REACHED(); } SetWindowDirty(WC_VEHICLE_VIEW, v->index); if (v->type != VEH_TRAIN) { /* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters. * We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */ InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); } SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); v->vehstatus |= VS_HIDDEN; v->cur_speed = 0; VehicleServiceInDepot(v); /* After a vehicle trigger, the graphics and properties of the vehicle could change. */ TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT); v->MarkDirty(); if (v->current_order.IsType(OT_GOTO_DEPOT)) { SetWindowDirty(WC_VEHICLE_VIEW, v->index); const Order *real_order = v->GetOrder(v->cur_real_order_index); /* Test whether we are heading for this depot. If not, do nothing. * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */ if ((v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && real_order != NULL && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && (v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) { /* We are heading for another depot, keep driving. */ return; } if (v->current_order.IsRefit()) { Backup cur_company(_current_company, v->owner, FILE_LINE); CommandCost cost = DoCommand(v->tile, v->index, v->current_order.GetRefitCargo() | 0xFF << 8, DC_EXEC, GetCmdRefitVeh(v)); cur_company.Restore(); if (cost.Failed()) { _vehicles_to_autoreplace[v] = false; if (v->owner == _local_company) { /* Notify the user that we stopped the vehicle */ SetDParam(0, v->index); AddVehicleAdviceNewsItem(STR_NEWS_ORDER_REFIT_FAILED, v->index); } } else if (cost.GetCost() != 0) { v->profit_this_year -= cost.GetCost() << 8; if (v->owner == _local_company) { ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost()); } } } if (v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) { /* Part of orders */ v->DeleteUnreachedImplicitOrders(); UpdateVehicleTimetable(v, true); v->IncrementImplicitOrderIndex(); } if (v->current_order.GetDepotActionType() & ODATFB_HALT) { /* Vehicles are always stopped on entering depots. Do not restart this one. */ _vehicles_to_autoreplace[v] = false; /* Invalidate last_loading_station. As the link from the station * before the stop to the station after the stop can't be predicted * we shouldn't construct it when the vehicle visits the next stop. */ v->last_loading_station = INVALID_STATION; if (v->owner == _local_company) { SetDParam(0, v->index); AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_WAITING + v->type, v->index); } AI::NewEvent(v->owner, new ScriptEventVehicleWaitingInDepot(v->index)); } v->current_order.MakeDummy(); } } /** * Update the position of the vehicle. This will update the hash that tells * which vehicles are on a tile. */ void Vehicle::UpdatePosition() { UpdateVehicleTileHash(this, false); } /** * Update the vehicle on the viewport, updating the right hash and setting the * new coordinates. * @param dirty Mark the (new and old) coordinates of the vehicle as dirty. */ void Vehicle::UpdateViewport(bool dirty) { int img = this->cur_image; Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos); const Sprite *spr = GetSprite(img, ST_NORMAL); pt.x += spr->x_offs; pt.y += spr->y_offs; UpdateVehicleViewportHash(this, pt.x, pt.y); Rect old_coord = this->coord; this->coord.left = pt.x; this->coord.top = pt.y; this->coord.right = pt.x + spr->width + 2 * ZOOM_LVL_BASE; this->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE; if (dirty) { if (old_coord.left == INVALID_COORD) { this->MarkAllViewportsDirty(); } else { ::MarkAllViewportsDirty( min(old_coord.left, this->coord.left), min(old_coord.top, this->coord.top), max(old_coord.right, this->coord.right), max(old_coord.bottom, this->coord.bottom)); } } } /** * Update the position of the vehicle, and update the viewport. */ void Vehicle::UpdatePositionAndViewport() { this->UpdatePosition(); this->UpdateViewport(true); } /** * Marks viewports dirty where the vehicle's image is. */ void Vehicle::MarkAllViewportsDirty() const { ::MarkAllViewportsDirty(this->coord.left, this->coord.top, this->coord.right, this->coord.bottom); } /** * Get position information of a vehicle when moving one pixel in the direction it is facing * @param v Vehicle to move * @return Position information after the move */ GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v) { static const int8 _delta_coord[16] = { -1,-1,-1, 0, 1, 1, 1, 0, /* x */ -1, 0, 1, 1, 1, 0,-1,-1, /* y */ }; int x = v->x_pos + _delta_coord[v->direction]; int y = v->y_pos + _delta_coord[v->direction + 8]; GetNewVehiclePosResult gp; gp.x = x; gp.y = y; gp.old_tile = v->tile; gp.new_tile = TileVirtXY(x, y); return gp; } static const Direction _new_direction_table[] = { DIR_N, DIR_NW, DIR_W, DIR_NE, DIR_SE, DIR_SW, DIR_E, DIR_SE, DIR_S }; Direction GetDirectionTowards(const Vehicle *v, int x, int y) { int i = 0; if (y >= v->y_pos) { if (y != v->y_pos) i += 3; i += 3; } if (x >= v->x_pos) { if (x != v->x_pos) i++; i++; } Direction dir = v->direction; DirDiff dirdiff = DirDifference(_new_direction_table[i], dir); if (dirdiff == DIRDIFF_SAME) return dir; return ChangeDir(dir, dirdiff > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT); } /** * Call the tile callback function for a vehicle entering a tile * @param v Vehicle entering the tile * @param tile Tile entered * @param x X position * @param y Y position * @return Some meta-data over the to be entered tile. * @see VehicleEnterTileStatus to see what the bits in the return value mean. */ VehicleEnterTileStatus VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y) { return _tile_type_procs[GetTileType(tile)]->vehicle_enter_tile_proc(v, tile, x, y); } /** * Initializes the structure. Vehicle unit numbers are supposed not to change after * struct initialization, except after each call to this->NextID() the returned value * is assigned to a vehicle. * @param type type of vehicle * @param owner owner of vehicles */ FreeUnitIDGenerator::FreeUnitIDGenerator(VehicleType type, CompanyID owner) : cache(NULL), maxid(0), curid(0) { /* Find maximum */ const Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->type == type && v->owner == owner) { this->maxid = max(this->maxid, v->unitnumber); } } if (this->maxid == 0) return; /* Reserving 'maxid + 2' because we need: * - space for the last item (with v->unitnumber == maxid) * - one free slot working as loop terminator in FreeUnitIDGenerator::NextID() */ this->cache = CallocT(this->maxid + 2); /* Fill the cache */ FOR_ALL_VEHICLES(v) { if (v->type == type && v->owner == owner) { this->cache[v->unitnumber] = true; } } } /** Returns next free UnitID. Supposes the last returned value was assigned to a vehicle. */ UnitID FreeUnitIDGenerator::NextID() { if (this->maxid <= this->curid) return ++this->curid; while (this->cache[++this->curid]) { } // it will stop, we reserved more space than needed return this->curid; } /** * Get an unused unit number for a vehicle (if allowed). * @param type Type of vehicle * @return A unused unit number for the given type of vehicle if it is allowed to build one, else \c UINT16_MAX. */ UnitID GetFreeUnitNumber(VehicleType type) { /* Check whether it is allowed to build another vehicle. */ uint max_veh; switch (type) { case VEH_TRAIN: max_veh = _settings_game.vehicle.max_trains; break; case VEH_ROAD: max_veh = _settings_game.vehicle.max_roadveh; break; case VEH_SHIP: max_veh = _settings_game.vehicle.max_ships; break; case VEH_AIRCRAFT: max_veh = _settings_game.vehicle.max_aircraft; break; default: NOT_REACHED(); } const Company *c = Company::Get(_current_company); if (c->group_all[type].num_vehicle >= max_veh) return UINT16_MAX; // Currently already at the limit, no room to make a new one. FreeUnitIDGenerator gen(type, _current_company); return gen.NextID(); } /** * Check whether we can build infrastructure for the given * vehicle type. This to disable building stations etc. when * you are not allowed/able to have the vehicle type yet. * @param type the vehicle type to check this for * @return true if there is any reason why you may build * the infrastructure for the given vehicle type */ bool CanBuildVehicleInfrastructure(VehicleType type) { assert(IsCompanyBuildableVehicleType(type)); if (!Company::IsValidID(_local_company)) return false; if (!_settings_client.gui.disable_unsuitable_building) return true; UnitID max; switch (type) { case VEH_TRAIN: max = _settings_game.vehicle.max_trains; break; case VEH_ROAD: max = _settings_game.vehicle.max_roadveh; break; case VEH_SHIP: max = _settings_game.vehicle.max_ships; break; case VEH_AIRCRAFT: max = _settings_game.vehicle.max_aircraft; break; default: NOT_REACHED(); } /* We can build vehicle infrastructure when we may build the vehicle type */ if (max > 0) { /* Can we actually build the vehicle type? */ const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, type) { if (HasBit(e->company_avail, _local_company)) return true; } return false; } /* We should be able to build infrastructure when we have the actual vehicle type */ const Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == _local_company && v->type == type) return true; } return false; } /** * Determines the #LiveryScheme for a vehicle. * @param engine_type Engine of the vehicle. * @param parent_engine_type Engine of the front vehicle, #INVALID_ENGINE if vehicle is at front itself. * @param v the vehicle, \c NULL if in purchase list etc. * @return livery scheme to use. */ LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v) { CargoID cargo_type = v == NULL ? (CargoID)CT_INVALID : v->cargo_type; const Engine *e = Engine::Get(engine_type); switch (e->type) { default: NOT_REACHED(); case VEH_TRAIN: if (v != NULL && parent_engine_type != INVALID_ENGINE && (UsesWagonOverride(v) || (v->IsArticulatedPart() && e->u.rail.railveh_type != RAILVEH_WAGON))) { /* Wagonoverrides use the colour scheme of the front engine. * Articulated parts use the colour scheme of the first part. (Not supported for articulated wagons) */ engine_type = parent_engine_type; e = Engine::Get(engine_type); /* Note: Luckily cargo_type is not needed for engines */ } if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType(); if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo if (e->u.rail.railveh_type == RAILVEH_WAGON) { if (!CargoSpec::Get(cargo_type)->is_freight) { if (parent_engine_type == INVALID_ENGINE) { return LS_PASSENGER_WAGON_STEAM; } else { switch (RailVehInfo(parent_engine_type)->engclass) { default: NOT_REACHED(); case EC_STEAM: return LS_PASSENGER_WAGON_STEAM; case EC_DIESEL: return LS_PASSENGER_WAGON_DIESEL; case EC_ELECTRIC: return LS_PASSENGER_WAGON_ELECTRIC; case EC_MONORAIL: return LS_PASSENGER_WAGON_MONORAIL; case EC_MAGLEV: return LS_PASSENGER_WAGON_MAGLEV; } } } else { return LS_FREIGHT_WAGON; } } else { bool is_mu = HasBit(e->info.misc_flags, EF_RAIL_IS_MU); switch (e->u.rail.engclass) { default: NOT_REACHED(); case EC_STEAM: return LS_STEAM; case EC_DIESEL: return is_mu ? LS_DMU : LS_DIESEL; case EC_ELECTRIC: return is_mu ? LS_EMU : LS_ELECTRIC; case EC_MONORAIL: return LS_MONORAIL; case EC_MAGLEV: return LS_MAGLEV; } } case VEH_ROAD: /* Always use the livery of the front */ if (v != NULL && parent_engine_type != INVALID_ENGINE) { engine_type = parent_engine_type; e = Engine::Get(engine_type); cargo_type = v->First()->cargo_type; } if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType(); if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo /* Important: Use Tram Flag of front part. Luckily engine_type refers to the front part here. */ if (HasBit(e->info.misc_flags, EF_ROAD_TRAM)) { /* Tram */ return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_TRAM : LS_FREIGHT_TRAM; } else { /* Bus or truck */ return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_BUS : LS_TRUCK; } case VEH_SHIP: if (cargo_type == CT_INVALID) cargo_type = e->GetDefaultCargoType(); if (cargo_type == CT_INVALID) cargo_type = CT_GOODS; // The vehicle does not carry anything, let's pick some freight cargo return IsCargoInClass(cargo_type, CC_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP; case VEH_AIRCRAFT: switch (e->u.air.subtype) { case AIR_HELI: return LS_HELICOPTER; case AIR_CTOL: return LS_SMALL_PLANE; case AIR_CTOL | AIR_FAST: return LS_LARGE_PLANE; default: NOT_REACHED(); } } } /** * Determines the livery for a vehicle. * @param engine_type EngineID of the vehicle * @param company Owner of the vehicle * @param parent_engine_type EngineID of the front vehicle. INVALID_VEHICLE if vehicle is at front itself. * @param v the vehicle. NULL if in purchase list etc. * @param livery_setting The livery settings to use for acquiring the livery information. * @return livery to use */ const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting) { const Company *c = Company::Get(company); LiveryScheme scheme = LS_DEFAULT; /* The default livery is always available for use, but its in_use flag determines * whether any _other_ liveries are in use. */ if (c->livery[LS_DEFAULT].in_use && (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company))) { /* Determine the livery scheme to use */ scheme = GetEngineLiveryScheme(engine_type, parent_engine_type, v); /* Switch back to the default scheme if the resolved scheme is not in use */ if (!c->livery[scheme].in_use) scheme = LS_DEFAULT; } return &c->livery[scheme]; } static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v) { PaletteID map = (v != NULL) ? v->colourmap : PAL_NONE; /* Return cached value if any */ if (map != PAL_NONE) return map; const Engine *e = Engine::Get(engine_type); /* Check if we should use the colour map callback */ if (HasBit(e->info.callback_mask, CBM_VEHICLE_COLOUR_REMAP)) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_COLOUR_MAPPING, 0, 0, engine_type, v); /* Failure means "use the default two-colour" */ if (callback != CALLBACK_FAILED) { assert_compile(PAL_NONE == 0); // Returning 0x4000 (resp. 0xC000) coincidences with default value (PAL_NONE) map = GB(callback, 0, 14); /* If bit 14 is set, then the company colours are applied to the * map else it's returned as-is. */ if (!HasBit(callback, 14)) { /* Update cache */ if (v != NULL) const_cast(v)->colourmap = map; return map; } } } bool twocc = HasBit(e->info.misc_flags, EF_USES_2CC); if (map == PAL_NONE) map = twocc ? (PaletteID)SPR_2CCMAP_BASE : (PaletteID)PALETTE_RECOLOUR_START; /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */ if (!Company::IsValidID(company)) return map; const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries); map += livery->colour1; if (twocc) map += livery->colour2 * 16; /* Update cache */ if (v != NULL) const_cast(v)->colourmap = map; return map; } /** * Get the colour map for an engine. This used for unbuilt engines in the user interface. * @param engine_type ID of engine * @param company ID of company * @return A ready-to-use palette modifier */ PaletteID GetEnginePalette(EngineID engine_type, CompanyID company) { return GetEngineColourMap(engine_type, company, INVALID_ENGINE, NULL); } /** * Get the colour map for a vehicle. * @param v Vehicle to get colour map for * @return A ready-to-use palette modifier */ PaletteID GetVehiclePalette(const Vehicle *v) { if (v->IsGroundVehicle()) { return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v); } return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v); } /** * Delete all implicit orders which were not reached. */ void Vehicle::DeleteUnreachedImplicitOrders() { if (this->IsGroundVehicle()) { uint16 &gv_flags = this->GetGroundVehicleFlags(); if (HasBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS)) { /* Do not delete orders, only skip them */ ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); this->cur_implicit_order_index = this->cur_real_order_index; InvalidateVehicleOrder(this, 0); return; } } const Order *order = this->GetOrder(this->cur_implicit_order_index); while (order != NULL) { if (this->cur_implicit_order_index == this->cur_real_order_index) break; if (order->IsType(OT_IMPLICIT)) { DeleteOrder(this, this->cur_implicit_order_index); /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */ order = this->GetOrder(this->cur_implicit_order_index); } else { /* Skip non-implicit orders, e.g. service-orders */ order = order->next; this->cur_implicit_order_index++; } /* Wrap around */ if (order == NULL) { order = this->GetOrder(0); this->cur_implicit_order_index = 0; } } } /** * Prepare everything to begin the loading when arriving at a station. * @pre IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP. */ void Vehicle::BeginLoading() { assert(IsTileType(this->tile, MP_STATION) || this->type == VEH_SHIP); if (this->current_order.IsType(OT_GOTO_STATION) && this->current_order.GetDestination() == this->last_station_visited) { this->DeleteUnreachedImplicitOrders(); /* Now both order indices point to the destination station, and we can start loading */ this->current_order.MakeLoading(true); UpdateVehicleTimetable(this, true); /* Furthermore add the Non Stop flag to mark that this station * is the actual destination of the vehicle, which is (for example) * necessary to be known for HandleTrainLoading to determine * whether the train is lost or not; not marking a train lost * that arrives at random stations is bad. */ this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION); } else { /* We weren't scheduled to stop here. Insert an implicit order * to show that we are stopping here. * While only groundvehicles have implicit orders, e.g. aircraft might still enter * the 'wrong' terminal when skipping orders etc. */ Order *in_list = this->GetOrder(this->cur_implicit_order_index); if (this->IsGroundVehicle() && (in_list == NULL || !in_list->IsType(OT_IMPLICIT) || in_list->GetDestination() != this->last_station_visited)) { bool suppress_implicit_orders = HasBit(this->GetGroundVehicleFlags(), GVF_SUPPRESS_IMPLICIT_ORDERS); /* Do not create consecutive duplicates of implicit orders */ Order *prev_order = this->cur_implicit_order_index > 0 ? this->GetOrder(this->cur_implicit_order_index - 1) : (this->GetNumOrders() > 1 ? this->GetLastOrder() : NULL); if (prev_order == NULL || (!prev_order->IsType(OT_IMPLICIT) && !prev_order->IsType(OT_GOTO_STATION)) || prev_order->GetDestination() != this->last_station_visited) { /* Prefer deleting implicit orders instead of inserting new ones, * so test whether the right order follows later. In case of only * implicit orders treat the last order in the list like an * explicit one, except if the overall number of orders surpasses * IMPLICIT_ORDER_ONLY_CAP. */ int target_index = this->cur_implicit_order_index; bool found = false; while (target_index != this->cur_real_order_index || this->GetNumManualOrders() == 0) { const Order *order = this->GetOrder(target_index); if (order == NULL) break; // No orders. if (order->IsType(OT_IMPLICIT) && order->GetDestination() == this->last_station_visited) { found = true; break; } target_index++; if (target_index >= this->orders.list->GetNumOrders()) { if (this->GetNumManualOrders() == 0 && this->GetNumOrders() < IMPLICIT_ORDER_ONLY_CAP) { break; } target_index = 0; } if (target_index == this->cur_implicit_order_index) break; // Avoid infinite loop. } if (found) { if (suppress_implicit_orders) { /* Skip to the found order */ this->cur_implicit_order_index = target_index; InvalidateVehicleOrder(this, 0); } else { /* Delete all implicit orders up to the station we just reached */ const Order *order = this->GetOrder(this->cur_implicit_order_index); while (!order->IsType(OT_IMPLICIT) || order->GetDestination() != this->last_station_visited) { if (order->IsType(OT_IMPLICIT)) { DeleteOrder(this, this->cur_implicit_order_index); /* DeleteOrder does various magic with order_indices, so resync 'order' with 'cur_implicit_order_index' */ order = this->GetOrder(this->cur_implicit_order_index); } else { /* Skip non-implicit orders, e.g. service-orders */ order = order->next; this->cur_implicit_order_index++; } /* Wrap around */ if (order == NULL) { order = this->GetOrder(0); this->cur_implicit_order_index = 0; } assert(order != NULL); } } } else if (!suppress_implicit_orders && ((this->orders.list == NULL ? OrderList::CanAllocateItem() : this->orders.list->GetNumOrders() < MAX_VEH_ORDER_ID)) && Order::CanAllocateItem()) { /* Insert new implicit order */ Order *implicit_order = new Order(); implicit_order->MakeImplicit(this->last_station_visited); InsertOrder(this, implicit_order, this->cur_implicit_order_index); if (this->cur_implicit_order_index > 0) --this->cur_implicit_order_index; /* InsertOrder disabled creation of implicit orders for all vehicles with the same implicit order. * Reenable it for this vehicle */ uint16 &gv_flags = this->GetGroundVehicleFlags(); ClrBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); } } } this->current_order.MakeLoading(false); } if (this->last_loading_station != INVALID_STATION && this->last_loading_station != this->last_station_visited && ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 || (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0)) { IncreaseStats(Station::Get(this->last_loading_station), this, this->last_station_visited); } PrepareUnload(this); SetWindowDirty(GetWindowClassForVehicleType(this->type), this->owner); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); SetWindowDirty(WC_STATION_VIEW, this->last_station_visited); Station::Get(this->last_station_visited)->MarkTilesDirty(true); this->cur_speed = 0; this->MarkDirty(); } /** * Return all reserved cargo packets to the station and reset all packets * staged for transfer. * @param st the station where the reserved packets should go. */ void Vehicle::CancelReservation(StationID next, Station *st) { for (Vehicle *v = this; v != NULL; v = v->next) { VehicleCargoList &cargo = v->cargo; if (cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) { DEBUG(misc, 1, "cancelling cargo reservation"); cargo.Return(UINT_MAX, &st->goods[v->cargo_type].cargo, next); cargo.SetTransferLoadPlace(st->xy); } cargo.KeepAll(); } } /** * Perform all actions when leaving a station. * @pre this->current_order.IsType(OT_LOADING) */ void Vehicle::LeaveStation() { assert(this->current_order.IsType(OT_LOADING)); delete this->cargo_payment; /* Only update the timetable if the vehicle was supposed to stop here. */ if (this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false); if ((this->current_order.GetLoadType() & OLFB_NO_LOAD) == 0 || (this->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { if (this->current_order.CanLeaveWithCargo(this->last_loading_station != INVALID_STATION)) { /* Refresh next hop stats to make sure we've done that at least once * during the stop and that refit_cap == cargo_cap for each vehicle in * the consist. */ this->ResetRefitCaps(); LinkRefresher::Run(this); /* if the vehicle could load here or could stop with cargo loaded set the last loading station */ this->last_loading_station = this->last_station_visited; } else { /* if the vehicle couldn't load and had to unload or transfer everything * set the last loading station to invalid as it will leave empty. */ this->last_loading_station = INVALID_STATION; } } this->current_order.MakeLeaveStation(); Station *st = Station::Get(this->last_station_visited); this->CancelReservation(INVALID_STATION, st); st->loading_vehicles.remove(this); HideFillingPercent(&this->fill_percent_te_id); if (this->type == VEH_TRAIN && !(this->vehstatus & VS_CRASHED)) { /* Trigger station animation (trains only) */ if (IsTileType(this->tile, MP_STATION)) { TriggerStationRandomisation(st, this->tile, SRT_TRAIN_DEPARTS); TriggerStationAnimation(st, this->tile, SAT_TRAIN_DEPARTS); } SetBit(Train::From(this)->flags, VRF_LEAVING_STATION); } this->MarkDirty(); } /** * Reset all refit_cap in the consist to cargo_cap. */ void Vehicle::ResetRefitCaps() { for (Vehicle *v = this; v != NULL; v = v->Next()) v->refit_cap = v->cargo_cap; } /** * Handle the loading of the vehicle; when not it skips through dummy * orders and does nothing in all other cases. * @param mode is the non-first call for this vehicle in this tick? */ void Vehicle::HandleLoading(bool mode) { switch (this->current_order.GetType()) { case OT_LOADING: { uint wait_time = max(this->current_order.GetTimetabledWait() - this->lateness_counter, 0); /* Not the first call for this tick, or still loading */ if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) || this->current_order_time < wait_time) return; this->PlayLeaveStationSound(); this->LeaveStation(); /* Only advance to next order if we just loaded at the current one */ const Order *order = this->GetOrder(this->cur_implicit_order_index); if (order == NULL || (!order->IsType(OT_IMPLICIT) && !order->IsType(OT_GOTO_STATION)) || order->GetDestination() != this->last_station_visited) { return; } break; } case OT_DUMMY: break; default: return; } this->IncrementImplicitOrderIndex(); } /** * Get a map of cargoes and free capacities in the consist. * @param capacities Map to be filled with cargoes and capacities. */ void Vehicle::GetConsistFreeCapacities(SmallMap &capacities) const { for (const Vehicle *v = this; v != NULL; v = v->Next()) { if (v->cargo_cap == 0) continue; SmallPair *pair = capacities.Find(v->cargo_type); if (pair == capacities.End()) { pair = capacities.Append(); pair->first = v->cargo_type; pair->second = v->cargo_cap - v->cargo.StoredCount(); } else { pair->second += v->cargo_cap - v->cargo.StoredCount(); } } } uint Vehicle::GetConsistTotalCapacity() const { uint result = 0; for (const Vehicle *v = this; v != NULL; v = v->Next()) { result += v->cargo_cap; } return result; } /** * Send this vehicle to the depot using the given command(s). * @param flags the command flags (like execute and such). * @param command the command to execute. * @return the cost of the depot action. */ CommandCost Vehicle::SendToDepot(DoCommandFlag flags, DepotCommand command) { CommandCost ret = CheckOwnership(this->owner); if (ret.Failed()) return ret; if (this->vehstatus & VS_CRASHED) return CMD_ERROR; if (this->IsStoppedInDepot()) return CMD_ERROR; if (this->current_order.IsType(OT_GOTO_DEPOT)) { bool halt_in_depot = (this->current_order.GetDepotActionType() & ODATFB_HALT) != 0; if (!!(command & DEPOT_SERVICE) == halt_in_depot) { /* We called with a different DEPOT_SERVICE setting. * Now we change the setting to apply the new one and let the vehicle head for the same depot. * Note: the if is (true for requesting service == true for ordered to stop in depot) */ if (flags & DC_EXEC) { this->current_order.SetDepotOrderType(ODTF_MANUAL); this->current_order.SetDepotActionType(halt_in_depot ? ODATF_SERVICE_ONLY : ODATFB_HALT); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); } return CommandCost(); } if (command & DEPOT_DONT_CANCEL) return CMD_ERROR; // Requested no cancelation of depot orders if (flags & DC_EXEC) { /* If the orders to 'goto depot' are in the orders list (forced servicing), * then skip to the next order; effectively cancelling this forced service */ if (this->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) this->IncrementRealOrderIndex(); if (this->IsGroundVehicle()) { uint16 &gv_flags = this->GetGroundVehicleFlags(); SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); } this->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); } return CommandCost(); } TileIndex location; DestinationID destination; bool reverse; static const StringID no_depot[] = {STR_ERROR_UNABLE_TO_FIND_ROUTE_TO, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT, STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR}; if (!this->FindClosestDepot(&location, &destination, &reverse)) return_cmd_error(no_depot[this->type]); if (flags & DC_EXEC) { if (this->current_order.IsType(OT_LOADING)) this->LeaveStation(); if (this->IsGroundVehicle() && this->GetNumManualOrders() > 0) { uint16 &gv_flags = this->GetGroundVehicleFlags(); SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); } this->dest_tile = location; this->current_order.MakeGoToDepot(destination, ODTF_MANUAL); if (!(command & DEPOT_SERVICE)) this->current_order.SetDepotActionType(ODATFB_HALT); SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP); /* If there is no depot in front, reverse automatically (trains only) */ if (this->type == VEH_TRAIN && reverse) DoCommand(this->tile, this->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); if (this->type == VEH_AIRCRAFT) { Aircraft *a = Aircraft::From(this); if (a->state == FLYING && a->targetairport != destination) { /* The aircraft is now heading for a different hangar than the next in the orders */ extern void AircraftNextAirportPos_and_Order(Aircraft *a); AircraftNextAirportPos_and_Order(a); } } } return CommandCost(); } /** * Update the cached visual effect. * @param allow_power_change true if the wagon-is-powered-state may change. */ void Vehicle::UpdateVisualEffect(bool allow_power_change) { bool powered_before = HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER); const Engine *e = this->GetEngine(); /* Evaluate properties */ byte visual_effect; switch (e->type) { case VEH_TRAIN: visual_effect = e->u.rail.visual_effect; break; case VEH_ROAD: visual_effect = e->u.road.visual_effect; break; case VEH_SHIP: visual_effect = e->u.ship.visual_effect; break; default: visual_effect = 1 << VE_DISABLE_EFFECT; break; } /* Check powered wagon / visual effect callback */ if (HasBit(e->info.callback_mask, CBM_VEHICLE_VISUAL_EFFECT)) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_VISUAL_EFFECT, 0, 0, this->engine_type, this); if (callback != CALLBACK_FAILED) { if (callback >= 0x100 && e->GetGRF()->grf_version >= 8) ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_VISUAL_EFFECT, callback); callback = GB(callback, 0, 8); /* Avoid accidentally setting 'visual_effect' to the default value * Since bit 6 (disable effects) is set anyways, we can safely erase some bits. */ if (callback == VE_DEFAULT) { assert(HasBit(callback, VE_DISABLE_EFFECT)); SB(callback, VE_TYPE_START, VE_TYPE_COUNT, 0); } visual_effect = callback; } } /* Apply default values */ if (visual_effect == VE_DEFAULT || (!HasBit(visual_effect, VE_DISABLE_EFFECT) && GB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT) == VE_TYPE_DEFAULT)) { /* Only train engines have default effects. * Note: This is independent of whether the engine is a front engine or articulated part or whatever. */ if (e->type != VEH_TRAIN || e->u.rail.railveh_type == RAILVEH_WAGON || !IsInsideMM(e->u.rail.engclass, EC_STEAM, EC_MONORAIL)) { if (visual_effect == VE_DEFAULT) { visual_effect = 1 << VE_DISABLE_EFFECT; } else { SetBit(visual_effect, VE_DISABLE_EFFECT); } } else { if (visual_effect == VE_DEFAULT) { /* Also set the offset */ visual_effect = (VE_OFFSET_CENTRE - (e->u.rail.engclass == EC_STEAM ? 4 : 0)) << VE_OFFSET_START; } SB(visual_effect, VE_TYPE_START, VE_TYPE_COUNT, e->u.rail.engclass - EC_STEAM + VE_TYPE_STEAM); } } this->vcache.cached_vis_effect = visual_effect; if (!allow_power_change && powered_before != HasBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER)) { ToggleBit(this->vcache.cached_vis_effect, VE_DISABLE_WAGON_POWER); ShowNewGrfVehicleError(this->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_POWERED_WAGON, GBUG_VEH_POWERED_WAGON, false); } } static const int8 _vehicle_smoke_pos[8] = { 1, 1, 1, 0, -1, -1, -1, 0 }; /** * Call CBID_VEHICLE_SPAWN_VISUAL_EFFECT and spawn requested effects. * @param v Vehicle to create effects for. */ static void SpawnAdvancedVisualEffect(const Vehicle *v) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_SPAWN_VISUAL_EFFECT, 0, Random(), v->engine_type, v); if (callback == CALLBACK_FAILED) return; uint count = GB(callback, 0, 2); bool auto_center = HasBit(callback, 13); bool auto_rotate = !HasBit(callback, 14); int8 l_center = 0; if (auto_center) { /* For road vehicles: Compute offset from vehicle position to vehicle center */ if (v->type == VEH_ROAD) l_center = -(int)(VEHICLE_LENGTH - RoadVehicle::From(v)->gcache.cached_veh_length) / 2; } else { /* For trains: Compute offset from vehicle position to sprite position */ if (v->type == VEH_TRAIN) l_center = (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2; } Direction l_dir = v->direction; if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) l_dir = ReverseDir(l_dir); Direction t_dir = ChangeDir(l_dir, DIRDIFF_90RIGHT); int8 x_center = _vehicle_smoke_pos[l_dir] * l_center; int8 y_center = _vehicle_smoke_pos[t_dir] * l_center; for (uint i = 0; i < count; i++) { uint32 reg = GetRegister(0x100 + i); uint type = GB(reg, 0, 8); int8 x = GB(reg, 8, 8); int8 y = GB(reg, 16, 8); int8 z = GB(reg, 24, 8); if (auto_rotate) { int8 l = x; int8 t = y; x = _vehicle_smoke_pos[l_dir] * l + _vehicle_smoke_pos[t_dir] * t; y = _vehicle_smoke_pos[t_dir] * l - _vehicle_smoke_pos[l_dir] * t; } if (type >= 0xF0) { switch (type) { case 0xF1: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_STEAM_SMOKE); break; case 0xF2: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_DIESEL_SMOKE); break; case 0xF3: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_ELECTRIC_SPARK); break; case 0xFA: CreateEffectVehicleRel(v, x_center + x, y_center + y, z, EV_BREAKDOWN_SMOKE_AIRCRAFT); break; default: break; } } } } /** * Draw visual effects (smoke and/or sparks) for a vehicle chain. * @pre this->IsPrimaryVehicle() */ void Vehicle::ShowVisualEffect() const { assert(this->IsPrimaryVehicle()); bool sound = false; /* Do not show any smoke when: * - vehicle smoke is disabled by the player * - the vehicle is slowing down or stopped (by the player) * - the vehicle is moving very slowly */ if (_settings_game.vehicle.smoke_amount == 0 || this->vehstatus & (VS_TRAIN_SLOWING | VS_STOPPED) || this->cur_speed < 2) { return; } /* Use the speed as limited by underground and orders. */ uint max_speed = this->GetCurrentMaxSpeed(); if (this->type == VEH_TRAIN) { const Train *t = Train::From(this); /* For trains, do not show any smoke when: * - the train is reversing * - is entering a station with an order to stop there and its speed is equal to maximum station entering speed */ if (HasBit(t->flags, VRF_REVERSING) || (IsRailStationTile(t->tile) && t->IsFrontEngine() && t->current_order.ShouldStopAtStation(t, GetStationIndex(t->tile)) && t->cur_speed >= max_speed)) { return; } } const Vehicle *v = this; do { bool advanced = HasBit(v->vcache.cached_vis_effect, VE_ADVANCED_EFFECT); int effect_offset = GB(v->vcache.cached_vis_effect, VE_OFFSET_START, VE_OFFSET_COUNT) - VE_OFFSET_CENTRE; VisualEffectSpawnModel effect_model = VESM_NONE; if (advanced) { effect_offset = VE_OFFSET_CENTRE; effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, 0, VE_ADVANCED_EFFECT); if (effect_model >= VESM_END) effect_model = VESM_NONE; // unknown spawning model } else { effect_model = (VisualEffectSpawnModel)GB(v->vcache.cached_vis_effect, VE_TYPE_START, VE_TYPE_COUNT); assert(effect_model != (VisualEffectSpawnModel)VE_TYPE_DEFAULT); // should have been resolved by UpdateVisualEffect assert_compile((uint)VESM_STEAM == (uint)VE_TYPE_STEAM); assert_compile((uint)VESM_DIESEL == (uint)VE_TYPE_DIESEL); assert_compile((uint)VESM_ELECTRIC == (uint)VE_TYPE_ELECTRIC); } /* Show no smoke when: * - Smoke has been disabled for this vehicle * - The vehicle is not visible * - The vehicle is under a bridge * - The vehicle is on a depot tile * - The vehicle is on a tunnel tile * - The vehicle is a train engine that is currently unpowered */ if (effect_model == VESM_NONE || v->vehstatus & VS_HIDDEN || IsBridgeAbove(v->tile) || IsDepotTile(v->tile) || IsTunnelTile(v->tile) || (v->type == VEH_TRAIN && !HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) { continue; } EffectVehicleType evt = EV_END; switch (effect_model) { case VESM_STEAM: /* Steam smoke - amount is gradually falling until vehicle reaches its maximum speed, after that it's normal. * Details: while vehicle's current speed is gradually increasing, steam plumes' density decreases by one third each * third of its maximum speed spectrum. Steam emission finally normalises at very close to vehicle's maximum speed. * REGULATION: * - instead of 1, 4 / 2^smoke_amount (max. 2) is used to provide sufficient regulation to steam puffs' amount. */ if (GB(v->tick_counter, 0, ((4 >> _settings_game.vehicle.smoke_amount) + ((this->cur_speed * 3) / max_speed))) == 0) { evt = EV_STEAM_SMOKE; } break; case VESM_DIESEL: { /* Diesel smoke - thicker when vehicle is starting, gradually subsiding till it reaches its maximum speed * when smoke emission stops. * Details: Vehicle's (max.) speed spectrum is divided into 32 parts. When max. speed is reached, chance for smoke * emission erodes by 32 (1/4). For trains, power and weight come in handy too to either increase smoke emission in * 6 steps (1000HP each) if the power is low or decrease smoke emission in 6 steps (512 tonnes each) if the train * isn't overweight. Power and weight contributions are expressed in a way that neither extreme power, nor * extreme weight can ruin the balance (e.g. FreightWagonMultiplier) in the formula. When the vehicle reaches * maximum speed no diesel_smoke is emitted. * REGULATION: * - up to which speed a diesel vehicle is emitting smoke (with reduced/small setting only until 1/2 of max_speed), * - in Chance16 - the last value is 512 / 2^smoke_amount (max. smoke when 128 = smoke_amount of 2). */ int power_weight_effect = 0; if (v->type == VEH_TRAIN) { power_weight_effect = (32 >> (Train::From(this)->gcache.cached_power >> 10)) - (32 >> (Train::From(this)->gcache.cached_weight >> 9)); } if (this->cur_speed < (max_speed >> (2 >> _settings_game.vehicle.smoke_amount)) && Chance16((64 - ((this->cur_speed << 5) / max_speed) + power_weight_effect), (512 >> _settings_game.vehicle.smoke_amount))) { evt = EV_DIESEL_SMOKE; } break; } case VESM_ELECTRIC: /* Electric train's spark - more often occurs when train is departing (more load) * Details: Electric locomotives are usually at least twice as powerful as their diesel counterparts, so spark * emissions are kept simple. Only when starting, creating huge force are sparks more likely to happen, but when * reaching its max. speed, quarter by quarter of it, chance decreases until the usual 2,22% at train's top speed. * REGULATION: * - in Chance16 the last value is 360 / 2^smoke_amount (max. sparks when 90 = smoke_amount of 2). */ if (GB(v->tick_counter, 0, 2) == 0 && Chance16((6 - ((this->cur_speed << 2) / max_speed)), (360 >> _settings_game.vehicle.smoke_amount))) { evt = EV_ELECTRIC_SPARK; } break; default: NOT_REACHED(); } if (evt != EV_END && advanced) { sound = true; SpawnAdvancedVisualEffect(v); } else if (evt != EV_END) { sound = true; /* The effect offset is relative to a point 4 units behind the vehicle's * front (which is the center of an 8/8 vehicle). Shorter vehicles need a * correction factor. */ if (v->type == VEH_TRAIN) effect_offset += (VEHICLE_LENGTH - Train::From(v)->gcache.cached_veh_length) / 2; int x = _vehicle_smoke_pos[v->direction] * effect_offset; int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset; if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION)) { x = -x; y = -y; } CreateEffectVehicleRel(v, x, y, 10, evt); } } while ((v = v->Next()) != NULL); if (sound) PlayVehicleSound(this, VSE_VISUAL_EFFECT); } /** * Set the next vehicle of this vehicle. * @param next the next vehicle. NULL removes the next vehicle. */ void Vehicle::SetNext(Vehicle *next) { assert(this != next); if (this->next != NULL) { /* We had an old next vehicle. Update the first and previous pointers */ for (Vehicle *v = this->next; v != NULL; v = v->Next()) { v->first = this->next; } this->next->previous = NULL; } this->next = next; if (this->next != NULL) { /* A new next vehicle. Update the first and previous pointers */ if (this->next->previous != NULL) this->next->previous->next = NULL; this->next->previous = this; for (Vehicle *v = this->next; v != NULL; v = v->Next()) { v->first = this->first; } } } /** * Adds this vehicle to a shared vehicle chain. * @param shared_chain a vehicle of the chain with shared vehicles. * @pre !this->IsOrderListShared() */ void Vehicle::AddToShared(Vehicle *shared_chain) { assert(this->previous_shared == NULL && this->next_shared == NULL); if (shared_chain->orders.list == NULL) { assert(shared_chain->previous_shared == NULL); assert(shared_chain->next_shared == NULL); this->orders.list = shared_chain->orders.list = new OrderList(NULL, shared_chain); } this->next_shared = shared_chain->next_shared; this->previous_shared = shared_chain; shared_chain->next_shared = this; if (this->next_shared != NULL) this->next_shared->previous_shared = this; shared_chain->orders.list->AddVehicle(this); } /** * Removes the vehicle from the shared order list. */ void Vehicle::RemoveFromShared() { /* Remember if we were first and the old window number before RemoveVehicle() * as this changes first if needed. */ bool were_first = (this->FirstShared() == this); VehicleListIdentifier vli(VL_SHARED_ORDERS, this->type, this->owner, this->FirstShared()->index); this->orders.list->RemoveVehicle(this); if (!were_first) { /* We are not the first shared one, so only relink our previous one. */ this->previous_shared->next_shared = this->NextShared(); } if (this->next_shared != NULL) this->next_shared->previous_shared = this->previous_shared; if (this->orders.list->GetNumVehicles() == 1) { /* When there is only one vehicle, remove the shared order list window. */ DeleteWindowById(GetWindowClassForVehicleType(this->type), vli.Pack()); InvalidateVehicleOrder(this->FirstShared(), 0); } else if (were_first) { /* If we were the first one, update to the new first one. * Note: FirstShared() is already the new first */ InvalidateWindowData(GetWindowClassForVehicleType(this->type), vli.Pack(), this->FirstShared()->index | (1U << 31)); } this->next_shared = NULL; this->previous_shared = NULL; } void VehiclesYearlyLoop() { Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->IsPrimaryVehicle()) { /* show warning if vehicle is not generating enough income last 2 years (corresponds to a red icon in the vehicle list) */ Money profit = v->GetDisplayProfitThisYear(); if (v->age >= 730 && profit < 0) { if (_settings_client.gui.vehicle_income_warn && v->owner == _local_company) { SetDParam(0, v->index); SetDParam(1, profit); AddVehicleAdviceNewsItem(STR_NEWS_VEHICLE_IS_UNPROFITABLE, v->index); } AI::NewEvent(v->owner, new ScriptEventVehicleUnprofitable(v->index)); } v->profit_last_year = v->profit_this_year; v->profit_this_year = 0; SetWindowDirty(WC_VEHICLE_DETAILS, v->index); } } GroupStatistics::UpdateProfits(); SetWindowClassesDirty(WC_TRAINS_LIST); SetWindowClassesDirty(WC_SHIPS_LIST); SetWindowClassesDirty(WC_ROADVEH_LIST); SetWindowClassesDirty(WC_AIRCRAFT_LIST); } /** * Can this station be used by the given engine type? * @param engine_type the type of vehicles to test * @param st the station to test for * @return true if and only if the vehicle of the type can use this station. * @note For road vehicles the Vehicle is needed to determine whether it can * use the station. This function will return true for road vehicles * when at least one of the facilities is available. */ bool CanVehicleUseStation(EngineID engine_type, const Station *st) { const Engine *e = Engine::GetIfValid(engine_type); assert(e != NULL); switch (e->type) { case VEH_TRAIN: return (st->facilities & FACIL_TRAIN) != 0; case VEH_ROAD: /* For road vehicles we need the vehicle to know whether it can actually * use the station, but if it doesn't have facilities for RVs it is * certainly not possible that the station can be used. */ return (st->facilities & (FACIL_BUS_STOP | FACIL_TRUCK_STOP)) != 0; case VEH_SHIP: return (st->facilities & FACIL_DOCK) != 0; case VEH_AIRCRAFT: return (st->facilities & FACIL_AIRPORT) != 0 && (st->airport.GetFTA()->flags & (e->u.air.subtype & AIR_CTOL ? AirportFTAClass::AIRPLANES : AirportFTAClass::HELICOPTERS)) != 0; default: return false; } } /** * Can this station be used by the given vehicle? * @param v the vehicle to test * @param st the station to test for * @return true if and only if the vehicle can use this station. */ bool CanVehicleUseStation(const Vehicle *v, const Station *st) { if (v->type == VEH_ROAD) return st->GetPrimaryRoadStop(RoadVehicle::From(v)) != NULL; return CanVehicleUseStation(v->engine_type, st); } /** * Access the ground vehicle cache of the vehicle. * @pre The vehicle is a #GroundVehicle. * @return #GroundVehicleCache of the vehicle. */ GroundVehicleCache *Vehicle::GetGroundVehicleCache() { assert(this->IsGroundVehicle()); if (this->type == VEH_TRAIN) { return &Train::From(this)->gcache; } else { return &RoadVehicle::From(this)->gcache; } } /** * Access the ground vehicle cache of the vehicle. * @pre The vehicle is a #GroundVehicle. * @return #GroundVehicleCache of the vehicle. */ const GroundVehicleCache *Vehicle::GetGroundVehicleCache() const { assert(this->IsGroundVehicle()); if (this->type == VEH_TRAIN) { return &Train::From(this)->gcache; } else { return &RoadVehicle::From(this)->gcache; } } /** * Access the ground vehicle flags of the vehicle. * @pre The vehicle is a #GroundVehicle. * @return #GroundVehicleFlags of the vehicle. */ uint16 &Vehicle::GetGroundVehicleFlags() { assert(this->IsGroundVehicle()); if (this->type == VEH_TRAIN) { return Train::From(this)->gv_flags; } else { return RoadVehicle::From(this)->gv_flags; } } /** * Access the ground vehicle flags of the vehicle. * @pre The vehicle is a #GroundVehicle. * @return #GroundVehicleFlags of the vehicle. */ const uint16 &Vehicle::GetGroundVehicleFlags() const { assert(this->IsGroundVehicle()); if (this->type == VEH_TRAIN) { return Train::From(this)->gv_flags; } else { return RoadVehicle::From(this)->gv_flags; } } /** * Calculates the set of vehicles that will be affected by a given selection. * @param set [inout] Set of affected vehicles. * @param v First vehicle of the selection. * @param num_vehicles Number of vehicles in the selection (not counting articulated parts). * @pre \a set must be empty. * @post \a set will contain the vehicles that will be refitted. */ void GetVehicleSet(VehicleSet &set, Vehicle *v, uint8 num_vehicles) { if (v->type == VEH_TRAIN) { Train *u = Train::From(v); /* Only include whole vehicles, so start with the first articulated part */ u = u->GetFirstEnginePart(); /* Include num_vehicles vehicles, not counting articulated parts */ for (; u != NULL && num_vehicles > 0; num_vehicles--) { do { /* Include current vehicle in the selection. */ set.Include(u->index); /* If the vehicle is multiheaded, add the other part too. */ if (u->IsMultiheaded()) set.Include(u->other_multiheaded_part->index); u = u->Next(); } while (u != NULL && u->IsArticulatedPart()); } } } openttd-1.5.3/src/signal.cpp0000644000000000000000000005114712627373442014465 0ustar rootroot/* $Id: signal.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 signal.cpp functions related to rail signals updating */ #include "stdafx.h" #include "debug.h" #include "station_map.h" #include "tunnelbridge_map.h" #include "vehicle_func.h" #include "viewport_func.h" #include "train.h" #include "company_base.h" #include "safeguards.h" /** these are the maximums used for updating signal blocks */ static const uint SIG_TBU_SIZE = 64; ///< number of signals entering to block static const uint SIG_TBD_SIZE = 256; ///< number of intersections - open nodes in current block static const uint SIG_GLOB_SIZE = 128; ///< number of open blocks (block can be opened more times until detected) static const uint SIG_GLOB_UPDATE = 64; ///< how many items need to be in _globset to force update assert_compile(SIG_GLOB_UPDATE <= SIG_GLOB_SIZE); /** incidating trackbits with given enterdir */ static const TrackBits _enterdir_to_trackbits[DIAGDIR_END] = { TRACK_BIT_3WAY_NE, TRACK_BIT_3WAY_SE, TRACK_BIT_3WAY_SW, TRACK_BIT_3WAY_NW }; /** incidating trackdirbits with given enterdir */ static const TrackdirBits _enterdir_to_trackdirbits[DIAGDIR_END] = { TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S, TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_RIGHT_N, TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N, TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S }; /** * Set containing 'items' items of 'tile and Tdir' * No tree structure is used because it would cause * slowdowns in most usual cases */ template struct SmallSet { private: uint n; // actual number of units bool overflowed; // did we try to overflow the set? const char *name; // name, used for debugging purposes... /** Element of set */ struct SSdata { TileIndex tile; Tdir dir; } data[items]; public: /** Constructor - just set default values and 'name' */ SmallSet(const char *name) : n(0), overflowed(false), name(name) { } /** Reset variables to default values */ void Reset() { this->n = 0; this->overflowed = false; } /** * Returns value of 'overflowed' * @return did we try to overflow the set? */ bool Overflowed() { return this->overflowed; } /** * Checks for empty set * @return is the set empty? */ bool IsEmpty() { return this->n == 0; } /** * Checks for full set * @return is the set full? */ bool IsFull() { return this->n == lengthof(data); } /** * Reads the number of items * @return current number of items */ uint Items() { return this->n; } /** * Tries to remove first instance of given tile and dir * @param tile tile * @param dir and dir to remove * @return element was found and removed */ bool Remove(TileIndex tile, Tdir dir) { for (uint i = 0; i < this->n; i++) { if (this->data[i].tile == tile && this->data[i].dir == dir) { this->data[i] = this->data[--this->n]; return true; } } return false; } /** * Tries to find given tile and dir in the set * @param tile tile * @param dir and dir to find * @return true iff the tile & dir element was found */ bool IsIn(TileIndex tile, Tdir dir) { for (uint i = 0; i < this->n; i++) { if (this->data[i].tile == tile && this->data[i].dir == dir) return true; } return false; } /** * Adds tile & dir into the set, checks for full set * Sets the 'overflowed' flag if the set was full * @param tile tile * @param dir and dir to add * @return true iff the item could be added (set wasn't full) */ bool Add(TileIndex tile, Tdir dir) { if (this->IsFull()) { overflowed = true; DEBUG(misc, 0, "SignalSegment too complex. Set %s is full (maximum %d)", name, items); return false; // set is full } this->data[this->n].tile = tile; this->data[this->n].dir = dir; this->n++; return true; } /** * Reads the last added element into the set * @param tile pointer where tile is written to * @param dir pointer where dir is written to * @return false iff the set was empty */ bool Get(TileIndex *tile, Tdir *dir) { if (this->n == 0) return false; this->n--; *tile = this->data[this->n].tile; *dir = this->data[this->n].dir; return true; } }; static SmallSet _tbuset("_tbuset"); ///< set of signals that will be updated static SmallSet _tbdset("_tbdset"); ///< set of open nodes in current signal block static SmallSet _globset("_globset"); ///< set of places to be updated in following runs /** Check whether there is a train on rail, not in a depot */ static Vehicle *TrainOnTileEnum(Vehicle *v, void *) { if (v->type != VEH_TRAIN || Train::From(v)->track == TRACK_BIT_DEPOT) return NULL; return v; } /** * Perform some operations before adding data into Todo set * The new and reverse direction is removed from _globset, because we are sure * it doesn't need to be checked again * Also, remove reverse direction from _tbdset * This is the 'core' part so the graph searching won't enter any tile twice * * @param t1 tile we are entering * @param d1 direction (tile side) we are entering * @param t2 tile we are leaving * @param d2 direction (tile side) we are leaving * @return false iff reverse direction was in Todo set */ static inline bool CheckAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2) { _globset.Remove(t1, d1); // it can be in Global but not in Todo _globset.Remove(t2, d2); // remove in all cases assert(!_tbdset.IsIn(t1, d1)); // it really shouldn't be there already if (_tbdset.Remove(t2, d2)) return false; return true; } /** * Perform some operations before adding data into Todo set * The new and reverse direction is removed from Global set, because we are sure * it doesn't need to be checked again * Also, remove reverse direction from Todo set * This is the 'core' part so the graph searching won't enter any tile twice * * @param t1 tile we are entering * @param d1 direction (tile side) we are entering * @param t2 tile we are leaving * @param d2 direction (tile side) we are leaving * @return false iff the Todo buffer would be overrun */ static inline bool MaybeAddToTodoSet(TileIndex t1, DiagDirection d1, TileIndex t2, DiagDirection d2) { if (!CheckAddToTodoSet(t1, d1, t2, d2)) return true; return _tbdset.Add(t1, d1); } /** Current signal block state flags */ enum SigFlags { SF_NONE = 0, SF_TRAIN = 1 << 0, ///< train found in segment SF_EXIT = 1 << 1, ///< exitsignal found SF_EXIT2 = 1 << 2, ///< two or more exits found SF_GREEN = 1 << 3, ///< green exitsignal found SF_GREEN2 = 1 << 4, ///< two or more green exits found SF_FULL = 1 << 5, ///< some of buffers was full, do not continue SF_PBS = 1 << 6, ///< pbs signal found }; DECLARE_ENUM_AS_BIT_SET(SigFlags) /** * Search signal block * * @param owner owner whose signals we are updating * @return SigFlags */ static SigFlags ExploreSegment(Owner owner) { SigFlags flags = SF_NONE; TileIndex tile; DiagDirection enterdir; while (_tbdset.Get(&tile, &enterdir)) { TileIndex oldtile = tile; // tile we are leaving DiagDirection exitdir = enterdir == INVALID_DIAGDIR ? INVALID_DIAGDIR : ReverseDiagDir(enterdir); // expected new exit direction (for straight line) switch (GetTileType(tile)) { case MP_RAILWAY: { if (GetTileOwner(tile) != owner) continue; // do not propagate signals on others' tiles (remove for tracksharing) if (IsRailDepot(tile)) { if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; exitdir = GetRailDepotDirection(tile); tile += TileOffsByDiagDir(exitdir); enterdir = ReverseDiagDir(exitdir); break; } else if (enterdir == GetRailDepotDirection(tile)) { // entered a depot if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; continue; } else { continue; } } assert(IsValidDiagDirection(enterdir)); TrackBits tracks = GetTrackBits(tile); // trackbits of tile TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) { // there is exactly one incidating track, no need to check tracks = tracks_masked; /* If no train detected yet, and there is not no train -> there is a train -> set the flag */ if (!(flags & SF_TRAIN) && EnsureNoTrainOnTrackBits(tile, tracks).Failed()) flags |= SF_TRAIN; } else { if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; } if (HasSignals(tile)) { // there is exactly one track - not zero, because there is exit from this tile Track track = TrackBitsToTrack(tracks_masked); // mask TRACK_BIT_X and Y too if (HasSignalOnTrack(tile, track)) { // now check whole track, not trackdir SignalType sig = GetSignalType(tile, track); Trackdir trackdir = (Trackdir)FindFirstBit((tracks * 0x101) & _enterdir_to_trackdirbits[enterdir]); Trackdir reversedir = ReverseTrackdir(trackdir); /* add (tile, reversetrackdir) to 'to-be-updated' set when there is * ANY conventional signal in REVERSE direction * (if it is a presignal EXIT and it changes, it will be added to 'to-be-done' set later) */ if (HasSignalOnTrackdir(tile, reversedir)) { if (IsPbsSignal(sig)) { flags |= SF_PBS; } else if (!_tbuset.Add(tile, reversedir)) { return flags | SF_FULL; } } if (HasSignalOnTrackdir(tile, trackdir) && !IsOnewaySignal(tile, track)) flags |= SF_PBS; /* if it is a presignal EXIT in OUR direction and we haven't found 2 green exits yes, do special check */ if (!(flags & SF_GREEN2) && IsPresignalExit(tile, track) && HasSignalOnTrackdir(tile, trackdir)) { // found presignal exit if (flags & SF_EXIT) flags |= SF_EXIT2; // found two (or more) exits flags |= SF_EXIT; // found at least one exit - allow for compiler optimizations if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_GREEN) { // found green presignal exit if (flags & SF_GREEN) flags |= SF_GREEN2; flags |= SF_GREEN; } } continue; } } for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { // test all possible exit directions if (dir != enterdir && (tracks & _enterdir_to_trackbits[dir])) { // any track incidating? TileIndex newtile = tile + TileOffsByDiagDir(dir); // new tile to check DiagDirection newdir = ReverseDiagDir(dir); // direction we are entering from if (!MaybeAddToTodoSet(newtile, newdir, tile, dir)) return flags | SF_FULL; } } continue; // continue the while() loop } case MP_STATION: if (!HasStationRail(tile)) continue; if (GetTileOwner(tile) != owner) continue; if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; tile += TileOffsByDiagDir(exitdir); break; case MP_ROAD: if (!IsLevelCrossing(tile)) continue; if (GetTileOwner(tile) != owner) continue; if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; tile += TileOffsByDiagDir(exitdir); break; case MP_TUNNELBRIDGE: { if (GetTileOwner(tile) != owner) continue; if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue; DiagDirection dir = GetTunnelBridgeDirection(tile); if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; enterdir = dir; exitdir = ReverseDiagDir(dir); tile += TileOffsByDiagDir(exitdir); // just skip to next tile } else { // NOT incoming from the wormhole! if (ReverseDiagDir(enterdir) != dir) continue; if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile enterdir = INVALID_DIAGDIR; exitdir = INVALID_DIAGDIR; } } break; default: continue; // continue the while() loop } if (!MaybeAddToTodoSet(tile, enterdir, oldtile, exitdir)) return flags | SF_FULL; } return flags; } /** * Update signals around segment in _tbuset * * @param flags info about segment */ static void UpdateSignalsAroundSegment(SigFlags flags) { TileIndex tile; Trackdir trackdir; while (_tbuset.Get(&tile, &trackdir)) { assert(HasSignalOnTrackdir(tile, trackdir)); SignalType sig = GetSignalType(tile, TrackdirToTrack(trackdir)); SignalState newstate = SIGNAL_STATE_GREEN; /* determine whether the new state is red */ if (flags & SF_TRAIN) { /* train in the segment */ newstate = SIGNAL_STATE_RED; } else { /* is it a bidir combo? - then do not count its other signal direction as exit */ if (sig == SIGTYPE_COMBO && HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir))) { /* at least one more exit */ if ((flags & SF_EXIT2) && /* no green exit */ (!(flags & SF_GREEN) || /* only one green exit, and it is this one - so all other exits are red */ (!(flags & SF_GREEN2) && GetSignalStateByTrackdir(tile, ReverseTrackdir(trackdir)) == SIGNAL_STATE_GREEN))) { newstate = SIGNAL_STATE_RED; } } else { // entry, at least one exit, no green exit if (IsPresignalEntry(tile, TrackdirToTrack(trackdir)) && (flags & SF_EXIT) && !(flags & SF_GREEN)) newstate = SIGNAL_STATE_RED; } } /* only when the state changes */ if (newstate != GetSignalStateByTrackdir(tile, trackdir)) { if (IsPresignalExit(tile, TrackdirToTrack(trackdir))) { /* for pre-signal exits, add block to the global set */ DiagDirection exitdir = TrackdirToExitdir(ReverseTrackdir(trackdir)); _globset.Add(tile, exitdir); // do not check for full global set, first update all signals } SetSignalStateByTrackdir(tile, trackdir, newstate); MarkTileDirtyByTile(tile); } } } /** Reset all sets after one set overflowed */ static inline void ResetSets() { _tbuset.Reset(); _tbdset.Reset(); _globset.Reset(); } /** * Updates blocks in _globset buffer * * @param owner company whose signals we are updating * @return state of the first block from _globset * @pre Company::IsValidID(owner) */ static SigSegState UpdateSignalsInBuffer(Owner owner) { assert(Company::IsValidID(owner)); bool first = true; // first block? SigSegState state = SIGSEG_FREE; // value to return TileIndex tile; DiagDirection dir; while (_globset.Get(&tile, &dir)) { assert(_tbuset.IsEmpty()); assert(_tbdset.IsEmpty()); /* After updating signal, data stored are always MP_RAILWAY with signals. * Other situations happen when data are from outside functions - * modification of railbits (including both rail building and removal), * train entering/leaving block, train leaving depot... */ switch (GetTileType(tile)) { case MP_TUNNELBRIDGE: /* 'optimization assert' - do not try to update signals when it is not needed */ assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL); assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile))); _tbdset.Add(tile, INVALID_DIAGDIR); // we can safely start from wormhole centre _tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR); break; case MP_RAILWAY: if (IsRailDepot(tile)) { /* 'optimization assert' do not try to update signals in other cases */ assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile)); _tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside break; } /* FALL THROUGH */ case MP_STATION: case MP_ROAD: if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) { /* only add to set when there is some 'interesting' track */ _tbdset.Add(tile, dir); _tbdset.Add(tile + TileOffsByDiagDir(dir), ReverseDiagDir(dir)); break; } /* FALL THROUGH */ default: /* jump to next tile */ tile = tile + TileOffsByDiagDir(dir); dir = ReverseDiagDir(dir); if ((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & _enterdir_to_trackbits[dir]) != TRACK_BIT_NONE) { _tbdset.Add(tile, dir); break; } /* happens when removing a rail that wasn't connected at one or both sides */ continue; // continue the while() loop } assert(!_tbdset.Overflowed()); // it really shouldn't overflow by these one or two items assert(!_tbdset.IsEmpty()); // it wouldn't hurt anyone, but shouldn't happen too SigFlags flags = ExploreSegment(owner); if (first) { first = false; /* SIGSEG_FREE is set by default */ if (flags & SF_PBS) { state = SIGSEG_PBS; } else if ((flags & SF_TRAIN) || ((flags & SF_EXIT) && !(flags & SF_GREEN)) || (flags & SF_FULL)) { state = SIGSEG_FULL; } } /* do not do anything when some buffer was full */ if (flags & SF_FULL) { ResetSets(); // free all sets break; } UpdateSignalsAroundSegment(flags); } return state; } static Owner _last_owner = INVALID_OWNER; ///< last owner whose track was put into _globset /** * Update signals in buffer * Called from 'outside' */ void UpdateSignalsInBuffer() { if (!_globset.IsEmpty()) { UpdateSignalsInBuffer(_last_owner); _last_owner = INVALID_OWNER; // invalidate } } /** * Add track to signal update buffer * * @param tile tile where we start * @param track track at which ends we will update signals * @param owner owner whose signals we will update */ void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner) { static const DiagDirection _search_dir_1[] = { DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE }; static const DiagDirection _search_dir_2[] = { DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE }; /* do not allow signal updates for two companies in one run */ assert(_globset.IsEmpty() || owner == _last_owner); _last_owner = owner; _globset.Add(tile, _search_dir_1[track]); _globset.Add(tile, _search_dir_2[track]); if (_globset.Items() >= SIG_GLOB_UPDATE) { /* too many items, force update */ UpdateSignalsInBuffer(_last_owner); _last_owner = INVALID_OWNER; } } /** * Add side of tile to signal update buffer * * @param tile tile where we start * @param side side of tile * @param owner owner whose signals we will update */ void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner) { /* do not allow signal updates for two companies in one run */ assert(_globset.IsEmpty() || owner == _last_owner); _last_owner = owner; _globset.Add(tile, side); if (_globset.Items() >= SIG_GLOB_UPDATE) { /* too many items, force update */ UpdateSignalsInBuffer(_last_owner); _last_owner = INVALID_OWNER; } } /** * Update signals, starting at one side of a tile * Will check tile next to this at opposite side too * * @see UpdateSignalsInBuffer() * @param tile tile where we start * @param side side of tile * @param owner owner whose signals we will update * @return the state of the signal segment */ SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner) { assert(_globset.IsEmpty()); _globset.Add(tile, side); return UpdateSignalsInBuffer(owner); } /** * Update signals at segments that are at both ends of * given (existent or non-existent) track * * @see UpdateSignalsInBuffer() * @param tile tile where we start * @param track track at which ends we will update signals * @param owner owner whose signals we will update */ void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner) { assert(_globset.IsEmpty()); AddTrackToSignalBuffer(tile, track, owner); UpdateSignalsInBuffer(owner); } openttd-1.5.3/src/terraform_gui.h0000644000000000000000000000161212627373433015512 0ustar rootroot/* $Id: terraform_gui.h 21608 2010-12-23 14:24:34Z alberth $ */ /* * 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 terraform_gui.h GUI stuff related to terraforming. */ #ifndef TERRAFORM_GUI_H #define TERRAFORM_GUI_H #include "window_type.h" Window *ShowTerraformToolbar(Window *link = NULL); Window *ShowEditorTerraformToolbar(); #endif /* TERRAFORM_GUI_H */ openttd-1.5.3/src/date_gui.h0000644000000000000000000000222712627373442014431 0ustar rootroot/* $Id: date_gui.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 date_gui.h Functions related to the graphical selection of a date. */ #ifndef DATE_GUI_H #define DATE_GUI_H #include "date_type.h" #include "window_type.h" /** * Callback for when a date has been chosen * @param w the window that sends the callback * @param date the date that has been chosen */ typedef void SetDateCallback(const Window *w, Date date); void ShowSetDateWindow(Window *parent, int window_number, Date initial_date, Year min_year, Year max_year, SetDateCallback *callback); #endif /* DATE_GUI_H */ openttd-1.5.3/src/order_gui.cpp0000644000000000000000000020036512627373442015165 0ustar rootroot/* $Id: order_gui.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 order_gui.cpp GUI related to orders. */ #include "stdafx.h" #include "command_func.h" #include "viewport_func.h" #include "depot_map.h" #include "roadveh.h" #include "timetable.h" #include "strings_func.h" #include "company_func.h" #include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" #include "textbuf_gui.h" #include "string_func.h" #include "tilehighlight_func.h" #include "network/network.h" #include "station_base.h" #include "waypoint_base.h" #include "core/geometry_func.hpp" #include "hotkeys.h" #include "aircraft.h" #include "engine_func.h" #include "widgets/order_widget.h" #include "safeguards.h" /** Order load types that could be given to station orders. */ static const StringID _station_load_types[][5][5] = { { /* No refitting. */ { STR_EMPTY, INVALID_STRING_ID, STR_ORDER_FULL_LOAD, STR_ORDER_FULL_LOAD_ANY, STR_ORDER_NO_LOAD, }, { STR_ORDER_UNLOAD, INVALID_STRING_ID, STR_ORDER_UNLOAD_FULL_LOAD, STR_ORDER_UNLOAD_FULL_LOAD_ANY, STR_ORDER_UNLOAD_NO_LOAD, }, { STR_ORDER_TRANSFER, INVALID_STRING_ID, STR_ORDER_TRANSFER_FULL_LOAD, STR_ORDER_TRANSFER_FULL_LOAD_ANY, STR_ORDER_TRANSFER_NO_LOAD, }, { /* Unload and transfer do not work together. */ INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, }, { STR_ORDER_NO_UNLOAD, INVALID_STRING_ID, STR_ORDER_NO_UNLOAD_FULL_LOAD, STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY, STR_ORDER_NO_UNLOAD_NO_LOAD, } }, { /* With auto-refitting. No loading and auto-refitting do not work together. */ { STR_ORDER_AUTO_REFIT, INVALID_STRING_ID, STR_ORDER_FULL_LOAD_REFIT, STR_ORDER_FULL_LOAD_ANY_REFIT, INVALID_STRING_ID, }, { STR_ORDER_UNLOAD_REFIT, INVALID_STRING_ID, STR_ORDER_UNLOAD_FULL_LOAD_REFIT, STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT, INVALID_STRING_ID, }, { STR_ORDER_TRANSFER_REFIT, INVALID_STRING_ID, STR_ORDER_TRANSFER_FULL_LOAD_REFIT, STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT, INVALID_STRING_ID, }, { /* Unload and transfer do not work together. */ INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, INVALID_STRING_ID, }, { STR_ORDER_NO_UNLOAD_REFIT, INVALID_STRING_ID, STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT, STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT, INVALID_STRING_ID, } } }; static const StringID _order_non_stop_drowdown[] = { STR_ORDER_GO_TO, STR_ORDER_GO_NON_STOP_TO, STR_ORDER_GO_VIA, STR_ORDER_GO_NON_STOP_VIA, INVALID_STRING_ID }; static const StringID _order_full_load_drowdown[] = { STR_ORDER_DROP_LOAD_IF_POSSIBLE, STR_EMPTY, STR_ORDER_DROP_FULL_LOAD_ALL, STR_ORDER_DROP_FULL_LOAD_ANY, STR_ORDER_DROP_NO_LOADING, INVALID_STRING_ID }; static const StringID _order_unload_drowdown[] = { STR_ORDER_DROP_UNLOAD_IF_ACCEPTED, STR_ORDER_DROP_UNLOAD, STR_ORDER_DROP_TRANSFER, STR_EMPTY, STR_ORDER_DROP_NO_UNLOADING, INVALID_STRING_ID }; static const StringID _order_goto_dropdown[] = { STR_ORDER_GO_TO, STR_ORDER_GO_TO_NEAREST_DEPOT, STR_ORDER_CONDITIONAL, STR_ORDER_SHARE, INVALID_STRING_ID }; static const StringID _order_goto_dropdown_aircraft[] = { STR_ORDER_GO_TO, STR_ORDER_GO_TO_NEAREST_HANGAR, STR_ORDER_CONDITIONAL, STR_ORDER_SHARE, INVALID_STRING_ID }; /** Variables for conditional orders; this defines the order of appearance in the dropdown box */ static const OrderConditionVariable _order_conditional_variable[] = { OCV_LOAD_PERCENTAGE, OCV_RELIABILITY, OCV_MAX_SPEED, OCV_AGE, OCV_REMAINING_LIFETIME, OCV_REQUIRES_SERVICE, OCV_UNCONDITIONALLY, }; static const StringID _order_conditional_condition[] = { STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS, STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS, STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN, STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS, STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN, STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS, STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE, STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE, INVALID_STRING_ID, }; extern uint ConvertSpeedToDisplaySpeed(uint speed); extern uint ConvertDisplaySpeedToSpeed(uint speed); static const StringID _order_depot_action_dropdown[] = { STR_ORDER_DROP_GO_ALWAYS_DEPOT, STR_ORDER_DROP_SERVICE_DEPOT, STR_ORDER_DROP_HALT_DEPOT, INVALID_STRING_ID }; static int DepotActionStringIndex(const Order *order) { if (order->GetDepotActionType() & ODATFB_HALT) { return DA_STOP; } else if (order->GetDepotOrderType() & ODTFB_SERVICE) { return DA_SERVICE; } else { return DA_ALWAYS_GO; } } static const StringID _order_refit_action_dropdown[] = { STR_ORDER_DROP_REFIT_AUTO, STR_ORDER_DROP_REFIT_AUTO_ANY, INVALID_STRING_ID }; /** * Draws an order in order or timetable GUI * @param v Vehicle the order belongs to * @param order The order to draw * @param order_index Index of the order in the orders of the vehicle * @param y Y position for drawing * @param selected True, if the order is selected * @param timetable True, when drawing in the timetable GUI * @param left Left border for text drawing * @param middle X position between order index and order text * @param right Right border for text drawing */ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int y, bool selected, bool timetable, int left, int middle, int right) { bool rtl = _current_text_dir == TD_RTL; SpriteID sprite = rtl ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; Dimension sprite_size = GetSpriteSize(sprite); if (v->cur_real_order_index == order_index) { DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); DrawSprite(sprite, PAL_NONE, rtl ? right - 2 * sprite_size.width : left + sprite_size.width, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); } else if (v->cur_implicit_order_index == order_index) { DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); } TextColour colour = TC_BLACK; if (order->IsType(OT_IMPLICIT)) { colour = (selected ? TC_SILVER : TC_GREY) | TC_NO_SHADE; } else if (selected) { colour = TC_WHITE; } SetDParam(0, order_index + 1); DrawString(left, rtl ? right - 2 * sprite_size.width - 3 : middle, y, STR_ORDER_INDEX, colour, SA_RIGHT | SA_FORCE); SetDParam(5, STR_EMPTY); SetDParam(8, STR_EMPTY); /* Check range for aircraft. */ if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0 && order->IsGotoOrder()) { const Order *next = order->next != NULL ? order->next : v->GetFirstOrder(); if (GetOrderDistance(order, next, v) > Aircraft::From(v)->acache.cached_max_range_sqr) SetDParam(8, STR_ORDER_OUT_OF_RANGE); } switch (order->GetType()) { case OT_DUMMY: SetDParam(0, STR_INVALID_ORDER); SetDParam(1, order->GetDestination()); break; case OT_IMPLICIT: SetDParam(0, STR_ORDER_GO_TO_STATION); SetDParam(1, STR_ORDER_GO_TO); SetDParam(2, order->GetDestination()); SetDParam(3, timetable ? STR_EMPTY : STR_ORDER_IMPLICIT); break; case OT_GOTO_STATION: { OrderLoadFlags load = order->GetLoadType(); OrderUnloadFlags unload = order->GetUnloadType(); SetDParam(0, STR_ORDER_GO_TO_STATION); SetDParam(1, STR_ORDER_GO_TO + (v->IsGroundVehicle() ? order->GetNonStopType() : 0)); SetDParam(2, order->GetDestination()); if (timetable) { SetDParam(3, STR_EMPTY); if (order->GetWaitTime() > 0) { SetDParam(5, order->IsWaitTimetabled() ? STR_TIMETABLE_STAY_FOR : STR_TIMETABLE_STAY_FOR_ESTIMATED); SetTimetableParams(6, 7, order->GetWaitTime()); } } else { SetDParam(3, (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) ? STR_EMPTY : _station_load_types[order->IsRefit()][unload][load]); if (order->IsRefit()) { SetDParam(4, order->IsAutoRefit() ? STR_ORDER_AUTO_REFIT_ANY : CargoSpec::Get(order->GetRefitCargo())->name); } if (v->type == VEH_TRAIN && (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0) { SetDParam(5, order->GetStopLocation() + STR_ORDER_STOP_LOCATION_NEAR_END); } } break; } case OT_GOTO_DEPOT: if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) { SetDParam(0, STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT); if (v->type == VEH_AIRCRAFT) { SetDParam(2, STR_ORDER_NEAREST_HANGAR); SetDParam(3, STR_EMPTY); } else { SetDParam(2, STR_ORDER_NEAREST_DEPOT); SetDParam(3, STR_ORDER_TRAIN_DEPOT + v->type); } } else { SetDParam(0, STR_ORDER_GO_TO_DEPOT_FORMAT); SetDParam(2, v->type); SetDParam(3, order->GetDestination()); } if (order->GetDepotOrderType() & ODTFB_SERVICE) { SetDParam(1, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_SERVICE_NON_STOP_AT : STR_ORDER_SERVICE_AT); } else { SetDParam(1, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO : STR_ORDER_GO_TO); } if (!timetable && (order->GetDepotActionType() & ODATFB_HALT)) { SetDParam(5, STR_ORDER_STOP_ORDER); } if (!timetable && order->IsRefit()) { SetDParam(5, (order->GetDepotActionType() & ODATFB_HALT) ? STR_ORDER_REFIT_STOP_ORDER : STR_ORDER_REFIT_ORDER); SetDParam(6, CargoSpec::Get(order->GetRefitCargo())->name); } break; case OT_GOTO_WAYPOINT: SetDParam(0, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_ORDER_GO_NON_STOP_TO_WAYPOINT : STR_ORDER_GO_TO_WAYPOINT); SetDParam(1, order->GetDestination()); break; case OT_CONDITIONAL: SetDParam(1, order->GetConditionSkipToOrder() + 1); if (order->GetConditionVariable() == OCV_UNCONDITIONALLY) { SetDParam(0, STR_ORDER_CONDITIONAL_UNCONDITIONAL); } else { OrderConditionComparator occ = order->GetConditionComparator(); SetDParam(0, (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) ? STR_ORDER_CONDITIONAL_TRUE_FALSE : STR_ORDER_CONDITIONAL_NUM); SetDParam(2, STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + order->GetConditionVariable()); SetDParam(3, STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS + occ); uint value = order->GetConditionValue(); if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value); SetDParam(4, value); } if (timetable && order->GetWaitTime() > 0) { SetDParam(5, order->IsWaitTimetabled() ? STR_TIMETABLE_AND_TRAVEL_FOR : STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED); SetTimetableParams(6, 7, order->GetWaitTime()); } else { SetDParam(5, STR_EMPTY); } break; default: NOT_REACHED(); } DrawString(rtl ? left : middle, rtl ? middle : right, y, STR_ORDER_TEXT, colour); } /** * Get the order command a vehicle can do in a given tile. * @param v Vehicle involved. * @param tile Tile being queried. * @return The order associated to vehicle v in given tile (or empty order if vehicle can do nothing in the tile). */ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile) { /* Hack-ish; unpack order 0, so everything gets initialised with either zero * or a suitable default value for the variable. Then also override the index * as it is not coming from a pool, so would be initialised. */ Order order(0); order.index = 0; /* check depot first */ if (IsDepotTypeTile(tile, (TransportType)(uint)v->type) && IsTileOwner(tile, _local_company)) { order.MakeGoToDepot(v->type == VEH_AIRCRAFT ? GetStationIndex(tile) : GetDepotIndex(tile), ODTFB_PART_OF_ORDERS, (_settings_client.gui.new_nonstop && v->IsGroundVehicle()) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE)); return order; } /* check rail waypoint */ if (IsRailWaypointTile(tile) && v->type == VEH_TRAIN && IsTileOwner(tile, _local_company)) { order.MakeGoToWaypoint(GetStationIndex(tile)); if (_settings_client.gui.new_nonstop != _ctrl_pressed) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION); return order; } /* check buoy (no ownership) */ if (IsBuoyTile(tile) && v->type == VEH_SHIP) { order.MakeGoToWaypoint(GetStationIndex(tile)); return order; } if (IsTileType(tile, MP_STATION)) { StationID st_index = GetStationIndex(tile); const Station *st = Station::Get(st_index); if (st->owner == _local_company || st->owner == OWNER_NONE) { byte facil; (facil = FACIL_DOCK, v->type == VEH_SHIP) || (facil = FACIL_TRAIN, v->type == VEH_TRAIN) || (facil = FACIL_AIRPORT, v->type == VEH_AIRCRAFT) || (facil = FACIL_BUS_STOP, v->type == VEH_ROAD && RoadVehicle::From(v)->IsBus()) || (facil = FACIL_TRUCK_STOP, 1); if (st->facilities & facil) { order.MakeGoToStation(st_index); if (_ctrl_pressed) order.SetLoadType(OLF_FULL_LOAD_ANY); if (_settings_client.gui.new_nonstop && v->IsGroundVehicle()) order.SetNonStopType(ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); order.SetStopLocation(v->type == VEH_TRAIN ? (OrderStopLocation)(_settings_client.gui.stop_location) : OSL_PLATFORM_FAR_END); return order; } } } /* not found */ order.Free(); return order; } /** Hotkeys for order window. */ enum { OHK_SKIP, OHK_DELETE, OHK_GOTO, OHK_NONSTOP, OHK_FULLLOAD, OHK_UNLOAD, OHK_NEAREST_DEPOT, OHK_ALWAYS_SERVICE, OHK_TRANSFER, OHK_NO_UNLOAD, OHK_NO_LOAD, }; /** * %Order window code for all vehicles. * * At the bottom of the window two button rows are located for changing the orders of the vehicle. * * \section top-row Top row * The top-row is for manipulating an individual order. What row is displayed depends on the type of vehicle, and whether or not you are the owner of the vehicle. * * The top-row buttons of one of your trains or road vehicles is one of the following three cases: * \verbatim * +-----------------+-----------------+-----------------+-----------------+ * | NON-STOP | FULL_LOAD | UNLOAD | REFIT | (normal) * +-----------------+-----+-----------+-----------+-----+-----------------+ * | COND_VAR | COND_COMPARATOR | COND_VALUE | (for conditional orders) * +-----------------+-----+-----------+-----------+-----+-----------------+ * | NON-STOP | REFIT | SERVICE | (empty) | (for depot orders) * +-----------------+-----------------+-----------------+-----------------+ * \endverbatim * * Airplanes and ships have one of the following three top-row button rows: * \verbatim * +-----------------+-----------------+-----------------+ * | FULL_LOAD | UNLOAD | REFIT | (normal) * +-----------------+-----------------+-----------------+ * | COND_VAR | COND_COMPARATOR | COND_VALUE | (for conditional orders) * +-----------------+--------+--------+-----------------+ * | REFIT | SERVICE | (for depot order) * +--------------------------+--------------------------+ * \endverbatim * * \section bottom-row Bottom row * The second row (the bottom row) is for manipulating the list of orders: * \verbatim * +-----------------+-----------------+-----------------+ * | SKIP | DELETE | GOTO | * +-----------------+-----------------+-----------------+ * \endverbatim * * For vehicles of other companies, both button rows are not displayed. */ struct OrdersWindow : public Window { private: /** Under what reason are we using the PlaceObject functionality? */ enum OrderPlaceObjectState { OPOS_NONE, OPOS_GOTO, OPOS_CONDITIONAL, OPOS_SHARE, OPOS_END, }; /** Displayed planes of the #NWID_SELECTION widgets. */ enum DisplayPane { /* WID_O_SEL_TOP_ROW_GROUNDVEHICLE */ DP_GROUNDVEHICLE_ROW_NORMAL = 0, ///< Display the row for normal/depot orders in the top row of the train/rv order window. DP_GROUNDVEHICLE_ROW_CONDITIONAL = 1, ///< Display the row for conditional orders in the top row of the train/rv order window. /* WID_O_SEL_TOP_LEFT */ DP_LEFT_LOAD = 0, ///< Display 'load' in the left button of the top row of the train/rv order window. DP_LEFT_REFIT = 1, ///< Display 'refit' in the left button of the top row of the train/rv order window. /* WID_O_SEL_TOP_MIDDLE */ DP_MIDDLE_UNLOAD = 0, ///< Display 'unload' in the middle button of the top row of the train/rv order window. DP_MIDDLE_SERVICE = 1, ///< Display 'service' in the middle button of the top row of the train/rv order window. /* WID_O_SEL_TOP_RIGHT */ DP_RIGHT_EMPTY = 0, ///< Display an empty panel in the right button of the top row of the train/rv order window. DP_RIGHT_REFIT = 1, ///< Display 'refit' in the right button of the top row of the train/rv order window. /* WID_O_SEL_TOP_ROW */ DP_ROW_LOAD = 0, ///< Display 'load' / 'unload' / 'refit' buttons in the top row of the ship/airplane order window. DP_ROW_DEPOT = 1, ///< Display 'refit' / 'service' buttons in the top row of the ship/airplane order window. DP_ROW_CONDITIONAL = 2, ///< Display the conditional order buttons in the top row of the ship/airplane order window. /* WID_O_SEL_BOTTOM_MIDDLE */ DP_BOTTOM_MIDDLE_DELETE = 0, ///< Display 'delete' in the middle button of the bottom row of the vehicle order window. DP_BOTTOM_MIDDLE_STOP_SHARING = 1, ///< Display 'stop sharing' in the middle button of the bottom row of the vehicle order window. }; int selected_order; VehicleOrderID order_over; ///< Order over which another order is dragged, \c INVALID_VEH_ORDER_ID if none. OrderPlaceObjectState goto_type; const Vehicle *vehicle; ///< Vehicle owning the orders being displayed and manipulated. Scrollbar *vscroll; bool can_do_refit; ///< Vehicle chain can be refitted in depot. bool can_do_autorefit; ///< Vehicle chain can be auto-refitted. /** * Return the memorised selected order. * @return the memorised order if it is a valid one * else return the number of orders */ VehicleOrderID OrderGetSel() const { int num = this->selected_order; return (num >= 0 && num < vehicle->GetNumOrders()) ? num : vehicle->GetNumOrders(); } /** * Calculate the selected order. * The calculation is based on the relative (to the window) y click position and * the position of the scrollbar. * * @param y Y-value of the click relative to the window origin * @return The selected order if the order is valid, else return \c INVALID_VEH_ORDER_ID. */ VehicleOrderID GetOrderFromPt(int y) { NWidgetBase *nwid = this->GetWidget(WID_O_ORDER_LIST); int sel = (y - nwid->pos_y - WD_FRAMERECT_TOP) / nwid->resize_y; // Selected line in the WID_O_ORDER_LIST panel. if ((uint)sel >= this->vscroll->GetCapacity()) return INVALID_VEH_ORDER_ID; sel += this->vscroll->GetPosition(); return (sel <= vehicle->GetNumOrders() && sel >= 0) ? sel : INVALID_VEH_ORDER_ID; } /** * Handle the click on the goto button. */ void OrderClick_Goto(OrderPlaceObjectState type) { assert(type > OPOS_NONE && type < OPOS_END); static const HighLightStyle goto_place_style[OPOS_END - 1] = { HT_RECT | HT_VEHICLE, // OPOS_GOTO HT_NONE, // OPOS_CONDITIONAL HT_VEHICLE, // OPOS_SHARE }; SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, goto_place_style[type - 1], this); this->goto_type = type; this->SetWidgetDirty(WID_O_GOTO); } /** * Handle the click on the full load button. * @param load_type the way to load. */ void OrderClick_FullLoad(int load_type) { VehicleOrderID sel_ord = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel_ord); if (order == NULL || order->GetLoadType() == load_type) return; if (load_type < 0) { load_type = order->GetLoadType() == OLF_LOAD_IF_POSSIBLE ? OLF_FULL_LOAD_ANY : OLF_LOAD_IF_POSSIBLE; } DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (load_type << 4), CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); } /** * Handle the 'no loading' hotkey */ void OrderHotkey_NoLoad() { this->OrderClick_FullLoad(OLFB_NO_LOAD); } /** * Handle the click on the service. */ void OrderClick_Service(int i) { VehicleOrderID sel_ord = this->OrderGetSel(); if (i < 0) { const Order *order = this->vehicle->GetOrder(sel_ord); if (order == NULL) return; i = (order->GetDepotOrderType() & ODTFB_SERVICE) ? DA_ALWAYS_GO : DA_SERVICE; } DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_DEPOT_ACTION | (i << 4), CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); } /** * Handle the click on the service in nearest depot button. */ void OrderClick_NearestDepot() { Order order; order.next = NULL; order.index = 0; order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS, _settings_client.gui.new_nonstop && this->vehicle->IsGroundVehicle() ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); order.SetDepotActionType(ODATFB_NEAREST_DEPOT); DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER)); } /** * Handle the click on the unload button. */ void OrderClick_Unload(int unload_type) { VehicleOrderID sel_ord = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel_ord); if (order == NULL || order->GetUnloadType() == unload_type) return; if (unload_type < 0) { unload_type = order->GetUnloadType() == OUF_UNLOAD_IF_POSSIBLE ? OUFB_UNLOAD : OUF_UNLOAD_IF_POSSIBLE; } DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_UNLOAD | (unload_type << 4), CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); /* Transfer orders with leave empty as default */ if (unload_type == OUFB_TRANSFER) { DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_LOAD | (OLFB_NO_LOAD << 4), CMD_MODIFY_ORDER); this->SetWidgetDirty(WID_O_FULL_LOAD); } } /** * Handle the transfer hotkey */ void OrderHotkey_Transfer() { this->OrderClick_Unload(OUFB_TRANSFER); } /** * Handle the 'no unload' hotkey */ void OrderHotkey_NoUnload() { this->OrderClick_Unload(OUFB_NO_UNLOAD); } /** * Handle the click on the nonstop button. * @param non_stop what non-stop type to use; -1 to use the 'next' one. */ void OrderClick_Nonstop(int non_stop) { if (!this->vehicle->IsGroundVehicle()) return; VehicleOrderID sel_ord = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel_ord); if (order == NULL || order->GetNonStopType() == non_stop) return; /* Keypress if negative, so 'toggle' to the next */ if (non_stop < 0) { non_stop = order->GetNonStopType() ^ ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS; } this->SetWidgetDirty(WID_O_NON_STOP); DoCommandP(this->vehicle->tile, this->vehicle->index + (sel_ord << 20), MOF_NON_STOP | non_stop << 4, CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); } /** * Handle the click on the skip button. * If ctrl is pressed, skip to selected order, else skip to current order + 1 */ void OrderClick_Skip() { /* Don't skip when there's nothing to skip */ if (_ctrl_pressed && this->vehicle->cur_implicit_order_index == this->OrderGetSel()) return; if (this->vehicle->GetNumOrders() <= 1) return; DoCommandP(this->vehicle->tile, this->vehicle->index, _ctrl_pressed ? this->OrderGetSel() : ((this->vehicle->cur_implicit_order_index + 1) % this->vehicle->GetNumOrders()), CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_ERROR_CAN_T_SKIP_TO_ORDER : STR_ERROR_CAN_T_SKIP_ORDER)); } /** * Handle the click on the delete button. */ void OrderClick_Delete() { /* When networking, move one order lower */ int selected = this->selected_order + (int)_networking; if (DoCommandP(this->vehicle->tile, this->vehicle->index, this->OrderGetSel(), CMD_DELETE_ORDER | CMD_MSG(STR_ERROR_CAN_T_DELETE_THIS_ORDER))) { this->selected_order = selected >= this->vehicle->GetNumOrders() ? -1 : selected; this->UpdateButtonState(); } } /** * Handle the click on the 'stop sharing' button. * If 'End of Shared Orders' isn't selected, do nothing. If Ctrl is pressed, call OrderClick_Delete and exit. * To stop sharing this vehicle order list, we copy the orders of a vehicle that share this order list. That way we * exit the group of shared vehicles while keeping the same order list. */ void OrderClick_StopSharing() { /* Don't try to stop sharing orders if 'End of Shared Orders' isn't selected. */ if (!this->vehicle->IsOrderListShared() || this->selected_order != this->vehicle->GetNumOrders()) return; /* If Ctrl is pressed, delete the order list as if we clicked the 'Delete' button. */ if (_ctrl_pressed) { this->OrderClick_Delete(); return; } /* Get another vehicle that share orders with this vehicle. */ Vehicle *other_shared = (this->vehicle->FirstShared() == this->vehicle) ? this->vehicle->NextShared() : this->vehicle->PreviousShared(); /* Copy the order list of the other vehicle. */ if (DoCommandP(this->vehicle->tile, this->vehicle->index | CO_COPY << 30, other_shared->index, CMD_CLONE_ORDER | CMD_MSG(STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST))) { this->UpdateButtonState(); } } /** * Handle the click on the refit button. * If ctrl is pressed, cancel refitting, else show the refit window. * @param i Selected refit command. * @param auto_refit Select refit for auto-refitting. */ void OrderClick_Refit(int i, bool auto_refit) { if (_ctrl_pressed) { /* Cancel refitting */ DoCommandP(this->vehicle->tile, this->vehicle->index, (this->OrderGetSel() << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, CMD_ORDER_REFIT); } else { if (i == 1) { // Auto-refit to available cargo type. DoCommandP(this->vehicle->tile, this->vehicle->index, (this->OrderGetSel() << 16) | CT_AUTO_REFIT, CMD_ORDER_REFIT); } else { ShowVehicleRefitWindow(this->vehicle, this->OrderGetSel(), this, auto_refit); } } } /** Cache auto-refittability of the vehicle chain. */ void UpdateAutoRefitState() { this->can_do_refit = false; this->can_do_autorefit = false; for (const Vehicle *w = this->vehicle; w != NULL; w = w->IsGroundVehicle() ? w->Next() : NULL) { if (IsEngineRefittable(w->engine_type)) this->can_do_refit = true; if (HasBit(Engine::Get(w->engine_type)->info.misc_flags, EF_AUTO_REFIT)) this->can_do_autorefit = true; } } public: OrdersWindow(WindowDesc *desc, const Vehicle *v) : Window(desc) { this->vehicle = v; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_O_SCROLLBAR); this->FinishInitNested(v->index); if (v->owner == _local_company) { this->DisableWidget(WID_O_EMPTY); } this->selected_order = -1; this->order_over = INVALID_VEH_ORDER_ID; this->goto_type = OPOS_NONE; this->owner = v->owner; this->UpdateAutoRefitState(); if (_settings_client.gui.quick_goto && v->owner == _local_company) { /* If there are less than 2 station, make Go To active. */ int station_orders = 0; const Order *order; FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_GOTO_STATION)) station_orders++; } if (station_orders < 2) this->OrderClick_Goto(OPOS_GOTO); } this->OnInvalidateData(VIWD_MODIFY_ORDERS); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_O_ORDER_LIST: resize->height = FONT_HEIGHT_NORMAL; size->height = 6 * resize->height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; break; case WID_O_COND_VARIABLE: { Dimension d = {0, 0}; for (uint i = 0; i < lengthof(_order_conditional_variable); i++) { d = maxdim(d, GetStringBoundingBox(STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + _order_conditional_variable[i])); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_O_COND_COMPARATOR: { Dimension d = {0, 0}; for (int i = 0; _order_conditional_condition[i] != INVALID_STRING_ID; i++) { d = maxdim(d, GetStringBoundingBox(_order_conditional_condition[i])); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); 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) { VehicleOrderID from = INVALID_VEH_ORDER_ID; VehicleOrderID to = INVALID_VEH_ORDER_ID; switch (data) { case VIWD_AUTOREPLACE: /* Autoreplace replaced the vehicle */ this->vehicle = Vehicle::Get(this->window_number); /* FALL THROUGH */ case VIWD_CONSIST_CHANGED: /* Vehicle composition was changed. */ this->UpdateAutoRefitState(); break; case VIWD_REMOVE_ALL_ORDERS: /* Removed / replaced all orders (after deleting / sharing) */ if (this->selected_order == -1) break; this->DeleteChildWindows(); HideDropDownMenu(this); this->selected_order = -1; break; case VIWD_MODIFY_ORDERS: /* Some other order changes */ break; default: if (data < 0) break; if (gui_scope) break; // only do this once; from command scope from = GB(data, 0, 8); to = GB(data, 8, 8); /* Moving an order. If one of these is INVALID_VEH_ORDER_ID, then * the order is being created / removed */ if (this->selected_order == -1) break; if (from == to) break; // no need to change anything if (from != this->selected_order) { /* Moving from preceding order? */ this->selected_order -= (int)(from <= this->selected_order); /* Moving to preceding order? */ this->selected_order += (int)(to <= this->selected_order); break; } /* Now we are modifying the selected order */ if (to == INVALID_VEH_ORDER_ID) { /* Deleting selected order */ this->DeleteChildWindows(); HideDropDownMenu(this); this->selected_order = -1; break; } /* Moving selected order */ this->selected_order = to; break; } this->vscroll->SetCount(this->vehicle->GetNumOrders() + 1); if (gui_scope) this->UpdateButtonState(); /* Scroll to the new order. */ if (from == INVALID_VEH_ORDER_ID && to != INVALID_VEH_ORDER_ID && !this->vscroll->IsVisible(to)) { this->vscroll->ScrollTowards(to); } } void UpdateButtonState() { if (this->vehicle->owner != _local_company) return; // No buttons are displayed with competitor order windows. bool shared_orders = this->vehicle->IsOrderListShared(); VehicleOrderID sel = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel); /* Second row. */ /* skip */ this->SetWidgetDisabledState(WID_O_SKIP, this->vehicle->GetNumOrders() <= 1); /* delete / stop sharing */ NWidgetStacked *delete_sel = this->GetWidget(WID_O_SEL_BOTTOM_MIDDLE); if (shared_orders && this->selected_order == this->vehicle->GetNumOrders()) { /* The 'End of Shared Orders' order is selected, show the 'stop sharing' button. */ delete_sel->SetDisplayedPlane(DP_BOTTOM_MIDDLE_STOP_SHARING); } else { /* The 'End of Shared Orders' order isn't selected, show the 'delete' button. */ delete_sel->SetDisplayedPlane(DP_BOTTOM_MIDDLE_DELETE); this->SetWidgetDisabledState(WID_O_DELETE, (uint)this->vehicle->GetNumOrders() + ((shared_orders || this->vehicle->GetNumOrders() != 0) ? 1 : 0) <= (uint)this->selected_order); /* Set the tooltip of the 'delete' button depending on whether the * 'End of Orders' order or a regular order is selected. */ NWidgetCore *nwi = this->GetWidget(WID_O_DELETE); if (this->selected_order == this->vehicle->GetNumOrders()) { nwi->SetDataTip(STR_ORDERS_DELETE_BUTTON, STR_ORDERS_DELETE_ALL_TOOLTIP); } else { nwi->SetDataTip(STR_ORDERS_DELETE_BUTTON, STR_ORDERS_DELETE_TOOLTIP); } } /* First row. */ this->RaiseWidget(WID_O_FULL_LOAD); this->RaiseWidget(WID_O_UNLOAD); this->RaiseWidget(WID_O_SERVICE); /* Selection widgets. */ /* Train or road vehicle. */ NWidgetStacked *train_row_sel = this->GetWidget(WID_O_SEL_TOP_ROW_GROUNDVEHICLE); NWidgetStacked *left_sel = this->GetWidget(WID_O_SEL_TOP_LEFT); NWidgetStacked *middle_sel = this->GetWidget(WID_O_SEL_TOP_MIDDLE); NWidgetStacked *right_sel = this->GetWidget(WID_O_SEL_TOP_RIGHT); /* Ship or airplane. */ NWidgetStacked *row_sel = this->GetWidget(WID_O_SEL_TOP_ROW); assert(row_sel != NULL || (train_row_sel != NULL && left_sel != NULL && middle_sel != NULL && right_sel != NULL)); if (order == NULL) { if (row_sel != NULL) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); left_sel->SetDisplayedPlane(DP_LEFT_LOAD); middle_sel->SetDisplayedPlane(DP_MIDDLE_UNLOAD); right_sel->SetDisplayedPlane(DP_RIGHT_EMPTY); this->DisableWidget(WID_O_NON_STOP); this->RaiseWidget(WID_O_NON_STOP); } this->DisableWidget(WID_O_FULL_LOAD); this->DisableWidget(WID_O_UNLOAD); this->DisableWidget(WID_O_REFIT_DROPDOWN); } else { this->SetWidgetDisabledState(WID_O_FULL_LOAD, (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // full load this->SetWidgetDisabledState(WID_O_UNLOAD, (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // unload switch (order->GetType()) { case OT_GOTO_STATION: if (row_sel != NULL) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); left_sel->SetDisplayedPlane(DP_LEFT_LOAD); middle_sel->SetDisplayedPlane(DP_MIDDLE_UNLOAD); right_sel->SetDisplayedPlane(DP_RIGHT_REFIT); this->EnableWidget(WID_O_NON_STOP); this->SetWidgetLoweredState(WID_O_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); } this->SetWidgetLoweredState(WID_O_FULL_LOAD, order->GetLoadType() == OLF_FULL_LOAD_ANY); this->SetWidgetLoweredState(WID_O_UNLOAD, order->GetUnloadType() == OUFB_UNLOAD); /* Can only do refitting when stopping at the destination and loading cargo. * Also enable the button if a refit is already set to allow clearing it. */ this->SetWidgetDisabledState(WID_O_REFIT_DROPDOWN, order->GetLoadType() == OLFB_NO_LOAD || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) || ((!this->can_do_refit || !this->can_do_autorefit) && !order->IsRefit())); break; case OT_GOTO_WAYPOINT: if (row_sel != NULL) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); left_sel->SetDisplayedPlane(DP_LEFT_LOAD); middle_sel->SetDisplayedPlane(DP_MIDDLE_UNLOAD); right_sel->SetDisplayedPlane(DP_RIGHT_EMPTY); this->EnableWidget(WID_O_NON_STOP); this->SetWidgetLoweredState(WID_O_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); } this->DisableWidget(WID_O_FULL_LOAD); this->DisableWidget(WID_O_UNLOAD); this->DisableWidget(WID_O_REFIT_DROPDOWN); break; case OT_GOTO_DEPOT: if (row_sel != NULL) { row_sel->SetDisplayedPlane(DP_ROW_DEPOT); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); left_sel->SetDisplayedPlane(DP_LEFT_REFIT); middle_sel->SetDisplayedPlane(DP_MIDDLE_SERVICE); right_sel->SetDisplayedPlane(DP_RIGHT_EMPTY); this->EnableWidget(WID_O_NON_STOP); this->SetWidgetLoweredState(WID_O_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); } /* Disable refit button if the order is no 'always go' order. * However, keep the service button enabled for refit-orders to allow clearing refits (without knowing about ctrl). */ this->SetWidgetDisabledState(WID_O_REFIT, (order->GetDepotOrderType() & ODTFB_SERVICE) || (order->GetDepotActionType() & ODATFB_HALT) || (!this->can_do_refit && !order->IsRefit())); this->SetWidgetLoweredState(WID_O_SERVICE, order->GetDepotOrderType() & ODTFB_SERVICE); break; case OT_CONDITIONAL: { if (row_sel != NULL) { row_sel->SetDisplayedPlane(DP_ROW_CONDITIONAL); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_CONDITIONAL); } OrderConditionVariable ocv = order->GetConditionVariable(); /* Set the strings for the dropdown boxes. */ this->GetWidget(WID_O_COND_VARIABLE)->widget_data = STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + ocv; this->GetWidget(WID_O_COND_COMPARATOR)->widget_data = _order_conditional_condition[order->GetConditionComparator()]; this->SetWidgetDisabledState(WID_O_COND_COMPARATOR, ocv == OCV_UNCONDITIONALLY); this->SetWidgetDisabledState(WID_O_COND_VALUE, ocv == OCV_REQUIRES_SERVICE || ocv == OCV_UNCONDITIONALLY); break; } default: // every other order if (row_sel != NULL) { row_sel->SetDisplayedPlane(DP_ROW_LOAD); } else { train_row_sel->SetDisplayedPlane(DP_GROUNDVEHICLE_ROW_NORMAL); left_sel->SetDisplayedPlane(DP_LEFT_LOAD); middle_sel->SetDisplayedPlane(DP_MIDDLE_UNLOAD); right_sel->SetDisplayedPlane(DP_RIGHT_EMPTY); this->DisableWidget(WID_O_NON_STOP); } this->DisableWidget(WID_O_FULL_LOAD); this->DisableWidget(WID_O_UNLOAD); this->DisableWidget(WID_O_REFIT_DROPDOWN); break; } } /* Disable list of vehicles with the same shared orders if there is no list */ this->SetWidgetDisabledState(WID_O_SHARED_ORDER_LIST, !shared_orders); this->SetDirty(); } virtual void OnPaint() { if (this->vehicle->owner != _local_company) { this->selected_order = -1; // Disable selection any selected row at a competitor order window. } else { this->SetWidgetLoweredState(WID_O_GOTO, this->goto_type != OPOS_NONE); } this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_O_ORDER_LIST) return; bool rtl = _current_text_dir == TD_RTL; SetDParamMaxValue(0, this->vehicle->GetNumOrders(), 2); int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3; int middle = rtl ? r.right - WD_FRAMETEXT_RIGHT - index_column_width : r.left + WD_FRAMETEXT_LEFT + index_column_width; int y = r.top + WD_FRAMERECT_TOP; int line_height = this->GetWidget(WID_O_ORDER_LIST)->resize_y; int i = this->vscroll->GetPosition(); const Order *order = this->vehicle->GetOrder(i); /* First draw the highlighting underground if it exists. */ if (this->order_over != INVALID_VEH_ORDER_ID) { while (order != NULL) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; if (i != this->selected_order && i == this->order_over) { /* Highlight dragged order destination. */ int top = (this->order_over < this->selected_order ? y : y + line_height) - WD_FRAMERECT_TOP; int bottom = min(top + 2, r.bottom - WD_FRAMERECT_BOTTOM); top = max(top - 3, r.top + WD_FRAMERECT_TOP); GfxFillRect(r.left + WD_FRAMETEXT_LEFT, top, r.right - WD_FRAMETEXT_RIGHT, bottom, _colour_gradient[COLOUR_GREY][7]); break; } y += line_height; i++; order = order->next; } /* Reset counters for drawing the orders. */ y = r.top + WD_FRAMERECT_TOP; i = this->vscroll->GetPosition(); order = this->vehicle->GetOrder(i); } /* Draw the orders. */ while (order != NULL) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; DrawOrderString(this->vehicle, order, i, y, i == this->selected_order, false, r.left + WD_FRAMETEXT_LEFT, middle, r.right - WD_FRAMETEXT_RIGHT); y += line_height; i++; order = order->next; } if (this->vscroll->IsVisible(i)) { StringID str = this->vehicle->IsOrderListShared() ? STR_ORDERS_END_OF_SHARED_ORDERS : STR_ORDERS_END_OF_ORDERS; DrawString(rtl ? r.left + WD_FRAMETEXT_LEFT : middle, rtl ? middle : r.right - WD_FRAMETEXT_RIGHT, y, str, (i == this->selected_order) ? TC_WHITE : TC_BLACK); } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_O_COND_VALUE: { VehicleOrderID sel = this->OrderGetSel(); const Order *order = this->vehicle->GetOrder(sel); if (order != NULL && order->IsType(OT_CONDITIONAL)) { uint value = order->GetConditionValue(); if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value); SetDParam(0, value); } break; } case WID_O_CAPTION: SetDParam(0, this->vehicle->index); break; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_O_ORDER_LIST: { if (this->goto_type == OPOS_CONDITIONAL) { VehicleOrderID order_id = this->GetOrderFromPt(_cursor.pos.y - this->top); if (order_id != INVALID_VEH_ORDER_ID) { Order order; order.next = NULL; order.index = 0; order.MakeConditional(order_id); DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), order.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER)); } ResetObjectToPlace(); break; } VehicleOrderID sel = this->GetOrderFromPt(pt.y); if (_ctrl_pressed && sel < this->vehicle->GetNumOrders()) { TileIndex xy = this->vehicle->GetOrder(sel)->GetLocation(this->vehicle); if (xy != INVALID_TILE) ScrollMainWindowToTile(xy); return; } /* This order won't be selected any more, close all child windows and dropdowns */ this->DeleteChildWindows(); HideDropDownMenu(this); if (sel == INVALID_VEH_ORDER_ID || this->vehicle->owner != _local_company) { /* Deselect clicked order */ this->selected_order = -1; } else if (sel == this->selected_order) { if (this->vehicle->type == VEH_TRAIN && sel < this->vehicle->GetNumOrders()) { DoCommandP(this->vehicle->tile, this->vehicle->index + (sel << 20), MOF_STOP_LOCATION | ((this->vehicle->GetOrder(sel)->GetStopLocation() + 1) % OSL_END) << 4, CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); } } else { /* Select clicked order */ this->selected_order = sel; if (this->vehicle->owner == _local_company) { /* Activate drag and drop */ SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); } } this->UpdateButtonState(); break; } case WID_O_SKIP: this->OrderClick_Skip(); break; case WID_O_DELETE: this->OrderClick_Delete(); break; case WID_O_STOP_SHARING: this->OrderClick_StopSharing(); break; case WID_O_NON_STOP: if (this->GetWidget(widget)->ButtonHit(pt)) { this->OrderClick_Nonstop(-1); } else { const Order *o = this->vehicle->GetOrder(this->OrderGetSel()); ShowDropDownMenu(this, _order_non_stop_drowdown, o->GetNonStopType(), WID_O_NON_STOP, 0, o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12)); } break; case WID_O_GOTO: if (this->GetWidget(widget)->ButtonHit(pt)) { if (this->goto_type != OPOS_NONE) { ResetObjectToPlace(); } else { this->OrderClick_Goto(OPOS_GOTO); } } else { int sel; switch (this->goto_type) { case OPOS_NONE: sel = -1; break; case OPOS_GOTO: sel = 0; break; case OPOS_CONDITIONAL: sel = 2; break; case OPOS_SHARE: sel = 3; break; default: NOT_REACHED(); } ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, sel, WID_O_GOTO, 0, 0); } break; case WID_O_FULL_LOAD: if (this->GetWidget(widget)->ButtonHit(pt)) { this->OrderClick_FullLoad(-1); } else { ShowDropDownMenu(this, _order_full_load_drowdown, this->vehicle->GetOrder(this->OrderGetSel())->GetLoadType(), WID_O_FULL_LOAD, 0, 2); } break; case WID_O_UNLOAD: if (this->GetWidget(widget)->ButtonHit(pt)) { this->OrderClick_Unload(-1); } else { ShowDropDownMenu(this, _order_unload_drowdown, this->vehicle->GetOrder(this->OrderGetSel())->GetUnloadType(), WID_O_UNLOAD, 0, 8); } break; case WID_O_REFIT: this->OrderClick_Refit(0, false); break; case WID_O_SERVICE: if (this->GetWidget(widget)->ButtonHit(pt)) { this->OrderClick_Service(-1); } else { ShowDropDownMenu(this, _order_depot_action_dropdown, DepotActionStringIndex(this->vehicle->GetOrder(this->OrderGetSel())), WID_O_SERVICE, 0, 0); } break; case WID_O_REFIT_DROPDOWN: if (this->GetWidget(widget)->ButtonHit(pt)) { this->OrderClick_Refit(0, true); } else { ShowDropDownMenu(this, _order_refit_action_dropdown, 0, WID_O_REFIT_DROPDOWN, 0, 0); } break; case WID_O_TIMETABLE_VIEW: ShowTimetableWindow(this->vehicle); break; case WID_O_COND_VARIABLE: { DropDownList *list = new DropDownList(); for (uint i = 0; i < lengthof(_order_conditional_variable); i++) { *list->Append() = new DropDownListStringItem(STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE + _order_conditional_variable[i], _order_conditional_variable[i], false); } ShowDropDownList(this, list, this->vehicle->GetOrder(this->OrderGetSel())->GetConditionVariable(), WID_O_COND_VARIABLE); break; } case WID_O_COND_COMPARATOR: { const Order *o = this->vehicle->GetOrder(this->OrderGetSel()); ShowDropDownMenu(this, _order_conditional_condition, o->GetConditionComparator(), WID_O_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0); break; } case WID_O_COND_VALUE: { const Order *order = this->vehicle->GetOrder(this->OrderGetSel()); uint value = order->GetConditionValue(); if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value); SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, this, CS_NUMERAL, QSF_NONE); break; } case WID_O_SHARED_ORDER_LIST: ShowVehicleListWindow(this->vehicle); break; } } virtual void OnQueryTextFinished(char *str) { if (!StrEmpty(str)) { VehicleOrderID sel = this->OrderGetSel(); uint value = atoi(str); switch (this->vehicle->GetOrder(sel)->GetConditionVariable()) { case OCV_MAX_SPEED: value = ConvertDisplaySpeedToSpeed(value); break; case OCV_RELIABILITY: case OCV_LOAD_PERCENTAGE: value = Clamp(value, 0, 100); break; default: break; } DoCommandP(this->vehicle->tile, this->vehicle->index + (sel << 20), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_O_NON_STOP: this->OrderClick_Nonstop(index); break; case WID_O_FULL_LOAD: this->OrderClick_FullLoad(index); break; case WID_O_UNLOAD: this->OrderClick_Unload(index); break; case WID_O_GOTO: switch (index) { case 0: this->OrderClick_Goto(OPOS_GOTO); break; case 1: this->OrderClick_NearestDepot(); break; case 2: this->OrderClick_Goto(OPOS_CONDITIONAL); break; case 3: this->OrderClick_Goto(OPOS_SHARE); break; default: NOT_REACHED(); } break; case WID_O_SERVICE: this->OrderClick_Service(index); break; case WID_O_REFIT_DROPDOWN: this->OrderClick_Refit(index, true); break; case WID_O_COND_VARIABLE: DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), MOF_COND_VARIABLE | index << 4, CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); break; case WID_O_COND_COMPARATOR: DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), MOF_COND_COMPARATOR | index << 4, CMD_MODIFY_ORDER | CMD_MSG(STR_ERROR_CAN_T_MODIFY_THIS_ORDER)); break; } } virtual void OnDragDrop(Point pt, int widget) { switch (widget) { case WID_O_ORDER_LIST: { VehicleOrderID from_order = this->OrderGetSel(); VehicleOrderID to_order = this->GetOrderFromPt(pt.y); if (!(from_order == to_order || from_order == INVALID_VEH_ORDER_ID || from_order > this->vehicle->GetNumOrders() || to_order == INVALID_VEH_ORDER_ID || to_order > this->vehicle->GetNumOrders()) && DoCommandP(this->vehicle->tile, this->vehicle->index, from_order | (to_order << 16), CMD_MOVE_ORDER | CMD_MSG(STR_ERROR_CAN_T_MOVE_THIS_ORDER))) { this->selected_order = -1; this->UpdateButtonState(); } break; } case WID_O_DELETE: this->OrderClick_Delete(); break; case WID_O_STOP_SHARING: this->OrderClick_StopSharing(); break; } ResetObjectToPlace(); if (this->order_over != INVALID_VEH_ORDER_ID) { /* End of drag-and-drop, hide dragged order destination highlight. */ this->order_over = INVALID_VEH_ORDER_ID; this->SetWidgetDirty(WID_O_ORDER_LIST); } } virtual EventState OnHotkey(int hotkey) { if (this->vehicle->owner != _local_company) return ES_NOT_HANDLED; switch (hotkey) { case OHK_SKIP: this->OrderClick_Skip(); break; case OHK_DELETE: this->OrderClick_Delete(); break; case OHK_GOTO: this->OrderClick_Goto(OPOS_GOTO); break; case OHK_NONSTOP: this->OrderClick_Nonstop(-1); break; case OHK_FULLLOAD: this->OrderClick_FullLoad(-1); break; case OHK_UNLOAD: this->OrderClick_Unload(-1); break; case OHK_NEAREST_DEPOT: this->OrderClick_NearestDepot(); break; case OHK_ALWAYS_SERVICE: this->OrderClick_Service(-1); break; case OHK_TRANSFER: this->OrderHotkey_Transfer(); break; case OHK_NO_UNLOAD: this->OrderHotkey_NoUnload(); break; case OHK_NO_LOAD: this->OrderHotkey_NoLoad(); break; default: return ES_NOT_HANDLED; } return ES_HANDLED; } virtual void OnPlaceObject(Point pt, TileIndex tile) { if (this->goto_type == OPOS_GOTO) { const Order cmd = GetOrderCmdFromTile(this->vehicle, tile); if (cmd.IsType(OT_NOTHING)) return; if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 20), cmd.Pack(), CMD_INSERT_ORDER | CMD_MSG(STR_ERROR_CAN_T_INSERT_NEW_ORDER))) { /* With quick goto the Go To button stays active */ if (!_settings_client.gui.quick_goto) ResetObjectToPlace(); } } } virtual bool OnVehicleSelect(const Vehicle *v) { /* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet. * We disallow copying orders of other vehicles if we already have at least one order entry * ourself as it easily copies orders of vehicles within a station when we mean the station. * Obviously if you press CTRL on a non-empty orders vehicle you know what you are doing * TODO: give a warning message */ bool share_order = _ctrl_pressed || this->goto_type == OPOS_SHARE; if (this->vehicle->GetNumOrders() != 0 && !share_order) return false; if (DoCommandP(this->vehicle->tile, this->vehicle->index | (share_order ? CO_SHARE : CO_COPY) << 30, v->index, share_order ? CMD_CLONE_ORDER | CMD_MSG(STR_ERROR_CAN_T_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_ERROR_CAN_T_COPY_ORDER_LIST))) { this->selected_order = -1; ResetObjectToPlace(); } return true; } virtual void OnPlaceObjectAbort() { this->goto_type = OPOS_NONE; this->SetWidgetDirty(WID_O_GOTO); /* Remove drag highlighting if it exists. */ if (this->order_over != INVALID_VEH_ORDER_ID) { this->order_over = INVALID_VEH_ORDER_ID; this->SetWidgetDirty(WID_O_ORDER_LIST); } } virtual void OnMouseDrag(Point pt, int widget) { if (this->selected_order != -1 && widget == WID_O_ORDER_LIST) { /* An order is dragged.. */ VehicleOrderID from_order = this->OrderGetSel(); VehicleOrderID to_order = this->GetOrderFromPt(pt.y); uint num_orders = this->vehicle->GetNumOrders(); if (from_order != INVALID_VEH_ORDER_ID && from_order <= num_orders) { if (to_order != INVALID_VEH_ORDER_ID && to_order <= num_orders) { // ..over an existing order. this->order_over = to_order; this->SetWidgetDirty(widget); } else if (from_order != to_order && this->order_over != INVALID_VEH_ORDER_ID) { // ..outside of the order list. this->order_over = INVALID_VEH_ORDER_ID; this->SetWidgetDirty(widget); } } } } virtual void OnResize() { /* Update the scroll bar */ this->vscroll->SetCapacityFromWidget(this, WID_O_ORDER_LIST); } static HotkeyList hotkeys; }; static Hotkey order_hotkeys[] = { Hotkey('D', "skip", OHK_SKIP), Hotkey('F', "delete", OHK_DELETE), Hotkey('G', "goto", OHK_GOTO), Hotkey('H', "nonstop", OHK_NONSTOP), Hotkey('J', "fullload", OHK_FULLLOAD), Hotkey('K', "unload", OHK_UNLOAD), Hotkey((uint16)0, "nearest_depot", OHK_NEAREST_DEPOT), Hotkey((uint16)0, "always_service", OHK_ALWAYS_SERVICE), Hotkey((uint16)0, "transfer", OHK_TRANSFER), Hotkey((uint16)0, "no_unload", OHK_NO_UNLOAD), Hotkey((uint16)0, "no_load", OHK_NO_LOAD), HOTKEY_LIST_END }; HotkeyList OrdersWindow::hotkeys("order", order_hotkeys); /** Nested widget definition for "your" train orders. */ static const NWidgetPart _nested_orders_train_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_O_CAPTION), SetDataTip(STR_ORDERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_TIMETABLE_VIEW), SetMinimalSize(61, 14), SetDataTip(STR_ORDERS_TIMETABLE_VIEW, STR_ORDERS_TIMETABLE_VIEW_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_O_ORDER_LIST), SetMinimalSize(372, 62), SetDataTip(0x0, STR_ORDERS_LIST_TOOLTIP), SetResize(1, 1), SetScrollbar(WID_O_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_O_SCROLLBAR), EndContainer(), /* First button row. */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_ROW_GROUNDVEHICLE), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_NON_STOP), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_NON_STOP, STR_ORDER_TOOLTIP_NON_STOP), SetResize(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_LEFT), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_FULL_LOAD), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_TOGGLE_FULL_LOAD, STR_ORDER_TOOLTIP_FULL_LOAD), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_REFIT), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_REFIT, STR_ORDER_REFIT_TOOLTIP), SetResize(1, 0), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_MIDDLE), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_UNLOAD), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_TOGGLE_UNLOAD, STR_ORDER_TOOLTIP_UNLOAD), SetResize(1, 0), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_SERVICE), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_SERVICE, STR_ORDER_SERVICE_TOOLTIP), SetResize(1, 0), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_RIGHT), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_O_EMPTY), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_REFIT, STR_ORDER_REFIT_TOOLTIP), SetResize(1, 0), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_REFIT_DROPDOWN), SetMinimalSize(93, 12), SetFill(1, 0), SetDataTip(STR_ORDER_REFIT_AUTO, STR_ORDER_REFIT_AUTO_TOOLTIP), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_VARIABLE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP), SetResize(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_COMPARATOR), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_COND_VALUE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_BLACK_COMMA, STR_ORDER_CONDITIONAL_VALUE_TOOLTIP), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_O_SHARED_ORDER_LIST), SetMinimalSize(12, 12), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP), EndContainer(), /* Second button row. */ NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_SKIP), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_SKIP_BUTTON, STR_ORDERS_SKIP_TOOLTIP), SetResize(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_BOTTOM_MIDDLE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_DELETE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_DELETE_BUTTON, STR_ORDERS_DELETE_TOOLTIP), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_STOP_SHARING), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_STOP_SHARING_BUTTON, STR_ORDERS_STOP_SHARING_TOOLTIP), SetResize(1, 0), EndContainer(), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_GOTO), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_GO_TO_BUTTON, STR_ORDERS_GO_TO_TOOLTIP), SetResize(1, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; static WindowDesc _orders_train_desc( WDP_AUTO, "view_vehicle_orders_train", 384, 100, WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, _nested_orders_train_widgets, lengthof(_nested_orders_train_widgets), &OrdersWindow::hotkeys ); /** Nested widget definition for "your" orders (non-train). */ static const NWidgetPart _nested_orders_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_O_CAPTION), SetDataTip(STR_ORDERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_TIMETABLE_VIEW), SetMinimalSize(61, 14), SetDataTip(STR_ORDERS_TIMETABLE_VIEW, STR_ORDERS_TIMETABLE_VIEW_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_O_ORDER_LIST), SetMinimalSize(372, 62), SetDataTip(0x0, STR_ORDERS_LIST_TOOLTIP), SetResize(1, 1), SetScrollbar(WID_O_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_O_SCROLLBAR), EndContainer(), /* First button row. */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_TOP_ROW), /* Load + unload + refit buttons. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_FULL_LOAD), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDER_TOGGLE_FULL_LOAD, STR_ORDER_TOOLTIP_FULL_LOAD), SetResize(1, 0), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_UNLOAD), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDER_TOGGLE_UNLOAD, STR_ORDER_TOOLTIP_UNLOAD), SetResize(1, 0), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_REFIT_DROPDOWN), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDER_REFIT_AUTO, STR_ORDER_REFIT_AUTO_TOOLTIP), SetResize(1, 0), EndContainer(), /* Refit + service buttons. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_REFIT), SetMinimalSize(186, 12), SetFill(1, 0), SetDataTip(STR_ORDER_REFIT, STR_ORDER_REFIT_TOOLTIP), SetResize(1, 0), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_SERVICE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDER_SERVICE, STR_ORDER_SERVICE_TOOLTIP), SetResize(1, 0), EndContainer(), /* Buttons for setting a condition. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_VARIABLE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP), SetResize(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_O_COND_COMPARATOR), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_NULL, STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_COND_VALUE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_BLACK_COMMA, STR_ORDER_CONDITIONAL_VALUE_TOOLTIP), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_O_SHARED_ORDER_LIST), SetMinimalSize(12, 12), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP), EndContainer(), /* Second button row. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_SKIP), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_SKIP_BUTTON, STR_ORDERS_SKIP_TOOLTIP), SetResize(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_O_SEL_BOTTOM_MIDDLE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_DELETE), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_DELETE_BUTTON, STR_ORDERS_DELETE_TOOLTIP), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_STOP_SHARING), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_STOP_SHARING_BUTTON, STR_ORDERS_STOP_SHARING_TOOLTIP), SetResize(1, 0), EndContainer(), NWidget(NWID_BUTTON_DROPDOWN, COLOUR_GREY, WID_O_GOTO), SetMinimalSize(124, 12), SetFill(1, 0), SetDataTip(STR_ORDERS_GO_TO_BUTTON, STR_ORDERS_GO_TO_TOOLTIP), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; static WindowDesc _orders_desc( WDP_AUTO, "view_vehicle_orders", 384, 100, WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, _nested_orders_widgets, lengthof(_nested_orders_widgets), &OrdersWindow::hotkeys ); /** Nested widget definition for competitor orders. */ static const NWidgetPart _nested_other_orders_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_O_CAPTION), SetDataTip(STR_ORDERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_O_TIMETABLE_VIEW), SetMinimalSize(61, 14), SetDataTip(STR_ORDERS_TIMETABLE_VIEW, STR_ORDERS_TIMETABLE_VIEW_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_O_ORDER_LIST), SetMinimalSize(372, 72), SetDataTip(0x0, STR_ORDERS_LIST_TOOLTIP), SetResize(1, 1), SetScrollbar(WID_O_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_O_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), }; static WindowDesc _other_orders_desc( WDP_AUTO, "view_vehicle_orders_competitor", 384, 86, WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, _nested_other_orders_widgets, lengthof(_nested_other_orders_widgets), &OrdersWindow::hotkeys ); void ShowOrdersWindow(const Vehicle *v) { DeleteWindowById(WC_VEHICLE_DETAILS, v->index, false); DeleteWindowById(WC_VEHICLE_TIMETABLE, v->index, false); if (BringWindowToFrontById(WC_VEHICLE_ORDERS, v->index) != NULL) return; /* Using a different WindowDescs for _local_company causes problems. * Due to this we have to close order windows in ChangeWindowOwner/DeleteCompanyWindows, * because we cannot change switch the WindowDescs and keeping the old WindowDesc results * in crashed due to missing widges. * TODO Rewrite the order GUI to not use different WindowDescs. */ if (v->owner != _local_company) { new OrdersWindow(&_other_orders_desc, v); } else { new OrdersWindow(v->IsGroundVehicle() ? &_orders_train_desc : &_orders_desc, v); } } openttd-1.5.3/src/video/0000755000000000000000000000000012627373435013604 5ustar rootrootopenttd-1.5.3/src/video/dedicated_v.cpp0000644000000000000000000002171412627373435016550 0ustar rootroot/* $Id: dedicated_v.cpp 26496 2014-04-24 17:49:31Z frosch $ */ /* * 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 dedicated_v.cpp Dedicated server video 'driver'. */ #include "../stdafx.h" #ifdef ENABLE_NETWORK #include "../gfx_func.h" #include "../network/network.h" #include "../network/network_internal.h" #include "../console_func.h" #include "../genworld.h" #include "../fileio_type.h" #include "../fios.h" #include "../blitter/factory.hpp" #include "../company_func.h" #include "../core/random_func.hpp" #include "../saveload/saveload.h" #include "dedicated_v.h" #ifdef BEOS_NET_SERVER #include #endif #ifdef __OS2__ # include /* gettimeofday */ # include # include # include # define INCL_DOS # include # define STDIN 0 /* file descriptor for standard input */ /** * Switches OpenTTD to a console app at run-time, instead of a PM app * Necessary to see stdout, etc. */ static void OS2_SwitchToConsoleMode() { PPIB pib; PTIB tib; DosGetInfoBlocks(&tib, &pib); /* Change flag from PM to VIO */ pib->pib_ultype = 3; } #endif #if defined(UNIX) || defined(PSP) # include /* gettimeofday */ # include # include # include # define STDIN 0 /* file descriptor for standard input */ # if defined(PSP) # include # include # endif /* PSP */ /* Signal handlers */ static void DedicatedSignalHandler(int sig) { if (_game_mode == GM_NORMAL && _settings_client.gui.autosave_on_exit) DoExitSave(); _exit_game = true; signal(sig, DedicatedSignalHandler); } #endif #if defined(WIN32) # include /* GetTickCount */ # if !defined(WINCE) # include # endif # include # include static HANDLE _hInputReady, _hWaitForInputHandling; static HANDLE _hThread; // Thread to close static char _win_console_thread_buffer[200]; /* Windows Console thread. Just loop and signal when input has been received */ static void WINAPI CheckForConsoleInput() { #if defined(WINCE) /* WinCE doesn't support console stuff */ return; #else DWORD nb; HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); for (;;) { ReadFile(hStdin, _win_console_thread_buffer, lengthof(_win_console_thread_buffer), &nb, NULL); if (nb >= lengthof(_win_console_thread_buffer)) nb = lengthof(_win_console_thread_buffer) - 1; _win_console_thread_buffer[nb] = '\0'; /* Signal input waiting that input is read and wait for it being handled * SignalObjectAndWait() should be used here, but it's unsupported in Win98< */ SetEvent(_hInputReady); WaitForSingleObject(_hWaitForInputHandling, INFINITE); } #endif } static void CreateWindowsConsoleThread() { DWORD dwThreadId; /* Create event to signal when console input is ready */ _hInputReady = CreateEvent(NULL, false, false, NULL); _hWaitForInputHandling = CreateEvent(NULL, false, false, NULL); if (_hInputReady == NULL || _hWaitForInputHandling == NULL) usererror("Cannot create console event!"); _hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)CheckForConsoleInput, NULL, 0, &dwThreadId); if (_hThread == NULL) usererror("Cannot create console thread!"); DEBUG(driver, 2, "Windows console thread started"); } static void CloseWindowsConsoleThread() { CloseHandle(_hThread); CloseHandle(_hInputReady); CloseHandle(_hWaitForInputHandling); DEBUG(driver, 2, "Windows console thread shut down"); } #endif #include "../safeguards.h" static void *_dedicated_video_mem; /* Whether a fork has been done. */ bool _dedicated_forks; extern bool SafeLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL); static FVideoDriver_Dedicated iFVideoDriver_Dedicated; const char *VideoDriver_Dedicated::Start(const char * const *parm) { int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); _dedicated_video_mem = (bpp == 0) ? NULL : MallocT(_cur_resolution.width * _cur_resolution.height * (bpp / 8)); _screen.width = _screen.pitch = _cur_resolution.width; _screen.height = _cur_resolution.height; _screen.dst_ptr = _dedicated_video_mem; ScreenSizeChanged(); BlitterFactory::GetCurrentBlitter()->PostResize(); #if defined(WINCE) /* WinCE doesn't support console stuff */ #elif defined(WIN32) /* For win32 we need to allocate a console (debug mode does the same) */ CreateConsole(); CreateWindowsConsoleThread(); SetConsoleTitle(_T("OpenTTD Dedicated Server")); #endif #ifdef _MSC_VER /* Disable the MSVC assertion message box. */ _set_error_mode(_OUT_TO_STDERR); #endif #ifdef __OS2__ /* For OS/2 we also need to switch to console mode instead of PM mode */ OS2_SwitchToConsoleMode(); #endif DEBUG(driver, 1, "Loading dedicated server"); return NULL; } void VideoDriver_Dedicated::Stop() { #ifdef WIN32 CloseWindowsConsoleThread(); #endif free(_dedicated_video_mem); } void VideoDriver_Dedicated::MakeDirty(int left, int top, int width, int height) {} bool VideoDriver_Dedicated::ChangeResolution(int w, int h) { return false; } bool VideoDriver_Dedicated::ToggleFullscreen(bool fs) { return false; } #if defined(UNIX) || defined(__OS2__) || defined(PSP) static bool InputWaiting() { struct timeval tv; fd_set readfds; tv.tv_sec = 0; tv.tv_usec = 1; FD_ZERO(&readfds); FD_SET(STDIN, &readfds); /* don't care about writefds and exceptfds: */ return select(STDIN + 1, &readfds, NULL, NULL, &tv) > 0; } static uint32 GetTime() { struct timeval tim; gettimeofday(&tim, NULL); return tim.tv_usec / 1000 + tim.tv_sec * 1000; } #else static bool InputWaiting() { return WaitForSingleObject(_hInputReady, 1) == WAIT_OBJECT_0; } static uint32 GetTime() { return GetTickCount(); } #endif static void DedicatedHandleKeyInput() { static char input_line[1024] = ""; if (!InputWaiting()) return; if (_exit_game) return; #if defined(UNIX) || defined(__OS2__) || defined(PSP) if (fgets(input_line, lengthof(input_line), stdin) == NULL) return; #else /* Handle console input, and signal console thread, it can accept input again */ assert_compile(lengthof(_win_console_thread_buffer) <= lengthof(input_line)); strecpy(input_line, _win_console_thread_buffer, lastof(input_line)); SetEvent(_hWaitForInputHandling); #endif /* Remove trailing \r or \n */ for (char *c = input_line; *c != '\0'; c++) { if (*c == '\n' || *c == '\r' || c == lastof(input_line)) { *c = '\0'; break; } } str_validate(input_line, lastof(input_line)); IConsoleCmdExec(input_line); // execute command } void VideoDriver_Dedicated::MainLoop() { uint32 cur_ticks = GetTime(); uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; /* Signal handlers */ #if defined(UNIX) || defined(PSP) signal(SIGTERM, DedicatedSignalHandler); signal(SIGINT, DedicatedSignalHandler); signal(SIGQUIT, DedicatedSignalHandler); #endif /* Load the dedicated server stuff */ _is_network_server = true; _network_dedicated = true; _current_company = _local_company = COMPANY_SPECTATOR; /* If SwitchMode is SM_LOAD_GAME, it means that the user used the '-g' options */ if (_switch_mode != SM_LOAD_GAME) { StartNewGameWithoutGUI(GENERATE_NEW_SEED); SwitchToMode(_switch_mode); _switch_mode = SM_NONE; } else { _switch_mode = SM_NONE; /* First we need to test if the savegame can be loaded, else we will end up playing the * intro game... */ if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL, BASE_DIR)) { /* Loading failed, pop out.. */ DEBUG(net, 0, "Loading requested map failed, aborting"); _networking = false; } else { /* We can load this game, so go ahead */ SwitchToMode(SM_LOAD_GAME); } } /* Done loading, start game! */ if (!_networking) { DEBUG(net, 0, "Dedicated server could not be started, aborting"); return; } while (!_exit_game) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping InteractiveRandom(); // randomness if (!_dedicated_forks) DedicatedHandleKeyInput(); cur_ticks = GetTime(); _realtime_tick += cur_ticks - prev_cur_ticks; if (cur_ticks >= next_tick || cur_ticks < prev_cur_ticks || _ddc_fastforward) { next_tick = cur_ticks + MILLISECONDS_PER_TICK; GameLoop(); UpdateWindows(); } /* Don't sleep when fast forwarding (for desync debugging) */ if (!_ddc_fastforward) { /* Sleep longer on a dedicated server, if the game is paused and no clients connected. * That can allow the CPU to better use deep sleep states. */ if (_pause_mode != 0 && !HasClients()) { CSleep(100); } else { CSleep(1); } } } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/video/video_driver.hpp0000644000000000000000000000551312627373435017002 0ustar rootroot/* $Id: video_driver.hpp 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 video_driver.hpp Base of all video drivers. */ #ifndef VIDEO_VIDEO_DRIVER_HPP #define VIDEO_VIDEO_DRIVER_HPP #include "../driver.h" #include "../core/geometry_type.hpp" /** The base of all video drivers. */ class VideoDriver : public Driver { public: /** * Mark a particular area dirty. * @param left The left most line of the dirty area. * @param top The top most line of the dirty area. * @param width The width of the dirty area. * @param height The height of the dirty area. */ virtual void MakeDirty(int left, int top, int width, int height) = 0; /** * Perform the actual drawing. */ virtual void MainLoop() = 0; /** * Change the resolution of the window. * @param w The new width. * @param h The new height. * @return True if the change succeeded. */ virtual bool ChangeResolution(int w, int h) = 0; /** * Change the full screen setting. * @param fullscreen The new setting. * @return True if the change succeeded. */ virtual bool ToggleFullscreen(bool fullscreen) = 0; /** * Callback invoked after the blitter was changed. * @return True if no error. */ virtual bool AfterBlitterChange() { return true; } virtual bool ClaimMousePointer() { return true; } /** * Whether the driver has a graphical user interface with the end user. * Or in other words, whether we should spawn a thread for world generation * and NewGRF scanning so the graphical updates can keep coming. Otherwise * progress has to be shown on the console, which uses by definition another * thread/process for display purposes. * @return True for all drivers except null and dedicated. */ virtual bool HasGUI() const { return true; } /** * An edit box lost the input focus. Abort character compositing if necessary. */ virtual void EditBoxLostFocus() {} /** * Get the currently active instance of the video driver. */ static VideoDriver *GetInstance() { return static_cast(*DriverFactoryBase::GetActiveDriver(Driver::DT_VIDEO)); } }; extern char *_ini_videodriver; extern int _num_resolutions; extern Dimension _resolutions[32]; extern Dimension _cur_resolution; extern bool _rightclick_emulate; #endif /* VIDEO_VIDEO_DRIVER_HPP */ openttd-1.5.3/src/video/win32_v.h0000644000000000000000000000327612627373435015254 0ustar rootroot/* $Id: win32_v.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 win32_v.h Base of the Windows video driver. */ #ifndef VIDEO_WIN32_H #define VIDEO_WIN32_H #include "video_driver.hpp" /** The video driver for windows. */ class VideoDriver_Win32 : public VideoDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void MakeDirty(int left, int top, int width, int height); /* virtual */ void MainLoop(); /* virtual */ bool ChangeResolution(int w, int h); /* virtual */ bool ToggleFullscreen(bool fullscreen); /* virtual */ bool AfterBlitterChange(); /* virtual */ bool ClaimMousePointer(); /* virtual */ void EditBoxLostFocus(); /* virtual */ const char *GetName() const { return "win32"; } bool MakeWindow(bool full_screen); }; /** The factory for Windows' video driver. */ class FVideoDriver_Win32 : public DriverFactoryBase { public: FVideoDriver_Win32() : DriverFactoryBase(Driver::DT_VIDEO, 10, "win32", "Win32 GDI Video Driver") {} /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Win32(); } }; #endif /* VIDEO_WIN32_H */ openttd-1.5.3/src/video/allegro_v.h0000644000000000000000000000317612627373435015736 0ustar rootroot/* $Id: allegro_v.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 allegro_v.h Base of the Allegro video driver. */ #ifndef VIDEO_ALLEGRO_H #define VIDEO_ALLEGRO_H #include "video_driver.hpp" /** The allegro video driver. */ class VideoDriver_Allegro : public VideoDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void MakeDirty(int left, int top, int width, int height); /* virtual */ void MainLoop(); /* virtual */ bool ChangeResolution(int w, int h); /* virtual */ bool ToggleFullscreen(bool fullscreen); /* virtual */ bool AfterBlitterChange(); /* virtual */ bool ClaimMousePointer(); /* virtual */ const char *GetName() const { return "allegro"; } }; /** Factory for the allegro video driver. */ class FVideoDriver_Allegro : public DriverFactoryBase { public: FVideoDriver_Allegro() : DriverFactoryBase(Driver::DT_VIDEO, 4, "allegro", "Allegro Video Driver") {} /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Allegro(); } }; #endif /* VIDEO_ALLEGRO_H */ openttd-1.5.3/src/video/allegro_v.cpp0000644000000000000000000003452312627373435016271 0ustar rootroot/* $Id: allegro_v.cpp 27167 2015-02-22 23:06:45Z frosch $ */ /* * 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 allegro_v.cpp Implementation of the Allegro video driver. * @note Implementing threaded pushing of data to the display is * not faster (it's a few percent slower) in contrast to the * results gained with threading it for SDL. */ #ifdef WITH_ALLEGRO #include "../stdafx.h" #include "../openttd.h" #include "../gfx_func.h" #include "../rev.h" #include "../blitter/factory.hpp" #include "../network/network.h" #include "../core/random_func.hpp" #include "../core/math_func.hpp" #include "allegro_v.h" #include #include "../safeguards.h" #ifdef _DEBUG /* Allegro replaces SEGV/ABRT signals meaning that the debugger will never * be triggered, so rereplace the signals and make the debugger useful. */ #include #endif static FVideoDriver_Allegro iFVideoDriver_Allegro; static BITMAP *_allegro_screen; #define MAX_DIRTY_RECTS 100 static PointDimension _dirty_rects[MAX_DIRTY_RECTS]; static int _num_dirty_rects; void VideoDriver_Allegro::MakeDirty(int left, int top, int width, int height) { if (_num_dirty_rects < MAX_DIRTY_RECTS) { _dirty_rects[_num_dirty_rects].x = left; _dirty_rects[_num_dirty_rects].y = top; _dirty_rects[_num_dirty_rects].width = width; _dirty_rects[_num_dirty_rects].height = height; } _num_dirty_rects++; } static void DrawSurfaceToScreen() { int n = _num_dirty_rects; if (n == 0) return; _num_dirty_rects = 0; if (n > MAX_DIRTY_RECTS) { blit(_allegro_screen, screen, 0, 0, 0, 0, _allegro_screen->w, _allegro_screen->h); return; } for (int i = 0; i < n; i++) { blit(_allegro_screen, screen, _dirty_rects[i].x, _dirty_rects[i].y, _dirty_rects[i].x, _dirty_rects[i].y, _dirty_rects[i].width, _dirty_rects[i].height); } } static void UpdatePalette(uint start, uint count) { static PALETTE pal; uint end = start + count; for (uint i = start; i != end; i++) { pal[i].r = _cur_palette.palette[i].r / 4; pal[i].g = _cur_palette.palette[i].g / 4; pal[i].b = _cur_palette.palette[i].b / 4; pal[i].filler = 0; } set_palette_range(pal, start, end - 1, 1); } static void InitPalette() { UpdatePalette(0, 256); } static void CheckPaletteAnim() { if (_cur_palette.count_dirty != 0) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); switch (blitter->UsePaletteAnimation()) { case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: UpdatePalette(_cur_palette.first_dirty, _cur_palette.count_dirty); break; case Blitter::PALETTE_ANIMATION_BLITTER: blitter->PaletteAnimate(_cur_palette); break; case Blitter::PALETTE_ANIMATION_NONE: break; default: NOT_REACHED(); } _cur_palette.count_dirty = 0; } } static const Dimension default_resolutions[] = { { 640, 480}, { 800, 600}, {1024, 768}, {1152, 864}, {1280, 800}, {1280, 960}, {1280, 1024}, {1400, 1050}, {1600, 1200}, {1680, 1050}, {1920, 1200} }; static void GetVideoModes() { /* Need to set a gfx_mode as there is NO other way to autodetect for * cards ourselves... and we need a card to get the modes. */ set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); GFX_MODE_LIST *mode_list = get_gfx_mode_list(gfx_driver->id); if (mode_list == NULL) { memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); _num_resolutions = lengthof(default_resolutions); return; } GFX_MODE *modes = mode_list->mode; int n = 0; for (int i = 0; modes[i].bpp != 0; i++) { uint w = modes[i].width; uint h = modes[i].height; if (w >= 640 && h >= 480) { int j; for (j = 0; j < n; j++) { if (_resolutions[j].width == w && _resolutions[j].height == h) break; } if (j == n) { _resolutions[j].width = w; _resolutions[j].height = h; if (++n == lengthof(_resolutions)) break; } } } _num_resolutions = n; SortResolutions(_num_resolutions); destroy_gfx_mode_list(mode_list); } static void GetAvailableVideoMode(uint *w, uint *h) { /* No video modes, so just try it and see where it ends */ if (_num_resolutions == 0) return; /* is the wanted mode among the available modes? */ for (int i = 0; i != _num_resolutions; i++) { if (*w == _resolutions[i].width && *h == _resolutions[i].height) return; } /* use the closest possible resolution */ int best = 0; uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h); for (int i = 1; i != _num_resolutions; ++i) { uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h); if (newdelta < delta) { best = i; delta = newdelta; } } *w = _resolutions[best].width; *h = _resolutions[best].height; } static bool CreateMainSurface(uint w, uint h) { int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); set_color_depth(bpp); GetAvailableVideoMode(&w, &h); if (set_gfx_mode(_fullscreen ? GFX_AUTODETECT_FULLSCREEN : GFX_AUTODETECT_WINDOWED, w, h, 0, 0) != 0) { DEBUG(driver, 0, "Allegro: Couldn't allocate a window to draw on '%s'", allegro_error); return false; } /* The size of the screen might be bigger than the part we can actually draw on! * So calculate the size based on the top, bottom, left and right */ _allegro_screen = create_bitmap_ex(bpp, screen->cr - screen->cl, screen->cb - screen->ct); _screen.width = _allegro_screen->w; _screen.height = _allegro_screen->h; _screen.pitch = ((byte*)screen->line[1] - (byte*)screen->line[0]) / (bpp / 8); _screen.dst_ptr = _allegro_screen->line[0]; /* Initialise the screen so we don't blit garbage to the screen */ memset(_screen.dst_ptr, 0, _screen.height * _screen.pitch); /* Set the mouse at the place where we expect it */ poll_mouse(); _cursor.pos.x = mouse_x; _cursor.pos.y = mouse_y; BlitterFactory::GetCurrentBlitter()->PostResize(); InitPalette(); char caption[32]; seprintf(caption, lastof(caption), "OpenTTD %s", _openttd_revision); set_window_title(caption); enable_hardware_cursor(); select_mouse_cursor(MOUSE_CURSOR_ARROW); show_mouse(_allegro_screen); GameSizeChanged(); return true; } bool VideoDriver_Allegro::ClaimMousePointer() { select_mouse_cursor(MOUSE_CURSOR_NONE); show_mouse(NULL); disable_hardware_cursor(); return true; } struct VkMapping { uint16 vk_from; byte vk_count; byte map_to; }; #define AS(x, z) {x, 0, z} #define AM(x, y, z, w) {x, y - x, z} static const VkMapping _vk_mapping[] = { /* Pageup stuff + up/down */ AM(KEY_PGUP, KEY_PGDN, WKC_PAGEUP, WKC_PAGEDOWN), AS(KEY_UP, WKC_UP), AS(KEY_DOWN, WKC_DOWN), AS(KEY_LEFT, WKC_LEFT), AS(KEY_RIGHT, WKC_RIGHT), AS(KEY_HOME, WKC_HOME), AS(KEY_END, WKC_END), AS(KEY_INSERT, WKC_INSERT), AS(KEY_DEL, WKC_DELETE), /* Map letters & digits */ AM(KEY_A, KEY_Z, 'A', 'Z'), AM(KEY_0, KEY_9, '0', '9'), AS(KEY_ESC, WKC_ESC), AS(KEY_PAUSE, WKC_PAUSE), AS(KEY_BACKSPACE, WKC_BACKSPACE), AS(KEY_SPACE, WKC_SPACE), AS(KEY_ENTER, WKC_RETURN), AS(KEY_TAB, WKC_TAB), /* Function keys */ AM(KEY_F1, KEY_F12, WKC_F1, WKC_F12), /* Numeric part. */ AM(KEY_0_PAD, KEY_9_PAD, '0', '9'), AS(KEY_SLASH_PAD, WKC_NUM_DIV), AS(KEY_ASTERISK, WKC_NUM_MUL), AS(KEY_MINUS_PAD, WKC_NUM_MINUS), AS(KEY_PLUS_PAD, WKC_NUM_PLUS), AS(KEY_ENTER_PAD, WKC_NUM_ENTER), AS(KEY_DEL_PAD, WKC_DELETE), /* Other non-letter keys */ AS(KEY_SLASH, WKC_SLASH), AS(KEY_SEMICOLON, WKC_SEMICOLON), AS(KEY_EQUALS, WKC_EQUALS), AS(KEY_OPENBRACE, WKC_L_BRACKET), AS(KEY_BACKSLASH, WKC_BACKSLASH), AS(KEY_CLOSEBRACE, WKC_R_BRACKET), AS(KEY_QUOTE, WKC_SINGLEQUOTE), AS(KEY_COMMA, WKC_COMMA), AS(KEY_MINUS, WKC_MINUS), AS(KEY_STOP, WKC_PERIOD), AS(KEY_TILDE, WKC_BACKQUOTE), }; static uint32 ConvertAllegroKeyIntoMy(WChar *character) { int scancode; int unicode = ureadkey(&scancode); const VkMapping *map; uint key = 0; for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { if ((uint)(scancode - map->vk_from) <= map->vk_count) { key = scancode - map->vk_from + map->map_to; break; } } if (key_shifts & KB_SHIFT_FLAG) key |= WKC_SHIFT; if (key_shifts & KB_CTRL_FLAG) key |= WKC_CTRL; if (key_shifts & KB_ALT_FLAG) key |= WKC_ALT; #if 0 DEBUG(driver, 0, "Scancode character pressed %u", scancode); DEBUG(driver, 0, "Unicode character pressed %u", unicode); #endif *character = unicode; return key; } static const uint LEFT_BUTTON = 0; static const uint RIGHT_BUTTON = 1; static void PollEvent() { poll_mouse(); bool mouse_action = false; /* Mouse buttons */ static int prev_button_state; if (prev_button_state != mouse_b) { uint diff = prev_button_state ^ mouse_b; while (diff != 0) { uint button = FindFirstBit(diff); ClrBit(diff, button); if (HasBit(mouse_b, button)) { /* Pressed mouse button */ if (_rightclick_emulate && (key_shifts & KB_CTRL_FLAG)) { button = RIGHT_BUTTON; ClrBit(diff, RIGHT_BUTTON); } switch (button) { case LEFT_BUTTON: _left_button_down = true; break; case RIGHT_BUTTON: _right_button_down = true; _right_button_clicked = true; break; default: /* ignore rest */ break; } } else { /* Released mouse button */ if (_rightclick_emulate) { _right_button_down = false; _left_button_down = false; _left_button_clicked = false; } else if (button == LEFT_BUTTON) { _left_button_down = false; _left_button_clicked = false; } else if (button == RIGHT_BUTTON) { _right_button_down = false; } } } prev_button_state = mouse_b; mouse_action = true; } /* Mouse movement */ if (_cursor.UpdateCursorPosition(mouse_x, mouse_y, false)) { position_mouse(_cursor.pos.x, _cursor.pos.y); } if (_cursor.delta.x != 0 || _cursor.delta.y) mouse_action = true; static int prev_mouse_z = 0; if (prev_mouse_z != mouse_z) { _cursor.wheel = (prev_mouse_z - mouse_z) < 0 ? -1 : 1; prev_mouse_z = mouse_z; mouse_action = true; } if (mouse_action) HandleMouseEvents(); poll_keyboard(); if ((key_shifts & KB_ALT_FLAG) && (key[KEY_ENTER] || key[KEY_F])) { ToggleFullScreen(!_fullscreen); } else if (keypressed()) { WChar character; uint keycode = ConvertAllegroKeyIntoMy(&character); HandleKeypress(keycode, character); } } /** * There are multiple modules that might be using Allegro and * Allegro can only be initiated once. */ int _allegro_instance_count = 0; const char *VideoDriver_Allegro::Start(const char * const *parm) { if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, NULL)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); return "Failed to set up Allegro"; } _allegro_instance_count++; install_timer(); install_mouse(); install_keyboard(); #if defined _DEBUG /* Allegro replaces SEGV/ABRT signals meaning that the debugger will never * be triggered, so rereplace the signals and make the debugger useful. */ signal(SIGABRT, NULL); signal(SIGSEGV, NULL); #endif #if defined(DOS) /* Force DOS builds to ALWAYS use full screen as * it can't do windowed. */ _fullscreen = true; #endif GetVideoModes(); if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height)) { return "Failed to set up Allegro video"; } MarkWholeScreenDirty(); set_close_button_callback(HandleExitGameRequest); return NULL; } void VideoDriver_Allegro::Stop() { if (--_allegro_instance_count == 0) allegro_exit(); } #if defined(UNIX) || defined(__OS2__) || defined(PSP) || defined(DOS) # include /* gettimeofday */ static uint32 GetTime() { struct timeval tim; gettimeofday(&tim, NULL); return tim.tv_usec / 1000 + tim.tv_sec * 1000; } #else static uint32 GetTime() { return GetTickCount(); } #endif void VideoDriver_Allegro::MainLoop() { uint32 cur_ticks = GetTime(); uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; CheckPaletteAnim(); for (;;) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping InteractiveRandom(); // randomness PollEvent(); if (_exit_game) return; #if defined(_DEBUG) if (_shift_pressed) #else /* Speedup when pressing tab, except when using ALT+TAB * to switch to another application */ if (key[KEY_TAB] && (key_shifts & KB_ALT_FLAG) == 0) #endif { if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; } else if (_fast_forward & 2) { _fast_forward = 0; } cur_ticks = GetTime(); if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { _realtime_tick += cur_ticks - last_cur_ticks; last_cur_ticks = cur_ticks; next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; _ctrl_pressed = !!(key_shifts & KB_CTRL_FLAG); _shift_pressed = !!(key_shifts & KB_SHIFT_FLAG); /* determine which directional keys are down */ _dirkeys = (key[KEY_LEFT] ? 1 : 0) | (key[KEY_UP] ? 2 : 0) | (key[KEY_RIGHT] ? 4 : 0) | (key[KEY_DOWN] ? 8 : 0); if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); GameLoop(); UpdateWindows(); CheckPaletteAnim(); DrawSurfaceToScreen(); } else { CSleep(1); NetworkDrawChatMessage(); DrawMouseCursor(); DrawSurfaceToScreen(); } } } bool VideoDriver_Allegro::ChangeResolution(int w, int h) { return CreateMainSurface(w, h); } bool VideoDriver_Allegro::ToggleFullscreen(bool fullscreen) { #ifdef DOS return false; #else _fullscreen = fullscreen; GetVideoModes(); // get the list of available video modes if (_num_resolutions == 0 || !this->ChangeResolution(_cur_resolution.width, _cur_resolution.height)) { /* switching resolution failed, put back full_screen to original status */ _fullscreen ^= true; return false; } return true; #endif } bool VideoDriver_Allegro::AfterBlitterChange() { return CreateMainSurface(_screen.width, _screen.height); } #endif /* WITH_ALLEGRO */ openttd-1.5.3/src/video/null_v.h0000644000000000000000000000315512627373435015260 0ustar rootroot/* $Id: null_v.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 null_v.h Base of the video driver that doesn't blit. */ #ifndef VIDEO_NULL_H #define VIDEO_NULL_H #include "video_driver.hpp" /** The null video driver. */ class VideoDriver_Null : public VideoDriver { private: uint ticks; ///< Amount of ticks to run. public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void MakeDirty(int left, int top, int width, int height); /* virtual */ void MainLoop(); /* virtual */ bool ChangeResolution(int w, int h); /* virtual */ bool ToggleFullscreen(bool fullscreen); /* virtual */ const char *GetName() const { return "null"; } /* virtual */ bool HasGUI() const { return false; } }; /** Factory the null video driver. */ class FVideoDriver_Null : public DriverFactoryBase { public: FVideoDriver_Null() : DriverFactoryBase(Driver::DT_VIDEO, 0, "null", "Null Video Driver") {} /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Null(); } }; #endif /* VIDEO_NULL_H */ openttd-1.5.3/src/video/cocoa/0000755000000000000000000000000012627373435014670 5ustar rootrootopenttd-1.5.3/src/video/cocoa/wnd_quickdraw.mm0000644000000000000000000004254312627373435020075 0ustar rootroot/* $Id: wnd_quickdraw.mm 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 . */ /****************************************************************************** * Cocoa video driver * * Known things left to do: * * List available resolutions. * ******************************************************************************/ #ifdef WITH_COCOA #ifdef ENABLE_COCOA_QUICKDRAW #define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3 #include "../../stdafx.h" #include "../../os/macosx/macos.h" #define Rect OTTDRect #define Point OTTDPoint #import #undef Rect #undef Point #include "../../debug.h" #include "../../rev.h" #include "../../core/geometry_type.hpp" #include "cocoa_v.h" #include "../../core/math_func.hpp" #include "../../gfx_func.h" /** * Important notice regarding all modifications!!!!!!! * There are certain limitations because the file is objective C++. * gdb has limitations. * C++ and objective C code can't be joined in all cases (classes stuff). * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. */ class WindowQuickdrawSubdriver; class WindowQuickdrawSubdriver : public CocoaSubdriver { private: /** * This function copies 32bpp pixels from the screen buffer in 16bpp windowed mode. * * @param left The x coord for the left edge of the box to blit. * @param top The y coord for the top edge of the box to blit. * @param right The x coord for the right edge of the box to blit. * @param bottom The y coord for the bottom edge of the box to blit. */ void Blit32ToView32(int left, int top, int right, int bottom); /** * This function copies 8bpp pixels from the screen buffer in 32bpp windowed mode. * * @param left The x coord for the left edge of the box to blit. * @param top The y coord for the top edge of the box to blit. * @param right The x coord for the right edge of the box to blit. * @param bottom The y coord for the bottom edge of the box to blit. */ void BlitIndexedToView32(int left, int top, int right, int bottom); /** * This function copies 8bpp pixels from the screen buffer in 16bpp windowed mode. * * @param left The x coord for the left edge of the box to blit. * @param top The y coord for the top edge of the box to blit. * @param right The x coord for the right edge of the box to blit. * @param bottom The y coord for the bottom edge of the box to blit. */ void BlitIndexedToView16(int left, int top, int right, int bottom); inline void BlitToView(int left, int top, int right, int bottom); void DrawResizeIcon(); virtual void GetDeviceInfo(); virtual bool SetVideoMode(int width, int height, int bpp); public: WindowQuickdrawSubdriver(); virtual ~WindowQuickdrawSubdriver(); virtual void Draw(bool force_update); virtual void MakeDirty(int left, int top, int width, int height); virtual void UpdatePalette(uint first_color, uint num_colors); virtual uint ListModes(OTTD_Point *modes, uint max_modes); virtual bool ChangeResolution(int w, int h, int bpp); virtual bool IsFullscreen() { return false; } virtual int GetWidth() { return window_width; } virtual int GetHeight() { return window_height; } virtual void *GetPixelBuffer() { return pixel_buffer; } /* Convert local coordinate to window server (CoreGraphics) coordinate */ virtual CGPoint PrivateLocalToCG(NSPoint *p); virtual NSPoint GetMouseLocation(NSEvent *event); virtual bool MouseIsInsideView(NSPoint *pt); virtual bool IsActive() { return active; } void SetPortAlphaOpaque(); bool WindowResized(); }; static const int _resize_icon_width = 16; static const int _resize_icon_height = 16; static bool _resize_icon[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 }; void WindowQuickdrawSubdriver::GetDeviceInfo() { /* Initialize the video settings; this data persists between mode switches */ CFDictionaryRef cur_mode = CGDisplayCurrentMode(kCGDirectMainDisplay); /* Gather some information that is useful to know about the display */ CFNumberGetValue((const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayBitsPerPixel), kCFNumberSInt32Type, &this->device_depth); CFNumberGetValue((const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayWidth), kCFNumberSInt32Type, &this->device_width); CFNumberGetValue((const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayHeight), kCFNumberSInt32Type, &this->device_height); } bool WindowQuickdrawSubdriver::SetVideoMode(int width, int height, int bpp) { this->setup = true; this->GetDeviceInfo(); if (bpp > this->device_depth) { DEBUG(driver, 0, "Cannot use a blitter with a higher screen depth than the display when running in windowed mode."); this->setup = false; return false; } if (width > this->device_width) width = this->device_width; if (height > this->device_height) height = this->device_height; NSRect contentRect = NSMakeRect(0, 0, width, height); /* Check if we should recreate the window */ if (this->window == nil) { OTTD_CocoaWindowDelegate *delegate; /* Set the window style */ unsigned int style = NSTitledWindowMask; style |= (NSMiniaturizableWindowMask | NSClosableWindowMask); style |= NSResizableWindowMask; /* Manually create a window, avoids having a nib file resource */ this->window = [ [ OTTD_CocoaWindow alloc ] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:NO ]; if (this->window == nil) { DEBUG(driver, 0, "Could not create the Cocoa window."); this->setup = false; return false; } [ this->window setDriver:this ]; char caption[50]; snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision); NSString *nsscaption = [ [ NSString alloc ] initWithUTF8String:caption ]; [ this->window setTitle:nsscaption ]; [ this->window setMiniwindowTitle:nsscaption ]; [ nsscaption release ]; [ this->window setContentMinSize:NSMakeSize(64.0f, 64.0f) ]; [ this->window setAcceptsMouseMovedEvents:YES ]; [ this->window setViewsNeedDisplay:NO ]; delegate = [ [ OTTD_CocoaWindowDelegate alloc ] init ]; [ delegate setDriver:this ]; [ this->window setDelegate: [ delegate autorelease ] ]; } else { /* We already have a window, just change its size */ [ this->window setContentSize:contentRect.size ]; /* Ensure frame height - title bar height >= view height * The height of title bar of the window is 22 pixels */ contentRect.size.height = Clamp(height, 0, [ this->window frame ].size.height - 22); height = contentRect.size.height; [ this->cocoaview setFrameSize:contentRect.size ]; } /* Update again */ this->window_width = width; this->window_height = height; this->buffer_depth = bpp; [ this->window center ]; /* Only recreate the view if it doesn't already exist */ if (this->cocoaview == nil) { this->cocoaview = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ]; if (this->cocoaview == nil) { DEBUG(driver, 0, "Could not create the Quickdraw view."); this->setup = false; return false; } [ this->cocoaview setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ]; [ [ this->window contentView ] addSubview:this->cocoaview ]; [ this->cocoaview release ]; [ this->window makeKeyAndOrderFront:nil ]; } bool ret = this->WindowResized(); this->UpdatePalette(0, 256); this->setup = false; return ret; } void WindowQuickdrawSubdriver::Blit32ToView32(int left, int top, int right, int bottom) { const uint32 *src = (uint32*)this->pixel_buffer; uint32 *dst = (uint32*)this->window_buffer; uint width = this->window_width; uint pitch = this->window_pitch / 4; dst += top * pitch + left; src += top * width + left; for (int y = top; y < bottom; y++, dst+= pitch, src+= width) { memcpy(dst, src, (right - left) * 4); } } void WindowQuickdrawSubdriver::BlitIndexedToView32(int left, int top, int right, int bottom) { const uint32 *pal = this->palette; const uint8 *src = (uint8*)this->pixel_buffer; uint32 *dst = (uint32*)this->window_buffer; uint width = this->window_width; uint pitch = this->window_pitch / 4; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { dst[y * pitch + x] = pal[src[y * width + x]]; } } } void WindowQuickdrawSubdriver::BlitIndexedToView16(int left, int top, int right, int bottom) { const uint32 *pal = this->palette; const uint8 *src = (uint8*)this->pixel_buffer; uint16 *dst = (uint16*)this->window_buffer; uint width = this->window_width; uint pitch = this->window_pitch / 2; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { dst[y * pitch + x] = pal[src[y * width + x]]; } } } inline void WindowQuickdrawSubdriver::BlitToView(int left, int top, int right, int bottom) { switch (this->device_depth) { case 32: switch (this->buffer_depth) { case 32: this->Blit32ToView32(left, top, right, bottom); break; case 8: this->BlitIndexedToView32(left, top, right, bottom); break; } break; case 16: this->BlitIndexedToView16(left, top, right, bottom); break; } } void WindowQuickdrawSubdriver::DrawResizeIcon() { int xoff = this->window_width - _resize_icon_width; int yoff = this->window_height - _resize_icon_height; switch (this->device_depth) { case 32: for (int y = 0; y < _resize_icon_height; y++) { uint32 *trg = (uint32*)this->window_buffer + (yoff + y) * this->window_pitch / 4 + xoff; for (int x = 0; x < _resize_icon_width; x++, trg++) { if (_resize_icon[y * _resize_icon_width + x]) *trg = 0xff000000; } } break; case 16: for (int y = 0; y < _resize_icon_height; y++) { uint16 *trg = (uint16*)this->window_buffer + (yoff + y) * this->window_pitch / 2 + xoff; for (int x = 0; x < _resize_icon_width; x++, trg++) { if (_resize_icon[y * _resize_icon_width + x]) *trg = 0x0000; } } break; } } WindowQuickdrawSubdriver::WindowQuickdrawSubdriver() { this->window_width = 0; this->window_height = 0; this->buffer_depth = 0; this->pixel_buffer = NULL; this->active = false; this->setup = false; this->window = nil; this->cocoaview = nil; this->num_dirty_rects = MAX_DIRTY_RECTS; } WindowQuickdrawSubdriver::~WindowQuickdrawSubdriver() { /* Release window mode resources */ if (this->window != nil) [ this->window close ]; free(this->pixel_buffer); } void WindowQuickdrawSubdriver::Draw(bool force_update) { /* Check if we need to do anything */ if (this->num_dirty_rects == 0 || [ this->window isMiniaturized ]) return; if (this->num_dirty_rects >= MAX_DIRTY_RECTS) { this->num_dirty_rects = 1; this->dirty_rects[0].left = 0; this->dirty_rects[0].top = 0; this->dirty_rects[0].right = this->window_width; this->dirty_rects[0].bottom = this->window_height; } RgnHandle dirty = NewRgn(); RgnHandle temp = NewRgn(); SetEmptyRgn(dirty); /* Build the region of dirty rectangles */ for (int i = 0; i < this->num_dirty_rects; i++) { this->BlitToView(this->dirty_rects[i].left, this->dirty_rects[i].top, this->dirty_rects[i].right, this->dirty_rects[i].bottom); MacSetRectRgn(temp, this->dirty_rects[i].left, this->dirty_rects[i].top, this->dirty_rects[i].right, this->dirty_rects[i].bottom); MacUnionRgn(dirty, temp, dirty); } this->DrawResizeIcon(); /* Flush the dirty region */ QDFlushPortBuffer( (OpaqueGrafPtr*) [ this->cocoaview qdPort ], dirty); DisposeRgn(dirty); DisposeRgn(temp); this->num_dirty_rects = 0; } void WindowQuickdrawSubdriver::MakeDirty(int left, int top, int width, int height) { if (this->num_dirty_rects < MAX_DIRTY_RECTS) { this->dirty_rects[this->num_dirty_rects].left = left; this->dirty_rects[this->num_dirty_rects].top = top; this->dirty_rects[this->num_dirty_rects].right = left + width; this->dirty_rects[this->num_dirty_rects].bottom = top + height; } this->num_dirty_rects++; } void WindowQuickdrawSubdriver::UpdatePalette(uint first_color, uint num_colors) { if (this->buffer_depth != 8) return; switch (this->device_depth) { case 32: for (uint i = first_color; i < first_color + num_colors; i++) { uint32 clr32 = 0xff000000; clr32 |= (uint32)_cur_palette.palette[i].r << 16; clr32 |= (uint32)_cur_palette.palette[i].g << 8; clr32 |= (uint32)_cur_palette.palette[i].b; this->palette[i] = clr32; } break; case 16: for (uint i = first_color; i < first_color + num_colors; i++) { uint16 clr16 = 0x0000; clr16 |= (uint16)((_cur_palette.palette[i].r >> 3) & 0x1f) << 10; clr16 |= (uint16)((_cur_palette.palette[i].g >> 3) & 0x1f) << 5; clr16 |= (uint16)((_cur_palette.palette[i].b >> 3) & 0x1f); this->palette[i] = clr16; } break; } this->num_dirty_rects = MAX_DIRTY_RECTS; } uint WindowQuickdrawSubdriver::ListModes(OTTD_Point *modes, uint max_modes) { return QZ_ListModes(modes, max_modes, kCGDirectMainDisplay, this->buffer_depth); } bool WindowQuickdrawSubdriver::ChangeResolution(int w, int h, int bpp) { int old_width = this->window_width; int old_height = this->window_height; int old_bpp = this->buffer_depth; if (this->SetVideoMode(w, h, bpp)) return true; if (old_width != 0 && old_height != 0) this->SetVideoMode(old_width, old_height, old_bpp); return false; } /* Convert local coordinate to window server (CoreGraphics) coordinate */ CGPoint WindowQuickdrawSubdriver::PrivateLocalToCG(NSPoint *p) { *p = [ this->cocoaview convertPoint:*p toView: nil ]; *p = [ this->window convertBaseToScreen:*p ]; p->y = this->device_height - p->y; return CGPointMake(p->x, p->y); } NSPoint WindowQuickdrawSubdriver::GetMouseLocation(NSEvent *event) { NSPoint pt = [ event locationInWindow ]; pt = [ this->cocoaview convertPoint:pt fromView:nil ]; return pt; } bool WindowQuickdrawSubdriver::MouseIsInsideView(NSPoint *pt) { return [ this->cocoaview mouse:*pt inRect:[ this->cocoaview bounds ] ]; } /* This function makes the *game region* of the window 100% opaque. * The genie effect uses the alpha component. Otherwise, * it doesn't seem to matter what value it has. */ void WindowQuickdrawSubdriver::SetPortAlphaOpaque() { if (this->device_depth != 32) return; uint32 *pixels = (uint32*)this->window_buffer; uint32 pitch = this->window_pitch / 4; for (int y = 0; y < this->window_height; y++) for (int x = 0; x < this->window_width; x++) { pixels[y * pitch + x] |= 0xFF000000; } } bool WindowQuickdrawSubdriver::WindowResized() { if (this->window == nil || this->cocoaview == nil) return true; NSRect newframe = [ this->cocoaview frame ]; CGrafPtr thePort = (OpaqueGrafPtr*) [ this->cocoaview qdPort ]; LockPortBits(thePort); this->window_buffer = GetPixBaseAddr(GetPortPixMap(thePort)); this->window_pitch = GetPixRowBytes(GetPortPixMap(thePort)); UnlockPortBits(thePort); /* _cocoa_video_data.realpixels now points to the window's pixels * We want it to point to the *view's* pixels */ int voff = [ this->window frame ].size.height - newframe.size.height - newframe.origin.y; int hoff = [ this->cocoaview frame ].origin.x; this->window_buffer = (uint8*)this->window_buffer + (voff * this->window_pitch) + hoff * (this->device_depth / 8); this->window_width = newframe.size.width; this->window_height = newframe.size.height; free(this->pixel_buffer); this->pixel_buffer = malloc(this->window_width * this->window_height * this->buffer_depth / 8); if (this->pixel_buffer == NULL) { DEBUG(driver, 0, "Failed to allocate pixel buffer"); return false; } QZ_GameSizeChanged(); /* Redraw screen */ this->num_dirty_rects = MAX_DIRTY_RECTS; return true; } CocoaSubdriver *QZ_CreateWindowQuickdrawSubdriver(int width, int height, int bpp) { WindowQuickdrawSubdriver *ret; if (MacOSVersionIsAtLeast(10, 5, 0)) { DEBUG(driver, 0, "The cocoa quickdraw subdriver is not recommended for Mac OS X 10.5 or later."); } if (bpp != 8 && bpp != 32) { DEBUG(driver, 0, "The cocoa quickdraw subdriver only supports 8 and 32 bpp."); return NULL; } ret = new WindowQuickdrawSubdriver(); if (!ret->ChangeResolution(width, height, bpp)) { delete ret; return NULL; } return ret; } #endif /* ENABLE_COCOA_QUICKDRAW */ #endif /* WITH_COCOA */ openttd-1.5.3/src/video/cocoa/wnd_quartz.mm0000644000000000000000000004741012627373435017427 0ustar rootroot/* $Id: wnd_quartz.mm 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 . */ /****************************************************************************** * Cocoa video driver * * Known things left to do: * * List available resolutions. * ******************************************************************************/ #ifdef WITH_COCOA #ifdef ENABLE_COCOA_QUARTZ #include "../../stdafx.h" #include "../../os/macosx/macos.h" #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 #define Rect OTTDRect #define Point OTTDPoint #import #undef Rect #undef Point #include "../../debug.h" #include "../../rev.h" #include "../../core/geometry_type.hpp" #include "cocoa_v.h" #include "../../core/math_func.hpp" #include "../../gfx_func.h" /* On some old versions of MAC OS this may not be defined. * Those versions generally only produce code for PPC. So it should be safe to * set this to 0. */ #ifndef kCGBitmapByteOrder32Host #define kCGBitmapByteOrder32Host 0 #endif /** * Important notice regarding all modifications!!!!!!! * There are certain limitations because the file is objective C++. * gdb has limitations. * C++ and objective C code can't be joined in all cases (classes stuff). * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. */ class WindowQuartzSubdriver; /* Subclass of OTTD_CocoaView to fix Quartz rendering */ @interface OTTD_QuartzView : OTTD_CocoaView - (void)setDriver:(WindowQuartzSubdriver*)drv; - (void)drawRect:(NSRect)invalidRect; @end class WindowQuartzSubdriver : public CocoaSubdriver { private: /** * This function copies 8bpp pixels from the screen buffer in 32bpp windowed mode. * * @param left The x coord for the left edge of the box to blit. * @param top The y coord for the top edge of the box to blit. * @param right The x coord for the right edge of the box to blit. * @param bottom The y coord for the bottom edge of the box to blit. */ void BlitIndexedToView32(int left, int top, int right, int bottom); virtual void GetDeviceInfo(); virtual bool SetVideoMode(int width, int height, int bpp); public: WindowQuartzSubdriver(); virtual ~WindowQuartzSubdriver(); virtual void Draw(bool force_update); virtual void MakeDirty(int left, int top, int width, int height); virtual void UpdatePalette(uint first_color, uint num_colors); virtual uint ListModes(OTTD_Point *modes, uint max_modes); virtual bool ChangeResolution(int w, int h, int bpp); virtual bool IsFullscreen() { return false; } virtual bool ToggleFullscreen(); /* Full screen mode on OSX 10.7 */ virtual int GetWidth() { return window_width; } virtual int GetHeight() { return window_height; } virtual void *GetPixelBuffer() { return buffer_depth == 8 ? pixel_buffer : window_buffer; } /* Convert local coordinate to window server (CoreGraphics) coordinate */ virtual CGPoint PrivateLocalToCG(NSPoint *p); virtual NSPoint GetMouseLocation(NSEvent *event); virtual bool MouseIsInsideView(NSPoint *pt); virtual bool IsActive() { return active; } void SetPortAlphaOpaque(); bool WindowResized(); }; static CGColorSpaceRef QZ_GetCorrectColorSpace() { static CGColorSpaceRef colorSpace = NULL; if (colorSpace == NULL) { CMProfileRef sysProfile; if (CMGetSystemProfile(&sysProfile) == noErr) { colorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysProfile); CMCloseProfile(sysProfile); } else { colorSpace = CGColorSpaceCreateDeviceRGB(); } if (colorSpace == NULL) error("Could not get system colour space. You might need to recalibrate your monitor."); } return colorSpace; } @implementation OTTD_QuartzView - (void)setDriver:(WindowQuartzSubdriver*)drv { driver = drv; } - (void)drawRect:(NSRect)invalidRect { if (driver->cgcontext == NULL) return; CGContextRef viewContext = (CGContextRef)[ [ NSGraphicsContext currentContext ] graphicsPort ]; CGContextSetShouldAntialias(viewContext, FALSE); CGContextSetInterpolationQuality(viewContext, kCGInterpolationNone); /* The obtained 'rect' is actually a union of all dirty rects, let's ask for an explicit list of rects instead */ const NSRect *dirtyRects; NSInteger dirtyRectCount; [ self getRectsBeingDrawn:&dirtyRects count:&dirtyRectCount ]; /* We need an Image in order to do blitting, but as we don't touch the context between this call and drawing no copying will actually be done here */ CGImageRef fullImage = CGBitmapContextCreateImage(driver->cgcontext); /* Calculate total area we are blitting */ uint32 blitArea = 0; for (int n = 0; n < dirtyRectCount; n++) { blitArea += (uint32)(dirtyRects[n].size.width * dirtyRects[n].size.height); } /* * This might be completely stupid, but in my extremely subjective opinion it feels faster * The point is, if we're blitting less than 50% of the dirty rect union then it's still a good idea to blit each dirty * rect separately but if we blit more than that, it's just cheaper to blit the entire union in one pass. * Feel free to remove or find an even better value than 50% ... / blackis */ NSRect frameRect = [ self frame ]; if (blitArea / (float)(invalidRect.size.width * invalidRect.size.height) > 0.5f) { NSRect rect = invalidRect; CGRect clipRect; CGRect blitRect; blitRect.origin.x = rect.origin.x; blitRect.origin.y = rect.origin.y; blitRect.size.width = rect.size.width; blitRect.size.height = rect.size.height; clipRect.origin.x = rect.origin.x; clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height; clipRect.size.width = rect.size.width; clipRect.size.height = rect.size.height; /* Blit dirty part of image */ CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect); CGContextDrawImage(viewContext, blitRect, clippedImage); CGImageRelease(clippedImage); } else { for (int n = 0; n < dirtyRectCount; n++) { NSRect rect = dirtyRects[n]; CGRect clipRect; CGRect blitRect; blitRect.origin.x = rect.origin.x; blitRect.origin.y = rect.origin.y; blitRect.size.width = rect.size.width; blitRect.size.height = rect.size.height; clipRect.origin.x = rect.origin.x; clipRect.origin.y = frameRect.size.height - rect.origin.y - rect.size.height; clipRect.size.width = rect.size.width; clipRect.size.height = rect.size.height; /* Blit dirty part of image */ CGImageRef clippedImage = CGImageCreateWithImageInRect(fullImage, clipRect); CGContextDrawImage(viewContext, blitRect, clippedImage); CGImageRelease(clippedImage); } } CGImageRelease(fullImage); } @end void WindowQuartzSubdriver::GetDeviceInfo() { /* Initialize the video settings; this data persists between mode switches * and gather some information that is useful to know about the display */ # if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 /* This way is deprecated as of OSX 10.6 but continues to work.Thus use it * always, unless allowed to skip compatibility with 10.5 and earlier */ CFDictionaryRef cur_mode = CGDisplayCurrentMode(kCGDirectMainDisplay); CFNumberGetValue( (const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayWidth), kCFNumberSInt32Type, &this->device_width ); CFNumberGetValue( (const __CFNumber*)CFDictionaryGetValue(cur_mode, kCGDisplayHeight), kCFNumberSInt32Type, &this->device_height ); # else /* Use the new API when compiling for OSX 10.6 or later */ CGDisplayModeRef cur_mode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay); if (cur_mode == NULL) { return; } this->device_width = CGDisplayModeGetWidth(cur_mode); this->device_height = CGDisplayModeGetHeight(cur_mode); CGDisplayModeRelease(cur_mode); # endif } /** Switch to full screen mode on OSX 10.7 * @return Whether we switched to full screen */ bool WindowQuartzSubdriver::ToggleFullscreen() { if ([ this->window respondsToSelector:@selector(toggleFullScreen:) ]) { [ this->window performSelector:@selector(toggleFullScreen:) withObject:this->window ]; return true; } return false; } bool WindowQuartzSubdriver::SetVideoMode(int width, int height, int bpp) { this->setup = true; this->GetDeviceInfo(); if (width > this->device_width) width = this->device_width; if (height > this->device_height) height = this->device_height; NSRect contentRect = NSMakeRect(0, 0, width, height); /* Check if we should recreate the window */ if (this->window == nil) { OTTD_CocoaWindowDelegate *delegate; /* Set the window style */ unsigned int style = NSTitledWindowMask; style |= (NSMiniaturizableWindowMask | NSClosableWindowMask); style |= NSResizableWindowMask; /* Manually create a window, avoids having a nib file resource */ this->window = [ [ OTTD_CocoaWindow alloc ] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:NO ]; if (this->window == nil) { DEBUG(driver, 0, "Could not create the Cocoa window."); this->setup = false; return false; } #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 /* Add built in full-screen support when available (OS X 10.7 and higher) * This code actually compiles for 10.5 and later, but only makes sense in conjunction * with the quartz fullscreen support as found only in 10.7 and later */ if ([this->window respondsToSelector:@selector(toggleFullScreen:)]) { #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 /* Constants needed to build on pre-10.7 SDKs. Source: NSWindow documentation. */ const int NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7; const int NSWindowFullScreenButton = 7; #endif NSWindowCollectionBehavior behavior = [ this->window collectionBehavior ]; behavior |= NSWindowCollectionBehaviorFullScreenPrimary; [ this->window setCollectionBehavior:behavior ]; NSButton* fullscreenButton = [ this->window standardWindowButton:NSWindowFullScreenButton ]; [ fullscreenButton setAction:@selector(toggleFullScreen:) ]; [ fullscreenButton setTarget:this->window ]; [ this->window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary ]; } #endif [ this->window setDriver:this ]; char caption[50]; snprintf(caption, sizeof(caption), "OpenTTD %s", _openttd_revision); NSString *nsscaption = [ [ NSString alloc ] initWithUTF8String:caption ]; [ this->window setTitle:nsscaption ]; [ this->window setMiniwindowTitle:nsscaption ]; [ nsscaption release ]; [ this->window setContentMinSize:NSMakeSize(64.0f, 64.0f) ]; [ this->window setAcceptsMouseMovedEvents:YES ]; [ this->window setViewsNeedDisplay:NO ]; [ this->window useOptimizedDrawing:YES ]; delegate = [ [ OTTD_CocoaWindowDelegate alloc ] init ]; [ delegate setDriver:this ]; [ this->window setDelegate:[ delegate autorelease ] ]; } else { /* We already have a window, just change its size */ [ this->window setContentSize:contentRect.size ]; /* Ensure frame height - title bar height >= view height */ contentRect.size.height = Clamp(height, 0, (int)[ this->window frame ].size.height - 22 /* 22 is the height of title bar of window*/); if (this->cocoaview != nil) { height = (int)contentRect.size.height; [ this->cocoaview setFrameSize:contentRect.size ]; } } this->window_width = width; this->window_height = height; this->buffer_depth = bpp; [ this->window center ]; /* Only recreate the view if it doesn't already exist */ if (this->cocoaview == nil) { this->cocoaview = [ [ OTTD_QuartzView alloc ] initWithFrame:contentRect ]; if (this->cocoaview == nil) { DEBUG(driver, 0, "Could not create the Quartz view."); this->setup = false; return false; } [ this->cocoaview setDriver:this ]; [ (NSView*)this->cocoaview setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable ]; [ this->window setContentView:cocoaview ]; [ this->cocoaview release ]; [ this->window makeKeyAndOrderFront:nil ]; } bool ret = WindowResized(); this->UpdatePalette(0, 256); this->setup = false; return ret; } void WindowQuartzSubdriver::BlitIndexedToView32(int left, int top, int right, int bottom) { const uint32 *pal = this->palette; const uint8 *src = (uint8*)this->pixel_buffer; uint32 *dst = (uint32*)this->window_buffer; uint width = this->window_width; uint pitch = this->window_width; for (int y = top; y < bottom; y++) { for (int x = left; x < right; x++) { dst[y * pitch + x] = pal[src[y * width + x]]; } } } WindowQuartzSubdriver::WindowQuartzSubdriver() { this->window_width = 0; this->window_height = 0; this->buffer_depth = 0; this->window_buffer = NULL; this->pixel_buffer = NULL; this->active = false; this->setup = false; this->window = nil; this->cocoaview = nil; this->cgcontext = NULL; this->num_dirty_rects = MAX_DIRTY_RECTS; } WindowQuartzSubdriver::~WindowQuartzSubdriver() { /* Release window mode resources */ if (this->window != nil) [ this->window close ]; CGContextRelease(this->cgcontext); free(this->window_buffer); free(this->pixel_buffer); } void WindowQuartzSubdriver::Draw(bool force_update) { /* Check if we need to do anything */ if (this->num_dirty_rects == 0 || [ this->window isMiniaturized ]) return; if (this->num_dirty_rects >= MAX_DIRTY_RECTS) { this->num_dirty_rects = 1; this->dirty_rects[0].left = 0; this->dirty_rects[0].top = 0; this->dirty_rects[0].right = this->window_width; this->dirty_rects[0].bottom = this->window_height; } /* Build the region of dirty rectangles */ for (int i = 0; i < this->num_dirty_rects; i++) { /* We only need to blit in indexed mode since in 32bpp mode the game draws directly to the image. */ if (this->buffer_depth == 8) { BlitIndexedToView32( this->dirty_rects[i].left, this->dirty_rects[i].top, this->dirty_rects[i].right, this->dirty_rects[i].bottom ); } NSRect dirtyrect; dirtyrect.origin.x = this->dirty_rects[i].left; dirtyrect.origin.y = this->window_height - this->dirty_rects[i].bottom; dirtyrect.size.width = this->dirty_rects[i].right - this->dirty_rects[i].left; dirtyrect.size.height = this->dirty_rects[i].bottom - this->dirty_rects[i].top; /* Normally drawRect will be automatically called by Mac OS X during next update cycle, * and then blitting will occur. If force_update is true, it will be done right now. */ [ this->cocoaview setNeedsDisplayInRect:dirtyrect ]; if (force_update) [ this->cocoaview displayIfNeeded ]; } this->num_dirty_rects = 0; } void WindowQuartzSubdriver::MakeDirty(int left, int top, int width, int height) { if (this->num_dirty_rects < MAX_DIRTY_RECTS) { dirty_rects[this->num_dirty_rects].left = left; dirty_rects[this->num_dirty_rects].top = top; dirty_rects[this->num_dirty_rects].right = left + width; dirty_rects[this->num_dirty_rects].bottom = top + height; } this->num_dirty_rects++; } void WindowQuartzSubdriver::UpdatePalette(uint first_color, uint num_colors) { if (this->buffer_depth != 8) return; for (uint i = first_color; i < first_color + num_colors; i++) { uint32 clr = 0xff000000; clr |= (uint32)_cur_palette.palette[i].r << 16; clr |= (uint32)_cur_palette.palette[i].g << 8; clr |= (uint32)_cur_palette.palette[i].b; this->palette[i] = clr; } this->num_dirty_rects = MAX_DIRTY_RECTS; } uint WindowQuartzSubdriver::ListModes(OTTD_Point *modes, uint max_modes) { return QZ_ListModes(modes, max_modes, kCGDirectMainDisplay, this->buffer_depth); } bool WindowQuartzSubdriver::ChangeResolution(int w, int h, int bpp) { int old_width = this->window_width; int old_height = this->window_height; int old_bpp = this->buffer_depth; if (this->SetVideoMode(w, h, bpp)) return true; if (old_width != 0 && old_height != 0) this->SetVideoMode(old_width, old_height, old_bpp); return false; } /* Convert local coordinate to window server (CoreGraphics) coordinate */ CGPoint WindowQuartzSubdriver::PrivateLocalToCG(NSPoint *p) { p->y = this->window_height - p->y; *p = [ this->cocoaview convertPoint:*p toView:nil ]; *p = [ this->window convertBaseToScreen:*p ]; p->y = this->device_height - p->y; CGPoint cgp; cgp.x = p->x; cgp.y = p->y; return cgp; } NSPoint WindowQuartzSubdriver::GetMouseLocation(NSEvent *event) { NSPoint pt; if ( [ event window ] == nil) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if ([ this->cocoaview respondsToSelector:@selector(convertRectFromScreen:) ]) { pt = [ this->cocoaview convertPoint:[ [ this->cocoaview window ] convertRectFromScreen:NSMakeRect([ event locationInWindow ].x, [ event locationInWindow ].y, 0, 0) ].origin fromView:nil ]; } else #endif { pt = [ this->cocoaview convertPoint:[ [ this->cocoaview window ] convertScreenToBase:[ event locationInWindow ] ] fromView:nil ]; } } else { pt = [ event locationInWindow ]; } pt.y = this->window_height - pt.y; return pt; } bool WindowQuartzSubdriver::MouseIsInsideView(NSPoint *pt) { return [ cocoaview mouse:*pt inRect:[ this->cocoaview bounds ] ]; } /* This function makes the *game region* of the window 100% opaque. * The genie effect uses the alpha component. Otherwise, * it doesn't seem to matter what value it has. */ void WindowQuartzSubdriver::SetPortAlphaOpaque() { uint32 *pixels = (uint32*)this->window_buffer; uint32 pitch = this->window_width; for (int y = 0; y < this->window_height; y++) for (int x = 0; x < this->window_width; x++) { pixels[y * pitch + x] |= 0xFF000000; } } bool WindowQuartzSubdriver::WindowResized() { if (this->window == nil || this->cocoaview == nil) return true; NSRect newframe = [ this->cocoaview frame ]; this->window_width = (int)newframe.size.width; this->window_height = (int)newframe.size.height; /* Create Core Graphics Context */ free(this->window_buffer); this->window_buffer = (uint32*)malloc(this->window_width * this->window_height * 4); CGContextRelease(this->cgcontext); this->cgcontext = CGBitmapContextCreate( this->window_buffer, // data this->window_width, // width this->window_height, // height 8, // bits per component this->window_width * 4, // bytes per row QZ_GetCorrectColorSpace(), // color space kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host ); assert(this->cgcontext != NULL); CGContextSetShouldAntialias(this->cgcontext, FALSE); CGContextSetAllowsAntialiasing(this->cgcontext, FALSE); CGContextSetInterpolationQuality(this->cgcontext, kCGInterpolationNone); if (this->buffer_depth == 8) { free(this->pixel_buffer); this->pixel_buffer = malloc(this->window_width * this->window_height); if (this->pixel_buffer == NULL) { DEBUG(driver, 0, "Failed to allocate pixel buffer"); return false; } } QZ_GameSizeChanged(); /* Redraw screen */ this->num_dirty_rects = MAX_DIRTY_RECTS; return true; } CocoaSubdriver *QZ_CreateWindowQuartzSubdriver(int width, int height, int bpp) { if (!MacOSVersionIsAtLeast(10, 4, 0)) { DEBUG(driver, 0, "The cocoa quartz subdriver requires Mac OS X 10.4 or later."); return NULL; } if (bpp != 8 && bpp != 32) { DEBUG(driver, 0, "The cocoa quartz subdriver only supports 8 and 32 bpp."); return NULL; } WindowQuartzSubdriver *ret = new WindowQuartzSubdriver(); if (!ret->ChangeResolution(width, height, bpp)) { delete ret; return NULL; } return ret; } #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ #endif /* ENABLE_COCOA_QUARTZ */ #endif /* WITH_COCOA */ openttd-1.5.3/src/video/cocoa/fullscreen.mm0000644000000000000000000004010112627373435017361 0ustar rootroot/* $Id: fullscreen.mm 26709 2014-07-30 20:19:29Z planetmaker $ */ /* * 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 . */ /****************************************************************************** * Cocoa video driver * * Known things left to do: * * Scale© the old pixel buffer to the new one when switching resolution. * ******************************************************************************/ #ifdef WITH_COCOA #include "../../stdafx.h" #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) #define Rect OTTDRect #define Point OTTDPoint #import #undef Rect #undef Point #include "../../debug.h" #include "../../core/geometry_type.hpp" #include "../../core/sort_func.hpp" #include "cocoa_v.h" #include "../../gfx_func.h" #include "../../os/macosx/macos.h" /** * Important notice regarding all modifications!!!!!!! * There are certain limitations because the file is objective C++. * gdb has limitations. * C++ and objective C code can't be joined in all cases (classes stuff). * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. */ /* From Menus.h (according to Xcode Developer Documentation) */ extern "C" void ShowMenuBar(); extern "C" void HideMenuBar(); /* Structure for rez switch gamma fades * We can hide the monitor flicker by setting the gamma tables to 0 */ #define QZ_GAMMA_TABLE_SIZE 256 struct OTTD_QuartzGammaTable { CGGammaValue red[QZ_GAMMA_TABLE_SIZE]; CGGammaValue green[QZ_GAMMA_TABLE_SIZE]; CGGammaValue blue[QZ_GAMMA_TABLE_SIZE]; }; /* Add methods to get at private members of NSScreen. * Since there is a bug in Apple's screen switching code that does not update * this variable when switching to fullscreen, we'll set it manually (but only * for the main screen). */ @interface NSScreen (NSScreenAccess) - (void) setFrame:(NSRect)frame; @end @implementation NSScreen (NSScreenAccess) - (void) setFrame:(NSRect)frame { /* The 64 bits libraries don't seem to know about _frame, so this hack won't work. */ #ifndef __LP64__ _frame = frame; #endif } @end class FullscreenSubdriver : public CocoaSubdriver { CGDirectDisplayID display_id; ///< 0 == main display (only support single display) CFDictionaryRef cur_mode; ///< current mode of the display CFDictionaryRef save_mode; ///< original mode of the display CGDirectPaletteRef palette; ///< palette of an 8-bit display /* Gamma functions to try to hide the flash from a res switch * Fade the display from normal to black * Save gamma tables for fade back to normal */ uint32 FadeGammaOut(OTTD_QuartzGammaTable *table) { CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE]; CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE]; CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE]; unsigned int actual; if (CGGetDisplayTransferByTable(this->display_id, QZ_GAMMA_TABLE_SIZE, table->red, table->green, table->blue, &actual) != CGDisplayNoErr || actual != QZ_GAMMA_TABLE_SIZE) { return 1; } memcpy(redTable, table->red, sizeof(redTable)); memcpy(greenTable, table->green, sizeof(greenTable)); memcpy(blueTable, table->blue, sizeof(greenTable)); for (float percent = 1.0; percent >= 0.0; percent -= 0.01) { for (int j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) { redTable[j] = redTable[j] * percent; greenTable[j] = greenTable[j] * percent; blueTable[j] = blueTable[j] * percent; } if (CGSetDisplayTransferByTable(this->display_id, QZ_GAMMA_TABLE_SIZE, redTable, greenTable, blueTable) != CGDisplayNoErr) { CGDisplayRestoreColorSyncSettings(); return 1; } CSleep(10); } return 0; } /* Fade the display from black to normal * Restore previously saved gamma values */ uint32 FadeGammaIn(const OTTD_QuartzGammaTable *table) { CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE]; CGGammaValue greenTable[QZ_GAMMA_TABLE_SIZE]; CGGammaValue blueTable[QZ_GAMMA_TABLE_SIZE]; memset(redTable, 0, sizeof(redTable)); memset(greenTable, 0, sizeof(greenTable)); memset(blueTable, 0, sizeof(greenTable)); for (float percent = 0.0; percent <= 1.0; percent += 0.01) { for (int j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) { redTable[j] = table->red[j] * percent; greenTable[j] = table->green[j] * percent; blueTable[j] = table->blue[j] * percent; } if (CGSetDisplayTransferByTable(this->display_id, QZ_GAMMA_TABLE_SIZE, redTable, greenTable, blueTable) != CGDisplayNoErr) { CGDisplayRestoreColorSyncSettings(); return 1; } CSleep(10); } return 0; } /** Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */ void WaitForVerticalBlank() { /* The VBL delay is based on Ian Ollmann's RezLib */ CFNumberRef refreshRateCFNumber = (const __CFNumber*)CFDictionaryGetValue(this->cur_mode, kCGDisplayRefreshRate); if (refreshRateCFNumber == NULL) return; double refreshRate; if (CFNumberGetValue(refreshRateCFNumber, kCFNumberDoubleType, &refreshRate) == 0) return; if (refreshRate == 0) return; double linesPerSecond = refreshRate * this->device_height; double target = this->device_height; /* Figure out the first delay so we start off about right */ double position = CGDisplayBeamPosition(this->display_id); if (position > target) position = 0; double adjustment = (target - position) / linesPerSecond; CSleep((uint32)(adjustment * 1000)); } bool SetVideoMode(int w, int h, int bpp) { /* Define this variables at the top (against coding style) because * otherwise GCC 4.2 barfs at the goto's jumping over variable initialization. */ NSRect screen_rect; int gamma_error; NSPoint mouseLocation; /* Destroy any previous mode */ if (this->pixel_buffer != NULL) { free(this->pixel_buffer); this->pixel_buffer = NULL; } /* See if requested mode exists */ boolean_t exact_match; this->cur_mode = CGDisplayBestModeForParameters(this->display_id, bpp, w, h, &exact_match); /* If the mode wasn't an exact match, check if it has the right bpp, and update width and height */ if (!exact_match) { int act_bpp; CFNumberRef number = (const __CFNumber*) CFDictionaryGetValue(this->cur_mode, kCGDisplayBitsPerPixel); CFNumberGetValue(number, kCFNumberSInt32Type, &act_bpp); if (act_bpp != bpp) { DEBUG(driver, 0, "Failed to find display resolution"); goto ERR_NO_MATCH; } number = (const __CFNumber*)CFDictionaryGetValue(this->cur_mode, kCGDisplayWidth); CFNumberGetValue(number, kCFNumberSInt32Type, &w); number = (const __CFNumber*)CFDictionaryGetValue(this->cur_mode, kCGDisplayHeight); CFNumberGetValue(number, kCFNumberSInt32Type, &h); } /* Capture the main screen */ CGDisplayCapture(this->display_id); /* Store the mouse coordinates relative to the total screen */ mouseLocation = [ NSEvent mouseLocation ]; mouseLocation.x /= this->device_width; mouseLocation.y /= this->device_height; /* Fade display to zero gamma */ OTTD_QuartzGammaTable gamma_table; gamma_error = this->FadeGammaOut(&gamma_table); /* Put up the blanking window (a window above all other windows) */ if (CGDisplayCapture(this->display_id) != CGDisplayNoErr ) { DEBUG(driver, 0, "Failed capturing display"); goto ERR_NO_CAPTURE; } /* Do the physical switch */ if (CGDisplaySwitchToMode(this->display_id, this->cur_mode) != CGDisplayNoErr) { DEBUG(driver, 0, "Failed switching display resolution"); goto ERR_NO_SWITCH; } /* Since CGDisplayBaseAddress and CGDisplayBytesPerRow are no longer available on 10.7, * disable until a replacement can be found. */ if (MacOSVersionIsAtLeast(10, 7, 0)) { this->window_buffer = NULL; this->window_pitch = 0; } else { #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) this->window_buffer = CGDisplayBaseAddress(this->display_id); this->window_pitch = CGDisplayBytesPerRow(this->display_id); #endif } this->device_width = CGDisplayPixelsWide(this->display_id); this->device_height = CGDisplayPixelsHigh(this->display_id); this->device_depth = bpp; /* Setup double-buffer emulation */ this->pixel_buffer = malloc(this->device_width * this->device_height * this->device_depth / 8); if (this->pixel_buffer == NULL) { DEBUG(driver, 0, "Failed to allocate memory for double buffering"); goto ERR_DOUBLEBUF; } if (this->device_depth == 8 && !CGDisplayCanSetPalette(this->display_id)) { DEBUG(driver, 0, "Not an indexed display mode."); goto ERR_NOT_INDEXED; } /* If we don't hide menu bar, it will get events and interrupt the program */ HideMenuBar(); /* Hide the OS cursor */ CGDisplayHideCursor(this->display_id); /* Fade the display to original gamma */ if (!gamma_error) FadeGammaIn(&gamma_table); /* There is a bug in Cocoa where NSScreen doesn't synchronize * with CGDirectDisplay, so the main screen's frame is wrong. * As a result, coordinate translation produces incorrect results. * We can hack around this bug by setting the screen rect ourselves. * This hack should be removed if/when the bug is fixed. */ screen_rect = NSMakeRect(0, 0, this->device_width, this->device_height); [ [ NSScreen mainScreen ] setFrame:screen_rect ]; this->UpdatePalette(0, 256); /* Move the mouse cursor to approx. the same location */ CGPoint display_mouseLocation; display_mouseLocation.x = mouseLocation.x * this->device_width; display_mouseLocation.y = this->device_height - (mouseLocation.y * this->device_height); _cursor.in_window = true; CGDisplayMoveCursorToPoint(this->display_id, display_mouseLocation); return true; /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ ERR_NOT_INDEXED: free(this->pixel_buffer); this->pixel_buffer = NULL; ERR_DOUBLEBUF: CGDisplaySwitchToMode(this->display_id, this->save_mode); ERR_NO_SWITCH: CGReleaseAllDisplays(); ERR_NO_CAPTURE: if (!gamma_error) this->FadeGammaIn(&gamma_table); ERR_NO_MATCH: this->device_width = 0; this->device_height = 0; return false; } void RestoreVideoMode() { /* Release fullscreen resources */ OTTD_QuartzGammaTable gamma_table; int gamma_error = this->FadeGammaOut(&gamma_table); /* Restore original screen resolution/bpp */ CGDisplaySwitchToMode(this->display_id, this->save_mode); CGReleaseAllDisplays(); /* Bring back the cursor */ CGDisplayShowCursor(this->display_id); ShowMenuBar(); /* Reset the main screen's rectangle * See comment in SetVideoMode for why we do this */ NSRect screen_rect = NSMakeRect(0, 0, CGDisplayPixelsWide(this->display_id), CGDisplayPixelsHigh(this->display_id)); [ [ NSScreen mainScreen ] setFrame:screen_rect ]; /* Destroy the pixel buffer */ if (this->pixel_buffer != NULL) { free(this->pixel_buffer); this->pixel_buffer = NULL; } if (!gamma_error) this->FadeGammaIn(&gamma_table); this->device_width = CGDisplayPixelsWide(this->display_id); this->device_height = CGDisplayPixelsHigh(this->display_id); } public: FullscreenSubdriver() { /* Initialize the video settings; this data persists between mode switches */ this->display_id = kCGDirectMainDisplay; this->save_mode = CGDisplayCurrentMode(this->display_id); this->palette = CGPaletteCreateDefaultColorPalette(); this->device_width = CGDisplayPixelsWide(this->display_id); this->device_height = CGDisplayPixelsHigh(this->display_id); this->device_depth = 0; this->pixel_buffer = NULL; this->num_dirty_rects = MAX_DIRTY_RECTS; } virtual ~FullscreenSubdriver() { this->RestoreVideoMode(); } virtual void Draw(bool force_update) { const uint8 *src = (uint8 *)this->pixel_buffer; uint8 *dst = (uint8 *)this->window_buffer; uint pitch = this->window_pitch; uint width = this->device_width; uint num_dirty = this->num_dirty_rects; uint bytesperpixel = this->device_depth / 8; /* Check if we need to do anything */ if (num_dirty == 0) return; if (num_dirty >= MAX_DIRTY_RECTS) { num_dirty = 1; this->dirty_rects[0].left = 0; this->dirty_rects[0].top = 0; this->dirty_rects[0].right = this->device_width; this->dirty_rects[0].bottom = this->device_height; } WaitForVerticalBlank(); /* Build the region of dirty rectangles */ for (uint i = 0; i < num_dirty; i++) { uint y = this->dirty_rects[i].top; uint left = this->dirty_rects[i].left; uint length = this->dirty_rects[i].right - left; uint bottom = this->dirty_rects[i].bottom; for (; y < bottom; y++) { memcpy(dst + y * pitch + left * bytesperpixel, src + y * width * bytesperpixel + left * bytesperpixel, length * bytesperpixel); } } this->num_dirty_rects = 0; } virtual void MakeDirty(int left, int top, int width, int height) { if (this->num_dirty_rects < MAX_DIRTY_RECTS) { this->dirty_rects[this->num_dirty_rects].left = left; this->dirty_rects[this->num_dirty_rects].top = top; this->dirty_rects[this->num_dirty_rects].right = left + width; this->dirty_rects[this->num_dirty_rects].bottom = top + height; } this->num_dirty_rects++; } virtual void UpdatePalette(uint first_color, uint num_colors) { if (this->device_depth != 8) return; for (uint32_t index = first_color; index < first_color + num_colors; index++) { /* Clamp colors between 0.0 and 1.0 */ CGDeviceColor color; color.red = _cur_palette.palette[index].r / 255.0; color.blue = _cur_palette.palette[index].b / 255.0; color.green = _cur_palette.palette[index].g / 255.0; CGPaletteSetColorAtIndex(this->palette, color, index); } CGDisplaySetPalette(this->display_id, this->palette); } virtual uint ListModes(OTTD_Point *modes, uint max_modes) { return QZ_ListModes(modes, max_modes, this->display_id, this->device_depth); } virtual bool ChangeResolution(int w, int h, int bpp) { int old_width = this->device_width; int old_height = this->device_height; int old_bpp = this->device_depth; if (bpp != 8 && bpp != 32) error("Cocoa: This video driver only supports 8 and 32 bpp blitters."); if (SetVideoMode(w, h, bpp)) return true; if (old_width != 0 && old_height != 0) SetVideoMode(old_width, old_height, old_bpp); return false; } virtual bool IsFullscreen() { return true; } virtual int GetWidth() { return this->device_width; } virtual int GetHeight() { return this->device_height; } virtual void *GetPixelBuffer() { return this->pixel_buffer; } /* * Convert local coordinate to window server (CoreGraphics) coordinate. * In fullscreen mode this just means copying the coords. */ virtual CGPoint PrivateLocalToCG(NSPoint *p) { return CGPointMake(p->x, p->y); } virtual NSPoint GetMouseLocation(NSEvent *event) { NSPoint pt = [ NSEvent mouseLocation ]; pt.y = this->device_height - pt.y; return pt; } virtual bool MouseIsInsideView(NSPoint *pt) { return pt->x >= 0 && pt->y >= 0 && pt->x < this->device_width && pt->y < this->device_height; } virtual bool IsActive() { return true; } }; CocoaSubdriver *QZ_CreateFullscreenSubdriver(int width, int height, int bpp) { /* OSX 10.7 doesn't support this way of the fullscreen driver. If we end up here * OpenTTD was compiled without SDK 10.7 available and - and thus we don't support * fullscreen mode in OSX 10.7 or higher, as necessary elements for this way have * been removed from the API. */ if (MacOSVersionIsAtLeast(10, 7, 0)) { return NULL; } FullscreenSubdriver *ret = new FullscreenSubdriver(); if (!ret->ChangeResolution(width, height, bpp)) { delete ret; return NULL; } return ret; } #endif /* (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) */ #endif /* WITH_COCOA */ openttd-1.5.3/src/video/cocoa/cocoa_v.mm0000644000000000000000000011147012627373435016640 0ustar rootroot/* $Id: cocoa_v.mm 26818 2014-09-13 22:00:10Z michi_cc $ */ /* * 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 cocoa_v.mm Code related to the cocoa video driver(s). */ /****************************************************************************** * Cocoa video driver * * Known things left to do: * * Nothing at the moment. * ******************************************************************************/ #ifdef WITH_COCOA #include "../../stdafx.h" #include "../../os/macosx/macos.h" #define Rect OTTDRect #define Point OTTDPoint #import #undef Rect #undef Point #include "../../openttd.h" #include "../../debug.h" #include "../../core/geometry_type.hpp" #include "cocoa_v.h" #include "../../blitter/factory.hpp" #include "../../fileio_func.h" #include "../../gfx_func.h" #include "../../window_func.h" #include "../../window_gui.h" #import /* for MAXPATHLEN */ /** * Important notice regarding all modifications!!!!!!! * There are certain limitations because the file is objective C++. * gdb has limitations. * C++ and objective C code can't be joined in all cases (classes stuff). * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. */ @interface OTTDMain : NSObject @end static NSAutoreleasePool *_ottd_autorelease_pool; static OTTDMain *_ottd_main; static bool _cocoa_video_started = false; static bool _cocoa_video_dialog = false; CocoaSubdriver *_cocoa_subdriver = NULL; static NSString *OTTDMainLaunchGameEngine = @"ottdmain_launch_game_engine"; /** * The main class of the application, the application's delegate. */ @implementation OTTDMain /** * Stop the game engine. Must be called on main thread. */ - (void)stopEngine { [ NSApp stop:self ]; /* Send an empty event to return from the run loop. Without that, application is stuck waiting for an event. */ NSEvent *event = [ NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0 ]; [ NSApp postEvent:event atStart:YES ]; } /** * Start the game loop. */ - (void)launchGameEngine: (NSNotification*) note { /* Setup cursor for the current _game_mode. */ [ _cocoa_subdriver->cocoaview resetCursorRects ]; /* Hand off to main application code. */ QZ_GameLoop(); /* We are done, thank you for playing. */ [ self performSelectorOnMainThread:@selector(stopEngine) withObject:nil waitUntilDone:FALSE ]; } /** * Called when the internal event loop has just started running. */ - (void) applicationDidFinishLaunching: (NSNotification*) note { /* Add a notification observer so we can restart the game loop later on if necessary. */ [ [ NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(launchGameEngine:) name:OTTDMainLaunchGameEngine object:nil ]; /* Start game loop. */ [ [ NSNotificationCenter defaultCenter ] postNotificationName:OTTDMainLaunchGameEngine object:nil ]; } /** * Display the in game quit confirmation dialog. */ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*) sender { HandleExitGameRequest(); return NSTerminateCancel; // NSTerminateLater ? } /** * Remove ourself as a notification observer. */ - (void)unregisterObserver { [ [ NSNotificationCenter defaultCenter ] removeObserver:self ]; } @end /** * Initialize the application menu shown in top bar. */ static void setApplicationMenu() { NSString *appName = @"OpenTTD"; NSMenu *appleMenu = [ [ NSMenu alloc ] initWithTitle:appName ]; /* Add menu items */ NSString *title = [ @"About " stringByAppendingString:appName ]; [ appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@"" ]; [ appleMenu addItem:[ NSMenuItem separatorItem ] ]; title = [ @"Hide " stringByAppendingString:appName ]; [ appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h" ]; NSMenuItem *menuItem = [ appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h" ]; [ menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask | NSCommandKeyMask) ]; [ appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@"" ]; [ appleMenu addItem:[ NSMenuItem separatorItem ] ]; title = [ @"Quit " stringByAppendingString:appName ]; [ appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q" ]; /* Put menu into the menubar */ menuItem = [ [ NSMenuItem alloc ] initWithTitle:@"" action:nil keyEquivalent:@"" ]; [ menuItem setSubmenu:appleMenu ]; [ [ NSApp mainMenu ] addItem:menuItem ]; /* Tell the application object that this is now the application menu. * This interesting Objective-C construct is used because not all SDK * versions define this method publicly. */ [ NSApp performSelector:@selector(setAppleMenu:) withObject:appleMenu ]; /* Finally give up our references to the objects */ [ appleMenu release ]; [ menuItem release ]; } /** * Create a window menu. */ static void setupWindowMenu() { NSMenu *windowMenu = [ [ NSMenu alloc ] initWithTitle:@"Window" ]; /* "Minimize" item */ [ windowMenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m" ]; /* Put menu into the menubar */ NSMenuItem *menuItem = [ [ NSMenuItem alloc ] initWithTitle:@"Window" action:nil keyEquivalent:@"" ]; [ menuItem setSubmenu:windowMenu ]; [ [ NSApp mainMenu ] addItem:menuItem ]; if (MacOSVersionIsAtLeast(10, 7, 0)) { /* The OS will change the name of this menu item automatically */ [ windowMenu addItemWithTitle:@"Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"^f" ]; } /* Tell the application object that this is now the window menu */ [ NSApp setWindowsMenu:windowMenu ]; /* Finally give up our references to the objects */ [ windowMenu release ]; [ menuItem release ]; } /** * Startup the application. */ static void setupApplication() { ProcessSerialNumber psn = { 0, kCurrentProcess }; /* Ensure the application object is initialised */ [ NSApplication sharedApplication ]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 /* Tell the dock about us */ if (MacOSVersionIsAtLeast(10, 3, 0)) { OSStatus returnCode = TransformProcessType(&psn, kProcessTransformToForegroundApplication); if (returnCode != 0) DEBUG(driver, 0, "Could not change to foreground application. Error %d", (int)returnCode); } #endif /* Become the front process, important when start from the command line. */ OSErr err = SetFrontProcess(&psn); if (err != 0) DEBUG(driver, 0, "Could not bring the application to front. Error %d", (int)err); /* Set up the menubar */ [ NSApp setMainMenu:[ [ NSMenu alloc ] init ] ]; setApplicationMenu(); setupWindowMenu(); /* Create OTTDMain and make it the app delegate */ _ottd_main = [ [ OTTDMain alloc ] init ]; [ NSApp setDelegate:_ottd_main ]; } static int CDECL ModeSorter(const OTTD_Point *p1, const OTTD_Point *p2) { if (p1->x < p2->x) return -1; if (p1->x > p2->x) return +1; if (p1->y < p2->y) return -1; if (p1->y > p2->y) return +1; return 0; } uint QZ_ListModes(OTTD_Point *modes, uint max_modes, CGDirectDisplayID display_id, int device_depth) { CFArrayRef mode_list = CGDisplayAvailableModes(display_id); CFIndex num_modes = CFArrayGetCount(mode_list); /* Build list of modes with the requested bpp */ uint count = 0; for (CFIndex i = 0; i < num_modes && count < max_modes; i++) { int intvalue, bpp; uint16 width, height; CFDictionaryRef onemode = (const __CFDictionary*)CFArrayGetValueAtIndex(mode_list, i); CFNumberRef number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayBitsPerPixel); CFNumberGetValue(number, kCFNumberSInt32Type, &bpp); if (bpp != device_depth) continue; number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayWidth); CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue); width = (uint16)intvalue; number = (const __CFNumber*)CFDictionaryGetValue(onemode, kCGDisplayHeight); CFNumberGetValue(number, kCFNumberSInt32Type, &intvalue); height = (uint16)intvalue; /* Check if mode is already in the list */ bool hasMode = false; for (uint i = 0; i < count; i++) { if (modes[i].x == width && modes[i].y == height) { hasMode = true; break; } } if (hasMode) continue; /* Add mode to the list */ modes[count].x = width; modes[count].y = height; count++; } /* Sort list smallest to largest */ QSortT(modes, count, &ModeSorter); return count; } /** Small function to test if the main display can display 8 bpp in fullscreen */ bool QZ_CanDisplay8bpp() { /* 8bpp modes are deprecated starting in 10.5. CoreGraphics will return them * as available in the display list, but many features (e.g. palette animation) * will be broken. */ if (MacOSVersionIsAtLeast(10, 5, 0)) return false; OTTD_Point p; /* We want to know if 8 bpp is possible in fullscreen and not anything about * resolutions. Because of this we want to fill a list of 1 resolution of 8 bpp * on display 0 (main) and return if we found one. */ return QZ_ListModes(&p, 1, 0, 8); } /** * Update the video modus. * * @pre _cocoa_subdriver != NULL */ static void QZ_UpdateVideoModes() { assert(_cocoa_subdriver != NULL); OTTD_Point modes[32]; uint count = _cocoa_subdriver->ListModes(modes, lengthof(modes)); for (uint i = 0; i < count; i++) { _resolutions[i].width = modes[i].x; _resolutions[i].height = modes[i].y; } _num_resolutions = count; } /** * Handle a change of the display area. */ void QZ_GameSizeChanged() { if (_cocoa_subdriver == NULL) return; /* Tell the game that the resolution has changed */ _screen.width = _cocoa_subdriver->GetWidth(); _screen.height = _cocoa_subdriver->GetHeight(); _screen.pitch = _cocoa_subdriver->GetWidth(); _screen.dst_ptr = _cocoa_subdriver->GetPixelBuffer(); _fullscreen = _cocoa_subdriver->IsFullscreen(); BlitterFactory::GetCurrentBlitter()->PostResize(); GameSizeChanged(); } /** * Find a suitable cocoa window subdriver. * * @param width Width of display area. * @param height Height of display area. * @param bpp Colour depth of display area. * @return Pointer to window subdriver. */ static CocoaSubdriver *QZ_CreateWindowSubdriver(int width, int height, int bpp) { #if defined(ENABLE_COCOA_QUARTZ) || defined(ENABLE_COCOA_QUICKDRAW) CocoaSubdriver *ret; #endif #if defined(ENABLE_COCOA_QUARTZ) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) /* The reason for the version mismatch is due to the fact that the 10.4 binary needs to work on 10.5 as well. */ if (MacOSVersionIsAtLeast(10, 5, 0)) { ret = QZ_CreateWindowQuartzSubdriver(width, height, bpp); if (ret != NULL) return ret; } #endif #ifdef ENABLE_COCOA_QUICKDRAW ret = QZ_CreateWindowQuickdrawSubdriver(width, height, bpp); if (ret != NULL) return ret; #endif #if defined(ENABLE_COCOA_QUARTZ) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) /* * If we get here we are running 10.4 or earlier and either openttd was compiled without the QuickDraw driver * or it failed to load for some reason. Fall back to Quartz if possible even though that driver is slower. */ if (MacOSVersionIsAtLeast(10, 4, 0)) { ret = QZ_CreateWindowQuartzSubdriver(width, height, bpp); if (ret != NULL) return ret; } #endif return NULL; } /** * Find a suitable cocoa subdriver. * * @param width Width of display area. * @param height Height of display area. * @param bpp Colour depth of display area. * @param fullscreen Whether a fullscreen mode is requested. * @param fallback Whether we look for a fallback driver. * @return Pointer to window subdriver. */ static CocoaSubdriver *QZ_CreateSubdriver(int width, int height, int bpp, bool fullscreen, bool fallback) { CocoaSubdriver *ret = NULL; /* OSX 10.7 allows to toggle fullscreen mode differently */ if (MacOSVersionIsAtLeast(10, 7, 0)) { ret = QZ_CreateWindowSubdriver(width, height, bpp); if (ret != NULL && fullscreen) ret->ToggleFullscreen(); } #if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) else { ret = fullscreen ? QZ_CreateFullscreenSubdriver(width, height, bpp) : QZ_CreateWindowSubdriver(width, height, bpp); } #endif /* (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) */ if (ret != NULL) return ret; if (!fallback) return NULL; /* Try again in 640x480 windowed */ DEBUG(driver, 0, "Setting video mode failed, falling back to 640x480 windowed mode."); ret = QZ_CreateWindowSubdriver(640, 480, bpp); if (ret != NULL) return ret; #if defined(_DEBUG) && (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9) /* This Fullscreen mode crashes on OSX 10.7 */ if (!MacOSVersionIsAtLeast(10, 7, 0)) { /* Try fullscreen too when in debug mode */ DEBUG(driver, 0, "Setting video mode failed, falling back to 640x480 fullscreen mode."); ret = QZ_CreateFullscreenSubdriver(640, 480, bpp); if (ret != NULL) return ret; } #endif /* defined(_DEBUG) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9) */ return NULL; } static FVideoDriver_Cocoa iFVideoDriver_Cocoa; /** * Stop the cocoa video subdriver. */ void VideoDriver_Cocoa::Stop() { if (!_cocoa_video_started) return; [ _ottd_main unregisterObserver ]; delete _cocoa_subdriver; _cocoa_subdriver = NULL; [ _ottd_main release ]; _cocoa_video_started = false; } /** * Initialize a cocoa video subdriver. */ const char *VideoDriver_Cocoa::Start(const char * const *parm) { if (!MacOSVersionIsAtLeast(10, 3, 0)) return "The Cocoa video driver requires Mac OS X 10.3 or later."; if (_cocoa_video_started) return "Already started"; _cocoa_video_started = true; setupApplication(); /* Don't create a window or enter fullscreen if we're just going to show a dialog. */ if (_cocoa_video_dialog) return NULL; int width = _cur_resolution.width; int height = _cur_resolution.height; int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); _cocoa_subdriver = QZ_CreateSubdriver(width, height, bpp, _fullscreen, true); if (_cocoa_subdriver == NULL) { Stop(); return "Could not create subdriver"; } QZ_GameSizeChanged(); QZ_UpdateVideoModes(); return NULL; } /** * Set dirty a rectangle managed by a cocoa video subdriver. * * @param left Left x cooordinate of the dirty rectangle. * @param top Uppder y coordinate of the dirty rectangle. * @param width Width of the dirty rectangle. * @param height Height of the dirty rectangle. */ void VideoDriver_Cocoa::MakeDirty(int left, int top, int width, int height) { assert(_cocoa_subdriver != NULL); _cocoa_subdriver->MakeDirty(left, top, width, height); } /** * Start the main programme loop when using a cocoa video driver. */ void VideoDriver_Cocoa::MainLoop() { /* Restart game loop if it was already running (e.g. after bootstrapping), * otherwise this call is a no-op. */ [ [ NSNotificationCenter defaultCenter ] postNotificationName:OTTDMainLaunchGameEngine object:nil ]; /* Start the main event loop. */ [ NSApp run ]; } /** * Change the resolution when using a cocoa video driver. * * @param w New window width. * @param h New window height. * @return Whether the video driver was successfully updated. */ bool VideoDriver_Cocoa::ChangeResolution(int w, int h) { assert(_cocoa_subdriver != NULL); bool ret = _cocoa_subdriver->ChangeResolution(w, h, BlitterFactory::GetCurrentBlitter()->GetScreenDepth()); QZ_GameSizeChanged(); QZ_UpdateVideoModes(); return ret; } /** * Toggle between windowed and full screen mode for cocoa display driver. * * @param full_screen Whether to switch to full screen or not. * @return Whether the mode switch was successful. */ bool VideoDriver_Cocoa::ToggleFullscreen(bool full_screen) { assert(_cocoa_subdriver != NULL); /* For 10.7 and later, we try to toggle using the quartz subdriver. */ if (_cocoa_subdriver->ToggleFullscreen()) return true; bool oldfs = _cocoa_subdriver->IsFullscreen(); if (full_screen != oldfs) { int width = _cocoa_subdriver->GetWidth(); int height = _cocoa_subdriver->GetHeight(); int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); delete _cocoa_subdriver; _cocoa_subdriver = NULL; _cocoa_subdriver = QZ_CreateSubdriver(width, height, bpp, full_screen, false); if (_cocoa_subdriver == NULL) { _cocoa_subdriver = QZ_CreateSubdriver(width, height, bpp, oldfs, true); if (_cocoa_subdriver == NULL) error("Cocoa: Failed to create subdriver"); } } QZ_GameSizeChanged(); QZ_UpdateVideoModes(); return _cocoa_subdriver->IsFullscreen() == full_screen; } /** * Callback invoked after the blitter was changed. * * @return True if no error. */ bool VideoDriver_Cocoa::AfterBlitterChange() { return this->ChangeResolution(_screen.width, _screen.height); } /** * An edit box lost the input focus. Abort character compositing if necessary. */ void VideoDriver_Cocoa::EditBoxLostFocus() { if (_cocoa_subdriver != NULL) { if ([ _cocoa_subdriver->cocoaview respondsToSelector:@selector(inputContext) ] && [ [ _cocoa_subdriver->cocoaview performSelector:@selector(inputContext) ] respondsToSelector:@selector(discardMarkedText) ]) { [ [ _cocoa_subdriver->cocoaview performSelector:@selector(inputContext) ] performSelector:@selector(discardMarkedText) ]; } else { [ [ NSInputManager currentInputManager ] markedTextAbandoned:_cocoa_subdriver->cocoaview ]; } } /* Clear any marked string from the current edit box. */ HandleTextInput(NULL, true); } /** * Catch asserts prior to initialization of the videodriver. * * @param title Window title. * @param message Message text. * @param buttonLabel Button text. * * @note This is needed since sometimes assert is called before the videodriver is initialized . */ void CocoaDialog(const char *title, const char *message, const char *buttonLabel) { _cocoa_video_dialog = true; bool wasstarted = _cocoa_video_started; if (VideoDriver::GetInstance() == NULL) { setupApplication(); // Setup application before showing dialog } else if (!_cocoa_video_started && VideoDriver::GetInstance()->Start(NULL) != NULL) { fprintf(stderr, "%s: %s\n", title, message); return; } NSRunAlertPanel([ NSString stringWithUTF8String:title ], [ NSString stringWithUTF8String:message ], [ NSString stringWithUTF8String:buttonLabel ], nil, nil); if (!wasstarted && VideoDriver::GetInstance() != NULL) VideoDriver::GetInstance()->Stop(); _cocoa_video_dialog = false; } /** Set the application's bundle directory. * * This is needed since OS X application bundles do not have a * current directory and the data files are 'somewhere' in the bundle. */ void cocoaSetApplicationBundleDir() { char tmp[MAXPATHLEN]; CFURLRef url = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); if (CFURLGetFileSystemRepresentation(url, true, (unsigned char*)tmp, MAXPATHLEN)) { AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_APPLICATION_BUNDLE_DIR] = stredup(tmp); } else { _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL; } CFRelease(url); } /** * Setup autorelease for the application pool. * * These are called from main() to prevent a _NSAutoreleaseNoPool error when * exiting before the cocoa video driver has been loaded */ void cocoaSetupAutoreleasePool() { _ottd_autorelease_pool = [ [ NSAutoreleasePool alloc ] init ]; } /** * Autorelease the application pool. */ void cocoaReleaseAutoreleasePool() { [ _ottd_autorelease_pool release ]; } /** * Re-implement the system cursor in order to allow hiding and showing it nicely */ @implementation NSCursor (OTTD_CocoaCursor) + (NSCursor *) clearCocoaCursor { /* RAW 16x16 transparent GIF */ unsigned char clearGIFBytes[] = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xF9, 0x04, 0x01, 0x00, 0x00, 0x01, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x0E, 0x8C, 0x8F, 0xA9, 0xCB, 0xED, 0x0F, 0xA3, 0x9C, 0xB4, 0xDA, 0x8B, 0xB3, 0x3E, 0x05, 0x00, 0x3B}; NSData *clearGIFData = [ NSData dataWithBytesNoCopy:&clearGIFBytes[0] length:55 freeWhenDone:NO ]; NSImage *clearImg = [ [ NSImage alloc ] initWithData:clearGIFData ]; return [ [ NSCursor alloc ] initWithImage:clearImg hotSpot:NSMakePoint(0.0,0.0) ]; } @end @implementation OTTD_CocoaWindow - (void)setDriver:(CocoaSubdriver*)drv { driver = drv; } /** * Minimize the window */ - (void)miniaturize:(id)sender { /* make the alpha channel opaque so anim won't have holes in it */ driver->SetPortAlphaOpaque(); /* window is hidden now */ driver->active = false; [ super miniaturize:sender ]; } /** * This method fires just before the window deminaturizes from the Dock. * We'll save the current visible surface, let the window manager redraw any * UI elements, and restore the surface. This way, no expose event * is required, and the deminiaturize works perfectly. */ - (void)display { driver->SetPortAlphaOpaque(); /* save current visible surface */ [ self cacheImageInRect:[ driver->cocoaview frame ] ]; /* let the window manager redraw controls, border, etc */ [ super display ]; /* restore visible surface */ [ self restoreCachedImage ]; /* window is visible again */ driver->active = true; } /** * Define the rectangle we draw our window in */ - (void)setFrame:(NSRect)frameRect display:(BOOL)flag { [ super setFrame:frameRect display:flag ]; /* Don't do anything if the window is currently being created */ if (driver->setup) return; if (!driver->WindowResized()) error("Cocoa: Failed to resize window."); } /** * Handle hiding of the application */ - (void)appDidHide:(NSNotification*)note { driver->active = false; } /** * Fade-in the application and restore display plane */ - (void)appWillUnhide:(NSNotification*)note { driver->SetPortAlphaOpaque (); } /** * Unhide and restore display plane and re-activate driver */ - (void)appDidUnhide:(NSNotification*)note { driver->active = true; } /** * Initialize event system for the application rectangle */ - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag { /* Make our window subclass receive these application notifications */ [ [ NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(appDidHide:) name:NSApplicationDidHideNotification object:NSApp ]; [ [ NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ]; [ [ NSNotificationCenter defaultCenter ] addObserver:self selector:@selector(appWillUnhide:) name:NSApplicationWillUnhideNotification object:NSApp ]; return [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ]; } @end /** * Count the number of UTF-16 code points in a range of an UTF-8 string. * @param from Start of the range. * @param to End of the range. * @return Number of UTF-16 code points in the range. */ static NSUInteger CountUtf16Units(const char *from, const char *to) { NSUInteger i = 0; while (from < to) { WChar c; size_t len = Utf8Decode(&c, from); i += len < 4 ? 1 : 2; // Watch for surrogate pairs. from += len; } return i; } /** * Advance an UTF-8 string by a number of equivalent UTF-16 code points. * @param str UTF-8 string. * @param count Number of UTF-16 code points to advance the string by. * @return Advanced string pointer. */ static const char *Utf8AdvanceByUtf16Units(const char *str, NSUInteger count) { for (NSUInteger i = 0; i < count && *str != '\0'; ) { WChar c; size_t len = Utf8Decode(&c, str); i += len < 4 ? 1 : 2; // Watch for surrogates. str += len; } return str; } @implementation OTTD_CocoaView /** * Initialize the driver */ - (void)setDriver:(CocoaSubdriver*)drv { driver = drv; } /** * Define the opaqueness of the window / screen * @return opaqueness of window / screen */ - (BOOL)isOpaque { return YES; } /** * Draws a rectangle on the screen. * It's overwritten by the individual drivers but must be defined */ - (void)drawRect:(NSRect)invalidRect { return; } /** * Allow to handle events */ - (BOOL)acceptsFirstResponder { return YES; } /** * Actually handle events */ - (BOOL)becomeFirstResponder { return YES; } /** * Define the rectangle where we draw our application window */ - (void)setTrackingRect { NSPoint loc = [ self convertPoint:[ [ self window ] mouseLocationOutsideOfEventStream ] fromView:nil ]; BOOL inside = ([ self hitTest:loc ]==self); if (inside) [ [ self window ] makeFirstResponder:self ]; trackingtag = [ self addTrackingRect:[ self visibleRect ] owner:self userData:nil assumeInside:inside ]; } /** * Return responsibility for the application window to system */ - (void)clearTrackingRect { [ self removeTrackingRect:trackingtag ]; } /** * Declare responsibility for the cursor within our application rect */ - (void)resetCursorRects { [ super resetCursorRects ]; [ self clearTrackingRect ]; [ self setTrackingRect ]; [ self addCursorRect:[ self bounds ] cursor:(_game_mode == GM_BOOTSTRAP ? [ NSCursor arrowCursor ] : [ NSCursor clearCocoaCursor ]) ]; } /** * Prepare for moving the application window */ - (void)viewWillMoveToWindow:(NSWindow *)win { if (!win && [ self window ]) [ self clearTrackingRect ]; } /** * Restore our responsibility for our application window after moving */ - (void)viewDidMoveToWindow { if ([ self window ]) [ self setTrackingRect ]; } /** * Make OpenTTD aware that it has control over the mouse */ - (void)mouseEntered:(NSEvent *)theEvent { _cursor.in_window = true; } /** * Make OpenTTD aware that it has NOT control over the mouse */ - (void)mouseExited:(NSEvent *)theEvent { if (_cocoa_subdriver != NULL) UndrawMouseCursor(); _cursor.in_window = false; } /** Insert the given text at the given range. */ - (void)insertText:(id)aString replacementRange:(NSRange)replacementRange { if (!EditBoxInGlobalFocus()) return; NSString *s = [ aString isKindOfClass:[ NSAttributedString class ] ] ? [ aString string ] : (NSString *)aString; const char *insert_point = NULL; const char *replace_range = NULL; if (replacementRange.location != NSNotFound) { /* Calculate the part to be replaced. */ insert_point = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), replacementRange.location); replace_range = Utf8AdvanceByUtf16Units(insert_point, replacementRange.length); } HandleTextInput(NULL, true); HandleTextInput([ s UTF8String ], false, NULL, insert_point, replace_range); } /** Insert the given text at the caret. */ - (void)insertText:(id)aString { [ self insertText:aString replacementRange:NSMakeRange(NSNotFound, 0) ]; } /** Set a new marked text and reposition the caret. */ - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange replacementRange:(NSRange)replacementRange { if (!EditBoxInGlobalFocus()) return; NSString *s = [ aString isKindOfClass:[ NSAttributedString class ] ] ? [ aString string ] : (NSString *)aString; const char *utf8 = [ s UTF8String ]; if (utf8 != NULL) { const char *insert_point = NULL; const char *replace_range = NULL; if (replacementRange.location != NSNotFound) { /* Calculate the part to be replaced. */ NSRange marked = [ self markedRange ]; insert_point = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), replacementRange.location + (marked.location != NSNotFound ? marked.location : 0u)); replace_range = Utf8AdvanceByUtf16Units(insert_point, replacementRange.length); } /* Convert caret index into a pointer in the UTF-8 string. */ const char *selection = Utf8AdvanceByUtf16Units(utf8, selRange.location); HandleTextInput(utf8, true, selection, insert_point, replace_range); } } /** Set a new marked text and reposition the caret. */ - (void)setMarkedText:(id)aString selectedRange:(NSRange)selRange { [ self setMarkedText:aString selectedRange:selRange replacementRange:NSMakeRange(NSNotFound, 0) ]; } /** Unmark the current marked text. */ - (void)unmarkText { HandleTextInput(NULL, true); } /** Get the caret position. */ - (NSRange)selectedRange { if (!EditBoxInGlobalFocus()) return NSMakeRange(NSNotFound, 0); NSUInteger start = CountUtf16Units(_focused_window->GetFocusedText(), _focused_window->GetCaret()); return NSMakeRange(start, 0); } /** Get the currently marked range. */ - (NSRange)markedRange { if (!EditBoxInGlobalFocus()) return NSMakeRange(NSNotFound, 0); size_t mark_len; const char *mark = _focused_window->GetMarkedText(&mark_len); if (mark != NULL) { NSUInteger start = CountUtf16Units(_focused_window->GetFocusedText(), mark); NSUInteger len = CountUtf16Units(mark, mark + mark_len); return NSMakeRange(start, len); } return NSMakeRange(NSNotFound, 0); } /** Is any text marked? */ - (BOOL)hasMarkedText { if (!EditBoxInGlobalFocus()) return NO; size_t len; return _focused_window->GetMarkedText(&len) != NULL; } /** Get a string corresponding to the given range. */ - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange { if (!EditBoxInGlobalFocus()) return nil; NSString *s = [ NSString stringWithUTF8String:_focused_window->GetFocusedText() ]; NSRange valid_range = NSIntersectionRange(NSMakeRange(0, [ s length ]), theRange); if (actualRange != NULL) *actualRange = valid_range; if (valid_range.length == 0) return nil; return [ [ [ NSAttributedString alloc ] initWithString:[ s substringWithRange:valid_range ] ] autorelease ]; } /** Get a string corresponding to the given range. */ - (NSAttributedString *)attributedSubstringFromRange:(NSRange)theRange { return [ self attributedSubstringForProposedRange:theRange actualRange:NULL ]; } /** Get the current edit box string. */ - (NSAttributedString *)attributedString { if (!EditBoxInGlobalFocus()) return [ [ [ NSAttributedString alloc ] initWithString:@"" ] autorelease ]; return [ [ [ NSAttributedString alloc ] initWithString:[ NSString stringWithUTF8String:_focused_window->GetFocusedText() ] ] autorelease ]; } /** Get the character that is rendered at the given point. */ - (NSUInteger)characterIndexForPoint:(NSPoint)thePoint { if (!EditBoxInGlobalFocus()) return NSNotFound; NSPoint view_pt = [ self convertPoint:[ [ self window ] convertScreenToBase:thePoint ] fromView:nil ]; Point pt = { (int)view_pt.x, (int)[ self frame ].size.height - (int)view_pt.y }; const char *ch = _focused_window->GetTextCharacterAtPosition(pt); if (ch == NULL) return NSNotFound; return CountUtf16Units(_focused_window->GetFocusedText(), ch); } /** Get the bounding rect for the given range. */ - (NSRect)firstRectForCharacterRange:(NSRange)aRange { if (!EditBoxInGlobalFocus()) return NSMakeRect(0, 0, 0, 0); /* Convert range to UTF-8 string pointers. */ const char *start = Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), aRange.location); const char *end = aRange.length != 0 ? Utf8AdvanceByUtf16Units(_focused_window->GetFocusedText(), aRange.location + aRange.length) : start; /* Get the bounding rect for the text range.*/ Rect r = _focused_window->GetTextBoundingRect(start, end); NSRect view_rect = NSMakeRect(_focused_window->left + r.left, [ self frame ].size.height - _focused_window->top - r.bottom, r.right - r.left, r.bottom - r.top); #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if ([ [ self window ] respondsToSelector:@selector(convertRectToScreen:) ]) { return [ [ self window ] convertRectToScreen:[ self convertRect:view_rect toView:nil ] ]; } #endif NSRect window_rect = [ self convertRect:view_rect toView:nil ]; NSPoint origin = [ [ self window ] convertBaseToScreen:window_rect.origin ]; return NSMakeRect(origin.x, origin.y, window_rect.size.width, window_rect.size.height); } /** Get the bounding rect for the given range. */ - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange { return [ self firstRectForCharacterRange:aRange ]; } /** Get all string attributes that we can process for marked text. */ - (NSArray*)validAttributesForMarkedText { return [ NSArray array ]; } /** Identifier for this text input instance. */ #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 - (long)conversationIdentifier #else - (NSInteger)conversationIdentifier #endif { return 0; } /** Delete single character left of the cursor. */ - (void)deleteBackward:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_BACKSPACE, 0); } /** Delete word left of the cursor. */ - (void)deleteWordBackward:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_BACKSPACE | WKC_CTRL, 0); } /** Delete single character right of the cursor. */ - (void)deleteForward:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_DELETE, 0); } /** Delete word right of the cursor. */ - (void)deleteWordForward:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_DELETE | WKC_CTRL, 0); } /** Move cursor one character left. */ - (void)moveLeft:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_LEFT, 0); } /** Move cursor one word left. */ - (void)moveWordLeft:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_LEFT | WKC_CTRL, 0); } /** Move cursor one character right. */ - (void)moveRight:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_RIGHT, 0); } /** Move cursor one word right. */ - (void)moveWordRight:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_RIGHT | WKC_CTRL, 0); } /** Move cursor one line up. */ - (void)moveUp:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_UP, 0); } /** Move cursor one line down. */ - (void)moveDown:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_DOWN, 0); } /** MScroll one line up. */ - (void)moveUpAndModifySelection:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_UP | WKC_SHIFT, 0); } /** Scroll one line down. */ - (void)moveDownAndModifySelection:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_DOWN | WKC_SHIFT, 0); } /** Move cursor to the start of the line. */ - (void)moveToBeginningOfLine:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_HOME, 0); } /** Move cursor to the end of the line. */ - (void)moveToEndOfLine:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_END, 0); } /** Scroll one page up. */ - (void)scrollPageUp:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_PAGEUP, 0); } /** Scroll one page down. */ - (void)scrollPageDown:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_PAGEDOWN, 0); } /** Move cursor (and selection) one page up. */ - (void)pageUpAndModifySelection:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_PAGEUP | WKC_SHIFT, 0); } /** Move cursor (and selection) one page down. */ - (void)pageDownAndModifySelection:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_PAGEDOWN | WKC_SHIFT, 0); } /** Scroll to the beginning of the document. */ - (void)scrollToBeginningOfDocument:(id)sender { /* For compatibility with OTTD on Win/Linux. */ [ self moveToBeginningOfLine:sender ]; } /** Scroll to the end of the document. */ - (void)scrollToEndOfDocument:(id)sender { /* For compatibility with OTTD on Win/Linux. */ [ self moveToEndOfLine:sender ]; } /** Return was pressed. */ - (void)insertNewline:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_RETURN, '\r'); } /** Escape was pressed. */ - (void)cancelOperation:(id)sender { if (EditBoxInGlobalFocus()) HandleKeypress(WKC_ESC, 0); } /** Invoke the selector if we implement it. */ - (void)doCommandBySelector:(SEL)aSelector { if ([ self respondsToSelector:aSelector ]) [ self performSelector:aSelector ]; } @end @implementation OTTD_CocoaWindowDelegate /** Initialize the video driver */ - (void)setDriver:(CocoaSubdriver*)drv { driver = drv; } /** Handle closure requests */ - (BOOL)windowShouldClose:(id)sender { HandleExitGameRequest(); return NO; } /** Handle key acceptance */ - (void)windowDidBecomeKey:(NSNotification*)aNotification { driver->active = true; } /** Resign key acceptance */ - (void)windowDidResignKey:(NSNotification*)aNotification { driver->active = false; } /** Handle becoming main window */ - (void)windowDidBecomeMain:(NSNotification*)aNotification { driver->active = true; } /** Resign being main window */ - (void)windowDidResignMain:(NSNotification*)aNotification { driver->active = false; } /** Window entered fullscreen mode (10.7). */ - (void)windowDidEnterFullScreen:(NSNotification *)aNotification { NSPoint loc = [ driver->cocoaview convertPoint:[ [ aNotification object ] mouseLocationOutsideOfEventStream ] fromView:nil ]; BOOL inside = ([ driver->cocoaview hitTest:loc ] == driver->cocoaview); if (inside) [ driver->cocoaview mouseEntered:NULL ]; } @end #endif /* WITH_COCOA */ openttd-1.5.3/src/video/cocoa/cocoa_keys.h0000644000000000000000000001023112627373435017155 0ustar rootroot/* $Id: cocoa_keys.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 cocoa_keys.h Mappings of Cocoa keys. */ #ifndef COCOA_KEYS_H #define COCOA_KEYS_H /* From SDL_QuartzKeys.h * These are the Macintosh key scancode constants -- from Inside Macintosh */ #define QZ_ESCAPE 0x35 #define QZ_F1 0x7A #define QZ_F2 0x78 #define QZ_F3 0x63 #define QZ_F4 0x76 #define QZ_F5 0x60 #define QZ_F6 0x61 #define QZ_F7 0x62 #define QZ_F8 0x64 #define QZ_F9 0x65 #define QZ_F10 0x6D #define QZ_F11 0x67 #define QZ_F12 0x6F #define QZ_PRINT 0x69 #define QZ_SCROLLOCK 0x6B #define QZ_PAUSE 0x71 #define QZ_POWER 0x7F #define QZ_BACKQUOTE 0x0A #define QZ_BACKQUOTE2 0x32 #define QZ_1 0x12 #define QZ_2 0x13 #define QZ_3 0x14 #define QZ_4 0x15 #define QZ_5 0x17 #define QZ_6 0x16 #define QZ_7 0x1A #define QZ_8 0x1C #define QZ_9 0x19 #define QZ_0 0x1D #define QZ_MINUS 0x1B #define QZ_EQUALS 0x18 #define QZ_BACKSPACE 0x33 #define QZ_INSERT 0x72 #define QZ_HOME 0x73 #define QZ_PAGEUP 0x74 #define QZ_NUMLOCK 0x47 #define QZ_KP_EQUALS 0x51 #define QZ_KP_DIVIDE 0x4B #define QZ_KP_MULTIPLY 0x43 #define QZ_TAB 0x30 #define QZ_q 0x0C #define QZ_w 0x0D #define QZ_e 0x0E #define QZ_r 0x0F #define QZ_t 0x11 #define QZ_y 0x10 #define QZ_u 0x20 #define QZ_i 0x22 #define QZ_o 0x1F #define QZ_p 0x23 #define QZ_LEFTBRACKET 0x21 #define QZ_RIGHTBRACKET 0x1E #define QZ_BACKSLASH 0x2A #define QZ_DELETE 0x75 #define QZ_END 0x77 #define QZ_PAGEDOWN 0x79 #define QZ_KP7 0x59 #define QZ_KP8 0x5B #define QZ_KP9 0x5C #define QZ_KP_MINUS 0x4E #define QZ_CAPSLOCK 0x39 #define QZ_a 0x00 #define QZ_s 0x01 #define QZ_d 0x02 #define QZ_f 0x03 #define QZ_g 0x05 #define QZ_h 0x04 #define QZ_j 0x26 #define QZ_k 0x28 #define QZ_l 0x25 #define QZ_SEMICOLON 0x29 #define QZ_QUOTE 0x27 #define QZ_RETURN 0x24 #define QZ_KP4 0x56 #define QZ_KP5 0x57 #define QZ_KP6 0x58 #define QZ_KP_PLUS 0x45 #define QZ_LSHIFT 0x38 #define QZ_z 0x06 #define QZ_x 0x07 #define QZ_c 0x08 #define QZ_v 0x09 #define QZ_b 0x0B #define QZ_n 0x2D #define QZ_m 0x2E #define QZ_COMMA 0x2B #define QZ_PERIOD 0x2F #define QZ_SLASH 0x2C #if 1 /* Panther now defines right side keys */ #define QZ_RSHIFT 0x3C #endif #define QZ_UP 0x7E #define QZ_KP1 0x53 #define QZ_KP2 0x54 #define QZ_KP3 0x55 #define QZ_KP_ENTER 0x4C #define QZ_LCTRL 0x3B #define QZ_LALT 0x3A #define QZ_LMETA 0x37 #define QZ_SPACE 0x31 #if 1 /* Panther now defines right side keys */ #define QZ_RMETA 0x36 #define QZ_RALT 0x3D #define QZ_RCTRL 0x3E #endif #define QZ_LEFT 0x7B #define QZ_DOWN 0x7D #define QZ_RIGHT 0x7C #define QZ_KP0 0x52 #define QZ_KP_PERIOD 0x41 /* Wierd, these keys are on my iBook under MacOS X */ #define QZ_IBOOK_ENTER 0x34 #define QZ_IBOOK_LEFT 0x3B #define QZ_IBOOK_RIGHT 0x3C #define QZ_IBOOK_DOWN 0x3D #define QZ_IBOOK_UP 0x3E #endif openttd-1.5.3/src/video/cocoa/cocoa_v.h0000644000000000000000000002034312627373435016454 0ustar rootroot/* $Id: cocoa_v.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 cocoa_v.h The Cocoa video driver. */ #ifndef VIDEO_COCOA_H #define VIDEO_COCOA_H #include "../video_driver.hpp" class VideoDriver_Cocoa : public VideoDriver { public: /* virtual */ const char *Start(const char * const *param); /** Stop the video driver */ /* virtual */ void Stop(); /** Mark dirty a screen region * @param left x-coordinate of left border * @param top y-coordinate of top border * @param width width or dirty rectangle * @param height height of dirty rectangle */ /* virtual */ void MakeDirty(int left, int top, int width, int height); /** Programme main loop */ /* virtual */ void MainLoop(); /** Change window resolution * @param w New window width * @param h New window height * @return Whether change was successful */ /* virtual */ bool ChangeResolution(int w, int h); /** Set a new window mode * @param fullscreen Whether to set fullscreen mode or not * @return Whether changing the screen mode was successful */ /* virtual */ bool ToggleFullscreen(bool fullscreen); /** Callback invoked after the blitter was changed. * @return True if no error. */ /* virtual */ bool AfterBlitterChange(); /** * An edit box lost the input focus. Abort character compositing if necessary. */ /* virtual */ void EditBoxLostFocus(); /** Return driver name * @return driver name */ /* virtual */ const char *GetName() const { return "cocoa"; } }; class FVideoDriver_Cocoa : public DriverFactoryBase { public: FVideoDriver_Cocoa() : DriverFactoryBase(Driver::DT_VIDEO, 10, "cocoa", "Cocoa Video Driver") {} /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Cocoa(); } }; /** * Generic display driver for cocoa * On grounds to not duplicate some code, it contains a few variables * which are not used by all device drivers. */ class CocoaSubdriver { public: int device_width; ///< Width of device in pixel int device_height; ///< Height of device in pixel int device_depth; ///< Colour depth of device in bit int window_width; ///< Current window width in pixel int window_height; ///< Current window height in pixel int window_pitch; int buffer_depth; ///< Colour depth of used frame buffer void *pixel_buffer; ///< used for direct pixel access void *window_buffer; ///< Colour translation from palette to screen id window; ///< Pointer to window object # define MAX_DIRTY_RECTS 100 Rect dirty_rects[MAX_DIRTY_RECTS]; ///< dirty rectangles int num_dirty_rects; ///< Number of dirty rectangles uint32 palette[256]; ///< Colour Palette bool active; ///< Whether the window is visible bool setup; id cocoaview; ///< Pointer to view object /* Separate driver vars for Quarz * Needed here in order to avoid much code duplication */ CGContextRef cgcontext; ///< Context reference for Quartz subdriver /* Driver methods */ /** Initialize driver */ virtual ~CocoaSubdriver() {} /** Draw window * @param force_update Whether to redraw unconditionally */ virtual void Draw(bool force_update = false) = 0; /** Mark dirty a screen region * @param left x-coordinate of left border * @param top y-coordinate of top border * @param width width or dirty rectangle * @param height height of dirty rectangle */ virtual void MakeDirty(int left, int top, int width, int height) = 0; /** Update the palette */ virtual void UpdatePalette(uint first_color, uint num_colors) = 0; virtual uint ListModes(OTTD_Point *modes, uint max_modes) = 0; /** Change window resolution * @param w New window width * @param h New window height * @return Whether change was successful */ virtual bool ChangeResolution(int w, int h, int bpp) = 0; /** Are we in fullscreen mode * @return whether fullscreen mode is currently used */ virtual bool IsFullscreen() = 0; /** Toggle between fullscreen and windowed mode * @return whether switch was successful */ virtual bool ToggleFullscreen() { return false; }; /** Return the width of the current view * @return width of the current view */ virtual int GetWidth() = 0; /** Return the height of the current view * @return height of the current view */ virtual int GetHeight() = 0; /** Return the current pixel buffer * @return pixelbuffer */ virtual void *GetPixelBuffer() = 0; /** Convert local coordinate to window server (CoreGraphics) coordinate * @param p local coordinates * @return window driver coordinates */ virtual CGPoint PrivateLocalToCG(NSPoint *p) = 0; /** Return the mouse location * @param event UI event * @return mouse location as NSPoint */ virtual NSPoint GetMouseLocation(NSEvent *event) = 0; /** Return whether the mouse is within our view * @param pt Mouse coordinates * @return Whether mouse coordinates are within view */ virtual bool MouseIsInsideView(NSPoint *pt) = 0; /** Return whether the window is active (visible) * @return whether the window is visible or not */ virtual bool IsActive() = 0; /** Makes the *game region* of the window 100% opaque. */ virtual void SetPortAlphaOpaque() { return; }; /** Whether the window was successfully resized * @return whether the window was successfully resized */ virtual bool WindowResized() { return false; }; }; extern CocoaSubdriver *_cocoa_subdriver; CocoaSubdriver *QZ_CreateFullscreenSubdriver(int width, int height, int bpp); #ifdef ENABLE_COCOA_QUICKDRAW CocoaSubdriver *QZ_CreateWindowQuickdrawSubdriver(int width, int height, int bpp); #endif #ifdef ENABLE_COCOA_QUARTZ #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 CocoaSubdriver *QZ_CreateWindowQuartzSubdriver(int width, int height, int bpp); #endif #endif void QZ_GameSizeChanged(); void QZ_GameLoop(); uint QZ_ListModes(OTTD_Point *modes, uint max_modes, CGDirectDisplayID display_id, int display_depth); /** Category of NSCursor to allow cursor showing/hiding */ @interface NSCursor (OTTD_QuickdrawCursor) + (NSCursor *) clearCocoaCursor; @end /** Subclass of NSWindow to cater our special needs */ @interface OTTD_CocoaWindow : NSWindow { CocoaSubdriver *driver; } - (void)setDriver:(CocoaSubdriver*)drv; - (void)miniaturize:(id)sender; - (void)display; - (void)setFrame:(NSRect)frameRect display:(BOOL)flag; - (void)appDidHide:(NSNotification*)note; - (void)appWillUnhide:(NSNotification*)note; - (void)appDidUnhide:(NSNotification*)note; - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag; @end /** Subclass of NSView to fix Quartz rendering and mouse awareness */ @interface OTTD_CocoaView : NSView #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 # if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 # else # endif /* MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4 */ #else #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 */ { CocoaSubdriver *driver; NSTrackingRectTag trackingtag; } - (void)setDriver:(CocoaSubdriver*)drv; - (void)drawRect:(NSRect)rect; - (BOOL)isOpaque; - (BOOL)acceptsFirstResponder; - (BOOL)becomeFirstResponder; - (void)setTrackingRect; - (void)clearTrackingRect; - (void)resetCursorRects; - (void)viewWillMoveToWindow:(NSWindow *)win; - (void)viewDidMoveToWindow; - (void)mouseEntered:(NSEvent *)theEvent; - (void)mouseExited:(NSEvent *)theEvent; @end /** Delegate for our NSWindow to send ask for quit on close */ @interface OTTD_CocoaWindowDelegate : NSObject { CocoaSubdriver *driver; } - (void)setDriver:(CocoaSubdriver*)drv; - (BOOL)windowShouldClose:(id)sender; - (void)windowDidEnterFullScreen:(NSNotification *)aNotification; @end #endif /* VIDEO_COCOA_H */ openttd-1.5.3/src/video/cocoa/event.mm0000644000000000000000000004463312627373435016356 0ustar rootroot/* $Id: event.mm 27167 2015-02-22 23:06:45Z frosch $ */ /* * 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 . */ /****************************************************************************** * Cocoa video driver * * Known things left to do: * * Nothing at the moment. * ******************************************************************************/ #ifdef WITH_COCOA #include "../../stdafx.h" #define Rect OTTDRect #define Point OTTDPoint #import #undef Rect #undef Point #include "../../openttd.h" #include "../../debug.h" #include "../../os/macosx/splash.h" #include "../../settings_type.h" #include "../../core/geometry_type.hpp" #include "cocoa_v.h" #include "cocoa_keys.h" #include "../../blitter/factory.hpp" #include "../../gfx_func.h" #include "../../network/network.h" #include "../../core/random_func.hpp" #include "../../core/math_func.hpp" #include "../../texteff.hpp" #include "../../window_func.h" #import /* gettimeofday */ /** * Important notice regarding all modifications!!!!!!! * There are certain limitations because the file is objective C++. * gdb has limitations. * C++ and objective C code can't be joined in all cases (classes stuff). * Read http://developer.apple.com/releasenotes/Cocoa/Objective-C++.html for more information. */ /* Right Mouse Button Emulation enum */ enum RightMouseButtonEmulationState { RMBE_COMMAND, RMBE_CONTROL, RMBE_OFF, }; static unsigned int _current_mods; static bool _tab_is_down; static bool _emulating_right_button; #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) static float _current_magnification; #endif #ifdef _DEBUG static uint32 _tEvent; #endif /* Support for touch gestures is only available starting with the * 10.6 SDK, even if it says that support starts in fact with 10.5.2. * Replicate the needed stuff for older SDKs. */ #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6) static const NSUInteger NSEventTypeMagnify = 30; static const NSUInteger NSEventTypeEndGesture = 20; @interface NSEvent () /* This message is valid for events of type NSEventTypeMagnify, on 10.5.2 or later */ - (CGFloat)magnification WEAK_IMPORT_ATTRIBUTE; @end #endif static uint32 GetTick() { struct timeval tim; gettimeofday(&tim, NULL); return tim.tv_usec / 1000 + tim.tv_sec * 1000; } static void QZ_WarpCursor(int x, int y) { assert(_cocoa_subdriver != NULL); /* Only allow warping when in foreground */ if (![ NSApp isActive ]) return; NSPoint p = NSMakePoint(x, y); CGPoint cgp = _cocoa_subdriver->PrivateLocalToCG(&p); /* this is the magic call that fixes cursor "freezing" after warp */ CGSetLocalEventsSuppressionInterval(0.0); /* Do the actual warp */ CGWarpMouseCursorPosition(cgp); } static void QZ_CheckPaletteAnim() { if (_cur_palette.count_dirty != 0) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); switch (blitter->UsePaletteAnimation()) { case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: _cocoa_subdriver->UpdatePalette(_cur_palette.first_dirty, _cur_palette.count_dirty); break; case Blitter::PALETTE_ANIMATION_BLITTER: blitter->PaletteAnimate(_cur_palette); break; case Blitter::PALETTE_ANIMATION_NONE: break; default: NOT_REACHED(); } _cur_palette.count_dirty = 0; } } struct VkMapping { unsigned short vk_from; byte map_to; }; #define AS(x, z) {x, z} static const VkMapping _vk_mapping[] = { AS(QZ_BACKQUOTE, WKC_BACKQUOTE), // key left of '1' AS(QZ_BACKQUOTE2, WKC_BACKQUOTE), // some keyboards have it on another scancode /* Pageup stuff + up/down */ AS(QZ_PAGEUP, WKC_PAGEUP), AS(QZ_PAGEDOWN, WKC_PAGEDOWN), AS(QZ_UP, WKC_UP), AS(QZ_DOWN, WKC_DOWN), AS(QZ_LEFT, WKC_LEFT), AS(QZ_RIGHT, WKC_RIGHT), AS(QZ_HOME, WKC_HOME), AS(QZ_END, WKC_END), AS(QZ_INSERT, WKC_INSERT), AS(QZ_DELETE, WKC_DELETE), /* Letters. QZ_[a-z] is not in numerical order so we can't use AM(...) */ AS(QZ_a, 'A'), AS(QZ_b, 'B'), AS(QZ_c, 'C'), AS(QZ_d, 'D'), AS(QZ_e, 'E'), AS(QZ_f, 'F'), AS(QZ_g, 'G'), AS(QZ_h, 'H'), AS(QZ_i, 'I'), AS(QZ_j, 'J'), AS(QZ_k, 'K'), AS(QZ_l, 'L'), AS(QZ_m, 'M'), AS(QZ_n, 'N'), AS(QZ_o, 'O'), AS(QZ_p, 'P'), AS(QZ_q, 'Q'), AS(QZ_r, 'R'), AS(QZ_s, 'S'), AS(QZ_t, 'T'), AS(QZ_u, 'U'), AS(QZ_v, 'V'), AS(QZ_w, 'W'), AS(QZ_x, 'X'), AS(QZ_y, 'Y'), AS(QZ_z, 'Z'), /* Same thing for digits */ AS(QZ_0, '0'), AS(QZ_1, '1'), AS(QZ_2, '2'), AS(QZ_3, '3'), AS(QZ_4, '4'), AS(QZ_5, '5'), AS(QZ_6, '6'), AS(QZ_7, '7'), AS(QZ_8, '8'), AS(QZ_9, '9'), AS(QZ_ESCAPE, WKC_ESC), AS(QZ_PAUSE, WKC_PAUSE), AS(QZ_BACKSPACE, WKC_BACKSPACE), AS(QZ_SPACE, WKC_SPACE), AS(QZ_RETURN, WKC_RETURN), AS(QZ_TAB, WKC_TAB), /* Function keys */ AS(QZ_F1, WKC_F1), AS(QZ_F2, WKC_F2), AS(QZ_F3, WKC_F3), AS(QZ_F4, WKC_F4), AS(QZ_F5, WKC_F5), AS(QZ_F6, WKC_F6), AS(QZ_F7, WKC_F7), AS(QZ_F8, WKC_F8), AS(QZ_F9, WKC_F9), AS(QZ_F10, WKC_F10), AS(QZ_F11, WKC_F11), AS(QZ_F12, WKC_F12), /* Numeric part */ AS(QZ_KP0, '0'), AS(QZ_KP1, '1'), AS(QZ_KP2, '2'), AS(QZ_KP3, '3'), AS(QZ_KP4, '4'), AS(QZ_KP5, '5'), AS(QZ_KP6, '6'), AS(QZ_KP7, '7'), AS(QZ_KP8, '8'), AS(QZ_KP9, '9'), AS(QZ_KP_DIVIDE, WKC_NUM_DIV), AS(QZ_KP_MULTIPLY, WKC_NUM_MUL), AS(QZ_KP_MINUS, WKC_NUM_MINUS), AS(QZ_KP_PLUS, WKC_NUM_PLUS), AS(QZ_KP_ENTER, WKC_NUM_ENTER), AS(QZ_KP_PERIOD, WKC_NUM_DECIMAL), /* Other non-letter keys */ AS(QZ_SLASH, WKC_SLASH), AS(QZ_SEMICOLON, WKC_SEMICOLON), AS(QZ_EQUALS, WKC_EQUALS), AS(QZ_LEFTBRACKET, WKC_L_BRACKET), AS(QZ_BACKSLASH, WKC_BACKSLASH), AS(QZ_RIGHTBRACKET, WKC_R_BRACKET), AS(QZ_QUOTE, WKC_SINGLEQUOTE), AS(QZ_COMMA, WKC_COMMA), AS(QZ_MINUS, WKC_MINUS), AS(QZ_PERIOD, WKC_PERIOD) }; static uint32 QZ_MapKey(unsigned short sym) { uint32 key = 0; for (const VkMapping *map = _vk_mapping; map != endof(_vk_mapping); ++map) { if (sym == map->vk_from) { key = map->map_to; break; } } if (_current_mods & NSShiftKeyMask) key |= WKC_SHIFT; if (_current_mods & NSControlKeyMask) key |= (_settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? WKC_CTRL : WKC_META); if (_current_mods & NSAlternateKeyMask) key |= WKC_ALT; if (_current_mods & NSCommandKeyMask) key |= (_settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? WKC_META : WKC_CTRL); return key; } static bool QZ_KeyEvent(unsigned short keycode, unsigned short unicode, BOOL down) { bool interpret_keys = true; switch (keycode) { case QZ_UP: SB(_dirkeys, 1, 1, down); break; case QZ_DOWN: SB(_dirkeys, 3, 1, down); break; case QZ_LEFT: SB(_dirkeys, 0, 1, down); break; case QZ_RIGHT: SB(_dirkeys, 2, 1, down); break; case QZ_TAB: _tab_is_down = down; break; case QZ_RETURN: case QZ_f: if (down && (_current_mods & NSCommandKeyMask)) { VideoDriver::GetInstance()->ToggleFullscreen(!_fullscreen); } break; case QZ_v: if (down && EditBoxInGlobalFocus() && (_current_mods & (NSCommandKeyMask | NSControlKeyMask))) { HandleKeypress(WKC_CTRL | 'V', unicode); } break; case QZ_u: if (down && EditBoxInGlobalFocus() && (_current_mods & (NSCommandKeyMask | NSControlKeyMask))) { HandleKeypress(WKC_CTRL | 'U', unicode); } break; } if (down) { uint32 pressed_key = QZ_MapKey(keycode); static bool console = false; /* The second backquote may have a character, which we don't want to interpret. */ if (pressed_key == WKC_BACKQUOTE && (console || unicode == 0)) { if (!console) { /* Backquote is a dead key, require a double press for hotkey behaviour (i.e. console). */ console = true; return true; } else { /* Second backquote, don't interpret as text input. */ interpret_keys = false; } } console = false; /* Don't handle normal characters if an edit box has the focus. */ if (!EditBoxInGlobalFocus() || IsInsideMM(pressed_key & ~WKC_SPECIAL_KEYS, WKC_F1, WKC_PAUSE + 1)) { HandleKeypress(pressed_key, unicode); } DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), down, mapping: %x", keycode, unicode, pressed_key); } else { DEBUG(driver, 2, "cocoa_v: QZ_KeyEvent: %x (%x), up", keycode, unicode); } return interpret_keys; } static void QZ_DoUnsidedModifiers(unsigned int newMods) { const int mapping[] = { QZ_CAPSLOCK, QZ_LSHIFT, QZ_LCTRL, QZ_LALT, QZ_LMETA }; if (_current_mods == newMods) return; /* Iterate through the bits, testing each against the current modifiers */ for (unsigned int i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) { unsigned int currentMask, newMask; currentMask = _current_mods & bit; newMask = newMods & bit; if (currentMask && currentMask != newMask) { // modifier up event /* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */ if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, YES); QZ_KeyEvent(mapping[i], 0, NO); } else if (newMask && currentMask != newMask) { // modifier down event QZ_KeyEvent(mapping[i], 0, YES); /* If this was Caps Lock, we need some additional voodoo to make SDL happy (is this needed in ottd?) */ if (bit == NSAlphaShiftKeyMask) QZ_KeyEvent(mapping[i], 0, NO); } } _current_mods = newMods; } static void QZ_MouseMovedEvent(int x, int y) { if (_cursor.UpdateCursorPosition(x, y, false)) { QZ_WarpCursor(_cursor.pos.x, _cursor.pos.y); } HandleMouseEvents(); } static void QZ_MouseButtonEvent(int button, BOOL down) { switch (button) { case 0: if (down) { _left_button_down = true; } else { _left_button_down = false; _left_button_clicked = false; } HandleMouseEvents(); break; case 1: if (down) { _right_button_down = true; _right_button_clicked = true; } else { _right_button_down = false; } HandleMouseEvents(); break; } } static bool QZ_PollEvent() { assert(_cocoa_subdriver != NULL); #ifdef _DEBUG uint32 et0 = GetTick(); #endif NSEvent *event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[ NSDate distantPast ] inMode:NSDefaultRunLoopMode dequeue:YES ]; #ifdef _DEBUG _tEvent += GetTick() - et0; #endif if (event == nil) return false; if (!_cocoa_subdriver->IsActive()) { [ NSApp sendEvent:event ]; return true; } QZ_DoUnsidedModifiers( [ event modifierFlags ] ); NSString *chars; NSPoint pt; switch ([ event type ]) { case NSMouseMoved: case NSOtherMouseDragged: case NSLeftMouseDragged: pt = _cocoa_subdriver->GetMouseLocation(event); if (!_cocoa_subdriver->MouseIsInsideView(&pt) && !_emulating_right_button) { [ NSApp sendEvent:event ]; break; } QZ_MouseMovedEvent((int)pt.x, (int)pt.y); break; case NSRightMouseDragged: pt = _cocoa_subdriver->GetMouseLocation(event); QZ_MouseMovedEvent((int)pt.x, (int)pt.y); break; case NSLeftMouseDown: { uint32 keymask = 0; if (_settings_client.gui.right_mouse_btn_emulation == RMBE_COMMAND) keymask |= NSCommandKeyMask; if (_settings_client.gui.right_mouse_btn_emulation == RMBE_CONTROL) keymask |= NSControlKeyMask; pt = _cocoa_subdriver->GetMouseLocation(event); if (!([ event modifierFlags ] & keymask) || !_cocoa_subdriver->MouseIsInsideView(&pt)) { [ NSApp sendEvent:event ]; } QZ_MouseMovedEvent((int)pt.x, (int)pt.y); /* Right mouse button emulation */ if ([ event modifierFlags ] & keymask) { _emulating_right_button = true; QZ_MouseButtonEvent(1, YES); } else { QZ_MouseButtonEvent(0, YES); } break; } case NSLeftMouseUp: [ NSApp sendEvent:event ]; pt = _cocoa_subdriver->GetMouseLocation(event); QZ_MouseMovedEvent((int)pt.x, (int)pt.y); /* Right mouse button emulation */ if (_emulating_right_button) { _emulating_right_button = false; QZ_MouseButtonEvent(1, NO); } else { QZ_MouseButtonEvent(0, NO); } break; case NSRightMouseDown: pt = _cocoa_subdriver->GetMouseLocation(event); if (!_cocoa_subdriver->MouseIsInsideView(&pt)) { [ NSApp sendEvent:event ]; break; } QZ_MouseMovedEvent((int)pt.x, (int)pt.y); QZ_MouseButtonEvent(1, YES); break; case NSRightMouseUp: pt = _cocoa_subdriver->GetMouseLocation(event); if (!_cocoa_subdriver->MouseIsInsideView(&pt)) { [ NSApp sendEvent:event ]; break; } QZ_MouseMovedEvent((int)pt.x, (int)pt.y); QZ_MouseButtonEvent(1, NO); break; #if 0 /* This is not needed since openttd currently only use two buttons */ case NSOtherMouseDown: pt = QZ_GetMouseLocation(event); if (!QZ_MouseIsInsideView(&pt)) { [ NSApp sendEvent:event ]; break; } QZ_MouseMovedEvent((int)pt.x, (int)pt.y); QZ_MouseButtonEvent([ event buttonNumber ], YES); break; case NSOtherMouseUp: pt = QZ_GetMouseLocation(event); if (!QZ_MouseIsInsideView(&pt)) { [ NSApp sendEvent:event ]; break; } QZ_MouseMovedEvent((int)pt.x, (int)pt.y); QZ_MouseButtonEvent([ event buttonNumber ], NO); break; #endif case NSKeyDown: { /* Quit, hide and minimize */ switch ([ event keyCode ]) { case QZ_q: case QZ_h: case QZ_m: if ([ event modifierFlags ] & NSCommandKeyMask) { [ NSApp sendEvent:event ]; } break; } chars = [ event characters ]; unsigned short unicode = [ chars length ] > 0 ? [ chars characterAtIndex:0 ] : 0; if (EditBoxInGlobalFocus()) { if (QZ_KeyEvent([ event keyCode ], unicode, YES)) { [ _cocoa_subdriver->cocoaview interpretKeyEvents:[ NSArray arrayWithObject:event ] ]; } } else { QZ_KeyEvent([ event keyCode ], unicode, YES); for (uint i = 1; i < [ chars length ]; i++) { QZ_KeyEvent(0, [ chars characterAtIndex:i ], YES); } } break; } case NSKeyUp: /* Quit, hide and minimize */ switch ([ event keyCode ]) { case QZ_q: case QZ_h: case QZ_m: if ([ event modifierFlags ] & NSCommandKeyMask) { [ NSApp sendEvent:event ]; } break; } chars = [ event characters ]; QZ_KeyEvent([ event keyCode ], [ chars length ] ? [ chars characterAtIndex:0 ] : 0, NO); break; case NSScrollWheel: if ([ event deltaY ] > 0.0) { /* Scroll up */ _cursor.wheel--; } else if ([ event deltaY ] < 0.0) { /* Scroll down */ _cursor.wheel++; } /* else: deltaY was 0.0 and we don't want to do anything */ /* Set the scroll count for scrollwheel scrolling */ _cursor.h_wheel -= (int)([ event deltaX ] * 5 * _settings_client.gui.scrollwheel_multiplier); _cursor.v_wheel -= (int)([ event deltaY ] * 5 * _settings_client.gui.scrollwheel_multiplier); break; #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) case NSEventTypeMagnify: /* Pinch open or close gesture. */ _current_magnification += [ event magnification ] * 5.0f; while (_current_magnification >= 1.0f) { _current_magnification -= 1.0f; _cursor.wheel++; HandleMouseEvents(); } while (_current_magnification <= -1.0f) { _current_magnification += 1.0f; _cursor.wheel--; HandleMouseEvents(); } break; case NSEventTypeEndGesture: /* Gesture ended. */ _current_magnification = 0.0f; break; #endif case NSCursorUpdate: case NSMouseEntered: case NSMouseExited: /* Catch these events if the cursor is dragging. During dragging, we reset * the mouse position programmatically, which would trigger OS X to show * the default arrow cursor if the events are propagated. */ if (_cursor.fix_at) break; /* FALL THROUGH */ default: [ NSApp sendEvent:event ]; } return true; } void QZ_GameLoop() { uint32 cur_ticks = GetTick(); uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; #ifdef _DEBUG uint32 et0 = GetTick(); uint32 st = 0; #endif DisplaySplashImage(); QZ_CheckPaletteAnim(); _cocoa_subdriver->Draw(true); CSleep(1); for (int i = 0; i < 2; i++) GameLoop(); UpdateWindows(); QZ_CheckPaletteAnim(); _cocoa_subdriver->Draw(); CSleep(1); /* Set the proper OpenTTD palette which got spoilt by the splash * image when using 8bpp blitter */ GfxInitPalettes(); QZ_CheckPaletteAnim(); _cocoa_subdriver->Draw(true); for (;;) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping InteractiveRandom(); // randomness while (QZ_PollEvent()) {} if (_exit_game) break; #if defined(_DEBUG) if (_current_mods & NSShiftKeyMask) #else if (_tab_is_down) #endif { if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; } else if (_fast_forward & 2) { _fast_forward = 0; } cur_ticks = GetTick(); if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { _realtime_tick += cur_ticks - last_cur_ticks; last_cur_ticks = cur_ticks; next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; _ctrl_pressed = !!(_current_mods & ( _settings_client.gui.right_mouse_btn_emulation != RMBE_CONTROL ? NSControlKeyMask : NSCommandKeyMask)); _shift_pressed = !!(_current_mods & NSShiftKeyMask); if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); GameLoop(); UpdateWindows(); QZ_CheckPaletteAnim(); _cocoa_subdriver->Draw(); } else { #ifdef _DEBUG uint32 st0 = GetTick(); #endif CSleep(1); #ifdef _DEBUG st += GetTick() - st0; #endif NetworkDrawChatMessage(); DrawMouseCursor(); _cocoa_subdriver->Draw(); } } #ifdef _DEBUG uint32 et = GetTick(); DEBUG(driver, 1, "cocoa_v: nextEventMatchingMask took %i ms total", _tEvent); DEBUG(driver, 1, "cocoa_v: game loop took %i ms total (%i ms without sleep)", et - et0, et - et0 - st); DEBUG(driver, 1, "cocoa_v: (nextEventMatchingMask total)/(game loop total) is %f%%", (double)_tEvent / (double)(et - et0) * 100); DEBUG(driver, 1, "cocoa_v: (nextEventMatchingMask total)/(game loop without sleep total) is %f%%", (double)_tEvent / (double)(et - et0 - st) * 100); #endif } #endif /* WITH_COCOA */ openttd-1.5.3/src/video/dedicated_v.h0000644000000000000000000000351412627373435016213 0ustar rootroot/* $Id: dedicated_v.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 dedicated_v.h Base for the dedicated video driver. */ #ifndef VIDEO_DEDICATED_H #define VIDEO_DEDICATED_H #include "video_driver.hpp" /** The dedicated server video driver. */ class VideoDriver_Dedicated : public VideoDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void MakeDirty(int left, int top, int width, int height); /* virtual */ void MainLoop(); /* virtual */ bool ChangeResolution(int w, int h); /* virtual */ bool ToggleFullscreen(bool fullscreen); /* virtual */ const char *GetName() const { return "dedicated"; } /* virtual */ bool HasGUI() const { return false; } }; /** Factory for the dedicated server video driver. */ class FVideoDriver_Dedicated : public DriverFactoryBase { public: #ifdef DEDICATED /* Automatically select this dedicated driver when making a dedicated * server build. */ static const int PRIORITY = 10; #else static const int PRIORITY = 0; #endif FVideoDriver_Dedicated() : DriverFactoryBase(Driver::DT_VIDEO, PRIORITY, "dedicated", "Dedicated Video Driver") {} /* virtual */ Driver *CreateInstance() const { return new VideoDriver_Dedicated(); } }; #endif /* VIDEO_DEDICATED_H */ openttd-1.5.3/src/video/null_v.cpp0000644000000000000000000000341512627373435015612 0ustar rootroot/* $Id: null_v.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 null_v.cpp The videio driver that doesn't blit. */ #include "../stdafx.h" #include "../gfx_func.h" #include "../blitter/factory.hpp" #include "null_v.h" #include "../safeguards.h" /** Factory for the null video driver. */ static FVideoDriver_Null iFVideoDriver_Null; const char *VideoDriver_Null::Start(const char * const *parm) { #ifdef _MSC_VER /* Disable the MSVC assertion message box. */ _set_error_mode(_OUT_TO_STDERR); #endif this->ticks = GetDriverParamInt(parm, "ticks", 1000); _screen.width = _screen.pitch = _cur_resolution.width; _screen.height = _cur_resolution.height; _screen.dst_ptr = NULL; ScreenSizeChanged(); /* Do not render, nor blit */ DEBUG(misc, 1, "Forcing blitter 'null'..."); BlitterFactory::SelectBlitter("null"); return NULL; } void VideoDriver_Null::Stop() { } void VideoDriver_Null::MakeDirty(int left, int top, int width, int height) {} void VideoDriver_Null::MainLoop() { uint i; for (i = 0; i < this->ticks; i++) { GameLoop(); UpdateWindows(); } } bool VideoDriver_Null::ChangeResolution(int w, int h) { return false; } bool VideoDriver_Null::ToggleFullscreen(bool fs) { return false; } openttd-1.5.3/src/video/sdl_v.cpp0000644000000000000000000006044212627373435015425 0ustar rootroot/* $Id: sdl_v.cpp 27167 2015-02-22 23:06:45Z frosch $ */ /* * 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 sdl_v.cpp Implementation of the SDL video driver. */ #ifdef WITH_SDL #include "../stdafx.h" #include "../openttd.h" #include "../gfx_func.h" #include "../sdl.h" #include "../rev.h" #include "../blitter/factory.hpp" #include "../network/network.h" #include "../thread/thread.h" #include "../progress.h" #include "../core/random_func.hpp" #include "../core/math_func.hpp" #include "../fileio_func.h" #include "sdl_v.h" #include #include "../safeguards.h" static FVideoDriver_SDL iFVideoDriver_SDL; static SDL_Surface *_sdl_screen; static SDL_Surface *_sdl_realscreen; static bool _all_modes; /** Whether the drawing is/may be done in a separate thread. */ static bool _draw_threaded; /** Thread used to 'draw' to the screen, i.e. push data to the screen. */ static ThreadObject *_draw_thread = NULL; /** Mutex to keep the access to the shared memory controlled. */ static ThreadMutex *_draw_mutex = NULL; /** Should we keep continue drawing? */ static volatile bool _draw_continue; static Palette _local_palette; #define MAX_DIRTY_RECTS 100 static SDL_Rect _dirty_rects[MAX_DIRTY_RECTS]; static int _num_dirty_rects; static int _use_hwpalette; static int _requested_hwpalette; /* Did we request a HWPALETTE for the current video mode? */ void VideoDriver_SDL::MakeDirty(int left, int top, int width, int height) { if (_num_dirty_rects < MAX_DIRTY_RECTS) { _dirty_rects[_num_dirty_rects].x = left; _dirty_rects[_num_dirty_rects].y = top; _dirty_rects[_num_dirty_rects].w = width; _dirty_rects[_num_dirty_rects].h = height; } _num_dirty_rects++; } static void UpdatePalette(bool init = false) { SDL_Color pal[256]; for (int i = 0; i != _local_palette.count_dirty; i++) { pal[i].r = _local_palette.palette[_local_palette.first_dirty + i].r; pal[i].g = _local_palette.palette[_local_palette.first_dirty + i].g; pal[i].b = _local_palette.palette[_local_palette.first_dirty + i].b; pal[i].unused = 0; } SDL_CALL SDL_SetColors(_sdl_screen, pal, _local_palette.first_dirty, _local_palette.count_dirty); if (_sdl_screen != _sdl_realscreen && init) { /* When using a shadow surface, also set our palette on the real screen. This lets SDL * allocate as much colors (or approximations) as * possible, instead of using only the default SDL * palette. This allows us to get more colors exactly * right and might allow using better approximations for * other colors. * * Note that colors allocations are tried in-order, so * this favors colors further up into the palette. Also * note that if two colors from the same animation * sequence are approximated using the same color, that * animation will stop working. * * Since changing the system palette causes the colours * to change right away, and allocations might * drastically change, we can't use this for animation, * since that could cause weird coloring between the * palette change and the blitting below, so we only set * the real palette during initialisation. */ SDL_CALL SDL_SetColors(_sdl_realscreen, pal, _local_palette.first_dirty, _local_palette.count_dirty); } if (_sdl_screen != _sdl_realscreen && !init) { /* We're not using real hardware palette, but are letting SDL * approximate the palette during shadow -> screen copy. To * change the palette, we need to recopy the entire screen. * * Note that this operation can slow down the rendering * considerably, especially since changing the shadow * palette will need the next blit to re-detect the * best mapping of shadow palette colors to real palette * colors from scratch. */ SDL_CALL SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); SDL_CALL SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); } } static void InitPalette() { _local_palette = _cur_palette; _local_palette.first_dirty = 0; _local_palette.count_dirty = 256; UpdatePalette(true); } static void CheckPaletteAnim() { if (_cur_palette.count_dirty != 0) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); switch (blitter->UsePaletteAnimation()) { case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: UpdatePalette(); break; case Blitter::PALETTE_ANIMATION_BLITTER: blitter->PaletteAnimate(_local_palette); break; case Blitter::PALETTE_ANIMATION_NONE: break; default: NOT_REACHED(); } _cur_palette.count_dirty = 0; } } static void DrawSurfaceToScreen() { int n = _num_dirty_rects; if (n == 0) return; _num_dirty_rects = 0; if (n > MAX_DIRTY_RECTS) { if (_sdl_screen != _sdl_realscreen) { SDL_CALL SDL_BlitSurface(_sdl_screen, NULL, _sdl_realscreen, NULL); } SDL_CALL SDL_UpdateRect(_sdl_realscreen, 0, 0, 0, 0); } else { if (_sdl_screen != _sdl_realscreen) { for (int i = 0; i < n; i++) { SDL_CALL SDL_BlitSurface(_sdl_screen, &_dirty_rects[i], _sdl_realscreen, &_dirty_rects[i]); } } SDL_CALL SDL_UpdateRects(_sdl_realscreen, n, _dirty_rects); } } static void DrawSurfaceToScreenThread(void *) { /* First tell the main thread we're started */ _draw_mutex->BeginCritical(); _draw_mutex->SendSignal(); /* Now wait for the first thing to draw! */ _draw_mutex->WaitForSignal(); while (_draw_continue) { CheckPaletteAnim(); /* Then just draw and wait till we stop */ DrawSurfaceToScreen(); _draw_mutex->WaitForSignal(); } _draw_mutex->EndCritical(); _draw_thread->Exit(); } static const Dimension _default_resolutions[] = { { 640, 480}, { 800, 600}, {1024, 768}, {1152, 864}, {1280, 800}, {1280, 960}, {1280, 1024}, {1400, 1050}, {1600, 1200}, {1680, 1050}, {1920, 1200} }; static void GetVideoModes() { SDL_Rect **modes = SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE | SDL_FULLSCREEN); if (modes == NULL) usererror("sdl: no modes available"); _all_modes = (SDL_CALL SDL_ListModes(NULL, SDL_SWSURFACE | (_fullscreen ? SDL_FULLSCREEN : 0)) == (void*)-1); if (modes == (void*)-1) { int n = 0; for (uint i = 0; i < lengthof(_default_resolutions); i++) { if (SDL_CALL SDL_VideoModeOK(_default_resolutions[i].width, _default_resolutions[i].height, 8, SDL_FULLSCREEN) != 0) { _resolutions[n] = _default_resolutions[i]; if (++n == lengthof(_resolutions)) break; } } _num_resolutions = n; } else { int n = 0; for (int i = 0; modes[i]; i++) { uint w = modes[i]->w; uint h = modes[i]->h; int j; for (j = 0; j < n; j++) { if (_resolutions[j].width == w && _resolutions[j].height == h) break; } if (j == n) { _resolutions[j].width = w; _resolutions[j].height = h; if (++n == lengthof(_resolutions)) break; } } _num_resolutions = n; SortResolutions(_num_resolutions); } } static void GetAvailableVideoMode(uint *w, uint *h) { /* All modes available? */ if (_all_modes || _num_resolutions == 0) return; /* Is the wanted mode among the available modes? */ for (int i = 0; i != _num_resolutions; i++) { if (*w == _resolutions[i].width && *h == _resolutions[i].height) return; } /* Use the closest possible resolution */ int best = 0; uint delta = Delta(_resolutions[0].width, *w) * Delta(_resolutions[0].height, *h); for (int i = 1; i != _num_resolutions; ++i) { uint newdelta = Delta(_resolutions[i].width, *w) * Delta(_resolutions[i].height, *h); if (newdelta < delta) { best = i; delta = newdelta; } } *w = _resolutions[best].width; *h = _resolutions[best].height; } #ifdef WIN32 /* Let's redefine the LoadBMP macro with because we are dynamically * loading SDL and need to 'SDL_CALL' all functions */ #undef SDL_LoadBMP #define SDL_LoadBMP(file) SDL_LoadBMP_RW(SDL_CALL SDL_RWFromFile(file, "rb"), 1) #endif bool VideoDriver_SDL::CreateMainSurface(uint w, uint h) { SDL_Surface *newscreen, *icon; char caption[50]; int bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); bool want_hwpalette; GetAvailableVideoMode(&w, &h); DEBUG(driver, 1, "SDL: using mode %ux%ux%d", w, h, bpp); if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); char icon_path[MAX_PATH]; if (FioFindFullPath(icon_path, lastof(icon_path), BASESET_DIR, "openttd.32.bmp") != NULL) { /* Give the application an icon */ icon = SDL_CALL SDL_LoadBMP(icon_path); if (icon != NULL) { /* Get the colourkey, which will be magenta */ uint32 rgbmap = SDL_CALL SDL_MapRGB(icon->format, 255, 0, 255); SDL_CALL SDL_SetColorKey(icon, SDL_SRCCOLORKEY, rgbmap); SDL_CALL SDL_WM_SetIcon(icon, NULL); SDL_CALL SDL_FreeSurface(icon); } } if (_use_hwpalette == 2) { /* Default is to autodetect when to use SDL_HWPALETTE. * In this case, SDL_HWPALETTE is only used for 8bpp * blitters in fullscreen. * * When using an 8bpp blitter on a 8bpp system in * windowed mode with SDL_HWPALETTE, OpenTTD will claim * the system palette, making all other applications * get the wrong colours. In this case, we're better of * trying to approximate the colors we need using system * colors, using a shadow surface (see below). * * On a 32bpp system, SDL_HWPALETTE is ignored, so it * doesn't matter what we do. * * When using a 32bpp blitter on a 8bpp system, setting * SDL_HWPALETTE messes up rendering (at least on X11), * so we don't do that. In this case, SDL takes care of * color approximation using its own shadow surface * (which we can't force in 8bpp on 8bpp mode, * unfortunately). */ want_hwpalette = bpp == 8 && _fullscreen && _support8bpp == S8BPP_HARDWARE; } else { /* User specified a value manually */ want_hwpalette = _use_hwpalette; } if (want_hwpalette) DEBUG(driver, 1, "SDL: requesting hardware palete"); /* Free any previously allocated shadow surface */ if (_sdl_screen != NULL && _sdl_screen != _sdl_realscreen) SDL_CALL SDL_FreeSurface(_sdl_screen); if (_sdl_realscreen != NULL) { if (_requested_hwpalette != want_hwpalette) { /* SDL (at least the X11 driver), reuses the * same window and palette settings when the bpp * (and a few flags) are the same. Since we need * to hwpalette value to change (in particular * when switching between fullscreen and * windowed), we restart the entire video * subsystem to force creating a new window. */ DEBUG(driver, 0, "SDL: Restarting SDL video subsystem, to force hwpalette change"); SDL_CALL SDL_QuitSubSystem(SDL_INIT_VIDEO); SDL_CALL SDL_InitSubSystem(SDL_INIT_VIDEO); ClaimMousePointer(); SetupKeyboard(); } } /* Remember if we wanted a hwpalette. We can't reliably query * SDL for the SDL_HWPALETTE flag, since it might get set even * though we didn't ask for it (when SDL creates a shadow * surface, for example). */ _requested_hwpalette = want_hwpalette; /* DO NOT CHANGE TO HWSURFACE, IT DOES NOT WORK */ newscreen = SDL_CALL SDL_SetVideoMode(w, h, bpp, SDL_SWSURFACE | (want_hwpalette ? SDL_HWPALETTE : 0) | (_fullscreen ? SDL_FULLSCREEN : SDL_RESIZABLE)); if (newscreen == NULL) { DEBUG(driver, 0, "SDL: Couldn't allocate a window to draw on"); return false; } _sdl_realscreen = newscreen; if (bpp == 8 && (_sdl_realscreen->flags & SDL_HWPALETTE) != SDL_HWPALETTE) { /* Using an 8bpp blitter, if we didn't get a hardware * palette (most likely because we didn't request one, * see above), we'll have to set up a shadow surface to * render on. * * Our palette will be applied to this shadow surface, * while the real screen surface will use the shared * system palette (which will partly contain our colors, * but most likely will not have enough free color cells * for all of our colors). SDL can use these two * palettes at blit time to approximate colors used in * the shadow surface using system colors automatically. * * Note that when using an 8bpp blitter on a 32bpp * system, SDL will create an internal shadow surface. * This shadow surface will have SDL_HWPALLETE set, so * we won't create a second shadow surface in this case. */ DEBUG(driver, 1, "SDL: using shadow surface"); newscreen = SDL_CALL SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, bpp, 0, 0, 0, 0); if (newscreen == NULL) { DEBUG(driver, 0, "SDL: Couldn't allocate a shadow surface to draw on"); return false; } } /* Delay drawing for this cycle; the next cycle will redraw the whole screen */ _num_dirty_rects = 0; _screen.width = newscreen->w; _screen.height = newscreen->h; _screen.pitch = newscreen->pitch / (bpp / 8); _screen.dst_ptr = newscreen->pixels; _sdl_screen = newscreen; /* When in full screen, we will always have the mouse cursor * within the window, even though SDL does not give us the * appropriate event to know this. */ if (_fullscreen) _cursor.in_window = true; Blitter *blitter = BlitterFactory::GetCurrentBlitter(); blitter->PostResize(); InitPalette(); switch (blitter->UsePaletteAnimation()) { case Blitter::PALETTE_ANIMATION_NONE: case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: UpdatePalette(); break; case Blitter::PALETTE_ANIMATION_BLITTER: if (VideoDriver::GetInstance() != NULL) blitter->PaletteAnimate(_local_palette); break; default: NOT_REACHED(); } seprintf(caption, lastof(caption), "OpenTTD %s", _openttd_revision); SDL_CALL SDL_WM_SetCaption(caption, caption); GameSizeChanged(); return true; } bool VideoDriver_SDL::ClaimMousePointer() { SDL_CALL SDL_ShowCursor(0); return true; } struct VkMapping { #if SDL_VERSION_ATLEAST(1, 3, 0) SDL_Keycode vk_from; #else uint16 vk_from; #endif byte vk_count; byte map_to; }; #define AS(x, z) {x, 0, z} #define AM(x, y, z, w) {x, (byte)(y - x), z} static const VkMapping _vk_mapping[] = { /* Pageup stuff + up/down */ AM(SDLK_PAGEUP, SDLK_PAGEDOWN, WKC_PAGEUP, WKC_PAGEDOWN), AS(SDLK_UP, WKC_UP), AS(SDLK_DOWN, WKC_DOWN), AS(SDLK_LEFT, WKC_LEFT), AS(SDLK_RIGHT, WKC_RIGHT), AS(SDLK_HOME, WKC_HOME), AS(SDLK_END, WKC_END), AS(SDLK_INSERT, WKC_INSERT), AS(SDLK_DELETE, WKC_DELETE), /* Map letters & digits */ AM(SDLK_a, SDLK_z, 'A', 'Z'), AM(SDLK_0, SDLK_9, '0', '9'), AS(SDLK_ESCAPE, WKC_ESC), AS(SDLK_PAUSE, WKC_PAUSE), AS(SDLK_BACKSPACE, WKC_BACKSPACE), AS(SDLK_SPACE, WKC_SPACE), AS(SDLK_RETURN, WKC_RETURN), AS(SDLK_TAB, WKC_TAB), /* Function keys */ AM(SDLK_F1, SDLK_F12, WKC_F1, WKC_F12), /* Numeric part. */ AM(SDLK_KP0, SDLK_KP9, '0', '9'), AS(SDLK_KP_DIVIDE, WKC_NUM_DIV), AS(SDLK_KP_MULTIPLY, WKC_NUM_MUL), AS(SDLK_KP_MINUS, WKC_NUM_MINUS), AS(SDLK_KP_PLUS, WKC_NUM_PLUS), AS(SDLK_KP_ENTER, WKC_NUM_ENTER), AS(SDLK_KP_PERIOD, WKC_NUM_DECIMAL), /* Other non-letter keys */ AS(SDLK_SLASH, WKC_SLASH), AS(SDLK_SEMICOLON, WKC_SEMICOLON), AS(SDLK_EQUALS, WKC_EQUALS), AS(SDLK_LEFTBRACKET, WKC_L_BRACKET), AS(SDLK_BACKSLASH, WKC_BACKSLASH), AS(SDLK_RIGHTBRACKET, WKC_R_BRACKET), AS(SDLK_QUOTE, WKC_SINGLEQUOTE), AS(SDLK_COMMA, WKC_COMMA), AS(SDLK_MINUS, WKC_MINUS), AS(SDLK_PERIOD, WKC_PERIOD) }; static uint ConvertSdlKeyIntoMy(SDL_keysym *sym, WChar *character) { const VkMapping *map; uint key = 0; for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { if ((uint)(sym->sym - map->vk_from) <= map->vk_count) { key = sym->sym - map->vk_from + map->map_to; break; } } /* check scancode for BACKQUOTE key, because we want the key left of "1", not anything else (on non-US keyboards) */ #if defined(WIN32) || defined(__OS2__) if (sym->scancode == 41) key = WKC_BACKQUOTE; #elif defined(__APPLE__) if (sym->scancode == 10) key = WKC_BACKQUOTE; #elif defined(__MORPHOS__) if (sym->scancode == 0) key = WKC_BACKQUOTE; // yes, that key is code '0' under MorphOS :) #elif defined(__BEOS__) if (sym->scancode == 17) key = WKC_BACKQUOTE; #elif defined(__SVR4) && defined(__sun) if (sym->scancode == 60) key = WKC_BACKQUOTE; if (sym->scancode == 49) key = WKC_BACKSPACE; #elif defined(__sgi__) if (sym->scancode == 22) key = WKC_BACKQUOTE; #else if (sym->scancode == 49) key = WKC_BACKQUOTE; #endif /* META are the command keys on mac */ if (sym->mod & KMOD_META) key |= WKC_META; if (sym->mod & KMOD_SHIFT) key |= WKC_SHIFT; if (sym->mod & KMOD_CTRL) key |= WKC_CTRL; if (sym->mod & KMOD_ALT) key |= WKC_ALT; *character = sym->unicode; return key; } int VideoDriver_SDL::PollEvent() { SDL_Event ev; if (!SDL_CALL SDL_PollEvent(&ev)) return -2; switch (ev.type) { case SDL_MOUSEMOTION: if (_cursor.UpdateCursorPosition(ev.motion.x, ev.motion.y, true)) { SDL_CALL SDL_WarpMouse(_cursor.pos.x, _cursor.pos.y); } HandleMouseEvents(); break; case SDL_MOUSEBUTTONDOWN: if (_rightclick_emulate && SDL_CALL SDL_GetModState() & KMOD_CTRL) { ev.button.button = SDL_BUTTON_RIGHT; } switch (ev.button.button) { case SDL_BUTTON_LEFT: _left_button_down = true; break; case SDL_BUTTON_RIGHT: _right_button_down = true; _right_button_clicked = true; break; case SDL_BUTTON_WHEELUP: _cursor.wheel--; break; case SDL_BUTTON_WHEELDOWN: _cursor.wheel++; break; default: break; } HandleMouseEvents(); break; case SDL_MOUSEBUTTONUP: if (_rightclick_emulate) { _right_button_down = false; _left_button_down = false; _left_button_clicked = false; } else if (ev.button.button == SDL_BUTTON_LEFT) { _left_button_down = false; _left_button_clicked = false; } else if (ev.button.button == SDL_BUTTON_RIGHT) { _right_button_down = false; } HandleMouseEvents(); break; case SDL_ACTIVEEVENT: if (!(ev.active.state & SDL_APPMOUSEFOCUS)) break; if (ev.active.gain) { // mouse entered the window, enable cursor _cursor.in_window = true; } else { UndrawMouseCursor(); // mouse left the window, undraw cursor _cursor.in_window = false; } break; case SDL_QUIT: HandleExitGameRequest(); break; case SDL_KEYDOWN: // Toggle full-screen on ALT + ENTER/F if ((ev.key.keysym.mod & (KMOD_ALT | KMOD_META)) && (ev.key.keysym.sym == SDLK_RETURN || ev.key.keysym.sym == SDLK_f)) { ToggleFullScreen(!_fullscreen); } else { WChar character; uint keycode = ConvertSdlKeyIntoMy(&ev.key.keysym, &character); HandleKeypress(keycode, character); } break; case SDL_VIDEORESIZE: { int w = max(ev.resize.w, 64); int h = max(ev.resize.h, 64); CreateMainSurface(w, h); break; } case SDL_VIDEOEXPOSE: { /* Force a redraw of the entire screen. Note * that SDL 1.2 seems to do this automatically * in most cases, but 1.3 / 2.0 does not. */ _num_dirty_rects = MAX_DIRTY_RECTS + 1; break; } } return -1; } const char *VideoDriver_SDL::Start(const char * const *parm) { char buf[30]; _use_hwpalette = GetDriverParamInt(parm, "hw_palette", 2); const char *s = SdlOpen(SDL_INIT_VIDEO); if (s != NULL) return s; GetVideoModes(); if (!CreateMainSurface(_cur_resolution.width, _cur_resolution.height)) { return SDL_CALL SDL_GetError(); } SDL_CALL SDL_VideoDriverName(buf, sizeof buf); DEBUG(driver, 1, "SDL: using driver '%s'", buf); MarkWholeScreenDirty(); SetupKeyboard(); _draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL; return NULL; } void VideoDriver_SDL::SetupKeyboard() { SDL_CALL SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); SDL_CALL SDL_EnableUNICODE(1); } void VideoDriver_SDL::Stop() { SdlClose(SDL_INIT_VIDEO); } void VideoDriver_SDL::MainLoop() { uint32 cur_ticks = SDL_CALL SDL_GetTicks(); uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; uint32 mod; int numkeys; Uint8 *keys; CheckPaletteAnim(); if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* * directly in the newly created thread. */ _draw_mutex = ThreadMutex::New(); if (_draw_mutex == NULL) { _draw_threaded = false; } else { _draw_mutex->BeginCritical(); _draw_continue = true; _draw_threaded = ThreadObject::New(&DrawSurfaceToScreenThread, NULL, &_draw_thread); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { _draw_mutex->EndCritical(); delete _draw_mutex; _draw_mutex = NULL; } else { /* Wait till the draw mutex has started itself. */ _draw_mutex->WaitForSignal(); } } } DEBUG(driver, 1, "SDL: using %sthreads", _draw_threaded ? "" : "no "); for (;;) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping InteractiveRandom(); // randomness while (PollEvent() == -1) {} if (_exit_game) break; mod = SDL_CALL SDL_GetModState(); #if SDL_VERSION_ATLEAST(1, 3, 0) keys = SDL_CALL SDL_GetKeyboardState(&numkeys); #else keys = SDL_CALL SDL_GetKeyState(&numkeys); #endif #if defined(_DEBUG) if (_shift_pressed) #else /* Speedup when pressing tab, except when using ALT+TAB * to switch to another application */ #if SDL_VERSION_ATLEAST(1, 3, 0) if (keys[SDL_SCANCODE_TAB] && (mod & KMOD_ALT) == 0) #else if (keys[SDLK_TAB] && (mod & KMOD_ALT) == 0) #endif /* SDL_VERSION_ATLEAST(1, 3, 0) */ #endif /* defined(_DEBUG) */ { if (!_networking && _game_mode != GM_MENU) _fast_forward |= 2; } else if (_fast_forward & 2) { _fast_forward = 0; } cur_ticks = SDL_CALL SDL_GetTicks(); if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { _realtime_tick += cur_ticks - last_cur_ticks; last_cur_ticks = cur_ticks; next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; _ctrl_pressed = !!(mod & KMOD_CTRL); _shift_pressed = !!(mod & KMOD_SHIFT); /* determine which directional keys are down */ _dirkeys = #if SDL_VERSION_ATLEAST(1, 3, 0) (keys[SDL_SCANCODE_LEFT] ? 1 : 0) | (keys[SDL_SCANCODE_UP] ? 2 : 0) | (keys[SDL_SCANCODE_RIGHT] ? 4 : 0) | (keys[SDL_SCANCODE_DOWN] ? 8 : 0); #else (keys[SDLK_LEFT] ? 1 : 0) | (keys[SDLK_UP] ? 2 : 0) | (keys[SDLK_RIGHT] ? 4 : 0) | (keys[SDLK_DOWN] ? 8 : 0); #endif if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); /* The gameloop is the part that can run asynchronously. The rest * except sleeping can't. */ if (_draw_mutex != NULL) _draw_mutex->EndCritical(); GameLoop(); if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); UpdateWindows(); _local_palette = _cur_palette; } else { /* Release the thread while sleeping */ if (_draw_mutex != NULL) _draw_mutex->EndCritical(); CSleep(1); if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); NetworkDrawChatMessage(); DrawMouseCursor(); } /* End of the critical part. */ if (_draw_mutex != NULL && !HasModalProgress()) { _draw_mutex->SendSignal(); } else { /* Oh, we didn't have threads, then just draw unthreaded */ CheckPaletteAnim(); DrawSurfaceToScreen(); } } if (_draw_mutex != NULL) { _draw_continue = false; /* Sending signal if there is no thread blocked * is very valid and results in noop */ _draw_mutex->SendSignal(); _draw_mutex->EndCritical(); _draw_thread->Join(); delete _draw_mutex; delete _draw_thread; _draw_mutex = NULL; _draw_thread = NULL; } } bool VideoDriver_SDL::ChangeResolution(int w, int h) { if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); bool ret = CreateMainSurface(w, h); if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen) { if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); _fullscreen = fullscreen; GetVideoModes(); // get the list of available video modes bool ret = _num_resolutions != 0 && CreateMainSurface(_cur_resolution.width, _cur_resolution.height); if (!ret) { /* switching resolution failed, put back full_screen to original status */ _fullscreen ^= true; } if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } bool VideoDriver_SDL::AfterBlitterChange() { if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); bool ret = CreateMainSurface(_screen.width, _screen.height); if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } #endif /* WITH_SDL */ openttd-1.5.3/src/video/sdl_v.h0000644000000000000000000000323512627373435015067 0ustar rootroot/* $Id: sdl_v.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 sdl_v.h Base of the SDL video driver. */ #ifndef VIDEO_SDL_H #define VIDEO_SDL_H #include "video_driver.hpp" /** The SDL video driver. */ class VideoDriver_SDL : public VideoDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void MakeDirty(int left, int top, int width, int height); /* virtual */ void MainLoop(); /* virtual */ bool ChangeResolution(int w, int h); /* virtual */ bool ToggleFullscreen(bool fullscreen); /* virtual */ bool AfterBlitterChange(); /* virtual */ bool ClaimMousePointer(); /* virtual */ const char *GetName() const { return "sdl"; } private: int PollEvent(); bool CreateMainSurface(uint w, uint h); void SetupKeyboard(); }; /** Factory for the SDL video driver. */ class FVideoDriver_SDL : public DriverFactoryBase { public: FVideoDriver_SDL() : DriverFactoryBase(Driver::DT_VIDEO, 5, "sdl", "SDL Video Driver") {} /* virtual */ Driver *CreateInstance() const { return new VideoDriver_SDL(); } }; #endif /* VIDEO_SDL_H */ openttd-1.5.3/src/video/win32_v.cpp0000644000000000000000000011140712627373435015603 0ustar rootroot/* $Id: win32_v.cpp 27167 2015-02-22 23:06:45Z frosch $ */ /* * 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 win32_v.cpp Implementation of the Windows (GDI) video driver. */ #include "../stdafx.h" #include "../openttd.h" #include "../gfx_func.h" #include "../os/windows/win32.h" #include "../rev.h" #include "../blitter/factory.hpp" #include "../network/network.h" #include "../core/math_func.hpp" #include "../core/random_func.hpp" #include "../texteff.hpp" #include "../thread/thread.h" #include "../progress.h" #include "../window_gui.h" #include "../window_func.h" #include "win32_v.h" #include #include #include "../safeguards.h" /* Missing define in MinGW headers. */ #ifndef MAPVK_VK_TO_CHAR #define MAPVK_VK_TO_CHAR (2) #endif static struct { HWND main_wnd; HBITMAP dib_sect; void *buffer_bits; HPALETTE gdi_palette; RECT update_rect; int width; int height; int width_org; int height_org; bool fullscreen; bool has_focus; bool running; } _wnd; bool _force_full_redraw; bool _window_maximize; uint _display_hz; static Dimension _bck_resolution; #if !defined(WINCE) || _WIN32_WCE >= 0x400 DWORD _imm_props; #endif /** Whether the drawing is/may be done in a separate thread. */ static bool _draw_threaded; /** Thread used to 'draw' to the screen, i.e. push data to the screen. */ static ThreadObject *_draw_thread = NULL; /** Mutex to keep the access to the shared memory controlled. */ static ThreadMutex *_draw_mutex = NULL; /** Event that is signaled when the drawing thread has finished initializing. */ static HANDLE _draw_thread_initialized = NULL; /** Should we keep continue drawing? */ static volatile bool _draw_continue; /** Local copy of the palette for use in the drawing thread. */ static Palette _local_palette; static void MakePalette() { LOGPALETTE *pal = (LOGPALETTE*)alloca(sizeof(LOGPALETTE) + (256 - 1) * sizeof(PALETTEENTRY)); pal->palVersion = 0x300; pal->palNumEntries = 256; for (uint i = 0; i != 256; i++) { pal->palPalEntry[i].peRed = _cur_palette.palette[i].r; pal->palPalEntry[i].peGreen = _cur_palette.palette[i].g; pal->palPalEntry[i].peBlue = _cur_palette.palette[i].b; pal->palPalEntry[i].peFlags = 0; } _wnd.gdi_palette = CreatePalette(pal); if (_wnd.gdi_palette == NULL) usererror("CreatePalette failed!\n"); _cur_palette.first_dirty = 0; _cur_palette.count_dirty = 256; _local_palette = _cur_palette; } static void UpdatePalette(HDC dc, uint start, uint count) { RGBQUAD rgb[256]; uint i; for (i = 0; i != count; i++) { rgb[i].rgbRed = _local_palette.palette[start + i].r; rgb[i].rgbGreen = _local_palette.palette[start + i].g; rgb[i].rgbBlue = _local_palette.palette[start + i].b; rgb[i].rgbReserved = 0; } SetDIBColorTable(dc, start, count, rgb); } bool VideoDriver_Win32::ClaimMousePointer() { MyShowCursor(false, true); return true; } struct VkMapping { byte vk_from; byte vk_count; byte map_to; }; #define AS(x, z) {x, 0, z} #define AM(x, y, z, w) {x, y - x, z} static const VkMapping _vk_mapping[] = { /* Pageup stuff + up/down */ AM(VK_PRIOR, VK_DOWN, WKC_PAGEUP, WKC_DOWN), /* Map letters & digits */ AM('A', 'Z', 'A', 'Z'), AM('0', '9', '0', '9'), AS(VK_ESCAPE, WKC_ESC), AS(VK_PAUSE, WKC_PAUSE), AS(VK_BACK, WKC_BACKSPACE), AM(VK_INSERT, VK_DELETE, WKC_INSERT, WKC_DELETE), AS(VK_SPACE, WKC_SPACE), AS(VK_RETURN, WKC_RETURN), AS(VK_TAB, WKC_TAB), /* Function keys */ AM(VK_F1, VK_F12, WKC_F1, WKC_F12), /* Numeric part */ AM(VK_NUMPAD0, VK_NUMPAD9, '0', '9'), AS(VK_DIVIDE, WKC_NUM_DIV), AS(VK_MULTIPLY, WKC_NUM_MUL), AS(VK_SUBTRACT, WKC_NUM_MINUS), AS(VK_ADD, WKC_NUM_PLUS), AS(VK_DECIMAL, WKC_NUM_DECIMAL), /* Other non-letter keys */ AS(0xBF, WKC_SLASH), AS(0xBA, WKC_SEMICOLON), AS(0xBB, WKC_EQUALS), AS(0xDB, WKC_L_BRACKET), AS(0xDC, WKC_BACKSLASH), AS(0xDD, WKC_R_BRACKET), AS(0xDE, WKC_SINGLEQUOTE), AS(0xBC, WKC_COMMA), AS(0xBD, WKC_MINUS), AS(0xBE, WKC_PERIOD) }; static uint MapWindowsKey(uint sym) { const VkMapping *map; uint key = 0; for (map = _vk_mapping; map != endof(_vk_mapping); ++map) { if ((uint)(sym - map->vk_from) <= map->vk_count) { key = sym - map->vk_from + map->map_to; break; } } if (GetAsyncKeyState(VK_SHIFT) < 0) key |= WKC_SHIFT; if (GetAsyncKeyState(VK_CONTROL) < 0) key |= WKC_CTRL; if (GetAsyncKeyState(VK_MENU) < 0) key |= WKC_ALT; return key; } static bool AllocateDibSection(int w, int h, bool force = false); static void ClientSizeChanged(int w, int h) { /* allocate new dib section of the new size */ if (AllocateDibSection(w, h)) { /* mark all palette colours dirty */ _cur_palette.first_dirty = 0; _cur_palette.count_dirty = 256; _local_palette = _cur_palette; BlitterFactory::GetCurrentBlitter()->PostResize(); GameSizeChanged(); } } #ifdef _DEBUG /* Keep this function here.. * It allows you to redraw the screen from within the MSVC debugger */ int RedrawScreenDebug() { HDC dc, dc2; static int _fooctr; HBITMAP old_bmp; HPALETTE old_palette; UpdateWindows(); dc = GetDC(_wnd.main_wnd); dc2 = CreateCompatibleDC(dc); old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect); old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); SelectPalette(dc, old_palette, TRUE); SelectObject(dc2, old_bmp); DeleteDC(dc2); ReleaseDC(_wnd.main_wnd, dc); return _fooctr++; } #endif /* Windows 95 will not have a WM_MOUSELEAVE message, so define it if needed */ #if !defined(WM_MOUSELEAVE) #define WM_MOUSELEAVE 0x02A3 #endif #define TID_POLLMOUSE 1 #define MOUSE_POLL_DELAY 75 static void CALLBACK TrackMouseTimerProc(HWND hwnd, UINT msg, UINT event, DWORD time) { RECT rc; POINT pt; /* Get the rectangle of our window and translate it to screen coordinates. * Compare this with the current screen coordinates of the mouse and if it * falls outside of the area or our window we have left the window. */ GetClientRect(hwnd, &rc); MapWindowPoints(hwnd, HWND_DESKTOP, (LPPOINT)(LPRECT)&rc, 2); GetCursorPos(&pt); if (!PtInRect(&rc, pt) || (WindowFromPoint(pt) != hwnd)) { KillTimer(hwnd, event); PostMessage(hwnd, WM_MOUSELEAVE, 0, 0L); } } /** * Instantiate a new window. * @param full_screen Whether to make a full screen window or not. * @return True if the window could be created. */ bool VideoDriver_Win32::MakeWindow(bool full_screen) { _fullscreen = full_screen; /* recreate window? */ if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) { DestroyWindow(_wnd.main_wnd); _wnd.main_wnd = 0; } #if defined(WINCE) /* WinCE is always fullscreen */ #else if (full_screen) { DEVMODE settings; memset(&settings, 0, sizeof(settings)); settings.dmSize = sizeof(settings); settings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | (_display_hz != 0 ? DM_DISPLAYFREQUENCY : 0); settings.dmBitsPerPel = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); settings.dmPelsWidth = _wnd.width_org; settings.dmPelsHeight = _wnd.height_org; settings.dmDisplayFrequency = _display_hz; /* Check for 8 bpp support. */ if (settings.dmBitsPerPel == 8 && (_support8bpp != S8BPP_HARDWARE || ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL)) { settings.dmBitsPerPel = 32; } /* Test fullscreen with current resolution, if it fails use desktop resolution. */ if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN | CDS_TEST) != DISP_CHANGE_SUCCESSFUL) { RECT r; GetWindowRect(GetDesktopWindow(), &r); /* Guard against recursion. If we already failed here once, just fall through to * the next ChangeDisplaySettings call which will fail and error out appropriately. */ if ((int)settings.dmPelsWidth != r.right - r.left || (int)settings.dmPelsHeight != r.bottom - r.top) { return this->ChangeResolution(r.right - r.left, r.bottom - r.top); } } if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { this->MakeWindow(false); // don't care about the result return false; // the request failed } } else if (_wnd.fullscreen) { /* restore display? */ ChangeDisplaySettings(NULL, 0); /* restore the resolution */ _wnd.width = _bck_resolution.width; _wnd.height = _bck_resolution.height; } #endif { RECT r; DWORD style, showstyle; int w, h; showstyle = SW_SHOWNORMAL; _wnd.fullscreen = full_screen; if (_wnd.fullscreen) { style = WS_POPUP; SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org); } else { style = WS_OVERLAPPEDWINDOW; /* On window creation, check if we were in maximize mode before */ if (_window_maximize) showstyle = SW_SHOWMAXIMIZED; SetRect(&r, 0, 0, _wnd.width, _wnd.height); } #if !defined(WINCE) AdjustWindowRect(&r, style, FALSE); #endif w = r.right - r.left; h = r.bottom - r.top; if (_wnd.main_wnd != NULL) { if (!_window_maximize) SetWindowPos(_wnd.main_wnd, 0, 0, 0, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE); } else { TCHAR Windowtitle[50]; int x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2; int y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2; _sntprintf(Windowtitle, lengthof(Windowtitle), _T("OpenTTD %s"), MB_TO_WIDE(_openttd_revision)); _wnd.main_wnd = CreateWindow(_T("OTTD"), Windowtitle, style, x, y, w, h, 0, 0, GetModuleHandle(NULL), 0); if (_wnd.main_wnd == NULL) usererror("CreateWindow failed"); ShowWindow(_wnd.main_wnd, showstyle); } } BlitterFactory::GetCurrentBlitter()->PostResize(); GameSizeChanged(); // invalidate all windows, force redraw return true; // the request succeeded } /** Do palette animation and blit to the window. */ static void PaintWindow(HDC dc) { HDC dc2 = CreateCompatibleDC(dc); HBITMAP old_bmp = (HBITMAP)SelectObject(dc2, _wnd.dib_sect); HPALETTE old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE); if (_cur_palette.count_dirty != 0) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); switch (blitter->UsePaletteAnimation()) { case Blitter::PALETTE_ANIMATION_VIDEO_BACKEND: UpdatePalette(dc2, _local_palette.first_dirty, _local_palette.count_dirty); break; case Blitter::PALETTE_ANIMATION_BLITTER: blitter->PaletteAnimate(_local_palette); break; case Blitter::PALETTE_ANIMATION_NONE: break; default: NOT_REACHED(); } _cur_palette.count_dirty = 0; } BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY); SelectPalette(dc, old_palette, TRUE); SelectObject(dc2, old_bmp); DeleteDC(dc2); } static void PaintWindowThread(void *) { /* First tell the main thread we're started */ _draw_mutex->BeginCritical(); SetEvent(_draw_thread_initialized); /* Now wait for the first thing to draw! */ _draw_mutex->WaitForSignal(); while (_draw_continue) { /* Convert update region from logical to device coordinates. */ POINT pt = {0, 0}; ClientToScreen(_wnd.main_wnd, &pt); OffsetRect(&_wnd.update_rect, pt.x, pt.y); /* Create a device context that is clipped to the region we need to draw. * GetDCEx 'consumes' the update region, so we may not destroy it ourself. */ HRGN rgn = CreateRectRgnIndirect(&_wnd.update_rect); HDC dc = GetDCEx(_wnd.main_wnd, rgn, DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_INTERSECTRGN); PaintWindow(dc); /* Clear update rect. */ SetRectEmpty(&_wnd.update_rect); ReleaseDC(_wnd.main_wnd, dc); /* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */ GdiFlush(); _draw_mutex->WaitForSignal(); } _draw_mutex->EndCritical(); _draw_thread->Exit(); } /** Forward key presses to the window system. */ static LRESULT HandleCharMsg(uint keycode, WChar charcode) { #if !defined(UNICODE) static char prev_char = 0; char input[2] = {(char)charcode, 0}; int input_len = 1; if (prev_char != 0) { /* We stored a lead byte previously, combine it with this byte. */ input[0] = prev_char; input[1] = (char)charcode; input_len = 2; } else if (IsDBCSLeadByte(charcode)) { /* We got a lead byte, store and exit. */ prev_char = charcode; return 0; } prev_char = 0; wchar_t w[2]; // Can get up to two code points as a result. int len = MultiByteToWideChar(CP_ACP, 0, input, input_len, w, 2); switch (len) { case 1: // Normal unicode character. charcode = w[0]; break; case 2: // Got an UTF-16 surrogate pair back. charcode = Utf16DecodeSurrogate(w[0], w[1]); break; default: // Some kind of error. DEBUG(driver, 1, "Invalid DBCS character sequence encountered, dropping input"); charcode = 0; break; } #else static WChar prev_char = 0; /* Did we get a lead surrogate? If yes, store and exit. */ if (Utf16IsLeadSurrogate(charcode)) { if (prev_char != 0) DEBUG(driver, 1, "Got two UTF-16 lead surrogates, dropping the first one"); prev_char = charcode; return 0; } /* Stored lead surrogate and incoming trail surrogate? Combine and forward to input handling. */ if (prev_char != 0) { if (Utf16IsTrailSurrogate(charcode)) { charcode = Utf16DecodeSurrogate(prev_char, charcode); } else { DEBUG(driver, 1, "Got an UTF-16 lead surrogate without a trail surrogate, dropping the lead surrogate"); } } prev_char = 0; #endif /* UNICODE */ HandleKeypress(keycode, charcode); return 0; } #if !defined(WINCE) || _WIN32_WCE >= 0x400 /** Should we draw the composition string ourself, i.e is this a normal IME? */ static bool DrawIMECompositionString() { return (_imm_props & IME_PROP_AT_CARET) && !(_imm_props & IME_PROP_SPECIAL_UI); } /** Set position of the composition window to the caret position. */ static void SetCompositionPos(HWND hwnd) { HIMC hIMC = ImmGetContext(hwnd); if (hIMC != NULL) { COMPOSITIONFORM cf; cf.dwStyle = CFS_POINT; if (EditBoxInGlobalFocus()) { /* Get caret position. */ Point pt = _focused_window->GetCaretPosition(); cf.ptCurrentPos.x = _focused_window->left + pt.x; cf.ptCurrentPos.y = _focused_window->top + pt.y; } else { cf.ptCurrentPos.x = 0; cf.ptCurrentPos.y = 0; } ImmSetCompositionWindow(hIMC, &cf); } ImmReleaseContext(hwnd, hIMC); } /** Set the position of the candidate window. */ static void SetCandidatePos(HWND hwnd) { HIMC hIMC = ImmGetContext(hwnd); if (hIMC != NULL) { CANDIDATEFORM cf; cf.dwIndex = 0; cf.dwStyle = CFS_EXCLUDE; if (EditBoxInGlobalFocus()) { Point pt = _focused_window->GetCaretPosition(); cf.ptCurrentPos.x = _focused_window->left + pt.x; cf.ptCurrentPos.y = _focused_window->top + pt.y; if (_focused_window->window_class == WC_CONSOLE) { cf.rcArea.left = _focused_window->left; cf.rcArea.top = _focused_window->top; cf.rcArea.right = _focused_window->left + _focused_window->width; cf.rcArea.bottom = _focused_window->top + _focused_window->height; } else { cf.rcArea.left = _focused_window->left + _focused_window->nested_focus->pos_x; cf.rcArea.top = _focused_window->top + _focused_window->nested_focus->pos_y; cf.rcArea.right = cf.rcArea.left + _focused_window->nested_focus->current_x; cf.rcArea.bottom = cf.rcArea.top + _focused_window->nested_focus->current_y; } } else { cf.ptCurrentPos.x = 0; cf.ptCurrentPos.y = 0; SetRectEmpty(&cf.rcArea); } ImmSetCandidateWindow(hIMC, &cf); } ImmReleaseContext(hwnd, hIMC); } /** Handle WM_IME_COMPOSITION messages. */ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) { HIMC hIMC = ImmGetContext(hwnd); if (hIMC != NULL) { if (lParam & GCS_RESULTSTR) { /* Read result string from the IME. */ LONG len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, NULL, 0); // Length is always in bytes, even in UNICODE build. TCHAR *str = (TCHAR *)_alloca(len + sizeof(TCHAR)); len = ImmGetCompositionString(hIMC, GCS_RESULTSTR, str, len); str[len / sizeof(TCHAR)] = '\0'; /* Transmit text to windowing system. */ if (len > 0) { HandleTextInput(NULL, true); // Clear marked string. HandleTextInput(FS2OTTD(str)); } SetCompositionPos(hwnd); /* Don't pass the result string on to the default window proc. */ lParam &= ~(GCS_RESULTSTR | GCS_RESULTCLAUSE | GCS_RESULTREADCLAUSE | GCS_RESULTREADSTR); } if ((lParam & GCS_COMPSTR) && DrawIMECompositionString()) { /* Read composition string from the IME. */ LONG len = ImmGetCompositionString(hIMC, GCS_COMPSTR, NULL, 0); // Length is always in bytes, even in UNICODE build. TCHAR *str = (TCHAR *)_alloca(len + sizeof(TCHAR)); len = ImmGetCompositionString(hIMC, GCS_COMPSTR, str, len); str[len / sizeof(TCHAR)] = '\0'; if (len > 0) { static char utf8_buf[1024]; convert_from_fs(str, utf8_buf, lengthof(utf8_buf)); /* Convert caret position from bytes in the input string to a position in the UTF-8 encoded string. */ LONG caret_bytes = ImmGetCompositionString(hIMC, GCS_CURSORPOS, NULL, 0); const char *caret = utf8_buf; for (const TCHAR *c = str; *c != '\0' && *caret != '\0' && caret_bytes > 0; c++, caret_bytes--) { /* Skip DBCS lead bytes or leading surrogates. */ #ifdef UNICODE if (Utf16IsLeadSurrogate(*c)) { #else if (IsDBCSLeadByte(*c)) { #endif c++; caret_bytes--; } Utf8Consume(&caret); } HandleTextInput(utf8_buf, true, caret); } else { HandleTextInput(NULL, true); } lParam &= ~(GCS_COMPSTR | GCS_COMPATTR | GCS_COMPCLAUSE | GCS_CURSORPOS | GCS_DELTASTART); } } ImmReleaseContext(hwnd, hIMC); return lParam != 0 ? DefWindowProc(hwnd, WM_IME_COMPOSITION, wParam, lParam) : 0; } /** Clear the current composition string. */ static void CancelIMEComposition(HWND hwnd) { HIMC hIMC = ImmGetContext(hwnd); if (hIMC != NULL) ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_CANCEL, 0); ImmReleaseContext(hwnd, hIMC); /* Clear any marked string from the current edit box. */ HandleTextInput(NULL, true); } #else static bool DrawIMECompositionString() { return false; } static void SetCompositionPos(HWND hwnd) {} static void SetCandidatePos(HWND hwnd) {} static void CancelIMEComposition(HWND hwnd) {} #endif /* !defined(WINCE) || _WIN32_WCE >= 0x400 */ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static uint32 keycode = 0; static bool console = false; static bool in_sizemove = false; switch (msg) { case WM_CREATE: SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc); SetCompositionPos(hwnd); #if !defined(WINCE) || _WIN32_WCE >= 0x400 _imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY); #endif break; case WM_ENTERSIZEMOVE: in_sizemove = true; break; case WM_EXITSIZEMOVE: in_sizemove = false; break; case WM_PAINT: if (!in_sizemove && _draw_mutex != NULL && !HasModalProgress()) { /* Get the union of the old update rect and the new update rect. */ RECT r; GetUpdateRect(hwnd, &r, FALSE); UnionRect(&_wnd.update_rect, &_wnd.update_rect, &r); /* Mark the window as updated, otherwise Windows would send more WM_PAINT messages. */ ValidateRect(hwnd, NULL); _draw_mutex->SendSignal(); } else { PAINTSTRUCT ps; BeginPaint(hwnd, &ps); PaintWindow(ps.hdc); EndPaint(hwnd, &ps); } return 0; case WM_PALETTECHANGED: if ((HWND)wParam == hwnd) return 0; /* FALL THROUGH */ case WM_QUERYNEWPALETTE: { HDC hDC = GetWindowDC(hwnd); HPALETTE hOldPalette = SelectPalette(hDC, _wnd.gdi_palette, FALSE); UINT nChanged = RealizePalette(hDC); SelectPalette(hDC, hOldPalette, TRUE); ReleaseDC(hwnd, hDC); if (nChanged != 0) InvalidateRect(hwnd, NULL, FALSE); return 0; } case WM_CLOSE: HandleExitGameRequest(); return 0; case WM_DESTROY: if (_window_maximize) _cur_resolution = _bck_resolution; return 0; case WM_LBUTTONDOWN: SetCapture(hwnd); _left_button_down = true; HandleMouseEvents(); return 0; case WM_LBUTTONUP: ReleaseCapture(); _left_button_down = false; _left_button_clicked = false; HandleMouseEvents(); return 0; case WM_RBUTTONDOWN: SetCapture(hwnd); _right_button_down = true; _right_button_clicked = true; HandleMouseEvents(); return 0; case WM_RBUTTONUP: ReleaseCapture(); _right_button_down = false; HandleMouseEvents(); return 0; case WM_MOUSELEAVE: UndrawMouseCursor(); _cursor.in_window = false; if (!_left_button_down && !_right_button_down) MyShowCursor(true); return 0; case WM_MOUSEMOVE: { int x = (int16)LOWORD(lParam); int y = (int16)HIWORD(lParam); POINT pt; /* If the mouse was not in the window and it has moved it means it has * come into the window, so start drawing the mouse. Also start * tracking the mouse for exiting the window */ if (!_cursor.in_window) { _cursor.in_window = true; SetTimer(hwnd, TID_POLLMOUSE, MOUSE_POLL_DELAY, (TIMERPROC)TrackMouseTimerProc); } if (_cursor.UpdateCursorPosition(x, y, true)) { pt.x = _cursor.pos.x; pt.y = _cursor.pos.y; ClientToScreen(hwnd, &pt); SetCursorPos(pt.x, pt.y); } MyShowCursor(false); HandleMouseEvents(); return 0; } #if !defined(WINCE) || _WIN32_WCE >= 0x400 case WM_INPUTLANGCHANGE: _imm_props = ImmGetProperty(GetKeyboardLayout(0), IGP_PROPERTY); break; case WM_IME_SETCONTEXT: /* Don't show the composition window if we draw the string ourself. */ if (DrawIMECompositionString()) lParam &= ~ISC_SHOWUICOMPOSITIONWINDOW; break; case WM_IME_STARTCOMPOSITION: SetCompositionPos(hwnd); if (DrawIMECompositionString()) return 0; break; case WM_IME_COMPOSITION: return HandleIMEComposition(hwnd, wParam, lParam); case WM_IME_ENDCOMPOSITION: /* Clear any pending composition string. */ HandleTextInput(NULL, true); if (DrawIMECompositionString()) return 0; break; case WM_IME_NOTIFY: if (wParam == IMN_OPENCANDIDATE) SetCandidatePos(hwnd); break; #if !defined(UNICODE) case WM_IME_CHAR: if (GB(wParam, 8, 8) != 0) { /* DBCS character, send lead byte first. */ HandleCharMsg(0, GB(wParam, 8, 8)); } HandleCharMsg(0, GB(wParam, 0, 8)); return 0; #endif #endif case WM_DEADCHAR: console = GB(lParam, 16, 8) == 41; return 0; case WM_CHAR: { uint scancode = GB(lParam, 16, 8); uint charcode = wParam; /* If the console key is a dead-key, we need to press it twice to get a WM_CHAR message. * But we then get two WM_CHAR messages, so ignore the first one */ if (console && scancode == 41) { console = false; return 0; } /* IMEs and other input methods sometimes send a WM_CHAR without a WM_KEYDOWN, * clear the keycode so a previous WM_KEYDOWN doesn't become 'stuck'. */ uint cur_keycode = keycode; keycode = 0; return HandleCharMsg(cur_keycode, charcode); } case WM_KEYDOWN: { /* No matter the keyboard layout, we will map the '~' to the console. */ uint scancode = GB(lParam, 16, 8); keycode = scancode == 41 ? (uint)WKC_BACKQUOTE : MapWindowsKey(wParam); /* Silently drop all messages handled by WM_CHAR. */ MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { if ((msg.message == WM_CHAR || msg.message == WM_DEADCHAR) && GB(lParam, 16, 8) == GB(msg.lParam, 16, 8)) { return 0; } } uint charcode = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR); /* No character translation? */ if (charcode == 0) { HandleKeypress(keycode, 0); return 0; } /* Is the console key a dead key? If yes, ignore the first key down event. */ if (HasBit(charcode, 31) && !console) { if (scancode == 41) { console = true; return 0; } } console = false; /* IMEs and other input methods sometimes send a WM_CHAR without a WM_KEYDOWN, * clear the keycode so a previous WM_KEYDOWN doesn't become 'stuck'. */ uint cur_keycode = keycode; keycode = 0; return HandleCharMsg(cur_keycode, LOWORD(charcode)); } case WM_SYSKEYDOWN: // user presses F10 or Alt, both activating the title-menu switch (wParam) { case VK_RETURN: case 'F': // Full Screen on ALT + ENTER/F ToggleFullScreen(!_wnd.fullscreen); return 0; case VK_MENU: // Just ALT return 0; // do nothing case VK_F10: // F10, ignore activation of menu HandleKeypress(MapWindowsKey(wParam), 0); return 0; default: // ALT in combination with something else HandleKeypress(MapWindowsKey(wParam), 0); break; } break; case WM_SIZE: if (wParam != SIZE_MINIMIZED) { /* Set maximized flag when we maximize (obviously), but also when we * switched to fullscreen from a maximized state */ _window_maximize = (wParam == SIZE_MAXIMIZED || (_window_maximize && _fullscreen)); if (_window_maximize || _fullscreen) _bck_resolution = _cur_resolution; ClientSizeChanged(LOWORD(lParam), HIWORD(lParam)); } return 0; #if !defined(WINCE) case WM_SIZING: { RECT *r = (RECT*)lParam; RECT r2; int w, h; SetRect(&r2, 0, 0, 0, 0); AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE); w = r->right - r->left - (r2.right - r2.left); h = r->bottom - r->top - (r2.bottom - r2.top); w = max(w, 64); h = max(h, 64); SetRect(&r2, 0, 0, w, h); AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE); w = r2.right - r2.left; h = r2.bottom - r2.top; switch (wParam) { case WMSZ_BOTTOM: r->bottom = r->top + h; break; case WMSZ_BOTTOMLEFT: r->bottom = r->top + h; r->left = r->right - w; break; case WMSZ_BOTTOMRIGHT: r->bottom = r->top + h; r->right = r->left + w; break; case WMSZ_LEFT: r->left = r->right - w; break; case WMSZ_RIGHT: r->right = r->left + w; break; case WMSZ_TOP: r->top = r->bottom - h; break; case WMSZ_TOPLEFT: r->top = r->bottom - h; r->left = r->right - w; break; case WMSZ_TOPRIGHT: r->top = r->bottom - h; r->right = r->left + w; break; } return TRUE; } #endif /* needed for wheel */ #if !defined(WM_MOUSEWHEEL) # define WM_MOUSEWHEEL 0x020A #endif /* WM_MOUSEWHEEL */ #if !defined(GET_WHEEL_DELTA_WPARAM) # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam)) #endif /* GET_WHEEL_DELTA_WPARAM */ case WM_MOUSEWHEEL: { int delta = GET_WHEEL_DELTA_WPARAM(wParam); if (delta < 0) { _cursor.wheel++; } else if (delta > 0) { _cursor.wheel--; } HandleMouseEvents(); return 0; } case WM_SETFOCUS: _wnd.has_focus = true; SetCompositionPos(hwnd); break; case WM_KILLFOCUS: _wnd.has_focus = false; break; #if !defined(WINCE) case WM_ACTIVATE: { /* Don't do anything if we are closing openttd */ if (_exit_game) break; bool active = (LOWORD(wParam) != WA_INACTIVE); bool minimized = (HIWORD(wParam) != 0); if (_wnd.fullscreen) { if (active && minimized) { /* Restore the game window */ ShowWindow(hwnd, SW_RESTORE); static_cast(VideoDriver::GetInstance())->MakeWindow(true); } else if (!active && !minimized) { /* Minimise the window and restore desktop */ ShowWindow(hwnd, SW_MINIMIZE); ChangeDisplaySettings(NULL, 0); } } break; } #endif } return DefWindowProc(hwnd, msg, wParam, lParam); } static void RegisterWndClass() { static bool registered = false; if (!registered) { HINSTANCE hinst = GetModuleHandle(NULL); WNDCLASS wnd = { CS_OWNDC, WndProcGdi, 0, 0, hinst, LoadIcon(hinst, MAKEINTRESOURCE(100)), LoadCursor(NULL, IDC_ARROW), 0, 0, _T("OTTD") }; registered = true; if (!RegisterClass(&wnd)) usererror("RegisterClass failed"); } } static bool AllocateDibSection(int w, int h, bool force) { BITMAPINFO *bi; HDC dc; uint bpp = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); w = max(w, 64); h = max(h, 64); if (bpp == 0) usererror("Can't use a blitter that blits 0 bpp for normal visuals"); if (!force && w == _screen.width && h == _screen.height) return false; bi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256); bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi->bmiHeader.biWidth = _wnd.width = w; bi->bmiHeader.biHeight = -(_wnd.height = h); bi->bmiHeader.biPlanes = 1; bi->bmiHeader.biBitCount = BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); bi->bmiHeader.biCompression = BI_RGB; if (_wnd.dib_sect) DeleteObject(_wnd.dib_sect); dc = GetDC(0); _wnd.dib_sect = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (VOID**)&_wnd.buffer_bits, NULL, 0); if (_wnd.dib_sect == NULL) usererror("CreateDIBSection failed"); ReleaseDC(0, dc); _screen.width = w; _screen.pitch = (bpp == 8) ? Align(w, 4) : w; _screen.height = h; _screen.dst_ptr = _wnd.buffer_bits; return true; } static const Dimension default_resolutions[] = { { 640, 480 }, { 800, 600 }, { 1024, 768 }, { 1152, 864 }, { 1280, 800 }, { 1280, 960 }, { 1280, 1024 }, { 1400, 1050 }, { 1600, 1200 }, { 1680, 1050 }, { 1920, 1200 } }; static void FindResolutions() { uint n = 0; #if defined(WINCE) /* EnumDisplaySettingsW is only supported in CE 4.2+ * XXX -- One might argue that we assume 4.2+ on every system. Then we can use this function safely */ #else uint i; DEVMODEA dm; /* Check modes for the relevant fullscreen bpp */ uint bpp = _support8bpp != S8BPP_HARDWARE ? 32 : BlitterFactory::GetCurrentBlitter()->GetScreenDepth(); /* XXX - EnumDisplaySettingsW crashes with unicows.dll on Windows95 * Doesn't really matter since we don't pass a string anyways, but still * a letdown */ for (i = 0; EnumDisplaySettingsA(NULL, i, &dm) != 0; i++) { if (dm.dmBitsPerPel == bpp && dm.dmPelsWidth >= 640 && dm.dmPelsHeight >= 480) { uint j; for (j = 0; j < n; j++) { if (_resolutions[j].width == dm.dmPelsWidth && _resolutions[j].height == dm.dmPelsHeight) break; } /* In the previous loop we have checked already existing/added resolutions if * they are the same as the new ones. If this is not the case (j == n); we have * looped all and found none, add the new one to the list. If we have reached the * maximum amount of resolutions, then quit querying the display */ if (j == n) { _resolutions[j].width = dm.dmPelsWidth; _resolutions[j].height = dm.dmPelsHeight; if (++n == lengthof(_resolutions)) break; } } } #endif /* We have found no resolutions, show the default list */ if (n == 0) { memcpy(_resolutions, default_resolutions, sizeof(default_resolutions)); n = lengthof(default_resolutions); } _num_resolutions = n; SortResolutions(_num_resolutions); } static FVideoDriver_Win32 iFVideoDriver_Win32; const char *VideoDriver_Win32::Start(const char * const *parm) { memset(&_wnd, 0, sizeof(_wnd)); RegisterWndClass(); MakePalette(); FindResolutions(); DEBUG(driver, 2, "Resolution for display: %ux%u", _cur_resolution.width, _cur_resolution.height); /* fullscreen uses those */ _wnd.width_org = _cur_resolution.width; _wnd.height_org = _cur_resolution.height; AllocateDibSection(_cur_resolution.width, _cur_resolution.height); this->MakeWindow(_fullscreen); MarkWholeScreenDirty(); _draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL && GetCPUCoreCount() > 1; return NULL; } void VideoDriver_Win32::Stop() { DeleteObject(_wnd.gdi_palette); DeleteObject(_wnd.dib_sect); DestroyWindow(_wnd.main_wnd); #if !defined(WINCE) if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0); #endif MyShowCursor(true); } void VideoDriver_Win32::MakeDirty(int left, int top, int width, int height) { RECT r = { left, top, left + width, top + height }; InvalidateRect(_wnd.main_wnd, &r, FALSE); } static void CheckPaletteAnim() { if (_cur_palette.count_dirty == 0) return; _local_palette = _cur_palette; InvalidateRect(_wnd.main_wnd, NULL, FALSE); } void VideoDriver_Win32::MainLoop() { MSG mesg; uint32 cur_ticks = GetTickCount(); uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* * directly in the newly created thread. */ _draw_mutex = ThreadMutex::New(); _draw_thread_initialized = CreateEvent(NULL, FALSE, FALSE, NULL); if (_draw_mutex == NULL || _draw_thread_initialized == NULL) { _draw_threaded = false; } else { _draw_continue = true; _draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { delete _draw_mutex; _draw_mutex = NULL; CloseHandle(_draw_thread_initialized); _draw_thread_initialized = NULL; } else { DEBUG(driver, 1, "Threaded drawing enabled"); /* Wait till the draw thread has started itself. */ WaitForSingleObject(_draw_thread_initialized, INFINITE); _draw_mutex->BeginCritical(); } } } _wnd.running = true; CheckPaletteAnim(); for (;;) { uint32 prev_cur_ticks = cur_ticks; // to check for wrapping while (PeekMessage(&mesg, NULL, 0, 0, PM_REMOVE)) { InteractiveRandom(); // randomness /* Convert key messages to char messages if we want text input. */ if (EditBoxInGlobalFocus()) TranslateMessage(&mesg); DispatchMessage(&mesg); } if (_exit_game) return; #if defined(_DEBUG) if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 && #else /* Speed up using TAB, but disable for ALT+TAB of course */ if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0 && GetAsyncKeyState(VK_MENU) >= 0 && #endif !_networking && _game_mode != GM_MENU) { _fast_forward |= 2; } else if (_fast_forward & 2) { _fast_forward = 0; } cur_ticks = GetTickCount(); if (cur_ticks >= next_tick || (_fast_forward && !_pause_mode) || cur_ticks < prev_cur_ticks) { _realtime_tick += cur_ticks - last_cur_ticks; last_cur_ticks = cur_ticks; next_tick = cur_ticks + MILLISECONDS_PER_TICK; bool old_ctrl_pressed = _ctrl_pressed; _ctrl_pressed = _wnd.has_focus && GetAsyncKeyState(VK_CONTROL)<0; _shift_pressed = _wnd.has_focus && GetAsyncKeyState(VK_SHIFT)<0; /* determine which directional keys are down */ if (_wnd.has_focus) { _dirkeys = (GetAsyncKeyState(VK_LEFT) < 0 ? 1 : 0) + (GetAsyncKeyState(VK_UP) < 0 ? 2 : 0) + (GetAsyncKeyState(VK_RIGHT) < 0 ? 4 : 0) + (GetAsyncKeyState(VK_DOWN) < 0 ? 8 : 0); } else { _dirkeys = 0; } if (old_ctrl_pressed != _ctrl_pressed) HandleCtrlChanged(); #if !defined(WINCE) /* Flush GDI buffer to ensure we don't conflict with the drawing thread. */ GdiFlush(); #endif /* The game loop is the part that can run asynchronously. * The rest except sleeping can't. */ if (_draw_threaded) _draw_mutex->EndCritical(); GameLoop(); if (_draw_threaded) _draw_mutex->BeginCritical(); if (_force_full_redraw) MarkWholeScreenDirty(); UpdateWindows(); CheckPaletteAnim(); } else { #if !defined(WINCE) /* Flush GDI buffer to ensure we don't conflict with the drawing thread. */ GdiFlush(); #endif /* Release the thread while sleeping */ if (_draw_threaded) _draw_mutex->EndCritical(); Sleep(1); if (_draw_threaded) _draw_mutex->BeginCritical(); NetworkDrawChatMessage(); DrawMouseCursor(); } } if (_draw_threaded) { _draw_continue = false; /* Sending signal if there is no thread blocked * is very valid and results in noop */ _draw_mutex->SendSignal(); _draw_mutex->EndCritical(); _draw_thread->Join(); CloseHandle(_draw_thread_initialized); delete _draw_mutex; delete _draw_thread; } } bool VideoDriver_Win32::ChangeResolution(int w, int h) { if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); if (_window_maximize) ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL); _wnd.width = _wnd.width_org = w; _wnd.height = _wnd.height_org = h; bool ret = this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } bool VideoDriver_Win32::ToggleFullscreen(bool full_screen) { if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); bool ret = this->MakeWindow(full_screen); if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } bool VideoDriver_Win32::AfterBlitterChange() { if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); bool ret = AllocateDibSection(_screen.width, _screen.height, true) && this->MakeWindow(_fullscreen); if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } void VideoDriver_Win32::EditBoxLostFocus() { if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); CancelIMEComposition(_wnd.main_wnd); SetCompositionPos(_wnd.main_wnd); SetCandidatePos(_wnd.main_wnd); if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); } openttd-1.5.3/src/dock_gui.cpp0000644000000000000000000005424112627373441014771 0ustar rootroot/* $Id: dock_gui.cpp 27163 2015-02-22 15:26:27Z frosch $ */ /* * 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 dock_gui.cpp GUI to create amazing water objects. */ #include "stdafx.h" #include "terraform_gui.h" #include "window_gui.h" #include "station_gui.h" #include "command_func.h" #include "water.h" #include "window_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "viewport_func.h" #include "gfx_func.h" #include "company_func.h" #include "slope_func.h" #include "tilehighlight_func.h" #include "company_base.h" #include "hotkeys.h" #include "gui.h" #include "zoom_func.h" #include "widgets/dock_widget.h" #include "table/sprites.h" #include "table/strings.h" #include "safeguards.h" static void ShowBuildDockStationPicker(Window *parent); static void ShowBuildDocksDepotPicker(Window *parent); static Axis _ship_depot_direction; void CcBuildDocks(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; if (_settings_client.sound.confirm) SndPlayTileFx(SND_02_SPLAT_WATER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } void CcBuildCanal(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_02_SPLAT_WATER, tile); } /** * Gets the other end of the aqueduct, if possible. * @param tile_from The begin tile for the aqueduct. * @param [out] tile_to The tile till where to show a selection for the aqueduct. * @return The other end of the aqueduct, or otherwise a tile in line with the aqueduct to cause the right error message. */ static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = NULL) { int z; DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile_from, &z)); /* If the direction isn't right, just return the next tile so the command * complains about the wrong slope instead of the ends not matching up. * Make sure the coordinate is always a valid tile within the map, so we * don't go "off" the map. That would cause the wrong error message. */ if (!IsValidDiagDirection(dir)) return TILE_ADDXY(tile_from, TileX(tile_from) > 2 ? -1 : 1, 0); /* Direction the aqueduct is built to. */ TileIndexDiff offset = TileOffsByDiagDir(ReverseDiagDir(dir)); /* The maximum length of the aqueduct. */ int max_length = min(_settings_game.construction.max_bridge_length, DistanceFromEdgeDir(tile_from, ReverseDiagDir(dir)) - 1); TileIndex endtile = tile_from; for (int length = 0; IsValidTile(endtile) && TileX(endtile) != 0 && TileY(endtile) != 0; length++) { endtile = TILE_ADD(endtile, offset); if (length > max_length) break; if (GetTileMaxZ(endtile) > z) { if (tile_to != NULL) *tile_to = endtile; break; } } return endtile; } /** Toolbar window for constructing water infrastructure. */ struct BuildDocksToolbarWindow : Window { DockToolbarWidgets last_clicked_widget; ///< Contains the last widget that has been clicked on this toolbar. BuildDocksToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->last_clicked_widget = WID_DT_INVALID; this->InitNested(window_number); this->OnInvalidateData(); if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); } ~BuildDocksToolbarWindow() { if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } /** * 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; bool can_build = CanBuildVehicleInfrastructure(VEH_SHIP); this->SetWidgetsDisabledState(!can_build, WID_DT_DEPOT, WID_DT_STATION, WID_DT_BUOY, WIDGET_LIST_END); if (!can_build) { DeleteWindowById(WC_BUILD_STATION, TRANSPORT_WATER); DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_WATER); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_DT_CANAL: // Build canal button HandlePlacePushButton(this, WID_DT_CANAL, SPR_CURSOR_CANAL, HT_RECT); break; case WID_DT_LOCK: // Build lock button HandlePlacePushButton(this, WID_DT_LOCK, SPR_CURSOR_LOCK, HT_SPECIAL); break; case WID_DT_DEMOLISH: // Demolish aka dynamite button HandlePlacePushButton(this, WID_DT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); break; case WID_DT_DEPOT: // Build depot button if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; if (HandlePlacePushButton(this, WID_DT_DEPOT, SPR_CURSOR_SHIP_DEPOT, HT_RECT)) ShowBuildDocksDepotPicker(this); break; case WID_DT_STATION: // Build station button if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; if (HandlePlacePushButton(this, WID_DT_STATION, SPR_CURSOR_DOCK, HT_SPECIAL)) ShowBuildDockStationPicker(this); break; case WID_DT_BUOY: // Build buoy button if (!CanBuildVehicleInfrastructure(VEH_SHIP)) return; HandlePlacePushButton(this, WID_DT_BUOY, SPR_CURSOR_BUOY, HT_RECT); break; case WID_DT_RIVER: // Build river button (in scenario editor) if (_game_mode != GM_EDITOR) return; HandlePlacePushButton(this, WID_DT_RIVER, SPR_CURSOR_RIVER, HT_RECT); break; case WID_DT_BUILD_AQUEDUCT: // Build aqueduct button HandlePlacePushButton(this, WID_DT_BUILD_AQUEDUCT, SPR_CURSOR_AQUEDUCT, HT_SPECIAL); break; default: return; } this->last_clicked_widget = (DockToolbarWidgets)widget; } virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_clicked_widget) { case WID_DT_CANAL: // Build canal button VpStartPlaceSizing(tile, (_game_mode == GM_EDITOR) ? VPM_X_AND_Y : VPM_X_OR_Y, DDSP_CREATE_WATER); break; case WID_DT_LOCK: // Build lock button DoCommandP(tile, 0, 0, CMD_BUILD_LOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_LOCKS), CcBuildDocks); break; case WID_DT_DEMOLISH: // Demolish aka dynamite button PlaceProc_DemolishArea(tile); break; case WID_DT_DEPOT: // Build depot button DoCommandP(tile, _ship_depot_direction, 0, CMD_BUILD_SHIP_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_SHIP_DEPOT), CcBuildDocks); break; case WID_DT_STATION: { // Build station button uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join /* tile is always the land tile, so need to evaluate _thd.pos */ CommandContainer cmdcont = { tile, _ctrl_pressed, p2, CMD_BUILD_DOCK | CMD_MSG(STR_ERROR_CAN_T_BUILD_DOCK_HERE), CcBuildDocks, "" }; /* Determine the watery part of the dock. */ DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile)); TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile, ReverseDiagDir(dir)) : tile); ShowSelectStationIfNeeded(cmdcont, TileArea(tile, tile_to)); break; } case WID_DT_BUOY: // Build buoy button DoCommandP(tile, 0, 0, CMD_BUILD_BUOY | CMD_MSG(STR_ERROR_CAN_T_POSITION_BUOY_HERE), CcBuildDocks); break; case WID_DT_RIVER: // Build river button (in scenario editor) VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CREATE_RIVER); break; case WID_DT_BUILD_AQUEDUCT: // Build aqueduct button DoCommandP(tile, GetOtherAqueductEnd(tile), TRANSPORT_WATER << 15, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE), CcBuildBridge); break; default: NOT_REACHED(); } } 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_DEMOLISH_AREA: GUIPlaceProcDragXY(select_proc, start_tile, end_tile); break; case DDSP_CREATE_WATER: DoCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcBuildCanal); break; case DDSP_CREATE_RIVER: DoCommandP(end_tile, start_tile, WATER_CLASS_RIVER, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcBuildCanal); break; default: break; } } } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); DeleteWindowById(WC_BUILD_STATION, TRANSPORT_WATER); DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_WATER); DeleteWindowById(WC_SELECT_STATION, 0); DeleteWindowByClass(WC_BUILD_BRIDGE); } virtual void OnPlacePresize(Point pt, TileIndex tile_from) { TileIndex tile_to = tile_from; if (this->last_clicked_widget == WID_DT_BUILD_AQUEDUCT) { GetOtherAqueductEnd(tile_from, &tile_to); } else { DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile_from)); if (IsValidDiagDirection(dir)) { /* Locks and docks always select the tile "down" the slope. */ tile_to = TileAddByDiagDir(tile_from, ReverseDiagDir(dir)); /* Locks also select the tile "up" the slope. */ if (this->last_clicked_widget == WID_DT_LOCK) tile_from = TileAddByDiagDir(tile_from, dir); } } VpSetPresizeRange(tile_from, tile_to); } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the BuildDocksToolbarWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState DockToolbarGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; Window *w = ShowBuildDocksToolbar(); if (w == NULL) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } const uint16 _dockstoolbar_aqueduct_keys[] = {'B', '8', 0}; static Hotkey dockstoolbar_hotkeys[] = { Hotkey('1', "canal", WID_DT_CANAL), Hotkey('2', "lock", WID_DT_LOCK), Hotkey('3', "demolish", WID_DT_DEMOLISH), Hotkey('4', "depot", WID_DT_DEPOT), Hotkey('5', "dock", WID_DT_STATION), Hotkey('6', "buoy", WID_DT_BUOY), Hotkey('7', "river", WID_DT_RIVER), Hotkey(_dockstoolbar_aqueduct_keys, "aqueduct", WID_DT_BUILD_AQUEDUCT), HOTKEY_LIST_END }; HotkeyList BuildDocksToolbarWindow::hotkeys("dockstoolbar", dockstoolbar_hotkeys, DockToolbarGlobalHotkeys); /** * Nested widget parts of docks toolbar, game version. * Position of #WID_DT_RIVER widget has changed. */ static const NWidgetPart _nested_build_docks_toolbar_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WATERWAYS_TOOLBAR_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL_LTR), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_CANAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BUILD_CANAL, STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_LOCK), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BUILD_LOCK, STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(5, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_DEMOLISH), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_DEPOT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIP_DEPOT, STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_STATION), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIP_DOCK, STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_BUOY), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BUOY, STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_BUILD_AQUEDUCT), SetMinimalSize(23, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AQUEDUCT, STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP), EndContainer(), }; static WindowDesc _build_docks_toolbar_desc( WDP_ALIGN_TOOLBAR, "toolbar_water", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_docks_toolbar_widgets, lengthof(_nested_build_docks_toolbar_widgets), &BuildDocksToolbarWindow::hotkeys ); /** * Open the build water toolbar window * * If the terraform toolbar is linked to the toolbar, that window is also opened. * * @return newly opened water toolbar, or NULL if the toolbar could not be opened. */ Window *ShowBuildDocksToolbar() { if (!Company::IsValidID(_local_company)) return NULL; DeleteWindowByClass(WC_BUILD_TOOLBAR); return AllocateWindowDescFront(&_build_docks_toolbar_desc, TRANSPORT_WATER); } /** * Nested widget parts of docks toolbar, scenario editor version. * Positions of #WID_DT_DEPOT, #WID_DT_STATION, and #WID_DT_BUOY widgets have changed. */ static const NWidgetPart _nested_build_docks_scen_toolbar_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WATERWAYS_TOOLBAR_CAPTION_SE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_CANAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BUILD_CANAL, STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_LOCK), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BUILD_LOCK, STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(5, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_DEMOLISH), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_RIVER), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_BUILD_RIVER, STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_DT_BUILD_AQUEDUCT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AQUEDUCT, STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP), EndContainer(), }; /** Window definition for the build docks in scenario editor window. */ static WindowDesc _build_docks_scen_toolbar_desc( WDP_AUTO, "toolbar_water_scen", 0, 0, WC_SCEN_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_build_docks_scen_toolbar_widgets, lengthof(_nested_build_docks_scen_toolbar_widgets) ); /** * Open the build water toolbar window for the scenario editor. * * @return newly opened water toolbar, or NULL if the toolbar could not be opened. */ Window *ShowBuildDocksScenToolbar() { return AllocateWindowDescFront(&_build_docks_scen_toolbar_desc, TRANSPORT_WATER); } /** Widget numbers of the build-dock GUI. */ enum BuildDockStationWidgets { BDSW_BACKGROUND, ///< Background panel. BDSW_LT_OFF, ///< 'Off' button of coverage high light. BDSW_LT_ON, ///< 'On' button of coverage high light. BDSW_INFO, ///< 'Coverage highlight' label. }; struct BuildDocksStationWindow : public PickerWindowBase { public: BuildDocksStationWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->InitNested(TRANSPORT_WATER); this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF); } virtual ~BuildDocksStationWindow() { DeleteWindowById(WC_SELECT_STATION, 0); } virtual void OnPaint() { int rad = (_settings_game.station.modified_catchment) ? CA_DOCK : CA_UNMODIFIED; this->DrawWidgets(); if (_settings_client.gui.station_show_coverage) { SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); } else { SetTileSelectSize(1, 1); } /* strings such as 'Size' and 'Coverage Area' */ int top = this->GetWidget(BDSW_LT_OFF)->pos_y + this->GetWidget(BDSW_LT_OFF)->current_y + WD_PAR_VSEP_NORMAL; NWidgetBase *back_nwi = this->GetWidget(BDSW_BACKGROUND); int right = back_nwi->pos_x + back_nwi->current_x; int bottom = back_nwi->pos_y + back_nwi->current_y; top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; /* Resize background if the window is too small. * Never make the window smaller to avoid oscillating if the size change affects the acceptance. * (This is the case, if making the window bigger moves the mouse into the window.) */ if (top > bottom) { ResizeWindow(this, 0, top - bottom); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case BDSW_LT_OFF: case BDSW_LT_ON: this->RaiseWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF); _settings_client.gui.station_show_coverage = (widget != BDSW_LT_OFF); this->LowerWidget(_settings_client.gui.station_show_coverage + BDSW_LT_OFF); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->SetDirty(); break; } } virtual void OnTick() { CheckRedrawStationCoverage(this); } }; /** Nested widget parts of a build dock station window. */ static const NWidgetPart _nested_build_dock_station_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_DOCK_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BDSW_BACKGROUND), NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, BDSW_INFO), SetMinimalSize(148, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), NWidget(NWID_HORIZONTAL), SetPIP(14, 0, 14), NWidget(WWT_TEXTBTN, COLOUR_GREY, BDSW_LT_OFF), SetMinimalSize(40, 12), SetFill(1, 0), SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, BDSW_LT_ON), SetMinimalSize(40, 12), SetFill(1, 0), SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 20), SetResize(0, 1), EndContainer(), }; static WindowDesc _build_dock_station_desc( WDP_AUTO, NULL, 0, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_dock_station_widgets, lengthof(_nested_build_dock_station_widgets) ); static void ShowBuildDockStationPicker(Window *parent) { new BuildDocksStationWindow(&_build_dock_station_desc, parent); } struct BuildDocksDepotWindow : public PickerWindowBase { private: static void UpdateDocksDirection() { if (_ship_depot_direction != AXIS_X) { SetTileSelectSize(1, 2); } else { SetTileSelectSize(2, 1); } } public: BuildDocksDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->InitNested(TRANSPORT_WATER); this->LowerWidget(_ship_depot_direction + WID_BDD_X); UpdateDocksDirection(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_BDD_X: case WID_BDD_Y: size->width = ScaleGUITrad(96) + 2; size->height = ScaleGUITrad(64) + 2; break; } } virtual void OnPaint() { this->DrawWidgets(); int x1 = ScaleGUITrad(63) + 1; int x2 = ScaleGUITrad(31) + 1; int y1 = ScaleGUITrad(17) + 1; int y2 = ScaleGUITrad(33) + 1; DrawShipDepotSprite(this->GetWidget(WID_BDD_X)->pos_x + x1, this->GetWidget(WID_BDD_X)->pos_y + y1, AXIS_X, DEPOT_PART_NORTH); DrawShipDepotSprite(this->GetWidget(WID_BDD_X)->pos_x + x2, this->GetWidget(WID_BDD_X)->pos_y + y2, AXIS_X, DEPOT_PART_SOUTH); DrawShipDepotSprite(this->GetWidget(WID_BDD_Y)->pos_x + x2, this->GetWidget(WID_BDD_Y)->pos_y + y1, AXIS_Y, DEPOT_PART_NORTH); DrawShipDepotSprite(this->GetWidget(WID_BDD_Y)->pos_x + x1, this->GetWidget(WID_BDD_Y)->pos_y + y2, AXIS_Y, DEPOT_PART_SOUTH); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BDD_X: case WID_BDD_Y: this->RaiseWidget(_ship_depot_direction + WID_BDD_X); _ship_depot_direction = (widget == WID_BDD_X ? AXIS_X : AXIS_Y); this->LowerWidget(_ship_depot_direction + WID_BDD_X); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); UpdateDocksDirection(); this->SetDirty(); break; } } }; static const NWidgetPart _nested_build_docks_depot_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_DEPOT_BUILD_SHIP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BDD_BACKGROUND), NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(NWID_HORIZONTAL_LTR), NWidget(NWID_SPACER), SetMinimalSize(3, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_X), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BDD_Y), SetMinimalSize(98, 66), SetDataTip(0x0, STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), EndContainer(), }; static WindowDesc _build_docks_depot_desc( WDP_AUTO, NULL, 0, 0, WC_BUILD_DEPOT, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_docks_depot_widgets, lengthof(_nested_build_docks_depot_widgets) ); static void ShowBuildDocksDepotPicker(Window *parent) { new BuildDocksDepotWindow(&_build_docks_depot_desc, parent); } void InitializeDockGui() { _ship_depot_direction = AXIS_X; } openttd-1.5.3/src/vehiclelist.h0000644000000000000000000000431312627373435015163 0ustar rootroot/* $Id: vehiclelist.h 27013 2014-10-14 11:23:41Z rubidium $ */ /* * 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 vehiclelist.h Functions and type for generating vehicle lists. */ #ifndef VEHICLELIST_H #define VEHICLELIST_H #include "core/smallvec_type.hpp" #include "vehicle_type.h" #include "company_type.h" #include "tile_type.h" /** Vehicle List type flags */ enum VehicleListType { VL_STANDARD, VL_SHARED_ORDERS, VL_STATION_LIST, VL_DEPOT_LIST, VL_GROUP_LIST, VLT_END }; /** The information about a vehicle list. */ struct VehicleListIdentifier { VehicleListType type; ///< The type of vehicle list. VehicleType vtype; ///< The vehicle type associated with this list. CompanyID company; ///< The company associated with this list. uint32 index; ///< A vehicle list type specific index. uint32 Pack() const; bool Unpack(uint32 data); /** * Create a simple vehicle list. * @param type List type. * @param vtype Vehicle type associated with this list. * @param company Company associated with this list. * @param index Optional type specific index. */ VehicleListIdentifier(VehicleListType type, VehicleType vtype, CompanyID company, uint index = 0) : type(type), vtype(vtype), company(company), index(index) {} VehicleListIdentifier(uint32 data = 0); }; /** A list of vehicles. */ typedef SmallVector VehicleList; bool GenerateVehicleSortList(VehicleList *list, const VehicleListIdentifier &identifier); void BuildDepotVehicleList(VehicleType type, TileIndex tile, VehicleList *engine_list, VehicleList *wagon_list, bool individual_wagons = false); uint GetUnitNumberDigits(VehicleList &vehicles); #endif /* VEHICLELIST_H */ openttd-1.5.3/src/genworld_gui.cpp0000644000000000000000000017006612627373441015676 0ustar rootroot/* $Id: genworld_gui.cpp 27140 2015-02-08 21:05:48Z alberth $ */ /* * 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 genworld_gui.cpp GUI to configure and show progress during map generation. */ #include "stdafx.h" #include "heightmap.h" #include "debug.h" #include "genworld.h" #include "network/network.h" #include "strings_func.h" #include "window_func.h" #include "date_func.h" #include "sound_func.h" #include "fios.h" #include "string_func.h" #include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" #include "querystring_gui.h" #include "town.h" #include "core/geometry_func.hpp" #include "core/random_func.hpp" #include "progress.h" #include "error.h" #include "widgets/genworld_widget.h" #include "safeguards.h" extern void MakeNewgameSettingsLive(); /** Enum for the modes we can generate in. */ enum GenerateLandscapeWindowMode { GLWM_GENERATE, ///< Generate new game. GLWM_HEIGHTMAP, ///< Load from heightmap. GLWM_SCENARIO, ///< Generate flat land. }; /** * Changes landscape type and sets genworld window dirty * @param landscape new landscape type */ void SetNewLandscapeType(byte landscape) { _settings_newgame.game_creation.landscape = landscape; InvalidateWindowClassesData(WC_SELECT_GAME); InvalidateWindowClassesData(WC_GENERATE_LANDSCAPE); } /** Widgets of GenerateLandscapeWindow when generating world */ static const NWidgetPart _nested_generate_landscape_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_MAPGEN_WORLD_GENERATION_CAPTION, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_SPACER), SetMinimalSize(0, 10), /* Landscape selection. */ NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TEMPERATE), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_ARCTIC), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TROPICAL), SetDataTip(SPR_SELECT_SUB_TROPICAL, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TOYLAND), SetDataTip(SPR_SELECT_TOYLAND, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 11), NWidget(NWID_HORIZONTAL), SetPIP(10, 5, 10), NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0), /* Left column with labels. */ NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_MAPSIZE, STR_MAPGEN_MAPSIZE_TOOLTIP), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_LAND_GENERATOR, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NUMBER_OF_TOWNS, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_TERRAIN_TYPE, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_VARIETY, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_QUANTITY_OF_SEA_LAKES, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_TREE_PLACER, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_BORDER_TYPE, STR_NULL), SetFill(1, 1), EndContainer(), /* Widgets at the right of the labels. */ NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), /* Mapsize X * Y. */ NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAPSIZE_X_PULLDOWN), SetDataTip(STR_JUST_INT, STR_MAPGEN_MAPSIZE_TOOLTIP), SetFill(1, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_BY, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAPSIZE_Y_PULLDOWN), SetDataTip(STR_JUST_INT, STR_MAPGEN_MAPSIZE_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_LANDSCAPE_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TOWN_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TERRAIN_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_VARIETY_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_WATER_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TREE_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_BORDERS_RANDOM), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_MAX_HEIGHTLEVEL, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_SNOW_LINE_HEIGHT, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_DATE, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_SMOOTHNESS, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS, STR_NULL), SetFill(1, 1), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), /* Max. heightlevel. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_MAX_HEIGHTLEVEL_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_MAX_HEIGHTLEVEL_TEXT), SetDataTip(STR_BLACK_INT, STR_NULL), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_MAX_HEIGHTLEVEL_UP), SetDataTip(SPR_ARROW_UP, STR_MAPGEN_MAX_HEIGHTLEVEL_UP), SetFill(0, 1), EndContainer(), /* Snow line. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_SNOW_LEVEL_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_MAPGEN_SNOW_LINE_DOWN), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_SNOW_LEVEL_TEXT), SetDataTip(STR_BLACK_INT, STR_NULL), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_SNOW_LEVEL_UP), SetDataTip(SPR_ARROW_UP, STR_MAPGEN_SNOW_LINE_UP), SetFill(0, 1), EndContainer(), /* Starting date. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_START_DATE_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), SetFill(0, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_GL_START_DATE_TEXT), SetDataTip(STR_BLACK_DATE_LONG, STR_NULL), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_START_DATE_UP), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), SetFill(0, 1), EndContainer(), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_INDUSTRY_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_SMOOTHNESS_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_RIVER_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_GL_GENERATE_BUTTON), SetMinimalSize(84, 0), SetDataTip(STR_MAPGEN_GENERATE, STR_NULL), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 4), /* Map borders buttons for each edge. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 0, 10), NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 3), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NORTHWEST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NW), SetDataTip(STR_JUST_STRING, STR_MAPGEN_NORTHWEST), SetFill(1, 1), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_NE), SetDataTip(STR_JUST_STRING, STR_MAPGEN_NORTHEAST), SetFill(1, 1), NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NORTHEAST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 0, 10), NWidget(NWID_HORIZONTAL), SetPIP(0, 0, 3), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_SOUTHWEST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SW), SetDataTip(STR_JUST_STRING, STR_MAPGEN_SOUTHWEST), SetFill(1, 1), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_WATER_SE), SetDataTip(STR_JUST_STRING, STR_MAPGEN_SOUTHEAST), SetFill(1, 1), NWidget(NWID_HORIZONTAL), SetPIP(3, 0, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_SOUTHEAST, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(0, 1), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 9), SetFill(1, 1), EndContainer(), }; /** Widgets of GenerateLandscapeWindow when loading heightmap */ static const NWidgetPart _nested_heightmap_load_widgets[] = { /* Window header. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_MAPGEN_WORLD_GENERATION_CAPTION, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_SPACER), SetMinimalSize(0, 10), /* Landscape selection. */ NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TEMPERATE), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_ARCTIC), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TROPICAL), SetDataTip(SPR_SELECT_SUB_TROPICAL, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_GL_TOYLAND), SetDataTip(SPR_SELECT_TOYLAND, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 11), SetFill(0, 1), NWidget(NWID_HORIZONTAL), SetPIP(10, 3, 10), /* Labels at the left side. */ NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_HEIGHTMAP_NAME, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_MAPSIZE, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_HEIGHTMAP_ROTATION, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NUMBER_OF_TOWNS, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_NUMBER_OF_INDUSTRIES, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_QUANTITY_OF_RIVERS, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_TREE_PLACER, STR_NULL), SetFill(1, 1), EndContainer(), /* Widgets at the right of the labels. */ NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), NWidget(WWT_EMPTY, COLOUR_ORANGE, WID_GL_HEIGHTMAP_NAME_TEXT), SetFill(1, 0), NWidget(NWID_HORIZONTAL), SetPIP(0, 5, 0), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), /* Mapsize X * Y. */ NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAPSIZE_X_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), SetFill(1, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_BY, STR_NULL), SetPadding(1, 0, 0, 0), SetFill(1, 1), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_MAPSIZE_Y_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), SetFill(1, 0), EndContainer(), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TOWN_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_INDUSTRY_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_RIVER_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_GL_TREE_PULLDOWN), SetDataTip(STR_JUST_STRING, STR_NULL), SetFill(1, 0), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_HEIGHTMAP_SIZE_LABEL, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_SNOW_LINE_HEIGHT, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_MAX_HEIGHTLEVEL, STR_NULL), SetFill(1, 1), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_DATE, STR_NULL), SetFill(1, 1), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 4, 0), NWidget(WWT_TEXT, COLOUR_ORANGE, WID_GL_HEIGHTMAP_SIZE_TEXT), SetDataTip(STR_MAPGEN_HEIGHTMAP_SIZE, STR_NULL), SetFill(1, 0), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_SNOW_LEVEL_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_MAPGEN_SNOW_LINE_DOWN), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_SNOW_LEVEL_TEXT), SetDataTip(STR_BLACK_INT, STR_NULL), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_SNOW_LEVEL_UP), SetDataTip(SPR_ARROW_UP, STR_MAPGEN_SNOW_LINE_UP), SetFill(0, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_MAX_HEIGHTLEVEL_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN), SetFill(0, 1), NWidget(WWT_TEXTBTN, COLOUR_ORANGE, WID_GL_MAX_HEIGHTLEVEL_TEXT), SetDataTip(STR_BLACK_INT, STR_NULL), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_MAX_HEIGHTLEVEL_UP), SetDataTip(SPR_ARROW_UP, STR_MAPGEN_MAX_HEIGHTLEVEL_UP), SetFill(0, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_START_DATE_DOWN), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), SetFill(0, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_GL_START_DATE_TEXT), SetDataTip(STR_BLACK_DATE_LONG, STR_NULL), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_GL_START_DATE_UP), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), SetFill(0, 1), EndContainer(), EndContainer(), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_GL_GENERATE_BUTTON), SetMinimalSize(84, 0), SetDataTip(STR_MAPGEN_GENERATE, STR_NULL), SetFill(1, 1), EndContainer(), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 9), SetFill(1, 1), EndContainer(), }; static void StartGeneratingLandscape(GenerateLandscapeWindowMode mode) { DeleteAllNonVitalWindows(); ClearErrorMessages(); /* Copy all XXX_newgame to XXX when coming from outside the editor */ MakeNewgameSettingsLive(); ResetGRFConfig(true); if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP); switch (mode) { case GLWM_GENERATE: _switch_mode = (_game_mode == GM_EDITOR) ? SM_GENRANDLAND : SM_NEWGAME; break; case GLWM_HEIGHTMAP: _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_HEIGHTMAP : SM_START_HEIGHTMAP; break; case GLWM_SCENARIO: _switch_mode = SM_EDITOR; break; default: NOT_REACHED(); } } static void LandscapeGenerationCallback(Window *w, bool confirmed) { if (confirmed) StartGeneratingLandscape((GenerateLandscapeWindowMode)w->window_number); } static DropDownList *BuildMapsizeDropDown() { DropDownList *list = new DropDownList(); for (uint i = MIN_MAP_SIZE_BITS; i <= MAX_MAP_SIZE_BITS; i++) { DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_JUST_INT, i, false); item->SetParam(0, 1 << i); *list->Append() = item; } return list; } static const StringID _elevations[] = {STR_TERRAIN_TYPE_VERY_FLAT, STR_TERRAIN_TYPE_FLAT, STR_TERRAIN_TYPE_HILLY, STR_TERRAIN_TYPE_MOUNTAINOUS, STR_TERRAIN_TYPE_ALPINIST, INVALID_STRING_ID}; static const StringID _sea_lakes[] = {STR_SEA_LEVEL_VERY_LOW, STR_SEA_LEVEL_LOW, STR_SEA_LEVEL_MEDIUM, STR_SEA_LEVEL_HIGH, STR_SEA_LEVEL_CUSTOM, INVALID_STRING_ID}; static const StringID _rivers[] = {STR_RIVERS_NONE, STR_RIVERS_FEW, STR_RIVERS_MODERATE, STR_RIVERS_LOT, INVALID_STRING_ID}; static const StringID _smoothness[] = {STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH, STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH, INVALID_STRING_ID}; static const StringID _tree_placer[] = {STR_CONFIG_SETTING_TREE_PLACER_NONE, STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL, STR_CONFIG_SETTING_TREE_PLACER_IMPROVED, INVALID_STRING_ID}; static const StringID _rotation[] = {STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE, STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE, INVALID_STRING_ID}; static const StringID _landscape[] = {STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL, STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS, INVALID_STRING_ID}; static const StringID _num_towns[] = {STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_NORMAL, STR_NUM_HIGH, STR_NUM_CUSTOM, INVALID_STRING_ID}; static const StringID _num_inds[] = {STR_FUNDING_ONLY, STR_MINIMAL, STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_NORMAL, STR_NUM_HIGH, INVALID_STRING_ID}; static const StringID _variety[] = {STR_VARIETY_NONE, STR_VARIETY_VERY_LOW, STR_VARIETY_LOW, STR_VARIETY_MEDIUM, STR_VARIETY_HIGH, STR_VARIETY_VERY_HIGH, INVALID_STRING_ID}; assert_compile(lengthof(_num_inds) == ID_END + 1); struct GenerateLandscapeWindow : public Window { uint widget_id; uint x; uint y; char name[64]; GenerateLandscapeWindowMode mode; GenerateLandscapeWindow(WindowDesc *desc, WindowNumber number = 0) : Window(desc) { this->InitNested(number); this->LowerWidget(_settings_newgame.game_creation.landscape + WID_GL_TEMPERATE); this->mode = (GenerateLandscapeWindowMode)this->window_number; /* Disable town, industry and trees in SE */ this->SetWidgetDisabledState(WID_GL_TOWN_PULLDOWN, _game_mode == GM_EDITOR); this->SetWidgetDisabledState(WID_GL_INDUSTRY_PULLDOWN, _game_mode == GM_EDITOR); this->SetWidgetDisabledState(WID_GL_TREE_PULLDOWN, _game_mode == GM_EDITOR); this->OnInvalidateData(); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_GL_START_DATE_TEXT: SetDParam(0, ConvertYMDToDate(_settings_newgame.game_creation.starting_year, 0, 1)); break; case WID_GL_MAPSIZE_X_PULLDOWN: SetDParam(0, 1 << _settings_newgame.game_creation.map_x); break; case WID_GL_MAPSIZE_Y_PULLDOWN: SetDParam(0, 1 << _settings_newgame.game_creation.map_y); break; case WID_GL_MAX_HEIGHTLEVEL_TEXT: SetDParam(0, _settings_newgame.construction.max_heightlevel); break; case WID_GL_SNOW_LEVEL_TEXT: SetDParam(0, _settings_newgame.game_creation.snow_line_height); break; case WID_GL_TOWN_PULLDOWN: if (_game_mode == GM_EDITOR) { SetDParam(0, STR_CONFIG_SETTING_OFF); } else if (_settings_newgame.difficulty.number_towns == CUSTOM_TOWN_NUMBER_DIFFICULTY) { SetDParam(0, STR_NUM_CUSTOM_NUMBER); SetDParam(1, _settings_newgame.game_creation.custom_town_number); } else { SetDParam(0, _num_towns[_settings_newgame.difficulty.number_towns]); } break; case WID_GL_INDUSTRY_PULLDOWN: SetDParam(0, _game_mode == GM_EDITOR ? STR_CONFIG_SETTING_OFF : _num_inds[_settings_newgame.difficulty.industry_density]); break; case WID_GL_LANDSCAPE_PULLDOWN: SetDParam(0, _landscape[_settings_newgame.game_creation.land_generator]); break; case WID_GL_TREE_PULLDOWN: SetDParam(0, _tree_placer[_settings_newgame.game_creation.tree_placer]); break; case WID_GL_TERRAIN_PULLDOWN: SetDParam(0, _elevations[_settings_newgame.difficulty.terrain_type]); break; case WID_GL_WATER_PULLDOWN: if (_settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { SetDParam(0, STR_SEA_LEVEL_CUSTOM_PERCENTAGE); SetDParam(1, _settings_newgame.game_creation.custom_sea_level); } else { SetDParam(0, _sea_lakes[_settings_newgame.difficulty.quantity_sea_lakes]); } break; case WID_GL_RIVER_PULLDOWN: SetDParam(0, _rivers[_settings_newgame.game_creation.amount_of_rivers]); break; case WID_GL_SMOOTHNESS_PULLDOWN: SetDParam(0, _smoothness[_settings_newgame.game_creation.tgen_smoothness]); break; case WID_GL_VARIETY_PULLDOWN: SetDParam(0, _variety[_settings_newgame.game_creation.variety]); break; case WID_GL_BORDERS_RANDOM: SetDParam(0, (_settings_newgame.game_creation.water_borders == BORDERS_RANDOM) ? STR_MAPGEN_BORDER_RANDOMIZE : STR_MAPGEN_BORDER_MANUAL); break; case WID_GL_WATER_NE: SetDParam(0, (_settings_newgame.game_creation.water_borders == BORDERS_RANDOM) ? STR_MAPGEN_BORDER_RANDOM : HasBit(_settings_newgame.game_creation.water_borders, BORDER_NE) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM); break; case WID_GL_WATER_NW: SetDParam(0, (_settings_newgame.game_creation.water_borders == BORDERS_RANDOM) ? STR_MAPGEN_BORDER_RANDOM : HasBit(_settings_newgame.game_creation.water_borders, BORDER_NW) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM); break; case WID_GL_WATER_SE: SetDParam(0, (_settings_newgame.game_creation.water_borders == BORDERS_RANDOM) ? STR_MAPGEN_BORDER_RANDOM : HasBit(_settings_newgame.game_creation.water_borders, BORDER_SE) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM); break; case WID_GL_WATER_SW: SetDParam(0, (_settings_newgame.game_creation.water_borders == BORDERS_RANDOM) ? STR_MAPGEN_BORDER_RANDOM : HasBit(_settings_newgame.game_creation.water_borders, BORDER_SW) ? STR_MAPGEN_BORDER_WATER : STR_MAPGEN_BORDER_FREEFORM); break; case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN: SetDParam(0, _rotation[_settings_newgame.game_creation.heightmap_rotation]); break; case WID_GL_HEIGHTMAP_SIZE_TEXT: if (_settings_newgame.game_creation.heightmap_rotation == HM_CLOCKWISE) { SetDParam(0, this->y); SetDParam(1, this->x); } else { SetDParam(0, this->x); SetDParam(1, this->y); } 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; /* Update the climate buttons */ this->SetWidgetLoweredState(WID_GL_TEMPERATE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); this->SetWidgetLoweredState(WID_GL_ARCTIC, _settings_newgame.game_creation.landscape == LT_ARCTIC); this->SetWidgetLoweredState(WID_GL_TROPICAL, _settings_newgame.game_creation.landscape == LT_TROPIC); this->SetWidgetLoweredState(WID_GL_TOYLAND, _settings_newgame.game_creation.landscape == LT_TOYLAND); /* You can't select smoothness / non-water borders if not terragenesis */ if (mode == GLWM_GENERATE) { this->SetWidgetDisabledState(WID_GL_SMOOTHNESS_PULLDOWN, _settings_newgame.game_creation.land_generator == 0); this->SetWidgetDisabledState(WID_GL_VARIETY_PULLDOWN, _settings_newgame.game_creation.land_generator == 0); this->SetWidgetDisabledState(WID_GL_BORDERS_RANDOM, _settings_newgame.game_creation.land_generator == 0 || !_settings_newgame.construction.freeform_edges); this->SetWidgetsDisabledState(_settings_newgame.game_creation.land_generator == 0 || !_settings_newgame.construction.freeform_edges || _settings_newgame.game_creation.water_borders == BORDERS_RANDOM, WID_GL_WATER_NW, WID_GL_WATER_NE, WID_GL_WATER_SE, WID_GL_WATER_SW, WIDGET_LIST_END); this->SetWidgetLoweredState(WID_GL_BORDERS_RANDOM, _settings_newgame.game_creation.water_borders == BORDERS_RANDOM); this->SetWidgetLoweredState(WID_GL_WATER_NW, HasBit(_settings_newgame.game_creation.water_borders, BORDER_NW)); this->SetWidgetLoweredState(WID_GL_WATER_NE, HasBit(_settings_newgame.game_creation.water_borders, BORDER_NE)); this->SetWidgetLoweredState(WID_GL_WATER_SE, HasBit(_settings_newgame.game_creation.water_borders, BORDER_SE)); this->SetWidgetLoweredState(WID_GL_WATER_SW, HasBit(_settings_newgame.game_creation.water_borders, BORDER_SW)); this->SetWidgetsDisabledState(_settings_newgame.game_creation.land_generator == 0 && (_settings_newgame.game_creation.landscape == LT_ARCTIC || _settings_newgame.game_creation.landscape == LT_TROPIC), WID_GL_TERRAIN_PULLDOWN, WID_GL_WATER_PULLDOWN, WIDGET_LIST_END); } /* Disable snowline if not arctic */ this->SetWidgetDisabledState(WID_GL_SNOW_LEVEL_TEXT, _settings_newgame.game_creation.landscape != LT_ARCTIC); /* Update availability of decreasing / increasing start date and snow level */ this->SetWidgetDisabledState(WID_GL_MAX_HEIGHTLEVEL_DOWN, _settings_newgame.construction.max_heightlevel <= MIN_MAX_HEIGHTLEVEL); this->SetWidgetDisabledState(WID_GL_MAX_HEIGHTLEVEL_UP, _settings_newgame.construction.max_heightlevel >= MAX_MAX_HEIGHTLEVEL); this->SetWidgetDisabledState(WID_GL_START_DATE_DOWN, _settings_newgame.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(WID_GL_START_DATE_UP, _settings_newgame.game_creation.starting_year >= MAX_YEAR); this->SetWidgetDisabledState(WID_GL_SNOW_LEVEL_DOWN, _settings_newgame.game_creation.snow_line_height <= MIN_SNOWLINE_HEIGHT || _settings_newgame.game_creation.landscape != LT_ARCTIC); this->SetWidgetDisabledState(WID_GL_SNOW_LEVEL_UP, _settings_newgame.game_creation.snow_line_height >= MAX_SNOWLINE_HEIGHT || _settings_newgame.game_creation.landscape != LT_ARCTIC); /* Do not allow a custom sea level with the original land generator. */ if (_settings_newgame.game_creation.land_generator == 0 && _settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { _settings_newgame.difficulty.quantity_sea_lakes = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { const StringID *strs = NULL; switch (widget) { case WID_GL_MAX_HEIGHTLEVEL_TEXT: SetDParam(0, MAX_TILE_HEIGHT); *size = GetStringBoundingBox(STR_JUST_INT); break; case WID_GL_START_DATE_TEXT: SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1)); *size = maxdim(*size, GetStringBoundingBox(STR_BLACK_DATE_LONG)); break; case WID_GL_MAPSIZE_X_PULLDOWN: case WID_GL_MAPSIZE_Y_PULLDOWN: SetDParamMaxValue(0, MAX_MAP_SIZE); *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT)); break; case WID_GL_SNOW_LEVEL_TEXT: SetDParamMaxValue(0, MAX_TILE_HEIGHT); *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT)); break; case WID_GL_HEIGHTMAP_SIZE_TEXT: SetDParam(0, this->x); SetDParam(1, this->y); *size = maxdim(*size, GetStringBoundingBox(STR_MAPGEN_HEIGHTMAP_SIZE)); break; case WID_GL_TOWN_PULLDOWN: strs = _num_towns; SetDParamMaxValue(0, CUSTOM_TOWN_MAX_NUMBER); *size = maxdim(*size, GetStringBoundingBox(STR_NUM_CUSTOM_NUMBER)); break; case WID_GL_INDUSTRY_PULLDOWN: strs = _num_inds; break; case WID_GL_LANDSCAPE_PULLDOWN: strs = _landscape; break; case WID_GL_TREE_PULLDOWN: strs = _tree_placer; break; case WID_GL_TERRAIN_PULLDOWN: strs = _elevations; break; case WID_GL_WATER_PULLDOWN: strs = _sea_lakes; SetDParamMaxValue(0, CUSTOM_SEA_LEVEL_MAX_PERCENTAGE); *size = maxdim(*size, GetStringBoundingBox(STR_SEA_LEVEL_CUSTOM_PERCENTAGE)); break; case WID_GL_RIVER_PULLDOWN: strs = _rivers; break; case WID_GL_SMOOTHNESS_PULLDOWN: strs = _smoothness; break; case WID_GL_VARIETY_PULLDOWN: strs = _variety; break; case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN: strs = _rotation; break; case WID_GL_BORDERS_RANDOM: *size = maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_RANDOMIZE), GetStringBoundingBox(STR_MAPGEN_BORDER_MANUAL)); break; case WID_GL_WATER_NE: case WID_GL_WATER_NW: case WID_GL_WATER_SE: case WID_GL_WATER_SW: *size = maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_RANDOM), maxdim(GetStringBoundingBox(STR_MAPGEN_BORDER_WATER), GetStringBoundingBox(STR_MAPGEN_BORDER_FREEFORM))); break; case WID_GL_HEIGHTMAP_NAME_TEXT: size->width = 0; break; default: return; } if (strs != NULL) { while (*strs != INVALID_STRING_ID) { *size = maxdim(*size, GetStringBoundingBox(*strs++)); } } size->width += padding.width; size->height = max(size->height, (uint)(FONT_HEIGHT_NORMAL + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM)); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_GL_HEIGHTMAP_NAME_TEXT: { DrawString(r.left, r.right, r.top, this->name, TC_ORANGE); break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_GL_TEMPERATE: case WID_GL_ARCTIC: case WID_GL_TROPICAL: case WID_GL_TOYLAND: SetNewLandscapeType(widget - WID_GL_TEMPERATE); break; case WID_GL_MAPSIZE_X_PULLDOWN: // Mapsize X ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_x, WID_GL_MAPSIZE_X_PULLDOWN); break; case WID_GL_MAPSIZE_Y_PULLDOWN: // Mapsize Y ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_y, WID_GL_MAPSIZE_Y_PULLDOWN); break; case WID_GL_TOWN_PULLDOWN: // Number of towns ShowDropDownMenu(this, _num_towns, _settings_newgame.difficulty.number_towns, WID_GL_TOWN_PULLDOWN, 0, 0); break; case WID_GL_INDUSTRY_PULLDOWN: // Number of industries ShowDropDownMenu(this, _num_inds, _settings_newgame.difficulty.industry_density, WID_GL_INDUSTRY_PULLDOWN, 0, 0); break; case WID_GL_GENERATE_BUTTON: { // Generate /* Get rotated map size. */ uint map_x; uint map_y; if (_settings_newgame.game_creation.heightmap_rotation == HM_CLOCKWISE) { map_x = this->y; map_y = this->x; } else { map_x = this->x; map_y = this->y; } if (mode == GLWM_HEIGHTMAP && (map_x * 2 < (1U << _settings_newgame.game_creation.map_x) || map_x / 2 > (1U << _settings_newgame.game_creation.map_x) || map_y * 2 < (1U << _settings_newgame.game_creation.map_y) || map_y / 2 > (1U << _settings_newgame.game_creation.map_y))) { ShowQuery( STR_WARNING_HEIGHTMAP_SCALE_CAPTION, STR_WARNING_HEIGHTMAP_SCALE_MESSAGE, this, LandscapeGenerationCallback); } else { StartGeneratingLandscape(mode); } break; } case WID_GL_MAX_HEIGHTLEVEL_DOWN: case WID_GL_MAX_HEIGHTLEVEL_UP: // Height level buttons /* Don't allow too fast scrolling */ if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) { this->HandleButtonClick(widget); _settings_newgame.construction.max_heightlevel = Clamp(_settings_newgame.construction.max_heightlevel + widget - WID_GL_MAX_HEIGHTLEVEL_TEXT, MIN_MAX_HEIGHTLEVEL, MAX_MAX_HEIGHTLEVEL); this->InvalidateData(); } _left_button_clicked = false; break; case WID_GL_MAX_HEIGHTLEVEL_TEXT: // Height level text this->widget_id = WID_GL_MAX_HEIGHTLEVEL_TEXT; SetDParam(0, _settings_newgame.construction.max_heightlevel); ShowQueryString(STR_JUST_INT, STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT, 4, this, CS_NUMERAL, QSF_ENABLE_DEFAULT); break; case WID_GL_START_DATE_DOWN: case WID_GL_START_DATE_UP: // Year buttons /* Don't allow too fast scrolling */ if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) { this->HandleButtonClick(widget); _settings_newgame.game_creation.starting_year = Clamp(_settings_newgame.game_creation.starting_year + widget - WID_GL_START_DATE_TEXT, MIN_YEAR, MAX_YEAR); this->InvalidateData(); } _left_button_clicked = false; break; case WID_GL_START_DATE_TEXT: // Year text this->widget_id = WID_GL_START_DATE_TEXT; SetDParam(0, _settings_newgame.game_creation.starting_year); ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_ENABLE_DEFAULT); break; case WID_GL_SNOW_LEVEL_DOWN: case WID_GL_SNOW_LEVEL_UP: // Snow line buttons /* Don't allow too fast scrolling */ if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) { this->HandleButtonClick(widget); _settings_newgame.game_creation.snow_line_height = Clamp(_settings_newgame.game_creation.snow_line_height + widget - WID_GL_SNOW_LEVEL_TEXT, MIN_SNOWLINE_HEIGHT, MAX_SNOWLINE_HEIGHT); this->InvalidateData(); } _left_button_clicked = false; break; case WID_GL_SNOW_LEVEL_TEXT: // Snow line text this->widget_id = WID_GL_SNOW_LEVEL_TEXT; SetDParam(0, _settings_newgame.game_creation.snow_line_height); ShowQueryString(STR_JUST_INT, STR_MAPGEN_SNOW_LINE_QUERY_CAPT, 4, this, CS_NUMERAL, QSF_ENABLE_DEFAULT); break; case WID_GL_TREE_PULLDOWN: // Tree placer ShowDropDownMenu(this, _tree_placer, _settings_newgame.game_creation.tree_placer, WID_GL_TREE_PULLDOWN, 0, 0); break; case WID_GL_LANDSCAPE_PULLDOWN: // Landscape generator ShowDropDownMenu(this, _landscape, _settings_newgame.game_creation.land_generator, WID_GL_LANDSCAPE_PULLDOWN, 0, 0); break; case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN: // Heightmap rotation ShowDropDownMenu(this, _rotation, _settings_newgame.game_creation.heightmap_rotation, WID_GL_HEIGHTMAP_ROTATION_PULLDOWN, 0, 0); break; case WID_GL_TERRAIN_PULLDOWN: // Terrain type /* For the original map generation only the first four are valid. */ ShowDropDownMenu(this, _elevations, _settings_newgame.difficulty.terrain_type, WID_GL_TERRAIN_PULLDOWN, 0, _settings_newgame.game_creation.land_generator == LG_ORIGINAL ? ~0xF : 0); break; case WID_GL_WATER_PULLDOWN: { // Water quantity uint32 hidden_mask = 0; /* Disable custom water level when the original map generator is active. */ if (_settings_newgame.game_creation.land_generator == 0) { SetBit(hidden_mask, CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY); } ShowDropDownMenu(this, _sea_lakes, _settings_newgame.difficulty.quantity_sea_lakes, WID_GL_WATER_PULLDOWN, 0, hidden_mask); break; } case WID_GL_RIVER_PULLDOWN: // Amount of rivers ShowDropDownMenu(this, _rivers, _settings_newgame.game_creation.amount_of_rivers, WID_GL_RIVER_PULLDOWN, 0, 0); break; case WID_GL_SMOOTHNESS_PULLDOWN: // Map smoothness ShowDropDownMenu(this, _smoothness, _settings_newgame.game_creation.tgen_smoothness, WID_GL_SMOOTHNESS_PULLDOWN, 0, 0); break; case WID_GL_VARIETY_PULLDOWN: // Map variety ShowDropDownMenu(this, _variety, _settings_newgame.game_creation.variety, WID_GL_VARIETY_PULLDOWN, 0, 0); break; /* Freetype map borders */ case WID_GL_WATER_NW: _settings_newgame.game_creation.water_borders = ToggleBit(_settings_newgame.game_creation.water_borders, BORDER_NW); this->InvalidateData(); break; case WID_GL_WATER_NE: _settings_newgame.game_creation.water_borders = ToggleBit(_settings_newgame.game_creation.water_borders, BORDER_NE); this->InvalidateData(); break; case WID_GL_WATER_SE: _settings_newgame.game_creation.water_borders = ToggleBit(_settings_newgame.game_creation.water_borders, BORDER_SE); this->InvalidateData(); break; case WID_GL_WATER_SW: _settings_newgame.game_creation.water_borders = ToggleBit(_settings_newgame.game_creation.water_borders, BORDER_SW); this->InvalidateData(); break; case WID_GL_BORDERS_RANDOM: _settings_newgame.game_creation.water_borders = (_settings_newgame.game_creation.water_borders == BORDERS_RANDOM) ? 0 : BORDERS_RANDOM; this->InvalidateData(); break; } } virtual void OnTimeout() { static const int raise_widgets[] = {WID_GL_MAX_HEIGHTLEVEL_DOWN, WID_GL_MAX_HEIGHTLEVEL_UP, WID_GL_START_DATE_DOWN, WID_GL_START_DATE_UP, WID_GL_SNOW_LEVEL_UP, WID_GL_SNOW_LEVEL_DOWN, WIDGET_LIST_END}; for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) { if (this->IsWidgetLowered(*widget)) { this->RaiseWidget(*widget); this->SetWidgetDirty(*widget); } } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_GL_MAPSIZE_X_PULLDOWN: _settings_newgame.game_creation.map_x = index; break; case WID_GL_MAPSIZE_Y_PULLDOWN: _settings_newgame.game_creation.map_y = index; break; case WID_GL_TREE_PULLDOWN: _settings_newgame.game_creation.tree_placer = index; break; case WID_GL_RIVER_PULLDOWN: _settings_newgame.game_creation.amount_of_rivers = index; break; case WID_GL_SMOOTHNESS_PULLDOWN: _settings_newgame.game_creation.tgen_smoothness = index; break; case WID_GL_VARIETY_PULLDOWN: _settings_newgame.game_creation.variety = index; break; case WID_GL_LANDSCAPE_PULLDOWN: _settings_newgame.game_creation.land_generator = index; /* If original landgenerator is selected and alpinist terrain_type was selected, revert to mountainous. */ if (_settings_newgame.game_creation.land_generator == LG_ORIGINAL) { _settings_newgame.difficulty.terrain_type = Clamp(_settings_newgame.difficulty.terrain_type, 0, 3); } break; case WID_GL_HEIGHTMAP_ROTATION_PULLDOWN: _settings_newgame.game_creation.heightmap_rotation = index; break; case WID_GL_TOWN_PULLDOWN: if ((uint)index == CUSTOM_TOWN_NUMBER_DIFFICULTY) { this->widget_id = widget; SetDParam(0, _settings_newgame.game_creation.custom_town_number); ShowQueryString(STR_JUST_INT, STR_MAPGEN_NUMBER_OF_TOWNS, 5, this, CS_NUMERAL, QSF_NONE); } _settings_newgame.difficulty.number_towns = index; break; case WID_GL_INDUSTRY_PULLDOWN: _settings_newgame.difficulty.industry_density = index; break; case WID_GL_TERRAIN_PULLDOWN: _settings_newgame.difficulty.terrain_type = index; break; case WID_GL_WATER_PULLDOWN: { if ((uint)index == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { this->widget_id = widget; SetDParam(0, _settings_newgame.game_creation.custom_sea_level); ShowQueryString(STR_JUST_INT, STR_MAPGEN_QUANTITY_OF_SEA_LAKES, 3, this, CS_NUMERAL, QSF_NONE); } _settings_newgame.difficulty.quantity_sea_lakes = index; break; } } this->InvalidateData(); } virtual void OnQueryTextFinished(char *str) { /* Was 'cancel' pressed? */ if (str == NULL) return; int32 value; if (!StrEmpty(str)) { value = atoi(str); } else { /* An empty string means revert to the default */ switch (this->widget_id) { case WID_GL_MAX_HEIGHTLEVEL_TEXT: value = DEF_MAX_HEIGHTLEVEL; break; case WID_GL_START_DATE_TEXT: value = DEF_START_YEAR; break; case WID_GL_SNOW_LEVEL_TEXT: value = DEF_SNOWLINE_HEIGHT; break; case WID_GL_TOWN_PULLDOWN: value = 1; break; case WID_GL_WATER_PULLDOWN: value = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE; break; default: NOT_REACHED(); } } switch (this->widget_id) { case WID_GL_MAX_HEIGHTLEVEL_TEXT: this->SetWidgetDirty(WID_GL_MAX_HEIGHTLEVEL_TEXT); _settings_newgame.construction.max_heightlevel = Clamp(value, MIN_MAX_HEIGHTLEVEL, MAX_MAX_HEIGHTLEVEL); break; case WID_GL_START_DATE_TEXT: this->SetWidgetDirty(WID_GL_START_DATE_TEXT); _settings_newgame.game_creation.starting_year = Clamp(value, MIN_YEAR, MAX_YEAR); break; case WID_GL_SNOW_LEVEL_TEXT: this->SetWidgetDirty(WID_GL_SNOW_LEVEL_TEXT); _settings_newgame.game_creation.snow_line_height = Clamp(value, MIN_SNOWLINE_HEIGHT, MAX_SNOWLINE_HEIGHT); break; case WID_GL_TOWN_PULLDOWN: _settings_newgame.game_creation.custom_town_number = Clamp(value, 1, CUSTOM_TOWN_MAX_NUMBER); break; case WID_GL_WATER_PULLDOWN: _settings_newgame.game_creation.custom_sea_level = Clamp(value, CUSTOM_SEA_LEVEL_MIN_PERCENTAGE, CUSTOM_SEA_LEVEL_MAX_PERCENTAGE); break; } this->InvalidateData(); } }; static WindowDesc _generate_landscape_desc( WDP_CENTER, NULL, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, _nested_generate_landscape_widgets, lengthof(_nested_generate_landscape_widgets) ); static WindowDesc _heightmap_load_desc( WDP_CENTER, NULL, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, _nested_heightmap_load_widgets, lengthof(_nested_heightmap_load_widgets) ); static void _ShowGenerateLandscape(GenerateLandscapeWindowMode mode) { uint x = 0; uint y = 0; DeleteWindowByClass(WC_GENERATE_LANDSCAPE); /* Generate a new seed when opening the window */ _settings_newgame.game_creation.generation_seed = InteractiveRandom(); if (mode == GLWM_HEIGHTMAP) { /* If the function returns negative, it means there was a problem loading the heightmap */ if (!GetHeightmapDimensions(_file_to_saveload.name, &x, &y)) return; } WindowDesc *desc = (mode == GLWM_HEIGHTMAP) ? &_heightmap_load_desc : &_generate_landscape_desc; GenerateLandscapeWindow *w = AllocateWindowDescFront(desc, mode, true); if (mode == GLWM_HEIGHTMAP) { w->x = x; w->y = y; strecpy(w->name, _file_to_saveload.title, lastof(w->name)); } SetWindowDirty(WC_GENERATE_LANDSCAPE, mode); } /** Start with a normal game. */ void ShowGenerateLandscape() { _ShowGenerateLandscape(GLWM_GENERATE); } /** Start with loading a heightmap. */ void ShowHeightmapLoad() { _ShowGenerateLandscape(GLWM_HEIGHTMAP); } /** Start with a scenario editor. */ void StartScenarioEditor() { StartGeneratingLandscape(GLWM_SCENARIO); } /** * Start a normal game without the GUI. * @param seed The seed of the new game. */ void StartNewGameWithoutGUI(uint seed) { /* GenerateWorld takes care of the possible GENERATE_NEW_SEED value in 'seed' */ _settings_newgame.game_creation.generation_seed = seed; StartGeneratingLandscape(GLWM_GENERATE); } struct CreateScenarioWindow : public Window { uint widget_id; CreateScenarioWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); this->LowerWidget(_settings_newgame.game_creation.landscape + WID_CS_TEMPERATE); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_CS_START_DATE_TEXT: SetDParam(0, ConvertYMDToDate(_settings_newgame.game_creation.starting_year, 0, 1)); break; case WID_CS_MAPSIZE_X_PULLDOWN: SetDParam(0, 1 << _settings_newgame.game_creation.map_x); break; case WID_CS_MAPSIZE_Y_PULLDOWN: SetDParam(0, 1 << _settings_newgame.game_creation.map_y); break; case WID_CS_FLAT_LAND_HEIGHT_TEXT: SetDParam(0, _settings_newgame.game_creation.se_flat_world_height); break; } } virtual void OnPaint() { this->SetWidgetDisabledState(WID_CS_START_DATE_DOWN, _settings_newgame.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(WID_CS_START_DATE_UP, _settings_newgame.game_creation.starting_year >= MAX_YEAR); this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_DOWN, _settings_newgame.game_creation.se_flat_world_height <= 0); this->SetWidgetDisabledState(WID_CS_FLAT_LAND_HEIGHT_UP, _settings_newgame.game_creation.se_flat_world_height >= MAX_TILE_HEIGHT); this->SetWidgetLoweredState(WID_CS_TEMPERATE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); this->SetWidgetLoweredState(WID_CS_ARCTIC, _settings_newgame.game_creation.landscape == LT_ARCTIC); this->SetWidgetLoweredState(WID_CS_TROPICAL, _settings_newgame.game_creation.landscape == LT_TROPIC); this->SetWidgetLoweredState(WID_CS_TOYLAND, _settings_newgame.game_creation.landscape == LT_TOYLAND); this->DrawWidgets(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { StringID str = STR_JUST_INT; switch (widget) { case WID_CS_START_DATE_TEXT: SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1)); str = STR_BLACK_DATE_LONG; break; case WID_CS_MAPSIZE_X_PULLDOWN: case WID_CS_MAPSIZE_Y_PULLDOWN: SetDParamMaxValue(0, MAX_MAP_SIZE); break; case WID_CS_FLAT_LAND_HEIGHT_TEXT: SetDParamMaxValue(0, MAX_TILE_HEIGHT); break; default: return; } *size = maxdim(*size, GetStringBoundingBox(str)); size->width += padding.width; size->height += padding.height; } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_CS_TEMPERATE: case WID_CS_ARCTIC: case WID_CS_TROPICAL: case WID_CS_TOYLAND: this->RaiseWidget(_settings_newgame.game_creation.landscape + WID_CS_TEMPERATE); SetNewLandscapeType(widget - WID_CS_TEMPERATE); break; case WID_CS_MAPSIZE_X_PULLDOWN: // Mapsize X ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_x, WID_CS_MAPSIZE_X_PULLDOWN); break; case WID_CS_MAPSIZE_Y_PULLDOWN: // Mapsize Y ShowDropDownList(this, BuildMapsizeDropDown(), _settings_newgame.game_creation.map_y, WID_CS_MAPSIZE_Y_PULLDOWN); break; case WID_CS_EMPTY_WORLD: // Empty world / flat world StartGeneratingLandscape(GLWM_SCENARIO); break; case WID_CS_RANDOM_WORLD: // Generate ShowGenerateLandscape(); break; case WID_CS_START_DATE_DOWN: case WID_CS_START_DATE_UP: // Year buttons /* Don't allow too fast scrolling */ if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) { this->HandleButtonClick(widget); this->SetDirty(); _settings_newgame.game_creation.starting_year = Clamp(_settings_newgame.game_creation.starting_year + widget - WID_CS_START_DATE_TEXT, MIN_YEAR, MAX_YEAR); } _left_button_clicked = false; break; case WID_CS_START_DATE_TEXT: // Year text this->widget_id = WID_CS_START_DATE_TEXT; SetDParam(0, _settings_newgame.game_creation.starting_year); ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, this, CS_NUMERAL, QSF_NONE); break; case WID_CS_FLAT_LAND_HEIGHT_DOWN: case WID_CS_FLAT_LAND_HEIGHT_UP: // Height level buttons /* Don't allow too fast scrolling */ if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) { this->HandleButtonClick(widget); this->SetDirty(); _settings_newgame.game_creation.se_flat_world_height = Clamp(_settings_newgame.game_creation.se_flat_world_height + widget - WID_CS_FLAT_LAND_HEIGHT_TEXT, 0, _settings_game.construction.max_heightlevel); } _left_button_clicked = false; break; case WID_CS_FLAT_LAND_HEIGHT_TEXT: // Height level text this->widget_id = WID_CS_FLAT_LAND_HEIGHT_TEXT; SetDParam(0, _settings_newgame.game_creation.se_flat_world_height); ShowQueryString(STR_JUST_INT, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT, 4, this, CS_NUMERAL, QSF_NONE); break; } } virtual void OnTimeout() { static const int raise_widgets[] = {WID_CS_START_DATE_DOWN, WID_CS_START_DATE_UP, WID_CS_FLAT_LAND_HEIGHT_DOWN, WID_CS_FLAT_LAND_HEIGHT_UP, WIDGET_LIST_END}; for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) { if (this->IsWidgetLowered(*widget)) { this->RaiseWidget(*widget); this->SetWidgetDirty(*widget); } } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_CS_MAPSIZE_X_PULLDOWN: _settings_newgame.game_creation.map_x = index; break; case WID_CS_MAPSIZE_Y_PULLDOWN: _settings_newgame.game_creation.map_y = index; break; } this->SetDirty(); } virtual void OnQueryTextFinished(char *str) { if (!StrEmpty(str)) { int32 value = atoi(str); switch (this->widget_id) { case WID_CS_START_DATE_TEXT: this->SetWidgetDirty(WID_CS_START_DATE_TEXT); _settings_newgame.game_creation.starting_year = Clamp(value, MIN_YEAR, MAX_YEAR); break; case WID_CS_FLAT_LAND_HEIGHT_TEXT: this->SetWidgetDirty(WID_CS_FLAT_LAND_HEIGHT_TEXT); _settings_newgame.game_creation.se_flat_world_height = Clamp(value, 0, _settings_game.construction.max_heightlevel); break; } this->SetDirty(); } } }; static const NWidgetPart _nested_create_scenario_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_SE_MAPGEN_CAPTION, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_SPACER), SetMinimalSize(0, 10), /* Landscape style selection. */ NWidget(NWID_HORIZONTAL), SetPIP(10, 3, 10), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_TEMPERATE), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_ARCTIC), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_TROPICAL), SetDataTip(SPR_SELECT_SUB_TROPICAL, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_CS_TOYLAND), SetDataTip(SPR_SELECT_TOYLAND, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 8, 10), /* Green generation type buttons: 'Flat land' and 'Random land'. */ NWidget(NWID_VERTICAL), SetPIP(10, 6, 10), NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_CS_EMPTY_WORLD), SetDataTip(STR_SE_MAPGEN_FLAT_WORLD, STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP), SetFill(1, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_CS_RANDOM_WORLD), SetDataTip(STR_SE_MAPGEN_RANDOM_LAND, STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND), SetFill(1, 1), EndContainer(), /* Labels + setting drop-downs */ NWidget(NWID_VERTICAL), SetPIP(10, 6, 10), /* Map size. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_MAPSIZE, STR_NULL), SetPadding(1, 0, 0, 0), NWidget(NWID_SPACER), SetMinimalSize(6, 0), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_CS_MAPSIZE_X_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), SetPadding(0, 4, 0, 0), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_BY, STR_NULL), SetPadding(1, 2, 0, 0), NWidget(WWT_DROPDOWN, COLOUR_ORANGE, WID_CS_MAPSIZE_Y_PULLDOWN), SetDataTip(STR_JUST_INT, STR_NULL), EndContainer(), /* Date. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_MAPGEN_DATE, STR_NULL), SetPadding(1, 0, 0, 0), NWidget(NWID_SPACER), SetMinimalSize(6, 0), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_CS_START_DATE_DOWN), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CS_START_DATE_TEXT), SetDataTip(STR_BLACK_DATE_LONG, STR_NULL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_CS_START_DATE_UP), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), EndContainer(), /* Flat map height. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXT, COLOUR_ORANGE), SetDataTip(STR_SE_MAPGEN_FLAT_WORLD_HEIGHT, STR_NULL), SetPadding(1, 0, 0, 0), NWidget(NWID_SPACER), SetMinimalSize(6, 0), SetFill(1, 0), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_CS_FLAT_LAND_HEIGHT_DOWN), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CS_FLAT_LAND_HEIGHT_TEXT), SetDataTip(STR_BLACK_INT, STR_NULL), NWidget(WWT_IMGBTN, COLOUR_ORANGE, WID_CS_FLAT_LAND_HEIGHT_UP), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP), EndContainer(), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _create_scenario_desc( WDP_CENTER, NULL, 0, 0, WC_GENERATE_LANDSCAPE, WC_NONE, 0, _nested_create_scenario_widgets, lengthof(_nested_create_scenario_widgets) ); /** Show the window to create a scenario. */ void ShowCreateScenario() { DeleteWindowByClass(WC_GENERATE_LANDSCAPE); new CreateScenarioWindow(&_create_scenario_desc, GLWM_SCENARIO); } static const NWidgetPart _nested_generate_progress_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GENERATION_WORLD, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_HORIZONTAL), SetPIP(20, 0, 20), NWidget(NWID_VERTICAL), SetPIP(11, 8, 11), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GP_PROGRESS_BAR), SetFill(1, 0), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GP_PROGRESS_TEXT), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_WHITE, WID_GP_ABORT), SetDataTip(STR_GENERATION_ABORT, STR_NULL), SetFill(1, 0), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _generate_progress_desc( WDP_CENTER, NULL, 0, 0, WC_MODAL_PROGRESS, WC_NONE, 0, _nested_generate_progress_widgets, lengthof(_nested_generate_progress_widgets) ); struct GenWorldStatus { uint percent; StringID cls; uint current; uint total; int timer; }; static GenWorldStatus _gws; static const StringID _generation_class_table[] = { STR_GENERATION_WORLD_GENERATION, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION, STR_GENERATION_RIVER_GENERATION, STR_GENERATION_CLEARING_TILES, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION, STR_GENERATION_OBJECT_GENERATION, STR_GENERATION_TREE_GENERATION, STR_GENERATION_SETTINGUP_GAME, STR_GENERATION_PREPARING_TILELOOP, STR_GENERATION_PREPARING_SCRIPT, STR_GENERATION_PREPARING_GAME }; assert_compile(lengthof(_generation_class_table) == GWP_CLASS_COUNT); static void AbortGeneratingWorldCallback(Window *w, bool confirmed) { if (confirmed) { AbortGeneratingWorld(); } else if (HasModalProgress() && !IsGeneratingWorldAborted()) { SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE); } } struct GenerateProgressWindow : public Window { GenerateProgressWindow() : Window(&_generate_progress_desc) { this->InitNested(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_GP_ABORT: if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE); ShowQuery( STR_GENERATION_ABORT_CAPTION, STR_GENERATION_ABORT_MESSAGE, this, AbortGeneratingWorldCallback ); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_GP_PROGRESS_BAR: { SetDParamMaxValue(0, 100); *size = GetStringBoundingBox(STR_GENERATION_PROGRESS); /* We need some spacing for the 'border' */ size->height += 8; size->width += 8; break; } case WID_GP_PROGRESS_TEXT: for (uint i = 0; i < GWP_CLASS_COUNT; i++) { size->width = max(size->width, GetStringBoundingBox(_generation_class_table[i]).width); } size->height = FONT_HEIGHT_NORMAL * 2 + WD_PAR_VSEP_NORMAL; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_GP_PROGRESS_BAR: /* Draw the % complete with a bar and a text */ DrawFrameRect(r.left, r.top, r.right, r.bottom, COLOUR_GREY, FR_BORDERONLY); DrawFrameRect(r.left + 1, r.top + 1, (int)((r.right - r.left - 2) * _gws.percent / 100) + r.left + 1, r.bottom - 1, COLOUR_MAUVE, FR_NONE); SetDParam(0, _gws.percent); DrawString(r.left, r.right, r.top + 5, STR_GENERATION_PROGRESS, TC_FROMSTRING, SA_HOR_CENTER); break; case WID_GP_PROGRESS_TEXT: /* Tell which class we are generating */ DrawString(r.left, r.right, r.top, _gws.cls, TC_FROMSTRING, SA_HOR_CENTER); /* And say where we are in that class */ SetDParam(0, _gws.current); SetDParam(1, _gws.total); DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL, STR_GENERATION_PROGRESS_NUM, TC_FROMSTRING, SA_HOR_CENTER); } } }; /** * Initializes the progress counters to the starting point. */ void PrepareGenerateWorldProgress() { _gws.cls = STR_GENERATION_WORLD_GENERATION; _gws.current = 0; _gws.total = 0; _gws.percent = 0; _gws.timer = 0; // Forces to paint the progress window immediately } /** * Show the window where a user can follow the process of the map generation. */ void ShowGenerateWorldProgress() { if (BringWindowToFrontById(WC_MODAL_PROGRESS, 0)) return; new GenerateProgressWindow(); } static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uint total) { static const int percent_table[] = {0, 5, 14, 17, 20, 40, 60, 65, 80, 85, 95, 99, 100 }; assert_compile(lengthof(percent_table) == GWP_CLASS_COUNT + 1); assert(cls < GWP_CLASS_COUNT); /* Do not run this function if we aren't in a thread */ if (!IsGenerateWorldThreaded() && !_network_dedicated) return; if (IsGeneratingWorldAborted()) HandleGeneratingWorldAbortion(); if (total == 0) { assert(_gws.cls == _generation_class_table[cls]); _gws.current += progress; assert(_gws.current <= _gws.total); } else { _gws.cls = _generation_class_table[cls]; _gws.current = progress; _gws.total = total; _gws.percent = percent_table[cls]; } /* Don't update the screen too often. So update it once in every once in a while... */ if (!_network_dedicated && _gws.timer != 0 && _realtime_tick - _gws.timer < MODAL_PROGRESS_REDRAW_TIMEOUT) return; /* Percentage is about the number of completed tasks, so 'current - 1' */ _gws.percent = percent_table[cls] + (percent_table[cls + 1] - percent_table[cls]) * (_gws.current == 0 ? 0 : _gws.current - 1) / _gws.total; if (_network_dedicated) { static uint last_percent = 0; /* Never display 0% */ if (_gws.percent == 0) return; /* Reset if percent is lower than the last recorded */ if (_gws.percent < last_percent) last_percent = 0; /* Display every 5%, but 6% is also very valid.. just not smaller steps than 5% */ if (_gws.percent % 5 != 0 && _gws.percent <= last_percent + 5) return; /* Never show steps smaller than 2%, even if it is a mod 5% */ if (_gws.percent <= last_percent + 2) return; DEBUG(net, 1, "Map generation percentage complete: %d", _gws.percent); last_percent = _gws.percent; /* Don't continue as dedicated never has a thread running */ return; } SetWindowDirty(WC_MODAL_PROGRESS, 0); MarkWholeScreenDirty(); /* Release the rights to the map generator, and acquire the rights to the * paint thread. The 'other' thread already has the paint thread rights so * this ensures us that we are waiting until the paint thread is done * before we reacquire the mapgen rights */ _modal_progress_work_mutex->EndCritical(); _modal_progress_paint_mutex->BeginCritical(); _modal_progress_work_mutex->BeginCritical(); _modal_progress_paint_mutex->EndCritical(); _gws.timer = _realtime_tick; } /** * Set the total of a stage of the world generation. * @param cls the current class we are in. * @param total Set the total expected items for this class. * * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always. * Also, progress works if total is zero, total works if progress is zero. */ void SetGeneratingWorldProgress(GenWorldProgress cls, uint total) { if (total == 0) return; _SetGeneratingWorldProgress(cls, 0, total); } /** * Increases the current stage of the world generation with one. * @param cls the current class we are in. * * Warning: this function isn't clever. Don't go from class 4 to 3. Go upwards, always. * Also, progress works if total is zero, total works if progress is zero. */ void IncreaseGeneratingWorldProgress(GenWorldProgress cls) { /* In fact the param 'class' isn't needed.. but for some security reasons, we want it around */ _SetGeneratingWorldProgress(cls, 1, 0); } openttd-1.5.3/src/company_type.h0000644000000000000000000000551112627373435015360 0ustar rootroot/* $Id: company_type.h 23602 2011-12-19 20:50:36Z truebrain $ */ /* * 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 company_type.h Types related to companies. */ #ifndef COMPANY_TYPE_H #define COMPANY_TYPE_H #include "core/enum_type.hpp" /** * Enum for all companies/owners. */ enum Owner { /* All companies below MAX_COMPANIES are playable * companies, above, they are special, computer controlled 'companies' */ OWNER_BEGIN = 0x00, ///< First owner COMPANY_FIRST = 0x00, ///< First company, same as owner MAX_COMPANIES = 0x0F, ///< Maximum number of companies OWNER_TOWN = 0x0F, ///< A town owns the tile, or a town is expanding OWNER_NONE = 0x10, ///< The tile has no ownership OWNER_WATER = 0x11, ///< The tile/execution is done by "water" OWNER_DEITY = 0x12, ///< The object is owned by a superuser / goal script OWNER_END, ///< Last + 1 owner INVALID_OWNER = 0xFF, ///< An invalid owner INVALID_COMPANY = 0xFF, ///< An invalid company /* 'Fake' companies used for networks */ COMPANY_INACTIVE_CLIENT = 253, ///< The client is joining COMPANY_NEW_COMPANY = 254, ///< The client wants a new company COMPANY_SPECTATOR = 255, ///< The client is spectating }; DECLARE_POSTFIX_INCREMENT(Owner) static const uint MAX_LENGTH_PRESIDENT_NAME_CHARS = 32; ///< The maximum length of a president name in characters including '\0' static const uint MAX_LENGTH_COMPANY_NAME_CHARS = 32; ///< The maximum length of a company name in characters including '\0' static const uint MAX_HISTORY_QUARTERS = 24; ///< The maximum number of quarters kept as performance's history /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT OwnerByte; typedef Owner CompanyID; typedef OwnerByte CompanyByte; typedef uint16 CompanyMask; struct Company; typedef uint32 CompanyManagerFace; ///< Company manager face bits, info see in company_manager_face.h /** The reason why the company was removed. */ enum CompanyRemoveReason { CRR_MANUAL, ///< The company is manually removed. CRR_AUTOCLEAN, ///< The company is removed due to autoclean. CRR_BANKRUPT, ///< The company went belly-up. CRR_END, ///< Sentinel for end. }; #endif /* COMPANY_TYPE_H */ openttd-1.5.3/src/airport.h0000644000000000000000000002271412627373435014335 0ustar rootroot/* $Id: airport.h 25841 2013-10-12 16:34:59Z frosch $ */ /* * 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 airport.h Various declarations for airports */ #ifndef AIRPORT_H #define AIRPORT_H #include "direction_type.h" #include "tile_type.h" /** Some airport-related constants */ static const uint MAX_TERMINALS = 8; ///< maximum number of terminals per airport static const uint MAX_HELIPADS = 3; ///< maximum number of helipads per airport static const uint MAX_ELEMENTS = 255; ///< maximum number of aircraft positions at airport static const uint NUM_AIRPORTTILES_PER_GRF = 255; ///< Number of airport tiles per NewGRF; limited to 255 to allow extending Action3 with an extended byte later on. static const uint NUM_AIRPORTTILES = 256; ///< Total number of airport tiles. static const uint NEW_AIRPORTTILE_OFFSET = 74; ///< offset of first newgrf airport tile static const uint INVALID_AIRPORTTILE = NUM_AIRPORTTILES; ///< id for an invalid airport tile /** Airport types */ enum AirportTypes { AT_SMALL = 0, ///< Small airport. AT_LARGE = 1, ///< Large airport. AT_HELIPORT = 2, ///< Heli port. AT_METROPOLITAN = 3, ///< Metropolitan airport. AT_INTERNATIONAL = 4, ///< International airport. AT_COMMUTER = 5, ///< Commuter airport. AT_HELIDEPOT = 6, ///< Heli depot. AT_INTERCON = 7, ///< Intercontinental airport. AT_HELISTATION = 8, ///< Heli station airport. AT_OILRIG = 9, ///< Oilrig airport. NEW_AIRPORT_OFFSET = 10, ///< Number of the first newgrf airport. NUM_AIRPORTS_PER_GRF = 128, ///< Maximal number of airports per NewGRF. NUM_AIRPORTS = 128, ///< Maximal number of airports in total. AT_INVALID = 254, ///< Invalid airport. AT_DUMMY = 255, ///< Dummy airport. }; /** Flags for airport movement data. */ enum AirportMovingDataFlags { AMED_NOSPDCLAMP = 1 << 0, ///< No speed restrictions. AMED_TAKEOFF = 1 << 1, ///< Takeoff movement. AMED_SLOWTURN = 1 << 2, ///< Turn slowly (mostly used in the air). AMED_LAND = 1 << 3, ///< Landing onto landing strip. AMED_EXACTPOS = 1 << 4, ///< Go exactly to the destination coordinates. AMED_BRAKE = 1 << 5, ///< Taxiing at the airport. AMED_HELI_RAISE = 1 << 6, ///< Helicopter take-off. AMED_HELI_LOWER = 1 << 7, ///< Helicopter landing. AMED_HOLD = 1 << 8, ///< Holding pattern movement (above the airport). }; /** Movement States on Airports (headings target) */ enum AirportMovementStates { TO_ALL = 0, ///< Go in this direction for every target. HANGAR = 1, ///< Heading for hangar. TERM1 = 2, ///< Heading for terminal 1. TERM2 = 3, ///< Heading for terminal 2. TERM3 = 4, ///< Heading for terminal 3. TERM4 = 5, ///< Heading for terminal 4. TERM5 = 6, ///< Heading for terminal 5. TERM6 = 7, ///< Heading for terminal 6. HELIPAD1 = 8, ///< Heading for helipad 1. HELIPAD2 = 9, ///< Heading for helipad 2. TAKEOFF = 10, ///< Airplane wants to leave the airport. STARTTAKEOFF = 11, ///< Airplane has arrived at a runway for take-off. ENDTAKEOFF = 12, ///< Airplane has reached end-point of the take-off runway. HELITAKEOFF = 13, ///< Helicopter wants to leave the airport. FLYING = 14, ///< %Vehicle is flying in the air. LANDING = 15, ///< Airplane wants to land. ENDLANDING = 16, ///< Airplane wants to finish landing. HELILANDING = 17, ///< Helicopter wants to land. HELIENDLANDING = 18, ///< Helicopter wants to finish landing. TERM7 = 19, ///< Heading for terminal 7. TERM8 = 20, ///< Heading for terminal 8. HELIPAD3 = 21, ///< Heading for helipad 3. MAX_HEADINGS = 21, ///< Last valid target to head for. }; /** Movement Blocks on Airports blocks (eg_airport_flags). */ static const uint64 TERM1_block = 1ULL << 0, ///< Block belonging to terminal 1. TERM2_block = 1ULL << 1, ///< Block belonging to terminal 2. TERM3_block = 1ULL << 2, ///< Block belonging to terminal 3. TERM4_block = 1ULL << 3, ///< Block belonging to terminal 4. TERM5_block = 1ULL << 4, ///< Block belonging to terminal 5. TERM6_block = 1ULL << 5, ///< Block belonging to terminal 6. HELIPAD1_block = 1ULL << 6, ///< Block belonging to helipad 1. HELIPAD2_block = 1ULL << 7, ///< Block belonging to helipad 2. RUNWAY_IN_OUT_block = 1ULL << 8, RUNWAY_IN_block = 1ULL << 8, AIRPORT_BUSY_block = 1ULL << 8, RUNWAY_OUT_block = 1ULL << 9, TAXIWAY_BUSY_block = 1ULL << 10, OUT_WAY_block = 1ULL << 11, IN_WAY_block = 1ULL << 12, AIRPORT_ENTRANCE_block = 1ULL << 13, TERM_GROUP1_block = 1ULL << 14, TERM_GROUP2_block = 1ULL << 15, HANGAR2_AREA_block = 1ULL << 16, TERM_GROUP2_ENTER1_block = 1ULL << 17, TERM_GROUP2_ENTER2_block = 1ULL << 18, TERM_GROUP2_EXIT1_block = 1ULL << 19, TERM_GROUP2_EXIT2_block = 1ULL << 20, PRE_HELIPAD_block = 1ULL << 21, /* blocks for new airports */ TERM7_block = 1ULL << 22, ///< Block belonging to terminal 7. TERM8_block = 1ULL << 23, ///< Block belonging to terminal 8. HELIPAD3_block = 1ULL << 24, ///< Block belonging to helipad 3. HANGAR1_AREA_block = 1ULL << 26, OUT_WAY2_block = 1ULL << 27, IN_WAY2_block = 1ULL << 28, RUNWAY_IN2_block = 1ULL << 29, RUNWAY_OUT2_block = 1ULL << 10, ///< @note re-uses #TAXIWAY_BUSY_block HELIPAD_GROUP_block = 1ULL << 13, ///< @note re-uses #AIRPORT_ENTRANCE_block OUT_WAY_block2 = 1ULL << 31, /* end of new blocks */ NOTHING_block = 1ULL << 30, AIRPORT_CLOSED_block = 1ULL << 63; ///< Dummy block for indicating a closed airport. /** A single location on an airport where aircraft can move to. */ struct AirportMovingData { int16 x; ///< x-coordinate of the destination. int16 y; ///< y-coordinate of the destination. uint16 flag; ///< special flags when moving towards the destination. DirectionByte direction; ///< Direction to turn the aircraft after reaching the destination. }; AirportMovingData RotateAirportMovingData(const AirportMovingData *orig, Direction rotation, uint num_tiles_x, uint num_tiles_y); struct AirportFTAbuildup; /** Finite sTate mAchine (FTA) of an airport. */ struct AirportFTAClass { public: /** Bitmask of airport flags. */ enum Flags { AIRPLANES = 0x1, ///< Can planes land on this airport type? HELICOPTERS = 0x2, ///< Can helicopters land on this airport type? ALL = AIRPLANES | HELICOPTERS, ///< Mask to check for both planes and helicopters. SHORT_STRIP = 0x4, ///< This airport has a short landing strip, dangerous for fast aircraft. }; AirportFTAClass( const AirportMovingData *moving_data, const byte *terminals, const byte num_helipads, const byte *entry_points, Flags flags, const AirportFTAbuildup *apFA, byte delta_z ); ~AirportFTAClass(); /** * Get movement data at a position. * @param position Element number to get movement data about. * @return Pointer to the movement data. */ const AirportMovingData *MovingData(byte position) const { assert(position < nofelements); return &moving_data[position]; } const AirportMovingData *moving_data; ///< Movement data. struct AirportFTA *layout; ///< state machine for airport const byte *terminals; ///< %Array with the number of terminal groups, followed by the number of terminals in each group. const byte num_helipads; ///< Number of helipads on this airport. When 0 helicopters will go to normal terminals. Flags flags; ///< Flags for this airport type. byte nofelements; ///< number of positions the airport consists of const byte *entry_points; ///< when an airplane arrives at this airport, enter it at position entry_point, index depends on direction byte delta_z; ///< Z adjustment for helicopter pads }; DECLARE_ENUM_AS_BIT_SET(AirportFTAClass::Flags) /** Internal structure used in openttd - Finite sTate mAchine --> FTA */ struct AirportFTA { AirportFTA *next; ///< possible extra movement choices from this position uint64 block; ///< 64 bit blocks (st->airport.flags), should be enough for the most complex airports byte position; ///< the position that an airplane is at byte next_position; ///< next position from this position byte heading; ///< heading (current orders), guiding an airplane to its target on an airport }; const AirportFTAClass *GetAirport(const byte airport_type); byte GetVehiclePosOnBuild(TileIndex hangar_tile); #endif /* AIRPORT_H */ openttd-1.5.3/src/tilehighlight_type.h0000644000000000000000000001047112627373442016536 0ustar rootroot/* $Id: tilehighlight_type.h 23595 2011-12-19 17:48:04Z rubidium $ */ /* * 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 tilehighlight_type.h Types related to highlighting tiles. */ #ifndef TILEHIGHLIGHT_TYPE_H #define TILEHIGHLIGHT_TYPE_H #include "core/geometry_type.hpp" #include "window_type.h" #include "tile_type.h" #include "viewport_type.h" /** Highlighting draw styles */ enum HighLightStyle { HT_NONE = 0x000, ///< default HT_RECT = 0x010, ///< rectangle (stations, depots, ...) HT_POINT = 0x020, ///< point (lower land, raise land, level land, ...) HT_SPECIAL = 0x030, ///< special mode used for highlighting while dragging (and for tunnels/docks) HT_DRAG = 0x040, ///< dragging items in the depot windows HT_LINE = 0x008, ///< used for autorail highlighting (longer stretches), lower bits: direction HT_RAIL = 0x080, ///< autorail (one piece), lower bits: direction HT_VEHICLE = 0x100, ///< vehicle is accepted as target as well (bitmask) HT_DIAGONAL = 0x200, ///< Also allow 'diagonal rectangles'. Only usable in combination with #HT_RECT or #HT_POINT. HT_DRAG_MASK = 0x0F8, ///< Mask for the tile drag-type modes. /* lower bits (used with HT_LINE and HT_RAIL): * (see ASCII art in table/autorail.h for a visual interpretation) */ HT_DIR_X = 0, ///< X direction HT_DIR_Y = 1, ///< Y direction HT_DIR_HU = 2, ///< horizontal upper HT_DIR_HL = 3, ///< horizontal lower HT_DIR_VL = 4, ///< vertical left HT_DIR_VR = 5, ///< vertical right HT_DIR_END, ///< end marker HT_DIR_MASK = 0x7, ///< masks the drag-direction }; DECLARE_ENUM_AS_BIT_SET(HighLightStyle) /** Metadata about the current highlighting. */ struct TileHighlightData { Point pos; ///< Location, in tile "units", of the northern tile of the selected area. Point size; ///< Size, in tile "units", of the white/red selection area. Point offs; ///< Offset, in tile "units", for the blue coverage area from the selected area's northern tile. Point outersize; ///< Size, in tile "units", of the blue coverage area excluding the side of the selected area. bool diagonal; ///< Whether the dragged area is a 45 degrees rotated rectangle. Point new_pos; ///< New value for \a pos; used to determine whether to redraw the selection. Point new_size; ///< New value for \a size; used to determine whether to redraw the selection. Point new_outersize; ///< New value for \a outersize; used to determine whether to redraw the selection. byte dirty; ///< Whether the build station window needs to redraw due to the changed selection. Point selstart; ///< The location where the dragging started. Point selend; ///< The location where the drag currently ends. byte sizelimit; ///< Whether the selection is limited in length, and what the maximum length is. HighLightStyle drawstyle; ///< Lower bits 0-3 are reserved for detailed highlight information. HighLightStyle next_drawstyle; ///< Queued, but not yet drawn style. HighLightStyle place_mode; ///< Method which is used to place the selection. WindowClass window_class; ///< The \c WindowClass of the window that is responsible for the selection mode. WindowNumber window_number; ///< The \c WindowNumber of the window that is responsible for the selection mode. bool make_square_red; ///< Whether to give a tile a red selection. TileIndex redsq; ///< The tile that has to get a red selection. ViewportPlaceMethod select_method; ///< The method which governs how tiles are selected. ViewportDragDropSelectionProcess select_proc; ///< The procedure that has to be called when the selection is done. void Reset(); bool IsDraggingDiagonal(); Window *GetCallbackWnd(); }; #endif /* TILEHIGHLIGHT_TYPE_H */ openttd-1.5.3/src/screenshot.cpp0000644000000000000000000006307712627373441015371 0ustar rootroot/* $Id: screenshot.cpp 26983 2014-10-09 19:52:07Z frosch $ */ /* * 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 screenshot.cpp The creation of screenshots! */ #include "stdafx.h" #include "fileio_func.h" #include "viewport_func.h" #include "gfx_func.h" #include "screenshot.h" #include "blitter/factory.hpp" #include "zoom_func.h" #include "core/endian_func.hpp" #include "saveload/saveload.h" #include "company_func.h" #include "strings_func.h" #include "error.h" #include "window_gui.h" #include "window_func.h" #include "tile_map.h" #include "landscape.h" #include "table/strings.h" #include "safeguards.h" static const char * const SCREENSHOT_NAME = "screenshot"; ///< Default filename of a saved screenshot. static const char * const HEIGHTMAP_NAME = "heightmap"; ///< Default filename of a saved heightmap. char _screenshot_format_name[8]; ///< Extension of the current screenshot format (corresponds with #_cur_screenshot_format). uint _num_screenshot_formats; ///< Number of available screenshot formats. uint _cur_screenshot_format; ///< Index of the currently selected screenshot format in #_screenshot_formats. static char _screenshot_name[128]; ///< Filename of the screenshot file. char _full_screenshot_name[MAX_PATH]; ///< Pathname of the screenshot file. /** * Callback function signature for generating lines of pixel data to be written to the screenshot file. * @param userdata Pointer to user data. * @param buf Destination buffer. * @param y Line number of the first line to write. * @param pitch Number of pixels to write (1 byte for 8bpp, 4 bytes for 32bpp). @see Colour * @param n Number of lines to write. */ typedef void ScreenshotCallback(void *userdata, void *buf, uint y, uint pitch, uint n); /** * Function signature for a screenshot generation routine for one of the available formats. * @param name Filename, including extension. * @param callb Callback function for generating lines of pixels. * @param userdata User data, passed on to \a callb. * @param w Width of the image in pixels. * @param h Height of the image in pixels. * @param pixelformat Bits per pixel (bpp), either 8 or 32. * @param palette %Colour palette (for 8bpp images). * @return File was written successfully. */ typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette); /** Screenshot format information. */ struct ScreenshotFormat { const char *extension; ///< File extension. ScreenshotHandlerProc *proc; ///< Function for writing the screenshot. }; /************************************************* **** SCREENSHOT CODE FOR WINDOWS BITMAP (.BMP) *************************************************/ #if defined(_MSC_VER) || defined(__WATCOMC__) #pragma pack(push, 1) #endif /** BMP File Header (stored in little endian) */ struct BitmapFileHeader { uint16 type; uint32 size; uint32 reserved; uint32 off_bits; } GCC_PACK; assert_compile(sizeof(BitmapFileHeader) == 14); #if defined(_MSC_VER) || defined(__WATCOMC__) #pragma pack(pop) #endif /** BMP Info Header (stored in little endian) */ struct BitmapInfoHeader { uint32 size; int32 width, height; uint16 planes, bitcount; uint32 compression, sizeimage, xpels, ypels, clrused, clrimp; }; assert_compile(sizeof(BitmapInfoHeader) == 40); /** Format of palette data in BMP header */ struct RgbQuad { byte blue, green, red, reserved; }; assert_compile(sizeof(RgbQuad) == 4); /** * Generic .BMP writer * @param name file name including extension * @param callb callback used for gathering rendered image * @param userdata parameters forwarded to \a callb * @param w width in pixels * @param h height in pixels * @param pixelformat bits per pixel * @param palette colour palette (for 8bpp mode) * @return was everything ok? * @see ScreenshotHandlerProc */ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) { uint bpp; // bytes per pixel switch (pixelformat) { case 8: bpp = 1; break; /* 32bpp mode is saved as 24bpp BMP */ case 32: bpp = 3; break; /* Only implemented for 8bit and 32bit images so far */ default: return false; } FILE *f = fopen(name, "wb"); if (f == NULL) return false; /* Each scanline must be aligned on a 32bit boundary */ uint bytewidth = Align(w * bpp, 4); // bytes per line in file /* Size of palette. Only present for 8bpp mode */ uint pal_size = pixelformat == 8 ? sizeof(RgbQuad) * 256 : 0; /* Setup the file header */ BitmapFileHeader bfh; bfh.type = TO_LE16('MB'); bfh.size = TO_LE32(sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + pal_size + bytewidth * h); bfh.reserved = 0; bfh.off_bits = TO_LE32(sizeof(BitmapFileHeader) + sizeof(BitmapInfoHeader) + pal_size); /* Setup the info header */ BitmapInfoHeader bih; bih.size = TO_LE32(sizeof(BitmapInfoHeader)); bih.width = TO_LE32(w); bih.height = TO_LE32(h); bih.planes = TO_LE16(1); bih.bitcount = TO_LE16(bpp * 8); bih.compression = 0; bih.sizeimage = 0; bih.xpels = 0; bih.ypels = 0; bih.clrused = 0; bih.clrimp = 0; /* Write file header and info header */ if (fwrite(&bfh, sizeof(bfh), 1, f) != 1 || fwrite(&bih, sizeof(bih), 1, f) != 1) { fclose(f); return false; } if (pixelformat == 8) { /* Convert the palette to the windows format */ RgbQuad rq[256]; for (uint i = 0; i < 256; i++) { rq[i].red = palette[i].r; rq[i].green = palette[i].g; rq[i].blue = palette[i].b; rq[i].reserved = 0; } /* Write the palette */ if (fwrite(rq, sizeof(rq), 1, f) != 1) { fclose(f); return false; } } /* Try to use 64k of memory, store between 16 and 128 lines */ uint maxlines = Clamp(65536 / (w * pixelformat / 8), 16, 128); // number of lines per iteration uint8 *buff = MallocT(maxlines * w * pixelformat / 8); // buffer which is rendered to uint8 *line = AllocaM(uint8, bytewidth); // one line, stored to file memset(line, 0, bytewidth); /* Start at the bottom, since bitmaps are stored bottom up */ do { uint n = min(h, maxlines); h -= n; /* Render the pixels */ callb(userdata, buff, h, w, n); /* Write each line */ while (n-- != 0) { if (pixelformat == 8) { /* Move to 'line', leave last few pixels in line zeroed */ memcpy(line, buff + n * w, w); } else { /* Convert from 'native' 32bpp to BMP-like 24bpp. * Works for both big and little endian machines */ Colour *src = ((Colour *)buff) + n * w; byte *dst = line; for (uint i = 0; i < w; i++) { dst[i * 3 ] = src[i].b; dst[i * 3 + 1] = src[i].g; dst[i * 3 + 2] = src[i].r; } } /* Write to file */ if (fwrite(line, bytewidth, 1, f) != 1) { free(buff); fclose(f); return false; } } } while (h != 0); free(buff); fclose(f); return true; } /********************************************************* **** SCREENSHOT CODE FOR PORTABLE NETWORK GRAPHICS (.PNG) *********************************************************/ #if defined(WITH_PNG) #include #ifdef PNG_TEXT_SUPPORTED #include "rev.h" #include "newgrf_config.h" #include "ai/ai_info.hpp" #include "company_base.h" #include "base_media_base.h" #endif /* PNG_TEXT_SUPPORTED */ static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message) { DEBUG(misc, 0, "[libpng] error: %s - %s", message, (const char *)png_get_error_ptr(png_ptr)); longjmp(png_jmpbuf(png_ptr), 1); } static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message) { DEBUG(misc, 1, "[libpng] warning: %s - %s", message, (const char *)png_get_error_ptr(png_ptr)); } /** * Generic .PNG file image writer. * @param name Filename, including extension. * @param callb Callback function for generating lines of pixels. * @param userdata User data, passed on to \a callb. * @param w Width of the image in pixels. * @param h Height of the image in pixels. * @param pixelformat Bits per pixel (bpp), either 8 or 32. * @param palette %Colour palette (for 8bpp images). * @return File was written successfully. * @see ScreenshotHandlerProc */ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) { png_color rq[256]; FILE *f; uint i, y, n; uint maxlines; uint bpp = pixelformat / 8; png_structp png_ptr; png_infop info_ptr; /* only implemented for 8bit and 32bit images so far. */ if (pixelformat != 8 && pixelformat != 32) return false; f = fopen(name, "wb"); if (f == NULL) return false; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast(name), png_my_error, png_my_warning); if (png_ptr == NULL) { fclose(f); return false; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); fclose(f); return false; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(f); return false; } png_init_io(png_ptr, f); png_set_filter(png_ptr, 0, PNG_FILTER_NONE); png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); #ifdef PNG_TEXT_SUPPORTED /* Try to add some game metadata to the PNG screenshot so * it's more useful for debugging and archival purposes. */ png_text_struct text[2]; memset(text, 0, sizeof(text)); text[0].key = const_cast("Software"); text[0].text = const_cast(_openttd_revision); text[0].text_length = strlen(_openttd_revision); text[0].compression = PNG_TEXT_COMPRESSION_NONE; char buf[8192]; char *p = buf; p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version); p = strecpy(p, "NewGRFs:\n", lastof(buf)); for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) { p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid)); p = md5sumToString(p, lastof(buf), c->ident.md5sum); p += seprintf(p, lastof(buf), " %s\n", c->filename); } p = strecpy(p, "\nCompanies:\n", lastof(buf)); const Company *c; FOR_ALL_COMPANIES(c) { if (c->ai_info == NULL) { p += seprintf(p, lastof(buf), "%2i: Human\n", (int)c->index); } else { p += seprintf(p, lastof(buf), "%2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion()); } } text[1].key = const_cast("Description"); text[1].text = buf; text[1].text_length = p - buf; text[1].compression = PNG_TEXT_COMPRESSION_zTXt; png_set_text(png_ptr, info_ptr, text, 2); #endif /* PNG_TEXT_SUPPORTED */ if (pixelformat == 8) { /* convert the palette to the .PNG format. */ for (i = 0; i != 256; i++) { rq[i].red = palette[i].r; rq[i].green = palette[i].g; rq[i].blue = palette[i].b; } png_set_PLTE(png_ptr, info_ptr, rq, 256); } png_write_info(png_ptr, info_ptr); png_set_flush(png_ptr, 512); if (pixelformat == 32) { png_color_8 sig_bit; /* Save exact colour/alpha resolution */ sig_bit.alpha = 0; sig_bit.blue = 8; sig_bit.green = 8; sig_bit.red = 8; sig_bit.gray = 8; png_set_sBIT(png_ptr, info_ptr, &sig_bit); #if TTD_ENDIAN == TTD_LITTLE_ENDIAN png_set_bgr(png_ptr); png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); #else png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); #endif /* TTD_ENDIAN == TTD_LITTLE_ENDIAN */ } /* use by default 64k temp memory */ maxlines = Clamp(65536 / w, 16, 128); /* now generate the bitmap bits */ void *buff = CallocT(w * maxlines * bpp); // by default generate 128 lines at a time. y = 0; do { /* determine # lines to write */ n = min(h - y, maxlines); /* render the pixels into the buffer */ callb(userdata, buff, y, w, n); y += n; /* write them to png */ for (i = 0; i != n; i++) { png_write_row(png_ptr, (png_bytep)buff + i * w * bpp); } } while (y != h); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); free(buff); fclose(f); return true; } #endif /* WITH_PNG */ /************************************************* **** SCREENSHOT CODE FOR ZSOFT PAINTBRUSH (.PCX) *************************************************/ /** Definition of a PCX file header. */ struct PcxHeader { byte manufacturer; byte version; byte rle; byte bpp; uint32 unused; uint16 xmax, ymax; uint16 hdpi, vdpi; byte pal_small[16 * 3]; byte reserved; byte planes; uint16 pitch; uint16 cpal; uint16 width; uint16 height; byte filler[54]; }; assert_compile(sizeof(PcxHeader) == 128); /** * Generic .PCX file image writer. * @param name Filename, including extension. * @param callb Callback function for generating lines of pixels. * @param userdata User data, passed on to \a callb. * @param w Width of the image in pixels. * @param h Height of the image in pixels. * @param pixelformat Bits per pixel (bpp), either 8 or 32. * @param palette %Colour palette (for 8bpp images). * @return File was written successfully. * @see ScreenshotHandlerProc */ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) { FILE *f; uint maxlines; uint y; PcxHeader pcx; bool success; if (pixelformat == 32) { DEBUG(misc, 0, "Can't convert a 32bpp screenshot to PCX format. Please pick another format."); return false; } if (pixelformat != 8 || w == 0) return false; f = fopen(name, "wb"); if (f == NULL) return false; memset(&pcx, 0, sizeof(pcx)); /* setup pcx header */ pcx.manufacturer = 10; pcx.version = 5; pcx.rle = 1; pcx.bpp = 8; pcx.xmax = TO_LE16(w - 1); pcx.ymax = TO_LE16(h - 1); pcx.hdpi = TO_LE16(320); pcx.vdpi = TO_LE16(320); pcx.planes = 1; pcx.cpal = TO_LE16(1); pcx.width = pcx.pitch = TO_LE16(w); pcx.height = TO_LE16(h); /* write pcx header */ if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) { fclose(f); return false; } /* use by default 64k temp memory */ maxlines = Clamp(65536 / w, 16, 128); /* now generate the bitmap bits */ uint8 *buff = CallocT(w * maxlines); // by default generate 128 lines at a time. y = 0; do { /* determine # lines to write */ uint n = min(h - y, maxlines); uint i; /* render the pixels into the buffer */ callb(userdata, buff, y, w, n); y += n; /* write them to pcx */ for (i = 0; i != n; i++) { const uint8 *bufp = buff + i * w; byte runchar = bufp[0]; uint runcount = 1; uint j; /* for each pixel... */ for (j = 1; j < w; j++) { uint8 ch = bufp[j]; if (ch != runchar || runcount >= 0x3f) { if (runcount > 1 || (runchar & 0xC0) == 0xC0) { if (fputc(0xC0 | runcount, f) == EOF) { free(buff); fclose(f); return false; } } if (fputc(runchar, f) == EOF) { free(buff); fclose(f); return false; } runcount = 0; runchar = ch; } runcount++; } /* write remaining bytes.. */ if (runcount > 1 || (runchar & 0xC0) == 0xC0) { if (fputc(0xC0 | runcount, f) == EOF) { free(buff); fclose(f); return false; } } if (fputc(runchar, f) == EOF) { free(buff); fclose(f); return false; } } } while (y != h); free(buff); /* write 8-bit colour palette */ if (fputc(12, f) == EOF) { fclose(f); return false; } /* Palette is word-aligned, copy it to a temporary byte array */ byte tmp[256 * 3]; for (uint i = 0; i < 256; i++) { tmp[i * 3 + 0] = palette[i].r; tmp[i * 3 + 1] = palette[i].g; tmp[i * 3 + 2] = palette[i].b; } success = fwrite(tmp, sizeof(tmp), 1, f) == 1; fclose(f); return success; } /************************************************* **** GENERIC SCREENSHOT CODE *************************************************/ /** Available screenshot formats. */ static const ScreenshotFormat _screenshot_formats[] = { #if defined(WITH_PNG) {"png", &MakePNGImage}, #endif {"bmp", &MakeBMPImage}, {"pcx", &MakePCXImage}, }; /** Get filename extension of current screenshot file format. */ const char *GetCurrentScreenshotExtension() { return _screenshot_formats[_cur_screenshot_format].extension; } /** Initialize screenshot format information on startup, with #_screenshot_format_name filled from the loadsave code. */ void InitializeScreenshotFormats() { uint j = 0; for (uint i = 0; i < lengthof(_screenshot_formats); i++) { if (!strcmp(_screenshot_format_name, _screenshot_formats[i].extension)) { j = i; break; } } _cur_screenshot_format = j; _num_screenshot_formats = lengthof(_screenshot_formats); } /** * Callback of the screenshot generator that dumps the current video buffer. * @see ScreenshotCallback */ static void CurrentScreenCallback(void *userdata, void *buf, uint y, uint pitch, uint n) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); void *src = blitter->MoveTo(_screen.dst_ptr, 0, y); blitter->CopyImageToBuffer(src, buf, _screen.width, n, pitch); } /** * generate a large piece of the world * @param userdata Viewport area to draw * @param buf Videobuffer with same bitdepth as current blitter * @param y First line to render * @param pitch Pitch of the videobuffer * @param n Number of lines to render */ static void LargeWorldCallback(void *userdata, void *buf, uint y, uint pitch, uint n) { ViewPort *vp = (ViewPort *)userdata; DrawPixelInfo dpi, *old_dpi; int wx, left; /* We are no longer rendering to the screen */ DrawPixelInfo old_screen = _screen; bool old_disable_anim = _screen_disable_anim; _screen.dst_ptr = buf; _screen.width = pitch; _screen.height = n; _screen.pitch = pitch; _screen_disable_anim = true; old_dpi = _cur_dpi; _cur_dpi = &dpi; dpi.dst_ptr = buf; dpi.height = n; dpi.width = vp->width; dpi.pitch = pitch; dpi.zoom = ZOOM_LVL_WORLD_SCREENSHOT; dpi.left = 0; dpi.top = y; /* Render viewport in blocks of 1600 pixels width */ left = 0; while (vp->width - left != 0) { wx = min(vp->width - left, 1600); left += wx; ViewportDoDraw(vp, ScaleByZoom(left - wx - vp->left, vp->zoom) + vp->virtual_left, ScaleByZoom(y - vp->top, vp->zoom) + vp->virtual_top, ScaleByZoom(left - vp->left, vp->zoom) + vp->virtual_left, ScaleByZoom((y + n) - vp->top, vp->zoom) + vp->virtual_top ); } _cur_dpi = old_dpi; /* Switch back to rendering to the screen */ _screen = old_screen; _screen_disable_anim = old_disable_anim; } /** * Construct a pathname for a screenshot file. * @param default_fn Default filename. * @param ext Extension to use. * @param crashlog Create path for crash.png * @return Pathname for a screenshot file. */ static const char *MakeScreenshotName(const char *default_fn, const char *ext, bool crashlog = false) { bool generate = StrEmpty(_screenshot_name); if (generate) { if (_game_mode == GM_EDITOR || _game_mode == GM_MENU || _local_company == COMPANY_SPECTATOR) { strecpy(_screenshot_name, default_fn, lastof(_screenshot_name)); } else { GenerateDefaultSaveName(_screenshot_name, lastof(_screenshot_name)); } } /* Add extension to screenshot file */ size_t len = strlen(_screenshot_name); seprintf(&_screenshot_name[len], lastof(_screenshot_name), ".%s", ext); const char *screenshot_dir = crashlog ? _personal_dir : FiosGetScreenshotDir(); for (uint serial = 1;; serial++) { if (seprintf(_full_screenshot_name, lastof(_full_screenshot_name), "%s%s", screenshot_dir, _screenshot_name) >= (int)lengthof(_full_screenshot_name)) { /* We need more characters than MAX_PATH -> end with error */ _full_screenshot_name[0] = '\0'; break; } if (!generate) break; // allow overwriting of non-automatic filenames if (!FileExists(_full_screenshot_name)) break; /* If file exists try another one with same name, but just with a higher index */ seprintf(&_screenshot_name[len], lastof(_screenshot_name) - len, "#%u.%s", serial, ext); } return _full_screenshot_name; } /** Make a screenshot of the current screen. */ static bool MakeSmallScreenshot(bool crashlog) { const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension, crashlog), CurrentScreenCallback, NULL, _screen.width, _screen.height, BlitterFactory::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette); } /** * Configure a ViewPort for rendering (a part of) the map into a screenshot. * @param t Screenshot type * @param [out] vp Result viewport */ void SetupScreenshotViewport(ScreenshotType t, ViewPort *vp) { /* Determine world coordinates of screenshot */ if (t == SC_WORLD) { vp->zoom = ZOOM_LVL_WORLD_SCREENSHOT; TileIndex north_tile = _settings_game.construction.freeform_edges ? TileXY(1, 1) : TileXY(0, 0); TileIndex south_tile = MapSize() - 1; /* We need to account for a hill or high building at tile 0,0. */ int extra_height_top = TilePixelHeight(north_tile) + 150; /* If there is a hill at the bottom don't create a large black area. */ int reclaim_height_bottom = TilePixelHeight(south_tile); vp->virtual_left = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, 0).x; vp->virtual_top = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, extra_height_top).y; vp->virtual_width = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, 0).x - vp->virtual_left + 1; vp->virtual_height = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, reclaim_height_bottom).y - vp->virtual_top + 1; } else { vp->zoom = (t == SC_ZOOMEDIN) ? _settings_client.gui.zoom_min : ZOOM_LVL_VIEWPORT; Window *w = FindWindowById(WC_MAIN_WINDOW, 0); vp->virtual_left = w->viewport->virtual_left; vp->virtual_top = w->viewport->virtual_top; vp->virtual_width = w->viewport->virtual_width; vp->virtual_height = w->viewport->virtual_height; } /* Compute pixel coordinates */ vp->left = 0; vp->top = 0; vp->width = UnScaleByZoom(vp->virtual_width, vp->zoom); vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom); vp->overlay = NULL; } /** * Make a screenshot of the map. * @param t Screenshot type: World or viewport screenshot * @return true on success */ static bool MakeLargeWorldScreenshot(ScreenshotType t) { ViewPort vp; SetupScreenshotViewport(t, &vp); const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), LargeWorldCallback, &vp, vp.width, vp.height, BlitterFactory::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette); } /** * Callback for generating a heightmap. Supports 8bpp grayscale only. * @param userdata Pointer to user data. * @param buf Destination buffer. * @param y Line number of the first line to write. * @param pitch Number of pixels to write (1 byte for 8bpp, 4 bytes for 32bpp). @see Colour * @param n Number of lines to write. * @see ScreenshotCallback */ static void HeightmapCallback(void *userdata, void *buffer, uint y, uint pitch, uint n) { byte *buf = (byte *)buffer; while (n > 0) { TileIndex ti = TileXY(MapMaxX(), y); for (uint x = MapMaxX(); true; x--) { *buf = 256 * TileHeight(ti) / (1 + _settings_game.construction.max_heightlevel); buf++; if (x == 0) break; ti = TILE_ADDXY(ti, -1, 0); } y++; n--; } } /** * Make a heightmap of the current map. * @param filename Filename to use for saving. */ bool MakeHeightmapScreenshot(const char *filename) { Colour palette[256]; for (uint i = 0; i < lengthof(palette); i++) { palette[i].a = 0xff; palette[i].r = i; palette[i].g = i; palette[i].b = i; } const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; return sf->proc(filename, HeightmapCallback, NULL, MapSizeX(), MapSizeY(), 8, palette); } /** * Make an actual screenshot. * @param t the type of screenshot to make. * @param name the name to give to the screenshot. * @return true iff the screenshot was made successfully */ bool MakeScreenshot(ScreenshotType t, const char *name) { if (t == SC_VIEWPORT) { /* First draw the dirty parts of the screen and only then change the name * of the screenshot. This way the screenshot will always show the name * of the previous screenshot in the 'successful' message instead of the * name of the new screenshot (or an empty name). */ UndrawMouseCursor(); DrawDirtyBlocks(); } _screenshot_name[0] = '\0'; if (name != NULL) strecpy(_screenshot_name, name, lastof(_screenshot_name)); bool ret; switch (t) { case SC_VIEWPORT: ret = MakeSmallScreenshot(false); break; case SC_CRASHLOG: ret = MakeSmallScreenshot(true); break; case SC_ZOOMEDIN: case SC_DEFAULTZOOM: case SC_WORLD: ret = MakeLargeWorldScreenshot(t); break; case SC_HEIGHTMAP: { const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format; ret = MakeHeightmapScreenshot(MakeScreenshotName(HEIGHTMAP_NAME, sf->extension)); break; } default: NOT_REACHED(); } if (ret) { SetDParamStr(0, _screenshot_name); ShowErrorMessage(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING); } else { ShowErrorMessage(STR_ERROR_SCREENSHOT_FAILED, INVALID_STRING_ID, WL_ERROR); } return ret; } openttd-1.5.3/src/vehicle_gui.cpp0000644000000000000000000031511612627373441015471 0ustar rootroot/* $Id: vehicle_gui.cpp 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 vehicle_gui.cpp The base GUI for all vehicles. */ #include "stdafx.h" #include "debug.h" #include "company_func.h" #include "gui.h" #include "textbuf_gui.h" #include "command_func.h" #include "vehicle_gui_base.h" #include "viewport_func.h" #include "newgrf_text.h" #include "newgrf_debug.h" #include "roadveh.h" #include "train.h" #include "aircraft.h" #include "depot_map.h" #include "group_gui.h" #include "strings_func.h" #include "vehicle_func.h" #include "autoreplace_gui.h" #include "string_func.h" #include "widgets/dropdown_func.h" #include "timetable.h" #include "articulated_vehicles.h" #include "spritecache.h" #include "core/geometry_func.hpp" #include "company_base.h" #include "engine_func.h" #include "station_base.h" #include "tilehighlight_func.h" #include "zoom_func.h" #include "safeguards.h" Sorting _sorting; static GUIVehicleList::SortFunction VehicleNumberSorter; static GUIVehicleList::SortFunction VehicleNameSorter; static GUIVehicleList::SortFunction VehicleAgeSorter; static GUIVehicleList::SortFunction VehicleProfitThisYearSorter; static GUIVehicleList::SortFunction VehicleProfitLastYearSorter; static GUIVehicleList::SortFunction VehicleCargoSorter; static GUIVehicleList::SortFunction VehicleReliabilitySorter; static GUIVehicleList::SortFunction VehicleMaxSpeedSorter; static GUIVehicleList::SortFunction VehicleModelSorter; static GUIVehicleList::SortFunction VehicleValueSorter; static GUIVehicleList::SortFunction VehicleLengthSorter; static GUIVehicleList::SortFunction VehicleTimeToLiveSorter; static GUIVehicleList::SortFunction VehicleTimetableDelaySorter; GUIVehicleList::SortFunction * const BaseVehicleListWindow::vehicle_sorter_funcs[] = { &VehicleNumberSorter, &VehicleNameSorter, &VehicleAgeSorter, &VehicleProfitThisYearSorter, &VehicleProfitLastYearSorter, &VehicleCargoSorter, &VehicleReliabilitySorter, &VehicleMaxSpeedSorter, &VehicleModelSorter, &VehicleValueSorter, &VehicleLengthSorter, &VehicleTimeToLiveSorter, &VehicleTimetableDelaySorter, }; const StringID BaseVehicleListWindow::vehicle_sorter_names[] = { STR_SORT_BY_NUMBER, STR_SORT_BY_NAME, STR_SORT_BY_AGE, STR_SORT_BY_PROFIT_THIS_YEAR, STR_SORT_BY_PROFIT_LAST_YEAR, STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE, STR_SORT_BY_RELIABILITY, STR_SORT_BY_MAX_SPEED, STR_SORT_BY_MODEL, STR_SORT_BY_VALUE, STR_SORT_BY_LENGTH, STR_SORT_BY_LIFE_TIME, STR_SORT_BY_TIMETABLE_DELAY, INVALID_STRING_ID }; const StringID BaseVehicleListWindow::vehicle_depot_name[] = { STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT, STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT, STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT, STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR }; /** * Get the number of digits the biggest unit number of a set of vehicles has. * @param vehicles The list of vehicles. * @return The number of digits to allocate space for. */ uint GetUnitNumberDigits(VehicleList &vehicles) { uint unitnumber = 0; for (const Vehicle **v = vehicles.Begin(); v != vehicles.End(); v++) { unitnumber = max(unitnumber, (*v)->unitnumber); } if (unitnumber >= 10000) return 5; if (unitnumber >= 1000) return 4; if (unitnumber >= 100) return 3; /* * When the smallest unit number is less than 10, it is * quite likely that it will expand to become more than * 10 quite soon. */ return 2; } void BaseVehicleListWindow::BuildVehicleList() { if (!this->vehicles.NeedRebuild()) return; DEBUG(misc, 3, "Building vehicle list type %d for company %d given index %d", this->vli.type, this->vli.company, this->vli.index); GenerateVehicleSortList(&this->vehicles, this->vli); this->unitnumber_digits = GetUnitNumberDigits(this->vehicles); this->vehicles.RebuildDone(); this->vscroll->SetCount(this->vehicles.Length()); } /** * Compute the size for the Action dropdown. * @param show_autoreplace If true include the autoreplace item. * @param show_group If true include group-related stuff. * @return Required size. */ Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bool show_group) { Dimension d = {0, 0}; if (show_autoreplace) d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_REPLACE_VEHICLES)); d = maxdim(d, GetStringBoundingBox(STR_VEHICLE_LIST_SEND_FOR_SERVICING)); d = maxdim(d, GetStringBoundingBox(this->vehicle_depot_name[this->vli.vtype])); if (show_group) { d = maxdim(d, GetStringBoundingBox(STR_GROUP_ADD_SHARED_VEHICLE)); d = maxdim(d, GetStringBoundingBox(STR_GROUP_REMOVE_ALL_VEHICLES)); } return d; } /** * Display the Action dropdown window. * @param show_autoreplace If true include the autoreplace item. * @param show_group If true include group-related stuff. * @return Itemlist for dropdown */ DropDownList *BaseVehicleListWindow::BuildActionDropdownList(bool show_autoreplace, bool show_group) { DropDownList *list = new DropDownList(); if (show_autoreplace) *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_REPLACE_VEHICLES, ADI_REPLACE, false); *list->Append() = new DropDownListStringItem(STR_VEHICLE_LIST_SEND_FOR_SERVICING, ADI_SERVICE, false); *list->Append() = new DropDownListStringItem(this->vehicle_depot_name[this->vli.vtype], ADI_DEPOT, false); if (show_group) { *list->Append() = new DropDownListStringItem(STR_GROUP_ADD_SHARED_VEHICLE, ADI_ADD_SHARED, false); *list->Append() = new DropDownListStringItem(STR_GROUP_REMOVE_ALL_VEHICLES, ADI_REMOVE_ALL, false); } return list; } /* cached values for VehicleNameSorter to spare many GetString() calls */ static const Vehicle *_last_vehicle[2] = { NULL, NULL }; void BaseVehicleListWindow::SortVehicleList() { if (this->vehicles.Sort()) return; /* invalidate cached values for name sorter - vehicle names could change */ _last_vehicle[0] = _last_vehicle[1] = NULL; } void DepotSortList(VehicleList *list) { if (list->Length() < 2) return; QSortT(list->Begin(), list->Length(), &VehicleNumberSorter); } /** draw the vehicle profit button in the vehicle list window. */ static void DrawVehicleProfitButton(const Vehicle *v, int x, int y) { SpriteID spr; /* draw profit-based coloured icons */ if (v->age <= VEHICLE_PROFIT_MIN_AGE) { spr = SPR_PROFIT_NA; } else if (v->GetDisplayProfitLastYear() < 0) { spr = SPR_PROFIT_NEGATIVE; } else if (v->GetDisplayProfitLastYear() < VEHICLE_PROFIT_THRESHOLD) { spr = SPR_PROFIT_SOME; } else { spr = SPR_PROFIT_LOT; } DrawSprite(spr, PAL_NONE, x, y); } /** Maximum number of refit cycles we try, to prevent infinite loops. And we store only a byte anyway */ static const uint MAX_REFIT_CYCLE = 256; /** * Get the best fitting subtype when 'cloning'/'replacing' \a v_from with \a v_for. * All articulated parts of both vehicles are tested to find a possibly shared subtype. * For \a v_for only vehicle refittable to \a dest_cargo_type are considered. * @param v_from the vehicle to match the subtype from * @param v_for the vehicle to get the subtype for * @param dest_cargo_type Destination cargo type. * @return the best sub type */ byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_type) { v_from = v_from->GetFirstEnginePart(); v_for = v_for->GetFirstEnginePart(); /* Create a list of subtypes used by the various parts of v_for */ static SmallVector subtypes; subtypes.Clear(); for (; v_from != NULL; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : NULL) { const Engine *e_from = v_from->GetEngine(); if (!e_from->CanCarryCargo() || !HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; subtypes.Include(GetCargoSubtypeText(v_from)); } byte ret_refit_cyc = 0; bool success = false; if (subtypes.Length() > 0) { /* Check whether any articulated part is refittable to 'dest_cargo_type' with a subtype listed in 'subtypes' */ for (Vehicle *v = v_for; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { const Engine *e = v->GetEngine(); if (!e->CanCarryCargo() || !HasBit(e->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) continue; if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; CargoID old_cargo_type = v->cargo_type; byte old_cargo_subtype = v->cargo_subtype; /* Set the 'destination' cargo */ v->cargo_type = dest_cargo_type; /* Cycle through the refits */ for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { v->cargo_subtype = refit_cyc; /* Make sure we don't pick up anything cached. */ v->First()->InvalidateNewGRFCache(); v->InvalidateNewGRFCache(); StringID subtype = GetCargoSubtypeText(v); if (subtype == STR_EMPTY) break; if (!subtypes.Contains(subtype)) continue; /* We found something matching. */ ret_refit_cyc = refit_cyc; success = true; break; } /* Reset the vehicle's cargo type */ v->cargo_type = old_cargo_type; v->cargo_subtype = old_cargo_subtype; /* Make sure we don't taint the vehicle. */ v->First()->InvalidateNewGRFCache(); v->InvalidateNewGRFCache(); if (success) break; } } return ret_refit_cyc; } /** Option to refit a vehicle chain */ struct RefitOption { CargoID cargo; ///< Cargo to refit to byte subtype; ///< Subcargo to use StringID string; ///< GRF-local String to display for the cargo /** * Inequality operator for #RefitOption. * @param other Compare to this #RefitOption. * @return True if both #RefitOption are different. */ inline bool operator != (const RefitOption &other) const { return other.cargo != this->cargo || other.string != this->string; } /** * Equality operator for #RefitOption. * @param other Compare to this #RefitOption. * @return True if both #RefitOption are equal. */ inline bool operator == (const RefitOption &other) const { return other.cargo == this->cargo && other.string == this->string; } }; typedef SmallVector SubtypeList; ///< List of refit subtypes associated to a cargo. /** * Draw the list of available refit options for a consist and highlight the selected refit option (if any). * @param list List of subtype options for each (sorted) cargo. * @param sel Selected refit cargo-type in the window * @param pos Position of the selected item in caller widow * @param rows Number of rows(capacity) in caller window * @param delta Step height in caller window * @param r Rectangle of the matrix widget. */ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int sel[2], uint pos, uint rows, uint delta, const Rect &r) { uint y = r.top + WD_MATRIX_TOP; uint current = 0; bool rtl = _current_text_dir == TD_RTL; uint iconwidth = max(GetSpriteSize(SPR_CIRCLE_FOLDED).width, GetSpriteSize(SPR_CIRCLE_UNFOLDED).width); uint iconheight = GetSpriteSize(SPR_CIRCLE_FOLDED).height; int linecolour = _colour_gradient[COLOUR_ORANGE][4]; int iconleft = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth : r.left + WD_MATRIX_LEFT; int iconcenter = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth / 2 : r.left + WD_MATRIX_LEFT + iconwidth / 2; int iconinner = rtl ? r.right - WD_MATRIX_RIGHT - iconwidth : r.left + WD_MATRIX_LEFT + iconwidth; int textleft = r.left + WD_MATRIX_LEFT + (rtl ? 0 : iconwidth + 4); int textright = r.right - WD_MATRIX_RIGHT - (rtl ? iconwidth + 4 : 0); /* Draw the list of subtypes for each cargo, and find the selected refit option (by its position). */ for (uint i = 0; current < pos + rows && i < NUM_CARGO; i++) { for (uint j = 0; current < pos + rows && j < list[i].Length(); j++) { const RefitOption &refit = list[i][j]; /* Hide subtypes if sel[0] does not match */ if (sel[0] != (int)i && refit.subtype != 0xFF) continue; /* Refit options with a position smaller than pos don't have to be drawn. */ if (current < pos) { current++; continue; } if (list[i].Length() > 1) { if (refit.subtype != 0xFF) { /* Draw tree lines */ int ycenter = y + FONT_HEIGHT_NORMAL / 2; GfxDrawLine(iconcenter, y - WD_MATRIX_TOP, iconcenter, j == list[i].Length() - 1 ? ycenter : y - WD_MATRIX_TOP + delta - 1, linecolour); GfxDrawLine(iconcenter, ycenter, iconinner, ycenter, linecolour); } else { /* Draw expand/collapse icon */ DrawSprite(sel[0] == (int)i ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED, PAL_NONE, iconleft, y + (FONT_HEIGHT_NORMAL - iconheight) / 2); } } TextColour colour = (sel[0] == (int)i && (uint)sel[1] == j) ? TC_WHITE : TC_BLACK; /* Get the cargo name. */ SetDParam(0, CargoSpec::Get(refit.cargo)->name); SetDParam(1, refit.string); DrawString(textleft, textright, y, STR_JUST_STRING_STRING, colour); y += delta; current++; } } } /** Refit cargo window. */ struct RefitWindow : public Window { int sel[2]; ///< Index in refit options, sel[0] == -1 if nothing is selected. RefitOption *cargo; ///< Refit option selected by #sel. SubtypeList list[NUM_CARGO]; ///< List of refit subtypes available for each sorted cargo. VehicleOrderID order; ///< If not #INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly). uint information_width; ///< Width required for correctly displaying all cargoes in the information panel. Scrollbar *vscroll; ///< The main scrollbar. Scrollbar *hscroll; ///< Only used for long vehicles. int vehicle_width; ///< Width of the vehicle being drawn. int sprite_left; ///< Left position of the vehicle sprite. int sprite_right; ///< Right position of the vehicle sprite. uint vehicle_margin; ///< Margin to use while selecting vehicles when the vehicle image is centered. int click_x; ///< Position of the first click while dragging. VehicleID selected_vehicle; ///< First vehicle in the current selection. uint8 num_vehicles; ///< Number of selected vehicles. bool auto_refit; ///< Select cargo for auto-refitting. /** * Collects all (cargo, subcargo) refit options of a vehicle chain. */ void BuildRefitList() { for (uint i = 0; i < NUM_CARGO; i++) this->list[i].Clear(); Vehicle *v = Vehicle::Get(this->window_number); /* Check only the selected vehicles. */ VehicleSet vehicles_to_refit; GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles); do { if (v->type == VEH_TRAIN && !vehicles_to_refit.Contains(v->index)) continue; const Engine *e = v->GetEngine(); uint32 cmask = e->info.refit_mask; byte callback_mask = e->info.callback_mask; /* Skip this engine if it does not carry anything */ if (!e->CanCarryCargo()) continue; /* Skip this engine if we build the list for auto-refitting and engine doesn't allow it. */ if (this->auto_refit && !HasBit(e->info.misc_flags, EF_AUTO_REFIT)) continue; /* Loop through all cargoes in the refit mask */ int current_index = 0; const CargoSpec *cs; FOR_ALL_SORTED_CARGOSPECS(cs) { CargoID cid = cs->Index(); /* Skip cargo type if it's not listed */ if (!HasBit(cmask, cid)) { current_index++; continue; } bool first_vehicle = this->list[current_index].Length() == 0; if (first_vehicle) { /* Keeping the current subtype is always an option. It also serves as the option in case of no subtypes */ RefitOption *option = this->list[current_index].Append(); option->cargo = cid; option->subtype = 0xFF; option->string = STR_EMPTY; } /* Check the vehicle's callback mask for cargo suffixes. * This is not supported for ordered refits, since subtypes only have a meaning * for a specific vehicle at a specific point in time, which conflicts with shared orders, * autoreplace, autorenew, clone, order restoration, ... */ if (this->order == INVALID_VEH_ORDER_ID && HasBit(callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) { /* Make a note of the original cargo type. It has to be * changed to test the cargo & subtype... */ CargoID temp_cargo = v->cargo_type; byte temp_subtype = v->cargo_subtype; v->cargo_type = cid; for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { v->cargo_subtype = refit_cyc; /* Make sure we don't pick up anything cached. */ v->First()->InvalidateNewGRFCache(); v->InvalidateNewGRFCache(); StringID subtype = GetCargoSubtypeText(v); if (first_vehicle) { /* Append new subtype (don't add duplicates though) */ if (subtype == STR_EMPTY) break; RefitOption option; option.cargo = cid; option.subtype = refit_cyc; option.string = subtype; this->list[current_index].Include(option); } else { /* Intersect the subtypes of earlier vehicles with the subtypes of this vehicle */ if (subtype == STR_EMPTY) { /* No more subtypes for this vehicle, delete all subtypes >= refit_cyc */ SubtypeList &l = this->list[current_index]; /* 0xFF item is in front, other subtypes are sorted. So just truncate the list in the right spot */ for (uint i = 1; i < l.Length(); i++) { if (l[i].subtype >= refit_cyc) { l.Resize(i); break; } } break; } else { /* Check whether the subtype matches with the subtype of earlier vehicles. */ uint pos = 1; SubtypeList &l = this->list[current_index]; while (pos < l.Length() && l[pos].subtype != refit_cyc) pos++; if (pos < l.Length() && l[pos].string != subtype) { /* String mismatch, remove item keeping the order */ l.ErasePreservingOrder(pos); } } } } /* Reset the vehicle's cargo type */ v->cargo_type = temp_cargo; v->cargo_subtype = temp_subtype; /* And make sure we haven't tainted the cache */ v->First()->InvalidateNewGRFCache(); v->InvalidateNewGRFCache(); } current_index++; } } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); } /** * Refresh scrollbar after selection changed */ void RefreshScrollbar() { uint scroll_row = 0; uint row = 0; for (uint i = 0; i < NUM_CARGO; i++) { for (uint j = 0; j < this->list[i].Length(); j++) { const RefitOption &refit = this->list[i][j]; /* Hide subtypes if sel[0] does not match */ if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue; if (this->sel[0] == (int)i && (uint)this->sel[1] == j) scroll_row = row; row++; } } this->vscroll->SetCount(row); if (scroll_row < row) this->vscroll->ScrollTowards(scroll_row); } /** * Select a row. * @param click_row Clicked row */ void SetSelection(uint click_row) { uint row = 0; for (uint i = 0; i < NUM_CARGO; i++) { for (uint j = 0; j < this->list[i].Length(); j++) { const RefitOption &refit = this->list[i][j]; /* Hide subtypes if sel[0] does not match */ if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue; if (row == click_row) { this->sel[0] = i; this->sel[1] = j; return; } row++; } } this->sel[0] = -1; this->sel[1] = 0; } /** * Gets the #RefitOption placed in the selected index. * @return Pointer to the #RefitOption currently in use. */ RefitOption *GetRefitOption() { if (this->sel[0] < 0) return NULL; SubtypeList &l = this->list[this->sel[0]]; if ((uint)this->sel[1] >= l.Length()) return NULL; return &l[this->sel[1]]; } RefitWindow(WindowDesc *desc, const Vehicle *v, VehicleOrderID order, bool auto_refit) : Window(desc) { this->sel[0] = -1; this->sel[1] = 0; this->auto_refit = auto_refit; this->order = order; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_VR_SCROLLBAR); this->hscroll = (v->IsGroundVehicle() ? this->GetScrollbar(WID_VR_HSCROLLBAR) : NULL); this->GetWidget(WID_VR_SELECT_HEADER)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; this->GetWidget(WID_VR_MATRIX)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type; NWidgetCore *nwi = this->GetWidget(WID_VR_REFIT); nwi->widget_data = STR_REFIT_TRAIN_REFIT_BUTTON + v->type; nwi->tool_tip = STR_REFIT_TRAIN_REFIT_TOOLTIP + v->type; this->GetWidget(WID_VR_SHOW_HSCROLLBAR)->SetDisplayedPlane(v->IsGroundVehicle() ? 0 : SZSP_HORIZONTAL); this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY)->tool_tip = (v->type == VEH_TRAIN) ? STR_REFIT_SELECT_VEHICLES_TOOLTIP : STR_NULL; this->FinishInitNested(v->index); this->owner = v->owner; this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); } virtual void OnInit() { if (this->cargo != NULL) { /* Store the RefitOption currently in use. */ RefitOption current_refit_option = *(this->cargo); /* Rebuild the refit list */ this->BuildRefitList(); this->sel[0] = -1; this->sel[1] = 0; this->cargo = NULL; for (uint i = 0; this->cargo == NULL && i < NUM_CARGO; i++) { for (uint j = 0; j < list[i].Length(); j++) { if (list[i][j] == current_refit_option) { this->sel[0] = i; this->sel[1] = j; this->cargo = &list[i][j]; break; } } } this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); this->RefreshScrollbar(); } else { /* Rebuild the refit list */ this->OnInvalidateData(VIWD_CONSIST_CHANGED); } } virtual void OnPaint() { /* Determine amount of items for scroller. */ if (this->hscroll != NULL) this->hscroll->SetCount(this->vehicle_width); /* Calculate sprite position. */ NWidgetCore *vehicle_panel_display = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); int sprite_width = max(0, ((int)vehicle_panel_display->current_x - this->vehicle_width) / 2); this->sprite_left = vehicle_panel_display->pos_x; this->sprite_right = vehicle_panel_display->pos_x + vehicle_panel_display->current_x - 1; if (_current_text_dir == TD_RTL) { this->sprite_right -= sprite_width; this->vehicle_margin = vehicle_panel_display->current_x - sprite_right; } else { this->sprite_left += sprite_width; this->vehicle_margin = sprite_left; } this->DrawWidgets(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_VR_MATRIX: resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; size->height = resize->height * 8; break; case WID_VR_VEHICLE_PANEL_DISPLAY: size->height = ScaleGUITrad(GetVehicleHeight(Vehicle::Get(this->window_number)->type)); break; case WID_VR_INFO: size->width = WD_FRAMERECT_LEFT + this->information_width + WD_FRAMERECT_RIGHT; break; } } virtual void SetStringParameters(int widget) const { if (widget == WID_VR_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); } /** * Gets the #StringID to use for displaying capacity. * @param Cargo and cargo subtype to check for capacity. * @return INVALID_STRING_ID if there is no capacity. StringID to use in any other case. * @post String parameters have been set. */ StringID GetCapacityString(RefitOption *option) const { assert(_current_company == _local_company); Vehicle *v = Vehicle::Get(this->window_number); CommandCost cost = DoCommand(v->tile, this->selected_vehicle, option->cargo | (int)this->auto_refit << 6 | option->subtype << 8 | this->num_vehicles << 16, DC_QUERY_COST, GetCmdRefitVeh(v->type)); if (cost.Failed()) return INVALID_STRING_ID; SetDParam(0, option->cargo); SetDParam(1, _returned_refit_capacity); Money money = cost.GetCost(); if (_returned_mail_refit_capacity > 0) { SetDParam(2, CT_MAIL); SetDParam(3, _returned_mail_refit_capacity); if (this->order != INVALID_VEH_ORDER_ID) { /* No predictable cost */ return STR_PURCHASE_INFO_AIRCRAFT_CAPACITY; } else if (money <= 0) { SetDParam(4, -money); return STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT; } else { SetDParam(4, money); return STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT; } } else { if (this->order != INVALID_VEH_ORDER_ID) { /* No predictable cost */ SetDParam(2, STR_EMPTY); return STR_PURCHASE_INFO_CAPACITY; } else if (money <= 0) { SetDParam(2, -money); return STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT; } else { SetDParam(2, money); return STR_REFIT_NEW_CAPACITY_COST_OF_REFIT; } } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { Vehicle *v = Vehicle::Get(this->window_number); DrawVehicleImage(v, this->sprite_left + WD_FRAMERECT_LEFT, this->sprite_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, this->hscroll != NULL ? this->hscroll->GetPosition() : 0); /* Highlight selected vehicles. */ if (this->order != INVALID_VEH_ORDER_ID) break; int x = 0; switch (v->type) { case VEH_TRAIN: { VehicleSet vehicles_to_refit; GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles); int left = INT32_MIN; int width = 0; for (Train *u = Train::From(v); u != NULL; u = u->Next()) { /* Start checking. */ if (vehicles_to_refit.Contains(u->index) && left == INT32_MIN) { left = x - this->hscroll->GetPosition() + r.left + this->vehicle_margin; width = 0; } /* Draw a selection. */ if ((!vehicles_to_refit.Contains(u->index) || u->Next() == NULL) && left != INT32_MIN) { if (u->Next() == NULL && vehicles_to_refit.Contains(u->index)) { int current_width = u->GetDisplayImageWidth(); width += current_width; x += current_width; } int right = Clamp(left + width, 0, r.right); left = max(0, left); if (_current_text_dir == TD_RTL) { right = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY)->current_x - left; left = right - width; } if (left != right) { DrawFrameRect(left, r.top + WD_FRAMERECT_TOP, right, r.top + WD_FRAMERECT_TOP + ScaleGUITrad(14) - 1, COLOUR_WHITE, FR_BORDERONLY); } left = INT32_MIN; } int current_width = u->GetDisplayImageWidth(); width += current_width; x += current_width; } break; } default: break; } break; } case WID_VR_MATRIX: DrawVehicleRefitWindow(this->list, this->sel, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->resize.step_height, r); break; case WID_VR_INFO: if (this->cargo != NULL) { StringID string = this->GetCapacityString(this->cargo); if (string != INVALID_STRING_ID) { DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, string); } } 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) { switch (data) { case VIWD_AUTOREPLACE: // Autoreplace replaced the vehicle; selected_vehicle became invalid. case VIWD_CONSIST_CHANGED: { // The consist has changed; rebuild the entire list. /* Clear the selection. */ Vehicle *v = Vehicle::Get(this->window_number); this->selected_vehicle = v->index; this->num_vehicles = UINT8_MAX; /* FALL THROUGH */ } case 2: { // The vehicle selection has changed; rebuild the entire list. if (!gui_scope) break; this->BuildRefitList(); /* The vehicle width has changed too. */ this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS); uint max_width = 0; /* Check the width of all cargo information strings. */ for (uint i = 0; i < NUM_CARGO; i++) { for (uint j = 0; j < this->list[i].Length(); j++) { StringID string = this->GetCapacityString(&list[i][j]); if (string != INVALID_STRING_ID) { Dimension dim = GetStringBoundingBox(string); max_width = max(dim.width, max_width); } } } if (this->information_width < max_width) { this->information_width = max_width; this->ReInit(); } /* FALL THROUGH */ } case 1: // A new cargo has been selected. if (!gui_scope) break; this->cargo = GetRefitOption(); this->RefreshScrollbar(); break; } } int GetClickPosition(int click_x) { const NWidgetCore *matrix_widget = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); if (_current_text_dir == TD_RTL) click_x = matrix_widget->current_x - click_x; click_x -= this->vehicle_margin; if (this->hscroll != NULL) click_x += this->hscroll->GetPosition(); return click_x; } void SetSelectedVehicles(int drag_x) { drag_x = GetClickPosition(drag_x); int left_x = min(this->click_x, drag_x); int right_x = max(this->click_x, drag_x); this->num_vehicles = 0; Vehicle *v = Vehicle::Get(this->window_number); /* Find the vehicle part that was clicked. */ switch (v->type) { case VEH_TRAIN: { /* Don't select anything if we are not clicking in the vehicle. */ if (left_x >= 0) { const Train *u = Train::From(v); bool start_counting = false; for (; u != NULL; u = u->Next()) { int current_width = u->GetDisplayImageWidth(); left_x -= current_width; right_x -= current_width; if (left_x < 0 && !start_counting) { this->selected_vehicle = u->index; start_counting = true; /* Count the first vehicle, even if articulated part */ this->num_vehicles++; } else if (start_counting && !u->IsArticulatedPart()) { /* Do not count articulated parts */ this->num_vehicles++; } if (right_x < 0) break; } } /* If the selection is not correct, clear it. */ if (this->num_vehicles != 0) { if (_ctrl_pressed) this->num_vehicles = UINT8_MAX; break; } /* FALL THROUGH */ } default: /* Clear the selection. */ this->selected_vehicle = v->index; this->num_vehicles = UINT8_MAX; break; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. if (this->order != INVALID_VEH_ORDER_ID) break; NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); this->click_x = GetClickPosition(pt.x - nwi->pos_x); this->SetSelectedVehicles(pt.x - nwi->pos_x); this->SetWidgetDirty(WID_VR_VEHICLE_PANEL_DISPLAY); if (!_ctrl_pressed) { SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this); } else { /* The vehicle selection has changed. */ this->InvalidateData(2); } break; } case WID_VR_MATRIX: { // listbox this->SetSelection(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VR_MATRIX)); this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0); this->InvalidateData(1); if (click_count == 1) break; /* FALL THROUGH */ } case WID_VR_REFIT: // refit button if (this->cargo != NULL) { const Vehicle *v = Vehicle::Get(this->window_number); if (this->order == INVALID_VEH_ORDER_ID) { bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX; if (DoCommandP(v->tile, this->selected_vehicle, this->cargo->cargo | this->cargo->subtype << 8 | this->num_vehicles << 16, GetCmdRefitVeh(v)) && delete_window) delete this; } else { if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->order << 16, CMD_ORDER_REFIT)) delete this; } } break; } } virtual void OnMouseDrag(Point pt, int widget) { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. if (this->order != INVALID_VEH_ORDER_ID) break; NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); this->SetSelectedVehicles(pt.x - nwi->pos_x); this->SetWidgetDirty(WID_VR_VEHICLE_PANEL_DISPLAY); break; } } } virtual void OnDragDrop(Point pt, int widget) { switch (widget) { case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image. if (this->order != INVALID_VEH_ORDER_ID) break; NWidgetBase *nwi = this->GetWidget(WID_VR_VEHICLE_PANEL_DISPLAY); this->SetSelectedVehicles(pt.x - nwi->pos_x); this->InvalidateData(2); break; } } } virtual void OnResize() { this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS); this->vscroll->SetCapacityFromWidget(this, WID_VR_MATRIX); if (this->hscroll != NULL) this->hscroll->SetCapacityFromWidget(this, WID_VR_VEHICLE_PANEL_DISPLAY); } }; static const NWidgetPart _nested_vehicle_refit_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_VR_CAPTION), SetDataTip(STR_REFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), EndContainer(), /* Vehicle display + scrollbar. */ NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_VEHICLE_PANEL_DISPLAY), SetMinimalSize(228, 14), SetResize(1, 0), SetScrollbar(WID_VR_HSCROLLBAR), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VR_SHOW_HSCROLLBAR), NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_VR_HSCROLLBAR), EndContainer(), EndContainer(), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_VR_SELECT_HEADER), SetDataTip(STR_REFIT_TITLE, STR_NULL), SetResize(1, 0), /* Matrix + scrollbar. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_VR_MATRIX), SetMinimalSize(228, 112), SetResize(1, 14), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VR_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VR_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_VR_INFO), SetMinimalTextLines(2, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VR_REFIT), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; static WindowDesc _vehicle_refit_desc( WDP_AUTO, "view_vehicle_refit", 240, 174, WC_VEHICLE_REFIT, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, _nested_vehicle_refit_widgets, lengthof(_nested_vehicle_refit_widgets) ); /** * Show the refit window for a vehicle * @param *v The vehicle to show the refit window for * @param order of the vehicle to assign refit to, or INVALID_VEH_ORDER_ID to refit the vehicle now * @param parent the parent window of the refit window * @param auto_refit Choose cargo for auto-refitting */ void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent, bool auto_refit) { DeleteWindowById(WC_VEHICLE_REFIT, v->index); RefitWindow *w = new RefitWindow(&_vehicle_refit_desc, v, order, auto_refit); w->parent = parent; } /** Display list of cargo types of the engine, for the purchase information window */ uint ShowRefitOptionsList(int left, int right, int y, EngineID engine) { /* List of cargo types of this engine */ uint32 cmask = GetUnionOfArticulatedRefitMasks(engine, false); /* List of cargo types available in this climate */ uint32 lmask = _cargo_mask; /* Draw nothing if the engine is not refittable */ if (HasAtMostOneBit(cmask)) return y; if (cmask == lmask) { /* Engine can be refitted to all types in this climate */ SetDParam(0, STR_PURCHASE_INFO_ALL_TYPES); } else { /* Check if we are able to refit to more cargo types and unable to. If * so, invert the cargo types to list those that we can't refit to. */ if (CountBits(cmask ^ lmask) < CountBits(cmask) && CountBits(cmask ^ lmask) <= 7) { cmask ^= lmask; SetDParam(0, STR_PURCHASE_INFO_ALL_BUT); } else { SetDParam(0, STR_JUST_CARGO_LIST); } SetDParam(1, cmask); } return DrawStringMultiLine(left, right, y, INT32_MAX, STR_PURCHASE_INFO_REFITTABLE_TO); } /** Get the cargo subtype text from NewGRF for the vehicle details window. */ StringID GetCargoSubtypeText(const Vehicle *v) { if (HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) { uint16 cb = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v->engine_type, v); if (cb != CALLBACK_FAILED) { if (cb > 0x400) ErrorUnknownCallbackResult(v->GetGRFID(), CBID_VEHICLE_CARGO_SUFFIX, cb); if (cb >= 0x400 || (v->GetGRF()->grf_version < 8 && cb == 0xFF)) cb = CALLBACK_FAILED; } if (cb != CALLBACK_FAILED) { return GetGRFStringID(v->GetGRFID(), 0xD000 + cb); } } return STR_EMPTY; } /** Sort vehicles by their number */ static int CDECL VehicleNumberSorter(const Vehicle * const *a, const Vehicle * const *b) { return (*a)->unitnumber - (*b)->unitnumber; } /** Sort vehicles by their name */ static int CDECL VehicleNameSorter(const Vehicle * const *a, const Vehicle * const *b) { static char last_name[2][64]; if (*a != _last_vehicle[0]) { _last_vehicle[0] = *a; SetDParam(0, (*a)->index); GetString(last_name[0], STR_VEHICLE_NAME, lastof(last_name[0])); } if (*b != _last_vehicle[1]) { _last_vehicle[1] = *b; SetDParam(0, (*b)->index); GetString(last_name[1], STR_VEHICLE_NAME, lastof(last_name[1])); } int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by their age */ static int CDECL VehicleAgeSorter(const Vehicle * const *a, const Vehicle * const *b) { int r = (*a)->age - (*b)->age; return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by this year profit */ static int CDECL VehicleProfitThisYearSorter(const Vehicle * const *a, const Vehicle * const *b) { int r = ClampToI32((*a)->GetDisplayProfitThisYear() - (*b)->GetDisplayProfitThisYear()); return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by last year profit */ static int CDECL VehicleProfitLastYearSorter(const Vehicle * const *a, const Vehicle * const *b) { int r = ClampToI32((*a)->GetDisplayProfitLastYear() - (*b)->GetDisplayProfitLastYear()); return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by their cargo */ static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * const *b) { const Vehicle *v; CargoArray diff; /* Append the cargo of the connected waggons */ for (v = *a; v != NULL; v = v->Next()) diff[v->cargo_type] += v->cargo_cap; for (v = *b; v != NULL; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap; int r = 0; for (CargoID i = 0; i < NUM_CARGO; i++) { r = diff[i]; if (r != 0) break; } return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by their reliability */ static int CDECL VehicleReliabilitySorter(const Vehicle * const *a, const Vehicle * const *b) { int r = (*a)->reliability - (*b)->reliability; return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by their max speed */ static int CDECL VehicleMaxSpeedSorter(const Vehicle * const *a, const Vehicle * const *b) { int r = (*a)->vcache.cached_max_speed - (*b)->vcache.cached_max_speed; return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by model */ static int CDECL VehicleModelSorter(const Vehicle * const *a, const Vehicle * const *b) { int r = (*a)->engine_type - (*b)->engine_type; return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by their value */ static int CDECL VehicleValueSorter(const Vehicle * const *a, const Vehicle * const *b) { const Vehicle *u; Money diff = 0; for (u = *a; u != NULL; u = u->Next()) diff += u->value; for (u = *b; u != NULL; u = u->Next()) diff -= u->value; int r = ClampToI32(diff); return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by their length */ static int CDECL VehicleLengthSorter(const Vehicle * const *a, const Vehicle * const *b) { int r = (*a)->GetGroundVehicleCache()->cached_total_length - (*b)->GetGroundVehicleCache()->cached_total_length; return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by the time they can still live */ static int CDECL VehicleTimeToLiveSorter(const Vehicle * const *a, const Vehicle * const *b) { int r = ClampToI32(((*a)->max_age - (*a)->age) - ((*b)->max_age - (*b)->age)); return (r != 0) ? r : VehicleNumberSorter(a, b); } /** Sort vehicles by the timetable delay */ static int CDECL VehicleTimetableDelaySorter(const Vehicle * const *a, const Vehicle * const *b) { int r = (*a)->lateness_counter - (*b)->lateness_counter; return (r != 0) ? r : VehicleNumberSorter(a, b); } void InitializeGUI() { MemSetT(&_sorting, 0); } /** * Assign a vehicle window a new vehicle * @param window_class WindowClass to search for * @param from_index the old vehicle ID * @param to_index the new vehicle ID */ static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_index, VehicleID to_index) { Window *w = FindWindowById(window_class, from_index); if (w != NULL) { /* Update window_number */ w->window_number = to_index; if (w->viewport != NULL) w->viewport->follow_vehicle = to_index; /* Update vehicle drag data */ if (_thd.window_class == window_class && _thd.window_number == (WindowNumber)from_index) { _thd.window_number = to_index; } /* Notify the window. */ w->InvalidateData(VIWD_AUTOREPLACE, false); } } /** * Report a change in vehicle IDs (due to autoreplace) to affected vehicle windows. * @param from_index the old vehicle ID * @param to_index the new vehicle ID */ void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index) { ChangeVehicleWindow(WC_VEHICLE_VIEW, from_index, to_index); ChangeVehicleWindow(WC_VEHICLE_ORDERS, from_index, to_index); ChangeVehicleWindow(WC_VEHICLE_REFIT, from_index, to_index); ChangeVehicleWindow(WC_VEHICLE_DETAILS, from_index, to_index); ChangeVehicleWindow(WC_VEHICLE_TIMETABLE, from_index, to_index); } static const NWidgetPart _nested_vehicle_list[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_VL_CAPTION), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_SORT_BY_PULLDOWN), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_VL_LIST), SetMinimalSize(248, 0), SetFill(1, 0), SetResize(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_VL_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VL_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VL_HIDE_BUTTONS), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), SetFill(1, 1), EndContainer(), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1), SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VL_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), EndContainer(), /* Widget to be shown for other companies hiding the previous 5 widgets. */ NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, VehicleOrderID start = 0) { const Order *order = v->GetOrder(start); if (order == NULL) return; bool rtl = _current_text_dir == TD_RTL; int l_offset = rtl ? 0 : ScaleGUITrad(6); int r_offset = rtl ? ScaleGUITrad(6) : 0; int i = 0; VehicleOrderID oid = start; do { if (oid == v->cur_real_order_index) DrawString(left, right, y, STR_TINY_RIGHT_ARROW, TC_BLACK); if (order->IsType(OT_GOTO_STATION)) { SetDParam(0, order->GetDestination()); DrawString(left + l_offset, right - r_offset, y, STR_TINY_BLACK_STATION); y += FONT_HEIGHT_SMALL; if (++i == 4) break; } oid++; order = order->next; if (order == NULL) { order = v->orders.list->GetFirstOrder(); oid = 0; } } while (oid != start); } /** * Draws an image of a vehicle chain * @param v Front vehicle * @param left The minimum horizontal position * @param right The maximum horizontal position * @param y Vertical position to draw at * @param selection Selected vehicle to draw a frame around * @param skip Number of pixels to skip at the front (for scrolling) */ void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type, int skip) { switch (v->type) { case VEH_TRAIN: DrawTrainImage(Train::From(v), left, right, y, selection, image_type, skip); break; case VEH_ROAD: DrawRoadVehImage(v, left, right, y, selection, image_type, skip); break; case VEH_SHIP: DrawShipImage(v, left, right, y, selection, image_type); break; case VEH_AIRCRAFT: DrawAircraftImage(v, left, right, y, selection, image_type); break; default: NOT_REACHED(); } } /** * Get the height of a vehicle in the vehicle list GUIs. * @param type the vehicle type to look at * @param divisor the resulting height must be dividable by this * @return the height */ uint GetVehicleListHeight(VehicleType type, uint divisor) { /* Name + vehicle + profit */ uint base = ScaleGUITrad(GetVehicleHeight(type)) + 2 * FONT_HEIGHT_SMALL; /* Drawing of the 4 small orders + profit*/ if (type >= VEH_SHIP) base = max(base, 5U * FONT_HEIGHT_SMALL); if (divisor == 1) return base; /* Make sure the height is dividable by divisor */ uint rem = base % divisor; return base + (rem == 0 ? 0 : divisor - rem); } /** * Draw all the vehicle list items. * @param selected_vehicle The vehicle that is to be highlighted. * @param line_height Height of a single item line. * @param r Rectangle with edge positions of the matrix widget. */ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const { int left = r.left + WD_MATRIX_LEFT; int right = r.right - WD_MATRIX_RIGHT; int width = right - left; bool rtl = _current_text_dir == TD_RTL; int text_offset = max(GetSpriteSize(SPR_PROFIT_LOT).width, GetDigitWidth() * this->unitnumber_digits) + WD_FRAMERECT_RIGHT; int text_left = left + (rtl ? 0 : text_offset); int text_right = right - (rtl ? text_offset : 0); bool show_orderlist = this->vli.vtype >= VEH_SHIP; int orderlist_left = left + (rtl ? 0 : max(ScaleGUITrad(100) + text_offset, width / 2)); int orderlist_right = right - (rtl ? max(ScaleGUITrad(100) + text_offset, width / 2) : 0); int image_left = (rtl && show_orderlist) ? orderlist_right : text_left; int image_right = (!rtl && show_orderlist) ? orderlist_left : text_right; int vehicle_button_x = rtl ? right - GetSpriteSize(SPR_PROFIT_LOT).width : left; int y = r.top; uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehicles.Length()); for (uint i = this->vscroll->GetPosition(); i < max; ++i) { const Vehicle *v = this->vehicles[i]; StringID str; SetDParam(0, v->GetDisplayProfitThisYear()); SetDParam(1, v->GetDisplayProfitLastYear()); DrawVehicleImage(v, image_left, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, EIT_IN_LIST, 0); DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR); if (v->name != NULL) { /* The vehicle got a name so we will print it */ SetDParam(0, v->index); DrawString(text_left, text_right, y, STR_TINY_BLACK_VEHICLE); } else if (v->group_id != DEFAULT_GROUP) { /* The vehicle has no name, but is member of a group, so print group name */ SetDParam(0, v->group_id); DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK); } if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_real_order_index); if (v->IsChainInDepot()) { str = STR_BLUE_COMMA; } else { str = (v->age > v->max_age - DAYS_IN_LEAP_YEAR) ? STR_RED_COMMA : STR_BLACK_COMMA; } SetDParam(0, v->unitnumber); DrawString(left, right, y + 2, str); DrawVehicleProfitButton(v, vehicle_button_x, y + FONT_HEIGHT_NORMAL + 3); y += line_height; } } /** * Window for the (old) vehicle listing. * * bitmask for w->window_number * 0-7 CompanyID (owner) * 8-10 window type (use flags in vehicle_gui.h) * 11-15 vehicle type (using VEH_, but can be compressed to fewer bytes if needed) * 16-31 StationID or OrderID depending on window type (bit 8-10) */ struct VehicleListWindow : public BaseVehicleListWindow { private: /** Enumeration of planes of the button row at the bottom. */ enum ButtonPlanes { BP_SHOW_BUTTONS, ///< Show the buttons. BP_HIDE_BUTTONS, ///< Show the empty panel. }; public: VehicleListWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number) { /* Set up sorting. Make the window-specific _sorting variable * point to the correct global _sorting struct so we are freed * from having conditionals during window operation */ switch (this->vli.vtype) { case VEH_TRAIN: this->sorting = &_sorting.train; break; case VEH_ROAD: this->sorting = &_sorting.roadveh; break; case VEH_SHIP: this->sorting = &_sorting.ship; break; case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break; default: NOT_REACHED(); } this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_VL_SCROLLBAR); this->vehicles.SetListing(*this->sorting); this->vehicles.ForceRebuild(); this->vehicles.NeedResort(); this->BuildVehicleList(); this->SortVehicleList(); /* Set up the window widgets */ this->GetWidget(WID_VL_LIST)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype; if (this->vli.type == VL_SHARED_ORDERS) { this->GetWidget(WID_VL_CAPTION)->widget_data = STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION; } else { this->GetWidget(WID_VL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype; } this->FinishInitNested(window_number); if (this->vli.company != OWNER_NONE) this->owner = this->vli.company; } ~VehicleListWindow() { *this->sorting = this->vehicles.GetListing(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_VL_LIST: resize->height = GetVehicleListHeight(this->vli.vtype, 1); switch (this->vli.vtype) { case VEH_TRAIN: case VEH_ROAD: size->height = 6 * resize->height; break; case VEH_SHIP: case VEH_AIRCRAFT: size->height = 4 * resize->height; break; default: NOT_REACHED(); } break; case WID_VL_SORT_ORDER: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_VL_MANAGE_VEHICLES_DROPDOWN: { Dimension d = this->GetActionDropdownSize(this->vli.type == VL_STANDARD, false); d.height += padding.height; d.width += padding.width; *size = maxdim(*size, d); break; } } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_VL_AVAILABLE_VEHICLES: SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype); break; case WID_VL_CAPTION: { switch (this->vli.type) { case VL_SHARED_ORDERS: // Shared Orders if (this->vehicles.Length() == 0) { /* We can't open this window without vehicles using this order * and we should close the window when deleting the order. */ NOT_REACHED(); } SetDParam(0, this->vscroll->GetCount()); break; case VL_STANDARD: // Company Name SetDParam(0, STR_COMPANY_NAME); SetDParam(1, this->vli.index); SetDParam(3, this->vscroll->GetCount()); break; case VL_STATION_LIST: // Station/Waypoint Name SetDParam(0, Station::IsExpected(BaseStation::Get(this->vli.index)) ? STR_STATION_NAME : STR_WAYPOINT_NAME); SetDParam(1, this->vli.index); SetDParam(3, this->vscroll->GetCount()); break; case VL_DEPOT_LIST: SetDParam(0, STR_DEPOT_CAPTION); SetDParam(1, this->vli.vtype); SetDParam(2, this->vli.index); SetDParam(3, this->vscroll->GetCount()); break; default: NOT_REACHED(); } break; } } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_VL_SORT_ORDER: /* draw arrow pointing up/down for ascending/descending sorting */ this->DrawSortButtonState(widget, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; case WID_VL_LIST: this->DrawVehicleListItems(INVALID_VEHICLE, this->resize.step_height, r); break; } } virtual void OnPaint() { this->BuildVehicleList(); this->SortVehicleList(); if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_VL_MANAGE_VEHICLES_DROPDOWN)) { HideDropDownMenu(this); } /* Hide the widgets that we will not use in this window * Some windows contains actions only fit for the owner */ int plane_to_show = (this->owner == _local_company) ? BP_SHOW_BUTTONS : BP_HIDE_BUTTONS; NWidgetStacked *nwi = this->GetWidget(WID_VL_HIDE_BUTTONS); if (plane_to_show != nwi->shown_plane) { nwi->SetDisplayedPlane(plane_to_show); nwi->SetDirty(this); } if (this->owner == _local_company) { this->SetWidgetDisabledState(WID_VL_AVAILABLE_VEHICLES, this->vli.type != VL_STANDARD); this->SetWidgetsDisabledState(this->vehicles.Length() == 0, WID_VL_MANAGE_VEHICLES_DROPDOWN, WID_VL_STOP_ALL, WID_VL_START_ALL, WIDGET_LIST_END); } /* Set text of sort by dropdown widget. */ this->GetWidget(WID_VL_SORT_BY_PULLDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()]; this->DrawWidgets(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_VL_SORT_ORDER: // Flip sorting method ascending/descending this->vehicles.ToggleSortOrder(); this->SetDirty(); break; case WID_VL_SORT_BY_PULLDOWN:// Select sorting criteria dropdown menu ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), WID_VL_SORT_BY_PULLDOWN, 0, (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10)); return; case WID_VL_LIST: { // Matrix to show vehicles uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VL_LIST); if (id_v >= this->vehicles.Length()) return; // click out of list bound const Vehicle *v = this->vehicles[id_v]; if (!VehicleClicked(v)) ShowVehicleViewWindow(v); break; } case WID_VL_AVAILABLE_VEHICLES: ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype); break; case WID_VL_MANAGE_VEHICLES_DROPDOWN: { DropDownList *list = this->BuildActionDropdownList(VehicleListIdentifier(this->window_number).type == VL_STANDARD, false); ShowDropDownList(this, list, 0, WID_VL_MANAGE_VEHICLES_DROPDOWN); break; } case WID_VL_STOP_ALL: case WID_VL_START_ALL: DoCommandP(0, (1 << 1) | (widget == WID_VL_START_ALL ? (1 << 0) : 0), this->window_number, CMD_MASS_START_STOP); break; } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_VL_SORT_BY_PULLDOWN: this->vehicles.SetSortType(index); break; case WID_VL_MANAGE_VEHICLES_DROPDOWN: assert(this->vehicles.Length() != 0); switch (index) { case ADI_REPLACE: // Replace window ShowReplaceGroupVehicleWindow(ALL_GROUP, this->vli.vtype); break; case ADI_SERVICE: // Send for servicing case ADI_DEPOT: // Send to Depots DoCommandP(0, DEPOT_MASS_SEND | (index == ADI_SERVICE ? DEPOT_SERVICE : (DepotCommand)0), this->window_number, GetCmdSendToDepot(this->vli.vtype)); break; default: NOT_REACHED(); } break; default: NOT_REACHED(); } this->SetDirty(); } virtual void OnTick() { if (_pause_mode != PM_UNPAUSED) return; if (this->vehicles.NeedResort()) { StationID station = (this->vli.type == VL_STATION_LIST) ? this->vli.index : INVALID_STATION; DEBUG(misc, 3, "Periodic resort %d list company %d at station %d", this->vli.vtype, this->owner, station); this->SetDirty(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_VL_LIST); } /** * 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 && HasBit(data, 31) && this->vli.type == VL_SHARED_ORDERS) { /* Needs to be done in command-scope, so everything stays valid */ this->vli.index = GB(data, 0, 20); this->window_number = this->vli.Pack(); this->vehicles.ForceRebuild(); return; } if (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->vehicles.ForceRebuild(); } else { this->vehicles.ForceResort(); } } }; static WindowDesc _vehicle_list_other_desc( WDP_AUTO, "list_vehicles", 260, 246, WC_INVALID, WC_NONE, 0, _nested_vehicle_list, lengthof(_nested_vehicle_list) ); static WindowDesc _vehicle_list_train_desc( WDP_AUTO, "list_vehicles_train", 325, 246, WC_TRAINS_LIST, WC_NONE, 0, _nested_vehicle_list, lengthof(_nested_vehicle_list) ); static void ShowVehicleListWindowLocal(CompanyID company, VehicleListType vlt, VehicleType vehicle_type, uint32 unique_number) { if (!Company::IsValidID(company) && company != OWNER_NONE) return; WindowNumber num = VehicleListIdentifier(vlt, vehicle_type, company, unique_number).Pack(); if (vehicle_type == VEH_TRAIN) { AllocateWindowDescFront(&_vehicle_list_train_desc, num); } else { _vehicle_list_other_desc.cls = GetWindowClassForVehicleType(vehicle_type); AllocateWindowDescFront(&_vehicle_list_other_desc, num); } } void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type) { /* If _settings_client.gui.advanced_vehicle_list > 1, display the Advanced list * if _settings_client.gui.advanced_vehicle_list == 1, display Advanced list only for local company * if _ctrl_pressed, do the opposite action (Advanced list x Normal list) */ if ((_settings_client.gui.advanced_vehicle_list > (uint)(company != _local_company)) != _ctrl_pressed) { ShowCompanyGroup(company, vehicle_type); } else { ShowVehicleListWindowLocal(company, VL_STANDARD, vehicle_type, company); } } void ShowVehicleListWindow(const Vehicle *v) { ShowVehicleListWindowLocal(v->owner, VL_SHARED_ORDERS, v->type, v->FirstShared()->index); } void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station) { ShowVehicleListWindowLocal(company, VL_STATION_LIST, vehicle_type, station); } void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile) { uint16 depot_airport_index; if (vehicle_type == VEH_AIRCRAFT) { depot_airport_index = GetStationIndex(depot_tile); } else { depot_airport_index = GetDepotIndex(depot_tile); } ShowVehicleListWindowLocal(company, VL_DEPOT_LIST, vehicle_type, depot_airport_index); } /* Unified vehicle GUI - Vehicle Details Window */ assert_compile(WID_VD_DETAILS_CARGO_CARRIED == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CARGO ); assert_compile(WID_VD_DETAILS_TRAIN_VEHICLES == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_INFO ); assert_compile(WID_VD_DETAILS_CAPACITY_OF_EACH == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_CAPACITY); assert_compile(WID_VD_DETAILS_TOTAL_CARGO == WID_VD_DETAILS_CARGO_CARRIED + TDW_TAB_TOTALS ); /** Vehicle details widgets (other than train). */ static const NWidgetPart _nested_nontrain_vehicle_details_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL /* filled in later */), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetMinimalSize(405, 42), SetResize(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_MIDDLE_DETAILS), SetMinimalSize(405, 45), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_DECREASE_SERVICING_INTERVAL), SetFill(0, 1), SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_INCREASE_SERVICING_INTERVAL), SetFill(0, 1), SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VD_SERVICE_INTERVAL_DROPDOWN), SetFill(0, 1), SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; /** Train details widgets. */ static const NWidgetPart _nested_train_vehicle_details_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_VD_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL /* filled in later */), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_TOP_DETAILS), SetResize(1, 0), SetMinimalSize(405, 42), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_VD_MATRIX), SetResize(1, 1), SetMinimalSize(393, 45), SetMatrixDataTip(1, 0, STR_NULL), SetFill(1, 0), SetScrollbar(WID_VD_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VD_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_DECREASE_SERVICING_INTERVAL), SetFill(0, 1), SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_VD_INCREASE_SERVICING_INTERVAL), SetFill(0, 1), SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_VD_SERVICE_INTERVAL_DROPDOWN), SetFill(0, 1), SetDataTip(STR_EMPTY, STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY, WID_VD_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_CARGO_CARRIED), SetMinimalSize(96, 12), SetDataTip(STR_VEHICLE_DETAIL_TAB_CARGO, STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_TRAIN_VEHICLES), SetMinimalSize(99, 12), SetDataTip(STR_VEHICLE_DETAIL_TAB_INFORMATION, STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_CAPACITY_OF_EACH), SetMinimalSize(99, 12), SetDataTip(STR_VEHICLE_DETAIL_TAB_CAPACITIES, STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VD_DETAILS_TOTAL_CARGO), SetMinimalSize(99, 12), SetDataTip(STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; extern int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab); extern void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_pos, uint16 vscroll_cap, TrainDetailsWindowTabs det_tab); extern void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y); extern void DrawShipDetails(const Vehicle *v, int left, int right, int y); extern void DrawAircraftDetails(const Aircraft *v, int left, int right, int y); static StringID _service_interval_dropdown[] = { STR_VEHICLE_DETAILS_DEFAULT, STR_VEHICLE_DETAILS_DAYS, STR_VEHICLE_DETAILS_PERCENT, INVALID_STRING_ID, }; /** Class for managing the vehicle details window. */ struct VehicleDetailsWindow : Window { TrainDetailsWindowTabs tab; ///< For train vehicles: which tab is displayed. Scrollbar *vscroll; /** Initialize a newly created vehicle details window */ VehicleDetailsWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { const Vehicle *v = Vehicle::Get(window_number); this->CreateNestedTree(); this->vscroll = (v->type == VEH_TRAIN ? this->GetScrollbar(WID_VD_SCROLLBAR) : NULL); this->FinishInitNested(window_number); this->GetWidget(WID_VD_RENAME_VEHICLE)->tool_tip = STR_VEHICLE_DETAILS_TRAIN_RENAME + v->type; this->owner = v->owner; this->tab = TDW_TAB_CARGO; } /** * 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 (data == VIWD_AUTOREPLACE) { /* Autoreplace replaced the vehicle. * Nothing to do for this window. */ return; } if (!gui_scope) return; const Vehicle *v = Vehicle::Get(this->window_number); if (v->type == VEH_ROAD) { const NWidgetBase *nwid_info = this->GetWidget(WID_VD_MIDDLE_DETAILS); uint aimed_height = this->GetRoadVehDetailsHeight(v); /* If the number of articulated parts changes, the size of the window must change too. */ if (aimed_height != nwid_info->current_y) { this->ReInit(); } } } /** * Gets the desired height for the road vehicle details panel. * @param v Road vehicle being shown. * @return Desired height in pixels. */ uint GetRoadVehDetailsHeight(const Vehicle *v) { uint desired_height; if (v->HasArticulatedPart()) { /* An articulated RV has its text drawn under the sprite instead of after it, hence 15 pixels extra. */ desired_height = WD_FRAMERECT_TOP + ScaleGUITrad(15) + 3 * FONT_HEIGHT_NORMAL + 2 + WD_FRAMERECT_BOTTOM; /* Add space for the cargo amount for each part. */ for (const Vehicle *u = v; u != NULL; u = u->Next()) { if (u->cargo_cap != 0) desired_height += FONT_HEIGHT_NORMAL + 1; } } else { desired_height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM; } return desired_height; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_VD_TOP_DETAILS: { Dimension dim = { 0, 0 }; size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; for (uint i = 0; i < 4; i++) SetDParamMaxValue(i, INT16_MAX); static const StringID info_strings[] = { STR_VEHICLE_INFO_MAX_SPEED, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS }; for (uint i = 0; i < lengthof(info_strings); i++) { dim = maxdim(dim, GetStringBoundingBox(info_strings[i])); } SetDParam(0, STR_VEHICLE_INFO_AGE); dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_AGE_RUNNING_COST_YR)); size->width = dim.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; break; } case WID_VD_MIDDLE_DETAILS: { const Vehicle *v = Vehicle::Get(this->window_number); switch (v->type) { case VEH_ROAD: size->height = this->GetRoadVehDetailsHeight(v); break; case VEH_SHIP: size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM; break; case VEH_AIRCRAFT: size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + 4 + WD_FRAMERECT_BOTTOM; break; default: NOT_REACHED(); // Train uses WID_VD_MATRIX instead. } break; } case WID_VD_MATRIX: resize->height = max(ScaleGUITrad(14), WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM); size->height = 4 * resize->height; break; case WID_VD_SERVICE_INTERVAL_DROPDOWN: { StringID *strs = _service_interval_dropdown; while (*strs != INVALID_STRING_ID) { *size = maxdim(*size, GetStringBoundingBox(*strs++)); } size->width += padding.width; size->height = FONT_HEIGHT_NORMAL + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; break; } case WID_VD_SERVICING_INTERVAL: SetDParamMaxValue(0, MAX_SERVINT_DAYS); // Roughly the maximum interval SetDParamMaxValue(1, MAX_YEAR * DAYS_IN_YEAR); // Roughly the maximum year size->width = max(GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width, GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; size->height = WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; break; } } /** Checks whether service interval is enabled for the vehicle. */ static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type, CompanyID company_id) { const VehicleDefaultSettings *vds = &Company::Get(company_id)->settings.vehicle; switch (vehicle_type) { default: NOT_REACHED(); case VEH_TRAIN: return vds->servint_trains != 0; case VEH_ROAD: return vds->servint_roadveh != 0; case VEH_SHIP: return vds->servint_ships != 0; case VEH_AIRCRAFT: return vds->servint_aircraft != 0; } } /** * Draw the details for the given vehicle at the position of the Details windows * * @param v current vehicle * @param left The left most coordinate to draw * @param right The right most coordinate to draw * @param y The y coordinate * @param vscroll_pos Position of scrollbar (train only) * @param vscroll_cap Number of lines currently displayed (train only) * @param det_tab Selected details tab (train only) */ static void DrawVehicleDetails(const Vehicle *v, int left, int right, int y, int vscroll_pos, uint vscroll_cap, TrainDetailsWindowTabs det_tab) { switch (v->type) { case VEH_TRAIN: DrawTrainDetails(Train::From(v), left, right, y, vscroll_pos, vscroll_cap, det_tab); break; case VEH_ROAD: DrawRoadVehDetails(v, left, right, y); break; case VEH_SHIP: DrawShipDetails(v, left, right, y); break; case VEH_AIRCRAFT: DrawAircraftDetails(Aircraft::From(v), left, right, y); break; default: NOT_REACHED(); } } virtual void SetStringParameters(int widget) const { if (widget == WID_VD_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index); } virtual void DrawWidget(const Rect &r, int widget) const { const Vehicle *v = Vehicle::Get(this->window_number); switch (widget) { case WID_VD_TOP_DETAILS: { int y = r.top + WD_FRAMERECT_TOP; /* Draw running cost */ SetDParam(1, v->age / DAYS_IN_LEAP_YEAR); SetDParam(0, (v->age + DAYS_IN_YEAR < v->max_age) ? STR_VEHICLE_INFO_AGE : STR_VEHICLE_INFO_AGE_RED); SetDParam(2, v->max_age / DAYS_IN_LEAP_YEAR); SetDParam(3, v->GetDisplayRunningCost()); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_AGE_RUNNING_COST_YR); y += FONT_HEIGHT_NORMAL; /* Draw max speed */ StringID string; if (v->type == VEH_TRAIN || (v->type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL)) { const GroundVehicleCache *gcache = v->GetGroundVehicleCache(); SetDParam(2, v->GetDisplayMaxSpeed()); SetDParam(1, gcache->cached_power); SetDParam(0, gcache->cached_weight); SetDParam(3, gcache->cached_max_te / 1000); if (v->type == VEH_TRAIN && (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL || GetRailTypeInfo(Train::From(v)->railtype)->acceleration_type == 2)) { string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED; } else { string = STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE; } } else { SetDParam(0, v->GetDisplayMaxSpeed()); if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->GetRange() > 0) { SetDParam(1, Aircraft::From(v)->GetRange()); string = STR_VEHICLE_INFO_MAX_SPEED_RANGE; } else { string = STR_VEHICLE_INFO_MAX_SPEED; } } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, string); y += FONT_HEIGHT_NORMAL; /* Draw profit */ SetDParam(0, v->GetDisplayProfitThisYear()); SetDParam(1, v->GetDisplayProfitLastYear()); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR); y += FONT_HEIGHT_NORMAL; /* Draw breakdown & reliability */ SetDParam(0, ToPercent16(v->reliability)); SetDParam(1, v->breakdowns_since_last_service); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS); break; } case WID_VD_MATRIX: /* For trains only. */ DrawVehicleDetails(v, r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, r.top + WD_MATRIX_TOP, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->tab); break; case WID_VD_MIDDLE_DETAILS: { /* For other vehicles, at the place of the matrix. */ bool rtl = _current_text_dir == TD_RTL; uint sprite_width = UnScaleGUI( max(GetSprite(v->GetImage(rtl ? DIR_E : DIR_W, EIT_IN_DETAILS), ST_NORMAL)->width, 70U)) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; uint text_left = r.left + (rtl ? 0 : sprite_width); uint text_right = r.right - (rtl ? sprite_width : 0); /* Articulated road vehicles use a complete line. */ if (v->type == VEH_ROAD && v->HasArticulatedPart()) { DrawVehicleImage(v, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } else { uint sprite_left = rtl ? text_right : r.left; uint sprite_right = rtl ? r.right : text_left; DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, EIT_IN_DETAILS, 0); } DrawVehicleDetails(v, text_left + WD_FRAMERECT_LEFT, text_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, 0, 0, this->tab); break; } case WID_VD_SERVICING_INTERVAL: /* Draw service interval text */ SetDParam(0, v->GetServiceInterval()); SetDParam(1, v->date_of_last_service); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + (r.bottom - r.top + 1 - FONT_HEIGHT_NORMAL) / 2, v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS); break; } } /** Repaint vehicle details window. */ virtual void OnPaint() { const Vehicle *v = Vehicle::Get(this->window_number); this->SetWidgetDisabledState(WID_VD_RENAME_VEHICLE, v->owner != _local_company); if (v->type == VEH_TRAIN) { this->DisableWidget(this->tab + WID_VD_DETAILS_CARGO_CARRIED); this->vscroll->SetCount(GetTrainDetailsWndVScroll(v->index, this->tab)); } /* Disable service-scroller when interval is set to disabled */ this->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type, v->owner), WID_VD_INCREASE_SERVICING_INTERVAL, WID_VD_DECREASE_SERVICING_INTERVAL, WIDGET_LIST_END); StringID str = v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_PERCENT : STR_VEHICLE_DETAILS_DAYS) : STR_VEHICLE_DETAILS_DEFAULT; this->GetWidget(WID_VD_SERVICE_INTERVAL_DROPDOWN)->widget_data = str; this->DrawWidgets(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_VD_RENAME_VEHICLE: { // rename const Vehicle *v = Vehicle::Get(this->window_number); SetDParam(0, v->index); ShowQueryString(STR_VEHICLE_NAME, STR_QUERY_RENAME_TRAIN_CAPTION + v->type, MAX_LENGTH_VEHICLE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); break; } case WID_VD_INCREASE_SERVICING_INTERVAL: // increase int case WID_VD_DECREASE_SERVICING_INTERVAL: { // decrease int int mod = _ctrl_pressed ? 5 : 10; const Vehicle *v = Vehicle::Get(this->window_number); mod = (widget == WID_VD_DECREASE_SERVICING_INTERVAL) ? -mod : mod; mod = GetServiceIntervalClamped(mod + v->GetServiceInterval(), v->ServiceIntervalIsPercent()); if (mod == v->GetServiceInterval()) return; DoCommandP(v->tile, v->index, mod | (1 << 16) | (v->ServiceIntervalIsPercent() << 17), CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SERVICING)); break; } case WID_VD_SERVICE_INTERVAL_DROPDOWN: { const Vehicle *v = Vehicle::Get(this->window_number); ShowDropDownMenu(this, _service_interval_dropdown, v->ServiceIntervalIsCustom() ? (v->ServiceIntervalIsPercent() ? 2 : 1) : 0, widget, 0, 0); break; } case WID_VD_DETAILS_CARGO_CARRIED: case WID_VD_DETAILS_TRAIN_VEHICLES: case WID_VD_DETAILS_CAPACITY_OF_EACH: case WID_VD_DETAILS_TOTAL_CARGO: this->SetWidgetsDisabledState(false, WID_VD_DETAILS_CARGO_CARRIED, WID_VD_DETAILS_TRAIN_VEHICLES, WID_VD_DETAILS_CAPACITY_OF_EACH, WID_VD_DETAILS_TOTAL_CARGO, widget, WIDGET_LIST_END); this->tab = (TrainDetailsWindowTabs)(widget - WID_VD_DETAILS_CARGO_CARRIED); this->SetDirty(); break; } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_VD_SERVICE_INTERVAL_DROPDOWN: { const Vehicle *v = Vehicle::Get(this->window_number); bool iscustom = index != 0; bool ispercent = iscustom ? (index == 2) : Company::Get(v->owner)->settings.vehicle.servint_ispercent; uint16 interval = GetServiceIntervalClamped(v->GetServiceInterval(), ispercent); DoCommandP(v->tile, v->index, interval | (iscustom << 16) | (ispercent << 17), CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SERVICING)); break; } } } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; DoCommandP(0, this->window_number, 0, CMD_RENAME_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type), NULL, str); } virtual void OnResize() { NWidgetCore *nwi = this->GetWidget(WID_VD_MATRIX); if (nwi != NULL) { this->vscroll->SetCapacityFromWidget(this, WID_VD_MATRIX); } } }; /** Vehicle details window descriptor. */ static WindowDesc _train_vehicle_details_desc( WDP_AUTO, "view_vehicle_details_train", 405, 178, WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, 0, _nested_train_vehicle_details_widgets, lengthof(_nested_train_vehicle_details_widgets) ); /** Vehicle details window descriptor for other vehicles than a train. */ static WindowDesc _nontrain_vehicle_details_desc( WDP_AUTO, "view_vehicle_details", 405, 113, WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW, 0, _nested_nontrain_vehicle_details_widgets, lengthof(_nested_nontrain_vehicle_details_widgets) ); /** Shows the vehicle details window of the given vehicle. */ static void ShowVehicleDetailsWindow(const Vehicle *v) { DeleteWindowById(WC_VEHICLE_ORDERS, v->index, false); DeleteWindowById(WC_VEHICLE_TIMETABLE, v->index, false); AllocateWindowDescFront((v->type == VEH_TRAIN) ? &_train_vehicle_details_desc : &_nontrain_vehicle_details_desc, v->index); } /* Unified vehicle GUI - Vehicle View Window */ /** Vehicle view widgets. */ static const NWidgetPart _nested_vehicle_view_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_VV_CAPTION), SetDataTip(STR_VEHICLE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEBUGBOX, COLOUR_GREY), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_INSET, COLOUR_GREY), SetPadding(2, 2, 2, 2), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_VV_VIEWPORT), SetMinimalSize(226, 84), SetResize(1, 1), SetPadding(1, 1, 1, 1), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CENTER_MAIN_VIEW), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_CENTRE_VIEW_VEHICLE, 0x0 /* filled later */), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VV_SELECT_DEPOT_CLONE), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_GOTO_DEPOT), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_CLONE), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 /* filled later */, 0x0 /* filled later */), EndContainer(), /* For trains only, 'ignore signal' button. */ NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_FORCE_PROCEED), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_IGNORE_SIGNALS, STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VV_SELECT_REFIT_TURN), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_REFIT), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_REFIT_VEHICLE, 0x0 /* filled later */), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_TURN_AROUND), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_FORCE_VEHICLE_TURN, STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_ORDERS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_ORDERS, 0x0 /* filled later */), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VV_SHOW_DETAILS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_VEHICLE_DETAILS, 0x0 /* filled later */), NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetMinimalSize(18, 0), SetResize(0, 1), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_VV_START_STOP), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetResize(1, 0), SetFill(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; /** Vehicle view window descriptor for all vehicles but trains. */ static WindowDesc _vehicle_view_desc( WDP_AUTO, "view_vehicle", 250, 116, WC_VEHICLE_VIEW, WC_NONE, 0, _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) ); /** * Vehicle view window descriptor for trains. Only minimum_height and * default_height are different for train view. */ static WindowDesc _train_view_desc( WDP_AUTO, "view_vehicle_train", 250, 134, WC_VEHICLE_VIEW, WC_NONE, 0, _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets) ); /* Just to make sure, nobody has changed the vehicle type constants, as we are using them for array indexing in a number of places here. */ assert_compile(VEH_TRAIN == 0); assert_compile(VEH_ROAD == 1); assert_compile(VEH_SHIP == 2); assert_compile(VEH_AIRCRAFT == 3); /** Zoom levels for vehicle views indexed by vehicle type. */ static const ZoomLevel _vehicle_view_zoom_levels[] = { ZOOM_LVL_TRAIN, ZOOM_LVL_ROADVEH, ZOOM_LVL_SHIP, ZOOM_LVL_AIRCRAFT, }; /* Constants for geometry of vehicle view viewport */ static const int VV_INITIAL_VIEWPORT_WIDTH = 226; static const int VV_INITIAL_VIEWPORT_HEIGHT = 84; static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102; /** Command indices for the _vehicle_command_translation_table. */ enum VehicleCommandTranslation { VCT_CMD_START_STOP = 0, VCT_CMD_CLONE_VEH, VCT_CMD_TURN_AROUND, }; /** Command codes for the shared buttons indexed by VehicleCommandTranslation and vehicle type. */ static const uint32 _vehicle_command_translation_table[][4] = { { // VCT_CMD_START_STOP CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_TRAIN), CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE), CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_SHIP), CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_AIRCRAFT) }, { // VCT_CMD_CLONE_VEH CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN), CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_ROAD_VEHICLE), CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_SHIP), CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_AIRCRAFT) }, { // VCT_CMD_TURN_AROUND CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN), CMD_TURN_ROADVEH | CMD_MSG(STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN), 0xffffffff, // invalid for ships 0xffffffff // invalid for aircrafts }, }; /** * This is the Callback method after the cloning attempt of a vehicle * @param result the result of the cloning command * @param tile unused * @param p1 vehicle ID * @param p2 unused */ void CcStartStopVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; const Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL || !v->IsPrimaryVehicle() || v->owner != _local_company) return; StringID msg = (v->vehstatus & VS_STOPPED) ? STR_VEHICLE_COMMAND_STOPPED : STR_VEHICLE_COMMAND_STARTED; Point pt = RemapCoords(v->x_pos, v->y_pos, v->z_pos); AddTextEffect(msg, pt.x, pt.y, DAY_TICKS, TE_RISING); } /** * Executes #CMD_START_STOP_VEHICLE for given vehicle. * @param v Vehicle to start/stop * @param texteffect Should a texteffect be shown? */ void StartStopVehicle(const Vehicle *v, bool texteffect) { assert(v->IsPrimaryVehicle()); DoCommandP(v->tile, v->index, 0, _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type], texteffect ? CcStartStopVehicle : NULL); } /** Checks whether the vehicle may be refitted at the moment.*/ static bool IsVehicleRefitable(const Vehicle *v) { if (!v->IsStoppedInDepot()) return false; do { if (IsEngineRefittable(v->engine_type)) return true; } while (v->IsGroundVehicle() && (v = v->Next()) != NULL); return false; } /** Window manager class for viewing a vehicle. */ struct VehicleViewWindow : Window { private: /** Display planes available in the vehicle view window. */ enum PlaneSelections { SEL_DC_GOTO_DEPOT, ///< Display 'goto depot' button in #WID_VV_SELECT_DEPOT_CLONE stacked widget. SEL_DC_CLONE, ///< Display 'clone vehicle' button in #WID_VV_SELECT_DEPOT_CLONE stacked widget. SEL_RT_REFIT, ///< Display 'refit' button in #WID_VV_SELECT_REFIT_TURN stacked widget. SEL_RT_TURN_AROUND, ///< Display 'turn around' button in #WID_VV_SELECT_REFIT_TURN stacked widget. SEL_DC_BASEPLANE = SEL_DC_GOTO_DEPOT, ///< First plane of the #WID_VV_SELECT_DEPOT_CLONE stacked widget. SEL_RT_BASEPLANE = SEL_RT_REFIT, ///< First plane of the #WID_VV_SELECT_REFIT_TURN stacked widget. }; /** * Display a plane in the window. * @param plane Plane to show. */ void SelectPlane(PlaneSelections plane) { switch (plane) { case SEL_DC_GOTO_DEPOT: case SEL_DC_CLONE: this->GetWidget(WID_VV_SELECT_DEPOT_CLONE)->SetDisplayedPlane(plane - SEL_DC_BASEPLANE); break; case SEL_RT_REFIT: case SEL_RT_TURN_AROUND: this->GetWidget(WID_VV_SELECT_REFIT_TURN)->SetDisplayedPlane(plane - SEL_RT_BASEPLANE); break; default: NOT_REACHED(); } } public: VehicleViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->CreateNestedTree(); /* Sprites for the 'send to depot' button indexed by vehicle type. */ static const SpriteID vehicle_view_goto_depot_sprites[] = { SPR_SEND_TRAIN_TODEPOT, SPR_SEND_ROADVEH_TODEPOT, SPR_SEND_SHIP_TODEPOT, SPR_SEND_AIRCRAFT_TODEPOT, }; const Vehicle *v = Vehicle::Get(window_number); this->GetWidget(WID_VV_GOTO_DEPOT)->widget_data = vehicle_view_goto_depot_sprites[v->type]; /* Sprites for the 'clone vehicle' button indexed by vehicle type. */ static const SpriteID vehicle_view_clone_sprites[] = { SPR_CLONE_TRAIN, SPR_CLONE_ROADVEH, SPR_CLONE_SHIP, SPR_CLONE_AIRCRAFT, }; this->GetWidget(WID_VV_CLONE)->widget_data = vehicle_view_clone_sprites[v->type]; switch (v->type) { case VEH_TRAIN: this->GetWidget(WID_VV_TURN_AROUND)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP; break; case VEH_ROAD: break; case VEH_SHIP: case VEH_AIRCRAFT: this->SelectPlane(SEL_RT_REFIT); break; default: NOT_REACHED(); } this->FinishInitNested(window_number); this->owner = v->owner; this->GetWidget(WID_VV_VIEWPORT)->InitializeViewport(this, this->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]); this->GetWidget(WID_VV_START_STOP)->tool_tip = STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP + v->type; this->GetWidget(WID_VV_CENTER_MAIN_VIEW)->tool_tip = STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP + v->type; this->GetWidget(WID_VV_REFIT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP + v->type; this->GetWidget(WID_VV_GOTO_DEPOT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + v->type; this->GetWidget(WID_VV_SHOW_ORDERS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP + v->type; this->GetWidget(WID_VV_SHOW_DETAILS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP + v->type; this->GetWidget(WID_VV_CLONE)->tool_tip = STR_VEHICLE_VIEW_CLONE_TRAIN_INFO + v->type; } ~VehicleViewWindow() { DeleteWindowById(WC_VEHICLE_ORDERS, this->window_number, false); DeleteWindowById(WC_VEHICLE_REFIT, this->window_number, false); DeleteWindowById(WC_VEHICLE_DETAILS, this->window_number, false); DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number, false); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { const Vehicle *v = Vehicle::Get(this->window_number); switch (widget) { case WID_VV_START_STOP: size->height = max(size->height, max(GetSpriteSize(SPR_FLAG_VEH_STOPPED).height, GetSpriteSize(SPR_FLAG_VEH_RUNNING).height) + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); break; case WID_VV_FORCE_PROCEED: if (v->type != VEH_TRAIN) { size->height = 0; size->width = 0; } break; case WID_VV_VIEWPORT: size->width = VV_INITIAL_VIEWPORT_WIDTH; size->height = (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT; break; } } virtual void OnPaint() { const Vehicle *v = Vehicle::Get(this->window_number); bool is_localcompany = v->owner == _local_company; bool refitable_and_stopped_in_depot = IsVehicleRefitable(v); this->SetWidgetDisabledState(WID_VV_GOTO_DEPOT, !is_localcompany); this->SetWidgetDisabledState(WID_VV_REFIT, !refitable_and_stopped_in_depot || !is_localcompany); this->SetWidgetDisabledState(WID_VV_CLONE, !is_localcompany); if (v->type == VEH_TRAIN) { this->SetWidgetLoweredState(WID_VV_FORCE_PROCEED, Train::From(v)->force_proceed == TFP_SIGNAL); this->SetWidgetDisabledState(WID_VV_FORCE_PROCEED, !is_localcompany); this->SetWidgetDisabledState(WID_VV_TURN_AROUND, !is_localcompany); } this->DrawWidgets(); } virtual void SetStringParameters(int widget) const { if (widget != WID_VV_CAPTION) return; const Vehicle *v = Vehicle::Get(this->window_number); SetDParam(0, v->index); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_VV_START_STOP) return; const Vehicle *v = Vehicle::Get(this->window_number); StringID str; if (v->vehstatus & VS_CRASHED) { str = STR_VEHICLE_STATUS_CRASHED; } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary? str = STR_VEHICLE_STATUS_BROKEN_DOWN; } else if (v->vehstatus & VS_STOPPED) { if (v->type == VEH_TRAIN) { if (v->cur_speed == 0) { if (Train::From(v)->gcache.cached_power == 0) { str = STR_VEHICLE_STATUS_TRAIN_NO_POWER; } else { str = STR_VEHICLE_STATUS_STOPPED; } } else { SetDParam(0, v->GetDisplaySpeed()); str = STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL; } } else { // no train str = STR_VEHICLE_STATUS_STOPPED; } } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) { str = STR_VEHICLE_STATUS_TRAIN_STUCK; } else if (v->type == VEH_AIRCRAFT && HasBit(Aircraft::From(v)->flags, VAF_DEST_TOO_FAR) && !v->current_order.IsType(OT_LOADING)) { str = STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR; } else { // vehicle is in a "normal" state, show current order switch (v->current_order.GetType()) { case OT_GOTO_STATION: { SetDParam(0, v->current_order.GetDestination()); SetDParam(1, v->GetDisplaySpeed()); str = STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL; break; } case OT_GOTO_DEPOT: { SetDParam(0, v->type); SetDParam(1, v->current_order.GetDestination()); SetDParam(2, v->GetDisplaySpeed()); if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) { /* This case *only* happens when multiple nearest depot orders * follow each other (including an order list only one order: a * nearest depot order) and there are no reachable depots. * It is primarily to guard for the case that there is no * depot with index 0, which would be used as fallback for * evaluating the string in the status bar. */ str = STR_EMPTY; } else if (v->current_order.GetDepotActionType() & ODATFB_HALT) { str = STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL; } else { str = STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL; } break; } case OT_LOADING: str = STR_VEHICLE_STATUS_LOADING_UNLOADING; break; case OT_GOTO_WAYPOINT: { assert(v->type == VEH_TRAIN || v->type == VEH_SHIP); SetDParam(0, v->current_order.GetDestination()); str = STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL; SetDParam(1, v->GetDisplaySpeed()); break; } case OT_LEAVESTATION: if (v->type != VEH_AIRCRAFT) { str = STR_VEHICLE_STATUS_LEAVING; break; } /* FALL THROUGH, if aircraft. Does this even happen? */ default: if (v->GetNumManualOrders() == 0) { str = STR_VEHICLE_STATUS_NO_ORDERS_VEL; SetDParam(0, v->GetDisplaySpeed()); } else { str = STR_EMPTY; } break; } } /* Draw the flag plus orders. */ bool rtl = (_current_text_dir == TD_RTL); uint text_offset = max(GetSpriteSize(SPR_FLAG_VEH_STOPPED).width, GetSpriteSize(SPR_FLAG_VEH_RUNNING).width) + WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT; int text_left = r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : text_offset); int text_right = r.right - (rtl ? text_offset : (uint)WD_FRAMERECT_RIGHT); int image_left = (rtl ? text_right + 1 : r.left) + WD_IMGBTN_LEFT; int image = ((v->vehstatus & VS_STOPPED) != 0) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING; int lowered = this->IsWidgetLowered(WID_VV_START_STOP) ? 1 : 0; DrawSprite(image, PAL_NONE, image_left + lowered, r.top + WD_IMGBTN_TOP + lowered); DrawString(text_left + lowered, text_right + lowered, r.top + WD_FRAMERECT_TOP + lowered, str, TC_FROMSTRING, SA_HOR_CENTER); } virtual void OnClick(Point pt, int widget, int click_count) { const Vehicle *v = Vehicle::Get(this->window_number); switch (widget) { case WID_VV_START_STOP: // start stop if (_ctrl_pressed) { /* Scroll to current order destination */ TileIndex tile = v->current_order.GetLocation(v); if (tile != INVALID_TILE) ScrollMainWindowToTile(tile); } else { /* Start/Stop */ StartStopVehicle(v, false); } break; case WID_VV_CENTER_MAIN_VIEW: {// center main view const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0); /* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */ if (_ctrl_pressed && mainwindow->viewport->zoom <= ZOOM_LVL_OUT_4X) { mainwindow->viewport->follow_vehicle = v->index; } else { ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos); } break; } case WID_VV_GOTO_DEPOT: // goto hangar DoCommandP(v->tile, v->index | (_ctrl_pressed ? DEPOT_SERVICE : 0U), 0, GetCmdSendToDepot(v)); break; case WID_VV_REFIT: // refit ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID, this); break; case WID_VV_SHOW_ORDERS: // show orders if (_ctrl_pressed) { ShowTimetableWindow(v); } else { ShowOrdersWindow(v); } break; case WID_VV_SHOW_DETAILS: // show details ShowVehicleDetailsWindow(v); break; case WID_VV_CLONE: // clone vehicle /* Suppress the vehicle GUI when share-cloning. * There is no point to it except for starting the vehicle. * For starting the vehicle the player has to open the depot GUI, which is * most likely already open, but is also visible in the vehicle viewport. */ DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type], _ctrl_pressed ? NULL : CcCloneVehicle); break; case WID_VV_TURN_AROUND: // turn around assert(v->IsGroundVehicle()); DoCommandP(v->tile, v->index, 0, _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]); break; case WID_VV_FORCE_PROCEED: // force proceed assert(v->type == VEH_TRAIN); DoCommandP(v->tile, v->index, 0, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL)); break; } } virtual void OnResize() { if (this->viewport != NULL) { NWidgetViewport *nvp = this->GetWidget(WID_VV_VIEWPORT); nvp->UpdateViewportCoordinates(this); } } virtual void OnTick() { const Vehicle *v = Vehicle::Get(this->window_number); bool veh_stopped = v->IsStoppedInDepot(); /* Widget WID_VV_GOTO_DEPOT must be hidden if the vehicle is already stopped in depot. * Widget WID_VV_CLONE_VEH should then be shown, since cloning is allowed only while in depot and stopped. */ PlaneSelections plane = veh_stopped ? SEL_DC_CLONE : SEL_DC_GOTO_DEPOT; NWidgetStacked *nwi = this->GetWidget(WID_VV_SELECT_DEPOT_CLONE); // Selection widget 'send to depot' / 'clone'. if (nwi->shown_plane + SEL_DC_BASEPLANE != plane) { this->SelectPlane(plane); this->SetWidgetDirty(WID_VV_SELECT_DEPOT_CLONE); } /* The same system applies to widget WID_VV_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/ if (v->IsGroundVehicle()) { PlaneSelections plane = veh_stopped ? SEL_RT_REFIT : SEL_RT_TURN_AROUND; NWidgetStacked *nwi = this->GetWidget(WID_VV_SELECT_REFIT_TURN); if (nwi->shown_plane + SEL_RT_BASEPLANE != plane) { this->SelectPlane(plane); this->SetWidgetDirty(WID_VV_SELECT_REFIT_TURN); } } } /** * 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 (data == VIWD_AUTOREPLACE) { /* Autoreplace replaced the vehicle. * Nothing to do for this window. */ return; } } virtual bool IsNewGRFInspectable() const { return ::IsNewGRFInspectable(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); } virtual void ShowNewGRFInspectWindow() const { ::ShowNewGRFInspectWindow(GetGrfSpecFeature(Vehicle::Get(this->window_number)->type), this->window_number); } }; /** Shows the vehicle view window of the given vehicle. */ void ShowVehicleViewWindow(const Vehicle *v) { AllocateWindowDescFront((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index); } /** * Dispatch a "vehicle selected" event if any window waits for it. * @param v selected vehicle; * @return did any window accept vehicle selection? */ bool VehicleClicked(const Vehicle *v) { assert(v != NULL); if (!(_thd.place_mode & HT_VEHICLE)) return false; v = v->First(); if (!v->IsPrimaryVehicle()) return false; return _thd.GetCallbackWnd()->OnVehicleSelect(v); } void StopGlobalFollowVehicle(const Vehicle *v) { Window *w = FindWindowById(WC_MAIN_WINDOW, 0); if (w != NULL && w->viewport->follow_vehicle == v->index) { ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos, true); // lock the main view on the vehicle's last position w->viewport->follow_vehicle = INVALID_VEHICLE; } } /** * This is the Callback method after the construction attempt of a primary vehicle * @param result indicates completion (or not) of the operation * @param tile unused * @param p1 unused * @param p2 unused */ void CcBuildPrimaryVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; const Vehicle *v = Vehicle::Get(_new_vehicle_id); ShowVehicleViewWindow(v); } /** * Get the width of a vehicle (including all parts of the consist) in pixels. * @param v Vehicle to get the width for. * @return Width of the vehicle. */ int GetVehicleWidth(Vehicle *v, EngineImageType image_type) { int vehicle_width = 0; switch (v->type) { case VEH_TRAIN: for (const Train *u = Train::From(v); u != NULL; u = u->Next()) { vehicle_width += u->GetDisplayImageWidth(); } break; case VEH_ROAD: for (const RoadVehicle *u = RoadVehicle::From(v); u != NULL; u = u->Next()) { vehicle_width += u->GetDisplayImageWidth(); } break; default: bool rtl = _current_text_dir == TD_RTL; SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); vehicle_width = UnScaleGUI(real_sprite->width); break; } return vehicle_width; } openttd-1.5.3/src/town.h0000644000000000000000000002656412627373442013651 0ustar rootroot/* $Id: town.h 27105 2015-01-01 21:25:42Z rubidium $ */ /* * 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 town.h Base of the town class. */ #ifndef TOWN_H #define TOWN_H #include "viewport_type.h" #include "town_map.h" #include "subsidy_type.h" #include "newgrf_storage.h" #include "cargotype.h" #include "tilematrix_type.hpp" #include template struct BuildingCounts { T id_count[NUM_HOUSES]; T class_count[HOUSE_CLASS_MAX]; }; typedef TileMatrix AcceptanceMatrix; static const uint CUSTOM_TOWN_NUMBER_DIFFICULTY = 4; ///< value for custom town number in difficulty settings static const uint CUSTOM_TOWN_MAX_NUMBER = 5000; ///< this is the maximum number of towns a user can specify in customisation static const uint INVALID_TOWN = 0xFFFF; static const uint TOWN_GROWTH_WINTER = 0xFFFFFFFE; ///< The town only needs this cargo in the winter (any amount) static const uint TOWN_GROWTH_DESERT = 0xFFFFFFFF; ///< The town needs the cargo for growth when on desert (any amount) static const uint16 TOWN_GROW_RATE_CUSTOM = 0x8000; ///< If this mask is applied to Town::growth_rate, the grow_counter will not be calculated by the system (but assumed to be set by scripts) static const uint16 TOWN_GROW_RATE_CUSTOM_NONE = 0xFFFF; ///< Special value for Town::growth_rate to disable town growth. typedef Pool TownPool; extern TownPool _town_pool; /** Data structure with cached data of towns. */ struct TownCache { uint32 num_houses; ///< Amount of houses uint32 population; ///< Current population of people ViewportSign sign; ///< Location of name sign, UpdateVirtCoord updates this PartOfSubsidyByte part_of_subsidy; ///< Is this town a source/destination of a subsidy? uint32 squared_town_zone_radius[HZB_END]; ///< UpdateTownRadius updates this given the house count BuildingCounts building_counts; ///< The number of each type of building in the town }; /** Town data structure. */ struct Town : TownPool::PoolItem<&_town_pool> { TileIndex xy; ///< town center tile TownCache cache; ///< Container for all cacheable data. /* Town name */ uint32 townnamegrfid; uint16 townnametype; uint32 townnameparts; char *name; ///< Custom town name. If NULL, the town was not renamed and uses the generated name. byte flags; ///< See #TownFlags. uint16 noise_reached; ///< level of noise that all the airports are generating CompanyMask statues; ///< which companies have a statue? /* Company ratings. */ CompanyMask have_ratings; ///< which companies have a rating uint8 unwanted[MAX_COMPANIES]; ///< how many months companies aren't wanted by towns (bribe) CompanyByte exclusivity; ///< which company has exclusivity uint8 exclusive_counter; ///< months till the exclusivity expires int16 ratings[MAX_COMPANIES]; ///< ratings of each company for this town TransportedCargoStat supplied[NUM_CARGO]; ///< Cargo statistics about supplied cargo. TransportedCargoStat received[NUM_TE]; ///< Cargo statistics about received cargotypes. uint32 goal[NUM_TE]; ///< Amount of cargo required for the town to grow. char *text; ///< General text with additional information. inline byte GetPercentTransported(CargoID cid) const { return this->supplied[cid].old_act * 256 / (this->supplied[cid].old_max + 1); } /* Cargo production and acceptance stats. */ uint32 cargo_produced; ///< Bitmap of all cargoes produced by houses in this town. AcceptanceMatrix cargo_accepted; ///< Bitmap of cargoes accepted by houses for each 4*4 map square of the town. uint32 cargo_accepted_total; ///< NOSAVE: Bitmap of all cargoes accepted by houses in this town. uint16 time_until_rebuild; ///< time until we rebuild a house uint16 grow_counter; ///< counter to count when to grow, value is smaller than or equal to growth_rate uint16 growth_rate; ///< town growth rate byte fund_buildings_months; ///< fund buildings program in action? byte road_build_months; ///< fund road reconstruction in action? bool larger_town; ///< if this is a larger town and should grow more quickly TownLayoutByte layout; ///< town specific road layout std::list psa_list; /** * Creates a new town. * @param tile center tile of the town */ Town(TileIndex tile = INVALID_TILE) : xy(tile) { } /** Destroy the town. */ ~Town(); void InitializeLayout(TownLayout layout); /** * Calculate the max town noise. * The value is counted using the population divided by the content of the * entry in town_noise_population corresponding to the town's tolerance. * @return the maximum noise level the town will tolerate. */ inline uint16 MaxTownNoise() const { if (this->cache.population == 0) return 0; // no population? no noise /* 3 is added (the noise of the lowest airport), so the user can at least build a small airfield. */ return (this->cache.population / _settings_game.economy.town_noise_population[_settings_game.difficulty.town_council_tolerance]) + 3; } void UpdateVirtCoord(); static inline Town *GetByTile(TileIndex tile) { return Town::Get(GetTownIndex(tile)); } static Town *GetRandom(); static void PostDestructor(size_t index); }; uint32 GetWorldPopulation(); void UpdateAllTownVirtCoords(); void ShowTownViewWindow(TownID town); void ExpandTown(Town *t); /** * Action types that a company must ask permission for to a town authority. * @see CheckforTownRating */ enum TownRatingCheckType { ROAD_REMOVE = 0, ///< Removal of a road owned by the town. TUNNELBRIDGE_REMOVE = 1, ///< Removal of a tunnel or bridge owned by the towb. TOWN_RATING_CHECK_TYPE_COUNT, ///< Number of town checking action types. }; /** * This enum is used in conjunction with town->flags. * IT simply states what bit is used for. * It is pretty unrealistic (IMHO) to only have one church/stadium * per town, NO MATTER the population of it. * And there are 5 more bits available on flags... */ enum TownFlags { TOWN_IS_GROWING = 0, ///< Conditions for town growth are met. Grow according to Town::growth_rate. TOWN_HAS_CHURCH = 1, ///< There can be only one church by town. TOWN_HAS_STADIUM = 2, ///< There can be only one stadium by town. }; CommandCost CheckforTownRating(DoCommandFlag flags, Town *t, TownRatingCheckType type); TileIndexDiff GetHouseNorthPart(HouseID &house); Town *CalcClosestTownFromTile(TileIndex tile, uint threshold = UINT_MAX); #define FOR_ALL_TOWNS_FROM(var, start) FOR_ALL_ITEMS_FROM(Town, town_index, var, start) #define FOR_ALL_TOWNS(var) FOR_ALL_TOWNS_FROM(var, 0) void ResetHouses(); void ClearTownHouse(Town *t, TileIndex tile); void UpdateTownMaxPass(Town *t); void UpdateTownRadius(Town *t); void UpdateTownCargoes(Town *t); void UpdateTownCargoTotal(Town *t); void UpdateTownCargoBitmap(); CommandCost CheckIfAuthorityAllowsNewStation(TileIndex tile, DoCommandFlag flags); Town *ClosestTownFromTile(TileIndex tile, uint threshold); void ChangeTownRating(Town *t, int add, int max, DoCommandFlag flags); HouseZonesBits GetTownRadiusGroup(const Town *t, TileIndex tile); void SetTownRatingTestMode(bool mode); uint GetMaskOfTownActions(int *nump, CompanyID cid, const Town *t); bool GenerateTowns(TownLayout layout); const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect); /** Town actions of a company. */ enum TownActions { TACT_NONE = 0x00, ///< Empty action set. TACT_ADVERTISE_SMALL = 0x01, ///< Small advertising campaign. TACT_ADVERTISE_MEDIUM = 0x02, ///< Medium advertising campaign. TACT_ADVERTISE_LARGE = 0x04, ///< Large advertising campaign. TACT_ROAD_REBUILD = 0x08, ///< Rebuild the roads. TACT_BUILD_STATUE = 0x10, ///< Build a statue. TACT_FUND_BUILDINGS = 0x20, ///< Fund new buildings. TACT_BUY_RIGHTS = 0x40, ///< Buy exclusive transport rights. TACT_BRIBE = 0x80, ///< Try to bribe the council. TACT_COUNT = 8, ///< Number of available town actions. TACT_ADVERTISE = TACT_ADVERTISE_SMALL | TACT_ADVERTISE_MEDIUM | TACT_ADVERTISE_LARGE, ///< All possible advertising actions. TACT_CONSTRUCTION = TACT_ROAD_REBUILD | TACT_BUILD_STATUE | TACT_FUND_BUILDINGS, ///< All possible construction actions. TACT_FUNDS = TACT_BUY_RIGHTS | TACT_BRIBE, ///< All possible funding actions. TACT_ALL = TACT_ADVERTISE | TACT_CONSTRUCTION | TACT_FUNDS, ///< All possible actions. }; DECLARE_ENUM_AS_BIT_SET(TownActions) extern const byte _town_action_costs[TACT_COUNT]; extern TownID _new_town_id; /** * Set the default name for a depot/waypoint * @tparam T The type/class to make a default name for * @param obj The object/instance we want to find the name for */ template void MakeDefaultName(T *obj) { /* We only want to set names if it hasn't been set before, or when we're calling from afterload. */ assert(obj->name == NULL || obj->town_cn == UINT16_MAX); obj->town = ClosestTownFromTile(obj->xy, UINT_MAX); /* Find first unused number belonging to this town. This can never fail, * as long as there can be at most 65535 waypoints/depots in total. * * This does 'n * m' search, but with 32bit 'used' bitmap, it needs at * most 'n * (1 + ceil(m / 32))' steps (n - number of waypoints in pool, * m - number of waypoints near this town). * Usually, it needs only 'n' steps. * * If it wasn't using 'used' and 'idx', it would just search for increasing 'next', * but this way it is faster */ uint32 used = 0; // bitmap of used waypoint numbers, sliding window with 'next' as base uint32 next = 0; // first number in the bitmap uint32 idx = 0; // index where we will stop uint32 cid = 0; // current index, goes to T::GetPoolSize()-1, then wraps to 0 do { T *lobj = T::GetIfValid(cid); /* check only valid waypoints... */ if (lobj != NULL && obj != lobj) { /* only objects within the same city and with the same type */ if (lobj->town == obj->town && lobj->IsOfType(obj)) { /* if lobj->town_cn < next, uint will overflow to '+inf' */ uint i = (uint)lobj->town_cn - next; if (i < 32) { SetBit(used, i); // update bitmap if (i == 0) { /* shift bitmap while the lowest bit is '1'; * increase the base of the bitmap too */ do { used >>= 1; next++; } while (HasBit(used, 0)); /* when we are at 'idx' again at end of the loop and * 'next' hasn't changed, then no object had town_cn == next, * so we can safely use it */ idx = cid; } } } } cid++; if (cid == T::GetPoolSize()) cid = 0; // wrap to zero... } while (cid != idx); obj->town_cn = (uint16)next; // set index... } extern uint32 _town_cargoes_accepted; #endif /* TOWN_H */ openttd-1.5.3/src/story_base.h0000644000000000000000000000770412627373442015027 0ustar rootroot/* $Id: story_base.h 25621 2013-07-21 15:21:55Z zuu $ */ /* * 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 story_base.h %StoryPage base class. */ #ifndef STORY_BASE_H #define STORY_BASE_H #include "company_type.h" #include "story_type.h" #include "date_type.h" #include "core/pool_type.hpp" typedef Pool StoryPageElementPool; typedef Pool StoryPagePool; extern StoryPageElementPool _story_page_element_pool; extern StoryPagePool _story_page_pool; extern uint32 _story_page_element_next_sort_value; extern uint32 _story_page_next_sort_value; /* * Each story page element is one of these types. */ enum StoryPageElementType { SPET_TEXT = 0, ///< A text element. SPET_LOCATION, ///< An element that references a tile along with a one-line text. SPET_GOAL, ///< An element that references a goal. SPET_END, INVALID_SPET = 0xFF, }; /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT StoryPageElementTypeByte; ///< typedefing-enumification of Direction /** * Struct about story page elements. * Each StoryPage is composed of one or more page elements that provide * page content. Each element only contain one type of content. **/ struct StoryPageElement : StoryPageElementPool::PoolItem<&_story_page_element_pool> { uint32 sort_value; ///< A number that increases for every created story page element. Used for sorting. The id of a story page element is the pool index. StoryPageID page; ///< Id of the page which the page element belongs to StoryPageElementTypeByte type; ///< Type of page element uint32 referenced_id; ///< Id of referenced object (location, goal etc.) char *text; ///< Static content text of page element /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) */ inline StoryPageElement() { } /** * (Empty) destructor has to be defined else operator delete might be called with NULL parameter */ inline ~StoryPageElement() { free(this->text); } }; #define FOR_ALL_STORY_PAGE_ELEMENTS_FROM(var, start) FOR_ALL_ITEMS_FROM(StoryPageElement, story_page_element_index, var, start) #define FOR_ALL_STORY_PAGE_ELEMENTS(var) FOR_ALL_STORY_PAGE_ELEMENTS_FROM(var, 0) /** Struct about stories, current and completed */ struct StoryPage : StoryPagePool::PoolItem<&_story_page_pool> { uint32 sort_value; ///< A number that increases for every created story page. Used for sorting. The id of a story page is the pool index. Date date; ///< Date when the page was created. CompanyByte company; ///< StoryPage is for a specific company; INVALID_COMPANY if it is global char *title; ///< Title of story page /** * We need an (empty) constructor so struct isn't zeroed (as C++ standard states) */ inline StoryPage() { } /** * (Empty) destructor has to be defined else operator delete might be called with NULL parameter */ inline ~StoryPage() { if (!this->CleaningPool()) { StoryPageElement *spe; FOR_ALL_STORY_PAGE_ELEMENTS(spe) { if (spe->page == this->index) delete spe; } } free(this->title); } }; #define FOR_ALL_STORY_PAGES_FROM(var, start) FOR_ALL_ITEMS_FROM(StoryPage, story_page_index, var, start) #define FOR_ALL_STORY_PAGES(var) FOR_ALL_STORY_PAGES_FROM(var, 0) #endif /* STORY_BASE_H */ openttd-1.5.3/src/engine.cpp0000644000000000000000000011304112627373445014450 0ustar rootroot/* $Id: engine.cpp 26802 2014-09-07 16:12:58Z alberth $ */ /* * 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 engine.cpp Base for all engine handling. */ #include "stdafx.h" #include "company_func.h" #include "command_func.h" #include "news_func.h" #include "aircraft.h" #include "newgrf.h" #include "newgrf_engine.h" #include "strings_func.h" #include "core/random_func.hpp" #include "window_func.h" #include "date_func.h" #include "autoreplace_gui.h" #include "string_func.h" #include "ai/ai.hpp" #include "core/pool_func.hpp" #include "engine_gui.h" #include "engine_func.h" #include "engine_base.h" #include "company_base.h" #include "vehicle_func.h" #include "articulated_vehicles.h" #include "error.h" #include "table/strings.h" #include "table/engines.h" #include "safeguards.h" EnginePool _engine_pool("Engine"); INSTANTIATE_POOL_METHODS(Engine) EngineOverrideManager _engine_mngr; /** * Year that engine aging stops. Engines will not reduce in reliability * and no more engines will be introduced */ static Year _year_engine_aging_stops; /** * The railtypes that have been or never will be introduced, or * an inverse bitmap of rail types that have to be introduced. */ static uint16 _introduced_railtypes; /** Number of engines of each vehicle type in original engine data */ const uint8 _engine_counts[4] = { lengthof(_orig_rail_vehicle_info), lengthof(_orig_road_vehicle_info), lengthof(_orig_ship_vehicle_info), lengthof(_orig_aircraft_vehicle_info), }; /** Offset of the first engine of each vehicle type in original engine data */ const uint8 _engine_offsets[4] = { 0, lengthof(_orig_rail_vehicle_info), lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info), lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info), }; assert_compile(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info)); const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT]; Engine::Engine() : name(NULL), overrides_count(0), overrides(NULL) { } Engine::Engine(VehicleType type, EngineID base) { this->type = type; this->grf_prop.local_id = base; this->list_position = base; /* Check if this base engine is within the original engine data range */ if (base >= _engine_counts[type]) { /* Set model life to maximum to make wagons available */ this->info.base_life = 0xFF; /* Set road vehicle tractive effort to the default value */ if (type == VEH_ROAD) this->u.road.tractive_effort = 0x4C; /* Aircraft must have CT_INVALID as default, as there is no property */ if (type == VEH_AIRCRAFT) this->info.cargo_type = CT_INVALID; /* Set visual effect to the default value */ switch (type) { case VEH_TRAIN: this->u.rail.visual_effect = VE_DEFAULT; break; case VEH_ROAD: this->u.road.visual_effect = VE_DEFAULT; break; case VEH_SHIP: this->u.ship.visual_effect = VE_DEFAULT; break; default: break; // The aircraft, disasters and especially visual effects have no NewGRF configured visual effects } /* Set cargo aging period to the default value. */ this->info.cargo_age_period = CARGO_AGING_TICKS; return; } /* Copy the original engine info for this slot */ this->info = _orig_engine_info[_engine_offsets[type] + base]; /* Copy the original engine data for this slot */ switch (type) { default: NOT_REACHED(); case VEH_TRAIN: this->u.rail = _orig_rail_vehicle_info[base]; this->original_image_index = this->u.rail.image_index; this->info.string_id = STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM + base; /* Set the default model life of original wagons to "infinite" */ if (this->u.rail.railveh_type == RAILVEH_WAGON) this->info.base_life = 0xFF; break; case VEH_ROAD: this->u.road = _orig_road_vehicle_info[base]; this->original_image_index = this->u.road.image_index; this->info.string_id = STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS + base; break; case VEH_SHIP: this->u.ship = _orig_ship_vehicle_info[base]; this->original_image_index = this->u.ship.image_index; this->info.string_id = STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER + base; break; case VEH_AIRCRAFT: this->u.air = _orig_aircraft_vehicle_info[base]; this->original_image_index = this->u.air.image_index; this->info.string_id = STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 + base; break; } } Engine::~Engine() { UnloadWagonOverrides(this); free(this->name); } /** * Checks whether the engine is a valid (non-articulated part of an) engine. * @return true if enabled */ bool Engine::IsEnabled() const { return this->info.string_id != STR_NEWGRF_INVALID_ENGINE && HasBit(this->info.climates, _settings_game.game_creation.landscape); } /** * Retrieve the GRF ID of the NewGRF the engine is tied to. * This is the GRF providing the Action 3. * @return GRF ID of the associated NewGRF. */ uint32 Engine::GetGRFID() const { const GRFFile *file = this->GetGRF(); return file == NULL ? 0 : file->grfid; } /** * Determines whether an engine can carry something. * A vehicle cannot carry anything if its capacity is zero, or none of the possible cargoes is available in the climate. * @return true if the vehicle can carry something. */ bool Engine::CanCarryCargo() const { /* For engines that can appear in a consist (i.e. rail vehicles and (articulated) road vehicles), a capacity * of zero is a special case, to define the vehicle to not carry anything. The default cargotype is still used * for livery selection etc. * Note: Only the property is tested. A capacity callback returning 0 does not have the same effect. */ switch (this->type) { case VEH_TRAIN: if (this->u.rail.capacity == 0) return false; break; case VEH_ROAD: if (this->u.road.capacity == 0) return false; break; case VEH_SHIP: case VEH_AIRCRAFT: break; default: NOT_REACHED(); } return this->GetDefaultCargoType() != CT_INVALID; } /** * Determines capacity of a given vehicle from scratch. * For aircraft the main capacity is determined. Mail might be present as well. * @param v Vehicle of interest; NULL in purchase list * @param mail_capacity returns secondary cargo (mail) capacity of aircraft * @return Capacity */ uint Engine::DetermineCapacity(const Vehicle *v, uint16 *mail_capacity) const { assert(v == NULL || this->index == v->engine_type); if (mail_capacity != NULL) *mail_capacity = 0; if (!this->CanCarryCargo()) return 0; bool new_multipliers = HasBit(this->info.misc_flags, EF_NO_DEFAULT_CARGO_MULTIPLIER); CargoID default_cargo = this->GetDefaultCargoType(); CargoID cargo_type = (v != NULL) ? v->cargo_type : default_cargo; if (mail_capacity != NULL && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CC_PASSENGERS)) { *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v); } /* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */ if (HasBit(this->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) && (new_multipliers || default_cargo != cargo_type || (v != NULL && v->cargo_subtype != 0))) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v); if (callback != CALLBACK_FAILED) return callback; } /* Get capacity according to property resp. CB */ uint capacity; uint extra_mail_cap = 0; switch (this->type) { case VEH_TRAIN: capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity, v); /* In purchase list add the capacity of the second head. Always use the plain property for this. */ if (v == NULL && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity; break; case VEH_ROAD: capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->u.road.capacity, v); break; case VEH_SHIP: capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->u.ship.capacity, v); break; case VEH_AIRCRAFT: capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->u.air.passenger_capacity, v); if (!IsCargoInClass(cargo_type, CC_PASSENGERS)) { extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v); } if (!new_multipliers && cargo_type == CT_MAIL) return capacity + extra_mail_cap; default_cargo = CT_PASSENGERS; // Always use 'passengers' wrt. cargo multipliers break; default: NOT_REACHED(); } if (!new_multipliers) { /* Use the passenger multiplier for mail as well */ capacity += extra_mail_cap; extra_mail_cap = 0; } /* Apply multipliers depending on cargo- and vehicletype. */ if (new_multipliers || (this->type != VEH_SHIP && default_cargo != cargo_type)) { uint16 default_multiplier = new_multipliers ? 0x100 : CargoSpec::Get(default_cargo)->multiplier; uint16 cargo_multiplier = CargoSpec::Get(cargo_type)->multiplier; capacity *= cargo_multiplier; if (extra_mail_cap > 0) { uint mail_multiplier = CargoSpec::Get(CT_MAIL)->multiplier; capacity += (default_multiplier * extra_mail_cap * cargo_multiplier + mail_multiplier / 2) / mail_multiplier; } capacity = (capacity + default_multiplier / 2) / default_multiplier; } return capacity; } /** * Return how much the running costs of this engine are. * @return Yearly running cost of the engine. */ Money Engine::GetRunningCost() const { Price base_price; uint cost_factor; switch (this->type) { case VEH_ROAD: base_price = this->u.road.running_cost_class; if (base_price == INVALID_PRICE) return 0; cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_RUNNING_COST_FACTOR, this->u.road.running_cost); break; case VEH_TRAIN: base_price = this->u.rail.running_cost_class; if (base_price == INVALID_PRICE) return 0; cost_factor = GetEngineProperty(this->index, PROP_TRAIN_RUNNING_COST_FACTOR, this->u.rail.running_cost); break; case VEH_SHIP: base_price = PR_RUNNING_SHIP; cost_factor = GetEngineProperty(this->index, PROP_SHIP_RUNNING_COST_FACTOR, this->u.ship.running_cost); break; case VEH_AIRCRAFT: base_price = PR_RUNNING_AIRCRAFT; cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_RUNNING_COST_FACTOR, this->u.air.running_cost); break; default: NOT_REACHED(); } return GetPrice(base_price, cost_factor, this->GetGRF(), -8); } /** * Return how much a new engine costs. * @return Cost of the engine. */ Money Engine::GetCost() const { Price base_price; uint cost_factor; switch (this->type) { case VEH_ROAD: base_price = PR_BUILD_VEHICLE_ROAD; cost_factor = GetEngineProperty(this->index, PROP_ROADVEH_COST_FACTOR, this->u.road.cost_factor); break; case VEH_TRAIN: if (this->u.rail.railveh_type == RAILVEH_WAGON) { base_price = PR_BUILD_VEHICLE_WAGON; cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor); } else { base_price = PR_BUILD_VEHICLE_TRAIN; cost_factor = GetEngineProperty(this->index, PROP_TRAIN_COST_FACTOR, this->u.rail.cost_factor); } break; case VEH_SHIP: base_price = PR_BUILD_VEHICLE_SHIP; cost_factor = GetEngineProperty(this->index, PROP_SHIP_COST_FACTOR, this->u.ship.cost_factor); break; case VEH_AIRCRAFT: base_price = PR_BUILD_VEHICLE_AIRCRAFT; cost_factor = GetEngineProperty(this->index, PROP_AIRCRAFT_COST_FACTOR, this->u.air.cost_factor); break; default: NOT_REACHED(); } return GetPrice(base_price, cost_factor, this->GetGRF(), -8); } /** * Returns max speed of the engine for display purposes * @return max speed in km-ish/h */ uint Engine::GetDisplayMaxSpeed() const { switch (this->type) { case VEH_TRAIN: return GetEngineProperty(this->index, PROP_TRAIN_SPEED, this->u.rail.max_speed); case VEH_ROAD: { uint max_speed = GetEngineProperty(this->index, PROP_ROADVEH_SPEED, 0); return (max_speed != 0) ? max_speed * 2 : this->u.road.max_speed / 2; } case VEH_SHIP: return GetEngineProperty(this->index, PROP_SHIP_SPEED, this->u.ship.max_speed) / 2; case VEH_AIRCRAFT: { uint max_speed = GetEngineProperty(this->index, PROP_AIRCRAFT_SPEED, 0); if (max_speed != 0) { return (max_speed * 128) / 10; } return this->u.air.max_speed; } default: NOT_REACHED(); } } /** * Returns the power of the engine for display * and sorting purposes. * Only trains and road vehicles have power * @return power in display units hp */ uint Engine::GetPower() const { /* Only trains and road vehicles have 'power'. */ switch (this->type) { case VEH_TRAIN: return GetEngineProperty(this->index, PROP_TRAIN_POWER, this->u.rail.power); case VEH_ROAD: return GetEngineProperty(this->index, PROP_ROADVEH_POWER, this->u.road.power) * 10; default: NOT_REACHED(); } } /** * Returns the weight of the engine for display purposes. * For dual-headed train-engines this is the weight of both heads * @return weight in display units metric tons */ uint Engine::GetDisplayWeight() const { /* Only trains and road vehicles have 'weight'. */ switch (this->type) { case VEH_TRAIN: return GetEngineProperty(this->index, PROP_TRAIN_WEIGHT, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0); case VEH_ROAD: return GetEngineProperty(this->index, PROP_ROADVEH_WEIGHT, this->u.road.weight) / 4; default: NOT_REACHED(); } } /** * Returns the tractive effort of the engine for display purposes. * For dual-headed train-engines this is the tractive effort of both heads * @return tractive effort in display units kN */ uint Engine::GetDisplayMaxTractiveEffort() const { /* Only trains and road vehicles have 'tractive effort'. */ switch (this->type) { case VEH_TRAIN: return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_TRAIN_TRACTIVE_EFFORT, this->u.rail.tractive_effort)) / 256; case VEH_ROAD: return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, PROP_ROADVEH_TRACTIVE_EFFORT, this->u.road.tractive_effort)) / 256; default: NOT_REACHED(); } } /** * Returns the vehicle's (not model's!) life length in days. * @return the life length */ Date Engine::GetLifeLengthInDays() const { /* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */ return (this->info.lifelength + _settings_game.vehicle.extend_vehicle_life) * DAYS_IN_LEAP_YEAR; } /** * Get the range of an aircraft type. * @return Range of the aircraft type in tiles or 0 if unlimited range. */ uint16 Engine::GetRange() const { switch (this->type) { case VEH_AIRCRAFT: return GetEngineProperty(this->index, PROP_AIRCRAFT_RANGE, this->u.air.max_range); default: NOT_REACHED(); } } /** * Initializes the EngineOverrideManager with the default engines. */ void EngineOverrideManager::ResetToDefaultMapping() { this->Clear(); for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) { for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) { EngineIDMapping *eid = this->Append(); eid->type = type; eid->grfid = INVALID_GRFID; eid->internal_id = internal_id; eid->substitute_id = internal_id; } } } /** * Looks up an EngineID in the EngineOverrideManager * @param type Vehicle type * @param grf_local_id The local id in the newgrf * @param grfid The GrfID that defines the scope of grf_local_id. * If a newgrf overrides the engines of another newgrf, the "scope grfid" is the ID of the overridden newgrf. * If dynnamic_engines is disabled, all newgrf share the same ID scope identified by INVALID_GRFID. * @return The engine ID if present, or INVALID_ENGINE if not. */ EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid) { const EngineIDMapping *end = this->End(); EngineID index = 0; for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) { if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) { return index; } } return INVALID_ENGINE; } /** * Tries to reset the engine mapping to match the current NewGRF configuration. * This is only possible when there are currently no vehicles in the game. * @return false if resetting failed due to present vehicles. */ bool EngineOverrideManager::ResetToCurrentNewGRFConfig() { const Vehicle *v; FOR_ALL_VEHICLES(v) { if (IsCompanyBuildableVehicleType(v)) return false; } /* Reset the engines, they will get new EngineIDs */ _engine_mngr.ResetToDefaultMapping(); ReloadNewGRFData(); return true; } /** * Initialise the engine pool with the data from the original vehicles. */ void SetupEngines() { DeleteWindowByClass(WC_ENGINE_PREVIEW); _engine_pool.CleanPool(); assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES); const EngineIDMapping *end = _engine_mngr.End(); uint index = 0; for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) { /* Assert is safe; there won't be more than 256 original vehicles * in any case, and we just cleaned the pool. */ assert(Engine::CanAllocateItem()); const Engine *e = new Engine(eid->type, eid->internal_id); assert(e->index == index); } _introduced_railtypes = 0; } /** * Check whether the railtypes should be introduced. */ static void CheckRailIntroduction() { /* All railtypes have been introduced. */ if (_introduced_railtypes == UINT16_MAX || Company::GetPoolSize() == 0) return; /* We need to find the railtypes that are known to all companies. */ RailTypes rts = (RailTypes)UINT16_MAX; /* We are at, or past the introduction date of the rail. */ Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes, _date); rts &= c->avail_railtypes; } _introduced_railtypes |= rts; } void ShowEnginePreviewWindow(EngineID engine); /** * Determine whether an engine type is a wagon (and not a loco). * @param index %Engine getting queried. * @return Whether the queried engine is a wagon. */ static bool IsWagon(EngineID index) { const Engine *e = Engine::Get(index); return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON; } /** * Update #reliability of engine \a e, (if needed) update the engine GUIs. * @param e %Engine to update. */ static void CalcEngineReliability(Engine *e) { uint age = e->age; /* Check for early retirement */ if (e->company_avail != 0 && !_settings_game.vehicle.never_expire_vehicles && e->info.base_life != 0xFF) { int retire_early = e->info.retire_early; uint retire_early_max_age = max(0, e->duration_phase_1 + e->duration_phase_2 - retire_early * 12); if (retire_early != 0 && age >= retire_early_max_age) { /* Early retirement is enabled and we're past the date... */ e->company_avail = 0; AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } } if (age < e->duration_phase_1) { uint start = e->reliability_start; e->reliability = age * (e->reliability_max - start) / e->duration_phase_1 + start; } else if ((age -= e->duration_phase_1) < e->duration_phase_2 || _settings_game.vehicle.never_expire_vehicles || e->info.base_life == 0xFF) { /* We are at the peak of this engines life. It will have max reliability. * This is also true if the engines never expire. They will not go bad over time */ e->reliability = e->reliability_max; } else if ((age -= e->duration_phase_2) < e->duration_phase_3) { uint max = e->reliability_max; e->reliability = (int)age * (int)(e->reliability_final - max) / e->duration_phase_3 + max; } else { /* time's up for this engine. * We will now completely retire this design */ e->company_avail = 0; e->reliability = e->reliability_final; /* Kick this engine out of the lists */ AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } SetWindowClassesDirty(WC_BUILD_VEHICLE); // Update to show the new reliability SetWindowClassesDirty(WC_REPLACE_VEHICLE); } /** Compute the value for #_year_engine_aging_stops. */ void SetYearEngineAgingStops() { /* Determine last engine aging year, default to 2050 as previously. */ _year_engine_aging_stops = 2050; const Engine *e; FOR_ALL_ENGINES(e) { const EngineInfo *ei = &e->info; /* Exclude certain engines */ if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue; if (e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON) continue; /* Base year ending date on half the model life */ YearMonthDay ymd; ConvertDateToYMD(ei->base_intro + (ei->lifelength * DAYS_IN_LEAP_YEAR) / 2, &ymd); _year_engine_aging_stops = max(_year_engine_aging_stops, ymd.year); } } /** * Start/initialise one engine. * @param e The engine to initialise. * @param aging_date The date used for age calculations. */ void StartupOneEngine(Engine *e, Date aging_date) { const EngineInfo *ei = &e->info; e->age = 0; e->flags = 0; e->company_avail = 0; e->company_hidden = 0; /* Don't randomise the start-date in the first two years after gamestart to ensure availability * of engines in early starting games. * Note: TTDP uses fixed 1922 */ uint32 r = Random(); e->intro_date = ei->base_intro <= ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro; if (e->intro_date <= _date) { e->age = (aging_date - e->intro_date) >> 5; e->company_avail = (CompanyMask)-1; e->flags |= ENGINE_AVAILABLE; } e->reliability_start = GB(r, 16, 14) + 0x7AE0; r = Random(); e->reliability_max = GB(r, 0, 14) + 0xBFFF; e->reliability_final = GB(r, 16, 14) + 0x3FFF; r = Random(); e->duration_phase_1 = GB(r, 0, 5) + 7; e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96; e->duration_phase_3 = GB(r, 9, 7) + 120; e->reliability_spd_dec = ei->decay_speed << 2; CalcEngineReliability(e); /* prevent certain engines from ever appearing. */ if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) { e->flags |= ENGINE_AVAILABLE; e->company_avail = 0; } } /** * Start/initialise all our engines. Must be called whenever there are changes * to the NewGRF config. */ void StartupEngines() { Engine *e; /* Aging of vehicles stops, so account for that when starting late */ const Date aging_date = min(_date, ConvertYMDToDate(_year_engine_aging_stops, 0, 1)); FOR_ALL_ENGINES(e) { StartupOneEngine(e, aging_date); } /* Update the bitmasks for the vehicle lists */ Company *c; FOR_ALL_COMPANIES(c) { c->avail_railtypes = GetCompanyRailtypes(c->index); c->avail_roadtypes = GetCompanyRoadtypes(c->index); } /* Rail types that are invalid or never introduced are marked as * being introduced upon start. That way we can easily check whether * there is any date related introduction that is still going to * happen somewhere in the future. */ for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { const RailtypeInfo *rti = GetRailTypeInfo(rt); if (rti->label != 0 && IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue; SetBit(_introduced_railtypes, rt); } CheckRailIntroduction(); /* Invalidate any open purchase lists */ InvalidateWindowClassesData(WC_BUILD_VEHICLE); } /** * Company \a company accepts engine \a eid for preview. * @param eid Engine being accepted (is under preview). * @param company Current company previewing the engine. */ static void AcceptEnginePreview(EngineID eid, CompanyID company) { Engine *e = Engine::Get(eid); Company *c = Company::Get(company); SetBit(e->company_avail, company); if (e->type == VEH_TRAIN) { assert(e->u.rail.railtype < RAILTYPE_END); c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date); } else if (e->type == VEH_ROAD) { SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); } e->preview_company = INVALID_COMPANY; e->preview_asked = (CompanyMask)-1; if (company == _local_company) { AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } /* Update the toolbar. */ if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD); if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER); /* Notify preview window, that it might want to close. * Note: We cannot directly close the window. * In singleplayer this function is called from the preview window, so * we have to use the GUI-scope scheduling of InvalidateWindowData. */ InvalidateWindowData(WC_ENGINE_PREVIEW, eid); } /** * Get the best company for an engine preview. * @param e Engine to preview. * @return Best company if it exists, #INVALID_COMPANY otherwise. */ static CompanyID GetPreviewCompany(Engine *e) { CompanyID best_company = INVALID_COMPANY; /* For trains the cargomask has no useful meaning, since you can attach other wagons */ uint32 cargomask = e->type != VEH_TRAIN ? GetUnionOfArticulatedRefitMasks(e->index, true) : (uint32)-1; int32 best_hist = -1; const Company *c; FOR_ALL_COMPANIES(c) { if (c->block_preview == 0 && !HasBit(e->preview_asked, c->index) && c->old_economy[0].performance_history > best_hist) { /* Check whether the company uses similar vehicles */ Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner != c->index || v->type != e->type) continue; if (!v->GetEngine()->CanCarryCargo() || !HasBit(cargomask, v->cargo_type)) continue; best_hist = c->old_economy[0].performance_history; best_company = c->index; break; } } } return best_company; } /** * Checks if a vehicle type is disabled for all/ai companies. * @param type The vehicle type which shall be checked. * @param ai If true, check if the type is disabled for AI companies, otherwise check if * the vehicle type is disabled for human companies. * @return Whether or not a vehicle type is disabled. */ static bool IsVehicleTypeDisabled(VehicleType type, bool ai) { switch (type) { case VEH_TRAIN: return _settings_game.vehicle.max_trains == 0 || (ai && _settings_game.ai.ai_disable_veh_train); case VEH_ROAD: return _settings_game.vehicle.max_roadveh == 0 || (ai && _settings_game.ai.ai_disable_veh_roadveh); case VEH_SHIP: return _settings_game.vehicle.max_ships == 0 || (ai && _settings_game.ai.ai_disable_veh_ship); case VEH_AIRCRAFT: return _settings_game.vehicle.max_aircraft == 0 || (ai && _settings_game.ai.ai_disable_veh_aircraft); default: NOT_REACHED(); } } /** Daily check to offer an exclusive engine preview to the companies. */ void EnginesDailyLoop() { CheckRailIntroduction(); if (_cur_year >= _year_engine_aging_stops) return; Engine *e; FOR_ALL_ENGINES(e) { EngineID i = e->index; if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) { if (e->preview_company != INVALID_COMPANY) { if (!--e->preview_wait) { DeleteWindowById(WC_ENGINE_PREVIEW, i); e->preview_company = INVALID_COMPANY; } } else if (CountBits(e->preview_asked) < MAX_COMPANIES) { e->preview_company = GetPreviewCompany(e); if (e->preview_company == INVALID_COMPANY) { e->preview_asked = (CompanyMask)-1; continue; } SetBit(e->preview_asked, e->preview_company); e->preview_wait = 20; /* AIs are intentionally not skipped for preview even if they cannot build a certain * vehicle type. This is done to not give poor performing human companies an "unfair" * boost that they wouldn't have gotten against other human companies. The check on * the line below is just to make AIs not notice that they have a preview if they * cannot build the vehicle. */ if (!IsVehicleTypeDisabled(e->type, true)) AI::NewEvent(e->preview_company, new ScriptEventEnginePreview(i)); if (IsInteractiveCompany(e->preview_company)) ShowEnginePreviewWindow(i); } } } } /** * Clear the 'hidden' flag for all engines of a new company. * @param cid Company being created. */ void ClearEnginesHiddenFlagOfCompany(CompanyID cid) { Engine *e; FOR_ALL_ENGINES(e) { SB(e->company_hidden, cid, 1, 0); } } /** * Set the visibility of an engine. * @param tile Unused. * @param flags Operation to perform. * @param p1 Unused. * @param p2 Bit 31: 0=visible, 1=hidden, other bits for the #EngineID. * @param text Unused. * @return The cost of this operation or an error. */ CommandCost CmdSetVehicleVisibility(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Engine *e = Engine::GetIfValid(GB(p2, 0, 31)); if (e == NULL || _current_company >= MAX_COMPANIES) return CMD_ERROR; if ((e->flags & ENGINE_AVAILABLE) == 0 || !HasBit(e->company_avail, _current_company)) return CMD_ERROR; if ((flags & DC_EXEC) != 0) { SB(e->company_hidden, _current_company, 1, GB(p2, 31, 1)); AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); } return CommandCost(); } /** * Accept an engine prototype. XXX - it is possible that the top-company * changes while you are waiting to accept the offer? Then it becomes invalid * @param tile unused * @param flags operation to perform * @param p1 engine-prototype offered * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdWantEnginePreview(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Engine *e = Engine::GetIfValid(p1); if (e == NULL || e->preview_company != _current_company) return CMD_ERROR; if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_company); return CommandCost(); } /** * An engine has become available for general use. * Also handle the exclusive engine preview contract. * @param e Engine generally available as of now. */ static void NewVehicleAvailable(Engine *e) { Vehicle *v; Company *c; EngineID index = e->index; /* In case the company didn't build the vehicle during the intro period, * prevent that company from getting future intro periods for a while. */ if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) { FOR_ALL_COMPANIES(c) { uint block_preview = c->block_preview; if (!HasBit(e->company_avail, c->index)) continue; /* We assume the user did NOT build it.. prove me wrong ;) */ c->block_preview = 20; FOR_ALL_VEHICLES(v) { if (v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP || (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft())) { if (v->owner == c->index && v->engine_type == index) { /* The user did prove me wrong, so restore old value */ c->block_preview = block_preview; break; } } } } } e->flags = (e->flags & ~ENGINE_EXCLUSIVE_PREVIEW) | ENGINE_AVAILABLE; AddRemoveEngineFromAutoreplaceAndBuildWindows(e->type); /* Now available for all companies */ e->company_avail = (CompanyMask)-1; /* Do not introduce new rail wagons */ if (IsWagon(index)) return; if (e->type == VEH_TRAIN) { /* maybe make another rail type available */ RailType railtype = e->u.rail.railtype; assert(railtype < RAILTYPE_END); FOR_ALL_COMPANIES(c) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date); } else if (e->type == VEH_ROAD) { /* maybe make another road type available */ FOR_ALL_COMPANIES(c) SetBit(c->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD); } /* Only broadcast event if AIs are able to build this vehicle type. */ if (!IsVehicleTypeDisabled(e->type, true)) AI::BroadcastNewEvent(new ScriptEventEngineAvailable(index)); /* Only provide the "New Vehicle available" news paper entry, if engine can be built. */ if (!IsVehicleTypeDisabled(e->type, false)) { SetDParam(0, GetEngineCategoryName(index)); SetDParam(1, index); AddNewsItem(STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NT_NEW_VEHICLES, NF_VEHICLE, NR_ENGINE, index); } /* Update the toolbar. */ if (e->type == VEH_ROAD) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_ROAD); if (e->type == VEH_SHIP) InvalidateWindowData(WC_BUILD_TOOLBAR, TRANSPORT_WATER); /* Close pending preview windows */ DeleteWindowById(WC_ENGINE_PREVIEW, index); } /** Monthly update of the availability, reliability, and preview offers of the engines. */ void EnginesMonthlyLoop() { if (_cur_year < _year_engine_aging_stops) { Engine *e; FOR_ALL_ENGINES(e) { /* Age the vehicle */ if ((e->flags & ENGINE_AVAILABLE) && e->age != MAX_DAY) { e->age++; CalcEngineReliability(e); } /* Do not introduce invalid engines */ if (!e->IsEnabled()) continue; if (!(e->flags & ENGINE_AVAILABLE) && _date >= (e->intro_date + DAYS_IN_YEAR)) { /* Introduce it to all companies */ NewVehicleAvailable(e); } else if (!(e->flags & (ENGINE_AVAILABLE | ENGINE_EXCLUSIVE_PREVIEW)) && _date >= e->intro_date) { /* Introduction date has passed... * Check if it is allowed to build this vehicle type at all * based on the current game settings. If not, it does not * make sense to show the preview dialog to any company. */ if (IsVehicleTypeDisabled(e->type, false)) continue; /* Do not introduce new rail wagons */ if (IsWagon(e->index)) continue; /* Show preview dialog to one of the companies. */ e->flags |= ENGINE_EXCLUSIVE_PREVIEW; e->preview_company = INVALID_COMPANY; e->preview_asked = 0; } } InvalidateWindowClassesData(WC_BUILD_VEHICLE); // rebuild the purchase list (esp. when sorted by reliability) } } /** * Is \a name still free as name for an engine? * @param name New name of an engine. * @return \c false if the name is being used already, else \c true. */ static bool IsUniqueEngineName(const char *name) { const Engine *e; FOR_ALL_ENGINES(e) { if (e->name != NULL && strcmp(e->name, name) == 0) return false; } return true; } /** * Rename an engine. * @param tile unused * @param flags operation to perform * @param p1 engine ID to rename * @param p2 unused * @param text the new name or an empty string when resetting to the default * @return the cost of this operation or an error */ CommandCost CmdRenameEngine(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Engine *e = Engine::GetIfValid(p1); if (e == NULL) return CMD_ERROR; bool reset = StrEmpty(text); if (!reset) { if (Utf8StringLength(text) >= MAX_LENGTH_ENGINE_NAME_CHARS) return CMD_ERROR; if (!IsUniqueEngineName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE); } if (flags & DC_EXEC) { free(e->name); if (reset) { e->name = NULL; } else { e->name = stredup(text); } MarkWholeScreenDirty(); } return CommandCost(); } /** * Check if an engine is buildable. * @param engine index of the engine to check. * @param type the type the engine should be. * @param company index of the company. * @return True if an engine is valid, of the specified type, and buildable by * the given company. */ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company) { const Engine *e = Engine::GetIfValid(engine); /* check if it's an engine that is in the engine array */ if (e == NULL) return false; /* check if it's an engine of specified type */ if (e->type != type) return false; /* check if it's available ... */ if (company == OWNER_DEITY) { /* ... for any company (preview does not count) */ if (!(e->flags & ENGINE_AVAILABLE) || e->company_avail == 0) return false; } else { /* ... for this company */ if (!HasBit(e->company_avail, company)) return false; } if (!e->IsEnabled()) return false; if (type == VEH_TRAIN && company != OWNER_DEITY) { /* Check if the rail type is available to this company */ const Company *c = Company::Get(company); if (((GetRailTypeInfo(e->u.rail.railtype))->compatible_railtypes & c->avail_railtypes) == 0) return false; } return true; } /** * Check if an engine is refittable. * Note: Likely you want to use IsArticulatedVehicleRefittable(). * @param engine index of the engine to check. * @return true if the engine is refittable. */ bool IsEngineRefittable(EngineID engine) { const Engine *e = Engine::GetIfValid(engine); /* check if it's an engine that is in the engine array */ if (e == NULL) return false; if (!e->CanCarryCargo()) return false; const EngineInfo *ei = &e->info; if (ei->refit_mask == 0) return false; /* Are there suffixes? * Note: This does not mean the suffixes are actually available for every consist at any time. */ if (HasBit(ei->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) return true; /* Is there any cargo except the default cargo? */ CargoID default_cargo = e->GetDefaultCargoType(); return default_cargo != CT_INVALID && ei->refit_mask != 1U << default_cargo; } /** * Check for engines that have an appropriate availability. */ void CheckEngines() { const Engine *e; Date min_date = INT32_MAX; FOR_ALL_ENGINES(e) { if (!e->IsEnabled()) continue; /* We have an available engine... yay! */ if ((e->flags & ENGINE_AVAILABLE) != 0 && e->company_avail != 0) return; /* Okay, try to find the earliest date. */ min_date = min(min_date, e->info.base_intro); } if (min_date < INT32_MAX) { SetDParam(0, min_date); ShowErrorMessage(STR_ERROR_NO_VEHICLES_AVAILABLE_YET, STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION, WL_WARNING); } else { ShowErrorMessage(STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL, STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION, WL_WARNING); } } openttd-1.5.3/src/goal.cpp0000644000000000000000000002046412627373442014130 0ustar rootroot/* $Id: goal.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 goal.cpp Handling of goals. */ #include "stdafx.h" #include "company_func.h" #include "industry.h" #include "town.h" #include "window_func.h" #include "goal_base.h" #include "core/pool_func.hpp" #include "game/game.hpp" #include "command_func.h" #include "company_base.h" #include "story_base.h" #include "string_func.h" #include "gui.h" #include "network/network.h" #include "safeguards.h" GoalID _new_goal_id; GoalPool _goal_pool("Goal"); INSTANTIATE_POOL_METHODS(Goal) /** * Create a new goal. * @param tile unused. * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 7) - GoalType of destination. * - p1 = (bit 8 - 15) - Company for which this goal is. * @param p2 GoalTypeID of destination. * @param text Text of the goal. * @return the cost of this operation or an error */ CommandCost CmdCreateGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (!Goal::CanAllocateItem()) return CMD_ERROR; GoalType type = (GoalType)GB(p1, 0, 8); CompanyID company = (CompanyID)GB(p1, 8, 8); if (_current_company != OWNER_DEITY) return CMD_ERROR; if (StrEmpty(text)) return CMD_ERROR; if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR; switch (type) { case GT_NONE: if (p2 != 0) return CMD_ERROR; break; case GT_TILE: if (!IsValidTile(p2)) return CMD_ERROR; break; case GT_INDUSTRY: if (!Industry::IsValidID(p2)) return CMD_ERROR; break; case GT_TOWN: if (!Town::IsValidID(p2)) return CMD_ERROR; break; case GT_COMPANY: if (!Company::IsValidID(p2)) return CMD_ERROR; break; case GT_STORY_PAGE: { if (!StoryPage::IsValidID(p2)) return CMD_ERROR; CompanyByte story_company = StoryPage::Get(p2)->company; if (company == INVALID_COMPANY ? story_company != INVALID_COMPANY : story_company != INVALID_COMPANY && story_company != company) return CMD_ERROR; break; } default: return CMD_ERROR; } if (flags & DC_EXEC) { Goal *g = new Goal(); g->type = type; g->dst = p2; g->company = company; g->text = stredup(text); g->progress = NULL; g->completed = false; if (g->company == INVALID_COMPANY) { InvalidateWindowClassesData(WC_GOALS_LIST); } else { InvalidateWindowData(WC_GOALS_LIST, g->company); } if (Goal::GetNumItems() == 1) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); _new_goal_id = g->index; } return CommandCost(); } /** * Remove a goal. * @param tile unused. * @param flags type of operation * @param p1 GoalID to remove. * @param p2 unused. * @param text unused. * @return the cost of this operation or an error */ CommandCost CmdRemoveGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!Goal::IsValidID(p1)) return CMD_ERROR; if (flags & DC_EXEC) { Goal *g = Goal::Get(p1); CompanyID c = g->company; delete g; if (c == INVALID_COMPANY) { InvalidateWindowClassesData(WC_GOALS_LIST); } else { InvalidateWindowData(WC_GOALS_LIST, c); } if (Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); } return CommandCost(); } /** * Update goal text of a goal. * @param tile unused. * @param flags type of operation * @param p1 GoalID to update. * @param p2 unused * @param text Text of the goal. * @return the cost of this operation or an error */ CommandCost CmdSetGoalText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!Goal::IsValidID(p1)) return CMD_ERROR; if (StrEmpty(text)) return CMD_ERROR; if (flags & DC_EXEC) { Goal *g = Goal::Get(p1); free(g->text); g->text = stredup(text); if (g->company == INVALID_COMPANY) { InvalidateWindowClassesData(WC_GOALS_LIST); } else { InvalidateWindowData(WC_GOALS_LIST, g->company); } } return CommandCost(); } /** * Update progress text of a goal. * @param tile unused. * @param flags type of operation * @param p1 GoalID to update. * @param p2 unused * @param text Progress text of the goal. * @return the cost of this operation or an error */ CommandCost CmdSetGoalProgress(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!Goal::IsValidID(p1)) return CMD_ERROR; if (flags & DC_EXEC) { Goal *g = Goal::Get(p1); free(g->progress); if (StrEmpty(text)) { g->progress = NULL; } else { g->progress = stredup(text); } if (g->company == INVALID_COMPANY) { InvalidateWindowClassesData(WC_GOALS_LIST); } else { InvalidateWindowData(WC_GOALS_LIST, g->company); } } return CommandCost(); } /** * Update completed state of a goal. * @param tile unused. * @param flags type of operation * @param p1 GoalID to update. * @param p2 completed state. If goal is completed, set to 1, otherwise 0. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSetGoalCompleted(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!Goal::IsValidID(p1)) return CMD_ERROR; if (flags & DC_EXEC) { Goal *g = Goal::Get(p1); g->completed = p2 == 1; if (g->company == INVALID_COMPANY) { InvalidateWindowClassesData(WC_GOALS_LIST); } else { InvalidateWindowData(WC_GOALS_LIST, g->company); } } return CommandCost(); } /** * Ask a goal related question * @param tile unused. * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 15) - Unique ID to use for this question. * - p1 = (bit 16 - 23) - Company for which this question is. * @param p2 Buttons of the question. * @param text Text of the question. * @return the cost of this operation or an error */ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { uint16 uniqueid = (GoalType)GB(p1, 0, 16); CompanyID company = (CompanyID)GB(p1, 16, 8); byte type = GB(p1, 24, 8); if (_current_company != OWNER_DEITY) return CMD_ERROR; if (StrEmpty(text)) return CMD_ERROR; if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR; if (CountBits(p2) < 1 || CountBits(p2) > 3) return CMD_ERROR; if (p2 >= (1 << GOAL_QUESTION_BUTTON_COUNT)) return CMD_ERROR; if (type >= GOAL_QUESTION_TYPE_COUNT) return CMD_ERROR; if (flags & DC_EXEC) { if ((company != INVALID_COMPANY && company == _local_company) || (company == INVALID_COMPANY && Company::IsValidID(_local_company))) ShowGoalQuestion(uniqueid, type, p2, text); } return CommandCost(); } /** * Reply to a goal question. * @param tile unused. * @param flags type of operation * @param p1 Unique ID to use for this question. * @param p2 Button the company pressed * @param text Text of the question. * @return the cost of this operation or an error */ CommandCost CmdGoalQuestionAnswer(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (p1 > UINT16_MAX) return CMD_ERROR; if (p2 >= GOAL_QUESTION_BUTTON_COUNT) return CMD_ERROR; if (_current_company == OWNER_DEITY) { /* It has been requested to close this specific question on all clients */ if (flags & DC_EXEC) DeleteWindowById(WC_GOAL_QUESTION, p1); return CommandCost(); } if (_networking && _local_company == _current_company) { /* Somebody in the same company answered the question. Close the window */ if (flags & DC_EXEC) DeleteWindowById(WC_GOAL_QUESTION, p1); if (!_network_server) return CommandCost(); } if (flags & DC_EXEC) { Game::NewEvent(new ScriptEventGoalQuestionAnswer(p1, (ScriptCompany::CompanyID)(byte)_current_company, (ScriptGoal::QuestionButton)(1 << p2))); } return CommandCost(); } openttd-1.5.3/src/tilearea.cpp0000644000000000000000000001472212627373442014774 0ustar rootroot/* $Id: tilearea.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tilearea.cpp Handling of tile areas. */ #include "stdafx.h" #include "tilearea_type.h" #include "safeguards.h" /** * Construct this tile area based on two points. * @param start the start of the area * @param end the end of the area */ OrthogonalTileArea::OrthogonalTileArea(TileIndex start, TileIndex end) { assert(start < MapSize()); assert(end < MapSize()); uint sx = TileX(start); uint sy = TileY(start); uint ex = TileX(end); uint ey = TileY(end); if (sx > ex) Swap(sx, ex); if (sy > ey) Swap(sy, ey); this->tile = TileXY(sx, sy); this->w = ex - sx + 1; this->h = ey - sy + 1; } /** * Add a single tile to a tile area; enlarge if needed. * @param to_add The tile to add */ void OrthogonalTileArea::Add(TileIndex to_add) { if (this->tile == INVALID_TILE) { this->tile = to_add; this->w = 1; this->h = 1; return; } uint sx = TileX(this->tile); uint sy = TileY(this->tile); uint ex = sx + this->w - 1; uint ey = sy + this->h - 1; uint ax = TileX(to_add); uint ay = TileY(to_add); sx = min(ax, sx); sy = min(ay, sy); ex = max(ax, ex); ey = max(ay, ey); this->tile = TileXY(sx, sy); this->w = ex - sx + 1; this->h = ey - sy + 1; } /** * Does this tile area intersect with another? * @param ta the other tile area to check against. * @return true if they intersect. */ bool OrthogonalTileArea::Intersects(const OrthogonalTileArea &ta) const { if (ta.w == 0 || this->w == 0) return false; assert(ta.w != 0 && ta.h != 0 && this->w != 0 && this->h != 0); uint left1 = TileX(this->tile); uint top1 = TileY(this->tile); uint right1 = left1 + this->w - 1; uint bottom1 = top1 + this->h - 1; uint left2 = TileX(ta.tile); uint top2 = TileY(ta.tile); uint right2 = left2 + ta.w - 1; uint bottom2 = top2 + ta.h - 1; return !( left2 > right1 || right2 < left1 || top2 > bottom1 || bottom2 < top1 ); } /** * Does this tile area contain a tile? * @param tile Tile to test for. * @return True if the tile is inside the area. */ bool OrthogonalTileArea::Contains(TileIndex tile) const { if (this->w == 0) return false; assert(this->w != 0 && this->h != 0); uint left = TileX(this->tile); uint top = TileY(this->tile); uint tile_x = TileX(tile); uint tile_y = TileY(tile); return IsInsideBS(tile_x, left, this->w) && IsInsideBS(tile_y, top, this->h); } /** * Clamp the tile area to map borders. */ void OrthogonalTileArea::ClampToMap() { assert(this->tile < MapSize()); this->w = min(this->w, MapSizeX() - TileX(this->tile)); this->h = min(this->h, MapSizeY() - TileY(this->tile)); } /** * Create a diagonal tile area from two corners. * @param start First corner of the area. * @param end Second corner of the area. */ DiagonalTileArea::DiagonalTileArea(TileIndex start, TileIndex end) : tile(start) { assert(start < MapSize()); assert(end < MapSize()); /* Unfortunately we can't find a new base and make all a and b positive because * the new base might be a "flattened" corner where there actually is no single * tile. If we try anyway the result is either inaccurate ("one off" half of the * time) or the code gets much more complex; * * We also need to increment/decrement a and b here to have one-past-end semantics * for a and b, just the way the orthogonal tile area does it for w and h. */ this->a = TileY(end) + TileX(end) - TileY(start) - TileX(start); this->b = TileY(end) - TileX(end) - TileY(start) + TileX(start); if (this->a > 0) { this->a++; } else { this->a--; } if (this->b > 0) { this->b++; } else { this->b--; } } /** * Does this tile area contain a tile? * @param tile Tile to test for. * @return True if the tile is inside the area. */ bool DiagonalTileArea::Contains(TileIndex tile) const { int a = TileY(tile) + TileX(tile); int b = TileY(tile) - TileX(tile); int start_a = TileY(this->tile) + TileX(this->tile); int start_b = TileY(this->tile) - TileX(this->tile); int end_a = start_a + this->a; int end_b = start_b + this->b; /* Swap if necessary, preserving the "one past end" semantics. */ if (start_a > end_a) { int tmp = start_a; start_a = end_a + 1; end_a = tmp + 1; } if (start_b > end_b) { int tmp = start_b; start_b = end_b + 1; end_b = tmp + 1; } return (a >= start_a && a < end_a && b >= start_b && b < end_b); } /** * Move ourselves to the next tile in the rectangle on the map. */ TileIterator &DiagonalTileIterator::operator++() { assert(this->tile != INVALID_TILE); /* Determine the next tile, while clipping at map borders */ bool new_line = false; do { /* Iterate using the rotated coordinates. */ if (this->a_max == 1 || this->a_max == -1) { /* Special case: Every second column has zero length, skip them completely */ this->a_cur = 0; if (this->b_max > 0) { this->b_cur = min(this->b_cur + 2, this->b_max); } else { this->b_cur = max(this->b_cur - 2, this->b_max); } } else { /* Every column has at least one tile to process */ if (this->a_max > 0) { this->a_cur += 2; new_line = this->a_cur >= this->a_max; } else { this->a_cur -= 2; new_line = this->a_cur <= this->a_max; } if (new_line) { /* offset of initial a_cur: one tile in the same direction as a_max * every second line. */ this->a_cur = abs(this->a_cur) % 2 ? 0 : (this->a_max > 0 ? 1 : -1); if (this->b_max > 0) { ++this->b_cur; } else { --this->b_cur; } } } /* And convert the coordinates back once we've gone to the next tile. */ uint x = this->base_x + (this->a_cur - this->b_cur) / 2; uint y = this->base_y + (this->b_cur + this->a_cur) / 2; /* Prevent wrapping around the map's borders. */ this->tile = x >= MapSizeX() || y >= MapSizeY() ? INVALID_TILE : TileXY(x, y); } while (this->tile > MapSize() && this->b_max != this->b_cur); if (this->b_max == this->b_cur) this->tile = INVALID_TILE; return *this; } openttd-1.5.3/src/story_type.h0000644000000000000000000000243012627373442015065 0ustar rootroot/* $Id: story_type.h 25371 2013-06-09 13:18:37Z rubidium $ */ /* * 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 story_type.h basic types related to story pages */ #ifndef STORY_TYPE_H #define STORY_TYPE_H #include "core/enum_type.hpp" typedef uint16 StoryPageElementID; ///< ID of a story page element typedef uint16 StoryPageID; ///< ID of a story page struct StoryPageElement; struct StoryPage; extern StoryPageElementID _new_story_page_element_id; extern StoryPageID _new_story_page_id; static const StoryPageElementID INVALID_STORY_PAGE_ELEMENT = 0xFFFF; ///< Constant representing a non-existing story page element. static const StoryPageID INVALID_STORY_PAGE = 0xFFFF; ///< Constant representing a non-existing story page. #endif /* STORY_TYPE_H */ openttd-1.5.3/src/debug.h0000644000000000000000000000700212627373441013731 0ustar rootroot/* $Id: debug.h 26195 2014-01-02 08:45:28Z rubidium $ */ /* * 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 debug.h Functions related to debugging. */ #ifndef DEBUG_H #define DEBUG_H #include "cpu.h" /* Debugging messages policy: * These should be the severities used for direct DEBUG() calls * maximum debugging level should be 10 if really deep, deep * debugging is needed. * (there is room for exceptions, but you have to have a good cause): * 0 - errors or severe warnings * 1 - other non-fatal, non-severe warnings * 2 - crude progress indicator of functionality * 3 - important debugging messages (function entry) * 4 - debugging messages (crude loop status, etc.) * 5 - detailed debugging information * 6.. - extremely detailed spamming */ #ifdef NO_DEBUG_MESSAGES #define DEBUG(name, level, ...) { } #else /* NO_DEBUG_MESSAGES */ /** * Output a line of debugging information. * @param name Category * @param level Debugging level, higher levels means more detailed information. */ #define DEBUG(name, level, ...) if ((level) == 0 || _debug_ ## name ## _level >= (level)) debug(#name, __VA_ARGS__) extern int _debug_driver_level; extern int _debug_grf_level; extern int _debug_map_level; extern int _debug_misc_level; extern int _debug_net_level; extern int _debug_sprite_level; extern int _debug_oldloader_level; extern int _debug_npf_level; extern int _debug_yapf_level; extern int _debug_freetype_level; extern int _debug_script_level; extern int _debug_sl_level; extern int _debug_gamelog_level; extern int _debug_desync_level; extern int _debug_console_level; #ifdef RANDOM_DEBUG extern int _debug_random_level; #endif void CDECL debug(const char *dbg, const char *format, ...) WARN_FORMAT(2, 3); #endif /* NO_DEBUG_MESSAGES */ char *DumpDebugFacilityNames(char *buf, char *last); void SetDebugString(const char *s); const char *GetDebugString(); /* Shorter form for passing filename and linenumber */ #define FILE_LINE __FILE__, __LINE__ /* Used for profiling * * Usage: * TIC(); * --Do your code-- * TOC("A name", 1); * * When you run the TIC() / TOC() multiple times, you can increase the '1' * to only display average stats every N values. Some things to know: * * for (int i = 0; i < 5; i++) { * TIC(); * --Do your code-- * TOC("A name", 5); * } * * Is the correct usage for multiple TIC() / TOC() calls. * * TIC() / TOC() creates its own block, so make sure not the mangle * it with another block. **/ #define TIC() {\ uint64 _xxx_ = ottd_rdtsc();\ static uint64 __sum__ = 0;\ static uint32 __i__ = 0; #define TOC(str, count)\ __sum__ += ottd_rdtsc() - _xxx_;\ if (++__i__ == count) {\ DEBUG(misc, 0, "[%s] " OTTD_PRINTF64 " [avg: %.1f]", str, __sum__, __sum__/(double)__i__);\ __i__ = 0;\ __sum__ = 0;\ }\ } void ShowInfo(const char *str); void CDECL ShowInfoF(const char *str, ...) WARN_FORMAT(1, 2); const char *GetLogPrefix(); /** The real time in the game. */ extern uint32 _realtime_tick; #endif /* DEBUG_H */ openttd-1.5.3/src/date.cpp0000644000000000000000000002775612627373441014135 0ustar rootroot/* $Id: date.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 date.cpp Handling of dates in our native format and transforming them to something human readable. */ #include "stdafx.h" #include "network/network.h" #include "network/network_func.h" #include "currency.h" #include "window_func.h" #include "settings_type.h" #include "date_func.h" #include "vehicle_base.h" #include "rail_gui.h" #include "linkgraph/linkgraph.h" #include "saveload/saveload.h" #include "safeguards.h" Year _cur_year; ///< Current year, starting at 0 Month _cur_month; ///< Current month (0..11) Date _date; ///< Current date in days (day counter) DateFract _date_fract; ///< Fractional part of the day. uint16 _tick_counter; ///< Ever incrementing (and sometimes wrapping) tick counter for setting off various events /** * Set the date. * @param date New date * @param fract The number of ticks that have passed on this date. */ void SetDate(Date date, DateFract fract) { assert(fract < DAY_TICKS); YearMonthDay ymd; _date = date; _date_fract = fract; ConvertDateToYMD(date, &ymd); _cur_year = ymd.year; _cur_month = ymd.month; } #define M(a, b) ((a << 5) | b) static const uint16 _month_date_from_year_day[] = { M( 0, 1), M( 0, 2), M( 0, 3), M( 0, 4), M( 0, 5), M( 0, 6), M( 0, 7), M( 0, 8), M( 0, 9), M( 0, 10), M( 0, 11), M( 0, 12), M( 0, 13), M( 0, 14), M( 0, 15), M( 0, 16), M( 0, 17), M( 0, 18), M( 0, 19), M( 0, 20), M( 0, 21), M( 0, 22), M( 0, 23), M( 0, 24), M( 0, 25), M( 0, 26), M( 0, 27), M( 0, 28), M( 0, 29), M( 0, 30), M( 0, 31), M( 1, 1), M( 1, 2), M( 1, 3), M( 1, 4), M( 1, 5), M( 1, 6), M( 1, 7), M( 1, 8), M( 1, 9), M( 1, 10), M( 1, 11), M( 1, 12), M( 1, 13), M( 1, 14), M( 1, 15), M( 1, 16), M( 1, 17), M( 1, 18), M( 1, 19), M( 1, 20), M( 1, 21), M( 1, 22), M( 1, 23), M( 1, 24), M( 1, 25), M( 1, 26), M( 1, 27), M( 1, 28), M( 1, 29), M( 2, 1), M( 2, 2), M( 2, 3), M( 2, 4), M( 2, 5), M( 2, 6), M( 2, 7), M( 2, 8), M( 2, 9), M( 2, 10), M( 2, 11), M( 2, 12), M( 2, 13), M( 2, 14), M( 2, 15), M( 2, 16), M( 2, 17), M( 2, 18), M( 2, 19), M( 2, 20), M( 2, 21), M( 2, 22), M( 2, 23), M( 2, 24), M( 2, 25), M( 2, 26), M( 2, 27), M( 2, 28), M( 2, 29), M( 2, 30), M( 2, 31), M( 3, 1), M( 3, 2), M( 3, 3), M( 3, 4), M( 3, 5), M( 3, 6), M( 3, 7), M( 3, 8), M( 3, 9), M( 3, 10), M( 3, 11), M( 3, 12), M( 3, 13), M( 3, 14), M( 3, 15), M( 3, 16), M( 3, 17), M( 3, 18), M( 3, 19), M( 3, 20), M( 3, 21), M( 3, 22), M( 3, 23), M( 3, 24), M( 3, 25), M( 3, 26), M( 3, 27), M( 3, 28), M( 3, 29), M( 3, 30), M( 4, 1), M( 4, 2), M( 4, 3), M( 4, 4), M( 4, 5), M( 4, 6), M( 4, 7), M( 4, 8), M( 4, 9), M( 4, 10), M( 4, 11), M( 4, 12), M( 4, 13), M( 4, 14), M( 4, 15), M( 4, 16), M( 4, 17), M( 4, 18), M( 4, 19), M( 4, 20), M( 4, 21), M( 4, 22), M( 4, 23), M( 4, 24), M( 4, 25), M( 4, 26), M( 4, 27), M( 4, 28), M( 4, 29), M( 4, 30), M( 4, 31), M( 5, 1), M( 5, 2), M( 5, 3), M( 5, 4), M( 5, 5), M( 5, 6), M( 5, 7), M( 5, 8), M( 5, 9), M( 5, 10), M( 5, 11), M( 5, 12), M( 5, 13), M( 5, 14), M( 5, 15), M( 5, 16), M( 5, 17), M( 5, 18), M( 5, 19), M( 5, 20), M( 5, 21), M( 5, 22), M( 5, 23), M( 5, 24), M( 5, 25), M( 5, 26), M( 5, 27), M( 5, 28), M( 5, 29), M( 5, 30), M( 6, 1), M( 6, 2), M( 6, 3), M( 6, 4), M( 6, 5), M( 6, 6), M( 6, 7), M( 6, 8), M( 6, 9), M( 6, 10), M( 6, 11), M( 6, 12), M( 6, 13), M( 6, 14), M( 6, 15), M( 6, 16), M( 6, 17), M( 6, 18), M( 6, 19), M( 6, 20), M( 6, 21), M( 6, 22), M( 6, 23), M( 6, 24), M( 6, 25), M( 6, 26), M( 6, 27), M( 6, 28), M( 6, 29), M( 6, 30), M( 6, 31), M( 7, 1), M( 7, 2), M( 7, 3), M( 7, 4), M( 7, 5), M( 7, 6), M( 7, 7), M( 7, 8), M( 7, 9), M( 7, 10), M( 7, 11), M( 7, 12), M( 7, 13), M( 7, 14), M( 7, 15), M( 7, 16), M( 7, 17), M( 7, 18), M( 7, 19), M( 7, 20), M( 7, 21), M( 7, 22), M( 7, 23), M( 7, 24), M( 7, 25), M( 7, 26), M( 7, 27), M( 7, 28), M( 7, 29), M( 7, 30), M( 7, 31), M( 8, 1), M( 8, 2), M( 8, 3), M( 8, 4), M( 8, 5), M( 8, 6), M( 8, 7), M( 8, 8), M( 8, 9), M( 8, 10), M( 8, 11), M( 8, 12), M( 8, 13), M( 8, 14), M( 8, 15), M( 8, 16), M( 8, 17), M( 8, 18), M( 8, 19), M( 8, 20), M( 8, 21), M( 8, 22), M( 8, 23), M( 8, 24), M( 8, 25), M( 8, 26), M( 8, 27), M( 8, 28), M( 8, 29), M( 8, 30), M( 9, 1), M( 9, 2), M( 9, 3), M( 9, 4), M( 9, 5), M( 9, 6), M( 9, 7), M( 9, 8), M( 9, 9), M( 9, 10), M( 9, 11), M( 9, 12), M( 9, 13), M( 9, 14), M( 9, 15), M( 9, 16), M( 9, 17), M( 9, 18), M( 9, 19), M( 9, 20), M( 9, 21), M( 9, 22), M( 9, 23), M( 9, 24), M( 9, 25), M( 9, 26), M( 9, 27), M( 9, 28), M( 9, 29), M( 9, 30), M( 9, 31), M(10, 1), M(10, 2), M(10, 3), M(10, 4), M(10, 5), M(10, 6), M(10, 7), M(10, 8), M(10, 9), M(10, 10), M(10, 11), M(10, 12), M(10, 13), M(10, 14), M(10, 15), M(10, 16), M(10, 17), M(10, 18), M(10, 19), M(10, 20), M(10, 21), M(10, 22), M(10, 23), M(10, 24), M(10, 25), M(10, 26), M(10, 27), M(10, 28), M(10, 29), M(10, 30), M(11, 1), M(11, 2), M(11, 3), M(11, 4), M(11, 5), M(11, 6), M(11, 7), M(11, 8), M(11, 9), M(11, 10), M(11, 11), M(11, 12), M(11, 13), M(11, 14), M(11, 15), M(11, 16), M(11, 17), M(11, 18), M(11, 19), M(11, 20), M(11, 21), M(11, 22), M(11, 23), M(11, 24), M(11, 25), M(11, 26), M(11, 27), M(11, 28), M(11, 29), M(11, 30), M(11, 31), }; #undef M enum DaysTillMonth { ACCUM_JAN = 0, ACCUM_FEB = ACCUM_JAN + 31, ACCUM_MAR = ACCUM_FEB + 29, ACCUM_APR = ACCUM_MAR + 31, ACCUM_MAY = ACCUM_APR + 30, ACCUM_JUN = ACCUM_MAY + 31, ACCUM_JUL = ACCUM_JUN + 30, ACCUM_AUG = ACCUM_JUL + 31, ACCUM_SEP = ACCUM_AUG + 31, ACCUM_OCT = ACCUM_SEP + 30, ACCUM_NOV = ACCUM_OCT + 31, ACCUM_DEC = ACCUM_NOV + 30, }; /** Number of days to pass from the first day in the year before reaching the first of a month. */ static const uint16 _accum_days_for_month[] = { ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR, ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG, ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC, }; /** * Converts a Date to a Year, Month & Day. * @param date the date to convert from * @param ymd the year, month and day to write to */ void ConvertDateToYMD(Date date, YearMonthDay *ymd) { /* Year determination in multiple steps to account for leap * years. First do the large steps, then the smaller ones. */ /* There are 97 leap years in 400 years */ Year yr = 400 * (date / (DAYS_IN_YEAR * 400 + 97)); int rem = date % (DAYS_IN_YEAR * 400 + 97); uint16 x; if (rem >= DAYS_IN_YEAR * 100 + 25) { /* There are 25 leap years in the first 100 years after * every 400th year, as every 400th year is a leap year */ yr += 100; rem -= DAYS_IN_YEAR * 100 + 25; /* There are 24 leap years in the next couple of 100 years */ yr += 100 * (rem / (DAYS_IN_YEAR * 100 + 24)); rem = (rem % (DAYS_IN_YEAR * 100 + 24)); } if (!IsLeapYear(yr) && rem >= DAYS_IN_YEAR * 4) { /* The first 4 year of the century are not always a leap year */ yr += 4; rem -= DAYS_IN_YEAR * 4; } /* There is 1 leap year every 4 years */ yr += 4 * (rem / (DAYS_IN_YEAR * 4 + 1)); rem = rem % (DAYS_IN_YEAR * 4 + 1); /* The last (max 3) years to account for; the first one * can be, but is not necessarily a leap year */ while (rem >= (IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR)) { rem -= IsLeapYear(yr) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR; yr++; } /* Skip the 29th of February in non-leap years */ if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++; ymd->year = yr; x = _month_date_from_year_day[rem]; ymd->month = x >> 5; ymd->day = x & 0x1F; } /** * Converts a tuple of Year, Month and Day to a Date. * @param year is a number between 0..MAX_YEAR * @param month is a number between 0..11 * @param day is a number between 1..31 */ Date ConvertYMDToDate(Year year, Month month, Day day) { /* Day-offset in a leap year */ int days = _accum_days_for_month[month] + day - 1; /* Account for the missing of the 29th of February in non-leap years */ if (!IsLeapYear(year) && days >= ACCUM_MAR) days--; return DAYS_TILL(year) + days; } /** Functions used by the IncreaseDate function */ extern void EnginesDailyLoop(); extern void DisasterDailyLoop(); extern void IndustryDailyLoop(); extern void CompaniesMonthlyLoop(); extern void EnginesMonthlyLoop(); extern void TownsMonthlyLoop(); extern void IndustryMonthlyLoop(); extern void StationMonthlyLoop(); extern void SubsidyMonthlyLoop(); extern void CompaniesYearlyLoop(); extern void VehiclesYearlyLoop(); extern void TownsYearlyLoop(); extern void ShowEndGameChart(); /** Available settings for autosave intervals. */ static const Month _autosave_months[] = { 0, ///< never 1, ///< every month 3, ///< every 3 months 6, ///< every 6 months 12, ///< every 12 months }; /** * Runs various procedures that have to be done yearly */ static void OnNewYear() { CompaniesYearlyLoop(); VehiclesYearlyLoop(); TownsYearlyLoop(); InvalidateWindowClassesData(WC_BUILD_STATION); #ifdef ENABLE_NETWORK if (_network_server) NetworkServerYearlyLoop(); #endif /* ENABLE_NETWORK */ if (_cur_year == _settings_client.gui.semaphore_build_before) ResetSignalVariant(); /* check if we reached end of the game */ if (_cur_year == ORIGINAL_END_YEAR) { ShowEndGameChart(); /* check if we reached the maximum year, decrement dates by a year */ } else if (_cur_year == MAX_YEAR + 1) { Vehicle *v; int days_this_year; _cur_year--; days_this_year = IsLeapYear(_cur_year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR; _date -= days_this_year; FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year; LinkGraph *lg; FOR_ALL_LINK_GRAPHS(lg) lg->ShiftDates(-days_this_year); #ifdef ENABLE_NETWORK /* Because the _date wraps here, and text-messages expire by game-days, we have to clean out * all of them if the date is set back, else those messages will hang for ever */ NetworkInitChatMessage(); #endif /* ENABLE_NETWORK */ } if (_settings_client.gui.auto_euro) CheckSwitchToEuro(); } /** * Runs various procedures that have to be done monthly */ static void OnNewMonth() { if (_settings_client.gui.autosave != 0 && (_cur_month % _autosave_months[_settings_client.gui.autosave]) == 0) { _do_autosave = true; SetWindowDirty(WC_STATUS_BAR, 0); } SetWindowClassesDirty(WC_CHEATS); CompaniesMonthlyLoop(); EnginesMonthlyLoop(); TownsMonthlyLoop(); IndustryMonthlyLoop(); SubsidyMonthlyLoop(); StationMonthlyLoop(); #ifdef ENABLE_NETWORK if (_network_server) NetworkServerMonthlyLoop(); #endif /* ENABLE_NETWORK */ } /** * Runs various procedures that have to be done daily */ static void OnNewDay() { #ifdef ENABLE_NETWORK if (_network_server) NetworkServerDailyLoop(); #endif /* ENABLE_NETWORK */ DisasterDailyLoop(); IndustryDailyLoop(); SetWindowWidgetDirty(WC_STATUS_BAR, 0, 0); EnginesDailyLoop(); /* Refresh after possible snowline change */ SetWindowClassesDirty(WC_TOWN_VIEW); } /** * Increases the tick counter, increases date and possibly calls * procedures that have to be called daily, monthly or yearly. */ void IncreaseDate() { /* increase day, and check if a new day is there? */ _tick_counter++; if (_game_mode == GM_MENU) return; _date_fract++; if (_date_fract < DAY_TICKS) return; _date_fract = 0; /* increase day counter */ _date++; YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); /* check if we entered a new month? */ bool new_month = ymd.month != _cur_month; /* check if we entered a new year? */ bool new_year = ymd.year != _cur_year; /* update internal variables before calling the daily/monthly/yearly loops */ _cur_month = ymd.month; _cur_year = ymd.year; /* yes, call various daily loops */ OnNewDay(); /* yes, call various monthly loops */ if (new_month) OnNewMonth(); /* yes, call various yearly loops */ if (new_year) OnNewYear(); } openttd-1.5.3/src/cheat_func.h0000644000000000000000000000155012627373445014750 0ustar rootroot/* $Id: cheat_func.h 21844 2011-01-18 22:17:15Z rubidium $ */ /* * 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 cheat_func.h Functions related to cheating. */ #ifndef CHEAT_FUNC_H #define CHEAT_FUNC_H #include "cheat_type.h" extern Cheats _cheats; void ShowCheatWindow(); bool CheatHasBeenUsed(); #endif /* CHEAT_FUNC_H */ openttd-1.5.3/src/graph_gui.h0000644000000000000000000000175712627373446014630 0ustar rootroot/* $Id: graph_gui.h 21610 2010-12-23 16:54:41Z smatz $ */ /* * 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 graph_gui.h Graph GUI functions. */ #ifndef GRAPH_GUI_H #define GRAPH_GUI_H void ShowOperatingProfitGraph(); void ShowIncomeGraph(); void ShowDeliveredCargoGraph(); void ShowPerformanceHistoryGraph(); void ShowCompanyValueGraph(); void ShowCargoPaymentRates(); void ShowCompanyLeagueTable(); void ShowPerformanceRatingDetail(); #endif /* GRAPH_GUI_H */ openttd-1.5.3/src/ini_type.h0000644000000000000000000000733712627373442014477 0ustar rootroot/* $Id: ini_type.h 26499 2014-04-24 18:37:39Z rubidium $ */ /* * 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 ini_type.h Types related to reading/writing '*.ini' files. */ #ifndef INI_TYPE_H #define INI_TYPE_H #include "fileio_type.h" /** Types of groups */ enum IniGroupType { IGT_VARIABLES = 0, ///< Values of the form "landscape = hilly". IGT_LIST = 1, ///< A list of values, separated by \n and terminated by the next group block. IGT_SEQUENCE = 2, ///< A list of uninterpreted lines, terminated by the next group block. }; /** A single "line" in an ini file. */ struct IniItem { IniItem *next; ///< The next item in this group char *name; ///< The name of this item char *value; ///< The value of this item char *comment; ///< The comment associated with this item IniItem(struct IniGroup *parent, const char *name, const char *last = NULL); ~IniItem(); void SetValue(const char *value); }; /** A group within an ini file. */ struct IniGroup { IniGroup *next; ///< the next group within this file IniGroupType type; ///< type of group IniItem *item; ///< the first item in the group IniItem **last_item; ///< the last item in the group char *name; ///< name of group char *comment; ///< comment for group IniGroup(struct IniLoadFile *parent, const char *name, const char *last = NULL); ~IniGroup(); IniItem *GetItem(const char *name, bool create); void Clear(); }; /** Ini file that only supports loading. */ struct IniLoadFile { IniGroup *group; ///< the first group in the ini IniGroup **last_group; ///< the last group in the ini char *comment; ///< last comment in file const char * const *list_group_names; ///< NULL terminated list with group names that are lists const char * const *seq_group_names; ///< NULL terminated list with group names that are sequences. IniLoadFile(const char * const *list_group_names = NULL, const char * const *seq_group_names = NULL); virtual ~IniLoadFile(); IniGroup *GetGroup(const char *name, size_t len = 0, bool create_new = true); void RemoveGroup(const char *name); void LoadFromDisk(const char *filename, Subdirectory subdir); /** * Open the INI file. * @param filename Name of the INI file. * @param subdir The subdir to load the file from. * @param size [out] Size of the opened file. * @return File handle of the opened file, or \c NULL. */ virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size) = 0; /** * Report an error about the file contents. * @param pre Prefix text of the \a buffer part. * @param buffer Part of the file with the error. * @param post Suffix text of the \a buffer part. */ virtual void ReportFileError(const char * const pre, const char * const buffer, const char * const post) = 0; }; /** Ini file that supports both loading and saving. */ struct IniFile : IniLoadFile { IniFile(const char * const *list_group_names = NULL); bool SaveToDisk(const char *filename); virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size); virtual void ReportFileError(const char * const pre, const char * const buffer, const char * const post); }; #endif /* INI_TYPE_H */ openttd-1.5.3/src/house_type.h0000644000000000000000000000162112627373435015033 0ustar rootroot/* $Id: house_type.h 22411 2011-05-02 17:42:12Z rubidium $ */ /* * 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 house_type.h declaration of basic house types and enums */ #ifndef HOUSE_TYPE_H #define HOUSE_TYPE_H typedef uint16 HouseID; ///< OpenTTD ID of house types. typedef uint16 HouseClassID; ///< Classes of houses. struct HouseSpec; #endif /* HOUSE_TYPE_H */ openttd-1.5.3/src/pathfinder/0000755000000000000000000000000012627373445014623 5ustar rootrootopenttd-1.5.3/src/pathfinder/follow_track.hpp0000644000000000000000000004062712627373445020033 0ustar rootroot/* $Id: follow_track.hpp 27431 2015-11-01 11:59:17Z frosch $ */ /* * 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 follow_track.hpp Template function for track followers */ #ifndef FOLLOW_TRACK_HPP #define FOLLOW_TRACK_HPP #include "../pbs.h" #include "../roadveh.h" #include "../station_base.h" #include "../train.h" #include "../tunnelbridge.h" #include "../tunnelbridge_map.h" #include "../depot_map.h" #include "pf_performance_timer.hpp" /** * Track follower helper template class (can serve pathfinders and vehicle * controllers). See 6 different typedefs below for 3 different transport * types w/ or w/o 90-deg turns allowed */ template struct CFollowTrackT { enum ErrorCode { EC_NONE, EC_OWNER, EC_RAIL_TYPE, EC_90DEG, EC_NO_WAY, EC_RESERVED, }; const VehicleType *m_veh; ///< moving vehicle Owner m_veh_owner; ///< owner of the vehicle TileIndex m_old_tile; ///< the origin (vehicle moved from) before move Trackdir m_old_td; ///< the trackdir (the vehicle was on) before move TileIndex m_new_tile; ///< the new tile (the vehicle has entered) TrackdirBits m_new_td_bits; ///< the new set of available trackdirs DiagDirection m_exitdir; ///< exit direction (leaving the old tile) bool m_is_tunnel; ///< last turn passed tunnel bool m_is_bridge; ///< last turn passed bridge ramp bool m_is_station; ///< last turn passed station int m_tiles_skipped; ///< number of skipped tunnel or station tiles ErrorCode m_err; CPerformanceTimer *m_pPerf; RailTypes m_railtypes; inline CFollowTrackT(const VehicleType *v = NULL, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = NULL) { Init(v, railtype_override, pPerf); } inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = NULL) { m_veh = NULL; Init(o, railtype_override, pPerf); } inline void Init(const VehicleType *v, RailTypes railtype_override, CPerformanceTimer *pPerf) { assert(!IsRailTT() || (v != NULL && v->type == VEH_TRAIN)); m_veh = v; Init(v != NULL ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override, pPerf); } inline void Init(Owner o, RailTypes railtype_override, CPerformanceTimer *pPerf) { assert((!IsRoadTT() || m_veh != NULL) && (!IsRailTT() || railtype_override != INVALID_RAILTYPES)); m_veh_owner = o; m_pPerf = pPerf; /* don't worry, all is inlined so compiler should remove unnecessary initializations */ m_old_tile = INVALID_TILE; m_old_td = INVALID_TRACKDIR; m_new_tile = INVALID_TILE; m_new_td_bits = TRACKDIR_BIT_NONE; m_exitdir = INVALID_DIAGDIR; m_is_station = m_is_bridge = m_is_tunnel = false; m_tiles_skipped = 0; m_err = EC_NONE; m_railtypes = railtype_override; } inline static TransportType TT() { return Ttr_type_; } inline static bool IsWaterTT() { return TT() == TRANSPORT_WATER; } inline static bool IsRailTT() { return TT() == TRANSPORT_RAIL; } inline bool IsTram() { return IsRoadTT() && HasBit(RoadVehicle::From(m_veh)->compatible_roadtypes, ROADTYPE_TRAM); } inline static bool IsRoadTT() { return TT() == TRANSPORT_ROAD; } inline static bool Allow90degTurns() { return T90deg_turns_allowed_; } inline static bool DoTrackMasking() { return Tmask_reserved_tracks; } /** Tests if a tile is a road tile with a single tramtrack (tram can reverse) */ inline DiagDirection GetSingleTramBit(TileIndex tile) { assert(IsTram()); // this function shouldn't be called in other cases if (IsNormalRoadTile(tile)) { RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM); switch (rb) { case ROAD_NW: return DIAGDIR_NW; case ROAD_SW: return DIAGDIR_SW; case ROAD_SE: return DIAGDIR_SE; case ROAD_NE: return DIAGDIR_NE; default: break; } } return INVALID_DIAGDIR; } /** * main follower routine. Fills all members and return true on success. * Otherwise returns false if track can't be followed. */ inline bool Follow(TileIndex old_tile, Trackdir old_td) { m_old_tile = old_tile; m_old_td = old_td; m_err = EC_NONE; assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) || (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR)); // Disable the assertion for single tram bits m_exitdir = TrackdirToExitdir(m_old_td); if (ForcedReverse()) return true; if (!CanExitOldTile()) return false; FollowTileExit(); if (!QueryNewTileTrackStatus()) return TryReverse(); m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir); if (m_new_td_bits == TRACKDIR_BIT_NONE || !CanEnterNewTile()) { /* In case we can't enter the next tile, but are * a normal road vehicle, then we can actually * try to reverse as this is the end of the road. * Trams can only turn on the appropriate bits in * which case reaching this would mean a dead end * near a building and in that case there would * a "false" QueryNewTileTrackStatus result and * as such reversing is already tried. The fact * that function failed can have to do with a * missing road bit, or inability to connect the * different bits due to slopes. */ if (IsRoadTT() && !IsTram() && TryReverse()) return true; /* CanEnterNewTile already set a reason. * Do NOT overwrite it (important for example for EC_RAIL_TYPE). * Only set a reason if CanEnterNewTile was not called */ if (m_new_td_bits == TRACKDIR_BIT_NONE) m_err = EC_NO_WAY; return false; } if (!Allow90degTurns()) { m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td); if (m_new_td_bits == TRACKDIR_BIT_NONE) { m_err = EC_90DEG; return false; } } return true; } inline bool MaskReservedTracks() { if (!DoTrackMasking()) return true; if (m_is_station) { /* Check skipped station tiles as well. */ TileIndexDiff diff = TileOffsByDiagDir(m_exitdir); for (TileIndex tile = m_new_tile - diff * m_tiles_skipped; tile != m_new_tile; tile += diff) { if (HasStationReservation(tile)) { m_new_td_bits = TRACKDIR_BIT_NONE; m_err = EC_RESERVED; return false; } } } TrackBits reserved = GetReservedTrackbits(m_new_tile); /* Mask already reserved trackdirs. */ m_new_td_bits &= ~TrackBitsToTrackdirBits(reserved); /* Mask out all trackdirs that conflict with the reservation. */ Track t; FOR_EACH_SET_TRACK(t, TrackdirBitsToTrackBits(m_new_td_bits)) { if (TracksOverlap(reserved | TrackToTrackBits(t))) m_new_td_bits &= ~TrackToTrackdirBits(t); } if (m_new_td_bits == TRACKDIR_BIT_NONE) { m_err = EC_RESERVED; return false; } return true; } protected: /** Follow the m_exitdir from m_old_tile and fill m_new_tile and m_tiles_skipped */ inline void FollowTileExit() { m_is_station = m_is_bridge = m_is_tunnel = false; m_tiles_skipped = 0; /* extra handling for tunnels and bridges in our direction */ if (IsTileType(m_old_tile, MP_TUNNELBRIDGE)) { DiagDirection enterdir = GetTunnelBridgeDirection(m_old_tile); if (enterdir == m_exitdir) { /* we are entering the tunnel / bridge */ if (IsTunnel(m_old_tile)) { m_is_tunnel = true; m_new_tile = GetOtherTunnelEnd(m_old_tile); } else { // IsBridge(m_old_tile) m_is_bridge = true; m_new_tile = GetOtherBridgeEnd(m_old_tile); } m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile); return; } assert(ReverseDiagDir(enterdir) == m_exitdir); } /* normal or station tile, do one step */ TileIndexDiff diff = TileOffsByDiagDir(m_exitdir); m_new_tile = TILE_ADD(m_old_tile, diff); /* special handling for stations */ if (IsRailTT() && HasStationTileRail(m_new_tile)) { m_is_station = true; } else if (IsRoadTT() && IsRoadStopTile(m_new_tile)) { m_is_station = true; } else { m_is_station = false; } } /** stores track status (available trackdirs) for the new tile into m_new_td_bits */ inline bool QueryNewTileTrackStatus() { CPerfStart perf(*m_pPerf); if (IsRailTT() && IsPlainRailTile(m_new_tile)) { m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101); } else { m_new_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(m_new_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)); if (IsTram() && m_new_td_bits == 0) { /* GetTileTrackStatus() returns 0 for single tram bits. * As we cannot change it there (easily) without breaking something, change it here */ switch (GetSingleTramBit(m_new_tile)) { case DIAGDIR_NE: case DIAGDIR_SW: m_new_td_bits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW; break; case DIAGDIR_NW: case DIAGDIR_SE: m_new_td_bits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE; break; default: break; } } } return (m_new_td_bits != TRACKDIR_BIT_NONE); } /** return true if we can leave m_old_tile in m_exitdir */ inline bool CanExitOldTile() { /* road stop can be left at one direction only unless it's a drive-through stop */ if (IsRoadTT() && IsStandardRoadStopTile(m_old_tile)) { DiagDirection exitdir = GetRoadStopDir(m_old_tile); if (exitdir != m_exitdir) { m_err = EC_NO_WAY; return false; } } /* single tram bits can only be left in one direction */ if (IsTram()) { DiagDirection single_tram = GetSingleTramBit(m_old_tile); if (single_tram != INVALID_DIAGDIR && single_tram != m_exitdir) { m_err = EC_NO_WAY; return false; } } /* road depots can be also left in one direction only */ if (IsRoadTT() && IsDepotTypeTile(m_old_tile, TT())) { DiagDirection exitdir = GetRoadDepotDirection(m_old_tile); if (exitdir != m_exitdir) { m_err = EC_NO_WAY; return false; } } return true; } /** return true if we can enter m_new_tile from m_exitdir */ inline bool CanEnterNewTile() { if (IsRoadTT() && IsStandardRoadStopTile(m_new_tile)) { /* road stop can be entered from one direction only unless it's a drive-through stop */ DiagDirection exitdir = GetRoadStopDir(m_new_tile); if (ReverseDiagDir(exitdir) != m_exitdir) { m_err = EC_NO_WAY; return false; } } /* single tram bits can only be entered from one direction */ if (IsTram()) { DiagDirection single_tram = GetSingleTramBit(m_new_tile); if (single_tram != INVALID_DIAGDIR && single_tram != ReverseDiagDir(m_exitdir)) { m_err = EC_NO_WAY; return false; } } /* road and rail depots can also be entered from one direction only */ if (IsRoadTT() && IsDepotTypeTile(m_new_tile, TT())) { DiagDirection exitdir = GetRoadDepotDirection(m_new_tile); if (ReverseDiagDir(exitdir) != m_exitdir) { m_err = EC_NO_WAY; return false; } /* don't try to enter other company's depots */ if (GetTileOwner(m_new_tile) != m_veh_owner) { m_err = EC_OWNER; return false; } } if (IsRailTT() && IsDepotTypeTile(m_new_tile, TT())) { DiagDirection exitdir = GetRailDepotDirection(m_new_tile); if (ReverseDiagDir(exitdir) != m_exitdir) { m_err = EC_NO_WAY; return false; } } /* rail transport is possible only on tiles with the same owner as vehicle */ if (IsRailTT() && GetTileOwner(m_new_tile) != m_veh_owner) { /* different owner */ m_err = EC_NO_WAY; return false; } /* rail transport is possible only on compatible rail types */ if (IsRailTT()) { RailType rail_type = GetTileRailType(m_new_tile); if (!HasBit(m_railtypes, rail_type)) { /* incompatible rail type */ m_err = EC_RAIL_TYPE; return false; } } /* tunnel holes and bridge ramps can be entered only from proper direction */ if (IsTileType(m_new_tile, MP_TUNNELBRIDGE)) { if (IsTunnel(m_new_tile)) { if (!m_is_tunnel) { DiagDirection tunnel_enterdir = GetTunnelBridgeDirection(m_new_tile); if (tunnel_enterdir != m_exitdir) { m_err = EC_NO_WAY; return false; } } } else { // IsBridge(m_new_tile) if (!m_is_bridge) { DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile); if (ramp_enderdir != m_exitdir) { m_err = EC_NO_WAY; return false; } } } } /* special handling for rail stations - get to the end of platform */ if (IsRailTT() && m_is_station) { /* entered railway station * get platform length */ uint length = BaseStation::GetByTile(m_new_tile)->GetPlatformLength(m_new_tile, TrackdirToExitdir(m_old_td)); /* how big step we must do to get to the last platform tile; */ m_tiles_skipped = length - 1; /* move to the platform end */ TileIndexDiff diff = TileOffsByDiagDir(m_exitdir); diff *= m_tiles_skipped; m_new_tile = TILE_ADD(m_new_tile, diff); return true; } return true; } /** return true if we must reverse (in depots and single tram bits) */ inline bool ForcedReverse() { /* rail and road depots cause reversing */ if (!IsWaterTT() && IsDepotTypeTile(m_old_tile, TT())) { DiagDirection exitdir = IsRailTT() ? GetRailDepotDirection(m_old_tile) : GetRoadDepotDirection(m_old_tile); if (exitdir != m_exitdir) { /* reverse */ m_new_tile = m_old_tile; m_new_td_bits = TrackdirToTrackdirBits(ReverseTrackdir(m_old_td)); m_exitdir = exitdir; m_tiles_skipped = 0; m_is_tunnel = m_is_bridge = m_is_station = false; return true; } } /* single tram bits cause reversing */ if (IsTram() && GetSingleTramBit(m_old_tile) == ReverseDiagDir(m_exitdir)) { /* reverse */ m_new_tile = m_old_tile; m_new_td_bits = TrackdirToTrackdirBits(ReverseTrackdir(m_old_td)); m_exitdir = ReverseDiagDir(m_exitdir); m_tiles_skipped = 0; m_is_tunnel = m_is_bridge = m_is_station = false; return true; } return false; } /** return true if we successfully reversed at end of road/track */ inline bool TryReverse() { if (IsRoadTT() && !IsTram()) { /* if we reached the end of road, we can reverse the RV and continue moving */ m_exitdir = ReverseDiagDir(m_exitdir); /* new tile will be the same as old one */ m_new_tile = m_old_tile; /* set new trackdir bits to all reachable trackdirs */ QueryNewTileTrackStatus(); m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir); if (m_new_td_bits != TRACKDIR_BIT_NONE) { /* we have some trackdirs reachable after reversal */ return true; } } m_err = EC_NO_WAY; return false; } public: /** Helper for pathfinders - get min/max speed on the m_old_tile/m_old_td */ int GetSpeedLimit(int *pmin_speed = NULL) const { int min_speed = 0; int max_speed = INT_MAX; // no limit /* Check for on-bridge speed limit */ if (!IsWaterTT() && IsBridgeTile(m_old_tile)) { int spd = GetBridgeSpec(GetBridgeType(m_old_tile))->speed; if (IsRoadTT()) spd *= 2; if (max_speed > spd) max_speed = spd; } /* Check for speed limit imposed by railtype */ if (IsRailTT()) { uint16 rail_speed = GetRailTypeInfo(GetRailType(m_old_tile))->max_speed; if (rail_speed > 0) max_speed = min(max_speed, rail_speed); } /* if min speed was requested, return it */ if (pmin_speed != NULL) *pmin_speed = min_speed; return max_speed; } }; typedef CFollowTrackT CFollowTrackWater; typedef CFollowTrackT CFollowTrackRoad; typedef CFollowTrackT CFollowTrackRail; typedef CFollowTrackT CFollowTrackWaterNo90; typedef CFollowTrackT CFollowTrackRoadNo90; typedef CFollowTrackT CFollowTrackRailNo90; typedef CFollowTrackT CFollowTrackFreeRail; typedef CFollowTrackT CFollowTrackFreeRailNo90; #endif /* FOLLOW_TRACK_HPP */ openttd-1.5.3/src/pathfinder/pathfinder_func.h0000644000000000000000000000417012627373445020135 0ustar rootroot/* $Id: pathfinder_func.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 pathfinder_func.h General functions related to pathfinders. */ #ifndef PATHFINDER_FUNC_H #define PATHFINDER_FUNC_H #include "../waypoint_base.h" /** * Calculates the tile of given station that is closest to a given tile * for this we assume the station is a rectangle, * as defined by its tile are (st->train_station) * @param station The station to calculate the distance to * @param tile The tile from where to calculate the distance * @param station_type the station type to get the closest tile of * @return The closest station tile to the given tile. */ static inline TileIndex CalcClosestStationTile(StationID station, TileIndex tile, StationType station_type) { const BaseStation *st = BaseStation::Get(station); TileArea ta; st->GetTileArea(&ta, station_type); /* If the rail station is (temporarily) not present, use the station sign to drive near the station */ if (ta.tile == INVALID_TILE) return st->xy; uint minx = TileX(ta.tile); // topmost corner of station uint miny = TileY(ta.tile); uint maxx = minx + ta.w - 1; // lowermost corner of station uint maxy = miny + ta.h - 1; /* we are going the aim for the x coordinate of the closest corner * but if we are between those coordinates, we will aim for our own x coordinate */ uint x = ClampU(TileX(tile), minx, maxx); /* same for y coordinate, see above comment */ uint y = ClampU(TileY(tile), miny, maxy); /* return the tile of our target coordinates */ return TileXY(x, y); } #endif /* PATHFINDER_FUNC_H */ openttd-1.5.3/src/pathfinder/yapf/0000755000000000000000000000000012627373445015562 5ustar rootrootopenttd-1.5.3/src/pathfinder/yapf/yapf_ship.cpp0000644000000000000000000002357212627373445020261 0ustar rootroot/* $Id: yapf_ship.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 yapf_ship.cpp Implementation of YAPF for ships. */ #include "../../stdafx.h" #include "../../ship.h" #include "yapf.hpp" #include "yapf_node_ship.hpp" #include "../../safeguards.h" /** Node Follower module of YAPF for ships */ template class CYapfFollowShipT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** * Called by YAPF to move from the given node to the next tile. For each * reachable trackdir on the new tile creates new node, initializes it * and adds it to the open list by calling Yapf().AddNewNode(n) */ inline void PfFollowNode(Node& old_node) { TrackFollower F(Yapf().GetVehicle()); if (F.Follow(old_node.m_key.m_tile, old_node.m_key.m_td)) { Yapf().AddMultipleNodes(&old_node, F); } } /** return debug report character to identify the transportation type */ inline char TransportTypeChar() const { return 'w'; } static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found) { /* handle special case - when next tile is destination tile */ if (tile == v->dest_tile) { /* convert tracks to trackdirs */ TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8)); /* limit to trackdirs reachable from enterdir */ trackdirs &= DiagdirReachesTrackdirs(enterdir); /* use vehicle's current direction if that's possible, otherwise use first usable one. */ Trackdir veh_dir = v->GetVehicleTrackdir(); return ((trackdirs & TrackdirToTrackdirBits(veh_dir)) != 0) ? veh_dir : (Trackdir)FindFirstBit2x64(trackdirs); } /* move back to the old tile/trackdir (where ship is coming from) */ TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir))); Trackdir trackdir = v->GetVehicleTrackdir(); assert(IsValidTrackdir(trackdir)); /* convert origin trackdir to TrackdirBits */ TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir); /* get available trackdirs on the destination tile */ TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0)); /* create pathfinder instance */ Tpf pf; /* set origin and destination nodes */ pf.SetOrigin(src_tile, trackdirs); pf.SetDestination(v->dest_tile, dest_trackdirs); /* find best path */ path_found = pf.FindPath(v); Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found" Node *pNode = pf.GetBestNode(); if (pNode != NULL) { /* walk through the path back to the origin */ Node *pPrevNode = NULL; while (pNode->m_parent != NULL) { pPrevNode = pNode; pNode = pNode->m_parent; } /* return trackdir from the best next node (direct child of origin) */ Node& best_next_node = *pPrevNode; assert(best_next_node.GetTile() == tile); next_trackdir = best_next_node.GetTrackdir(); } return next_trackdir; } /** * Check whether a ship should reverse to reach its destination. * Called when leaving depot. * @param v Ship * @param tile Current position * @param td1 Forward direction * @param td2 Reverse direction * @return true if the reverse direction is better */ static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2) { /* get available trackdirs on the destination tile */ TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0)); /* create pathfinder instance */ Tpf pf; /* set origin and destination nodes */ pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2)); pf.SetDestination(v->dest_tile, dest_trackdirs); /* find best path */ if (!pf.FindPath(v)) return false; Node *pNode = pf.GetBestNode(); if (pNode == NULL) return false; /* path was found * walk through the path back to the origin */ while (pNode->m_parent != NULL) { pNode = pNode->m_parent; } Trackdir best_trackdir = pNode->GetTrackdir(); assert(best_trackdir == td1 || best_trackdir == td2); return best_trackdir == td2; } }; /** Cost Provider module of YAPF for ships */ template class CYapfCostShipT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } public: /** * Called by YAPF to calculate the cost from the origin to the given node. * Calculates only the cost of given node, adds it to the parent node cost * and stores the result into Node::m_cost member */ inline bool PfCalcCost(Node& n, const TrackFollower *tf) { /* base tile cost depending on distance */ int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH; /* additional penalty for curves */ if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) { /* new trackdir does not match the next one when going straight */ c += YAPF_TILE_LENGTH; } /* Skipped tile cost for aqueducts. */ c += YAPF_TILE_LENGTH * tf->m_tiles_skipped; /* Ocean/canal speed penalty. */ const ShipVehicleInfo *svi = ShipVehInfo(Yapf().GetVehicle()->engine_type); byte speed_frac = (GetEffectiveWaterClass(n.GetTile()) == WATER_CLASS_SEA) ? svi->ocean_speed_frac : svi->canal_speed_frac; if (speed_frac > 0) c += YAPF_TILE_LENGTH * (1 + tf->m_tiles_skipped) * speed_frac / (256 - speed_frac); /* apply it */ n.m_cost = n.m_parent->m_cost + c; return true; } }; /** * Config struct of YAPF for ships. * Defines all 6 base YAPF modules as classes providing services for CYapfBaseT. */ template struct CYapfShip_TypesT { /** Types - shortcut for this struct type */ typedef CYapfShip_TypesT Types; /** Tpf - pathfinder type */ typedef Tpf_ Tpf; /** track follower helper class */ typedef Ttrack_follower TrackFollower; /** node list type */ typedef Tnode_list NodeList; typedef Ship VehicleType; /** pathfinder components (modules) */ typedef CYapfBaseT PfBase; // base pathfinder class typedef CYapfFollowShipT PfFollow; // node follower typedef CYapfOriginTileT PfOrigin; // origin provider typedef CYapfDestinationTileT PfDestination; // destination/distance provider typedef CYapfSegmentCostCacheNoneT PfCache; // segment cost cache provider typedef CYapfCostShipT PfCost; // cost provider }; /* YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns */ struct CYapfShip1 : CYapfT > {}; /* YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns */ struct CYapfShip2 : CYapfT > {}; /* YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns */ struct CYapfShip3 : CYapfT > {}; /** Ship controller helper - path finder invoker */ Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found) { /* default is YAPF type 2 */ typedef Trackdir (*PfnChooseShipTrack)(const Ship*, TileIndex, DiagDirection, TrackBits, bool &path_found); PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg /* check if non-default YAPF type needed */ if (_settings_game.pf.forbid_90_deg) { pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg } else if (_settings_game.pf.yapf.disable_node_optimization) { pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg } Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks, path_found); return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK; } bool YapfShipCheckReverse(const Ship *v) { Trackdir td = v->GetVehicleTrackdir(); Trackdir td_rev = ReverseTrackdir(td); TileIndex tile = v->tile; typedef bool (*PfnCheckReverseShip)(const Ship*, TileIndex, Trackdir, Trackdir); PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse; // default: ExitDir, allow 90-deg /* check if non-default YAPF type needed */ if (_settings_game.pf.forbid_90_deg) { pfnCheckReverseShip = &CYapfShip3::CheckShipReverse; // Trackdir, forbid 90-deg } else if (_settings_game.pf.yapf.disable_node_optimization) { pfnCheckReverseShip = &CYapfShip1::CheckShipReverse; // Trackdir, allow 90-deg } bool reverse = pfnCheckReverseShip(v, tile, td, td_rev); return reverse; } openttd-1.5.3/src/pathfinder/yapf/yapf_costbase.hpp0000644000000000000000000000350612627373445021121 0ustar rootroot/* $Id: yapf_costbase.hpp 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 yapf_costbase.hpp Handling of cost determination. */ #ifndef YAPF_COSTBASE_HPP #define YAPF_COSTBASE_HPP /** Base implementation for cost accounting. */ struct CYapfCostBase { /** * Does the given track direction on the given tile yield an uphill penalty? * @param tile The tile to check. * @param td The track direction to check. * @return True if there's a slope, otherwise false. */ inline static bool stSlopeCost(TileIndex tile, Trackdir td) { if (IsDiagonalTrackdir(td)) { if (IsBridgeTile(tile)) { /* it is bridge ramp, check if we are entering the bridge */ if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(td)) return false; // no, we are leaving it, no penalty /* we are entering the bridge */ Slope tile_slope = GetTileSlope(tile); Axis axis = DiagDirToAxis(GetTunnelBridgeDirection(tile)); return !HasBridgeFlatRamp(tile_slope, axis); } else { /* not bridge ramp */ if (IsTunnelTile(tile)) return false; // tunnel entry/exit doesn't slope Slope tile_slope = GetTileSlope(tile); return IsUphillTrackdir(tile_slope, td); // slopes uphill => apply penalty } } return false; } }; #endif /* YAPF_COSTBASE_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_type.hpp0000644000000000000000000000753012627373445020300 0ustar rootroot/* $Id: yapf_type.hpp 25608 2013-07-14 09:20:34Z rubidium $ */ /* * 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 yapf_type.hpp Types used by YAPF. */ #ifndef YAPF_TYPE_HPP #define YAPF_TYPE_HPP /* Enum used in PfCalcCost() to see why was the segment closed. */ enum EndSegmentReason { /* The following reasons can be saved into cached segment */ ESR_DEAD_END = 0, ///< track ends here ESR_RAIL_TYPE, ///< the next tile has a different rail type than our tiles ESR_INFINITE_LOOP, ///< infinite loop detected ESR_SEGMENT_TOO_LONG, ///< the segment is too long (possible infinite loop) ESR_CHOICE_FOLLOWS, ///< the next tile contains a choice (the track splits to more than one segments) ESR_DEPOT, ///< stop in the depot (could be a target next time) ESR_WAYPOINT, ///< waypoint encountered (could be a target next time) ESR_STATION, ///< station encountered (could be a target next time) ESR_SAFE_TILE, ///< safe waiting position found (could be a target) /* The following reasons are used only internally by PfCalcCost(). * They should not be found in the cached segment. */ ESR_PATH_TOO_LONG, ///< the path is too long (searching for the nearest depot in the given radius) ESR_FIRST_TWO_WAY_RED, ///< first signal was 2-way and it was red ESR_LOOK_AHEAD_END, ///< we have just passed the last look-ahead signal ESR_TARGET_REACHED, ///< we have just reached the destination /* Special values */ ESR_NONE = 0xFF, ///< no reason to end the segment here }; enum EndSegmentReasonBits { ESRB_NONE = 0, ESRB_DEAD_END = 1 << ESR_DEAD_END, ESRB_RAIL_TYPE = 1 << ESR_RAIL_TYPE, ESRB_INFINITE_LOOP = 1 << ESR_INFINITE_LOOP, ESRB_SEGMENT_TOO_LONG = 1 << ESR_SEGMENT_TOO_LONG, ESRB_CHOICE_FOLLOWS = 1 << ESR_CHOICE_FOLLOWS, ESRB_DEPOT = 1 << ESR_DEPOT, ESRB_WAYPOINT = 1 << ESR_WAYPOINT, ESRB_STATION = 1 << ESR_STATION, ESRB_SAFE_TILE = 1 << ESR_SAFE_TILE, ESRB_PATH_TOO_LONG = 1 << ESR_PATH_TOO_LONG, ESRB_FIRST_TWO_WAY_RED = 1 << ESR_FIRST_TWO_WAY_RED, ESRB_LOOK_AHEAD_END = 1 << ESR_LOOK_AHEAD_END, ESRB_TARGET_REACHED = 1 << ESR_TARGET_REACHED, /* Additional (composite) values. */ /* What reasons mean that the target can be found and needs to be detected. */ ESRB_POSSIBLE_TARGET = ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE, /* What reasons can be stored back into cached segment. */ ESRB_CACHED_MASK = ESRB_DEAD_END | ESRB_RAIL_TYPE | ESRB_INFINITE_LOOP | ESRB_SEGMENT_TOO_LONG | ESRB_CHOICE_FOLLOWS | ESRB_DEPOT | ESRB_WAYPOINT | ESRB_STATION | ESRB_SAFE_TILE, /* Reasons to abort pathfinding in this direction. */ ESRB_ABORT_PF_MASK = ESRB_DEAD_END | ESRB_PATH_TOO_LONG | ESRB_INFINITE_LOOP | ESRB_FIRST_TWO_WAY_RED, }; DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits) inline CStrA ValueStr(EndSegmentReasonBits bits) { static const char * const end_segment_reason_names[] = { "DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS", "DEPOT", "WAYPOINT", "STATION", "SAFE_TILE", "PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED" }; CStrA out; out.Format("0x%04X (%s)", bits, ComposeNameT(bits, end_segment_reason_names, "UNK", ESRB_NONE, "NONE").Data()); return out.Transfer(); } #endif /* YAPF_TYPE_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_node_road.hpp0000644000000000000000000000315012627373445021243 0ustar rootroot/* $Id: yapf_node_road.hpp 22350 2011-04-19 18:12:47Z smatz $ */ /* * 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 yapf_node_road.hpp Node tailored for road pathfinding. */ #ifndef YAPF_NODE_ROAD_HPP #define YAPF_NODE_ROAD_HPP /** Yapf Node for road YAPF */ template struct CYapfRoadNodeT : CYapfNodeT > { typedef CYapfNodeT > base; TileIndex m_segment_last_tile; Trackdir m_segment_last_td; void Set(CYapfRoadNodeT *parent, TileIndex tile, Trackdir td, bool is_choice) { base::Set(parent, tile, td, is_choice); m_segment_last_tile = tile; m_segment_last_td = td; } }; /* now define two major node types (that differ by key type) */ typedef CYapfRoadNodeT CYapfRoadNodeExitDir; typedef CYapfRoadNodeT CYapfRoadNodeTrackDir; /* Default NodeList types */ typedef CNodeList_HashTableT CRoadNodeListExitDir; typedef CNodeList_HashTableT CRoadNodeListTrackDir; #endif /* YAPF_NODE_ROAD_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_destrail.hpp0000644000000000000000000001563312627373445021131 0ustar rootroot/* $Id: yapf_destrail.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 yapf_destrail.hpp Determining the destination for rail vehicles. */ #ifndef YAPF_DESTRAIL_HPP #define YAPF_DESTRAIL_HPP class CYapfDestinationRailBase { protected: RailTypes m_compatible_railtypes; public: void SetDestination(const Train *v, bool override_rail_type = false) { m_compatible_railtypes = v->compatible_railtypes; if (override_rail_type) m_compatible_railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes; } bool IsCompatibleRailType(RailType rt) { return HasBit(m_compatible_railtypes, rt); } RailTypes GetCompatibleRailTypes() const { return m_compatible_railtypes; } }; template class CYapfDestinationAnyDepotRailT : public CYapfDestinationRailBase { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(Node& n) { return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir()); } /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(TileIndex tile, Trackdir td) { bool bDest = IsRailDepotTile(tile); return bDest; } /** * Called by YAPF to calculate cost estimate. Calculates distance to the destination * adds it to the actual cost from origin and stores the sum to the Node::m_estimate */ inline bool PfCalcEstimate(Node& n) { n.m_estimate = n.m_cost; return true; } }; template class CYapfDestinationAnySafeTileRailT : public CYapfDestinationRailBase { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables typedef typename Types::TrackFollower TrackFollower; ///< TrackFollower. Need to typedef for gcc 2.95 /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(Node& n) { return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir()); } /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(TileIndex tile, Trackdir td) { return IsSafeWaitingPosition(Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns()) && IsWaitingPositionFree(Yapf().GetVehicle(), tile, td, !TrackFollower::Allow90degTurns()); } /** * Called by YAPF to calculate cost estimate. Calculates distance to the destination * adds it to the actual cost from origin and stores the sum to the Node::m_estimate. */ inline bool PfCalcEstimate(Node& n) { n.m_estimate = n.m_cost; return true; } }; template class CYapfDestinationTileOrStationRailT : public CYapfDestinationRailBase { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: TileIndex m_destTile; TrackdirBits m_destTrackdirs; StationID m_dest_station_id; /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } public: void SetDestination(const Train *v) { switch (v->current_order.GetType()) { case OT_GOTO_WAYPOINT: if (!Waypoint::Get(v->current_order.GetDestination())->IsSingleTile()) { /* In case of 'complex' waypoints we need to do a look * ahead. This look ahead messes a bit about, which * means that it 'corrupts' the cache. To prevent this * we disable caching when we're looking for a complex * waypoint. */ Yapf().DisableCache(true); } /* FALL THROUGH */ case OT_GOTO_STATION: m_destTile = CalcClosestStationTile(v->current_order.GetDestination(), v->tile, v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT); m_dest_station_id = v->current_order.GetDestination(); m_destTrackdirs = INVALID_TRACKDIR_BIT; break; default: m_destTile = v->dest_tile; m_dest_station_id = INVALID_STATION; m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_RAIL, 0)); break; } CYapfDestinationRailBase::SetDestination(v); } /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(Node& n) { return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir()); } /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(TileIndex tile, Trackdir td) { bool bDest; if (m_dest_station_id != INVALID_STATION) { bDest = HasStationTileRail(tile) && (GetStationIndex(tile) == m_dest_station_id) && (GetRailStationTrack(tile) == TrackdirToTrack(td)); } else { bDest = (tile == m_destTile) && ((m_destTrackdirs & TrackdirToTrackdirBits(td)) != TRACKDIR_BIT_NONE); } return bDest; } /** * Called by YAPF to calculate cost estimate. Calculates distance to the destination * adds it to the actual cost from origin and stores the sum to the Node::m_estimate */ inline bool PfCalcEstimate(Node& n) { static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0}; static const int dg_dir_to_y_offs[] = {0, 1, 0, -1}; if (PfDetectDestination(n)) { n.m_estimate = n.m_cost; return true; } TileIndex tile = n.GetLastTile(); DiagDirection exitdir = TrackdirToExitdir(n.GetLastTrackdir()); int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir]; int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir]; int x2 = 2 * TileX(m_destTile); int y2 = 2 * TileY(m_destTile); int dx = abs(x1 - x2); int dy = abs(y1 - y2); int dmin = min(dx, dy); int dxy = abs(dx - dy); int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2); n.m_estimate = n.m_cost + d; assert(n.m_estimate >= n.m_parent->m_estimate); return true; } }; #endif /* YAPF_DESTRAIL_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_rail.cpp0000644000000000000000000005610412627373445020242 0ustar rootroot/* $Id: yapf_rail.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 yapf_rail.cpp The rail pathfinding. */ #include "../../stdafx.h" #include "yapf.hpp" #include "yapf_cache.h" #include "yapf_node_rail.hpp" #include "yapf_costrail.hpp" #include "yapf_destrail.hpp" #include "../../viewport_func.h" #include "../../newgrf_station.h" #include "../../safeguards.h" #define DEBUG_YAPF_CACHE 0 #if DEBUG_YAPF_CACHE template void DumpState(Tpf &pf1, Tpf &pf2) { DumpTarget dmp1, dmp2; pf1.DumpBase(dmp1); pf2.DumpBase(dmp2); FILE *f1 = fopen("yapf1.txt", "wt"); FILE *f2 = fopen("yapf2.txt", "wt"); fwrite(dmp1.m_out.Data(), 1, dmp1.m_out.Size(), f1); fwrite(dmp2.m_out.Data(), 1, dmp2.m_out.Size(), f2); fclose(f1); fclose(f2); } #endif int _total_pf_time_us = 0; template class CYapfReserveTrack { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type protected: /** to access inherited pathfinder */ inline Tpf& Yapf() { return *static_cast(this); } private: TileIndex m_res_dest; ///< The reservation target tile Trackdir m_res_dest_td; ///< The reservation target trackdir Node *m_res_node; ///< The reservation target node TileIndex m_res_fail_tile; ///< The tile where the reservation failed Trackdir m_res_fail_td; ///< The trackdir where the reservation failed TileIndex m_origin_tile; ///< Tile our reservation will originate from bool FindSafePositionProc(TileIndex tile, Trackdir td) { if (IsSafeWaitingPosition(Yapf().GetVehicle(), tile, td, true, !TrackFollower::Allow90degTurns())) { m_res_dest = tile; m_res_dest_td = td; return false; // Stop iterating segment } return true; } /** Reserve a railway platform. Tile contains the failed tile on abort. */ bool ReserveRailStationPlatform(TileIndex &tile, DiagDirection dir) { TileIndex start = tile; TileIndexDiff diff = TileOffsByDiagDir(dir); do { if (HasStationReservation(tile)) return false; SetRailStationReservation(tile, true); MarkTileDirtyByTile(tile); tile = TILE_ADD(tile, diff); } while (IsCompatibleTrainStationTile(tile, start) && tile != m_origin_tile); TriggerStationRandomisation(NULL, start, SRT_PATH_RESERVATION); return true; } /** Try to reserve a single track/platform. */ bool ReserveSingleTrack(TileIndex tile, Trackdir td) { if (IsRailStationTile(tile)) { if (!ReserveRailStationPlatform(tile, TrackdirToExitdir(ReverseTrackdir(td)))) { /* Platform could not be reserved, undo. */ m_res_fail_tile = tile; m_res_fail_td = td; } } else { if (!TryReserveRailTrack(tile, TrackdirToTrack(td))) { /* Tile couldn't be reserved, undo. */ m_res_fail_tile = tile; m_res_fail_td = td; return false; } } return tile != m_res_dest || td != m_res_dest_td; } /** Unreserve a single track/platform. Stops when the previous failer is reached. */ bool UnreserveSingleTrack(TileIndex tile, Trackdir td) { if (IsRailStationTile(tile)) { TileIndex start = tile; TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(td))); while ((tile != m_res_fail_tile || td != m_res_fail_td) && IsCompatibleTrainStationTile(tile, start)) { SetRailStationReservation(tile, false); tile = TILE_ADD(tile, diff); } } else if (tile != m_res_fail_tile || td != m_res_fail_td) { UnreserveRailTrack(tile, TrackdirToTrack(td)); } return (tile != m_res_dest || td != m_res_dest_td) && (tile != m_res_fail_tile || td != m_res_fail_td); } public: /** Set the target to where the reservation should be extended. */ inline void SetReservationTarget(Node *node, TileIndex tile, Trackdir td) { m_res_node = node; m_res_dest = tile; m_res_dest_td = td; } /** Check the node for a possible reservation target. */ inline void FindSafePositionOnNode(Node *node) { assert(node->m_parent != NULL); /* We will never pass more than two signals, no need to check for a safe tile. */ if (node->m_parent->m_num_signals_passed >= 2) return; if (!node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack::FindSafePositionProc)) { m_res_node = node; } } /** Try to reserve the path till the reservation target. */ bool TryReservePath(PBSTileInfo *target, TileIndex origin) { m_res_fail_tile = INVALID_TILE; m_origin_tile = origin; if (target != NULL) { target->tile = m_res_dest; target->trackdir = m_res_dest_td; target->okay = false; } /* Don't bother if the target is reserved. */ if (!IsWaitingPositionFree(Yapf().GetVehicle(), m_res_dest, m_res_dest_td)) return false; for (Node *node = m_res_node; node->m_parent != NULL; node = node->m_parent) { node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack::ReserveSingleTrack); if (m_res_fail_tile != INVALID_TILE) { /* Reservation failed, undo. */ Node *fail_node = m_res_node; TileIndex stop_tile = m_res_fail_tile; do { /* If this is the node that failed, stop at the failed tile. */ m_res_fail_tile = fail_node == node ? stop_tile : INVALID_TILE; fail_node->IterateTiles(Yapf().GetVehicle(), Yapf(), *this, &CYapfReserveTrack::UnreserveSingleTrack); } while (fail_node != node && (fail_node = fail_node->m_parent) != NULL); return false; } } if (target != NULL) target->okay = true; if (Yapf().CanUseGlobalCache(*m_res_node)) { YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); } return true; } }; template class CYapfFollowAnyDepotRailT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** * Called by YAPF to move from the given node to the next tile. For each * reachable trackdir on the new tile creates new node, initializes it * and adds it to the open list by calling Yapf().AddNewNode(n) */ inline void PfFollowNode(Node& old_node) { TrackFollower F(Yapf().GetVehicle()); if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) { Yapf().AddMultipleNodes(&old_node, F); } } /** return debug report character to identify the transportation type */ inline char TransportTypeChar() const { return 't'; } static bool stFindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty, TileIndex *depot_tile, bool *reversed) { Tpf pf1; /* * With caching enabled it simply cannot get a reliable result when you * have limited the distance a train may travel. This means that the * cached result does not match uncached result in all cases and that * causes desyncs. So disable caching when finding for a depot that is * nearby. This only happens with automatic servicing of vehicles, * so it will only impact performance when you do not manually set * depot orders and you do not disable automatic servicing. */ if (max_penalty != 0) pf1.DisableCache(true); bool result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty, depot_tile, reversed); #if DEBUG_YAPF_CACHE Tpf pf2; TileIndex depot_tile2 = INVALID_TILE; bool reversed2 = false; pf2.DisableCache(true); bool result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_penalty, reverse_penalty, &depot_tile2, &reversed2); if (result1 != result2 || (result1 && (*depot_tile != depot_tile2 || *reversed != reversed2))) { DEBUG(yapf, 0, "CACHE ERROR: FindNearestDepotTwoWay() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F"); DumpState(pf1, pf2); } #endif return result1; } inline bool FindNearestDepotTwoWay(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_penalty, int reverse_penalty, TileIndex *depot_tile, bool *reversed) { /* set origin and destination nodes */ Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty, true); Yapf().SetDestination(v); Yapf().SetMaxCost(max_penalty); /* find the best path */ bool bFound = Yapf().FindPath(v); if (!bFound) return false; /* some path found * get found depot tile */ Node *n = Yapf().GetBestNode(); *depot_tile = n->GetLastTile(); /* walk through the path back to the origin */ Node *pNode = n; while (pNode->m_parent != NULL) { pNode = pNode->m_parent; } /* if the origin node is our front vehicle tile/Trackdir then we didn't reverse * but we can also look at the cost (== 0 -> not reversed, == reverse_penalty -> reversed) */ *reversed = (pNode->m_cost != 0); return true; } }; template class CYapfFollowAnySafeTileRailT : public CYapfReserveTrack { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** * Called by YAPF to move from the given node to the next tile. For each * reachable trackdir on the new tile creates new node, initializes it * and adds it to the open list by calling Yapf().AddNewNode(n) */ inline void PfFollowNode(Node& old_node) { TrackFollower F(Yapf().GetVehicle(), Yapf().GetCompatibleRailTypes()); if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()) && F.MaskReservedTracks()) { Yapf().AddMultipleNodes(&old_node, F); } } /** Return debug report character to identify the transportation type */ inline char TransportTypeChar() const { return 't'; } static bool stFindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype) { /* Create pathfinder instance */ Tpf pf1; #if !DEBUG_YAPF_CACHE bool result1 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, false); #else bool result2 = pf1.FindNearestSafeTile(v, t1, td, override_railtype, true); Tpf pf2; pf2.DisableCache(true); bool result1 = pf2.FindNearestSafeTile(v, t1, td, override_railtype, false); if (result1 != result2) { DEBUG(yapf, 0, "CACHE ERROR: FindSafeTile() = [%s, %s]", result2 ? "T" : "F", result1 ? "T" : "F"); DumpState(pf1, pf2); } #endif return result1; } bool FindNearestSafeTile(const Train *v, TileIndex t1, Trackdir td, bool override_railtype, bool dont_reserve) { /* Set origin and destination. */ Yapf().SetOrigin(t1, td); Yapf().SetDestination(v, override_railtype); bool bFound = Yapf().FindPath(v); if (!bFound) return false; /* Found a destination, set as reservation target. */ Node *pNode = Yapf().GetBestNode(); this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir()); /* Walk through the path back to the origin. */ Node *pPrev = NULL; while (pNode->m_parent != NULL) { pPrev = pNode; pNode = pNode->m_parent; this->FindSafePositionOnNode(pPrev); } return dont_reserve || this->TryReservePath(NULL, pNode->GetLastTile()); } }; template class CYapfFollowRailT : public CYapfReserveTrack { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** * Called by YAPF to move from the given node to the next tile. For each * reachable trackdir on the new tile creates new node, initializes it * and adds it to the open list by calling Yapf().AddNewNode(n) */ inline void PfFollowNode(Node& old_node) { TrackFollower F(Yapf().GetVehicle()); if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir())) { Yapf().AddMultipleNodes(&old_node, F); } } /** return debug report character to identify the transportation type */ inline char TransportTypeChar() const { return 't'; } static Trackdir stChooseRailTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target) { /* create pathfinder instance */ Tpf pf1; #if !DEBUG_YAPF_CACHE Trackdir result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target); #else Trackdir result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_found, false, NULL); Tpf pf2; pf2.DisableCache(true); Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target); if (result1 != result2) { DEBUG(yapf, 0, "CACHE ERROR: ChooseRailTrack() = [%d, %d]", result1, result2); DumpState(pf1, pf2); } #endif return result1; } inline Trackdir ChooseRailTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target) { if (target != NULL) target->tile = INVALID_TILE; /* set origin and destination nodes */ PBSTileInfo origin = FollowTrainReservation(v); Yapf().SetOrigin(origin.tile, origin.trackdir, INVALID_TILE, INVALID_TRACKDIR, 1, true); Yapf().SetDestination(v); /* find the best path */ path_found = Yapf().FindPath(v); /* if path not found - return INVALID_TRACKDIR */ Trackdir next_trackdir = INVALID_TRACKDIR; Node *pNode = Yapf().GetBestNode(); if (pNode != NULL) { /* reserve till end of path */ this->SetReservationTarget(pNode, pNode->GetLastTile(), pNode->GetLastTrackdir()); /* path was found or at least suggested * walk through the path back to the origin */ Node *pPrev = NULL; while (pNode->m_parent != NULL) { pPrev = pNode; pNode = pNode->m_parent; this->FindSafePositionOnNode(pPrev); } /* return trackdir from the best origin node (one of start nodes) */ Node& best_next_node = *pPrev; next_trackdir = best_next_node.GetTrackdir(); if (reserve_track && path_found) this->TryReservePath(target, pNode->GetLastTile()); } /* Treat the path as found if stopped on the first two way signal(s). */ path_found |= Yapf().m_stopped_on_first_two_way_signal; return next_trackdir; } static bool stCheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty) { Tpf pf1; bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty); #if DEBUG_YAPF_CACHE Tpf pf2; pf2.DisableCache(true); bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty); if (result1 != result2) { DEBUG(yapf, 0, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F"); DumpState(pf1, pf2); } #endif return result1; } inline bool CheckReverseTrain(const Train *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty) { /* create pathfinder instance * set origin and destination nodes */ Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty, false); Yapf().SetDestination(v); /* find the best path */ bool bFound = Yapf().FindPath(v); if (!bFound) return false; /* path was found * walk through the path back to the origin */ Node *pNode = Yapf().GetBestNode(); while (pNode->m_parent != NULL) { pNode = pNode->m_parent; } /* check if it was reversed origin */ Node& best_org_node = *pNode; bool reversed = (best_org_node.m_cost != 0); return reversed; } }; template class TdestinationT, template class TfollowT> struct CYapfRail_TypesT { typedef CYapfRail_TypesT Types; typedef Tpf_ Tpf; typedef Ttrack_follower TrackFollower; typedef Tnode_list NodeList; typedef Train VehicleType; typedef CYapfBaseT PfBase; typedef TfollowT PfFollow; typedef CYapfOriginTileTwoWayT PfOrigin; typedef TdestinationT PfDestination; typedef CYapfSegmentCostCacheGlobalT PfCache; typedef CYapfCostRailT PfCost; }; struct CYapfRail1 : CYapfT > {}; struct CYapfRail2 : CYapfT > {}; struct CYapfAnyDepotRail1 : CYapfT > {}; struct CYapfAnyDepotRail2 : CYapfT > {}; struct CYapfAnySafeTileRail1 : CYapfT > {}; struct CYapfAnySafeTileRail2 : CYapfT > {}; Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, PBSTileInfo *target) { /* default is YAPF type 2 */ typedef Trackdir (*PfnChooseRailTrack)(const Train*, TileIndex, DiagDirection, TrackBits, bool&, bool, PBSTileInfo*); PfnChooseRailTrack pfnChooseRailTrack = &CYapfRail1::stChooseRailTrack; /* check if non-default YAPF type needed */ if (_settings_game.pf.forbid_90_deg) { pfnChooseRailTrack = &CYapfRail2::stChooseRailTrack; // Trackdir, forbid 90-deg } Trackdir td_ret = pfnChooseRailTrack(v, tile, enterdir, tracks, path_found, reserve_track, target); return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : FindFirstTrack(tracks); } bool YapfTrainCheckReverse(const Train *v) { const Train *last_veh = v->Last(); /* get trackdirs of both ends */ Trackdir td = v->GetVehicleTrackdir(); Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir()); /* tiles where front and back are */ TileIndex tile = v->tile; TileIndex tile_rev = last_veh->tile; int reverse_penalty = 0; if (v->track == TRACK_BIT_WORMHOLE) { /* front in tunnel / on bridge */ DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile); if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile); /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */ /* Current position of the train in the wormhole */ TileIndex cur_tile = TileVirtXY(v->x_pos, v->y_pos); /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path * Note: Negative penalties are ok for the start tile. */ reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH; } if (last_veh->track == TRACK_BIT_WORMHOLE) { /* back in tunnel / on bridge */ DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev); if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev); /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */ /* Current position of the last wagon in the wormhole */ TileIndex cur_tile = TileVirtXY(last_veh->x_pos, last_veh->y_pos); /* Add distance to drive in the wormhole as penalty for the revere path. */ reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH; } typedef bool (*PfnCheckReverseTrain)(const Train*, TileIndex, Trackdir, TileIndex, Trackdir, int); PfnCheckReverseTrain pfnCheckReverseTrain = CYapfRail1::stCheckReverseTrain; /* check if non-default YAPF type needed */ if (_settings_game.pf.forbid_90_deg) { pfnCheckReverseTrain = &CYapfRail2::stCheckReverseTrain; // Trackdir, forbid 90-deg } /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */ if (reverse_penalty == 0) reverse_penalty = 1; bool reverse = pfnCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty); return reverse; } FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_penalty) { FindDepotData fdd; const Train *last_veh = v->Last(); PBSTileInfo origin = FollowTrainReservation(v); TileIndex last_tile = last_veh->tile; Trackdir td_rev = ReverseTrackdir(last_veh->GetVehicleTrackdir()); typedef bool (*PfnFindNearestDepotTwoWay)(const Train*, TileIndex, Trackdir, TileIndex, Trackdir, int, int, TileIndex*, bool*); PfnFindNearestDepotTwoWay pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail1::stFindNearestDepotTwoWay; /* check if non-default YAPF type needed */ if (_settings_game.pf.forbid_90_deg) { pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail2::stFindNearestDepotTwoWay; // Trackdir, forbid 90-deg } bool ret = pfnFindNearestDepotTwoWay(v, origin.tile, origin.trackdir, last_tile, td_rev, max_penalty, YAPF_INFINITE_PENALTY, &fdd.tile, &fdd.reverse); fdd.best_length = ret ? max_penalty / 2 : UINT_MAX; // some fake distance or NOT_FOUND return fdd; } bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype) { typedef bool (*PfnFindNearestSafeTile)(const Train*, TileIndex, Trackdir, bool); PfnFindNearestSafeTile pfnFindNearestSafeTile = CYapfAnySafeTileRail1::stFindNearestSafeTile; /* check if non-default YAPF type needed */ if (_settings_game.pf.forbid_90_deg) { pfnFindNearestSafeTile = &CYapfAnySafeTileRail2::stFindNearestSafeTile; } return pfnFindNearestSafeTile(v, tile, td, override_railtype); } /** if any track changes, this counter is incremented - that will invalidate segment cost cache */ int CSegmentCostCacheBase::s_rail_change_counter = 0; void YapfNotifyTrackLayoutChange(TileIndex tile, Track track) { CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track); } openttd-1.5.3/src/pathfinder/yapf/yapf.hpp0000644000000000000000000000254512627373445017240 0ustar rootroot/* $Id: yapf.hpp 25608 2013-07-14 09:20:34Z rubidium $ */ /* * 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 yapf.hpp Base includes/functions for YAPF. */ #ifndef YAPF_HPP #define YAPF_HPP #include "../../landscape.h" #include "../pathfinder_func.h" #include "../pf_performance_timer.hpp" #include "yapf.h" //#undef FORCEINLINE //#define inline inline #include "../../misc/blob.hpp" #include "../../misc/str.hpp" #include "../../misc/fixedsizearray.hpp" #include "../../misc/array.hpp" #include "../../misc/hashtable.hpp" #include "../../misc/binaryheap.hpp" #include "../../misc/dbg_helpers.h" #include "nodelist.hpp" #include "../follow_track.hpp" #include "yapf_type.hpp" #include "yapf_base.hpp" #include "yapf_node.hpp" #include "yapf_common.hpp" #include "yapf_costbase.hpp" #include "yapf_costcache.hpp" #endif /* YAPF_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_road.cpp0000644000000000000000000004302112627373445020232 0ustar rootroot/* $Id: yapf_road.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 yapf_road.cpp The road pathfinding. */ #include "../../stdafx.h" #include "yapf.hpp" #include "yapf_node_road.hpp" #include "../../roadstop_base.h" #include "../../safeguards.h" template class CYapfCostRoadT { public: typedef typename Types::Tpf Tpf; ///< pathfinder (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; ///< track follower helper typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } int SlopeCost(TileIndex tile, TileIndex next_tile, Trackdir trackdir) { /* height of the center of the current tile */ int x1 = TileX(tile) * TILE_SIZE; int y1 = TileY(tile) * TILE_SIZE; int z1 = GetSlopePixelZ(x1 + TILE_SIZE / 2, y1 + TILE_SIZE / 2); /* height of the center of the next tile */ int x2 = TileX(next_tile) * TILE_SIZE; int y2 = TileY(next_tile) * TILE_SIZE; int z2 = GetSlopePixelZ(x2 + TILE_SIZE / 2, y2 + TILE_SIZE / 2); if (z2 - z1 > 1) { /* Slope up */ return Yapf().PfGetSettings().road_slope_penalty; } return 0; } /** return one tile cost */ inline int OneTileCost(TileIndex tile, Trackdir trackdir) { int cost = 0; /* set base cost */ if (IsDiagonalTrackdir(trackdir)) { cost += YAPF_TILE_LENGTH; switch (GetTileType(tile)) { case MP_ROAD: /* Increase the cost for level crossings */ if (IsLevelCrossing(tile)) { cost += Yapf().PfGetSettings().road_crossing_penalty; } break; case MP_STATION: { const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile)); if (IsDriveThroughStopTile(tile)) { /* Increase the cost for drive-through road stops */ cost += Yapf().PfGetSettings().road_stop_penalty; DiagDirection dir = TrackdirToExitdir(trackdir); if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) { /* When we're the first road stop in a 'queue' of them we increase * cost based on the fill percentage of the whole queue. */ const RoadStop::Entry *entry = rs->GetEntry(dir); cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength(); } } else { /* Increase cost for filled road stops */ cost += Yapf().PfGetSettings().road_stop_bay_occupied_penalty * (!rs->IsFreeBay(0) + !rs->IsFreeBay(1)) / 2; } break; } default: break; } } else { /* non-diagonal trackdir */ cost = YAPF_TILE_CORNER_LENGTH + Yapf().PfGetSettings().road_curve_penalty; } return cost; } public: /** * Called by YAPF to calculate the cost from the origin to the given node. * Calculates only the cost of given node, adds it to the parent node cost * and stores the result into Node::m_cost member */ inline bool PfCalcCost(Node& n, const TrackFollower *tf) { int segment_cost = 0; uint tiles = 0; /* start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment */ TileIndex tile = n.m_key.m_tile; Trackdir trackdir = n.m_key.m_td; for (;;) { /* base tile cost depending on distance between edges */ segment_cost += Yapf().OneTileCost(tile, trackdir); const RoadVehicle *v = Yapf().GetVehicle(); /* we have reached the vehicle's destination - segment should end here to avoid target skipping */ if (Yapf().PfDetectDestinationTile(tile, trackdir)) break; /* stop if we have just entered the depot */ if (IsRoadDepotTile(tile) && trackdir == DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) { /* next time we will reverse and leave the depot */ break; } /* if there are no reachable trackdirs on new tile, we have end of road */ TrackFollower F(Yapf().GetVehicle()); if (!F.Follow(tile, trackdir)) break; /* if there are more trackdirs available & reachable, we are at the end of segment */ if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break; Trackdir new_td = (Trackdir)FindFirstBit2x64(F.m_new_td_bits); /* stop if RV is on simple loop with no junctions */ if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false; /* if we skipped some tunnel tiles, add their cost */ segment_cost += F.m_tiles_skipped * YAPF_TILE_LENGTH; tiles += F.m_tiles_skipped + 1; /* add hilly terrain penalty */ segment_cost += Yapf().SlopeCost(tile, F.m_new_tile, trackdir); /* add min/max speed penalties */ int min_speed = 0; int max_veh_speed = v->GetDisplayMaxSpeed(); int max_speed = F.GetSpeedLimit(&min_speed); if (max_speed < max_veh_speed) segment_cost += 1 * (max_veh_speed - max_speed); if (min_speed > max_veh_speed) segment_cost += 10 * (min_speed - max_veh_speed); /* move to the next tile */ tile = F.m_new_tile; trackdir = new_td; if (tiles > MAX_MAP_SIZE) break; } /* save end of segment back to the node */ n.m_segment_last_tile = tile; n.m_segment_last_td = trackdir; /* save also tile cost */ int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0; n.m_cost = parent_cost + segment_cost; return true; } }; template class CYapfDestinationAnyDepotRoadT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(Node& n) { bool bDest = IsRoadDepotTile(n.m_segment_last_tile); return bDest; } inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir) { return IsRoadDepotTile(tile); } /** * Called by YAPF to calculate cost estimate. Calculates distance to the destination * adds it to the actual cost from origin and stores the sum to the Node::m_estimate */ inline bool PfCalcEstimate(Node& n) { n.m_estimate = n.m_cost; return true; } }; template class CYapfDestinationTileRoadT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: TileIndex m_destTile; TrackdirBits m_destTrackdirs; StationID m_dest_station; bool m_bus; bool m_non_artic; public: void SetDestination(const RoadVehicle *v) { if (v->current_order.IsType(OT_GOTO_STATION)) { m_dest_station = v->current_order.GetDestination(); m_bus = v->IsBus(); m_destTile = CalcClosestStationTile(m_dest_station, v->tile, m_bus ? STATION_BUS : STATION_TRUCK); m_non_artic = !v->HasArticulatedPart(); m_destTrackdirs = INVALID_TRACKDIR_BIT; } else { m_dest_station = INVALID_STATION; m_destTile = v->dest_tile; m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, v->compatible_roadtypes)); } } protected: /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } public: /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(Node& n) { return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td); } inline bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir) { if (m_dest_station != INVALID_STATION) { return IsTileType(tile, MP_STATION) && GetStationIndex(tile) == m_dest_station && (m_bus ? IsBusStop(tile) : IsTruckStop(tile)) && (m_non_artic || IsDriveThroughStopTile(tile)); } return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE); } /** * Called by YAPF to calculate cost estimate. Calculates distance to the destination * adds it to the actual cost from origin and stores the sum to the Node::m_estimate */ inline bool PfCalcEstimate(Node& n) { static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0}; static const int dg_dir_to_y_offs[] = {0, 1, 0, -1}; if (PfDetectDestination(n)) { n.m_estimate = n.m_cost; return true; } TileIndex tile = n.m_segment_last_tile; DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td); int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir]; int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir]; int x2 = 2 * TileX(m_destTile); int y2 = 2 * TileY(m_destTile); int dx = abs(x1 - x2); int dy = abs(y1 - y2); int dmin = min(dx, dy); int dxy = abs(dx - dy); int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2); n.m_estimate = n.m_cost + d; assert(n.m_estimate >= n.m_parent->m_estimate); return true; } }; template class CYapfFollowRoadT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** * Called by YAPF to move from the given node to the next tile. For each * reachable trackdir on the new tile creates new node, initializes it * and adds it to the open list by calling Yapf().AddNewNode(n) */ inline void PfFollowNode(Node& old_node) { TrackFollower F(Yapf().GetVehicle()); if (F.Follow(old_node.m_segment_last_tile, old_node.m_segment_last_td)) { Yapf().AddMultipleNodes(&old_node, F); } } /** return debug report character to identify the transportation type */ inline char TransportTypeChar() const { return 'r'; } static Trackdir stChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found) { Tpf pf; return pf.ChooseRoadTrack(v, tile, enterdir, path_found); } inline Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found) { /* Handle special case - when next tile is destination tile. * However, when going to a station the (initial) destination * tile might not be a station, but a junction, in which case * this method forces the vehicle to jump in circles. */ if (tile == v->dest_tile && !v->current_order.IsType(OT_GOTO_STATION)) { /* choose diagonal trackdir reachable from enterdir */ return DiagDirToDiagTrackdir(enterdir); } /* our source tile will be the next vehicle tile (should be the given one) */ TileIndex src_tile = tile; /* get available trackdirs on the start tile */ TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)); /* select reachable trackdirs only */ src_trackdirs &= DiagdirReachesTrackdirs(enterdir); /* set origin and destination nodes */ Yapf().SetOrigin(src_tile, src_trackdirs); Yapf().SetDestination(v); /* find the best path */ path_found = Yapf().FindPath(v); /* if path not found - return INVALID_TRACKDIR */ Trackdir next_trackdir = INVALID_TRACKDIR; Node *pNode = Yapf().GetBestNode(); if (pNode != NULL) { /* path was found or at least suggested * walk through the path back to its origin */ while (pNode->m_parent != NULL) { pNode = pNode->m_parent; } /* return trackdir from the best origin node (one of start nodes) */ Node& best_next_node = *pNode; assert(best_next_node.GetTile() == tile); next_trackdir = best_next_node.GetTrackdir(); } return next_trackdir; } static uint stDistanceToTile(const RoadVehicle *v, TileIndex tile) { Tpf pf; return pf.DistanceToTile(v, tile); } inline uint DistanceToTile(const RoadVehicle *v, TileIndex dst_tile) { /* handle special case - when current tile is the destination tile */ if (dst_tile == v->tile) { /* distance is zero in this case */ return 0; } if (!SetOriginFromVehiclePos(v)) return UINT_MAX; /* get available trackdirs on the destination tile */ Yapf().SetDestination(v); /* if path not found - return distance = UINT_MAX */ uint dist = UINT_MAX; /* find the best path */ if (!Yapf().FindPath(v)) return dist; Node *pNode = Yapf().GetBestNode(); if (pNode != NULL) { /* path was found * get the path cost estimate */ dist = pNode->GetCostEstimate(); } return dist; } /** Return true if the valid origin (tile/trackdir) was set from the current vehicle position. */ inline bool SetOriginFromVehiclePos(const RoadVehicle *v) { /* set origin (tile, trackdir) */ TileIndex src_tile = v->tile; Trackdir src_td = v->GetVehicleTrackdir(); if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) { /* sometimes the roadveh is not on the road (it resides on non-existing track) * how should we handle that situation? */ return false; } Yapf().SetOrigin(src_tile, TrackdirToTrackdirBits(src_td)); return true; } static bool stFindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile) { Tpf pf; return pf.FindNearestDepot(v, tile, td, max_distance, depot_tile); } inline bool FindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile) { /* set origin and destination nodes */ Yapf().SetOrigin(tile, TrackdirToTrackdirBits(td)); /* find the best path */ bool bFound = Yapf().FindPath(v); if (!bFound) return false; /* some path found * get found depot tile */ Node *n = Yapf().GetBestNode(); if (max_distance > 0 && n->m_cost > max_distance * YAPF_TILE_LENGTH) return false; *depot_tile = n->m_segment_last_tile; return true; } }; template class Tdestination> struct CYapfRoad_TypesT { typedef CYapfRoad_TypesT Types; typedef Tpf_ Tpf; typedef CFollowTrackRoad TrackFollower; typedef Tnode_list NodeList; typedef RoadVehicle VehicleType; typedef CYapfBaseT PfBase; typedef CYapfFollowRoadT PfFollow; typedef CYapfOriginTileT PfOrigin; typedef Tdestination PfDestination; typedef CYapfSegmentCostCacheNoneT PfCache; typedef CYapfCostRoadT PfCost; }; struct CYapfRoad1 : CYapfT > {}; struct CYapfRoad2 : CYapfT > {}; struct CYapfRoadAnyDepot1 : CYapfT > {}; struct CYapfRoadAnyDepot2 : CYapfT > {}; Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found) { /* default is YAPF type 2 */ typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection, bool &path_found); PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack; // default: ExitDir, allow 90-deg /* check if non-default YAPF type should be used */ if (_settings_game.pf.yapf.disable_node_optimization) { pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack; // Trackdir, allow 90-deg } Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir, path_found); return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit2x64(trackdirs); } FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance) { TileIndex tile = v->tile; Trackdir trackdir = v->GetVehicleTrackdir(); if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) { return FindDepotData(); } /* default is YAPF type 2 */ typedef bool (*PfnFindNearestDepot)(const RoadVehicle*, TileIndex, Trackdir, int, TileIndex*); PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot; /* check if non-default YAPF type should be used */ if (_settings_game.pf.yapf.disable_node_optimization) { pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot; // Trackdir, allow 90-deg } FindDepotData fdd; bool ret = pfnFindNearestDepot(v, tile, trackdir, max_distance, &fdd.tile); fdd.best_length = ret ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND return fdd; } openttd-1.5.3/src/pathfinder/yapf/yapf.h0000644000000000000000000001214512627373445016675 0ustar rootroot/* $Id: yapf.h 24481 2012-08-18 11:37:47Z frosch $ */ /* * 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 yapf.h Entry point for OpenTTD to YAPF. */ #ifndef YAPF_H #define YAPF_H #include "../../direction_type.h" #include "../../track_type.h" #include "../../vehicle_type.h" #include "../pathfinder_type.h" /** * Finds the best path for given ship using YAPF. * @param v the ship that needs to find a path * @param tile the tile to find the path from (should be next tile the ship is about to enter) * @param enterdir diagonal direction which the ship will enter this new tile from * @param tracks available tracks on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @return the best trackdir for next turn or INVALID_TRACK if the path could not be found */ Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found); /** * Returns true if it is better to reverse the ship before leaving depot using YAPF. * @param v the ship leaving the depot * @return true if reversing is better */ bool YapfShipCheckReverse(const Ship *v); /** * Finds the best path for given road vehicle using YAPF. * @param v the RV that needs to find a path * @param tile the tile to find the path from (should be next tile the RV is about to enter) * @param enterdir diagonal direction which the RV will enter this new tile from * @param trackdirs available trackdirs on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @return the best trackdir for next turn or INVALID_TRACKDIR if the path could not be found */ Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found); /** * Finds the best path for given train using YAPF. * @param v the train that needs to find a path * @param tile the tile to find the path from (should be next tile the train is about to enter) * @param enterdir diagonal direction which the RV will enter this new tile from * @param tracks available trackdirs on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @param reserve_track indicates whether YAPF should try to reserve the found path * @param target [out] the target tile of the reservation, free is set to true if path was reserved * @return the best track for next turn */ Track YapfTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, struct PBSTileInfo *target); /** * Used when user sends road vehicle to the nearest depot or if road vehicle needs servicing using YAPF. * @param v vehicle that needs to go to some depot * @param max_penalty max distance (in pathfinder penalty) from the current vehicle position * (used also as optimization - the pathfinder can stop path finding if max_penalty * was reached and no depot was seen) * @return the data about the depot */ FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penalty); /** * Used when user sends train to the nearest depot or if train needs servicing using YAPF. * @param v train that needs to go to some depot * @param max_distance max distance (int pathfinder penalty) from the current train position * (used also as optimization - the pathfinder can stop path finding if max_penalty * was reached and no depot was seen) * @return the data about the depot */ FindDepotData YapfTrainFindNearestDepot(const Train *v, int max_distance); /** * Returns true if it is better to reverse the train before leaving station using YAPF. * @param v the train leaving the station * @return true if reversing is better */ bool YapfTrainCheckReverse(const Train *v); /** * Try to extend the reserved path of a train to the nearest safe tile using YAPF. * * @param v The train that needs to find a safe tile. * @param tile Last tile of the current reserved path. * @param td Last trackdir of the current reserved path. * @param override_railtype Should all physically compatible railtypes be searched, even if the vehicle can't run on them on its own? * @return True if the path could be extended to a safe tile. */ bool YapfTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype); #endif /* YAPF_H */ openttd-1.5.3/src/pathfinder/yapf/yapf_cache.h0000644000000000000000000000205012627373445020012 0ustar rootroot/* $Id: yapf_cache.h 21594 2010-12-22 11:24:38Z alberth $ */ /* * 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 yapf_cache.h Entry point for OpenTTD to YAPF's cache. */ #ifndef YAPF_CACHE_H #define YAPF_CACHE_H #include "../../track_type.h" /** * Use this function to notify YAPF that track layout (or signal configuration) has change. * @param tile the tile that is changed * @param track what piece of track is changed */ void YapfNotifyTrackLayoutChange(TileIndex tile, Track track); #endif /* YAPF_CACHE_H */ openttd-1.5.3/src/pathfinder/yapf/yapf_base.hpp0000644000000000000000000003167212627373445020235 0ustar rootroot/* $Id: yapf_base.hpp 25609 2013-07-14 09:21:46Z rubidium $ */ /* * 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 yapf_base.hpp Base classes for YAPF. */ #ifndef YAPF_BASE_HPP #define YAPF_BASE_HPP #include "../../debug.h" #include "../../settings_type.h" extern int _total_pf_time_us; /** * CYapfBaseT - A-star type path finder base class. * Derive your own pathfinder from it. You must provide the following template argument: * Types - used as collection of local types used in pathfinder * * Requirements for the Types struct: * ---------------------------------- * The following types must be defined in the 'Types' argument: * - Types::Tpf - your pathfinder derived from CYapfBaseT * - Types::NodeList - open/closed node list (look at CNodeList_HashTableT) * NodeList needs to have defined local type Titem - defines the pathfinder node type. * Node needs to define local type Key - the node key in the collection () * * For node list you can use template class CNodeList_HashTableT, for which * you need to declare only your node type. Look at test_yapf.h for an example. * * * Requirements to your pathfinder class derived from CYapfBaseT: * -------------------------------------------------------------- * Your pathfinder derived class needs to implement following methods: * inline void PfSetStartupNodes() * inline void PfFollowNode(Node& org) * inline bool PfCalcCost(Node& n) * inline bool PfCalcEstimate(Node& n) * inline bool PfDetectDestination(Node& n) * * For more details about those methods, look at the end of CYapfBaseT * declaration. There are some examples. For another example look at * test_yapf.h (part or unittest project). */ template class CYapfBaseT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList NodeList; ///< our node list typedef typename Types::VehicleType VehicleType; ///< the type of vehicle typedef typename NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables NodeList m_nodes; ///< node list multi-container protected: Node *m_pBestDestNode; ///< pointer to the destination node found at last round Node *m_pBestIntermediateNode; ///< here should be node closest to the destination if path not found const YAPFSettings *m_settings; ///< current settings (_settings_game.yapf) int m_max_search_nodes; ///< maximum number of nodes we are allowed to visit before we give up const VehicleType *m_veh; ///< vehicle that we are trying to drive int m_stats_cost_calcs; ///< stats - how many node's costs were calculated int m_stats_cache_hits; ///< stats - how many node's costs were reused from cache public: CPerformanceTimer m_perf_cost; ///< stats - total CPU time of this run CPerformanceTimer m_perf_slope_cost; ///< stats - slope calculation CPU time CPerformanceTimer m_perf_ts_cost; ///< stats - GetTrackStatus() CPU time CPerformanceTimer m_perf_other_cost; ///< stats - other CPU time public: int m_num_steps; ///< this is there for debugging purposes (hope it doesn't hurt) public: /** default constructor */ inline CYapfBaseT() : m_pBestDestNode(NULL) , m_pBestIntermediateNode(NULL) , m_settings(&_settings_game.pf.yapf) , m_max_search_nodes(PfGetSettings().max_search_nodes) , m_veh(NULL) , m_stats_cost_calcs(0) , m_stats_cache_hits(0) , m_num_steps(0) { } /** default destructor */ ~CYapfBaseT() {} protected: /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** return current settings (can be custom - company based - but later) */ inline const YAPFSettings& PfGetSettings() const { return *m_settings; } /** * Main pathfinder routine: * - set startup node(s) * - main loop that stops if: * - the destination was found * - or the open list is empty (no route to destination). * - or the maximum amount of loops reached - m_max_search_nodes (default = 10000) * @return true if the path was found */ inline bool FindPath(const VehicleType *v) { m_veh = v; #ifndef NO_DEBUG_MESSAGES CPerformanceTimer perf; perf.Start(); #endif /* !NO_DEBUG_MESSAGES */ Yapf().PfSetStartupNodes(); bool bDestFound = true; for (;;) { m_num_steps++; Node *n = m_nodes.GetBestOpenNode(); if (n == NULL) { break; } /* if the best open node was worse than the best path found, we can finish */ if (m_pBestDestNode != NULL && m_pBestDestNode->GetCost() < n->GetCostEstimate()) { break; } Yapf().PfFollowNode(*n); if (m_max_search_nodes == 0 || m_nodes.ClosedCount() < m_max_search_nodes) { m_nodes.PopOpenNode(n->GetKey()); m_nodes.InsertClosedNode(*n); } else { bDestFound = false; break; } } bDestFound &= (m_pBestDestNode != NULL); #ifndef NO_DEBUG_MESSAGES perf.Stop(); if (_debug_yapf_level >= 2) { int t = perf.Get(1000000); _total_pf_time_us += t; if (_debug_yapf_level >= 3) { UnitID veh_idx = (m_veh != NULL) ? m_veh->unitnumber : 0; char ttc = Yapf().TransportTypeChar(); float cache_hit_ratio = (m_stats_cache_hits == 0) ? 0.0f : ((float)m_stats_cache_hits / (float)(m_stats_cache_hits + m_stats_cost_calcs) * 100.0f); int cost = bDestFound ? m_pBestDestNode->m_cost : -1; int dist = bDestFound ? m_pBestDestNode->m_estimate - m_pBestDestNode->m_cost : -1; DEBUG(yapf, 3, "[YAPF%c]%c%4d- %d us - %d rounds - %d open - %d closed - CHR %4.1f%% - C %d D %d - c%d(sc%d, ts%d, o%d) -- ", ttc, bDestFound ? '-' : '!', veh_idx, t, m_num_steps, m_nodes.OpenCount(), m_nodes.ClosedCount(), cache_hit_ratio, cost, dist, m_perf_cost.Get(1000000), m_perf_slope_cost.Get(1000000), m_perf_ts_cost.Get(1000000), m_perf_other_cost.Get(1000000) ); } } #endif /* !NO_DEBUG_MESSAGES */ return bDestFound; } /** * If path was found return the best node that has reached the destination. Otherwise * return the best visited node (which was nearest to the destination). */ inline Node *GetBestNode() { return (m_pBestDestNode != NULL) ? m_pBestDestNode : m_pBestIntermediateNode; } /** * Calls NodeList::CreateNewNode() - allocates new node that can be filled and used * as argument for AddStartupNode() or AddNewNode() */ inline Node& CreateNewNode() { Node& node = *m_nodes.CreateNewNode(); return node; } /** Add new node (created by CreateNewNode and filled with data) into open list */ inline void AddStartupNode(Node& n) { Yapf().PfNodeCacheFetch(n); /* insert the new node only if it is not there */ if (m_nodes.FindOpenNode(n.m_key) == NULL) { m_nodes.InsertOpenNode(n); } else { /* if we are here, it means that node is already there - how it is possible? * probably the train is in the position that both its ends point to the same tile/exit-dir * very unlikely, but it happened */ } } /** add multiple nodes - direct children of the given node */ inline void AddMultipleNodes(Node *parent, const TrackFollower &tf) { bool is_choice = (KillFirstBit(tf.m_new_td_bits) != TRACKDIR_BIT_NONE); for (TrackdirBits rtds = tf.m_new_td_bits; rtds != TRACKDIR_BIT_NONE; rtds = KillFirstBit(rtds)) { Trackdir td = (Trackdir)FindFirstBit2x64(rtds); Node& n = Yapf().CreateNewNode(); n.Set(parent, tf.m_new_tile, td, is_choice); Yapf().AddNewNode(n, tf); } } /** * In some cases an intermediate node branch should be pruned. * The most prominent case is when a red EOL signal is encountered, but * there was a segment change (e.g. a rail type change) before that. If * the branch would not be pruned, the rail type change location would * remain the best intermediate node, and thus the vehicle would still * go towards the red EOL signal. */ void PruneIntermediateNodeBranch() { while (Yapf().m_pBestIntermediateNode != NULL && (Yapf().m_pBestIntermediateNode->m_segment->m_end_segment_reason & ESRB_CHOICE_FOLLOWS) == 0) { Yapf().m_pBestIntermediateNode = Yapf().m_pBestIntermediateNode->m_parent; } } /** * AddNewNode() - called by Tderived::PfFollowNode() for each child node. * Nodes are evaluated here and added into open list */ void AddNewNode(Node &n, const TrackFollower &tf) { /* evaluate the node */ bool bCached = Yapf().PfNodeCacheFetch(n); if (!bCached) { m_stats_cost_calcs++; } else { m_stats_cache_hits++; } bool bValid = Yapf().PfCalcCost(n, &tf); if (bCached) { Yapf().PfNodeCacheFlush(n); } if (bValid) bValid = Yapf().PfCalcEstimate(n); /* have the cost or estimate callbacks marked this node as invalid? */ if (!bValid) return; /* detect the destination */ bool bDestination = Yapf().PfDetectDestination(n); if (bDestination) { if (m_pBestDestNode == NULL || n < *m_pBestDestNode) { m_pBestDestNode = &n; } m_nodes.FoundBestNode(n); return; } if (m_max_search_nodes > 0 && (m_pBestIntermediateNode == NULL || (m_pBestIntermediateNode->GetCostEstimate() - m_pBestIntermediateNode->GetCost()) > (n.GetCostEstimate() - n.GetCost()))) { m_pBestIntermediateNode = &n; } /* check new node against open list */ Node *openNode = m_nodes.FindOpenNode(n.GetKey()); if (openNode != NULL) { /* another node exists with the same key in the open list * is it better than new one? */ if (n.GetCostEstimate() < openNode->GetCostEstimate()) { /* update the old node by value from new one */ m_nodes.PopOpenNode(n.GetKey()); *openNode = n; /* add the updated old node back to open list */ m_nodes.InsertOpenNode(*openNode); } return; } /* check new node against closed list */ Node *closedNode = m_nodes.FindClosedNode(n.GetKey()); if (closedNode != NULL) { /* another node exists with the same key in the closed list * is it better than new one? */ int node_est = n.GetCostEstimate(); int closed_est = closedNode->GetCostEstimate(); if (node_est < closed_est) { /* If this assert occurs, you have probably problem in * your Tderived::PfCalcCost() or Tderived::PfCalcEstimate(). * The problem could be: * - PfCalcEstimate() gives too large numbers * - PfCalcCost() gives too small numbers * - You have used negative cost penalty in some cases (cost bonus) */ NOT_REACHED(); } return; } /* the new node is really new * add it to the open list */ m_nodes.InsertOpenNode(n); } const VehicleType * GetVehicle() const { return m_veh; } void DumpBase(DumpTarget &dmp) const { dmp.WriteStructT("m_nodes", &m_nodes); dmp.WriteLine("m_num_steps = %d", m_num_steps); } /* methods that should be implemented at derived class Types::Tpf (derived from CYapfBaseT) */ #if 0 /** Example: PfSetStartupNodes() - set source (origin) nodes */ inline void PfSetStartupNodes() { /* example: */ Node& n1 = *base::m_nodes.CreateNewNode(); . . // setup node members here . base::m_nodes.InsertOpenNode(n1); } /** Example: PfFollowNode() - set following (child) nodes of the given node */ inline void PfFollowNode(Node& org) { for (each follower of node org) { Node& n = *base::m_nodes.CreateNewNode(); . . // setup node members here . n.m_parent = &org; // set node's parent to allow back tracking AddNewNode(n); } } /** Example: PfCalcCost() - set path cost from origin to the given node */ inline bool PfCalcCost(Node& n) { /* evaluate last step cost */ int cost = ...; /* set the node cost as sum of parent's cost and last step cost */ n.m_cost = n.m_parent->m_cost + cost; return true; // true if node is valid follower (i.e. no obstacle was found) } /** Example: PfCalcEstimate() - set path cost estimate from origin to the target through given node */ inline bool PfCalcEstimate(Node& n) { /* evaluate the distance to our destination */ int distance = ...; /* set estimate as sum of cost from origin + distance to the target */ n.m_estimate = n.m_cost + distance; return true; // true if node is valid (i.e. not too far away :) } /** Example: PfDetectDestination() - return true if the given node is our destination */ inline bool PfDetectDestination(Node& n) { bool bDest = (n.m_key.m_x == m_x2) && (n.m_key.m_y == m_y2); return bDest; } #endif }; #endif /* YAPF_BASE_HPP */ openttd-1.5.3/src/pathfinder/yapf/nodelist.hpp0000644000000000000000000001110412627373445020111 0ustar rootroot/* $Id: nodelist.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 nodelist.hpp List of nodes used for the A-star pathfinder. */ #ifndef NODELIST_HPP #define NODELIST_HPP #include "../../misc/array.hpp" #include "../../misc/hashtable.hpp" #include "../../misc/binaryheap.hpp" /** * Hash table based node list multi-container class. * Implements open list, closed list and priority queue for A-star * path finder. */ template class CNodeList_HashTableT { public: /** make Titem_ visible from outside of class */ typedef Titem_ Titem; /** make Titem_::Key a property of HashTable */ typedef typename Titem_::Key Key; /** type that we will use as item container */ typedef SmallArray CItemArray; /** how pointers to open nodes will be stored */ typedef CHashTableT COpenList; /** how pointers to closed nodes will be stored */ typedef CHashTableT CClosedList; /** how the priority queue will be managed */ typedef CBinaryHeapT CPriorityQueue; protected: /** here we store full item data (Titem_) */ CItemArray m_arr; /** hash table of pointers to open item data */ COpenList m_open; /** hash table of pointers to closed item data */ CClosedList m_closed; /** priority queue of pointers to open item data */ CPriorityQueue m_open_queue; /** new open node under construction */ Titem *m_new_node; public: /** default constructor */ CNodeList_HashTableT() : m_open_queue(2048) { m_new_node = NULL; } /** destructor */ ~CNodeList_HashTableT() { } /** return number of open nodes */ inline int OpenCount() { return m_open.Count(); } /** return number of closed nodes */ inline int ClosedCount() { return m_closed.Count(); } /** allocate new data item from m_arr */ inline Titem_ *CreateNewNode() { if (m_new_node == NULL) m_new_node = m_arr.AppendC(); return m_new_node; } /** Notify the nodelist that we don't want to discard the given node. */ inline void FoundBestNode(Titem_& item) { /* for now it is enough to invalidate m_new_node if it is our given node */ if (&item == m_new_node) { m_new_node = NULL; } /* TODO: do we need to store best nodes found in some extra list/array? Probably not now. */ } /** insert given item as open node (into m_open and m_open_queue) */ inline void InsertOpenNode(Titem_& item) { assert(m_closed.Find(item.GetKey()) == NULL); m_open.Push(item); m_open_queue.Include(&item); if (&item == m_new_node) { m_new_node = NULL; } } /** return the best open node */ inline Titem_ *GetBestOpenNode() { if (!m_open_queue.IsEmpty()) { return m_open_queue.Begin(); } return NULL; } /** remove and return the best open node */ inline Titem_ *PopBestOpenNode() { if (!m_open_queue.IsEmpty()) { Titem_ *item = m_open_queue.Shift(); m_open.Pop(*item); return item; } return NULL; } /** return the open node specified by a key or NULL if not found */ inline Titem_ *FindOpenNode(const Key& key) { Titem_ *item = m_open.Find(key); return item; } /** remove and return the open node specified by a key */ inline Titem_& PopOpenNode(const Key& key) { Titem_& item = m_open.Pop(key); uint idxPop = m_open_queue.FindIndex(item); m_open_queue.Remove(idxPop); return item; } /** close node */ inline void InsertClosedNode(Titem_& item) { assert(m_open.Find(item.GetKey()) == NULL); m_closed.Push(item); } /** return the closed node specified by a key or NULL if not found */ inline Titem_ *FindClosedNode(const Key& key) { Titem_ *item = m_closed.Find(key); return item; } /** The number of items. */ inline int TotalCount() {return m_arr.Length();} /** Get a particular item. */ inline Titem_& ItemAt(int idx) {return m_arr[idx];} /** Helper for creating output of this array. */ template void Dump(D &dmp) const { dmp.WriteStructT("m_arr", &m_arr); } }; #endif /* NODELIST_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_costcache.hpp0000644000000000000000000001572112627373445021254 0ustar rootroot/* $Id: yapf_costcache.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 yapf_costcache.hpp Caching of segment costs. */ #ifndef YAPF_COSTCACHE_HPP #define YAPF_COSTCACHE_HPP #include "../../date_func.h" /** * CYapfSegmentCostCacheNoneT - the formal only yapf cost cache provider that implements * PfNodeCacheFetch() and PfNodeCacheFlush() callbacks. Used when nodes don't have CachedData * defined (they don't count with any segment cost caching). */ template class CYapfSegmentCostCacheNoneT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type /** * Called by YAPF to attach cached or local segment cost data to the given node. * @return true if globally cached data were used or false if local data was used */ inline bool PfNodeCacheFetch(Node& n) { return false; } /** * Called by YAPF to flush the cached segment cost data back into cache storage. * Current cache implementation doesn't use that. */ inline void PfNodeCacheFlush(Node& n) { } }; /** * CYapfSegmentCostCacheLocalT - the yapf cost cache provider that implements fake segment * cost caching functionality for yapf. Used when node needs caching, but you don't want to * cache the segment costs. */ template class CYapfSegmentCostCacheLocalT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables typedef typename Node::CachedData CachedData; typedef typename CachedData::Key CacheKey; typedef SmallArray LocalCache; protected: LocalCache m_local_cache; /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** * Called by YAPF to attach cached or local segment cost data to the given node. * @return true if globally cached data were used or false if local data was used */ inline bool PfNodeCacheFetch(Node& n) { CacheKey key(n.GetKey()); Yapf().ConnectNodeToCachedData(n, *new (m_local_cache.Append()) CachedData(key)); return false; } /** * Called by YAPF to flush the cached segment cost data back into cache storage. * Current cache implementation doesn't use that. */ inline void PfNodeCacheFlush(Node& n) { } }; /** * Base class for segment cost cache providers. Contains global counter * of track layout changes and static notification function called whenever * the track layout changes. It is implemented as base class because it needs * to be shared between all rail YAPF types (one shared counter, one notification * function. */ struct CSegmentCostCacheBase { static int s_rail_change_counter; static void NotifyTrackLayoutChange(TileIndex tile, Track track) { s_rail_change_counter++; } }; /** * CSegmentCostCacheT - template class providing hash-map and storage (heap) * of Tsegment structures. Each rail node contains pointer to the segment * that contains cached (or non-cached) segment cost information. Nodes can * differ by key type, but they use the same segment type. Segment key should * be always the same (TileIndex + DiagDirection) that represent the beginning * of the segment (origin tile and exit-dir from this tile). * Different CYapfCachedCostT types can share the same type of CSegmentCostCacheT. * Look at CYapfRailSegment (yapf_node_rail.hpp) for the segment example */ template struct CSegmentCostCacheT : public CSegmentCostCacheBase { static const int C_HASH_BITS = 14; typedef CHashTableT HashTable; typedef SmallArray Heap; typedef typename Tsegment::Key Key; ///< key to hash table HashTable m_map; Heap m_heap; inline CSegmentCostCacheT() {} /** flush (clear) the cache */ inline void Flush() { m_map.Clear(); m_heap.Clear(); } inline Tsegment& Get(Key& key, bool *found) { Tsegment *item = m_map.Find(key); if (item == NULL) { *found = false; item = new (m_heap.Append()) Tsegment(key); m_map.Push(*item); } else { *found = true; } return *item; } }; /** * CYapfSegmentCostCacheGlobalT - the yapf cost cache provider that adds the segment cost * caching functionality to yapf. Using this class as base of your will provide the global * segment cost caching services for your Nodes. */ template class CYapfSegmentCostCacheGlobalT : public CYapfSegmentCostCacheLocalT { public: typedef CYapfSegmentCostCacheLocalT Tlocal; typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables typedef typename Node::CachedData CachedData; typedef typename CachedData::Key CacheKey; typedef CSegmentCostCacheT Cache; protected: Cache& m_global_cache; inline CYapfSegmentCostCacheGlobalT() : m_global_cache(stGetGlobalCache()) {}; /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } inline static Cache& stGetGlobalCache() { static int last_rail_change_counter = 0; static Date last_date = 0; static Cache C; /* some statistics */ if (last_date != _date) { last_date = _date; DEBUG(yapf, 2, "Pf time today: %5d ms", _total_pf_time_us / 1000); _total_pf_time_us = 0; } /* delete the cache sometimes... */ if (last_rail_change_counter != Cache::s_rail_change_counter) { last_rail_change_counter = Cache::s_rail_change_counter; C.Flush(); } return C; } public: /** * Called by YAPF to attach cached or local segment cost data to the given node. * @return true if globally cached data were used or false if local data was used */ inline bool PfNodeCacheFetch(Node& n) { if (!Yapf().CanUseGlobalCache(n)) { return Tlocal::PfNodeCacheFetch(n); } CacheKey key(n.GetKey()); bool found; CachedData& item = m_global_cache.Get(key, &found); Yapf().ConnectNodeToCachedData(n, item); return found; } /** * Called by YAPF to flush the cached segment cost data back into cache storage. * Current cache implementation doesn't use that. */ inline void PfNodeCacheFlush(Node& n) { } }; #endif /* YAPF_COSTCACHE_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_node_rail.hpp0000644000000000000000000001520412627373445021250 0ustar rootroot/* $Id: yapf_node_rail.hpp 26058 2013-11-23 13:15:07Z rubidium $ */ /* * 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 yapf_node_rail.hpp Node tailored for rail pathfinding. */ #ifndef YAPF_NODE_RAIL_HPP #define YAPF_NODE_RAIL_HPP /** key for cached segment cost for rail YAPF */ struct CYapfRailSegmentKey { uint32 m_value; inline CYapfRailSegmentKey(const CYapfRailSegmentKey& src) : m_value(src.m_value) {} inline CYapfRailSegmentKey(const CYapfNodeKeyTrackDir& node_key) { Set(node_key); } inline void Set(const CYapfRailSegmentKey& src) { m_value = src.m_value; } inline void Set(const CYapfNodeKeyTrackDir& node_key) { m_value = (((int)node_key.m_tile) << 4) | node_key.m_td; } inline int32 CalcHash() const { return m_value; } inline TileIndex GetTile() const { return (TileIndex)(m_value >> 4); } inline Trackdir GetTrackdir() const { return (Trackdir)(m_value & 0x0F); } inline bool operator == (const CYapfRailSegmentKey& other) const { return m_value == other.m_value; } void Dump(DumpTarget &dmp) const { dmp.WriteTile("tile", GetTile()); dmp.WriteEnumT("td", GetTrackdir()); } }; /** cached segment cost for rail YAPF */ struct CYapfRailSegment { typedef CYapfRailSegmentKey Key; CYapfRailSegmentKey m_key; TileIndex m_last_tile; Trackdir m_last_td; int m_cost; TileIndex m_last_signal_tile; Trackdir m_last_signal_td; EndSegmentReasonBits m_end_segment_reason; CYapfRailSegment *m_hash_next; inline CYapfRailSegment(const CYapfRailSegmentKey& key) : m_key(key) , m_last_tile(INVALID_TILE) , m_last_td(INVALID_TRACKDIR) , m_cost(-1) , m_last_signal_tile(INVALID_TILE) , m_last_signal_td(INVALID_TRACKDIR) , m_end_segment_reason(ESRB_NONE) , m_hash_next(NULL) {} inline const Key& GetKey() const { return m_key; } inline TileIndex GetTile() const { return m_key.GetTile(); } inline CYapfRailSegment *GetHashNext() { return m_hash_next; } inline void SetHashNext(CYapfRailSegment *next) { m_hash_next = next; } void Dump(DumpTarget &dmp) const { dmp.WriteStructT("m_key", &m_key); dmp.WriteTile("m_last_tile", m_last_tile); dmp.WriteEnumT("m_last_td", m_last_td); dmp.WriteLine("m_cost = %d", m_cost); dmp.WriteTile("m_last_signal_tile", m_last_signal_tile); dmp.WriteEnumT("m_last_signal_td", m_last_signal_td); dmp.WriteEnumT("m_end_segment_reason", m_end_segment_reason); } }; /** Yapf Node for rail YAPF */ template struct CYapfRailNodeT : CYapfNodeT > { typedef CYapfNodeT > base; typedef CYapfRailSegment CachedData; CYapfRailSegment *m_segment; uint16 m_num_signals_passed; union { uint32 m_inherited_flags; struct { bool m_targed_seen : 1; bool m_choice_seen : 1; bool m_last_signal_was_red : 1; } flags_s; } flags_u; SignalType m_last_red_signal_type; SignalType m_last_signal_type; inline void Set(CYapfRailNodeT *parent, TileIndex tile, Trackdir td, bool is_choice) { base::Set(parent, tile, td, is_choice); m_segment = NULL; if (parent == NULL) { m_num_signals_passed = 0; flags_u.m_inherited_flags = 0; m_last_red_signal_type = SIGTYPE_NORMAL; /* We use PBS as initial signal type because if we are in * a PBS section and need to route, i.e. we're at a safe * waiting point of a station, we need to account for the * reservation costs. If we are in a normal block then we * should be alone in there and as such the reservation * costs should be 0 anyway. If there would be another * train in the block, i.e. passing signals at danger * then avoiding that train with help of the reservation * costs is not a bad thing, actually it would probably * be a good thing to do. */ m_last_signal_type = SIGTYPE_PBS; } else { m_num_signals_passed = parent->m_num_signals_passed; flags_u.m_inherited_flags = parent->flags_u.m_inherited_flags; m_last_red_signal_type = parent->m_last_red_signal_type; m_last_signal_type = parent->m_last_signal_type; } flags_u.flags_s.m_choice_seen |= is_choice; } inline TileIndex GetLastTile() const { assert(m_segment != NULL); return m_segment->m_last_tile; } inline Trackdir GetLastTrackdir() const { assert(m_segment != NULL); return m_segment->m_last_td; } inline void SetLastTileTrackdir(TileIndex tile, Trackdir td) { assert(m_segment != NULL); m_segment->m_last_tile = tile; m_segment->m_last_td = td; } template bool IterateTiles(const Train *v, Tpf &yapf, Tbase &obj, bool (Tfunc::*func)(TileIndex, Trackdir)) const { typename Tbase::TrackFollower ft(v, yapf.GetCompatibleRailTypes()); TileIndex cur = base::GetTile(); Trackdir cur_td = base::GetTrackdir(); while (cur != GetLastTile() || cur_td != GetLastTrackdir()) { if (!((obj.*func)(cur, cur_td))) return false; if (!ft.Follow(cur, cur_td)) break; cur = ft.m_new_tile; assert(KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE); cur_td = FindFirstTrackdir(ft.m_new_td_bits); } return (obj.*func)(cur, cur_td); } void Dump(DumpTarget &dmp) const { base::Dump(dmp); dmp.WriteStructT("m_segment", m_segment); dmp.WriteLine("m_num_signals_passed = %d", m_num_signals_passed); dmp.WriteLine("m_targed_seen = %s", flags_u.flags_s.m_targed_seen ? "Yes" : "No"); dmp.WriteLine("m_choice_seen = %s", flags_u.flags_s.m_choice_seen ? "Yes" : "No"); dmp.WriteLine("m_last_signal_was_red = %s", flags_u.flags_s.m_last_signal_was_red ? "Yes" : "No"); dmp.WriteEnumT("m_last_red_signal_type", m_last_red_signal_type); } }; /* now define two major node types (that differ by key type) */ typedef CYapfRailNodeT CYapfRailNodeExitDir; typedef CYapfRailNodeT CYapfRailNodeTrackDir; /* Default NodeList types */ typedef CNodeList_HashTableT CRailNodeListExitDir; typedef CNodeList_HashTableT CRailNodeListTrackDir; #endif /* YAPF_NODE_RAIL_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_node.hpp0000644000000000000000000000541712627373445020246 0ustar rootroot/* $Id: yapf_node.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 yapf_node.hpp Node in the pathfinder's graph. */ #ifndef YAPF_NODE_HPP #define YAPF_NODE_HPP /** Yapf Node Key that evaluates hash from (and compares) tile & exit dir. */ struct CYapfNodeKeyExitDir { TileIndex m_tile; Trackdir m_td; DiagDirection m_exitdir; inline void Set(TileIndex tile, Trackdir td) { m_tile = tile; m_td = td; m_exitdir = (m_td == INVALID_TRACKDIR) ? INVALID_DIAGDIR : TrackdirToExitdir(m_td); } inline int CalcHash() const {return m_exitdir | (m_tile << 2);} inline bool operator == (const CYapfNodeKeyExitDir& other) const {return (m_tile == other.m_tile) && (m_exitdir == other.m_exitdir);} void Dump(DumpTarget &dmp) const { dmp.WriteTile("m_tile", m_tile); dmp.WriteEnumT("m_td", m_td); dmp.WriteEnumT("m_exitdir", m_exitdir); } }; struct CYapfNodeKeyTrackDir : public CYapfNodeKeyExitDir { inline int CalcHash() const {return m_td | (m_tile << 4);} inline bool operator == (const CYapfNodeKeyTrackDir& other) const {return (m_tile == other.m_tile) && (m_td == other.m_td);} }; /** Yapf Node base */ template struct CYapfNodeT { typedef Tkey_ Key; typedef Tnode Node; Tkey_ m_key; Node *m_hash_next; Node *m_parent; int m_cost; int m_estimate; inline void Set(Node *parent, TileIndex tile, Trackdir td, bool is_choice) { m_key.Set(tile, td); m_hash_next = NULL; m_parent = parent; m_cost = 0; m_estimate = 0; } inline Node *GetHashNext() {return m_hash_next;} inline void SetHashNext(Node *pNext) {m_hash_next = pNext;} inline TileIndex GetTile() const {return m_key.m_tile;} inline Trackdir GetTrackdir() const {return m_key.m_td;} inline const Tkey_& GetKey() const {return m_key;} inline int GetCost() const {return m_cost;} inline int GetCostEstimate() const {return m_estimate;} inline bool operator < (const Node& other) const {return m_estimate < other.m_estimate;} void Dump(DumpTarget &dmp) const { dmp.WriteStructT("m_key", &m_key); dmp.WriteStructT("m_parent", m_parent); dmp.WriteLine("m_cost = %d", m_cost); dmp.WriteLine("m_estimate = %d", m_estimate); } }; #endif /* YAPF_NODE_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_common.hpp0000644000000000000000000001613512627373445020610 0ustar rootroot/* $Id: yapf_common.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 yapf_common.hpp Commonly used classes for YAPF. */ #ifndef YAPF_COMMON_HPP #define YAPF_COMMON_HPP /** YAPF origin provider base class - used when origin is one tile / multiple trackdirs */ template class CYapfOriginTileT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: TileIndex m_orgTile; ///< origin tile TrackdirBits m_orgTrackdirs; ///< origin trackdir mask /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** Set origin tile / trackdir mask */ void SetOrigin(TileIndex tile, TrackdirBits trackdirs) { m_orgTile = tile; m_orgTrackdirs = trackdirs; } /** Called when YAPF needs to place origin nodes into open list */ void PfSetStartupNodes() { bool is_choice = (KillFirstBit(m_orgTrackdirs) != TRACKDIR_BIT_NONE); for (TrackdirBits tdb = m_orgTrackdirs; tdb != TRACKDIR_BIT_NONE; tdb = KillFirstBit(tdb)) { Trackdir td = (Trackdir)FindFirstBit2x64(tdb); Node& n1 = Yapf().CreateNewNode(); n1.Set(NULL, m_orgTile, td, is_choice); Yapf().AddStartupNode(n1); } } }; /** YAPF origin provider base class - used when there are two tile/trackdir origins */ template class CYapfOriginTileTwoWayT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: TileIndex m_orgTile; ///< first origin tile Trackdir m_orgTd; ///< first origin trackdir TileIndex m_revTile; ///< second (reversed) origin tile Trackdir m_revTd; ///< second (reversed) origin trackdir int m_reverse_penalty; ///< penalty to be added for using the reversed origin bool m_treat_first_red_two_way_signal_as_eol; ///< in some cases (leaving station) we need to handle first two-way signal differently /** to access inherited path finder */ inline Tpf& Yapf() { return *static_cast(this); } public: /** set origin (tiles, trackdirs, etc.) */ void SetOrigin(TileIndex tile, Trackdir td, TileIndex tiler = INVALID_TILE, Trackdir tdr = INVALID_TRACKDIR, int reverse_penalty = 0, bool treat_first_red_two_way_signal_as_eol = true) { m_orgTile = tile; m_orgTd = td; m_revTile = tiler; m_revTd = tdr; m_reverse_penalty = reverse_penalty; m_treat_first_red_two_way_signal_as_eol = treat_first_red_two_way_signal_as_eol; } /** Called when YAPF needs to place origin nodes into open list */ void PfSetStartupNodes() { if (m_orgTile != INVALID_TILE && m_orgTd != INVALID_TRACKDIR) { Node& n1 = Yapf().CreateNewNode(); n1.Set(NULL, m_orgTile, m_orgTd, false); Yapf().AddStartupNode(n1); } if (m_revTile != INVALID_TILE && m_revTd != INVALID_TRACKDIR) { Node& n2 = Yapf().CreateNewNode(); n2.Set(NULL, m_revTile, m_revTd, false); n2.m_cost = m_reverse_penalty; Yapf().AddStartupNode(n2); } } /** return true if first two-way signal should be treated as dead end */ inline bool TreatFirstRedTwoWaySignalAsEOL() { return Yapf().PfGetSettings().rail_firstred_twoway_eol && m_treat_first_red_two_way_signal_as_eol; } }; /** YAPF destination provider base class - used when destination is single tile / multiple trackdirs */ template class CYapfDestinationTileT { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables protected: TileIndex m_destTile; ///< destination tile TrackdirBits m_destTrackdirs; ///< destination trackdir mask public: /** set the destination tile / more trackdirs */ void SetDestination(TileIndex tile, TrackdirBits trackdirs) { m_destTile = tile; m_destTrackdirs = trackdirs; } protected: /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } public: /** Called by YAPF to detect if node ends in the desired destination */ inline bool PfDetectDestination(Node& n) { bool bDest = (n.m_key.m_tile == m_destTile) && ((m_destTrackdirs & TrackdirToTrackdirBits(n.GetTrackdir())) != TRACKDIR_BIT_NONE); return bDest; } /** * Called by YAPF to calculate cost estimate. Calculates distance to the destination * adds it to the actual cost from origin and stores the sum to the Node::m_estimate */ inline bool PfCalcEstimate(Node& n) { static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0}; static const int dg_dir_to_y_offs[] = {0, 1, 0, -1}; if (PfDetectDestination(n)) { n.m_estimate = n.m_cost; return true; } TileIndex tile = n.GetTile(); DiagDirection exitdir = TrackdirToExitdir(n.GetTrackdir()); int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir]; int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir]; int x2 = 2 * TileX(m_destTile); int y2 = 2 * TileY(m_destTile); int dx = abs(x1 - x2); int dy = abs(y1 - y2); int dmin = min(dx, dy); int dxy = abs(dx - dy); int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2); n.m_estimate = n.m_cost + d; assert(n.m_estimate >= n.m_parent->m_estimate); return true; } }; /** * YAPF template that uses Ttypes template argument to determine all YAPF * components (base classes) from which the actual YAPF is composed. * For example classes consult: CYapfRail_TypesT template and its instantiations: * CYapfRail1, CYapfRail2, CYapfRail3, CYapfAnyDepotRail1, CYapfAnyDepotRail2, CYapfAnyDepotRail3 */ template class CYapfT : public Ttypes::PfBase ///< Instance of CYapfBaseT - main YAPF loop and support base class , public Ttypes::PfCost ///< Cost calculation provider base class , public Ttypes::PfCache ///< Segment cost cache provider , public Ttypes::PfOrigin ///< Origin (tile or two-tile origin) , public Ttypes::PfDestination ///< Destination detector and distance (estimate) calculation provider , public Ttypes::PfFollow ///< Node follower (stepping provider) { }; #endif /* YAPF_COMMON_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_node_ship.hpp0000644000000000000000000000245412627373445021267 0ustar rootroot/* $Id: yapf_node_ship.hpp 22350 2011-04-19 18:12:47Z smatz $ */ /* * 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 yapf_node_ship.hpp Node tailored for ship pathfinding. */ #ifndef YAPF_NODE_SHIP_HPP #define YAPF_NODE_SHIP_HPP /** Yapf Node for ships */ template struct CYapfShipNodeT : CYapfNodeT > { }; /* now define two major node types (that differ by key type) */ typedef CYapfShipNodeT CYapfShipNodeExitDir; typedef CYapfShipNodeT CYapfShipNodeTrackDir; /* Default NodeList types */ typedef CNodeList_HashTableT CShipNodeListExitDir; typedef CNodeList_HashTableT CShipNodeListTrackDir; #endif /* YAPF_NODE_SHIP_HPP */ openttd-1.5.3/src/pathfinder/yapf/yapf_costrail.hpp0000644000000000000000000005637312627373445021150 0ustar rootroot/* $Id: yapf_costrail.hpp 25609 2013-07-14 09:21:46Z rubidium $ */ /* * 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 yapf_costrail.hpp Cost determination for rails. */ #ifndef YAPF_COSTRAIL_HPP #define YAPF_COSTRAIL_HPP #include "../../pbs.h" template class CYapfCostRailT : public CYapfCostBase { public: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) typedef typename Types::TrackFollower TrackFollower; typedef typename Types::NodeList::Titem Node; ///< this will be our node type typedef typename Node::Key Key; ///< key to hash tables typedef typename Node::CachedData CachedData; protected: /* Structure used inside PfCalcCost() to keep basic tile information. */ struct TILE { TileIndex tile; Trackdir td; TileType tile_type; RailType rail_type; TILE() { tile = INVALID_TILE; td = INVALID_TRACKDIR; tile_type = MP_VOID; rail_type = INVALID_RAILTYPE; } TILE(TileIndex tile, Trackdir td) { this->tile = tile; this->td = td; this->tile_type = GetTileType(tile); this->rail_type = GetTileRailType(tile); } TILE(const TILE &src) { tile = src.tile; td = src.td; tile_type = src.tile_type; rail_type = src.rail_type; } }; protected: /** * @note maximum cost doesn't work with caching enabled * @todo fix maximum cost failing with caching (e.g. FS#2900) */ int m_max_cost; CBlobT m_sig_look_ahead_costs; bool m_disable_cache; public: bool m_stopped_on_first_two_way_signal; protected: static const int s_max_segment_cost = 10000; CYapfCostRailT() : m_max_cost(0) , m_disable_cache(false) , m_stopped_on_first_two_way_signal(false) { /* pre-compute look-ahead penalties into array */ int p0 = Yapf().PfGetSettings().rail_look_ahead_signal_p0; int p1 = Yapf().PfGetSettings().rail_look_ahead_signal_p1; int p2 = Yapf().PfGetSettings().rail_look_ahead_signal_p2; int *pen = m_sig_look_ahead_costs.GrowSizeNC(Yapf().PfGetSettings().rail_look_ahead_max_signals); for (uint i = 0; i < Yapf().PfGetSettings().rail_look_ahead_max_signals; i++) { pen[i] = p0 + i * (p1 + i * p2); } } /** to access inherited path finder */ Tpf& Yapf() { return *static_cast(this); } public: inline int SlopeCost(TileIndex tile, Trackdir td) { CPerfStart perf_cost(Yapf().m_perf_slope_cost); if (!stSlopeCost(tile, td)) return 0; return Yapf().PfGetSettings().rail_slope_penalty; } inline int CurveCost(Trackdir td1, Trackdir td2) { assert(IsValidTrackdir(td1)); assert(IsValidTrackdir(td2)); int cost = 0; if (TrackFollower::Allow90degTurns() && ((TrackdirToTrackdirBits(td2) & (TrackdirBits)TrackdirCrossesTrackdirs(td1)) != 0)) { /* 90-deg curve penalty */ cost += Yapf().PfGetSettings().rail_curve90_penalty; } else if (td2 != NextTrackdir(td1)) { /* 45-deg curve penalty */ cost += Yapf().PfGetSettings().rail_curve45_penalty; } return cost; } inline int SwitchCost(TileIndex tile1, TileIndex tile2, DiagDirection exitdir) { if (IsPlainRailTile(tile1) && IsPlainRailTile(tile2)) { bool t1 = KillFirstBit(GetTrackBits(tile1) & DiagdirReachesTracks(ReverseDiagDir(exitdir))) != TRACK_BIT_NONE; bool t2 = KillFirstBit(GetTrackBits(tile2) & DiagdirReachesTracks(exitdir)) != TRACK_BIT_NONE; if (t1 && t2) return Yapf().PfGetSettings().rail_doubleslip_penalty; } return 0; } /** Return one tile cost (base cost + level crossing penalty). */ inline int OneTileCost(TileIndex& tile, Trackdir trackdir) { int cost = 0; /* set base cost */ if (IsDiagonalTrackdir(trackdir)) { cost += YAPF_TILE_LENGTH; switch (GetTileType(tile)) { case MP_ROAD: /* Increase the cost for level crossings */ if (IsLevelCrossing(tile)) { cost += Yapf().PfGetSettings().rail_crossing_penalty; } break; default: break; } } else { /* non-diagonal trackdir */ cost = YAPF_TILE_CORNER_LENGTH; } return cost; } /** Check for a reserved station platform. */ inline bool IsAnyStationTileReserved(TileIndex tile, Trackdir trackdir, int skipped) { TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(trackdir))); for (; skipped >= 0; skipped--, tile += diff) { if (HasStationReservation(tile)) return true; } return false; } /** The cost for reserved tiles, including skipped ones. */ inline int ReservationCost(Node& n, TileIndex tile, Trackdir trackdir, int skipped) { if (n.m_num_signals_passed >= m_sig_look_ahead_costs.Size() / 2) return 0; if (!IsPbsSignal(n.m_last_signal_type)) return 0; if (IsRailStationTile(tile) && IsAnyStationTileReserved(tile, trackdir, skipped)) { return Yapf().PfGetSettings().rail_pbs_station_penalty * (skipped + 1); } else if (TrackOverlapsTracks(GetReservedTrackbits(tile), TrackdirToTrack(trackdir))) { int cost = Yapf().PfGetSettings().rail_pbs_cross_penalty; if (!IsDiagonalTrackdir(trackdir)) cost = (cost * YAPF_TILE_CORNER_LENGTH) / YAPF_TILE_LENGTH; return cost * (skipped + 1); } return 0; } int SignalCost(Node& n, TileIndex tile, Trackdir trackdir) { int cost = 0; /* if there is one-way signal in the opposite direction, then it is not our way */ CPerfStart perf_cost(Yapf().m_perf_other_cost); if (IsTileType(tile, MP_RAILWAY)) { bool has_signal_against = HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir)); bool has_signal_along = HasSignalOnTrackdir(tile, trackdir); if (has_signal_against && !has_signal_along && IsOnewaySignal(tile, TrackdirToTrack(trackdir))) { /* one-way signal in opposite direction */ n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; } else { if (has_signal_along) { SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir); SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir)); n.m_last_signal_type = sig_type; /* cache the look-ahead polynomial constant only if we didn't pass more signals than the look-ahead limit is */ int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) ? m_sig_look_ahead_costs.Data()[n.m_num_signals_passed] : 0; if (sig_state != SIGNAL_STATE_RED) { /* green signal */ n.flags_u.flags_s.m_last_signal_was_red = false; /* negative look-ahead red-signal penalties would cause problems later, so use them as positive penalties for green signal */ if (look_ahead_cost < 0) { /* add its negation to the cost */ cost -= look_ahead_cost; } } else { /* we have a red signal in our direction * was it first signal which is two-way? */ if (!IsPbsSignal(sig_type) && Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) { /* yes, the first signal is two-way red signal => DEAD END. Prune this branch... */ Yapf().PruneIntermediateNodeBranch(); n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; Yapf().m_stopped_on_first_two_way_signal = true; return -1; } n.m_last_red_signal_type = sig_type; n.flags_u.flags_s.m_last_signal_was_red = true; /* look-ahead signal penalty */ if (!IsPbsSignal(sig_type) && look_ahead_cost > 0) { /* add the look ahead penalty only if it is positive */ cost += look_ahead_cost; } /* special signal penalties */ if (n.m_num_signals_passed == 0) { switch (sig_type) { case SIGTYPE_COMBO: case SIGTYPE_EXIT: cost += Yapf().PfGetSettings().rail_firstred_exit_penalty; break; // first signal is red pre-signal-exit case SIGTYPE_NORMAL: case SIGTYPE_ENTRY: cost += Yapf().PfGetSettings().rail_firstred_penalty; break; default: break; } } } n.m_num_signals_passed++; n.m_segment->m_last_signal_tile = tile; n.m_segment->m_last_signal_td = trackdir; } if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) { cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0; } } } return cost; } inline int PlatformLengthPenalty(int platform_length) { int cost = 0; const Train *v = Yapf().GetVehicle(); assert(v != NULL); assert(v->type == VEH_TRAIN); assert(v->gcache.cached_total_length != 0); int missing_platform_length = CeilDiv(v->gcache.cached_total_length, TILE_SIZE) - platform_length; if (missing_platform_length < 0) { /* apply penalty for longer platform than needed */ cost += Yapf().PfGetSettings().rail_longer_platform_penalty + Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length; } else if (missing_platform_length > 0) { /* apply penalty for shorter platform than needed */ cost += Yapf().PfGetSettings().rail_shorter_platform_penalty + Yapf().PfGetSettings().rail_shorter_platform_per_tile_penalty * missing_platform_length; } return cost; } public: inline void SetMaxCost(int max_cost) { m_max_cost = max_cost; } /** * Called by YAPF to calculate the cost from the origin to the given node. * Calculates only the cost of given node, adds it to the parent node cost * and stores the result into Node::m_cost member */ inline bool PfCalcCost(Node &n, const TrackFollower *tf) { assert(!n.flags_u.flags_s.m_targed_seen); assert(tf->m_new_tile == n.m_key.m_tile); assert((TrackdirToTrackdirBits(n.m_key.m_td) & tf->m_new_td_bits) != TRACKDIR_BIT_NONE); CPerfStart perf_cost(Yapf().m_perf_cost); /* Does the node have some parent node? */ bool has_parent = (n.m_parent != NULL); /* Do we already have a cached segment? */ CachedData &segment = *n.m_segment; bool is_cached_segment = (segment.m_cost >= 0); int parent_cost = has_parent ? n.m_parent->m_cost : 0; /* Each node cost contains 2 or 3 main components: * 1. Transition cost - cost of the move from previous node (tile): * - curve cost (or zero for straight move) * 2. Tile cost: * - base tile cost * - YAPF_TILE_LENGTH for diagonal tiles * - YAPF_TILE_CORNER_LENGTH for non-diagonal tiles * - tile penalties * - tile slope penalty (upward slopes) * - red signal penalty * - level crossing penalty * - speed-limit penalty (bridges) * - station platform penalty * - penalty for reversing in the depot * - etc. * 3. Extra cost (applies to the last node only) * - last red signal penalty * - penalty for too long or too short platform on the destination station */ int transition_cost = 0; int extra_cost = 0; /* Segment: one or more tiles connected by contiguous tracks of the same type. * Each segment cost includes 'Tile cost' for all its tiles (including the first * and last), and the 'Transition cost' between its tiles. The first transition * cost of segment entry (move from the 'parent' node) is not included! */ int segment_entry_cost = 0; int segment_cost = 0; const Train *v = Yapf().GetVehicle(); /* start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment */ TILE cur(n.m_key.m_tile, n.m_key.m_td); /* the previous tile will be needed for transition cost calculations */ TILE prev = !has_parent ? TILE() : TILE(n.m_parent->GetLastTile(), n.m_parent->GetLastTrackdir()); EndSegmentReasonBits end_segment_reason = ESRB_NONE; TrackFollower tf_local(v, Yapf().GetCompatibleRailTypes(), &Yapf().m_perf_ts_cost); if (!has_parent) { /* We will jump to the middle of the cost calculator assuming that segment cache is not used. */ assert(!is_cached_segment); /* Skip the first transition cost calculation. */ goto no_entry_cost; } for (;;) { /* Transition cost (cost of the move from previous tile) */ transition_cost = Yapf().CurveCost(prev.td, cur.td); transition_cost += Yapf().SwitchCost(prev.tile, cur.tile, TrackdirToExitdir(prev.td)); /* First transition cost counts against segment entry cost, other transitions * inside segment will come to segment cost (and will be cached) */ if (segment_cost == 0) { /* We just entered the loop. First transition cost goes to segment entry cost)*/ segment_entry_cost = transition_cost; transition_cost = 0; /* It is the right time now to look if we can reuse the cached segment cost. */ if (is_cached_segment) { /* Yes, we already know the segment cost. */ segment_cost = segment.m_cost; /* We know also the reason why the segment ends. */ end_segment_reason = segment.m_end_segment_reason; /* We will need also some information about the last signal (if it was red). */ if (segment.m_last_signal_tile != INVALID_TILE) { assert(HasSignalOnTrackdir(segment.m_last_signal_tile, segment.m_last_signal_td)); SignalState sig_state = GetSignalStateByTrackdir(segment.m_last_signal_tile, segment.m_last_signal_td); bool is_red = (sig_state == SIGNAL_STATE_RED); n.flags_u.flags_s.m_last_signal_was_red = is_red; if (is_red) { n.m_last_red_signal_type = GetSignalType(segment.m_last_signal_tile, TrackdirToTrack(segment.m_last_signal_td)); } } /* No further calculation needed. */ cur = TILE(n.GetLastTile(), n.GetLastTrackdir()); break; } } else { /* Other than first transition cost count as the regular segment cost. */ segment_cost += transition_cost; } no_entry_cost: // jump here at the beginning if the node has no parent (it is the first node) /* All other tile costs will be calculated here. */ segment_cost += Yapf().OneTileCost(cur.tile, cur.td); /* If we skipped some tunnel/bridge/station tiles, add their base cost */ segment_cost += YAPF_TILE_LENGTH * tf->m_tiles_skipped; /* Slope cost. */ segment_cost += Yapf().SlopeCost(cur.tile, cur.td); /* Signal cost (routine can modify segment data). */ segment_cost += Yapf().SignalCost(n, cur.tile, cur.td); /* Reserved tiles. */ segment_cost += Yapf().ReservationCost(n, cur.tile, cur.td, tf->m_tiles_skipped); end_segment_reason = segment.m_end_segment_reason; /* Tests for 'potential target' reasons to close the segment. */ if (cur.tile == prev.tile) { /* Penalty for reversing in a depot. */ assert(IsRailDepot(cur.tile)); segment_cost += Yapf().PfGetSettings().rail_depot_reverse_penalty; /* We will end in this pass (depot is possible target) */ end_segment_reason |= ESRB_DEPOT; } else if (cur.tile_type == MP_STATION && IsRailWaypoint(cur.tile)) { if (v->current_order.IsType(OT_GOTO_WAYPOINT) && GetStationIndex(cur.tile) == v->current_order.GetDestination() && !Waypoint::Get(v->current_order.GetDestination())->IsSingleTile()) { /* This waypoint is our destination; maybe this isn't an unreserved * one, so check that and if so see that as the last signal being * red. This way waypoints near stations should work better. */ CFollowTrackRail ft(v); TileIndex t = cur.tile; Trackdir td = cur.td; while (ft.Follow(t, td)) { assert(t != ft.m_new_tile); t = ft.m_new_tile; if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { /* We encountered a junction; it's going to be too complex to * handle this perfectly, so just bail out. There is no simple * free path, so try the other possibilities. */ td = INVALID_TRACKDIR; break; } td = RemoveFirstTrackdir(&ft.m_new_td_bits); /* If this is a safe waiting position we're done searching for it */ if (IsSafeWaitingPosition(v, t, td, true, _settings_game.pf.forbid_90_deg)) break; } /* In the case this platform is (possibly) occupied we add penalty so the * other platforms of this waypoint are evaluated as well, i.e. we assume * that there is a red signal in the waypoint when it's occupied. */ if (td == INVALID_TRACKDIR || !IsSafeWaitingPosition(v, t, td, true, _settings_game.pf.forbid_90_deg) || !IsWaitingPositionFree(v, t, td, _settings_game.pf.forbid_90_deg)) { extra_cost += Yapf().PfGetSettings().rail_lastred_penalty; } } /* Waypoint is also a good reason to finish. */ end_segment_reason |= ESRB_WAYPOINT; } else if (tf->m_is_station) { /* Station penalties. */ uint platform_length = tf->m_tiles_skipped + 1; /* We don't know yet if the station is our target or not. Act like * if it is pass-through station (not our destination). */ segment_cost += Yapf().PfGetSettings().rail_station_penalty * platform_length; /* We will end in this pass (station is possible target) */ end_segment_reason |= ESRB_STATION; } else if (TrackFollower::DoTrackMasking() && cur.tile_type == MP_RAILWAY) { /* Searching for a safe tile? */ if (HasSignalOnTrackdir(cur.tile, cur.td) && !IsPbsSignal(GetSignalType(cur.tile, TrackdirToTrack(cur.td)))) { end_segment_reason |= ESRB_SAFE_TILE; } } /* Apply min/max speed penalties only when inside the look-ahead radius. Otherwise * it would cause desync in MP. */ if (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) { int min_speed = 0; int max_speed = tf->GetSpeedLimit(&min_speed); int max_veh_speed = v->GetDisplayMaxSpeed(); if (max_speed < max_veh_speed) { extra_cost += YAPF_TILE_LENGTH * (max_veh_speed - max_speed) * (4 + tf->m_tiles_skipped) / max_veh_speed; } if (min_speed > max_veh_speed) { extra_cost += YAPF_TILE_LENGTH * (min_speed - max_veh_speed); } } /* Finish if we already exceeded the maximum path cost (i.e. when * searching for the nearest depot). */ if (m_max_cost > 0 && (parent_cost + segment_entry_cost + segment_cost) > m_max_cost) { end_segment_reason |= ESRB_PATH_TOO_LONG; } /* Move to the next tile/trackdir. */ tf = &tf_local; tf_local.Init(v, Yapf().GetCompatibleRailTypes(), &Yapf().m_perf_ts_cost); if (!tf_local.Follow(cur.tile, cur.td)) { assert(tf_local.m_err != TrackFollower::EC_NONE); /* Can't move to the next tile (EOL?). */ if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) { end_segment_reason |= ESRB_RAIL_TYPE; } else { end_segment_reason |= ESRB_DEAD_END; } if (TrackFollower::DoTrackMasking() && !HasOnewaySignalBlockingTrackdir(cur.tile, cur.td)) { end_segment_reason |= ESRB_SAFE_TILE; } break; } /* Check if the next tile is not a choice. */ if (KillFirstBit(tf_local.m_new_td_bits) != TRACKDIR_BIT_NONE) { /* More than one segment will follow. Close this one. */ end_segment_reason |= ESRB_CHOICE_FOLLOWS; break; } /* Gather the next tile/trackdir/tile_type/rail_type. */ TILE next(tf_local.m_new_tile, (Trackdir)FindFirstBit2x64(tf_local.m_new_td_bits)); if (TrackFollower::DoTrackMasking() && IsTileType(next.tile, MP_RAILWAY)) { if (HasSignalOnTrackdir(next.tile, next.td) && IsPbsSignal(GetSignalType(next.tile, TrackdirToTrack(next.td)))) { /* Possible safe tile. */ end_segment_reason |= ESRB_SAFE_TILE; } else if (HasSignalOnTrackdir(next.tile, ReverseTrackdir(next.td)) && GetSignalType(next.tile, TrackdirToTrack(next.td)) == SIGTYPE_PBS_ONEWAY) { /* Possible safe tile, but not so good as it's the back of a signal... */ end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END; extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty; } } /* Check the next tile for the rail type. */ if (next.rail_type != cur.rail_type) { /* Segment must consist from the same rail_type tiles. */ end_segment_reason |= ESRB_RAIL_TYPE; break; } /* Avoid infinite looping. */ if (next.tile == n.m_key.m_tile && next.td == n.m_key.m_td) { end_segment_reason |= ESRB_INFINITE_LOOP; break; } if (segment_cost > s_max_segment_cost) { /* Potentially in the infinite loop (or only very long segment?). We should * not force it to finish prematurely unless we are on a regular tile. */ if (IsTileType(tf->m_new_tile, MP_RAILWAY)) { end_segment_reason |= ESRB_SEGMENT_TOO_LONG; break; } } /* Any other reason bit set? */ if (end_segment_reason != ESRB_NONE) { break; } /* For the next loop set new prev and cur tile info. */ prev = cur; cur = next; } // for (;;) bool target_seen = false; if ((end_segment_reason & ESRB_POSSIBLE_TARGET) != ESRB_NONE) { /* Depot, station or waypoint. */ if (Yapf().PfDetectDestination(cur.tile, cur.td)) { /* Destination found. */ target_seen = true; } } /* Update the segment if needed. */ if (!is_cached_segment) { /* Write back the segment information so it can be reused the next time. */ segment.m_cost = segment_cost; segment.m_end_segment_reason = end_segment_reason & ESRB_CACHED_MASK; /* Save end of segment back to the node. */ n.SetLastTileTrackdir(cur.tile, cur.td); } /* Do we have an excuse why not to continue pathfinding in this direction? */ if (!target_seen && (end_segment_reason & ESRB_ABORT_PF_MASK) != ESRB_NONE) { /* Reason to not continue. Stop this PF branch. */ return false; } /* Special costs for the case we have reached our target. */ if (target_seen) { n.flags_u.flags_s.m_targed_seen = true; /* Last-red and last-red-exit penalties. */ if (n.flags_u.flags_s.m_last_signal_was_red) { if (n.m_last_red_signal_type == SIGTYPE_EXIT) { /* last signal was red pre-signal-exit */ extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty; } else if (!IsPbsSignal(n.m_last_red_signal_type)) { /* Last signal was red, but not exit or path signal. */ extra_cost += Yapf().PfGetSettings().rail_lastred_penalty; } } /* Station platform-length penalty. */ if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) { const BaseStation *st = BaseStation::GetByTile(n.GetLastTile()); assert(st != NULL); uint platform_length = st->GetPlatformLength(n.GetLastTile(), ReverseDiagDir(TrackdirToExitdir(n.GetLastTrackdir()))); /* Reduce the extra cost caused by passing-station penalty (each station receives it in the segment cost). */ extra_cost -= Yapf().PfGetSettings().rail_station_penalty * platform_length; /* Add penalty for the inappropriate platform length. */ extra_cost += PlatformLengthPenalty(platform_length); } } /* total node cost */ n.m_cost = parent_cost + segment_entry_cost + segment_cost + extra_cost; return true; } inline bool CanUseGlobalCache(Node& n) const { return !m_disable_cache && (n.m_parent != NULL) && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.Size()); } inline void ConnectNodeToCachedData(Node& n, CachedData& ci) { n.m_segment = &ci; if (n.m_segment->m_cost < 0) { n.m_segment->m_last_tile = n.m_key.m_tile; n.m_segment->m_last_td = n.m_key.m_td; } } void DisableCache(bool disable) { m_disable_cache = disable; } }; #endif /* YAPF_COSTRAIL_HPP */ openttd-1.5.3/src/pathfinder/npf/0000755000000000000000000000000012627373445015406 5ustar rootrootopenttd-1.5.3/src/pathfinder/npf/npf_func.h0000644000000000000000000001216012627373445017355 0ustar rootroot/* $Id: npf_func.h 24481 2012-08-18 11:37:47Z frosch $ */ /* * 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 npf_func.h Functions to access the new pathfinder. */ #ifndef NPF_FUNC_H #define NPF_FUNC_H #include "../../track_type.h" #include "../../direction_type.h" #include "../../vehicle_type.h" #include "../pathfinder_type.h" /** * Used when user sends road vehicle to the nearest depot or if road vehicle needs servicing using NPF. * @param v vehicle that needs to go to some depot * @param max_penalty max distance (in pathfinder penalty) from the current vehicle position * (used also as optimization - the pathfinder can stop path finding if max_penalty * was reached and no depot was seen) * @return the data about the depot */ FindDepotData NPFRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penalty); /** * Finds the best path for given road vehicle using NPF. * @param v the RV that needs to find a path * @param tile the tile to find the path from (should be next tile the RV is about to enter) * @param enterdir diagonal direction which the RV will enter this new tile from * @param trackdirs available trackdirs on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @return the best trackdir for next turn or INVALID_TRACKDIR if the path could not be found */ Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found); /** * Finds the best path for given ship using NPF. * @param v the ship that needs to find a path * @param tile the tile to find the path from (should be next tile the ship is about to enter) * @param enterdir diagonal direction which the ship will enter this new tile from * @param tracks available tracks on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @return the best trackdir for next turn or INVALID_TRACK if the path could not be found */ Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found); /** * Returns true if it is better to reverse the ship before leaving depot using NPF. * @param v the ship leaving the depot * @return true if reversing is better */ bool NPFShipCheckReverse(const Ship *v); /** * Used when user sends train to the nearest depot or if train needs servicing using NPF * @param v train that needs to go to some depot * @param max_penalty max max_penalty (in pathfinder penalty) from the current train position * (used also as optimization - the pathfinder can stop path finding if max_penalty * was reached and no depot was seen) * @return the data about the depot */ FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty); /** * Try to extend the reserved path of a train to the nearest safe tile using NPF. * * @param v The train that needs to find a safe tile. * @param tile Last tile of the current reserved path. * @param td Last trackdir of the current reserved path. * @param override_railtype Should all physically compatible railtypes be searched, even if the vehicle can't run on them on its own? * @return True if the path could be extended to a safe tile. */ bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir td, bool override_railtype); /** * Returns true if it is better to reverse the train before leaving station using NPF. * @param v the train leaving the station * @return true if reversing is better */ bool NPFTrainCheckReverse(const Train *v); /** * Finds the best path for given train using NPF. * @param v the train that needs to find a path * @param tile the tile to find the path from (should be next tile the train is about to enter) * @param enterdir diagonal direction which the RV will enter this new tile from * @param tracks available trackdirs on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @param reserve_track indicates whether YAPF should try to reserve the found path * @param target [out] the target tile of the reservation, free is set to true if path was reserved * @return the best track for next turn */ Track NPFTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, struct PBSTileInfo *target); #endif /* NPF_FUNC_H */ openttd-1.5.3/src/pathfinder/npf/queue.h0000644000000000000000000000547612627373445016717 0ustar rootroot/* $Id: queue.h 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 queue.h Binary heap implementation, hash implementation. */ #ifndef QUEUE_H #define QUEUE_H //#define HASH_STATS struct BinaryHeapNode { void *item; int priority; }; /** * Binary Heap. * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm */ struct BinaryHeap { static const int BINARY_HEAP_BLOCKSIZE; static const int BINARY_HEAP_BLOCKSIZE_BITS; static const int BINARY_HEAP_BLOCKSIZE_MASK; void Init(uint max_size); bool Push(void *item, int priority); void *Pop(); bool Delete(void *item, int priority); void Clear(bool free_values); void Free(bool free_values); /** * Get an element from the #elements. * @param i Element to access (starts at offset \c 1). * @return Value of the element. */ inline BinaryHeapNode &GetElement(uint i) { assert(i > 0); return this->elements[(i - 1) >> BINARY_HEAP_BLOCKSIZE_BITS][(i - 1) & BINARY_HEAP_BLOCKSIZE_MASK]; } uint max_size; uint size; uint blocks; ///< The amount of blocks for which space is reserved in elements BinaryHeapNode **elements; }; /* * Hash */ struct HashNode { uint key1; uint key2; void *value; HashNode *next; }; /** * Generates a hash code from the given key pair. You should make sure that * the resulting range is clearly defined. */ typedef uint Hash_HashProc(uint key1, uint key2); struct Hash { /* The hash function used */ Hash_HashProc *hash; /* The amount of items in the hash */ uint size; /* The number of buckets allocated */ uint num_buckets; /* A pointer to an array of num_buckets buckets. */ HashNode *buckets; /* A pointer to an array of numbuckets booleans, which will be true if * there are any Nodes in the bucket */ bool *buckets_in_use; void Init(Hash_HashProc *hash, uint num_buckets); void *Get(uint key1, uint key2) const; void *Set(uint key1, uint key2, void *value); void *DeleteValue(uint key1, uint key2); void Clear(bool free_values); void Delete(bool free_values); /** * Gets the current size of the hash. */ inline uint GetSize() const { return this->size; } protected: #ifdef HASH_STATS void PrintStatistics() const; #endif HashNode *FindNode(uint key1, uint key2, HashNode** prev_out) const; }; #endif /* QUEUE_H */ openttd-1.5.3/src/pathfinder/npf/aystar.cpp0000644000000000000000000002417712627373445017430 0ustar rootroot/* $Id: aystar.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 aystar.cpp Implementation of A*. * * This file has the core function for %AyStar. * %AyStar is a fast path finding routine and is used for things like AI path finding and Train path finding. * For more information about %AyStar (A* Algorithm), you can look at *
http://en.wikipedia.org/wiki/A-star_search_algorithm. */ /* * Friendly reminder: * Call (AyStar).free() when you are done with Aystar. It reserves a lot of memory * And when not free'd, it can cause system-crashes. * Also remember that when you stop an algorithm before it is finished, your * should call clear() yourself! */ #include "../../stdafx.h" #include "../../core/alloc_func.hpp" #include "aystar.h" #include "../../safeguards.h" /** * This looks in the hash whether a node exists in the closed list. * @param node Node to search. * @return The #PathNode if it is available, else \c NULL */ PathNode *AyStar::ClosedListIsInList(const AyStarNode *node) { return (PathNode*)this->closedlist_hash.Get(node->tile, node->direction); } /** * This adds a node to the closed list. * It makes a copy of the data. * @param node Node to add to the closed list. */ void AyStar::ClosedListAdd(const PathNode *node) { /* Add a node to the ClosedList */ PathNode *new_node = MallocT(1); *new_node = *node; this->closedlist_hash.Set(node->node.tile, node->node.direction, new_node); } /** * Check whether a node is in the open list. * @param node Node to search. * @return If the node is available, it is returned, else \c NULL is returned. */ OpenListNode *AyStar::OpenListIsInList(const AyStarNode *node) { return (OpenListNode*)this->openlist_hash.Get(node->tile, node->direction); } /** * Gets the best node from the open list. * It deletes the returned node from the open list. * @returns the best node available, or \c NULL of none is found. */ OpenListNode *AyStar::OpenListPop() { /* Return the item the Queue returns.. the best next OpenList item. */ OpenListNode *res = (OpenListNode*)this->openlist_queue.Pop(); if (res != NULL) { this->openlist_hash.DeleteValue(res->path.node.tile, res->path.node.direction); } return res; } /** * Adds a node to the open list. * It makes a copy of node, and puts the pointer of parent in the struct. */ void AyStar::OpenListAdd(PathNode *parent, const AyStarNode *node, int f, int g) { /* Add a new Node to the OpenList */ OpenListNode *new_node = MallocT(1); new_node->g = g; new_node->path.parent = parent; new_node->path.node = *node; this->openlist_hash.Set(node->tile, node->direction, new_node); /* Add it to the queue */ this->openlist_queue.Push(new_node, f); } /** * Checks one tile and calculate its f-value */ void AyStar::CheckTile(AyStarNode *current, OpenListNode *parent) { int new_f, new_g, new_h; PathNode *closedlist_parent; OpenListNode *check; /* Check the new node against the ClosedList */ if (this->ClosedListIsInList(current) != NULL) return; /* Calculate the G-value for this node */ new_g = this->CalculateG(this, current, parent); /* If the value was INVALID_NODE, we don't do anything with this node */ if (new_g == AYSTAR_INVALID_NODE) return; /* There should not be given any other error-code.. */ assert(new_g >= 0); /* Add the parent g-value to the new g-value */ new_g += parent->g; if (this->max_path_cost != 0 && (uint)new_g > this->max_path_cost) return; /* Calculate the h-value */ new_h = this->CalculateH(this, current, parent); /* There should not be given any error-code.. */ assert(new_h >= 0); /* The f-value if g + h */ new_f = new_g + new_h; /* Get the pointer to the parent in the ClosedList (the current one is to a copy of the one in the OpenList) */ closedlist_parent = this->ClosedListIsInList(&parent->path.node); /* Check if this item is already in the OpenList */ check = this->OpenListIsInList(current); if (check != NULL) { uint i; /* Yes, check if this g value is lower.. */ if (new_g > check->g) return; this->openlist_queue.Delete(check, 0); /* It is lower, so change it to this item */ check->g = new_g; check->path.parent = closedlist_parent; /* Copy user data, will probably have changed */ for (i = 0; i < lengthof(current->user_data); i++) { check->path.node.user_data[i] = current->user_data[i]; } /* Re-add it in the openlist_queue. */ this->openlist_queue.Push(check, new_f); } else { /* A new node, add him to the OpenList */ this->OpenListAdd(closedlist_parent, current, new_f, new_g); } } /** * This function is the core of %AyStar. It handles one item and checks * his neighbour items. If they are valid, they are added to be checked too. * @return Possible values: * - #AYSTAR_EMPTY_OPENLIST : indicates all items are tested, and no path has been found. * - #AYSTAR_LIMIT_REACHED : Indicates that the max_nodes limit has been reached. * - #AYSTAR_FOUND_END_NODE : indicates we found the end. Path_found now is true, and in path is the path found. * - #AYSTAR_STILL_BUSY : indicates we have done this tile, did not found the path yet, and have items left to try. */ int AyStar::Loop() { int i; /* Get the best node from OpenList */ OpenListNode *current = this->OpenListPop(); /* If empty, drop an error */ if (current == NULL) return AYSTAR_EMPTY_OPENLIST; /* Check for end node and if found, return that code */ if (this->EndNodeCheck(this, current) == AYSTAR_FOUND_END_NODE) { if (this->FoundEndNode != NULL) { this->FoundEndNode(this, current); } free(current); return AYSTAR_FOUND_END_NODE; } /* Add the node to the ClosedList */ this->ClosedListAdd(¤t->path); /* Load the neighbours */ this->GetNeighbours(this, current); /* Go through all neighbours */ for (i = 0; i < this->num_neighbours; i++) { /* Check and add them to the OpenList if needed */ this->CheckTile(&this->neighbours[i], current); } /* Free the node */ free(current); if (this->max_search_nodes != 0 && this->closedlist_hash.GetSize() >= this->max_search_nodes) { /* We've expanded enough nodes */ return AYSTAR_LIMIT_REACHED; } else { /* Return that we are still busy */ return AYSTAR_STILL_BUSY; } } /** * This function frees the memory it allocated */ void AyStar::Free() { this->openlist_queue.Free(false); /* 2nd argument above is false, below is true, to free the values only * once */ this->openlist_hash.Delete(true); this->closedlist_hash.Delete(true); #ifdef AYSTAR_DEBUG printf("[AyStar] Memory free'd\n"); #endif } /** * This function make the memory go back to zero. * This function should be called when you are using the same instance again. */ void AyStar::Clear() { /* Clean the Queue, but not the elements within. That will be done by * the hash. */ this->openlist_queue.Clear(false); /* Clean the hashes */ this->openlist_hash.Clear(true); this->closedlist_hash.Clear(true); #ifdef AYSTAR_DEBUG printf("[AyStar] Cleared AyStar\n"); #endif } /** * This is the function you call to run AyStar. * @return Possible values: * - #AYSTAR_FOUND_END_NODE : indicates we found an end node. * - #AYSTAR_NO_PATH : indicates that there was no path found. * - #AYSTAR_STILL_BUSY : indicates we have done some checked, that we did not found the path yet, and that we still have items left to try. * @note When the algorithm is done (when the return value is not #AYSTAR_STILL_BUSY) #Clear() is called automatically. * When you stop the algorithm halfway, you should call #Clear() yourself! */ int AyStar::Main() { int r, i = 0; /* Loop through the OpenList * Quit if result is no AYSTAR_STILL_BUSY or is more than loops_per_tick */ while ((r = this->Loop()) == AYSTAR_STILL_BUSY && (this->loops_per_tick == 0 || ++i < this->loops_per_tick)) { } #ifdef AYSTAR_DEBUG switch (r) { case AYSTAR_FOUND_END_NODE: printf("[AyStar] Found path!\n"); break; case AYSTAR_EMPTY_OPENLIST: printf("[AyStar] OpenList run dry, no path found\n"); break; case AYSTAR_LIMIT_REACHED: printf("[AyStar] Exceeded search_nodes, no path found\n"); break; default: break; } #endif if (r != AYSTAR_STILL_BUSY) { /* We're done, clean up */ this->Clear(); } switch (r) { case AYSTAR_FOUND_END_NODE: return AYSTAR_FOUND_END_NODE; case AYSTAR_EMPTY_OPENLIST: case AYSTAR_LIMIT_REACHED: return AYSTAR_NO_PATH; default: return AYSTAR_STILL_BUSY; } } /** * Adds a node from where to start an algorithm. Multiple nodes can be added * if wanted. You should make sure that #Clear() is called before adding nodes * if the #AyStar has been used before (though the normal main loop calls * #Clear() automatically when the algorithm finishes. * @param start_node Node to start with. * @param g the cost for starting with this node. */ void AyStar::AddStartNode(AyStarNode *start_node, uint g) { #ifdef AYSTAR_DEBUG printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n", TileX(start_node->tile), TileY(start_node->tile), start_node->direction); #endif this->OpenListAdd(NULL, start_node, 0, g); } /** * Initialize an #AyStar. You should fill all appropriate fields before * calling #Init (see the declaration of #AyStar for which fields are internal). */ void AyStar::Init(Hash_HashProc hash, uint num_buckets) { /* Allocated the Hash for the OpenList and ClosedList */ this->openlist_hash.Init(hash, num_buckets); this->closedlist_hash.Init(hash, num_buckets); /* Set up our sorting queue * BinaryHeap allocates a block of 1024 nodes * When that one gets full it reserves another one, till this number * That is why it can stay this high */ this->openlist_queue.Init(102400); } openttd-1.5.3/src/pathfinder/npf/aystar.h0000644000000000000000000001527012627373445017067 0ustar rootroot/* $Id: aystar.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 aystar.h * This file has the header for %AyStar. * %AyStar is a fast path finding routine and is used for things like AI path finding and Train path finding. * For more information about AyStar (A* Algorithm), you can look at * http://en.wikipedia.org/wiki/A-star_search_algorithm. */ #ifndef AYSTAR_H #define AYSTAR_H #include "queue.h" #include "../../tile_type.h" #include "../../track_type.h" //#define AYSTAR_DEBUG /** Return status of #AyStar methods. */ enum AystarStatus { AYSTAR_FOUND_END_NODE, ///< An end node was found. AYSTAR_EMPTY_OPENLIST, ///< All items are tested, and no path has been found. AYSTAR_STILL_BUSY, ///< Some checking was done, but no path found yet, and there are still items left to try. AYSTAR_NO_PATH, ///< No path to the goal was found. AYSTAR_LIMIT_REACHED, ///< The #max_nodes limit has been reached, aborting search. AYSTAR_DONE, ///< Not an end-tile, or wrong direction. }; static const int AYSTAR_INVALID_NODE = -1; ///< Item is not valid (for example, not walkable). /** Node in the search. */ struct AyStarNode { TileIndex tile; Trackdir direction; uint user_data[2]; }; /** A path of nodes. */ struct PathNode { AyStarNode node; PathNode *parent; ///< The parent of this item. }; /** * Internal node. * @note We do not save the h-value, because it is only needed to calculate the f-value. * h-value should \em always be the distance left to the end-tile. */ struct OpenListNode { int g; PathNode path; }; struct AyStar; /** * Check whether the end-tile is found. * @param aystar %AyStar search algorithm data. * @param current Node to exam one. * @note The 2nd parameter should be #OpenListNode, and \em not #AyStarNode. #AyStarNode is * part of #OpenListNode and so it could be accessed without any problems. * The good part about #OpenListNode is, and how AIs use it, that you can * access the parent of the current node, and so check if you, for example * don't try to enter the file tile with a 90-degree curve. So please, leave * this an #OpenListNode, it works just fine. * @return Status of the node: * - #AYSTAR_FOUND_END_NODE : indicates this is the end tile * - #AYSTAR_DONE : indicates this is not the end tile (or direction was wrong) */ typedef int32 AyStar_EndNodeCheck(AyStar *aystar, OpenListNode *current); /** * Calculate the G-value for the %AyStar algorithm. * @return G value of the node: * - #AYSTAR_INVALID_NODE : indicates an item is not valid (e.g.: unwalkable) * - Any value >= 0 : the g-value for this tile */ typedef int32 AyStar_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent); /** * Calculate the H-value for the %AyStar algorithm. * Mostly, this must return the distance (Manhattan way) between the current point and the end point. * @return The h-value for this tile (any value >= 0) */ typedef int32 AyStar_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent); /** * This function requests the tiles around the current tile and put them in #tiles_around. * #tiles_around is never reset, so if you are not using directions, just leave it alone. * \warning Never add more tiles_around than memory allocated for it. */ typedef void AyStar_GetNeighbours(AyStar *aystar, OpenListNode *current); /** * If the End Node is found, this function is called. * It can do, for example, calculate the route and put that in an array. */ typedef void AyStar_FoundEndNode(AyStar *aystar, OpenListNode *current); /** * %AyStar search algorithm struct. * Before calling #Init(), fill #CalculateG, #CalculateH, #GetNeighbours, #EndNodeCheck, and #FoundEndNode. * If you want to change them after calling #Init(), first call #Free() ! * * The #user_path, #user_target, and #user_data[10] are intended to be used by the user routines. The data not accessed by the #AyStar code itself. * The user routines can change any moment they like. */ struct AyStar { /* These fields should be filled before initing the AyStar, but not changed * afterwards (except for user_data and user_path)! (free and init again to change them) */ /* These should point to the application specific routines that do the * actual work */ AyStar_CalculateG *CalculateG; AyStar_CalculateH *CalculateH; AyStar_GetNeighbours *GetNeighbours; AyStar_EndNodeCheck *EndNodeCheck; AyStar_FoundEndNode *FoundEndNode; /* These are completely untouched by AyStar, they can be accessed by * the application specific routines to input and output data. * user_path should typically contain data about the resulting path * afterwards, user_target should typically contain information about * what you where looking for, and user_data can contain just about * everything */ void *user_path; void *user_target; uint user_data[10]; byte loops_per_tick; ///< How many loops are there called before Main() gives control back to the caller. 0 = until done. uint max_path_cost; ///< If the g-value goes over this number, it stops searching, 0 = infinite. uint max_search_nodes; ///< The maximum number of nodes that will be expanded, 0 = infinite. /* These should be filled with the neighbours of a tile by * GetNeighbours */ AyStarNode neighbours[12]; byte num_neighbours; void Init(Hash_HashProc hash, uint num_buckets); /* These will contain the methods for manipulating the AyStar. Only * Main() should be called externally */ void AddStartNode(AyStarNode *start_node, uint g); int Main(); int Loop(); void Free(); void Clear(); void CheckTile(AyStarNode *current, OpenListNode *parent); protected: Hash closedlist_hash; ///< The actual closed list. BinaryHeap openlist_queue; ///< The open queue. Hash openlist_hash; ///< An extra hash to speed up the process of looking up an element in the open list. void OpenListAdd(PathNode *parent, const AyStarNode *node, int f, int g); OpenListNode *OpenListIsInList(const AyStarNode *node); OpenListNode *OpenListPop(); void ClosedListAdd(const PathNode *node); PathNode *ClosedListIsInList(const AyStarNode *node); }; #endif /* AYSTAR_H */ openttd-1.5.3/src/pathfinder/npf/queue.cpp0000644000000000000000000003230212627373445017236 0ustar rootroot/* $Id: queue.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 queue.cpp Implementation of the #BinaryHeap/#Hash. */ #include "../../stdafx.h" #include "../../core/alloc_func.hpp" #include "queue.h" #include "../../safeguards.h" /* * Binary Heap * For information, see: http://www.policyalmanac.org/games/binaryHeaps.htm */ const int BinaryHeap::BINARY_HEAP_BLOCKSIZE_BITS = 10; ///< The number of elements that will be malloc'd at a time. const int BinaryHeap::BINARY_HEAP_BLOCKSIZE = 1 << BinaryHeap::BINARY_HEAP_BLOCKSIZE_BITS; const int BinaryHeap::BINARY_HEAP_BLOCKSIZE_MASK = BinaryHeap::BINARY_HEAP_BLOCKSIZE - 1; /** * Clears the queue, by removing all values from it. Its state is * effectively reset. If free_items is true, each of the items cleared * in this way are free()'d. */ void BinaryHeap::Clear(bool free_values) { /* Free all items if needed and free all but the first blocks of memory */ uint i; uint j; for (i = 0; i < this->blocks; i++) { if (this->elements[i] == NULL) { /* No more allocated blocks */ break; } /* For every allocated block */ if (free_values) { for (j = 0; j < (1 << BINARY_HEAP_BLOCKSIZE_BITS); j++) { /* For every element in the block */ if ((this->size >> BINARY_HEAP_BLOCKSIZE_BITS) == i && (this->size & BINARY_HEAP_BLOCKSIZE_MASK) == j) { break; // We're past the last element } free(this->elements[i][j].item); } } if (i != 0) { /* Leave the first block of memory alone */ free(this->elements[i]); this->elements[i] = NULL; } } this->size = 0; this->blocks = 1; } /** * Frees the queue, by reclaiming all memory allocated by it. After * this it is no longer usable. If free_items is true, any remaining * items are free()'d too. */ void BinaryHeap::Free(bool free_values) { uint i; this->Clear(free_values); for (i = 0; i < this->blocks; i++) { if (this->elements[i] == NULL) break; free(this->elements[i]); } free(this->elements); } /** * Pushes an element into the queue, at the appropriate place for the queue. * Requires the queue pointer to be of an appropriate type, of course. */ bool BinaryHeap::Push(void *item, int priority) { if (this->size == this->max_size) return false; assert(this->size < this->max_size); if (this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] == NULL) { /* The currently allocated blocks are full, allocate a new one */ assert((this->size & BINARY_HEAP_BLOCKSIZE_MASK) == 0); this->elements[this->size >> BINARY_HEAP_BLOCKSIZE_BITS] = MallocT(BINARY_HEAP_BLOCKSIZE); this->blocks++; } /* Add the item at the end of the array */ this->GetElement(this->size + 1).priority = priority; this->GetElement(this->size + 1).item = item; this->size++; /* Now we are going to check where it belongs. As long as the parent is * bigger, we switch with the parent */ { BinaryHeapNode temp; int i; int j; i = this->size; while (i > 1) { /* Get the parent of this object (divide by 2) */ j = i / 2; /* Is the parent bigger than the current, switch them */ if (this->GetElement(i).priority <= this->GetElement(j).priority) { temp = this->GetElement(j); this->GetElement(j) = this->GetElement(i); this->GetElement(i) = temp; i = j; } else { /* It is not, we're done! */ break; } } } return true; } /** * Deletes the item from the queue. priority should be specified if * known, which speeds up the deleting for some queue's. Should be -1 * if not known. */ bool BinaryHeap::Delete(void *item, int priority) { uint i = 0; /* First, we try to find the item.. */ do { if (this->GetElement(i + 1).item == item) break; i++; } while (i < this->size); /* We did not find the item, so we return false */ if (i == this->size) return false; /* Now we put the last item over the current item while decreasing the size of the elements */ this->size--; this->GetElement(i + 1) = this->GetElement(this->size + 1); /* Now the only thing we have to do, is resort it.. * On place i there is the item to be sorted.. let's start there */ { uint j; BinaryHeapNode temp; /* Because of the fact that Binary Heap uses array from 1 to n, we need to * increase i by 1 */ i++; for (;;) { j = i; /* Check if we have 2 children */ if (2 * j + 1 <= this->size) { /* Is this child smaller than the parent? */ if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j; /* Yes, we _need_ to use i here, not j, because we want to have the smallest child * This way we get that straight away! */ if (this->GetElement(i).priority >= this->GetElement(2 * j + 1).priority) i = 2 * j + 1; /* Do we have one child? */ } else if (2 * j <= this->size) { if (this->GetElement(j).priority >= this->GetElement(2 * j).priority) i = 2 * j; } /* One of our children is smaller than we are, switch */ if (i != j) { temp = this->GetElement(j); this->GetElement(j) = this->GetElement(i); this->GetElement(i) = temp; } else { /* None of our children is smaller, so we stay here.. stop :) */ break; } } } return true; } /** * Pops the first element from the queue. What exactly is the first element, * is defined by the exact type of queue. */ void *BinaryHeap::Pop() { void *result; if (this->size == 0) return NULL; /* The best item is always on top, so give that as result */ result = this->GetElement(1).item; /* And now we should get rid of this item... */ this->Delete(this->GetElement(1).item, this->GetElement(1).priority); return result; } /** * Initializes a binary heap and allocates internal memory for maximum of * max_size elements */ void BinaryHeap::Init(uint max_size) { this->max_size = max_size; this->size = 0; /* We malloc memory in block of BINARY_HEAP_BLOCKSIZE * It autosizes when it runs out of memory */ this->elements = CallocT((max_size - 1) / BINARY_HEAP_BLOCKSIZE + 1); this->elements[0] = MallocT(BINARY_HEAP_BLOCKSIZE); this->blocks = 1; } /* Because we don't want anyone else to bother with our defines */ #undef BIN_HEAP_ARR /* * Hash */ /** * Builds a new hash in an existing struct. Make sure that hash() always * returns a hash less than num_buckets! Call delete_hash after use */ void Hash::Init(Hash_HashProc *hash, uint num_buckets) { /* Allocate space for the Hash, the buckets and the bucket flags */ uint i; /* Ensure the size won't overflow. */ CheckAllocationConstraints(sizeof(*this->buckets) + sizeof(*this->buckets_in_use), num_buckets); this->hash = hash; this->size = 0; this->num_buckets = num_buckets; this->buckets = (HashNode*)MallocT(num_buckets * (sizeof(*this->buckets) + sizeof(*this->buckets_in_use))); this->buckets_in_use = (bool*)(this->buckets + num_buckets); for (i = 0; i < num_buckets; i++) this->buckets_in_use[i] = false; } /** * Deletes the hash and cleans up. Only cleans up memory allocated by new_Hash * & friends. If free is true, it will call free() on all the values that * are left in the hash. */ void Hash::Delete(bool free_values) { uint i; /* Iterate all buckets */ for (i = 0; i < this->num_buckets; i++) { if (this->buckets_in_use[i]) { HashNode *node; /* Free the first value */ if (free_values) free(this->buckets[i].value); node = this->buckets[i].next; while (node != NULL) { HashNode *prev = node; node = node->next; /* Free the value */ if (free_values) free(prev->value); /* Free the node */ free(prev); } } } free(this->buckets); /* No need to free buckets_in_use, it is always allocated in one * malloc with buckets */ } #ifdef HASH_STATS void Hash::PrintStatistics() const { uint used_buckets = 0; uint max_collision = 0; uint max_usage = 0; uint usage[200]; uint i; for (i = 0; i < lengthof(usage); i++) usage[i] = 0; for (i = 0; i < this->num_buckets; i++) { uint collision = 0; if (this->buckets_in_use[i]) { const HashNode *node; used_buckets++; for (node = &this->buckets[i]; node != NULL; node = node->next) collision++; if (collision > max_collision) max_collision = collision; } if (collision >= lengthof(usage)) collision = lengthof(usage) - 1; usage[collision]++; if (collision > 0 && usage[collision] >= max_usage) { max_usage = usage[collision]; } } printf( "---\n" "Hash size: %d\n" "Nodes used: %d\n" "Non empty buckets: %d\n" "Max collision: %d\n", this->num_buckets, this->size, used_buckets, max_collision ); printf("{ "); for (i = 0; i <= max_collision; i++) { if (usage[i] > 0) { printf("%d:%d ", i, usage[i]); #if 0 if (i > 0) { uint j; for (j = 0; j < usage[i] * 160 / 800; j++) putchar('#'); } printf("\n"); #endif } } printf ("}\n"); } #endif /** * Cleans the hash, but keeps the memory allocated */ void Hash::Clear(bool free_values) { uint i; #ifdef HASH_STATS if (this->size > 2000) this->PrintStatistics(); #endif /* Iterate all buckets */ for (i = 0; i < this->num_buckets; i++) { if (this->buckets_in_use[i]) { HashNode *node; this->buckets_in_use[i] = false; /* Free the first value */ if (free_values) free(this->buckets[i].value); node = this->buckets[i].next; while (node != NULL) { HashNode *prev = node; node = node->next; if (free_values) free(prev->value); free(prev); } } } this->size = 0; } /** * Finds the node that that saves this key pair. If it is not * found, returns NULL. If it is found, *prev is set to the * node before the one found, or if the node found was the first in the bucket * to NULL. If it is not found, *prev is set to the last HashNode in the * bucket, or NULL if it is empty. prev can also be NULL, in which case it is * not used for output. */ HashNode *Hash::FindNode(uint key1, uint key2, HashNode** prev_out) const { uint hash = this->hash(key1, key2); HashNode *result = NULL; /* Check if the bucket is empty */ if (!this->buckets_in_use[hash]) { if (prev_out != NULL) *prev_out = NULL; result = NULL; /* Check the first node specially */ } else if (this->buckets[hash].key1 == key1 && this->buckets[hash].key2 == key2) { /* Save the value */ result = this->buckets + hash; if (prev_out != NULL) *prev_out = NULL; /* Check all other nodes */ } else { HashNode *prev = this->buckets + hash; HashNode *node; for (node = prev->next; node != NULL; node = node->next) { if (node->key1 == key1 && node->key2 == key2) { /* Found it */ result = node; break; } prev = node; } if (prev_out != NULL) *prev_out = prev; } return result; } /** * Deletes the value with the specified key pair from the hash and returns * that value. Returns NULL when the value was not present. The value returned * is _not_ free()'d! */ void *Hash::DeleteValue(uint key1, uint key2) { void *result; HashNode *prev; // Used as output var for below function call HashNode *node = this->FindNode(key1, key2, &prev); if (node == NULL) { /* not found */ result = NULL; } else if (prev == NULL) { /* It is in the first node, we can't free that one, so we free * the next one instead (if there is any)*/ /* Save the value */ result = node->value; if (node->next != NULL) { HashNode *next = node->next; /* Copy the second to the first */ *node = *next; /* Free the second */ free(next); } else { /* This was the last in this bucket * Mark it as empty */ uint hash = this->hash(key1, key2); this->buckets_in_use[hash] = false; } } else { /* It is in another node * Save the value */ result = node->value; /* Link previous and next nodes */ prev->next = node->next; /* Free the node */ free(node); } if (result != NULL) this->size--; return result; } /** * Sets the value associated with the given key pair to the given value. * Returns the old value if the value was replaced, NULL when it was not yet present. */ void *Hash::Set(uint key1, uint key2, void *value) { HashNode *prev; HashNode *node = this->FindNode(key1, key2, &prev); if (node != NULL) { /* Found it */ void *result = node->value; node->value = value; return result; } /* It is not yet present, let's add it */ if (prev == NULL) { /* The bucket is still empty */ uint hash = this->hash(key1, key2); this->buckets_in_use[hash] = true; node = this->buckets + hash; } else { /* Add it after prev */ node = MallocT(1); prev->next = node; } node->next = NULL; node->key1 = key1; node->key2 = key2; node->value = value; this->size++; return NULL; } /** * Gets the value associated with the given key pair, or NULL when it is not * present. */ void *Hash::Get(uint key1, uint key2) const { HashNode *node = this->FindNode(key1, key2, NULL); return (node != NULL) ? node->value : NULL; } openttd-1.5.3/src/pathfinder/npf/npf.cpp0000644000000000000000000014515012627373445016703 0ustar rootroot/* $Id: npf.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 npf.cpp Implementation of the NPF pathfinder. */ #include "../../stdafx.h" #include "../../network/network.h" #include "../../viewport_func.h" #include "../../ship.h" #include "../../roadstop_base.h" #include "../pathfinder_func.h" #include "../pathfinder_type.h" #include "../follow_track.hpp" #include "aystar.h" #include "../../safeguards.h" static const uint NPF_HASH_BITS = 12; ///< The size of the hash used in pathfinding. Just changing this value should be sufficient to change the hash size. Should be an even value. /* Do no change below values */ static const uint NPF_HASH_SIZE = 1 << NPF_HASH_BITS; static const uint NPF_HASH_HALFBITS = NPF_HASH_BITS / 2; static const uint NPF_HASH_HALFMASK = (1 << NPF_HASH_HALFBITS) - 1; /** Meant to be stored in AyStar.targetdata */ struct NPFFindStationOrTileData { TileIndex dest_coords; ///< An indication of where the station is, for heuristic purposes, or the target tile StationID station_index; ///< station index we're heading for, or INVALID_STATION when we're heading for a tile bool reserve_path; ///< Indicates whether the found path should be reserved StationType station_type; ///< The type of station we're heading for bool not_articulated; ///< The (road) vehicle is not articulated const Vehicle *v; ///< The vehicle we are pathfinding for }; /** Indices into AyStar.userdata[] */ enum AyStarUserDataType { NPF_TYPE = 0, ///< Contains a TransportTypes value NPF_SUB_TYPE, ///< Contains the sub transport type NPF_OWNER, ///< Contains an Owner value NPF_RAILTYPES, ///< Contains a bitmask the compatible RailTypes of the engine when NPF_TYPE == TRANSPORT_RAIL. Unused otherwise. }; /** Indices into AyStarNode.userdata[] */ enum AyStarNodeUserDataType { NPF_TRACKDIR_CHOICE = 0, ///< The trackdir chosen to get here NPF_NODE_FLAGS, }; /** Flags for AyStarNode.userdata[NPF_NODE_FLAGS]. Use NPFSetFlag() and NPFGetFlag() to use them. */ enum NPFNodeFlag { NPF_FLAG_SEEN_SIGNAL, ///< Used to mark that a signal was seen on the way, for rail only NPF_FLAG_2ND_SIGNAL, ///< Used to mark that two signals were seen, rail only NPF_FLAG_3RD_SIGNAL, ///< Used to mark that three signals were seen, rail only NPF_FLAG_REVERSE, ///< Used to mark that this node was reached from the second start node, if applicable NPF_FLAG_LAST_SIGNAL_RED, ///< Used to mark that the last signal on this path was red NPF_FLAG_LAST_SIGNAL_BLOCK, ///< Used to mark that the last signal on this path was a block signal NPF_FLAG_IGNORE_START_TILE, ///< Used to mark that the start tile is invalid, and searching should start from the second tile on NPF_FLAG_TARGET_RESERVED, ///< Used to mark that the possible reservation target is already reserved NPF_FLAG_IGNORE_RESERVED, ///< Used to mark that reserved tiles should be considered impassable }; /** Meant to be stored in AyStar.userpath */ struct NPFFoundTargetData { uint best_bird_dist; ///< The best heuristic found. Is 0 if the target was found uint best_path_dist; ///< The shortest path. Is UINT_MAX if no path is found Trackdir best_trackdir; ///< The trackdir that leads to the shortest path/closest birds dist AyStarNode node; ///< The node within the target the search led us to bool res_okay; ///< True if a path reservation could be made }; static AyStar _npf_aystar; /* The cost of each trackdir. A diagonal piece is the full NPF_TILE_LENGTH, * the shorter piece is sqrt(2)/2*NPF_TILE_LENGTH =~ 0.7071 */ #define NPF_STRAIGHT_LENGTH (uint)(NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH) static const uint _trackdir_length[TRACKDIR_END] = { NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, 0, 0, NPF_TILE_LENGTH, NPF_TILE_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH, NPF_STRAIGHT_LENGTH }; /** * Returns the current value of the given flag on the given AyStarNode. */ static inline bool NPFGetFlag(const AyStarNode *node, NPFNodeFlag flag) { return HasBit(node->user_data[NPF_NODE_FLAGS], flag); } /** * Sets the given flag on the given AyStarNode to the given value. */ static inline void NPFSetFlag(AyStarNode *node, NPFNodeFlag flag, bool value) { SB(node->user_data[NPF_NODE_FLAGS], flag, 1, value); } /** * Calculates the minimum distance travelled to get from t0 to t1 when only * using tracks (ie, only making 45 degree turns). Returns the distance in the * NPF scale, ie the number of full tiles multiplied by NPF_TILE_LENGTH to * prevent rounding. */ static uint NPFDistanceTrack(TileIndex t0, TileIndex t1) { const uint dx = Delta(TileX(t0), TileX(t1)); const uint dy = Delta(TileY(t0), TileY(t1)); const uint straightTracks = 2 * min(dx, dy); // The number of straight (not full length) tracks /* OPTIMISATION: * Original: diagTracks = max(dx, dy) - min(dx,dy); * Proof: * (dx+dy) - straightTracks == (min + max) - straightTracks = min + max - 2 * min = max - min */ const uint diagTracks = dx + dy - straightTracks; // The number of diagonal (full tile length) tracks. /* Don't factor out NPF_TILE_LENGTH below, this will round values and lose * precision */ return diagTracks * NPF_TILE_LENGTH + straightTracks * NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH; } /** * Calculates a hash value for use in the NPF. * @param key1 The TileIndex of the tile to hash * @param key2 The Trackdir of the track on the tile. * * @todo Think of a better hash. */ static uint NPFHash(uint key1, uint key2) { /* TODO: think of a better hash? */ uint part1 = TileX(key1) & NPF_HASH_HALFMASK; uint part2 = TileY(key1) & NPF_HASH_HALFMASK; assert(IsValidTrackdir((Trackdir)key2)); assert(IsValidTile(key1)); return ((part1 << NPF_HASH_HALFBITS | part2) + (NPF_HASH_SIZE * key2 / TRACKDIR_END)) % NPF_HASH_SIZE; } static int32 NPFCalcZero(AyStar *as, AyStarNode *current, OpenListNode *parent) { return 0; } /* Calculates the heuristic to the target station or tile. For train stations, it * takes into account the direction of approach. */ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, OpenListNode *parent) { NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target; NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path; TileIndex from = current->tile; TileIndex to = fstd->dest_coords; uint dist; /* for train-stations, we are going to aim for the closest station tile */ if (as->user_data[NPF_TYPE] != TRANSPORT_WATER && fstd->station_index != INVALID_STATION) { to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type); } if (as->user_data[NPF_TYPE] == TRANSPORT_ROAD) { /* Since roads only have diagonal pieces, we use manhattan distance here */ dist = DistanceManhattan(from, to) * NPF_TILE_LENGTH; } else { /* Ships and trains can also go diagonal, so the minimum distance is shorter */ dist = NPFDistanceTrack(from, to); } DEBUG(npf, 4, "Calculating H for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), dist); if (dist < ftd->best_bird_dist) { ftd->best_bird_dist = dist; ftd->best_trackdir = (Trackdir)current->user_data[NPF_TRACKDIR_CHOICE]; } return dist; } /* Fills AyStarNode.user_data[NPF_TRACKDIRCHOICE] with the chosen direction to * get here, either getting it from the current choice or from the parent's * choice */ static void NPFFillTrackdirChoice(AyStarNode *current, OpenListNode *parent) { if (parent->path.parent == NULL) { Trackdir trackdir = current->direction; /* This is a first order decision, so we'd better save the * direction we chose */ current->user_data[NPF_TRACKDIR_CHOICE] = trackdir; DEBUG(npf, 6, "Saving trackdir: 0x%X", trackdir); } else { /* We've already made the decision, so just save our parent's decision */ current->user_data[NPF_TRACKDIR_CHOICE] = parent->path.node.user_data[NPF_TRACKDIR_CHOICE]; } } /* Will return the cost of the tunnel. If it is an entry, it will return the * cost of that tile. If the tile is an exit, it will return the tunnel length * including the exit tile. Requires that this is a Tunnel tile */ static uint NPFTunnelCost(AyStarNode *current) { DiagDirection exitdir = TrackdirToExitdir(current->direction); TileIndex tile = current->tile; if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) { /* We just popped out if this tunnel, since were * facing the tunnel exit */ return NPF_TILE_LENGTH * (GetTunnelBridgeLength(current->tile, GetOtherTunnelEnd(current->tile)) + 1); /* @todo: Penalty for tunnels? */ } else { /* We are entering the tunnel, the enter tile is just a * straight track */ return NPF_TILE_LENGTH; } } static inline uint NPFBridgeCost(AyStarNode *current) { return NPF_TILE_LENGTH * GetTunnelBridgeLength(current->tile, GetOtherBridgeEnd(current->tile)); } static uint NPFSlopeCost(AyStarNode *current) { TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction)); /* Get center of tiles */ int x1 = TileX(current->tile) * TILE_SIZE + TILE_SIZE / 2; int y1 = TileY(current->tile) * TILE_SIZE + TILE_SIZE / 2; int x2 = TileX(next) * TILE_SIZE + TILE_SIZE / 2; int y2 = TileY(next) * TILE_SIZE + TILE_SIZE / 2; int dx4 = (x2 - x1) / 4; int dy4 = (y2 - y1) / 4; /* Get the height on both sides of the tile edge. * Avoid testing the height on the tile-center. This will fail for halftile-foundations. */ int z1 = GetSlopePixelZ(x1 + dx4, y1 + dy4); int z2 = GetSlopePixelZ(x2 - dx4, y2 - dy4); if (z2 - z1 > 1) { /* Slope up */ return _settings_game.pf.npf.npf_rail_slope_penalty; } return 0; /* Should we give a bonus for slope down? Probably not, we * could just subtract that bonus from the penalty, because * there is only one level of steepness... */ } static uint NPFReservedTrackCost(AyStarNode *current) { TileIndex tile = current->tile; TrackBits track = TrackToTrackBits(TrackdirToTrack(current->direction)); TrackBits res = GetReservedTrackbits(tile); if (NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL) || NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK) || ((res & track) == TRACK_BIT_NONE && !TracksOverlap(res | track))) return 0; if (IsTileType(tile, MP_TUNNELBRIDGE)) { DiagDirection exitdir = TrackdirToExitdir(current->direction); if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(exitdir)) { return _settings_game.pf.npf.npf_rail_pbs_cross_penalty * (GetTunnelBridgeLength(tile, GetOtherTunnelBridgeEnd(tile)) + 1); } } return _settings_game.pf.npf.npf_rail_pbs_cross_penalty; } /** * Mark tiles by mowing the grass when npf debug level >= 1. * Will not work for multiplayer games, since it can (will) cause desyncs. */ static void NPFMarkTile(TileIndex tile) { #ifndef NO_DEBUG_MESSAGES if (_debug_npf_level < 1 || _networking) return; switch (GetTileType(tile)) { case MP_RAILWAY: /* DEBUG: mark visited tiles by mowing the grass under them ;-) */ if (!IsRailDepot(tile)) { SetRailGroundType(tile, RAIL_GROUND_BARREN); MarkTileDirtyByTile(tile); } break; case MP_ROAD: if (!IsRoadDepot(tile)) { SetRoadside(tile, ROADSIDE_BARREN); MarkTileDirtyByTile(tile); } break; default: break; } #endif } static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent) { /* TileIndex tile = current->tile; */ int32 cost = 0; Trackdir trackdir = current->direction; cost = _trackdir_length[trackdir]; // Should be different for diagonal tracks if (IsBuoyTile(current->tile) && IsDiagonalTrackdir(trackdir)) { cost += _settings_game.pf.npf.npf_buoy_penalty; // A small penalty for going over buoys } if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction)) { cost += _settings_game.pf.npf.npf_water_curve_penalty; } /* @todo More penalties? */ return cost; } /* Determine the cost of this node, for road tracks */ static int32 NPFRoadPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent) { TileIndex tile = current->tile; int32 cost = 0; /* Determine base length */ switch (GetTileType(tile)) { case MP_TUNNELBRIDGE: cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current); break; case MP_ROAD: cost = NPF_TILE_LENGTH; /* Increase the cost for level crossings */ if (IsLevelCrossing(tile)) cost += _settings_game.pf.npf.npf_crossing_penalty; break; case MP_STATION: { cost = NPF_TILE_LENGTH; const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile)); if (IsDriveThroughStopTile(tile)) { /* Increase the cost for drive-through road stops */ cost += _settings_game.pf.npf.npf_road_drive_through_penalty; DiagDirection dir = TrackdirToExitdir(current->direction); if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) { /* When we're the first road stop in a 'queue' of them we increase * cost based on the fill percentage of the whole queue. */ const RoadStop::Entry *entry = rs->GetEntry(dir); cost += entry->GetOccupied() * _settings_game.pf.npf.npf_road_dt_occupied_penalty / entry->GetLength(); } } else { /* Increase cost for filled road stops */ cost += _settings_game.pf.npf.npf_road_bay_occupied_penalty * (!rs->IsFreeBay(0) + !rs->IsFreeBay(1)) / 2; } break; } default: break; } /* Determine extra costs */ /* Check for slope */ cost += NPFSlopeCost(current); /* Check for turns. Road vehicles only really drive diagonal, turns are * represented by non-diagonal tracks */ if (!IsDiagonalTrackdir(current->direction)) { cost += _settings_game.pf.npf.npf_road_curve_penalty; } NPFMarkTile(tile); DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost); return cost; } /* Determine the cost of this node, for railway tracks */ static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent) { TileIndex tile = current->tile; Trackdir trackdir = current->direction; int32 cost = 0; /* HACK: We create a OpenListNode manually, so we can call EndNodeCheck */ OpenListNode new_node; /* Determine base length */ switch (GetTileType(tile)) { case MP_TUNNELBRIDGE: cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current); break; case MP_RAILWAY: cost = _trackdir_length[trackdir]; // Should be different for diagonal tracks break; case MP_ROAD: // Railway crossing cost = NPF_TILE_LENGTH; break; case MP_STATION: /* We give a station tile a penalty. Logically we would only want to give * station tiles that are not our destination this penalty. This would * discourage trains to drive through busy stations. But, we can just * give any station tile a penalty, because every possible route will get * this penalty exactly once, on its end tile (if it's a station) and it * will therefore not make a difference. */ cost = NPF_TILE_LENGTH + _settings_game.pf.npf.npf_rail_station_penalty; if (IsRailWaypoint(tile)) { NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target; if (fstd->v->current_order.IsType(OT_GOTO_WAYPOINT) && GetStationIndex(tile) == fstd->v->current_order.GetDestination()) { /* This waypoint is our destination; maybe this isn't an unreserved * one, so check that and if so see that as the last signal being * red. This way waypoints near stations should work better. */ const Train *train = Train::From(fstd->v); CFollowTrackRail ft(train); TileIndex t = tile; Trackdir td = trackdir; while (ft.Follow(t, td)) { assert(t != ft.m_new_tile); t = ft.m_new_tile; if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) { /* We encountered a junction; it's going to be too complex to * handle this perfectly, so just bail out. There is no simple * free path, so try the other possibilities. */ td = INVALID_TRACKDIR; break; } td = RemoveFirstTrackdir(&ft.m_new_td_bits); /* If this is a safe waiting position we're done searching for it */ if (IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg)) break; } if (td == INVALID_TRACKDIR || !IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg) || !IsWaitingPositionFree(train, t, td, _settings_game.pf.forbid_90_deg)) { cost += _settings_game.pf.npf.npf_rail_lastred_penalty; } } } break; default: break; } /* Determine extra costs */ /* Check for signals */ if (IsTileType(tile, MP_RAILWAY)) { if (HasSignalOnTrackdir(tile, trackdir)) { SignalType sigtype = GetSignalType(tile, TrackdirToTrack(trackdir)); /* Ordinary track with signals */ if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_RED) { /* Signal facing us is red */ if (!NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) { /* Penalize the first signal we * encounter, if it is red */ /* Is this a presignal exit or combo? */ if (!IsPbsSignal(sigtype)) { if (sigtype == SIGTYPE_EXIT || sigtype == SIGTYPE_COMBO) { /* Penalise exit and combo signals differently (heavier) */ cost += _settings_game.pf.npf.npf_rail_firstred_exit_penalty; } else { cost += _settings_game.pf.npf.npf_rail_firstred_penalty; } } } /* Record the state of this signal. Path signals are assumed to * be green as the signal state of them has no meaning for this. */ NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, !IsPbsSignal(sigtype)); } else { /* Record the state of this signal */ NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, false); } if (NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) { if (NPFGetFlag(current, NPF_FLAG_2ND_SIGNAL)) { NPFSetFlag(current, NPF_FLAG_3RD_SIGNAL, true); } else { NPFSetFlag(current, NPF_FLAG_2ND_SIGNAL, true); } } else { NPFSetFlag(current, NPF_FLAG_SEEN_SIGNAL, true); } NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK, !IsPbsSignal(sigtype)); } if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) { cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty; } } /* Penalise the tile if it is a target tile and the last signal was * red */ /* HACK: We create a new_node here so we can call EndNodeCheck. Ugly as hell * of course... */ new_node.path.node = *current; if (as->EndNodeCheck(as, &new_node) == AYSTAR_FOUND_END_NODE && NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_RED)) { cost += _settings_game.pf.npf.npf_rail_lastred_penalty; } /* Check for slope */ cost += NPFSlopeCost(current); /* Check for turns */ if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction)) { cost += _settings_game.pf.npf.npf_rail_curve_penalty; } /* TODO, with realistic acceleration, also the amount of straight track between * curves should be taken into account, as this affects the speed limit. */ /* Check for reverse in depot */ if (IsRailDepotTile(tile) && as->EndNodeCheck(as, &new_node) != AYSTAR_FOUND_END_NODE) { /* Penalise any depot tile that is not the last tile in the path. This * _should_ penalise every occurrence of reversing in a depot (and only * that) */ cost += _settings_game.pf.npf.npf_rail_depot_reverse_penalty; } /* Check for occupied track */ cost += NPFReservedTrackCost(current); NPFMarkTile(tile); DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost); return cost; } /* Will find any depot */ static int32 NPFFindDepot(AyStar *as, OpenListNode *current) { /* It's not worth caching the result with NPF_FLAG_IS_TARGET here as below, * since checking the cache not that much faster than the actual check */ return IsDepotTypeTile(current->path.node.tile, (TransportType)as->user_data[NPF_TYPE]) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE; } /** Find any safe and free tile. */ static int32 NPFFindSafeTile(AyStar *as, OpenListNode *current) { const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v); return (IsSafeWaitingPosition(v, current->path.node.tile, current->path.node.direction, true, _settings_game.pf.forbid_90_deg) && IsWaitingPositionFree(v, current->path.node.tile, current->path.node.direction, _settings_game.pf.forbid_90_deg)) ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE; } /* Will find a station identified using the NPFFindStationOrTileData */ static int32 NPFFindStationOrTile(AyStar *as, OpenListNode *current) { NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target; AyStarNode *node = ¤t->path.node; TileIndex tile = node->tile; if (fstd->station_index == INVALID_STATION && tile == fstd->dest_coords) return AYSTAR_FOUND_END_NODE; if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == fstd->station_index) { if (fstd->v->type == VEH_TRAIN) return AYSTAR_FOUND_END_NODE; assert(fstd->v->type == VEH_ROAD); /* Only if it is a valid station *and* we can stop there */ if (GetStationType(tile) == fstd->station_type && (fstd->not_articulated || IsDriveThroughStopTile(tile))) return AYSTAR_FOUND_END_NODE; } return AYSTAR_DONE; } /** * Find the node containing the first signal on the path. * * If the first signal is on the very first two tiles of the path, * the second signal is returned. If no suitable signal is present, the * last node of the path is returned. */ static const PathNode *FindSafePosition(PathNode *path, const Train *v) { /* If there is no signal, reserve the whole path. */ PathNode *sig = path; for (; path->parent != NULL; path = path->parent) { if (IsSafeWaitingPosition(v, path->node.tile, path->node.direction, true, _settings_game.pf.forbid_90_deg)) { sig = path; } } return sig; } /** * Lift the reservation of the tiles from @p start till @p end, excluding @p end itself. */ static void ClearPathReservation(const PathNode *start, const PathNode *end) { bool first_run = true; for (; start != end; start = start->parent) { if (IsRailStationTile(start->node.tile) && first_run) { SetRailStationPlatformReservation(start->node.tile, TrackdirToExitdir(start->node.direction), false); } else { UnreserveRailTrack(start->node.tile, TrackdirToTrack(start->node.direction)); } first_run = false; } } /** * To be called when @p current contains the (shortest route to) the target node. * Will fill the contents of the NPFFoundTargetData using * AyStarNode[NPF_TRACKDIR_CHOICE]. If requested, path reservation * is done here. */ static void NPFSaveTargetData(AyStar *as, OpenListNode *current) { NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path; ftd->best_trackdir = (Trackdir)current->path.node.user_data[NPF_TRACKDIR_CHOICE]; ftd->best_path_dist = current->g; ftd->best_bird_dist = 0; ftd->node = current->path.node; ftd->res_okay = false; if (as->user_target != NULL && ((NPFFindStationOrTileData*)as->user_target)->reserve_path && as->user_data[NPF_TYPE] == TRANSPORT_RAIL) { /* Path reservation is requested. */ const Train *v = Train::From(((NPFFindStationOrTileData *)as->user_target)->v); const PathNode *target = FindSafePosition(¤t->path, v); ftd->node = target->node; /* If the target is a station skip to platform end. */ if (IsRailStationTile(target->node.tile)) { DiagDirection dir = TrackdirToExitdir(target->node.direction); uint len = Station::GetByTile(target->node.tile)->GetPlatformLength(target->node.tile, dir); TileIndex end_tile = TILE_ADD(target->node.tile, (len - 1) * TileOffsByDiagDir(dir)); /* Update only end tile, trackdir of a station stays the same. */ ftd->node.tile = end_tile; if (!IsWaitingPositionFree(v, end_tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return; SetRailStationPlatformReservation(target->node.tile, dir, true); SetRailStationReservation(target->node.tile, false); } else { if (!IsWaitingPositionFree(v, target->node.tile, target->node.direction, _settings_game.pf.forbid_90_deg)) return; } for (const PathNode *cur = target; cur->parent != NULL; cur = cur->parent) { if (!TryReserveRailTrack(cur->node.tile, TrackdirToTrack(cur->node.direction))) { /* Reservation failed, undo. */ ClearPathReservation(target, cur); return; } } ftd->res_okay = true; } } /** * Finds out if a given company's vehicles are allowed to enter a given tile. * @param owner The owner of the vehicle. * @param tile The tile that is about to be entered. * @param enterdir The direction in which the vehicle wants to enter the tile. * @return true if the vehicle can enter the tile. * @todo This function should be used in other places than just NPF, * maybe moved to another file too. */ static bool CanEnterTileOwnerCheck(Owner owner, TileIndex tile, DiagDirection enterdir) { if (IsTileType(tile, MP_RAILWAY) || // Rail tile (also rail depot) HasStationTileRail(tile) || // Rail station tile/waypoint IsRoadDepotTile(tile) || // Road depot tile IsStandardRoadStopTile(tile)) { // Road station tile (but not drive-through stops) return IsTileOwner(tile, owner); // You need to own these tiles entirely to use them } switch (GetTileType(tile)) { case MP_ROAD: /* rail-road crossing : are we looking at the railway part? */ if (IsLevelCrossing(tile) && DiagDirToAxis(enterdir) != GetCrossingRoadAxis(tile)) { return IsTileOwner(tile, owner); // Railway needs owner check, while the street is public } break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) { return IsTileOwner(tile, owner); } break; default: break; } return true; // no need to check } /** * Returns the direction the exit of the depot on the given tile is facing. */ static DiagDirection GetDepotDirection(TileIndex tile, TransportType type) { assert(IsDepotTypeTile(tile, type)); switch (type) { case TRANSPORT_RAIL: return GetRailDepotDirection(tile); case TRANSPORT_ROAD: return GetRoadDepotDirection(tile); case TRANSPORT_WATER: return GetShipDepotDirection(tile); default: return INVALID_DIAGDIR; // Not reached } } /** Tests if a tile is a road tile with a single tramtrack (tram can reverse) */ static DiagDirection GetSingleTramBit(TileIndex tile) { if (IsNormalRoadTile(tile)) { RoadBits rb = GetRoadBits(tile, ROADTYPE_TRAM); switch (rb) { case ROAD_NW: return DIAGDIR_NW; case ROAD_SW: return DIAGDIR_SW; case ROAD_SE: return DIAGDIR_SE; case ROAD_NE: return DIAGDIR_NE; default: break; } } return INVALID_DIAGDIR; } /** * Tests if a tile can be entered or left only from one side. * * Depots, non-drive-through roadstops, and tiles with single trambits are tested. * * @param tile The tile of interest. * @param type The transporttype of the vehicle. * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle. * @return The single entry/exit-direction of the tile, or INVALID_DIAGDIR if there are more or less directions */ static DiagDirection GetTileSingleEntry(TileIndex tile, TransportType type, uint subtype) { if (type != TRANSPORT_WATER && IsDepotTypeTile(tile, type)) return GetDepotDirection(tile, type); if (type == TRANSPORT_ROAD) { if (IsStandardRoadStopTile(tile)) return GetRoadStopDir(tile); if (HasBit(subtype, ROADTYPE_TRAM)) return GetSingleTramBit(tile); } return INVALID_DIAGDIR; } /** * Tests if a vehicle must reverse on a tile. * * @param tile The tile of interest. * @param dir The direction in which the vehicle drives on a tile. * @param type The transporttype of the vehicle. * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle. * @return true iff the vehicle must reverse on the tile. */ static inline bool ForceReverse(TileIndex tile, DiagDirection dir, TransportType type, uint subtype) { DiagDirection single_entry = GetTileSingleEntry(tile, type, subtype); return single_entry != INVALID_DIAGDIR && single_entry != dir; } /** * Tests if a vehicle can enter a tile. * * @param tile The tile of interest. * @param dir The direction in which the vehicle drives onto a tile. * @param type The transporttype of the vehicle. * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle. * @param railtypes For TRANSPORT_RAIL the compatible RailTypes of the vehicle. * @param owner The owner of the vehicle. * @return true iff the vehicle can enter the tile. */ static bool CanEnterTile(TileIndex tile, DiagDirection dir, TransportType type, uint subtype, RailTypes railtypes, Owner owner) { /* Check tunnel entries and bridge ramps */ if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(tile) != dir) return false; /* Test ownership */ if (!CanEnterTileOwnerCheck(owner, tile, dir)) return false; /* check correct rail type (mono, maglev, etc) */ if (type == TRANSPORT_RAIL) { RailType rail_type = GetTileRailType(tile); if (!HasBit(railtypes, rail_type)) return false; } /* Depots, standard roadstops and single tram bits can only be entered from one direction */ DiagDirection single_entry = GetTileSingleEntry(tile, type, subtype); if (single_entry != INVALID_DIAGDIR && single_entry != ReverseDiagDir(dir)) return false; return true; } /** * Returns the driveable Trackdirs on a tile. * * One-way-roads are taken into account. Signals are not tested. * * @param dst_tile The tile of interest. * @param src_trackdir The direction the vehicle is currently moving. * @param type The transporttype of the vehicle. * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle. * @return The Trackdirs the vehicle can continue moving on. */ static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype) { TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype)); if (trackdirbits == 0 && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) { /* GetTileTrackStatus() returns 0 for single tram bits. * As we cannot change it there (easily) without breaking something, change it here */ switch (GetSingleTramBit(dst_tile)) { case DIAGDIR_NE: case DIAGDIR_SW: trackdirbits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW; break; case DIAGDIR_NW: case DIAGDIR_SE: trackdirbits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE; break; default: break; } } DEBUG(npf, 4, "Next node: (%d, %d) [%d], possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirbits); /* Select only trackdirs we can reach from our current trackdir */ trackdirbits &= TrackdirReachesTrackdirs(src_trackdir); /* Filter out trackdirs that would make 90 deg turns for trains */ if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir); DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits); return trackdirbits; } /* Will just follow the results of GetTileTrackStatus concerning where we can * go and where not. Uses AyStar.user_data[NPF_TYPE] as the transport type and * an argument to GetTileTrackStatus. Will skip tunnels, meaning that the * entry and exit are neighbours. Will fill * AyStarNode.user_data[NPF_TRACKDIR_CHOICE] with an appropriate value, and * copy AyStarNode.user_data[NPF_NODE_FLAGS] from the parent */ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) { /* We leave src_tile on track src_trackdir in direction src_exitdir */ Trackdir src_trackdir = current->path.node.direction; TileIndex src_tile = current->path.node.tile; DiagDirection src_exitdir = TrackdirToExitdir(src_trackdir); /* Is src_tile valid, and can be used? * When choosing track on a junction src_tile is the tile neighboured to the junction wrt. exitdir. * But we must not check the validity of this move, as src_tile is totally unrelated to the move, if a roadvehicle reversed on a junction. */ bool ignore_src_tile = (current->path.parent == NULL && NPFGetFlag(¤t->path.node, NPF_FLAG_IGNORE_START_TILE)); /* Information about the vehicle: TransportType (road/rail/water) and SubType (compatible rail/road types) */ TransportType type = (TransportType)aystar->user_data[NPF_TYPE]; uint subtype = aystar->user_data[NPF_SUB_TYPE]; /* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */ aystar->num_neighbours = 0; DEBUG(npf, 4, "Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile); /* We want to determine the tile we arrive, and which choices we have there */ TileIndex dst_tile; TrackdirBits trackdirbits; /* Find dest tile */ if (ignore_src_tile) { /* Do not perform any checks that involve src_tile */ dst_tile = src_tile + TileOffsByDiagDir(src_exitdir); trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); } else if (IsTileType(src_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(src_tile) == src_exitdir) { /* We drive through the wormhole and arrive on the other side */ dst_tile = GetOtherTunnelBridgeEnd(src_tile); trackdirbits = TrackdirToTrackdirBits(src_trackdir); } else if (ForceReverse(src_tile, src_exitdir, type, subtype)) { /* We can only reverse on this tile */ dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); trackdirbits = TrackdirToTrackdirBits(src_trackdir); } else { /* We leave src_tile in src_exitdir and reach dst_tile */ dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(src_exitdir)); if (dst_tile != INVALID_TILE && !CanEnterTile(dst_tile, src_exitdir, type, subtype, (RailTypes)aystar->user_data[NPF_RAILTYPES], (Owner)aystar->user_data[NPF_OWNER])) dst_tile = INVALID_TILE; if (dst_tile == INVALID_TILE) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); } trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); if (trackdirbits == 0) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); } } if (NPFGetFlag(¤t->path.node, NPF_FLAG_IGNORE_RESERVED)) { /* Mask out any reserved tracks. */ TrackBits reserved = GetReservedTrackbits(dst_tile); trackdirbits &= ~TrackBitsToTrackdirBits(reserved); Track t; FOR_EACH_SET_TRACK(t, TrackdirBitsToTrackBits(trackdirbits)) { if (TracksOverlap(reserved | TrackToTrackBits(t))) trackdirbits &= ~TrackToTrackdirBits(t); } } /* Enumerate possible track */ uint i = 0; while (trackdirbits != 0) { Trackdir dst_trackdir = RemoveFirstTrackdir(&trackdirbits); DEBUG(npf, 5, "Expanded into trackdir: %d, remaining trackdirs: 0x%X", dst_trackdir, trackdirbits); /* Tile with signals? */ if (IsTileType(dst_tile, MP_RAILWAY) && GetRailTileType(dst_tile) == RAIL_TILE_SIGNALS) { if (HasSignalOnTrackdir(dst_tile, ReverseTrackdir(dst_trackdir)) && !HasSignalOnTrackdir(dst_tile, dst_trackdir) && IsOnewaySignal(dst_tile, TrackdirToTrack(dst_trackdir))) { /* If there's a one-way signal not pointing towards us, stop going in this direction. */ break; } } { /* We've found ourselves a neighbour :-) */ AyStarNode *neighbour = &aystar->neighbours[i]; neighbour->tile = dst_tile; neighbour->direction = dst_trackdir; /* Save user data */ neighbour->user_data[NPF_NODE_FLAGS] = current->path.node.user_data[NPF_NODE_FLAGS]; NPFFillTrackdirChoice(neighbour, current); } i++; } aystar->num_neighbours = i; } /* * Plan a route to the specified target (which is checked by target_proc), * from start1 and if not NULL, from start2 as well. The type of transport we * are checking is in type. reverse_penalty is applied to all routes that * originate from the second start node. * When we are looking for one specific target (optionally multiple tiles), we * should use a good heuristic to perform aystar search. When we search for * multiple targets that are spread around, we should perform a breadth first * search by specifiying CalcZero as our heuristic. */ static NPFFoundTargetData NPFRouteInternal(AyStarNode *start1, bool ignore_start_tile1, AyStarNode *start2, bool ignore_start_tile2, NPFFindStationOrTileData *target, AyStar_EndNodeCheck target_proc, AyStar_CalculateH heuristic_proc, TransportType type, uint sub_type, Owner owner, RailTypes railtypes, uint reverse_penalty) { int r; NPFFoundTargetData result; /* Initialize procs */ _npf_aystar.CalculateH = heuristic_proc; _npf_aystar.EndNodeCheck = target_proc; _npf_aystar.FoundEndNode = NPFSaveTargetData; _npf_aystar.GetNeighbours = NPFFollowTrack; switch (type) { default: NOT_REACHED(); case TRANSPORT_RAIL: _npf_aystar.CalculateG = NPFRailPathCost; break; case TRANSPORT_ROAD: _npf_aystar.CalculateG = NPFRoadPathCost; break; case TRANSPORT_WATER: _npf_aystar.CalculateG = NPFWaterPathCost; break; } /* Initialize Start Node(s) */ start1->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start1->user_data[NPF_NODE_FLAGS] = 0; NPFSetFlag(start1, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile1); _npf_aystar.AddStartNode(start1, 0); if (start2 != NULL) { start2->user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start2->user_data[NPF_NODE_FLAGS] = 0; NPFSetFlag(start2, NPF_FLAG_IGNORE_START_TILE, ignore_start_tile2); NPFSetFlag(start2, NPF_FLAG_REVERSE, true); _npf_aystar.AddStartNode(start2, reverse_penalty); } /* Initialize result */ result.best_bird_dist = UINT_MAX; result.best_path_dist = UINT_MAX; result.best_trackdir = INVALID_TRACKDIR; result.node.tile = INVALID_TILE; result.res_okay = false; _npf_aystar.user_path = &result; /* Initialize target */ _npf_aystar.user_target = target; /* Initialize user_data */ _npf_aystar.user_data[NPF_TYPE] = type; _npf_aystar.user_data[NPF_SUB_TYPE] = sub_type; _npf_aystar.user_data[NPF_OWNER] = owner; _npf_aystar.user_data[NPF_RAILTYPES] = railtypes; /* GO! */ r = _npf_aystar.Main(); assert(r != AYSTAR_STILL_BUSY); if (result.best_bird_dist != 0) { if (target != NULL) { DEBUG(npf, 1, "Could not find route to tile 0x%X from 0x%X.", target->dest_coords, start1->tile); } else { /* Assumption: target == NULL, so we are looking for a depot */ DEBUG(npf, 1, "Could not find route to a depot from tile 0x%X.", start1->tile); } } return result; } /* Will search as below, but with two start nodes, the second being the * reverse. Look at the NPF_FLAG_REVERSE flag in the result node to see which * direction was taken (NPFGetFlag(result.node, NPF_FLAG_REVERSE)) */ static NPFFoundTargetData NPFRouteToStationOrTileTwoWay(TileIndex tile1, Trackdir trackdir1, bool ignore_start_tile1, TileIndex tile2, Trackdir trackdir2, bool ignore_start_tile2, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes) { AyStarNode start1; AyStarNode start2; start1.tile = tile1; start2.tile = tile2; /* We set this in case the target is also the start tile, we will just * return a not found then */ start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start1.direction = trackdir1; start2.direction = trackdir2; start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindStationOrTile, NPFCalcStationOrTileHeuristic, type, sub_type, owner, railtypes, 0); } /* Will search from the given tile and direction, for a route to the given * station for the given transport type. See the declaration of * NPFFoundTargetData above for the meaning of the result. */ static NPFFoundTargetData NPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes) { return NPFRouteToStationOrTileTwoWay(tile, trackdir, ignore_start_tile, INVALID_TILE, INVALID_TRACKDIR, false, target, type, sub_type, owner, railtypes); } /* Search using breadth first. Good for little track choice and inaccurate * heuristic, such as railway/road with two start nodes, the second being the reverse. Call * NPFGetFlag(result.node, NPF_FLAG_REVERSE) to see from which node the path * originated. All paths from the second node will have the given * reverse_penalty applied (NPF_TILE_LENGTH is the equivalent of one full * tile). */ static NPFFoundTargetData NPFRouteToDepotBreadthFirstTwoWay(TileIndex tile1, Trackdir trackdir1, bool ignore_start_tile1, TileIndex tile2, Trackdir trackdir2, bool ignore_start_tile2, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes, uint reverse_penalty) { AyStarNode start1; AyStarNode start2; start1.tile = tile1; start2.tile = tile2; /* We set this in case the target is also the start tile, we will just * return a not found then */ start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start1.direction = trackdir1; start2.direction = trackdir2; start2.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; /* perform a breadth first search. Target is NULL, * since we are just looking for any depot...*/ return NPFRouteInternal(&start1, ignore_start_tile1, (IsValidTile(tile2) ? &start2 : NULL), ignore_start_tile2, target, NPFFindDepot, NPFCalcZero, type, sub_type, owner, railtypes, reverse_penalty); } void InitializeNPF() { static bool first_init = true; if (first_init) { first_init = false; _npf_aystar.Init(NPFHash, NPF_HASH_SIZE); } else { _npf_aystar.Clear(); } _npf_aystar.loops_per_tick = 0; _npf_aystar.max_path_cost = 0; //_npf_aystar.max_search_nodes = 0; /* We will limit the number of nodes for now, until we have a better * solution to really fix performance */ _npf_aystar.max_search_nodes = _settings_game.pf.npf.npf_max_search_nodes; } static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *v, bool reserve_path = false) { /* Ships don't really reach their stations, but the tile in front. So don't * save the station id for ships. For roadvehs we don't store it either, * because multistop depends on vehicles actually reaching the exact * dest_tile, not just any stop of that station. * So only for train orders to stations we fill fstd->station_index, for all * others only dest_coords */ if (v->type != VEH_SHIP && (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_WAYPOINT))) { assert(v->IsGroundVehicle()); fstd->station_index = v->current_order.GetDestination(); fstd->station_type = (v->type == VEH_TRAIN) ? (v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT) : (RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK); fstd->not_articulated = v->type == VEH_ROAD && !RoadVehicle::From(v)->HasArticulatedPart(); /* Let's take the closest tile of the station as our target for vehicles */ fstd->dest_coords = CalcClosestStationTile(fstd->station_index, v->tile, fstd->station_type); } else { fstd->dest_coords = v->dest_tile; fstd->station_index = INVALID_STATION; } fstd->reserve_path = reserve_path; fstd->v = v; } /*** Road vehicles ***/ FindDepotData NPFRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_penalty) { Trackdir trackdir = v->GetVehicleTrackdir(); NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, v->tile, ReverseTrackdir(trackdir), false, NULL, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES, 0); if (ftd.best_bird_dist != 0) return FindDepotData(); /* Found target */ /* Our caller expects a number of tiles, so we just approximate that * number by this. It might not be completely what we want, but it will * work for now :-) We can possibly change this when the old pathfinder * is removed. */ return FindDepotData(ftd.node.tile, ftd.best_path_dist); } Trackdir NPFRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found) { NPFFindStationOrTileData fstd; NPFFillWithOrderData(&fstd, v); Trackdir trackdir = DiagDirToDiagTrackdir(enterdir); NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->compatible_roadtypes, v->owner, INVALID_RAILTYPES); if (ftd.best_trackdir == INVALID_TRACKDIR) { /* We are already at our target. Just do something * @todo: maybe display error? * @todo: go straight ahead if possible? */ path_found = true; return (Trackdir)FindFirstBit2x64(trackdirs); } /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains * the direction we need to take to get there, if ftd.best_bird_dist is not 0, * we did not find our target, but ftd.best_trackdir contains the direction leading * to the tile closest to our target. */ path_found = (ftd.best_bird_dist == 0); return ftd.best_trackdir; } /*** Ships ***/ Track NPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found) { NPFFindStationOrTileData fstd; Trackdir trackdir = v->GetVehicleTrackdir(); assert(trackdir != INVALID_TRACKDIR); // Check that we are not in a depot NPFFillWithOrderData(&fstd, v); NPFFoundTargetData ftd = NPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_WATER, 0, v->owner, INVALID_RAILTYPES); /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains * the direction we need to take to get there, if ftd.best_bird_dist is not 0, * we did not find our target, but ftd.best_trackdir contains the direction leading * to the tile closest to our target. */ path_found = (ftd.best_bird_dist == 0); if (ftd.best_trackdir == 0xff) return INVALID_TRACK; return TrackdirToTrack(ftd.best_trackdir); } bool NPFShipCheckReverse(const Ship *v) { NPFFindStationOrTileData fstd; NPFFoundTargetData ftd; NPFFillWithOrderData(&fstd, v); Trackdir trackdir = v->GetVehicleTrackdir(); Trackdir trackdir_rev = ReverseTrackdir(trackdir); assert(trackdir != INVALID_TRACKDIR); assert(trackdir_rev != INVALID_TRACKDIR); ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, v->tile, trackdir_rev, false, &fstd, TRANSPORT_WATER, 0, v->owner, INVALID_RAILTYPES); /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */ return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE); } /*** Trains ***/ FindDepotData NPFTrainFindNearestDepot(const Train *v, int max_penalty) { const Train *last = v->Last(); Trackdir trackdir = v->GetVehicleTrackdir(); Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir()); NPFFindStationOrTileData fstd; fstd.v = v; fstd.reserve_path = false; assert(trackdir != INVALID_TRACKDIR); NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes, NPF_INFINITE_PENALTY); if (ftd.best_bird_dist != 0) return FindDepotData(); /* Found target */ /* Our caller expects a number of tiles, so we just approximate that * number by this. It might not be completely what we want, but it will * work for now :-) We can possibly change this when the old pathfinder * is removed. */ return FindDepotData(ftd.node.tile, ftd.best_path_dist, NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE)); } bool NPFTrainFindNearestSafeTile(const Train *v, TileIndex tile, Trackdir trackdir, bool override_railtype) { assert(v->type == VEH_TRAIN); NPFFindStationOrTileData fstd; fstd.v = v; fstd.reserve_path = true; AyStarNode start1; start1.tile = tile; /* We set this in case the target is also the start tile, we will just * return a not found then */ start1.user_data[NPF_TRACKDIR_CHOICE] = INVALID_TRACKDIR; start1.direction = trackdir; NPFSetFlag(&start1, NPF_FLAG_IGNORE_RESERVED, true); RailTypes railtypes = v->compatible_railtypes; if (override_railtype) railtypes |= GetRailTypeInfo(v->railtype)->compatible_railtypes; /* perform a breadth first search. Target is NULL, * since we are just looking for any safe tile...*/ return NPFRouteInternal(&start1, true, NULL, false, &fstd, NPFFindSafeTile, NPFCalcZero, TRANSPORT_RAIL, 0, v->owner, railtypes, 0).res_okay; } bool NPFTrainCheckReverse(const Train *v) { NPFFindStationOrTileData fstd; NPFFoundTargetData ftd; const Train *last = v->Last(); NPFFillWithOrderData(&fstd, v); Trackdir trackdir = v->GetVehicleTrackdir(); Trackdir trackdir_rev = ReverseTrackdir(last->GetVehicleTrackdir()); assert(trackdir != INVALID_TRACKDIR); assert(trackdir_rev != INVALID_TRACKDIR); ftd = NPFRouteToStationOrTileTwoWay(v->tile, trackdir, false, last->tile, trackdir_rev, false, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes); /* If we didn't find anything, just keep on going straight ahead, otherwise take the reverse flag */ return ftd.best_bird_dist == 0 && NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE); } Track NPFTrainChooseTrack(const Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found, bool reserve_track, struct PBSTileInfo *target) { NPFFindStationOrTileData fstd; NPFFillWithOrderData(&fstd, v, reserve_track); PBSTileInfo origin = FollowTrainReservation(v); assert(IsValidTrackdir(origin.trackdir)); NPFFoundTargetData ftd = NPFRouteToStationOrTile(origin.tile, origin.trackdir, true, &fstd, TRANSPORT_RAIL, 0, v->owner, v->compatible_railtypes); if (target != NULL) { target->tile = ftd.node.tile; target->trackdir = (Trackdir)ftd.node.direction; target->okay = ftd.res_okay; } if (ftd.best_trackdir == INVALID_TRACKDIR) { /* We are already at our target. Just do something * @todo maybe display error? * @todo: go straight ahead if possible? */ path_found = true; return FindFirstTrack(tracks); } /* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains * the direction we need to take to get there, if ftd.best_bird_dist is not 0, * we did not find our target, but ftd.best_trackdir contains the direction leading * to the tile closest to our target. */ path_found = (ftd.best_bird_dist == 0); /* Discard enterdir information, making it a normal track */ return TrackdirToTrack(ftd.best_trackdir); } openttd-1.5.3/src/pathfinder/opf/0000755000000000000000000000000012627373445015407 5ustar rootrootopenttd-1.5.3/src/pathfinder/opf/opf_ship.h0000644000000000000000000000304412627373445017370 0ustar rootroot/* $Id: opf_ship.h 21511 2010-12-13 21:56:40Z rubidium $ */ /* * 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 opf_ship.h Original pathfinder for ships; very simple. */ #ifndef OPF_SHIP_H #define OPF_SHIP_H #include "../../direction_type.h" #include "../../tile_type.h" #include "../../track_type.h" #include "../../vehicle_type.h" /** * Finds the best path for given ship using OPF. * @param v the ship that needs to find a path * @param tile the tile to find the path from (should be next tile the ship is about to enter) * @param enterdir diagonal direction which the ship will enter this new tile from * @param tracks available tracks on the new tile (to choose from) * @param path_found [out] Whether a path has been found (true) or has been guessed (false) * @return the best trackdir for next turn or INVALID_TRACK if the path could not be found */ Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found); #endif /* OPF_SHIP_H */ openttd-1.5.3/src/pathfinder/opf/opf_ship.cpp0000644000000000000000000001554712627373445017736 0ustar rootroot/* $Id: opf_ship.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 opf_ship.cpp Implementation of the oldest supported ship pathfinder. */ #include "../../stdafx.h" #include "../../tunnelbridge_map.h" #include "../../tunnelbridge.h" #include "../../ship.h" #include "../../core/random_func.hpp" #include "../../safeguards.h" struct RememberData { uint16 cur_length; byte depth; Track last_choosen_track; }; struct TrackPathFinder { TileIndex skiptile; TileIndex dest_coords; uint best_bird_dist; uint best_length; RememberData rd; TrackdirByte the_dir; }; static bool ShipTrackFollower(TileIndex tile, TrackPathFinder *pfs, uint length) { /* Found dest? */ if (tile == pfs->dest_coords) { pfs->best_bird_dist = 0; pfs->best_length = minu(pfs->best_length, length); return true; } /* Skip this tile in the calculation */ if (tile != pfs->skiptile) { pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile)); } return false; } static void TPFModeShip(TrackPathFinder *tpf, TileIndex tile, DiagDirection direction) { if (IsTileType(tile, MP_TUNNELBRIDGE)) { /* wrong track type */ if (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) return; DiagDirection dir = GetTunnelBridgeDirection(tile); /* entering tunnel / bridge? */ if (dir == direction) { TileIndex endtile = GetOtherTunnelBridgeEnd(tile); tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1; tile = endtile; } else { /* leaving tunnel / bridge? */ if (ReverseDiagDir(dir) != direction) return; } } /* This addition will sometimes overflow by a single tile. * The use of TILE_MASK here makes sure that we still point at a valid * tile, and then this tile will be in the sentinel row/col, so GetTileTrackStatus will fail. */ tile = TILE_MASK(tile + TileOffsByDiagDir(direction)); if (++tpf->rd.cur_length > 50) return; TrackBits bits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(direction); if (bits == TRACK_BIT_NONE) return; assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY()); bool only_one_track = true; do { Track track = RemoveFirstTrack(&bits); if (bits != TRACK_BIT_NONE) only_one_track = false; RememberData rd = tpf->rd; /* Change direction 4 times only */ if (!only_one_track && track != tpf->rd.last_choosen_track) { if (++tpf->rd.depth > 4) { tpf->rd = rd; return; } tpf->rd.last_choosen_track = track; } tpf->the_dir = TrackEnterdirToTrackdir(track, direction); if (!ShipTrackFollower(tile, tpf, tpf->rd.cur_length)) { TPFModeShip(tpf, tile, TrackdirToExitdir(tpf->the_dir)); } tpf->rd = rd; } while (bits != TRACK_BIT_NONE); } static void OPFShipFollowTrack(TileIndex tile, DiagDirection direction, TrackPathFinder *tpf) { assert(IsValidDiagDirection(direction)); /* initialize path finder variables */ tpf->rd.cur_length = 0; tpf->rd.depth = 0; tpf->rd.last_choosen_track = INVALID_TRACK; ShipTrackFollower(tile, tpf, 0); TPFModeShip(tpf, tile, direction); } /** Directions to search towards given track bits and the ship's enter direction. */ static const DiagDirection _ship_search_directions[6][4] = { { DIAGDIR_NE, INVALID_DIAGDIR, DIAGDIR_SW, INVALID_DIAGDIR }, { INVALID_DIAGDIR, DIAGDIR_SE, INVALID_DIAGDIR, DIAGDIR_NW }, { INVALID_DIAGDIR, DIAGDIR_NE, DIAGDIR_NW, INVALID_DIAGDIR }, { DIAGDIR_SE, INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SW }, { DIAGDIR_NW, DIAGDIR_SW, INVALID_DIAGDIR, INVALID_DIAGDIR }, { INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SE, DIAGDIR_NE }, }; /** Track to "direction (& 3)" mapping. */ static const byte _pick_shiptrack_table[6] = {DIR_NE, DIR_SE, DIR_E, DIR_E, DIR_N, DIR_N}; static uint FindShipTrack(const Ship *v, TileIndex tile, DiagDirection dir, TrackBits bits, TileIndex skiptile, Track *track) { TrackPathFinder pfs; uint best_bird_dist = 0; uint best_length = 0; byte ship_dir = v->direction & 3; pfs.dest_coords = v->dest_tile; pfs.skiptile = skiptile; Track best_track = INVALID_TRACK; do { Track i = RemoveFirstTrack(&bits); pfs.best_bird_dist = UINT_MAX; pfs.best_length = UINT_MAX; OPFShipFollowTrack(tile, _ship_search_directions[i][dir], &pfs); if (best_track != INVALID_TRACK) { if (pfs.best_bird_dist != 0) { /* neither reached the destination, pick the one with the smallest bird dist */ if (pfs.best_bird_dist > best_bird_dist) goto bad; if (pfs.best_bird_dist < best_bird_dist) goto good; } else { if (pfs.best_length > best_length) goto bad; if (pfs.best_length < best_length) goto good; } /* if we reach this position, there's two paths of equal value so far. * pick one randomly. */ uint r = GB(Random(), 0, 8); if (_pick_shiptrack_table[i] == ship_dir) r += 80; if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80; if (r <= 127) goto bad; } good:; best_track = i; best_bird_dist = pfs.best_bird_dist; best_length = pfs.best_length; bad:; } while (bits != 0); *track = best_track; return best_bird_dist; } /** * returns the track to choose on the next tile, or -1 when it's better to * reverse. The tile given is the tile we are about to enter, enterdir is the * direction in which we are entering the tile */ Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found) { assert(IsValidDiagDirection(enterdir)); TileIndex tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir)); Track track; /* Let's find out how far it would be if we would reverse first */ Trackdir trackdir = v->GetVehicleTrackdir(); TrackBits b = TrackStatusToTrackBits(GetTileTrackStatus(tile2, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(ReverseDiagDir(enterdir)) & TrackdirBitsToTrackBits(TrackdirToTrackdirBits(trackdir)); uint distr = UINT_MAX; // distance if we reversed if (b != 0) { distr = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track); if (distr != UINT_MAX) distr++; // penalty for reversing } /* And if we would not reverse? */ uint dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track); /* Due to the way this pathfinder works we cannot determine whether we're lost or not. */ path_found = true; if (dist <= distr) return track; return INVALID_TRACK; // We could better reverse } openttd-1.5.3/src/pathfinder/pf_performance_timer.hpp0000644000000000000000000000336012627373445021524 0ustar rootroot/* $Id: pf_performance_timer.hpp 23640 2011-12-20 17:57:56Z truebrain $ */ /* * 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 pf_performance_timer.hpp Performance timer for pathfinders. */ #ifndef PF_PERFORMANCE_TIMER_HPP #define PF_PERFORMANCE_TIMER_HPP #include "../debug.h" struct CPerformanceTimer { int64 m_start; int64 m_acc; CPerformanceTimer() : m_start(0), m_acc(0) {} inline void Start() { m_start = QueryTime(); } inline void Stop() { m_acc += QueryTime() - m_start; } inline int Get(int64 coef) { return (int)(m_acc * coef / QueryFrequency()); } inline int64 QueryTime() { return ottd_rdtsc(); } inline int64 QueryFrequency() { return ((int64)2200 * 1000000); } }; struct CPerfStartReal { CPerformanceTimer *m_pperf; inline CPerfStartReal(CPerformanceTimer& perf) : m_pperf(&perf) { if (m_pperf != NULL) m_pperf->Start(); } inline ~CPerfStartReal() { Stop(); } inline void Stop() { if (m_pperf != NULL) { m_pperf->Stop(); m_pperf = NULL; } } }; struct CPerfStartFake { inline CPerfStartFake(CPerformanceTimer& perf) {} inline ~CPerfStartFake() {} inline void Stop() {} }; typedef CPerfStartFake CPerfStart; #endif /* PF_PERFORMANCE_TIMER_HPP */ openttd-1.5.3/src/pathfinder/pathfinder_type.h0000644000000000000000000000464112627373445020166 0ustar rootroot/* $Id: pathfinder_type.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 pathfinder_type.h General types related to pathfinders. */ #ifndef PATHFINDER_TYPE_H #define PATHFINDER_TYPE_H #include "../tile_type.h" /** Length (penalty) of one tile with NPF */ static const int NPF_TILE_LENGTH = 100; /** * This penalty is the equivalent of "infinite", which means that paths that * get this penalty will be chosen, but only if there is no other route * without it. Be careful with not applying this penalty to often, or the * total path cost might overflow.. */ static const int NPF_INFINITE_PENALTY = 1000 * NPF_TILE_LENGTH; /** Length (penalty) of one tile with YAPF */ static const int YAPF_TILE_LENGTH = 100; /** Length (penalty) of a corner with YAPF */ static const int YAPF_TILE_CORNER_LENGTH = 71; /** * This penalty is the equivalent of "infinite", which means that paths that * get this penalty will be chosen, but only if there is no other route * without it. Be careful with not applying this penalty to often, or the * total path cost might overflow.. */ static const int YAPF_INFINITE_PENALTY = 1000 * YAPF_TILE_LENGTH; /** * Helper container to find a depot */ struct FindDepotData { TileIndex tile; ///< The tile of the depot uint best_length; ///< The distance towards the depot in penalty, or UINT_MAX if not found bool reverse; ///< True if reversing is necessary for the train to get to this depot /** * Create an instance of this structure. * @param tile the tile of the depot * @param best_length the distance towards the depot, or UINT_MAX if not found * @param reverse whether we need to reverse first. */ FindDepotData(TileIndex tile = INVALID_TILE, uint best_length = UINT_MAX, bool reverse = false) : tile(tile), best_length(best_length), reverse(reverse) { } }; #endif /* PATHFINDER_TYPE_H */ openttd-1.5.3/src/linkgraph/0000755000000000000000000000000012627373441014452 5ustar rootrootopenttd-1.5.3/src/linkgraph/linkgraphjob.h0000644000000000000000000003217112627373441017301 0ustar rootroot/* $Id: linkgraphjob.h 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 linkgraphjob.h Declaration of link graph job classes used for cargo distribution. */ #ifndef LINKGRAPHJOB_H #define LINKGRAPHJOB_H #include "../thread/thread.h" #include "linkgraph.h" #include class LinkGraphJob; class Path; typedef std::list PathList; /** Type of the pool for link graph jobs. */ typedef Pool LinkGraphJobPool; /** The actual pool with link graph jobs. */ extern LinkGraphJobPool _link_graph_job_pool; /** * Class for calculation jobs to be run on link graphs. */ class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{ private: /** * Annotation for a link graph edge. */ struct EdgeAnnotation { uint demand; ///< Transport demand between the nodes. uint unsatisfied_demand; ///< Demand over this edge that hasn't been satisfied yet. uint flow; ///< Planned flow over this edge. void Init(); }; /** * Annotation for a link graph node. */ struct NodeAnnotation { uint undelivered_supply; ///< Amount of supply that hasn't been distributed yet. PathList paths; ///< Paths through this node, sorted so that those with flow == 0 are in the back. FlowStatMap flows; ///< Planned flows to other nodes. void Init(uint supply); }; typedef SmallVector NodeAnnotationVector; typedef SmallMatrix EdgeAnnotationMatrix; friend const SaveLoad *GetLinkGraphJobDesc(); friend class LinkGraphSchedule; protected: const LinkGraph link_graph; ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later. const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time. ThreadObject *thread; ///< Thread the job is running in or NULL if it's running in the main thread. Date join_date; ///< Date when the job is to be joined. NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation. EdgeAnnotationMatrix edges; ///< Extra edge data necessary for link graph calculation. void EraseFlows(NodeID from); void JoinThread(); void SpawnThread(); public: /** * A job edge. Wraps a link graph edge and an edge annotation. The * annotation can be modified, the edge is constant. */ class Edge : public LinkGraph::ConstEdge { private: EdgeAnnotation &anno; ///< Annotation being wrapped. public: /** * Constructor. * @param edge Link graph edge to be wrapped. * @param anno Annotation to be wrapped. */ Edge(const LinkGraph::BaseEdge &edge, EdgeAnnotation &anno) : LinkGraph::ConstEdge(edge), anno(anno) {} /** * Get the transport demand between end the points of the edge. * @return Demand. */ uint Demand() const { return this->anno.demand; } /** * Get the transport demand that hasn't been satisfied by flows, yet. * @return Unsatisfied demand. */ uint UnsatisfiedDemand() const { return this->anno.unsatisfied_demand; } /** * Get the total flow on the edge. * @return Flow. */ uint Flow() const { return this->anno.flow; } /** * Add some flow. * @param flow Flow to be added. */ void AddFlow(uint flow) { this->anno.flow += flow; } /** * Remove some flow. * @param flow Flow to be removed. */ void RemoveFlow(uint flow) { assert(flow <= this->anno.flow); this->anno.flow -= flow; } /** * Add some (not yet satisfied) demand. * @param demand Demand to be added. */ void AddDemand(uint demand) { this->anno.demand += demand; this->anno.unsatisfied_demand += demand; } /** * Satisfy some demand. * @param demand Demand to be satisfied. */ void SatisfyDemand(uint demand) { assert(demand <= this->anno.unsatisfied_demand); this->anno.unsatisfied_demand -= demand; } }; /** * Iterator for job edges. */ class EdgeIterator : public LinkGraph::BaseEdgeIterator { EdgeAnnotation *base_anno; ///< Array of annotations to be (indirectly) iterated. public: /** * Constructor. * @param base Array of edges to be iterated. * @param base_anno Array of annotations to be iterated. * @param current Start offset of iteration. */ EdgeIterator(const LinkGraph::BaseEdge *base, EdgeAnnotation *base_anno, NodeID current) : LinkGraph::BaseEdgeIterator(base, current), base_anno(base_anno) {} /** * Dereference. * @return Pair of the edge currently pointed to and the ID of its * other end. */ SmallPair operator*() const { return SmallPair(this->current, Edge(this->base[this->current], this->base_anno[this->current])); } /** * Dereference. Has to be repeated here as operator* is different than * in LinkGraph::EdgeWrapper. * @return Fake pointer to pair of NodeID/Edge. */ FakePointer operator->() const { return FakePointer(this->operator*()); } }; /** * Link graph job node. Wraps a constant link graph node and a modifiable * node annotation. */ class Node : public LinkGraph::ConstNode { private: NodeAnnotation &node_anno; ///< Annotation being wrapped. EdgeAnnotation *edge_annos; ///< Edge annotations belonging to this node. public: /** * Constructor. * @param lgj Job to take the node from. * @param node ID of the node. */ Node (LinkGraphJob *lgj, NodeID node) : LinkGraph::ConstNode(&lgj->link_graph, node), node_anno(lgj->nodes[node]), edge_annos(lgj->edges[node]) {} /** * Retrieve an edge starting at this node. Mind that this returns an * object, not a reference. * @param to Remote end of the edge. * @return Edge between this node and "to". */ Edge operator[](NodeID to) const { return Edge(this->edges[to], this->edge_annos[to]); } /** * Iterator for the "begin" of the edge array. Only edges with capacity * are iterated. The others are skipped. * @return Iterator pointing to the first edge. */ EdgeIterator Begin() const { return EdgeIterator(this->edges, this->edge_annos, index); } /** * Iterator for the "end" of the edge array. Only edges with capacity * are iterated. The others are skipped. * @return Iterator pointing beyond the last edge. */ EdgeIterator End() const { return EdgeIterator(this->edges, this->edge_annos, INVALID_NODE); } /** * Get amount of supply that hasn't been delivered, yet. * @return Undelivered supply. */ uint UndeliveredSupply() const { return this->node_anno.undelivered_supply; } /** * Get the flows running through this node. * @return Flows. */ FlowStatMap &Flows() { return this->node_anno.flows; } /** * Get a constant version of the flows running through this node. * @return Flows. */ const FlowStatMap &Flows() const { return this->node_anno.flows; } /** * Get the paths this node is part of. Paths are always expected to be * sorted so that those with flow == 0 are in the back of the list. * @return Paths. */ PathList &Paths() { return this->node_anno.paths; } /** * Get a constant version of the paths this node is part of. * @return Paths. */ const PathList &Paths() const { return this->node_anno.paths; } /** * Deliver some supply, adding demand to the respective edge. * @param to Destination for supply. * @param amount Amount of supply to be delivered. */ void DeliverSupply(NodeID to, uint amount) { this->node_anno.undelivered_supply -= amount; (*this)[to].AddDemand(amount); } }; /** * Bare constructor, only for save/load. link_graph, join_date and actually * settings have to be brutally const-casted in order to populate them. */ LinkGraphJob() : settings(_settings_game.linkgraph), thread(NULL), join_date(INVALID_DATE) {} LinkGraphJob(const LinkGraph &orig); ~LinkGraphJob(); void Init(); /** * Check if job is supposed to be finished. * @return True if job should be finished by now, false if not. */ inline bool IsFinished() const { return this->join_date <= _date; } /** * Get the date when the job should be finished. * @return Join date. */ inline Date JoinDate() const { return join_date; } /** * Change the join date on date cheating. * @param interval Number of days to add. */ inline void ShiftJoinDate(int interval) { this->join_date += interval; } /** * Get the link graph settings for this component. * @return Settings. */ inline const LinkGraphSettings &Settings() const { return this->settings; } /** * Get a node abstraction with the specified id. * @param num ID of the node. * @return the Requested node. */ inline Node operator[](NodeID num) { return Node(this, num); } /** * Get the size of the underlying link graph. * @return Size. */ inline uint Size() const { return this->link_graph.Size(); } /** * Get the cargo of the underlying link graph. * @return Cargo. */ inline CargoID Cargo() const { return this->link_graph.Cargo(); } /** * Get the date when the underlying link graph was last compressed. * @return Compression date. */ inline Date LastCompression() const { return this->link_graph.LastCompression(); } /** * Get the ID of the underlying link graph. * @return Link graph ID. */ inline LinkGraphID LinkGraphIndex() const { return this->link_graph.index; } /** * Get a reference to the underlying link graph. Only use this for save/load. * @return Link graph. */ inline const LinkGraph &Graph() const { return this->link_graph; } }; #define FOR_ALL_LINK_GRAPH_JOBS(var) FOR_ALL_ITEMS_FROM(LinkGraphJob, link_graph_job_index, var, 0) /** * A leg of a path in the link graph. Paths can form trees by being "forked". */ class Path { public: static Path *invalid_path; Path(NodeID n, bool source = false); /** Get the node this leg passes. */ inline NodeID GetNode() const { return this->node; } /** Get the overall origin of the path. */ inline NodeID GetOrigin() const { return this->origin; } /** Get the parent leg of this one. */ inline Path *GetParent() { return this->parent; } /** Get the overall capacity of the path. */ inline uint GetCapacity() const { return this->capacity; } /** Get the free capacity of the path. */ inline int GetFreeCapacity() const { return this->free_capacity; } /** * Get ratio of free * 16 (so that we get fewer 0) / * max(total capacity, 1) (so that we don't divide by 0). * @param free Free capacity. * @param total Total capacity. * @return free * 16 / max(total, 1). */ inline static int GetCapacityRatio(int free, uint total) { return Clamp(free, PATH_CAP_MIN_FREE, PATH_CAP_MAX_FREE) * PATH_CAP_MULTIPLIER / max(total, 1U); } /** * Get capacity ratio of this path. * @return free capacity * 16 / (total capacity + 1). */ inline int GetCapacityRatio() const { return Path::GetCapacityRatio(this->free_capacity, this->capacity); } /** Get the overall distance of the path. */ inline uint GetDistance() const { return this->distance; } /** Reduce the flow on this leg only by the specified amount. */ inline void ReduceFlow(uint f) { this->flow -= f; } /** Increase the flow on this leg only by the specified amount. */ inline void AddFlow(uint f) { this->flow += f; } /** Get the flow on this leg. */ inline uint GetFlow() const { return this->flow; } /** Get the number of "forked off" child legs of this one. */ inline uint GetNumChildren() const { return this->num_children; } /** * Detach this path from its parent. */ inline void Detach() { if (this->parent != NULL) { this->parent->num_children--; this->parent = NULL; } } uint AddFlow(uint f, LinkGraphJob &job, uint max_saturation); void Fork(Path *base, uint cap, int free_cap, uint dist); protected: /** * Some boundaries to clamp agains in order to avoid integer overflows. */ enum PathCapacityBoundaries { PATH_CAP_MULTIPLIER = 16, PATH_CAP_MIN_FREE = (INT_MIN + 1) / PATH_CAP_MULTIPLIER, PATH_CAP_MAX_FREE = (INT_MAX - 1) / PATH_CAP_MULTIPLIER }; uint distance; ///< Sum(distance of all legs up to this one). uint capacity; ///< This capacity is min(capacity) fom all edges. int free_capacity; ///< This capacity is min(edge.capacity - edge.flow) for the current run of Dijkstra. uint flow; ///< Flow the current run of the mcf solver assigns. NodeID node; ///< Link graph node this leg passes. NodeID origin; ///< Link graph node this path originates from. uint num_children; ///< Number of child legs that have been forked from this path. Path *parent; ///< Parent leg of this one. }; #endif /* LINKGRAPHJOB_H */ openttd-1.5.3/src/linkgraph/refresh.h0000644000000000000000000001101012627373441016252 0ustar rootroot/* $Id: refresh.h 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 refresh.h Declaration of link refreshing utility. */ #ifndef REFRESH_H #define REFRESH_H #include "../cargo_type.h" #include "../vehicle_base.h" #include #include #include /** * Utility to refresh links a consist will visit. */ class LinkRefresher { public: static void Run(Vehicle *v, bool allow_merge = true, bool is_full_loading = false); protected: /** * Various flags about properties of the last examined link that might have * an influence on the next one. */ enum RefreshFlags { USE_NEXT, ///< There was a conditional jump. Try to use the given next order when looking for a new one. HAS_CARGO, ///< Consist could leave the last stop where it could interact with cargo carrying cargo (i.e. not an "unload all" + "no loading" order). WAS_REFIT, ///< Consist was refit since the last stop where it could interact with cargo. RESET_REFIT, ///< Consist had a chance to load since the last refit and the refit capacities can be reset. IN_AUTOREFIT, ///< Currently doing an autorefit loop. Ignore the first autorefit order. }; /** * Simulated cargo type and capacity for prediction of future links. */ struct RefitDesc { CargoID cargo; ///< Cargo type the vehicle will be carrying. uint16 capacity; ///< Capacity the vehicle will have. uint16 remaining; ///< Capacity remaining from before the previous refit. RefitDesc(CargoID cargo, uint16 capacity, uint16 remaining) : cargo(cargo), capacity(capacity), remaining(remaining) {} }; /** * A hop the refresh algorithm might evaluate. If the same hop is seen again * the evaluation is stopped. This of course is a fairly simple heuristic. * Sequences of refit orders can produce vehicles with all kinds of * different cargoes and remembering only one can lead to early termination * of the algorithm. However, as the order language is Turing complete, we * are facing the halting problem here. At some point we have to draw the * line. */ struct Hop { OrderID from; ///< Last order where vehicle could interact with cargo or absolute first order. OrderID to; ///< Next order to be processed. CargoID cargo; ///< Cargo the consist is probably carrying or CT_INVALID if unknown. /** * Default constructor should not be called but has to be visible for * usage in std::set. */ Hop() {NOT_REACHED();} /** * Real constructor, only use this one. * @param from First order of the hop. * @param to Second order of the hop. * @param cargo Cargo the consist is probably carrying when passing the hop. */ Hop(OrderID from, OrderID to, CargoID cargo) : from(from), to(to), cargo(cargo) {} bool operator<(const Hop &other) const; }; typedef std::list RefitList; typedef std::map CapacitiesMap; typedef std::set HopSet; Vehicle *vehicle; ///< Vehicle for which the links should be refreshed. CapacitiesMap capacities; ///< Current added capacities per cargo ID in the consist. RefitList refit_capacities; ///< Current state of capacity remaining from previous refits versus overall capacity per vehicle in the consist. HopSet *seen_hops; ///< Hops already seen. If the same hop is seen twice we stop the algorithm. This is shared between all Refreshers of the same run. CargoID cargo; ///< Cargo given in last refit order. bool allow_merge; ///< If the refresher is allowed to merge or extend link graphs. bool is_full_loading; ///< If the vehicle is full loading. LinkRefresher(Vehicle *v, HopSet *seen_hops, bool allow_merge, bool is_full_loading); bool HandleRefit(CargoID refit_cargo); void ResetRefit(); void RefreshStats(const Order *cur, const Order *next); const Order *PredictNextOrder(const Order *cur, const Order *next, uint8 flags, uint num_hops = 0); void RefreshLinks(const Order *cur, const Order *next, uint8 flags, uint num_hops = 0); }; #endif /* REFRESH_H */ openttd-1.5.3/src/linkgraph/linkgraph_type.h0000644000000000000000000000554612627373441017655 0ustar rootroot/* $Id: linkgraph_type.h 26549 2014-05-01 14:50:52Z fonsinchen $ */ /* * 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 linkgraph_type.h Declaration of link graph types used for cargo distribution. */ #ifndef LINKGRAPH_TYPE_H #define LINKGRAPH_TYPE_H typedef uint16 LinkGraphID; static const LinkGraphID INVALID_LINK_GRAPH = UINT16_MAX; typedef uint16 LinkGraphJobID; static const LinkGraphID INVALID_LINK_GRAPH_JOB = UINT16_MAX; typedef uint16 NodeID; static const NodeID INVALID_NODE = UINT16_MAX; enum DistributionType { DT_BEGIN = 0, DT_MIN = 0, DT_MANUAL = 0, ///< Manual distribution. No link graph calculations are run. DT_ASYMMETRIC = 1, ///< Asymmetric distribution. Usually cargo will only travel in one direction. DT_MAX_NONSYMMETRIC = 1, ///< Maximum non-symmetric distribution. DT_SYMMETRIC = 2, ///< Symmetric distribution. The same amount of cargo travels in each direction between each pair of nodes. DT_MAX = 2, DT_NUM = 3, DT_END = 3 }; /* It needs to be 8bits, because we save and load it as such * Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT DistributionTypeByte; // typedefing-enumification of DistributionType /** * Special modes for updating links. 'Restricted' means that vehicles with * 'no loading' orders are serving the link. If a link is only served by * such vehicles it's 'fully restricted'. This means the link can be used * by cargo arriving in such vehicles, but not by cargo generated or * transferring at the source station of the link. In order to find out * about this condition we keep two update timestamps in each link, one for * the restricted and one for the unrestricted part of it. If either one * times out while the other is still valid the link becomes fully * restricted or fully unrestricted, respectively. * Refreshing a link makes just sure a minimum capacity is kept. Increasing * actually adds the given capacity. */ enum EdgeUpdateMode { EUM_INCREASE = 1, ///< Increase capacity. EUM_REFRESH = 1 << 1, ///< Refresh capacity. EUM_RESTRICTED = 1 << 2, ///< Use restricted link. EUM_UNRESTRICTED = 1 << 3, ///< Use unrestricted link. }; DECLARE_ENUM_AS_BIT_SET(EdgeUpdateMode) #endif /* LINKGRAPH_TYPE_H */ openttd-1.5.3/src/linkgraph/mcf.h0000644000000000000000000000560612627373441015377 0ustar rootroot/** @file mcf.h Declaration of Multi-Commodity-Flow solver */ #ifndef MCF_H #define MCF_H #include "linkgraphjob_base.h" #include typedef std::vector PathVector; /** * Multi-commodity flow calculating base class. */ class MultiCommodityFlow { protected: /** * Constructor. * @param job Link graph job being executed. */ MultiCommodityFlow(LinkGraphJob &job) : job(job), max_saturation(job.Settings().short_path_saturation) {} template void Dijkstra(NodeID from, PathVector &paths); uint PushFlow(Edge &edge, Path *path, uint accuracy, uint max_saturation); void CleanupPaths(NodeID source, PathVector &paths); LinkGraphJob &job; ///< Job we're working with. uint max_saturation; ///< Maximum saturation for edges. }; /** * First pass of the MCF calculation. Saturates shortest paths first, creates * new paths if needed, eliminates cycles. This calculation is of exponential * complexity in the number of nodes but the constant factors are sufficiently * small to make it usable for most real-life link graph components. You can * deal with performance problems that might occur here in multiple ways: * - The overall accuracy is used here to determine how much flow is assigned * in each loop. The lower the accuracy, the more flow is assigned, the less * loops it takes to assign all flow. * - The short_path_saturation setting determines when this pass stops. The * lower you set it, the less flow will be assigned in this pass, the less * time it will take. * - You can increase the recalculation interval to allow for longer running * times without creating lags. */ class MCF1stPass : public MultiCommodityFlow { private: bool EliminateCycles(); bool EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id); void EliminateCycle(PathVector &path, Path *cycle_begin, uint flow); uint FindCycleFlow(const PathVector &path, const Path *cycle_begin); public: MCF1stPass(LinkGraphJob &job); }; /** * Second pass of the MCF calculation. Saturates paths with most capacity left * first and doesn't create any paths along edges that haven't been visited in * the first pass. This is why it doesn't have to do any cycle detection and * elimination. As cycle detection is the most intense problem in the first * pass this pass is cheaper. The accuracy is used here, too. */ class MCF2ndPass : public MultiCommodityFlow { public: MCF2ndPass(LinkGraphJob &job); }; /** * Link graph handler for MCF. Creates MultiCommodityFlow instance according to * the template parameter. */ template class MCFHandler : public ComponentHandler { public: /** * Run the calculation. * @param graph Component to be calculated. */ virtual void Run(LinkGraphJob &job) const { Tpass pass(job); } /** * Destructor. Has to be given because of virtual Run(). */ virtual ~MCFHandler() {} }; #endif /* MCF_H */ openttd-1.5.3/src/linkgraph/demands.cpp0000644000000000000000000001756012627373441016602 0ustar rootroot/** @file demands.cpp Definition of demand calculating link graph handler. */ #include "../stdafx.h" #include "demands.h" #include #include "../safeguards.h" typedef std::list NodeList; /** * Scale various things according to symmetric/asymmetric distribution. */ class Scaler { public: void SetDemands(LinkGraphJob &job, NodeID from, NodeID to, uint demand_forw); }; /** * Scaler for symmetric distribution. */ class SymmetricScaler : public Scaler { public: /** * Constructor. * @param mod_size Size modifier to be used. Determines how much demands * increase with the supply of the remote station. */ inline SymmetricScaler(uint mod_size) : mod_size(mod_size), supply_sum(0), demand_per_node(0) {} /** * Count a node's supply into the sum of supplies. * @param node Node. */ inline void AddNode(const Node &node) { this->supply_sum += node.Supply(); } /** * Calculate the mean demand per node using the sum of supplies. * @param num_demands Number of accepting nodes. */ inline void SetDemandPerNode(uint num_demands) { this->demand_per_node = max(this->supply_sum / num_demands, 1U); } /** * Get the effective supply of one node towards another one. In symmetric * distribution the supply of the other node is weighed in. * @param from The supplying node. * @param to The receiving node. * @return Effective supply. */ inline uint EffectiveSupply(const Node &from, const Node &to) { return max(from.Supply() * max(1U, to.Supply()) * this->mod_size / 100 / this->demand_per_node, 1U); } /** * Check if there is any acceptance left for this node. In symmetric distribution * nodes only accept anything if they also supply something. So if * undelivered_supply == 0 at the node there isn't any demand left either. * @param to Node to be checked. * @return If demand is left. */ inline bool HasDemandLeft(const Node &to) { return (to.Supply() == 0 || to.UndeliveredSupply() > 0) && to.Demand() > 0; } void SetDemands(LinkGraphJob &job, NodeID from, NodeID to, uint demand_forw); private: uint mod_size; ///< Size modifier. Determines how much demands increase with the supply of the remote station. uint supply_sum; ///< Sum of all supplies in the component. uint demand_per_node; ///< Mean demand associated with each node. }; /** * A scaler for asymmetric distribution. */ class AsymmetricScaler : public Scaler { public: /** * Nothing to do here. * @param unused. */ inline void AddNode(const Node &) { } /** * Nothing to do here. * @param unused. */ inline void SetDemandPerNode(uint) { } /** * Get the effective supply of one node towards another one. * @param from The supplying node. * @param unused. */ inline uint EffectiveSupply(const Node &from, const Node &) { return from.Supply(); } /** * Check if there is any acceptance left for this node. In asymmetric distribution * nodes always accept as long as their demand > 0. * @param to The node to be checked. * @param to_anno Unused. */ inline bool HasDemandLeft(const Node &to) { return to.Demand() > 0; } }; /** * Set the demands between two nodes using the given base demand. In symmetric mode * this sets demands in both directions. * @param job The link graph job. * @param from_id The supplying node. * @param to_id The receiving node. * @param demand_forw Demand calculated for the "forward" direction. */ void SymmetricScaler::SetDemands(LinkGraphJob &job, NodeID from_id, NodeID to_id, uint demand_forw) { if (job[from_id].Demand() > 0) { uint demand_back = demand_forw * this->mod_size / 100; uint undelivered = job[to_id].UndeliveredSupply(); if (demand_back > undelivered) { demand_back = undelivered; demand_forw = max(1U, demand_back * 100 / this->mod_size); } this->Scaler::SetDemands(job, to_id, from_id, demand_back); } this->Scaler::SetDemands(job, from_id, to_id, demand_forw); } /** * Set the demands between two nodes using the given base demand. In asymmetric mode * this only sets demand in the "forward" direction. * @param job The link graph job. * @param from_id The supplying node. * @param to_id The receiving node. * @param demand_forw Demand calculated for the "forward" direction. */ inline void Scaler::SetDemands(LinkGraphJob &job, NodeID from_id, NodeID to_id, uint demand_forw) { job[from_id].DeliverSupply(to_id, demand_forw); } /** * Do the actual demand calculation, called from constructor. * @param job Job to calculate the demands for. * @tparam Tscaler Scaler to be used for scaling demands. */ template void DemandCalculator::CalcDemand(LinkGraphJob &job, Tscaler scaler) { NodeList supplies; NodeList demands; uint num_supplies = 0; uint num_demands = 0; for (NodeID node = 0; node < job.Size(); node++) { scaler.AddNode(job[node]); if (job[node].Supply() > 0) { supplies.push_back(node); num_supplies++; } if (job[node].Demand() > 0) { demands.push_back(node); num_demands++; } } if (num_supplies == 0 || num_demands == 0) return; /* Mean acceptance attributed to each node. If the distribution is * symmetric this is relative to remote supply, otherwise it is * relative to remote demand. */ scaler.SetDemandPerNode(num_demands); uint chance = 0; while (!supplies.empty() && !demands.empty()) { NodeID from_id = supplies.front(); supplies.pop_front(); for (uint i = 0; i < num_demands; ++i) { assert(!demands.empty()); NodeID to_id = demands.front(); demands.pop_front(); if (from_id == to_id) { /* Only one node with supply and demand left */ if (demands.empty() && supplies.empty()) return; demands.push_back(to_id); continue; } int32 supply = scaler.EffectiveSupply(job[from_id], job[to_id]); assert(supply > 0); /* Scale the distance by mod_dist around max_distance */ int32 distance = this->max_distance - (this->max_distance - (int32)DistanceMaxPlusManhattan(job[from_id].XY(), job[to_id].XY())) * this->mod_dist / 100; /* Scale the accuracy by distance around accuracy / 2 */ int32 divisor = this->accuracy * (this->mod_dist - 50) / 100 + this->accuracy * distance / this->max_distance + 1; assert(divisor > 0); uint demand_forw = 0; if (divisor <= supply) { /* At first only distribute demand if * effective supply / accuracy divisor >= 1 * Others are too small or too far away to be considered. */ demand_forw = supply / divisor; } else if (++chance > this->accuracy * num_demands * num_supplies) { /* After some trying, if there is still supply left, distribute * demand also to other nodes. */ demand_forw = 1; } demand_forw = min(demand_forw, job[from_id].UndeliveredSupply()); scaler.SetDemands(job, from_id, to_id, demand_forw); if (scaler.HasDemandLeft(job[to_id])) { demands.push_back(to_id); } else { num_demands--; } if (job[from_id].UndeliveredSupply() == 0) break; } if (job[from_id].UndeliveredSupply() != 0) { supplies.push_back(from_id); } else { num_supplies--; } } } /** * Create the DemandCalculator and immediately do the calculation. * @param job Job to calculate the demands for. */ DemandCalculator::DemandCalculator(LinkGraphJob &job) : max_distance(DistanceMaxPlusManhattan(TileXY(0,0), TileXY(MapMaxX(), MapMaxY()))) { const LinkGraphSettings &settings = job.Settings(); CargoID cargo = job.Cargo(); this->accuracy = settings.accuracy; this->mod_dist = settings.demand_distance; if (this->mod_dist > 100) { /* Increase effect of mod_dist > 100 */ int over100 = this->mod_dist - 100; this->mod_dist = 100 + over100 * over100; } switch (settings.GetDistributionType(cargo)) { case DT_SYMMETRIC: this->CalcDemand(job, SymmetricScaler(settings.demand_size)); break; case DT_ASYMMETRIC: this->CalcDemand(job, AsymmetricScaler()); break; default: /* Nothing to do. */ break; } } openttd-1.5.3/src/linkgraph/linkgraph_base.h0000644000000000000000000000211012627373441017566 0ustar rootroot/* $Id: linkgraph_base.h 25354 2013-06-09 12:58:37Z fonsinchen $ */ /* * 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 linkgraph_base.h Some typedefs for the main game. */ #ifndef LINKGRAPH_BASE_H #define LINKGRAPH_BASE_H #include "linkgraph.h" #include "linkgraphschedule.h" typedef LinkGraph::Node Node; typedef LinkGraph::Edge Edge; typedef LinkGraph::EdgeIterator EdgeIterator; typedef LinkGraph::ConstNode ConstNode; typedef LinkGraph::ConstEdge ConstEdge; typedef LinkGraph::ConstEdgeIterator ConstEdgeIterator; #endif /* LINKGRAPH_BASE_H */ openttd-1.5.3/src/linkgraph/linkgraphjob_base.h0000644000000000000000000000176312627373441020276 0ustar rootroot/* $Id: linkgraphjob_base.h 25371 2013-06-09 13:18:37Z rubidium $ */ /* * 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 linkgraphjob_base.h Some typedefs for component handlers. */ #ifndef LINKGRAPHJOB_BASE_H #define LINKGRAPHJOB_BASE_H #include "linkgraph.h" #include "linkgraphjob.h" #include "linkgraphschedule.h" typedef LinkGraphJob::Node Node; typedef LinkGraphJob::Edge Edge; typedef LinkGraphJob::EdgeIterator EdgeIterator; #endif /* LINKGRAPHJOB_BASE_H */ openttd-1.5.3/src/linkgraph/demands.h0000644000000000000000000000214612627373441016241 0ustar rootroot/** @file demands.h Declaration of demand calculating link graph handler. */ #ifndef DEMANDS_H #define DEMANDS_H #include "linkgraphjob_base.h" /** * Calculate the demands. This class has a state, but is recreated for each * call to of DemandHandler::Run. */ class DemandCalculator { public: DemandCalculator(LinkGraphJob &job); private: int32 max_distance; ///< Maximum distance possible on the map. int32 mod_dist; ///< Distance modifier, determines how much demands decrease with distance. int32 accuracy; ///< Accuracy of the calculation. template void CalcDemand(LinkGraphJob &job, Tscaler scaler); }; /** * Stateless, thread safe demand hander. Doesn't do anything but call DemandCalculator. */ class DemandHandler : public ComponentHandler { public: /** * Call the demand calculator on the given component. * @param graph Component to calculate the demands for. */ virtual void Run(LinkGraphJob &job) const { DemandCalculator c(job); } /** * Virtual destructor has to be defined because of virtual Run(). */ virtual ~DemandHandler() {} }; #endif /* DEMANDS_H */ openttd-1.5.3/src/linkgraph/mcf.cpp0000644000000000000000000004337212627373441015734 0ustar rootroot/** @file mcf.cpp Definition of Multi-Commodity-Flow solver. */ #include "../stdafx.h" #include "../core/math_func.hpp" #include "mcf.h" #include #include "../safeguards.h" typedef std::map PathViaMap; /** * Distance-based annotation for use in the Dijkstra algorithm. This is close * to the original meaning of "annotation" in this context. Paths are rated * according to the sum of distances of their edges. */ class DistanceAnnotation : public Path { public: /** * Constructor. * @param n ID of node to be annotated. * @param source If the node is the source of its path. */ DistanceAnnotation(NodeID n, bool source = false) : Path(n, source) {} bool IsBetter(const DistanceAnnotation *base, uint cap, int free_cap, uint dist) const; /** * Return the actual value of the annotation, in this case the distance. * @return Distance. */ inline uint GetAnnotation() const { return this->distance; } /** * Comparator for std containers. */ struct Comparator { bool operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const; }; }; /** * Capacity-based annotation for use in the Dijkstra algorithm. This annotation * rates paths according to the maximum capacity of their edges. The Dijkstra * algorithm still gives meaningful results like this as the capacity of a path * can only decrease or stay the same if you add more edges. */ class CapacityAnnotation : public Path { public: /** * Constructor. * @param n ID of node to be annotated. * @param source If the node is the source of its path. */ CapacityAnnotation(NodeID n, bool source = false) : Path(n, source) {} bool IsBetter(const CapacityAnnotation *base, uint cap, int free_cap, uint dist) const; /** * Return the actual value of the annotation, in this case the capacity. * @return Capacity. */ inline int GetAnnotation() const { return this->GetCapacityRatio(); } /** * Comparator for std containers. */ struct Comparator { bool operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const; }; }; /** * Iterator class for getting the edges in the order of their next_edge * members. */ class GraphEdgeIterator { private: LinkGraphJob &job; ///< Job being executed EdgeIterator i; ///< Iterator pointing to current edge. EdgeIterator end; ///< Iterator pointing beyond last edge. public: /** * Construct a GraphEdgeIterator. * @param job Job to iterate on. */ GraphEdgeIterator(LinkGraphJob &job) : job(job), i(NULL, NULL, INVALID_NODE), end(NULL, NULL, INVALID_NODE) {} /** * Setup the node to start iterating at. * @param source Unused. * @param node Node to start iterating at. */ void SetNode(NodeID source, NodeID node) { this->i = this->job[node].Begin(); this->end = this->job[node].End(); } /** * Retrieve the ID of the node the next edge points to. * @return Next edge's target node ID or INVALID_NODE. */ NodeID Next() { return this->i != this->end ? (this->i++)->first : INVALID_NODE; } }; /** * Iterator class for getting edges from a FlowStatMap. */ class FlowEdgeIterator { private: LinkGraphJob &job; ///< Link graph job we're working with. /** Lookup table for getting NodeIDs from StationIDs. */ std::map station_to_node; /** Current iterator in the shares map. */ FlowStat::SharesMap::const_iterator it; /** End of the shares map. */ FlowStat::SharesMap::const_iterator end; public: /** * Constructor. * @param job Link graph job to work with. */ FlowEdgeIterator(LinkGraphJob &job) : job(job) { for (NodeID i = 0; i < job.Size(); ++i) { this->station_to_node[job[i].Station()] = i; } } /** * Setup the node to retrieve edges from. * @param source Root of the current path tree. * @param node Current node to be checked for outgoing flows. */ void SetNode(NodeID source, NodeID node) { const FlowStatMap &flows = this->job[node].Flows(); FlowStatMap::const_iterator it = flows.find(this->job[source].Station()); if (it != flows.end()) { this->it = it->second.GetShares()->begin(); this->end = it->second.GetShares()->end(); } else { this->it = FlowStat::empty_sharesmap.begin(); this->end = FlowStat::empty_sharesmap.end(); } } /** * Get the next node for which a flow exists. * @return ID of next node with flow. */ NodeID Next() { if (this->it == this->end) return INVALID_NODE; return this->station_to_node[(this->it++)->second]; } }; /** * Determines if an extension to the given Path with the given parameters is * better than this path. * @param base Other path. * @param cap Capacity of the new edge to be added to base. * @param dist Distance of the new edge. * @return True if base + the new edge would be better than the path associated * with this annotation. */ bool DistanceAnnotation::IsBetter(const DistanceAnnotation *base, uint cap, int free_cap, uint dist) const { /* If any of the paths is disconnected, the other one is better. If both * are disconnected, this path is better.*/ if (base->distance == UINT_MAX) { return false; } else if (this->distance == UINT_MAX) { return true; } if (free_cap > 0 && base->free_capacity > 0) { /* If both paths have capacity left, compare their distances. * If the other path has capacity left and this one hasn't, the * other one's better (thus, return true). */ return this->free_capacity > 0 ? (base->distance + dist < this->distance) : true; } else { /* If the other path doesn't have capacity left, but this one has, * the other one is worse (thus, return false). * If both paths are out of capacity, do the regular distance * comparison. */ return this->free_capacity > 0 ? false : (base->distance + dist < this->distance); } } /** * Determines if an extension to the given Path with the given parameters is * better than this path. * @param base Other path. * @param cap Capacity of the new edge to be added to base. * @param dist Distance of the new edge. * @return True if base + the new edge would be better than the path associated * with this annotation. */ bool CapacityAnnotation::IsBetter(const CapacityAnnotation *base, uint cap, int free_cap, uint dist) const { int min_cap = Path::GetCapacityRatio(min(base->free_capacity, free_cap), min(base->capacity, cap)); int this_cap = this->GetCapacityRatio(); if (min_cap == this_cap) { /* If the capacities are the same and the other path isn't disconnected * choose the shorter path. */ return base->distance == UINT_MAX ? false : (base->distance + dist < this->distance); } else { return min_cap > this_cap; } } /** * A slightly modified Dijkstra algorithm. Grades the paths not necessarily by * distance, but by the value Tannotation computes. It uses the max_saturation * setting to artificially decrease capacities. * @tparam Tannotation Annotation to be used. * @tparam Tedge_iterator Iterator to be used for getting outgoing edges. * @param source_node Node where the algorithm starts. * @param paths Container for the paths to be calculated. */ template void MultiCommodityFlow::Dijkstra(NodeID source_node, PathVector &paths) { typedef std::set AnnoSet; Tedge_iterator iter(this->job); uint size = this->job.Size(); AnnoSet annos; paths.resize(size, NULL); for (NodeID node = 0; node < size; ++node) { Tannotation *anno = new Tannotation(node, node == source_node); annos.insert(anno); paths[node] = anno; } while (!annos.empty()) { typename AnnoSet::iterator i = annos.begin(); Tannotation *source = *i; annos.erase(i); NodeID from = source->GetNode(); iter.SetNode(source_node, from); for (NodeID to = iter.Next(); to != INVALID_NODE; to = iter.Next()) { if (to == from) continue; // Not a real edge but a consumption sign. Edge edge = this->job[from][to]; uint capacity = edge.Capacity(); if (this->max_saturation != UINT_MAX) { capacity *= this->max_saturation; capacity /= 100; if (capacity == 0) capacity = 1; } /* punish in-between stops a little */ uint distance = DistanceMaxPlusManhattan(this->job[from].XY(), this->job[to].XY()) + 1; Tannotation *dest = static_cast(paths[to]); if (dest->IsBetter(source, capacity, capacity - edge.Flow(), distance)) { annos.erase(dest); dest->Fork(source, capacity, capacity - edge.Flow(), distance); annos.insert(dest); } } } } /** * Clean up paths that lead nowhere and the root path. * @param source_id ID of the root node. * @param paths Paths to be cleaned up. */ void MultiCommodityFlow::CleanupPaths(NodeID source_id, PathVector &paths) { Path *source = paths[source_id]; paths[source_id] = NULL; for (PathVector::iterator i = paths.begin(); i != paths.end(); ++i) { Path *path = *i; if (path == NULL) continue; if (path->GetParent() == source) path->Detach(); while (path != source && path != NULL && path->GetFlow() == 0) { Path *parent = path->GetParent(); path->Detach(); if (path->GetNumChildren() == 0) { paths[path->GetNode()] = NULL; delete path; } path = parent; } } delete source; paths.clear(); } /** * Push flow along a path and update the unsatisfied_demand of the associated * edge. * @param edge Edge whose ends the path connects. * @param path End of the path the flow should be pushed on. * @param accuracy Accuracy of the calculation. * @param max_saturation If < UINT_MAX only push flow up to the given * saturation, otherwise the path can be "overloaded". */ uint MultiCommodityFlow::PushFlow(Edge &edge, Path *path, uint accuracy, uint max_saturation) { assert(edge.UnsatisfiedDemand() > 0); uint flow = Clamp(edge.Demand() / accuracy, 1, edge.UnsatisfiedDemand()); flow = path->AddFlow(flow, this->job, max_saturation); edge.SatisfyDemand(flow); return flow; } /** * Find the flow along a cycle including cycle_begin in path. * @param path Set of paths that form the cycle. * @param cycle_begin Path to start at. * @return Flow along the cycle. */ uint MCF1stPass::FindCycleFlow(const PathVector &path, const Path *cycle_begin) { uint flow = UINT_MAX; const Path *cycle_end = cycle_begin; do { flow = min(flow, cycle_begin->GetFlow()); cycle_begin = path[cycle_begin->GetNode()]; } while (cycle_begin != cycle_end); return flow; } /** * Eliminate a cycle of the given flow in the given set of paths. * @param path Set of paths containing the cycle. * @param cycle_begin Part of the cycle to start at. * @param flow Flow along the cycle. */ void MCF1stPass::EliminateCycle(PathVector &path, Path *cycle_begin, uint flow) { Path *cycle_end = cycle_begin; do { NodeID prev = cycle_begin->GetNode(); cycle_begin->ReduceFlow(flow); if (cycle_begin->GetFlow() == 0) { PathList &node_paths = this->job[cycle_begin->GetParent()->GetNode()].Paths(); for (PathList::iterator i = node_paths.begin(); i != node_paths.end(); ++i) { if (*i == cycle_begin) { node_paths.erase(i); node_paths.push_back(cycle_begin); break; } } } cycle_begin = path[prev]; Edge edge = this->job[prev][cycle_begin->GetNode()]; edge.RemoveFlow(flow); } while (cycle_begin != cycle_end); } /** * Eliminate cycles for origin_id in the graph. Start searching at next_id and * work recursively. Also "summarize" paths: Add up the flows along parallel * paths in one. * @param path Paths checked in parent calls to this method. * @param origin_id Origin of the paths to be checked. * @param next_id Next node to be checked. * @return If any cycles have been found and eliminated. */ bool MCF1stPass::EliminateCycles(PathVector &path, NodeID origin_id, NodeID next_id) { Path *at_next_pos = path[next_id]; /* this node has already been searched */ if (at_next_pos == Path::invalid_path) return false; if (at_next_pos == NULL) { /* Summarize paths; add up the paths with the same source and next hop * in one path each. */ PathList &paths = this->job[next_id].Paths(); PathViaMap next_hops; for (PathList::iterator i = paths.begin(); i != paths.end();) { Path *new_child = *i; uint new_flow = new_child->GetFlow(); if (new_flow == 0) break; if (new_child->GetOrigin() == origin_id) { PathViaMap::iterator via_it = next_hops.find(new_child->GetNode()); if (via_it == next_hops.end()) { next_hops[new_child->GetNode()] = new_child; ++i; } else { Path *child = via_it->second; child->AddFlow(new_flow); new_child->ReduceFlow(new_flow); /* We might hit end() with with the ++ here and skip the * newly push_back'ed path. That's good as the flow of that * path is 0 anyway. */ paths.erase(i++); paths.push_back(new_child); } } else { ++i; } } bool found = false; /* Search the next hops for nodes we have already visited */ for (PathViaMap::iterator via_it = next_hops.begin(); via_it != next_hops.end(); ++via_it) { Path *child = via_it->second; if (child->GetFlow() > 0) { /* Push one child into the path vector and search this child's * children. */ path[next_id] = child; found = this->EliminateCycles(path, origin_id, child->GetNode()) || found; } } /* All paths departing from this node have been searched. Mark as * resolved if no cycles found. If cycles were found further cycles * could be found in this branch, thus it has to be searched again next * time we spot it. */ path[next_id] = found ? NULL : Path::invalid_path; return found; } /* This node has already been visited => we have a cycle. * Backtrack to find the exact flow. */ uint flow = this->FindCycleFlow(path, at_next_pos); if (flow > 0) { this->EliminateCycle(path, at_next_pos, flow); return true; } return false; } /** * Eliminate all cycles in the graph. Check paths starting at each node for * potential cycles. * @return If any cycles have been found and eliminated. */ bool MCF1stPass::EliminateCycles() { bool cycles_found = false; uint size = this->job.Size(); PathVector path(size, NULL); for (NodeID node = 0; node < size; ++node) { /* Starting at each node in the graph find all cycles involving this * node. */ std::fill(path.begin(), path.end(), (Path *)NULL); cycles_found |= this->EliminateCycles(path, node, node); } return cycles_found; } /** * Run the first pass of the MCF calculation. * @param job Link graph job to calculate. */ MCF1stPass::MCF1stPass(LinkGraphJob &job) : MultiCommodityFlow(job) { PathVector paths; uint size = job.Size(); uint accuracy = job.Settings().accuracy; bool more_loops; do { more_loops = false; for (NodeID source = 0; source < size; ++source) { /* First saturate the shortest paths. */ this->Dijkstra(source, paths); for (NodeID dest = 0; dest < size; ++dest) { Edge edge = job[source][dest]; if (edge.UnsatisfiedDemand() > 0) { Path *path = paths[dest]; assert(path != NULL); /* Generally only allow paths that don't exceed the * available capacity. But if no demand has been assigned * yet, make an exception and allow any valid path *once*. */ if (path->GetFreeCapacity() > 0 && this->PushFlow(edge, path, accuracy, this->max_saturation) > 0) { /* If a path has been found there is a chance we can * find more. */ more_loops = more_loops || (edge.UnsatisfiedDemand() > 0); } else if (edge.UnsatisfiedDemand() == edge.Demand() && path->GetFreeCapacity() > INT_MIN) { this->PushFlow(edge, path, accuracy, UINT_MAX); } } } this->CleanupPaths(source, paths); } } while (more_loops || this->EliminateCycles()); } /** * Run the second pass of the MCF calculation which assigns all remaining * demands to existing paths. * @param job Link graph job to calculate. */ MCF2ndPass::MCF2ndPass(LinkGraphJob &job) : MultiCommodityFlow(job) { this->max_saturation = UINT_MAX; // disable artificial cap on saturation PathVector paths; uint size = job.Size(); uint accuracy = job.Settings().accuracy; bool demand_left = true; while (demand_left) { demand_left = false; for (NodeID source = 0; source < size; ++source) { this->Dijkstra(source, paths); for (NodeID dest = 0; dest < size; ++dest) { Edge edge = this->job[source][dest]; Path *path = paths[dest]; if (edge.UnsatisfiedDemand() > 0 && path->GetFreeCapacity() > INT_MIN) { this->PushFlow(edge, path, accuracy, UINT_MAX); if (edge.UnsatisfiedDemand() > 0) demand_left = true; } } this->CleanupPaths(source, paths); } } } /** * Relation that creates a weak order without duplicates. * Avoid accidentally deleting different paths of the same capacity/distance in * a set. When the annotation is the same node IDs are compared, so there are * no equal ranges. * @tparam T Type to be compared on. * @param x_anno First value. * @param y_anno Second value. * @param x Node id associated with the first value. * @param y Node id associated with the second value. */ template bool Greater(T x_anno, T y_anno, NodeID x, NodeID y) { if (x_anno > y_anno) return true; if (x_anno < y_anno) return false; return x > y; } /** * Compare two capacity annotations. * @param x First capacity annotation. * @param y Second capacity annotation. * @return If x is better than y. */ bool CapacityAnnotation::Comparator::operator()(const CapacityAnnotation *x, const CapacityAnnotation *y) const { return x != y && Greater(x->GetAnnotation(), y->GetAnnotation(), x->GetNode(), y->GetNode()); } /** * Compare two distance annotations. * @param x First distance annotation. * @param y Second distance annotation. * @return If x is better than y. */ bool DistanceAnnotation::Comparator::operator()(const DistanceAnnotation *x, const DistanceAnnotation *y) const { return x != y && !Greater(x->GetAnnotation(), y->GetAnnotation(), x->GetNode(), y->GetNode()); } openttd-1.5.3/src/linkgraph/linkgraphjob.cpp0000644000000000000000000002175412627373441017641 0ustar rootroot/* $Id: linkgraphjob.cpp 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 linkgraphjob.cpp Definition of link graph job classes used for cargo distribution. */ #include "../stdafx.h" #include "../core/pool_func.hpp" #include "../window_func.h" #include "linkgraphjob.h" #include "linkgraphschedule.h" #include "../safeguards.h" /* Initialize the link-graph-job-pool */ LinkGraphJobPool _link_graph_job_pool("LinkGraphJob"); INSTANTIATE_POOL_METHODS(LinkGraphJob) /** * Static instance of an invalid path. * Note: This instance is created on task start. * Lazy creation on first usage results in a data race between the CDist threads. */ /* static */ Path *Path::invalid_path = new Path(INVALID_NODE, true); /** * Create a link graph job from a link graph. The link graph will be copied so * that the calculations don't interfer with the normal operations on the * original. The job is immediately started. * @param orig Original LinkGraph to be copied. */ LinkGraphJob::LinkGraphJob(const LinkGraph &orig) : /* Copying the link graph here also copies its index member. * This is on purpose. */ link_graph(orig), settings(_settings_game.linkgraph), thread(NULL), join_date(_date + _settings_game.linkgraph.recalc_time) { } /** * Erase all flows originating at a specific node. * @param from Node to erase flows for. */ void LinkGraphJob::EraseFlows(NodeID from) { for (NodeID node_id = 0; node_id < this->Size(); ++node_id) { (*this)[node_id].Flows().erase(from); } } /** * Spawn a thread if possible and run the link graph job in the thread. If * that's not possible run the job right now in the current thread. */ void LinkGraphJob::SpawnThread() { if (!ThreadObject::New(&(LinkGraphSchedule::Run), this, &this->thread)) { this->thread = NULL; /* Of course this will hang a bit. * On the other hand, if you want to play games which make this hang noticably * on a platform without threads then you'll probably get other problems first. * OK: * If someone comes and tells me that this hangs for him/her, I'll implement a * smaller grained "Step" method for all handlers and add some more ticks where * "Step" is called. No problem in principle. */ LinkGraphSchedule::Run(this); } } /** * Join the calling thread with this job's thread if threading is enabled. */ void LinkGraphJob::JoinThread() { if (this->thread != NULL) { this->thread->Join(); delete this->thread; this->thread = NULL; } } /** * Join the link graph job and destroy it. */ LinkGraphJob::~LinkGraphJob() { this->JoinThread(); /* Don't update stuff from other pools, when everything is being removed. * Accessing other pools may be invalid. */ if (CleaningPool()) return; /* Link graph has been merged into another one. */ if (!LinkGraph::IsValidID(this->link_graph.index)) return; uint size = this->Size(); for (NodeID node_id = 0; node_id < size; ++node_id) { Node from = (*this)[node_id]; /* The station can have been deleted. Remove all flows originating from it then. */ Station *st = Station::GetIfValid(from.Station()); if (st == NULL) { this->EraseFlows(node_id); continue; } /* Link graph merging and station deletion may change around IDs. Make * sure that everything is still consistent or ignore it otherwise. */ GoodsEntry &ge = st->goods[this->Cargo()]; if (ge.link_graph != this->link_graph.index || ge.node != node_id) { this->EraseFlows(node_id); continue; } LinkGraph *lg = LinkGraph::Get(ge.link_graph); FlowStatMap &flows = from.Flows(); for (EdgeIterator it(from.Begin()); it != from.End(); ++it) { if (from[it->first].Flow() == 0) continue; StationID to = (*this)[it->first].Station(); Station *st2 = Station::GetIfValid(to); if (st2 == NULL || st2->goods[this->Cargo()].link_graph != this->link_graph.index || st2->goods[this->Cargo()].node != it->first || (*lg)[node_id][it->first].LastUpdate() == INVALID_DATE) { /* Edge has been removed. Delete flows. */ StationIDStack erased = flows.DeleteFlows(to); /* Delete old flows for source stations which have been deleted * from the new flows. This avoids flow cycles between old and * new flows. */ while (!erased.IsEmpty()) ge.flows.erase(erased.Pop()); } else if ((*lg)[node_id][it->first].LastUnrestrictedUpdate() == INVALID_DATE) { /* Edge is fully restricted. */ flows.RestrictFlows(to); } } /* Swap shares and invalidate ones that are completely deleted. Don't * really delete them as we could then end up with unroutable cargo * somewhere. Do delete them and also reroute relevant cargo if * automatic distribution has been turned off for that cargo. */ for (FlowStatMap::iterator it(ge.flows.begin()); it != ge.flows.end();) { FlowStatMap::iterator new_it = flows.find(it->first); if (new_it == flows.end()) { if (_settings_game.linkgraph.GetDistributionType(this->Cargo()) != DT_MANUAL) { it->second.Invalidate(); ++it; } else { FlowStat shares(INVALID_STATION, 1); it->second.SwapShares(shares); ge.flows.erase(it++); for (FlowStat::SharesMap::const_iterator shares_it(shares.GetShares()->begin()); shares_it != shares.GetShares()->end(); ++shares_it) { RerouteCargo(st, this->Cargo(), shares_it->second, st->index); } } } else { it->second.SwapShares(new_it->second); flows.erase(new_it); ++it; } } ge.flows.insert(flows.begin(), flows.end()); InvalidateWindowData(WC_STATION_VIEW, st->index, this->Cargo()); } } /** * Initialize the link graph job: Resize nodes and edges and populate them. * This is done after the constructor so that we can do it in the calculation * thread without delaying the main game. */ void LinkGraphJob::Init() { uint size = this->Size(); this->nodes.Resize(size); this->edges.Resize(size, size); for (uint i = 0; i < size; ++i) { this->nodes[i].Init(this->link_graph[i].Supply()); EdgeAnnotation *node_edges = this->edges[i]; for (uint j = 0; j < size; ++j) { node_edges[j].Init(); } } } /** * Initialize a linkgraph job edge. */ void LinkGraphJob::EdgeAnnotation::Init() { this->demand = 0; this->flow = 0; this->unsatisfied_demand = 0; } /** * Initialize a Linkgraph job node. The underlying memory is expected to be * freshly allocated, without any constructors having been called. * @param supply Initial undelivered supply. */ void LinkGraphJob::NodeAnnotation::Init(uint supply) { this->undelivered_supply = supply; new (&this->flows) FlowStatMap; new (&this->paths) PathList; } /** * Add this path as a new child to the given base path, thus making this path * a "fork" of the base path. * @param base Path to fork from. * @param cap Maximum capacity of the new leg. * @param free_cap Remaining free capacity of the new leg. * @param dist Distance of the new leg. */ void Path::Fork(Path *base, uint cap, int free_cap, uint dist) { this->capacity = min(base->capacity, cap); this->free_capacity = min(base->free_capacity, free_cap); this->distance = base->distance + dist; assert(this->distance > 0); if (this->parent != base) { this->Detach(); this->parent = base; this->parent->num_children++; } this->origin = base->origin; } /** * Push some flow along a path and register the path in the nodes it passes if * successful. * @param new_flow Amount of flow to push. * @param job Link graph job this node belongs to. * @param max_saturation Maximum saturation of edges. * @return Amount of flow actually pushed. */ uint Path::AddFlow(uint new_flow, LinkGraphJob &job, uint max_saturation) { if (this->parent != NULL) { LinkGraphJob::Edge edge = job[this->parent->node][this->node]; if (max_saturation != UINT_MAX) { uint usable_cap = edge.Capacity() * max_saturation / 100; if (usable_cap > edge.Flow()) { new_flow = min(new_flow, usable_cap - edge.Flow()); } else { return 0; } } new_flow = this->parent->AddFlow(new_flow, job, max_saturation); if (this->flow == 0 && new_flow > 0) { job[this->parent->node].Paths().push_front(this); } edge.AddFlow(new_flow); } this->flow += new_flow; return new_flow; } /** * Create a leg of a path in the link graph. * @param n Id of the link graph node this path passes. * @param source If true, this is the first leg of the path. */ Path::Path(NodeID n, bool source) : distance(source ? 0 : UINT_MAX), capacity(source ? UINT_MAX : 0), free_capacity(source ? INT_MAX : INT_MIN), flow(0), node(n), origin(source ? n : INVALID_NODE), num_children(0), parent(NULL) {} openttd-1.5.3/src/linkgraph/linkgraphschedule.cpp0000644000000000000000000001074412627373441020660 0ustar rootroot/* $Id: linkgraphschedule.cpp 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 linkgraphschedule.cpp Definition of link graph schedule used for cargo distribution. */ #include "../stdafx.h" #include "linkgraphschedule.h" #include "init.h" #include "demands.h" #include "mcf.h" #include "flowmapper.h" #include "../safeguards.h" /** * Static instance of LinkGraphSchedule. * Note: This instance is created on task start. * Lazy creation on first usage results in a data race between the CDist threads. */ /* static */ LinkGraphSchedule LinkGraphSchedule::instance; /** * Start the next job in the schedule. */ void LinkGraphSchedule::SpawnNext() { if (this->schedule.empty()) return; LinkGraph *next = this->schedule.front(); LinkGraph *first = next; while (next->Size() < 2) { this->schedule.splice(this->schedule.end(), this->schedule, this->schedule.begin()); next = this->schedule.front(); if (next == first) return; } assert(next == LinkGraph::Get(next->index)); this->schedule.pop_front(); if (LinkGraphJob::CanAllocateItem()) { LinkGraphJob *job = new LinkGraphJob(*next); job->SpawnThread(); this->running.push_back(job); } else { NOT_REACHED(); } } /** * Join the next finished job, if available. */ void LinkGraphSchedule::JoinNext() { if (this->running.empty()) return; LinkGraphJob *next = this->running.front(); if (!next->IsFinished()) return; this->running.pop_front(); LinkGraphID id = next->LinkGraphIndex(); delete next; // implicitly joins the thread if (LinkGraph::IsValidID(id)) { LinkGraph *lg = LinkGraph::Get(id); this->Unqueue(lg); // Unqueue to avoid double-queueing recycled IDs. this->Queue(lg); } } /** * Run all handlers for the given Job. This method is tailored to * ThreadObject::New. * @param j Pointer to a link graph job. */ /* static */ void LinkGraphSchedule::Run(void *j) { LinkGraphJob *job = (LinkGraphJob *)j; for (uint i = 0; i < lengthof(instance.handlers); ++i) { instance.handlers[i]->Run(*job); } } /** * Start all threads in the running list. This is only useful for save/load. * Usually threads are started when the job is created. */ void LinkGraphSchedule::SpawnAll() { for (JobList::iterator i = this->running.begin(); i != this->running.end(); ++i) { (*i)->SpawnThread(); } } /** * Clear all link graphs and jobs from the schedule. */ /* static */ void LinkGraphSchedule::Clear() { for (JobList::iterator i(instance.running.begin()); i != instance.running.end(); ++i) { (*i)->JoinThread(); } instance.running.clear(); instance.schedule.clear(); } /** * Shift all dates (join dates and edge annotations) of link graphs and link * graph jobs by the number of days given. * @param interval Number of days to be added or subtracted. */ void LinkGraphSchedule::ShiftDates(int interval) { LinkGraph *lg; FOR_ALL_LINK_GRAPHS(lg) lg->ShiftDates(interval); LinkGraphJob *lgj; FOR_ALL_LINK_GRAPH_JOBS(lgj) lgj->ShiftJoinDate(interval); } /** * Create a link graph schedule and initialize its handlers. */ LinkGraphSchedule::LinkGraphSchedule() { this->handlers[0] = new InitHandler; this->handlers[1] = new DemandHandler; this->handlers[2] = new MCFHandler; this->handlers[3] = new FlowMapper(false); this->handlers[4] = new MCFHandler; this->handlers[5] = new FlowMapper(true); } /** * Delete a link graph schedule and its handlers. */ LinkGraphSchedule::~LinkGraphSchedule() { this->Clear(); for (uint i = 0; i < lengthof(this->handlers); ++i) { delete this->handlers[i]; } } /** * Spawn or join a link graph job or compress a link graph if any link graph is * due to do so. */ void OnTick_LinkGraph() { if (_date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return; Date offset = _date % _settings_game.linkgraph.recalc_interval; if (offset == 0) { LinkGraphSchedule::instance.SpawnNext(); } else if (offset == _settings_game.linkgraph.recalc_interval / 2) { LinkGraphSchedule::instance.JoinNext(); } } openttd-1.5.3/src/linkgraph/linkgraph.h0000644000000000000000000004047212627373441016611 0ustar rootroot/* $Id: linkgraph.h 26646 2014-06-14 13:35:39Z fonsinchen $ */ /* * 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 linkgraph.h Declaration of link graph classes used for cargo distribution. */ #ifndef LINKGRAPH_H #define LINKGRAPH_H #include "../core/pool_type.hpp" #include "../core/smallmap_type.hpp" #include "../core/smallmatrix_type.hpp" #include "../station_base.h" #include "../cargotype.h" #include "../date_func.h" #include "linkgraph_type.h" struct SaveLoad; class LinkGraph; /** * Type of the pool for link graph components. Each station can be in at up to * 32 link graphs. So we allow for plenty of them to be created. */ typedef Pool LinkGraphPool; /** The actual pool with link graphs. */ extern LinkGraphPool _link_graph_pool; /** * A connected component of a link graph. Contains a complete set of stations * connected by links as nodes and edges. Each component also holds a copy of * the link graph settings at the time of its creation. The global settings * might change between the creation and join time so we can't rely on them. */ class LinkGraph : public LinkGraphPool::PoolItem<&_link_graph_pool> { public: /** * Node of the link graph. contains all relevant information from the associated * station. It's copied so that the link graph job can work on its own data set * in a separate thread. */ struct BaseNode { uint supply; ///< Supply at the station. uint demand; ///< Acceptance at the station. StationID station; ///< Station ID. TileIndex xy; ///< Location of the station referred to by the node. Date last_update; ///< When the supply was last updated. void Init(TileIndex xy = INVALID_TILE, StationID st = INVALID_STATION, uint demand = 0); }; /** * An edge in the link graph. Corresponds to a link between two stations or at * least the distance between them. Edges from one node to itself contain the * ID of the opposite Node of the first active edge (i.e. not just distance) in * the column as next_edge. */ struct BaseEdge { uint capacity; ///< Capacity of the link. uint usage; ///< Usage of the link. Date last_unrestricted_update; ///< When the unrestricted part of the link was last updated. Date last_restricted_update; ///< When the restricted part of the link was last updated. NodeID next_edge; ///< Destination of next valid edge starting at the same source node. void Init(); }; /** * Wrapper for an edge (const or not) allowing retrieval, but no modification. * @tparam Tedge Actual edge class, may be "const BaseEdge" or just "BaseEdge". */ template class EdgeWrapper { protected: Tedge &edge; ///< Actual edge to be used. public: /** * Wrap a an edge. * @param edge Edge to be wrapped. */ EdgeWrapper (Tedge &edge) : edge(edge) {} /** * Get edge's capacity. * @return Capacity. */ uint Capacity() const { return this->edge.capacity; } /** * Get edge's usage. * @return Usage. */ uint Usage() const { return this->edge.usage; } /** * Get the date of the last update to the edge's unrestricted capacity. * @return Last update. */ Date LastUnrestrictedUpdate() const { return this->edge.last_unrestricted_update; } /** * Get the date of the last update to the edge's restricted capacity. * @return Last update. */ Date LastRestrictedUpdate() const { return this->edge.last_restricted_update; } /** * Get the date of the last update to any part of the edge's capacity. * @return Last update. */ Date LastUpdate() const { return max(this->edge.last_unrestricted_update, this->edge.last_restricted_update); } }; /** * Wrapper for a node (const or not) allowing retrieval, but no modification. * @tparam Tedge Actual node class, may be "const BaseNode" or just "BaseNode". * @tparam Tedge Actual edge class, may be "const BaseEdge" or just "BaseEdge". */ template class NodeWrapper { protected: Tnode &node; ///< Node being wrapped. Tedge *edges; ///< Outgoing edges for wrapped node. NodeID index; ///< ID of wrapped node. public: /** * Wrap a node. * @param node Node to be wrapped. * @param edges Outgoing edges for node to be wrapped. * @param index ID of node to be wrapped. */ NodeWrapper(Tnode &node, Tedge *edges, NodeID index) : node(node), edges(edges), index(index) {} /** * Get supply of wrapped node. * @return Supply. */ uint Supply() const { return this->node.supply; } /** * Get demand of wrapped node. * @return Demand. */ uint Demand() const { return this->node.demand; } /** * Get ID of station belonging to wrapped node. * @return ID of node's station. */ StationID Station() const { return this->node.station; } /** * Get node's last update. * @return Last update. */ Date LastUpdate() const { return this->node.last_update; } /** * Get the location of the station associated with the node. * @return Location of the station. */ TileIndex XY() const { return this->node.xy; } }; /** * Base class for iterating across outgoing edges of a node. Only the real * edges (those with capacity) are iterated. The ones with only distance * information are skipped. * @tparam Tedge Actual edge class. May be "BaseEdge" or "const BaseEdge". * @tparam Titer Actual iterator class. */ template class BaseEdgeIterator { protected: Tedge *base; ///< Array of edges being iterated. NodeID current; ///< Current offset in edges array. /** * A "fake" pointer to enable operator-> on temporaries. As the objects * returned from operator* aren't references but real objects, we have * to return something that implements operator->, but isn't a pointer * from operator->. A fake pointer. */ class FakePointer : public SmallPair { public: /** * Construct a fake pointer from a pair of NodeID and edge. * @param pair Pair to be "pointed" to (in fact shallow-copied). */ FakePointer(const SmallPair &pair) : SmallPair(pair) {} /** * Retrieve the pair by operator->. * @return Pair being "pointed" to. */ SmallPair *operator->() { return this; } }; public: /** * Constructor. * @param base Array of edges to be iterated. * @param current ID of current node (to locate the first edge). */ BaseEdgeIterator (Tedge *base, NodeID current) : base(base), current(current == INVALID_NODE ? current : base[current].next_edge) {} /** * Prefix-increment. * @return This. */ Titer &operator++() { this->current = this->base[this->current].next_edge; return static_cast(*this); } /** * Postfix-increment. * @return Version of this before increment. */ Titer operator++(int) { Titer ret(static_cast(*this)); this->current = this->base[this->current].next_edge; return ret; } /** * Compare with some other edge iterator. The other one may be of a * child class. * @tparam Tother Class of other iterator. * @param other Instance of other iterator. * @return If the iterators have the same edge array and current node. */ template bool operator==(const Tother &other) { return this->base == other.base && this->current == other.current; } /** * Compare for inequality with some other edge iterator. The other one * may be of a child class. * @tparam Tother Class of other iterator. * @param other Instance of other iterator. * @return If either the edge arrays or the current nodes differ. */ template bool operator!=(const Tother &other) { return this->base != other.base || this->current != other.current; } /** * Dereference with operator*. * @return Pair of current target NodeID and edge object. */ SmallPair operator*() const { return SmallPair(this->current, Tedge_wrapper(this->base[this->current])); } /** * Dereference with operator->. * @return Fake pointer to Pair of current target NodeID and edge object. */ FakePointer operator->() const { return FakePointer(this->operator*()); } }; /** * A constant edge class. */ typedef EdgeWrapper ConstEdge; /** * An updatable edge class. */ class Edge : public EdgeWrapper { public: /** * Constructor * @param edge Edge to be wrapped. */ Edge(BaseEdge &edge) : EdgeWrapper(edge) {} void Update(uint capacity, uint usage, EdgeUpdateMode mode); void Restrict() { this->edge.last_unrestricted_update = INVALID_DATE; } void Release() { this->edge.last_restricted_update = INVALID_DATE; } }; /** * An iterator for const edges. Cannot be typedef'ed because of * template-reference to ConstEdgeIterator itself. */ class ConstEdgeIterator : public BaseEdgeIterator { public: /** * Constructor. * @param edges Array of edges to be iterated over. * @param current ID of current edge's end node. */ ConstEdgeIterator(const BaseEdge *edges, NodeID current) : BaseEdgeIterator(edges, current) {} }; /** * An iterator for non-const edges. Cannot be typedef'ed because of * template-reference to EdgeIterator itself. */ class EdgeIterator : public BaseEdgeIterator { public: /** * Constructor. * @param edges Array of edges to be iterated over. * @param current ID of current edge's end node. */ EdgeIterator(BaseEdge *edges, NodeID current) : BaseEdgeIterator(edges, current) {} }; /** * Constant node class. Only retrieval operations are allowed on both the * node itself and its edges. */ class ConstNode : public NodeWrapper { public: /** * Constructor. * @param lg LinkGraph to get the node from. * @param node ID of the node. */ ConstNode(const LinkGraph *lg, NodeID node) : NodeWrapper(lg->nodes[node], lg->edges[node], node) {} /** * Get a ConstEdge. This is not a reference as the wrapper objects are * not actually persistent. * @param to ID of end node of edge. * @return Constant edge wrapper. */ ConstEdge operator[](NodeID to) const { return ConstEdge(this->edges[to]); } /** * Get an iterator pointing to the start of the edges array. * @return Constant edge iterator. */ ConstEdgeIterator Begin() const { return ConstEdgeIterator(this->edges, this->index); } /** * Get an iterator pointing beyond the end of the edges array. * @return Constant edge iterator. */ ConstEdgeIterator End() const { return ConstEdgeIterator(this->edges, INVALID_NODE); } }; /** * Updatable node class. The node itself as well as its edges can be modified. */ class Node : public NodeWrapper { public: /** * Constructor. * @param lg LinkGraph to get the node from. * @param node ID of the node. */ Node(LinkGraph *lg, NodeID node) : NodeWrapper(lg->nodes[node], lg->edges[node], node) {} /** * Get an Edge. This is not a reference as the wrapper objects are not * actually persistent. * @param to ID of end node of edge. * @return Edge wrapper. */ Edge operator[](NodeID to) { return Edge(this->edges[to]); } /** * Get an iterator pointing to the start of the edges array. * @return Edge iterator. */ EdgeIterator Begin() { return EdgeIterator(this->edges, this->index); } /** * Get an iterator pointing beyond the end of the edges array. * @return Constant edge iterator. */ EdgeIterator End() { return EdgeIterator(this->edges, INVALID_NODE); } /** * Update the node's supply and set last_update to the current date. * @param supply Supply to be added. */ void UpdateSupply(uint supply) { this->node.supply += supply; this->node.last_update = _date; } /** * Update the node's location on the map. * @param xy New location. */ void UpdateLocation(TileIndex xy) { this->node.xy = xy; } /** * Set the node's demand. * @param demand New demand for the node. */ void SetDemand(uint demand) { this->node.demand = demand; } void AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode); void UpdateEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode); void RemoveEdge(NodeID to); }; typedef SmallVector NodeVector; typedef SmallMatrix EdgeMatrix; /** Minimum effective distance for timeout calculation. */ static const uint MIN_TIMEOUT_DISTANCE = 32; /** Minimum number of days between subsequent compressions of a LG. */ static const uint COMPRESSION_INTERVAL = 256; /** * Scale a value from a link graph of age orig_age for usage in one of age * target_age. Make sure that the value stays > 0 if it was > 0 before. * @param val Value to be scaled. * @param target_age Age of the target link graph. * @param orig_age Age of the original link graph. * @return scaled value. */ inline static uint Scale(uint val, uint target_age, uint orig_age) { return val > 0 ? max(1U, val * target_age / orig_age) : 0; } /** Bare constructor, only for save/load. */ LinkGraph() : cargo(INVALID_CARGO), last_compression(0) {} /** * Real constructor. * @param cargo Cargo the link graph is about. */ LinkGraph(CargoID cargo) : cargo(cargo), last_compression(_date) {} void Init(uint size); void ShiftDates(int interval); void Compress(); void Merge(LinkGraph *other); /* Splitting link graphs is intentionally not implemented. * The overhead in determining connectedness would probably outweigh the * benefit of having to deal with smaller graphs. In real world examples * networks generally grow. Only rarely a network is permanently split. * Reacting to temporary splits here would obviously create performance * problems and detecting the temporary or permanent nature of splits isn't * trivial. */ /** * Get a node with the specified id. * @param num ID of the node. * @return the Requested node. */ inline Node operator[](NodeID num) { return Node(this, num); } /** * Get a const reference to a node with the specified id. * @param num ID of the node. * @return the Requested node. */ inline ConstNode operator[](NodeID num) const { return ConstNode(this, num); } /** * Get the current size of the component. * @return Size. */ inline uint Size() const { return this->nodes.Length(); } /** * Get date of last compression. * @return Date of last compression. */ inline Date LastCompression() const { return this->last_compression; } /** * Get the cargo ID this component's link graph refers to. * @return Cargo ID. */ inline CargoID Cargo() const { return this->cargo; } /** * Scale a value to its monthly equivalent, based on last compression. * @param base Value to be scaled. * @return Scaled value. */ inline uint Monthly(uint base) const { return base * 30 / (_date - this->last_compression + 1); } NodeID AddNode(const Station *st); void RemoveNode(NodeID id); protected: friend class LinkGraph::ConstNode; friend class LinkGraph::Node; friend const SaveLoad *GetLinkGraphDesc(); friend const SaveLoad *GetLinkGraphJobDesc(); friend void SaveLoad_LinkGraph(LinkGraph &lg); CargoID cargo; ///< Cargo of this component's link graph. Date last_compression; ///< Last time the capacities and supplies were compressed. NodeVector nodes; ///< Nodes in the component. EdgeMatrix edges; ///< Edges in the component. }; #define FOR_ALL_LINK_GRAPHS(var) FOR_ALL_ITEMS_FROM(LinkGraph, link_graph_index, var, 0) #endif /* LINKGRAPH_H */ openttd-1.5.3/src/linkgraph/flowmapper.h0000644000000000000000000000325612627373441017005 0ustar rootroot/* $Id: flowmapper.h 26166 2013-12-20 14:57:44Z fonsinchen $ */ /* * 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 flowmapper.h Declaration of flow mapper; maps paths into flows at nodes. */ #ifndef FLOWMAPPER_H_ #define FLOWMAPPER_H_ #include "linkgraphjob_base.h" /** * Map the path trees generated by the MCF solver into flows. The path tree is * useful to cache capacities and distances and allow quick disconnecting and * reconnecting to other paths. The flows show how much cargo from which nodes * is to be routed in which direction at a given node. This is what we need in * the end. */ class FlowMapper : public ComponentHandler { public: /** * Create a flow mapper. * @param scale Whether the flow mapper should scale all flows to monthly * values. Only do that on the very last flow mapping. */ FlowMapper(bool scale) : scale(scale) {} virtual void Run(LinkGraphJob &job) const; /** * Virtual destructor has to be defined because of virtual Run(). */ virtual ~FlowMapper() {} private: /** * Whether the flow mapper should scale all flows to monthly values. */ const bool scale; }; #endif /* FLOWMAPPER_H_ */ openttd-1.5.3/src/linkgraph/linkgraph_gui.h0000644000000000000000000001074012627373441017450 0ustar rootroot/* $Id: linkgraph_gui.h 26266 2014-01-19 09:26:56Z fonsinchen $ */ /* * 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 linkgraph_gui.h Declaration of linkgraph overlay GUI. */ #ifndef LINKGRAPH_GUI_H #define LINKGRAPH_GUI_H #include "../company_func.h" #include "../station_base.h" #include "../widget_type.h" #include "linkgraph_base.h" #include #include /** * Properties of a link between two stations. */ struct LinkProperties { LinkProperties() : capacity(0), usage(0), planned(0), shared(false) {} uint capacity; ///< Capacity of the link. uint usage; ///< Actual usage of the link. uint planned; ///< Planned usage of the link. bool shared; ///< If this is a shared link to be drawn dashed. }; /** * Handles drawing of links into some window. * The window must either be a smallmap or have a valid viewport. */ class LinkGraphOverlay { public: typedef std::map StationLinkMap; typedef std::map LinkMap; typedef std::list > StationSupplyList; static const uint8 LINK_COLOURS[]; /** * Create a link graph overlay for the specified window. * @param w Window to be drawn into. * @param wid ID of the widget to draw into. * @param cargo_mask Bitmask of cargoes to be shown. * @param company_mask Bitmask of companies to be shown. * @param scale Desired thickness of lines and size of station dots. */ LinkGraphOverlay(const Window *w, uint wid, uint32 cargo_mask, uint32 company_mask, uint scale) : window(w), widget_id(wid), cargo_mask(cargo_mask), company_mask(company_mask), scale(scale) {} void RebuildCache(); void Draw(const DrawPixelInfo *dpi) const; void SetCargoMask(uint32 cargo_mask); void SetCompanyMask(uint32 company_mask); /** Get a bitmask of the currently shown cargoes. */ uint32 GetCargoMask() { return this->cargo_mask; } /** Get a bitmask of the currently shown companies. */ uint32 GetCompanyMask() { return this->company_mask; } protected: const Window *window; ///< Window to be drawn into. const uint widget_id; ///< ID of Widget in Window to be drawn to. uint32 cargo_mask; ///< Bitmask of cargos to be displayed. uint32 company_mask; ///< Bitmask of companies to be displayed. LinkMap cached_links; ///< Cache for links to reduce recalculation. StationSupplyList cached_stations; ///< Cache for stations to be drawn. uint scale; ///< Width of link lines. Point GetStationMiddle(const Station *st) const; void DrawForwBackLinks(Point pta, StationID sta, Point ptb, StationID stb) const; void AddLinks(const Station *sta, const Station *stb); void DrawLinks(const DrawPixelInfo *dpi) const; void DrawStationDots(const DrawPixelInfo *dpi) const; void DrawContent(Point pta, Point ptb, const LinkProperties &cargo) const; bool IsLinkVisible(Point pta, Point ptb, const DrawPixelInfo *dpi, int padding = 0) const; bool IsPointVisible(Point pt, const DrawPixelInfo *dpi, int padding = 0) const; void GetWidgetDpi(DrawPixelInfo *dpi) const; static void AddStats(uint new_cap, uint new_usg, uint new_flow, bool new_shared, LinkProperties &cargo); static void DrawVertex(int x, int y, int size, int colour, int border_colour); }; void ShowLinkGraphLegend(); /** * Menu window to select cargoes and companies to show in a link graph overlay. */ struct LinkGraphLegendWindow : Window { public: LinkGraphLegendWindow(WindowDesc *desc, int window_number); void SetOverlay(LinkGraphOverlay *overlay); virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize); virtual void DrawWidget(const Rect &r, int widget) const; virtual void OnClick(Point pt, int widget, int click_count); virtual void OnInvalidateData(int data = 0, bool gui_scope = true); private: LinkGraphOverlay *overlay; void UpdateOverlayCompanies(); void UpdateOverlayCargoes(); }; #endif /* LINKGRAPH_GUI_H */ openttd-1.5.3/src/linkgraph/linkgraph.cpp0000644000000000000000000002266212627373441017145 0ustar rootroot/* $Id: linkgraph.cpp 26646 2014-06-14 13:35:39Z fonsinchen $ */ /* * 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 linkgraph.cpp Definition of link graph classes used for cargo distribution. */ #include "../stdafx.h" #include "../core/pool_func.hpp" #include "linkgraph.h" #include "../safeguards.h" /* Initialize the link-graph-pool */ LinkGraphPool _link_graph_pool("LinkGraph"); INSTANTIATE_POOL_METHODS(LinkGraph) /** * Create a node or clear it. * @param xy Location of the associated station. * @param st ID of the associated station. * @param demand Demand for cargo at the station. */ inline void LinkGraph::BaseNode::Init(TileIndex xy, StationID st, uint demand) { this->xy = xy; this->supply = 0; this->demand = demand; this->station = st; this->last_update = INVALID_DATE; } /** * Create an edge. */ inline void LinkGraph::BaseEdge::Init() { this->capacity = 0; this->usage = 0; this->last_unrestricted_update = INVALID_DATE; this->last_restricted_update = INVALID_DATE; this->next_edge = INVALID_NODE; } /** * Shift all dates by given interval. * This is useful if the date has been modified with the cheat menu. * @param interval Number of days to be added or subtracted. */ void LinkGraph::ShiftDates(int interval) { this->last_compression += interval; for (NodeID node1 = 0; node1 < this->Size(); ++node1) { BaseNode &source = this->nodes[node1]; if (source.last_update != INVALID_DATE) source.last_update += interval; for (NodeID node2 = 0; node2 < this->Size(); ++node2) { BaseEdge &edge = this->edges[node1][node2]; if (edge.last_unrestricted_update != INVALID_DATE) edge.last_unrestricted_update += interval; if (edge.last_restricted_update != INVALID_DATE) edge.last_restricted_update += interval; } } } void LinkGraph::Compress() { this->last_compression = (_date + this->last_compression) / 2; for (NodeID node1 = 0; node1 < this->Size(); ++node1) { this->nodes[node1].supply /= 2; for (NodeID node2 = 0; node2 < this->Size(); ++node2) { BaseEdge &edge = this->edges[node1][node2]; if (edge.capacity > 0) { edge.capacity = max(1U, edge.capacity / 2); edge.usage /= 2; } } } } /** * Merge a link graph with another one. * @param other LinkGraph to be merged into this one. */ void LinkGraph::Merge(LinkGraph *other) { Date age = _date - this->last_compression + 1; Date other_age = _date - other->last_compression + 1; NodeID first = this->Size(); for (NodeID node1 = 0; node1 < other->Size(); ++node1) { Station *st = Station::Get(other->nodes[node1].station); NodeID new_node = this->AddNode(st); this->nodes[new_node].supply = LinkGraph::Scale(other->nodes[node1].supply, age, other_age); st->goods[this->cargo].link_graph = this->index; st->goods[this->cargo].node = new_node; for (NodeID node2 = 0; node2 < node1; ++node2) { BaseEdge &forward = this->edges[new_node][first + node2]; BaseEdge &backward = this->edges[first + node2][new_node]; forward = other->edges[node1][node2]; backward = other->edges[node2][node1]; forward.capacity = LinkGraph::Scale(forward.capacity, age, other_age); forward.usage = LinkGraph::Scale(forward.usage, age, other_age); if (forward.next_edge != INVALID_NODE) forward.next_edge += first; backward.capacity = LinkGraph::Scale(backward.capacity, age, other_age); backward.usage = LinkGraph::Scale(backward.usage, age, other_age); if (backward.next_edge != INVALID_NODE) backward.next_edge += first; } BaseEdge &new_start = this->edges[new_node][new_node]; new_start = other->edges[node1][node1]; if (new_start.next_edge != INVALID_NODE) new_start.next_edge += first; } delete other; } /** * Remove a node from the link graph by overwriting it with the last node. * @param id ID of the node to be removed. */ void LinkGraph::RemoveNode(NodeID id) { assert(id < this->Size()); NodeID last_node = this->Size() - 1; for (NodeID i = 0; i <= last_node; ++i) { (*this)[i].RemoveEdge(id); BaseEdge *node_edges = this->edges[i]; NodeID prev = i; NodeID next = node_edges[i].next_edge; while (next != INVALID_NODE) { if (next == last_node) { node_edges[prev].next_edge = id; break; } prev = next; next = node_edges[prev].next_edge; } node_edges[id] = node_edges[last_node]; } Station::Get(this->nodes[last_node].station)->goods[this->cargo].node = id; this->nodes.Erase(this->nodes.Get(id)); this->edges.EraseColumn(id); /* Not doing EraseRow here, as having the extra invalid row doesn't hurt * and removing it would trigger a lot of memmove. The data has already * been copied around in the loop above. */ } /** * Add a node to the component and create empty edges associated with it. Set * the station's last_component to this component. Calculate the distances to all * other nodes. The distances to _all_ nodes are important as the demand * calculator relies on their availability. * @param st New node's station. * @return New node's ID. */ NodeID LinkGraph::AddNode(const Station *st) { const GoodsEntry &good = st->goods[this->cargo]; NodeID new_node = this->Size(); this->nodes.Append(); /* Avoid reducing the height of the matrix as that is expensive and we * most likely will increase it again later which is again expensive. */ this->edges.Resize(new_node + 1U, max(new_node + 1U, this->edges.Height())); this->nodes[new_node].Init(st->xy, st->index, HasBit(good.status, GoodsEntry::GES_ACCEPTANCE)); BaseEdge *new_edges = this->edges[new_node]; /* Reset the first edge starting at the new node */ new_edges[new_node].next_edge = INVALID_NODE; for (NodeID i = 0; i <= new_node; ++i) { new_edges[i].Init(); this->edges[i][new_node].Init(); } return new_node; } /** * Fill an edge with values from a link. Set the restricted or unrestricted * update timestamp according to the given update mode. * @param to Destination node of the link. * @param capacity Capacity of the link. * @param usage Usage to be added. * @param mode Update mode to be used. */ void LinkGraph::Node::AddEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode) { assert(this->index != to); BaseEdge &edge = this->edges[to]; BaseEdge &first = this->edges[this->index]; edge.capacity = capacity; edge.usage = usage; edge.next_edge = first.next_edge; first.next_edge = to; if (mode & EUM_UNRESTRICTED) edge.last_unrestricted_update = _date; if (mode & EUM_RESTRICTED) edge.last_restricted_update = _date; } /** * Creates an edge if none exists yet or updates an existing edge. * @param to Target node. * @param capacity Capacity of the link. * @param usage Usage to be added. * @param mode Update mode to be used. */ void LinkGraph::Node::UpdateEdge(NodeID to, uint capacity, uint usage, EdgeUpdateMode mode) { assert(capacity > 0); assert(usage <= capacity); if (this->edges[to].capacity == 0) { this->AddEdge(to, capacity, usage, mode); } else { (*this)[to].Update(capacity, usage, mode); } } /** * Remove an outgoing edge from this node. * @param to ID of destination node. */ void LinkGraph::Node::RemoveEdge(NodeID to) { if (this->index == to) return; BaseEdge &edge = this->edges[to]; edge.capacity = 0; edge.last_unrestricted_update = INVALID_DATE; edge.last_restricted_update = INVALID_DATE; edge.usage = 0; NodeID prev = this->index; NodeID next = this->edges[this->index].next_edge; while (next != INVALID_NODE) { if (next == to) { /* Will be removed, skip it. */ this->edges[prev].next_edge = edge.next_edge; edge.next_edge = INVALID_NODE; break; } else { prev = next; next = this->edges[next].next_edge; } } } /** * Update an edge. If mode contains UM_REFRESH refresh the edge to have at * least the given capacity and usage, otherwise add the capacity and usage. * In any case set the respective update timestamp(s), according to the given * mode. * @param from Start node of the edge. * @param to End node of the edge. * @param capacity Capacity to be added/updated. * @param usage Usage to be added. * @param mode Update mode to be applied. */ void LinkGraph::Edge::Update(uint capacity, uint usage, EdgeUpdateMode mode) { assert(this->edge.capacity > 0); assert(capacity >= usage); if (mode & EUM_INCREASE) { this->edge.capacity += capacity; this->edge.usage += usage; } else if (mode & EUM_REFRESH) { this->edge.capacity = max(this->edge.capacity, capacity); this->edge.usage = max(this->edge.usage, usage); } if (mode & EUM_UNRESTRICTED) this->edge.last_unrestricted_update = _date; if (mode & EUM_RESTRICTED) this->edge.last_restricted_update = _date; } /** * Resize the component and fill it with empty nodes and edges. Used when * loading from save games. The component is expected to be empty before. * @param size New size of the component. */ void LinkGraph::Init(uint size) { assert(this->Size() == 0); this->edges.Resize(size, size); this->nodes.Resize(size); for (uint i = 0; i < size; ++i) { this->nodes[i].Init(); BaseEdge *column = this->edges[i]; for (uint j = 0; j < size; ++j) column[j].Init(); } } openttd-1.5.3/src/linkgraph/linkgraph_gui.cpp0000644000000000000000000005122712627373441020010 0ustar rootroot/* $Id: linkgraph_gui.cpp 26891 2014-09-21 16:19:52Z fonsinchen $ */ /* * 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 linkgraph_gui.cpp Implementation of linkgraph overlay GUI. */ #include "../stdafx.h" #include "../window_gui.h" #include "../window_func.h" #include "../company_base.h" #include "../company_gui.h" #include "../date_func.h" #include "../viewport_func.h" #include "../smallmap_gui.h" #include "../core/geometry_func.hpp" #include "../widgets/link_graph_legend_widget.h" #include "table/strings.h" #include "../safeguards.h" /** * Colours for the various "load" states of links. Ordered from "unused" to * "overloaded". */ const uint8 LinkGraphOverlay::LINK_COLOURS[] = { 0x0f, 0xd1, 0xd0, 0x57, 0x55, 0x53, 0xbf, 0xbd, 0xba, 0xb9, 0xb7, 0xb5 }; /** * Get a DPI for the widget we will be drawing to. * @param dpi DrawPixelInfo to fill with the desired dimensions. */ void LinkGraphOverlay::GetWidgetDpi(DrawPixelInfo *dpi) const { const NWidgetBase *wi = this->window->GetWidget(this->widget_id); dpi->left = dpi->top = 0; dpi->width = wi->current_x; dpi->height = wi->current_y; } /** * Rebuild the cache and recalculate which links and stations to be shown. */ void LinkGraphOverlay::RebuildCache() { this->cached_links.clear(); this->cached_stations.clear(); if (this->company_mask == 0) return; DrawPixelInfo dpi; this->GetWidgetDpi(&dpi); const Station *sta; FOR_ALL_STATIONS(sta) { if (sta->rect.IsEmpty()) continue; Point pta = this->GetStationMiddle(sta); StationID from = sta->index; StationLinkMap &seen_links = this->cached_links[from]; uint supply = 0; CargoID c; FOR_EACH_SET_CARGO_ID(c, this->cargo_mask) { if (!CargoSpec::Get(c)->IsValid()) continue; if (!LinkGraph::IsValidID(sta->goods[c].link_graph)) continue; const LinkGraph &lg = *LinkGraph::Get(sta->goods[c].link_graph); ConstNode from_node = lg[sta->goods[c].node]; supply += lg.Monthly(from_node.Supply()); for (ConstEdgeIterator i = from_node.Begin(); i != from_node.End(); ++i) { StationID to = lg[i->first].Station(); assert(from != to); if (!Station::IsValidID(to) || seen_links.find(to) != seen_links.end()) { continue; } const Station *stb = Station::Get(to); assert(sta != stb); /* Show links between stations of selected companies or "neutral" ones like oilrigs. */ if (stb->owner != OWNER_NONE && sta->owner != OWNER_NONE && !HasBit(this->company_mask, stb->owner)) continue; if (stb->rect.IsEmpty()) continue; if (!this->IsLinkVisible(pta, this->GetStationMiddle(stb), &dpi)) continue; this->AddLinks(sta, stb); seen_links[to]; // make sure it is created and marked as seen } } if (this->IsPointVisible(pta, &dpi)) { this->cached_stations.push_back(std::make_pair(from, supply)); } } } /** * Determine if a certain point is inside the given DPI, with some lee way. * @param pt Point we are looking for. * @param dpi Visible area. * @param padding Extent of the point. * @return If the point or any of its 'extent' is inside the dpi. */ inline bool LinkGraphOverlay::IsPointVisible(Point pt, const DrawPixelInfo *dpi, int padding) const { return pt.x > dpi->left - padding && pt.y > dpi->top - padding && pt.x < dpi->left + dpi->width + padding && pt.y < dpi->top + dpi->height + padding; } /** * Determine if a certain link crosses through the area given by the dpi with some lee way. * @param pta First end of the link. * @param ptb Second end of the link. * @param dpi Visible area. * @param padding Width or thickness of the link. * @return If the link or any of its "thickness" is visible. This may return false positives. */ inline bool LinkGraphOverlay::IsLinkVisible(Point pta, Point ptb, const DrawPixelInfo *dpi, int padding) const { return !((pta.x < dpi->left - padding && ptb.x < dpi->left - padding) || (pta.y < dpi->top - padding && ptb.y < dpi->top - padding) || (pta.x > dpi->left + dpi->width + padding && ptb.x > dpi->left + dpi->width + padding) || (pta.y > dpi->top + dpi->height + padding && ptb.y > dpi->top + dpi->height + padding)); } /** * Add all "interesting" links between the given stations to the cache. * @param from The source station. * @param to The destination station. */ void LinkGraphOverlay::AddLinks(const Station *from, const Station *to) { CargoID c; FOR_EACH_SET_CARGO_ID(c, this->cargo_mask) { if (!CargoSpec::Get(c)->IsValid()) continue; const GoodsEntry &ge = from->goods[c]; if (!LinkGraph::IsValidID(ge.link_graph) || ge.link_graph != to->goods[c].link_graph) { continue; } const LinkGraph &lg = *LinkGraph::Get(ge.link_graph); ConstEdge edge = lg[ge.node][to->goods[c].node]; if (edge.Capacity() > 0) { this->AddStats(lg.Monthly(edge.Capacity()), lg.Monthly(edge.Usage()), ge.flows.GetFlowVia(to->index), from->owner == OWNER_NONE || to->owner == OWNER_NONE, this->cached_links[from->index][to->index]); } } } /** * Add information from a given pair of link stat and flow stat to the given * link properties. The shown usage or plan is always the maximum of all link * stats involved. * @param new_cap Capacity of the new link. * @param new_usg Usage of the new link. * @param new_plan Planned flow for the new link. * @param new_shared If the new link is shared. * @param cargo LinkProperties to write the information to. */ /* static */ void LinkGraphOverlay::AddStats(uint new_cap, uint new_usg, uint new_plan, bool new_shared, LinkProperties &cargo) { /* multiply the numbers by 32 in order to avoid comparing to 0 too often. */ if (cargo.capacity == 0 || max(cargo.usage, cargo.planned) * 32 / (cargo.capacity + 1) < max(new_usg, new_plan) * 32 / (new_cap + 1)) { cargo.capacity = new_cap; cargo.usage = new_usg; cargo.planned = new_plan; } if (new_shared) cargo.shared = true; } /** * Draw the linkgraph overlay or some part of it, in the area given. * @param dpi Area to be drawn to. */ void LinkGraphOverlay::Draw(const DrawPixelInfo *dpi) const { this->DrawLinks(dpi); this->DrawStationDots(dpi); } /** * Draw the cached links or part of them into the given area. * @param dpi Area to be drawn to. */ void LinkGraphOverlay::DrawLinks(const DrawPixelInfo *dpi) const { for (LinkMap::const_iterator i(this->cached_links.begin()); i != this->cached_links.end(); ++i) { if (!Station::IsValidID(i->first)) continue; Point pta = this->GetStationMiddle(Station::Get(i->first)); for (StationLinkMap::const_iterator j(i->second.begin()); j != i->second.end(); ++j) { if (!Station::IsValidID(j->first)) continue; Point ptb = this->GetStationMiddle(Station::Get(j->first)); if (!this->IsLinkVisible(pta, ptb, dpi, this->scale + 2)) continue; this->DrawContent(pta, ptb, j->second); } } } /** * Draw one specific link. * @param pta Source of the link. * @param ptb Destination of the link. * @param cargo Properties of the link. */ void LinkGraphOverlay::DrawContent(Point pta, Point ptb, const LinkProperties &cargo) const { uint usage_or_plan = min(cargo.capacity * 2 + 1, max(cargo.usage, cargo.planned)); int colour = LinkGraphOverlay::LINK_COLOURS[usage_or_plan * lengthof(LinkGraphOverlay::LINK_COLOURS) / (cargo.capacity * 2 + 2)]; int dash = cargo.shared ? this->scale * 4 : 0; /* Move line a bit 90° against its dominant direction to prevent it from * being hidden below the grey line. */ int side = _settings_game.vehicle.road_side ? 1 : -1; if (abs(pta.x - ptb.x) < abs(pta.y - ptb.y)) { int offset_x = (pta.y > ptb.y ? 1 : -1) * side * this->scale; GfxDrawLine(pta.x + offset_x, pta.y, ptb.x + offset_x, ptb.y, colour, this->scale, dash); } else { int offset_y = (pta.x < ptb.x ? 1 : -1) * side * this->scale; GfxDrawLine(pta.x, pta.y + offset_y, ptb.x, ptb.y + offset_y, colour, this->scale, dash); } GfxDrawLine(pta.x, pta.y, ptb.x, ptb.y, _colour_gradient[COLOUR_GREY][1], this->scale); } /** * Draw dots for stations into the smallmap. The dots' sizes are determined by the amount of * cargo produced there, their colours by the type of cargo produced. */ void LinkGraphOverlay::DrawStationDots(const DrawPixelInfo *dpi) const { for (StationSupplyList::const_iterator i(this->cached_stations.begin()); i != this->cached_stations.end(); ++i) { const Station *st = Station::GetIfValid(i->first); if (st == NULL) continue; Point pt = this->GetStationMiddle(st); if (!this->IsPointVisible(pt, dpi, 3 * this->scale)) continue; uint r = this->scale * 2 + this->scale * 2 * min(200, i->second) / 200; LinkGraphOverlay::DrawVertex(pt.x, pt.y, r, _colour_gradient[st->owner != OWNER_NONE ? (Colours)Company::Get(st->owner)->colour : COLOUR_GREY][5], _colour_gradient[COLOUR_GREY][1]); } } /** * Draw a square symbolizing a producer of cargo. * @param x X coordinate of the middle of the vertex. * @param y Y coordinate of the middle of the vertex. * @param size Y and y extend of the vertex. * @param colour Colour with which the vertex will be filled. * @param border_colour Colour for the border of the vertex. */ /* static */ void LinkGraphOverlay::DrawVertex(int x, int y, int size, int colour, int border_colour) { size--; int w1 = size / 2; int w2 = size / 2 + size % 2; GfxFillRect(x - w1, y - w1, x + w2, y + w2, colour); w1++; w2++; GfxDrawLine(x - w1, y - w1, x + w2, y - w1, border_colour); GfxDrawLine(x - w1, y + w2, x + w2, y + w2, border_colour); GfxDrawLine(x - w1, y - w1, x - w1, y + w2, border_colour); GfxDrawLine(x + w2, y - w1, x + w2, y + w2, border_colour); } /** * Determine the middle of a station in the current window. * @param st The station we're looking for. * @return Middle point of the station in the current window. */ Point LinkGraphOverlay::GetStationMiddle(const Station *st) const { if (this->window->viewport != NULL) { return GetViewportStationMiddle(this->window->viewport, st); } else { /* assume this is a smallmap */ return static_cast(this->window)->GetStationMiddle(st); } } /** * Set a new cargo mask and rebuild the cache. * @param cargo_mask New cargo mask. */ void LinkGraphOverlay::SetCargoMask(uint32 cargo_mask) { this->cargo_mask = cargo_mask; this->RebuildCache(); this->window->GetWidget(this->widget_id)->SetDirty(this->window); } /** * Set a new company mask and rebuild the cache. * @param company_mask New company mask. */ void LinkGraphOverlay::SetCompanyMask(uint32 company_mask) { this->company_mask = company_mask; this->RebuildCache(); this->window->GetWidget(this->widget_id)->SetDirty(this->window); } /** Make a number of rows with buttons for each company for the linkgraph legend window. */ NWidgetBase *MakeCompanyButtonRowsLinkGraphGUI(int *biggest_index) { return MakeCompanyButtonRows(biggest_index, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST, 3, STR_LINKGRAPH_LEGEND_SELECT_COMPANIES); } NWidgetBase *MakeSaturationLegendLinkGraphGUI(int *biggest_index) { NWidgetVertical *panel = new NWidgetVertical(NC_EQUALSIZE); for (uint i = 0; i < lengthof(LinkGraphOverlay::LINK_COLOURS); ++i) { NWidgetBackground * wid = new NWidgetBackground(WWT_PANEL, COLOUR_DARK_GREEN, i + WID_LGL_SATURATION_FIRST); wid->SetMinimalSize(50, FONT_HEIGHT_SMALL); wid->SetFill(1, 1); wid->SetResize(0, 0); panel->Add(wid); } *biggest_index = WID_LGL_SATURATION_LAST; return panel; } NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index) { static const uint ENTRIES_PER_ROW = CeilDiv(NUM_CARGO, 5); NWidgetVertical *panel = new NWidgetVertical(NC_EQUALSIZE); NWidgetHorizontal *row = NULL; for (uint i = 0; i < NUM_CARGO; ++i) { if (i % ENTRIES_PER_ROW == 0) { if (row) panel->Add(row); row = new NWidgetHorizontal(NC_EQUALSIZE); } NWidgetBackground * wid = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, i + WID_LGL_CARGO_FIRST); wid->SetMinimalSize(25, FONT_HEIGHT_SMALL); wid->SetFill(1, 1); wid->SetResize(0, 0); row->Add(wid); } /* Fill up last row */ for (uint i = 0; i < 4 - (NUM_CARGO - 1) % 5; ++i) { NWidgetSpacer *spc = new NWidgetSpacer(25, FONT_HEIGHT_SMALL); spc->SetFill(1, 1); spc->SetResize(0, 0); row->Add(spc); } panel->Add(row); *biggest_index = WID_LGL_CARGO_LAST; return panel; } static const NWidgetPart _nested_linkgraph_legend_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_LGL_CAPTION), SetDataTip(STR_LINKGRAPH_LEGEND_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_LGL_SATURATION), SetPadding(WD_FRAMERECT_TOP, 0, WD_FRAMERECT_BOTTOM, WD_CAPTIONTEXT_LEFT), NWidgetFunction(MakeSaturationLegendLinkGraphGUI), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_LGL_COMPANIES), SetPadding(WD_FRAMERECT_TOP, 0, WD_FRAMERECT_BOTTOM, WD_CAPTIONTEXT_LEFT), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidgetFunction(MakeCompanyButtonRowsLinkGraphGUI), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_LGL_COMPANIES_ALL), SetDataTip(STR_LINKGRAPH_LEGEND_ALL, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_LGL_COMPANIES_NONE), SetDataTip(STR_LINKGRAPH_LEGEND_NONE, STR_NULL), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_LGL_CARGOES), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_CAPTIONTEXT_LEFT), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidgetFunction(MakeCargoesLegendLinkGraphGUI), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_LGL_CARGOES_ALL), SetDataTip(STR_LINKGRAPH_LEGEND_ALL, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_LGL_CARGOES_NONE), SetDataTip(STR_LINKGRAPH_LEGEND_NONE, STR_NULL), EndContainer(), EndContainer(), EndContainer(), EndContainer() }; assert_compile(WID_LGL_SATURATION_LAST - WID_LGL_SATURATION_FIRST == lengthof(LinkGraphOverlay::LINK_COLOURS) - 1); static WindowDesc _linkgraph_legend_desc( WDP_AUTO, "toolbar_linkgraph", 0, 0, WC_LINKGRAPH_LEGEND, WC_NONE, 0, _nested_linkgraph_legend_widgets, lengthof(_nested_linkgraph_legend_widgets) ); /** * Open a link graph legend window. */ void ShowLinkGraphLegend() { AllocateWindowDescFront(&_linkgraph_legend_desc, 0); } LinkGraphLegendWindow::LinkGraphLegendWindow(WindowDesc *desc, int window_number) : Window(desc) { this->InitNested(window_number); this->InvalidateData(0); this->SetOverlay(FindWindowById(WC_MAIN_WINDOW, 0)->viewport->overlay); } /** * Set the overlay belonging to this menu and import its company/cargo settings. * @params overlay New overlay for this menu. */ void LinkGraphLegendWindow::SetOverlay(LinkGraphOverlay *overlay) { this->overlay = overlay; uint32 companies = this->overlay->GetCompanyMask(); for (uint c = 0; c < MAX_COMPANIES; c++) { if (!this->IsWidgetDisabled(WID_LGL_COMPANY_FIRST + c)) { this->SetWidgetLoweredState(WID_LGL_COMPANY_FIRST + c, HasBit(companies, c)); } } uint32 cargoes = this->overlay->GetCargoMask(); for (uint c = 0; c < NUM_CARGO; c++) { if (!this->IsWidgetDisabled(WID_LGL_CARGO_FIRST + c)) { this->SetWidgetLoweredState(WID_LGL_CARGO_FIRST + c, HasBit(cargoes, c)); } } } void LinkGraphLegendWindow::UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) { StringID str = STR_NULL; if (widget == WID_LGL_SATURATION_FIRST) { str = STR_LINKGRAPH_LEGEND_UNUSED; } else if (widget == WID_LGL_SATURATION_LAST) { str = STR_LINKGRAPH_LEGEND_OVERLOADED; } else if (widget == (WID_LGL_SATURATION_LAST + WID_LGL_SATURATION_FIRST) / 2) { str = STR_LINKGRAPH_LEGEND_SATURATED; } if (str != STR_NULL) { Dimension dim = GetStringBoundingBox(str); dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, dim); } } if (IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) { CargoSpec *cargo = CargoSpec::Get(widget - WID_LGL_CARGO_FIRST); if (cargo->IsValid()) { Dimension dim = GetStringBoundingBox(cargo->abbrev); dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, dim); } } } void LinkGraphLegendWindow::DrawWidget(const Rect &r, int widget) const { if (IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) { if (this->IsWidgetDisabled(widget)) return; CompanyID cid = (CompanyID)(widget - WID_LGL_COMPANY_FIRST); Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); DrawCompanyIcon(cid, (r.left + r.right + 1 - sprite_size.width) / 2, (r.top + r.bottom + 1 - sprite_size.height) / 2); } if (IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) { GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, LinkGraphOverlay::LINK_COLOURS[widget - WID_LGL_SATURATION_FIRST]); StringID str = STR_NULL; if (widget == WID_LGL_SATURATION_FIRST) { str = STR_LINKGRAPH_LEGEND_UNUSED; } else if (widget == WID_LGL_SATURATION_LAST) { str = STR_LINKGRAPH_LEGEND_OVERLOADED; } else if (widget == (WID_LGL_SATURATION_LAST + WID_LGL_SATURATION_FIRST) / 2) { str = STR_LINKGRAPH_LEGEND_SATURATED; } if (str != STR_NULL) DrawString(r.left, r.right, (r.top + r.bottom + 1 - FONT_HEIGHT_SMALL) / 2, str, TC_FROMSTRING, SA_HOR_CENTER); } if (IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) { if (this->IsWidgetDisabled(widget)) return; CargoSpec *cargo = CargoSpec::Get(widget - WID_LGL_CARGO_FIRST); GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, cargo->legend_colour); DrawString(r.left, r.right, (r.top + r.bottom + 1 - FONT_HEIGHT_SMALL) / 2, cargo->abbrev, TC_BLACK, SA_HOR_CENTER); } } /** * Update the overlay with the new company selection. */ void LinkGraphLegendWindow::UpdateOverlayCompanies() { uint32 mask = 0; for (uint c = 0; c < MAX_COMPANIES; c++) { if (this->IsWidgetDisabled(c + WID_LGL_COMPANY_FIRST)) continue; if (!this->IsWidgetLowered(c + WID_LGL_COMPANY_FIRST)) continue; SetBit(mask, c); } this->overlay->SetCompanyMask(mask); } /** * Update the overlay with the new cargo selection. */ void LinkGraphLegendWindow::UpdateOverlayCargoes() { uint32 mask = 0; for (uint c = 0; c < NUM_CARGO; c++) { if (this->IsWidgetDisabled(c + WID_LGL_CARGO_FIRST)) continue; if (!this->IsWidgetLowered(c + WID_LGL_CARGO_FIRST)) continue; SetBit(mask, c); } this->overlay->SetCargoMask(mask); } void LinkGraphLegendWindow::OnClick(Point pt, int widget, int click_count) { /* Check which button is clicked */ if (IsInsideMM(widget, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST + 1)) { if (!this->IsWidgetDisabled(widget)) { this->ToggleWidgetLoweredState(widget); this->UpdateOverlayCompanies(); } } else if (widget == WID_LGL_COMPANIES_ALL || widget == WID_LGL_COMPANIES_NONE) { for (uint c = 0; c < MAX_COMPANIES; c++) { if (this->IsWidgetDisabled(c + WID_LGL_COMPANY_FIRST)) continue; this->SetWidgetLoweredState(WID_LGL_COMPANY_FIRST + c, widget == WID_LGL_COMPANIES_ALL); } this->UpdateOverlayCompanies(); this->SetDirty(); } else if (IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) { if (!this->IsWidgetDisabled(widget)) { this->ToggleWidgetLoweredState(widget); this->UpdateOverlayCargoes(); } } else if (widget == WID_LGL_CARGOES_ALL || widget == WID_LGL_CARGOES_NONE) { for (uint c = 0; c < NUM_CARGO; c++) { if (this->IsWidgetDisabled(c + WID_LGL_CARGO_FIRST)) continue; this->SetWidgetLoweredState(WID_LGL_CARGO_FIRST + c, widget == WID_LGL_CARGOES_ALL); } this->UpdateOverlayCargoes(); } this->SetDirty(); } /** * Invalidate the data of this window if the cargoes or companies have changed. * @param data ignored * @param gui_scope ignored */ void LinkGraphLegendWindow::OnInvalidateData(int data, bool gui_scope) { /* Disable the companies who are not active */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { this->SetWidgetDisabledState(i + WID_LGL_COMPANY_FIRST, !Company::IsValidID(i)); } for (CargoID i = 0; i < NUM_CARGO; i++) { this->SetWidgetDisabledState(i + WID_LGL_CARGO_FIRST, !CargoSpec::Get(i)->IsValid()); } } openttd-1.5.3/src/linkgraph/refresh.cpp0000644000000000000000000003012312627373441016613 0ustar rootroot/* $Id: refresh.cpp 26889 2014-09-21 14:22:32Z fonsinchen $ */ /* * 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 refresh.h Definition of link refreshing utility. */ #include "../stdafx.h" #include "../core/bitmath_func.hpp" #include "../station_func.h" #include "../engine_base.h" #include "../vehicle_func.h" #include "refresh.h" #include "linkgraph.h" #include "../safeguards.h" /** * Refresh all links the given vehicle will visit. * @param v Vehicle to refresh links for. * @param allow_merge If the refresher is allowed to merge or extend link graphs. * @param is_full_loading If the vehicle is full loading. */ /* static */ void LinkRefresher::Run(Vehicle *v, bool allow_merge, bool is_full_loading) { /* If there are no orders we can't predict anything.*/ if (v->orders.list == NULL) return; /* Make sure the first order is a useful order. */ const Order *first = v->orders.list->GetNextDecisionNode(v->GetOrder(v->cur_implicit_order_index), 0); if (first == NULL) return; HopSet seen_hops; LinkRefresher refresher(v, &seen_hops, allow_merge, is_full_loading); refresher.RefreshLinks(first, first, v->last_loading_station != INVALID_STATION ? 1 << HAS_CARGO : 0); } /** * Comparison operator to allow hops to be used in a std::set. * @param other Other hop to be compared with. * @return If this hop is "smaller" than the other (defined by from, to and cargo in this order). */ bool LinkRefresher::Hop::operator<(const Hop &other) const { if (this->from < other.from) { return true; } else if (this->from > other.from) { return false; } if (this->to < other.to) { return true; } else if (this->to > other.to) { return false; } return this->cargo < other.cargo; } /** * Constructor for link refreshing algorithm. * @param vehicle Vehicle to refresh links for. * @param seen_hops Set of hops already seen. This is shared between this * refresher and all its children. * @param allow_merge If the refresher is allowed to merge or extend link graphs. * @param is_full_loading If the vehicle is full loading. */ LinkRefresher::LinkRefresher(Vehicle *vehicle, HopSet *seen_hops, bool allow_merge, bool is_full_loading) : vehicle(vehicle), seen_hops(seen_hops), cargo(CT_INVALID), allow_merge(allow_merge), is_full_loading(is_full_loading) { /* Assemble list of capacities and set last loading stations to 0. */ for (Vehicle *v = this->vehicle; v != NULL; v = v->Next()) { this->refit_capacities.push_back(RefitDesc(v->cargo_type, v->cargo_cap, v->refit_cap)); if (v->refit_cap > 0) this->capacities[v->cargo_type] += v->refit_cap; } } /** * Handle refit orders by updating capacities and refit_capacities. * @param refit_cargo Cargo to refit to. * @return True if any vehicle was refit; false if none was. */ bool LinkRefresher::HandleRefit(CargoID refit_cargo) { this->cargo = refit_cargo; RefitList::iterator refit_it = this->refit_capacities.begin(); bool any_refit = false; for (Vehicle *v = this->vehicle; v != NULL; v = v->Next()) { const Engine *e = Engine::Get(v->engine_type); if (!HasBit(e->info.refit_mask, this->cargo)) { ++refit_it; continue; } any_refit = true; /* Back up the vehicle's cargo type */ CargoID temp_cid = v->cargo_type; byte temp_subtype = v->cargo_subtype; v->cargo_type = this->cargo; v->cargo_subtype = GetBestFittingSubType(v, v, this->cargo); uint16 mail_capacity = 0; uint amount = e->DetermineCapacity(v, &mail_capacity); /* Restore the original cargo type */ v->cargo_type = temp_cid; v->cargo_subtype = temp_subtype; /* Skip on next refit. */ if (this->cargo != refit_it->cargo && refit_it->remaining > 0) { this->capacities[refit_it->cargo] -= refit_it->remaining; refit_it->remaining = 0; } else if (amount < refit_it->remaining) { this->capacities[refit_it->cargo] -= refit_it->remaining - amount; refit_it->remaining = amount; } refit_it->capacity = amount; refit_it->cargo = this->cargo; ++refit_it; /* Special case for aircraft with mail. */ if (v->type == VEH_AIRCRAFT) { if (mail_capacity < refit_it->remaining) { this->capacities[refit_it->cargo] -= refit_it->remaining - mail_capacity; refit_it->remaining = mail_capacity; } refit_it->capacity = mail_capacity; break; // aircraft have only one vehicle } } return any_refit; } /** * Restore capacities and refit_capacities as vehicle might have been able to load now. */ void LinkRefresher::ResetRefit() { for (RefitList::iterator it(this->refit_capacities.begin()); it != this->refit_capacities.end(); ++it) { if (it->remaining == it->capacity) continue; this->capacities[it->cargo] += it->capacity - it->remaining; it->remaining = it->capacity; } } /** * Predict the next order the vehicle will execute and resolve conditionals by * recursion and return next non-conditional order in list. * @param cur Current order being evaluated. * @param next Next order to be evaluated. * @param flags RefreshFlags to give hints about the previous link and state carried over from that. * @param num_hops Number of hops already taken by recursive calls to this method. * @return new next Order. */ const Order *LinkRefresher::PredictNextOrder(const Order *cur, const Order *next, uint8 flags, uint num_hops) { /* next is good if it's either NULL (then the caller will stop the * evaluation) or if it's not conditional and the caller allows it to be * chosen (by setting USE_NEXT). */ while (next != NULL && (!HasBit(flags, USE_NEXT) || next->IsType(OT_CONDITIONAL))) { /* After the first step any further non-conditional order is good, * regardless of previous USE_NEXT settings. The case of cur and next or * their respective stations being equal is handled elsewhere. */ SetBit(flags, USE_NEXT); if (next->IsType(OT_CONDITIONAL)) { const Order *skip_to = this->vehicle->orders.list->GetNextDecisionNode( this->vehicle->orders.list->GetOrderAt(next->GetConditionSkipToOrder()), num_hops); if (skip_to != NULL && num_hops < this->vehicle->orders.list->GetNumOrders()) { /* Make copies of capacity tracking lists. There is potential * for optimization here: If the vehicle never refits we don't * need to copy anything. Also, if we've seen the branched link * before we don't need to branch at all. */ LinkRefresher branch(*this); branch.RefreshLinks(cur, skip_to, flags, num_hops + 1); } } /* Reassign next with the following stop. This can be a station or a * depot.*/ next = this->vehicle->orders.list->GetNextDecisionNode( this->vehicle->orders.list->GetNext(next), num_hops++); } return next; } /** * Refresh link stats for the given pair of orders. * @param cur Last stop where the consist could interact with cargo. * @param next Next order to be processed. */ void LinkRefresher::RefreshStats(const Order *cur, const Order *next) { StationID next_station = next->GetDestination(); Station *st = Station::GetIfValid(cur->GetDestination()); if (st != NULL && next_station != INVALID_STATION && next_station != st->index) { for (CapacitiesMap::const_iterator i = this->capacities.begin(); i != this->capacities.end(); ++i) { /* Refresh the link and give it a minimum capacity. */ if (i->second == 0) continue; CargoID c = i->first; /* If not allowed to merge link graphs, make sure the stations are * already in the same link graph. */ if (!this->allow_merge && st->goods[c].link_graph != Station::Get(next_station)->goods[c].link_graph) { continue; } /* A link is at least partly restricted if a vehicle can't load at its source. */ EdgeUpdateMode restricted_mode = (cur->GetLoadType() & OLFB_NO_LOAD) == 0 ? EUM_UNRESTRICTED : EUM_RESTRICTED; /* If the vehicle is currently full loading, increase the capacities at the station * where it is loading by an estimate of what it would have transported if it wasn't * loading. Don't do that if the vehicle has been waiting for longer than the entire * order list is supposed to take, though. If that is the case the total duration is * probably far off and we'd greatly overestimate the capacity by increasing.*/ if (this->is_full_loading && this->vehicle->orders.list != NULL && st->index == vehicle->last_station_visited && this->vehicle->orders.list->GetTotalDuration() > (Ticks)this->vehicle->current_order_time) { uint effective_capacity = i->second * this->vehicle->load_unload_ticks; if (effective_capacity > (uint)this->vehicle->orders.list->GetTotalDuration()) { IncreaseStats(st, c, next_station, effective_capacity / this->vehicle->orders.list->GetTotalDuration(), 0, EUM_INCREASE | restricted_mode); } else if (RandomRange(this->vehicle->orders.list->GetTotalDuration()) < effective_capacity) { IncreaseStats(st, c, next_station, 1, 0, EUM_INCREASE | restricted_mode); } else { IncreaseStats(st, c, next_station, i->second, 0, EUM_REFRESH | restricted_mode); } } else { IncreaseStats(st, c, next_station, i->second, 0, EUM_REFRESH | restricted_mode); } } } } /** * Iterate over orders starting at \a cur and \a next and refresh links * associated with them. \a cur and \a next can be equal. If they're not they * must be "neigbours" in their order list, which means \a next must be directly * reachable from \a cur without passing any further OT_GOTO_STATION or * OT_IMPLICIT orders in between. * @param cur Current order being evaluated. * @param next Next order to be checked. * @param flags RefreshFlags to give hints about the previous link and state carried over from that. * @param num_hops Number of hops already taken by recursive calls to this method. */ void LinkRefresher::RefreshLinks(const Order *cur, const Order *next, uint8 flags, uint num_hops) { while (next != NULL) { if ((next->IsType(OT_GOTO_DEPOT) || next->IsType(OT_GOTO_STATION)) && next->IsRefit()) { SetBit(flags, WAS_REFIT); if (!next->IsAutoRefit()) { this->HandleRefit(next->GetRefitCargo()); } else if (!HasBit(flags, IN_AUTOREFIT)) { SetBit(flags, IN_AUTOREFIT); LinkRefresher backup(*this); for (CargoID c = 0; c != NUM_CARGO; ++c) { if (CargoSpec::Get(c)->IsValid() && this->HandleRefit(c)) { this->RefreshLinks(cur, next, flags, num_hops); *this = backup; } } } } /* Only reset the refit capacities if the "previous" next is a station, * meaning that either the vehicle was refit at the previous station or * it wasn't at all refit during the current hop. */ if (HasBit(flags, WAS_REFIT) && (next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT))) { SetBit(flags, RESET_REFIT); } else { ClrBit(flags, RESET_REFIT); } next = this->PredictNextOrder(cur, next, flags, num_hops); if (next == NULL) break; Hop hop(cur->index, next->index, this->cargo); if (this->seen_hops->find(hop) != this->seen_hops->end()) { break; } else { this->seen_hops->insert(hop); } /* Don't use the same order again, but choose a new one in the next round. */ ClrBit(flags, USE_NEXT); /* Skip resetting and link refreshing if next order won't do anything with cargo. */ if (!next->IsType(OT_GOTO_STATION) && !next->IsType(OT_IMPLICIT)) continue; if (HasBit(flags, RESET_REFIT)) { this->ResetRefit(); ClrBit(flags, RESET_REFIT); ClrBit(flags, WAS_REFIT); } if (cur->IsType(OT_GOTO_STATION) || cur->IsType(OT_IMPLICIT)) { if (cur->CanLeaveWithCargo(HasBit(flags, HAS_CARGO))) { SetBit(flags, HAS_CARGO); this->RefreshStats(cur, next); } else { ClrBit(flags, HAS_CARGO); } } /* "cur" is only assigned here if the stop is a station so that * whenever stats are to be increased two stations can be found. */ cur = next; } } openttd-1.5.3/src/linkgraph/init.h0000644000000000000000000000105512627373441015567 0ustar rootroot/** @file init.h Declaration of initializing link graph handler. */ #ifndef INIT_H #define INIT_H #include "linkgraphjob_base.h" /** * Stateless, thread safe initialization hander. Initializes node and edge * annotations. */ class InitHandler : public ComponentHandler { public: /** * Initialize the link graph job. * @param job Job to be initialized. */ virtual void Run(LinkGraphJob &job) const { job.Init(); } /** * Virtual destructor has to be defined because of virtual Run(). */ virtual ~InitHandler() {} }; #endif /* INIT_H */ openttd-1.5.3/src/linkgraph/flowmapper.cpp0000644000000000000000000000520112627373441017330 0ustar rootroot/* $Id: flowmapper.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 flowmapper.cpp Definition of flowmapper. */ #include "../stdafx.h" #include "flowmapper.h" #include "../safeguards.h" /** * Map the paths generated by the MCF solver into flows associated with nodes. * @param component the link graph component to be used. */ void FlowMapper::Run(LinkGraphJob &job) const { for (NodeID node_id = 0; node_id < job.Size(); ++node_id) { Node prev_node = job[node_id]; StationID prev = prev_node.Station(); PathList &paths = prev_node.Paths(); for (PathList::iterator i = paths.begin(); i != paths.end(); ++i) { Path *path = *i; uint flow = path->GetFlow(); if (flow == 0) break; Node node = job[path->GetNode()]; StationID via = node.Station(); StationID origin = job[path->GetOrigin()].Station(); assert(prev != via && via != origin); /* Mark all of the flow for local consumption at "first". */ node.Flows().AddFlow(origin, via, flow); if (prev != origin) { /* Pass some of the flow marked for local consumption at "prev" on * to this node. */ prev_node.Flows().PassOnFlow(origin, via, flow); } else { /* Prev node is origin. Simply add flow. */ prev_node.Flows().AddFlow(origin, via, flow); } } } for (NodeID node_id = 0; node_id < job.Size(); ++node_id) { /* Remove local consumption shares marked as invalid. */ Node node = job[node_id]; FlowStatMap &flows = node.Flows(); flows.FinalizeLocalConsumption(node.Station()); if (this->scale) { /* Scale by time the graph has been running without being compressed. Add 1 to avoid * division by 0 if spawn date == last compression date. This matches * LinkGraph::Monthly(). */ uint runtime = job.JoinDate() - job.Settings().recalc_time - job.LastCompression() + 1; for (FlowStatMap::iterator i = flows.begin(); i != flows.end(); ++i) { i->second.ScaleToMonthly(runtime); } } /* Clear paths. */ PathList &paths = node.Paths(); for (PathList::iterator i = paths.begin(); i != paths.end(); ++i) { delete *i; } paths.clear(); } } openttd-1.5.3/src/linkgraph/linkgraphschedule.h0000644000000000000000000000502712627373441020323 0ustar rootroot/* $Id: linkgraphschedule.h 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 linkgraphschedule.h Declaration of link graph schedule used for cargo distribution. */ #ifndef LINKGRAPHSCHEDULE_H #define LINKGRAPHSCHEDULE_H #include "linkgraph.h" class LinkGraphJob; /** * A handler doing "something" on a link graph component. It must not keep any * state as it is called concurrently from different threads. */ class ComponentHandler { public: /** * Destroy the handler. Must be given due to virtual Run. */ virtual ~ComponentHandler() {} /** * Run the handler. A link graph handler must not read or write any data * outside the given component as that would create a potential desync. * @param job Link graph component to run the handler on. */ virtual void Run(LinkGraphJob &job) const = 0; }; class LinkGraphSchedule { private: LinkGraphSchedule(); ~LinkGraphSchedule(); typedef std::list GraphList; typedef std::list JobList; friend const SaveLoad *GetLinkGraphScheduleDesc(); protected: ComponentHandler *handlers[6]; ///< Handlers to be run for each job. GraphList schedule; ///< Queue for new jobs. JobList running; ///< Currently running jobs. public: /* This is a tick where not much else is happening, so a small lag might go unnoticed. */ static const uint SPAWN_JOIN_TICK = 21; ///< Tick when jobs are spawned or joined every day. static LinkGraphSchedule instance; static void Run(void *j); static void Clear(); void SpawnNext(); void JoinNext(); void SpawnAll(); void ShiftDates(int interval); /** * Queue a link graph for execution. * @param lg Link graph to be queued. */ void Queue(LinkGraph *lg) { assert(LinkGraph::Get(lg->index) == lg); this->schedule.push_back(lg); } /** * Remove a link graph from the execution queue. * @param lg Link graph to be removed. */ void Unqueue(LinkGraph *lg) { this->schedule.remove(lg); } }; #endif /* LINKGRAPHSCHEDULE_H */ openttd-1.5.3/src/townname_func.h0000644000000000000000000000231012627373435015506 0ustar rootroot/* $Id: townname_func.h 26313 2014-02-06 21:06:59Z rubidium $ */ /* * 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 townname_func.h %Town name generator stuff. */ #ifndef TOWNNAME_FUNC_H #define TOWNNAME_FUNC_H #include "townname_type.h" char *GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed); char *GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last); char *GetTownName(char *buff, const Town *t, const char *last); bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names = NULL); bool GenerateTownName(uint32 *townnameparts, TownNames *town_names = NULL); #endif /* TOWNNAME_FUNC_H */ openttd-1.5.3/src/company_manager_face.h0000644000000000000000000002613112627373435016770 0ustar rootroot/* $Id: company_manager_face.h 25490 2013-06-27 20:20:13Z rubidium $ */ /* * 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 company_manager_face.h Functionality related to the company manager's face */ #ifndef COMPANY_MANAGER_FACE_H #define COMPANY_MANAGER_FACE_H #include "core/random_func.hpp" #include "core/bitmath_func.hpp" #include "table/sprites.h" #include "company_type.h" /** The gender/race combinations that we have faces for */ enum GenderEthnicity { GENDER_FEMALE = 0, ///< This bit set means a female, otherwise male ETHNICITY_BLACK = 1, ///< This bit set means black, otherwise white GE_WM = 0, ///< A male of Caucasian origin (white) GE_WF = 1 << GENDER_FEMALE, ///< A female of Caucasian origin (white) GE_BM = 1 << ETHNICITY_BLACK, ///< A male of African origin (black) GE_BF = 1 << ETHNICITY_BLACK | 1 << GENDER_FEMALE, ///< A female of African origin (black) GE_END, }; DECLARE_ENUM_AS_BIT_SET(GenderEthnicity) ///< See GenderRace as a bitset /** Bitgroups of the CompanyManagerFace variable */ enum CompanyManagerFaceVariable { CMFV_GENDER, CMFV_ETHNICITY, CMFV_GEN_ETHN, CMFV_HAS_MOUSTACHE, CMFV_HAS_TIE_EARRING, CMFV_HAS_GLASSES, CMFV_EYE_COLOUR, CMFV_CHEEKS, CMFV_CHIN, CMFV_EYEBROWS, CMFV_MOUSTACHE, CMFV_LIPS, CMFV_NOSE, CMFV_HAIR, CMFV_JACKET, CMFV_COLLAR, CMFV_TIE_EARRING, CMFV_GLASSES, CMFV_END, }; DECLARE_POSTFIX_INCREMENT(CompanyManagerFaceVariable) /** Information about the valid values of CompanyManagerFace bitgroups as well as the sprites to draw */ struct CompanyManagerFaceBitsInfo { byte offset; ///< Offset in bits into the CompanyManagerFace byte length; ///< Number of bits used in the CompanyManagerFace byte valid_values[GE_END]; ///< The number of valid values per gender/ethnicity SpriteID first_sprite[GE_END]; ///< The first sprite per gender/ethnicity }; /** Lookup table for indices into the CompanyManagerFace, valid ranges and sprites */ static const CompanyManagerFaceBitsInfo _cmf_info[] = { /* Index off len WM WF BM BF WM WF BM BF * CMFV_GENDER */ { 0, 1, { 2, 2, 2, 2 }, { 0, 0, 0, 0 } }, ///< 0 = male, 1 = female /* CMFV_ETHNICITY */ { 1, 2, { 2, 2, 2, 2 }, { 0, 0, 0, 0 } }, ///< 0 = (Western-)Caucasian, 1 = African(-American)/Black /* CMFV_GEN_ETHN */ { 0, 3, { 4, 4, 4, 4 }, { 0, 0, 0, 0 } }, ///< Shortcut to get/set gender _and_ ethnicity /* CMFV_HAS_MOUSTACHE */ { 3, 1, { 2, 0, 2, 0 }, { 0, 0, 0, 0 } }, ///< Females do not have a moustache /* CMFV_HAS_TIE_EARRING */ { 3, 1, { 0, 2, 0, 2 }, { 0, 0, 0, 0 } }, ///< Draw the earring for females or not. For males the tie is always drawn. /* CMFV_HAS_GLASSES */ { 4, 1, { 2, 2, 2, 2 }, { 0, 0, 0, 0 } }, ///< Whether to draw glasses or not /* CMFV_EYE_COLOUR */ { 5, 2, { 3, 3, 1, 1 }, { 0, 0, 0, 0 } }, ///< Palette modification /* CMFV_CHEEKS */ { 0, 0, { 1, 1, 1, 1 }, { 0x325, 0x326, 0x390, 0x3B0 } }, ///< Cheeks are only indexed by their gender/ethnicity /* CMFV_CHIN */ { 7, 2, { 4, 1, 2, 2 }, { 0x327, 0x327, 0x391, 0x3B1 } }, /* CMFV_EYEBROWS */ { 9, 4, { 12, 16, 11, 16 }, { 0x32B, 0x337, 0x39A, 0x3B8 } }, /* CMFV_MOUSTACHE */ { 13, 2, { 3, 0, 3, 0 }, { 0x367, 0, 0x397, 0 } }, ///< Depends on CMFV_HAS_MOUSTACHE /* CMFV_LIPS */ { 13, 4, { 12, 10, 9, 9 }, { 0x35B, 0x351, 0x3A5, 0x3C8 } }, ///< Depends on !CMFV_HAS_MOUSTACHE /* CMFV_NOSE */ { 17, 3, { 8, 4, 4, 5 }, { 0x349, 0x34C, 0x393, 0x3B3 } }, ///< Depends on !CMFV_HAS_MOUSTACHE /* CMFV_HAIR */ { 20, 4, { 9, 5, 5, 4 }, { 0x382, 0x38B, 0x3D4, 0x3D9 } }, /* CMFV_JACKET */ { 24, 2, { 3, 3, 3, 3 }, { 0x36B, 0x378, 0x36B, 0x378 } }, /* CMFV_COLLAR */ { 26, 2, { 4, 4, 4, 4 }, { 0x36E, 0x37B, 0x36E, 0x37B } }, /* CMFV_TIE_EARRING */ { 28, 3, { 6, 3, 6, 3 }, { 0x372, 0x37F, 0x372, 0x3D1 } }, ///< Depends on CMFV_HAS_TIE_EARRING /* CMFV_GLASSES */ { 31, 1, { 2, 2, 2, 2 }, { 0x347, 0x347, 0x3AE, 0x3AE } } ///< Depends on CMFV_HAS_GLASSES }; /** Make sure the table's size is right. */ assert_compile(lengthof(_cmf_info) == CMFV_END); /** * Gets the company manager's face bits for the given company manager's face variable * @param cmf the face to extract the bits from * @param cmfv the face variable to get the data of * @param ge the gender and ethnicity of the face * @pre _cmf_info[cmfv].valid_values[ge] != 0 * @return the requested bits */ static inline uint GetCompanyManagerFaceBits(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge) { assert(_cmf_info[cmfv].valid_values[ge] != 0); return GB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length); } /** * Sets the company manager's face bits for the given company manager's face variable * @param cmf the face to write the bits to * @param cmfv the face variable to write the data of * @param ge the gender and ethnicity of the face * @param val the new value * @pre val < _cmf_info[cmfv].valid_values[ge] */ static inline void SetCompanyManagerFaceBits(CompanyManagerFace &cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge, uint val) { assert(val < _cmf_info[cmfv].valid_values[ge]); SB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length, val); } /** * Increase/Decrease the company manager's face variable by the given amount. * If the new value greater than the max value for this variable it will be set to 0. * Or is it negative (< 0) it will be set to max value. * * @param cmf the company manager face to write the bits to * @param cmfv the company manager face variable to write the data of * @param ge the gender and ethnicity of the company manager's face * @param amount the amount which change the value * * @pre 0 <= val < _cmf_info[cmfv].valid_values[ge] */ static inline void IncreaseCompanyManagerFaceBits(CompanyManagerFace &cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge, int8 amount) { int8 val = GetCompanyManagerFaceBits(cmf, cmfv, ge) + amount; // the new value for the cmfv /* scales the new value to the correct scope */ if (val >= _cmf_info[cmfv].valid_values[ge]) { val = 0; } else if (val < 0) { val = _cmf_info[cmfv].valid_values[ge] - 1; } SetCompanyManagerFaceBits(cmf, cmfv, ge, val); // save the new value } /** * Checks whether the company manager's face bits have a valid range * @param cmf the face to extract the bits from * @param cmfv the face variable to get the data of * @param ge the gender and ethnicity of the face * @return true if and only if the bits are valid */ static inline bool AreCompanyManagerFaceBitsValid(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge) { return GB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length) < _cmf_info[cmfv].valid_values[ge]; } /** * Scales a company manager's face bits variable to the correct scope * @param cmfv the face variable to write the data of * @param ge the gender and ethnicity of the face * @param val the to value to scale * @pre val < (1U << _cmf_info[cmfv].length), i.e. val has a value of 0..2^(bits used for this variable)-1 * @return the scaled value */ static inline uint ScaleCompanyManagerFaceValue(CompanyManagerFaceVariable cmfv, GenderEthnicity ge, uint val) { assert(val < (1U << _cmf_info[cmfv].length)); return (val * _cmf_info[cmfv].valid_values[ge]) >> _cmf_info[cmfv].length; } /** * Scales all company manager's face bits to the correct scope * * @param cmf the company manager's face to write the bits to */ static inline void ScaleAllCompanyManagerFaceBits(CompanyManagerFace &cmf) { IncreaseCompanyManagerFaceBits(cmf, CMFV_ETHNICITY, GE_WM, 0); // scales the ethnicity GenderEthnicity ge = (GenderEthnicity)GB(cmf, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // gender & ethnicity of the face /* Is a male face with moustache. Need to reduce CPU load in the loop. */ bool is_moust_male = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0; for (CompanyManagerFaceVariable cmfv = CMFV_EYE_COLOUR; cmfv < CMFV_END; cmfv++) { // scales all other variables /* The moustache variable will be scaled only if it is a male face with has a moustache */ if (cmfv != CMFV_MOUSTACHE || is_moust_male) { IncreaseCompanyManagerFaceBits(cmf, cmfv, ge, 0); } } } /** * Make a random new face. * If it is for the advanced company manager's face window then the new face have the same gender * and ethnicity as the old one, else the gender is equal and the ethnicity is random. * * @param cmf the company manager's face to write the bits to * @param ge the gender and ethnicity of the old company manager's face * @param adv if it for the advanced company manager's face window * @param interactive is the call from within the user interface? * * @pre scale 'ge' to a valid gender/ethnicity combination */ static inline void RandomCompanyManagerFaceBits(CompanyManagerFace &cmf, GenderEthnicity ge, bool adv, bool interactive = true) { /* This method is called from a command when not interactive and * then we must use Random to get the same result on all clients. */ cmf = interactive ? InteractiveRandom() : Random(); // random all company manager's face bits /* scale ge: 0 == GE_WM, 1 == GE_WF, 2 == GE_BM, 3 == GE_BF (and maybe in future: ...) */ ge = (GenderEthnicity)((uint)ge % GE_END); /* set the gender (and ethnicity) for the new company manager's face */ if (adv) { SetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, ge, ge); } else { SetCompanyManagerFaceBits(cmf, CMFV_GENDER, ge, HasBit(ge, GENDER_FEMALE)); } /* scales all company manager's face bits to the correct scope */ ScaleAllCompanyManagerFaceBits(cmf); } /** * Gets the sprite to draw for the given company manager's face variable * @param cmf the face to extract the data from * @param cmfv the face variable to get the sprite of * @param ge the gender and ethnicity of the face * @pre _cmf_info[cmfv].valid_values[ge] != 0 * @return sprite to draw */ static inline SpriteID GetCompanyManagerFaceSprite(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge) { assert(_cmf_info[cmfv].valid_values[ge] != 0); return _cmf_info[cmfv].first_sprite[ge] + GB(cmf, _cmf_info[cmfv].offset, _cmf_info[cmfv].length); } void DrawCompanyManagerFace(CompanyManagerFace face, int colour, int x, int y); #endif /* COMPANY_MANAGER_FACE_H */ openttd-1.5.3/src/clear_cmd.cpp0000644000000000000000000002724612627373442015124 0ustar rootroot/* $Id: clear_cmd.cpp 27214 2015-03-31 18:45:30Z frosch $ */ /* * 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 clear_cmd.cpp Commands related to clear tiles. */ #include "stdafx.h" #include "clear_map.h" #include "command_func.h" #include "landscape.h" #include "genworld.h" #include "viewport_func.h" #include "water.h" #include "core/random_func.hpp" #include "newgrf_generic.h" #include "table/strings.h" #include "table/sprites.h" #include "table/clear_land.h" #include "safeguards.h" static CommandCost ClearTile_Clear(TileIndex tile, DoCommandFlag flags) { static const Price clear_price_table[] = { PR_CLEAR_GRASS, PR_CLEAR_ROUGH, PR_CLEAR_ROCKS, PR_CLEAR_FIELDS, PR_CLEAR_ROUGH, PR_CLEAR_ROUGH, }; CommandCost price(EXPENSES_CONSTRUCTION); if (!IsClearGround(tile, CLEAR_GRASS) || GetClearDensity(tile) != 0) { price.AddCost(_price[clear_price_table[GetClearGround(tile)]]); } if (flags & DC_EXEC) DoClearSquare(tile); return price; } void DrawClearLandTile(const TileInfo *ti, byte set) { DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh) + set * 19, PAL_NONE); } void DrawHillyLandTile(const TileInfo *ti) { if (ti->tileh != SLOPE_FLAT) { DrawGroundSprite(SPR_FLAT_ROUGH_LAND + SlopeToSpriteOffset(ti->tileh), PAL_NONE); } else { DrawGroundSprite(_landscape_clear_sprites_rough[GB(ti->x ^ ti->y, 4, 3)], PAL_NONE); } } static void DrawClearLandFence(const TileInfo *ti) { /* combine fences into one sprite object */ StartSpriteCombine(); int maxz = GetSlopeMaxPixelZ(ti->tileh); uint fence_nw = GetFence(ti->tile, DIAGDIR_NW); if (fence_nw != 0) { int z = GetSlopePixelZInCorner(ti->tileh, CORNER_W); SpriteID sprite = _clear_land_fence_sprites[fence_nw - 1] + _fence_mod_by_tileh_nw[ti->tileh]; AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y - 15, 16, 31, maxz - z + 4, ti->z + z, false, 0, 15, -z); } uint fence_ne = GetFence(ti->tile, DIAGDIR_NE); if (fence_ne != 0) { int z = GetSlopePixelZInCorner(ti->tileh, CORNER_E); SpriteID sprite = _clear_land_fence_sprites[fence_ne - 1] + _fence_mod_by_tileh_ne[ti->tileh]; AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x - 15, ti->y, 31, 16, maxz - z + 4, ti->z + z, false, 15, 0, -z); } uint fence_sw = GetFence(ti->tile, DIAGDIR_SW); uint fence_se = GetFence(ti->tile, DIAGDIR_SE); if (fence_sw != 0 || fence_se != 0) { int z = GetSlopePixelZInCorner(ti->tileh, CORNER_S); if (fence_sw != 0) { SpriteID sprite = _clear_land_fence_sprites[fence_sw - 1] + _fence_mod_by_tileh_sw[ti->tileh]; AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z); } if (fence_se != 0) { SpriteID sprite = _clear_land_fence_sprites[fence_se - 1] + _fence_mod_by_tileh_se[ti->tileh]; AddSortableSpriteToDraw(sprite, PAL_NONE, ti->x, ti->y, 16, 16, maxz - z + 4, ti->z + z, false, 0, 0, -z); } } EndSpriteCombine(); } static void DrawTile_Clear(TileInfo *ti) { switch (GetClearGround(ti->tile)) { case CLEAR_GRASS: DrawClearLandTile(ti, GetClearDensity(ti->tile)); break; case CLEAR_ROUGH: DrawHillyLandTile(ti); break; case CLEAR_ROCKS: DrawGroundSprite((HasGrfMiscBit(GMB_SECOND_ROCKY_TILE_SET) && (TileHash(ti->x, ti->y) & 1) ? SPR_FLAT_ROCKY_LAND_2 : SPR_FLAT_ROCKY_LAND_1) + SlopeToSpriteOffset(ti->tileh), PAL_NONE); break; case CLEAR_FIELDS: DrawGroundSprite(_clear_land_sprites_farmland[GetFieldType(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE); DrawClearLandFence(ti); break; case CLEAR_SNOW: case CLEAR_DESERT: DrawGroundSprite(_clear_land_sprites_snow_desert[GetClearDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE); break; } DrawBridgeMiddle(ti); } static int GetSlopePixelZ_Clear(TileIndex tile, uint x, uint y) { int z; Slope tileh = GetTilePixelSlope(tile, &z); return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh); } static Foundation GetFoundation_Clear(TileIndex tile, Slope tileh) { return FOUNDATION_NONE; } static void UpdateFences(TileIndex tile) { assert(IsTileType(tile, MP_CLEAR) && IsClearGround(tile, CLEAR_FIELDS)); bool dirty = false; bool neighbour = (IsTileType(TILE_ADDXY(tile, 1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 1, 0), CLEAR_FIELDS)); if (!neighbour && GetFence(tile, DIAGDIR_SW) == 0) { SetFence(tile, DIAGDIR_SW, 3); dirty = true; } neighbour = (IsTileType(TILE_ADDXY(tile, 0, 1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, 1), CLEAR_FIELDS)); if (!neighbour && GetFence(tile, DIAGDIR_SE) == 0) { SetFence(tile, DIAGDIR_SE, 3); dirty = true; } neighbour = (IsTileType(TILE_ADDXY(tile, -1, 0), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, -1, 0), CLEAR_FIELDS)); if (!neighbour && GetFence(tile, DIAGDIR_NE) == 0) { SetFence(tile, DIAGDIR_NE, 3); dirty = true; } neighbour = (IsTileType(TILE_ADDXY(tile, 0, -1), MP_CLEAR) && IsClearGround(TILE_ADDXY(tile, 0, -1), CLEAR_FIELDS)); if (!neighbour && GetFence(tile, DIAGDIR_NW) == 0) { SetFence(tile, DIAGDIR_NW, 3); dirty = true; } if (dirty) MarkTileDirtyByTile(tile); } /** Convert to or from snowy tiles. */ static void TileLoopClearAlps(TileIndex tile) { int k = GetTileZ(tile) - GetSnowLine() + 1; if (k < 0) { /* Below the snow line, do nothing if no snow. */ if (!IsSnowTile(tile)) return; } else { /* At or above the snow line, make snow tile if needed. */ if (!IsSnowTile(tile)) { MakeSnow(tile); MarkTileDirtyByTile(tile); return; } } /* Update snow density. */ uint current_density = GetClearDensity(tile); uint req_density = (k < 0) ? 0u : min((uint)k, 3); if (current_density < req_density) { AddClearDensity(tile, 1); } else if (current_density > req_density) { AddClearDensity(tile, -1); } else { /* Density at the required level. */ if (k >= 0) return; ClearSnow(tile); } MarkTileDirtyByTile(tile); } /** * Tests if at least one surrounding tile is desert * @param tile tile to check * @return does this tile have at least one desert tile around? */ static inline bool NeighbourIsDesert(TileIndex tile) { return GetTropicZone(tile + TileDiffXY( 1, 0)) == TROPICZONE_DESERT || GetTropicZone(tile + TileDiffXY( -1, 0)) == TROPICZONE_DESERT || GetTropicZone(tile + TileDiffXY( 0, 1)) == TROPICZONE_DESERT || GetTropicZone(tile + TileDiffXY( 0, -1)) == TROPICZONE_DESERT; } static void TileLoopClearDesert(TileIndex tile) { /* Current desert level - 0 if it is not desert */ uint current = 0; if (IsClearGround(tile, CLEAR_DESERT)) current = GetClearDensity(tile); /* Expected desert level - 0 if it shouldn't be desert */ uint expected = 0; if (GetTropicZone(tile) == TROPICZONE_DESERT) { expected = 3; } else if (NeighbourIsDesert(tile)) { expected = 1; } if (current == expected) return; if (expected == 0) { SetClearGroundDensity(tile, CLEAR_GRASS, 3); } else { /* Transition from clear to desert is not smooth (after clearing desert tile) */ SetClearGroundDensity(tile, CLEAR_DESERT, expected); } MarkTileDirtyByTile(tile); } static void TileLoop_Clear(TileIndex tile) { /* If the tile is at any edge flood it to prevent maps without water. */ if (_settings_game.construction.freeform_edges && DistanceFromEdge(tile) == 1) { int z; if (IsTileFlat(tile, &z) && z == 0) { DoFloodTile(tile); MarkTileDirtyByTile(tile); return; } } AmbientSoundEffect(tile); switch (_settings_game.game_creation.landscape) { case LT_TROPIC: TileLoopClearDesert(tile); break; case LT_ARCTIC: TileLoopClearAlps(tile); break; } switch (GetClearGround(tile)) { case CLEAR_GRASS: if (GetClearDensity(tile) == 3) return; if (_game_mode != GM_EDITOR) { if (GetClearCounter(tile) < 7) { AddClearCounter(tile, 1); return; } else { SetClearCounter(tile, 0); AddClearDensity(tile, 1); } } else { SetClearGroundDensity(tile, GB(Random(), 0, 8) > 21 ? CLEAR_GRASS : CLEAR_ROUGH, 3); } break; case CLEAR_FIELDS: UpdateFences(tile); if (_game_mode == GM_EDITOR) return; if (GetClearCounter(tile) < 7) { AddClearCounter(tile, 1); return; } else { SetClearCounter(tile, 0); } if (GetIndustryIndexOfField(tile) == INVALID_INDUSTRY && GetFieldType(tile) >= 7) { /* This farmfield is no longer farmfield, so make it grass again */ MakeClear(tile, CLEAR_GRASS, 2); } else { uint field_type = GetFieldType(tile); field_type = (field_type < 8) ? field_type + 1 : 0; SetFieldType(tile, field_type); } break; default: return; } MarkTileDirtyByTile(tile); } void GenerateClearTile() { uint i, gi; TileIndex tile; /* add rough tiles */ i = ScaleByMapSize(GB(Random(), 0, 10) + 0x400); gi = ScaleByMapSize(GB(Random(), 0, 7) + 0x80); SetGeneratingWorldProgress(GWP_ROUGH_ROCKY, gi + i); do { IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); tile = RandomTile(); if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) SetClearGroundDensity(tile, CLEAR_ROUGH, 3); } while (--i); /* add rocky tiles */ i = gi; do { uint32 r = Random(); tile = RandomTileSeed(r); IncreaseGeneratingWorldProgress(GWP_ROUGH_ROCKY); if (IsTileType(tile, MP_CLEAR) && !IsClearGround(tile, CLEAR_DESERT)) { uint j = GB(r, 16, 4) + 5; for (;;) { TileIndex tile_new; SetClearGroundDensity(tile, CLEAR_ROCKS, 3); do { if (--j == 0) goto get_out; tile_new = tile + TileOffsByDiagDir((DiagDirection)GB(Random(), 0, 2)); } while (!IsTileType(tile_new, MP_CLEAR) || IsClearGround(tile_new, CLEAR_DESERT)); tile = tile_new; } get_out:; } } while (--i); } static TrackStatus GetTileTrackStatus_Clear(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { return 0; } static const StringID _clear_land_str[] = { STR_LAI_CLEAR_DESCRIPTION_GRASS, STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND, STR_LAI_CLEAR_DESCRIPTION_ROCKS, STR_LAI_CLEAR_DESCRIPTION_FIELDS, STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND, STR_LAI_CLEAR_DESCRIPTION_DESERT }; static void GetTileDesc_Clear(TileIndex tile, TileDesc *td) { if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) == 0) { td->str = STR_LAI_CLEAR_DESCRIPTION_BARE_LAND; } else { td->str = _clear_land_str[GetClearGround(tile)]; } td->owner[0] = GetTileOwner(tile); } static void ChangeTileOwner_Clear(TileIndex tile, Owner old_owner, Owner new_owner) { return; } static CommandCost TerraformTile_Clear(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } extern const TileTypeProcs _tile_type_clear_procs = { DrawTile_Clear, ///< draw_tile_proc GetSlopePixelZ_Clear, ///< get_slope_z_proc ClearTile_Clear, ///< clear_tile_proc NULL, ///< add_accepted_cargo_proc GetTileDesc_Clear, ///< get_tile_desc_proc GetTileTrackStatus_Clear, ///< get_tile_track_status_proc NULL, ///< click_tile_proc NULL, ///< animate_tile_proc TileLoop_Clear, ///< tile_loop_proc ChangeTileOwner_Clear, ///< change_tile_owner_proc NULL, ///< add_produced_cargo_proc NULL, ///< vehicle_enter_tile_proc GetFoundation_Clear, ///< get_foundation_proc TerraformTile_Clear, ///< terraform_tile_proc }; openttd-1.5.3/src/order_cmd.cpp0000644000000000000000000022261112627373441015141 0ustar rootroot/* $Id: order_cmd.cpp 26694 2014-07-16 22:24:55Z frosch $ */ /* * 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 order_cmd.cpp Handling of orders. */ #include "stdafx.h" #include "debug.h" #include "cmd_helper.h" #include "command_func.h" #include "company_func.h" #include "news_func.h" #include "strings_func.h" #include "timetable.h" #include "vehicle_func.h" #include "depot_base.h" #include "core/pool_func.hpp" #include "core/random_func.hpp" #include "aircraft.h" #include "roadveh.h" #include "station_base.h" #include "waypoint_base.h" #include "company_base.h" #include "order_backup.h" #include "cheat_type.h" #include "table/strings.h" #include "safeguards.h" /* DestinationID must be at least as large as every these below, because it can * be any of them */ assert_compile(sizeof(DestinationID) >= sizeof(DepotID)); assert_compile(sizeof(DestinationID) >= sizeof(StationID)); OrderPool _order_pool("Order"); INSTANTIATE_POOL_METHODS(Order) OrderListPool _orderlist_pool("OrderList"); INSTANTIATE_POOL_METHODS(OrderList) /** Clean everything up. */ Order::~Order() { if (CleaningPool()) return; /* We can visit oil rigs and buoys that are not our own. They will be shown in * the list of stations. So, we need to invalidate that window if needed. */ if (this->IsType(OT_GOTO_STATION) || this->IsType(OT_GOTO_WAYPOINT)) { BaseStation *bs = BaseStation::GetIfValid(this->GetDestination()); if (bs != NULL && bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0); } } /** * 'Free' the order * @note ONLY use on "current_order" vehicle orders! */ void Order::Free() { this->type = OT_NOTHING; this->flags = 0; this->dest = 0; this->next = NULL; } /** * Makes this order a Go To Station order. * @param destination the station to go to. */ void Order::MakeGoToStation(StationID destination) { this->type = OT_GOTO_STATION; this->flags = 0; this->dest = destination; } /** * Makes this order a Go To Depot order. * @param destination the depot to go to. * @param order is this order a 'default' order, or an overridden vehicle order? * @param non_stop_type how to get to the depot? * @param action what to do in the depot? * @param cargo the cargo type to change to. */ void Order::MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type, OrderDepotActionFlags action, CargoID cargo) { this->type = OT_GOTO_DEPOT; this->SetDepotOrderType(order); this->SetDepotActionType(action); this->SetNonStopType(non_stop_type); this->dest = destination; this->SetRefit(cargo); } /** * Makes this order a Go To Waypoint order. * @param destination the waypoint to go to. */ void Order::MakeGoToWaypoint(StationID destination) { this->type = OT_GOTO_WAYPOINT; this->flags = 0; this->dest = destination; } /** * Makes this order a Loading order. * @param ordered is this an ordered stop? */ void Order::MakeLoading(bool ordered) { this->type = OT_LOADING; if (!ordered) this->flags = 0; } /** * Makes this order a Leave Station order. */ void Order::MakeLeaveStation() { this->type = OT_LEAVESTATION; this->flags = 0; } /** * Makes this order a Dummy order. */ void Order::MakeDummy() { this->type = OT_DUMMY; this->flags = 0; } /** * Makes this order an conditional order. * @param order the order to jump to. */ void Order::MakeConditional(VehicleOrderID order) { this->type = OT_CONDITIONAL; this->flags = order; this->dest = 0; } /** * Makes this order an implicit order. * @param destination the station to go to. */ void Order::MakeImplicit(StationID destination) { this->type = OT_IMPLICIT; this->dest = destination; } /** * Make this depot/station order also a refit order. * @param cargo the cargo type to change to. * @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION). */ void Order::SetRefit(CargoID cargo) { this->refit_cargo = cargo; } /** * Does this order have the same type, flags and destination? * @param other the second order to compare to. * @return true if the type, flags and destination match. */ bool Order::Equals(const Order &other) const { /* In case of go to nearest depot orders we need "only" compare the flags * with the other and not the nearest depot order bit or the actual * destination because those get clear/filled in during the order * evaluation. If we do not do this the order will continuously be seen as * a different order and it will try to find a "nearest depot" every tick. */ if ((this->IsType(OT_GOTO_DEPOT) && this->type == other.type) && ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0 || (other.GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0)) { return this->GetDepotOrderType() == other.GetDepotOrderType() && (this->GetDepotActionType() & ~ODATFB_NEAREST_DEPOT) == (other.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT); } return this->type == other.type && this->flags == other.flags && this->dest == other.dest; } /** * Pack this order into a 32 bits integer, or actually only * the type, flags and destination. * @return the packed representation. * @note unpacking is done in the constructor. */ uint32 Order::Pack() const { return this->dest << 16 | this->flags << 8 | this->type; } /** * Pack this order into a 16 bits integer as close to the TTD * representation as possible. * @return the TTD-like packed representation. */ uint16 Order::MapOldOrder() const { uint16 order = this->GetType(); switch (this->type) { case OT_GOTO_STATION: if (this->GetUnloadType() & OUFB_UNLOAD) SetBit(order, 5); if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6); if (this->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) SetBit(order, 7); order |= GB(this->GetDestination(), 0, 8) << 8; break; case OT_GOTO_DEPOT: if (!(this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) SetBit(order, 6); SetBit(order, 7); order |= GB(this->GetDestination(), 0, 8) << 8; break; case OT_LOADING: if (this->GetLoadType() & OLFB_FULL_LOAD) SetBit(order, 6); break; } return order; } /** * Create an order based on a packed representation of that order. * @param packed the packed representation. */ Order::Order(uint32 packed) { this->type = (OrderType)GB(packed, 0, 8); this->flags = GB(packed, 8, 8); this->dest = GB(packed, 16, 16); this->next = NULL; this->refit_cargo = CT_NO_REFIT; this->wait_time = 0; this->travel_time = 0; this->max_speed = UINT16_MAX; } /** * * Updates the widgets of a vehicle which contains the order-data * */ void InvalidateVehicleOrder(const Vehicle *v, int data) { SetWindowDirty(WC_VEHICLE_VIEW, v->index); if (data != 0) { /* Calls SetDirty() too */ InvalidateWindowData(WC_VEHICLE_ORDERS, v->index, data); InvalidateWindowData(WC_VEHICLE_TIMETABLE, v->index, data); return; } SetWindowDirty(WC_VEHICLE_ORDERS, v->index); SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } /** * * Assign data to an order (from another order) * This function makes sure that the index is maintained correctly * @param other the data to copy (except next pointer). * */ void Order::AssignOrder(const Order &other) { this->type = other.type; this->flags = other.flags; this->dest = other.dest; this->refit_cargo = other.refit_cargo; this->wait_time = other.wait_time; this->travel_time = other.travel_time; this->max_speed = other.max_speed; } /** * Recomputes everything. * @param chain first order in the chain * @param v one of vehicle that is using this orderlist */ void OrderList::Initialize(Order *chain, Vehicle *v) { this->first = chain; this->first_shared = v; this->num_orders = 0; this->num_manual_orders = 0; this->num_vehicles = 1; this->timetable_duration = 0; this->total_duration = 0; for (Order *o = this->first; o != NULL; o = o->next) { ++this->num_orders; if (!o->IsType(OT_IMPLICIT)) ++this->num_manual_orders; this->timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel(); this->total_duration += o->GetWaitTime() + o->GetTravelTime(); } for (Vehicle *u = this->first_shared->PreviousShared(); u != NULL; u = u->PreviousShared()) { ++this->num_vehicles; this->first_shared = u; } for (const Vehicle *u = v->NextShared(); u != NULL; u = u->NextShared()) ++this->num_vehicles; } /** * Free a complete order chain. * @param keep_orderlist If this is true only delete the orders, otherwise also delete the OrderList. * @note do not use on "current_order" vehicle orders! */ void OrderList::FreeChain(bool keep_orderlist) { Order *next; for (Order *o = this->first; o != NULL; o = next) { next = o->next; delete o; } if (keep_orderlist) { this->first = NULL; this->num_orders = 0; this->num_manual_orders = 0; this->timetable_duration = 0; } else { delete this; } } /** * Get a certain order of the order chain. * @param index zero-based index of the order within the chain. * @return the order at position index. */ Order *OrderList::GetOrderAt(int index) const { if (index < 0) return NULL; Order *order = this->first; while (order != NULL && index-- > 0) { order = order->next; } return order; } /** * Get the next order which will make the given vehicle stop at a station * or refit at a depot or evaluate a non-trivial condition. * @param next The order to start looking at. * @param hops The number of orders we have already looked at. * @return Either of * \li a station order * \li a refitting depot order * \li a non-trivial conditional order * \li NULL if the vehicle won't stop anymore. */ const Order *OrderList::GetNextDecisionNode(const Order *next, uint hops) const { if (hops > this->GetNumOrders() || next == NULL) return NULL; if (next->IsType(OT_CONDITIONAL)) { if (next->GetConditionVariable() != OCV_UNCONDITIONALLY) return next; /* We can evaluate trivial conditions right away. They're conceptually * the same as regular order progression. */ return this->GetNextDecisionNode( this->GetOrderAt(next->GetConditionSkipToOrder()), hops + 1); } if (next->IsType(OT_GOTO_DEPOT)) { if (next->GetDepotActionType() == ODATFB_HALT) return NULL; if (next->IsRefit()) return next; } if (!next->CanLoadOrUnload()) { return this->GetNextDecisionNode(this->GetNext(next), hops + 1); } return next; } /** * Recursively determine the next deterministic station to stop at. * @param v The vehicle we're looking at. * @param first Order to start searching at or NULL to start at cur_implicit_order_index + 1. * @param hops Number of orders we have already looked at. * @return Next stoppping station or INVALID_STATION. * @pre The vehicle is currently loading and v->last_station_visited is meaningful. * @note This function may draw a random number. Don't use it from the GUI. */ StationIDStack OrderList::GetNextStoppingStation(const Vehicle *v, const Order *first, uint hops) const { const Order *next = first; if (first == NULL) { next = this->GetOrderAt(v->cur_implicit_order_index); if (next == NULL) { next = this->GetFirstOrder(); if (next == NULL) return INVALID_STATION; } else { /* GetNext never returns NULL if there is a valid station in the list. * As the given "next" is already valid and a station in the list, we * don't have to check for NULL here. */ next = this->GetNext(next); assert(next != NULL); } } do { next = this->GetNextDecisionNode(next, ++hops); /* Resolve possibly nested conditionals by estimation. */ while (next != NULL && next->IsType(OT_CONDITIONAL)) { /* We return both options of conditional orders. */ const Order *skip_to = this->GetNextDecisionNode( this->GetOrderAt(next->GetConditionSkipToOrder()), hops); const Order *advance = this->GetNextDecisionNode( this->GetNext(next), hops); if (advance == NULL || advance == first || skip_to == advance) { next = (skip_to == first) ? NULL : skip_to; } else if (skip_to == NULL || skip_to == first) { next = (advance == first) ? NULL : advance; } else { StationIDStack st1 = this->GetNextStoppingStation(v, skip_to, hops); StationIDStack st2 = this->GetNextStoppingStation(v, advance, hops); while (!st2.IsEmpty()) st1.Push(st2.Pop()); return st1; } ++hops; } /* Don't return a next stop if the vehicle has to unload everything. */ if (next == NULL || ((next->IsType(OT_GOTO_STATION) || next->IsType(OT_IMPLICIT)) && next->GetDestination() == v->last_station_visited && (next->GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) != 0)) { return INVALID_STATION; } } while (next->IsType(OT_GOTO_DEPOT) || next->GetDestination() == v->last_station_visited); return next->GetDestination(); } /** * Insert a new order into the order chain. * @param new_order is the order to insert into the chain. * @param index is the position where the order is supposed to be inserted. */ void OrderList::InsertOrderAt(Order *new_order, int index) { if (this->first == NULL) { this->first = new_order; } else { if (index == 0) { /* Insert as first or only order */ new_order->next = this->first; this->first = new_order; } else if (index >= this->num_orders) { /* index is after the last order, add it to the end */ this->GetLastOrder()->next = new_order; } else { /* Put the new order in between */ Order *order = this->GetOrderAt(index - 1); new_order->next = order->next; order->next = new_order; } } ++this->num_orders; if (!new_order->IsType(OT_IMPLICIT)) ++this->num_manual_orders; this->timetable_duration += new_order->GetTimetabledWait() + new_order->GetTimetabledTravel(); this->total_duration += new_order->GetWaitTime() + new_order->GetTravelTime(); /* We can visit oil rigs and buoys that are not our own. They will be shown in * the list of stations. So, we need to invalidate that window if needed. */ if (new_order->IsType(OT_GOTO_STATION) || new_order->IsType(OT_GOTO_WAYPOINT)) { BaseStation *bs = BaseStation::Get(new_order->GetDestination()); if (bs->owner == OWNER_NONE) InvalidateWindowClassesData(WC_STATION_LIST, 0); } } /** * Remove an order from the order list and delete it. * @param index is the position of the order which is to be deleted. */ void OrderList::DeleteOrderAt(int index) { if (index >= this->num_orders) return; Order *to_remove; if (index == 0) { to_remove = this->first; this->first = to_remove->next; } else { Order *prev = GetOrderAt(index - 1); to_remove = prev->next; prev->next = to_remove->next; } --this->num_orders; if (!to_remove->IsType(OT_IMPLICIT)) --this->num_manual_orders; this->timetable_duration -= (to_remove->GetTimetabledWait() + to_remove->GetTimetabledTravel()); this->total_duration -= (to_remove->GetWaitTime() + to_remove->GetTravelTime()); delete to_remove; } /** * Move an order to another position within the order list. * @param from is the zero-based position of the order to move. * @param to is the zero-based position where the order is moved to. */ void OrderList::MoveOrder(int from, int to) { if (from >= this->num_orders || to >= this->num_orders || from == to) return; Order *moving_one; /* Take the moving order out of the pointer-chain */ if (from == 0) { moving_one = this->first; this->first = moving_one->next; } else { Order *one_before = GetOrderAt(from - 1); moving_one = one_before->next; one_before->next = moving_one->next; } /* Insert the moving_order again in the pointer-chain */ if (to == 0) { moving_one->next = this->first; this->first = moving_one; } else { Order *one_before = GetOrderAt(to - 1); moving_one->next = one_before->next; one_before->next = moving_one; } } /** * Removes the vehicle from the shared order list. * @note This is supposed to be called when the vehicle is still in the chain * @param v vehicle to remove from the list */ void OrderList::RemoveVehicle(Vehicle *v) { --this->num_vehicles; if (v == this->first_shared) this->first_shared = v->NextShared(); } /** * Checks whether a vehicle is part of the shared vehicle chain. * @param v is the vehicle to search in the shared vehicle chain. */ bool OrderList::IsVehicleInSharedOrdersList(const Vehicle *v) const { for (const Vehicle *v_shared = this->first_shared; v_shared != NULL; v_shared = v_shared->NextShared()) { if (v_shared == v) return true; } return false; } /** * Gets the position of the given vehicle within the shared order vehicle list. * @param v is the vehicle of which to get the position * @return position of v within the shared vehicle chain. */ int OrderList::GetPositionInSharedOrderList(const Vehicle *v) const { int count = 0; for (const Vehicle *v_shared = v->PreviousShared(); v_shared != NULL; v_shared = v_shared->PreviousShared()) count++; return count; } /** * Checks whether all orders of the list have a filled timetable. * @return whether all orders have a filled timetable. */ bool OrderList::IsCompleteTimetable() const { for (Order *o = this->first; o != NULL; o = o->next) { /* Implicit orders are, by definition, not timetabled. */ if (o->IsType(OT_IMPLICIT)) continue; if (!o->IsCompletelyTimetabled()) return false; } return true; } /** * Checks for internal consistency of order list. Triggers assertion if something is wrong. */ void OrderList::DebugCheckSanity() const { VehicleOrderID check_num_orders = 0; VehicleOrderID check_num_manual_orders = 0; uint check_num_vehicles = 0; Ticks check_timetable_duration = 0; Ticks check_total_duration = 0; DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index); for (const Order *o = this->first; o != NULL; o = o->next) { ++check_num_orders; if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders; check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel(); check_total_duration += o->GetWaitTime() + o->GetTravelTime(); } assert(this->num_orders == check_num_orders); assert(this->num_manual_orders == check_num_manual_orders); assert(this->timetable_duration == check_timetable_duration); assert(this->total_duration == check_total_duration); for (const Vehicle *v = this->first_shared; v != NULL; v = v->NextShared()) { ++check_num_vehicles; assert(v->orders.list == this); } assert(this->num_vehicles == check_num_vehicles); DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i timetabled, %i total", (uint)this->num_orders, (uint)this->num_manual_orders, this->num_vehicles, this->timetable_duration, this->total_duration); } /** * Checks whether the order goes to a station or not, i.e. whether the * destination is a station * @param v the vehicle to check for * @param o the order to check * @return true if the destination is a station */ static inline bool OrderGoesToStation(const Vehicle *v, const Order *o) { return o->IsType(OT_GOTO_STATION) || (v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT)); } /** * Delete all news items regarding defective orders about a vehicle * This could kill still valid warnings (for example about void order when just * another order gets added), but assume the company will notice the problems, * when (s)he's changing the orders. */ static void DeleteOrderWarnings(const Vehicle *v) { DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS); DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER); DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY); DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY); DeleteVehicleNews(v->index, STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY); } /** * Returns a tile somewhat representing the order destination (not suitable for pathfinding). * @param v The vehicle to get the location for. * @param airport Get the airport tile and not the station location for aircraft. * @return destination of order, or INVALID_TILE if none. */ TileIndex Order::GetLocation(const Vehicle *v, bool airport) const { switch (this->GetType()) { case OT_GOTO_WAYPOINT: case OT_GOTO_STATION: case OT_IMPLICIT: if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile; return BaseStation::Get(this->GetDestination())->xy; case OT_GOTO_DEPOT: if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE; return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy; default: return INVALID_TILE; } } /** * Get the distance between two orders of a vehicle. Conditional orders are resolved * and the bigger distance of the two order branches is returned. * @param prev Origin order. * @param cur Destination order. * @param v The vehicle to get the distance for. * @param conditional_depth Internal param for resolving conditional orders. * @return Maximum distance between the two orders. */ uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth) { if (cur->IsType(OT_CONDITIONAL)) { if (conditional_depth > v->GetNumOrders()) return 0; conditional_depth++; int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth); int dist2 = GetOrderDistance(prev, cur->next == NULL ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth); return max(dist1, dist2); } TileIndex prev_tile = prev->GetLocation(v, true); TileIndex cur_tile = cur->GetLocation(v, true); if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0; return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile); } /** * Add an order to the orderlist of a vehicle. * @param tile unused * @param flags operation to perform * @param p1 various bitstuffed elements * - p1 = (bit 0 - 19) - ID of the vehicle * - p1 = (bit 24 - 31) - the selected order (if any). If the last order is given, * the order will be inserted before that one * the maximum vehicle order id is 254. * @param p2 packed order to insert * @param text unused * @return the cost of this operation or an error */ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh = GB(p1, 0, 20); VehicleOrderID sel_ord = GB(p1, 20, 8); Order new_order(p2); Vehicle *v = Vehicle::GetIfValid(veh); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; /* Check if the inserted order is to the correct destination (owner, type), * and has the correct flags if any */ switch (new_order.GetType()) { case OT_GOTO_STATION: { const Station *st = Station::GetIfValid(new_order.GetDestination()); if (st == NULL) return CMD_ERROR; if (st->owner != OWNER_NONE) { CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; } if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER); for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) { if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED); } /* Non stop only allowed for ground vehicles. */ if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR; /* Filter invalid load/unload types. */ switch (new_order.GetLoadType()) { case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break; default: return CMD_ERROR; } switch (new_order.GetUnloadType()) { case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break; default: return CMD_ERROR; } /* Filter invalid stop locations */ switch (new_order.GetStopLocation()) { case OSL_PLATFORM_NEAR_END: case OSL_PLATFORM_MIDDLE: if (v->type != VEH_TRAIN) return CMD_ERROR; /* FALL THROUGH */ case OSL_PLATFORM_FAR_END: break; default: return CMD_ERROR; } break; } case OT_GOTO_DEPOT: { if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) { if (v->type == VEH_AIRCRAFT) { const Station *st = Station::GetIfValid(new_order.GetDestination()); if (st == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(st->owner); if (ret.Failed()) return ret; if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) { return CMD_ERROR; } } else { const Depot *dp = Depot::GetIfValid(new_order.GetDestination()); if (dp == NULL) return CMD_ERROR; CommandCost ret = CheckOwnership(GetTileOwner(dp->xy)); if (ret.Failed()) return ret; switch (v->type) { case VEH_TRAIN: if (!IsRailDepotTile(dp->xy)) return CMD_ERROR; break; case VEH_ROAD: if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR; break; case VEH_SHIP: if (!IsShipDepotTile(dp->xy)) return CMD_ERROR; break; default: return CMD_ERROR; } } } if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR; if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) return CMD_ERROR; if (new_order.GetDepotActionType() & ~(ODATFB_HALT | ODATFB_NEAREST_DEPOT)) return CMD_ERROR; if ((new_order.GetDepotOrderType() & ODTFB_SERVICE) && (new_order.GetDepotActionType() & ODATFB_HALT)) return CMD_ERROR; break; } case OT_GOTO_WAYPOINT: { const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination()); if (wp == NULL) return CMD_ERROR; switch (v->type) { default: return CMD_ERROR; case VEH_TRAIN: { if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER); CommandCost ret = CheckOwnership(wp->owner); if (ret.Failed()) return ret; break; } case VEH_SHIP: if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER); if (wp->owner != OWNER_NONE) { CommandCost ret = CheckOwnership(wp->owner); if (ret.Failed()) return ret; } break; } /* Order flags can be any of the following for waypoints: * [non-stop] * non-stop orders (if any) are only valid for trains */ if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR; break; } case OT_CONDITIONAL: { VehicleOrderID skip_to = new_order.GetConditionSkipToOrder(); if (skip_to != 0 && skip_to >= v->GetNumOrders()) return CMD_ERROR; // Always allow jumping to the first (even when there is no order). if (new_order.GetConditionVariable() >= OCV_END) return CMD_ERROR; OrderConditionComparator occ = new_order.GetConditionComparator(); if (occ >= OCC_END) return CMD_ERROR; switch (new_order.GetConditionVariable()) { case OCV_REQUIRES_SERVICE: if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) return CMD_ERROR; break; case OCV_UNCONDITIONALLY: if (occ != OCC_EQUALS) return CMD_ERROR; if (new_order.GetConditionValue() != 0) return CMD_ERROR; break; case OCV_LOAD_PERCENTAGE: case OCV_RELIABILITY: if (new_order.GetConditionValue() > 100) return CMD_ERROR; /* FALL THROUGH */ default: if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) return CMD_ERROR; break; } break; } default: return CMD_ERROR; } if (sel_ord > v->GetNumOrders()) return CMD_ERROR; if (v->GetNumOrders() >= MAX_VEH_ORDER_ID) return_cmd_error(STR_ERROR_TOO_MANY_ORDERS); if (!Order::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); if (v->orders.list == NULL && !OrderList::CanAllocateItem()) return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); if (v->type == VEH_SHIP && _settings_game.pf.pathfinder_for_ships != VPF_NPF) { /* Make sure the new destination is not too far away from the previous */ const Order *prev = NULL; uint n = 0; /* Find the last goto station or depot order before the insert location. * If the order is to be inserted at the beginning of the order list this * finds the last order in the list. */ const Order *o; FOR_VEHICLE_ORDERS(v, o) { switch (o->GetType()) { case OT_GOTO_STATION: case OT_GOTO_DEPOT: case OT_GOTO_WAYPOINT: prev = o; break; default: break; } if (++n == sel_ord && prev != NULL) break; } if (prev != NULL) { uint dist; if (new_order.IsType(OT_CONDITIONAL)) { /* The order is not yet inserted, so we have to do the first iteration here. */ dist = GetOrderDistance(prev, v->GetOrder(new_order.GetConditionSkipToOrder()), v); } else { dist = GetOrderDistance(prev, &new_order, v); } if (dist >= 130) { return_cmd_error(STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION); } } } if (flags & DC_EXEC) { Order *new_o = new Order(); new_o->AssignOrder(new_order); InsertOrder(v, new_o, sel_ord); } return CommandCost(); } /** * Insert a new order but skip the validation. * @param v The vehicle to insert the order to. * @param new_o The new order. * @param sel_ord The position the order should be inserted at. */ void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord) { /* Create new order and link in list */ if (v->orders.list == NULL) { v->orders.list = new OrderList(new_o, v); } else { v->orders.list->InsertOrderAt(new_o, sel_ord); } Vehicle *u = v->FirstShared(); DeleteOrderWarnings(u); for (; u != NULL; u = u->NextShared()) { assert(v->orders.list == u->orders.list); /* If there is added an order before the current one, we need * to update the selected order. We do not change implicit/real order indices though. * If the new order is between the current implicit order and real order, the implicit order will * later skip the inserted order. */ if (sel_ord <= u->cur_real_order_index) { uint cur = u->cur_real_order_index + 1; /* Check if we don't go out of bound */ if (cur < u->GetNumOrders()) { u->cur_real_order_index = cur; } } if (sel_ord == u->cur_implicit_order_index && u->IsGroundVehicle()) { /* We are inserting an order just before the current implicit order. * We do not know whether we will reach current implicit or the newly inserted order first. * So, disable creation of implicit orders until we are on track again. */ uint16 &gv_flags = u->GetGroundVehicleFlags(); SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); } if (sel_ord <= u->cur_implicit_order_index) { uint cur = u->cur_implicit_order_index + 1; /* Check if we don't go out of bound */ if (cur < u->GetNumOrders()) { u->cur_implicit_order_index = cur; } } /* Update any possible open window of the vehicle */ InvalidateVehicleOrder(u, INVALID_VEH_ORDER_ID | (sel_ord << 8)); } /* As we insert an order, the order to skip to will be 'wrong'. */ VehicleOrderID cur_order_id = 0; Order *order; FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_CONDITIONAL)) { VehicleOrderID order_id = order->GetConditionSkipToOrder(); if (order_id >= sel_ord) { order->SetConditionSkipToOrder(order_id + 1); } if (order_id == cur_order_id) { order->SetConditionSkipToOrder((order_id + 1) % v->GetNumOrders()); } } cur_order_id++; } /* Make sure to rebuild the whole list */ InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0); } /** * Declone an order-list * @param *dst delete the orders of this vehicle * @param flags execution flags */ static CommandCost DecloneOrder(Vehicle *dst, DoCommandFlag flags) { if (flags & DC_EXEC) { DeleteVehicleOrders(dst); InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS); InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0); } return CommandCost(); } /** * Delete an order from the orderlist of a vehicle. * @param tile unused * @param flags operation to perform * @param p1 the ID of the vehicle * @param p2 the order to delete (max 255) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh_id = GB(p1, 0, 20); VehicleOrderID sel_ord = GB(p2, 0, 8); Vehicle *v = Vehicle::GetIfValid(veh_id); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; /* If we did not select an order, we maybe want to de-clone the orders */ if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags); if (v->GetOrder(sel_ord) == NULL) return CMD_ERROR; if (flags & DC_EXEC) DeleteOrder(v, sel_ord); return CommandCost(); } /** * Cancel the current loading order of the vehicle as the order was deleted. * @param v the vehicle */ static void CancelLoadingDueToDeletedOrder(Vehicle *v) { assert(v->current_order.IsType(OT_LOADING)); /* NON-stop flag is misused to see if a train is in a station that is * on his order list or not */ v->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE); /* When full loading, "cancel" that order so the vehicle doesn't * stay indefinitely at this station anymore. */ if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) v->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE); } /** * Delete an order but skip the parameter validation. * @param v The vehicle to delete the order from. * @param sel_ord The id of the order to be deleted. */ void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord) { v->orders.list->DeleteOrderAt(sel_ord); Vehicle *u = v->FirstShared(); DeleteOrderWarnings(u); for (; u != NULL; u = u->NextShared()) { assert(v->orders.list == u->orders.list); if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) { CancelLoadingDueToDeletedOrder(u); } if (sel_ord < u->cur_real_order_index) { u->cur_real_order_index--; } else if (sel_ord == u->cur_real_order_index) { u->UpdateRealOrderIndex(); } if (sel_ord < u->cur_implicit_order_index) { u->cur_implicit_order_index--; } else if (sel_ord == u->cur_implicit_order_index) { /* Make sure the index is valid */ if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0; /* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */ while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) { u->cur_implicit_order_index++; if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0; } } /* Update any possible open window of the vehicle */ InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8)); } /* As we delete an order, the order to skip to will be 'wrong'. */ VehicleOrderID cur_order_id = 0; Order *order = NULL; FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_CONDITIONAL)) { VehicleOrderID order_id = order->GetConditionSkipToOrder(); if (order_id >= sel_ord) { order_id = max(order_id - 1, 0); } if (order_id == cur_order_id) { order_id = (order_id + 1) % v->GetNumOrders(); } order->SetConditionSkipToOrder(order_id); } cur_order_id++; } InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0); } /** * Goto order of order-list. * @param tile unused * @param flags operation to perform * @param p1 The ID of the vehicle which order is skipped * @param p2 the selected order to which we want to skip * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh_id = GB(p1, 0, 20); VehicleOrderID sel_ord = GB(p2, 0, 8); Vehicle *v = Vehicle::GetIfValid(veh_id); if (v == NULL || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; if (flags & DC_EXEC) { if (v->current_order.IsType(OT_LOADING)) v->LeaveStation(); v->cur_implicit_order_index = v->cur_real_order_index = sel_ord; v->UpdateRealOrderIndex(); InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS); } /* We have an aircraft/ship, they have a mini-schedule, so update them all */ if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST); if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST); return CommandCost(); } /** * Move an order inside the orderlist * @param tile unused * @param flags operation to perform * @param p1 the ID of the vehicle * @param p2 order to move and target * bit 0-15 : the order to move * bit 16-31 : the target order * @param text unused * @return the cost of this operation or an error * @note The target order will move one place down in the orderlist * if you move the order upwards else it'll move it one place down */ CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh = GB(p1, 0, 20); VehicleOrderID moving_order = GB(p2, 0, 16); VehicleOrderID target_order = GB(p2, 16, 16); Vehicle *v = Vehicle::GetIfValid(veh); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; /* Don't make senseless movements */ if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() || moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR; Order *moving_one = v->GetOrder(moving_order); /* Don't move an empty order */ if (moving_one == NULL) return CMD_ERROR; if (flags & DC_EXEC) { v->orders.list->MoveOrder(moving_order, target_order); /* Update shared list */ Vehicle *u = v->FirstShared(); DeleteOrderWarnings(u); for (; u != NULL; u = u->NextShared()) { /* Update the current order. * There are multiple ways to move orders, which result in cur_implicit_order_index * and cur_real_order_index to not longer make any sense. E.g. moving another * real order between them. * * Basically one could choose to preserve either of them, but not both. * While both ways are suitable in this or that case from a human point of view, neither * of them makes really sense. * However, from an AI point of view, preserving cur_real_order_index is the most * predictable and transparent behaviour. * * With that decision it basically does not matter what we do to cur_implicit_order_index. * If we change orders between the implicit- and real-index, the implicit orders are mostly likely * completely out-dated anyway. So, keep it simple and just keep cur_implicit_order_index as well. * The worst which can happen is that a lot of implicit orders are removed when reaching current_order. */ if (u->cur_real_order_index == moving_order) { u->cur_real_order_index = target_order; } else if (u->cur_real_order_index > moving_order && u->cur_real_order_index <= target_order) { u->cur_real_order_index--; } else if (u->cur_real_order_index < moving_order && u->cur_real_order_index >= target_order) { u->cur_real_order_index++; } if (u->cur_implicit_order_index == moving_order) { u->cur_implicit_order_index = target_order; } else if (u->cur_implicit_order_index > moving_order && u->cur_implicit_order_index <= target_order) { u->cur_implicit_order_index--; } else if (u->cur_implicit_order_index < moving_order && u->cur_implicit_order_index >= target_order) { u->cur_implicit_order_index++; } assert(v->orders.list == u->orders.list); /* Update any possible open window of the vehicle */ InvalidateVehicleOrder(u, moving_order | (target_order << 8)); } /* As we move an order, the order to skip to will be 'wrong'. */ Order *order; FOR_VEHICLE_ORDERS(v, order) { if (order->IsType(OT_CONDITIONAL)) { VehicleOrderID order_id = order->GetConditionSkipToOrder(); if (order_id == moving_order) { order_id = target_order; } else if (order_id > moving_order && order_id <= target_order) { order_id--; } else if (order_id < moving_order && order_id >= target_order) { order_id++; } order->SetConditionSkipToOrder(order_id); } } /* Make sure to rebuild the whole list */ InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0); } return CommandCost(); } /** * Modify an order in the orderlist of a vehicle. * @param tile unused * @param flags operation to perform * @param p1 various bitstuffed elements * - p1 = (bit 0 - 19) - ID of the vehicle * - p1 = (bit 24 - 31) - the selected order (if any). If the last order is given, * the order will be inserted before that one * the maximum vehicle order id is 254. * @param p2 various bitstuffed elements * - p2 = (bit 0 - 3) - what data to modify (@see ModifyOrderFlags) * - p2 = (bit 4 - 15) - the data to modify * @param text unused * @return the cost of this operation or an error */ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleOrderID sel_ord = GB(p1, 20, 8); VehicleID veh = GB(p1, 0, 20); ModifyOrderFlags mof = Extract(p2); uint16 data = GB(p2, 4, 11); if (mof >= MOF_END) return CMD_ERROR; Vehicle *v = Vehicle::GetIfValid(veh); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; /* Is it a valid order? */ if (sel_ord >= v->GetNumOrders()) return CMD_ERROR; Order *order = v->GetOrder(sel_ord); switch (order->GetType()) { case OT_GOTO_STATION: if (mof != MOF_NON_STOP && mof != MOF_STOP_LOCATION && mof != MOF_UNLOAD && mof != MOF_LOAD) return CMD_ERROR; break; case OT_GOTO_DEPOT: if (mof != MOF_NON_STOP && mof != MOF_DEPOT_ACTION) return CMD_ERROR; break; case OT_GOTO_WAYPOINT: if (mof != MOF_NON_STOP) return CMD_ERROR; break; case OT_CONDITIONAL: if (mof != MOF_COND_VARIABLE && mof != MOF_COND_COMPARATOR && mof != MOF_COND_VALUE && mof != MOF_COND_DESTINATION) return CMD_ERROR; break; default: return CMD_ERROR; } switch (mof) { default: NOT_REACHED(); case MOF_NON_STOP: if (!v->IsGroundVehicle()) return CMD_ERROR; if (data >= ONSF_END) return CMD_ERROR; if (data == order->GetNonStopType()) return CMD_ERROR; break; case MOF_STOP_LOCATION: if (v->type != VEH_TRAIN) return CMD_ERROR; if (data >= OSL_END) return CMD_ERROR; break; case MOF_UNLOAD: if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return CMD_ERROR; if ((data & ~(OUFB_UNLOAD | OUFB_TRANSFER | OUFB_NO_UNLOAD)) != 0) return CMD_ERROR; /* Unload and no-unload are mutual exclusive and so are transfer and no unload. */ if (data != 0 && ((data & (OUFB_UNLOAD | OUFB_TRANSFER)) != 0) == ((data & OUFB_NO_UNLOAD) != 0)) return CMD_ERROR; if (data == order->GetUnloadType()) return CMD_ERROR; break; case MOF_LOAD: if (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) return CMD_ERROR; if (data > OLFB_NO_LOAD || data == 1) return CMD_ERROR; if (data == order->GetLoadType()) return CMD_ERROR; break; case MOF_DEPOT_ACTION: if (data >= DA_END) return CMD_ERROR; break; case MOF_COND_VARIABLE: if (data >= OCV_END) return CMD_ERROR; break; case MOF_COND_COMPARATOR: if (data >= OCC_END) return CMD_ERROR; switch (order->GetConditionVariable()) { case OCV_UNCONDITIONALLY: return CMD_ERROR; case OCV_REQUIRES_SERVICE: if (data != OCC_IS_TRUE && data != OCC_IS_FALSE) return CMD_ERROR; break; default: if (data == OCC_IS_TRUE || data == OCC_IS_FALSE) return CMD_ERROR; break; } break; case MOF_COND_VALUE: switch (order->GetConditionVariable()) { case OCV_UNCONDITIONALLY: case OCV_REQUIRES_SERVICE: return CMD_ERROR; case OCV_LOAD_PERCENTAGE: case OCV_RELIABILITY: if (data > 100) return CMD_ERROR; break; default: if (data > 2047) return CMD_ERROR; break; } break; case MOF_COND_DESTINATION: if (data >= v->GetNumOrders()) return CMD_ERROR; break; } if (flags & DC_EXEC) { switch (mof) { case MOF_NON_STOP: order->SetNonStopType((OrderNonStopFlags)data); if (data & ONSF_NO_STOP_AT_DESTINATION_STATION) { order->SetRefit(CT_NO_REFIT); order->SetLoadType(OLF_LOAD_IF_POSSIBLE); order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); } break; case MOF_STOP_LOCATION: order->SetStopLocation((OrderStopLocation)data); break; case MOF_UNLOAD: order->SetUnloadType((OrderUnloadFlags)data); break; case MOF_LOAD: order->SetLoadType((OrderLoadFlags)data); if (data & OLFB_NO_LOAD) order->SetRefit(CT_NO_REFIT); break; case MOF_DEPOT_ACTION: { switch (data) { case DA_ALWAYS_GO: order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE)); order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT)); break; case DA_SERVICE: order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() | ODTFB_SERVICE)); order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT)); order->SetRefit(CT_NO_REFIT); break; case DA_STOP: order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE)); order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() | ODATFB_HALT)); order->SetRefit(CT_NO_REFIT); break; default: NOT_REACHED(); } break; } case MOF_COND_VARIABLE: { order->SetConditionVariable((OrderConditionVariable)data); OrderConditionComparator occ = order->GetConditionComparator(); switch (order->GetConditionVariable()) { case OCV_UNCONDITIONALLY: order->SetConditionComparator(OCC_EQUALS); order->SetConditionValue(0); break; case OCV_REQUIRES_SERVICE: if (occ != OCC_IS_TRUE && occ != OCC_IS_FALSE) order->SetConditionComparator(OCC_IS_TRUE); order->SetConditionValue(0); break; case OCV_LOAD_PERCENTAGE: case OCV_RELIABILITY: if (order->GetConditionValue() > 100) order->SetConditionValue(100); /* FALL THROUGH */ default: if (occ == OCC_IS_TRUE || occ == OCC_IS_FALSE) order->SetConditionComparator(OCC_EQUALS); break; } break; } case MOF_COND_COMPARATOR: order->SetConditionComparator((OrderConditionComparator)data); break; case MOF_COND_VALUE: order->SetConditionValue(data); break; case MOF_COND_DESTINATION: order->SetConditionSkipToOrder(data); break; default: NOT_REACHED(); } /* Update the windows and full load flags, also for vehicles that share the same order list */ Vehicle *u = v->FirstShared(); DeleteOrderWarnings(u); for (; u != NULL; u = u->NextShared()) { /* Toggle u->current_order "Full load" flag if it changed. * However, as the same flag is used for depot orders, check * whether we are not going to a depot as there are three * cases where the full load flag can be active and only * one case where the flag is used for depot orders. In the * other cases for the OrderTypeByte the flags are not used, * so do not care and those orders should not be active * when this function is called. */ if (sel_ord == u->cur_real_order_index && (u->current_order.IsType(OT_GOTO_STATION) || u->current_order.IsType(OT_LOADING)) && u->current_order.GetLoadType() != order->GetLoadType()) { u->current_order.SetLoadType(order->GetLoadType()); } InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS); } } return CommandCost(); } /** * Check if an aircraft has enough range for an order list. * @param v_new Aircraft to check. * @param v_order Vehicle currently holding the order list. * @param first First order in the source order list. * @return True if the aircraft has enough range for the orders, false otherwise. */ static bool CheckAircraftOrderDistance(const Aircraft *v_new, const Vehicle *v_order, const Order *first) { if (first == NULL || v_new->acache.cached_max_range == 0) return true; /* Iterate over all orders to check the distance between all * 'goto' orders and their respective next order (of any type). */ for (const Order *o = first; o != NULL; o = o->next) { switch (o->GetType()) { case OT_GOTO_STATION: case OT_GOTO_DEPOT: case OT_GOTO_WAYPOINT: /* If we don't have a next order, we've reached the end and must check the first order instead. */ if (GetOrderDistance(o, o->next != NULL ? o->next : first, v_order) > v_new->acache.cached_max_range_sqr) return false; break; default: break; } } return true; } /** * Clone/share/copy an order-list of another vehicle. * @param tile unused * @param flags operation to perform * @param p1 various bitstuffed elements * - p1 = (bit 0-19) - destination vehicle to clone orders to * - p1 = (bit 30-31) - action to perform * @param p2 source vehicle to clone orders from, if any (none for CO_UNSHARE) * @param text unused * @return the cost of this operation or an error */ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh_src = GB(p2, 0, 20); VehicleID veh_dst = GB(p1, 0, 20); Vehicle *dst = Vehicle::GetIfValid(veh_dst); if (dst == NULL || !dst->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(dst->owner); if (ret.Failed()) return ret; switch (GB(p1, 30, 2)) { case CO_SHARE: { Vehicle *src = Vehicle::GetIfValid(veh_src); /* Sanity checks */ if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR; CommandCost ret = CheckOwnership(src->owner); if (ret.Failed()) return ret; /* Trucks can't share orders with busses (and visa versa) */ if (src->type == VEH_ROAD && RoadVehicle::From(src)->IsBus() != RoadVehicle::From(dst)->IsBus()) { return CMD_ERROR; } /* Is the vehicle already in the shared list? */ if (src->FirstShared() == dst->FirstShared()) return CMD_ERROR; const Order *order; FOR_VEHICLE_ORDERS(src, order) { if (!OrderGoesToStation(dst, order)) continue; /* Allow copying unreachable destinations if they were already unreachable for the source. * This is basically to allow cloning / autorenewing / autoreplacing vehicles, while the stations * are temporarily invalid due to reconstruction. */ const Station *st = Station::Get(order->GetDestination()); if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) { return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER); } } /* Check for aircraft range limits. */ if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) { return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE); } if (src->orders.list == NULL && !OrderList::CanAllocateItem()) { return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); } if (flags & DC_EXEC) { /* If the destination vehicle had a OrderList, destroy it. * We only reset the order indices, if the new orders are obviously different. * (We mainly do this to keep the order indices valid and in range.) */ DeleteVehicleOrders(dst, false, dst->GetNumOrders() != src->GetNumOrders()); dst->orders.list = src->orders.list; /* Link this vehicle in the shared-list */ dst->AddToShared(src); InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS); InvalidateVehicleOrder(src, VIWD_MODIFY_ORDERS); InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0); } break; } case CO_COPY: { Vehicle *src = Vehicle::GetIfValid(veh_src); /* Sanity checks */ if (src == NULL || !src->IsPrimaryVehicle() || dst->type != src->type || dst == src) return CMD_ERROR; CommandCost ret = CheckOwnership(src->owner); if (ret.Failed()) return ret; /* Trucks can't copy all the orders from busses (and visa versa), * and neither can helicopters and aircraft. */ const Order *order; FOR_VEHICLE_ORDERS(src, order) { if (OrderGoesToStation(dst, order) && !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) { return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER); } } /* Check for aircraft range limits. */ if (dst->type == VEH_AIRCRAFT && !CheckAircraftOrderDistance(Aircraft::From(dst), src, src->GetFirstOrder())) { return_cmd_error(STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE); } /* make sure there are orders available */ if (!Order::CanAllocateItem(src->GetNumOrders()) || !OrderList::CanAllocateItem()) { return_cmd_error(STR_ERROR_NO_MORE_SPACE_FOR_ORDERS); } if (flags & DC_EXEC) { const Order *order; Order *first = NULL; Order **order_dst; /* If the destination vehicle had an order list, destroy the chain but keep the OrderList. * We only reset the order indices, if the new orders are obviously different. * (We mainly do this to keep the order indices valid and in range.) */ DeleteVehicleOrders(dst, true, dst->GetNumOrders() != src->GetNumOrders()); order_dst = &first; FOR_VEHICLE_ORDERS(src, order) { *order_dst = new Order(); (*order_dst)->AssignOrder(*order); order_dst = &(*order_dst)->next; } if (dst->orders.list == NULL) { dst->orders.list = new OrderList(first, dst); } else { assert(dst->orders.list->GetFirstOrder() == NULL); assert(!dst->orders.list->IsShared()); delete dst->orders.list; assert(OrderList::CanAllocateItem()); dst->orders.list = new OrderList(first, dst); } InvalidateVehicleOrder(dst, VIWD_REMOVE_ALL_ORDERS); InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0); } break; } case CO_UNSHARE: return DecloneOrder(dst, flags); default: return CMD_ERROR; } return CommandCost(); } /** * Add/remove refit orders from an order * @param tile Not used * @param flags operation to perform * @param p1 VehicleIndex of the vehicle having the order * @param p2 bitmask * - bit 0-7 CargoID * - bit 16-23 number of order to modify * @param text unused * @return the cost of this operation or an error */ CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { VehicleID veh = GB(p1, 0, 20); VehicleOrderID order_number = GB(p2, 16, 8); CargoID cargo = GB(p2, 0, 8); if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT && cargo != CT_AUTO_REFIT) return CMD_ERROR; const Vehicle *v = Vehicle::GetIfValid(veh); if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR; CommandCost ret = CheckOwnership(v->owner); if (ret.Failed()) return ret; Order *order = v->GetOrder(order_number); if (order == NULL) return CMD_ERROR; /* Automatic refit cargo is only supported for goto station orders. */ if (cargo == CT_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR; if (order->GetLoadType() & OLFB_NO_LOAD) return CMD_ERROR; if (flags & DC_EXEC) { order->SetRefit(cargo); /* Make the depot order an 'always go' order. */ if (cargo != CT_NO_REFIT && order->IsType(OT_GOTO_DEPOT)) { order->SetDepotOrderType((OrderDepotTypeFlags)(order->GetDepotOrderType() & ~ODTFB_SERVICE)); order->SetDepotActionType((OrderDepotActionFlags)(order->GetDepotActionType() & ~ODATFB_HALT)); } for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) { /* Update any possible open window of the vehicle */ InvalidateVehicleOrder(u, VIWD_MODIFY_ORDERS); /* If the vehicle already got the current depot set as current order, then update current order as well */ if (u->cur_real_order_index == order_number && (u->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) { u->current_order.SetRefit(cargo); } } } return CommandCost(); } /** * * Check the orders of a vehicle, to see if there are invalid orders and stuff * */ void CheckOrders(const Vehicle *v) { /* Does the user wants us to check things? */ if (_settings_client.gui.order_review_system == 0) return; /* Do nothing for crashed vehicles */ if (v->vehstatus & VS_CRASHED) return; /* Do nothing for stopped vehicles if setting is '1' */ if (_settings_client.gui.order_review_system == 1 && (v->vehstatus & VS_STOPPED)) return; /* do nothing we we're not the first vehicle in a share-chain */ if (v->FirstShared() != v) return; /* Only check every 20 days, so that we don't flood the message log */ if (v->owner == _local_company && v->day_counter % 20 == 0) { const Order *order; StringID message = INVALID_STRING_ID; /* Check the order list */ int n_st = 0; FOR_VEHICLE_ORDERS(v, order) { /* Dummy order? */ if (order->IsType(OT_DUMMY)) { message = STR_NEWS_VEHICLE_HAS_VOID_ORDER; break; } /* Does station have a load-bay for this vehicle? */ if (order->IsType(OT_GOTO_STATION)) { const Station *st = Station::Get(order->GetDestination()); n_st++; if (!CanVehicleUseStation(v, st)) { message = STR_NEWS_VEHICLE_HAS_INVALID_ENTRY; } else if (v->type == VEH_AIRCRAFT && (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) && (st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) && _settings_game.vehicle.plane_crashes != 0 && !_cheats.no_jetcrash.value && message == INVALID_STRING_ID) { message = STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY; } } } /* Check if the last and the first order are the same */ if (v->GetNumOrders() > 1) { const Order *last = v->GetLastOrder(); if (v->orders.list->GetFirstOrder()->Equals(*last)) { message = STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY; } } /* Do we only have 1 station in our order list? */ if (n_st < 2 && message == INVALID_STRING_ID) message = STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS; #ifndef NDEBUG if (v->orders.list != NULL) v->orders.list->DebugCheckSanity(); #endif /* We don't have a problem */ if (message == INVALID_STRING_ID) return; SetDParam(0, v->index); AddVehicleAdviceNewsItem(message, v->index); } } /** * Removes an order from all vehicles. Triggers when, say, a station is removed. * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]). * @param destination The destination. Can be a StationID, DepotID or WaypointID. */ void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination) { Vehicle *v; /* Aircraft have StationIDs for depot orders and never use DepotIDs * This fact is handled specially below */ /* Go through all vehicles */ FOR_ALL_VEHICLES(v) { Order *order; order = &v->current_order; if ((v->type == VEH_AIRCRAFT && order->IsType(OT_GOTO_DEPOT) ? OT_GOTO_STATION : order->GetType()) == type && v->current_order.GetDestination() == destination) { order->MakeDummy(); SetWindowDirty(WC_VEHICLE_VIEW, v->index); } /* Clear the order from the order-list */ int id = -1; FOR_VEHICLE_ORDERS(v, order) { id++; restart: OrderType ot = order->GetType(); if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue; if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT)) ot = OT_GOTO_STATION; if (ot == type && order->GetDestination() == destination) { /* We want to clear implicit orders, but we don't want to make them * dummy orders. They should just vanish. Also check the actual order * type as ot is currently OT_GOTO_STATION. */ if (order->IsType(OT_IMPLICIT)) { order = order->next; // DeleteOrder() invalidates current order DeleteOrder(v, id); if (order != NULL) goto restart; break; } /* Clear wait time */ v->orders.list->UpdateTotalDuration(-order->GetWaitTime()); if (order->IsWaitTimetabled()) { v->orders.list->UpdateTimetableDuration(-order->GetTimetabledWait()); order->SetWaitTimetabled(false); } order->SetWaitTime(0); /* Clear order, preserving travel time */ bool travel_timetabled = order->IsTravelTimetabled(); order->MakeDummy(); order->SetTravelTimetabled(travel_timetabled); for (const Vehicle *w = v->FirstShared(); w != NULL; w = w->NextShared()) { /* In GUI, simulate by removing the order and adding it back */ InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8)); InvalidateVehicleOrder(w, (INVALID_VEH_ORDER_ID << 8) | id); } } } } OrderBackup::RemoveOrder(type, destination); } /** * Checks if a vehicle has a depot in its order list. * @return True iff at least one order is a depot order. */ bool Vehicle::HasDepotOrder() const { const Order *order; FOR_VEHICLE_ORDERS(this, order) { if (order->IsType(OT_GOTO_DEPOT)) return true; } return false; } /** * Delete all orders from a vehicle * @param v Vehicle whose orders to reset * @param keep_orderlist If true, do not free the order list, only empty it. * @param reset_order_indices If true, reset cur_implicit_order_index and cur_real_order_index * and cancel the current full load order (if the vehicle is loading). * If false, _you_ have to make sure the order indices are valid after * your messing with them! */ void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist, bool reset_order_indices) { DeleteOrderWarnings(v); if (v->IsOrderListShared()) { /* Remove ourself from the shared order list. */ v->RemoveFromShared(); v->orders.list = NULL; } else if (v->orders.list != NULL) { /* Remove the orders */ v->orders.list->FreeChain(keep_orderlist); if (!keep_orderlist) v->orders.list = NULL; } if (reset_order_indices) { v->cur_implicit_order_index = v->cur_real_order_index = 0; if (v->current_order.IsType(OT_LOADING)) { CancelLoadingDueToDeletedOrder(v); } } } /** * Clamp the service interval to the correct min/max. The actual min/max values * depend on whether it's in percent or days. * @param interval proposed service interval * @param company_id the owner of the vehicle * @return Clamped service interval */ uint16 GetServiceIntervalClamped(uint interval, bool ispercent) { return ispercent ? Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS); } /** * * Check if a vehicle has any valid orders * * @return false if there are no valid orders * @note Conditional orders are not considered valid destination orders * */ static bool CheckForValidOrders(const Vehicle *v) { const Order *order; FOR_VEHICLE_ORDERS(v, order) { switch (order->GetType()) { case OT_GOTO_STATION: case OT_GOTO_DEPOT: case OT_GOTO_WAYPOINT: return true; default: break; } } return false; } /** * Compare the variable and value based on the given comparator. */ static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value) { switch (occ) { case OCC_EQUALS: return variable == value; case OCC_NOT_EQUALS: return variable != value; case OCC_LESS_THAN: return variable < value; case OCC_LESS_EQUALS: return variable <= value; case OCC_MORE_THAN: return variable > value; case OCC_MORE_EQUALS: return variable >= value; case OCC_IS_TRUE: return variable != 0; case OCC_IS_FALSE: return variable == 0; default: NOT_REACHED(); } } /** * Process a conditional order and determine the next order. * @param order the order the vehicle currently has * @param v the vehicle to update * @return index of next order to jump to, or INVALID_VEH_ORDER_ID to use the next order */ VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v) { if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID; bool skip_order = false; OrderConditionComparator occ = order->GetConditionComparator(); uint16 value = order->GetConditionValue(); switch (order->GetConditionVariable()) { case OCV_LOAD_PERCENTAGE: skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, NULL), value); break; case OCV_RELIABILITY: skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability), value); break; case OCV_MAX_SPEED: skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break; case OCV_AGE: skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR, value); break; case OCV_REQUIRES_SERVICE: skip_order = OrderConditionCompare(occ, v->NeedsServicing(), value); break; case OCV_UNCONDITIONALLY: skip_order = true; break; case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, max(v->max_age - v->age + DAYS_IN_LEAP_YEAR - 1, 0) / DAYS_IN_LEAP_YEAR, value); break; default: NOT_REACHED(); } return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID; } /** * Update the vehicle's destination tile from an order. * @param order the order the vehicle currently has * @param v the vehicle to update * @param conditional_depth the depth (amount of steps) to go with conditional orders. This to prevent infinite loops. * @param pbs_look_ahead Whether we are forecasting orders for pbs reservations in advance. If true, the order indices must not be modified. */ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead) { if (conditional_depth > v->GetNumOrders()) { v->current_order.Free(); v->dest_tile = 0; return false; } switch (order->GetType()) { case OT_GOTO_STATION: v->dest_tile = v->GetOrderStationLocation(order->GetDestination()); return true; case OT_GOTO_DEPOT: if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) { assert(!pbs_look_ahead); UpdateVehicleTimetable(v, true); v->IncrementRealOrderIndex(); break; } if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) { /* We need to search for the nearest depot (hangar). */ TileIndex location; DestinationID destination; bool reverse; if (v->FindClosestDepot(&location, &destination, &reverse)) { /* PBS reservations cannot reverse */ if (pbs_look_ahead && reverse) return false; v->dest_tile = location; v->current_order.MakeGoToDepot(destination, v->current_order.GetDepotOrderType(), v->current_order.GetNonStopType(), (OrderDepotActionFlags)(v->current_order.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT), v->current_order.GetRefitCargo()); /* If there is no depot in front, reverse automatically (trains only) */ if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION); if (v->type == VEH_AIRCRAFT) { Aircraft *a = Aircraft::From(v); if (a->state == FLYING && a->targetairport != destination) { /* The aircraft is now heading for a different hangar than the next in the orders */ extern void AircraftNextAirportPos_and_Order(Aircraft *a); AircraftNextAirportPos_and_Order(a); } } return true; } /* If there is no depot, we cannot help PBS either. */ if (pbs_look_ahead) return false; UpdateVehicleTimetable(v, true); v->IncrementRealOrderIndex(); } else { if (v->type != VEH_AIRCRAFT) { v->dest_tile = Depot::Get(order->GetDestination())->xy; } return true; } break; case OT_GOTO_WAYPOINT: v->dest_tile = Waypoint::Get(order->GetDestination())->xy; return true; case OT_CONDITIONAL: { assert(!pbs_look_ahead); VehicleOrderID next_order = ProcessConditionalOrder(order, v); if (next_order != INVALID_VEH_ORDER_ID) { /* Jump to next_order. cur_implicit_order_index becomes exactly that order, * cur_real_order_index might come after next_order. */ UpdateVehicleTimetable(v, false); v->cur_implicit_order_index = v->cur_real_order_index = next_order; v->UpdateRealOrderIndex(); v->current_order_time += v->GetOrder(v->cur_real_order_index)->GetTimetabledTravel(); /* Disable creation of implicit orders. * When inserting them we do not know that we would have to make the conditional orders point to them. */ if (v->IsGroundVehicle()) { uint16 &gv_flags = v->GetGroundVehicleFlags(); SetBit(gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS); } } else { UpdateVehicleTimetable(v, true); v->IncrementRealOrderIndex(); } break; } default: v->dest_tile = 0; return false; } assert(v->cur_implicit_order_index < v->GetNumOrders()); assert(v->cur_real_order_index < v->GetNumOrders()); /* Get the current order */ order = v->GetOrder(v->cur_real_order_index); if (order != NULL && order->IsType(OT_IMPLICIT)) { assert(v->GetNumManualOrders() == 0); order = NULL; } if (order == NULL) { v->current_order.Free(); v->dest_tile = 0; return false; } v->current_order = *order; return UpdateOrderDest(v, order, conditional_depth + 1, pbs_look_ahead); } /** * Handle the orders of a vehicle and determine the next place * to go to if needed. * @param v the vehicle to do this for. * @return true *if* the vehicle is eligible for reversing * (basically only when leaving a station). */ bool ProcessOrders(Vehicle *v) { switch (v->current_order.GetType()) { case OT_GOTO_DEPOT: /* Let a depot order in the orderlist interrupt. */ if (!(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) return false; break; case OT_LOADING: return false; case OT_LEAVESTATION: if (v->type != VEH_AIRCRAFT) return false; break; default: break; } /** * Reversing because of order change is allowed only just after leaving a * station (and the difficulty setting to allowed, of course) * this can be detected because only after OT_LEAVESTATION, current_order * will be reset to nothing. (That also happens if no order, but in that case * it won't hit the point in code where may_reverse is checked) */ bool may_reverse = v->current_order.IsType(OT_NOTHING); /* Check if we've reached a 'via' destination. */ if (((v->current_order.IsType(OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) || v->current_order.IsType(OT_GOTO_WAYPOINT)) && IsTileType(v->tile, MP_STATION) && v->current_order.GetDestination() == GetStationIndex(v->tile)) { v->DeleteUnreachedImplicitOrders(); /* We set the last visited station here because we do not want * the train to stop at this 'via' station if the next order * is a no-non-stop order; in that case not setting the last * visited station will cause the vehicle to still stop. */ v->last_station_visited = v->current_order.GetDestination(); UpdateVehicleTimetable(v, true); v->IncrementImplicitOrderIndex(); } /* Get the current order */ assert(v->cur_implicit_order_index == 0 || v->cur_implicit_order_index < v->GetNumOrders()); v->UpdateRealOrderIndex(); const Order *order = v->GetOrder(v->cur_real_order_index); if (order != NULL && order->IsType(OT_IMPLICIT)) { assert(v->GetNumManualOrders() == 0); order = NULL; } /* If no order, do nothing. */ if (order == NULL || (v->type == VEH_AIRCRAFT && !CheckForValidOrders(v))) { if (v->type == VEH_AIRCRAFT) { /* Aircraft do something vastly different here, so handle separately */ extern void HandleMissingAircraftOrders(Aircraft *v); HandleMissingAircraftOrders(Aircraft::From(v)); return false; } v->current_order.Free(); v->dest_tile = 0; return false; } /* If it is unchanged, keep it. */ if (order->Equals(v->current_order) && (v->type == VEH_AIRCRAFT || v->dest_tile != 0) && (v->type != VEH_SHIP || !order->IsType(OT_GOTO_STATION) || Station::Get(order->GetDestination())->dock_tile != INVALID_TILE)) { return false; } /* Otherwise set it, and determine the destination tile. */ v->current_order = *order; InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS); switch (v->type) { default: NOT_REACHED(); case VEH_ROAD: case VEH_TRAIN: break; case VEH_AIRCRAFT: case VEH_SHIP: SetWindowClassesDirty(GetWindowClassForVehicleType(v->type)); break; } return UpdateOrderDest(v, order) && may_reverse; } /** * Check whether the given vehicle should stop at the given station * based on this order and the non-stop settings. * @param v the vehicle that might be stopping. * @param station the station to stop at. * @return true if the vehicle should stop. */ bool Order::ShouldStopAtStation(const Vehicle *v, StationID station) const { bool is_dest_station = this->IsType(OT_GOTO_STATION) && this->dest == station; return (!this->IsType(OT_GOTO_DEPOT) || (this->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0) && v->last_station_visited != station && // Do stop only when we've not just been there /* Finally do stop when there is no non-stop flag set for this type of station. */ !(this->GetNonStopType() & (is_dest_station ? ONSF_NO_STOP_AT_DESTINATION_STATION : ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS)); } bool Order::CanLoadOrUnload() const { return (this->IsType(OT_GOTO_STATION) || this->IsType(OT_IMPLICIT)) && (this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) == 0 && ((this->GetLoadType() & OLFB_NO_LOAD) == 0 || (this->GetUnloadType() & OUFB_NO_UNLOAD) == 0); } /** * A vehicle can leave the current station with cargo if: * 1. it can load cargo here OR * 2a. it could leave the last station with cargo AND * 2b. it doesn't have to unload all cargo here. */ bool Order::CanLeaveWithCargo(bool has_cargo) const { return (this->GetLoadType() & OLFB_NO_LOAD) == 0 || (has_cargo && (this->GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) == 0); } openttd-1.5.3/src/subsidy_type.h0000644000000000000000000000244112627373441015370 0ustar rootroot/* $Id: subsidy_type.h 22406 2011-05-01 19:51:52Z rubidium $ */ /* * 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 subsidy_type.h basic types related to subsidies */ #ifndef SUBSIDY_TYPE_H #define SUBSIDY_TYPE_H #include "core/enum_type.hpp" /** What part of a subsidy is something? */ enum PartOfSubsidy { POS_NONE = 0, ///< nothing POS_SRC = 1 << 0, ///< bit 0 set -> town/industry is source of subsidised path POS_DST = 1 << 1, ///< bit 1 set -> town/industry is destination of subsidised path }; /** Helper to store the PartOfSubsidy data in a single byte. */ typedef SimpleTinyEnumT PartOfSubsidyByte; DECLARE_ENUM_AS_BIT_SET(PartOfSubsidy) typedef uint16 SubsidyID; ///< ID of a subsidy struct Subsidy; #endif /* SUBSIDY_TYPE_H */ openttd-1.5.3/src/crashlog.cpp0000644000000000000000000003700612627373433015010 0ustar rootroot/* $Id: crashlog.cpp 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 crashlog.cpp Implementation of generic function to be called to log a crash */ #include "stdafx.h" #include "crashlog.h" #include "gamelog.h" #include "date_func.h" #include "map_func.h" #include "rev.h" #include "strings_func.h" #include "blitter/factory.hpp" #include "base_media_base.h" #include "music/music_driver.hpp" #include "sound/sound_driver.hpp" #include "video/video_driver.hpp" #include "saveload/saveload.h" #include "screenshot.h" #include "gfx_func.h" #include "network/network.h" #include "language.h" #include "fontcache.h" #include "ai/ai_info.hpp" #include "game/game.hpp" #include "game/game_info.hpp" #include "company_base.h" #include "company_func.h" #include #include "safeguards.h" /* static */ const char *CrashLog::message = NULL; /* static */ char *CrashLog::gamelog_buffer = NULL; /* static */ const char *CrashLog::gamelog_last = NULL; char *CrashLog::LogCompiler(char *buffer, const char *last) const { buffer += seprintf(buffer, last, " Compiler: " #if defined(_MSC_VER) "MSVC %d", _MSC_VER #elif defined(__ICC) && defined(__GNUC__) "ICC %d (GCC %d.%d.%d mode)", __ICC, __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ #elif defined(__ICC) "ICC %d", __ICC #elif defined(__GNUC__) "GCC %d.%d.%d", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ #elif defined(__WATCOMC__) "WatcomC %d", __WATCOMC__ #else "" #endif ); #if defined(__VERSION__) return buffer + seprintf(buffer, last, " \"" __VERSION__ "\"\n\n"); #else return buffer + seprintf(buffer, last, "\n\n"); #endif } /* virtual */ char *CrashLog::LogRegisters(char *buffer, const char *last) const { /* Stub implementation; not all OSes support this. */ return buffer; } /* virtual */ char *CrashLog::LogModules(char *buffer, const char *last) const { /* Stub implementation; not all OSes support this. */ return buffer; } /** * Writes OpenTTD's version to the buffer. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ char *CrashLog::LogOpenTTDVersion(char *buffer, const char *last) const { return buffer + seprintf(buffer, last, "OpenTTD version:\n" " Version: %s (%d)\n" " NewGRF ver: %08x\n" " Bits: %d\n" " Endian: %s\n" " Dedicated: %s\n" " Build date: %s\n\n", _openttd_revision, _openttd_revision_modified, _openttd_newgrf_version, #ifdef _SQ64 64, #else 32, #endif #if (TTD_ENDIAN == TTD_LITTLE_ENDIAN) "little", #else "big", #endif #ifdef DEDICATED "yes", #else "no", #endif _openttd_build_date ); } /** * Writes the (important) configuration settings to the buffer. * E.g. graphics set, sound set, blitter and AIs. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ char *CrashLog::LogConfiguration(char *buffer, const char *last) const { buffer += seprintf(buffer, last, "Configuration:\n" " Blitter: %s\n" " Graphics set: %s (%u)\n" " Language: %s\n" " Music driver: %s\n" " Music set: %s (%u)\n" " Network: %s\n" " Sound driver: %s\n" " Sound set: %s (%u)\n" " Video driver: %s\n\n", BlitterFactory::GetCurrentBlitter() == NULL ? "none" : BlitterFactory::GetCurrentBlitter()->GetName(), BaseGraphics::GetUsedSet() == NULL ? "none" : BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet() == NULL ? UINT32_MAX : BaseGraphics::GetUsedSet()->version, _current_language == NULL ? "none" : _current_language->file, MusicDriver::GetInstance() == NULL ? "none" : MusicDriver::GetInstance()->GetName(), BaseMusic::GetUsedSet() == NULL ? "none" : BaseMusic::GetUsedSet()->name, BaseMusic::GetUsedSet() == NULL ? UINT32_MAX : BaseMusic::GetUsedSet()->version, _networking ? (_network_server ? "server" : "client") : "no", SoundDriver::GetInstance() == NULL ? "none" : SoundDriver::GetInstance()->GetName(), BaseSounds::GetUsedSet() == NULL ? "none" : BaseSounds::GetUsedSet()->name, BaseSounds::GetUsedSet() == NULL ? UINT32_MAX : BaseSounds::GetUsedSet()->version, VideoDriver::GetInstance() == NULL ? "none" : VideoDriver::GetInstance()->GetName() ); buffer += seprintf(buffer, last, "Fonts:\n" " Small: %s\n" " Medium: %s\n" " Large: %s\n" " Mono: %s\n\n", FontCache::Get(FS_SMALL)->GetFontName(), FontCache::Get(FS_NORMAL)->GetFontName(), FontCache::Get(FS_LARGE)->GetFontName(), FontCache::Get(FS_MONO)->GetFontName() ); buffer += seprintf(buffer, last, "AI Configuration (local: %i):\n", (int)_local_company); const Company *c; FOR_ALL_COMPANIES(c) { if (c->ai_info == NULL) { buffer += seprintf(buffer, last, " %2i: Human\n", (int)c->index); } else { buffer += seprintf(buffer, last, " %2i: %s (v%d)\n", (int)c->index, c->ai_info->GetName(), c->ai_info->GetVersion()); } } if (Game::GetInfo() != NULL) { buffer += seprintf(buffer, last, " GS: %s (v%d)\n", Game::GetInfo()->GetName(), Game::GetInfo()->GetVersion()); } buffer += seprintf(buffer, last, "\n"); return buffer; } /* Include these here so it's close to where it's actually used. */ #ifdef WITH_ALLEGRO # include #endif /* WITH_ALLEGRO */ #ifdef WITH_FONTCONFIG # include #endif /* WITH_FONTCONFIG */ #ifdef WITH_PNG /* pngconf.h, included by png.h doesn't like something in the * freetype headers. As such it's not alphabetically sorted. */ # include #endif /* WITH_PNG */ #ifdef WITH_FREETYPE # include # include FT_FREETYPE_H #endif /* WITH_FREETYPE */ #ifdef WITH_ICU # include #endif /* WITH_ICU */ #ifdef WITH_LZMA # include #endif #ifdef WITH_LZO #include #endif #ifdef WITH_SDL # include "sdl.h" # include #endif /* WITH_SDL */ #ifdef WITH_ZLIB # include #endif /** * Writes information (versions) of the used libraries. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ char *CrashLog::LogLibraries(char *buffer, const char *last) const { buffer += seprintf(buffer, last, "Libraries:\n"); #ifdef WITH_ALLEGRO buffer += seprintf(buffer, last, " Allegro: %s\n", allegro_id); #endif /* WITH_ALLEGRO */ #ifdef WITH_FONTCONFIG int version = FcGetVersion(); buffer += seprintf(buffer, last, " FontConfig: %d.%d.%d\n", version / 10000, (version / 100) % 100, version % 100); #endif /* WITH_FONTCONFIG */ #ifdef WITH_FREETYPE FT_Library library; int major, minor, patch; FT_Init_FreeType(&library); FT_Library_Version(library, &major, &minor, &patch); FT_Done_FreeType(library); buffer += seprintf(buffer, last, " FreeType: %d.%d.%d\n", major, minor, patch); #endif /* WITH_FREETYPE */ #ifdef WITH_ICU /* 4 times 0-255, separated by dots (.) and a trailing '\0' */ char buf[4 * 3 + 3 + 1]; UVersionInfo ver; u_getVersion(ver); u_versionToString(ver, buf); buffer += seprintf(buffer, last, " ICU: %s\n", buf); #endif /* WITH_ICU */ #ifdef WITH_LZMA buffer += seprintf(buffer, last, " LZMA: %s\n", lzma_version_string()); #endif #ifdef WITH_LZO buffer += seprintf(buffer, last, " LZO: %s\n", lzo_version_string()); #endif #ifdef WITH_PNG buffer += seprintf(buffer, last, " PNG: %s\n", png_get_libpng_ver(NULL)); #endif /* WITH_PNG */ #ifdef WITH_SDL #ifdef DYNAMICALLY_LOADED_SDL if (SDL_CALL SDL_Linked_Version != NULL) { #else { #endif const SDL_version *v = SDL_CALL SDL_Linked_Version(); buffer += seprintf(buffer, last, " SDL: %d.%d.%d\n", v->major, v->minor, v->patch); } #endif /* WITH_SDL */ #ifdef WITH_ZLIB buffer += seprintf(buffer, last, " Zlib: %s\n", zlibVersion()); #endif buffer += seprintf(buffer, last, "\n"); return buffer; } /** * Helper function for printing the gamelog. * @param s the string to print. */ /* static */ void CrashLog::GamelogFillCrashLog(const char *s) { CrashLog::gamelog_buffer += seprintf(CrashLog::gamelog_buffer, CrashLog::gamelog_last, "%s\n", s); } /** * Writes the gamelog data to the buffer. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ char *CrashLog::LogGamelog(char *buffer, const char *last) const { CrashLog::gamelog_buffer = buffer; CrashLog::gamelog_last = last; GamelogPrint(&CrashLog::GamelogFillCrashLog); return CrashLog::gamelog_buffer + seprintf(CrashLog::gamelog_buffer, last, "\n"); } /** * Fill the crash log buffer with all data of a crash log. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ char *CrashLog::FillCrashLog(char *buffer, const char *last) const { time_t cur_time = time(NULL); buffer += seprintf(buffer, last, "*** OpenTTD Crash Report ***\n\n"); buffer += seprintf(buffer, last, "Crash at: %s", asctime(gmtime(&cur_time))); YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); buffer += seprintf(buffer, last, "In game date: %i-%02i-%02i (%i)\n\n", ymd.year, ymd.month + 1, ymd.day, _date_fract); buffer = this->LogError(buffer, last, CrashLog::message); buffer = this->LogOpenTTDVersion(buffer, last); buffer = this->LogRegisters(buffer, last); buffer = this->LogStacktrace(buffer, last); buffer = this->LogOSVersion(buffer, last); buffer = this->LogCompiler(buffer, last); buffer = this->LogConfiguration(buffer, last); buffer = this->LogLibraries(buffer, last); buffer = this->LogModules(buffer, last); buffer = this->LogGamelog(buffer, last); buffer += seprintf(buffer, last, "*** End of OpenTTD Crash Report ***\n"); return buffer; } /** * Write the crash log to a file. * @note On success the filename will be filled with the full path of the * crash log file. Make sure filename is at least \c MAX_PATH big. * @param buffer The begin of the buffer to write to the disk. * @param filename Output for the filename of the written file. * @param filename_last The last position in the filename buffer. * @return true when the crash log was successfully written. */ bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *filename_last) const { seprintf(filename, filename_last, "%scrash.log", _personal_dir); FILE *file = FioFOpenFile(filename, "w", NO_DIRECTORY); if (file == NULL) return false; size_t len = strlen(buffer); size_t written = fwrite(buffer, 1, len, file); FioFCloseFile(file); return len == written; } /* virtual */ int CrashLog::WriteCrashDump(char *filename, const char *filename_last) const { /* Stub implementation; not all OSes support this. */ return 0; } /** * Write the (crash) savegame to a file. * @note On success the filename will be filled with the full path of the * crash save file. Make sure filename is at least \c MAX_PATH big. * @param filename Output for the filename of the written file. * @param filename_last The last position in the filename buffer. * @return true when the crash save was successfully made. */ bool CrashLog::WriteSavegame(char *filename, const char *filename_last) const { /* If the map array doesn't exist, saving will fail too. If the map got * initialised, there is a big chance the rest is initialised too. */ if (_m == NULL) return false; try { GamelogEmergency(); seprintf(filename, filename_last, "%scrash.sav", _personal_dir); /* Don't do a threaded saveload. */ return SaveOrLoad(filename, SL_SAVE, NO_DIRECTORY, false) == SL_OK; } catch (...) { return false; } } /** * Write the (crash) screenshot to a file. * @note On success the filename will be filled with the full path of the * screenshot. Make sure filename is at least \c MAX_PATH big. * @param filename Output for the filename of the written file. * @param filename_last The last position in the filename buffer. * @return true when the crash screenshot was successfully made. */ bool CrashLog::WriteScreenshot(char *filename, const char *filename_last) const { /* Don't draw when we have invalid screen size */ if (_screen.width < 1 || _screen.height < 1 || _screen.dst_ptr == NULL) return false; bool res = MakeScreenshot(SC_CRASHLOG, "crash"); if (res) strecpy(filename, _full_screenshot_name, filename_last); return res; } /** * Makes the crash log, writes it to a file and then subsequently tries * to make a crash dump and crash savegame. It uses DEBUG to write * information like paths to the console. * @return true when everything is made successfully. */ bool CrashLog::MakeCrashLog() const { /* Don't keep looping logging crashes. */ static bool crashlogged = false; if (crashlogged) return false; crashlogged = true; char filename[MAX_PATH]; char buffer[65536]; bool ret = true; printf("Crash encountered, generating crash log...\n"); this->FillCrashLog(buffer, lastof(buffer)); printf("%s\n", buffer); printf("Crash log generated.\n\n"); printf("Writing crash log to disk...\n"); bool bret = this->WriteCrashLog(buffer, filename, lastof(filename)); if (bret) { printf("Crash log written to %s. Please add this file to any bug reports.\n\n", filename); } else { printf("Writing crash log failed. Please attach the output above to any bug reports.\n\n"); ret = false; } /* Don't mention writing crash dumps because not all platforms support it. */ int dret = this->WriteCrashDump(filename, lastof(filename)); if (dret < 0) { printf("Writing crash dump failed.\n\n"); ret = false; } else if (dret > 0) { printf("Crash dump written to %s. Please add this file to any bug reports.\n\n", filename); } printf("Writing crash savegame...\n"); bret = this->WriteSavegame(filename, lastof(filename)); if (bret) { printf("Crash savegame written to %s. Please add this file and the last (auto)save to any bug reports.\n\n", filename); } else { ret = false; printf("Writing crash savegame failed. Please attach the last (auto)save to any bug reports.\n\n"); } printf("Writing crash screenshot...\n"); bret = this->WriteScreenshot(filename, lastof(filename)); if (bret) { printf("Crash screenshot written to %s. Please add this file to any bug reports.\n\n", filename); } else { ret = false; printf("Writing crash screenshot failed.\n\n"); } return ret; } /** * Sets a message for the error message handler. * @param message The error message of the error. */ /* static */ void CrashLog::SetErrorMessage(const char *message) { CrashLog::message = message; } /** * Try to close the sound/video stuff so it doesn't keep lingering around * incorrect video states or so, e.g. keeping dpmi disabled. */ /* static */ void CrashLog::AfterCrashLogCleanup() { if (MusicDriver::GetInstance() != NULL) MusicDriver::GetInstance()->Stop(); if (SoundDriver::GetInstance() != NULL) SoundDriver::GetInstance()->Stop(); if (VideoDriver::GetInstance() != NULL) VideoDriver::GetInstance()->Stop(); } openttd-1.5.3/src/graph_gui.cpp0000644000000000000000000015331212627373433015152 0ustar rootroot/* $Id: graph_gui.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 graph_gui.cpp GUI that shows performance graphs. */ #include "stdafx.h" #include "graph_gui.h" #include "window_gui.h" #include "company_base.h" #include "company_gui.h" #include "economy_func.h" #include "cargotype.h" #include "strings_func.h" #include "window_func.h" #include "date_func.h" #include "gfx_func.h" #include "sortlist_type.h" #include "core/geometry_func.hpp" #include "currency.h" #include "widgets/graph_widget.h" #include "table/strings.h" #include "table/sprites.h" #include #include "safeguards.h" /* Bitmasks of company and cargo indices that shouldn't be drawn. */ static uint _legend_excluded_companies; static uint _legend_excluded_cargo; /* Apparently these don't play well with enums. */ static const OverflowSafeInt64 INVALID_DATAPOINT(INT64_MAX); // Value used for a datapoint that shouldn't be drawn. static const uint INVALID_DATAPOINT_POS = UINT_MAX; // Used to determine if the previous point was drawn. /****************/ /* GRAPH LEGEND */ /****************/ struct GraphLegendWindow : Window { GraphLegendWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (!HasBit(_legend_excluded_companies, c)) this->LowerWidget(c + WID_GL_FIRST_COMPANY); this->OnInvalidateData(c); } } virtual void DrawWidget(const Rect &r, int widget) const { if (!IsInsideMM(widget, WID_GL_FIRST_COMPANY, MAX_COMPANIES + WID_GL_FIRST_COMPANY)) return; CompanyID cid = (CompanyID)(widget - WID_GL_FIRST_COMPANY); if (!Company::IsValidID(cid)) return; bool rtl = _current_text_dir == TD_RTL; Dimension d = GetSpriteSize(SPR_COMPANY_ICON); DrawCompanyIcon(cid, rtl ? r.right - d.width - 2 : r.left + 2, r.top + (r.bottom - r.top - d.height) / 2); SetDParam(0, cid); SetDParam(1, cid); DrawString(r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : (d.width + 4)), r.right - (rtl ? (d.width + 4) : (uint)WD_FRAMERECT_RIGHT), r.top + (r.bottom - r.top + 1 - FONT_HEIGHT_NORMAL) / 2, STR_COMPANY_NAME_COMPANY_NUM, HasBit(_legend_excluded_companies, cid) ? TC_BLACK : TC_WHITE); } virtual void OnClick(Point pt, int widget, int click_count) { if (!IsInsideMM(widget, WID_GL_FIRST_COMPANY, MAX_COMPANIES + WID_GL_FIRST_COMPANY)) return; ToggleBit(_legend_excluded_companies, widget - WID_GL_FIRST_COMPANY); this->ToggleWidgetLoweredState(widget); this->SetDirty(); InvalidateWindowData(WC_INCOME_GRAPH, 0); InvalidateWindowData(WC_OPERATING_PROFIT, 0); InvalidateWindowData(WC_DELIVERED_CARGO, 0); InvalidateWindowData(WC_PERFORMANCE_HISTORY, 0); InvalidateWindowData(WC_COMPANY_VALUE, 0); } /** * 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; if (Company::IsValidID(data)) return; SetBit(_legend_excluded_companies, data); this->RaiseWidget(data + WID_GL_FIRST_COMPANY); } }; /** * Construct a vertical list of buttons, one for each company. * @param biggest_index Storage for collecting the biggest index used in the returned tree. * @return Panel with company buttons. * @post \c *biggest_index contains the largest used index in the tree. */ static NWidgetBase *MakeNWidgetCompanyLines(int *biggest_index) { NWidgetVertical *vert = new NWidgetVertical(); uint line_height = max(GetSpriteSize(SPR_COMPANY_ICON).height, FONT_HEIGHT_NORMAL) + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; for (int widnum = WID_GL_FIRST_COMPANY; widnum <= WID_GL_LAST_COMPANY; widnum++) { NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); panel->SetMinimalSize(246, line_height); panel->SetFill(1, 0); panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP); vert->Add(panel); } *biggest_index = WID_GL_LAST_COMPANY; return vert; } static const NWidgetPart _nested_graph_legend_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_BACKGROUND), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(2, 0), NWidgetFunction(MakeNWidgetCompanyLines), NWidget(NWID_SPACER), SetMinimalSize(2, 0), EndContainer(), EndContainer(), }; static WindowDesc _graph_legend_desc( WDP_AUTO, "graph_legend", 0, 0, WC_GRAPH_LEGEND, WC_NONE, 0, _nested_graph_legend_widgets, lengthof(_nested_graph_legend_widgets) ); static void ShowGraphLegend() { AllocateWindowDescFront(&_graph_legend_desc, 0); } /** Contains the interval of a graph's data. */ struct ValuesInterval { OverflowSafeInt64 highest; ///< Highest value of this interval. Must be zero or greater. OverflowSafeInt64 lowest; ///< Lowest value of this interval. Must be zero or less. }; /******************/ /* BASE OF GRAPHS */ /*****************/ struct BaseGraphWindow : Window { protected: static const int GRAPH_MAX_DATASETS = 32; static const int GRAPH_AXIS_LINE_COLOUR = PC_BLACK; static const int GRAPH_NUM_MONTHS = 24; ///< Number of months displayed in the graph. static const int MIN_GRAPH_NUM_LINES_Y = 9; ///< Minimal number of horizontal lines to draw. static const int MIN_GRID_PIXEL_SIZE = 20; ///< Minimum distance between graph lines. uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed. byte num_dataset; byte num_on_x_axis; byte num_vert_lines; static const TextColour graph_axis_label_colour = TC_BLACK; ///< colour of the graph axis label. /* The starting month and year that values are plotted against. If month is * 0xFF, use x_values_start and x_values_increment below instead. */ byte month; Year year; /* These values are used if the graph is being plotted against values * rather than the dates specified by month and year. */ uint16 x_values_start; uint16 x_values_increment; int graph_widget; StringID format_str_y_axis; byte colours[GRAPH_MAX_DATASETS]; OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][GRAPH_NUM_MONTHS]; ///< Stored costs for the last #GRAPH_NUM_MONTHS months /** * Get the interval that contains the graph's data. Excluded data is ignored to show smaller values in * better detail when disabling higher ones. * @param num_hori_lines Number of horizontal lines to be drawn. * @return Highest and lowest values of the graph (ignoring disabled data). */ ValuesInterval GetValuesInterval(int num_hori_lines) const { assert(num_hori_lines > 0); ValuesInterval current_interval; current_interval.highest = INT64_MIN; current_interval.lowest = INT64_MAX; for (int i = 0; i < this->num_dataset; i++) { if (HasBit(this->excluded_data, i)) continue; for (int j = 0; j < this->num_on_x_axis; j++) { OverflowSafeInt64 datapoint = this->cost[i][j]; if (datapoint != INVALID_DATAPOINT) { current_interval.highest = max(current_interval.highest, datapoint); current_interval.lowest = min(current_interval.lowest, datapoint); } } } /* Prevent showing values too close to the graph limits. */ current_interval.highest = (11 * current_interval.highest) / 10; current_interval.lowest = (11 * current_interval.lowest) / 10; /* Always include zero in the shown range. */ double abs_lower = (current_interval.lowest > 0) ? 0 : (double)abs(current_interval.lowest); double abs_higher = (current_interval.highest < 0) ? 0 : (double)current_interval.highest; int num_pos_grids; int64 grid_size; if (abs_lower != 0 || abs_higher != 0) { /* The number of grids to reserve for the positive part is: */ num_pos_grids = (int)floor(0.5 + num_hori_lines * abs_higher / (abs_higher + abs_lower)); /* If there are any positive or negative values, force that they have at least one grid. */ if (num_pos_grids == 0 && abs_higher != 0) num_pos_grids++; if (num_pos_grids == num_hori_lines && abs_lower != 0) num_pos_grids--; /* Get the required grid size for each side and use the maximum one. */ int64 grid_size_higher = (abs_higher > 0) ? ((int64)abs_higher + num_pos_grids - 1) / num_pos_grids : 0; int64 grid_size_lower = (abs_lower > 0) ? ((int64)abs_lower + num_hori_lines - num_pos_grids - 1) / (num_hori_lines - num_pos_grids) : 0; grid_size = max(grid_size_higher, grid_size_lower); } else { /* If both values are zero, show an empty graph. */ num_pos_grids = num_hori_lines / 2; grid_size = 1; } current_interval.highest = num_pos_grids * grid_size; current_interval.lowest = -(num_hori_lines - num_pos_grids) * grid_size; return current_interval; } /** * Get width for Y labels. * @param current_interval Interval that contains all of the graph data. * @param num_hori_lines Number of horizontal lines to be drawn. */ uint GetYLabelWidth(ValuesInterval current_interval, int num_hori_lines) const { /* draw text strings on the y axis */ int64 y_label = current_interval.highest; int64 y_label_separation = (current_interval.highest - current_interval.lowest) / num_hori_lines; uint max_width = 0; for (int i = 0; i < (num_hori_lines + 1); i++) { SetDParam(0, this->format_str_y_axis); SetDParam(1, y_label); Dimension d = GetStringBoundingBox(STR_GRAPH_Y_LABEL); if (d.width > max_width) max_width = d.width; y_label -= y_label_separation; } return max_width; } /** * Actually draw the graph. * @param r the rectangle of the data field of the graph */ void DrawGraph(Rect r) const { uint x, y; ///< Reused whenever x and y coordinates are needed. ValuesInterval interval; ///< Interval that contains all of the graph data. int x_axis_offset; ///< Distance from the top of the graph to the x axis. /* the colours and cost array of GraphDrawer must accommodate * both values for cargo and companies. So if any are higher, quit */ assert_compile(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES); assert(this->num_vert_lines > 0); byte grid_colour = _colour_gradient[COLOUR_GREY][4]; /* Rect r will be adjusted to contain just the graph, with labels being * placed outside the area. */ r.top += 5 + GetCharacterHeight(FS_SMALL) / 2; r.bottom -= (this->month == 0xFF ? 1 : 3) * GetCharacterHeight(FS_SMALL) + 4; r.left += 9; r.right -= 5; /* Initial number of horizontal lines. */ int num_hori_lines = 160 / MIN_GRID_PIXEL_SIZE; /* For the rest of the height, the number of horizontal lines will increase more slowly. */ int resize = (r.bottom - r.top - 160) / (2 * MIN_GRID_PIXEL_SIZE); if (resize > 0) num_hori_lines += resize; interval = GetValuesInterval(num_hori_lines); int label_width = GetYLabelWidth(interval, num_hori_lines); r.left += label_width; int x_sep = (r.right - r.left) / this->num_vert_lines; int y_sep = (r.bottom - r.top) / num_hori_lines; /* Redetermine right and bottom edge of graph to fit with the integer * separation values. */ r.right = r.left + x_sep * this->num_vert_lines; r.bottom = r.top + y_sep * num_hori_lines; OverflowSafeInt64 interval_size = interval.highest + abs(interval.lowest); /* Where to draw the X axis. Use floating point to avoid overflowing and results of zero. */ x_axis_offset = (int)((r.bottom - r.top) * (double)interval.highest / (double)interval_size); /* Draw the vertical grid lines. */ /* Don't draw the first line, as that's where the axis will be. */ x = r.left + x_sep; for (int i = 0; i < this->num_vert_lines; i++) { GfxFillRect(x, r.top, x, r.bottom, grid_colour); x += x_sep; } /* Draw the horizontal grid lines. */ y = r.bottom; for (int i = 0; i < (num_hori_lines + 1); i++) { GfxFillRect(r.left - 3, y, r.left - 1, y, GRAPH_AXIS_LINE_COLOUR); GfxFillRect(r.left, y, r.right, y, grid_colour); y -= y_sep; } /* Draw the y axis. */ GfxFillRect(r.left, r.top, r.left, r.bottom, GRAPH_AXIS_LINE_COLOUR); /* Draw the x axis. */ y = x_axis_offset + r.top; GfxFillRect(r.left, y, r.right, y, GRAPH_AXIS_LINE_COLOUR); /* Find the largest value that will be drawn. */ if (this->num_on_x_axis == 0) return; assert(this->num_on_x_axis > 0); assert(this->num_dataset > 0); /* draw text strings on the y axis */ int64 y_label = interval.highest; int64 y_label_separation = abs(interval.highest - interval.lowest) / num_hori_lines; y = r.top - GetCharacterHeight(FS_SMALL) / 2; for (int i = 0; i < (num_hori_lines + 1); i++) { SetDParam(0, this->format_str_y_axis); SetDParam(1, y_label); DrawString(r.left - label_width - 4, r.left - 4, y, STR_GRAPH_Y_LABEL, graph_axis_label_colour, SA_RIGHT); y_label -= y_label_separation; y += y_sep; } /* draw strings on the x axis */ if (this->month != 0xFF) { x = r.left; y = r.bottom + 2; byte month = this->month; Year year = this->year; for (int i = 0; i < this->num_on_x_axis; i++) { SetDParam(0, month + STR_MONTH_ABBREV_JAN); SetDParam(1, month + STR_MONTH_ABBREV_JAN + 2); SetDParam(2, year); DrawStringMultiLine(x, x + x_sep, y, this->height, month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, graph_axis_label_colour); month += 3; if (month >= 12) { month = 0; year++; } x += x_sep; } } else { /* Draw the label under the data point rather than on the grid line. */ x = r.left; y = r.bottom + 2; uint16 label = this->x_values_start; for (int i = 0; i < this->num_on_x_axis; i++) { SetDParam(0, label); DrawString(x + 1, x + x_sep - 1, y, STR_GRAPH_Y_LABEL_NUMBER, graph_axis_label_colour, SA_HOR_CENTER); label += this->x_values_increment; x += x_sep; } } /* draw lines and dots */ uint linewidth = _settings_client.gui.graph_line_thickness; uint pointoffs1 = (linewidth + 1) / 2; uint pointoffs2 = linewidth + 1 - pointoffs1; for (int i = 0; i < this->num_dataset; i++) { if (!HasBit(this->excluded_data, i)) { /* Centre the dot between the grid lines. */ x = r.left + (x_sep / 2); byte colour = this->colours[i]; uint prev_x = INVALID_DATAPOINT_POS; uint prev_y = INVALID_DATAPOINT_POS; for (int j = 0; j < this->num_on_x_axis; j++) { OverflowSafeInt64 datapoint = this->cost[i][j]; if (datapoint != INVALID_DATAPOINT) { /* * Check whether we need to reduce the 'accuracy' of the * datapoint value and the highest value to split overflows. * And when 'drawing' 'one million' or 'one million and one' * there is no significant difference, so the least * significant bits can just be removed. * * If there are more bits needed than would fit in a 32 bits * integer, so at about 31 bits because of the sign bit, the * least significant bits are removed. */ int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint)); int reduce_range = max(mult_range - 31, 0); /* Handle negative values differently (don't shift sign) */ if (datapoint < 0) { datapoint = -(abs(datapoint) >> reduce_range); } else { datapoint >>= reduce_range; } y = r.top + x_axis_offset - ((r.bottom - r.top) * datapoint) / (interval_size >> reduce_range); /* Draw the point. */ GfxFillRect(x - pointoffs1, y - pointoffs1, x + pointoffs2, y + pointoffs2, colour); /* Draw the line connected to the previous point. */ if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour, linewidth); prev_x = x; prev_y = y; } else { prev_x = INVALID_DATAPOINT_POS; prev_y = INVALID_DATAPOINT_POS; } x += x_sep; } } } } BaseGraphWindow(WindowDesc *desc, int widget, StringID format_str_y_axis) : Window(desc), format_str_y_axis(format_str_y_axis) { SetWindowDirty(WC_GRAPH_LEGEND, 0); this->num_vert_lines = 24; this->graph_widget = widget; } void InitializeWindow(WindowNumber number) { /* Initialise the dataset */ this->UpdateStatistics(true); this->InitNested(number); } public: virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != this->graph_widget) return; uint x_label_width = 0; if (this->month != 0xFF) { byte month = this->month; Year year = this->year; for (int i = 0; i < this->num_on_x_axis; i++) { SetDParam(0, month + STR_MONTH_ABBREV_JAN); SetDParam(1, month + STR_MONTH_ABBREV_JAN + 2); SetDParam(2, year); x_label_width = max(x_label_width, GetStringBoundingBox(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH).width); month += 3; if (month >= 12) { month = 0; year++; } } } else { /* Draw the label under the data point rather than on the grid line. */ SetDParamMaxValue(0, this->x_values_start + this->num_on_x_axis * this->x_values_increment, 0, FS_SMALL); x_label_width = GetStringBoundingBox(STR_GRAPH_Y_LABEL_NUMBER).width; } SetDParam(0, this->format_str_y_axis); SetDParam(1, INT64_MAX); uint y_label_width = GetStringBoundingBox(STR_GRAPH_Y_LABEL).width; size->width = max(size->width, 5 + y_label_width + this->num_on_x_axis * (x_label_width + 5) + 9); size->height = max(size->height, 5 + (1 + MIN_GRAPH_NUM_LINES_Y * 2 + (this->month != 0xFF ? 3 : 1)) * FONT_HEIGHT_SMALL + 4); size->height = max(size->height, size->width / 3); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != this->graph_widget) return; DrawGraph(r); } virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { return INVALID_DATAPOINT; } virtual void OnClick(Point pt, int widget, int click_count) { /* Clicked on legend? */ if (widget == WID_CV_KEY_BUTTON) ShowGraphLegend(); } virtual void OnTick() { this->UpdateStatistics(false); } /** * 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->UpdateStatistics(true); } /** * Update the statistics. * @param initialize Initialize the data structure. */ void UpdateStatistics(bool initialize) { uint excluded_companies = _legend_excluded_companies; /* Exclude the companies which aren't valid */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (!Company::IsValidID(c)) SetBit(excluded_companies, c); } byte nums = 0; const Company *c; FOR_ALL_COMPANIES(c) { nums = min(this->num_vert_lines, max(nums, c->num_valid_stat_ent)); } int mo = (_cur_month / 3 - nums) * 3; int yr = _cur_year; while (mo < 0) { yr--; mo += 12; } if (!initialize && this->excluded_data == excluded_companies && this->num_on_x_axis == nums && this->year == yr && this->month == mo) { /* There's no reason to get new stats */ return; } this->excluded_data = excluded_companies; this->num_on_x_axis = nums; this->year = yr; this->month = mo; int numd = 0; for (CompanyID k = COMPANY_FIRST; k < MAX_COMPANIES; k++) { c = Company::GetIfValid(k); if (c != NULL) { this->colours[numd] = _colour_gradient[c->colour][6]; for (int j = this->num_on_x_axis, i = 0; --j >= 0;) { this->cost[numd][i] = (j >= c->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(c, j); i++; } } numd++; } this->num_dataset = numd; } }; /********************/ /* OPERATING PROFIT */ /********************/ struct OperatingProfitGraphWindow : BaseGraphWindow { OperatingProfitGraphWindow(WindowDesc *desc, WindowNumber window_number) : BaseGraphWindow(desc, WID_CV_GRAPH, STR_JUST_CURRENCY_SHORT) { this->InitializeWindow(window_number); } virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { return c->old_economy[j].income + c->old_economy[j].expenses; } }; static const NWidgetPart _nested_operating_profit_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 160), SetFill(1, 1), SetResize(1, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _operating_profit_desc( WDP_AUTO, "graph_operating_profit", 0, 0, WC_OPERATING_PROFIT, WC_NONE, 0, _nested_operating_profit_widgets, lengthof(_nested_operating_profit_widgets) ); void ShowOperatingProfitGraph() { AllocateWindowDescFront(&_operating_profit_desc, 0); } /****************/ /* INCOME GRAPH */ /****************/ struct IncomeGraphWindow : BaseGraphWindow { IncomeGraphWindow(WindowDesc *desc, WindowNumber window_number) : BaseGraphWindow(desc, WID_CV_GRAPH, STR_JUST_CURRENCY_SHORT) { this->InitializeWindow(window_number); } virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { return c->old_economy[j].income; } }; static const NWidgetPart _nested_income_graph_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _income_graph_desc( WDP_AUTO, "graph_income", 0, 0, WC_INCOME_GRAPH, WC_NONE, 0, _nested_income_graph_widgets, lengthof(_nested_income_graph_widgets) ); void ShowIncomeGraph() { AllocateWindowDescFront(&_income_graph_desc, 0); } /*******************/ /* DELIVERED CARGO */ /*******************/ struct DeliveredCargoGraphWindow : BaseGraphWindow { DeliveredCargoGraphWindow(WindowDesc *desc, WindowNumber window_number) : BaseGraphWindow(desc, WID_CV_GRAPH, STR_JUST_COMMA) { this->InitializeWindow(window_number); } virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { return c->old_economy[j].delivered_cargo.GetSum(); } }; static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 128), SetFill(1, 1), SetResize(1, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _delivered_cargo_graph_desc( WDP_AUTO, "graph_delivered_cargo", 0, 0, WC_DELIVERED_CARGO, WC_NONE, 0, _nested_delivered_cargo_graph_widgets, lengthof(_nested_delivered_cargo_graph_widgets) ); void ShowDeliveredCargoGraph() { AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0); } /***********************/ /* PERFORMANCE HISTORY */ /***********************/ struct PerformanceHistoryGraphWindow : BaseGraphWindow { PerformanceHistoryGraphWindow(WindowDesc *desc, WindowNumber window_number) : BaseGraphWindow(desc, WID_PHG_GRAPH, STR_JUST_COMMA) { this->InitializeWindow(window_number); } virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { return c->old_economy[j].performance_history; } virtual void OnClick(Point pt, int widget, int click_count) { if (widget == WID_PHG_DETAILED_PERFORMANCE) ShowPerformanceRatingDetail(); this->BaseGraphWindow::OnClick(pt, widget, click_count); } }; static const NWidgetPart _nested_performance_history_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_PHG_DETAILED_PERFORMANCE), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_PERFORMANCE_DETAIL_KEY, STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_PHG_KEY), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_PHG_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_PHG_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_PHG_RESIZE), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _performance_history_desc( WDP_AUTO, "graph_performance", 0, 0, WC_PERFORMANCE_HISTORY, WC_NONE, 0, _nested_performance_history_widgets, lengthof(_nested_performance_history_widgets) ); void ShowPerformanceHistoryGraph() { AllocateWindowDescFront(&_performance_history_desc, 0); } /*****************/ /* COMPANY VALUE */ /*****************/ struct CompanyValueGraphWindow : BaseGraphWindow { CompanyValueGraphWindow(WindowDesc *desc, WindowNumber window_number) : BaseGraphWindow(desc, WID_CV_GRAPH, STR_JUST_CURRENCY_SHORT) { this->InitializeWindow(window_number); } virtual OverflowSafeInt64 GetGraphData(const Company *c, int j) { return c->old_economy[j].company_value; } }; static const NWidgetPart _nested_company_value_graph_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CV_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_CV_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CV_GRAPH), SetMinimalSize(576, 224), SetFill(1, 1), SetResize(1, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), SetResize(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CV_RESIZE), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _company_value_graph_desc( WDP_AUTO, "graph_company_value", 0, 0, WC_COMPANY_VALUE, WC_NONE, 0, _nested_company_value_graph_widgets, lengthof(_nested_company_value_graph_widgets) ); void ShowCompanyValueGraph() { AllocateWindowDescFront(&_company_value_graph_desc, 0); } /*****************/ /* PAYMENT RATES */ /*****************/ struct PaymentRatesGraphWindow : BaseGraphWindow { bool first_init; ///< This value is true until the first initialization of the window has finished. PaymentRatesGraphWindow(WindowDesc *desc, WindowNumber window_number) : BaseGraphWindow(desc, WID_CPR_GRAPH, STR_JUST_CURRENCY_SHORT) { this->first_init = true; this->num_on_x_axis = 20; this->num_vert_lines = 20; this->month = 0xFF; this->x_values_start = 10; this->x_values_increment = 10; /* Initialise the dataset */ this->OnHundredthTick(); this->InitNested(window_number); this->UpdateLoweredWidgets(); } virtual void OnInit() { /* UpdateLoweredWidgets needs to be called after a language or NewGRF change, but it can't be called before * InitNested is done. On the first init these functions are called in the correct order by the constructor. */ if (!this->first_init) { /* Initialise the dataset */ this->OnHundredthTick(); this->UpdateLoweredWidgets(); } this->first_init = false; } void UpdateExcludedData() { this->excluded_data = 0; int i = 0; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { if (HasBit(_legend_excluded_cargo, cs->Index())) SetBit(this->excluded_data, i); i++; } } void UpdateLoweredWidgets() { for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { this->SetWidgetLoweredState(WID_CPR_CARGO_FIRST + i, !HasBit(this->excluded_data, i)); } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget < WID_CPR_CARGO_FIRST) { BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize); return; } const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST]; SetDParam(0, cs->name); Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO); d.width += 14; // colour field d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(d, *size); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget < WID_CPR_CARGO_FIRST) { BaseGraphWindow::DrawWidget(r, widget); return; } const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CPR_CARGO_FIRST]; bool rtl = _current_text_dir == TD_RTL; /* Since the buttons have no text, no images, * both the text and the coloured box have to be manually painted. * clk_dif will move one pixel down and one pixel to the right * when the button is clicked */ byte clk_dif = this->IsWidgetLowered(widget) ? 1 : 0; int x = r.left + WD_FRAMERECT_LEFT; int y = r.top; int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT); GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, PC_BLACK); GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour); SetDParam(0, cs->name); DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_CPR_ENABLE_CARGOES: /* Remove all cargoes from the excluded lists. */ _legend_excluded_cargo = 0; this->excluded_data = 0; this->UpdateLoweredWidgets(); this->SetDirty(); break; case WID_CPR_DISABLE_CARGOES: { /* Add all cargoes to the excluded lists. */ int i = 0; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { SetBit(_legend_excluded_cargo, cs->Index()); SetBit(this->excluded_data, i); i++; } this->UpdateLoweredWidgets(); this->SetDirty(); break; } default: if (widget >= WID_CPR_CARGO_FIRST) { int i = widget - WID_CPR_CARGO_FIRST; ToggleBit(_legend_excluded_cargo, _sorted_cargo_specs[i]->Index()); this->ToggleWidgetLoweredState(widget); this->UpdateExcludedData(); this->SetDirty(); } break; } } virtual void OnTick() { /* Override default OnTick */ } /** * 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->OnHundredthTick(); } virtual void OnHundredthTick() { this->UpdateExcludedData(); int i = 0; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { this->colours[i] = cs->legend_colour; for (uint j = 0; j != 20; j++) { this->cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index()); } i++; } this->num_dataset = i; } }; /** Construct the row containing the digit keys. */ static NWidgetBase *MakeCargoButtons(int *biggest_index) { NWidgetVertical *ver = new NWidgetVertical; for (int i = 0; i < _sorted_standard_cargo_specs_size; i++) { NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, COLOUR_ORANGE, WID_CPR_CARGO_FIRST + i, NULL); leaf->tool_tip = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO; leaf->SetFill(1, 0); leaf->SetLowered(true); ver->Add(leaf); } *biggest_index = WID_CPR_CARGO_FIRST + _sorted_standard_cargo_specs_size - 1; return ver; } static const NWidgetPart _nested_cargo_payment_rates_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_CPR_BACKGROUND), SetMinimalSize(568, 128), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_TEXT, COLOUR_GREY, WID_CPR_HEADER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_TITLE, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CPR_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 0), SetResize(0, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_ENABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_CPR_DISABLE_CARGOES), SetDataTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0), NWidget(NWID_SPACER), SetMinimalSize(0, 4), NWidgetFunction(MakeCargoButtons), NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), SetResize(0, 1), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(WD_RESIZEBOX_WIDTH, 0), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_TEXT, COLOUR_GREY, WID_CPR_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY, WID_CPR_RESIZE), EndContainer(), EndContainer(), }; static WindowDesc _cargo_payment_rates_desc( WDP_AUTO, "graph_cargo_payment_rates", 0, 0, WC_PAYMENT_RATES, WC_NONE, 0, _nested_cargo_payment_rates_widgets, lengthof(_nested_cargo_payment_rates_widgets) ); void ShowCargoPaymentRates() { AllocateWindowDescFront(&_cargo_payment_rates_desc, 0); } /************************/ /* COMPANY LEAGUE TABLE */ /************************/ static const StringID _performance_titles[] = { STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT, STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON, }; static inline StringID GetPerformanceTitleFromValue(uint value) { return _performance_titles[minu(value, 1000) >> 6]; } class CompanyLeagueWindow : public Window { private: GUIList companies; uint ordinal_width; ///< The width of the ordinal number uint text_width; ///< The width of the actual text uint icon_width; ///< The width of the company icon int line_height; ///< Height of the text lines /** * (Re)Build the company league list */ void BuildCompanyList() { if (!this->companies.NeedRebuild()) return; this->companies.Clear(); const Company *c; FOR_ALL_COMPANIES(c) { *this->companies.Append() = c; } this->companies.Compact(); this->companies.RebuildDone(); } /** Sort the company league by performance history */ static int CDECL PerformanceSorter(const Company * const *c1, const Company * const *c2) { return (*c2)->old_economy[0].performance_history - (*c1)->old_economy[0].performance_history; } public: CompanyLeagueWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); this->companies.ForceRebuild(); this->companies.NeedResort(); } virtual void OnPaint() { this->BuildCompanyList(); this->companies.Sort(&PerformanceSorter); this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_CL_BACKGROUND) return; int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - this->line_height) / 2; uint y = r.top + WD_FRAMERECT_TOP - icon_y_offset; bool rtl = _current_text_dir == TD_RTL; uint ordinal_left = rtl ? r.right - WD_FRAMERECT_LEFT - this->ordinal_width : r.left + WD_FRAMERECT_LEFT; uint ordinal_right = rtl ? r.right - WD_FRAMERECT_LEFT : r.left + WD_FRAMERECT_LEFT + this->ordinal_width; uint icon_left = r.left + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + (rtl ? this->text_width : this->ordinal_width); uint text_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_LEFT - this->text_width; uint text_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->text_width : r.right - WD_FRAMERECT_LEFT; for (uint i = 0; i != this->companies.Length(); i++) { const Company *c = this->companies[i]; DrawString(ordinal_left, ordinal_right, y, i + STR_ORDINAL_NUMBER_1ST, i == 0 ? TC_WHITE : TC_YELLOW); DrawCompanyIcon(c->index, icon_left, y + icon_y_offset); SetDParam(0, c->index); SetDParam(1, c->index); SetDParam(2, GetPerformanceTitleFromValue(c->old_economy[0].performance_history)); DrawString(text_left, text_right, y, STR_COMPANY_LEAGUE_COMPANY_NAME); y += this->line_height; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_CL_BACKGROUND) return; this->ordinal_width = 0; for (uint i = 0; i < MAX_COMPANIES; i++) { this->ordinal_width = max(this->ordinal_width, GetStringBoundingBox(STR_ORDINAL_NUMBER_1ST + i).width); } this->ordinal_width += 5; // Keep some extra spacing uint widest_width = 0; uint widest_title = 0; for (uint i = 0; i < lengthof(_performance_titles); i++) { uint width = GetStringBoundingBox(_performance_titles[i]).width; if (width > widest_width) { widest_title = i; widest_width = width; } } Dimension d = GetSpriteSize(SPR_COMPANY_ICON); this->icon_width = d.width + 2; this->line_height = max(d.height + 2, FONT_HEIGHT_NORMAL); const Company *c; FOR_ALL_COMPANIES(c) { SetDParam(0, c->index); SetDParam(1, c->index); SetDParam(2, _performance_titles[widest_title]); widest_width = max(widest_width, GetStringBoundingBox(STR_COMPANY_LEAGUE_COMPANY_NAME).width); } this->text_width = widest_width + 30; // Keep some extra spacing size->width = WD_FRAMERECT_LEFT + this->ordinal_width + WD_FRAMERECT_RIGHT + this->icon_width + WD_FRAMERECT_LEFT + this->text_width + WD_FRAMERECT_RIGHT; size->height = WD_FRAMERECT_TOP + this->line_height * MAX_COMPANIES + WD_FRAMERECT_BOTTOM; } virtual void OnTick() { if (this->companies.NeedResort()) { this->SetDirty(); } } /** * 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 (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->companies.ForceRebuild(); } else { this->companies.ForceResort(); } } }; static const NWidgetPart _nested_company_league_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_LEAGUE_TABLE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_CL_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), }; static WindowDesc _company_league_desc( WDP_AUTO, "league", 0, 0, WC_COMPANY_LEAGUE, WC_NONE, 0, _nested_company_league_widgets, lengthof(_nested_company_league_widgets) ); void ShowCompanyLeagueTable() { AllocateWindowDescFront(&_company_league_desc, 0); } /*****************************/ /* PERFORMANCE RATING DETAIL */ /*****************************/ struct PerformanceRatingDetailWindow : Window { static CompanyID company; int timeout; PerformanceRatingDetailWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->UpdateCompanyStats(); this->InitNested(window_number); this->OnInvalidateData(INVALID_COMPANY); } void UpdateCompanyStats() { /* Update all company stats with the current data * (this is because _score_info is not saved to a savegame) */ Company *c; FOR_ALL_COMPANIES(c) { UpdateCompanyRatingAndValue(c, false); } this->timeout = DAY_TICKS * 5; } uint score_info_left; uint score_info_right; uint bar_left; uint bar_right; uint bar_width; uint bar_height; uint score_detail_left; uint score_detail_right; virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_PRD_SCORE_FIRST: this->bar_height = FONT_HEIGHT_NORMAL + 4; size->height = this->bar_height + 2 * WD_MATRIX_TOP; uint score_info_width = 0; for (uint i = SCORE_BEGIN; i < SCORE_END; i++) { score_info_width = max(score_info_width, GetStringBoundingBox(STR_PERFORMANCE_DETAIL_VEHICLES + i).width); } SetDParamMaxValue(0, 1000); score_info_width += GetStringBoundingBox(STR_BLACK_COMMA).width + WD_FRAMERECT_LEFT; SetDParamMaxValue(0, 100); this->bar_width = GetStringBoundingBox(STR_PERFORMANCE_DETAIL_PERCENT).width + 20; // Wide bars! /* At this number we are roughly at the max; it can become wider, * but then you need at 1000 times more money. At that time you're * not that interested anymore in the last few digits anyway. * The 500 is because 999 999 500 to 999 999 999 are rounded to * 1 000 M, and not 999 999 k. Use negative numbers to account for * the negative income/amount of money etc. as well. */ int max = -(999999999 - 500); /* Scale max for the display currency. Prior to rendering the value * is converted into the display currency, which may cause it to * raise significantly. We need to compensate for that since {{CURRCOMPACT}} * is used, which can produce quite short renderings of very large * values. Otherwise the calculated width could be too narrow. * Note that it doesn't work if there was a currency with an exchange * rate greater than max. * When the currency rate is more than 1000, the 999 999 k becomes at * least 999 999 M which roughly is equally long. Furthermore if the * exchange rate is that high, 999 999 k is usually not enough anymore * to show the different currency numbers. */ if (_currency->rate < 1000) max /= _currency->rate; SetDParam(0, max); SetDParam(1, max); uint score_detail_width = GetStringBoundingBox(STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY).width; size->width = 7 + score_info_width + 5 + this->bar_width + 5 + score_detail_width + 7; uint left = 7; uint right = size->width - 7; bool rtl = _current_text_dir == TD_RTL; this->score_info_left = rtl ? right - score_info_width : left; this->score_info_right = rtl ? right : left + score_info_width; this->score_detail_left = rtl ? left : right - score_detail_width; this->score_detail_right = rtl ? left + score_detail_width : right; this->bar_left = left + (rtl ? score_detail_width : score_info_width) + 5; this->bar_right = this->bar_left + this->bar_width; break; } } virtual void DrawWidget(const Rect &r, int widget) const { /* No need to draw when there's nothing to draw */ if (this->company == INVALID_COMPANY) return; if (IsInsideMM(widget, WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST + 1)) { if (this->IsWidgetDisabled(widget)) return; CompanyID cid = (CompanyID)(widget - WID_PRD_COMPANY_FIRST); int offset = (cid == this->company) ? 1 : 0; Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); DrawCompanyIcon(cid, (r.left + r.right - sprite_size.width) / 2 + offset, (r.top + r.bottom - sprite_size.height) / 2 + offset); return; } if (!IsInsideMM(widget, WID_PRD_SCORE_FIRST, WID_PRD_SCORE_LAST + 1)) return; ScoreID score_type = (ScoreID)(widget - WID_PRD_SCORE_FIRST); /* The colours used to show how the progress is going */ int colour_done = _colour_gradient[COLOUR_GREEN][4]; int colour_notdone = _colour_gradient[COLOUR_RED][4]; /* Draw all the score parts */ int val = _score_part[company][score_type]; int needed = _score_info[score_type].needed; int score = _score_info[score_type].score; /* SCORE_TOTAL has his own rules ;) */ if (score_type == SCORE_TOTAL) { for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) score += _score_info[i].score; needed = SCORE_MAX; } uint bar_top = r.top + WD_MATRIX_TOP; uint text_top = bar_top + 2; DrawString(this->score_info_left, this->score_info_right, text_top, STR_PERFORMANCE_DETAIL_VEHICLES + score_type); /* Draw the score */ SetDParam(0, score); DrawString(this->score_info_left, this->score_info_right, text_top, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT); /* Calculate the %-bar */ uint x = Clamp(val, 0, needed) * this->bar_width / needed; bool rtl = _current_text_dir == TD_RTL; if (rtl) { x = this->bar_right - x; } else { x = this->bar_left + x; } /* Draw the bar */ if (x != this->bar_left) GfxFillRect(this->bar_left, bar_top, x, bar_top + this->bar_height, rtl ? colour_notdone : colour_done); if (x != this->bar_right) GfxFillRect(x, bar_top, this->bar_right, bar_top + this->bar_height, rtl ? colour_done : colour_notdone); /* Draw it */ SetDParam(0, Clamp(val, 0, needed) * 100 / needed); DrawString(this->bar_left, this->bar_right, text_top, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING, SA_HOR_CENTER); /* SCORE_LOAN is inversed */ if (score_type == SCORE_LOAN) val = needed - val; /* Draw the amount we have against what is needed * For some of them it is in currency format */ SetDParam(0, val); SetDParam(1, needed); switch (score_type) { case SCORE_MIN_PROFIT: case SCORE_MIN_INCOME: case SCORE_MAX_INCOME: case SCORE_MONEY: case SCORE_LOAN: DrawString(this->score_detail_left, this->score_detail_right, text_top, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY); break; default: DrawString(this->score_detail_left, this->score_detail_right, text_top, STR_PERFORMANCE_DETAIL_AMOUNT_INT); } } virtual void OnClick(Point pt, int widget, int click_count) { /* Check which button is clicked */ if (IsInsideMM(widget, WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST + 1)) { /* Is it no on disable? */ if (!this->IsWidgetDisabled(widget)) { this->RaiseWidget(this->company + WID_PRD_COMPANY_FIRST); this->company = (CompanyID)(widget - WID_PRD_COMPANY_FIRST); this->LowerWidget(this->company + WID_PRD_COMPANY_FIRST); this->SetDirty(); } } } virtual void OnTick() { if (_pause_mode != PM_UNPAUSED) return; /* Update the company score every 5 days */ if (--this->timeout == 0) { this->UpdateCompanyStats(); this->SetDirty(); } } /** * Some data on this window has become invalid. * @param data the company ID of the company that is going to be removed * @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; /* Disable the companies who are not active */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { this->SetWidgetDisabledState(i + WID_PRD_COMPANY_FIRST, !Company::IsValidID(i)); } /* Check if the currently selected company is still active. */ if (this->company != INVALID_COMPANY && !Company::IsValidID(this->company)) { /* Raise the widget for the previous selection. */ this->RaiseWidget(this->company + WID_PRD_COMPANY_FIRST); this->company = INVALID_COMPANY; } if (this->company == INVALID_COMPANY) { const Company *c; FOR_ALL_COMPANIES(c) { this->company = c->index; break; } } /* Make sure the widget is lowered */ this->LowerWidget(this->company + WID_PRD_COMPANY_FIRST); } }; CompanyID PerformanceRatingDetailWindow::company = INVALID_COMPANY; /** * Make a vertical list of panels for outputting score details. * @param biggest_index Storage for collecting the biggest index used in the returned tree. * @return Panel with performance details. * @post \c *biggest_index contains the largest used index in the tree. */ static NWidgetBase *MakePerformanceDetailPanels(int *biggest_index) { const StringID performance_tips[] = { STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP, STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP, STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP, STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP, STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP, STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP, STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP, STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP, STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP, STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP, }; assert_compile(lengthof(performance_tips) == SCORE_END - SCORE_BEGIN); NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE); for (int widnum = WID_PRD_SCORE_FIRST; widnum <= WID_PRD_SCORE_LAST; widnum++) { NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum); panel->SetFill(1, 1); panel->SetDataTip(0x0, performance_tips[widnum - WID_PRD_SCORE_FIRST]); vert->Add(panel); } *biggest_index = WID_PRD_SCORE_LAST; return vert; } /** Make a number of rows with buttons for each company for the performance rating detail window. */ NWidgetBase *MakeCompanyButtonRowsGraphGUI(int *biggest_index) { return MakeCompanyButtonRows(biggest_index, WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST, 8, STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP); } static const NWidgetPart _nested_performance_rating_detail_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_PERFORMANCE_DETAIL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidgetFunction(MakeCompanyButtonRowsGraphGUI), SetPadding(0, 1, 1, 2), EndContainer(), NWidgetFunction(MakePerformanceDetailPanels), }; static WindowDesc _performance_rating_detail_desc( WDP_AUTO, "league_details", 0, 0, WC_PERFORMANCE_DETAIL, WC_NONE, 0, _nested_performance_rating_detail_widgets, lengthof(_nested_performance_rating_detail_widgets) ); void ShowPerformanceRatingDetail() { AllocateWindowDescFront(&_performance_rating_detail_desc, 0); } openttd-1.5.3/src/roadveh.h0000644000000000000000000002557612627373445014317 0ustar rootroot/* $Id: roadveh.h 25185 2013-04-13 13:42:08Z frosch $ */ /* * 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 src/roadveh.h Road vehicle states */ #ifndef ROADVEH_H #define ROADVEH_H #include "ground_vehicle.hpp" #include "engine_base.h" #include "cargotype.h" #include "track_func.h" #include "road_type.h" #include "newgrf_engine.h" struct RoadVehicle; /** Road vehicle states */ enum RoadVehicleStates { /* * Lower 4 bits are used for vehicle track direction. (Trackdirs) * When in a road stop (bit 5 or bit 6 set) these bits give the * track direction of the entry to the road stop. * As the entry direction will always be a diagonal * direction (X_NE, Y_SE, X_SW or Y_NW) only bits 0 and 3 * are needed to hold this direction. Bit 1 is then used to show * that the vehicle is using the second road stop bay. * Bit 2 is then used for drive-through stops to show the vehicle * is stopping at this road stop. */ /* Numeric values */ RVSB_IN_DEPOT = 0xFE, ///< The vehicle is in a depot RVSB_WORMHOLE = 0xFF, ///< The vehicle is in a tunnel and/or bridge /* Bit numbers */ RVS_USING_SECOND_BAY = 1, ///< Only used while in a road stop RVS_ENTERED_STOP = 2, ///< Only set when a vehicle has entered the stop RVS_DRIVE_SIDE = 4, ///< Only used when retrieving move data RVS_IN_ROAD_STOP = 5, ///< The vehicle is in a road stop RVS_IN_DT_ROAD_STOP = 6, ///< The vehicle is in a drive-through road stop /* Bit sets of the above specified bits */ RVSB_IN_ROAD_STOP = 1 << RVS_IN_ROAD_STOP, ///< The vehicle is in a road stop RVSB_IN_ROAD_STOP_END = RVSB_IN_ROAD_STOP + TRACKDIR_END, RVSB_IN_DT_ROAD_STOP = 1 << RVS_IN_DT_ROAD_STOP, ///< The vehicle is in a drive-through road stop RVSB_IN_DT_ROAD_STOP_END = RVSB_IN_DT_ROAD_STOP + TRACKDIR_END, RVSB_DRIVE_SIDE = 1 << RVS_DRIVE_SIDE, ///< The vehicle is at the opposite side of the road RVSB_TRACKDIR_MASK = 0x0F, ///< The mask used to extract track dirs RVSB_ROAD_STOP_TRACKDIR_MASK = 0x09, ///< Only bits 0 and 3 are used to encode the trackdir for road stops }; /** State information about the Road Vehicle controller */ static const uint RDE_NEXT_TILE = 0x80; ///< We should enter the next tile static const uint RDE_TURNED = 0x40; ///< We just finished turning /* Start frames for when a vehicle enters a tile/changes its state. * The start frame is different for vehicles that turned around or * are leaving the depot as the do not start at the edge of the tile. * For trams there are a few different start frames as there are two * places where trams can turn. */ static const uint RVC_DEFAULT_START_FRAME = 0; static const uint RVC_TURN_AROUND_START_FRAME = 1; static const uint RVC_DEPOT_START_FRAME = 6; static const uint RVC_START_FRAME_AFTER_LONG_TRAM = 21; static const uint RVC_TURN_AROUND_START_FRAME_SHORT_TRAM = 16; /* Stop frame for a vehicle in a drive-through stop */ static const uint RVC_DRIVE_THROUGH_STOP_FRAME = 11; static const uint RVC_DEPOT_STOP_FRAME = 11; /** The number of ticks a vehicle has for overtaking. */ static const byte RV_OVERTAKE_TIMEOUT = 35; void RoadVehUpdateCache(RoadVehicle *v, bool same_length = false); void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type); /** * Buses, trucks and trams belong to this class. */ struct RoadVehicle FINAL : public GroundVehicle { byte state; ///< @see RoadVehicleStates byte frame; uint16 blocked_ctr; byte overtaking; ///< Set to #RVSB_DRIVE_SIDE when overtaking, otherwise 0. byte overtaking_ctr; ///< The length of the current overtake attempt. uint16 crashed_ctr; ///< Animation counter when the vehicle has crashed. @see RoadVehIsCrashed byte reverse_ctr; RoadType roadtype; RoadTypes compatible_roadtypes; /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ RoadVehicle() : GroundVehicleBase() {} /** We want to 'destruct' the right class. */ virtual ~RoadVehicle() { this->PreDestructor(); } friend struct GroundVehicle; // GroundVehicle needs to use the acceleration functions defined at RoadVehicle. void MarkDirty(); void UpdateDeltaXY(Direction direction); ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_ROADVEH_INC : EXPENSES_ROADVEH_RUN; } bool IsPrimaryVehicle() const { return this->IsFrontEngine(); } SpriteID GetImage(Direction direction, EngineImageType image_type) const; int GetDisplaySpeed() const { return this->gcache.last_speed / 2; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; } Money GetRunningCost() const; int GetDisplayImageWidth(Point *offset = NULL) const; bool IsInDepot() const { return this->state == RVSB_IN_DEPOT; } bool Tick(); void OnNewDay(); uint Crash(bool flooded = false); Trackdir GetVehicleTrackdir() const; TileIndex GetOrderStationLocation(StationID station); bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); bool IsBus() const; int GetCurrentMaxSpeed() const; int UpdateSpeed(); protected: // These functions should not be called outside acceleration code. /** * Allows to know the power value that this vehicle will use. * @return Power value from the engine in HP, or zero if the vehicle is not powered. */ inline uint16 GetPower() const { /* Power is not added for articulated parts */ if (!this->IsArticulatedPart()) { /* Road vehicle power is in units of 10 HP. */ return 10 * GetVehicleProperty(this, PROP_ROADVEH_POWER, RoadVehInfo(this->engine_type)->power); } return 0; } /** * Returns a value if this articulated part is powered. * @return Zero, because road vehicles don't have powered parts. */ inline uint16 GetPoweredPartPower(const RoadVehicle *head) const { return 0; } /** * Allows to know the weight value that this vehicle will use. * @return Weight value from the engine in tonnes. */ inline uint16 GetWeight() const { uint16 weight = (CargoSpec::Get(this->cargo_type)->weight * this->cargo.StoredCount()) / 16; /* Vehicle weight is not added for articulated parts. */ if (!this->IsArticulatedPart()) { /* Road vehicle weight is in units of 1/4 t. */ weight += GetVehicleProperty(this, PROP_ROADVEH_WEIGHT, RoadVehInfo(this->engine_type)->weight) / 4; } return weight; } /** * Allows to know the tractive effort value that this vehicle will use. * @return Tractive effort value from the engine. */ inline byte GetTractiveEffort() const { /* The tractive effort coefficient is in units of 1/256. */ return GetVehicleProperty(this, PROP_ROADVEH_TRACTIVE_EFFORT, RoadVehInfo(this->engine_type)->tractive_effort); } /** * Gets the area used for calculating air drag. * @return Area of the engine in m^2. */ inline byte GetAirDragArea() const { return 6; } /** * Gets the air drag coefficient of this vehicle. * @return Air drag value from the engine. */ inline byte GetAirDrag() const { return RoadVehInfo(this->engine_type)->air_drag; } /** * Checks the current acceleration status of this vehicle. * @return Acceleration status. */ inline AccelStatus GetAccelerationStatus() const { return (this->vehstatus & VS_STOPPED) ? AS_BRAKE : AS_ACCEL; } /** * Calculates the current speed of this vehicle. * @return Current speed in km/h-ish. */ inline uint16 GetCurrentSpeed() const { return this->cur_speed / 2; } /** * Returns the rolling friction coefficient of this vehicle. * @return Rolling friction coefficient in [1e-4]. */ inline uint32 GetRollingFriction() const { /* Trams have a slightly greater friction coefficient than trains. * The rest of road vehicles have bigger values. */ uint32 coeff = (this->roadtype == ROADTYPE_TRAM) ? 40 : 75; /* The friction coefficient increases with speed in a way that * it doubles at 128 km/h, triples at 256 km/h and so on. */ return coeff * (128 + this->GetCurrentSpeed()) / 128; } /** * Allows to know the acceleration type of a vehicle. * @return Zero, road vehicles always use a normal acceleration method. */ inline int GetAccelerationType() const { return 0; } /** * Returns the slope steepness used by this vehicle. * @return Slope steepness used by the vehicle. */ inline uint32 GetSlopeSteepness() const { return _settings_game.vehicle.roadveh_slope_steepness; } /** * Gets the maximum speed allowed by the track for this vehicle. * @return Since roads don't limit road vehicle speed, it returns always zero. */ inline uint16 GetMaxTrackSpeed() const { return 0; } /** * Checks if the vehicle is at a tile that can be sloped. * @return True if the tile can be sloped. */ inline bool TileMayHaveSlopedTrack() const { TrackStatus ts = GetTileTrackStatus(this->tile, TRANSPORT_ROAD, this->compatible_roadtypes); TrackBits trackbits = TrackStatusToTrackBits(ts); return trackbits == TRACK_BIT_X || trackbits == TRACK_BIT_Y; } /** * Road vehicles have to use GetSlopePixelZ() to compute their height * if they are reversing because in that case, their direction * is not parallel with the road. It is safe to return \c true * even if it is not reversing. * @return are we (possibly) reversing? */ inline bool HasToUseGetSlopePixelZ() { const RoadVehicle *rv = this->First(); /* Check if this vehicle is in the same direction as the road under. * We already know it has either GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set. */ if (rv->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)rv->state)) { /* If the first vehicle is reversing, this vehicle may be reversing too * (especially if this is the first, and maybe the only, vehicle).*/ return true; } while (rv != this) { /* If any previous vehicle has different direction, * we may be in the middle of reversing. */ if (this->direction != rv->direction) return true; rv = rv->Next(); } return false; } }; #define FOR_ALL_ROADVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(RoadVehicle, var) #endif /* ROADVEH_H */ openttd-1.5.3/src/clear_map.h0000644000000000000000000002071412627373443014575 0ustar rootroot/* $Id: clear_map.h 27037 2014-10-23 17:13:44Z rubidium $ */ /* * 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 clear_map.h Map accessors for 'clear' tiles */ #ifndef CLEAR_MAP_H #define CLEAR_MAP_H #include "bridge_map.h" #include "industry_type.h" /** * Ground types. Valid densities in comments after the enum. */ enum ClearGround { CLEAR_GRASS = 0, ///< 0-3 CLEAR_ROUGH = 1, ///< 3 CLEAR_ROCKS = 2, ///< 3 CLEAR_FIELDS = 3, ///< 3 CLEAR_SNOW = 4, ///< 0-3 CLEAR_DESERT = 5, ///< 1,3 }; /** * Test if a tile is covered with snow. * @param t the tile to check * @pre IsTileType(t, MP_CLEAR) * @return whether the tile is covered with snow. */ static inline bool IsSnowTile(TileIndex t) { assert(IsTileType(t, MP_CLEAR)); return HasBit(_m[t].m3, 4); } /** * Get the type of clear tile but never return CLEAR_SNOW. * @param t the tile to get the clear ground type of * @pre IsTileType(t, MP_CLEAR) * @return the ground type */ static inline ClearGround GetRawClearGround(TileIndex t) { assert(IsTileType(t, MP_CLEAR)); return (ClearGround)GB(_m[t].m5, 2, 3); } /** * Get the type of clear tile. * @param t the tile to get the clear ground type of * @pre IsTileType(t, MP_CLEAR) * @return the ground type */ static inline ClearGround GetClearGround(TileIndex t) { if (IsSnowTile(t)) return CLEAR_SNOW; return GetRawClearGround(t); } /** * Set the type of clear tile. * @param t the tile to set the clear ground type of * @param ct the ground type * @pre IsTileType(t, MP_CLEAR) */ static inline bool IsClearGround(TileIndex t, ClearGround ct) { return GetClearGround(t) == ct; } /** * Get the density of a non-field clear tile. * @param t the tile to get the density of * @pre IsTileType(t, MP_CLEAR) * @return the density */ static inline uint GetClearDensity(TileIndex t) { assert(IsTileType(t, MP_CLEAR)); return GB(_m[t].m5, 0, 2); } /** * Increment the density of a non-field clear tile. * @param t the tile to increment the density of * @param d the amount to increment the density with * @pre IsTileType(t, MP_CLEAR) */ static inline void AddClearDensity(TileIndex t, int d) { assert(IsTileType(t, MP_CLEAR)); // XXX incomplete _m[t].m5 += d; } /** * Set the density of a non-field clear tile. * @param t the tile to set the density of * @param d the new density * @pre IsTileType(t, MP_CLEAR) */ static inline void SetClearDensity(TileIndex t, uint d) { assert(IsTileType(t, MP_CLEAR)); SB(_m[t].m5, 0, 2, d); } /** * Get the counter used to advance to the next clear density/field type. * @param t the tile to get the counter of * @pre IsTileType(t, MP_CLEAR) * @return the value of the counter */ static inline uint GetClearCounter(TileIndex t) { assert(IsTileType(t, MP_CLEAR)); return GB(_m[t].m5, 5, 3); } /** * Increments the counter used to advance to the next clear density/field type. * @param t the tile to increment the counter of * @param c the amount to increment the counter with * @pre IsTileType(t, MP_CLEAR) */ static inline void AddClearCounter(TileIndex t, int c) { assert(IsTileType(t, MP_CLEAR)); // XXX incomplete _m[t].m5 += c << 5; } /** * Sets the counter used to advance to the next clear density/field type. * @param t the tile to set the counter of * @param c the amount to set the counter to * @pre IsTileType(t, MP_CLEAR) */ static inline void SetClearCounter(TileIndex t, uint c) { assert(IsTileType(t, MP_CLEAR)); // XXX incomplete SB(_m[t].m5, 5, 3, c); } /** * Sets ground type and density in one go, also sets the counter to 0 * @param t the tile to set the ground type and density for * @param type the new ground type of the tile * @param density the density of the ground tile * @pre IsTileType(t, MP_CLEAR) */ static inline void SetClearGroundDensity(TileIndex t, ClearGround type, uint density) { assert(IsTileType(t, MP_CLEAR)); // XXX incomplete _m[t].m5 = 0 << 5 | type << 2 | density; } /** * Get the field type (production stage) of the field * @param t the field to get the type of * @pre GetClearGround(t) == CLEAR_FIELDS * @return the field type */ static inline uint GetFieldType(TileIndex t) { assert(GetClearGround(t) == CLEAR_FIELDS); return GB(_m[t].m3, 0, 4); } /** * Set the field type (production stage) of the field * @param t the field to get the type of * @param f the field type * @pre GetClearGround(t) == CLEAR_FIELDS */ static inline void SetFieldType(TileIndex t, uint f) { assert(GetClearGround(t) == CLEAR_FIELDS); // XXX incomplete SB(_m[t].m3, 0, 4, f); } /** * Get the industry (farm) that made the field * @param t the field to get creating industry of * @pre GetClearGround(t) == CLEAR_FIELDS * @return the industry that made the field */ static inline IndustryID GetIndustryIndexOfField(TileIndex t) { assert(GetClearGround(t) == CLEAR_FIELDS); return(IndustryID) _m[t].m2; } /** * Set the industry (farm) that made the field * @param t the field to get creating industry of * @param i the industry that made the field * @pre GetClearGround(t) == CLEAR_FIELDS */ static inline void SetIndustryIndexOfField(TileIndex t, IndustryID i) { assert(GetClearGround(t) == CLEAR_FIELDS); _m[t].m2 = i; } /** * Is there a fence at the given border? * @param t the tile to check for fences * @param side the border to check * @pre IsClearGround(t, CLEAR_FIELDS) * @return 0 if there is no fence, otherwise the fence type */ static inline uint GetFence(TileIndex t, DiagDirection side) { assert(IsClearGround(t, CLEAR_FIELDS)); switch (side) { default: NOT_REACHED(); case DIAGDIR_SE: return GB(_m[t].m4, 2, 3); case DIAGDIR_SW: return GB(_m[t].m4, 5, 3); case DIAGDIR_NE: return GB(_m[t].m3, 5, 3); case DIAGDIR_NW: return GB(_me[t].m6, 2, 3); } } /** * Sets the type of fence (and whether there is one) for the given border. * @param t the tile to check for fences * @param side the border to check * @param h 0 if there is no fence, otherwise the fence type * @pre IsClearGround(t, CLEAR_FIELDS) */ static inline void SetFence(TileIndex t, DiagDirection side, uint h) { assert(IsClearGround(t, CLEAR_FIELDS)); switch (side) { default: NOT_REACHED(); case DIAGDIR_SE: SB(_m[t].m4, 2, 3, h); break; case DIAGDIR_SW: SB(_m[t].m4, 5, 3, h); break; case DIAGDIR_NE: SB(_m[t].m3, 5, 3, h); break; case DIAGDIR_NW: SB(_me[t].m6, 2, 3, h); break; } } /** * Make a clear tile. * @param t the tile to make a clear tile * @param g the type of ground * @param density the density of the grass/snow/desert etc */ static inline void MakeClear(TileIndex t, ClearGround g, uint density) { SetTileType(t, MP_CLEAR); _m[t].m1 = 0; SetTileOwner(t, OWNER_NONE); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0 << 5 | 0 << 2; SetClearGroundDensity(t, g, density); // Sets m5 _me[t].m6 = 0; _me[t].m7 = 0; } /** * Make a (farm) field tile. * @param t the tile to make a farm field * @param field_type the 'growth' level of the field * @param industry the industry this tile belongs to */ static inline void MakeField(TileIndex t, uint field_type, IndustryID industry) { SetTileType(t, MP_CLEAR); _m[t].m1 = 0; SetTileOwner(t, OWNER_NONE); _m[t].m2 = industry; _m[t].m3 = field_type; _m[t].m4 = 0 << 5 | 0 << 2; SetClearGroundDensity(t, CLEAR_FIELDS, 3); SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } /** * Make a snow tile. * @param t the tile to make snowy * @param density The density of snowiness. * @pre GetClearGround(t) != CLEAR_SNOW */ static inline void MakeSnow(TileIndex t, uint density = 0) { assert(GetClearGround(t) != CLEAR_SNOW); SetBit(_m[t].m3, 4); if (GetRawClearGround(t) == CLEAR_FIELDS) { SetClearGroundDensity(t, CLEAR_GRASS, density); } else { SetClearDensity(t, density); } } /** * Clear the snow from a tile and return it to its previous type. * @param t the tile to clear of snow * @pre GetClearGround(t) == CLEAR_SNOW */ static inline void ClearSnow(TileIndex t) { assert(GetClearGround(t) == CLEAR_SNOW); ClrBit(_m[t].m3, 4); SetClearDensity(t, 3); } #endif /* CLEAR_MAP_H */ openttd-1.5.3/src/road_cmd.h0000644000000000000000000000164512627373442014423 0ustar rootroot/* $Id: road_cmd.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 road_cmd.h Road related functions. */ #ifndef ROAD_CMD_H #define ROAD_CMD_H #include "direction_type.h" #include "road_type.h" void DrawRoadDepotSprite(int x, int y, DiagDirection dir, RoadType rt); void UpdateNearestTownForRoadTiles(bool invalidate); #endif /* ROAD_CMD_H */ openttd-1.5.3/src/texteff.hpp0000644000000000000000000000330612627373442014654 0ustar rootroot/* $Id: texteff.hpp 25011 2013-02-17 14:50:54Z rubidium $ */ /* * 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 texteff.hpp Functions related to text effects. */ #ifndef TEXTEFF_HPP #define TEXTEFF_HPP #include "economy_type.h" #include "gfx_type.h" #include "strings_type.h" /** * Text effect modes. */ enum TextEffectMode { TE_RISING, ///< Make the text effect slowly go upwards TE_STATIC, ///< Keep the text effect static INVALID_TE_ID = 0xFFFF, }; typedef uint16 TextEffectID; void MoveAllTextEffects(); TextEffectID AddTextEffect(StringID msg, int x, int y, uint8 duration, TextEffectMode mode); void InitTextEffects(); void DrawTextEffects(DrawPixelInfo *dpi); void UpdateTextEffect(TextEffectID effect_id, StringID msg); void RemoveTextEffect(TextEffectID effect_id); /* misc_gui.cpp */ TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID colour); void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID colour); void HideFillingPercent(TextEffectID *te_id); void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost); void ShowFeederIncomeAnimation(int x, int y, int z, Money transfer, Money income); #endif /* TEXTEFF_HPP */ openttd-1.5.3/src/ship_cmd.cpp0000644000000000000000000005206612627373434015000 0ustar rootroot/* $Id: ship_cmd.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 ship_cmd.cpp Handling of ships. */ #include "stdafx.h" #include "ship.h" #include "landscape.h" #include "timetable.h" #include "news_func.h" #include "company_func.h" #include "pathfinder/npf/npf_func.h" #include "depot_base.h" #include "station_base.h" #include "newgrf_engine.h" #include "pathfinder/yapf/yapf.h" #include "newgrf_sound.h" #include "spritecache.h" #include "strings_func.h" #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "ai/ai.hpp" #include "pathfinder/opf/opf_ship.h" #include "engine_base.h" #include "company_base.h" #include "tunnelbridge_map.h" #include "zoom_func.h" #include "table/strings.h" #include "safeguards.h" /** * Determine the effective #WaterClass for a ship travelling on a tile. * @param tile Tile of interest * @return the waterclass to be used by the ship. */ WaterClass GetEffectiveWaterClass(TileIndex tile) { if (HasTileWaterClass(tile)) return GetWaterClass(tile); if (IsTileType(tile, MP_TUNNELBRIDGE)) { assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_WATER); return WATER_CLASS_CANAL; } if (IsTileType(tile, MP_RAILWAY)) { assert(GetRailGroundType(tile) == RAIL_GROUND_WATER); return WATER_CLASS_SEA; } NOT_REACHED(); } static const uint16 _ship_sprites[] = {0x0E5D, 0x0E55, 0x0E65, 0x0E6D}; template <> bool IsValidImageIndex(uint8 image_index) { return image_index < lengthof(_ship_sprites); } static inline TrackBits GetTileShipTrackStatus(TileIndex tile) { return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); } static SpriteID GetShipIcon(EngineID engine, EngineImageType image_type) { const Engine *e = Engine::Get(engine); uint8 spritenum = e->u.ship.image_index; if (is_custom_sprite(spritenum)) { SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type); if (sprite != 0) return sprite; spritenum = e->original_image_index; } assert(IsValidImageIndex(spritenum)); return DIR_W + _ship_sprites[spritenum]; } void DrawShipEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { SpriteID sprite = GetShipIcon(engine, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); preferred_x = Clamp(preferred_x, left - UnScaleGUI(real_sprite->x_offs), right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); DrawSprite(sprite, pal, preferred_x, y); } /** * Get the size of the sprite of a ship sprite heading west (used for lists). * @param engine The engine to get the sprite from. * @param[out] width The width of the sprite. * @param[out] height The height of the sprite. * @param[out] xoffs Number of pixels to shift the sprite to the right. * @param[out] yoffs Number of pixels to shift the sprite downwards. * @param image_type Context the sprite is used in. */ void GetShipSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) { const Sprite *spr = GetSprite(GetShipIcon(engine, image_type), ST_NORMAL); width = UnScaleGUI(spr->width); height = UnScaleGUI(spr->height); xoffs = UnScaleGUI(spr->x_offs); yoffs = UnScaleGUI(spr->y_offs); } SpriteID Ship::GetImage(Direction direction, EngineImageType image_type) const { uint8 spritenum = this->spritenum; if (is_custom_sprite(spritenum)) { SpriteID sprite = GetCustomVehicleSprite(this, direction, image_type); if (sprite != 0) return sprite; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); return _ship_sprites[spritenum] + direction; } static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance) { /* Find the closest depot */ const Depot *depot; const Depot *best_depot = NULL; /* If we don't have a maximum distance, i.e. distance = 0, * we want to find any depot so the best distance of no * depot must be more than any correct distance. On the * other hand if we have set a maximum distance, any depot * further away than max_distance can safely be ignored. */ uint best_dist = max_distance == 0 ? UINT_MAX : max_distance + 1; FOR_ALL_DEPOTS(depot) { TileIndex tile = depot->xy; if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) { uint dist = DistanceManhattan(tile, v->tile); if (dist < best_dist) { best_dist = dist; best_depot = depot; } } } return best_depot; } static void CheckIfShipNeedsService(Vehicle *v) { if (Company::Get(v->owner)->settings.vehicle.servint_ships == 0 || !v->NeedsAutomaticServicing()) return; if (v->IsChainInDepot()) { VehicleServiceInDepot(v); return; } uint max_distance; switch (_settings_game.pf.pathfinder_for_ships) { case VPF_OPF: max_distance = 12; break; case VPF_NPF: max_distance = _settings_game.pf.npf.maximum_go_to_depot_penalty / NPF_TILE_LENGTH; break; case VPF_YAPF: max_distance = _settings_game.pf.yapf.maximum_go_to_depot_penalty / YAPF_TILE_LENGTH; break; default: NOT_REACHED(); } const Depot *depot = FindClosestShipDepot(v, max_distance); if (depot == NULL) { if (v->current_order.IsType(OT_GOTO_DEPOT)) { v->current_order.MakeDummy(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } return; } v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE); v->dest_tile = depot->xy; SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } /** * Update the caches of this ship. */ void Ship::UpdateCache() { const ShipVehicleInfo *svi = ShipVehInfo(this->engine_type); /* Get speed fraction for the current water type. Aqueducts are always canals. */ bool is_ocean = GetEffectiveWaterClass(this->tile) == WATER_CLASS_SEA; uint raw_speed = GetVehicleProperty(this, PROP_SHIP_SPEED, svi->max_speed); this->vcache.cached_max_speed = svi->ApplyWaterClassSpeedFrac(raw_speed, is_ocean); /* Update cargo aging period. */ this->vcache.cached_cargo_age_period = GetVehicleProperty(this, PROP_SHIP_CARGO_AGE_PERIOD, EngInfo(this->engine_type)->cargo_age_period); this->UpdateVisualEffect(); } Money Ship::GetRunningCost() const { const Engine *e = this->GetEngine(); uint cost_factor = GetVehicleProperty(this, PROP_SHIP_RUNNING_COST_FACTOR, e->u.ship.running_cost); return GetPrice(PR_RUNNING_SHIP, cost_factor, e->GetGRF()); } void Ship::OnNewDay() { if ((++this->day_counter & 7) == 0) { DecreaseVehicleValue(this); } CheckVehicleBreakdown(this); AgeVehicle(this); CheckIfShipNeedsService(this); CheckOrders(this); if (this->running_ticks == 0) return; CommandCost cost(EXPENSES_SHIP_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS)); this->profit_this_year -= cost.GetCost(); this->running_ticks = 0; SubtractMoneyFromCompanyFract(this->owner, cost); SetWindowDirty(WC_VEHICLE_DETAILS, this->index); /* we need this for the profit */ SetWindowClassesDirty(WC_SHIPS_LIST); } Trackdir Ship::GetVehicleTrackdir() const { if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR; if (this->IsInDepot()) { /* We'll assume the ship is facing outwards */ return DiagDirToDiagTrackdir(GetShipDepotDirection(this->tile)); } if (this->state == TRACK_BIT_WORMHOLE) { /* ship on aqueduct, so just use his direction and assume a diagonal track */ return DiagDirToDiagTrackdir(DirToDiagDir(this->direction)); } return TrackDirectionToTrackdir(FindFirstTrack(this->state), this->direction); } void Ship::MarkDirty() { this->colourmap = PAL_NONE; this->UpdateViewport(true, false); this->UpdateCache(); } static void PlayShipSound(const Vehicle *v) { if (!PlayVehicleSound(v, VSE_START)) { SndPlayVehicleFx(ShipVehInfo(v->engine_type)->sfx, v); } } void Ship::PlayLeaveStationSound() const { PlayShipSound(this); } TileIndex Ship::GetOrderStationLocation(StationID station) { if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION; const Station *st = Station::Get(station); if (st->dock_tile != INVALID_TILE) { return TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile))); } else { this->IncrementRealOrderIndex(); return 0; } } void Ship::UpdateDeltaXY(Direction direction) { static const int8 _delta_xy_table[8][4] = { /* y_extent, x_extent, y_offs, x_offs */ { 6, 6, -3, -3}, // N { 6, 32, -3, -16}, // NE { 6, 6, -3, -3}, // E {32, 6, -16, -3}, // SE { 6, 6, -3, -3}, // S { 6, 32, -3, -16}, // SW { 6, 6, -3, -3}, // W {32, 6, -16, -3}, // NW }; const int8 *bb = _delta_xy_table[direction]; this->x_offs = bb[3]; this->y_offs = bb[2]; this->x_extent = bb[1]; this->y_extent = bb[0]; this->z_extent = 6; } static const TileIndexDiffC _ship_leave_depot_offs[] = { {-1, 0}, { 0, -1} }; static bool CheckShipLeaveDepot(Ship *v) { if (!v->IsChainInDepot()) return false; /* We are leaving a depot, but have to go to the exact same one; re-enter */ if (v->current_order.IsType(OT_GOTO_DEPOT) && IsShipDepotTile(v->tile) && GetDepotIndex(v->tile) == v->current_order.GetDestination()) { VehicleEnterDepot(v); return true; } TileIndex tile = v->tile; Axis axis = GetShipDepotAxis(tile); DiagDirection north_dir = ReverseDiagDir(AxisToDiagDir(axis)); TileIndex north_neighbour = TILE_ADD(tile, ToTileIndexDiff(_ship_leave_depot_offs[axis])); DiagDirection south_dir = AxisToDiagDir(axis); TileIndex south_neighbour = TILE_ADD(tile, -2 * ToTileIndexDiff(_ship_leave_depot_offs[axis])); TrackBits north_tracks = DiagdirReachesTracks(north_dir) & GetTileShipTrackStatus(north_neighbour); TrackBits south_tracks = DiagdirReachesTracks(south_dir) & GetTileShipTrackStatus(south_neighbour); if (north_tracks && south_tracks) { /* Ask pathfinder for best direction */ bool reverse = false; bool path_found; switch (_settings_game.pf.pathfinder_for_ships) { case VPF_OPF: reverse = OPFShipChooseTrack(v, north_neighbour, north_dir, north_tracks, path_found) == INVALID_TRACK; break; // OPF always allows reversing case VPF_NPF: reverse = NPFShipCheckReverse(v); break; case VPF_YAPF: reverse = YapfShipCheckReverse(v); break; default: NOT_REACHED(); } if (reverse) north_tracks = TRACK_BIT_NONE; } if (north_tracks) { /* Leave towards north */ v->direction = DiagDirToDir(north_dir); } else if (south_tracks) { /* Leave towards south */ v->direction = DiagDirToDir(south_dir); } else { /* Both ways blocked */ return false; } v->state = AxisToTrackBits(axis); v->vehstatus &= ~VS_HIDDEN; v->cur_speed = 0; v->UpdateViewport(true, true); SetWindowDirty(WC_VEHICLE_DEPOT, v->tile); PlayShipSound(v); VehicleServiceInDepot(v); InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile); SetWindowClassesDirty(WC_SHIPS_LIST); return false; } static bool ShipAccelerate(Vehicle *v) { uint spd; byte t; spd = min(v->cur_speed + 1, v->vcache.cached_max_speed); spd = min(spd, v->current_order.GetMaxSpeed() * 2); /* 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, WID_VV_START_STOP); } /* Convert direction-independent speed into direction-dependent speed. (old movement method) */ spd = v->GetOldAdvanceSpeed(spd); if (spd == 0) return false; if ((byte)++spd == 0) return true; v->progress = (t = v->progress) - (byte)spd; return (t < v->progress); } /** * Ship arrives at a dock. If it is the first time, send out a news item. * @param v Ship that arrived. * @param st Station being visited. */ static void ShipArrivesAt(const Vehicle *v, Station *st) { /* Check if station was ever visited before */ if (!(st->had_vehicle_of_type & HVOT_SHIP)) { st->had_vehicle_of_type |= HVOT_SHIP; SetDParam(0, st->index); AddVehicleNewsItem( STR_NEWS_FIRST_SHIP_ARRIVAL, (v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER, v->index, st->index ); AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index)); } } /** * Runs the pathfinder to choose a track to continue along. * * @param v Ship to navigate * @param tile Tile, the ship is about to enter * @param enterdir Direction of entering * @param tracks Available track choices on \a tile * @return Track to choose, or INVALID_TRACK when to reverse. */ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks) { assert(IsValidDiagDirection(enterdir)); bool path_found = true; Track track; switch (_settings_game.pf.pathfinder_for_ships) { case VPF_OPF: track = OPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break; case VPF_NPF: track = NPFShipChooseTrack(v, tile, enterdir, tracks, path_found); break; case VPF_YAPF: track = YapfShipChooseTrack(v, tile, enterdir, tracks, path_found); break; default: NOT_REACHED(); } v->HandlePathfindingResult(path_found); return track; } static const Direction _new_vehicle_direction_table[] = { DIR_N , DIR_NW, DIR_W , INVALID_DIR, DIR_NE, DIR_N , DIR_SW, INVALID_DIR, DIR_E , DIR_SE, DIR_S }; static Direction ShipGetNewDirectionFromTiles(TileIndex new_tile, TileIndex old_tile) { uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 + TileX(new_tile) - TileX(old_tile) + 1; assert(offs < 11 && offs != 3 && offs != 7); return _new_vehicle_direction_table[offs]; } static Direction ShipGetNewDirection(Vehicle *v, int x, int y) { uint offs = (y - v->y_pos + 1) * 4 + (x - v->x_pos + 1); assert(offs < 11 && offs != 3 && offs != 7); return _new_vehicle_direction_table[offs]; } static inline TrackBits GetAvailShipTracks(TileIndex tile, DiagDirection dir) { return GetTileShipTrackStatus(tile) & DiagdirReachesTracks(dir); } static const byte _ship_subcoord[4][6][3] = { { {15, 8, 1}, { 0, 0, 0}, { 0, 0, 0}, {15, 8, 2}, {15, 7, 0}, { 0, 0, 0}, }, { { 0, 0, 0}, { 8, 0, 3}, { 7, 0, 2}, { 0, 0, 0}, { 8, 0, 4}, { 0, 0, 0}, }, { { 0, 8, 5}, { 0, 0, 0}, { 0, 7, 6}, { 0, 0, 0}, { 0, 0, 0}, { 0, 8, 4}, }, { { 0, 0, 0}, { 8, 15, 7}, { 0, 0, 0}, { 8, 15, 6}, { 0, 0, 0}, { 7, 15, 0}, } }; static void ShipController(Ship *v) { uint32 r; const byte *b; Direction dir; Track track; TrackBits tracks; v->tick_counter++; v->current_order_time++; if (v->HandleBreakdown()) return; if (v->vehstatus & VS_STOPPED) return; ProcessOrders(v); v->HandleLoading(); if (v->current_order.IsType(OT_LOADING)) return; if (CheckShipLeaveDepot(v)) return; v->ShowVisualEffect(); if (!ShipAccelerate(v)) return; GetNewVehiclePosResult gp = GetNewVehiclePos(v); if (v->state != TRACK_BIT_WORMHOLE) { /* Not on a bridge */ if (gp.old_tile == gp.new_tile) { /* Staying in tile */ if (v->IsInDepot()) { gp.x = v->x_pos; gp.y = v->y_pos; } else { /* Not inside depot */ r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction; /* A leave station order only needs one tick to get processed, so we can * always skip ahead. */ if (v->current_order.IsType(OT_LEAVESTATION)) { v->current_order.Free(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); } else if (v->dest_tile != 0) { /* We have a target, let's see if we reached it... */ if (v->current_order.IsType(OT_GOTO_WAYPOINT) && DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) { /* We got within 3 tiles of our target buoy, so let's skip to our * next order */ UpdateVehicleTimetable(v, true); v->IncrementRealOrderIndex(); v->current_order.MakeDummy(); } else { /* Non-buoy orders really need to reach the tile */ if (v->dest_tile == gp.new_tile) { if (v->current_order.IsType(OT_GOTO_DEPOT)) { if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) { VehicleEnterDepot(v); return; } } else if (v->current_order.IsType(OT_GOTO_STATION)) { v->last_station_visited = v->current_order.GetDestination(); /* Process station in the orderlist. */ Station *st = Station::Get(v->current_order.GetDestination()); if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations ShipArrivesAt(v, st); v->BeginLoading(); } else { // leave stations without docks right aways v->current_order.MakeLeaveStation(); v->IncrementRealOrderIndex(); } } } } } } } else { /* New tile */ if (!IsValidTile(gp.new_tile)) goto reverse_direction; dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile); assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW); DiagDirection diagdir = DirToDiagDir(dir); tracks = GetAvailShipTracks(gp.new_tile, diagdir); if (tracks == TRACK_BIT_NONE) goto reverse_direction; /* Choose a direction, and continue if we find one */ track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks); if (track == INVALID_TRACK) goto reverse_direction; b = _ship_subcoord[diagdir][track]; gp.x = (gp.x & ~0xF) | b[0]; gp.y = (gp.y & ~0xF) | b[1]; /* Call the landscape function and tell it that the vehicle entered the tile */ r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction; if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { v->tile = gp.new_tile; v->state = TrackToTrackBits(track); /* Update ship cache when the water class changes. Aqueducts are always canals. */ WaterClass old_wc = GetEffectiveWaterClass(gp.old_tile); WaterClass new_wc = GetEffectiveWaterClass(gp.new_tile); if (old_wc != new_wc) v->UpdateCache(); } v->direction = (Direction)b[2]; } } else { /* On a bridge */ if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { v->x_pos = gp.x; v->y_pos = gp.y; v->UpdatePosition(); if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true); return; } } /* update image of ship, as well as delta XY */ dir = ShipGetNewDirection(v, gp.x, gp.y); v->x_pos = gp.x; v->y_pos = gp.y; v->z_pos = GetSlopePixelZ(gp.x, gp.y); getout: v->UpdatePosition(); v->UpdateViewport(true, true); return; reverse_direction: dir = ReverseDir(v->direction); v->direction = dir; goto getout; } bool Ship::Tick() { if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; ShipController(this); return true; } /** * Build a ship. * @param tile tile of the depot where ship is built. * @param flags type of operation. * @param e the engine to build. * @param data unused. * @param ret[out] the vehicle that has been built. * @return the cost of this operation or an error. */ CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret) { tile = GetShipDepotNorthTile(tile); if (flags & DC_EXEC) { int x; int y; const ShipVehicleInfo *svi = &e->u.ship; Ship *v = new Ship(); *ret = v; v->owner = _current_company; v->tile = tile; x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2; y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2; v->x_pos = x; v->y_pos = y; v->z_pos = GetSlopePixelZ(x, y); v->UpdateDeltaXY(v->direction); v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; v->spritenum = svi->image_index; v->cargo_type = e->GetDefaultCargoType(); v->cargo_cap = svi->capacity; v->refit_cap = 0; v->last_station_visited = INVALID_STATION; v->last_loading_station = INVALID_STATION; v->engine_type = e->index; v->reliability = e->reliability; v->reliability_spd_dec = e->reliability_spd_dec; v->max_age = e->GetLifeLengthInDays(); _new_vehicle_id = v->index; v->state = TRACK_BIT_DEPOT; v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_ships); v->date_of_last_service = _date; v->build_year = _cur_year; v->cur_image = SPR_IMG_QUERY; v->random_bits = VehicleRandomBits(); v->UpdateCache(); if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent); v->InvalidateNewGRFCacheOfChain(); v->cargo_cap = e->DetermineCapacity(v); v->InvalidateNewGRFCacheOfChain(); v->UpdatePosition(); } return CommandCost(); } bool Ship::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { const Depot *depot = FindClosestShipDepot(this, 0); if (depot == NULL) return false; if (location != NULL) *location = depot->xy; if (destination != NULL) *destination = depot->index; return true; } openttd-1.5.3/src/station_func.h0000644000000000000000000000520112627373435015341 0ustar rootroot/* $Id: station_func.h 26549 2014-05-01 14:50:52Z fonsinchen $ */ /* * 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 station_func.h Functions related to stations. */ #ifndef STATION_FUNC_H #define STATION_FUNC_H #include "sprite.h" #include "rail_type.h" #include "road_type.h" #include "vehicle_type.h" #include "economy_func.h" #include "rail.h" #include "linkgraph/linkgraph_type.h" void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius); void FindStationsAroundTiles(const TileArea &location, StationList *stations); void ShowStationViewWindow(StationID station); void UpdateAllStationVirtCoords(); CargoArray GetProductionAroundTiles(TileIndex tile, int w, int h, int rad); CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad, uint32 *always_accepted = NULL); void UpdateStationAcceptance(Station *st, bool show_msg); const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx); void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image); bool HasStationInUse(StationID station, bool include_company, CompanyID company); void DeleteOilRig(TileIndex t); /* Check if a rail station tile is traversable. */ bool IsStationTileBlocked(TileIndex tile); bool CanStationTileHavePylons(TileIndex tile); bool CanStationTileHaveWires(TileIndex tile); void UpdateAirportsNoise(); bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrackOffset *overlay_offset); void IncreaseStats(Station *st, const Vehicle *v, StationID next_station_id); void IncreaseStats(Station *st, CargoID cargo, StationID next_station_id, uint capacity, uint usage, EdgeUpdateMode mode); void RerouteCargo(Station *st, CargoID c, StationID avoid, StationID avoid2); /** * Calculates the maintenance cost of a number of station tiles. * @param num Number of station tiles. * @return Total cost. */ static inline Money StationMaintenanceCost(uint32 num) { return (_price[PR_INFRASTRUCTURE_STATION] * num * (1 + IntSqrt(num))) >> 7; // 7 bits scaling. } Money AirportMaintenanceCost(Owner owner); #endif /* STATION_FUNC_H */ openttd-1.5.3/src/townname.cpp0000644000000000000000000010453012627373435015035 0ustar rootroot/* $Id: townname.cpp 27187 2015-03-15 12:19:58Z frosch $ */ /* * 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 townname.cpp %Town name generators. */ #include "stdafx.h" #include "string_func.h" #include "townname_type.h" #include "town.h" #include "strings_func.h" #include "core/random_func.hpp" #include "genworld.h" #include "gfx_layout.h" #include "table/townname.h" #include "safeguards.h" /** * Initializes this struct from town data * @param t town for which we will be printing name later */ TownNameParams::TownNameParams(const Town *t) : grfid(t->townnamegrfid), // by default, use supplied data type(t->townnametype) { if (t->townnamegrfid != 0 && GetGRFTownName(t->townnamegrfid) == NULL) { /* Fallback to english original */ this->grfid = 0; this->type = SPECSTR_TOWNNAME_ENGLISH; return; } } /** * Fills buffer with specified town name * @param buff buffer start * @param par town name parameters * @param townnameparts 'encoded' town name * @param last end of buffer * @return pointer to terminating '\0' */ char *GetTownName(char *buff, const TownNameParams *par, uint32 townnameparts, const char *last) { if (par->grfid == 0) { int64 args_array[1] = { townnameparts }; StringParameters tmp_params(args_array); return GetStringWithArgs(buff, par->type, &tmp_params, last); } return GRFTownNameGenerate(buff, par->grfid, par->type, townnameparts, last); } /** * Fills buffer with town's name * @param buff buffer start * @param t we want to get name of this town * @param last end of buffer * @return pointer to terminating '\0' */ char *GetTownName(char *buff, const Town *t, const char *last) { TownNameParams par(t); return GetTownName(buff, &par, t->townnameparts, last); } /** * Verifies the town name is valid and unique. * @param r random bits * @param par town name parameters * @param town_names if a name is generated, check its uniqueness with the set * @return true iff name is valid and unique */ bool VerifyTownName(uint32 r, const TownNameParams *par, TownNames *town_names) { /* reserve space for extra unicode character and terminating '\0' */ char buf1[(MAX_LENGTH_TOWN_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; char buf2[(MAX_LENGTH_TOWN_NAME_CHARS + 1) * MAX_CHAR_LENGTH]; GetTownName(buf1, par, r, lastof(buf1)); /* Check size and width */ if (Utf8StringLength(buf1) >= MAX_LENGTH_TOWN_NAME_CHARS) return false; if (town_names != NULL) { if (town_names->find(buf1) != town_names->end()) return false; town_names->insert(buf1); } else { const Town *t; FOR_ALL_TOWNS(t) { /* We can't just compare the numbers since * several numbers may map to a single name. */ const char *buf = t->name; if (buf == NULL) { GetTownName(buf2, t, lastof(buf2)); buf = buf2; } if (strcmp(buf1, buf) == 0) return false; } } return true; } /** * Generates valid town name. * @param townnameparts if a name is generated, it's stored there * @param town_names if a name is generated, check its uniqueness with the set * @return true iff a name was generated */ bool GenerateTownName(uint32 *townnameparts, TownNames *town_names) { /* Do not set too low tries, since when we run out of names, we loop * for #tries only one time anyway - then we stop generating more * towns. Do not show it too high neither, since looping through all * the other towns may take considerable amount of time (10000 is * too much). */ TownNameParams par(_settings_game.game_creation.town_name); /* This function is called very often without entering the gameloop * inbetween. So reset layout cache to prevent it from growing too big. */ Layouter::ReduceLineCache(); for (int i = 1000; i != 0; i--) { uint32 r = _generating_world ? Random() : InteractiveRandom(); if (!VerifyTownName(r, &par, town_names)) continue; *townnameparts = r; return true; } return false; } /** * Generates a number from given seed. * @param shift_by number of bits seed is shifted to the right * @param max generated number is in interval 0...max-1 * @param seed seed * @return seed transformed to a number from given range */ static inline uint32 SeedChance(byte shift_by, int max, uint32 seed) { return (GB(seed, shift_by, 16) * max) >> 16; } /** * Generates a number from given seed. Uses different algorithm than SeedChance(). * @param shift_by number of bits seed is shifted to the right * @param max generated number is in interval 0...max-1 * @param seed seed * @return seed transformed to a number from given range */ static inline uint32 SeedModChance(byte shift_by, int max, uint32 seed) { /* This actually gives *MUCH* more even distribution of the values * than SeedChance(), which is absolutely horrible in that. If * you do not believe me, try with i.e. the Czech town names, * compare the words (nicely visible on prefixes) generated by * SeedChance() and SeedModChance(). Do not get discouraged by the * never-use-modulo myths, which hold true only for the linear * congruential generators (and Random() isn't such a generator). * --pasky * TODO: Perhaps we should use it for all the name generators? --pasky */ return (seed >> shift_by) % max; } /** * Generates a number from given seed. * @param shift_by number of bits seed is shifted to the right * @param max generated number is in interval -bias...max-1 * @param seed seed * @param bias minimum value that can be returned * @return seed transformed to a number from given range */ static inline int32 SeedChanceBias(byte shift_by, int max, uint32 seed, int bias) { return SeedChance(shift_by, max + bias, seed) - bias; } /** * Replaces a string beginning in 'org' with 'rep'. * @param org string to replace, has to be 4 characters long * @param rep string to be replaced with, has to be 4 characters long * @param buf buffer with string */ static void ReplaceWords(const char *org, const char *rep, char *buf) { assert(strlen(org) == 4 && strlen(rep) == 4 && strlen(buf) >= 4); if (strncmp(buf, org, 4) == 0) memcpy(buf, rep, 4); // Safe as the string in buf is always more than 4 characters long. } /** * Replaces english curses and ugly letter combinations by nicer ones. * @param buf buffer with town name * @param original English (Original) generator was used */ static void ReplaceEnglishWords(char *buf, bool original) { ReplaceWords("Cunt", "East", buf); ReplaceWords("Slag", "Pits", buf); ReplaceWords("Slut", "Edin", buf); if (!original) ReplaceWords("Fart", "Boot", buf); // never happens with 'English (Original)' ReplaceWords("Drar", "Quar", buf); ReplaceWords("Dreh", "Bash", buf); ReplaceWords("Frar", "Shor", buf); ReplaceWords("Grar", "Aber", buf); ReplaceWords("Brar", "Over", buf); ReplaceWords("Wrar", original ? "Inve" : "Stan", buf); } /** * Generates English (Original) town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeEnglishOriginalTownName(char *buf, const char *last, uint32 seed) { char *orig = buf; /* optional first segment */ int i = SeedChanceBias(0, lengthof(_name_original_english_1), seed, 50); if (i >= 0) buf = strecpy(buf, _name_original_english_1[i], last); /* mandatory middle segments */ buf = strecpy(buf, _name_original_english_2[SeedChance(4, lengthof(_name_original_english_2), seed)], last); buf = strecpy(buf, _name_original_english_3[SeedChance(7, lengthof(_name_original_english_3), seed)], last); buf = strecpy(buf, _name_original_english_4[SeedChance(10, lengthof(_name_original_english_4), seed)], last); buf = strecpy(buf, _name_original_english_5[SeedChance(13, lengthof(_name_original_english_5), seed)], last); /* optional last segment */ i = SeedChanceBias(15, lengthof(_name_original_english_6), seed, 60); if (i >= 0) buf = strecpy(buf, _name_original_english_6[i], last); /* Ce, Ci => Ke, Ki */ if (orig[0] == 'C' && (orig[1] == 'e' || orig[1] == 'i')) { orig[0] = 'K'; } assert(buf - orig >= 4); ReplaceEnglishWords(orig, true); return buf; } /** * Generates English (Additional) town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeEnglishAdditionalTownName(char *buf, const char *last, uint32 seed) { char *orig = buf; /* optional first segment */ int i = SeedChanceBias(0, lengthof(_name_additional_english_prefix), seed, 50); if (i >= 0) buf = strecpy(buf, _name_additional_english_prefix[i], last); if (SeedChance(3, 20, seed) >= 14) { buf = strecpy(buf, _name_additional_english_1a[SeedChance(6, lengthof(_name_additional_english_1a), seed)], last); } else { buf = strecpy(buf, _name_additional_english_1b1[SeedChance(6, lengthof(_name_additional_english_1b1), seed)], last); buf = strecpy(buf, _name_additional_english_1b2[SeedChance(9, lengthof(_name_additional_english_1b2), seed)], last); if (SeedChance(11, 20, seed) >= 4) { buf = strecpy(buf, _name_additional_english_1b3a[SeedChance(12, lengthof(_name_additional_english_1b3a), seed)], last); } else { buf = strecpy(buf, _name_additional_english_1b3b[SeedChance(12, lengthof(_name_additional_english_1b3b), seed)], last); } } buf = strecpy(buf, _name_additional_english_2[SeedChance(14, lengthof(_name_additional_english_2), seed)], last); /* optional last segment */ i = SeedChanceBias(15, lengthof(_name_additional_english_3), seed, 60); if (i >= 0) buf = strecpy(buf, _name_additional_english_3[i], last); assert(buf - orig >= 4); ReplaceEnglishWords(orig, false); return buf; } /** * Generates Austrian town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeAustrianTownName(char *buf, const char *last, uint32 seed) { /* Bad, Maria, Gross, ... */ int i = SeedChanceBias(0, lengthof(_name_austrian_a1), seed, 15); if (i >= 0) buf = strecpy(buf, _name_austrian_a1[i], last); int j = 0; i = SeedChance(4, 6, seed); if (i >= 4) { /* Kaisers-kirchen */ buf = strecpy(buf, _name_austrian_a2[SeedChance( 7, lengthof(_name_austrian_a2), seed)], last); buf = strecpy(buf, _name_austrian_a3[SeedChance(13, lengthof(_name_austrian_a3), seed)], last); } else if (i >= 2) { /* St. Johann */ buf = strecpy(buf, _name_austrian_a5[SeedChance( 7, lengthof(_name_austrian_a5), seed)], last); buf = strecpy(buf, _name_austrian_a6[SeedChance( 9, lengthof(_name_austrian_a6), seed)], last); j = 1; // More likely to have a " an der " or " am " } else { /* Zell */ buf = strecpy(buf, _name_austrian_a4[SeedChance( 7, lengthof(_name_austrian_a4), seed)], last); } i = SeedChance(1, 6, seed); if (i >= 4 - j) { /* an der Donau (rivers) */ buf = strecpy(buf, _name_austrian_f1[SeedChance(4, lengthof(_name_austrian_f1), seed)], last); buf = strecpy(buf, _name_austrian_f2[SeedChance(5, lengthof(_name_austrian_f2), seed)], last); } else if (i >= 2 - j) { /* am Dachstein (mountains) */ buf = strecpy(buf, _name_austrian_b1[SeedChance(4, lengthof(_name_austrian_b1), seed)], last); buf = strecpy(buf, _name_austrian_b2[SeedChance(5, lengthof(_name_austrian_b2), seed)], last); } return buf; } /** * Generates German town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeGermanTownName(char *buf, const char *last, uint32 seed) { uint seed_derivative = SeedChance(7, 28, seed); /* optional prefix */ if (seed_derivative == 12 || seed_derivative == 19) { uint i = SeedChance(2, lengthof(_name_german_pre), seed); buf = strecpy(buf, _name_german_pre[i], last); } /* mandatory middle segments including option of hardcoded name */ uint i = SeedChance(3, lengthof(_name_german_real) + lengthof(_name_german_1), seed); if (i < lengthof(_name_german_real)) { buf = strecpy(buf, _name_german_real[i], last); } else { buf = strecpy(buf, _name_german_1[i - lengthof(_name_german_real)], last); i = SeedChance(5, lengthof(_name_german_2), seed); buf = strecpy(buf, _name_german_2[i], last); } /* optional suffix */ if (seed_derivative == 24) { i = SeedChance(9, lengthof(_name_german_4_an_der) + lengthof(_name_german_4_am), seed); if (i < lengthof(_name_german_4_an_der)) { buf = strecpy(buf, _name_german_3_an_der[0], last); buf = strecpy(buf, _name_german_4_an_der[i], last); } else { buf = strecpy(buf, _name_german_3_am[0], last); buf = strecpy(buf, _name_german_4_am[i - lengthof(_name_german_4_an_der)], last); } } return buf; } /** * Generates Latin-American town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeSpanishTownName(char *buf, const char *last, uint32 seed) { return strecpy(buf, _name_spanish_real[SeedChance(0, lengthof(_name_spanish_real), seed)], last); } /** * Generates French town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeFrenchTownName(char *buf, const char *last, uint32 seed) { return strecpy(buf, _name_french_real[SeedChance(0, lengthof(_name_french_real), seed)], last); } /** * Generates Silly town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeSillyTownName(char *buf, const char *last, uint32 seed) { buf = strecpy(buf, _name_silly_1[SeedChance( 0, lengthof(_name_silly_1), seed)], last); buf = strecpy(buf, _name_silly_2[SeedChance(16, lengthof(_name_silly_2), seed)], last); return buf; } /** * Generates Swedish town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeSwedishTownName(char *buf, const char *last, uint32 seed) { /* optional first segment */ int i = SeedChanceBias(0, lengthof(_name_swedish_1), seed, 50); if (i >= 0) buf = strecpy(buf, _name_swedish_1[i], last); /* mandatory middle segments including option of hardcoded name */ if (SeedChance(4, 5, seed) >= 3) { buf = strecpy(buf, _name_swedish_2[SeedChance( 7, lengthof(_name_swedish_2), seed)], last); } else { buf = strecpy(buf, _name_swedish_2a[SeedChance( 7, lengthof(_name_swedish_2a), seed)], last); buf = strecpy(buf, _name_swedish_2b[SeedChance(10, lengthof(_name_swedish_2b), seed)], last); buf = strecpy(buf, _name_swedish_2c[SeedChance(13, lengthof(_name_swedish_2c), seed)], last); } buf = strecpy(buf, _name_swedish_3[SeedChance(16, lengthof(_name_swedish_3), seed)], last); return buf; } /** * Generates Dutch town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeDutchTownName(char *buf, const char *last, uint32 seed) { /* optional first segment */ int i = SeedChanceBias(0, lengthof(_name_dutch_1), seed, 50); if (i >= 0) buf = strecpy(buf, _name_dutch_1[i], last); /* mandatory middle segments including option of hardcoded name */ if (SeedChance(6, 9, seed) > 4) { buf = strecpy(buf, _name_dutch_2[SeedChance( 9, lengthof(_name_dutch_2), seed)], last); } else { buf = strecpy(buf, _name_dutch_3[SeedChance( 9, lengthof(_name_dutch_3), seed)], last); buf = strecpy(buf, _name_dutch_4[SeedChance(12, lengthof(_name_dutch_4), seed)], last); } buf = strecpy(buf, _name_dutch_5[SeedChance(15, lengthof(_name_dutch_5), seed)], last); return buf; } /** * Generates Finnish town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeFinnishTownName(char *buf, const char *last, uint32 seed) { char *orig = buf; /* Select randomly if town name should consists of one or two parts. */ if (SeedChance(0, 15, seed) >= 10) { return strecpy(buf, _name_finnish_real[SeedChance(2, lengthof(_name_finnish_real), seed)], last); } if (SeedChance(0, 15, seed) >= 5) { /* A two-part name by combining one of _name_finnish_1 + "la"/"lä" * The reason for not having the contents of _name_finnish_{1,2} in the same table is * that the ones in _name_finnish_2 are not good for this purpose. */ uint sel = SeedChance( 0, lengthof(_name_finnish_1), seed); buf = strecpy(buf, _name_finnish_1[sel], last); char *end = buf - 1; assert(end >= orig); if (*end == 'i') *end = 'e'; if (strstr(orig, "a") != NULL || strstr(orig, "o") != NULL || strstr(orig, "u") != NULL || strstr(orig, "A") != NULL || strstr(orig, "O") != NULL || strstr(orig, "U") != NULL) { buf = strecpy(buf, "la", last); } else { buf = strecpy(buf, "l\xC3\xA4", last); } return buf; } /* A two-part name by combining one of _name_finnish_{1,2} + _name_finnish_3. * Why aren't _name_finnish_{1,2} just one table? See above. */ uint sel = SeedChance(2, lengthof(_name_finnish_1) + lengthof(_name_finnish_2), seed); if (sel >= lengthof(_name_finnish_1)) { buf = strecpy(buf, _name_finnish_2[sel - lengthof(_name_finnish_1)], last); } else { buf = strecpy(buf, _name_finnish_1[sel], last); } buf = strecpy(buf, _name_finnish_3[SeedChance(10, lengthof(_name_finnish_3), seed)], last); return buf; } /** * Generates Polish town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakePolishTownName(char *buf, const char *last, uint32 seed) { /* optional first segment */ uint i = SeedChance(0, lengthof(_name_polish_2_o) + lengthof(_name_polish_2_m) + lengthof(_name_polish_2_f) + lengthof(_name_polish_2_n), seed); uint j = SeedChance(2, 20, seed); if (i < lengthof(_name_polish_2_o)) { return strecpy(buf, _name_polish_2_o[SeedChance(3, lengthof(_name_polish_2_o), seed)], last); } if (i < lengthof(_name_polish_2_m) + lengthof(_name_polish_2_o)) { if (j < 4) { buf = strecpy(buf, _name_polish_1_m[SeedChance(5, lengthof(_name_polish_1_m), seed)], last); } buf = strecpy(buf, _name_polish_2_m[SeedChance(7, lengthof(_name_polish_2_m), seed)], last); if (j >= 4 && j < 16) { buf = strecpy(buf, _name_polish_3_m[SeedChance(10, lengthof(_name_polish_3_m), seed)], last); } return buf; } if (i < lengthof(_name_polish_2_f) + lengthof(_name_polish_2_m) + lengthof(_name_polish_2_o)) { if (j < 4) { buf = strecpy(buf, _name_polish_1_f[SeedChance(5, lengthof(_name_polish_1_f), seed)], last); } buf = strecpy(buf, _name_polish_2_f[SeedChance(7, lengthof(_name_polish_2_f), seed)], last); if (j >= 4 && j < 16) { buf = strecpy(buf, _name_polish_3_f[SeedChance(10, lengthof(_name_polish_3_f), seed)], last); } return buf; } if (j < 4) { buf = strecpy(buf, _name_polish_1_n[SeedChance(5, lengthof(_name_polish_1_n), seed)], last); } buf = strecpy(buf, _name_polish_2_n[SeedChance(7, lengthof(_name_polish_2_n), seed)], last); if (j >= 4 && j < 16) { buf = strecpy(buf, _name_polish_3_n[SeedChance(10, lengthof(_name_polish_3_n), seed)], last); } return buf; } /** * Generates Czech town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeCzechTownName(char *buf, const char *last, uint32 seed) { /* 1:3 chance to use a real name. */ if (SeedModChance(0, 4, seed) == 0) { return strecpy(buf, _name_czech_real[SeedModChance(4, lengthof(_name_czech_real), seed)], last); } const char *orig = buf; /* Probability of prefixes/suffixes * 0..11 prefix, 12..13 prefix+suffix, 14..17 suffix, 18..31 nothing */ int prob_tails = SeedModChance(2, 32, seed); bool do_prefix = prob_tails < 12; bool do_suffix = prob_tails > 11 && prob_tails < 17; bool dynamic_subst; /* IDs of the respective parts */ int prefix = 0, ending = 0, suffix = 0; uint postfix = 0; uint stem; /* The select criteria. */ CzechGender gender; CzechChoose choose; CzechAllow allow; if (do_prefix) prefix = SeedModChance(5, lengthof(_name_czech_adj) * 12, seed) / 12; if (do_suffix) suffix = SeedModChance(7, lengthof(_name_czech_suffix), seed); /* 3:1 chance 3:1 to use dynamic substantive */ stem = SeedModChance(9, lengthof(_name_czech_subst_full) + 3 * lengthof(_name_czech_subst_stem), seed); if (stem < lengthof(_name_czech_subst_full)) { /* That was easy! */ dynamic_subst = false; gender = _name_czech_subst_full[stem].gender; choose = _name_czech_subst_full[stem].choose; allow = _name_czech_subst_full[stem].allow; } else { uint map[lengthof(_name_czech_subst_ending)]; int ending_start = -1, ending_stop = -1; /* Load the substantive */ dynamic_subst = true; stem -= lengthof(_name_czech_subst_full); stem %= lengthof(_name_czech_subst_stem); gender = _name_czech_subst_stem[stem].gender; choose = _name_czech_subst_stem[stem].choose; allow = _name_czech_subst_stem[stem].allow; /* Load the postfix (1:1 chance that a postfix will be inserted) */ postfix = SeedModChance(14, lengthof(_name_czech_subst_postfix) * 2, seed); if (choose & CZC_POSTFIX) { /* Always get a real postfix. */ postfix %= lengthof(_name_czech_subst_postfix); } if (choose & CZC_NOPOSTFIX) { /* Always drop a postfix. */ postfix += lengthof(_name_czech_subst_postfix); } if (postfix < lengthof(_name_czech_subst_postfix)) { choose |= CZC_POSTFIX; } else { choose |= CZC_NOPOSTFIX; } /* Localize the array segment containing a good gender */ for (ending = 0; ending < (int)lengthof(_name_czech_subst_ending); ending++) { const CzechNameSubst *e = &_name_czech_subst_ending[ending]; if (gender == CZG_FREE || (gender == CZG_NFREE && e->gender != CZG_SNEUT && e->gender != CZG_PNEUT) || gender == e->gender) { if (ending_start < 0) { ending_start = ending; } } else if (ending_start >= 0) { ending_stop = ending - 1; break; } } if (ending_stop < 0) { /* Whoa. All the endings matched. */ ending_stop = ending - 1; } /* Make a sequential map of the items with good mask */ size_t i = 0; for (ending = ending_start; ending <= ending_stop; ending++) { const CzechNameSubst *e = &_name_czech_subst_ending[ending]; if ((e->choose & choose) == choose && (e->allow & allow) != 0) { map[i++] = ending; } } assert(i > 0); /* Load the ending */ ending = map[SeedModChance(16, (int)i, seed)]; /* Override possible CZG_*FREE; this must be a real gender, * otherwise we get overflow when modifying the adjectivum. */ gender = _name_czech_subst_ending[ending].gender; assert(gender != CZG_FREE && gender != CZG_NFREE); } if (do_prefix && (_name_czech_adj[prefix].choose & choose) != choose) { /* Throw away non-matching prefix. */ do_prefix = false; } /* Now finally construct the name */ if (do_prefix) { CzechPattern pattern = _name_czech_adj[prefix].pattern; buf = strecpy(buf, _name_czech_adj[prefix].name, last); char *endpos = buf - 1; /* Find the first character in a UTF-8 sequence */ while (GB(*endpos, 6, 2) == 2) endpos--; if (gender == CZG_SMASC && pattern == CZP_PRIVL) { assert(endpos >= orig + 2); /* -ovX -> -uv */ *(endpos - 2) = 'u'; assert(*(endpos - 1) == 'v'); *endpos = '\0'; } else { assert(endpos >= orig); endpos = strecpy(endpos, _name_czech_patmod[gender][pattern], last); } buf = strecpy(endpos, " ", last); } if (dynamic_subst) { buf = strecpy(buf, _name_czech_subst_stem[stem].name, last); if (postfix < lengthof(_name_czech_subst_postfix)) { const char *poststr = _name_czech_subst_postfix[postfix]; const char *endstr = _name_czech_subst_ending[ending].name; size_t postlen = strlen(poststr); size_t endlen = strlen(endstr); assert(postlen > 0 && endlen > 0); /* Kill the "avava" and "Jananna"-like cases */ if (postlen < 2 || postlen > endlen || ((poststr[1] != 'v' || poststr[1] != endstr[1]) && poststr[2] != endstr[1])) { buf = strecpy(buf, poststr, last); /* k-i -> c-i, h-i -> z-i */ if (endstr[0] == 'i') { switch (*(buf - 1)) { case 'k': *(buf - 1) = 'c'; break; case 'h': *(buf - 1) = 'z'; break; default: break; } } } } buf = strecpy(buf, _name_czech_subst_ending[ending].name, last); } else { buf = strecpy(buf, _name_czech_subst_full[stem].name, last); } if (do_suffix) { buf = strecpy(buf, " ", last); buf = strecpy(buf, _name_czech_suffix[suffix], last); } return buf; } /** * Generates Romanian town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeRomanianTownName(char *buf, const char *last, uint32 seed) { return strecpy(buf, _name_romanian_real[SeedChance(0, lengthof(_name_romanian_real), seed)], last); } /** * Generates Slovak town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeSlovakTownName(char *buf, const char *last, uint32 seed) { return strecpy(buf, _name_slovak_real[SeedChance(0, lengthof(_name_slovak_real), seed)], last); } /** * Generates Norwegian town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeNorwegianTownName(char *buf, const char *last, uint32 seed) { /* Use first 4 bit from seed to decide whether or not this town should * have a real name 3/16 chance. Bit 0-3 */ if (SeedChance(0, 15, seed) < 3) { /* Use 7bit for the realname table index. Bit 4-10 */ return strecpy(buf, _name_norwegian_real[SeedChance(4, lengthof(_name_norwegian_real), seed)], last); } /* Use 7bit for the first fake part. Bit 4-10 */ buf = strecpy(buf, _name_norwegian_1[SeedChance(4, lengthof(_name_norwegian_1), seed)], last); /* Use 7bit for the last fake part. Bit 11-17 */ buf = strecpy(buf, _name_norwegian_2[SeedChance(11, lengthof(_name_norwegian_2), seed)], last); return buf; } /** * Generates Hungarian town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeHungarianTownName(char *buf, const char *last, uint32 seed) { if (SeedChance(12, 15, seed) < 3) { return strecpy(buf, _name_hungarian_real[SeedChance(0, lengthof(_name_hungarian_real), seed)], last); } /* optional first segment */ uint i = SeedChance(3, lengthof(_name_hungarian_1) * 3, seed); if (i < lengthof(_name_hungarian_1)) buf = strecpy(buf, _name_hungarian_1[i], last); /* mandatory middle segments */ buf = strecpy(buf, _name_hungarian_2[SeedChance(3, lengthof(_name_hungarian_2), seed)], last); buf = strecpy(buf, _name_hungarian_3[SeedChance(6, lengthof(_name_hungarian_3), seed)], last); /* optional last segment */ i = SeedChance(10, lengthof(_name_hungarian_4) * 3, seed); if (i < lengthof(_name_hungarian_4)) { buf = strecpy(buf, _name_hungarian_4[i], last); } return buf; } /** * Generates Swiss town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeSwissTownName(char *buf, const char *last, uint32 seed) { return strecpy(buf, _name_swiss_real[SeedChance(0, lengthof(_name_swiss_real), seed)], last); } /** * Generates Danish town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeDanishTownName(char *buf, const char *last, uint32 seed) { /* optional first segment */ int i = SeedChanceBias(0, lengthof(_name_danish_1), seed, 50); if (i >= 0) buf = strecpy(buf, _name_danish_1[i], last); /* middle segments removed as this algorithm seems to create much more realistic names */ buf = strecpy(buf, _name_danish_2[SeedChance( 7, lengthof(_name_danish_2), seed)], last); buf = strecpy(buf, _name_danish_3[SeedChance(16, lengthof(_name_danish_3), seed)], last); return buf; } /** * Generates Turkish town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeTurkishTownName(char *buf, const char *last, uint32 seed) { uint i = SeedModChance(0, 5, seed); switch (i) { case 0: buf = strecpy(buf, _name_turkish_prefix[SeedModChance( 2, lengthof(_name_turkish_prefix), seed)], last); /* middle segment */ buf = strecpy(buf, _name_turkish_middle[SeedModChance( 4, lengthof(_name_turkish_middle), seed)], last); /* optional suffix */ if (SeedModChance(0, 7, seed) == 0) { buf = strecpy(buf, _name_turkish_suffix[SeedModChance( 10, lengthof(_name_turkish_suffix), seed)], last); } break; case 1: case 2: buf = strecpy(buf, _name_turkish_prefix[SeedModChance( 2, lengthof(_name_turkish_prefix), seed)], last); buf = strecpy(buf, _name_turkish_suffix[SeedModChance( 4, lengthof(_name_turkish_suffix), seed)], last); break; default: buf = strecpy(buf, _name_turkish_real[SeedModChance( 4, lengthof(_name_turkish_real), seed)], last); break; } return buf; } /** * Generates Italian town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeItalianTownName(char *buf, const char *last, uint32 seed) { if (SeedModChance(0, 6, seed) == 0) { // real city names return strecpy(buf, _name_italian_real[SeedModChance(4, lengthof(_name_italian_real), seed)], last); } static const char * const mascul_femin_italian[] = { "o", "a", }; if (SeedModChance(0, 8, seed) == 0) { // prefix buf = strecpy(buf, _name_italian_pref[SeedModChance(11, lengthof(_name_italian_pref), seed)], last); } uint i = SeedChance(0, 2, seed); if (i == 0) { // masculine form buf = strecpy(buf, _name_italian_1m[SeedModChance(4, lengthof(_name_italian_1m), seed)], last); } else { // feminine form buf = strecpy(buf, _name_italian_1f[SeedModChance(4, lengthof(_name_italian_1f), seed)], last); } if (SeedModChance(3, 3, seed) == 0) { buf = strecpy(buf, _name_italian_2[SeedModChance(11, lengthof(_name_italian_2), seed)], last); buf = strecpy(buf, mascul_femin_italian[i], last); } else { buf = strecpy(buf, _name_italian_2i[SeedModChance(16, lengthof(_name_italian_2i), seed)], last); } if (SeedModChance(15, 4, seed) == 0) { if (SeedModChance(5, 2, seed) == 0) { // generic suffix buf = strecpy(buf, _name_italian_3[SeedModChance(4, lengthof(_name_italian_3), seed)], last); } else { // river name suffix buf = strecpy(buf, _name_italian_river1[SeedModChance(4, lengthof(_name_italian_river1), seed)], last); buf = strecpy(buf, _name_italian_river2[SeedModChance(16, lengthof(_name_italian_river2), seed)], last); } } return buf; } /** * Generates Catalan town name from given seed. * @param buf output buffer * @param seed town name seed * @param last end of buffer */ static char *MakeCatalanTownName(char *buf, const char *last, uint32 seed) { if (SeedModChance(0, 3, seed) == 0) { // real city names return strecpy(buf, _name_catalan_real[SeedModChance(4, lengthof(_name_catalan_real), seed)], last); } if (SeedModChance(0, 2, seed) == 0) { // prefix buf = strecpy(buf, _name_catalan_pref[SeedModChance(11, lengthof(_name_catalan_pref), seed)], last); } uint i = SeedChance(0, 2, seed); if (i == 0) { // masculine form buf = strecpy(buf, _name_catalan_1m[SeedModChance(4, lengthof(_name_catalan_1m), seed)], last); buf = strecpy(buf, _name_catalan_2m[SeedModChance(11, lengthof(_name_catalan_2m), seed)], last); } else { // feminine form buf = strecpy(buf, _name_catalan_1f[SeedModChance(4, lengthof(_name_catalan_1f), seed)], last); buf = strecpy(buf, _name_catalan_2f[SeedModChance(11, lengthof(_name_catalan_2f), seed)], last); } if (SeedModChance(15, 5, seed) == 0) { if (SeedModChance(5, 2, seed) == 0) { // generic suffix buf = strecpy(buf, _name_catalan_3[SeedModChance(4, lengthof(_name_catalan_3), seed)], last); } else { // river name suffix buf = strecpy(buf, _name_catalan_river1[SeedModChance(4, lengthof(_name_catalan_river1), seed)], last); } } return buf; } /** * Type for all town name generator functions. * @param buf The buffer to write the name to. * @param last The last element of the buffer. * @param seed The seed of the town name. * @return The end of the filled buffer. */ typedef char *TownNameGenerator(char *buf, const char *last, uint32 seed); /** Contains pointer to generator and minimum buffer size (not incl. terminating '\0') */ struct TownNameGeneratorParams { byte min; ///< minimum number of characters that need to be printed for generator to work correctly TownNameGenerator *proc; ///< generator itself }; /** Town name generators */ static const TownNameGeneratorParams _town_name_generators[] = { { 4, MakeEnglishOriginalTownName}, // replaces first 4 characters of name { 0, MakeFrenchTownName}, { 0, MakeGermanTownName}, { 4, MakeEnglishAdditionalTownName}, // replaces first 4 characters of name { 0, MakeSpanishTownName}, { 0, MakeSillyTownName}, { 0, MakeSwedishTownName}, { 0, MakeDutchTownName}, { 8, MakeFinnishTownName}, // _name_finnish_1 { 0, MakePolishTownName}, { 0, MakeSlovakTownName}, { 0, MakeNorwegianTownName}, { 0, MakeHungarianTownName}, { 0, MakeAustrianTownName}, { 0, MakeRomanianTownName}, { 28, MakeCzechTownName}, // _name_czech_adj + _name_czech_patmod + 1 + _name_czech_subst_stem + _name_czech_subst_postfix { 0, MakeSwissTownName}, { 0, MakeDanishTownName}, { 0, MakeTurkishTownName}, { 0, MakeItalianTownName}, { 0, MakeCatalanTownName}, }; /** * Generates town name from given seed. a language. * @param buf output buffer * @param last end of buffer * @param lang town name language * @param seed generation seed * @return last character ('/0') */ char *GenerateTownNameString(char *buf, const char *last, size_t lang, uint32 seed) { assert(lang < lengthof(_town_name_generators)); /* Some generators need at least 9 bytes in buffer. English generators need 5 for * string replacing, others use constructions like strlen(buf)-3 and so on. * Finnish generator needs to fit all strings from _name_finnish_1. * Czech generator needs to fit almost whole town name... * These would break. Using another temporary buffer results in ~40% slower code, * so use it only when really needed. */ const TownNameGeneratorParams *par = &_town_name_generators[lang]; if (last >= buf + par->min) return par->proc(buf, last, seed); char *buffer = AllocaM(char, par->min + 1); par->proc(buffer, buffer + par->min, seed); return strecpy(buf, buffer, last); } openttd-1.5.3/src/osk_gui.cpp0000644000000000000000000003435412627373435014653 0ustar rootroot/* $Id: osk_gui.cpp 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 osk_gui.cpp The On Screen Keyboard GUI */ #include "stdafx.h" #include "string_func.h" #include "strings_func.h" #include "debug.h" #include "window_func.h" #include "gfx_func.h" #include "querystring_gui.h" #include "video/video_driver.hpp" #include "widgets/osk_widget.h" #include "table/sprites.h" #include "table/strings.h" #include "safeguards.h" char _keyboard_opt[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; static WChar _keyboard[2][OSK_KEYBOARD_ENTRIES]; enum KeyStateBits { KEYS_NONE, KEYS_SHIFT, KEYS_CAPS }; static byte _keystate = KEYS_NONE; struct OskWindow : public Window { StringID caption; ///< the caption for this window. QueryString *qs; ///< text-input int text_btn; ///< widget number of parent's text field Textbuf *text; ///< pointer to parent's textbuffer (to update caret position) char *orig_str_buf; ///< Original string. bool shift; ///< Is the shift effectively pressed? OskWindow(WindowDesc *desc, Window *parent, int button) : Window(desc) { this->parent = parent; assert(parent != NULL); NWidgetCore *par_wid = parent->GetWidget(button); assert(par_wid != NULL); assert(parent->querystrings.Contains(button)); this->qs = parent->querystrings.Find(button)->second; this->caption = (par_wid->widget_data != STR_NULL) ? par_wid->widget_data : this->qs->caption; this->text_btn = button; this->text = &this->qs->text; this->querystrings[WID_OSK_TEXT] = this->qs; /* make a copy in case we need to reset later */ this->orig_str_buf = stredup(this->qs->text.buf); this->InitNested(0); this->SetFocusedWidget(WID_OSK_TEXT); /* Not needed by default. */ this->DisableWidget(WID_OSK_SPECIAL); this->UpdateOskState(); } ~OskWindow() { free(this->orig_str_buf); } /** * Only show valid characters; do not show characters that would * only insert a space when we have a spacebar to do that or * characters that are not allowed to be entered. */ void UpdateOskState() { this->shift = HasBit(_keystate, KEYS_CAPS) ^ HasBit(_keystate, KEYS_SHIFT); for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) { this->SetWidgetDisabledState(WID_OSK_LETTERS + i, !IsValidChar(_keyboard[this->shift][i], this->qs->text.afilter) || _keyboard[this->shift][i] == ' '); } this->SetWidgetDisabledState(WID_OSK_SPACE, !IsValidChar(' ', this->qs->text.afilter)); this->SetWidgetLoweredState(WID_OSK_SHIFT, HasBit(_keystate, KEYS_SHIFT)); this->SetWidgetLoweredState(WID_OSK_CAPS, HasBit(_keystate, KEYS_CAPS)); } virtual void SetStringParameters(int widget) const { if (widget == WID_OSK_CAPTION) SetDParam(0, this->caption); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget < WID_OSK_LETTERS) return; widget -= WID_OSK_LETTERS; DrawCharCentered(_keyboard[this->shift][widget], r.left + 8, r.top + 3, TC_BLACK); } virtual void OnClick(Point pt, int widget, int click_count) { /* clicked a letter */ if (widget >= WID_OSK_LETTERS) { WChar c = _keyboard[this->shift][widget - WID_OSK_LETTERS]; if (!IsValidChar(c, this->qs->text.afilter)) return; if (this->qs->text.InsertChar(c)) this->OnEditboxChanged(WID_OSK_TEXT); if (HasBit(_keystate, KEYS_SHIFT)) { ToggleBit(_keystate, KEYS_SHIFT); this->UpdateOskState(); this->SetDirty(); } return; } switch (widget) { case WID_OSK_BACKSPACE: if (this->qs->text.DeleteChar(WKC_BACKSPACE)) this->OnEditboxChanged(WID_OSK_TEXT); break; case WID_OSK_SPECIAL: /* * Anything device specific can go here. * The button itself is hidden by default, and when you need it you * can not hide it in the create event. */ break; case WID_OSK_CAPS: ToggleBit(_keystate, KEYS_CAPS); this->UpdateOskState(); this->SetDirty(); break; case WID_OSK_SHIFT: ToggleBit(_keystate, KEYS_SHIFT); this->UpdateOskState(); this->SetDirty(); break; case WID_OSK_SPACE: if (this->qs->text.InsertChar(' ')) this->OnEditboxChanged(WID_OSK_TEXT); break; case WID_OSK_LEFT: if (this->qs->text.MovePos(WKC_LEFT)) this->InvalidateData(); break; case WID_OSK_RIGHT: if (this->qs->text.MovePos(WKC_RIGHT)) this->InvalidateData(); break; case WID_OSK_OK: if (this->qs->orig == NULL || strcmp(this->qs->text.buf, this->qs->orig) != 0) { /* pass information by simulating a button press on parent window */ if (this->qs->ok_button >= 0) { this->parent->OnClick(pt, this->qs->ok_button, 1); /* Window gets deleted when the parent window removes itself. */ return; } } delete this; break; case WID_OSK_CANCEL: if (this->qs->cancel_button >= 0) { // pass a cancel event to the parent window this->parent->OnClick(pt, this->qs->cancel_button, 1); /* Window gets deleted when the parent window removes itself. */ return; } else { // or reset to original string qs->text.Assign(this->orig_str_buf); qs->text.MovePos(WKC_END); this->OnEditboxChanged(WID_OSK_TEXT); delete this; } break; } } virtual void OnEditboxChanged(int widget) { this->SetWidgetDirty(WID_OSK_TEXT); this->parent->OnEditboxChanged(this->text_btn); this->parent->SetWidgetDirty(this->text_btn); } virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (!gui_scope) return; this->SetWidgetDirty(WID_OSK_TEXT); this->parent->SetWidgetDirty(this->text_btn); } virtual void OnFocusLost() { VideoDriver::GetInstance()->EditBoxLostFocus(); delete this; } }; static const int HALF_KEY_WIDTH = 7; // Width of 1/2 key in pixels. static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. /** * Add a key widget to a row of the keyboard. * @param hor Row container to add key widget to. * @param height Height of the key (all keys in a row should have equal height). * @param num_half Number of 1/2 key widths that this key has. * @param widtype Widget type of the key. Must be either \c NWID_SPACER for an invisible key, or a \c WWT_* widget. * @param widnum Widget number of the key. * @param widdata Data value of the key widget. * @param biggest_index Collected biggest widget index so far. * @note Key width is measured in 1/2 keys to allow for 1/2 key shifting between rows. */ static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) { int key_width = HALF_KEY_WIDTH + (INTER_KEY_SPACE + HALF_KEY_WIDTH) * (num_half - 1); if (widtype == NWID_SPACER) { if (!hor->IsEmpty()) key_width += INTER_KEY_SPACE; NWidgetSpacer *spc = new NWidgetSpacer(key_width, height); hor->Add(spc); } else { if (!hor->IsEmpty()) { NWidgetSpacer *spc = new NWidgetSpacer(INTER_KEY_SPACE, height); hor->Add(spc); } NWidgetLeaf *leaf = new NWidgetLeaf(widtype, COLOUR_GREY, widnum, widdata, STR_NULL); leaf->SetMinimalSize(key_width, height); hor->Add(leaf); } *biggest_index = max(*biggest_index, widnum); } /** Construct the top row keys (cancel, ok, backspace). */ static NWidgetBase *MakeTopKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontal(); int key_height = FONT_HEIGHT_NORMAL + 2; AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL, biggest_index); AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK, biggest_index); AddKey(hor, key_height, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE, biggest_index); return hor; } /** Construct the row containing the digit keys. */ static NWidgetBase *MakeNumberKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); int key_height = FONT_HEIGHT_NORMAL + 6; for (int widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) { AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } return hor; } /** Construct the qwerty row keys. */ static NWidgetBase *MakeQwertyKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); int key_height = FONT_HEIGHT_NORMAL + 6; AddKey(hor, key_height, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL, biggest_index); for (int widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) { AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); return hor; } /** Construct the asdfg row keys. */ static NWidgetBase *MakeAsdfgKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); int key_height = FONT_HEIGHT_NORMAL + 6; AddKey(hor, key_height, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS, biggest_index); for (int widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) { AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } return hor; } /** Construct the zxcvb row keys. */ static NWidgetBase *MakeZxcvbKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); int key_height = FONT_HEIGHT_NORMAL + 6; AddKey(hor, key_height, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT, biggest_index); for (int widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) { AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); return hor; } /** Construct the spacebar row keys. */ static NWidgetBase *MakeSpacebarKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontal(); int key_height = FONT_HEIGHT_NORMAL + 6; AddKey(hor, key_height, 8, NWID_SPACER, 0, 0, biggest_index); AddKey(hor, key_height, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); AddKey(hor, key_height, 3, NWID_SPACER, 0, 0, biggest_index); AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT, biggest_index); AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT, biggest_index); return hor; } static const NWidgetPart _nested_osk_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY, WID_OSK_CAPTION), SetDataTip(STR_WHITE_STRING, STR_NULL), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_OSK_TEXT), SetMinimalSize(252, 12), SetPadding(2, 2, 2, 2), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), SetPIP(5, 2, 3), NWidgetFunction(MakeTopKeys), SetPadding(0, 3, 0, 3), NWidgetFunction(MakeNumberKeys), SetPadding(0, 3, 0, 3), NWidgetFunction(MakeQwertyKeys), SetPadding(0, 3, 0, 3), NWidgetFunction(MakeAsdfgKeys), SetPadding(0, 3, 0, 3), NWidgetFunction(MakeZxcvbKeys), SetPadding(0, 3, 0, 3), NWidgetFunction(MakeSpacebarKeys), SetPadding(0, 3, 0, 3), EndContainer(), }; static WindowDesc _osk_desc( WDP_CENTER, "query_osk", 0, 0, WC_OSK, WC_NONE, 0, _nested_osk_widgets, lengthof(_nested_osk_widgets) ); /** * Retrieve keyboard layout from language string or (if set) config file. * Also check for invalid characters. */ void GetKeyboardLayout() { char keyboard[2][OSK_KEYBOARD_ENTRIES * 4 + 1]; char errormark[2][OSK_KEYBOARD_ENTRIES + 1]; // used for marking invalid chars bool has_error = false; // true when an invalid char is detected if (StrEmpty(_keyboard_opt[0])) { GetString(keyboard[0], STR_OSK_KEYBOARD_LAYOUT, lastof(keyboard[0])); } else { strecpy(keyboard[0], _keyboard_opt[0], lastof(keyboard[0])); } if (StrEmpty(_keyboard_opt[1])) { GetString(keyboard[1], STR_OSK_KEYBOARD_LAYOUT_CAPS, lastof(keyboard[1])); } else { strecpy(keyboard[1], _keyboard_opt[1], lastof(keyboard[1])); } for (uint j = 0; j < 2; j++) { const char *kbd = keyboard[j]; bool ended = false; for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) { _keyboard[j][i] = Utf8Consume(&kbd); /* Be lenient when the last characters are missing (is quite normal) */ if (_keyboard[j][i] == '\0' || ended) { ended = true; _keyboard[j][i] = ' '; continue; } if (IsPrintable(_keyboard[j][i])) { errormark[j][i] = ' '; } else { has_error = true; errormark[j][i] = '^'; _keyboard[j][i] = ' '; } } } if (has_error) { ShowInfoF("The keyboard layout you selected contains invalid chars. Please check those chars marked with ^."); ShowInfoF("Normal keyboard: %s", keyboard[0]); ShowInfoF(" %s", errormark[0]); ShowInfoF("Caps Lock: %s", keyboard[1]); ShowInfoF(" %s", errormark[1]); } } /** * Show the on-screen keyboard (osk) associated with a given textbox * @param parent pointer to the Window where this keyboard originated from * @param button widget number of parent's textbox */ void ShowOnScreenKeyboard(Window *parent, int button) { DeleteWindowById(WC_OSK, 0); GetKeyboardLayout(); new OskWindow(&_osk_desc, parent, button); } /** * Updates the original text of the OSK so when the 'parent' changes the * original and you press on cancel you won't get the 'old' original text * but the updated one. * @param parent window that just updated its orignal text * @param button widget number of parent's textbox to update */ void UpdateOSKOriginalText(const Window *parent, int button) { OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); if (osk == NULL || osk->parent != parent || osk->text_btn != button) return; free(osk->orig_str_buf); osk->orig_str_buf = stredup(osk->qs->text.buf); osk->SetDirty(); } /** * Check whether the OSK is opened for a specific editbox. * @parent w Window to check for * @param button Editbox of \a w to check for * @return true if the OSK is oppened for \a button. */ bool IsOSKOpenedFor(const Window *w, int button) { OskWindow *osk = dynamic_cast(FindWindowById(WC_OSK, 0)); return osk != NULL && osk->parent == w && osk->text_btn == button; } openttd-1.5.3/src/sprite.cpp0000644000000000000000000001213412627373441014506 0ustar rootroot/* $Id: sprite.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 sprite.cpp Handling of sprites */ #include "stdafx.h" #include "sprite.h" #include "viewport_func.h" #include "landscape.h" #include "spritecache.h" #include "zoom_func.h" #include "safeguards.h" /** * Draws a tile sprite sequence. * @param ti The tile to draw on * @param dts Sprite and subsprites to draw * @param to The transparency bit that toggles drawing of these sprites * @param orig_offset Sprite-Offset for original sprites * @param newgrf_offset Sprite-Offset for NewGRF defined sprites * @param default_palette The default recolour sprite to use (typically company colour) * @param child_offset_is_unsigned Whether child sprite offsets are interpreted signed or unsigned */ void DrawCommonTileSeq(const TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, int32 orig_offset, uint32 newgrf_offset, PaletteID default_palette, bool child_offset_is_unsigned) { bool parent_sprite_encountered = false; const DrawTileSeqStruct *dtss; bool skip_childs = false; foreach_draw_tile_seq(dtss, dts->seq) { SpriteID image = dtss->image.sprite; PaletteID pal = dtss->image.pal; if (skip_childs) { if (!dtss->IsParentSprite()) continue; skip_childs = false; } /* TTD sprite 0 means no sprite */ if ((GB(image, 0, SPRITE_WIDTH) == 0 && !HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) || (IsInvisibilitySet(to) && !HasBit(image, SPRITE_MODIFIER_OPAQUE))) { skip_childs = dtss->IsParentSprite(); continue; } image += (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? newgrf_offset : orig_offset); if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += newgrf_offset; pal = SpriteLayoutPaletteTransform(image, pal, default_palette); if (dtss->IsParentSprite()) { parent_sprite_encountered = true; AddSortableSpriteToDraw( image, pal, ti->x + dtss->delta_x, ti->y + dtss->delta_y, dtss->size_x, dtss->size_y, dtss->size_z, ti->z + dtss->delta_z, !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to) ); } else { int offs_x = child_offset_is_unsigned ? (uint8)dtss->delta_x : dtss->delta_x; int offs_y = child_offset_is_unsigned ? (uint8)dtss->delta_y : dtss->delta_y; bool transparent = !HasBit(image, SPRITE_MODIFIER_OPAQUE) && IsTransparencySet(to); if (parent_sprite_encountered) { AddChildSpriteScreen(image, pal, offs_x, offs_y, transparent); } else { if (transparent) { SetBit(image, PALETTE_MODIFIER_TRANSPARENT); pal = PALETTE_TO_TRANSPARENT; } DrawGroundSprite(image, pal, NULL, offs_x, offs_y); } } } } /** * Draws a tile sprite sequence in the GUI * @param x X position to draw to * @param y Y position to draw to * @param dts Sprite and subsprites to draw * @param orig_offset Sprite-Offset for original sprites * @param newgrf_offset Sprite-Offset for NewGRF defined sprites * @param default_palette The default recolour sprite to use (typically company colour) * @param child_offset_is_unsigned Whether child sprite offsets are interpreted signed or unsigned */ void DrawCommonTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32 orig_offset, uint32 newgrf_offset, PaletteID default_palette, bool child_offset_is_unsigned) { const DrawTileSeqStruct *dtss; Point child_offset = {0, 0}; bool skip_childs = false; foreach_draw_tile_seq(dtss, dts->seq) { SpriteID image = dtss->image.sprite; PaletteID pal = dtss->image.pal; if (skip_childs) { if (!dtss->IsParentSprite()) continue; skip_childs = false; } /* TTD sprite 0 means no sprite */ if (GB(image, 0, SPRITE_WIDTH) == 0 && !HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) { skip_childs = dtss->IsParentSprite(); continue; } image += (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE) ? newgrf_offset : orig_offset); if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += newgrf_offset; pal = SpriteLayoutPaletteTransform(image, pal, default_palette); if (dtss->IsParentSprite()) { Point pt = RemapCoords(dtss->delta_x, dtss->delta_y, dtss->delta_z); DrawSprite(image, pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y)); const Sprite *spr = GetSprite(image & SPRITE_MASK, ST_NORMAL); child_offset.x = UnScaleGUI(pt.x + spr->x_offs); child_offset.y = UnScaleGUI(pt.y + spr->y_offs); } else { int offs_x = child_offset_is_unsigned ? (uint8)dtss->delta_x : dtss->delta_x; int offs_y = child_offset_is_unsigned ? (uint8)dtss->delta_y : dtss->delta_y; DrawSprite(image, pal, x + child_offset.x + ScaleGUITrad(offs_x), y + child_offset.y + ScaleGUITrad(offs_y)); } } } openttd-1.5.3/src/tgp.cpp0000644000000000000000000011460412627373433014000 0ustar rootroot/* $Id: tgp.cpp 27351 2015-07-30 18:53:31Z frosch $ */ /* * 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 tgp.cpp OTTD Perlin Noise Landscape Generator, aka TerraGenesis Perlin */ #include "stdafx.h" #include #include "clear_map.h" #include "void_map.h" #include "genworld.h" #include "core/random_func.hpp" #include "landscape_type.h" #include "safeguards.h" /* * * Quickie guide to Perlin Noise * Perlin noise is a predictable pseudo random number sequence. By generating * it in 2 dimensions, it becomes a useful random map that, for a given seed * and starting X & Y, is entirely predictable. On the face of it, that may not * be useful. However, it means that if you want to replay a map in a different * terrain, or just vary the sea level, you just re-run the generator with the * same seed. The seed is an int32, and is randomised on each run of New Game. * The Scenario Generator does not randomise the value, so that you can * experiment with one terrain until you are happy, or click "Random" for a new * random seed. * * Perlin Noise is a series of "octaves" of random noise added together. By * reducing the amplitude of the noise with each octave, the first octave of * noise defines the main terrain sweep, the next the ripples on that, and the * next the ripples on that. I use 6 octaves, with the amplitude controlled by * a power ratio, usually known as a persistence or p value. This I vary by the * smoothness selection, as can be seen in the table below. The closer to 1, * the more of that octave is added. Each octave is however raised to the power * of its position in the list, so the last entry in the "smooth" row, 0.35, is * raised to the power of 6, so can only add 0.001838... of the amplitude to * the running total. * * In other words; the first p value sets the general shape of the terrain, the * second sets the major variations to that, ... until finally the smallest * bumps are added. * * Usefully, this routine is totally scaleable; so when 32bpp comes along, the * terrain can be as bumpy as you like! It is also infinitely expandable; a * single random seed terrain continues in X & Y as far as you care to * calculate. In theory, we could use just one seed value, but randomly select * where in the Perlin XY space we use for the terrain. Personally I prefer * using a simple (0, 0) to (X, Y), with a varying seed. * * * Other things i have had to do: mountainous wasn't mountainous enough, and * since we only have 0..15 heights available, I add a second generated map * (with a modified seed), onto the original. This generally raises the * terrain, which then needs scaling back down. Overall effect is a general * uplift. * * However, the values on the top of mountains are then almost guaranteed to go * too high, so large flat plateaus appeared at height 15. To counter this, I * scale all heights above 12 to proportion up to 15. It still makes the * mountains have flattish tops, rather than craggy peaks, but at least they * aren't smooth as glass. * * * For a full discussion of Perlin Noise, please visit: * http://freespace.virgin.net/hugo.elias/models/m_perlin.htm * * * Evolution II * * The algorithm as described in the above link suggests to compute each tile height * as composition of several noise waves. Some of them are computed directly by * noise(x, y) function, some are calculated using linear approximation. Our * first implementation of perlin_noise_2D() used 4 noise(x, y) calls plus * 3 linear interpolations. It was called 6 times for each tile. This was a bit * CPU expensive. * * The following implementation uses optimized algorithm that should produce * the same quality result with much less computations, but more memory accesses. * The overall speedup should be 300% to 800% depending on CPU and memory speed. * * I will try to explain it on the example below: * * Have a map of 4 x 4 tiles, our simplified noise generator produces only two * values -1 and +1, use 3 octaves with wave length 1, 2 and 4, with amplitudes * 3, 2, 1. Original algorithm produces: * * h00 = lerp(lerp(-3, 3, 0/4), lerp(3, -3, 0/4), 0/4) + lerp(lerp(-2, 2, 0/2), lerp( 2, -2, 0/2), 0/2) + -1 = lerp(-3.0, 3.0, 0/4) + lerp(-2, 2, 0/2) + -1 = -3.0 + -2 + -1 = -6.0 * h01 = lerp(lerp(-3, 3, 1/4), lerp(3, -3, 1/4), 0/4) + lerp(lerp(-2, 2, 1/2), lerp( 2, -2, 1/2), 0/2) + 1 = lerp(-1.5, 1.5, 0/4) + lerp( 0, 0, 0/2) + 1 = -1.5 + 0 + 1 = -0.5 * h02 = lerp(lerp(-3, 3, 2/4), lerp(3, -3, 2/4), 0/4) + lerp(lerp( 2, -2, 0/2), lerp(-2, 2, 0/2), 0/2) + -1 = lerp( 0, 0, 0/4) + lerp( 2, -2, 0/2) + -1 = 0 + 2 + -1 = 1.0 * h03 = lerp(lerp(-3, 3, 3/4), lerp(3, -3, 3/4), 0/4) + lerp(lerp( 2, -2, 1/2), lerp(-2, 2, 1/2), 0/2) + 1 = lerp( 1.5, -1.5, 0/4) + lerp( 0, 0, 0/2) + 1 = 1.5 + 0 + 1 = 2.5 * * h10 = lerp(lerp(-3, 3, 0/4), lerp(3, -3, 0/4), 1/4) + lerp(lerp(-2, 2, 0/2), lerp( 2, -2, 0/2), 1/2) + 1 = lerp(-3.0, 3.0, 1/4) + lerp(-2, 2, 1/2) + 1 = -1.5 + 0 + 1 = -0.5 * h11 = lerp(lerp(-3, 3, 1/4), lerp(3, -3, 1/4), 1/4) + lerp(lerp(-2, 2, 1/2), lerp( 2, -2, 1/2), 1/2) + -1 = lerp(-1.5, 1.5, 1/4) + lerp( 0, 0, 1/2) + -1 = -0.75 + 0 + -1 = -1.75 * h12 = lerp(lerp(-3, 3, 2/4), lerp(3, -3, 2/4), 1/4) + lerp(lerp( 2, -2, 0/2), lerp(-2, 2, 0/2), 1/2) + 1 = lerp( 0, 0, 1/4) + lerp( 2, -2, 1/2) + 1 = 0 + 0 + 1 = 1.0 * h13 = lerp(lerp(-3, 3, 3/4), lerp(3, -3, 3/4), 1/4) + lerp(lerp( 2, -2, 1/2), lerp(-2, 2, 1/2), 1/2) + -1 = lerp( 1.5, -1.5, 1/4) + lerp( 0, 0, 1/2) + -1 = 0.75 + 0 + -1 = -0.25 * * * Optimization 1: * * 1) we need to allocate a bit more tiles: (size_x + 1) * (size_y + 1) = (5 * 5): * * 2) setup corner values using amplitude 3 * { -3.0 X X X 3.0 } * { X X X X X } * { X X X X X } * { X X X X X } * { 3.0 X X X -3.0 } * * 3a) interpolate values in the middle * { -3.0 X 0.0 X 3.0 } * { X X X X X } * { 0.0 X 0.0 X 0.0 } * { X X X X X } * { 3.0 X 0.0 X -3.0 } * * 3b) add patches with amplitude 2 to them * { -5.0 X 2.0 X 1.0 } * { X X X X X } * { 2.0 X -2.0 X 2.0 } * { X X X X X } * { 1.0 X 2.0 X -5.0 } * * 4a) interpolate values in the middle * { -5.0 -1.5 2.0 1.5 1.0 } * { -1.5 -0.75 0.0 0.75 1.5 } * { 2.0 0.0 -2.0 0.0 2.0 } * { 1.5 0.75 0.0 -0.75 -1.5 } * { 1.0 1.5 2.0 -1.5 -5.0 } * * 4b) add patches with amplitude 1 to them * { -6.0 -0.5 1.0 2.5 0.0 } * { -0.5 -1.75 1.0 -0.25 2.5 } * { 1.0 1.0 -3.0 1.0 1.0 } * { 2.5 -0.25 1.0 -1.75 -0.5 } * { 0.0 2.5 1.0 -0.5 -6.0 } * * * * Optimization 2: * * As you can see above, each noise function was called just once. Therefore * we don't need to use noise function that calculates the noise from x, y and * some prime. The same quality result we can obtain using standard Random() * function instead. * */ /** Fixed point type for heights */ typedef int16 height_t; static const int height_decimal_bits = 4; static const height_t _invalid_height = -32768; /** Fixed point array for amplitudes (and percent values) */ typedef int amplitude_t; static const int amplitude_decimal_bits = 10; /** Height map - allocated array of heights (MapSizeX() + 1) x (MapSizeY() + 1) */ struct HeightMap { height_t *h; //< array of heights /* Even though the sizes are always positive, there are many cases where * X and Y need to be signed integers due to subtractions. */ int dim_x; //< height map size_x MapSizeX() + 1 int total_size; //< height map total size int size_x; //< MapSizeX() int size_y; //< MapSizeY() /** * Height map accessor * @param x X position * @param y Y position * @return height as fixed point number */ inline height_t &height(uint x, uint y) { return h[x + y * dim_x]; } }; /** Global height map instance */ static HeightMap _height_map = {NULL, 0, 0, 0, 0}; /** Conversion: int to height_t */ #define I2H(i) ((i) << height_decimal_bits) /** Conversion: height_t to int */ #define H2I(i) ((i) >> height_decimal_bits) /** Conversion: int to amplitude_t */ #define I2A(i) ((i) << amplitude_decimal_bits) /** Conversion: amplitude_t to int */ #define A2I(i) ((i) >> amplitude_decimal_bits) /** Conversion: amplitude_t to height_t */ #define A2H(a) ((a) >> (amplitude_decimal_bits - height_decimal_bits)) /** Walk through all items of _height_map.h */ #define FOR_ALL_TILES_IN_HEIGHT(h) for (h = _height_map.h; h < &_height_map.h[_height_map.total_size]; h++) /** Maximum number of TGP noise frequencies. */ static const int MAX_TGP_FREQUENCIES = 10; /** Desired water percentage (100% == 1024) - indexed by _settings_game.difficulty.quantity_sea_lakes */ static const amplitude_t _water_percent[4] = {20, 80, 250, 400}; /** * Gets the maximum allowed height while generating a map based on * mapsize, terraintype, and the maximum height level. * @return The maximum height for the map generation. */ static height_t TGPGetMaxHeight() { /** * Desired maximum height - indexed by: * - _settings_game.difficulty.terrain_type * - min(MapLogX(), MapLogY()) - MIN_MAP_SIZE_BITS * * It is indexed by map size as well as terrain type since the map size limits the height of * a usable mountain. For example, on a 64x64 map a 24 high single peak mountain (as if you * raised land 24 times in the center of the map) will leave only a ring of about 10 tiles * around the mountain to build on. On a 4096x4096 map, it won't cover any major part of the map. */ static const int max_height[5][MAX_MAP_SIZE_BITS - MIN_MAP_SIZE_BITS + 1] = { /* 64 128 256 512 1024 2048 4096 */ { 3, 3, 5, 5, 5, 5, 5 }, ///< Very flat { 4, 4, 6, 10, 10, 10, 10 }, ///< Flat { 6, 9, 15, 25, 31, 31, 31 }, ///< Hilly { 7, 12, 23, 42, 78, 85, 85 }, ///< Mountainous { 12, 21, 36, 73, 146, 170, 170 } ///< Alpinist }; int max_height_from_table = max_height[_settings_game.difficulty.terrain_type][min(MapLogX(), MapLogY()) - MIN_MAP_SIZE_BITS]; return I2H(min(max_height_from_table, _settings_game.construction.max_heightlevel)); } /** * Get the amplitude associated with the currently selected * smoothness and maximum height level. * @param frequency The frequency to get the amplitudes for * @return The amplitudes to apply to the map. */ static amplitude_t GetAmplitude(int frequency) { /* Base noise amplitudes (multiplied by 1024) and indexed by "smoothness setting" and log2(frequency). */ static const amplitude_t amplitudes[][7] = { /* lowest frequency ...... highest (every corner) */ {16000, 5600, 1968, 688, 240, 16, 16}, ///< Very smooth {24000, 12800, 6400, 2700, 1024, 128, 16}, ///< Smooth {32000, 19200, 12800, 8000, 3200, 256, 64}, ///< Rough {48000, 24000, 19200, 16000, 8000, 512, 320}, ///< Very rough }; /* * Extrapolation factors for ranges before the table. * The extrapolation is needed to account for the higher map heights. They need larger * areas with a particular gradient so that we are able to create maps without too * many steep slopes up to the wanted height level. It's definitely not perfect since * it will bring larger rectangles with similar slopes which makes the rectangular * behaviour of TGP more noticable. However, these height differentiations cannot * happen over much smaller areas; we basically double the "range" to give a similar * slope for every doubling of map height. */ static const double extrapolation_factors[] = { 3.3, 2.8, 2.3, 1.8 }; int smoothness = _settings_game.game_creation.tgen_smoothness; /* Get the table index, and return that value if possible. */ int index = frequency - MAX_TGP_FREQUENCIES + lengthof(amplitudes[smoothness]); amplitude_t amplitude = amplitudes[smoothness][max(0, index)]; if (index >= 0) return amplitude; /* We need to extrapolate the amplitude. */ double extrapolation_factor = extrapolation_factors[smoothness]; int height_range = I2H(16); do { amplitude = (amplitude_t)(extrapolation_factor * (double)amplitude); height_range <<= 1; index++; } while (index < 0); return Clamp((TGPGetMaxHeight() - height_range) / height_range, 0, 1) * amplitude; } /** * Check if a X/Y set are within the map. * @param x coordinate x * @param y coordinate y * @return true if within the map */ static inline bool IsValidXY(int x, int y) { return x >= 0 && x < _height_map.size_x && y >= 0 && y < _height_map.size_y; } /** * Allocate array of (MapSizeX()+1)*(MapSizeY()+1) heights and init the _height_map structure members * @return true on success */ static inline bool AllocHeightMap() { height_t *h; _height_map.size_x = MapSizeX(); _height_map.size_y = MapSizeY(); /* Allocate memory block for height map row pointers */ _height_map.total_size = (_height_map.size_x + 1) * (_height_map.size_y + 1); _height_map.dim_x = _height_map.size_x + 1; _height_map.h = CallocT(_height_map.total_size); /* Iterate through height map initialize values */ FOR_ALL_TILES_IN_HEIGHT(h) *h = _invalid_height; return true; } /** Free height map */ static inline void FreeHeightMap() { free(_height_map.h); _height_map.h = NULL; } /** * Generates new random height in given amplitude (generated numbers will range from - amplitude to + amplitude) * @param rMax Limit of result * @return generated height */ static inline height_t RandomHeight(amplitude_t rMax) { /* Spread height into range -rMax..+rMax */ return A2H(RandomRange(2 * rMax + 1) - rMax); } /** * Base Perlin noise generator - fills height map with raw Perlin noise. * * This runs several iterations with increasing precision; the last iteration looks at areas * of 1 by 1 tiles, the second to last at 2 by 2 tiles and the initial 2**MAX_TGP_FREQUENCIES * by 2**MAX_TGP_FREQUENCIES tiles. */ static void HeightMapGenerate() { /* Trying to apply noise to uninitialized height map */ assert(_height_map.h != NULL); int start = max(MAX_TGP_FREQUENCIES - (int)min(MapLogX(), MapLogY()), 0); bool first = true; for (int frequency = start; frequency < MAX_TGP_FREQUENCIES; frequency++) { const amplitude_t amplitude = GetAmplitude(frequency); /* Ignore zero amplitudes; it means our map isn't height enough for this * amplitude, so ignore it and continue with the next set of amplitude. */ if (amplitude == 0) continue; const int step = 1 << (MAX_TGP_FREQUENCIES - frequency - 1); if (first) { /* This is first round, we need to establish base heights with step = size_min */ for (int y = 0; y <= _height_map.size_y; y += step) { for (int x = 0; x <= _height_map.size_x; x += step) { height_t height = (amplitude > 0) ? RandomHeight(amplitude) : 0; _height_map.height(x, y) = height; } } first = false; continue; } /* It is regular iteration round. * Interpolate height values at odd x, even y tiles */ for (int y = 0; y <= _height_map.size_y; y += 2 * step) { for (int x = 0; x <= _height_map.size_x - 2 * step; x += 2 * step) { height_t h00 = _height_map.height(x + 0 * step, y); height_t h02 = _height_map.height(x + 2 * step, y); height_t h01 = (h00 + h02) / 2; _height_map.height(x + 1 * step, y) = h01; } } /* Interpolate height values at odd y tiles */ for (int y = 0; y <= _height_map.size_y - 2 * step; y += 2 * step) { for (int x = 0; x <= _height_map.size_x; x += step) { height_t h00 = _height_map.height(x, y + 0 * step); height_t h20 = _height_map.height(x, y + 2 * step); height_t h10 = (h00 + h20) / 2; _height_map.height(x, y + 1 * step) = h10; } } /* Add noise for next higher frequency (smaller steps) */ for (int y = 0; y <= _height_map.size_y; y += step) { for (int x = 0; x <= _height_map.size_x; x += step) { _height_map.height(x, y) += RandomHeight(amplitude); } } } } /** Returns min, max and average height from height map */ static void HeightMapGetMinMaxAvg(height_t *min_ptr, height_t *max_ptr, height_t *avg_ptr) { height_t h_min, h_max, h_avg, *h; int64 h_accu = 0; h_min = h_max = _height_map.height(0, 0); /* Get h_min, h_max and accumulate heights into h_accu */ FOR_ALL_TILES_IN_HEIGHT(h) { if (*h < h_min) h_min = *h; if (*h > h_max) h_max = *h; h_accu += *h; } /* Get average height */ h_avg = (height_t)(h_accu / (_height_map.size_x * _height_map.size_y)); /* Return required results */ if (min_ptr != NULL) *min_ptr = h_min; if (max_ptr != NULL) *max_ptr = h_max; if (avg_ptr != NULL) *avg_ptr = h_avg; } /** Dill histogram and return pointer to its base point - to the count of zero heights */ static int *HeightMapMakeHistogram(height_t h_min, height_t h_max, int *hist_buf) { int *hist = hist_buf - h_min; height_t *h; /* Count the heights and fill the histogram */ FOR_ALL_TILES_IN_HEIGHT(h) { assert(*h >= h_min); assert(*h <= h_max); hist[*h]++; } return hist; } /** Applies sine wave redistribution onto height map */ static void HeightMapSineTransform(height_t h_min, height_t h_max) { height_t *h; FOR_ALL_TILES_IN_HEIGHT(h) { double fheight; if (*h < h_min) continue; /* Transform height into 0..1 space */ fheight = (double)(*h - h_min) / (double)(h_max - h_min); /* Apply sine transform depending on landscape type */ switch (_settings_game.game_creation.landscape) { case LT_TOYLAND: case LT_TEMPERATE: /* Move and scale 0..1 into -1..+1 */ fheight = 2 * fheight - 1; /* Sine transform */ fheight = sin(fheight * M_PI_2); /* Transform it back from -1..1 into 0..1 space */ fheight = 0.5 * (fheight + 1); break; case LT_ARCTIC: { /* Arctic terrain needs special height distribution. * Redistribute heights to have more tiles at highest (75%..100%) range */ double sine_upper_limit = 0.75; double linear_compression = 2; if (fheight >= sine_upper_limit) { /* Over the limit we do linear compression up */ fheight = 1.0 - (1.0 - fheight) / linear_compression; } else { double m = 1.0 - (1.0 - sine_upper_limit) / linear_compression; /* Get 0..sine_upper_limit into -1..1 */ fheight = 2.0 * fheight / sine_upper_limit - 1.0; /* Sine wave transform */ fheight = sin(fheight * M_PI_2); /* Get -1..1 back to 0..(1 - (1 - sine_upper_limit) / linear_compression) == 0.0..m */ fheight = 0.5 * (fheight + 1.0) * m; } } break; case LT_TROPIC: { /* Desert terrain needs special height distribution. * Half of tiles should be at lowest (0..25%) heights */ double sine_lower_limit = 0.5; double linear_compression = 2; if (fheight <= sine_lower_limit) { /* Under the limit we do linear compression down */ fheight = fheight / linear_compression; } else { double m = sine_lower_limit / linear_compression; /* Get sine_lower_limit..1 into -1..1 */ fheight = 2.0 * ((fheight - sine_lower_limit) / (1.0 - sine_lower_limit)) - 1.0; /* Sine wave transform */ fheight = sin(fheight * M_PI_2); /* Get -1..1 back to (sine_lower_limit / linear_compression)..1.0 */ fheight = 0.5 * ((1.0 - m) * fheight + (1.0 + m)); } } break; default: NOT_REACHED(); break; } /* Transform it back into h_min..h_max space */ *h = (height_t)(fheight * (h_max - h_min) + h_min); if (*h < 0) *h = I2H(0); if (*h >= h_max) *h = h_max - 1; } } /** * Additional map variety is provided by applying different curve maps * to different parts of the map. A randomized low resolution grid contains * which curve map to use on each part of the make. This filtered non-linearly * to smooth out transitions between curves, so each tile could have between * 100% of one map applied or 25% of four maps. * * The curve maps define different land styles, i.e. lakes, low-lands, hills * and mountain ranges, although these are dependent on the landscape style * chosen as well. * * The level parameter dictates the resolution of the grid. A low resolution * grid will result in larger continuous areas of a land style, a higher * resolution grid splits the style into smaller areas. * @param level Rough indication of the size of the grid sections to style. Small level means large grid sections. */ static void HeightMapCurves(uint level) { height_t mh = TGPGetMaxHeight() - I2H(1); // height levels above sea level only /** Basically scale height X to height Y. Everything in between is interpolated. */ struct control_point_t { height_t x; ///< The height to scale from. height_t y; ///< The height to scale to. }; /* Scaled curve maps; value is in height_ts. */ #define F(fraction) ((height_t)(fraction * mh)) const control_point_t curve_map_1[] = { { F(0.0), F(0.0) }, { F(0.8), F(0.13) }, { F(1.0), F(0.4) } }; const control_point_t curve_map_2[] = { { F(0.0), F(0.0) }, { F(0.53), F(0.13) }, { F(0.8), F(0.27) }, { F(1.0), F(0.6) } }; const control_point_t curve_map_3[] = { { F(0.0), F(0.0) }, { F(0.53), F(0.27) }, { F(0.8), F(0.57) }, { F(1.0), F(0.8) } }; const control_point_t curve_map_4[] = { { F(0.0), F(0.0) }, { F(0.4), F(0.3) }, { F(0.7), F(0.8) }, { F(0.92), F(0.99) }, { F(1.0), F(0.99) } }; #undef F /** Helper structure to index the different curve maps. */ struct control_point_list_t { size_t length; ///< The length of the curve map. const control_point_t *list; ///< The actual curve map. }; const control_point_list_t curve_maps[] = { { lengthof(curve_map_1), curve_map_1 }, { lengthof(curve_map_2), curve_map_2 }, { lengthof(curve_map_3), curve_map_3 }, { lengthof(curve_map_4), curve_map_4 }, }; height_t ht[lengthof(curve_maps)]; MemSetT(ht, 0, lengthof(ht)); /* Set up a grid to choose curve maps based on location; attempt to get a somewhat square grid */ float factor = sqrt((float)_height_map.size_x / (float)_height_map.size_y); uint sx = Clamp((int)(((1 << level) * factor) + 0.5), 1, 128); uint sy = Clamp((int)(((1 << level) / factor) + 0.5), 1, 128); byte *c = AllocaM(byte, sx * sy); for (uint i = 0; i < sx * sy; i++) { c[i] = Random() % lengthof(curve_maps); } /* Apply curves */ for (int x = 0; x < _height_map.size_x; x++) { /* Get our X grid positions and bi-linear ratio */ float fx = (float)(sx * x) / _height_map.size_x + 1.0f; uint x1 = (uint)fx; uint x2 = x1; float xr = 2.0f * (fx - x1) - 1.0f; xr = sin(xr * M_PI_2); xr = sin(xr * M_PI_2); xr = 0.5f * (xr + 1.0f); float xri = 1.0f - xr; if (x1 > 0) { x1--; if (x2 >= sx) x2--; } for (int y = 0; y < _height_map.size_y; y++) { /* Get our Y grid position and bi-linear ratio */ float fy = (float)(sy * y) / _height_map.size_y + 1.0f; uint y1 = (uint)fy; uint y2 = y1; float yr = 2.0f * (fy - y1) - 1.0f; yr = sin(yr * M_PI_2); yr = sin(yr * M_PI_2); yr = 0.5f * (yr + 1.0f); float yri = 1.0f - yr; if (y1 > 0) { y1--; if (y2 >= sy) y2--; } uint corner_a = c[x1 + sx * y1]; uint corner_b = c[x1 + sx * y2]; uint corner_c = c[x2 + sx * y1]; uint corner_d = c[x2 + sx * y2]; /* Bitmask of which curve maps are chosen, so that we do not bother * calculating a curve which won't be used. */ uint corner_bits = 0; corner_bits |= 1 << corner_a; corner_bits |= 1 << corner_b; corner_bits |= 1 << corner_c; corner_bits |= 1 << corner_d; height_t *h = &_height_map.height(x, y); /* Do not touch sea level */ if (*h < I2H(1)) continue; /* Only scale above sea level */ *h -= I2H(1); /* Apply all curve maps that are used on this tile. */ for (uint t = 0; t < lengthof(curve_maps); t++) { if (!HasBit(corner_bits, t)) continue; bool found = false; const control_point_t *cm = curve_maps[t].list; for (uint i = 0; i < curve_maps[t].length - 1; i++) { const control_point_t &p1 = cm[i]; const control_point_t &p2 = cm[i + 1]; if (*h >= p1.x && *h < p2.x) { ht[t] = p1.y + (*h - p1.x) * (p2.y - p1.y) / (p2.x - p1.x); found = true; break; } } assert(found); } /* Apply interpolation of curve map results. */ *h = (height_t)((ht[corner_a] * yri + ht[corner_b] * yr) * xri + (ht[corner_c] * yri + ht[corner_d] * yr) * xr); /* Readd sea level */ *h += I2H(1); } } } /** Adjusts heights in height map to contain required amount of water tiles */ static void HeightMapAdjustWaterLevel(amplitude_t water_percent, height_t h_max_new) { height_t h_min, h_max, h_avg, h_water_level; int64 water_tiles, desired_water_tiles; height_t *h; int *hist; HeightMapGetMinMaxAvg(&h_min, &h_max, &h_avg); /* Allocate histogram buffer and clear its cells */ int *hist_buf = CallocT(h_max - h_min + 1); /* Fill histogram */ hist = HeightMapMakeHistogram(h_min, h_max, hist_buf); /* How many water tiles do we want? */ desired_water_tiles = A2I(((int64)water_percent) * (int64)(_height_map.size_x * _height_map.size_y)); /* Raise water_level and accumulate values from histogram until we reach required number of water tiles */ for (h_water_level = h_min, water_tiles = 0; h_water_level < h_max; h_water_level++) { water_tiles += hist[h_water_level]; if (water_tiles >= desired_water_tiles) break; } /* We now have the proper water level value. * Transform the height map into new (normalized) height map: * values from range: h_min..h_water_level will become negative so it will be clamped to 0 * values from range: h_water_level..h_max are transformed into 0..h_max_new * where h_max_new is depending on terrain type and map size. */ FOR_ALL_TILES_IN_HEIGHT(h) { /* Transform height from range h_water_level..h_max into 0..h_max_new range */ *h = (height_t)(((int)h_max_new) * (*h - h_water_level) / (h_max - h_water_level)) + I2H(1); /* Make sure all values are in the proper range (0..h_max_new) */ if (*h < 0) *h = I2H(0); if (*h >= h_max_new) *h = h_max_new - 1; } free(hist_buf); } static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime); /** * This routine sculpts in from the edge a random amount, again a Perlin * sequence, to avoid the rigid flat-edge slopes that were present before. The * Perlin noise map doesn't know where we are going to slice across, and so we * often cut straight through high terrain. The smoothing routine makes it * legal, gradually increasing up from the edge to the original terrain height. * By cutting parts of this away, it gives a far more irregular edge to the * map-edge. Sometimes it works beautifully with the existing sea & lakes, and * creates a very realistic coastline. Other times the variation is less, and * the map-edge shows its cliff-like roots. * * This routine may be extended to randomly sculpt the height of the terrain * near the edge. This will have the coast edge at low level (1-3), rising in * smoothed steps inland to about 15 tiles in. This should make it look as * though the map has been built for the map size, rather than a slice through * a larger map. * * Please note that all the small numbers; 53, 101, 167, etc. are small primes * to help give the perlin noise a bit more of a random feel. */ static void HeightMapCoastLines(uint8 water_borders) { int smallest_size = min(_settings_game.game_creation.map_x, _settings_game.game_creation.map_y); const int margin = 4; int y, x; double max_x; double max_y; /* Lower to sea level */ for (y = 0; y <= _height_map.size_y; y++) { if (HasBit(water_borders, BORDER_NE)) { /* Top right */ max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.9, 53) + 0.25) * 5 + (perlin_coast_noise_2D(y, y, 0.35, 179) + 1) * 12); max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x); if (smallest_size < 8 && max_x > 5) max_x /= 1.5; for (x = 0; x < max_x; x++) { _height_map.height(x, y) = 0; } } if (HasBit(water_borders, BORDER_SW)) { /* Bottom left */ max_x = abs((perlin_coast_noise_2D(_height_map.size_y - y, y, 0.85, 101) + 0.3) * 6 + (perlin_coast_noise_2D(y, y, 0.45, 67) + 0.75) * 8); max_x = max((smallest_size * smallest_size / 16) + max_x, (smallest_size * smallest_size / 16) + margin - max_x); if (smallest_size < 8 && max_x > 5) max_x /= 1.5; for (x = _height_map.size_x; x > (_height_map.size_x - 1 - max_x); x--) { _height_map.height(x, y) = 0; } } } /* Lower to sea level */ for (x = 0; x <= _height_map.size_x; x++) { if (HasBit(water_borders, BORDER_NW)) { /* Top left */ max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 2, 0.9, 167) + 0.4) * 5 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.4, 211) + 0.7) * 9); max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y); if (smallest_size < 8 && max_y > 5) max_y /= 1.5; for (y = 0; y < max_y; y++) { _height_map.height(x, y) = 0; } } if (HasBit(water_borders, BORDER_SE)) { /* Bottom right */ max_y = abs((perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.85, 71) + 0.25) * 6 + (perlin_coast_noise_2D(x, _height_map.size_y / 3, 0.35, 193) + 0.75) * 12); max_y = max((smallest_size * smallest_size / 16) + max_y, (smallest_size * smallest_size / 16) + margin - max_y); if (smallest_size < 8 && max_y > 5) max_y /= 1.5; for (y = _height_map.size_y; y > (_height_map.size_y - 1 - max_y); y--) { _height_map.height(x, y) = 0; } } } } /** Start at given point, move in given direction, find and Smooth coast in that direction */ static void HeightMapSmoothCoastInDirection(int org_x, int org_y, int dir_x, int dir_y) { const int max_coast_dist_from_edge = 35; const int max_coast_Smooth_depth = 35; int x, y; int ed; // coast distance from edge int depth; height_t h_prev = I2H(1); height_t h; assert(IsValidXY(org_x, org_y)); /* Search for the coast (first non-water tile) */ for (x = org_x, y = org_y, ed = 0; IsValidXY(x, y) && ed < max_coast_dist_from_edge; x += dir_x, y += dir_y, ed++) { /* Coast found? */ if (_height_map.height(x, y) >= I2H(1)) break; /* Coast found in the neighborhood? */ if (IsValidXY(x + dir_y, y + dir_x) && _height_map.height(x + dir_y, y + dir_x) > 0) break; /* Coast found in the neighborhood on the other side */ if (IsValidXY(x - dir_y, y - dir_x) && _height_map.height(x - dir_y, y - dir_x) > 0) break; } /* Coast found or max_coast_dist_from_edge has been reached. * Soften the coast slope */ for (depth = 0; IsValidXY(x, y) && depth <= max_coast_Smooth_depth; depth++, x += dir_x, y += dir_y) { h = _height_map.height(x, y); h = min(h, h_prev + (4 + depth)); // coast softening formula _height_map.height(x, y) = h; h_prev = h; } } /** Smooth coasts by modulating height of tiles close to map edges with cosine of distance from edge */ static void HeightMapSmoothCoasts(uint8 water_borders) { int x, y; /* First Smooth NW and SE coasts (y close to 0 and y close to size_y) */ for (x = 0; x < _height_map.size_x; x++) { if (HasBit(water_borders, BORDER_NW)) HeightMapSmoothCoastInDirection(x, 0, 0, 1); if (HasBit(water_borders, BORDER_SE)) HeightMapSmoothCoastInDirection(x, _height_map.size_y - 1, 0, -1); } /* First Smooth NE and SW coasts (x close to 0 and x close to size_x) */ for (y = 0; y < _height_map.size_y; y++) { if (HasBit(water_borders, BORDER_NE)) HeightMapSmoothCoastInDirection(0, y, 1, 0); if (HasBit(water_borders, BORDER_SW)) HeightMapSmoothCoastInDirection(_height_map.size_x - 1, y, -1, 0); } } /** * This routine provides the essential cleanup necessary before OTTD can * display the terrain. When generated, the terrain heights can jump more than * one level between tiles. This routine smooths out those differences so that * the most it can change is one level. When OTTD can support cliffs, this * routine may not be necessary. */ static void HeightMapSmoothSlopes(height_t dh_max) { for (int y = 0; y <= (int)_height_map.size_y; y++) { for (int x = 0; x <= (int)_height_map.size_x; x++) { height_t h_max = min(_height_map.height(x > 0 ? x - 1 : x, y), _height_map.height(x, y > 0 ? y - 1 : y)) + dh_max; if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max; } } for (int y = _height_map.size_y; y >= 0; y--) { for (int x = _height_map.size_x; x >= 0; x--) { height_t h_max = min(_height_map.height(x < _height_map.size_x ? x + 1 : x, y), _height_map.height(x, y < _height_map.size_y ? y + 1 : y)) + dh_max; if (_height_map.height(x, y) > h_max) _height_map.height(x, y) = h_max; } } } /** * Height map terraform post processing: * - water level adjusting * - coast Smoothing * - slope Smoothing * - height histogram redistribution by sine wave transform */ static void HeightMapNormalize() { int sea_level_setting = _settings_game.difficulty.quantity_sea_lakes; const amplitude_t water_percent = sea_level_setting != (int)CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY ? _water_percent[sea_level_setting] : _settings_game.game_creation.custom_sea_level * 1024 / 100; const height_t h_max_new = TGPGetMaxHeight(); const height_t roughness = 7 + 3 * _settings_game.game_creation.tgen_smoothness; HeightMapAdjustWaterLevel(water_percent, h_max_new); byte water_borders = _settings_game.construction.freeform_edges ? _settings_game.game_creation.water_borders : 0xF; if (water_borders == BORDERS_RANDOM) water_borders = GB(Random(), 0, 4); HeightMapCoastLines(water_borders); HeightMapSmoothSlopes(roughness); HeightMapSmoothCoasts(water_borders); HeightMapSmoothSlopes(roughness); HeightMapSineTransform(I2H(1), h_max_new); if (_settings_game.game_creation.variety > 0) { HeightMapCurves(_settings_game.game_creation.variety); } HeightMapSmoothSlopes(I2H(1)); } /** * The Perlin Noise calculation using large primes * The initial number is adjusted by two values; the generation_seed, and the * passed parameter; prime. * prime is used to allow the perlin noise generator to create useful random * numbers from slightly different series. */ static double int_noise(const long x, const long y, const int prime) { long n = x + y * prime + _settings_game.game_creation.generation_seed; n = (n << 13) ^ n; /* Pseudo-random number generator, using several large primes */ return 1.0 - (double)((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0; } /** * This routine determines the interpolated value between a and b */ static inline double linear_interpolate(const double a, const double b, const double x) { return a + x * (b - a); } /** * This routine returns the smoothed interpolated noise for an x and y, using * the values from the surrounding positions. */ static double interpolated_noise(const double x, const double y, const int prime) { const int integer_X = (int)x; const int integer_Y = (int)y; const double fractional_X = x - (double)integer_X; const double fractional_Y = y - (double)integer_Y; const double v1 = int_noise(integer_X, integer_Y, prime); const double v2 = int_noise(integer_X + 1, integer_Y, prime); const double v3 = int_noise(integer_X, integer_Y + 1, prime); const double v4 = int_noise(integer_X + 1, integer_Y + 1, prime); const double i1 = linear_interpolate(v1, v2, fractional_X); const double i2 = linear_interpolate(v3, v4, fractional_X); return linear_interpolate(i1, i2, fractional_Y); } /** * This is a similar function to the main perlin noise calculation, but uses * the value p passed as a parameter rather than selected from the predefined * sequences. as you can guess by its title, i use this to create the indented * coastline, which is just another perlin sequence. */ static double perlin_coast_noise_2D(const double x, const double y, const double p, const int prime) { double total = 0.0; for (int i = 0; i < 6; i++) { const double frequency = (double)(1 << i); const double amplitude = pow(p, (double)i); total += interpolated_noise((x * frequency) / 64.0, (y * frequency) / 64.0, prime) * amplitude; } return total; } /** A small helper function to initialize the terrain */ static void TgenSetTileHeight(TileIndex tile, int height) { SetTileHeight(tile, height); /* Only clear the tiles within the map area. */ if (IsInnerTile(tile)) { MakeClear(tile, CLEAR_GRASS, 3); } } /** * The main new land generator using Perlin noise. Desert landscape is handled * different to all others to give a desert valley between two high mountains. * Clearly if a low height terrain (flat/very flat) is chosen, then the tropic * areas wont be high enough, and there will be very little tropic on the map. * Thus Tropic works best on Hilly or Mountainous. */ void GenerateTerrainPerlin() { if (!AllocHeightMap()) return; GenerateWorldSetAbortCallback(FreeHeightMap); HeightMapGenerate(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); HeightMapNormalize(); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); /* First make sure the tiles at the north border are void tiles if needed. */ if (_settings_game.construction.freeform_edges) { for (int y = 0; y < _height_map.size_y - 1; y++) MakeVoid(_height_map.size_x * y); for (int x = 0; x < _height_map.size_x; x++) MakeVoid(x); } int max_height = H2I(TGPGetMaxHeight()); /* Transfer height map into OTTD map */ for (int y = 0; y < _height_map.size_y; y++) { for (int x = 0; x < _height_map.size_x; x++) { TgenSetTileHeight(TileXY(x, y), Clamp(H2I(_height_map.height(x, y)), 0, max_height)); } } IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); FreeHeightMap(); GenerateWorldSetAbortCallback(NULL); } openttd-1.5.3/src/subsidy_func.h0000644000000000000000000000230612627373441015342 0ustar rootroot/* $Id: subsidy_func.h 20674 2010-08-28 20:15:45Z alberth $ */ /* * 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 subsidy_func.h Functions related to subsidies. */ #ifndef SUBSIDY_FUNC_H #define SUBSIDY_FUNC_H #include "core/geometry_type.hpp" #include "station_type.h" #include "company_type.h" #include "cargo_type.h" Pair SetupSubsidyDecodeParam(const struct Subsidy *s, bool mode); void DeleteSubsidyWith(SourceType type, SourceID index); bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st); void RebuildSubsidisedSourceAndDestinationCache(); void DeleteSubsidy(struct Subsidy *s); #endif /* SUBSIDY_FUNC_H */ openttd-1.5.3/src/newgrf_animation_base.h0000644000000000000000000001327112627373442017172 0ustar rootroot/* $Id: newgrf_animation_base.h 24846 2012-12-23 21:09:09Z frosch $ */ /* * 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 newgrf_animation_base.h Function implementations related to NewGRF animation. */ /* No inclusion guards as this file must only be included from .cpp files. */ #include "animated_tile_func.h" #include "core/random_func.hpp" #include "date_func.h" #include "viewport_func.h" #include "newgrf_animation_type.h" #include "newgrf_callbacks.h" #include "tile_map.h" /** * Helper class for a unified approach to NewGRF animation. * @tparam Tbase Instantiation of this class. * @tparam Tspec NewGRF specification related to the animated tile. * @tparam Tobj Object related to the animated tile. * @tparam Textra Custom extra callback data. * @tparam GetCallback The callback function pointer. */ template struct AnimationBase { /** * Animate a single tile. * @param cb The callback to actually call. * @param spec Specification related to the tile. * @param obj Object related to the tile. * @param tile Tile to animate changes for. * @param random_animation Whether to pass random bits to the "next frame" callback. * @param extra_data Custom extra callback data. */ static void AnimateTile(const Tspec *spec, Tobj *obj, TileIndex tile, bool random_animation, Textra extra_data = 0) { assert(spec != NULL); /* Acquire the animation speed from the NewGRF. */ uint8 animation_speed = spec->animation.speed; if (HasBit(spec->callback_mask, Tbase::cbm_animation_speed)) { uint16 callback = GetCallback(Tbase::cb_animation_speed, 0, 0, spec, obj, tile, extra_data); if (callback != CALLBACK_FAILED) { if (callback >= 0x100 && spec->grf_prop.grffile->grf_version >= 8) ErrorUnknownCallbackResult(spec->grf_prop.grffile->grfid, Tbase::cb_animation_speed, callback); animation_speed = Clamp(callback & 0xFF, 0, 16); } } /* An animation speed of 2 means the animation frame changes 4 ticks, and * increasing this value by one doubles the wait. 0 is the minimum value * allowed for animation_speed, which corresponds to 30ms, and 16 is the * maximum, corresponding to around 33 minutes. */ if (_tick_counter % (1 << animation_speed) != 0) return; uint8 frame = GetAnimationFrame(tile); uint8 num_frames = spec->animation.frames; bool frame_set_by_callback = false; if (HasBit(spec->callback_mask, Tbase::cbm_animation_next_frame)) { uint16 callback = GetCallback(Tbase::cb_animation_next_frame, random_animation ? Random() : 0, 0, spec, obj, tile, extra_data); if (callback != CALLBACK_FAILED) { frame_set_by_callback = true; switch (callback & 0xFF) { case 0xFF: DeleteAnimatedTile(tile); break; case 0xFE: frame_set_by_callback = false; break; default: frame = callback & 0xFF; break; } /* If the lower 7 bits of the upper byte of the callback * result are not empty, it is a sound effect. */ if (GB(callback, 8, 7) != 0 && _settings_client.sound.ambient) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile); } } if (!frame_set_by_callback) { if (frame < num_frames) { frame++; } else if (frame == num_frames && spec->animation.status == ANIM_STATUS_LOOPING) { /* This animation loops, so start again from the beginning */ frame = 0; } else { /* This animation doesn't loop, so stay here */ DeleteAnimatedTile(tile); } } SetAnimationFrame(tile, frame); MarkTileDirtyByTile(tile); } /** * Check a callback to determine what the next animation step is and * execute that step. This includes stopping and starting animations * as well as updating animation frames and playing sounds. * @param cb The callback to actually call. * @param spec Specification related to the tile. * @param obj Object related to the tile. * @param tile Tile to consider animation changes for. * @param random_bits Random bits for this update. To be passed as parameter to the NewGRF. * @param trigger What triggered this update? To be passed as parameter to the NewGRF. * @param extra_data Custom extra data for callback processing. */ static void ChangeAnimationFrame(CallbackID cb, const Tspec *spec, Tobj *obj, TileIndex tile, uint32 random_bits, uint32 trigger, Textra extra_data = 0) { uint16 callback = GetCallback(cb, random_bits, trigger, spec, obj, tile, extra_data); if (callback == CALLBACK_FAILED) return; switch (callback & 0xFF) { case 0xFD: /* Do nothing. */ break; case 0xFE: AddAnimatedTile(tile); break; case 0xFF: DeleteAnimatedTile(tile); break; default: SetAnimationFrame(tile, callback); AddAnimatedTile(tile); break; } /* If the lower 7 bits of the upper byte of the callback * result are not empty, it is a sound effect. */ if (GB(callback, 8, 7) != 0 && _settings_client.sound.ambient) PlayTileSound(spec->grf_prop.grffile, GB(callback, 8, 7), tile); } }; openttd-1.5.3/src/order_base.h0000644000000000000000000004174212627373445014765 0ustar rootroot/* $Id: order_base.h 26547 2014-05-01 14:49:16Z fonsinchen $ */ /* * 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 order_base.h Base class for orders. */ #ifndef ORDER_BASE_H #define ORDER_BASE_H #include "order_type.h" #include "core/pool_type.hpp" #include "core/bitmath_func.hpp" #include "cargo_type.h" #include "depot_type.h" #include "station_type.h" #include "vehicle_type.h" #include "date_type.h" typedef Pool OrderPool; typedef Pool OrderListPool; extern OrderPool _order_pool; extern OrderListPool _orderlist_pool; /* If you change this, keep in mind that it is saved on 3 places: * - Load_ORDR, all the global orders * - Vehicle -> current_order * - REF_ORDER (all REFs are currently limited to 16 bits!!) */ struct Order : OrderPool::PoolItem<&_order_pool> { private: friend const struct SaveLoad *GetVehicleDescription(VehicleType vt); ///< Saving and loading the current order of vehicles. friend void Load_VEHS(); ///< Loading of ancient vehicles. friend const struct SaveLoad *GetOrderDescription(); ///< Saving and loading of orders. uint8 type; ///< The type of order + non-stop flags uint8 flags; ///< Load/unload types, depot order/action types. DestinationID dest; ///< The destination of the order. CargoID refit_cargo; ///< Refit CargoID uint16 wait_time; ///< How long in ticks to wait at the destination. uint16 travel_time; ///< How long in ticks the journey to this destination should take. uint16 max_speed; ///< How fast the vehicle may go on the way to the destination. public: Order *next; ///< Pointer to next order. If NULL, end of list Order() : refit_cargo(CT_NO_REFIT), max_speed(UINT16_MAX) {} ~Order(); Order(uint32 packed); /** * Check whether this order is of the given type. * @param type the type to check against. * @return true if the order matches. */ inline bool IsType(OrderType type) const { return this->GetType() == type; } /** * Get the type of order of this order. * @return the order type. */ inline OrderType GetType() const { return (OrderType)GB(this->type, 0, 4); } void Free(); void MakeGoToStation(StationID destination); void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type = ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action = ODATF_SERVICE_ONLY, CargoID cargo = CT_NO_REFIT); void MakeGoToWaypoint(StationID destination); void MakeLoading(bool ordered); void MakeLeaveStation(); void MakeDummy(); void MakeConditional(VehicleOrderID order); void MakeImplicit(StationID destination); /** * Is this a 'goto' order with a real destination? * @return True if the type is either #OT_GOTO_WAYPOINT, #OT_GOTO_DEPOT or #OT_GOTO_STATION. */ inline bool IsGotoOrder() const { return IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION); } /** * Gets the destination of this order. * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION). * @return the destination of the order. */ inline DestinationID GetDestination() const { return this->dest; } /** * Sets the destination of this order. * @param destination the new destination of the order. * @pre IsType(OT_GOTO_WAYPOINT) || IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION). */ inline void SetDestination(DestinationID destination) { this->dest = destination; } /** * Is this order a refit order. * @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) * @return true if a refit should happen. */ inline bool IsRefit() const { return this->refit_cargo < NUM_CARGO || this->refit_cargo == CT_AUTO_REFIT; } /** * Is this order a auto-refit order. * @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) * @return true if a auto-refit should happen. */ inline bool IsAutoRefit() const { return this->refit_cargo == CT_AUTO_REFIT; } /** * Get the cargo to to refit to. * @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION) * @return the cargo type. */ inline CargoID GetRefitCargo() const { return this->refit_cargo; } void SetRefit(CargoID cargo); /** How must the consist be loaded? */ inline OrderLoadFlags GetLoadType() const { return (OrderLoadFlags)GB(this->flags, 4, 3); } /** How must the consist be unloaded? */ inline OrderUnloadFlags GetUnloadType() const { return (OrderUnloadFlags)GB(this->flags, 0, 3); } /** At which stations must we stop? */ inline OrderNonStopFlags GetNonStopType() const { return (OrderNonStopFlags)GB(this->type, 6, 2); } /** Where must we stop at the platform? */ inline OrderStopLocation GetStopLocation() const { return (OrderStopLocation)GB(this->type, 4, 2); } /** What caused us going to the depot? */ inline OrderDepotTypeFlags GetDepotOrderType() const { return (OrderDepotTypeFlags)GB(this->flags, 0, 3); } /** What are we going to do when in the depot. */ inline OrderDepotActionFlags GetDepotActionType() const { return (OrderDepotActionFlags)GB(this->flags, 4, 3); } /** What variable do we have to compare? */ inline OrderConditionVariable GetConditionVariable() const { return (OrderConditionVariable)GB(this->dest, 11, 5); } /** What is the comparator to use? */ inline OrderConditionComparator GetConditionComparator() const { return (OrderConditionComparator)GB(this->type, 5, 3); } /** Get the order to skip to. */ inline VehicleOrderID GetConditionSkipToOrder() const { return this->flags; } /** Get the value to base the skip on. */ inline uint16 GetConditionValue() const { return GB(this->dest, 0, 11); } /** Set how the consist must be loaded. */ inline void SetLoadType(OrderLoadFlags load_type) { SB(this->flags, 4, 3, load_type); } /** Set how the consist must be unloaded. */ inline void SetUnloadType(OrderUnloadFlags unload_type) { SB(this->flags, 0, 3, unload_type); } /** Set whether we must stop at stations or not. */ inline void SetNonStopType(OrderNonStopFlags non_stop_type) { SB(this->type, 6, 2, non_stop_type); } /** Set where we must stop at the platform. */ inline void SetStopLocation(OrderStopLocation stop_location) { SB(this->type, 4, 2, stop_location); } /** Set the cause to go to the depot. */ inline void SetDepotOrderType(OrderDepotTypeFlags depot_order_type) { SB(this->flags, 0, 3, depot_order_type); } /** Set what we are going to do in the depot. */ inline void SetDepotActionType(OrderDepotActionFlags depot_service_type) { SB(this->flags, 4, 3, depot_service_type); } /** Set variable we have to compare. */ inline void SetConditionVariable(OrderConditionVariable condition_variable) { SB(this->dest, 11, 5, condition_variable); } /** Set the comparator to use. */ inline void SetConditionComparator(OrderConditionComparator condition_comparator) { SB(this->type, 5, 3, condition_comparator); } /** Get the order to skip to. */ inline void SetConditionSkipToOrder(VehicleOrderID order_id) { this->flags = order_id; } /** Set the value to base the skip on. */ inline void SetConditionValue(uint16 value) { SB(this->dest, 0, 11, value); } /* As conditional orders write their "skip to" order all over the flags, we cannot check the * flags to find out if timetabling is enabled. However, as conditional orders are never * autofilled we can be sure that any non-zero values for their wait_time and travel_time are * explicitly set (but travel_time is actually unused for conditionals). */ /** Does this order have an explicit wait time set? */ inline bool IsWaitTimetabled() const { return this->IsType(OT_CONDITIONAL) ? this->wait_time > 0 : HasBit(this->flags, 3); } /** Does this order have an explicit travel time set? */ inline bool IsTravelTimetabled() const { return this->IsType(OT_CONDITIONAL) ? this->travel_time > 0 : HasBit(this->flags, 7); } /** Get the time in ticks a vehicle should wait at the destination or 0 if it's not timetabled. */ inline uint16 GetTimetabledWait() const { return this->IsWaitTimetabled() ? this->wait_time : 0; } /** Get the time in ticks a vehicle should take to reach the destination or 0 if it's not timetabled. */ inline uint16 GetTimetabledTravel() const { return this->IsTravelTimetabled() ? this->travel_time : 0; } /** Get the time in ticks a vehicle will probably wait at the destination (timetabled or not). */ inline uint16 GetWaitTime() const { return this->wait_time; } /** Get the time in ticks a vehicle will probably take to reach the destination (timetabled or not). */ inline uint16 GetTravelTime() const { return this->travel_time; } /** * Get the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the * destination. * @return maximum speed. */ inline uint16 GetMaxSpeed() const { return this->max_speed; } /** Set if the wait time is explicitly timetabled (unless the order is conditional). */ inline void SetWaitTimetabled(bool timetabled) { if (!this->IsType(OT_CONDITIONAL)) SB(this->flags, 3, 1, timetabled ? 1 : 0); } /** Set if the travel time is explicitly timetabled (unless the order is conditional). */ inline void SetTravelTimetabled(bool timetabled) { if (!this->IsType(OT_CONDITIONAL)) SB(this->flags, 7, 1, timetabled ? 1 : 0); } /** * Set the time in ticks to wait at the destination. * @param time Time to set as wait time. */ inline void SetWaitTime(uint16 time) { this->wait_time = time; } /** * Set the time in ticks to take for travelling to the destination. * @param time Time to set as travel time. */ inline void SetTravelTime(uint16 time) { this->travel_time = time; } /** * Set the maxmimum speed in km-ish/h a vehicle is allowed to reach on the way to the * destination. * @param speed Speed to be set. */ inline void SetMaxSpeed(uint16 speed) { this->max_speed = speed; } bool ShouldStopAtStation(const Vehicle *v, StationID station) const; bool CanLoadOrUnload() const; bool CanLeaveWithCargo(bool has_cargo) const; TileIndex GetLocation(const Vehicle *v, bool airport = false) const; /** Checks if travel_time and wait_time apply to this order and if they are timetabled. */ inline bool IsCompletelyTimetabled() const { if (!this->IsTravelTimetabled() && !this->IsType(OT_CONDITIONAL)) return false; if (!this->IsWaitTimetabled() && this->IsType(OT_GOTO_STATION) && !(this->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) { return false; } return true; } void AssignOrder(const Order &other); bool Equals(const Order &other) const; uint32 Pack() const; uint16 MapOldOrder() const; void ConvertFromOldSavegame(); }; void InsertOrder(Vehicle *v, Order *new_o, VehicleOrderID sel_ord); void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord); /** * Shared order list linking together the linked list of orders and the list * of vehicles sharing this order list. */ struct OrderList : OrderListPool::PoolItem<&_orderlist_pool> { private: friend void AfterLoadVehicles(bool part_of_load); ///< For instantiating the shared vehicle chain friend const struct SaveLoad *GetOrderListDescription(); ///< Saving and loading of order lists. StationID GetBestLoadableNext(const Vehicle *v, const Order *o1, const Order *o2) const; Order *first; ///< First order of the order list. VehicleOrderID num_orders; ///< NOSAVE: How many orders there are in the list. VehicleOrderID num_manual_orders; ///< NOSAVE: How many manually added orders are there in the list. uint num_vehicles; ///< NOSAVE: Number of vehicles that share this order list. Vehicle *first_shared; ///< NOSAVE: pointer to the first vehicle in the shared order chain. Ticks timetable_duration; ///< NOSAVE: Total timetabled duration of the order list. Ticks total_duration; ///< NOSAVE: Total (timetabled or not) duration of the order list. public: /** Default constructor producing an invalid order list. */ OrderList(VehicleOrderID num_orders = INVALID_VEH_ORDER_ID) : first(NULL), num_orders(num_orders), num_manual_orders(0), num_vehicles(0), first_shared(NULL), timetable_duration(0), total_duration(0) { } /** * Create an order list with the given order chain for the given vehicle. * @param chain pointer to the first order of the order chain * @param v any vehicle using this orderlist */ OrderList(Order *chain, Vehicle *v) { this->Initialize(chain, v); } /** Destructor. Invalidates OrderList for re-usage by the pool. */ ~OrderList() {} void Initialize(Order *chain, Vehicle *v); /** * Get the first order of the order chain. * @return the first order of the chain. */ inline Order *GetFirstOrder() const { return this->first; } Order *GetOrderAt(int index) const; /** * Get the last order of the order chain. * @return the last order of the chain. */ inline Order *GetLastOrder() const { return this->GetOrderAt(this->num_orders - 1); } /** * Get the order after the given one or the first one, if the given one is the * last one. * @param curr Order to find the next one for. * @return Next order. */ inline const Order *GetNext(const Order *curr) const { return (curr->next == NULL) ? this->GetFirstOrder() : curr->next; } /** * Get number of orders in the order list. * @return number of orders in the chain. */ inline VehicleOrderID GetNumOrders() const { return this->num_orders; } /** * Get number of manually added orders in the order list. * @return number of manual orders in the chain. */ inline VehicleOrderID GetNumManualOrders() const { return this->num_manual_orders; } StationIDStack GetNextStoppingStation(const Vehicle *v, const Order *first = NULL, uint hops = 0) const; const Order *GetNextDecisionNode(const Order *next, uint hops) const; void InsertOrderAt(Order *new_order, int index); void DeleteOrderAt(int index); void MoveOrder(int from, int to); /** * Is this a shared order list? * @return whether this order list is shared among multiple vehicles */ inline bool IsShared() const { return this->num_vehicles > 1; }; /** * Get the first vehicle of this vehicle chain. * @return the first vehicle of the chain. */ inline Vehicle *GetFirstSharedVehicle() const { return this->first_shared; } /** * Return the number of vehicles that share this orders list * @return the count of vehicles that use this shared orders list */ inline uint GetNumVehicles() const { return this->num_vehicles; } bool IsVehicleInSharedOrdersList(const Vehicle *v) const; int GetPositionInSharedOrderList(const Vehicle *v) const; /** * Adds the given vehicle to this shared order list. * @note This is supposed to be called after the vehicle has been inserted * into the shared vehicle chain. * @param v vehicle to add to the list */ inline void AddVehicle(Vehicle *v) { ++this->num_vehicles; } void RemoveVehicle(Vehicle *v); bool IsCompleteTimetable() const; /** * Gets the total duration of the vehicles timetable or INVALID_TICKS is the timetable is not complete. * @return total timetable duration or INVALID_TICKS for incomplete timetables */ inline Ticks GetTimetableTotalDuration() const { return this->IsCompleteTimetable() ? this->timetable_duration : INVALID_TICKS; } /** * Gets the known duration of the vehicles timetable even if the timetable is not complete. * @return known timetable duration */ inline Ticks GetTimetableDurationIncomplete() const { return this->timetable_duration; } /** * Gets the known duration of the vehicles orders, timetabled or not. * @return known order duration. */ inline Ticks GetTotalDuration() const { return this->total_duration; } /** * Must be called if an order's timetable is changed to update internal book keeping. * @param delta By how many ticks has the timetable duration changed */ void UpdateTimetableDuration(Ticks delta) { this->timetable_duration += delta; } /** * Must be called if an order's timetable is changed to update internal book keeping. * @param delta By how many ticks has the total duration changed */ void UpdateTotalDuration(Ticks delta) { this->total_duration += delta; } void FreeChain(bool keep_orderlist = false); void DebugCheckSanity() const; }; #define FOR_ALL_ORDERS_FROM(var, start) FOR_ALL_ITEMS_FROM(Order, order_index, var, start) #define FOR_ALL_ORDERS(var) FOR_ALL_ORDERS_FROM(var, 0) #define FOR_VEHICLE_ORDERS(v, order) for (order = (v->orders.list == NULL) ? NULL : v->orders.list->GetFirstOrder(); order != NULL; order = order->next) #define FOR_ALL_ORDER_LISTS_FROM(var, start) FOR_ALL_ITEMS_FROM(OrderList, orderlist_index, var, start) #define FOR_ALL_ORDER_LISTS(var) FOR_ALL_ORDER_LISTS_FROM(var, 0) #endif /* ORDER_BASE_H */ openttd-1.5.3/src/effectvehicle.cpp0000644000000000000000000003343612627373442016005 0ustar rootroot/* $Id: effectvehicle.cpp 26863 2014-09-20 15:31:26Z rubidium $ */ /* * 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 effectvehicle.cpp Implementation of everything generic to vehicles. */ #include "stdafx.h" #include "landscape.h" #include "core/random_func.hpp" #include "industry_map.h" #include "vehicle_func.h" #include "sound_func.h" #include "animated_tile_func.h" #include "effectvehicle_func.h" #include "effectvehicle_base.h" #include "safeguards.h" static void ChimneySmokeInit(EffectVehicle *v) { uint32 r = Random(); v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3); v->progress = GB(r, 16, 3); } static bool ChimneySmokeTick(EffectVehicle *v) { if (v->progress > 0) { v->progress--; } else { TileIndex tile = TileVirtXY(v->x_pos, v->y_pos); if (!IsTileType(tile, MP_INDUSTRY)) { delete v; return false; } if (v->cur_image != SPR_CHIMNEY_SMOKE_7) { v->cur_image++; } else { v->cur_image = SPR_CHIMNEY_SMOKE_0; } v->progress = 7; v->UpdatePositionAndViewport(); } return true; } static void SteamSmokeInit(EffectVehicle *v) { v->cur_image = SPR_STEAM_SMOKE_0; v->progress = 12; } static bool SteamSmokeTick(EffectVehicle *v) { bool moved = false; v->progress++; if ((v->progress & 7) == 0) { v->z_pos++; moved = true; } if ((v->progress & 0xF) == 4) { if (v->cur_image != SPR_STEAM_SMOKE_4) { v->cur_image++; } else { delete v; return false; } moved = true; } if (moved) v->UpdatePositionAndViewport(); return true; } static void DieselSmokeInit(EffectVehicle *v) { v->cur_image = SPR_DIESEL_SMOKE_0; v->progress = 0; } static bool DieselSmokeTick(EffectVehicle *v) { v->progress++; if ((v->progress & 3) == 0) { v->z_pos++; v->UpdatePositionAndViewport(); } else if ((v->progress & 7) == 1) { if (v->cur_image != SPR_DIESEL_SMOKE_5) { v->cur_image++; v->UpdatePositionAndViewport(); } else { delete v; return false; } } return true; } static void ElectricSparkInit(EffectVehicle *v) { v->cur_image = SPR_ELECTRIC_SPARK_0; v->progress = 1; } static bool ElectricSparkTick(EffectVehicle *v) { if (v->progress < 2) { v->progress++; } else { v->progress = 0; if (v->cur_image != SPR_ELECTRIC_SPARK_5) { v->cur_image++; v->UpdatePositionAndViewport(); } else { delete v; return false; } } return true; } static void SmokeInit(EffectVehicle *v) { v->cur_image = SPR_SMOKE_0; v->progress = 12; } static bool SmokeTick(EffectVehicle *v) { bool moved = false; v->progress++; if ((v->progress & 3) == 0) { v->z_pos++; moved = true; } if ((v->progress & 0xF) == 4) { if (v->cur_image != SPR_SMOKE_4) { v->cur_image++; } else { delete v; return false; } moved = true; } if (moved) v->UpdatePositionAndViewport(); return true; } static void ExplosionLargeInit(EffectVehicle *v) { v->cur_image = SPR_EXPLOSION_LARGE_0; v->progress = 0; } static bool ExplosionLargeTick(EffectVehicle *v) { v->progress++; if ((v->progress & 3) == 0) { if (v->cur_image != SPR_EXPLOSION_LARGE_F) { v->cur_image++; v->UpdatePositionAndViewport(); } else { delete v; return false; } } return true; } static void BreakdownSmokeInit(EffectVehicle *v) { v->cur_image = SPR_BREAKDOWN_SMOKE_0; v->progress = 0; } static bool BreakdownSmokeTick(EffectVehicle *v) { v->progress++; if ((v->progress & 7) == 0) { if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) { v->cur_image++; } else { v->cur_image = SPR_BREAKDOWN_SMOKE_0; } v->UpdatePositionAndViewport(); } v->animation_state--; if (v->animation_state == 0) { delete v; return false; } return true; } static void ExplosionSmallInit(EffectVehicle *v) { v->cur_image = SPR_EXPLOSION_SMALL_0; v->progress = 0; } static bool ExplosionSmallTick(EffectVehicle *v) { v->progress++; if ((v->progress & 3) == 0) { if (v->cur_image != SPR_EXPLOSION_SMALL_B) { v->cur_image++; v->UpdatePositionAndViewport(); } else { delete v; return false; } } return true; } static void BulldozerInit(EffectVehicle *v) { v->cur_image = SPR_BULLDOZER_NE; v->progress = 0; v->animation_state = 0; v->animation_substate = 0; } struct BulldozerMovement { byte direction:2; byte image:2; byte duration:3; }; static const BulldozerMovement _bulldozer_movement[] = { { 0, 0, 4 }, { 3, 3, 4 }, { 2, 2, 7 }, { 0, 2, 7 }, { 1, 1, 3 }, { 2, 2, 7 }, { 0, 2, 7 }, { 1, 1, 3 }, { 2, 2, 7 }, { 0, 2, 7 }, { 3, 3, 6 }, { 2, 2, 6 }, { 1, 1, 7 }, { 3, 1, 7 }, { 0, 0, 3 }, { 1, 1, 7 }, { 3, 1, 7 }, { 0, 0, 3 }, { 1, 1, 7 }, { 3, 1, 7 } }; static const struct { int8 x; int8 y; } _inc_by_dir[] = { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 } }; static bool BulldozerTick(EffectVehicle *v) { v->progress++; if ((v->progress & 7) == 0) { const BulldozerMovement *b = &_bulldozer_movement[v->animation_state]; v->cur_image = SPR_BULLDOZER_NE + b->image; v->x_pos += _inc_by_dir[b->direction].x; v->y_pos += _inc_by_dir[b->direction].y; v->animation_substate++; if (v->animation_substate >= b->duration) { v->animation_substate = 0; v->animation_state++; if (v->animation_state == lengthof(_bulldozer_movement)) { delete v; return false; } } v->UpdatePositionAndViewport(); } return true; } static void BubbleInit(EffectVehicle *v) { v->cur_image = SPR_BUBBLE_GENERATE_0; v->spritenum = 0; v->progress = 0; } struct BubbleMovement { int8 x:4; int8 y:4; int8 z:4; byte image:4; }; #define MK(x, y, z, i) { x, y, z, i } #define ME(i) { i, 4, 0, 0 } static const BubbleMovement _bubble_float_sw[] = { MK(0, 0, 1, 0), MK(1, 0, 1, 1), MK(0, 0, 1, 0), MK(1, 0, 1, 2), ME(1) }; static const BubbleMovement _bubble_float_ne[] = { MK( 0, 0, 1, 0), MK(-1, 0, 1, 1), MK( 0, 0, 1, 0), MK(-1, 0, 1, 2), ME(1) }; static const BubbleMovement _bubble_float_se[] = { MK(0, 0, 1, 0), MK(0, 1, 1, 1), MK(0, 0, 1, 0), MK(0, 1, 1, 2), ME(1) }; static const BubbleMovement _bubble_float_nw[] = { MK(0, 0, 1, 0), MK(0, -1, 1, 1), MK(0, 0, 1, 0), MK(0, -1, 1, 2), ME(1) }; static const BubbleMovement _bubble_burst[] = { MK(0, 0, 1, 2), MK(0, 0, 1, 7), MK(0, 0, 1, 8), MK(0, 0, 1, 9), ME(0) }; static const BubbleMovement _bubble_absorb[] = { MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(0, 0, 1, 0), MK(0, 0, 1, 2), MK(0, 0, 1, 0), MK(0, 0, 1, 1), MK(2, 1, 3, 0), MK(1, 1, 3, 1), MK(2, 1, 3, 0), MK(1, 1, 3, 2), MK(2, 1, 3, 0), MK(1, 1, 3, 1), MK(2, 1, 3, 0), MK(1, 0, 1, 2), MK(0, 0, 1, 0), MK(1, 0, 1, 1), MK(0, 0, 1, 0), MK(1, 0, 1, 2), MK(0, 0, 1, 0), MK(1, 0, 1, 1), MK(0, 0, 1, 0), MK(1, 0, 1, 2), ME(2), MK(0, 0, 0, 0xA), MK(0, 0, 0, 0xB), MK(0, 0, 0, 0xC), MK(0, 0, 0, 0xD), MK(0, 0, 0, 0xE), ME(0) }; #undef ME #undef MK static const BubbleMovement * const _bubble_movement[] = { _bubble_float_sw, _bubble_float_ne, _bubble_float_se, _bubble_float_nw, _bubble_burst, _bubble_absorb, }; static bool BubbleTick(EffectVehicle *v) { uint anim_state; v->progress++; if ((v->progress & 3) != 0) return true; if (v->spritenum == 0) { v->cur_image++; if (v->cur_image < SPR_BUBBLE_GENERATE_3) { v->UpdatePositionAndViewport(); return true; } if (v->animation_substate != 0) { v->spritenum = GB(Random(), 0, 2) + 1; } else { v->spritenum = 6; } anim_state = 0; } else { anim_state = v->animation_state + 1; } const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][anim_state]; if (b->y == 4 && b->x == 0) { delete v; return false; } if (b->y == 4 && b->x == 1) { if (v->z_pos > 180 || Chance16I(1, 96, Random())) { v->spritenum = 5; if (_settings_client.sound.ambient) SndPlayVehicleFx(SND_2F_POP, v); } anim_state = 0; } if (b->y == 4 && b->x == 2) { TileIndex tile; anim_state++; if (_settings_client.sound.ambient) SndPlayVehicleFx(SND_31_EXTRACT, v); tile = TileVirtXY(v->x_pos, v->y_pos); if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile); } v->animation_state = anim_state; b = &_bubble_movement[v->spritenum - 1][anim_state]; v->x_pos += b->x; v->y_pos += b->y; v->z_pos += b->z; v->cur_image = SPR_BUBBLE_0 + b->image; v->UpdatePositionAndViewport(); return true; } typedef void EffectInitProc(EffectVehicle *v); typedef bool EffectTickProc(EffectVehicle *v); /** Functions to initialise an effect vehicle after construction. */ static EffectInitProc * const _effect_init_procs[] = { ChimneySmokeInit, // EV_CHIMNEY_SMOKE SteamSmokeInit, // EV_STEAM_SMOKE DieselSmokeInit, // EV_DIESEL_SMOKE ElectricSparkInit, // EV_ELECTRIC_SPARK SmokeInit, // EV_CRASH_SMOKE ExplosionLargeInit, // EV_EXPLOSION_LARGE BreakdownSmokeInit, // EV_BREAKDOWN_SMOKE ExplosionSmallInit, // EV_EXPLOSION_SMALL BulldozerInit, // EV_BULLDOZER BubbleInit, // EV_BUBBLE SmokeInit, // EV_BREAKDOWN_SMOKE_AIRCRAFT SmokeInit, // EV_COPPER_MINE_SMOKE }; assert_compile(lengthof(_effect_init_procs) == EV_END); /** Functions for controlling effect vehicles at each tick. */ static EffectTickProc * const _effect_tick_procs[] = { ChimneySmokeTick, // EV_CHIMNEY_SMOKE SteamSmokeTick, // EV_STEAM_SMOKE DieselSmokeTick, // EV_DIESEL_SMOKE ElectricSparkTick, // EV_ELECTRIC_SPARK SmokeTick, // EV_CRASH_SMOKE ExplosionLargeTick, // EV_EXPLOSION_LARGE BreakdownSmokeTick, // EV_BREAKDOWN_SMOKE ExplosionSmallTick, // EV_EXPLOSION_SMALL BulldozerTick, // EV_BULLDOZER BubbleTick, // EV_BUBBLE SmokeTick, // EV_BREAKDOWN_SMOKE_AIRCRAFT SmokeTick, // EV_COPPER_MINE_SMOKE }; assert_compile(lengthof(_effect_tick_procs) == EV_END); /** Transparency options affecting the effects. */ static const TransparencyOption _effect_transparency_options[] = { TO_INDUSTRIES, // EV_CHIMNEY_SMOKE TO_INVALID, // EV_STEAM_SMOKE TO_INVALID, // EV_DIESEL_SMOKE TO_INVALID, // EV_ELECTRIC_SPARK TO_INVALID, // EV_CRASH_SMOKE TO_INVALID, // EV_EXPLOSION_LARGE TO_INVALID, // EV_BREAKDOWN_SMOKE TO_INVALID, // EV_EXPLOSION_SMALL TO_INVALID, // EV_BULLDOZER TO_INDUSTRIES, // EV_BUBBLE TO_INVALID, // EV_BREAKDOWN_SMOKE_AIRCRAFT TO_INDUSTRIES, // EV_COPPER_MINE_SMOKE }; assert_compile(lengthof(_effect_transparency_options) == EV_END); /** * Create an effect vehicle at a particular location. * @param x The x location on the map. * @param y The y location on the map. * @param z The z location on the map. * @param type The type of effect vehicle. * @return The effect vehicle. */ EffectVehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type) { if (!Vehicle::CanAllocateItem()) return NULL; EffectVehicle *v = new EffectVehicle(); v->subtype = type; v->x_pos = x; v->y_pos = y; v->z_pos = z; v->tile = 0; v->UpdateDeltaXY(INVALID_DIR); v->vehstatus = VS_UNCLICKABLE; _effect_init_procs[type](v); v->UpdatePositionAndViewport(); return v; } /** * Create an effect vehicle above a particular location. * @param x The x location on the map. * @param y The y location on the map. * @param z The offset from the ground. * @param type The type of effect vehicle. * @return The effect vehicle. */ EffectVehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type) { int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE); return CreateEffectVehicle(x, y, GetSlopePixelZ(safe_x, safe_y) + z, type); } /** * Create an effect vehicle above a particular vehicle. * @param v The vehicle to base the position on. * @param x The x offset to the vehicle. * @param y The y offset to the vehicle. * @param z The z offset to the vehicle. * @param type The type of effect vehicle. * @return The effect vehicle. */ EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type) { return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type); } bool EffectVehicle::Tick() { return _effect_tick_procs[this->subtype](this); } void EffectVehicle::UpdateDeltaXY(Direction direction) { this->x_offs = 0; this->y_offs = 0; this->x_extent = 1; this->y_extent = 1; this->z_extent = 1; } /** * Determines the transparency option affecting the effect. * @return Transparency option, or TO_INVALID if none. */ TransparencyOption EffectVehicle::GetTransparencyOption() const { return _effect_transparency_options[this->subtype]; } openttd-1.5.3/src/sound_func.h0000644000000000000000000000175412627373442015017 0ustar rootroot/* $Id: sound_func.h 22202 2011-03-05 18:00:48Z rubidium $ */ /* * 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 sound_func.h Functions related to sound. */ #ifndef SOUND_FUNC_H #define SOUND_FUNC_H #include "sound_type.h" #include "vehicle_type.h" #include "tile_type.h" void SndPlayTileFx(SoundID sound, TileIndex tile); void SndPlayVehicleFx(SoundID sound, const Vehicle *v); void SndPlayFx(SoundID sound); void SndCopyToPool(); #endif /* SOUND_FUNC_H */ openttd-1.5.3/src/map_func.h0000644000000000000000000002660212627373441014442 0ustar rootroot/* $Id: map_func.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 map_func.h Functions related to maps. */ #ifndef MAP_FUNC_H #define MAP_FUNC_H #include "core/math_func.hpp" #include "tile_type.h" #include "map_type.h" #include "direction_func.h" extern uint _map_tile_mask; /** * 'Wraps' the given tile to it is within the map. It does * this by masking the 'high' bits of. * @param x the tile to 'wrap' */ #define TILE_MASK(x) ((x) & _map_tile_mask) /** * Pointer to the tile-array. * * This variable points to the tile-array which contains the tiles of * the map. */ extern Tile *_m; /** * Pointer to the extended tile-array. * * This variable points to the extended tile-array which contains the tiles * of the map. */ extern TileExtended *_me; void AllocateMap(uint size_x, uint size_y); /** * Logarithm of the map size along the X side. * @note try to avoid using this one * @return 2^"return value" == MapSizeX() */ static inline uint MapLogX() { extern uint _map_log_x; return _map_log_x; } /** * Logarithm of the map size along the y side. * @note try to avoid using this one * @return 2^"return value" == MapSizeY() */ static inline uint MapLogY() { extern uint _map_log_y; return _map_log_y; } /** * Get the size of the map along the X * @return the number of tiles along the X of the map */ static inline uint MapSizeX() { extern uint _map_size_x; return _map_size_x; } /** * Get the size of the map along the Y * @return the number of tiles along the Y of the map */ static inline uint MapSizeY() { extern uint _map_size_y; return _map_size_y; } /** * Get the size of the map * @return the number of tiles of the map */ static inline uint MapSize() { extern uint _map_size; return _map_size; } /** * Gets the maximum X coordinate within the map, including MP_VOID * @return the maximum X coordinate */ static inline uint MapMaxX() { return MapSizeX() - 1; } /** * Gets the maximum Y coordinate within the map, including MP_VOID * @return the maximum Y coordinate */ static inline uint MapMaxY() { return MapSizeY() - 1; } /** * Scales the given value by the map size, where the given value is * for a 256 by 256 map. * @param n the value to scale * @return the scaled size */ static inline uint ScaleByMapSize(uint n) { /* Subtract 12 from shift in order to prevent integer overflow * for large values of n. It's safe since the min mapsize is 64x64. */ return CeilDiv(n << (MapLogX() + MapLogY() - 12), 1 << 4); } /** * Scales the given value by the maps circumference, where the given * value is for a 256 by 256 map * @param n the value to scale * @return the scaled size */ static inline uint ScaleByMapSize1D(uint n) { /* Normal circumference for the X+Y is 256+256 = 1<<9 * Note, not actually taking the full circumference into account, * just half of it. */ return CeilDiv((n << MapLogX()) + (n << MapLogY()), 1 << 9); } /** * An offset value between to tiles. * * This value is used for the difference between * to tiles. It can be added to a tileindex to get * the resulting tileindex of the start tile applied * with this saved difference. * * @see TileDiffXY(int, int) */ typedef int32 TileIndexDiff; /** * Returns the TileIndex of a coordinate. * * @param x The x coordinate of the tile * @param y The y coordinate of the tile * @return The TileIndex calculated by the coordinate */ static inline TileIndex TileXY(uint x, uint y) { return (y << MapLogX()) + x; } /** * Calculates an offset for the given coordinate(-offset). * * This function calculate an offset value which can be added to an * #TileIndex. The coordinates can be negative. * * @param x The offset in x direction * @param y The offset in y direction * @return The resulting offset value of the given coordinate * @see ToTileIndexDiff(TileIndexDiffC) */ static inline TileIndexDiff TileDiffXY(int x, int y) { /* Multiplication gives much better optimization on MSVC than shifting. * 0 << shift isn't optimized to 0 properly. * Typically x and y are constants, and then this doesn't result * in any actual multiplication in the assembly code.. */ return (y * MapSizeX()) + x; } /** * Get a tile from the virtual XY-coordinate. * @param x The virtual x coordinate of the tile. * @param y The virtual y coordinate of the tile. * @return The TileIndex calculated by the coordinate. */ static inline TileIndex TileVirtXY(uint x, uint y) { return (y >> 4 << MapLogX()) + (x >> 4); } /** * Get the X component of a tile * @param tile the tile to get the X component of * @return the X component */ static inline uint TileX(TileIndex tile) { return tile & MapMaxX(); } /** * Get the Y component of a tile * @param tile the tile to get the Y component of * @return the Y component */ static inline uint TileY(TileIndex tile) { return tile >> MapLogX(); } /** * Return the offset between to tiles from a TileIndexDiffC struct. * * This function works like #TileDiffXY(int, int) and returns the * difference between two tiles. * * @param tidc The coordinate of the offset as TileIndexDiffC * @return The difference between two tiles. * @see TileDiffXY(int, int) */ static inline TileIndexDiff ToTileIndexDiff(TileIndexDiffC tidc) { return (tidc.y << MapLogX()) + tidc.x; } #ifndef _DEBUG /** * Adds to tiles together. * * @param x One tile * @param y Another tile to add * @return The resulting tile(index) */ #define TILE_ADD(x, y) ((x) + (y)) #else extern TileIndex TileAdd(TileIndex tile, TileIndexDiff add, const char *exp, const char *file, int line); #define TILE_ADD(x, y) (TileAdd((x), (y), #x " + " #y, __FILE__, __LINE__)) #endif /** * Adds a given offset to a tile. * * @param tile The tile to add an offset on it * @param x The x offset to add to the tile * @param y The y offset to add to the tile */ #define TILE_ADDXY(tile, x, y) TILE_ADD(tile, TileDiffXY(x, y)) TileIndex TileAddWrap(TileIndex tile, int addx, int addy); /** * Returns the TileIndexDiffC offset from a DiagDirection. * * @param dir The given direction * @return The offset as TileIndexDiffC value */ static inline TileIndexDiffC TileIndexDiffCByDiagDir(DiagDirection dir) { extern const TileIndexDiffC _tileoffs_by_diagdir[DIAGDIR_END]; assert(IsValidDiagDirection(dir)); return _tileoffs_by_diagdir[dir]; } /** * Returns the TileIndexDiffC offset from a Direction. * * @param dir The given direction * @return The offset as TileIndexDiffC value */ static inline TileIndexDiffC TileIndexDiffCByDir(Direction dir) { extern const TileIndexDiffC _tileoffs_by_dir[DIR_END]; assert(IsValidDirection(dir)); return _tileoffs_by_dir[dir]; } /** * Add a TileIndexDiffC to a TileIndex and returns the new one. * * Returns tile + the diff given in diff. If the result tile would end up * outside of the map, INVALID_TILE is returned instead. * * @param tile The base tile to add the offset on * @param diff The offset to add on the tile * @return The resulting TileIndex */ static inline TileIndex AddTileIndexDiffCWrap(TileIndex tile, TileIndexDiffC diff) { int x = TileX(tile) + diff.x; int y = TileY(tile) + diff.y; /* Negative value will become big positive value after cast */ if ((uint)x >= MapSizeX() || (uint)y >= MapSizeY()) return INVALID_TILE; return TileXY(x, y); } /** * Returns the diff between two tiles * * @param tile_a from tile * @param tile_b to tile * @return the difference between tila_a and tile_b */ static inline TileIndexDiffC TileIndexToTileIndexDiffC(TileIndex tile_a, TileIndex tile_b) { TileIndexDiffC difference; difference.x = TileX(tile_a) - TileX(tile_b); difference.y = TileY(tile_a) - TileY(tile_b); return difference; } /* Functions to calculate distances */ uint DistanceManhattan(TileIndex, TileIndex); ///< also known as L1-Norm. Is the shortest distance one could go over diagonal tracks (or roads) uint DistanceSquare(TileIndex, TileIndex); ///< euclidian- or L2-Norm squared uint DistanceMax(TileIndex, TileIndex); ///< also known as L-Infinity-Norm uint DistanceMaxPlusManhattan(TileIndex, TileIndex); ///< Max + Manhattan uint DistanceFromEdge(TileIndex); ///< shortest distance from any edge of the map uint DistanceFromEdgeDir(TileIndex, DiagDirection); ///< distance from the map edge in given direction /** * Convert a DiagDirection to a TileIndexDiff * * @param dir The DiagDirection * @return The resulting TileIndexDiff * @see TileIndexDiffCByDiagDir */ static inline TileIndexDiff TileOffsByDiagDir(DiagDirection dir) { extern const TileIndexDiffC _tileoffs_by_diagdir[DIAGDIR_END]; assert(IsValidDiagDirection(dir)); return ToTileIndexDiff(_tileoffs_by_diagdir[dir]); } /** * Convert a Direction to a TileIndexDiff. * * @param dir The direction to convert from * @return The resulting TileIndexDiff */ static inline TileIndexDiff TileOffsByDir(Direction dir) { extern const TileIndexDiffC _tileoffs_by_dir[DIR_END]; assert(IsValidDirection(dir)); return ToTileIndexDiff(_tileoffs_by_dir[dir]); } /** * Adds a DiagDir to a tile. * * @param tile The current tile * @param dir The direction in which we want to step * @return the moved tile */ static inline TileIndex TileAddByDiagDir(TileIndex tile, DiagDirection dir) { return TILE_ADD(tile, TileOffsByDiagDir(dir)); } /** * Determines the DiagDirection to get from one tile to another. * The tiles do not necessarily have to be adjacent. * @param tile_from Origin tile * @param tile_to Destination tile * @return DiagDirection from tile_from towards tile_to, or INVALID_DIAGDIR if the tiles are not on an axis */ static inline DiagDirection DiagdirBetweenTiles(TileIndex tile_from, TileIndex tile_to) { int dx = (int)TileX(tile_to) - (int)TileX(tile_from); int dy = (int)TileY(tile_to) - (int)TileY(tile_from); if (dx == 0) { if (dy == 0) return INVALID_DIAGDIR; return (dy < 0 ? DIAGDIR_NW : DIAGDIR_SE); } else { if (dy != 0) return INVALID_DIAGDIR; return (dx < 0 ? DIAGDIR_NE : DIAGDIR_SW); } } /** * A callback function type for searching tiles. * * @param tile The tile to test * @param user_data additional data for the callback function to use * @return A boolean value, depend on the definition of the function. */ typedef bool TestTileOnSearchProc(TileIndex tile, void *user_data); bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data); bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOnSearchProc proc, void *user_data); /** * Get a random tile out of a given seed. * @param r the random 'seed' * @return a valid tile */ static inline TileIndex RandomTileSeed(uint32 r) { return TILE_MASK(r); } /** * Get a valid random tile. * @note a define so 'random' gets inserted in the place where it is actually * called, thus making the random traces more explicit. * @return a valid tile */ #define RandomTile() RandomTileSeed(Random()) uint GetClosestWaterDistance(TileIndex tile, bool water); #endif /* MAP_FUNC_H */ openttd-1.5.3/src/gamelog.cpp0000644000000000000000000005657512627373435014637 0ustar rootroot/* $Id: gamelog.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 gamelog.cpp Definition of functions used for logging of important changes in the game */ #include "stdafx.h" #include "saveload/saveload.h" #include "string_func.h" #include "settings_type.h" #include "gamelog_internal.h" #include "console_func.h" #include "debug.h" #include "date_func.h" #include "rev.h" #include #include "safeguards.h" extern const uint16 SAVEGAME_VERSION; ///< current savegame version extern SavegameType _savegame_type; ///< type of savegame we are loading extern uint32 _ttdp_version; ///< version of TTDP savegame (if applicable) extern uint16 _sl_version; ///< the major savegame version identifier extern byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! static GamelogActionType _gamelog_action_type = GLAT_NONE; ///< action to record if anything changes LoggedAction *_gamelog_action = NULL; ///< first logged action uint _gamelog_actions = 0; ///< number of actions static LoggedAction *_current_action = NULL; ///< current action we are logging, NULL when there is no action active /** * Stores information about new action, but doesn't allocate it * Action is allocated only when there is at least one change * @param at type of action */ void GamelogStartAction(GamelogActionType at) { assert(_gamelog_action_type == GLAT_NONE); // do not allow starting new action without stopping the previous first _gamelog_action_type = at; } /** * Stops logging of any changes */ void GamelogStopAction() { assert(_gamelog_action_type != GLAT_NONE); // nobody should try to stop if there is no action in progress bool print = _current_action != NULL; _current_action = NULL; _gamelog_action_type = GLAT_NONE; if (print) GamelogPrintDebug(5); } /** * Frees the memory allocated by a gamelog */ void GamelogFree(LoggedAction *gamelog_action, uint gamelog_actions) { for (uint i = 0; i < gamelog_actions; i++) { const LoggedAction *la = &gamelog_action[i]; for (uint j = 0; j < la->changes; j++) { const LoggedChange *lc = &la->change[j]; if (lc->ct == GLCT_SETTING) free(lc->setting.name); } free(la->change); } free(gamelog_action); } /** * Resets and frees all memory allocated - used before loading or starting a new game */ void GamelogReset() { assert(_gamelog_action_type == GLAT_NONE); GamelogFree(_gamelog_action, _gamelog_actions); _gamelog_action = NULL; _gamelog_actions = 0; _current_action = NULL; } /** * Prints GRF ID, checksum and filename if found * @param buf The location in the buffer to draw * @param last The end of the buffer * @param grfid GRF ID * @param md5sum array of md5sum to print, if known * @param gc GrfConfig, if known * @return The buffer location. */ static char *PrintGrfInfo(char *buf, const char *last, uint grfid, const uint8 *md5sum, const GRFConfig *gc) { char txt[40]; if (md5sum != NULL) { md5sumToString(txt, lastof(txt), md5sum); buf += seprintf(buf, last, "GRF ID %08X, checksum %s", BSWAP32(grfid), txt); } else { buf += seprintf(buf, last, "GRF ID %08X", BSWAP32(grfid)); } if (gc != NULL) { buf += seprintf(buf, last, ", filename: %s (md5sum matches)", gc->filename); } else { gc = FindGRFConfig(grfid, FGCM_ANY); if (gc != NULL) { buf += seprintf(buf, last, ", filename: %s (matches GRFID only)", gc->filename); } else { buf += seprintf(buf, last, ", unknown GRF"); } } return buf; } /** Text messages for various logged actions */ static const char * const la_text[] = { "new game started", "game loaded", "GRF config changed", "cheat was used", "settings changed", "GRF bug triggered", "emergency savegame", }; assert_compile(lengthof(la_text) == GLAT_END); /** * Information about the presence of a Grf at a certain point during gamelog history * Note about missing Grfs: * Changes to missing Grfs are not logged including manual removal of the Grf. * So if the gamelog tells a Grf is missing we do not know whether it was readded or completely removed * at some later point. */ struct GRFPresence{ const GRFConfig *gc; ///< GRFConfig, if known bool was_missing; ///< Grf was missing during some gameload in the past GRFPresence(const GRFConfig *gc) : gc(gc), was_missing(false) {} }; typedef SmallMap GrfIDMapping; /** * Prints active gamelog * @param proc the procedure to draw with */ void GamelogPrint(GamelogPrintProc *proc) { char buffer[1024]; GrfIDMapping grf_names; proc("---- gamelog start ----"); const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { assert((uint)la->at < GLAT_END); seprintf(buffer, lastof(buffer), "Tick %u: %s", (uint)la->tick, la_text[(uint)la->at]); proc(buffer); const LoggedChange *lcend = &la->change[la->changes]; for (const LoggedChange *lc = la->change; lc != lcend; lc++) { char *buf = buffer; switch (lc->ct) { default: NOT_REACHED(); case GLCT_MODE: buf += seprintf(buf, lastof(buffer), "New game mode: %u landscape: %u", (uint)lc->mode.mode, (uint)lc->mode.landscape); break; case GLCT_REVISION: buf += seprintf(buf, lastof(buffer), "Revision text changed to %s, savegame version %u, ", lc->revision.text, lc->revision.slver); switch (lc->revision.modified) { case 0: buf += seprintf(buf, lastof(buffer), "not "); break; case 1: buf += seprintf(buf, lastof(buffer), "maybe "); break; default: break; } buf += seprintf(buf, lastof(buffer), "modified, _openttd_newgrf_version = 0x%08x", lc->revision.newgrf); break; case GLCT_OLDVER: buf += seprintf(buf, lastof(buffer), "Conversion from "); switch (lc->oldver.type) { default: NOT_REACHED(); case SGT_OTTD: buf += seprintf(buf, lastof(buffer), "OTTD savegame without gamelog: version %u, %u", GB(lc->oldver.version, 8, 16), GB(lc->oldver.version, 0, 8)); break; case SGT_TTO: buf += seprintf(buf, lastof(buffer), "TTO savegame"); break; case SGT_TTD: buf += seprintf(buf, lastof(buffer), "TTD savegame"); break; case SGT_TTDP1: case SGT_TTDP2: buf += seprintf(buf, lastof(buffer), "TTDP savegame, %s format", lc->oldver.type == SGT_TTDP1 ? "old" : "new"); if (lc->oldver.version != 0) { buf += seprintf(buf, lastof(buffer), ", TTDP version %u.%u.%u.%u", GB(lc->oldver.version, 24, 8), GB(lc->oldver.version, 20, 4), GB(lc->oldver.version, 16, 4), GB(lc->oldver.version, 0, 16)); } break; } break; case GLCT_SETTING: buf += seprintf(buf, lastof(buffer), "Setting changed: %s : %d -> %d", lc->setting.name, lc->setting.oldval, lc->setting.newval); break; case GLCT_GRFADD: { const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum); buf += seprintf(buf, lastof(buffer), "Added NewGRF: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfadd.grfid, lc->grfadd.md5sum, gc); GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); if (gm != grf_names.End() && !gm->second.was_missing) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was already added!"); grf_names[lc->grfadd.grfid] = gc; break; } case GLCT_GRFREM: { GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), la->at == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfrem.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); if (gm == grf_names.End()) { buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); } else { if (la->at == GLAT_LOAD) { /* Missing grfs on load are not removed from the configuration */ gm->second.was_missing = true; } else { grf_names.Erase(gm); } } break; } case GLCT_GRFCOMPAT: { const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum); buf += seprintf(buf, lastof(buffer), "Compatible NewGRF loaded: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfcompat.grfid, lc->grfcompat.md5sum, gc); if (!grf_names.Contains(lc->grfcompat.grfid)) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); grf_names[lc->grfcompat.grfid] = gc; break; } case GLCT_GRFPARAM: { GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), "GRF parameter changed: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfparam.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); break; } case GLCT_GRFMOVE: { GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), "GRF order changed: %08X moved %d places %s", BSWAP32(lc->grfmove.grfid), abs(lc->grfmove.offset), lc->grfmove.offset >= 0 ? "down" : "up" ); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfmove.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); break; } case GLCT_GRFBUG: { GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); switch (lc->grfbug.bug) { default: NOT_REACHED(); case GBUG_VEH_LENGTH: buf += seprintf(buf, lastof(buffer), "Rail vehicle changes length outside a depot: GRF ID %08X, internal ID 0x%X", BSWAP32(lc->grfbug.grfid), (uint)lc->grfbug.data); break; } buf = PrintGrfInfo(buf, lastof(buffer), lc->grfbug.grfid, NULL, gm != grf_names.End() ? gm->second.gc : NULL); if (gm == grf_names.End()) buf += seprintf(buf, lastof(buffer), ". Gamelog inconsistency: GrfID was never added!"); break; } case GLCT_EMERGENCY: break; } proc(buffer); } } proc("---- gamelog end ----"); } static void GamelogPrintConsoleProc(const char *s) { IConsolePrint(CC_WARNING, s); } /** Print the gamelog data to the console. */ void GamelogPrintConsole() { GamelogPrint(&GamelogPrintConsoleProc); } static int _gamelog_print_level = 0; ///< gamelog debug level we need to print stuff static void GamelogPrintDebugProc(const char *s) { DEBUG(gamelog, _gamelog_print_level, "%s", s); } /** * Prints gamelog to debug output. Code is executed even when * there will be no output. It is called very seldom, so it * doesn't matter that much. At least it gives more uniform code... * @param level debug level we need to print stuff */ void GamelogPrintDebug(int level) { _gamelog_print_level = level; GamelogPrint(&GamelogPrintDebugProc); } /** * Allocates new LoggedChange and new LoggedAction if needed. * If there is no action active, NULL is returned. * @param ct type of change * @return new LoggedChange, or NULL if there is no action active */ static LoggedChange *GamelogChange(GamelogChangeType ct) { if (_current_action == NULL) { if (_gamelog_action_type == GLAT_NONE) return NULL; _gamelog_action = ReallocT(_gamelog_action, _gamelog_actions + 1); _current_action = &_gamelog_action[_gamelog_actions++]; _current_action->at = _gamelog_action_type; _current_action->tick = _tick_counter; _current_action->change = NULL; _current_action->changes = 0; } _current_action->change = ReallocT(_current_action->change, _current_action->changes + 1); LoggedChange *lc = &_current_action->change[_current_action->changes++]; lc->ct = ct; return lc; } /** * Logs a emergency savegame */ void GamelogEmergency() { /* Terminate any active action */ if (_gamelog_action_type != GLAT_NONE) GamelogStopAction(); GamelogStartAction(GLAT_EMERGENCY); GamelogChange(GLCT_EMERGENCY); GamelogStopAction(); } /** * Finds out if current game is a loaded emergency savegame. */ bool GamelogTestEmergency() { const LoggedChange *emergency = NULL; const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { const LoggedChange *lcend = &la->change[la->changes]; for (const LoggedChange *lc = la->change; lc != lcend; lc++) { if (lc->ct == GLCT_EMERGENCY) emergency = lc; } } return (emergency != NULL); } /** * Logs a change in game revision */ void GamelogRevision() { assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD); LoggedChange *lc = GamelogChange(GLCT_REVISION); if (lc == NULL) return; memset(lc->revision.text, 0, sizeof(lc->revision.text)); strecpy(lc->revision.text, _openttd_revision, lastof(lc->revision.text)); lc->revision.slver = SAVEGAME_VERSION; lc->revision.modified = _openttd_revision_modified; lc->revision.newgrf = _openttd_newgrf_version; } /** * Logs a change in game mode (scenario editor or game) */ void GamelogMode() { assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_CHEAT); LoggedChange *lc = GamelogChange(GLCT_MODE); if (lc == NULL) return; lc->mode.mode = _game_mode; lc->mode.landscape = _settings_game.game_creation.landscape; } /** * Logs loading from savegame without gamelog */ void GamelogOldver() { assert(_gamelog_action_type == GLAT_LOAD); LoggedChange *lc = GamelogChange(GLCT_OLDVER); if (lc == NULL) return; lc->oldver.type = _savegame_type; lc->oldver.version = (_savegame_type == SGT_OTTD ? ((uint32)_sl_version << 8 | _sl_minor_version) : _ttdp_version); } /** * Logs change in game settings. Only non-networksafe settings are logged * @param name setting name * @param oldval old setting value * @param newval new setting value */ void GamelogSetting(const char *name, int32 oldval, int32 newval) { assert(_gamelog_action_type == GLAT_SETTING); LoggedChange *lc = GamelogChange(GLCT_SETTING); if (lc == NULL) return; lc->setting.name = stredup(name); lc->setting.oldval = oldval; lc->setting.newval = newval; } /** * Finds out if current revision is different than last revision stored in the savegame. * Appends GLCT_REVISION when the revision string changed */ void GamelogTestRevision() { const LoggedChange *rev = NULL; const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { const LoggedChange *lcend = &la->change[la->changes]; for (const LoggedChange *lc = la->change; lc != lcend; lc++) { if (lc->ct == GLCT_REVISION) rev = lc; } } if (rev == NULL || strcmp(rev->revision.text, _openttd_revision) != 0 || rev->revision.modified != _openttd_revision_modified || rev->revision.newgrf != _openttd_newgrf_version) { GamelogRevision(); } } /** * Finds last stored game mode or landscape. * Any change is logged */ void GamelogTestMode() { const LoggedChange *mode = NULL; const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { const LoggedChange *lcend = &la->change[la->changes]; for (const LoggedChange *lc = la->change; lc != lcend; lc++) { if (lc->ct == GLCT_MODE) mode = lc; } } if (mode == NULL || mode->mode.mode != _game_mode || mode->mode.landscape != _settings_game.game_creation.landscape) GamelogMode(); } /** * Logs triggered GRF bug. * @param grfid ID of problematic GRF * @param bug type of bug, @see enum GRFBugs * @param data additional data */ static void GamelogGRFBug(uint32 grfid, byte bug, uint64 data) { assert(_gamelog_action_type == GLAT_GRFBUG); LoggedChange *lc = GamelogChange(GLCT_GRFBUG); if (lc == NULL) return; lc->grfbug.data = data; lc->grfbug.grfid = grfid; lc->grfbug.bug = bug; } /** * Logs GRF bug - rail vehicle has different length after reversing. * Ensures this is logged only once for each GRF and engine type * This check takes some time, but it is called pretty seldom, so it * doesn't matter that much (ideally it shouldn't be called at all). * @param grfid the broken NewGRF * @param internal_id the internal ID of whatever's broken in the NewGRF * @return true iff a unique record was done */ bool GamelogGRFBugReverse(uint32 grfid, uint16 internal_id) { const LoggedAction *laend = &_gamelog_action[_gamelog_actions]; for (const LoggedAction *la = _gamelog_action; la != laend; la++) { const LoggedChange *lcend = &la->change[la->changes]; for (const LoggedChange *lc = la->change; lc != lcend; lc++) { if (lc->ct == GLCT_GRFBUG && lc->grfbug.grfid == grfid && lc->grfbug.bug == GBUG_VEH_LENGTH && lc->grfbug.data == internal_id) { return false; } } } GamelogStartAction(GLAT_GRFBUG); GamelogGRFBug(grfid, GBUG_VEH_LENGTH, internal_id); GamelogStopAction(); return true; } /** * Decides if GRF should be logged * @param g grf to determine * @return true iff GRF is not static and is loaded */ static inline bool IsLoggableGrfConfig(const GRFConfig *g) { return !HasBit(g->flags, GCF_STATIC) && g->status != GCS_NOT_FOUND; } /** * Logs removal of a GRF * @param grfid ID of removed GRF */ void GamelogGRFRemove(uint32 grfid) { assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFREM); if (lc == NULL) return; lc->grfrem.grfid = grfid; } /** * Logs adding of a GRF * @param newg added GRF */ void GamelogGRFAdd(const GRFConfig *newg) { assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_GRF); if (!IsLoggableGrfConfig(newg)) return; LoggedChange *lc = GamelogChange(GLCT_GRFADD); if (lc == NULL) return; lc->grfadd = newg->ident; } /** * Logs loading compatible GRF * (the same ID, but different MD5 hash) * @param newg new (updated) GRF */ void GamelogGRFCompatible(const GRFIdentifier *newg) { assert(_gamelog_action_type == GLAT_LOAD || _gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFCOMPAT); if (lc == NULL) return; lc->grfcompat = *newg; } /** * Logs changing GRF order * @param grfid GRF that is moved * @param offset how far it is moved, positive = moved down */ static void GamelogGRFMove(uint32 grfid, int32 offset) { assert(_gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFMOVE); if (lc == NULL) return; lc->grfmove.grfid = grfid; lc->grfmove.offset = offset; } /** * Logs change in GRF parameters. * Details about parameters changed are not stored * @param grfid ID of GRF to store */ static void GamelogGRFParameters(uint32 grfid) { assert(_gamelog_action_type == GLAT_GRF); LoggedChange *lc = GamelogChange(GLCT_GRFPARAM); if (lc == NULL) return; lc->grfparam.grfid = grfid; } /** * Logs adding of list of GRFs. * Useful when old savegame is loaded or when new game is started * @param newg head of GRF linked list */ void GamelogGRFAddList(const GRFConfig *newg) { assert(_gamelog_action_type == GLAT_START || _gamelog_action_type == GLAT_LOAD); for (; newg != NULL; newg = newg->next) { GamelogGRFAdd(newg); } } /** List of GRFs using array of pointers instead of linked list */ struct GRFList { uint n; const GRFConfig *grf[]; }; /** * Generates GRFList * @param grfc head of GRF linked list */ static GRFList *GenerateGRFList(const GRFConfig *grfc) { uint n = 0; for (const GRFConfig *g = grfc; g != NULL; g = g->next) { if (IsLoggableGrfConfig(g)) n++; } GRFList *list = (GRFList*)MallocT(sizeof(GRFList) + n * sizeof(GRFConfig*)); list->n = 0; for (const GRFConfig *g = grfc; g != NULL; g = g->next) { if (IsLoggableGrfConfig(g)) list->grf[list->n++] = g; } return list; } /** * Compares two NewGRF lists and logs any change * @param oldc original GRF list * @param newc new GRF list */ void GamelogGRFUpdate(const GRFConfig *oldc, const GRFConfig *newc) { GRFList *ol = GenerateGRFList(oldc); GRFList *nl = GenerateGRFList(newc); uint o = 0, n = 0; while (o < ol->n && n < nl->n) { const GRFConfig *og = ol->grf[o]; const GRFConfig *ng = nl->grf[n]; if (og->ident.grfid != ng->ident.grfid) { uint oi, ni; for (oi = 0; oi < ol->n; oi++) { if (ol->grf[oi]->ident.grfid == nl->grf[n]->ident.grfid) break; } if (oi < o) { /* GRF was moved, this change has been logged already */ n++; continue; } if (oi == ol->n) { /* GRF couldn't be found in the OLD list, GRF was ADDED */ GamelogGRFAdd(nl->grf[n++]); continue; } for (ni = 0; ni < nl->n; ni++) { if (nl->grf[ni]->ident.grfid == ol->grf[o]->ident.grfid) break; } if (ni < n) { /* GRF was moved, this change has been logged already */ o++; continue; } if (ni == nl->n) { /* GRF couldn't be found in the NEW list, GRF was REMOVED */ GamelogGRFRemove(ol->grf[o++]->ident.grfid); continue; } /* o < oi < ol->n * n < ni < nl->n */ assert(ni > n && ni < nl->n); assert(oi > o && oi < ol->n); ni -= n; // number of GRFs it was moved downwards oi -= o; // number of GRFs it was moved upwards if (ni >= oi) { // prefer the one that is moved further /* GRF was moved down */ GamelogGRFMove(ol->grf[o++]->ident.grfid, ni); } else { GamelogGRFMove(nl->grf[n++]->ident.grfid, -(int)oi); } } else { if (memcmp(og->ident.md5sum, ng->ident.md5sum, sizeof(og->ident.md5sum)) != 0) { /* md5sum changed, probably loading 'compatible' GRF */ GamelogGRFCompatible(&nl->grf[n]->ident); } if (og->num_params != ng->num_params || memcmp(og->param, ng->param, og->num_params * sizeof(og->param[0])) != 0) { GamelogGRFParameters(ol->grf[o]->ident.grfid); } o++; n++; } } while (o < ol->n) GamelogGRFRemove(ol->grf[o++]->ident.grfid); // remaining GRFs were removed ... while (n < nl->n) GamelogGRFAdd (nl->grf[n++]); // ... or added free(ol); free(nl); } /** * Get some basic information from the given gamelog. * @param gamelog_action Pointer to the gamelog to extract information from. * @param gamelog_actions Number of actions in the given gamelog. * @param [out] last_ottd_rev OpenTTD NewGRF version from the binary that saved the savegame last. * @param [out] ever_modified Max value of 'modified' from all binaries that ever saved this savegame. * @param [out] removed_newgrfs Set to true if any NewGRFs have been removed. */ void GamelogInfo(LoggedAction *gamelog_action, uint gamelog_actions, uint32 *last_ottd_rev, byte *ever_modified, bool *removed_newgrfs) { const LoggedAction *laend = &gamelog_action[gamelog_actions]; for (const LoggedAction *la = gamelog_action; la != laend; la++) { const LoggedChange *lcend = &la->change[la->changes]; for (const LoggedChange *lc = la->change; lc != lcend; lc++) { switch (lc->ct) { default: break; case GLCT_REVISION: *last_ottd_rev = lc->revision.newgrf; *ever_modified = max(*ever_modified, lc->revision.modified); break; case GLCT_GRFREM: *removed_newgrfs = true; break; } } } } openttd-1.5.3/src/viewport_gui.cpp0000644000000000000000000001646312627373445015740 0ustar rootroot/* $Id: viewport_gui.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 viewport_gui.cpp Extra viewport window. */ #include "stdafx.h" #include "landscape.h" #include "window_gui.h" #include "viewport_func.h" #include "strings_func.h" #include "zoom_func.h" #include "window_func.h" #include "widgets/viewport_widget.h" #include "table/strings.h" #include "table/sprites.h" #include "safeguards.h" /* Extra ViewPort Window Stuff */ static const NWidgetPart _nested_extra_view_port_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_EV_CAPTION), SetDataTip(STR_EXTRA_VIEW_PORT_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_EV_VIEWPORT), SetPadding(2, 2, 2, 2), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_EV_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_EV_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_EV_MAIN_TO_VIEW), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW, STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_EV_VIEW_TO_MAIN), SetFill(1, 1), SetResize(1, 0), SetDataTip(STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN, STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; class ExtraViewportWindow : public Window { public: ExtraViewportWindow(WindowDesc *desc, int window_number, TileIndex tile) : Window(desc) { this->InitNested(window_number); NWidgetViewport *nvp = this->GetWidget(WID_EV_VIEWPORT); nvp->InitializeViewport(this, 0, ZOOM_LVL_VIEWPORT); if (_settings_client.gui.zoom_min == ZOOM_LVL_VIEWPORT) this->DisableWidget(WID_EV_ZOOM_IN); Point pt; if (tile == INVALID_TILE) { /* No tile? Use center of main viewport. */ const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); /* center on same place as main window (zoom is maximum, no adjustment needed) */ pt.x = w->viewport->scrollpos_x + w->viewport->virtual_width / 2; pt.y = w->viewport->scrollpos_y + w->viewport->virtual_height / 2; } else { pt = RemapCoords(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, TileHeight(tile)); } this->viewport->scrollpos_x = pt.x - this->viewport->virtual_width / 2; this->viewport->scrollpos_y = pt.y - this->viewport->virtual_height / 2; this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x; this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_EV_CAPTION: /* set the number in the title bar */ SetDParam(0, this->window_number + 1); break; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_EV_ZOOM_IN: DoZoomInOutWindow(ZOOM_IN, this); break; case WID_EV_ZOOM_OUT: DoZoomInOutWindow(ZOOM_OUT, this); break; case WID_EV_MAIN_TO_VIEW: { // location button (move main view to same spot as this view) 'Paste Location' Window *w = FindWindowById(WC_MAIN_WINDOW, 0); int x = this->viewport->scrollpos_x; // Where is the main looking at int y = this->viewport->scrollpos_y; /* set this view to same location. Based on the center, adjusting for zoom */ w->viewport->dest_scrollpos_x = x - (w->viewport->virtual_width - this->viewport->virtual_width) / 2; w->viewport->dest_scrollpos_y = y - (w->viewport->virtual_height - this->viewport->virtual_height) / 2; w->viewport->follow_vehicle = INVALID_VEHICLE; break; } case WID_EV_VIEW_TO_MAIN: { // inverse location button (move this view to same spot as main view) 'Copy Location' const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); int x = w->viewport->scrollpos_x; int y = w->viewport->scrollpos_y; this->viewport->dest_scrollpos_x = x + (w->viewport->virtual_width - this->viewport->virtual_width) / 2; this->viewport->dest_scrollpos_y = y + (w->viewport->virtual_height - this->viewport->virtual_height) / 2; break; } } } virtual void OnResize() { if (this->viewport != NULL) { NWidgetViewport *nvp = this->GetWidget(WID_EV_VIEWPORT); nvp->UpdateViewportCoordinates(this); } } virtual void OnScroll(Point delta) { this->viewport->scrollpos_x += ScaleByZoom(delta.x, this->viewport->zoom); this->viewport->scrollpos_y += ScaleByZoom(delta.y, this->viewport->zoom); this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x; this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; } virtual void OnMouseWheel(int wheel) { if (_settings_client.gui.scrollwheel_scrolling == 0) { ZoomInOrOutToCursorWindow(wheel < 0, this); } } /** * 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; /* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */ HandleZoomMessage(this, this->viewport, WID_EV_ZOOM_IN, WID_EV_ZOOM_OUT); } }; static WindowDesc _extra_view_port_desc( WDP_AUTO, "extra_viewport", 300, 268, WC_EXTRA_VIEW_PORT, WC_NONE, 0, _nested_extra_view_port_widgets, lengthof(_nested_extra_view_port_widgets) ); /** * Show a new Extra Viewport window. * @param tile Tile to center the view on. INVALID_TILE means to use the center of main viewport. */ void ShowExtraViewPortWindow(TileIndex tile) { int i = 0; /* find next free window number for extra viewport */ while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != NULL) i++; new ExtraViewportWindow(&_extra_view_port_desc, i, tile); } /** * Show a new Extra Viewport window. * Center it on the tile under the cursor, if the cursor is inside a viewport. * If that fails, center it on main viewport center. */ void ShowExtraViewPortWindowForTileUnderCursor() { /* Use tile under mouse as center for new viewport. * Do this before creating the window, it might appear just below the mouse. */ Point pt = GetTileBelowCursor(); ShowExtraViewPortWindow(pt.x != -1 ? TileVirtXY(pt.x, pt.y) : INVALID_TILE); } openttd-1.5.3/src/string.cpp0000644000000000000000000006237712627373435014527 0ustar rootroot/* $Id: string.cpp 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 string.cpp Handling of C-type strings (char*). */ #include "stdafx.h" #include "debug.h" #include "core/alloc_func.hpp" #include "core/math_func.hpp" #include "string_func.h" #include "string_base.h" #include "table/control_codes.h" #include #include /* required for tolower() */ #ifdef _MSC_VER #include // required by vsnprintf implementation for MSVC #endif #ifdef WITH_ICU /* Required by strnatcmp. */ #include #include "language.h" #include "gfx_func.h" #endif /* WITH_ICU */ /* The function vsnprintf is used internally to perform the required formatting * tasks. As such this one must be allowed, and makes sure it's terminated. */ #include "safeguards.h" #undef vsnprintf /** * Safer implementation of vsnprintf; same as vsnprintf except: * - last instead of size, i.e. replace sizeof with lastof. * - return gives the amount of characters added, not what it would add. * @param str buffer to write to up to last * @param last last character we may write to * @param format the formatting (see snprintf) * @param ap the list of arguments for the format * @return the number of added characters */ int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) { ptrdiff_t diff = last - str; if (diff < 0) return 0; return min((int)diff, vsnprintf(str, diff + 1, format, ap)); } /** * Appends characters from one string to another. * * Appends the source string to the destination string with respect of the * terminating null-character and and the last pointer to the last element * in the destination buffer. If the last pointer is set to NULL no * boundary check is performed. * * @note usage: strecat(dst, src, lastof(dst)); * @note lastof() applies only to fixed size arrays * * @param dst The buffer containing the target string * @param src The buffer containing the string to append * @param last The pointer to the last element of the destination buffer * @return The pointer to the terminating null-character in the destination buffer */ char *strecat(char *dst, const char *src, const char *last) { assert(dst <= last); while (*dst != '\0') { if (dst == last) return dst; dst++; } return strecpy(dst, src, last); } /** * Copies characters from one buffer to another. * * Copies the source string to the destination buffer with respect of the * terminating null-character and the last pointer to the last element in * the destination buffer. If the last pointer is set to NULL no boundary * check is performed. * * @note usage: strecpy(dst, src, lastof(dst)); * @note lastof() applies only to fixed size arrays * * @param dst The destination buffer * @param src The buffer containing the string to copy * @param last The pointer to the last element of the destination buffer * @return The pointer to the terminating null-character in the destination buffer */ char *strecpy(char *dst, const char *src, const char *last) { assert(dst <= last); while (dst != last && *src != '\0') { *dst++ = *src++; } *dst = '\0'; if (dst == last && *src != '\0') { #if defined(STRGEN) || defined(SETTINGSGEN) error("String too long for destination buffer"); #else /* STRGEN || SETTINGSGEN */ DEBUG(misc, 0, "String too long for destination buffer"); #endif /* STRGEN || SETTINGSGEN */ } return dst; } /** * Create a duplicate of the given string. * @param s The string to duplicate. * @param last The last character that is safe to duplicate. If NULL, the whole string is duplicated. * @note The maximum length of the resulting string might therefore be last - s + 1. * @return The duplicate of the string. */ char *stredup(const char *s, const char *last) { size_t len = last == NULL ? strlen(s) : ttd_strnlen(s, last - s + 1); char *tmp = CallocT(len + 1); memcpy(tmp, s, len); return tmp; } /** * Format, "printf", into a newly allocated string. * @param str The formatting string. * @return The formatted string. You must free this! */ char *CDECL str_fmt(const char *str, ...) { char buf[4096]; va_list va; va_start(va, str); int len = vseprintf(buf, lastof(buf), str, va); va_end(va); char *p = MallocT(len + 1); memcpy(p, buf, len + 1); return p; } /** * Scan the string for old values of SCC_ENCODED and fix it to * it's new, static value. * @param str the string to scan * @param last the last valid character of str */ void str_fix_scc_encoded(char *str, const char *last) { while (str <= last && *str != '\0') { size_t len = Utf8EncodedCharLen(*str); if ((len == 0 && str + 4 > last) || str + len > last) break; WChar c; len = Utf8Decode(&c, str); if (c == '\0') break; if (c == 0xE028 || c == 0xE02A) { c = SCC_ENCODED; } str += Utf8Encode(str, c); } *str = '\0'; } /** * Scans the string for valid characters and if it finds invalid ones, * replaces them with a question mark '?' (if not ignored) * @param str the string to validate * @param last the last valid character of str * @param settings the settings for the string validation. */ void str_validate(char *str, const char *last, StringValidationSettings settings) { /* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */ char *dst = str; while (str <= last && *str != '\0') { size_t len = Utf8EncodedCharLen(*str); /* If the character is unknown, i.e. encoded length is 0 * we assume worst case for the length check. * The length check is needed to prevent Utf8Decode to read * over the terminating '\0' if that happens to be placed * within the encoding of an UTF8 character. */ if ((len == 0 && str + 4 > last) || str + len > last) break; WChar c; len = Utf8Decode(&c, str); /* It's possible to encode the string termination character * into a multiple bytes. This prevents those termination * characters to be skipped */ if (c == '\0') break; if ((IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END)) || ((settings & SVS_ALLOW_CONTROL_CODE) != 0 && c == SCC_ENCODED)) { /* Copy the character back. Even if dst is current the same as str * (i.e. no characters have been changed) this is quicker than * moving the pointers ahead by len */ do { *dst++ = *str++; } while (--len != 0); } else if ((settings & SVS_ALLOW_NEWLINE) != 0 && c == '\n') { *dst++ = *str++; } else { if ((settings & SVS_ALLOW_NEWLINE) != 0 && c == '\r' && str[1] == '\n') { str += len; continue; } /* Replace the undesirable character with a question mark */ str += len; if ((settings & SVS_REPLACE_WITH_QUESTION_MARK) != 0) *dst++ = '?'; } } *dst = '\0'; } /** * Scans the string for valid characters and if it finds invalid ones, * replaces them with a question mark '?'. * @param str the string to validate */ void ValidateString(const char *str) { /* We know it is '\0' terminated. */ str_validate(const_cast(str), str + strlen(str) + 1); } /** * Checks whether the given string is valid, i.e. contains only * valid (printable) characters and is properly terminated. * @param str The string to validate. * @param last The last character of the string, i.e. the string * must be terminated here or earlier. */ bool StrValid(const char *str, const char *last) { /* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */ while (str <= last && *str != '\0') { size_t len = Utf8EncodedCharLen(*str); /* Encoded length is 0 if the character isn't known. * The length check is needed to prevent Utf8Decode to read * over the terminating '\0' if that happens to be placed * within the encoding of an UTF8 character. */ if (len == 0 || str + len > last) return false; WChar c; len = Utf8Decode(&c, str); if (!IsPrintable(c) || (c >= SCC_SPRITE_START && c <= SCC_SPRITE_END)) { return false; } str += len; } return *str == '\0'; } /** Scans the string for colour codes and strips them */ void str_strip_colours(char *str) { char *dst = str; WChar c; size_t len; for (len = Utf8Decode(&c, str); c != '\0'; len = Utf8Decode(&c, str)) { if (c < SCC_BLUE || c > SCC_BLACK) { /* Copy the character back. Even if dst is current the same as str * (i.e. no characters have been changed) this is quicker than * moving the pointers ahead by len */ do { *dst++ = *str++; } while (--len != 0); } else { /* Just skip (strip) the colour codes */ str += len; } } *dst = '\0'; } /** * Get the length of an UTF-8 encoded string in number of characters * and thus not the number of bytes that the encoded string contains. * @param s The string to get the length for. * @return The length of the string in characters. */ size_t Utf8StringLength(const char *s) { size_t len = 0; const char *t = s; while (Utf8Consume(&t) != 0) len++; return len; } /** * Convert a given ASCII string to lowercase. * NOTE: only support ASCII characters, no UTF8 fancy. As currently * the function is only used to lowercase data-filenames if they are * not found, this is sufficient. If more, or general functionality is * needed, look to r7271 where it was removed because it was broken when * using certain locales: eg in Turkish the uppercase 'I' was converted to * '?', so just revert to the old functionality * @param str string to convert * @return String has changed. */ bool strtolower(char *str) { bool changed = false; for (; *str != '\0'; str++) { char new_str = tolower(*str); changed |= new_str != *str; *str = new_str; } return changed; } /** * Only allow certain keys. You can define the filter to be used. This makes * sure no invalid keys can get into an editbox, like BELL. * @param key character to be checked * @param afilter the filter to use * @return true or false depending if the character is printable/valid or not */ bool IsValidChar(WChar key, CharSetFilter afilter) { switch (afilter) { case CS_ALPHANUMERAL: return IsPrintable(key); case CS_NUMERAL: return (key >= '0' && key <= '9'); case CS_NUMERAL_SPACE: return (key >= '0' && key <= '9') || key == ' '; case CS_ALPHA: return IsPrintable(key) && !(key >= '0' && key <= '9'); case CS_HEXADECIMAL: return (key >= '0' && key <= '9') || (key >= 'a' && key <= 'f') || (key >= 'A' && key <= 'F'); } return false; } #ifdef WIN32 #ifdef _MSC_VER /** * Almost POSIX compliant implementation of \c vsnprintf for VC compiler. * The difference is in the value returned on output truncation. This * implementation returns size whereas a POSIX implementation returns * size or more (the number of bytes that would be written to str * had size been sufficiently large excluding the terminating null byte). */ int CDECL vsnprintf(char *str, size_t size, const char *format, va_list ap) { if (size == 0) return 0; errno = 0; int ret = _vsnprintf(str, size, format, ap); if (ret < 0) { if (errno != ERANGE) { /* There's a formatting error, better get that looked * at properly instead of ignoring it. */ NOT_REACHED(); } } else if ((size_t)ret < size) { /* The buffer is big enough for the number of * characters stored (excluding null), i.e. * the string has been null-terminated. */ return ret; } /* The buffer is too small for _vsnprintf to write the * null-terminator at its end and return size. */ str[size - 1] = '\0'; return (int)size; } #endif /* _MSC_VER */ #endif /* WIN32 */ /** * Safer implementation of snprintf; same as snprintf except: * - last instead of size, i.e. replace sizeof with lastof. * - return gives the amount of characters added, not what it would add. * @param str buffer to write to up to last * @param last last character we may write to * @param format the formatting (see snprintf) * @return the number of added characters */ int CDECL seprintf(char *str, const char *last, const char *format, ...) { va_list ap; va_start(ap, format); int ret = vseprintf(str, last, format, ap); va_end(ap); return ret; } /** * Convert the md5sum to a hexadecimal string representation * @param buf buffer to put the md5sum into * @param last last character of buffer (usually lastof(buf)) * @param md5sum the md5sum itself * @return a pointer to the next character after the md5sum */ char *md5sumToString(char *buf, const char *last, const uint8 md5sum[16]) { char *p = buf; for (uint i = 0; i < 16; i++) { p += seprintf(p, last, "%02X", md5sum[i]); } return p; } /* UTF-8 handling routines */ /** * Decode and consume the next UTF-8 encoded character. * @param c Buffer to place decoded character. * @param s Character stream to retrieve character from. * @return Number of characters in the sequence. */ size_t Utf8Decode(WChar *c, const char *s) { assert(c != NULL); if (!HasBit(s[0], 7)) { /* Single byte character: 0xxxxxxx */ *c = s[0]; return 1; } else if (GB(s[0], 5, 3) == 6) { if (IsUtf8Part(s[1])) { /* Double byte character: 110xxxxx 10xxxxxx */ *c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6); if (*c >= 0x80) return 2; } } else if (GB(s[0], 4, 4) == 14) { if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) { /* Triple byte character: 1110xxxx 10xxxxxx 10xxxxxx */ *c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6); if (*c >= 0x800) return 3; } } else if (GB(s[0], 3, 5) == 30) { if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) { /* 4 byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ *c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6); if (*c >= 0x10000 && *c <= 0x10FFFF) return 4; } } /* DEBUG(misc, 1, "[utf8] invalid UTF-8 sequence"); */ *c = '?'; return 1; } /** * Encode a unicode character and place it in the buffer. * @param buf Buffer to place character. * @param c Unicode character to encode. * @return Number of characters in the encoded sequence. */ size_t Utf8Encode(char *buf, WChar c) { if (c < 0x80) { *buf = c; return 1; } else if (c < 0x800) { *buf++ = 0xC0 + GB(c, 6, 5); *buf = 0x80 + GB(c, 0, 6); return 2; } else if (c < 0x10000) { *buf++ = 0xE0 + GB(c, 12, 4); *buf++ = 0x80 + GB(c, 6, 6); *buf = 0x80 + GB(c, 0, 6); return 3; } else if (c < 0x110000) { *buf++ = 0xF0 + GB(c, 18, 3); *buf++ = 0x80 + GB(c, 12, 6); *buf++ = 0x80 + GB(c, 6, 6); *buf = 0x80 + GB(c, 0, 6); return 4; } /* DEBUG(misc, 1, "[utf8] can't UTF-8 encode value 0x%X", c); */ *buf = '?'; return 1; } /** * Properly terminate an UTF8 string to some maximum length * @param s string to check if it needs additional trimming * @param maxlen the maximum length the buffer can have. * @return the new length in bytes of the string (eg. strlen(new_string)) * @note maxlen is the string length _INCLUDING_ the terminating '\0' */ size_t Utf8TrimString(char *s, size_t maxlen) { size_t length = 0; for (const char *ptr = strchr(s, '\0'); *s != '\0';) { size_t len = Utf8EncodedCharLen(*s); /* Silently ignore invalid UTF8 sequences, our only concern trimming */ if (len == 0) len = 1; /* Take care when a hard cutoff was made for the string and * the last UTF8 sequence is invalid */ if (length + len >= maxlen || (s + len > ptr)) break; s += len; length += len; } *s = '\0'; return length; } #ifdef DEFINE_STRCASESTR char *strcasestr(const char *haystack, const char *needle) { size_t hay_len = strlen(haystack); size_t needle_len = strlen(needle); while (hay_len >= needle_len) { if (strncasecmp(haystack, needle, needle_len) == 0) return const_cast(haystack); haystack++; hay_len--; } return NULL; } #endif /* DEFINE_STRCASESTR */ /** * Skip some of the 'garbage' in the string that we don't want to use * to sort on. This way the alphabetical sorting will work better as * we would be actually using those characters instead of some other * characters such as spaces and tildes at the begin of the name. * @param str The string to skip the initial garbage of. * @return The string with the garbage skipped. */ static const char *SkipGarbage(const char *str) { while (*str != '\0' && (*str < '0' || IsInsideMM(*str, ';', '@' + 1) || IsInsideMM(*str, '[', '`' + 1) || IsInsideMM(*str, '{', '~' + 1))) str++; return str; } /** * Compares two strings using case insensitive natural sort. * * @param s1 First string to compare. * @param s2 Second string to compare. * @param ignore_garbage_at_front Skip punctuation characters in the front * @return Less than zero if s1 < s2, zero if s1 == s2, greater than zero if s1 > s2. */ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front) { if (ignore_garbage_at_front) { s1 = SkipGarbage(s1); s2 = SkipGarbage(s2); } #ifdef WITH_ICU if (_current_collator != NULL) { UErrorCode status = U_ZERO_ERROR; int result; /* We want to use the new faster method for ICU 4.2 and higher. */ #if U_ICU_VERSION_MAJOR_NUM > 4 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM >= 2) /* The StringPiece parameter gets implicitly constructed from the char *. */ result = _current_collator->compareUTF8(s1, s2, status); #else /* The following for 4.0 and lower. */ UChar buffer1[DRAW_STRING_BUFFER]; u_strFromUTF8Lenient(buffer1, lengthof(buffer1), NULL, s1, -1, &status); UChar buffer2[DRAW_STRING_BUFFER]; u_strFromUTF8Lenient(buffer2, lengthof(buffer2), NULL, s2, -1, &status); result = _current_collator->compare(buffer1, buffer2, status); #endif /* ICU version check. */ if (U_SUCCESS(status)) return result; } #endif /* WITH_ICU */ /* Do a normal comparison if ICU is missing or if we cannot create a collator. */ return strcasecmp(s1, s2); } #ifdef WITH_ICU #include #include /** String iterator using ICU as a backend. */ class IcuStringIterator : public StringIterator { icu::BreakIterator *char_itr; ///< ICU iterator for characters. icu::BreakIterator *word_itr; ///< ICU iterator for words. SmallVector utf16_str; ///< UTF-16 copy of the string. SmallVector utf16_to_utf8; ///< Mapping from UTF-16 code point position to index in the UTF-8 source string. public: IcuStringIterator() : char_itr(NULL), word_itr(NULL) { UErrorCode status = U_ZERO_ERROR; this->char_itr = icu::BreakIterator::createCharacterInstance(icu::Locale(_current_language != NULL ? _current_language->isocode : "en"), status); this->word_itr = icu::BreakIterator::createWordInstance(icu::Locale(_current_language != NULL ? _current_language->isocode : "en"), status); *this->utf16_str.Append() = '\0'; *this->utf16_to_utf8.Append() = 0; } virtual ~IcuStringIterator() { delete this->char_itr; delete this->word_itr; } virtual void SetString(const char *s) { const char *string_base = s; /* Unfortunately current ICU versions only provide rudimentary support * for word break iterators (especially for CJK languages) in combination * with UTF-8 input. As a work around we have to convert the input to * UTF-16 and create a mapping back to UTF-8 character indices. */ this->utf16_str.Clear(); this->utf16_to_utf8.Clear(); while (*s != '\0') { size_t idx = s - string_base; WChar c = Utf8Consume(&s); if (c < 0x10000) { *this->utf16_str.Append() = (UChar)c; } else { /* Make a surrogate pair. */ *this->utf16_str.Append() = (UChar)(0xD800 + ((c - 0x10000) >> 10)); *this->utf16_str.Append() = (UChar)(0xDC00 + ((c - 0x10000) & 0x3FF)); *this->utf16_to_utf8.Append() = idx; } *this->utf16_to_utf8.Append() = idx; } *this->utf16_str.Append() = '\0'; *this->utf16_to_utf8.Append() = s - string_base; UText text = UTEXT_INITIALIZER; UErrorCode status = U_ZERO_ERROR; utext_openUChars(&text, this->utf16_str.Begin(), this->utf16_str.Length() - 1, &status); this->char_itr->setText(&text, status); this->word_itr->setText(&text, status); this->char_itr->first(); this->word_itr->first(); } virtual size_t SetCurPosition(size_t pos) { /* Convert incoming position to an UTF-16 string index. */ uint utf16_pos = 0; for (uint i = 0; i < this->utf16_to_utf8.Length(); i++) { if (this->utf16_to_utf8[i] == pos) { utf16_pos = i; break; } } /* isBoundary has the documented side-effect of setting the current * position to the first valid boundary equal to or greater than * the passed value. */ this->char_itr->isBoundary(utf16_pos); return this->utf16_to_utf8[this->char_itr->current()]; } virtual size_t Next(IterType what) { int32_t pos; switch (what) { case ITER_CHARACTER: pos = this->char_itr->next(); break; case ITER_WORD: pos = this->word_itr->following(this->char_itr->current()); /* The ICU word iterator considers both the start and the end of a word a valid * break point, but we only want word starts. Move to the next location in * case the new position points to whitespace. */ while (pos != icu::BreakIterator::DONE && IsWhitespace(Utf16DecodeChar((const uint16 *)&this->utf16_str[pos]))) { int32_t new_pos = this->word_itr->next(); /* Don't set it to DONE if it was valid before. Otherwise we'll return END * even though the iterator wasn't at the end of the string before. */ if (new_pos == icu::BreakIterator::DONE) break; pos = new_pos; } this->char_itr->isBoundary(pos); break; default: NOT_REACHED(); } return pos == icu::BreakIterator::DONE ? END : this->utf16_to_utf8[pos]; } virtual size_t Prev(IterType what) { int32_t pos; switch (what) { case ITER_CHARACTER: pos = this->char_itr->previous(); break; case ITER_WORD: pos = this->word_itr->preceding(this->char_itr->current()); /* The ICU word iterator considers both the start and the end of a word a valid * break point, but we only want word starts. Move to the previous location in * case the new position points to whitespace. */ while (pos != icu::BreakIterator::DONE && IsWhitespace(Utf16DecodeChar((const uint16 *)&this->utf16_str[pos]))) { int32_t new_pos = this->word_itr->previous(); /* Don't set it to DONE if it was valid before. Otherwise we'll return END * even though the iterator wasn't at the start of the string before. */ if (new_pos == icu::BreakIterator::DONE) break; pos = new_pos; } this->char_itr->isBoundary(pos); break; default: NOT_REACHED(); } return pos == icu::BreakIterator::DONE ? END : this->utf16_to_utf8[pos]; } }; /* static */ StringIterator *StringIterator::Create() { return new IcuStringIterator(); } #else /** Fallback simple string iterator. */ class DefaultStringIterator : public StringIterator { const char *string; ///< Current string. size_t len; ///< String length. size_t cur_pos; ///< Current iteration position. public: DefaultStringIterator() : string(NULL), len(0), cur_pos(0) { } virtual void SetString(const char *s) { this->string = s; this->len = strlen(s); this->cur_pos = 0; } virtual size_t SetCurPosition(size_t pos) { assert(this->string != NULL && pos <= this->len); /* Sanitize in case we get a position inside an UTF-8 sequence. */ while (pos > 0 && IsUtf8Part(this->string[pos])) pos--; return this->cur_pos = pos; } virtual size_t Next(IterType what) { assert(this->string != NULL); /* Already at the end? */ if (this->cur_pos >= this->len) return END; switch (what) { case ITER_CHARACTER: { WChar c; this->cur_pos += Utf8Decode(&c, this->string + this->cur_pos); return this->cur_pos; } case ITER_WORD: { WChar c; /* Consume current word. */ size_t offs = Utf8Decode(&c, this->string + this->cur_pos); while (this->cur_pos < this->len && !IsWhitespace(c)) { this->cur_pos += offs; offs = Utf8Decode(&c, this->string + this->cur_pos); } /* Consume whitespace to the next word. */ while (this->cur_pos < this->len && IsWhitespace(c)) { this->cur_pos += offs; offs = Utf8Decode(&c, this->string + this->cur_pos); } return this->cur_pos; } default: NOT_REACHED(); } return END; } virtual size_t Prev(IterType what) { assert(this->string != NULL); /* Already at the beginning? */ if (this->cur_pos == 0) return END; switch (what) { case ITER_CHARACTER: return this->cur_pos = Utf8PrevChar(this->string + this->cur_pos) - this->string; case ITER_WORD: { const char *s = this->string + this->cur_pos; WChar c; /* Consume preceding whitespace. */ do { s = Utf8PrevChar(s); Utf8Decode(&c, s); } while (s > this->string && IsWhitespace(c)); /* Consume preceding word. */ while (s > this->string && !IsWhitespace(c)) { s = Utf8PrevChar(s); Utf8Decode(&c, s); } /* Move caret back to the beginning of the word. */ if (IsWhitespace(c)) Utf8Consume(&s); return this->cur_pos = s - this->string; } default: NOT_REACHED(); } return END; } }; /* static */ StringIterator *StringIterator::Create() { return new DefaultStringIterator(); } #endif openttd-1.5.3/src/bmp.h0000644000000000000000000000311012627373445013421 0ustar rootroot/* $Id: bmp.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 bmp.h Read and write support for bmps. */ #ifndef BMP_H #define BMP_H #include "gfx_type.h" struct BmpInfo { uint32 offset; ///< offset of bitmap data from .bmp file begining uint32 width; ///< bitmap width uint32 height; ///< bitmap height bool os2_bmp; ///< true if OS/2 1.x or windows 2.x bitmap uint16 bpp; ///< bits per pixel uint32 compression; ///< compression method (0 = none, 1 = 8-bit RLE, 2 = 4-bit RLE) uint32 palette_size; ///< number of colours in palette }; struct BmpData { Colour *palette; byte *bitmap; }; #define BMP_BUFFER_SIZE 1024 struct BmpBuffer { byte data[BMP_BUFFER_SIZE]; int pos; int read; FILE *file; uint real_pos; }; void BmpInitializeBuffer(BmpBuffer *buffer, FILE *file); bool BmpReadHeader(BmpBuffer *buffer, BmpInfo *info, BmpData *data); bool BmpReadBitmap(BmpBuffer *buffer, BmpInfo *info, BmpData *data); void BmpDestroyData(BmpData *data); #endif /* BMP_H */ openttd-1.5.3/src/articulated_vehicles.h0000644000000000000000000000313112627373433017026 0ustar rootroot/* $Id: articulated_vehicles.h 24029 2012-03-14 20:49:54Z yexo $ */ /* * 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 articulated_vehicles.h Functions related to articulated vehicles. */ #ifndef ARTICULATED_VEHICLES_H #define ARTICULATED_VEHICLES_H #include "vehicle_type.h" #include "engine_type.h" uint CountArticulatedParts(EngineID engine_type, bool purchase_window); CargoArray GetCapacityOfArticulatedParts(EngineID engine); void AddArticulatedParts(Vehicle *first); void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, uint32 *union_mask, uint32 *intersection_mask); uint32 GetUnionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type); uint32 GetIntersectionOfArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type); bool IsArticulatedVehicleCarryingDifferentCargoes(const Vehicle *v, CargoID *cargo_type); bool IsArticulatedVehicleRefittable(EngineID engine); bool IsArticulatedEngine(EngineID engine_type); void CheckConsistencyOfArticulatedVehicle(const Vehicle *v); #endif /* ARTICULATED_VEHICLES_H */ openttd-1.5.3/src/build_vehicle_gui.cpp0000644000000000000000000015151712627373436016657 0ustar rootroot/* $Id: build_vehicle_gui.cpp 26960 2014-10-05 11:20:02Z peter1138 $ */ /* * 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 build_vehicle_gui.cpp GUI for building vehicles. */ #include "stdafx.h" #include "engine_base.h" #include "engine_func.h" #include "station_base.h" #include "network/network.h" #include "articulated_vehicles.h" #include "textbuf_gui.h" #include "command_func.h" #include "company_func.h" #include "vehicle_gui.h" #include "newgrf_engine.h" #include "newgrf_text.h" #include "group.h" #include "string_func.h" #include "strings_func.h" #include "window_func.h" #include "date_func.h" #include "vehicle_func.h" #include "widgets/dropdown_func.h" #include "engine_gui.h" #include "cargotype.h" #include "core/geometry_func.hpp" #include "autoreplace_func.h" #include "widgets/build_vehicle_widget.h" #include "table/strings.h" #include "safeguards.h" /** * Get the height of a single 'entry' in the engine lists. * @param type the vehicle type to get the height of * @return the height for the entry */ uint GetEngineListHeight(VehicleType type) { return max(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleImageCellSize(type, EIT_PURCHASE).height); } static const NWidgetPart _nested_build_vehicle_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_BV_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SORT_ASCENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDDEN_ENGINES), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_BV_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA), EndContainer(), EndContainer(), EndContainer(), /* Vehicle list. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_BV_LIST), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_BV_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BV_SCROLLBAR), EndContainer(), /* Panel with details. */ NWidget(WWT_PANEL, COLOUR_GREY, WID_BV_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(), /* Build/rename buttons, resize button. */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BV_BUILD_SEL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_BUILD), SetResize(1, 0), SetFill(1, 0), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_SHOW_HIDE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BV_RENAME), SetResize(1, 0), SetFill(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; /** Special cargo filter criteria */ static const CargoID CF_ANY = CT_NO_REFIT; ///< Show all vehicles independent of carried cargo (i.e. no filtering) static const CargoID CF_NONE = CT_INVALID; ///< Show only vehicles which do not carry cargo (e.g. train engines) bool _engine_sort_direction; ///< \c false = descending, \c true = ascending. byte _engine_sort_last_criteria[] = {0, 0, 0, 0}; ///< Last set sort criteria, for each vehicle type. bool _engine_sort_last_order[] = {false, false, false, false}; ///< Last set direction of the sort order, for each vehicle type. bool _engine_sort_show_hidden_engines[] = {false, false, false, false}; ///< Last set 'show hidden engines' setting for each vehicle type. static CargoID _engine_sort_last_cargo_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY}; ///< Last set filter criteria, for each vehicle type. /** * Determines order of engines by engineID * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b) { int r = Engine::Get(*a)->list_position - Engine::Get(*b)->list_position; return _engine_sort_direction ? -r : r; } /** * Determines order of engines by introduction date * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineIntroDateSorter(const EngineID *a, const EngineID *b) { const int va = Engine::Get(*a)->intro_date; const int vb = Engine::Get(*b)->intro_date; const int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by name * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b) { static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE }; static char last_name[2][64] = { "\0", "\0" }; const EngineID va = *a; const EngineID vb = *b; if (va != last_engine[0]) { last_engine[0] = va; SetDParam(0, va); GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0])); } if (vb != last_engine[1]) { last_engine[1] = vb; SetDParam(0, vb); GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1])); } int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting). /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by reliability * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineReliabilitySorter(const EngineID *a, const EngineID *b) { const int va = Engine::Get(*a)->reliability; const int vb = Engine::Get(*b)->reliability; const int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by purchase cost * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineCostSorter(const EngineID *a, const EngineID *b) { Money va = Engine::Get(*a)->GetCost(); Money vb = Engine::Get(*b)->GetCost(); int r = ClampToI32(va - vb); /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by speed * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineSpeedSorter(const EngineID *a, const EngineID *b) { int va = Engine::Get(*a)->GetDisplayMaxSpeed(); int vb = Engine::Get(*b)->GetDisplayMaxSpeed(); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by power * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EnginePowerSorter(const EngineID *a, const EngineID *b) { int va = Engine::Get(*a)->GetPower(); int vb = Engine::Get(*b)->GetPower(); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by tractive effort * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineTractiveEffortSorter(const EngineID *a, const EngineID *b) { int va = Engine::Get(*a)->GetDisplayMaxTractiveEffort(); int vb = Engine::Get(*b)->GetDisplayMaxTractiveEffort(); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by running costs * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EngineRunningCostSorter(const EngineID *a, const EngineID *b) { Money va = Engine::Get(*a)->GetRunningCost(); Money vb = Engine::Get(*b)->GetRunningCost(); int r = ClampToI32(va - vb); /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of engines by running costs * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL EnginePowerVsRunningCostSorter(const EngineID *a, const EngineID *b) { const Engine *e_a = Engine::Get(*a); const Engine *e_b = Engine::Get(*b); /* Here we are using a few tricks to get the right sort. * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int, * we will actually calculate cunning cost/power (to make it more than 1). * Because of this, the return value have to be reversed as well and we return b - a instead of a - b. * Another thing is that both power and running costs should be doubled for multiheaded engines. * Since it would be multiplying with 2 in both numerator and denominator, it will even themselves out and we skip checking for multiheaded. */ Money va = (e_a->GetRunningCost()) / max(1U, (uint)e_a->GetPower()); Money vb = (e_b->GetRunningCost()) / max(1U, (uint)e_b->GetPower()); int r = ClampToI32(vb - va); /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /* Train sorting functions */ /** * Determines order of train engines by capacity * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL TrainEngineCapacitySorter(const EngineID *a, const EngineID *b) { const RailVehicleInfo *rvi_a = RailVehInfo(*a); const RailVehicleInfo *rvi_b = RailVehInfo(*b); int va = GetTotalCapacityOfArticulatedParts(*a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); int vb = GetTotalCapacityOfArticulatedParts(*b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** * Determines order of train engines by engine / wagon * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b) { int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0); int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0); int r = val_a - val_b; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /* Road vehicle sorting functions */ /** * Determines order of road vehicles by capacity * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL RoadVehEngineCapacitySorter(const EngineID *a, const EngineID *b) { int va = GetTotalCapacityOfArticulatedParts(*a); int vb = GetTotalCapacityOfArticulatedParts(*b); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /* Ship vehicle sorting functions */ /** * Determines order of ships by capacity * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL ShipEngineCapacitySorter(const EngineID *a, const EngineID *b) { const Engine *e_a = Engine::Get(*a); const Engine *e_b = Engine::Get(*b); int va = e_a->GetDisplayDefaultCapacity(); int vb = e_b->GetDisplayDefaultCapacity(); int r = va - vb; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /* Aircraft sorting functions */ /** * Determines order of aircraft by cargo * @param *a first engine to compare * @param *b second engine to compare * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal */ static int CDECL AircraftEngineCargoSorter(const EngineID *a, const EngineID *b) { const Engine *e_a = Engine::Get(*a); const Engine *e_b = Engine::Get(*b); uint16 mail_a, mail_b; int va = e_a->GetDisplayDefaultCapacity(&mail_a); int vb = e_b->GetDisplayDefaultCapacity(&mail_b); int r = va - vb; if (r == 0) { /* The planes have the same passenger capacity. Check mail capacity instead */ r = mail_a - mail_b; if (r == 0) { /* Use EngineID to sort instead since we want consistent sorting */ return EngineNumberSorter(a, b); } } return _engine_sort_direction ? -r : r; } /** * Determines order of aircraft by range. * @param *a first engine to compare. * @param *b second engine to compare. * @return for descending order: returns < 0 if a < b and > 0 for a > b. Vice versa for ascending order and 0 for equal. */ static int CDECL AircraftRangeSorter(const EngineID *a, const EngineID *b) { uint16 r_a = Engine::Get(*a)->GetRange(); uint16 r_b = Engine::Get(*b)->GetRange(); int r = r_a - r_b; /* Use EngineID to sort instead since we want consistent sorting */ if (r == 0) return EngineNumberSorter(a, b); return _engine_sort_direction ? -r : r; } /** Sort functions for the vehicle sort criteria, for each vehicle type. */ EngList_SortTypeFunction * const _engine_sort_functions[][11] = {{ /* Trains */ &EngineNumberSorter, &EngineCostSorter, &EngineSpeedSorter, &EnginePowerSorter, &EngineTractiveEffortSorter, &EngineIntroDateSorter, &EngineNameSorter, &EngineRunningCostSorter, &EnginePowerVsRunningCostSorter, &EngineReliabilitySorter, &TrainEngineCapacitySorter, }, { /* Road vehicles */ &EngineNumberSorter, &EngineCostSorter, &EngineSpeedSorter, &EnginePowerSorter, &EngineTractiveEffortSorter, &EngineIntroDateSorter, &EngineNameSorter, &EngineRunningCostSorter, &EnginePowerVsRunningCostSorter, &EngineReliabilitySorter, &RoadVehEngineCapacitySorter, }, { /* Ships */ &EngineNumberSorter, &EngineCostSorter, &EngineSpeedSorter, &EngineIntroDateSorter, &EngineNameSorter, &EngineRunningCostSorter, &EngineReliabilitySorter, &ShipEngineCapacitySorter, }, { /* Aircraft */ &EngineNumberSorter, &EngineCostSorter, &EngineSpeedSorter, &EngineIntroDateSorter, &EngineNameSorter, &EngineRunningCostSorter, &EngineReliabilitySorter, &AircraftEngineCargoSorter, &AircraftRangeSorter, }}; /** Dropdown menu strings for the vehicle sort criteria. */ const StringID _engine_sort_listing[][12] = {{ /* Trains */ STR_SORT_BY_ENGINE_ID, STR_SORT_BY_COST, STR_SORT_BY_MAX_SPEED, STR_SORT_BY_POWER, STR_SORT_BY_TRACTIVE_EFFORT, STR_SORT_BY_INTRO_DATE, STR_SORT_BY_NAME, STR_SORT_BY_RUNNING_COST, STR_SORT_BY_POWER_VS_RUNNING_COST, STR_SORT_BY_RELIABILITY, STR_SORT_BY_CARGO_CAPACITY, INVALID_STRING_ID }, { /* Road vehicles */ STR_SORT_BY_ENGINE_ID, STR_SORT_BY_COST, STR_SORT_BY_MAX_SPEED, STR_SORT_BY_POWER, STR_SORT_BY_TRACTIVE_EFFORT, STR_SORT_BY_INTRO_DATE, STR_SORT_BY_NAME, STR_SORT_BY_RUNNING_COST, STR_SORT_BY_POWER_VS_RUNNING_COST, STR_SORT_BY_RELIABILITY, STR_SORT_BY_CARGO_CAPACITY, INVALID_STRING_ID }, { /* Ships */ STR_SORT_BY_ENGINE_ID, STR_SORT_BY_COST, STR_SORT_BY_MAX_SPEED, STR_SORT_BY_INTRO_DATE, STR_SORT_BY_NAME, STR_SORT_BY_RUNNING_COST, STR_SORT_BY_RELIABILITY, STR_SORT_BY_CARGO_CAPACITY, INVALID_STRING_ID }, { /* Aircraft */ STR_SORT_BY_ENGINE_ID, STR_SORT_BY_COST, STR_SORT_BY_MAX_SPEED, STR_SORT_BY_INTRO_DATE, STR_SORT_BY_NAME, STR_SORT_BY_RUNNING_COST, STR_SORT_BY_RELIABILITY, STR_SORT_BY_CARGO_CAPACITY, STR_SORT_BY_RANGE, INVALID_STRING_ID }}; /** Cargo filter functions */ static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid) { if (cid == CF_ANY) return true; uint32 refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true) & _standard_cargo_mask; return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid)); } static GUIEngineList::FilterFunction * const _filter_funcs[] = { &CargoFilter, }; static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine) { CargoArray cap; uint32 refits; GetArticulatedVehicleCargoesAndRefits(engine, &cap, &refits); for (CargoID c = 0; c < NUM_CARGO; c++) { if (cap[c] == 0) continue; SetDParam(0, c); SetDParam(1, cap[c]); SetDParam(2, HasBit(refits, c) ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); y += FONT_HEIGHT_NORMAL; } return y; } /* Draw rail wagon specific details */ static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) { const Engine *e = Engine::Get(engine_number); /* Purchase cost */ SetDParam(0, e->GetCost()); DrawString(left, right, y, STR_PURCHASE_INFO_COST); y += FONT_HEIGHT_NORMAL; /* Wagon weight - (including cargo) */ uint weight = e->GetDisplayWeight(); SetDParam(0, weight); uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); SetDParam(1, cargo_weight + weight); DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); y += FONT_HEIGHT_NORMAL; /* Wagon speed limit, displayed if above zero */ if (_settings_game.vehicle.wagon_speed_limits) { uint max_speed = e->GetDisplayMaxSpeed(); if (max_speed > 0) { SetDParam(0, max_speed); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED); y += FONT_HEIGHT_NORMAL; } } /* Running cost */ if (rvi->running_cost_class != INVALID_PRICE) { SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; } return y; } /* Draw locomotive specific details */ static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi) { const Engine *e = Engine::Get(engine_number); /* Purchase Cost - Engine weight */ SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayWeight()); DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT); y += FONT_HEIGHT_NORMAL; /* Max speed - Engine power */ SetDParam(0, e->GetDisplayMaxSpeed()); SetDParam(1, e->GetPower()); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); y += FONT_HEIGHT_NORMAL; /* Max tractive effort - not applicable if old acceleration or maglev */ if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) { SetDParam(0, e->GetDisplayMaxTractiveEffort()); DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); y += FONT_HEIGHT_NORMAL; } /* Running cost */ if (rvi->running_cost_class != INVALID_PRICE) { SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; } /* Powered wagons power - Powered wagons extra weight */ if (rvi->pow_wag_power != 0) { SetDParam(0, rvi->pow_wag_power); SetDParam(1, rvi->pow_wag_weight); DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT); y += FONT_HEIGHT_NORMAL; } return y; } /* Draw road vehicle specific details */ static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number) { const Engine *e = Engine::Get(engine_number); if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { /* Purchase Cost */ SetDParam(0, e->GetCost()); DrawString(left, right, y, STR_PURCHASE_INFO_COST); y += FONT_HEIGHT_NORMAL; /* Road vehicle weight - (including cargo) */ int16 weight = e->GetDisplayWeight(); SetDParam(0, weight); uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16 : 0); SetDParam(1, cargo_weight + weight); DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT); y += FONT_HEIGHT_NORMAL; /* Max speed - Engine power */ SetDParam(0, e->GetDisplayMaxSpeed()); SetDParam(1, e->GetPower()); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER); y += FONT_HEIGHT_NORMAL; /* Max tractive effort */ SetDParam(0, e->GetDisplayMaxTractiveEffort()); DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE); y += FONT_HEIGHT_NORMAL; } else { /* Purchase cost - Max speed */ SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayMaxSpeed()); DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); y += FONT_HEIGHT_NORMAL; } /* Running cost */ SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; return y; } /* Draw ship specific details */ static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) { const Engine *e = Engine::Get(engine_number); /* Purchase cost - Max speed */ uint raw_speed = e->GetDisplayMaxSpeed(); uint ocean_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, true); uint canal_speed = e->u.ship.ApplyWaterClassSpeedFrac(raw_speed, false); SetDParam(0, e->GetCost()); if (ocean_speed == canal_speed) { SetDParam(1, ocean_speed); DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); y += FONT_HEIGHT_NORMAL; } else { DrawString(left, right, y, STR_PURCHASE_INFO_COST); y += FONT_HEIGHT_NORMAL; SetDParam(0, ocean_speed); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_OCEAN); y += FONT_HEIGHT_NORMAL; SetDParam(0, canal_speed); DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_CANAL); y += FONT_HEIGHT_NORMAL; } /* Cargo type + capacity */ SetDParam(0, e->GetDefaultCargoType()); SetDParam(1, e->GetDisplayDefaultCapacity()); SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); y += FONT_HEIGHT_NORMAL; /* Running cost */ SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; return y; } /* Draw aircraft specific details */ static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable) { const Engine *e = Engine::Get(engine_number); CargoID cargo = e->GetDefaultCargoType(); /* Purchase cost - Max speed */ SetDParam(0, e->GetCost()); SetDParam(1, e->GetDisplayMaxSpeed()); DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED); y += FONT_HEIGHT_NORMAL; /* Cargo capacity */ uint16 mail_capacity; uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity); if (mail_capacity > 0) { SetDParam(0, cargo); SetDParam(1, capacity); SetDParam(2, CT_MAIL); SetDParam(3, mail_capacity); DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY); } else { /* Note, if the default capacity is selected by the refit capacity * callback, then the capacity shown is likely to be incorrect. */ SetDParam(0, cargo); SetDParam(1, capacity); SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); } y += FONT_HEIGHT_NORMAL; /* Running cost */ SetDParam(0, e->GetRunningCost()); DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST); y += FONT_HEIGHT_NORMAL; uint16 range = e->GetRange(); if (range != 0) { SetDParam(0, range); DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_RANGE); y += FONT_HEIGHT_NORMAL; } return y; } /** * Display additional text from NewGRF in the purchase information window * @param left Left border of text bounding box * @param right Right border of text bounding box * @param y Top border of text bounding box * @param engine Engine to query the additional purchase information for * @return Bottom border of text bounding box */ static uint ShowAdditionalText(int left, int right, int y, EngineID engine) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL); if (callback == CALLBACK_FAILED || callback == 0x400) return y; const GRFFile *grffile = Engine::Get(engine)->GetGRF(); if (callback > 0x400) { ErrorUnknownCallbackResult(grffile->grfid, CBID_VEHICLE_ADDITIONAL_TEXT, callback); return y; } StartTextRefStackUsage(grffile, 6); uint result = DrawStringMultiLine(left, right, y, INT32_MAX, GetGRFStringID(grffile->grfid, 0xD000 + callback), TC_BLACK); StopTextRefStackUsage(); return result; } /** * Draw the purchase info details of a vehicle at a given location. * @param left,right,y location where to draw the info * @param engine_number the engine of which to draw the info of * @return y after drawing all the text */ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number) { const Engine *e = Engine::Get(engine_number); YearMonthDay ymd; ConvertDateToYMD(e->intro_date, &ymd); bool refittable = IsArticulatedVehicleRefittable(engine_number); bool articulated_cargo = false; switch (e->type) { default: NOT_REACHED(); case VEH_TRAIN: if (e->u.rail.railveh_type == RAILVEH_WAGON) { y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail); } else { y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail); } articulated_cargo = true; break; case VEH_ROAD: y = DrawRoadVehPurchaseInfo(left, right, y, engine_number); articulated_cargo = true; break; case VEH_SHIP: y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable); break; case VEH_AIRCRAFT: y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable); break; } if (articulated_cargo) { /* Cargo type + capacity, or N/A */ int new_y = DrawCargoCapacityInfo(left, right, y, engine_number); if (new_y == y) { SetDParam(0, CT_INVALID); SetDParam(2, STR_EMPTY); DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY); y += FONT_HEIGHT_NORMAL; } else { y = new_y; } } /* Draw details that apply to all types except rail wagons. */ if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) { /* Design date - Life length */ SetDParam(0, ymd.year); SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR); DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE); y += FONT_HEIGHT_NORMAL; /* Reliability */ SetDParam(0, ToPercent16(e->reliability)); DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY); y += FONT_HEIGHT_NORMAL; } if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number); /* Additional text from NewGRF */ y = ShowAdditionalText(left, right, y, engine_number); return y; } /** * Engine drawing loop * @param type Type of vehicle (VEH_*) * @param l The left most location of the list * @param r The right most location of the list * @param y The top most location of the list * @param eng_list What engines to draw * @param min where to start in the list * @param max where in the list to end * @param selected_id what engine to highlight as selected, if any * @param show_count Whether to show the amount of engines or not * @param selected_group the group to list the engines of */ void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group) { static const int sprite_y_offsets[] = { -1, -1, -2, -2 }; /* Obligatory sanity checks! */ assert(max <= eng_list->Length()); bool rtl = _current_text_dir == TD_RTL; int step_size = GetEngineListHeight(type); int sprite_left = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_left; int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right; int sprite_width = sprite_left + sprite_right; int sprite_x = rtl ? r - sprite_right - 1 : l + sprite_left + 1; int sprite_y_offset = sprite_y_offsets[type] + step_size / 2; Dimension replace_icon = {0, 0}; int count_width = 0; if (show_count) { replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE); SetDParamMaxDigits(0, 3, FS_SMALL); count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width; } int text_left = l + (rtl ? WD_FRAMERECT_LEFT + replace_icon.width + 8 + count_width : sprite_width + WD_FRAMETEXT_LEFT); int text_right = r - (rtl ? sprite_width + WD_FRAMETEXT_RIGHT : WD_FRAMERECT_RIGHT + replace_icon.width + 8 + count_width); int replace_icon_left = rtl ? l + WD_FRAMERECT_LEFT : r - WD_FRAMERECT_RIGHT - replace_icon.width; int count_left = l; int count_right = rtl ? text_left : r - WD_FRAMERECT_RIGHT - replace_icon.width - 8; int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2; int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1; int replace_icon_y_offset = (step_size - replace_icon.height) / 2 - 1; for (; min < max; min++, y += step_size) { const EngineID engine = (*eng_list)[min]; /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */ const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine); const Engine *e = Engine::Get(engine); bool hidden = HasBit(e->company_hidden, _local_company); StringID str = hidden ? STR_HIDDEN_ENGINE_NAME : STR_ENGINE_NAME; TextColour tc = (engine == selected_id) ? TC_WHITE : (TC_NO_SHADE | (hidden ? TC_GREY : TC_BLACK)); SetDParam(0, engine); DrawString(text_left, text_right, y + normal_text_y_offset, str, tc); DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company), EIT_PURCHASE); if (show_count) { SetDParam(0, num_engines); DrawString(count_left, count_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT | SA_FORCE); if (EngineHasReplacementForCompany(Company::Get(_local_company), engine, selected_group)) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, num_engines == 0 ? PALETTE_CRASH : PAL_NONE, replace_icon_left, y + replace_icon_y_offset); } } } /** * Display the dropdown for the vehicle sort criteria. * @param w Parent window (holds the dropdown button). * @param vehicle_type %Vehicle type being sorted. * @param selected Currently selected sort criterium. * @param button Widget button. */ void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selected, int button) { uint32 hidden_mask = 0; /* Disable sorting by power or tractive effort when the original acceleration model for road vehicles is being used. */ if (vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) { SetBit(hidden_mask, 3); // power SetBit(hidden_mask, 4); // tractive effort SetBit(hidden_mask, 8); // power by running costs } /* Disable sorting by tractive effort when the original acceleration model for trains is being used. */ if (vehicle_type == VEH_TRAIN && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) { SetBit(hidden_mask, 4); // tractive effort } ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask); } /** GUI for building vehicles. */ struct BuildVehicleWindow : Window { VehicleType vehicle_type; ///< Type of vehicles shown in the window. union { RailTypeByte railtype; ///< Rail type to show, or #RAILTYPE_END. RoadTypes roadtypes; ///< Road type to show, or #ROADTYPES_ALL. } filter; ///< Filter to apply. bool descending_sort_order; ///< Sort direction, @see _engine_sort_direction byte sort_criteria; ///< Current sort criterium. bool show_hidden_engines; ///< State of the 'show hidden engines' button. bool listview_mode; ///< If set, only display the available vehicles and do not show a 'build' button. EngineID sel_engine; ///< Currently selected engine, or #INVALID_ENGINE EngineID rename_engine; ///< Engine being renamed. GUIEngineList eng_list; CargoID cargo_filter[NUM_CARGO + 2]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE StringID cargo_filter_texts[NUM_CARGO + 3]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID byte cargo_filter_criteria; ///< Selected cargo filter int details_height; ///< Minimal needed height of the details panels (found so far). Scrollbar *vscroll; BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc) { this->vehicle_type = type; this->window_number = tile == INVALID_TILE ? (int)type : tile; this->sel_engine = INVALID_ENGINE; this->sort_criteria = _engine_sort_last_criteria[type]; this->descending_sort_order = _engine_sort_last_order[type]; this->show_hidden_engines = _engine_sort_show_hidden_engines[type]; switch (type) { default: NOT_REACHED(); case VEH_TRAIN: this->filter.railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile); break; case VEH_ROAD: this->filter.roadtypes = (tile == INVALID_TILE) ? ROADTYPES_ALL : GetRoadTypes(tile); case VEH_SHIP: case VEH_AIRCRAFT: break; } this->listview_mode = (this->window_number <= VEH_END); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_BV_SCROLLBAR); /* If we are just viewing the list of vehicles, we do not need the Build button. * So we just hide it, and enlarge the Rename button by the now vacant place. */ if (this->listview_mode) this->GetWidget(WID_BV_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE); /* disable renaming engines in network games if you are not the server */ this->SetWidgetDisabledState(WID_BV_RENAME, _networking && !_network_server); NWidgetCore *widget = this->GetWidget(WID_BV_LIST); widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type; widget = this->GetWidget(WID_BV_SHOW_HIDE); widget->tool_tip = STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP + type; widget = this->GetWidget(WID_BV_BUILD); widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + type; widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + type; widget = this->GetWidget(WID_BV_RENAME); widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type; widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type; widget = this->GetWidget(WID_BV_SHOW_HIDDEN_ENGINES); widget->widget_data = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN + type; widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type; widget->SetLowered(this->show_hidden_engines); this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile); this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company; this->eng_list.ForceRebuild(); this->GenerateBuildList(); // generate the list, since we need it in the next line /* Select the first engine in the list as default when opening the window */ if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0]; } /** Populate the filter list and set the cargo filter criteria. */ void SetCargoFilterArray() { uint filter_items = 0; /* Add item for disabling filtering. */ this->cargo_filter[filter_items] = CF_ANY; this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES; filter_items++; /* Add item for vehicles not carrying anything, e.g. train engines. * This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */ if (this->vehicle_type == VEH_TRAIN) { this->cargo_filter[filter_items] = CF_NONE; this->cargo_filter_texts[filter_items] = STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE; filter_items++; } /* Collect available cargo types for filtering. */ const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { this->cargo_filter[filter_items] = cs->Index(); this->cargo_filter_texts[filter_items] = cs->name; filter_items++; } /* Terminate the filter list. */ this->cargo_filter_texts[filter_items] = INVALID_STRING_ID; /* If not found, the cargo criteria will be set to all cargoes. */ this->cargo_filter_criteria = 0; /* Find the last cargo filter criteria. */ for (uint i = 0; i < filter_items; i++) { if (this->cargo_filter[i] == _engine_sort_last_cargo_criteria[this->vehicle_type]) { this->cargo_filter_criteria = i; break; } } this->eng_list.SetFilterFuncs(_filter_funcs); this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); } void OnInit() { this->SetCargoFilterArray(); } /** Filter the engine list against the currently selected cargo filter */ void FilterEngineList() { this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]); if (0 == this->eng_list.Length()) { // no engine passed through the filter, invalidate the previously selected engine this->sel_engine = INVALID_ENGINE; } else if (!this->eng_list.Contains(this->sel_engine)) { // previously selected engine didn't pass the filter, select the first engine of the list this->sel_engine = this->eng_list[0]; } } /** Filter a single engine */ bool FilterSingleEngine(EngineID eid) { CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria]; return (filter_type == CF_ANY || CargoFilter(&eid, filter_type)); } /* Figure out what train EngineIDs to put in the list */ void GenerateBuildTrainList() { EngineID sel_id = INVALID_ENGINE; int num_engines = 0; int num_wagons = 0; this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number); this->eng_list.Clear(); /* Make list of all available train engines and wagons. * Also check to see if the previously selected engine is still available, * and if not, reset selection to INVALID_ENGINE. This could be the case * when engines become obsolete and are removed */ const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; const RailVehicleInfo *rvi = &e->u.rail; if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue; if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue; /* Filter now! So num_engines and num_wagons is valid */ if (!FilterSingleEngine(eid)) continue; *this->eng_list.Append() = eid; if (rvi->railveh_type != RAILVEH_WAGON) { num_engines++; } else { num_wagons++; } if (eid == this->sel_engine) sel_id = eid; } this->sel_engine = sel_id; /* make engines first, and then wagons, sorted by selected sort_criteria */ _engine_sort_direction = false; EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter); /* and then sort engines */ _engine_sort_direction = this->descending_sort_order; EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], 0, num_engines); /* and finally sort wagons */ EngList_SortPartial(&this->eng_list, _engine_sort_functions[0][this->sort_criteria], num_engines, num_wagons); } /* Figure out what road vehicle EngineIDs to put in the list */ void GenerateBuildRoadVehList() { EngineID sel_id = INVALID_ENGINE; this->eng_list.Clear(); const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) { if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue; if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue; *this->eng_list.Append() = eid; if (eid == this->sel_engine) sel_id = eid; } this->sel_engine = sel_id; } /* Figure out what ship EngineIDs to put in the list */ void GenerateBuildShipList() { EngineID sel_id = INVALID_ENGINE; this->eng_list.Clear(); const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) { if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue; *this->eng_list.Append() = eid; if (eid == this->sel_engine) sel_id = eid; } this->sel_engine = sel_id; } /* Figure out what aircraft EngineIDs to put in the list */ void GenerateBuildAircraftList() { EngineID sel_id = INVALID_ENGINE; this->eng_list.Clear(); const Station *st = this->listview_mode ? NULL : Station::GetByTile(this->window_number); /* Make list of all available planes. * Also check to see if the previously selected plane is still available, * and if not, reset selection to INVALID_ENGINE. This could be the case * when planes become obsolete and are removed */ const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) { if (!this->show_hidden_engines && e->IsHidden(_local_company)) continue; EngineID eid = e->index; if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue; /* First VEH_END window_numbers are fake to allow a window open for all different types at once */ if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue; *this->eng_list.Append() = eid; if (eid == this->sel_engine) sel_id = eid; } this->sel_engine = sel_id; } /* Generate the list of vehicles */ void GenerateBuildList() { if (!this->eng_list.NeedRebuild()) return; switch (this->vehicle_type) { default: NOT_REACHED(); case VEH_TRAIN: this->GenerateBuildTrainList(); this->eng_list.Compact(); this->eng_list.RebuildDone(); return; // trains should not reach the last sorting case VEH_ROAD: this->GenerateBuildRoadVehList(); break; case VEH_SHIP: this->GenerateBuildShipList(); break; case VEH_AIRCRAFT: this->GenerateBuildAircraftList(); break; } this->FilterEngineList(); _engine_sort_direction = this->descending_sort_order; EngList_Sort(&this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]); this->eng_list.Compact(); this->eng_list.RebuildDone(); } void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BV_SORT_ASCENDING_DESCENDING: this->descending_sort_order ^= true; _engine_sort_last_order[this->vehicle_type] = this->descending_sort_order; this->eng_list.ForceRebuild(); this->SetDirty(); break; case WID_BV_SHOW_HIDDEN_ENGINES: this->show_hidden_engines ^= true; _engine_sort_show_hidden_engines[this->vehicle_type] = this->show_hidden_engines; this->eng_list.ForceRebuild(); this->SetWidgetLoweredState(widget, this->show_hidden_engines); this->SetDirty(); break; case WID_BV_LIST: { uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BV_LIST); size_t num_items = this->eng_list.Length(); this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE; this->SetDirty(); if (_ctrl_pressed) { this->OnClick(pt, WID_BV_SHOW_HIDE, 1); } else if (click_count > 1 && !this->listview_mode) { this->OnClick(pt, WID_BV_BUILD, 1); } break; } case WID_BV_SORT_DROPDOWN: // Select sorting criteria dropdown menu DisplayVehicleSortDropDown(this, this->vehicle_type, this->sort_criteria, WID_BV_SORT_DROPDOWN); break; case WID_BV_CARGO_FILTER_DROPDOWN: // Select cargo filtering criteria dropdown menu ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, WID_BV_CARGO_FILTER_DROPDOWN, 0, 0); break; case WID_BV_SHOW_HIDE: { const Engine *e = (this->sel_engine == INVALID_ENGINE) ? NULL : Engine::Get(this->sel_engine); if (e != NULL) { DoCommandP(0, 0, this->sel_engine | (e->IsHidden(_current_company) ? 0 : (1u << 31)), CMD_SET_VEHICLE_VISIBILITY); } break; } case WID_BV_BUILD: { EngineID sel_eng = this->sel_engine; if (sel_eng != INVALID_ENGINE) { CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle; DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback); } break; } case WID_BV_RENAME: { EngineID sel_eng = this->sel_engine; if (sel_eng != INVALID_ENGINE) { this->rename_engine = sel_eng; SetDParam(0, sel_eng); ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); } 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; /* When switching to original acceleration model for road vehicles, clear the selected sort criteria if it is not available now. */ if (this->vehicle_type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL && this->sort_criteria > 7) { this->sort_criteria = 0; _engine_sort_last_criteria[VEH_ROAD] = 0; } this->eng_list.ForceRebuild(); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_BV_CAPTION: if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) { const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype); SetDParam(0, rti->strings.build_caption); } else { SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type); } break; case WID_BV_SORT_DROPDOWN: SetDParam(0, _engine_sort_listing[this->vehicle_type][this->sort_criteria]); break; case WID_BV_CARGO_FILTER_DROPDOWN: SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]); break; case WID_BV_SHOW_HIDE: { const Engine *e = (this->sel_engine == INVALID_ENGINE) ? NULL : Engine::Get(this->sel_engine); if (e != NULL && e->IsHidden(_local_company)) { SetDParam(0, STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type); } else { SetDParam(0, STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); } break; } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_BV_LIST: resize->height = GetEngineListHeight(this->vehicle_type); size->height = 3 * resize->height; size->width = max(size->width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165); break; case WID_BV_PANEL: size->height = this->details_height; break; case WID_BV_SORT_ASCENDING_DESCENDING: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_BV_SHOW_HIDE: *size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type); *size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type)); size->width += padding.width; size->height += padding.height; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_BV_LIST: DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP); break; case WID_BV_SORT_ASCENDING_DESCENDING: this->DrawSortButtonState(WID_BV_SORT_ASCENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP); break; } } virtual void OnPaint() { this->GenerateBuildList(); this->vscroll->SetCount(this->eng_list.Length()); this->SetWidgetDisabledState(WID_BV_SHOW_HIDE, this->sel_engine == INVALID_ENGINE); this->DrawWidgets(); if (!this->IsShaded()) { int needed_height = this->details_height; /* Draw details panels. */ if (this->sel_engine != INVALID_ENGINE) { NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL); int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine); needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); } if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. int resize = needed_height - this->details_height; this->details_height = needed_height; this->ReInit(0, resize); return; } } } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str); } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_BV_SORT_DROPDOWN: if (this->sort_criteria != index) { this->sort_criteria = index; _engine_sort_last_criteria[this->vehicle_type] = this->sort_criteria; this->eng_list.ForceRebuild(); } break; case WID_BV_CARGO_FILTER_DROPDOWN: // Select a cargo filter criteria if (this->cargo_filter_criteria != index) { this->cargo_filter_criteria = index; _engine_sort_last_cargo_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria]; /* deactivate filter if criteria is 'Show All', activate it otherwise */ this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY); this->eng_list.ForceRebuild(); } break; } this->SetDirty(); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_BV_LIST); } }; static WindowDesc _build_vehicle_desc( WDP_AUTO, "build_vehicle", 240, 268, WC_BUILD_VEHICLE, WC_NONE, WDF_CONSTRUCTION, _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets) ); void ShowBuildVehicleWindow(TileIndex tile, VehicleType type) { /* We want to be able to open both Available Train as Available Ships, * so if tile == INVALID_TILE (Available XXX Window), use 'type' as unique number. * As it always is a low value, it won't collide with any real tile * number. */ uint num = (tile == INVALID_TILE) ? (int)type : tile; assert(IsCompanyBuildableVehicleType(type)); DeleteWindowById(WC_BUILD_VEHICLE, num); new BuildVehicleWindow(&_build_vehicle_desc, tile, type); } openttd-1.5.3/src/genworld.cpp0000644000000000000000000002406412627373442015027 0ustar rootroot/* $Id: genworld.cpp 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 genworld.cpp Functions to generate a map. */ #include "stdafx.h" #include "landscape.h" #include "company_func.h" #include "genworld.h" #include "gfxinit.h" #include "window_func.h" #include "network/network.h" #include "heightmap.h" #include "viewport_func.h" #include "date_func.h" #include "engine_func.h" #include "water.h" #include "video/video_driver.hpp" #include "tilehighlight_func.h" #include "saveload/saveload.h" #include "void_map.h" #include "town.h" #include "newgrf.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "progress.h" #include "error.h" #include "game/game.hpp" #include "game/game_instance.hpp" #include "string_func.h" #include "safeguards.h" void GenerateClearTile(); void GenerateIndustries(); void GenerateObjects(); void GenerateTrees(); void StartupEconomy(); void StartupCompanies(); void StartupDisasters(); void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settings); /** * Please only use this variable in genworld.h and genworld.cpp and * nowhere else. For speed improvements we need it to be global, but * in no way the meaning of it is to use it anywhere else besides * in the genworld.h and genworld.cpp! */ GenWorldInfo _gw; /** Whether we are generating the map or not. */ bool _generating_world; /** * Tells if the world generation is done in a thread or not. * @return the 'threaded' status */ bool IsGenerateWorldThreaded() { return _gw.threaded && !_gw.quit_thread; } /** * Clean up the 'mess' of generation. That is, show windows again, reset * thread variables, and delete the progress window. */ static void CleanupGeneration() { _generating_world = false; if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE); /* Show all vital windows again, because we have hidden them */ if (_gw.threaded && _game_mode != GM_MENU) ShowVitalWindows(); SetModalProgress(false); _gw.proc = NULL; _gw.abortp = NULL; _gw.threaded = false; DeleteWindowByClass(WC_MODAL_PROGRESS); ShowFirstError(); MarkWholeScreenDirty(); } /** * The internal, real, generate function. */ static void _GenerateWorld(void *) { /* Make sure everything is done via OWNER_NONE. */ Backup _cur_company(_current_company, OWNER_NONE, FILE_LINE); try { _generating_world = true; _modal_progress_work_mutex->BeginCritical(); if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait..."); /* Set the Random() seed to generation_seed so we produce the same map with the same seed */ if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom(); _random.SetSeed(_settings_game.game_creation.generation_seed); SetGeneratingWorldProgress(GWP_MAP_INIT, 2); SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP); IncreaseGeneratingWorldProgress(GWP_MAP_INIT); /* Must start economy early because of the costs. */ StartupEconomy(); /* Don't generate landscape items when in the scenario editor. */ if (_gw.mode == GWM_EMPTY) { SetGeneratingWorldProgress(GWP_OBJECT, 1); /* Make sure the tiles at the north border are void tiles if needed. */ if (_settings_game.construction.freeform_edges) { for (uint row = 0; row < MapSizeY(); row++) MakeVoid(TileXY(0, row)); for (uint col = 0; col < MapSizeX(); col++) MakeVoid(TileXY(col, 0)); } /* Make the map the height of the setting */ if (_game_mode != GM_MENU) FlatEmptyWorld(_settings_game.game_creation.se_flat_world_height); ConvertGroundTilesIntoWaterTiles(); IncreaseGeneratingWorldProgress(GWP_OBJECT); } else { GenerateLandscape(_gw.mode); GenerateClearTile(); /* only generate towns, tree and industries in newgame mode. */ if (_game_mode != GM_EDITOR) { if (!GenerateTowns(_settings_game.economy.town_layout)) { _cur_company.Restore(); HandleGeneratingWorldAbortion(); return; } GenerateIndustries(); GenerateObjects(); GenerateTrees(); } } /* These are probably pointless when inside the scenario editor. */ SetGeneratingWorldProgress(GWP_GAME_INIT, 3); StartupCompanies(); IncreaseGeneratingWorldProgress(GWP_GAME_INIT); StartupEngines(); IncreaseGeneratingWorldProgress(GWP_GAME_INIT); StartupDisasters(); _generating_world = false; /* No need to run the tile loop in the scenario editor. */ if (_gw.mode != GWM_EMPTY) { uint i; SetGeneratingWorldProgress(GWP_RUNTILELOOP, 0x500); for (i = 0; i < 0x500; i++) { RunTileLoop(); _tick_counter++; IncreaseGeneratingWorldProgress(GWP_RUNTILELOOP); } if (_game_mode != GM_EDITOR) { Game::StartNew(); if (Game::GetInstance() != NULL) { SetGeneratingWorldProgress(GWP_RUNSCRIPT, 2500); _generating_world = true; for (i = 0; i < 2500; i++) { Game::GameLoop(); IncreaseGeneratingWorldProgress(GWP_RUNSCRIPT); if (Game::GetInstance()->IsSleeping()) break; } _generating_world = false; } } } BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP); ResetObjectToPlace(); _cur_company.Trash(); _current_company = _local_company = _gw.lc; SetGeneratingWorldProgress(GWP_GAME_START, 1); /* Call any callback */ if (_gw.proc != NULL) _gw.proc(); IncreaseGeneratingWorldProgress(GWP_GAME_START); CleanupGeneration(); _modal_progress_work_mutex->EndCritical(); ShowNewGRFError(); if (_network_dedicated) DEBUG(net, 1, "Map generated, starting game"); DEBUG(desync, 1, "new_map: %08x", _settings_game.game_creation.generation_seed); if (_debug_desync_level > 0) { char name[MAX_PATH]; seprintf(name, lastof(name), "dmp_cmds_%08x_%08x.sav", _settings_game.game_creation.generation_seed, _date); SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR, false); } } catch (...) { BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true); if (_cur_company.IsValid()) _cur_company.Restore(); _generating_world = false; _modal_progress_work_mutex->EndCritical(); throw; } } /** * Set here the function, if any, that you want to be called when landscape * generation is done. * @param proc callback procedure */ void GenerateWorldSetCallback(GWDoneProc *proc) { _gw.proc = proc; } /** * Set here the function, if any, that you want to be called when landscape * generation is aborted. * @param proc callback procedure */ void GenerateWorldSetAbortCallback(GWAbortProc *proc) { _gw.abortp = proc; } /** * This will wait for the thread to finish up his work. It will not continue * till the work is done. */ void WaitTillGeneratedWorld() { if (_gw.thread == NULL) return; _modal_progress_work_mutex->EndCritical(); _modal_progress_paint_mutex->EndCritical(); _gw.quit_thread = true; _gw.thread->Join(); delete _gw.thread; _gw.thread = NULL; _gw.threaded = false; _modal_progress_work_mutex->BeginCritical(); _modal_progress_paint_mutex->BeginCritical(); } /** * Initializes the abortion process */ void AbortGeneratingWorld() { _gw.abort = true; } /** * Is the generation being aborted? * @return the 'aborted' status */ bool IsGeneratingWorldAborted() { return _gw.abort; } /** * Really handle the abortion, i.e. clean up some of the mess */ void HandleGeneratingWorldAbortion() { /* Clean up - in SE create an empty map, otherwise, go to intro menu */ _switch_mode = (_game_mode == GM_EDITOR) ? SM_EDITOR : SM_MENU; if (_gw.abortp != NULL) _gw.abortp(); CleanupGeneration(); if (_gw.thread != NULL) _gw.thread->Exit(); SwitchToMode(_switch_mode); } /** * Generate a world. * @param mode The mode of world generation (see GenWorldMode). * @param size_x The X-size of the map. * @param size_y The Y-size of the map. * @param reset_settings Whether to reset the game configuration (used for restart) */ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_settings) { if (HasModalProgress()) return; _gw.mode = mode; _gw.size_x = size_x; _gw.size_y = size_y; SetModalProgress(true); _gw.abort = false; _gw.abortp = NULL; _gw.lc = _local_company; _gw.quit_thread = false; _gw.threaded = true; /* This disables some commands and stuff */ SetLocalCompany(COMPANY_SPECTATOR); InitializeGame(_gw.size_x, _gw.size_y, true, reset_settings); PrepareGenerateWorldProgress(); /* Load the right landscape stuff, and the NewGRFs! */ GfxLoadSprites(); LoadStringWidthTable(); /* Re-init the windowing system */ ResetWindowSystem(); /* Create toolbars */ SetupColoursAndInitialWindow(); SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0); if (_gw.thread != NULL) { _gw.thread->Join(); delete _gw.thread; _gw.thread = NULL; } if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&_GenerateWorld, NULL, &_gw.thread)) { DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode"); _gw.threaded = false; _modal_progress_work_mutex->EndCritical(); _GenerateWorld(NULL); _modal_progress_work_mutex->BeginCritical(); return; } UnshowCriticalError(); /* Remove any open window */ DeleteAllNonVitalWindows(); /* Hide vital windows, because we don't allow to use them */ HideVitalWindows(); /* Don't show the dialog if we don't have a thread */ ShowGenerateWorldProgress(); /* Centre the view on the map */ if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) { ScrollMainWindowToTile(TileXY(MapSizeX() / 2, MapSizeY() / 2), true); } } openttd-1.5.3/src/network/0000755000000000000000000000000012627373441014164 5ustar rootrootopenttd-1.5.3/src/network/network_admin.cpp0000644000000000000000000007717412627373441017551 0ustar rootroot/* $Id: network_admin.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 network_admin.cpp Server part of the admin network protocol. */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" #include "network_admin.h" #include "network_base.h" #include "network_server.h" #include "../command_func.h" #include "../company_base.h" #include "../console_func.h" #include "../core/pool_func.hpp" #include "../map_func.h" #include "../rev.h" #include "../game/game.hpp" #include "../safeguards.h" /* This file handles all the admin network commands. */ /** Redirection of the (remote) console to the admin. */ AdminIndex _redirect_console_to_admin = INVALID_ADMIN_ID; /** The amount of admins connected. */ byte _network_admins_connected = 0; /** The pool with sockets/clients. */ NetworkAdminSocketPool _networkadminsocket_pool("NetworkAdminSocket"); INSTANTIATE_POOL_METHODS(NetworkAdminSocket) /** The timeout for authorisation of the client. */ static const int ADMIN_AUTHORISATION_TIMEOUT = 10000; /** Frequencies, which may be registered for a certain update type. */ static const AdminUpdateFrequency _admin_update_type_frequencies[] = { ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_DAILY | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY, ///< ADMIN_UPDATE_DATE ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_CLIENT_INFO ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_COMPANY_INFO ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY, ///< ADMIN_UPDATE_COMPANY_ECONOMY ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY, ///< ADMIN_UPDATE_COMPANY_STATS ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_CHAT ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_CONSOLE ADMIN_FREQUENCY_POLL, ///< ADMIN_UPDATE_CMD_NAMES ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_CMD_LOGGING ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_GAMESCRIPT }; /** Sanity check. */ assert_compile(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END); /** * Create a new socket for the server side of the admin network. * @param s The socket to connect with. */ ServerNetworkAdminSocketHandler::ServerNetworkAdminSocketHandler(SOCKET s) : NetworkAdminSocketHandler(s) { _network_admins_connected++; this->status = ADMIN_STATUS_INACTIVE; this->realtime_connect = _realtime_tick; } /** * Clear everything related to this admin. */ ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler() { _network_admins_connected--; DEBUG(net, 1, "[admin] '%s' (%s) has disconnected", this->admin_name, this->admin_version); if (_redirect_console_to_admin == this->index) _redirect_console_to_admin = INVALID_ADMIN_ID; } /** * Whether a connection is allowed or not at this moment. * @return Whether the connection is allowed. */ /* static */ bool ServerNetworkAdminSocketHandler::AllowConnection() { bool accept = !StrEmpty(_settings_client.network.admin_password) && _network_admins_connected < MAX_ADMINS; /* We can't go over the MAX_ADMINS limit here. However, if we accept * the connection, there has to be space in the pool. */ assert_compile(NetworkAdminSocketPool::MAX_SIZE == MAX_ADMINS); assert(!accept || ServerNetworkAdminSocketHandler::CanAllocateItem()); return accept; } /** Send the packets for the server sockets. */ /* static */ void ServerNetworkAdminSocketHandler::Send() { ServerNetworkAdminSocketHandler *as; FOR_ALL_ADMIN_SOCKETS(as) { if (as->status == ADMIN_STATUS_INACTIVE && as->realtime_connect + ADMIN_AUTHORISATION_TIMEOUT < _realtime_tick) { DEBUG(net, 1, "[admin] Admin did not send its authorisation within %d seconds", ADMIN_AUTHORISATION_TIMEOUT / 1000); as->CloseConnection(true); continue; } if (as->writable) { as->SendPackets(); } } } /** * Handle the acception of a connection. * @param s The socket of the new connection. * @param address The address of the peer. */ /* static */ void ServerNetworkAdminSocketHandler::AcceptConnection(SOCKET s, const NetworkAddress &address) { ServerNetworkAdminSocketHandler *as = new ServerNetworkAdminSocketHandler(s); as->address = address; // Save the IP of the client } /*********** * Sending functions for admin network ************/ /** * Send an error to the admin. * @param error The error to send. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendError(NetworkErrorCode error) { Packet *p = new Packet(ADMIN_PACKET_SERVER_ERROR); p->Send_uint8(error); this->SendPacket(p); char str[100]; StringID strid = GetNetworkErrorMsg(error); GetString(str, strid, lastof(str)); DEBUG(net, 1, "[admin] the admin '%s' (%s) made an error and has been disconnected. Reason: '%s'", this->admin_name, this->admin_version, str); return this->CloseConnection(true); } /** Send the protocol version to the admin. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendProtocol() { Packet *p = new Packet(ADMIN_PACKET_SERVER_PROTOCOL); /* announce the protocol version */ p->Send_uint8(NETWORK_GAME_ADMIN_VERSION); for (int i = 0; i < ADMIN_UPDATE_END; i++) { p->Send_bool (true); p->Send_uint16(i); p->Send_uint16(_admin_update_type_frequencies[i]); } p->Send_bool(false); this->SendPacket(p); return this->SendWelcome(); } /** Send a welcome message to the admin. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome() { Packet *p = new Packet(ADMIN_PACKET_SERVER_WELCOME); p->Send_string(_settings_client.network.server_name); p->Send_string(_openttd_revision); p->Send_bool (_network_dedicated); p->Send_string(_network_game_info.map_name); p->Send_uint32(_settings_game.game_creation.generation_seed); p->Send_uint8 (_settings_game.game_creation.landscape); p->Send_uint32(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1)); p->Send_uint16(MapSizeX()); p->Send_uint16(MapSizeY()); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the admin we started a new game. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendNewGame() { Packet *p = new Packet(ADMIN_PACKET_SERVER_NEWGAME); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the admin we're shutting down. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendShutdown() { Packet *p = new Packet(ADMIN_PACKET_SERVER_SHUTDOWN); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the admin the date. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendDate() { Packet *p = new Packet(ADMIN_PACKET_SERVER_DATE); p->Send_uint32(_date); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the admin that a client joined. * @param client_id The client that joined. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID client_id) { Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_JOIN); p->Send_uint32(client_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send an initial set of data from some client's information. * @param cs The socket of the client. * @param ci The information about the client. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkClientSocket *cs, const NetworkClientInfo *ci) { /* Only send data when we're a proper client, not just someone trying to query the server. */ if (ci == NULL) return NETWORK_RECV_STATUS_OKAY; Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_INFO); p->Send_uint32(ci->client_id); p->Send_string(cs == NULL ? "" : const_cast(cs->client_address).GetHostname()); p->Send_string(ci->client_name); p->Send_uint8 (ci->client_lang); p->Send_uint32(ci->join_date); p->Send_uint8 (ci->client_playas); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send an update for some client's information. * @param ci The information about a client. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientUpdate(const NetworkClientInfo *ci) { Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_UPDATE); p->Send_uint32(ci->client_id); p->Send_string(ci->client_name); p->Send_uint8 (ci->client_playas); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the admin that a client quit. * @param client_id The client that quit. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientQuit(ClientID client_id) { Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_QUIT); p->Send_uint32(client_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the admin that a client made an error. * @param client_id The client that made the error. * @param error The error that was made. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientError(ClientID client_id, NetworkErrorCode error) { Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_ERROR); p->Send_uint32(client_id); p->Send_uint8 (error); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the admin that a new company was founded. * @param company_id The company that was founded. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID company_id) { Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_NEW); p->Send_uint8(company_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send the admin some information about a company. * @param c The company to send the information about. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company *c) { char company_name[NETWORK_COMPANY_NAME_LENGTH]; char manager_name[NETWORK_COMPANY_NAME_LENGTH]; SetDParam(0, c->index); GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); SetDParam(0, c->index); GetString(manager_name, STR_PRESIDENT_NAME, lastof(manager_name)); Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_INFO); p->Send_uint8 (c->index); p->Send_string(company_name); p->Send_string(manager_name); p->Send_uint8 (c->colour); p->Send_bool (NetworkCompanyIsPassworded(c->index)); p->Send_uint32(c->inaugurated_year); p->Send_bool (c->is_ai); p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy for (size_t i = 0; i < lengthof(c->share_owners); i++) { p->Send_uint8(c->share_owners[i]); } this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send an update about a company. * @param c The company to send the update of. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company *c) { char company_name[NETWORK_COMPANY_NAME_LENGTH]; char manager_name[NETWORK_COMPANY_NAME_LENGTH]; SetDParam(0, c->index); GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); SetDParam(0, c->index); GetString(manager_name, STR_PRESIDENT_NAME, lastof(manager_name)); Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_UPDATE); p->Send_uint8 (c->index); p->Send_string(company_name); p->Send_string(manager_name); p->Send_uint8 (c->colour); p->Send_bool (NetworkCompanyIsPassworded(c->index)); p->Send_uint8 (CeilDiv(c->months_of_bankruptcy, 3)); // send as quarters_of_bankruptcy for (size_t i = 0; i < lengthof(c->share_owners); i++) { p->Send_uint8(c->share_owners[i]); } this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the admin that a company got removed. * @param company_id The company that got removed. * @param acrr The reason for removal, e.g. bankruptcy or merger. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason acrr) { Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_REMOVE); p->Send_uint8(company_id); p->Send_uint8(acrr); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send economic information of all companies. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyEconomy() { const Company *company; FOR_ALL_COMPANIES(company) { /* Get the income. */ Money income = 0; for (uint i = 0; i < lengthof(company->yearly_expenses[0]); i++) { income -= company->yearly_expenses[0][i]; } Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_ECONOMY); p->Send_uint8(company->index); /* Current information. */ p->Send_uint64(company->money); p->Send_uint64(company->current_loan); p->Send_uint64(income); p->Send_uint16(min(UINT16_MAX, company->cur_economy.delivered_cargo.GetSum())); /* Send stats for the last 2 quarters. */ for (uint i = 0; i < 2; i++) { p->Send_uint64(company->old_economy[i].company_value); p->Send_uint16(company->old_economy[i].performance_history); p->Send_uint16(min(UINT16_MAX, company->old_economy[i].delivered_cargo.GetSum())); } this->SendPacket(p); } return NETWORK_RECV_STATUS_OKAY; } /** Send statistics about the companies. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyStats() { /* Fetch the latest version of the stats. */ NetworkCompanyStats company_stats[MAX_COMPANIES]; NetworkPopulateCompanyStats(company_stats); const Company *company; /* Go through all the companies. */ FOR_ALL_COMPANIES(company) { Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_STATS); /* Send the information. */ p->Send_uint8(company->index); for (uint i = 0; i < NETWORK_VEH_END; i++) { p->Send_uint16(company_stats[company->index].num_vehicle[i]); } for (uint i = 0; i < NETWORK_VEH_END; i++) { p->Send_uint16(company_stats[company->index].num_station[i]); } this->SendPacket(p); } return NETWORK_RECV_STATUS_OKAY; } /** * Send a chat message. * @param action The action associated with the message. * @param desttype The destination type. * @param client_id The origin of the chat message. * @param msg The actual message. * @param data Arbitrary extra data. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data) { Packet *p = new Packet(ADMIN_PACKET_SERVER_CHAT); p->Send_uint8 (action); p->Send_uint8 (desttype); p->Send_uint32(client_id); p->Send_string(msg); p->Send_uint64(data); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send a notification indicating the rcon command has completed. * @param command The original command sent. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRconEnd(const char *command) { Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON_END); p->Send_string(command); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send the reply of an rcon command. * @param colour The colour of the text. * @param result The result of the command. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendRcon(uint16 colour, const char *result) { Packet *p = new Packet(ADMIN_PACKET_SERVER_RCON); p->Send_uint16(colour); p->Send_string(result); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p) { if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); char command[NETWORK_RCONCOMMAND_LENGTH]; p->Recv_string(command, sizeof(command)); DEBUG(net, 2, "[admin] Rcon command from '%s' (%s): '%s'", this->admin_name, this->admin_version, command); _redirect_console_to_admin = this->index; IConsoleCmdExec(command); _redirect_console_to_admin = INVALID_ADMIN_ID; return this->SendRconEnd(command); } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet *p) { if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); char json[NETWORK_GAMESCRIPT_JSON_LENGTH]; p->Recv_string(json, sizeof(json)); DEBUG(net, 2, "[admin] GameScript JSON from '%s' (%s): '%s'", this->admin_name, this->admin_version, json); Game::NewEvent(new ScriptEventAdminPort(json)); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p) { if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); uint32 d1 = p->Recv_uint32(); DEBUG(net, 2, "[admin] Ping from '%s' (%s): '%d'", this->admin_name, this->admin_version, d1); return this->SendPong(d1); } /** * Send console output of other clients. * @param origin The origin of the string. * @param string The string that's put on the console. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const char *origin, const char *string) { /* If the length of both strings, plus the 2 '\0' terminations and 3 bytes of the packet * are bigger than the MTU, just ignore the message. Better safe than sorry. It should * never occur though as the longest strings are chat messages, which are still 30% * smaller than SEND_MTU. */ if (strlen(origin) + strlen(string) + 2 + 3 >= SEND_MTU) return NETWORK_RECV_STATUS_OKAY; Packet *p = new Packet(ADMIN_PACKET_SERVER_CONSOLE); p->Send_string(origin); p->Send_string(string); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send GameScript JSON output. * @param json The JSON string. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendGameScript(const char *json) { /* At the moment we cannot transmit anything larger than MTU. So we limit * the maximum amount of json data that can be sent. Account also for * the trailing \0 of the string */ if (strlen(json) + 1 >= NETWORK_GAMESCRIPT_JSON_LENGTH) return NETWORK_RECV_STATUS_OKAY; Packet *p = new Packet(ADMIN_PACKET_SERVER_GAMESCRIPT); p->Send_string(json); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send ping-reply (pong) to admin **/ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendPong(uint32 d1) { Packet *p = new Packet(ADMIN_PACKET_SERVER_PONG); p->Send_uint32(d1); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send the names of the commands. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames() { Packet *p = new Packet(ADMIN_PACKET_SERVER_CMD_NAMES); for (uint i = 0; i < CMD_END; i++) { const char *cmdname = GetCommandName(i); /* Should SEND_MTU be exceeded, start a new packet * (magic 5: 1 bool "more data" and one uint16 "command id", one * byte for string '\0' termination and 1 bool "no more data" */ if (p->size + strlen(cmdname) + 5 >= SEND_MTU) { p->Send_bool(false); this->SendPacket(p); p = new Packet(ADMIN_PACKET_SERVER_CMD_NAMES); } p->Send_bool(true); p->Send_uint16(i); p->Send_string(cmdname); } /* Marker to notify the end of the packet has been reached. */ p->Send_bool(false); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send a command for logging purposes. * @param client_id The client executing the command. * @param cp The command that would be executed. */ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdLogging(ClientID client_id, const CommandPacket *cp) { Packet *p = new Packet(ADMIN_PACKET_SERVER_CMD_LOGGING); p->Send_uint32(client_id); p->Send_uint8 (cp->company); p->Send_uint16(cp->cmd & CMD_ID_MASK); p->Send_uint32(cp->p1); p->Send_uint32(cp->p2); p->Send_uint32(cp->tile); p->Send_string(cp->text); p->Send_uint32(cp->frame); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /*********** * Receiving functions ************/ NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p) { if (this->status != ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); char password[NETWORK_PASSWORD_LENGTH]; p->Recv_string(password, sizeof(password)); if (StrEmpty(_settings_client.network.admin_password) || strcmp(password, _settings_client.network.admin_password) != 0) { /* Password is invalid */ return this->SendError(NETWORK_ERROR_WRONG_PASSWORD); } p->Recv_string(this->admin_name, sizeof(this->admin_name)); p->Recv_string(this->admin_version, sizeof(this->admin_version)); if (StrEmpty(this->admin_name) || StrEmpty(this->admin_version)) { /* no name or version supplied */ return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET); } this->status = ADMIN_STATUS_ACTIVE; DEBUG(net, 1, "[admin] '%s' (%s) has connected", this->admin_name, this->admin_version); return this->SendProtocol(); } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet *p) { /* The admin is leaving nothing else to do */ return this->CloseConnection(); } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet *p) { if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); AdminUpdateType type = (AdminUpdateType)p->Recv_uint16(); AdminUpdateFrequency freq = (AdminUpdateFrequency)p->Recv_uint16(); if (type >= ADMIN_UPDATE_END || (_admin_update_type_frequencies[type] & freq) != freq) { /* The server does not know of this UpdateType. */ DEBUG(net, 3, "[admin] Not supported update frequency %d (%d) from '%s' (%s).", type, freq, this->admin_name, this->admin_version); return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET); } this->update_frequency[type] = freq; return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p) { if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); AdminUpdateType type = (AdminUpdateType)p->Recv_uint8(); uint32 d1 = p->Recv_uint32(); switch (type) { case ADMIN_UPDATE_DATE: /* The admin is requesting the current date. */ this->SendDate(); break; case ADMIN_UPDATE_CLIENT_INFO: /* The admin is requesting client info. */ const NetworkClientSocket *cs; if (d1 == UINT32_MAX) { this->SendClientInfo(NULL, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER)); FOR_ALL_CLIENT_SOCKETS(cs) { this->SendClientInfo(cs, cs->GetInfo()); } } else { if (d1 == CLIENT_ID_SERVER) { this->SendClientInfo(NULL, NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER)); } else { cs = NetworkClientSocket::GetByClientID((ClientID)d1); if (cs != NULL) this->SendClientInfo(cs, cs->GetInfo()); } } break; case ADMIN_UPDATE_COMPANY_INFO: /* The admin is asking for company info. */ const Company *company; if (d1 == UINT32_MAX) { FOR_ALL_COMPANIES(company) { this->SendCompanyInfo(company); } } else { company = Company::GetIfValid(d1); if (company != NULL) this->SendCompanyInfo(company); } break; case ADMIN_UPDATE_COMPANY_ECONOMY: /* The admin is requesting economy info. */ this->SendCompanyEconomy(); break; case ADMIN_UPDATE_COMPANY_STATS: /* the admin is requesting company stats. */ this->SendCompanyStats(); break; case ADMIN_UPDATE_CMD_NAMES: /* The admin is requesting the names of DoCommands. */ this->SendCmdNames(); break; default: /* An unsupported "poll" update type. */ DEBUG(net, 3, "[admin] Not supported poll %d (%d) from '%s' (%s).", type, d1, this->admin_name, this->admin_version); return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET); } return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p) { if (this->status == ADMIN_STATUS_INACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); NetworkAction action = (NetworkAction)p->Recv_uint8(); DestType desttype = (DestType)p->Recv_uint8(); int dest = p->Recv_uint32(); char msg[NETWORK_CHAT_LENGTH]; p->Recv_string(msg, NETWORK_CHAT_LENGTH); switch (action) { case NETWORK_ACTION_CHAT: case NETWORK_ACTION_CHAT_CLIENT: case NETWORK_ACTION_CHAT_COMPANY: case NETWORK_ACTION_SERVER_MESSAGE: NetworkServerSendChat(action, desttype, dest, msg, _network_own_client_id, 0, true); break; default: DEBUG(net, 3, "[admin] Invalid chat action %d from admin '%s' (%s).", action, this->admin_name, this->admin_version); return this->SendError(NETWORK_ERROR_ILLEGAL_PACKET); } return NETWORK_RECV_STATUS_OKAY; } /* * Useful wrapper functions */ /** * Notify the admin network of a new client (if they did opt in for the respective update). * @param cs the client info. * @param new_client if this is a new client, send the respective packet too. */ void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendClientInfo(cs, cs->GetInfo()); if (new_client) { as->SendClientJoin(cs->client_id); } } } } /** * Notify the admin network of a client update (if they did opt in for the respective update). * @param ci the client info. */ void NetworkAdminClientUpdate(const NetworkClientInfo *ci) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendClientUpdate(ci); } } } /** * Notify the admin network that a client quit (if they have opt in for the respective update). * @param client_id of the client that quit. */ void NetworkAdminClientQuit(ClientID client_id) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendClientQuit(client_id); } } } /** * Notify the admin network of a client error (if they have opt in for the respective update). * @param client_id the client that made the error. * @param error_code the error that was caused. */ void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendClientError(client_id, error_code); } } } /** * Notify the admin network of company details. * @param company the company of which details will be sent into the admin network. * @param new_company whether this is a new company or not. */ void NetworkAdminCompanyInfo(const Company *company, bool new_company) { if (company == NULL) { DEBUG(net, 1, "[admin] Empty company given for update"); return; } ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_COMPANY_INFO] != ADMIN_FREQUENCY_AUTOMATIC) continue; as->SendCompanyInfo(company); if (new_company) { as->SendCompanyNew(company->index); } } } /** * Notify the admin network of company updates. * @param company company of which updates are going to be sent into the admin network. */ void NetworkAdminCompanyUpdate(const Company *company) { if (company == NULL) return; ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_COMPANY_INFO] != ADMIN_FREQUENCY_AUTOMATIC) continue; as->SendCompanyUpdate(company); } } /** * Notify the admin network of a company to be removed (including the reason why). * @param company_id ID of the company that got removed. * @param bcrr the reason why the company got removed (e.g. bankruptcy). */ void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { as->SendCompanyRemove(company_id, bcrr); } } /** * Send chat to the admin network (if they did opt in for the respective update). */ void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data, bool from_admin) { if (from_admin) return; ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_CHAT] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendChat(action, desttype, client_id, msg, data); } } } /** * Pass the rcon reply to the admin. * @param admin_index The admin to give the reply. * @param colour_code The colour of the string. * @param string The string to show. */ void NetworkServerSendAdminRcon(AdminIndex admin_index, TextColour colour_code, const char *string) { ServerNetworkAdminSocketHandler::Get(admin_index)->SendRcon(colour_code, string); } /** * Send console to the admin network (if they did opt in for the respective update). * @param origin the origin of the message. * @param string the message as printed on the console. */ void NetworkAdminConsole(const char *origin, const char *string) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_CONSOLE] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendConsole(origin, string); } } } /** * Send GameScript JSON to the admin network (if they did opt in for the respective update). * @param json The JSON data as received from the GameScript. */ void NetworkAdminGameScript(const char *json) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_GAMESCRIPT] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendGameScript(json); } } } /** * Distribute CommandPacket details over the admin network for logging purposes. * @param owner The owner of the CommandPacket (who sent us the CommandPacket). * @param cp The CommandPacket to be distributed. */ void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket *cp) { ClientID client_id = owner == NULL ? _network_own_client_id : owner->client_id; ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { if (as->update_frequency[ADMIN_UPDATE_CMD_LOGGING] & ADMIN_FREQUENCY_AUTOMATIC) { as->SendCmdLogging(client_id, cp); } } } /** * Send a Welcome packet to all connected admins */ void ServerNetworkAdminSocketHandler::WelcomeAll() { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { as->SendWelcome(); } } /** * Send (push) updates to the admin network as they have registered for these updates. * @param freq the frequency to be processed. */ void NetworkAdminUpdate(AdminUpdateFrequency freq) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { for (int i = 0; i < ADMIN_UPDATE_END; i++) { if (as->update_frequency[i] & freq) { /* Update the admin for the required details */ switch (i) { case ADMIN_UPDATE_DATE: as->SendDate(); break; case ADMIN_UPDATE_COMPANY_ECONOMY: as->SendCompanyEconomy(); break; case ADMIN_UPDATE_COMPANY_STATS: as->SendCompanyStats(); break; default: NOT_REACHED(); } } } } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_content.h0000644000000000000000000001341312627373441017562 0ustar rootroot/* $Id: network_content.h 23465 2011-12-09 21:49:52Z yexo $ */ /* * 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 network_content.h Part of the network protocol handling content distribution. */ #ifndef NETWORK_CONTENT_H #define NETWORK_CONTENT_H #include "core/tcp_content.h" #include "core/tcp_http.h" #if defined(ENABLE_NETWORK) /** Vector with content info */ typedef SmallVector ContentVector; /** Vector with constant content info */ typedef SmallVector ConstContentVector; /** Iterator for the content vector */ typedef ContentInfo **ContentIterator; /** Iterator for the constant content vector */ typedef const ContentInfo * const * ConstContentIterator; /** Callbacks for notifying others about incoming data */ struct ContentCallback { /** * Callback for when the connection has finished * @param success whether the connection was made or that we failed to make it */ virtual void OnConnect(bool success) {} /** * Callback for when the connection got disconnected. */ virtual void OnDisconnect() {} /** * We received a content info. * @param ci the content info */ virtual void OnReceiveContentInfo(const ContentInfo *ci) {} /** * We have progress in the download of a file * @param ci the content info of the file * @param bytes the number of bytes downloaded since the previous call */ virtual void OnDownloadProgress(const ContentInfo *ci, int bytes) {} /** * We have finished downloading a file * @param cid the ContentID of the downloaded file */ virtual void OnDownloadComplete(ContentID cid) {} /** Silentium */ virtual ~ContentCallback() {} }; /** * Socket handler for the content server connection */ class ClientNetworkContentSocketHandler : public NetworkContentSocketHandler, ContentCallback, HTTPCallback { protected: typedef SmallVector ContentIDList; ///< List of content IDs to (possibly) select. SmallVector callbacks; ///< Callbacks to notify "the world" ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again) ContentVector infos; ///< All content info we received SmallVector http_response; ///< The HTTP response to the requests we've been doing int http_response_index; ///< Where we are, in the response, with handling it FILE *curFile; ///< Currently downloaded file ContentInfo *curInfo; ///< Information about the currently downloaded file bool isConnecting; ///< Whether we're connecting uint32 lastActivity; ///< The last time there was network activity friend class NetworkContentConnecter; virtual bool Receive_SERVER_INFO(Packet *p); virtual bool Receive_SERVER_CONTENT(Packet *p); ContentInfo *GetContent(ContentID cid); void DownloadContentInfo(ContentID cid); void OnConnect(bool success); void OnDisconnect(); void OnReceiveContentInfo(const ContentInfo *ci); void OnDownloadProgress(const ContentInfo *ci, int bytes); void OnDownloadComplete(ContentID cid); void OnFailure(); void OnReceiveData(const char *data, size_t length); bool BeforeDownload(); void AfterDownload(); void DownloadSelectedContentHTTP(const ContentIDList &content); void DownloadSelectedContentFallback(const ContentIDList &content); public: /** The idle timeout; when to close the connection because it's idle. */ static const int IDLE_TIMEOUT = 60 * 1000; ClientNetworkContentSocketHandler(); ~ClientNetworkContentSocketHandler(); void Connect(); void SendReceive(); void Close(); void RequestContentList(ContentType type); void RequestContentList(uint count, const ContentID *content_ids); void RequestContentList(ContentVector *cv, bool send_md5sum = true); void DownloadSelectedContent(uint &files, uint &bytes, bool fallback = false); void Select(ContentID cid); void Unselect(ContentID cid); void SelectAll(); void SelectUpgrade(); void UnselectAll(); void ToggleSelectedState(const ContentInfo *ci); void ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const; void ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const; void CheckDependencyState(ContentInfo *ci); /** Get the number of content items we know locally. */ uint Length() const { return this->infos.Length(); } /** Get the begin of the content inf iterator. */ ConstContentIterator Begin() const { return this->infos.Begin(); } /** Get the nth position of the content inf iterator. */ ConstContentIterator Get(uint32 index) const { return this->infos.Get(index); } /** Get the end of the content inf iterator. */ ConstContentIterator End() const { return this->infos.End(); } void Clear(); /** Add a callback to this class */ void AddCallback(ContentCallback *cb) { this->callbacks.Include(cb); } /** Remove a callback */ void RemoveCallback(ContentCallback *cb) { this->callbacks.Erase(this->callbacks.Find(cb)); } }; extern ClientNetworkContentSocketHandler _network_content_client; void ShowNetworkContentListWindow(ContentVector *cv = NULL, ContentType type = CONTENT_TYPE_END); void ShowMissingContentWindow(const struct GRFConfig *list); #else static inline void ShowNetworkContentListWindow() {} #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CONTENT_H */ openttd-1.5.3/src/network/network_server.h0000644000000000000000000001500312627373441017413 0ustar rootroot/* $Id: network_server.h 26576 2014-05-11 12:52:21Z rubidium $ */ /* * 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 network_server.h Server part of the network protocol. */ #ifndef NETWORK_SERVER_H #define NETWORK_SERVER_H #ifdef ENABLE_NETWORK #include "network_internal.h" #include "core/tcp_listen.h" #include "../thread/thread.h" class ServerNetworkGameSocketHandler; /** Make the code look slightly nicer/simpler. */ typedef ServerNetworkGameSocketHandler NetworkClientSocket; /** Pool with all client sockets. */ typedef Pool NetworkClientSocketPool; extern NetworkClientSocketPool _networkclientsocket_pool; /** Class for handling the server side of the game connection. */ class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<&_networkclientsocket_pool>, public NetworkGameSocketHandler, public TCPListenHandler { protected: virtual NetworkRecvStatus Receive_CLIENT_JOIN(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_ACK(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_COMMAND(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_CHAT(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_QUIT(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_RCON(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet *p); virtual NetworkRecvStatus Receive_CLIENT_MOVE(Packet *p); NetworkRecvStatus SendCompanyInfo(); NetworkRecvStatus SendNewGRFCheck(); NetworkRecvStatus SendWelcome(); NetworkRecvStatus SendWait(); NetworkRecvStatus SendNeedGamePassword(); NetworkRecvStatus SendNeedCompanyPassword(); public: /** Status of a client */ enum ClientStatus { STATUS_INACTIVE, ///< The client is not connected nor active. STATUS_NEWGRFS_CHECK, ///< The client is checking NewGRFs. STATUS_AUTH_GAME, ///< The client is authorizing with game (server) password. STATUS_AUTH_COMPANY, ///< The client is authorizing with company password. STATUS_AUTHORIZED, ///< The client is authorized. STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map. STATUS_MAP, ///< The client is downloading the map. STATUS_DONE_MAP, ///< The client has downloaded the map. STATUS_PRE_ACTIVE, ///< The client is catching up the delayed frames. STATUS_ACTIVE, ///< The client is active within in the game. STATUS_END, ///< Must ALWAYS be on the end of this list!! (period). }; byte lag_test; ///< Byte used for lag-testing the client byte last_token; ///< The last random token we did send to verify the client is listening uint32 last_token_frame; ///< The last frame we received the right token ClientStatus status; ///< Status of this client CommandQueue outgoing_queue; ///< The command-queue awaiting delivery int receive_limit; ///< Amount of bytes that we can receive at this moment struct PacketWriter *savegame; ///< Writer used to write the savegame. NetworkAddress client_address; ///< IP-address of the client (so he can be banned) ServerNetworkGameSocketHandler(SOCKET s); ~ServerNetworkGameSocketHandler(); virtual Packet *ReceivePacket(); NetworkRecvStatus CloseConnection(NetworkRecvStatus status); void GetClientName(char *client_name, const char *last) const; NetworkRecvStatus SendMap(); NetworkRecvStatus SendErrorQuit(ClientID client_id, NetworkErrorCode errorno); NetworkRecvStatus SendQuit(ClientID client_id); NetworkRecvStatus SendShutdown(); NetworkRecvStatus SendNewGame(); NetworkRecvStatus SendRConResult(uint16 colour, const char *command); NetworkRecvStatus SendMove(ClientID client_id, CompanyID company_id); NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci); NetworkRecvStatus SendError(NetworkErrorCode error); NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, int64 data); NetworkRecvStatus SendJoin(ClientID client_id); NetworkRecvStatus SendFrame(); NetworkRecvStatus SendSync(); NetworkRecvStatus SendCommand(const CommandPacket *cp); NetworkRecvStatus SendCompanyUpdate(); NetworkRecvStatus SendConfigUpdate(); static void Send(); static void AcceptConnection(SOCKET s, const NetworkAddress &address); static bool AllowConnection(); /** * Get the name used by the listener. * @return the name to show in debug logs and the like. */ static const char *GetName() { return "server"; } const char *GetClientIP(); static ServerNetworkGameSocketHandler *GetByClientID(ClientID client_id); }; void NetworkServer_Tick(bool send_frame); void NetworkServerSetCompanyPassword(CompanyID company_id, const char *password, bool already_hashed = true); void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded); /** * Iterate over all the sockets from a given starting point. * @param var The variable to iterate with. * @param start The start of the iteration. */ #define FOR_ALL_CLIENT_SOCKETS_FROM(var, start) FOR_ALL_ITEMS_FROM(NetworkClientSocket, clientsocket_index, var, start) /** * Iterate over all the sockets. * @param var The variable to iterate with. */ #define FOR_ALL_CLIENT_SOCKETS(var) FOR_ALL_CLIENT_SOCKETS_FROM(var, 0) #else /* ENABLE_NETWORK */ /* Network function stubs when networking is disabled */ static inline void NetworkServerMonthlyLoop() {} static inline void NetworkServerYearlyLoop() {} #endif /* ENABLE_NETWORK */ #endif /* NETWORK_SERVER_H */ openttd-1.5.3/src/network/network_base.h0000644000000000000000000000466512627373441017033 0ustar rootroot/* $Id: network_base.h 22423 2011-05-04 20:24:23Z rubidium $ */ /* * 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 network_base.h Base core network types and some helper functions to access them. */ #ifndef NETWORK_BASE_H #define NETWORK_BASE_H #ifdef ENABLE_NETWORK #include "network_type.h" #include "core/address.h" #include "../core/pool_type.hpp" #include "../company_type.h" /** Type for the pool with client information. */ typedef Pool NetworkClientInfoPool; extern NetworkClientInfoPool _networkclientinfo_pool; /** Container for all information known about a client. */ struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_pool> { ClientID client_id; ///< Client identifier (same as ClientState->client_id) char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< Name of the client byte client_lang; ///< The language of the client CompanyID client_playas; ///< As which company is this client playing (CompanyID) Date join_date; ///< Gamedate the client has joined /** * Create a new client. * @param client_id The unique identifier of the client. */ NetworkClientInfo(ClientID client_id = INVALID_CLIENT_ID) : client_id(client_id) {} ~NetworkClientInfo(); static NetworkClientInfo *GetByClientID(ClientID client_id); }; /** * Iterate over all the clients from a given index. * @param var The variable to iterate with. * @param start The location to start the iteration from. */ #define FOR_ALL_CLIENT_INFOS_FROM(var, start) FOR_ALL_ITEMS_FROM(NetworkClientInfo, clientinfo_index, var, start) /** * Iterate over all the clients. * @param var The variable to iterate with. */ #define FOR_ALL_CLIENT_INFOS(var) FOR_ALL_CLIENT_INFOS_FROM(var, 0) #endif /* ENABLE_NETWORK */ #endif /* NETWORK_BASE_H */ openttd-1.5.3/src/network/network_gui.h0000644000000000000000000000455712627373441016705 0ustar rootroot/* $Id: network_gui.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 network_gui.h GUIs related to networking. */ #ifndef NETWORK_GUI_H #define NETWORK_GUI_H #include "../company_type.h" #include "../economy_type.h" #include "../window_type.h" #include "network_type.h" #ifdef ENABLE_NETWORK void ShowNetworkNeedPassword(NetworkPasswordType npt); void ShowNetworkGiveMoneyWindow(CompanyID company); void ShowNetworkChatQueryWindow(DestType type, int dest); void ShowJoinStatusWindow(); void ShowNetworkGameWindow(); void ShowClientList(); void ShowNetworkCompanyPasswordWindow(Window *parent); /** Company information stored at the client side */ struct NetworkCompanyInfo : NetworkCompanyStats { char company_name[NETWORK_COMPANY_NAME_LENGTH]; ///< Company name Year inaugurated_year; ///< What year the company started in Money company_value; ///< The company value Money money; ///< The amount of money the company has Money income; ///< How much did the company earned last year uint16 performance; ///< What was his performance last month? bool use_password; ///< Is there a password char clients[NETWORK_CLIENTS_LENGTH]; ///< The clients that control this company (Name1, name2, ..) }; NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company); #else /* ENABLE_NETWORK */ /* Network function stubs when networking is disabled */ static inline void ShowNetworkChatQueryWindow(byte desttype, int dest) {} static inline void ShowClientList() {} static inline void ShowNetworkGameWindow() {} static inline void ShowNetworkCompanyPasswordWindow(Window *parent) {} #endif /* ENABLE_NETWORK */ #endif /* NETWORK_GUI_H */ openttd-1.5.3/src/network/network_server.cpp0000644000000000000000000021630312627373441017754 0ustar rootroot/* $Id: network_server.cpp 26975 2014-10-07 17:32:29Z rubidium $ */ /* * 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 network_server.cpp Server part of the network protocol. */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" #include "network_admin.h" #include "network_server.h" #include "network_udp.h" #include "network_base.h" #include "../console_func.h" #include "../company_base.h" #include "../command_func.h" #include "../saveload/saveload.h" #include "../saveload/saveload_filter.h" #include "../station_base.h" #include "../genworld.h" #include "../company_func.h" #include "../company_gui.h" #include "../roadveh.h" #include "../order_backup.h" #include "../core/pool_func.hpp" #include "../core/random_func.hpp" #include "../rev.h" #include "../safeguards.h" /* This file handles all the server-commands */ DECLARE_POSTFIX_INCREMENT(ClientID) /** The identifier counter for new clients (is never decreased) */ static ClientID _network_client_id = CLIENT_ID_FIRST; /** Make very sure the preconditions given in network_type.h are actually followed */ assert_compile(MAX_CLIENT_SLOTS > MAX_CLIENTS); /** Yes... */ assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS); /** The pool with clients. */ NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket"); INSTANTIATE_POOL_METHODS(NetworkClientSocket) /** Instantiate the listen sockets. */ template SocketList TCPListenHandler::sockets; /** Writing a savegame directly to a number of packets. */ struct PacketWriter : SaveFilter { ServerNetworkGameSocketHandler *cs; ///< Socket we are associated with. Packet *current; ///< The packet we're currently writing to. size_t total_size; ///< Total size of the compressed savegame. Packet *packets; ///< Packet queue of the savegame; send these "slowly" to the client. ThreadMutex *mutex; ///< Mutex for making threaded saving safe. /** * Create the packet writer. * @param cs The socket handler we're making the packets for. */ PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0), packets(NULL) { this->mutex = ThreadMutex::New(); } /** Make sure everything is cleaned up. */ ~PacketWriter() { if (this->mutex != NULL) this->mutex->BeginCritical(); if (this->cs != NULL && this->mutex != NULL) { this->mutex->WaitForSignal(); } /* This must all wait until the Destroy function is called. */ while (this->packets != NULL) { Packet *p = this->packets->next; delete this->packets; this->packets = p; } delete this->current; if (this->mutex != NULL) this->mutex->EndCritical(); delete this->mutex; this->mutex = NULL; } /** * Begin the destruction of this packet writer. It can happen in two ways: * in the first case the client disconnected while saving the map. In this * case the saving has not finished and killed this PacketWriter. In that * case we simply set cs to NULL, triggering the appending to fail due to * the connection problem and eventually triggering the destructor. In the * second case the destructor is already called, and it is waiting for our * signal which we will send. Only then the packets will be removed by the * destructor. */ void Destroy() { if (this->mutex != NULL) this->mutex->BeginCritical(); this->cs = NULL; if (this->mutex != NULL) this->mutex->SendSignal(); if (this->mutex != NULL) this->mutex->EndCritical(); /* Make sure the saving is completely cancelled. Yes, * we need to handle the save finish as well as the * next connection might just be requesting a map. */ WaitTillSaved(); ProcessAsyncSaveFinish(); } /** * Checks whether there are packets. * It's not 100% threading safe, but this is only asked for when checking * whether there still is something to send. Then another call will be made * to actually get the Packet, which will be the only one popping packets * and thus eventually setting this on false. */ bool HasPackets() { return this->packets != NULL; } /** * Pop a single created packet from the queue with packets. */ Packet *PopPacket() { if (this->mutex != NULL) this->mutex->BeginCritical(); Packet *p = this->packets; this->packets = p->next; p->next = NULL; if (this->mutex != NULL) this->mutex->EndCritical(); return p; } /** Append the current packet to the queue. */ void AppendQueue() { if (this->current == NULL) return; Packet **p = &this->packets; while (*p != NULL) { p = &(*p)->next; } *p = this->current; this->current = NULL; } /* virtual */ void Write(byte *buf, size_t size) { /* We want to abort the saving when the socket is closed. */ if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA); if (this->mutex != NULL) this->mutex->BeginCritical(); byte *bufe = buf + size; while (buf != bufe) { size_t to_write = min(SEND_MTU - this->current->size, bufe - buf); memcpy(this->current->buffer + this->current->size, buf, to_write); this->current->size += (PacketSize)to_write; buf += to_write; if (this->current->size == SEND_MTU) { this->AppendQueue(); if (buf != bufe) this->current = new Packet(PACKET_SERVER_MAP_DATA); } } if (this->mutex != NULL) this->mutex->EndCritical(); this->total_size += size; } /* virtual */ void Finish() { /* We want to abort the saving when the socket is closed. */ if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); if (this->mutex != NULL) this->mutex->BeginCritical(); /* Make sure the last packet is flushed. */ this->AppendQueue(); /* Add a packet stating that this is the end to the queue. */ this->current = new Packet(PACKET_SERVER_MAP_DONE); this->AppendQueue(); /* Fast-track the size to the client. */ Packet *p = new Packet(PACKET_SERVER_MAP_SIZE); p->Send_uint32((uint32)this->total_size); this->cs->NetworkTCPSocketHandler::SendPacket(p); if (this->mutex != NULL) this->mutex->EndCritical(); } }; /** * Create a new socket for the server side of the game connection. * @param s The socket to connect with. */ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s) { this->status = STATUS_INACTIVE; this->client_id = _network_client_id++; this->receive_limit = _settings_client.network.bytes_per_frame_burst; /* The Socket and Info pools need to be the same in size. After all, * each Socket will be associated with at most one Info object. As * such if the Socket was allocated the Info object can as well. */ assert_compile(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE); } /** * Clear everything related to this client. */ ServerNetworkGameSocketHandler::~ServerNetworkGameSocketHandler() { if (_redirect_console_to_client == this->client_id) _redirect_console_to_client = INVALID_CLIENT_ID; OrderBackup::ResetUser(this->client_id); if (this->savegame != NULL) { this->savegame->Destroy(); this->savegame = NULL; } } Packet *ServerNetworkGameSocketHandler::ReceivePacket() { /* Only allow receiving when we have some buffer free; this value * can go negative, but eventually it will become positive again. */ if (this->receive_limit <= 0) return NULL; /* We can receive a packet, so try that and if needed account for * the amount of received data. */ Packet *p = this->NetworkTCPSocketHandler::ReceivePacket(); if (p != NULL) this->receive_limit -= p->size; return p; } NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status) { assert(status != NETWORK_RECV_STATUS_OKAY); /* * Sending a message just before leaving the game calls cs->SendPackets. * This might invoke this function, which means that when we close the * connection after cs->SendPackets we will close an already closed * connection. This handles that case gracefully without having to make * that code any more complex or more aware of the validity of the socket. */ if (this->sock == INVALID_SOCKET) return status; if (status != NETWORK_RECV_STATUS_CONN_LOST && !this->HasClientQuit() && this->status >= STATUS_AUTHORIZED) { /* We did not receive a leave message from this client... */ char client_name[NETWORK_CLIENT_NAME_LENGTH]; NetworkClientSocket *new_cs; this->GetClientName(client_name, lastof(client_name)); NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST); /* Inform other clients of this... strange leaving ;) */ FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED && this != new_cs) { new_cs->SendErrorQuit(this->client_id, NETWORK_ERROR_CONNECTION_LOST); } } } NetworkAdminClientError(this->client_id, NETWORK_ERROR_CONNECTION_LOST); DEBUG(net, 1, "Closed client connection %d", this->client_id); /* We just lost one client :( */ if (this->status >= STATUS_AUTHORIZED) _network_game_info.clients_on--; extern byte _network_clients_connected; _network_clients_connected--; DeleteWindowById(WC_CLIENT_LIST_POPUP, this->client_id); SetWindowDirty(WC_CLIENT_LIST, 0); this->SendPackets(true); delete this->GetInfo(); delete this; return status; } /** * Whether an connection is allowed or not at this moment. * @return true if the connection is allowed. */ /* static */ bool ServerNetworkGameSocketHandler::AllowConnection() { extern byte _network_clients_connected; bool accept = _network_clients_connected < MAX_CLIENTS && _network_game_info.clients_on < _settings_client.network.max_clients; /* We can't go over the MAX_CLIENTS limit here. However, the * pool must have place for all clients and ourself. */ assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1); assert(!accept || ServerNetworkGameSocketHandler::CanAllocateItem()); return accept; } /** Send the packets for the server sockets. */ /* static */ void ServerNetworkGameSocketHandler::Send() { NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->writable) { if (cs->SendPackets() != SPS_CLOSED && cs->status == STATUS_MAP) { /* This client is in the middle of a map-send, call the function for that */ cs->SendMap(); } } } } static void NetworkHandleCommandQueue(NetworkClientSocket *cs); /*********** * Sending functions * DEF_SERVER_SEND_COMMAND has parameter: NetworkClientSocket *cs ************/ /** * Send the client information about a client. * @param ci The client to send information about. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientInfo *ci) { if (ci->client_id != INVALID_CLIENT_ID) { Packet *p = new Packet(PACKET_SERVER_CLIENT_INFO); p->Send_uint32(ci->client_id); p->Send_uint8 (ci->client_playas); p->Send_string(ci->client_name); this->SendPacket(p); } return NETWORK_RECV_STATUS_OKAY; } /** Send the client information about the companies. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo() { /* Fetch the latest version of the stats */ NetworkCompanyStats company_stats[MAX_COMPANIES]; NetworkPopulateCompanyStats(company_stats); /* Make a list of all clients per company */ char clients[MAX_COMPANIES][NETWORK_CLIENTS_LENGTH]; NetworkClientSocket *csi; memset(clients, 0, sizeof(clients)); /* Add the local player (if not dedicated) */ const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); if (ci != NULL && Company::IsValidID(ci->client_playas)) { strecpy(clients[ci->client_playas], ci->client_name, lastof(clients[ci->client_playas])); } FOR_ALL_CLIENT_SOCKETS(csi) { char client_name[NETWORK_CLIENT_NAME_LENGTH]; ((ServerNetworkGameSocketHandler*)csi)->GetClientName(client_name, lastof(client_name)); ci = csi->GetInfo(); if (ci != NULL && Company::IsValidID(ci->client_playas)) { if (!StrEmpty(clients[ci->client_playas])) { strecat(clients[ci->client_playas], ", ", lastof(clients[ci->client_playas])); } strecat(clients[ci->client_playas], client_name, lastof(clients[ci->client_playas])); } } /* Now send the data */ Company *company; Packet *p; FOR_ALL_COMPANIES(company) { p = new Packet(PACKET_SERVER_COMPANY_INFO); p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION); p->Send_bool (true); this->SendCompanyInformation(p, company, &company_stats[company->index]); if (StrEmpty(clients[company->index])) { p->Send_string(""); } else { p->Send_string(clients[company->index]); } this->SendPacket(p); } p = new Packet(PACKET_SERVER_COMPANY_INFO); p->Send_uint8 (NETWORK_COMPANY_INFO_VERSION); p->Send_bool (false); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send an error to the client, and close its connection. * @param error The error to disconnect for. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error) { char str[100]; Packet *p = new Packet(PACKET_SERVER_ERROR); p->Send_uint8(error); this->SendPacket(p); StringID strid = GetNetworkErrorMsg(error); GetString(str, strid, lastof(str)); /* Only send when the current client was in game */ if (this->status > STATUS_AUTHORIZED) { NetworkClientSocket *new_cs; char client_name[NETWORK_CLIENT_NAME_LENGTH]; this->GetClientName(client_name, lastof(client_name)); DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str); NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid); FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) { /* Some errors we filter to a more general error. Clients don't have to know the real * reason a joining failed. */ if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) { error = NETWORK_ERROR_ILLEGAL_PACKET; } new_cs->SendErrorQuit(this->client_id, error); } } NetworkAdminClientError(this->client_id, error); } else { DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", this->client_id, str); } /* The client made a mistake, so drop his connection now! */ return this->CloseConnection(NETWORK_RECV_STATUS_SERVER_ERROR); } /** Send the check for the NewGRFs. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck() { Packet *p = new Packet(PACKET_SERVER_CHECK_NEWGRFS); const GRFConfig *c; uint grf_count = 0; for (c = _grfconfig; c != NULL; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) grf_count++; } p->Send_uint8 (grf_count); for (c = _grfconfig; c != NULL; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); } this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Request the game password. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedGamePassword() { /* Invalid packet when status is STATUS_AUTH_GAME or higher */ if (this->status >= STATUS_AUTH_GAME) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET); this->status = STATUS_AUTH_GAME; /* Reset 'lag' counters */ this->last_frame = this->last_frame_server = _frame_counter; Packet *p = new Packet(PACKET_SERVER_NEED_GAME_PASSWORD); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Request the company password. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNeedCompanyPassword() { /* Invalid packet when status is STATUS_AUTH_COMPANY or higher */ if (this->status >= STATUS_AUTH_COMPANY) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET); this->status = STATUS_AUTH_COMPANY; /* Reset 'lag' counters */ this->last_frame = this->last_frame_server = _frame_counter; Packet *p = new Packet(PACKET_SERVER_NEED_COMPANY_PASSWORD); p->Send_uint32(_settings_game.game_creation.generation_seed); p->Send_string(_settings_client.network.network_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send the client a welcome message with some basic information. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome() { Packet *p; NetworkClientSocket *new_cs; /* Invalid packet when status is AUTH or higher */ if (this->status >= STATUS_AUTHORIZED) return this->CloseConnection(NETWORK_RECV_STATUS_MALFORMED_PACKET); this->status = STATUS_AUTHORIZED; /* Reset 'lag' counters */ this->last_frame = this->last_frame_server = _frame_counter; _network_game_info.clients_on++; p = new Packet(PACKET_SERVER_WELCOME); p->Send_uint32(this->client_id); p->Send_uint32(_settings_game.game_creation.generation_seed); p->Send_string(_settings_client.network.network_id); this->SendPacket(p); /* Transmit info about all the active clients */ FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs != this && new_cs->status > STATUS_AUTHORIZED) { this->SendClientInfo(new_cs->GetInfo()); } } /* Also send the info of the server */ return this->SendClientInfo(NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER)); } /** Tell the client that its put in a waiting queue. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait() { int waiting = 0; NetworkClientSocket *new_cs; Packet *p; /* Count how many clients are waiting in the queue, in front of you! */ FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status != STATUS_MAP_WAIT) continue; if (new_cs->GetInfo()->join_date < this->GetInfo()->join_date || (new_cs->GetInfo()->join_date == this->GetInfo()->join_date && new_cs->client_id < this->client_id)) waiting++; } p = new Packet(PACKET_SERVER_WAIT); p->Send_uint8(waiting); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** This sends the map to the client */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap() { static uint sent_packets; // How many packets we did send successfully last time if (this->status < STATUS_AUTHORIZED) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED); } if (this->status == STATUS_AUTHORIZED) { this->savegame = new PacketWriter(this); /* Now send the _frame_counter and how many packets are coming */ Packet *p = new Packet(PACKET_SERVER_MAP_BEGIN); p->Send_uint32(_frame_counter); this->SendPacket(p); NetworkSyncCommandQueue(this); this->status = STATUS_MAP; /* Mark the start of download */ this->last_frame = _frame_counter; this->last_frame_server = _frame_counter; sent_packets = 4; // We start with trying 4 packets /* Make a dump of the current game */ if (SaveWithFilter(this->savegame, true) != SL_OK) usererror("network savedump failed"); } if (this->status == STATUS_MAP) { bool last_packet = false; bool has_packets = false; for (uint i = 0; (has_packets = this->savegame->HasPackets()) && i < sent_packets; i++) { Packet *p = this->savegame->PopPacket(); last_packet = p->buffer[2] == PACKET_SERVER_MAP_DONE; this->SendPacket(p); if (last_packet) { /* There is no more data, so break the for */ break; } } if (last_packet) { /* Done reading, make sure saving is done as well */ this->savegame->Destroy(); this->savegame = NULL; /* Set the status to DONE_MAP, no we will wait for the client * to send it is ready (maybe that happens like never ;)) */ this->status = STATUS_DONE_MAP; /* Find the best candidate for joining, i.e. the first joiner. */ NetworkClientSocket *new_cs; NetworkClientSocket *best = NULL; FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status == STATUS_MAP_WAIT) { if (best == NULL || best->GetInfo()->join_date > new_cs->GetInfo()->join_date || (best->GetInfo()->join_date == new_cs->GetInfo()->join_date && best->client_id > new_cs->client_id)) { best = new_cs; } } } /* Is there someone else to join? */ if (best != NULL) { /* Let the first start joining. */ best->status = STATUS_AUTHORIZED; best->SendMap(); /* And update the rest. */ FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait(); } } } switch (this->SendPackets()) { case SPS_CLOSED: return NETWORK_RECV_STATUS_CONN_LOST; case SPS_ALL_SENT: /* All are sent, increase the sent_packets */ if (has_packets) sent_packets *= 2; break; case SPS_PARTLY_SENT: /* Only a part is sent; leave the transmission state. */ break; case SPS_NONE_SENT: /* Not everything is sent, decrease the sent_packets */ if (sent_packets > 1) sent_packets /= 2; break; } } return NETWORK_RECV_STATUS_OKAY; } /** * Tell that a client joined. * @param client_id The client that joined. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendJoin(ClientID client_id) { Packet *p = new Packet(PACKET_SERVER_JOIN); p->Send_uint32(client_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the client that they may run to a particular frame. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame() { Packet *p = new Packet(PACKET_SERVER_FRAME); p->Send_uint32(_frame_counter); p->Send_uint32(_frame_counter_max); #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME p->Send_uint32(_sync_seed_1); #ifdef NETWORK_SEND_DOUBLE_SEED p->Send_uint32(_sync_seed_2); #endif #endif /* If token equals 0, we need to make a new token and send that. */ if (this->last_token == 0) { this->last_token = InteractiveRandomRange(UINT8_MAX - 1) + 1; p->Send_uint8(this->last_token); } this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Request the client to sync. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync() { Packet *p = new Packet(PACKET_SERVER_SYNC); p->Send_uint32(_frame_counter); p->Send_uint32(_sync_seed_1); #ifdef NETWORK_SEND_DOUBLE_SEED p->Send_uint32(_sync_seed_2); #endif this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send a command to the client to execute. * @param cp The command to send. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCommand(const CommandPacket *cp) { Packet *p = new Packet(PACKET_SERVER_COMMAND); this->NetworkGameSocketHandler::SendCommand(p, cp); p->Send_uint32(cp->frame); p->Send_bool (cp->my_cmd); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send a chat message. * @param action The action associated with the message. * @param client_id The origin of the chat message. * @param self_send Whether we did send the message. * @param msg The actual message. * @param data Arbitrary extra data. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, int64 data) { if (this->status < STATUS_PRE_ACTIVE) return NETWORK_RECV_STATUS_OKAY; Packet *p = new Packet(PACKET_SERVER_CHAT); p->Send_uint8 (action); p->Send_uint32(client_id); p->Send_bool (self_send); p->Send_string(msg); p->Send_uint64(data); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the client another client quit with an error. * @param client_id The client that quit. * @param errorno The reason the client quit. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendErrorQuit(ClientID client_id, NetworkErrorCode errorno) { Packet *p = new Packet(PACKET_SERVER_ERROR_QUIT); p->Send_uint32(client_id); p->Send_uint8 (errorno); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the client another client quit. * @param client_id The client that quit. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendQuit(ClientID client_id) { Packet *p = new Packet(PACKET_SERVER_QUIT); p->Send_uint32(client_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the client we're shutting down. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendShutdown() { Packet *p = new Packet(PACKET_SERVER_SHUTDOWN); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the client we're starting a new game. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGame() { Packet *p = new Packet(PACKET_SERVER_NEWGAME); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send the result of a console action. * @param colour The colour of the result. * @param command The command that was executed. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendRConResult(uint16 colour, const char *command) { Packet *p = new Packet(PACKET_SERVER_RCON); p->Send_uint16(colour); p->Send_string(command); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell that a client moved to another company. * @param client_id The client that moved. * @param company_id The company the client moved to. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMove(ClientID client_id, CompanyID company_id) { Packet *p = new Packet(PACKET_SERVER_MOVE); p->Send_uint32(client_id); p->Send_uint8(company_id); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send an update about the company password states. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyUpdate() { Packet *p = new Packet(PACKET_SERVER_COMPANY_UPDATE); p->Send_uint16(_network_company_passworded); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send an update about the max company/spectator counts. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate() { Packet *p = new Packet(PACKET_SERVER_CONFIG_UPDATE); p->Send_uint8(_settings_client.network.max_companies); p->Send_uint8(_settings_client.network.max_spectators); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /*********** * Receiving functions * DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p ************/ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_INFO(Packet *p) { return this->SendCompanyInfo(); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet *p) { if (this->status != STATUS_NEWGRFS_CHECK) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } NetworkClientInfo *ci = this->GetInfo(); /* We now want a password from the client else we do not allow him in! */ if (!StrEmpty(_settings_client.network.server_password)) { return this->SendNeedGamePassword(); } if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) { return this->SendNeedCompanyPassword(); } return this->SendWelcome(); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) { if (this->status != STATUS_INACTIVE) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } char name[NETWORK_CLIENT_NAME_LENGTH]; CompanyID playas; NetworkLanguage client_lang; char client_revision[NETWORK_REVISION_LENGTH]; p->Recv_string(client_revision, sizeof(client_revision)); uint32 newgrf_version = p->Recv_uint32(); /* Check if the client has revision control enabled */ if (!IsNetworkCompatibleVersion(client_revision) || _openttd_newgrf_version != newgrf_version) { /* Different revisions!! */ return this->SendError(NETWORK_ERROR_WRONG_REVISION); } p->Recv_string(name, sizeof(name)); playas = (Owner)p->Recv_uint8(); client_lang = (NetworkLanguage)p->Recv_uint8(); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; /* join another company does not affect these values */ switch (playas) { case COMPANY_NEW_COMPANY: // New company if (Company::GetNumItems() >= _settings_client.network.max_companies) { return this->SendError(NETWORK_ERROR_FULL); } break; case COMPANY_SPECTATOR: // Spectator if (NetworkSpectatorCount() >= _settings_client.network.max_spectators) { return this->SendError(NETWORK_ERROR_FULL); } break; default: // Join another company (companies 1-8 (index 0-7)) if (!Company::IsValidHumanID(playas)) { return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH); } break; } /* We need a valid name.. make it Player */ if (StrEmpty(name)) strecpy(name, "Player", lastof(name)); if (!NetworkFindName(name, lastof(name))) { // Change name if duplicate /* We could not create a name for this client */ return this->SendError(NETWORK_ERROR_NAME_IN_USE); } assert(NetworkClientInfo::CanAllocateItem()); NetworkClientInfo *ci = new NetworkClientInfo(this->client_id); this->SetInfo(ci); ci->join_date = _date; strecpy(ci->client_name, name, lastof(ci->client_name)); ci->client_playas = playas; ci->client_lang = client_lang; DEBUG(desync, 1, "client: %08x; %02x; %02x; %02x", _date, _date_fract, (int)ci->client_playas, (int)ci->index); /* Make sure companies to which people try to join are not autocleaned */ if (Company::IsValidID(playas)) _network_company_states[playas].months_empty = 0; this->status = STATUS_NEWGRFS_CHECK; if (_grfconfig == NULL) { /* Behave as if we received PACKET_CLIENT_NEWGRFS_CHECKED */ return this->Receive_CLIENT_NEWGRFS_CHECKED(NULL); } return this->SendNewGRFCheck(); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p) { if (this->status != STATUS_AUTH_GAME) { return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } char password[NETWORK_PASSWORD_LENGTH]; p->Recv_string(password, sizeof(password)); /* Check game password. Allow joining if we cleared the password meanwhile */ if (!StrEmpty(_settings_client.network.server_password) && strcmp(password, _settings_client.network.server_password) != 0) { /* Password is invalid */ return this->SendError(NETWORK_ERROR_WRONG_PASSWORD); } const NetworkClientInfo *ci = this->GetInfo(); if (Company::IsValidID(ci->client_playas) && !StrEmpty(_network_company_states[ci->client_playas].password)) { return this->SendNeedCompanyPassword(); } /* Valid password, allow user */ return this->SendWelcome(); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p) { if (this->status != STATUS_AUTH_COMPANY) { return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } char password[NETWORK_PASSWORD_LENGTH]; p->Recv_string(password, sizeof(password)); /* Check company password. Allow joining if we cleared the password meanwhile. * Also, check the company is still valid - client could be moved to spectators * in the middle of the authorization process */ CompanyID playas = this->GetInfo()->client_playas; if (Company::IsValidID(playas) && !StrEmpty(_network_company_states[playas].password) && strcmp(password, _network_company_states[playas].password) != 0) { /* Password is invalid */ return this->SendError(NETWORK_ERROR_WRONG_PASSWORD); } return this->SendWelcome(); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p) { NetworkClientSocket *new_cs; /* The client was never joined.. so this is impossible, right? * Ignore the packet, give the client a warning, and close his connection */ if (this->status < STATUS_AUTHORIZED || this->HasClientQuit()) { return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED); } /* Check if someone else is receiving the map */ FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status == STATUS_MAP) { /* Tell the new client to wait */ this->status = STATUS_MAP_WAIT; return this->SendWait(); } } /* We receive a request to upload the map.. give it to the client! */ return this->SendMap(); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *p) { /* Client has the map, now start syncing */ if (this->status == STATUS_DONE_MAP && !this->HasClientQuit()) { char client_name[NETWORK_CLIENT_NAME_LENGTH]; NetworkClientSocket *new_cs; this->GetClientName(client_name, lastof(client_name)); NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, NULL, this->client_id); /* Mark the client as pre-active, and wait for an ACK * so we know he is done loading and in sync with us */ this->status = STATUS_PRE_ACTIVE; NetworkHandleCommandQueue(this); this->SendFrame(); this->SendSync(); /* This is the frame the client receives * we need it later on to make sure the client is not too slow */ this->last_frame = _frame_counter; this->last_frame_server = _frame_counter; FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED) { new_cs->SendClientInfo(this->GetInfo()); new_cs->SendJoin(this->client_id); } } NetworkAdminClientInfo(this, true); /* also update the new client with our max values */ this->SendConfigUpdate(); /* quickly update the syncing client with company details */ return this->SendCompanyUpdate(); } /* Wrong status for this packet, give a warning to client, and close connection */ return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } /** * The client has done a command and wants us to handle it * @param p the packet in which the command was sent */ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet *p) { /* The client was never joined.. so this is impossible, right? * Ignore the packet, give the client a warning, and close his connection */ if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) { return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } if (this->incoming_queue.Count() >= _settings_client.network.max_commands_in_queue) { return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS); } CommandPacket cp; const char *err = this->ReceiveCommand(p, &cp); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; NetworkClientInfo *ci = this->GetInfo(); if (err != NULL) { IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, this->GetClientIP()); return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } if ((GetCommandFlags(cp.cmd) & CMD_SERVER) && ci->client_id != CLIENT_ID_SERVER) { IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP()); return this->SendError(NETWORK_ERROR_KICKED); } if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) { IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP()); return this->SendError(NETWORK_ERROR_KICKED); } /** * Only CMD_COMPANY_CTRL is always allowed, for the rest, playas needs * to match the company in the packet. If it doesn't, the client has done * something pretty naughty (or a bug), and will be kicked */ if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) { IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...", ci->client_playas + 1, this->GetClientIP(), cp.company + 1); return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH); } if (cp.cmd == CMD_COMPANY_CTRL) { if (cp.p1 != 0 || cp.company != COMPANY_SPECTATOR) { return this->SendError(NETWORK_ERROR_CHEATER); } /* Check if we are full - else it's possible for spectators to send a CMD_COMPANY_CTRL and the company is created regardless of max_companies! */ if (Company::GetNumItems() >= _settings_client.network.max_companies) { NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER); return NETWORK_RECV_STATUS_OKAY; } } if (GetCommandFlags(cp.cmd) & CMD_CLIENT_ID) cp.p2 = this->client_id; this->incoming_queue.Append(&cp); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p) { /* This packets means a client noticed an error and is reporting this * to us. Display the error and report it to the other clients */ NetworkClientSocket *new_cs; char str[100]; char client_name[NETWORK_CLIENT_NAME_LENGTH]; NetworkErrorCode errorno = (NetworkErrorCode)p->Recv_uint8(); /* The client was never joined.. thank the client for the packet, but ignore it */ if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) { return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } this->GetClientName(client_name, lastof(client_name)); StringID strid = GetNetworkErrorMsg(errorno); GetString(str, strid, lastof(str)); DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str); NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, strid); FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED) { new_cs->SendErrorQuit(this->client_id, errorno); } } NetworkAdminClientError(this->client_id, errorno); return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) { /* The client wants to leave. Display this and report it to the other * clients. */ NetworkClientSocket *new_cs; char client_name[NETWORK_CLIENT_NAME_LENGTH]; /* The client was never joined.. thank the client for the packet, but ignore it */ if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) { return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } this->GetClientName(client_name, lastof(client_name)); NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING); FOR_ALL_CLIENT_SOCKETS(new_cs) { if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) { new_cs->SendQuit(this->client_id); } } NetworkAdminClientQuit(this->client_id); return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p) { if (this->status < STATUS_AUTHORIZED) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED); } uint32 frame = p->Recv_uint32(); /* The client is trying to catch up with the server */ if (this->status == STATUS_PRE_ACTIVE) { /* The client is not yet catched up? */ if (frame + DAY_TICKS < _frame_counter) return NETWORK_RECV_STATUS_OKAY; /* Now he is! Unpause the game */ this->status = STATUS_ACTIVE; this->last_token_frame = _frame_counter; /* Execute script for, e.g. MOTD */ IConsoleCmdExec("exec scripts/on_server_connect.scr 0"); } /* Get, and validate the token. */ uint8 token = p->Recv_uint8(); if (token == this->last_token) { /* We differentiate between last_token_frame and last_frame so the lag * test uses the actual lag of the client instead of the lag for getting * the token back and forth; after all, the token is only sent every * time we receive a PACKET_CLIENT_ACK, after which we will send a new * token to the client. If the lag would be one day, then we would not * be sending the new token soon enough for the new daily scheduled * PACKET_CLIENT_ACK. This would then register the lag of the client as * two days, even when it's only a single day. */ this->last_token_frame = _frame_counter; /* Request a new token. */ this->last_token = 0; } /* The client received the frame, make note of it */ this->last_frame = frame; /* With those 2 values we can calculate the lag realtime */ this->last_frame_server = _frame_counter; return NETWORK_RECV_STATUS_OKAY; } /** * Send an actual chat message. * @param action The action that's performed. * @param desttype The type of destination. * @param dest The actual destination index. * @param msg The actual message. * @param from_id The origin of the message. * @param data Arbitrary data. * @param from_admin Whether the origin is an admin or not. */ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, ClientID from_id, int64 data, bool from_admin) { NetworkClientSocket *cs; const NetworkClientInfo *ci, *ci_own, *ci_to; switch (desttype) { case DESTTYPE_CLIENT: /* Are we sending to the server? */ if ((ClientID)dest == CLIENT_ID_SERVER) { ci = NetworkClientInfo::GetByClientID(from_id); /* Display the text locally, and that is it */ if (ci != NULL) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data); if (_settings_client.network.server_admin_chat) { NetworkAdminChat(action, desttype, from_id, msg, data, from_admin); } } } else { /* Else find the client to send the message to */ FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->client_id == (ClientID)dest) { cs->SendChat(action, from_id, false, msg, data); break; } } } /* Display the message locally (so you know you have sent it) */ if (from_id != (ClientID)dest) { if (from_id == CLIENT_ID_SERVER) { ci = NetworkClientInfo::GetByClientID(from_id); ci_to = NetworkClientInfo::GetByClientID((ClientID)dest); if (ci != NULL && ci_to != NULL) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data); } } else { FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->client_id == from_id) { cs->SendChat(action, (ClientID)dest, true, msg, data); break; } } } } break; case DESTTYPE_TEAM: { /* If this is false, the message is already displayed on the client who sent it. */ bool show_local = true; /* Find all clients that belong to this company */ ci_to = NULL; FOR_ALL_CLIENT_SOCKETS(cs) { ci = cs->GetInfo(); if (ci != NULL && ci->client_playas == (CompanyID)dest) { cs->SendChat(action, from_id, false, msg, data); if (cs->client_id == from_id) show_local = false; ci_to = ci; // Remember a client that is in the company for company-name } } /* if the server can read it, let the admin network read it, too. */ if (_local_company == (CompanyID)dest && _settings_client.network.server_admin_chat) { NetworkAdminChat(action, desttype, from_id, msg, data, from_admin); } ci = NetworkClientInfo::GetByClientID(from_id); ci_own = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data); if (from_id == CLIENT_ID_SERVER) show_local = false; ci_to = ci_own; } /* There is no such client */ if (ci_to == NULL) break; /* Display the message locally (so you know you have sent it) */ if (ci != NULL && show_local) { if (from_id == CLIENT_ID_SERVER) { char name[NETWORK_NAME_LENGTH]; StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS; SetDParam(0, ci_to->client_playas); GetString(name, str, lastof(name)); NetworkTextMessage(action, GetDrawStringCompanyColour(ci_own->client_playas), true, name, msg, data); } else { FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->client_id == from_id) { cs->SendChat(action, ci_to->client_id, true, msg, data); } } } } break; } default: DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype); /* FALL THROUGH */ case DESTTYPE_BROADCAST: FOR_ALL_CLIENT_SOCKETS(cs) { cs->SendChat(action, from_id, false, msg, data); } NetworkAdminChat(action, desttype, from_id, msg, data, from_admin); ci = NetworkClientInfo::GetByClientID(from_id); if (ci != NULL) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data); } break; } } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p) { if (this->status < STATUS_PRE_ACTIVE) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED); } NetworkAction action = (NetworkAction)p->Recv_uint8(); DestType desttype = (DestType)p->Recv_uint8(); int dest = p->Recv_uint32(); char msg[NETWORK_CHAT_LENGTH]; p->Recv_string(msg, NETWORK_CHAT_LENGTH); int64 data = p->Recv_uint64(); NetworkClientInfo *ci = this->GetInfo(); switch (action) { case NETWORK_ACTION_GIVE_MONEY: if (!Company::IsValidID(ci->client_playas)) break; /* FALL THROUGH */ case NETWORK_ACTION_CHAT: case NETWORK_ACTION_CHAT_CLIENT: case NETWORK_ACTION_CHAT_COMPANY: NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data); break; default: IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, this->GetClientIP()); return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet *p) { if (this->status != STATUS_ACTIVE) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } char password[NETWORK_PASSWORD_LENGTH]; const NetworkClientInfo *ci; p->Recv_string(password, sizeof(password)); ci = this->GetInfo(); NetworkServerSetCompanyPassword(ci->client_playas, password); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p) { if (this->status != STATUS_ACTIVE) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_EXPECTED); } char client_name[NETWORK_CLIENT_NAME_LENGTH]; NetworkClientInfo *ci; p->Recv_string(client_name, sizeof(client_name)); ci = this->GetInfo(); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; if (ci != NULL) { /* Display change */ if (NetworkFindName(client_name, lastof(client_name))) { NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name); strecpy(ci->client_name, client_name, lastof(ci->client_name)); NetworkUpdateClientInfo(ci->client_id); } } return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p) { if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); char pass[NETWORK_PASSWORD_LENGTH]; char command[NETWORK_RCONCOMMAND_LENGTH]; if (StrEmpty(_settings_client.network.rcon_password)) return NETWORK_RECV_STATUS_OKAY; p->Recv_string(pass, sizeof(pass)); p->Recv_string(command, sizeof(command)); if (strcmp(pass, _settings_client.network.rcon_password) != 0) { DEBUG(net, 0, "[rcon] wrong password from client-id %d", this->client_id); return NETWORK_RECV_STATUS_OKAY; } DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", this->client_id, command); _redirect_console_to_client = this->client_id; IConsoleCmdExec(command); _redirect_console_to_client = INVALID_CLIENT_ID; return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p) { if (this->status != STATUS_ACTIVE) return this->SendError(NETWORK_ERROR_NOT_EXPECTED); CompanyID company_id = (Owner)p->Recv_uint8(); /* Check if the company is valid, we don't allow moving to AI companies */ if (company_id != COMPANY_SPECTATOR && !Company::IsValidHumanID(company_id)) return NETWORK_RECV_STATUS_OKAY; /* Check if we require a password for this company */ if (company_id != COMPANY_SPECTATOR && !StrEmpty(_network_company_states[company_id].password)) { /* we need a password from the client - should be in this packet */ char password[NETWORK_PASSWORD_LENGTH]; p->Recv_string(password, sizeof(password)); /* Incorrect password sent, return! */ if (strcmp(password, _network_company_states[company_id].password) != 0) { DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", this->client_id, company_id + 1); return NETWORK_RECV_STATUS_OKAY; } } /* if we get here we can move the client */ NetworkServerDoMove(this->client_id, company_id); return NETWORK_RECV_STATUS_OKAY; } /** * Package some generic company information into a packet. * @param p The packet that will contain the data. * @param c The company to put the of into the packet. * @param stats The statistics to put in the packet. * @param max_len The maximum length of the company name. */ void NetworkSocketHandler::SendCompanyInformation(Packet *p, const Company *c, const NetworkCompanyStats *stats, uint max_len) { /* Grab the company name */ char company_name[NETWORK_COMPANY_NAME_LENGTH]; SetDParam(0, c->index); assert(max_len <= lengthof(company_name)); GetString(company_name, STR_COMPANY_NAME, company_name + max_len - 1); /* Get the income */ Money income = 0; if (_cur_year - 1 == c->inaugurated_year) { /* The company is here just 1 year, so display [2], else display[1] */ for (uint i = 0; i < lengthof(c->yearly_expenses[2]); i++) { income -= c->yearly_expenses[2][i]; } } else { for (uint i = 0; i < lengthof(c->yearly_expenses[1]); i++) { income -= c->yearly_expenses[1][i]; } } /* Send the information */ p->Send_uint8 (c->index); p->Send_string(company_name); p->Send_uint32(c->inaugurated_year); p->Send_uint64(c->old_economy[0].company_value); p->Send_uint64(c->money); p->Send_uint64(income); p->Send_uint16(c->old_economy[0].performance_history); /* Send 1 if there is a password for the company else send 0 */ p->Send_bool (!StrEmpty(_network_company_states[c->index].password)); for (uint i = 0; i < NETWORK_VEH_END; i++) { p->Send_uint16(stats->num_vehicle[i]); } for (uint i = 0; i < NETWORK_VEH_END; i++) { p->Send_uint16(stats->num_station[i]); } p->Send_bool(c->is_ai); } /** * Populate the company stats. * @param stats the stats to update */ void NetworkPopulateCompanyStats(NetworkCompanyStats *stats) { const Vehicle *v; const Station *s; memset(stats, 0, sizeof(*stats) * MAX_COMPANIES); /* Go through all vehicles and count the type of vehicles */ FOR_ALL_VEHICLES(v) { if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue; byte type = 0; switch (v->type) { case VEH_TRAIN: type = NETWORK_VEH_TRAIN; break; case VEH_ROAD: type = RoadVehicle::From(v)->IsBus() ? NETWORK_VEH_BUS : NETWORK_VEH_LORRY; break; case VEH_AIRCRAFT: type = NETWORK_VEH_PLANE; break; case VEH_SHIP: type = NETWORK_VEH_SHIP; break; default: continue; } stats[v->owner].num_vehicle[type]++; } /* Go through all stations and count the types of stations */ FOR_ALL_STATIONS(s) { if (Company::IsValidID(s->owner)) { NetworkCompanyStats *npi = &stats[s->owner]; if (s->facilities & FACIL_TRAIN) npi->num_station[NETWORK_VEH_TRAIN]++; if (s->facilities & FACIL_TRUCK_STOP) npi->num_station[NETWORK_VEH_LORRY]++; if (s->facilities & FACIL_BUS_STOP) npi->num_station[NETWORK_VEH_BUS]++; if (s->facilities & FACIL_AIRPORT) npi->num_station[NETWORK_VEH_PLANE]++; if (s->facilities & FACIL_DOCK) npi->num_station[NETWORK_VEH_SHIP]++; } } } /** * Send updated client info of a particular client. * @param client_id The client to send it for. */ void NetworkUpdateClientInfo(ClientID client_id) { NetworkClientSocket *cs; NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); if (ci == NULL) return; DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id); FOR_ALL_CLIENT_SOCKETS(cs) { cs->SendClientInfo(ci); } NetworkAdminClientUpdate(ci); } /** Check if we want to restart the map */ static void NetworkCheckRestartMap() { if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) { DEBUG(net, 0, "Auto-restarting map. Year %d reached", _cur_year); StartNewGameWithoutGUI(GENERATE_NEW_SEED); } } /** Check if the server has autoclean_companies activated * Two things happen: * 1) If a company is not protected, it is closed after 1 year (for example) * 2) If a company is protected, protection is disabled after 3 years (for example) * (and item 1. happens a year later) */ static void NetworkAutoCleanCompanies() { const NetworkClientInfo *ci; const Company *c; bool clients_in_company[MAX_COMPANIES]; int vehicles_in_company[MAX_COMPANIES]; if (!_settings_client.network.autoclean_companies) return; memset(clients_in_company, 0, sizeof(clients_in_company)); /* Detect the active companies */ FOR_ALL_CLIENT_INFOS(ci) { if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true; } if (!_network_dedicated) { ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true; } if (_settings_client.network.autoclean_novehicles != 0) { memset(vehicles_in_company, 0, sizeof(vehicles_in_company)); const Vehicle *v; FOR_ALL_VEHICLES(v) { if (!Company::IsValidID(v->owner) || !v->IsPrimaryVehicle()) continue; vehicles_in_company[v->owner]++; } } /* Go through all the companies */ FOR_ALL_COMPANIES(c) { /* Skip the non-active once */ if (c->is_ai) continue; if (!clients_in_company[c->index]) { /* The company is empty for one month more */ _network_company_states[c->index].months_empty++; /* Is the company empty for autoclean_unprotected-months, and is there no protection? */ if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && StrEmpty(_network_company_states[c->index].password)) { /* Shut the company down */ DoCommandP(0, 2 | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL); IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1); } /* Is the company empty for autoclean_protected-months, and there is a protection? */ if (_settings_client.network.autoclean_protected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_protected && !StrEmpty(_network_company_states[c->index].password)) { /* Unprotect the company */ _network_company_states[c->index].password[0] = '\0'; IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", c->index + 1); _network_company_states[c->index].months_empty = 0; NetworkServerUpdateCompanyPassworded(c->index, false); } /* Is the company empty for autoclean_novehicles-months, and has no vehicles? */ if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) { /* Shut the company down */ DoCommandP(0, 2 | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL); IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1); } } else { /* It is not empty, reset the date */ _network_company_states[c->index].months_empty = 0; } } } /** * Check whether a name is unique, and otherwise try to make it unique. * @param new_name The name to check/modify. * @param last The last writeable element of the buffer. * @return True if an unique name was achieved. */ bool NetworkFindName(char *new_name, const char *last) { bool found_name = false; uint number = 0; char original_name[NETWORK_CLIENT_NAME_LENGTH]; strecpy(original_name, new_name, lastof(original_name)); while (!found_name) { const NetworkClientInfo *ci; found_name = true; FOR_ALL_CLIENT_INFOS(ci) { if (strcmp(ci->client_name, new_name) == 0) { /* Name already in use */ found_name = false; break; } } /* Check if it is the same as the server-name */ ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER); if (ci != NULL) { if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use } if (!found_name) { /* Try a new name ( #1, #2, and so on) */ /* Something's really wrong when there're more names than clients */ if (number++ > MAX_CLIENTS) break; seprintf(new_name, last, "%s #%d", original_name, number); } } return found_name; } /** * Change the client name of the given client * @param client_id the client to change the name of * @param new_name the new name for the client * @return true iff the name was changed */ bool NetworkServerChangeClientName(ClientID client_id, const char *new_name) { NetworkClientInfo *ci; /* Check if the name's already in use */ FOR_ALL_CLIENT_INFOS(ci) { if (strcmp(ci->client_name, new_name) == 0) return false; } ci = NetworkClientInfo::GetByClientID(client_id); if (ci == NULL) return false; NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name); strecpy(ci->client_name, new_name, lastof(ci->client_name)); NetworkUpdateClientInfo(client_id); return true; } /** * Set/Reset a company password on the server end. * @param company_id ID of the company the password should be changed for. * @param password The new password. * @param already_hashed Is the given password already hashed? */ void NetworkServerSetCompanyPassword(CompanyID company_id, const char *password, bool already_hashed) { if (!Company::IsValidHumanID(company_id)) return; if (!already_hashed) { password = GenerateCompanyPasswordHash(password, _settings_client.network.network_id, _settings_game.game_creation.generation_seed); } strecpy(_network_company_states[company_id].password, password, lastof(_network_company_states[company_id].password)); NetworkServerUpdateCompanyPassworded(company_id, !StrEmpty(_network_company_states[company_id].password)); } /** * Handle the command-queue of a socket. * @param cs The socket to handle the queue for. */ static void NetworkHandleCommandQueue(NetworkClientSocket *cs) { CommandPacket *cp; while ((cp = cs->outgoing_queue.Pop()) != NULL) { cs->SendCommand(cp); free(cp); } } /** * This is called every tick if this is a _network_server * @param send_frame Whether to send the frame to the clients. */ void NetworkServer_Tick(bool send_frame) { NetworkClientSocket *cs; #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME bool send_sync = false; #endif #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME if (_frame_counter >= _last_sync_frame + _settings_client.network.sync_freq) { _last_sync_frame = _frame_counter; send_sync = true; } #endif /* Now we are done with the frame, inform the clients that they can * do their frame! */ FOR_ALL_CLIENT_SOCKETS(cs) { /* We allow a number of bytes per frame, but only to the burst amount * to be available for packet receiving at any particular time. */ cs->receive_limit = min(cs->receive_limit + _settings_client.network.bytes_per_frame, _settings_client.network.bytes_per_frame_burst); /* Check if the speed of the client is what we can expect from a client */ uint lag = NetworkCalculateLag(cs); switch (cs->status) { case NetworkClientSocket::STATUS_ACTIVE: if (lag > _settings_client.network.max_lag_time) { /* Client did still not report in within the specified limit. */ IConsolePrintF(CC_ERROR, cs->last_packet + lag * MILLISECONDS_PER_TICK > _realtime_tick ? /* A packet was received in the last three game days, so the client is likely lagging behind. */ "Client #%d is dropped because the client's game state is more than %d ticks behind" : /* No packet was received in the last three game days; sounds like a lost connection. */ "Client #%d is dropped because the client did not respond for more than %d ticks", cs->client_id, lag); cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER); continue; } /* Report once per time we detect the lag, and only when we * received a packet in the last 2000 milliseconds. If we * did not receive a packet, then the client is not just * slow, but the connection is likely severed. Mentioning * frame_freq is not useful in this case. */ if (lag > (uint)DAY_TICKS && cs->lag_test == 0 && cs->last_packet + 2000 > _realtime_tick) { IConsolePrintF(CC_WARNING, "[%d] Client #%d is slow, try increasing [network.]frame_freq to a higher value!", _frame_counter, cs->client_id); cs->lag_test = 1; } if (cs->last_frame_server - cs->last_token_frame >= _settings_client.network.max_lag_time) { /* This is a bad client! It didn't send the right token back within time. */ IConsolePrintF(CC_ERROR, "Client #%d is dropped because it fails to send valid acks", cs->client_id); cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER); continue; } break; case NetworkClientSocket::STATUS_INACTIVE: case NetworkClientSocket::STATUS_NEWGRFS_CHECK: case NetworkClientSocket::STATUS_AUTHORIZED: /* NewGRF check and authorized states should be handled almost instantly. * So give them some lee-way, likewise for the query with inactive. */ if (lag > _settings_client.network.max_init_time) { IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->client_id, _settings_client.network.max_init_time); cs->SendError(NETWORK_ERROR_TIMEOUT_COMPUTER); continue; } break; case NetworkClientSocket::STATUS_MAP: /* Downloading the map... this is the amount of time since starting the saving. */ if (lag > _settings_client.network.max_download_time) { IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to download the map", cs->client_id, _settings_client.network.max_download_time); cs->SendError(NETWORK_ERROR_TIMEOUT_MAP); continue; } break; case NetworkClientSocket::STATUS_DONE_MAP: case NetworkClientSocket::STATUS_PRE_ACTIVE: /* The map has been sent, so this is for loading the map and syncing up. */ if (lag > _settings_client.network.max_join_time) { IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to join", cs->client_id, _settings_client.network.max_join_time); cs->SendError(NETWORK_ERROR_TIMEOUT_JOIN); continue; } break; case NetworkClientSocket::STATUS_AUTH_GAME: case NetworkClientSocket::STATUS_AUTH_COMPANY: /* These don't block? */ if (lag > _settings_client.network.max_password_time) { IConsolePrintF(CC_ERROR, "Client #%d is dropped because it took longer than %d ticks to enter the password", cs->client_id, _settings_client.network.max_password_time); cs->SendError(NETWORK_ERROR_TIMEOUT_PASSWORD); continue; } break; case NetworkClientSocket::STATUS_MAP_WAIT: /* This is an internal state where we do not wait * on the client to move to a different state. */ break; case NetworkClientSocket::STATUS_END: /* Bad server/code. */ NOT_REACHED(); } if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) { /* Check if we can send command, and if we have anything in the queue */ NetworkHandleCommandQueue(cs); /* Send an updated _frame_counter_max to the client */ if (send_frame) cs->SendFrame(); #ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME /* Send a sync-check packet */ if (send_sync) cs->SendSync(); #endif } } /* See if we need to advertise */ NetworkUDPAdvertise(); } /** Yearly "callback". Called whenever the year changes. */ void NetworkServerYearlyLoop() { NetworkCheckRestartMap(); NetworkAdminUpdate(ADMIN_FREQUENCY_ANUALLY); } /** Monthly "callback". Called whenever the month changes. */ void NetworkServerMonthlyLoop() { NetworkAutoCleanCompanies(); NetworkAdminUpdate(ADMIN_FREQUENCY_MONTHLY); if ((_cur_month % 3) == 0) NetworkAdminUpdate(ADMIN_FREQUENCY_QUARTERLY); } /** Daily "callback". Called whenever the date changes. */ void NetworkServerDailyLoop() { NetworkAdminUpdate(ADMIN_FREQUENCY_DAILY); if ((_date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY); } /** * Get the IP address/hostname of the connected client. * @return The IP address. */ const char *ServerNetworkGameSocketHandler::GetClientIP() { return this->client_address.GetHostname(); } /** Show the status message of all clients on the console. */ void NetworkServerShowStatusToConsole() { static const char * const stat_str[] = { "inactive", "checking NewGRFs", "authorizing (server password)", "authorizing (company password)", "authorized", "waiting", "loading map", "map done", "ready", "active" }; assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END); NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { NetworkClientInfo *ci = cs->GetInfo(); if (ci == NULL) continue; uint lag = NetworkCalculateLag(cs); const char *status; status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown"); IConsolePrintF(CC_INFO, "Client #%1d name: '%s' status: '%s' frame-lag: %3d company: %1d IP: %s", cs->client_id, ci->client_name, status, lag, ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0), cs->GetClientIP()); } } /** * Send Config Update */ void NetworkServerSendConfigUpdate() { NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendConfigUpdate(); } } /** * Tell that a particular company is (not) passworded. * @param company_id The company that got/removed the password. * @param passworded Whether the password was received or removed. */ void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded) { if (NetworkCompanyIsPassworded(company_id) == passworded) return; SB(_network_company_passworded, company_id, 1, !!passworded); SetWindowClassesDirty(WC_COMPANY); NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->status >= NetworkClientSocket::STATUS_PRE_ACTIVE) cs->SendCompanyUpdate(); } NetworkAdminCompanyUpdate(Company::GetIfValid(company_id)); } /** * Handle the tid-bits of moving a client from one company to another. * @param client_id id of the client we want to move. * @param company_id id of the company we want to move the client to. * @return void */ void NetworkServerDoMove(ClientID client_id, CompanyID company_id) { /* Only allow non-dedicated servers and normal clients to be moved */ if (client_id == CLIENT_ID_SERVER && _network_dedicated) return; NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); /* No need to waste network resources if the client is in the company already! */ if (ci->client_playas == company_id) return; ci->client_playas = company_id; if (client_id == CLIENT_ID_SERVER) { SetLocalCompany(company_id); } else { NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id); /* When the company isn't authorized we can't move them yet. */ if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return; cs->SendMove(client_id, company_id); } /* announce the client's move */ NetworkUpdateClientInfo(client_id); NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN; NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1); } /** * Send an rcon reply to the client. * @param client_id The identifier of the client. * @param colour_code The colour of the text. * @param string The actual reply. */ void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string) { NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string); } /** * Kick a single client. * @param client_id The client to kick. */ void NetworkServerKickClient(ClientID client_id) { if (client_id == CLIENT_ID_SERVER) return; NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED); } /** * Ban, or kick, everyone joined from the given client's IP. * @param client_id The client to check for. * @param ban Whether to ban or kick. */ uint NetworkServerKickOrBanIP(ClientID client_id, bool ban) { return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban); } /** * Kick or ban someone based on an IP address. * @param ip The IP address/range to ban/kick. * @param ban Whether to ban or just kick. */ uint NetworkServerKickOrBanIP(const char *ip, bool ban) { /* Add address to ban-list */ if (ban) { bool contains = false; for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) { if (strcmp(*iter, ip) == 0) { contains = true; break; } } if (!contains) *_network_ban_list.Append() = stredup(ip); } uint n = 0; /* There can be multiple clients with the same IP, kick them all */ NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->client_id == CLIENT_ID_SERVER) continue; if (cs->client_address.IsInNetmask(const_cast(ip))) { NetworkServerKickClient(cs->client_id); n++; } } return n; } /** * Check whether a particular company has clients. * @param company The company to check. * @return True if at least one client is joined to the company. */ bool NetworkCompanyHasClients(CompanyID company) { const NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { if (ci->client_playas == company) return true; } return false; } /** * Get the name of the client, if the user did not send it yet, Client # is used. * @param client_name The variable to write the name to. * @param last The pointer to the last element of the destination buffer */ void ServerNetworkGameSocketHandler::GetClientName(char *client_name, const char *last) const { const NetworkClientInfo *ci = this->GetInfo(); if (ci == NULL || StrEmpty(ci->client_name)) { seprintf(client_name, last, "Client #%4d", this->client_id); } else { strecpy(client_name, ci->client_name, last); } } /** * Print all the clients to the console */ void NetworkPrintClients() { NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { if (_network_server) { IConsolePrintF(CC_INFO, "Client #%1d name: '%s' company: %1d IP: %s", ci->client_id, ci->client_name, ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0), ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP()); } else { IConsolePrintF(CC_INFO, "Client #%1d name: '%s' company: %1d", ci->client_id, ci->client_name, ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0)); } } } /** * Perform all the server specific administration of a new company. * @param c The newly created company; can't be NULL. * @param ci The client information of the client that made the company; can be NULL. */ void NetworkServerNewCompany(const Company *c, NetworkClientInfo *ci) { assert(c != NULL); if (!_network_server) return; _network_company_states[c->index].months_empty = 0; _network_company_states[c->index].password[0] = '\0'; NetworkServerUpdateCompanyPassworded(c->index, false); if (ci != NULL) { /* ci is NULL when replaying, or for AIs. In neither case there is a client. */ ci->client_playas = c->index; NetworkUpdateClientInfo(ci->client_id); NetworkSendCommand(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, c->index); } /* Announce new company on network. */ NetworkAdminCompanyInfo(c, true); if (ci != NULL) { /* ci is NULL when replaying, or for AIs. In neither case there is a client. We need to send Admin port update here so that they first know about the new company and then learn about a possibly joining client (see FS#6025) */ NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, c->index + 1); } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_content_gui.cpp0000644000000000000000000011342712627373441020767 0ustar rootroot/* $Id: network_content_gui.cpp 26921 2014-09-25 19:27:07Z peter1138 $ */ /* * 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 network_content_gui.cpp Implementation of the Network Content related GUIs. */ #if defined(ENABLE_NETWORK) #include "../stdafx.h" #include "../strings_func.h" #include "../gfx_func.h" #include "../window_func.h" #include "../error.h" #include "../ai/ai.hpp" #include "../game/game.hpp" #include "../base_media_base.h" #include "../sortlist_type.h" #include "../stringfilter_type.h" #include "../querystring_gui.h" #include "../core/geometry_func.hpp" #include "../textfile_gui.h" #include "network_content_gui.h" #include "table/strings.h" #include "../table/sprites.h" #include "../safeguards.h" /** Whether the user accepted to enter external websites during this session. */ static bool _accepted_external_search = false; /** Window for displaying the textfile of an item in the content list. */ struct ContentTextfileWindow : public TextfileWindow { const ContentInfo *ci; ///< View the textfile of this ContentInfo. ContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) : TextfileWindow(file_type), ci(ci) { const char *textfile = this->ci->GetTextfile(file_type); this->LoadTextfile(textfile, GetContentInfoSubDir(this->ci->type)); } StringID GetTypeString() const { switch (this->ci->type) { case CONTENT_TYPE_NEWGRF: return STR_CONTENT_TYPE_NEWGRF; case CONTENT_TYPE_BASE_GRAPHICS: return STR_CONTENT_TYPE_BASE_GRAPHICS; case CONTENT_TYPE_BASE_SOUNDS: return STR_CONTENT_TYPE_BASE_SOUNDS; case CONTENT_TYPE_BASE_MUSIC: return STR_CONTENT_TYPE_BASE_MUSIC; case CONTENT_TYPE_AI: return STR_CONTENT_TYPE_AI; case CONTENT_TYPE_AI_LIBRARY: return STR_CONTENT_TYPE_AI_LIBRARY; case CONTENT_TYPE_GAME: return STR_CONTENT_TYPE_GAME_SCRIPT; case CONTENT_TYPE_GAME_LIBRARY: return STR_CONTENT_TYPE_GS_LIBRARY; case CONTENT_TYPE_SCENARIO: return STR_CONTENT_TYPE_SCENARIO; case CONTENT_TYPE_HEIGHTMAP: return STR_CONTENT_TYPE_HEIGHTMAP; default: NOT_REACHED(); } } /* virtual */ void SetStringParameters(int widget) const { if (widget == WID_TF_CAPTION) { SetDParam(0, this->GetTypeString()); SetDParamStr(1, this->ci->name); } } }; void ShowContentTextfileWindow(TextfileType file_type, const ContentInfo *ci) { DeleteWindowByClass(WC_TEXTFILE); new ContentTextfileWindow(file_type, ci); } /** Nested widgets for the download window. */ static const NWidgetPart _nested_network_content_download_status_window_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PANEL, COLOUR_GREY, WID_NCDS_BACKGROUND), NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(125, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCDS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 4), EndContainer(), }; /** Window description for the download window */ static WindowDesc _network_content_download_status_window_desc( WDP_CENTER, NULL, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, _nested_network_content_download_status_window_widgets, lengthof(_nested_network_content_download_status_window_widgets) ); BaseNetworkContentDownloadStatusWindow::BaseNetworkContentDownloadStatusWindow(WindowDesc *desc) : Window(desc), cur_id(UINT32_MAX) { _network_content_client.AddCallback(this); _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes); this->InitNested(WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD); } BaseNetworkContentDownloadStatusWindow::~BaseNetworkContentDownloadStatusWindow() { _network_content_client.RemoveCallback(this); } /* virtual */ void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, int widget) const { if (widget != WID_NCDS_BACKGROUND) return; /* Draw nice progress bar :) */ DrawFrameRect(r.left + 20, r.top + 4, r.left + 20 + (int)((this->width - 40LL) * this->downloaded_bytes / this->total_bytes), r.top + 14, COLOUR_MAUVE, FR_NONE); int y = r.top + 20; SetDParam(0, this->downloaded_bytes); SetDParam(1, this->total_bytes); SetDParam(2, this->downloaded_bytes * 100LL / this->total_bytes); DrawString(r.left + 2, r.right - 2, y, STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, TC_FROMSTRING, SA_HOR_CENTER); StringID str; if (this->downloaded_bytes == this->total_bytes) { str = STR_CONTENT_DOWNLOAD_COMPLETE; } else if (!StrEmpty(this->name)) { SetDParamStr(0, this->name); SetDParam(1, this->downloaded_files); SetDParam(2, this->total_files); str = STR_CONTENT_DOWNLOAD_FILE; } else { str = STR_CONTENT_DOWNLOAD_INITIALISE; } y += FONT_HEIGHT_NORMAL + 5; DrawStringMultiLine(r.left + 2, r.right - 2, y, y + FONT_HEIGHT_NORMAL * 2, str, TC_FROMSTRING, SA_CENTER); } /* virtual */ void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo *ci, int bytes) { if (ci->id != this->cur_id) { strecpy(this->name, ci->filename, lastof(this->name)); this->cur_id = ci->id; this->downloaded_files++; } this->downloaded_bytes += bytes; this->SetDirty(); } /** Window for showing the download status of content */ struct NetworkContentDownloadStatusWindow : public BaseNetworkContentDownloadStatusWindow { private: SmallVector receivedTypes; ///< Types we received so we can update their cache public: /** * Create a new download window based on a list of content information * with flags whether to download them or not. */ NetworkContentDownloadStatusWindow() : BaseNetworkContentDownloadStatusWindow(&_network_content_download_status_window_desc) { this->parent = FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST); } /** Free whatever we've allocated */ ~NetworkContentDownloadStatusWindow() { TarScanner::Mode mode = TarScanner::NONE; for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) { switch (*iter) { case CONTENT_TYPE_AI: case CONTENT_TYPE_AI_LIBRARY: /* AI::Rescan calls the scanner. */ break; case CONTENT_TYPE_GAME: case CONTENT_TYPE_GAME_LIBRARY: /* Game::Rescan calls the scanner. */ break; case CONTENT_TYPE_BASE_GRAPHICS: case CONTENT_TYPE_BASE_SOUNDS: case CONTENT_TYPE_BASE_MUSIC: mode |= TarScanner::BASESET; break; case CONTENT_TYPE_NEWGRF: /* ScanNewGRFFiles calls the scanner. */ break; case CONTENT_TYPE_SCENARIO: case CONTENT_TYPE_HEIGHTMAP: mode |= TarScanner::SCENARIO; break; default: break; } } TarScanner::DoScan(mode); /* Tell all the backends about what we've downloaded */ for (ContentType *iter = this->receivedTypes.Begin(); iter != this->receivedTypes.End(); iter++) { switch (*iter) { case CONTENT_TYPE_AI: case CONTENT_TYPE_AI_LIBRARY: AI::Rescan(); break; case CONTENT_TYPE_GAME: case CONTENT_TYPE_GAME_LIBRARY: Game::Rescan(); break; case CONTENT_TYPE_BASE_GRAPHICS: BaseGraphics::FindSets(); SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS); break; case CONTENT_TYPE_BASE_SOUNDS: BaseSounds::FindSets(); SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS); break; case CONTENT_TYPE_BASE_MUSIC: BaseMusic::FindSets(); SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS); break; case CONTENT_TYPE_NEWGRF: ScanNewGRFFiles(NULL); break; case CONTENT_TYPE_SCENARIO: case CONTENT_TYPE_HEIGHTMAP: extern void ScanScenarios(); ScanScenarios(); InvalidateWindowData(WC_SAVELOAD, 0, 0); break; default: break; } } /* Always invalidate the download window; tell it we are going to be gone */ InvalidateWindowData(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST, 2); } virtual void OnClick(Point pt, int widget, int click_count) { if (widget == WID_NCDS_CANCELOK) { if (this->downloaded_bytes != this->total_bytes) { _network_content_client.Close(); delete this; } else { /* If downloading succeeded, close the online content window. This will close * the current window as well. */ DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST); } } } virtual void OnDownloadProgress(const ContentInfo *ci, int bytes) { BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ci, bytes); this->receivedTypes.Include(ci->type); /* When downloading is finished change cancel in ok */ if (this->downloaded_bytes == this->total_bytes) { this->GetWidget(WID_NCDS_CANCELOK)->widget_data = STR_BUTTON_OK; } } }; /** Window that lists the content that's at the content server */ class NetworkContentListWindow : public Window, ContentCallback { /** List with content infos. */ typedef GUIList GUIContentList; static const uint EDITBOX_MAX_SIZE = 50; ///< Maximum size of the editbox in characters. static Listing last_sorting; ///< The last sorting setting. static Filtering last_filtering; ///< The last filtering setting. static GUIContentList::SortFunction * const sorter_funcs[]; ///< Sorter functions static GUIContentList::FilterFunction * const filter_funcs[]; ///< Filter functions. GUIContentList content; ///< List with content bool auto_select; ///< Automatically select all content when the meta-data becomes available StringFilter string_filter; ///< Filter for content list QueryString filter_editbox; ///< Filter editbox; Dimension checkbox_size; ///< Size of checkbox/"blot" sprite const ContentInfo *selected; ///< The selected content info int list_pos; ///< Our position in the list uint filesize_sum; ///< The sum of all selected file sizes Scrollbar *vscroll; ///< Cache of the vertical scrollbar /** Search external websites for content */ void OpenExternalSearch() { extern void OpenBrowser(const char *url); char url[1024]; const char *last = lastof(url); char *pos = strecpy(url, "http://grfsearch.openttd.org/?", last); if (this->auto_select) { pos = strecpy(pos, "do=searchgrfid&q=", last); bool first = true; for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { const ContentInfo *ci = *iter; if (ci->state != ContentInfo::DOES_NOT_EXIST) continue; if (!first) pos = strecpy(pos, ",", last); first = false; pos += seprintf(pos, last, "%08X", ci->unique_id); pos = strecpy(pos, ":", last); pos = md5sumToString(pos, last, ci->md5sum); } } else { pos = strecpy(pos, "do=searchtext&q=", last); /* Escape search term */ for (const char *search = this->filter_editbox.text.buf; *search != '\0'; search++) { /* Remove quotes */ if (*search == '\'' || *search == '"') continue; /* Escape special chars, such as &%,= */ if (*search < 0x30) { pos += seprintf(pos, last, "%%%02X", *search); } else if (pos < last) { *pos = *search; *++pos = '\0'; } } } OpenBrowser(url); } /** * Callback function for disclaimer about entering external websites. */ static void ExternalSearchDisclaimerCallback(Window *w, bool accepted) { if (accepted) { _accepted_external_search = true; ((NetworkContentListWindow*)w)->OpenExternalSearch(); } } /** * (Re)build the network game list as its amount has changed because * an item has been added or deleted for example */ void BuildContentList() { if (!this->content.NeedRebuild()) return; /* Create temporary array of games to use for listing */ this->content.Clear(); bool all_available = true; for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { if ((*iter)->state == ContentInfo::DOES_NOT_EXIST) all_available = false; *this->content.Append() = *iter; } this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select && all_available); this->FilterContentList(); this->content.Compact(); this->content.RebuildDone(); this->SortContentList(); this->vscroll->SetCount(this->content.Length()); // Update the scrollbar this->ScrollToSelected(); } /** Sort content by name. */ static int CDECL NameSorter(const ContentInfo * const *a, const ContentInfo * const *b) { return strnatcmp((*a)->name, (*b)->name, true); // Sort by name (natural sorting). } /** Sort content by type. */ static int CDECL TypeSorter(const ContentInfo * const *a, const ContentInfo * const *b) { int r = 0; if ((*a)->type != (*b)->type) { char a_str[64]; char b_str[64]; GetString(a_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*a)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(a_str)); GetString(b_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*b)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(b_str)); r = strnatcmp(a_str, b_str); } if (r == 0) r = NameSorter(a, b); return r; } /** Sort content by state. */ static int CDECL StateSorter(const ContentInfo * const *a, const ContentInfo * const *b) { int r = (*a)->state - (*b)->state; if (r == 0) r = TypeSorter(a, b); return r; } /** Sort the content list */ void SortContentList() { if (!this->content.Sort()) return; for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { if (*iter == this->selected) { this->list_pos = iter - this->content.Begin(); break; } } } /** Filter content by tags/name */ static bool CDECL TagNameFilter(const ContentInfo * const *a, StringFilter &filter) { filter.ResetState(); for (int i = 0; i < (*a)->tag_count; i++) { filter.AddLine((*a)->tags[i]); } filter.AddLine((*a)->name); return filter.GetState(); } /** Filter the content list */ void FilterContentList() { if (!this->content.Filter(this->string_filter)) return; /* update list position */ for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { if (*iter == this->selected) { this->list_pos = iter - this->content.Begin(); return; } } /* previously selected item not in list anymore */ this->selected = NULL; this->list_pos = 0; } /** Make sure that the currently selected content info is within the visible part of the matrix */ void ScrollToSelected() { if (this->selected == NULL) return; this->vscroll->ScrollTowards(this->list_pos); } public: /** * Create the content list window. * @param desc the window description to pass to Window's constructor. * @param select_all Whether the select all button is allowed or not. */ NetworkContentListWindow(WindowDesc *desc, bool select_all) : Window(desc), auto_select(select_all), filter_editbox(EDITBOX_MAX_SIZE), selected(NULL), list_pos(0) { this->checkbox_size = maxdim(maxdim(GetSpriteSize(SPR_BOX_EMPTY), GetSpriteSize(SPR_BOX_CHECKED)), GetSpriteSize(SPR_BLOT)); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NCL_SCROLLBAR); this->FinishInitNested(WN_NETWORK_WINDOW_CONTENT_LIST); this->GetWidget(WID_NCL_SEL_ALL_UPDATE)->SetDisplayedPlane(select_all); this->querystrings[WID_NCL_FILTER] = &this->filter_editbox; this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; this->SetFocusedWidget(WID_NCL_FILTER); this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select); _network_content_client.AddCallback(this); this->content.SetListing(this->last_sorting); this->content.SetFiltering(this->last_filtering); this->content.SetSortFuncs(this->sorter_funcs); this->content.SetFilterFuncs(this->filter_funcs); this->content.ForceRebuild(); this->FilterContentList(); this->SortContentList(); this->InvalidateData(); } /** Free everything we allocated */ ~NetworkContentListWindow() { _network_content_client.RemoveCallback(this); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_NCL_FILTER_CAPT: *size = maxdim(*size, GetStringBoundingBox(STR_CONTENT_FILTER_TITLE)); break; case WID_NCL_CHECKBOX: size->width = this->checkbox_size.width + WD_MATRIX_RIGHT + WD_MATRIX_LEFT; break; case WID_NCL_TYPE: { Dimension d = *size; for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) { d = maxdim(d, GetStringBoundingBox(STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS)); } size->width = d.width + WD_MATRIX_RIGHT + WD_MATRIX_LEFT; break; } case WID_NCL_MATRIX: resize->height = max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 10 * resize->height; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_NCL_FILTER_CAPT: DrawString(r.left, r.right, r.top, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING, SA_RIGHT); break; case WID_NCL_DETAILS: this->DrawDetails(r); break; case WID_NCL_MATRIX: this->DrawMatrix(r); break; } } virtual void OnPaint() { const SortButtonState arrow = this->content.IsDescSortOrder() ? SBS_DOWN : SBS_UP; if (this->content.NeedRebuild()) { this->BuildContentList(); } this->DrawWidgets(); switch (this->content.SortType()) { case WID_NCL_CHECKBOX - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_CHECKBOX, arrow); break; case WID_NCL_TYPE - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_TYPE, arrow); break; case WID_NCL_NAME - WID_NCL_CHECKBOX: this->DrawSortButtonState(WID_NCL_NAME, arrow); break; } } /** * Draw/fill the matrix with the list of content to download. * @param r The boundaries of the matrix. */ void DrawMatrix(const Rect &r) const { const NWidgetBase *nwi_checkbox = this->GetWidget(WID_NCL_CHECKBOX); const NWidgetBase *nwi_name = this->GetWidget(WID_NCL_NAME); const NWidgetBase *nwi_type = this->GetWidget(WID_NCL_TYPE); int line_height = max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL); /* Fill the matrix with the information */ int sprite_y_offset = WD_MATRIX_TOP + (line_height - this->checkbox_size.height) / 2 - 1; int text_y_offset = WD_MATRIX_TOP + (line_height - FONT_HEIGHT_NORMAL) / 2; uint y = r.top; int cnt = 0; for (ConstContentIterator iter = this->content.Get(this->vscroll->GetPosition()); iter != this->content.End() && cnt < this->vscroll->GetCapacity(); iter++, cnt++) { const ContentInfo *ci = *iter; if (ci == this->selected) GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 1, PC_GREY); SpriteID sprite; SpriteID pal = PAL_NONE; switch (ci->state) { case ContentInfo::UNSELECTED: sprite = SPR_BOX_EMPTY; break; case ContentInfo::SELECTED: sprite = SPR_BOX_CHECKED; break; case ContentInfo::AUTOSELECTED: sprite = SPR_BOX_CHECKED; break; case ContentInfo::ALREADY_HERE: sprite = SPR_BLOT; pal = PALETTE_TO_GREEN; break; case ContentInfo::DOES_NOT_EXIST: sprite = SPR_BLOT; pal = PALETTE_TO_RED; break; default: NOT_REACHED(); } DrawSprite(sprite, pal, nwi_checkbox->pos_x + (pal == PAL_NONE ? 2 : 3), y + sprite_y_offset + (pal == PAL_NONE ? 1 : 0)); StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS; DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, y + text_y_offset, str, TC_BLACK, SA_HOR_CENTER); DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + text_y_offset, ci->name, TC_BLACK); y += this->resize.step_height; } } /** * Helper function to draw the details part of this window. * @param r the rectangle to stay within while drawing */ void DrawDetails(const Rect &r) const { static const int DETAIL_LEFT = 5; ///< Number of pixels at the left static const int DETAIL_RIGHT = 5; ///< Number of pixels at the right static const int DETAIL_TOP = 5; ///< Number of pixels at the top /* Height for the title banner */ int DETAIL_TITLE_HEIGHT = 5 * FONT_HEIGHT_NORMAL; /* Create the nice grayish rectangle at the details top */ GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + DETAIL_TITLE_HEIGHT, PC_DARK_BLUE); DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + FONT_HEIGHT_NORMAL + WD_INSET_TOP, STR_CONTENT_DETAIL_TITLE, TC_FROMSTRING, SA_HOR_CENTER); /* Draw the total download size */ SetDParam(0, this->filesize_sum); DrawString(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_NORMAL, STR_CONTENT_TOTAL_DOWNLOAD_SIZE); if (this->selected == NULL) return; /* And fill the rest of the details when there's information to place there */ DrawStringMultiLine(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + DETAIL_TITLE_HEIGHT / 2, r.top + DETAIL_TITLE_HEIGHT, STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED + this->selected->state, TC_FROMSTRING, SA_CENTER); /* Also show the total download size, so keep some space from the bottom */ const uint max_y = r.bottom - FONT_HEIGHT_NORMAL - WD_PAR_VSEP_WIDE; int y = r.top + DETAIL_TITLE_HEIGHT + DETAIL_TOP; if (this->selected->upgrade) { SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_UPDATE); y += WD_PAR_VSEP_WIDE; } SetDParamStr(0, this->selected->name); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_NAME); if (!StrEmpty(this->selected->version)) { SetDParamStr(0, this->selected->version); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_VERSION); } if (!StrEmpty(this->selected->description)) { SetDParamStr(0, this->selected->description); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DESCRIPTION); } if (!StrEmpty(this->selected->url)) { SetDParamStr(0, this->selected->url); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_URL); } SetDParam(0, STR_CONTENT_TYPE_BASE_GRAPHICS + this->selected->type - CONTENT_TYPE_BASE_GRAPHICS); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TYPE); y += WD_PAR_VSEP_WIDE; SetDParam(0, this->selected->filesize); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_FILESIZE); if (this->selected->dependency_count != 0) { /* List dependencies */ char buf[DRAW_STRING_BUFFER] = ""; char *p = buf; for (uint i = 0; i < this->selected->dependency_count; i++) { ContentID cid = this->selected->dependencies[i]; /* Try to find the dependency */ ConstContentIterator iter = _network_content_client.Begin(); for (; iter != _network_content_client.End(); iter++) { const ContentInfo *ci = *iter; if (ci->id != cid) continue; p += seprintf(p, lastof(buf), p == buf ? "%s" : ", %s", (*iter)->name); break; } } SetDParamStr(0, buf); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_DEPENDENCIES); } if (this->selected->tag_count != 0) { /* List all tags */ char buf[DRAW_STRING_BUFFER] = ""; char *p = buf; for (uint i = 0; i < this->selected->tag_count; i++) { p += seprintf(p, lastof(buf), i == 0 ? "%s" : ", %s", this->selected->tags[i]); } SetDParamStr(0, buf); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_TAGS); } if (this->selected->IsSelected()) { /* When selected show all manually selected content that depends on this */ ConstContentVector tree; _network_content_client.ReverseLookupTreeDependency(tree, this->selected); char buf[DRAW_STRING_BUFFER] = ""; char *p = buf; for (ConstContentIterator iter = tree.Begin(); iter != tree.End(); iter++) { const ContentInfo *ci = *iter; if (ci == this->selected || ci->state != ContentInfo::SELECTED) continue; p += seprintf(p, lastof(buf), buf == p ? "%s" : ", %s", ci->name); } if (p != buf) { SetDParamStr(0, buf); y = DrawStringMultiLine(r.left + DETAIL_LEFT, r.right - DETAIL_RIGHT, y, max_y, STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF); } } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget >= WID_NCL_TEXTFILE && widget < WID_NCL_TEXTFILE + TFT_END) { if (this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE) return; ShowContentTextfileWindow((TextfileType)(widget - WID_NCL_TEXTFILE), this->selected); return; } switch (widget) { case WID_NCL_MATRIX: { uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NCL_MATRIX); if (id_v >= this->content.Length()) return; // click out of bounds this->selected = *this->content.Get(id_v); this->list_pos = id_v; const NWidgetBase *checkbox = this->GetWidget(WID_NCL_CHECKBOX); if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) { _network_content_client.ToggleSelectedState(this->selected); this->content.ForceResort(); } this->InvalidateData(); break; } case WID_NCL_CHECKBOX: case WID_NCL_TYPE: case WID_NCL_NAME: if (this->content.SortType() == widget - WID_NCL_CHECKBOX) { this->content.ToggleSortOrder(); if (this->content.Length() > 0) this->list_pos = this->content.Length() - this->list_pos - 1; } else { this->content.SetSortType(widget - WID_NCL_CHECKBOX); this->content.ForceResort(); this->SortContentList(); } this->ScrollToSelected(); this->InvalidateData(); break; case WID_NCL_SELECT_ALL: _network_content_client.SelectAll(); this->InvalidateData(); break; case WID_NCL_SELECT_UPDATE: _network_content_client.SelectUpgrade(); this->InvalidateData(); break; case WID_NCL_UNSELECT: _network_content_client.UnselectAll(); this->InvalidateData(); break; case WID_NCL_CANCEL: delete this; break; case WID_NCL_OPEN_URL: if (this->selected != NULL) { extern void OpenBrowser(const char *url); OpenBrowser(this->selected->url); } break; case WID_NCL_DOWNLOAD: if (BringWindowToFrontById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) == NULL) new NetworkContentDownloadStatusWindow(); break; case WID_NCL_SEARCH_EXTERNAL: if (_accepted_external_search) { this->OpenExternalSearch(); } else { ShowQuery(STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION, STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER, this, ExternalSearchDisclaimerCallback); } break; } } virtual EventState OnKeyPress(WChar key, uint16 keycode) { switch (keycode) { case WKC_UP: /* scroll up by one */ if (this->list_pos > 0) this->list_pos--; break; case WKC_DOWN: /* scroll down by one */ if (this->list_pos < (int)this->content.Length() - 1) this->list_pos++; break; case WKC_PAGEUP: /* scroll up a page */ this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity(); break; case WKC_PAGEDOWN: /* scroll down a page */ this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.Length() - 1); break; case WKC_HOME: /* jump to beginning */ this->list_pos = 0; break; case WKC_END: /* jump to end */ this->list_pos = this->content.Length() - 1; break; case WKC_SPACE: case WKC_RETURN: if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) { if (this->selected != NULL) { _network_content_client.ToggleSelectedState(this->selected); this->content.ForceResort(); this->InvalidateData(); } return ES_HANDLED; } /* FALL THROUGH, space is pressed and filter isn't focused. */ default: return ES_NOT_HANDLED; } if (this->content.Length() == 0) { this->list_pos = 0; // above stuff may result in "-1". return ES_HANDLED; } this->selected = *this->content.Get(this->list_pos); /* scroll to the new server if it is outside the current range */ this->ScrollToSelected(); /* redraw window */ this->InvalidateData(); return ES_HANDLED; } virtual void OnEditboxChanged(int wid) { if (wid == WID_NCL_FILTER) { this->string_filter.SetFilterTerm(this->filter_editbox.text.buf); this->content.SetFilterState(!this->string_filter.IsEmpty()); this->content.ForceRebuild(); this->InvalidateData(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_NCL_MATRIX); } virtual void OnReceiveContentInfo(const ContentInfo *rci) { if (this->auto_select && !rci->IsSelected()) _network_content_client.ToggleSelectedState(rci); this->content.ForceRebuild(); this->InvalidateData(); } virtual void OnDownloadComplete(ContentID cid) { this->content.ForceResort(); this->InvalidateData(); } virtual void OnConnect(bool success) { if (!success) { ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_CONNECT, INVALID_STRING_ID, WL_ERROR); delete this; return; } this->InvalidateData(); } /** * 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; if (this->content.NeedRebuild()) this->BuildContentList(); /* To sum all the bytes we intend to download */ this->filesize_sum = 0; bool show_select_all = false; bool show_select_upgrade = false; for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { const ContentInfo *ci = *iter; switch (ci->state) { case ContentInfo::SELECTED: case ContentInfo::AUTOSELECTED: this->filesize_sum += ci->filesize; break; case ContentInfo::UNSELECTED: show_select_all = true; show_select_upgrade |= ci->upgrade; break; default: break; } } /* If data == 2 then the status window caused this OnInvalidate */ this->SetWidgetDisabledState(WID_NCL_DOWNLOAD, this->filesize_sum == 0 || (FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD) != NULL && data != 2)); this->SetWidgetDisabledState(WID_NCL_UNSELECT, this->filesize_sum == 0); this->SetWidgetDisabledState(WID_NCL_SELECT_ALL, !show_select_all); this->SetWidgetDisabledState(WID_NCL_SELECT_UPDATE, !show_select_upgrade); this->SetWidgetDisabledState(WID_NCL_OPEN_URL, this->selected == NULL || StrEmpty(this->selected->url)); for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { this->SetWidgetDisabledState(WID_NCL_TEXTFILE + tft, this->selected == NULL || this->selected->state != ContentInfo::ALREADY_HERE || this->selected->GetTextfile(tft) == NULL); } this->GetWidget(WID_NCL_CANCEL)->widget_data = this->filesize_sum == 0 ? STR_AI_SETTINGS_CLOSE : STR_AI_LIST_CANCEL; } }; Listing NetworkContentListWindow::last_sorting = {false, 1}; Filtering NetworkContentListWindow::last_filtering = {false, 0}; NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentListWindow::sorter_funcs[] = { &StateSorter, &TypeSorter, &NameSorter, }; NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = { &TagNameFilter, }; /** The widgets for the content list. */ static const NWidgetPart _nested_network_content_list_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_CONTENT_TITLE, STR_NULL), NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_BACKGROUND), NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), /* Top */ NWidget(WWT_EMPTY, COLOUR_LIGHT_BLUE, WID_NCL_FILTER_CAPT), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NCL_FILTER), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), /* Left side. */ NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CHECKBOX), SetMinimalSize(13, 1), SetDataTip(STR_EMPTY, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TYPE), SetDataTip(STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_NAME), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TOOLTIP), EndContainer(), NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NCL_MATRIX), SetResize(1, 14), SetFill(1, 1), SetScrollbar(WID_NCL_SCROLLBAR), SetMatrixDataTip(1, 0, STR_CONTENT_MATRIX_TOOLTIP), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NCL_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NCL_SEL_ALL_UPDATE), SetResize(1, 0), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_UPDATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SELECT_ALL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_UNSELECT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP), EndContainer(), EndContainer(), /* Right side. */ NWidget(NWID_VERTICAL), SetPIP(0, 4, 0), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NCL_DETAILS), SetResize(1, 1), SetFill(1, 1), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_OPEN_URL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 7), SetResize(1, 0), /* Bottom. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(8, 8, 8), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_SEARCH_EXTERNAL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_SEARCH_EXTERNAL, STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, 8, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NCL_DOWNLOAD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetResize(1, 0), /* Resize button. */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), EndContainer(), EndContainer(), }; /** Window description of the content list */ static WindowDesc _network_content_list_desc( WDP_CENTER, "list_content", 630, 460, WC_NETWORK_WINDOW, WC_NONE, 0, _nested_network_content_list_widgets, lengthof(_nested_network_content_list_widgets) ); /** * Show the content list window with a given set of content * @param cv the content to show, or NULL when it has to search for itself * @param type the type to (only) show */ void ShowNetworkContentListWindow(ContentVector *cv, ContentType type) { #if defined(WITH_ZLIB) _network_content_client.Clear(); if (cv == NULL) { _network_content_client.RequestContentList(type); } else { _network_content_client.RequestContentList(cv, true); } DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST); new NetworkContentListWindow(&_network_content_list_desc, cv != NULL); #else ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR); /* Connection failed... clean up the mess */ if (cv != NULL) { for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) delete *iter; } #endif /* WITH_ZLIB */ } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network.cpp0000644000000000000000000010606512627373441016371 0ustar rootroot/* $Id: network.cpp 27431 2015-11-01 11:59:17Z frosch $ */ /* * 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 network.cpp Base functions for networking support. */ #include "../stdafx.h" #ifdef ENABLE_NETWORK #include "../strings_func.h" #include "../command_func.h" #include "../date_func.h" #include "network_admin.h" #include "network_client.h" #include "network_server.h" #include "network_content.h" #include "network_udp.h" #include "network_gamelist.h" #include "network_base.h" #include "core/udp.h" #include "core/host.h" #include "network_gui.h" #include "../console_func.h" #include "../3rdparty/md5/md5.h" #include "../core/random_func.hpp" #include "../window_func.h" #include "../company_func.h" #include "../company_base.h" #include "../landscape_type.h" #include "../rev.h" #include "../core/pool_func.hpp" #include "../gfx_func.h" #include "../error.h" #include "../safeguards.h" #ifdef DEBUG_DUMP_COMMANDS #include "../fileio_func.h" /** When running the server till the wait point, run as fast as we can! */ bool _ddc_fastforward = true; #endif /* DEBUG_DUMP_COMMANDS */ /** Make sure both pools have the same size. */ assert_compile(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE); /** The pool with client information. */ NetworkClientInfoPool _networkclientinfo_pool("NetworkClientInfo"); INSTANTIATE_POOL_METHODS(NetworkClientInfo) bool _networking; ///< are we in networking mode? bool _network_server; ///< network-server is active bool _network_available; ///< is network mode available? bool _network_dedicated; ///< are we a dedicated server? bool _is_network_server; ///< Does this client wants to be a network-server? NetworkServerGameInfo _network_game_info; ///< Information about our game. NetworkCompanyState *_network_company_states = NULL; ///< Statistics about some companies. ClientID _network_own_client_id; ///< Our client identifier. ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client. bool _network_need_advertise; ///< Whether we need to advertise. uint8 _network_reconnect; ///< Reconnect timeout StringList _network_bind_list; ///< The addresses to bind on. StringList _network_host_list; ///< The servers we know. StringList _network_ban_list; ///< The banned clients. uint32 _frame_counter_server; ///< The frame_counter of the server, if in network-mode uint32 _frame_counter_max; ///< To where we may go with our clients uint32 _frame_counter; ///< The current frame. uint32 _last_sync_frame; ///< Used in the server to store the last time a sync packet was sent to clients. NetworkAddressList _broadcast_list; ///< List of broadcast addresses. uint32 _sync_seed_1; ///< Seed to compare during sync checks. #ifdef NETWORK_SEND_DOUBLE_SEED uint32 _sync_seed_2; ///< Second part of the seed. #endif uint32 _sync_frame; ///< The frame to perform the sync check. bool _network_first_time; ///< Whether we have finished joining or not. bool _network_udp_server; ///< Is the UDP server started? uint16 _network_udp_broadcast; ///< Timeout for the UDP broadcasts. uint8 _network_advertise_retries; ///< The number of advertisement retries we did. CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies. /* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */ assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE); assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH); extern NetworkUDPSocketHandler *_udp_client_socket; ///< udp client socket extern NetworkUDPSocketHandler *_udp_server_socket; ///< udp server socket extern NetworkUDPSocketHandler *_udp_master_socket; ///< udp master socket /** The amount of clients connected */ byte _network_clients_connected = 0; /* Some externs / forwards */ extern void StateGameLoop(); /** * Return whether there is any client connected or trying to connect at all. * @return whether we have any client activity */ bool HasClients() { NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) return true; return false; } /** * Basically a client is leaving us right now. */ NetworkClientInfo::~NetworkClientInfo() { /* Delete the chat window, if you were chatting with this client. */ InvalidateWindowData(WC_SEND_NETWORK_MSG, DESTTYPE_CLIENT, this->client_id); } /** * Return the CI given it's client-identifier * @param client_id the ClientID to search for * @return return a pointer to the corresponding NetworkClientInfo struct or NULL when not found */ /* static */ NetworkClientInfo *NetworkClientInfo::GetByClientID(ClientID client_id) { NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { if (ci->client_id == client_id) return ci; } return NULL; } /** * Return the client state given it's client-identifier * @param client_id the ClientID to search for * @return return a pointer to the corresponding NetworkClientSocket struct or NULL when not found */ /* static */ ServerNetworkGameSocketHandler *ServerNetworkGameSocketHandler::GetByClientID(ClientID client_id) { NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->client_id == client_id) return cs; } return NULL; } byte NetworkSpectatorCount() { const NetworkClientInfo *ci; byte count = 0; FOR_ALL_CLIENT_INFOS(ci) { if (ci->client_playas == COMPANY_SPECTATOR) count++; } /* Don't count a dedicated server as spectator */ if (_network_dedicated) count--; return count; } /** * Change the company password of a given company. * @param company_id ID of the company the password should be changed for. * @param password The unhashed password we like to set ('*' or '' resets the password) * @return The password. */ const char *NetworkChangeCompanyPassword(CompanyID company_id, const char *password) { if (strcmp(password, "*") == 0) password = ""; if (_network_server) { NetworkServerSetCompanyPassword(company_id, password, false); } else { NetworkClientSetCompanyPassword(password); } return password; } /** * Hash the given password using server ID and game seed. * @param password Password to hash. * @param password_server_id Server ID. * @param password_game_seed Game seed. * @return The hashed password. */ const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed) { if (StrEmpty(password)) return password; char salted_password[NETWORK_SERVER_ID_LENGTH]; memset(salted_password, 0, sizeof(salted_password)); seprintf(salted_password, lastof(salted_password), "%s", password); /* Add the game seed and the server's ID as the salt. */ for (uint i = 0; i < NETWORK_SERVER_ID_LENGTH - 1; i++) { salted_password[i] ^= password_server_id[i] ^ (password_game_seed >> (i % 32)); } Md5 checksum; uint8 digest[16]; static char hashed_password[NETWORK_SERVER_ID_LENGTH]; /* Generate the MD5 hash */ checksum.Append(salted_password, sizeof(salted_password) - 1); checksum.Finish(digest); for (int di = 0; di < 16; di++) seprintf(hashed_password + di * 2, lastof(hashed_password), "%02x", digest[di]); return hashed_password; } /** * Check if the company we want to join requires a password. * @param company_id id of the company we want to check the 'passworded' flag for. * @return true if the company requires a password. */ bool NetworkCompanyIsPassworded(CompanyID company_id) { return HasBit(_network_company_passworded, company_id); } /* This puts a text-message to the console, or in the future, the chat-box, * (to keep it all a bit more general) * If 'self_send' is true, this is the client who is sending the message */ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const char *name, const char *str, int64 data) { StringID strid; switch (action) { case NETWORK_ACTION_SERVER_MESSAGE: /* Ignore invalid messages */ strid = STR_NETWORK_SERVER_MESSAGE; colour = CC_DEFAULT; break; case NETWORK_ACTION_COMPANY_SPECTATOR: colour = CC_DEFAULT; strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE; break; case NETWORK_ACTION_COMPANY_JOIN: colour = CC_DEFAULT; strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN; break; case NETWORK_ACTION_COMPANY_NEW: colour = CC_DEFAULT; strid = STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW; break; case NETWORK_ACTION_JOIN: /* Show the Client ID for the server but not for the client. */ strid = _network_server ? STR_NETWORK_MESSAGE_CLIENT_JOINED_ID : STR_NETWORK_MESSAGE_CLIENT_JOINED; break; case NETWORK_ACTION_LEAVE: strid = STR_NETWORK_MESSAGE_CLIENT_LEFT; break; case NETWORK_ACTION_NAME_CHANGE: strid = STR_NETWORK_MESSAGE_NAME_CHANGE; break; case NETWORK_ACTION_GIVE_MONEY: strid = self_send ? STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY : STR_NETWORK_MESSAGE_GIVE_MONEY; break; case NETWORK_ACTION_CHAT_COMPANY: strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; break; case NETWORK_ACTION_CHAT_CLIENT: strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT; break; default: strid = STR_NETWORK_CHAT_ALL; break; } char message[1024]; SetDParamStr(0, name); SetDParamStr(1, str); SetDParam(2, data); /* All of these strings start with "***". These characters are interpreted as both left-to-right and * right-to-left characters depending on the context. As the next text might be an user's name, the * user name's characters will influence the direction of the "***" instead of the language setting * of the game. Manually set the direction of the "***" by inserting a text-direction marker. */ char *msg_ptr = message + Utf8Encode(message, _current_text_dir == TD_LTR ? CHAR_TD_LRM : CHAR_TD_RLM); GetString(msg_ptr, strid, lastof(message)); DEBUG(desync, 1, "msg: %08x; %02x; %s", _date, _date_fract, message); IConsolePrintF(colour, "%s", message); NetworkAddChatMessage((TextColour)colour, _settings_client.gui.network_chat_timeout, "%s", message); } /* Calculate the frame-lag of a client */ uint NetworkCalculateLag(const NetworkClientSocket *cs) { int lag = cs->last_frame_server - cs->last_frame; /* This client has missed his ACK packet after 1 DAY_TICKS.. * so we increase his lag for every frame that passes! * The packet can be out by a max of _net_frame_freq */ if (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq < _frame_counter) { lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _settings_client.network.frame_freq); } return lag; } /* There was a non-recoverable error, drop back to the main menu with a nice * error */ void NetworkError(StringID error_string) { _switch_mode = SM_MENU; ShowErrorMessage(error_string, INVALID_STRING_ID, WL_CRITICAL); } /** * Retrieve the string id of an internal error number * @param err NetworkErrorCode * @return the StringID */ StringID GetNetworkErrorMsg(NetworkErrorCode err) { /* List of possible network errors, used by * PACKET_SERVER_ERROR and PACKET_CLIENT_ERROR */ static const StringID network_error_strings[] = { STR_NETWORK_ERROR_CLIENT_GENERAL, STR_NETWORK_ERROR_CLIENT_DESYNC, STR_NETWORK_ERROR_CLIENT_SAVEGAME, STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST, STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR, STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH, STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED, STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED, STR_NETWORK_ERROR_CLIENT_WRONG_REVISION, STR_NETWORK_ERROR_CLIENT_NAME_IN_USE, STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD, STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH, STR_NETWORK_ERROR_CLIENT_KICKED, STR_NETWORK_ERROR_CLIENT_CHEATER, STR_NETWORK_ERROR_CLIENT_SERVER_FULL, STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS, STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD, STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER, STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP, STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN, }; assert_compile(lengthof(network_error_strings) == NETWORK_ERROR_END); if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL; return network_error_strings[err]; } /** * Handle the pause mode change so we send the right messages to the chat. * @param prev_mode The previous pause mode. * @param changed_mode The pause mode that got changed. */ void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode) { if (!_networking) return; switch (changed_mode) { case PM_PAUSED_NORMAL: case PM_PAUSED_JOIN: case PM_PAUSED_GAME_SCRIPT: case PM_PAUSED_ACTIVE_CLIENTS: { bool changed = ((_pause_mode == PM_UNPAUSED) != (prev_mode == PM_UNPAUSED)); bool paused = (_pause_mode != PM_UNPAUSED); if (!paused && !changed) return; StringID str; if (!changed) { int i = -1; if ((_pause_mode & PM_PAUSED_NORMAL) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL); if ((_pause_mode & PM_PAUSED_JOIN) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS); if ((_pause_mode & PM_PAUSED_GAME_SCRIPT) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT); if ((_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS); str = STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + i; } else { switch (changed_mode) { case PM_PAUSED_NORMAL: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL); break; case PM_PAUSED_JOIN: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS); break; case PM_PAUSED_GAME_SCRIPT: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT); break; case PM_PAUSED_ACTIVE_CLIENTS: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS); break; default: NOT_REACHED(); } str = paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED; } char buffer[DRAW_STRING_BUFFER]; GetString(buffer, str, lastof(buffer)); NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, CC_DEFAULT, false, NULL, buffer); break; } default: return; } } /** * Helper function for the pause checkers. If pause is true and the * current pause mode isn't set the game will be paused, if it it false * and the pause mode is set the game will be unpaused. In the other * cases nothing happens to the pause state. * @param pause whether we'd like to pause * @param pm the mode which we would like to pause with */ static void CheckPauseHelper(bool pause, PauseMode pm) { if (pause == ((_pause_mode & pm) != PM_UNPAUSED)) return; DoCommandP(0, pm, pause ? 1 : 0, CMD_PAUSE); } /** * Counts the number of active clients connected. * It has to be in STATUS_ACTIVE and not a spectator * @return number of active clients */ static uint NetworkCountActiveClients() { const NetworkClientSocket *cs; uint count = 0; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->status != NetworkClientSocket::STATUS_ACTIVE) continue; if (!Company::IsValidID(cs->GetInfo()->client_playas)) continue; count++; } return count; } /** * Check if the minimum number of active clients has been reached and pause or unpause the game as appropriate */ static void CheckMinActiveClients() { if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED || !_network_dedicated || (_settings_client.network.min_active_clients == 0 && (_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) == PM_UNPAUSED)) { return; } CheckPauseHelper(NetworkCountActiveClients() < _settings_client.network.min_active_clients, PM_PAUSED_ACTIVE_CLIENTS); } /** * Checks whether there is a joining client * @return true iff one client is joining (but not authorizing) */ static bool NetworkHasJoiningClient() { const NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->status >= NetworkClientSocket::STATUS_AUTHORIZED && cs->status < NetworkClientSocket::STATUS_ACTIVE) return true; } return false; } /** * Check whether we should pause on join */ static void CheckPauseOnJoin() { if ((_pause_mode & PM_PAUSED_ERROR) != PM_UNPAUSED || (!_settings_client.network.pause_on_join && (_pause_mode & PM_PAUSED_JOIN) == PM_UNPAUSED)) { return; } CheckPauseHelper(NetworkHasJoiningClient(), PM_PAUSED_JOIN); } /** * Converts a string to ip/port/company * Format: IP:port#company * * connection_string will be re-terminated to separate out the hostname, and company and port will * be set to the company and port strings given by the user, inside the memory area originally * occupied by connection_string. */ void ParseConnectionString(const char **company, const char **port, char *connection_string) { bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':')); char *p; for (p = connection_string; *p != '\0'; p++) { switch (*p) { case '[': ipv6 = true; break; case ']': ipv6 = false; break; case '#': *company = p + 1; *p = '\0'; break; case ':': if (ipv6) break; *port = p + 1; *p = '\0'; break; } } } /** * Handle the accepting of a connection to the server. * @param s The socket of the new connection. * @param address The address of the peer. */ /* static */ void ServerNetworkGameSocketHandler::AcceptConnection(SOCKET s, const NetworkAddress &address) { /* Register the login */ _network_clients_connected++; SetWindowDirty(WC_CLIENT_LIST, 0); ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s); cs->client_address = address; // Save the IP of the client } /** * Resets the pools used for network clients, and the admin pool if needed. * @param close_admins Whether the admin pool has to be cleared as well. */ static void InitializeNetworkPools(bool close_admins = true) { PoolBase::Clean(PT_NCLIENT | (close_admins ? PT_NADMIN : PT_NONE)); } /** * Close current connections. * @param close_admins Whether the admin connections have to be closed as well. */ void NetworkClose(bool close_admins) { if (_network_server) { if (close_admins) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ADMIN_SOCKETS(as) { as->CloseConnection(true); } } NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { cs->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } ServerNetworkGameSocketHandler::CloseListeners(); ServerNetworkAdminSocketHandler::CloseListeners(); } else if (MyClient::my_client != NULL) { MyClient::SendQuit(); MyClient::my_client->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } TCPConnecter::KillAll(); _networking = false; _network_server = false; NetworkFreeLocalCommandQueue(); free(_network_company_states); _network_company_states = NULL; InitializeNetworkPools(close_admins); } /* Initializes the network (cleans sockets and stuff) */ static void NetworkInitialize(bool close_admins = true) { InitializeNetworkPools(close_admins); NetworkUDPInitialize(); _sync_frame = 0; _network_first_time = true; _network_reconnect = 0; } /** Non blocking connection create to query servers */ class TCPQueryConnecter : TCPConnecter { public: TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {} virtual void OnFailure() { NetworkDisconnect(); } virtual void OnConnect(SOCKET s) { _networking = true; new ClientNetworkGameSocketHandler(s); MyClient::SendCompanyInformationQuery(); } }; /* Query a server to fetch his game-info * If game_info is true, only the gameinfo is fetched, * else only the client_info is fetched */ void NetworkTCPQueryServer(NetworkAddress address) { if (!_network_available) return; NetworkDisconnect(); NetworkInitialize(); new TCPQueryConnecter(address); } /* Validates an address entered as a string and adds the server to * the list. If you use this function, the games will be marked * as manually added. */ void NetworkAddServer(const char *b) { if (*b != '\0') { const char *port = NULL; const char *company = NULL; char host[NETWORK_HOSTNAME_LENGTH]; uint16 rport; strecpy(host, b, lastof(host)); strecpy(_settings_client.network.connect_to_ip, b, lastof(_settings_client.network.connect_to_ip)); rport = NETWORK_DEFAULT_PORT; ParseConnectionString(&company, &port, host); if (port != NULL) rport = atoi(port); NetworkUDPQueryServer(NetworkAddress(host, rport), true); } } /** * Get the addresses to bind to. * @param addresses the list to write to. * @param port the port to bind to. */ void GetBindAddresses(NetworkAddressList *addresses, uint16 port) { for (char **iter = _network_bind_list.Begin(); iter != _network_bind_list.End(); iter++) { *addresses->Append() = NetworkAddress(*iter, port); } /* No address, so bind to everything. */ if (addresses->Length() == 0) { *addresses->Append() = NetworkAddress("", port); } } /* Generates the list of manually added hosts from NetworkGameList and * dumps them into the array _network_host_list. This array is needed * by the function that generates the config file. */ void NetworkRebuildHostList() { _network_host_list.Clear(); for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { if (item->manually) *_network_host_list.Append() = stredup(item->address.GetAddressAsString(false)); } } /** Non blocking connection create to actually connect to servers */ class TCPClientConnecter : TCPConnecter { public: TCPClientConnecter(const NetworkAddress &address) : TCPConnecter(address) {} virtual void OnFailure() { NetworkError(STR_NETWORK_ERROR_NOCONNECTION); } virtual void OnConnect(SOCKET s) { _networking = true; new ClientNetworkGameSocketHandler(s); IConsoleCmdExec("exec scripts/on_client.scr 0"); NetworkClient_Connected(); } }; /* Used by clients, to connect to a server */ void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password, const char *join_company_password) { if (!_network_available) return; if (address.GetPort() == 0) return; strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host)); _settings_client.network.last_port = address.GetPort(); _network_join_as = join_as; _network_join_server_password = join_server_password; _network_join_company_password = join_company_password; NetworkDisconnect(); NetworkInitialize(); _network_join_status = NETWORK_JOIN_STATUS_CONNECTING; ShowJoinStatusWindow(); new TCPClientConnecter(address); } static void NetworkInitGameInfo() { if (StrEmpty(_settings_client.network.server_name)) { seprintf(_settings_client.network.server_name, lastof(_settings_client.network.server_name), "Unnamed Server"); } /* The server is a client too */ _network_game_info.clients_on = _network_dedicated ? 0 : 1; /* There should be always space for the server. */ assert(NetworkClientInfo::CanAllocateItem()); NetworkClientInfo *ci = new NetworkClientInfo(CLIENT_ID_SERVER); ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : COMPANY_FIRST; strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name)); } bool NetworkServerStart() { if (!_network_available) return false; /* Call the pre-scripts */ IConsoleCmdExec("exec scripts/pre_server.scr 0"); if (_network_dedicated) IConsoleCmdExec("exec scripts/pre_dedicated.scr 0"); NetworkDisconnect(false, false); NetworkInitialize(false); DEBUG(net, 1, "starting listeners for clients"); if (!ServerNetworkGameSocketHandler::Listen(_settings_client.network.server_port)) return false; /* Only listen for admins when the password isn't empty. */ if (!StrEmpty(_settings_client.network.admin_password)) { DEBUG(net, 1, "starting listeners for admins"); if (!ServerNetworkAdminSocketHandler::Listen(_settings_client.network.server_admin_port)) return false; } /* Try to start UDP-server */ DEBUG(net, 1, "starting listeners for incoming server queries"); _network_udp_server = _udp_server_socket->Listen(); _network_company_states = CallocT(MAX_COMPANIES); _network_server = true; _networking = true; _frame_counter = 0; _frame_counter_server = 0; _frame_counter_max = 0; _last_sync_frame = 0; _network_own_client_id = CLIENT_ID_SERVER; _network_clients_connected = 0; _network_company_passworded = 0; NetworkInitGameInfo(); /* execute server initialization script */ IConsoleCmdExec("exec scripts/on_server.scr 0"); /* if the server is dedicated ... add some other script */ if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0"); /* Try to register us to the master server */ _network_need_advertise = true; NetworkUDPAdvertise(); /* welcome possibly still connected admins - this can only happen on a dedicated server. */ if (_network_dedicated) ServerNetworkAdminSocketHandler::WelcomeAll(); return true; } /* The server is rebooting... * The only difference with NetworkDisconnect, is the packets that is sent */ void NetworkReboot() { if (_network_server) { NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { cs->SendNewGame(); cs->SendPackets(); } ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { as->SendNewGame(); as->SendPackets(); } } /* For non-dedicated servers we have to kick the admins as we are not * certain that we will end up in a new network game. */ NetworkClose(!_network_dedicated); } /** * We want to disconnect from the host/clients. * @param blocking whether to wait till everything has been closed. * @param close_admins Whether the admin sockets need to be closed as well. */ void NetworkDisconnect(bool blocking, bool close_admins) { if (_network_server) { NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { cs->SendShutdown(); cs->SendPackets(); } if (close_admins) { ServerNetworkAdminSocketHandler *as; FOR_ALL_ACTIVE_ADMIN_SOCKETS(as) { as->SendShutdown(); as->SendPackets(); } } } if (_settings_client.network.server_advertise) NetworkUDPRemoveAdvertise(blocking); DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); NetworkClose(close_admins); /* Reinitialize the UDP stack, i.e. close all existing connections. */ NetworkUDPInitialize(); } /** * Receives something from the network. * @return true if everything went fine, false when the connection got closed. */ static bool NetworkReceive() { if (_network_server) { ServerNetworkAdminSocketHandler::Receive(); return ServerNetworkGameSocketHandler::Receive(); } else { return ClientNetworkGameSocketHandler::Receive(); } } /* This sends all buffered commands (if possible) */ static void NetworkSend() { if (_network_server) { ServerNetworkAdminSocketHandler::Send(); ServerNetworkGameSocketHandler::Send(); } else { ClientNetworkGameSocketHandler::Send(); } } /** * We have to do some (simple) background stuff that runs normally, * even when we are not in multiplayer. For example stuff needed * for finding servers or downloading content. */ void NetworkBackgroundLoop() { _network_content_client.SendReceive(); TCPConnecter::CheckCallbacks(); NetworkHTTPSocketHandler::HTTPReceive(); NetworkBackgroundUDPLoop(); } /* The main loop called from ttd.c * Here we also have to do StateGameLoop if needed! */ void NetworkGameLoop() { if (!_networking) return; if (!NetworkReceive()) return; if (_network_server) { /* Log the sync state to check for in-syncedness of replays. */ if (_date_fract == 0) { /* We don't want to log multiple times if paused. */ static Date last_log; if (last_log != _date) { DEBUG(desync, 1, "sync: %08x; %02x; %08x; %08x", _date, _date_fract, _random.state[0], _random.state[1]); last_log = _date; } } #ifdef DEBUG_DUMP_COMMANDS /* Loading of the debug commands from -ddesync>=1 */ static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR); static Date next_date = 0; static uint32 next_date_fract; static CommandPacket *cp = NULL; static bool check_sync_state = false; static uint32 sync_state[2]; if (f == NULL && next_date == 0) { DEBUG(net, 0, "Cannot open commands.log"); next_date = 1; } while (f != NULL && !feof(f)) { if (_date == next_date && _date_fract == next_date_fract) { if (cp != NULL) { NetworkSendCommand(cp->tile, cp->p1, cp->p2, cp->cmd & ~CMD_FLAGS_MASK, NULL, cp->text, cp->company); DEBUG(net, 0, "injecting: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, cp->tile, cp->p1, cp->p2, cp->cmd, cp->text, GetCommandName(cp->cmd)); free(cp); cp = NULL; } if (check_sync_state) { if (sync_state[0] == _random.state[0] && sync_state[1] == _random.state[1]) { DEBUG(net, 0, "sync check: %08x; %02x; match", _date, _date_fract); } else { DEBUG(net, 0, "sync check: %08x; %02x; mismatch expected {%08x, %08x}, got {%08x, %08x}", _date, _date_fract, sync_state[0], sync_state[1], _random.state[0], _random.state[1]); NOT_REACHED(); } check_sync_state = false; } } if (cp != NULL || check_sync_state) break; char buff[4096]; if (fgets(buff, lengthof(buff), f) == NULL) break; char *p = buff; /* Ignore the "[date time] " part of the message */ if (*p == '[') { p = strchr(p, ']'); if (p == NULL) break; p += 2; } if (strncmp(p, "cmd: ", 5) == 0 #ifdef DEBUG_FAILED_DUMP_COMMANDS || strncmp(p, "cmdf: ", 6) == 0 #endif ) { p += 5; if (*p == ' ') p++; cp = CallocT(1); int company; int ret = sscanf(p, "%x; %x; %x; %x; %x; %x; %x; \"%[^\"]\"", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text); /* There are 8 pieces of data to read, however the last is a * string that might or might not exist. Ignore it if that * string misses because in 99% of the time it's not used. */ assert(ret == 8 || ret == 7); cp->company = (CompanyID)company; } else if (strncmp(p, "join: ", 6) == 0) { /* Manually insert a pause when joining; this way the client can join at the exact right time. */ int ret = sscanf(p + 6, "%x; %x", &next_date, &next_date_fract); assert(ret == 2); DEBUG(net, 0, "injecting pause for join at %08x:%02x; please join when paused", next_date, next_date_fract); cp = CallocT(1); cp->company = COMPANY_SPECTATOR; cp->cmd = CMD_PAUSE; cp->p1 = PM_PAUSED_NORMAL; cp->p2 = 1; _ddc_fastforward = false; } else if (strncmp(p, "sync: ", 6) == 0) { int ret = sscanf(p + 6, "%x; %x; %x; %x", &next_date, &next_date_fract, &sync_state[0], &sync_state[1]); assert(ret == 4); check_sync_state = true; } else if (strncmp(p, "msg: ", 5) == 0 || strncmp(p, "client: ", 8) == 0 || strncmp(p, "load: ", 6) == 0 || strncmp(p, "save: ", 6) == 0) { /* A message that is not very important to the log playback, but part of the log. */ #ifndef DEBUG_FAILED_DUMP_COMMANDS } else if (strncmp(p, "cmdf: ", 6) == 0) { DEBUG(net, 0, "Skipping replay of failed command: %s", p + 6); #endif } else { /* Can't parse a line; what's wrong here? */ DEBUG(net, 0, "trying to parse: %s", p); NOT_REACHED(); } } if (f != NULL && feof(f)) { DEBUG(net, 0, "End of commands.log"); fclose(f); f = NULL; } #endif /* DEBUG_DUMP_COMMANDS */ if (_frame_counter >= _frame_counter_max) { /* Only check for active clients just before we're going to send out * the commands so we don't send multiple pause/unpause commands when * the frame_freq is more than 1 tick. Same with distributing commands. */ CheckPauseOnJoin(); CheckMinActiveClients(); NetworkDistributeCommands(); } bool send_frame = false; /* We first increase the _frame_counter */ _frame_counter++; /* Update max-frame-counter */ if (_frame_counter > _frame_counter_max) { _frame_counter_max = _frame_counter + _settings_client.network.frame_freq; send_frame = true; } NetworkExecuteLocalCommandQueue(); /* Then we make the frame */ StateGameLoop(); _sync_seed_1 = _random.state[0]; #ifdef NETWORK_SEND_DOUBLE_SEED _sync_seed_2 = _random.state[1]; #endif NetworkServer_Tick(send_frame); } else { /* Client */ /* Make sure we are at the frame were the server is (quick-frames) */ if (_frame_counter_server > _frame_counter) { /* Run a number of frames; when things go bad, get out. */ while (_frame_counter_server > _frame_counter) { if (!ClientNetworkGameSocketHandler::GameLoop()) return; } } else { /* Else, keep on going till _frame_counter_max */ if (_frame_counter_max > _frame_counter) { /* Run one frame; if things went bad, get out. */ if (!ClientNetworkGameSocketHandler::GameLoop()) return; } } } NetworkSend(); } static void NetworkGenerateServerId() { Md5 checksum; uint8 digest[16]; char hex_output[16 * 2 + 1]; char coding_string[NETWORK_NAME_LENGTH]; int di; seprintf(coding_string, lastof(coding_string), "%d%s", (uint)Random(), "OpenTTD Server ID"); /* Generate the MD5 hash */ checksum.Append((const uint8*)coding_string, strlen(coding_string)); checksum.Finish(digest); for (di = 0; di < 16; ++di) { seprintf(hex_output + di * 2, lastof(hex_output), "%02x", digest[di]); } /* _settings_client.network.network_id is our id */ seprintf(_settings_client.network.network_id, lastof(_settings_client.network.network_id), "%s", hex_output); } void NetworkStartDebugLog(NetworkAddress address) { extern SOCKET _debug_socket; // Comes from debug.c DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort()); SOCKET s = address.Connect(); if (s == INVALID_SOCKET) { DEBUG(net, 0, "Failed to open socket for redirection DEBUG()"); return; } _debug_socket = s; DEBUG(net, 0, "DEBUG() is now redirected"); } /** This tries to launch the network for a given OS */ void NetworkStartUp() { DEBUG(net, 3, "[core] starting network..."); /* Network is available */ _network_available = NetworkCoreInitialize(); _network_dedicated = false; _network_need_advertise = true; _network_advertise_retries = 0; /* Generate an server id when there is none yet */ if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateServerId(); memset(&_network_game_info, 0, sizeof(_network_game_info)); NetworkInitialize(); DEBUG(net, 3, "[core] network online, multiplayer available"); NetworkFindBroadcastIPs(&_broadcast_list); } /** This shuts the network down */ void NetworkShutDown() { NetworkDisconnect(true); NetworkUDPClose(); DEBUG(net, 3, "[core] shutting down network"); _network_available = false; NetworkCoreShutdown(); } /** * Checks whether the given version string is compatible with our version. * @param other the version string to compare to */ bool IsNetworkCompatibleVersion(const char *other) { return strncmp(_openttd_revision, other, NETWORK_REVISION_LENGTH - 1) == 0; } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_content_gui.h0000644000000000000000000000345612627373441020434 0ustar rootroot/* $Id: network_content_gui.h 25287 2013-05-26 19:23:42Z frosch $ */ /* * 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 network_content_gui.h User interface for downloading files. */ #ifndef NETWORK_CONTENT_GUI_H #define NETWORK_CONTENT_GUI_H #include "network_content.h" #include "../window_gui.h" #include "../widgets/network_content_widget.h" /** Base window for showing the download status of content */ class BaseNetworkContentDownloadStatusWindow : public Window, ContentCallback { protected: uint total_bytes; ///< Number of bytes to download uint downloaded_bytes; ///< Number of bytes downloaded uint total_files; ///< Number of files to download uint downloaded_files; ///< Number of files downloaded uint32 cur_id; ///< The current ID of the downloaded file char name[48]; ///< The current name of the downloaded file public: /** * Create the window with the given description. * @param desc The description of the window. */ BaseNetworkContentDownloadStatusWindow(WindowDesc *desc); /** * Free everything associated with this window. */ ~BaseNetworkContentDownloadStatusWindow(); virtual void DrawWidget(const Rect &r, int widget) const; virtual void OnDownloadProgress(const ContentInfo *ci, int bytes); }; #endif /* NETWORK_CONTENT_GUI_H */ openttd-1.5.3/src/network/network_type.h0000644000000000000000000001030412627373441017065 0ustar rootroot/* $Id: network_type.h 23780 2012-01-09 21:22:48Z truebrain $ */ /* * 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 network_type.h Types used for networking. */ #ifndef NETWORK_TYPE_H #define NETWORK_TYPE_H #include "core/game.h" #ifdef ENABLE_NETWORK /** How many clients can we have */ static const uint MAX_CLIENTS = 255; /** * The number of slots; must be at least 1 more than MAX_CLIENTS. It must * furthermore be less than or equal to 256 as client indices (sent over * the network) are 8 bits. It needs 1 more for the dedicated server. */ static const uint MAX_CLIENT_SLOTS = 256; /** * Vehicletypes in the order they are send in info packets. */ enum NetworkVehicleType { NETWORK_VEH_TRAIN = 0, NETWORK_VEH_LORRY, NETWORK_VEH_BUS, NETWORK_VEH_PLANE, NETWORK_VEH_SHIP, NETWORK_VEH_END }; /** 'Unique' identifier to be given to clients */ enum ClientID { INVALID_CLIENT_ID = 0, ///< Client is not part of anything CLIENT_ID_SERVER = 1, ///< Servers always have this ID CLIENT_ID_FIRST = 2, ///< The first client ID }; /** Indices into the client tables */ typedef uint8 ClientIndex; /** Indices into the admin tables. */ typedef uint8 AdminIndex; /** Maximum number of allowed admins. */ static const AdminIndex MAX_ADMINS = 16; /** An invalid admin marker. */ static const AdminIndex INVALID_ADMIN_ID = UINT8_MAX; /** Simple calculated statistics of a company */ struct NetworkCompanyStats { uint16 num_vehicle[NETWORK_VEH_END]; ///< How many vehicles are there of this type? uint16 num_station[NETWORK_VEH_END]; ///< How many stations are there of this type? bool ai; ///< Is this company an AI }; /** Some state information of a company, especially for servers */ struct NetworkCompanyState { char password[NETWORK_PASSWORD_LENGTH]; ///< The password for the company uint16 months_empty; ///< How many months the company is empty }; struct NetworkClientInfo; /** The type of password we're asking for. */ enum NetworkPasswordType { NETWORK_GAME_PASSWORD, ///< The password of the game. NETWORK_COMPANY_PASSWORD, ///< The password of the company. }; /** Destination of our chat messages. */ enum DestType { DESTTYPE_BROADCAST, ///< Send message/notice to all clients (All) DESTTYPE_TEAM, ///< Send message/notice to everyone playing the same company (Team) DESTTYPE_CLIENT, ///< Send message/notice to only a certain client (Private) }; /** Actions that can be used for NetworkTextMessage */ enum NetworkAction { NETWORK_ACTION_JOIN, NETWORK_ACTION_LEAVE, NETWORK_ACTION_SERVER_MESSAGE, NETWORK_ACTION_CHAT, NETWORK_ACTION_CHAT_COMPANY, NETWORK_ACTION_CHAT_CLIENT, NETWORK_ACTION_GIVE_MONEY, NETWORK_ACTION_NAME_CHANGE, NETWORK_ACTION_COMPANY_SPECTATOR, NETWORK_ACTION_COMPANY_JOIN, NETWORK_ACTION_COMPANY_NEW, }; /** The error codes we send around in the protocols. */ enum NetworkErrorCode { NETWORK_ERROR_GENERAL, // Try to use this one like never /* Signals from clients */ NETWORK_ERROR_DESYNC, NETWORK_ERROR_SAVEGAME_FAILED, NETWORK_ERROR_CONNECTION_LOST, NETWORK_ERROR_ILLEGAL_PACKET, NETWORK_ERROR_NEWGRF_MISMATCH, /* Signals from servers */ NETWORK_ERROR_NOT_AUTHORIZED, NETWORK_ERROR_NOT_EXPECTED, NETWORK_ERROR_WRONG_REVISION, NETWORK_ERROR_NAME_IN_USE, NETWORK_ERROR_WRONG_PASSWORD, NETWORK_ERROR_COMPANY_MISMATCH, // Happens in CLIENT_COMMAND NETWORK_ERROR_KICKED, NETWORK_ERROR_CHEATER, NETWORK_ERROR_FULL, NETWORK_ERROR_TOO_MANY_COMMANDS, NETWORK_ERROR_TIMEOUT_PASSWORD, NETWORK_ERROR_TIMEOUT_COMPUTER, NETWORK_ERROR_TIMEOUT_MAP, NETWORK_ERROR_TIMEOUT_JOIN, NETWORK_ERROR_END, }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_TYPE_H */ openttd-1.5.3/src/network/network_command.cpp0000644000000000000000000002456112627373441020067 0ustar rootroot/* $Id: network_command.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 network_command.cpp Command handling over network connections. */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "network_admin.h" #include "network_client.h" #include "network_server.h" #include "../command_func.h" #include "../company_func.h" #include "../settings_type.h" #include "../safeguards.h" /** Table with all the callbacks we'll use for conversion*/ static CommandCallback * const _callback_table[] = { /* 0x00 */ NULL, /* 0x01 */ CcBuildPrimaryVehicle, /* 0x02 */ CcBuildAirport, /* 0x03 */ CcBuildBridge, /* 0x04 */ CcBuildCanal, /* 0x05 */ CcBuildDocks, /* 0x06 */ CcFoundTown, /* 0x07 */ CcBuildRoadTunnel, /* 0x08 */ CcBuildRailTunnel, /* 0x09 */ CcBuildWagon, /* 0x0A */ CcRoadDepot, /* 0x0B */ CcRailDepot, /* 0x0C */ CcPlaceSign, /* 0x0D */ CcPlaySound10, /* 0x0E */ CcPlaySound1D, /* 0x0F */ CcPlaySound1E, /* 0x10 */ CcStation, /* 0x11 */ CcTerraform, /* 0x12 */ CcAI, /* 0x13 */ CcCloneVehicle, /* 0x14 */ CcGiveMoney, /* 0x15 */ CcCreateGroup, /* 0x16 */ CcFoundRandomTown, /* 0x17 */ CcRoadStop, /* 0x18 */ CcBuildIndustry, /* 0x19 */ CcStartStopVehicle, /* 0x1A */ CcGame, /* 0x1B */ CcAddVehicleNewGroup, }; /** * Append a CommandPacket at the end of the queue. * @param p The packet to append to the queue. * @note A new instance of the CommandPacket will be made. */ void CommandQueue::Append(CommandPacket *p) { CommandPacket *add = MallocT(1); *add = *p; add->next = NULL; if (this->first == NULL) { this->first = add; } else { this->last->next = add; } this->last = add; this->count++; } /** * Return the first item in the queue and remove it from the queue. * @param ignore_paused Whether to ignore commands that may not be executed while paused. * @return the first item in the queue. */ CommandPacket *CommandQueue::Pop(bool ignore_paused) { CommandPacket **prev = &this->first; CommandPacket *ret = this->first; CommandPacket *prev_item = NULL; if (ignore_paused && _pause_mode != PM_UNPAUSED) { while (ret != NULL && !IsCommandAllowedWhilePaused(ret->cmd)) { prev_item = ret; prev = &ret->next; ret = ret->next; } } if (ret != NULL) { if (ret == this->last) this->last = prev_item; *prev = ret->next; this->count--; } return ret; } /** * Return the first item in the queue, but don't remove it. * @param ignore_paused Whether to ignore commands that may not be executed while paused. * @return the first item in the queue. */ CommandPacket *CommandQueue::Peek(bool ignore_paused) { if (!ignore_paused || _pause_mode == PM_UNPAUSED) return this->first; for (CommandPacket *p = this->first; p != NULL; p = p->next) { if (IsCommandAllowedWhilePaused(p->cmd)) return p; } return NULL; } /** Free everything that is in the queue. */ void CommandQueue::Free() { CommandPacket *cp; while ((cp = this->Pop()) != NULL) { free(cp); } assert(this->count == 0); } /** Local queue of packets waiting for handling. */ static CommandQueue _local_wait_queue; /** Local queue of packets waiting for execution. */ static CommandQueue _local_execution_queue; /** * Prepare a DoCommand to be send over the network * @param tile The tile to perform a command on (see #CommandProc) * @param p1 Additional data for the command (see #CommandProc) * @param p2 Additional data for the command (see #CommandProc) * @param cmd The command to execute (a CMD_* value) * @param callback A callback function to call after the command is finished * @param text The text to pass * @param company The company that wants to send the command */ void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, CompanyID company) { assert((cmd & CMD_FLAGS_MASK) == 0); CommandPacket c; c.company = company; c.tile = tile; c.p1 = p1; c.p2 = p2; c.cmd = cmd; c.callback = callback; strecpy(c.text, (text != NULL) ? text : "", lastof(c.text)); if (_network_server) { /* If we are the server, we queue the command in our 'special' queue. * In theory, we could execute the command right away, but then the * client on the server can do everything 1 tick faster than others. * So to keep the game fair, we delay the command with 1 tick * which gives about the same speed as most clients. */ c.frame = _frame_counter_max + 1; c.my_cmd = true; _local_wait_queue.Append(&c); return; } c.frame = 0; // The client can't tell which frame, so just make it 0 /* Clients send their command to the server and forget all about the packet */ MyClient::SendCommand(&c); } /** * Sync our local command queue to the command queue of the given * socket. This is needed for the case where we receive a command * before saving the game for a joining client, but without the * execution of those commands. Not syncing those commands means * that the client will never get them and as such will be in a * desynced state from the time it started with joining. * @param cs The client to sync the queue to. */ void NetworkSyncCommandQueue(NetworkClientSocket *cs) { for (CommandPacket *p = _local_execution_queue.Peek(); p != NULL; p = p->next) { CommandPacket c = *p; c.callback = 0; cs->outgoing_queue.Append(&c); } } /** * Execute all commands on the local command queue that ought to be executed this frame. */ void NetworkExecuteLocalCommandQueue() { assert(IsLocalCompany()); CommandQueue &queue = (_network_server ? _local_execution_queue : ClientNetworkGameSocketHandler::my_client->incoming_queue); CommandPacket *cp; while ((cp = queue.Peek()) != NULL) { /* The queue is always in order, which means * that the first element will be executed first. */ if (_frame_counter < cp->frame) break; if (_frame_counter > cp->frame) { /* If we reach here, it means for whatever reason, we've already executed * past the command we need to execute. */ error("[net] Trying to execute a packet in the past!"); } /* We can execute this command */ _current_company = cp->company; cp->cmd |= CMD_NETWORK_COMMAND; DoCommandP(cp, cp->my_cmd); queue.Pop(); free(cp); } /* Local company may have changed, so we should not restore the old value */ _current_company = _local_company; } /** * Free the local command queues. */ void NetworkFreeLocalCommandQueue() { _local_wait_queue.Free(); _local_execution_queue.Free(); } /** * "Send" a particular CommandPacket to all clients. * @param cp The command that has to be distributed. * @param owner The client that owns the command, */ static void DistributeCommandPacket(CommandPacket &cp, const NetworkClientSocket *owner) { CommandCallback *callback = cp.callback; cp.frame = _frame_counter_max + 1; NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { if (cs->status >= NetworkClientSocket::STATUS_MAP) { /* Callbacks are only send back to the client who sent them in the * first place. This filters that out. */ cp.callback = (cs != owner) ? NULL : callback; cp.my_cmd = (cs == owner); cs->outgoing_queue.Append(&cp); } } cp.callback = (cs != owner) ? NULL : callback; cp.my_cmd = (cs == owner); _local_execution_queue.Append(&cp); } /** * "Send" a particular CommandQueue to all clients. * @param queue The queue of commands that has to be distributed. * @param owner The client that owns the commands, */ static void DistributeQueue(CommandQueue *queue, const NetworkClientSocket *owner) { #ifdef DEBUG_DUMP_COMMANDS /* When replaying we do not want this limitation. */ int to_go = UINT16_MAX; #else int to_go = _settings_client.network.commands_per_frame; #endif CommandPacket *cp; while (--to_go >= 0 && (cp = queue->Pop(true)) != NULL) { DistributeCommandPacket(*cp, owner); NetworkAdminCmdLogging(owner, cp); free(cp); } } /** Distribute the commands of ourself and the clients. */ void NetworkDistributeCommands() { /* First send the server's commands. */ DistributeQueue(&_local_wait_queue, NULL); /* Then send the queues of the others. */ NetworkClientSocket *cs; FOR_ALL_CLIENT_SOCKETS(cs) { DistributeQueue(&cs->incoming_queue, cs); } } /** * Receives a command from the network. * @param p the packet to read from. * @param cp the struct to write the data to. * @return an error message. When NULL there has been no error. */ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *cp) { cp->company = (CompanyID)p->Recv_uint8(); cp->cmd = p->Recv_uint32(); if (!IsValidCommand(cp->cmd)) return "invalid command"; if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "offline only command"; if ((cp->cmd & CMD_FLAGS_MASK) != 0) return "invalid command flag"; cp->p1 = p->Recv_uint32(); cp->p2 = p->Recv_uint32(); cp->tile = p->Recv_uint32(); p->Recv_string(cp->text, lengthof(cp->text), (!_network_server && GetCommandFlags(cp->cmd) & CMD_STR_CTRL) != 0 ? SVS_ALLOW_CONTROL_CODE | SVS_REPLACE_WITH_QUESTION_MARK : SVS_REPLACE_WITH_QUESTION_MARK); byte callback = p->Recv_uint8(); if (callback >= lengthof(_callback_table)) return "invalid callback"; cp->callback = _callback_table[callback]; return NULL; } /** * Sends a command over the network. * @param p the packet to send it in. * @param cp the packet to actually send. */ void NetworkGameSocketHandler::SendCommand(Packet *p, const CommandPacket *cp) { p->Send_uint8 (cp->company); p->Send_uint32(cp->cmd); p->Send_uint32(cp->p1); p->Send_uint32(cp->p2); p->Send_uint32(cp->tile); p->Send_string(cp->text); byte callback = 0; while (callback < lengthof(_callback_table) && _callback_table[callback] != cp->callback) { callback++; } if (callback == lengthof(_callback_table)) { DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", cp->callback); callback = 0; // _callback_table[0] == NULL } p->Send_uint8 (callback); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_client.cpp0000644000000000000000000012405112627373441017722 0ustar rootroot/* $Id: network_client.cpp 27020 2014-10-15 18:31:37Z rubidium $ */ /* * 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 network_client.cpp Client part of the network protocol. */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "network_gui.h" #include "../saveload/saveload.h" #include "../saveload/saveload_filter.h" #include "../command_func.h" #include "../console_func.h" #include "../strings_func.h" #include "../window_func.h" #include "../company_func.h" #include "../company_base.h" #include "../company_gui.h" #include "../core/random_func.hpp" #include "../date_func.h" #include "../gfx_func.h" #include "../error.h" #include "../rev.h" #include "network.h" #include "network_base.h" #include "network_client.h" #include "../core/backup_type.hpp" #include "table/strings.h" #include "../safeguards.h" /* This file handles all the client-commands */ /** Read some packets, and when do use that data as initial load filter. */ struct PacketReader : LoadFilter { static const size_t CHUNK = 32 * 1024; ///< 32 KiB chunks of memory. AutoFreeSmallVector blocks; ///< Buffer with blocks of allocated memory. byte *buf; ///< Buffer we're going to write to/read from. byte *bufe; ///< End of the buffer we write to/read from. byte **block; ///< The block we're reading from/writing to. size_t written_bytes; ///< The total number of bytes we've written. size_t read_bytes; ///< The total number of read bytes. /** Initialise everything. */ PacketReader() : LoadFilter(NULL), buf(NULL), bufe(NULL), block(NULL), written_bytes(0), read_bytes(0) { } /** * Add a packet to this buffer. * @param p The packet to add. */ void AddPacket(const Packet *p) { assert(this->read_bytes == 0); size_t in_packet = p->size - p->pos; size_t to_write = min((size_t)(this->bufe - this->buf), in_packet); const byte *pbuf = p->buffer + p->pos; this->written_bytes += in_packet; if (to_write != 0) { memcpy(this->buf, pbuf, to_write); this->buf += to_write; } /* Did everything fit in the current chunk, then we're done. */ if (to_write == in_packet) return; /* Allocate a new chunk and add the remaining data. */ pbuf += to_write; to_write = in_packet - to_write; this->buf = *this->blocks.Append() = CallocT(CHUNK); this->bufe = this->buf + CHUNK; memcpy(this->buf, pbuf, to_write); this->buf += to_write; } /* virtual */ size_t Read(byte *rbuf, size_t size) { /* Limit the amount to read to whatever we still have. */ size_t ret_size = size = min(this->written_bytes - this->read_bytes, size); this->read_bytes += ret_size; const byte *rbufe = rbuf + ret_size; while (rbuf != rbufe) { if (this->buf == this->bufe) { this->buf = *this->block++; this->bufe = this->buf + CHUNK; } size_t to_write = min(this->bufe - this->buf, rbufe - rbuf); memcpy(rbuf, this->buf, to_write); rbuf += to_write; this->buf += to_write; } return ret_size; } /* virtual */ void Reset() { this->read_bytes = 0; this->block = this->blocks.Begin(); this->buf = *this->block++; this->bufe = this->buf + CHUNK; } }; /** * Create a new socket for the client side of the game connection. * @param s The socket to connect with. */ ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s), savegame(NULL), status(STATUS_INACTIVE) { assert(ClientNetworkGameSocketHandler::my_client == NULL); ClientNetworkGameSocketHandler::my_client = this; } /** Clear whatever we assigned. */ ClientNetworkGameSocketHandler::~ClientNetworkGameSocketHandler() { assert(ClientNetworkGameSocketHandler::my_client == this); ClientNetworkGameSocketHandler::my_client = NULL; delete this->savegame; } NetworkRecvStatus ClientNetworkGameSocketHandler::CloseConnection(NetworkRecvStatus status) { assert(status != NETWORK_RECV_STATUS_OKAY); /* * Sending a message just before leaving the game calls cs->SendPackets. * This might invoke this function, which means that when we close the * connection after cs->SendPackets we will close an already closed * connection. This handles that case gracefully without having to make * that code any more complex or more aware of the validity of the socket. */ if (this->sock == INVALID_SOCKET) return status; DEBUG(net, 1, "Closed client connection %d", this->client_id); this->SendPackets(true); /* Wait a number of ticks so our leave message can reach the server. * This is especially needed for Windows servers as they seem to get * the "socket is closed" message before receiving our leave message, * which would trigger the server to close the connection as well. */ CSleep(3 * MILLISECONDS_PER_TICK); delete this->GetInfo(); delete this; return status; } /** * Handle an error coming from the client side. * @param res The "error" that happened. */ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) { /* First, send a CLIENT_ERROR to the server, so he knows we are * disconnection (and why!) */ NetworkErrorCode errorno; /* We just want to close the connection.. */ if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) { this->NetworkSocketHandler::CloseConnection(); this->CloseConnection(res); _networking = false; DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return; } switch (res) { case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break; default: errorno = NETWORK_ERROR_GENERAL; break; } /* This means we fucked up and the server closed the connection */ if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL && res != NETWORK_RECV_STATUS_SERVER_BANNED) { SendError(errorno); } _switch_mode = SM_MENU; this->CloseConnection(res); _networking = false; } /** * Check whether we received/can send some data from/to the server and * when that's the case handle it appropriately. * @return true when everything went okay. */ /* static */ bool ClientNetworkGameSocketHandler::Receive() { if (my_client->CanSendReceive()) { NetworkRecvStatus res = my_client->ReceivePackets(); if (res != NETWORK_RECV_STATUS_OKAY) { /* The client made an error of which we can not recover. * Close the connection and drop back to the main menu. */ my_client->ClientError(res); return false; } } return _networking; } /** Send the packets of this socket handler. */ /* static */ void ClientNetworkGameSocketHandler::Send() { my_client->SendPackets(); my_client->CheckConnection(); } /** * Actual game loop for the client. * @return Whether everything went okay, or not. */ /* static */ bool ClientNetworkGameSocketHandler::GameLoop() { _frame_counter++; NetworkExecuteLocalCommandQueue(); extern void StateGameLoop(); StateGameLoop(); /* Check if we are in sync! */ if (_sync_frame != 0) { if (_sync_frame == _frame_counter) { #ifdef NETWORK_SEND_DOUBLE_SEED if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) { #else if (_sync_seed_1 != _random.state[0]) { #endif NetworkError(STR_NETWORK_ERROR_DESYNC); DEBUG(desync, 1, "sync_err: %08x; %02x", _date, _date_fract); DEBUG(net, 0, "Sync error detected!"); my_client->ClientError(NETWORK_RECV_STATUS_DESYNC); return false; } /* If this is the first time we have a sync-frame, we * need to let the server know that we are ready and at the same * frame as he is.. so we can start playing! */ if (_network_first_time) { _network_first_time = false; SendAck(); } _sync_frame = 0; } else if (_sync_frame < _frame_counter) { DEBUG(net, 1, "Missed frame for sync-test (%d / %d)", _sync_frame, _frame_counter); _sync_frame = 0; } } return true; } /** Our client's connection. */ ClientNetworkGameSocketHandler * ClientNetworkGameSocketHandler::my_client = NULL; /** Last frame we performed an ack. */ static uint32 last_ack_frame; /** One bit of 'entropy' used to generate a salt for the company passwords. */ static uint32 _password_game_seed; /** The other bit of 'entropy' used to generate a salt for the company passwords. */ static char _password_server_id[NETWORK_SERVER_ID_LENGTH]; /** Maximum number of companies of the currently joined server. */ static uint8 _network_server_max_companies; /** Maximum number of spectators of the currently joined server. */ static uint8 _network_server_max_spectators; /** Who would we like to join as. */ CompanyID _network_join_as; /** Login password from -p argument */ const char *_network_join_server_password = NULL; /** Company password from -P argument */ const char *_network_join_company_password = NULL; /** Make sure the server ID length is the same as a md5 hash. */ assert_compile(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1); /*********** * Sending functions * DEF_CLIENT_SEND_COMMAND has no parameters ************/ /** Query the server for company information. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyInformationQuery() { my_client->status = STATUS_COMPANY_INFO; _network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO; SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); Packet *p = new Packet(PACKET_CLIENT_COMPANY_INFO); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the server we would like to join. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin() { my_client->status = STATUS_JOIN; _network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING; SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); Packet *p = new Packet(PACKET_CLIENT_JOIN); p->Send_string(_openttd_revision); p->Send_uint32(_openttd_newgrf_version); p->Send_string(_settings_client.network.client_name); // Client name p->Send_uint8 (_network_join_as); // PlayAs p->Send_uint8 (NETLANG_ANY); // Language my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the server we got all the NewGRFs. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendNewGRFsOk() { Packet *p = new Packet(PACKET_CLIENT_NEWGRFS_CHECKED); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Set the game password as requested. * @param password The game password. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGamePassword(const char *password) { Packet *p = new Packet(PACKET_CLIENT_GAME_PASSWORD); p->Send_string(password); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Set the company password as requested. * @param password The company password. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyPassword(const char *password) { Packet *p = new Packet(PACKET_CLIENT_COMPANY_PASSWORD); p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Request the map from the server. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendGetMap() { my_client->status = STATUS_MAP_WAIT; Packet *p = new Packet(PACKET_CLIENT_GETMAP); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Tell the server we received the complete map. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMapOk() { my_client->status = STATUS_ACTIVE; Packet *p = new Packet(PACKET_CLIENT_MAP_OK); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send an acknowledgement from the server's ticks. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendAck() { Packet *p = new Packet(PACKET_CLIENT_ACK); p->Send_uint32(_frame_counter); p->Send_uint8 (my_client->token); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send a command to the server. * @param cp The command to send. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendCommand(const CommandPacket *cp) { Packet *p = new Packet(PACKET_CLIENT_COMMAND); my_client->NetworkGameSocketHandler::SendCommand(p, cp); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send a chat-packet over the network */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data) { Packet *p = new Packet(PACKET_CLIENT_CHAT); p->Send_uint8 (action); p->Send_uint8 (type); p->Send_uint32(dest); p->Send_string(msg); p->Send_uint64(data); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** Send an error-packet over the network */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendError(NetworkErrorCode errorno) { Packet *p = new Packet(PACKET_CLIENT_ERROR); p->Send_uint8(errorno); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the server that we like to change the password of the company. * @param password The new password. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetPassword(const char *password) { Packet *p = new Packet(PACKET_CLIENT_SET_PASSWORD); p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the server that we like to change the name of the client. * @param name The new name. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendSetName(const char *name) { Packet *p = new Packet(PACKET_CLIENT_SET_NAME); p->Send_string(name); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Tell the server we would like to quit. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendQuit() { Packet *p = new Packet(PACKET_CLIENT_QUIT); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Send a console command. * @param pass The password for the remote command. * @param command The actual command. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendRCon(const char *pass, const char *command) { Packet *p = new Packet(PACKET_CLIENT_RCON); p->Send_string(pass); p->Send_string(command); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Ask the server to move us. * @param company The company to move to. * @param password The password of the company to move to. */ NetworkRecvStatus ClientNetworkGameSocketHandler::SendMove(CompanyID company, const char *password) { Packet *p = new Packet(PACKET_CLIENT_MOVE); p->Send_uint8(company); p->Send_string(GenerateCompanyPasswordHash(password, _password_server_id, _password_game_seed)); my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } /** * Check whether the client is actually connected (and in the game). * @return True when the client is connected. */ bool ClientNetworkGameSocketHandler::IsConnected() { return my_client != NULL && my_client->status == STATUS_ACTIVE; } /*********** * Receiving functions * DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p ************/ extern bool SafeLoad(const char *filename, int mode, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = NULL); NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p) { /* We try to join a server which is full */ ShowErrorMessage(STR_NETWORK_ERROR_SERVER_FULL, INVALID_STRING_ID, WL_CRITICAL); DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_SERVER_FULL; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *p) { /* We try to join a server where we are banned */ ShowErrorMessage(STR_NETWORK_ERROR_SERVER_BANNED, INVALID_STRING_ID, WL_CRITICAL); DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_SERVER_BANNED; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_INFO(Packet *p) { if (this->status != STATUS_COMPANY_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET; byte company_info_version = p->Recv_uint8(); if (!this->HasClientQuit() && company_info_version == NETWORK_COMPANY_INFO_VERSION) { /* We have received all data... (there are no more packets coming) */ if (!p->Recv_bool()) return NETWORK_RECV_STATUS_CLOSE_QUERY; CompanyID current = (Owner)p->Recv_uint8(); if (current >= MAX_COMPANIES) return NETWORK_RECV_STATUS_CLOSE_QUERY; NetworkCompanyInfo *company_info = GetLobbyCompanyInfo(current); if (company_info == NULL) return NETWORK_RECV_STATUS_CLOSE_QUERY; p->Recv_string(company_info->company_name, sizeof(company_info->company_name)); company_info->inaugurated_year = p->Recv_uint32(); company_info->company_value = p->Recv_uint64(); company_info->money = p->Recv_uint64(); company_info->income = p->Recv_uint64(); company_info->performance = p->Recv_uint16(); company_info->use_password = p->Recv_bool(); for (uint i = 0; i < NETWORK_VEH_END; i++) { company_info->num_vehicle[i] = p->Recv_uint16(); } for (uint i = 0; i < NETWORK_VEH_END; i++) { company_info->num_station[i] = p->Recv_uint16(); } company_info->ai = p->Recv_bool(); p->Recv_string(company_info->clients, sizeof(company_info->clients)); SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY); return NETWORK_RECV_STATUS_OKAY; } return NETWORK_RECV_STATUS_CLOSE_QUERY; } /* This packet contains info about the client (playas and name) * as client we save this in NetworkClientInfo, linked via 'client_id' * which is always an unique number on a server. */ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet *p) { NetworkClientInfo *ci; ClientID client_id = (ClientID)p->Recv_uint32(); CompanyID playas = (CompanyID)p->Recv_uint8(); char name[NETWORK_NAME_LENGTH]; p->Recv_string(name, sizeof(name)); if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; ci = NetworkClientInfo::GetByClientID(client_id); if (ci != NULL) { if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) { /* Client name changed, display the change */ NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, name); } else if (playas != ci->client_playas) { /* The client changed from client-player.. * Do not display that for now */ } /* Make sure we're in the company the server tells us to be in, * for the rare case that we get moved while joining. */ if (client_id == _network_own_client_id) SetLocalCompany(!Company::IsValidID(playas) ? COMPANY_SPECTATOR : playas); ci->client_playas = playas; strecpy(ci->client_name, name, lastof(ci->client_name)); SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } /* There are at most as many ClientInfo as ClientSocket objects in a * server. Having more info than a server can have means something * has gone wrong somewhere, i.e. the server has more info than it * has actual clients. That means the server is feeding us an invalid * state. So, bail out! This server is broken. */ if (!NetworkClientInfo::CanAllocateItem()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; /* We don't have this client_id yet, find an empty client_id, and put the data there */ ci = new NetworkClientInfo(client_id); ci->client_playas = playas; if (client_id == _network_own_client_id) this->SetInfo(ci); strecpy(ci->client_name, name, lastof(ci->client_name)); SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p) { static const StringID network_error_strings[] = { STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_GENERAL STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_DESYNC STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_SAVEGAME_FAILED STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_CONNECTION_LOST STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_ILLEGAL_PACKET STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NEWGRF_MISMATCH STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_AUTHORIZED STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_EXPECTED STR_NETWORK_ERROR_WRONG_REVISION, // NETWORK_ERROR_WRONG_REVISION STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NAME_IN_USE STR_NETWORK_ERROR_WRONG_PASSWORD, // NETWORK_ERROR_WRONG_PASSWORD STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_COMPANY_MISMATCH STR_NETWORK_ERROR_KICKED, // NETWORK_ERROR_KICKED STR_NETWORK_ERROR_CHEATER, // NETWORK_ERROR_CHEATER STR_NETWORK_ERROR_SERVER_FULL, // NETWORK_ERROR_FULL STR_NETWORK_ERROR_TOO_MANY_COMMANDS, // NETWORK_ERROR_TOO_MANY_COMMANDS STR_NETWORK_ERROR_TIMEOUT_PASSWORD, // NETWORK_ERROR_TIMEOUT_PASSWORD STR_NETWORK_ERROR_TIMEOUT_COMPUTER, // NETWORK_ERROR_TIMEOUT_COMPUTER STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN }; assert_compile(lengthof(network_error_strings) == NETWORK_ERROR_END); NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8(); StringID err = STR_NETWORK_ERROR_LOSTCONNECTION; if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error]; ShowErrorMessage(err, INVALID_STRING_ID, WL_CRITICAL); DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_SERVER_ERROR; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet *p) { if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET; uint grf_count = p->Recv_uint8(); NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY; /* Check all GRFs */ for (; grf_count > 0; grf_count--) { GRFIdentifier c; this->ReceiveGRFIdentifier(p, &c); /* Check whether we know this GRF */ const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); if (f == NULL) { /* We do not know this GRF, bail out of initialization */ char buf[sizeof(c.md5sum) * 2 + 1]; md5sumToString(buf, lastof(buf), c.md5sum); DEBUG(grf, 0, "NewGRF %08X not found; checksum %s", BSWAP32(c.grfid), buf); ret = NETWORK_RECV_STATUS_NEWGRF_MISMATCH; } } if (ret == NETWORK_RECV_STATUS_OKAY) { /* Start receiving the map */ return SendNewGRFsOk(); } /* NewGRF mismatch, bail out */ ShowErrorMessage(STR_NETWORK_ERROR_NEWGRF_MISMATCH, INVALID_STRING_ID, WL_CRITICAL); return ret; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) { if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_AUTH_GAME; const char *password = _network_join_server_password; if (!StrEmpty(password)) { return SendGamePassword(password); } ShowNetworkNeedPassword(NETWORK_GAME_PASSWORD); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) { if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_COMPANY) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_AUTH_COMPANY; _password_game_seed = p->Recv_uint32(); p->Recv_string(_password_server_id, sizeof(_password_server_id)); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; const char *password = _network_join_company_password; if (!StrEmpty(password)) { return SendCompanyPassword(password); } ShowNetworkNeedPassword(NETWORK_COMPANY_PASSWORD); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet *p) { if (this->status < STATUS_JOIN || this->status >= STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_AUTHORIZED; _network_own_client_id = (ClientID)p->Recv_uint32(); /* Initialize the password hash salting variables, even if they were previously. */ _password_game_seed = p->Recv_uint32(); p->Recv_string(_password_server_id, sizeof(_password_server_id)); /* Start receiving the map */ return SendGetMap(); } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_WAIT(Packet *p) { /* We set the internal wait state when requesting the map. */ if (this->status != STATUS_MAP_WAIT) return NETWORK_RECV_STATUS_MALFORMED_PACKET; /* But... only now we set the join status to waiting, instead of requesting. */ _network_join_status = NETWORK_JOIN_STATUS_WAITING; _network_join_waiting = p->Recv_uint8(); SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet *p) { if (this->status < STATUS_AUTHORIZED || this->status >= STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_MAP; if (this->savegame != NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->savegame = new PacketReader(); _frame_counter = _frame_counter_server = _frame_counter_max = p->Recv_uint32(); _network_join_bytes = 0; _network_join_bytes_total = 0; _network_join_status = NETWORK_JOIN_STATUS_DOWNLOADING; SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet *p) { if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (this->savegame == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _network_join_bytes_total = p->Recv_uint32(); SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet *p) { if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (this->savegame == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; /* We are still receiving data, put it to the file */ this->savegame->AddPacket(p); _network_join_bytes = (uint32)this->savegame->written_bytes; SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet *p) { if (this->status != STATUS_MAP) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (this->savegame == NULL) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _network_join_status = NETWORK_JOIN_STATUS_PROCESSING; SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); /* * Make sure everything is set for reading. * * We need the local copy and reset this->savegame because when * loading fails the network gets reset upon loading the intro * game, which would cause us to free this->savegame twice. */ LoadFilter *lf = this->savegame; this->savegame = NULL; lf->Reset(); /* The map is done downloading, load it */ ClearErrorMessages(); bool load_success = SafeLoad(NULL, SL_LOAD, GM_NORMAL, NO_DIRECTORY, lf); /* Long savegame loads shouldn't affect the lag calculation! */ this->last_packet = _realtime_tick; if (!load_success) { DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); ShowErrorMessage(STR_NETWORK_ERROR_SAVEGAMEERROR, INVALID_STRING_ID, WL_CRITICAL); return NETWORK_RECV_STATUS_SAVEGAME; } /* If the savegame has successfully loaded, ALL windows have been removed, * only toolbar/statusbar and gamefield are visible */ /* Say we received the map and loaded it correctly! */ SendMapOk(); /* New company/spectator (invalid company) or company we want to join is not active * Switch local company to spectator and await the server's judgement */ if (_network_join_as == COMPANY_NEW_COMPANY || !Company::IsValidID(_network_join_as)) { SetLocalCompany(COMPANY_SPECTATOR); if (_network_join_as != COMPANY_SPECTATOR) { /* We have arrived and ready to start playing; send a command to make a new company; * the server will give us a client-id and let us in */ _network_join_status = NETWORK_JOIN_STATUS_REGISTERING; ShowJoinStatusWindow(); NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company); } } else { /* take control over an existing company */ SetLocalCompany(_network_join_as); } return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p) { if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _frame_counter_server = p->Recv_uint32(); _frame_counter_max = p->Recv_uint32(); #ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME /* Test if the server supports this option * and if we are at the frame the server is */ if (p->pos + 1 < p->size) { _sync_frame = _frame_counter_server; _sync_seed_1 = p->Recv_uint32(); #ifdef NETWORK_SEND_DOUBLE_SEED _sync_seed_2 = p->Recv_uint32(); #endif } #endif /* Receive the token. */ if (p->pos != p->size) this->token = p->Recv_uint8(); DEBUG(net, 5, "Received FRAME %d", _frame_counter_server); /* Let the server know that we received this frame correctly * We do this only once per day, to save some bandwidth ;) */ if (!_network_first_time && last_ack_frame < _frame_counter) { last_ack_frame = _frame_counter + DAY_TICKS; DEBUG(net, 4, "Sent ACK at %d", _frame_counter); SendAck(); } return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p) { if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _sync_frame = p->Recv_uint32(); _sync_seed_1 = p->Recv_uint32(); #ifdef NETWORK_SEND_DOUBLE_SEED _sync_seed_2 = p->Recv_uint32(); #endif return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet *p) { if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; CommandPacket cp; const char *err = this->ReceiveCommand(p, &cp); cp.frame = p->Recv_uint32(); cp.my_cmd = p->Recv_bool(); if (err != NULL) { IConsolePrintF(CC_ERROR, "WARNING: %s from server, dropping...", err); return NETWORK_RECV_STATUS_MALFORMED_PACKET; } this->incoming_queue.Append(&cp); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p) { if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH]; const NetworkClientInfo *ci = NULL, *ci_to; NetworkAction action = (NetworkAction)p->Recv_uint8(); ClientID client_id = (ClientID)p->Recv_uint32(); bool self_send = p->Recv_bool(); p->Recv_string(msg, NETWORK_CHAT_LENGTH); int64 data = p->Recv_uint64(); ci_to = NetworkClientInfo::GetByClientID(client_id); if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY; /* Did we initiate the action locally? */ if (self_send) { switch (action) { case NETWORK_ACTION_CHAT_CLIENT: /* For speaking to client we need the client-name */ seprintf(name, lastof(name), "%s", ci_to->client_name); ci = NetworkClientInfo::GetByClientID(_network_own_client_id); break; /* For speaking to company or giving money, we need the company-name */ case NETWORK_ACTION_GIVE_MONEY: if (!Company::IsValidID(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY; /* FALL THROUGH */ case NETWORK_ACTION_CHAT_COMPANY: { StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS; SetDParam(0, ci_to->client_playas); GetString(name, str, lastof(name)); ci = NetworkClientInfo::GetByClientID(_network_own_client_id); break; } default: return NETWORK_RECV_STATUS_MALFORMED_PACKET; } } else { /* Display message from somebody else */ seprintf(name, lastof(name), "%s", ci_to->client_name); ci = ci_to; } if (ci != NULL) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data); } return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet *p) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); if (ci != NULL) { NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, GetNetworkErrorMsg((NetworkErrorCode)p->Recv_uint8())); delete ci; } SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); if (ci != NULL) { NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING); delete ci; } else { DEBUG(net, 0, "Unknown client (%d) is leaving the game", client_id); } SetWindowDirty(WC_CLIENT_LIST, 0); /* If we come here it means we could not locate the client.. strange :s */ return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); if (ci != NULL) { NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name); } SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { /* Only when we're trying to join we really * care about the server shutting down. */ if (this->status >= STATUS_JOIN) { ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_SHUTDOWN, INVALID_STRING_ID, WL_CRITICAL); } return NETWORK_RECV_STATUS_SERVER_ERROR; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet *p) { /* Only when we're trying to join we really * care about the server shutting down. */ if (this->status >= STATUS_JOIN) { /* To throttle the reconnects a bit, every clients waits its * Client ID modulo 16. This way reconnects should be spread * out a bit. */ _network_reconnect = _network_own_client_id % 16; ShowErrorMessage(STR_NETWORK_MESSAGE_SERVER_REBOOT, INVALID_STRING_ID, WL_CRITICAL); } return NETWORK_RECV_STATUS_SERVER_ERROR; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_RCON(Packet *p) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; TextColour colour_code = (TextColour)p->Recv_uint16(); if (!IsValidConsoleColour(colour_code)) return NETWORK_RECV_STATUS_MALFORMED_PACKET; char rcon_out[NETWORK_RCONCOMMAND_LENGTH]; p->Recv_string(rcon_out, sizeof(rcon_out)); IConsolePrint(colour_code, rcon_out); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; /* Nothing more in this packet... */ ClientID client_id = (ClientID)p->Recv_uint32(); CompanyID company_id = (CompanyID)p->Recv_uint8(); if (client_id == 0) { /* definitely an invalid client id, debug message and do nothing. */ DEBUG(net, 0, "[move] received invalid client index = 0"); return NETWORK_RECV_STATUS_MALFORMED_PACKET; } const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); /* Just make sure we do not try to use a client_index that does not exist */ if (ci == NULL) return NETWORK_RECV_STATUS_OKAY; /* if not valid player, force spectator, else check player exists */ if (!Company::IsValidID(company_id)) company_id = COMPANY_SPECTATOR; if (client_id == _network_own_client_id) { SetLocalCompany(company_id); } return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet *p) { if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _network_server_max_companies = p->Recv_uint8(); _network_server_max_spectators = p->Recv_uint8(); return NETWORK_RECV_STATUS_OKAY; } NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet *p) { if (this->status < STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; _network_company_passworded = p->Recv_uint16(); SetWindowClassesDirty(WC_COMPANY); return NETWORK_RECV_STATUS_OKAY; } /** * Check the connection's state, i.e. is the connection still up? */ void ClientNetworkGameSocketHandler::CheckConnection() { /* Only once we're authorized we can expect a steady stream of packets. */ if (this->status < STATUS_AUTHORIZED) return; /* It might... sometimes occur that the realtime ticker overflows. */ if (_realtime_tick < this->last_packet) this->last_packet = _realtime_tick; /* Lag is in milliseconds; 5 seconds are roughly twice the * server's "you're slow" threshold (1 game day). */ uint lag = (_realtime_tick - this->last_packet) / 1000; if (lag < 5) return; /* 20 seconds are (way) more than 4 game days after which * the server will forcefully disconnect you. */ if (lag > 20) { this->NetworkGameSocketHandler::CloseConnection(); ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL); return; } /* Prevent showing the lag message every tick; just update it when needed. */ static uint last_lag = 0; if (last_lag == lag) return; last_lag = lag; SetDParam(0, lag); ShowErrorMessage(STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION, STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION, WL_INFO); } /** Is called after a client is connected to the server */ void NetworkClient_Connected() { /* Set the frame-counter to 0 so nothing happens till we are ready */ _frame_counter = 0; _frame_counter_server = 0; last_ack_frame = 0; /* Request the game-info */ MyClient::SendJoin(); } /** * Send a remote console command. * @param password The password. * @param command The command to execute. */ void NetworkClientSendRcon(const char *password, const char *command) { MyClient::SendRCon(password, command); } /** * Notify the server of this client wanting to be moved to another company. * @param company_id id of the company the client wishes to be moved to. * @param pass the password, is only checked on the server end if a password is needed. * @return void */ void NetworkClientRequestMove(CompanyID company_id, const char *pass) { MyClient::SendMove(company_id, pass); } /** * Move the clients of a company to the spectators. * @param cid The company to move the clients of. */ void NetworkClientsToSpectators(CompanyID cid) { Backup cur_company(_current_company, FILE_LINE); /* If our company is changing owner, go to spectators */ if (cid == _local_company) SetLocalCompany(COMPANY_SPECTATOR); NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { if (ci->client_playas != cid) continue; NetworkTextMessage(NETWORK_ACTION_COMPANY_SPECTATOR, CC_DEFAULT, false, ci->client_name); ci->client_playas = COMPANY_SPECTATOR; } cur_company.Restore(); } /** * Send the server our name. */ void NetworkUpdateClientName() { NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(_network_own_client_id); if (ci == NULL) return; /* Don't change the name if it is the same as the old name */ if (strcmp(ci->client_name, _settings_client.network.client_name) != 0) { if (!_network_server) { MyClient::SendSetName(_settings_client.network.client_name); } else { if (NetworkFindName(_settings_client.network.client_name, lastof(_settings_client.network.client_name))) { NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, _settings_client.network.client_name); strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name)); NetworkUpdateClientInfo(CLIENT_ID_SERVER); } } } } /** * Send a chat message. * @param action The action associated with the message. * @param type The destination type. * @param dest The destination index, be it a company index or client id. * @param msg The actual message. * @param data Arbitrary extra data. */ void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data) { MyClient::SendChat(action, type, dest, msg, data); } /** * Set/Reset company password on the client side. * @param password Password to be set. */ void NetworkClientSetCompanyPassword(const char *password) { MyClient::SendSetPassword(password); } /** * Tell whether the client has team members where he/she can chat to. * @param cio client to check members of. * @return true if there is at least one team member. */ bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio) { /* Only companies actually playing can speak to team. Eg spectators cannot */ if (!_settings_client.gui.prefer_teamchat || !Company::IsValidID(cio->client_playas)) return false; const NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { if (ci->client_playas == cio->client_playas && ci != cio) return true; } return false; } /** * Check if max_companies has been reached on the server (local check only). * @return true if the max value has been reached or exceeded, false otherwise. */ bool NetworkMaxCompaniesReached() { return Company::GetNumItems() >= (_network_server ? _settings_client.network.max_companies : _network_server_max_companies); } /** * Check if max_spectatos has been reached on the server (local check only). * @return true if the max value has been reached or exceeded, false otherwise. */ bool NetworkMaxSpectatorsReached() { return NetworkSpectatorCount() >= (_network_server ? _settings_client.network.max_spectators : _network_server_max_spectators); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_udp.h0000644000000000000000000000221312627373441016674 0ustar rootroot/* $Id: network_udp.h 23751 2012-01-04 22:08:43Z rubidium $ */ /* * 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 network_udp.h Sending and receiving UDP messages. */ #ifndef NETWORK_UDP_H #define NETWORK_UDP_H #ifdef ENABLE_NETWORK #include "core/address.h" void NetworkUDPInitialize(); void NetworkUDPSearchGame(); void NetworkUDPQueryMasterServer(); void NetworkUDPQueryServer(NetworkAddress address, bool manually = false); void NetworkUDPAdvertise(); void NetworkUDPRemoveAdvertise(bool blocking); void NetworkUDPClose(); void NetworkBackgroundUDPLoop(); #endif /* ENABLE_NETWORK */ #endif /* NETWORK_UDP_H */ openttd-1.5.3/src/network/core/0000755000000000000000000000000012627373441015114 5ustar rootrootopenttd-1.5.3/src/network/core/tcp_admin.cpp0000644000000000000000000002620012627373441017556 0ustar rootroot/* $Id: tcp_admin.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tcp_admin.cpp Basic functions to receive and send TCP packets to and from the admin network. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../network_internal.h" #include "tcp_admin.h" #include "../../debug.h" #include "../../safeguards.h" /* Make sure that these enums match. */ assert_compile((int)CRR_MANUAL == (int)ADMIN_CRR_MANUAL); assert_compile((int)CRR_AUTOCLEAN == (int)ADMIN_CRR_AUTOCLEAN); assert_compile((int)CRR_BANKRUPT == (int)ADMIN_CRR_BANKRUPT); assert_compile((int)CRR_END == (int)ADMIN_CRR_END); /** * Create the admin handler for the given socket. * @param s The socket to communicate over. */ NetworkAdminSocketHandler::NetworkAdminSocketHandler(SOCKET s) : status(ADMIN_STATUS_INACTIVE) { this->sock = s; this->admin_name[0] = '\0'; this->admin_version[0] = '\0'; } NetworkAdminSocketHandler::~NetworkAdminSocketHandler() { } NetworkRecvStatus NetworkAdminSocketHandler::CloseConnection(bool error) { delete this; return NETWORK_RECV_STATUS_CONN_LOST; } /** * Handle the given packet, i.e. pass it to the right parser receive command. * @param p the packet to handle. * @return #NetworkRecvStatus of handling. */ NetworkRecvStatus NetworkAdminSocketHandler::HandlePacket(Packet *p) { PacketAdminType type = (PacketAdminType)p->Recv_uint8(); switch (this->HasClientQuit() ? INVALID_ADMIN_PACKET : type) { case ADMIN_PACKET_ADMIN_JOIN: return this->Receive_ADMIN_JOIN(p); case ADMIN_PACKET_ADMIN_QUIT: return this->Receive_ADMIN_QUIT(p); case ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY: return this->Receive_ADMIN_UPDATE_FREQUENCY(p); case ADMIN_PACKET_ADMIN_POLL: return this->Receive_ADMIN_POLL(p); case ADMIN_PACKET_ADMIN_CHAT: return this->Receive_ADMIN_CHAT(p); case ADMIN_PACKET_ADMIN_RCON: return this->Receive_ADMIN_RCON(p); case ADMIN_PACKET_ADMIN_GAMESCRIPT: return this->Receive_ADMIN_GAMESCRIPT(p); case ADMIN_PACKET_ADMIN_PING: return this->Receive_ADMIN_PING(p); case ADMIN_PACKET_SERVER_FULL: return this->Receive_SERVER_FULL(p); case ADMIN_PACKET_SERVER_BANNED: return this->Receive_SERVER_BANNED(p); case ADMIN_PACKET_SERVER_ERROR: return this->Receive_SERVER_ERROR(p); case ADMIN_PACKET_SERVER_PROTOCOL: return this->Receive_SERVER_PROTOCOL(p); case ADMIN_PACKET_SERVER_WELCOME: return this->Receive_SERVER_WELCOME(p); case ADMIN_PACKET_SERVER_NEWGAME: return this->Receive_SERVER_NEWGAME(p); case ADMIN_PACKET_SERVER_SHUTDOWN: return this->Receive_SERVER_SHUTDOWN(p); case ADMIN_PACKET_SERVER_DATE: return this->Receive_SERVER_DATE(p); case ADMIN_PACKET_SERVER_CLIENT_JOIN: return this->Receive_SERVER_CLIENT_JOIN(p); case ADMIN_PACKET_SERVER_CLIENT_INFO: return this->Receive_SERVER_CLIENT_INFO(p); case ADMIN_PACKET_SERVER_CLIENT_UPDATE: return this->Receive_SERVER_CLIENT_UPDATE(p); case ADMIN_PACKET_SERVER_CLIENT_QUIT: return this->Receive_SERVER_CLIENT_QUIT(p); case ADMIN_PACKET_SERVER_CLIENT_ERROR: return this->Receive_SERVER_CLIENT_ERROR(p); case ADMIN_PACKET_SERVER_COMPANY_NEW: return this->Receive_SERVER_COMPANY_NEW(p); case ADMIN_PACKET_SERVER_COMPANY_INFO: return this->Receive_SERVER_COMPANY_INFO(p); case ADMIN_PACKET_SERVER_COMPANY_UPDATE: return this->Receive_SERVER_COMPANY_UPDATE(p); case ADMIN_PACKET_SERVER_COMPANY_REMOVE: return this->Receive_SERVER_COMPANY_REMOVE(p); case ADMIN_PACKET_SERVER_COMPANY_ECONOMY: return this->Receive_SERVER_COMPANY_ECONOMY(p); case ADMIN_PACKET_SERVER_COMPANY_STATS: return this->Receive_SERVER_COMPANY_STATS(p); case ADMIN_PACKET_SERVER_CHAT: return this->Receive_SERVER_CHAT(p); case ADMIN_PACKET_SERVER_RCON: return this->Receive_SERVER_RCON(p); case ADMIN_PACKET_SERVER_CONSOLE: return this->Receive_SERVER_CONSOLE(p); case ADMIN_PACKET_SERVER_CMD_NAMES: return this->Receive_SERVER_CMD_NAMES(p); case ADMIN_PACKET_SERVER_CMD_LOGGING: return this->Receive_SERVER_CMD_LOGGING(p); case ADMIN_PACKET_SERVER_RCON_END: return this->Receive_SERVER_RCON_END(p); case ADMIN_PACKET_SERVER_PONG: return this->Receive_SERVER_PONG(p); default: if (this->HasClientQuit()) { DEBUG(net, 0, "[tcp/admin] received invalid packet type %d from '%s' (%s)", type, this->admin_name, this->admin_version); } else { DEBUG(net, 0, "[tcp/admin] received illegal packet from '%s' (%s)", this->admin_name, this->admin_version); } this->CloseConnection(); return NETWORK_RECV_STATUS_MALFORMED_PACKET; } } /** * Do the actual receiving of packets. * As long as HandlePacket returns OKAY packets are handled. Upon * failure, or no more packets to process the last result of * HandlePacket is returned. * @return #NetworkRecvStatus of the last handled packet. */ NetworkRecvStatus NetworkAdminSocketHandler::ReceivePackets() { Packet *p; while ((p = this->ReceivePacket()) != NULL) { NetworkRecvStatus res = this->HandlePacket(p); if (res != NETWORK_RECV_STATUS_OKAY) return res; } return NETWORK_RECV_STATUS_OKAY; } /** * Helper for logging receiving invalid packets. * @param type The received packet type. * @return The status the network should have, in this case: "malformed packet error". */ NetworkRecvStatus NetworkAdminSocketHandler::ReceiveInvalidPacket(PacketAdminType type) { DEBUG(net, 0, "[tcp/admin] received illegal packet type %d from admin %s (%s)", type, this->admin_name, this->admin_version); return NETWORK_RECV_STATUS_MALFORMED_PACKET; } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_JOIN(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_JOIN); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_QUIT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_QUIT); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_UPDATE_FREQUENCY(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_POLL(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_POLL); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_CHAT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_CHAT); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_RCON(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_RCON); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_GAMESCRIPT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_GAMESCRIPT); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_ADMIN_PING(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_ADMIN_PING); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_FULL(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_FULL); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_BANNED(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_BANNED); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_ERROR(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_ERROR); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PROTOCOL(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PROTOCOL); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_WELCOME(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_WELCOME); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_NEWGAME(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_NEWGAME); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_SHUTDOWN); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_DATE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_DATE); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_JOIN(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_JOIN); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_INFO(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_INFO); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_UPDATE); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_QUIT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_QUIT); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CLIENT_ERROR(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CLIENT_ERROR); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_NEW(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_NEW); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_INFO(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_INFO); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_UPDATE); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_REMOVE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_REMOVE); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_ECONOMY(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_ECONOMY); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_COMPANY_STATS(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_COMPANY_STATS); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CHAT(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CHAT); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CONSOLE(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CONSOLE); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_NAMES(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_NAMES); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_CMD_LOGGING(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_CMD_LOGGING); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_RCON_END(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_RCON_END); } NetworkRecvStatus NetworkAdminSocketHandler::Receive_SERVER_PONG(Packet *p) { return this->ReceiveInvalidPacket(ADMIN_PACKET_SERVER_PONG); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/tcp_connect.cpp0000644000000000000000000000550112627373441020120 0ustar rootroot/* $Id: tcp_connect.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tcp_connect.cpp Basic functions to create connections without blocking. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../../thread/thread.h" #include "tcp.h" #include "../../safeguards.h" /** List of connections that are currently being created */ static SmallVector _tcp_connecters; /** * Create a new connecter for the given address * @param address the (un)resolved address to connect to */ TCPConnecter::TCPConnecter(const NetworkAddress &address) : connected(false), aborted(false), killed(false), sock(INVALID_SOCKET), address(address) { *_tcp_connecters.Append() = this; if (!ThreadObject::New(TCPConnecter::ThreadEntry, this, &this->thread)) { this->Connect(); } } /** The actual connection function */ void TCPConnecter::Connect() { this->sock = this->address.Connect(); if (this->sock == INVALID_SOCKET) { this->aborted = true; } else { this->connected = true; } } /** * Entry point for the new threads. * @param param the TCPConnecter instance to call Connect on. */ /* static */ void TCPConnecter::ThreadEntry(void *param) { static_cast(param)->Connect(); } /** * Check whether we need to call the callback, i.e. whether we * have connected or aborted and call the appropriate callback * for that. It's done this way to ease on the locking that * would otherwise be needed everywhere. */ /* static */ void TCPConnecter::CheckCallbacks() { for (TCPConnecter **iter = _tcp_connecters.Begin(); iter < _tcp_connecters.End(); /* nothing */) { TCPConnecter *cur = *iter; if ((cur->connected || cur->aborted) && cur->killed) { _tcp_connecters.Erase(iter); if (cur->sock != INVALID_SOCKET) closesocket(cur->sock); delete cur; continue; } if (cur->connected) { _tcp_connecters.Erase(iter); cur->OnConnect(cur->sock); delete cur; continue; } if (cur->aborted) { _tcp_connecters.Erase(iter); cur->OnFailure(); delete cur; continue; } iter++; } } /** Kill all connection attempts. */ /* static */ void TCPConnecter::KillAll() { for (TCPConnecter **iter = _tcp_connecters.Begin(); iter != _tcp_connecters.End(); iter++) (*iter)->killed = true; } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/tcp_admin.h0000644000000000000000000005151512627373441017232 0ustar rootroot/* $Id: tcp_admin.h 25588 2013-07-11 20:31:39Z planetmaker $ */ /* * 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 tcp_admin.h Basic functions to receive and send TCP packets to and from the admin network. */ #ifndef NETWORK_CORE_TCP_ADMIN_H #define NETWORK_CORE_TCP_ADMIN_H #include "os_abstraction.h" #include "tcp.h" #include "../network_type.h" #include "../../core/pool_type.hpp" #ifdef ENABLE_NETWORK /** * Enum with types of TCP packets specific to the admin network. * This protocol may only be extended to ensure stability. */ enum PacketAdminType { ADMIN_PACKET_ADMIN_JOIN, ///< The admin announces and authenticates itself to the server. ADMIN_PACKET_ADMIN_QUIT, ///< The admin tells the server that it is quitting. ADMIN_PACKET_ADMIN_UPDATE_FREQUENCY, ///< The admin tells the server the update frequency of a particular piece of information. ADMIN_PACKET_ADMIN_POLL, ///< The admin explicitly polls for a piece of information. ADMIN_PACKET_ADMIN_CHAT, ///< The admin sends a chat message to be distributed. ADMIN_PACKET_ADMIN_RCON, ///< The admin sends a remote console command. ADMIN_PACKET_ADMIN_GAMESCRIPT, ///< The admin sends a JSON string for the GameScript. ADMIN_PACKET_ADMIN_PING, ///< The admin sends a ping to the server, expecting a ping-reply (PONG) packet. ADMIN_PACKET_SERVER_FULL = 100, ///< The server tells the admin it cannot accept the admin. ADMIN_PACKET_SERVER_BANNED, ///< The server tells the admin it is banned. ADMIN_PACKET_SERVER_ERROR, ///< The server tells the admin an error has occurred. ADMIN_PACKET_SERVER_PROTOCOL, ///< The server tells the admin its protocol version. ADMIN_PACKET_SERVER_WELCOME, ///< The server welcomes the admin to a game. ADMIN_PACKET_SERVER_NEWGAME, ///< The server tells the admin its going to start a new game. ADMIN_PACKET_SERVER_SHUTDOWN, ///< The server tells the admin its shutting down. ADMIN_PACKET_SERVER_DATE, ///< The server tells the admin what the current game date is. ADMIN_PACKET_SERVER_CLIENT_JOIN, ///< The server tells the admin that a client has joined. ADMIN_PACKET_SERVER_CLIENT_INFO, ///< The server gives the admin information about a client. ADMIN_PACKET_SERVER_CLIENT_UPDATE, ///< The server gives the admin an information update on a client. ADMIN_PACKET_SERVER_CLIENT_QUIT, ///< The server tells the admin that a client quit. ADMIN_PACKET_SERVER_CLIENT_ERROR, ///< The server tells the admin that a client caused an error. ADMIN_PACKET_SERVER_COMPANY_NEW, ///< The server tells the admin that a new company has started. ADMIN_PACKET_SERVER_COMPANY_INFO, ///< The server gives the admin information about a company. ADMIN_PACKET_SERVER_COMPANY_UPDATE, ///< The server gives the admin an information update on a company. ADMIN_PACKET_SERVER_COMPANY_REMOVE, ///< The server tells the admin that a company was removed. ADMIN_PACKET_SERVER_COMPANY_ECONOMY, ///< The server gives the admin some economy related company information. ADMIN_PACKET_SERVER_COMPANY_STATS, ///< The server gives the admin some statistics about a company. ADMIN_PACKET_SERVER_CHAT, ///< The server received a chat message and relays it. ADMIN_PACKET_SERVER_RCON, ///< The server's reply to a remove console command. ADMIN_PACKET_SERVER_CONSOLE, ///< The server gives the admin the data that got printed to its console. ADMIN_PACKET_SERVER_CMD_NAMES, ///< The server sends out the names of the DoCommands to the admins. ADMIN_PACKET_SERVER_CMD_LOGGING, ///< The server gives the admin copies of incoming command packets. ADMIN_PACKET_SERVER_GAMESCRIPT, ///< The server gives the admin information from the GameScript in JSON. ADMIN_PACKET_SERVER_RCON_END, ///< The server indicates that the remote console command has completed. ADMIN_PACKET_SERVER_PONG, ///< The server replies to a ping request from the admin. INVALID_ADMIN_PACKET = 0xFF, ///< An invalid marker for admin packets. }; /** Status of an admin. */ enum AdminStatus { ADMIN_STATUS_INACTIVE, ///< The admin is not connected nor active. ADMIN_STATUS_ACTIVE, ///< The admin is active. ADMIN_STATUS_END, ///< Must ALWAYS be on the end of this list!! (period) }; /** Update types an admin can register a frequency for */ enum AdminUpdateType { ADMIN_UPDATE_DATE, ///< Updates about the date of the game. ADMIN_UPDATE_CLIENT_INFO, ///< Updates about the information of clients. ADMIN_UPDATE_COMPANY_INFO, ///< Updates about the generic information of companies. ADMIN_UPDATE_COMPANY_ECONOMY, ///< Updates about the economy of companies. ADMIN_UPDATE_COMPANY_STATS, ///< Updates about the statistics of companies. ADMIN_UPDATE_CHAT, ///< The admin would like to have chat messages. ADMIN_UPDATE_CONSOLE, ///< The admin would like to have console messages. ADMIN_UPDATE_CMD_NAMES, ///< The admin would like a list of all DoCommand names. ADMIN_UPDATE_CMD_LOGGING, ///< The admin would like to have DoCommand information. ADMIN_UPDATE_GAMESCRIPT, ///< The admin would like to have gamescript messages. ADMIN_UPDATE_END, ///< Must ALWAYS be on the end of this list!! (period) }; /** Update frequencies an admin can register. */ enum AdminUpdateFrequency { ADMIN_FREQUENCY_POLL = 0x01, ///< The admin can poll this. ADMIN_FREQUENCY_DAILY = 0x02, ///< The admin gets information about this on a daily basis. ADMIN_FREQUENCY_WEEKLY = 0x04, ///< The admin gets information about this on a weekly basis. ADMIN_FREQUENCY_MONTHLY = 0x08, ///< The admin gets information about this on a monthly basis. ADMIN_FREQUENCY_QUARTERLY = 0x10, ///< The admin gets information about this on a quarterly basis. ADMIN_FREQUENCY_ANUALLY = 0x20, ///< The admin gets information about this on a yearly basis. ADMIN_FREQUENCY_AUTOMATIC = 0x40, ///< The admin gets information about this when it changes. }; DECLARE_ENUM_AS_BIT_SET(AdminUpdateFrequency) /** Reasons for removing a company - communicated to admins. */ enum AdminCompanyRemoveReason { ADMIN_CRR_MANUAL, ///< The company is manually removed. ADMIN_CRR_AUTOCLEAN, ///< The company is removed due to autoclean. ADMIN_CRR_BANKRUPT, ///< The company went belly-up. ADMIN_CRR_END, ///< Sentinel for end. }; /** Main socket handler for admin related connections. */ class NetworkAdminSocketHandler : public NetworkTCPSocketHandler { protected: char admin_name[NETWORK_CLIENT_NAME_LENGTH]; ///< Name of the admin. char admin_version[NETWORK_REVISION_LENGTH]; ///< Version string of the admin. AdminStatus status; ///< Status of this admin. NetworkRecvStatus ReceiveInvalidPacket(PacketAdminType type); /** * Join the admin network: * string Password the server is expecting for this network. * string Name of the application being used to connect. * string Version string of the application being used to connect. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_JOIN(Packet *p); /** * Notification to the server that this admin is quitting. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_QUIT(Packet *p); /** * Register updates to be sent at certain frequencies (as announced in the PROTOCOL packet): * uint16 Update type (see #AdminUpdateType). * uint16 Update frequency (see #AdminUpdateFrequency), setting #ADMIN_FREQUENCY_POLL is always ignored. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet *p); /** * Poll the server for certain updates, an invalid poll (e.g. not existent id) gets silently dropped: * uint8 #AdminUpdateType the server should answer for, only if #AdminUpdateFrequency #ADMIN_FREQUENCY_POLL is advertised in the PROTOCOL packet. * uint32 ID relevant to the packet type, e.g. * - the client ID for #ADMIN_UPDATE_CLIENT_INFO. Use UINT32_MAX to show all clients. * - the company ID for #ADMIN_UPDATE_COMPANY_INFO. Use UINT32_MAX to show all companies. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_POLL(Packet *p); /** * Send chat as the server: * uint8 Action such as NETWORK_ACTION_CHAT_CLIENT (see #NetworkAction). * uint8 Destination type such as DESTTYPE_BROADCAST (see #DestType). * uint32 ID of the destination such as company or client id. * string Message. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_CHAT(Packet *p); /** * Execute a command on the servers console: * string Command to be executed. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_RCON(Packet *p); /** * Send a JSON string to the current active GameScript. * json JSON string for the GameScript. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p); /** * Ping the server, requiring the server to reply with a pong packet. * uint32 Integer value to pass to the server, which is quoted in the reply. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_ADMIN_PING(Packet *p); /** * The server is full (connection gets closed). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_FULL(Packet *p); /** * The source IP address is banned (connection gets closed). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet *p); /** * An error was caused by this admin connection (connection gets closed). * uint8 NetworkErrorCode the error caused. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet *p); /** * Inform a just joined admin about the protocol specifics: * uint8 Protocol version. * bool Further protocol data follows (repeats through all update packet types). * uint16 Update packet type. * uint16 Frequencies allowed for this update packet (bitwise). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_PROTOCOL(Packet *p); /** * Welcome a connected admin to the game: * string Name of the Server (e.g. as advertised to master server). * string OpenTTD version string. * bool Server is dedicated. * string Name of the Map. * uint32 Random seed of the Map. * uint8 Landscape of the Map. * uint32 Start date of the Map. * uint16 Map width. * uint16 Map height. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p); /** * Notification about a newgame. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p); /** * Notification about the server shutting down. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p); /** * Send the current date of the game: * uint32 Current game date. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_DATE(Packet *p); /** * Notification of a new client: * uint32 ID of the new client. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CLIENT_JOIN(Packet *p); /** * Client information of a specific client: * uint32 ID of the client. * string Network address of the client. * string Name of the client. * uint8 Language of the client. * uint32 Date the client joined the game. * uint8 ID of the company the client is playing as (255 for spectators). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p); /** * Client update details on a specific client (e.g. after rename or move): * uint32 ID of the client. * string Name of the client. * uint8 ID of the company the client is playing as (255 for spectators). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CLIENT_UPDATE(Packet *p); /** * Notification about a client leaving the game. * uint32 ID of the client that just left. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CLIENT_QUIT(Packet *p); /** * Notification about a client error (and thus the clients disconnection). * uint32 ID of the client that made the error. * uint8 Error the client made (see NetworkErrorCode). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CLIENT_ERROR(Packet *p); /** * Notification of a new company: * uint8 ID of the new company. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_NEW(Packet *p); /** * Company information on a specific company: * uint8 ID of the company. * string Name of the company. * string Name of the companies manager. * uint8 Main company colour. * bool Company is password protected. * uint32 Year the company was inaugurated. * bool Company is an AI. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet *p); /** * Company information of a specific company: * uint8 ID of the company. * string Name of the company. * string Name of the companies manager. * uint8 Main company colour. * bool Company is password protected. * uint8 Quarters of bankruptcy. * uint8 Owner of share 1. * uint8 Owner of share 2. * uint8 Owner of share 3. * uint8 Owner of share 4. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p); /** * Notification about a removed company (e.g. due to bankruptcy). * uint8 ID of the company. * uint8 Reason for being removed (see #AdminCompanyRemoveReason). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_REMOVE(Packet *p); /** * Economy update of a specific company: * uint8 ID of the company. * uint64 Money. * uint64 Loan. * uint64 Income. * uint16 Delivered cargo (this quarter). * uint64 Company value (last quarter). * uint16 Performance (last quarter). * uint16 Delivered cargo (last quarter). * uint64 Company value (previous quarter). * uint16 Performance (previous quarter). * uint16 Delivered cargo (previous quarter). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_ECONOMY(Packet *p); /** * Company statistics on stations and vehicles: * uint8 ID of the company. * uint16 Number of trains. * uint16 Number of lorries. * uint16 Number of busses. * uint16 Number of planes. * uint16 Number of ships. * uint16 Number of train stations. * uint16 Number of lorry stations. * uint16 Number of bus stops. * uint16 Number of airports and heliports. * uint16 Number of harbours. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_STATS(Packet *p); /** * Send chat from the game into the admin network: * uint8 Action such as NETWORK_ACTION_CHAT_CLIENT (see #NetworkAction). * uint8 Destination type such as DESTTYPE_BROADCAST (see #DestType). * uint32 ID of the client who sent this message. * string Message. * uint64 Money (only when it is a 'give money' action). * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet *p); /** * Result of an rcon command: * uint16 Colour as it would be used on the server or a client. * string Output of the executed command. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_RCON(Packet *p); /** * Send what would be printed on the server's console also into the admin network. * string The origin of the text, e.g. "console" for console, or "net" for network related (debug) messages. * string Text as found on the console of the server. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CONSOLE(Packet *p); /** * Send DoCommand names to the bot upon request only. * Multiple of these packets can follow each other in order to provide * all known DoCommand names. * * NOTICE: Data provided with this packet is not stable and will not be * treated as such. Do not rely on IDs or names to be constant * across different versions / revisions of OpenTTD. * Data provided in this packet is for logging purposes only. * * These three fields are repeated until the packet is full: * bool Data to follow. * uint16 ID of the DoCommand. * string Name of DoCommand. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CMD_NAMES(Packet *p); /** * Send incoming command packets to the admin network. * This is for logging purposes only. * * NOTICE: Data provided with this packet is not stable and will not be * treated as such. Do not rely on IDs or names to be constant * across different versions / revisions of OpenTTD. * Data provided in this packet is for logging purposes only. * * uint32 ID of the client sending the command. * uint8 ID of the company (0..MAX_COMPANIES-1). * uint16 ID of the command. * uint32 P1 (variable data passed to the command). * uint32 P2 (variable data passed to the command). * uint32 Tile where this is taking place. * string Text passed to the command. * uint32 Frame of execution. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_CMD_LOGGING(Packet *p); /** * Send a ping-reply (pong) to the admin that sent us the ping packet. * uint32 Integer identifier - should be the same as read from the admins ping packet. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_PONG(Packet *p); /** * Notify the admin connection that the rcon command has finished. * string The command as requested by the admin connection. * @param p The packet that was just received. * @return The state the network should have. */ virtual NetworkRecvStatus Receive_SERVER_RCON_END(Packet *p); NetworkRecvStatus HandlePacket(Packet *p); public: NetworkRecvStatus CloseConnection(bool error = true); NetworkAdminSocketHandler(SOCKET s); ~NetworkAdminSocketHandler(); NetworkRecvStatus ReceivePackets(); /** * Get the status of the admin. * @return The status of the admin. */ AdminStatus GetAdminStatus() const { return this->status; } }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_TCP_ADMIN_H */ openttd-1.5.3/src/network/core/host.h0000644000000000000000000000154112627373441016243 0ustar rootroot/* $Id: host.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 host.h Resolving of hostnames/IPs */ #ifndef NETWORK_CORE_HOST_H #define NETWORK_CORE_HOST_H #include "address.h" void NetworkFindBroadcastIPs(NetworkAddressList *broadcast); #endif /* NETWORK_CORE_HOST_H */ openttd-1.5.3/src/network/core/tcp_http.h0000644000000000000000000000767512627373441017131 0ustar rootroot/* $Id: tcp_http.h 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 tcp_http.h Basic functions to receive and send HTTP TCP packets. */ #ifndef NETWORK_CORE_TCP_HTTP_H #define NETWORK_CORE_TCP_HTTP_H #include "tcp.h" #ifdef ENABLE_NETWORK /** Callback for when the HTTP handler has something to tell us. */ struct HTTPCallback { /** * An error has occurred and the connection has been closed. * @note HTTP socket handler is closed/freed. */ virtual void OnFailure() = 0; /** * We're receiving data. * @param data the received data, NULL when all data has been received. * @param length the amount of received data, 0 when all data has been received. * @note When NULL is sent the HTTP socket handler is closed/freed. */ virtual void OnReceiveData(const char *data, size_t length) = 0; /** Silentium */ virtual ~HTTPCallback() {} }; /** Base socket handler for HTTP traffic. */ class NetworkHTTPSocketHandler : public NetworkSocketHandler { private: char recv_buffer[4096]; ///< Partially received message. int recv_pos; ///< Current position in buffer. int recv_length; ///< Length of the data still retrieving. HTTPCallback *callback; ///< The callback to call for the incoming data. const char *data; ///< The (POST) data we might want to forward (to a redirect). int redirect_depth; ///< The depth of the redirection. int HandleHeader(); int Receive(); public: SOCKET sock; ///< The socket currently connected to /** * Whether this socket is currently bound to a socket. * @return true when the socket is bound, false otherwise */ bool IsConnected() const { return this->sock != INVALID_SOCKET; } virtual NetworkRecvStatus CloseConnection(bool error = true); NetworkHTTPSocketHandler(SOCKET sock, HTTPCallback *callback, const char *host, const char *url, const char *data, int depth); ~NetworkHTTPSocketHandler(); static int Connect(char *uri, HTTPCallback *callback, const char *data = NULL, int depth = 0); static void HTTPReceive(); }; /** Connect with a HTTP server and do ONE query. */ class NetworkHTTPContentConnecter : TCPConnecter { HTTPCallback *callback; ///< Callback to tell that we received some data (or won't). const char *url; ///< The URL we want to get at the server. const char *data; ///< The data to send int depth; ///< How far we have recursed public: /** * Start the connecting. * @param address the address to connect to * @param callback the callback for HTTP retrieval * @param url the url at the server * @param data the data to send * @param depth the depth (redirect recursion) of the queries */ NetworkHTTPContentConnecter(const NetworkAddress &address, HTTPCallback *callback, const char *url, const char *data = NULL, int depth = 0) : TCPConnecter(address), callback(callback), url(stredup(url)), data(data), depth(depth) { } /** Free all our allocated data. */ ~NetworkHTTPContentConnecter() { free(this->url); } virtual void OnFailure() { this->callback->OnFailure(); free(this->data); } virtual void OnConnect(SOCKET s) { new NetworkHTTPSocketHandler(s, this->callback, this->address.GetHostname(), this->url, this->data, this->depth); /* We've relinquished control of data now. */ this->data = NULL; } }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_TCP_HTTP_H */ openttd-1.5.3/src/network/core/tcp_http.cpp0000644000000000000000000002522212627373441017450 0ustar rootroot/* $Id: tcp_http.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tcp_http.cpp Basic functions to receive and send HTTP TCP packets. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../../debug.h" #include "../../rev.h" #include "../network_func.h" #include "tcp_http.h" #include "../../safeguards.h" /** List of open HTTP connections. */ static SmallVector _http_connections; /** * Start the querying * @param s the socket of this connection * @param callback the callback for HTTP retrieval * @param host the hostname of the server to connect to * @param url the url at the server * @param data the data to send * @param depth the depth (redirect recursion) of the queries */ NetworkHTTPSocketHandler::NetworkHTTPSocketHandler(SOCKET s, HTTPCallback *callback, const char *host, const char *url, const char *data, int depth) : NetworkSocketHandler(), recv_pos(0), recv_length(0), callback(callback), data(data), redirect_depth(depth), sock(s) { size_t bufferSize = strlen(url) + strlen(host) + strlen(_openttd_revision) + (data == NULL ? 0 : strlen(data)) + 128; char *buffer = AllocaM(char, bufferSize); DEBUG(net, 7, "[tcp/http] requesting %s%s", host, url); if (data != NULL) { seprintf(buffer, buffer + bufferSize - 1, "POST %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s\r\n", url, host, _openttd_revision, (int)strlen(data), data); } else { seprintf(buffer, buffer + bufferSize - 1, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\n\r\n", url, host, _openttd_revision); } ssize_t size = strlen(buffer); ssize_t res = send(this->sock, (const char*)buffer, size, 0); if (res != size) { /* Sending all data failed. Socket can't handle this little bit * of information? Just fall back to the old system! */ this->callback->OnFailure(); delete this; return; } *_http_connections.Append() = this; } /** Free whatever needs to be freed. */ NetworkHTTPSocketHandler::~NetworkHTTPSocketHandler() { this->CloseConnection(); if (this->sock != INVALID_SOCKET) closesocket(this->sock); this->sock = INVALID_SOCKET; free(this->data); } NetworkRecvStatus NetworkHTTPSocketHandler::CloseConnection(bool error) { NetworkSocketHandler::CloseConnection(error); return NETWORK_RECV_STATUS_OKAY; } /** * Helper to simplify the error handling. * @param msg the error message to show. */ #define return_error(msg) { DEBUG(net, 0, msg); return -1; } static const char * const NEWLINE = "\r\n"; ///< End of line marker static const char * const END_OF_HEADER = "\r\n\r\n"; ///< End of header marker static const char * const HTTP_1_0 = "HTTP/1.0 "; ///< Preamble for HTTP 1.0 servers static const char * const HTTP_1_1 = "HTTP/1.1 "; ///< Preamble for HTTP 1.1 servers static const char * const CONTENT_LENGTH = "Content-Length: "; ///< Header for the length of the content static const char * const LOCATION = "Location: "; ///< Header for location /** * Handle the header of a HTTP reply. * @return amount of data to continue downloading. * > 0: we need to download N bytes. * = 0: we're being redirected. * < 0: an error occurred. Downloading failed. * @note if an error occurred the header might not be in its * original state. No effort is undertaken to bring * the header in its original state. */ int NetworkHTTPSocketHandler::HandleHeader() { assert(strlen(HTTP_1_0) == strlen(HTTP_1_1)); assert(strstr(this->recv_buffer, END_OF_HEADER) != NULL); /* We expect a HTTP/1.[01] reply */ if (strncmp(this->recv_buffer, HTTP_1_0, strlen(HTTP_1_0)) != 0 && strncmp(this->recv_buffer, HTTP_1_1, strlen(HTTP_1_1)) != 0) { return_error("[tcp/http] received invalid HTTP reply"); } char *status = this->recv_buffer + strlen(HTTP_1_0); if (strncmp(status, "200", 3) == 0) { /* We are going to receive a document. */ /* Get the length of the document to receive */ char *length = strcasestr(this->recv_buffer, CONTENT_LENGTH); if (length == NULL) return_error("[tcp/http] missing 'content-length' header"); /* Skip the header */ length += strlen(CONTENT_LENGTH); /* Search the end of the line. This is safe because the header will * always end with two newlines. */ char *end_of_line = strstr(length, NEWLINE); /* Read the length */ *end_of_line = '\0'; int len = atoi(length); /* Restore the header. */ *end_of_line = '\r'; /* Make sure we're going to download at least something; * zero sized files are, for OpenTTD's purposes, always * wrong. You can't have gzips of 0 bytes! */ if (len == 0) return_error("[tcp/http] refusing to download 0 bytes"); DEBUG(net, 7, "[tcp/http] downloading %i bytes", len); return len; } if (strncmp(status, "301", 3) != 0 && strncmp(status, "302", 3) != 0 && strncmp(status, "303", 3) != 0 && strncmp(status, "307", 3) != 0) { /* We are not going to be redirected :(. */ /* Search the end of the line. This is safe because the header will * always end with two newlines. */ *strstr(status, NEWLINE) = '\0'; DEBUG(net, 0, "[tcp/http] unhandled status reply %s", status); return -1; } if (this->redirect_depth == 5) return_error("[tcp/http] too many redirects, looping redirects?"); /* Redirect to other URL */ char *uri = strcasestr(this->recv_buffer, LOCATION); if (uri == NULL) return_error("[tcp/http] missing 'location' header for redirect"); uri += strlen(LOCATION); /* Search the end of the line. This is safe because the header will * always end with two newlines. */ char *end_of_line = strstr(uri, NEWLINE); *end_of_line = '\0'; DEBUG(net, 6, "[tcp/http] redirecting to %s", uri); int ret = NetworkHTTPSocketHandler::Connect(uri, this->callback, this->data, this->redirect_depth + 1); if (ret != 0) return ret; /* We've relinquished control of data now. */ this->data = NULL; /* Restore the header. */ *end_of_line = '\r'; return 0; } /** * Connect to the given URI. * @param uri the URI to connect to. * @param callback the callback to send data back on. * @param data the data we want to send (as POST). * @param depth the recursion/redirect depth. */ /* static */ int NetworkHTTPSocketHandler::Connect(char *uri, HTTPCallback *callback, const char *data, int depth) { char *hname = strstr(uri, "://"); if (hname == NULL) return_error("[tcp/http] invalid location"); hname += 3; char *url = strchr(hname, '/'); if (url == NULL) return_error("[tcp/http] invalid location"); *url = '\0'; /* Fetch the hostname, and possible port number. */ const char *company = NULL; const char *port = NULL; ParseConnectionString(&company, &port, hname); if (company != NULL) return_error("[tcp/http] invalid hostname"); NetworkAddress address(hname, port == NULL ? 80 : atoi(port)); /* Restore the URL. */ *url = '/'; new NetworkHTTPContentConnecter(address, callback, url, data, depth); return 0; } #undef return_error /** * Handle receiving of HTTP data. * @return state of the receival of HTTP data. * > 0: we need more cycles for downloading * = 0: we are done downloading * < 0: we have hit an error */ int NetworkHTTPSocketHandler::Receive() { for (;;) { ssize_t res = recv(this->sock, (char *)this->recv_buffer + this->recv_pos, lengthof(this->recv_buffer) - this->recv_pos, 0); if (res == -1) { int err = GET_LAST_ERROR(); if (err != EWOULDBLOCK) { /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); return -1; } /* Connection would block, so stop for now */ return 1; } /* No more data... did we get everything we wanted? */ if (res == 0) { if (this->recv_length != 0) return -1; this->callback->OnReceiveData(NULL, 0); return 0; } /* Wait till we read the end-of-header identifier */ if (this->recv_length == 0) { int read = this->recv_pos + res; int end = min(read, lengthof(this->recv_buffer) - 1); /* Do a 'safe' search for the end of the header. */ char prev = this->recv_buffer[end]; this->recv_buffer[end] = '\0'; char *end_of_header = strstr(this->recv_buffer, END_OF_HEADER); this->recv_buffer[end] = prev; if (end_of_header == NULL) { if (read == lengthof(this->recv_buffer)) { DEBUG(net, 0, "[tcp/http] header too big"); return -1; } this->recv_pos = read; } else { int ret = this->HandleHeader(); if (ret <= 0) return ret; this->recv_length = ret; end_of_header += strlen(END_OF_HEADER); int len = min(read - (end_of_header - this->recv_buffer), res); if (len != 0) { this->callback->OnReceiveData(end_of_header, len); this->recv_length -= len; } this->recv_pos = 0; } } else { res = min(this->recv_length, res); /* Receive whatever we're expecting. */ this->callback->OnReceiveData(this->recv_buffer, res); this->recv_length -= res; } } } /** * Do the receiving for all HTTP connections. */ /* static */ void NetworkHTTPSocketHandler::HTTPReceive() { /* No connections, just bail out. */ if (_http_connections.Length() == 0) return; fd_set read_fd; struct timeval tv; FD_ZERO(&read_fd); for (NetworkHTTPSocketHandler **iter = _http_connections.Begin(); iter < _http_connections.End(); iter++) { FD_SET((*iter)->sock, &read_fd); } tv.tv_sec = tv.tv_usec = 0; // don't block at all. #if !defined(__MORPHOS__) && !defined(__AMIGA__) int n = select(FD_SETSIZE, &read_fd, NULL, NULL, &tv); #else int n = WaitSelect(FD_SETSIZE, &read_fd, NULL, NULL, &tv, NULL); #endif if (n == -1) return; for (NetworkHTTPSocketHandler **iter = _http_connections.Begin(); iter < _http_connections.End(); /* nothing */) { NetworkHTTPSocketHandler *cur = *iter; if (FD_ISSET(cur->sock, &read_fd)) { int ret = cur->Receive(); /* First send the failure. */ if (ret < 0) cur->callback->OnFailure(); if (ret <= 0) { /* Then... the connection can be closed */ cur->CloseConnection(); _http_connections.Erase(iter); delete cur; continue; } } iter++; } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/core.cpp0000644000000000000000000000740612627373441016557 0ustar rootroot/* $Id: core.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 core.cpp Functions used to initialize/shut down the core network */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../../debug.h" #include "os_abstraction.h" #include "packet.h" #include "../../safeguards.h" #ifdef __MORPHOS__ /* the library base is required here */ struct Library *SocketBase = NULL; #endif /** * Initializes the network core (as that is needed for some platforms * @return true if the core has been initialized, false otherwise */ bool NetworkCoreInitialize() { #if defined(__MORPHOS__) || defined(__AMIGA__) /* * IMPORTANT NOTE: SocketBase needs to be initialized before we use _any_ * network related function, else: crash. */ DEBUG(net, 3, "[core] loading bsd socket library"); SocketBase = OpenLibrary("bsdsocket.library", 4); if (SocketBase == NULL) { DEBUG(net, 0, "[core] can't open bsdsocket.library version 4, network unavailable"); return false; } #if defined(__AMIGA__) /* for usleep() implementation (only required for legacy AmigaOS builds) */ TimerPort = CreateMsgPort(); if (TimerPort != NULL) { TimerRequest = (struct timerequest*)CreateIORequest(TimerPort, sizeof(struct timerequest); if (TimerRequest != NULL) { if (OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest*)TimerRequest, 0) == 0) { TimerBase = TimerRequest->tr_node.io_Device; if (TimerBase == NULL) { /* free resources... */ DEBUG(net, 0, "[core] can't initialize timer, network unavailable"); return false; } } } } #endif /* __AMIGA__ */ #endif /* __MORPHOS__ / __AMIGA__ */ /* Let's load the network in windows */ #ifdef WIN32 { WSADATA wsa; DEBUG(net, 3, "[core] loading windows socket library"); if (WSAStartup(MAKEWORD(2, 0), &wsa) != 0) { DEBUG(net, 0, "[core] WSAStartup failed, network unavailable"); return false; } } #endif /* WIN32 */ return true; } /** * Shuts down the network core (as that is needed for some platforms */ void NetworkCoreShutdown() { #if defined(__MORPHOS__) || defined(__AMIGA__) /* free allocated resources */ #if defined(__AMIGA__) if (TimerBase != NULL) CloseDevice((struct IORequest*)TimerRequest); // XXX This smells wrong if (TimerRequest != NULL) DeleteIORequest(TimerRequest); if (TimerPort != NULL) DeleteMsgPort(TimerPort); #endif if (SocketBase != NULL) CloseLibrary(SocketBase); #endif #if defined(WIN32) WSACleanup(); #endif } /** * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet * @param p the packet to write the data to * @param grf the GRFIdentifier to serialize */ void NetworkSocketHandler::SendGRFIdentifier(Packet *p, const GRFIdentifier *grf) { uint j; p->Send_uint32(grf->grfid); for (j = 0; j < sizeof(grf->md5sum); j++) { p->Send_uint8 (grf->md5sum[j]); } } /** * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet * @param p the packet to read the data from * @param grf the GRFIdentifier to deserialize */ void NetworkSocketHandler::ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf) { uint j; grf->grfid = p->Recv_uint32(); for (j = 0; j < sizeof(grf->md5sum); j++) { grf->md5sum[j] = p->Recv_uint8(); } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/tcp_game.cpp0000644000000000000000000003221212627373441017377 0ustar rootroot/* $Id: tcp_game.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tcp_game.cpp Basic functions to receive and send TCP packets for game purposes. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../network.h" #include "../network_internal.h" #include "../../debug.h" #include "../../error.h" #include "table/strings.h" #include "../../safeguards.h" /** * Create a new socket for the game connection. * @param s The socket to connect with. */ NetworkGameSocketHandler::NetworkGameSocketHandler(SOCKET s) : info(NULL), client_id(INVALID_CLIENT_ID), last_frame(_frame_counter), last_frame_server(_frame_counter), last_packet(_realtime_tick) { this->sock = s; } /** * Functions to help ReceivePacket/SendPacket a bit * A socket can make errors. When that happens this handles what to do. * For clients: close connection and drop back to main-menu * For servers: close connection and that is it * @return the new status */ NetworkRecvStatus NetworkGameSocketHandler::CloseConnection(bool error) { /* Clients drop back to the main menu */ if (!_network_server && _networking) { _switch_mode = SM_MENU; _networking = false; ShowErrorMessage(STR_NETWORK_ERROR_LOSTCONNECTION, INVALID_STRING_ID, WL_CRITICAL); return NETWORK_RECV_STATUS_CONN_LOST; } return this->CloseConnection(error ? NETWORK_RECV_STATUS_SERVER_ERROR : NETWORK_RECV_STATUS_CONN_LOST); } /** * Handle the given packet, i.e. pass it to the right parser receive command. * @param p the packet to handle * @return #NetworkRecvStatus of handling. */ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p) { PacketGameType type = (PacketGameType)p->Recv_uint8(); this->last_packet = _realtime_tick; switch (this->HasClientQuit() ? PACKET_END : type) { case PACKET_SERVER_FULL: return this->Receive_SERVER_FULL(p); case PACKET_SERVER_BANNED: return this->Receive_SERVER_BANNED(p); case PACKET_CLIENT_JOIN: return this->Receive_CLIENT_JOIN(p); case PACKET_SERVER_ERROR: return this->Receive_SERVER_ERROR(p); case PACKET_CLIENT_COMPANY_INFO: return this->Receive_CLIENT_COMPANY_INFO(p); case PACKET_SERVER_COMPANY_INFO: return this->Receive_SERVER_COMPANY_INFO(p); case PACKET_SERVER_CLIENT_INFO: return this->Receive_SERVER_CLIENT_INFO(p); case PACKET_SERVER_NEED_GAME_PASSWORD: return this->Receive_SERVER_NEED_GAME_PASSWORD(p); case PACKET_SERVER_NEED_COMPANY_PASSWORD: return this->Receive_SERVER_NEED_COMPANY_PASSWORD(p); case PACKET_CLIENT_GAME_PASSWORD: return this->Receive_CLIENT_GAME_PASSWORD(p); case PACKET_CLIENT_COMPANY_PASSWORD: return this->Receive_CLIENT_COMPANY_PASSWORD(p); case PACKET_SERVER_WELCOME: return this->Receive_SERVER_WELCOME(p); case PACKET_CLIENT_GETMAP: return this->Receive_CLIENT_GETMAP(p); case PACKET_SERVER_WAIT: return this->Receive_SERVER_WAIT(p); case PACKET_SERVER_MAP_BEGIN: return this->Receive_SERVER_MAP_BEGIN(p); case PACKET_SERVER_MAP_SIZE: return this->Receive_SERVER_MAP_SIZE(p); case PACKET_SERVER_MAP_DATA: return this->Receive_SERVER_MAP_DATA(p); case PACKET_SERVER_MAP_DONE: return this->Receive_SERVER_MAP_DONE(p); case PACKET_CLIENT_MAP_OK: return this->Receive_CLIENT_MAP_OK(p); case PACKET_SERVER_JOIN: return this->Receive_SERVER_JOIN(p); case PACKET_SERVER_FRAME: return this->Receive_SERVER_FRAME(p); case PACKET_SERVER_SYNC: return this->Receive_SERVER_SYNC(p); case PACKET_CLIENT_ACK: return this->Receive_CLIENT_ACK(p); case PACKET_CLIENT_COMMAND: return this->Receive_CLIENT_COMMAND(p); case PACKET_SERVER_COMMAND: return this->Receive_SERVER_COMMAND(p); case PACKET_CLIENT_CHAT: return this->Receive_CLIENT_CHAT(p); case PACKET_SERVER_CHAT: return this->Receive_SERVER_CHAT(p); case PACKET_CLIENT_SET_PASSWORD: return this->Receive_CLIENT_SET_PASSWORD(p); case PACKET_CLIENT_SET_NAME: return this->Receive_CLIENT_SET_NAME(p); case PACKET_CLIENT_QUIT: return this->Receive_CLIENT_QUIT(p); case PACKET_CLIENT_ERROR: return this->Receive_CLIENT_ERROR(p); case PACKET_SERVER_QUIT: return this->Receive_SERVER_QUIT(p); case PACKET_SERVER_ERROR_QUIT: return this->Receive_SERVER_ERROR_QUIT(p); case PACKET_SERVER_SHUTDOWN: return this->Receive_SERVER_SHUTDOWN(p); case PACKET_SERVER_NEWGAME: return this->Receive_SERVER_NEWGAME(p); case PACKET_SERVER_RCON: return this->Receive_SERVER_RCON(p); case PACKET_CLIENT_RCON: return this->Receive_CLIENT_RCON(p); case PACKET_SERVER_CHECK_NEWGRFS: return this->Receive_SERVER_CHECK_NEWGRFS(p); case PACKET_CLIENT_NEWGRFS_CHECKED: return this->Receive_CLIENT_NEWGRFS_CHECKED(p); case PACKET_SERVER_MOVE: return this->Receive_SERVER_MOVE(p); case PACKET_CLIENT_MOVE: return this->Receive_CLIENT_MOVE(p); case PACKET_SERVER_COMPANY_UPDATE: return this->Receive_SERVER_COMPANY_UPDATE(p); case PACKET_SERVER_CONFIG_UPDATE: return this->Receive_SERVER_CONFIG_UPDATE(p); default: this->CloseConnection(); if (this->HasClientQuit()) { DEBUG(net, 0, "[tcp/game] received invalid packet type %d from client %d", type, this->client_id); } else { DEBUG(net, 0, "[tcp/game] received illegal packet from client %d", this->client_id); } return NETWORK_RECV_STATUS_MALFORMED_PACKET; } } /** * Do the actual receiving of packets. * As long as HandlePacket returns OKAY packets are handled. Upon * failure, or no more packets to process the last result of * HandlePacket is returned. * @return #NetworkRecvStatus of the last handled packet. */ NetworkRecvStatus NetworkGameSocketHandler::ReceivePackets() { Packet *p; while ((p = this->ReceivePacket()) != NULL) { NetworkRecvStatus res = HandlePacket(p); delete p; if (res != NETWORK_RECV_STATUS_OKAY) return res; } return NETWORK_RECV_STATUS_OKAY; } /** * Helper for logging receiving invalid packets. * @param type The received packet type. * @return The status the network should have, in this case: "malformed packet error". */ NetworkRecvStatus NetworkGameSocketHandler::ReceiveInvalidPacket(PacketGameType type) { DEBUG(net, 0, "[tcp/game] received illegal packet type %d from client %d", type, this->client_id); return NETWORK_RECV_STATUS_MALFORMED_PACKET; } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_FULL); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_BANNED); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_JOIN); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_INFO); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_INFO); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CLIENT_INFO); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_GAME_PASSWORD); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEED_COMPANY_PASSWORD); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_PASSWORD); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_PASSWORD); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WELCOME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WELCOME); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GETMAP(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GETMAP); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_WAIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_WAIT); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_BEGIN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_BEGIN); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_SIZE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_SIZE); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DATA(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DATA); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MAP_DONE); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MAP_OK); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_JOIN); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_FRAME); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SYNC); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ACK(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ACK); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMMAND); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMMAND(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMMAND); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_CHAT); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHAT); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_PASSWORD(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_PASSWORD); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_SET_NAME); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_QUIT); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_ERROR); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_QUIT); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR_QUIT); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_SHUTDOWN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_SHUTDOWN); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_NEWGAME(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_NEWGAME); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_RCON(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_RCON); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_RCON(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_RCON); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CHECK_NEWGRFS); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_NEWGRFS_CHECKED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_NEWGRFS_CHECKED); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_MOVE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_MOVE); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_MOVE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_MOVE); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_UPDATE); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CONFIG_UPDATE); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/packet.h0000644000000000000000000000614012627373441016535 0ustar rootroot/* $Id: packet.h 23590 2011-12-18 18:37:54Z rubidium $ */ /* * 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 packet.h Basic functions to create, fill and read packets. */ #ifndef NETWORK_CORE_PACKET_H #define NETWORK_CORE_PACKET_H #include "config.h" #include "core.h" #include "../../string_type.h" #ifdef ENABLE_NETWORK typedef uint16 PacketSize; ///< Size of the whole packet. typedef uint8 PacketType; ///< Identifier for the packet /** * Internal entity of a packet. As everything is sent as a packet, * all network communication will need to call the functions that * populate the packet. * Every packet can be at most SEND_MTU bytes. Overflowing this * limit will give an assertion when sending (i.e. writing) the * packet. Reading past the size of the packet when receiving * will return all 0 values and "" in case of the string. * * --- Points of attention --- * - all > 1 byte integral values are written in little endian, * unless specified otherwise. * Thus, 0x01234567 would be sent as {0x67, 0x45, 0x23, 0x01}. * - all sent strings are of variable length and terminated by a '\0'. * Thus, the length of the strings is not sent. * - years that are leap years in the 'days since X' to 'date' calculations: * (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0)) */ struct Packet { /** The next packet. Used for queueing packets before sending. */ Packet *next; /** * The size of the whole packet for received packets. For packets * that will be sent, the value is filled in just before the * actual transmission. */ PacketSize size; /** The current read/write position in the packet */ PacketSize pos; /** The buffer of this packet, of basically variable length up to SEND_MTU. */ byte *buffer; private: /** Socket we're associated with. */ NetworkSocketHandler *cs; public: Packet(NetworkSocketHandler *cs); Packet(PacketType type); ~Packet(); /* Sending/writing of packets */ void PrepareToSend(); void Send_bool (bool data); void Send_uint8 (uint8 data); void Send_uint16(uint16 data); void Send_uint32(uint32 data); void Send_uint64(uint64 data); void Send_string(const char *data); /* Reading/receiving of packets */ void ReadRawPacketSize(); void PrepareToRead(); bool CanReadFromPacket (uint bytes_to_read); bool Recv_bool (); uint8 Recv_uint8 (); uint16 Recv_uint16(); uint32 Recv_uint32(); uint64 Recv_uint64(); void Recv_string(char *buffer, size_t size, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_PACKET_H */ openttd-1.5.3/src/network/core/tcp.cpp0000644000000000000000000001504112627373441016407 0ustar rootroot/* $Id: tcp.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tcp.cpp Basic functions to receive and send TCP packets. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../../debug.h" #include "tcp.h" #include "../../safeguards.h" /** * Construct a socket handler for a TCP connection. * @param s The just opened TCP connection. */ NetworkTCPSocketHandler::NetworkTCPSocketHandler(SOCKET s) : NetworkSocketHandler(), packet_queue(NULL), packet_recv(NULL), sock(s), writable(false) { } NetworkTCPSocketHandler::~NetworkTCPSocketHandler() { this->CloseConnection(); if (this->sock != INVALID_SOCKET) closesocket(this->sock); this->sock = INVALID_SOCKET; } NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error) { this->writable = false; NetworkSocketHandler::CloseConnection(error); /* Free all pending and partially received packets */ while (this->packet_queue != NULL) { Packet *p = this->packet_queue->next; delete this->packet_queue; this->packet_queue = p; } delete this->packet_recv; this->packet_recv = NULL; return NETWORK_RECV_STATUS_OKAY; } /** * This function puts the packet in the send-queue and it is send as * soon as possible. This is the next tick, or maybe one tick later * if the OS-network-buffer is full) * @param packet the packet to send */ void NetworkTCPSocketHandler::SendPacket(Packet *packet) { Packet *p; assert(packet != NULL); packet->PrepareToSend(); /* Reallocate the packet as in 99+% of the times we send at most 25 bytes and * keeping the other 1400+ bytes wastes memory, especially when someone tries * to do a denial of service attack! */ packet->buffer = ReallocT(packet->buffer, packet->size); /* Locate last packet buffered for the client */ p = this->packet_queue; if (p == NULL) { /* No packets yet */ this->packet_queue = packet; } else { /* Skip to the last packet */ while (p->next != NULL) p = p->next; p->next = packet; } } /** * Sends all the buffered packets out for this client. It stops when: * 1) all packets are send (queue is empty) * 2) the OS reports back that it can not send any more * data right now (full network-buffer, it happens ;)) * 3) sending took too long * @param closing_down Whether we are closing down the connection. * @return \c true if a (part of a) packet could be sent and * the connection is not closed yet. */ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) { ssize_t res; Packet *p; /* We can not write to this socket!! */ if (!this->writable) return SPS_NONE_SENT; if (!this->IsConnected()) return SPS_CLOSED; p = this->packet_queue; while (p != NULL) { res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0); if (res == -1) { int err = GET_LAST_ERROR(); if (err != EWOULDBLOCK) { /* Something went wrong.. close client! */ if (!closing_down) { DEBUG(net, 0, "send failed with error %d", err); this->CloseConnection(); } return SPS_CLOSED; } return SPS_PARTLY_SENT; } if (res == 0) { /* Client/server has left us :( */ if (!closing_down) this->CloseConnection(); return SPS_CLOSED; } p->pos += res; /* Is this packet sent? */ if (p->pos == p->size) { /* Go to the next packet */ this->packet_queue = p->next; delete p; p = this->packet_queue; } else { return SPS_PARTLY_SENT; } } return SPS_ALL_SENT; } /** * Receives a packet for the given client * @return The received packet (or NULL when it didn't receive one) */ Packet *NetworkTCPSocketHandler::ReceivePacket() { ssize_t res; if (!this->IsConnected()) return NULL; if (this->packet_recv == NULL) { this->packet_recv = new Packet(this); } Packet *p = this->packet_recv; /* Read packet size */ if (p->pos < sizeof(PacketSize)) { while (p->pos < sizeof(PacketSize)) { /* Read the size of the packet */ res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0); if (res == -1) { int err = GET_LAST_ERROR(); if (err != EWOULDBLOCK) { /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); this->CloseConnection(); return NULL; } /* Connection would block, so stop for now */ return NULL; } if (res == 0) { /* Client/server has left */ this->CloseConnection(); return NULL; } p->pos += res; } /* Read the packet size from the received packet */ p->ReadRawPacketSize(); if (p->size > SEND_MTU) { this->CloseConnection(); return NULL; } } /* Read rest of packet */ while (p->pos < p->size) { res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->pos, 0); if (res == -1) { int err = GET_LAST_ERROR(); if (err != EWOULDBLOCK) { /* Something went wrong... (104 is connection reset by peer) */ if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); this->CloseConnection(); return NULL; } /* Connection would block */ return NULL; } if (res == 0) { /* Client/server has left */ this->CloseConnection(); return NULL; } p->pos += res; } /* Prepare for receiving a new packet */ this->packet_recv = NULL; p->PrepareToRead(); return p; } /** * Check whether this socket can send or receive something. * @return \c true when there is something to receive. * @note Sets #writable if more data can be sent. */ bool NetworkTCPSocketHandler::CanSendReceive() { fd_set read_fd, write_fd; struct timeval tv; FD_ZERO(&read_fd); FD_ZERO(&write_fd); FD_SET(this->sock, &read_fd); FD_SET(this->sock, &write_fd); tv.tv_sec = tv.tv_usec = 0; // don't block at all. #if !defined(__MORPHOS__) && !defined(__AMIGA__) if (select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv) < 0) return false; #else if (WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL) < 0) return false; #endif this->writable = !!FD_ISSET(this->sock, &write_fd); return FD_ISSET(this->sock, &read_fd) != 0; } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/tcp_content.cpp0000644000000000000000000002242112627373441020141 0ustar rootroot/* $Id: tcp_content.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tcp_content.cpp Basic functions to receive and send Content packets. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #ifndef OPENTTD_MSU #include "../../textfile_gui.h" #include "../../newgrf_config.h" #include "../../base_media_base.h" #include "../../ai/ai.hpp" #include "../../game/game.hpp" #include "../../fios.h" #endif /* OPENTTD_MSU */ #include "tcp_content.h" #include "../../safeguards.h" /** Clear everything in the struct */ ContentInfo::ContentInfo() { memset(this, 0, sizeof(*this)); } /** Free everything allocated */ ContentInfo::~ContentInfo() { free(this->dependencies); free(this->tags); } /** * Copy data from other #ContentInfo and take ownership of allocated stuff. * @param other Source to copy from. #dependencies and #tags will be NULLed. */ void ContentInfo::TransferFrom(ContentInfo *other) { if (other != this) { free(this->dependencies); free(this->tags); memcpy(this, other, sizeof(ContentInfo)); other->dependencies = NULL; other->tags = NULL; } } /** * Get the size of the data as send over the network. * @return the size. */ size_t ContentInfo::Size() const { size_t len = 0; for (uint i = 0; i < this->tag_count; i++) len += strlen(this->tags[i]) + 1; /* The size is never larger than the content info size plus the size of the * tags and dependencies */ return sizeof(*this) + sizeof(this->dependency_count) + sizeof(*this->dependencies) * this->dependency_count; } /** * Is the state either selected or autoselected? * @return true iff that's the case */ bool ContentInfo::IsSelected() const { switch (this->state) { case ContentInfo::SELECTED: case ContentInfo::AUTOSELECTED: case ContentInfo::ALREADY_HERE: return true; default: return false; } } /** * Is the information from this content info valid? * @return true iff it's valid */ bool ContentInfo::IsValid() const { return this->state < ContentInfo::INVALID && this->type >= CONTENT_TYPE_BEGIN && this->type < CONTENT_TYPE_END; } #ifndef OPENTTD_MSU /** * Search a textfile file next to this file in the content list. * @param type The type of the textfile to search for. * @return The filename for the textfile, \c NULL otherwise. */ const char *ContentInfo::GetTextfile(TextfileType type) const { if (this->state == INVALID) return NULL; const char *tmp; switch (this->type) { default: NOT_REACHED(); case CONTENT_TYPE_AI: tmp = AI::GetScannerInfo()->FindMainScript(this, true); break; case CONTENT_TYPE_AI_LIBRARY: tmp = AI::GetScannerLibrary()->FindMainScript(this, true); break; case CONTENT_TYPE_GAME: tmp = Game::GetScannerInfo()->FindMainScript(this, true); break; case CONTENT_TYPE_GAME_LIBRARY: tmp = Game::GetScannerLibrary()->FindMainScript(this, true); break; case CONTENT_TYPE_NEWGRF: { const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, this->md5sum); tmp = gc != NULL ? gc->filename : NULL; break; } case CONTENT_TYPE_BASE_GRAPHICS: tmp = TryGetBaseSetFile(this, true, BaseGraphics::GetAvailableSets()); break; case CONTENT_TYPE_BASE_SOUNDS: tmp = TryGetBaseSetFile(this, true, BaseSounds::GetAvailableSets()); break; case CONTENT_TYPE_BASE_MUSIC: tmp = TryGetBaseSetFile(this, true, BaseMusic::GetAvailableSets()); break; case CONTENT_TYPE_SCENARIO: case CONTENT_TYPE_HEIGHTMAP: extern const char *FindScenario(const ContentInfo *ci, bool md5sum); tmp = FindScenario(this, true); break; } if (tmp == NULL) return NULL; return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp); } #endif /* OPENTTD_MSU */ void NetworkContentSocketHandler::Close() { CloseConnection(); if (this->sock == INVALID_SOCKET) return; closesocket(this->sock); this->sock = INVALID_SOCKET; } /** * Handle the given packet, i.e. pass it to the right * parser receive command. * @param p the packet to handle * @return true if we should immediately handle further packets, false otherwise */ bool NetworkContentSocketHandler::HandlePacket(Packet *p) { PacketContentType type = (PacketContentType)p->Recv_uint8(); switch (this->HasClientQuit() ? PACKET_CONTENT_END : type) { case PACKET_CONTENT_CLIENT_INFO_LIST: return this->Receive_CLIENT_INFO_LIST(p); case PACKET_CONTENT_CLIENT_INFO_ID: return this->Receive_CLIENT_INFO_ID(p); case PACKET_CONTENT_CLIENT_INFO_EXTID: return this->Receive_CLIENT_INFO_EXTID(p); case PACKET_CONTENT_CLIENT_INFO_EXTID_MD5: return this->Receive_CLIENT_INFO_EXTID_MD5(p); case PACKET_CONTENT_SERVER_INFO: return this->Receive_SERVER_INFO(p); case PACKET_CONTENT_CLIENT_CONTENT: return this->Receive_CLIENT_CONTENT(p); case PACKET_CONTENT_SERVER_CONTENT: return this->Receive_SERVER_CONTENT(p); default: if (this->HasClientQuit()) { DEBUG(net, 0, "[tcp/content] received invalid packet type %d from %s", type, this->client_addr.GetAddressAsString()); } else { DEBUG(net, 0, "[tcp/content] received illegal packet from %s", this->client_addr.GetAddressAsString()); } return false; } } /** * Receive a packet at TCP level * @return Whether at least one packet was received. */ bool NetworkContentSocketHandler::ReceivePackets() { /* * We read only a few of the packets. This as receiving packets can be expensive * due to the re-resolving of the parent/child relations and checking the toggle * state of all bits. We cannot do this all in one go, as we want to show the * user what we already received. Otherwise, it can take very long before any * progress is shown to the end user that something has been received. * It is also the case that we request extra content from the content server in * case there is an unknown (in the content list) piece of content. These will * come in after the main lists have been requested. As a result, we won't be * getting everything reliably in one batch. Thus, we need to make subsequent * updates in that case as well. * * As a result, we simple handle an arbitrary number of packets in one cycle, * and let the rest be handled in subsequent cycles. These are ran, almost, * immediately after this cycle so in speed it does not matter much, except * that the user inferface will appear better responding. * * What arbitrary number to choose is the ultimate question though. */ Packet *p; static const int MAX_PACKETS_TO_RECEIVE = 42; int i = MAX_PACKETS_TO_RECEIVE; while (--i != 0 && (p = this->ReceivePacket()) != NULL) { bool cont = this->HandlePacket(p); delete p; if (!cont) return true; } return i != MAX_PACKETS_TO_RECEIVE - 1; } /** * Helper for logging receiving invalid packets. * @param type The received packet type. * @return Always false, as it's an error. */ bool NetworkContentSocketHandler::ReceiveInvalidPacket(PacketContentType type) { DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s", type, this->client_addr.GetAddressAsString()); return false; } bool NetworkContentSocketHandler::Receive_CLIENT_INFO_LIST(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_LIST); } bool NetworkContentSocketHandler::Receive_CLIENT_INFO_ID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_ID); } bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID); } bool NetworkContentSocketHandler::Receive_CLIENT_INFO_EXTID_MD5(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_INFO_EXTID_MD5); } bool NetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_INFO); } bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); } bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); } #ifndef OPENTTD_MSU /** * Helper to get the subdirectory a #ContentInfo is located in. * @param type The type of content. * @return The subdirectory the content is located in. */ Subdirectory GetContentInfoSubDir(ContentType type) { switch (type) { default: return NO_DIRECTORY; case CONTENT_TYPE_AI: return AI_DIR; case CONTENT_TYPE_AI_LIBRARY: return AI_LIBRARY_DIR; case CONTENT_TYPE_GAME: return GAME_DIR; case CONTENT_TYPE_GAME_LIBRARY: return GAME_LIBRARY_DIR; case CONTENT_TYPE_NEWGRF: return NEWGRF_DIR; case CONTENT_TYPE_BASE_GRAPHICS: case CONTENT_TYPE_BASE_SOUNDS: case CONTENT_TYPE_BASE_MUSIC: return BASESET_DIR; case CONTENT_TYPE_SCENARIO: return SCENARIO_DIR; case CONTENT_TYPE_HEIGHTMAP: return HEIGHTMAP_DIR; } } #endif /* OPENTTD_MSU */ #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/udp.cpp0000644000000000000000000003272012627373441016414 0ustar rootroot/* $Id: udp.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 core/udp.cpp Basic functions to receive and send UDP packets. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../../date_func.h" #include "../../debug.h" #include "udp.h" #include "../../safeguards.h" /** * Create an UDP socket but don't listen yet. * @param bind the addresses to bind to. */ NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind) { if (bind != NULL) { for (NetworkAddress *addr = bind->Begin(); addr != bind->End(); addr++) { *this->bind.Append() = *addr; } } else { /* As hostname NULL and port 0/NULL don't go well when * resolving it we need to add an address for each of * the address families we support. */ *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET); *this->bind.Append() = NetworkAddress(NULL, 0, AF_INET6); } } /** * Start listening on the given host and port. * @return true if at least one port is listening */ bool NetworkUDPSocketHandler::Listen() { /* Make sure socket is closed */ this->Close(); for (NetworkAddress *addr = this->bind.Begin(); addr != this->bind.End(); addr++) { addr->Listen(SOCK_DGRAM, &this->sockets); } return this->sockets.Length() != 0; } /** * Close the given UDP socket */ void NetworkUDPSocketHandler::Close() { for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { closesocket(s->second); } this->sockets.Clear(); } NetworkRecvStatus NetworkUDPSocketHandler::CloseConnection(bool error) { NetworkSocketHandler::CloseConnection(error); return NETWORK_RECV_STATUS_OKAY; } /** * Send a packet over UDP * @param p the packet to send * @param recv the receiver (target) of the packet * @param all send the packet using all sockets that can send it * @param broadcast whether to send a broadcast message */ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool all, bool broadcast) { if (this->sockets.Length() == 0) this->Listen(); for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { /* Make a local copy because if we resolve it we cannot * easily unresolve it so we can resolve it later again. */ NetworkAddress send(*recv); /* Not the same type */ if (!send.IsFamily(s->first.GetAddress()->ss_family)) continue; p->PrepareToSend(); #ifndef BEOS_NET_SERVER /* will work around this, some day; maybe. */ if (broadcast) { /* Enable broadcast */ unsigned long val = 1; if (setsockopt(s->second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR()); } } #endif /* Send the buffer */ int res = sendto(s->second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength()); DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString()); /* Check for any errors, but ignore it otherwise */ if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString(), GET_LAST_ERROR()); if (!all) break; } } /** * Receive a packet at UDP level */ void NetworkUDPSocketHandler::ReceivePackets() { for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) { for (int i = 0; i < 1000; i++) { // Do not infinitely loop when DoSing with UDP struct sockaddr_storage client_addr; memset(&client_addr, 0, sizeof(client_addr)); Packet p(this); socklen_t client_len = sizeof(client_addr); /* Try to receive anything */ SetNonBlocking(s->second); // Some OSes seem to lose the non-blocking status of the socket int nbytes = recvfrom(s->second, (char*)p.buffer, SEND_MTU, 0, (struct sockaddr *)&client_addr, &client_len); /* Did we get the bytes for the base header of the packet? */ if (nbytes <= 0) break; // No data, i.e. no packet if (nbytes <= 2) continue; // Invalid data; try next packet NetworkAddress address(client_addr, client_len); p.PrepareToRead(); /* If the size does not match the packet must be corrupted. * Otherwise it will be marked as corrupted later on. */ if (nbytes != p.size) { DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString()); continue; } /* Handle the packet */ this->HandleUDPPacket(&p, &address); } } } /** * Serializes the NetworkGameInfo struct to the packet * @param p the packet to write the data to * @param info the NetworkGameInfo struct to serialize */ void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info) { p->Send_uint8 (NETWORK_GAME_INFO_VERSION); /* * Please observe the order. * The parts must be read in the same order as they are sent! */ /* Update the documentation in udp.h on changes * to the NetworkGameInfo wire-protocol! */ /* NETWORK_GAME_INFO_VERSION = 4 */ { /* Only send the GRF Identification (GRF_ID and MD5 checksum) of * the GRFs that are needed, i.e. the ones that the server has * selected in the NewGRF GUI and not the ones that are used due * to the fact that they are in [newgrf-static] in openttd.cfg */ const GRFConfig *c; uint count = 0; /* Count number of GRFs to send information about */ for (c = info->grfconfig; c != NULL; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) count++; } p->Send_uint8 (count); // Send number of GRFs /* Send actual GRF Identifications */ for (c = info->grfconfig; c != NULL; c = c->next) { if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); } } /* NETWORK_GAME_INFO_VERSION = 3 */ p->Send_uint32(info->game_date); p->Send_uint32(info->start_date); /* NETWORK_GAME_INFO_VERSION = 2 */ p->Send_uint8 (info->companies_max); p->Send_uint8 (info->companies_on); p->Send_uint8 (info->spectators_max); /* NETWORK_GAME_INFO_VERSION = 1 */ p->Send_string(info->server_name); p->Send_string(info->server_revision); p->Send_uint8 (info->server_lang); p->Send_bool (info->use_password); p->Send_uint8 (info->clients_max); p->Send_uint8 (info->clients_on); p->Send_uint8 (info->spectators_on); p->Send_string(info->map_name); p->Send_uint16(info->map_width); p->Send_uint16(info->map_height); p->Send_uint8 (info->map_set); p->Send_bool (info->dedicated); } /** * Deserializes the NetworkGameInfo struct from the packet * @param p the packet to read the data from * @param info the NetworkGameInfo to deserialize into */ void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info) { static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11 info->game_info_version = p->Recv_uint8(); /* * Please observe the order. * The parts must be read in the same order as they are sent! */ /* Update the documentation in udp.h on changes * to the NetworkGameInfo wire-protocol! */ switch (info->game_info_version) { case 4: { GRFConfig **dst = &info->grfconfig; uint i; uint num_grfs = p->Recv_uint8(); /* Broken/bad data. It cannot have that many NewGRFs. */ if (num_grfs > NETWORK_MAX_GRF_COUNT) return; for (i = 0; i < num_grfs; i++) { GRFConfig *c = new GRFConfig(); this->ReceiveGRFIdentifier(p, &c->ident); this->HandleIncomingNetworkGameInfoGRFConfig(c); /* Append GRFConfig to the list */ *dst = c; dst = &c->next; } /* FALL THROUGH */ } case 3: info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); /* FALL THROUGH */ case 2: info->companies_max = p->Recv_uint8 (); info->companies_on = p->Recv_uint8 (); info->spectators_max = p->Recv_uint8 (); /* FALL THROUGH */ case 1: p->Recv_string(info->server_name, sizeof(info->server_name)); p->Recv_string(info->server_revision, sizeof(info->server_revision)); info->server_lang = p->Recv_uint8 (); info->use_password = p->Recv_bool (); info->clients_max = p->Recv_uint8 (); info->clients_on = p->Recv_uint8 (); info->spectators_on = p->Recv_uint8 (); if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; } p->Recv_string(info->map_name, sizeof(info->map_name)); info->map_width = p->Recv_uint16(); info->map_height = p->Recv_uint16(); info->map_set = p->Recv_uint8 (); info->dedicated = p->Recv_bool (); if (info->server_lang >= NETWORK_NUM_LANGUAGES) info->server_lang = 0; if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0; } } /** * Handle an incoming packets by sending it to the correct function. * @param p the received packet * @param client_addr the sender of the packet */ void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_addr) { PacketUDPType type; /* New packet == new client, which has not quit yet */ this->Reopen(); type = (PacketUDPType)p->Recv_uint8(); switch (this->HasClientQuit() ? PACKET_UDP_END : type) { case PACKET_UDP_CLIENT_FIND_SERVER: this->Receive_CLIENT_FIND_SERVER(p, client_addr); break; case PACKET_UDP_SERVER_RESPONSE: this->Receive_SERVER_RESPONSE(p, client_addr); break; case PACKET_UDP_CLIENT_DETAIL_INFO: this->Receive_CLIENT_DETAIL_INFO(p, client_addr); break; case PACKET_UDP_SERVER_DETAIL_INFO: this->Receive_SERVER_DETAIL_INFO(p, client_addr); break; case PACKET_UDP_SERVER_REGISTER: this->Receive_SERVER_REGISTER(p, client_addr); break; case PACKET_UDP_MASTER_ACK_REGISTER: this->Receive_MASTER_ACK_REGISTER(p, client_addr); break; case PACKET_UDP_CLIENT_GET_LIST: this->Receive_CLIENT_GET_LIST(p, client_addr); break; case PACKET_UDP_MASTER_RESPONSE_LIST: this->Receive_MASTER_RESPONSE_LIST(p, client_addr); break; case PACKET_UDP_SERVER_UNREGISTER: this->Receive_SERVER_UNREGISTER(p, client_addr); break; case PACKET_UDP_CLIENT_GET_NEWGRFS: this->Receive_CLIENT_GET_NEWGRFS(p, client_addr); break; case PACKET_UDP_SERVER_NEWGRFS: this->Receive_SERVER_NEWGRFS(p, client_addr); break; case PACKET_UDP_MASTER_SESSION_KEY: this->Receive_MASTER_SESSION_KEY(p, client_addr); break; default: if (this->HasClientQuit()) { DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString()); } else { DEBUG(net, 0, "[udp] received illegal packet from %s", client_addr->GetAddressAsString()); } break; } } /** * Helper for logging receiving invalid packets. * @param type The received packet type. * @param client_addr The address we received the packet from. */ void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type, NetworkAddress *client_addr) { DEBUG(net, 0, "[udp] received packet type %d on wrong port from %s", type, client_addr->GetAddressAsString()); } void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); } void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE, client_addr); } void NetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_DETAIL_INFO, client_addr); } void NetworkUDPSocketHandler::Receive_SERVER_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_DETAIL_INFO, client_addr); } void NetworkUDPSocketHandler::Receive_SERVER_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_REGISTER, client_addr); } void NetworkUDPSocketHandler::Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_ACK_REGISTER, client_addr); } void NetworkUDPSocketHandler::Receive_CLIENT_GET_LIST(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_LIST, client_addr); } void NetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_RESPONSE_LIST, client_addr); } void NetworkUDPSocketHandler::Receive_SERVER_UNREGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_UNREGISTER, client_addr); } void NetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_GET_NEWGRFS, client_addr); } void NetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_NEWGRFS, client_addr); } void NetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_MASTER_SESSION_KEY, client_addr); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/tcp.h0000644000000000000000000000641212627373441016056 0ustar rootroot/* $Id: tcp.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 tcp.h Basic functions to receive and send TCP packets. */ #ifndef NETWORK_CORE_TCP_H #define NETWORK_CORE_TCP_H #include "address.h" #include "packet.h" #ifdef ENABLE_NETWORK /** The states of sending the packets. */ enum SendPacketsState { SPS_CLOSED, ///< The connection got closed. SPS_NONE_SENT, ///< The buffer is still full, so no (parts of) packets could be sent. SPS_PARTLY_SENT, ///< The packets are partly sent; there are more packets to be sent in the queue. SPS_ALL_SENT, ///< All packets in the queue are sent. }; /** Base socket handler for all TCP sockets */ class NetworkTCPSocketHandler : public NetworkSocketHandler { private: Packet *packet_queue; ///< Packets that are awaiting delivery Packet *packet_recv; ///< Partially received packet public: SOCKET sock; ///< The socket currently connected to bool writable; ///< Can we write to this socket? /** * Whether this socket is currently bound to a socket. * @return true when the socket is bound, false otherwise */ bool IsConnected() const { return this->sock != INVALID_SOCKET; } virtual NetworkRecvStatus CloseConnection(bool error = true); virtual void SendPacket(Packet *packet); SendPacketsState SendPackets(bool closing_down = false); virtual Packet *ReceivePacket(); bool CanSendReceive(); /** * Whether there is something pending in the send queue. * @return true when something is pending in the send queue. */ bool HasSendQueue() { return this->packet_queue != NULL; } NetworkTCPSocketHandler(SOCKET s = INVALID_SOCKET); ~NetworkTCPSocketHandler(); }; /** * "Helper" class for creating TCP connections in a non-blocking manner */ class TCPConnecter { private: class ThreadObject *thread; ///< Thread used to create the TCP connection bool connected; ///< Whether we succeeded in making the connection bool aborted; ///< Whether we bailed out (i.e. connection making failed) bool killed; ///< Whether we got killed SOCKET sock; ///< The socket we're connecting with void Connect(); static void ThreadEntry(void *param); protected: /** Address we're connecting to */ NetworkAddress address; public: TCPConnecter(const NetworkAddress &address); /** Silence the warnings */ virtual ~TCPConnecter() {} /** * Callback when the connection succeeded. * @param s the socket that we opened */ virtual void OnConnect(SOCKET s) {} /** * Callback for when the connection attempt failed. */ virtual void OnFailure() {} static void CheckCallbacks(); static void KillAll(); }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_TCP_H */ openttd-1.5.3/src/network/core/address.cpp0000644000000000000000000003322612627373441017253 0ustar rootroot/* $Id: address.cpp 27092 2014-12-24 17:17:18Z frosch $ */ /* * 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 core/address.cpp Implementation of the address. */ #include "../../stdafx.h" #ifdef ENABLE_NETWORK #include "address.h" #include "../../debug.h" #include "../../safeguards.h" /** * Get the hostname; in case it wasn't given the * IPv4 dotted representation is given. * @return the hostname */ const char *NetworkAddress::GetHostname() { if (StrEmpty(this->hostname) && this->address.ss_family != AF_UNSPEC) { assert(this->address_length != 0); getnameinfo((struct sockaddr *)&this->address, this->address_length, this->hostname, sizeof(this->hostname), NULL, 0, NI_NUMERICHOST); } return this->hostname; } /** * Get the port. * @return the port. */ uint16 NetworkAddress::GetPort() const { switch (this->address.ss_family) { case AF_UNSPEC: case AF_INET: return ntohs(((const struct sockaddr_in *)&this->address)->sin_port); case AF_INET6: return ntohs(((const struct sockaddr_in6 *)&this->address)->sin6_port); default: NOT_REACHED(); } } /** * Set the port. * @param port set the port number. */ void NetworkAddress::SetPort(uint16 port) { switch (this->address.ss_family) { case AF_UNSPEC: case AF_INET: ((struct sockaddr_in*)&this->address)->sin_port = htons(port); break; case AF_INET6: ((struct sockaddr_in6*)&this->address)->sin6_port = htons(port); break; default: NOT_REACHED(); } } /** * Get the address as a string, e.g. 127.0.0.1:12345. * @param buffer the buffer to write to * @param last the last element in the buffer * @param with_family whether to add the family (e.g. IPvX). */ void NetworkAddress::GetAddressAsString(char *buffer, const char *last, bool with_family) { if (this->GetAddress()->ss_family == AF_INET6) buffer = strecpy(buffer, "[", last); buffer = strecpy(buffer, this->GetHostname(), last); if (this->GetAddress()->ss_family == AF_INET6) buffer = strecpy(buffer, "]", last); buffer += seprintf(buffer, last, ":%d", this->GetPort()); if (with_family) { char family; switch (this->address.ss_family) { case AF_INET: family = '4'; break; case AF_INET6: family = '6'; break; default: family = '?'; break; } seprintf(buffer, last, " (IPv%c)", family); } } /** * Get the address as a string, e.g. 127.0.0.1:12345. * @param with_family whether to add the family (e.g. IPvX). * @return the address * @note NOT thread safe */ const char *NetworkAddress::GetAddressAsString(bool with_family) { /* 6 = for the : and 5 for the decimal port number */ static char buf[NETWORK_HOSTNAME_LENGTH + 6 + 7]; this->GetAddressAsString(buf, lastof(buf), with_family); return buf; } /** * Helper function to resolve without opening a socket. * @param runp information about the socket to try not * @return the opened socket or INVALID_SOCKET */ static SOCKET ResolveLoopProc(addrinfo *runp) { /* We just want the first 'entry', so return a valid socket. */ return !INVALID_SOCKET; } /** * Get the address in its internal representation. * @return the address */ const sockaddr_storage *NetworkAddress::GetAddress() { if (!this->IsResolved()) { /* Here we try to resolve a network address. We use SOCK_STREAM as * socket type because some stupid OSes, like Solaris, cannot be * bothered to implement the specifications and allow '0' as value * that means "don't care whether it is SOCK_STREAM or SOCK_DGRAM". */ this->Resolve(this->address.ss_family, SOCK_STREAM, AI_ADDRCONFIG, NULL, ResolveLoopProc); this->resolved = true; } return &this->address; } /** * Checks of this address is of the given family. * @param family the family to check against * @return true if it is of the given family */ bool NetworkAddress::IsFamily(int family) { if (!this->IsResolved()) { this->Resolve(family, SOCK_STREAM, AI_ADDRCONFIG, NULL, ResolveLoopProc); } return this->address.ss_family == family; } /** * Checks whether this IP address is contained by the given netmask. * @param netmask the netmask in CIDR notation to test against. * @note netmask without /n assumes all bits need to match. * @return true if this IP is within the netmask. */ bool NetworkAddress::IsInNetmask(char *netmask) { /* Resolve it if we didn't do it already */ if (!this->IsResolved()) this->GetAddress(); int cidr = this->address.ss_family == AF_INET ? 32 : 128; NetworkAddress mask_address; /* Check for CIDR separator */ char *chr_cidr = strchr(netmask, '/'); if (chr_cidr != NULL) { int tmp_cidr = atoi(chr_cidr + 1); /* Invalid CIDR, treat as single host */ if (tmp_cidr > 0 || tmp_cidr < cidr) cidr = tmp_cidr; /* Remove and then replace the / so that NetworkAddress works on the IP portion */ *chr_cidr = '\0'; mask_address = NetworkAddress(netmask, 0, this->address.ss_family); *chr_cidr = '/'; } else { mask_address = NetworkAddress(netmask, 0, this->address.ss_family); } if (mask_address.GetAddressLength() == 0) return false; uint32 *ip; uint32 *mask; switch (this->address.ss_family) { case AF_INET: ip = (uint32*)&((struct sockaddr_in*)&this->address)->sin_addr.s_addr; mask = (uint32*)&((struct sockaddr_in*)&mask_address.address)->sin_addr.s_addr; break; case AF_INET6: ip = (uint32*)&((struct sockaddr_in6*)&this->address)->sin6_addr; mask = (uint32*)&((struct sockaddr_in6*)&mask_address.address)->sin6_addr; break; default: NOT_REACHED(); } while (cidr > 0) { uint32 msk = cidr >= 32 ? (uint32)-1 : htonl(-(1 << (32 - cidr))); if ((*mask++ & msk) != (*ip++ & msk)) return false; cidr -= 32; } return true; } /** * Resolve this address into a socket * @param family the type of 'protocol' (IPv4, IPv6) * @param socktype the type of socket (TCP, UDP, etc) * @param flags the flags to send to getaddrinfo * @param sockets the list of sockets to add the sockets to * @param func the inner working while looping over the address info * @return the resolved socket or INVALID_SOCKET. */ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *sockets, LoopProc func) { struct addrinfo *ai; struct addrinfo hints; memset(&hints, 0, sizeof (hints)); hints.ai_family = family; hints.ai_flags = flags; hints.ai_socktype = socktype; /* The port needs to be a string. Six is enough to contain all characters + '\0'. */ char port_name[6]; seprintf(port_name, lastof(port_name), "%u", this->GetPort()); bool reset_hostname = false; /* Setting both hostname to NULL and port to 0 is not allowed. * As port 0 means bind to any port, the other must mean that * we want to bind to 'all' IPs. */ if (StrEmpty(this->hostname) && this->address_length == 0 && this->GetPort() == 0) { reset_hostname = true; int fam = this->address.ss_family; if (fam == AF_UNSPEC) fam = family; strecpy(this->hostname, fam == AF_INET ? "0.0.0.0" : "::", lastof(this->hostname)); } int e = getaddrinfo(StrEmpty(this->hostname) ? NULL : this->hostname, port_name, &hints, &ai); if (reset_hostname) strecpy(this->hostname, "", lastof(this->hostname)); if (e != 0) { if (func != ResolveLoopProc) { DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s failed: %s", this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e))); } return INVALID_SOCKET; } SOCKET sock = INVALID_SOCKET; for (struct addrinfo *runp = ai; runp != NULL; runp = runp->ai_next) { /* When we are binding to multiple sockets, make sure we do not * connect to one with exactly the same address twice. That's * of course totally unneeded ;) */ if (sockets != NULL) { NetworkAddress address(runp->ai_addr, (int)runp->ai_addrlen); if (sockets->Contains(address)) continue; } sock = func(runp); if (sock == INVALID_SOCKET) continue; if (sockets == NULL) { this->address_length = (int)runp->ai_addrlen; assert(sizeof(this->address) >= runp->ai_addrlen); memcpy(&this->address, runp->ai_addr, runp->ai_addrlen); break; } NetworkAddress addr(runp->ai_addr, (int)runp->ai_addrlen); (*sockets)[addr] = sock; sock = INVALID_SOCKET; } freeaddrinfo (ai); return sock; } /** * Helper function to resolve a connected socket. * @param runp information about the socket to try not * @return the opened socket or INVALID_SOCKET */ static SOCKET ConnectLoopProc(addrinfo *runp) { const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype); const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family); const char *address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(); SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, strerror(errno)); return INVALID_SOCKET; } if (!SetNoDelay(sock)) DEBUG(net, 1, "[%s] setting TCP_NODELAY failed", type); if (connect(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) { DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno)); closesocket(sock); return INVALID_SOCKET; } /* Connection succeeded */ if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed", type); DEBUG(net, 1, "[%s] connected to %s", type, address); return sock; } /** * Connect to the given address. * @return the connected socket or INVALID_SOCKET. */ SOCKET NetworkAddress::Connect() { DEBUG(net, 1, "Connecting to %s", this->GetAddressAsString()); return this->Resolve(AF_UNSPEC, SOCK_STREAM, AI_ADDRCONFIG, NULL, ConnectLoopProc); } /** * Helper function to resolve a listening. * @param runp information about the socket to try not * @return the opened socket or INVALID_SOCKET */ static SOCKET ListenLoopProc(addrinfo *runp) { const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype); const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family); const char *address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(); SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address, strerror(errno)); return INVALID_SOCKET; } if (runp->ai_socktype == SOCK_STREAM && !SetNoDelay(sock)) { DEBUG(net, 3, "[%s] setting TCP_NODELAY failed for port %s", type, address); } int on = 1; /* The (const char*) cast is needed for windows!! */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address, strerror(errno)); } #ifndef __OS2__ if (runp->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) { DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address, strerror(errno)); } #endif if (bind(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) { DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address, strerror(errno)); closesocket(sock); return INVALID_SOCKET; } if (runp->ai_socktype != SOCK_DGRAM && listen(sock, 1) != 0) { DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address, strerror(errno)); closesocket(sock); return INVALID_SOCKET; } /* Connection succeeded */ if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed for %s port %s", type, family, address); DEBUG(net, 1, "[%s] listening on %s port %s", type, family, address); return sock; } /** * Make the given socket listen. * @param socktype the type of socket (TCP, UDP, etc) * @param sockets the list of sockets to add the sockets to */ void NetworkAddress::Listen(int socktype, SocketList *sockets) { assert(sockets != NULL); /* Setting both hostname to NULL and port to 0 is not allowed. * As port 0 means bind to any port, the other must mean that * we want to bind to 'all' IPs. */ if (this->address_length == 0 && this->address.ss_family == AF_UNSPEC && StrEmpty(this->hostname) && this->GetPort() == 0) { this->Resolve(AF_INET, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc); this->Resolve(AF_INET6, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc); } else { this->Resolve(AF_UNSPEC, socktype, AI_ADDRCONFIG | AI_PASSIVE, sockets, ListenLoopProc); } } /** * Convert the socket type into a string * @param socktype the socket type to convert * @return the string representation * @note only works for SOCK_STREAM and SOCK_DGRAM */ /* static */ const char *NetworkAddress::SocketTypeAsString(int socktype) { switch (socktype) { case SOCK_STREAM: return "tcp"; case SOCK_DGRAM: return "udp"; default: return "unsupported"; } } /** * Convert the address family into a string * @param family the family to convert * @return the string representation * @note only works for AF_INET, AF_INET6 and AF_UNSPEC */ /* static */ const char *NetworkAddress::AddressFamilyAsString(int family) { switch (family) { case AF_UNSPEC: return "either IPv4 or IPv6"; case AF_INET: return "IPv4"; case AF_INET6: return "IPv6"; default: return "unsupported"; } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/tcp_listen.h0000644000000000000000000001224612627373441017436 0ustar rootroot/* $Id: tcp_listen.h 26046 2013-11-22 21:41:19Z rubidium $ */ /* * 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 tcp_listen.h Basic functions to listen for TCP connections. */ #ifndef NETWORK_CORE_TCP_LISTEN_H #define NETWORK_CORE_TCP_LISTEN_H #include "tcp.h" #include "../network.h" #include "../../core/pool_type.hpp" #include "../../debug.h" #include "table/strings.h" #ifdef ENABLE_NETWORK /** * Template for TCP listeners. * @param Tsocket The class we create sockets for. * @param Tfull_packet The packet type to return when we don't allow more sockets. * @param Tban_packet The packet type to return when the client is banned. */ template class TCPListenHandler { /** List of sockets we listen on. */ static SocketList sockets; public: /** * Accepts clients from the sockets. * @param ls Socket to accept clients from. */ static void AcceptClient(SOCKET ls) { for (;;) { struct sockaddr_storage sin; memset(&sin, 0, sizeof(sin)); socklen_t sin_len = sizeof(sin); SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len); if (s == INVALID_SOCKET) return; SetNonBlocking(s); // XXX error handling? NetworkAddress address(sin, sin_len); DEBUG(net, 1, "[%s] Client connected from %s on frame %d", Tsocket::GetName(), address.GetHostname(), _frame_counter); SetNoDelay(s); // XXX error handling? /* Check if the client is banned */ bool banned = false; for (char **iter = _network_ban_list.Begin(); iter != _network_ban_list.End(); iter++) { banned = address.IsInNetmask(*iter); if (banned) { Packet p(Tban_packet); p.PrepareToSend(); DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), *iter); if (send(s, (const char*)p.buffer, p.size, 0) < 0) { DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); } closesocket(s); break; } } /* If this client is banned, continue with next client */ if (banned) continue; /* Can we handle a new client? */ if (!Tsocket::AllowConnection()) { /* no more clients allowed? * Send to the client that we are full! */ Packet p(Tfull_packet); p.PrepareToSend(); if (send(s, (const char*)p.buffer, p.size, 0) < 0) { DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); } closesocket(s); continue; } Tsocket::AcceptConnection(s, address); } } /** * Handle the receiving of packets. * @return true if everything went okay. */ static bool Receive() { fd_set read_fd, write_fd; struct timeval tv; FD_ZERO(&read_fd); FD_ZERO(&write_fd); Tsocket *cs; FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) { FD_SET(cs->sock, &read_fd); FD_SET(cs->sock, &write_fd); } /* take care of listener port */ for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) { FD_SET(s->second, &read_fd); } tv.tv_sec = tv.tv_usec = 0; // don't block at all. #if !defined(__MORPHOS__) && !defined(__AMIGA__) if (select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv) < 0) return false; #else if (WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL) < 0) return false; #endif /* accept clients.. */ for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) { if (FD_ISSET(s->second, &read_fd)) AcceptClient(s->second); } /* read stuff from clients */ FOR_ALL_ITEMS_FROM(Tsocket, idx, cs, 0) { cs->writable = !!FD_ISSET(cs->sock, &write_fd); if (FD_ISSET(cs->sock, &read_fd)) { cs->ReceivePackets(); } } return _networking; } /** * Listen on a particular port. * @param port The port to listen on. * @return true if listening succeeded. */ static bool Listen(uint16 port) { assert(sockets.Length() == 0); NetworkAddressList addresses; GetBindAddresses(&addresses, port); for (NetworkAddress *address = addresses.Begin(); address != addresses.End(); address++) { address->Listen(SOCK_STREAM, &sockets); } if (sockets.Length() == 0) { DEBUG(net, 0, "[server] could not start network: could not create listening socket"); NetworkError(STR_NETWORK_ERROR_SERVER_START); return false; } return true; } /** Close the sockets we're listening on. */ static void CloseListeners() { for (SocketList::iterator s = sockets.Begin(); s != sockets.End(); s++) { closesocket(s->second); } sockets.Clear(); DEBUG(net, 1, "[%s] closed listeners", Tsocket::GetName()); } }; template SocketList TCPListenHandler::sockets; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_TCP_LISTEN_H */ openttd-1.5.3/src/network/core/game.h0000644000000000000000000000617212627373441016204 0ustar rootroot/* $Id: game.h 17699 2009-10-04 20:00:56Z rubidium $ */ /* * 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 game.h Information about a game that is sent between a * game server, game client and masterserver. */ #ifndef NETWORK_CORE_GAME_H #define NETWORK_CORE_GAME_H #include "config.h" #include "../../newgrf_config.h" #include "../../date_type.h" #ifdef ENABLE_NETWORK /** * The game information that is not generated on-the-fly and has to * be sent to the clients. */ struct NetworkServerGameInfo { char map_name[NETWORK_NAME_LENGTH]; ///< Map which is played ["random" for a randomized map] byte clients_on; ///< Current count of clients on server }; /** * The game information that is sent from the server to the clients. */ struct NetworkGameInfo : NetworkServerGameInfo { GRFConfig *grfconfig; ///< List of NewGRF files used Date start_date; ///< When the game started Date game_date; ///< Current date uint16 map_width; ///< Map width uint16 map_height; ///< Map height char server_name[NETWORK_NAME_LENGTH]; ///< Server name char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any) char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) bool dedicated; ///< Is this a dedicated server? bool version_compatible; ///< Can we connect to this server or not? (based on server_revision) bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match bool use_password; ///< Is this server passworded? byte game_info_version; ///< Version of the game info byte server_lang; ///< Language of the server (we should make a nice table for this) byte clients_max; ///< Max clients allowed on server byte companies_on; ///< How many started companies do we have byte companies_max; ///< Max companies allowed on server byte spectators_on; ///< How many spectators do we have? byte spectators_max; ///< Max spectators allowed on server byte map_set; ///< Graphical set }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_GAME_H */ openttd-1.5.3/src/network/core/tcp_content.h0000644000000000000000000002040012627373441017601 0ustar rootroot/* $Id: tcp_content.h 25597 2013-07-13 09:26:11Z rubidium $ */ /* * 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 tcp_content.h Basic functions to receive and send TCP packets to/from the content server. */ #ifndef NETWORK_CORE_TCP_CONTENT_H #define NETWORK_CORE_TCP_CONTENT_H #include "os_abstraction.h" #include "tcp.h" #include "packet.h" #include "../../debug.h" #ifdef ENABLE_NETWORK /** The values in the enum are important; they are used as database 'keys' */ enum ContentType { CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types CONTENT_TYPE_BASE_GRAPHICS = 1, ///< The content consists of base graphics CONTENT_TYPE_NEWGRF = 2, ///< The content consists of a NewGRF CONTENT_TYPE_AI = 3, ///< The content consists of an AI CONTENT_TYPE_AI_LIBRARY = 4, ///< The content consists of an AI library CONTENT_TYPE_SCENARIO = 5, ///< The content consists of a scenario CONTENT_TYPE_HEIGHTMAP = 6, ///< The content consists of a heightmap CONTENT_TYPE_BASE_SOUNDS = 7, ///< The content consists of base sounds CONTENT_TYPE_BASE_MUSIC = 8, ///< The content consists of base music CONTENT_TYPE_GAME = 9, ///< The content consists of a game script CONTENT_TYPE_GAME_LIBRARY = 10, ///< The content consists of a GS library CONTENT_TYPE_END, ///< Helper to mark the end of the types }; /** Enum with all types of TCP content packets. The order MUST not be changed **/ enum PacketContentType { PACKET_CONTENT_CLIENT_INFO_LIST, ///< Queries the content server for a list of info of a given content type PACKET_CONTENT_CLIENT_INFO_ID, ///< Queries the content server for information about a list of internal IDs PACKET_CONTENT_CLIENT_INFO_EXTID, ///< Queries the content server for information about a list of external IDs PACKET_CONTENT_CLIENT_INFO_EXTID_MD5, ///< Queries the content server for information about a list of external IDs and MD5 PACKET_CONTENT_SERVER_INFO, ///< Reply of content server with information about content PACKET_CONTENT_CLIENT_CONTENT, ///< Request a content file given an internal ID PACKET_CONTENT_SERVER_CONTENT, ///< Reply with the content of the given ID PACKET_CONTENT_END, ///< Must ALWAYS be on the end of this list!! (period) }; /** Unique identifier for the content. */ enum ContentID { INVALID_CONTENT_ID = UINT32_MAX, ///< Sentinel for invalid content. }; /** Container for all important information about a piece of content. */ struct ContentInfo { /** The state the content can be in. */ enum State { UNSELECTED, ///< The content has not been selected SELECTED, ///< The content has been manually selected AUTOSELECTED, ///< The content has been selected as dependency ALREADY_HERE, ///< The content is already at the client side DOES_NOT_EXIST, ///< The content does not exist in the content system INVALID, ///< The content's invalid }; ContentType type; ///< Type of content ContentID id; ///< Unique (server side) ID for the content uint32 filesize; ///< Size of the file char filename[48]; ///< Filename (for the .tar.gz; only valid on download) char name[32]; ///< Name of the content char version[16]; ///< Version of the content char url[96]; ///< URL related to the content char description[512]; ///< Description of the content uint32 unique_id; ///< Unique ID; either GRF ID or shortname byte md5sum[16]; ///< The MD5 checksum uint8 dependency_count; ///< Number of dependencies ContentID *dependencies; ///< Malloced array of dependencies (unique server side ids) uint8 tag_count; ///< Number of tags char (*tags)[32]; ///< Malloced array of tags (strings) State state; ///< Whether the content info is selected (for download) bool upgrade; ///< This item is an upgrade ContentInfo(); ~ContentInfo(); void TransferFrom(ContentInfo *other); size_t Size() const; bool IsSelected() const; bool IsValid() const; #ifndef OPENTTD_MSU const char *GetTextfile(TextfileType type) const; #endif /* OPENTTD_MSU */ }; /** Base socket handler for all Content TCP sockets */ class NetworkContentSocketHandler : public NetworkTCPSocketHandler { protected: NetworkAddress client_addr; ///< The address we're connected to. virtual void Close(); bool ReceiveInvalidPacket(PacketContentType type); /** * Client requesting a list of content info: * byte type * uint32 openttd version * @param p The packet that was just received. * @return True upon success, otherwise false. */ virtual bool Receive_CLIENT_INFO_LIST(Packet *p); /** * Client requesting a list of content info: * uint16 count of ids * uint32 id (count times) * @param p The packet that was just received. * @return True upon success, otherwise false. */ virtual bool Receive_CLIENT_INFO_ID(Packet *p); /** * Client requesting a list of content info based on an external * 'unique' id; GRF ID for NewGRFS, shortname and for base * graphics and AIs. * Scenarios and AI libraries are not supported * uint8 count of requests * for each request: * uint8 type * unique id (uint32) * @param p The packet that was just received. * @return True upon success, otherwise false. */ virtual bool Receive_CLIENT_INFO_EXTID(Packet *p); /** * Client requesting a list of content info based on an external * 'unique' id; GRF ID + MD5 checksum for NewGRFS, shortname and * xor-ed MD5 checksums for base graphics and AIs. * Scenarios and AI libraries are not supported * uint8 count of requests * for each request: * uint8 type * unique id (uint32) * md5 (16 bytes) * @param p The packet that was just received. * @return True upon success, otherwise false. */ virtual bool Receive_CLIENT_INFO_EXTID_MD5(Packet *p); /** * Server sending list of content info: * byte type (invalid ID == does not exist) * uint32 id * uint32 file_size * string name (max 32 characters) * string version (max 16 characters) * uint32 unique id * uint8 md5sum (16 bytes) * uint8 dependency count * uint32 unique id of dependency (dependency count times) * uint8 tag count * string tag (max 32 characters for tag count times) * @param p The packet that was just received. * @return True upon success, otherwise false. */ virtual bool Receive_SERVER_INFO(Packet *p); /** * Client requesting the actual content: * uint16 count of unique ids * uint32 unique id (count times) * @param p The packet that was just received. * @return True upon success, otherwise false. */ virtual bool Receive_CLIENT_CONTENT(Packet *p); /** * Server sending list of content info: * uint32 unique id * uint32 file size (0 == does not exist) * string file name (max 48 characters) * After this initial packet, packets with the actual data are send using * the same packet type. * @param p The packet that was just received. * @return True upon success, otherwise false. */ virtual bool Receive_SERVER_CONTENT(Packet *p); bool HandlePacket(Packet *p); public: /** * Create a new cs socket handler for a given cs * @param s the socket we are connected with * @param address IP etc. of the client */ NetworkContentSocketHandler(SOCKET s = INVALID_SOCKET, const NetworkAddress &address = NetworkAddress()) : NetworkTCPSocketHandler(s), client_addr(address) { } /** On destructing of this class, the socket needs to be closed */ virtual ~NetworkContentSocketHandler() { this->Close(); } bool ReceivePackets(); }; #ifndef OPENTTD_MSU Subdirectory GetContentInfoSubDir(ContentType type); #endif /* OPENTTD_MSU */ #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_TCP_CONTENT_H */ openttd-1.5.3/src/network/core/udp.h0000644000000000000000000002346312627373441016065 0ustar rootroot/* $Id: udp.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 core/udp.h Basic functions to receive and send UDP packets. */ #ifndef NETWORK_CORE_UDP_H #define NETWORK_CORE_UDP_H #include "address.h" #include "game.h" #include "packet.h" #ifdef ENABLE_NETWORK /** Enum with all types of UDP packets. The order MUST not be changed **/ enum PacketUDPType { PACKET_UDP_CLIENT_FIND_SERVER, ///< Queries a game server for game information PACKET_UDP_SERVER_RESPONSE, ///< Reply of the game server with game information PACKET_UDP_CLIENT_DETAIL_INFO, ///< Queries a game server about details of the game, such as companies PACKET_UDP_SERVER_DETAIL_INFO, ///< Reply of the game server about details of the game, such as companies PACKET_UDP_SERVER_REGISTER, ///< Packet to register itself to the master server PACKET_UDP_MASTER_ACK_REGISTER, ///< Packet indicating registration has succeeded PACKET_UDP_CLIENT_GET_LIST, ///< Request for serverlist from master server PACKET_UDP_MASTER_RESPONSE_LIST, ///< Response from master server with server ip's + port's PACKET_UDP_SERVER_UNREGISTER, ///< Request to be removed from the server-list PACKET_UDP_CLIENT_GET_NEWGRFS, ///< Requests the name for a list of GRFs (GRF_ID and MD5) PACKET_UDP_SERVER_NEWGRFS, ///< Sends the list of NewGRF's requested. PACKET_UDP_MASTER_SESSION_KEY, ///< Sends a fresh session key to the client PACKET_UDP_END, ///< Must ALWAYS be on the end of this list!! (period) }; /** The types of server lists we can get */ enum ServerListType { SLT_IPv4 = 0, ///< Get the IPv4 addresses SLT_IPv6 = 1, ///< Get the IPv6 addresses SLT_AUTODETECT, ///< Autodetect the type based on the connection SLT_END = SLT_AUTODETECT, ///< End of 'arrays' marker }; /** Base socket handler for all UDP sockets */ class NetworkUDPSocketHandler : public NetworkSocketHandler { protected: /** The address to bind to. */ NetworkAddressList bind; /** The opened sockets. */ SocketList sockets; NetworkRecvStatus CloseConnection(bool error = true); void ReceiveInvalidPacket(PacketUDPType, NetworkAddress *client_addr); /** * Queries to the server for information about the game. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr); /** * Return of server information to the client. * This packet has several legacy versions, so we list the version and size of each "field": * * Version: Bytes: Description: * all 1 the version of this packet's structure * * 4+ 1 number of GRFs attached (n) * 4+ n * 20 unique identifier for GRF files. Consists of: * - one 4 byte variable with the GRF ID * - 16 bytes (sent sequentially) for the MD5 checksum * of the GRF * * 3+ 4 current game date in days since 1-1-0 (DMY) * 3+ 4 game introduction date in days since 1-1-0 (DMY) * * 2+ 1 maximum number of companies allowed on the server * 2+ 1 number of companies on the server * 2+ 1 maximum number of spectators allowed on the server * * 1+ var string with the name of the server * 1+ var string with the revision of the server * 1+ 1 the language run on the server * (0 = any, 1 = English, 2 = German, 3 = French) * 1+ 1 whether the server uses a password (0 = no, 1 = yes) * 1+ 1 maximum number of clients allowed on the server * 1+ 1 number of clients on the server * 1+ 1 number of spectators on the server * 1 & 2 2 current game date in days since 1-1-1920 (DMY) * 1 & 2 2 game introduction date in days since 1-1-1920 (DMY) * 1+ var string with the name of the map * 1+ 2 width of the map in tiles * 1+ 2 height of the map in tiles * 1+ 1 type of map: * (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland) * 1+ 1 whether the server is dedicated (0 = no, 1 = yes) * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr); /** * Query for detailed information about companies. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr); /** * Reply with detailed company information. * uint8 Version of the packet. * uint8 Number of companies. * For each company: * uint8 ID of the company. * string Name of the company. * uint32 Year the company was inaugurated. * uint64 Value. * uint64 Money. * uint64 Income. * uint16 Performance (last quarter). * bool Company is password protected. * uint16 Number of trains. * uint16 Number of lorries. * uint16 Number of busses. * uint16 Number of planes. * uint16 Number of ships. * uint16 Number of train stations. * uint16 Number of lorry stations. * uint16 Number of bus stops. * uint16 Number of airports and heliports. * uint16 Number of harbours. * bool Company is an AI. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_SERVER_DETAIL_INFO(Packet *p, NetworkAddress *client_addr); /** * Registers the server to the master server. * string The "welcome" message to root out other binary packets. * uint8 Version of the protocol. * uint16 The port to unregister. * uint64 The session key. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_SERVER_REGISTER(Packet *p, NetworkAddress *client_addr); /** * The master server acknowledges the registration. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr); /** * The client requests a list of servers. * uint8 The protocol version. * uint8 The type of server to look for: IPv4, IPv6 or based on the received packet. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_CLIENT_GET_LIST(Packet *p, NetworkAddress *client_addr); /** * The server sends a list of servers. * uint8 The protocol version. * For each server: * 4 or 16 bytes of IPv4 or IPv6 address. * uint8 The port. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr); /** * A server unregisters itself at the master server. * uint8 Version of the protocol. * uint16 The port to unregister. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_SERVER_UNREGISTER(Packet *p, NetworkAddress *client_addr); /** * The client requests information about some NewGRFs. * uint8 The number of NewGRFs information is requested about. * For each NewGRF: * uint32 The GRFID. * 16 * uint8 MD5 checksum of the GRF. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr); /** * The server returns information about some NewGRFs. * uint8 The number of NewGRFs information is requested about. * For each NewGRF: * uint32 The GRFID. * 16 * uint8 MD5 checksum of the GRF. * string The name of the NewGRF. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr); /** * The master server sends us a session key. * uint64 The session key. * @param p The received packet. * @param client_addr The origin of the packet. */ virtual void Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr); void HandleUDPPacket(Packet *p, NetworkAddress *client_addr); /** * Function that is called for every GRFConfig that is read when receiving * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This * function must set all appropriate fields. This GRF is later appended to * the grfconfig list of the NetworkGameInfo. * @param config the GRF to handle */ virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); } public: NetworkUDPSocketHandler(NetworkAddressList *bind = NULL); /** On destructing of this class, the socket needs to be closed */ virtual ~NetworkUDPSocketHandler() { this->Close(); } bool Listen(); void Close(); void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false); void ReceivePackets(); void SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info); void ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info); }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_UDP_H */ openttd-1.5.3/src/network/core/core.h0000644000000000000000000000651312627373441016222 0ustar rootroot/* $Id: core.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 core.h Base for all network types (UDP and TCP) */ #ifndef NETWORK_CORE_CORE_H #define NETWORK_CORE_CORE_H #include "../../newgrf_config.h" #include "config.h" #ifdef ENABLE_NETWORK bool NetworkCoreInitialize(); void NetworkCoreShutdown(); /** Status of a network client; reasons why a client has quit */ enum NetworkRecvStatus { NETWORK_RECV_STATUS_OKAY, ///< Everything is okay NETWORK_RECV_STATUS_DESYNC, ///< A desync did occur NETWORK_RECV_STATUS_NEWGRF_MISMATCH, ///< We did not have the required NewGRFs NETWORK_RECV_STATUS_SAVEGAME, ///< Something went wrong (down)loading the savegame NETWORK_RECV_STATUS_CONN_LOST, ///< The connection is 'just' lost NETWORK_RECV_STATUS_MALFORMED_PACKET, ///< We apparently send a malformed packet NETWORK_RECV_STATUS_SERVER_ERROR, ///< The server told us we made an error NETWORK_RECV_STATUS_SERVER_FULL, ///< The server is full NETWORK_RECV_STATUS_SERVER_BANNED, ///< The server has banned us NETWORK_RECV_STATUS_CLOSE_QUERY, ///< Done querying the server }; /** Forward declaration due to circular dependencies */ struct Packet; /** * SocketHandler for all network sockets in OpenTTD. */ class NetworkSocketHandler { bool has_quit; ///< Whether the current client has quit/send a bad packet public: /** Create a new unbound socket */ NetworkSocketHandler() { this->has_quit = false; } /** Close the socket when destructing the socket handler */ virtual ~NetworkSocketHandler() { this->Close(); } /** Really close the socket */ virtual void Close() {} /** * Close the current connection; for TCP this will be mostly equivalent * to Close(), but for UDP it just means the packet has to be dropped. * @param error Whether we quit under an error condition or not. * @return new status of the connection. */ virtual NetworkRecvStatus CloseConnection(bool error = true) { this->has_quit = true; return NETWORK_RECV_STATUS_OKAY; } /** * Whether the current client connected to the socket has quit. * In the case of UDP, for example, once a client quits (send bad * data), the socket in not closed; only the packet is dropped. * @return true when the current client has quit, false otherwise */ bool HasClientQuit() const { return this->has_quit; } /** * Reopen the socket so we can send/receive stuff again. */ void Reopen() { this->has_quit = false; } void SendGRFIdentifier(Packet *p, const GRFIdentifier *grf); void ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf); void SendCompanyInformation(Packet *p, const struct Company *c, const struct NetworkCompanyStats *stats, uint max_len = NETWORK_COMPANY_NAME_LENGTH); }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_CORE_H */ openttd-1.5.3/src/network/core/address.h0000644000000000000000000001405512627373441016717 0ustar rootroot/* $Id: address.h 22695 2011-07-30 10:28:52Z rubidium $ */ /* * 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 core/address.h Wrapper for network addresses. */ #ifndef NETWORK_CORE_ADDRESS_H #define NETWORK_CORE_ADDRESS_H #include "os_abstraction.h" #include "config.h" #include "../../string_func.h" #include "../../core/smallmap_type.hpp" #ifdef ENABLE_NETWORK class NetworkAddress; typedef SmallVector NetworkAddressList; ///< Type for a list of addresses. typedef SmallMap SocketList; ///< Type for a mapping between address and socket. /** * Wrapper for (un)resolved network addresses; there's no reason to transform * a numeric IP to a string and then back again to pass it to functions. It * furthermore allows easier delaying of the hostname lookup. */ class NetworkAddress { private: char hostname[NETWORK_HOSTNAME_LENGTH]; ///< The hostname int address_length; ///< The length of the resolved address sockaddr_storage address; ///< The resolved address bool resolved; ///< Whether the address has been (tried to be) resolved /** * Helper function to resolve something to a socket. * @param runp information about the socket to try not * @return the opened socket or INVALID_SOCKET */ typedef SOCKET (*LoopProc)(addrinfo *runp); SOCKET Resolve(int family, int socktype, int flags, SocketList *sockets, LoopProc func); public: /** * Create a network address based on a resolved IP and port. * @param address The IP address with port. * @param address_length The length of the address. */ NetworkAddress(struct sockaddr_storage &address, int address_length) : address_length(address_length), address(address), resolved(address_length != 0) { *this->hostname = '\0'; } /** * Create a network address based on a resolved IP and port. * @param address The IP address with port. * @param address_length The length of the address. */ NetworkAddress(sockaddr *address, int address_length) : address_length(address_length), resolved(address_length != 0) { *this->hostname = '\0'; memset(&this->address, 0, sizeof(this->address)); memcpy(&this->address, address, address_length); } /** * Create a network address based on a unresolved host and port * @param hostname the unresolved hostname * @param port the port * @param family the address family */ NetworkAddress(const char *hostname = "", uint16 port = 0, int family = AF_UNSPEC) : address_length(0), resolved(false) { /* Also handle IPv6 bracket enclosed hostnames */ if (StrEmpty(hostname)) hostname = ""; if (*hostname == '[') hostname++; strecpy(this->hostname, StrEmpty(hostname) ? "" : hostname, lastof(this->hostname)); char *tmp = strrchr(this->hostname, ']'); if (tmp != NULL) *tmp = '\0'; memset(&this->address, 0, sizeof(this->address)); this->address.ss_family = family; this->SetPort(port); } /** * Make a clone of another address * @param address the address to clone */ NetworkAddress(const NetworkAddress &address) { memcpy(this, &address, sizeof(*this)); } const char *GetHostname(); void GetAddressAsString(char *buffer, const char *last, bool with_family = true); const char *GetAddressAsString(bool with_family = true); const sockaddr_storage *GetAddress(); /** * Get the (valid) length of the address. * @return the length */ int GetAddressLength() { /* Resolve it if we didn't do it already */ if (!this->IsResolved()) this->GetAddress(); return this->address_length; } uint16 GetPort() const; void SetPort(uint16 port); /** * Check whether the IP address has been resolved already * @return true iff the port has been resolved */ bool IsResolved() const { return this->resolved; } bool IsFamily(int family); bool IsInNetmask(char *netmask); /** * Compare the address of this class with the address of another. * @param address the other address. * @return < 0 if address is less, 0 if equal and > 0 if address is more */ int CompareTo(NetworkAddress &address) { int r = this->GetAddressLength() - address.GetAddressLength(); if (r == 0) r = this->address.ss_family - address.address.ss_family; if (r == 0) r = memcmp(&this->address, &address.address, this->address_length); if (r == 0) r = this->GetPort() - address.GetPort(); return r; } /** * Compare the address of this class with the address of another. * @param address the other address. * @return true if both match. */ bool operator == (NetworkAddress &address) { return this->CompareTo(address) == 0; } /** * Compare the address of this class with the address of another. * @param address the other address. * @return true if both match. */ bool operator == (NetworkAddress &address) const { return const_cast(this)->CompareTo(address) == 0; } /** * Compare the address of this class with the address of another. * @param address the other address. * @return true if both do not match. */ bool operator != (NetworkAddress address) const { return const_cast(this)->CompareTo(address) != 0; } /** * Compare the address of this class with the address of another. * @param address the other address. */ bool operator < (NetworkAddress &address) { return this->CompareTo(address) < 0; } SOCKET Connect(); void Listen(int socktype, SocketList *sockets); static const char *SocketTypeAsString(int socktype); static const char *AddressFamilyAsString(int family); }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_ADDRESS_H */ openttd-1.5.3/src/network/core/tcp_game.h0000644000000000000000000005046312627373441017054 0ustar rootroot/* $Id: tcp_game.h 26056 2013-11-22 21:50:43Z rubidium $ */ /* * 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 tcp_game.h Basic functions to receive and send TCP packets for game purposes. */ #ifndef NETWORK_CORE_TCP_GAME_H #define NETWORK_CORE_TCP_GAME_H #include "os_abstraction.h" #include "tcp.h" #include "../network_type.h" #include "../../core/pool_type.hpp" #ifdef ENABLE_NETWORK /** * Enum with all types of TCP packets. * For the exact meaning, look at #NetworkGameSocketHandler. */ enum PacketGameType { /* * These first three pair of packets (thus six in * total) must remain in this order for backward * and forward compatibility between clients that * are trying to join directly. */ /* Packets sent by socket accepting code without ever constructing a client socket instance. */ PACKET_SERVER_FULL, ///< The server is full and has no place for you. PACKET_SERVER_BANNED, ///< The server has banned you. /* Packets used by the client to join and an error message when the revision is wrong. */ PACKET_CLIENT_JOIN, ///< The client telling the server it wants to join. PACKET_SERVER_ERROR, ///< Server sending an error message to the client. /* Packets used for the pre-game lobby. */ PACKET_CLIENT_COMPANY_INFO, ///< Request information about all companies. PACKET_SERVER_COMPANY_INFO, ///< Information about a single company. /* * Packets after here assume that the client * and server are running the same version. As * such ordering is unimportant from here on. * * The following is the remainder of the packets * sent as part of authenticating and getting * the map and other important data. */ /* After the join step, the first is checking NewGRFs. */ PACKET_SERVER_CHECK_NEWGRFS, ///< Server sends NewGRF IDs and MD5 checksums for the client to check. PACKET_CLIENT_NEWGRFS_CHECKED, ///< Client acknowledges that it has all required NewGRFs. /* Checking the game, and then company passwords. */ PACKET_SERVER_NEED_GAME_PASSWORD, ///< Server requests the (hashed) game password. PACKET_CLIENT_GAME_PASSWORD, ///< Clients sends the (hashed) game password. PACKET_SERVER_NEED_COMPANY_PASSWORD, ///< Server requests the (hashed) company password. PACKET_CLIENT_COMPANY_PASSWORD, ///< Client sends the (hashed) company password. /* The server welcomes the authenticated client and sends information of other clients. */ PACKET_SERVER_WELCOME, ///< Server welcomes you and gives you your #ClientID. PACKET_SERVER_CLIENT_INFO, ///< Server sends you information about a client. /* Getting the savegame/map. */ PACKET_CLIENT_GETMAP, ///< Client requests the actual map. PACKET_SERVER_WAIT, ///< Server tells the client there are some people waiting for the map as well. PACKET_SERVER_MAP_BEGIN, ///< Server tells the client that it is beginning to send the map. PACKET_SERVER_MAP_SIZE, ///< Server tells the client what the (compressed) size of the map is. PACKET_SERVER_MAP_DATA, ///< Server sends bits of the map to the client. PACKET_SERVER_MAP_DONE, ///< Server tells it has just sent the last bits of the map to the client. PACKET_CLIENT_MAP_OK, ///< Client tells the server that it received the whole map. PACKET_SERVER_JOIN, ///< Tells clients that a new client has joined. /* * At this moment the client has the map and * the client is fully authenticated. Now the * normal communication starts. */ /* Game progress monitoring. */ PACKET_SERVER_FRAME, ///< Server tells the client what frame it is in, and thus to where the client may progress. PACKET_CLIENT_ACK, ///< The client tells the server which frame it has executed. PACKET_SERVER_SYNC, ///< Server tells the client what the random state should be. /* Sending commands around. */ PACKET_CLIENT_COMMAND, ///< Client executed a command and sends it to the server. PACKET_SERVER_COMMAND, ///< Server distributes a command to (all) the clients. /* Human communication! */ PACKET_CLIENT_CHAT, ///< Client said something that should be distributed. PACKET_SERVER_CHAT, ///< Server distributing the message of a client (or itself). /* Remote console. */ PACKET_CLIENT_RCON, ///< Client asks the server to execute some command. PACKET_SERVER_RCON, ///< Response of the executed command on the server. /* Moving a client.*/ PACKET_CLIENT_MOVE, ///< A client would like to be moved to another company. PACKET_SERVER_MOVE, ///< Server tells everyone that someone is moved to another company. /* Configuration updates. */ PACKET_CLIENT_SET_PASSWORD, ///< A client (re)sets its company's password. PACKET_CLIENT_SET_NAME, ///< A client changes its name. PACKET_SERVER_COMPANY_UPDATE, ///< Information (password) of a company changed. PACKET_SERVER_CONFIG_UPDATE, ///< Some network configuration important to the client changed. /* A server quitting this game. */ PACKET_SERVER_NEWGAME, ///< The server is preparing to start a new game. PACKET_SERVER_SHUTDOWN, ///< The server is shutting down. /* A client quitting. */ PACKET_CLIENT_QUIT, ///< A client tells the server it is going to quit. PACKET_SERVER_QUIT, ///< A server tells that a client has quit. PACKET_CLIENT_ERROR, ///< A client reports an error to the server. PACKET_SERVER_ERROR_QUIT, ///< A server tells that a client has hit an error and did quit. PACKET_END, ///< Must ALWAYS be on the end of this list!! (period) }; /** Packet that wraps a command */ struct CommandPacket; /** A queue of CommandPackets. */ class CommandQueue { CommandPacket *first; ///< The first packet in the queue. CommandPacket *last; ///< The last packet in the queue; only valid when first != NULL. uint count; ///< The number of items in the queue. public: /** Initialise the command queue. */ CommandQueue() : first(NULL), last(NULL), count(0) {} /** Clear the command queue. */ ~CommandQueue() { this->Free(); } void Append(CommandPacket *p); CommandPacket *Pop(bool ignore_paused = false); CommandPacket *Peek(bool ignore_paused = false); void Free(); /** Get the number of items in the queue. */ uint Count() const { return this->count; } }; /** Base socket handler for all TCP sockets */ class NetworkGameSocketHandler : public NetworkTCPSocketHandler { /* TODO: rewrite into a proper class */ private: NetworkClientInfo *info; ///< Client info related to this socket protected: NetworkRecvStatus ReceiveInvalidPacket(PacketGameType type); /** * Notification that the server is full. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_FULL(Packet *p); /** * Notification that the client trying to join is banned. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet *p); /** * Try to join the server: * string OpenTTD revision (norev000 if no revision). * string Name of the client (max NETWORK_NAME_LENGTH). * uint8 ID of the company to play as (1..MAX_COMPANIES). * uint8 ID of the clients Language. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_JOIN(Packet *p); /** * The client made an error: * uint8 Error code caused (see NetworkErrorCode). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet *p); /** * Request company information (in detail). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p); /** * Sends information about the companies (one packet per company): * uint8 Version of the structure of this packet (NETWORK_COMPANY_INFO_VERSION). * bool Contains data (false marks the end of updates). * uint8 ID of the company. * string Name of the company. * uint32 Year the company was inaugurated. * uint64 Value. * uint64 Money. * uint64 Income. * uint16 Performance (last quarter). * bool Company is password protected. * uint16 Number of trains. * uint16 Number of lorries. * uint16 Number of busses. * uint16 Number of planes. * uint16 Number of ships. * uint16 Number of train stations. * uint16 Number of lorry stations. * uint16 Number of bus stops. * uint16 Number of airports and heliports. * uint16 Number of harbours. * bool Company is an AI. * string Client names (comma separated list) * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet *p); /** * Send information about a client: * uint32 ID of the client (always unique on a server. 1 = server, 0 is invalid). * uint8 ID of the company the client is playing as (255 for spectators). * string Name of the client. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p); /** * Indication to the client that the server needs a game password. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p); /** * Indication to the client that the server needs a company password: * uint32 Generation seed. * string Network ID of the server. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p); /** * Send a password to the server to authorize: * uint8 Password type (see NetworkPasswordType). * string The password. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p); /** * Send a password to the server to authorize * uint8 Password type (see NetworkPasswordType). * string The password. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p); /** * The client is joined and ready to receive his map: * uint32 Own client ID. * uint32 Generation seed. * string Network ID of the server. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p); /** * Request the map from the server. * uint32 NewGRF version (release versions of OpenTTD only). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_GETMAP(Packet *p); /** * Notification that another client is currently receiving the map: * uint8 Number of clients waiting in front of you. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_WAIT(Packet *p); /** * Sends that the server will begin with sending the map to the client: * uint32 Current frame. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p); /** * Sends the size of the map to the client. * uint32 Size of the (compressed) map (in bytes). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet *p); /** * Sends the data of the map to the client: * Contains a part of the map (until max size of packet). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet *p); /** * Sends that all data of the map are sent to the client: * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet *p); /** * Tell the server that we are done receiving/loading the map. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_MAP_OK(Packet *p); /** * A client joined (PACKET_CLIENT_MAP_OK), what usually directly follows is a PACKET_SERVER_CLIENT_INFO: * uint32 ID of the client that just joined the game. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_JOIN(Packet *p); /** * Sends the current frame counter to the client: * uint32 Frame counter * uint32 Frame counter max (how far may the client walk before the server?) * uint32 General seed 1 (dependent on compile settings, not default). * uint32 General seed 2 (dependent on compile settings, not default). * uint8 Random token to validate the client is actually listening (only occasionally present). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_FRAME(Packet *p); /** * Sends a sync-check to the client: * uint32 Frame counter. * uint32 General seed 1. * uint32 General seed 2 (dependent on compile settings, not default). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_SYNC(Packet *p); /** * Tell the server we are done with this frame: * uint32 Current frame counter of the client. * uint8 The random token that the server sent in the PACKET_SERVER_FRAME packet. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_ACK(Packet *p); /** * Send a DoCommand to the Server: * uint8 ID of the company (0..MAX_COMPANIES-1). * uint32 ID of the command (see command.h). * uint32 P1 (free variables used in DoCommand). * uint32 P2 * uint32 Tile where this is taking place. * string Text. * uint8 ID of the callback. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_COMMAND(Packet *p); /** * Sends a DoCommand to the client: * uint8 ID of the company (0..MAX_COMPANIES-1). * uint32 ID of the command (see command.h). * uint32 P1 (free variable used in DoCommand). * uint32 P2. * uint32 Tile where this is taking place. * string Text. * uint8 ID of the callback. * uint32 Frame of execution. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_COMMAND(Packet *p); /** * Sends a chat-packet to the server: * uint8 ID of the action (see NetworkAction). * uint8 ID of the destination type (see DestType). * uint32 ID of the client or company (destination of the chat). * string Message (max NETWORK_CHAT_LENGTH). * uint64 data (used e.g. for 'give money' actions). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_CHAT(Packet *p); /** * Sends a chat-packet to the client: * uint8 ID of the action (see NetworkAction). * uint32 ID of the client (origin of the chat). * string Message (max NETWORK_CHAT_LENGTH). * uint64 data (used e.g. for 'give money' actions). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet *p); /** * Set the password for the clients current company: * string The password. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_SET_PASSWORD(Packet *p); /** * Gives the client a new name: * string New name of the client. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_SET_NAME(Packet *p); /** * The client is quitting the game. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_QUIT(Packet *p); /** * The client made an error and is quitting the game. * uint8 Error of the code caused (see NetworkErrorCode). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_ERROR(Packet *p); /** * Notification that a client left the game: * uint32 ID of the client. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_QUIT(Packet *p); /** * Inform all clients that one client made an error and thus has quit/been disconnected: * uint32 ID of the client that caused the error. * uint8 Code of the error caused (see NetworkErrorCode). * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p); /** * Let the clients know that the server is closing. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p); /** * Let the clients know that the server is loading a new map. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p); /** * Send the result of an issues RCon command back to the client: * uint16 Colour code. * string Output of the RCon command * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_RCON(Packet *p); /** * Send an RCon command to the server: * string RCon password. * string Command to be executed. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_RCON(Packet *p); /** * Sends information about all used GRFs to the client: * uint8 Amount of GRFs (the following data is repeated this many times, i.e. per GRF data). * uint32 GRF ID * 16 * uint8 MD5 checksum of the GRF * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet *p); /** * Tell the server that we have the required GRFs * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet *p); /** * Move a client from one company into another: * uint32 ID of the client. * uint8 ID of the new company. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_MOVE(Packet *p); /** * Request the server to move this client into another company: * uint8 ID of the company the client wants to join. * string Password, if the company is password protected. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_CLIENT_MOVE(Packet *p); /** * Update the clients knowledge of which company is password protected: * uint16 Bitwise representation of each company * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p); /** * Update the clients knowledge of the max settings: * uint8 Maximum number of companies allowed. * uint8 Maximum number of spectators allowed. * @param p The packet that was just received. */ virtual NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet *p); NetworkRecvStatus HandlePacket(Packet *p); NetworkGameSocketHandler(SOCKET s); public: ClientID client_id; ///< Client identifier uint32 last_frame; ///< Last frame we have executed uint32 last_frame_server; ///< Last frame the server has executed CommandQueue incoming_queue; ///< The command-queue awaiting handling uint last_packet; ///< Time we received the last frame. NetworkRecvStatus CloseConnection(bool error = true); /** * Close the network connection due to the given status. * @param status The reason the connection got closed. */ virtual NetworkRecvStatus CloseConnection(NetworkRecvStatus status) = 0; virtual ~NetworkGameSocketHandler() {} /** * Sets the client info for this socket handler. * @param info The new client info. */ inline void SetInfo(NetworkClientInfo *info) { assert(info != NULL && this->info == NULL); this->info = info; } /** * Gets the client info of this socket handler. * @return The client info. */ inline NetworkClientInfo *GetInfo() const { return this->info; } NetworkRecvStatus ReceivePackets(); const char *ReceiveCommand(Packet *p, CommandPacket *cp); void SendCommand(Packet *p, const CommandPacket *cp); }; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_TCP_GAME_H */ openttd-1.5.3/src/network/core/config.h0000644000000000000000000001236512627373441016541 0ustar rootroot/* $Id: config.h 25590 2013-07-12 17:15:13Z planetmaker $ */ /* * 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 config.h Configuration options of the network stuff. It is used even when compiling without network support. */ #ifndef NETWORK_CORE_CONFIG_H #define NETWORK_CORE_CONFIG_H /** DNS hostname of the masterserver */ static const char * const NETWORK_MASTER_SERVER_HOST = "master.openttd.org"; /** DNS hostname of the content server */ static const char * const NETWORK_CONTENT_SERVER_HOST = "content.openttd.org"; /** DNS hostname of the HTTP-content mirror server */ static const char * const NETWORK_CONTENT_MIRROR_HOST = "binaries.openttd.org"; /** URL of the HTTP mirror system */ static const char * const NETWORK_CONTENT_MIRROR_URL = "/bananas"; /** Message sent to the masterserver to 'identify' this client as OpenTTD */ static const char * const NETWORK_MASTER_SERVER_WELCOME_MESSAGE = "OpenTTDRegister"; static const uint16 NETWORK_MASTER_SERVER_PORT = 3978; ///< The default port of the master server (UDP) static const uint16 NETWORK_CONTENT_SERVER_PORT = 3978; ///< The default port of the content server (TCP) static const uint16 NETWORK_CONTENT_MIRROR_PORT = 80; ///< The default port of the content mirror (TCP) static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The default port of the game server (TCP & UDP) static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP) static const uint16 SEND_MTU = 1460; ///< Number of bytes we can pack in a single packet static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use? static const byte NETWORK_GAME_INFO_VERSION = 4; ///< What version of game-info do we use? static const byte NETWORK_COMPANY_INFO_VERSION = 6; ///< What version of company info is this? static const byte NETWORK_MASTER_SERVER_VERSION = 2; ///< What version of master-server-protocol do we use? static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0' static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0' static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0' static const uint NETWORK_REVISION_LENGTH = 15; ///< The maximum length of the revision, in bytes including '\0' static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH) static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0' static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0' static const uint NETWORK_RCONCOMMAND_LENGTH = 500; ///< The maximum length of a rconsole command, in bytes including '\0' static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = SEND_MTU - 3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than SEND_MTU including header (3 bytes) static const uint NETWORK_CHAT_LENGTH = 900; ///< The maximum length of a chat message, in bytes including '\0' static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maximum length of the name of a GRF /** * Maximum number of GRFs that can be sent. * This value is related to number of handles (files) OpenTTD can open. * This is currently 64. Two are used for configuration and sound. */ static const uint NETWORK_MAX_GRF_COUNT = 62; static const uint NETWORK_NUM_LANGUAGES = 36; ///< Number of known languages (to the network protocol) + 1 for 'any'. /** * The number of landscapes in OpenTTD. * This number must be equal to NUM_LANDSCAPE, but as this number is used * within the network code and that the network code is shared with the * masterserver/updater, it has to be declared in here too. In network.cpp * there is a compile assertion to check that this NUM_LANDSCAPE is equal * to NETWORK_NUM_LANDSCAPES. */ static const uint NETWORK_NUM_LANDSCAPES = 4; #endif /* NETWORK_CORE_CONFIG_H */ openttd-1.5.3/src/network/core/host.cpp0000644000000000000000000001474212627373441016605 0ustar rootroot/* $Id: host.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 host.cpp Functions related to getting host specific data (IPs). */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../../debug.h" #include "address.h" #include "../../safeguards.h" /** * Internal implementation for finding the broadcast IPs. * This function is implemented multiple times for multiple targets. * @param broadcast the list of broadcasts to write into. */ static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast); #if defined(PSP) static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // PSP implementation { } #elif defined(BEOS_NET_SERVER) || defined(__HAIKU__) /* doesn't have neither getifaddrs or net/if.h */ /* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */ extern "C" int _netstat(int fd, char **output, int verbose); int seek_past_header(char **pos, const char *header) { char *new_pos = strstr(*pos, header); if (new_pos == 0) { return B_ERROR; } *pos += strlen(header) + new_pos - *pos + 1; return B_OK; } static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // BEOS implementation { int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { DEBUG(net, 0, "[core] error creating socket"); return; } char *output_pointer = NULL; int output_length = _netstat(sock, &output_pointer, 1); if (output_length < 0) { DEBUG(net, 0, "[core] error running _netstat"); return; } char **output = &output_pointer; if (seek_past_header(output, "IP Interfaces:") == B_OK) { for (;;) { uint32 n; int fields, read; uint8 i1, i2, i3, i4, j1, j2, j3, j4; uint32 ip; uint32 netmask; fields = sscanf(*output, "%u: %hhu.%hhu.%hhu.%hhu, netmask %hhu.%hhu.%hhu.%hhu%n", &n, &i1, &i2, &i3, &i4, &j1, &j2, &j3, &j4, &read); read += 1; if (fields != 9) { break; } ip = (uint32)i1 << 24 | (uint32)i2 << 16 | (uint32)i3 << 8 | (uint32)i4; netmask = (uint32)j1 << 24 | (uint32)j2 << 16 | (uint32)j3 << 8 | (uint32)j4; if (ip != INADDR_LOOPBACK && ip != INADDR_ANY) { sockaddr_storage address; memset(&address, 0, sizeof(address)); ((sockaddr_in*)&address)->sin_addr.s_addr = htonl(ip | ~netmask); NetworkAddress addr(address, sizeof(sockaddr)); if (!broadcast->Contains(addr)) *broadcast->Append() = addr; } if (read < 0) { break; } *output += read; } closesocket(sock); } } #elif defined(HAVE_GETIFADDRS) static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // GETIFADDRS implementation { struct ifaddrs *ifap, *ifa; if (getifaddrs(&ifap) != 0) return; for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (!(ifa->ifa_flags & IFF_BROADCAST)) continue; if (ifa->ifa_broadaddr == NULL) continue; if (ifa->ifa_broadaddr->sa_family != AF_INET) continue; NetworkAddress addr(ifa->ifa_broadaddr, sizeof(sockaddr)); if (!broadcast->Contains(addr)) *broadcast->Append() = addr; } freeifaddrs(ifap); } #elif defined(WIN32) static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // Win32 implementation { SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return; DWORD len = 0; int num = 2; INTERFACE_INFO *ifo = CallocT(num); for (;;) { if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, NULL, 0, ifo, num * sizeof(*ifo), &len, NULL, NULL) == 0) break; free(ifo); if (WSAGetLastError() != WSAEFAULT) { closesocket(sock); return; } num *= 2; ifo = CallocT(num); } for (uint j = 0; j < len / sizeof(*ifo); j++) { if (ifo[j].iiFlags & IFF_LOOPBACK) continue; if (!(ifo[j].iiFlags & IFF_BROADCAST)) continue; sockaddr_storage address; memset(&address, 0, sizeof(address)); /* iiBroadcast is unusable, because it always seems to be set to 255.255.255.255. */ memcpy(&address, &ifo[j].iiAddress.Address, sizeof(sockaddr)); ((sockaddr_in*)&address)->sin_addr.s_addr = ifo[j].iiAddress.AddressIn.sin_addr.s_addr | ~ifo[j].iiNetmask.AddressIn.sin_addr.s_addr; NetworkAddress addr(address, sizeof(sockaddr)); if (!broadcast->Contains(addr)) *broadcast->Append() = addr; } free(ifo); closesocket(sock); } #else /* not HAVE_GETIFADDRS */ #include "../../string_func.h" static void NetworkFindBroadcastIPsInternal(NetworkAddressList *broadcast) // !GETIFADDRS implementation { SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock == INVALID_SOCKET) return; char buf[4 * 1024]; // Arbitrary buffer size struct ifconf ifconf; ifconf.ifc_len = sizeof(buf); ifconf.ifc_buf = buf; if (ioctl(sock, SIOCGIFCONF, &ifconf) == -1) { closesocket(sock); return; } const char *buf_end = buf + ifconf.ifc_len; for (const char *p = buf; p < buf_end;) { const struct ifreq *req = (const struct ifreq*)p; if (req->ifr_addr.sa_family == AF_INET) { struct ifreq r; strecpy(r.ifr_name, req->ifr_name, lastof(r.ifr_name)); if (ioctl(sock, SIOCGIFFLAGS, &r) != -1 && (r.ifr_flags & IFF_BROADCAST) && ioctl(sock, SIOCGIFBRDADDR, &r) != -1) { NetworkAddress addr(&r.ifr_broadaddr, sizeof(sockaddr)); if (!broadcast->Contains(addr)) *broadcast->Append() = addr; } } p += sizeof(struct ifreq); #if defined(AF_LINK) && !defined(SUNOS) p += req->ifr_addr.sa_len - sizeof(struct sockaddr); #endif } closesocket(sock); } #endif /* all NetworkFindBroadcastIPsInternals */ /** * Find the IPv4 broadcast addresses; IPv6 uses a completely different * strategy for broadcasting. * @param broadcast the list of broadcasts to write into. */ void NetworkFindBroadcastIPs(NetworkAddressList *broadcast) { NetworkFindBroadcastIPsInternal(broadcast); /* Now display to the debug all the detected ips */ DEBUG(net, 3, "Detected broadcast addresses:"); int i = 0; for (NetworkAddress *addr = broadcast->Begin(); addr != broadcast->End(); addr++) { addr->SetPort(NETWORK_DEFAULT_PORT); DEBUG(net, 3, "%d) %s", i++, addr->GetHostname()); } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/packet.cpp0000644000000000000000000001734412627373441017100 0ustar rootroot/* $Id: packet.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 packet.cpp Basic functions to create, fill and read packets. */ #ifdef ENABLE_NETWORK #include "../../stdafx.h" #include "../../string_func.h" #include "packet.h" #include "../../safeguards.h" /** * Create a packet that is used to read from a network socket * @param cs the socket handler associated with the socket we are reading from */ Packet::Packet(NetworkSocketHandler *cs) { assert(cs != NULL); this->cs = cs; this->next = NULL; this->pos = 0; // We start reading from here this->size = 0; this->buffer = MallocT(SEND_MTU); } /** * Creates a packet to send * @param type of the packet to send */ Packet::Packet(PacketType type) { this->cs = NULL; this->next = NULL; /* Skip the size so we can write that in before sending the packet */ this->pos = 0; this->size = sizeof(PacketSize); this->buffer = MallocT(SEND_MTU); this->buffer[this->size++] = type; } /** * Free the buffer of this packet. */ Packet::~Packet() { free(this->buffer); } /** * Writes the packet size from the raw packet from packet->size */ void Packet::PrepareToSend() { assert(this->cs == NULL && this->next == NULL); this->buffer[0] = GB(this->size, 0, 8); this->buffer[1] = GB(this->size, 8, 8); this->pos = 0; // We start reading from here } /* * The next couple of functions make sure we can send * uint8, uint16, uint32 and uint64 endian-safe * over the network. The least significant bytes are * sent first. * * So 0x01234567 would be sent as 67 45 23 01. * * A bool is sent as a uint8 where zero means false * and non-zero means true. */ /** * Package a boolean in the packet. * @param data The data to send. */ void Packet::Send_bool(bool data) { this->Send_uint8(data ? 1 : 0); } /** * Package a 8 bits integer in the packet. * @param data The data to send. */ void Packet::Send_uint8(uint8 data) { assert(this->size < SEND_MTU - sizeof(data)); this->buffer[this->size++] = data; } /** * Package a 16 bits integer in the packet. * @param data The data to send. */ void Packet::Send_uint16(uint16 data) { assert(this->size < SEND_MTU - sizeof(data)); this->buffer[this->size++] = GB(data, 0, 8); this->buffer[this->size++] = GB(data, 8, 8); } /** * Package a 32 bits integer in the packet. * @param data The data to send. */ void Packet::Send_uint32(uint32 data) { assert(this->size < SEND_MTU - sizeof(data)); this->buffer[this->size++] = GB(data, 0, 8); this->buffer[this->size++] = GB(data, 8, 8); this->buffer[this->size++] = GB(data, 16, 8); this->buffer[this->size++] = GB(data, 24, 8); } /** * Package a 64 bits integer in the packet. * @param data The data to send. */ void Packet::Send_uint64(uint64 data) { assert(this->size < SEND_MTU - sizeof(data)); this->buffer[this->size++] = GB(data, 0, 8); this->buffer[this->size++] = GB(data, 8, 8); this->buffer[this->size++] = GB(data, 16, 8); this->buffer[this->size++] = GB(data, 24, 8); this->buffer[this->size++] = GB(data, 32, 8); this->buffer[this->size++] = GB(data, 40, 8); this->buffer[this->size++] = GB(data, 48, 8); this->buffer[this->size++] = GB(data, 56, 8); } /** * Sends a string over the network. It sends out * the string + '\0'. No size-byte or something. * @param data The string to send */ void Packet::Send_string(const char *data) { assert(data != NULL); /* The <= *is* valid due to the fact that we are comparing sizes and not the index. */ assert(this->size + strlen(data) + 1 <= SEND_MTU); while ((this->buffer[this->size++] = *data++) != '\0') {} } /* * Receiving commands * Again, the next couple of functions are endian-safe * see the comment before Send_bool for more info. */ /** * Is it safe to read from the packet, i.e. didn't we run over the buffer ? * @param bytes_to_read The amount of bytes we want to try to read. * @return True if that is safe, otherwise false. */ bool Packet::CanReadFromPacket(uint bytes_to_read) { /* Don't allow reading from a quit client/client who send bad data */ if (this->cs->HasClientQuit()) return false; /* Check if variable is within packet-size */ if (this->pos + bytes_to_read > this->size) { this->cs->NetworkSocketHandler::CloseConnection(); return false; } return true; } /** * Reads the packet size from the raw packet and stores it in the packet->size */ void Packet::ReadRawPacketSize() { assert(this->cs != NULL && this->next == NULL); this->size = (PacketSize)this->buffer[0]; this->size += (PacketSize)this->buffer[1] << 8; } /** * Prepares the packet so it can be read */ void Packet::PrepareToRead() { this->ReadRawPacketSize(); /* Put the position on the right place */ this->pos = sizeof(PacketSize); } /** * Read a boolean from the packet. * @return The read data. */ bool Packet::Recv_bool() { return this->Recv_uint8() != 0; } /** * Read a 8 bits integer from the packet. * @return The read data. */ uint8 Packet::Recv_uint8() { uint8 n; if (!this->CanReadFromPacket(sizeof(n))) return 0; n = this->buffer[this->pos++]; return n; } /** * Read a 16 bits integer from the packet. * @return The read data. */ uint16 Packet::Recv_uint16() { uint16 n; if (!this->CanReadFromPacket(sizeof(n))) return 0; n = (uint16)this->buffer[this->pos++]; n += (uint16)this->buffer[this->pos++] << 8; return n; } /** * Read a 32 bits integer from the packet. * @return The read data. */ uint32 Packet::Recv_uint32() { uint32 n; if (!this->CanReadFromPacket(sizeof(n))) return 0; n = (uint32)this->buffer[this->pos++]; n += (uint32)this->buffer[this->pos++] << 8; n += (uint32)this->buffer[this->pos++] << 16; n += (uint32)this->buffer[this->pos++] << 24; return n; } /** * Read a 64 bits integer from the packet. * @return The read data. */ uint64 Packet::Recv_uint64() { uint64 n; if (!this->CanReadFromPacket(sizeof(n))) return 0; n = (uint64)this->buffer[this->pos++]; n += (uint64)this->buffer[this->pos++] << 8; n += (uint64)this->buffer[this->pos++] << 16; n += (uint64)this->buffer[this->pos++] << 24; n += (uint64)this->buffer[this->pos++] << 32; n += (uint64)this->buffer[this->pos++] << 40; n += (uint64)this->buffer[this->pos++] << 48; n += (uint64)this->buffer[this->pos++] << 56; return n; } /** * Reads a string till it finds a '\0' in the stream. * @param buffer The buffer to put the data into. * @param size The size of the buffer. * @param settings The string validation settings. */ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings settings) { PacketSize pos; char *bufp = buffer; const char *last = buffer + size - 1; /* Don't allow reading from a closed socket */ if (cs->HasClientQuit()) return; pos = this->pos; while (--size > 0 && pos < this->size && (*buffer++ = this->buffer[pos++]) != '\0') {} if (size == 0 || pos == this->size) { *buffer = '\0'; /* If size was sooner to zero then the string in the stream * skip till the \0, so than packet can be read out correctly for the rest */ while (pos < this->size && this->buffer[pos] != '\0') pos++; pos++; } this->pos = pos; str_validate(bufp, last, settings); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/core/os_abstraction.h0000644000000000000000000002406612627373441020307 0ustar rootroot/* $Id: os_abstraction.h 27092 2014-12-24 17:17:18Z frosch $ */ /* * 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 os_abstraction.h Network stuff has many things that needs to be * included and/or implemented by default. * All those things are in this file. */ #ifndef NETWORK_CORE_OS_ABSTRACTION_H #define NETWORK_CORE_OS_ABSTRACTION_H /* Include standard stuff per OS */ #ifdef ENABLE_NETWORK /* Windows stuff */ #if defined(WIN32) || defined(WIN64) #include #include #include #include #define GET_LAST_ERROR() WSAGetLastError() #undef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK /* Windows has some different names for some types */ typedef unsigned long in_addr_t; #if !(defined(__MINGW32__) || defined(__CYGWIN__)) /* Windows has some different names for some types */ typedef SSIZE_T ssize_t; typedef int socklen_t; # define IPPROTO_IPV6 41 #else #include "../../os/windows/win32.h" #include "../../core/alloc_func.hpp" #define AI_ADDRCONFIG 0x00000400 /* Resolution only if global address configured */ #define IPV6_V6ONLY 27 static inline int OTTDgetnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, DWORD hostlen, char *serv, DWORD servlen, int flags) { static int (WINAPI *getnameinfo)(const struct sockaddr *, socklen_t, char *, DWORD, char *, DWORD, int) = NULL; static bool first_time = true; if (first_time) { LoadLibraryList((Function*)&getnameinfo, "ws2_32.dll\0getnameinfo\0\0"); first_time = false; } if (getnameinfo != NULL) return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); strncpy(host, inet_ntoa(((const struct sockaddr_in *)sa)->sin_addr), hostlen); return 0; } #define getnameinfo OTTDgetnameinfo static inline int OTTDgetaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { static int (WINAPI *getaddrinfo)(const char *, const char *, const struct addrinfo *, struct addrinfo **) = NULL; static bool first_time = true; if (first_time) { LoadLibraryList((Function*)&getaddrinfo, "ws2_32.dll\0getaddrinfo\0\0"); first_time = false; } if (getaddrinfo != NULL) return getaddrinfo(nodename, servname, hints, res); *res = NULL; in_addr_t ip = inet_addr(nodename); if (ip == INADDR_NONE) { struct hostent *he = gethostbyname(nodename); if (he == NULL) return EAI_NONAME; ip = (*(struct in_addr *)he->h_addr).s_addr; } struct sockaddr_in *sin = CallocT(1); sin->sin_family = AF_INET; sin->sin_port = htons(strtoul(servname, NULL, 10)); sin->sin_addr.s_addr = ip; struct addrinfo *ai = CallocT(1); ai->ai_family = PF_INET; ai->ai_addr = (struct sockaddr*)sin; ai->ai_addrlen = sizeof(*sin); ai->ai_socktype = hints->ai_socktype; *res = ai; return 0; } #define getaddrinfo OTTDgetaddrinfo static inline void OTTDfreeaddrinfo(struct addrinfo *ai) { static int (WINAPI *freeaddrinfo)(struct addrinfo *) = NULL; static bool first_time = true; if (ai == NULL) return; if (first_time) { LoadLibraryList((Function*)&freeaddrinfo, "ws2_32.dll\0freeaddrinfo\0\0"); first_time = false; } if (freeaddrinfo != NULL) { freeaddrinfo(ai); return; } do { struct addrinfo *next = ai->ai_next; free(ai->ai_addr); free(ai); ai = next; } while (ai != NULL); } #define freeaddrinfo OTTDfreeaddrinfo #endif /* __MINGW32__ && __CYGWIN__ */ #endif /* WIN32 */ /* UNIX stuff */ #if defined(UNIX) && !defined(__OS2__) # if defined(OPENBSD) || defined(__NetBSD__) # define AI_ADDRCONFIG 0 # endif # define SOCKET int # define INVALID_SOCKET -1 # if !defined(__MORPHOS__) && !defined(__AMIGA__) # define ioctlsocket ioctl # if !defined(BEOS_NET_SERVER) # define closesocket close # endif # define GET_LAST_ERROR() (errno) # endif /* Need this for FIONREAD on solaris */ # define BSD_COMP /* Includes needed for UNIX-like systems */ # include # include # if defined(__BEOS__) && defined(BEOS_NET_SERVER) # include # include /* snooze() */ # include typedef unsigned long in_addr_t; # define INADDR_NONE INADDR_BROADCAST # else # include # include # include # include # include /* According to glibc/NEWS, appeared in glibc-2.3. */ # if !defined(__sgi__) && !defined(SUNOS) && !defined(__MORPHOS__) && !defined(__BEOS__) && !defined(__HAIKU__) && !defined(__INNOTEK_LIBC__) \ && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) && !defined(HPUX) /* If for any reason ifaddrs.h does not exist on your system, comment out * the following two lines and an alternative way will be used to fetch * the list of IPs from the system. */ # include # define HAVE_GETIFADDRS # endif # if !defined(INADDR_NONE) # define INADDR_NONE 0xffffffff # endif # if defined(__BEOS__) && !defined(BEOS_NET_SERVER) /* needed on Zeta */ # include # endif # endif /* BEOS_NET_SERVER */ # if !defined(__BEOS__) && defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1) typedef uint32_t in_addr_t; # endif # include # include # include #endif /* UNIX */ #ifdef __BEOS__ typedef int socklen_t; #endif #ifdef __HAIKU__ #define IPV6_V6ONLY 27 #endif #if defined(PSP) # include # include # include # include # include # include # include # include # include # include # include # include # define TCP_NODELAY 1 # define SO_NONBLOCK 0x1009 # define SOCKET int # define INVALID_SOCKET -1 # define INADDR_NONE 0xffffffff # define closesocket close # define GET_LAST_ERROR() sceNetInetGetErrno() #endif /* PSP */ /* OS/2 stuff */ #if defined(__OS2__) # define SOCKET int # define INVALID_SOCKET -1 # define ioctlsocket ioctl # define closesocket close # define GET_LAST_ERROR() (sock_errno()) /* Includes needed for OS/2 systems */ # include # include # include # include # include # include # include # include # include # include # include # include # define INADDR_NONE 0xffffffff # include "../../3rdparty/os2/getaddrinfo.h" # include "../../3rdparty/os2/getnameinfo.h" #define IPV6_V6ONLY 27 /* * IPv6 address */ struct in6_addr { union { uint8_t __u6_addr8[16]; uint16_t __u6_addr16[8]; uint32_t __u6_addr32[4]; } __u6_addr; /* 128-bit IP6 address */ }; #define s6_addr __u6_addr.__u6_addr8 struct sockaddr_in6 { uint8_t sin6_len; /* length of this struct */ sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* Transport layer port # */ uint32_t sin6_flowinfo; /* IP6 flow information */ struct in6_addr sin6_addr; /* IP6 address */ uint32_t sin6_scope_id; /* scope zone index */ }; typedef int socklen_t; #if !defined(__INNOTEK_LIBC__) typedef unsigned long in_addr_t; #endif /* __INNOTEK_LIBC__ */ #endif /* OS/2 */ /* MorphOS and Amiga stuff */ #if defined(__MORPHOS__) || defined(__AMIGA__) # include # include /* required for Open/CloseLibrary() */ /* MorphOS defines his network functions with UBYTE arrays while we * use char arrays. This gives tons of unneeded warnings */ # define UBYTE char # if defined(__MORPHOS__) # include /* FIO* defines */ # include /* SIO* defines */ # include # else /* __AMIGA__ */ # include # endif /* Make the names compatible */ # define closesocket(s) CloseSocket(s) # define GET_LAST_ERROR() Errno() # define ioctlsocket(s, request, status) IoctlSocket((LONG)s, (ULONG)request, (char*)status) # define ioctl ioctlsocket typedef unsigned int in_addr_t; typedef long socklen_t; extern struct Library *SocketBase; # ifdef __AMIGA__ /* for usleep() implementation */ extern struct Device *TimerBase; extern struct MsgPort *TimerPort; extern struct timerequest *TimerRequest; # endif #endif /* __MORPHOS__ || __AMIGA__ */ /** * Try to set the socket into non-blocking mode. * @param d The socket to set the non-blocking more for. * @return True if setting the non-blocking mode succeeded, otherwise false. */ static inline bool SetNonBlocking(SOCKET d) { #ifdef WIN32 u_long nonblocking = 1; #else int nonblocking = 1; #endif #if (defined(__BEOS__) && defined(BEOS_NET_SERVER)) || defined(PSP) return setsockopt(d, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(nonblocking)) == 0; #else return ioctlsocket(d, FIONBIO, &nonblocking) == 0; #endif } /** * Try to set the socket to not delay sending. * @param d The socket to disable the delaying for. * @return True if disabling the delaying succeeded, otherwise false. */ static inline bool SetNoDelay(SOCKET d) { /* XXX should this be done at all? */ #if !defined(BEOS_NET_SERVER) /* not implemented on BeOS net_server */ int b = 1; /* The (const char*) cast is needed for windows */ return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0; #else return true; #endif } /* Make sure these structures have the size we expect them to be */ assert_compile(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes. assert_compile(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes. #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CORE_OS_ABSTRACTION_H */ openttd-1.5.3/src/network/network_internal.h0000644000000000000000000001274212627373441017730 0ustar rootroot/* $Id: network_internal.h 26488 2014-04-23 21:19:54Z rubidium $ */ /* * 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 network_internal.h Variables and function used internally. */ #ifndef NETWORK_INTERNAL_H #define NETWORK_INTERNAL_H #include "network_func.h" #include "core/tcp_game.h" #include "../command_type.h" #ifdef ENABLE_NETWORK #ifdef RANDOM_DEBUG /** * If this line is enable, every frame will have a sync test * this is not needed in normal games. Normal is like 1 sync in 100 * frames. You can enable this if you have a lot of desyncs on a certain * game. * Remember: both client and server have to be compiled with this * option enabled to make it to work. If one of the two has it disabled * nothing will happen. */ #define ENABLE_NETWORK_SYNC_EVERY_FRAME /** * In theory sending 1 of the 2 seeds is enough to check for desyncs * so in theory, this next define can be left off. */ #define NETWORK_SEND_DOUBLE_SEED #endif /* RANDOM_DEBUG */ /** * Helper variable to make the dedicated server go fast until the (first) join. * Used to load the desync debug logs, i.e. for reproducing a desync. * There's basically no need to ever enable this, unless you really know what * you are doing, i.e. debugging a desync. * See docs/desync.txt for details. */ #ifdef DEBUG_DUMP_COMMANDS extern bool _ddc_fastforward; #else #define _ddc_fastforward (false) #endif /* DEBUG_DUMP_COMMANDS */ typedef class ServerNetworkGameSocketHandler NetworkClientSocket; /** Status of the clients during joining. */ enum NetworkJoinStatus { NETWORK_JOIN_STATUS_CONNECTING, NETWORK_JOIN_STATUS_AUTHORIZING, NETWORK_JOIN_STATUS_WAITING, NETWORK_JOIN_STATUS_DOWNLOADING, NETWORK_JOIN_STATUS_PROCESSING, NETWORK_JOIN_STATUS_REGISTERING, NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO, NETWORK_JOIN_STATUS_END, }; /** Language ids for server_lang and client_lang. Do NOT modify the order. */ enum NetworkLanguage { NETLANG_ANY = 0, NETLANG_ENGLISH, NETLANG_GERMAN, NETLANG_FRENCH, NETLANG_BRAZILIAN, NETLANG_BULGARIAN, NETLANG_CHINESE, NETLANG_CZECH, NETLANG_DANISH, NETLANG_DUTCH, NETLANG_ESPERANTO, NETLANG_FINNISH, NETLANG_HUNGARIAN, NETLANG_ICELANDIC, NETLANG_ITALIAN, NETLANG_JAPANESE, NETLANG_KOREAN, NETLANG_LITHUANIAN, NETLANG_NORWEGIAN, NETLANG_POLISH, NETLANG_PORTUGUESE, NETLANG_ROMANIAN, NETLANG_RUSSIAN, NETLANG_SLOVAK, NETLANG_SLOVENIAN, NETLANG_SPANISH, NETLANG_SWEDISH, NETLANG_TURKISH, NETLANG_UKRAINIAN, NETLANG_AFRIKAANS, NETLANG_CROATIAN, NETLANG_CATALAN, NETLANG_ESTONIAN, NETLANG_GALICIAN, NETLANG_GREEK, NETLANG_LATVIAN, NETLANG_COUNT }; extern uint32 _frame_counter_server; // The frame_counter of the server, if in network-mode extern uint32 _frame_counter_max; // To where we may go with our clients extern uint32 _frame_counter; extern uint32 _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients. /* networking settings */ extern NetworkAddressList _broadcast_list; extern uint32 _sync_seed_1; #ifdef NETWORK_SEND_DOUBLE_SEED extern uint32 _sync_seed_2; #endif extern uint32 _sync_frame; extern bool _network_first_time; /* Vars needed for the join-GUI */ extern NetworkJoinStatus _network_join_status; extern uint8 _network_join_waiting; extern uint32 _network_join_bytes; extern uint32 _network_join_bytes_total; extern uint8 _network_reconnect; extern bool _network_udp_server; extern uint16 _network_udp_broadcast; extern uint8 _network_advertise_retries; extern CompanyMask _network_company_passworded; void NetworkTCPQueryServer(NetworkAddress address); void GetBindAddresses(NetworkAddressList *addresses, uint16 port); void NetworkAddServer(const char *b); void NetworkRebuildHostList(); void UpdateNetworkGameWindow(); bool IsNetworkCompatibleVersion(const char *version); /* From network_command.cpp */ /** * Everything we need to know about a command to be able to execute it. */ struct CommandPacket : CommandContainer { /** Make sure the pointer is NULL. */ CommandPacket() : next(NULL), company(INVALID_COMPANY), frame(0), my_cmd(false) {} CommandPacket *next; ///< the next command packet (if in queue) CompanyID company; ///< company that is executing the command uint32 frame; ///< the frame in which this packet is executed bool my_cmd; ///< did the command originate from "me" }; void NetworkDistributeCommands(); void NetworkExecuteLocalCommandQueue(); void NetworkFreeLocalCommandQueue(); void NetworkSyncCommandQueue(NetworkClientSocket *cs); void NetworkError(StringID error_string); void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const char *name, const char *str = "", int64 data = 0); uint NetworkCalculateLag(const NetworkClientSocket *cs); StringID GetNetworkErrorMsg(NetworkErrorCode err); bool NetworkFindName(char *new_name, const char *last); const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed); #endif /* ENABLE_NETWORK */ #endif /* NETWORK_INTERNAL_H */ openttd-1.5.3/src/network/network_udp.cpp0000644000000000000000000006153412627373441017242 0ustar rootroot/* $Id: network_udp.cpp 27431 2015-11-01 11:59:17Z frosch $ */ /* * 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 network_udp.cpp This file handles the UDP related communication. * * This is the GameServer <-> MasterServer and GameServer <-> GameClient * communication before the game is being joined. */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "../date_func.h" #include "../map_func.h" #include "../debug.h" #include "network_gamelist.h" #include "network_internal.h" #include "network_udp.h" #include "network.h" #include "../core/endian_func.hpp" #include "../company_base.h" #include "../thread/thread.h" #include "../rev.h" #include "../newgrf_text.h" #include "../strings_func.h" #include "table/strings.h" #include "core/udp.h" #include "../safeguards.h" /** Mutex for all out threaded udp resolution and such. */ static ThreadMutex *_network_udp_mutex = ThreadMutex::New(); /** Session key to register ourselves to the master server */ static uint64 _session_key = 0; static const uint32 ADVERTISE_NORMAL_INTERVAL = 15 * 60 * 1000; ///< interval between advertising in ms (15 minutes) static const uint32 ADVERTISE_RETRY_INTERVAL = 10 * 1000; ///< re-advertise when no response after this many ms (10 seconds) static const uint32 ADVERTISE_RETRY_TIMES = 3; ///< give up re-advertising after this much failed retries NetworkUDPSocketHandler *_udp_client_socket = NULL; ///< udp client socket NetworkUDPSocketHandler *_udp_server_socket = NULL; ///< udp server socket NetworkUDPSocketHandler *_udp_master_socket = NULL; ///< udp master socket /** Simpler wrapper struct for NetworkUDPQueryServerThread */ struct NetworkUDPQueryServerInfo : NetworkAddress { bool manually; ///< Did we connect manually or not? /** * Create the structure. * @param address The address of the server to query. * @param manually Whether the address was entered manually. */ NetworkUDPQueryServerInfo(const NetworkAddress &address, bool manually) : NetworkAddress(address), manually(manually) { } }; /** * Helper function doing the actual work for querying the server. * @param address The address of the server. * @param needs_mutex Whether we need to acquire locks when sending the packet or not. * @param manually Whether the address was entered manually. */ static void NetworkUDPQueryServer(NetworkAddress *address, bool needs_mutex, bool manually) { /* Clear item in gamelist */ NetworkGameList *item = CallocT(1); address->GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); strecpy(item->info.hostname, address->GetHostname(), lastof(item->info.hostname)); item->address = *address; item->manually = manually; NetworkGameListAddItemDelayed(item); if (needs_mutex) _network_udp_mutex->BeginCritical(); /* Init the packet */ Packet p(PACKET_UDP_CLIENT_FIND_SERVER); if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address); if (needs_mutex) _network_udp_mutex->EndCritical(); } /** * Threaded part for resolving the IP of a server and querying it. * @param pntr the NetworkUDPQueryServerInfo. */ static void NetworkUDPQueryServerThread(void *pntr) { NetworkUDPQueryServerInfo *info = (NetworkUDPQueryServerInfo*)pntr; NetworkUDPQueryServer(info, true, info->manually); delete info; } /** * Query a specific server. * @param address The address of the server. * @param manually Whether the address was entered manually. */ void NetworkUDPQueryServer(NetworkAddress address, bool manually) { NetworkUDPQueryServerInfo *info = new NetworkUDPQueryServerInfo(address, manually); if (address.IsResolved() || !ThreadObject::New(NetworkUDPQueryServerThread, info)) { NetworkUDPQueryServerThread(info); } } ///*** Communication with the masterserver ***/ /** Helper class for connecting to the master server. */ class MasterNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: virtual void Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr); virtual void Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr); public: /** * Create the socket. * @param addresses The addresses to bind on. */ MasterNetworkUDPSocketHandler(NetworkAddressList *addresses) : NetworkUDPSocketHandler(addresses) {} virtual ~MasterNetworkUDPSocketHandler() {} }; void MasterNetworkUDPSocketHandler::Receive_MASTER_ACK_REGISTER(Packet *p, NetworkAddress *client_addr) { _network_advertise_retries = 0; DEBUG(net, 2, "[udp] advertising on master server successful (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family)); /* We are advertised, but we don't want to! */ if (!_settings_client.network.server_advertise) NetworkUDPRemoveAdvertise(false); } void MasterNetworkUDPSocketHandler::Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr) { _session_key = p->Recv_uint64(); DEBUG(net, 2, "[udp] received new session key from master server (%s)", NetworkAddress::AddressFamilyAsString(client_addr->GetAddress()->ss_family)); } ///*** Communication with clients (we are server) ***/ /** Helper class for handling all server side communication. */ class ServerNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: virtual void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr); virtual void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr); virtual void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr); public: /** * Create the socket. * @param addresses The addresses to bind on. */ ServerNetworkUDPSocketHandler(NetworkAddressList *addresses) : NetworkUDPSocketHandler(addresses) {} virtual ~ServerNetworkUDPSocketHandler() {} }; void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { /* Just a fail-safe.. should never happen */ if (!_network_udp_server) { return; } NetworkGameInfo ngi; /* Update some game_info */ ngi.clients_on = _network_game_info.clients_on; ngi.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); ngi.server_lang = _settings_client.network.server_lang; ngi.use_password = !StrEmpty(_settings_client.network.server_password); ngi.clients_max = _settings_client.network.max_clients; ngi.companies_on = (byte)Company::GetNumItems(); ngi.companies_max = _settings_client.network.max_companies; ngi.spectators_on = NetworkSpectatorCount(); ngi.spectators_max = _settings_client.network.max_spectators; ngi.game_date = _date; ngi.map_width = MapSizeX(); ngi.map_height = MapSizeY(); ngi.map_set = _settings_game.game_creation.landscape; ngi.dedicated = _network_dedicated; ngi.grfconfig = _grfconfig; strecpy(ngi.map_name, _network_game_info.map_name, lastof(ngi.map_name)); strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name)); strecpy(ngi.server_revision, _openttd_revision, lastof(ngi.server_revision)); Packet packet(PACKET_UDP_SERVER_RESPONSE); this->SendNetworkGameInfo(&packet, &ngi); /* Let the client know that we are here */ this->SendPacket(&packet, client_addr); DEBUG(net, 2, "[udp] queried from %s", client_addr->GetHostname()); } void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { /* Just a fail-safe.. should never happen */ if (!_network_udp_server) return; Packet packet(PACKET_UDP_SERVER_DETAIL_INFO); /* Send the amount of active companies */ packet.Send_uint8 (NETWORK_COMPANY_INFO_VERSION); packet.Send_uint8 ((uint8)Company::GetNumItems()); /* Fetch the latest version of the stats */ NetworkCompanyStats company_stats[MAX_COMPANIES]; NetworkPopulateCompanyStats(company_stats); /* The minimum company information "blob" size. */ static const uint MIN_CI_SIZE = 54; uint max_cname_length = NETWORK_COMPANY_NAME_LENGTH; if (Company::GetNumItems() * (MIN_CI_SIZE + NETWORK_COMPANY_NAME_LENGTH) >= (uint)SEND_MTU - packet.size) { /* Assume we can at least put the company information in the packets. */ assert(Company::GetNumItems() * MIN_CI_SIZE < (uint)SEND_MTU - packet.size); /* At this moment the company names might not fit in the * packet. Check whether that is really the case. */ for (;;) { int free = SEND_MTU - packet.size; Company *company; FOR_ALL_COMPANIES(company) { char company_name[NETWORK_COMPANY_NAME_LENGTH]; SetDParam(0, company->index); GetString(company_name, STR_COMPANY_NAME, company_name + max_cname_length - 1); free -= MIN_CI_SIZE; free -= (int)strlen(company_name); } if (free >= 0) break; /* Try again, with slightly shorter strings. */ assert(max_cname_length > 0); max_cname_length--; } } Company *company; /* Go through all the companies */ FOR_ALL_COMPANIES(company) { /* Send the information */ this->SendCompanyInformation(&packet, company, &company_stats[company->index], max_cname_length); } this->SendPacket(&packet, client_addr); } /** * A client has requested the names of some NewGRFs. * * Replying this can be tricky as we have a limit of SEND_MTU bytes * in the reply packet and we can send up to 100 bytes per NewGRF * (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name). * As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it * could be that a packet overflows. To stop this we only reply * with the first N NewGRFs so that if the first N + 1 NewGRFs * would be sent, the packet overflows. * in_reply and in_reply_count are used to keep a list of GRFs to * send in the reply. */ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr) { uint8 num_grfs; uint i; const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT]; uint8 in_reply_count = 0; size_t packet_len = 0; DEBUG(net, 6, "[udp] newgrf data request from %s", client_addr->GetAddressAsString()); num_grfs = p->Recv_uint8 (); if (num_grfs > NETWORK_MAX_GRF_COUNT) return; for (i = 0; i < num_grfs; i++) { GRFIdentifier c; const GRFConfig *f; this->ReceiveGRFIdentifier(p, &c); /* Find the matching GRF file */ f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); if (f == NULL) continue; // The GRF is unknown to this server /* If the reply might exceed the size of the packet, only reply * the current list and do not send the other data. * The name could be an empty string, if so take the filename. */ packet_len += sizeof(c.grfid) + sizeof(c.md5sum) + min(strlen(f->GetName()) + 1, (size_t)NETWORK_GRF_NAME_LENGTH); if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply break; } in_reply[in_reply_count] = f; in_reply_count++; } if (in_reply_count == 0) return; Packet packet(PACKET_UDP_SERVER_NEWGRFS); packet.Send_uint8(in_reply_count); for (i = 0; i < in_reply_count; i++) { char name[NETWORK_GRF_NAME_LENGTH]; /* The name could be an empty string, if so take the filename */ strecpy(name, in_reply[i]->GetName(), lastof(name)); this->SendGRFIdentifier(&packet, &in_reply[i]->ident); packet.Send_string(name); } this->SendPacket(&packet, client_addr); } ///*** Communication with servers (we are client) ***/ /** Helper class for handling all client side communication. */ class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler { protected: virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr); virtual void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr); virtual void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr); virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config); public: virtual ~ClientNetworkUDPSocketHandler() {} }; void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { NetworkGameList *item; /* Just a fail-safe.. should never happen */ if (_network_udp_server) return; DEBUG(net, 4, "[udp] server response from %s", client_addr->GetAddressAsString()); /* Find next item */ item = NetworkGameListAddItem(*client_addr); ClearGRFConfigList(&item->info.grfconfig); this->ReceiveNetworkGameInfo(p, &item->info); item->info.compatible = true; { /* Checks whether there needs to be a request for names of GRFs and makes * the request if necessary. GRFs that need to be requested are the GRFs * that do not exist on the clients system and we do not have the name * resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER. * The in_request array and in_request_count are used so there is no need * to do a second loop over the GRF list, which can be relatively expensive * due to the string comparisons. */ const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT]; const GRFConfig *c; uint in_request_count = 0; for (c = item->info.grfconfig; c != NULL; c = c->next) { if (c->status == GCS_NOT_FOUND) item->info.compatible = false; if (c->status != GCS_NOT_FOUND || strcmp(c->GetName(), UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue; in_request[in_request_count] = c; in_request_count++; } if (in_request_count > 0) { /* There are 'unknown' GRFs, now send a request for them */ uint i; Packet packet(PACKET_UDP_CLIENT_GET_NEWGRFS); packet.Send_uint8(in_request_count); for (i = 0; i < in_request_count; i++) { this->SendGRFIdentifier(&packet, &in_request[i]->ident); } this->SendPacket(&packet, &item->address); } } if (item->info.hostname[0] == '\0') { seprintf(item->info.hostname, lastof(item->info.hostname), "%s", client_addr->GetHostname()); } if (client_addr->GetAddress()->ss_family == AF_INET6) { strecat(item->info.server_name, " (IPv6)", lastof(item->info.server_name)); } /* Check if we are allowed on this server based on the revision-match */ item->info.version_compatible = IsNetworkCompatibleVersion(item->info.server_revision); item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs item->online = true; UpdateNetworkGameWindow(); } void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) { /* packet begins with the protocol version (uint8) * then an uint16 which indicates how many * ip:port pairs are in this packet, after that * an uint32 (ip) and an uint16 (port) for each pair. */ ServerListType type = (ServerListType)(p->Recv_uint8() - 1); if (type < SLT_END) { for (int i = p->Recv_uint16(); i != 0 ; i--) { sockaddr_storage addr_storage; memset(&addr_storage, 0, sizeof(addr_storage)); if (type == SLT_IPv4) { addr_storage.ss_family = AF_INET; ((sockaddr_in*)&addr_storage)->sin_addr.s_addr = TO_LE32(p->Recv_uint32()); } else { assert(type == SLT_IPv6); addr_storage.ss_family = AF_INET6; byte *addr = (byte*)&((sockaddr_in6*)&addr_storage)->sin6_addr; for (uint i = 0; i < sizeof(in6_addr); i++) *addr++ = p->Recv_uint8(); } NetworkAddress addr(addr_storage, type == SLT_IPv4 ? sizeof(sockaddr_in) : sizeof(sockaddr_in6)); addr.SetPort(p->Recv_uint16()); /* Somehow we reached the end of the packet */ if (this->HasClientQuit()) return; NetworkUDPQueryServer(&addr, false, false); } } } /** The return of the client's request of the names of some NewGRFs */ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) { uint8 num_grfs; uint i; DEBUG(net, 6, "[udp] newgrf data reply from %s", client_addr->GetAddressAsString()); num_grfs = p->Recv_uint8 (); if (num_grfs > NETWORK_MAX_GRF_COUNT) return; for (i = 0; i < num_grfs; i++) { char name[NETWORK_GRF_NAME_LENGTH]; GRFIdentifier c; this->ReceiveGRFIdentifier(p, &c); p->Recv_string(name, sizeof(name)); /* An empty name is not possible under normal circumstances * and causes problems when showing the NewGRF list. */ if (StrEmpty(name)) continue; /* Try to find the GRFTextWrapper for the name of this GRF ID and MD5sum tuple. * If it exists and not resolved yet, then name of the fake GRF is * overwritten with the name from the reply. */ GRFTextWrapper *unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false); if (unknown_name != NULL && strcmp(GetGRFStringFromGRFText(unknown_name->text), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) { AddGRFTextToList(&unknown_name->text, name); } } } void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { /* Find the matching GRF file */ const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum); if (f == NULL) { /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already */ config->name->Release(); config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); config->name->AddRef(); config->status = GCS_NOT_FOUND; } else { config->filename = f->filename; config->name->Release(); config->name = f->name; config->name->AddRef(); config->info->Release(); config->info = f->info; config->info->AddRef(); config->url->Release(); config->url = f->url; config->url->AddRef(); } SetBit(config->flags, GCF_COPY); } /** Broadcast to all ips */ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) { for (NetworkAddress *addr = _broadcast_list.Begin(); addr != _broadcast_list.End(); addr++) { Packet p(PACKET_UDP_CLIENT_FIND_SERVER); DEBUG(net, 4, "[udp] broadcasting to %s", addr->GetHostname()); socket->SendPacket(&p, addr, true, true); } } /** Request the the server-list from the master server */ void NetworkUDPQueryMasterServer() { Packet p(PACKET_UDP_CLIENT_GET_LIST); NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT); /* packet only contains protocol version */ p.Send_uint8(NETWORK_MASTER_SERVER_VERSION); p.Send_uint8(SLT_AUTODETECT); _udp_client_socket->SendPacket(&p, &out_addr, true); DEBUG(net, 2, "[udp] master server queried at %s", out_addr.GetAddressAsString()); } /** Find all servers */ void NetworkUDPSearchGame() { /* We are still searching.. */ if (_network_udp_broadcast > 0) return; DEBUG(net, 0, "[udp] searching server"); NetworkUDPBroadCast(_udp_client_socket); _network_udp_broadcast = 300; // Stay searching for 300 ticks } /** * Thread entry point for de-advertising. * @param pntr unused. */ static void NetworkUDPRemoveAdvertiseThread(void *pntr) { DEBUG(net, 1, "[udp] removing advertise from master server"); /* Find somewhere to send */ NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT); /* Send the packet */ Packet p(PACKET_UDP_SERVER_UNREGISTER); /* Packet is: Version, server_port */ p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION); p.Send_uint16(_settings_client.network.server_port); _network_udp_mutex->BeginCritical(); if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true); _network_udp_mutex->EndCritical(); } /** * Remove our advertise from the master-server. * @param blocking whether to wait until the removal has finished. */ void NetworkUDPRemoveAdvertise(bool blocking) { /* Check if we are advertising */ if (!_networking || !_network_server || !_network_udp_server) return; if (blocking || !ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL)) { NetworkUDPRemoveAdvertiseThread(NULL); } } /** * Thread entry point for advertising. * @param pntr unused. */ static void NetworkUDPAdvertiseThread(void *pntr) { /* Find somewhere to send */ NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT); DEBUG(net, 1, "[udp] advertising to master server"); /* Add a bit more messaging when we cannot get a session key */ static byte session_key_retries = 0; if (_session_key == 0 && session_key_retries++ == 2) { DEBUG(net, 0, "[udp] advertising to the master server is failing"); DEBUG(net, 0, "[udp] we are not receiving the session key from the server"); DEBUG(net, 0, "[udp] please allow udp packets from %s to you to be delivered", out_addr.GetAddressAsString(false)); DEBUG(net, 0, "[udp] please allow udp packets from you to %s to be delivered", out_addr.GetAddressAsString(false)); } if (_session_key != 0 && _network_advertise_retries == 0) { DEBUG(net, 0, "[udp] advertising to the master server is failing"); DEBUG(net, 0, "[udp] we are not receiving the acknowledgement from the server"); DEBUG(net, 0, "[udp] this usually means that the master server cannot reach us"); DEBUG(net, 0, "[udp] please allow udp and tcp packets to port %u to be delivered", _settings_client.network.server_port); DEBUG(net, 0, "[udp] please allow udp and tcp packets from port %u to be delivered", _settings_client.network.server_port); } /* Send the packet */ Packet p(PACKET_UDP_SERVER_REGISTER); /* Packet is: WELCOME_MESSAGE, Version, server_port */ p.Send_string(NETWORK_MASTER_SERVER_WELCOME_MESSAGE); p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION); p.Send_uint16(_settings_client.network.server_port); p.Send_uint64(_session_key); _network_udp_mutex->BeginCritical(); if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true); _network_udp_mutex->EndCritical(); } /** * Register us to the master server * This function checks if it needs to send an advertise */ void NetworkUDPAdvertise() { static uint32 _last_advertisement = 0; ///< The time of the last advertisement (used to check for wrapping of time) static uint32 _next_advertisement = 0; ///< The next time we should perform a normal advertisement. static uint32 _next_retry = 0; ///< The next time we should perform a retry of an advertisement. /* Check if we should send an advertise */ if (!_networking || !_network_server || !_network_udp_server || !_settings_client.network.server_advertise) return; if (_network_need_advertise || _realtime_tick < _last_advertisement) { /* Forced advertisement, or a wrapping of time in which case we determine the advertisement/retry times again. */ _network_need_advertise = false; _network_advertise_retries = ADVERTISE_RETRY_TIMES; } else { /* Only send once every ADVERTISE_NORMAL_INTERVAL ticks */ if (_network_advertise_retries == 0) { if (_realtime_tick <= _next_advertisement) return; _network_advertise_retries = ADVERTISE_RETRY_TIMES; } else { /* An actual retry. */ if (_realtime_tick <= _next_retry) return; } } _network_advertise_retries--; _last_advertisement = _realtime_tick; _next_advertisement = _realtime_tick + ADVERTISE_NORMAL_INTERVAL; _next_retry = _realtime_tick + ADVERTISE_RETRY_INTERVAL; /* Make sure we do not have an overflow when checking these; when time wraps, we simply force an advertisement. */ if (_next_advertisement < _last_advertisement) _next_advertisement = UINT32_MAX; if (_next_retry < _last_advertisement) _next_retry = UINT32_MAX; if (!ThreadObject::New(NetworkUDPAdvertiseThread, NULL)) { NetworkUDPAdvertiseThread(NULL); } } /** Initialize the whole UDP bit. */ void NetworkUDPInitialize() { /* If not closed, then do it. */ if (_udp_server_socket != NULL) NetworkUDPClose(); DEBUG(net, 1, "[udp] initializing listeners"); assert(_udp_client_socket == NULL && _udp_server_socket == NULL && _udp_master_socket == NULL); _network_udp_mutex->BeginCritical(); _udp_client_socket = new ClientNetworkUDPSocketHandler(); NetworkAddressList server; GetBindAddresses(&server, _settings_client.network.server_port); _udp_server_socket = new ServerNetworkUDPSocketHandler(&server); server.Clear(); GetBindAddresses(&server, 0); _udp_master_socket = new MasterNetworkUDPSocketHandler(&server); _network_udp_server = false; _network_udp_broadcast = 0; _network_udp_mutex->EndCritical(); } /** Close all UDP related stuff. */ void NetworkUDPClose() { _network_udp_mutex->BeginCritical(); _udp_server_socket->Close(); _udp_master_socket->Close(); _udp_client_socket->Close(); delete _udp_client_socket; delete _udp_server_socket; delete _udp_master_socket; _udp_client_socket = NULL; _udp_server_socket = NULL; _udp_master_socket = NULL; _network_udp_mutex->EndCritical(); _network_udp_server = false; _network_udp_broadcast = 0; DEBUG(net, 1, "[udp] closed listeners"); } /** Receive the UDP packets. */ void NetworkBackgroundUDPLoop() { _network_udp_mutex->BeginCritical(); if (_network_udp_server) { _udp_server_socket->ReceivePackets(); _udp_master_socket->ReceivePackets(); } else { _udp_client_socket->ReceivePackets(); if (_network_udp_broadcast > 0) _network_udp_broadcast--; } _network_udp_mutex->EndCritical(); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_admin.h0000644000000000000000000001325012627373441017177 0ustar rootroot/* $Id: network_admin.h 25588 2013-07-11 20:31:39Z planetmaker $ */ /* * 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 network_admin.h Server part of the admin network protocol. */ #ifndef NETWORK_ADMIN_H #define NETWORK_ADMIN_H #ifdef ENABLE_NETWORK #include "network_internal.h" #include "core/tcp_listen.h" #include "core/tcp_admin.h" extern AdminIndex _redirect_console_to_admin; class ServerNetworkAdminSocketHandler; /** Pool with all admin connections. */ typedef Pool NetworkAdminSocketPool; extern NetworkAdminSocketPool _networkadminsocket_pool; /** Class for handling the server side of the game connection. */ class ServerNetworkAdminSocketHandler : public NetworkAdminSocketPool::PoolItem<&_networkadminsocket_pool>, public NetworkAdminSocketHandler, public TCPListenHandler { protected: virtual NetworkRecvStatus Receive_ADMIN_JOIN(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_QUIT(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_UPDATE_FREQUENCY(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_POLL(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_CHAT(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_RCON(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_GAMESCRIPT(Packet *p); virtual NetworkRecvStatus Receive_ADMIN_PING(Packet *p); NetworkRecvStatus SendProtocol(); NetworkRecvStatus SendPong(uint32 d1); public: AdminUpdateFrequency update_frequency[ADMIN_UPDATE_END]; ///< Admin requested update intervals. uint32 realtime_connect; ///< Time of connection. NetworkAddress address; ///< Address of the admin. ServerNetworkAdminSocketHandler(SOCKET s); ~ServerNetworkAdminSocketHandler(); NetworkRecvStatus SendError(NetworkErrorCode error); NetworkRecvStatus SendWelcome(); NetworkRecvStatus SendNewGame(); NetworkRecvStatus SendShutdown(); NetworkRecvStatus SendDate(); NetworkRecvStatus SendClientJoin(ClientID client_id); NetworkRecvStatus SendClientInfo(const NetworkClientSocket *cs, const NetworkClientInfo *ci); NetworkRecvStatus SendClientUpdate(const NetworkClientInfo *ci); NetworkRecvStatus SendClientQuit(ClientID client_id); NetworkRecvStatus SendClientError(ClientID client_id, NetworkErrorCode error); NetworkRecvStatus SendCompanyNew(CompanyID company_id); NetworkRecvStatus SendCompanyInfo(const Company *c); NetworkRecvStatus SendCompanyUpdate(const Company *c); NetworkRecvStatus SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr); NetworkRecvStatus SendCompanyEconomy(); NetworkRecvStatus SendCompanyStats(); NetworkRecvStatus SendChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data); NetworkRecvStatus SendRcon(uint16 colour, const char *command); NetworkRecvStatus SendConsole(const char *origin, const char *command); NetworkRecvStatus SendGameScript(const char *json); NetworkRecvStatus SendCmdNames(); NetworkRecvStatus SendCmdLogging(ClientID client_id, const CommandPacket *cp); NetworkRecvStatus SendRconEnd(const char *command); static void Send(); static void AcceptConnection(SOCKET s, const NetworkAddress &address); static bool AllowConnection(); static void WelcomeAll(); /** * Get the name used by the listener. * @return the name to show in debug logs and the like. */ static const char *GetName() { return "admin"; } }; /** * Iterate over all the sockets from a given starting point. * @param var The variable to iterate with. * @param start The start of the iteration. */ #define FOR_ALL_ADMIN_SOCKETS_FROM(var, start) FOR_ALL_ITEMS_FROM(ServerNetworkAdminSocketHandler, adminsocket_index, var, start) /** * Iterate over all the sockets. * @param var The variable to iterate with. */ #define FOR_ALL_ADMIN_SOCKETS(var) FOR_ALL_ADMIN_SOCKETS_FROM(var, 0) /** * Iterate over all the active sockets. * @param var The variable to iterate with. */ #define FOR_ALL_ACTIVE_ADMIN_SOCKETS(var) \ FOR_ALL_ADMIN_SOCKETS(var) \ if (var->GetAdminStatus() == ADMIN_STATUS_ACTIVE) void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client = false); void NetworkAdminClientUpdate(const NetworkClientInfo *ci); void NetworkAdminClientQuit(ClientID client_id); void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code); void NetworkAdminCompanyInfo(const Company *company, bool new_company); void NetworkAdminCompanyUpdate(const Company *company); void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr); void NetworkAdminChat(NetworkAction action, DestType desttype, ClientID client_id, const char *msg, int64 data = 0, bool from_admin = false); void NetworkAdminUpdate(AdminUpdateFrequency freq); void NetworkServerSendAdminRcon(AdminIndex admin_index, TextColour colour_code, const char *string); void NetworkAdminConsole(const char *origin, const char *string); void NetworkAdminGameScript(const char *json); void NetworkAdminCmdLogging(const NetworkClientSocket *owner, const CommandPacket *cp); #endif /* ENABLE_NETWORK */ #endif /* NETWORK_ADMIN_H */ openttd-1.5.3/src/network/network_gamelist.cpp0000644000000000000000000001522012627373441020246 0ustar rootroot/* $Id: network_gamelist.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 network_gamelist.cpp This file handles the GameList * Also, it handles the request to a server for data about the server */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "../debug.h" #include "../window_func.h" #include "../thread/thread.h" #include "network_internal.h" #include "network_udp.h" #include "network_gamelist.h" #include "../safeguards.h" NetworkGameList *_network_game_list = NULL; /** Mutex for handling delayed insertion/querying of servers. */ static ThreadMutex *_network_game_list_mutex = ThreadMutex::New(); /** The games to insert when the GUI thread has time for us. */ static NetworkGameList *_network_game_delayed_insertion_list = NULL; /** * Add a new item to the linked gamelist, but do it delayed in the next tick * or so to prevent race conditions. * @param item the item to add. Will be freed once added. */ void NetworkGameListAddItemDelayed(NetworkGameList *item) { _network_game_list_mutex->BeginCritical(); item->next = _network_game_delayed_insertion_list; _network_game_delayed_insertion_list = item; _network_game_list_mutex->EndCritical(); } /** Perform the delayed (thread safe) insertion into the game list */ static void NetworkGameListHandleDelayedInsert() { _network_game_list_mutex->BeginCritical(); while (_network_game_delayed_insertion_list != NULL) { NetworkGameList *ins_item = _network_game_delayed_insertion_list; _network_game_delayed_insertion_list = ins_item->next; NetworkGameList *item = NetworkGameListAddItem(ins_item->address); if (item != NULL) { if (StrEmpty(item->info.server_name)) { ClearGRFConfigList(&item->info.grfconfig); memset(&item->info, 0, sizeof(item->info)); strecpy(item->info.server_name, ins_item->info.server_name, lastof(item->info.server_name)); strecpy(item->info.hostname, ins_item->info.hostname, lastof(item->info.hostname)); item->online = false; } item->manually |= ins_item->manually; if (item->manually) NetworkRebuildHostList(); UpdateNetworkGameWindow(); } free(ins_item); } _network_game_list_mutex->EndCritical(); } /** * Add a new item to the linked gamelist. If the IP and Port match * return the existing item instead of adding it again * @param address the address of the to-be added item * @return a point to the newly added or already existing item */ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) { const char *hostname = address.GetHostname(); /* Do not query the 'any' address. */ if (StrEmpty(hostname) || strcmp(hostname, "0.0.0.0") == 0 || strcmp(hostname, "::") == 0) { return NULL; } NetworkGameList *item, *prev_item; prev_item = NULL; for (item = _network_game_list; item != NULL; item = item->next) { if (item->address == address) return item; prev_item = item; } item = CallocT(1); item->next = NULL; item->address = address; if (prev_item == NULL) { _network_game_list = item; } else { prev_item->next = item; } DEBUG(net, 4, "[gamelist] added server to list"); UpdateNetworkGameWindow(); return item; } /** * Remove an item from the gamelist linked list * @param remove pointer to the item to be removed */ void NetworkGameListRemoveItem(NetworkGameList *remove) { NetworkGameList *prev_item = NULL; for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { if (remove == item) { if (prev_item == NULL) { _network_game_list = remove->next; } else { prev_item->next = remove->next; } /* Remove GRFConfig information */ ClearGRFConfigList(&remove->info.grfconfig); free(remove); remove = NULL; DEBUG(net, 4, "[gamelist] removed server from list"); NetworkRebuildHostList(); UpdateNetworkGameWindow(); return; } prev_item = item; } } static const uint MAX_GAME_LIST_REQUERY_COUNT = 10; ///< How often do we requery in number of times per server? static const uint REQUERY_EVERY_X_GAMELOOPS = 60; ///< How often do we requery in time? static const uint REFRESH_GAMEINFO_X_REQUERIES = 50; ///< Refresh the game info itself after REFRESH_GAMEINFO_X_REQUERIES * REQUERY_EVERY_X_GAMELOOPS game loops /** Requeries the (game) servers we have not gotten a reply from */ void NetworkGameListRequery() { NetworkGameListHandleDelayedInsert(); static uint8 requery_cnt = 0; if (++requery_cnt < REQUERY_EVERY_X_GAMELOOPS) return; requery_cnt = 0; for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { item->retries++; if (item->retries < REFRESH_GAMEINFO_X_REQUERIES && (item->online || item->retries >= MAX_GAME_LIST_REQUERY_COUNT)) continue; /* item gets mostly zeroed by NetworkUDPQueryServer */ uint8 retries = item->retries; NetworkUDPQueryServer(NetworkAddress(item->address)); item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries; } } /** * Rebuild the GRFConfig's of the servers in the game list as we did * a rescan and might have found new NewGRFs. */ void NetworkAfterNewGRFScan() { for (NetworkGameList *item = _network_game_list; item != NULL; item = item->next) { /* Reset compatibility state */ item->info.compatible = item->info.version_compatible; for (GRFConfig *c = item->info.grfconfig; c != NULL; c = c->next) { assert(HasBit(c->flags, GCF_COPY)); const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum); if (f == NULL) { /* Don't know the GRF, so mark game incompatible and the (possibly) * already resolved name for this GRF (another server has sent the * name of the GRF already. */ c->name->Release(); c->name = FindUnknownGRFName(c->ident.grfid, c->ident.md5sum, true); c->name->AddRef(); c->status = GCS_NOT_FOUND; /* If we miss a file, we're obviously incompatible. */ item->info.compatible = false; } else { c->filename = f->filename; c->name->Release(); c->name = f->name; c->name->AddRef(); c->info->Release(); c->info = f->info; c->info->AddRef(); c->status = GCS_UNKNOWN; } } } InvalidateWindowClassesData(WC_NETWORK_WINDOW); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network.h0000644000000000000000000000321012627373441016022 0ustar rootroot/* $Id: network.h 26449 2014-04-08 20:19:41Z planetmaker $ */ /* * 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 network.h Basic functions/variables used all over the place. */ #ifndef NETWORK_H #define NETWORK_H #ifdef ENABLE_NETWORK void NetworkStartUp(); void NetworkShutDown(); void NetworkDrawChatMessage(); bool HasClients(); extern bool _networking; ///< are we in networking mode? extern bool _network_server; ///< network-server is active extern bool _network_available; ///< is network mode available? extern bool _network_dedicated; ///< are we a dedicated server? extern bool _is_network_server; ///< Does this client wants to be a network-server? #else /* ENABLE_NETWORK */ /* Network function stubs when networking is disabled */ static inline void NetworkStartUp() {} static inline void NetworkShutDown() {} static inline void NetworkDrawChatMessage() {} static inline bool HasClients() { return false; } #define _networking 0 #define _network_server 0 #define _network_available 0 #define _network_dedicated 0 #define _is_network_server 0 #endif /* ENABLE_NETWORK */ #endif /* NETWORK_H */ openttd-1.5.3/src/network/network_client.h0000644000000000000000000001305412627373441017367 0ustar rootroot/* $Id: network_client.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 network_client.h Client part of the network protocol. */ #ifndef NETWORK_CLIENT_H #define NETWORK_CLIENT_H #ifdef ENABLE_NETWORK #include "network_internal.h" /** Class for handling the client side of the game connection. */ class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public NetworkGameSocketHandler { private: struct PacketReader *savegame; ///< Packet reader for reading the savegame. byte token; ///< The token we need to send back to the server to prove we're the right client. /** Status of the connection with the server. */ enum ServerStatus { STATUS_INACTIVE, ///< The client is not connected nor active. STATUS_COMPANY_INFO, ///< We are trying to get company information. STATUS_JOIN, ///< We are trying to join a server. STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs. STATUS_AUTH_GAME, ///< Last action was requesting game (server) password. STATUS_AUTH_COMPANY, ///< Last action was requesting company password. STATUS_AUTHORIZED, ///< The client is authorized at the server. STATUS_MAP_WAIT, ///< The client is waiting as someone else is downloading the map. STATUS_MAP, ///< The client is downloading the map. STATUS_ACTIVE, ///< The client is active within in the game. STATUS_END, ///< Must ALWAYS be on the end of this list!! (period) }; ServerStatus status; ///< Status of the connection with the server. protected: friend void NetworkExecuteLocalCommandQueue(); friend void NetworkClose(bool close_admins); static ClientNetworkGameSocketHandler *my_client; ///< This is us! virtual NetworkRecvStatus Receive_SERVER_FULL(Packet *p); virtual NetworkRecvStatus Receive_SERVER_BANNED(Packet *p); virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet *p); virtual NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet *p); virtual NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p); virtual NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p); virtual NetworkRecvStatus Receive_SERVER_NEED_COMPANY_PASSWORD(Packet *p); virtual NetworkRecvStatus Receive_SERVER_WELCOME(Packet *p); virtual NetworkRecvStatus Receive_SERVER_WAIT(Packet *p); virtual NetworkRecvStatus Receive_SERVER_MAP_BEGIN(Packet *p); virtual NetworkRecvStatus Receive_SERVER_MAP_SIZE(Packet *p); virtual NetworkRecvStatus Receive_SERVER_MAP_DATA(Packet *p); virtual NetworkRecvStatus Receive_SERVER_MAP_DONE(Packet *p); virtual NetworkRecvStatus Receive_SERVER_JOIN(Packet *p); virtual NetworkRecvStatus Receive_SERVER_FRAME(Packet *p); virtual NetworkRecvStatus Receive_SERVER_SYNC(Packet *p); virtual NetworkRecvStatus Receive_SERVER_COMMAND(Packet *p); virtual NetworkRecvStatus Receive_SERVER_CHAT(Packet *p); virtual NetworkRecvStatus Receive_SERVER_QUIT(Packet *p); virtual NetworkRecvStatus Receive_SERVER_ERROR_QUIT(Packet *p); virtual NetworkRecvStatus Receive_SERVER_SHUTDOWN(Packet *p); virtual NetworkRecvStatus Receive_SERVER_NEWGAME(Packet *p); virtual NetworkRecvStatus Receive_SERVER_RCON(Packet *p); virtual NetworkRecvStatus Receive_SERVER_CHECK_NEWGRFS(Packet *p); virtual NetworkRecvStatus Receive_SERVER_MOVE(Packet *p); virtual NetworkRecvStatus Receive_SERVER_COMPANY_UPDATE(Packet *p); virtual NetworkRecvStatus Receive_SERVER_CONFIG_UPDATE(Packet *p); static NetworkRecvStatus SendNewGRFsOk(); static NetworkRecvStatus SendGetMap(); static NetworkRecvStatus SendMapOk(); void CheckConnection(); public: ClientNetworkGameSocketHandler(SOCKET s); ~ClientNetworkGameSocketHandler(); NetworkRecvStatus CloseConnection(NetworkRecvStatus status); void ClientError(NetworkRecvStatus res); static NetworkRecvStatus SendCompanyInformationQuery(); static NetworkRecvStatus SendJoin(); static NetworkRecvStatus SendCommand(const CommandPacket *cp); static NetworkRecvStatus SendError(NetworkErrorCode errorno); static NetworkRecvStatus SendQuit(); static NetworkRecvStatus SendAck(); static NetworkRecvStatus SendGamePassword(const char *password); static NetworkRecvStatus SendCompanyPassword(const char *password); static NetworkRecvStatus SendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data); static NetworkRecvStatus SendSetPassword(const char *password); static NetworkRecvStatus SendSetName(const char *name); static NetworkRecvStatus SendRCon(const char *password, const char *command); static NetworkRecvStatus SendMove(CompanyID company, const char *password); static bool IsConnected(); static void Send(); static bool Receive(); static bool GameLoop(); }; /** Helper to make the code look somewhat nicer. */ typedef ClientNetworkGameSocketHandler MyClient; void NetworkClient_Connected(); void NetworkClientSetCompanyPassword(const char *password); extern CompanyID _network_join_as; extern const char *_network_join_server_password; extern const char *_network_join_company_password; #endif /* ENABLE_NETWORK */ #endif /* NETWORK_CLIENT_H */ openttd-1.5.3/src/network/network_func.h0000644000000000000000000000770112627373441017046 0ustar rootroot/* $Id: network_func.h 27431 2015-11-01 11:59:17Z frosch $ */ /* * 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 network_func.h Network functions used by other parts of OpenTTD. */ #ifndef NETWORK_FUNC_H #define NETWORK_FUNC_H /** * Uncomment the following define to enable command replaying. * See docs/desync.txt for details. */ // #define DEBUG_DUMP_COMMANDS // #define DEBUG_FAILED_DUMP_COMMANDS #include "core/address.h" #include "network_type.h" #include "../console_type.h" #include "../gfx_type.h" #include "../openttd.h" #include "../company_type.h" #ifdef ENABLE_NETWORK extern NetworkServerGameInfo _network_game_info; extern NetworkCompanyState *_network_company_states; extern ClientID _network_own_client_id; extern ClientID _redirect_console_to_client; extern bool _network_need_advertise; extern uint8 _network_reconnect; extern StringList _network_bind_list; extern StringList _network_host_list; extern StringList _network_ban_list; byte NetworkSpectatorCount(); void NetworkUpdateClientName(); bool NetworkCompanyHasClients(CompanyID company); const char *NetworkChangeCompanyPassword(CompanyID company_id, const char *password); void NetworkReboot(); void NetworkDisconnect(bool blocking = false, bool close_admins = true); void NetworkGameLoop(); void NetworkBackgroundLoop(); void ParseConnectionString(const char **company, const char **port, char *connection_string); void NetworkStartDebugLog(NetworkAddress address); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); void NetworkClientsToSpectators(CompanyID cid); void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = NULL, const char *join_company_password = NULL); void NetworkClientRequestMove(CompanyID company, const char *pass = ""); void NetworkClientSendRcon(const char *password, const char *command); void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0); bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio); bool NetworkCompanyIsPassworded(CompanyID company_id); bool NetworkMaxCompaniesReached(); bool NetworkMaxSpectatorsReached(); void NetworkPrintClients(); void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode); /*** Commands ran by the server ***/ void NetworkServerDailyLoop(); void NetworkServerMonthlyLoop(); void NetworkServerYearlyLoop(); void NetworkServerSendConfigUpdate(); void NetworkServerShowStatusToConsole(); bool NetworkServerStart(); void NetworkServerNewCompany(const Company *company, NetworkClientInfo *ci); bool NetworkServerChangeClientName(ClientID client_id, const char *new_name); void NetworkServerDoMove(ClientID client_id, CompanyID company_id); void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string); void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, ClientID from_id, int64 data = 0, bool from_admin = false); void NetworkServerKickClient(ClientID client_id); uint NetworkServerKickOrBanIP(ClientID client_id, bool ban); uint NetworkServerKickOrBanIP(const char *ip, bool ban); void NetworkInitChatMessage(); void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *message, ...) WARN_FORMAT(3, 4); void NetworkUndrawChatMessage(); void NetworkChatMessageLoop(); void NetworkAfterNewGRFScan(); #endif /* ENABLE_NETWORK */ #endif /* NETWORK_FUNC_H */ openttd-1.5.3/src/network/network_content.cpp0000644000000000000000000010023512627373441020114 0ustar rootroot/* $Id: network_content.cpp 26489 2014-04-23 21:23:21Z rubidium $ */ /* * 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 network_content.cpp Content sending/receiving part of the network protocol. */ #if defined(ENABLE_NETWORK) #include "../stdafx.h" #include "../rev.h" #include "../ai/ai.hpp" #include "../game/game.hpp" #include "../window_func.h" #include "../error.h" #include "../base_media_base.h" #include "../settings_type.h" #include "network_content.h" #include "table/strings.h" #if defined(WITH_ZLIB) #include #endif #include "../safeguards.h" extern bool HasScenario(const ContentInfo *ci, bool md5sum); /** The client we use to connect to the server. */ ClientNetworkContentSocketHandler _network_content_client; /** Wrapper function for the HasProc */ static bool HasGRFConfig(const ContentInfo *ci, bool md5sum) { return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : NULL) != NULL; } /** * Check whether a function piece of content is locally known. * Matches on the unique ID and possibly the MD5 checksum. * @param ci the content info to search for * @param md5sum also match the MD5 checksum? * @return true iff it's known */ typedef bool (*HasProc)(const ContentInfo *ci, bool md5sum); bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) { ContentInfo *ci = new ContentInfo(); ci->type = (ContentType)p->Recv_uint8(); ci->id = (ContentID)p->Recv_uint32(); ci->filesize = p->Recv_uint32(); p->Recv_string(ci->name, lengthof(ci->name)); p->Recv_string(ci->version, lengthof(ci->name)); p->Recv_string(ci->url, lengthof(ci->url)); p->Recv_string(ci->description, lengthof(ci->description), SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE); ci->unique_id = p->Recv_uint32(); for (uint j = 0; j < sizeof(ci->md5sum); j++) { ci->md5sum[j] = p->Recv_uint8(); } ci->dependency_count = p->Recv_uint8(); ci->dependencies = MallocT(ci->dependency_count); for (uint i = 0; i < ci->dependency_count; i++) ci->dependencies[i] = (ContentID)p->Recv_uint32(); ci->tag_count = p->Recv_uint8(); ci->tags = MallocT(ci->tag_count); for (uint i = 0; i < ci->tag_count; i++) p->Recv_string(ci->tags[i], lengthof(*ci->tags)); if (!ci->IsValid()) { delete ci; this->Close(); return false; } /* Find the appropriate check function */ HasProc proc = NULL; switch (ci->type) { case CONTENT_TYPE_NEWGRF: proc = HasGRFConfig; break; case CONTENT_TYPE_BASE_GRAPHICS: proc = BaseGraphics::HasSet; break; case CONTENT_TYPE_BASE_MUSIC: proc = BaseMusic::HasSet; break; case CONTENT_TYPE_BASE_SOUNDS: proc = BaseSounds::HasSet; break; case CONTENT_TYPE_AI: proc = AI::HasAI; break; break; case CONTENT_TYPE_AI_LIBRARY: proc = AI::HasAILibrary; break; break; case CONTENT_TYPE_GAME: proc = Game::HasGame; break; break; case CONTENT_TYPE_GAME_LIBRARY: proc = Game::HasGameLibrary; break; break; case CONTENT_TYPE_SCENARIO: case CONTENT_TYPE_HEIGHTMAP: proc = HasScenario; break; default: break; } if (proc != NULL) { if (proc(ci, true)) { ci->state = ContentInfo::ALREADY_HERE; } else { ci->state = ContentInfo::UNSELECTED; if (proc(ci, false)) ci->upgrade = true; } } else { ci->state = ContentInfo::UNSELECTED; } /* Something we don't have and has filesize 0 does not exist in te system */ if (ci->state == ContentInfo::UNSELECTED && ci->filesize == 0) ci->state = ContentInfo::DOES_NOT_EXIST; /* Do we already have a stub for this? */ for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { ContentInfo *ici = *iter; if (ici->type == ci->type && ici->unique_id == ci->unique_id && memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) { /* Preserve the name if possible */ if (StrEmpty(ci->name)) strecpy(ci->name, ici->name, lastof(ci->name)); if (ici->IsSelected()) ci->state = ici->state; /* * As ici might be selected by the content window we cannot delete that. * However, we want to keep most of the values of ci, except the values * we (just) already preserved. * So transfer data and ownership of allocated memory from ci to ici. */ ici->TransferFrom(ci); delete ci; this->OnReceiveContentInfo(ici); return true; } } /* Missing content info? Don't list it */ if (ci->filesize == 0) { delete ci; return true; } *this->infos.Append() = ci; /* Incoming data means that we might need to reconsider dependencies */ for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { this->CheckDependencyState(*iter); } this->OnReceiveContentInfo(ci); return true; } /** * Request the content list for the given type. * @param type The content type to request the list for. */ void ClientNetworkContentSocketHandler::RequestContentList(ContentType type) { if (type == CONTENT_TYPE_END) { this->RequestContentList(CONTENT_TYPE_BASE_GRAPHICS); this->RequestContentList(CONTENT_TYPE_BASE_MUSIC); this->RequestContentList(CONTENT_TYPE_BASE_SOUNDS); this->RequestContentList(CONTENT_TYPE_SCENARIO); this->RequestContentList(CONTENT_TYPE_HEIGHTMAP); this->RequestContentList(CONTENT_TYPE_AI); this->RequestContentList(CONTENT_TYPE_AI_LIBRARY); this->RequestContentList(CONTENT_TYPE_GAME); this->RequestContentList(CONTENT_TYPE_GAME_LIBRARY); this->RequestContentList(CONTENT_TYPE_NEWGRF); return; } this->Connect(); Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_LIST); p->Send_uint8 ((byte)type); p->Send_uint32(_openttd_newgrf_version); this->SendPacket(p); } /** * Request the content list for a given number of content IDs. * @param count The number of IDs to request. * @param content_ids The unique identifiers of the content to request information about. */ void ClientNetworkContentSocketHandler::RequestContentList(uint count, const ContentID *content_ids) { this->Connect(); while (count > 0) { /* We can "only" send a limited number of IDs in a single packet. * A packet begins with the packet size and a byte for the type. * Then this packet adds a byte for the content type and a uint16 * for the count in this packet. The rest of the packet can be * used for the IDs. */ uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32)); Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID); p->Send_uint16(p_count); for (uint i = 0; i < p_count; i++) { p->Send_uint32(content_ids[i]); } this->SendPacket(p); count -= p_count; content_ids += p_count; } } /** * Request the content list for a list of content. * @param cv List with unique IDs and MD5 checksums. * @param send_md5sum Whether we want a MD5 checksum matched set of files or not. */ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bool send_md5sum) { if (cv == NULL) return; this->Connect(); /* 20 is sizeof(uint32) + sizeof(md5sum (byte[16])) */ assert(cv->Length() < 255); assert(cv->Length() < (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / (send_md5sum ? 20 : sizeof(uint32))); Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID); p->Send_uint8(cv->Length()); for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) { const ContentInfo *ci = *iter; p->Send_uint8((byte)ci->type); p->Send_uint32(ci->unique_id); if (!send_md5sum) continue; for (uint j = 0; j < sizeof(ci->md5sum); j++) { p->Send_uint8(ci->md5sum[j]); } } this->SendPacket(p); for (ContentIterator iter = cv->Begin(); iter != cv->End(); iter++) { ContentInfo *ci = *iter; bool found = false; for (ContentIterator iter2 = this->infos.Begin(); iter2 != this->infos.End(); iter2++) { ContentInfo *ci2 = *iter2; if (ci->type == ci2->type && ci->unique_id == ci2->unique_id && (!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) { found = true; break; } } if (!found) { *this->infos.Append() = ci; } else { delete ci; } } } /** * Actually begin downloading the content we selected. * @param[out] files The number of files we are going to download. * @param[out] bytes The number of bytes we are going to download. * @param fallback Whether to use the fallback or not. */ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uint &bytes, bool fallback) { bytes = 0; ContentIDList content; for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { const ContentInfo *ci = *iter; if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue; *content.Append() = ci->id; bytes += ci->filesize; } files = content.Length(); /* If there's nothing to download, do nothing. */ if (files == 0) return; if (_settings_client.network.no_http_content_downloads || fallback) { this->DownloadSelectedContentFallback(content); } else { this->DownloadSelectedContentHTTP(content); } } /** * Initiate downloading the content over HTTP. * @param content The content to download. */ void ClientNetworkContentSocketHandler::DownloadSelectedContentHTTP(const ContentIDList &content) { uint count = content.Length(); /* Allocate memory for the whole request. * Requests are "id\nid\n..." (as strings), so assume the maximum ID, * which is uint32 so 10 characters long. Then the newlines and * multiply that all with the count and then add the '\0'. */ uint bytes = (10 + 1) * count + 1; char *content_request = MallocT(bytes); const char *lastof = content_request + bytes - 1; char *p = content_request; for (const ContentID *id = content.Begin(); id != content.End(); id++) { p += seprintf(p, lastof, "%d\n", *id); } this->http_response_index = -1; NetworkAddress address(NETWORK_CONTENT_MIRROR_HOST, NETWORK_CONTENT_MIRROR_PORT); new NetworkHTTPContentConnecter(address, this, NETWORK_CONTENT_MIRROR_URL, content_request); /* NetworkHTTPContentConnecter takes over freeing of content_request! */ } /** * Initiate downloading the content over the fallback protocol. * @param content The content to download. */ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const ContentIDList &content) { uint count = content.Length(); const ContentID *content_ids = content.Begin(); this->Connect(); while (count > 0) { /* We can "only" send a limited number of IDs in a single packet. * A packet begins with the packet size and a byte for the type. * Then this packet adds a uint16 for the count in this packet. * The rest of the packet can be used for the IDs. */ uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32)); Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT); p->Send_uint16(p_count); for (uint i = 0; i < p_count; i++) { p->Send_uint32(content_ids[i]); } this->SendPacket(p); count -= p_count; content_ids += p_count; } } /** * Determine the full filename of a piece of content information * @param ci the information to get the filename from * @param compressed should the filename end with .gz? * @return a statically allocated buffer with the filename or * NULL when no filename could be made. */ static char *GetFullFilename(const ContentInfo *ci, bool compressed) { Subdirectory dir = GetContentInfoSubDir(ci->type); if (dir == NO_DIRECTORY) return NULL; static char buf[MAX_PATH]; FioGetFullPath(buf, lastof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename); strecat(buf, compressed ? ".tar.gz" : ".tar", lastof(buf)); return buf; } /** * Gunzip a given file and remove the .gz if successful. * @param ci container with filename * @return true if the gunzip completed */ static bool GunzipFile(const ContentInfo *ci) { #if defined(WITH_ZLIB) bool ret = true; FILE *ftmp = fopen(GetFullFilename(ci, true), "rb"); if (ftmp == NULL) return false; gzFile fin = gzdopen(fileno(ftmp), "rb"); FILE *fout = fopen(GetFullFilename(ci, false), "wb"); if (fin == NULL || fout == NULL) { ret = false; } else { byte buff[8192]; for (;;) { int read = gzread(fin, buff, sizeof(buff)); if (read == 0) { /* If gzread() returns 0, either the end-of-file has been * reached or an underlying read error has occurred. * * gzeof() can't be used, because: * 1.2.5 - it is safe, 1 means 'everything was OK' * 1.2.3.5, 1.2.4 - 0 or 1 is returned 'randomly' * 1.2.3.3 - 1 is returned for truncated archive * * So we use gzerror(). When proper end of archive * has been reached, then: * errnum == Z_STREAM_END in 1.2.3.3, * errnum == 0 in 1.2.4 and 1.2.5 */ int errnum; gzerror(fin, &errnum); if (errnum != 0 && errnum != Z_STREAM_END) ret = false; break; } if (read < 0 || (size_t)read != fwrite(buff, 1, read, fout)) { /* If gzread() returns -1, there was an error in archive */ ret = false; break; } /* DO NOT DO THIS! It will fail to detect broken archive with 1.2.3.3! * if (read < sizeof(buff)) break; */ } } if (fin != NULL) { /* Closes ftmp too! */ gzclose(fin); } else if (ftmp != NULL) { /* In case the gz stream was opened correctly this will * be closed by gzclose. */ fclose(ftmp); } if (fout != NULL) fclose(fout); return ret; #else NOT_REACHED(); #endif /* defined(WITH_ZLIB) */ } bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { if (this->curFile == NULL) { delete this->curInfo; /* When we haven't opened a file this must be our first packet with metadata. */ this->curInfo = new ContentInfo; this->curInfo->type = (ContentType)p->Recv_uint8(); this->curInfo->id = (ContentID)p->Recv_uint32(); this->curInfo->filesize = p->Recv_uint32(); p->Recv_string(this->curInfo->filename, lengthof(this->curInfo->filename)); if (!this->BeforeDownload()) { this->Close(); return false; } } else { /* We have a file opened, thus are downloading internal content */ size_t toRead = (size_t)(p->size - p->pos); if (fwrite(p->buffer + p->pos, 1, toRead, this->curFile) != toRead) { DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD); ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR); this->Close(); fclose(this->curFile); this->curFile = NULL; return false; } this->OnDownloadProgress(this->curInfo, (int)toRead); if (toRead == 0) this->AfterDownload(); } return true; } /** * Handle the opening of the file before downloading. * @return false on any error. */ bool ClientNetworkContentSocketHandler::BeforeDownload() { if (!this->curInfo->IsValid()) { delete this->curInfo; this->curInfo = NULL; return false; } if (this->curInfo->filesize != 0) { /* The filesize is > 0, so we are going to download it */ const char *filename = GetFullFilename(this->curInfo, true); if (filename == NULL || (this->curFile = fopen(filename, "wb")) == NULL) { /* Unless that fails of course... */ DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD); ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR); return false; } } return true; } /** * Handle the closing and extracting of a file after * downloading it has been done. */ void ClientNetworkContentSocketHandler::AfterDownload() { /* We read nothing; that's our marker for end-of-stream. * Now gunzip the tar and make it known. */ fclose(this->curFile); this->curFile = NULL; if (GunzipFile(this->curInfo)) { unlink(GetFullFilename(this->curInfo, true)); Subdirectory sd = GetContentInfoSubDir(this->curInfo->type); if (sd == NO_DIRECTORY) NOT_REACHED(); TarScanner ts; ts.AddFile(sd, GetFullFilename(this->curInfo, false)); if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) { /* Music can't be in a tar. So extract the tar! */ ExtractTar(GetFullFilename(this->curInfo, false), BASESET_DIR); unlink(GetFullFilename(this->curInfo, false)); } this->OnDownloadComplete(this->curInfo->id); } else { ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR); } } /* Also called to just clean up the mess. */ void ClientNetworkContentSocketHandler::OnFailure() { /* If we fail, download the rest via the 'old' system. */ uint files, bytes; this->DownloadSelectedContent(files, bytes, true); this->http_response.Reset(); this->http_response_index = -2; if (this->curFile != NULL) { /* Revert the download progress when we are going for the old system. */ long size = ftell(this->curFile); if (size > 0) this->OnDownloadProgress(this->curInfo, (int)-size); fclose(this->curFile); this->curFile = NULL; } } void ClientNetworkContentSocketHandler::OnReceiveData(const char *data, size_t length) { assert(data == NULL || length != 0); /* Ignore any latent data coming from a connection we closed. */ if (this->http_response_index == -2) return; if (this->http_response_index == -1) { if (data != NULL) { /* Append the rest of the response. */ memcpy(this->http_response.Append((uint)length), data, length); return; } else { /* Make sure the response is properly terminated. */ *this->http_response.Append() = '\0'; /* And prepare for receiving the rest of the data. */ this->http_response_index = 0; } } if (data != NULL) { /* We have data, so write it to the file. */ if (fwrite(data, 1, length, this->curFile) != length) { /* Writing failed somehow, let try via the old method. */ this->OnFailure(); } else { /* Just received the data. */ this->OnDownloadProgress(this->curInfo, (int)length); } /* Nothing more to do now. */ return; } if (this->curFile != NULL) { /* We've finished downloading a file. */ this->AfterDownload(); } if ((uint)this->http_response_index >= this->http_response.Length()) { /* It's not a real failure, but if there's * nothing more to download it helps with * cleaning up the stuff we allocated. */ this->OnFailure(); return; } delete this->curInfo; /* When we haven't opened a file this must be our first packet with metadata. */ this->curInfo = new ContentInfo; /** Check p for not being null and return calling OnFailure if that's not the case. */ #define check_not_null(p) { if ((p) == NULL) { this->OnFailure(); return; } } /** Check p for not being null and then terminate, or return calling OnFailure. */ #define check_and_terminate(p) { check_not_null(p); *(p) = '\0'; } for (;;) { char *str = this->http_response.Begin() + this->http_response_index; char *p = strchr(str, '\n'); check_and_terminate(p); /* Update the index for the next one */ this->http_response_index += (int)strlen(str) + 1; /* Read the ID */ p = strchr(str, ','); check_and_terminate(p); this->curInfo->id = (ContentID)atoi(str); /* Read the type */ str = p + 1; p = strchr(str, ','); check_and_terminate(p); this->curInfo->type = (ContentType)atoi(str); /* Read the file size */ str = p + 1; p = strchr(str, ','); check_and_terminate(p); this->curInfo->filesize = atoi(str); /* Read the URL */ str = p + 1; /* Is it a fallback URL? If so, just continue with the next one. */ if (strncmp(str, "ottd", 4) == 0) { if ((uint)this->http_response_index >= this->http_response.Length()) { /* Have we gone through all lines? */ this->OnFailure(); return; } continue; } p = strrchr(str, '/'); check_not_null(p); p++; // Start after the '/' char tmp[MAX_PATH]; if (strecpy(tmp, p, lastof(tmp)) == lastof(tmp)) { this->OnFailure(); return; } /* Remove the extension from the string. */ for (uint i = 0; i < 2; i++) { p = strrchr(tmp, '.'); check_and_terminate(p); } /* Copy the string, without extension, to the filename. */ strecpy(this->curInfo->filename, tmp, lastof(this->curInfo->filename)); /* Request the next file. */ if (!this->BeforeDownload()) { this->OnFailure(); return; } NetworkHTTPSocketHandler::Connect(str, this); return; } #undef check #undef check_and_terminate } /** * Create a socket handler to handle the connection. */ ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() : NetworkContentSocketHandler(), http_response_index(-2), curFile(NULL), curInfo(NULL), isConnecting(false), lastActivity(_realtime_tick) { } /** Clear up the mess ;) */ ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler() { delete this->curInfo; if (this->curFile != NULL) fclose(this->curFile); for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter; } /** Connect to the content server. */ class NetworkContentConnecter : TCPConnecter { public: /** * Initiate the connecting. * @param address The address of the server. */ NetworkContentConnecter(const NetworkAddress &address) : TCPConnecter(address) {} virtual void OnFailure() { _network_content_client.isConnecting = false; _network_content_client.OnConnect(false); } virtual void OnConnect(SOCKET s) { assert(_network_content_client.sock == INVALID_SOCKET); _network_content_client.isConnecting = false; _network_content_client.sock = s; _network_content_client.Reopen(); _network_content_client.OnConnect(true); } }; /** * Connect with the content server. */ void ClientNetworkContentSocketHandler::Connect() { this->lastActivity = _realtime_tick; if (this->sock != INVALID_SOCKET || this->isConnecting) return; this->isConnecting = true; new NetworkContentConnecter(NetworkAddress(NETWORK_CONTENT_SERVER_HOST, NETWORK_CONTENT_SERVER_PORT, AF_UNSPEC)); } /** * Disconnect from the content server. */ void ClientNetworkContentSocketHandler::Close() { if (this->sock == INVALID_SOCKET) return; NetworkContentSocketHandler::Close(); this->OnDisconnect(); } /** * Check whether we received/can send some data from/to the content server and * when that's the case handle it appropriately */ void ClientNetworkContentSocketHandler::SendReceive() { if (this->sock == INVALID_SOCKET || this->isConnecting) return; if (this->lastActivity + IDLE_TIMEOUT < _realtime_tick) { this->Close(); return; } if (this->CanSendReceive()) { if (this->ReceivePackets()) { /* Only update activity once a packet is received, instead of everytime we try it. */ this->lastActivity = _realtime_tick; } } this->SendPackets(); } /** * Download information of a given Content ID if not already tried * @param cid the ID to try */ void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid) { /* When we tried to download it already, don't try again */ if (this->requested.Contains(cid)) return; *this->requested.Append() = cid; assert(this->requested.Contains(cid)); this->RequestContentList(1, &cid); } /** * Get the content info based on a ContentID * @param cid the ContentID to search for * @return the ContentInfo or NULL if not found */ ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid) { for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { ContentInfo *ci = *iter; if (ci->id == cid) return ci; } return NULL; } /** * Select a specific content id. * @param cid the content ID to select */ void ClientNetworkContentSocketHandler::Select(ContentID cid) { ContentInfo *ci = this->GetContent(cid); if (ci == NULL || ci->state != ContentInfo::UNSELECTED) return; ci->state = ContentInfo::SELECTED; this->CheckDependencyState(ci); } /** * Unselect a specific content id. * @param cid the content ID to deselect */ void ClientNetworkContentSocketHandler::Unselect(ContentID cid) { ContentInfo *ci = this->GetContent(cid); if (ci == NULL || !ci->IsSelected()) return; ci->state = ContentInfo::UNSELECTED; this->CheckDependencyState(ci); } /** Select everything we can select */ void ClientNetworkContentSocketHandler::SelectAll() { for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { ContentInfo *ci = *iter; if (ci->state == ContentInfo::UNSELECTED) { ci->state = ContentInfo::SELECTED; this->CheckDependencyState(ci); } } } /** Select everything that's an update for something we've got */ void ClientNetworkContentSocketHandler::SelectUpgrade() { for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { ContentInfo *ci = *iter; if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) { ci->state = ContentInfo::SELECTED; this->CheckDependencyState(ci); } } } /** Unselect everything that we've not downloaded so far. */ void ClientNetworkContentSocketHandler::UnselectAll() { for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { ContentInfo *ci = *iter; if (ci->IsSelected() && ci->state != ContentInfo::ALREADY_HERE) ci->state = ContentInfo::UNSELECTED; } } /** Toggle the state of a content info and check its dependencies */ void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *ci) { switch (ci->state) { case ContentInfo::SELECTED: case ContentInfo::AUTOSELECTED: this->Unselect(ci->id); break; case ContentInfo::UNSELECTED: this->Select(ci->id); break; default: break; } } /** * Reverse lookup the dependencies of (direct) parents over a given child. * @param parents list to store all parents in (is not cleared) * @param child the child to search the parents' dependencies for */ void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const { for (ConstContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) { const ContentInfo *ci = *iter; if (ci == child) continue; for (uint i = 0; i < ci->dependency_count; i++) { if (ci->dependencies[i] == child->id) { *parents.Append() = ci; break; } } } } /** * Reverse lookup the dependencies of all parents over a given child. * @param tree list to store all parents in (is not cleared) * @param child the child to search the parents' dependencies for */ void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const { *tree.Append() = child; /* First find all direct parents. We can't use the "normal" iterator as * we are including stuff into the vector and as such the vector's data * store can be reallocated (and thus move), which means out iterating * pointer gets invalid. So fall back to the indices. */ for (uint i = 0; i < tree.Length(); i++) { ConstContentVector parents; this->ReverseLookupDependency(parents, tree[i]); for (ConstContentIterator piter = parents.Begin(); piter != parents.End(); piter++) { tree.Include(*piter); } } } /** * Check the dependencies (recursively) of this content info * @param ci the content info to check the dependencies of */ void ClientNetworkContentSocketHandler::CheckDependencyState(ContentInfo *ci) { if (ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) { /* Selection is easy; just walk all children and set the * autoselected state. That way we can see what we automatically * selected and thus can unselect when a dependency is removed. */ for (uint i = 0; i < ci->dependency_count; i++) { ContentInfo *c = this->GetContent(ci->dependencies[i]); if (c == NULL) { this->DownloadContentInfo(ci->dependencies[i]); } else if (c->state == ContentInfo::UNSELECTED) { c->state = ContentInfo::AUTOSELECTED; this->CheckDependencyState(c); } } return; } if (ci->state != ContentInfo::UNSELECTED) return; /* For unselection we need to find the parents of us. We need to * unselect them. After that we unselect all children that we * depend on and are not used as dependency for us, but only when * we automatically selected them. */ ConstContentVector parents; this->ReverseLookupDependency(parents, ci); for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { const ContentInfo *c = *iter; if (!c->IsSelected()) continue; this->Unselect(c->id); } for (uint i = 0; i < ci->dependency_count; i++) { const ContentInfo *c = this->GetContent(ci->dependencies[i]); if (c == NULL) { DownloadContentInfo(ci->dependencies[i]); continue; } if (c->state != ContentInfo::AUTOSELECTED) continue; /* Only unselect when WE are the only parent. */ parents.Clear(); this->ReverseLookupDependency(parents, c); /* First check whether anything depends on us */ int sel_count = 0; bool force_selection = false; for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { if ((*iter)->IsSelected()) sel_count++; if ((*iter)->state == ContentInfo::SELECTED) force_selection = true; } if (sel_count == 0) { /* Nothing depends on us */ this->Unselect(c->id); continue; } /* Something manually selected depends directly on us */ if (force_selection) continue; /* "Flood" search to find all items in the dependency graph*/ parents.Clear(); this->ReverseLookupTreeDependency(parents, c); /* Is there anything that is "force" selected?, if so... we're done. */ for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { if ((*iter)->state != ContentInfo::SELECTED) continue; force_selection = true; break; } /* So something depended directly on us */ if (force_selection) continue; /* Nothing depends on us, mark the whole graph as unselected. * After that's done run over them once again to test their children * to unselect. Don't do it immediately because it'll do exactly what * we're doing now. */ for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { const ContentInfo *c = *iter; if (c->state == ContentInfo::AUTOSELECTED) this->Unselect(c->id); } for (ConstContentIterator iter = parents.Begin(); iter != parents.End(); iter++) { this->CheckDependencyState(this->GetContent((*iter)->id)); } } } /** Clear all downloaded content information. */ void ClientNetworkContentSocketHandler::Clear() { for (ContentIterator iter = this->infos.Begin(); iter != this->infos.End(); iter++) delete *iter; this->infos.Clear(); this->requested.Clear(); } /*** CALLBACK ***/ void ClientNetworkContentSocketHandler::OnConnect(bool success) { for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { ContentCallback *cb = *iter; cb->OnConnect(success); if (iter != this->callbacks.End() && *iter == cb) iter++; } } void ClientNetworkContentSocketHandler::OnDisconnect() { for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { ContentCallback *cb = *iter; cb->OnDisconnect(); if (iter != this->callbacks.End() && *iter == cb) iter++; } } void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo *ci) { for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { ContentCallback *cb = *iter; cb->OnReceiveContentInfo(ci); if (iter != this->callbacks.End() && *iter == cb) iter++; } } void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo *ci, int bytes) { for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { ContentCallback *cb = *iter; cb->OnDownloadProgress(ci, bytes); if (iter != this->callbacks.End() && *iter == cb) iter++; } } void ClientNetworkContentSocketHandler::OnDownloadComplete(ContentID cid) { ContentInfo *ci = this->GetContent(cid); if (ci != NULL) { ci->state = ContentInfo::ALREADY_HERE; } for (ContentCallback **iter = this->callbacks.Begin(); iter != this->callbacks.End(); /* nothing */) { ContentCallback *cb = *iter; cb->OnDownloadComplete(cid); if (iter != this->callbacks.End() && *iter == cb) iter++; } } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_gui.cpp0000644000000000000000000025233012627373441017232 0ustar rootroot/* $Id: network_gui.cpp 27431 2015-11-01 11:59:17Z frosch $ */ /* * 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 network_gui.cpp Implementation of the Network related GUIs. */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" #include "../fios.h" #include "network_client.h" #include "network_gui.h" #include "network_gamelist.h" #include "network.h" #include "network_base.h" #include "network_content.h" #include "../gui.h" #include "network_udp.h" #include "../window_func.h" #include "../gfx_func.h" #include "../widgets/dropdown_func.h" #include "../querystring_gui.h" #include "../sortlist_type.h" #include "../company_func.h" #include "../core/geometry_func.hpp" #include "../genworld.h" #include "../map_type.h" #include "../widgets/network_widget.h" #include "table/strings.h" #include "../table/sprites.h" #include "../stringfilter_type.h" #include "../safeguards.h" static void ShowNetworkStartServerWindow(); static void ShowNetworkLobbyWindow(NetworkGameList *ngl); /** * Advertisement options in the start server window */ static const StringID _connection_types_dropdown[] = { STR_NETWORK_START_SERVER_UNADVERTISED, STR_NETWORK_START_SERVER_ADVERTISED, INVALID_STRING_ID }; /** * Advertisement options in the server list */ static const StringID _lan_internet_types_dropdown[] = { STR_NETWORK_SERVER_LIST_ADVERTISED_NO, STR_NETWORK_SERVER_LIST_ADVERTISED_YES, INVALID_STRING_ID }; static StringID _language_dropdown[NETLANG_COUNT + 1] = {STR_NULL}; void SortNetworkLanguages() { /* Init the strings */ if (_language_dropdown[0] == STR_NULL) { for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown[i] = STR_NETWORK_LANG_ANY + i; _language_dropdown[NETLANG_COUNT] = INVALID_STRING_ID; } /* Sort the strings (we don't move 'any' and the 'invalid' one) */ QSortT(_language_dropdown + 1, NETLANG_COUNT - 1, &StringIDSorter); } /** * Update the network new window because a new server is * found on the network. */ void UpdateNetworkGameWindow() { InvalidateWindowData(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME, 0); } typedef GUIList GUIGameServerList; typedef uint16 ServerListPosition; static const ServerListPosition SLP_INVALID = 0xFFFF; /** Full blown container to make it behave exactly as we want :) */ class NWidgetServerListHeader : public NWidgetContainer { static const uint MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER = 150; ///< Minimum width before adding a new header bool visible[6]; ///< The visible headers public: NWidgetServerListHeader() : NWidgetContainer(NWID_HORIZONTAL) { NWidgetLeaf *leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP); leaf->SetResize(1, 0); leaf->SetFill(1, 0); this->Add(leaf); this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP)); this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP)); this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP)); this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP)); leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP); leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK).width + GetSpriteSize(SPR_BLOT).width + GetSpriteSize(SPR_FLAGS_BASE).width, 12); leaf->SetFill(0, 1); this->Add(leaf); /* First and last are always visible, the rest is implicitly zeroed */ this->visible[0] = true; *lastof(this->visible) = true; } void SetupSmallestSize(Window *w, bool init_array) { /* Oh yeah, we ought to be findable! */ w->nested_array[WID_NG_HEADER] = this; this->smallest_y = 0; // Biggest child. this->fill_x = 1; this->fill_y = 0; this->resize_x = 1; // We only resize in this direction this->resize_y = 0; // We never resize in this direction /* First initialise some variables... */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); } /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->current_x = child_wid->smallest_x; child_wid->current_y = this->smallest_y; } this->smallest_x = this->head->smallest_x + this->tail->smallest_x; // First and last are always shown, rest not } void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); this->pos_x = x; this->pos_y = y; this->current_x = given_width; this->current_y = given_height; given_width -= this->tail->smallest_x; NWidgetBase *child_wid = this->head->next; /* The first and last widget are always visible, determine which other should be visible */ for (uint i = 1; i < lengthof(this->visible) - 1; i++) { if (given_width > MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER + child_wid->smallest_x && this->visible[i - 1]) { this->visible[i] = true; given_width -= child_wid->smallest_x; } else { this->visible[i] = false; } child_wid = child_wid->next; } /* All remaining space goes to the first (name) widget */ this->head->current_x = given_width; /* Now assign the widgets to their rightful place */ uint position = 0; // Place to put next child relative to origin of the container. uint i = rtl ? lengthof(this->visible) - 1 : 0; child_wid = rtl ? this->tail : this->head; while (child_wid != NULL) { if (this->visible[i]) { child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); position += child_wid->current_x; } child_wid = rtl ? child_wid->prev : child_wid->next; i += rtl ? -1 : 1; } } /* virtual */ void Draw(const Window *w) { int i = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (!this->visible[i++]) continue; child_wid->Draw(w); } } /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y) { if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; int i = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (!this->visible[i++]) continue; NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); if (nwid != NULL) return nwid; } return NULL; } /** * Checks whether the given widget is actually visible. * @param widget the widget to check for visibility * @return true iff the widget is visible. */ bool IsWidgetVisible(NetworkGameWidgets widget) const { assert((uint)(widget - WID_NG_NAME) < lengthof(this->visible)); return this->visible[widget - WID_NG_NAME]; } }; class NetworkGameWindow : public Window { protected: /* Runtime saved values */ static Listing last_sorting; /* Constants for sorting servers */ static GUIGameServerList::SortFunction * const sorter_funcs[]; static GUIGameServerList::FilterFunction * const filter_funcs[]; NetworkGameList *server; ///< selected server NetworkGameList *last_joined; ///< the last joined server GUIGameServerList servers; ///< list with game servers. ServerListPosition list_pos; ///< position of the selected server Scrollbar *vscroll; ///< vertical scrollbar of the list of servers QueryString name_editbox; ///< Client name editbox. QueryString filter_editbox; ///< Editbox for filter on servers int lock_offset; ///< Left offset for lock icon. int blot_offset; ///< Left offset for green/yellow/red compatibility icon. int flag_offset; ///< Left offset for langauge flag icon. /** * (Re)build the GUI network game list (a.k.a. this->servers) as some * major change has occurred. It ensures appropriate filtering and * sorting, if both or either one is enabled. */ void BuildGUINetworkGameList() { if (!this->servers.NeedRebuild()) return; /* Create temporary array of games to use for listing */ this->servers.Clear(); for (NetworkGameList *ngl = _network_game_list; ngl != NULL; ngl = ngl->next) { *this->servers.Append() = ngl; } /* Apply the filter condition immediately, if a search string has been provided. */ StringFilter sf; sf.SetFilterTerm(this->filter_editbox.text.buf); if (!sf.IsEmpty()) { this->servers.SetFilterState(true); this->servers.Filter(sf); } else { this->servers.SetFilterState(false); } this->servers.Compact(); this->servers.RebuildDone(); this->vscroll->SetCount(this->servers.Length()); /* Sort the list of network games as requested. */ this->servers.Sort(); this->UpdateListPos(); } /** Sort servers by name. */ static int CDECL NGameNameSorter(NetworkGameList * const *a, NetworkGameList * const *b) { int r = strnatcmp((*a)->info.server_name, (*b)->info.server_name, true); // Sort by name (natural sorting). return r == 0 ? (*a)->address.CompareTo((*b)->address) : r; } /** * Sort servers by the amount of clients online on a * server. If the two servers have the same amount, the one with the * higher maximum is preferred. */ static int CDECL NGameClientSorter(NetworkGameList * const *a, NetworkGameList * const *b) { /* Reverse as per default we are interested in most-clients first */ int r = (*a)->info.clients_on - (*b)->info.clients_on; if (r == 0) r = (*a)->info.clients_max - (*b)->info.clients_max; if (r == 0) r = NGameNameSorter(a, b); return r; } /** Sort servers by map size */ static int CDECL NGameMapSizeSorter(NetworkGameList * const *a, NetworkGameList * const *b) { /* Sort by the area of the map. */ int r = ((*a)->info.map_height) * ((*a)->info.map_width) - ((*b)->info.map_height) * ((*b)->info.map_width); if (r == 0) r = (*a)->info.map_width - (*b)->info.map_width; return (r != 0) ? r : NGameClientSorter(a, b); } /** Sort servers by current date */ static int CDECL NGameDateSorter(NetworkGameList * const *a, NetworkGameList * const *b) { int r = (*a)->info.game_date - (*b)->info.game_date; return (r != 0) ? r : NGameClientSorter(a, b); } /** Sort servers by the number of days the game is running */ static int CDECL NGameYearsSorter(NetworkGameList * const *a, NetworkGameList * const *b) { int r = (*a)->info.game_date - (*a)->info.start_date - (*b)->info.game_date + (*b)->info.start_date; return (r != 0) ? r : NGameDateSorter(a, b); } /** * Sort servers by joinability. If both servers are the * same, prefer the non-passworded server first. */ static int CDECL NGameAllowedSorter(NetworkGameList * const *a, NetworkGameList * const *b) { /* The servers we do not know anything about (the ones that did not reply) should be at the bottom) */ int r = StrEmpty((*a)->info.server_revision) - StrEmpty((*b)->info.server_revision); /* Reverse default as we are interested in version-compatible clients first */ if (r == 0) r = (*b)->info.version_compatible - (*a)->info.version_compatible; /* The version-compatible ones are then sorted with NewGRF compatible first, incompatible last */ if (r == 0) r = (*b)->info.compatible - (*a)->info.compatible; /* Passworded servers should be below unpassworded servers */ if (r == 0) r = (*a)->info.use_password - (*b)->info.use_password; /* Finally sort on the number of clients of the server */ if (r == 0) r = -NGameClientSorter(a, b); return r; } /** Sort the server list */ void SortNetworkGameList() { if (this->servers.Sort()) this->UpdateListPos(); } /** Set this->list_pos to match this->server */ void UpdateListPos() { this->list_pos = SLP_INVALID; for (uint i = 0; i != this->servers.Length(); i++) { if (this->servers[i] == this->server) { this->list_pos = i; break; } } } static bool CDECL NGameSearchFilter(NetworkGameList * const *item, StringFilter &sf) { assert(item != NULL); assert((*item) != NULL); sf.ResetState(); sf.AddLine((*item)->info.server_name); return sf.GetState(); } /** * Draw a single server line. * @param cur_item the server to draw. * @param y from where to draw? * @param highlight does the line need to be highlighted? */ void DrawServerLine(const NetworkGameList *cur_item, uint y, bool highlight) const { const NWidgetBase *nwi_name = this->GetWidget(WID_NG_NAME); const NWidgetBase *nwi_info = this->GetWidget(WID_NG_INFO); /* show highlighted item with a different colour */ if (highlight) GfxFillRect(nwi_name->pos_x + 1, y + 1, nwi_info->pos_x + nwi_info->current_x - 2, y + this->resize.step_height - 2, PC_GREY); /* offsets to vertically centre text and icons */ int text_y_offset = (this->resize.step_height - FONT_HEIGHT_NORMAL) / 2 + 1; int icon_y_offset = (this->resize.step_height - GetSpriteSize(SPR_BLOT).height) / 2; DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + text_y_offset, cur_item->info.server_name, TC_BLACK); /* only draw details if the server is online */ if (cur_item->online) { const NWidgetServerListHeader *nwi_header = this->GetWidget(WID_NG_HEADER); if (nwi_header->IsWidgetVisible(WID_NG_CLIENTS)) { const NWidgetBase *nwi_clients = this->GetWidget(WID_NG_CLIENTS); SetDParam(0, cur_item->info.clients_on); SetDParam(1, cur_item->info.clients_max); SetDParam(2, cur_item->info.companies_on); SetDParam(3, cur_item->info.companies_max); DrawString(nwi_clients->pos_x, nwi_clients->pos_x + nwi_clients->current_x - 1, y + text_y_offset, STR_NETWORK_SERVER_LIST_GENERAL_ONLINE, TC_FROMSTRING, SA_HOR_CENTER); } if (nwi_header->IsWidgetVisible(WID_NG_MAPSIZE)) { /* map size */ const NWidgetBase *nwi_mapsize = this->GetWidget(WID_NG_MAPSIZE); SetDParam(0, cur_item->info.map_width); SetDParam(1, cur_item->info.map_height); DrawString(nwi_mapsize->pos_x, nwi_mapsize->pos_x + nwi_mapsize->current_x - 1, y + text_y_offset, STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT, TC_FROMSTRING, SA_HOR_CENTER); } if (nwi_header->IsWidgetVisible(WID_NG_DATE)) { /* current date */ const NWidgetBase *nwi_date = this->GetWidget(WID_NG_DATE); YearMonthDay ymd; ConvertDateToYMD(cur_item->info.game_date, &ymd); SetDParam(0, ymd.year); DrawString(nwi_date->pos_x, nwi_date->pos_x + nwi_date->current_x - 1, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER); } if (nwi_header->IsWidgetVisible(WID_NG_YEARS)) { /* number of years the game is running */ const NWidgetBase *nwi_years = this->GetWidget(WID_NG_YEARS); YearMonthDay ymd_cur, ymd_start; ConvertDateToYMD(cur_item->info.game_date, &ymd_cur); ConvertDateToYMD(cur_item->info.start_date, &ymd_start); SetDParam(0, ymd_cur.year - ymd_start.year); DrawString(nwi_years->pos_x, nwi_years->pos_x + nwi_years->current_x - 1, y + text_y_offset, STR_JUST_INT, TC_BLACK, SA_HOR_CENTER); } /* draw a lock if the server is password protected */ if (cur_item->info.use_password) DrawSprite(SPR_LOCK, PAL_NONE, nwi_info->pos_x + this->lock_offset, y + icon_y_offset - 1); /* draw red or green icon, depending on compatibility with server */ DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), nwi_info->pos_x + this->blot_offset, y + icon_y_offset); /* draw flag according to server language */ DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + this->flag_offset, y + icon_y_offset); } } /** * Scroll the list up or down to the currently selected server. * If the server is below the currently displayed servers, it will * scroll down an amount so that the server appears at the bottom. * If the server is above the currently displayed servers, it will * scroll up so that the server appears at the top. */ void ScrollToSelectedServer() { if (this->list_pos == SLP_INVALID) return; // no server selected this->vscroll->ScrollTowards(this->list_pos); } public: NetworkGameWindow(WindowDesc *desc) : Window(desc), name_editbox(NETWORK_CLIENT_NAME_LENGTH), filter_editbox(120) { this->list_pos = SLP_INVALID; this->server = NULL; this->lock_offset = 5; this->blot_offset = this->lock_offset + 3 + GetSpriteSize(SPR_LOCK).width; this->flag_offset = this->blot_offset + 2 + GetSpriteSize(SPR_BLOT).width; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NG_SCROLLBAR); this->FinishInitNested(WN_NETWORK_WINDOW_GAME); this->querystrings[WID_NG_CLIENT] = &this->name_editbox; this->name_editbox.text.Assign(_settings_client.network.client_name); this->querystrings[WID_NG_FILTER] = &this->filter_editbox; this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; this->SetFocusedWidget(WID_NG_FILTER); this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); this->server = this->last_joined; if (this->last_joined != NULL) NetworkUDPQueryServer(this->last_joined->address); this->servers.SetListing(this->last_sorting); this->servers.SetSortFuncs(this->sorter_funcs); this->servers.SetFilterFuncs(this->filter_funcs); this->servers.ForceRebuild(); } ~NetworkGameWindow() { this->last_sorting = this->servers.GetListing(); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_NG_CONN_BTN: SetDParam(0, _lan_internet_types_dropdown[_settings_client.network.lan_internet]); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_NG_CONN_BTN: *size = maxdim(*size, maxdim(GetStringBoundingBox(_lan_internet_types_dropdown[0]), GetStringBoundingBox(_lan_internet_types_dropdown[1]))); size->width += padding.width; size->height += padding.height; break; case WID_NG_MATRIX: resize->height = WD_MATRIX_TOP + max(GetSpriteSize(SPR_BLOT).height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM; size->height = 10 * resize->height; break; case WID_NG_LASTJOINED: size->height = WD_MATRIX_TOP + max(GetSpriteSize(SPR_BLOT).height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM; break; case WID_NG_LASTJOINED_SPACER: size->width = NWidgetScrollbar::GetVerticalDimension().width; break; case WID_NG_NAME: size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow break; case WID_NG_CLIENTS: size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow SetDParamMaxValue(0, MAX_CLIENTS); SetDParamMaxValue(1, MAX_CLIENTS); SetDParamMaxValue(2, MAX_COMPANIES); SetDParamMaxValue(3, MAX_COMPANIES); *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_GENERAL_ONLINE)); break; case WID_NG_MAPSIZE: size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow SetDParamMaxValue(0, MAX_MAP_SIZE); SetDParamMaxValue(1, MAX_MAP_SIZE); *size = maxdim(*size, GetStringBoundingBox(STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT)); break; case WID_NG_DATE: case WID_NG_YEARS: size->width += 2 * Window::SortButtonWidth(); // Make space for the arrow SetDParamMaxValue(0, 5); *size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT)); break; case WID_NG_DETAILS_SPACER: size->height = 20 + 12 * FONT_HEIGHT_NORMAL; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_NG_MATRIX: { uint16 y = r.top; const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.Length()); for (int i = this->vscroll->GetPosition(); i < max; ++i) { const NetworkGameList *ngl = this->servers[i]; this->DrawServerLine(ngl, y, ngl == this->server); y += this->resize.step_height; } break; } case WID_NG_LASTJOINED: /* Draw the last joined server, if any */ if (this->last_joined != NULL) this->DrawServerLine(this->last_joined, r.top, this->last_joined == this->server); break; case WID_NG_DETAILS: this->DrawDetails(r); break; case WID_NG_NAME: case WID_NG_CLIENTS: case WID_NG_MAPSIZE: case WID_NG_DATE: case WID_NG_YEARS: case WID_NG_INFO: if (widget - WID_NG_NAME == this->servers.SortType()) this->DrawSortButtonState(widget, this->servers.IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; } } virtual void OnPaint() { if (this->servers.NeedRebuild()) { this->BuildGUINetworkGameList(); } if (this->servers.NeedResort()) { this->SortNetworkGameList(); } NetworkGameList *sel = this->server; /* 'Refresh' button invisible if no server selected */ this->SetWidgetDisabledState(WID_NG_REFRESH, sel == NULL); /* 'Join' button disabling conditions */ this->SetWidgetDisabledState(WID_NG_JOIN, sel == NULL || // no Selected Server !sel->online || // Server offline sel->info.clients_on >= sel->info.clients_max || // Server full !sel->info.compatible); // Revision mismatch /* 'NewGRF Settings' button invisible if no NewGRF is used */ this->GetWidget(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == NULL || !sel->online || sel->info.grfconfig == NULL); this->GetWidget(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == NULL || !sel->online || sel->info.grfconfig == NULL || !sel->info.version_compatible || sel->info.compatible); this->DrawWidgets(); } void DrawDetails(const Rect &r) const { NetworkGameList *sel = this->server; const int detail_height = 6 + 8 + 6 + 3 * FONT_HEIGHT_NORMAL; /* Draw the right menu */ GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE); if (sel == NULL) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER); } else if (!sel->online) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + detail_height + 4, STR_NETWORK_SERVER_LIST_SERVER_OFFLINE, TC_FROMSTRING, SA_HOR_CENTER); // server offline } else { // show game info DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 8 + 2 * FONT_HEIGHT_NORMAL, sel->info.map_name, TC_BLACK, SA_HOR_CENTER); // map name uint16 y = r.top + detail_height + 4; SetDParam(0, sel->info.clients_on); SetDParam(1, sel->info.clients_max); SetDParam(2, sel->info.companies_on); SetDParam(3, sel->info.companies_max); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS); y += FONT_HEIGHT_NORMAL; SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANGUAGE); // server language y += FONT_HEIGHT_NORMAL; SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.map_set); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); // landscape y += FONT_HEIGHT_NORMAL; SetDParam(0, sel->info.map_width); SetDParam(1, sel->info.map_height); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE); // map size y += FONT_HEIGHT_NORMAL; SetDParamStr(0, sel->info.server_revision); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version y += FONT_HEIGHT_NORMAL; SetDParamStr(0, sel->address.GetAddressAsString()); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address y += FONT_HEIGHT_NORMAL; SetDParam(0, sel->info.start_date); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE); // start date y += FONT_HEIGHT_NORMAL; SetDParam(0, sel->info.game_date); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE); // current date y += FONT_HEIGHT_NORMAL; y += WD_PAR_VSEP_NORMAL; if (!sel->info.compatible) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, sel->info.version_compatible ? STR_NETWORK_SERVER_LIST_GRF_MISMATCH : STR_NETWORK_SERVER_LIST_VERSION_MISMATCH, TC_FROMSTRING, SA_HOR_CENTER); // server mismatch } else if (sel->info.clients_on == sel->info.clients_max) { /* Show: server full, when clients_on == max_clients */ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_FULL, TC_FROMSTRING, SA_HOR_CENTER); // server full } else if (sel->info.use_password) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_PASSWORD, TC_FROMSTRING, SA_HOR_CENTER); // password warning } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_NG_CANCEL: // Cancel button DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); break; case WID_NG_CONN_BTN: // 'Connection' droplist ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, WID_NG_CONN_BTN, 0, 0); // do it for widget WID_NSS_CONN_BTN break; case WID_NG_NAME: // Sort by name case WID_NG_CLIENTS: // Sort by connected clients case WID_NG_MAPSIZE: // Sort by map size case WID_NG_DATE: // Sort by date case WID_NG_YEARS: // Sort by years case WID_NG_INFO: // Connectivity (green dot) if (this->servers.SortType() == widget - WID_NG_NAME) { this->servers.ToggleSortOrder(); if (this->list_pos != SLP_INVALID) this->list_pos = this->servers.Length() - this->list_pos - 1; } else { this->servers.SetSortType(widget - WID_NG_NAME); this->servers.ForceResort(); this->SortNetworkGameList(); } this->ScrollToSelectedServer(); this->SetDirty(); break; case WID_NG_MATRIX: { // Show available network games uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NG_MATRIX); this->server = (id_v < this->servers.Length()) ? this->servers[id_v] : NULL; this->list_pos = (server == NULL) ? SLP_INVALID : id_v; this->SetDirty(); /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */ if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1); break; } case WID_NG_LASTJOINED: { if (this->last_joined != NULL) { this->server = this->last_joined; /* search the position of the newly selected server */ this->UpdateListPos(); this->ScrollToSelectedServer(); this->SetDirty(); /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */ if (click_count > 1 && !this->IsWidgetDisabled(WID_NG_JOIN)) this->OnClick(pt, WID_NG_JOIN, 1); } break; } case WID_NG_FIND: // Find server automatically switch (_settings_client.network.lan_internet) { case 0: NetworkUDPSearchGame(); break; case 1: NetworkUDPQueryMasterServer(); break; } break; case WID_NG_ADD: // Add a server SetDParamStr(0, _settings_client.network.connect_to_ip); ShowQueryString( STR_JUST_RAW_STRING, STR_NETWORK_SERVER_LIST_ENTER_IP, NETWORK_HOSTNAME_LENGTH, // maximum number of characters including '\0' this, CS_ALPHANUMERAL, QSF_ACCEPT_UNCHANGED); break; case WID_NG_START: // Start server ShowNetworkStartServerWindow(); break; case WID_NG_JOIN: // Join Game if (this->server != NULL) { seprintf(_settings_client.network.last_host, lastof(_settings_client.network.last_host), "%s", this->server->address.GetHostname()); _settings_client.network.last_port = this->server->address.GetPort(); ShowNetworkLobbyWindow(this->server); } break; case WID_NG_REFRESH: // Refresh if (this->server != NULL) NetworkUDPQueryServer(this->server->address); break; case WID_NG_NEWGRF: // NewGRF Settings if (this->server != NULL) ShowNewGRFSettings(false, false, false, &this->server->info.grfconfig); break; case WID_NG_NEWGRF_MISSING: // Find missing content online if (this->server != NULL) ShowMissingContentWindow(this->server->info.grfconfig); break; } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_NG_CONN_BTN: _settings_client.network.lan_internet = index; break; default: NOT_REACHED(); } this->SetDirty(); } /** * 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) { this->servers.ForceRebuild(); this->SetDirty(); } virtual EventState OnKeyPress(WChar key, uint16 keycode) { EventState state = ES_NOT_HANDLED; /* handle up, down, pageup, pagedown, home and end */ if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) { if (this->servers.Length() == 0) return ES_HANDLED; switch (keycode) { case WKC_UP: /* scroll up by one */ if (this->list_pos == SLP_INVALID) return ES_HANDLED; if (this->list_pos > 0) this->list_pos--; break; case WKC_DOWN: /* scroll down by one */ if (this->list_pos == SLP_INVALID) return ES_HANDLED; if (this->list_pos < this->servers.Length() - 1) this->list_pos++; break; case WKC_PAGEUP: /* scroll up a page */ if (this->list_pos == SLP_INVALID) return ES_HANDLED; this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity(); break; case WKC_PAGEDOWN: /* scroll down a page */ if (this->list_pos == SLP_INVALID) return ES_HANDLED; this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.Length() - 1); break; case WKC_HOME: /* jump to beginning */ this->list_pos = 0; break; case WKC_END: /* jump to end */ this->list_pos = this->servers.Length() - 1; break; default: NOT_REACHED(); } this->server = this->servers[this->list_pos]; /* Scroll to the new server if it is outside the current range. */ this->ScrollToSelectedServer(); /* redraw window */ this->SetDirty(); return ES_HANDLED; } if (this->server != NULL) { if (keycode == WKC_DELETE) { // Press 'delete' to remove servers NetworkGameListRemoveItem(this->server); if (this->server == this->last_joined) this->last_joined = NULL; this->server = NULL; this->list_pos = SLP_INVALID; } } return state; } virtual void OnEditboxChanged(int wid) { switch (wid) { case WID_NG_FILTER: { this->servers.ForceRebuild(); this->BuildGUINetworkGameList(); this->ScrollToSelectedServer(); this->SetDirty(); break; } case WID_NG_CLIENT: /* Make sure the name does not start with a space, so TAB completion works */ if (!StrEmpty(this->name_editbox.text.buf) && this->name_editbox.text.buf[0] != ' ') { strecpy(_settings_client.network.client_name, this->name_editbox.text.buf, lastof(_settings_client.network.client_name)); } else { strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name)); } break; } } virtual void OnQueryTextFinished(char *str) { if (!StrEmpty(str)) NetworkAddServer(str); } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_NG_MATRIX); } virtual void OnTick() { NetworkGameListRequery(); } }; Listing NetworkGameWindow::last_sorting = {false, 5}; GUIGameServerList::SortFunction * const NetworkGameWindow::sorter_funcs[] = { &NGameNameSorter, &NGameClientSorter, &NGameMapSizeSorter, &NGameDateSorter, &NGameYearsSorter, &NGameAllowedSorter }; GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = { &NGameSearchFilter }; static NWidgetBase *MakeResizableHeader(int *biggest_index) { *biggest_index = max(*biggest_index, WID_NG_INFO); return new NWidgetServerListHeader(); } static const NWidgetPart _nested_network_game_widgets[] = { /* TOP */ NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_SERVER_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_LIGHT_BLUE), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_MAIN), NWidget(NWID_VERTICAL), SetPIP(10, 7, 0), NWidget(NWID_HORIZONTAL), SetPIP(10, 7, 10), /* LEFT SIDE */ NWidget(NWID_VERTICAL), SetPIP(0, 7, 0), NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 12), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidgetFunction(MakeResizableHeader), NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NG_MATRIX), SetResize(1, 1), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT), SetScrollbar(WID_NG_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NG_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER, STR_NULL), SetResize(1, 0), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_LASTJOINED), SetFill(1, 0), SetResize(1, 0), SetDataTip(0x0, STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST), EndContainer(), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_LASTJOINED_SPACER), SetFill(0, 0), EndContainer(), EndContainer(), EndContainer(), /* RIGHT SIDE */ NWidget(NWID_VERTICAL), SetPIP(0, 7, 0), NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CLIENT_LABEL), SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_CLIENT), SetMinimalSize(151, 12), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE, STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(5, 5, 5), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_DETAILS_SPACER), SetMinimalSize(140, 155), SetResize(0, 1), SetFill(1, 1), // Make sure it's at least this wide NWidget(NWID_HORIZONTAL, NC_NONE), SetPIP(5, 5, 5), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_MISSING_SEL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(5, 5, 5), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_SEL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF), SetFill(1, 0), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(5, 5, 5), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_JOIN), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_JOIN_GAME, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_REFRESH), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), EndContainer(), EndContainer(), /* BOTTOM */ NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 7, 4), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_FIND), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_FIND_SERVER, STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_ADD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_START), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), SetResize(1, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetFill(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_LIGHT_BLUE), EndContainer(), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _network_game_window_desc( WDP_CENTER, "list_servers", 1000, 730, WC_NETWORK_WINDOW, WC_NONE, 0, _nested_network_game_widgets, lengthof(_nested_network_game_widgets) ); void ShowNetworkGameWindow() { static bool first = true; DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY); DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START); /* Only show once */ if (first) { first = false; /* Add all servers from the config file to our list. */ for (char **iter = _network_host_list.Begin(); iter != _network_host_list.End(); iter++) { NetworkAddServer(*iter); } } new NetworkGameWindow(&_network_game_window_desc); } struct NetworkStartServerWindow : public Window { byte widget_id; ///< The widget that has the pop-up input menu QueryString name_editbox; ///< Server name editbox. NetworkStartServerWindow(WindowDesc *desc) : Window(desc), name_editbox(NETWORK_NAME_LENGTH) { this->InitNested(WN_NETWORK_WINDOW_START); this->querystrings[WID_NSS_GAMENAME] = &this->name_editbox; this->name_editbox.text.Assign(_settings_client.network.server_name); this->SetFocusedWidget(WID_NSS_GAMENAME); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_NSS_CONNTYPE_BTN: SetDParam(0, _connection_types_dropdown[_settings_client.network.server_advertise]); break; case WID_NSS_CLIENTS_TXT: SetDParam(0, _settings_client.network.max_clients); break; case WID_NSS_COMPANIES_TXT: SetDParam(0, _settings_client.network.max_companies); break; case WID_NSS_SPECTATORS_TXT: SetDParam(0, _settings_client.network.max_spectators); break; case WID_NSS_LANGUAGE_BTN: SetDParam(0, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_NSS_CONNTYPE_BTN: *size = maxdim(GetStringBoundingBox(_connection_types_dropdown[0]), GetStringBoundingBox(_connection_types_dropdown[1])); size->width += padding.width; size->height += padding.height; break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_NSS_SETPWD: /* If password is set, draw red '*' next to 'Set password' button. */ if (!StrEmpty(_settings_client.network.server_password)) DrawString(r.right + WD_FRAMERECT_LEFT, this->width - WD_FRAMERECT_RIGHT, r.top, "*", TC_RED); } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_NSS_CANCEL: // Cancel button ShowNetworkGameWindow(); break; case WID_NSS_SETPWD: // Set password button this->widget_id = WID_NSS_SETPWD; SetDParamStr(0, _settings_client.network.server_password); ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_START_SERVER_SET_PASSWORD, 20, this, CS_ALPHANUMERAL, QSF_NONE); break; case WID_NSS_CONNTYPE_BTN: // Connection type ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0); // do it for widget WID_NSS_CONNTYPE_BTN break; case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: // Click on up/down button for number of companies case WID_NSS_SPECTATORS_BTND: case WID_NSS_SPECTATORS_BTNU: // Click on up/down button for number of spectators /* Don't allow too fast scrolling. */ if (!(this->flags & WF_TIMEOUT) || this->timeout_timer <= 1) { this->HandleButtonClick(widget); this->SetDirty(); switch (widget) { default: NOT_REACHED(); case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: _settings_client.network.max_clients = Clamp(_settings_client.network.max_clients + widget - WID_NSS_CLIENTS_TXT, 2, MAX_CLIENTS); break; case WID_NSS_COMPANIES_BTND: case WID_NSS_COMPANIES_BTNU: _settings_client.network.max_companies = Clamp(_settings_client.network.max_companies + widget - WID_NSS_COMPANIES_TXT, 1, MAX_COMPANIES); break; case WID_NSS_SPECTATORS_BTND: case WID_NSS_SPECTATORS_BTNU: _settings_client.network.max_spectators = Clamp(_settings_client.network.max_spectators + widget - WID_NSS_SPECTATORS_TXT, 0, MAX_CLIENTS); break; } } _left_button_clicked = false; break; case WID_NSS_CLIENTS_TXT: // Click on number of clients this->widget_id = WID_NSS_CLIENTS_TXT; SetDParam(0, _settings_client.network.max_clients); ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, 4, this, CS_NUMERAL, QSF_NONE); break; case WID_NSS_COMPANIES_TXT: // Click on number of companies this->widget_id = WID_NSS_COMPANIES_TXT; SetDParam(0, _settings_client.network.max_companies); ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, 3, this, CS_NUMERAL, QSF_NONE); break; case WID_NSS_SPECTATORS_TXT: // Click on number of spectators this->widget_id = WID_NSS_SPECTATORS_TXT; SetDParam(0, _settings_client.network.max_spectators); ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, 4, this, CS_NUMERAL, QSF_NONE); break; case WID_NSS_LANGUAGE_BTN: { // Language uint sel = 0; for (uint i = 0; i < lengthof(_language_dropdown) - 1; i++) { if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) { sel = i; break; } } ShowDropDownMenu(this, _language_dropdown, sel, WID_NSS_LANGUAGE_BTN, 0, 0); break; } case WID_NSS_GENERATE_GAME: // Start game _is_network_server = true; if (_ctrl_pressed) { StartNewGameWithoutGUI(GENERATE_NEW_SEED); } else { ShowGenerateLandscape(); } break; case WID_NSS_LOAD_GAME: _is_network_server = true; ShowSaveLoadDialog(SLD_LOAD_GAME); break; case WID_NSS_PLAY_SCENARIO: _is_network_server = true; ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break; case WID_NSS_PLAY_HEIGHTMAP: _is_network_server = true; ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break; } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_NSS_CONNTYPE_BTN: _settings_client.network.server_advertise = (index != 0); break; case WID_NSS_LANGUAGE_BTN: _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY; break; default: NOT_REACHED(); } this->SetDirty(); } virtual void OnEditboxChanged(int wid) { if (wid == WID_NSS_GAMENAME) { strecpy(_settings_client.network.server_name, this->name_editbox.text.buf, lastof(_settings_client.network.server_name)); } } virtual void OnTimeout() { static const int raise_widgets[] = {WID_NSS_CLIENTS_BTND, WID_NSS_CLIENTS_BTNU, WID_NSS_COMPANIES_BTND, WID_NSS_COMPANIES_BTNU, WID_NSS_SPECTATORS_BTND, WID_NSS_SPECTATORS_BTNU, WIDGET_LIST_END}; for (const int *widget = raise_widgets; *widget != WIDGET_LIST_END; widget++) { if (this->IsWidgetLowered(*widget)) { this->RaiseWidget(*widget); this->SetWidgetDirty(*widget); } } } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; if (this->widget_id == WID_NSS_SETPWD) { strecpy(_settings_client.network.server_password, str, lastof(_settings_client.network.server_password)); } else { int32 value = atoi(str); this->SetWidgetDirty(this->widget_id); switch (this->widget_id) { default: NOT_REACHED(); case WID_NSS_CLIENTS_TXT: _settings_client.network.max_clients = Clamp(value, 2, MAX_CLIENTS); break; case WID_NSS_COMPANIES_TXT: _settings_client.network.max_companies = Clamp(value, 1, MAX_COMPANIES); break; case WID_NSS_SPECTATORS_TXT: _settings_client.network.max_spectators = Clamp(value, 0, MAX_CLIENTS); break; } } this->SetDirty(); } }; static const NWidgetPart _nested_network_start_server_window_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_START_SERVER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NSS_BACKGROUND), NWidget(NWID_VERTICAL), SetPIP(10, 6, 10), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), /* Game name widgets */ NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NSS_GAMENAME), SetMinimalSize(10, 12), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(NWID_SPACER), SetFill(1, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_SETPWD), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SET_PASSWORD, STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS, STR_NULL), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_CLIENTS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_CLIENTS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES, STR_NULL), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_COMPANIES_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_COMPANIES_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, STR_NULL), NWidget(NWID_HORIZONTAL), NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_BTND), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_DOWN, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_TXT), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_SPECTATORS_SELECT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP), NWidget(WWT_IMGBTN, COLOUR_LIGHT_BLUE, WID_NSS_SPECTATORS_BTNU), SetMinimalSize(12, 12), SetFill(0, 1), SetDataTip(SPR_ARROW_UP, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), /* 'generate game' and 'load game' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_GENERATE_GAME), SetDataTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_LOAD_GAME), SetDataTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetFill(1, 0), EndContainer(), /* 'play scenario' and 'play heightmap' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_SCENARIO), SetDataTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_PLAY_HEIGHTMAP), SetDataTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 0, 10), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NSS_CANCEL), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), SetMinimalSize(128, 12), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _network_start_server_window_desc( WDP_CENTER, NULL, 0, 0, WC_NETWORK_WINDOW, WC_NONE, 0, _nested_network_start_server_window_widgets, lengthof(_nested_network_start_server_window_widgets) ); static void ShowNetworkStartServerWindow() { DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY); new NetworkStartServerWindow(&_network_start_server_window_desc); } struct NetworkLobbyWindow : public Window { CompanyID company; ///< Selected company NetworkGameList *server; ///< Selected server NetworkCompanyInfo company_info[MAX_COMPANIES]; Scrollbar *vscroll; NetworkLobbyWindow(WindowDesc *desc, NetworkGameList *ngl) : Window(desc), company(INVALID_COMPANY), server(ngl) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_NL_SCROLLBAR); this->FinishInitNested(WN_NETWORK_WINDOW_LOBBY); } CompanyID NetworkLobbyFindCompanyIndex(byte pos) const { /* Scroll through all this->company_info and get the 'pos' item that is not empty. */ for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) { if (!StrEmpty(this->company_info[i].company_name)) { if (pos-- == 0) return i; } } return COMPANY_FIRST; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_NL_HEADER: size->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; break; case WID_NL_MATRIX: resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM; size->height = 10 * resize->height; break; case WID_NL_DETAILS: size->height = 30 + 11 * FONT_HEIGHT_NORMAL; break; } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_NL_TEXT: SetDParamStr(0, this->server->info.server_name); break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_NL_DETAILS: this->DrawDetails(r); break; case WID_NL_MATRIX: this->DrawMatrix(r); break; } } virtual void OnPaint() { const NetworkGameInfo *gi = &this->server->info; /* Join button is disabled when no company is selected and for AI companies. */ this->SetWidgetDisabledState(WID_NL_JOIN, this->company == INVALID_COMPANY || GetLobbyCompanyInfo(this->company)->ai); /* Cannot start new company if there are too many. */ this->SetWidgetDisabledState(WID_NL_NEW, gi->companies_on >= gi->companies_max); /* Cannot spectate if there are too many spectators. */ this->SetWidgetDisabledState(WID_NL_SPECTATE, gi->spectators_on >= gi->spectators_max); this->vscroll->SetCount(gi->companies_on); /* Draw window widgets */ this->DrawWidgets(); } void DrawMatrix(const Rect &r) const { bool rtl = _current_text_dir == TD_RTL; uint left = r.left + WD_FRAMERECT_LEFT; uint right = r.right - WD_FRAMERECT_RIGHT; Dimension lock_size = GetSpriteSize(SPR_LOCK); int lock_width = lock_size.width; int lock_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - lock_size.height) / 2; Dimension profit_size = GetSpriteSize(SPR_PROFIT_LOT); int profit_width = lock_size.width; int profit_y_offset = (this->resize.step_height - WD_MATRIX_TOP - WD_MATRIX_BOTTOM - profit_size.height) / 2; uint text_left = left + (rtl ? lock_width + profit_width + 4 : 0); uint text_right = right - (rtl ? 0 : lock_width + profit_width + 4); uint profit_left = rtl ? left : right - profit_width; uint lock_left = rtl ? left + profit_width + 2 : right - profit_width - lock_width - 2; int y = r.top + WD_MATRIX_TOP; /* Draw company list */ int pos = this->vscroll->GetPosition(); while (pos < this->server->info.companies_on) { byte company = NetworkLobbyFindCompanyIndex(pos); bool income = false; if (this->company == company) { GfxFillRect(r.left + 1, y - 2, r.right - 1, y + FONT_HEIGHT_NORMAL, PC_GREY); // show highlighted item with a different colour } DrawString(text_left, text_right, y, this->company_info[company].company_name, TC_BLACK); if (this->company_info[company].use_password != 0) DrawSprite(SPR_LOCK, PAL_NONE, lock_left, y + lock_y_offset); /* If the company's income was positive puts a green dot else a red dot */ if (this->company_info[company].income >= 0) income = true; DrawSprite(income ? SPR_PROFIT_LOT : SPR_PROFIT_NEGATIVE, PAL_NONE, profit_left, y + profit_y_offset); pos++; y += this->resize.step_height; if (pos >= this->vscroll->GetPosition() + this->vscroll->GetCapacity()) break; } } void DrawDetails(const Rect &r) const { const int detail_height = 12 + FONT_HEIGHT_NORMAL + 12; /* Draw info about selected company when it is selected in the left window. */ GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.top + detail_height - 1, PC_DARK_BLUE); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 12, STR_NETWORK_GAME_LOBBY_COMPANY_INFO, TC_FROMSTRING, SA_HOR_CENTER); if (this->company == INVALID_COMPANY || StrEmpty(this->company_info[this->company].company_name)) return; int y = r.top + detail_height + 4; const NetworkGameInfo *gi = &this->server->info; SetDParam(0, gi->clients_on); SetDParam(1, gi->clients_max); SetDParam(2, gi->companies_on); SetDParam(3, gi->companies_max); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS); y += FONT_HEIGHT_NORMAL; SetDParamStr(0, this->company_info[this->company].company_name); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_COMPANY_NAME); y += FONT_HEIGHT_NORMAL; SetDParam(0, this->company_info[this->company].inaugurated_year); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR); // inauguration year y += FONT_HEIGHT_NORMAL; SetDParam(0, this->company_info[this->company].company_value); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VALUE); // company value y += FONT_HEIGHT_NORMAL; SetDParam(0, this->company_info[this->company].money); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE); // current balance y += FONT_HEIGHT_NORMAL; SetDParam(0, this->company_info[this->company].income); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME); // last year's income y += FONT_HEIGHT_NORMAL; SetDParam(0, this->company_info[this->company].performance); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PERFORMANCE); // performance y += FONT_HEIGHT_NORMAL; SetDParam(0, this->company_info[this->company].num_vehicle[NETWORK_VEH_TRAIN]); SetDParam(1, this->company_info[this->company].num_vehicle[NETWORK_VEH_LORRY]); SetDParam(2, this->company_info[this->company].num_vehicle[NETWORK_VEH_BUS]); SetDParam(3, this->company_info[this->company].num_vehicle[NETWORK_VEH_SHIP]); SetDParam(4, this->company_info[this->company].num_vehicle[NETWORK_VEH_PLANE]); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_VEHICLES); // vehicles y += FONT_HEIGHT_NORMAL; SetDParam(0, this->company_info[this->company].num_station[NETWORK_VEH_TRAIN]); SetDParam(1, this->company_info[this->company].num_station[NETWORK_VEH_LORRY]); SetDParam(2, this->company_info[this->company].num_station[NETWORK_VEH_BUS]); SetDParam(3, this->company_info[this->company].num_station[NETWORK_VEH_SHIP]); SetDParam(4, this->company_info[this->company].num_station[NETWORK_VEH_PLANE]); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_STATIONS); // stations y += FONT_HEIGHT_NORMAL; SetDParamStr(0, this->company_info[this->company].clients); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_GAME_LOBBY_PLAYERS); // players } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_NL_CANCEL: // Cancel button ShowNetworkGameWindow(); break; case WID_NL_MATRIX: { // Company list uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NL_MATRIX); this->company = (id_v >= this->server->info.companies_on) ? INVALID_COMPANY : NetworkLobbyFindCompanyIndex(id_v); this->SetDirty(); /* FIXME the disabling should go into some InvalidateData, which is called instead of the SetDirty */ if (click_count > 1 && !this->IsWidgetDisabled(WID_NL_JOIN)) this->OnClick(pt, WID_NL_JOIN, 1); break; } case WID_NL_JOIN: // Join company /* Button can be clicked only when it is enabled. */ NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), this->company); break; case WID_NL_NEW: // New company NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_NEW_COMPANY); break; case WID_NL_SPECTATE: // Spectate game NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); break; case WID_NL_REFRESH: // Refresh NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data /* Clear the information so removed companies don't remain */ memset(this->company_info, 0, sizeof(this->company_info)); break; } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_NL_MATRIX); } }; static const NWidgetPart _nested_network_lobby_window_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_NETWORK_GAME_LOBBY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_BACKGROUND), NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NL_TEXT), SetDataTip(STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN, STR_NULL), SetResize(1, 0), SetPadding(10, 10, 0, 10), NWidget(NWID_SPACER), SetMinimalSize(0, 3), NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 10), /* Company list. */ NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_WHITE, WID_NL_HEADER), SetMinimalSize(146, 0), SetResize(1, 0), SetFill(1, 0), EndContainer(), NWidget(WWT_MATRIX, COLOUR_LIGHT_BLUE, WID_NL_MATRIX), SetMinimalSize(146, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP), SetScrollbar(WID_NL_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_LIGHT_BLUE, WID_NL_SCROLLBAR), NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetResize(0, 1), /* Company info. */ NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NL_DETAILS), SetMinimalSize(232, 0), SetResize(1, 1), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 9), /* Buttons. */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 3, 10), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_JOIN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_JOIN_COMPANY, STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_NEW), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_NEW_COMPANY, STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_SPECTATE), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_GAME_LOBBY_SPECTATE_GAME, STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_REFRESH), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_REFRESH, STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(0, 3, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NL_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL), NWidget(NWID_SPACER), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 8), EndContainer(), }; static WindowDesc _network_lobby_window_desc( WDP_CENTER, NULL, 0, 0, WC_NETWORK_WINDOW, WC_NONE, 0, _nested_network_lobby_window_widgets, lengthof(_nested_network_lobby_window_widgets) ); /** * Show the networklobbywindow with the selected server. * @param ngl Selected game pointer which is passed to the new window. */ static void ShowNetworkLobbyWindow(NetworkGameList *ngl) { DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START); DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data new NetworkLobbyWindow(&_network_lobby_window_desc, ngl); } /** * Get the company information of a given company to fill for the lobby. * @param company the company to get the company info struct from. * @return the company info struct to write the (downloaded) data to. */ NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company) { NetworkLobbyWindow *lobby = dynamic_cast(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY)); return (lobby != NULL && company < MAX_COMPANIES) ? &lobby->company_info[company] : NULL; } /* The window below gives information about the connected clients * and also makes able to give money to them, kick them (if server) * and stuff like that. */ extern void DrawCompanyIcon(CompanyID cid, int x, int y); /** * Prototype for ClientList actions. * @param ci The information about the current client. */ typedef void ClientList_Action_Proc(const NetworkClientInfo *ci); static const NWidgetPart _nested_client_list_popup_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_CLP_PANEL), EndContainer(), }; static WindowDesc _client_list_popup_desc( WDP_AUTO, NULL, 0, 0, WC_CLIENT_LIST_POPUP, WC_CLIENT_LIST, 0, _nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets) ); /* Here we start to define the options out of the menu */ static void ClientList_Kick(const NetworkClientInfo *ci) { NetworkServerKickClient(ci->client_id); } static void ClientList_Ban(const NetworkClientInfo *ci) { NetworkServerKickOrBanIP(ci->client_id, true); } static void ClientList_GiveMoney(const NetworkClientInfo *ci) { ShowNetworkGiveMoneyWindow(ci->client_playas); } static void ClientList_SpeakToClient(const NetworkClientInfo *ci) { ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, ci->client_id); } static void ClientList_SpeakToCompany(const NetworkClientInfo *ci) { ShowNetworkChatQueryWindow(DESTTYPE_TEAM, ci->client_playas); } static void ClientList_SpeakToAll(const NetworkClientInfo *ci) { ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0); } /** Popup selection window to chose an action to perform */ struct NetworkClientListPopupWindow : Window { /** Container for actions that can be executed. */ struct ClientListAction { StringID name; ///< Name of the action to execute ClientList_Action_Proc *proc; ///< Action to execute }; uint sel_index; ClientID client_id; Point desired_location; SmallVector actions; ///< Actions to execute /** * Add an action to the list of actions to execute. * @param name the name of the action * @param proc the procedure to execute for the action */ inline void AddAction(StringID name, ClientList_Action_Proc *proc) { ClientListAction *action = this->actions.Append(); action->name = name; action->proc = proc; } NetworkClientListPopupWindow(WindowDesc *desc, int x, int y, ClientID client_id) : Window(desc), sel_index(0), client_id(client_id) { this->desired_location.x = x; this->desired_location.y = y; const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); if (_network_own_client_id != ci->client_id) { this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient); } if (Company::IsValidID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) { this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, &ClientList_SpeakToCompany); } this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll); if (_network_own_client_id != ci->client_id) { /* We are no spectator and the company we want to give money to is no spectator and money gifts are allowed. */ if (Company::IsValidID(_local_company) && Company::IsValidID(ci->client_playas) && _settings_game.economy.give_money) { this->AddAction(STR_NETWORK_CLIENTLIST_GIVE_MONEY, &ClientList_GiveMoney); } } /* A server can kick clients (but not himself). */ if (_network_server && _network_own_client_id != ci->client_id) { this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick); this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban); } this->InitNested(client_id); CLRBITS(this->flags, WF_WHITE_BORDER); } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { return this->desired_location; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { Dimension d = *size; for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++) { d = maxdim(GetStringBoundingBox(action->name), d); } d.height *= this->actions.Length(); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = d; } virtual void DrawWidget(const Rect &r, int widget) const { /* Draw the actions */ int sel = this->sel_index; int y = r.top + WD_FRAMERECT_TOP; for (const ClientListAction *action = this->actions.Begin(); action != this->actions.End(); action++, y += FONT_HEIGHT_NORMAL) { TextColour colour; if (sel-- == 0) { // Selected item, highlight it GfxFillRect(r.left + 1, y, r.right - 1, y + FONT_HEIGHT_NORMAL - 1, PC_BLACK); colour = TC_WHITE; } else { colour = TC_BLACK; } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, action->name, colour); } } virtual void OnMouseLoop() { /* We selected an action */ uint index = (_cursor.pos.y - this->top - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL; if (_left_button_down) { if (index == this->sel_index || index >= this->actions.Length()) return; this->sel_index = index; this->SetDirty(); } else { if (index < this->actions.Length() && _cursor.pos.y >= this->top) { const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id); if (ci != NULL) this->actions[index].proc(ci); } DeleteWindowByClass(WC_CLIENT_LIST_POPUP); } } }; /** * Show the popup (action list) */ static void PopupClientList(ClientID client_id, int x, int y) { DeleteWindowByClass(WC_CLIENT_LIST_POPUP); if (NetworkClientInfo::GetByClientID(client_id) == NULL) return; new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_id); } static const NWidgetPart _nested_client_list_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_CL_PANEL), SetMinimalSize(250, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 1), EndContainer(), }; static WindowDesc _client_list_desc( WDP_AUTO, "list_clients", 0, 0, WC_CLIENT_LIST, WC_NONE, 0, _nested_client_list_widgets, lengthof(_nested_client_list_widgets) ); /** * Main handle for clientlist */ struct NetworkClientListWindow : Window { int selected_item; uint server_client_width; uint line_height; Dimension icon_size; NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), selected_item(-1) { this->InitNested(window_number); } /** * Finds the amount of clients and set the height correct */ bool CheckClientListHeight() { int num = 0; const NetworkClientInfo *ci; /* Should be replaced with a loop through all clients */ FOR_ALL_CLIENT_INFOS(ci) { if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++; } num *= this->line_height; int diff = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget(WID_CL_PANEL)->current_y); /* If height is changed */ if (diff != 0) { ResizeWindow(this, 0, diff); return false; } return true; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_CL_PANEL) return; this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT; this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL); uint width = 100; // Default width const NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { width = max(width, GetStringBoundingBox(ci->client_name).width); } size->width = WD_FRAMERECT_LEFT + this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT; } virtual void OnPaint() { /* Check if we need to reset the height */ if (!this->CheckClientListHeight()) return; this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_CL_PANEL) return; bool rtl = _current_text_dir == TD_RTL; int icon_offset = (this->line_height - icon_size.height) / 2; int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; uint y = r.top + WD_FRAMERECT_TOP; uint left = r.left + WD_FRAMERECT_LEFT; uint right = r.right - WD_FRAMERECT_RIGHT; uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT; uint type_left = rtl ? right - this->server_client_width : left; uint type_right = rtl ? right : left + this->server_client_width - 1; uint icon_left = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width; uint name_left = rtl ? left : left + type_icon_width; uint name_right = rtl ? right - type_icon_width : right; int i = 0; const NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS(ci) { TextColour colour; if (this->selected_item == i++) { // Selected item, highlight it GfxFillRect(r.left + 1, y, r.right - 1, y + this->line_height - 1, PC_BLACK); colour = TC_WHITE; } else { colour = TC_BLACK; } if (ci->client_id == CLIENT_ID_SERVER) { DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour); } else { DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour); } /* Filter out spectators */ if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset); DrawString(name_left, name_right, y + text_offset, ci->client_name, colour); y += line_height; } } virtual void OnClick(Point pt, int widget, int click_count) { /* Show the popup with option */ if (this->selected_item != -1) { NetworkClientInfo *ci; int client_no = this->selected_item; FOR_ALL_CLIENT_INFOS(ci) { if (client_no == 0) break; client_no--; } if (ci != NULL) PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top); } } virtual void OnMouseOver(Point pt, int widget) { /* -1 means we left the current window */ if (pt.y == -1) { this->selected_item = -1; this->SetDirty(); return; } /* Find the new selected item (if any) */ pt.y -= this->GetWidget(WID_CL_PANEL)->pos_y; int item = -1; if (IsInsideMM(pt.y, WD_FRAMERECT_TOP, this->GetWidget(WID_CL_PANEL)->current_y - WD_FRAMERECT_BOTTOM)) { item = (pt.y - WD_FRAMERECT_TOP) / this->line_height; } /* It did not change.. no update! */ if (item == this->selected_item) return; this->selected_item = item; /* Repaint */ this->SetDirty(); } }; void ShowClientList() { AllocateWindowDescFront(&_client_list_desc, 0); } NetworkJoinStatus _network_join_status; ///< The status of joining. uint8 _network_join_waiting; ///< The number of clients waiting in front of us. uint32 _network_join_bytes; ///< The number of bytes we already downloaded. uint32 _network_join_bytes_total; ///< The total number of bytes to download. struct NetworkJoinStatusWindow : Window { NetworkPasswordType password_type; NetworkJoinStatusWindow(WindowDesc *desc) : Window(desc) { this->parent = FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); this->InitNested(WN_NETWORK_STATUS_WINDOW_JOIN); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_NJS_BACKGROUND) return; uint8 progress; // used for progress bar DrawString(r.left + 2, r.right - 2, r.top + 20, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER); switch (_network_join_status) { case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING: case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO: progress = 10; // first two stages 10% break; case NETWORK_JOIN_STATUS_WAITING: SetDParam(0, _network_join_waiting); DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, STR_NETWORK_CONNECTING_WAITING, TC_FROMSTRING, SA_HOR_CENTER); progress = 15; // third stage is 15% break; case NETWORK_JOIN_STATUS_DOWNLOADING: SetDParam(0, _network_join_bytes); SetDParam(1, _network_join_bytes_total); DrawString(r.left + 2, r.right - 2, r.top + 20 + FONT_HEIGHT_NORMAL, _network_join_bytes_total == 0 ? STR_NETWORK_CONNECTING_DOWNLOADING_1 : STR_NETWORK_CONNECTING_DOWNLOADING_2, TC_FROMSTRING, SA_HOR_CENTER); if (_network_join_bytes_total == 0) { progress = 15; // We don't have the final size yet; the server is still compressing! break; } /* FALL THROUGH */ default: // Waiting is 15%, so the resting receivement of map is maximum 70% progress = 15 + _network_join_bytes * (100 - 15) / _network_join_bytes_total; } /* Draw nice progress bar :) */ DrawFrameRect(r.left + 20, r.top + 5, (int)((this->width - 20) * progress / 100), r.top + 15, COLOUR_MAUVE, FR_NONE); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_NJS_BACKGROUND) return; size->height = 25 + 2 * FONT_HEIGHT_NORMAL; /* Account for the statuses */ uint width = 0; for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) { width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width); } /* For the number of waiting (other) players */ SetDParamMaxValue(0, MAX_CLIENTS); width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width); /* Account for downloading ~ 10 MiB */ SetDParamMaxDigits(0, 8); SetDParamMaxDigits(1, 8); width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_1).width); width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_2).width); /* Give a bit more clearing for the widest strings than strictly needed */ size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10; } virtual void OnClick(Point pt, int widget, int click_count) { if (widget == WID_NJS_CANCELOK) { // Disconnect button NetworkDisconnect(); SwitchToMode(SM_MENU); ShowNetworkGameWindow(); } } virtual void OnQueryTextFinished(char *str) { if (StrEmpty(str)) { NetworkDisconnect(); ShowNetworkGameWindow(); return; } switch (this->password_type) { case NETWORK_GAME_PASSWORD: MyClient::SendGamePassword (str); break; case NETWORK_COMPANY_PASSWORD: MyClient::SendCompanyPassword(str); break; default: NOT_REACHED(); } } }; static const NWidgetPart _nested_network_join_status_window_widgets[] = { NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CONNECTING_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(WWT_EMPTY, COLOUR_GREY, WID_NJS_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NJS_CANCELOK), SetMinimalSize(101, 12), SetDataTip(STR_NETWORK_CONNECTION_DISCONNECT, STR_NULL), NWidget(NWID_SPACER), SetMinimalSize(75, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 4), EndContainer(), }; static WindowDesc _network_join_status_window_desc( WDP_CENTER, NULL, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL, _nested_network_join_status_window_widgets, lengthof(_nested_network_join_status_window_widgets) ); void ShowJoinStatusWindow() { DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); new NetworkJoinStatusWindow(&_network_join_status_window_desc); } void ShowNetworkNeedPassword(NetworkPasswordType npt) { NetworkJoinStatusWindow *w = (NetworkJoinStatusWindow *)FindWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); if (w == NULL) return; w->password_type = npt; StringID caption; switch (npt) { default: NOT_REACHED(); case NETWORK_GAME_PASSWORD: caption = STR_NETWORK_NEED_GAME_PASSWORD_CAPTION; break; case NETWORK_COMPANY_PASSWORD: caption = STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION; break; } ShowQueryString(STR_EMPTY, caption, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_NONE); } struct NetworkCompanyPasswordWindow : public Window { QueryString password_editbox; ///< Password editbox. NetworkCompanyPasswordWindow(WindowDesc *desc, Window *parent) : Window(desc), password_editbox(lengthof(_settings_client.network.default_company_pass)) { this->InitNested(0); this->parent = parent; this->querystrings[WID_NCP_PASSWORD] = &this->password_editbox; this->password_editbox.cancel_button = WID_NCP_CANCEL; this->password_editbox.ok_button = WID_NCP_OK; this->SetFocusedWidget(WID_NCP_PASSWORD); } void OnOk() { if (this->IsWidgetLowered(WID_NCP_SAVE_AS_DEFAULT_PASSWORD)) { strecpy(_settings_client.network.default_company_pass, this->password_editbox.text.buf, lastof(_settings_client.network.default_company_pass)); } NetworkChangeCompanyPassword(_local_company, this->password_editbox.text.buf); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_NCP_OK: this->OnOk(); /* FALL THROUGH */ case WID_NCP_CANCEL: delete this; break; case WID_NCP_SAVE_AS_DEFAULT_PASSWORD: this->ToggleWidgetLoweredState(WID_NCP_SAVE_AS_DEFAULT_PASSWORD); this->SetDirty(); break; } } }; static const NWidgetPart _nested_network_company_password_window_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_PASSWORD_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_NCP_BACKGROUND), NWidget(NWID_VERTICAL), SetPIP(5, 5, 5), NWidget(NWID_HORIZONTAL), SetPIP(5, 5, 5), NWidget(WWT_TEXT, COLOUR_GREY, WID_NCP_LABEL), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NCP_PASSWORD), SetFill(1, 0), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_VIEW_SET_PASSWORD, STR_NULL), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(5, 0, 5), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_NCP_SAVE_AS_DEFAULT_PASSWORD), SetMinimalSize(194, 12), SetDataTip(STR_COMPANY_PASSWORD_MAKE_DEFAULT, STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_COMPANY_PASSWORD_CANCEL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NCP_OK), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_COMPANY_PASSWORD_OK), EndContainer(), }; static WindowDesc _network_company_password_window_desc( WDP_AUTO, NULL, 0, 0, WC_COMPANY_PASSWORD_WINDOW, WC_NONE, 0, _nested_network_company_password_window_widgets, lengthof(_nested_network_company_password_window_widgets) ); void ShowNetworkCompanyPasswordWindow(Window *parent) { DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0); new NetworkCompanyPasswordWindow(&_network_company_password_window_desc, parent); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_chat_gui.cpp0000644000000000000000000004441512627373441020234 0ustar rootroot/* $Id: network_chat_gui.cpp 27146 2015-02-13 21:13:45Z frosch $ */ /* * 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 network_chat_gui.cpp GUI for handling chat messages. */ #include /* va_list */ #ifdef ENABLE_NETWORK #include "../stdafx.h" #include "../strings_func.h" #include "../blitter/factory.hpp" #include "../console_func.h" #include "../video/video_driver.hpp" #include "../querystring_gui.h" #include "../town.h" #include "../window_func.h" #include "../toolbar_gui.h" #include "../core/geometry_func.hpp" #include "network.h" #include "network_client.h" #include "network_base.h" #include "../widgets/network_chat_widget.h" #include "table/strings.h" #include "../safeguards.h" /** The draw buffer must be able to contain the chat message, client name and the "[All]" message, * some spaces and possible translations of [All] to other languages. */ assert_compile((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40); /** Spacing between chat lines. */ static const uint NETWORK_CHAT_LINE_SPACING = 3; /** Container for a message. */ struct ChatMessage { char message[DRAW_STRING_BUFFER]; ///< The action message. TextColour colour; ///< The colour of the message. uint32 remove_time; ///< The time to remove the message. }; /* used for chat window */ static ChatMessage *_chatmsg_list = NULL; ///< The actual chat message list. static bool _chatmessage_dirty = false; ///< Does the chat message need repainting? static bool _chatmessage_visible = false; ///< Is a chat message visible. static bool _chat_tab_completion_active; ///< Whether tab completion is active. static uint MAX_CHAT_MESSAGES = 0; ///< The limit of chat messages to show. /** * The chatbox grows from the bottom so the coordinates are pixels from * the left and pixels from the bottom. The height is the maximum height. */ static PointDimension _chatmsg_box; static uint8 *_chatmessage_backup = NULL; ///< Backup in case text is moved. /** * Count the chat messages. * @return The number of chat messages. */ static inline uint GetChatMessageCount() { uint i = 0; for (; i < MAX_CHAT_MESSAGES; i++) { if (_chatmsg_list[i].message[0] == '\0') break; } return i; } /** * Add a text message to the 'chat window' to be shown * @param colour The colour this message is to be shown in * @param duration The duration of the chat message in seconds * @param message message itself in printf() style */ void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *message, ...) { char buf[DRAW_STRING_BUFFER]; va_list va; va_start(va, message); vseprintf(buf, lastof(buf), message, va); va_end(va); Utf8TrimString(buf, DRAW_STRING_BUFFER); uint msg_count = GetChatMessageCount(); if (MAX_CHAT_MESSAGES == msg_count) { memmove(&_chatmsg_list[0], &_chatmsg_list[1], sizeof(_chatmsg_list[0]) * (msg_count - 1)); msg_count = MAX_CHAT_MESSAGES - 1; } ChatMessage *cmsg = &_chatmsg_list[msg_count++]; strecpy(cmsg->message, buf, lastof(cmsg->message)); cmsg->colour = (colour & TC_IS_PALETTE_COLOUR) ? colour : TC_WHITE; cmsg->remove_time = _realtime_tick + duration * 1000; _chatmessage_dirty = true; } /** Initialize all font-dependent chat box sizes. */ void NetworkReInitChatBoxSize() { _chatmsg_box.y = 3 * FONT_HEIGHT_NORMAL; _chatmsg_box.height = MAX_CHAT_MESSAGES * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING) + 2; _chatmessage_backup = ReallocT(_chatmessage_backup, _chatmsg_box.width * _chatmsg_box.height * BlitterFactory::GetCurrentBlitter()->GetBytesPerPixel()); } /** Initialize all buffers of the chat visualisation. */ void NetworkInitChatMessage() { MAX_CHAT_MESSAGES = _settings_client.gui.network_chat_box_height; _chatmsg_list = ReallocT(_chatmsg_list, _settings_client.gui.network_chat_box_height); _chatmsg_box.x = 10; _chatmsg_box.width = _settings_client.gui.network_chat_box_width_pct * _screen.width / 100; NetworkReInitChatBoxSize(); _chatmessage_visible = false; for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) { _chatmsg_list[i].message[0] = '\0'; } } /** Hide the chatbox */ void NetworkUndrawChatMessage() { /* Sometimes we also need to hide the cursor * This is because both textmessage and the cursor take a shot of the * screen before drawing. * Now the textmessage takes his shot and paints his data before the cursor * does, so in the shot of the cursor is the screen-data of the textmessage * included when the cursor hangs somewhere over the textmessage. To * avoid wrong repaints, we undraw the cursor in that case, and everything * looks nicely ;) * (and now hope this story above makes sense to you ;)) */ if (_cursor.visible && _cursor.draw_pos.x + _cursor.draw_size.x >= _chatmsg_box.x && _cursor.draw_pos.x <= _chatmsg_box.x + _chatmsg_box.width && _cursor.draw_pos.y + _cursor.draw_size.y >= _screen.height - _chatmsg_box.y - _chatmsg_box.height && _cursor.draw_pos.y <= _screen.height - _chatmsg_box.y) { UndrawMouseCursor(); } if (_chatmessage_visible) { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); int x = _chatmsg_box.x; int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height; int width = _chatmsg_box.width; int height = _chatmsg_box.height; if (y < 0) { height = max(height + y, min(_chatmsg_box.height, _screen.height)); y = 0; } if (x + width >= _screen.width) { width = _screen.width - x; } if (width <= 0 || height <= 0) return; _chatmessage_visible = false; /* Put our 'shot' back to the screen */ blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height); /* And make sure it is updated next time */ VideoDriver::GetInstance()->MakeDirty(x, y, width, height); _chatmessage_dirty = true; } } /** Check if a message is expired. */ void NetworkChatMessageLoop() { for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) { ChatMessage *cmsg = &_chatmsg_list[i]; if (cmsg->message[0] == '\0') continue; /* Message has expired, remove from the list */ if (cmsg->remove_time < _realtime_tick) { /* Move the remaining messages over the current message */ if (i != MAX_CHAT_MESSAGES - 1) memmove(cmsg, cmsg + 1, sizeof(*cmsg) * (MAX_CHAT_MESSAGES - i - 1)); /* Mark the last item as empty */ _chatmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0'; _chatmessage_dirty = true; /* Go one item back, because we moved the array 1 to the left */ i--; } } } /** Draw the chat message-box */ void NetworkDrawChatMessage() { Blitter *blitter = BlitterFactory::GetCurrentBlitter(); if (!_chatmessage_dirty) return; /* First undraw if needed */ NetworkUndrawChatMessage(); if (_iconsole_mode == ICONSOLE_FULL) return; /* Check if we have anything to draw at all */ uint count = GetChatMessageCount(); if (count == 0) return; int x = _chatmsg_box.x; int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height; int width = _chatmsg_box.width; int height = _chatmsg_box.height; if (y < 0) { height = max(height + y, min(_chatmsg_box.height, _screen.height)); y = 0; } if (x + width >= _screen.width) { width = _screen.width - x; } if (width <= 0 || height <= 0) return; assert(blitter->BufferSize(width, height) <= (int)(_chatmsg_box.width * _chatmsg_box.height * blitter->GetBytesPerPixel())); /* Make a copy of the screen as it is before painting (for undraw) */ blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, x, y), _chatmessage_backup, width, height); _cur_dpi = &_screen; // switch to _screen painting int string_height = 0; for (uint i = 0; i < count; i++) { SetDParamStr(0, _chatmsg_list[i].message); string_height += GetStringLineCount(STR_JUST_RAW_STRING, width - 1) * FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING; } string_height = min(string_height, MAX_CHAT_MESSAGES * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING)); int top = _screen.height - _chatmsg_box.y - string_height - 2; int bottom = _screen.height - _chatmsg_box.y - 2; /* Paint a half-transparent box behind the chat messages */ GfxFillRect(_chatmsg_box.x, top - 2, _chatmsg_box.x + _chatmsg_box.width - 1, bottom, PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR // black, but with some alpha for background ); /* Paint the chat messages starting with the lowest at the bottom */ int ypos = bottom - 2; for (int i = count - 1; i >= 0; i--) { ypos = DrawStringMultiLine(_chatmsg_box.x + 3, _chatmsg_box.x + _chatmsg_box.width - 1, top, ypos, _chatmsg_list[i].message, _chatmsg_list[i].colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - NETWORK_CHAT_LINE_SPACING; if (ypos < top) break; } /* Make sure the data is updated next flush */ VideoDriver::GetInstance()->MakeDirty(x, y, width, height); _chatmessage_visible = true; _chatmessage_dirty = false; } /** * Send an actual chat message. * @param buf The message to send. * @param type The type of destination. * @param dest The actual destination index. */ static void SendChat(const char *buf, DestType type, int dest) { if (StrEmpty(buf)) return; if (!_network_server) { MyClient::SendChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, 0); } else { NetworkServerSendChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, CLIENT_ID_SERVER); } } /** Window to enter the chat message in. */ struct NetworkChatWindow : public Window { DestType dtype; ///< The type of destination. StringID dest_string; ///< String representation of the destination. int dest; ///< The identifier of the destination. QueryString message_editbox; ///< Message editbox. /** * Create a chat input window. * @param desc Description of the looks of the window. * @param type The type of destination. * @param dest The actual destination index. */ NetworkChatWindow(WindowDesc *desc, DestType type, int dest) : Window(desc), message_editbox(NETWORK_CHAT_LENGTH) { this->dtype = type; this->dest = dest; this->querystrings[WID_NC_TEXTBOX] = &this->message_editbox; this->message_editbox.cancel_button = WID_NC_CLOSE; this->message_editbox.ok_button = WID_NC_SENDBUTTON; static const StringID chat_captions[] = { STR_NETWORK_CHAT_ALL_CAPTION, STR_NETWORK_CHAT_COMPANY_CAPTION, STR_NETWORK_CHAT_CLIENT_CAPTION }; assert((uint)this->dtype < lengthof(chat_captions)); this->dest_string = chat_captions[this->dtype]; this->InitNested(type); this->SetFocusedWidget(WID_NC_TEXTBOX); InvalidateWindowData(WC_NEWS_WINDOW, 0, this->height); _chat_tab_completion_active = false; PositionNetworkChatWindow(this); } ~NetworkChatWindow() { InvalidateWindowData(WC_NEWS_WINDOW, 0, 0); } virtual void FindWindowPlacementAndResize(int def_width, int def_height) { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } /** * Find the next item of the list of things that can be auto-completed. * @param item The current indexed item to return. This function can, and most * likely will, alter item, to skip empty items in the arrays. * @return Returns the char that matched to the index. */ const char *ChatTabCompletionNextItem(uint *item) { static char chat_tab_temp_buffer[64]; /* First, try clients */ if (*item < MAX_CLIENT_SLOTS) { /* Skip inactive clients */ NetworkClientInfo *ci; FOR_ALL_CLIENT_INFOS_FROM(ci, *item) { *item = ci->index; return ci->client_name; } *item = MAX_CLIENT_SLOTS; } /* Then, try townnames * Not that the following assumes all town indices are adjacent, ie no * towns have been deleted. */ if (*item < (uint)MAX_CLIENT_SLOTS + Town::GetPoolSize()) { const Town *t; FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_SLOTS) { /* Get the town-name via the string-system */ SetDParam(0, t->index); GetString(chat_tab_temp_buffer, STR_TOWN_NAME, lastof(chat_tab_temp_buffer)); return &chat_tab_temp_buffer[0]; } } return NULL; } /** * Find what text to complete. It scans for a space from the left and marks * the word right from that as to complete. It also writes a \0 at the * position of the space (if any). If nothing found, buf is returned. */ static char *ChatTabCompletionFindText(char *buf) { char *p = strrchr(buf, ' '); if (p == NULL) return buf; *p = '\0'; return p + 1; } /** * See if we can auto-complete the current text of the user. */ void ChatTabCompletion() { static char _chat_tab_completion_buf[NETWORK_CHAT_LENGTH]; assert(this->message_editbox.text.max_bytes == lengthof(_chat_tab_completion_buf)); Textbuf *tb = &this->message_editbox.text; size_t len, tb_len; uint item; char *tb_buf, *pre_buf; const char *cur_name; bool second_scan = false; item = 0; /* Copy the buffer so we can modify it without damaging the real data */ pre_buf = (_chat_tab_completion_active) ? stredup(_chat_tab_completion_buf) : stredup(tb->buf); tb_buf = ChatTabCompletionFindText(pre_buf); tb_len = strlen(tb_buf); while ((cur_name = ChatTabCompletionNextItem(&item)) != NULL) { item++; if (_chat_tab_completion_active) { /* We are pressing TAB again on the same name, is there another name * that starts with this? */ if (!second_scan) { size_t offset; size_t length; /* If we are completing at the begin of the line, skip the ': ' we added */ if (tb_buf == pre_buf) { offset = 0; length = (tb->bytes - 1) - 2; } else { /* Else, find the place we are completing at */ offset = strlen(pre_buf) + 1; length = (tb->bytes - 1) - offset; } /* Compare if we have a match */ if (strlen(cur_name) == length && strncmp(cur_name, tb->buf + offset, length) == 0) second_scan = true; continue; } /* Now any match we make on _chat_tab_completion_buf after this, is perfect */ } len = strlen(cur_name); if (tb_len < len && strncasecmp(cur_name, tb_buf, tb_len) == 0) { /* Save the data it was before completion */ if (!second_scan) seprintf(_chat_tab_completion_buf, lastof(_chat_tab_completion_buf), "%s", tb->buf); _chat_tab_completion_active = true; /* Change to the found name. Add ': ' if we are at the start of the line (pretty) */ if (pre_buf == tb_buf) { this->message_editbox.text.Print("%s: ", cur_name); } else { this->message_editbox.text.Print("%s %s", pre_buf, cur_name); } this->SetDirty(); free(pre_buf); return; } } if (second_scan) { /* We walked all possibilities, and the user presses tab again.. revert to original text */ this->message_editbox.text.Assign(_chat_tab_completion_buf); _chat_tab_completion_active = false; this->SetDirty(); } free(pre_buf); } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { Point pt = { 0, _screen.height - sm_height - FindWindowById(WC_STATUS_BAR, 0)->height }; return pt; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_NC_DESTINATION) return; if (this->dtype == DESTTYPE_CLIENT) { SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name); } Dimension d = GetStringBoundingBox(this->dest_string); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_NC_DESTINATION) return; if (this->dtype == DESTTYPE_CLIENT) { SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name); } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, this->dest_string, TC_BLACK, SA_RIGHT); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { /* Send */ case WID_NC_SENDBUTTON: SendChat(this->message_editbox.text.buf, this->dtype, this->dest); /* FALL THROUGH */ case WID_NC_CLOSE: /* Cancel */ delete this; break; } } virtual EventState OnKeyPress(WChar key, uint16 keycode) { EventState state = ES_NOT_HANDLED; if (keycode == WKC_TAB) { ChatTabCompletion(); state = ES_HANDLED; } return state; } virtual void OnEditboxChanged(int wid) { _chat_tab_completion_active = false; } /** * 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 (data == this->dest) delete this; } }; /** The widgets of the chat window. */ static const NWidgetPart _nested_chat_window_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY, WID_NC_CLOSE), NWidget(WWT_PANEL, COLOUR_GREY, WID_NC_BACKGROUND), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXT, COLOUR_GREY, WID_NC_DESTINATION), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetDataTip(STR_NULL, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NC_TEXTBOX), SetMinimalSize(100, 12), SetPadding(1, 0, 1, 0), SetResize(1, 0), SetDataTip(STR_NETWORK_CHAT_OSKTITLE, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NC_SENDBUTTON), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetDataTip(STR_NETWORK_CHAT_SEND, STR_NULL), EndContainer(), EndContainer(), EndContainer(), }; /** The description of the chat window. */ static WindowDesc _chat_window_desc( WDP_MANUAL, NULL, 0, 0, WC_SEND_NETWORK_MSG, WC_NONE, 0, _nested_chat_window_widgets, lengthof(_nested_chat_window_widgets) ); /** * Show the chat window. * @param type The type of destination. * @param dest The actual destination index. */ void ShowNetworkChatQueryWindow(DestType type, int dest) { DeleteWindowByClass(WC_SEND_NETWORK_MSG); new NetworkChatWindow(&_chat_window_desc, type, dest); } #endif /* ENABLE_NETWORK */ openttd-1.5.3/src/network/network_gamelist.h0000644000000000000000000000317612627373441017722 0ustar rootroot/* $Id: network_gamelist.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 network_gamelist.h Handling of the list of games. */ #ifndef NETWORK_GAMELIST_H #define NETWORK_GAMELIST_H #include "core/address.h" #include "network_type.h" /** Structure with information shown in the game list (GUI) */ struct NetworkGameList { NetworkGameInfo info; ///< The game information of this server NetworkAddress address; ///< The connection info of the game server bool online; ///< False if the server did not respond (default status) bool manually; ///< True if the server was added manually uint8 retries; ///< Number of retries (to stop requerying) NetworkGameList *next; ///< Next pointer to make a linked game list }; /** Game list of this client */ extern NetworkGameList *_network_game_list; void NetworkGameListAddItemDelayed(NetworkGameList *item); NetworkGameList *NetworkGameListAddItem(NetworkAddress address); void NetworkGameListRemoveItem(NetworkGameList *remove); void NetworkGameListRequery(); #endif /* NETWORK_GAMELIST_H */ openttd-1.5.3/src/debug.cpp0000644000000000000000000001507512627373442014276 0ustar rootroot/* $Id: debug.cpp 26506 2014-04-24 19:51:45Z rubidium $ */ /* * 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 debug.cpp Handling of printing debug messages. */ #include "stdafx.h" #include #include "console_func.h" #include "debug.h" #include "string_func.h" #include "fileio_func.h" #include "settings_type.h" #include #if defined(ENABLE_NETWORK) #include "network/network_admin.h" SOCKET _debug_socket = INVALID_SOCKET; #endif /* ENABLE_NETWORK */ #include "safeguards.h" int _debug_driver_level; int _debug_grf_level; int _debug_map_level; int _debug_misc_level; int _debug_net_level; int _debug_sprite_level; int _debug_oldloader_level; int _debug_npf_level; int _debug_yapf_level; int _debug_freetype_level; int _debug_script_level; int _debug_sl_level; int _debug_gamelog_level; int _debug_desync_level; int _debug_console_level; #ifdef RANDOM_DEBUG int _debug_random_level; #endif uint32 _realtime_tick = 0; struct DebugLevel { const char *name; int *level; }; #define DEBUG_LEVEL(x) { #x, &_debug_##x##_level } static const DebugLevel debug_level[] = { DEBUG_LEVEL(driver), DEBUG_LEVEL(grf), DEBUG_LEVEL(map), DEBUG_LEVEL(misc), DEBUG_LEVEL(net), DEBUG_LEVEL(sprite), DEBUG_LEVEL(oldloader), DEBUG_LEVEL(npf), DEBUG_LEVEL(yapf), DEBUG_LEVEL(freetype), DEBUG_LEVEL(script), DEBUG_LEVEL(sl), DEBUG_LEVEL(gamelog), DEBUG_LEVEL(desync), DEBUG_LEVEL(console), #ifdef RANDOM_DEBUG DEBUG_LEVEL(random), #endif }; #undef DEBUG_LEVEL /** * Dump the available debug facility names in the help text. * @param buf Start address for storing the output. * @param last Last valid address for storing the output. * @return Next free position in the output. */ char *DumpDebugFacilityNames(char *buf, char *last) { size_t length = 0; for (const DebugLevel *i = debug_level; i != endof(debug_level); ++i) { if (length == 0) { buf = strecpy(buf, "List of debug facility names:\n", last); } else { buf = strecpy(buf, ", ", last); length += 2; } buf = strecpy(buf, i->name, last); length += strlen(i->name); } if (length > 0) { buf = strecpy(buf, "\n\n", last); } return buf; } #if !defined(NO_DEBUG_MESSAGES) /** * Internal function for outputting the debug line. * @param dbg Debug category. * @param buf Text line to output. */ static void debug_print(const char *dbg, const char *buf) { #if defined(ENABLE_NETWORK) if (_debug_socket != INVALID_SOCKET) { char buf2[1024 + 32]; seprintf(buf2, lastof(buf2), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf); /* Sending out an error when this fails would be nice, however... the error * would have to be send over this failing socket which won't work. */ send(_debug_socket, buf2, (int)strlen(buf2), 0); return; } #endif /* ENABLE_NETWORK */ if (strcmp(dbg, "desync") == 0) { static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR); if (f == NULL) return; fprintf(f, "%s%s\n", GetLogPrefix(), buf); fflush(f); #ifdef RANDOM_DEBUG } else if (strcmp(dbg, "random") == 0) { static FILE *f = FioFOpenFile("random-out.log", "wb", AUTOSAVE_DIR); if (f == NULL) return; fprintf(f, "%s\n", buf); fflush(f); #endif } else { char buffer[512]; seprintf(buffer, lastof(buffer), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf); #if defined(WINCE) NKDbgPrintfW(OTTD2FS(buffer)); #elif defined(WIN32) || defined(WIN64) _fputts(OTTD2FS(buffer, true), stderr); #else fputs(buffer, stderr); #endif #ifdef ENABLE_NETWORK NetworkAdminConsole(dbg, buf); #endif /* ENABLE_NETWORK */ IConsoleDebug(dbg, buf); } } /** * Output a debug line. * @note Do not call directly, use the #DEBUG macro instead. * @param dbg Debug category. * @param format Text string a la printf, with optional arguments. */ void CDECL debug(const char *dbg, const char *format, ...) { char buf[1024]; va_list va; va_start(va, format); vseprintf(buf, lastof(buf), format, va); va_end(va); debug_print(dbg, buf); } #endif /* NO_DEBUG_MESSAGES */ /** * Set debugging levels by parsing the text in \a s. * For setting individual levels a string like \c "net=3,grf=6" should be used. * If the string starts with a number, the number is used as global debugging level. * @param s Text describing the wanted debugging levels. */ void SetDebugString(const char *s) { int v; char *end; const char *t; /* global debugging level? */ if (*s >= '0' && *s <= '9') { const DebugLevel *i; v = strtoul(s, &end, 0); s = end; for (i = debug_level; i != endof(debug_level); ++i) *i->level = v; } /* individual levels */ for (;;) { const DebugLevel *i; int *p; /* skip delimiters */ while (*s == ' ' || *s == ',' || *s == '\t') s++; if (*s == '\0') break; t = s; while (*s >= 'a' && *s <= 'z') s++; /* check debugging levels */ p = NULL; for (i = debug_level; i != endof(debug_level); ++i) { if (s == t + strlen(i->name) && strncmp(t, i->name, s - t) == 0) { p = i->level; break; } } if (*s == '=') s++; v = strtoul(s, &end, 0); s = end; if (p != NULL) { *p = v; } else { ShowInfoF("Unknown debug level '%.*s'", (int)(s - t), t); return; } } } /** * Print out the current debug-level. * Just return a string with the values of all the debug categories. * @return string with debug-levels */ const char *GetDebugString() { const DebugLevel *i; static char dbgstr[150]; char dbgval[20]; memset(dbgstr, 0, sizeof(dbgstr)); i = debug_level; seprintf(dbgstr, lastof(dbgstr), "%s=%d", i->name, *i->level); for (i++; i != endof(debug_level); i++) { seprintf(dbgval, lastof(dbgval), ", %s=%d", i->name, *i->level); strecat(dbgstr, dbgval, lastof(dbgstr)); } return dbgstr; } /** * Get the prefix for logs; if show_date_in_logs is enabled it returns * the date, otherwise it returns nothing. * @return the prefix for logs (do not free), never NULL */ const char *GetLogPrefix() { static char _log_prefix[24]; if (_settings_client.gui.show_date_in_logs) { time_t cur_time = time(NULL); strftime(_log_prefix, sizeof(_log_prefix), "[%Y-%m-%d %H:%M:%S] ", localtime(&cur_time)); } else { *_log_prefix = '\0'; } return _log_prefix; } openttd-1.5.3/src/console_gui.h0000644000000000000000000000154212627373442015155 0ustar rootroot/* $Id: console_gui.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 console_gui.h GUI related functions in the console. */ #ifndef CONSOLE_GUI_H #define CONSOLE_GUI_H #include "window_type.h" void IConsoleResize(Window *w); void IConsoleSwitch(); #endif /* CONSOLE_GUI_H */ openttd-1.5.3/src/texteff.cpp0000644000000000000000000000712412627373446014655 0ustar rootroot/* $Id: texteff.cpp 27271 2015-05-08 17:30:07Z frosch $ */ /* * 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 texteff.cpp Handling of text effects. */ #include "stdafx.h" #include "texteff.hpp" #include "transparency.h" #include "strings_func.h" #include "core/smallvec_type.hpp" #include "viewport_func.h" #include "settings_type.h" #include "safeguards.h" /** Container for all information about a text effect */ struct TextEffect : public ViewportSign { uint64 params_1; ///< DParam parameter uint64 params_2; ///< second DParam parameter StringID string_id; ///< String to draw for the text effect, if INVALID_STRING_ID then it's not valid uint8 duration; ///< How long the text effect should stay, in ticks (applies only when mode == TE_RISING) TextEffectMode mode; ///< Type of text effect /** Reset the text effect */ void Reset() { this->MarkDirty(); this->width_normal = 0; this->string_id = INVALID_STRING_ID; } }; static SmallVector _text_effects; ///< Text effects are stored there /* Text Effects */ TextEffectID AddTextEffect(StringID msg, int center, int y, uint8 duration, TextEffectMode mode) { if (_game_mode == GM_MENU) return INVALID_TE_ID; TextEffectID i; for (i = 0; i < _text_effects.Length(); i++) { if (_text_effects[i].string_id == INVALID_STRING_ID) break; } if (i == _text_effects.Length()) _text_effects.Append(); TextEffect *te = _text_effects.Get(i); /* Start defining this object */ te->string_id = msg; te->duration = duration; te->params_1 = GetDParam(0); te->params_2 = GetDParam(1); te->mode = mode; /* Make sure we only dirty the new area */ te->width_normal = 0; te->UpdatePosition(center, y, msg); return i; } void UpdateTextEffect(TextEffectID te_id, StringID msg) { /* Update details */ TextEffect *te = _text_effects.Get(te_id); if (msg == te->string_id && GetDParam(0) == te->params_1) return; te->string_id = msg; te->params_1 = GetDParam(0); te->params_2 = GetDParam(1); te->UpdatePosition(te->center, te->top, msg); } void RemoveTextEffect(TextEffectID te_id) { _text_effects[te_id].Reset(); } void MoveAllTextEffects() { const TextEffect *end = _text_effects.End(); for (TextEffect *te = _text_effects.Begin(); te != end; te++) { if (te->string_id == INVALID_STRING_ID) continue; if (te->mode != TE_RISING) continue; if (te->duration-- == 0) { te->Reset(); continue; } te->MarkDirty(ZOOM_LVL_OUT_8X); te->top -= ZOOM_LVL_BASE; te->MarkDirty(ZOOM_LVL_OUT_8X); } } void InitTextEffects() { _text_effects.Reset(); } void DrawTextEffects(DrawPixelInfo *dpi) { /* Don't draw the text effects when zoomed out a lot */ if (dpi->zoom > ZOOM_LVL_OUT_8X) return; const TextEffect *end = _text_effects.End(); for (TextEffect *te = _text_effects.Begin(); te != end; te++) { if (te->string_id == INVALID_STRING_ID) continue; if (te->mode == TE_RISING || (_settings_client.gui.loading_indicators && !IsTransparencySet(TO_LOADING))) { ViewportAddString(dpi, ZOOM_LVL_OUT_8X, te, te->string_id, te->string_id - 1, STR_NULL, te->params_1, te->params_2); } } } openttd-1.5.3/src/newgrf_class.h0000644000000000000000000000501412627373435015324 0ustar rootroot/* $Id: newgrf_class.h 24170 2012-04-22 16:28:32Z frosch $ */ /* * 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 newgrf_class.h Header file for classes to be used by e.g. NewGRF stations and airports */ #ifndef NEWGRF_CLASS_H #define NEWGRF_CLASS_H #include "strings_type.h" /** * Struct containing information relating to NewGRF classes for stations and airports. */ template struct NewGRFClass { private: uint count; ///< Number of specs in this class. uint ui_count; ///< Number of specs in this class potentially available to the user. Tspec **spec; ///< Array of specifications. /** * The actual classes. * @note We store pointers to membes of this array in various places outside this class (e.g. to 'name' for GRF string resolving). * Thus this must be a static array, and cannot be a self-resizing SmallVector or similar. */ static NewGRFClass classes[Tmax]; void ResetClass(); /** Initialise the defaults. */ static void InsertDefaults(); public: uint32 global_id; ///< Global ID for class, e.g. 'DFLT', 'WAYP', etc. StringID name; ///< Name of this class. void Insert(Tspec *spec); /** Get the number of allocated specs within the class. */ uint GetSpecCount() const { return this->count; } /** Get the number of potentially user-available specs within the class. */ uint GetUISpecCount() const { return this->ui_count; } int GetUIFromIndex(int index) const; int GetIndexFromUI(int ui_index) const; const Tspec *GetSpec(uint index) const; /** Check whether the spec will be available to the user at some point in time. */ bool IsUIAvailable(uint index) const; static void Reset(); static Tid Allocate(uint32 global_id); static void Assign(Tspec *spec); static uint GetClassCount(); static uint GetUIClassCount(); static Tid GetUIClass(uint index); static NewGRFClass *Get(Tid cls_id); static const Tspec *GetByGrf(uint32 grfid, byte local_id, int *index); }; #endif /* NEWGRF_CLASS_H */ openttd-1.5.3/src/roadstop_base.h0000644000000000000000000001257712627373441015505 0ustar rootroot/* $Id: roadstop_base.h 23704 2012-01-01 17:22:32Z alberth $ */ /* * 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 roadstop_base.h Base class for roadstops. */ #ifndef ROADSTOP_BASE_H #define ROADSTOP_BASE_H #include "station_type.h" #include "core/pool_type.hpp" #include "core/bitmath_func.hpp" #include "vehicle_type.h" typedef Pool RoadStopPool; extern RoadStopPool _roadstop_pool; /** A Stop for a Road Vehicle */ struct RoadStop : RoadStopPool::PoolItem<&_roadstop_pool> { enum RoadStopStatusFlags { RSSFB_BAY0_FREE = 0, ///< Non-zero when bay 0 is free RSSFB_BAY1_FREE = 1, ///< Non-zero when bay 1 is free RSSFB_BAY_COUNT = 2, ///< Max. number of bays RSSFB_BASE_ENTRY = 6, ///< Non-zero when the entries on this road stop are the primary, i.e. the ones to delete RSSFB_ENTRY_BUSY = 7, ///< Non-zero when roadstop entry is busy }; /** Container for each entry point of a drive through road stop */ struct Entry { private: int length; ///< The length of the stop in tile 'units' int occupied; ///< The amount of occupied stop in tile 'units' public: friend struct RoadStop; ///< Oh yeah, the road stop may play with me. /** Create an entry */ Entry() : length(0), occupied(0) {} /** * Get the length of this drive through stop. * @return the length in tile units. */ inline int GetLength() const { return this->length; } /** * Get the amount of occupied space in this drive through stop. * @return the occupied space in tile units. */ inline int GetOccupied() const { return this->occupied; } void Leave(const RoadVehicle *rv); void Enter(const RoadVehicle *rv); void CheckIntegrity(const RoadStop *rs) const; void Rebuild(const RoadStop *rs, int side = -1); }; TileIndex xy; ///< Position on the map byte status; ///< Current status of the Stop, @see RoadStopSatusFlag. Access using *Bay and *Busy functions. struct RoadStop *next; ///< Next stop of the given type at this station /** Initializes a RoadStop */ inline RoadStop(TileIndex tile = INVALID_TILE) : xy(tile), status((1 << RSSFB_BAY_COUNT) - 1) { } ~RoadStop(); /** * Checks whether there is a free bay in this road stop * @return is at least one bay free? */ inline bool HasFreeBay() const { return GB(this->status, 0, RSSFB_BAY_COUNT) != 0; } /** * Checks whether the given bay is free in this road stop * @param nr bay to check * @return is given bay free? */ inline bool IsFreeBay(uint nr) const { assert(nr < RSSFB_BAY_COUNT); return HasBit(this->status, nr); } /** * Checks whether the entrance of the road stop is occupied by a vehicle * @return is entrance busy? */ inline bool IsEntranceBusy() const { return HasBit(this->status, RSSFB_ENTRY_BUSY); } /** * Makes an entrance occupied or free * @param busy If true, marks busy; free otherwise. */ inline void SetEntranceBusy(bool busy) { SB(this->status, RSSFB_ENTRY_BUSY, 1, busy); } /** * Get the drive through road stop entry struct for the given direction. * @param dir The direction to get the entry for. * @return the entry */ inline const Entry *GetEntry(DiagDirection dir) const { return HasBit((int)dir, 1) ? this->west : this->east; } /** * Get the drive through road stop entry struct for the given direction. * @param dir The direction to get the entry for. * @return the entry */ inline Entry *GetEntry(DiagDirection dir) { return HasBit((int)dir, 1) ? this->west : this->east; } void MakeDriveThrough(); void ClearDriveThrough(); void Leave(RoadVehicle *rv); bool Enter(RoadVehicle *rv); RoadStop *GetNextRoadStop(const struct RoadVehicle *v) const; static RoadStop *GetByTile(TileIndex tile, RoadStopType type); static bool IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next); private: Entry *east; ///< The vehicles that entered from the east Entry *west; ///< The vehicles that entered from the west /** * Allocates a bay * @return the allocated bay number * @pre this->HasFreeBay() */ inline uint AllocateBay() { assert(this->HasFreeBay()); /* Find the first free bay. If the bit is set, the bay is free. */ uint bay_nr = 0; while (!HasBit(this->status, bay_nr)) bay_nr++; ClrBit(this->status, bay_nr); return bay_nr; } /** * Allocates a bay in a drive-through road stop * @param nr the number of the bay to allocate */ inline void AllocateDriveThroughBay(uint nr) { assert(nr < RSSFB_BAY_COUNT); ClrBit(this->status, nr); } /** * Frees the given bay * @param nr the number of the bay to free */ inline void FreeBay(uint nr) { assert(nr < RSSFB_BAY_COUNT); SetBit(this->status, nr); } }; #define FOR_ALL_ROADSTOPS_FROM(var, start) FOR_ALL_ITEMS_FROM(RoadStop, roadstop_index, var, start) #define FOR_ALL_ROADSTOPS(var) FOR_ALL_ROADSTOPS_FROM(var, 0) #endif /* ROADSTOP_BASE_H */ openttd-1.5.3/src/tunnel_map.cpp0000644000000000000000000000441412627373435015347 0ustar rootroot/* $Id: tunnel_map.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tunnel_map.cpp Map accessors for tunnels. */ #include "stdafx.h" #include "tunnelbridge_map.h" #include "safeguards.h" /** * Gets the other end of the tunnel. Where a vehicle would reappear when it * enters at the given tile. * @param tile the tile to search from. * @return the tile of the other end of the tunnel. */ TileIndex GetOtherTunnelEnd(TileIndex tile) { DiagDirection dir = GetTunnelBridgeDirection(tile); TileIndexDiff delta = TileOffsByDiagDir(dir); int z = GetTileZ(tile); dir = ReverseDiagDir(dir); do { tile += delta; } while ( !IsTunnelTile(tile) || GetTunnelBridgeDirection(tile) != dir || GetTileZ(tile) != z ); return tile; } /** * Is there a tunnel in the way in the given direction? * @param tile the tile to search from. * @param z the 'z' to search on. * @param dir the direction to start searching to. * @return true if and only if there is a tunnel. */ bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir) { TileIndexDiff delta = TileOffsByDiagDir(dir); int height; do { tile -= delta; if (!IsValidTile(tile)) return false; height = GetTileZ(tile); } while (z < height); return z == height && IsTunnelTile(tile) && GetTunnelBridgeDirection(tile) == dir; } /** * Is there a tunnel in the way in any direction? * @param tile the tile to search from. * @param z the 'z' to search on. * @return true if and only if there is a tunnel. */ bool IsTunnelInWay(TileIndex tile, int z) { return IsTunnelInWayDir(tile, z, (TileX(tile) > (MapMaxX() / 2)) ? DIAGDIR_NE : DIAGDIR_SW) || IsTunnelInWayDir(tile, z, (TileY(tile) > (MapMaxY() / 2)) ? DIAGDIR_NW : DIAGDIR_SE); } openttd-1.5.3/src/sdl.h0000644000000000000000000000554712627373446013446 0ustar rootroot/* $Id: sdl.h 24993 2013-02-14 11:06:12Z matthijs $ */ /* * 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 sdl.h SDL support. */ #ifndef SDL_H #define SDL_H const char *SdlOpen(uint32 x); void SdlClose(uint32 x); #ifdef WIN32 #define DYNAMICALLY_LOADED_SDL #endif #ifdef DYNAMICALLY_LOADED_SDL #include struct SDLProcs { int (SDLCALL *SDL_Init)(Uint32); int (SDLCALL *SDL_InitSubSystem)(Uint32); char *(SDLCALL *SDL_GetError)(); void (SDLCALL *SDL_QuitSubSystem)(Uint32); void (SDLCALL *SDL_UpdateRect)(SDL_Surface *, Sint32, Sint32, Uint32, Uint32); void (SDLCALL *SDL_UpdateRects)(SDL_Surface *, int, SDL_Rect *); int (SDLCALL *SDL_SetColors)(SDL_Surface *, SDL_Color *, int, int); void (SDLCALL *SDL_WM_SetCaption)(const char *, const char *); int (SDLCALL *SDL_ShowCursor)(int); void (SDLCALL *SDL_FreeSurface)(SDL_Surface *); int (SDLCALL *SDL_PollEvent)(SDL_Event *); void (SDLCALL *SDL_WarpMouse)(Uint16, Uint16); uint32 (SDLCALL *SDL_GetTicks)(); int (SDLCALL *SDL_OpenAudio)(SDL_AudioSpec *, SDL_AudioSpec*); void (SDLCALL *SDL_PauseAudio)(int); void (SDLCALL *SDL_CloseAudio)(); int (SDLCALL *SDL_LockSurface)(SDL_Surface*); void (SDLCALL *SDL_UnlockSurface)(SDL_Surface*); SDLMod (SDLCALL *SDL_GetModState)(); void (SDLCALL *SDL_Delay)(Uint32); void (SDLCALL *SDL_Quit)(); SDL_Surface *(SDLCALL *SDL_SetVideoMode)(int, int, int, Uint32); int (SDLCALL *SDL_EnableKeyRepeat)(int, int); void (SDLCALL *SDL_EnableUNICODE)(int); void (SDLCALL *SDL_VideoDriverName)(char *, int); SDL_Rect **(SDLCALL *SDL_ListModes)(void *, int); Uint8 *(SDLCALL *SDL_GetKeyState)(int *); SDL_Surface *(SDLCALL *SDL_LoadBMP_RW)(SDL_RWops *, int); SDL_RWops *(SDLCALL *SDL_RWFromFile)(const char *, const char *); int (SDLCALL *SDL_SetColorKey)(SDL_Surface *, Uint32, Uint32); void (SDLCALL *SDL_WM_SetIcon)(SDL_Surface *, Uint8 *); Uint32 (SDLCALL *SDL_MapRGB)(SDL_PixelFormat *, Uint8, Uint8, Uint8); int (SDLCALL *SDL_VideoModeOK)(int, int, int, Uint32); SDL_version *(SDLCALL *SDL_Linked_Version)(); int (SDLCALL *SDL_BlitSurface)(SDL_Surface *, SDL_Rect *, SDL_Surface *, SDL_Rect *); SDL_Surface *(SDLCALL *SDL_CreateRGBSurface)(Uint32, int, int, int, Uint32, Uint32, Uint32, Uint32); }; extern SDLProcs sdl_proc; #define SDL_CALL sdl_proc. #else #define SDL_CALL #endif #endif /* SDL_H */ openttd-1.5.3/src/newgrf_spritegroup.h0000644000000000000000000002634012627373441016604 0ustar rootroot/* $Id: newgrf_spritegroup.h 26388 2014-03-03 20:02:31Z frosch $ */ /* * 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 newgrf_spritegroup.h Action 2 handling. */ #ifndef NEWGRF_SPRITEGROUP_H #define NEWGRF_SPRITEGROUP_H #include "town_type.h" #include "engine_type.h" #include "house_type.h" #include "newgrf_callbacks.h" #include "newgrf_generic.h" #include "newgrf_storage.h" #include "newgrf_commons.h" /** * Gets the value of a so-called newgrf "register". * @param i index of the register * @pre i < 0x110 * @return the value of the register */ static inline uint32 GetRegister(uint i) { extern TemporaryStorageArray _temp_store; return _temp_store.GetValue(i); } /* List of different sprite group types */ enum SpriteGroupType { SGT_REAL, SGT_DETERMINISTIC, SGT_RANDOMIZED, SGT_CALLBACK, SGT_RESULT, SGT_TILELAYOUT, SGT_INDUSTRY_PRODUCTION, }; struct SpriteGroup; typedef uint32 SpriteGroupID; struct ResolverObject; /* SPRITE_WIDTH is 24. ECS has roughly 30 sprite groups per real sprite. * Adding an 'extra' margin would be assuming 64 sprite groups per real * sprite. 64 = 2^6, so 2^30 should be enough (for now) */ typedef Pool SpriteGroupPool; extern SpriteGroupPool _spritegroup_pool; /* Common wrapper for all the different sprite group types */ struct SpriteGroup : SpriteGroupPool::PoolItem<&_spritegroup_pool> { protected: SpriteGroup(SpriteGroupType type) : type(type) {} /** Base sprite group resolver */ virtual const SpriteGroup *Resolve(ResolverObject &object) const { return this; }; public: virtual ~SpriteGroup() {} SpriteGroupType type; virtual SpriteID GetResult() const { return 0; } virtual byte GetNumResults() const { return 0; } virtual uint16 GetCallbackResult() const { return CALLBACK_FAILED; } static const SpriteGroup *Resolve(const SpriteGroup *group, ResolverObject &object, bool top_level = true); }; /* 'Real' sprite groups contain a list of other result or callback sprite * groups. */ struct RealSpriteGroup : SpriteGroup { RealSpriteGroup() : SpriteGroup(SGT_REAL) {} ~RealSpriteGroup(); /* Loaded = in motion, loading = not moving * Each group contains several spritesets, for various loading stages */ /* XXX: For stations the meaning is different - loaded is for stations * with small amount of cargo whilst loading is for stations with a lot * of da stuff. */ byte num_loaded; ///< Number of loaded groups byte num_loading; ///< Number of loading groups const SpriteGroup **loaded; ///< List of loaded groups (can be SpriteIDs or Callback results) const SpriteGroup **loading; ///< List of loading groups (can be SpriteIDs or Callback results) protected: const SpriteGroup *Resolve(ResolverObject &object) const; }; /* Shared by deterministic and random groups. */ enum VarSpriteGroupScope { VSG_BEGIN, VSG_SCOPE_SELF = VSG_BEGIN, ///< Resolved object itself VSG_SCOPE_PARENT, ///< Related object of the resolved one VSG_SCOPE_RELATIVE, ///< Relative position (vehicles only) VSG_END }; DECLARE_POSTFIX_INCREMENT(VarSpriteGroupScope) enum DeterministicSpriteGroupSize { DSG_SIZE_BYTE, DSG_SIZE_WORD, DSG_SIZE_DWORD, }; enum DeterministicSpriteGroupAdjustType { DSGA_TYPE_NONE, DSGA_TYPE_DIV, DSGA_TYPE_MOD, }; enum DeterministicSpriteGroupAdjustOperation { DSGA_OP_ADD, ///< a + b DSGA_OP_SUB, ///< a - b DSGA_OP_SMIN, ///< (signed) min(a, b) DSGA_OP_SMAX, ///< (signed) max(a, b) DSGA_OP_UMIN, ///< (unsigned) min(a, b) DSGA_OP_UMAX, ///< (unsigned) max(a, b) DSGA_OP_SDIV, ///< (signed) a / b DSGA_OP_SMOD, ///< (signed) a % b DSGA_OP_UDIV, ///< (unsigned) a / b DSGA_OP_UMOD, ///< (unsigned) a & b DSGA_OP_MUL, ///< a * b DSGA_OP_AND, ///< a & b DSGA_OP_OR, ///< a | b DSGA_OP_XOR, ///< a ^ b DSGA_OP_STO, ///< store a into temporary storage, indexed by b. return a DSGA_OP_RST, ///< return b DSGA_OP_STOP, ///< store a into persistent storage, indexed by b, return a DSGA_OP_ROR, ///< rotate a b positions to the right DSGA_OP_SCMP, ///< (signed) comparison (a < b -> 0, a == b = 1, a > b = 2) DSGA_OP_UCMP, ///< (unsigned) comparison (a < b -> 0, a == b = 1, a > b = 2) DSGA_OP_SHL, ///< a << b DSGA_OP_SHR, ///< (unsigned) a >> b DSGA_OP_SAR, ///< (signed) a >> b }; struct DeterministicSpriteGroupAdjust { DeterministicSpriteGroupAdjustOperation operation; DeterministicSpriteGroupAdjustType type; byte variable; byte parameter; ///< Used for variables between 0x60 and 0x7F inclusive. byte shift_num; uint32 and_mask; uint32 add_val; uint32 divmod_val; const SpriteGroup *subroutine; }; struct DeterministicSpriteGroupRange { const SpriteGroup *group; uint32 low; uint32 high; }; struct DeterministicSpriteGroup : SpriteGroup { DeterministicSpriteGroup() : SpriteGroup(SGT_DETERMINISTIC) {} ~DeterministicSpriteGroup(); VarSpriteGroupScope var_scope; DeterministicSpriteGroupSize size; uint num_adjusts; byte num_ranges; DeterministicSpriteGroupAdjust *adjusts; DeterministicSpriteGroupRange *ranges; // Dynamically allocated /* Dynamically allocated, this is the sole owner */ const SpriteGroup *default_group; protected: const SpriteGroup *Resolve(ResolverObject &object) const; }; enum RandomizedSpriteGroupCompareMode { RSG_CMP_ANY, RSG_CMP_ALL, }; struct RandomizedSpriteGroup : SpriteGroup { RandomizedSpriteGroup() : SpriteGroup(SGT_RANDOMIZED) {} ~RandomizedSpriteGroup(); VarSpriteGroupScope var_scope; ///< Take this object: RandomizedSpriteGroupCompareMode cmp_mode; ///< Check for these triggers: byte triggers; byte count; byte lowest_randbit; ///< Look for this in the per-object randomized bitmask: byte num_groups; ///< must be power of 2 const SpriteGroup **groups; ///< Take the group with appropriate index: protected: const SpriteGroup *Resolve(ResolverObject &object) const; }; /* This contains a callback result. A failed callback has a value of * CALLBACK_FAILED */ struct CallbackResultSpriteGroup : SpriteGroup { /** * Creates a spritegroup representing a callback result * @param value The value that was used to represent this callback result * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8. */ CallbackResultSpriteGroup(uint16 value, bool grf_version8) : SpriteGroup(SGT_CALLBACK), result(value) { /* Old style callback results (only valid for version < 8) have the highest byte 0xFF so signify it is a callback result. * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */ if (!grf_version8 && (this->result >> 8) == 0xFF) { this->result &= ~0xFF00; } else { this->result &= ~0x8000; } } uint16 result; uint16 GetCallbackResult() const { return this->result; } }; /* A result sprite group returns the first SpriteID and the number of * sprites in the set */ struct ResultSpriteGroup : SpriteGroup { /** * Creates a spritegroup representing a sprite number result. * @param sprite The sprite number. * @param num_sprites The number of sprites per set. * @return A spritegroup representing the sprite number result. */ ResultSpriteGroup(SpriteID sprite, byte num_sprites) : SpriteGroup(SGT_RESULT), sprite(sprite), num_sprites(num_sprites) { } SpriteID sprite; byte num_sprites; SpriteID GetResult() const { return this->sprite; } byte GetNumResults() const { return this->num_sprites; } }; /** * Action 2 sprite layout for houses, industry tiles, objects and airport tiles. */ struct TileLayoutSpriteGroup : SpriteGroup { TileLayoutSpriteGroup() : SpriteGroup(SGT_TILELAYOUT) {} ~TileLayoutSpriteGroup() {} NewGRFSpriteLayout dts; const DrawTileSprites *ProcessRegisters(uint8 *stage) const; }; struct IndustryProductionSpriteGroup : SpriteGroup { IndustryProductionSpriteGroup() : SpriteGroup(SGT_INDUSTRY_PRODUCTION) {} uint8 version; int16 subtract_input[3]; // signed uint16 add_output[2]; // unsigned uint8 again; }; /** * Interface to query and set values specific to a single #VarSpriteGroupScope (action 2 scope). * * Multiple of these interfaces are combined into a #ResolverObject to allow access * to different game entities from a #SpriteGroup-chain (action 1-2-3 chain). */ struct ScopeResolver { ResolverObject &ro; ///< Surrounding resolver object. ScopeResolver(ResolverObject &ro); virtual ~ScopeResolver(); virtual uint32 GetRandomBits() const; virtual uint32 GetTriggers() const; virtual void SetTriggers(int triggers) const; virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; virtual void StorePSA(uint reg, int32 value); }; /** * Interface for #SpriteGroup-s to access the gamestate. * * Using this interface #SpriteGroup-chains (action 1-2-3 chains) can be resolved, * to get the results of callbacks, rerandomisations or normal sprite lookups. */ struct ResolverObject { ResolverObject(const GRFFile *grffile, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); virtual ~ResolverObject(); ScopeResolver default_scope; ///< Default implementation of the grf scope. CallbackID callback; ///< Callback being resolved. uint32 callback_param1; ///< First parameter (var 10) of the callback. uint32 callback_param2; ///< Second parameter (var 18) of the callback. byte trigger; uint32 last_value; ///< Result of most recent DeterministicSpriteGroup (including procedure calls) uint32 reseed[VSG_END]; ///< Collects bits to rerandomise while triggering triggers. const GRFFile *grffile; ///< GRFFile the resolved SpriteGroup belongs to const SpriteGroup *root_spritegroup; ///< Root SpriteGroup to use for resolving /** * Resolve SpriteGroup. * @return Result spritegroup. */ const SpriteGroup *Resolve() { return SpriteGroup::Resolve(this->root_spritegroup, *this); } /** * Resolve callback. * @return Callback result. */ uint16 ResolveCallback() { const SpriteGroup *result = Resolve(); return result != NULL ? result->GetCallbackResult() : CALLBACK_FAILED; } virtual const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; virtual ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0); /** * Returns the OR-sum of all bits that need reseeding * independent of the scope they were accessed with. * @return OR-sum of the bits. */ uint32 GetReseedSum() const { uint32 sum = 0; for (VarSpriteGroupScope vsg = VSG_BEGIN; vsg < VSG_END; vsg++) { sum |= this->reseed[vsg]; } return sum; } /** * Resets the dynamic state of the resolver object. * To be called before resolving an Action-1-2-3 chain. */ void ResetState() { this->last_value = 0; this->trigger = 0; memset(this->reseed, 0, sizeof(this->reseed)); } }; #endif /* NEWGRF_SPRITEGROUP_H */ openttd-1.5.3/src/depend/0000755000000000000000000000000012627373442013733 5ustar rootrootopenttd-1.5.3/src/depend/depend.cpp0000644000000000000000000007466012627373442015713 0ustar rootroot/* $Id: depend.cpp 26060 2013-11-23 13:16:45Z rubidium $ */ /* * 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 depend/depend.cpp Custom implementation of Makedepend. * * We previously used makedepend, but that could not handle the amount of * files we have and does not handle conditional includes in a sane manner. * This caused many link problems because not enough files were recompiled. * This has lead to the development of our own dependency generator. It is * meant to be a substitute to the (relatively slow) dependency generation * via gcc. It thus helps speeding up compilation. It will also ignore * system headers making it less error prone when system headers are moved * or renamed. */ #include #include #include #include #include #include #include #include #include #include /** * Return the length of an fixed size array. * Unlike sizeof this function returns the number of elements * of the given type. * * @param x The pointer to the first element of the array * @return The number of elements */ #define lengthof(x) (sizeof(x) / sizeof(x[0])) /** * Get the last element of an fixed size array. * * @param x The pointer to the first element of the array * @return The pointer to the last element of the array */ #define lastof(x) (&x[lengthof(x) - 1]) /** * Copies characters from one buffer to another. * * Copies the source string to the destination buffer with respect of the * terminating null-character and the last pointer to the last element in * the destination buffer. If the last pointer is set to NULL no boundary * check is performed. * * @note usage: strecpy(dst, src, lastof(dst)); * @note lastof() applies only to fixed size arrays * * @param dst The destination buffer * @param src The buffer containing the string to copy * @param last The pointer to the last element of the destination buffer * @return The pointer to the terminating null-character in the destination buffer */ char *strecpy(char *dst, const char *src, const char *last) { assert(dst <= last); while (dst != last && *src != '\0') { *dst++ = *src++; } *dst = '\0'; if (dst == last && *src != '\0') { fprintf(stderr, "String too long for destination buffer\n"); exit(-3); } return dst; } /** * Appends characters from one string to another. * * Appends the source string to the destination string with respect of the * terminating null-character and and the last pointer to the last element * in the destination buffer. If the last pointer is set to NULL no * boundary check is performed. * * @note usage: strecat(dst, src, lastof(dst)); * @note lastof() applies only to fixed size arrays * * @param dst The buffer containing the target string * @param src The buffer containing the string to append * @param last The pointer to the last element of the destination buffer * @return The pointer to the terminating null-character in the destination buffer */ static char *strecat(char *dst, const char *src, const char *last) { assert(dst <= last); while (*dst != '\0') { if (dst == last) return dst; dst++; } return strecpy(dst, src, last); } /** * Version of the standard free that accepts const pointers. * @param ptr The data to free. */ static inline void free(const void *ptr) { free(const_cast(ptr)); } #ifndef PATH_MAX /** The maximum length of paths, if we don't know it. */ # define PATH_MAX 260 #endif /** Simple string comparator using strcmp as implementation */ struct StringCompare { /** * Compare a to b using strcmp. * @param a string to compare. * @param b string to compare. * @return whether a is less than b. */ bool operator () (const char *a, const char *b) const { return strcmp(a, b) < 0; } }; /** Set of C-style strings. */ typedef std::set StringSet; /** Mapping of C-style string to a set of C-style strings. */ typedef std::map StringMap; /** Pair of C-style string and a set of C-style strings. */ typedef std::pair StringMapItem; /** Include directory to search in. */ static StringSet _include_dirs; /** Files that have been parsed/handled with their dependencies. */ static StringMap _files; /** Dependencies of headers. */ static StringMap _headers; /** The current 'active' defines. */ static StringSet _defines; /** * Helper class to read a file. */ class File { public: /** * Create the helper by opening the given file. * @param filename the file to open * @post the file is open; otherwise the application is killed. */ File(const char *filename) { this->fp = fopen(filename, "r"); if (this->fp == NULL) { fprintf(stdout, "Could not open %s for reading\n", filename); exit(1); } this->dirname = strdup(filename); char *last = strrchr(this->dirname, '/'); if (last != NULL) { *last = '\0'; } else { *this->dirname = '\0'; } } /** Free everything we have allocated. */ ~File() { fclose(this->fp); free(this->dirname); } /** * Get a single character from the file. * If we are reading beyond the end of the file '\0' is returned. * @return the read character. */ char GetChar() const { int c = fgetc(this->fp); return (c == EOF) ? '\0' : c; } /** * Get the directory name of the file. * @return the directory name. */ const char *GetDirname() const { return this->dirname; } private: FILE *fp; ///< The currently opened file. char *dirname; ///< The directory of the file. }; /** A token returned by the tokenizer. */ enum Token { TOKEN_UNKNOWN, ///< Unknown token TOKEN_END, ///< End of document TOKEN_EOL, ///< End of line TOKEN_SHARP, ///< # character, usually telling something important comes. TOKEN_LOCAL, ///< Read a local include TOKEN_GLOBAL, ///< Read a global include TOKEN_IDENTIFIER, ///< Identifier within the data. TOKEN_DEFINE, ///< (#)define in code TOKEN_IF, ///< (#)if in code TOKEN_IFDEF, ///< (#)ifdef in code TOKEN_IFNDEF, ///< (#)ifndef in code TOKEN_ELIF, ///< (#)elif in code TOKEN_ELSE, ///< (#)else in code TOKEN_ENDIF, ///< (#)endif in code TOKEN_UNDEF, ///< (#)undef in code TOKEN_OR, ///< '||' within #if expression TOKEN_AND, ///< '&&' within #if expression TOKEN_DEFINED, ///< 'defined' within #if expression TOKEN_OPEN, ///< '(' within #if expression TOKEN_CLOSE, ///< ')' within #if expression TOKEN_NOT, ///< '!' within #if expression TOKEN_ZERO, ///< '0' within #if expression TOKEN_INCLUDE, ///< (#)include in code }; /** Mapping from a C-style keyword representation to a Token. */ typedef std::map KeywordList; /** * Lexer of a file. */ class Lexer { public: /** * Create the lexer and fill the keywords table. * @param file the file to read from. */ Lexer(const File *file) : file(file), current_char('\0'), string(NULL), token(TOKEN_UNKNOWN) { this->keywords["define"] = TOKEN_DEFINE; this->keywords["defined"] = TOKEN_DEFINED; this->keywords["if"] = TOKEN_IF; this->keywords["ifdef"] = TOKEN_IFDEF; this->keywords["ifndef"] = TOKEN_IFNDEF; this->keywords["include"] = TOKEN_INCLUDE; this->keywords["elif"] = TOKEN_ELIF; this->keywords["else"] = TOKEN_ELSE; this->keywords["endif"] = TOKEN_ENDIF; this->keywords["undef"] = TOKEN_UNDEF; /* Initialise currently read character. */ this->Next(); /* Allocate the buffer. */ this->buf_len = 32; this->buf = (char*)malloc(sizeof(*this->buf) * this->buf_len); } /** Free everything */ ~Lexer() { free(this->buf); } /** * Read the next character into 'current_char'. */ void Next() { this->current_char = this->file->GetChar(); } /** * Get the current token. * @return the token. */ Token GetToken() const { return this->token; } /** * Read the currenty processed string. * @return the string, can be NULL. */ const char *GetString() const { return this->string; } /** * Perform the lexing/tokenizing of the file till we can return something * that must be parsed. */ void Lex() { for (;;) { free(this->string); this->string = NULL; this->token = TOKEN_UNKNOWN; switch (this->current_char) { /* '\0' means End-Of-File */ case '\0': this->token = TOKEN_END; return; /* Skip some chars, as they don't do anything */ case '\t': this->Next(); break; case '\r': this->Next(); break; case ' ': this->Next(); break; case '\\': this->Next(); if (this->current_char == '\n') this->Next(); break; case '\n': this->token = TOKEN_EOL; this->Next(); return; case '#': this->token = TOKEN_SHARP; this->Next(); return; case '"': this->ReadString('"', TOKEN_LOCAL); this->Next(); return; case '<': this->ReadString('>', TOKEN_GLOBAL); this->Next(); return; case '&': this->Next(); if (this->current_char == '&') { this->Next(); this->token = TOKEN_AND; return; } break; case '|': this->Next(); if (this->current_char == '|') { this->Next(); this->token = TOKEN_OR; return; } break; case '(': this->Next(); this->token = TOKEN_OPEN; return; case ')': this->Next(); this->token = TOKEN_CLOSE; return; case '!': this->Next(); if (this->current_char != '=') { this->token = TOKEN_NOT; return; } break; /* Possible begin of comment */ case '/': this->Next(); switch (this->current_char) { case '*': { this->Next(); char previous_char = '\0'; while ((this->current_char != '/' || previous_char != '*') && this->current_char != '\0') { previous_char = this->current_char; this->Next(); } this->Next(); break; } case '/': while (this->current_char != '\n' && this->current_char != '\0') this->Next(); break; default: break; } break; default: if (isalpha(this->current_char) || this->current_char == '_') { /* If the name starts with a letter, it is an identifier */ this->ReadIdentifier(); return; } if (isdigit(this->current_char)) { bool zero = this->current_char == '0'; this->Next(); if (this->current_char == 'x' || this->current_char == 'X') Next(); while (isdigit(this->current_char) || this->current_char == '.' || (this->current_char >= 'a' && this->current_char <= 'f') || (this->current_char >= 'A' && this->current_char <= 'F')) { zero &= this->current_char == '0'; this->Next(); } if (zero) this->token = TOKEN_ZERO; return; } this->Next(); break; } } } private: /** * The token based on keyword with a given name. * @param name the actual keyword. * @return the token of the keyword. */ Token FindKeyword(const char *name) const { KeywordList::const_iterator it = this->keywords.find(name); if (it == this->keywords.end()) return TOKEN_IDENTIFIER; return (*it).second; } /** * Read an identifier. */ void ReadIdentifier() { size_t count = 0; /* Read the rest of the identifier */ do { this->buf[count++] = this->current_char; this->Next(); if (count >= buf_len) { /* Scale the buffer if required */ this->buf_len *= 2; this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len); } } while ((isalpha(this->current_char) || this->current_char == '_' || isdigit(this->current_char))); this->buf[count] = '\0'; free(this->string); this->string = strdup(this->buf); this->token = FindKeyword(this->string); } /** * Read a string up to a given character, then set the given token. * @param end the 'marker' for the end of the string. * @param token the token to set after returning. */ void ReadString(char end, Token token) { size_t count = 0; this->Next(); while (this->current_char != end && this->current_char != ')' && this->current_char != '\n' && this->current_char != '\0') { this->buf[count++] = this->current_char; this->Next(); if (count >= this->buf_len) { /* Scale the buffer if required */ this->buf_len *= 2; this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len); } } this->buf[count] = '\0'; free(this->string); this->string = strdup(this->buf); this->token = token; } const File *file; ///< The file to read from. char current_char; ///< The current character to process. char *string; ///< Currently processed string. Token token; ///< The current token to process. char *buf; ///< Temporary buffer. size_t buf_len; ///< Length of the temporary buffer. KeywordList keywords; ///< All keywords we know of. }; /** * Generate a path from a directory name and a relative filename. * If the file is not local the include directory names will be used instead * of the passed parameter with directory name. If the file is local both will * be queried where the parameter takes precedence. * @param dirname the directory to look in. * @param filename the file to look for. * @param local whether to look locally (in dirname) for the file. * @return the absolute path, or NULL if the file doesn't exist. */ const char *GeneratePath(const char *dirname, const char *filename, bool local) { if (local) { if (access(filename, R_OK) == 0) return strdup(filename); char path[PATH_MAX]; strecpy(path, dirname, lastof(path)); const char *p = filename; /* Remove '..' from the begin of the filename. */ while (*p == '.') { if (*(++p) == '.') { char *s = strrchr(path, '/'); if (s != NULL) *s = '\0'; p += 2; } } strecat(path, "/", lastof(path)); strecat(path, p, lastof(path)); if (access(path, R_OK) == 0) return strdup(path); } for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) { char path[PATH_MAX]; strecpy(path, *it, lastof(path)); const char *p = filename; /* Remove '..' from the begin of the filename. */ while (*p == '.') { if (*(++p) == '.') { char *s = strrchr(path, '/'); if (s != NULL) *s = '\0'; p += 2; } } strecat(path, "/", lastof(path)); strecat(path, p, lastof(path)); if (access(path, R_OK) == 0) return strdup(path); } return NULL; } /** * Try to parse a 'defined(expr)' expression. * @param lexer the lexer to get tokens from. * @param defines the set of known defines. * @param verbose whether to give verbose debugging information. * @return the value of the expression. */ bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose); /** * Try to parse a 'expr || expr' expression. * @param lexer the lexer to get tokens from. * @param defines the set of known defines. * @param verbose whether to give verbose debugging information. * @return the value of the expression. */ bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose); /** * Try to parse a '!expr' expression. Also parses the '(expr)', '0' and * identifiers. Finally it also consumes any unknown tokens. * @param lexer the lexer to get tokens from. * @param defines the set of known defines. * @param verbose whether to give verbose debugging information. * @return the value of the expression. */ bool ExpressionNot(Lexer *lexer, StringSet *defines, bool verbose) { if (lexer->GetToken() == TOKEN_NOT) { if (verbose) fprintf(stderr, "!"); lexer->Lex(); bool value = !ExpressionDefined(lexer, defines, verbose); if (verbose) fprintf(stderr, "[%d]", value); return value; } if (lexer->GetToken() == TOKEN_OPEN) { if (verbose) fprintf(stderr, "("); lexer->Lex(); bool value = ExpressionOr(lexer, defines, verbose); if (verbose) fprintf(stderr, ")[%d]", value); lexer->Lex(); return value; } if (lexer->GetToken() == TOKEN_ZERO) { if (verbose) fprintf(stderr, "0"); lexer->Lex(); if (verbose) fprintf(stderr, "[0]"); return false; } bool first = true; while (lexer->GetToken() == TOKEN_UNKNOWN || lexer->GetToken() == TOKEN_IDENTIFIER) { if (verbose && first) fprintf(stderr, ""); first = false; lexer->Lex(); } return true; } /** * Try to parse a 'defined(expr)' expression. * @param lexer the lexer to get tokens from. * @param defines the set of known defines. * @param verbose whether to give verbose debugging information. * @return the value of the expression. */ bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose) { bool value = ExpressionNot(lexer, defines, verbose); if (lexer->GetToken() != TOKEN_DEFINED) return value; lexer->Lex(); if (verbose) fprintf(stderr, "defined"); bool open = (lexer->GetToken() == TOKEN_OPEN); if (open) lexer->Lex(); if (verbose) fprintf(stderr, open ? "(" : " "); if (lexer->GetToken() == TOKEN_IDENTIFIER) { if (verbose) fprintf(stderr, "%s", lexer->GetString()); value = defines->find(lexer->GetString()) != defines->end(); } if (open) { if (verbose) fprintf(stderr, ")"); lexer->Lex(); } lexer->Lex(); if (verbose) fprintf(stderr, "[%d]", value); return value; } /** * Try to parse a 'expr && expr' expression. * @param lexer the lexer to get tokens from. * @param defines the set of known defines. * @param verbose whether to give verbose debugging information. * @return the value of the expression. */ bool ExpressionAnd(Lexer *lexer, StringSet *defines, bool verbose) { bool value = ExpressionDefined(lexer, defines, verbose); for (;;) { if (lexer->GetToken() != TOKEN_AND) return value; if (verbose) fprintf(stderr, " && "); lexer->Lex(); value = value && ExpressionDefined(lexer, defines, verbose); } } /** * Try to parse a 'expr || expr' expression. * @param lexer the lexer to get tokens from. * @param defines the set of known defines. * @param verbose whether to give verbose debugging information. * @return the value of the expression. */ bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose) { bool value = ExpressionAnd(lexer, defines, verbose); for (;;) { if (lexer->GetToken() != TOKEN_OR) return value; if (verbose) fprintf(stderr, " || "); lexer->Lex(); value = value || ExpressionAnd(lexer, defines, verbose); } } /** Enumerator to tell how long to ignore 'stuff'. */ enum Ignore { NOT_IGNORE, ///< No ignoring. IGNORE_UNTIL_ELSE, ///< Ignore till a #else is reached. IGNORE_UNTIL_ENDIF, ///< Ignore till a #endif is reached. }; /** * Scan a file for includes, defines and the lot. * @param filename the name of the file to scan. * @param ext the extension of the filename. * @param header whether the file is a header or not. * @param verbose whether to give verbose debugging information. */ void ScanFile(const char *filename, const char *ext, bool header, bool verbose) { static StringSet defines; static std::stack ignore; /* Copy in the default defines (parameters of depend) */ if (!header) { for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) { defines.insert(strdup(*it)); } } File file(filename); Lexer lexer(&file); /* Start the lexing! */ lexer.Lex(); while (lexer.GetToken() != TOKEN_END) { switch (lexer.GetToken()) { /* We reached the end of the file... yay, we're done! */ case TOKEN_END: break; /* The line started with a # (minus whitespace) */ case TOKEN_SHARP: lexer.Lex(); switch (lexer.GetToken()) { case TOKEN_INCLUDE: if (verbose) fprintf(stderr, "%s #include ", filename); lexer.Lex(); switch (lexer.GetToken()) { case TOKEN_LOCAL: case TOKEN_GLOBAL: { if (verbose) fprintf(stderr, "%s", lexer.GetString()); if (!ignore.empty() && ignore.top() != NOT_IGNORE) { if (verbose) fprintf(stderr, " (ignored)"); break; } const char *h = GeneratePath(file.GetDirname(), lexer.GetString(), lexer.GetToken() == TOKEN_LOCAL); if (h != NULL) { StringMap::iterator it = _headers.find(h); if (it == _headers.end()) { it = (_headers.insert(StringMapItem(strdup(h), new StringSet()))).first; if (verbose) fprintf(stderr, "\n"); ScanFile(h, ext, true, verbose); } StringMap::iterator curfile; if (header) { curfile = _headers.find(filename); } else { /* Replace the extension with the provided extension of '.o'. */ char path[PATH_MAX]; strecpy(path, filename, lastof(path)); *(strrchr(path, '.')) = '\0'; strecat(path, ext != NULL ? ext : ".o", lastof(path)); curfile = _files.find(path); if (curfile == _files.end()) { curfile = (_files.insert(StringMapItem(strdup(path), new StringSet()))).first; } } if (it != _headers.end()) { for (StringSet::iterator header = it->second->begin(); header != it->second->end(); header++) { if (curfile->second->find(*header) == curfile->second->end()) curfile->second->insert(strdup(*header)); } } if (curfile->second->find(h) == curfile->second->end()) curfile->second->insert(strdup(h)); free(h); } } /* FALL THROUGH */ default: break; } break; case TOKEN_DEFINE: if (verbose) fprintf(stderr, "%s #define ", filename); lexer.Lex(); if (lexer.GetToken() == TOKEN_IDENTIFIER) { if (verbose) fprintf(stderr, "%s", lexer.GetString()); if (!ignore.empty() && ignore.top() != NOT_IGNORE) { if (verbose) fprintf(stderr, " (ignored)"); break; } if (defines.find(lexer.GetString()) == defines.end()) defines.insert(strdup(lexer.GetString())); lexer.Lex(); } break; case TOKEN_UNDEF: if (verbose) fprintf(stderr, "%s #undef ", filename); lexer.Lex(); if (lexer.GetToken() == TOKEN_IDENTIFIER) { if (verbose) fprintf(stderr, "%s", lexer.GetString()); if (!ignore.empty() && ignore.top() != NOT_IGNORE) { if (verbose) fprintf(stderr, " (ignored)"); break; } StringSet::iterator it = defines.find(lexer.GetString()); if (it != defines.end()) { free(*it); defines.erase(it); } lexer.Lex(); } break; case TOKEN_ENDIF: if (verbose) fprintf(stderr, "%s #endif", filename); lexer.Lex(); if (!ignore.empty()) ignore.pop(); if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); break; case TOKEN_ELSE: { if (verbose) fprintf(stderr, "%s #else", filename); lexer.Lex(); Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top(); if (!ignore.empty()) ignore.pop(); if (ignore.empty() || ignore.top() == NOT_IGNORE) { ignore.push(last == IGNORE_UNTIL_ELSE ? NOT_IGNORE : IGNORE_UNTIL_ENDIF); } else { ignore.push(IGNORE_UNTIL_ENDIF); } if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); break; } case TOKEN_ELIF: { if (verbose) fprintf(stderr, "%s #elif ", filename); lexer.Lex(); Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top(); if (!ignore.empty()) ignore.pop(); if (ignore.empty() || ignore.top() == NOT_IGNORE) { bool value = ExpressionOr(&lexer, &defines, verbose); ignore.push(last == IGNORE_UNTIL_ELSE ? (value ? NOT_IGNORE : IGNORE_UNTIL_ELSE) : IGNORE_UNTIL_ENDIF); } else { ignore.push(IGNORE_UNTIL_ENDIF); } if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); break; } case TOKEN_IF: { if (verbose) fprintf(stderr, "%s #if ", filename); lexer.Lex(); if (ignore.empty() || ignore.top() == NOT_IGNORE) { bool value = ExpressionOr(&lexer, &defines, verbose); ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE); } else { ignore.push(IGNORE_UNTIL_ENDIF); } if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); break; } case TOKEN_IFDEF: if (verbose) fprintf(stderr, "%s #ifdef ", filename); lexer.Lex(); if (lexer.GetToken() == TOKEN_IDENTIFIER) { bool value = defines.find(lexer.GetString()) != defines.end(); if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value); if (ignore.empty() || ignore.top() == NOT_IGNORE) { ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE); } else { ignore.push(IGNORE_UNTIL_ENDIF); } } if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); break; case TOKEN_IFNDEF: if (verbose) fprintf(stderr, "%s #ifndef ", filename); lexer.Lex(); if (lexer.GetToken() == TOKEN_IDENTIFIER) { bool value = defines.find(lexer.GetString()) != defines.end(); if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value); if (ignore.empty() || ignore.top() == NOT_IGNORE) { ignore.push(!value ? NOT_IGNORE : IGNORE_UNTIL_ELSE); } else { ignore.push(IGNORE_UNTIL_ENDIF); } } if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); break; default: if (verbose) fprintf(stderr, "%s #", filename); lexer.Lex(); break; } if (verbose) fprintf(stderr, "\n"); /* FALL THROUGH */ default: /* Ignore the rest of the garbage on this line */ while (lexer.GetToken() != TOKEN_EOL && lexer.GetToken() != TOKEN_END) lexer.Lex(); lexer.Lex(); break; } } if (!header) { for (StringSet::iterator it = defines.begin(); it != defines.end(); it++) { free(*it); } defines.clear(); while (!ignore.empty()) ignore.pop(); } } /** * Entry point. Arguably the most common function in all applications. * @param argc the number of arguments. * @param argv the actual arguments. * @return return value for the caller to tell we succeed or not. */ int main(int argc, char *argv[]) { bool ignorenext = true; char *filename = NULL; char *ext = NULL; char *delimiter = NULL; bool append = false; bool verbose = false; for (int i = 0; i < argc; i++) { if (ignorenext) { ignorenext = false; continue; } if (argv[i][0] == '-') { /* Append */ if (strncmp(argv[i], "-a", 2) == 0) append = true; /* Include dir */ if (strncmp(argv[i], "-I", 2) == 0) { if (argv[i][2] == '\0') { i++; _include_dirs.insert(strdup(argv[i])); } else { _include_dirs.insert(strdup(&argv[i][2])); } continue; } /* Define */ if (strncmp(argv[i], "-D", 2) == 0) { char *p = strchr(argv[i], '='); if (p != NULL) *p = '\0'; _defines.insert(strdup(&argv[i][2])); continue; } /* Output file */ if (strncmp(argv[i], "-f", 2) == 0) { if (filename != NULL) continue; filename = strdup(&argv[i][2]); continue; } /* Object file extension */ if (strncmp(argv[i], "-o", 2) == 0) { if (ext != NULL) continue; ext = strdup(&argv[i][2]); continue; } /* Starting string delimiter */ if (strncmp(argv[i], "-s", 2) == 0) { if (delimiter != NULL) continue; delimiter = strdup(&argv[i][2]); continue; } /* Verbose */ if (strncmp(argv[i], "-v", 2) == 0) verbose = true; continue; } ScanFile(argv[i], ext, false, verbose); } /* Default output file is Makefile */ if (filename == NULL) filename = strdup("Makefile"); /* Default delimiter string */ if (delimiter == NULL) delimiter = strdup("# DO NOT DELETE"); char backup[PATH_MAX]; strecpy(backup, filename, lastof(backup)); strecat(backup, ".bak", lastof(backup)); char *content = NULL; long size = 0; /* Read in the current file; so we can overwrite everything from the * end of non-depend data marker down till the end. */ FILE *src = fopen(filename, "rb"); if (src != NULL) { fseek(src, 0, SEEK_END); if ((size = ftell(src)) < 0) { fprintf(stderr, "Could not read %s\n", filename); exit(-2); } rewind(src); content = (char*)malloc(size * sizeof(*content)); if (fread(content, 1, size, src) != (size_t)size) { fprintf(stderr, "Could not read %s\n", filename); exit(-2); } fclose(src); } FILE *dst = fopen(filename, "w"); bool found_delimiter = false; if (size != 0) { src = fopen(backup, "wb"); if (fwrite(content, 1, size, src) != (size_t)size) { fprintf(stderr, "Could not write %s\n", filename); exit(-2); } fclose(src); /* Then append it to the real file. */ src = fopen(backup, "rb"); while (fgets(content, size, src) != NULL) { fputs(content, dst); if (!strncmp(content, delimiter, strlen(delimiter))) found_delimiter = true; if (!append && found_delimiter) break; } fclose(src); } if (!found_delimiter) fprintf(dst, "\n%s\n", delimiter); for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) { for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) { fprintf(dst, "%s: %s\n", it->first, *h); } } /* Clean up our mess. */ fclose(dst); free(delimiter); free(filename); free(ext); free(content); for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) { for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) { free(*h); } it->second->clear(); delete it->second; free(it->first); } _files.clear(); for (StringMap::iterator it = _headers.begin(); it != _headers.end(); it++) { for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) { free(*h); } it->second->clear(); delete it->second; free(it->first); } _headers.clear(); for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) { free(*it); } _defines.clear(); for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) { free(*it); } _include_dirs.clear(); return 0; } openttd-1.5.3/src/rail.h0000644000000000000000000003575212627373442013610 0ustar rootroot/* $Id: rail.h 27432 2015-11-01 12:03:13Z frosch $ */ /* * 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 rail.h Rail specific functions. */ #ifndef RAIL_H #define RAIL_H #include "rail_type.h" #include "track_type.h" #include "gfx_type.h" #include "core/bitmath_func.hpp" #include "economy_func.h" #include "slope_type.h" #include "strings_type.h" #include "date_type.h" #include "signal_type.h" /** Railtype flags. */ enum RailTypeFlags { RTF_CATENARY = 0, ///< Bit number for drawing a catenary. RTF_NO_LEVEL_CROSSING = 1, ///< Bit number for disallowing level crossings. RTFB_NONE = 0, ///< All flags cleared. RTFB_CATENARY = 1 << RTF_CATENARY, ///< Value for drawing a catenary. RTFB_NO_LEVEL_CROSSING = 1 << RTF_NO_LEVEL_CROSSING, ///< Value for disallowing level crossings. }; DECLARE_ENUM_AS_BIT_SET(RailTypeFlags) struct SpriteGroup; /** Sprite groups for a railtype. */ enum RailTypeSpriteGroup { RTSG_CURSORS, ///< Cursor and toolbar icon images RTSG_OVERLAY, ///< Images for overlaying track RTSG_GROUND, ///< Main group of ground images RTSG_TUNNEL, ///< Main group of ground images for snow or desert RTSG_WIRES, ///< Catenary wires RTSG_PYLONS, ///< Catenary pylons RTSG_BRIDGE, ///< Bridge surface images RTSG_CROSSING, ///< Level crossing overlay images RTSG_DEPOT, ///< Depot images RTSG_FENCES, ///< Fence images RTSG_TUNNEL_PORTAL, ///< Tunnel portal overlay RTSG_SIGNALS, ///< Signal images RTSG_END, }; /** * Offsets for sprites within an overlay/underlay set. * These are the same for overlay and underlay sprites. */ enum RailTrackOffset { RTO_X, ///< Piece of rail in X direction RTO_Y, ///< Piece of rail in Y direction RTO_N, ///< Piece of rail in northern corner RTO_S, ///< Piece of rail in southern corner RTO_E, ///< Piece of rail in eastern corner RTO_W, ///< Piece of rail in western corner RTO_SLOPE_NE, ///< Piece of rail on slope with north-east raised RTO_SLOPE_SE, ///< Piece of rail on slope with south-east raised RTO_SLOPE_SW, ///< Piece of rail on slope with south-west raised RTO_SLOPE_NW, ///< Piece of rail on slope with north-west raised RTO_CROSSING_XY, ///< Crossing of X and Y rail, with ballast RTO_JUNCTION_SW, ///< Ballast for junction 'pointing' SW RTO_JUNCTION_NE, ///< Ballast for junction 'pointing' NE RTO_JUNCTION_SE, ///< Ballast for junction 'pointing' SE RTO_JUNCTION_NW, ///< Ballast for junction 'pointing' NW RTO_JUNCTION_NSEW,///< Ballast for full junction }; /** * Offsets for sprites within a bridge surface overlay set. */ enum RailTrackBridgeOffset { RTBO_X, ///< Piece of rail in X direction RTBO_Y, ///< Piece of rail in Y direction RTBO_SLOPE, ///< Sloped rail pieces, in order NE, SE, SW, NW }; /** * Offsets from base sprite for fence sprites. These are in the order of * the sprites in the original data files. */ enum RailFenceOffset { RFO_FLAT_X, RFO_FLAT_Y, RFO_FLAT_VERT, RFO_FLAT_HORZ, RFO_SLOPE_SW, RFO_SLOPE_SE, RFO_SLOPE_NE, RFO_SLOPE_NW, }; /** List of rail type labels. */ typedef SmallVector RailTypeLabelList; /** * This struct contains all the info that is needed to draw and construct tracks. */ struct RailtypeInfo { /** * Struct containing the main sprites. @note not all sprites are listed, but only * the ones used directly in the code */ struct { SpriteID track_y; ///< single piece of rail in Y direction, with ground SpriteID track_ns; ///< two pieces of rail in North and South corner (East-West direction) SpriteID ground; ///< ground sprite for a 3-way switch SpriteID single_x; ///< single piece of rail in X direction, without ground SpriteID single_y; ///< single piece of rail in Y direction, without ground SpriteID single_n; ///< single piece of rail in the northern corner SpriteID single_s; ///< single piece of rail in the southern corner SpriteID single_e; ///< single piece of rail in the eastern corner SpriteID single_w; ///< single piece of rail in the western corner SpriteID single_sloped;///< single piece of rail for slopes SpriteID crossing; ///< level crossing, rail in X direction SpriteID tunnel; ///< tunnel sprites base } base_sprites; /** * struct containing the sprites for the rail GUI. @note only sprites referred to * directly in the code are listed */ struct { SpriteID build_ns_rail; ///< button for building single rail in N-S direction SpriteID build_x_rail; ///< button for building single rail in X direction SpriteID build_ew_rail; ///< button for building single rail in E-W direction SpriteID build_y_rail; ///< button for building single rail in Y direction SpriteID auto_rail; ///< button for the autorail construction SpriteID build_depot; ///< button for building depots SpriteID build_tunnel; ///< button for building a tunnel SpriteID convert_rail; ///< button for converting rail SpriteID signals[SIGTYPE_END][2][2]; ///< signal GUI sprites (type, variant, state) } gui_sprites; struct { CursorID rail_ns; ///< Cursor for building rail in N-S direction CursorID rail_swne; ///< Cursor for building rail in X direction CursorID rail_ew; ///< Cursor for building rail in E-W direction CursorID rail_nwse; ///< Cursor for building rail in Y direction CursorID autorail; ///< Cursor for autorail tool CursorID depot; ///< Cursor for building a depot CursorID tunnel; ///< Cursor for building a tunnel CursorID convert; ///< Cursor for converting track } cursor; ///< Cursors associated with the rail type. struct { StringID name; ///< Name of this rail type. StringID toolbar_caption; ///< Caption in the construction toolbar GUI for this rail type. StringID menu_text; ///< Name of this rail type in the main toolbar dropdown. StringID build_caption; ///< Caption of the build vehicle GUI for this rail type. StringID replace_text; ///< Text used in the autoreplace GUI. StringID new_loco; ///< Name of an engine for this type of rail in the engine preview GUI. } strings; ///< Strings associated with the rail type. /** sprite number difference between a piece of track on a snowy ground and the corresponding one on normal ground */ SpriteID snow_offset; /** bitmask to the OTHER railtypes on which an engine of THIS railtype generates power */ RailTypes powered_railtypes; /** bitmask to the OTHER railtypes on which an engine of THIS railtype can physically travel */ RailTypes compatible_railtypes; /** * Bridge offset */ SpriteID bridge_offset; /** * Original railtype number to use when drawing non-newgrf railtypes, or when drawing stations. */ byte fallback_railtype; /** * Multiplier for curve maximum speed advantage */ byte curve_speed; /** * Bit mask of rail type flags */ RailTypeFlags flags; /** * Cost multiplier for building this rail type */ uint16 cost_multiplier; /** * Cost multiplier for maintenance of this rail type */ uint16 maintenance_multiplier; /** * Acceleration type of this rail type */ uint8 acceleration_type; /** * Maximum speed for vehicles travelling on this rail type */ uint16 max_speed; /** * Unique 32 bit rail type identifier */ RailTypeLabel label; /** * Rail type labels this type provides in addition to the main label. */ RailTypeLabelList alternate_labels; /** * Colour on mini-map */ byte map_colour; /** * Introduction date. * When #INVALID_DATE or a vehicle using this railtype gets introduced earlier, * the vehicle's introduction date will be used instead for this railtype. * The introduction at this date is furthermore limited by the * #introduction_required_types. */ Date introduction_date; /** * Bitmask of railtypes that are required for this railtype to be introduced * at a given #introduction_date. */ RailTypes introduction_required_railtypes; /** * Bitmask of which other railtypes are introduced when this railtype is introduced. */ RailTypes introduces_railtypes; /** * The sorting order of this railtype for the toolbar dropdown. */ byte sorting_order; /** * NewGRF providing the Action3 for the railtype. NULL if not available. */ const GRFFile *grffile[RTSG_END]; /** * Sprite groups for resolving sprites */ const SpriteGroup *group[RTSG_END]; inline bool UsesOverlay() const { return this->group[RTSG_GROUND] != NULL; } /** * Offset between the current railtype and normal rail. This means that:

* 1) All the sprites in a railset MUST be in the same order. This order * is determined by normal rail. Check sprites 1005 and following for this order

* 2) The position where the railtype is loaded must always be the same, otherwise * the offset will fail. */ inline uint GetRailtypeSpriteOffset() const { return 82 * this->fallback_railtype; } }; /** * Returns a pointer to the Railtype information for a given railtype * @param railtype the rail type which the information is requested for * @return The pointer to the RailtypeInfo */ static inline const RailtypeInfo *GetRailTypeInfo(RailType railtype) { extern RailtypeInfo _railtypes[RAILTYPE_END]; assert(railtype < RAILTYPE_END); return &_railtypes[railtype]; } /** * Checks if an engine of the given RailType can drive on a tile with a given * RailType. This would normally just be an equality check, but for electric * rails (which also support non-electric engines). * @return Whether the engine can drive on this tile. * @param enginetype The RailType of the engine we are considering. * @param tiletype The RailType of the tile we are considering. */ static inline bool IsCompatibleRail(RailType enginetype, RailType tiletype) { return HasBit(GetRailTypeInfo(enginetype)->compatible_railtypes, tiletype); } /** * Checks if an engine of the given RailType got power on a tile with a given * RailType. This would normally just be an equality check, but for electric * rails (which also support non-electric engines). * @return Whether the engine got power on this tile. * @param enginetype The RailType of the engine we are considering. * @param tiletype The RailType of the tile we are considering. */ static inline bool HasPowerOnRail(RailType enginetype, RailType tiletype) { return HasBit(GetRailTypeInfo(enginetype)->powered_railtypes, tiletype); } /** * Test if a RailType disallows build of level crossings. * @param rt The RailType to check. * @return Whether level crossings are not allowed. */ static inline bool RailNoLevelCrossings(RailType rt) { return HasBit(GetRailTypeInfo(rt)->flags, RTF_NO_LEVEL_CROSSING); } /** * Returns the cost of building the specified railtype. * @param railtype The railtype being built. * @return The cost multiplier. */ static inline Money RailBuildCost(RailType railtype) { assert(railtype < RAILTYPE_END); return (_price[PR_BUILD_RAIL] * GetRailTypeInfo(railtype)->cost_multiplier) >> 3; } /** * Returns the 'cost' of clearing the specified railtype. * @param railtype The railtype being removed. * @return The cost. */ static inline Money RailClearCost(RailType railtype) { /* Clearing rail in fact earns money, but if the build cost is set * very low then a loophole exists where money can be made. * In this case we limit the removal earnings to 3/4s of the build * cost. */ assert(railtype < RAILTYPE_END); return max(_price[PR_CLEAR_RAIL], -RailBuildCost(railtype) * 3 / 4); } /** * Calculates the cost of rail conversion * @param from The railtype we are converting from * @param to The railtype we are converting to * @return Cost per TrackBit */ static inline Money RailConvertCost(RailType from, RailType to) { /* Get the costs for removing and building anew * A conversion can never be more costly */ Money rebuildcost = RailBuildCost(to) + RailClearCost(from); /* Conversion between somewhat compatible railtypes: * Pay 1/8 of the target rail cost (labour costs) and additionally any difference in the * build costs, if the target type is more expensive (material upgrade costs). * Upgrade can never be more expensive than re-building. */ if (HasPowerOnRail(from, to) || HasPowerOnRail(to, from)) { Money upgradecost = RailBuildCost(to) / 8 + max((Money)0, RailBuildCost(to) - RailBuildCost(from)); return min(upgradecost, rebuildcost); } /* make the price the same as remove + build new type for rail types * which are not compatible in any way */ return rebuildcost; } /** * Calculates the maintenance cost of a number of track bits. * @param railtype The railtype to get the cost of. * @param num Number of track bits of this railtype. * @param total_num Total number of track bits of all railtypes. * @return Total cost. */ static inline Money RailMaintenanceCost(RailType railtype, uint32 num, uint32 total_num) { assert(railtype < RAILTYPE_END); return (_price[PR_INFRASTRUCTURE_RAIL] * GetRailTypeInfo(railtype)->maintenance_multiplier * num * (1 + IntSqrt(total_num))) >> 11; // 4 bits fraction for the multiplier and 7 bits scaling. } /** * Calculates the maintenance cost of a number of signals. * @param num Number of signals. * @return Total cost. */ static inline Money SignalMaintenanceCost(uint32 num) { return (_price[PR_INFRASTRUCTURE_RAIL] * 15 * num * (1 + IntSqrt(num))) >> 8; // 1 bit fraction for the multiplier and 7 bits scaling. } void DrawTrainDepotSprite(int x, int y, int image, RailType railtype); int TicksToLeaveDepot(const Train *v); Foundation GetRailFoundation(Slope tileh, TrackBits bits); bool HasRailtypeAvail(const CompanyID company, const RailType railtype); bool ValParamRailtype(const RailType rail); RailTypes AddDateIntroducedRailTypes(RailTypes current, Date date); RailType GetBestRailtype(const CompanyID company); RailTypes GetCompanyRailtypes(const CompanyID c); RailType GetRailTypeByLabel(RailTypeLabel label, bool allow_alternate_labels = true); void ResetRailTypes(); void InitRailTypes(); RailType AllocateRailType(RailTypeLabel label); extern RailType _sorted_railtypes[RAILTYPE_END]; extern uint8 _sorted_railtypes_size; /** * Loop header for iterating over railtypes, sorted by sortorder. * @param var Railtype. */ #define FOR_ALL_SORTED_RAILTYPES(var) for (uint8 index = 0; index < _sorted_railtypes_size && (var = _sorted_railtypes[index], true) ; index++) #endif /* RAIL_H */ openttd-1.5.3/src/command.cpp0000644000000000000000000010777312627373442014635 0ustar rootroot/* $Id: command.cpp 26802 2014-09-07 16:12:58Z alberth $ */ /* * 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 command.cpp Handling of commands. */ #include "stdafx.h" #include "landscape.h" #include "error.h" #include "gui.h" #include "command_func.h" #include "network/network_type.h" #include "network/network.h" #include "genworld.h" #include "strings_func.h" #include "texteff.hpp" #include "town.h" #include "date_func.h" #include "company_func.h" #include "company_base.h" #include "signal_func.h" #include "core/backup_type.hpp" #include "object_base.h" #include "table/strings.h" #include "safeguards.h" CommandProc CmdBuildRailroadTrack; CommandProc CmdRemoveRailroadTrack; CommandProc CmdBuildSingleRail; CommandProc CmdRemoveSingleRail; CommandProc CmdLandscapeClear; CommandProc CmdBuildBridge; CommandProc CmdBuildRailStation; CommandProc CmdRemoveFromRailStation; CommandProc CmdConvertRail; CommandProc CmdBuildSingleSignal; CommandProc CmdRemoveSingleSignal; CommandProc CmdTerraformLand; CommandProc CmdBuildObject; CommandProc CmdSellLandArea; CommandProc CmdBuildTunnel; CommandProc CmdBuildTrainDepot; CommandProc CmdBuildRailWaypoint; CommandProc CmdRenameWaypoint; CommandProc CmdRemoveFromRailWaypoint; CommandProc CmdBuildRoadStop; CommandProc CmdRemoveRoadStop; CommandProc CmdBuildLongRoad; CommandProc CmdRemoveLongRoad; CommandProc CmdBuildRoad; CommandProc CmdBuildRoadDepot; CommandProc CmdBuildAirport; CommandProc CmdBuildDock; CommandProc CmdBuildShipDepot; CommandProc CmdBuildBuoy; CommandProc CmdPlantTree; CommandProc CmdMoveRailVehicle; CommandProc CmdBuildVehicle; CommandProc CmdSellVehicle; CommandProc CmdRefitVehicle; CommandProc CmdSendVehicleToDepot; CommandProc CmdSetVehicleVisibility; CommandProc CmdForceTrainProceed; CommandProc CmdReverseTrainDirection; CommandProc CmdClearOrderBackup; CommandProc CmdModifyOrder; CommandProc CmdSkipToOrder; CommandProc CmdDeleteOrder; CommandProc CmdInsertOrder; CommandProc CmdChangeServiceInt; CommandProc CmdBuildIndustry; CommandProc CmdSetCompanyManagerFace; CommandProc CmdSetCompanyColour; CommandProc CmdIncreaseLoan; CommandProc CmdDecreaseLoan; CommandProc CmdWantEnginePreview; CommandProc CmdRenameVehicle; CommandProc CmdRenameEngine; CommandProc CmdRenameCompany; CommandProc CmdRenamePresident; CommandProc CmdRenameStation; CommandProc CmdRenameDepot; CommandProc CmdPlaceSign; CommandProc CmdRenameSign; CommandProc CmdTurnRoadVeh; CommandProc CmdPause; CommandProc CmdBuyShareInCompany; CommandProc CmdSellShareInCompany; CommandProc CmdBuyCompany; CommandProc CmdFoundTown; CommandProc CmdRenameTown; CommandProc CmdDoTownAction; CommandProc CmdTownGrowthRate; CommandProc CmdTownCargoGoal; CommandProc CmdTownSetText; CommandProc CmdExpandTown; CommandProc CmdDeleteTown; CommandProc CmdChangeSetting; CommandProc CmdChangeCompanySetting; CommandProc CmdOrderRefit; CommandProc CmdCloneOrder; CommandProc CmdClearArea; CommandProc CmdGiveMoney; CommandProc CmdMoneyCheat; CommandProc CmdChangeBankBalance; CommandProc CmdBuildCanal; CommandProc CmdBuildLock; CommandProc CmdCreateSubsidy; CommandProc CmdCompanyCtrl; CommandProc CmdCustomNewsItem; CommandProc CmdCreateGoal; CommandProc CmdRemoveGoal; CommandProc CmdSetGoalText; CommandProc CmdSetGoalProgress; CommandProc CmdSetGoalCompleted; CommandProc CmdGoalQuestion; CommandProc CmdGoalQuestionAnswer; CommandProc CmdCreateStoryPage; CommandProc CmdCreateStoryPageElement; CommandProc CmdUpdateStoryPageElement; CommandProc CmdSetStoryPageTitle; CommandProc CmdSetStoryPageDate; CommandProc CmdShowStoryPage; CommandProc CmdRemoveStoryPage; CommandProc CmdRemoveStoryPageElement; CommandProc CmdLevelLand; CommandProc CmdBuildSignalTrack; CommandProc CmdRemoveSignalTrack; CommandProc CmdSetAutoReplace; CommandProc CmdCloneVehicle; CommandProc CmdStartStopVehicle; CommandProc CmdMassStartStopVehicle; CommandProc CmdAutoreplaceVehicle; CommandProc CmdDepotSellAllVehicles; CommandProc CmdDepotMassAutoReplace; CommandProc CmdCreateGroup; CommandProc CmdAlterGroup; CommandProc CmdDeleteGroup; CommandProc CmdAddVehicleGroup; CommandProc CmdAddSharedVehicleGroup; CommandProc CmdRemoveAllVehiclesGroup; CommandProc CmdSetGroupReplaceProtection; CommandProc CmdMoveOrder; CommandProc CmdChangeTimetable; CommandProc CmdSetVehicleOnTime; CommandProc CmdAutofillTimetable; CommandProc CmdSetTimetableStart; CommandProc CmdOpenCloseAirport; #define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type} /** * The master command table * * This table contains all possible CommandProc functions with * the flags which belongs to it. The indices are the same * as the value from the CMD_* enums. */ static const Command _command_proc_table[] = { DEF_CMD(CmdBuildRailroadTrack, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_RAILROAD_TRACK DEF_CMD(CmdRemoveRailroadTrack, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_RAILROAD_TRACK DEF_CMD(CmdBuildSingleRail, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SINGLE_RAIL DEF_CMD(CmdRemoveSingleRail, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SINGLE_RAIL DEF_CMD(CmdLandscapeClear, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_LANDSCAPE_CLEAR DEF_CMD(CmdBuildBridge, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_BRIDGE DEF_CMD(CmdBuildRailStation, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_RAIL_STATION DEF_CMD(CmdBuildTrainDepot, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TRAIN_DEPOT DEF_CMD(CmdBuildSingleSignal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SIGNALS DEF_CMD(CmdRemoveSingleSignal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SIGNALS DEF_CMD(CmdTerraformLand, CMD_ALL_TILES | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_TERRAFORM_LAND DEF_CMD(CmdBuildObject, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_OBJECT DEF_CMD(CmdBuildTunnel, CMD_DEITY | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_TUNNEL DEF_CMD(CmdRemoveFromRailStation, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_STATION DEF_CMD(CmdConvertRail, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CONVERT_RAILD DEF_CMD(CmdBuildRailWaypoint, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_RAIL_WAYPOINT DEF_CMD(CmdRenameWaypoint, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_WAYPOINT DEF_CMD(CmdRemoveFromRailWaypoint, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_WAYPOINT DEF_CMD(CmdBuildRoadStop, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD_STOP DEF_CMD(CmdRemoveRoadStop, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_ROAD_STOP DEF_CMD(CmdBuildLongRoad,CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_LONG_ROAD DEF_CMD(CmdRemoveLongRoad, CMD_NO_TEST | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_LONG_ROAD; towns may disallow removing road bits (as they are connected) in test, but in exec they're removed and thus removing is allowed. DEF_CMD(CmdBuildRoad, CMD_DEITY | CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD DEF_CMD(CmdBuildRoadDepot, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD_DEPOT DEF_CMD(CmdBuildAirport, CMD_NO_WATER | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_AIRPORT DEF_CMD(CmdBuildDock, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_DOCK DEF_CMD(CmdBuildShipDepot, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SHIP_DEPOT DEF_CMD(CmdBuildBuoy, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_BUOY DEF_CMD(CmdPlantTree, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_PLANT_TREE DEF_CMD(CmdBuildVehicle, CMD_CLIENT_ID, CMDT_VEHICLE_CONSTRUCTION ), // CMD_BUILD_VEHICLE DEF_CMD(CmdSellVehicle, CMD_CLIENT_ID, CMDT_VEHICLE_CONSTRUCTION ), // CMD_SELL_VEHICLE DEF_CMD(CmdRefitVehicle, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_REFIT_VEHICLE DEF_CMD(CmdSendVehicleToDepot, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_SEND_VEHICLE_TO_DEPOT DEF_CMD(CmdSetVehicleVisibility, 0, CMDT_COMPANY_SETTING ), // CMD_SET_VEHICLE_VISIBILITY DEF_CMD(CmdMoveRailVehicle, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_MOVE_RAIL_VEHICLE DEF_CMD(CmdForceTrainProceed, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_FORCE_TRAIN_PROCEED DEF_CMD(CmdReverseTrainDirection, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_REVERSE_TRAIN_DIRECTION DEF_CMD(CmdClearOrderBackup, CMD_CLIENT_ID, CMDT_SERVER_SETTING ), // CMD_CLEAR_ORDER_BACKUP DEF_CMD(CmdModifyOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MODIFY_ORDER DEF_CMD(CmdSkipToOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SKIP_TO_ORDER DEF_CMD(CmdDeleteOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_DELETE_ORDER DEF_CMD(CmdInsertOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_INSERT_ORDER DEF_CMD(CmdChangeServiceInt, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_CHANGE_SERVICE_INT DEF_CMD(CmdBuildIndustry, CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_INDUSTRY DEF_CMD(CmdSetCompanyManagerFace, 0, CMDT_OTHER_MANAGEMENT ), // CMD_SET_COMPANY_MANAGER_FACE DEF_CMD(CmdSetCompanyColour, 0, CMDT_OTHER_MANAGEMENT ), // CMD_SET_COMPANY_COLOUR DEF_CMD(CmdIncreaseLoan, 0, CMDT_MONEY_MANAGEMENT ), // CMD_INCREASE_LOAN DEF_CMD(CmdDecreaseLoan, 0, CMDT_MONEY_MANAGEMENT ), // CMD_DECREASE_LOAN DEF_CMD(CmdWantEnginePreview, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_WANT_ENGINE_PREVIEW DEF_CMD(CmdRenameVehicle, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_VEHICLE DEF_CMD(CmdRenameEngine, CMD_SERVER, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_ENGINE DEF_CMD(CmdRenameCompany, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_COMPANY DEF_CMD(CmdRenamePresident, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_PRESIDENT DEF_CMD(CmdRenameStation, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_STATION DEF_CMD(CmdRenameDepot, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_DEPOT DEF_CMD(CmdPlaceSign, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_PLACE_SIGN DEF_CMD(CmdRenameSign, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_SIGN DEF_CMD(CmdTurnRoadVeh, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_TURN_ROADVEH DEF_CMD(CmdPause, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_PAUSE DEF_CMD(CmdBuyShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_SHARE_IN_COMPANY DEF_CMD(CmdSellShareInCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_SELL_SHARE_IN_COMPANY DEF_CMD(CmdBuyCompany, 0, CMDT_MONEY_MANAGEMENT ), // CMD_BUY_COMANY DEF_CMD(CmdFoundTown, CMD_DEITY | CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_FOUND_TOWN; founding random town can fail only in exec run DEF_CMD(CmdRenameTown, CMD_DEITY | CMD_SERVER, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_TOWN DEF_CMD(CmdDoTownAction, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_DO_TOWN_ACTION DEF_CMD(CmdTownCargoGoal, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_CARGO_GOAL DEF_CMD(CmdTownGrowthRate, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_GROWTH_RATE DEF_CMD(CmdTownSetText, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_TOWN_SET_TEXT DEF_CMD(CmdExpandTown, CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_EXPAND_TOWN DEF_CMD(CmdDeleteTown, CMD_OFFLINE, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_DELETE_TOWN DEF_CMD(CmdOrderRefit, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ORDER_REFIT DEF_CMD(CmdCloneOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CLONE_ORDER DEF_CMD(CmdClearArea, CMD_NO_TEST, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CLEAR_AREA; destroying multi-tile houses makes town rating differ between test and execution DEF_CMD(CmdMoneyCheat, CMD_OFFLINE, CMDT_CHEAT ), // CMD_MONEY_CHEAT DEF_CMD(CmdChangeBankBalance, CMD_DEITY, CMDT_MONEY_MANAGEMENT ), // CMD_CHANGE_BANK_BALANCE DEF_CMD(CmdBuildCanal, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_CANAL DEF_CMD(CmdCreateSubsidy, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_SUBSIDY DEF_CMD(CmdCompanyCtrl, CMD_SPECTATOR | CMD_CLIENT_ID, CMDT_SERVER_SETTING ), // CMD_COMPANY_CTRL DEF_CMD(CmdCustomNewsItem, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CUSTOM_NEWS_ITEM DEF_CMD(CmdCreateGoal, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_GOAL DEF_CMD(CmdRemoveGoal, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_GOAL DEF_CMD(CmdSetGoalText, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_GOAL_TEXT DEF_CMD(CmdSetGoalProgress, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_GOAL_PROGRESS DEF_CMD(CmdSetGoalCompleted, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_GOAL_COMPLETED DEF_CMD(CmdGoalQuestion, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_GOAL_QUESTION DEF_CMD(CmdGoalQuestionAnswer, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_GOAL_QUESTION_ANSWER DEF_CMD(CmdCreateStoryPage, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_STORY_PAGE DEF_CMD(CmdCreateStoryPageElement, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_STORY_PAGE_ELEMENT DEF_CMD(CmdUpdateStoryPageElement, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_UPDATE_STORY_PAGE_ELEMENT DEF_CMD(CmdSetStoryPageTitle, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_STORY_PAGE_TITLE DEF_CMD(CmdSetStoryPageDate, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_STORY_PAGE_DATE DEF_CMD(CmdShowStoryPage, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SHOW_STORY_PAGE DEF_CMD(CmdRemoveStoryPage, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_STORY_PAGE DEF_CMD(CmdRemoveStoryPageElement, CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_STORY_ELEMENT_PAGE DEF_CMD(CmdLevelLand, CMD_ALL_TILES | CMD_NO_TEST | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once DEF_CMD(CmdBuildLock, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_LOCK DEF_CMD(CmdBuildSignalTrack, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_SIGNAL_TRACK DEF_CMD(CmdRemoveSignalTrack, CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_SIGNAL_TRACK DEF_CMD(CmdGiveMoney, 0, CMDT_MONEY_MANAGEMENT ), // CMD_GIVE_MONEY DEF_CMD(CmdChangeSetting, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_CHANGE_SETTING DEF_CMD(CmdChangeCompanySetting, 0, CMDT_COMPANY_SETTING ), // CMD_CHANGE_COMPANY_SETTING DEF_CMD(CmdSetAutoReplace, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_SET_AUTOREPLACE DEF_CMD(CmdCloneVehicle, CMD_NO_TEST, CMDT_VEHICLE_CONSTRUCTION ), // CMD_CLONE_VEHICLE; NewGRF callbacks influence building and refitting making it impossible to correctly estimate the cost DEF_CMD(CmdStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_START_STOP_VEHICLE DEF_CMD(CmdMassStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_MASS_START_STOP DEF_CMD(CmdAutoreplaceVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_AUTOREPLACE_VEHICLE DEF_CMD(CmdDepotSellAllVehicles, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_SELL_ALL_VEHICLES DEF_CMD(CmdDepotMassAutoReplace, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_MASS_AUTOREPLACE DEF_CMD(CmdCreateGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CREATE_GROUP DEF_CMD(CmdDeleteGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_DELETE_GROUP DEF_CMD(CmdAlterGroup, 0, CMDT_OTHER_MANAGEMENT ), // CMD_ALTER_GROUP DEF_CMD(CmdAddVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_VEHICLE_GROUP DEF_CMD(CmdAddSharedVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_SHARE_VEHICLE_GROUP DEF_CMD(CmdRemoveAllVehiclesGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_REMOVE_ALL_VEHICLES_GROUP DEF_CMD(CmdSetGroupReplaceProtection, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_REPLACE_PROTECTION DEF_CMD(CmdMoveOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MOVE_ORDER 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(CmdSetTimetableStart, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_TIMETABLE_START DEF_CMD(CmdOpenCloseAirport, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_OPEN_CLOSE_AIRPORT }; /*! * This function range-checks a cmd, and checks if the cmd is not NULL * * @param cmd The integer value of a command * @return true if the command is valid (and got a CommandProc function) */ bool IsValidCommand(uint32 cmd) { cmd &= CMD_ID_MASK; return cmd < lengthof(_command_proc_table) && _command_proc_table[cmd].proc != NULL; } /*! * This function mask the parameter with CMD_ID_MASK and returns * the flags which belongs to the given command. * * @param cmd The integer value of the command * @return The flags for this command */ CommandFlags GetCommandFlags(uint32 cmd) { assert(IsValidCommand(cmd)); return _command_proc_table[cmd & CMD_ID_MASK].flags; } /*! * This function mask the parameter with CMD_ID_MASK and returns * the name which belongs to the given command. * * @param cmd The integer value of the command * @return The name for this command */ const char *GetCommandName(uint32 cmd) { assert(IsValidCommand(cmd)); return _command_proc_table[cmd & CMD_ID_MASK].name; } /** * Returns whether the command is allowed while the game is paused. * @param cmd The command to check. * @return True if the command is allowed while paused, false otherwise. */ bool IsCommandAllowedWhilePaused(uint32 cmd) { /* Lookup table for the command types that are allowed for a given pause level setting. */ static const int command_type_lookup[] = { CMDPL_ALL_ACTIONS, ///< CMDT_LANDSCAPE_CONSTRUCTION CMDPL_NO_LANDSCAPING, ///< CMDT_VEHICLE_CONSTRUCTION CMDPL_NO_LANDSCAPING, ///< CMDT_MONEY_MANAGEMENT CMDPL_NO_CONSTRUCTION, ///< CMDT_VEHICLE_MANAGEMENT CMDPL_NO_CONSTRUCTION, ///< CMDT_ROUTE_MANAGEMENT CMDPL_NO_CONSTRUCTION, ///< CMDT_OTHER_MANAGEMENT CMDPL_NO_CONSTRUCTION, ///< CMDT_COMPANY_SETTING CMDPL_NO_ACTIONS, ///< CMDT_SERVER_SETTING CMDPL_NO_ACTIONS, ///< CMDT_CHEAT }; assert_compile(lengthof(command_type_lookup) == CMDT_END); assert(IsValidCommand(cmd)); return _game_mode == GM_EDITOR || command_type_lookup[_command_proc_table[cmd & CMD_ID_MASK].type] <= _settings_game.construction.command_pause_level; } static int _docommand_recursive = 0; /** * Shorthand for calling the long DoCommand with a container. * * @param container Container with (almost) all information * @param flags Flags for the command and how to execute the command * @see CommandProc * @return the cost */ CommandCost DoCommand(const CommandContainer *container, DoCommandFlag flags) { return DoCommand(container->tile, container->p1, container->p2, flags, container->cmd & CMD_ID_MASK, container->text); } /*! * This function executes a given command with the parameters from the #CommandProc parameter list. * Depending on the flags parameter it execute or test a command. * * @param tile The tile to apply the command on (for the #CommandProc) * @param p1 Additional data for the command (for the #CommandProc) * @param p2 Additional data for the command (for the #CommandProc) * @param flags Flags for the command and how to execute the command * @param cmd The command-id to execute (a value of the CMD_* enums) * @param text The text to pass * @see CommandProc * @return the cost */ CommandCost DoCommand(TileIndex tile, uint32 p1, uint32 p2, DoCommandFlag flags, uint32 cmd, const char *text) { CommandCost res; /* Do not even think about executing out-of-bounds tile-commands */ if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (flags & DC_ALL_TILES) == 0))) return CMD_ERROR; /* Chop of any CMD_MSG or other flags; we don't need those here */ CommandProc *proc = _command_proc_table[cmd & CMD_ID_MASK].proc; _docommand_recursive++; /* only execute the test call if it's toplevel, or we're not execing. */ if (_docommand_recursive == 1 || !(flags & DC_EXEC) ) { if (_docommand_recursive == 1) _cleared_object_areas.Clear(); SetTownRatingTestMode(true); res = proc(tile, flags & ~DC_EXEC, p1, p2, text); SetTownRatingTestMode(false); if (res.Failed()) { goto error; } if (_docommand_recursive == 1 && !(flags & DC_QUERY_COST) && !(flags & DC_BANKRUPT) && !CheckCompanyHasMoney(res)) { // CheckCompanyHasMoney() modifies 'res' to an error if it fails. goto error; } if (!(flags & DC_EXEC)) { _docommand_recursive--; return res; } } /* Execute the command here. All cost-relevant functions set the expenses type * themselves to the cost object at some point */ if (_docommand_recursive == 1) _cleared_object_areas.Clear(); res = proc(tile, flags, p1, p2, text); if (res.Failed()) { error: _docommand_recursive--; return res; } /* if toplevel, subtract the money. */ if (--_docommand_recursive == 0 && !(flags & DC_BANKRUPT)) { SubtractMoneyFromCompany(res); } return res; } /*! * This functions returns the money which can be used to execute a command. * This is either the money of the current company or INT64_MAX if there * is no such a company "at the moment" like the server itself. * * @return The available money of a company or INT64_MAX */ Money GetAvailableMoneyForCommand() { CompanyID company = _current_company; if (!Company::IsValidID(company)) return INT64_MAX; return Company::Get(company)->money; } /** * Shortcut for the long DoCommandP when having a container with the data. * @param container the container with information. * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) * @return true if the command succeeded, else false */ bool DoCommandP(const CommandContainer *container, bool my_cmd) { return DoCommandP(container->tile, container->p1, container->p2, container->cmd, container->callback, container->text, my_cmd); } /*! * Toplevel network safe docommand function for the current company. Must not be called recursively. * The callback is called when the command succeeded or failed. The parameters * \a tile, \a p1, and \a p2 are from the #CommandProc function. The parameter \a cmd is the command to execute. * The parameter \a my_cmd is used to indicate if the command is from a company or the server. * * @param tile The tile to perform a command on (see #CommandProc) * @param p1 Additional data for the command (see #CommandProc) * @param p2 Additional data for the command (see #CommandProc) * @param cmd The command to execute (a CMD_* value) * @param callback A callback function to call after the command is finished * @param text The text to pass * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) * @return \c true if the command succeeded, else \c false. */ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd) { /* Cost estimation is generally only done when the * local user presses shift while doing somthing. * However, in case of incoming network commands, * map generation or the pause button we do want * to execute. */ bool estimate_only = _shift_pressed && IsLocalCompany() && !_generating_world && !(cmd & CMD_NETWORK_COMMAND) && (cmd & CMD_ID_MASK) != CMD_PAUSE; /* We're only sending the command, so don't do * fancy things for 'success'. */ bool only_sending = _networking && !(cmd & CMD_NETWORK_COMMAND); /* Where to show the message? */ int x = TileX(tile) * TILE_SIZE; int y = TileY(tile) * TILE_SIZE; if (_pause_mode != PM_UNPAUSED && !IsCommandAllowedWhilePaused(cmd)) { ShowErrorMessage(GB(cmd, 16, 16), STR_ERROR_NOT_ALLOWED_WHILE_PAUSED, WL_INFO, x, y); return false; } #ifdef ENABLE_NETWORK /* Only set p2 when the command does not come from the network. */ if (!(cmd & CMD_NETWORK_COMMAND) && GetCommandFlags(cmd) & CMD_CLIENT_ID && p2 == 0) p2 = CLIENT_ID_SERVER; #endif CommandCost res = DoCommandPInternal(tile, p1, p2, cmd, callback, text, my_cmd, estimate_only); if (res.Failed()) { /* Only show the error when it's for us. */ StringID error_part1 = GB(cmd, 16, 16); if (estimate_only || (IsLocalCompany() && error_part1 != 0 && my_cmd)) { ShowErrorMessage(error_part1, res.GetErrorMessage(), WL_INFO, x, y, res.GetTextRefStackGRF(), res.GetTextRefStackSize(), res.GetTextRefStack()); } } else if (estimate_only) { ShowEstimatedCostOrIncome(res.GetCost(), x, y); } else if (!only_sending && res.GetCost() != 0 && tile != 0 && IsLocalCompany() && _game_mode != GM_EDITOR) { /* Only show the cost animation when we did actually * execute the command, i.e. we're not sending it to * the server, when it has cost the local company * something. Furthermore in the editor there is no * concept of cost, so don't show it there either. */ ShowCostOrIncomeAnimation(x, y, GetSlopePixelZ(x, y), res.GetCost()); } if (!estimate_only && !only_sending && callback != NULL) { callback(res, tile, p1, p2); } return res.Succeeded(); } /** * Helper to deduplicate the code for returning. * @param cmd the command cost to return. * @param clear whether to keep the storage changes or not. */ #define return_dcpi(cmd) { _docommand_recursive = 0; return cmd; } /*! * Helper function for the toplevel network safe docommand function for the current company. * * @param tile The tile to perform a command on (see #CommandProc) * @param p1 Additional data for the command (see #CommandProc) * @param p2 Additional data for the command (see #CommandProc) * @param cmd The command to execute (a CMD_* value) * @param callback A callback function to call after the command is finished * @param text The text to pass * @param my_cmd indicator if the command is from a company or server (to display error messages for a user) * @param estimate_only whether to give only the estimate or also execute the command * @return the command cost of this function. */ CommandCost DoCommandPInternal(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback, const char *text, bool my_cmd, bool estimate_only) { /* Prevent recursion; it gives a mess over the network */ assert(_docommand_recursive == 0); _docommand_recursive = 1; /* Reset the state. */ _additional_cash_required = 0; /* Get pointer to command handler */ byte cmd_id = cmd & CMD_ID_MASK; assert(cmd_id < lengthof(_command_proc_table)); CommandProc *proc = _command_proc_table[cmd_id].proc; /* Shouldn't happen, but you never know when someone adds * NULLs to the _command_proc_table. */ assert(proc != NULL); /* Command flags are used internally */ CommandFlags cmd_flags = GetCommandFlags(cmd); /* Flags get send to the DoCommand */ DoCommandFlag flags = CommandFlagsToDCFlags(cmd_flags); #ifdef ENABLE_NETWORK /* Make sure p2 is properly set to a ClientID. */ assert(!(cmd_flags & CMD_CLIENT_ID) || p2 != 0); #endif /* Do not even think about executing out-of-bounds tile-commands */ if (tile != 0 && (tile >= MapSize() || (!IsValidTile(tile) && (cmd_flags & CMD_ALL_TILES) == 0))) return_dcpi(CMD_ERROR); /* Always execute server and spectator commands as spectator */ bool exec_as_spectator = (cmd_flags & (CMD_SPECTATOR | CMD_SERVER)) != 0; /* If the company isn't valid it may only do server command or start a new company! * The server will ditch any server commands a client sends to it, so effectively * this guards the server from executing functions for an invalid company. */ if (_game_mode == GM_NORMAL && !exec_as_spectator && !Company::IsValidID(_current_company) && !(_current_company == OWNER_DEITY && (cmd_flags & CMD_DEITY) != 0)) { return_dcpi(CMD_ERROR); } Backup cur_company(_current_company, FILE_LINE); if (exec_as_spectator) cur_company.Change(COMPANY_SPECTATOR); bool test_and_exec_can_differ = (cmd_flags & CMD_NO_TEST) != 0; /* Test the command. */ _cleared_object_areas.Clear(); SetTownRatingTestMode(true); BasePersistentStorageArray::SwitchMode(PSM_ENTER_TESTMODE); CommandCost res = proc(tile, flags, p1, p2, text); BasePersistentStorageArray::SwitchMode(PSM_LEAVE_TESTMODE); SetTownRatingTestMode(false); /* Make sure we're not messing things up here. */ assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify()); /* If the command fails, we're doing an estimate * or the player does not have enough money * (unless it's a command where the test and * execution phase might return different costs) * we bail out here. */ if (res.Failed() || estimate_only || (!test_and_exec_can_differ && !CheckCompanyHasMoney(res))) { if (!_networking || _generating_world || (cmd & CMD_NETWORK_COMMAND) != 0) { /* Log the failed command as well. Just to be able to be find * causes of desyncs due to bad command test implementations. */ DEBUG(desync, 1, "cmdf: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, GetCommandName(cmd)); } cur_company.Restore(); return_dcpi(res); } #ifdef ENABLE_NETWORK /* * If we are in network, and the command is not from the network * send it to the command-queue and abort execution */ if (_networking && !_generating_world && !(cmd & CMD_NETWORK_COMMAND)) { NetworkSendCommand(tile, p1, p2, cmd & ~CMD_FLAGS_MASK, callback, text, _current_company); cur_company.Restore(); /* Don't return anything special here; no error, no costs. * This way it's not handled by DoCommand and only the * actual execution of the command causes messages. Also * reset the storages as we've not executed the command. */ return_dcpi(CommandCost()); } #endif /* ENABLE_NETWORK */ DEBUG(desync, 1, "cmd: %08x; %02x; %02x; %06x; %08x; %08x; %08x; \"%s\" (%s)", _date, _date_fract, (int)_current_company, tile, p1, p2, cmd & ~CMD_NETWORK_COMMAND, text, GetCommandName(cmd)); /* Actually try and execute the command. If no cost-type is given * use the construction one */ _cleared_object_areas.Clear(); BasePersistentStorageArray::SwitchMode(PSM_ENTER_COMMAND); CommandCost res2 = proc(tile, flags | DC_EXEC, p1, p2, text); BasePersistentStorageArray::SwitchMode(PSM_LEAVE_COMMAND); if (cmd_id == CMD_COMPANY_CTRL) { cur_company.Trash(); /* We are a new company -> Switch to new local company. * We were closed down -> Switch to spectator * Some other company opened/closed down -> The outside function will switch back */ _current_company = _local_company; } else { /* Make sure nothing bad happened, like changing the current company. */ assert(exec_as_spectator ? _current_company == COMPANY_SPECTATOR : cur_company.Verify()); cur_company.Restore(); } /* If the test and execution can differ we have to check the * return of the command. Otherwise we can check whether the * test and execution have yielded the same result, * i.e. cost and error state are the same. */ if (!test_and_exec_can_differ) { assert(res.GetCost() == res2.GetCost() && res.Failed() == res2.Failed()); // sanity check } else if (res2.Failed()) { return_dcpi(res2); } /* If we're needing more money and we haven't done * anything yet, ask for the money! */ if (_additional_cash_required != 0 && res2.GetCost() == 0) { /* It could happen we removed rail, thus gained money, and deleted something else. * So make sure the signal buffer is empty even in this case */ UpdateSignalsInBuffer(); SetDParam(0, _additional_cash_required); return_dcpi(CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY)); } /* update last build coordinate of company. */ if (tile != 0) { Company *c = Company::GetIfValid(_current_company); if (c != NULL) c->last_build_coordinate = tile; } SubtractMoneyFromCompany(res2); /* update signals if needed */ UpdateSignalsInBuffer(); return_dcpi(res2); } #undef return_dcpi /** * Adds the cost of the given command return value to this cost. * Also takes a possible error message when it is set. * @param ret The command to add the cost of. */ void CommandCost::AddCost(const CommandCost &ret) { this->AddCost(ret.cost); if (this->success && !ret.success) { this->message = ret.message; this->success = false; } } /** * Values to put on the #TextRefStack for the error message. * There is only one static instance of the array, just like there is only one * instance of normal DParams. */ uint32 CommandCost::textref_stack[16]; /** * Activate usage of the NewGRF #TextRefStack for the error message. * @param grffile NewGRF that provides the #TextRefStack * @param num_registers number of entries to copy from the temporary NewGRF registers */ void CommandCost::UseTextRefStack(const GRFFile *grffile, uint num_registers) { extern TemporaryStorageArray _temp_store; assert(num_registers < lengthof(textref_stack)); this->textref_stack_grffile = grffile; this->textref_stack_size = num_registers; for (uint i = 0; i < num_registers; i++) { textref_stack[i] = _temp_store.GetValue(0x100 + i); } } openttd-1.5.3/src/statusbar_gui.h0000644000000000000000000000233512627373442015524 0ustar rootroot/* $Id: statusbar_gui.h 25289 2013-05-26 19:24:37Z frosch $ */ /* * 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 statusbar_gui.h Functions, definitions and such used only by the GUI. */ #ifndef STATUSBAR_GUI_H #define STATUSBAR_GUI_H /** What of the statusbar must be invalidated? */ enum StatusBarInvalidate { SBI_SAVELOAD_START, ///< started saving SBI_SAVELOAD_FINISH, ///< finished saving SBI_SHOW_TICKER, ///< start scrolling news SBI_SHOW_REMINDER, ///< show a reminder (dot on the right side of the statusbar) SBI_NEWS_DELETED, ///< abort current news display (active news were deleted) SBI_END }; bool IsNewsTickerShown(); void ShowStatusBar(); #endif /* STATUSBAR_GUI_H */ openttd-1.5.3/src/newgrf_townname.cpp0000644000000000000000000000766612627373442016417 0ustar rootroot/* $Id: newgrf_townname.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_townname.cpp * Implementation of Action 0F "universal holder" structure and functions. * This file implements a linked-lists of townname generators, * holding everything that the newgrf action 0F will send over to OpenTTD. */ #include "stdafx.h" #include "newgrf_townname.h" #include "core/alloc_func.hpp" #include "string_func.h" #include "safeguards.h" static GRFTownName *_grf_townnames = NULL; GRFTownName *GetGRFTownName(uint32 grfid) { GRFTownName *t = _grf_townnames; for (; t != NULL; t = t->next) { if (t->grfid == grfid) return t; } return NULL; } GRFTownName *AddGRFTownName(uint32 grfid) { GRFTownName *t = GetGRFTownName(grfid); if (t == NULL) { t = CallocT(1); t->grfid = grfid; t->next = _grf_townnames; _grf_townnames = t; } return t; } void DelGRFTownName(uint32 grfid) { GRFTownName *t = _grf_townnames; GRFTownName *p = NULL; for (;t != NULL; p = t, t = t->next) if (t->grfid == grfid) break; if (t != NULL) { for (int i = 0; i < 128; i++) { for (int j = 0; j < t->nbparts[i]; j++) { for (int k = 0; k < t->partlist[i][j].partcount; k++) { if (!HasBit(t->partlist[i][j].parts[k].prob, 7)) free(t->partlist[i][j].parts[k].data.text); } free(t->partlist[i][j].parts); } free(t->partlist[i]); } if (p != NULL) { p->next = t->next; } else { _grf_townnames = t->next; } free(t); } } static char *RandomPart(char *buf, GRFTownName *t, uint32 seed, byte id, const char *last) { assert(t != NULL); for (int i = 0; i < t->nbparts[id]; i++) { byte count = t->partlist[id][i].bitcount; uint16 maxprob = t->partlist[id][i].maxprob; uint32 r = (GB(seed, t->partlist[id][i].bitstart, count) * maxprob) >> count; for (int j = 0; j < t->partlist[id][i].partcount; j++) { byte prob = t->partlist[id][i].parts[j].prob; maxprob -= GB(prob, 0, 7); if (maxprob > r) continue; if (HasBit(prob, 7)) { buf = RandomPart(buf, t, seed, t->partlist[id][i].parts[j].data.id, last); } else { buf = strecat(buf, t->partlist[id][i].parts[j].data.text, last); } break; } } return buf; } char *GRFTownNameGenerate(char *buf, uint32 grfid, uint16 gen, uint32 seed, const char *last) { strecpy(buf, "", last); for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { if (t->grfid == grfid) { assert(gen < t->nb_gen); buf = RandomPart(buf, t, seed, t->id[gen], last); break; } } return buf; } StringID *GetGRFTownNameList() { int nb_names = 0, n = 0; for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) nb_names += t->nb_gen; StringID *list = MallocT(nb_names + 1); for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { for (int j = 0; j < t->nb_gen; j++) list[n++] = t->name[j]; } list[n] = INVALID_STRING_ID; return list; } void CleanUpGRFTownNames() { while (_grf_townnames != NULL) DelGRFTownName(_grf_townnames->grfid); } uint32 GetGRFTownNameId(int gen) { for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { if (gen < t->nb_gen) return t->grfid; gen -= t->nb_gen; } /* Fallback to no NewGRF */ return 0; } uint16 GetGRFTownNameType(int gen) { for (GRFTownName *t = _grf_townnames; t != NULL; t = t->next) { if (gen < t->nb_gen) return gen; gen -= t->nb_gen; } /* Fallback to english original */ return SPECSTR_TOWNNAME_ENGLISH; } openttd-1.5.3/src/base_media_func.h0000644000000000000000000003235312627373442015737 0ustar rootroot/* $Id: base_media_func.h 26637 2014-06-09 17:43:59Z rubidium $ */ /* * 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 base_media_func.h Generic function implementations for base data (graphics, sounds). * @note You should _never_ include this file due to the SET_TYPE define. */ #include "base_media_base.h" #include "debug.h" #include "ini_type.h" #include "string_func.h" template /* static */ const char *BaseMedia::ini_set; template /* static */ const Tbase_set *BaseMedia::used_set; template /* static */ Tbase_set *BaseMedia::available_sets; template /* static */ Tbase_set *BaseMedia::duplicate_sets; /** * Try to read a single piece of metadata and return false if it doesn't exist. * @param name the name of the item to fetch. */ #define fetch_metadata(name) \ item = metadata->GetItem(name, false); \ if (item == NULL || StrEmpty(item->value)) { \ DEBUG(grf, 0, "Base " SET_TYPE "set detail loading: %s field missing.", name); \ DEBUG(grf, 0, " Is %s readable for the user running OpenTTD?", full_filename); \ return false; \ } /** * Read the set information from a loaded ini. * @param ini the ini to read from * @param path the path to this ini file (for filenames) * @param full_filename the full filename of the loaded file (for error reporting purposes) * @param allow_empty_filename empty filenames are valid * @return true if loading was successful. */ template bool BaseSet::FillSetDetails(IniFile *ini, const char *path, const char *full_filename, bool allow_empty_filename) { memset(this, 0, sizeof(*this)); IniGroup *metadata = ini->GetGroup("metadata"); IniItem *item; fetch_metadata("name"); this->name = stredup(item->value); fetch_metadata("description"); this->description[stredup("")] = stredup(item->value); /* Add the translations of the descriptions too. */ for (const IniItem *item = metadata->item; item != NULL; item = item->next) { if (strncmp("description.", item->name, 12) != 0) continue; this->description[stredup(item->name + 12)] = stredup(item->value); } fetch_metadata("shortname"); for (uint i = 0; item->value[i] != '\0' && i < 4; i++) { this->shortname |= ((uint8)item->value[i]) << (i * 8); } fetch_metadata("version"); this->version = atoi(item->value); item = metadata->GetItem("fallback", false); this->fallback = (item != NULL && strcmp(item->value, "0") != 0 && strcmp(item->value, "false") != 0); /* For each of the file types we want to find the file, MD5 checksums and warning messages. */ IniGroup *files = ini->GetGroup("files"); IniGroup *md5s = ini->GetGroup("md5s"); IniGroup *origin = ini->GetGroup("origin"); for (uint i = 0; i < Tnum_files; i++) { MD5File *file = &this->files[i]; /* Find the filename first. */ item = files->GetItem(BaseSet::file_names[i], false); if (item == NULL || (item->value == NULL && !allow_empty_filename)) { DEBUG(grf, 0, "No " SET_TYPE " file for: %s (in %s)", BaseSet::file_names[i], full_filename); return false; } const char *filename = item->value; if (filename == NULL) { file->filename = NULL; /* If we list no file, that file must be valid */ this->valid_files++; this->found_files++; continue; } file->filename = str_fmt("%s%s", path, filename); /* Then find the MD5 checksum */ item = md5s->GetItem(filename, false); if (item == NULL || item->value == NULL) { DEBUG(grf, 0, "No MD5 checksum specified for: %s (in %s)", filename, full_filename); return false; } char *c = item->value; for (uint i = 0; i < sizeof(file->hash) * 2; i++, c++) { uint j; if ('0' <= *c && *c <= '9') { j = *c - '0'; } else if ('a' <= *c && *c <= 'f') { j = *c - 'a' + 10; } else if ('A' <= *c && *c <= 'F') { j = *c - 'A' + 10; } else { DEBUG(grf, 0, "Malformed MD5 checksum specified for: %s (in %s)", filename, full_filename); return false; } if (i % 2 == 0) { file->hash[i / 2] = j << 4; } else { file->hash[i / 2] |= j; } } /* Then find the warning message when the file's missing */ item = origin->GetItem(filename, false); if (item == NULL) item = origin->GetItem("default", false); if (item == NULL) { DEBUG(grf, 1, "No origin warning message specified for: %s", filename); file->missing_warning = stredup(""); } else { file->missing_warning = stredup(item->value); } switch (T::CheckMD5(file, BASESET_DIR)) { case MD5File::CR_MATCH: this->valid_files++; this->found_files++; break; case MD5File::CR_MISMATCH: DEBUG(grf, 1, "MD5 checksum mismatch for: %s (in %s)", filename, full_filename); this->found_files++; break; case MD5File::CR_NO_FILE: DEBUG(grf, 1, "The file %s specified in %s is missing", filename, full_filename); break; } } return true; } template bool BaseMedia::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { bool ret = false; DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename); Tbase_set *set = new Tbase_set(); IniFile *ini = new IniFile(); ini->LoadFromDisk(filename, BASESET_DIR); char *path = stredup(filename + basepath_length); char *psep = strrchr(path, PATHSEPCHAR); if (psep != NULL) { psep[1] = '\0'; } else { *path = '\0'; } if (set->FillSetDetails(ini, path, filename)) { Tbase_set *duplicate = NULL; for (Tbase_set *c = BaseMedia::available_sets; c != NULL; c = c->next) { if (strcmp(c->name, set->name) == 0 || c->shortname == set->shortname) { duplicate = c; break; } } if (duplicate != NULL) { /* The more complete set takes precedence over the version number. */ if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) || duplicate->valid_files > set->valid_files) { DEBUG(grf, 1, "Not adding %s (%i) as base " SET_TYPE " set (duplicate, %s)", set->name, set->version, duplicate->valid_files > set->valid_files ? "less valid files" : "lower version"); set->next = BaseMedia::duplicate_sets; BaseMedia::duplicate_sets = set; } else { Tbase_set **prev = &BaseMedia::available_sets; while (*prev != duplicate) prev = &(*prev)->next; *prev = set; set->next = duplicate->next; /* If the duplicate set is currently used (due to rescanning this can happen) * update the currently used set to the new one. This will 'lie' about the * version number until a new game is started which isn't a big problem */ if (BaseMedia::used_set == duplicate) BaseMedia::used_set = set; DEBUG(grf, 1, "Removing %s (%i) as base " SET_TYPE " set (duplicate, %s)", duplicate->name, duplicate->version, duplicate->valid_files < set->valid_files ? "less valid files" : "lower version"); duplicate->next = BaseMedia::duplicate_sets; BaseMedia::duplicate_sets = duplicate; ret = true; } } else { Tbase_set **last = &BaseMedia::available_sets; while (*last != NULL) last = &(*last)->next; *last = set; ret = true; } if (ret) { DEBUG(grf, 1, "Adding %s (%i) as base " SET_TYPE " set", set->name, set->version); } } else { delete set; } free(path); delete ini; return ret; } /** * Set the set to be used. * @param name of the set to use * @return true if it could be loaded */ template /* static */ bool BaseMedia::SetSet(const char *name) { extern void CheckExternalFiles(); if (StrEmpty(name)) { if (!BaseMedia::DetermineBestSet()) return false; CheckExternalFiles(); return true; } for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { if (strcmp(name, s->name) == 0) { BaseMedia::used_set = s; CheckExternalFiles(); return true; } } return false; } /** * Returns a list with the sets. * @param p where to print to * @param last the last character to print to * @return the last printed character */ template /* static */ char *BaseMedia::GetSetsList(char *p, const char *last) { p += seprintf(p, last, "List of " SET_TYPE " sets:\n"); for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { p += seprintf(p, last, "%18s: %s", s->name, s->GetDescription()); int invalid = s->GetNumInvalid(); if (invalid != 0) { int missing = s->GetNumMissing(); if (missing == 0) { p += seprintf(p, last, " (%i corrupt file%s)\n", invalid, invalid == 1 ? "" : "s"); } else { p += seprintf(p, last, " (unusable: %i missing file%s)\n", missing, missing == 1 ? "" : "s"); } } else { p += seprintf(p, last, "\n"); } } p += seprintf(p, last, "\n"); return p; } #if defined(ENABLE_NETWORK) #include "network/network_content.h" template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s) { for (; s != NULL; s = s->next) { if (s->GetNumMissing() != 0) continue; if (s->shortname != ci->unique_id) continue; if (!md5sum) return s->files[0].filename; byte md5[16]; memset(md5, 0, sizeof(md5)); for (uint i = 0; i < Tbase_set::NUM_FILES; i++) { for (uint j = 0; j < sizeof(md5); j++) { md5[j] ^= s->files[i].hash[j]; } } if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return s->files[0].filename; } return NULL; } template /* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) { return (TryGetBaseSetFile(ci, md5sum, BaseMedia::available_sets) != NULL) || (TryGetBaseSetFile(ci, md5sum, BaseMedia::duplicate_sets) != NULL); } #else template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s) { return NULL; } template /* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) { return false; } #endif /* ENABLE_NETWORK */ /** * Count the number of available graphics sets. * @return the number of sets */ template /* static */ int BaseMedia::GetNumSets() { int n = 0; for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; n++; } return n; } /** * Get the index of the currently active graphics set * @return the current set's index */ template /* static */ int BaseMedia::GetIndexOfUsedSet() { int n = 0; for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { if (s == BaseMedia::used_set) return n; if (s->GetNumMissing() != 0) continue; n++; } return -1; } /** * Get the name of the graphics set at the specified index * @return the name of the set */ template /* static */ const Tbase_set *BaseMedia::GetSet(int index) { for (const Tbase_set *s = BaseMedia::available_sets; s != NULL; s = s->next) { if (s != BaseMedia::used_set && s->GetNumMissing() != 0) continue; if (index == 0) return s; index--; } error("Base" SET_TYPE "::GetSet(): index %d out of range", index); } /** * Return the used set. * @return the used set. */ template /* static */ const Tbase_set *BaseMedia::GetUsedSet() { return BaseMedia::used_set; } /** * Return the available sets. * @return The available sets. */ template /* static */ Tbase_set *BaseMedia::GetAvailableSets() { return BaseMedia::available_sets; } /** * Force instantiation of methods so we don't get linker errors. * @param repl_type the type of the BaseMedia to instantiate * @param set_type the type of the BaseSet to instantiate */ #define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \ template const char *repl_type::ini_set; \ template const char *repl_type::GetExtension(); \ template bool repl_type::AddFile(const char *filename, size_t pathlength, const char *tar_filename); \ template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ template bool repl_type::SetSet(const char *name); \ template char *repl_type::GetSetsList(char *p, const char *last); \ template int repl_type::GetNumSets(); \ template int repl_type::GetIndexOfUsedSet(); \ template const set_type *repl_type::GetSet(int index); \ template const set_type *repl_type::GetUsedSet(); \ template bool repl_type::DetermineBestSet(); \ template set_type *repl_type::GetAvailableSets(); \ template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const set_type *s); openttd-1.5.3/src/date_func.h0000644000000000000000000000247012627373441014577 0ustar rootroot/* $Id: date_func.h 22411 2011-05-02 17:42:12Z rubidium $ */ /* * 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 date_func.h Functions related to dates. */ #ifndef DATE_FUNC_H #define DATE_FUNC_H #include "date_type.h" extern Year _cur_year; extern Month _cur_month; extern Date _date; extern DateFract _date_fract; extern uint16 _tick_counter; void SetDate(Date date, DateFract fract); void ConvertDateToYMD(Date date, YearMonthDay *ymd); Date ConvertYMDToDate(Year year, Month month, Day day); /** * Checks whether the given year is a leap year or not. * @param yr The year to check. * @return True if \c yr is a leap year, otherwise false. */ static inline bool IsLeapYear(Year yr) { return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0); } #endif /* DATE_FUNC_H */ openttd-1.5.3/src/music/0000755000000000000000000000000012627373435013616 5ustar rootrootopenttd-1.5.3/src/music/bemidi.cpp0000644000000000000000000000310212627373435015547 0ustar rootroot/* $Id: bemidi.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 bemidi.cpp Support for BeOS midi. */ #include "../stdafx.h" #include "../openttd.h" #include "bemidi.h" /* BeOS System Includes */ #include #include "../safeguards.h" /** The file we're playing. */ static BMidiSynthFile midiSynthFile; /** Factory for BeOS' midi player. */ static FMusicDriver_BeMidi iFMusicDriver_BeMidi; const char *MusicDriver_BeMidi::Start(const char * const *parm) { return NULL; } void MusicDriver_BeMidi::Stop() { midiSynthFile.UnloadFile(); } void MusicDriver_BeMidi::PlaySong(const char *filename) { this->Stop(); entry_ref midiRef; get_ref_for_path(filename, &midiRef); midiSynthFile.LoadFile(&midiRef); midiSynthFile.Start(); } void MusicDriver_BeMidi::StopSong() { midiSynthFile.UnloadFile(); } bool MusicDriver_BeMidi::IsSongPlaying() { return !midiSynthFile.IsFinished(); } void MusicDriver_BeMidi::SetVolume(byte vol) { fprintf(stderr, "BeMidi: Set volume not implemented\n"); } openttd-1.5.3/src/music/bemidi.h0000644000000000000000000000273112627373435015223 0ustar rootroot/* $Id: bemidi.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 bemidi.h Base of BeOS Midi support. */ #ifndef MUSIC_BEMIDI_H #define MUSIC_BEMIDI_H #include "music_driver.hpp" /** The midi player for BeOS. */ class MusicDriver_BeMidi : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "bemidi"; } }; /** Factory for the BeOS midi player. */ class FMusicDriver_BeMidi : public DriverFactoryBase { public: FMusicDriver_BeMidi() : DriverFactoryBase(Driver::DT_MUSIC, 10, "bemidi", "BeOS MIDI Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_BeMidi(); } }; #endif /* MUSIC_BEMIDI_H */ openttd-1.5.3/src/music/allegro_m.cpp0000644000000000000000000000435212627373435016267 0ustar rootroot/* $Id: allegro_m.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 allegro_m.cpp Playing music via allegro. */ #ifdef WITH_ALLEGRO #include "../stdafx.h" #include "../debug.h" #include "allegro_m.h" #include #include "../safeguards.h" static FMusicDriver_Allegro iFMusicDriver_Allegro; static MIDI *_midi = NULL; /** * There are multiple modules that might be using Allegro and * Allegro can only be initiated once. */ extern int _allegro_instance_count; const char *MusicDriver_Allegro::Start(const char * const *param) { if (_allegro_instance_count == 0 && install_allegro(SYSTEM_AUTODETECT, &errno, NULL)) { DEBUG(driver, 0, "allegro: install_allegro failed '%s'", allegro_error); return "Failed to set up Allegro"; } _allegro_instance_count++; /* Initialise the sound */ if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL) != 0) { DEBUG(driver, 0, "allegro: install_sound failed '%s'", allegro_error); return "Failed to set up Allegro sound"; } /* Okay, there's no soundcard */ if (midi_card == MIDI_NONE) { DEBUG(driver, 0, "allegro: no midi card found"); return "No sound card found"; } return NULL; } void MusicDriver_Allegro::Stop() { if (_midi != NULL) destroy_midi(_midi); _midi = NULL; if (--_allegro_instance_count == 0) allegro_exit(); } void MusicDriver_Allegro::PlaySong(const char *filename) { if (_midi != NULL) destroy_midi(_midi); _midi = load_midi(filename); play_midi(_midi, false); } void MusicDriver_Allegro::StopSong() { stop_midi(); } bool MusicDriver_Allegro::IsSongPlaying() { return midi_pos >= 0; } void MusicDriver_Allegro::SetVolume(byte vol) { set_volume(-1, vol); } #endif /* WITH_ALLEGRO */ openttd-1.5.3/src/music/libtimidity.h0000644000000000000000000000306012627373435016311 0ustar rootroot/* $Id: libtimidity.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 libtimidity.h Base for LibTimidity music playback. */ #ifndef MUSIC_LIBTIMIDITY_H #define MUSIC_LIBTIMIDITY_H #include "music_driver.hpp" /** Music driver making use of libtimidity. */ class MusicDriver_LibTimidity : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "libtimidity"; } }; /** Factory for the libtimidity driver. */ class FMusicDriver_LibTimidity : public DriverFactoryBase { public: FMusicDriver_LibTimidity() : DriverFactoryBase(Driver::DT_MUSIC, 5, "libtimidity", "LibTimidity MIDI Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_LibTimidity(); } }; #endif /* MUSIC_LIBTIMIDITY_H */ openttd-1.5.3/src/music/dmusic.cpp0000644000000000000000000001716512627373435015620 0ustar rootroot/* $Id: dmusic.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 dmusic.cpp Playing music via DirectMusic. */ #ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT #define INITGUID #include "../stdafx.h" #ifdef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN // Don't exclude rarely-used stuff from Windows headers #endif #include "../debug.h" #include "../os/windows/win32.h" #include "../core/mem_func.hpp" #include "dmusic.h" #include #include #include #include #include #include "../safeguards.h" static FMusicDriver_DMusic iFMusicDriver_DMusic; /** the direct music object manages buffers and ports */ static IDirectMusic *music = NULL; /** the performance object controls manipulation of the segments */ static IDirectMusicPerformance *performance = NULL; /** the loader object can load many types of DMusic related files */ static IDirectMusicLoader *loader = NULL; /** the segment object is where the MIDI data is stored for playback */ static IDirectMusicSegment *segment = NULL; static bool seeking = false; #define M(x) x "\0" static const char ole_files[] = M("ole32.dll") M("CoCreateInstance") M("CoInitialize") M("CoUninitialize") M("") ; #undef M struct ProcPtrs { unsigned long (WINAPI * CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv); HRESULT (WINAPI * CoInitialize)(LPVOID pvReserved); void (WINAPI * CoUninitialize)(); }; static ProcPtrs proc; const char *MusicDriver_DMusic::Start(const char * const *parm) { if (performance != NULL) return NULL; if (proc.CoCreateInstance == NULL) { if (!LoadLibraryList((Function*)&proc, ole_files)) { return "ole32.dll load failed"; } } /* Initialize COM */ if (FAILED(proc.CoInitialize(NULL))) { return "COM initialization failed"; } /* create the performance object */ if (FAILED(proc.CoCreateInstance( CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, IID_IDirectMusicPerformance, (LPVOID*)&performance ))) { return "Failed to create the performance object"; } /* initialize it */ if (FAILED(performance->Init(&music, NULL, NULL))) { return "Failed to initialize performance object"; } int port = GetDriverParamInt(parm, "port", -1); #ifndef NO_DEBUG_MESSAGES if (_debug_driver_level > 0) { /* Print all valid output ports. */ char desc[DMUS_MAX_DESCRIPTION]; DMUS_PORTCAPS caps; MemSetT(&caps, 0); caps.dwSize = sizeof(DMUS_PORTCAPS); DEBUG(driver, 1, "Detected DirectMusic ports:"); for (int i = 0; music->EnumPort(i, &caps) == S_OK; i++) { if (caps.dwClass == DMUS_PC_OUTPUTCLASS) { /* Description is UNICODE even for ANSI build. */ DEBUG(driver, 1, " %d: %s%s", i, convert_from_fs(caps.wszDescription, desc, lengthof(desc)), i == port ? " (selected)" : ""); } } } #endif IDirectMusicPort *music_port = NULL; // NULL means 'use default port'. if (port >= 0) { /* Check if the passed port is a valid port. */ DMUS_PORTCAPS caps; MemSetT(&caps, 0); caps.dwSize = sizeof(DMUS_PORTCAPS); if (FAILED(music->EnumPort(port, &caps))) return "Supplied port parameter is not a valid port"; if (caps.dwClass != DMUS_PC_OUTPUTCLASS) return "Supplied port parameter is not an output port"; /* Create new port. */ DMUS_PORTPARAMS params; MemSetT(¶ms, 0); params.dwSize = sizeof(DMUS_PORTPARAMS); params.dwValidParams = DMUS_PORTPARAMS_CHANNELGROUPS; params.dwChannelGroups = 1; if (FAILED(music->CreatePort(caps.guidPort, ¶ms, &music_port, NULL))) { return "Failed to create port"; } /* Activate port. */ if (FAILED(music_port->Activate(TRUE))) { music_port->Release(); return "Failed to activate port"; } } /* Add port to performance. */ if (FAILED(performance->AddPort(music_port))) { if (music_port != NULL) music_port->Release(); return "AddPort failed"; } /* Assign a performance channel block to the performance if we added * a custom port to the performance. */ if (music_port != NULL) { if (FAILED(performance->AssignPChannelBlock(0, music_port, 1))) { music_port->Release(); return "Failed to assign PChannel block"; } /* We don't need the port anymore. */ music_port->Release(); } /* create the loader object; this will be used to load the MIDI file */ if (FAILED(proc.CoCreateInstance( CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, IID_IDirectMusicLoader, (LPVOID*)&loader ))) { return "Failed to create loader object"; } return NULL; } MusicDriver_DMusic::~MusicDriver_DMusic() { this->Stop(); } void MusicDriver_DMusic::Stop() { seeking = false; if (performance != NULL) performance->Stop(NULL, NULL, 0, 0); if (segment != NULL) { segment->SetParam(GUID_Unload, 0xFFFFFFFF, 0, 0, performance); segment->Release(); segment = NULL; } if (music != NULL) { music->Release(); music = NULL; } if (performance != NULL) { performance->CloseDown(); performance->Release(); performance = NULL; } if (loader != NULL) { loader->Release(); loader = NULL; } proc.CoUninitialize(); } void MusicDriver_DMusic::PlaySong(const char *filename) { /* set up the loader object info */ DMUS_OBJECTDESC obj_desc; ZeroMemory(&obj_desc, sizeof(obj_desc)); obj_desc.dwSize = sizeof(obj_desc); obj_desc.guidClass = CLSID_DirectMusicSegment; obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME | DMUS_OBJ_FULLPATH; MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, filename, -1, obj_desc.wszFileName, lengthof(obj_desc.wszFileName) ); /* release the existing segment if we have any */ if (segment != NULL) { segment->Release(); segment = NULL; } /* make a new segment */ if (FAILED(loader->GetObject( &obj_desc, IID_IDirectMusicSegment, (LPVOID*)&segment ))) { DEBUG(driver, 0, "DirectMusic: GetObject failed"); return; } /* tell the segment what kind of data it contains */ if (FAILED(segment->SetParam( GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, performance ))) { DEBUG(driver, 0, "DirectMusic: SetParam (MIDI file) failed"); return; } /* tell the segment to 'download' the instruments */ if (FAILED(segment->SetParam(GUID_Download, 0xFFFFFFFF, 0, 0, performance))) { DEBUG(driver, 0, "DirectMusic: failed to download instruments"); return; } /* start playing the MIDI file */ if (FAILED(performance->PlaySegment(segment, 0, 0, NULL))) { DEBUG(driver, 0, "DirectMusic: PlaySegment failed"); return; } seeking = true; } void MusicDriver_DMusic::StopSong() { if (FAILED(performance->Stop(segment, NULL, 0, 0))) { DEBUG(driver, 0, "DirectMusic: StopSegment failed"); } seeking = false; } bool MusicDriver_DMusic::IsSongPlaying() { /* Not the nicest code, but there is a short delay before playing actually * starts. OpenTTD makes no provision for this. */ if (performance->IsPlaying(segment, NULL) == S_OK) { seeking = false; return true; } else { return seeking; } } void MusicDriver_DMusic::SetVolume(byte vol) { long db = vol * 2000 / 127 - 2000; ///< 0 - 127 -> -2000 - 0 performance->SetGlobalParam(GUID_PerfMasterVolume, &db, sizeof(db)); } #endif /* WIN32_ENABLE_DIRECTMUSIC_SUPPORT */ openttd-1.5.3/src/music/cocoa_m.cpp0000644000000000000000000001422712627373435015730 0ustar rootroot/* $Id: cocoa_m.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cocoa_m.cpp * @brief MIDI music player for MacOS X using CoreAudio. */ #ifdef WITH_COCOA #include "../stdafx.h" #include "../os/macosx/macos.h" #include "cocoa_m.h" #include "../debug.h" #define Rect OTTDRect #define Point OTTDPoint #include #include #include #undef Rect #undef Point #include "../safeguards.h" static FMusicDriver_Cocoa iFMusicDriver_Cocoa; static MusicPlayer _player = NULL; static MusicSequence _sequence = NULL; static MusicTimeStamp _seq_length = 0; static bool _playing = false; static byte _volume = 127; /** Set the volume of the current sequence. */ static void DoSetVolume() { if (_sequence == NULL) return; AUGraph graph; MusicSequenceGetAUGraph(_sequence, &graph); AudioUnit output_unit = NULL; /* Get output audio unit */ UInt32 node_count = 0; AUGraphGetNodeCount(graph, &node_count); for (UInt32 i = 0; i < node_count; i++) { AUNode node; AUGraphGetIndNode(graph, i, &node); AudioUnit unit; OSType comp_type = 0; #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) if (MacOSVersionIsAtLeast(10, 5, 0)) { /* The 10.6 SDK has changed the function prototype of * AUGraphNodeInfo. This is a binary compatible change, * but we need to get the type declaration right or * risk compilation errors. The header AudioComponent.h * was introduced in 10.6 so use it to decide which * type definition to use. */ #ifdef __AUDIOCOMPONENT_H__ AudioComponentDescription desc; #else ComponentDescription desc; #endif AUGraphNodeInfo(graph, node, &desc, &unit); comp_type = desc.componentType; } else #endif { #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) ComponentDescription desc; AUGraphGetNodeInfo(graph, node, &desc, NULL, NULL, &unit); comp_type = desc.componentType; #endif } if (comp_type == kAudioUnitType_Output) { output_unit = unit; break; } } if (output_unit == NULL) { DEBUG(driver, 1, "cocoa_m: Failed to get output node to set volume"); return; } Float32 vol = _volume / 127.0f; // 0 - +127 -> 0.0 - 1.0 AudioUnitSetParameter(output_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, vol, 0); } /** * Initialized the MIDI player, including QuickTime initialization. */ const char *MusicDriver_Cocoa::Start(const char * const *parm) { if (NewMusicPlayer(&_player) != noErr) return "failed to create music player"; return NULL; } /** * Checks wether the player is active. */ bool MusicDriver_Cocoa::IsSongPlaying() { if (!_playing) return false; MusicTimeStamp time = 0; MusicPlayerGetTime(_player, &time); return time < _seq_length; } /** * Stops the MIDI player. */ void MusicDriver_Cocoa::Stop() { if (_player != NULL) DisposeMusicPlayer(_player); if (_sequence != NULL) DisposeMusicSequence(_sequence); } /** * Starts playing a new song. * * @param filename Path to a MIDI file. */ void MusicDriver_Cocoa::PlaySong(const char *filename) { DEBUG(driver, 2, "cocoa_m: trying to play '%s'", filename); this->StopSong(); if (_sequence != NULL) { DisposeMusicSequence(_sequence); _sequence = NULL; } if (NewMusicSequence(&_sequence) != noErr) { DEBUG(driver, 0, "cocoa_m: Failed to create music sequence"); return; } const char *os_file = OTTD2FS(filename); CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)os_file, strlen(os_file), false); #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) if (MacOSVersionIsAtLeast(10, 5, 0)) { if (MusicSequenceFileLoad(_sequence, url, 0, 0) != noErr) { DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file"); CFRelease(url); return; } } else #endif { #if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) FSRef ref_file; if (!CFURLGetFSRef(url, &ref_file)) { DEBUG(driver, 0, "cocoa_m: Failed to make FSRef"); CFRelease(url); return; } if (MusicSequenceLoadSMFWithFlags(_sequence, &ref_file, 0) != noErr) { DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file old style"); CFRelease(url); return; } #endif } CFRelease(url); /* Construct audio graph */ AUGraph graph = NULL; MusicSequenceGetAUGraph(_sequence, &graph); AUGraphOpen(graph); if (AUGraphInitialize(graph) != noErr) { DEBUG(driver, 0, "cocoa_m: Failed to initialize AU graph"); return; } /* Figure out sequence length */ UInt32 num_tracks; MusicSequenceGetTrackCount(_sequence, &num_tracks); _seq_length = 0; for (UInt32 i = 0; i < num_tracks; i++) { MusicTrack track = NULL; MusicTimeStamp track_length = 0; UInt32 prop_size = sizeof(MusicTimeStamp); MusicSequenceGetIndTrack(_sequence, i, &track); MusicTrackGetProperty(track, kSequenceTrackProperty_TrackLength, &track_length, &prop_size); if (track_length > _seq_length) _seq_length = track_length; } /* Add 8 beats for reverb/long note release */ _seq_length += 8; DoSetVolume(); MusicPlayerSetSequence(_player, _sequence); MusicPlayerPreroll(_player); if (MusicPlayerStart(_player) != noErr) return; _playing = true; DEBUG(driver, 3, "cocoa_m: playing '%s'", filename); } /** * Stops playing the current song, if the player is active. */ void MusicDriver_Cocoa::StopSong() { MusicPlayerStop(_player); MusicPlayerSetSequence(_player, NULL); _playing = false; } /** * Changes the playing volume of the MIDI player. * * @param vol The desired volume, range of the value is @c 0-127 */ void MusicDriver_Cocoa::SetVolume(byte vol) { _volume = vol; DoSetVolume(); } #endif /* WITH_COCOA */ openttd-1.5.3/src/music/cocoa_m.h0000644000000000000000000000265112627373435015373 0ustar rootroot/* $Id: cocoa_m.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 cocoa_m.h Base of music playback via CoreAudio. */ #ifndef MUSIC_MACOSX_COCOA_H #define MUSIC_MACOSX_COCOA_H #include "music_driver.hpp" class MusicDriver_Cocoa : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "cocoa"; } }; class FMusicDriver_Cocoa : public DriverFactoryBase { public: FMusicDriver_Cocoa() : DriverFactoryBase(Driver::DT_MUSIC, 10, "cocoa", "Cocoa MIDI Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Cocoa(); } }; #endif /* MUSIC_MACOSX_COCOA_H */ openttd-1.5.3/src/music/extmidi.cpp0000644000000000000000000000712112627373435015766 0ustar rootroot/* $Id: extmidi.cpp 26556 2014-05-03 20:21:01Z rubidium $ */ /* * 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 extmidi.cpp Playing music via an external player. */ #include "../stdafx.h" #include "../debug.h" #include "../string_func.h" #include "../sound/sound_driver.hpp" #include "../video/video_driver.hpp" #include "../gfx_func.h" #include "extmidi.h" #include #include #include #include #include #include #include #include "../safeguards.h" #ifndef EXTERNAL_PLAYER /** The default external midi player. */ #define EXTERNAL_PLAYER "timidity" #endif /** Factory for the midi player that uses external players. */ static FMusicDriver_ExtMidi iFMusicDriver_ExtMidi; const char *MusicDriver_ExtMidi::Start(const char * const * parm) { if (strcmp(VideoDriver::GetInstance()->GetName(), "allegro") == 0 || strcmp(SoundDriver::GetInstance()->GetName(), "allegro") == 0) { return "the extmidi driver does not work when Allegro is loaded."; } const char *command = GetDriverParam(parm, "cmd"); if (StrEmpty(command)) command = EXTERNAL_PLAYER; this->command = stredup(command); this->song[0] = '\0'; this->pid = -1; return NULL; } void MusicDriver_ExtMidi::Stop() { free(command); this->song[0] = '\0'; this->DoStop(); } void MusicDriver_ExtMidi::PlaySong(const char *filename) { strecpy(this->song, filename, lastof(this->song)); this->DoStop(); } void MusicDriver_ExtMidi::StopSong() { this->song[0] = '\0'; this->DoStop(); } bool MusicDriver_ExtMidi::IsSongPlaying() { if (this->pid != -1 && waitpid(this->pid, NULL, WNOHANG) == this->pid) { this->pid = -1; } if (this->pid == -1 && this->song[0] != '\0') this->DoPlay(); return this->pid != -1; } void MusicDriver_ExtMidi::SetVolume(byte vol) { DEBUG(driver, 1, "extmidi: set volume not implemented"); } void MusicDriver_ExtMidi::DoPlay() { this->pid = fork(); switch (this->pid) { case 0: { close(0); int d = open("/dev/null", O_RDONLY); if (d != -1 && dup2(d, 1) != -1 && dup2(d, 2) != -1) { #if defined(MIDI_ARG) execlp(this->command, "extmidi", MIDI_ARG, this->song, (char*)0); #else execlp(this->command, "extmidi", this->song, (char*)0); #endif } _exit(1); } case -1: DEBUG(driver, 0, "extmidi: couldn't fork: %s", strerror(errno)); /* FALL THROUGH */ default: this->song[0] = '\0'; break; } } void MusicDriver_ExtMidi::DoStop() { if (this->pid <= 0) return; /* First try to gracefully stop for about five seconds; * 5 seconds = 5000 milliseconds, 10 ms per cycle => 500 cycles. */ for (int i = 0; i < 500; i++) { kill(this->pid, SIGTERM); if (waitpid(this->pid, NULL, WNOHANG) == this->pid) { /* It has shut down, so we are done */ this->pid = -1; return; } /* Wait 10 milliseconds. */ CSleep(10); } DEBUG(driver, 0, "extmidi: gracefully stopping failed, trying the hard way"); /* Gracefully stopping failed. Do it the hard way * and wait till the process finally died. */ kill(this->pid, SIGKILL); waitpid(this->pid, NULL, 0); this->pid = -1; } openttd-1.5.3/src/music/null_m.cpp0000644000000000000000000000155712627373435015620 0ustar rootroot/* $Id: null_m.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 null_m.cpp The music playback that is silent. */ #include "../stdafx.h" #include "null_m.h" #include "../safeguards.h" /** The factory for the music player that does nothing. */ static FMusicDriver_Null iFMusicDriver_Null; openttd-1.5.3/src/music/qtmidi.cpp0000644000000000000000000002234312627373435015615 0ustar rootroot/* $Id: qtmidi.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 qtmidi.cpp * @brief MIDI music player for MacOS X using QuickTime. * * This music player should work in all MacOS X releases starting from 10.0, * as QuickTime is an integral part of the system since the old days of the * Motorola 68k-based Macintoshes. The only extra dependency apart from * QuickTime itself is Carbon, which is included since 10.0 as well. * * QuickTime gets fooled with the MIDI files from Transport Tycoon Deluxe * because of the @c .gm suffix. To force QuickTime to load the MIDI files * without the need of dealing with the individual QuickTime components * needed to play music (data source, MIDI parser, note allocators, * synthesizers and the like) some Carbon functions are used to set the file * type as seen by QuickTime, using @c FSpSetFInfo() (which modifies the * file's resource fork). */ #ifndef NO_QUICKTIME #include "../stdafx.h" #include "qtmidi.h" #include "../debug.h" #define Rect OTTDRect #define Point OTTDPoint #include #undef Rect #undef Point #include "../safeguards.h" static FMusicDriver_QtMidi iFMusicDriver_QtMidi; static const uint MIDI_TYPE = 'Midi'; ///< OSType code for MIDI songs. /** * Sets the @c OSType of a given file to @c 'Midi', but only if it's not * already set. * * @param *ref A @c FSSpec structure referencing a file. */ static void SetMIDITypeIfNeeded(const FSRef *ref) { FSCatalogInfo catalogInfo; assert(ref); if (noErr != FSGetCatalogInfo(ref, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, NULL)) return; if (!(catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) { FileInfo * const info = (FileInfo *) catalogInfo.finderInfo; if (info->fileType != MIDI_TYPE && !(info->finderFlags & kIsAlias)) { OSErr e; info->fileType = MIDI_TYPE; e = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo); if (e == noErr) { DEBUG(driver, 3, "qtmidi: changed filetype to 'Midi'"); } else { DEBUG(driver, 0, "qtmidi: changing filetype to 'Midi' failed - error %d", e); } } } } /** * Loads a MIDI file and returns it as a QuickTime Movie structure. * * @param *path String with the path of an existing MIDI file. * @param *moov Pointer to a @c Movie where the result will be stored. * @return Whether the file was loaded and the @c Movie successfully created. */ static bool LoadMovieForMIDIFile(const char *path, Movie *moov) { int fd; int ret; char magic[4]; FSRef fsref; FSSpec fsspec; short refnum = 0; short resid = 0; assert(path != NULL); assert(moov != NULL); DEBUG(driver, 2, "qtmidi: start loading '%s'...", path); /* * XXX Manual check for MIDI header ('MThd'), as I don't know how to make * QuickTime load MIDI files without a .mid suffix without knowing it's * a MIDI file and setting the OSType of the file to the 'Midi' value. * Perhaps ugly, but it seems that it does the Right Thing(tm). */ fd = open(path, O_RDONLY, 0); if (fd == -1) return false; ret = read(fd, magic, 4); close(fd); if (ret < 4) return false; DEBUG(driver, 3, "qtmidi: header is '%.4s'", magic); if (magic[0] != 'M' || magic[1] != 'T' || magic[2] != 'h' || magic[3] != 'd') { return false; } if (noErr != FSPathMakeRef((const UInt8 *) path, &fsref, NULL)) return false; SetMIDITypeIfNeeded(&fsref); if (noErr != FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL)) return false; if (OpenMovieFile(&fsspec, &refnum, fsRdPerm) != noErr) return false; DEBUG(driver, 3, "qtmidi: '%s' successfully opened", path); if (noErr != NewMovieFromFile(moov, refnum, &resid, NULL, newMovieActive | newMovieDontAskUnresolvedDataRefs, NULL)) { CloseMovieFile(refnum); return false; } DEBUG(driver, 3, "qtmidi: movie container created"); CloseMovieFile(refnum); return true; } /** * Flag which has the @c true value when QuickTime is available and * initialized. */ static bool _quicktime_started = false; /** * Initialize QuickTime if needed. This function sets the * #_quicktime_started flag to @c true if QuickTime is present in the system * and it was initialized properly. */ static void InitQuickTimeIfNeeded() { OSStatus dummy; if (_quicktime_started) return; DEBUG(driver, 2, "qtmidi: initializing Quicktime"); /* Be polite: check wether QuickTime is available and initialize it. */ _quicktime_started = (noErr == Gestalt(gestaltQuickTime, &dummy)) && (noErr == EnterMovies()); if (!_quicktime_started) DEBUG(driver, 0, "qtmidi: Quicktime initialization failed!"); } /** Possible states of the QuickTime music driver. */ enum QTStates { QT_STATE_IDLE, ///< No file loaded. QT_STATE_PLAY, ///< File loaded, playing. QT_STATE_STOP, ///< File loaded, stopped. }; static Movie _quicktime_movie; ///< Current QuickTime @c Movie. static byte _quicktime_volume = 127; ///< Current volume. static int _quicktime_state = QT_STATE_IDLE; ///< Current player state. /** * Maps OpenTTD volume to QuickTime notion of volume. */ #define VOLUME ((short)((0x00FF & _quicktime_volume) << 1)) /** * Initialized the MIDI player, including QuickTime initialization. * * @todo Give better error messages by inspecting error codes returned by * @c Gestalt() and @c EnterMovies(). Needs changes in * #InitQuickTimeIfNeeded. */ const char *MusicDriver_QtMidi::Start(const char * const *parm) { InitQuickTimeIfNeeded(); return (_quicktime_started) ? NULL : "can't initialize QuickTime"; } /** * Checks whether the player is active. * * This function is called at regular intervals from OpenTTD's main loop, so * we call @c MoviesTask() from here to let QuickTime do its work. */ bool MusicDriver_QtMidi::IsSongPlaying() { if (!_quicktime_started) return true; switch (_quicktime_state) { case QT_STATE_IDLE: case QT_STATE_STOP: /* Do nothing. */ break; case QT_STATE_PLAY: MoviesTask(_quicktime_movie, 0); /* Check wether movie ended. */ if (IsMovieDone(_quicktime_movie) || (GetMovieTime(_quicktime_movie, NULL) >= GetMovieDuration(_quicktime_movie))) { _quicktime_state = QT_STATE_STOP; } } return _quicktime_state == QT_STATE_PLAY; } /** * Stops the MIDI player. * * Stops playing and frees any used resources before returning. As it * deinitilizes QuickTime, the #_quicktime_started flag is set to @c false. */ void MusicDriver_QtMidi::Stop() { if (!_quicktime_started) return; DEBUG(driver, 2, "qtmidi: stopping driver..."); switch (_quicktime_state) { case QT_STATE_IDLE: DEBUG(driver, 3, "qtmidi: stopping not needed, already idle"); /* Do nothing. */ break; case QT_STATE_PLAY: StopSong(); /* FALL THROUGH */ case QT_STATE_STOP: DisposeMovie(_quicktime_movie); } ExitMovies(); _quicktime_started = false; } /** * Starts playing a new song. * * @param filename Path to a MIDI file. */ void MusicDriver_QtMidi::PlaySong(const char *filename) { if (!_quicktime_started) return; DEBUG(driver, 2, "qtmidi: trying to play '%s'", filename); switch (_quicktime_state) { case QT_STATE_PLAY: StopSong(); DEBUG(driver, 3, "qtmidi: previous tune stopped"); /* FALL THROUGH */ case QT_STATE_STOP: DisposeMovie(_quicktime_movie); DEBUG(driver, 3, "qtmidi: previous tune disposed"); _quicktime_state = QT_STATE_IDLE; /* FALL THROUGH */ case QT_STATE_IDLE: LoadMovieForMIDIFile(filename, &_quicktime_movie); SetMovieVolume(_quicktime_movie, VOLUME); StartMovie(_quicktime_movie); _quicktime_state = QT_STATE_PLAY; } DEBUG(driver, 3, "qtmidi: playing '%s'", filename); } /** * Stops playing the current song, if the player is active. */ void MusicDriver_QtMidi::StopSong() { if (!_quicktime_started) return; switch (_quicktime_state) { case QT_STATE_IDLE: /* FALL THROUGH */ case QT_STATE_STOP: DEBUG(driver, 3, "qtmidi: stop requested, but already idle"); /* Do nothing. */ break; case QT_STATE_PLAY: StopMovie(_quicktime_movie); _quicktime_state = QT_STATE_STOP; DEBUG(driver, 3, "qtmidi: player stopped"); } } /** * Changes the playing volume of the MIDI player. * * As QuickTime controls volume in a per-movie basis, the desired volume is * stored in #_quicktime_volume, and the volume is set here using the * #VOLUME macro, @b and when loading new song in #PlaySong. * * @param vol The desired volume, range of the value is @c 0-127 */ void MusicDriver_QtMidi::SetVolume(byte vol) { if (!_quicktime_started) return; _quicktime_volume = vol; DEBUG(driver, 2, "qtmidi: set volume to %u (%hi)", vol, VOLUME); switch (_quicktime_state) { case QT_STATE_IDLE: /* Do nothing. */ break; case QT_STATE_PLAY: case QT_STATE_STOP: SetMovieVolume(_quicktime_movie, VOLUME); } } #endif /* NO_QUICKTIME */ openttd-1.5.3/src/music/win32_m.cpp0000644000000000000000000001101212627373435015573 0ustar rootroot/* $Id: win32_m.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 win32_m.cpp Music playback for Windows. */ #include "../stdafx.h" #include "../string_func.h" #include "win32_m.h" #include #include #include "../safeguards.h" static struct { bool stop_song; bool terminate; bool playing; int new_vol; HANDLE wait_obj; HANDLE thread; UINT_PTR devid; char start_song[MAX_PATH]; } _midi; static FMusicDriver_Win32 iFMusicDriver_Win32; void MusicDriver_Win32::PlaySong(const char *filename) { assert(filename != NULL); strecpy(_midi.start_song, filename, lastof(_midi.start_song)); _midi.playing = true; _midi.stop_song = false; SetEvent(_midi.wait_obj); } void MusicDriver_Win32::StopSong() { if (_midi.playing) { _midi.stop_song = true; _midi.start_song[0] = '\0'; SetEvent(_midi.wait_obj); } } bool MusicDriver_Win32::IsSongPlaying() { return _midi.playing; } void MusicDriver_Win32::SetVolume(byte vol) { _midi.new_vol = vol; SetEvent(_midi.wait_obj); } static MCIERROR CDECL MidiSendCommand(const TCHAR *cmd, ...) { va_list va; TCHAR buf[512]; va_start(va, cmd); _vsntprintf(buf, lengthof(buf), cmd, va); va_end(va); return mciSendString(buf, NULL, 0, 0); } static bool MidiIntPlaySong(const char *filename) { MidiSendCommand(_T("close all")); if (MidiSendCommand(_T("open \"%s\" type sequencer alias song"), OTTD2FS(filename)) != 0) { /* Let's try the "short name" */ TCHAR buf[MAX_PATH]; if (GetShortPathName(OTTD2FS(filename), buf, MAX_PATH) == 0) return false; if (MidiSendCommand(_T("open \"%s\" type sequencer alias song"), buf) != 0) return false; } MidiSendCommand(_T("seek song to start wait")); return MidiSendCommand(_T("play song")) == 0; } static void MidiIntStopSong() { MidiSendCommand(_T("close all")); } static void MidiIntSetVolume(int vol) { DWORD v = (vol * 65535 / 127); midiOutSetVolume((HMIDIOUT)_midi.devid, v + (v << 16)); } static bool MidiIntIsSongPlaying() { char buf[16]; mciSendStringA("status song mode", buf, sizeof(buf), 0); return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; } static DWORD WINAPI MidiThread(LPVOID arg) { do { char *s; int vol; vol = _midi.new_vol; if (vol != -1) { _midi.new_vol = -1; MidiIntSetVolume(vol); } s = _midi.start_song; if (s[0] != '\0') { _midi.playing = MidiIntPlaySong(s); s[0] = '\0'; /* Delay somewhat in case we don't manage to play. */ if (!_midi.playing) WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 5000); } if (_midi.stop_song && _midi.playing) { _midi.stop_song = false; _midi.playing = false; MidiIntStopSong(); } if (_midi.playing && !MidiIntIsSongPlaying()) _midi.playing = false; WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000); } while (!_midi.terminate); MidiIntStopSong(); return 0; } const char *MusicDriver_Win32::Start(const char * const *parm) { MIDIOUTCAPS midicaps; UINT nbdev; UINT_PTR dev; char buf[16]; mciSendStringA("capability sequencer has audio", buf, lengthof(buf), 0); if (strcmp(buf, "true") != 0) return "MCI sequencer can't play audio"; memset(&_midi, 0, sizeof(_midi)); _midi.new_vol = -1; /* Get midi device */ _midi.devid = MIDI_MAPPER; for (dev = 0, nbdev = midiOutGetNumDevs(); dev < nbdev; dev++) { if (midiOutGetDevCaps(dev, &midicaps, sizeof(midicaps)) == 0 && (midicaps.dwSupport & MIDICAPS_VOLUME)) { _midi.devid = dev; break; } } if (NULL == (_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL))) return "Failed to create event"; /* The lpThreadId parameter of CreateThread (the last parameter) * may NOT be NULL on Windows 95, 98 and ME. */ DWORD threadId; if (NULL == (_midi.thread = CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId))) return "Failed to create thread"; return NULL; } void MusicDriver_Win32::Stop() { _midi.terminate = true; SetEvent(_midi.wait_obj); WaitForMultipleObjects(1, &_midi.thread, true, INFINITE); CloseHandle(_midi.wait_obj); CloseHandle(_midi.thread); } openttd-1.5.3/src/music/win32_m.h0000644000000000000000000000273212627373435015251 0ustar rootroot/* $Id: win32_m.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 win32_m.h Base for Windows music playback. */ #ifndef MUSIC_WIN32_H #define MUSIC_WIN32_H #include "music_driver.hpp" /** The Windows music player. */ class MusicDriver_Win32 : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "win32"; } }; /** Factory for Windows' music player. */ class FMusicDriver_Win32 : public DriverFactoryBase { public: FMusicDriver_Win32() : DriverFactoryBase(Driver::DT_MUSIC, 5, "win32", "Win32 Music Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Win32(); } }; #endif /* MUSIC_WIN32_H */ openttd-1.5.3/src/music/qtmidi.h0000644000000000000000000000267712627373435015272 0ustar rootroot/* $Id: qtmidi.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 qtmidi.h Base of music playback via the QuickTime driver. */ #ifndef MUSIC_MACOSX_QUICKTIME_H #define MUSIC_MACOSX_QUICKTIME_H #include "music_driver.hpp" class MusicDriver_QtMidi : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "qt"; } }; class FMusicDriver_QtMidi : public DriverFactoryBase { public: FMusicDriver_QtMidi() : DriverFactoryBase(Driver::DT_MUSIC, 5, "qt", "QuickTime MIDI Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_QtMidi(); } }; #endif /* MUSIC_MACOSX_QUICKTIME_H */ openttd-1.5.3/src/music/libtimidity.cpp0000644000000000000000000000760612627373435016656 0ustar rootroot/* $Id: libtimidity.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 libtimidity.cpp Playing music via the timidity library. */ #include "../stdafx.h" #include "../openttd.h" #include "../sound_type.h" #include "../debug.h" #include "libtimidity.h" #include #include #include #include #include #include #include #include #if defined(PSP) #include #endif /* PSP */ #include "../safeguards.h" /** The state of playing. */ enum MidiState { MIDI_STOPPED = 0, MIDI_PLAYING = 1, }; static struct { MidIStream *stream; MidSongOptions options; MidSong *song; MidiState status; uint32 song_length; uint32 song_position; } _midi; ///< Metadata about the midi we're playing. #if defined(PSP) static void AudioOutCallback(void *buf, unsigned int _reqn, void *userdata) { memset(buf, 0, _reqn * PSP_NUM_AUDIO_CHANNELS); if (_midi.status == MIDI_PLAYING) { mid_song_read_wave(_midi.song, buf, _reqn * PSP_NUM_AUDIO_CHANNELS); } } #endif /* PSP */ /** Factory for the libtimidity driver. */ static FMusicDriver_LibTimidity iFMusicDriver_LibTimidity; const char *MusicDriver_LibTimidity::Start(const char * const *param) { _midi.status = MIDI_STOPPED; _midi.song = NULL; if (mid_init(param == NULL ? NULL : const_cast(param[0])) < 0) { /* If init fails, it can be because no configuration was found. * If it was not forced via param, try to load it without a * configuration. Who knows that works. */ if (param != NULL || mid_init_no_config() < 0) { return "error initializing timidity"; } } DEBUG(driver, 1, "successfully initialised timidity"); _midi.options.rate = 44100; _midi.options.format = MID_AUDIO_S16LSB; _midi.options.channels = 2; #if defined(PSP) _midi.options.buffer_size = PSP_NUM_AUDIO_SAMPLES; #else _midi.options.buffer_size = _midi.options.rate; #endif #if defined(PSP) pspAudioInit(); pspAudioSetChannelCallback(_midi.options.channels, &AudioOutCallback, NULL); pspAudioSetVolume(_midi.options.channels, PSP_VOLUME_MAX, PSP_VOLUME_MAX); #endif /* PSP */ return NULL; } void MusicDriver_LibTimidity::Stop() { if (_midi.status == MIDI_PLAYING) this->StopSong(); mid_exit(); } void MusicDriver_LibTimidity::PlaySong(const char *filename) { this->StopSong(); _midi.stream = mid_istream_open_file(filename); if (_midi.stream == NULL) { DEBUG(driver, 0, "Could not open music file"); return; } _midi.song = mid_song_load(_midi.stream, &_midi.options); mid_istream_close(_midi.stream); _midi.song_length = mid_song_get_total_time(_midi.song); if (_midi.song == NULL) { DEBUG(driver, 1, "Invalid MIDI file"); return; } mid_song_start(_midi.song); _midi.status = MIDI_PLAYING; } void MusicDriver_LibTimidity::StopSong() { _midi.status = MIDI_STOPPED; /* mid_song_free cannot handle NULL! */ if (_midi.song != NULL) mid_song_free(_midi.song); _midi.song = NULL; } bool MusicDriver_LibTimidity::IsSongPlaying() { if (_midi.status == MIDI_PLAYING) { _midi.song_position = mid_song_get_time(_midi.song); if (_midi.song_position >= _midi.song_length) { _midi.status = MIDI_STOPPED; _midi.song_position = 0; } } return (_midi.status == MIDI_PLAYING); } void MusicDriver_LibTimidity::SetVolume(byte vol) { if (_midi.song != NULL) mid_song_set_volume(_midi.song, vol); } openttd-1.5.3/src/music/os2_m.h0000644000000000000000000000267112627373435015014 0ustar rootroot/* $Id: os2_m.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 os2_m.h Base for OS2 music playback. */ #ifndef MUSIC_OS2_H #define MUSIC_OS2_H #include "music_driver.hpp" /** OS/2's music player. */ class MusicDriver_OS2 : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "os2"; } }; /** Factory for OS/2's music player. */ class FMusicDriver_OS2 : public DriverFactoryBase { public: FMusicDriver_OS2() : DriverFactoryBase(Driver::DT_MUSIC, 10, "os2", "OS/2 Music Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_OS2(); } }; #endif /* MUSIC_OS2_H */ openttd-1.5.3/src/music/dmusic.h0000644000000000000000000000303312627373435015252 0ustar rootroot/* $Id: dmusic.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 dmusic.h Base of playing music via DirectMusic. */ #ifndef MUSIC_DMUSIC_H #define MUSIC_DMUSIC_H #include "music_driver.hpp" /** Music player making use of DirectX. */ class MusicDriver_DMusic : public MusicDriver { public: virtual ~MusicDriver_DMusic(); /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "dmusic"; } }; /** Factory for the DirectX music player. */ class FMusicDriver_DMusic : public DriverFactoryBase { public: FMusicDriver_DMusic() : DriverFactoryBase(Driver::DT_MUSIC, 10, "dmusic", "DirectMusic MIDI Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_DMusic(); } }; #endif /* MUSIC_DMUSIC_H */ openttd-1.5.3/src/music/allegro_m.h0000644000000000000000000000350012627373435015726 0ustar rootroot/* $Id: allegro_m.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 allegro_m.h Base support for playing music via allegro. */ #ifndef MUSIC_ALLEGRO_H #define MUSIC_ALLEGRO_H #include "music_driver.hpp" /** Allegro's music player. */ class MusicDriver_Allegro : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "allegro"; } }; /** Factory for allegro's music player. */ class FMusicDriver_Allegro : public DriverFactoryBase { public: #if !defined(WITH_SDL) && defined(WITH_ALLEGRO) /* If SDL is not compiled in but Allegro is, chances are quite big * that Allegro is going to be used. Then favour this sound driver * over extmidi because with extmidi we get crashes. */ static const int PRIORITY = 9; #else static const int PRIORITY = 2; #endif FMusicDriver_Allegro() : DriverFactoryBase(Driver::DT_MUSIC, PRIORITY, "allegro", "Allegro MIDI Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Allegro(); } }; #endif /* MUSIC_ALLEGRO_H */ openttd-1.5.3/src/music/extmidi.h0000644000000000000000000000303612627373435015434 0ustar rootroot/* $Id: extmidi.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 extmidi.h Base support for playing music via an external application. */ #ifndef MUSIC_EXTERNAL_H #define MUSIC_EXTERNAL_H #include "music_driver.hpp" class MusicDriver_ExtMidi : public MusicDriver { private: char *command; char song[MAX_PATH]; pid_t pid; void DoPlay(); void DoStop(); public: /* virtual */ const char *Start(const char * const *param); /* virtual */ void Stop(); /* virtual */ void PlaySong(const char *filename); /* virtual */ void StopSong(); /* virtual */ bool IsSongPlaying(); /* virtual */ void SetVolume(byte vol); /* virtual */ const char *GetName() const { return "extmidi"; } }; class FMusicDriver_ExtMidi : public DriverFactoryBase { public: FMusicDriver_ExtMidi() : DriverFactoryBase(Driver::DT_MUSIC, 3, "extmidi", "External MIDI Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_ExtMidi(); } }; #endif /* MUSIC_EXTERNAL_H */ openttd-1.5.3/src/music/os2_m.cpp0000644000000000000000000000430012627373435015336 0ustar rootroot/* $Id: os2_m.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 os2_m.cpp Music playback on OS/2. */ #include "../stdafx.h" #include "../openttd.h" #include "os2_m.h" #define INCL_DOS #define INCL_OS2MM #define INCL_WIN #include #include #include #include "../safeguards.h" /********************** * OS/2 MIDI PLAYER **********************/ /* Interesting how similar the MCI API in OS/2 is to the Win32 MCI API, * eh? Anyone would think they both came from the same place originally! ;) */ /** * Send a midi command. * @param cmd The command to send. * @return The result of sending it. */ static long CDECL MidiSendCommand(const char *cmd, ...) { va_list va; char buf[512]; va_start(va, cmd); vseprintf(buf, lastof(buf), cmd, va); va_end(va); return mciSendString(buf, NULL, 0, NULL, 0); } /** OS/2's music player's factory. */ static FMusicDriver_OS2 iFMusicDriver_OS2; void MusicDriver_OS2::PlaySong(const char *filename) { MidiSendCommand("close all"); if (MidiSendCommand("open %s type sequencer alias song", filename) != 0) { return; } MidiSendCommand("play song from 0"); } void MusicDriver_OS2::StopSong() { MidiSendCommand("close all"); } void MusicDriver_OS2::SetVolume(byte vol) { MidiSendCommand("set song audio volume %d", ((vol/127)*100)); } bool MusicDriver_OS2::IsSongPlaying() { char buf[16]; mciSendString("status song mode", buf, sizeof(buf), NULL, 0); return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; } const char *MusicDriver_OS2::Start(const char * const *parm) { return 0; } void MusicDriver_OS2::Stop() { MidiSendCommand("close all"); } openttd-1.5.3/src/music/music_driver.hpp0000644000000000000000000000312012627373435017016 0ustar rootroot/* $Id: music_driver.hpp 26538 2014-04-28 21:06:51Z rubidium $ */ /* * 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 music_driver.hpp Base for all music playback. */ #ifndef MUSIC_MUSIC_DRIVER_HPP #define MUSIC_MUSIC_DRIVER_HPP #include "../driver.h" /** Driver for all music playback. */ class MusicDriver : public Driver { public: /** * Play a particular song. * @param filename The name of file with the song to play. */ virtual void PlaySong(const char *filename) = 0; /** * Stop playing the current song. */ virtual void StopSong() = 0; /** * Are we currently playing a song? * @return True if a song is being played. */ virtual bool IsSongPlaying() = 0; /** * Set the volume, if possible. * @param vol The new volume. */ virtual void SetVolume(byte vol) = 0; /** * Get the currently active instance of the music driver. */ static MusicDriver *GetInstance() { return static_cast(*DriverFactoryBase::GetActiveDriver(Driver::DT_MUSIC)); } }; extern char *_ini_musicdriver; #endif /* MUSIC_MUSIC_DRIVER_HPP */ openttd-1.5.3/src/music/null_m.h0000644000000000000000000000300712627373435015255 0ustar rootroot/* $Id: null_m.h 26108 2013-11-25 14:30:22Z rubidium $ */ /* * 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 null_m.h Base for the silent music playback. */ #ifndef MUSIC_NULL_H #define MUSIC_NULL_H #include "music_driver.hpp" /** The music player that does nothing. */ class MusicDriver_Null : public MusicDriver { public: /* virtual */ const char *Start(const char * const *param) { return NULL; } /* virtual */ void Stop() { } /* virtual */ void PlaySong(const char *filename) { } /* virtual */ void StopSong() { } /* virtual */ bool IsSongPlaying() { return true; } /* virtual */ void SetVolume(byte vol) { } /* virtual */ const char *GetName() const { return "null"; } }; /** Factory for the null music player. */ class FMusicDriver_Null : public DriverFactoryBase { public: FMusicDriver_Null() : DriverFactoryBase(Driver::DT_MUSIC, 1, "null", "Null Music Driver") {} /* virtual */ Driver *CreateInstance() const { return new MusicDriver_Null(); } }; #endif /* MUSIC_NULL_H */ openttd-1.5.3/src/newgrf_airporttiles.cpp0000644000000000000000000002750612627373435017305 0ustar rootroot/* $Id: newgrf_airporttiles.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_airporttiles.cpp NewGRF handling of airport tiles. */ #include "stdafx.h" #include "debug.h" #include "newgrf_airporttiles.h" #include "newgrf_spritegroup.h" #include "newgrf_sound.h" #include "station_base.h" #include "water.h" #include "landscape.h" #include "company_base.h" #include "town.h" #include "table/strings.h" #include "table/airporttiles.h" #include "newgrf_animation_base.h" #include "safeguards.h" AirportTileSpec AirportTileSpec::tiles[NUM_AIRPORTTILES]; AirportTileOverrideManager _airporttile_mngr(NEW_AIRPORTTILE_OFFSET, NUM_AIRPORTTILES, INVALID_AIRPORTTILE); /** * Retrieve airport tile spec for the given airport tile * @param gfx index of airport tile * @return A pointer to the corresponding AirportTileSpec */ /* static */ const AirportTileSpec *AirportTileSpec::Get(StationGfx gfx) { /* should be assert(gfx < lengthof(tiles)), but that gives compiler warnings * since it's always true if the following holds: */ assert_compile(MAX_UVALUE(StationGfx) + 1 == lengthof(tiles)); return &AirportTileSpec::tiles[gfx]; } /** * Retrieve airport tile spec for the given airport tile. * @param tile The airport tile. * @return A pointer to the corresponding AirportTileSpec. */ /* static */ const AirportTileSpec *AirportTileSpec::GetByTile(TileIndex tile) { return AirportTileSpec::Get(GetAirportGfx(tile)); } /** * This function initializes the tile array of AirportTileSpec */ void AirportTileSpec::ResetAirportTiles() { memset(&AirportTileSpec::tiles, 0, sizeof(AirportTileSpec::tiles)); memcpy(&AirportTileSpec::tiles, &_origin_airporttile_specs, sizeof(_origin_airporttile_specs)); /* Reset any overrides that have been set. */ _airporttile_mngr.ResetOverride(); } void AirportTileOverrideManager::SetEntitySpec(const AirportTileSpec *airpts) { StationGfx airpt_id = this->AddEntityID(airpts->grf_prop.local_id, airpts->grf_prop.grffile->grfid, airpts->grf_prop.subst_id); if (airpt_id == invalid_ID) { grfmsg(1, "AirportTile.SetEntitySpec: Too many airport tiles allocated. Ignoring."); return; } memcpy(&AirportTileSpec::tiles[airpt_id], airpts, sizeof(*airpts)); /* Now add the overrides. */ for (int i = 0; i < max_offset; i++) { AirportTileSpec *overridden_airpts = &AirportTileSpec::tiles[i]; if (entity_overrides[i] != airpts->grf_prop.local_id || grfid_overrides[i] != airpts->grf_prop.grffile->grfid) continue; overridden_airpts->grf_prop.override = airpt_id; overridden_airpts->enabled = false; entity_overrides[i] = invalid_ID; grfid_overrides[i] = 0; } } /** * Do airporttile gfx ID translation for NewGRFs. * @param gfx the type to get the override for. * @return the gfx to actually work with. */ StationGfx GetTranslatedAirportTileID(StationGfx gfx) { const AirportTileSpec *it = AirportTileSpec::Get(gfx); return it->grf_prop.override == INVALID_AIRPORTTILE ? gfx : it->grf_prop.override; } /** * Based on newhouses/newindustries equivalent, but adapted for airports. * @param parameter from callback. It's in fact a pair of coordinates * @param tile TileIndex from which the callback was initiated * @param index of the industry been queried for * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8. * @return a construction of bits obeying the newgrf format */ static uint32 GetNearbyAirportTileInformation(byte parameter, TileIndex tile, StationID index, bool grf_version8) { if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required bool is_same_airport = (IsTileType(tile, MP_STATION) && IsAirport(tile) && GetStationIndex(tile) == index); return GetNearbyTileInformation(tile, grf_version8) | (is_same_airport ? 1 : 0) << 8; } /** * Make an analysis of a tile and check whether it belongs to the same * airport, and/or the same grf file * @param tile TileIndex of the tile to query * @param st Station to which to compare the tile to * @param cur_grfid GRFID of the current callback * @return value encoded as per NFO specs */ static uint32 GetAirportTileIDAtOffset(TileIndex tile, const Station *st, uint32 cur_grfid) { if (!st->TileBelongsToAirport(tile)) { return 0xFFFF; } StationGfx gfx = GetAirportGfx(tile); const AirportTileSpec *ats = AirportTileSpec::Get(gfx); if (gfx < NEW_AIRPORTTILE_OFFSET) { // Does it belongs to an old type? /* It is an old tile. We have to see if it's been overridden */ if (ats->grf_prop.override == INVALID_AIRPORTTILE) { // has it been overridden? return 0xFF << 8 | gfx; // no. Tag FF + the gfx id of that tile } /* Overridden */ const AirportTileSpec *tile_ovr = AirportTileSpec::Get(ats->grf_prop.override); if (tile_ovr->grf_prop.grffile->grfid == cur_grfid) { return tile_ovr->grf_prop.local_id; // same grf file } else { return 0xFFFE; // not the same grf file } } /* Not an 'old type' tile */ if (ats->grf_prop.spritegroup[0] != NULL) { // tile has a spritegroup ? if (ats->grf_prop.grffile->grfid == cur_grfid) { // same airport, same grf ? return ats->grf_prop.local_id; } else { return 0xFFFE; // Defined in another grf file } } /* The tile has no spritegroup */ return 0xFF << 8 | ats->grf_prop.subst_id; // so just give him the substitute } /* virtual */ uint32 AirportTileScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { assert(this->st != NULL); extern uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile); switch (variable) { /* Terrain type */ case 0x41: return GetTerrainType(this->tile); /* Current town zone of the tile in the nearest town */ case 0x42: return GetTownRadiusGroup(ClosestTownFromTile(this->tile, UINT_MAX), this->tile); /* Position relative to most northern airport tile. */ case 0x43: return GetRelativePosition(this->tile, this->st->airport.tile); /* Animation frame of tile */ case 0x44: return GetAnimationFrame(this->tile); /* Land info of nearby tiles */ case 0x60: return GetNearbyAirportTileInformation(parameter, this->tile, this->st->index, this->ro.grffile->grf_version >= 8); /* Animation stage of nearby tiles */ case 0x61: { TileIndex tile = GetNearbyTile(parameter, this->tile); if (this->st->TileBelongsToAirport(tile)) { return GetAnimationFrame(tile); } return UINT_MAX; } /* Get airport tile ID at offset */ case 0x62: return GetAirportTileIDAtOffset(GetNearbyTile(parameter, this->tile), this->st, this->ro.grffile->grfid); } DEBUG(grf, 1, "Unhandled airport tile variable 0x%X", variable); *available = false; return UINT_MAX; } /* virtual */ uint32 AirportTileScopeResolver::GetRandomBits() const { return (this->st == NULL ? 0 : this->st->random_bits) | (this->tile == INVALID_TILE ? 0 : GetStationTileRandomBits(this->tile) << 16); } /** * Constructor of the resolver for airport tiles. * @param ats Specification of the airport tiles. * @param tile %Tile for the callback, only valid for airporttile callbacks. * @param st Station of the airport for which the callback is run, or \c NULL for build gui. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ AirportTileResolverObject::AirportTileResolverObject(const AirportTileSpec *ats, TileIndex tile, Station *st, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(ats->grf_prop.grffile, callback, callback_param1, callback_param2), tiles_scope(*this, ats, tile, st) { this->root_spritegroup = ats->grf_prop.spritegroup[0]; } /** * Constructor of the scope resolver specific for airport tiles. * @param ats Specification of the airport tiles. * @param tile %Tile for the callback, only valid for airporttile callbacks. * @param st Station of the airport for which the callback is run, or \c NULL for build gui. */ AirportTileScopeResolver::AirportTileScopeResolver(ResolverObject &ro, const AirportTileSpec *ats, TileIndex tile, Station *st) : ScopeResolver(ro) { assert(st != NULL); this->st = st; this->airport_id = st->airport.type; this->tile = tile; } uint16 GetAirportTileCallback(CallbackID callback, uint32 param1, uint32 param2, const AirportTileSpec *ats, Station *st, TileIndex tile, int extra_data = 0) { AirportTileResolverObject object(ats, tile, st, callback, param1, param2); return object.ResolveCallback(); } static void AirportDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte colour, StationGfx gfx) { const DrawTileSprites *dts = group->ProcessRegisters(NULL); SpriteID image = dts->ground.sprite; SpriteID pal = dts->ground.pal; if (GB(image, 0, SPRITE_WIDTH) != 0) { if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) { DrawWaterClassGround(ti); } else { DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, GENERAL_SPRITE_COLOUR(colour))); } } DrawNewGRFTileSeq(ti, dts, TO_BUILDINGS, 0, GENERAL_SPRITE_COLOUR(colour)); } bool DrawNewAirportTile(TileInfo *ti, Station *st, StationGfx gfx, const AirportTileSpec *airts) { if (ti->tileh != SLOPE_FLAT) { bool draw_old_one = true; if (HasBit(airts->callback_mask, CBM_AIRT_DRAW_FOUNDATIONS)) { /* Called to determine the type (if any) of foundation to draw */ uint32 callback_res = GetAirportTileCallback(CBID_AIRPTILE_DRAW_FOUNDATIONS, 0, 0, airts, st, ti->tile); if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(airts->grf_prop.grffile, CBID_AIRPTILE_DRAW_FOUNDATIONS, callback_res); } if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED); } AirportTileResolverObject object(airts, ti->tile, st); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->type != SGT_TILELAYOUT) { return false; } const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group; AirportDrawTileLayout(ti, tlgroup, Company::Get(st->owner)->colour, gfx); return true; } /** Helper class for animation control. */ struct AirportTileAnimationBase : public AnimationBase { static const CallbackID cb_animation_speed = CBID_AIRPTILE_ANIMATION_SPEED; static const CallbackID cb_animation_next_frame = CBID_AIRPTILE_ANIM_NEXT_FRAME; static const AirportTileCallbackMask cbm_animation_speed = CBM_AIRT_ANIM_SPEED; static const AirportTileCallbackMask cbm_animation_next_frame = CBM_AIRT_ANIM_NEXT_FRAME; }; void AnimateAirportTile(TileIndex tile) { const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); if (ats == NULL) return; AirportTileAnimationBase::AnimateTile(ats, Station::GetByTile(tile), tile, HasBit(ats->animation_special_flags, 0)); } void AirportTileAnimationTrigger(Station *st, TileIndex tile, AirpAnimationTrigger trigger, CargoID cargo_type) { const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); if (!HasBit(ats->animation.triggers, trigger)) return; AirportTileAnimationBase::ChangeAnimationFrame(CBID_AIRPTILE_ANIM_START_STOP, ats, st, tile, Random(), (uint8)trigger | (cargo_type << 8)); } void AirportAnimationTrigger(Station *st, AirpAnimationTrigger trigger, CargoID cargo_type) { if (st->airport.tile == INVALID_TILE) return; TILE_AREA_LOOP(tile, st->airport) { if (st->TileBelongsToAirport(tile)) AirportTileAnimationTrigger(st, tile, trigger, cargo_type); } } openttd-1.5.3/src/settings_gui.cpp0000644000000000000000000031741512627373436015722 0ustar rootroot/* $Id: settings_gui.cpp 27430 2015-11-01 11:55:45Z frosch $ */ /* * 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 settings_gui.cpp GUI for settings. */ #include "stdafx.h" #include "currency.h" #include "error.h" #include "settings_gui.h" #include "textbuf_gui.h" #include "command_func.h" #include "network/network.h" #include "town.h" #include "settings_internal.h" #include "newgrf_townname.h" #include "strings_func.h" #include "window_func.h" #include "string_func.h" #include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" #include "highscore.h" #include "base_media_base.h" #include "company_base.h" #include "company_func.h" #include "viewport_func.h" #include "core/geometry_func.hpp" #include "ai/ai.hpp" #include "blitter/factory.hpp" #include "language.h" #include "textfile_gui.h" #include "stringfilter_type.h" #include "querystring_gui.h" #include #include "safeguards.h" static const StringID _driveside_dropdown[] = { STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT, STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT, INVALID_STRING_ID }; static const StringID _autosave_dropdown[] = { STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS, INVALID_STRING_ID, }; static const StringID _gui_zoom_dropdown[] = { STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL, STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM, STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM, INVALID_STRING_ID, }; int _nb_orig_names = SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1; ///< Number of original town names. static StringID *_grf_names = NULL; ///< Pointer to town names defined by NewGRFs. static int _nb_grf_names = 0; ///< Number of town names defined by NewGRFs. static Dimension _circle_size; ///< Dimension of the circle +/- icon. This is here as not all users are within the class of the settings window. static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd); /** Allocate memory for the NewGRF town names. */ void InitGRFTownGeneratorNames() { free(_grf_names); _grf_names = GetGRFTownNameList(); _nb_grf_names = 0; for (StringID *s = _grf_names; *s != INVALID_STRING_ID; s++) _nb_grf_names++; } /** * Get a town name. * @param town_name Number of the wanted town name. * @return Name of the town as string ID. */ static inline StringID TownName(int town_name) { if (town_name < _nb_orig_names) return STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + town_name; town_name -= _nb_orig_names; if (town_name < _nb_grf_names) return _grf_names[town_name]; return STR_UNDEFINED; } /** * Get index of the current screen resolution. * @return Index of the current screen resolution if it is a known resolution, #_num_resolutions otherwise. */ static int GetCurRes() { int i; for (i = 0; i != _num_resolutions; i++) { if ((int)_resolutions[i].width == _screen.width && (int)_resolutions[i].height == _screen.height) { break; } } return i; } static void ShowCustCurrency(); template static DropDownList *BuiltSetDropDownList(int *selected_index) { int n = T::GetNumSets(); *selected_index = T::GetIndexOfUsedSet(); DropDownList *list = new DropDownList(); for (int i = 0; i < n; i++) { *list->Append() = new DropDownListCharStringItem(T::GetSet(i)->name, i, (_game_mode == GM_MENU) ? false : (*selected_index != i)); } return list; } /** Window for displaying the textfile of a BaseSet. */ template struct BaseSetTextfileWindow : public TextfileWindow { const TBaseSet* baseset; ///< View the textfile of this BaseSet. StringID content_type; ///< STR_CONTENT_TYPE_xxx for title. BaseSetTextfileWindow(TextfileType file_type, const TBaseSet* baseset, StringID content_type) : TextfileWindow(file_type), baseset(baseset), content_type(content_type) { const char *textfile = this->baseset->GetTextfile(file_type); this->LoadTextfile(textfile, BASESET_DIR); } /* virtual */ void SetStringParameters(int widget) const { if (widget == WID_TF_CAPTION) { SetDParam(0, content_type); SetDParamStr(1, this->baseset->name); } } }; /** * Open the BaseSet version of the textfile window. * @param file_type The type of textfile to display. * @param baseset The BaseSet to use. * @param content_type STR_CONTENT_TYPE_xxx for title. */ template void ShowBaseSetTextfileWindow(TextfileType file_type, const TBaseSet* baseset, StringID content_type) { DeleteWindowByClass(WC_TEXTFILE); new BaseSetTextfileWindow(file_type, baseset, content_type); } struct GameOptionsWindow : Window { GameSettings *opt; bool reload; GameOptionsWindow(WindowDesc *desc) : Window(desc) { this->opt = &GetGameSettings(); this->reload = false; this->InitNested(WN_GAME_OPTIONS_GAME_OPTIONS); this->OnInvalidateData(0); } ~GameOptionsWindow() { DeleteWindowById(WC_CUSTOM_CURRENCY, 0); if (this->reload) _switch_mode = SM_MENU; } /** * Build the dropdown list for a specific widget. * @param widget Widget to build list for * @param selected_index Currently selected item * @return the built dropdown list, or NULL if the widget has no dropdown menu. */ DropDownList *BuildDropDownList(int widget, int *selected_index) const { DropDownList *list = NULL; switch (widget) { case WID_GO_CURRENCY_DROPDOWN: { // Setup currencies dropdown list = new DropDownList(); *selected_index = this->opt->locale.currency; StringID *items = BuildCurrencyDropdown(); uint64 disabled = _game_mode == GM_MENU ? 0LL : ~GetMaskOfAllowedCurrencies(); /* Add non-custom currencies; sorted naturally */ for (uint i = 0; i < CURRENCY_END; items++, i++) { if (i == CURRENCY_CUSTOM) continue; *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); } QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); /* Append custom currency at the end */ *list->Append() = new DropDownListItem(-1, false); // separator line *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_CURRENCY_CUSTOM, CURRENCY_CUSTOM, HasBit(disabled, CURRENCY_CUSTOM)); break; } case WID_GO_ROADSIDE_DROPDOWN: { // Setup road-side dropdown list = new DropDownList(); *selected_index = this->opt->vehicle.road_side; const StringID *items = _driveside_dropdown; uint disabled = 0; /* You can only change the drive side if you are in the menu or ingame with * no vehicles present. In a networking game only the server can change it */ extern bool RoadVehiclesAreBuilt(); if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) { disabled = ~(1 << this->opt->vehicle.road_side); // disable the other value } for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { *list->Append() = new DropDownListStringItem(*items, i, HasBit(disabled, i)); } break; } case WID_GO_TOWNNAME_DROPDOWN: { // Setup townname dropdown list = new DropDownList(); *selected_index = this->opt->game_creation.town_name; int enabled_item = (_game_mode == GM_MENU || Town::GetNumItems() == 0) ? -1 : *selected_index; /* Add and sort newgrf townnames generators */ for (int i = 0; i < _nb_grf_names; i++) { int result = _nb_orig_names + i; *list->Append() = new DropDownListStringItem(_grf_names[i], result, enabled_item != result && enabled_item >= 0); } QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); int newgrf_size = list->Length(); /* Insert newgrf_names at the top of the list */ if (newgrf_size > 0) { *list->Append() = new DropDownListItem(-1, false); // separator line newgrf_size++; } /* Add and sort original townnames generators */ for (int i = 0; i < _nb_orig_names; i++) { *list->Append() = new DropDownListStringItem(STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH + i, i, enabled_item != i && enabled_item >= 0); } QSortT(list->Begin() + newgrf_size, list->Length() - newgrf_size, DropDownListStringItem::NatSortFunc); break; } case WID_GO_AUTOSAVE_DROPDOWN: { // Setup autosave dropdown list = new DropDownList(); *selected_index = _settings_client.gui.autosave; const StringID *items = _autosave_dropdown; for (uint i = 0; *items != INVALID_STRING_ID; items++, i++) { *list->Append() = new DropDownListStringItem(*items, i, false); } break; } case WID_GO_LANG_DROPDOWN: { // Setup interface language dropdown list = new DropDownList(); for (uint i = 0; i < _languages.Length(); i++) { if (&_languages[i] == _current_language) *selected_index = i; *list->Append() = new DropDownListStringItem(SPECSTR_LANGUAGE_START + i, i, false); } QSortT(list->Begin(), list->Length(), DropDownListStringItem::NatSortFunc); break; } case WID_GO_RESOLUTION_DROPDOWN: // Setup resolution dropdown if (_num_resolutions == 0) break; list = new DropDownList(); *selected_index = GetCurRes(); for (int i = 0; i < _num_resolutions; i++) { *list->Append() = new DropDownListStringItem(SPECSTR_RESOLUTION_START + i, i, false); } break; case WID_GO_GUI_ZOOM_DROPDOWN: { list = new DropDownList(); *selected_index = ZOOM_LVL_OUT_4X - _gui_zoom; const StringID *items = _gui_zoom_dropdown; for (int i = 0; *items != INVALID_STRING_ID; items++, i++) { *list->Append() = new DropDownListStringItem(*items, i, _settings_client.gui.zoom_min > ZOOM_LVL_OUT_4X - i); } break; } case WID_GO_BASE_GRF_DROPDOWN: list = BuiltSetDropDownList(selected_index); break; case WID_GO_BASE_SFX_DROPDOWN: list = BuiltSetDropDownList(selected_index); break; case WID_GO_BASE_MUSIC_DROPDOWN: list = BuiltSetDropDownList(selected_index); break; default: return NULL; } return list; } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_GO_CURRENCY_DROPDOWN: SetDParam(0, _currency_specs[this->opt->locale.currency].name); break; case WID_GO_ROADSIDE_DROPDOWN: SetDParam(0, STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT + this->opt->vehicle.road_side); break; case WID_GO_TOWNNAME_DROPDOWN: SetDParam(0, TownName(this->opt->game_creation.town_name)); break; case WID_GO_AUTOSAVE_DROPDOWN: SetDParam(0, _autosave_dropdown[_settings_client.gui.autosave]); break; case WID_GO_LANG_DROPDOWN: SetDParamStr(0, _current_language->own_name); break; case WID_GO_RESOLUTION_DROPDOWN: SetDParam(0, GetCurRes() == _num_resolutions ? STR_GAME_OPTIONS_RESOLUTION_OTHER : SPECSTR_RESOLUTION_START + GetCurRes()); break; case WID_GO_GUI_ZOOM_DROPDOWN: SetDParam(0, _gui_zoom_dropdown[ZOOM_LVL_OUT_4X - _gui_zoom]); break; case WID_GO_BASE_GRF_DROPDOWN: SetDParamStr(0, BaseGraphics::GetUsedSet()->name); break; case WID_GO_BASE_GRF_STATUS: SetDParam(0, BaseGraphics::GetUsedSet()->GetNumInvalid()); break; case WID_GO_BASE_SFX_DROPDOWN: SetDParamStr(0, BaseSounds::GetUsedSet()->name); break; case WID_GO_BASE_MUSIC_DROPDOWN: SetDParamStr(0, BaseMusic::GetUsedSet()->name); break; case WID_GO_BASE_MUSIC_STATUS: SetDParam(0, BaseMusic::GetUsedSet()->GetNumInvalid()); break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_GO_BASE_GRF_DESCRIPTION: SetDParamStr(0, BaseGraphics::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); break; case WID_GO_BASE_SFX_DESCRIPTION: SetDParamStr(0, BaseSounds::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); break; case WID_GO_BASE_MUSIC_DESCRIPTION: SetDParamStr(0, BaseMusic::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_BLACK_RAW_STRING); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_GO_BASE_GRF_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { SetDParamStr(0, BaseGraphics::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; case WID_GO_BASE_GRF_STATUS: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseGraphics::GetNumSets(); i++) { uint invalid_files = BaseGraphics::GetSet(i)->GetNumInvalid(); if (invalid_files == 0) continue; SetDParam(0, invalid_files); *size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_GRF_STATUS)); } break; case WID_GO_BASE_SFX_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseSounds::GetNumSets(); i++) { SetDParamStr(0, BaseSounds::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; case WID_GO_BASE_MUSIC_DESCRIPTION: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseMusic::GetNumSets(); i++) { SetDParamStr(0, BaseMusic::GetSet(i)->GetDescription(GetCurrentLanguageIsoCode())); size->height = max(size->height, (uint)GetStringHeight(STR_BLACK_RAW_STRING, size->width)); } break; case WID_GO_BASE_MUSIC_STATUS: /* Find the biggest description for the default size. */ for (int i = 0; i < BaseMusic::GetNumSets(); i++) { uint invalid_files = BaseMusic::GetSet(i)->GetNumInvalid(); if (invalid_files == 0) continue; SetDParam(0, invalid_files); *size = maxdim(*size, GetStringBoundingBox(STR_GAME_OPTIONS_BASE_MUSIC_STATUS)); } break; default: { int selected; DropDownList *list = this->BuildDropDownList(widget, &selected); if (list != NULL) { /* Find the biggest item for the default size. */ for (const DropDownListItem * const *it = list->Begin(); it != list->End(); it++) { Dimension string_dim; int width = (*it)->Width(); string_dim.width = width + padding.width; string_dim.height = (*it)->Height(width) + padding.height; *size = maxdim(*size, string_dim); } delete list; } } } } virtual void OnClick(Point pt, int widget, int click_count) { if (widget >= WID_GO_BASE_GRF_TEXTFILE && widget < WID_GO_BASE_GRF_TEXTFILE + TFT_END) { if (BaseGraphics::GetUsedSet() == NULL) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_GRF_TEXTFILE), BaseGraphics::GetUsedSet(), STR_CONTENT_TYPE_BASE_GRAPHICS); return; } if (widget >= WID_GO_BASE_SFX_TEXTFILE && widget < WID_GO_BASE_SFX_TEXTFILE + TFT_END) { if (BaseSounds::GetUsedSet() == NULL) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_SFX_TEXTFILE), BaseSounds::GetUsedSet(), STR_CONTENT_TYPE_BASE_SOUNDS); return; } if (widget >= WID_GO_BASE_MUSIC_TEXTFILE && widget < WID_GO_BASE_MUSIC_TEXTFILE + TFT_END) { if (BaseMusic::GetUsedSet() == NULL) return; ShowBaseSetTextfileWindow((TextfileType)(widget - WID_GO_BASE_MUSIC_TEXTFILE), BaseMusic::GetUsedSet(), STR_CONTENT_TYPE_BASE_MUSIC); return; } switch (widget) { case WID_GO_FULLSCREEN_BUTTON: // Click fullscreen on/off /* try to toggle full-screen on/off */ if (!ToggleFullScreen(!_fullscreen)) { ShowErrorMessage(STR_ERROR_FULLSCREEN_FAILED, INVALID_STRING_ID, WL_ERROR); } this->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); this->SetDirty(); break; default: { int selected; DropDownList *list = this->BuildDropDownList(widget, &selected); if (list != NULL) { ShowDropDownList(this, list, selected, widget); } else { if (widget == WID_GO_RESOLUTION_DROPDOWN) ShowErrorMessage(STR_ERROR_RESOLUTION_LIST_FAILED, INVALID_STRING_ID, WL_ERROR); } break; } } } /** * Set the base media set. * @param index the index of the media set * @tparam T class of media set */ template void SetMediaSet(int index) { if (_game_mode == GM_MENU) { const char *name = T::GetSet(index)->name; free(T::ini_set); T::ini_set = stredup(name); T::SetSet(name); this->reload = true; this->InvalidateData(); } } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_GO_CURRENCY_DROPDOWN: // Currency if (index == CURRENCY_CUSTOM) ShowCustCurrency(); this->opt->locale.currency = index; ReInitAllWindows(); break; case WID_GO_ROADSIDE_DROPDOWN: // Road side if (this->opt->vehicle.road_side != index) { // only change if setting changed uint i; if (GetSettingFromName("vehicle.road_side", &i) == NULL) NOT_REACHED(); SetSettingValue(i, index); MarkWholeScreenDirty(); } break; case WID_GO_TOWNNAME_DROPDOWN: // Town names if (_game_mode == GM_MENU || Town::GetNumItems() == 0) { this->opt->game_creation.town_name = index; SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_GAME_OPTIONS); } break; case WID_GO_AUTOSAVE_DROPDOWN: // Autosave options _settings_client.gui.autosave = index; this->SetDirty(); break; case WID_GO_LANG_DROPDOWN: // Change interface language ReadLanguagePack(&_languages[index]); DeleteWindowByClass(WC_QUERY_STRING); CheckForMissingGlyphs(); UpdateAllVirtCoords(); ReInitAllWindows(); break; case WID_GO_RESOLUTION_DROPDOWN: // Change resolution if (index < _num_resolutions && ChangeResInGame(_resolutions[index].width, _resolutions[index].height)) { this->SetDirty(); } break; case WID_GO_GUI_ZOOM_DROPDOWN: GfxClearSpriteCache(); _gui_zoom = (ZoomLevel)(ZOOM_LVL_OUT_4X - index); UpdateCursorSize(); LoadStringWidthTable(); break; case WID_GO_BASE_GRF_DROPDOWN: this->SetMediaSet(index); break; case WID_GO_BASE_SFX_DROPDOWN: this->SetMediaSet(index); break; case WID_GO_BASE_MUSIC_DROPDOWN: this->SetMediaSet(index); break; } } /** * Some data on this window has become invalid. * @param data Information about the changed data. @see GameOptionsInvalidationData * @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->SetWidgetLoweredState(WID_GO_FULLSCREEN_BUTTON, _fullscreen); bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) { this->SetWidgetDisabledState(WID_GO_BASE_GRF_TEXTFILE + tft, BaseGraphics::GetUsedSet() == NULL || BaseGraphics::GetUsedSet()->GetTextfile(tft) == NULL); this->SetWidgetDisabledState(WID_GO_BASE_SFX_TEXTFILE + tft, BaseSounds::GetUsedSet() == NULL || BaseSounds::GetUsedSet()->GetTextfile(tft) == NULL); this->SetWidgetDisabledState(WID_GO_BASE_MUSIC_TEXTFILE + tft, BaseMusic::GetUsedSet() == NULL || BaseMusic::GetUsedSet()->GetTextfile(tft) == NULL); } missing_files = BaseMusic::GetUsedSet()->GetNumInvalid() == 0; this->GetWidget(WID_GO_BASE_MUSIC_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_MUSIC_STATUS, STR_NULL); } }; static const NWidgetPart _nested_game_options_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_GO_BACKGROUND), SetPIP(6, 6, 10), NWidget(NWID_HORIZONTAL), SetPIP(10, 10, 10), NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_ROADSIDE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_AUTOSAVE_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_AUTOSAVE_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_RESOLUTION, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_RESOLUTION_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_RESOLUTION_TOOLTIP), SetFill(1, 0), SetPadding(0, 0, 3, 0), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetDataTip(STR_GAME_OPTIONS_FULLSCREEN, STR_NULL), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GO_FULLSCREEN_BUTTON), SetMinimalSize(21, 9), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP), EndContainer(), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_GUI_ZOOM_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_GUI_ZOOM_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 6, 0), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_TOWN_NAMES_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_TOWNNAME_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_LANGUAGE, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_LANG_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_LANGUAGE_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_CURRENCY_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_STRING, STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 0), SetFill(0, 1), EndContainer(), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_GRF, STR_NULL), SetPadding(0, 10, 0, 10), NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_GRF_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_GRF_TOOLTIP), NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), EndContainer(), NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_GRF_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_GRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_SFX, STR_NULL), SetPadding(0, 10, 0, 10), NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_SFX_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_SFX_TOOLTIP), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_SFX_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_SFX_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), EndContainer(), NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_GAME_OPTIONS_BASE_MUSIC, STR_NULL), SetPadding(0, 10, 0, 10), NWidget(NWID_HORIZONTAL), SetPIP(0, 30, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GO_BASE_MUSIC_DROPDOWN), SetMinimalSize(150, 12), SetDataTip(STR_BLACK_RAW_STRING, STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP), NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_STATUS), SetMinimalSize(150, 12), SetDataTip(STR_EMPTY, STR_NULL), SetFill(1, 0), EndContainer(), NWidget(WWT_TEXT, COLOUR_GREY, WID_GO_BASE_MUSIC_DESCRIPTION), SetMinimalSize(330, 0), SetDataTip(STR_EMPTY, STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP), SetFill(1, 0), SetPadding(6, 0, 6, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GO_BASE_MUSIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _game_options_desc( WDP_CENTER, "settings_game", 0, 0, WC_GAME_OPTIONS, WC_NONE, 0, _nested_game_options_widgets, lengthof(_nested_game_options_widgets) ); /** Open the game options window. */ void ShowGameOptions() { DeleteWindowByClass(WC_GAME_OPTIONS); new GameOptionsWindow(&_game_options_desc); } static int SETTING_HEIGHT = 11; ///< Height of a single setting in the tree view in pixels static const int LEVEL_WIDTH = 15; ///< Indenting width of a sub-page in pixels /** * Flags for #SettingEntry * @note The #SEF_BUTTONS_MASK matches expectations of the formal parameter 'state' of #DrawArrowButtons */ enum SettingEntryFlags { SEF_LEFT_DEPRESSED = 0x01, ///< Of a numeric setting entry, the left button is depressed SEF_RIGHT_DEPRESSED = 0x02, ///< Of a numeric setting entry, the right button is depressed SEF_BUTTONS_MASK = (SEF_LEFT_DEPRESSED | SEF_RIGHT_DEPRESSED), ///< Bit-mask for button flags SEF_LAST_FIELD = 0x04, ///< This entry is the last one in a (sub-)page SEF_FILTERED = 0x08, ///< Entry is hidden by the string filter }; /** How the list of advanced settings is filtered. */ enum RestrictionMode { RM_BASIC, ///< Display settings associated to the "basic" list. RM_ADVANCED, ///< Display settings associated to the "advanced" list. RM_ALL, ///< List all settings regardless of the default/newgame/... values. RM_CHANGED_AGAINST_DEFAULT, ///< Show only settings which are different compared to default values. RM_CHANGED_AGAINST_NEW, ///< Show only settings which are different compared to the user's new game setting values. RM_END, ///< End for iteration. }; DECLARE_POSTFIX_INCREMENT(RestrictionMode) /** Filter for settings list. */ struct SettingFilter { StringFilter string; ///< Filter string. RestrictionMode min_cat; ///< Minimum category needed to display all filtered strings (#RM_BASIC, #RM_ADVANCED, or #RM_ALL). bool type_hides; ///< Whether the type hides filtered strings. RestrictionMode mode; ///< Filter based on category. SettingType type; ///< Filter based on type. }; /** Data structure describing a single setting in a tab */ struct BaseSettingEntry { byte flags; ///< Flags of the setting entry. @see SettingEntryFlags byte level; ///< Nesting level of this setting entry BaseSettingEntry() : flags(0), level(0) {} virtual ~BaseSettingEntry() {} virtual void Init(byte level = 0); virtual void FoldAll() {} virtual void UnFoldAll() {} /** * Set whether this is the last visible entry of the parent node. * @param last_field Value to set */ void SetLastField(bool last_field) { if (last_field) SETBITS(this->flags, SEF_LAST_FIELD); else CLRBITS(this->flags, SEF_LAST_FIELD); } virtual uint Length() const = 0; virtual void GetFoldingState(bool &all_folded, bool &all_unfolded) const {} virtual bool IsVisible(const BaseSettingEntry *item) const; virtual BaseSettingEntry *FindEntry(uint row, uint *cur_row); virtual uint GetMaxHelpHeight(int maxw) { return 0; } /** * Check whether an entry is hidden due to filters * @return true if hidden. */ bool IsFiltered() const { return (this->flags & SEF_FILTERED) != 0; } virtual bool UpdateFilterState(SettingFilter &filter, bool force_visible) = 0; virtual uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const; protected: virtual void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const = 0; }; /** Standard setting */ struct SettingEntry : BaseSettingEntry { const char *name; ///< Name of the setting const SettingDesc *setting; ///< Setting description of the setting uint index; ///< Index of the setting in the settings table SettingEntry(const char *name); virtual void Init(byte level = 0); virtual uint Length() const; virtual uint GetMaxHelpHeight(int maxw); virtual bool UpdateFilterState(SettingFilter &filter, bool force_visible); void SetButtons(byte new_val); /** * Get the help text of a single setting. * @return The requested help text. */ inline StringID GetHelpText() const { return this->setting->desc.str_help; } void SetValueDParams(uint first_param, int32 value) const; protected: virtual void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const; private: bool IsVisibleByRestrictionMode(RestrictionMode mode) const; }; /** Containers for BaseSettingEntry */ struct SettingsContainer { typedef std::vector EntryVector; EntryVector entries; ///< Settings on this page template T *Add(T *item) { this->entries.push_back(item); return item; } void Init(byte level = 0); void FoldAll(); void UnFoldAll(); uint Length() const; void GetFoldingState(bool &all_folded, bool &all_unfolded) const; bool IsVisible(const BaseSettingEntry *item) const; BaseSettingEntry *FindEntry(uint row, uint *cur_row); uint GetMaxHelpHeight(int maxw); bool UpdateFilterState(SettingFilter &filter, bool force_visible); uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const; }; /** Data structure describing one page of settings in the settings window. */ struct SettingsPage : BaseSettingEntry, SettingsContainer { StringID title; ///< Title of the sub-page bool folded; ///< Sub-page is folded (not visible except for its title) SettingsPage(StringID title); virtual void Init(byte level = 0); virtual void FoldAll(); virtual void UnFoldAll(); virtual uint Length() const; virtual void GetFoldingState(bool &all_folded, bool &all_unfolded) const; virtual bool IsVisible(const BaseSettingEntry *item) const; virtual BaseSettingEntry *FindEntry(uint row, uint *cur_row); virtual uint GetMaxHelpHeight(int maxw) { return SettingsContainer::GetMaxHelpHeight(maxw); } virtual bool UpdateFilterState(SettingFilter &filter, bool force_visible); virtual uint Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row = 0, uint parent_last = 0) const; protected: virtual void DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const; }; /* == BaseSettingEntry methods == */ /** * Initialization of a setting entry * @param level Page nesting level of this entry */ void BaseSettingEntry::Init(byte level) { this->level = level; } /** * Check whether an entry is visible and not folded or filtered away. * Note: This does not consider the scrolling range; it might still require scrolling to make the setting really visible. * @param item Entry to search for. * @return true if entry is visible. */ bool BaseSettingEntry::IsVisible(const BaseSettingEntry *item) const { if (this->IsFiltered()) return false; if (this == item) return true; return false; } /** * Find setting entry at row \a row_num * @param row_num Index of entry to return * @param cur_row Current row number * @return The requested setting entry or \c NULL if it not found (folded or filtered) */ BaseSettingEntry *BaseSettingEntry::FindEntry(uint row_num, uint *cur_row) { if (this->IsFiltered()) return NULL; if (row_num == *cur_row) return this; (*cur_row)++; return NULL; } /** * Draw a row in the settings panel. * * The scrollbar uses rows of the page, while the page data structure is a tree of #SettingsPage and #SettingEntry objects. * As a result, the drawing routing traverses the tree from top to bottom, counting rows in \a cur_row until it reaches \a first_row. * Then it enables drawing rows while traversing until \a max_row is reached, at which point drawing is terminated. * * The \a parent_last parameter ensures that the vertical lines at the left are * only drawn when another entry follows, that it prevents output like * \verbatim * |-- setting * |-- (-) - Title * | |-- setting * | |-- setting * \endverbatim * The left-most vertical line is not wanted. It is prevented by setting the * appropriate bit in the \a parent_last parameter. * * @param settings_ptr Pointer to current values of all settings * @param left Left-most position in window/panel to start drawing \a first_row * @param right Right-most x position to draw strings at. * @param y Upper-most position in window/panel to start drawing \a first_row * @param first_row First row number to draw * @param max_row Row-number to stop drawing (the row-number of the row below the last row to draw) * @param selected Selected entry by the user. * @param cur_row Current row number (internal variable) * @param parent_last Last-field booleans of parent page level (page level \e i sets bit \e i to 1 if it is its last field) * @return Row number of the next row to draw */ uint BaseSettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row, uint parent_last) const { if (this->IsFiltered()) return cur_row; if (cur_row >= max_row) return cur_row; bool rtl = _current_text_dir == TD_RTL; int offset = rtl ? -4 : 4; int level_width = rtl ? -LEVEL_WIDTH : LEVEL_WIDTH; int x = rtl ? right : left; if (cur_row >= first_row) { int colour = _colour_gradient[COLOUR_ORANGE][4]; y += (cur_row - first_row) * SETTING_HEIGHT; // Compute correct y start position /* Draw vertical for parent nesting levels */ for (uint lvl = 0; lvl < this->level; lvl++) { if (!HasBit(parent_last, lvl)) GfxDrawLine(x + offset, y, x + offset, y + SETTING_HEIGHT - 1, colour); x += level_width; } /* draw own |- prefix */ int halfway_y = y + SETTING_HEIGHT / 2; int bottom_y = (flags & SEF_LAST_FIELD) ? halfway_y : y + SETTING_HEIGHT - 1; GfxDrawLine(x + offset, y, x + offset, bottom_y, colour); /* Small horizontal line from the last vertical line */ GfxDrawLine(x + offset, halfway_y, x + level_width - offset, halfway_y, colour); x += level_width; this->DrawSetting(settings_ptr, rtl ? left : x, rtl ? x : right, y, this == selected); } cur_row++; return cur_row; } /* == SettingEntry methods == */ /** * Constructor for a single setting in the 'advanced settings' window * @param name Name of the setting in the setting table */ SettingEntry::SettingEntry(const char *name) { this->name = name; this->setting = NULL; this->index = 0; } /** * Initialization of a setting entry * @param level Page nesting level of this entry */ void SettingEntry::Init(byte level) { BaseSettingEntry::Init(level); this->setting = GetSettingFromName(this->name, &this->index); assert(this->setting != NULL); } /** * Set the button-depressed flags (#SEF_LEFT_DEPRESSED and #SEF_RIGHT_DEPRESSED) to a specified value * @param new_val New value for the button flags * @see SettingEntryFlags */ void SettingEntry::SetButtons(byte new_val) { assert((new_val & ~SEF_BUTTONS_MASK) == 0); // Should not touch any flags outside the buttons this->flags = (this->flags & ~SEF_BUTTONS_MASK) | new_val; } /** Return number of rows needed to display the (filtered) entry */ uint SettingEntry::Length() const { return this->IsFiltered() ? 0 : 1; } /** * Get the biggest height of the help text(s), if the width is at least \a maxw. Help text gets wrapped if needed. * @param maxw Maximal width of a line help text. * @return Biggest height needed to display any help text of this node (and its descendants). */ uint SettingEntry::GetMaxHelpHeight(int maxw) { return GetStringHeight(this->GetHelpText(), maxw); } /** * Checks whether an entry shall be made visible based on the restriction mode. * @param mode The current status of the restriction drop down box. * @return true if the entry shall be visible. */ bool SettingEntry::IsVisibleByRestrictionMode(RestrictionMode mode) const { /* There shall not be any restriction, i.e. all settings shall be visible. */ if (mode == RM_ALL) return true; GameSettings *settings_ptr = &GetGameSettings(); const SettingDesc *sd = this->setting; if (mode == RM_BASIC) return (this->setting->desc.cat & SC_BASIC_LIST) != 0; if (mode == RM_ADVANCED) return (this->setting->desc.cat & SC_ADVANCED_LIST) != 0; /* Read the current value. */ const void *var = ResolveVariableAddress(settings_ptr, sd); int64 current_value = ReadValue(var, sd->save.conv); int64 filter_value; if (mode == RM_CHANGED_AGAINST_DEFAULT) { /* This entry shall only be visible, if the value deviates from its default value. */ /* Read the default value. */ filter_value = ReadValue(&sd->desc.def, sd->save.conv); } else { assert(mode == RM_CHANGED_AGAINST_NEW); /* This entry shall only be visible, if the value deviates from * its value is used when starting a new game. */ /* Make sure we're not comparing the new game settings against itself. */ assert(settings_ptr != &_settings_newgame); /* Read the new game's value. */ var = ResolveVariableAddress(&_settings_newgame, sd); filter_value = ReadValue(var, sd->save.conv); } return current_value != filter_value; } /** * Update the filter state. * @param filter Filter * @param force_visible Whether to force all items visible, no matter what (due to filter text; not affected by restriction drop down box). * @return true if item remains visible */ bool SettingEntry::UpdateFilterState(SettingFilter &filter, bool force_visible) { CLRBITS(this->flags, SEF_FILTERED); bool visible = true; const SettingDesc *sd = this->setting; if (!force_visible && !filter.string.IsEmpty()) { /* Process the search text filter for this item. */ filter.string.ResetState(); const SettingDescBase *sdb = &sd->desc; SetDParam(0, STR_EMPTY); filter.string.AddLine(sdb->str); filter.string.AddLine(this->GetHelpText()); visible = filter.string.GetState(); } if (visible) { if (filter.type != ST_ALL && sd->GetType() != filter.type) { filter.type_hides = true; visible = false; } if (!this->IsVisibleByRestrictionMode(filter.mode)) { while (filter.min_cat < RM_ALL && (filter.min_cat == filter.mode || !this->IsVisibleByRestrictionMode(filter.min_cat))) filter.min_cat++; visible = false; } } if (!visible) SETBITS(this->flags, SEF_FILTERED); return visible; } static const void *ResolveVariableAddress(const GameSettings *settings_ptr, const SettingDesc *sd) { if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { return GetVariableAddress(&Company::Get(_local_company)->settings, &sd->save); } else { return GetVariableAddress(&_settings_client.company, &sd->save); } } else { return GetVariableAddress(settings_ptr, &sd->save); } } /** * Set the DParams for drawing the value of a setting. * @param first_param First DParam to use * @param value Setting value to set params for. */ void SettingEntry::SetValueDParams(uint first_param, int32 value) const { const SettingDescBase *sdb = &this->setting->desc; if (sdb->cmd == SDT_BOOLX) { SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); } else { if ((sdb->flags & SGF_MULTISTRING) != 0) { SetDParam(first_param++, sdb->str_val - sdb->min + value); } else if ((sdb->flags & SGF_DISPLAY_ABS) != 0) { SetDParam(first_param++, sdb->str_val + ((value >= 0) ? 1 : 0)); value = abs(value); } else { SetDParam(first_param++, sdb->str_val + ((value == 0 && (sdb->flags & SGF_0ISDISABLED) != 0) ? 1 : 0)); } SetDParam(first_param++, value); } } /** * Function to draw setting value (button + text + current value) * @param settings_ptr Pointer to current values of all settings * @param left Left-most position in window/panel to start drawing * @param right Right-most position in window/panel to draw * @param y Upper-most position in window/panel to start drawing * @param highlight Highlight entry. */ void SettingEntry::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const { const SettingDesc *sd = this->setting; const SettingDescBase *sdb = &sd->desc; const void *var = ResolveVariableAddress(settings_ptr, sd); int state = this->flags & SEF_BUTTONS_MASK; bool rtl = _current_text_dir == TD_RTL; uint buttons_left = rtl ? right + 1 - SETTING_BUTTON_WIDTH : left; uint text_left = left + (rtl ? 0 : SETTING_BUTTON_WIDTH + 5); uint text_right = right - (rtl ? SETTING_BUTTON_WIDTH + 5 : 0); uint button_y = y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2; /* We do not allow changes of some items when we are a client in a networkgame */ bool editable = sd->IsEditable(); SetDParam(0, highlight ? STR_ORANGE_STRING1_WHITE : STR_ORANGE_STRING1_LTBLUE); int32 value = (int32)ReadValue(var, sd->save.conv); if (sdb->cmd == SDT_BOOLX) { /* Draw checkbox for boolean-value either on/off */ DrawBoolButton(buttons_left, button_y, value != 0, editable); } else if ((sdb->flags & SGF_MULTISTRING) != 0) { /* Draw [v] button for settings of an enum-type */ DrawDropDownButton(buttons_left, button_y, COLOUR_YELLOW, state != 0, editable); } else { /* Draw [<][>] boxes for settings of an integer-type */ DrawArrowButtons(buttons_left, button_y, COLOUR_YELLOW, state, editable && value != (sdb->flags & SGF_0ISDISABLED ? 0 : sdb->min), editable && (uint32)value != sdb->max); } this->SetValueDParams(1, value); DrawString(text_left, text_right, y + (SETTING_HEIGHT - FONT_HEIGHT_NORMAL) / 2, sdb->str, highlight ? TC_WHITE : TC_LIGHT_BLUE); } /* == SettingsContainer methods == */ /** * Initialization of an entire setting page * @param level Nesting level of this page (internal variable, do not provide a value for it when calling) */ void SettingsContainer::Init(byte level) { for (EntryVector::iterator it = this->entries.begin(); it != this->entries.end(); ++it) { (*it)->Init(level); } } /** Recursively close all folds of sub-pages */ void SettingsContainer::FoldAll() { for (EntryVector::iterator it = this->entries.begin(); it != this->entries.end(); ++it) { (*it)->FoldAll(); } } /** Recursively open all folds of sub-pages */ void SettingsContainer::UnFoldAll() { for (EntryVector::iterator it = this->entries.begin(); it != this->entries.end(); ++it) { (*it)->UnFoldAll(); } } /** * Recursively accumulate the folding state of the tree. * @param[in,out] all_folded Set to false, if one entry is not folded. * @param[in,out] all_unfolded Set to false, if one entry is folded. */ void SettingsContainer::GetFoldingState(bool &all_folded, bool &all_unfolded) const { for (EntryVector::const_iterator it = this->entries.begin(); it != this->entries.end(); ++it) { (*it)->GetFoldingState(all_folded, all_unfolded); } } /** * Update the filter state. * @param filter Filter * @param force_visible Whether to force all items visible, no matter what * @return true if item remains visible */ bool SettingsContainer::UpdateFilterState(SettingFilter &filter, bool force_visible) { bool visible = false; bool first_visible = true; for (EntryVector::reverse_iterator it = this->entries.rbegin(); it != this->entries.rend(); ++it) { visible |= (*it)->UpdateFilterState(filter, force_visible); (*it)->SetLastField(first_visible); if (visible && first_visible) first_visible = false; } return visible; } /** * Check whether an entry is visible and not folded or filtered away. * Note: This does not consider the scrolling range; it might still require scrolling to make the setting really visible. * @param item Entry to search for. * @return true if entry is visible. */ bool SettingsContainer::IsVisible(const BaseSettingEntry *item) const { for (EntryVector::const_iterator it = this->entries.begin(); it != this->entries.end(); ++it) { if ((*it)->IsVisible(item)) return true; } return false; } /** Return number of rows needed to display the whole page */ uint SettingsContainer::Length() const { uint length = 0; for (EntryVector::const_iterator it = this->entries.begin(); it != this->entries.end(); ++it) { length += (*it)->Length(); } return length; } /** * Find the setting entry at row number \a row_num * @param row_num Index of entry to return * @param cur_row Variable used for keeping track of the current row number. Should point to memory initialized to \c 0 when first called. * @return The requested setting entry or \c NULL if it does not exist */ BaseSettingEntry *SettingsContainer::FindEntry(uint row_num, uint *cur_row) { BaseSettingEntry *pe = NULL; for (EntryVector::iterator it = this->entries.begin(); it != this->entries.end(); ++it) { pe = (*it)->FindEntry(row_num, cur_row); if (pe != NULL) { break; } } return pe; } /** * Get the biggest height of the help texts, if the width is at least \a maxw. Help text gets wrapped if needed. * @param maxw Maximal width of a line help text. * @return Biggest height needed to display any help text of this (sub-)tree. */ uint SettingsContainer::GetMaxHelpHeight(int maxw) { uint biggest = 0; for (EntryVector::const_iterator it = this->entries.begin(); it != this->entries.end(); ++it) { biggest = max(biggest, (*it)->GetMaxHelpHeight(maxw)); } return biggest; } /** * Draw a row in the settings panel. * * @param settings_ptr Pointer to current values of all settings * @param left Left-most position in window/panel to start drawing \a first_row * @param right Right-most x position to draw strings at. * @param y Upper-most position in window/panel to start drawing \a first_row * @param first_row First row number to draw * @param max_row Row-number to stop drawing (the row-number of the row below the last row to draw) * @param selected Selected entry by the user. * @param cur_row Current row number (internal variable) * @param parent_last Last-field booleans of parent page level (page level \e i sets bit \e i to 1 if it is its last field) * @return Row number of the next row to draw */ uint SettingsContainer::Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row, uint parent_last) const { for (EntryVector::const_iterator it = this->entries.begin(); it != this->entries.end(); ++it) { cur_row = (*it)->Draw(settings_ptr, left, right, y, first_row, max_row, selected, cur_row, parent_last); if (cur_row >= max_row) { break; } } return cur_row; } /* == SettingsPage methods == */ /** * Constructor for a sub-page in the 'advanced settings' window * @param title Title of the sub-page */ SettingsPage::SettingsPage(StringID title) { this->title = title; this->folded = true; } /** * Initialization of an entire setting page * @param level Nesting level of this page (internal variable, do not provide a value for it when calling) */ void SettingsPage::Init(byte level) { BaseSettingEntry::Init(level); SettingsContainer::Init(level + 1); } /** Recursively close all (filtered) folds of sub-pages */ void SettingsPage::FoldAll() { if (this->IsFiltered()) return; this->folded = true; SettingsContainer::FoldAll(); } /** Recursively open all (filtered) folds of sub-pages */ void SettingsPage::UnFoldAll() { if (this->IsFiltered()) return; this->folded = false; SettingsContainer::UnFoldAll(); } /** * Recursively accumulate the folding state of the (filtered) tree. * @param[in,out] all_folded Set to false, if one entry is not folded. * @param[in,out] all_unfolded Set to false, if one entry is folded. */ void SettingsPage::GetFoldingState(bool &all_folded, bool &all_unfolded) const { if (this->IsFiltered()) return; if (this->folded) { all_unfolded = false; } else { all_folded = false; } SettingsContainer::GetFoldingState(all_folded, all_unfolded); } /** * Update the filter state. * @param filter Filter * @param force_visible Whether to force all items visible, no matter what (due to filter text; not affected by restriction drop down box). * @return true if item remains visible */ bool SettingsPage::UpdateFilterState(SettingFilter &filter, bool force_visible) { if (!force_visible && !filter.string.IsEmpty()) { filter.string.ResetState(); filter.string.AddLine(this->title); force_visible = filter.string.GetState(); } bool visible = SettingsContainer::UpdateFilterState(filter, force_visible); if (visible) { CLRBITS(this->flags, SEF_FILTERED); } else { SETBITS(this->flags, SEF_FILTERED); } return visible; } /** * Check whether an entry is visible and not folded or filtered away. * Note: This does not consider the scrolling range; it might still require scrolling to make the setting really visible. * @param item Entry to search for. * @return true if entry is visible. */ bool SettingsPage::IsVisible(const BaseSettingEntry *item) const { if (this->IsFiltered()) return false; if (this == item) return true; if (this->folded) return false; return SettingsContainer::IsVisible(item); } /** Return number of rows needed to display the (filtered) entry */ uint SettingsPage::Length() const { if (this->IsFiltered()) return 0; if (this->folded) return 1; // Only displaying the title return 1 + SettingsContainer::Length(); } /** * Find setting entry at row \a row_num * @param row_num Index of entry to return * @param cur_row Current row number * @return The requested setting entry or \c NULL if it not found (folded or filtered) */ BaseSettingEntry *SettingsPage::FindEntry(uint row_num, uint *cur_row) { if (this->IsFiltered()) return NULL; if (row_num == *cur_row) return this; (*cur_row)++; if (this->folded) return NULL; return SettingsContainer::FindEntry(row_num, cur_row); } /** * Draw a row in the settings panel. * * @param settings_ptr Pointer to current values of all settings * @param left Left-most position in window/panel to start drawing \a first_row * @param right Right-most x position to draw strings at. * @param y Upper-most position in window/panel to start drawing \a first_row * @param first_row First row number to draw * @param max_row Row-number to stop drawing (the row-number of the row below the last row to draw) * @param selected Selected entry by the user. * @param cur_row Current row number (internal variable) * @param parent_last Last-field booleans of parent page level (page level \e i sets bit \e i to 1 if it is its last field) * @return Row number of the next row to draw */ uint SettingsPage::Draw(GameSettings *settings_ptr, int left, int right, int y, uint first_row, uint max_row, BaseSettingEntry *selected, uint cur_row, uint parent_last) const { if (this->IsFiltered()) return cur_row; if (cur_row >= max_row) return cur_row; cur_row = BaseSettingEntry::Draw(settings_ptr, left, right, y, first_row, max_row, selected, cur_row, parent_last); if (!this->folded) { if (this->flags & SEF_LAST_FIELD) { assert(this->level < 8 * sizeof(parent_last)); SetBit(parent_last, this->level); // Add own last-field state } cur_row = SettingsContainer::Draw(settings_ptr, left, right, y, first_row, max_row, selected, cur_row, parent_last); } return cur_row; } /** * Function to draw setting value (button + text + current value) * @param settings_ptr Pointer to current values of all settings * @param left Left-most position in window/panel to start drawing * @param right Right-most position in window/panel to draw * @param y Upper-most position in window/panel to start drawing * @param highlight Highlight entry. */ void SettingsPage::DrawSetting(GameSettings *settings_ptr, int left, int right, int y, bool highlight) const { bool rtl = _current_text_dir == TD_RTL; DrawSprite((this->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? right - _circle_size.width : left, y + (SETTING_HEIGHT - _circle_size.height) / 2); DrawString(rtl ? left : left + _circle_size.width + 2, rtl ? right - _circle_size.width - 2 : right, y + (SETTING_HEIGHT - FONT_HEIGHT_NORMAL) / 2, this->title); } /** Construct settings tree */ static SettingsContainer &GetSettingsTree() { static SettingsContainer *main = NULL; if (main == NULL) { /* Build up the dynamic settings-array only once per OpenTTD session */ main = new SettingsContainer(); SettingsPage *localisation = main->Add(new SettingsPage(STR_CONFIG_SETTING_LOCALISATION)); { localisation->Add(new SettingEntry("locale.units_velocity")); localisation->Add(new SettingEntry("locale.units_power")); localisation->Add(new SettingEntry("locale.units_weight")); localisation->Add(new SettingEntry("locale.units_volume")); localisation->Add(new SettingEntry("locale.units_force")); localisation->Add(new SettingEntry("locale.units_height")); localisation->Add(new SettingEntry("gui.date_format_in_default_names")); } SettingsPage *graphics = main->Add(new SettingsPage(STR_CONFIG_SETTING_GRAPHICS)); { graphics->Add(new SettingEntry("gui.zoom_min")); graphics->Add(new SettingEntry("gui.zoom_max")); graphics->Add(new SettingEntry("gui.smallmap_land_colour")); graphics->Add(new SettingEntry("gui.graph_line_thickness")); } SettingsPage *sound = main->Add(new SettingsPage(STR_CONFIG_SETTING_SOUND)); { sound->Add(new SettingEntry("sound.click_beep")); sound->Add(new SettingEntry("sound.confirm")); sound->Add(new SettingEntry("sound.news_ticker")); sound->Add(new SettingEntry("sound.news_full")); sound->Add(new SettingEntry("sound.new_year")); sound->Add(new SettingEntry("sound.disaster")); sound->Add(new SettingEntry("sound.vehicle")); sound->Add(new SettingEntry("sound.ambient")); } SettingsPage *interface = main->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE)); { SettingsPage *general = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_GENERAL)); { general->Add(new SettingEntry("gui.osk_activation")); general->Add(new SettingEntry("gui.hover_delay_ms")); general->Add(new SettingEntry("gui.errmsg_duration")); general->Add(new SettingEntry("gui.window_snap_radius")); general->Add(new SettingEntry("gui.window_soft_limit")); } SettingsPage *viewports = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_VIEWPORTS)); { viewports->Add(new SettingEntry("gui.auto_scrolling")); viewports->Add(new SettingEntry("gui.reverse_scroll")); viewports->Add(new SettingEntry("gui.smooth_scroll")); viewports->Add(new SettingEntry("gui.left_mouse_btn_scrolling")); /* While the horizontal scrollwheel scrolling is written as general code, only * the cocoa (OSX) driver generates input for it. * Since it's also able to completely disable the scrollwheel will we display it on all platforms anyway */ viewports->Add(new SettingEntry("gui.scrollwheel_scrolling")); viewports->Add(new SettingEntry("gui.scrollwheel_multiplier")); #ifdef __APPLE__ /* We might need to emulate a right mouse button on mac */ viewports->Add(new SettingEntry("gui.right_mouse_btn_emulation")); #endif viewports->Add(new SettingEntry("gui.population_in_label")); viewports->Add(new SettingEntry("gui.liveries")); viewports->Add(new SettingEntry("construction.train_signal_side")); viewports->Add(new SettingEntry("gui.measure_tooltip")); viewports->Add(new SettingEntry("gui.loading_indicators")); viewports->Add(new SettingEntry("gui.show_track_reservation")); } SettingsPage *construction = interface->Add(new SettingsPage(STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION)); { construction->Add(new SettingEntry("gui.link_terraform_toolbar")); construction->Add(new SettingEntry("gui.enable_signal_gui")); construction->Add(new SettingEntry("gui.persistent_buildingtools")); construction->Add(new SettingEntry("gui.quick_goto")); construction->Add(new SettingEntry("gui.default_rail_type")); construction->Add(new SettingEntry("gui.disable_unsuitable_building")); } interface->Add(new SettingEntry("gui.autosave")); interface->Add(new SettingEntry("gui.toolbar_pos")); interface->Add(new SettingEntry("gui.statusbar_pos")); interface->Add(new SettingEntry("gui.prefer_teamchat")); interface->Add(new SettingEntry("gui.advanced_vehicle_list")); interface->Add(new SettingEntry("gui.timetable_in_ticks")); interface->Add(new SettingEntry("gui.timetable_arrival_departure")); interface->Add(new SettingEntry("gui.expenses_layout")); } SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS)); { advisors->Add(new SettingEntry("gui.coloured_news_year")); advisors->Add(new SettingEntry("news_display.general")); advisors->Add(new SettingEntry("news_display.new_vehicles")); advisors->Add(new SettingEntry("news_display.accident")); advisors->Add(new SettingEntry("news_display.company_info")); advisors->Add(new SettingEntry("news_display.acceptance")); advisors->Add(new SettingEntry("news_display.arrival_player")); advisors->Add(new SettingEntry("news_display.arrival_other")); advisors->Add(new SettingEntry("news_display.advice")); advisors->Add(new SettingEntry("gui.order_review_system")); advisors->Add(new SettingEntry("gui.vehicle_income_warn")); advisors->Add(new SettingEntry("gui.lost_vehicle_warn")); advisors->Add(new SettingEntry("gui.show_finances")); advisors->Add(new SettingEntry("news_display.economy")); advisors->Add(new SettingEntry("news_display.subsidies")); advisors->Add(new SettingEntry("news_display.open")); advisors->Add(new SettingEntry("news_display.close")); advisors->Add(new SettingEntry("news_display.production_player")); advisors->Add(new SettingEntry("news_display.production_other")); advisors->Add(new SettingEntry("news_display.production_nobody")); } SettingsPage *company = main->Add(new SettingsPage(STR_CONFIG_SETTING_COMPANY)); { company->Add(new SettingEntry("gui.semaphore_build_before")); company->Add(new SettingEntry("gui.default_signal_type")); company->Add(new SettingEntry("gui.cycle_signal_types")); company->Add(new SettingEntry("gui.drag_signals_fixed_distance")); company->Add(new SettingEntry("gui.new_nonstop")); company->Add(new SettingEntry("gui.stop_location")); company->Add(new SettingEntry("company.engine_renew")); company->Add(new SettingEntry("company.engine_renew_months")); company->Add(new SettingEntry("company.engine_renew_money")); company->Add(new SettingEntry("vehicle.servint_ispercent")); company->Add(new SettingEntry("vehicle.servint_trains")); company->Add(new SettingEntry("vehicle.servint_roadveh")); company->Add(new SettingEntry("vehicle.servint_ships")); company->Add(new SettingEntry("vehicle.servint_aircraft")); } SettingsPage *accounting = main->Add(new SettingsPage(STR_CONFIG_SETTING_ACCOUNTING)); { accounting->Add(new SettingEntry("economy.inflation")); accounting->Add(new SettingEntry("difficulty.initial_interest")); accounting->Add(new SettingEntry("difficulty.max_loan")); accounting->Add(new SettingEntry("difficulty.subsidy_multiplier")); accounting->Add(new SettingEntry("economy.feeder_payment_share")); accounting->Add(new SettingEntry("economy.infrastructure_maintenance")); accounting->Add(new SettingEntry("difficulty.vehicle_costs")); accounting->Add(new SettingEntry("difficulty.construction_cost")); } SettingsPage *vehicles = main->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES)); { SettingsPage *physics = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_PHYSICS)); { physics->Add(new SettingEntry("vehicle.train_acceleration_model")); physics->Add(new SettingEntry("vehicle.train_slope_steepness")); physics->Add(new SettingEntry("vehicle.wagon_speed_limits")); physics->Add(new SettingEntry("vehicle.freight_trains")); physics->Add(new SettingEntry("vehicle.roadveh_acceleration_model")); physics->Add(new SettingEntry("vehicle.roadveh_slope_steepness")); physics->Add(new SettingEntry("vehicle.smoke_amount")); physics->Add(new SettingEntry("vehicle.plane_speed")); } SettingsPage *routing = vehicles->Add(new SettingsPage(STR_CONFIG_SETTING_VEHICLES_ROUTING)); { routing->Add(new SettingEntry("pf.pathfinder_for_trains")); routing->Add(new SettingEntry("difficulty.line_reverse_mode")); routing->Add(new SettingEntry("pf.reverse_at_signals")); routing->Add(new SettingEntry("pf.forbid_90_deg")); routing->Add(new SettingEntry("pf.pathfinder_for_roadvehs")); routing->Add(new SettingEntry("pf.pathfinder_for_ships")); } vehicles->Add(new SettingEntry("order.no_servicing_if_no_breakdowns")); vehicles->Add(new SettingEntry("order.serviceathelipad")); } SettingsPage *limitations = main->Add(new SettingsPage(STR_CONFIG_SETTING_LIMITATIONS)); { limitations->Add(new SettingEntry("construction.command_pause_level")); limitations->Add(new SettingEntry("construction.autoslope")); limitations->Add(new SettingEntry("construction.extra_dynamite")); limitations->Add(new SettingEntry("construction.max_heightlevel")); limitations->Add(new SettingEntry("construction.max_bridge_length")); limitations->Add(new SettingEntry("construction.max_bridge_height")); limitations->Add(new SettingEntry("construction.max_tunnel_length")); limitations->Add(new SettingEntry("station.never_expire_airports")); limitations->Add(new SettingEntry("vehicle.never_expire_vehicles")); limitations->Add(new SettingEntry("vehicle.max_trains")); limitations->Add(new SettingEntry("vehicle.max_roadveh")); limitations->Add(new SettingEntry("vehicle.max_aircraft")); limitations->Add(new SettingEntry("vehicle.max_ships")); limitations->Add(new SettingEntry("vehicle.max_train_length")); limitations->Add(new SettingEntry("station.station_spread")); limitations->Add(new SettingEntry("station.distant_join_stations")); limitations->Add(new SettingEntry("construction.road_stop_on_town_road")); limitations->Add(new SettingEntry("construction.road_stop_on_competitor_road")); limitations->Add(new SettingEntry("vehicle.disable_elrails")); } SettingsPage *disasters = main->Add(new SettingsPage(STR_CONFIG_SETTING_ACCIDENTS)); { disasters->Add(new SettingEntry("difficulty.disasters")); disasters->Add(new SettingEntry("difficulty.economy")); disasters->Add(new SettingEntry("difficulty.vehicle_breakdowns")); disasters->Add(new SettingEntry("vehicle.plane_crashes")); } SettingsPage *genworld = main->Add(new SettingsPage(STR_CONFIG_SETTING_GENWORLD)); { genworld->Add(new SettingEntry("game_creation.landscape")); genworld->Add(new SettingEntry("game_creation.land_generator")); genworld->Add(new SettingEntry("difficulty.terrain_type")); genworld->Add(new SettingEntry("game_creation.tgen_smoothness")); genworld->Add(new SettingEntry("game_creation.variety")); genworld->Add(new SettingEntry("game_creation.snow_line_height")); genworld->Add(new SettingEntry("game_creation.amount_of_rivers")); genworld->Add(new SettingEntry("game_creation.tree_placer")); genworld->Add(new SettingEntry("vehicle.road_side")); genworld->Add(new SettingEntry("economy.larger_towns")); genworld->Add(new SettingEntry("economy.initial_city_size")); genworld->Add(new SettingEntry("economy.town_layout")); genworld->Add(new SettingEntry("difficulty.industry_density")); genworld->Add(new SettingEntry("gui.pause_on_newgame")); } SettingsPage *environment = main->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT)); { SettingsPage *authorities = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES)); { authorities->Add(new SettingEntry("difficulty.town_council_tolerance")); authorities->Add(new SettingEntry("economy.bribe")); authorities->Add(new SettingEntry("economy.exclusive_rights")); authorities->Add(new SettingEntry("economy.fund_roads")); authorities->Add(new SettingEntry("economy.fund_buildings")); authorities->Add(new SettingEntry("economy.station_noise_level")); } SettingsPage *towns = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_TOWNS)); { towns->Add(new SettingEntry("economy.town_growth_rate")); towns->Add(new SettingEntry("economy.allow_town_roads")); towns->Add(new SettingEntry("economy.allow_town_level_crossings")); towns->Add(new SettingEntry("economy.found_town")); } SettingsPage *industries = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES)); { industries->Add(new SettingEntry("construction.raw_industry_construction")); industries->Add(new SettingEntry("construction.industry_platform")); industries->Add(new SettingEntry("economy.multiple_industry_per_town")); industries->Add(new SettingEntry("game_creation.oil_refinery_limit")); industries->Add(new SettingEntry("economy.smooth_economy")); } SettingsPage *cdist = environment->Add(new SettingsPage(STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST)); { cdist->Add(new SettingEntry("linkgraph.recalc_time")); cdist->Add(new SettingEntry("linkgraph.recalc_interval")); cdist->Add(new SettingEntry("linkgraph.distribution_pax")); cdist->Add(new SettingEntry("linkgraph.distribution_mail")); cdist->Add(new SettingEntry("linkgraph.distribution_armoured")); cdist->Add(new SettingEntry("linkgraph.distribution_default")); cdist->Add(new SettingEntry("linkgraph.accuracy")); cdist->Add(new SettingEntry("linkgraph.demand_distance")); cdist->Add(new SettingEntry("linkgraph.demand_size")); cdist->Add(new SettingEntry("linkgraph.short_path_saturation")); } environment->Add(new SettingEntry("station.modified_catchment")); environment->Add(new SettingEntry("construction.extra_tree_placement")); } SettingsPage *ai = main->Add(new SettingsPage(STR_CONFIG_SETTING_AI)); { SettingsPage *npc = ai->Add(new SettingsPage(STR_CONFIG_SETTING_AI_NPC)); { npc->Add(new SettingEntry("script.settings_profile")); npc->Add(new SettingEntry("script.script_max_opcode_till_suspend")); npc->Add(new SettingEntry("difficulty.competitor_speed")); npc->Add(new SettingEntry("ai.ai_in_multiplayer")); npc->Add(new SettingEntry("ai.ai_disable_veh_train")); npc->Add(new SettingEntry("ai.ai_disable_veh_roadveh")); npc->Add(new SettingEntry("ai.ai_disable_veh_aircraft")); npc->Add(new SettingEntry("ai.ai_disable_veh_ship")); } ai->Add(new SettingEntry("economy.give_money")); ai->Add(new SettingEntry("economy.allow_shares")); } main->Init(); } return *main; } static const StringID _game_settings_restrict_dropdown[] = { STR_CONFIG_SETTING_RESTRICT_BASIC, // RM_BASIC STR_CONFIG_SETTING_RESTRICT_ADVANCED, // RM_ADVANCED STR_CONFIG_SETTING_RESTRICT_ALL, // RM_ALL STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT, // RM_CHANGED_AGAINST_DEFAULT STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW, // RM_CHANGED_AGAINST_NEW }; assert_compile(lengthof(_game_settings_restrict_dropdown) == RM_END); /** Warnings about hidden search results. */ enum WarnHiddenResult { WHR_NONE, ///< Nothing was filtering matches away. WHR_CATEGORY, ///< Category setting filtered matches away. WHR_TYPE, ///< Type setting filtered matches away. WHR_CATEGORY_TYPE, ///< Both category and type settings filtered matches away. }; /** Window to edit settings of the game. */ struct GameSettingsWindow : Window { static const int SETTINGTREE_LEFT_OFFSET = 5; ///< Position of left edge of setting values static const int SETTINGTREE_RIGHT_OFFSET = 5; ///< Position of right edge of setting values static const int SETTINGTREE_TOP_OFFSET = 5; ///< Position of top edge of setting values static const int SETTINGTREE_BOTTOM_OFFSET = 5; ///< Position of bottom edge of setting values static GameSettings *settings_ptr; ///< Pointer to the game settings being displayed and modified. SettingEntry *valuewindow_entry; ///< If non-NULL, pointer to setting for which a value-entering window has been opened. SettingEntry *clicked_entry; ///< If non-NULL, pointer to a clicked numeric setting (with a depressed left or right button). SettingEntry *last_clicked; ///< If non-NULL, pointer to the last clicked setting. SettingEntry *valuedropdown_entry; ///< If non-NULL, pointer to the value for which a dropdown window is currently opened. bool closing_dropdown; ///< True, if the dropdown list is currently closing. SettingFilter filter; ///< Filter for the list. QueryString filter_editbox; ///< Filter editbox; bool manually_changed_folding; ///< Whether the user expanded/collapsed something manually. WarnHiddenResult warn_missing; ///< Whether and how to warn about missing search results. int warn_lines; ///< Number of lines used for warning about missing search results. Scrollbar *vscroll; GameSettingsWindow(WindowDesc *desc) : Window(desc), filter_editbox(50) { this->warn_missing = WHR_NONE; this->warn_lines = 0; this->filter.mode = (RestrictionMode)_settings_client.gui.settings_restriction_mode; this->filter.min_cat = RM_ALL; this->filter.type = ST_ALL; this->filter.type_hides = false; this->settings_ptr = &GetGameSettings(); _circle_size = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED)); GetSettingsTree().FoldAll(); // Close all sub-pages this->valuewindow_entry = NULL; // No setting entry for which a entry window is opened this->clicked_entry = NULL; // No numeric setting buttons are depressed this->last_clicked = NULL; this->valuedropdown_entry = NULL; this->closing_dropdown = false; this->manually_changed_folding = false; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_GS_SCROLLBAR); this->FinishInitNested(WN_GAME_OPTIONS_GAME_SETTINGS); this->querystrings[WID_GS_FILTER] = &this->filter_editbox; this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR; this->SetFocusedWidget(WID_GS_FILTER); this->InvalidateData(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_GS_OPTIONSPANEL: resize->height = SETTING_HEIGHT = max(max(_circle_size.height, SETTING_BUTTON_HEIGHT), FONT_HEIGHT_NORMAL) + 1; resize->width = 1; size->height = 5 * resize->height + SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET; break; case WID_GS_HELP_TEXT: { static const StringID setting_types[] = { STR_CONFIG_SETTING_TYPE_CLIENT, STR_CONFIG_SETTING_TYPE_COMPANY_MENU, STR_CONFIG_SETTING_TYPE_COMPANY_INGAME, STR_CONFIG_SETTING_TYPE_GAME_MENU, STR_CONFIG_SETTING_TYPE_GAME_INGAME, }; for (uint i = 0; i < lengthof(setting_types); i++) { SetDParam(0, setting_types[i]); size->width = max(size->width, GetStringBoundingBox(STR_CONFIG_SETTING_TYPE).width); } size->height = 2 * FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL + max(size->height, GetSettingsTree().GetMaxHelpHeight(size->width)); break; } case WID_GS_RESTRICT_CATEGORY: case WID_GS_RESTRICT_TYPE: size->width = max(GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_CATEGORY).width, GetStringBoundingBox(STR_CONFIG_SETTING_RESTRICT_TYPE).width); break; default: break; } } virtual void OnPaint() { if (this->closing_dropdown) { this->closing_dropdown = false; assert(this->valuedropdown_entry != NULL); this->valuedropdown_entry->SetButtons(0); this->valuedropdown_entry = NULL; } /* Reserve the correct number of lines for the 'some search results are hidden' notice in the central settings display panel. */ const NWidgetBase *panel = this->GetWidget(WID_GS_OPTIONSPANEL); StringID warn_str = STR_CONFIG_SETTING_CATEGORY_HIDES - 1 + this->warn_missing; int new_warn_lines; if (this->warn_missing == WHR_NONE) { new_warn_lines = 0; } else { SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]); new_warn_lines = GetStringLineCount(warn_str, panel->current_x); } if (this->warn_lines != new_warn_lines) { this->vscroll->SetCount(this->vscroll->GetCount() - this->warn_lines + new_warn_lines); this->warn_lines = new_warn_lines; } this->DrawWidgets(); /* Draw the 'some search results are hidden' notice. */ if (this->warn_missing != WHR_NONE) { const int left = panel->pos_x; const int right = left + panel->current_x - 1; const int top = panel->pos_y + WD_FRAMETEXT_TOP + (SETTING_HEIGHT - FONT_HEIGHT_NORMAL) * this->warn_lines / 2; SetDParam(0, _game_settings_restrict_dropdown[this->filter.min_cat]); if (this->warn_lines == 1) { /* If the warning fits at one line, center it. */ DrawString(left + WD_FRAMETEXT_LEFT, right - WD_FRAMETEXT_RIGHT, top, warn_str, TC_FROMSTRING, SA_HOR_CENTER); } else { DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, INT32_MAX, warn_str, TC_FROMSTRING, SA_HOR_CENTER); } } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_GS_RESTRICT_DROPDOWN: SetDParam(0, _game_settings_restrict_dropdown[this->filter.mode]); break; case WID_GS_TYPE_DROPDOWN: switch (this->filter.type) { case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME); break; case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME); break; case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT); break; default: SetDParam(0, STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL); break; } break; } } DropDownList *BuildDropDownList(int widget) const { DropDownList *list = NULL; switch (widget) { case WID_GS_RESTRICT_DROPDOWN: list = new DropDownList(); for (int mode = 0; mode != RM_END; mode++) { /* If we are in adv. settings screen for the new game's settings, * we don't want to allow comparing with new game's settings. */ bool disabled = mode == RM_CHANGED_AGAINST_NEW && settings_ptr == &_settings_newgame; *list->Append() = new DropDownListStringItem(_game_settings_restrict_dropdown[mode], mode, disabled); } break; case WID_GS_TYPE_DROPDOWN: list = new DropDownList(); *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL, ST_ALL, false); *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME, ST_GAME, false); *list->Append() = new DropDownListStringItem(_game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME, ST_COMPANY, false); *list->Append() = new DropDownListStringItem(STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT, ST_CLIENT, false); break; } return list; } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_GS_OPTIONSPANEL: { int top_pos = r.top + SETTINGTREE_TOP_OFFSET + 1 + this->warn_lines * SETTING_HEIGHT; uint last_row = this->vscroll->GetPosition() + this->vscroll->GetCapacity() - this->warn_lines; int next_row = GetSettingsTree().Draw(settings_ptr, r.left + SETTINGTREE_LEFT_OFFSET, r.right - SETTINGTREE_RIGHT_OFFSET, top_pos, this->vscroll->GetPosition(), last_row, this->last_clicked); if (next_row == 0) DrawString(r.left + SETTINGTREE_LEFT_OFFSET, r.right - SETTINGTREE_RIGHT_OFFSET, top_pos, STR_CONFIG_SETTINGS_NONE); break; } case WID_GS_HELP_TEXT: if (this->last_clicked != NULL) { const SettingDesc *sd = this->last_clicked->setting; int y = r.top; switch (sd->GetType()) { case ST_COMPANY: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_COMPANY_MENU : STR_CONFIG_SETTING_TYPE_COMPANY_INGAME); break; case ST_CLIENT: SetDParam(0, STR_CONFIG_SETTING_TYPE_CLIENT); break; case ST_GAME: SetDParam(0, _game_mode == GM_MENU ? STR_CONFIG_SETTING_TYPE_GAME_MENU : STR_CONFIG_SETTING_TYPE_GAME_INGAME); break; default: NOT_REACHED(); } DrawString(r.left, r.right, y, STR_CONFIG_SETTING_TYPE); y += FONT_HEIGHT_NORMAL; int32 default_value = ReadValue(&sd->desc.def, sd->save.conv); this->last_clicked->SetValueDParams(0, default_value); DrawString(r.left, r.right, y, STR_CONFIG_SETTING_DEFAULT_VALUE); y += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; DrawStringMultiLine(r.left, r.right, y, r.bottom, this->last_clicked->GetHelpText(), TC_WHITE); } break; default: break; } } /** * Set the entry that should have its help text displayed, and mark the window dirty so it gets repainted. * @param pe Setting to display help text of, use \c NULL to stop displaying help of the currently displayed setting. */ void SetDisplayedHelpText(SettingEntry *pe) { if (this->last_clicked != pe) this->SetDirty(); this->last_clicked = pe; } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_GS_EXPAND_ALL: this->manually_changed_folding = true; GetSettingsTree().UnFoldAll(); this->InvalidateData(); break; case WID_GS_COLLAPSE_ALL: this->manually_changed_folding = true; GetSettingsTree().FoldAll(); this->InvalidateData(); break; case WID_GS_RESTRICT_DROPDOWN: { DropDownList *list = this->BuildDropDownList(widget); if (list != NULL) { ShowDropDownList(this, list, this->filter.mode, widget); } break; } case WID_GS_TYPE_DROPDOWN: { DropDownList *list = this->BuildDropDownList(widget); if (list != NULL) { ShowDropDownList(this, list, this->filter.type, widget); } break; } } if (widget != WID_GS_OPTIONSPANEL) return; uint btn = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GS_OPTIONSPANEL, SETTINGTREE_TOP_OFFSET); if (btn == INT_MAX || (int)btn < this->warn_lines) return; btn -= this->warn_lines; uint cur_row = 0; BaseSettingEntry *clicked_entry = GetSettingsTree().FindEntry(btn, &cur_row); if (clicked_entry == NULL) return; // Clicked below the last setting of the page int x = (_current_text_dir == TD_RTL ? this->width - 1 - pt.x : pt.x) - SETTINGTREE_LEFT_OFFSET - (clicked_entry->level + 1) * LEVEL_WIDTH; // Shift x coordinate if (x < 0) return; // Clicked left of the entry SettingsPage *clicked_page = dynamic_cast(clicked_entry); if (clicked_page != NULL) { this->SetDisplayedHelpText(NULL); clicked_page->folded = !clicked_page->folded; // Flip 'folded'-ness of the sub-page this->manually_changed_folding = true; this->InvalidateData(); return; } SettingEntry *pe = dynamic_cast(clicked_entry); assert(pe != NULL); const SettingDesc *sd = pe->setting; /* return if action is only active in network, or only settable by server */ if (!sd->IsEditable()) { this->SetDisplayedHelpText(pe); return; } const void *var = ResolveVariableAddress(settings_ptr, sd); int32 value = (int32)ReadValue(var, sd->save.conv); /* clicked on the icon on the left side. Either scroller, bool on/off or dropdown */ if (x < SETTING_BUTTON_WIDTH && (sd->desc.flags & SGF_MULTISTRING)) { const SettingDescBase *sdb = &sd->desc; this->SetDisplayedHelpText(pe); if (this->valuedropdown_entry == pe) { /* unclick the dropdown */ HideDropDownMenu(this); this->closing_dropdown = false; this->valuedropdown_entry->SetButtons(0); this->valuedropdown_entry = NULL; } else { if (this->valuedropdown_entry != NULL) this->valuedropdown_entry->SetButtons(0); this->closing_dropdown = false; const NWidgetBase *wid = this->GetWidget(WID_GS_OPTIONSPANEL); int rel_y = (pt.y - (int)wid->pos_y - SETTINGTREE_TOP_OFFSET) % wid->resize_y; Rect wi_rect; wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x); wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1; wi_rect.top = pt.y - rel_y + (SETTING_HEIGHT - SETTING_BUTTON_HEIGHT) / 2; wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1; /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */ if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) { this->valuedropdown_entry = pe; this->valuedropdown_entry->SetButtons(SEF_LEFT_DEPRESSED); DropDownList *list = new DropDownList(); for (int i = sdb->min; i <= (int)sdb->max; i++) { *list->Append() = new DropDownListStringItem(sdb->str_val + i - sdb->min, i, false); } ShowDropDownListAt(this, list, value, -1, wi_rect, COLOUR_ORANGE, true); } } this->SetDirty(); } else if (x < SETTING_BUTTON_WIDTH) { this->SetDisplayedHelpText(pe); const SettingDescBase *sdb = &sd->desc; int32 oldvalue = value; switch (sdb->cmd) { case SDT_BOOLX: value ^= 1; break; case SDT_ONEOFMANY: case SDT_NUMX: { /* Add a dynamic step-size to the scroller. In a maximum of * 50-steps you should be able to get from min to max, * unless specified otherwise in the 'interval' variable * of the current setting. */ uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval; if (step == 0) step = 1; /* don't allow too fast scrolling */ if ((this->flags & WF_TIMEOUT) && this->timeout_timer > 1) { _left_button_clicked = false; return; } /* Increase or decrease the value and clamp it to extremes */ if (x >= SETTING_BUTTON_WIDTH / 2) { value += step; if (sdb->min < 0) { assert((int32)sdb->max >= 0); if (value > (int32)sdb->max) value = (int32)sdb->max; } else { if ((uint32)value > sdb->max) value = (int32)sdb->max; } if (value < sdb->min) value = sdb->min; // skip between "disabled" and minimum } else { value -= step; if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min; } /* Set up scroller timeout for numeric values */ if (value != oldvalue) { if (this->clicked_entry != NULL) { // Release previous buttons if any this->clicked_entry->SetButtons(0); } this->clicked_entry = pe; this->clicked_entry->SetButtons((x >= SETTING_BUTTON_WIDTH / 2) != (_current_text_dir == TD_RTL) ? SEF_RIGHT_DEPRESSED : SEF_LEFT_DEPRESSED); this->SetTimeout(); _left_button_clicked = false; } break; } default: NOT_REACHED(); } if (value != oldvalue) { if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { SetCompanySetting(pe->index, value); } else { SetSettingValue(pe->index, value); } this->SetDirty(); } } else { /* Only open editbox if clicked for the second time, and only for types where it is sensible for. */ if (this->last_clicked == pe && sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) { /* Show the correct currency-translated value */ if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate; this->valuewindow_entry = pe; SetDParam(0, value); ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_ENABLE_DEFAULT); } this->SetDisplayedHelpText(pe); } } virtual void OnTimeout() { if (this->clicked_entry != NULL) { // On timeout, release any depressed buttons this->clicked_entry->SetButtons(0); this->clicked_entry = NULL; this->SetDirty(); } } virtual void OnQueryTextFinished(char *str) { /* The user pressed cancel */ if (str == NULL) return; assert(this->valuewindow_entry != NULL); const SettingDesc *sd = this->valuewindow_entry->setting; int32 value; if (!StrEmpty(str)) { value = atoi(str); /* Save the correct currency-translated value */ if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate; } else { value = (int32)(size_t)sd->desc.def; } if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { SetCompanySetting(this->valuewindow_entry->index, value); } else { SetSettingValue(this->valuewindow_entry->index, value); } this->SetDirty(); } virtual void OnDropdownSelect(int widget, int index) { switch (widget) { case WID_GS_RESTRICT_DROPDOWN: this->filter.mode = (RestrictionMode)index; if (this->filter.mode == RM_CHANGED_AGAINST_DEFAULT || this->filter.mode == RM_CHANGED_AGAINST_NEW) { if (!this->manually_changed_folding) { /* Expand all when selecting 'changes'. Update the filter state first, in case it becomes less restrictive in some cases. */ GetSettingsTree().UpdateFilterState(this->filter, false); GetSettingsTree().UnFoldAll(); } } else { /* Non-'changes' filter. Save as default. */ _settings_client.gui.settings_restriction_mode = this->filter.mode; } this->InvalidateData(); break; case WID_GS_TYPE_DROPDOWN: this->filter.type = (SettingType)index; this->InvalidateData(); break; default: if (widget < 0) { /* Deal with drop down boxes on the panel. */ assert(this->valuedropdown_entry != NULL); const SettingDesc *sd = this->valuedropdown_entry->setting; assert(sd->desc.flags & SGF_MULTISTRING); if ((sd->desc.flags & SGF_PER_COMPANY) != 0) { SetCompanySetting(this->valuedropdown_entry->index, index); } else { SetSettingValue(this->valuedropdown_entry->index, index); } this->SetDirty(); } break; } } virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) { if (widget >= 0) { /* Normally the default implementation of OnDropdownClose() takes care of * a few things. We want that behaviour here too, but only for * "normal" dropdown boxes. The special dropdown boxes added for every * setting that needs one can't have this call. */ Window::OnDropdownClose(pt, widget, index, instant_close); } else { /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether * the same dropdown button was clicked again, and then not open the dropdown again. * So, we only remember that it was closed, and process it on the next OnPaint, which is * after OnClick. */ assert(this->valuedropdown_entry != NULL); this->closing_dropdown = true; this->SetDirty(); } } virtual void OnInvalidateData(int data = 0, bool gui_scope = true) { if (!gui_scope) return; /* Update which settings are to be visible. */ RestrictionMode min_level = (this->filter.mode <= RM_ALL) ? this->filter.mode : RM_BASIC; this->filter.min_cat = min_level; this->filter.type_hides = false; GetSettingsTree().UpdateFilterState(this->filter, false); if (this->filter.string.IsEmpty()) { this->warn_missing = WHR_NONE; } else if (min_level < this->filter.min_cat) { this->warn_missing = this->filter.type_hides ? WHR_CATEGORY_TYPE : WHR_CATEGORY; } else { this->warn_missing = this->filter.type_hides ? WHR_TYPE : WHR_NONE; } this->vscroll->SetCount(GetSettingsTree().Length() + this->warn_lines); if (this->last_clicked != NULL && !GetSettingsTree().IsVisible(this->last_clicked)) { this->SetDisplayedHelpText(NULL); } bool all_folded = true; bool all_unfolded = true; GetSettingsTree().GetFoldingState(all_folded, all_unfolded); this->SetWidgetDisabledState(WID_GS_EXPAND_ALL, all_unfolded); this->SetWidgetDisabledState(WID_GS_COLLAPSE_ALL, all_folded); } virtual void OnEditboxChanged(int wid) { if (wid == WID_GS_FILTER) { this->filter.string.SetFilterTerm(this->filter_editbox.text.buf); if (!this->filter.string.IsEmpty() && !this->manually_changed_folding) { /* User never expanded/collapsed single pages and entered a filter term. * Expand everything, to save weird expand clicks, */ GetSettingsTree().UnFoldAll(); } this->InvalidateData(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_GS_OPTIONSPANEL, SETTINGTREE_TOP_OFFSET + SETTINGTREE_BOTTOM_OFFSET); } }; GameSettings *GameSettingsWindow::settings_ptr = NULL; static const NWidgetPart _nested_settings_selection_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_CONFIG_SETTING_TREE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE), EndContainer(), NWidget(WWT_PANEL, COLOUR_MAUVE), NWidget(NWID_VERTICAL), SetPIP(0, WD_PAR_VSEP_NORMAL, 0), SetPadding(WD_TEXTPANEL_TOP, 0, WD_TEXTPANEL_BOTTOM, 0), NWidget(NWID_HORIZONTAL), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_CATEGORY), SetDataTip(STR_CONFIG_SETTING_RESTRICT_CATEGORY, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_RESTRICT_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_BLACK_STRING, STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), NWidget(WWT_TEXT, COLOUR_MAUVE, WID_GS_RESTRICT_TYPE), SetDataTip(STR_CONFIG_SETTING_RESTRICT_TYPE, STR_NULL), NWidget(WWT_DROPDOWN, COLOUR_MAUVE, WID_GS_TYPE_DROPDOWN), SetMinimalSize(100, 12), SetDataTip(STR_BLACK_STRING, STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT), SetFill(1, 0), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), SetPadding(0, 0, WD_TEXTPANEL_BOTTOM, 0), SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT), NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_CONFIG_SETTING_FILTER_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_GS_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_MAUVE, WID_GS_OPTIONSPANEL), SetMinimalSize(400, 174), SetScrollbar(WID_GS_SCROLLBAR), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_GS_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_MAUVE), SetMinimalSize(400, 40), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GS_HELP_TEXT), SetMinimalSize(300, 25), SetFill(1, 1), SetResize(1, 0), SetPadding(WD_FRAMETEXT_TOP, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_BOTTOM, WD_FRAMETEXT_LEFT), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_EXPAND_ALL), SetDataTip(STR_CONFIG_SETTING_EXPAND_ALL, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_COLLAPSE_ALL), SetDataTip(STR_CONFIG_SETTING_COLLAPSE_ALL, STR_NULL), NWidget(WWT_PANEL, COLOUR_MAUVE), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), EndContainer(), }; static WindowDesc _settings_selection_desc( WDP_CENTER, "settings", 510, 450, WC_GAME_OPTIONS, WC_NONE, 0, _nested_settings_selection_widgets, lengthof(_nested_settings_selection_widgets) ); /** Open advanced settings window. */ void ShowGameSettings() { DeleteWindowByClass(WC_GAME_OPTIONS); new GameSettingsWindow(&_settings_selection_desc); } /** * Draw [<][>] boxes. * @param x the x position to draw * @param y the y position to draw * @param button_colour the colour of the button * @param state 0 = none clicked, 1 = first clicked, 2 = second clicked * @param clickable_left is the left button clickable? * @param clickable_right is the right button clickable? */ void DrawArrowButtons(int x, int y, Colours button_colour, byte state, bool clickable_left, bool clickable_right) { int colour = _colour_gradient[button_colour][2]; Dimension dim = NWidgetScrollbar::GetHorizontalDimension(); DrawFrameRect(x, y, x + dim.width - 1, y + dim.height - 1, button_colour, (state == 1) ? FR_LOWERED : FR_NONE); DrawFrameRect(x + dim.width, y, x + dim.width + dim.width - 1, y + dim.height - 1, button_colour, (state == 2) ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_LEFT, PAL_NONE, x + WD_IMGBTN_LEFT, y + WD_IMGBTN_TOP); DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, x + WD_IMGBTN_LEFT + dim.width, y + WD_IMGBTN_TOP); /* Grey out the buttons that aren't clickable */ bool rtl = _current_text_dir == TD_RTL; if (rtl ? !clickable_right : !clickable_left) { GfxFillRect(x + 1, y, x + dim.width - 1, y + dim.height - 2, colour, FILLRECT_CHECKER); } if (rtl ? !clickable_left : !clickable_right) { GfxFillRect(x + dim.width + 1, y, x + dim.width + dim.width - 1, y + dim.height - 2, colour, FILLRECT_CHECKER); } } /** * Draw a dropdown button. * @param x the x position to draw * @param y the y position to draw * @param button_colour the colour of the button * @param state true = lowered * @param clickable is the button clickable? */ void DrawDropDownButton(int x, int y, Colours button_colour, bool state, bool clickable) { int colour = _colour_gradient[button_colour][2]; DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, button_colour, state ? FR_LOWERED : FR_NONE); DrawSprite(SPR_ARROW_DOWN, PAL_NONE, x + (SETTING_BUTTON_WIDTH - NWidgetScrollbar::GetVerticalDimension().width) / 2 + state, y + 2 + state); if (!clickable) { GfxFillRect(x + 1, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 2, colour, FILLRECT_CHECKER); } } /** * Draw a toggle button. * @param x the x position to draw * @param y the y position to draw * @param state true = lowered * @param clickable is the button clickable? */ void DrawBoolButton(int x, int y, bool state, bool clickable) { static const Colours _bool_ctabs[2][2] = {{COLOUR_CREAM, COLOUR_RED}, {COLOUR_DARK_GREEN, COLOUR_GREEN}}; DrawFrameRect(x, y, x + SETTING_BUTTON_WIDTH - 1, y + SETTING_BUTTON_HEIGHT - 1, _bool_ctabs[state][clickable], state ? FR_LOWERED : FR_NONE); } struct CustomCurrencyWindow : Window { int query_widget; CustomCurrencyWindow(WindowDesc *desc) : Window(desc) { this->InitNested(); SetButtonState(); } void SetButtonState() { this->SetWidgetDisabledState(WID_CC_RATE_DOWN, _custom_currency.rate == 1); this->SetWidgetDisabledState(WID_CC_RATE_UP, _custom_currency.rate == UINT16_MAX); this->SetWidgetDisabledState(WID_CC_YEAR_DOWN, _custom_currency.to_euro == CF_NOEURO); this->SetWidgetDisabledState(WID_CC_YEAR_UP, _custom_currency.to_euro == MAX_YEAR); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_CC_RATE: SetDParam(0, 1); SetDParam(1, 1); break; case WID_CC_SEPARATOR: SetDParamStr(0, _custom_currency.separator); break; case WID_CC_PREFIX: SetDParamStr(0, _custom_currency.prefix); break; case WID_CC_SUFFIX: SetDParamStr(0, _custom_currency.suffix); break; case WID_CC_YEAR: SetDParam(0, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER); SetDParam(1, _custom_currency.to_euro); break; case WID_CC_PREVIEW: SetDParam(0, 10000); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { /* Set the appropriate width for the edit 'buttons' */ case WID_CC_SEPARATOR_EDIT: case WID_CC_PREFIX_EDIT: case WID_CC_SUFFIX_EDIT: size->width = this->GetWidget(WID_CC_RATE_DOWN)->smallest_x + this->GetWidget(WID_CC_RATE_UP)->smallest_x; break; /* Make sure the window is wide enough for the widest exchange rate */ case WID_CC_RATE: SetDParam(0, 1); SetDParam(1, INT32_MAX); *size = GetStringBoundingBox(STR_CURRENCY_EXCHANGE_RATE); break; } } virtual void OnClick(Point pt, int widget, int click_count) { int line = 0; int len = 0; StringID str = 0; CharSetFilter afilter = CS_ALPHANUMERAL; switch (widget) { case WID_CC_RATE_DOWN: if (_custom_currency.rate > 1) _custom_currency.rate--; if (_custom_currency.rate == 1) this->DisableWidget(WID_CC_RATE_DOWN); this->EnableWidget(WID_CC_RATE_UP); break; case WID_CC_RATE_UP: if (_custom_currency.rate < UINT16_MAX) _custom_currency.rate++; if (_custom_currency.rate == UINT16_MAX) this->DisableWidget(WID_CC_RATE_UP); this->EnableWidget(WID_CC_RATE_DOWN); break; case WID_CC_RATE: SetDParam(0, _custom_currency.rate); str = STR_JUST_INT; len = 5; line = WID_CC_RATE; afilter = CS_NUMERAL; break; case WID_CC_SEPARATOR_EDIT: case WID_CC_SEPARATOR: SetDParamStr(0, _custom_currency.separator); str = STR_JUST_RAW_STRING; len = 1; line = WID_CC_SEPARATOR; break; case WID_CC_PREFIX_EDIT: case WID_CC_PREFIX: SetDParamStr(0, _custom_currency.prefix); str = STR_JUST_RAW_STRING; len = 12; line = WID_CC_PREFIX; break; case WID_CC_SUFFIX_EDIT: case WID_CC_SUFFIX: SetDParamStr(0, _custom_currency.suffix); str = STR_JUST_RAW_STRING; len = 12; line = WID_CC_SUFFIX; break; case WID_CC_YEAR_DOWN: _custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ? CF_NOEURO : _custom_currency.to_euro - 1; if (_custom_currency.to_euro == CF_NOEURO) this->DisableWidget(WID_CC_YEAR_DOWN); this->EnableWidget(WID_CC_YEAR_UP); break; case WID_CC_YEAR_UP: _custom_currency.to_euro = Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR); if (_custom_currency.to_euro == MAX_YEAR) this->DisableWidget(WID_CC_YEAR_UP); this->EnableWidget(WID_CC_YEAR_DOWN); break; case WID_CC_YEAR: SetDParam(0, _custom_currency.to_euro); str = STR_JUST_INT; len = 7; line = WID_CC_YEAR; afilter = CS_NUMERAL; break; } if (len != 0) { this->query_widget = line; ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, this, afilter, QSF_NONE); } this->SetTimeout(); this->SetDirty(); } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; switch (this->query_widget) { case WID_CC_RATE: _custom_currency.rate = Clamp(atoi(str), 1, UINT16_MAX); break; case WID_CC_SEPARATOR: // Thousands separator strecpy(_custom_currency.separator, str, lastof(_custom_currency.separator)); break; case WID_CC_PREFIX: strecpy(_custom_currency.prefix, str, lastof(_custom_currency.prefix)); break; case WID_CC_SUFFIX: strecpy(_custom_currency.suffix, str, lastof(_custom_currency.suffix)); break; case WID_CC_YEAR: { // Year to switch to euro int val = atoi(str); _custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR)); break; } } MarkWholeScreenDirty(); SetButtonState(); } virtual void OnTimeout() { this->SetDirty(); } }; static const NWidgetPart _nested_cust_currency_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CURRENCY_WINDOW, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(7, 3, 0), NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_RATE_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP), NWidget(NWID_SPACER), SetMinimalSize(5, 0), NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_RATE), SetDataTip(STR_CURRENCY_EXCHANGE_RATE, STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SEPARATOR_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(0, 1), NWidget(NWID_SPACER), SetMinimalSize(5, 0), NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SEPARATOR), SetDataTip(STR_CURRENCY_SEPARATOR, STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_PREFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(0, 1), NWidget(NWID_SPACER), SetMinimalSize(5, 0), NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_PREFIX), SetDataTip(STR_CURRENCY_PREFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), NWidget(WWT_PUSHBTN, COLOUR_DARK_BLUE, WID_CC_SUFFIX_EDIT), SetDataTip(0x0, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(0, 1), NWidget(NWID_SPACER), SetMinimalSize(5, 0), NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_SUFFIX), SetDataTip(STR_CURRENCY_SUFFIX, STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), SetPIP(10, 0, 5), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_DOWN), SetDataTip(AWV_DECREASE, STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_CC_YEAR_UP), SetDataTip(AWV_INCREASE, STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), NWidget(NWID_SPACER), SetMinimalSize(5, 0), NWidget(WWT_TEXT, COLOUR_BLUE, WID_CC_YEAR), SetDataTip(STR_JUST_STRING, STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP), SetFill(1, 0), EndContainer(), EndContainer(), NWidget(WWT_LABEL, COLOUR_BLUE, WID_CC_PREVIEW), SetDataTip(STR_CURRENCY_PREVIEW, STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP), SetPadding(15, 1, 18, 2), EndContainer(), }; static WindowDesc _cust_currency_desc( WDP_CENTER, NULL, 0, 0, WC_CUSTOM_CURRENCY, WC_NONE, 0, _nested_cust_currency_widgets, lengthof(_nested_cust_currency_widgets) ); /** Open custom currency window. */ static void ShowCustCurrency() { DeleteWindowById(WC_CUSTOM_CURRENCY, 0); new CustomCurrencyWindow(&_cust_currency_desc); } openttd-1.5.3/src/map.cpp0000644000000000000000000003007312627373441013757 0ustar rootroot/* $Id: map.cpp 26503 2014-04-24 18:49:24Z rubidium $ */ /* * 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 map.cpp Base functions related to the map and distances on them. */ #include "stdafx.h" #include "debug.h" #include "core/alloc_func.hpp" #include "water_map.h" #include "string_func.h" #include "safeguards.h" #if defined(_MSC_VER) /* Why the hell is that not in all MSVC headers?? */ extern "C" _CRTIMP void __cdecl _assert(void *, void *, unsigned); #endif uint _map_log_x; ///< 2^_map_log_x == _map_size_x uint _map_log_y; ///< 2^_map_log_y == _map_size_y uint _map_size_x; ///< Size of the map along the X uint _map_size_y; ///< Size of the map along the Y uint _map_size; ///< The number of tiles on the map uint _map_tile_mask; ///< _map_size - 1 (to mask the mapsize) Tile *_m = NULL; ///< Tiles of the map TileExtended *_me = NULL; ///< Extended Tiles of the map /** * (Re)allocates a map with the given dimension * @param size_x the width of the map along the NE/SW edge * @param size_y the 'height' of the map along the SE/NW edge */ void AllocateMap(uint size_x, uint size_y) { /* Make sure that the map size is within the limits and that * size of both axes is a power of 2. */ if (!IsInsideMM(size_x, MIN_MAP_SIZE, MAX_MAP_SIZE + 1) || !IsInsideMM(size_y, MIN_MAP_SIZE, MAX_MAP_SIZE + 1) || (size_x & (size_x - 1)) != 0 || (size_y & (size_y - 1)) != 0) { error("Invalid map size"); } DEBUG(map, 1, "Allocating map of size %dx%d", size_x, size_y); _map_log_x = FindFirstBit(size_x); _map_log_y = FindFirstBit(size_y); _map_size_x = size_x; _map_size_y = size_y; _map_size = size_x * size_y; _map_tile_mask = _map_size - 1; free(_m); free(_me); _m = CallocT(_map_size); _me = CallocT(_map_size); } #ifdef _DEBUG TileIndex TileAdd(TileIndex tile, TileIndexDiff add, const char *exp, const char *file, int line) { int dx; int dy; uint x; uint y; dx = add & MapMaxX(); if (dx >= (int)MapSizeX() / 2) dx -= MapSizeX(); dy = (add - dx) / (int)MapSizeX(); x = TileX(tile) + dx; y = TileY(tile) + dy; if (x >= MapSizeX() || y >= MapSizeY()) { char buf[512]; seprintf(buf, lastof(buf), "TILE_ADD(%s) when adding 0x%.4X and 0x%.4X failed", exp, tile, add); #if !defined(_MSC_VER) || defined(WINCE) fprintf(stderr, "%s:%d %s\n", file, line, buf); #else _assert(buf, (char*)file, line); #endif } assert(TileXY(x, y) == TILE_MASK(tile + add)); return TileXY(x, y); } #endif /** * This function checks if we add addx/addy to tile, if we * do wrap around the edges. For example, tile = (10,2) and * addx = +3 and addy = -4. This function will now return * INVALID_TILE, because the y is wrapped. This is needed in * for example, farmland. When the tile is not wrapped, * the result will be tile + TileDiffXY(addx, addy) * * @param tile the 'starting' point of the adding * @param addx the amount of tiles in the X direction to add * @param addy the amount of tiles in the Y direction to add * @return translated tile, or INVALID_TILE when it would've wrapped. */ TileIndex TileAddWrap(TileIndex tile, int addx, int addy) { uint x = TileX(tile) + addx; uint y = TileY(tile) + addy; /* Disallow void tiles at the north border. */ if ((x == 0 || y == 0) && _settings_game.construction.freeform_edges) return INVALID_TILE; /* Are we about to wrap? */ if (x >= MapMaxX() || y >= MapMaxY()) return INVALID_TILE; return TileXY(x, y); } /** 'Lookup table' for tile offsets given a DiagDirection */ extern const TileIndexDiffC _tileoffs_by_diagdir[] = { {-1, 0}, ///< DIAGDIR_NE { 0, 1}, ///< DIAGDIR_SE { 1, 0}, ///< DIAGDIR_SW { 0, -1} ///< DIAGDIR_NW }; /** 'Lookup table' for tile offsets given a Direction */ extern const TileIndexDiffC _tileoffs_by_dir[] = { {-1, -1}, ///< DIR_N {-1, 0}, ///< DIR_NE {-1, 1}, ///< DIR_E { 0, 1}, ///< DIR_SE { 1, 1}, ///< DIR_S { 1, 0}, ///< DIR_SW { 1, -1}, ///< DIR_W { 0, -1} ///< DIR_NW }; /** * Gets the Manhattan distance between the two given tiles. * The Manhattan distance is the sum of the delta of both the * X and Y component. * Also known as L1-Norm * @param t0 the start tile * @param t1 the end tile * @return the distance */ uint DistanceManhattan(TileIndex t0, TileIndex t1) { const uint dx = Delta(TileX(t0), TileX(t1)); const uint dy = Delta(TileY(t0), TileY(t1)); return dx + dy; } /** * Gets the 'Square' distance between the two given tiles. * The 'Square' distance is the square of the shortest (straight line) * distance between the two tiles. * Also known as euclidian- or L2-Norm squared. * @param t0 the start tile * @param t1 the end tile * @return the distance */ uint DistanceSquare(TileIndex t0, TileIndex t1) { const int dx = TileX(t0) - TileX(t1); const int dy = TileY(t0) - TileY(t1); return dx * dx + dy * dy; } /** * Gets the biggest distance component (x or y) between the two given tiles. * Also known as L-Infinity-Norm. * @param t0 the start tile * @param t1 the end tile * @return the distance */ uint DistanceMax(TileIndex t0, TileIndex t1) { const uint dx = Delta(TileX(t0), TileX(t1)); const uint dy = Delta(TileY(t0), TileY(t1)); return max(dx, dy); } /** * Gets the biggest distance component (x or y) between the two given tiles * plus the Manhattan distance, i.e. two times the biggest distance component * and once the smallest component. * @param t0 the start tile * @param t1 the end tile * @return the distance */ uint DistanceMaxPlusManhattan(TileIndex t0, TileIndex t1) { const uint dx = Delta(TileX(t0), TileX(t1)); const uint dy = Delta(TileY(t0), TileY(t1)); return dx > dy ? 2 * dx + dy : 2 * dy + dx; } /** * Param the minimum distance to an edge * @param tile the tile to get the distance from * @return the distance from the edge in tiles */ uint DistanceFromEdge(TileIndex tile) { const uint xl = TileX(tile); const uint yl = TileY(tile); const uint xh = MapSizeX() - 1 - xl; const uint yh = MapSizeY() - 1 - yl; const uint minl = min(xl, yl); const uint minh = min(xh, yh); return min(minl, minh); } /** * Gets the distance to the edge of the map in given direction. * @param tile the tile to get the distance from * @param dir the direction of interest * @return the distance from the edge in tiles */ uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir) { switch (dir) { case DIAGDIR_NE: return TileX(tile) - (_settings_game.construction.freeform_edges ? 1 : 0); case DIAGDIR_NW: return TileY(tile) - (_settings_game.construction.freeform_edges ? 1 : 0); case DIAGDIR_SW: return MapMaxX() - TileX(tile) - 1; case DIAGDIR_SE: return MapMaxY() - TileY(tile) - 1; default: NOT_REACHED(); } } /** * Function performing a search around a center tile and going outward, thus in circle. * Although it really is a square search... * Every tile will be tested by means of the callback function proc, * which will determine if yes or no the given tile meets criteria of search. * @param tile to start the search from. Upon completion, it will return the tile matching the search * @param size: number of tiles per side of the desired search area * @param proc: callback testing function pointer. * @param user_data to be passed to the callback function. Depends on the implementation * @return result of the search * @pre proc != NULL * @pre size > 0 */ bool CircularTileSearch(TileIndex *tile, uint size, TestTileOnSearchProc proc, void *user_data) { assert(proc != NULL); assert(size > 0); if (size % 2 == 1) { /* If the length of the side is uneven, the center has to be checked * separately, as the pattern of uneven sides requires to go around the center */ if (proc(*tile, user_data)) return true; /* If tile test is not successful, get one tile up, * ready for a test in first circle around center tile */ *tile = TILE_ADD(*tile, TileOffsByDir(DIR_N)); return CircularTileSearch(tile, size / 2, 1, 1, proc, user_data); } else { return CircularTileSearch(tile, size / 2, 0, 0, proc, user_data); } } /** * Generalized circular search allowing for rectangles and a hole. * Function performing a search around a center rectangle and going outward. * The center rectangle is left out from the search. To do a rectangular search * without a hole, set either h or w to zero. * Every tile will be tested by means of the callback function proc, * which will determine if yes or no the given tile meets criteria of search. * @param tile to start the search from. Upon completion, it will return the tile matching the search. * This tile should be directly north of the hole (if any). * @param radius How many tiles to search outwards. Note: This is a radius and thus different * from the size parameter of the other CircularTileSearch function, which is a diameter. * @param w the width of the inner rectangle * @param h the height of the inner rectangle * @param proc callback testing function pointer. * @param user_data to be passed to the callback function. Depends on the implementation * @return result of the search * @pre proc != NULL * @pre radius > 0 */ bool CircularTileSearch(TileIndex *tile, uint radius, uint w, uint h, TestTileOnSearchProc proc, void *user_data) { assert(proc != NULL); assert(radius > 0); uint x = TileX(*tile) + w + 1; uint y = TileY(*tile); const uint extent[DIAGDIR_END] = { w, h, w, h }; for (uint n = 0; n < radius; n++) { for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { /* Is the tile within the map? */ for (uint j = extent[dir] + n * 2 + 1; j != 0; j--) { if (x < MapSizeX() && y < MapSizeY()) { TileIndex t = TileXY(x, y); /* Is the callback successful? */ if (proc(t, user_data)) { /* Stop the search */ *tile = t; return true; } } /* Step to the next 'neighbour' in the circular line */ x += _tileoffs_by_diagdir[dir].x; y += _tileoffs_by_diagdir[dir].y; } } /* Jump to next circle to test */ x += _tileoffs_by_dir[DIR_W].x; y += _tileoffs_by_dir[DIR_W].y; } *tile = INVALID_TILE; return false; } /** * Finds the distance for the closest tile with water/land given a tile * @param tile the tile to find the distance too * @param water whether to find water or land * @return distance to nearest water (max 0x7F) / land (max 0x1FF; 0x200 if there is no land) */ uint GetClosestWaterDistance(TileIndex tile, bool water) { if (HasTileWaterGround(tile) == water) return 0; uint max_dist = water ? 0x7F : 0x200; int x = TileX(tile); int y = TileY(tile); uint max_x = MapMaxX(); uint max_y = MapMaxY(); uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0; /* go in a 'spiral' with increasing manhattan distance in each iteration */ for (uint dist = 1; dist < max_dist; dist++) { /* next 'diameter' */ y--; /* going counter-clockwise around this square */ for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { static const int8 ddx[DIAGDIR_END] = { -1, 1, 1, -1}; static const int8 ddy[DIAGDIR_END] = { 1, 1, -1, -1}; int dx = ddx[dir]; int dy = ddy[dir]; /* each side of this square has length 'dist' */ for (uint a = 0; a < dist; a++) { /* MP_VOID tiles are not checked (interval is [min; max) for IsInsideMM())*/ if (IsInsideMM(x, min_xy, max_x) && IsInsideMM(y, min_xy, max_y)) { TileIndex t = TileXY(x, y); if (HasTileWaterGround(t) == water) return dist; } x += dx; y += dy; } } } if (!water) { /* no land found - is this a water-only map? */ for (TileIndex t = 0; t < MapSize(); t++) { if (!IsTileType(t, MP_VOID) && !IsTileType(t, MP_WATER)) return 0x1FF; } } return max_dist; } openttd-1.5.3/src/newgrf_industries.cpp0000644000000000000000000006062012627373445016750 0ustar rootroot/* $Id: newgrf_industries.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_industries.cpp Handling of NewGRF industries. */ #include "stdafx.h" #include "debug.h" #include "industry.h" #include "newgrf_industries.h" #include "newgrf_town.h" #include "newgrf_cargo.h" #include "window_func.h" #include "town.h" #include "company_base.h" #include "error.h" #include "strings_func.h" #include "core/random_func.hpp" #include "table/strings.h" #include "safeguards.h" /* Since the industry IDs defined by the GRF file don't necessarily correlate * to those used by the game, the IDs used for overriding old industries must be * translated when the idustry spec is set. */ IndustryOverrideManager _industry_mngr(NEW_INDUSTRYOFFSET, NUM_INDUSTRYTYPES, INVALID_INDUSTRYTYPE); IndustryTileOverrideManager _industile_mngr(NEW_INDUSTRYTILEOFFSET, NUM_INDUSTRYTILES, INVALID_INDUSTRYTILE); /** * Map the GRF local type to an industry type. * @param grf_type The GRF local type. * @param grf_id The GRF of the local type. * @return The industry type in the global scope. */ IndustryType MapNewGRFIndustryType(IndustryType grf_type, uint32 grf_id) { if (grf_type == IT_INVALID) return IT_INVALID; if (!HasBit(grf_type, 7)) return GB(grf_type, 0, 6); return _industry_mngr.GetID(GB(grf_type, 0, 6), grf_id); } /** * Make an analysis of a tile and check for its belonging to the same * industry, and/or the same grf file * @param tile TileIndex of the tile to query * @param i Industry to which to compare the tile to * @param cur_grfid GRFID of the current callback chain * @return value encoded as per NFO specs */ uint32 GetIndustryIDAtOffset(TileIndex tile, const Industry *i, uint32 cur_grfid) { if (!i->TileBelongsToIndustry(tile)) { /* No industry and/or the tile does not have the same industry as the one we match it with */ return 0xFFFF; } IndustryGfx gfx = GetCleanIndustryGfx(tile); const IndustryTileSpec *indtsp = GetIndustryTileSpec(gfx); if (gfx < NEW_INDUSTRYTILEOFFSET) { // Does it belongs to an old type? /* It is an old tile. We have to see if it's been overridden */ if (indtsp->grf_prop.override == INVALID_INDUSTRYTILE) { // has it been overridden? return 0xFF << 8 | gfx; // no. Tag FF + the gfx id of that tile } /* Overridden */ const IndustryTileSpec *tile_ovr = GetIndustryTileSpec(indtsp->grf_prop.override); if (tile_ovr->grf_prop.grffile->grfid == cur_grfid) { return tile_ovr->grf_prop.local_id; // same grf file } else { return 0xFFFE; // not the same grf file } } /* Not an 'old type' tile */ if (indtsp->grf_prop.spritegroup[0] != NULL) { // tile has a spritegroup ? if (indtsp->grf_prop.grffile->grfid == cur_grfid) { // same industry, same grf ? return indtsp->grf_prop.local_id; } else { return 0xFFFE; // Defined in another grf file } } /* The tile has no spritegroup */ return 0xFF << 8 | indtsp->grf_prop.subst_id; // so just give him the substitute } static uint32 GetClosestIndustry(TileIndex tile, IndustryType type, const Industry *current) { uint32 best_dist = UINT32_MAX; const Industry *i; FOR_ALL_INDUSTRIES(i) { if (i->type != type || i == current) continue; best_dist = min(best_dist, DistanceManhattan(tile, i->location.tile)); } return best_dist; } /** * Implementation of both var 67 and 68 * since the mechanism is almost the same, it is easier to regroup them on the same * function. * @param param_setID parameter given to the callback, which is the set id, or the local id, in our terminology * @param layout_filter on what layout do we filter? * @param town_filter Do we filter on the same town as the current industry? * @param current Industry for which the inquiry is made * @return the formatted answer to the callback : rr(reserved) cc(count) dddd(manhattan distance of closest sister) */ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout_filter, bool town_filter, const Industry *current) { uint32 GrfID = GetRegister(0x100); ///< Get the GRFID of the definition to look for in register 100h IndustryType ind_index; uint32 closest_dist = UINT32_MAX; byte count = 0; /* Determine what will be the industry type to look for */ switch (GrfID) { case 0: // this is a default industry type ind_index = param_setID; break; case 0xFFFFFFFF: // current grf GrfID = GetIndustrySpec(current->type)->grf_prop.grffile->grfid; /* FALL THROUGH */ default: // use the grfid specified in register 100h SetBit(param_setID, 7); // bit 7 means it is not an old type ind_index = MapNewGRFIndustryType(param_setID, GrfID); break; } /* If the industry type is invalid, there is none and the closest is far away. */ if (ind_index >= NUM_INDUSTRYTYPES) return 0 | 0xFFFF; if (layout_filter == 0 && !town_filter) { /* If the filter is 0, it could be because none was specified as well as being really a 0. * In either case, just do the regular var67 */ closest_dist = GetClosestIndustry(current->location.tile, ind_index, current); count = min(Industry::GetIndustryTypeCount(ind_index), UINT8_MAX); // clamp to 8 bit } else { /* Count only those who match the same industry type and layout filter * Unfortunately, we have to do it manually */ const Industry *i; FOR_ALL_INDUSTRIES(i) { if (i->type == ind_index && i != current && (i->selected_layout == layout_filter || layout_filter == 0) && (!town_filter || i->town == current->town)) { closest_dist = min(closest_dist, DistanceManhattan(current->location.tile, i->location.tile)); count++; } } } return count << 16 | GB(closest_dist, 0, 16); } /* virtual */ uint32 IndustriesScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { if (this->ro.callback == CBID_INDUSTRY_LOCATION) { /* Variables available during construction check. */ switch (variable) { case 0x80: return this->tile; case 0x81: return GB(this->tile, 8, 8); /* Pointer to the town the industry is associated with */ case 0x82: return this->industry->town->index; case 0x83: case 0x84: case 0x85: DEBUG(grf, 0, "NewGRFs shouldn't be doing pointer magic"); break; // not supported /* Number of the layout */ case 0x86: return this->industry->selected_layout; /* Ground type */ case 0x87: return GetTerrainType(this->tile); /* Town zone */ case 0x88: return GetTownRadiusGroup(this->industry->town, this->tile); /* Manhattan distance of the closest town */ case 0x89: return min(DistanceManhattan(this->industry->town->xy, this->tile), 255); /* Lowest height of the tile */ case 0x8A: return Clamp(GetTileZ(this->tile) * (this->ro.grffile->grf_version >= 8 ? 1 : TILE_HEIGHT), 0, 0xFF); /* Distance to the nearest water/land tile */ case 0x8B: return GetClosestWaterDistance(this->tile, (GetIndustrySpec(this->industry->type)->behaviour & INDUSTRYBEH_BUILT_ONWATER) == 0); /* Square of Euclidian distance from town */ case 0x8D: return min(DistanceSquare(this->industry->town->xy, this->tile), 65535); /* 32 random bits */ case 0x8F: return this->random_bits; } } const IndustrySpec *indspec = GetIndustrySpec(this->type); if (this->industry == NULL) { DEBUG(grf, 1, "Unhandled variable 0x%X (no available industry) in callback 0x%x", variable, this->ro.callback); *available = false; return UINT_MAX; } switch (variable) { case 0x40: case 0x41: case 0x42: { // waiting cargo, but only if those two callback flags are set uint16 callback = indspec->callback_mask; if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) { if ((indspec->behaviour & INDUSTRYBEH_PROD_MULTI_HNDLING) != 0) { if (this->industry->prod_level == 0) return 0; return min(this->industry->incoming_cargo_waiting[variable - 0x40] / this->industry->prod_level, (uint16)0xFFFF); } else { return min(this->industry->incoming_cargo_waiting[variable - 0x40], (uint16)0xFFFF); } } else { return 0; } } /* Manhattan distance of closes dry/water tile */ case 0x43: if (this->tile == INVALID_TILE) break; return GetClosestWaterDistance(this->tile, (indspec->behaviour & INDUSTRYBEH_BUILT_ONWATER) == 0); /* Layout number */ case 0x44: return this->industry->selected_layout; /* Company info */ case 0x45: { byte colours = 0; bool is_ai = false; const Company *c = Company::GetIfValid(this->industry->founder); if (c != NULL) { const Livery *l = &c->livery[LS_DEFAULT]; is_ai = c->is_ai; colours = l->colour1 + l->colour2 * 16; } return this->industry->founder | (is_ai ? 0x10000 : 0) | (colours << 24); } case 0x46: return this->industry->construction_date; // Date when built - long format - (in days) /* Get industry ID at offset param */ case 0x60: return GetIndustryIDAtOffset(GetNearbyTile(parameter, this->industry->location.tile, false), this->industry, this->ro.grffile->grfid); /* Get random tile bits at offset param */ case 0x61: { if (this->tile == INVALID_TILE) break; TileIndex tile = GetNearbyTile(parameter, this->tile, false); return this->industry->TileBelongsToIndustry(tile) ? GetIndustryRandomBits(tile) : 0; } /* Land info of nearby tiles */ case 0x62: if (this->tile == INVALID_TILE) break; return GetNearbyIndustryTileInformation(parameter, this->tile, INVALID_INDUSTRY, false, this->ro.grffile->grf_version >= 8); /* Animation stage of nearby tiles */ case 0x63: { if (this->tile == INVALID_TILE) break; TileIndex tile = GetNearbyTile(parameter, this->tile, false); if (this->industry->TileBelongsToIndustry(tile)) { return GetAnimationFrame(tile); } return 0xFFFFFFFF; } /* Distance of nearest industry of given type */ case 0x64: if (this->tile == INVALID_TILE) break; return GetClosestIndustry(this->tile, MapNewGRFIndustryType(parameter, indspec->grf_prop.grffile->grfid), this->industry); /* Get town zone and Manhattan distance of closest town */ case 0x65: if (this->tile == INVALID_TILE) break; return GetTownRadiusGroup(this->industry->town, this->tile) << 16 | min(DistanceManhattan(this->tile, this->industry->town->xy), 0xFFFF); /* Get square of Euclidian distance of closes town */ case 0x66: if (this->tile == INVALID_TILE) break; return GetTownRadiusGroup(this->industry->town, this->tile) << 16 | min(DistanceSquare(this->tile, this->industry->town->xy), 0xFFFF); /* Count of industry, distance of closest instance * 68 is the same as 67, but with a filtering on selected layout */ case 0x67: case 0x68: { byte layout_filter = 0; bool town_filter = false; if (variable == 0x68) { uint32 reg = GetRegister(0x101); layout_filter = GB(reg, 0, 8); town_filter = HasBit(reg, 8); } return GetCountAndDistanceOfClosestInstance(parameter, layout_filter, town_filter, this->industry); } /* Get a variable from the persistent storage */ case 0x7C: return (this->industry->psa != NULL) ? this->industry->psa->GetValue(parameter) : 0; /* Industry structure access*/ case 0x80: return this->industry->location.tile; case 0x81: return GB(this->industry->location.tile, 8, 8); /* Pointer to the town the industry is associated with */ case 0x82: return this->industry->town->index; case 0x83: case 0x84: case 0x85: DEBUG(grf, 0, "NewGRFs shouldn't be doing pointer magic"); break; // not supported case 0x86: return this->industry->location.w; case 0x87: return this->industry->location.h;// xy dimensions case 0x88: case 0x89: return this->industry->produced_cargo[variable - 0x88]; case 0x8A: return this->industry->produced_cargo_waiting[0]; case 0x8B: return GB(this->industry->produced_cargo_waiting[0], 8, 8); case 0x8C: return this->industry->produced_cargo_waiting[1]; case 0x8D: return GB(this->industry->produced_cargo_waiting[1], 8, 8); case 0x8E: case 0x8F: return this->industry->production_rate[variable - 0x8E]; case 0x90: case 0x91: case 0x92: return this->industry->accepts_cargo[variable - 0x90]; case 0x93: return this->industry->prod_level; /* amount of cargo produced so far THIS month. */ case 0x94: return this->industry->this_month_production[0]; case 0x95: return GB(this->industry->this_month_production[0], 8, 8); case 0x96: return this->industry->this_month_production[1]; case 0x97: return GB(this->industry->this_month_production[1], 8, 8); /* amount of cargo transported so far THIS month. */ case 0x98: return this->industry->this_month_transported[0]; case 0x99: return GB(this->industry->this_month_transported[0], 8, 8); case 0x9A: return this->industry->this_month_transported[1]; case 0x9B: return GB(this->industry->this_month_transported[1], 8, 8); /* fraction of cargo transported LAST month. */ case 0x9C: case 0x9D: return this->industry->last_month_pct_transported[variable - 0x9C]; /* amount of cargo produced LAST month. */ case 0x9E: return this->industry->last_month_production[0]; case 0x9F: return GB(this->industry->last_month_production[0], 8, 8); case 0xA0: return this->industry->last_month_production[1]; case 0xA1: return GB(this->industry->last_month_production[1], 8, 8); /* amount of cargo transported last month. */ case 0xA2: return this->industry->last_month_transported[0]; case 0xA3: return GB(this->industry->last_month_transported[0], 8, 8); case 0xA4: return this->industry->last_month_transported[1]; case 0xA5: return GB(this->industry->last_month_transported[1], 8, 8); case 0xA6: return this->industry->type; case 0xA7: return this->industry->founder; case 0xA8: return this->industry->random_colour; case 0xA9: return Clamp(this->industry->last_prod_year - ORIGINAL_BASE_YEAR, 0, 255); case 0xAA: return this->industry->counter; case 0xAB: return GB(this->industry->counter, 8, 8); case 0xAC: return this->industry->was_cargo_delivered; case 0xB0: return Clamp(this->industry->construction_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Date when built since 1920 (in days) case 0xB3: return this->industry->construction_type; // Construction type case 0xB4: return Clamp(this->industry->last_cargo_accepted_at - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Date last cargo accepted since 1920 (in days) } DEBUG(grf, 1, "Unhandled industry variable 0x%X", variable); *available = false; return UINT_MAX; } /* virtual */ uint32 IndustriesScopeResolver::GetRandomBits() const { return this->industry != NULL ? this->industry->random : 0; } /* virtual */ uint32 IndustriesScopeResolver::GetTriggers() const { return this->industry != NULL ? this->industry->random_triggers : 0; } /* virtual */ void IndustriesScopeResolver::SetTriggers(int triggers) const { assert(this->industry != NULL && this->industry->index != INVALID_INDUSTRY); this->industry->random_triggers = triggers; } /* virtual */ void IndustriesScopeResolver::StorePSA(uint pos, int32 value) { if (this->industry->index == INVALID_INDUSTRY) return; if (this->industry->psa == NULL) { /* There is no need to create a storage if the value is zero. */ if (value == 0) return; /* Create storage on first modification. */ const IndustrySpec *indsp = GetIndustrySpec(this->industry->type); uint32 grfid = (indsp->grf_prop.grffile != NULL) ? indsp->grf_prop.grffile->grfid : 0; assert(PersistentStorage::CanAllocateItem()); this->industry->psa = new PersistentStorage(grfid, GSF_INDUSTRIES, this->industry->location.tile); } this->industry->psa->StoreValue(pos, value); } /** * Get the grf file associated with the given industry type. * @param type Industry type to query. * @return The associated GRF file, if any. */ static const GRFFile *GetGrffile(IndustryType type) { const IndustrySpec *indspec = GetIndustrySpec(type); return (indspec != NULL) ? indspec->grf_prop.grffile : NULL; } /** * Constructor of the industries resolver. * @param tile %Tile owned by the industry. * @param industry %Industry being resolved. * @param type Type of the industry. * @param random_bits Random bits of the new industry. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ IndustriesResolverObject::IndustriesResolverObject(TileIndex tile, Industry *indus, IndustryType type, uint32 random_bits, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(GetGrffile(type), callback, callback_param1, callback_param2), industries_scope(*this, tile, indus, type, random_bits), town_scope(NULL) { this->root_spritegroup = GetIndustrySpec(type)->grf_prop.spritegroup[0]; } IndustriesResolverObject::~IndustriesResolverObject() { delete this->town_scope; } /** * Get or create the town scope object associated with the industry. * @return The associated town scope, if it exists. */ TownScopeResolver *IndustriesResolverObject::GetTown() { if (this->town_scope == NULL) { Town *t = NULL; bool readonly = true; if (this->industries_scope.industry != NULL) { t = this->industries_scope.industry->town; readonly = this->industries_scope.industry->index == INVALID_INDUSTRY; } else if (this->industries_scope.tile != INVALID_TILE) { t = ClosestTownFromTile(this->industries_scope.tile, UINT_MAX); } if (t == NULL) return NULL; this->town_scope = new TownScopeResolver(*this, t, readonly); } return this->town_scope; } /** * Scope resolver for industries. * @param ro Surrounding resolver. * @param tile %Tile owned by the industry. * @param industry %Industry being resolved. * @param type Type of the industry. * @param random_bits Random bits of the new industry. */ IndustriesScopeResolver::IndustriesScopeResolver(ResolverObject &ro, TileIndex tile, Industry *industry, IndustryType type, uint32 random_bits) : ScopeResolver(ro) { this->tile = tile; this->industry = industry; this->type = type; this->random_bits = random_bits; } /** * Perform an industry callback. * @param callback The callback to perform. * @param param1 The first parameter. * @param param2 The second parameter. * @param industry The industry to do the callback for. * @param type The type of industry to do the callback for. * @param tile The tile associated with the callback. * @return The callback result. */ uint16 GetIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, Industry *industry, IndustryType type, TileIndex tile) { IndustriesResolverObject object(tile, industry, type, 0, callback, param1, param2); return object.ResolveCallback(); } /** * Check that the industry callback allows creation of the industry. * @param tile %Tile to build the industry. * @param type Type of industry to build. * @param layout Layout number. * @param seed Seed for the random generator. * @param initial_random_bits The random bits the industry is going to have after construction. * @param founder Industry founder * @param creation_type The circumstances the industry is created under. * @return Succeeded or failed command. */ CommandCost CheckIfCallBackAllowsCreation(TileIndex tile, IndustryType type, uint layout, uint32 seed, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type) { const IndustrySpec *indspec = GetIndustrySpec(type); Industry ind; ind.index = INVALID_INDUSTRY; ind.location.tile = tile; ind.location.w = 0; // important to mark the industry invalid ind.type = type; ind.selected_layout = layout; ind.town = ClosestTownFromTile(tile, UINT_MAX); ind.random = initial_random_bits; ind.founder = founder; ind.psa = NULL; IndustriesResolverObject object(tile, &ind, type, seed, CBID_INDUSTRY_LOCATION, 0, creation_type); uint16 result = object.ResolveCallback(); /* Unlike the "normal" cases, not having a valid result means we allow * the building of the industry, as that's how it's done in TTDP. */ if (result == CALLBACK_FAILED) return CommandCost(); return GetErrorMessageFromLocationCallbackResult(result, indspec->grf_prop.grffile, STR_ERROR_SITE_UNSUITABLE); } /** * Check with callback #CBID_INDUSTRY_PROBABILITY whether the industry can be built. * @param type Industry type to check. * @param creation_type Reason to construct a new industry. * @return If the industry has no callback or allows building, \c true is returned. Otherwise, \c false is returned. */ uint32 GetIndustryProbabilityCallback(IndustryType type, IndustryAvailabilityCallType creation_type, uint32 default_prob) { const IndustrySpec *indspec = GetIndustrySpec(type); if (HasBit(indspec->callback_mask, CBM_IND_PROBABILITY)) { uint16 res = GetIndustryCallback(CBID_INDUSTRY_PROBABILITY, 0, creation_type, NULL, type, INVALID_TILE); if (res != CALLBACK_FAILED) { if (indspec->grf_prop.grffile->grf_version < 8) { /* Disallow if result != 0 */ if (res != 0) default_prob = 0; } else { /* Use returned probability. 0x100 to use default */ if (res < 0x100) { default_prob = res; } else if (res > 0x100) { ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_PROBABILITY, res); } } } } return default_prob; } static int32 DerefIndProd(int field, bool use_register) { return use_register ? (int32)GetRegister(field) : field; } /** * Get the industry production callback and apply it to the industry. * @param ind the industry this callback has to be called for * @param reason the reason it is called (0 = incoming cargo, 1 = periodic tick callback) */ void IndustryProductionCallback(Industry *ind, int reason) { const IndustrySpec *spec = GetIndustrySpec(ind->type); IndustriesResolverObject object(ind->location.tile, ind, ind->type); if ((spec->behaviour & INDUSTRYBEH_PRODCALLBACK_RANDOM) != 0) object.callback_param1 = Random(); int multiplier = 1; if ((spec->behaviour & INDUSTRYBEH_PROD_MULTI_HNDLING) != 0) multiplier = ind->prod_level; object.callback_param2 = reason; for (uint loop = 0;; loop++) { /* limit the number of calls to break infinite loops. * 'loop' is provided as 16 bits to the newgrf, so abort when those are exceeded. */ if (loop >= 0x10000) { /* display error message */ SetDParamStr(0, spec->grf_prop.grffile->filename); SetDParam(1, spec->name); ShowErrorMessage(STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK, WL_WARNING); /* abort the function early, this error isn't critical and will allow the game to continue to run */ break; } SB(object.callback_param2, 8, 16, loop); const SpriteGroup *tgroup = object.Resolve(); if (tgroup == NULL || tgroup->type != SGT_INDUSTRY_PRODUCTION) break; const IndustryProductionSpriteGroup *group = (const IndustryProductionSpriteGroup *)tgroup; bool deref = (group->version == 1); for (uint i = 0; i < 3; i++) { ind->incoming_cargo_waiting[i] = Clamp(ind->incoming_cargo_waiting[i] - DerefIndProd(group->subtract_input[i], deref) * multiplier, 0, 0xFFFF); } for (uint i = 0; i < 2; i++) { ind->produced_cargo_waiting[i] = Clamp(ind->produced_cargo_waiting[i] + max(DerefIndProd(group->add_output[i], deref), 0) * multiplier, 0, 0xFFFF); } int32 again = DerefIndProd(group->again, deref); if (again == 0) break; SB(object.callback_param2, 24, 8, again); } SetWindowDirty(WC_INDUSTRY_VIEW, ind->index); } /** * Check whether an industry temporarily refuses to accept a certain cargo. * @param ind The industry to query. * @param cargo_type The cargo to get information about. * @pre cargo_type is in ind->accepts_cargo. * @return Whether the given industry refuses to accept this cargo type. */ bool IndustryTemporarilyRefusesCargo(Industry *ind, CargoID cargo_type) { assert(cargo_type == ind->accepts_cargo[0] || cargo_type == ind->accepts_cargo[1] || cargo_type == ind->accepts_cargo[2]); const IndustrySpec *indspec = GetIndustrySpec(ind->type); if (HasBit(indspec->callback_mask, CBM_IND_REFUSE_CARGO)) { uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO, 0, indspec->grf_prop.grffile->cargo_map[cargo_type], ind, ind->type, ind->location.tile); if (res != CALLBACK_FAILED) return !ConvertBooleanCallback(indspec->grf_prop.grffile, CBID_INDUSTRY_REFUSE_CARGO, res); } return false; } openttd-1.5.3/src/animated_tile.cpp0000644000000000000000000000700612627373435016004 0ustar rootroot/* $Id: animated_tile.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 animated_tile.cpp Everything related to animated tiles. */ #include "stdafx.h" #include "core/alloc_func.hpp" #include "tile_cmd.h" #include "viewport_func.h" #include "safeguards.h" /** The table/list with animated tiles. */ TileIndex *_animated_tile_list = NULL; /** The number of animated tiles in the current state. */ uint _animated_tile_count = 0; /** The number of slots for animated tiles allocated currently. */ uint _animated_tile_allocated = 0; /** * Removes the given tile from the animated tile table. * @param tile the tile to remove */ void DeleteAnimatedTile(TileIndex tile) { for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { if (tile == *ti) { /* Remove the hole * The order of the remaining elements must stay the same, otherwise the animation loop * may miss a tile; that's why we must use memmove instead of just moving the last element. */ memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti)); _animated_tile_count--; MarkTileDirtyByTile(tile); return; } } } /** * Add the given tile to the animated tile table (if it does not exist * on that table yet). Also increases the size of the table if necessary. * @param tile the tile to make animated */ void AddAnimatedTile(TileIndex tile) { MarkTileDirtyByTile(tile); for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { if (tile == *ti) return; } /* Table not large enough, so make it larger */ if (_animated_tile_count == _animated_tile_allocated) { _animated_tile_allocated *= 2; _animated_tile_list = ReallocT(_animated_tile_list, _animated_tile_allocated); } _animated_tile_list[_animated_tile_count] = tile; _animated_tile_count++; } /** * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them. */ void AnimateAnimatedTiles() { const TileIndex *ti = _animated_tile_list; while (ti < _animated_tile_list + _animated_tile_count) { const TileIndex curr = *ti; AnimateTile(curr); /* During the AnimateTile call, DeleteAnimatedTile could have been called, * deleting an element we've already processed and pushing the rest one * slot to the left. We can detect this by checking whether the index * in the current slot has changed - if it has, an element has been deleted, * and we should process the current slot again instead of going forward. * NOTE: this will still break if more than one animated tile is being * deleted during the same AnimateTile call, but no code seems to * be doing this anyway. */ if (*ti == curr) ++ti; } } /** * Initialize all animated tile variables to some known begin point */ void InitializeAnimatedTiles() { _animated_tile_list = ReallocT(_animated_tile_list, 256); _animated_tile_count = 0; _animated_tile_allocated = 256; } openttd-1.5.3/src/economy.cpp0000644000000000000000000022223112627373433014653 0ustar rootroot/* $Id: economy.cpp 27348 2015-07-30 18:45:29Z frosch $ */ /* * 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 economy.cpp Handling of the economy. */ #include "stdafx.h" #include "company_func.h" #include "command_func.h" #include "industry.h" #include "town.h" #include "news_func.h" #include "network/network.h" #include "network/network_func.h" #include "ai/ai.hpp" #include "aircraft.h" #include "train.h" #include "newgrf_engine.h" #include "engine_base.h" #include "ground_vehicle.hpp" #include "newgrf_cargo.h" #include "newgrf_sound.h" #include "newgrf_industrytiles.h" #include "newgrf_station.h" #include "newgrf_airporttiles.h" #include "object.h" #include "strings_func.h" #include "date_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "autoreplace_func.h" #include "company_gui.h" #include "signs_base.h" #include "subsidy_base.h" #include "subsidy_func.h" #include "station_base.h" #include "waypoint_base.h" #include "economy_base.h" #include "core/pool_func.hpp" #include "core/backup_type.hpp" #include "cargo_type.h" #include "water.h" #include "game/game.hpp" #include "cargomonitor.h" #include "goal_base.h" #include "story_base.h" #include "linkgraph/refresh.h" #include "table/strings.h" #include "table/pricebase.h" #include "safeguards.h" /* Initialize the cargo payment-pool */ CargoPaymentPool _cargo_payment_pool("CargoPayment"); INSTANTIATE_POOL_METHODS(CargoPayment) /** * Multiply two integer values and shift the results to right. * * This function multiplies two integer values. The result is * shifted by the amount of shift to right. * * @param a The first integer * @param b The second integer * @param shift The amount to shift the value to right. * @return The shifted result */ static inline int32 BigMulS(const int32 a, const int32 b, const uint8 shift) { return (int32)((int64)a * (int64)b >> shift); } typedef SmallVector SmallIndustryList; /** * Score info, values used for computing the detailed performance rating. */ const ScoreInfo _score_info[] = { { 120, 100}, // SCORE_VEHICLES { 80, 100}, // SCORE_STATIONS { 10000, 100}, // SCORE_MIN_PROFIT { 50000, 50}, // SCORE_MIN_INCOME { 100000, 100}, // SCORE_MAX_INCOME { 40000, 400}, // SCORE_DELIVERED { 8, 50}, // SCORE_CARGO {10000000, 50}, // SCORE_MONEY { 250000, 50}, // SCORE_LOAN { 0, 0} // SCORE_TOTAL }; int _score_part[MAX_COMPANIES][SCORE_END]; Economy _economy; Prices _price; Money _additional_cash_required; static PriceMultipliers _price_base_multiplier; /** * Calculate the value of the company. That is the value of all * assets (vehicles, stations, etc) and money minus the loan, * except when including_loan is \c false which is useful when * we want to calculate the value for bankruptcy. * @param c the company to get the value of. * @param including_loan include the loan in the company value. * @return the value of the company. */ Money CalculateCompanyValue(const Company *c, bool including_loan) { Owner owner = c->index; Station *st; uint num = 0; FOR_ALL_STATIONS(st) { if (st->owner == owner) num += CountBits((byte)st->facilities); } Money value = num * _price[PR_STATION_VALUE] * 25; Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner != owner) continue; if (v->type == VEH_TRAIN || v->type == VEH_ROAD || (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft()) || v->type == VEH_SHIP) { value += v->value * 3 >> 1; } } /* Add real money value */ if (including_loan) value -= c->current_loan; value += c->money; return max(value, (Money)1); } /** * if update is set to true, the economy is updated with this score * (also the house is updated, should only be true in the on-tick event) * @param update the economy with calculated score * @param c company been evaluated * @return actual score of this company * */ int UpdateCompanyRatingAndValue(Company *c, bool update) { Owner owner = c->index; int score = 0; memset(_score_part[owner], 0, sizeof(_score_part[owner])); /* Count vehicles */ { Vehicle *v; Money min_profit = 0; bool min_profit_first = true; uint num = 0; FOR_ALL_VEHICLES(v) { if (v->owner != owner) continue; if (IsCompanyBuildableVehicleType(v->type) && v->IsPrimaryVehicle()) { if (v->profit_last_year > 0) num++; // For the vehicle score only count profitable vehicles if (v->age > 730) { /* Find the vehicle with the lowest amount of profit */ if (min_profit_first || min_profit > v->profit_last_year) { min_profit = v->profit_last_year; min_profit_first = false; } } } } min_profit >>= 8; // remove the fract part _score_part[owner][SCORE_VEHICLES] = num; /* Don't allow negative min_profit to show */ if (min_profit > 0) { _score_part[owner][SCORE_MIN_PROFIT] = ClampToI32(min_profit); } } /* Count stations */ { uint num = 0; const Station *st; FOR_ALL_STATIONS(st) { /* Only count stations that are actually serviced */ if (st->owner == owner && (st->time_since_load <= 20 || st->time_since_unload <= 20)) num += CountBits((byte)st->facilities); } _score_part[owner][SCORE_STATIONS] = num; } /* Generate statistics depending on recent income statistics */ { int numec = min(c->num_valid_stat_ent, 12); if (numec != 0) { const CompanyEconomyEntry *cee = c->old_economy; Money min_income = cee->income + cee->expenses; Money max_income = cee->income + cee->expenses; do { min_income = min(min_income, cee->income + cee->expenses); max_income = max(max_income, cee->income + cee->expenses); } while (++cee, --numec); if (min_income > 0) { _score_part[owner][SCORE_MIN_INCOME] = ClampToI32(min_income); } _score_part[owner][SCORE_MAX_INCOME] = ClampToI32(max_income); } } /* Generate score depending on amount of transported cargo */ { int numec = min(c->num_valid_stat_ent, 4); if (numec != 0) { const CompanyEconomyEntry *cee = c->old_economy; OverflowSafeInt64 total_delivered = 0; do { total_delivered += cee->delivered_cargo.GetSum(); } while (++cee, --numec); _score_part[owner][SCORE_DELIVERED] = ClampToI32(total_delivered); } } /* Generate score for variety of cargo */ { _score_part[owner][SCORE_CARGO] = c->old_economy->delivered_cargo.GetCount(); } /* Generate score for company's money */ { if (c->money > 0) { _score_part[owner][SCORE_MONEY] = ClampToI32(c->money); } } /* Generate score for loan */ { _score_part[owner][SCORE_LOAN] = ClampToI32(_score_info[SCORE_LOAN].needed - c->current_loan); } /* Now we calculate the score for each item.. */ { int total_score = 0; int s; score = 0; for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) { /* Skip the total */ if (i == SCORE_TOTAL) continue; /* Check the score */ s = Clamp(_score_part[owner][i], 0, _score_info[i].needed) * _score_info[i].score / _score_info[i].needed; score += s; total_score += _score_info[i].score; } _score_part[owner][SCORE_TOTAL] = score; /* We always want the score scaled to SCORE_MAX (1000) */ if (total_score != SCORE_MAX) score = score * SCORE_MAX / total_score; } if (update) { c->old_economy[0].performance_history = score; UpdateCompanyHQ(c->location_of_HQ, score); c->old_economy[0].company_value = CalculateCompanyValue(c); } SetWindowDirty(WC_PERFORMANCE_DETAIL, 0); return score; } /** * Change the ownership of all the items of a company. * @param old_owner The company that gets removed. * @param new_owner The company to merge to, or INVALID_OWNER to remove the company. */ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) { /* We need to set _current_company to old_owner before we try to move * the client. This is needed as it needs to know whether "you" really * are the current local company. */ Backup cur_company(_current_company, old_owner, FILE_LINE); #ifdef ENABLE_NETWORK /* In all cases, make spectators of clients connected to that company */ if (_networking) NetworkClientsToSpectators(old_owner); #endif /* ENABLE_NETWORK */ if (old_owner == _local_company) { /* Single player cheated to AI company. * There are no spectators in single player, so we must pick some other company. */ assert(!_networking); Backup cur_company2(_current_company, FILE_LINE); Company *c; FOR_ALL_COMPANIES(c) { if (c->index != old_owner) { SetLocalCompany(c->index); break; } } cur_company2.Restore(); assert(old_owner != _local_company); } Town *t; assert(old_owner != new_owner); { Company *c; uint i; /* See if the old_owner had shares in other companies */ FOR_ALL_COMPANIES(c) { for (i = 0; i < 4; i++) { if (c->share_owners[i] == old_owner) { /* Sell his shares */ CommandCost res = DoCommand(0, c->index, 0, DC_EXEC | DC_BANKRUPT, CMD_SELL_SHARE_IN_COMPANY); /* Because we are in a DoCommand, we can't just execute another one and * expect the money to be removed. We need to do it ourself! */ SubtractMoneyFromCompany(res); } } } /* Sell all the shares that people have on this company */ Backup cur_company2(_current_company, FILE_LINE); c = Company::Get(old_owner); for (i = 0; i < 4; i++) { cur_company2.Change(c->share_owners[i]); if (_current_company != INVALID_OWNER) { /* Sell the shares */ CommandCost res = DoCommand(0, old_owner, 0, DC_EXEC | DC_BANKRUPT, CMD_SELL_SHARE_IN_COMPANY); /* Because we are in a DoCommand, we can't just execute another one and * expect the money to be removed. We need to do it ourself! */ SubtractMoneyFromCompany(res); } } cur_company2.Restore(); } /* Temporarily increase the company's money, to be sure that * removing his/her property doesn't fail because of lack of money. * Not too drastically though, because it could overflow */ if (new_owner == INVALID_OWNER) { Company::Get(old_owner)->money = UINT64_MAX >> 2; // jackpot ;p } Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (s->awarded == old_owner) { if (new_owner == INVALID_OWNER) { delete s; } else { s->awarded = new_owner; } } } if (new_owner == INVALID_OWNER) RebuildSubsidisedSourceAndDestinationCache(); /* Take care of rating and transport rights in towns */ FOR_ALL_TOWNS(t) { /* If a company takes over, give the ratings to that company. */ if (new_owner != INVALID_OWNER) { if (HasBit(t->have_ratings, old_owner)) { if (HasBit(t->have_ratings, new_owner)) { /* use max of the two ratings. */ t->ratings[new_owner] = max(t->ratings[new_owner], t->ratings[old_owner]); } else { SetBit(t->have_ratings, new_owner); t->ratings[new_owner] = t->ratings[old_owner]; } } } /* Reset the ratings for the old owner */ t->ratings[old_owner] = RATING_INITIAL; ClrBit(t->have_ratings, old_owner); /* Transfer exclusive rights */ if (t->exclusive_counter > 0 && t->exclusivity == old_owner) { if (new_owner != INVALID_OWNER) { t->exclusivity = new_owner; } else { t->exclusive_counter = 0; t->exclusivity = INVALID_COMPANY; } } } { Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == old_owner && IsCompanyBuildableVehicleType(v->type)) { if (new_owner == INVALID_OWNER) { if (v->Previous() == NULL) delete v; } else { if (v->IsEngineCountable()) GroupStatistics::CountEngine(v, -1); if (v->IsPrimaryVehicle()) GroupStatistics::CountVehicle(v, -1); } } } } /* In all cases clear replace engine rules. * Even if it was copied, it could interfere with new owner's rules */ RemoveAllEngineReplacementForCompany(Company::Get(old_owner)); if (new_owner == INVALID_OWNER) { RemoveAllGroupsForCompany(old_owner); } else { Group *g; FOR_ALL_GROUPS(g) { if (g->owner == old_owner) g->owner = new_owner; } } { FreeUnitIDGenerator unitidgen[] = { FreeUnitIDGenerator(VEH_TRAIN, new_owner), FreeUnitIDGenerator(VEH_ROAD, new_owner), FreeUnitIDGenerator(VEH_SHIP, new_owner), FreeUnitIDGenerator(VEH_AIRCRAFT, new_owner) }; /* Override company settings to new company defaults in case we need to convert them. * This is required as the CmdChangeServiceInt doesn't copy the supplied value when it is non-custom */ if (new_owner != INVALID_OWNER) { Company *old_company = Company::Get(old_owner); Company *new_company = Company::Get(new_owner); old_company->settings.vehicle.servint_aircraft = new_company->settings.vehicle.servint_aircraft; old_company->settings.vehicle.servint_trains = new_company->settings.vehicle.servint_trains; old_company->settings.vehicle.servint_roadveh = new_company->settings.vehicle.servint_roadveh; old_company->settings.vehicle.servint_ships = new_company->settings.vehicle.servint_ships; old_company->settings.vehicle.servint_ispercent = new_company->settings.vehicle.servint_ispercent; } Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == old_owner && IsCompanyBuildableVehicleType(v->type)) { assert(new_owner != INVALID_OWNER); /* Correct default values of interval settings while maintaining custom set ones. * This prevents invalid values on mismatching company defaults being accepted. */ if (!v->ServiceIntervalIsCustom()) { Company *new_company = Company::Get(new_owner); /* Technically, passing the interval is not needed as the command will query the default value itself. * However, do not rely on that behaviour. */ int interval = CompanyServiceInterval(new_company, v->type); DoCommand(v->tile, v->index, interval | (new_company->settings.vehicle.servint_ispercent << 17), DC_EXEC | DC_BANKRUPT, CMD_CHANGE_SERVICE_INT); } v->owner = new_owner; /* Owner changes, clear cache */ v->colourmap = PAL_NONE; v->InvalidateNewGRFCache(); if (v->IsEngineCountable()) { GroupStatistics::CountEngine(v, 1); } if (v->IsPrimaryVehicle()) { GroupStatistics::CountVehicle(v, 1); v->unitnumber = unitidgen[v->type].NextID(); } /* Invalidate the vehicle's cargo payment "owner cache". */ if (v->cargo_payment != NULL) v->cargo_payment->owner = NULL; } } if (new_owner != INVALID_OWNER) GroupStatistics::UpdateAutoreplace(new_owner); } /* Change ownership of tiles */ { TileIndex tile = 0; do { ChangeTileOwner(tile, old_owner, new_owner); } while (++tile != MapSize()); if (new_owner != INVALID_OWNER) { /* Update all signals because there can be new segment that was owned by two companies * and signals were not propagated * Similar with crossings - it is needed to bar crossings that weren't before * because of different owner of crossing and approaching train */ tile = 0; do { if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, new_owner) && HasSignals(tile)) { TrackBits tracks = GetTrackBits(tile); do { // there may be two tracks with signals for TRACK_BIT_HORZ and TRACK_BIT_VERT Track track = RemoveFirstTrack(&tracks); if (HasSignalOnTrack(tile, track)) AddTrackToSignalBuffer(tile, track, new_owner); } while (tracks != TRACK_BIT_NONE); } else if (IsLevelCrossingTile(tile) && IsTileOwner(tile, new_owner)) { UpdateLevelCrossing(tile); } } while (++tile != MapSize()); } /* update signals in buffer */ UpdateSignalsInBuffer(); } /* Add airport infrastructure count of the old company to the new one. */ if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.airport += Company::Get(old_owner)->infrastructure.airport; /* convert owner of stations (including deleted ones, but excluding buoys) */ Station *st; FOR_ALL_STATIONS(st) { if (st->owner == old_owner) { /* if a company goes bankrupt, set owner to OWNER_NONE so the sign doesn't disappear immediately * also, drawing station window would cause reading invalid company's colour */ st->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner; } } /* do the same for waypoints (we need to do this here so deleted waypoints are converted too) */ Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { if (wp->owner == old_owner) { wp->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner; } } Sign *si; FOR_ALL_SIGNS(si) { if (si->owner == old_owner) si->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner; } /* Remove Game Script created Goals, CargoMonitors and Story pages. */ Goal *g; FOR_ALL_GOALS(g) { if (g->company == old_owner) delete g; } ClearCargoPickupMonitoring(old_owner); ClearCargoDeliveryMonitoring(old_owner); StoryPage *sp; FOR_ALL_STORY_PAGES(sp) { if (sp->company == old_owner) delete sp; } /* Change colour of existing windows */ if (new_owner != INVALID_OWNER) ChangeWindowOwner(old_owner, new_owner); cur_company.Restore(); MarkWholeScreenDirty(); } /** * Check for bankruptcy of a company. Called every three months. * @param c Company to check. */ static void CompanyCheckBankrupt(Company *c) { /* If the company has money again, it does not go bankrupt */ if (c->money - c->current_loan >= -_economy.max_loan) { c->months_of_bankruptcy = 0; c->bankrupt_asked = 0; return; } c->months_of_bankruptcy++; switch (c->months_of_bankruptcy) { /* All the boring cases (months) with a bad balance where no action is taken */ case 0: case 1: case 2: case 3: case 5: case 6: case 8: case 9: break; /* Warn about bankruptcy after 3 months */ case 4: { CompanyNewsInformation *cni = MallocT(1); cni->FillData(c); SetDParam(0, STR_NEWS_COMPANY_IN_TROUBLE_TITLE); SetDParam(1, STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION); SetDParamStr(2, cni->company_name); AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, cni); AI::BroadcastNewEvent(new ScriptEventCompanyInTrouble(c->index)); Game::NewEvent(new ScriptEventCompanyInTrouble(c->index)); break; } /* Offer company for sale after 6 months */ case 7: { /* Don't consider the loan */ Money val = CalculateCompanyValue(c, false); c->bankrupt_value = val; c->bankrupt_asked = 1 << c->index; // Don't ask the owner c->bankrupt_timeout = 0; /* The company assets should always have some value */ assert(c->bankrupt_value > 0); break; } /* Bankrupt company after 6 months (if the company has no value) or latest * after 9 months (if it still had value after 6 months) */ default: case 10: { if (!_networking && _local_company == c->index) { /* If we are in offline mode, leave the company playing. Eg. there * is no THE-END, otherwise mark the client as spectator to make sure * he/she is no long in control of this company. However... when you * join another company (cheat) the "unowned" company can bankrupt. */ c->bankrupt_asked = MAX_UVALUE(CompanyMask); break; } /* Actually remove the company, but not when we're a network client. * In case of network clients we will be getting a command from the * server. It is done in this way as we are called from the * StateGameLoop which can't change the current company, and thus * updating the local company triggers an assert later on. In the * case of a network game the command will be processed at a time * that changing the current company is okay. In case of single * player we are sure (the above check) that we are not the local * company and thus we won't be moved. */ if (!_networking || _network_server) DoCommandP(0, 2 | (c->index << 16), CRR_BANKRUPT, CMD_COMPANY_CTRL); break; } } } /** * Update the finances of all companies. * Pay for the stations, update the history graph, update ratings and company values, and deal with bankruptcy. */ static void CompaniesGenStatistics() { Station *st; Backup cur_company(_current_company, FILE_LINE); Company *c; if (!_settings_game.economy.infrastructure_maintenance) { FOR_ALL_STATIONS(st) { cur_company.Change(st->owner); CommandCost cost(EXPENSES_PROPERTY, _price[PR_STATION_VALUE] >> 1); SubtractMoneyFromCompany(cost); } } else { /* Improved monthly infrastructure costs. */ FOR_ALL_COMPANIES(c) { cur_company.Change(c->index); CommandCost cost(EXPENSES_PROPERTY); uint32 rail_total = c->infrastructure.GetRailTotal(); for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { if (c->infrastructure.rail[rt] != 0) cost.AddCost(RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); } cost.AddCost(SignalMaintenanceCost(c->infrastructure.signal)); for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { if (c->infrastructure.road[rt] != 0) cost.AddCost(RoadMaintenanceCost(rt, c->infrastructure.road[rt])); } cost.AddCost(CanalMaintenanceCost(c->infrastructure.water)); cost.AddCost(StationMaintenanceCost(c->infrastructure.station)); cost.AddCost(AirportMaintenanceCost(c->index)); SubtractMoneyFromCompany(cost); } } cur_company.Restore(); /* Check for bankruptcy each month */ FOR_ALL_COMPANIES(c) { CompanyCheckBankrupt(c); } /* Only run the economic statics and update company stats every 3rd month (1st of quarter). */ if (!HasBit(1 << 0 | 1 << 3 | 1 << 6 | 1 << 9, _cur_month)) return; FOR_ALL_COMPANIES(c) { memmove(&c->old_economy[1], &c->old_economy[0], sizeof(c->old_economy) - sizeof(c->old_economy[0])); c->old_economy[0] = c->cur_economy; memset(&c->cur_economy, 0, sizeof(c->cur_economy)); if (c->num_valid_stat_ent != MAX_HISTORY_QUARTERS) c->num_valid_stat_ent++; UpdateCompanyRatingAndValue(c, true); if (c->block_preview != 0) c->block_preview--; } SetWindowDirty(WC_INCOME_GRAPH, 0); SetWindowDirty(WC_OPERATING_PROFIT, 0); SetWindowDirty(WC_DELIVERED_CARGO, 0); SetWindowDirty(WC_PERFORMANCE_HISTORY, 0); SetWindowDirty(WC_COMPANY_VALUE, 0); SetWindowDirty(WC_COMPANY_LEAGUE, 0); } /** * Add monthly inflation * @param check_year Shall the inflation get stopped after 170 years? * @return true if inflation is maxed and nothing was changed */ bool AddInflation(bool check_year) { /* The cargo payment inflation differs from the normal inflation, so the * relative amount of money you make with a transport decreases slowly over * the 170 years. After a few hundred years we reach a level in which the * games will become unplayable as the maximum income will be less than * the minimum running cost. * * Furthermore there are a lot of inflation related overflows all over the * place. Solving them is hardly possible because inflation will always * reach the overflow threshold some day. So we'll just perform the * inflation mechanism during the first 170 years (the amount of years that * one had in the original TTD) and stop doing the inflation after that * because it only causes problems that can't be solved nicely and the * inflation doesn't add anything after that either; it even makes playing * it impossible due to the diverging cost and income rates. */ if (check_year && (_cur_year - _settings_game.game_creation.starting_year) >= (ORIGINAL_MAX_YEAR - ORIGINAL_BASE_YEAR)) return true; if (_economy.inflation_prices == MAX_INFLATION || _economy.inflation_payment == MAX_INFLATION) return true; /* Approximation for (100 + infl_amount)% ** (1 / 12) - 100% * scaled by 65536 * 12 -> months per year * This is only a good approximation for small values */ _economy.inflation_prices += (_economy.inflation_prices * _economy.infl_amount * 54) >> 16; _economy.inflation_payment += (_economy.inflation_payment * _economy.infl_amount_pr * 54) >> 16; if (_economy.inflation_prices > MAX_INFLATION) _economy.inflation_prices = MAX_INFLATION; if (_economy.inflation_payment > MAX_INFLATION) _economy.inflation_payment = MAX_INFLATION; return false; } /** * Computes all prices, payments and maximum loan. */ void RecomputePrices() { /* Setup maximum loan */ _economy.max_loan = (_settings_game.difficulty.max_loan * _economy.inflation_prices >> 16) / 50000 * 50000; /* Setup price bases */ for (Price i = PR_BEGIN; i < PR_END; i++) { Money price = _price_base_specs[i].start_price; /* Apply difficulty settings */ uint mod = 1; switch (_price_base_specs[i].category) { case PCAT_RUNNING: mod = _settings_game.difficulty.vehicle_costs; break; case PCAT_CONSTRUCTION: mod = _settings_game.difficulty.construction_cost; break; default: break; } switch (mod) { case 0: price *= 6; break; case 1: price *= 8; break; // normalised to 1 below case 2: price *= 9; break; default: NOT_REACHED(); } /* Apply inflation */ price = (int64)price * _economy.inflation_prices; /* Apply newgrf modifiers, remove fractional part of inflation, and normalise on medium difficulty. */ int shift = _price_base_multiplier[i] - 16 - 3; if (shift >= 0) { price <<= shift; } else { price >>= -shift; } /* Make sure the price does not get reduced to zero. * Zero breaks quite a few commands that use a zero * cost to see whether something got changed or not * and based on that cause an error. When the price * is zero that fails even when things are done. */ if (price == 0) { price = Clamp(_price_base_specs[i].start_price, -1, 1); /* No base price should be zero, but be sure. */ assert(price != 0); } /* Store value */ _price[i] = price; } /* Setup cargo payment */ CargoSpec *cs; FOR_ALL_CARGOSPECS(cs) { cs->current_payment = ((int64)cs->initial_payment * _economy.inflation_payment) >> 16; } SetWindowClassesDirty(WC_BUILD_VEHICLE); SetWindowClassesDirty(WC_REPLACE_VEHICLE); SetWindowClassesDirty(WC_VEHICLE_DETAILS); SetWindowClassesDirty(WC_COMPANY_INFRASTRUCTURE); InvalidateWindowData(WC_PAYMENT_RATES, 0); } /** Let all companies pay the monthly interest on their loan. */ static void CompaniesPayInterest() { const Company *c; Backup cur_company(_current_company, FILE_LINE); FOR_ALL_COMPANIES(c) { cur_company.Change(c->index); /* Over a year the paid interest should be "loan * interest percentage", * but... as that number is likely not dividable by 12 (pay each month), * one needs to account for that in the monthly fee calculations. * To easily calculate what one should pay "this" month, you calculate * what (total) should have been paid up to this month and you subtract * whatever has been paid in the previous months. This will mean one month * it'll be a bit more and the other it'll be a bit less than the average * monthly fee, but on average it will be exact. * In order to prevent cheating or abuse (just not paying interest by not * taking a loan we make companies pay interest on negative cash as well */ Money yearly_fee = c->current_loan * _economy.interest_rate / 100; if (c->money < 0) { yearly_fee += -c->money *_economy.interest_rate / 100; } Money up_to_previous_month = yearly_fee * _cur_month / 12; Money up_to_this_month = yearly_fee * (_cur_month + 1) / 12; SubtractMoneyFromCompany(CommandCost(EXPENSES_LOAN_INT, up_to_this_month - up_to_previous_month)); SubtractMoneyFromCompany(CommandCost(EXPENSES_OTHER, _price[PR_STATION_VALUE] >> 2)); } cur_company.Restore(); } static void HandleEconomyFluctuations() { if (_settings_game.difficulty.economy != 0) { /* When economy is Fluctuating, decrease counter */ _economy.fluct--; } else if (EconomyIsInRecession()) { /* When it's Steady and we are in recession, end it now */ _economy.fluct = -12; } else { /* No need to do anything else in other cases */ return; } if (_economy.fluct == 0) { _economy.fluct = -(int)GB(Random(), 0, 2); AddNewsItem(STR_NEWS_BEGIN_OF_RECESSION, NT_ECONOMY, NF_NORMAL); } else if (_economy.fluct == -12) { _economy.fluct = GB(Random(), 0, 8) + 312; AddNewsItem(STR_NEWS_END_OF_RECESSION, NT_ECONOMY, NF_NORMAL); } } /** * Reset changes to the price base multipliers. */ void ResetPriceBaseMultipliers() { memset(_price_base_multiplier, 0, sizeof(_price_base_multiplier)); } /** * Change a price base by the given factor. * The price base is altered by factors of two. * NewBaseCost = OldBaseCost * 2^n * @param price Index of price base to change. * @param factor Amount to change by. */ void SetPriceBaseMultiplier(Price price, int factor) { assert(price < PR_END); _price_base_multiplier[price] = Clamp(factor, MIN_PRICE_MODIFIER, MAX_PRICE_MODIFIER); } /** * Initialize the variables that will maintain the daily industry change system. * @param init_counter specifies if the counter is required to be initialized */ void StartupIndustryDailyChanges(bool init_counter) { uint map_size = MapLogX() + MapLogY(); /* After getting map size, it needs to be scaled appropriately and divided by 31, * which stands for the days in a month. * Using just 31 will make it so that a monthly reset (based on the real number of days of that month) * would not be needed. * Since it is based on "fractional parts", the leftover days will not make much of a difference * on the overall total number of changes performed */ _economy.industry_daily_increment = (1 << map_size) / 31; if (init_counter) { /* A new game or a savegame from an older version will require the counter to be initialized */ _economy.industry_daily_change_counter = 0; } } void StartupEconomy() { _economy.interest_rate = _settings_game.difficulty.initial_interest; _economy.infl_amount = _settings_game.difficulty.initial_interest; _economy.infl_amount_pr = max(0, _settings_game.difficulty.initial_interest - 1); _economy.fluct = GB(Random(), 0, 8) + 168; /* Set up prices */ RecomputePrices(); StartupIndustryDailyChanges(true); // As we are starting a new game, initialize the counter too } /** * Resets economy to initial values */ void InitializeEconomy() { _economy.inflation_prices = _economy.inflation_payment = 1 << 16; ClearCargoPickupMonitoring(); ClearCargoDeliveryMonitoring(); } /** * Determine a certain price * @param index Price base * @param cost_factor Price factor * @param grf_file NewGRF to use local price multipliers from. * @param shift Extra bit shifting after the computation * @return Price */ Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift) { if (index >= PR_END) return 0; Money cost = _price[index] * cost_factor; if (grf_file != NULL) shift += grf_file->price_base_multipliers[index]; if (shift >= 0) { cost <<= shift; } else { cost >>= -shift; } return cost; } Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type) { const CargoSpec *cs = CargoSpec::Get(cargo_type); if (!cs->IsValid()) { /* User changed newgrfs and some vehicle still carries some cargo which is no longer available. */ return 0; } /* Use callback to calculate cargo profit, if available */ if (HasBit(cs->callback_mask, CBM_CARGO_PROFIT_CALC)) { uint32 var18 = min(dist, 0xFFFF) | (min(num_pieces, 0xFF) << 16) | (transit_days << 24); uint16 callback = GetCargoCallback(CBID_CARGO_PROFIT_CALC, 0, var18, cs); if (callback != CALLBACK_FAILED) { int result = GB(callback, 0, 14); /* Simulate a 15 bit signed value */ if (HasBit(callback, 14)) result -= 0x4000; /* "The result should be a signed multiplier that gets multiplied * by the amount of cargo moved and the price factor, then gets * divided by 8192." */ return result * num_pieces * cs->current_payment / 8192; } } static const int MIN_TIME_FACTOR = 31; static const int MAX_TIME_FACTOR = 255; const int days1 = cs->transit_days[0]; const int days2 = cs->transit_days[1]; const int days_over_days1 = max( transit_days - days1, 0); const int days_over_days2 = max(days_over_days1 - days2, 0); /* * The time factor is calculated based on the time it took * (transit_days) compared two cargo-depending values. The * range is divided into three parts: * * - constant for fast transits * - linear decreasing with time with a slope of -1 for medium transports * - linear decreasing with time with a slope of -2 for slow transports * */ const int time_factor = max(MAX_TIME_FACTOR - days_over_days1 - days_over_days2, MIN_TIME_FACTOR); return BigMulS(dist * time_factor * num_pieces, cs->current_payment, 21); } /** The industries we've currently brought cargo to. */ static SmallIndustryList _cargo_delivery_destinations; /** * Transfer goods from station to industry. * All cargo is delivered to the nearest (Manhattan) industry to the station sign, which is inside the acceptance rectangle and actually accepts the cargo. * @param st The station that accepted the cargo * @param cargo_type Type of cargo delivered * @param num_pieces Amount of cargo delivered * @param source The source of the cargo * @return actually accepted pieces of cargo */ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint num_pieces, IndustryID source) { /* Find the nearest industrytile to the station sign inside the catchment area, whose industry accepts the cargo. * This fails in three cases: * 1) The station accepts the cargo because there are enough houses around it accepting the cargo. * 2) The industries in the catchment area temporarily reject the cargo, and the daily station loop has not yet updated station acceptance. * 3) The results of callbacks CBID_INDUSTRY_REFUSE_CARGO and CBID_INDTILE_CARGO_ACCEPTANCE are inconsistent. (documented behaviour) */ uint accepted = 0; for (uint i = 0; i < st->industries_near.Length() && num_pieces != 0; i++) { Industry *ind = st->industries_near[i]; if (ind->index == source) continue; uint cargo_index; for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) { if (cargo_type == ind->accepts_cargo[cargo_index]) break; } /* Check if matching cargo has been found */ if (cargo_index >= lengthof(ind->accepts_cargo)) continue; /* Check if industry temporarily refuses acceptance */ if (IndustryTemporarilyRefusesCargo(ind, cargo_type)) continue; /* Insert the industry into _cargo_delivery_destinations, if not yet contained */ _cargo_delivery_destinations.Include(ind); uint amount = min(num_pieces, 0xFFFFU - ind->incoming_cargo_waiting[cargo_index]); ind->incoming_cargo_waiting[cargo_index] += amount; num_pieces -= amount; accepted += amount; } return accepted; } /** * Delivers goods to industries/towns and calculates the payment * @param num_pieces amount of cargo delivered * @param cargo_type the type of cargo that is delivered * @param dest Station the cargo has been unloaded * @param source_tile The origin of the cargo for distance calculation * @param days_in_transit Travel time * @param company The company delivering the cargo * @param src_type Type of source of cargo (industry, town, headquarters) * @param src Index of source of cargo * @return Revenue for delivering cargo * @note The cargo is just added to the stockpile of the industry. It is due to the caller to trigger the industry's production machinery */ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, TileIndex source_tile, byte days_in_transit, Company *company, SourceType src_type, SourceID src) { assert(num_pieces > 0); Station *st = Station::Get(dest); /* Give the goods to the industry. */ uint accepted = DeliverGoodsToIndustry(st, cargo_type, num_pieces, src_type == ST_INDUSTRY ? src : INVALID_INDUSTRY); /* If this cargo type is always accepted, accept all */ if (HasBit(st->always_accepted, cargo_type)) accepted = num_pieces; /* Update station statistics */ if (accepted > 0) { SetBit(st->goods[cargo_type].status, GoodsEntry::GES_EVER_ACCEPTED); SetBit(st->goods[cargo_type].status, GoodsEntry::GES_CURRENT_MONTH); SetBit(st->goods[cargo_type].status, GoodsEntry::GES_ACCEPTED_BIGTICK); } /* Update company statistics */ company->cur_economy.delivered_cargo[cargo_type] += accepted; /* Increase town's counter for town effects */ const CargoSpec *cs = CargoSpec::Get(cargo_type); st->town->received[cs->town_effect].new_act += accepted; /* Determine profit */ Money profit = GetTransportedGoodsIncome(accepted, DistanceManhattan(source_tile, st->xy), days_in_transit, cargo_type); /* Update the cargo monitor. */ AddCargoDelivery(cargo_type, company->index, accepted, src_type, src, st); /* Modify profit if a subsidy is in effect */ if (CheckSubsidised(cargo_type, company->index, src_type, src, st)) { switch (_settings_game.difficulty.subsidy_multiplier) { case 0: profit += profit >> 1; break; case 1: profit *= 2; break; case 2: profit *= 3; break; default: profit *= 4; break; } } return profit; } /** * Inform the industry about just delivered cargo * DeliverGoodsToIndustry() silently incremented incoming_cargo_waiting, now it is time to do something with the new cargo. * @param i The industry to process */ static void TriggerIndustryProduction(Industry *i) { const IndustrySpec *indspec = GetIndustrySpec(i->type); uint16 callback = indspec->callback_mask; i->was_cargo_delivered = true; i->last_cargo_accepted_at = _date; if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) { if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL)) { IndustryProductionCallback(i, 0); } else { SetWindowDirty(WC_INDUSTRY_VIEW, i->index); } } else { for (uint cargo_index = 0; cargo_index < lengthof(i->incoming_cargo_waiting); cargo_index++) { uint cargo_waiting = i->incoming_cargo_waiting[cargo_index]; if (cargo_waiting == 0) continue; i->produced_cargo_waiting[0] = min(i->produced_cargo_waiting[0] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][0] / 256), 0xFFFF); i->produced_cargo_waiting[1] = min(i->produced_cargo_waiting[1] + (cargo_waiting * indspec->input_cargo_multiplier[cargo_index][1] / 256), 0xFFFF); i->incoming_cargo_waiting[cargo_index] = 0; } } TriggerIndustry(i, INDUSTRY_TRIGGER_RECEIVED_CARGO); StartStopIndustryTileAnimation(i, IAT_INDUSTRY_RECEIVED_CARGO); } /** * Makes us a new cargo payment helper. * @param front The front of the train */ CargoPayment::CargoPayment(Vehicle *front) : front(front), current_station(front->last_station_visited) { } CargoPayment::~CargoPayment() { if (this->CleaningPool()) return; this->front->cargo_payment = NULL; if (this->visual_profit == 0 && this->visual_transfer == 0) return; Backup cur_company(_current_company, this->front->owner, FILE_LINE); SubtractMoneyFromCompany(CommandCost(this->front->GetExpenseType(true), -this->route_profit)); this->front->profit_this_year += (this->visual_profit + this->visual_transfer) << 8; if (this->route_profit != 0 && IsLocalCompany() && !PlayVehicleSound(this->front, VSE_LOAD_UNLOAD)) { SndPlayVehicleFx(SND_14_CASHTILL, this->front); } if (this->visual_transfer != 0) { ShowFeederIncomeAnimation(this->front->x_pos, this->front->y_pos, this->front->z_pos, this->visual_transfer, -this->visual_profit); } else if (this->visual_profit != 0) { ShowCostOrIncomeAnimation(this->front->x_pos, this->front->y_pos, this->front->z_pos, -this->visual_profit); } cur_company.Restore(); } /** * Handle payment for final delivery of the given cargo packet. * @param cp The cargo packet to pay for. * @param count The number of packets to pay for. */ void CargoPayment::PayFinalDelivery(const CargoPacket *cp, uint count) { if (this->owner == NULL) { this->owner = Company::Get(this->front->owner); } /* Handle end of route payment */ Money profit = DeliverGoods(count, this->ct, this->current_station, cp->SourceStationXY(), cp->DaysInTransit(), this->owner, cp->SourceSubsidyType(), cp->SourceSubsidyID()); this->route_profit += profit; /* The vehicle's profit is whatever route profit there is minus feeder shares. */ this->visual_profit += profit - cp->FeederShare(count); } /** * Handle payment for transfer of the given cargo packet. * @param cp The cargo packet to pay for; actual payment won't be made!. * @param count The number of packets to pay for. * @return The amount of money paid for the transfer. */ Money CargoPayment::PayTransfer(const CargoPacket *cp, uint count) { Money profit = GetTransportedGoodsIncome( count, /* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */ DistanceManhattan(cp->LoadedAtXY(), Station::Get(this->current_station)->xy), cp->DaysInTransit(), this->ct); profit = profit * _settings_game.economy.feeder_payment_share / 100; this->visual_transfer += profit; // accumulate transfer profits for whole vehicle return profit; // account for the (virtual) profit already made for the cargo packet } /** * Prepare the vehicle to be unloaded. * @param curr_station the station where the consist is at the moment * @param front_v the vehicle to be unloaded */ void PrepareUnload(Vehicle *front_v) { Station *curr_station = Station::Get(front_v->last_station_visited); curr_station->loading_vehicles.push_back(front_v); /* At this moment loading cannot be finished */ ClrBit(front_v->vehicle_flags, VF_LOADING_FINISHED); /* Start unloading at the first possible moment */ front_v->load_unload_ticks = 1; assert(front_v->cargo_payment == NULL); /* One CargoPayment per vehicle and the vehicle limit equals the * limit in number of CargoPayments. Can't go wrong. */ assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); assert(CargoPayment::CanAllocateItem()); front_v->cargo_payment = new CargoPayment(front_v); StationIDStack next_station = front_v->GetNextStoppingStation(); if (front_v->orders.list == NULL || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { Station *st = Station::Get(front_v->last_station_visited); for (Vehicle *v = front_v; v != NULL; v = v->Next()) { const GoodsEntry *ge = &st->goods[v->cargo_type]; if (v->cargo_cap > 0 && v->cargo.TotalCount() > 0) { v->cargo.Stage( HasBit(ge->status, GoodsEntry::GES_ACCEPTANCE), front_v->last_station_visited, next_station, front_v->current_order.GetUnloadType(), ge, front_v->cargo_payment); if (v->cargo.UnloadCount() > 0) SetBit(v->vehicle_flags, VF_CARGO_UNLOADING); } } } } /** * Gets the amount of cargo the given vehicle can load in the current tick. * This is only about loading speed. The free capacity is ignored. * @param v Vehicle to be queried. * @return Amount of cargo the vehicle can load at once. */ static uint GetLoadAmount(Vehicle *v) { const Engine *e = v->GetEngine(); uint load_amount = e->info.load_amount; /* The default loadamount for mail is 1/4 of the load amount for passengers */ bool air_mail = v->type == VEH_AIRCRAFT && !Aircraft::From(v)->IsNormalAircraft(); if (air_mail) load_amount = CeilDiv(load_amount, 4); if (_settings_game.order.gradual_loading) { uint16 cb_load_amount = CALLBACK_FAILED; if (e->GetGRF() != NULL && e->GetGRF()->grf_version >= 8) { /* Use callback 36 */ cb_load_amount = GetVehicleProperty(v, PROP_VEHICLE_LOAD_AMOUNT, CALLBACK_FAILED); } else if (HasBit(e->info.callback_mask, CBM_VEHICLE_LOAD_AMOUNT)) { /* Use callback 12 */ cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v); } if (cb_load_amount != CALLBACK_FAILED) { if (e->GetGRF()->grf_version < 8) cb_load_amount = GB(cb_load_amount, 0, 8); if (cb_load_amount >= 0x100) { ErrorUnknownCallbackResult(e->GetGRFID(), CBID_VEHICLE_LOAD_AMOUNT, cb_load_amount); } else if (cb_load_amount != 0) { load_amount = cb_load_amount; } } } /* Scale load amount the same as capacity */ if (HasBit(e->info.misc_flags, EF_NO_DEFAULT_CARGO_MULTIPLIER) && !air_mail) load_amount = CeilDiv(load_amount * CargoSpec::Get(v->cargo_type)->multiplier, 0x100); return load_amount; } /** * Iterate the articulated parts of a vehicle, also considering the special cases of "normal" * aircraft and double headed trains. Apply an action to each vehicle and immediately return false * if that action does so. Otherwise return true. * @tparam Taction Class of action to be applied. Must implement bool operator()([const] Vehicle *). * @param v First articulated part. * @param action Instance of Taction. * @return false if any of the action invocations returned false, true otherwise. */ template bool IterateVehicleParts(Vehicle *v, Taction action) { for (Vehicle *w = v; w != NULL; w = w->HasArticulatedPart() ? w->GetNextArticulatedPart() : NULL) { if (!action(w)) return false; if (w->type == VEH_TRAIN) { Train *train = Train::From(w); if (train->IsMultiheaded() && !action(train->other_multiheaded_part)) return false; } } if (v->type == VEH_AIRCRAFT && Aircraft::From(v)->IsNormalAircraft()) return action(v->Next()); return true; } /** * Action to check if a vehicle has no stored cargo. */ struct IsEmptyAction { /** * Checks if the vehicle has stored cargo. * @param v Vehicle to be checked. * @return true if v is either empty or has only reserved cargo, false otherwise. */ bool operator()(const Vehicle *v) { return v->cargo.StoredCount() == 0; } }; /** * Refit preparation action. */ struct PrepareRefitAction { CargoArray &consist_capleft; ///< Capacities left in the consist. uint32 &refit_mask; ///< Bitmask of possible refit cargoes. /** * Create a refit preparation action. * @param consist_capleft Capacities left in consist, to be updated here. * @param refit_mask Refit mask to be constructed from refit information of vehicles. */ PrepareRefitAction(CargoArray &consist_capleft, uint32 &refit_mask) : consist_capleft(consist_capleft), refit_mask(refit_mask) {} /** * Prepares for refitting of a vehicle, subtracting its free capacity from consist_capleft and * adding the cargoes it can refit to to the refit mask. * @param v The vehicle to be refitted. * @return true. */ bool operator()(const Vehicle *v) { this->consist_capleft[v->cargo_type] -= v->cargo_cap - v->cargo.ReservedCount(); this->refit_mask |= EngInfo(v->engine_type)->refit_mask; return true; } }; /** * Action for returning reserved cargo. */ struct ReturnCargoAction { Station *st; ///< Station to give the returned cargo to. StationID next_hop; ///< Next hop the cargo should be assigned to. /** * Construct a cargo return action. * @param st Station to give the returned cargo to. * @param next_one Next hop the cargo should be assigned to. */ ReturnCargoAction(Station *st, StationID next_one) : st(st), next_hop(next_one) {} /** * Return all reserved cargo from a vehicle. * @param v Vehicle to return cargo from. * @return true. */ bool operator()(Vehicle *v) { v->cargo.Return(UINT_MAX, &this->st->goods[v->cargo_type].cargo, this->next_hop); return true; } }; /** * Action for finalizing a refit. */ struct FinalizeRefitAction { CargoArray &consist_capleft; ///< Capacities left in the consist. Station *st; ///< Station to reserve cargo from. StationIDStack &next_station; ///< Next hops to reserve cargo for. bool do_reserve; ///< If the vehicle should reserve. /** * Create a finalizing action. * @param consist_capleft Capacities left in the consist. * @param st Station to reserve cargo from. * @param next_station Next hops to reserve cargo for. * @param do_reserve If we should reserve cargo or just add up the capacities. */ FinalizeRefitAction(CargoArray &consist_capleft, Station *st, StationIDStack &next_station, bool do_reserve) : consist_capleft(consist_capleft), st(st), next_station(next_station), do_reserve(do_reserve) {} /** * Reserve cargo from the station and update the remaining consist capacities with the * vehicle's remaining free capacity. * @param v Vehicle to be finalized. * @return true. */ bool operator()(Vehicle *v) { if (this->do_reserve) { this->st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), &v->cargo, st->xy, this->next_station); } this->consist_capleft[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount(); return true; } }; /** * Refit a vehicle in a station. * @param v Vehicle to be refitted. * @param consist_capleft Added cargo capacities in the consist. * @param st Station the vehicle is loading at. * @param next_station Possible next stations the vehicle can travel to. * @param new_cid Target cargo for refit. */ static void HandleStationRefit(Vehicle *v, CargoArray &consist_capleft, Station *st, StationIDStack next_station, CargoID new_cid) { Vehicle *v_start = v->GetFirstEnginePart(); if (!IterateVehicleParts(v_start, IsEmptyAction())) return; Backup cur_company(_current_company, v->owner, FILE_LINE); uint32 refit_mask = v->GetEngine()->info.refit_mask; /* Remove old capacity from consist capacity and collect refit mask. */ IterateVehicleParts(v_start, PrepareRefitAction(consist_capleft, refit_mask)); bool is_auto_refit = new_cid == CT_AUTO_REFIT; if (is_auto_refit) { /* Get a refittable cargo type with waiting cargo for next_station or INVALID_STATION. */ CargoID cid; new_cid = v_start->cargo_type; FOR_EACH_SET_CARGO_ID(cid, refit_mask) { if (st->goods[cid].cargo.HasCargoFor(next_station)) { /* Try to find out if auto-refitting would succeed. In case the refit is allowed, * the returned refit capacity will be greater than zero. */ DoCommand(v_start->tile, v_start->index, cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts. /* Try to balance different loadable cargoes between parts of the consist, so that * all of them can be loaded. Avoid a situation where all vehicles suddenly switch * to the first loadable cargo for which there is only one packet. If the capacities * are equal refit to the cargo of which most is available. This is important for * consists of only a single vehicle as those will generally have a consist_capleft * of 0 for all cargoes. */ if (_returned_refit_capacity > 0 && (consist_capleft[cid] < consist_capleft[new_cid] || (consist_capleft[cid] == consist_capleft[new_cid] && st->goods[cid].cargo.AvailableCount() > st->goods[new_cid].cargo.AvailableCount()))) { new_cid = cid; } } } } /* Refit if given a valid cargo. */ if (new_cid < NUM_CARGO && new_cid != v_start->cargo_type) { /* INVALID_STATION because in the DT_MANUAL case that's correct and in the DT_(A)SYMMETRIC * cases the next hop of the vehicle doesn't really tell us anything if the cargo had been * "via any station" before reserving. We rather produce some more "any station" cargo than * misrouting it. */ IterateVehicleParts(v_start, ReturnCargoAction(st, INVALID_STATION)); CommandCost cost = DoCommand(v_start->tile, v_start->index, new_cid | 1U << 6 | 0xFF << 8 | 1U << 16, DC_EXEC, GetCmdRefitVeh(v_start)); // Auto-refit and only this vehicle including artic parts. if (cost.Succeeded()) v->First()->profit_this_year -= cost.GetCost() << 8; } /* Add new capacity to consist capacity and reserve cargo */ IterateVehicleParts(v_start, FinalizeRefitAction(consist_capleft, st, next_station, is_auto_refit || (v->First()->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0)); cur_company.Restore(); } struct ReserveCargoAction { Station *st; StationIDStack *next_station; ReserveCargoAction(Station *st, StationIDStack *next_station) : st(st), next_station(next_station) {} bool operator()(Vehicle *v) { if (v->cargo_cap > v->cargo.RemainingCount()) { st->goods[v->cargo_type].cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), &v->cargo, st->xy, *next_station); } return true; } }; /** * Reserves cargo if the full load order and improved_load is set or if the * current order allows autorefit. * @param st Station where the consist is loading at the moment. * @param u Front of the loading vehicle consist. * @param consist_capleft If given, save free capacities after reserving there. * @param next_station Station(s) the vehicle will stop at next. */ static void ReserveConsist(Station *st, Vehicle *u, CargoArray *consist_capleft, StationIDStack *next_station) { /* If there is a cargo payment not all vehicles of the consist have tried to do the refit. * In that case, only reserve if it's a fixed refit and the equivalent of "articulated chain" * a vehicle belongs to already has the right cargo. */ bool must_reserve = !u->current_order.IsRefit() || u->cargo_payment == NULL; for (Vehicle *v = u; v != NULL; v = v->Next()) { assert(v->cargo_cap >= v->cargo.RemainingCount()); /* Exclude various ways in which the vehicle might not be the head of an equivalent of * "articulated chain". Also don't do the reservation if the vehicle is going to refit * to a different cargo and hasn't tried to do so, yet. */ if (!v->IsArticulatedPart() && (v->type != VEH_TRAIN || !Train::From(v)->IsRearDualheaded()) && (v->type != VEH_AIRCRAFT || Aircraft::From(v)->IsNormalAircraft()) && (must_reserve || u->current_order.GetRefitCargo() == v->cargo_type)) { IterateVehicleParts(v, ReserveCargoAction(st, next_station)); } if (consist_capleft == NULL || v->cargo_cap == 0) continue; (*consist_capleft)[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount(); } } /** * Update the vehicle's load_unload_ticks, the time it will wait until it tries to load or unload * again. Adjust for overhang of trains and set it at least to 1. * @param front The vehicle to be updated. * @param st The station the vehicle is loading at. * @param ticks The time it would normally wait, based on cargo loaded and unloaded. */ static void UpdateLoadUnloadTicks(Vehicle *front, const Station *st, int ticks) { if (front->type == VEH_TRAIN) { /* Each platform tile is worth 2 rail vehicles. */ int overhang = front->GetGroundVehicleCache()->cached_total_length - st->GetPlatformLength(front->tile) * TILE_SIZE; if (overhang > 0) { ticks <<= 1; ticks += (overhang * ticks) / 8; } } /* Always wait at least 1, otherwise we'll wait 'infinitively' long. */ front->load_unload_ticks = max(1, ticks); } /** * Loads/unload the vehicle if possible. * @param front the vehicle to be (un)loaded */ static void LoadUnloadVehicle(Vehicle *front) { assert(front->current_order.IsType(OT_LOADING)); StationID last_visited = front->last_station_visited; Station *st = Station::Get(last_visited); StationIDStack next_station = front->GetNextStoppingStation(); bool use_autorefit = front->current_order.IsRefit() && front->current_order.GetRefitCargo() == CT_AUTO_REFIT; CargoArray consist_capleft; if (_settings_game.order.improved_load && use_autorefit ? front->cargo_payment == NULL : (front->current_order.GetLoadType() & OLFB_FULL_LOAD) != 0) { ReserveConsist(st, front, (use_autorefit && front->load_unload_ticks != 0) ? &consist_capleft : NULL, &next_station); } /* We have not waited enough time till the next round of loading/unloading */ if (front->load_unload_ticks != 0) return; if (front->type == VEH_TRAIN && (!IsTileType(front->tile, MP_STATION) || GetStationIndex(front->tile) != st->index)) { /* The train reversed in the station. Take the "easy" way * out and let the train just leave as it always did. */ SetBit(front->vehicle_flags, VF_LOADING_FINISHED); front->load_unload_ticks = 1; return; } int new_load_unload_ticks = 0; bool dirty_vehicle = false; bool dirty_station = false; bool completely_emptied = true; bool anything_unloaded = false; bool anything_loaded = false; uint32 full_load_amount = 0; uint32 cargo_not_full = 0; uint32 cargo_full = 0; uint32 reservation_left = 0; front->cur_speed = 0; CargoPayment *payment = front->cargo_payment; uint artic_part = 0; // Articulated part we are currently trying to load. (not counting parts without capacity) for (Vehicle *v = front; v != NULL; v = v->Next()) { if (v == front || !v->Previous()->HasArticulatedPart()) artic_part = 0; if (v->cargo_cap == 0) continue; artic_part++; uint load_amount = GetLoadAmount(v); GoodsEntry *ge = &st->goods[v->cargo_type]; if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) && (front->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) { uint cargo_count = v->cargo.UnloadCount(); uint amount_unloaded = _settings_game.order.gradual_loading ? min(cargo_count, load_amount) : cargo_count; bool remaining = false; // Are there cargo entities in this vehicle that can still be unloaded here? payment->SetCargo(v->cargo_type); if (!HasBit(ge->status, GoodsEntry::GES_ACCEPTANCE) && v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER) > 0) { /* The station does not accept our goods anymore. */ if (front->current_order.GetUnloadType() & (OUFB_TRANSFER | OUFB_UNLOAD)) { /* Transfer instead of delivering. */ v->cargo.Reassign( v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER), INVALID_STATION); } else { uint new_remaining = v->cargo.RemainingCount() + v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER); if (v->cargo_cap < new_remaining) { /* Return some of the reserved cargo to not overload the vehicle. */ v->cargo.Return(new_remaining - v->cargo_cap, &ge->cargo, INVALID_STATION); } /* Keep instead of delivering. This may lead to no cargo being unloaded, so ...*/ v->cargo.Reassign( v->cargo.ActionCount(VehicleCargoList::MTA_DELIVER)); /* ... say we unloaded something, otherwise we'll think we didn't unload * something and we didn't load something, so we must be finished * at this station. Setting the unloaded means that we will get a * retry for loading in the next cycle. */ anything_unloaded = true; } } if (v->cargo.ActionCount(VehicleCargoList::MTA_TRANSFER) > 0) { /* Mark the station dirty if we transfer, but not if we only deliver. */ dirty_station = true; if (!ge->HasRating()) { /* Upon transfering cargo, make sure the station has a rating. Fake a pickup for the * first unload to prevent the cargo from quickly decaying after the initial drop. */ ge->time_since_pickup = 0; SetBit(ge->status, GoodsEntry::GES_RATING); } } amount_unloaded = v->cargo.Unload(amount_unloaded, &ge->cargo, payment); remaining = v->cargo.UnloadCount() > 0; if (amount_unloaded > 0) { dirty_vehicle = true; anything_unloaded = true; new_load_unload_ticks += amount_unloaded; /* Deliver goods to the station */ st->time_since_unload = 0; } if (_settings_game.order.gradual_loading && remaining) { completely_emptied = false; } else { /* We have finished unloading (cargo count == 0) */ ClrBit(v->vehicle_flags, VF_CARGO_UNLOADING); } continue; } /* Do not pick up goods when we have no-load set or loading is stopped. */ if (front->current_order.GetLoadType() & OLFB_NO_LOAD || HasBit(front->vehicle_flags, VF_STOP_LOADING)) continue; /* This order has a refit, if this is the first vehicle part carrying cargo and the whole vehicle is empty, try refitting. */ if (front->current_order.IsRefit() && artic_part == 1) { HandleStationRefit(v, consist_capleft, st, next_station, front->current_order.GetRefitCargo()); ge = &st->goods[v->cargo_type]; } /* As we're loading here the following link can carry the full capacity of the vehicle. */ v->refit_cap = v->cargo_cap; /* update stats */ int t; switch (front->type) { case VEH_TRAIN: /* FALL THROUGH */ case VEH_SHIP: t = front->vcache.cached_max_speed; break; case VEH_ROAD: t = front->vcache.cached_max_speed / 2; break; case VEH_AIRCRAFT: t = Aircraft::From(front)->GetSpeedOldUnits(); // Convert to old units. break; default: NOT_REACHED(); } /* if last speed is 0, we treat that as if no vehicle has ever visited the station. */ ge->last_speed = min(t, 255); ge->last_age = min(_cur_year - front->build_year, 255); ge->time_since_pickup = 0; assert(v->cargo_cap >= v->cargo.StoredCount()); /* If there's goods waiting at the station, and the vehicle * has capacity for it, load it on the vehicle. */ uint cap_left = v->cargo_cap - v->cargo.StoredCount(); if (cap_left > 0 && (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0 || ge->cargo.AvailableCount() > 0)) { if (_settings_game.order.gradual_loading) cap_left = min(cap_left, load_amount); if (v->cargo.StoredCount() == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO); uint loaded = ge->cargo.Load(cap_left, &v->cargo, st->xy, next_station); if (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) { /* Remember if there are reservations left so that we don't stop * loading before they're loaded. */ SetBit(reservation_left, v->cargo_type); } /* Store whether the maximum possible load amount was loaded or not.*/ if (loaded == cap_left) { SetBit(full_load_amount, v->cargo_type); } else { ClrBit(full_load_amount, v->cargo_type); } /* TODO: Regarding this, when we do gradual loading, we * should first unload all vehicles and then start * loading them. Since this will cause * VEHICLE_TRIGGER_EMPTY to be called at the time when * the whole vehicle chain is really totally empty, the * completely_emptied assignment can then be safely * removed; that's how TTDPatch behaves too. --pasky */ if (loaded > 0) { completely_emptied = false; anything_loaded = true; st->time_since_load = 0; st->last_vehicle_type = v->type; if (ge->cargo.TotalCount() == 0) { TriggerStationRandomisation(st, st->xy, SRT_CARGO_TAKEN, v->cargo_type); TriggerStationAnimation(st, st->xy, SAT_CARGO_TAKEN, v->cargo_type); AirportAnimationTrigger(st, AAT_STATION_CARGO_TAKEN, v->cargo_type); } new_load_unload_ticks += loaded; dirty_vehicle = dirty_station = true; } } if (v->cargo.StoredCount() >= v->cargo_cap) { SetBit(cargo_full, v->cargo_type); } else { SetBit(cargo_not_full, v->cargo_type); } } if (anything_loaded || anything_unloaded) { if (front->type == VEH_TRAIN) { TriggerStationRandomisation(st, front->tile, SRT_TRAIN_LOADS); TriggerStationAnimation(st, front->tile, SAT_TRAIN_LOADS); } } /* Only set completely_emptied, if we just unloaded all remaining cargo */ completely_emptied &= anything_unloaded; if (!anything_unloaded) delete payment; ClrBit(front->vehicle_flags, VF_STOP_LOADING); if (anything_loaded || anything_unloaded) { if (_settings_game.order.gradual_loading) { /* The time it takes to load one 'slice' of cargo or passengers depends * on the vehicle type - the values here are those found in TTDPatch */ const uint gradual_loading_wait_time[] = { 40, 20, 10, 20 }; new_load_unload_ticks = gradual_loading_wait_time[front->type]; } /* We loaded less cargo than possible for all cargo types and it's not full * load and we're not supposed to wait any longer: stop loading. */ if (!anything_unloaded && full_load_amount == 0 && reservation_left == 0 && !(front->current_order.GetLoadType() & OLFB_FULL_LOAD) && front->current_order_time >= (uint)max(front->current_order.GetTimetabledWait() - front->lateness_counter, 0)) { SetBit(front->vehicle_flags, VF_STOP_LOADING); } UpdateLoadUnloadTicks(front, st, new_load_unload_ticks); } else { UpdateLoadUnloadTicks(front, st, 20); // We need the ticks for link refreshing. bool finished_loading = true; if (front->current_order.GetLoadType() & OLFB_FULL_LOAD) { if (front->current_order.GetLoadType() == OLF_FULL_LOAD_ANY) { /* if the aircraft carries passengers and is NOT full, then * continue loading, no matter how much mail is in */ if ((front->type == VEH_AIRCRAFT && IsCargoInClass(front->cargo_type, CC_PASSENGERS) && front->cargo_cap > front->cargo.StoredCount()) || (cargo_not_full && (cargo_full & ~cargo_not_full) == 0)) { // There are still non-full cargoes finished_loading = false; } } else if (cargo_not_full != 0) { finished_loading = false; } /* Refresh next hop stats if we're full loading to make the links * known to the distribution algorithm and allow cargo to be sent * along them. Otherwise the vehicle could wait for cargo * indefinitely if it hasn't visited the other links yet, or if the * links die while it's loading. */ if (!finished_loading) LinkRefresher::Run(front, true, true); } SB(front->vehicle_flags, VF_LOADING_FINISHED, 1, finished_loading); } /* Calculate the loading indicator fill percent and display * In the Game Menu do not display indicators * If _settings_client.gui.loading_indicators == 2, show indicators (bool can be promoted to int as 0 or 1 - results in 2 > 0,1 ) * if _settings_client.gui.loading_indicators == 1, _local_company must be the owner or must be a spectator to show ind., so 1 > 0 * if _settings_client.gui.loading_indicators == 0, do not display indicators ... 0 is never greater than anything */ if (_game_mode != GM_MENU && (_settings_client.gui.loading_indicators > (uint)(front->owner != _local_company && _local_company != COMPANY_SPECTATOR))) { StringID percent_up_down = STR_NULL; int percent = CalcPercentVehicleFilled(front, &percent_up_down); if (front->fill_percent_te_id == INVALID_TE_ID) { front->fill_percent_te_id = ShowFillingPercent(front->x_pos, front->y_pos, front->z_pos + 20, percent, percent_up_down); } else { UpdateFillingPercent(front->fill_percent_te_id, percent, percent_up_down); } } if (completely_emptied) { /* Make sure the vehicle is marked dirty, since we need to update the NewGRF * properties such as weight, power and TE whenever the trigger runs. */ dirty_vehicle = true; TriggerVehicle(front, VEHICLE_TRIGGER_EMPTY); } if (dirty_vehicle) { SetWindowDirty(GetWindowClassForVehicleType(front->type), front->owner); SetWindowDirty(WC_VEHICLE_DETAILS, front->index); front->MarkDirty(); } if (dirty_station) { st->MarkTilesDirty(true); SetWindowDirty(WC_STATION_VIEW, last_visited); InvalidateWindowData(WC_STATION_LIST, last_visited); } } /** * Load/unload the vehicles in this station according to the order * they entered. * @param st the station to do the loading/unloading for */ void LoadUnloadStation(Station *st) { /* No vehicle is here... */ if (st->loading_vehicles.empty()) return; Vehicle *last_loading = NULL; std::list::iterator iter; /* Check if anything will be loaded at all. Otherwise we don't need to reserve either. */ for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) { Vehicle *v = *iter; if ((v->vehstatus & (VS_STOPPED | VS_CRASHED))) continue; assert(v->load_unload_ticks != 0); if (--v->load_unload_ticks == 0) last_loading = v; } /* We only need to reserve and load/unload up to the last loading vehicle. * Anything else will be forgotten anyway after returning from this function. * * Especially this means we do _not_ need to reserve cargo for a single * consist in a station which is not allowed to load yet because its * load_unload_ticks is still not 0. */ if (last_loading == NULL) return; for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) { Vehicle *v = *iter; if (!(v->vehstatus & (VS_STOPPED | VS_CRASHED))) LoadUnloadVehicle(v); if (v == last_loading) break; } /* Call the production machinery of industries */ const Industry * const *isend = _cargo_delivery_destinations.End(); for (Industry **iid = _cargo_delivery_destinations.Begin(); iid != isend; iid++) { TriggerIndustryProduction(*iid); } _cargo_delivery_destinations.Clear(); } /** * Monthly update of the economic data (of the companies as well as economic fluctuations). */ void CompaniesMonthlyLoop() { CompaniesGenStatistics(); if (_settings_game.economy.inflation) { AddInflation(); RecomputePrices(); } CompaniesPayInterest(); HandleEconomyFluctuations(); } static void DoAcquireCompany(Company *c) { CompanyID ci = c->index; CompanyNewsInformation *cni = MallocT(1); cni->FillData(c, Company::Get(_current_company)); SetDParam(0, STR_NEWS_COMPANY_MERGER_TITLE); SetDParam(1, c->bankrupt_value == 0 ? STR_NEWS_MERGER_TAKEOVER_TITLE : STR_NEWS_COMPANY_MERGER_DESCRIPTION); SetDParamStr(2, cni->company_name); SetDParamStr(3, cni->other_company_name); SetDParam(4, c->bankrupt_value); AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, cni); AI::BroadcastNewEvent(new ScriptEventCompanyMerger(ci, _current_company)); Game::NewEvent(new ScriptEventCompanyMerger(ci, _current_company)); ChangeOwnershipOfCompanyItems(ci, _current_company); if (c->bankrupt_value == 0) { Company *owner = Company::Get(_current_company); owner->current_loan += c->current_loan; } if (c->is_ai) AI::Stop(c->index); DeleteCompanyWindows(ci); InvalidateWindowClassesData(WC_TRAINS_LIST, 0); InvalidateWindowClassesData(WC_SHIPS_LIST, 0); InvalidateWindowClassesData(WC_ROADVEH_LIST, 0); InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0); delete c; } extern int GetAmountOwnedBy(const Company *c, Owner owner); /** * Acquire shares in an opposing company. * @param tile unused * @param flags type of operation * @param p1 company to buy the shares from * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuyShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CommandCost cost(EXPENSES_OTHER); CompanyID target_company = (CompanyID)p1; Company *c = Company::GetIfValid(target_company); /* Check if buying shares is allowed (protection against modified clients) * Cannot buy own shares */ if (c == NULL || !_settings_game.economy.allow_shares || _current_company == target_company) return CMD_ERROR; /* Protect new companies from hostile takeovers */ if (_cur_year - c->inaugurated_year < 6) return_cmd_error(STR_ERROR_PROTECTED); /* Those lines are here for network-protection (clients can be slow) */ if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 0) return cost; if (GetAmountOwnedBy(c, COMPANY_SPECTATOR) == 1) { if (!c->is_ai) return cost; // We can not buy out a real company (temporarily). TODO: well, enable it obviously. if (GetAmountOwnedBy(c, _current_company) == 3 && !MayCompanyTakeOver(_current_company, target_company)) return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME); } cost.AddCost(CalculateCompanyValue(c) >> 2); if (flags & DC_EXEC) { OwnerByte *b = c->share_owners; while (*b != COMPANY_SPECTATOR) b++; // share owners is guaranteed to contain at least one COMPANY_SPECTATOR *b = _current_company; for (int i = 0; c->share_owners[i] == _current_company;) { if (++i == 4) { c->bankrupt_value = 0; DoAcquireCompany(c); break; } } InvalidateWindowData(WC_COMPANY, target_company); CompanyAdminUpdate(c); } return cost; } /** * Sell shares in an opposing company. * @param tile unused * @param flags type of operation * @param p1 company to sell the shares from * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSellShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CompanyID target_company = (CompanyID)p1; Company *c = Company::GetIfValid(target_company); /* Cannot sell own shares */ if (c == NULL || _current_company == target_company) return CMD_ERROR; /* Check if selling shares is allowed (protection against modified clients). * However, we must sell shares of companies being closed down. */ if (!_settings_game.economy.allow_shares && !(flags & DC_BANKRUPT)) return CMD_ERROR; /* Those lines are here for network-protection (clients can be slow) */ if (GetAmountOwnedBy(c, _current_company) == 0) return CommandCost(); /* adjust it a little to make it less profitable to sell and buy */ Money cost = CalculateCompanyValue(c) >> 2; cost = -(cost - (cost >> 7)); if (flags & DC_EXEC) { OwnerByte *b = c->share_owners; while (*b != _current_company) b++; // share owners is guaranteed to contain company *b = COMPANY_SPECTATOR; InvalidateWindowData(WC_COMPANY, target_company); CompanyAdminUpdate(c); } return CommandCost(EXPENSES_OTHER, cost); } /** * Buy up another company. * When a competing company is gone bankrupt you get the chance to purchase * that company. * @todo currently this only works for AI companies * @param tile unused * @param flags type of operation * @param p1 company to buy up * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuyCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CompanyID target_company = (CompanyID)p1; Company *c = Company::GetIfValid(target_company); if (c == NULL) return CMD_ERROR; /* Disable takeovers when not asked */ if (!HasBit(c->bankrupt_asked, _current_company)) return CMD_ERROR; /* Disable taking over the local company in single player */ if (!_networking && _local_company == c->index) return CMD_ERROR; /* Do not allow companies to take over themselves */ if (target_company == _current_company) return CMD_ERROR; /* Disable taking over when not allowed. */ if (!MayCompanyTakeOver(_current_company, target_company)) return CMD_ERROR; /* Get the cost here as the company is deleted in DoAcquireCompany. */ CommandCost cost(EXPENSES_OTHER, c->bankrupt_value); if (flags & DC_EXEC) { DoAcquireCompany(c); } return cost; } openttd-1.5.3/src/timetable_gui.cpp0000644000000000000000000006632212627373435016025 0ustar rootroot/* $Id: timetable_gui.cpp 26639 2014-06-10 16:29:03Z frosch $ */ /* * 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 timetable_gui.cpp GUI for time tabling. */ #include "stdafx.h" #include "command_func.h" #include "gui.h" #include "window_gui.h" #include "window_func.h" #include "textbuf_gui.h" #include "strings_func.h" #include "vehicle_base.h" #include "string_func.h" #include "gfx_func.h" #include "company_func.h" #include "date_func.h" #include "date_gui.h" #include "vehicle_gui.h" #include "settings_type.h" #include "widgets/timetable_widget.h" #include "table/sprites.h" #include "table/strings.h" #include "safeguards.h" /** Container for the arrival/departure dates of a vehicle */ struct TimetableArrivalDeparture { Ticks arrival; ///< The arrival time Ticks departure; ///< The departure time }; /** * Set the timetable parameters in the format as described by the setting. * @param param1 the first DParam to fill * @param param2 the second DParam to fill * @param ticks the number of ticks to 'draw' */ void SetTimetableParams(int param1, int param2, Ticks ticks) { if (_settings_client.gui.timetable_in_ticks) { SetDParam(param1, STR_TIMETABLE_TICKS); SetDParam(param2, ticks); } else { SetDParam(param1, STR_TIMETABLE_DAYS); SetDParam(param2, ticks / DAY_TICKS); } } /** * Check whether it is possible to determine how long the order takes. * @param order the order to check. * @param travelling whether we are interested in the travel or the wait part. * @return true if the travel/wait time can be used. */ static bool CanDetermineTimeTaken(const Order *order, bool travelling) { /* Current order is conditional */ if (order->IsType(OT_CONDITIONAL) || order->IsType(OT_IMPLICIT)) return false; /* No travel time and we have not already finished travelling */ if (travelling && !order->IsTravelTimetabled()) return false; /* No wait time but we are loading at this timetabled station */ if (!travelling && !order->IsWaitTimetabled() && order->IsType(OT_GOTO_STATION) && !(order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) { return false; } return true; } /** * Fill the table with arrivals and departures * @param v Vehicle which must have at least 2 orders. * @param start order index to start at * @param travelling Are we still in the travelling part of the start order * @param table Fill in arrival and departures including intermediate orders * @param offset Add this value to result and all arrivals and departures */ static void FillTimetableArrivalDepartureTable(const Vehicle *v, VehicleOrderID start, bool travelling, TimetableArrivalDeparture *table, Ticks offset) { assert(table != NULL); assert(v->GetNumOrders() >= 2); assert(start < v->GetNumOrders()); Ticks sum = offset; VehicleOrderID i = start; const Order *order = v->GetOrder(i); /* Pre-initialize with unknown time */ for (int i = 0; i < v->GetNumOrders(); ++i) { table[i].arrival = table[i].departure = INVALID_TICKS; } /* Cyclically loop over all orders until we reach the current one again. * As we may start at the current order, do a post-checking loop */ do { /* Automatic orders don't influence the overall timetable; * they just add some untimetabled entries, but the time till * the next non-implicit order can still be known. */ if (!order->IsType(OT_IMPLICIT)) { if (travelling || i != start) { if (!CanDetermineTimeTaken(order, true)) return; sum += order->GetTimetabledTravel(); table[i].arrival = sum; } if (!CanDetermineTimeTaken(order, false)) return; sum += order->GetTimetabledWait(); table[i].departure = sum; } ++i; order = order->next; if (i >= v->GetNumOrders()) { i = 0; assert(order == NULL); order = v->orders.list->GetFirstOrder(); } } while (i != start); /* When loading at a scheduled station we still have to treat the * travelling part of the first order. */ if (!travelling) { if (!CanDetermineTimeTaken(order, true)) return; sum += order->GetTimetabledTravel(); table[i].arrival = sum; } } /** * Callback for when a time has been chosen to start the time table * @param window the window related to the setting of the date * @param date the actually chosen date */ static void ChangeTimetableStartCallback(const Window *w, Date date) { DoCommandP(0, w->window_number, date, CMD_SET_TIMETABLE_START | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); } struct TimetableWindow : Window { int sel_index; const Vehicle *vehicle; ///< Vehicle monitored by the window. bool show_expected; ///< Whether we show expected arrival or scheduled uint deparr_time_width; ///< The width of the departure/arrival time uint deparr_abbr_width; ///< The width of the departure/arrival abbreviation Scrollbar *vscroll; bool query_is_speed_query; ///< The currently open query window is a speed query and not a time query. TimetableWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc), sel_index(-1), vehicle(Vehicle::Get(window_number)), show_expected(true) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_VT_SCROLLBAR); this->UpdateSelectionStates(); this->FinishInitNested(window_number); this->owner = this->vehicle->owner; } /** * Build the arrival-departure list for a given vehicle * @param v the vehicle to make the list for * @param table the table to fill * @return if next arrival will be early */ static bool BuildArrivalDepartureList(const Vehicle *v, TimetableArrivalDeparture *table) { assert(HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)); bool travelling = (!v->current_order.IsType(OT_LOADING) || v->current_order.GetNonStopType() == ONSF_STOP_EVERYWHERE); Ticks start_time = _date_fract - v->current_order_time; FillTimetableArrivalDepartureTable(v, v->cur_real_order_index % v->GetNumOrders(), travelling, table, start_time); return (travelling && v->lateness_counter < 0); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_VT_ARRIVAL_DEPARTURE_PANEL: SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR, 0, FS_SMALL); this->deparr_time_width = GetStringBoundingBox(STR_JUST_DATE_TINY).width; this->deparr_abbr_width = max(GetStringBoundingBox(STR_TIMETABLE_ARRIVAL_ABBREVIATION).width, GetStringBoundingBox(STR_TIMETABLE_DEPARTURE_ABBREVIATION).width); size->width = WD_FRAMERECT_LEFT + this->deparr_abbr_width + 10 + this->deparr_time_width + WD_FRAMERECT_RIGHT; /* FALL THROUGH */ case WID_VT_ARRIVAL_DEPARTURE_SELECTION: case WID_VT_TIMETABLE_PANEL: resize->height = FONT_HEIGHT_NORMAL; size->height = WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM; break; case WID_VT_SUMMARY_PANEL: size->height = WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM; break; } } int GetOrderFromTimetableWndPt(int y, const Vehicle *v) { int sel = (y - this->GetWidget(WID_VT_TIMETABLE_PANEL)->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL; if ((uint)sel >= this->vscroll->GetCapacity()) return INVALID_ORDER; sel += this->vscroll->GetPosition(); return (sel < v->GetNumOrders() * 2 && sel >= 0) ? sel : INVALID_ORDER; } /** * 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) { switch (data) { case VIWD_AUTOREPLACE: /* Autoreplace replaced the vehicle */ this->vehicle = Vehicle::Get(this->window_number); break; case VIWD_REMOVE_ALL_ORDERS: /* Removed / replaced all orders (after deleting / sharing) */ if (this->sel_index == -1) break; this->DeleteChildWindows(); this->sel_index = -1; break; case VIWD_MODIFY_ORDERS: if (!gui_scope) break; this->UpdateSelectionStates(); this->ReInit(); break; default: { if (gui_scope) break; // only do this once; from command scope /* Moving an order. If one of these is INVALID_VEH_ORDER_ID, then * the order is being created / removed */ if (this->sel_index == -1) break; VehicleOrderID from = GB(data, 0, 8); VehicleOrderID to = GB(data, 8, 8); if (from == to) break; // no need to change anything /* if from == INVALID_VEH_ORDER_ID, one order was added; if to == INVALID_VEH_ORDER_ID, one order was removed */ uint old_num_orders = this->vehicle->GetNumOrders() - (uint)(from == INVALID_VEH_ORDER_ID) + (uint)(to == INVALID_VEH_ORDER_ID); VehicleOrderID selected_order = (this->sel_index + 1) / 2; if (selected_order == old_num_orders) selected_order = 0; // when last travel time is selected, it belongs to order 0 bool travel = HasBit(this->sel_index, 0); if (from != selected_order) { /* Moving from preceding order? */ selected_order -= (int)(from <= selected_order); /* Moving to preceding order? */ selected_order += (int)(to <= selected_order); } else { /* Now we are modifying the selected order */ if (to == INVALID_VEH_ORDER_ID) { /* Deleting selected order */ this->DeleteChildWindows(); this->sel_index = -1; break; } else { /* Moving selected order */ selected_order = to; } } /* recompute new sel_index */ this->sel_index = 2 * selected_order - (int)travel; /* travel time of first order needs special handling */ if (this->sel_index == -1) this->sel_index = this->vehicle->GetNumOrders() * 2 - 1; break; } } } virtual void OnPaint() { const Vehicle *v = this->vehicle; int selected = this->sel_index; this->vscroll->SetCount(v->GetNumOrders() * 2); if (v->owner == _local_company) { bool disable = true; if (selected != -1) { const Order *order = v->GetOrder(((selected + 1) / 2) % v->GetNumOrders()); if (selected % 2 == 1) { disable = order != NULL && (order->IsType(OT_CONDITIONAL) || order->IsType(OT_IMPLICIT)); } else { disable = order == NULL || ((!order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) && !order->IsType(OT_CONDITIONAL)); } } bool disable_speed = disable || selected % 2 != 1 || v->type == VEH_AIRCRAFT; this->SetWidgetDisabledState(WID_VT_CHANGE_TIME, disable); this->SetWidgetDisabledState(WID_VT_CLEAR_TIME, disable); this->SetWidgetDisabledState(WID_VT_CHANGE_SPEED, disable_speed); this->SetWidgetDisabledState(WID_VT_CLEAR_SPEED, disable_speed); this->SetWidgetDisabledState(WID_VT_SHARED_ORDER_LIST, !v->IsOrderListShared()); this->SetWidgetDisabledState(WID_VT_START_DATE, v->orders.list == NULL); this->SetWidgetDisabledState(WID_VT_RESET_LATENESS, v->orders.list == NULL); this->SetWidgetDisabledState(WID_VT_AUTOFILL, v->orders.list == NULL); } else { this->DisableWidget(WID_VT_START_DATE); this->DisableWidget(WID_VT_CHANGE_TIME); this->DisableWidget(WID_VT_CLEAR_TIME); this->DisableWidget(WID_VT_CHANGE_SPEED); this->DisableWidget(WID_VT_CLEAR_SPEED); this->DisableWidget(WID_VT_RESET_LATENESS); this->DisableWidget(WID_VT_AUTOFILL); this->DisableWidget(WID_VT_SHARED_ORDER_LIST); } this->SetWidgetLoweredState(WID_VT_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)); this->DrawWidgets(); } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_VT_CAPTION: SetDParam(0, this->vehicle->index); break; case WID_VT_EXPECTED: SetDParam(0, this->show_expected ? STR_TIMETABLE_EXPECTED : STR_TIMETABLE_SCHEDULED); break; } } virtual void DrawWidget(const Rect &r, int widget) const { const Vehicle *v = this->vehicle; int selected = this->sel_index; switch (widget) { case WID_VT_TIMETABLE_PANEL: { int y = r.top + WD_FRAMERECT_TOP; int i = this->vscroll->GetPosition(); VehicleOrderID order_id = (i + 1) / 2; bool final_order = false; bool rtl = _current_text_dir == TD_RTL; SetDParamMaxValue(0, v->GetNumOrders(), 2); int index_column_width = GetStringBoundingBox(STR_ORDER_INDEX).width + 2 * GetSpriteSize(rtl ? SPR_ARROW_RIGHT : SPR_ARROW_LEFT).width + 3; int middle = rtl ? r.right - WD_FRAMERECT_RIGHT - index_column_width : r.left + WD_FRAMERECT_LEFT + index_column_width; const Order *order = v->GetOrder(order_id); while (order != NULL) { /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; if (i % 2 == 0) { DrawOrderString(v, order, order_id, y, i == selected, true, r.left + WD_FRAMERECT_LEFT, middle, r.right - WD_FRAMERECT_RIGHT); order_id++; if (order_id >= v->GetNumOrders()) { order = v->GetOrder(0); final_order = true; } else { order = order->next; } } else { StringID string; TextColour colour = (i == selected) ? TC_WHITE : TC_BLACK; if (order->IsType(OT_CONDITIONAL)) { string = STR_TIMETABLE_NO_TRAVEL; } else if (order->IsType(OT_IMPLICIT)) { string = STR_TIMETABLE_NOT_TIMETABLEABLE; colour = ((i == selected) ? TC_SILVER : TC_GREY) | TC_NO_SHADE; } else if (!order->IsTravelTimetabled()) { if (order->GetTravelTime() > 0) { SetTimetableParams(0, 1, order->GetTravelTime()); string = order->GetMaxSpeed() != UINT16_MAX ? STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED : STR_TIMETABLE_TRAVEL_FOR_ESTIMATED; } else { string = order->GetMaxSpeed() != UINT16_MAX ? STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED : STR_TIMETABLE_TRAVEL_NOT_TIMETABLED; } } else { SetTimetableParams(0, 1, order->GetTimetabledTravel()); string = order->GetMaxSpeed() != UINT16_MAX ? STR_TIMETABLE_TRAVEL_FOR_SPEED : STR_TIMETABLE_TRAVEL_FOR; } SetDParam(2, order->GetMaxSpeed()); DrawString(rtl ? r.left + WD_FRAMERECT_LEFT : middle, rtl ? middle : r.right - WD_FRAMERECT_LEFT, y, string, colour); if (final_order) break; } i++; y += FONT_HEIGHT_NORMAL; } break; } case WID_VT_ARRIVAL_DEPARTURE_PANEL: { /* Arrival and departure times are handled in an all-or-nothing approach, * i.e. are only shown if we can calculate all times. * Excluding order lists with only one order makes some things easier. */ Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time <= 0 || v->GetNumOrders() <= 1 || !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) break; TimetableArrivalDeparture *arr_dep = AllocaM(TimetableArrivalDeparture, v->GetNumOrders()); const VehicleOrderID cur_order = v->cur_real_order_index % v->GetNumOrders(); VehicleOrderID earlyID = BuildArrivalDepartureList(v, arr_dep) ? cur_order : (VehicleOrderID)INVALID_VEH_ORDER_ID; int y = r.top + WD_FRAMERECT_TOP; bool show_late = this->show_expected && v->lateness_counter > DAY_TICKS; Ticks offset = show_late ? 0 : -v->lateness_counter; bool rtl = _current_text_dir == TD_RTL; int abbr_left = rtl ? r.right - WD_FRAMERECT_RIGHT - this->deparr_abbr_width : r.left + WD_FRAMERECT_LEFT; int abbr_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->deparr_abbr_width; int time_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_RIGHT - this->deparr_time_width; int time_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->deparr_time_width : r.right - WD_FRAMERECT_RIGHT; for (int i = this->vscroll->GetPosition(); i / 2 < v->GetNumOrders(); ++i) { // note: i is also incremented in the loop /* Don't draw anything if it extends past the end of the window. */ if (!this->vscroll->IsVisible(i)) break; if (i % 2 == 0) { if (arr_dep[i / 2].arrival != INVALID_TICKS) { DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_ARRIVAL_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK); if (this->show_expected && i / 2 == earlyID) { SetDParam(0, _date + arr_dep[i / 2].arrival / DAY_TICKS); DrawString(time_left, time_right, y, STR_JUST_DATE_TINY, TC_GREEN); } else { SetDParam(0, _date + (arr_dep[i / 2].arrival + offset) / DAY_TICKS); DrawString(time_left, time_right, y, STR_JUST_DATE_TINY, show_late ? TC_RED : i == selected ? TC_WHITE : TC_BLACK); } } } else { if (arr_dep[i / 2].departure != INVALID_TICKS) { DrawString(abbr_left, abbr_right, y, STR_TIMETABLE_DEPARTURE_ABBREVIATION, i == selected ? TC_WHITE : TC_BLACK); SetDParam(0, _date + (arr_dep[i/2].departure + offset) / DAY_TICKS); DrawString(time_left, time_right, y, STR_JUST_DATE_TINY, show_late ? TC_RED : i == selected ? TC_WHITE : TC_BLACK); } } y += FONT_HEIGHT_NORMAL; } break; } case WID_VT_SUMMARY_PANEL: { int y = r.top + WD_FRAMERECT_TOP; Ticks total_time = v->orders.list != NULL ? v->orders.list->GetTimetableDurationIncomplete() : 0; if (total_time != 0) { SetTimetableParams(0, 1, total_time); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->orders.list->IsCompleteTimetable() ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE); } y += FONT_HEIGHT_NORMAL; if (v->timetable_start != 0) { /* We are running towards the first station so we can start the * timetable at the given time. */ SetDParam(0, STR_JUST_DATE_TINY); SetDParam(1, v->timetable_start); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_START_AT); } else if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) { /* We aren't running on a timetable yet, so how can we be "on time" * when we aren't even "on service"/"on duty"? */ DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_NOT_STARTED); } else if (v->lateness_counter == 0 || (!_settings_client.gui.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_TIMETABLE_STATUS_ON_TIME); } else { SetTimetableParams(0, 1, abs(v->lateness_counter)); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE); } break; } } } static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected, bool speed) { uint order_number = (selected + 1) / 2; ModifyTimetableFlags mtf = (selected % 2 == 1) ? (speed ? MTF_TRAVEL_SPEED : MTF_TRAVEL_TIME) : MTF_WAIT_TIME; if (order_number >= v->GetNumOrders()) order_number = 0; return v->index | (order_number << 20) | (mtf << 28); } virtual void OnClick(Point pt, int widget, int click_count) { const Vehicle *v = this->vehicle; switch (widget) { case WID_VT_ORDER_VIEW: // Order view button ShowOrdersWindow(v); break; case WID_VT_TIMETABLE_PANEL: { // Main panel. int selected = GetOrderFromTimetableWndPt(pt.y, v); this->DeleteChildWindows(); this->sel_index = (selected == INVALID_ORDER || selected == this->sel_index) ? -1 : selected; break; } case WID_VT_START_DATE: // Change the date that the timetable starts. ShowSetDateWindow(this, v->index | (v->orders.list->IsCompleteTimetable() && _ctrl_pressed ? 1U << 20 : 0), _date, _cur_year, _cur_year + 15, ChangeTimetableStartCallback); break; case WID_VT_CHANGE_TIME: { // "Wait For" button. int selected = this->sel_index; VehicleOrderID real = (selected + 1) / 2; if (real >= v->GetNumOrders()) real = 0; const Order *order = v->GetOrder(real); StringID current = STR_EMPTY; if (order != NULL) { uint time = (selected % 2 == 1) ? order->GetTravelTime() : order->GetWaitTime(); if (!_settings_client.gui.timetable_in_ticks) time /= DAY_TICKS; if (time != 0) { SetDParam(0, time); current = STR_JUST_INT; } } this->query_is_speed_query = false; ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, this, CS_NUMERAL, QSF_ACCEPT_UNCHANGED); break; } case WID_VT_CHANGE_SPEED: { // Change max speed button. int selected = this->sel_index; VehicleOrderID real = (selected + 1) / 2; if (real >= v->GetNumOrders()) real = 0; StringID current = STR_EMPTY; const Order *order = v->GetOrder(real); if (order != NULL) { if (order->GetMaxSpeed() != UINT16_MAX) { SetDParam(0, ConvertKmhishSpeedToDisplaySpeed(order->GetMaxSpeed())); current = STR_JUST_INT; } } this->query_is_speed_query = true; ShowQueryString(current, STR_TIMETABLE_CHANGE_SPEED, 31, this, CS_NUMERAL, QSF_NONE); break; } case WID_VT_CLEAR_TIME: { // Clear waiting time. uint32 p1 = PackTimetableArgs(v, this->sel_index, false); DoCommandP(0, p1, 0, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; } case WID_VT_CLEAR_SPEED: { // Clear max speed button. uint32 p1 = PackTimetableArgs(v, this->sel_index, true); DoCommandP(0, p1, UINT16_MAX, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; } case WID_VT_RESET_LATENESS: // Reset the vehicle's late counter. DoCommandP(0, v->index, 0, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; case WID_VT_AUTOFILL: { // Autofill the timetable. uint32 p2 = 0; if (!HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(p2, 0); if (_ctrl_pressed) SetBit(p2, 1); DoCommandP(0, v->index, p2, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); break; } case WID_VT_EXPECTED: this->show_expected = !this->show_expected; break; case WID_VT_SHARED_ORDER_LIST: ShowVehicleListWindow(v); break; } this->SetDirty(); } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; const Vehicle *v = this->vehicle; uint32 p1 = PackTimetableArgs(v, this->sel_index, this->query_is_speed_query); uint64 val = StrEmpty(str) ? 0 : strtoul(str, NULL, 10); if (this->query_is_speed_query) { val = ConvertDisplaySpeedToKmhishSpeed(val); } else { if (!_settings_client.gui.timetable_in_ticks) val *= DAY_TICKS; } uint32 p2 = minu(val, UINT16_MAX); DoCommandP(0, p1, p2, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_ERROR_CAN_T_TIMETABLE_VEHICLE)); } virtual void OnResize() { /* Update the scroll bar */ this->vscroll->SetCapacityFromWidget(this, WID_VT_TIMETABLE_PANEL, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); } /** * Update the selection state of the arrival/departure data */ void UpdateSelectionStates() { this->GetWidget(WID_VT_ARRIVAL_DEPARTURE_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : SZSP_NONE); this->GetWidget(WID_VT_EXPECTED_SELECTION)->SetDisplayedPlane(_settings_client.gui.timetable_arrival_departure ? 0 : 1); } }; static const NWidgetPart _nested_timetable_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_VT_CAPTION), SetDataTip(STR_TIMETABLE_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_ORDER_VIEW), SetMinimalSize(61, 14), SetDataTip( STR_TIMETABLE_ORDER_VIEW, STR_TIMETABLE_ORDER_VIEW_TOOLTIP), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_VT_TIMETABLE_PANEL), SetMinimalSize(388, 82), SetResize(1, 10), SetDataTip(STR_NULL, STR_TIMETABLE_TOOLTIP), SetScrollbar(WID_VT_SCROLLBAR), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VT_ARRIVAL_DEPARTURE_SELECTION), NWidget(WWT_PANEL, COLOUR_GREY, WID_VT_ARRIVAL_DEPARTURE_PANEL), SetMinimalSize(110, 0), SetFill(0, 1), SetDataTip(STR_NULL, STR_TIMETABLE_TOOLTIP), SetScrollbar(WID_VT_SCROLLBAR), EndContainer(), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_VT_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_VT_SUMMARY_PANEL), SetMinimalSize(400, 22), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CHANGE_TIME), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CHANGE_TIME, STR_TIMETABLE_WAIT_TIME_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CLEAR_TIME), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CLEAR_TIME, STR_TIMETABLE_CLEAR_TIME_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CHANGE_SPEED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CHANGE_SPEED, STR_TIMETABLE_CHANGE_SPEED_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_CLEAR_SPEED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_CLEAR_SPEED, STR_TIMETABLE_CLEAR_SPEED_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_START_DATE), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_STARTING_DATE, STR_TIMETABLE_STARTING_DATE_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_RESET_LATENESS), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_RESET_LATENESS, STR_TIMETABLE_RESET_LATENESS_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_AUTOFILL), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_TIMETABLE_AUTOFILL, STR_TIMETABLE_AUTOFILL_TOOLTIP), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_VT_EXPECTED_SELECTION), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_VT_EXPECTED), SetResize(1, 0), SetFill(1, 1), SetDataTip(STR_BLACK_STRING, STR_TIMETABLE_EXPECTED_TOOLTIP), NWidget(WWT_PANEL, COLOUR_GREY), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL, NC_EQUALSIZE), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_VT_SHARED_ORDER_LIST), SetFill(0, 1), SetDataTip(SPR_SHARED_ORDERS_ICON, STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), SetFill(0, 1), EndContainer(), EndContainer(), }; static WindowDesc _timetable_desc( WDP_AUTO, "view_vehicle_timetable", 400, 130, WC_VEHICLE_TIMETABLE, WC_VEHICLE_VIEW, WDF_CONSTRUCTION, _nested_timetable_widgets, lengthof(_nested_timetable_widgets) ); /** * Show the timetable for a given vehicle. * @param v The vehicle to show the timetable for. */ void ShowTimetableWindow(const Vehicle *v) { DeleteWindowById(WC_VEHICLE_DETAILS, v->index, false); DeleteWindowById(WC_VEHICLE_ORDERS, v->index, false); AllocateWindowDescFront(&_timetable_desc, v->index); } openttd-1.5.3/src/base_consist.cpp0000644000000000000000000000405012627373442015653 0ustar rootroot/* $Id: base_consist.cpp 27348 2015-07-30 18:45:29Z frosch $ */ /* * 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 base_consist.cpp Properties for front vehicles/consists. */ #include "stdafx.h" #include "base_consist.h" #include "vehicle_base.h" #include "string_func.h" #include "safeguards.h" BaseConsist::~BaseConsist() { free(this->name); } /** * Copy properties of other BaseConsist. * @param src Source for copying */ void BaseConsist::CopyConsistPropertiesFrom(const BaseConsist *src) { if (this == src) return; free(this->name); this->name = src->name != NULL ? stredup(src->name) : NULL; this->current_order_time = src->current_order_time; this->lateness_counter = src->lateness_counter; this->timetable_start = src->timetable_start; this->service_interval = src->service_interval; this->cur_real_order_index = src->cur_real_order_index; this->cur_implicit_order_index = src->cur_implicit_order_index; if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED); if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE); if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); if (HasBit(src->vehicle_flags, VF_SERVINT_IS_PERCENT) != HasBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT)) { ToggleBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT); } if (HasBit(src->vehicle_flags, VF_SERVINT_IS_CUSTOM)) SetBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM); } openttd-1.5.3/src/tile_type.h0000644000000000000000000001013212627373433014640 0ustar rootroot/* $Id: tile_type.h 27148 2015-02-14 12:53:07Z frosch $ */ /* * 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 tile_type.h Types related to tiles. */ #ifndef TILE_TYPE_H #define TILE_TYPE_H static const uint TILE_SIZE = 16; ///< Tile size in world coordinates. static const uint TILE_UNIT_MASK = TILE_SIZE - 1; ///< For masking in/out the inner-tile world coordinate units. static const uint TILE_PIXELS = 32; ///< Pixel distance between tile columns/rows in #ZOOM_LVL_BASE. static const uint TILE_HEIGHT = 8; ///< Height of a height level in world coordinate AND in pixels in #ZOOM_LVL_BASE. static const uint MAX_BUILDING_PIXELS = 200; ///< Maximum height of a building in pixels in #ZOOM_LVL_BASE. (Also applies to "bridge buildings" on the bridge floor.) static const uint MAX_TILE_HEIGHT = 255; ///< Maximum allowed tile height static const uint MIN_MAX_HEIGHTLEVEL = 15; ///< Lower bound of maximum allowed heightlevel (in the construction settings) static const uint DEF_MAX_HEIGHTLEVEL = 30; ///< Default maximum allowed heightlevel (in the construction settings) static const uint MAX_MAX_HEIGHTLEVEL = MAX_TILE_HEIGHT; ///< Upper bound of maximum allowed heightlevel (in the construction settings) static const uint MIN_SNOWLINE_HEIGHT = 2; ///< Minimum snowline height static const uint DEF_SNOWLINE_HEIGHT = 15; ///< Default snowline height static const uint MAX_SNOWLINE_HEIGHT = (MAX_TILE_HEIGHT - 2); ///< Maximum allowed snowline height /** * The different types of tiles. * * Each tile belongs to one type, according whatever is build on it. * * @note A railway with a crossing street is marked as MP_ROAD. */ enum TileType { MP_CLEAR, ///< A tile without any structures, i.e. grass, rocks, farm fields etc. MP_RAILWAY, ///< A railway MP_ROAD, ///< A tile with road (or tram tracks) MP_HOUSE, ///< A house by a town MP_TREES, ///< Tile got trees MP_STATION, ///< A tile of a station MP_WATER, ///< Water tile MP_VOID, ///< Invisible tiles at the SW and SE border MP_INDUSTRY, ///< Part of an industry MP_TUNNELBRIDGE, ///< Tunnel entry/exit and bridge heads MP_OBJECT, ///< Contains objects such as transmitters and owned land }; /** * Additional infos of a tile on a tropic game. * * The tropiczone is not modified during gameplay. It mainly affects tree growth. (desert tiles are visible though) * * In randomly generated maps: * TROPICZONE_DESERT: Generated everywhere, if there is neither water nor mountains (TileHeight >= 4) in a certain distance from the tile. * TROPICZONE_RAINFOREST: Generated everywhere, if there is no desert in a certain distance from the tile. * TROPICZONE_NORMAL: Everywhere else, i.e. between desert and rainforest and on sea (if you clear the water). * * In scenarios: * TROPICZONE_NORMAL: Default value. * TROPICZONE_DESERT: Placed manually. * TROPICZONE_RAINFOREST: Placed if you plant certain rainforest-trees. */ enum TropicZone { TROPICZONE_NORMAL = 0, ///< Normal tropiczone TROPICZONE_DESERT = 1, ///< Tile is desert TROPICZONE_RAINFOREST = 2, ///< Rainforest tile }; /** * The index/ID of a Tile. */ typedef uint32 TileIndex; /** * The very nice invalid tile marker */ static const TileIndex INVALID_TILE = (TileIndex)-1; #endif /* TILE_TYPE_H */ openttd-1.5.3/src/subsidy_gui.cpp0000644000000000000000000001610612627373442015532 0ustar rootroot/* $Id: subsidy_gui.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 subsidy_gui.cpp GUI for subsidies. */ #include "stdafx.h" #include "industry.h" #include "town.h" #include "window_gui.h" #include "strings_func.h" #include "date_func.h" #include "viewport_func.h" #include "gui.h" #include "subsidy_func.h" #include "subsidy_base.h" #include "core/geometry_func.hpp" #include "widgets/subsidy_widget.h" #include "table/strings.h" #include "safeguards.h" struct SubsidyListWindow : Window { Scrollbar *vscroll; SubsidyListWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_SUL_SCROLLBAR); this->FinishInitNested(window_number); this->OnInvalidateData(0); } virtual void OnClick(Point pt, int widget, int click_count) { if (widget != WID_SUL_PANEL) return; int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SUL_PANEL, WD_FRAMERECT_TOP); int num = 0; const Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (!s->IsAwarded()) { y--; if (y == 0) { this->HandleClick(s); return; } num++; } } if (num == 0) { y--; // "None" if (y < 0) return; } y -= 2; // "Services already subsidised:" if (y < 0) return; FOR_ALL_SUBSIDIES(s) { if (s->IsAwarded()) { y--; if (y == 0) { this->HandleClick(s); return; } } } } void HandleClick(const Subsidy *s) { /* determine src coordinate for subsidy and try to scroll to it */ TileIndex xy; switch (s->src_type) { case ST_INDUSTRY: xy = Industry::Get(s->src)->location.tile; break; case ST_TOWN: xy = Town::Get(s->src)->xy; break; default: NOT_REACHED(); } if (_ctrl_pressed || !ScrollMainWindowToTile(xy)) { if (_ctrl_pressed) ShowExtraViewPortWindow(xy); /* otherwise determine dst coordinate for subsidy and scroll to it */ switch (s->dst_type) { case ST_INDUSTRY: xy = Industry::Get(s->dst)->location.tile; break; case ST_TOWN: xy = Town::Get(s->dst)->xy; break; default: NOT_REACHED(); } if (_ctrl_pressed) { ShowExtraViewPortWindow(xy); } else { ScrollMainWindowToTile(xy); } } } /** * Count the number of lines in this window. * @return the number of lines */ uint CountLines() { /* Count number of (non) awarded subsidies */ uint num_awarded = 0; uint num_not_awarded = 0; const Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (!s->IsAwarded()) { num_not_awarded++; } else { num_awarded++; } } /* Count the 'none' lines */ if (num_awarded == 0) num_awarded = 1; if (num_not_awarded == 0) num_not_awarded = 1; /* Offered, accepted and an empty line before the accepted ones. */ return 3 + num_awarded + num_not_awarded; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != WID_SUL_PANEL) return; Dimension d = maxdim(GetStringBoundingBox(STR_SUBSIDIES_OFFERED_TITLE), GetStringBoundingBox(STR_SUBSIDIES_SUBSIDISED_TITLE)); resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_RIGHT + WD_FRAMERECT_LEFT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_SUL_PANEL) return; YearMonthDay ymd; ConvertDateToYMD(_date, &ymd); int right = r.right - WD_FRAMERECT_RIGHT; int y = r.top + WD_FRAMERECT_TOP; int x = r.left + WD_FRAMERECT_LEFT; int pos = -this->vscroll->GetPosition(); const int cap = this->vscroll->GetCapacity(); /* Section for drawing the offered subsidies */ if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_OFFERED_TITLE); pos++; uint num = 0; const Subsidy *s; FOR_ALL_SUBSIDIES(s) { if (!s->IsAwarded()) { if (IsInsideMM(pos, 0, cap)) { /* Displays the two offered towns */ SetupSubsidyDecodeParam(s, true); SetDParam(7, _date - ymd.day + s->remaining * 32); DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_OFFERED_FROM_TO); } pos++; num++; } } if (num == 0) { if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_NONE); pos++; } /* Section for drawing the already granted subsidies */ pos++; if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_SUBSIDISED_TITLE); pos++; num = 0; FOR_ALL_SUBSIDIES(s) { if (s->IsAwarded()) { if (IsInsideMM(pos, 0, cap)) { SetupSubsidyDecodeParam(s, true); SetDParam(7, s->awarded); SetDParam(8, _date - ymd.day + s->remaining * 32); /* Displays the two connected stations */ DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_SUBSIDISED_FROM_TO); } pos++; num++; } } if (num == 0) { if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_SUBSIDIES_NONE); pos++; } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_SUL_PANEL); } /** * 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->vscroll->SetCount(this->CountLines()); } }; static const NWidgetPart _nested_subsidies_list_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_SUBSIDIES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_SUL_PANEL), SetDataTip(0x0, STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetResize(1, 1), SetScrollbar(WID_SUL_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SUL_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), }; static WindowDesc _subsidies_list_desc( WDP_AUTO, "list_subsidies", 500, 127, WC_SUBSIDIES_LIST, WC_NONE, 0, _nested_subsidies_list_widgets, lengthof(_nested_subsidies_list_widgets) ); void ShowSubsidiesList() { AllocateWindowDescFront(&_subsidies_list_desc, 0); } openttd-1.5.3/src/timetable.h0000644000000000000000000000173212627373445014621 0ustar rootroot/* $Id: timetable.h 18809 2010-01-15 16:41:15Z rubidium $ */ /* * 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 timetable.h Functions related to time tabling. */ #ifndef TIMETABLE_H #define TIMETABLE_H #include "date_type.h" #include "vehicle_type.h" void ShowTimetableWindow(const Vehicle *v); void UpdateVehicleTimetable(Vehicle *v, bool travelling); void SetTimetableParams(int param1, int param2, Ticks ticks); #endif /* TIMETABLE_H */ openttd-1.5.3/src/animated_tile_func.h0000644000000000000000000000170212627373441016456 0ustar rootroot/* $Id: animated_tile_func.h 23704 2012-01-01 17:22:32Z alberth $ */ /* * 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 animated_tile_func.h %Tile animation! */ #ifndef ANIMATED_TILE_FUNC_H #define ANIMATED_TILE_FUNC_H #include "tile_type.h" void AddAnimatedTile(TileIndex tile); void DeleteAnimatedTile(TileIndex tile); void AnimateAnimatedTiles(); void InitializeAnimatedTiles(); #endif /* ANIMATED_TILE_FUNC_H */ openttd-1.5.3/src/road_func.h0000644000000000000000000001170612627373435014614 0ustar rootroot/* $Id: road_func.h 26105 2013-11-25 13:16:06Z rubidium $ */ /* * 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 road_func.h Functions related to roads. */ #ifndef ROAD_FUNC_H #define ROAD_FUNC_H #include "core/bitmath_func.hpp" #include "road_type.h" #include "economy_func.h" /** * Iterate through each set RoadType in a RoadTypes value. * For more informations see FOR_EACH_SET_BIT_EX. * * @param var Loop index variable that stores fallowing set road type. Must be of type RoadType. * @param road_types The value to iterate through (any expression). * * @see FOR_EACH_SET_BIT_EX */ #define FOR_EACH_SET_ROADTYPE(var, road_types) FOR_EACH_SET_BIT_EX(RoadType, var, RoadTypes, road_types) /** * Whether the given roadtype is valid. * @param rt the roadtype to check for validness * @return true if and only if valid */ static inline bool IsValidRoadType(RoadType rt) { return rt == ROADTYPE_ROAD || rt == ROADTYPE_TRAM; } /** * Whether the given roadtype is valid. * @param rt the roadtype to check for validness * @return true if and only if valid */ static inline bool IsValidRoadBits(RoadBits r) { return r < ROAD_END; } /** * Maps a RoadType to the corresponding RoadTypes value * * @param rt the roadtype to get the roadtypes from * @return the roadtypes with the given roadtype */ static inline RoadTypes RoadTypeToRoadTypes(RoadType rt) { assert(IsValidRoadType(rt)); return (RoadTypes)(1 << rt); } /** * Returns the RoadTypes which are not present in the given RoadTypes * * This function returns the complement of a given RoadTypes. * * @param r The given RoadTypes * @return The complement of the given RoadTypes */ static inline RoadTypes ComplementRoadTypes(RoadTypes r) { return (RoadTypes)(ROADTYPES_ALL ^ r); } /** * Calculate the complement of a RoadBits value * * Simply flips all bits in the RoadBits value to get the complement * of the RoadBits. * * @param r The given RoadBits value * @return the complement */ static inline RoadBits ComplementRoadBits(RoadBits r) { assert(IsValidRoadBits(r)); return (RoadBits)(ROAD_ALL ^ r); } /** * Calculate the mirrored RoadBits * * Simply move the bits to their new position. * * @param r The given RoadBits value * @return the mirrored */ static inline RoadBits MirrorRoadBits(RoadBits r) { assert(IsValidRoadBits(r)); return (RoadBits)(GB(r, 0, 2) << 2 | GB(r, 2, 2)); } /** * Calculate rotated RoadBits * * Move the Roadbits clockwise until they are in their final position. * * @param r The given RoadBits value * @param rot The given Rotation angle * @return the rotated */ static inline RoadBits RotateRoadBits(RoadBits r, DiagDirDiff rot) { assert(IsValidRoadBits(r)); for (; rot > (DiagDirDiff)0; rot--) { r = (RoadBits)(GB(r, 0, 1) << 3 | GB(r, 1, 3)); } return r; } /** * Check if we've got a straight road * * @param r The given RoadBits * @return true if we've got a straight road */ static inline bool IsStraightRoad(RoadBits r) { assert(IsValidRoadBits(r)); return (r == ROAD_X || r == ROAD_Y); } /** * Create the road-part which belongs to the given DiagDirection * * This function returns a RoadBits value which belongs to * the given DiagDirection. * * @param d The DiagDirection * @return The result RoadBits which the selected road-part set */ static inline RoadBits DiagDirToRoadBits(DiagDirection d) { assert(IsValidDiagDirection(d)); return (RoadBits)(ROAD_NW << (3 ^ d)); } /** * Create the road-part which belongs to the given Axis * * This function returns a RoadBits value which belongs to * the given Axis. * * @param a The Axis * @return The result RoadBits which the selected road-part set */ static inline RoadBits AxisToRoadBits(Axis a) { assert(IsValidAxis(a)); return a == AXIS_X ? ROAD_X : ROAD_Y; } /** * Calculates the maintenance cost of a number of road bits. * @param roadtype Road type to get the cost for. * @param num Number of road bits. * @return Total cost. */ static inline Money RoadMaintenanceCost(RoadType roadtype, uint32 num) { assert(IsValidRoadType(roadtype)); return (_price[PR_INFRASTRUCTURE_ROAD] * (roadtype == ROADTYPE_TRAM ? 3 : 2) * num * (1 + IntSqrt(num))) >> 9; // 2 bits fraction for the multiplier and 7 bits scaling. } bool HasRoadTypesAvail(const CompanyID company, const RoadTypes rts); bool ValParamRoadType(const RoadType rt); RoadTypes GetCompanyRoadtypes(const CompanyID company); void UpdateLevelCrossing(TileIndex tile, bool sound = true); #endif /* ROAD_FUNC_H */ openttd-1.5.3/src/void_cmd.cpp0000644000000000000000000000515612627373441014772 0ustar rootroot/* $Id: void_cmd.cpp 26870 2014-09-21 08:19:32Z rubidium $ */ /* * 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 void_cmd.cpp Handling of void tiles. */ #include "stdafx.h" #include "tile_cmd.h" #include "command_func.h" #include "viewport_func.h" #include "slope_func.h" #include "table/strings.h" #include "table/sprites.h" #include "safeguards.h" static void DrawTile_Void(TileInfo *ti) { DrawGroundSprite(SPR_FLAT_BARE_LAND + SlopeToSpriteOffset(ti->tileh), PALETTE_ALL_BLACK); } static int GetSlopePixelZ_Void(TileIndex tile, uint x, uint y) { return TilePixelHeight(tile); } static Foundation GetFoundation_Void(TileIndex tile, Slope tileh) { return FOUNDATION_NONE; } static CommandCost ClearTile_Void(TileIndex tile, DoCommandFlag flags) { return_cmd_error(STR_ERROR_OFF_EDGE_OF_MAP); } static void GetTileDesc_Void(TileIndex tile, TileDesc *td) { td->str = STR_EMPTY; td->owner[0] = OWNER_NONE; } static void TileLoop_Void(TileIndex tile) { /* not used */ } static void ChangeTileOwner_Void(TileIndex tile, Owner old_owner, Owner new_owner) { /* not used */ } static TrackStatus GetTileTrackStatus_Void(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { return 0; } static CommandCost TerraformTile_Void(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { return_cmd_error(STR_ERROR_OFF_EDGE_OF_MAP); } extern const TileTypeProcs _tile_type_void_procs = { DrawTile_Void, // draw_tile_proc GetSlopePixelZ_Void, // get_slope_z_proc ClearTile_Void, // clear_tile_proc NULL, // add_accepted_cargo_proc GetTileDesc_Void, // get_tile_desc_proc GetTileTrackStatus_Void, // get_tile_track_status_proc NULL, // click_tile_proc NULL, // animate_tile_proc TileLoop_Void, // tile_loop_proc ChangeTileOwner_Void, // change_tile_owner_proc NULL, // add_produced_cargo_proc NULL, // vehicle_enter_tile_proc GetFoundation_Void, // get_foundation_proc TerraformTile_Void, // terraform_tile_proc }; openttd-1.5.3/src/newgrf_storage.h0000644000000000000000000001637312627373434015674 0ustar rootroot/* $Id: newgrf_storage.h 26371 2014-02-23 22:03:08Z frosch $ */ /* * 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 newgrf_storage.h Functionality related to the temporary and persistent storage arrays for NewGRFs. */ #ifndef NEWGRF_STORAGE_H #define NEWGRF_STORAGE_H #include "core/pool_type.hpp" #include "tile_type.h" /** * Mode switches to the behaviour of persistent storage array. */ enum PersistentStorageMode { PSM_ENTER_GAMELOOP, ///< Enter the gameloop, changes will be permanent. PSM_LEAVE_GAMELOOP, ///< Leave the gameloop, changes will be temporary. PSM_ENTER_COMMAND, ///< Enter command scope, changes will be permanent. PSM_LEAVE_COMMAND, ///< Leave command scope, revert to previous mode. PSM_ENTER_TESTMODE, ///< Enter command test mode, changes will be tempoary. PSM_LEAVE_TESTMODE, ///< Leave command test mode, revert to previous mode. }; /** * Base class for all persistent NewGRF storage arrays. Nothing fancy, only here * so we have a generalised access to the virtual methods. */ struct BasePersistentStorageArray { uint32 grfid; ///< GRFID associated to this persistent storage. A value of zero means "default". byte feature; ///< NOSAVE: Used to identify in the owner of the array in debug output. TileIndex tile; ///< NOSAVE: Used to identify in the owner of the array in debug output. virtual ~BasePersistentStorageArray(); static void SwitchMode(PersistentStorageMode mode, bool ignore_prev_mode = false); protected: /** * Discard temporary changes. */ virtual void ClearChanges() = 0; /** * Check whether currently changes to the storage shall be persistent or * temporary till the next call to ClearChanges(). */ static bool AreChangesPersistent() { return (gameloop || command) && !testmode; } private: static bool gameloop; static bool command; static bool testmode; }; /** * Class for persistent storage of data. * On #ClearChanges that data is either reverted or saved. * @tparam TYPE the type of variable to store. * @tparam SIZE the size of the array. */ template struct PersistentStorageArray : BasePersistentStorageArray { TYPE storage[SIZE]; ///< Memory to for the storage array TYPE *prev_storage; ///< Memory to store "old" states so we can revert them on the performance of test cases for commands etc. /** Simply construct the array */ PersistentStorageArray() : prev_storage(NULL) { memset(this->storage, 0, sizeof(this->storage)); } /** And free all data related to it */ ~PersistentStorageArray() { free(this->prev_storage); } /** Resets all values to zero. */ void ResetToZero() { memset(this->storage, 0, sizeof(this->storage)); } /** * Stores some value at a given position. * If there is no backup of the data that backup is made and then * we write the data. * @param pos the position to write at * @param value the value to write */ void StoreValue(uint pos, int32 value) { /* Out of the scope of the array */ if (pos >= SIZE) return; /* The value hasn't changed, so we pretend nothing happened. * Saves a few cycles and such and it's pretty easy to check. */ if (this->storage[pos] == value) return; /* We do not have made a backup; lets do so */ if (AreChangesPersistent()) { assert(this->prev_storage == NULL); } else if (this->prev_storage == NULL) { this->prev_storage = MallocT(SIZE); memcpy(this->prev_storage, this->storage, sizeof(this->storage)); /* We only need to register ourselves when we made the backup * as that is the only time something will have changed */ AddChangedPersistentStorage(this); } this->storage[pos] = value; } /** * Gets the value from a given position. * @param pos the position to get the data from * @return the data from that position */ TYPE GetValue(uint pos) const { /* Out of the scope of the array */ if (pos >= SIZE) return 0; return this->storage[pos]; } void ClearChanges() { if (this->prev_storage != NULL) { memcpy(this->storage, this->prev_storage, sizeof(this->storage)); free(this->prev_storage); this->prev_storage = NULL; } } }; /** * Class for temporary storage of data. * On #ClearChanges that data is always zero-ed. * @tparam TYPE the type of variable to store. * @tparam SIZE the size of the array. */ template struct TemporaryStorageArray { TYPE storage[SIZE]; ///< Memory to for the storage array uint16 init[SIZE]; ///< Storage has been assigned, if this equals 'init_key'. uint16 init_key; ///< Magic key to 'init'. /** Simply construct the array */ TemporaryStorageArray() { memset(this->storage, 0, sizeof(this->storage)); // not exactly needed, but makes code analysers happy memset(this->init, 0, sizeof(this->init)); this->init_key = 1; } /** * Stores some value at a given position. * @param pos the position to write at * @param value the value to write */ void StoreValue(uint pos, int32 value) { /* Out of the scope of the array */ if (pos >= SIZE) return; this->storage[pos] = value; this->init[pos] = this->init_key; } /** * Gets the value from a given position. * @param pos the position to get the data from * @return the data from that position */ TYPE GetValue(uint pos) const { /* Out of the scope of the array */ if (pos >= SIZE) return 0; if (this->init[pos] != this->init_key) { /* Unassigned since last call to ClearChanges */ return 0; } return this->storage[pos]; } void ClearChanges() { /* Increment init_key to invalidate all storage */ this->init_key++; if (this->init_key == 0) { /* When init_key wraps around, we need to reset everything */ memset(this->init, 0, sizeof(this->init)); this->init_key = 1; } } }; void AddChangedPersistentStorage(BasePersistentStorageArray *storage); typedef PersistentStorageArray OldPersistentStorage; typedef uint32 PersistentStorageID; struct PersistentStorage; typedef Pool PersistentStoragePool; extern PersistentStoragePool _persistent_storage_pool; /** * Class for pooled persistent storage of data. */ struct PersistentStorage : PersistentStorageArray, PersistentStoragePool::PoolItem<&_persistent_storage_pool> { /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ PersistentStorage(const uint32 new_grfid, byte feature, TileIndex tile) { this->grfid = new_grfid; this->feature = feature; this->tile = tile; } }; assert_compile(cpp_lengthof(OldPersistentStorage, storage) == cpp_lengthof(PersistentStorage, storage)); #define FOR_ALL_STORAGES_FROM(var, start) FOR_ALL_ITEMS_FROM(PersistentStorage, storage_index, var, start) #define FOR_ALL_STORAGES(var) FOR_ALL_STORAGES_FROM(var, 0) #endif /* NEWGRF_STORAGE_H */ openttd-1.5.3/src/track_type.h0000644000000000000000000001625512627373442015023 0ustar rootroot/* $Id: track_type.h 23595 2011-12-19 17:48:04Z rubidium $ */ /* * 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 track_type.h All types related to tracks */ #ifndef TRACK_TYPE_H #define TRACK_TYPE_H #include "core/enum_type.hpp" /** * These are used to specify a single track. * Can be translated to a trackbit with TrackToTrackbit */ enum Track { TRACK_BEGIN = 0, ///< Used for iterations TRACK_X = 0, ///< Track along the x-axis (north-east to south-west) TRACK_Y = 1, ///< Track along the y-axis (north-west to south-east) TRACK_UPPER = 2, ///< Track in the upper corner of the tile (north) TRACK_LOWER = 3, ///< Track in the lower corner of the tile (south) TRACK_LEFT = 4, ///< Track in the left corner of the tile (west) TRACK_RIGHT = 5, ///< Track in the right corner of the tile (east) TRACK_END, ///< Used for iterations INVALID_TRACK = 0xFF, ///< Flag for an invalid track }; /** Allow incrementing of Track variables */ DECLARE_POSTFIX_INCREMENT(Track) /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT TrackByte; /** Bitfield corresponding to Track */ enum TrackBits { TRACK_BIT_NONE = 0U, ///< No track TRACK_BIT_X = 1U << TRACK_X, ///< X-axis track TRACK_BIT_Y = 1U << TRACK_Y, ///< Y-axis track TRACK_BIT_UPPER = 1U << TRACK_UPPER, ///< Upper track TRACK_BIT_LOWER = 1U << TRACK_LOWER, ///< Lower track TRACK_BIT_LEFT = 1U << TRACK_LEFT, ///< Left track TRACK_BIT_RIGHT = 1U << TRACK_RIGHT, ///< Right track TRACK_BIT_CROSS = TRACK_BIT_X | TRACK_BIT_Y, ///< X-Y-axis cross TRACK_BIT_HORZ = TRACK_BIT_UPPER | TRACK_BIT_LOWER, ///< Upper and lower track TRACK_BIT_VERT = TRACK_BIT_LEFT | TRACK_BIT_RIGHT, ///< Left and right track TRACK_BIT_3WAY_NE = TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,///< "Arrow" to the north-east TRACK_BIT_3WAY_SE = TRACK_BIT_Y | TRACK_BIT_LOWER | TRACK_BIT_RIGHT,///< "Arrow" to the south-east TRACK_BIT_3WAY_SW = TRACK_BIT_X | TRACK_BIT_LOWER | TRACK_BIT_LEFT, ///< "Arrow" to the south-west TRACK_BIT_3WAY_NW = TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_LEFT, ///< "Arrow" to the north-west TRACK_BIT_ALL = TRACK_BIT_CROSS | TRACK_BIT_HORZ | TRACK_BIT_VERT, ///< All possible tracks TRACK_BIT_MASK = 0x3FU, ///< Bitmask for the first 6 bits TRACK_BIT_WORMHOLE = 0x40U, ///< Bitflag for a wormhole (used for tunnels) TRACK_BIT_DEPOT = 0x80U, ///< Bitflag for a depot INVALID_TRACK_BIT = 0xFF, ///< Flag for an invalid trackbits value }; DECLARE_ENUM_AS_BIT_SET(TrackBits) typedef SimpleTinyEnumT TrackBitsByte; /** * Enumeration for tracks and directions. * * These are a combination of tracks and directions. Values are 0-5 in one * direction (corresponding to the Track enum) and 8-13 in the other direction. * 6, 7, 14 and 15 are used to encode the reversing of road vehicles. Those * reversing track dirs are not considered to be 'valid' except in a small * corner in the road vehicle controller. */ enum Trackdir { TRACKDIR_BEGIN = 0, ///< Used for iterations TRACKDIR_X_NE = 0, ///< X-axis and direction to north-east TRACKDIR_Y_SE = 1, ///< Y-axis and direction to south-east TRACKDIR_UPPER_E = 2, ///< Upper track and direction to east TRACKDIR_LOWER_E = 3, ///< Lower track and direction to east TRACKDIR_LEFT_S = 4, ///< Left track and direction to south TRACKDIR_RIGHT_S = 5, ///< Right track and direction to south TRACKDIR_RVREV_NE = 6, ///< (Road vehicle) reverse direction north-east TRACKDIR_RVREV_SE = 7, ///< (Road vehicle) reverse direction south-east TRACKDIR_X_SW = 8, ///< X-axis and direction to south-west TRACKDIR_Y_NW = 9, ///< Y-axis and direction to north-west TRACKDIR_UPPER_W = 10, ///< Upper track and direction to west TRACKDIR_LOWER_W = 11, ///< Lower track and direction to west TRACKDIR_LEFT_N = 12, ///< Left track and direction to north TRACKDIR_RIGHT_N = 13, ///< Right track and direction to north TRACKDIR_RVREV_SW = 14, ///< (Road vehicle) reverse direction south-west TRACKDIR_RVREV_NW = 15, ///< (Road vehicle) reverse direction north-west TRACKDIR_END, ///< Used for iterations INVALID_TRACKDIR = 0xFF, ///< Flag for an invalid trackdir }; /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT TrackdirByte; /** * Enumeration of bitmasks for the TrackDirs * * These are a combination of tracks and directions. Values are 0-5 in one * direction (corresponding to the Track enum) and 8-13 in the other direction. */ enum TrackdirBits { TRACKDIR_BIT_NONE = 0x0000, ///< No track build TRACKDIR_BIT_X_NE = 0x0001, ///< Track x-axis, direction north-east TRACKDIR_BIT_Y_SE = 0x0002, ///< Track y-axis, direction south-east TRACKDIR_BIT_UPPER_E = 0x0004, ///< Track upper, direction east TRACKDIR_BIT_LOWER_E = 0x0008, ///< Track lower, direction east TRACKDIR_BIT_LEFT_S = 0x0010, ///< Track left, direction south TRACKDIR_BIT_RIGHT_S = 0x0020, ///< Track right, direction south /* Again, note the two missing values here. This enables trackdir -> track conversion by doing (trackdir & 0xFF) */ TRACKDIR_BIT_X_SW = 0x0100, ///< Track x-axis, direction south-west TRACKDIR_BIT_Y_NW = 0x0200, ///< Track y-axis, direction north-west TRACKDIR_BIT_UPPER_W = 0x0400, ///< Track upper, direction west TRACKDIR_BIT_LOWER_W = 0x0800, ///< Track lower, direction west TRACKDIR_BIT_LEFT_N = 0x1000, ///< Track left, direction north TRACKDIR_BIT_RIGHT_N = 0x2000, ///< Track right, direction north TRACKDIR_BIT_MASK = 0x3F3F, ///< Bitmask for bit-operations INVALID_TRACKDIR_BIT = 0xFFFF, ///< Flag for an invalid trackdirbit value }; DECLARE_ENUM_AS_BIT_SET(TrackdirBits) typedef SimpleTinyEnumT TrackdirBitsShort; typedef uint32 TrackStatus; #endif /* TRACK_TYPE_H */ openttd-1.5.3/src/newgrf_house.cpp0000644000000000000000000006476312627373435015715 0ustar rootroot/* $Id: newgrf_house.cpp 26580 2014-05-11 18:02:11Z rubidium $ */ /* * 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 newgrf_house.cpp Implementation of NewGRF houses. */ #include "stdafx.h" #include "debug.h" #include "landscape.h" #include "newgrf_house.h" #include "newgrf_spritegroup.h" #include "newgrf_town.h" #include "newgrf_sound.h" #include "company_func.h" #include "company_base.h" #include "town.h" #include "genworld.h" #include "newgrf_animation_base.h" #include "newgrf_cargo.h" #include "station_base.h" #include "safeguards.h" static BuildingCounts _building_counts; static HouseClassMapping _class_mapping[HOUSE_CLASS_MAX]; HouseOverrideManager _house_mngr(NEW_HOUSE_OFFSET, NUM_HOUSES, INVALID_HOUSE_ID); /** * Constructor of a house scope resolver. * @param ro Surrounding resolver. * @param house_id House type being queried. * @param tile %Tile containing the house. * @param town %Town containing the house. * @param not_yet_constructed House is still under construction. * @param initial_random_bits Random bits during construction checks. * @param watched_cargo_triggers Cargo types that triggered the watched cargo callback. */ HouseScopeResolver::HouseScopeResolver(ResolverObject &ro, HouseID house_id, TileIndex tile, Town *town, bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers) : ScopeResolver(ro) { this->house_id = house_id; this->tile = tile; this->town = town; this->not_yet_constructed = not_yet_constructed; this->initial_random_bits = initial_random_bits; this->watched_cargo_triggers = watched_cargo_triggers; } /** * Retrieve the grf file associated with a house. * @param house_id House to query. * @return The associated GRF file (may be \c NULL). */ static const GRFFile *GetHouseSpecGrf(HouseID house_id) { const HouseSpec *hs = HouseSpec::Get(house_id); return (hs != NULL) ? hs->grf_prop.grffile : NULL; } /** * Construct a resolver for a house. * @param house_id House to query. * @param tile %Tile containing the house. * @param town %Town containing the house. * @param callback Callback ID. * @param param1 First parameter (var 10) of the callback. * @param param2 Second parameter (var 18) of the callback. * @param not_yet_constructed House is still under construction. * @param initial_random_bits Random bits during construction checks. * @param watched_cargo_triggers Cargo types that triggered the watched cargo callback. */ HouseResolverObject::HouseResolverObject(HouseID house_id, TileIndex tile, Town *town, CallbackID callback, uint32 param1, uint32 param2, bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers) : ResolverObject(GetHouseSpecGrf(house_id), callback, param1, param2), house_scope(*this, house_id, tile, town, not_yet_constructed, initial_random_bits, watched_cargo_triggers), town_scope(*this, town, not_yet_constructed) // Don't access StorePSA if house is not yet constructed. { this->root_spritegroup = HouseSpec::Get(house_id)->grf_prop.spritegroup[0]; } HouseClassID AllocateHouseClassID(byte grf_class_id, uint32 grfid) { /* Start from 1 because 0 means that no class has been assigned. */ for (int i = 1; i != lengthof(_class_mapping); i++) { HouseClassMapping *map = &_class_mapping[i]; if (map->class_id == grf_class_id && map->grfid == grfid) return (HouseClassID)i; if (map->class_id == 0 && map->grfid == 0) { map->class_id = grf_class_id; map->grfid = grfid; return (HouseClassID)i; } } return HOUSE_NO_CLASS; } void InitializeBuildingCounts() { memset(&_building_counts, 0, sizeof(_building_counts)); Town *t; FOR_ALL_TOWNS(t) { memset(&t->cache.building_counts, 0, sizeof(t->cache.building_counts)); } } /** * IncreaseBuildingCount() * Increase the count of a building when it has been added by a town. * @param t The town that the building is being built in * @param house_id The id of the house being added */ void IncreaseBuildingCount(Town *t, HouseID house_id) { HouseClassID class_id = HouseSpec::Get(house_id)->class_id; if (!_loaded_newgrf_features.has_newhouses) return; t->cache.building_counts.id_count[house_id]++; _building_counts.id_count[house_id]++; if (class_id == HOUSE_NO_CLASS) return; t->cache.building_counts.class_count[class_id]++; _building_counts.class_count[class_id]++; } /** * DecreaseBuildingCount() * Decrease the number of a building when it is deleted. * @param t The town that the building was built in * @param house_id The id of the house being removed */ void DecreaseBuildingCount(Town *t, HouseID house_id) { HouseClassID class_id = HouseSpec::Get(house_id)->class_id; if (!_loaded_newgrf_features.has_newhouses) return; if (t->cache.building_counts.id_count[house_id] > 0) t->cache.building_counts.id_count[house_id]--; if (_building_counts.id_count[house_id] > 0) _building_counts.id_count[house_id]--; if (class_id == HOUSE_NO_CLASS) return; if (t->cache.building_counts.class_count[class_id] > 0) t->cache.building_counts.class_count[class_id]--; if (_building_counts.class_count[class_id] > 0) _building_counts.class_count[class_id]--; } /* virtual */ uint32 HouseScopeResolver::GetRandomBits() const { /* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */ assert(IsValidTile(this->tile) && (this->not_yet_constructed || IsTileType(this->tile, MP_HOUSE))); return this->not_yet_constructed ? this->initial_random_bits : GetHouseRandomBits(this->tile); } /* virtual */ uint32 HouseScopeResolver::GetTriggers() const { /* Note: Towns build houses over houses. So during construction checks 'tile' may be a valid but unrelated house. */ assert(IsValidTile(this->tile) && (this->not_yet_constructed || IsTileType(this->tile, MP_HOUSE))); return this->not_yet_constructed ? 0 : GetHouseTriggers(this->tile); } /* virtual */ void HouseScopeResolver::SetTriggers(int triggers) const { assert(!this->not_yet_constructed && IsValidTile(this->tile) && IsTileType(this->tile, MP_HOUSE)); SetHouseTriggers(this->tile, triggers); } static uint32 GetNumHouses(HouseID house_id, const Town *town) { uint8 map_id_count, town_id_count, map_class_count, town_class_count; HouseClassID class_id = HouseSpec::Get(house_id)->class_id; map_id_count = ClampU(_building_counts.id_count[house_id], 0, 255); map_class_count = ClampU(_building_counts.class_count[class_id], 0, 255); town_id_count = ClampU(town->cache.building_counts.id_count[house_id], 0, 255); town_class_count = ClampU(town->cache.building_counts.class_count[class_id], 0, 255); return map_class_count << 24 | town_class_count << 16 | map_id_count << 8 | town_id_count; } /** * Get information about a nearby tile. * @param parameter from callback. It's in fact a pair of coordinates * @param tile TileIndex from which the callback was initiated * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8. * @return a construction of bits obeying the newgrf format */ static uint32 GetNearbyTileInformation(byte parameter, TileIndex tile, bool grf_version8) { tile = GetNearbyTile(parameter, tile); return GetNearbyTileInformation(tile, grf_version8); } /** Structure with user-data for SearchNearbyHouseXXX - functions */ struct SearchNearbyHouseData { const HouseSpec *hs; ///< Specs of the house that started the search. TileIndex north_tile; ///< Northern tile of the house. }; /** * Callback function to search a house by its HouseID * @param tile TileIndex to be examined * @param user_data SearchNearbyHouseData * @return true or false, if found or not */ static bool SearchNearbyHouseID(TileIndex tile, void *user_data) { if (IsTileType(tile, MP_HOUSE)) { HouseID house = GetHouseType(tile); // tile been examined const HouseSpec *hs = HouseSpec::Get(house); if (hs->grf_prop.grffile != NULL) { // must be one from a grf file SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data; TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'! if (north_tile == nbhd->north_tile) return false; // Always ignore origin house return hs->grf_prop.local_id == nbhd->hs->grf_prop.local_id && // same local id as the one requested hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid; // from the same grf } } return false; } /** * Callback function to search a house by its classID * @param tile TileIndex to be examined * @param user_data SearchNearbyHouseData * @return true or false, if found or not */ static bool SearchNearbyHouseClass(TileIndex tile, void *user_data) { if (IsTileType(tile, MP_HOUSE)) { HouseID house = GetHouseType(tile); // tile been examined const HouseSpec *hs = HouseSpec::Get(house); if (hs->grf_prop.grffile != NULL) { // must be one from a grf file SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data; TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'! if (north_tile == nbhd->north_tile) return false; // Always ignore origin house return hs->class_id == nbhd->hs->class_id && // same classid as the one requested hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid; // from the same grf } } return false; } /** * Callback function to search a house by its grfID * @param tile TileIndex to be examined * @param user_data SearchNearbyHouseData * @return true or false, if found or not */ static bool SearchNearbyHouseGRFID(TileIndex tile, void *user_data) { if (IsTileType(tile, MP_HOUSE)) { HouseID house = GetHouseType(tile); // tile been examined const HouseSpec *hs = HouseSpec::Get(house); if (hs->grf_prop.grffile != NULL) { // must be one from a grf file SearchNearbyHouseData *nbhd = (SearchNearbyHouseData *)user_data; TileIndex north_tile = tile + GetHouseNorthPart(house); // modifies 'house'! if (north_tile == nbhd->north_tile) return false; // Always ignore origin house return hs->grf_prop.grffile->grfid == nbhd->hs->grf_prop.grffile->grfid; // from the same grf } } return false; } /** * This function will activate a search around a central tile, looking for some houses * that fit the requested characteristics * @param parameter that is given by the callback. * bits 0..6 radius of the search * bits 7..8 search type i.e.: 0 = houseID/ 1 = classID/ 2 = grfID * @param tile TileIndex from which to start the search * @param house the HouseID that is associated to the house, the callback is called for * @return the Manhattan distance from the center tile, if any, and 0 if failure */ static uint32 GetDistanceFromNearbyHouse(uint8 parameter, TileIndex tile, HouseID house) { static TestTileOnSearchProc * const search_procs[3] = { SearchNearbyHouseID, SearchNearbyHouseClass, SearchNearbyHouseGRFID, }; TileIndex found_tile = tile; uint8 searchtype = GB(parameter, 6, 2); uint8 searchradius = GB(parameter, 0, 6); if (searchtype >= lengthof(search_procs)) return 0; // do not run on ill-defined code if (searchradius < 1) return 0; // do not use a too low radius SearchNearbyHouseData nbhd; nbhd.hs = HouseSpec::Get(house); nbhd.north_tile = tile + GetHouseNorthPart(house); // modifies 'house'! /* Use a pointer for the tile to start the search. Will be required for calculating the distance*/ if (CircularTileSearch(&found_tile, 2 * searchradius + 1, search_procs[searchtype], &nbhd)) { return DistanceManhattan(found_tile, tile); } return 0; } /** * @note Used by the resolver to get values for feature 07 deterministic spritegroups. */ /* virtual */ uint32 HouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { switch (variable) { /* Construction stage. */ case 0x40: return (IsTileType(this->tile, MP_HOUSE) ? GetHouseBuildingStage(this->tile) : 0) | TileHash2Bit(TileX(this->tile), TileY(this->tile)) << 2; /* Building age. */ case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile) : 0; /* Town zone */ case 0x42: return GetTownRadiusGroup(this->town, this->tile); /* Terrain type */ case 0x43: return GetTerrainType(this->tile); /* Number of this type of building on the map. */ case 0x44: return GetNumHouses(this->house_id, this->town); /* Whether the town is being created or just expanded. */ case 0x45: return _generating_world ? 1 : 0; /* Current animation frame. */ case 0x46: return IsTileType(this->tile, MP_HOUSE) ? GetAnimationFrame(this->tile) : 0; /* Position of the house */ case 0x47: return TileY(this->tile) << 16 | TileX(this->tile); /* Building counts for old houses with id = parameter. */ case 0x60: return parameter < NEW_HOUSE_OFFSET ? GetNumHouses(parameter, this->town) : 0; /* Building counts for new houses with id = parameter. */ case 0x61: { const HouseSpec *hs = HouseSpec::Get(this->house_id); if (hs->grf_prop.grffile == NULL) return 0; HouseID new_house = _house_mngr.GetID(parameter, hs->grf_prop.grffile->grfid); return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, this->town); } /* Land info for nearby tiles. */ case 0x62: return GetNearbyTileInformation(parameter, this->tile, this->ro.grffile->grf_version >= 8); /* Current animation frame of nearby house tiles */ case 0x63: { TileIndex testtile = GetNearbyTile(parameter, this->tile); return IsTileType(testtile, MP_HOUSE) ? GetAnimationFrame(testtile) : 0; } /* Cargo acceptance history of nearby stations */ case 0x64: { CargoID cid = GetCargoTranslation(parameter, this->ro.grffile); if (cid == CT_INVALID) return 0; /* Extract tile offset. */ int8 x_offs = GB(GetRegister(0x100), 0, 8); int8 y_offs = GB(GetRegister(0x100), 8, 8); TileIndex testtile = TILE_MASK(this->tile + TileDiffXY(x_offs, y_offs)); StationFinder stations(TileArea(testtile, 1, 1)); const StationList *sl = stations.GetStations(); /* Collect acceptance stats. */ uint32 res = 0; for (Station * const * st_iter = sl->Begin(); st_iter != sl->End(); st_iter++) { const Station *st = *st_iter; if (HasBit(st->goods[cid].status, GoodsEntry::GES_EVER_ACCEPTED)) SetBit(res, 0); if (HasBit(st->goods[cid].status, GoodsEntry::GES_LAST_MONTH)) SetBit(res, 1); if (HasBit(st->goods[cid].status, GoodsEntry::GES_CURRENT_MONTH)) SetBit(res, 2); if (HasBit(st->goods[cid].status, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3); } /* Cargo triggered CB 148? */ if (HasBit(this->watched_cargo_triggers, cid)) SetBit(res, 4); return res; } /* Distance test for some house types */ case 0x65: return GetDistanceFromNearbyHouse(parameter, this->tile, this->house_id); /* Class and ID of nearby house tile */ case 0x66: { TileIndex testtile = GetNearbyTile(parameter, this->tile); if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF; HouseSpec *hs = HouseSpec::Get(GetHouseType(testtile)); /* Information about the grf local classid if the house has a class */ uint houseclass = 0; if (hs->class_id != HOUSE_NO_CLASS) { houseclass = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8; houseclass |= _class_mapping[hs->class_id].class_id; } /* old house type or grf-local houseid */ uint local_houseid = 0; if (this->house_id < NEW_HOUSE_OFFSET) { local_houseid = this->house_id; } else { local_houseid = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8; local_houseid |= hs->grf_prop.local_id; } return houseclass << 16 | local_houseid; } /* GRFID of nearby house tile */ case 0x67: { TileIndex testtile = GetNearbyTile(parameter, this->tile); if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF; HouseID house_id = GetHouseType(testtile); if (house_id < NEW_HOUSE_OFFSET) return 0; /* Checking the grffile information via HouseSpec doesn't work * in case the newgrf was removed. */ return _house_mngr.GetGRFID(house_id); } } DEBUG(grf, 1, "Unhandled house variable 0x%X", variable); *available = false; return UINT_MAX; } uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile, bool not_yet_constructed, uint8 initial_random_bits, uint32 watched_cargo_triggers) { assert(IsValidTile(tile) && (not_yet_constructed || IsTileType(tile, MP_HOUSE))); HouseResolverObject object(house_id, tile, town, callback, param1, param2, not_yet_constructed, initial_random_bits, watched_cargo_triggers); return object.ResolveCallback(); } static void DrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte stage, HouseID house_id) { const DrawTileSprites *dts = group->ProcessRegisters(&stage); const HouseSpec *hs = HouseSpec::Get(house_id); PaletteID palette = hs->random_colour[TileHash2Bit(ti->x, ti->y)] + PALETTE_RECOLOUR_START; if (HasBit(hs->callback_mask, CBM_HOUSE_COLOUR)) { uint16 callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile); if (callback != CALLBACK_FAILED) { /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */ palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback; } } SpriteID image = dts->ground.sprite; PaletteID pal = dts->ground.pal; if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage; if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage; if (GB(image, 0, SPRITE_WIDTH) != 0) { DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette)); } DrawNewGRFTileSeq(ti, dts, TO_HOUSES, stage, palette); } void DrawNewHouseTile(TileInfo *ti, HouseID house_id) { const HouseSpec *hs = HouseSpec::Get(house_id); if (ti->tileh != SLOPE_FLAT) { bool draw_old_one = true; if (HasBit(hs->callback_mask, CBM_HOUSE_DRAW_FOUNDATIONS)) { /* Called to determine the type (if any) of foundation to draw for the house tile */ uint32 callback_res = GetHouseCallback(CBID_HOUSE_DRAW_FOUNDATIONS, 0, 0, house_id, Town::GetByTile(ti->tile), ti->tile); if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DRAW_FOUNDATIONS, callback_res); } if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED); } HouseResolverObject object(house_id, ti->tile, Town::GetByTile(ti->tile)); const SpriteGroup *group = object.Resolve(); if (group != NULL && group->type == SGT_TILELAYOUT) { /* Limit the building stage to the number of stages supplied. */ const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group; byte stage = GetHouseBuildingStage(ti->tile); DrawTileLayout(ti, tlgroup, stage, house_id); } } /* Simple wrapper for GetHouseCallback to keep the animation unified. */ uint16 GetSimpleHouseCallback(CallbackID callback, uint32 param1, uint32 param2, const HouseSpec *spec, Town *town, TileIndex tile, uint32 extra_data) { return GetHouseCallback(callback, param1, param2, spec - HouseSpec::Get(0), town, tile, false, 0, extra_data); } /** Helper class for animation control. */ struct HouseAnimationBase : public AnimationBase { static const CallbackID cb_animation_speed = CBID_HOUSE_ANIMATION_SPEED; static const CallbackID cb_animation_next_frame = CBID_HOUSE_ANIMATION_NEXT_FRAME; static const HouseCallbackMask cbm_animation_speed = CBM_HOUSE_ANIMATION_SPEED; static const HouseCallbackMask cbm_animation_next_frame = CBM_HOUSE_ANIMATION_NEXT_FRAME; }; void AnimateNewHouseTile(TileIndex tile) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); if (hs == NULL) return; HouseAnimationBase::AnimateTile(hs, Town::GetByTile(tile), tile, HasBit(hs->extra_flags, CALLBACK_1A_RANDOM_BITS)); } void AnimateNewHouseConstruction(TileIndex tile) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) { HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, hs, Town::GetByTile(tile), tile, 0, 0); } } bool CanDeleteHouse(TileIndex tile) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); /* Humans are always allowed to remove buildings, as is water and disasters and * anyone using the scenario editor. */ if (Company::IsValidHumanID(_current_company) || _current_company == OWNER_WATER || _current_company == OWNER_NONE || _game_mode == GM_EDITOR || _generating_world) { return true; } if (HasBit(hs->callback_mask, CBM_HOUSE_DENY_DESTRUCTION)) { uint16 callback_res = GetHouseCallback(CBID_HOUSE_DENY_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile); return (callback_res == CALLBACK_FAILED || !ConvertBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DENY_DESTRUCTION, callback_res)); } else { return !(hs->extra_flags & BUILDING_IS_PROTECTED); } } static void AnimationControl(TileIndex tile, uint16 random_bits) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) { uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0); } } bool NewHouseTileLoop(TileIndex tile) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); if (GetHouseProcessingTime(tile) > 0) { DecHouseProcessingTime(tile); return true; } TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP); if (hs->building_flags & BUILDING_HAS_1_TILE) TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP); if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_START_STOP)) { /* If this house is marked as having a synchronised callback, all the * tiles will have the callback called at once, rather than when the * tile loop reaches them. This should only be enabled for the northern * tile, or strange things will happen (here, and in TTDPatch). */ if (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) { uint16 random = GB(Random(), 0, 16); if (hs->building_flags & BUILDING_HAS_1_TILE) AnimationControl(tile, random); if (hs->building_flags & BUILDING_2_TILES_Y) AnimationControl(TILE_ADDXY(tile, 0, 1), random); if (hs->building_flags & BUILDING_2_TILES_X) AnimationControl(TILE_ADDXY(tile, 1, 0), random); if (hs->building_flags & BUILDING_HAS_4_TILES) AnimationControl(TILE_ADDXY(tile, 1, 1), random); } else { AnimationControl(tile, 0); } } /* Check callback 21, which determines if a house should be destroyed. */ if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) { uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED && Convert8bitBooleanCallback(hs->grf_prop.grffile, CBID_HOUSE_DESTRUCTION, callback_res)) { ClearTownHouse(Town::GetByTile(tile), tile); return false; } } SetHouseProcessingTime(tile, hs->processing_time); MarkTileDirtyByTile(tile); return true; } static void DoTriggerHouse(TileIndex tile, HouseTrigger trigger, byte base_random, bool first) { /* We can't trigger a non-existent building... */ assert(IsTileType(tile, MP_HOUSE)); HouseID hid = GetHouseType(tile); HouseSpec *hs = HouseSpec::Get(hid); if (hs->grf_prop.spritegroup[0] == NULL) return; HouseResolverObject object(hid, tile, Town::GetByTile(tile), CBID_RANDOM_TRIGGER); object.trigger = trigger; const SpriteGroup *group = object.Resolve(); if (group == NULL) return; byte new_random_bits = Random(); byte random_bits = GetHouseRandomBits(tile); uint32 reseed = object.GetReseedSum(); // The scope only affects triggers, not the reseeding random_bits &= ~reseed; random_bits |= (first ? new_random_bits : base_random) & reseed; SetHouseRandomBits(tile, random_bits); switch (trigger) { case HOUSE_TRIGGER_TILE_LOOP: /* Random value already set. */ break; case HOUSE_TRIGGER_TILE_LOOP_TOP: if (!first) { /* The top tile is marked dirty by the usual TileLoop */ MarkTileDirtyByTile(tile); break; } /* Random value of first tile already set. */ if (hs->building_flags & BUILDING_2_TILES_Y) DoTriggerHouse(TILE_ADDXY(tile, 0, 1), trigger, random_bits, false); if (hs->building_flags & BUILDING_2_TILES_X) DoTriggerHouse(TILE_ADDXY(tile, 1, 0), trigger, random_bits, false); if (hs->building_flags & BUILDING_HAS_4_TILES) DoTriggerHouse(TILE_ADDXY(tile, 1, 1), trigger, random_bits, false); break; } } void TriggerHouse(TileIndex t, HouseTrigger trigger) { DoTriggerHouse(t, trigger, 0, true); } /** * Run the watched cargo accepted callback for a single house tile. * @param tile The house tile. * @param origin The triggering tile. * @param trigger_cargoes Cargo types that triggered the callback. * @param random Random bits. */ void DoWatchedCargoCallback(TileIndex tile, TileIndex origin, uint32 trigger_cargoes, uint16 random) { TileIndexDiffC diff = TileIndexToTileIndexDiffC(origin, tile); uint32 cb_info = random << 16 | (uint8)diff.y << 8 | (uint8)diff.x; HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_WATCHED_CARGO_ACCEPTED, HouseSpec::Get(GetHouseType(tile)), Town::GetByTile(tile), tile, 0, cb_info, trigger_cargoes); } /** * Run watched cargo accepted callback for a house. * @param tile House tile. * @param trigger_cargoes Triggering cargo types. * @pre IsTileType(t, MP_HOUSE) */ void WatchedCargoCallback(TileIndex tile, uint32 trigger_cargoes) { assert(IsTileType(tile, MP_HOUSE)); HouseID id = GetHouseType(tile); const HouseSpec *hs = HouseSpec::Get(id); trigger_cargoes &= hs->watched_cargoes; /* None of the trigger cargoes is watched? */ if (trigger_cargoes == 0) return; /* Same random value for all tiles of a multi-tile house. */ uint16 r = Random(); /* Do the callback, start at northern tile. */ TileIndex north = tile + GetHouseNorthPart(id); hs = HouseSpec::Get(id); DoWatchedCargoCallback(north, tile, trigger_cargoes, r); if (hs->building_flags & BUILDING_2_TILES_Y) DoWatchedCargoCallback(TILE_ADDXY(north, 0, 1), tile, trigger_cargoes, r); if (hs->building_flags & BUILDING_2_TILES_X) DoWatchedCargoCallback(TILE_ADDXY(north, 1, 0), tile, trigger_cargoes, r); if (hs->building_flags & BUILDING_HAS_4_TILES) DoWatchedCargoCallback(TILE_ADDXY(north, 1, 1), tile, trigger_cargoes, r); } openttd-1.5.3/src/newgrf_storage.cpp0000644000000000000000000000645112627373433016222 0ustar rootroot/* $Id: newgrf_storage.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_storage.cpp Functionality related to the temporary and persistent storage arrays for NewGRFs. */ #include "stdafx.h" #include "newgrf_storage.h" #include "core/pool_func.hpp" #include "core/endian_func.hpp" #include "debug.h" #include #include "safeguards.h" PersistentStoragePool _persistent_storage_pool("PersistentStorage"); INSTANTIATE_POOL_METHODS(PersistentStorage) /** The changed storage arrays */ static std::set *_changed_storage_arrays = new std::set; bool BasePersistentStorageArray::gameloop; bool BasePersistentStorageArray::command; bool BasePersistentStorageArray::testmode; /** * Remove references to use. */ BasePersistentStorageArray::~BasePersistentStorageArray() { _changed_storage_arrays->erase(this); } /** * Add the changed storage array to the list of changed arrays. * This is done so we only have to revert/save the changed * arrays, which saves quite a few clears, etc. after callbacks. * @param storage the array that has changed */ void AddChangedPersistentStorage(BasePersistentStorageArray *storage) { _changed_storage_arrays->insert(storage); } /** * Clear temporary changes made since the last call to SwitchMode, and * set whether subsequent changes shall be persistent or temporary. * * @param mode Mode switch affecting temporary/persistent changes. * @param ignore_prev_mode Disable some sanity checks for exceptional call circumstances. */ /* static */ void BasePersistentStorageArray::SwitchMode(PersistentStorageMode mode, bool ignore_prev_mode) { switch (mode) { case PSM_ENTER_GAMELOOP: assert(ignore_prev_mode || !gameloop); assert(!command && !testmode); gameloop = true; break; case PSM_LEAVE_GAMELOOP: assert(ignore_prev_mode || gameloop); assert(!command && !testmode); gameloop = false; break; case PSM_ENTER_COMMAND: assert((ignore_prev_mode || !command) && !testmode); command = true; break; case PSM_LEAVE_COMMAND: assert(ignore_prev_mode || command); command = false; break; case PSM_ENTER_TESTMODE: assert(!command && (ignore_prev_mode || !testmode)); testmode = true; break; case PSM_LEAVE_TESTMODE: assert(ignore_prev_mode || testmode); testmode = false; break; default: NOT_REACHED(); } /* Discard all temporary changes */ for (std::set::iterator it = _changed_storage_arrays->begin(); it != _changed_storage_arrays->end(); it++) { DEBUG(desync, 1, "Discarding persistent storage changes: Feature %d, GrfID %08X, Tile %d", (*it)->feature, BSWAP32((*it)->grfid), (*it)->tile); (*it)->ClearChanges(); } _changed_storage_arrays->clear(); } openttd-1.5.3/src/toolbar_gui.cpp0000644000000000000000000022061712627373446015522 0ustar rootroot/* $Id: toolbar_gui.cpp 27178 2015-03-07 18:27:01Z frosch $ */ /* * 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 toolbar_gui.cpp Code related to the (main) toolbar. */ #include "stdafx.h" #include "gui.h" #include "window_gui.h" #include "window_func.h" #include "viewport_func.h" #include "command_func.h" #include "vehicle_gui.h" #include "rail_gui.h" #include "road_gui.h" #include "date_func.h" #include "vehicle_func.h" #include "sound_func.h" #include "terraform_gui.h" #include "strings_func.h" #include "company_func.h" #include "company_gui.h" #include "vehicle_base.h" #include "cheat_func.h" #include "transparency_gui.h" #include "screenshot.h" #include "signs_func.h" #include "fios.h" #include "console_gui.h" #include "news_gui.h" #include "ai/ai_gui.hpp" #include "tilehighlight_func.h" #include "smallmap_gui.h" #include "graph_gui.h" #include "textbuf_gui.h" #include "linkgraph/linkgraph_gui.h" #include "newgrf_debug.h" #include "hotkeys.h" #include "engine_base.h" #include "highscore.h" #include "game/game.hpp" #include "goal_base.h" #include "story_base.h" #include "toolbar_gui.h" #include "widgets/toolbar_widget.h" #include "network/network.h" #include "network/network_gui.h" #include "network/network_func.h" #include "safeguards.h" /** Width of the toolbar, shared by statusbar. */ uint _toolbar_width = 0; RailType _last_built_railtype; RoadType _last_built_roadtype; static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm. /** Toobar modes */ enum ToolbarMode { TB_NORMAL, TB_UPPER, TB_LOWER }; /** Callback functions. */ enum CallBackFunction { CBF_NONE, CBF_PLACE_SIGN, CBF_PLACE_LANDINFO, }; /** * Drop down list entry for showing a checked/unchecked toggle item. */ class DropDownListCheckedItem : public DropDownListStringItem { uint checkmark_width; public: bool checked; DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked) { this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3; } virtual ~DropDownListCheckedItem() {} uint Width() const { return DropDownListStringItem::Width() + this->checkmark_width; } void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const { bool rtl = _current_text_dir == TD_RTL; if (this->checked) { DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK); } DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK); } }; /** * Drop down list entry for showing a company entry, with companies 'blob'. */ class DropDownListCompanyItem : public DropDownListItem { Dimension icon_size; public: bool greyed; DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed) { this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); } virtual ~DropDownListCompanyItem() {} bool Selectable() const { return true; } uint Width() const { CompanyID company = (CompanyID)this->result; SetDParam(0, company); SetDParam(1, company); return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3; } uint Height(uint width) const { return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL); } void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const { CompanyID company = (CompanyID)this->result; bool rtl = _current_text_dir == TD_RTL; /* It's possible the company is deleted while the dropdown is open */ if (!Company::IsValidID(company)) return; int icon_offset = (bottom - top - icon_size.height) / 2; int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2; DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset); SetDParam(0, company); SetDParam(1, company); TextColour col; if (this->greyed) { col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE; } else { col = sel ? TC_WHITE : TC_BLACK; } DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col); } }; /** * Pop up a generic text only menu. * @param w Toolbar * @param widget Toolbar button * @param list List of items * @param def Default item */ static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def) { ShowDropDownList(w, list, def, widget, 0, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } /** * Pop up a generic text only menu. * @param w Toolbar * @param widget Toolbar button * @param string String for the first item in the menu * @param count Number of items in the menu */ static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count) { DropDownList *list = new DropDownList(); for (int i = 0; i < count; i++) { *list->Append() = new DropDownListStringItem(string + i, i, false); } PopupMainToolbMenu(w, widget, list, 0); } /** Enum for the Company Toolbar's network related buttons */ static const int CTMN_CLIENT_LIST = -1; ///< Show the client list static const int CTMN_NEW_COMPANY = -2; ///< Create a new company static const int CTMN_SPECTATE = -3; ///< Become spectator static const int CTMN_SPECTATOR = -4; ///< Show a company window as spectator /** * Pop up a generic company list menu. * @param w The toolbar window. * @param widget The button widget id. * @param grey A bitbask of which items to mark as disabled. * @param include_spectator If true, a spectator option is included in the list. */ static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0, bool include_spectator = false) { DropDownList *list = new DropDownList(); #ifdef ENABLE_NETWORK if (_networking) { if (widget == WID_TN_COMPANIES) { /* Add the client list button for the companies menu */ *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false); } if (include_spectator) { if (widget == WID_TN_COMPANIES) { if (_local_company == COMPANY_SPECTATOR) { *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached()); } else { *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached()); } } else { *list->Append() = new DropDownListStringItem(STR_NETWORK_TOOLBAR_LIST_SPECTATOR, CTMN_SPECTATOR, false); } } } #endif /* ENABLE_NETWORK */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { if (!Company::IsValidID(c)) continue; *list->Append() = new DropDownListCompanyItem(c, false, HasBit(grey, c)); } PopupMainToolbMenu(w, widget, list, _local_company == COMPANY_SPECTATOR ? CTMN_CLIENT_LIST : (int)_local_company); } static ToolbarMode _toolbar_mode; static CallBackFunction SelectSignTool() { if (_cursor.sprite == SPR_CURSOR_SIGN) { ResetObjectToPlace(); return CBF_NONE; } else { SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); return CBF_PLACE_SIGN; } } /* --- Pausing --- */ static CallBackFunction ToolbarPauseClick(Window *w) { if (_networking && !_network_server) return CBF_NONE; // only server can pause the game if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) { if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP); } return CBF_NONE; } /** * Toggle fast forward mode. * * @param w Unused. * @return #CBF_NONE */ static CallBackFunction ToolbarFastForwardClick(Window *w) { _fast_forward ^= true; if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } /** * Game Option button menu entries. */ enum OptionMenuEntries { OME_GAMEOPTIONS, OME_SETTINGS, OME_SCRIPT_SETTINGS, OME_NEWGRFSETTINGS, OME_TRANSPARENCIES, OME_SHOW_TOWNNAMES, OME_SHOW_STATIONNAMES, OME_SHOW_WAYPOINTNAMES, OME_SHOW_SIGNS, OME_SHOW_COMPETITOR_SIGNS, OME_FULL_ANIMATION, OME_FULL_DETAILS, OME_TRANSPARENTBUILDINGS, OME_SHOW_STATIONSIGNS, }; /** * Handle click on Options button in toolbar. * * @param w parent window the shown Drop down list is attached to. * @return #CBF_NONE */ static CallBackFunction ToolbarOptionsClick(Window *w) { DropDownList *list = new DropDownList(); *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false); *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false); /* Changes to the per-AI settings don't get send from the server to the clients. Clients get * the settings once they join but never update it. As such don't show the window at all * to network clients. */ if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false); *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false); *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false); *list->Append() = new DropDownListItem(-1, false); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)); *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)); ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } /** * Handle click on one of the entries in the Options button menu. * * @param index Index being clicked. * @return #CBF_NONE */ static CallBackFunction MenuClickSettings(int index) { switch (index) { case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE; case OME_SETTINGS: ShowGameSettings(); return CBF_NONE; case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE; case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE; case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break; case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break; case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break; case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break; case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break; case OME_SHOW_COMPETITOR_SIGNS: ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS); InvalidateWindowClassesData(WC_SIGN_LIST, -1); break; case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break; case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break; case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break; case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break; } MarkWholeScreenDirty(); return CBF_NONE; } /** * SaveLoad entries in scenario editor mode. */ enum SaveLoadEditorMenuEntries { SLEME_SAVE_SCENARIO = 0, SLEME_LOAD_SCENARIO, SLEME_SAVE_HEIGHTMAP, SLEME_LOAD_HEIGHTMAP, SLEME_EXIT_TOINTRO, SLEME_EXIT_GAME = 6, SLEME_MENUCOUNT, }; /** * SaveLoad entries in normal game mode. */ enum SaveLoadNormalMenuEntries { SLNME_SAVE_GAME = 0, SLNME_LOAD_GAME, SLNME_EXIT_TOINTRO, SLNME_EXIT_GAME = 4, SLNME_MENUCOUNT, }; /** * Handle click on Save button in toolbar in normal game mode. * * @param w parent window the shown save dialogue is attached to. * @return #CBF_NONE */ static CallBackFunction ToolbarSaveClick(Window *w) { PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT); return CBF_NONE; } /** * Handle click on SaveLoad button in toolbar in the scenario editor. * * @param w parent window the shown save dialogue is attached to. * @return #CBF_NONE */ static CallBackFunction ToolbarScenSaveOrLoad(Window *w) { PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT); return CBF_NONE; } /** * Handle click on one of the entries in the SaveLoad menu. * * @param index Index being clicked. * @return #CBF_NONE */ static CallBackFunction MenuClickSaveLoad(int index = 0) { if (_game_mode == GM_EDITOR) { switch (index) { case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break; case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break; case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(SLD_SAVE_HEIGHTMAP); break; case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break; case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break; case SLEME_EXIT_GAME: HandleExitGameRequest(); break; } } else { switch (index) { case SLNME_SAVE_GAME: ShowSaveLoadDialog(SLD_SAVE_GAME); break; case SLNME_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break; case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break; case SLNME_EXIT_GAME: HandleExitGameRequest(); break; } } return CBF_NONE; } /* --- Map button menu --- */ enum MapMenuEntries { MME_SHOW_SMALLMAP = 0, MME_SHOW_EXTRAVIEWPORTS, MME_SHOW_LINKGRAPH, MME_SHOW_SIGNLISTS, MME_SHOW_TOWNDIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, }; static CallBackFunction ToolbarMapClick(Window *w) { DropDownList *list = new DropDownList(); *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); *list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false); *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); PopupMainToolbMenu(w, WID_TN_SMALL_MAP, list, 0); return CBF_NONE; } static CallBackFunction ToolbarScenMapTownDir(Window *w) { DropDownList *list = new DropDownList(); *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false); *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false); *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false); *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false); *list->Append() = new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false); PopupMainToolbMenu(w, WID_TE_SMALL_MAP, list, 0); return CBF_NONE; } /** * Handle click on one of the entries in the Map menu. * * @param index Index being clicked. * @return #CBF_NONE */ static CallBackFunction MenuClickMap(int index) { switch (index) { case MME_SHOW_SMALLMAP: ShowSmallMap(); break; case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewPortWindow(); break; case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break; case MME_SHOW_SIGNLISTS: ShowSignList(); break; case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break; case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break; } return CBF_NONE; } /* --- Town button menu --- */ static CallBackFunction ToolbarTownClick(Window *w) { PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2); return CBF_NONE; } /** * Handle click on one of the entries in the Town menu. * * @param index Index being clicked. * @return #CBF_NONE */ static CallBackFunction MenuClickTown(int index) { switch (index) { case 0: ShowTownDirectory(); break; case 1: // setting could be changed when the dropdown was open if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow(); break; } return CBF_NONE; } /* --- Subidies button menu --- */ static CallBackFunction ToolbarSubsidiesClick(Window *w) { PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1); return CBF_NONE; } /** * Handle click on the entry in the Subsidies menu. * * @param index Unused. * @return #CBF_NONE */ static CallBackFunction MenuClickSubsidies(int index) { switch (index) { case 0: ShowSubsidiesList(); break; } return CBF_NONE; } /* --- Stations button menu --- */ static CallBackFunction ToolbarStationsClick(Window *w) { PopupMainCompanyToolbMenu(w, WID_TN_STATIONS); return CBF_NONE; } /** * Handle click on the entry in the Stations menu * * @param index CompanyID to show station list for * @return #CBF_NONE */ static CallBackFunction MenuClickStations(int index) { ShowCompanyStations((CompanyID)index); return CBF_NONE; } /* --- Finances button menu --- */ static CallBackFunction ToolbarFinancesClick(Window *w) { PopupMainCompanyToolbMenu(w, WID_TN_FINANCES); return CBF_NONE; } /** * Handle click on the entry in the finances overview menu. * * @param index CompanyID to show finances for. * @return #CBF_NONE */ static CallBackFunction MenuClickFinances(int index) { ShowCompanyFinances((CompanyID)index); return CBF_NONE; } /* --- Company's button menu --- */ static CallBackFunction ToolbarCompaniesClick(Window *w) { PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0, true); return CBF_NONE; } /** * Handle click on the entry in the Company menu. * * @param index Menu entry to handle. * @return #CBF_NONE */ static CallBackFunction MenuClickCompany(int index) { #ifdef ENABLE_NETWORK if (_networking) { switch (index) { case CTMN_CLIENT_LIST: ShowClientList(); return CBF_NONE; case CTMN_NEW_COMPANY: if (_network_server) { DoCommandP(0, 0, _network_own_client_id, CMD_COMPANY_CTRL); } else { NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company); } return CBF_NONE; case CTMN_SPECTATE: if (_network_server) { NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR); MarkWholeScreenDirty(); } else { NetworkClientRequestMove(COMPANY_SPECTATOR); } return CBF_NONE; } } #endif /* ENABLE_NETWORK */ ShowCompany((CompanyID)index); return CBF_NONE; } /* --- Story button menu --- */ static CallBackFunction ToolbarStoryClick(Window *w) { PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0, true); return CBF_NONE; } /** * Handle click on the entry in the Story menu * * @param index CompanyID to show story book for * @return #CBF_NONE */ static CallBackFunction MenuClickStory(int index) { ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index); return CBF_NONE; } /* --- Goal button menu --- */ static CallBackFunction ToolbarGoalClick(Window *w) { PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0, true); return CBF_NONE; } /** * Handle click on the entry in the Goal menu * * @param index CompanyID to show story book for * @return #CBF_NONE */ static CallBackFunction MenuClickGoal(int index) { ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index); return CBF_NONE; } /* --- Graphs button menu --- */ static CallBackFunction ToolbarGraphsClick(Window *w) { PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8); return CBF_NONE; } /** * Handle click on the entry in the Graphs menu. * * @param index Graph to show. * @return #CBF_NONE */ static CallBackFunction MenuClickGraphs(int index) { switch (index) { case 0: ShowOperatingProfitGraph(); break; case 1: ShowIncomeGraph(); break; case 2: ShowDeliveredCargoGraph(); break; case 3: ShowPerformanceHistoryGraph(); break; case 4: ShowCompanyValueGraph(); break; case 5: ShowCargoPaymentRates(); break; /* functions for combined graphs/league button */ case 6: ShowCompanyLeagueTable(); break; case 7: ShowPerformanceRatingDetail(); break; } return CBF_NONE; } /* --- League button menu --- */ static CallBackFunction ToolbarLeagueClick(Window *w) { PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3); return CBF_NONE; } /** * Handle click on the entry in the CompanyLeague menu. * * @param index Menu entry number. * @return #CBF_NONE */ static CallBackFunction MenuClickLeague(int index) { switch (index) { case 0: ShowCompanyLeagueTable(); break; case 1: ShowPerformanceRatingDetail(); break; case 2: ShowHighscoreTable(); break; } return CBF_NONE; } /* --- Industries button menu --- */ static CallBackFunction ToolbarIndustryClick(Window *w) { /* Disable build-industry menu if we are a spectator */ PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3); return CBF_NONE; } /** * Handle click on the entry in the Industry menu. * * @param index Menu entry number. * @return #CBF_NONE */ static CallBackFunction MenuClickIndustry(int index) { switch (index) { case 0: ShowIndustryDirectory(); break; case 1: ShowIndustryCargoesWindow(); break; case 2: ShowBuildIndustryWindow(); break; } return CBF_NONE; } /* --- Trains button menu + 1 helper function for all vehicles. --- */ static void ToolbarVehicleClick(Window *w, VehicleType veh) { const Vehicle *v; int dis = ~0; FOR_ALL_VEHICLES(v) { if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner); } PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis); } static CallBackFunction ToolbarTrainClick(Window *w) { ToolbarVehicleClick(w, VEH_TRAIN); return CBF_NONE; } /** * Handle click on the entry in the Train menu. * * @param index CompanyID to show train list for. * @return #CBF_NONE */ static CallBackFunction MenuClickShowTrains(int index) { ShowVehicleListWindow((CompanyID)index, VEH_TRAIN); return CBF_NONE; } /* --- Road vehicle button menu --- */ static CallBackFunction ToolbarRoadClick(Window *w) { ToolbarVehicleClick(w, VEH_ROAD); return CBF_NONE; } /** * Handle click on the entry in the Road Vehicles menu. * * @param index CompanyID to show road vehicles list for. * @return #CBF_NONE */ static CallBackFunction MenuClickShowRoad(int index) { ShowVehicleListWindow((CompanyID)index, VEH_ROAD); return CBF_NONE; } /* --- Ship button menu --- */ static CallBackFunction ToolbarShipClick(Window *w) { ToolbarVehicleClick(w, VEH_SHIP); return CBF_NONE; } /** * Handle click on the entry in the Ships menu. * * @param index CompanyID to show ship list for. * @return #CBF_NONE */ static CallBackFunction MenuClickShowShips(int index) { ShowVehicleListWindow((CompanyID)index, VEH_SHIP); return CBF_NONE; } /* --- Aircraft button menu --- */ static CallBackFunction ToolbarAirClick(Window *w) { ToolbarVehicleClick(w, VEH_AIRCRAFT); return CBF_NONE; } /** * Handle click on the entry in the Aircraft menu. * * @param index CompanyID to show aircraft list for. * @return #CBF_NONE */ static CallBackFunction MenuClickShowAir(int index) { ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT); return CBF_NONE; } /* --- Zoom in button --- */ static CallBackFunction ToolbarZoomInClick(Window *w) { if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) { w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } return CBF_NONE; } /* --- Zoom out button --- */ static CallBackFunction ToolbarZoomOutClick(Window *w) { if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) { w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } return CBF_NONE; } /* --- Rail button menu --- */ static CallBackFunction ToolbarBuildRailClick(Window *w) { ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } /** * Handle click on the entry in the Build Rail menu. * * @param index RailType to show the build toolbar for. * @return #CBF_NONE */ static CallBackFunction MenuClickBuildRail(int index) { _last_built_railtype = (RailType)index; ShowBuildRailToolbar(_last_built_railtype); return CBF_NONE; } /* --- Road button menu --- */ static CallBackFunction ToolbarBuildRoadClick(Window *w) { const Company *c = Company::Get(_local_company); DropDownList *list = new DropDownList(); /* Road is always visible and available. */ *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false); /* Tram is only visible when there will be a tram, and available when that has been introduced. */ Engine *e; 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; *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM)); break; } ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } /** * Handle click on the entry in the Build Road menu. * * @param index RoadType to show the build toolbar for. * @return #CBF_NONE */ static CallBackFunction MenuClickBuildRoad(int index) { _last_built_roadtype = (RoadType)index; ShowBuildRoadToolbar(_last_built_roadtype); return CBF_NONE; } /* --- Water button menu --- */ static CallBackFunction ToolbarBuildWaterClick(Window *w) { PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1); return CBF_NONE; } /** * Handle click on the entry in the Build Waterways menu. * * @param index Unused. * @return #CBF_NONE */ static CallBackFunction MenuClickBuildWater(int index) { ShowBuildDocksToolbar(); return CBF_NONE; } /* --- Airport button menu --- */ static CallBackFunction ToolbarBuildAirClick(Window *w) { PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1); return CBF_NONE; } /** * Handle click on the entry in the Build Air menu. * * @param index Unused. * @return #CBF_NONE */ static CallBackFunction MenuClickBuildAir(int index) { ShowBuildAirToolbar(); return CBF_NONE; } /* --- Forest button menu --- */ static CallBackFunction ToolbarForestClick(Window *w) { PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3); return CBF_NONE; } /** * Handle click on the entry in the landscaping menu. * * @param index Menu entry clicked. * @return #CBF_NONE */ static CallBackFunction MenuClickForest(int index) { switch (index) { case 0: ShowTerraformToolbar(); break; case 1: ShowBuildTreesToolbar(); break; case 2: return SelectSignTool(); } return CBF_NONE; } /* --- Music button menu --- */ static CallBackFunction ToolbarMusicClick(Window *w) { PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1); return CBF_NONE; } /** * Handle click on the entry in the Music menu. * * @param index Unused. * @return #CBF_NONE */ static CallBackFunction MenuClickMusicWindow(int index) { ShowMusicWindow(); return CBF_NONE; } /* --- Newspaper button menu --- */ static CallBackFunction ToolbarNewspaperClick(Window *w) { PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 2); return CBF_NONE; } /** * Handle click on the entry in the Newspaper menu. * * @param index Menu entry clicked. * @return #CBF_NONE */ static CallBackFunction MenuClickNewspaper(int index) { switch (index) { case 0: ShowLastNewsMessage(); break; case 1: ShowMessageHistory(); break; } return CBF_NONE; } /* --- Help button menu --- */ static CallBackFunction PlaceLandBlockInfo() { if (_cursor.sprite == SPR_CURSOR_QUERY) { ResetObjectToPlace(); return CBF_NONE; } else { SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0); return CBF_PLACE_LANDINFO; } } static CallBackFunction ToolbarHelpClick(Window *w) { PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 9); return CBF_NONE; } static void MenuClickSmallScreenshot() { MakeScreenshot(SC_VIEWPORT, NULL); } /** * Callback on the confirmation window for huge screenshots. * @param w Window with viewport * @param confirmed true on confirmation */ static void ScreenshotConfirmCallback(Window *w, bool confirmed) { if (confirmed) MakeScreenshot(_confirmed_screenshot_type, NULL); } /** * Make a screenshot of the world. * Ask for confirmation if the screenshot will be huge. * @param t Screenshot type: World or viewport screenshot */ static void MenuClickLargeWorldScreenshot(ScreenshotType t) { ViewPort vp; SetupScreenshotViewport(t, &vp); if ((uint64)vp.width * (uint64)vp.height > 8192 * 8192) { /* Ask for confirmation */ SetDParam(0, vp.width); SetDParam(1, vp.height); _confirmed_screenshot_type = t; ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, NULL, ScreenshotConfirmCallback); } else { /* Less than 64M pixels, just do it */ MakeScreenshot(t, NULL); } } /** * Toggle drawing of sprites' bounding boxes. * @note has only an effect when newgrf_developer_tools are active. * * Function is found here and not in viewport.cpp in order to avoid * importing the settings structs to there. */ void ToggleBoundingBoxes() { extern bool _draw_bounding_boxes; /* Always allow to toggle them off */ if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) { _draw_bounding_boxes = !_draw_bounding_boxes; MarkWholeScreenDirty(); } } /** * Toggle drawing of the dirty blocks. * @note has only an effect when newgrf_developer_tools are active. * * Function is found here and not in viewport.cpp in order to avoid * importing the settings structs to there. */ void ToggleDirtyBlocks() { extern bool _draw_dirty_blocks; /* Always allow to toggle them off */ if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) { _draw_dirty_blocks = !_draw_dirty_blocks; MarkWholeScreenDirty(); } } /** * Set the starting year for a scenario. * @param year New starting year. */ void SetStartingYear(Year year) { _settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR); Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); /* If you open a savegame as scenario there may already be link graphs.*/ LinkGraphSchedule::instance.ShiftDates(new_date - _date); SetDate(new_date, 0); } /** * Choose the proper callback function for the main toolbar's help menu. * @param index The menu index which was selected. * @return CBF_NONE */ static CallBackFunction MenuClickHelp(int index) { switch (index) { case 0: return PlaceLandBlockInfo(); case 2: IConsoleSwitch(); break; case 3: ShowAIDebugWindow(); break; case 4: MenuClickSmallScreenshot(); break; case 5: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break; case 8: ShowAboutWindow(); break; case 9: ShowSpriteAlignerWindow(); break; case 10: ToggleBoundingBoxes(); break; case 11: ToggleDirtyBlocks(); break; } return CBF_NONE; } /* --- Switch toolbar button --- */ static CallBackFunction ToolbarSwitchClick(Window *w) { if (_toolbar_mode != TB_LOWER) { _toolbar_mode = TB_LOWER; } else { _toolbar_mode = TB_UPPER; } w->ReInit(); w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return CBF_NONE; } /* --- Scenario editor specific handlers. */ /** * Called when clicking at the date panel of the scenario editor toolbar. */ static CallBackFunction ToolbarScenDatePanel(Window *w) { SetDParam(0, _settings_game.game_creation.starting_year); ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT); _left_button_clicked = false; return CBF_NONE; } static CallBackFunction ToolbarScenDateBackward(Window *w) { /* don't allow too fast scrolling */ if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) { w->HandleButtonClick(WID_TE_DATE_BACKWARD); w->SetDirty(); SetStartingYear(_settings_game.game_creation.starting_year - 1); } _left_button_clicked = false; return CBF_NONE; } static CallBackFunction ToolbarScenDateForward(Window *w) { /* don't allow too fast scrolling */ if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) { w->HandleButtonClick(WID_TE_DATE_FORWARD); w->SetDirty(); SetStartingYear(_settings_game.game_creation.starting_year + 1); } _left_button_clicked = false; return CBF_NONE; } static CallBackFunction ToolbarScenGenLand(Window *w) { w->HandleButtonClick(WID_TE_LAND_GENERATE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); ShowEditorTerraformToolbar(); return CBF_NONE; } static CallBackFunction ToolbarScenGenTown(Window *w) { w->HandleButtonClick(WID_TE_TOWN_GENERATE); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); ShowFoundTownWindow(); return CBF_NONE; } static CallBackFunction ToolbarScenGenIndustry(Window *w) { w->HandleButtonClick(WID_TE_INDUSTRY); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); ShowBuildIndustryWindow(); return CBF_NONE; } static CallBackFunction ToolbarScenBuildRoad(Window *w) { w->HandleButtonClick(WID_TE_ROADS); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); ShowBuildRoadScenToolbar(); return CBF_NONE; } static CallBackFunction ToolbarScenBuildDocks(Window *w) { w->HandleButtonClick(WID_TE_WATER); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); ShowBuildDocksScenToolbar(); return CBF_NONE; } static CallBackFunction ToolbarScenPlantTrees(Window *w) { w->HandleButtonClick(WID_TE_TREES); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); ShowBuildTreesToolbar(); return CBF_NONE; } static CallBackFunction ToolbarScenPlaceSign(Window *w) { w->HandleButtonClick(WID_TE_SIGNS); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); return SelectSignTool(); } static CallBackFunction ToolbarBtn_NULL(Window *w) { return CBF_NONE; } typedef CallBackFunction MenuClickedProc(int index); static MenuClickedProc * const _menu_clicked_procs[] = { NULL, // 0 NULL, // 1 MenuClickSettings, // 2 MenuClickSaveLoad, // 3 MenuClickMap, // 4 MenuClickTown, // 5 MenuClickSubsidies, // 6 MenuClickStations, // 7 MenuClickFinances, // 8 MenuClickCompany, // 9 MenuClickStory, // 10 MenuClickGoal, // 11 MenuClickGraphs, // 12 MenuClickLeague, // 13 MenuClickIndustry, // 14 MenuClickShowTrains, // 15 MenuClickShowRoad, // 16 MenuClickShowShips, // 17 MenuClickShowAir, // 18 MenuClickMap, // 19 NULL, // 20 MenuClickBuildRail, // 21 MenuClickBuildRoad, // 22 MenuClickBuildWater, // 23 MenuClickBuildAir, // 24 MenuClickForest, // 25 MenuClickMusicWindow, // 26 MenuClickNewspaper, // 27 MenuClickHelp, // 28 }; /** Full blown container to make it behave exactly as we want :) */ class NWidgetToolbarContainer : public NWidgetContainer { bool visible[WID_TN_END]; ///< The visible headers protected: uint spacers; ///< Number of spacer widgets in this toolbar public: NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL) { } /** * Check whether the given widget type is a button for us. * @param type the widget type to check. * @return true if it is a button for us. */ bool IsButton(WidgetType type) const { return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN; } void SetupSmallestSize(Window *w, bool init_array) { this->smallest_x = 0; // Biggest child this->smallest_y = 0; // Biggest child this->fill_x = 1; this->fill_y = 0; this->resize_x = 1; // We only resize in this direction this->resize_y = 0; // We never resize in this direction this->spacers = 0; uint nbuttons = 0; /* First initialise some variables... */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->SetupSmallestSize(w, init_array); this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom); if (this->IsButton(child_wid->type)) { nbuttons++; this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right); } else if (child_wid->type == NWID_SPACER) { this->spacers++; } } /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */ for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { child_wid->current_y = this->smallest_y; if (!this->IsButton(child_wid->type)) { child_wid->current_x = child_wid->smallest_x; } } _toolbar_width = nbuttons * this->smallest_x; } void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) { assert(given_width >= this->smallest_x && given_height >= this->smallest_y); this->pos_x = x; this->pos_y = y; this->current_x = given_width; this->current_y = given_height; /* Figure out what are the visible buttons */ memset(this->visible, 0, sizeof(this->visible)); uint arrangable_count, button_count, spacer_count; const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count); for (uint i = 0; i < arrangable_count; i++) { this->visible[arrangement[i]] = true; } /* Create us ourselves a quick lookup table */ NWidgetBase *widgets[WID_TN_END]; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (child_wid->type == NWID_SPACER) continue; widgets[((NWidgetCore*)child_wid)->index] = child_wid; } /* Now assign the widgets to their rightful place */ uint position = 0; // Place to put next child relative to origin of the container. uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets uint button_space = given_width - spacer_space; // Remaining spacing for the buttons uint spacer_i = 0; uint button_i = 0; /* Index into the arrangement indices. The macro lastof cannot be used here! */ const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement; for (uint i = 0; i < arrangable_count; i++) { NWidgetBase *child_wid = widgets[*cur_wid]; /* If we have to give space to the spacers, do that */ if (spacer_space != 0) { NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev; if (possible_spacer != NULL && possible_spacer->type == NWID_SPACER) { uint add = spacer_space / (spacer_count - spacer_i); position += add; spacer_space -= add; spacer_i++; } } /* Buttons can be scaled, the others not. */ if (this->IsButton(child_wid->type)) { child_wid->current_x = button_space / (button_count - button_i); button_space -= child_wid->current_x; button_i++; } child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); position += child_wid->current_x; if (rtl) { cur_wid--; } else { cur_wid++; } } } /* virtual */ void Draw(const Window *w) { /* Draw brown-red toolbar bg. */ GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_VERY_DARK_RED); GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_DARK_RED, FILLRECT_CHECKER); bool rtl = _current_text_dir == TD_RTL; for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != NULL; child_wid = rtl ? child_wid->prev : child_wid->next) { if (child_wid->type == NWID_SPACER) continue; if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; child_wid->Draw(w); } } /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y) { if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (child_wid->type == NWID_SPACER) continue; if (!this->visible[((NWidgetCore*)child_wid)->index]) continue; NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); if (nwid != NULL) return nwid; } return NULL; } /** * Get the arrangement of the buttons for the toolbar. * @param width the new width of the toolbar. * @param arrangable_count output of the number of visible items. * @param button_count output of the number of visible buttons. * @param spacer_count output of the number of spacers. * @return the button configuration. */ virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0; }; /** Container for the 'normal' main toolbar */ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { static const uint SMALLEST_ARRANGEMENT = 14; static const uint BIGGEST_ARRANGEMENT = 20; static const byte arrange14[] = { 0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29, 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, }; static const byte arrange15[] = { 0, 1, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, 0, 2, 4, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, }; static const byte arrange16[] = { 0, 1, 2, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, 0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, }; static const byte arrange17[] = { 0, 1, 2, 4, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, 0, 1, 3, 4, 6, 5, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, }; static const byte arrange18[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, }; static const byte arrange19[] = { 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29, 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29, }; static const byte arrange20[] = { 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, }; static const byte arrange_all[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 }; /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT); if (full_buttons > BIGGEST_ARRANGEMENT) { button_count = arrangable_count = lengthof(arrange_all); spacer_count = this->spacers; return arrange_all; } /* Introduce the split toolbar */ static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 }; button_count = arrangable_count = full_buttons; spacer_count = this->spacers; return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0); } }; /** Container for the scenario editor's toolbar */ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel) void SetupSmallestSize(Window *w, bool init_array) { this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array); /* Find the size of panel_widths */ uint i = 0; for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) { if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue; assert(i < lengthof(this->panel_widths)); this->panel_widths[i++] = child_wid->current_x; _toolbar_width += child_wid->current_x; } } /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { static const byte arrange_all[] = { 0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, }; static const byte arrange_nopanel[] = { 0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, }; static const byte arrange_switch[] = { 18, 8, 11, 12, 13, 14, 15, 16, 17, 29, 0, 1, 2, 3, 18, 9, 10, 26, 28, 29, }; /* If we can place all buttons *and* the panels, show them. */ uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1]; if (width >= min_full_width) { width -= this->panel_widths[0] + this->panel_widths[1]; arrangable_count = lengthof(arrange_all); button_count = arrangable_count - 2; spacer_count = this->spacers; return arrange_all; } /* Otherwise don't show the date panel and if we can't fit half the buttons and the panels anymore, split the toolbar in two */ uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1]; if (width > min_small_width) { width -= this->panel_widths[1]; arrangable_count = lengthof(arrange_nopanel); button_count = arrangable_count - 1; spacer_count = this->spacers - 1; return arrange_nopanel; } /* Split toolbar */ width -= this->panel_widths[1]; arrangable_count = lengthof(arrange_switch) / 2; button_count = arrangable_count - 1; spacer_count = 0; return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0); } }; /* --- Toolbar handling for the 'normal' case */ typedef CallBackFunction ToolbarButtonProc(Window *w); static ToolbarButtonProc * const _toolbar_button_procs[] = { ToolbarPauseClick, ToolbarFastForwardClick, ToolbarOptionsClick, ToolbarSaveClick, ToolbarMapClick, ToolbarTownClick, ToolbarSubsidiesClick, ToolbarStationsClick, ToolbarFinancesClick, ToolbarCompaniesClick, ToolbarStoryClick, ToolbarGoalClick, ToolbarGraphsClick, ToolbarLeagueClick, ToolbarIndustryClick, ToolbarTrainClick, ToolbarRoadClick, ToolbarShipClick, ToolbarAirClick, ToolbarZoomInClick, ToolbarZoomOutClick, ToolbarBuildRailClick, ToolbarBuildRoadClick, ToolbarBuildWaterClick, ToolbarBuildAirClick, ToolbarForestClick, ToolbarMusicClick, ToolbarNewspaperClick, ToolbarHelpClick, ToolbarSwitchClick, }; enum MainToolbarHotkeys { MTHK_PAUSE, MTHK_FASTFORWARD, MTHK_SETTINGS, MTHK_SAVEGAME, MTHK_LOADGAME, MTHK_SMALLMAP, MTHK_TOWNDIRECTORY, MTHK_SUBSIDIES, MTHK_STATIONS, MTHK_FINANCES, MTHK_COMPANIES, MTHK_STORY, MTHK_GOAL, MTHK_GRAPHS, MTHK_LEAGUE, MTHK_INDUSTRIES, MTHK_TRAIN_LIST, MTHK_ROADVEH_LIST, MTHK_SHIP_LIST, MTHK_AIRCRAFT_LIST, MTHK_ZOOM_IN, MTHK_ZOOM_OUT, MTHK_BUILD_RAIL, MTHK_BUILD_ROAD, MTHK_BUILD_DOCKS, MTHK_BUILD_AIRPORT, MTHK_BUILD_TREES, MTHK_MUSIC, MTHK_AI_DEBUG, MTHK_SMALL_SCREENSHOT, MTHK_ZOOMEDIN_SCREENSHOT, MTHK_DEFAULTZOOM_SCREENSHOT, MTHK_GIANT_SCREENSHOT, MTHK_CHEATS, MTHK_TERRAFORM, MTHK_EXTRA_VIEWPORT, MTHK_CLIENT_LIST, MTHK_SIGN_LIST, }; /** Main toolbar. */ struct MainToolbarWindow : Window { CallBackFunction last_started_action; ///< Last started user action. MainToolbarWindow(WindowDesc *desc) : Window(desc) { this->InitNested(0); this->last_started_action = CBF_NONE; CLRBITS(this->flags, WF_WHITE_BORDER); this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button PositionMainToolbar(this); DoZoomInOutWindow(ZOOM_NONE, this); } virtual void FindWindowPlacementAndResize(int def_width, int def_height) { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } virtual void OnPaint() { /* If spectator, disable all construction buttons * ie : Build road, rail, ships, airports and landscaping * Since enabled state is the default, just disable when needed */ this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END); /* disable company list drop downs, if there are no companies */ this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END); this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0); this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0); this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN)); this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT)); this->DrawWidgets(); } virtual void OnClick(Point pt, int widget, int click_count) { if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this); } virtual void OnDropdownSelect(int widget, int index) { CallBackFunction cbf = _menu_clicked_procs[widget](index); if (cbf != CBF_NONE) this->last_started_action = cbf; } virtual EventState OnHotkey(int hotkey) { switch (hotkey) { case MTHK_PAUSE: ToolbarPauseClick(this); break; case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break; case MTHK_SETTINGS: ShowGameOptions(); break; case MTHK_SAVEGAME: MenuClickSaveLoad(); break; case MTHK_LOADGAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break; case MTHK_SMALLMAP: ShowSmallMap(); break; case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break; case MTHK_SUBSIDIES: ShowSubsidiesList(); break; case MTHK_STATIONS: ShowCompanyStations(_local_company); break; case MTHK_FINANCES: ShowCompanyFinances(_local_company); break; case MTHK_COMPANIES: ShowCompany(_local_company); break; case MTHK_STORY: ShowStoryBook(_local_company); break; case MTHK_GOAL: ShowGoalsList(_local_company); break; case MTHK_GRAPHS: ShowOperatingProfitGraph(); break; case MTHK_LEAGUE: ShowCompanyLeagueTable(); break; case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break; case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break; case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break; case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break; case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break; case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break; case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break; case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break; case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break; case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break; case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break; case MTHK_MUSIC: ShowMusicWindow(); break; case MTHK_AI_DEBUG: ShowAIDebugWindow(); break; case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break; case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break; case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break; case MTHK_TERRAFORM: ShowTerraformToolbar(); break; case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; #ifdef ENABLE_NETWORK case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break; #endif case MTHK_SIGN_LIST: ShowSignList(); break; default: return ES_NOT_HANDLED; } return ES_HANDLED; } virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_started_action) { case CBF_PLACE_SIGN: PlaceProc_Sign(tile); break; case CBF_PLACE_LANDINFO: ShowLandInfo(tile); break; default: NOT_REACHED(); } } virtual void OnTick() { if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) { this->ToggleWidgetLoweredState(WID_TN_PAUSE); this->SetWidgetDirty(WID_TN_PAUSE); } if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) { this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD); this->SetWidgetDirty(WID_TN_FAST_FORWARD); } } virtual void OnTimeout() { /* We do not want to automatically raise the pause, fast forward and * switchbar buttons; they have to stay down when pressed etc. */ for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) { if (this->IsWidgetLowered(i)) { this->RaiseWidget(i); this->SetWidgetDirty(i); } } } /** * 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; if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT); } static HotkeyList hotkeys; }; const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0}; const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0}; const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0}; const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0}; static Hotkey maintoolbar_hotkeys[] = { Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE), Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD), Hotkey(WKC_F2, "settings", MTHK_SETTINGS), Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME), Hotkey((uint16)0, "load_game", MTHK_LOADGAME), Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP), Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY), Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES), Hotkey(WKC_F7, "station_list", MTHK_STATIONS), Hotkey(WKC_F8, "finances", MTHK_FINANCES), Hotkey(WKC_F9, "companies", MTHK_COMPANIES), Hotkey((uint16)0, "story_book", MTHK_STORY), Hotkey((uint16)0, "goal_list", MTHK_GOAL), Hotkey(WKC_F10, "graphs", MTHK_GRAPHS), Hotkey(WKC_F11, "league", MTHK_LEAGUE), Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES), Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST), Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST), Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST), Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST), Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN), Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT), Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL), Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD), Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS), Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT), Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES), Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC), Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG), Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT), Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT), Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT), Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT), Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS), Hotkey('L', "terraform", MTHK_TERRAFORM), Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT), #ifdef ENABLE_NETWORK Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST), #endif Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST), HOTKEY_LIST_END }; HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys); static NWidgetBase *MakeMainToolbar(int *biggest_index) { /** Sprites to use for the different toolbar buttons */ static const SpriteID toolbar_button_sprites[] = { SPR_IMG_PAUSE, // WID_TN_PAUSE SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD SPR_IMG_SETTINGS, // WID_TN_SETTINGS SPR_IMG_SAVE, // WID_TN_SAVE SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP SPR_IMG_TOWN, // WID_TN_TOWNS SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES SPR_IMG_STORY_BOOK, // WID_TN_STORY SPR_IMG_GOAL, // WID_TN_GOAL SPR_IMG_GRAPHS, // WID_TN_GRAPHS SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES SPR_IMG_TRAINLIST, // WID_TN_TRAINS SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS SPR_IMG_SHIPLIST, // WID_TN_SHIPS SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT SPR_IMG_BUILDRAIL, // WID_TN_RAILS SPR_IMG_BUILDROAD, // WID_TN_ROADS SPR_IMG_BUILDWATER, // WID_TN_WATER SPR_IMG_BUILDAIR, // WID_TN_AIR SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND SPR_IMG_MESSAGES, // WID_TN_MESSAGES SPR_IMG_QUERY, // WID_TN_HELP SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR }; NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); for (uint i = 0; i < WID_TN_END; i++) { switch (i) { case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; } hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } *biggest_index = max(*biggest_index, WID_TN_SWITCH_BAR); return hor; } static const NWidgetPart _nested_toolbar_normal_widgets[] = { NWidgetFunction(MakeMainToolbar), }; static WindowDesc _toolb_normal_desc( WDP_MANUAL, NULL, 0, 0, WC_MAIN_TOOLBAR, WC_NONE, WDF_NO_FOCUS, _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets), &MainToolbarWindow::hotkeys ); /* --- Toolbar handling for the scenario editor */ static ToolbarButtonProc * const _scen_toolbar_button_procs[] = { ToolbarPauseClick, ToolbarFastForwardClick, ToolbarOptionsClick, ToolbarScenSaveOrLoad, ToolbarBtn_NULL, ToolbarScenDatePanel, ToolbarScenDateBackward, ToolbarScenDateForward, ToolbarScenMapTownDir, ToolbarZoomInClick, ToolbarZoomOutClick, ToolbarScenGenLand, ToolbarScenGenTown, ToolbarScenGenIndustry, ToolbarScenBuildRoad, ToolbarScenBuildDocks, ToolbarScenPlantTrees, ToolbarScenPlaceSign, ToolbarBtn_NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ToolbarMusicClick, NULL, ToolbarHelpClick, ToolbarSwitchClick, }; enum MainToolbarEditorHotkeys { MTEHK_PAUSE, MTEHK_FASTFORWARD, MTEHK_SETTINGS, MTEHK_SAVEGAME, MTEHK_GENLAND, MTEHK_GENTOWN, MTEHK_GENINDUSTRY, MTEHK_BUILD_ROAD, MTEHK_BUILD_DOCKS, MTEHK_BUILD_TREES, MTEHK_SIGN, MTEHK_MUSIC, MTEHK_LANDINFO, MTEHK_SMALL_SCREENSHOT, MTEHK_ZOOMEDIN_SCREENSHOT, MTEHK_DEFAULTZOOM_SCREENSHOT, MTEHK_GIANT_SCREENSHOT, MTEHK_ZOOM_IN, MTEHK_ZOOM_OUT, MTEHK_TERRAFORM, MTEHK_SMALLMAP, MTEHK_EXTRA_VIEWPORT, }; struct ScenarioEditorToolbarWindow : Window { CallBackFunction last_started_action; ///< Last started user action. ScenarioEditorToolbarWindow(WindowDesc *desc) : Window(desc) { this->InitNested(0); this->last_started_action = CBF_NONE; CLRBITS(this->flags, WF_WHITE_BORDER); PositionMainToolbar(this); DoZoomInOutWindow(ZOOM_NONE, this); } virtual void FindWindowPlacementAndResize(int def_width, int def_height) { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } virtual void OnPaint() { this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR); this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR); this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_TE_DATE: SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1)); DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER); break; case WID_TE_SPACER: { int height = r.bottom - r.top; if (height > 2 * FONT_HEIGHT_NORMAL) { DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER); DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER); } else { DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER); } break; } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_TE_SPACER: size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; break; case WID_TE_DATE: SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1)); *size = GetStringBoundingBox(STR_WHITE_DATE_LONG); size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM); break; } } virtual void OnClick(Point pt, int widget, int click_count) { if (_game_mode == GM_MENU) return; CallBackFunction cbf = _scen_toolbar_button_procs[widget](this); if (cbf != CBF_NONE) this->last_started_action = cbf; } virtual void OnDropdownSelect(int widget, int index) { /* The map button is in a different location on the scenario * editor toolbar, so we need to adjust for it. */ if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP; CallBackFunction cbf = _menu_clicked_procs[widget](index); if (cbf != CBF_NONE) this->last_started_action = cbf; if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); } virtual EventState OnHotkey(int hotkey) { CallBackFunction cbf = CBF_NONE; switch (hotkey) { case MTEHK_PAUSE: ToolbarPauseClick(this); break; case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break; case MTEHK_SETTINGS: ShowGameOptions(); break; case MTEHK_SAVEGAME: MenuClickSaveLoad(); break; case MTEHK_GENLAND: ToolbarScenGenLand(this); break; case MTEHK_GENTOWN: ToolbarScenGenTown(this); break; case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break; case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break; case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break; case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break; case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break; case MTEHK_MUSIC: ShowMusicWindow(); break; case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break; case MTEHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break; case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break; case MTEHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break; case MTEHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break; case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break; case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break; case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break; case MTEHK_SMALLMAP: ShowSmallMap(); break; case MTEHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break; default: return ES_NOT_HANDLED; } if (cbf != CBF_NONE) this->last_started_action = cbf; return ES_HANDLED; } virtual void OnPlaceObject(Point pt, TileIndex tile) { switch (this->last_started_action) { case CBF_PLACE_SIGN: PlaceProc_Sign(tile); break; case CBF_PLACE_LANDINFO: ShowLandInfo(tile); break; default: NOT_REACHED(); } } virtual void OnTimeout() { this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END); this->SetWidgetDirty(WID_TE_DATE_BACKWARD); this->SetWidgetDirty(WID_TE_DATE_FORWARD); } virtual void OnTick() { if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) { this->ToggleWidgetLoweredState(WID_TE_PAUSE); this->SetDirty(); } if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) { this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD); this->SetDirty(); } } /** * 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; if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT); } virtual void OnQueryTextFinished(char *str) { /* Was 'cancel' pressed? */ if (str == NULL) return; int32 value; if (!StrEmpty(str)) { value = atoi(str); } else { /* An empty string means revert to the default */ value = DEF_START_YEAR; } SetStartingYear(value); this->SetDirty(); } static HotkeyList hotkeys; }; static Hotkey scenedit_maintoolbar_hotkeys[] = { Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE), Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD), Hotkey(WKC_F2, "settings", MTEHK_SETTINGS), Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME), Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND), Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN), Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY), Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD), Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS), Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES), Hotkey(WKC_F10, "build_sign", MTEHK_SIGN), Hotkey(WKC_F11, "music", MTEHK_MUSIC), Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO), Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT), Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT), Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT), Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT), Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN), Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT), Hotkey('L', "terraform", MTEHK_TERRAFORM), Hotkey('M', "smallmap", MTEHK_SMALLMAP), Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT), HOTKEY_LIST_END }; HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys); static const NWidgetPart _nested_toolb_scen_inner_widgets[] = { NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS), NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO), NWidget(NWID_SPACER), NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(), NWidget(NWID_SPACER), NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL), NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), EndContainer(), EndContainer(), NWidget(NWID_SPACER), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY), NWidget(NWID_SPACER), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), NWidget(NWID_SPACER), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN), NWidget(NWID_SPACER), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), }; static NWidgetBase *MakeScenarioToolbar(int *biggest_index) { return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer()); } static const NWidgetPart _nested_toolb_scen_widgets[] = { NWidgetFunction(MakeScenarioToolbar), }; static WindowDesc _toolb_scen_desc( WDP_MANUAL, NULL, 0, 0, WC_MAIN_TOOLBAR, WC_NONE, WDF_NO_FOCUS, _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets), &ScenarioEditorToolbarWindow::hotkeys ); /** Allocate the toolbar. */ void AllocateToolbar() { /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */ _last_built_roadtype = ROADTYPE_ROAD; if (_game_mode == GM_EDITOR) { new ScenarioEditorToolbarWindow(&_toolb_scen_desc); } else { new MainToolbarWindow(&_toolb_normal_desc); } } openttd-1.5.3/src/strings_func.h0000644000000000000000000001521212627373435015354 0ustar rootroot/* $Id: strings_func.h 26238 2014-01-12 17:59:43Z frosch $ */ /* * 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 strings_func.h Functions related to OTTD's strings. */ #ifndef STRINGS_FUNC_H #define STRINGS_FUNC_H #include "strings_type.h" #include "string_type.h" #include "gfx_type.h" class StringParameters { StringParameters *parent; ///< If not NULL, this instance references data from this parent instance. uint64 *data; ///< Array with the actual data. WChar *type; ///< Array with type information about the data. Can be NULL when no type information is needed. See #StringControlCode. public: uint offset; ///< Current offset in the data/type arrays. uint num_param; ///< Length of the data array. /** Create a new StringParameters instance. */ StringParameters(uint64 *data, uint num_param, WChar *type) : parent(NULL), data(data), type(type), offset(0), num_param(num_param) { } /** Create a new StringParameters instance. */ template StringParameters(int64 (&data)[Tnum_param]) : parent(NULL), data((uint64 *)data), type(NULL), offset(0), num_param(Tnum_param) { assert_compile(sizeof(data[0]) == sizeof(uint64)); } /** * Create a new StringParameters instance that can reference part of the data of * the given partent instance. */ StringParameters(StringParameters &parent, uint size) : parent(&parent), data(parent.data + parent.offset), offset(0), num_param(size) { assert(size <= parent.GetDataLeft()); if (parent.type == NULL) { this->type = NULL; } else { this->type = parent.type + parent.offset; } } ~StringParameters() { if (this->parent != NULL) { this->parent->offset += this->num_param; } } void ClearTypeInformation(); int64 GetInt64(WChar type = 0); /** Read an int32 from the argument array. @see GetInt64. */ int32 GetInt32(WChar type = 0) { return (int32)this->GetInt64(type); } void ShiftParameters(uint amount); /** Get a pointer to the current element in the data array. */ uint64 *GetDataPointer() const { return &this->data[this->offset]; } /** Return the amount of elements which can still be read. */ uint GetDataLeft() const { return this->num_param - this->offset; } /** Get a pointer to a specific element in the data array. */ uint64 *GetPointerToOffset(uint offset) const { assert(offset < this->num_param); return &this->data[offset]; } /** Does this instance store information about the type of the parameters. */ bool HasTypeInformation() const { return this->type != NULL; } /** Get the type of a specific element. */ WChar GetTypeAtOffset(uint offset) const { assert(offset < this->num_param); assert(this->HasTypeInformation()); return this->type[offset]; } void SetParam(uint n, uint64 v) { assert(n < this->num_param); this->data[n] = v; } uint64 GetParam(uint n) const { assert(n < this->num_param); return this->data[n]; } }; extern StringParameters _global_string_params; char *GetString(char *buffr, StringID string, const char *last); char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false); const char *GetStringPtr(StringID string); uint ConvertKmhishSpeedToDisplaySpeed(uint speed); uint ConvertDisplaySpeedToKmhishSpeed(uint speed); void InjectDParam(uint amount); /** * Set a string parameter \a v at index \a n in a given array \a s. * @param s Array of string parameters. * @param n Index of the string parameter. * @param v Value of the string parameter. */ static inline void SetDParamX(uint64 *s, uint n, uint64 v) { s[n] = v; } /** * Set a string parameter \a v at index \a n in the global string parameter array. * @param n Index of the string parameter. * @param v Value of the string parameter. */ static inline void SetDParam(uint n, uint64 v) { _global_string_params.SetParam(n, v); } void SetDParamMaxValue(uint n, uint64 max_value, uint min_count = 0, FontSize size = FS_NORMAL); void SetDParamMaxDigits(uint n, uint count, FontSize size = FS_NORMAL); void SetDParamStr(uint n, const char *str); void CopyInDParam(int offs, const uint64 *src, int num); void CopyOutDParam(uint64 *dst, int offs, int num); void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num); /** * Get the current string parameter at index \a n from parameter array \a s. * @param s Array of string parameters. * @param n Index of the string parameter. * @return Value of the requested string parameter. */ static inline uint64 GetDParamX(const uint64 *s, uint n) { return s[n]; } /** * Get the current string parameter at index \a n from the global string parameter array. * @param n Index of the string parameter. * @return Value of the requested string parameter. */ static inline uint64 GetDParam(uint n) { return _global_string_params.GetParam(n); } extern TextDirection _current_text_dir; ///< Text direction of the currently selected language void InitializeLanguagePacks(); const char *GetCurrentLanguageIsoCode(); int CDECL StringIDSorter(const StringID *a, const StringID *b); /** * A searcher for missing glyphs. */ class MissingGlyphSearcher { public: /** Make sure everything gets destructed right. */ virtual ~MissingGlyphSearcher() {} /** * Get the next string to search through. * @return The next string or NULL if there is none. */ virtual const char *NextString() = 0; /** * Get the default (font) size of the string. * @return The font size. */ virtual FontSize DefaultSize() = 0; /** * Reset the search, i.e. begin from the beginning again. */ virtual void Reset() = 0; /** * Whether to search for a monospace font or not. * @return True if searching for monospace. */ virtual bool Monospace() = 0; /** * Set the right font names. * @param settings The settings to modify. * @param font_name The new font name. */ virtual void SetFontNames(struct FreeTypeSettings *settings, const char *font_name) = 0; bool FindMissingGlyphs(const char **str); }; void CheckForMissingGlyphs(bool base_font = true, MissingGlyphSearcher *search = NULL); #endif /* STRINGS_FUNC_H */ openttd-1.5.3/src/gui.h0000644000000000000000000000415612627373442013437 0ustar rootroot/* $Id: gui.h 25372 2013-06-09 13:23:03Z zuu $ */ /* * 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 gui.h GUI functions that shouldn't be here. */ #ifndef GUI_H #define GUI_H #include "vehicle_type.h" #include "economy_type.h" #include "tile_type.h" #include "transport_type.h" #include "story_type.h" #include "company_type.h" struct Window; /* main_gui.cpp */ void HandleOnEditText(const char *str); void InitializeGUI(); /* settings_gui.cpp */ void ShowGameOptions(); void ShowGameSettings(); /* train_gui.cpp */ void ShowOrdersWindow(const Vehicle *v); /* dock_gui.cpp */ Window *ShowBuildDocksToolbar(); Window *ShowBuildDocksScenToolbar(); /* airport_gui.cpp */ Window *ShowBuildAirToolbar(); /* tgp_gui.cpp */ void ShowGenerateLandscape(); void ShowHeightmapLoad(); /* misc_gui.cpp */ void ShowLandInfo(TileIndex tile); void ShowAboutWindow(); void ShowBuildTreesToolbar(); void ShowTownDirectory(); void ShowIndustryDirectory(); void ShowIndustryCargoesWindow(); void ShowSubsidiesList(); void ShowGoalsList(CompanyID company); void ShowGoalQuestion(uint16 id, byte type, uint32 button_mask, const char *question); void ShowStoryBook(CompanyID company, uint16 page_id = INVALID_STORY_PAGE); void ShowEstimatedCostOrIncome(Money cost, int x, int y); void ShowExtraViewPortWindow(TileIndex tile = INVALID_TILE); void ShowExtraViewPortWindowForTileUnderCursor(); /* bridge_gui.cpp */ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte bridge_type); void ShowBuildIndustryWindow(); void ShowFoundTownWindow(); void ShowMusicWindow(); #endif /* GUI_H */ openttd-1.5.3/src/gfx_layout.h0000644000000000000000000001421112627373435015027 0ustar rootroot/* $Id: gfx_layout.h 26029 2013-11-17 17:08:20Z michi_cc $ */ /* * 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 gfx_layout.h Functions related to laying out the texts. */ #ifndef GFX_LAYOUT_H #define GFX_LAYOUT_H #include "fontcache.h" #include "gfx_func.h" #include "core/smallmap_type.hpp" #include #include #ifdef WITH_ICU #include "layout/ParagraphLayout.h" #define ICU_FONTINSTANCE : public LEFontInstance #else /* WITH_ICU */ #define ICU_FONTINSTANCE #endif /* WITH_ICU */ /** * Text drawing parameters, which can change while drawing a line, but are kept between multiple parts * of the same text, e.g. on line breaks. */ struct FontState { FontSize fontsize; ///< Current font size. TextColour cur_colour; ///< Current text colour. TextColour prev_colour; ///< Text colour from before the last colour switch. FontState() : fontsize(FS_END), cur_colour(TC_INVALID), prev_colour(TC_INVALID) {} FontState(TextColour colour, FontSize fontsize) : fontsize(fontsize), cur_colour(colour), prev_colour(colour) {} /** * Switch to new colour \a c. * @param c New colour to use. */ inline void SetColour(TextColour c) { assert(c >= TC_BLUE && c <= TC_BLACK); this->prev_colour = this->cur_colour; this->cur_colour = c; } /** Switch to previous colour. */ inline void SetPreviousColour() { Swap(this->cur_colour, this->prev_colour); } /** * Switch to using a new font \a f. * @param f New font to use. */ inline void SetFontSize(FontSize f) { this->fontsize = f; } }; /** * Container with information about a font. */ class Font ICU_FONTINSTANCE { public: FontCache *fc; ///< The font we are using. TextColour colour; ///< The colour this font has to be. Font(FontSize size, TextColour colour); #ifdef WITH_ICU /* Implementation details of LEFontInstance */ le_int32 getUnitsPerEM() const; le_int32 getAscent() const; le_int32 getDescent() const; le_int32 getLeading() const; float getXPixelsPerEm() const; float getYPixelsPerEm() const; float getScaleFactorX() const; float getScaleFactorY() const; const void *getFontTable(LETag tableTag) const; const void *getFontTable(LETag tableTag, size_t &length) const; LEGlyphID mapCharToGlyph(LEUnicode32 ch) const; void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const; le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const; #endif /* WITH_ICU */ }; /** Mapping from index to font. */ typedef SmallMap FontMap; /** * Interface to glue fallback and normal layouter into one. */ class ParagraphLayouter { public: virtual ~ParagraphLayouter() {} /** Visual run contains data about the bit of text with the same font. */ class VisualRun { public: virtual ~VisualRun() {} virtual const Font *GetFont() const = 0; virtual int GetGlyphCount() const = 0; virtual const GlyphID *GetGlyphs() const = 0; virtual const float *GetPositions() const = 0; virtual int GetLeading() const = 0; virtual const int *GetGlyphToCharMap() const = 0; }; /** A single line worth of VisualRuns. */ class Line { public: virtual ~Line() {} virtual int GetLeading() const = 0; virtual int GetWidth() const = 0; virtual int CountRuns() const = 0; virtual const VisualRun *GetVisualRun(int run) const = 0; virtual int GetInternalCharLength(WChar c) const = 0; }; virtual void Reflow() = 0; virtual const Line *NextLine(int max_width) = 0; }; /** * The layouter performs all the layout work. * * It also accounts for the memory allocations and frees. */ class Layouter : public AutoDeleteSmallVector { const char *string; ///< Pointer to the original string. /** Key into the linecache */ struct LineCacheKey { FontState state_before; ///< Font state at the beginning of the line. std::string str; ///< Source string of the line (including colour and font size codes). /** Comparison operator for std::map */ bool operator<(const LineCacheKey &other) const { if (this->state_before.fontsize != other.state_before.fontsize) return this->state_before.fontsize < other.state_before.fontsize; if (this->state_before.cur_colour != other.state_before.cur_colour) return this->state_before.cur_colour < other.state_before.cur_colour; if (this->state_before.prev_colour != other.state_before.prev_colour) return this->state_before.prev_colour < other.state_before.prev_colour; return this->str < other.str; } }; public: /** Item in the linecache */ struct LineCacheItem { /* Stuff that cannot be freed until the ParagraphLayout is freed */ void *buffer; ///< Accessed by both ICU's and our ParagraphLayout::nextLine. FontMap runs; ///< Accessed by our ParagraphLayout::nextLine. FontState state_after; ///< Font state after the line. ParagraphLayouter *layout; ///< Layout of the line. LineCacheItem() : buffer(NULL), layout(NULL) {} ~LineCacheItem() { delete layout; free(buffer); } }; private: typedef std::map LineCache; static LineCache *linecache; static LineCacheItem &GetCachedParagraphLayout(const char *str, size_t len, const FontState &state); typedef SmallMap FontColourMap; static FontColourMap fonts[FS_END]; public: static Font *GetFont(FontSize size, TextColour colour); Layouter(const char *str, int maxw = INT32_MAX, TextColour colour = TC_FROMSTRING, FontSize fontsize = FS_NORMAL); Dimension GetBounds(); Point GetCharPosition(const char *ch) const; const char *GetCharAtPosition(int x) const; static void ResetFontCache(FontSize size); static void ResetLineCache(); static void ReduceLineCache(); }; #endif /* GFX_LAYOUT_H */ openttd-1.5.3/src/newgrf_animation_type.h0000644000000000000000000000624112627373443017241 0ustar rootroot/* $Id: newgrf_animation_type.h 22745 2011-08-14 13:45:36Z frosch $ */ /* * 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 newgrf_animation_type.h Definitions related to NewGRF animation. */ #ifndef NEWGRF_ANIMATION_TYPE_H #define NEWGRF_ANIMATION_TYPE_H static const uint8 ANIM_STATUS_NON_LOOPING = 0x00; ///< Animation is not looping. static const uint8 ANIM_STATUS_LOOPING = 0x01; ///< Animation is looping. static const uint8 ANIM_STATUS_NO_ANIMATION = 0xFF; ///< There is no animation. /** Information about animation. */ struct AnimationInfo { uint8 frames; ///< The number of frames. uint8 status; ///< Status; 0: no looping, 1: looping, 0xFF: no animation. uint8 speed; ///< The speed, i.e. the amount of time between frames. uint16 triggers; ///< The triggers that trigger animation. }; /** Animation triggers for station. */ enum StationAnimationTrigger { SAT_BUILT, ///< Trigger tile when built. SAT_NEW_CARGO, ///< Trigger station on new cargo arrival. SAT_CARGO_TAKEN, ///< Trigger station when cargo is completely taken. SAT_TRAIN_ARRIVES, ///< Trigger platform when train arrives. SAT_TRAIN_DEPARTS, ///< Trigger platform when train leaves. SAT_TRAIN_LOADS, ///< Trigger platform when train loads/unloads. SAT_250_TICKS, ///< Trigger station every 250 ticks. }; /** Animation triggers of the industries. */ enum IndustryAnimationTrigger { IAT_CONSTRUCTION_STATE_CHANGE, ///< Trigger whenever the construction state changes. IAT_TILELOOP, ///< Trigger in the periodic tile loop. IAT_INDUSTRY_TICK, ///< Trigger every tick. IAT_INDUSTRY_RECEIVED_CARGO, ///< Trigger when cargo is received . IAT_INDUSTRY_DISTRIBUTES_CARGO, ///< Trigger when cargo is distributed. }; /** Animation triggers for airport tiles */ enum AirpAnimationTrigger { AAT_BUILT, ///< Triggered when the airport is built (for all tiles at the same time). AAT_TILELOOP, ///< Triggered in the periodic tile loop. AAT_STATION_NEW_CARGO, ///< Triggered when new cargo arrives at the station (for all tiles at the same time). AAT_STATION_CARGO_TAKEN, ///< Triggered when a cargo type is completely removed from the station (for all tiles at the same time). AAT_STATION_250_TICKS, ///< Triggered every 250 ticks (for all tiles at the same time). }; /** Animation triggers for objects. */ enum ObjectAnimationTrigger { OAT_BUILT, ///< Triggered when the object is built (for all tiles at the same time). OAT_TILELOOP, ///< Triggered in the periodic tile loop. OAT_256_TICKS, ///< Triggered every 256 ticks (for all tiles at the same time). }; #endif /* NEWGRF_ANIMATION_TYPE_H */ openttd-1.5.3/src/newgrf_text.cpp0000644000000000000000000010701012627373442015533 0ustar rootroot/* $Id: newgrf_text.cpp 26713 2014-08-03 11:59:07Z frosch $ */ /* * 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 newgrf_text.cpp * Implementation of Action 04 "universal holder" structure and functions. * This file implements a linked-lists of strings, * holding everything that the newgrf action 04 will send over to OpenTTD. * One of the biggest problems is that Dynamic lang Array uses ISO codes * as way to identifying current user lang, while newgrf uses bit shift codes * not related to ISO. So equivalence functionnality had to be set. */ #include "stdafx.h" #include "newgrf.h" #include "strings_func.h" #include "newgrf_storage.h" #include "newgrf_text.h" #include "newgrf_cargo.h" #include "string_func.h" #include "date_type.h" #include "debug.h" #include "core/alloc_type.hpp" #include "core/smallmap_type.hpp" #include "language.h" #include "table/strings.h" #include "table/control_codes.h" #include "safeguards.h" #define GRFTAB 28 #define TABSIZE 11 /** * Explains the newgrf shift bit positioning. * the grf base will not be used in order to find the string, but rather for * jumping from standard langID scheme to the new one. */ enum GRFBaseLanguages { GRFLB_AMERICAN = 0x01, GRFLB_ENGLISH = 0x02, GRFLB_GERMAN = 0x04, GRFLB_FRENCH = 0x08, GRFLB_SPANISH = 0x10, GRFLB_GENERIC = 0x80, }; enum GRFExtendedLanguages { GRFLX_AMERICAN = 0x00, GRFLX_ENGLISH = 0x01, GRFLX_GERMAN = 0x02, GRFLX_FRENCH = 0x03, GRFLX_SPANISH = 0x04, GRFLX_UNSPECIFIED = 0x7F, }; /** * Element of the linked list. * Each of those elements represent the string, * but according to a different lang. */ struct GRFText { public: /** * Allocate, and assign a new GRFText with the given text. * As these strings can have string terminations in them, e.g. * due to "choice lists" we (sometimes) cannot rely on detecting * the length by means of strlen. Also, if the length of already * known not scanning the whole string is more efficient. * @param langid The language of the text. * @param text The text to store in the new GRFText. * @param len The length of the text. */ static GRFText *New(byte langid, const char *text, size_t len) { return new (len) GRFText(langid, text, len); } /** * Create a copy of this GRFText. * @param orig the grftext to copy. * @return an exact copy of the given text. */ static GRFText *Copy(GRFText *orig) { return GRFText::New(orig->langid, orig->text, orig->len); } /** * Helper allocation function to disallow something. * Don't allow simple 'news'; they wouldn't have enough memory. * @param size the amount of space not to allocate. */ void *operator new(size_t size) { NOT_REACHED(); } /** * Free the memory we allocated. * @param p memory to free. */ void operator delete(void *p) { free(p); } private: /** * Actually construct the GRFText. * @param langid_ The language of the text. * @param text_ The text to store in this GRFText. * @param len_ The length of the text to store. */ GRFText(byte langid_, const char *text_, size_t len_) : next(NULL), len(len_), langid(langid_) { /* We need to use memcpy instead of strcpy due to * the possibility of "choice lists" and therefore * intermediate string terminators. */ memcpy(this->text, text_, len); } /** * Allocate memory for this class. * @param size the size of the instance * @param extra the extra memory for the text * @return the requested amount of memory for both the instance and the text */ void *operator new(size_t size, size_t extra) { return MallocT(size + extra); } public: GRFText *next; ///< The next GRFText in this chain. size_t len; ///< The length of the stored string, used for copying. byte langid; ///< The language associated with this GRFText. char text[]; ///< The actual (translated) text. }; /** * Holder of the above structure. * Putting both grfid and stringid together allows us to avoid duplicates, * since it is NOT SUPPOSED to happen. */ struct GRFTextEntry { uint32 grfid; uint16 stringid; StringID def_string; GRFText *textholder; }; static uint _num_grf_texts = 0; static GRFTextEntry _grf_text[(1 << TABSIZE) * 3]; static byte _currentLangID = GRFLX_ENGLISH; ///< by default, english is used. /** * Get the mapping from the NewGRF supplied ID to OpenTTD's internal ID. * @param newgrf_id The NewGRF ID to map. * @param gender Whether to map genders or cases. * @return The, to OpenTTD's internal ID, mapped index, or -1 if there is no mapping. */ int LanguageMap::GetMapping(int newgrf_id, bool gender) const { const SmallVector &map = gender ? this->gender_map : this->case_map; for (const Mapping *m = map.Begin(); m != map.End(); m++) { if (m->newgrf_id == newgrf_id) return m->openttd_id; } return -1; } /** * Get the mapping from OpenTTD's internal ID to the NewGRF supplied ID. * @param openttd_id The OpenTTD ID to map. * @param gender Whether to map genders or cases. * @return The, to the NewGRF supplied ID, mapped index, or -1 if there is no mapping. */ int LanguageMap::GetReverseMapping(int openttd_id, bool gender) const { const SmallVector &map = gender ? this->gender_map : this->case_map; for (const Mapping *m = map.Begin(); m != map.End(); m++) { if (m->openttd_id == openttd_id) return m->newgrf_id; } return -1; } /** Helper structure for mapping choice lists. */ struct UnmappedChoiceList : ZeroedMemoryAllocator { /** Clean everything up. */ ~UnmappedChoiceList() { for (SmallPair *p = this->strings.Begin(); p < this->strings.End(); p++) { free(p->second); } } /** * Initialise the mapping. * @param type The type of mapping. * @param old_d The old begin of the string, i.e. from where to start writing again. * @param offset The offset to get the plural/gender from. */ UnmappedChoiceList(StringControlCode type, char *old_d, int offset) : type(type), old_d(old_d), offset(offset) { } StringControlCode type; ///< The type of choice list. char *old_d; ///< The old/original location of the "d" local variable. int offset; ///< The offset for the plural/gender form. /** Mapping of NewGRF supplied ID to the different strings in the choice list. */ SmallMap strings; /** * Flush this choice list into the old d variable. * @param lm The current language mapping. * @return The new location of the output string. */ char *Flush(const LanguageMap *lm) { if (!this->strings.Contains(0)) { /* In case of a (broken) NewGRF without a default, * assume an empty string. */ grfmsg(1, "choice list misses default value"); this->strings[0] = stredup(""); } char *d = old_d; if (lm == NULL) { /* In case there is no mapping, just ignore everything but the default. * A probable cause for this happening is when the language file has * been removed by the user and as such no mapping could be made. */ size_t len = strlen(this->strings[0]); memcpy(d, this->strings[0], len); return d + len; } d += Utf8Encode(d, this->type); if (this->type == SCC_SWITCH_CASE) { /* * Format for case switch: * * Each LEN is printed using 2 bytes in big endian order. */ /* "" */ int count = 0; for (uint8 i = 0; i < _current_language->num_cases; i++) { /* Count the ones we have a mapped string for. */ if (this->strings.Contains(lm->GetReverseMapping(i, false))) count++; } *d++ = count; for (uint8 i = 0; i < _current_language->num_cases; i++) { /* Resolve the string we're looking for. */ int idx = lm->GetReverseMapping(i, false); if (!this->strings.Contains(idx)) continue; char *str = this->strings[idx]; /* "" */ *d++ = i + 1; /* "" */ size_t len = strlen(str) + 1; *d++ = GB(len, 8, 8); *d++ = GB(len, 0, 8); /* "" */ memcpy(d, str, len); d += len; } /* "" */ size_t len = strlen(this->strings[0]) + 1; memcpy(d, this->strings[0], len); d += len; } else { if (this->type == SCC_PLURAL_LIST) { *d++ = lm->plural_form; } /* * Format for choice list: * */ /* "" */ *d++ = this->offset - 0x80; /* "" */ int count = (this->type == SCC_GENDER_LIST ? _current_language->num_genders : LANGUAGE_MAX_PLURAL_FORMS); *d++ = count; /* "" */ for (int i = 0; i < count; i++) { int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1); const char *str = this->strings[this->strings.Contains(idx) ? idx : 0]; size_t len = strlen(str) + 1; if (len > 0xFF) grfmsg(1, "choice list string is too long"); *d++ = GB(len, 0, 8); } /* "" */ for (int i = 0; i < count; i++) { int idx = (this->type == SCC_GENDER_LIST ? lm->GetReverseMapping(i, true) : i + 1); const char *str = this->strings[this->strings.Contains(idx) ? idx : 0]; /* Limit the length of the string we copy to 0xFE. The length is written above * as a byte and we need room for the final '\0'. */ size_t len = min(0xFE, strlen(str)); memcpy(d, str, len); d += len; *d++ = '\0'; } } return d; } }; /** * Translate TTDPatch string codes into something OpenTTD can handle (better). * @param grfid The (NewGRF) ID associated with this string * @param language_id The (NewGRF) language ID associated with this string. * @param allow_newlines Whether newlines are allowed in the string or not. * @param str The string to translate. * @param [out] olen The length of the final string. * @param byte80 The control code to use as replacement for the 0x80-value. * @return The translated string. */ char *TranslateTTDPatchCodes(uint32 grfid, uint8 language_id, bool allow_newlines, const char *str, int *olen, StringControlCode byte80) { char *tmp = MallocT(strlen(str) * 10 + 1); // Allocate space to allow for expansion char *d = tmp; bool unicode = false; WChar c; size_t len = Utf8Decode(&c, str); /* Helper variable for a possible (string) mapping. */ UnmappedChoiceList *mapping = NULL; if (c == NFO_UTF8_IDENTIFIER) { unicode = true; str += len; } for (;;) { if (unicode && Utf8EncodedCharLen(*str) != 0) { c = Utf8Consume(&str); /* 'Magic' range of control codes. */ if (GB(c, 8, 8) == 0xE0) { c = GB(c, 0, 8); } else if (c >= 0x20) { if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?'; d += Utf8Encode(d, c); continue; } } else { c = (byte)*str++; } if (c == '\0') break; switch (c) { case 0x01: if (str[0] == '\0') goto string_end; d += Utf8Encode(d, ' '); str++; break; case 0x0A: break; case 0x0D: if (allow_newlines) { *d++ = 0x0A; } else { grfmsg(1, "Detected newline in string that does not allow one"); } break; case 0x0E: d += Utf8Encode(d, SCC_TINYFONT); break; case 0x0F: d += Utf8Encode(d, SCC_BIGFONT); break; case 0x1F: if (str[0] == '\0' || str[1] == '\0') goto string_end; d += Utf8Encode(d, ' '); str += 2; break; case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_SIGNED + c - 0x7B); break; case 0x80: d += Utf8Encode(d, byte80); break; case 0x81: { if (str[0] == '\0' || str[1] == '\0') goto string_end; StringID string; string = ((uint8)*str++); string |= ((uint8)*str++) << 8; d += Utf8Encode(d, SCC_NEWGRF_STRINL); d += Utf8Encode(d, MapGRFStringID(grfid, string)); break; } case 0x82: case 0x83: case 0x84: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_DATE_LONG + c - 0x82); break; case 0x85: d += Utf8Encode(d, SCC_NEWGRF_DISCARD_WORD); break; case 0x86: d += Utf8Encode(d, SCC_NEWGRF_ROTATE_TOP_4_WORDS); break; case 0x87: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_VOLUME_LONG); break; case 0x88: d += Utf8Encode(d, SCC_BLUE); break; case 0x89: d += Utf8Encode(d, SCC_SILVER); break; case 0x8A: d += Utf8Encode(d, SCC_GOLD); break; case 0x8B: d += Utf8Encode(d, SCC_RED); break; case 0x8C: d += Utf8Encode(d, SCC_PURPLE); break; case 0x8D: d += Utf8Encode(d, SCC_LTBROWN); break; case 0x8E: d += Utf8Encode(d, SCC_ORANGE); break; case 0x8F: d += Utf8Encode(d, SCC_GREEN); break; case 0x90: d += Utf8Encode(d, SCC_YELLOW); break; case 0x91: d += Utf8Encode(d, SCC_DKGREEN); break; case 0x92: d += Utf8Encode(d, SCC_CREAM); break; case 0x93: d += Utf8Encode(d, SCC_BROWN); break; case 0x94: d += Utf8Encode(d, SCC_WHITE); break; case 0x95: d += Utf8Encode(d, SCC_LTBLUE); break; case 0x96: d += Utf8Encode(d, SCC_GRAY); break; case 0x97: d += Utf8Encode(d, SCC_DKBLUE); break; case 0x98: d += Utf8Encode(d, SCC_BLACK); break; case 0x9A: { int code = *str++; switch (code) { case 0x00: goto string_end; case 0x01: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_CURRENCY); break; /* 0x02: ignore next colour byte is not supported. It works on the final * string and as such hooks into the string drawing routine. At that * point many things already happened, such as splitting up of strings * when drawn over multiple lines or right-to-left translations, which * make the behaviour peculiar, e.g. only happening at specific width * of windows. Or we need to add another pass over the string to just * support this. As such it is not implemented in OpenTTD. */ case 0x03: { if (str[0] == '\0' || str[1] == '\0') goto string_end; uint16 tmp = ((uint8)*str++); tmp |= ((uint8)*str++) << 8; d += Utf8Encode(d, SCC_NEWGRF_PUSH_WORD); d += Utf8Encode(d, tmp); break; } case 0x04: if (str[0] == '\0') goto string_end; d += Utf8Encode(d, SCC_NEWGRF_UNPRINT); d += Utf8Encode(d, *str++); break; case 0x06: d += Utf8Encode(d, SCC_NEWGRF_PRINT_BYTE_HEX); break; case 0x07: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_HEX); break; case 0x08: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_HEX); break; /* 0x09, 0x0A are TTDPatch internal use only string codes. */ case 0x0B: d += Utf8Encode(d, SCC_NEWGRF_PRINT_QWORD_HEX); break; case 0x0C: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_STATION_NAME); break; case 0x0D: d += Utf8Encode(d, SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG); break; case 0x0E: case 0x0F: { if (str[0] == '\0') goto string_end; const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id); int index = *str++; int mapped = lm != NULL ? lm->GetMapping(index, code == 0x0E) : -1; if (mapped >= 0) { d += Utf8Encode(d, code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE); d += Utf8Encode(d, code == 0x0E ? mapped : mapped + 1); } break; } case 0x10: case 0x11: if (str[0] == '\0') goto string_end; if (mapping == NULL) { if (code == 0x10) str++; // Skip the index grfmsg(1, "choice list %s marker found when not expected", code == 0x10 ? "next" : "default"); break; } else { /* Terminate the previous string. */ *d = '\0'; int index = (code == 0x10 ? *str++ : 0); if (mapping->strings.Contains(index)) { grfmsg(1, "duplicate choice list string, ignoring"); d++; } else { d = mapping->strings[index] = MallocT(strlen(str) * 10 + 1); } } break; case 0x12: if (mapping == NULL) { grfmsg(1, "choice list end marker found when not expected"); } else { /* Terminate the previous string. */ *d = '\0'; /* Now we can start flushing everything and clean everything up. */ d = mapping->Flush(LanguageMap::GetLanguageMap(grfid, language_id)); delete mapping; mapping = NULL; } break; case 0x13: case 0x14: case 0x15: if (str[0] == '\0') goto string_end; if (mapping != NULL) { grfmsg(1, "choice lists can't be stacked, it's going to get messy now..."); if (code != 0x14) str++; } else { static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST }; mapping = new UnmappedChoiceList(mp[code - 0x13], d, code == 0x14 ? 0 : *str++); } break; case 0x16: case 0x17: case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: d += Utf8Encode(d, SCC_NEWGRF_PRINT_DWORD_DATE_LONG + code - 0x16); break; default: grfmsg(1, "missing handler for extended format code"); break; } break; } case 0x9E: d += Utf8Encode(d, 0x20AC); break; // Euro case 0x9F: d += Utf8Encode(d, 0x0178); break; // Y with diaeresis case 0xA0: d += Utf8Encode(d, SCC_UP_ARROW); break; case 0xAA: d += Utf8Encode(d, SCC_DOWN_ARROW); break; case 0xAC: d += Utf8Encode(d, SCC_CHECKMARK); break; case 0xAD: d += Utf8Encode(d, SCC_CROSS); break; case 0xAF: d += Utf8Encode(d, SCC_RIGHT_ARROW); break; case 0xB4: d += Utf8Encode(d, SCC_TRAIN); break; case 0xB5: d += Utf8Encode(d, SCC_LORRY); break; case 0xB6: d += Utf8Encode(d, SCC_BUS); break; case 0xB7: d += Utf8Encode(d, SCC_PLANE); break; case 0xB8: d += Utf8Encode(d, SCC_SHIP); break; case 0xB9: d += Utf8Encode(d, SCC_SUPERSCRIPT_M1); break; case 0xBC: d += Utf8Encode(d, SCC_SMALL_UP_ARROW); break; case 0xBD: d += Utf8Encode(d, SCC_SMALL_DOWN_ARROW); break; default: /* Validate any unhandled character */ if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?'; d += Utf8Encode(d, c); break; } } string_end: if (mapping != NULL) { grfmsg(1, "choice list was incomplete, the whole list is ignored"); delete mapping; } *d = '\0'; if (olen != NULL) *olen = d - tmp + 1; tmp = ReallocT(tmp, d - tmp + 1); return tmp; } /** * Add a GRFText to a GRFText list. * @param list The list where the text should be added to. * @param text_to_add The GRFText to add to the list. */ void AddGRFTextToList(GRFText **list, GRFText *text_to_add) { GRFText **ptext, *text; /* Loop through all languages and see if we can replace a string */ for (ptext = list; (text = *ptext) != NULL; ptext = &text->next) { if (text->langid == text_to_add->langid) { text_to_add->next = text->next; *ptext = text_to_add; delete text; return; } } /* If a string wasn't replaced, then we must append the new string */ *ptext = text_to_add; } /** * Add a string to a GRFText list. * @param list The list where the text should be added to. * @param langid The language of the new text. * @param grfid The grfid where this string is defined. * @param allow_newlines Whether newlines are allowed in this string. * @param text_to_add The text to add to the list. * @note All text-codes will be translated. */ void AddGRFTextToList(struct GRFText **list, byte langid, uint32 grfid, bool allow_newlines, const char *text_to_add) { int len; char *translatedtext = TranslateTTDPatchCodes(grfid, langid, allow_newlines, text_to_add, &len); GRFText *newtext = GRFText::New(langid, translatedtext, len); free(translatedtext); AddGRFTextToList(list, newtext); } /** * Add a GRFText to a GRFText list. The text should not contain any text-codes. * The text will be added as a 'default language'-text. * @param list The list where the text should be added to. * @param text_to_add The text to add to the list. */ void AddGRFTextToList(struct GRFText **list, const char *text_to_add) { AddGRFTextToList(list, GRFText::New(0x7F, text_to_add, strlen(text_to_add) + 1)); } /** * Create a copy of this GRFText list. * @param orig The GRFText list to copy. * @return A duplicate of the given GRFText. */ GRFText *DuplicateGRFText(GRFText *orig) { GRFText *newtext = NULL; GRFText **ptext = &newtext; for (; orig != NULL; orig = orig->next) { *ptext = GRFText::Copy(orig); ptext = &(*ptext)->next; } return newtext; } /** * Add the new read string into our structure. */ StringID AddGRFString(uint32 grfid, uint16 stringid, byte langid_to_add, bool new_scheme, bool allow_newlines, const char *text_to_add, StringID def_string) { char *translatedtext; uint id; /* When working with the old language scheme (grf_version is less than 7) and * English or American is among the set bits, simply add it as English in * the new scheme, i.e. as langid = 1. * If English is set, it is pretty safe to assume the translations are not * actually translated. */ if (!new_scheme) { if (langid_to_add & (GRFLB_AMERICAN | GRFLB_ENGLISH)) { langid_to_add = GRFLX_ENGLISH; } else { StringID ret = STR_EMPTY; if (langid_to_add & GRFLB_GERMAN) ret = AddGRFString(grfid, stringid, GRFLX_GERMAN, true, allow_newlines, text_to_add, def_string); if (langid_to_add & GRFLB_FRENCH) ret = AddGRFString(grfid, stringid, GRFLX_FRENCH, true, allow_newlines, text_to_add, def_string); if (langid_to_add & GRFLB_SPANISH) ret = AddGRFString(grfid, stringid, GRFLX_SPANISH, true, allow_newlines, text_to_add, def_string); return ret; } } for (id = 0; id < _num_grf_texts; id++) { if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) { break; } } /* Too many strings allocated, return empty */ if (id == lengthof(_grf_text)) return STR_EMPTY; int len; translatedtext = TranslateTTDPatchCodes(grfid, langid_to_add, allow_newlines, text_to_add, &len); GRFText *newtext = GRFText::New(langid_to_add, translatedtext, len); free(translatedtext); /* If we didn't find our stringid and grfid in the list, allocate a new id */ if (id == _num_grf_texts) _num_grf_texts++; if (_grf_text[id].textholder == NULL) { _grf_text[id].grfid = grfid; _grf_text[id].stringid = stringid; _grf_text[id].def_string = def_string; } AddGRFTextToList(&_grf_text[id].textholder, newtext); grfmsg(3, "Added 0x%X: grfid %08X string 0x%X lang 0x%X string '%s'", id, grfid, stringid, newtext->langid, newtext->text); return (GRFTAB << TABSIZE) + id; } /** * Returns the index for this stringid associated with its grfID */ StringID GetGRFStringID(uint32 grfid, uint16 stringid) { for (uint id = 0; id < _num_grf_texts; id++) { if (_grf_text[id].grfid == grfid && _grf_text[id].stringid == stringid) { return (GRFTAB << TABSIZE) + id; } } return STR_UNDEFINED; } /** * Get a C-string from a GRFText-list. If there is a translation for the * current language it is returned, otherwise the default translation * is returned. If there is neither a default nor a translation for the * current language NULL is returned. * @param text The GRFText to get the string from. */ const char *GetGRFStringFromGRFText(const GRFText *text) { const char *default_text = NULL; /* Search the list of lang-strings of this stringid for current lang */ for (; text != NULL; text = text->next) { if (text->langid == _currentLangID) return text->text; /* If the current string is English or American, set it as the * fallback language if the specific language isn't available. */ if (text->langid == GRFLX_UNSPECIFIED || (default_text == NULL && (text->langid == GRFLX_ENGLISH || text->langid == GRFLX_AMERICAN))) { default_text = text->text; } } return default_text; } /** * Get a C-string from a stringid set by a newgrf. */ const char *GetGRFStringPtr(uint16 stringid) { assert(_grf_text[stringid].grfid != 0); const char *str = GetGRFStringFromGRFText(_grf_text[stringid].textholder); if (str != NULL) return str; /* Use the default string ID if the fallback string isn't available */ return GetStringPtr(_grf_text[stringid].def_string); } /** * Equivalence Setter function between game and newgrf langID. * This function will adjust _currentLangID as to what is the LangID * of the current language set by the user. * This function is called after the user changed language, * from strings.cpp:ReadLanguagePack * @param language_id iso code of current selection */ void SetCurrentGrfLangID(byte language_id) { _currentLangID = language_id; } bool CheckGrfLangID(byte lang_id, byte grf_version) { if (grf_version < 7) { switch (_currentLangID) { case GRFLX_GERMAN: return (lang_id & GRFLB_GERMAN) != 0; case GRFLX_FRENCH: return (lang_id & GRFLB_FRENCH) != 0; case GRFLX_SPANISH: return (lang_id & GRFLB_SPANISH) != 0; default: return (lang_id & (GRFLB_ENGLISH | GRFLB_AMERICAN)) != 0; } } return (lang_id == _currentLangID || lang_id == GRFLX_UNSPECIFIED); } /** * Delete all items of a linked GRFText list. * @param grftext the head of the list to delete */ void CleanUpGRFText(GRFText *grftext) { while (grftext != NULL) { GRFText *grftext2 = grftext->next; delete grftext; grftext = grftext2; } } /** * House cleaning. * Remove all strings and reset the text counter. */ void CleanUpStrings() { uint id; for (id = 0; id < _num_grf_texts; id++) { CleanUpGRFText(_grf_text[id].textholder); _grf_text[id].grfid = 0; _grf_text[id].stringid = 0; _grf_text[id].textholder = NULL; } _num_grf_texts = 0; } struct TextRefStack { byte stack[0x30]; byte position; const GRFFile *grffile; bool used; TextRefStack() : position(0), grffile(NULL), used(false) {} TextRefStack(const TextRefStack &stack) : position(stack.position), grffile(stack.grffile), used(stack.used) { memcpy(this->stack, stack.stack, sizeof(this->stack)); } uint8 PopUnsignedByte() { assert(this->position < lengthof(this->stack)); return this->stack[this->position++]; } int8 PopSignedByte() { return (int8)this->PopUnsignedByte(); } uint16 PopUnsignedWord() { uint16 val = this->PopUnsignedByte(); return val | (this->PopUnsignedByte() << 8); } int16 PopSignedWord() { return (int32)this->PopUnsignedWord(); } uint32 PopUnsignedDWord() { uint32 val = this->PopUnsignedWord(); return val | (this->PopUnsignedWord() << 16); } int32 PopSignedDWord() { return (int32)this->PopUnsignedDWord(); } uint64 PopUnsignedQWord() { uint64 val = this->PopUnsignedDWord(); return val | (((uint64)this->PopUnsignedDWord()) << 32); } int64 PopSignedQWord() { return (int64)this->PopUnsignedQWord(); } /** Rotate the top four words down: W1, W2, W3, W4 -> W4, W1, W2, W3 */ void RotateTop4Words() { byte tmp[2]; for (int i = 0; i < 2; i++) tmp[i] = this->stack[this->position + i + 6]; for (int i = 5; i >= 0; i--) this->stack[this->position + i + 2] = this->stack[this->position + i]; for (int i = 0; i < 2; i++) this->stack[this->position + i] = tmp[i]; } void PushWord(uint16 word) { if (this->position >= 2) { this->position -= 2; } else { for (int i = lengthof(stack) - 1; i >= this->position + 2; i--) { this->stack[i] = this->stack[i - 2]; } } this->stack[this->position] = GB(word, 0, 8); this->stack[this->position + 1] = GB(word, 8, 8); } void ResetStack(const GRFFile *grffile) { assert(grffile != NULL); this->position = 0; this->grffile = grffile; this->used = true; } void RewindStack() { this->position = 0; } }; /** The stack that is used for TTDP compatible string code parsing */ static TextRefStack _newgrf_textrefstack; /** * Check whether the NewGRF text stack is in use. * @return True iff the NewGRF text stack is used. */ bool UsingNewGRFTextStack() { return _newgrf_textrefstack.used; } /** * Create a backup of the current NewGRF text stack. * @return A copy of the current text stack. */ struct TextRefStack *CreateTextRefStackBackup() { return new TextRefStack(_newgrf_textrefstack); } /** * Restore a copy of the text stack to the used stack. * @param backup The copy to restore. */ void RestoreTextRefStackBackup(struct TextRefStack *backup) { _newgrf_textrefstack = *backup; delete backup; } /** * Start using the TTDP compatible string code parsing. * * On start a number of values is copied on the #TextRefStack. * You can then use #GetString() and the normal string drawing functions, * and they will use the #TextRefStack for NewGRF string codes. * * However, when you want to draw a string multiple times using the same stack, * you have to call #RewindTextRefStack() between draws. * * After you are done with drawing, you must disable usage of the #TextRefStack * by calling #StopTextRefStackUsage(), so NewGRF string codes operate on the * normal string parameters again. * * @param grffile the NewGRF providing the stack data * @param numEntries number of entries to copy from the registers * @param values values to copy onto the stack; if NULL the temporary NewGRF registers will be used instead */ void StartTextRefStackUsage(const GRFFile *grffile, byte numEntries, const uint32 *values) { extern TemporaryStorageArray _temp_store; _newgrf_textrefstack.ResetStack(grffile); byte *p = _newgrf_textrefstack.stack; for (uint i = 0; i < numEntries; i++) { uint32 value = values != NULL ? values[i] : _temp_store.GetValue(0x100 + i); for (uint j = 0; j < 32; j += 8) { *p = GB(value, j, 8); p++; } } } /** Stop using the TTDP compatible string code parsing */ void StopTextRefStackUsage() { _newgrf_textrefstack.used = false; } void RewindTextRefStack() { _newgrf_textrefstack.RewindStack(); } /** * FormatString for NewGRF specific "magic" string control codes * @param scc the string control code that has been read * @param buff the buffer we're writing to * @param str the string that we need to write * @param argv the OpenTTD stack of values * @param argv_size space on the stack \a argv * @param modify_argv When true, modify the OpenTTD stack. * @return the string control code to "execute" now */ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const char **str, int64 *argv, uint argv_size, bool modify_argv) { switch (scc) { default: break; case SCC_NEWGRF_PRINT_DWORD_SIGNED: case SCC_NEWGRF_PRINT_WORD_SIGNED: case SCC_NEWGRF_PRINT_BYTE_SIGNED: case SCC_NEWGRF_PRINT_WORD_UNSIGNED: case SCC_NEWGRF_PRINT_BYTE_HEX: case SCC_NEWGRF_PRINT_WORD_HEX: case SCC_NEWGRF_PRINT_DWORD_HEX: case SCC_NEWGRF_PRINT_QWORD_HEX: case SCC_NEWGRF_PRINT_DWORD_CURRENCY: case SCC_NEWGRF_PRINT_QWORD_CURRENCY: case SCC_NEWGRF_PRINT_WORD_STRING_ID: case SCC_NEWGRF_PRINT_WORD_DATE_LONG: case SCC_NEWGRF_PRINT_DWORD_DATE_LONG: case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT: case SCC_NEWGRF_PRINT_WORD_SPEED: case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG: case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT: case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG: case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT: case SCC_NEWGRF_PRINT_WORD_POWER: case SCC_NEWGRF_PRINT_WORD_STATION_NAME: if (argv_size < 1) { DEBUG(misc, 0, "Too many NewGRF string parameters."); return 0; } break; case SCC_NEWGRF_PRINT_WORD_CARGO_LONG: case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT: case SCC_NEWGRF_PRINT_WORD_CARGO_TINY: if (argv_size < 2) { DEBUG(misc, 0, "Too many NewGRF string parameters."); return 0; } break; } if (_newgrf_textrefstack.used && modify_argv) { switch (scc) { default: NOT_REACHED(); case SCC_NEWGRF_PRINT_BYTE_SIGNED: *argv = _newgrf_textrefstack.PopSignedByte(); break; case SCC_NEWGRF_PRINT_QWORD_CURRENCY: *argv = _newgrf_textrefstack.PopSignedQWord(); break; case SCC_NEWGRF_PRINT_DWORD_CURRENCY: case SCC_NEWGRF_PRINT_DWORD_SIGNED: *argv = _newgrf_textrefstack.PopSignedDWord(); break; case SCC_NEWGRF_PRINT_BYTE_HEX: *argv = _newgrf_textrefstack.PopUnsignedByte(); break; case SCC_NEWGRF_PRINT_QWORD_HEX: *argv = _newgrf_textrefstack.PopUnsignedQWord(); break; case SCC_NEWGRF_PRINT_WORD_SPEED: case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG: case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT: case SCC_NEWGRF_PRINT_WORD_SIGNED: *argv = _newgrf_textrefstack.PopSignedWord(); break; case SCC_NEWGRF_PRINT_WORD_HEX: case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG: case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT: case SCC_NEWGRF_PRINT_WORD_POWER: case SCC_NEWGRF_PRINT_WORD_STATION_NAME: case SCC_NEWGRF_PRINT_WORD_UNSIGNED: *argv = _newgrf_textrefstack.PopUnsignedWord(); break; case SCC_NEWGRF_PRINT_DWORD_DATE_LONG: case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT: case SCC_NEWGRF_PRINT_DWORD_HEX: *argv = _newgrf_textrefstack.PopUnsignedDWord(); break; case SCC_NEWGRF_PRINT_WORD_DATE_LONG: case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: *argv = _newgrf_textrefstack.PopUnsignedWord() + DAYS_TILL_ORIGINAL_BASE_YEAR; break; case SCC_NEWGRF_DISCARD_WORD: _newgrf_textrefstack.PopUnsignedWord(); break; case SCC_NEWGRF_ROTATE_TOP_4_WORDS: _newgrf_textrefstack.RotateTop4Words(); break; case SCC_NEWGRF_PUSH_WORD: _newgrf_textrefstack.PushWord(Utf8Consume(str)); break; case SCC_NEWGRF_UNPRINT: *buff = max(*buff - Utf8Consume(str), buf_start); break; case SCC_NEWGRF_PRINT_WORD_CARGO_LONG: case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT: case SCC_NEWGRF_PRINT_WORD_CARGO_TINY: argv[0] = GetCargoTranslation(_newgrf_textrefstack.PopUnsignedWord(), _newgrf_textrefstack.grffile); argv[1] = _newgrf_textrefstack.PopUnsignedWord(); break; case SCC_NEWGRF_PRINT_WORD_STRING_ID: *argv = MapGRFStringID(_newgrf_textrefstack.grffile->grfid, _newgrf_textrefstack.PopUnsignedWord()); break; } } else { /* Consume additional parameter characters */ switch (scc) { default: break; case SCC_NEWGRF_PUSH_WORD: case SCC_NEWGRF_UNPRINT: Utf8Consume(str); break; } } switch (scc) { default: NOT_REACHED(); case SCC_NEWGRF_PRINT_DWORD_SIGNED: case SCC_NEWGRF_PRINT_WORD_SIGNED: case SCC_NEWGRF_PRINT_BYTE_SIGNED: case SCC_NEWGRF_PRINT_WORD_UNSIGNED: return SCC_COMMA; case SCC_NEWGRF_PRINT_BYTE_HEX: case SCC_NEWGRF_PRINT_WORD_HEX: case SCC_NEWGRF_PRINT_DWORD_HEX: case SCC_NEWGRF_PRINT_QWORD_HEX: return SCC_HEX; case SCC_NEWGRF_PRINT_DWORD_CURRENCY: case SCC_NEWGRF_PRINT_QWORD_CURRENCY: return SCC_CURRENCY_LONG; case SCC_NEWGRF_PRINT_WORD_STRING_ID: return SCC_NEWGRF_PRINT_WORD_STRING_ID; case SCC_NEWGRF_PRINT_WORD_DATE_LONG: case SCC_NEWGRF_PRINT_DWORD_DATE_LONG: return SCC_DATE_LONG; case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT: return SCC_DATE_SHORT; case SCC_NEWGRF_PRINT_WORD_SPEED: return SCC_VELOCITY; case SCC_NEWGRF_PRINT_WORD_VOLUME_LONG: return SCC_VOLUME_LONG; case SCC_NEWGRF_PRINT_WORD_VOLUME_SHORT: return SCC_VOLUME_SHORT; case SCC_NEWGRF_PRINT_WORD_WEIGHT_LONG: return SCC_WEIGHT_LONG; case SCC_NEWGRF_PRINT_WORD_WEIGHT_SHORT: return SCC_WEIGHT_SHORT; case SCC_NEWGRF_PRINT_WORD_POWER: return SCC_POWER; case SCC_NEWGRF_PRINT_WORD_CARGO_LONG: return SCC_CARGO_LONG; case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT: return SCC_CARGO_SHORT; case SCC_NEWGRF_PRINT_WORD_CARGO_TINY: return SCC_CARGO_TINY; case SCC_NEWGRF_PRINT_WORD_STATION_NAME: return SCC_STATION_NAME; case SCC_NEWGRF_DISCARD_WORD: case SCC_NEWGRF_ROTATE_TOP_4_WORDS: case SCC_NEWGRF_PUSH_WORD: case SCC_NEWGRF_UNPRINT: return 0; } } openttd-1.5.3/src/autoreplace.cpp0000644000000000000000000001134712627373434015513 0ustar rootroot/* $Id: autoreplace.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 autoreplace.cpp Management of replacement lists. */ #include "stdafx.h" #include "command_func.h" #include "group.h" #include "autoreplace_base.h" #include "core/pool_func.hpp" #include "safeguards.h" /** The pool of autoreplace "orders". */ EngineRenewPool _enginerenew_pool("EngineRenew"); INSTANTIATE_POOL_METHODS(EngineRenew) /** * Retrieves the EngineRenew that specifies the replacement of the given * engine type from the given renewlist */ static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine, GroupID group) { EngineRenew *er = (EngineRenew *)erl; while (er != NULL) { if (er->from == engine && GroupIsInGroup(group, er->group_id)) return er; er = er->next; } return NULL; } /** * Remove all engine replacement settings for the company. * @param erl The renewlist for a given company. * @return The new renewlist for the company. */ void RemoveAllEngineReplacement(EngineRenewList *erl) { EngineRenew *er = (EngineRenew *)(*erl); EngineRenew *next; while (er != NULL) { next = er->next; delete er; er = next; } *erl = NULL; // Empty list } /** * Retrieve the engine replacement in a given renewlist for an original engine type. * @param erl The renewlist to search in. * @param engine Engine type to be replaced. * @param group The group related to this replacement. * @param[out] replace_when_old Set to true if the replacement should be done when old. * @return The engine type to replace with, or INVALID_ENGINE if no * replacement is in the list. */ EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old) { const EngineRenew *er = GetEngineReplacement(erl, engine, group); if (er == NULL && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !Group::Get(group)->replace_protection))) { /* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */ er = GetEngineReplacement(erl, engine, ALL_GROUP); } if (replace_when_old != NULL) *replace_when_old = er == NULL ? false : er->replace_when_old; return er == NULL ? INVALID_ENGINE : er->to; } /** * Add an engine replacement to the given renewlist. * @param erl The renewlist to add to. * @param old_engine The original engine type. * @param new_engine The replacement engine type. * @param group The group related to this replacement. * @param replace_when_old Replace when old or always? * @param flags The calling command flags. * @return 0 on success, CMD_ERROR on failure. */ CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags) { /* Check if the old vehicle is already in the list */ EngineRenew *er = GetEngineReplacement(*erl, old_engine, group); if (er != NULL) { if (flags & DC_EXEC) { er->to = new_engine; er->replace_when_old = replace_when_old; } return CommandCost(); } if (!EngineRenew::CanAllocateItem()) return CMD_ERROR; if (flags & DC_EXEC) { er = new EngineRenew(old_engine, new_engine); er->group_id = group; er->replace_when_old = replace_when_old; /* Insert before the first element */ er->next = (EngineRenew *)(*erl); *erl = (EngineRenewList)er; } return CommandCost(); } /** * Remove an engine replacement from a given renewlist. * @param erl The renewlist from which to remove the replacement * @param engine The original engine type. * @param group The group related to this replacement. * @param flags The calling command flags. * @return 0 on success, CMD_ERROR on failure. */ CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, DoCommandFlag flags) { EngineRenew *er = (EngineRenew *)(*erl); EngineRenew *prev = NULL; while (er != NULL) { if (er->from == engine && er->group_id == group) { if (flags & DC_EXEC) { if (prev == NULL) { // First element /* The second becomes the new first element */ *erl = (EngineRenewList)er->next; } else { /* Cut this element out */ prev->next = er->next; } delete er; } return CommandCost(); } prev = er; er = er->next; } return CMD_ERROR; } openttd-1.5.3/src/industry_gui.cpp0000644000000000000000000031102712627373441015730 0ustar rootroot/* $Id: industry_gui.cpp 26960 2014-10-05 11:20:02Z peter1138 $ */ /* * 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 industry_gui.cpp GUIs related to industries. */ #include "stdafx.h" #include "error.h" #include "gui.h" #include "settings_gui.h" #include "sound_func.h" #include "window_func.h" #include "textbuf_gui.h" #include "command_func.h" #include "viewport_func.h" #include "industry.h" #include "town.h" #include "cheat_type.h" #include "newgrf_industries.h" #include "newgrf_text.h" #include "newgrf_debug.h" #include "network/network.h" #include "strings_func.h" #include "company_func.h" #include "tilehighlight_func.h" #include "string_func.h" #include "sortlist_type.h" #include "widgets/dropdown_func.h" #include "company_base.h" #include "core/geometry_func.hpp" #include "core/random_func.hpp" #include "core/backup_type.hpp" #include "genworld.h" #include "smallmap_gui.h" #include "widgets/dropdown_type.h" #include "widgets/industry_widget.h" #include "table/strings.h" #include "safeguards.h" bool _ignore_restrictions; uint64 _displayed_industries; ///< Communication from the industry chain window to the smallmap window about what industries to display. assert_compile(NUM_INDUSTRYTYPES <= 64); // Make sure all industry types fit in _displayed_industries. /** Cargo suffix type (for which window is it requested) */ enum CargoSuffixType { CST_FUND, ///< Fund-industry window CST_VIEW, ///< View-industry window CST_DIR, ///< Industry-directory window }; static void ShowIndustryCargoesWindow(IndustryType id); /** * Gets the string to display after the cargo name (using callback 37) * @param cargo the cargo for which the suffix is requested * - 00 - first accepted cargo type * - 01 - second accepted cargo type * - 02 - third accepted cargo type * - 03 - first produced cargo type * - 04 - second produced cargo type * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType * @param ind the industry (NULL if in fund window) * @param ind_type the industry type * @param indspec the industry spec * @param suffix is filled with the string to display * @param suffix_last lastof(suffix) */ static void GetCargoSuffix(uint cargo, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, char *suffix, const char *suffix_last) { suffix[0] = '\0'; if (HasBit(indspec->callback_mask, CBM_IND_CARGO_SUFFIX)) { uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, const_cast(ind), ind_type, (cst != CST_FUND) ? ind->location.tile : INVALID_TILE); if (callback == CALLBACK_FAILED || callback == 0x400) return; if (callback > 0x400) { ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_CARGO_SUFFIX, callback); } else if (indspec->grf_prop.grffile->grf_version >= 8 || GB(callback, 0, 8) != 0xFF) { StartTextRefStackUsage(indspec->grf_prop.grffile, 6); GetString(suffix, GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback), suffix_last); StopTextRefStackUsage(); } } } /** * Gets all strings to display after the cargoes of industries (using callback 37) * @param cb_offset The offset for the cargo used in cb37, 0 for accepted cargoes, 3 for produced cargoes * @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType * @param ind the industry (NULL if in fund window) * @param ind_type the industry type * @param indspec the industry spec * @param cargoes array with cargotypes. for CT_INVALID no suffix will be determined * @param suffixes is filled with the suffixes */ template static inline void GetAllCargoSuffixes(uint cb_offset, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes) { assert_compile(lengthof(cargoes) <= lengthof(suffixes)); for (uint j = 0; j < lengthof(cargoes); j++) { if (cargoes[j] != CT_INVALID) { GetCargoSuffix(cb_offset + j, cst, ind, ind_type, indspec, suffixes[j], lastof(suffixes[j])); } else { suffixes[j][0] = '\0'; } } } IndustryType _sorted_industry_types[NUM_INDUSTRYTYPES]; ///< Industry types sorted by name. /** Sort industry types by their name. */ static int CDECL IndustryTypeNameSorter(const IndustryType *a, const IndustryType *b) { static char industry_name[2][64]; const IndustrySpec *indsp1 = GetIndustrySpec(*a); GetString(industry_name[0], indsp1->name, lastof(industry_name[0])); const IndustrySpec *indsp2 = GetIndustrySpec(*b); GetString(industry_name[1], indsp2->name, lastof(industry_name[1])); int r = strnatcmp(industry_name[0], industry_name[1]); // Sort by name (natural sorting). /* If the names are equal, sort by industry type. */ return (r != 0) ? r : (*a - *b); } /** * Initialize the list of sorted industry types. */ void SortIndustryTypes() { /* Add each industry type to the list. */ for (IndustryType i = 0; i < NUM_INDUSTRYTYPES; i++) { _sorted_industry_types[i] = i; } /* Sort industry types by name. */ QSortT(_sorted_industry_types, NUM_INDUSTRYTYPES, &IndustryTypeNameSorter); } /** * Command callback. In case of failure to build an industry, show an error message. * @param result Result of the command. * @param tile Tile where the industry is placed. * @param p1 Additional data of the #CMD_BUILD_INDUSTRY command. * @param p2 Additional data of the #CMD_BUILD_INDUSTRY command. */ void CcBuildIndustry(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Succeeded()) return; uint8 indtype = GB(p1, 0, 8); if (indtype < NUM_INDUSTRYTYPES) { const IndustrySpec *indsp = GetIndustrySpec(indtype); if (indsp->enabled) { SetDParam(0, indsp->name); ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, result.GetErrorMessage(), WL_INFO, TileX(tile) * TILE_SIZE, TileY(tile) * TILE_SIZE); } } } static const NWidgetPart _nested_build_industry_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_FUND_INDUSTRY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_DARK_GREEN, WID_DPI_MATRIX_WIDGET), SetMatrixDataTip(1, 0, STR_FUND_INDUSTRY_SELECTION_TOOLTIP), SetFill(1, 0), SetResize(1, 1), SetScrollbar(WID_DPI_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_DPI_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_DPI_INFOPANEL), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_DPI_DISPLAY_WIDGET), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_DPI_FUND_WIDGET), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_JUST_STRING, STR_NULL), NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), EndContainer(), }; /** Window definition of the dynamic place industries gui */ static WindowDesc _build_industry_desc( WDP_AUTO, "build_industry", 170, 212, WC_BUILD_INDUSTRY, WC_NONE, WDF_CONSTRUCTION, _nested_build_industry_widgets, lengthof(_nested_build_industry_widgets) ); /** Build (fund or prospect) a new industry, */ class BuildIndustryWindow : public Window { int selected_index; ///< index of the element in the matrix IndustryType selected_type; ///< industry corresponding to the above index uint16 callback_timer; ///< timer counter for callback eventual verification bool timer_enabled; ///< timer can be used uint16 count; ///< How many industries are loaded IndustryType index[NUM_INDUSTRYTYPES + 1]; ///< Type of industry, in the order it was loaded bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_PROBABILITY (if ever) Scrollbar *vscroll; /** The offset for the text in the matrix. */ static const int MATRIX_TEXT_OFFSET = 17; void SetupArrays() { this->count = 0; for (uint i = 0; i < lengthof(this->index); i++) { this->index[i] = INVALID_INDUSTRYTYPE; this->enabled[i] = false; } if (_game_mode == GM_EDITOR) { // give room for the Many Random "button" this->index[this->count] = INVALID_INDUSTRYTYPE; this->enabled[this->count] = true; this->count++; this->timer_enabled = false; } /* Fill the arrays with industries. * The tests performed after the enabled allow to load the industries * In the same way they are inserted by grf (if any) */ for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { IndustryType ind = _sorted_industry_types[i]; const IndustrySpec *indsp = GetIndustrySpec(ind); if (indsp->enabled) { /* Rule is that editor mode loads all industries. * In game mode, all non raw industries are loaded too * and raw ones are loaded only when setting allows it */ if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _settings_game.construction.raw_industry_construction == 0) { /* Unselect if the industry is no longer in the list */ if (this->selected_type == ind) this->selected_index = -1; continue; } this->index[this->count] = ind; this->enabled[this->count] = (_game_mode == GM_EDITOR) || GetIndustryProbabilityCallback(ind, IACT_USERCREATION, 1) > 0; /* Keep the selection to the correct line */ if (this->selected_type == ind) this->selected_index = this->count; this->count++; } } /* first industry type is selected if the current selection is invalid. * I'll be damned if there are none available ;) */ if (this->selected_index == -1) { this->selected_index = 0; this->selected_type = this->index[0]; } this->vscroll->SetCount(this->count); } /** Update status of the fund and display-chain widgets. */ void SetButtons() { this->SetWidgetDisabledState(WID_DPI_FUND_WIDGET, this->selected_type != INVALID_INDUSTRYTYPE && !this->enabled[this->selected_index]); this->SetWidgetDisabledState(WID_DPI_DISPLAY_WIDGET, this->selected_type == INVALID_INDUSTRYTYPE && this->enabled[this->selected_index]); } public: BuildIndustryWindow() : Window(&_build_industry_desc) { this->timer_enabled = _loaded_newgrf_features.has_newindustries; this->selected_index = -1; this->selected_type = INVALID_INDUSTRYTYPE; this->callback_timer = DAY_TICKS; this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_DPI_SCROLLBAR); this->FinishInitNested(0); this->SetButtons(); } virtual void OnInit() { this->SetupArrays(); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_DPI_MATRIX_WIDGET: { Dimension d = GetStringBoundingBox(STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES); for (byte i = 0; i < this->count; i++) { if (this->index[i] == INVALID_INDUSTRYTYPE) continue; d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); } resize->height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; d.width += MATRIX_TEXT_OFFSET + padding.width; d.height = 5 * resize->height; *size = maxdim(*size, d); break; } case WID_DPI_INFOPANEL: { /* Extra line for cost outside of editor + extra lines for 'extra' information for NewGRFs. */ int height = 2 + (_game_mode == GM_EDITOR ? 0 : 1) + (_loaded_newgrf_features.has_newindustries ? 4 : 0); Dimension d = {0, 0}; for (byte i = 0; i < this->count; i++) { if (this->index[i] == INVALID_INDUSTRYTYPE) continue; const IndustrySpec *indsp = GetIndustrySpec(this->index[i]); char cargo_suffix[3][512]; GetAllCargoSuffixes(0, CST_FUND, NULL, this->index[i], indsp, indsp->accepts_cargo, cargo_suffix); StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; byte p = 0; SetDParam(0, STR_JUST_NOTHING); SetDParamStr(1, ""); for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { if (indsp->accepts_cargo[j] == CT_INVALID) continue; if (p > 0) str++; SetDParam(p++, CargoSpec::Get(indsp->accepts_cargo[j])->name); SetDParamStr(p++, cargo_suffix[j]); } d = maxdim(d, GetStringBoundingBox(str)); /* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */ GetAllCargoSuffixes(3, CST_FUND, NULL, this->index[i], indsp, indsp->produced_cargo, cargo_suffix); str = STR_INDUSTRY_VIEW_PRODUCES_CARGO; p = 0; SetDParam(0, STR_JUST_NOTHING); SetDParamStr(1, ""); for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { if (indsp->produced_cargo[j] == CT_INVALID) continue; if (p > 0) str++; SetDParam(p++, CargoSpec::Get(indsp->produced_cargo[j])->name); SetDParamStr(p++, cargo_suffix[j]); } d = maxdim(d, GetStringBoundingBox(str)); } /* Set it to something more sane :) */ size->height = height * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; size->width = d.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; break; } case WID_DPI_FUND_WIDGET: { Dimension d = GetStringBoundingBox(STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY); d = maxdim(d, GetStringBoundingBox(STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY)); d = maxdim(d, GetStringBoundingBox(STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY)); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } } } virtual void SetStringParameters(int widget) const { switch (widget) { case WID_DPI_FUND_WIDGET: /* Raw industries might be prospected. Show this fact by changing the string * In Editor, you just build, while ingame, or you fund or you prospect */ if (_game_mode == GM_EDITOR) { /* We've chosen many random industries but no industries have been specified */ SetDParam(0, STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY); } else { const IndustrySpec *indsp = GetIndustrySpec(this->index[this->selected_index]); SetDParam(0, (_settings_game.construction.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY : STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY); } break; } } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_DPI_MATRIX_WIDGET: { uint text_left, text_right, icon_left, icon_right; if (_current_text_dir == TD_RTL) { icon_right = r.right - WD_MATRIX_RIGHT; icon_left = icon_right - 10; text_right = icon_right - BuildIndustryWindow::MATRIX_TEXT_OFFSET; text_left = r.left + WD_MATRIX_LEFT; } else { icon_left = r.left + WD_MATRIX_LEFT; icon_right = icon_left + 10; text_left = icon_left + BuildIndustryWindow::MATRIX_TEXT_OFFSET; text_right = r.right - WD_MATRIX_RIGHT; } for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++) { int y = r.top + WD_MATRIX_TOP + i * this->resize.step_height; bool selected = this->selected_index == i + this->vscroll->GetPosition(); if (this->index[i + this->vscroll->GetPosition()] == INVALID_INDUSTRYTYPE) { DrawString(text_left, text_right, y, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE); continue; } const IndustrySpec *indsp = GetIndustrySpec(this->index[i + this->vscroll->GetPosition()]); /* Draw the name of the industry in white is selected, otherwise, in orange */ DrawString(text_left, text_right, y, indsp->name, selected ? TC_WHITE : TC_ORANGE); GfxFillRect(icon_left, y + 1, icon_right, y + 7, selected ? PC_WHITE : PC_BLACK); GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + 6, indsp->map_colour); } break; } case WID_DPI_INFOPANEL: { int y = r.top + WD_FRAMERECT_TOP; int bottom = r.bottom - WD_FRAMERECT_BOTTOM; int left = r.left + WD_FRAMERECT_LEFT; int right = r.right - WD_FRAMERECT_RIGHT; if (this->selected_type == INVALID_INDUSTRYTYPE) { DrawStringMultiLine(left, right, y, bottom, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP); break; } const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); if (_game_mode != GM_EDITOR) { SetDParam(0, indsp->GetConstructionCost()); DrawString(left, right, y, STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST); y += FONT_HEIGHT_NORMAL; } /* Draw the accepted cargoes, if any. Otherwise, will print "Nothing". */ char cargo_suffix[3][512]; GetAllCargoSuffixes(0, CST_FUND, NULL, this->selected_type, indsp, indsp->accepts_cargo, cargo_suffix); StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; byte p = 0; SetDParam(0, STR_JUST_NOTHING); SetDParamStr(1, ""); for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { if (indsp->accepts_cargo[j] == CT_INVALID) continue; if (p > 0) str++; SetDParam(p++, CargoSpec::Get(indsp->accepts_cargo[j])->name); SetDParamStr(p++, cargo_suffix[j]); } DrawString(left, right, y, str); y += FONT_HEIGHT_NORMAL; /* Draw the produced cargoes, if any. Otherwise, will print "Nothing". */ GetAllCargoSuffixes(3, CST_FUND, NULL, this->selected_type, indsp, indsp->produced_cargo, cargo_suffix); str = STR_INDUSTRY_VIEW_PRODUCES_CARGO; p = 0; SetDParam(0, STR_JUST_NOTHING); SetDParamStr(1, ""); for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { if (indsp->produced_cargo[j] == CT_INVALID) continue; if (p > 0) str++; SetDParam(p++, CargoSpec::Get(indsp->produced_cargo[j])->name); SetDParamStr(p++, cargo_suffix[j]); } DrawString(left, right, y, str); y += FONT_HEIGHT_NORMAL; /* Get the additional purchase info text, if it has not already been queried. */ str = STR_NULL; if (HasBit(indsp->callback_mask, CBM_IND_FUND_MORE_TEXT)) { uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE); if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { if (callback_res > 0x400) { ErrorUnknownCallbackResult(indsp->grf_prop.grffile->grfid, CBID_INDUSTRY_FUND_MORE_TEXT, callback_res); } else { str = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string if (str != STR_UNDEFINED) { StartTextRefStackUsage(indsp->grf_prop.grffile, 6); DrawStringMultiLine(left, right, y, bottom, str, TC_YELLOW); StopTextRefStackUsage(); } } } } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_DPI_MATRIX_WIDGET: { int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_DPI_MATRIX_WIDGET); if (y < this->count) { // Is it within the boundaries of available data? this->selected_index = y; this->selected_type = this->index[y]; const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); this->SetDirty(); if (_thd.GetCallbackWnd() == this && ((_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) || this->selected_type == INVALID_INDUSTRYTYPE || !this->enabled[this->selected_index])) { /* Reset the button state if going to prospecting or "build many industries" */ this->RaiseButtons(); ResetObjectToPlace(); } this->SetButtons(); if (this->enabled[this->selected_index] && click_count > 1) this->OnClick(pt, WID_DPI_FUND_WIDGET, 1); } break; } case WID_DPI_DISPLAY_WIDGET: if (this->selected_type != INVALID_INDUSTRYTYPE) ShowIndustryCargoesWindow(this->selected_type); break; case WID_DPI_FUND_WIDGET: { if (this->selected_type == INVALID_INDUSTRYTYPE) { this->HandleButtonClick(WID_DPI_FUND_WIDGET); if (Town::GetNumItems() == 0) { ShowErrorMessage(STR_ERROR_CAN_T_GENERATE_INDUSTRIES, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO); } else { extern void GenerateIndustries(); _generating_world = true; GenerateIndustries(); _generating_world = false; } } else if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && GetIndustrySpec(this->selected_type)->IsRawIndustry()) { DoCommandP(0, this->selected_type, InteractiveRandom(), CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); this->HandleButtonClick(WID_DPI_FUND_WIDGET); } else { HandlePlacePushButton(this, WID_DPI_FUND_WIDGET, SPR_CURSOR_INDUSTRY, HT_RECT); } break; } } } virtual void OnResize() { /* Adjust the number of items in the matrix depending of the resize */ this->vscroll->SetCapacityFromWidget(this, WID_DPI_MATRIX_WIDGET); } virtual void OnPlaceObject(Point pt, TileIndex tile) { bool success = true; /* We do not need to protect ourselves against "Random Many Industries" in this mode */ const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); uint32 seed = InteractiveRandom(); if (_game_mode == GM_EDITOR) { /* Show error if no town exists at all */ if (Town::GetNumItems() == 0) { SetDParam(0, indsp->name); ShowErrorMessage(STR_ERROR_CAN_T_BUILD_HERE, STR_ERROR_MUST_FOUND_TOWN_FIRST, WL_INFO, pt.x, pt.y); return; } Backup cur_company(_current_company, OWNER_NONE, FILE_LINE); _generating_world = true; _ignore_restrictions = true; DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY), &CcBuildIndustry); cur_company.Restore(); _ignore_restrictions = false; _generating_world = false; } else { success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 8) | this->selected_type, seed, CMD_BUILD_INDUSTRY | CMD_MSG(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY)); } /* If an industry has been built, just reset the cursor and the system */ if (success && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } virtual void OnTick() { if (_pause_mode != PM_UNPAUSED) return; if (!this->timer_enabled) return; if (--this->callback_timer == 0) { /* We have just passed another day. * See if we need to update availability of currently selected industry */ this->callback_timer = DAY_TICKS; // restart counter const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); if (indsp->enabled) { bool call_back_result = GetIndustryProbabilityCallback(this->selected_type, IACT_USERCREATION, 1) > 0; /* Only if result does match the previous state would it require a redraw. */ if (call_back_result != this->enabled[this->selected_index]) { this->enabled[this->selected_index] = call_back_result; this->SetButtons(); this->SetDirty(); } } } } virtual void OnTimeout() { this->RaiseButtons(); } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); } /** * 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->SetupArrays(); const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.industry_density != ID_FUND_ONLY; this->SetButtons(); } }; void ShowBuildIndustryWindow() { if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return; new BuildIndustryWindow(); } static void UpdateIndustryProduction(Industry *i); static inline bool IsProductionAlterable(const Industry *i) { const IndustrySpec *is = GetIndustrySpec(i->type); return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) && (is->production_rate[0] != 0 || is->production_rate[1] != 0 || is->IsRawIndustry()) && !_networking); } class IndustryViewWindow : public Window { /** Modes for changing production */ enum Editability { EA_NONE, ///< Not alterable EA_MULTIPLIER, ///< Allow changing the production multiplier EA_RATE, ///< Allow changing the production rates }; /** Specific lines in the info panel */ enum InfoLine { IL_NONE, ///< No line IL_MULTIPLIER, ///< Production multiplier IL_RATE1, ///< Production rate of cargo 1 IL_RATE2, ///< Production rate of cargo 2 }; Editability editable; ///< Mode for changing production InfoLine editbox_line; ///< The line clicked to open the edit box InfoLine clicked_line; ///< The line of the button that has been clicked byte clicked_button; ///< The button that has been clicked (to raise) int production_offset_y; ///< The offset of the production texts/buttons int info_height; ///< Height needed for the #WID_IV_INFO panel public: IndustryViewWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->flags |= WF_DISABLE_VP_SCROLL; this->editbox_line = IL_NONE; this->clicked_line = IL_NONE; this->clicked_button = 0; this->info_height = WD_FRAMERECT_TOP + 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM + 1; // Info panel has at least two lines text. this->InitNested(window_number); NWidgetViewport *nvp = this->GetWidget(WID_IV_VIEWPORT); nvp->InitializeViewport(this, Industry::Get(window_number)->location.GetCenterTile(), ZOOM_LVL_INDUSTRY); this->InvalidateData(); } virtual void OnPaint() { this->DrawWidgets(); if (this->IsShaded()) return; // Don't draw anything when the window is shaded. NWidgetBase *nwi = this->GetWidget(WID_IV_INFO); uint expected = this->DrawInfo(nwi->pos_x, nwi->pos_x + nwi->current_x - 1, nwi->pos_y) - nwi->pos_y; if (expected > nwi->current_y - 1) { this->info_height = expected + 1; this->ReInit(); return; } } /** * Draw the text in the #WID_IV_INFO panel. * @param left Left edge of the panel. * @param right Right edge of the panel. * @param top Top edge of the panel. * @return Expected position of the bottom edge of the panel. */ int DrawInfo(uint left, uint right, uint top) { Industry *i = Industry::Get(this->window_number); const IndustrySpec *ind = GetIndustrySpec(i->type); int y = top + WD_FRAMERECT_TOP; bool first = true; bool has_accept = false; char cargo_suffix[3][512]; if (i->prod_level == PRODLEVEL_CLOSURE) { DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE); y += 2 * FONT_HEIGHT_NORMAL; } if (HasBit(ind->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) { GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix); for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { if (i->accepts_cargo[j] == CT_INVALID) continue; has_accept = true; if (first) { DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING); y += FONT_HEIGHT_NORMAL; first = false; } SetDParam(0, i->accepts_cargo[j]); SetDParam(1, i->incoming_cargo_waiting[j]); SetDParamStr(2, cargo_suffix[j]); DrawString(left + WD_FRAMETEXT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO); y += FONT_HEIGHT_NORMAL; } } else { GetAllCargoSuffixes(0, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix); StringID str = STR_INDUSTRY_VIEW_REQUIRES_CARGO; byte p = 0; for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { if (i->accepts_cargo[j] == CT_INVALID) continue; has_accept = true; if (p > 0) str++; SetDParam(p++, CargoSpec::Get(i->accepts_cargo[j])->name); SetDParamStr(p++, cargo_suffix[j]); } if (has_accept) { DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, str); y += FONT_HEIGHT_NORMAL; } } GetAllCargoSuffixes(3, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix); first = true; for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == CT_INVALID) continue; if (first) { if (has_accept) y += WD_PAR_VSEP_WIDE; DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE); y += FONT_HEIGHT_NORMAL; if (this->editable == EA_RATE) this->production_offset_y = y; first = false; } SetDParam(0, i->produced_cargo[j]); SetDParam(1, i->last_month_production[j]); SetDParamStr(2, cargo_suffix[j]); SetDParam(3, ToPercent8(i->last_month_pct_transported[j])); uint x = left + WD_FRAMETEXT_LEFT + (this->editable == EA_RATE ? SETTING_BUTTON_WIDTH + 10 : 0); DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_TRANSPORTED); /* Let's put out those buttons.. */ if (this->editable == EA_RATE) { DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_RATE1 + j) ? this->clicked_button : 0, i->production_rate[j] > 0, i->production_rate[j] < 255); } y += FONT_HEIGHT_NORMAL; } /* Display production multiplier if editable */ if (this->editable == EA_MULTIPLIER) { y += WD_PAR_VSEP_WIDE; this->production_offset_y = y; SetDParam(0, RoundDivSU(i->prod_level * 100, PRODLEVEL_DEFAULT)); uint x = left + WD_FRAMETEXT_LEFT + SETTING_BUTTON_WIDTH + 10; DrawString(x, right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_VIEW_PRODUCTION_LEVEL); DrawArrowButtons(left + WD_FRAMETEXT_LEFT, y, COLOUR_YELLOW, (this->clicked_line == IL_MULTIPLIER) ? this->clicked_button : 0, i->prod_level > PRODLEVEL_MINIMUM, i->prod_level < PRODLEVEL_MAXIMUM); y += FONT_HEIGHT_NORMAL; } /* Get the extra message for the GUI */ if (HasBit(ind->callback_mask, CBM_IND_WINDOW_MORE_TEXT)) { uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->location.tile); if (callback_res != CALLBACK_FAILED && callback_res != 0x400) { if (callback_res > 0x400) { ErrorUnknownCallbackResult(ind->grf_prop.grffile->grfid, CBID_INDUSTRY_WINDOW_MORE_TEXT, callback_res); } else { StringID message = GetGRFStringID(ind->grf_prop.grffile->grfid, 0xD000 + callback_res); if (message != STR_NULL && message != STR_UNDEFINED) { y += WD_PAR_VSEP_WIDE; StartTextRefStackUsage(ind->grf_prop.grffile, 6); /* Use all the available space left from where we stand up to the * end of the window. We ALSO enlarge the window if needed, so we * can 'go' wild with the bottom of the window. */ y = DrawStringMultiLine(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, y, UINT16_MAX, message, TC_BLACK); StopTextRefStackUsage(); } } } } return y + WD_FRAMERECT_BOTTOM; } virtual void SetStringParameters(int widget) const { if (widget == WID_IV_CAPTION) SetDParam(0, this->window_number); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_IV_INFO) size->height = this->info_height; } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_IV_INFO: { Industry *i = Industry::Get(this->window_number); InfoLine line = IL_NONE; switch (this->editable) { case EA_NONE: break; case EA_MULTIPLIER: if (IsInsideBS(pt.y, this->production_offset_y, FONT_HEIGHT_NORMAL)) line = IL_MULTIPLIER; break; case EA_RATE: if (pt.y >= this->production_offset_y) { int row = (pt.y - this->production_offset_y) / FONT_HEIGHT_NORMAL; for (uint j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == CT_INVALID) continue; row--; if (row < 0) { line = (InfoLine)(IL_RATE1 + j); break; } } } break; } if (line == IL_NONE) return; NWidgetBase *nwi = this->GetWidget(widget); int left = nwi->pos_x + WD_FRAMETEXT_LEFT; int right = nwi->pos_x + nwi->current_x - 1 - WD_FRAMERECT_RIGHT; if (IsInsideMM(pt.x, left, left + SETTING_BUTTON_WIDTH)) { /* Clicked buttons, decrease or increase production */ byte button = (pt.x < left + SETTING_BUTTON_WIDTH / 2) ? 1 : 2; switch (this->editable) { case EA_MULTIPLIER: if (button == 1) { if (i->prod_level <= PRODLEVEL_MINIMUM) return; i->prod_level = max(i->prod_level / 2, PRODLEVEL_MINIMUM); } else { if (i->prod_level >= PRODLEVEL_MAXIMUM) return; i->prod_level = minu(i->prod_level * 2, PRODLEVEL_MAXIMUM); } break; case EA_RATE: if (button == 1) { if (i->production_rate[line - IL_RATE1] <= 0) return; i->production_rate[line - IL_RATE1] = max(i->production_rate[line - IL_RATE1] / 2, 0); } else { if (i->production_rate[line - IL_RATE1] >= 255) return; /* a zero production industry is unlikely to give anything but zero, so push it a little bit */ int new_prod = i->production_rate[line - IL_RATE1] == 0 ? 1 : i->production_rate[line - IL_RATE1] * 2; i->production_rate[line - IL_RATE1] = minu(new_prod, 255); } break; default: NOT_REACHED(); } UpdateIndustryProduction(i); this->SetDirty(); this->SetTimeout(); this->clicked_line = line; this->clicked_button = button; } else if (IsInsideMM(pt.x, left + SETTING_BUTTON_WIDTH + 10, right)) { /* clicked the text */ this->editbox_line = line; switch (this->editable) { case EA_MULTIPLIER: SetDParam(0, RoundDivSU(i->prod_level * 100, PRODLEVEL_DEFAULT)); ShowQueryString(STR_JUST_INT, STR_CONFIG_GAME_PRODUCTION_LEVEL, 10, this, CS_ALPHANUMERAL, QSF_NONE); break; case EA_RATE: SetDParam(0, i->production_rate[line - IL_RATE1] * 8); ShowQueryString(STR_JUST_INT, STR_CONFIG_GAME_PRODUCTION, 10, this, CS_ALPHANUMERAL, QSF_NONE); break; default: NOT_REACHED(); } } break; } case WID_IV_GOTO: { Industry *i = Industry::Get(this->window_number); if (_ctrl_pressed) { ShowExtraViewPortWindow(i->location.GetCenterTile()); } else { ScrollMainWindowToTile(i->location.GetCenterTile()); } break; } case WID_IV_DISPLAY: { Industry *i = Industry::Get(this->window_number); ShowIndustryCargoesWindow(i->type); break; } } } virtual void OnTimeout() { this->clicked_line = IL_NONE; this->clicked_button = 0; this->SetDirty(); } virtual void OnResize() { if (this->viewport != NULL) { NWidgetViewport *nvp = this->GetWidget(WID_IV_VIEWPORT); nvp->UpdateViewportCoordinates(this); ScrollWindowToTile(Industry::Get(this->window_number)->location.GetCenterTile(), this, true); // Re-center viewport. } } virtual void OnQueryTextFinished(char *str) { if (StrEmpty(str)) return; Industry *i = Industry::Get(this->window_number); uint value = atoi(str); switch (this->editbox_line) { case IL_NONE: NOT_REACHED(); case IL_MULTIPLIER: i->prod_level = ClampU(RoundDivSU(value * PRODLEVEL_DEFAULT, 100), PRODLEVEL_MINIMUM, PRODLEVEL_MAXIMUM); break; default: i->production_rate[this->editbox_line - IL_RATE1] = ClampU(RoundDivSU(value, 8), 0, 255); break; } UpdateIndustryProduction(i); this->SetDirty(); } /** * 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; const Industry *i = Industry::Get(this->window_number); if (IsProductionAlterable(i)) { const IndustrySpec *ind = GetIndustrySpec(i->type); this->editable = ind->UsesSmoothEconomy() ? EA_RATE : EA_MULTIPLIER; } else { this->editable = EA_NONE; } } virtual bool IsNewGRFInspectable() const { return ::IsNewGRFInspectable(GSF_INDUSTRIES, this->window_number); } virtual void ShowNewGRFInspectWindow() const { ::ShowNewGRFInspectWindow(GSF_INDUSTRIES, this->window_number); } }; static void UpdateIndustryProduction(Industry *i) { const IndustrySpec *indspec = GetIndustrySpec(i->type); if (!indspec->UsesSmoothEconomy()) i->RecomputeProductionMultipliers(); for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] != CT_INVALID) { i->last_month_production[j] = 8 * i->production_rate[j]; } } } /** Widget definition of the view industry gui */ static const NWidgetPart _nested_industry_view_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_CREAM), NWidget(WWT_CAPTION, COLOUR_CREAM, WID_IV_CAPTION), SetDataTip(STR_INDUSTRY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEBUGBOX, COLOUR_CREAM), NWidget(WWT_SHADEBOX, COLOUR_CREAM), NWidget(WWT_DEFSIZEBOX, COLOUR_CREAM), NWidget(WWT_STICKYBOX, COLOUR_CREAM), EndContainer(), NWidget(WWT_PANEL, COLOUR_CREAM), NWidget(WWT_INSET, COLOUR_CREAM), SetPadding(2, 2, 2, 2), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_IV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetPadding(1, 1, 1, 1), SetResize(1, 1), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_CREAM, WID_IV_INFO), SetMinimalSize(260, 2), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_GOTO), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_BUTTON_LOCATION, STR_INDUSTRY_VIEW_LOCATION_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_CREAM, WID_IV_DISPLAY), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_INDUSTRY_DISPLAY_CHAIN, STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_CREAM), EndContainer(), }; /** Window definition of the view industry gui */ static WindowDesc _industry_view_desc( WDP_AUTO, "view_industry", 260, 120, WC_INDUSTRY_VIEW, WC_NONE, 0, _nested_industry_view_widgets, lengthof(_nested_industry_view_widgets) ); void ShowIndustryViewWindow(int industry) { AllocateWindowDescFront(&_industry_view_desc, industry); } /** Widget definition of the industry directory gui */ static const NWidgetPart _nested_industry_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_INDUSTRY_DIRECTORY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_ID_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), }; typedef GUIList GUIIndustryList; /** * The list of industries. */ class IndustryDirectoryWindow : public Window { protected: /* Runtime saved values */ static Listing last_sorting; static const Industry *last_industry; /* Constants for sorting stations */ static const StringID sorter_names[]; static GUIIndustryList::SortFunction * const sorter_funcs[]; GUIIndustryList industries; Scrollbar *vscroll; /** (Re)Build industries list */ void BuildSortIndustriesList() { if (this->industries.NeedRebuild()) { this->industries.Clear(); const Industry *i; FOR_ALL_INDUSTRIES(i) { *this->industries.Append() = i; } this->industries.Compact(); this->industries.RebuildDone(); this->vscroll->SetCount(this->industries.Length()); // Update scrollbar as well. } if (!this->industries.Sort()) return; IndustryDirectoryWindow::last_industry = NULL; // Reset name sorter sort cache this->SetWidgetDirty(WID_ID_INDUSTRY_LIST); // Set the modified widget dirty } /** * Returns percents of cargo transported if industry produces this cargo, else -1 * * @param i industry to check * @param id cargo slot * @return percents of cargo transported, or -1 if industry doesn't use this cargo slot */ static inline int GetCargoTransportedPercentsIfValid(const Industry *i, uint id) { assert(id < lengthof(i->produced_cargo)); if (i->produced_cargo[id] == CT_INVALID) return 101; return ToPercent8(i->last_month_pct_transported[id]); } /** * Returns value representing industry's transported cargo * percentage for industry sorting * * @param i industry to check * @return value used for sorting */ static int GetCargoTransportedSortValue(const Industry *i) { int p1 = GetCargoTransportedPercentsIfValid(i, 0); int p2 = GetCargoTransportedPercentsIfValid(i, 1); if (p1 > p2) Swap(p1, p2); // lower value has higher priority return (p1 << 8) + p2; } /** Sort industries by name */ static int CDECL IndustryNameSorter(const Industry * const *a, const Industry * const *b) { static char buf_cache[96]; static char buf[96]; SetDParam(0, (*a)->index); GetString(buf, STR_INDUSTRY_NAME, lastof(buf)); if (*b != last_industry) { last_industry = *b; SetDParam(0, (*b)->index); GetString(buf_cache, STR_INDUSTRY_NAME, lastof(buf_cache)); } return strnatcmp(buf, buf_cache); // Sort by name (natural sorting). } /** Sort industries by type and name */ static int CDECL IndustryTypeSorter(const Industry * const *a, const Industry * const *b) { int it_a = 0; while (it_a != NUM_INDUSTRYTYPES && (*a)->type != _sorted_industry_types[it_a]) it_a++; int it_b = 0; while (it_b != NUM_INDUSTRYTYPES && (*b)->type != _sorted_industry_types[it_b]) it_b++; int r = it_a - it_b; return (r == 0) ? IndustryNameSorter(a, b) : r; } /** Sort industries by production and name */ static int CDECL IndustryProductionSorter(const Industry * const *a, const Industry * const *b) { uint prod_a = 0, prod_b = 0; for (uint i = 0; i < lengthof((*a)->produced_cargo); i++) { if ((*a)->produced_cargo[i] != CT_INVALID) prod_a += (*a)->last_month_production[i]; if ((*b)->produced_cargo[i] != CT_INVALID) prod_b += (*b)->last_month_production[i]; } int r = prod_a - prod_b; return (r == 0) ? IndustryTypeSorter(a, b) : r; } /** Sort industries by transported cargo and name */ static int CDECL IndustryTransportedCargoSorter(const Industry * const *a, const Industry * const *b) { int r = GetCargoTransportedSortValue(*a) - GetCargoTransportedSortValue(*b); return (r == 0) ? IndustryNameSorter(a, b) : r; } /** * Get the StringID to draw and set the appropriate DParams. * @param i the industry to get the StringID of. * @return the StringID. */ StringID GetIndustryString(const Industry *i) const { const IndustrySpec *indsp = GetIndustrySpec(i->type); byte p = 0; /* Industry name */ SetDParam(p++, i->index); static char cargo_suffix[lengthof(i->produced_cargo)][512]; GetAllCargoSuffixes(3, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix); /* Industry productions */ for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == CT_INVALID) continue; SetDParam(p++, i->produced_cargo[j]); SetDParam(p++, i->last_month_production[j]); SetDParamStr(p++, cargo_suffix[j]); } /* Transported productions */ for (byte j = 0; j < lengthof(i->produced_cargo); j++) { if (i->produced_cargo[j] == CT_INVALID) continue; SetDParam(p++, ToPercent8(i->last_month_pct_transported[j])); } /* Drawing the right string */ switch (p) { case 1: return STR_INDUSTRY_DIRECTORY_ITEM_NOPROD; case 5: return STR_INDUSTRY_DIRECTORY_ITEM; default: return STR_INDUSTRY_DIRECTORY_ITEM_TWO; } } public: IndustryDirectoryWindow(WindowDesc *desc, WindowNumber number) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_ID_SCROLLBAR); this->industries.SetListing(this->last_sorting); this->industries.SetSortFuncs(IndustryDirectoryWindow::sorter_funcs); this->industries.ForceRebuild(); this->BuildSortIndustriesList(); this->FinishInitNested(0); } ~IndustryDirectoryWindow() { this->last_sorting = this->industries.GetListing(); } virtual void SetStringParameters(int widget) const { if (widget == WID_ID_DROPDOWN_CRITERIA) SetDParam(0, IndustryDirectoryWindow::sorter_names[this->industries.SortType()]); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_ID_DROPDOWN_ORDER: this->DrawSortButtonState(widget, this->industries.IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; case WID_ID_INDUSTRY_LIST: { int n = 0; int y = r.top + WD_FRAMERECT_TOP; if (this->industries.Length() == 0) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_INDUSTRY_DIRECTORY_NONE); break; } for (uint i = this->vscroll->GetPosition(); i < this->industries.Length(); i++) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, this->GetIndustryString(this->industries[i])); y += this->resize.step_height; if (++n == this->vscroll->GetCapacity()) break; // max number of industries in 1 window } break; } } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_ID_DROPDOWN_ORDER: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_ID_DROPDOWN_CRITERIA: { Dimension d = {0, 0}; for (uint i = 0; IndustryDirectoryWindow::sorter_names[i] != INVALID_STRING_ID; i++) { d = maxdim(d, GetStringBoundingBox(IndustryDirectoryWindow::sorter_names[i])); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_ID_INDUSTRY_LIST: { Dimension d = GetStringBoundingBox(STR_INDUSTRY_DIRECTORY_NONE); for (uint i = 0; i < this->industries.Length(); i++) { d = maxdim(d, GetStringBoundingBox(this->GetIndustryString(this->industries[i]))); } resize->height = d.height; d.height *= 5; d.width += padding.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += padding.height + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_ID_DROPDOWN_ORDER: this->industries.ToggleSortOrder(); this->SetDirty(); break; case WID_ID_DROPDOWN_CRITERIA: ShowDropDownMenu(this, IndustryDirectoryWindow::sorter_names, this->industries.SortType(), WID_ID_DROPDOWN_CRITERIA, 0, 0); break; case WID_ID_INDUSTRY_LIST: { uint p = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_ID_INDUSTRY_LIST, WD_FRAMERECT_TOP); if (p < this->industries.Length()) { if (_ctrl_pressed) { ShowExtraViewPortWindow(this->industries[p]->location.tile); } else { ScrollMainWindowToTile(this->industries[p]->location.tile); } } break; } } } virtual void OnDropdownSelect(int widget, int index) { if (this->industries.SortType() != index) { this->industries.SetSortType(index); this->BuildSortIndustriesList(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_ID_INDUSTRY_LIST); } virtual void OnPaint() { if (this->industries.NeedRebuild()) this->BuildSortIndustriesList(); this->DrawWidgets(); } virtual void OnHundredthTick() { this->industries.ForceResort(); this->BuildSortIndustriesList(); } /** * 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 (data == 0) { /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */ this->industries.ForceRebuild(); } else { this->industries.ForceResort(); } } }; Listing IndustryDirectoryWindow::last_sorting = {false, 0}; const Industry *IndustryDirectoryWindow::last_industry = NULL; /* Available station sorting functions. */ GUIIndustryList::SortFunction * const IndustryDirectoryWindow::sorter_funcs[] = { &IndustryNameSorter, &IndustryTypeSorter, &IndustryProductionSorter, &IndustryTransportedCargoSorter }; /* Names of the sorting functions */ const StringID IndustryDirectoryWindow::sorter_names[] = { STR_SORT_BY_NAME, STR_SORT_BY_TYPE, STR_SORT_BY_PRODUCTION, STR_SORT_BY_TRANSPORTED, INVALID_STRING_ID }; /** Window definition of the industry directory gui */ static WindowDesc _industry_directory_desc( WDP_AUTO, "list_industries", 428, 190, WC_INDUSTRY_DIRECTORY, WC_NONE, 0, _nested_industry_directory_widgets, lengthof(_nested_industry_directory_widgets) ); void ShowIndustryDirectory() { AllocateWindowDescFront(&_industry_directory_desc, 0); } /** Widgets of the industry cargoes window. */ static const NWidgetPart _nested_industry_cargoes_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN, WID_IC_CAPTION), SetDataTip(STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_IC_PANEL), SetResize(1, 10), SetMinimalSize(200, 90), SetScrollbar(WID_IC_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_IC_NOTIFY), SetDataTip(STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP, STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP), NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 0), SetResize(0, 0), EndContainer(), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_IC_IND_DROPDOWN), SetFill(0, 0), SetResize(0, 0), SetDataTip(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY, STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_IC_CARGO_DROPDOWN), SetFill(0, 0), SetResize(0, 0), SetDataTip(STR_INDUSTRY_CARGOES_SELECT_CARGO, STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_IC_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), }; /** Window description for the industry cargoes window. */ static WindowDesc _industry_cargoes_desc( WDP_AUTO, "industry_cargoes", 300, 210, WC_INDUSTRY_CARGOES, WC_NONE, 0, _nested_industry_cargoes_widgets, lengthof(_nested_industry_cargoes_widgets) ); /** Available types of field. */ enum CargoesFieldType { CFT_EMPTY, ///< Empty field. CFT_SMALL_EMPTY, ///< Empty small field (for the header). CFT_INDUSTRY, ///< Display industry. CFT_CARGO, ///< Display cargo connections. CFT_CARGO_LABEL, ///< Display cargo labels. CFT_HEADER, ///< Header text. }; static const uint MAX_CARGOES = 3; ///< Maximum number of cargoes carried in a #CFT_CARGO field in #CargoesField. /** Data about a single field in the #IndustryCargoesWindow panel. */ struct CargoesField { static const int VERT_INTER_INDUSTRY_SPACE; static const int HOR_CARGO_BORDER_SPACE; static const int CARGO_STUB_WIDTH; static const int HOR_CARGO_WIDTH, HOR_CARGO_SPACE; static const int CARGO_FIELD_WIDTH; static const int VERT_CARGO_SPACE, VERT_CARGO_EDGE; static const int BLOB_DISTANCE, BLOB_WIDTH, BLOB_HEIGHT; static const int INDUSTRY_LINE_COLOUR; static const int CARGO_LINE_COLOUR; static int small_height, normal_height; static int industry_width; CargoesFieldType type; ///< Type of field. union { struct { IndustryType ind_type; ///< Industry type (#NUM_INDUSTRYTYPES means 'houses'). CargoID other_produced[MAX_CARGOES]; ///< Cargoes produced but not used in this figure. CargoID other_accepted[MAX_CARGOES]; ///< Cargoes accepted but not used in this figure. } industry; ///< Industry data (for #CFT_INDUSTRY). struct { CargoID vertical_cargoes[MAX_CARGOES]; ///< Cargoes running from top to bottom (cargo ID or #INVALID_CARGO). byte num_cargoes; ///< Number of cargoes. CargoID supp_cargoes[MAX_CARGOES]; ///< Cargoes entering from the left (index in #vertical_cargoes, or #INVALID_CARGO). byte top_end; ///< Stop at the top of the vertical cargoes. CargoID cust_cargoes[MAX_CARGOES]; ///< Cargoes leaving to the right (index in #vertical_cargoes, or #INVALID_CARGO). byte bottom_end; ///< Stop at the bottom of the vertical cargoes. } cargo; ///< Cargo data (for #CFT_CARGO). struct { CargoID cargoes[MAX_CARGOES]; ///< Cargoes to display (or #INVALID_CARGO). bool left_align; ///< Align all cargo texts to the left (else align to the right). } cargo_label; ///< Label data (for #CFT_CARGO_LABEL). StringID header; ///< Header text (for #CFT_HEADER). } u; // Data for each type. /** * Make one of the empty fields (#CFT_EMPTY or #CFT_SMALL_EMPTY). * @param type Type of empty field. */ void MakeEmpty(CargoesFieldType type) { this->type = type; } /** * Make an industry type field. * @param ind_type Industry type (#NUM_INDUSTRYTYPES means 'houses'). * @note #other_accepted and #other_produced should be filled later. */ void MakeIndustry(IndustryType ind_type) { this->type = CFT_INDUSTRY; this->u.industry.ind_type = ind_type; MemSetT(this->u.industry.other_accepted, INVALID_CARGO, MAX_CARGOES); MemSetT(this->u.industry.other_produced, INVALID_CARGO, MAX_CARGOES); } /** * Connect a cargo from an industry to the #CFT_CARGO column. * @param cargo Cargo to connect. * @param produced Cargo is produced (if \c false, cargo is assumed to be accepted). * @return Horizontal connection index, or \c -1 if not accepted at all. */ int ConnectCargo(CargoID cargo, bool producer) { assert(this->type == CFT_CARGO); if (cargo == INVALID_CARGO) return -1; /* Find the vertical cargo column carrying the cargo. */ int column = -1; for (int i = 0; i < this->u.cargo.num_cargoes; i++) { if (cargo == this->u.cargo.vertical_cargoes[i]) { column = i; break; } } if (column < 0) return -1; if (producer) { assert(this->u.cargo.supp_cargoes[column] == INVALID_CARGO); this->u.cargo.supp_cargoes[column] = column; } else { assert(this->u.cargo.cust_cargoes[column] == INVALID_CARGO); this->u.cargo.cust_cargoes[column] = column; } return column; } /** * Does this #CFT_CARGO field have a horizontal connection? * @return \c true if a horizontal connection exists, \c false otherwise. */ bool HasConnection() { assert(this->type == CFT_CARGO); for (uint i = 0; i < MAX_CARGOES; i++) { if (this->u.cargo.supp_cargoes[i] != INVALID_CARGO) return true; if (this->u.cargo.cust_cargoes[i] != INVALID_CARGO) return true; } return false; } /** * Make a piece of cargo column. * @param cargoes Array of #CargoID (may contain #INVALID_CARGO). * @param length Number of cargoes in \a cargoes. * @param count Number of cargoes to display (should be at least the number of valid cargoes, or \c -1 to let the method compute it). * @param top_end This is the first cargo field of this column. * @param bottom_end This is the last cargo field of this column. * @note #supp_cargoes and #cust_cargoes should be filled in later. */ void MakeCargo(const CargoID *cargoes, uint length, int count = -1, bool top_end = false, bool bottom_end = false) { this->type = CFT_CARGO; uint i; uint num = 0; for (i = 0; i < MAX_CARGOES && i < length; i++) { if (cargoes[i] != INVALID_CARGO) { this->u.cargo.vertical_cargoes[num] = cargoes[i]; num++; } } this->u.cargo.num_cargoes = (count < 0) ? num : count; for (; num < MAX_CARGOES; num++) this->u.cargo.vertical_cargoes[num] = INVALID_CARGO; this->u.cargo.top_end = top_end; this->u.cargo.bottom_end = bottom_end; MemSetT(this->u.cargo.supp_cargoes, INVALID_CARGO, MAX_CARGOES); MemSetT(this->u.cargo.cust_cargoes, INVALID_CARGO, MAX_CARGOES); } /** * Make a field displaying cargo type names. * @param cargoes Array of #CargoID (may contain #INVALID_CARGO). * @param length Number of cargoes in \a cargoes. * @param left_align ALign texts to the left (else to the right). */ void MakeCargoLabel(const CargoID *cargoes, uint length, bool left_align) { this->type = CFT_CARGO_LABEL; uint i; for (i = 0; i < MAX_CARGOES && i < length; i++) this->u.cargo_label.cargoes[i] = cargoes[i]; for (; i < MAX_CARGOES; i++) this->u.cargo_label.cargoes[i] = INVALID_CARGO; this->u.cargo_label.left_align = left_align; } /** * Make a header above an industry column. * @param textid Text to display. */ void MakeHeader(StringID textid) { this->type = CFT_HEADER; this->u.header = textid; } /** * For a #CFT_CARGO, compute the left position of the left-most vertical cargo connection. * @param xpos Left position of the field. * @return Left position of the left-most vertical cargo column. */ int GetCargoBase(int xpos) const { assert(this->type == CFT_CARGO); switch (this->u.cargo.num_cargoes) { case 0: return xpos + CARGO_FIELD_WIDTH / 2; case 1: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH / 2; case 2: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH - HOR_CARGO_SPACE / 2; case 3: return xpos + CARGO_FIELD_WIDTH / 2 - HOR_CARGO_WIDTH - HOR_CARGO_SPACE - HOR_CARGO_WIDTH / 2; default: NOT_REACHED(); } } /** * Draw the field. * @param xpos Position of the left edge. * @param vpos Position of the top edge. */ void Draw(int xpos, int ypos) const { switch (this->type) { case CFT_EMPTY: case CFT_SMALL_EMPTY: break; case CFT_HEADER: ypos += (small_height - FONT_HEIGHT_NORMAL) / 2; DrawString(xpos, xpos + industry_width, ypos, this->u.header, TC_WHITE, SA_HOR_CENTER); break; case CFT_INDUSTRY: { int ypos1 = ypos + VERT_INTER_INDUSTRY_SPACE / 2; int ypos2 = ypos + normal_height - 1 - VERT_INTER_INDUSTRY_SPACE / 2; int xpos2 = xpos + industry_width - 1; GfxDrawLine(xpos, ypos1, xpos2, ypos1, INDUSTRY_LINE_COLOUR); GfxDrawLine(xpos, ypos1, xpos, ypos2, INDUSTRY_LINE_COLOUR); GfxDrawLine(xpos, ypos2, xpos2, ypos2, INDUSTRY_LINE_COLOUR); GfxDrawLine(xpos2, ypos1, xpos2, ypos2, INDUSTRY_LINE_COLOUR); ypos += (normal_height - FONT_HEIGHT_NORMAL) / 2; if (this->u.industry.ind_type < NUM_INDUSTRYTYPES) { const IndustrySpec *indsp = GetIndustrySpec(this->u.industry.ind_type); DrawString(xpos, xpos2, ypos, indsp->name, TC_WHITE, SA_HOR_CENTER); /* Draw the industry legend. */ int blob_left, blob_right; if (_current_text_dir == TD_RTL) { blob_right = xpos2 - BLOB_DISTANCE; blob_left = blob_right - BLOB_WIDTH; } else { blob_left = xpos + BLOB_DISTANCE; blob_right = blob_left + BLOB_WIDTH; } GfxFillRect(blob_left, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT, blob_right, ypos2 - BLOB_DISTANCE, PC_BLACK); // Border GfxFillRect(blob_left + 1, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT + 1, blob_right - 1, ypos2 - BLOB_DISTANCE - 1, indsp->map_colour); } else { DrawString(xpos, xpos2, ypos, STR_INDUSTRY_CARGOES_HOUSES, TC_FROMSTRING, SA_HOR_CENTER); } /* Draw the other_produced/other_accepted cargoes. */ const CargoID *other_right, *other_left; if (_current_text_dir == TD_RTL) { other_right = this->u.industry.other_accepted; other_left = this->u.industry.other_produced; } else { other_right = this->u.industry.other_produced; other_left = this->u.industry.other_accepted; } ypos1 += VERT_CARGO_EDGE; for (uint i = 0; i < MAX_CARGOES; i++) { if (other_right[i] != INVALID_CARGO) { const CargoSpec *csp = CargoSpec::Get(other_right[i]); int xp = xpos + industry_width + CARGO_STUB_WIDTH; DrawHorConnection(xpos + industry_width, xp - 1, ypos1, csp); GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); } if (other_left[i] != INVALID_CARGO) { const CargoSpec *csp = CargoSpec::Get(other_left[i]); int xp = xpos - CARGO_STUB_WIDTH; DrawHorConnection(xp + 1, xpos - 1, ypos1, csp); GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); } ypos1 += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; } break; } case CFT_CARGO: { int cargo_base = this->GetCargoBase(xpos); int top = ypos + (this->u.cargo.top_end ? VERT_INTER_INDUSTRY_SPACE / 2 + 1 : 0); int bot = ypos - (this->u.cargo.bottom_end ? VERT_INTER_INDUSTRY_SPACE / 2 + 1 : 0) + normal_height - 1; int colpos = cargo_base; for (int i = 0; i < this->u.cargo.num_cargoes; i++) { if (this->u.cargo.top_end) GfxDrawLine(colpos, top - 1, colpos + HOR_CARGO_WIDTH - 1, top - 1, CARGO_LINE_COLOUR); if (this->u.cargo.bottom_end) GfxDrawLine(colpos, bot + 1, colpos + HOR_CARGO_WIDTH - 1, bot + 1, CARGO_LINE_COLOUR); GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); colpos++; const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[i]); GfxFillRect(colpos, top, colpos + HOR_CARGO_WIDTH - 2, bot, csp->legend_colour, FILLRECT_OPAQUE); colpos += HOR_CARGO_WIDTH - 2; GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); colpos += 1 + HOR_CARGO_SPACE; } const CargoID *hor_left, *hor_right; if (_current_text_dir == TD_RTL) { hor_left = this->u.cargo.cust_cargoes; hor_right = this->u.cargo.supp_cargoes; } else { hor_left = this->u.cargo.supp_cargoes; hor_right = this->u.cargo.cust_cargoes; } ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; for (uint i = 0; i < MAX_CARGOES; i++) { if (hor_left[i] != INVALID_CARGO) { int col = hor_left[i]; int dx = 0; const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); for (; col > 0; col--) { int lf = cargo_base + col * HOR_CARGO_WIDTH + (col - 1) * HOR_CARGO_SPACE; DrawHorConnection(lf, lf + HOR_CARGO_SPACE - dx, ypos, csp); dx = 1; } DrawHorConnection(xpos, cargo_base - dx, ypos, csp); } if (hor_right[i] != INVALID_CARGO) { int col = hor_right[i]; int dx = 0; const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); for (; col < this->u.cargo.num_cargoes - 1; col++) { int lf = cargo_base + (col + 1) * HOR_CARGO_WIDTH + col * HOR_CARGO_SPACE; DrawHorConnection(lf + dx - 1, lf + HOR_CARGO_SPACE - 1, ypos, csp); dx = 1; } DrawHorConnection(cargo_base + col * HOR_CARGO_SPACE + (col + 1) * HOR_CARGO_WIDTH - 1 + dx, xpos + CARGO_FIELD_WIDTH - 1, ypos, csp); } ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; } break; } case CFT_CARGO_LABEL: ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; for (uint i = 0; i < MAX_CARGOES; i++) { if (this->u.cargo_label.cargoes[i] != INVALID_CARGO) { const CargoSpec *csp = CargoSpec::Get(this->u.cargo_label.cargoes[i]); DrawString(xpos + WD_FRAMERECT_LEFT, xpos + industry_width - 1 - WD_FRAMERECT_RIGHT, ypos, csp->name, TC_WHITE, (this->u.cargo_label.left_align) ? SA_LEFT : SA_RIGHT); } ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; } break; default: NOT_REACHED(); } } /** * Decide which cargo was clicked at in a #CFT_CARGO field. * @param left Left industry neighbour if available (else \c NULL should be supplied). * @param right Right industry neighbour if available (else \c NULL should be supplied). * @param pt Click position in the cargo field. * @return Cargo clicked at, or #INVALID_CARGO if none. */ CargoID CargoClickedAt(const CargoesField *left, const CargoesField *right, Point pt) const { assert(this->type == CFT_CARGO); /* Vertical matching. */ int cpos = this->GetCargoBase(0); uint col; for (col = 0; col < this->u.cargo.num_cargoes; col++) { if (pt.x < cpos) break; if (pt.x < cpos + CargoesField::HOR_CARGO_WIDTH) return this->u.cargo.vertical_cargoes[col]; cpos += CargoesField::HOR_CARGO_WIDTH + CargoesField::HOR_CARGO_SPACE; } /* col = 0 -> left of first col, 1 -> left of 2nd col, ... this->u.cargo.num_cargoes right of last-col. */ int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; uint row; for (row = 0; row < MAX_CARGOES; row++) { if (pt.y < vpos) return INVALID_CARGO; if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; } if (row == MAX_CARGOES) return INVALID_CARGO; /* row = 0 -> at first horizontal row, row = 1 -> second horizontal row, 2 = 3rd horizontal row. */ if (col == 0) { if (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]]; if (left != NULL) { if (left->type == CFT_INDUSTRY) return left->u.industry.other_produced[row]; if (left->type == CFT_CARGO_LABEL && !left->u.cargo_label.left_align) return left->u.cargo_label.cargoes[row]; } return INVALID_CARGO; } if (col == this->u.cargo.num_cargoes) { if (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) return this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]]; if (right != NULL) { if (right->type == CFT_INDUSTRY) return right->u.industry.other_accepted[row]; if (right->type == CFT_CARGO_LABEL && right->u.cargo_label.left_align) return right->u.cargo_label.cargoes[row]; } return INVALID_CARGO; } if (row >= col) { /* Clicked somewhere in-between vertical cargo connection. * Since the horizontal connection is made in the same order as the vertical list, the above condition * ensures we are left-below the main diagonal, thus at the supplying side. */ return (this->u.cargo.supp_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.supp_cargoes[row]] : INVALID_CARGO; } else { /* Clicked at a customer connection. */ return (this->u.cargo.cust_cargoes[row] != INVALID_CARGO) ? this->u.cargo.vertical_cargoes[this->u.cargo.cust_cargoes[row]] : INVALID_CARGO; } } /** * Decide what cargo the user clicked in the cargo label field. * @param pt Click position in the cargo label field. * @return Cargo clicked at, or #INVALID_CARGO if none. */ CargoID CargoLabelClickedAt(Point pt) const { assert(this->type == CFT_CARGO_LABEL); int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; uint row; for (row = 0; row < MAX_CARGOES; row++) { if (pt.y < vpos) return INVALID_CARGO; if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; } if (row == MAX_CARGOES) return INVALID_CARGO; return this->u.cargo_label.cargoes[row]; } private: /** * Draw a horizontal cargo connection. * @param left Left-most coordinate to draw. * @param right Right-most coordinate to draw. * @param top Top coordinate of the cargo connection. * @param csp Cargo to draw. */ static void DrawHorConnection(int left, int right, int top, const CargoSpec *csp) { GfxDrawLine(left, top, right, top, CARGO_LINE_COLOUR); GfxFillRect(left, top + 1, right, top + FONT_HEIGHT_NORMAL - 2, csp->legend_colour, FILLRECT_OPAQUE); GfxDrawLine(left, top + FONT_HEIGHT_NORMAL - 1, right, top + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); } }; assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); int CargoesField::small_height; ///< Height of the header row. int CargoesField::normal_height; ///< Height of the non-header rows. int CargoesField::industry_width; ///< Width of an industry field. const int CargoesField::VERT_INTER_INDUSTRY_SPACE = 6; ///< Amount of space between two industries in a column. const int CargoesField::HOR_CARGO_BORDER_SPACE = 15; ///< Amount of space between the left/right edge of a #CFT_CARGO field, and the left/right most vertical cargo. const int CargoesField::CARGO_STUB_WIDTH = 10; ///< Width of a cargo not carried in the column (should be less than #HOR_CARGO_BORDER_SPACE). const int CargoesField::HOR_CARGO_WIDTH = 15; ///< Width of a vertical cargo column (inclusive the border line). const int CargoesField::HOR_CARGO_SPACE = 5; ///< Amount of horizontal space between two vertical cargoes. const int CargoesField::VERT_CARGO_EDGE = 4; ///< Amount of vertical space between top/bottom and the top/bottom connected cargo at an industry. const int CargoesField::VERT_CARGO_SPACE = 4; ///< Amount of vertical space between two connected cargoes at an industry. const int CargoesField::BLOB_DISTANCE = 5; ///< Distance of the industry legend colour from the edge of the industry box. const int CargoesField::BLOB_WIDTH = 12; ///< Width of the industry legend colour, including border. const int CargoesField::BLOB_HEIGHT = 9; ///< Height of the industry legend colour, including border /** Width of a #CFT_CARGO field. */ const int CargoesField::CARGO_FIELD_WIDTH = HOR_CARGO_BORDER_SPACE * 2 + HOR_CARGO_WIDTH * MAX_CARGOES + HOR_CARGO_SPACE * (MAX_CARGOES - 1); const int CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box. const int CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo. /** A single row of #CargoesField. */ struct CargoesRow { CargoesField columns[5]; ///< One row of fields. /** * Connect industry production cargoes to the cargo column after it. * @param column Column of the industry. */ void ConnectIndustryProduced(int column) { CargoesField *ind_fld = this->columns + column; CargoesField *cargo_fld = this->columns + column + 1; assert(ind_fld->type == CFT_INDUSTRY && cargo_fld->type == CFT_CARGO); MemSetT(ind_fld->u.industry.other_produced, INVALID_CARGO, MAX_CARGOES); if (ind_fld->u.industry.ind_type < NUM_INDUSTRYTYPES) { CargoID others[MAX_CARGOES]; // Produced cargoes not carried in the cargo column. int other_count = 0; const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type); for (uint i = 0; i < lengthof(indsp->produced_cargo); i++) { int col = cargo_fld->ConnectCargo(indsp->produced_cargo[i], true); if (col < 0) others[other_count++] = indsp->produced_cargo[i]; } /* Allocate other cargoes in the empty holes of the horizontal cargo connections. */ for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) { if (cargo_fld->u.cargo.supp_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_produced[i] = others[--other_count]; } } else { /* Houses only display what is demanded. */ for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { CargoID cid = cargo_fld->u.cargo.vertical_cargoes[i]; if (cid == CT_PASSENGERS || cid == CT_MAIL) cargo_fld->ConnectCargo(cid, true); } } } /** * Construct a #CFT_CARGO_LABEL field. * @param column Column to create the new field. * @param accepting Display accepted cargo (if \c false, display produced cargo). */ void MakeCargoLabel(int column, bool accepting) { CargoID cargoes[MAX_CARGOES]; MemSetT(cargoes, INVALID_CARGO, lengthof(cargoes)); CargoesField *label_fld = this->columns + column; CargoesField *cargo_fld = this->columns + (accepting ? column - 1 : column + 1); assert(cargo_fld->type == CFT_CARGO && label_fld->type == CFT_EMPTY); for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { int col = cargo_fld->ConnectCargo(cargo_fld->u.cargo.vertical_cargoes[i], !accepting); if (col >= 0) cargoes[col] = cargo_fld->u.cargo.vertical_cargoes[i]; } label_fld->MakeCargoLabel(cargoes, lengthof(cargoes), accepting); } /** * Connect industry accepted cargoes to the cargo column before it. * @param column Column of the industry. */ void ConnectIndustryAccepted(int column) { CargoesField *ind_fld = this->columns + column; CargoesField *cargo_fld = this->columns + column - 1; assert(ind_fld->type == CFT_INDUSTRY && cargo_fld->type == CFT_CARGO); MemSetT(ind_fld->u.industry.other_accepted, INVALID_CARGO, MAX_CARGOES); if (ind_fld->u.industry.ind_type < NUM_INDUSTRYTYPES) { CargoID others[MAX_CARGOES]; // Accepted cargoes not carried in the cargo column. int other_count = 0; const IndustrySpec *indsp = GetIndustrySpec(ind_fld->u.industry.ind_type); for (uint i = 0; i < lengthof(indsp->accepts_cargo); i++) { int col = cargo_fld->ConnectCargo(indsp->accepts_cargo[i], false); if (col < 0) others[other_count++] = indsp->accepts_cargo[i]; } /* Allocate other cargoes in the empty holes of the horizontal cargo connections. */ for (uint i = 0; i < MAX_CARGOES && other_count > 0; i++) { if (cargo_fld->u.cargo.cust_cargoes[i] == INVALID_CARGO) ind_fld->u.industry.other_accepted[i] = others[--other_count]; } } else { /* Houses only display what is demanded. */ for (uint i = 0; i < cargo_fld->u.cargo.num_cargoes; i++) { for (uint h = 0; h < NUM_HOUSES; h++) { HouseSpec *hs = HouseSpec::Get(h); if (!hs->enabled) continue; for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) { if (hs->cargo_acceptance[j] > 0 && cargo_fld->u.cargo.vertical_cargoes[i] == hs->accepts_cargo[j]) { cargo_fld->ConnectCargo(cargo_fld->u.cargo.vertical_cargoes[i], false); goto next_cargo; } } } next_cargo: ; } } } }; /** * Window displaying the cargo connections around an industry (or cargo). * * The main display is constructed from 'fields', rectangles that contain an industry, piece of the cargo connection, cargo labels, or headers. * For a nice display, the following should be kept in mind: * - A #CFT_HEADER is always at the top of an column of #CFT_INDUSTRY fields. * - A #CFT_CARGO_LABEL field is also always put in a column of #CFT_INDUSTRY fields. * - The top row contains #CFT_HEADER and #CFT_SMALL_EMPTY fields. * - Cargo connections have a column of their own (#CFT_CARGO fields). * - Cargo accepted or produced by an industry, but not carried in a cargo connection, is drawn in the space of a cargo column attached to the industry. * The information however is part of the industry. * * This results in the following invariants: * - Width of a #CFT_INDUSTRY column is large enough to hold all industry type labels, all cargo labels, and all header texts. * - Height of a #CFT_INDUSTRY is large enough to hold a header line, or a industry type line, \c N cargo labels * (where \c N is the maximum number of cargoes connected between industries), \c N connections of cargo types, and space * between two industry types (1/2 above it, and 1/2 underneath it). * - Width of a cargo field (#CFT_CARGO) is large enough to hold \c N vertical columns (one for each type of cargo). * Also, space is needed between an industry and the leftmost/rightmost column to draw the non-carried cargoes. * - Height of a #CFT_CARGO field is equally high as the height of the #CFT_INDUSTRY. * - A field at the top (#CFT_HEADER or #CFT_SMALL_EMPTY) match the width of the fields below them (#CFT_INDUSTRY respectively * #CFT_CARGO), the height should be sufficient to display the header text. * * When displaying the cargoes around an industry type, five columns are needed (supplying industries, accepted cargoes, the industry, * produced cargoes, customer industries). Displaying the industries around a cargo needs three columns (supplying industries, the cargo, * customer industries). The remaining two columns are set to #CFT_EMPTY with a width equal to the average of a cargo and an industry column. */ struct IndustryCargoesWindow : public Window { static const int HOR_TEXT_PADDING, VERT_TEXT_PADDING; typedef SmallVector Fields; Fields fields; ///< Fields to display in the #WID_IC_PANEL. uint ind_cargo; ///< If less than #NUM_INDUSTRYTYPES, an industry type, else a cargo id + NUM_INDUSTRYTYPES. Dimension cargo_textsize; ///< Size to hold any cargo text, as well as STR_INDUSTRY_CARGOES_SELECT_CARGO. Dimension ind_textsize; ///< Size to hold any industry type text, as well as STR_INDUSTRY_CARGOES_SELECT_INDUSTRY. Scrollbar *vscroll; IndustryCargoesWindow(int id) : Window(&_industry_cargoes_desc) { this->OnInit(); this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_IC_SCROLLBAR); this->FinishInitNested(0); this->OnInvalidateData(id); } virtual void OnInit() { /* Initialize static CargoesField size variables. */ Dimension d = GetStringBoundingBox(STR_INDUSTRY_CARGOES_PRODUCERS); d = maxdim(d, GetStringBoundingBox(STR_INDUSTRY_CARGOES_CUSTOMERS)); d.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT; d.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; CargoesField::small_height = d.height; /* Decide about the size of the box holding the text of an industry type. */ this->ind_textsize.width = 0; this->ind_textsize.height = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { const IndustrySpec *indsp = GetIndustrySpec(it); if (!indsp->enabled) continue; this->ind_textsize = maxdim(this->ind_textsize, GetStringBoundingBox(indsp->name)); } d.width = max(d.width, this->ind_textsize.width); d.height = this->ind_textsize.height; this->ind_textsize = maxdim(this->ind_textsize, GetStringBoundingBox(STR_INDUSTRY_CARGOES_SELECT_INDUSTRY)); /* Compute max size of the cargo texts. */ this->cargo_textsize.width = 0; this->cargo_textsize.height = 0; for (uint i = 0; i < NUM_CARGO; i++) { const CargoSpec *csp = CargoSpec::Get(i); if (!csp->IsValid()) continue; this->cargo_textsize = maxdim(this->cargo_textsize, GetStringBoundingBox(csp->name)); } d = maxdim(d, this->cargo_textsize); // Box must also be wide enough to hold any cargo label. this->cargo_textsize = maxdim(this->cargo_textsize, GetStringBoundingBox(STR_INDUSTRY_CARGOES_SELECT_CARGO)); d.width += 2 * HOR_TEXT_PADDING; /* Ensure the height is enough for the industry type text, for the horizontal connections, and for the cargo labels. */ uint min_ind_height = CargoesField::VERT_CARGO_EDGE * 2 + MAX_CARGOES * FONT_HEIGHT_NORMAL + (MAX_CARGOES - 1) * CargoesField::VERT_CARGO_SPACE; d.height = max(d.height + 2 * VERT_TEXT_PADDING, min_ind_height); CargoesField::industry_width = d.width; CargoesField::normal_height = d.height + CargoesField::VERT_INTER_INDUSTRY_SPACE; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_IC_PANEL: size->width = WD_FRAMETEXT_LEFT + CargoesField::industry_width * 3 + CargoesField::CARGO_FIELD_WIDTH * 2 + WD_FRAMETEXT_RIGHT; break; case WID_IC_IND_DROPDOWN: size->width = max(size->width, this->ind_textsize.width + padding.width); break; case WID_IC_CARGO_DROPDOWN: size->width = max(size->width, this->cargo_textsize.width + padding.width); break; } } CargoesFieldType type; ///< Type of field. virtual void SetStringParameters (int widget) const { if (widget != WID_IC_CAPTION) return; if (this->ind_cargo < NUM_INDUSTRYTYPES) { const IndustrySpec *indsp = GetIndustrySpec(this->ind_cargo); SetDParam(0, indsp->name); } else { const CargoSpec *csp = CargoSpec::Get(this->ind_cargo - NUM_INDUSTRYTYPES); SetDParam(0, csp->name); } } /** * Do the two sets of cargoes have a valid cargo in common? * @param cargoes1 Base address of the first cargo array. * @param length1 Number of cargoes in the first cargo array. * @param cargoes2 Base address of the second cargo array. * @param length2 Number of cargoes in the second cargo array. * @return Arrays have at least one valid cargo in common. */ static bool HasCommonValidCargo(const CargoID *cargoes1, uint length1, const CargoID *cargoes2, uint length2) { while (length1 > 0) { if (*cargoes1 != INVALID_CARGO) { for (uint i = 0; i < length2; i++) if (*cargoes1 == cargoes2[i]) return true; } cargoes1++; length1--; } return false; } /** * Can houses be used to supply one of the cargoes? * @param cargoes Base address of the cargo array. * @param length Number of cargoes in the array. * @return Houses can supply at least one of the cargoes. */ static bool HousesCanSupply(const CargoID *cargoes, uint length) { for (uint i = 0; i < length; i++) { if (cargoes[i] == INVALID_CARGO) continue; if (cargoes[i] == CT_PASSENGERS || cargoes[i] == CT_MAIL) return true; } return false; } /** * Can houses be used as customers of the produced cargoes? * @param cargoes Base address of the cargo array. * @param length Number of cargoes in the array. * @return Houses can accept at least one of the cargoes. */ static bool HousesCanAccept(const CargoID *cargoes, uint length) { HouseZones climate_mask; switch (_settings_game.game_creation.landscape) { case LT_TEMPERATE: climate_mask = HZ_TEMP; break; case LT_ARCTIC: climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break; case LT_TROPIC: climate_mask = HZ_SUBTROPIC; break; case LT_TOYLAND: climate_mask = HZ_TOYLND; break; default: NOT_REACHED(); } for (uint i = 0; i < length; i++) { if (cargoes[i] == INVALID_CARGO) continue; for (uint h = 0; h < NUM_HOUSES; h++) { HouseSpec *hs = HouseSpec::Get(h); if (!hs->enabled || !(hs->building_availability & climate_mask)) continue; for (uint j = 0; j < lengthof(hs->accepts_cargo); j++) { if (hs->cargo_acceptance[j] > 0 && cargoes[i] == hs->accepts_cargo[j]) return true; } } } return false; } /** * Count how many industries have accepted cargoes in common with one of the supplied set. * @param cargoes Cargoes to search. * @param length Number of cargoes in \a cargoes. * @return Number of industries that have an accepted cargo in common with the supplied set. */ static int CountMatchingAcceptingIndustries(const CargoID *cargoes, uint length) { int count = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { const IndustrySpec *indsp = GetIndustrySpec(it); if (!indsp->enabled) continue; if (HasCommonValidCargo(cargoes, length, indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) count++; } return count; } /** * Count how many industries have produced cargoes in common with one of the supplied set. * @param cargoes Cargoes to search. * @param length Number of cargoes in \a cargoes. * @return Number of industries that have a produced cargo in common with the supplied set. */ static int CountMatchingProducingIndustries(const CargoID *cargoes, uint length) { int count = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { const IndustrySpec *indsp = GetIndustrySpec(it); if (!indsp->enabled) continue; if (HasCommonValidCargo(cargoes, length, indsp->produced_cargo, lengthof(indsp->produced_cargo))) count++; } return count; } /** * Shorten the cargo column to just the part between industries. * @param column Column number of the cargo column. * @param top Current top row. * @param bottom Current bottom row. */ void ShortenCargoColumn(int column, int top, int bottom) { while (top < bottom && !this->fields[top].columns[column].HasConnection()) { this->fields[top].columns[column].MakeEmpty(CFT_EMPTY); top++; } this->fields[top].columns[column].u.cargo.top_end = true; while (bottom > top && !this->fields[bottom].columns[column].HasConnection()) { this->fields[bottom].columns[column].MakeEmpty(CFT_EMPTY); bottom--; } this->fields[bottom].columns[column].u.cargo.bottom_end = true; } /** * Place an industry in the fields. * @param row Row of the new industry. * @param col Column of the new industry. * @param it Industry to place. */ void PlaceIndustry(int row, int col, IndustryType it) { assert(this->fields[row].columns[col].type == CFT_EMPTY); this->fields[row].columns[col].MakeIndustry(it); if (col == 0) { this->fields[row].ConnectIndustryProduced(col); } else { this->fields[row].ConnectIndustryAccepted(col); } } /** * Notify smallmap that new displayed industries have been selected (in #_displayed_industries). */ void NotifySmallmap() { if (!this->IsWidgetLowered(WID_IC_NOTIFY)) return; /* Only notify the smallmap window if it exists. In particular, do not * bring it to the front to prevent messing up any nice layout of the user. */ InvalidateWindowClassesData(WC_SMALLMAP, 0); } /** * Compute what and where to display for industry type \a it. * @param it Industry type to display. */ void ComputeIndustryDisplay(IndustryType it) { this->GetWidget(WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION; this->ind_cargo = it; _displayed_industries = 1ULL << it; this->fields.Clear(); CargoesRow *row = this->fields.Append(); row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); row->columns[2].MakeEmpty(CFT_SMALL_EMPTY); row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); row->columns[4].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); const IndustrySpec *central_sp = GetIndustrySpec(it); bool houses_supply = HousesCanSupply(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); bool houses_accept = HousesCanAccept(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); /* Make a field consisting of two cargo columns. */ int num_supp = CountMatchingProducingIndustries(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)) + houses_supply; int num_cust = CountMatchingAcceptingIndustries(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)) + houses_accept; int num_indrows = max(3, max(num_supp, num_cust)); // One is needed for the 'it' industry, and 2 for the cargo labels. for (int i = 0; i < num_indrows; i++) { CargoesRow *row = this->fields.Append(); row->columns[0].MakeEmpty(CFT_EMPTY); row->columns[1].MakeCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo)); row->columns[2].MakeEmpty(CFT_EMPTY); row->columns[3].MakeCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo)); row->columns[4].MakeEmpty(CFT_EMPTY); } /* Add central industry. */ int central_row = 1 + num_indrows / 2; this->fields[central_row].columns[2].MakeIndustry(it); this->fields[central_row].ConnectIndustryProduced(2); this->fields[central_row].ConnectIndustryAccepted(2); /* Add cargo labels. */ this->fields[central_row - 1].MakeCargoLabel(2, true); this->fields[central_row + 1].MakeCargoLabel(2, false); /* Add suppliers and customers of the 'it' industry. */ int supp_count = 0; int cust_count = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { const IndustrySpec *indsp = GetIndustrySpec(it); if (!indsp->enabled) continue; if (HasCommonValidCargo(central_sp->accepts_cargo, lengthof(central_sp->accepts_cargo), indsp->produced_cargo, lengthof(indsp->produced_cargo))) { this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it); SetBit(_displayed_industries, it); supp_count++; } if (HasCommonValidCargo(central_sp->produced_cargo, lengthof(central_sp->produced_cargo), indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) { this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, it); SetBit(_displayed_industries, it); cust_count++; } } if (houses_supply) { this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES); supp_count++; } if (houses_accept) { this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 4, NUM_INDUSTRYTYPES); cust_count++; } this->ShortenCargoColumn(1, 1, num_indrows); this->ShortenCargoColumn(3, 1, num_indrows); const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); this->SetDirty(); this->NotifySmallmap(); } /** * Compute what and where to display for cargo id \a cid. * @param cid Cargo id to display. */ void ComputeCargoDisplay(CargoID cid) { this->GetWidget(WID_IC_CAPTION)->widget_data = STR_INDUSTRY_CARGOES_CARGO_CAPTION; this->ind_cargo = cid + NUM_INDUSTRYTYPES; _displayed_industries = 0; this->fields.Clear(); CargoesRow *row = this->fields.Append(); row->columns[0].MakeHeader(STR_INDUSTRY_CARGOES_PRODUCERS); row->columns[1].MakeEmpty(CFT_SMALL_EMPTY); row->columns[2].MakeHeader(STR_INDUSTRY_CARGOES_CUSTOMERS); row->columns[3].MakeEmpty(CFT_SMALL_EMPTY); row->columns[4].MakeEmpty(CFT_SMALL_EMPTY); bool houses_supply = HousesCanSupply(&cid, 1); bool houses_accept = HousesCanAccept(&cid, 1); int num_supp = CountMatchingProducingIndustries(&cid, 1) + houses_supply + 1; // Ensure room for the cargo label. int num_cust = CountMatchingAcceptingIndustries(&cid, 1) + houses_accept; int num_indrows = max(num_supp, num_cust); for (int i = 0; i < num_indrows; i++) { CargoesRow *row = this->fields.Append(); row->columns[0].MakeEmpty(CFT_EMPTY); row->columns[1].MakeCargo(&cid, 1); row->columns[2].MakeEmpty(CFT_EMPTY); row->columns[3].MakeEmpty(CFT_EMPTY); row->columns[4].MakeEmpty(CFT_EMPTY); } this->fields[num_indrows].MakeCargoLabel(0, false); // Add cargo labels at the left bottom. /* Add suppliers and customers of the cargo. */ int supp_count = 0; int cust_count = 0; for (IndustryType it = 0; it < NUM_INDUSTRYTYPES; it++) { const IndustrySpec *indsp = GetIndustrySpec(it); if (!indsp->enabled) continue; if (HasCommonValidCargo(&cid, 1, indsp->produced_cargo, lengthof(indsp->produced_cargo))) { this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, it); SetBit(_displayed_industries, it); supp_count++; } if (HasCommonValidCargo(&cid, 1, indsp->accepts_cargo, lengthof(indsp->accepts_cargo))) { this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, it); SetBit(_displayed_industries, it); cust_count++; } } if (houses_supply) { this->PlaceIndustry(1 + supp_count * num_indrows / num_supp, 0, NUM_INDUSTRYTYPES); supp_count++; } if (houses_accept) { this->PlaceIndustry(1 + cust_count * num_indrows / num_cust, 2, NUM_INDUSTRYTYPES); cust_count++; } this->ShortenCargoColumn(1, 1, num_indrows); const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); this->SetDirty(); this->NotifySmallmap(); } /** * Some data on this window has become invalid. * @param data Information about the changed data. * - data = 0 .. NUM_INDUSTRYTYPES - 1: Display the chain around the given industry. * - data = NUM_INDUSTRYTYPES: Stop sending updates to the smallmap window. * @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; if (data == NUM_INDUSTRYTYPES) { if (this->IsWidgetLowered(WID_IC_NOTIFY)) { this->RaiseWidget(WID_IC_NOTIFY); this->SetWidgetDirty(WID_IC_NOTIFY); } return; } assert(data >= 0 && data < NUM_INDUSTRYTYPES); this->ComputeIndustryDisplay(data); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_IC_PANEL) return; DrawPixelInfo tmp_dpi, *old_dpi; int width = r.right - r.left + 1; int height = r.bottom - r.top + 1 - WD_FRAMERECT_TOP - WD_FRAMERECT_BOTTOM; if (!FillDrawPixelInfo(&tmp_dpi, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, width, height)) return; old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; int left_pos = WD_FRAMERECT_LEFT; if (this->ind_cargo >= NUM_INDUSTRYTYPES) left_pos += (CargoesField::industry_width + CargoesField::CARGO_FIELD_WIDTH) / 2; int last_column = (this->ind_cargo < NUM_INDUSTRYTYPES) ? 4 : 2; const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); int vpos = -this->vscroll->GetPosition() * nwp->resize_y; for (uint i = 0; i < this->fields.Length(); i++) { int row_height = (i == 0) ? CargoesField::small_height : CargoesField::normal_height; if (vpos + row_height >= 0) { int xpos = left_pos; int col, dir; if (_current_text_dir == TD_RTL) { col = last_column; dir = -1; } else { col = 0; dir = 1; } while (col >= 0 && col <= last_column) { this->fields[i].columns[col].Draw(xpos, vpos); xpos += (col & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width; col += dir; } } vpos += row_height; if (vpos >= height) break; } _cur_dpi = old_dpi; } /** * Calculate in which field was clicked, and within the field, at what position. * @param pt Clicked position in the #WID_IC_PANEL widget. * @param fieldxy If \c true is returned, field x/y coordinate of \a pt. * @param xy If \c true is returned, x/y coordinate with in the field. * @return Clicked at a valid position. */ bool CalculatePositionInWidget(Point pt, Point *fieldxy, Point *xy) { const NWidgetBase *nw = this->GetWidget(WID_IC_PANEL); pt.x -= nw->pos_x; pt.y -= nw->pos_y; int vpos = WD_FRAMERECT_TOP + CargoesField::small_height - this->vscroll->GetPosition() * nw->resize_y; if (pt.y < vpos) return false; int row = (pt.y - vpos) / CargoesField::normal_height; // row is relative to row 1. if (row + 1 >= (int)this->fields.Length()) return false; vpos = pt.y - vpos - row * CargoesField::normal_height; // Position in the row + 1 field row++; // rebase row to match index of this->fields. int xpos = 2 * WD_FRAMERECT_LEFT + ((this->ind_cargo < NUM_INDUSTRYTYPES) ? 0 : (CargoesField::industry_width + CargoesField::CARGO_FIELD_WIDTH) / 2); if (pt.x < xpos) return false; int column; for (column = 0; column <= 5; column++) { int width = (column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width; if (pt.x < xpos + width) break; xpos += width; } int num_columns = (this->ind_cargo < NUM_INDUSTRYTYPES) ? 4 : 2; if (column > num_columns) return false; xpos = pt.x - xpos; /* Return both positions, compensating for RTL languages (which works due to the equal symmetry in both displays). */ fieldxy->y = row; xy->y = vpos; if (_current_text_dir == TD_RTL) { fieldxy->x = num_columns - column; xy->x = ((column & 1) ? CargoesField::CARGO_FIELD_WIDTH : CargoesField::industry_width) - xpos; } else { fieldxy->x = column; xy->x = xpos; } return true; } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_IC_PANEL: { Point fieldxy, xy; if (!CalculatePositionInWidget(pt, &fieldxy, &xy)) return; const CargoesField *fld = this->fields[fieldxy.y].columns + fieldxy.x; switch (fld->type) { case CFT_INDUSTRY: if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES) this->ComputeIndustryDisplay(fld->u.industry.ind_type); break; case CFT_CARGO: { CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; CargoID cid = fld->CargoClickedAt(lft, rgt, xy); if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid); break; } case CFT_CARGO_LABEL: { CargoID cid = fld->CargoLabelClickedAt(xy); if (cid != INVALID_CARGO) this->ComputeCargoDisplay(cid); break; } default: break; } break; } case WID_IC_NOTIFY: this->ToggleWidgetLoweredState(WID_IC_NOTIFY); this->SetWidgetDirty(WID_IC_NOTIFY); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); if (this->IsWidgetLowered(WID_IC_NOTIFY)) { if (FindWindowByClass(WC_SMALLMAP) == NULL) ShowSmallMap(); this->NotifySmallmap(); } break; case WID_IC_CARGO_DROPDOWN: { DropDownList *lst = new DropDownList; const CargoSpec *cs; FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { *lst->Append() = new DropDownListStringItem(cs->name, cs->Index(), false); } if (lst->Length() == 0) { delete lst; break; } int selected = (this->ind_cargo >= NUM_INDUSTRYTYPES) ? (int)(this->ind_cargo - NUM_INDUSTRYTYPES) : -1; ShowDropDownList(this, lst, selected, WID_IC_CARGO_DROPDOWN, 0, true); break; } case WID_IC_IND_DROPDOWN: { DropDownList *lst = new DropDownList; for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { IndustryType ind = _sorted_industry_types[i]; const IndustrySpec *indsp = GetIndustrySpec(ind); if (!indsp->enabled) continue; *lst->Append() = new DropDownListStringItem(indsp->name, ind, false); } if (lst->Length() == 0) { delete lst; break; } int selected = (this->ind_cargo < NUM_INDUSTRYTYPES) ? (int)this->ind_cargo : -1; ShowDropDownList(this, lst, selected, WID_IC_IND_DROPDOWN, 0, true); break; } } } virtual void OnDropdownSelect(int widget, int index) { if (index < 0) return; switch (widget) { case WID_IC_CARGO_DROPDOWN: this->ComputeCargoDisplay(index); break; case WID_IC_IND_DROPDOWN: this->ComputeIndustryDisplay(index); break; } } virtual void OnHover(Point pt, int widget) { if (widget != WID_IC_PANEL) return; Point fieldxy, xy; if (!CalculatePositionInWidget(pt, &fieldxy, &xy)) return; const CargoesField *fld = this->fields[fieldxy.y].columns + fieldxy.x; CargoID cid = INVALID_CARGO; switch (fld->type) { case CFT_CARGO: { CargoesField *lft = (fieldxy.x > 0) ? this->fields[fieldxy.y].columns + fieldxy.x - 1 : NULL; CargoesField *rgt = (fieldxy.x < 4) ? this->fields[fieldxy.y].columns + fieldxy.x + 1 : NULL; cid = fld->CargoClickedAt(lft, rgt, xy); break; } case CFT_CARGO_LABEL: { cid = fld->CargoLabelClickedAt(xy); break; } case CFT_INDUSTRY: if (fld->u.industry.ind_type < NUM_INDUSTRYTYPES && (this->ind_cargo >= NUM_INDUSTRYTYPES || fieldxy.x != 2)) { GuiShowTooltips(this, STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP, 0, NULL, TCC_HOVER); } return; default: break; } if (cid != INVALID_CARGO && (this->ind_cargo < NUM_INDUSTRYTYPES || cid != this->ind_cargo - NUM_INDUSTRYTYPES)) { const CargoSpec *csp = CargoSpec::Get(cid); uint64 params[5]; params[0] = csp->name; GuiShowTooltips(this, STR_INDUSTRY_CARGOES_CARGO_TOOLTIP, 1, params, TCC_HOVER); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_IC_PANEL); } }; const int IndustryCargoesWindow::HOR_TEXT_PADDING = 5; ///< Horizontal padding around the industry type text. const int IndustryCargoesWindow::VERT_TEXT_PADDING = 5; ///< Vertical padding around the industry type text. /** * Open the industry and cargoes window. * @param id Industry type to display, \c NUM_INDUSTRYTYPES selects a default industry type. */ static void ShowIndustryCargoesWindow(IndustryType id) { if (id >= NUM_INDUSTRYTYPES) { for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) { const IndustrySpec *indsp = GetIndustrySpec(_sorted_industry_types[i]); if (indsp->enabled) { id = _sorted_industry_types[i]; break; } } if (id >= NUM_INDUSTRYTYPES) return; } Window *w = BringWindowToFrontById(WC_INDUSTRY_CARGOES, 0); if (w != NULL) { w->InvalidateData(id); return; } new IndustryCargoesWindow(id); } /** Open the industry and cargoes window with an industry. */ void ShowIndustryCargoesWindow() { ShowIndustryCargoesWindow(NUM_INDUSTRYTYPES); } openttd-1.5.3/src/fontcache.h0000644000000000000000000001377112627373442014610 0ustar rootroot/* $Id: fontcache.h 27004 2014-10-12 20:43:25Z peter1138 $ */ /* * 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 fontcache.h Functions to read fonts from files and cache them. */ #ifndef FONTCACHE_H #define FONTCACHE_H #include "string_type.h" #include "spritecache.h" /** Glyphs are characters from a font. */ typedef uint32 GlyphID; static const GlyphID SPRITE_GLYPH = 1U << 30; /** Font cache for basic fonts. */ class FontCache { private: static FontCache *caches[FS_END]; ///< All the font caches. protected: FontCache *parent; ///< The parent of this font cache. const FontSize fs; ///< The size of the font. int height; ///< The height of the font. int ascender; ///< The ascender value of the font. int descender; ///< The descender value of the font. int units_per_em; ///< The units per EM value of the font. public: FontCache(FontSize fs); virtual ~FontCache(); /** * Get the FontSize of the font. * @return The FontSize. */ inline FontSize GetSize() const { return this->fs; } /** * Get the height of the font. * @return The height of the font. */ virtual int GetHeight() const { return this->height; } /** * Get the ascender value of the font. * @return The ascender value of the font. */ inline int GetAscender() const { return this->ascender; } /** * Get the descender value of the font. * @return The descender value of the font. */ inline int GetDescender() const{ return this->descender; } /** * Get the units per EM value of the font. * @return The units per EM value of the font. */ inline int GetUnitsPerEM() const { return this->units_per_em; } /** * Get the SpriteID mapped to the given key * @param key The key to get the sprite for. * @return The sprite. */ virtual SpriteID GetUnicodeGlyph(WChar key) = 0; /** * Map a SpriteID to the key * @param key The key to map to. * @param sprite The sprite that is being mapped. */ virtual void SetUnicodeGlyph(WChar key, SpriteID sprite) = 0; /** Initialize the glyph map */ virtual void InitializeUnicodeGlyphMap() = 0; /** Clear the font cache. */ virtual void ClearFontCache() = 0; /** * Get the glyph (sprite) of the given key. * @param key The key to look up. * @return The sprite. */ virtual const Sprite *GetGlyph(GlyphID key) = 0; /** * Get the width of the glyph with the given key. * @param key The key to look up. * @return The width. */ virtual uint GetGlyphWidth(GlyphID key) = 0; /** * Do we need to draw a glyph shadow? * @return True if it has to be done, otherwise false. */ virtual bool GetDrawGlyphShadow() = 0; /** * Map a character into a glyph. * @param key The character. * @return The glyph ID used to draw the character. */ virtual GlyphID MapCharToGlyph(WChar key) = 0; /** * Read a font table from the font. * @param tag The of the table to load. * @param length The length of the read data. * @return The loaded table data. */ virtual const void *GetFontTable(uint32 tag, size_t &length) = 0; /** * Get the name of this font. * @return The name of the font. */ virtual const char *GetFontName() = 0; /** * Get the font cache of a given font size. * @param fs The font size to look up. * @return The font cache. */ static inline FontCache *Get(FontSize fs) { assert(fs < FS_END); return FontCache::caches[fs]; } /** * Check whether the font cache has a parent. */ inline bool HasParent() { return this->parent != NULL; } }; /** Get the SpriteID mapped to the given font size and key */ static inline SpriteID GetUnicodeGlyph(FontSize size, WChar key) { return FontCache::Get(size)->GetUnicodeGlyph(key); } /** Map a SpriteID to the font size and key */ static inline void SetUnicodeGlyph(FontSize size, WChar key, SpriteID sprite) { FontCache::Get(size)->SetUnicodeGlyph(key, sprite); } /** Initialize the glyph map */ static inline void InitializeUnicodeGlyphMap() { for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) { FontCache::Get(fs)->InitializeUnicodeGlyphMap(); } } static inline void ClearFontCache() { for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) { FontCache::Get(fs)->ClearFontCache(); } } /** Get the Sprite for a glyph */ static inline const Sprite *GetGlyph(FontSize size, WChar key) { FontCache *fc = FontCache::Get(size); return fc->GetGlyph(fc->MapCharToGlyph(key)); } /** Get the width of a glyph */ static inline uint GetGlyphWidth(FontSize size, WChar key) { FontCache *fc = FontCache::Get(size); return fc->GetGlyphWidth(fc->MapCharToGlyph(key)); } static inline bool GetDrawGlyphShadow(FontSize size) { return FontCache::Get(size)->GetDrawGlyphShadow(); } #ifdef WITH_FREETYPE /** Settings for a single freetype font. */ struct FreeTypeSubSetting { char font[MAX_PATH]; ///< The name of the font, or path to the font. uint size; ///< The (requested) size of the font. bool aa; ///< Whether to do anti aliasing or not. }; /** Settings for the freetype fonts. */ struct FreeTypeSettings { FreeTypeSubSetting small; ///< The smallest font; mostly used for zoomed out view. FreeTypeSubSetting medium; ///< The normal font size. FreeTypeSubSetting large; ///< The largest font; mostly used for newspapers. FreeTypeSubSetting mono; ///< The mono space font used for license/readme viewers. }; extern FreeTypeSettings _freetype; #endif /* WITH_FREETYPE */ void InitFreeType(bool monospace); void UninitFreeType(); #endif /* FONTCACHE_H */ openttd-1.5.3/src/settings.cpp0000644000000000000000000020442012627373442015042 0ustar rootroot/* $Id: settings.cpp 27163 2015-02-22 15:26:27Z frosch $ */ /* * 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 settings.cpp * All actions handling saving and loading of the settings/configuration goes on in this file. * The file consists of three parts: *

    *
  1. Parsing the configuration file (openttd.cfg). This is achieved with the ini_ functions which * handle various types, such as normal 'key = value' pairs, lists and value combinations of * lists, strings, integers, 'bit'-masks and element selections. *
  2. Handle reading and writing to the setting-structures from inside the game either from * the console for example or through the gui with CMD_ functions. *
  3. Handle saving/loading of the PATS chunk inside the savegame. *
* @see SettingDesc * @see SaveLoad */ #include "stdafx.h" #include "currency.h" #include "screenshot.h" #include "network/network.h" #include "network/network_func.h" #include "settings_internal.h" #include "command_func.h" #include "console_func.h" #include "pathfinder/pathfinder_type.h" #include "genworld.h" #include "train.h" #include "news_func.h" #include "window_func.h" #include "sound_func.h" #include "company_func.h" #include "rev.h" #ifdef WITH_FREETYPE #include "fontcache.h" #endif #include "textbuf_gui.h" #include "rail_gui.h" #include "elrail_func.h" #include "error.h" #include "town.h" #include "video/video_driver.hpp" #include "sound/sound_driver.hpp" #include "music/music_driver.hpp" #include "blitter/factory.hpp" #include "base_media_base.h" #include "gamelog.h" #include "settings_func.h" #include "ini_type.h" #include "ai/ai_config.hpp" #include "ai/ai.hpp" #include "game/game_config.hpp" #include "game/game.hpp" #include "ship.h" #include "smallmap_gui.h" #include "roadveh.h" #include "fios.h" #include "strings_func.h" #include "void_map.h" #include "station_base.h" #include "table/strings.h" #include "table/settings.h" #include "safeguards.h" ClientSettings _settings_client; GameSettings _settings_game; ///< Game settings of a running game or the scenario editor. GameSettings _settings_newgame; ///< Game settings for new games (updated from the intro screen). VehicleDefaultSettings _old_vds; ///< Used for loading default vehicles settings from old savegames char *_config_file; ///< Configuration file of OpenTTD typedef std::list ErrorList; static ErrorList _settings_error_list; ///< Errors while loading minimal settings. typedef void SettingDescProc(IniFile *ini, const SettingDesc *desc, const char *grpname, void *object); typedef void SettingDescProcList(IniFile *ini, const char *grpname, StringList *list); static bool IsSignedVarMemType(VarType vt); /** * Groups in openttd.cfg that are actually lists. */ static const char * const _list_group_names[] = { "bans", "newgrf", "servers", "server_bind_addresses", NULL }; /** * Find the index value of a ONEofMANY type in a string separated by | * @param many full domain of values the ONEofMANY setting can have * @param one the current value of the setting for which a value needs found * @param onelen force calculation of the *one parameter * @return the integer index of the full-list, or -1 if not found */ static size_t LookupOneOfMany(const char *many, const char *one, size_t onelen = 0) { const char *s; size_t idx; if (onelen == 0) onelen = strlen(one); /* check if it's an integer */ if (*one >= '0' && *one <= '9') return strtoul(one, NULL, 0); idx = 0; for (;;) { /* find end of item */ s = many; while (*s != '|' && *s != 0) s++; if ((size_t)(s - many) == onelen && !memcmp(one, many, onelen)) return idx; if (*s == 0) return (size_t)-1; many = s + 1; idx++; } } /** * Find the set-integer value MANYofMANY type in a string * @param many full domain of values the MANYofMANY setting can have * @param str the current string value of the setting, each individual * of separated by a whitespace,tab or | character * @return the 'fully' set integer, or -1 if a set is not found */ static size_t LookupManyOfMany(const char *many, const char *str) { const char *s; size_t r; size_t res = 0; for (;;) { /* skip "whitespace" */ while (*str == ' ' || *str == '\t' || *str == '|') str++; if (*str == 0) break; s = str; while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++; r = LookupOneOfMany(many, str, s - str); if (r == (size_t)-1) return r; SetBit(res, (uint8)r); // value found, set it if (*s == 0) break; str = s + 1; } return res; } /** * Parse an integerlist string and set each found value * @param p the string to be parsed. Each element in the list is separated by a * comma or a space character * @param items pointer to the integerlist-array that will be filled with values * @param maxitems the maximum number of elements the integerlist-array has * @return returns the number of items found, or -1 on an error */ static int ParseIntList(const char *p, int *items, int maxitems) { int n = 0; // number of items read so far bool comma = false; // do we accept comma? while (*p != '\0') { switch (*p) { case ',': /* Do not accept multiple commas between numbers */ if (!comma) return -1; comma = false; /* FALL THROUGH */ case ' ': p++; break; default: { if (n == maxitems) return -1; // we don't accept that many numbers char *end; long v = strtol(p, &end, 0); if (p == end) return -1; // invalid character (not a number) if (sizeof(int) < sizeof(long)) v = ClampToI32(v); items[n++] = v; p = end; // first non-number comma = true; // we accept comma now break; } } } /* If we have read comma but no number after it, fail. * We have read comma when (n != 0) and comma is not allowed */ if (n != 0 && !comma) return -1; return n; } /** * Load parsed string-values into an integer-array (intlist) * @param str the string that contains the values (and will be parsed) * @param array pointer to the integer-arrays that will be filled * @param nelems the number of elements the array holds. Maximum is 64 elements * @param type the type of elements the array holds (eg INT8, UINT16, etc.) * @return return true on success and false on error */ static bool LoadIntList(const char *str, void *array, int nelems, VarType type) { int items[64]; int i, nitems; if (str == NULL) { memset(items, 0, sizeof(items)); nitems = nelems; } else { nitems = ParseIntList(str, items, lengthof(items)); if (nitems != nelems) return false; } switch (type) { case SLE_VAR_BL: case SLE_VAR_I8: case SLE_VAR_U8: for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i]; break; case SLE_VAR_I16: case SLE_VAR_U16: for (i = 0; i != nitems; i++) ((uint16*)array)[i] = items[i]; break; case SLE_VAR_I32: case SLE_VAR_U32: for (i = 0; i != nitems; i++) ((uint32*)array)[i] = items[i]; break; default: NOT_REACHED(); } return true; } /** * Convert an integer-array (intlist) to a string representation. Each value * is separated by a comma or a space character * @param buf output buffer where the string-representation will be stored * @param last last item to write to in the output buffer * @param array pointer to the integer-arrays that is read from * @param nelems the number of elements the array holds. * @param type the type of elements the array holds (eg INT8, UINT16, etc.) */ static void MakeIntList(char *buf, const char *last, const void *array, int nelems, VarType type) { int i, v = 0; const byte *p = (const byte *)array; for (i = 0; i != nelems; i++) { switch (type) { case SLE_VAR_BL: case SLE_VAR_I8: v = *(const int8 *)p; p += 1; break; case SLE_VAR_U8: v = *(const uint8 *)p; p += 1; break; case SLE_VAR_I16: v = *(const int16 *)p; p += 2; break; case SLE_VAR_U16: v = *(const uint16 *)p; p += 2; break; case SLE_VAR_I32: v = *(const int32 *)p; p += 4; break; case SLE_VAR_U32: v = *(const uint32 *)p; p += 4; break; default: NOT_REACHED(); } buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v); } } /** * Convert a ONEofMANY structure to a string representation. * @param buf output buffer where the string-representation will be stored * @param last last item to write to in the output buffer * @param many the full-domain string of possible values * @param id the value of the variable and whose string-representation must be found */ static void MakeOneOfMany(char *buf, const char *last, const char *many, int id) { int orig_id = id; /* Look for the id'th element */ while (--id >= 0) { for (; *many != '|'; many++) { if (*many == '\0') { // not found seprintf(buf, last, "%d", orig_id); return; } } many++; // pass the |-character } /* copy string until next item (|) or the end of the list if this is the last one */ while (*many != '\0' && *many != '|' && buf < last) *buf++ = *many++; *buf = '\0'; } /** * Convert a MANYofMANY structure to a string representation. * @param buf output buffer where the string-representation will be stored * @param last last item to write to in the output buffer * @param many the full-domain string of possible values * @param x the value of the variable and whose string-representation must * be found in the bitmasked many string */ static void MakeManyOfMany(char *buf, const char *last, const char *many, uint32 x) { const char *start; int i = 0; bool init = true; for (; x != 0; x >>= 1, i++) { start = many; while (*many != 0 && *many != '|') many++; // advance to the next element if (HasBit(x, 0)) { // item found, copy it if (!init) buf += seprintf(buf, last, "|"); init = false; if (start == many) { buf += seprintf(buf, last, "%d", i); } else { memcpy(buf, start, many - start); buf += many - start; } } if (*many == '|') many++; } *buf = '\0'; } /** * Convert a string representation (external) of a setting to the internal rep. * @param desc SettingDesc struct that holds all information about the variable * @param orig_str input string that will be parsed based on the type of desc * @return return the parsed value of the setting */ static const void *StringToVal(const SettingDescBase *desc, const char *orig_str) { const char *str = orig_str == NULL ? "" : orig_str; switch (desc->cmd) { case SDT_NUMX: { char *end; size_t val = strtoul(str, &end, 0); if (end == str) { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); msg.SetDParamStr(1, desc->name); _settings_error_list.push_back(msg); return desc->def; } if (*end != '\0') { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS); msg.SetDParamStr(0, desc->name); _settings_error_list.push_back(msg); } return (void*)val; } case SDT_ONEOFMANY: { size_t r = LookupOneOfMany(desc->many, str); /* if the first attempt of conversion from string to the appropriate value fails, * look if we have defined a converter from old value to new value. */ if (r == (size_t)-1 && desc->proc_cnvt != NULL) r = desc->proc_cnvt(str); if (r != (size_t)-1) return (void*)r; // and here goes converted value ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); msg.SetDParamStr(1, desc->name); _settings_error_list.push_back(msg); return desc->def; } case SDT_MANYOFMANY: { size_t r = LookupManyOfMany(desc->many, str); if (r != (size_t)-1) return (void*)r; ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); msg.SetDParamStr(1, desc->name); _settings_error_list.push_back(msg); return desc->def; } case SDT_BOOLX: { if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return (void*)true; if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return (void*)false; ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE); msg.SetDParamStr(0, str); msg.SetDParamStr(1, desc->name); _settings_error_list.push_back(msg); return desc->def; } case SDT_STRING: return orig_str; case SDT_INTLIST: return str; default: break; } return NULL; } /** * Set the value of a setting and if needed clamp the value to * the preset minimum and maximum. * @param ptr the variable itself * @param sd pointer to the 'information'-database of the variable * @param val signed long version of the new value * @pre SettingDesc is of type SDT_BOOLX, SDT_NUMX, * SDT_ONEOFMANY or SDT_MANYOFMANY. Other types are not supported as of now */ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) { const SettingDescBase *sdb = &sd->desc; if (sdb->cmd != SDT_BOOLX && sdb->cmd != SDT_NUMX && sdb->cmd != SDT_ONEOFMANY && sdb->cmd != SDT_MANYOFMANY) { return; } /* We cannot know the maximum value of a bitset variable, so just have faith */ if (sdb->cmd != SDT_MANYOFMANY) { /* We need to take special care of the uint32 type as we receive from the function * a signed integer. While here also bail out on 64-bit settings as those are not * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed * 32-bit variable * TODO: Support 64-bit settings/variables */ switch (GetVarMemType(sd->save.conv)) { case SLE_VAR_NULL: return; case SLE_VAR_BL: case SLE_VAR_I8: case SLE_VAR_U8: case SLE_VAR_I16: case SLE_VAR_U16: case SLE_VAR_I32: { /* Override the minimum value. No value below sdb->min, except special value 0 */ if (!(sdb->flags & SGF_0ISDISABLED) || val != 0) val = Clamp(val, sdb->min, sdb->max); break; } case SLE_VAR_U32: { /* Override the minimum value. No value below sdb->min, except special value 0 */ uint min = ((sdb->flags & SGF_0ISDISABLED) && (uint)val <= (uint)sdb->min) ? 0 : sdb->min; WriteValue(ptr, SLE_VAR_U32, (int64)ClampU(val, min, sdb->max)); return; } case SLE_VAR_I64: case SLE_VAR_U64: default: NOT_REACHED(); } } WriteValue(ptr, sd->save.conv, (int64)val); } /** * Load values from a group of an IniFile structure into the internal representation * @param ini pointer to IniFile structure that holds administrative information * @param sd pointer to SettingDesc structure whose internally pointed variables will * be given values * @param grpname the group of the IniFile to search in for the new values * @param object pointer to the object been loaded */ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object) { IniGroup *group; IniGroup *group_def = ini->GetGroup(grpname); IniItem *item; const void *p; void *ptr; const char *s; for (; sd->save.cmd != SL_END; sd++) { const SettingDescBase *sdb = &sd->desc; const SaveLoad *sld = &sd->save; if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; /* For settings.xx.yy load the settings from [xx] yy = ? */ s = strchr(sdb->name, '.'); if (s != NULL) { group = ini->GetGroup(sdb->name, s - sdb->name); s++; } else { s = sdb->name; group = group_def; } item = group->GetItem(s, false); if (item == NULL && group != group_def) { /* For settings.xx.yy load the settings from [settingss] yy = ? in case the previous * did not exist (e.g. loading old config files with a [settings] section */ item = group_def->GetItem(s, false); } if (item == NULL) { /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous * did not exist (e.g. loading old config files with a [yapf] section */ const char *sc = strchr(s, '.'); if (sc != NULL) item = ini->GetGroup(s, sc - s)->GetItem(sc + 1, false); } p = (item == NULL) ? sdb->def : StringToVal(sdb, item->value); ptr = GetVariableAddress(object, sld); switch (sdb->cmd) { case SDT_BOOLX: // All four are various types of (integer) numbers case SDT_NUMX: case SDT_ONEOFMANY: case SDT_MANYOFMANY: Write_ValidateSetting(ptr, sd, (int32)(size_t)p); break; case SDT_STRING: switch (GetVarMemType(sld->conv)) { case SLE_VAR_STRB: case SLE_VAR_STRBQ: if (p != NULL) strecpy((char*)ptr, (const char*)p, (char*)ptr + sld->length - 1); break; case SLE_VAR_STR: case SLE_VAR_STRQ: free(*(char**)ptr); *(char**)ptr = p == NULL ? NULL : stredup((const char*)p); break; case SLE_VAR_CHAR: if (p != NULL) *(char *)ptr = *(const char *)p; break; default: NOT_REACHED(); } break; case SDT_INTLIST: { if (!LoadIntList((const char*)p, ptr, sld->length, GetVarMemType(sld->conv))) { ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY); msg.SetDParamStr(0, sdb->name); _settings_error_list.push_back(msg); /* Use default */ LoadIntList((const char*)sdb->def, ptr, sld->length, GetVarMemType(sld->conv)); } else if (sd->desc.proc_cnvt != NULL) { sd->desc.proc_cnvt((const char*)p); } break; } default: NOT_REACHED(); } } } /** * Save the values of settings to the inifile. * @param ini pointer to IniFile structure * @param sd read-only SettingDesc structure which contains the unmodified, * loaded values of the configuration file and various information about it * @param grpname holds the name of the group (eg. [network]) where these will be saved * @param object pointer to the object been saved * The function works as follows: for each item in the SettingDesc structure we * have a look if the value has changed since we started the game (the original * values are reloaded when saving). If settings indeed have changed, we get * these and save them. */ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grpname, void *object) { IniGroup *group_def = NULL, *group; IniItem *item; char buf[512]; const char *s; void *ptr; for (; sd->save.cmd != SL_END; sd++) { const SettingDescBase *sdb = &sd->desc; const SaveLoad *sld = &sd->save; /* If the setting is not saved to the configuration * file, just continue with the next setting */ if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; if (sld->conv & SLF_NOT_IN_CONFIG) continue; /* XXX - wtf is this?? (group override?) */ s = strchr(sdb->name, '.'); if (s != NULL) { group = ini->GetGroup(sdb->name, s - sdb->name); s++; } else { if (group_def == NULL) group_def = ini->GetGroup(grpname); s = sdb->name; group = group_def; } item = group->GetItem(s, true); ptr = GetVariableAddress(object, sld); if (item->value != NULL) { /* check if the value is the same as the old value */ const void *p = StringToVal(sdb, item->value); /* The main type of a variable/setting is in bytes 8-15 * The subtype (what kind of numbers do we have there) is in 0-7 */ switch (sdb->cmd) { case SDT_BOOLX: case SDT_NUMX: case SDT_ONEOFMANY: case SDT_MANYOFMANY: switch (GetVarMemType(sld->conv)) { case SLE_VAR_BL: if (*(bool*)ptr == (p != NULL)) continue; break; case SLE_VAR_I8: case SLE_VAR_U8: if (*(byte*)ptr == (byte)(size_t)p) continue; break; case SLE_VAR_I16: case SLE_VAR_U16: if (*(uint16*)ptr == (uint16)(size_t)p) continue; break; case SLE_VAR_I32: case SLE_VAR_U32: if (*(uint32*)ptr == (uint32)(size_t)p) continue; break; default: NOT_REACHED(); } break; default: break; // Assume the other types are always changed } } /* Value has changed, get the new value and put it into a buffer */ switch (sdb->cmd) { case SDT_BOOLX: case SDT_NUMX: case SDT_ONEOFMANY: case SDT_MANYOFMANY: { uint32 i = (uint32)ReadValue(ptr, sld->conv); switch (sdb->cmd) { case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break; case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break; case SDT_ONEOFMANY: MakeOneOfMany(buf, lastof(buf), sdb->many, i); break; case SDT_MANYOFMANY: MakeManyOfMany(buf, lastof(buf), sdb->many, i); break; default: NOT_REACHED(); } break; } case SDT_STRING: switch (GetVarMemType(sld->conv)) { case SLE_VAR_STRB: strecpy(buf, (char*)ptr, lastof(buf)); break; case SLE_VAR_STRBQ:seprintf(buf, lastof(buf), "\"%s\"", (char*)ptr); break; case SLE_VAR_STR: strecpy(buf, *(char**)ptr, lastof(buf)); break; case SLE_VAR_STRQ: if (*(char**)ptr == NULL) { buf[0] = '\0'; } else { seprintf(buf, lastof(buf), "\"%s\"", *(char**)ptr); } break; case SLE_VAR_CHAR: buf[0] = *(char*)ptr; buf[1] = '\0'; break; default: NOT_REACHED(); } break; case SDT_INTLIST: MakeIntList(buf, lastof(buf), ptr, sld->length, GetVarMemType(sld->conv)); break; default: NOT_REACHED(); } /* The value is different, that means we have to write it to the ini */ free(item->value); item->value = stredup(buf); } } /** * Loads all items from a 'grpname' section into a list * The list parameter can be a NULL pointer, in this case nothing will be * saved and a callback function should be defined that will take over the * list-handling and store the data itself somewhere. * @param ini IniFile handle to the ini file with the source data * @param grpname character string identifying the section-header of the ini file that will be parsed * @param list new list with entries of the given section */ static void IniLoadSettingList(IniFile *ini, const char *grpname, StringList *list) { IniGroup *group = ini->GetGroup(grpname); if (group == NULL || list == NULL) return; list->Clear(); for (const IniItem *item = group->item; item != NULL; item = item->next) { if (item->name != NULL) *list->Append() = stredup(item->name); } } /** * Saves all items from a list into the 'grpname' section * The list parameter can be a NULL pointer, in this case a callback function * should be defined that will provide the source data to be saved. * @param ini IniFile handle to the ini file where the destination data is saved * @param grpname character string identifying the section-header of the ini file * @param list pointer to an string(pointer) array that will be used as the * source to be saved into the relevant ini section */ static void IniSaveSettingList(IniFile *ini, const char *grpname, StringList *list) { IniGroup *group = ini->GetGroup(grpname); if (group == NULL || list == NULL) return; group->Clear(); for (char **iter = list->Begin(); iter != list->End(); iter++) { group->GetItem(*iter, true)->SetValue(""); } } /** * Load a WindowDesc from config. * @param ini IniFile handle to the ini file with the source data * @param grpname character string identifying the section-header of the ini file that will be parsed * @param desc Destination WindowDesc */ void IniLoadWindowSettings(IniFile *ini, const char *grpname, void *desc) { IniLoadSettings(ini, _window_settings, grpname, desc); } /** * Save a WindowDesc to config. * @param ini IniFile handle to the ini file where the destination data is saved * @param grpname character string identifying the section-header of the ini file * @param desc Source WindowDesc */ void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc) { IniSaveSettings(ini, _window_settings, grpname, desc); } /** * Check whether the setting is editable in the current gamemode. * @param do_command true if this is about checking a command from the server. * @return true if editable. */ bool SettingDesc::IsEditable(bool do_command) const { if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->desc.flags & SGF_PER_COMPANY)) return false; if ((this->desc.flags & SGF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false; if ((this->desc.flags & SGF_NO_NETWORK) && _networking) return false; if ((this->desc.flags & SGF_NEWGAME_ONLY) && (_game_mode == GM_NORMAL || (_game_mode == GM_EDITOR && !(this->desc.flags & SGF_SCENEDIT_TOO)))) return false; return true; } /** * Return the type of the setting. * @return type of setting */ SettingType SettingDesc::GetType() const { if (this->desc.flags & SGF_PER_COMPANY) return ST_COMPANY; return (this->save.conv & SLF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME; } /* Begin - Callback Functions for the various settings. */ /** Reposition the main toolbar as the setting changed. */ static bool v_PositionMainToolbar(int32 p1) { if (_game_mode != GM_MENU) PositionMainToolbar(NULL); return true; } /** Reposition the statusbar as the setting changed. */ static bool v_PositionStatusbar(int32 p1) { if (_game_mode != GM_MENU) { PositionStatusbar(NULL); PositionNewsMessage(NULL); PositionNetworkChatWindow(NULL); } return true; } static bool PopulationInLabelActive(int32 p1) { UpdateAllTownVirtCoords(); return true; } static bool RedrawScreen(int32 p1) { MarkWholeScreenDirty(); return true; } /** * Redraw the smallmap after a colour scheme change. * @param p1 Callback parameter. * @return Always true. */ static bool RedrawSmallmap(int32 p1) { BuildLandLegend(); BuildOwnerLegend(); SetWindowClassesDirty(WC_SMALLMAP); return true; } static bool InvalidateDetailsWindow(int32 p1) { SetWindowClassesDirty(WC_VEHICLE_DETAILS); return true; } static bool StationSpreadChanged(int32 p1) { InvalidateWindowData(WC_SELECT_STATION, 0); InvalidateWindowData(WC_BUILD_STATION, 0); return true; } static bool InvalidateBuildIndustryWindow(int32 p1) { InvalidateWindowData(WC_BUILD_INDUSTRY, 0); return true; } static bool CloseSignalGUI(int32 p1) { if (p1 == 0) { DeleteWindowByClass(WC_BUILD_SIGNAL); } return true; } static bool InvalidateTownViewWindow(int32 p1) { InvalidateWindowClassesData(WC_TOWN_VIEW, p1); return true; } static bool DeleteSelectStationWindow(int32 p1) { DeleteWindowById(WC_SELECT_STATION, 0); return true; } static bool UpdateConsists(int32 p1) { Train *t; FOR_ALL_TRAINS(t) { /* Update the consist of all trains so the maximum speed is set correctly. */ if (t->IsFrontEngine() || t->IsFreeWagon()) t->ConsistChanged(CCF_TRACK); } InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); return true; } /* Check service intervals of vehicles, p1 is value of % or day based servicing */ static bool CheckInterval(int32 p1) { bool update_vehicles; VehicleDefaultSettings *vds; if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) { vds = &_settings_client.company.vehicle; update_vehicles = false; } else { vds = &Company::Get(_current_company)->settings.vehicle; update_vehicles = true; } if (p1 != 0) { vds->servint_trains = 50; vds->servint_roadveh = 50; vds->servint_aircraft = 50; vds->servint_ships = 50; } else { vds->servint_trains = 150; vds->servint_roadveh = 150; vds->servint_aircraft = 100; vds->servint_ships = 360; } if (update_vehicles) { const Company *c = Company::Get(_current_company); Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == _current_company && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { v->SetServiceInterval(CompanyServiceInterval(c, v->type)); v->SetServiceIntervalIsPercent(p1 != 0); } } } InvalidateDetailsWindow(0); return true; } static bool UpdateInterval(VehicleType type, int32 p1) { bool update_vehicles; VehicleDefaultSettings *vds; if (_game_mode == GM_MENU || !Company::IsValidID(_current_company)) { vds = &_settings_client.company.vehicle; update_vehicles = false; } else { vds = &Company::Get(_current_company)->settings.vehicle; update_vehicles = true; } /* Test if the interval is valid */ uint16 interval = GetServiceIntervalClamped(p1, vds->servint_ispercent); if (interval != p1) return false; if (update_vehicles) { Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->owner == _current_company && v->type == type && v->IsPrimaryVehicle() && !v->ServiceIntervalIsCustom()) { v->SetServiceInterval(p1); } } } InvalidateDetailsWindow(0); return true; } static bool UpdateIntervalTrains(int32 p1) { return UpdateInterval(VEH_TRAIN, p1); } static bool UpdateIntervalRoadVeh(int32 p1) { return UpdateInterval(VEH_ROAD, p1); } static bool UpdateIntervalShips(int32 p1) { return UpdateInterval(VEH_SHIP, p1); } static bool UpdateIntervalAircraft(int32 p1) { return UpdateInterval(VEH_AIRCRAFT, p1); } static bool TrainAccelerationModelChanged(int32 p1) { Train *t; FOR_ALL_TRAINS(t) { if (t->IsFrontEngine()) { t->tcache.cached_max_curve_speed = t->GetCurveSpeedLimit(); t->UpdateAcceleration(); } } /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */ SetWindowClassesDirty(WC_ENGINE_PREVIEW); InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); SetWindowClassesDirty(WC_VEHICLE_DETAILS); return true; } /** * This function updates the train acceleration cache after a steepness change. * @param p1 Callback parameter. * @return Always true. */ static bool TrainSlopeSteepnessChanged(int32 p1) { Train *t; FOR_ALL_TRAINS(t) { if (t->IsFrontEngine()) t->CargoChanged(); } return true; } /** * This function updates realistic acceleration caches when the setting "Road vehicle acceleration model" is set. * @param p1 Callback parameter * @return Always true */ static bool RoadVehAccelerationModelChanged(int32 p1) { if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) { RoadVehicle *rv; FOR_ALL_ROADVEHICLES(rv) { if (rv->IsFrontEngine()) { rv->CargoChanged(); } } } /* These windows show acceleration values only when realistic acceleration is on. They must be redrawn after a setting change. */ SetWindowClassesDirty(WC_ENGINE_PREVIEW); InvalidateWindowClassesData(WC_BUILD_VEHICLE, 0); SetWindowClassesDirty(WC_VEHICLE_DETAILS); return true; } /** * This function updates the road vehicle acceleration cache after a steepness change. * @param p1 Callback parameter. * @return Always true. */ static bool RoadVehSlopeSteepnessChanged(int32 p1) { RoadVehicle *rv; FOR_ALL_ROADVEHICLES(rv) { if (rv->IsFrontEngine()) rv->CargoChanged(); } return true; } static bool DragSignalsDensityChanged(int32) { InvalidateWindowData(WC_BUILD_SIGNAL, 0); return true; } static bool TownFoundingChanged(int32 p1) { if (_game_mode != GM_EDITOR && _settings_game.economy.found_town == TF_FORBIDDEN) { DeleteWindowById(WC_FOUND_TOWN, 0); return true; } InvalidateWindowData(WC_FOUND_TOWN, 0); return true; } static bool InvalidateVehTimetableWindow(int32 p1) { InvalidateWindowClassesData(WC_VEHICLE_TIMETABLE, VIWD_MODIFY_ORDERS); return true; } static bool ZoomMinMaxChanged(int32 p1) { extern void ConstrainAllViewportsZoom(); ConstrainAllViewportsZoom(); GfxClearSpriteCache(); if (_settings_client.gui.zoom_min > _gui_zoom) { /* Restrict GUI zoom if it is no longer available. */ _gui_zoom = _settings_client.gui.zoom_min; UpdateCursorSize(); LoadStringWidthTable(); } return true; } /** * Update any possible saveload window and delete any newgrf dialogue as * its widget parts might change. Reinit all windows as it allows access to the * newgrf debug button. * @param p1 unused. * @return Always true. */ static bool InvalidateNewGRFChangeWindows(int32 p1) { InvalidateWindowClassesData(WC_SAVELOAD); DeleteWindowByClass(WC_GAME_OPTIONS); ReInitAllWindows(); return true; } static bool InvalidateCompanyLiveryWindow(int32 p1) { InvalidateWindowClassesData(WC_COMPANY_COLOUR); return RedrawScreen(p1); } static bool InvalidateIndustryViewWindow(int32 p1) { InvalidateWindowClassesData(WC_INDUSTRY_VIEW); return true; } static bool InvalidateAISettingsWindow(int32 p1) { InvalidateWindowClassesData(WC_AI_SETTINGS); return true; } /** * Update the town authority window after a town authority setting change. * @param p1 Unused. * @return Always true. */ static bool RedrawTownAuthority(int32 p1) { SetWindowClassesDirty(WC_TOWN_AUTHORITY); return true; } /** * Invalidate the company infrastructure details window after a infrastructure maintenance setting change. * @param p1 Unused. * @return Always true. */ static bool InvalidateCompanyInfrastructureWindow(int32 p1) { InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE); return true; } /** * Invalidate the company details window after the shares setting changed. * @param p1 Unused. * @return Always true. */ static bool InvalidateCompanyWindow(int32 p1) { InvalidateWindowClassesData(WC_COMPANY); return true; } /** Checks if any settings are set to incorrect values, and sets them to correct values in that case. */ static void ValidateSettings() { /* Do not allow a custom sea level with the original land generator. */ if (_settings_newgame.game_creation.land_generator == 0 && _settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) { _settings_newgame.difficulty.quantity_sea_lakes = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE; } } static bool DifficultyNoiseChange(int32 i) { if (_game_mode == GM_NORMAL) { UpdateAirportsNoise(); if (_settings_game.economy.station_noise_level) { InvalidateWindowClassesData(WC_TOWN_VIEW, 0); } } return true; } static bool MaxNoAIsChange(int32 i) { if (GetGameSettings().difficulty.max_no_competitors != 0 && AI::GetInfoList()->size() == 0 && (!_networking || _network_server)) { ShowErrorMessage(STR_WARNING_NO_SUITABLE_AI, INVALID_STRING_ID, WL_CRITICAL); } return true; } /** * Check whether the road side may be changed. * @param p1 unused * @return true if the road side may be changed. */ static bool CheckRoadSide(int p1) { extern bool RoadVehiclesAreBuilt(); return _game_mode == GM_MENU || !RoadVehiclesAreBuilt(); } /** * Conversion callback for _gameopt_settings_game.landscape * It converts (or try) between old values and the new ones, * without losing initial setting of the user * @param value that was read from config file * @return the "hopefully" converted value */ static size_t ConvertLandscape(const char *value) { /* try with the old values */ return LookupOneOfMany("normal|hilly|desert|candy", value); } static bool CheckFreeformEdges(int32 p1) { if (_game_mode == GM_MENU) return true; if (p1 != 0) { Ship *s; FOR_ALL_SHIPS(s) { /* Check if there is a ship on the northern border. */ if (TileX(s->tile) == 0 || TileY(s->tile) == 0) { ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR); return false; } } BaseStation *st; FOR_ALL_BASE_STATIONS(st) { /* Check if there is a non-deleted buoy on the northern border. */ if (st->IsInUse() && (TileX(st->xy) == 0 || TileY(st->xy) == 0)) { ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_EMPTY, INVALID_STRING_ID, WL_ERROR); return false; } } for (uint i = 0; i < MapSizeX(); i++) MakeVoid(TileXY(i, 0)); for (uint i = 0; i < MapSizeY(); i++) MakeVoid(TileXY(0, i)); } else { for (uint i = 0; i < MapMaxX(); i++) { if (TileHeight(TileXY(i, 1)) != 0) { ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); return false; } } for (uint i = 1; i < MapMaxX(); i++) { if (!IsTileType(TileXY(i, MapMaxY() - 1), MP_WATER) || TileHeight(TileXY(1, MapMaxY())) != 0) { ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); return false; } } for (uint i = 0; i < MapMaxY(); i++) { if (TileHeight(TileXY(1, i)) != 0) { ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); return false; } } for (uint i = 1; i < MapMaxY(); i++) { if (!IsTileType(TileXY(MapMaxX() - 1, i), MP_WATER) || TileHeight(TileXY(MapMaxX(), i)) != 0) { ShowErrorMessage(STR_CONFIG_SETTING_EDGES_NOT_WATER, INVALID_STRING_ID, WL_ERROR); return false; } } /* Make tiles at the border water again. */ for (uint i = 0; i < MapMaxX(); i++) { SetTileHeight(TileXY(i, 0), 0); SetTileType(TileXY(i, 0), MP_WATER); } for (uint i = 0; i < MapMaxY(); i++) { SetTileHeight(TileXY(0, i), 0); SetTileType(TileXY(0, i), MP_WATER); } } MarkWholeScreenDirty(); return true; } /** * Changing the setting "allow multiple NewGRF sets" is not allowed * if there are vehicles. */ static bool ChangeDynamicEngines(int32 p1) { if (_game_mode == GM_MENU) return true; if (!EngineOverrideManager::ResetToCurrentNewGRFConfig()) { ShowErrorMessage(STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES, INVALID_STRING_ID, WL_ERROR); return false; } return true; } static bool ChangeMaxHeightLevel(int32 p1) { if (_game_mode == GM_NORMAL) return false; if (_game_mode != GM_EDITOR) return true; /* Check if at least one mountain on the map is higher than the new value. * If yes, disallow the change. */ for (TileIndex t = 0; t < MapSize(); t++) { if ((int32)TileHeight(t) > p1) { ShowErrorMessage(STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN, INVALID_STRING_ID, WL_ERROR); /* Return old, unchanged value */ return false; } } /* The smallmap uses an index from heightlevels to colours. Trigger rebuilding it. */ InvalidateWindowClassesData(WC_SMALLMAP, 2); return true; } static bool StationCatchmentChanged(int32 p1) { Station::RecomputeIndustriesNearForAll(); return true; } static bool MaxVehiclesChanged(int32 p1) { InvalidateWindowClassesData(WC_BUILD_TOOLBAR); MarkWholeScreenDirty(); return true; } #ifdef ENABLE_NETWORK static bool UpdateClientName(int32 p1) { NetworkUpdateClientName(); return true; } static bool UpdateServerPassword(int32 p1) { if (strcmp(_settings_client.network.server_password, "*") == 0) { _settings_client.network.server_password[0] = '\0'; } return true; } static bool UpdateRconPassword(int32 p1) { if (strcmp(_settings_client.network.rcon_password, "*") == 0) { _settings_client.network.rcon_password[0] = '\0'; } return true; } static bool UpdateClientConfigValues(int32 p1) { if (_network_server) NetworkServerSendConfigUpdate(); return true; } #endif /* ENABLE_NETWORK */ /* End - Callback Functions */ /** * Prepare for reading and old diff_custom by zero-ing the memory. */ static void PrepareOldDiffCustom() { memset(_old_diff_custom, 0, sizeof(_old_diff_custom)); } /** * Reading of the old diff_custom array and transforming it to the new format. * @param savegame is it read from the config or savegame. In the latter case * we are sure there is an array; in the former case we have * to check that. */ static void HandleOldDiffCustom(bool savegame) { uint options_to_load = GAME_DIFFICULTY_NUM - ((savegame && IsSavegameVersionBefore(4)) ? 1 : 0); if (!savegame) { /* If we did read to old_diff_custom, then at least one value must be non 0. */ bool old_diff_custom_used = false; for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) { old_diff_custom_used = (_old_diff_custom[i] != 0); } if (!old_diff_custom_used) return; } for (uint i = 0; i < options_to_load; i++) { const SettingDesc *sd = &_settings[i]; /* Skip deprecated options */ if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; void *var = GetVariableAddress(savegame ? &_settings_game : &_settings_newgame, &sd->save); Write_ValidateSetting(var, sd, (int32)((i == 4 ? 1000 : 1) * _old_diff_custom[i])); } } static void AILoadConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini->GetGroup(grpname); IniItem *item; /* Clean any configured AI */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(NULL); } /* If no group exists, return */ if (group == NULL) return; CompanyID c = COMPANY_FIRST; for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) { AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); config->Change(item->name); if (!config->HasScript()) { if (strcmp(item->name, "none") != 0) { DEBUG(script, 0, "The AI by the name '%s' was no longer found, and removed from the list.", item->name); continue; } } if (item->value != NULL) config->StringToSettings(item->value); } } static void GameLoadConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini->GetGroup(grpname); IniItem *item; /* Clean any configured GameScript */ GameConfig::GetConfig(GameConfig::SSS_FORCE_NEWGAME)->Change(NULL); /* If no group exists, return */ if (group == NULL) return; item = group->item; if (item == NULL) return; GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); config->Change(item->name); if (!config->HasScript()) { if (strcmp(item->name, "none") != 0) { DEBUG(script, 0, "The GameScript by the name '%s' was no longer found, and removed from the list.", item->name); return; } } if (item->value != NULL) config->StringToSettings(item->value); } /** * Convert a character to a hex nibble value, or \c -1 otherwise. * @param c Character to convert. * @return Hex value of the character, or \c -1 if not a hex digit. */ static int DecodeHexNibble(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'A' && c <= 'F') return c + 10 - 'A'; if (c >= 'a' && c <= 'f') return c + 10 - 'a'; return -1; } /** * Parse a sequence of characters (supposedly hex digits) into a sequence of bytes. * After the hex number should be a \c '|' character. * @param pos First character to convert. * @param dest [out] Output byte array to write the bytes. * @param dest_size Number of bytes in \a dest. * @return Whether reading was successful. */ static bool DecodeHexText(char *pos, uint8 *dest, size_t dest_size) { while (dest_size > 0) { int hi = DecodeHexNibble(pos[0]); int lo = (hi >= 0) ? DecodeHexNibble(pos[1]) : -1; if (lo < 0) return false; *dest++ = (hi << 4) | lo; pos += 2; dest_size--; } return *pos == '|'; } /** * Load a GRF configuration * @param ini The configuration to read from. * @param grpname Group name containing the configuration of the GRF. * @param is_static GRF is static. */ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_static) { IniGroup *group = ini->GetGroup(grpname); IniItem *item; GRFConfig *first = NULL; GRFConfig **curr = &first; if (group == NULL) return NULL; for (item = group->item; item != NULL; item = item->next) { GRFConfig *c = NULL; uint8 grfid_buf[4], md5sum[16]; char *filename = item->name; bool has_grfid = false; bool has_md5sum = false; /* Try reading "|" and on success, "|". */ has_grfid = DecodeHexText(filename, grfid_buf, lengthof(grfid_buf)); if (has_grfid) { filename += 1 + 2 * lengthof(grfid_buf); has_md5sum = DecodeHexText(filename, md5sum, lengthof(md5sum)); if (has_md5sum) filename += 1 + 2 * lengthof(md5sum); uint32 grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24); if (has_md5sum) { const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, md5sum); if (s != NULL) c = new GRFConfig(*s); } if (c == NULL && !FioCheckFileExists(filename, NEWGRF_DIR)) { const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID); if (s != NULL) c = new GRFConfig(*s); } } if (c == NULL) c = new GRFConfig(filename); /* Parse parameters */ if (!StrEmpty(item->value)) { int count = ParseIntList(item->value, (int*)c->param, lengthof(c->param)); if (count < 0) { SetDParamStr(0, filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); count = 0; } c->num_params = count; } /* Check if item is valid */ if (!FillGRFDetails(c, is_static) || HasBit(c->flags, GCF_INVALID)) { if (c->status == GCS_NOT_FOUND) { SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND); } else if (HasBit(c->flags, GCF_UNSAFE)) { SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNSAFE); } else if (HasBit(c->flags, GCF_SYSTEM)) { SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_SYSTEM); } else if (HasBit(c->flags, GCF_INVALID)) { SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE); } else { SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN); } SetDParamStr(0, StrEmpty(filename) ? item->name : filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL); delete c; continue; } /* Check for duplicate GRFID (will also check for duplicate filenames) */ bool duplicate = false; for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) { if (gc->ident.grfid == c->ident.grfid) { SetDParamStr(0, c->filename); SetDParamStr(1, gc->filename); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL); duplicate = true; break; } } if (duplicate) { delete c; continue; } /* Mark file as static to avoid saving in savegame. */ if (is_static) SetBit(c->flags, GCF_STATIC); /* Add item to list */ *curr = c; curr = &c->next; } return first; } static void AISaveConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini->GetGroup(grpname); if (group == NULL) return; group->Clear(); for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME); const char *name; char value[1024]; config->SettingsToString(value, lastof(value)); if (config->HasScript()) { name = config->GetName(); } else { name = "none"; } IniItem *item = new IniItem(group, name); item->SetValue(value); } } static void GameSaveConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini->GetGroup(grpname); if (group == NULL) return; group->Clear(); GameConfig *config = GameConfig::GetConfig(AIConfig::SSS_FORCE_NEWGAME); const char *name; char value[1024]; config->SettingsToString(value, lastof(value)); if (config->HasScript()) { name = config->GetName(); } else { name = "none"; } IniItem *item = new IniItem(group, name); item->SetValue(value); } /** * Save the version of OpenTTD to the ini file. * @param ini the ini to write to */ static void SaveVersionInConfig(IniFile *ini) { IniGroup *group = ini->GetGroup("version"); char version[9]; seprintf(version, lastof(version), "%08X", _openttd_newgrf_version); const char * const versions[][2] = { { "version_string", _openttd_revision }, { "version_number", version } }; for (uint i = 0; i < lengthof(versions); i++) { group->GetItem(versions[i][0], true)->SetValue(versions[i][1]); } } /* Save a GRF configuration to the given group name */ static void GRFSaveConfig(IniFile *ini, const char *grpname, const GRFConfig *list) { ini->RemoveGroup(grpname); IniGroup *group = ini->GetGroup(grpname); const GRFConfig *c; for (c = list; c != NULL; c = c->next) { /* Hex grfid (4 bytes in nibbles), "|", hex md5sum (16 bytes in nibbles), "|", file system path. */ char key[4 * 2 + 1 + 16 * 2 + 1 + MAX_PATH]; char params[512]; GRFBuildParamList(params, c, lastof(params)); char *pos = key + seprintf(key, lastof(key), "%08X|", BSWAP32(c->ident.grfid)); pos = md5sumToString(pos, lastof(key), c->ident.md5sum); seprintf(pos, lastof(key), "|%s", c->filename); group->GetItem(key, true)->SetValue(params); } } /* Common handler for saving/loading variables to the configuration file */ static void HandleSettingDescs(IniFile *ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool basic_settings = true, bool other_settings = true) { if (basic_settings) { proc(ini, (const SettingDesc*)_misc_settings, "misc", NULL); #if defined(WIN32) && !defined(DEDICATED) proc(ini, (const SettingDesc*)_win32_settings, "win32", NULL); #endif /* WIN32 */ } if (other_settings) { proc(ini, _settings, "patches", &_settings_newgame); proc(ini, _currency_settings,"currency", &_custom_currency); proc(ini, _company_settings, "company", &_settings_client.company); #ifdef ENABLE_NETWORK proc_list(ini, "server_bind_addresses", &_network_bind_list); proc_list(ini, "servers", &_network_host_list); proc_list(ini, "bans", &_network_ban_list); #endif /* ENABLE_NETWORK */ } } static IniFile *IniLoadConfig() { IniFile *ini = new IniFile(_list_group_names); ini->LoadFromDisk(_config_file, BASE_DIR); return ini; } /** * Load the values from the configuration files * @param minimal Load the minimal amount of the configuration to "bootstrap" the blitter and such. */ void LoadFromConfig(bool minimal) { IniFile *ini = IniLoadConfig(); if (!minimal) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one /* Load basic settings only during bootstrap, load other settings not during bootstrap */ HandleSettingDescs(ini, IniLoadSettings, IniLoadSettingList, minimal, !minimal); if (!minimal) { _grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false); _grfconfig_static = GRFLoadConfig(ini, "newgrf-static", true); AILoadConfig(ini, "ai_players"); GameLoadConfig(ini, "game_scripts"); PrepareOldDiffCustom(); IniLoadSettings(ini, _gameopt_settings, "gameopt", &_settings_newgame); HandleOldDiffCustom(false); ValidateSettings(); /* Display sheduled errors */ extern void ScheduleErrorMessage(ErrorList &datas); ScheduleErrorMessage(_settings_error_list); if (FindWindowById(WC_ERRMSG, 0) == NULL) ShowFirstError(); } delete ini; } /** Save the values to the configuration file */ void SaveToConfig() { IniFile *ini = IniLoadConfig(); /* Remove some obsolete groups. These have all been loaded into other groups. */ ini->RemoveGroup("patches"); ini->RemoveGroup("yapf"); ini->RemoveGroup("gameopt"); HandleSettingDescs(ini, IniSaveSettings, IniSaveSettingList); GRFSaveConfig(ini, "newgrf", _grfconfig_newgame); GRFSaveConfig(ini, "newgrf-static", _grfconfig_static); AISaveConfig(ini, "ai_players"); GameSaveConfig(ini, "game_scripts"); SaveVersionInConfig(ini); ini->SaveToDisk(_config_file); delete ini; } /** * Get the list of known NewGrf presets. * @param list[inout] Pointer to list for storing the preset names. */ void GetGRFPresetList(GRFPresetList *list) { list->Clear(); IniFile *ini = IniLoadConfig(); IniGroup *group; for (group = ini->group; group != NULL; group = group->next) { if (strncmp(group->name, "preset-", 7) == 0) { *list->Append() = stredup(group->name + 7); } } delete ini; } /** * Load a NewGRF configuration by preset-name. * @param config_name Name of the preset. * @return NewGRF configuration. * @see GetGRFPresetList */ GRFConfig *LoadGRFPresetFromConfig(const char *config_name) { size_t len = strlen(config_name) + 8; char *section = (char*)alloca(len); seprintf(section, section + len - 1, "preset-%s", config_name); IniFile *ini = IniLoadConfig(); GRFConfig *config = GRFLoadConfig(ini, section, false); delete ini; return config; } /** * Save a NewGRF configuration with a preset name. * @param config_name Name of the preset. * @param config NewGRF configuration to save. * @see GetGRFPresetList */ void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config) { size_t len = strlen(config_name) + 8; char *section = (char*)alloca(len); seprintf(section, section + len - 1, "preset-%s", config_name); IniFile *ini = IniLoadConfig(); GRFSaveConfig(ini, section, config); ini->SaveToDisk(_config_file); delete ini; } /** * Delete a NewGRF configuration by preset name. * @param config_name Name of the preset. */ void DeleteGRFPresetFromConfig(const char *config_name) { size_t len = strlen(config_name) + 8; char *section = (char*)alloca(len); seprintf(section, section + len - 1, "preset-%s", config_name); IniFile *ini = IniLoadConfig(); ini->RemoveGroup(section); ini->SaveToDisk(_config_file); delete ini; } const SettingDesc *GetSettingDescription(uint index) { if (index >= lengthof(_settings)) return NULL; return &_settings[index]; } /** * Network-safe changing of settings (server-only). * @param tile unused * @param flags operation to perform * @param p1 the index of the setting in the SettingDesc array which identifies it * @param p2 the new value for the setting * The new value is properly clamped to its minimum/maximum when setting * @param text unused * @return the cost of this operation or an error * @see _settings */ CommandCost CmdChangeSetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { const SettingDesc *sd = GetSettingDescription(p1); if (sd == NULL) return CMD_ERROR; if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) return CMD_ERROR; if (!sd->IsEditable(true)) return CMD_ERROR; if (flags & DC_EXEC) { void *var = GetVariableAddress(&GetGameSettings(), &sd->save); int32 oldval = (int32)ReadValue(var, sd->save.conv); int32 newval = (int32)p2; Write_ValidateSetting(var, sd, newval); newval = (int32)ReadValue(var, sd->save.conv); if (oldval == newval) return CommandCost(); if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { WriteValue(var, sd->save.conv, (int64)oldval); return CommandCost(); } if (sd->desc.flags & SGF_NO_NETWORK) { GamelogStartAction(GLAT_SETTING); GamelogSetting(sd->desc.name, oldval, newval); GamelogStopAction(); } SetWindowClassesDirty(WC_GAME_OPTIONS); } return CommandCost(); } /** * Change one of the per-company settings. * @param tile unused * @param flags operation to perform * @param p1 the index of the setting in the _company_settings array which identifies it * @param p2 the new value for the setting * The new value is properly clamped to its minimum/maximum when setting * @param text unused * @return the cost of this operation or an error */ CommandCost CmdChangeCompanySetting(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (p1 >= lengthof(_company_settings)) return CMD_ERROR; const SettingDesc *sd = &_company_settings[p1]; if (flags & DC_EXEC) { void *var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); int32 oldval = (int32)ReadValue(var, sd->save.conv); int32 newval = (int32)p2; Write_ValidateSetting(var, sd, newval); newval = (int32)ReadValue(var, sd->save.conv); if (oldval == newval) return CommandCost(); if (sd->desc.proc != NULL && !sd->desc.proc(newval)) { WriteValue(var, sd->save.conv, (int64)oldval); return CommandCost(); } SetWindowClassesDirty(WC_GAME_OPTIONS); } return CommandCost(); } /** * Top function to save the new value of an element of the Settings struct * @param index offset in the SettingDesc array of the Settings struct which * identifies the setting member we want to change * @param value new value of the setting * @param force_newgame force the newgame settings */ bool SetSettingValue(uint index, int32 value, bool force_newgame) { const SettingDesc *sd = &_settings[index]; /* If an item is company-based, we do not send it over the network * (if any) to change. Also *hack*hack* we update the _newgame version * of settings because changing a company-based setting in a game also * changes its defaults. At least that is the convention we have chosen */ if (sd->save.conv & SLF_NO_NETWORK_SYNC) { void *var = GetVariableAddress(&GetGameSettings(), &sd->save); Write_ValidateSetting(var, sd, value); if (_game_mode != GM_MENU) { void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); Write_ValidateSetting(var2, sd, value); } if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); SetWindowClassesDirty(WC_GAME_OPTIONS); return true; } if (force_newgame) { void *var2 = GetVariableAddress(&_settings_newgame, &sd->save); Write_ValidateSetting(var2, sd, value); return true; } /* send non-company-based settings over the network */ if (!_networking || (_networking && _network_server)) { return DoCommandP(0, index, value, CMD_CHANGE_SETTING); } return false; } /** * Top function to save the new value of an element of the Settings struct * @param index offset in the SettingDesc array of the CompanySettings struct * which identifies the setting member we want to change * @param value new value of the setting */ void SetCompanySetting(uint index, int32 value) { const SettingDesc *sd = &_company_settings[index]; if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) { DoCommandP(0, index, value, CMD_CHANGE_COMPANY_SETTING); } else { void *var = GetVariableAddress(&_settings_client.company, &sd->save); Write_ValidateSetting(var, sd, value); if (sd->desc.proc != NULL) sd->desc.proc((int32)ReadValue(var, sd->save.conv)); } } /** * Set the company settings for a new company to their default values. */ void SetDefaultCompanySettings(CompanyID cid) { Company *c = Company::Get(cid); const SettingDesc *sd; for (sd = _company_settings; sd->save.cmd != SL_END; sd++) { void *var = GetVariableAddress(&c->settings, &sd->save); Write_ValidateSetting(var, sd, (int32)(size_t)sd->desc.def); } } #if defined(ENABLE_NETWORK) /** * Sync all company settings in a multiplayer game. */ void SyncCompanySettings() { const SettingDesc *sd; uint i = 0; for (sd = _company_settings; sd->save.cmd != SL_END; sd++, i++) { const void *old_var = GetVariableAddress(&Company::Get(_current_company)->settings, &sd->save); const void *new_var = GetVariableAddress(&_settings_client.company, &sd->save); uint32 old_value = (uint32)ReadValue(old_var, sd->save.conv); uint32 new_value = (uint32)ReadValue(new_var, sd->save.conv); if (old_value != new_value) NetworkSendCommand(0, i, new_value, CMD_CHANGE_COMPANY_SETTING, NULL, NULL, _local_company); } } #endif /* ENABLE_NETWORK */ /** * Get the index in the _company_settings array of a setting * @param name The name of the setting * @return The index in the _company_settings array */ uint GetCompanySettingIndex(const char *name) { uint i; const SettingDesc *sd = GetSettingFromName(name, &i); assert(sd != NULL && (sd->desc.flags & SGF_PER_COMPANY) != 0); return i; } /** * Set a setting value with a string. * @param index the settings index. * @param value the value to write * @param force_newgame force the newgame settings * @note Strings WILL NOT be synced over the network */ bool SetSettingValue(uint index, const char *value, bool force_newgame) { const SettingDesc *sd = &_settings[index]; assert(sd->save.conv & SLF_NO_NETWORK_SYNC); if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) { char **var = (char**)GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); free(*var); *var = strcmp(value, "(null)") == 0 ? NULL : stredup(value); } else { char *var = (char*)GetVariableAddress(NULL, &sd->save); strecpy(var, value, &var[sd->save.length - 1]); } if (sd->desc.proc != NULL) sd->desc.proc(0); return true; } /** * Given a name of setting, return a setting description of it. * @param name Name of the setting to return a setting description of * @param i Pointer to an integer that will contain the index of the setting after the call, if it is successful. * @return Pointer to the setting description of setting \a name if it can be found, * \c NULL indicates failure to obtain the description */ const SettingDesc *GetSettingFromName(const char *name, uint *i) { const SettingDesc *sd; /* First check all full names */ for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) { if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; if (strcmp(sd->desc.name, name) == 0) return sd; } /* Then check the shortcut variant of the name. */ for (*i = 0, sd = _settings; sd->save.cmd != SL_END; sd++, (*i)++) { if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; const char *short_name = strchr(sd->desc.name, '.'); if (short_name != NULL) { short_name++; if (strcmp(short_name, name) == 0) return sd; } } if (strncmp(name, "company.", 8) == 0) name += 8; /* And finally the company-based settings */ for (*i = 0, sd = _company_settings; sd->save.cmd != SL_END; sd++, (*i)++) { if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; if (strcmp(sd->desc.name, name) == 0) return sd; } return NULL; } /* Those 2 functions need to be here, else we have to make some stuff non-static * and besides, it is also better to keep stuff like this at the same place */ void IConsoleSetSetting(const char *name, const char *value, bool force_newgame) { uint index; const SettingDesc *sd = GetSettingFromName(name, &index); if (sd == NULL) { IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); return; } bool success; if (sd->desc.cmd == SDT_STRING) { success = SetSettingValue(index, value, force_newgame); } else { uint32 val; extern bool GetArgumentInteger(uint32 *value, const char *arg); success = GetArgumentInteger(&val, value); if (!success) { IConsolePrintF(CC_ERROR, "'%s' is not an integer.", value); return; } success = SetSettingValue(index, val, force_newgame); } if (!success) { if (_network_server) { IConsoleError("This command/variable is not available during network games."); } else { IConsoleError("This command/variable is only available to a network server."); } } } void IConsoleSetSetting(const char *name, int value) { uint index; const SettingDesc *sd = GetSettingFromName(name, &index); assert(sd != NULL); SetSettingValue(index, value); } /** * Output value of a specific setting to the console * @param name Name of the setting to output its value * @param force_newgame force the newgame settings */ void IConsoleGetSetting(const char *name, bool force_newgame) { char value[20]; uint index; const SettingDesc *sd = GetSettingFromName(name, &index); const void *ptr; if (sd == NULL) { IConsolePrintF(CC_WARNING, "'%s' is an unknown setting.", name); return; } ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); if (sd->desc.cmd == SDT_STRING) { IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s'", name, (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) ? *(const char * const *)ptr : (const char *)ptr); } else { if (sd->desc.cmd == SDT_BOOLX) { seprintf(value, lastof(value), (*(const bool*)ptr != 0) ? "on" : "off"); } else { seprintf(value, lastof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); } IConsolePrintF(CC_WARNING, "Current value for '%s' is: '%s' (min: %s%d, max: %u)", name, value, (sd->desc.flags & SGF_0ISDISABLED) ? "(0) " : "", sd->desc.min, sd->desc.max); } } /** * List all settings and their value to the console * * @param prefilter If not \c NULL, only list settings with names that begin with \a prefilter prefix */ void IConsoleListSettings(const char *prefilter) { IConsolePrintF(CC_WARNING, "All settings with their current value:"); for (const SettingDesc *sd = _settings; sd->save.cmd != SL_END; sd++) { if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; if (prefilter != NULL && strstr(sd->desc.name, prefilter) == NULL) continue; char value[80]; const void *ptr = GetVariableAddress(&GetGameSettings(), &sd->save); if (sd->desc.cmd == SDT_BOOLX) { seprintf(value, lastof(value), (*(const bool *)ptr != 0) ? "on" : "off"); } else if (sd->desc.cmd == SDT_STRING) { seprintf(value, lastof(value), "%s", (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) ? *(const char * const *)ptr : (const char *)ptr); } else { seprintf(value, lastof(value), sd->desc.min < 0 ? "%d" : "%u", (int32)ReadValue(ptr, sd->save.conv)); } IConsolePrintF(CC_DEFAULT, "%s = %s", sd->desc.name, value); } IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value"); } /** * Save and load handler for settings * @param osd SettingDesc struct containing all information * @param object can be either NULL in which case we load global variables or * a pointer to a struct which is getting saved */ static void LoadSettings(const SettingDesc *osd, void *object) { for (; osd->save.cmd != SL_END; osd++) { const SaveLoad *sld = &osd->save; void *ptr = GetVariableAddress(object, sld); if (!SlObjectMember(ptr, sld)) continue; if (IsNumericType(sld->conv)) Write_ValidateSetting(ptr, osd, ReadValue(ptr, sld->conv)); } } /** * Save and load handler for settings * @param sd SettingDesc struct containing all information * @param object can be either NULL in which case we load global variables or * a pointer to a struct which is getting saved */ static void SaveSettings(const SettingDesc *sd, void *object) { /* We need to write the CH_RIFF header, but unfortunately can't call * SlCalcLength() because we have a different format. So do this manually */ const SettingDesc *i; size_t length = 0; for (i = sd; i->save.cmd != SL_END; i++) { length += SlCalcObjMemberLength(object, &i->save); } SlSetLength(length); for (i = sd; i->save.cmd != SL_END; i++) { void *ptr = GetVariableAddress(object, &i->save); SlObjectMember(ptr, &i->save); } } static void Load_OPTS() { /* Copy over default setting since some might not get loaded in * a networking environment. This ensures for example that the local * autosave-frequency stays when joining a network-server */ PrepareOldDiffCustom(); LoadSettings(_gameopt_settings, &_settings_game); HandleOldDiffCustom(true); } static void Load_PATS() { /* Copy over default setting since some might not get loaded in * a networking environment. This ensures for example that the local * currency setting stays when joining a network-server */ LoadSettings(_settings, &_settings_game); } static void Check_PATS() { LoadSettings(_settings, &_load_check_data.settings); } static void Save_PATS() { SaveSettings(_settings, &_settings_game); } void CheckConfig() { /* * Increase old default values for pf_maxdepth and pf_maxlength * to support big networks. */ if (_settings_newgame.pf.opf.pf_maxdepth == 16 && _settings_newgame.pf.opf.pf_maxlength == 512) { _settings_newgame.pf.opf.pf_maxdepth = 48; _settings_newgame.pf.opf.pf_maxlength = 4096; } } extern const ChunkHandler _setting_chunk_handlers[] = { { 'OPTS', NULL, Load_OPTS, NULL, NULL, CH_RIFF}, { 'PATS', Save_PATS, Load_PATS, NULL, Check_PATS, CH_RIFF | CH_LAST}, }; static bool IsSignedVarMemType(VarType vt) { switch (GetVarMemType(vt)) { case SLE_VAR_I8: case SLE_VAR_I16: case SLE_VAR_I32: case SLE_VAR_I64: return true; } return false; } openttd-1.5.3/src/ini_load.cpp0000644000000000000000000002174712627373442014771 0ustar rootroot/* $Id: ini_load.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 ini_load.cpp Definition of the #IniLoadFile class, related to reading and storing '*.ini' files. */ #include "stdafx.h" #include "core/alloc_func.hpp" #include "core/mem_func.hpp" #include "ini_type.h" #include "string_func.h" #include "safeguards.h" /** * Construct a new in-memory item of an Ini file. * @param parent the group we belong to * @param name the name of the item * @param last the last element of the name of the item */ IniItem::IniItem(IniGroup *parent, const char *name, const char *last) : next(NULL), value(NULL), comment(NULL) { this->name = stredup(name, last); str_validate(this->name, this->name + strlen(this->name)); *parent->last_item = this; parent->last_item = &this->next; } /** Free everything we loaded. */ IniItem::~IniItem() { free(this->name); free(this->value); free(this->comment); delete this->next; } /** * Replace the current value with another value. * @param value the value to replace with. */ void IniItem::SetValue(const char *value) { free(this->value); this->value = stredup(value); } /** * Construct a new in-memory group of an Ini file. * @param parent the file we belong to * @param name the name of the group * @param last the last element of the name of the group */ IniGroup::IniGroup(IniLoadFile *parent, const char *name, const char *last) : next(NULL), type(IGT_VARIABLES), item(NULL), comment(NULL) { this->name = stredup(name, last); str_validate(this->name, this->name + strlen(this->name)); this->last_item = &this->item; *parent->last_group = this; parent->last_group = &this->next; if (parent->list_group_names != NULL) { for (uint i = 0; parent->list_group_names[i] != NULL; i++) { if (strcmp(this->name, parent->list_group_names[i]) == 0) { this->type = IGT_LIST; return; } } } if (parent->seq_group_names != NULL) { for (uint i = 0; parent->seq_group_names[i] != NULL; i++) { if (strcmp(this->name, parent->seq_group_names[i]) == 0) { this->type = IGT_SEQUENCE; return; } } } } /** Free everything we loaded. */ IniGroup::~IniGroup() { free(this->name); free(this->comment); delete this->item; delete this->next; } /** * Get the item with the given name, and if it doesn't exist * and create is true it creates a new item. * @param name name of the item to find. * @param create whether to create an item when not found or not. * @return the requested item or NULL if not found. */ IniItem *IniGroup::GetItem(const char *name, bool create) { for (IniItem *item = this->item; item != NULL; item = item->next) { if (strcmp(item->name, name) == 0) return item; } if (!create) return NULL; /* otherwise make a new one */ return new IniItem(this, name, NULL); } /** * Clear all items in the group */ void IniGroup::Clear() { delete this->item; this->item = NULL; this->last_item = &this->item; } /** * Construct a new in-memory Ini file representation. * @param list_group_names A \c NULL terminated list with group names that should be loaded as lists instead of variables. @see IGT_LIST * @param seq_group_names A \c NULL terminated list with group names that should be loaded as lists of names. @see IGT_SEQUENCE */ IniLoadFile::IniLoadFile(const char * const *list_group_names, const char * const *seq_group_names) : group(NULL), comment(NULL), list_group_names(list_group_names), seq_group_names(seq_group_names) { this->last_group = &this->group; } /** Free everything we loaded. */ IniLoadFile::~IniLoadFile() { free(this->comment); delete this->group; } /** * Get the group with the given name. If it doesn't exist * and \a create_new is \c true create a new group. * @param name name of the group to find. * @param len the maximum length of said name (\c 0 means length of the string). * @param create_new Allow creation of group if it does not exist. * @return The requested group if it exists or was created, else \c NULL. */ IniGroup *IniLoadFile::GetGroup(const char *name, size_t len, bool create_new) { if (len == 0) len = strlen(name); /* does it exist already? */ for (IniGroup *group = this->group; group != NULL; group = group->next) { if (!strncmp(group->name, name, len) && group->name[len] == 0) { return group; } } if (!create_new) return NULL; /* otherwise make a new one */ IniGroup *group = new IniGroup(this, name, name + len - 1); group->comment = stredup("\n"); return group; } /** * Remove the group with the given name. * @param name name of the group to remove. */ void IniLoadFile::RemoveGroup(const char *name) { size_t len = strlen(name); IniGroup *prev = NULL; IniGroup *group; /* does it exist already? */ for (group = this->group; group != NULL; prev = group, group = group->next) { if (strncmp(group->name, name, len) == 0) { break; } } if (group == NULL) return; if (prev != NULL) { prev->next = prev->next->next; if (this->last_group == &group->next) this->last_group = &prev->next; } else { this->group = this->group->next; if (this->last_group == &group->next) this->last_group = &this->group; } group->next = NULL; delete group; } /** * Load the Ini file's data from the disk. * @param filename the file to load. * @param subdir the sub directory to load the file from. * @pre nothing has been loaded yet. */ void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir) { assert(this->last_group == &this->group); char buffer[1024]; IniGroup *group = NULL; char *comment = NULL; uint comment_size = 0; uint comment_alloc = 0; size_t end; FILE *in = this->OpenFile(filename, subdir, &end); if (in == NULL) return; end += ftell(in); /* for each line in the file */ while ((size_t)ftell(in) < end && fgets(buffer, sizeof(buffer), in)) { char c, *s; /* trim whitespace from the left side */ for (s = buffer; *s == ' ' || *s == '\t'; s++) {} /* trim whitespace from right side. */ char *e = s + strlen(s); while (e > s && ((c = e[-1]) == '\n' || c == '\r' || c == ' ' || c == '\t')) e--; *e = '\0'; /* Skip comments and empty lines outside IGT_SEQUENCE groups. */ if ((group == NULL || group->type != IGT_SEQUENCE) && (*s == '#' || *s == ';' || *s == '\0')) { uint ns = comment_size + (e - s + 1); uint a = comment_alloc; /* add to comment */ if (ns > a) { a = max(a, 128U); do a *= 2; while (a < ns); comment = ReallocT(comment, comment_alloc = a); } uint pos = comment_size; comment_size += (e - s + 1); comment[pos + e - s] = '\n'; // comment newline memcpy(comment + pos, s, e - s); // copy comment contents continue; } /* it's a group? */ if (s[0] == '[') { if (e[-1] != ']') { this->ReportFileError("ini: invalid group name '", buffer, "'"); } else { e--; } s++; // skip [ group = new IniGroup(this, s, e - 1); if (comment_size != 0) { group->comment = stredup(comment, comment + comment_size - 1); comment_size = 0; } } else if (group != NULL) { if (group->type == IGT_SEQUENCE) { /* A sequence group, use the line as item name without further interpretation. */ IniItem *item = new IniItem(group, buffer, e - 1); if (comment_size) { item->comment = stredup(comment, comment + comment_size - 1); comment_size = 0; } continue; } char *t; /* find end of keyname */ if (*s == '\"') { s++; for (t = s; *t != '\0' && *t != '\"'; t++) {} if (*t == '\"') *t = ' '; } else { for (t = s; *t != '\0' && *t != '=' && *t != '\t' && *t != ' '; t++) {} } /* it's an item in an existing group */ IniItem *item = new IniItem(group, s, t - 1); if (comment_size != 0) { item->comment = stredup(comment, comment + comment_size - 1); comment_size = 0; } /* find start of parameter */ while (*t == '=' || *t == ' ' || *t == '\t') t++; bool quoted = (*t == '\"'); /* remove starting quotation marks */ if (*t == '\"') t++; /* remove ending quotation marks */ e = t + strlen(t); if (e > t && e[-1] == '\"') e--; *e = '\0'; /* If the value was not quoted and empty, it must be NULL */ item->value = (!quoted && e == t) ? NULL : stredup(t); if (item->value != NULL) str_validate(item->value, item->value + strlen(item->value)); } else { /* it's an orphan item */ this->ReportFileError("ini: '", buffer, "' outside of group"); } } if (comment_size > 0) { this->comment = stredup(comment, comment + comment_size - 1); comment_size = 0; } free(comment); fclose(in); } openttd-1.5.3/src/engine_type.h0000644000000000000000000001665112627373441015163 0ustar rootroot/* $Id: engine_type.h 24810 2012-12-09 16:55:03Z frosch $ */ /* * 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 engine_type.h Types related to engines. */ #ifndef ENGINE_TYPE_H #define ENGINE_TYPE_H #include "economy_type.h" #include "rail_type.h" #include "cargo_type.h" #include "date_type.h" #include "sound_type.h" #include "strings_type.h" typedef uint16 EngineID; ///< Unique identification number of an engine. struct Engine; /** Available types of rail vehicles. */ enum RailVehicleTypes { RAILVEH_SINGLEHEAD, ///< indicates a "standalone" locomotive RAILVEH_MULTIHEAD, ///< indicates a combination of two locomotives RAILVEH_WAGON, ///< simple wagon, not motorized }; /** Type of rail engine. */ enum EngineClass { EC_STEAM, ///< Steam rail engine. EC_DIESEL, ///< Diesel rail engine. EC_ELECTRIC, ///< Electric rail engine. EC_MONORAIL, ///< Mono rail engine. EC_MAGLEV, ///< Maglev engine. }; /** Information about a rail vehicle. */ struct RailVehicleInfo { byte image_index; RailVehicleTypes railveh_type; byte cost_factor; ///< Purchase cost factor; For multiheaded engines the sum of both engine prices. RailTypeByte railtype; uint16 max_speed; ///< Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h) uint16 power; ///< Power of engine (hp); For multiheaded engines the sum of both engine powers. uint16 weight; ///< Weight of vehicle (tons); For multiheaded engines the weight of each single engine. byte running_cost; ///< Running cost of engine; For multiheaded engines the sum of both running costs. Price running_cost_class; EngineClass engclass; ///< Class of engine for this vehicle byte capacity; ///< Cargo capacity of vehicle; For multiheaded engines the capacity of each single engine. byte ai_passenger_only; ///< Bit value to tell AI that this engine is for passenger use only uint16 pow_wag_power; ///< Extra power applied to consist if wagon should be powered byte pow_wag_weight; ///< Extra weight applied to consist if wagon should be powered byte visual_effect; ///< Bitstuffed NewGRF visual effect data byte shorten_factor; ///< length on main map for this type is 8 - shorten_factor byte tractive_effort; ///< Tractive effort coefficient byte air_drag; ///< Coefficient of air drag byte user_def_data; ///< Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles }; /** Information about a ship vehicle. */ struct ShipVehicleInfo { byte image_index; byte cost_factor; uint16 max_speed; ///< Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h) uint16 capacity; byte running_cost; SoundID sfx; bool old_refittable; ///< Is ship refittable; only used during initialisation. Later use EngineInfo::refit_mask. byte visual_effect; ///< Bitstuffed NewGRF visual effect data byte ocean_speed_frac; ///< Fraction of maximum speed for ocean tiles. byte canal_speed_frac; ///< Fraction of maximum speed for canal/river tiles. /** Apply ocean/canal speed fraction to a velocity */ uint ApplyWaterClassSpeedFrac(uint raw_speed, bool is_ocean) const { /* speed_frac == 0 means no reduction while 0xFF means reduction to 1/256. */ return raw_speed * (256 - (is_ocean ? this->ocean_speed_frac : this->canal_speed_frac)) / 256; } }; /** * AircraftVehicleInfo subtypes, bitmask type. * If bit 0 is 0 then it is a helicopter, otherwise it is a plane * in which case bit 1 tells us whether it's a big(fast) plane or not. */ enum AircraftSubTypeBits { AIR_HELI = 0, AIR_CTOL = 1, ///< Conventional Take Off and Landing, i.e. planes AIR_FAST = 2 }; /** Information about a aircraft vehicle. */ struct AircraftVehicleInfo { byte image_index; byte cost_factor; byte running_cost; byte subtype; ///< Type of aircraft. @see AircraftSubTypeBits SoundID sfx; byte acceleration; uint16 max_speed; ///< Maximum speed (1 unit = 8 mph = 12.8 km-ish/h) byte mail_capacity; ///< Mail capacity (bags). uint16 passenger_capacity; ///< Passenger capacity (persons). uint16 max_range; ///< Maximum range of this aircraft. }; /** Information about a road vehicle. */ struct RoadVehicleInfo { byte image_index; byte cost_factor; byte running_cost; Price running_cost_class; SoundID sfx; uint16 max_speed; ///< Maximum speed (1 unit = 1/3.2 mph = 0.5 km-ish/h) byte capacity; uint8 weight; ///< Weight in 1/4t units uint8 power; ///< Power in 10hp units uint8 tractive_effort; ///< Coefficient of tractive effort uint8 air_drag; ///< Coefficient of air drag byte visual_effect; ///< Bitstuffed NewGRF visual effect data byte shorten_factor; ///< length on main map for this type is 8 - shorten_factor }; /** * Information about a vehicle * @see table/engines.h */ struct EngineInfo { Date base_intro; ///< Basic date of engine introduction (without random parts). Year lifelength; ///< Lifetime of a single vehicle Year base_life; ///< Basic duration of engine availability (without random parts). \c 0xFF means infinite life. byte decay_speed; byte load_amount; byte climates; ///< Climates supported by the engine. CargoID cargo_type; uint32 refit_mask; byte refit_cost; byte misc_flags; ///< Miscellaneous flags. @see EngineMiscFlags byte callback_mask; ///< Bitmask of vehicle callbacks that have to be called int8 retire_early; ///< Number of years early to retire vehicle StringID string_id; ///< Default name of engine uint16 cargo_age_period; ///< Number of ticks before carried cargo is aged. }; /** * EngineInfo.misc_flags is a bitmask, with the following values */ enum EngineMiscFlags { EF_RAIL_TILTS = 0, ///< Rail vehicle tilts in curves EF_ROAD_TRAM = 0, ///< Road vehicle is a tram/light rail vehicle EF_USES_2CC = 1, ///< Vehicle uses two company colours EF_RAIL_IS_MU = 2, ///< Rail vehicle is a multiple-unit (DMU/EMU) EF_RAIL_FLIPS = 3, ///< Rail vehicle can be flipped in the depot EF_AUTO_REFIT = 4, ///< Automatic refitting is allowed EF_NO_DEFAULT_CARGO_MULTIPLIER = 5, ///< Use the new capacity algorithm. The default cargotype of the vehicle does not affect capacity multipliers. CB 15 is also called in purchase list. EF_NO_BREAKDOWN_SMOKE = 6, ///< Do not show black smoke during a breakdown. }; /** * Engine.flags is a bitmask, with the following values. */ enum EngineFlags { ENGINE_AVAILABLE = 1, ///< This vehicle is available to everyone. ENGINE_EXCLUSIVE_PREVIEW = 2, ///< This vehicle is in the exclusive preview stage, either being used or being offered to a company. }; static const uint MAX_LENGTH_ENGINE_NAME_CHARS = 32; ///< The maximum length of an engine name in characters including '\0' static const EngineID INVALID_ENGINE = 0xFFFF; ///< Constant denoting an invalid engine. #endif /* ENGINE_TYPE_H */ openttd-1.5.3/src/economy_type.h0000644000000000000000000001736112627373435015371 0ustar rootroot/* $Id: economy_type.h 25788 2013-09-21 13:07:42Z zuu $ */ /* * 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 economy_type.h Types related to the economy. */ #ifndef ECONOMY_TYPE_H #define ECONOMY_TYPE_H #include "core/overflowsafe_type.hpp" #include "core/enum_type.hpp" typedef OverflowSafeInt64 Money; /** Data of the economy. */ struct Economy { Money max_loan; ///< NOSAVE: Maximum possible loan int16 fluct; ///< Economy fluctuation status byte interest_rate; ///< Interest byte infl_amount; ///< inflation amount byte infl_amount_pr; ///< inflation rate for payment rates uint32 industry_daily_change_counter; ///< Bits 31-16 are number of industry to be performed, 15-0 are fractional collected daily uint32 industry_daily_increment; ///< The value which will increment industry_daily_change_counter. Computed value. NOSAVE uint64 inflation_prices; ///< Cumulated inflation of prices since game start; 16 bit fractional part uint64 inflation_payment; ///< Cumulated inflation of cargo paypent since game start; 16 bit fractional part /* Old stuff for savegame conversion only */ Money old_max_loan_unround; ///< Old: Unrounded max loan uint16 old_max_loan_unround_fract; ///< Old: Fraction of the unrounded max loan }; /** Score categories in the detailed performance rating. */ enum ScoreID { SCORE_BEGIN = 0, SCORE_VEHICLES = 0, SCORE_STATIONS = 1, SCORE_MIN_PROFIT = 2, SCORE_MIN_INCOME = 3, SCORE_MAX_INCOME = 4, SCORE_DELIVERED = 5, SCORE_CARGO = 6, SCORE_MONEY = 7, SCORE_LOAN = 8, SCORE_TOTAL = 9, ///< This must always be the last entry SCORE_END = 10, ///< How many scores are there.. SCORE_MAX = 1000, ///< The max score that can be in the performance history /* the scores together of score_info is allowed to be more! */ }; DECLARE_POSTFIX_INCREMENT(ScoreID) /** Data structure for storing how the score is computed for a single score id. */ struct ScoreInfo { int needed; ///< How much you need to get the perfect score int score; ///< How much score it will give }; /** * Enumeration of all base prices for use with #Prices. * The prices are ordered as they are expected by NewGRF cost multipliers, so don't shuffle them. */ enum Price { PR_BEGIN = 0, PR_STATION_VALUE = 0, PR_BUILD_RAIL, PR_BUILD_ROAD, PR_BUILD_SIGNALS, PR_BUILD_BRIDGE, PR_BUILD_DEPOT_TRAIN, PR_BUILD_DEPOT_ROAD, PR_BUILD_DEPOT_SHIP, PR_BUILD_TUNNEL, PR_BUILD_STATION_RAIL, PR_BUILD_STATION_RAIL_LENGTH, PR_BUILD_STATION_AIRPORT, PR_BUILD_STATION_BUS, PR_BUILD_STATION_TRUCK, PR_BUILD_STATION_DOCK, PR_BUILD_VEHICLE_TRAIN, PR_BUILD_VEHICLE_WAGON, PR_BUILD_VEHICLE_AIRCRAFT, PR_BUILD_VEHICLE_ROAD, PR_BUILD_VEHICLE_SHIP, PR_BUILD_TREES, PR_TERRAFORM, PR_CLEAR_GRASS, PR_CLEAR_ROUGH, PR_CLEAR_ROCKS, PR_CLEAR_FIELDS, PR_CLEAR_TREES, PR_CLEAR_RAIL, PR_CLEAR_SIGNALS, PR_CLEAR_BRIDGE, PR_CLEAR_DEPOT_TRAIN, PR_CLEAR_DEPOT_ROAD, PR_CLEAR_DEPOT_SHIP, PR_CLEAR_TUNNEL, PR_CLEAR_WATER, PR_CLEAR_STATION_RAIL, PR_CLEAR_STATION_AIRPORT, PR_CLEAR_STATION_BUS, PR_CLEAR_STATION_TRUCK, PR_CLEAR_STATION_DOCK, PR_CLEAR_HOUSE, PR_CLEAR_ROAD, PR_RUNNING_TRAIN_STEAM, PR_RUNNING_TRAIN_DIESEL, PR_RUNNING_TRAIN_ELECTRIC, PR_RUNNING_AIRCRAFT, PR_RUNNING_ROADVEH, PR_RUNNING_SHIP, PR_BUILD_INDUSTRY, PR_CLEAR_INDUSTRY, PR_BUILD_OBJECT, PR_CLEAR_OBJECT, PR_BUILD_WAYPOINT_RAIL, PR_CLEAR_WAYPOINT_RAIL, PR_BUILD_WAYPOINT_BUOY, PR_CLEAR_WAYPOINT_BUOY, PR_TOWN_ACTION, PR_BUILD_FOUNDATION, PR_BUILD_INDUSTRY_RAW, PR_BUILD_TOWN, PR_BUILD_CANAL, PR_CLEAR_CANAL, PR_BUILD_AQUEDUCT, PR_CLEAR_AQUEDUCT, PR_BUILD_LOCK, PR_CLEAR_LOCK, PR_INFRASTRUCTURE_RAIL, PR_INFRASTRUCTURE_ROAD, PR_INFRASTRUCTURE_WATER, PR_INFRASTRUCTURE_STATION, PR_INFRASTRUCTURE_AIRPORT, PR_END, INVALID_PRICE = 0xFF }; DECLARE_POSTFIX_INCREMENT(Price) typedef Money Prices[PR_END]; ///< Prices of everything. @see Price typedef int8 PriceMultipliers[PR_END]; /** Types of expenses. */ enum ExpensesType { EXPENSES_CONSTRUCTION = 0, ///< Construction costs. EXPENSES_NEW_VEHICLES, ///< New vehicles. EXPENSES_TRAIN_RUN, ///< Running costs trains. EXPENSES_ROADVEH_RUN, ///< Running costs road vehicles. EXPENSES_AIRCRAFT_RUN, ///< Running costs aircrafts. EXPENSES_SHIP_RUN, ///< Running costs ships. EXPENSES_PROPERTY, ///< Property costs. EXPENSES_TRAIN_INC, ///< Income from trains. EXPENSES_ROADVEH_INC, ///< Income from road vehicles. EXPENSES_AIRCRAFT_INC, ///< Income from aircrafts. EXPENSES_SHIP_INC, ///< Income from ships. EXPENSES_LOAN_INT, ///< Interest payments over the loan. EXPENSES_OTHER, ///< Other expenses. EXPENSES_END, ///< Number of expense types. INVALID_EXPENSES = 0xFF, ///< Invalid expense type. }; /** Define basic enum properties for ExpensesType */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT ExpensesTypeByte; ///< typedefing-enumification of ExpensesType /** * Categories of a price bases. */ enum PriceCategory { PCAT_NONE, ///< Not affected by difficulty settings PCAT_RUNNING, ///< Price is affected by "vehicle running cost" difficulty setting PCAT_CONSTRUCTION, ///< Price is affected by "construction cost" difficulty setting }; /** * Describes properties of price bases. */ struct PriceBaseSpec { Money start_price; ///< Default value at game start, before adding multipliers. PriceCategory category; ///< Price is affected by certain difficulty settings. uint grf_feature; ///< GRF Feature that decides whether price multipliers apply locally or globally, #GSF_END if none. Price fallback_price; ///< Fallback price multiplier for new prices but old grfs. }; /** The "steps" in loan size, in British Pounds! */ static const int LOAN_INTERVAL = 10000; /** * Maximum inflation (including fractional part) without causing overflows in int64 price computations. * This allows for 32 bit base prices (21 are currently needed). * Considering the sign bit and 16 fractional bits, there are 15 bits left. * 170 years of 4% inflation result in a inflation of about 822, so 10 bits are actually enough. * Note that NewGRF multipliers share the 16 fractional bits. * @see MAX_PRICE_MODIFIER */ static const uint64 MAX_INFLATION = (1ull << (63 - 32)) - 1; /** * Maximum NewGRF price modifiers. * Increasing base prices by factor 65536 should be enough. * @see MAX_INFLATION */ static const int MIN_PRICE_MODIFIER = -8; static const int MAX_PRICE_MODIFIER = 16; static const int INVALID_PRICE_MODIFIER = MIN_PRICE_MODIFIER - 1; /** Multiplier for how many regular track bits a tunnel/bridge counts. */ static const uint TUNNELBRIDGE_TRACKBIT_FACTOR = 4; /** Multiplier for how many regular track bits a level crossing counts. */ static const uint LEVELCROSSING_TRACKBIT_FACTOR = 2; /** Multiplier for how many regular tiles a lock counts. */ static const uint LOCK_DEPOT_TILE_FACTOR = 2; struct CargoPayment; typedef uint32 CargoPaymentID; #endif /* ECONOMY_TYPE_H */ openttd-1.5.3/src/zoom_type.h0000644000000000000000000000525312627373435014701 0ustar rootroot/* $Id: zoom_type.h 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 zoom_type.h Types related to zooming in and out. */ #ifndef ZOOM_TYPE_H #define ZOOM_TYPE_H #include "core/enum_type.hpp" static int const ZOOM_LVL_SHIFT = 2; static int const ZOOM_LVL_BASE = 1 << ZOOM_LVL_SHIFT; /** All zoom levels we know. */ enum ZoomLevel { /* Our possible zoom-levels */ ZOOM_LVL_BEGIN = 0, ///< Begin for iteration. ZOOM_LVL_NORMAL = 0, ///< The normal zoom level. ZOOM_LVL_OUT_2X, ///< Zoomed 2 times out. ZOOM_LVL_OUT_4X, ///< Zoomed 4 times out. ZOOM_LVL_OUT_8X, ///< Zoomed 8 times out. ZOOM_LVL_OUT_16X, ///< Zoomed 16 times out. ZOOM_LVL_OUT_32X, ///< Zoomed 32 times out. ZOOM_LVL_END, ///< End for iteration. ZOOM_LVL_COUNT = ZOOM_LVL_END - ZOOM_LVL_BEGIN, ///< Number of zoom levels. /* Here we define in which zoom viewports are */ ZOOM_LVL_VIEWPORT = ZOOM_LVL_OUT_4X, ///< Default zoom level for viewports. ZOOM_LVL_NEWS = ZOOM_LVL_OUT_4X, ///< Default zoom level for the news messages. ZOOM_LVL_INDUSTRY = ZOOM_LVL_OUT_8X, ///< Default zoom level for the industry view. ZOOM_LVL_TOWN = ZOOM_LVL_OUT_8X, ///< Default zoom level for the town view. ZOOM_LVL_AIRCRAFT = ZOOM_LVL_OUT_4X, ///< Default zoom level for the aircraft view. ZOOM_LVL_SHIP = ZOOM_LVL_OUT_4X, ///< Default zoom level for the ship view. ZOOM_LVL_TRAIN = ZOOM_LVL_OUT_4X, ///< Default zoom level for the train view. ZOOM_LVL_ROADVEH = ZOOM_LVL_OUT_4X, ///< Default zoom level for the road vehicle view. ZOOM_LVL_WORLD_SCREENSHOT = ZOOM_LVL_OUT_4X, ///< Default zoom level for the world screen shot. ZOOM_LVL_DETAIL = ZOOM_LVL_OUT_8X, ///< All zoomlevels below or equal to this, will result in details on the screen, like road-work, ... ZOOM_LVL_MIN = ZOOM_LVL_NORMAL, ///< Minimum zoom level. ZOOM_LVL_MAX = ZOOM_LVL_OUT_32X, ///< Maximum zoom level. }; DECLARE_POSTFIX_INCREMENT(ZoomLevel) /** Type for storing the zoom level in a byte. */ typedef SimpleTinyEnumT ZoomLevelByte; extern ZoomLevelByte _gui_zoom; #define ZOOM_LVL_GUI (_gui_zoom) #endif /* ZOOM_TYPE_H */ openttd-1.5.3/src/bridge_gui.cpp0000644000000000000000000003637312627373441015313 0ustar rootroot/* $Id: bridge_gui.cpp 26960 2014-10-05 11:20:02Z peter1138 $ */ /* * 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 bridge_gui.cpp Graphical user interface for bridge construction */ #include "stdafx.h" #include "error.h" #include "command_func.h" #include "rail.h" #include "strings_func.h" #include "window_func.h" #include "sound_func.h" #include "gfx_func.h" #include "tunnelbridge.h" #include "sortlist_type.h" #include "widgets/dropdown_func.h" #include "core/geometry_func.hpp" #include "cmd_helper.h" #include "tunnelbridge_map.h" #include "road_gui.h" #include "widgets/bridge_widget.h" #include "table/strings.h" #include "safeguards.h" /** The type of the last built rail bridge */ static BridgeType _last_railbridge_type = 0; /** The type of the last built road bridge */ static BridgeType _last_roadbridge_type = 0; /** * Carriage for the data we need if we want to build a bridge */ struct BuildBridgeData { BridgeType index; const BridgeSpec *spec; Money cost; }; typedef GUIList GUIBridgeList; ///< List of bridges, used in #BuildBridgeWindow. /** * Callback executed after a build Bridge CMD has been called * * @param result Whether the build succeeded * @param end_tile End tile of the bridge. * @param p1 packed start tile coords (~ dx) * @param p2 various bitstuffed elements * - p2 = (bit 0- 7) - bridge type (hi bh) * - p2 = (bit 8-11) - rail type or road types. * - p2 = (bit 15-16) - transport type. */ void CcBuildBridge(const CommandCost &result, TileIndex end_tile, uint32 p1, uint32 p2) { if (result.Failed()) return; if (_settings_client.sound.confirm) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, end_tile); TransportType transport_type = Extract(p2); if (transport_type == TRANSPORT_ROAD) { DiagDirection end_direction = ReverseDiagDir(GetTunnelBridgeDirection(end_tile)); ConnectRoadToStructure(end_tile, end_direction); DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(p1)); ConnectRoadToStructure(p1, start_direction); } } /** Window class for handling the bridge-build GUI. */ class BuildBridgeWindow : public Window { private: /* Runtime saved values */ static Listing last_sorting; ///< Last setting of the sort. /* Constants for sorting the bridges */ static const StringID sorter_names[]; static GUIBridgeList::SortFunction * const sorter_funcs[]; /* Internal variables */ TileIndex start_tile; TileIndex end_tile; uint32 type; GUIBridgeList *bridges; int bridgetext_offset; ///< Horizontal offset of the text describing the bridge properties in #WID_BBS_BRIDGE_LIST relative to the left edge. Scrollbar *vscroll; /** Sort the bridges by their index */ static int CDECL BridgeIndexSorter(const BuildBridgeData *a, const BuildBridgeData *b) { return a->index - b->index; } /** Sort the bridges by their price */ static int CDECL BridgePriceSorter(const BuildBridgeData *a, const BuildBridgeData *b) { return a->cost - b->cost; } /** Sort the bridges by their maximum speed */ static int CDECL BridgeSpeedSorter(const BuildBridgeData *a, const BuildBridgeData *b) { return a->spec->speed - b->spec->speed; } void BuildBridge(uint8 i) { switch ((TransportType)(this->type >> 15)) { case TRANSPORT_RAIL: _last_railbridge_type = this->bridges->Get(i)->index; break; case TRANSPORT_ROAD: _last_roadbridge_type = this->bridges->Get(i)->index; break; default: break; } DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->Get(i)->index, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); } /** Sort the builable bridges */ void SortBridgeList() { this->bridges->Sort(); /* Display the current sort variant */ this->GetWidget(WID_BBS_DROPDOWN_CRITERIA)->widget_data = this->sorter_names[this->bridges->SortType()]; /* Set the modified widgets dirty */ this->SetWidgetDirty(WID_BBS_DROPDOWN_CRITERIA); this->SetWidgetDirty(WID_BBS_BRIDGE_LIST); } public: BuildBridgeWindow(WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(desc), start_tile(start), end_tile(end), type(br_type), bridges(bl) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_BBS_SCROLLBAR); /* Change the data, or the caption of the gui. Set it to road or rail, accordingly. */ this->GetWidget(WID_BBS_CAPTION)->widget_data = (GB(this->type, 15, 2) == TRANSPORT_ROAD) ? STR_SELECT_ROAD_BRIDGE_CAPTION : STR_SELECT_RAIL_BRIDGE_CAPTION; this->FinishInitNested(GB(br_type, 15, 2)); // Initializes 'this->bridgetext_offset'. this->parent = FindWindowById(WC_BUILD_TOOLBAR, GB(this->type, 15, 2)); this->bridges->SetListing(this->last_sorting); this->bridges->SetSortFuncs(this->sorter_funcs); this->bridges->NeedResort(); this->SortBridgeList(); this->vscroll->SetCount(bl->Length()); } ~BuildBridgeWindow() { this->last_sorting = this->bridges->GetListing(); delete bridges; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_BBS_DROPDOWN_ORDER: { Dimension d = GetStringBoundingBox(this->GetWidget(widget)->widget_data); d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better. d.height += padding.height; *size = maxdim(*size, d); break; } case WID_BBS_DROPDOWN_CRITERIA: { Dimension d = {0, 0}; for (const StringID *str = this->sorter_names; *str != INVALID_STRING_ID; str++) { d = maxdim(d, GetStringBoundingBox(*str)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_BBS_BRIDGE_LIST: { Dimension sprite_dim = {0, 0}; // Biggest bridge sprite dimension Dimension text_dim = {0, 0}; // Biggest text dimension for (int i = 0; i < (int)this->bridges->Length(); i++) { const BridgeSpec *b = this->bridges->Get(i)->spec; sprite_dim = maxdim(sprite_dim, GetSpriteSize(b->sprite)); SetDParam(2, this->bridges->Get(i)->cost); SetDParam(1, b->speed); SetDParam(0, b->material); text_dim = maxdim(text_dim, GetStringBoundingBox(_game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_SCENEDIT_INFO : STR_SELECT_BRIDGE_INFO)); } sprite_dim.height++; // Sprite is rendered one pixel down in the matrix field. text_dim.height++; // Allowing the bottom row pixels to be rendered on the edge of the matrix field. resize->height = max(sprite_dim.height, text_dim.height) + 2; // Max of both sizes + account for matrix edges. this->bridgetext_offset = WD_MATRIX_LEFT + sprite_dim.width + 1; // Left edge of text, 1 pixel distance from the sprite. size->width = this->bridgetext_offset + text_dim.width + WD_MATRIX_RIGHT; size->height = 4 * resize->height; // Smallest bridge gui is 4 entries high in the matrix. break; } } } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { /* Position the window so hopefully the first bridge from the list is under the mouse pointer. */ NWidgetBase *list = this->GetWidget(WID_BBS_BRIDGE_LIST); Point corner; // point of the top left corner of the window. corner.y = Clamp(_cursor.pos.y - list->pos_y - 5, GetMainViewTop(), GetMainViewBottom() - sm_height); corner.x = Clamp(_cursor.pos.x - list->pos_x - 5, 0, _screen.width - sm_width); return corner; } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_BBS_DROPDOWN_ORDER: this->DrawSortButtonState(widget, this->bridges->IsDescSortOrder() ? SBS_DOWN : SBS_UP); break; case WID_BBS_BRIDGE_LIST: { uint y = r.top; for (int i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < (int)this->bridges->Length(); i++) { const BridgeSpec *b = this->bridges->Get(i)->spec; SetDParam(2, this->bridges->Get(i)->cost); SetDParam(1, b->speed); SetDParam(0, b->material); DrawSprite(b->sprite, b->pal, r.left + WD_MATRIX_LEFT, y + this->resize.step_height - 1 - GetSpriteSize(b->sprite).height); DrawStringMultiLine(r.left + this->bridgetext_offset, r.right, y + 2, y + this->resize.step_height, _game_mode == GM_EDITOR ? STR_SELECT_BRIDGE_SCENEDIT_INFO : STR_SELECT_BRIDGE_INFO); y += this->resize.step_height; } break; } } } virtual EventState OnKeyPress(WChar key, uint16 keycode) { const uint8 i = keycode - '1'; if (i < 9 && i < this->bridges->Length()) { /* Build the requested bridge */ this->BuildBridge(i); delete this; return ES_HANDLED; } return ES_NOT_HANDLED; } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { default: break; case WID_BBS_BRIDGE_LIST: { uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BBS_BRIDGE_LIST); if (i < this->bridges->Length()) { this->BuildBridge(i); delete this; } break; } case WID_BBS_DROPDOWN_ORDER: this->bridges->ToggleSortOrder(); this->SetDirty(); break; case WID_BBS_DROPDOWN_CRITERIA: ShowDropDownMenu(this, this->sorter_names, this->bridges->SortType(), WID_BBS_DROPDOWN_CRITERIA, 0, 0); break; } } virtual void OnDropdownSelect(int widget, int index) { if (widget == WID_BBS_DROPDOWN_CRITERIA && this->bridges->SortType() != index) { this->bridges->SetSortType(index); this->SortBridgeList(); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_BBS_BRIDGE_LIST); } }; /** Set the default sorting for the bridges */ Listing BuildBridgeWindow::last_sorting = {true, 2}; /** Available bridge sorting functions. */ GUIBridgeList::SortFunction * const BuildBridgeWindow::sorter_funcs[] = { &BridgeIndexSorter, &BridgePriceSorter, &BridgeSpeedSorter }; /** Names of the sorting functions. */ const StringID BuildBridgeWindow::sorter_names[] = { STR_SORT_BY_NUMBER, STR_SORT_BY_COST, STR_SORT_BY_MAX_SPEED, INVALID_STRING_ID }; /** Widgets of the bridge gui. */ static const NWidgetPart _nested_build_bridge_widgets[] = { /* Header */ NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BBS_CAPTION), SetDataTip(STR_SELECT_RAIL_BRIDGE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), /* Sort order + criteria buttons */ NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_DARK_GREEN, WID_BBS_DROPDOWN_ORDER), SetFill(1, 0), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_DARK_GREEN, WID_BBS_DROPDOWN_CRITERIA), SetFill(1, 0), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA), EndContainer(), /* Matrix. */ NWidget(WWT_MATRIX, COLOUR_DARK_GREEN, WID_BBS_BRIDGE_LIST), SetFill(1, 0), SetResize(0, 22), SetMatrixDataTip(1, 0, STR_SELECT_BRIDGE_SELECTION_TOOLTIP), SetScrollbar(WID_BBS_SCROLLBAR), EndContainer(), /* scrollbar + resize button */ NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_DARK_GREEN, WID_BBS_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), EndContainer(), EndContainer(), }; /** Window definition for the rail bridge selection window. */ static WindowDesc _build_bridge_desc( WDP_AUTO, "build_bridge", 200, 114, WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_bridge_widgets, lengthof(_nested_build_bridge_widgets) ); /** * Prepare the data for the build a bridge window. * If we can't build a bridge under the given conditions * show an error message. * * @param start The start tile of the bridge * @param end The end tile of the bridge * @param transport_type The transport type * @param road_rail_type The road/rail type */ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte road_rail_type) { DeleteWindowByClass(WC_BUILD_BRIDGE); /* Data type for the bridge. * Bit 16,15 = transport type, * 14..8 = road/rail types, * 7..0 = type of bridge */ uint32 type = (transport_type << 15) | (road_rail_type << 8); /* The bridge length without ramps. */ const uint bridge_len = GetTunnelBridgeLength(start, end); /* If Ctrl is being pressed, check whether the last bridge built is available * If so, return this bridge type. Otherwise continue normally. * We store bridge types for each transport type, so we have to check for * the transport type beforehand. */ BridgeType last_bridge_type = 0; switch (transport_type) { case TRANSPORT_ROAD: last_bridge_type = _last_roadbridge_type; break; case TRANSPORT_RAIL: last_bridge_type = _last_railbridge_type; break; default: break; // water ways and air routes don't have bridge types } if (_ctrl_pressed && CheckBridgeAvailability(last_bridge_type, bridge_len).Succeeded()) { DoCommandP(end, start, type | last_bridge_type, CMD_BUILD_BRIDGE | CMD_MSG(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE), CcBuildBridge); return; } /* only query bridge building possibility once, result is the same for all bridges! * returns CMD_ERROR on failure, and price on success */ StringID errmsg = INVALID_STRING_ID; CommandCost ret = DoCommand(end, start, type, CommandFlagsToDCFlags(GetCommandFlags(CMD_BUILD_BRIDGE)) | DC_QUERY_COST, CMD_BUILD_BRIDGE); GUIBridgeList *bl = NULL; if (ret.Failed()) { errmsg = ret.GetErrorMessage(); } else { /* check which bridges can be built */ const uint tot_bridgedata_len = CalcBridgeLenCostFactor(bridge_len + 2); bl = new GUIBridgeList(); Money infra_cost = 0; switch (transport_type) { case TRANSPORT_ROAD: infra_cost = (bridge_len + 2) * _price[PR_BUILD_ROAD] * 2; /* In case we add a new road type as well, we must be aware of those costs. */ if (IsBridgeTile(start)) infra_cost *= CountBits(GetRoadTypes(start) | (RoadTypes)road_rail_type); break; case TRANSPORT_RAIL: infra_cost = (bridge_len + 2) * RailBuildCost((RailType)road_rail_type); break; default: break; } /* loop for all bridgetypes */ for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) { if (CheckBridgeAvailability(brd_type, bridge_len).Succeeded()) { /* bridge is accepted, add to list */ BuildBridgeData *item = bl->Append(); item->index = brd_type; item->spec = GetBridgeSpec(brd_type); /* Add to terraforming & bulldozing costs the cost of the * bridge itself (not computed with DC_QUERY_COST) */ item->cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price[PR_BUILD_BRIDGE] * item->spec->price) >> 8) + infra_cost; } } } if (bl != NULL && bl->Length() != 0) { new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl); } else { delete bl; ShowErrorMessage(STR_ERROR_CAN_T_BUILD_BRIDGE_HERE, errmsg, WL_INFO, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE); } } openttd-1.5.3/src/industry_type.h0000644000000000000000000000425012627373441015567 0ustar rootroot/* $Id: industry_type.h 26729 2014-08-13 19:31:45Z alberth $ */ /* * 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 industry_type.h Types related to the industry. */ #ifndef INDUSTRY_TYPE_H #define INDUSTRY_TYPE_H typedef uint16 IndustryID; typedef uint16 IndustryGfx; typedef uint8 IndustryType; struct Industry; struct IndustrySpec; struct IndustryTileSpec; static const IndustryID INVALID_INDUSTRY = 0xFFFF; static const IndustryType NUM_INDUSTRYTYPES_PER_GRF = 64; ///< maximum number of industry types per NewGRF static const IndustryType NEW_INDUSTRYOFFSET = 37; ///< original number of industry types static const IndustryType NUM_INDUSTRYTYPES = 64; ///< total number of industry types, new and old static const IndustryType INVALID_INDUSTRYTYPE = NUM_INDUSTRYTYPES; ///< one above amount is considered invalid static const IndustryGfx NUM_INDUSTRYTILES_PER_GRF = 255; ///< Maximum number of industry tiles per NewGRF; limited to 255 to allow extending Action3 with an extended byte later on. static const IndustryGfx INDUSTRYTILE_NOANIM = 0xFF; ///< flag to mark industry tiles as having no animation static const IndustryGfx NEW_INDUSTRYTILEOFFSET = 175; ///< original number of tiles static const IndustryGfx NUM_INDUSTRYTILES = 512; ///< total number of industry tiles, new and old static const IndustryGfx INVALID_INDUSTRYTILE = NUM_INDUSTRYTILES; ///< one above amount is considered invalid static const int INDUSTRY_COMPLETED = 3; ///< final stage of industry construction. void CheckIndustries(); #endif /* INDUSTRY_TYPE_H */ openttd-1.5.3/src/newgrf_config.cpp0000644000000000000000000006737612627373442016040 0ustar rootroot/* $Id: newgrf_config.cpp 27063 2014-11-18 20:12:42Z frosch $ */ /* * 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 newgrf_config.cpp Finding NewGRFs and configuring them. */ #include "stdafx.h" #include "debug.h" #include "3rdparty/md5/md5.h" #include "newgrf.h" #include "network/network_func.h" #include "gfx_func.h" #include "newgrf_text.h" #include "window_func.h" #include "progress.h" #include "video/video_driver.hpp" #include "strings_func.h" #include "textfile_gui.h" #include "fileio_func.h" #include "fios.h" #include "safeguards.h" /** Create a new GRFTextWrapper. */ GRFTextWrapper::GRFTextWrapper() : text(NULL) { } /** Cleanup a GRFTextWrapper object. */ GRFTextWrapper::~GRFTextWrapper() { CleanUpGRFText(this->text); } /** * Create a new GRFConfig. * @param filename Set the filename of this GRFConfig to filename. The argument * is copied so the original string isn't needed after the constructor. */ GRFConfig::GRFConfig(const char *filename) : name(new GRFTextWrapper()), info(new GRFTextWrapper()), url(new GRFTextWrapper()), num_valid_params(lengthof(param)) { if (filename != NULL) this->filename = stredup(filename); this->name->AddRef(); this->info->AddRef(); this->url->AddRef(); } /** * Create a new GRFConfig that is a deep copy of an existing config. * @param config The GRFConfig object to make a copy of. */ GRFConfig::GRFConfig(const GRFConfig &config) : ZeroedMemoryAllocator(), ident(config.ident), name(config.name), info(config.info), url(config.url), version(config.version), min_loadable_version(config.min_loadable_version), flags(config.flags & ~(1 << GCF_COPY)), status(config.status), grf_bugs(config.grf_bugs), num_params(config.num_params), num_valid_params(config.num_valid_params), palette(config.palette), has_param_defaults(config.has_param_defaults) { MemCpyT(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum)); MemCpyT(this->param, config.param, lengthof(this->param)); if (config.filename != NULL) this->filename = stredup(config.filename); this->name->AddRef(); this->info->AddRef(); this->url->AddRef(); if (config.error != NULL) this->error = new GRFError(*config.error); for (uint i = 0; i < config.param_info.Length(); i++) { if (config.param_info[i] == NULL) { *this->param_info.Append() = NULL; } else { *this->param_info.Append() = new GRFParameterInfo(*config.param_info[i]); } } } /** Cleanup a GRFConfig object. */ GRFConfig::~GRFConfig() { /* GCF_COPY as in NOT stredupped/alloced the filename */ if (!HasBit(this->flags, GCF_COPY)) { free(this->filename); delete this->error; } this->name->Release(); this->info->Release(); this->url->Release(); for (uint i = 0; i < this->param_info.Length(); i++) delete this->param_info[i]; } /** * Copy the parameter information from the \a src config. * @param src Source config. */ void GRFConfig::CopyParams(const GRFConfig &src) { this->num_params = src.num_params; this->num_valid_params = src.num_valid_params; MemCpyT(this->param, src.param, lengthof(this->param)); } /** * Get the name of this grf. In case the name isn't known * the filename is returned. * @return The name of filename of this grf. */ const char *GRFConfig::GetName() const { const char *name = GetGRFStringFromGRFText(this->name->text); return StrEmpty(name) ? this->filename : name; } /** * Get the grf info. * @return A string with a description of this grf. */ const char *GRFConfig::GetDescription() const { return GetGRFStringFromGRFText(this->info->text); } /** * Get the grf url. * @return A string with an url of this grf. */ const char *GRFConfig::GetURL() const { return GetGRFStringFromGRFText(this->url->text); } /** Set the default value for all parameters as specified by action14. */ void GRFConfig::SetParameterDefaults() { this->num_params = 0; MemSetT(this->param, 0, lengthof(this->param)); if (!this->has_param_defaults) return; for (uint i = 0; i < this->param_info.Length(); i++) { if (this->param_info[i] == NULL) continue; this->param_info[i]->SetValue(this, this->param_info[i]->def_value); } } /** * Set the palette of this GRFConfig to something suitable. * That is either the setting coming from the NewGRF or * the globally used palette. */ void GRFConfig::SetSuitablePalette() { PaletteType pal; switch (this->palette & GRFP_GRF_MASK) { case GRFP_GRF_DOS: pal = PAL_DOS; break; case GRFP_GRF_WINDOWS: pal = PAL_WINDOWS; break; default: pal = _settings_client.gui.newgrf_default_palette == 1 ? PAL_WINDOWS : PAL_DOS; break; } SB(this->palette, GRFP_USE_BIT, 1, pal == PAL_WINDOWS ? GRFP_USE_WINDOWS : GRFP_USE_DOS); } /** * Finalize Action 14 info after file scan is finished. */ void GRFConfig::FinalizeParameterInfo() { for (GRFParameterInfo **info = this->param_info.Begin(); info != this->param_info.End(); ++info) { if (*info == NULL) continue; (*info)->Finalize(); } } GRFConfig *_all_grfs; GRFConfig *_grfconfig; GRFConfig *_grfconfig_newgame; GRFConfig *_grfconfig_static; /** * Construct a new GRFError. * @param severity The severity of this error. * @param message The actual error-string. */ GRFError::GRFError(StringID severity, StringID message) : message(message), severity(severity) { } /** * Create a new GRFError that is a deep copy of an existing error message. * @param error The GRFError object to make a copy of. */ GRFError::GRFError(const GRFError &error) : ZeroedMemoryAllocator(), custom_message(error.custom_message), data(error.data), message(error.message), severity(error.severity) { if (error.custom_message != NULL) this->custom_message = stredup(error.custom_message); if (error.data != NULL) this->data = stredup(error.data); memcpy(this->param_value, error.param_value, sizeof(this->param_value)); } GRFError::~GRFError() { free(this->custom_message); free(this->data); } /** * Create a new empty GRFParameterInfo object. * @param nr The newgrf parameter that is changed. */ GRFParameterInfo::GRFParameterInfo(uint nr) : name(NULL), desc(NULL), type(PTYPE_UINT_ENUM), min_value(0), max_value(UINT32_MAX), def_value(0), param_nr(nr), first_bit(0), num_bit(32), complete_labels(false) {} /** * Create a new GRFParameterInfo object that is a deep copy of an existing * parameter info object. * @param info The GRFParameterInfo object to make a copy of. */ GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) : name(DuplicateGRFText(info.name)), desc(DuplicateGRFText(info.desc)), type(info.type), min_value(info.min_value), max_value(info.max_value), def_value(info.def_value), param_nr(info.param_nr), first_bit(info.first_bit), num_bit(info.num_bit), complete_labels(info.complete_labels) { for (uint i = 0; i < info.value_names.Length(); i++) { SmallPair *data = info.value_names.Get(i); this->value_names.Insert(data->first, DuplicateGRFText(data->second)); } } /** Cleanup all parameter info. */ GRFParameterInfo::~GRFParameterInfo() { CleanUpGRFText(this->name); CleanUpGRFText(this->desc); for (uint i = 0; i < this->value_names.Length(); i++) { SmallPair *data = this->value_names.Get(i); CleanUpGRFText(data->second); } } /** * Get the value of this user-changeable parameter from the given config. * @param config The GRFConfig to get the value from. * @return The value of this parameter. */ uint32 GRFParameterInfo::GetValue(struct GRFConfig *config) const { /* GB doesn't work correctly with nbits == 32, so handle that case here. */ if (this->num_bit == 32) return config->param[this->param_nr]; return GB(config->param[this->param_nr], this->first_bit, this->num_bit); } /** * Set the value of this user-changeable parameter in the given config. * @param config The GRFConfig to set the value in. * @param value The new value. */ void GRFParameterInfo::SetValue(struct GRFConfig *config, uint32 value) { /* SB doesn't work correctly with nbits == 32, so handle that case here. */ if (this->num_bit == 32) { config->param[this->param_nr] = value; } else { SB(config->param[this->param_nr], this->first_bit, this->num_bit, value); } config->num_params = max(config->num_params, this->param_nr + 1); SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE); } /** * Finalize Action 14 info after file scan is finished. */ void GRFParameterInfo::Finalize() { this->complete_labels = true; for (uint32 value = this->min_value; value <= this->max_value; value++) { if (!this->value_names.Contains(value)) { this->complete_labels = false; break; } } } /** * Update the palettes of the graphics from the config file. * Called when changing the default palette in advanced settings. * @param p1 Unused. * @return Always true. */ bool UpdateNewGRFConfigPalette(int32 p1) { for (GRFConfig *c = _grfconfig_newgame; c != NULL; c = c->next) c->SetSuitablePalette(); for (GRFConfig *c = _grfconfig_static; c != NULL; c = c->next) c->SetSuitablePalette(); for (GRFConfig *c = _all_grfs; c != NULL; c = c->next) c->SetSuitablePalette(); return true; } /** * Get the data section size of a GRF. * @param f GRF. * @return Size of the data section or SIZE_MAX if the file has no separate data section. */ size_t GRFGetSizeOfDataSection(FILE *f) { extern const byte _grf_cont_v2_sig[]; static const uint header_len = 14; byte data[header_len]; if (fread(data, 1, header_len, f) == header_len) { if (data[0] == 0 && data[1] == 0 && MemCmpT(data + 2, _grf_cont_v2_sig, 8) == 0) { /* Valid container version 2, get data section size. */ size_t offset = ((size_t)data[13] << 24) | ((size_t)data[12] << 16) | ((size_t)data[11] << 8) | (size_t)data[10]; if (offset >= 1 * 1024 * 1024 * 1024) { DEBUG(grf, 0, "Unexpectedly large offset for NewGRF"); /* Having more than 1 GiB of data is very implausible. Mostly because then * all pools in OpenTTD are flooded already. Or it's just Action C all over. * In any case, the offsets to graphics will likely not work either. */ return SIZE_MAX; } return header_len + offset; } } return SIZE_MAX; } /** * Calculate the MD5 sum for a GRF, and store it in the config. * @param config GRF to compute. * @param subdir The subdirectory to look in. * @return MD5 sum was successfully computed */ static bool CalcGRFMD5Sum(GRFConfig *config, Subdirectory subdir) { FILE *f; Md5 checksum; uint8 buffer[1024]; size_t len, size; /* open the file */ f = FioFOpenFile(config->filename, "rb", subdir, &size); if (f == NULL) return false; long start = ftell(f); size = min(size, GRFGetSizeOfDataSection(f)); if (start < 0 || fseek(f, start, SEEK_SET) < 0) { FioFCloseFile(f); return false; } /* calculate md5sum */ while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) { size -= len; checksum.Append(buffer, len); } checksum.Finish(config->ident.md5sum); FioFCloseFile(f); return true; } /** * Find the GRFID of a given grf, and calculate its md5sum. * @param config grf to fill. * @param is_static grf is static. * @param subdir the subdirectory to search in. * @return Operation was successfully completed. */ bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir) { if (!FioCheckFileExists(config->filename, subdir)) { config->status = GCS_NOT_FOUND; return false; } /* Find and load the Action 8 information */ LoadNewGRFFile(config, CONFIG_SLOT, GLS_FILESCAN, subdir); config->SetSuitablePalette(); config->FinalizeParameterInfo(); /* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */ if (config->ident.grfid == 0 || config->ident.grfid == 0xFFFFFFFF || config->IsOpenTTDBaseGRF()) return false; if (is_static) { /* Perform a 'safety scan' for static GRFs */ LoadNewGRFFile(config, 62, GLS_SAFETYSCAN, subdir); /* GCF_UNSAFE is set if GLS_SAFETYSCAN finds unsafe actions */ if (HasBit(config->flags, GCF_UNSAFE)) return false; } return CalcGRFMD5Sum(config, subdir); } /** * Clear a GRF Config list, freeing all nodes. * @param config Start of the list. * @post \a config is set to \c NULL. */ void ClearGRFConfigList(GRFConfig **config) { GRFConfig *c, *next; for (c = *config; c != NULL; c = next) { next = c->next; delete c; } *config = NULL; } /** * Copy a GRF Config list * @param dst pointer to destination list * @param src pointer to source list values * @param init_only the copied GRF will be processed up to GLS_INIT * @return pointer to the last value added to the destination list */ GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only) { /* Clear destination as it will be overwritten */ ClearGRFConfigList(dst); for (; src != NULL; src = src->next) { GRFConfig *c = new GRFConfig(*src); ClrBit(c->flags, GCF_INIT_ONLY); if (init_only) SetBit(c->flags, GCF_INIT_ONLY); *dst = c; dst = &c->next; } return dst; } /** * Removes duplicates from lists of GRFConfigs. These duplicates * are introduced when the _grfconfig_static GRFs are appended * to the _grfconfig on a newgame or savegame. As the parameters * of the static GRFs could be different that the parameters of * the ones used non-statically. This can result in desyncs in * multiplayers, so the duplicate static GRFs have to be removed. * * This function _assumes_ that all static GRFs are placed after * the non-static GRFs. * * @param list the list to remove the duplicates from */ static void RemoveDuplicatesFromGRFConfigList(GRFConfig *list) { GRFConfig *prev; GRFConfig *cur; if (list == NULL) return; for (prev = list, cur = list->next; cur != NULL; prev = cur, cur = cur->next) { if (cur->ident.grfid != list->ident.grfid) continue; prev->next = cur->next; delete cur; cur = prev; // Just go back one so it continues as normal later on } RemoveDuplicatesFromGRFConfigList(list->next); } /** * Appends the static GRFs to a list of GRFs * @param dst the head of the list to add to */ void AppendStaticGRFConfigs(GRFConfig **dst) { GRFConfig **tail = dst; while (*tail != NULL) tail = &(*tail)->next; CopyGRFConfigList(tail, _grfconfig_static, false); RemoveDuplicatesFromGRFConfigList(*dst); } /** * Appends an element to a list of GRFs * @param dst the head of the list to add to * @param el the new tail to be */ void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el) { GRFConfig **tail = dst; while (*tail != NULL) tail = &(*tail)->next; *tail = el; RemoveDuplicatesFromGRFConfigList(*dst); } /** Reset the current GRF Config to either blank or newgame settings. */ void ResetGRFConfig(bool defaults) { CopyGRFConfigList(&_grfconfig, _grfconfig_newgame, !defaults); AppendStaticGRFConfigs(&_grfconfig); } /** * Check if all GRFs in the GRF config from a savegame can be loaded. * @param grfconfig GrfConfig to check * @return will return any of the following 3 values:
*
    *
  • GLC_ALL_GOOD: No problems occurred, all GRF files were found and loaded *
  • GLC_COMPATIBLE: For one or more GRF's no exact match was found, but a * compatible GRF with the same grfid was found and used instead *
  • GLC_NOT_FOUND: For one or more GRF's no match was found at all *
*/ GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig) { GRFListCompatibility res = GLC_ALL_GOOD; for (GRFConfig *c = grfconfig; c != NULL; c = c->next) { const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum); if (f == NULL || HasBit(f->flags, GCF_INVALID)) { char buf[256]; /* If we have not found the exactly matching GRF try to find one with the * same grfid, as it most likely is compatible */ f = FindGRFConfig(c->ident.grfid, FGCM_COMPATIBLE, NULL, c->version); if (f != NULL) { md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 1, "NewGRF %08X (%s) not found; checksum %s. Compatibility mode on", BSWAP32(c->ident.grfid), c->filename, buf); if (!HasBit(c->flags, GCF_COMPATIBLE)) { /* Preserve original_md5sum after it has been assigned */ SetBit(c->flags, GCF_COMPATIBLE); memcpy(c->original_md5sum, c->ident.md5sum, sizeof(c->original_md5sum)); } /* Non-found has precedence over compatibility load */ if (res != GLC_NOT_FOUND) res = GLC_COMPATIBLE; goto compatible_grf; } /* No compatible grf was found, mark it as disabled */ md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 0, "NewGRF %08X (%s) not found; checksum %s", BSWAP32(c->ident.grfid), c->filename, buf); c->status = GCS_NOT_FOUND; res = GLC_NOT_FOUND; } else { compatible_grf: DEBUG(grf, 1, "Loading GRF %08X from %s", BSWAP32(f->ident.grfid), f->filename); /* The filename could be the filename as in the savegame. As we need * to load the GRF here, we need the correct filename, so overwrite that * in any case and set the name and info when it is not set already. * When the GCF_COPY flag is set, it is certain that the filename is * already a local one, so there is no need to replace it. */ if (!HasBit(c->flags, GCF_COPY)) { free(c->filename); c->filename = stredup(f->filename); memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum)); c->name->Release(); c->name = f->name; c->name->AddRef(); c->info->Release(); c->info = f->name; c->info->AddRef(); c->error = NULL; c->version = f->version; c->min_loadable_version = f->min_loadable_version; c->num_valid_params = f->num_valid_params; c->has_param_defaults = f->has_param_defaults; for (uint i = 0; i < f->param_info.Length(); i++) { if (f->param_info[i] == NULL) { *c->param_info.Append() = NULL; } else { *c->param_info.Append() = new GRFParameterInfo(*f->param_info[i]); } } } } } return res; } /** Helper for scanning for files with GRF as extension */ class GRFFileScanner : FileScanner { uint next_update; ///< The next (realtime tick) we do update the screen. uint num_scanned; ///< The number of GRFs we have scanned. public: GRFFileScanner() : next_update(_realtime_tick), num_scanned(0) { } /* virtual */ bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename); /** Do the scan for GRFs. */ static uint DoScan() { GRFFileScanner fs; int ret = fs.Scan(".grf", NEWGRF_DIR); /* The number scanned and the number returned may not be the same; * duplicate NewGRFs and base sets are ignored in the return value. */ _settings_client.gui.last_newgrf_count = fs.num_scanned; return ret; } }; bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { GRFConfig *c = new GRFConfig(filename + basepath_length); bool added = true; if (FillGRFDetails(c, false)) { if (_all_grfs == NULL) { _all_grfs = c; } else { /* Insert file into list at a position determined by its * name, so the list is sorted as we go along */ GRFConfig **pd, *d; bool stop = false; for (pd = &_all_grfs; (d = *pd) != NULL; pd = &d->next) { if (c->ident.grfid == d->ident.grfid && memcmp(c->ident.md5sum, d->ident.md5sum, sizeof(c->ident.md5sum)) == 0) added = false; /* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name, * before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of * just after the first with the same name. Avoids doubles in the list. */ if (strcasecmp(c->GetName(), d->GetName()) <= 0) { stop = true; } else if (stop) { break; } } if (added) { c->next = d; *pd = c; } } } else { added = false; } this->num_scanned++; if (this->next_update <= _realtime_tick) { _modal_progress_work_mutex->EndCritical(); _modal_progress_paint_mutex->BeginCritical(); const char *name = NULL; if (c->name != NULL) name = GetGRFStringFromGRFText(c->name->text); if (name == NULL) name = c->filename; UpdateNewGRFScanStatus(this->num_scanned, name); _modal_progress_work_mutex->BeginCritical(); _modal_progress_paint_mutex->EndCritical(); this->next_update = _realtime_tick + 200; } if (!added) { /* File couldn't be opened, or is either not a NewGRF or is a * 'system' NewGRF or it's already known, so forget about it. */ delete c; } return added; } /** * Simple sorter for GRFS * @param p1 the first GRFConfig * * @param p2 the second GRFConfig * * @return the same strcmp would return for the name of the NewGRF. */ static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2) { const GRFConfig *c1 = *p1; const GRFConfig *c2 = *p2; return strnatcmp(c1->GetName(), c2->GetName()); } /** * Really perform the scan for all NewGRFs. * @param callback The callback to call after the scanning is complete. */ void DoScanNewGRFFiles(void *callback) { _modal_progress_work_mutex->BeginCritical(); ClearGRFConfigList(&_all_grfs); TarScanner::DoScan(TarScanner::NEWGRF); DEBUG(grf, 1, "Scanning for NewGRFs"); uint num = GRFFileScanner::DoScan(); DEBUG(grf, 1, "Scan complete, found %d files", num); if (num != 0 && _all_grfs != NULL) { /* Sort the linked list using quicksort. * For that we first have to make an array, then sort and * then remake the linked list. */ GRFConfig **to_sort = MallocT(num); uint i = 0; for (GRFConfig *p = _all_grfs; p != NULL; p = p->next, i++) { to_sort[i] = p; } /* Number of files is not necessarily right */ num = i; QSortT(to_sort, num, &GRFSorter); for (i = 1; i < num; i++) { to_sort[i - 1]->next = to_sort[i]; } to_sort[num - 1]->next = NULL; _all_grfs = to_sort[0]; free(to_sort); #ifdef ENABLE_NETWORK NetworkAfterNewGRFScan(); #endif } _modal_progress_work_mutex->EndCritical(); _modal_progress_paint_mutex->BeginCritical(); /* Yes... these are the NewGRF windows */ InvalidateWindowClassesData(WC_SAVELOAD, 0, true); InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, true); if (callback != NULL) ((NewGRFScanCallback*)callback)->OnNewGRFsScanned(); DeleteWindowByClass(WC_MODAL_PROGRESS); SetModalProgress(false); MarkWholeScreenDirty(); _modal_progress_paint_mutex->EndCritical(); } /** * Scan for all NewGRFs. * @param callback The callback to call after the scanning is complete. */ void ScanNewGRFFiles(NewGRFScanCallback *callback) { /* First set the modal progress. This ensures that it will eventually let go of the paint mutex. */ SetModalProgress(true); /* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */ MarkWholeScreenDirty(); if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&DoScanNewGRFFiles, callback, NULL)) { _modal_progress_work_mutex->EndCritical(); _modal_progress_paint_mutex->EndCritical(); DoScanNewGRFFiles(callback); _modal_progress_paint_mutex->BeginCritical(); _modal_progress_work_mutex->BeginCritical(); } else { UpdateNewGRFScanStatus(0, NULL); } } /** * Find a NewGRF in the scanned list. * @param grfid GRFID to look for, * @param mode Restrictions for matching grfs * @param md5sum Expected MD5 sum * @param desired_version Requested version * @return The matching grf, if it exists in #_all_grfs, else \c NULL. */ const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum, uint32 desired_version) { assert((mode == FGCM_EXACT) != (md5sum == NULL)); const GRFConfig *best = NULL; for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) { /* if md5sum is set, we look for an exact match and continue if not found */ if (!c->ident.HasGrfIdentifier(grfid, md5sum)) continue; /* return it, if the exact same newgrf is found, or if we do not care about finding "the best" */ if (md5sum != NULL || mode == FGCM_ANY) return c; /* Skip incompatible stuff, unless explicitly allowed */ if (mode != FGCM_NEWEST && HasBit(c->flags, GCF_INVALID)) continue; /* check version compatibility */ if (mode == FGCM_COMPATIBLE && (c->version < desired_version || c->min_loadable_version > desired_version)) continue; /* remember the newest one as "the best" */ if (best == NULL || c->version > best->version) best = c; } return best; } #ifdef ENABLE_NETWORK /** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */ struct UnknownGRF : public GRFIdentifier { UnknownGRF *next; ///< The next unknown GRF. GRFTextWrapper *name; ///< Name of the GRF. }; /** * Finds the name of a NewGRF in the list of names for unknown GRFs. An * unknown GRF is a GRF where the .grf is not found during scanning. * * The names are resolved via UDP calls to servers that should know the name, * though the replies may not come. This leaves "" as name, though * that shouldn't matter _very_ much as they need GRF crawler or so to look * up the GRF anyway and that works better with the GRF ID. * * @param grfid the GRF ID part of the 'unique' GRF identifier * @param md5sum the MD5 checksum part of the 'unique' GRF identifier * @param create whether to create a new GRFConfig if the GRFConfig did not * exist in the fake list of GRFConfigs. * @return The GRFTextWrapper of the name of the GRFConfig with the given GRF ID * and MD5 checksum or NULL when it does not exist and create is false. * This value must NEVER be freed by the caller. */ GRFTextWrapper *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create) { UnknownGRF *grf; static UnknownGRF *unknown_grfs = NULL; for (grf = unknown_grfs; grf != NULL; grf = grf->next) { if (grf->grfid == grfid) { if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name; } } if (!create) return NULL; grf = CallocT(1); grf->grfid = grfid; grf->next = unknown_grfs; grf->name = new GRFTextWrapper(); grf->name->AddRef(); AddGRFTextToList(&grf->name->text, UNKNOWN_GRF_NAME_PLACEHOLDER); memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum)); unknown_grfs = grf; return grf->name; } #endif /* ENABLE_NETWORK */ /** * Retrieve a NewGRF from the current config by its grfid. * @param grfid grf to look for. * @param mask GRFID mask to allow for partial matching. * @return The grf config, if it exists, else \c NULL. */ GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask) { GRFConfig *c; for (c = _grfconfig; c != NULL; c = c->next) { if ((c->ident.grfid & mask) == (grfid & mask)) return c; } return NULL; } /** Build a string containing space separated parameter values, and terminate */ char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last) { uint i; /* Return an empty string if there are no parameters */ if (c->num_params == 0) return strecpy(dst, "", last); for (i = 0; i < c->num_params; i++) { if (i > 0) dst = strecpy(dst, " ", last); dst += seprintf(dst, last, "%d", c->param[i]); } return dst; } /** Base GRF ID for OpenTTD's base graphics GRFs. */ static const uint32 OPENTTD_GRAPHICS_BASE_GRF_ID = BSWAP32(0xFF4F5400); /** * Checks whether this GRF is a OpenTTD base graphic GRF. * @return true if and only if it is a base GRF. */ bool GRFConfig::IsOpenTTDBaseGRF() const { return (this->ident.grfid & 0x00FFFFFF) == OPENTTD_GRAPHICS_BASE_GRF_ID; } /** * Search a textfile file next to this NewGRF. * @param type The type of the textfile to search for. * @return The filename for the textfile, \c NULL otherwise. */ const char *GRFConfig::GetTextfile(TextfileType type) const { return ::GetTextfile(type, NEWGRF_DIR, this->filename); } openttd-1.5.3/src/story.cpp0000644000000000000000000002650112627373435014366 0ustar rootroot/* $Id: story.cpp 26509 2014-04-25 15:40:32Z rubidium $ */ /* * 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 story.cpp Handling of stories. */ #include "stdafx.h" #include "story_base.h" #include "core/pool_func.hpp" #include "cmd_helper.h" #include "command_func.h" #include "company_base.h" #include "company_func.h" #include "string_func.h" #include "date_func.h" #include "tile_map.h" #include "goal_type.h" #include "goal_base.h" #include "window_func.h" #include "gui.h" #include "safeguards.h" StoryPageElementID _new_story_page_element_id; StoryPageID _new_story_page_id; uint32 _story_page_element_next_sort_value; uint32 _story_page_next_sort_value; StoryPageElementPool _story_page_element_pool("StoryPageElement"); StoryPagePool _story_page_pool("StoryPage"); INSTANTIATE_POOL_METHODS(StoryPageElement) INSTANTIATE_POOL_METHODS(StoryPage) /** * This helper for Create/Update PageElement Cmd procedure verifies if the page * element parameters are correct for the given page element type. * @param page_id The page id of the page which the page element (will) belong to * @param type The type of the page element to create/update * @param tile The tile parameter of the DoCommand proc * @param reference The reference parameter of the DoCommand proc (p2) * @param text The text parameter of the DoCommand proc * @return true, if and only if the given parameters are valid for the given page elment type and page id. */ static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElementType type, TileIndex tile, uint32 reference, const char *text) { switch (type) { case SPET_TEXT: if (StrEmpty(text)) return false; break; case SPET_LOCATION: if (StrEmpty(text)) return false; if (!IsValidTile(tile)) return false; break; case SPET_GOAL: if (!Goal::IsValidID((GoalID)reference)) return false; /* Reject company specific goals on global pages */ if (StoryPage::Get(page_id)->company == INVALID_COMPANY && Goal::Get((GoalID)reference)->company != INVALID_COMPANY) return false; break; default: return false; } return true; } /** * This helper for Create/Update PageElement Cmd procedure updates a page * element with new content data. * @param pe The page element to update * @param tile The tile parameter of the DoCommand proc * @param reference The reference parameter of the DoCommand proc (p2) * @param text The text parameter of the DoCommand proc */ static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32 reference, const char *text) { switch (pe.type) { case SPET_TEXT: pe.text = stredup(text); break; case SPET_LOCATION: pe.text = stredup(text); pe.referenced_id = tile; break; case SPET_GOAL: pe.referenced_id = (GoalID)reference; break; default: NOT_REACHED(); } } /** * Create a new story page. * @param tile unused. * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 7) - Company for which this story page belongs to. * @param p2 unused. * @param text Title of the story page. Null is allowed in wich case a generic page title is provided by OpenTTD. * @return the cost of this operation or an error */ CommandCost CmdCreateStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (!StoryPage::CanAllocateItem()) return CMD_ERROR; CompanyID company = (CompanyID)GB(p1, 0, 8); if (_current_company != OWNER_DEITY) return CMD_ERROR; if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR; if (flags & DC_EXEC) { if (_story_page_pool.items == 0) { /* Initialize the next sort value variable. */ _story_page_next_sort_value = 0; } StoryPage *s = new StoryPage(); s->sort_value = _story_page_next_sort_value; s->date = _date; s->company = company; if (StrEmpty(text)) { s->title = NULL; } else { s->title = stredup(text); } InvalidateWindowClassesData(WC_STORY_BOOK, -1); if (StoryPage::GetNumItems() == 1) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); _new_story_page_id = s->index; _story_page_next_sort_value++; } return CommandCost(); } /** * Create a new story page element. * @param tile Tile location if it is a location page element, otherwise unused. * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 15) - The page which the element belongs to. * (bit 16 - 23) - Page element type * @param p2 Id of referenced object * @param text Text content in case it is a text or location page element * @return the cost of this operation or an error */ CommandCost CmdCreateStoryPageElement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (!StoryPageElement::CanAllocateItem()) return CMD_ERROR; StoryPageID page_id = (CompanyID)GB(p1, 0, 16); StoryPageElementType type = Extract(p1); /* Allow at most 128 elements per page. */ uint16 element_count = 0; StoryPageElement *iter; FOR_ALL_STORY_PAGE_ELEMENTS(iter) { if (iter->page == page_id) element_count++; } if (element_count >= 128) return CMD_ERROR; if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!StoryPage::IsValidID(page_id)) return CMD_ERROR; if (!VerifyElementContentParameters(page_id, type, tile, p2, text)) return CMD_ERROR; if (flags & DC_EXEC) { if (_story_page_element_pool.items == 0) { /* Initialize the next sort value variable. */ _story_page_element_next_sort_value = 0; } StoryPageElement *pe = new StoryPageElement(); pe->sort_value = _story_page_element_next_sort_value; pe->type = type; pe->page = page_id; UpdateElement(*pe, tile, p2, text); InvalidateWindowClassesData(WC_STORY_BOOK, page_id); _new_story_page_element_id = pe->index; _story_page_element_next_sort_value++; } return CommandCost(); } /** * Update a new story page element. * @param tile Tile location if it is a location page element, otherwise unused. * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 15) - The page element to update. * (bit 16 - 31) - unused * @param p2 Id of referenced object * @param text Text content in case it is a text or location page element * @return the cost of this operation or an error */ CommandCost CmdUpdateStoryPageElement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { StoryPageElementID page_element_id = (StoryPageElementID)GB(p1, 0, 16); if (_current_company != OWNER_DEITY) return CMD_ERROR; if (!StoryPageElement::IsValidID(page_element_id)) return CMD_ERROR; StoryPageElement *pe = StoryPageElement::Get(page_element_id); StoryPageID page_id = pe->page; StoryPageElementType type = pe->type; if (!VerifyElementContentParameters(page_id, type, tile, p2, text)) return CMD_ERROR; if (flags & DC_EXEC) { UpdateElement(*pe, tile, p2, text); InvalidateWindowClassesData(WC_STORY_BOOK, pe->page); } return CommandCost(); } /** * Update title of a story page. * @param tile unused. * @param flags type of operation * @param p1 = (bit 0 - 15) - StoryPageID to update. * @param p2 unused * @param text title text of the story page. * @return the cost of this operation or an error */ CommandCost CmdSetStoryPageTitle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; StoryPageID page_id = (StoryPageID)GB(p1, 0, 16); if (!StoryPage::IsValidID(page_id)) return CMD_ERROR; if (flags & DC_EXEC) { StoryPage *p = StoryPage::Get(page_id); free(p->title); if (StrEmpty(text)) { p->title = NULL; } else { p->title = stredup(text); } InvalidateWindowClassesData(WC_STORY_BOOK, page_id); } return CommandCost(); } /** * Update date of a story page. * @param tile unused. * @param flags type of operation * @param p1 = (bit 0 - 15) - StoryPageID to update. * @param p2 = (bit 0 - 31) - date * @param text unused * @return the cost of this operation or an error */ CommandCost CmdSetStoryPageDate(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; StoryPageID page_id = (StoryPageID)GB(p1, 0, 16); if (!StoryPage::IsValidID(page_id)) return CMD_ERROR; Date date = (Date)p2; if (flags & DC_EXEC) { StoryPage *p = StoryPage::Get(page_id); p->date = date; InvalidateWindowClassesData(WC_STORY_BOOK, page_id); } return CommandCost(); } /** * Display a story page for all clients that are allowed to * view the story page. * @param tile unused. * @param flags type of operation * @param p1 = (bit 0 - 15) - StoryPageID to show. * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdShowStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; StoryPageID page_id = (StoryPageID)GB(p1, 0, 16); if (!StoryPage::IsValidID(page_id)) return CMD_ERROR; if (flags & DC_EXEC) { StoryPage *g = StoryPage::Get(page_id); if ((g->company != INVALID_COMPANY && g->company == _local_company) || (g->company == INVALID_COMPANY && Company::IsValidID(_local_company))) ShowStoryBook(_local_company, page_id); } return CommandCost(); } /** * Remove a story page and associated story page elements. * @param tile unused. * @param flags type of operation * @param p1 = (bit 0 - 15) - StoryPageID to remove. * @param p2 unused. * @param text unused. * @return the cost of this operation or an error */ CommandCost CmdRemoveStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; StoryPageID page_id = (StoryPageID)p1; if (!StoryPage::IsValidID(page_id)) return CMD_ERROR; if (flags & DC_EXEC) { StoryPage *p = StoryPage::Get(page_id); StoryPageElement *pe; FOR_ALL_STORY_PAGE_ELEMENTS(pe) { if (pe->page == p->index) { delete pe; } } delete p; InvalidateWindowClassesData(WC_STORY_BOOK, -1); if (StoryPage::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); } return CommandCost(); } /** * Remove a story page element * @param tile unused. * @param flags type of operation * @param p1 = (bit 0 - 15) - StoryPageElementID to remove. * @param p2 unused. * @param text unused. * @return the cost of this operation or an error */ CommandCost CmdRemoveStoryPageElement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; StoryPageElementID page_element_id = (StoryPageElementID)p1; if (!StoryPageElement::IsValidID(page_element_id)) return CMD_ERROR; if (flags & DC_EXEC) { StoryPageElement *pe = StoryPageElement::Get(page_element_id); StoryPageID page_id = pe->page; delete pe; InvalidateWindowClassesData(WC_STORY_BOOK, page_id); } return CommandCost(); } openttd-1.5.3/src/industrytype.h0000644000000000000000000002460012627373435015434 0ustar rootroot/* $Id: industrytype.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 industrytype.h %Industry type specs. */ #ifndef INDUSTRYTYPE_H #define INDUSTRYTYPE_H #include "map_type.h" #include "slope_type.h" #include "industry_type.h" #include "landscape_type.h" #include "cargo_type.h" #include "newgrf_animation_type.h" #include "newgrf_commons.h" enum IndustryCleanupType { CLEAN_RANDOMSOUNDS, ///< Free the dynamically allocated sounds table CLEAN_TILELAYOUT, ///< Free the dynamically allocated tile layout structure }; /** Available types of industry lifetimes. */ enum IndustryLifeType { INDUSTRYLIFE_BLACK_HOLE = 0, ///< Like power plants and banks INDUSTRYLIFE_EXTRACTIVE = 1 << 0, ///< Like mines INDUSTRYLIFE_ORGANIC = 1 << 1, ///< Like forests INDUSTRYLIFE_PROCESSING = 1 << 2, ///< Like factories }; /** * Available procedures to check whether an industry may build at a given location. * @see CheckNewIndustryProc, _check_new_industry_procs[] */ enum CheckProc { CHECK_NOTHING, ///< Always succeeds. CHECK_FOREST, ///< %Industry should be build above snow-line in arctic climate. CHECK_REFINERY, ///< %Industry should be positioned near edge of the map. CHECK_FARM, ///< %Industry should be below snow-line in arctic. CHECK_PLANTATION, ///< %Industry should NOT be in the desert. CHECK_WATER, ///< %Industry should be in the desert. CHECK_LUMBERMILL, ///< %Industry should be in the rain forest. CHECK_BUBBLEGEN, ///< %Industry should be in low land. CHECK_OIL_RIG, ///< Industries at sea should be positioned near edge of the map. CHECK_END, ///< End marker of the industry check procedures. }; /** How was the industry created */ enum IndustryConstructionType { ICT_UNKNOWN, ///< in previous game version or without newindustries activated ICT_NORMAL_GAMEPLAY, ///< either by user or random creation process ICT_MAP_GENERATION, ///< during random map creation ICT_SCENARIO_EDITOR, ///< while editing a scenario }; /** Various industry behaviours mostly to represent original TTD specialities */ enum IndustryBehaviour { INDUSTRYBEH_NONE = 0, INDUSTRYBEH_PLANT_FIELDS = 1 << 0, ///< periodically plants fields around itself (temp and arctic farms) INDUSTRYBEH_CUT_TREES = 1 << 1, ///< cuts trees and produce first output cargo from them (lumber mill) INDUSTRYBEH_BUILT_ONWATER = 1 << 2, ///< is built on water (oil rig) INDUSTRYBEH_TOWN1200_MORE = 1 << 3, ///< can only be built in towns larger than 1200 inhabitants (temperate bank) INDUSTRYBEH_ONLY_INTOWN = 1 << 4, ///< can only be built in towns (arctic/tropic banks, water tower) INDUSTRYBEH_ONLY_NEARTOWN = 1 << 5, ///< is always built near towns (toy shop) INDUSTRYBEH_PLANT_ON_BUILT = 1 << 6, ///< Fields are planted around when built (all farms) INDUSTRYBEH_DONT_INCR_PROD = 1 << 7, ///< do not increase production (oil wells) in the temperate climate INDUSTRYBEH_BEFORE_1950 = 1 << 8, ///< can only be built before 1950 (oil wells) INDUSTRYBEH_AFTER_1960 = 1 << 9, ///< can only be built after 1960 (oil rigs) INDUSTRYBEH_AI_AIRSHIP_ROUTES = 1 << 10, ///< ai will attempt to establish air/ship routes to this industry (oil rig) INDUSTRYBEH_AIRPLANE_ATTACKS = 1 << 11, ///< can be exploded by a military airplane (oil refinery) INDUSTRYBEH_CHOPPER_ATTACKS = 1 << 12, ///< can be exploded by a military helicopter (factory) INDUSTRYBEH_CAN_SUBSIDENCE = 1 << 13, ///< can cause a subsidence (coal mine, shaft that collapses) /* The following flags are only used for newindustries and do no represent any normal behaviour */ INDUSTRYBEH_PROD_MULTI_HNDLING = 1 << 14, ///< Automatic production multiplier handling INDUSTRYBEH_PRODCALLBACK_RANDOM = 1 << 15, ///< Production callback needs random bits in var 10 INDUSTRYBEH_NOBUILT_MAPCREATION = 1 << 16, ///< Do not force one instance of this type to appear on map generation INDUSTRYBEH_CANCLOSE_LASTINSTANCE = 1 << 17, ///< Allow closing down the last instance of this type }; DECLARE_ENUM_AS_BIT_SET(IndustryBehaviour) /** Flags for miscellaneous industry tile specialities */ enum IndustryTileSpecialFlags { INDTILE_SPECIAL_NONE = 0, INDTILE_SPECIAL_NEXTFRAME_RANDOMBITS = 1 << 0, ///< Callback 0x26 needs random bits }; DECLARE_ENUM_AS_BIT_SET(IndustryTileSpecialFlags) struct IndustryTileTable { TileIndexDiffC ti; IndustryGfx gfx; }; /** * Defines the data structure for constructing industry. */ struct IndustrySpec { const IndustryTileTable * const *table;///< List of the tiles composing the industry byte num_table; ///< Number of elements in the table uint8 cost_multiplier; ///< Base construction cost multiplier. uint32 removal_cost_multiplier; ///< Base removal cost multiplier. uint32 prospecting_chance; ///< Chance prospecting succeeds IndustryType conflicting[3]; ///< Industries this industry cannot be close to byte check_proc; ///< Index to a procedure to check for conflicting circumstances CargoID produced_cargo[2]; byte production_rate[2]; /** * minimum amount of cargo transported to the stations. * If the waiting cargo is less than this number, no cargo is moved to it. */ byte minimal_cargo; CargoID accepts_cargo[3]; ///< 3 accepted cargoes. uint16 input_cargo_multiplier[3][2]; ///< Input cargo multipliers (multiply amount of incoming cargo for the produced cargoes) IndustryLifeType life_type; ///< This is also known as Industry production flag, in newgrf specs byte climate_availability; ///< Bitmask, giving landscape enums as bit position IndustryBehaviour behaviour; ///< How this industry will behave, and how others entities can use it byte map_colour; ///< colour used for the small map StringID name; ///< Displayed name of the industry StringID new_industry_text; ///< Message appearing when the industry is built StringID closure_text; ///< Message appearing when the industry closes StringID production_up_text; ///< Message appearing when the industry's production is increasing StringID production_down_text; ///< Message appearing when the industry's production is decreasing StringID station_name; ///< Default name for nearby station byte appear_ingame[NUM_LANDSCAPE]; ///< Probability of appearance in game byte appear_creation[NUM_LANDSCAPE]; ///< Probability of appearance during map creation uint8 number_of_sounds; ///< Number of sounds available in the sounds array const uint8 *random_sounds; ///< array of random sounds. /* Newgrf data */ uint16 callback_mask; ///< Bitmask of industry callbacks that have to be called uint8 cleanup_flag; ///< flags indicating which data should be freed upon cleaning up bool enabled; ///< entity still available (by default true).newgrf can disable it, though GRFFileProps grf_prop; ///< properties related to the grf file bool IsRawIndustry() const; bool IsProcessingIndustry() const; Money GetConstructionCost() const; Money GetRemovalCost() const; bool UsesSmoothEconomy() const; }; /** * Defines the data structure of each individual tile of an industry. */ struct IndustryTileSpec { CargoID accepts_cargo[3]; ///< Cargo accepted by this tile uint8 acceptance[3]; ///< Level of acceptance per cargo type Slope slopes_refused; ///< slope pattern on which this tile cannot be built byte anim_production; ///< Animation frame to start when goods are produced byte anim_next; ///< Next frame in an animation /** * When true, the tile has to be drawn using the animation * state instead of the construction state */ bool anim_state; /* Newgrf data */ uint8 callback_mask; ///< Bitmask of industry tile callbacks that have to be called AnimationInfo animation; ///< Information about the animation (is it looping, how many loops etc) IndustryTileSpecialFlags special_flags; ///< Bitmask of extra flags used by the tile bool enabled; ///< entity still available (by default true).newgrf can disable it, though GRFFileProps grf_prop; ///< properties related to the grf file }; /* industry_cmd.cpp*/ const IndustrySpec *GetIndustrySpec(IndustryType thistype); ///< Array of industries data const IndustryTileSpec *GetIndustryTileSpec(IndustryGfx gfx); ///< Array of industry tiles data void ResetIndustries(); /* writable arrays of specs */ extern IndustrySpec _industry_specs[NUM_INDUSTRYTYPES]; extern IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES]; /* industry_gui.cpp */ void SortIndustryTypes(); /* Industry types sorted alphabetically by name. */ extern IndustryType _sorted_industry_types[NUM_INDUSTRYTYPES]; /** * Do industry gfx ID translation for NewGRFs. * @param gfx the type to get the override for. * @return the gfx to actually work with. */ static inline IndustryGfx GetTranslatedIndustryTileID(IndustryGfx gfx) { /* the 0xFF should be GFX_WATERTILE_SPECIALCHECK but for reasons of include mess, * we'll simplify the writing. * Basically, the first test is required since the GFX_WATERTILE_SPECIALCHECK value * will never be assigned as a tile index and is only required in order to do some * tests while building the industry (as in WATER REQUIRED */ if (gfx != 0xFF) { assert(gfx < INVALID_INDUSTRYTILE); const IndustryTileSpec *it = &_industry_tile_specs[gfx]; return it->grf_prop.override == INVALID_INDUSTRYTILE ? gfx : it->grf_prop.override; } else { return gfx; } } static const uint8 IT_INVALID = 255; #endif /* INDUSTRYTYPE_H */ openttd-1.5.3/src/base_consist.h0000644000000000000000000000356612627373442015333 0ustar rootroot/* $Id: base_consist.h 24998 2013-02-14 17:24:55Z rubidium $ */ /* * 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 base_consist.h Properties for front vehicles/consists. */ #ifndef BASE_CONSIST_H #define BASE_CONSIST_H #include "order_type.h" #include "date_type.h" /** Various front vehicle properties that are preserved when autoreplacing, using order-backup or switching front engines within a consist. */ struct BaseConsist { char *name; ///< Name of vehicle /* Used for timetabling. */ uint32 current_order_time; ///< How many ticks have passed since this order started. int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is. Date timetable_start; ///< When the vehicle is supposed to start the timetable. uint16 service_interval; ///< The interval for (automatic) servicing; either in days or %. VehicleOrderID cur_real_order_index;///< The index to the current real (non-implicit) order VehicleOrderID cur_implicit_order_index;///< The index to the current implicit order uint16 vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum) BaseConsist() : name(NULL) {} virtual ~BaseConsist(); void CopyConsistPropertiesFrom(const BaseConsist *src); }; #endif /* BASE_CONSIST_H */ openttd-1.5.3/src/airport.cpp0000644000000000000000000001646612627373442014675 0ustar rootroot/* $Id: airport.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 airport.cpp Functions related to airports. */ #include "stdafx.h" #include "station_base.h" #include "table/strings.h" #include "table/airport_movement.h" #include "table/airporttile_ids.h" #include "safeguards.h" /** * Define a generic airport. * @param name Suffix of the names of the airport data. * @param terminals The terminals. * @param num_helipads Number of heli pads. * @param flags Information about the class of FTA. * @param delta_z Height of the airport above the land. */ #define AIRPORT_GENERIC(name, terminals, num_helipads, flags, delta_z) \ static AirportFTAClass _airportfta_ ## name(_airport_moving_data_ ## name, terminals, \ num_helipads, _airport_entries_ ## name, flags, _airport_fta_ ## name, delta_z); /** * Define an airport. * @param name Suffix of the names of the airport data. * @param num_helipads Number of heli pads. * @param short_strip Airport has a short land/take-off strip. */ #define AIRPORT(name, num_helipads, short_strip) \ AIRPORT_GENERIC(name, _airport_terminal_ ## name, num_helipads, AirportFTAClass::ALL | (short_strip ? AirportFTAClass::SHORT_STRIP : (AirportFTAClass::Flags)0), 0) /** * Define a heliport. * @param name Suffix of the names of the helipad data. * @param num_helipads Number of heli pads. * @param delta_z Height of the airport above the land. */ #define HELIPORT(name, num_helipads, delta_z) \ AIRPORT_GENERIC(name, NULL, num_helipads, AirportFTAClass::HELICOPTERS, delta_z) AIRPORT(country, 0, true) AIRPORT(city, 0, false) HELIPORT(heliport, 1, 60) AIRPORT(metropolitan, 0, false) AIRPORT(international, 2, false) AIRPORT(commuter, 2, true) HELIPORT(helidepot, 1, 0) AIRPORT(intercontinental, 2, false) HELIPORT(helistation, 3, 0) HELIPORT(oilrig, 1, 54) AIRPORT_GENERIC(dummy, NULL, 0, AirportFTAClass::ALL, 0) #undef HELIPORT #undef AIRPORT #undef AIRPORT_GENERIC #include "table/airport_defaults.h" static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA); static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA); /** * Rotate the airport moving data to another rotation. * @param orig Pointer to the moving data to rotate. * @param rotation How to rotate the moving data. * @param num_tiles_x Number of tiles in x direction. * @param num_tiles_y Number of tiles in y direction. * @return The rotated moving data. */ AirportMovingData RotateAirportMovingData(const AirportMovingData *orig, Direction rotation, uint num_tiles_x, uint num_tiles_y) { AirportMovingData amd; amd.flag = orig->flag; amd.direction = ChangeDir(orig->direction, (DirDiff)rotation); switch (rotation) { case DIR_N: amd.x = orig->x; amd.y = orig->y; break; case DIR_E: amd.x = orig->y; amd.y = num_tiles_y * TILE_SIZE - orig->x - 1; break; case DIR_S: amd.x = num_tiles_x * TILE_SIZE - orig->x - 1; amd.y = num_tiles_y * TILE_SIZE - orig->y - 1; break; case DIR_W: amd.x = num_tiles_x * TILE_SIZE - orig->y - 1; amd.y = orig->x; break; default: NOT_REACHED(); } return amd; } AirportFTAClass::AirportFTAClass( const AirportMovingData *moving_data_, const byte *terminals_, const byte num_helipads_, const byte *entry_points_, Flags flags_, const AirportFTAbuildup *apFA, byte delta_z_ ) : moving_data(moving_data_), terminals(terminals_), num_helipads(num_helipads_), flags(flags_), nofelements(AirportGetNofElements(apFA)), entry_points(entry_points_), delta_z(delta_z_) { /* Build the state machine itself */ this->layout = AirportBuildAutomata(this->nofelements, apFA); } AirportFTAClass::~AirportFTAClass() { for (uint i = 0; i < nofelements; i++) { AirportFTA *current = layout[i].next; while (current != NULL) { AirportFTA *next = current->next; free(current); current = next; } } free(layout); } /** * Get the number of elements of a source Airport state automata * Since it is actually just a big array of AirportFTA types, we only * know one element from the other by differing 'position' identifiers */ static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA) { uint16 nofelements = 0; int temp = apFA[0].position; for (uint i = 0; i < MAX_ELEMENTS; i++) { if (temp != apFA[i].position) { nofelements++; temp = apFA[i].position; } if (apFA[i].position == MAX_ELEMENTS) break; } return nofelements; } /** * Construct the FTA given a description. * @param nofelements The number of elements in the FTA. * @param apFA The description of the FTA. * @return The FTA describing the airport. */ static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA) { AirportFTA *FAutomata = MallocT(nofelements); uint16 internalcounter = 0; for (uint i = 0; i < nofelements; i++) { AirportFTA *current = &FAutomata[i]; current->position = apFA[internalcounter].position; current->heading = apFA[internalcounter].heading; current->block = apFA[internalcounter].block; current->next_position = apFA[internalcounter].next; /* outgoing nodes from the same position, create linked list */ while (current->position == apFA[internalcounter + 1].position) { AirportFTA *newNode = MallocT(1); newNode->position = apFA[internalcounter + 1].position; newNode->heading = apFA[internalcounter + 1].heading; newNode->block = apFA[internalcounter + 1].block; newNode->next_position = apFA[internalcounter + 1].next; /* create link */ current->next = newNode; current = current->next; internalcounter++; } current->next = NULL; internalcounter++; } return FAutomata; } /** * Get the finite state machine of an airport type. * @param airport_type %Airport type to query FTA from. @see AirportTypes * @return Finite state machine of the airport. */ const AirportFTAClass *GetAirport(const byte airport_type) { if (airport_type == AT_DUMMY) return &_airportfta_dummy; return AirportSpec::Get(airport_type)->fsm; } /** * Get the vehicle position when an aircraft is build at the given tile * @param hangar_tile The tile on which the vehicle is build * @return The position (index in airport node array) where the aircraft ends up */ byte GetVehiclePosOnBuild(TileIndex hangar_tile) { const Station *st = Station::GetByTile(hangar_tile); const AirportFTAClass *apc = st->airport.GetFTA(); /* When we click on hangar we know the tile it is on. By that we know * its position in the array of depots the airport has.....we can search * layout for #th position of depot. Since layout must start with a listing * of all depots, it is simple */ for (uint i = 0;; i++) { if (st->airport.GetHangarTile(i) == hangar_tile) { assert(apc->layout[i].heading == HANGAR); return apc->layout[i].position; } } NOT_REACHED(); } openttd-1.5.3/src/mixer.h0000644000000000000000000000207312627373434013774 0ustar rootroot/* $Id: mixer.h 19332 2010-03-06 11:08:31Z peter1138 $ */ /* * 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 mixer.h Functions to mix sound samples. */ #ifndef MIXER_H #define MIXER_H struct MixerChannel; bool MxInitialize(uint rate); void MxMixSamples(void *buffer, uint samples); MixerChannel *MxAllocateChannel(); void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, size_t size, uint rate, bool is16bit); void MxSetChannelVolume(MixerChannel *mc, uint volume, float pan); void MxActivateChannel(MixerChannel*); #endif /* MIXER_H */ openttd-1.5.3/src/group.h0000644000000000000000000000721212627373435014005 0ustar rootroot/* $Id: group.h 26450 2014-04-08 21:09:06Z peter1138 $ */ /* * 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 group.h Base class for groups and group functions. */ #ifndef GROUP_H #define GROUP_H #include "group_type.h" #include "core/pool_type.hpp" #include "company_type.h" #include "vehicle_type.h" #include "engine_type.h" typedef Pool GroupPool; extern GroupPool _group_pool; ///< Pool of groups. /** Statistics and caches on the vehicles in a group. */ struct GroupStatistics { uint16 num_vehicle; ///< Number of vehicles. uint16 *num_engines; ///< Caches the number of engines of each type the company owns. bool autoreplace_defined; ///< Are any autoreplace rules set? bool autoreplace_finished; ///< Have all autoreplacement finished? uint16 num_profit_vehicle; ///< Number of vehicles considered for profit statistics; Money profit_last_year; ///< Sum of profits for all vehicles. GroupStatistics(); ~GroupStatistics(); void Clear(); void ClearProfits() { this->num_profit_vehicle = 0; this->profit_last_year = 0; } void ClearAutoreplace() { this->autoreplace_defined = false; this->autoreplace_finished = false; } static GroupStatistics &Get(CompanyID company, GroupID id_g, VehicleType type); static GroupStatistics &Get(const Vehicle *v); static GroupStatistics &GetAllGroup(const Vehicle *v); static void CountVehicle(const Vehicle *v, int delta); static void CountEngine(const Vehicle *v, int delta); static void VehicleReachedProfitAge(const Vehicle *v); static void UpdateProfits(); static void UpdateAfterLoad(); static void UpdateAutoreplace(CompanyID company); }; /** Group data. */ struct Group : GroupPool::PoolItem<&_group_pool> { char *name; ///< Group Name OwnerByte owner; ///< Group Owner VehicleTypeByte vehicle_type; ///< Vehicle type of the group bool replace_protection; ///< If set to true, the global autoreplace have no effect on the group GroupStatistics statistics; ///< NOSAVE: Statistics and caches on the vehicles in the group. GroupID parent; ///< Parent group Group(CompanyID owner = INVALID_COMPANY); ~Group(); }; static inline bool IsDefaultGroupID(GroupID index) { return index == DEFAULT_GROUP; } /** * Checks if a GroupID stands for all vehicles of a company * @param id_g The GroupID to check * @return true is id_g is identical to ALL_GROUP */ static inline bool IsAllGroupID(GroupID id_g) { return id_g == ALL_GROUP; } #define FOR_ALL_GROUPS_FROM(var, start) FOR_ALL_ITEMS_FROM(Group, group_index, var, start) #define FOR_ALL_GROUPS(var) FOR_ALL_GROUPS_FROM(var, 0) uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e); void SetTrainGroupID(Train *v, GroupID grp); void UpdateTrainGroupID(Train *v); void RemoveVehicleFromGroup(const Vehicle *v); void RemoveAllGroupsForCompany(const CompanyID company); bool GroupIsInGroup(GroupID search, GroupID group); extern GroupID _new_group_id; #endif /* GROUP_H */ openttd-1.5.3/src/hotkeys.h0000644000000000000000000000410612627373435014336 0ustar rootroot/* $Id: hotkeys.h 25669 2013-08-05 20:36:28Z michi_cc $ */ /* * 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 hotkeys.h %Hotkey related functions. */ #ifndef HOTKEYS_H #define HOTKEYS_H #include "core/smallvec_type.hpp" #include "gfx_type.h" #include "window_type.h" #include "string_type.h" /** * All data for a single hotkey. The name (for saving/loading a configfile), * a list of keycodes and a number to help identifying this hotkey. */ struct Hotkey { Hotkey(uint16 default_keycode, const char *name, int num); Hotkey(const uint16 *default_keycodes, const char *name, int num); void AddKeycode(uint16 keycode); const char *name; int num; SmallVector keycodes; }; #define HOTKEY_LIST_END Hotkey((uint16)0, NULL, -1) struct IniFile; /** * List of hotkeys for a window. */ struct HotkeyList { typedef EventState (*GlobalHotkeyHandlerFunc)(int hotkey); HotkeyList(const char *ini_group, Hotkey *items, GlobalHotkeyHandlerFunc global_hotkey_handler = NULL); ~HotkeyList(); void Load(IniFile *ini); void Save(IniFile *ini) const; int CheckMatch(uint16 keycode, bool global_only = false) const; GlobalHotkeyHandlerFunc global_hotkey_handler; private: const char *ini_group; Hotkey *items; /** * Dummy private copy constructor to prevent compilers from * copying the structure, which fails due to _hotkey_lists. */ HotkeyList(const HotkeyList &other); }; bool IsQuitKey(uint16 keycode); void LoadHotkeysFromConfig(); void SaveHotkeysToConfig(); void HandleGlobalHotkeys(WChar key, uint16 keycode); #endif /* HOTKEYS_H */ openttd-1.5.3/src/genworld.h0000644000000000000000000001020512627373434014465 0ustar rootroot/* $Id: genworld.h 23611 2011-12-19 20:56:50Z truebrain $ */ /* * 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 genworld.h Functions related to world/map generation. */ #ifndef GENWORLD_H #define GENWORLD_H #include "company_type.h" /** Constants related to world generation */ enum LandscapeGenerator { /* Order of these enums has to be the same as in lang/english.txt * Otherwise you will get inconsistent behaviour. */ LG_ORIGINAL = 0, ///< The original landscape generator LG_TERRAGENESIS = 1, ///< TerraGenesis Perlin landscape generator }; static const uint GENERATE_NEW_SEED = UINT_MAX; ///< Create a new random seed /** Modes for GenerateWorld */ enum GenWorldMode { GWM_NEWGAME = 0, ///< Generate a map for a new game GWM_EMPTY = 1, ///< Generate an empty map (sea-level) GWM_RANDOM = 2, ///< Generate a random map for SE GWM_HEIGHTMAP = 3, ///< Generate a newgame from a heightmap }; static const uint CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY = 4; ///< Value for custom sea level in difficulty settings. static const uint CUSTOM_SEA_LEVEL_MIN_PERCENTAGE = 1; ///< Minimum percentage a user can specify for custom sea level. static const uint CUSTOM_SEA_LEVEL_MAX_PERCENTAGE = 90; ///< Maximum percentage a user can specify for custom sea level. typedef void GWDoneProc(); ///< Procedure called when the genworld process finishes typedef void GWAbortProc(); ///< Called when genworld is aborted /** Properties of current genworld process */ struct GenWorldInfo { bool abort; ///< Whether to abort the thread ASAP bool quit_thread; ///< Do we want to quit the active thread bool threaded; ///< Whether we run _GenerateWorld threaded GenWorldMode mode; ///< What mode are we making a world in CompanyID lc; ///< The local_company before generating uint size_x; ///< X-size of the map uint size_y; ///< Y-size of the map GWDoneProc *proc; ///< Proc that is called when done (can be NULL) GWAbortProc *abortp; ///< Proc that is called when aborting (can be NULL) class ThreadObject *thread; ///< The thread we are in (can be NULL) }; /** Current stage of world generation process */ enum GenWorldProgress { GWP_MAP_INIT, ///< Initialize/allocate the map, start economy GWP_LANDSCAPE, ///< Create the landscape GWP_RIVER, ///< Create the rivers GWP_ROUGH_ROCKY, ///< Make rough and rocky areas GWP_TOWN, ///< Generate towns GWP_INDUSTRY, ///< Generate industries GWP_OBJECT, ///< Generate objects (radio tower, light houses) GWP_TREE, ///< Generate trees GWP_GAME_INIT, ///< Initialize the game GWP_RUNTILELOOP, ///< Runs the tile loop 1280 times to make snow etc GWP_RUNSCRIPT, ///< Runs the game script at most 2500 times, or when ever the script sleeps GWP_GAME_START, ///< Really prepare to start the game GWP_CLASS_COUNT }; /* genworld.cpp */ bool IsGenerateWorldThreaded(); void GenerateWorldSetCallback(GWDoneProc *proc); void GenerateWorldSetAbortCallback(GWAbortProc *proc); void WaitTillGeneratedWorld(); void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_settings = true); void AbortGeneratingWorld(); bool IsGeneratingWorldAborted(); void HandleGeneratingWorldAbortion(); /* genworld_gui.cpp */ void SetNewLandscapeType(byte landscape); void SetGeneratingWorldProgress(GenWorldProgress cls, uint total); void IncreaseGeneratingWorldProgress(GenWorldProgress cls); void PrepareGenerateWorldProgress(); void ShowGenerateWorldProgress(); void StartNewGameWithoutGUI(uint seed); void ShowCreateScenario(); void StartScenarioEditor(); extern bool _generating_world; #endif /* GENWORLD_H */ openttd-1.5.3/src/newgrf_industrytiles.cpp0000644000000000000000000003464412627373434017506 0ustar rootroot/* $Id: newgrf_industrytiles.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 newgrf_industrytiles.cpp NewGRF handling of industry tiles. */ #include "stdafx.h" #include "debug.h" #include "landscape.h" #include "newgrf_industrytiles.h" #include "newgrf_sound.h" #include "industry.h" #include "town.h" #include "command_func.h" #include "water.h" #include "newgrf_animation_base.h" #include "table/strings.h" #include "safeguards.h" /** * Based on newhouses equivalent, but adapted for newindustries * @param parameter from callback. It's in fact a pair of coordinates * @param tile TileIndex from which the callback was initiated * @param index of the industry been queried for * @param signed_offsets Are the x and y offset encoded in parameter signed? * @param grf_version8 True, if we are dealing with a new NewGRF which uses GRF version >= 8. * @return a construction of bits obeying the newgrf format */ uint32 GetNearbyIndustryTileInformation(byte parameter, TileIndex tile, IndustryID index, bool signed_offsets, bool grf_version8) { if (parameter != 0) tile = GetNearbyTile(parameter, tile, signed_offsets); // only perform if it is required bool is_same_industry = (IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == index); return GetNearbyTileInformation(tile, grf_version8) | (is_same_industry ? 1 : 0) << 8; } /** * This is the position of the tile relative to the northernmost tile of the industry. * Format: 00yxYYXX * Variable Content * x the x offset from the northernmost tile * XX same, but stored in a byte instead of a nibble * y the y offset from the northernmost tile * YY same, but stored in a byte instead of a nibble * @param tile TileIndex of the tile to evaluate * @param ind_tile northernmost tile of the industry */ uint32 GetRelativePosition(TileIndex tile, TileIndex ind_tile) { byte x = TileX(tile) - TileX(ind_tile); byte y = TileY(tile) - TileY(ind_tile); return ((y & 0xF) << 20) | ((x & 0xF) << 16) | (y << 8) | x; } /* virtual */ uint32 IndustryTileScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { switch (variable) { /* Construction state of the tile: a value between 0 and 3 */ case 0x40: return (IsTileType(this->tile, MP_INDUSTRY)) ? GetIndustryConstructionStage(this->tile) : 0; /* Terrain type */ case 0x41: return GetTerrainType(this->tile); /* Current town zone of the tile in the nearest town */ case 0x42: return GetTownRadiusGroup(ClosestTownFromTile(this->tile, UINT_MAX), this->tile); /* Relative position */ case 0x43: return GetRelativePosition(this->tile, this->industry->location.tile); /* Animation frame. Like house variable 46 but can contain anything 0..FF. */ case 0x44: return IsTileType(this->tile, MP_INDUSTRY) ? GetAnimationFrame(this->tile) : 0; /* Land info of nearby tiles */ case 0x60: return GetNearbyIndustryTileInformation(parameter, this->tile, this->industry == NULL ? (IndustryID)INVALID_INDUSTRY : this->industry->index, true, this->ro.grffile->grf_version >= 8); /* Animation stage of nearby tiles */ case 0x61: { TileIndex tile = GetNearbyTile(parameter, this->tile); if (IsTileType(tile, MP_INDUSTRY) && Industry::GetByTile(tile) == this->industry) { return GetAnimationFrame(tile); } return UINT_MAX; } /* Get industry tile ID at offset */ case 0x62: return GetIndustryIDAtOffset(GetNearbyTile(parameter, this->tile), this->industry, this->ro.grffile->grfid); } DEBUG(grf, 1, "Unhandled industry tile variable 0x%X", variable); *available = false; return UINT_MAX; } /* virtual */ uint32 IndustryTileScopeResolver::GetRandomBits() const { assert(this->industry != NULL && IsValidTile(this->tile)); assert(this->industry->index == INVALID_INDUSTRY || IsTileType(this->tile, MP_INDUSTRY)); return (this->industry->index != INVALID_INDUSTRY) ? GetIndustryRandomBits(this->tile) : 0; } /* virtual */ uint32 IndustryTileScopeResolver::GetTriggers() const { assert(this->industry != NULL && IsValidTile(this->tile)); assert(this->industry->index == INVALID_INDUSTRY || IsTileType(this->tile, MP_INDUSTRY)); if (this->industry->index == INVALID_INDUSTRY) return 0; return GetIndustryTriggers(this->tile); } /* virtual */ void IndustryTileScopeResolver::SetTriggers(int triggers) const { assert(this->industry != NULL && this->industry->index != INVALID_INDUSTRY && IsValidTile(this->tile) && IsTileType(this->tile, MP_INDUSTRY)); SetIndustryTriggers(this->tile, triggers); } /** * Get the associated NewGRF file from the industry graphics. * @param gfx Graphics to query. * @return Grf file associated with the graphics, if any. */ static const GRFFile *GetIndTileGrffile(IndustryGfx gfx) { const IndustryTileSpec *its = GetIndustryTileSpec(gfx); return (its != NULL) ? its->grf_prop.grffile : NULL; } /** * Constructor of the industry tiles scope resolver. * @param gfx Graphics of the industry. * @param tile %Tile of the industry. * @param indus %Industry owning the tile. * @param callback Callback ID. * @param callback_param1 First parameter (var 10) of the callback. * @param callback_param2 Second parameter (var 18) of the callback. */ IndustryTileResolverObject::IndustryTileResolverObject(IndustryGfx gfx, TileIndex tile, Industry *indus, CallbackID callback, uint32 callback_param1, uint32 callback_param2) : ResolverObject(GetIndTileGrffile(gfx), callback, callback_param1, callback_param2), indtile_scope(*this, indus, tile), ind_scope(*this, tile, indus, indus->type) { this->root_spritegroup = GetIndustryTileSpec(gfx)->grf_prop.spritegroup[0]; } /** * Constructor of the scope resolver for the industry tile. * @param ro Surrounding resolver. * @param industry %Industry owning the tile. * @param tile %Tile of the industry. */ IndustryTileScopeResolver::IndustryTileScopeResolver(ResolverObject &ro, Industry *industry, TileIndex tile) : ScopeResolver(ro) { this->industry = industry; this->tile = tile; } static void IndustryDrawTileLayout(const TileInfo *ti, const TileLayoutSpriteGroup *group, byte rnd_colour, byte stage, IndustryGfx gfx) { const DrawTileSprites *dts = group->ProcessRegisters(&stage); SpriteID image = dts->ground.sprite; PaletteID pal = dts->ground.pal; if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage; if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage; if (GB(image, 0, SPRITE_WIDTH) != 0) { /* If the ground sprite is the default flat water sprite, draw also canal/river borders * Do not do this if the tile's WaterClass is 'land'. */ if (image == SPR_FLAT_WATER_TILE && IsTileOnWater(ti->tile)) { DrawWaterClassGround(ti); } else { DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, GENERAL_SPRITE_COLOUR(rnd_colour))); } } DrawNewGRFTileSeq(ti, dts, TO_INDUSTRIES, stage, GENERAL_SPRITE_COLOUR(rnd_colour)); } uint16 GetIndustryTileCallback(CallbackID callback, uint32 param1, uint32 param2, IndustryGfx gfx_id, Industry *industry, TileIndex tile) { assert(industry != NULL && IsValidTile(tile)); assert(industry->index == INVALID_INDUSTRY || IsTileType(tile, MP_INDUSTRY)); IndustryTileResolverObject object(gfx_id, tile, industry, callback, param1, param2); return object.ResolveCallback(); } bool DrawNewIndustryTile(TileInfo *ti, Industry *i, IndustryGfx gfx, const IndustryTileSpec *inds) { if (ti->tileh != SLOPE_FLAT) { bool draw_old_one = true; if (HasBit(inds->callback_mask, CBM_INDT_DRAW_FOUNDATIONS)) { /* Called to determine the type (if any) of foundation to draw for industry tile */ uint32 callback_res = GetIndustryTileCallback(CBID_INDTILE_DRAW_FOUNDATIONS, 0, 0, gfx, i, ti->tile); if (callback_res != CALLBACK_FAILED) draw_old_one = ConvertBooleanCallback(inds->grf_prop.grffile, CBID_INDTILE_DRAW_FOUNDATIONS, callback_res); } if (draw_old_one) DrawFoundation(ti, FOUNDATION_LEVELED); } IndustryTileResolverObject object(gfx, ti->tile, i); const SpriteGroup *group = object.Resolve(); if (group == NULL || group->type != SGT_TILELAYOUT) return false; /* Limit the building stage to the number of stages supplied. */ const TileLayoutSpriteGroup *tlgroup = (const TileLayoutSpriteGroup *)group; byte stage = GetIndustryConstructionStage(ti->tile); IndustryDrawTileLayout(ti, tlgroup, i->random_colour, stage, gfx); return true; } extern bool IsSlopeRefused(Slope current, Slope refused); /** * Check the slope of a tile of a new industry. * @param ind_base_tile Base tile of the industry. * @param ind_tile Tile to check. * @param its Tile specification. * @param type Industry type. * @param gfx Gfx of the tile. * @param itspec_index Layout. * @param initial_random_bits Random bits of industry after construction * @param founder Industry founder * @param creation_type The circumstances the industry is created under. * @return Succeeded or failed command. */ CommandCost PerformIndustryTileSlopeCheck(TileIndex ind_base_tile, TileIndex ind_tile, const IndustryTileSpec *its, IndustryType type, IndustryGfx gfx, uint itspec_index, uint16 initial_random_bits, Owner founder, IndustryAvailabilityCallType creation_type) { Industry ind; ind.index = INVALID_INDUSTRY; ind.location.tile = ind_base_tile; ind.location.w = 0; ind.type = type; ind.random = initial_random_bits; ind.founder = founder; uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_SHAPE_CHECK, 0, creation_type << 8 | itspec_index, gfx, &ind, ind_tile); if (callback_res == CALLBACK_FAILED) { if (!IsSlopeRefused(GetTileSlope(ind_tile), its->slopes_refused)) return CommandCost(); return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } if (its->grf_prop.grffile->grf_version < 7) { if (callback_res != 0) return CommandCost(); return_cmd_error(STR_ERROR_SITE_UNSUITABLE); } return GetErrorMessageFromLocationCallbackResult(callback_res, its->grf_prop.grffile, STR_ERROR_SITE_UNSUITABLE); } /* Simple wrapper for GetHouseCallback to keep the animation unified. */ uint16 GetSimpleIndustryCallback(CallbackID callback, uint32 param1, uint32 param2, const IndustryTileSpec *spec, Industry *ind, TileIndex tile, int extra_data) { return GetIndustryTileCallback(callback, param1, param2, spec - GetIndustryTileSpec(0), ind, tile); } /** Helper class for animation control. */ struct IndustryAnimationBase : public AnimationBase { static const CallbackID cb_animation_speed = CBID_INDTILE_ANIMATION_SPEED; static const CallbackID cb_animation_next_frame = CBID_INDTILE_ANIM_NEXT_FRAME; static const IndustryTileCallbackMask cbm_animation_speed = CBM_INDT_ANIM_SPEED; static const IndustryTileCallbackMask cbm_animation_next_frame = CBM_INDT_ANIM_NEXT_FRAME; }; void AnimateNewIndustryTile(TileIndex tile) { const IndustryTileSpec *itspec = GetIndustryTileSpec(GetIndustryGfx(tile)); if (itspec == NULL) return; IndustryAnimationBase::AnimateTile(itspec, Industry::GetByTile(tile), tile, (itspec->special_flags & INDTILE_SPECIAL_NEXTFRAME_RANDOMBITS) != 0); } bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random) { const IndustryTileSpec *itspec = GetIndustryTileSpec(GetIndustryGfx(tile)); if (!HasBit(itspec->animation.triggers, iat)) return false; IndustryAnimationBase::ChangeAnimationFrame(CBID_INDTILE_ANIM_START_STOP, itspec, Industry::GetByTile(tile), tile, random, iat); return true; } bool StartStopIndustryTileAnimation(const Industry *ind, IndustryAnimationTrigger iat) { bool ret = true; uint32 random = Random(); TILE_AREA_LOOP(tile, ind->location) { if (ind->TileBelongsToIndustry(tile)) { if (StartStopIndustryTileAnimation(tile, iat, random)) { SB(random, 0, 16, Random()); } else { ret = false; } } } return ret; } /** * Trigger random triggers for an industry tile and reseed its random bits. * @param tile Industry tile to trigger. * @param trigger Trigger to trigger. * @param ind Industry of the tile. * @param [in,out] reseed_industry Collects bits to reseed for the industry. */ static void DoTriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger, Industry *ind, uint32 &reseed_industry) { assert(IsValidTile(tile) && IsTileType(tile, MP_INDUSTRY)); IndustryGfx gfx = GetIndustryGfx(tile); const IndustryTileSpec *itspec = GetIndustryTileSpec(gfx); if (itspec->grf_prop.spritegroup[0] == NULL) return; IndustryTileResolverObject object(gfx, tile, ind, CBID_RANDOM_TRIGGER); object.trigger = trigger; const SpriteGroup *group = object.Resolve(); if (group == NULL) return; byte new_random_bits = Random(); byte random_bits = GetIndustryRandomBits(tile); random_bits &= ~object.reseed[VSG_SCOPE_SELF]; random_bits |= new_random_bits & object.reseed[VSG_SCOPE_SELF]; SetIndustryRandomBits(tile, random_bits); MarkTileDirtyByTile(tile); reseed_industry |= object.reseed[VSG_SCOPE_PARENT]; } /** * Reseeds the random bits of an industry. * @param ind Industry. * @param reseed Bits to reseed. */ static void DoReseedIndustry(Industry *ind, uint32 reseed) { if (reseed == 0 || ind == NULL) return; uint16 random_bits = Random(); ind->random &= reseed; ind->random |= random_bits & reseed; } /** * Trigger a random trigger for a single industry tile. * @param tile Industry tile to trigger. * @param trigger Trigger to trigger. */ void TriggerIndustryTile(TileIndex tile, IndustryTileTrigger trigger) { uint32 reseed_industry = 0; Industry *ind = Industry::GetByTile(tile); DoTriggerIndustryTile(tile, trigger, ind, reseed_industry); DoReseedIndustry(ind, reseed_industry); } /** * Trigger a random trigger for all industry tiles. * @param ind Industry to trigger. * @param trigger Trigger to trigger. */ void TriggerIndustry(Industry *ind, IndustryTileTrigger trigger) { uint32 reseed_industry = 0; TILE_AREA_LOOP(tile, ind->location) { if (ind->TileBelongsToIndustry(tile)) { DoTriggerIndustryTile(tile, trigger, ind, reseed_industry); } } DoReseedIndustry(ind, reseed_industry); } openttd-1.5.3/src/thread/0000755000000000000000000000000012627373434013744 5ustar rootrootopenttd-1.5.3/src/thread/thread_win32.cpp0000644000000000000000000001052512627373434016744 0ustar rootroot/* $Id: thread_win32.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 thread_win32.cpp Win32 thread implementation of Threads. */ #include "../stdafx.h" #include "thread.h" #include "../debug.h" #include "../core/alloc_func.hpp" #include #include #include #include "../safeguards.h" /** * Win32 thread version for ThreadObject. */ class ThreadObject_Win32 : public ThreadObject { private: HANDLE thread; ///< System thread identifier. uint id; ///< Thread identifier. OTTDThreadFunc proc; ///< External thread procedure. void *param; ///< Parameter for the external thread procedure. bool self_destruct; ///< Free ourselves when done? public: /** * Create a win32 thread and start it, calling proc(param). */ ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct) : thread(NULL), id(0), proc(proc), param(param), self_destruct(self_destruct) { this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id); if (this->thread == NULL) return; ResumeThread(this->thread); } /* virtual */ ~ThreadObject_Win32() { if (this->thread != NULL) { CloseHandle(this->thread); this->thread = NULL; } } /* virtual */ bool Exit() { assert(GetCurrentThreadId() == this->id); /* For now we terminate by throwing an error, gives much cleaner cleanup */ throw OTTDThreadExitSignal(); } /* virtual */ void Join() { /* You cannot join yourself */ assert(GetCurrentThreadId() != this->id); WaitForSingleObject(this->thread, INFINITE); } private: /** * On thread creation, this function is called, which calls the real startup * function. This to get back into the correct instance again. */ static uint CALLBACK stThreadProc(void *thr) { ((ThreadObject_Win32 *)thr)->ThreadProc(); return 0; } /** * A new thread is created, and this function is called. Call the custom * function of the creator of the thread. */ void ThreadProc() { try { this->proc(this->param); } catch (OTTDThreadExitSignal) { } catch (...) { NOT_REACHED(); } if (self_destruct) delete this; } }; /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread) { ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL); if (thread != NULL) *thread = to; return true; } /** * Win32 thread version of ThreadMutex. */ class ThreadMutex_Win32 : public ThreadMutex { private: CRITICAL_SECTION critical_section; ///< The critical section we would enter. HANDLE event; ///< Event for signalling. uint recursive_count; ///< Recursive lock count. public: ThreadMutex_Win32() : recursive_count(0) { InitializeCriticalSection(&this->critical_section); this->event = CreateEvent(NULL, FALSE, FALSE, NULL); } /* virtual */ ~ThreadMutex_Win32() { DeleteCriticalSection(&this->critical_section); CloseHandle(this->event); } /* virtual */ void BeginCritical(bool allow_recursive = false) { /* windows mutex is recursive by itself */ EnterCriticalSection(&this->critical_section); this->recursive_count++; if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); } /* virtual */ void EndCritical(bool allow_recursive = false) { if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); this->recursive_count--; LeaveCriticalSection(&this->critical_section); } /* virtual */ void WaitForSignal() { assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise? this->EndCritical(); WaitForSingleObject(this->event, INFINITE); this->BeginCritical(); } /* virtual */ void SendSignal() { SetEvent(this->event); } }; /* static */ ThreadMutex *ThreadMutex::New() { return new ThreadMutex_Win32(); } openttd-1.5.3/src/thread/thread_pthread.cpp0000644000000000000000000001143312627373434017430 0ustar rootroot/* $Id: thread_pthread.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 thread_pthread.cpp POSIX pthread implementation of Threads. */ #include "../stdafx.h" #include "thread.h" #include #include #include "../safeguards.h" /** * POSIX pthread version for ThreadObject. */ class ThreadObject_pthread : public ThreadObject { private: pthread_t thread; ///< System thread identifier. OTTDThreadFunc proc; ///< External thread procedure. void *param; ///< Parameter for the external thread procedure. bool self_destruct; ///< Free ourselves when done? public: /** * Create a pthread and start it, calling proc(param). */ ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct) : thread(0), proc(proc), param(param), self_destruct(self_destruct) { pthread_create(&this->thread, NULL, &stThreadProc, this); } /* virtual */ bool Exit() { assert(pthread_self() == this->thread); /* For now we terminate by throwing an error, gives much cleaner cleanup */ throw OTTDThreadExitSignal(); } /* virtual */ void Join() { /* You cannot join yourself */ assert(pthread_self() != this->thread); pthread_join(this->thread, NULL); this->thread = 0; } private: /** * On thread creation, this function is called, which calls the real startup * function. This to get back into the correct instance again. */ static void *stThreadProc(void *thr) { ((ThreadObject_pthread *)thr)->ThreadProc(); pthread_exit(NULL); } /** * A new thread is created, and this function is called. Call the custom * function of the creator of the thread. */ void ThreadProc() { /* Call the proc of the creator to continue this thread */ try { this->proc(this->param); } catch (OTTDThreadExitSignal) { } catch (...) { NOT_REACHED(); } if (self_destruct) { pthread_detach(pthread_self()); delete this; } } }; /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread) { ThreadObject *to = new ThreadObject_pthread(proc, param, thread == NULL); if (thread != NULL) *thread = to; return true; } /** * POSIX pthread version of ThreadMutex. */ class ThreadMutex_pthread : public ThreadMutex { private: pthread_mutex_t mutex; ///< The actual mutex. pthread_cond_t condition; ///< Data for conditional waiting. pthread_mutexattr_t attr; ///< Attributes set for the mutex. pthread_t owner; ///< Owning thread of the mutex. uint recursive_count; ///< Recursive lock count. public: ThreadMutex_pthread() : owner(0), recursive_count(0) { pthread_mutexattr_init(&this->attr); pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK); pthread_mutex_init(&this->mutex, &this->attr); pthread_cond_init(&this->condition, NULL); } /* virtual */ ~ThreadMutex_pthread() { int err = pthread_cond_destroy(&this->condition); assert(err != EBUSY); err = pthread_mutex_destroy(&this->mutex); assert(err != EBUSY); } bool IsOwnedByCurrentThread() const { return this->owner == pthread_self(); } /* virtual */ void BeginCritical(bool allow_recursive = false) { /* pthread mutex is not recursive by itself */ if (this->IsOwnedByCurrentThread()) { if (!allow_recursive) NOT_REACHED(); } else { int err = pthread_mutex_lock(&this->mutex); assert(err == 0); assert(this->recursive_count == 0); this->owner = pthread_self(); } this->recursive_count++; } /* virtual */ void EndCritical(bool allow_recursive = false) { assert(this->IsOwnedByCurrentThread()); if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); this->recursive_count--; if (this->recursive_count != 0) return; this->owner = 0; int err = pthread_mutex_unlock(&this->mutex); assert(err == 0); } /* virtual */ void WaitForSignal() { uint old_recursive_count = this->recursive_count; this->recursive_count = 0; this->owner = 0; int err = pthread_cond_wait(&this->condition, &this->mutex); assert(err == 0); this->owner = pthread_self(); this->recursive_count = old_recursive_count; } /* virtual */ void SendSignal() { int err = pthread_cond_signal(&this->condition); assert(err == 0); } }; /* static */ ThreadMutex *ThreadMutex::New() { return new ThreadMutex_pthread(); } openttd-1.5.3/src/thread/thread_morphos.cpp0000644000000000000000000001225412627373434017472 0ustar rootroot/* $Id: thread_morphos.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 thread_morphos.cpp MorphOS implementation of Threads. */ #include "../stdafx.h" #include "thread.h" #include "../debug.h" #include "../core/alloc_func.hpp" #include #include #include #include #include #include #include #include "../safeguards.h" /** * avoid name clashes with MorphOS API functions */ #undef Exit #undef Wait /** * NOTE: this code heavily depends on latest libnix updates. So make * sure you link with new stuff which supports semaphore locking of * the IO resources, else it will just go foobar. */ struct OTTDThreadStartupMessage { struct Message msg; ///< standard exec.library message (MUST be the first thing in the message struct!) OTTDThreadFunc func; ///< function the thread will execute void *arg; ///< functions arguments for the thread function }; /** * Default OpenTTD STDIO/ERR debug output is not very useful for this, so we * utilize serial/ramdebug instead. */ #ifndef NO_DEBUG_MESSAGES void KPutStr(CONST_STRPTR format) { RawDoFmt(format, NULL, (void (*)())RAWFMTFUNC_SERIAL, NULL); } #else #define KPutStr(x) #endif /** * MorphOS version for ThreadObject. */ class ThreadObject_MorphOS : public ThreadObject { private: APTR m_thr; ///< System thread identifier. struct MsgPort *m_replyport; struct OTTDThreadStartupMessage m_msg; bool self_destruct; public: /** * Create a sub process and start it, calling proc(param). */ ThreadObject_MorphOS(OTTDThreadFunc proc, void *param, self_destruct) : m_thr(0), self_destruct(self_destruct) { struct Task *parent; KPutStr("[OpenTTD] Create thread...\n"); parent = FindTask(NULL); /* Make sure main thread runs with sane priority */ SetTaskPri(parent, 0); /* Things we'll pass down to the child by utilizing NP_StartupMsg */ m_msg.func = proc; m_msg.arg = param; m_replyport = CreateMsgPort(); if (m_replyport != NULL) { struct Process *child; m_msg.msg.mn_Node.ln_Type = NT_MESSAGE; m_msg.msg.mn_ReplyPort = m_replyport; m_msg.msg.mn_Length = sizeof(struct OTTDThreadStartupMessage); child = CreateNewProcTags( NP_CodeType, CODETYPE_PPC, NP_Entry, ThreadObject_MorphOS::Proxy, NP_StartupMsg, (IPTR)&m_msg, NP_Priority, 5UL, NP_Name, (IPTR)"OpenTTD Thread", NP_PPCStackSize, 131072UL, TAG_DONE); m_thr = (APTR) child; if (child != NULL) { KPutStr("[OpenTTD] Child process launched.\n"); } else { KPutStr("[OpenTTD] Couldn't create child process. (constructors never fail, yeah!)\n"); DeleteMsgPort(m_replyport); } } } /* virtual */ ~ThreadObject_MorphOS() { } /* virtual */ bool Exit() { struct OTTDThreadStartupMessage *msg; /* You can only exit yourself */ assert(IsCurrent()); KPutStr("[Child] Aborting...\n"); if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) { /* For now we terminate by throwing an error, gives much cleaner cleanup */ throw OTTDThreadExitSignal(); } return true; } /* virtual */ void Join() { struct OTTDThreadStartupMessage *reply; /* You cannot join yourself */ assert(!IsCurrent()); KPutStr("[OpenTTD] Join threads...\n"); KPutStr("[OpenTTD] Wait for child to quit...\n"); WaitPort(m_replyport); GetMsg(m_replyport); DeleteMsgPort(m_replyport); m_thr = 0; } /* virtual */ bool IsCurrent() { return FindTask(NULL) == m_thr; } private: /** * On thread creation, this function is called, which calls the real startup * function. This to get back into the correct instance again. */ static void Proxy() { struct Task *child = FindTask(NULL); struct OTTDThreadStartupMessage *msg; /* Make sure, we don't block the parent. */ SetTaskPri(child, -5); KPutStr("[Child] Progressing...\n"); if (NewGetTaskAttrs(NULL, &msg, sizeof(struct OTTDThreadStartupMessage *), TASKINFOTYPE_STARTUPMSG, TAG_DONE) && msg != NULL) { try { msg->func(msg->arg); } catch(OTTDThreadExitSignal e) { KPutStr("[Child] Returned to main()\n"); } catch(...) { NOT_REACHED(); } } /* Quit the child, exec.library will reply the startup msg internally. */ KPutStr("[Child] Done.\n"); if (self_destruct) delete this; } }; /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread) { ThreadObject *to = new ThreadObject_MorphOS(proc, param, thread == NULL); if (thread != NULL) *thread = to; return true; } openttd-1.5.3/src/thread/thread.h0000644000000000000000000000711412627373434015367 0ustar rootroot/* $Id: thread.h 26349 2014-02-16 21:37:05Z frosch $ */ /* * 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 thread.h Base of all threads. */ #ifndef THREAD_H #define THREAD_H /** Definition of all thread entry functions. */ typedef void (*OTTDThreadFunc)(void *); /** Signal used for signalling we knowingly want to end the thread. */ class OTTDThreadExitSignal { }; /** * A Thread Object which works on all our supported OSes. */ class ThreadObject { public: /** * Virtual destructor to allow 'delete' operator to work properly. */ virtual ~ThreadObject() {}; /** * Exit this thread. */ virtual bool Exit() = 0; /** * Join this thread. */ virtual void Join() = 0; /** * Create a thread; proc will be called as first function inside the thread, * with optional params. * @param proc The procedure to call inside the thread. * @param param The params to give with 'proc'. * @param thread Place to store a pointer to the thread in. May be NULL. * @return True if the thread was started correctly. */ static bool New(OTTDThreadFunc proc, void *param, ThreadObject **thread = NULL); }; /** * Cross-platform Mutex */ class ThreadMutex { public: /** * Create a new mutex. */ static ThreadMutex *New(); /** * Virtual Destructor to avoid compiler warnings. */ virtual ~ThreadMutex() {}; /** * Begin the critical section * @param allow_recursive Whether recursive locking is intentional. * If false, NOT_REACHED() will be called when the mutex is already locked * by the current thread. */ virtual void BeginCritical(bool allow_recursive = false) = 0; /** * End of the critical section * @param allow_recursive Whether recursive unlocking is intentional. * If false, NOT_REACHED() will be called when the mutex was locked more * than once by the current thread. */ virtual void EndCritical(bool allow_recursive = false) = 0; /** * Wait for a signal to be send. * @pre You must be in the critical section. * @note While waiting the critical section is left. * @post You will be in the critical section. */ virtual void WaitForSignal() = 0; /** * Send a signal and wake the 'thread' that was waiting for it. */ virtual void SendSignal() = 0; }; /** * Simple mutex locker to keep a mutex locked until the locker goes out of scope. */ class ThreadMutexLocker { public: /** * Lock the mutex and keep it locked for the life time of this object. * @param mutex Mutex to be locked. */ ThreadMutexLocker(ThreadMutex *mutex) : mutex(mutex) { mutex->BeginCritical(); } /** * Unlock the mutex. */ ~ThreadMutexLocker() { this->mutex->EndCritical(); } private: ThreadMutexLocker(const ThreadMutexLocker &) { NOT_REACHED(); } ThreadMutexLocker &operator=(const ThreadMutexLocker &) { NOT_REACHED(); return *this; } ThreadMutex *mutex; }; /** * Get number of processor cores in the system, including HyperThreading or similar. * @return Total number of processor cores. */ uint GetCPUCoreCount(); #endif /* THREAD_H */ openttd-1.5.3/src/thread/thread_os2.cpp0000644000000000000000000000731312627373434016506 0ustar rootroot/* $Id: thread_os2.cpp 27092 2014-12-24 17:17:18Z frosch $ */ /* * 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 thread_os2.cpp OS/2 implementation of Threads. */ #include "../stdafx.h" #include "thread.h" #define INCL_DOS #include #include #include "../safeguards.h" /** * OS/2 version for ThreadObject. */ class ThreadObject_OS2 : public ThreadObject { private: TID thread; ///< System thread identifier. OTTDThreadFunc proc; ///< External thread procedure. void *param; ///< Parameter for the external thread procedure. bool self_destruct; ///< Free ourselves when done? public: /** * Create a thread and start it, calling proc(param). */ ThreadObject_OS2(OTTDThreadFunc proc, void *param, bool self_destruct) : thread(0), proc(proc), param(param), self_destruct(self_destruct) { thread = _beginthread(stThreadProc, NULL, 1048576, this); } /* virtual */ bool Exit() { _endthread(); return true; } /* virtual */ void Join() { DosWaitThread(&this->thread, DCWW_WAIT); this->thread = 0; } private: /** * On thread creation, this function is called, which calls the real startup * function. This to get back into the correct instance again. */ static void stThreadProc(void *thr) { ((ThreadObject_OS2 *)thr)->ThreadProc(); } /** * A new thread is created, and this function is called. Call the custom * function of the creator of the thread. */ void ThreadProc() { /* Call the proc of the creator to continue this thread */ try { this->proc(this->param); } catch (OTTDThreadExitSignal e) { } catch (...) { NOT_REACHED(); } if (self_destruct) { this->Exit(); delete this; } } }; /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread) { ThreadObject *to = new ThreadObject_OS2(proc, param, thread == NULL); if (thread != NULL) *thread = to; return true; } /** * OS/2 version of ThreadMutex. */ class ThreadMutex_OS2 : public ThreadMutex { private: HMTX mutex; ///< The mutex. HEV event; ///< Event for waiting. uint recursive_count; ///< Recursive lock count. public: ThreadMutex_OS2() : recursive_count(0) { DosCreateMutexSem(NULL, &mutex, 0, FALSE); DosCreateEventSem(NULL, &event, 0, FALSE); } /* virtual */ ~ThreadMutex_OS2() { DosCloseMutexSem(mutex); DosCloseEventSem(event); } /* virtual */ void BeginCritical(bool allow_recursive = false) { /* os2 mutex is recursive by itself */ DosRequestMutexSem(mutex, (unsigned long) SEM_INDEFINITE_WAIT); this->recursive_count++; if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); } /* virtual */ void EndCritical(bool allow_recursive = false) { if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); this->recursive_count--; DosReleaseMutexSem(mutex); } /* virtual */ void WaitForSignal() { assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise? this->EndCritical(); DosWaitEventSem(event, SEM_INDEFINITE_WAIT); this->BeginCritical(); } /* virtual */ void SendSignal() { DosPostEventSem(event); } }; /* static */ ThreadMutex *ThreadMutex::New() { return new ThreadMutex_OS2(); } openttd-1.5.3/src/thread/thread_none.cpp0000644000000000000000000000251312627373434016737 0ustar rootroot/* $Id: thread_none.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 thread_none.cpp No-Threads-Available implementation of Threads */ #include "../stdafx.h" #include "thread.h" #include "../safeguards.h" /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread) { if (thread != NULL) *thread = NULL; return false; } /** Mutex that doesn't do locking because it ain't needed when there're no threads */ class ThreadMutex_None : public ThreadMutex { public: virtual void BeginCritical(bool allow_recursive = false) {} virtual void EndCritical(bool allow_recursive = false) {} virtual void WaitForSignal() {} virtual void SendSignal() {} }; /* static */ ThreadMutex *ThreadMutex::New() { return new ThreadMutex_None(); } openttd-1.5.3/src/news_gui.cpp0000644000000000000000000010732012627373441015022 0ustar rootroot/* $Id: news_gui.cpp 26965 2014-10-05 21:18:37Z peter1138 $ */ /* * 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 news_gui.cpp GUI functions related to news messages. */ #include "stdafx.h" #include "gui.h" #include "viewport_func.h" #include "strings_func.h" #include "window_func.h" #include "date_func.h" #include "vehicle_base.h" #include "vehicle_func.h" #include "vehicle_gui.h" #include "station_base.h" #include "industry.h" #include "town.h" #include "sound_func.h" #include "string_func.h" #include "widgets/dropdown_func.h" #include "statusbar_gui.h" #include "company_manager_face.h" #include "company_func.h" #include "engine_base.h" #include "engine_gui.h" #include "core/geometry_func.hpp" #include "command_func.h" #include "company_base.h" #include "settings_internal.h" #include "widgets/news_widget.h" #include "table/strings.h" #include "safeguards.h" const NewsItem *_statusbar_news_item = NULL; static uint MIN_NEWS_AMOUNT = 30; ///< preferred minimum amount of news messages static uint _total_news = 0; ///< current number of news items static NewsItem *_oldest_news = NULL; ///< head of news items queue static NewsItem *_latest_news = NULL; ///< tail of news items queue /** * Forced news item. * Users can force an item by accessing the history or "last message". * If the message being shown was forced by the user, a pointer is stored * in _forced_news. Otherwise, \a _forced_news variable is NULL. */ static const NewsItem *_forced_news = NULL; ///< item the user has asked for /** Current news item (last item shown regularly). */ static const NewsItem *_current_news = NULL; /** * Get the position a news-reference is referencing. * @param reftype The type of reference. * @param ref The reference. * @return A tile for the referenced object, or INVALID_TILE if none. */ static TileIndex GetReferenceTile(NewsReferenceType reftype, uint32 ref) { switch (reftype) { case NR_TILE: return (TileIndex)ref; case NR_STATION: return Station::Get((StationID)ref)->xy; case NR_INDUSTRY: return Industry::Get((IndustryID)ref)->location.tile + TileDiffXY(1, 1); case NR_TOWN: return Town::Get((TownID)ref)->xy; default: return INVALID_TILE; } } /* Normal news items. */ static const NWidgetPart _nested_normal_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_DATE), SetDataTip(STR_DATE_LONG_SMALL, STR_NULL), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), EndContainer(), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_MESSAGE), SetMinimalSize(428, 154), SetPadding(0, 5, 1, 5), EndContainer(), }; static WindowDesc _normal_news_desc( WDP_MANUAL, NULL, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_normal_news_widgets, lengthof(_nested_normal_news_widgets) ); /* New vehicles news items. */ static const NWidgetPart _nested_vehicle_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), NWidget(NWID_VERTICAL), NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_VEH_TITLE), SetFill(1, 1), SetMinimalSize(419, 55), SetDataTip(STR_EMPTY, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_VEH_BKGND), SetPadding(0, 25, 1, 25), NWidget(NWID_VERTICAL), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_NAME), SetMinimalSize(369, 33), SetFill(1, 0), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_SPR), SetMinimalSize(369, 32), SetFill(1, 0), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_N_VEH_INFO), SetMinimalSize(369, 46), SetFill(1, 0), EndContainer(), EndContainer(), EndContainer(), }; static WindowDesc _vehicle_news_desc( WDP_MANUAL, NULL, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_vehicle_news_widgets, lengthof(_nested_vehicle_news_widgets) ); /* Company news items. */ static const NWidgetPart _nested_company_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), NWidget(NWID_VERTICAL), NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_TITLE), SetFill(1, 1), SetMinimalSize(410, 20), SetDataTip(STR_EMPTY, STR_NULL), EndContainer(), NWidget(NWID_HORIZONTAL), SetPadding(0, 1, 1, 1), NWidget(NWID_VERTICAL), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_MGR_FACE), SetMinimalSize(93, 119), SetPadding(2, 6, 2, 1), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_MGR_NAME), SetMinimalSize(93, 24), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_COMPANY_MSG), SetFill(1, 1), SetMinimalSize(328, 150), EndContainer(), EndContainer(), }; static WindowDesc _company_news_desc( WDP_MANUAL, NULL, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_company_news_widgets, lengthof(_nested_company_news_widgets) ); /* Thin news items. */ static const NWidgetPart _nested_thin_news_widgets[] = { NWidget(WWT_PANEL, COLOUR_WHITE, WID_N_PANEL), NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1), NWidget(WWT_CLOSEBOX, COLOUR_WHITE, WID_N_CLOSEBOX), SetPadding(0, 0, 0, 1), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_LABEL, COLOUR_WHITE, WID_N_DATE), SetDataTip(STR_DATE_LONG_SMALL, STR_NULL), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), EndContainer(), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_MESSAGE), SetMinimalSize(428, 48), SetFill(1, 0), SetPadding(0, 5, 0, 5), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetMinimalSize(426, 70), SetPadding(1, 2, 2, 2), EndContainer(), }; static WindowDesc _thin_news_desc( WDP_MANUAL, NULL, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_thin_news_widgets, lengthof(_nested_thin_news_widgets) ); /* Small news items. */ static const NWidgetPart _nested_small_news_widgets[] = { /* Caption + close box. The caption is no WWT_CAPTION as the window shall not be moveable and so on. */ NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE, WID_N_CLOSEBOX), NWidget(WWT_EMPTY, COLOUR_LIGHT_BLUE, WID_N_CAPTION), SetFill(1, 0), EndContainer(), /* Main part */ NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_N_HEADLINE), NWidget(WWT_INSET, COLOUR_LIGHT_BLUE, WID_N_INSET), SetPadding(2, 2, 2, 2), NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_N_VIEWPORT), SetPadding(1, 1, 1, 1), SetMinimalSize(274, 47), SetFill(1, 0), EndContainer(), NWidget(WWT_EMPTY, COLOUR_WHITE, WID_N_MESSAGE), SetMinimalSize(275, 20), SetFill(1, 0), SetPadding(0, 5, 0, 5), EndContainer(), }; static WindowDesc _small_news_desc( WDP_MANUAL, NULL, 0, 0, WC_NEWS_WINDOW, WC_NONE, 0, _nested_small_news_widgets, lengthof(_nested_small_news_widgets) ); /** * Window layouts for news items. */ static WindowDesc* _news_window_layout[] = { &_thin_news_desc, ///< NF_THIN &_small_news_desc, ///< NF_SMALL &_normal_news_desc, ///< NF_NORMAL &_vehicle_news_desc, ///< NF_VEHICLE &_company_news_desc, ///< NF_COMPANY }; WindowDesc* GetNewsWindowLayout(NewsFlag flags) { uint layout = GB(flags, NFB_WINDOW_LAYOUT, NFB_WINDOW_LAYOUT_COUNT); assert(layout < lengthof(_news_window_layout)); return _news_window_layout[layout]; } /** * Per-NewsType data */ static NewsTypeData _news_type_data[] = { /* name, age, sound, */ NewsTypeData("news_display.arrival_player", 60, SND_1D_APPLAUSE ), ///< NT_ARRIVAL_COMPANY NewsTypeData("news_display.arrival_other", 60, SND_1D_APPLAUSE ), ///< NT_ARRIVAL_OTHER NewsTypeData("news_display.accident", 90, SND_BEGIN ), ///< NT_ACCIDENT NewsTypeData("news_display.company_info", 60, SND_BEGIN ), ///< NT_COMPANY_INFO NewsTypeData("news_display.open", 90, SND_BEGIN ), ///< NT_INDUSTRY_OPEN NewsTypeData("news_display.close", 90, SND_BEGIN ), ///< NT_INDUSTRY_CLOSE NewsTypeData("news_display.economy", 30, SND_BEGIN ), ///< NT_ECONOMY NewsTypeData("news_display.production_player", 30, SND_BEGIN ), ///< NT_INDUSTRY_COMPANY NewsTypeData("news_display.production_other", 30, SND_BEGIN ), ///< NT_INDUSTRY_OTHER NewsTypeData("news_display.production_nobody", 30, SND_BEGIN ), ///< NT_INDUSTRY_NOBODY NewsTypeData("news_display.advice", 150, SND_BEGIN ), ///< NT_ADVICE NewsTypeData("news_display.new_vehicles", 30, SND_1E_OOOOH ), ///< NT_NEW_VEHICLES NewsTypeData("news_display.acceptance", 90, SND_BEGIN ), ///< NT_ACCEPTANCE NewsTypeData("news_display.subsidies", 180, SND_BEGIN ), ///< NT_SUBSIDIES NewsTypeData("news_display.general", 60, SND_BEGIN ), ///< NT_GENERAL }; assert_compile(lengthof(_news_type_data) == NT_END); /** * Return the news display option. * @return display options */ NewsDisplay NewsTypeData::GetDisplay() const { uint index; const SettingDesc *sd = GetSettingFromName(this->name, &index); assert(sd != NULL); void *ptr = GetVariableAddress(NULL, &sd->save); return (NewsDisplay)ReadValue(ptr, sd->save.conv); } /** Window class displaying a news item. */ struct NewsWindow : Window { uint16 chat_height; ///< Height of the chat window. uint16 status_height; ///< Height of the status bar window const NewsItem *ni; ///< News item to display. static uint duration; ///< Remaining time for showing current news message (may only be accessed while a news item is displayed). NewsWindow(WindowDesc *desc, const NewsItem *ni) : Window(desc), ni(ni) { NewsWindow::duration = 555; const Window *w = FindWindowByClass(WC_SEND_NETWORK_MSG); this->chat_height = (w != NULL) ? w->height : 0; this->status_height = FindWindowById(WC_STATUS_BAR, 0)->height; this->flags |= WF_DISABLE_VP_SCROLL; this->CreateNestedTree(); /* For company news with a face we have a separate headline in param[0] */ if (desc == &_company_news_desc) this->GetWidget(WID_N_TITLE)->widget_data = this->ni->params[0]; this->FinishInitNested(0); /* Initialize viewport if it exists. */ NWidgetViewport *nvp = this->GetWidget(WID_N_VIEWPORT); if (nvp != NULL) { nvp->InitializeViewport(this, ni->reftype1 == NR_VEHICLE ? 0x80000000 | ni->ref1 : GetReferenceTile(ni->reftype1, ni->ref1), ZOOM_LVL_NEWS); if (this->ni->flags & NF_NO_TRANSPARENT) nvp->disp_flags |= ND_NO_TRANSPARENCY; if ((this->ni->flags & NF_INCOLOUR) == 0) { nvp->disp_flags |= ND_SHADE_GREY; } else if (this->ni->flags & NF_SHADE) { nvp->disp_flags |= ND_SHADE_DIMMED; } } PositionNewsMessage(this); } void DrawNewsBorder(const Rect &r) const { GfxFillRect(r.left, r.top, r.right, r.bottom, PC_WHITE); GfxFillRect(r.left, r.top, r.left, r.bottom, PC_BLACK); GfxFillRect(r.right, r.top, r.right, r.bottom, PC_BLACK); GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK); GfxFillRect(r.left, r.bottom, r.right, r.bottom, PC_BLACK); } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { Point pt = { 0, _screen.height }; return pt; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { StringID str = STR_NULL; switch (widget) { case WID_N_MGR_FACE: *size = maxdim(*size, GetSpriteSize(SPR_GRADIENT)); break; case WID_N_MESSAGE: CopyInDParam(0, this->ni->params, lengthof(this->ni->params)); str = this->ni->string_id; break; case WID_N_COMPANY_MSG: str = this->GetCompanyMessageString(); break; case WID_N_VEH_NAME: case WID_N_VEH_TITLE: str = this->GetNewVehicleMessageString(widget); break; case WID_N_VEH_INFO: { assert(this->ni->reftype1 == NR_ENGINE); EngineID engine = this->ni->ref1; str = GetEngineInfoString(engine); break; } default: return; // Do nothing } /* Update minimal size with length of the multi-line string. */ Dimension d = *size; d.width = (d.width >= padding.width) ? d.width - padding.width : 0; d.height = (d.height >= padding.height) ? d.height - padding.height : 0; d = GetStringMultiLineBoundingBox(str, d); d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); } virtual void SetStringParameters(int widget) const { if (widget == WID_N_DATE) SetDParam(0, this->ni->date); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_N_CAPTION: DrawCaption(r, COLOUR_LIGHT_BLUE, this->owner, STR_NEWS_MESSAGE_CAPTION); break; case WID_N_PANEL: this->DrawNewsBorder(r); break; case WID_N_MESSAGE: CopyInDParam(0, this->ni->params, lengthof(this->ni->params)); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->ni->string_id, TC_FROMSTRING, SA_CENTER); break; case WID_N_MGR_FACE: { const CompanyNewsInformation *cni = (const CompanyNewsInformation*)this->ni->free_data; DrawCompanyManagerFace(cni->face, cni->colour, r.left, r.top); GfxFillRect(r.left, r.top, r.right, r.bottom, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); break; } case WID_N_MGR_NAME: { const CompanyNewsInformation *cni = (const CompanyNewsInformation*)this->ni->free_data; SetDParamStr(0, cni->president_name); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER); break; } case WID_N_COMPANY_MSG: DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->GetCompanyMessageString(), TC_FROMSTRING, SA_CENTER); break; case WID_N_VEH_BKGND: GfxFillRect(r.left, r.top, r.right, r.bottom, PC_GREY); break; case WID_N_VEH_NAME: case WID_N_VEH_TITLE: DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->GetNewVehicleMessageString(widget), TC_FROMSTRING, SA_CENTER); break; case WID_N_VEH_SPR: { assert(this->ni->reftype1 == NR_ENGINE); EngineID engine = this->ni->ref1; DrawVehicleEngine(r.left, r.right, (r.left + r.right) / 2, (r.top + r.bottom) / 2, engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW); GfxFillRect(r.left, r.top, r.right, r.bottom, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); break; } case WID_N_VEH_INFO: { assert(this->ni->reftype1 == NR_ENGINE); EngineID engine = this->ni->ref1; DrawStringMultiLine(r.left, r.right, r.top, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER); break; } } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_N_CLOSEBOX: NewsWindow::duration = 0; delete this; _forced_news = NULL; break; case WID_N_CAPTION: if (this->ni->reftype1 == NR_VEHICLE) { const Vehicle *v = Vehicle::Get(this->ni->ref1); ShowVehicleViewWindow(v); } break; case WID_N_VIEWPORT: break; // Ignore clicks default: if (this->ni->reftype1 == NR_VEHICLE) { const Vehicle *v = Vehicle::Get(this->ni->ref1); ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos); } else { TileIndex tile1 = GetReferenceTile(this->ni->reftype1, this->ni->ref1); TileIndex tile2 = GetReferenceTile(this->ni->reftype2, this->ni->ref2); if (_ctrl_pressed) { if (tile1 != INVALID_TILE) ShowExtraViewPortWindow(tile1); if (tile2 != INVALID_TILE) ShowExtraViewPortWindow(tile2); } else { if ((tile1 == INVALID_TILE || !ScrollMainWindowToTile(tile1)) && tile2 != INVALID_TILE) { ScrollMainWindowToTile(tile2); } } } break; } } virtual EventState OnKeyPress(WChar key, uint16 keycode) { if (keycode == WKC_SPACE) { /* Don't continue. */ delete this; return ES_HANDLED; } return ES_NOT_HANDLED; } /** * 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; /* The chatbar has notified us that is was either created or closed */ int newtop = this->top + this->chat_height - data; this->chat_height = data; this->SetWindowTop(newtop); } virtual void OnTick() { /* Scroll up newsmessages from the bottom in steps of 4 pixels */ int newtop = max(this->top - 4, _screen.height - this->height - this->status_height - this->chat_height); this->SetWindowTop(newtop); } private: /** * Moves the window so #newtop is new 'top' coordinate. Makes screen dirty where needed. * @param newtop new top coordinate */ void SetWindowTop(int newtop) { if (this->top == newtop) return; int mintop = min(newtop, this->top); int maxtop = max(newtop, this->top); if (this->viewport != NULL) this->viewport->top += newtop - this->top; this->top = newtop; SetDirtyBlocks(this->left, mintop, this->left + this->width, maxtop + this->height); } StringID GetCompanyMessageString() const { /* Company news with a face have a separate headline, so the normal message is shifted by two params */ CopyInDParam(0, this->ni->params + 2, lengthof(this->ni->params) - 2); return this->ni->params[1]; } StringID GetNewVehicleMessageString(int widget) const { assert(this->ni->reftype1 == NR_ENGINE); EngineID engine = this->ni->ref1; switch (widget) { case WID_N_VEH_TITLE: SetDParam(0, GetEngineCategoryName(engine)); return STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE; case WID_N_VEH_NAME: SetDParam(0, engine); return STR_NEWS_NEW_VEHICLE_TYPE; default: NOT_REACHED(); } } }; /* static */ uint NewsWindow::duration = 0; // Instance creation. /** Open up an own newspaper window for the news item */ static void ShowNewspaper(const NewsItem *ni) { SoundFx sound = _news_type_data[ni->type].sound; if (sound != 0 && _settings_client.sound.news_full) SndPlayFx(sound); new NewsWindow(GetNewsWindowLayout(ni->flags), ni); } /** Show news item in the ticker */ static void ShowTicker(const NewsItem *ni) { if (_settings_client.sound.news_ticker) SndPlayFx(SND_16_MORSE); _statusbar_news_item = ni; InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_TICKER); } /** Initialize the news-items data structures */ void InitNewsItemStructs() { for (NewsItem *ni = _oldest_news; ni != NULL; ) { NewsItem *next = ni->next; delete ni; ni = next; } _total_news = 0; _oldest_news = NULL; _latest_news = NULL; _forced_news = NULL; _current_news = NULL; _statusbar_news_item = NULL; NewsWindow::duration = 0; } /** * Are we ready to show another news item? * Only if nothing is in the newsticker and no newspaper is displayed */ static bool ReadyForNextItem() { const NewsItem *ni = _forced_news == NULL ? _current_news : _forced_news; if (ni == NULL) return true; /* Ticker message * Check if the status bar message is still being displayed? */ if (IsNewsTickerShown()) return false; /* Newspaper message, decrement duration counter */ if (NewsWindow::duration != 0) NewsWindow::duration--; /* neither newsticker nor newspaper are running */ return (NewsWindow::duration == 0 || FindWindowById(WC_NEWS_WINDOW, 0) == NULL); } /** Move to the next news item */ static void MoveToNextItem() { InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); // invalidate the statusbar DeleteWindowById(WC_NEWS_WINDOW, 0); // close the newspapers window if shown _forced_news = NULL; _statusbar_news_item = NULL; /* if we're not at the last item, then move on */ if (_current_news != _latest_news) { _current_news = (_current_news == NULL) ? _oldest_news : _current_news->next; const NewsItem *ni = _current_news; const NewsType type = ni->type; /* check the date, don't show too old items */ if (_date - _news_type_data[type].age > ni->date) return; switch (_news_type_data[type].GetDisplay()) { default: NOT_REACHED(); case ND_OFF: // Off - show nothing only a small reminder in the status bar InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_REMINDER); break; case ND_SUMMARY: // Summary - show ticker ShowTicker(ni); break; case ND_FULL: // Full - show newspaper ShowNewspaper(ni); break; } } } /** * Add a new newsitem to be shown. * @param string String to display * @param type news category * @param flags display flags for the news * @param reftype1 Type of ref1 * @param ref1 Reference 1 to some object: Used for a possible viewport, scrolling after clicking on the news, and for deleteing the news when the object is deleted. * @param reftype2 Type of ref2 * @param ref2 Reference 2 to some object: Used for scrolling after clicking on the news, and for deleteing the news when the object is deleted. * @param free_data Pointer to data that must be freed once the news message is cleared * * @see NewsSubtype */ void AddNewsItem(StringID string, NewsType type, NewsFlag flags, NewsReferenceType reftype1, uint32 ref1, NewsReferenceType reftype2, uint32 ref2, void *free_data) { if (_game_mode == GM_MENU) return; /* Create new news item node */ NewsItem *ni = new NewsItem; ni->string_id = string; ni->type = type; ni->flags = flags; /* show this news message in colour? */ if (_cur_year >= _settings_client.gui.coloured_news_year) ni->flags |= NF_INCOLOUR; ni->reftype1 = reftype1; ni->reftype2 = reftype2; ni->ref1 = ref1; ni->ref2 = ref2; ni->free_data = free_data; ni->date = _date; CopyOutDParam(ni->params, 0, lengthof(ni->params)); if (_total_news++ == 0) { assert(_oldest_news == NULL); _oldest_news = ni; ni->prev = NULL; } else { assert(_latest_news->next == NULL); _latest_news->next = ni; ni->prev = _latest_news; } ni->next = NULL; _latest_news = ni; SetWindowDirty(WC_MESSAGE_HISTORY, 0); } /** * Create a new custom news item. * @param tile unused * @param flags type of operation * @param p1 various bitstuffed elements * - p1 = (bit 0 - 7) - NewsType of the message. * - p1 = (bit 8 - 15) - NewsReferenceType of first reference. * - p1 = (bit 16 - 23) - Company this news message is for. * @param p2 First reference of the news message. * @param text The text of the news message. * @return the cost of this operation or an error */ CommandCost CmdCustomNewsItem(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { if (_current_company != OWNER_DEITY) return CMD_ERROR; NewsType type = (NewsType)GB(p1, 0, 8); NewsReferenceType reftype1 = (NewsReferenceType)GB(p1, 8, 8); CompanyID company = (CompanyID)GB(p1, 16, 8); if (company != INVALID_OWNER && !Company::IsValidID(company)) return CMD_ERROR; if (type >= NT_END) return CMD_ERROR; if (StrEmpty(text)) return CMD_ERROR; switch (reftype1) { case NR_NONE: break; case NR_TILE: if (!IsValidTile(p2)) return CMD_ERROR; break; case NR_VEHICLE: if (!Vehicle::IsValidID(p2)) return CMD_ERROR; break; case NR_STATION: if (!Station::IsValidID(p2)) return CMD_ERROR; break; case NR_INDUSTRY: if (!Industry::IsValidID(p2)) return CMD_ERROR; break; case NR_TOWN: if (!Town::IsValidID(p2)) return CMD_ERROR; break; case NR_ENGINE: if (!Engine::IsValidID(p2)) return CMD_ERROR; break; default: return CMD_ERROR; } if (company != INVALID_OWNER && company != _local_company) return CommandCost(); if (flags & DC_EXEC) { char *news = stredup(text); SetDParamStr(0, news); AddNewsItem(STR_NEWS_CUSTOM_ITEM, type, NF_NORMAL, reftype1, p2, NR_NONE, UINT32_MAX, news); } return CommandCost(); } /** Delete a news item from the queue */ static void DeleteNewsItem(NewsItem *ni) { /* Delete the news from the news queue. */ if (ni->prev != NULL) { ni->prev->next = ni->next; } else { assert(_oldest_news == ni); _oldest_news = ni->next; } if (ni->next != NULL) { ni->next->prev = ni->prev; } else { assert(_latest_news == ni); _latest_news = ni->prev; } _total_news--; if (_forced_news == ni || _current_news == ni || _statusbar_news_item == ni) { /* When we're the current news, go to the previous item first; * we just possibly made that the last news item. */ if (_current_news == ni) _current_news = ni->prev; /* About to remove the currently forced item (shown as newspapers) || * about to remove the currently displayed item (newspapers, ticker, or just a reminder) */ MoveToNextItem(); } delete ni; SetWindowDirty(WC_MESSAGE_HISTORY, 0); } /** * Delete a news item type about a vehicle. * When the news item type is INVALID_STRING_ID all news about the vehicle gets deleted. * @param vid The vehicle to remove the news for. * @param news The news type to remove. */ void DeleteVehicleNews(VehicleID vid, StringID news) { NewsItem *ni = _oldest_news; while (ni != NULL) { NewsItem *next = ni->next; if (((ni->reftype1 == NR_VEHICLE && ni->ref1 == vid) || (ni->reftype2 == NR_VEHICLE && ni->ref2 == vid)) && (news == INVALID_STRING_ID || ni->string_id == news)) { DeleteNewsItem(ni); } ni = next; } } /** * Remove news regarding given station so there are no 'unknown station now accepts Mail' * or 'First train arrived at unknown station' news items. * @param sid station to remove news about */ void DeleteStationNews(StationID sid) { NewsItem *ni = _oldest_news; while (ni != NULL) { NewsItem *next = ni->next; if ((ni->reftype1 == NR_STATION && ni->ref1 == sid) || (ni->reftype2 == NR_STATION && ni->ref2 == sid)) { DeleteNewsItem(ni); } ni = next; } } /** * Remove news regarding given industry * @param iid industry to remove news about */ void DeleteIndustryNews(IndustryID iid) { NewsItem *ni = _oldest_news; while (ni != NULL) { NewsItem *next = ni->next; if ((ni->reftype1 == NR_INDUSTRY && ni->ref1 == iid) || (ni->reftype2 == NR_INDUSTRY && ni->ref2 == iid)) { DeleteNewsItem(ni); } ni = next; } } /** * Remove engine announcements for invalid engines. */ void DeleteInvalidEngineNews() { NewsItem *ni = _oldest_news; while (ni != NULL) { NewsItem *next = ni->next; if ((ni->reftype1 == NR_ENGINE && (!Engine::IsValidID(ni->ref1) || !Engine::Get(ni->ref1)->IsEnabled())) || (ni->reftype2 == NR_ENGINE && (!Engine::IsValidID(ni->ref2) || !Engine::Get(ni->ref2)->IsEnabled()))) { DeleteNewsItem(ni); } ni = next; } } static void RemoveOldNewsItems() { NewsItem *next; for (NewsItem *cur = _oldest_news; _total_news > MIN_NEWS_AMOUNT && cur != NULL; cur = next) { next = cur->next; if (_date - _news_type_data[cur->type].age * _settings_client.gui.news_message_timeout > cur->date) DeleteNewsItem(cur); } } /** * Report a change in vehicle IDs (due to autoreplace) to affected vehicle news. * @note Viewports of currently displayed news is changed via #ChangeVehicleViewports * @param from_index the old vehicle ID * @param to_index the new vehicle ID */ void ChangeVehicleNews(VehicleID from_index, VehicleID to_index) { for (NewsItem *ni = _oldest_news; ni != NULL; ni = ni->next) { if (ni->reftype1 == NR_VEHICLE && ni->ref1 == from_index) ni->ref1 = to_index; if (ni->reftype2 == NR_VEHICLE && ni->ref2 == from_index) ni->ref2 = to_index; if (ni->flags & NF_VEHICLE_PARAM0 && ni->params[0] == from_index) ni->params[0] = to_index; } } void NewsLoop() { /* no news item yet */ if (_total_news == 0) return; /* There is no status bar, so no reason to show news; * especially important with the end game screen when * there is no status bar but possible news. */ if (FindWindowById(WC_STATUS_BAR, 0) == NULL) return; static byte _last_clean_month = 0; if (_last_clean_month != _cur_month) { RemoveOldNewsItems(); _last_clean_month = _cur_month; } if (ReadyForNextItem()) MoveToNextItem(); } /** Do a forced show of a specific message */ static void ShowNewsMessage(const NewsItem *ni) { assert(_total_news != 0); /* Delete the news window */ DeleteWindowById(WC_NEWS_WINDOW, 0); /* setup forced news item */ _forced_news = ni; if (_forced_news != NULL) { DeleteWindowById(WC_NEWS_WINDOW, 0); ShowNewspaper(ni); } } /** Show previous news item */ void ShowLastNewsMessage() { const NewsItem *ni = NULL; if (_total_news == 0) { return; } else if (_forced_news == NULL) { /* Not forced any news yet, show the current one, unless a news window is * open (which can only be the current one), then show the previous item */ if (_current_news == NULL) { /* No news were shown yet resp. the last shown one was already deleted. * Threat this as if _forced_news reached _oldest_news; so, wrap around and start anew with the latest. */ ni = _latest_news; } else { const Window *w = FindWindowById(WC_NEWS_WINDOW, 0); ni = (w == NULL || (_current_news == _oldest_news)) ? _current_news : _current_news->prev; } } else if (_forced_news == _oldest_news) { /* We have reached the oldest news, start anew with the latest */ ni = _latest_news; } else { /* 'Scrolling' through news history show each one in turn */ ni = _forced_news->prev; } bool wrap = false; for (;;) { if (_news_type_data[ni->type].GetDisplay() != ND_OFF) { ShowNewsMessage(ni); break; } ni = ni->prev; if (ni == NULL) { if (wrap) break; /* We have reached the oldest news, start anew with the latest */ ni = _latest_news; wrap = true; } } } /** * Draw an unformatted news message truncated to a maximum length. If * length exceeds maximum length it will be postfixed by '...' * @param left the left most location for the string * @param right the right most location for the string * @param y position of the string * @param colour the colour the string will be shown in * @param *ni NewsItem being printed * @param maxw maximum width of string in pixels */ static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem *ni) { char buffer[512], buffer2[512]; StringID str; CopyInDParam(0, ni->params, lengthof(ni->params)); str = ni->string_id; GetString(buffer, str, lastof(buffer)); /* Copy the just gotten string to another buffer to remove any formatting * from it such as big fonts, etc. */ const char *ptr = buffer; char *dest = buffer2; WChar c_last = '\0'; for (;;) { WChar c = Utf8Consume(&ptr); if (c == 0) break; /* Make a space from a newline, but ignore multiple newlines */ if (c == '\n' && c_last != '\n') { dest[0] = ' '; dest++; } else if (c == '\r') { dest[0] = dest[1] = dest[2] = dest[3] = ' '; dest += 4; } else if (IsPrintable(c)) { dest += Utf8Encode(dest, c); } c_last = c; } *dest = '\0'; /* Truncate and show string; postfixed by '...' if necessary */ DrawString(left, right, y, buffer2, colour); } struct MessageHistoryWindow : Window { static const int top_spacing; ///< Additional spacing at the top of the #WID_MH_BACKGROUND widget. static const int bottom_spacing; ///< Additional spacing at the bottom of the #WID_MH_BACKGROUND widget. int line_height; /// < Height of a single line in the news history window including spacing. int date_width; /// < Width needed for the date part. Scrollbar *vscroll; MessageHistoryWindow(WindowDesc *desc) : Window(desc) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_MH_SCROLLBAR); this->FinishInitNested(); // Initializes 'this->line_height' and 'this->date_width'. this->OnInvalidateData(0); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget == WID_MH_BACKGROUND) { this->line_height = FONT_HEIGHT_NORMAL + 2; resize->height = this->line_height; /* Months are off-by-one, so it's actually 8. Not using * month 12 because the 1 is usually less wide. */ SetDParam(0, ConvertYMDToDate(ORIGINAL_MAX_YEAR, 7, 30)); this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width; size->height = 4 * resize->height + this->top_spacing + this->bottom_spacing; // At least 4 lines are visible. size->width = max(200u, size->width); // At least 200 pixels wide. } } virtual void OnPaint() { this->OnInvalidateData(0); this->DrawWidgets(); } virtual void DrawWidget(const Rect &r, int widget) const { if (widget != WID_MH_BACKGROUND || _total_news == 0) return; /* Find the first news item to display. */ NewsItem *ni = _latest_news; for (int n = this->vscroll->GetPosition(); n > 0; n--) { ni = ni->prev; if (ni == NULL) return; } /* Fill the widget with news items. */ int y = r.top + this->top_spacing; bool rtl = _current_text_dir == TD_RTL; uint date_left = rtl ? r.right - WD_FRAMERECT_RIGHT - this->date_width : r.left + WD_FRAMERECT_LEFT; uint date_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->date_width; uint news_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.left + WD_FRAMERECT_LEFT + this->date_width + WD_FRAMERECT_RIGHT; uint news_right = rtl ? r.right - WD_FRAMERECT_RIGHT - this->date_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT; for (int n = this->vscroll->GetCapacity(); n > 0; n--) { SetDParam(0, ni->date); DrawString(date_left, date_right, y, STR_SHORT_DATE); DrawNewsString(news_left, news_right, y, TC_WHITE, ni); y += this->line_height; ni = ni->prev; if (ni == NULL) return; } } /** * 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->vscroll->SetCount(_total_news); } virtual void OnClick(Point pt, int widget, int click_count) { if (widget == WID_MH_BACKGROUND) { NewsItem *ni = _latest_news; if (ni == NULL) return; for (int n = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_MH_BACKGROUND, WD_FRAMERECT_TOP, this->line_height); n > 0; n--) { ni = ni->prev; if (ni == NULL) return; } ShowNewsMessage(ni); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_MH_BACKGROUND); } }; const int MessageHistoryWindow::top_spacing = WD_FRAMERECT_TOP + 4; const int MessageHistoryWindow::bottom_spacing = WD_FRAMERECT_BOTTOM; static const NWidgetPart _nested_message_history[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_BROWN), NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_MESSAGE_HISTORY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_BROWN), NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), NWidget(WWT_STICKYBOX, COLOUR_BROWN), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN, WID_MH_BACKGROUND), SetMinimalSize(200, 125), SetDataTip(0x0, STR_MESSAGE_HISTORY_TOOLTIP), SetResize(1, 12), SetScrollbar(WID_MH_SCROLLBAR), EndContainer(), NWidget(NWID_VERTICAL), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_MH_SCROLLBAR), NWidget(WWT_RESIZEBOX, COLOUR_BROWN), EndContainer(), EndContainer(), }; static WindowDesc _message_history_desc( WDP_AUTO, "list_news", 400, 140, WC_MESSAGE_HISTORY, WC_NONE, 0, _nested_message_history, lengthof(_nested_message_history) ); /** Display window with news messages history */ void ShowMessageHistory() { DeleteWindowById(WC_MESSAGE_HISTORY, 0); new MessageHistoryWindow(&_message_history_desc); } openttd-1.5.3/src/newgrf_station.h0000644000000000000000000001757312627373435015715 0ustar rootroot/* $Id: newgrf_station.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 newgrf_station.h Header file for NewGRF stations */ #ifndef NEWGRF_STATION_H #define NEWGRF_STATION_H #include "newgrf_animation_type.h" #include "newgrf_callbacks.h" #include "newgrf_class.h" #include "newgrf_commons.h" #include "cargo_type.h" #include "station_type.h" #include "rail_type.h" #include "newgrf_spritegroup.h" #include "newgrf_town.h" /** Scope resolver for stations. */ struct StationScopeResolver : public ScopeResolver { TileIndex tile; ///< %Tile of the station. struct BaseStation *st; ///< Instance of the station. const struct StationSpec *statspec; ///< Station (type) specification. CargoID cargo_type; ///< Type of cargo of the station. Axis axis; ///< Station axis, used only for the slope check callback. StationScopeResolver(ResolverObject &ro, const StationSpec *statspec, BaseStation *st, TileIndex tile); /* virtual */ uint32 GetRandomBits() const; /* virtual */ uint32 GetTriggers() const; /* virtual */ void SetTriggers(int triggers) const; /* virtual */ uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; }; /** Station resolver. */ struct StationResolverObject : public ResolverObject { StationScopeResolver station_scope; ///< The station scope resolver. TownScopeResolver *town_scope; ///< The town scope resolver (created on the first call). StationResolverObject(const StationSpec *statspec, BaseStation *st, TileIndex tile, CallbackID callback = CBID_NO_CALLBACK, uint32 callback_param1 = 0, uint32 callback_param2 = 0); ~StationResolverObject(); TownScopeResolver *GetTown(); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &this->station_scope; case VSG_SCOPE_PARENT: { TownScopeResolver *tsr = this->GetTown(); if (tsr != NULL) return tsr; /* FALL-THROUGH */ } default: return ResolverObject::GetScope(scope, relative); } } /* virtual */ const SpriteGroup *ResolveReal(const RealSpriteGroup *group) const; }; enum StationClassID { STAT_CLASS_BEGIN = 0, ///< the lowest valid value STAT_CLASS_DFLT = 0, ///< Default station class. STAT_CLASS_WAYP, ///< Waypoint class. STAT_CLASS_MAX = 256, ///< Maximum number of classes. }; typedef SimpleTinyEnumT StationClassIDByte; template <> struct EnumPropsT : MakeEnumPropsT {}; /** Allow incrementing of StationClassID variables */ DECLARE_POSTFIX_INCREMENT(StationClassID) enum StationSpecFlags { SSF_SEPARATE_GROUND, ///< Use different sprite set for ground sprites. SSF_DIV_BY_STATION_SIZE, ///< Divide cargo amount by station size. SSF_CB141_RANDOM_BITS, ///< Callback 141 needs random bits. SSF_CUSTOM_FOUNDATIONS, ///< Draw custom foundations. SSF_EXTENDED_FOUNDATIONS, ///< Extended foundation block instead of simple. }; /** Randomisation triggers for stations */ enum StationRandomTrigger { SRT_NEW_CARGO, ///< Trigger station on new cargo arrival. SRT_CARGO_TAKEN, ///< Trigger station when cargo is completely taken. SRT_TRAIN_ARRIVES, ///< Trigger platform when train arrives. SRT_TRAIN_DEPARTS, ///< Trigger platform when train leaves. SRT_TRAIN_LOADS, ///< Trigger platform when train loads/unloads. SRT_PATH_RESERVATION, ///< Trigger platform when train reserves path. }; /* Station layout for given dimensions - it is a two-dimensional array * where index is computed as (x * platforms) + platform. */ typedef byte *StationLayout; /** Station specification. */ struct StationSpec { /** * Properties related the the grf file. * NUM_CARGO real cargo plus three pseudo cargo sprite groups. * Used for obtaining the sprite offset of custom sprites, and for * evaluating callbacks. */ GRFFilePropsBase grf_prop; StationClassID cls_id; ///< The class to which this spec belongs. StringID name; ///< Name of this station. /** * Bitmask of number of platforms available for the station. * 0..6 correspond to 1..7, while bit 7 corresponds to >7 platforms. */ byte disallowed_platforms; /** * Bitmask of platform lengths available for the station. * 0..6 correspond to 1..7, while bit 7 corresponds to >7 tiles long. */ byte disallowed_lengths; /** * Number of tile layouts. * A minimum of 8 is required is required for stations. * 0-1 = plain platform * 2-3 = platform with building * 4-5 = platform with roof, left side * 6-7 = platform with roof, right side */ uint tiles; NewGRFSpriteLayout *renderdata; ///< Array of tile layouts. /** * Cargo threshold for choosing between little and lots of cargo * @note little/lots are equivalent to the moving/loading states for vehicles */ uint16 cargo_threshold; uint32 cargo_triggers; ///< Bitmask of cargo types which cause trigger re-randomizing byte callback_mask; ///< Bitmask of station callbacks that have to be called byte flags; ///< Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size byte pylons; ///< Bitmask of base tiles (0 - 7) which should contain elrail pylons byte wires; ///< Bitmask of base tiles (0 - 7) which should contain elrail wires byte blocked; ///< Bitmask of base tiles (0 - 7) which are blocked to trains AnimationInfo animation; byte lengths; byte *platforms; StationLayout **layouts; bool copied_layouts; }; /** Struct containing information relating to station classes. */ typedef NewGRFClass StationClass; const StationSpec *GetStationSpec(TileIndex t); /* Evaluate a tile's position within a station, and return the result a bitstuffed format. */ uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, int y, bool centred); SpriteID GetCustomStationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint32 var10 = 0); SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, BaseStation *st, TileIndex tile, uint layout, uint edge_info); uint16 GetStationCallback(CallbackID callback, uint32 param1, uint32 param2, const StationSpec *statspec, BaseStation *st, TileIndex tile); CommandCost PerformStationTileSlopeCheck(TileIndex north_tile, TileIndex cur_tile, const StationSpec *statspec, Axis axis, byte plat_len, byte numtracks); /* Allocate a StationSpec to a Station. This is called once per build operation. */ int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec); /* Deallocate a StationSpec from a Station. Called when removing a single station tile. */ void DeallocateSpecFromStation(BaseStation *st, byte specindex); /* Draw representation of a station tile for GUI purposes. */ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station); void AnimateStationTile(TileIndex tile); void TriggerStationAnimation(BaseStation *st, TileIndex tile, StationAnimationTrigger trigger, CargoID cargo_type = CT_INVALID); void TriggerStationRandomisation(Station *st, TileIndex tile, StationRandomTrigger trigger, CargoID cargo_type = CT_INVALID); void StationUpdateCachedTriggers(BaseStation *st); #endif /* NEWGRF_STATION_H */ openttd-1.5.3/src/livery.h0000644000000000000000000000436412627373433014166 0ustar rootroot/* $Id: livery.h 22411 2011-05-02 17:42:12Z rubidium $ */ /* * 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 livery.h Functions/types related to livery colours. */ #ifndef LIVERY_H #define LIVERY_H #include "company_type.h" static const byte LIT_NONE = 0; ///< Don't show the liveries at all static const byte LIT_COMPANY = 1; ///< Show the liveries of your own company static const byte LIT_ALL = 2; ///< Show the liveries of all companies /** List of different livery schemes. */ enum LiveryScheme { LS_BEGIN = 0, LS_DEFAULT = 0, /* Rail vehicles */ LS_STEAM, LS_DIESEL, LS_ELECTRIC, LS_MONORAIL, LS_MAGLEV, LS_DMU, LS_EMU, LS_PASSENGER_WAGON_STEAM, LS_PASSENGER_WAGON_DIESEL, LS_PASSENGER_WAGON_ELECTRIC, LS_PASSENGER_WAGON_MONORAIL, LS_PASSENGER_WAGON_MAGLEV, LS_FREIGHT_WAGON, /* Road vehicles */ LS_BUS, LS_TRUCK, /* Ships */ LS_PASSENGER_SHIP, LS_FREIGHT_SHIP, /* Aircraft */ LS_HELICOPTER, LS_SMALL_PLANE, LS_LARGE_PLANE, /* Trams (appear on Road Vehicles tab) */ LS_PASSENGER_TRAM, LS_FREIGHT_TRAM, LS_END }; DECLARE_POSTFIX_INCREMENT(LiveryScheme) /** Helper information for extract tool. */ template <> struct EnumPropsT : MakeEnumPropsT {}; /** List of different livery classes, used only by the livery GUI. */ enum LiveryClass { LC_OTHER, LC_RAIL, LC_ROAD, LC_SHIP, LC_AIRCRAFT, LC_END }; /** Information about a particular livery. */ struct Livery { bool in_use; ///< Set if this livery should be used instead of the default livery. byte colour1; ///< First colour, for all vehicles. byte colour2; ///< Second colour, for vehicles with 2CC support. }; void ResetCompanyLivery(Company *c); #endif /* LIVERY_H */ openttd-1.5.3/src/tree_gui.cpp0000644000000000000000000002336312627373441015011 0ustar rootroot/* $Id: tree_gui.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tree_gui.cpp GUIs for building trees. */ #include "stdafx.h" #include "window_gui.h" #include "gfx_func.h" #include "tilehighlight_func.h" #include "company_func.h" #include "company_base.h" #include "command_func.h" #include "sound_func.h" #include "tree_map.h" #include "widgets/tree_widget.h" #include "table/sprites.h" #include "table/strings.h" #include "table/tree_land.h" #include "safeguards.h" void PlaceTreesRandomly(); /** Tree Sprites with their palettes */ const PalSpriteID tree_sprites[] = { { 1621, PAL_NONE }, { 1587, PAL_NONE }, { 1656, PAL_NONE }, { 1579, PAL_NONE }, { 1607, PAL_NONE }, { 1593, PAL_NONE }, { 1614, PAL_NONE }, { 1586, PAL_NONE }, { 1663, PAL_NONE }, { 1677, PAL_NONE }, { 1691, PAL_NONE }, { 1705, PAL_NONE }, { 1711, PAL_NONE }, { 1746, PAL_NONE }, { 1753, PAL_NONE }, { 1732, PAL_NONE }, { 1739, PAL_NONE }, { 1718, PAL_NONE }, { 1725, PAL_NONE }, { 1760, PAL_NONE }, { 1838, PAL_NONE }, { 1844, PAL_NONE }, { 1866, PAL_NONE }, { 1871, PAL_NONE }, { 1899, PAL_NONE }, { 1935, PAL_NONE }, { 1928, PAL_NONE }, { 1915, PAL_NONE }, { 1887, PAL_NONE }, { 1908, PAL_NONE }, { 1824, PAL_NONE }, { 1943, PAL_NONE }, { 1950, PAL_NONE }, { 1957, PALETTE_TO_GREEN }, { 1964, PALETTE_TO_RED }, { 1971, PAL_NONE }, { 1978, PAL_NONE }, { 1985, PALETTE_TO_RED, }, { 1992, PALETTE_TO_PALE_GREEN }, { 1999, PALETTE_TO_YELLOW }, { 2006, PALETTE_TO_RED } }; /** * The build trees window. */ class BuildTreesWindow : public Window { uint16 base; ///< Base tree number used for drawing the window. uint16 count; ///< Number of different trees available. TreeType tree_to_plant; ///< Tree number to plant, \c TREE_INVALID for a random tree. public: BuildTreesWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); ResetObjectToPlace(); } /** * Calculate the maximum size of all tree sprites * @return Dimension of the largest tree sprite */ Dimension GetMaxTreeSpriteSize() { Dimension size, this_size; Point offset; /* Avoid to use it uninitialized */ size.width = 32; // default width - 2 size.height = 39; // default height - 7 offset.x = 0; offset.y = 0; for (int i = this->base; i < this->base + this->count; i++) { if (i >= (int)lengthof(tree_sprites)) return size; this_size = GetSpriteSize(tree_sprites[i].sprite, &offset); size.width = max(size.width, 2 * max(this_size.width, -offset.x)); size.height = max(size.height, max(this_size.height, -offset.y)); } return size; } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget >= WID_BT_TYPE_11 && widget <= WID_BT_TYPE_34) { Dimension d = GetMaxTreeSpriteSize(); /* Allow some pixels extra width and height */ size->width = d.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; size->height = d.height + WD_FRAMERECT_RIGHT + WD_FRAMERECT_BOTTOM + 7; // we need some more space return; } if (widget != WID_BT_MANY_RANDOM) return; if (_game_mode != GM_EDITOR) { size->width = 0; size->height = 0; } } virtual void DrawWidget(const Rect &r, int widget) const { if (widget < WID_BT_TYPE_11 || widget > WID_BT_TYPE_34 || widget - WID_BT_TYPE_11 >= this->count) return; int i = this->base + widget - WID_BT_TYPE_11; /* Trees "grow" in the centre on the bottom line of the buttons */ DrawSprite(tree_sprites[i].sprite, tree_sprites[i].pal, (r.left + r.right) / 2 + WD_FRAMERECT_LEFT, r.bottom - 7); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_BT_TYPE_11: case WID_BT_TYPE_12: case WID_BT_TYPE_13: case WID_BT_TYPE_14: case WID_BT_TYPE_21: case WID_BT_TYPE_22: case WID_BT_TYPE_23: case WID_BT_TYPE_24: case WID_BT_TYPE_31: case WID_BT_TYPE_32: case WID_BT_TYPE_33: case WID_BT_TYPE_34: if (widget - WID_BT_TYPE_11 >= this->count) break; if (HandlePlacePushButton(this, widget, SPR_CURSOR_TREE, HT_RECT)) { this->tree_to_plant = (TreeType)(this->base + widget - WID_BT_TYPE_11); } break; case WID_BT_TYPE_RANDOM: // tree of random type. if (HandlePlacePushButton(this, WID_BT_TYPE_RANDOM, SPR_CURSOR_TREE, HT_RECT)) { this->tree_to_plant = TREE_INVALID; } break; case WID_BT_MANY_RANDOM: // place trees randomly over the landscape if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP); PlaceTreesRandomly(); MarkWholeScreenDirty(); break; } } virtual void OnPlaceObject(Point pt, TileIndex tile) { VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_PLANT_TREES); } 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 && select_proc == DDSP_PLANT_TREES) { DoCommandP(end_tile, this->tree_to_plant, start_tile, CMD_PLANT_TREE | CMD_MSG(STR_ERROR_CAN_T_PLANT_TREE_HERE)); } } /** * Initialize the window data */ virtual void OnInit() { this->base = _tree_base_by_landscape[_settings_game.game_creation.landscape]; this->count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; } virtual void OnPlaceObjectAbort() { this->RaiseButtons(); } }; static const NWidgetPart _nested_build_trees_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_PLANT_TREE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(2, 0), NWidget(NWID_VERTICAL), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_11), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_12), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_13), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_14), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_21), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_22), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_23), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_24), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_31), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_32), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_33), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_34), SetMinimalSize(34, 46), SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BT_TYPE_RANDOM), SetMinimalSize(139, 12), SetDataTip(STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TOOLTIP), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BT_MANY_RANDOM), SetMinimalSize(139, 12), SetDataTip(STR_TREES_RANDOM_TREES_BUTTON, STR_TREES_RANDOM_TREES_TOOLTIP), NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(2, 0), EndContainer(), EndContainer(), }; static WindowDesc _build_trees_desc( WDP_AUTO, "build_tree", 0, 0, WC_BUILD_TREES, WC_NONE, WDF_CONSTRUCTION, _nested_build_trees_widgets, lengthof(_nested_build_trees_widgets) ); void ShowBuildTreesToolbar() { if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return; AllocateWindowDescFront(&_build_trees_desc, 0); } openttd-1.5.3/src/newgrf_town.h0000644000000000000000000000362712627373435015216 0ustar rootroot/* $Id: newgrf_town.h 26085 2013-11-24 14:41:19Z frosch $ */ /* * 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 newgrf_town.h Functions to handle the town part of NewGRF towns. */ #ifndef NEWGRF_TOWN_H #define NEWGRF_TOWN_H #include "town_type.h" #include "newgrf_spritegroup.h" /** * Scope resolver for a town. * @note Currently there is no direct town resolver; we only need to get town * variable results from inside stations, house tiles and industries, * and to check the town's persistent storage. */ struct TownScopeResolver : public ScopeResolver { Town *t; ///< %Town of the scope. bool readonly; ///< When set, persistent storage of the town is read-only, TownScopeResolver(ResolverObject &ro, Town *t, bool readonly); virtual uint32 GetVariable(byte variable, uint32 parameter, bool *available) const; virtual void StorePSA(uint reg, int32 value); }; /** Resolver of town properties. */ struct TownResolverObject : public ResolverObject { TownScopeResolver town_scope; ///< Scope resolver specific for towns. TownResolverObject(const struct GRFFile *grffile, Town *t, bool readonly); /* virtual */ ScopeResolver *GetScope(VarSpriteGroupScope scope = VSG_SCOPE_SELF, byte relative = 0) { switch (scope) { case VSG_SCOPE_SELF: return &town_scope; default: return ResolverObject::GetScope(scope, relative); } } }; #endif /* NEWGRF_TOWN_H */ openttd-1.5.3/src/rail.cpp0000644000000000000000000003107312627373445014136 0ustar rootroot/* $Id: rail.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 rail.cpp Implementation of rail specific functions. */ #include "stdafx.h" #include "station_map.h" #include "tunnelbridge_map.h" #include "date_func.h" #include "company_func.h" #include "company_base.h" #include "engine_base.h" #include "safeguards.h" /* XXX: Below 3 tables store duplicate data. Maybe remove some? */ /* Maps a trackdir to the bit that stores its status in the map arrays, in the * direction along with the trackdir */ extern const byte _signal_along_trackdir[TRACKDIR_END] = { 0x8, 0x8, 0x8, 0x2, 0x4, 0x1, 0, 0, 0x4, 0x4, 0x4, 0x1, 0x8, 0x2 }; /* Maps a trackdir to the bit that stores its status in the map arrays, in the * direction against the trackdir */ extern const byte _signal_against_trackdir[TRACKDIR_END] = { 0x4, 0x4, 0x4, 0x1, 0x8, 0x2, 0, 0, 0x8, 0x8, 0x8, 0x2, 0x4, 0x1 }; /* Maps a Track to the bits that store the status of the two signals that can * be present on the given track */ extern const byte _signal_on_track[] = { 0xC, 0xC, 0xC, 0x3, 0xC, 0x3 }; /* Maps a diagonal direction to the all trackdirs that are connected to any * track entering in this direction (including those making 90 degree turns) */ extern const TrackdirBits _exitdir_reaches_trackdirs[] = { TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N, // DIAGDIR_NE TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_E, // DIAGDIR_SE TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S, // DIAGDIR_SW TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W // DIAGDIR_NW }; extern const Trackdir _next_trackdir[TRACKDIR_END] = { TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_LOWER_E, TRACKDIR_UPPER_E, TRACKDIR_RIGHT_S, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_LOWER_W, TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N }; /* Maps a trackdir to all trackdirs that make 90 deg turns with it. */ extern const TrackdirBits _track_crosses_trackdirs[TRACKDIR_END] = { TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_Y_NW, // TRACK_X TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW, // TRACK_Y TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_LEFT_S, // TRACK_UPPER TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_LEFT_S, // TRACK_LOWER TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E, // TRACK_LEFT TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_LOWER_E // TRACK_RIGHT }; /* Maps a track to all tracks that make 90 deg turns with it. */ extern const TrackBits _track_crosses_tracks[] = { TRACK_BIT_Y, // TRACK_X TRACK_BIT_X, // TRACK_Y TRACK_BIT_VERT, // TRACK_UPPER TRACK_BIT_VERT, // TRACK_LOWER TRACK_BIT_HORZ, // TRACK_LEFT TRACK_BIT_HORZ // TRACK_RIGHT }; /* Maps a trackdir to the (4-way) direction the tile is exited when following * that trackdir */ extern const DiagDirection _trackdir_to_exitdir[TRACKDIR_END] = { DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_NE, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, }; extern const Trackdir _track_exitdir_to_trackdir[][DIAGDIR_END] = { {TRACKDIR_X_NE, INVALID_TRACKDIR, TRACKDIR_X_SW, INVALID_TRACKDIR}, {INVALID_TRACKDIR, TRACKDIR_Y_SE, INVALID_TRACKDIR, TRACKDIR_Y_NW}, {TRACKDIR_UPPER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_UPPER_W}, {INVALID_TRACKDIR, TRACKDIR_LOWER_E, TRACKDIR_LOWER_W, INVALID_TRACKDIR}, {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LEFT_S, TRACKDIR_LEFT_N}, {TRACKDIR_RIGHT_N, TRACKDIR_RIGHT_S, INVALID_TRACKDIR, INVALID_TRACKDIR} }; extern const Trackdir _track_enterdir_to_trackdir[][DIAGDIR_END] = { {TRACKDIR_X_NE, INVALID_TRACKDIR, TRACKDIR_X_SW, INVALID_TRACKDIR}, {INVALID_TRACKDIR, TRACKDIR_Y_SE, INVALID_TRACKDIR, TRACKDIR_Y_NW}, {INVALID_TRACKDIR, TRACKDIR_UPPER_E, TRACKDIR_UPPER_W, INVALID_TRACKDIR}, {TRACKDIR_LOWER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_W}, {TRACKDIR_LEFT_N, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR}, {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_RIGHT_S, TRACKDIR_RIGHT_N} }; extern const Trackdir _track_direction_to_trackdir[][DIR_END] = { {INVALID_TRACKDIR, TRACKDIR_X_NE, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_X_SW, INVALID_TRACKDIR, INVALID_TRACKDIR}, {INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_Y_SE, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_Y_NW}, {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_UPPER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_UPPER_W, INVALID_TRACKDIR}, {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_W, INVALID_TRACKDIR}, {TRACKDIR_LEFT_N, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LEFT_S, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR}, {TRACKDIR_RIGHT_N, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_RIGHT_S, INVALID_TRACKDIR, INVALID_TRACKDIR, INVALID_TRACKDIR} }; extern const Trackdir _dir_to_diag_trackdir[] = { TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW, }; extern const TrackBits _corner_to_trackbits[] = { TRACK_BIT_LEFT, TRACK_BIT_LOWER, TRACK_BIT_RIGHT, TRACK_BIT_UPPER, }; extern const TrackdirBits _uphill_trackdirs[] = { TRACKDIR_BIT_NONE , ///< 0 SLOPE_FLAT TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW, ///< 1 SLOPE_W -> inclined for diagonal track TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_SE, ///< 2 SLOPE_S -> inclined for diagonal track TRACKDIR_BIT_X_SW , ///< 3 SLOPE_SW TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE, ///< 4 SLOPE_E -> inclined for diagonal track TRACKDIR_BIT_NONE , ///< 5 SLOPE_EW TRACKDIR_BIT_Y_SE , ///< 6 SLOPE_SE TRACKDIR_BIT_NONE , ///< 7 SLOPE_WSE -> leveled TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_NW, ///< 8 SLOPE_N -> inclined for diagonal track TRACKDIR_BIT_Y_NW , ///< 9 SLOPE_NW TRACKDIR_BIT_NONE , ///< 10 SLOPE_NS TRACKDIR_BIT_NONE , ///< 11 SLOPE_NWS -> leveled TRACKDIR_BIT_X_NE , ///< 12 SLOPE_NE TRACKDIR_BIT_NONE , ///< 13 SLOPE_ENW -> leveled TRACKDIR_BIT_NONE , ///< 14 SLOPE_SEN -> leveled TRACKDIR_BIT_NONE , ///< 15 invalid TRACKDIR_BIT_NONE , ///< 16 invalid TRACKDIR_BIT_NONE , ///< 17 invalid TRACKDIR_BIT_NONE , ///< 18 invalid TRACKDIR_BIT_NONE , ///< 19 invalid TRACKDIR_BIT_NONE , ///< 20 invalid TRACKDIR_BIT_NONE , ///< 21 invalid TRACKDIR_BIT_NONE , ///< 22 invalid TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_SE, ///< 23 SLOPE_STEEP_S -> inclined for diagonal track TRACKDIR_BIT_NONE , ///< 24 invalid TRACKDIR_BIT_NONE , ///< 25 invalid TRACKDIR_BIT_NONE , ///< 26 invalid TRACKDIR_BIT_X_SW | TRACKDIR_BIT_Y_NW, ///< 27 SLOPE_STEEP_W -> inclined for diagonal track TRACKDIR_BIT_NONE , ///< 28 invalid TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_NW, ///< 29 SLOPE_STEEP_N -> inclined for diagonal track TRACKDIR_BIT_X_NE | TRACKDIR_BIT_Y_SE, ///< 30 SLOPE_STEEP_E -> inclined for diagonal track }; /** * Return the rail type of tile, or INVALID_RAILTYPE if this is no rail tile. */ RailType GetTileRailType(TileIndex tile) { switch (GetTileType(tile)) { case MP_RAILWAY: return GetRailType(tile); case MP_ROAD: /* rail/road crossing */ if (IsLevelCrossing(tile)) return GetRailType(tile); break; case MP_STATION: if (HasStationRail(tile)) return GetRailType(tile); break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) return GetRailType(tile); break; default: break; } return INVALID_RAILTYPE; } /** * Finds out if a company has a certain railtype available * @param company the company in question * @param railtype requested RailType * @return true if company has requested RailType available */ bool HasRailtypeAvail(const CompanyID company, const RailType railtype) { return HasBit(Company::Get(company)->avail_railtypes, railtype); } /** * Validate functions for rail building. * @param rail the railtype to check. * @return true if the current company may build the rail. */ bool ValParamRailtype(const RailType rail) { return rail < RAILTYPE_END && HasRailtypeAvail(_current_company, rail); } /** * Returns the "best" railtype a company can build. * As the AI doesn't know what the BEST one is, we have our own priority list * here. When adding new railtypes, modify this function * @param company the company "in action" * @return The "best" railtype a company has available */ RailType GetBestRailtype(const CompanyID company) { if (HasRailtypeAvail(company, RAILTYPE_MAGLEV)) return RAILTYPE_MAGLEV; if (HasRailtypeAvail(company, RAILTYPE_MONO)) return RAILTYPE_MONO; if (HasRailtypeAvail(company, RAILTYPE_ELECTRIC)) return RAILTYPE_ELECTRIC; return RAILTYPE_RAIL; } /** * Add the rail types that are to be introduced at the given date. * @param current The currently available railtypes. * @param date The date for the introduction comparisons. * @return The rail types that should be available when date * introduced rail types are taken into account as well. */ RailTypes AddDateIntroducedRailTypes(RailTypes current, Date date) { RailTypes rts = current; for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { const RailtypeInfo *rti = GetRailTypeInfo(rt); /* Unused rail type. */ if (rti->label == 0) continue; /* Not date introduced. */ if (!IsInsideMM(rti->introduction_date, 0, MAX_DAY)) continue; /* Not yet introduced at this date. */ if (rti->introduction_date > date) continue; /* Have we introduced all required railtypes? */ RailTypes required = rti->introduction_required_railtypes; if ((rts & required) != required) continue; rts |= rti->introduces_railtypes; } /* When we added railtypes we need to run this method again; the added * railtypes might enable more rail types to become introduced. */ return rts == current ? rts : AddDateIntroducedRailTypes(rts, date); } /** * Get the rail types the given company can build. * @param c the company to get the rail types for. * @return the rail types. */ RailTypes GetCompanyRailtypes(CompanyID company) { RailTypes rts = RAILTYPES_NONE; Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) { const EngineInfo *ei = &e->info; if (HasBit(ei->climates, _settings_game.game_creation.landscape) && (HasBit(e->company_avail, company) || _date >= e->intro_date + DAYS_IN_YEAR)) { const RailVehicleInfo *rvi = &e->u.rail; if (rvi->railveh_type != RAILVEH_WAGON) { assert(rvi->railtype < RAILTYPE_END); rts |= GetRailTypeInfo(rvi->railtype)->introduces_railtypes; } } } return AddDateIntroducedRailTypes(rts, _date); } /** * Get the rail type for a given label. * @param label the railtype label. * @param allow_alternate_labels Search in the alternate label lists as well. * @return the railtype. */ RailType GetRailTypeByLabel(RailTypeLabel label, bool allow_alternate_labels) { /* Loop through each rail type until the label is found */ for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) { const RailtypeInfo *rti = GetRailTypeInfo(r); if (rti->label == label) return r; } if (allow_alternate_labels) { /* Test if any rail type defines the label as an alternate. */ for (RailType r = RAILTYPE_BEGIN; r != RAILTYPE_END; r++) { const RailtypeInfo *rti = GetRailTypeInfo(r); if (rti->alternate_labels.Contains(label)) return r; } } /* No matching label was found, so it is invalid */ return INVALID_RAILTYPE; } openttd-1.5.3/src/viewport_sprite_sorter_sse4.cpp0000644000000000000000000001036012627373442021001 0ustar rootroot/* $Id: viewport_sprite_sorter_sse4.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 viewport_sprite_sorter_sse.cpp Sprite sorter that uses SSE4.1. */ #ifdef WITH_SSE #include "stdafx.h" #include "cpu.h" #include "smmintrin.h" #include "viewport_sprite_sorter.h" #include "safeguards.h" #ifdef _SQ64 assert_compile((sizeof(ParentSpriteToDraw) % 16) == 0); #define LOAD_128 _mm_load_si128 #else #define LOAD_128 _mm_loadu_si128 #endif /** Sort parent sprites pointer array using SSE4.1 optimizations. */ void ViewportSortParentSpritesSSE41(ParentSpriteToSortVector *psdv) { const __m128i mask_ptest = _mm_setr_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0); ParentSpriteToDraw ** const psdvend = psdv->End(); ParentSpriteToDraw **psd = psdv->Begin(); while (psd != psdvend) { ParentSpriteToDraw * const ps = *psd; if (ps->comparison_done) { psd++; continue; } ps->comparison_done = true; for (ParentSpriteToDraw **psd2 = psd + 1; psd2 != psdvend; psd2++) { ParentSpriteToDraw * const ps2 = *psd2; if (ps2->comparison_done) continue; /* * Decide which comparator to use, based on whether the bounding boxes overlap * * Original code: * if (ps->xmax >= ps2->xmin && ps->xmin <= ps2->xmax && // overlap in X? * ps->ymax >= ps2->ymin && ps->ymin <= ps2->ymax && // overlap in Y? * ps->zmax >= ps2->zmin && ps->zmin <= ps2->zmax) { // overlap in Z? * * Above conditions are equivalent to: * 1/ !( (ps->xmax >= ps2->xmin) && (ps->ymax >= ps2->ymin) && (ps->zmax >= ps2->zmin) && (ps->xmin <= ps2->xmax) && (ps->ymin <= ps2->ymax) && (ps->zmin <= ps2->zmax) ) * 2/ !( (ps->xmax >= ps2->xmin) && (ps->ymax >= ps2->ymin) && (ps->zmax >= ps2->zmin) && (ps2->xmax >= ps->xmin) && (ps2->ymax >= ps->ymin) && (ps2->zmax >= ps->zmin) ) * 3/ !( ( (ps->xmax >= ps2->xmin) && (ps->ymax >= ps2->ymin) && (ps->zmax >= ps2->zmin) ) && ( (ps2->xmax >= ps->xmin) && (ps2->ymax >= ps->ymin) && (ps2->zmax >= ps->zmin) ) ) * 4/ !( !( (ps->xmax < ps2->xmin) || (ps->ymax < ps2->ymin) || (ps->zmax < ps2->zmin) ) && !( (ps2->xmax < ps->xmin) || (ps2->ymax < ps->ymin) || (ps2->zmax < ps->zmin) ) ) * 5/ PTEST <---------------------------------- rslt1 ----------------------------------> <------------------------------ rslt2 --------------------------------------> */ __m128i ps1_max = LOAD_128((__m128i*) &ps->xmax); __m128i ps2_min = LOAD_128((__m128i*) &ps2->xmin); __m128i rslt1 = _mm_cmplt_epi32(ps1_max, ps2_min); if (!_mm_testz_si128(mask_ptest, rslt1)) continue; __m128i ps1_min = LOAD_128((__m128i*) &ps->xmin); __m128i ps2_max = LOAD_128((__m128i*) &ps2->xmax); __m128i rslt2 = _mm_cmplt_epi32(ps2_max, ps1_min); if (_mm_testz_si128(mask_ptest, rslt2)) { /* Use X+Y+Z as the sorting order, so sprites closer to the bottom of * the screen and with higher Z elevation, are drawn in front. * Here X,Y,Z are the coordinates of the "center of mass" of the sprite, * i.e. X=(left+right)/2, etc. * However, since we only care about order, don't actually divide / 2 */ if (ps->xmin + ps->xmax + ps->ymin + ps->ymax + ps->zmin + ps->zmax <= ps2->xmin + ps2->xmax + ps2->ymin + ps2->ymax + ps2->zmin + ps2->zmax) { continue; } } /* Move ps2 in front of ps */ ParentSpriteToDraw * const temp = ps2; for (ParentSpriteToDraw **psd3 = psd2; psd3 > psd; psd3--) { *psd3 = *(psd3 - 1); } *psd = temp; } } } /** * Check whether the current CPU supports SSE 4.1. * @return True iff the CPU supports SSE 4.1. */ bool ViewportSortParentSpritesSSE41Checker() { return HasCPUIDFlag(1, 2, 19); } #endif /* WITH_SSE */ openttd-1.5.3/src/textbuf.cpp0000644000000000000000000003343012627373441014663 0ustar rootroot/* $Id: textbuf.cpp 26758 2014-08-24 10:34:43Z michi_cc $ */ /* * 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 textbuf.cpp Textbuffer handling. */ #include "stdafx.h" #include #include "textbuf_type.h" #include "string_func.h" #include "strings_func.h" #include "gfx_type.h" #include "gfx_func.h" #include "window_func.h" #include "core/alloc_func.hpp" #include "safeguards.h" /** * Try to retrieve the current clipboard contents. * * @note OS-specific function. * @param buffer Clipboard content. * @param last The pointer to the last element of the destination buffer * @return True if some text could be retrieved. */ bool GetClipboardContents(char *buffer, const char *last); int _caret_timer; /** * Checks if it is possible to delete a character. * @param backspace if set, delete the character before the caret, * otherwise, delete the character after it. * @return true if a character can be deleted in the given direction. */ bool Textbuf::CanDelChar(bool backspace) { return backspace ? this->caretpos != 0 : this->caretpos < this->bytes - 1; } /** * Delete a character from a textbuffer, either with 'Delete' or 'Backspace' * The character is delete from the position the caret is at * @param keycode Type of deletion, either WKC_BACKSPACE or WKC_DELETE * @return Return true on successful change of Textbuf, or false otherwise */ bool Textbuf::DeleteChar(uint16 keycode) { bool word = (keycode & WKC_CTRL) != 0; keycode &= ~WKC_SPECIAL_KEYS; if (keycode != WKC_BACKSPACE && keycode != WKC_DELETE) return false; bool backspace = keycode == WKC_BACKSPACE; if (!CanDelChar(backspace)) return false; char *s = this->buf + this->caretpos; uint16 len = 0; if (word) { /* Delete a complete word. */ if (backspace) { /* Delete whitespace and word in front of the caret. */ len = this->caretpos - (uint16)this->char_iter->Prev(StringIterator::ITER_WORD); s -= len; } else { /* Delete word and following whitespace following the caret. */ len = (uint16)this->char_iter->Next(StringIterator::ITER_WORD) - this->caretpos; } /* Update character count. */ for (const char *ss = s; ss < s + len; Utf8Consume(&ss)) { this->chars--; } } else { /* Delete a single character. */ if (backspace) { /* Delete the last code point in front of the caret. */ s = Utf8PrevChar(s); WChar c; len = (uint16)Utf8Decode(&c, s); this->chars--; } else { /* Delete the complete character following the caret. */ len = (uint16)this->char_iter->Next(StringIterator::ITER_CHARACTER) - this->caretpos; /* Update character count. */ for (const char *ss = s; ss < s + len; Utf8Consume(&ss)) { this->chars--; } } } /* Move the remaining characters over the marker */ memmove(s, s + len, this->bytes - (s - this->buf) - len); this->bytes -= len; if (backspace) this->caretpos -= len; this->UpdateStringIter(); this->UpdateWidth(); this->UpdateCaretPosition(); this->UpdateMarkedText(); return true; } /** * Delete every character in the textbuffer */ void Textbuf::DeleteAll() { memset(this->buf, 0, this->max_bytes); this->bytes = this->chars = 1; this->pixels = this->caretpos = this->caretxoffs = 0; this->markpos = this->markend = this->markxoffs = this->marklength = 0; this->UpdateStringIter(); } /** * Insert a character to a textbuffer. If maxwidth of the Textbuf is zero, * we don't care about the visual-length but only about the physical * length of the string * @param key Character to be inserted * @return Return true on successful change of Textbuf, or false otherwise */ bool Textbuf::InsertChar(WChar key) { uint16 len = (uint16)Utf8CharLen(key); if (this->bytes + len <= this->max_bytes && this->chars + 1 <= this->max_chars) { memmove(this->buf + this->caretpos + len, this->buf + this->caretpos, this->bytes - this->caretpos); Utf8Encode(this->buf + this->caretpos, key); this->chars++; this->bytes += len; this->caretpos += len; this->UpdateStringIter(); this->UpdateWidth(); this->UpdateCaretPosition(); this->UpdateMarkedText(); return true; } return false; } /** * Insert a string into the text buffer. If maxwidth of the Textbuf is zero, * we don't care about the visual-length but only about the physical * length of the string. * @param str String to insert. * @param marked Replace the currently marked text with the new text. * @param caret Move the caret to this point in the insertion string. * @param insert_location Position at which to insert the string. * @param replacement_end Replace all characters from #insert_location up to this location with the new string. * @return True on successful change of Textbuf, or false otherwise. */ bool Textbuf::InsertString(const char *str, bool marked, const char *caret, const char *insert_location, const char *replacement_end) { uint16 insertpos = (marked && this->marklength != 0) ? this->markpos : this->caretpos; if (insert_location != NULL) { insertpos = insert_location - this->buf; if (insertpos > this->bytes) return false; if (replacement_end != NULL) { this->DeleteText(insertpos, replacement_end - this->buf, str == NULL); } } else { if (marked) this->DiscardMarkedText(str == NULL); } if (str == NULL) return false; uint16 bytes = 0, chars = 0; WChar c; for (const char *ptr = str; (c = Utf8Consume(&ptr)) != '\0';) { if (!IsValidChar(c, this->afilter)) break; byte len = Utf8CharLen(c); if (this->bytes + bytes + len > this->max_bytes) break; if (this->chars + chars + 1 > this->max_chars) break; bytes += len; chars++; /* Move caret if needed. */ if (ptr == caret) this->caretpos = insertpos + bytes; } if (bytes == 0) return false; if (marked) { this->markpos = insertpos; this->markend = insertpos + bytes; } memmove(this->buf + insertpos + bytes, this->buf + insertpos, this->bytes - insertpos); memcpy(this->buf + insertpos, str, bytes); this->bytes += bytes; this->chars += chars; if (!marked && caret == NULL) this->caretpos += bytes; assert(this->bytes <= this->max_bytes); assert(this->chars <= this->max_chars); this->buf[this->bytes - 1] = '\0'; // terminating zero this->UpdateStringIter(); this->UpdateWidth(); this->UpdateCaretPosition(); this->UpdateMarkedText(); return true; } /** * Insert a chunk of text from the clipboard onto the textbuffer. Get TEXT clipboard * and append this up to the maximum length (either absolute or screenlength). If maxlength * is zero, we don't care about the screenlength but only about the physical length of the string * @return true on successful change of Textbuf, or false otherwise */ bool Textbuf::InsertClipboard() { char utf8_buf[512]; if (!GetClipboardContents(utf8_buf, lastof(utf8_buf))) return false; return this->InsertString(utf8_buf, false); } /** * Delete a part of the text. * @param from Start of the text to delete. * @param to End of the text to delete. * @param update Set to true if the internal state should be updated. */ void Textbuf::DeleteText(uint16 from, uint16 to, bool update) { uint c = 0; const char *s = this->buf + from; while (s < this->buf + to) { Utf8Consume(&s); c++; } /* Strip marked characters from buffer. */ memmove(this->buf + from, this->buf + to, this->bytes - to); this->bytes -= to - from; this->chars -= c; /* Fixup caret if needed. */ if (this->caretpos > from) { if (this->caretpos <= to) { this->caretpos = from; } else { this->caretpos -= to - from; } } if (update) { this->UpdateStringIter(); this->UpdateCaretPosition(); this->UpdateMarkedText(); } } /** * Discard any marked text. * @param update Set to true if the internal state should be updated. */ void Textbuf::DiscardMarkedText(bool update) { if (this->markend == 0) return; this->DeleteText(this->markpos, this->markend, update); this->markpos = this->markend = this->markxoffs = this->marklength = 0; } /** Update the character iter after the text has changed. */ void Textbuf::UpdateStringIter() { this->char_iter->SetString(this->buf); size_t pos = this->char_iter->SetCurPosition(this->caretpos); this->caretpos = pos == StringIterator::END ? 0 : (uint16)pos; } /** Update pixel width of the text. */ void Textbuf::UpdateWidth() { this->pixels = GetStringBoundingBox(this->buf, FS_NORMAL).width; } /** Update pixel position of the caret. */ void Textbuf::UpdateCaretPosition() { this->caretxoffs = this->chars > 1 ? GetCharPosInString(this->buf, this->buf + this->caretpos, FS_NORMAL).x : 0; } /** Update pixel positions of the marked text area. */ void Textbuf::UpdateMarkedText() { if (this->markend != 0) { this->markxoffs = GetCharPosInString(this->buf, this->buf + this->markpos, FS_NORMAL).x; this->marklength = GetCharPosInString(this->buf, this->buf + this->markend, FS_NORMAL).x - this->markxoffs; } else { this->markxoffs = this->marklength = 0; } } /** * Handle text navigation with arrow keys left/right. * This defines where the caret will blink and the next character interaction will occur * @param keycode Direction in which navigation occurs (WKC_CTRL |) WKC_LEFT, (WKC_CTRL |) WKC_RIGHT, WKC_END, WKC_HOME * @return Return true on successful change of Textbuf, or false otherwise */ bool Textbuf::MovePos(uint16 keycode) { switch (keycode) { case WKC_LEFT: case WKC_CTRL | WKC_LEFT: { if (this->caretpos == 0) break; size_t pos = this->char_iter->Prev(keycode & WKC_CTRL ? StringIterator::ITER_WORD : StringIterator::ITER_CHARACTER); if (pos == StringIterator::END) return true; this->caretpos = (uint16)pos; this->UpdateCaretPosition(); return true; } case WKC_RIGHT: case WKC_CTRL | WKC_RIGHT: { if (this->caretpos >= this->bytes - 1) break; size_t pos = this->char_iter->Next(keycode & WKC_CTRL ? StringIterator::ITER_WORD : StringIterator::ITER_CHARACTER); if (pos == StringIterator::END) return true; this->caretpos = (uint16)pos; this->UpdateCaretPosition(); return true; } case WKC_HOME: this->caretpos = 0; this->char_iter->SetCurPosition(this->caretpos); this->UpdateCaretPosition(); return true; case WKC_END: this->caretpos = this->bytes - 1; this->char_iter->SetCurPosition(this->caretpos); this->UpdateCaretPosition(); return true; default: break; } return false; } /** * Initialize the textbuffer by supplying it the buffer to write into * and the maximum length of this buffer * @param buf the buffer that will be holding the data for input * @param max_bytes maximum size in bytes, including terminating '\0' * @param max_chars maximum size in chars, including terminating '\0' */ Textbuf::Textbuf(uint16 max_bytes, uint16 max_chars) : buf(MallocT(max_bytes)) { assert(max_bytes != 0); assert(max_chars != 0); this->char_iter = StringIterator::Create(); this->afilter = CS_ALPHANUMERAL; this->max_bytes = max_bytes; this->max_chars = max_chars == UINT16_MAX ? max_bytes : max_chars; this->caret = true; this->DeleteAll(); } Textbuf::~Textbuf() { delete this->char_iter; free(this->buf); } /** * Render a string into the textbuffer. * @param string String */ void Textbuf::Assign(StringID string) { GetString(this->buf, string, &this->buf[this->max_bytes - 1]); this->UpdateSize(); } /** * Copy a string into the textbuffer. * @param text Source. */ void Textbuf::Assign(const char *text) { strecpy(this->buf, text, &this->buf[this->max_bytes - 1]); this->UpdateSize(); } /** * Print a formatted string into the textbuffer. */ void Textbuf::Print(const char *format, ...) { va_list va; va_start(va, format); vseprintf(this->buf, &this->buf[this->max_bytes - 1], format, va); va_end(va); this->UpdateSize(); } /** * Update Textbuf type with its actual physical character and screenlength * Get the count of characters in the string as well as the width in pixels. * Useful when copying in a larger amount of text at once */ void Textbuf::UpdateSize() { const char *buf = this->buf; this->chars = this->bytes = 1; // terminating zero WChar c; while ((c = Utf8Consume(&buf)) != '\0') { this->bytes += Utf8CharLen(c); this->chars++; } assert(this->bytes <= this->max_bytes); assert(this->chars <= this->max_chars); this->caretpos = this->bytes - 1; this->UpdateStringIter(); this->UpdateWidth(); this->UpdateMarkedText(); this->UpdateCaretPosition(); } /** * Handle the flashing of the caret. * @return True if the caret state changes. */ bool Textbuf::HandleCaret() { /* caret changed? */ bool b = !!(_caret_timer & 0x20); if (b != this->caret) { this->caret = b; return true; } return false; } HandleKeyPressResult Textbuf::HandleKeyPress(WChar key, uint16 keycode) { bool edited = false; switch (keycode) { case WKC_ESC: return HKPR_CANCEL; case WKC_RETURN: case WKC_NUM_ENTER: return HKPR_CONFIRM; case (WKC_CTRL | 'V'): edited = this->InsertClipboard(); break; case (WKC_CTRL | 'U'): this->DeleteAll(); edited = true; break; case WKC_BACKSPACE: case WKC_DELETE: case WKC_CTRL | WKC_BACKSPACE: case WKC_CTRL | WKC_DELETE: edited = this->DeleteChar(keycode); break; case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME: case WKC_CTRL | WKC_LEFT: case WKC_CTRL | WKC_RIGHT: this->MovePos(keycode); break; default: if (IsValidChar(key, this->afilter)) { edited = this->InsertChar(key); } else { return HKPR_NOT_HANDLED; } break; } return edited ? HKPR_EDITING : HKPR_CURSOR; } openttd-1.5.3/src/aircraft_gui.cpp0000644000000000000000000000766312627373441015652 0ustar rootroot/* $Id: aircraft_gui.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 aircraft_gui.cpp The GUI of aircraft. */ #include "stdafx.h" #include "aircraft.h" #include "vehicle_gui.h" #include "newgrf_engine.h" #include "strings_func.h" #include "vehicle_func.h" #include "window_gui.h" #include "spritecache.h" #include "zoom_func.h" #include "table/strings.h" #include "safeguards.h" /** * Draw the details for the given vehicle at the given position * * @param v current vehicle * @param left The left most coordinate to draw * @param right The right most coordinate to draw * @param y The y coordinate */ void DrawAircraftDetails(const Aircraft *v, int left, int right, int y) { int y_offset = (v->Next()->cargo_cap != 0) ? -(FONT_HEIGHT_NORMAL + 1): 0; Money feeder_share = 0; for (const Aircraft *u = v; u != NULL; u = u->Next()) { if (u->IsNormalAircraft()) { SetDParam(0, u->engine_type); SetDParam(1, u->build_year); SetDParam(2, u->value); DrawString(left, right, y, STR_VEHICLE_INFO_BUILT_VALUE); SetDParam(0, u->cargo_type); SetDParam(1, u->cargo_cap); SetDParam(2, u->Next()->cargo_type); SetDParam(3, u->Next()->cargo_cap); SetDParam(4, GetCargoSubtypeText(u)); DrawString(left, right, y + FONT_HEIGHT_NORMAL, (u->Next()->cargo_cap != 0) ? STR_VEHICLE_INFO_CAPACITY_CAPACITY : STR_VEHICLE_INFO_CAPACITY); } if (u->cargo_cap != 0) { uint cargo_count = u->cargo.StoredCount(); y_offset += FONT_HEIGHT_NORMAL + 1; if (cargo_count != 0) { /* Cargo names (fix pluralness) */ SetDParam(0, u->cargo_type); SetDParam(1, cargo_count); SetDParam(2, u->cargo.Source()); DrawString(left, right, y + 2 * FONT_HEIGHT_NORMAL + 1 + y_offset, STR_VEHICLE_DETAILS_CARGO_FROM); feeder_share += u->cargo.FeederShare(); } } } SetDParam(0, feeder_share); DrawString(left, right, y + 3 * FONT_HEIGHT_NORMAL + 3 + y_offset, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE); } /** * Draws an image of an aircraft * @param v Front vehicle * @param left The minimum horizontal position * @param right The maximum horizontal position * @param y Vertical position to draw at * @param selection Selected vehicle to draw a frame around */ void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID selection, EngineImageType image_type) { bool rtl = _current_text_dir == TD_RTL; SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); int width = UnScaleGUI(real_sprite->width); int x_offs = UnScaleGUI(real_sprite->x_offs); int x = rtl ? right - width - x_offs : left - x_offs; bool helicopter = v->subtype == AIR_HELICOPTER; int y_offs = ScaleGUITrad(10); int heli_offs = 0; PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); DrawSprite(sprite, pal, x, y + y_offs); if (helicopter) { const Aircraft *a = Aircraft::From(v); SpriteID rotor_sprite = GetCustomRotorSprite(a, true, image_type); if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED; heli_offs = ScaleGUITrad(5); DrawSprite(rotor_sprite, PAL_NONE, x, y + y_offs - heli_offs); } if (v->index == selection) { x += x_offs; y += UnScaleGUI(real_sprite->y_offs) + y_offs - heli_offs; DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(real_sprite->height) + heli_offs + 1, COLOUR_WHITE, FR_BORDERONLY); } } openttd-1.5.3/src/depot_map.h0000644000000000000000000000443212627373446014624 0ustar rootroot/* $Id: depot_map.h 26692 2014-07-16 20:56:39Z frosch $ */ /* * 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 depot_map.h Map related accessors for depots. */ #ifndef DEPOT_MAP_H #define DEPOT_MAP_H #include "station_map.h" /** * Check if a tile is a depot and it is a depot of the given type. */ static inline bool IsDepotTypeTile(TileIndex tile, TransportType type) { switch (type) { default: NOT_REACHED(); case TRANSPORT_RAIL: return IsRailDepotTile(tile); case TRANSPORT_ROAD: return IsRoadDepotTile(tile); case TRANSPORT_WATER: return IsShipDepotTile(tile); case TRANSPORT_AIR: return IsHangarTile(tile); } } /** * Is the given tile a tile with a depot on it? * @param tile the tile to check * @return true if and only if there is a depot on the tile. */ static inline bool IsDepotTile(TileIndex tile) { return IsRailDepotTile(tile) || IsRoadDepotTile(tile) || IsShipDepotTile(tile) || IsHangarTile(tile); } /** * Get the index of which depot is attached to the tile. * @param t the tile * @pre IsRailDepotTile(t) || IsRoadDepotTile(t) || IsShipDepotTile(t) * @return DepotID */ static inline DepotID GetDepotIndex(TileIndex t) { /* Hangars don't have a Depot class, thus store no DepotID. */ assert(IsRailDepotTile(t) || IsRoadDepotTile(t) || IsShipDepotTile(t)); return _m[t].m2; } /** * Get the type of vehicles that can use a depot * @param t The tile * @pre IsDepotTile(t) * @return the type of vehicles that can use the depot */ static inline VehicleType GetDepotVehicleType(TileIndex t) { switch (GetTileType(t)) { default: NOT_REACHED(); case MP_RAILWAY: return VEH_TRAIN; case MP_ROAD: return VEH_ROAD; case MP_WATER: return VEH_SHIP; case MP_STATION: return VEH_AIRCRAFT; } } #endif /* DEPOT_MAP_H */ openttd-1.5.3/src/cheat.cpp0000644000000000000000000000245112627373442014266 0ustar rootroot/* $Id: cheat.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 cheat.cpp Handling (loading/saving/initializing) of cheats. */ #include "stdafx.h" #include "cheat_type.h" #include "safeguards.h" /** All the cheats. */ Cheats _cheats; /** Reinitialise all the cheats. */ void InitializeCheats() { memset(&_cheats, 0, sizeof(Cheats)); } /** * Return true if any cheat has been used, false otherwise * @return has a cheat been used? */ bool CheatHasBeenUsed() { /* Cannot use lengthof because _cheats is of type Cheats, not Cheat */ const Cheat *cht = (Cheat*)&_cheats; const Cheat *cht_last = &cht[sizeof(_cheats) / sizeof(Cheat)]; for (; cht != cht_last; cht++) { if (cht->been_used) return true; } return false; } openttd-1.5.3/src/pbs.cpp0000644000000000000000000003666112627373442014000 0ustar rootroot/* $Id: pbs.cpp 27270 2015-05-08 17:23:55Z frosch $ */ /* * 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 pbs.cpp PBS support routines */ #include "stdafx.h" #include "viewport_func.h" #include "vehicle_func.h" #include "newgrf_station.h" #include "pathfinder/follow_track.hpp" #include "safeguards.h" /** * Get the reserved trackbits for any tile, regardless of type. * @param t the tile * @return the reserved trackbits. TRACK_BIT_NONE on nothing reserved or * a tile without rail. */ TrackBits GetReservedTrackbits(TileIndex t) { switch (GetTileType(t)) { case MP_RAILWAY: if (IsRailDepot(t)) return GetDepotReservationTrackBits(t); if (IsPlainRail(t)) return GetRailReservationTrackBits(t); break; case MP_ROAD: if (IsLevelCrossing(t)) return GetCrossingReservationTrackBits(t); break; case MP_STATION: if (HasStationRail(t)) return GetStationReservationTrackBits(t); break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) return GetTunnelBridgeReservationTrackBits(t); break; default: break; } return TRACK_BIT_NONE; } /** * Set the reservation for a complete station platform. * @pre IsRailStationTile(start) * @param start starting tile of the platform * @param dir the direction in which to follow the platform * @param b the state the reservation should be set to */ void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool b) { TileIndex tile = start; TileIndexDiff diff = TileOffsByDiagDir(dir); assert(IsRailStationTile(start)); assert(GetRailStationAxis(start) == DiagDirToAxis(dir)); do { SetRailStationReservation(tile, b); MarkTileDirtyByTile(tile); tile = TILE_ADD(tile, diff); } while (IsCompatibleTrainStationTile(tile, start)); } /** * Try to reserve a specific track on a tile * @param tile the tile * @param t the track * @param trigger_stations whether to call station randomisation trigger * @return \c true if reservation was successful, i.e. the track was * free and didn't cross any other reserved tracks. */ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations) { assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0); if (_settings_client.gui.show_track_reservation) { /* show the reserved rail if needed */ if (IsBridgeTile(tile)) { MarkBridgeDirty(tile); } else { MarkTileDirtyByTile(tile); } } switch (GetTileType(tile)) { case MP_RAILWAY: if (IsPlainRail(tile)) return TryReserveTrack(tile, t); if (IsRailDepot(tile)) { if (!HasDepotReservation(tile)) { SetDepotReservation(tile, true); MarkTileDirtyByTile(tile); // some GRFs change their appearance when tile is reserved return true; } } break; case MP_ROAD: if (IsLevelCrossing(tile) && !HasCrossingReservation(tile)) { SetCrossingReservation(tile, true); BarCrossing(tile); MarkTileDirtyByTile(tile); // crossing barred, make tile dirty return true; } break; case MP_STATION: if (HasStationRail(tile) && !HasStationReservation(tile)) { SetRailStationReservation(tile, true); if (trigger_stations && IsRailStation(tile)) TriggerStationRandomisation(NULL, tile, SRT_PATH_RESERVATION); MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track return true; } break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) { SetTunnelBridgeReservation(tile, true); return true; } break; default: break; } return false; } /** * Lift the reservation of a specific track on a tile * @param tile the tile * @param t the track */ void UnreserveRailTrack(TileIndex tile, Track t) { assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0); if (_settings_client.gui.show_track_reservation) { if (IsBridgeTile(tile)) { MarkBridgeDirty(tile); } else { MarkTileDirtyByTile(tile); } } switch (GetTileType(tile)) { case MP_RAILWAY: if (IsRailDepot(tile)) { SetDepotReservation(tile, false); MarkTileDirtyByTile(tile); break; } if (IsPlainRail(tile)) UnreserveTrack(tile, t); break; case MP_ROAD: if (IsLevelCrossing(tile)) { SetCrossingReservation(tile, false); UpdateLevelCrossing(tile); } break; case MP_STATION: if (HasStationRail(tile)) { SetRailStationReservation(tile, false); MarkTileDirtyByTile(tile); } break; case MP_TUNNELBRIDGE: if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) SetTunnelBridgeReservation(tile, false); break; default: break; } } /** Follow a reservation starting from a specific tile to the end. */ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Trackdir trackdir, bool ignore_oneway = false) { TileIndex start_tile = tile; Trackdir start_trackdir = trackdir; bool first_loop = true; /* Start track not reserved? This can happen if two trains * are on the same tile. The reservation on the next tile * is not ours in this case, so exit. */ if (!HasReservedTracks(tile, TrackToTrackBits(TrackdirToTrack(trackdir)))) return PBSTileInfo(tile, trackdir, false); /* Do not disallow 90 deg turns as the setting might have changed between reserving and now. */ CFollowTrackRail ft(o, rts); while (ft.Follow(tile, trackdir)) { TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile)); /* No reservation --> path end found */ if (reserved == TRACKDIR_BIT_NONE) { if (ft.m_is_station) { /* Check skipped station tiles as well, maybe our reservation ends inside the station. */ TileIndexDiff diff = TileOffsByDiagDir(ft.m_exitdir); while (ft.m_tiles_skipped-- > 0) { ft.m_new_tile -= diff; if (HasStationReservation(ft.m_new_tile)) { tile = ft.m_new_tile; trackdir = DiagDirToDiagTrackdir(ft.m_exitdir); break; } } } break; } /* Can't have more than one reserved trackdir */ Trackdir new_trackdir = FindFirstTrackdir(reserved); /* One-way signal against us. The reservation can't be ours as it is not * a safe position from our direction and we can never pass the signal. */ if (!ignore_oneway && HasOnewaySignalBlockingTrackdir(ft.m_new_tile, new_trackdir)) break; tile = ft.m_new_tile; trackdir = new_trackdir; if (first_loop) { /* Update the start tile after we followed the track the first * time. This is necessary because the track follower can skip * tiles (in stations for example) which means that we might * never visit our original starting tile again. */ start_tile = tile; start_trackdir = trackdir; first_loop = false; } else { /* Loop encountered? */ if (tile == start_tile && trackdir == start_trackdir) break; } /* Depot tile? Can't continue. */ if (IsRailDepotTile(tile)) break; /* Non-pbs signal? Reservation can't continue. */ if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break; } return PBSTileInfo(tile, trackdir, false); } /** * Helper struct for finding the best matching vehicle on a specific track. */ struct FindTrainOnTrackInfo { PBSTileInfo res; ///< Information about the track. Train *best; ///< The currently "best" vehicle we have found. /** Init the best location to NULL always! */ FindTrainOnTrackInfo() : best(NULL) {} }; /** Callback for Has/FindVehicleOnPos to find a train on a specific track. */ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data) { FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data; if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL; Train *t = Train::From(v); if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) { t = t->First(); /* ALWAYS return the lowest ID (anti-desync!) */ if (info->best == NULL || t->index < info->best->index) info->best = t; return t; } return NULL; } /** * Follow a train reservation to the last tile. * * @param v the vehicle * @param train_on_res Is set to a train we might encounter * @returns The last tile of the reservation or the current train tile if no reservation present. */ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res) { assert(v->type == VEH_TRAIN); TileIndex tile = v->tile; Trackdir trackdir = v->GetVehicleTrackdir(); if (IsRailDepotTile(tile) && !GetDepotReservationTrackBits(tile)) return PBSTileInfo(tile, trackdir, false); FindTrainOnTrackInfo ftoti; ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir); ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg); if (train_on_res != NULL) { FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); if (*train_on_res == NULL && IsRailStationTile(ftoti.res.tile)) { /* The target tile is a rail station. The track follower * has stopped on the last platform tile where we haven't * found a train. Also check all previous platform tiles * for a possible train. */ TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir))); for (TileIndex st_tile = ftoti.res.tile + diff; *train_on_res == NULL && IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum); if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); } } if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { /* The target tile is a bridge/tunnel, also check the other end tile. */ FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); } } return ftoti.res; } /** * Find the train which has reserved a specific path. * * @param tile A tile on the path. * @param track A reserved track on the tile. * @return The vehicle holding the reservation or NULL if the path is stray. */ Train *GetTrainForReservation(TileIndex tile, Track track) { assert(HasReservedTracks(tile, TrackToTrackBits(track))); Trackdir trackdir = TrackToTrackdir(track); RailTypes rts = GetRailTypeInfo(GetTileRailType(tile))->compatible_railtypes; /* Follow the path from tile to both ends, one of the end tiles should * have a train on it. We need FollowReservation to ignore one-way signals * here, as one of the two search directions will be the "wrong" way. */ for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) { /* If the tile has a one-way block signal in the current trackdir, skip the * search in this direction as the reservation can't come from this side.*/ if (HasOnewaySignalBlockingTrackdir(tile, ReverseTrackdir(trackdir)) && !HasPbsSignalOnTrackdir(tile, trackdir)) continue; FindTrainOnTrackInfo ftoti; ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true); FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); if (ftoti.best != NULL) return ftoti.best; /* Special case for stations: check the whole platform for a vehicle. */ if (IsRailStationTile(ftoti.res.tile)) { TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir))); for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum); if (ftoti.best != NULL) return ftoti.best; } } /* Special case for bridges/tunnels: check the other end as well. */ if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); if (ftoti.best != NULL) return ftoti.best; } } return NULL; } /** * Determine whether a certain track on a tile is a safe position to end a path. * * @param v the vehicle to test for * @param tile The tile * @param trackdir The trackdir to test * @param include_line_end Should end-of-line tiles be considered safe? * @param forbid_90deg Don't allow trains to make 90 degree turns * @return True if it is a safe position */ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bool include_line_end, bool forbid_90deg) { if (IsRailDepotTile(tile)) return true; if (IsTileType(tile, MP_RAILWAY)) { /* For non-pbs signals, stop on the signal tile. */ if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true; } /* Check next tile. For performance reasons, we check for 90 degree turns ourself. */ CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); /* End of track? */ if (!ft.Follow(tile, trackdir)) { /* Last tile of a terminus station is a safe position. */ if (include_line_end) return true; } /* Check for reachable tracks. */ ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir); if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); if (ft.m_new_td_bits == TRACKDIR_BIT_NONE) return include_line_end; if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) { Trackdir td = FindFirstTrackdir(ft.m_new_td_bits); /* PBS signal on next trackdir? Safe position. */ if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) return true; /* One-way PBS signal against us? Safe if end-of-line is allowed. */ if (IsTileType(ft.m_new_tile, MP_RAILWAY) && HasSignalOnTrackdir(ft.m_new_tile, ReverseTrackdir(td)) && GetSignalType(ft.m_new_tile, TrackdirToTrack(td)) == SIGTYPE_PBS_ONEWAY) { return include_line_end; } } return false; } /** * Check if a safe position is free. * * @param v the vehicle to test for * @param tile The tile * @param trackdir The trackdir to test * @param forbid_90deg Don't allow trains to make 90 degree turns * @return True if the position is free */ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bool forbid_90deg) { Track track = TrackdirToTrack(trackdir); TrackBits reserved = GetReservedTrackbits(tile); /* Tile reserved? Can never be a free waiting position. */ if (TrackOverlapsTracks(reserved, track)) return false; /* Not reserved and depot or not a pbs signal -> free. */ if (IsRailDepotTile(tile)) return true; if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, track))) return true; /* Check the next tile, if it's a PBS signal, it has to be free as well. */ CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes); if (!ft.Follow(tile, trackdir)) return true; /* Check for reachable tracks. */ ft.m_new_td_bits &= DiagdirReachesTrackdirs(ft.m_exitdir); if (forbid_90deg) ft.m_new_td_bits &= ~TrackdirCrossesTrackdirs(trackdir); return !HasReservedTracks(ft.m_new_tile, TrackdirBitsToTrackBits(ft.m_new_td_bits)); } openttd-1.5.3/src/depot_gui.cpp0000644000000000000000000011060212627373442015157 0ustar rootroot/* $Id: depot_gui.cpp 27134 2015-02-01 20:54:24Z frosch $ */ /* * 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 depot_gui.cpp The GUI for depots. */ #include "stdafx.h" #include "train.h" #include "roadveh.h" #include "ship.h" #include "aircraft.h" #include "gui.h" #include "textbuf_gui.h" #include "viewport_func.h" #include "command_func.h" #include "depot_base.h" #include "spritecache.h" #include "strings_func.h" #include "vehicle_func.h" #include "company_func.h" #include "tilehighlight_func.h" #include "window_gui.h" #include "vehiclelist.h" #include "order_backup.h" #include "zoom_func.h" #include "widgets/depot_widget.h" #include "table/strings.h" #include "safeguards.h" /* * Since all depot window sizes aren't the same, we need to modify sizes a little. * It's done with the following arrays of widget indexes. Each of them tells if a widget side should be moved and in what direction. * How long they should be moved and for what window types are controlled in ShowDepotWindow() */ /** Nested widget definition for train depots. */ static const NWidgetPart _nested_train_depot_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CAPTION, COLOUR_GREY, WID_D_CAPTION), SetDataTip(STR_DEPOT_CAPTION, STR_NULL), NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_D_MATRIX), SetResize(1, 1), SetScrollbar(WID_D_V_SCROLL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_D_SHOW_H_SCROLL), NWidget(NWID_HSCROLLBAR, COLOUR_GREY, WID_D_H_SCROLL), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_D_SELL), SetDataTip(0x0, STR_NULL), SetResize(0, 1), SetFill(0, 1), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_D_SHOW_SELL_CHAIN), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_D_SELL_CHAIN), SetDataTip(SPR_SELL_CHAIN_TRAIN, STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP), SetResize(0, 1), SetFill(0, 1), EndContainer(), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_SELL_ALL), SetDataTip(0x0, STR_NULL), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_AUTOREPLACE), SetDataTip(0x0, STR_NULL), EndContainer(), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_D_V_SCROLL), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_D_BUILD), SetDataTip(0x0, STR_NULL), SetFill(1, 1), SetResize(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_D_CLONE), SetDataTip(0x0, STR_NULL), SetFill(1, 1), SetResize(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_D_LOCATION), SetDataTip(STR_BUTTON_LOCATION, STR_NULL), SetFill(1, 1), SetResize(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_D_SHOW_RENAME), // rename button NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_D_RENAME), SetDataTip(STR_BUTTON_RENAME, STR_DEPOT_RENAME_TOOLTIP), SetFill(1, 1), SetResize(1, 0), EndContainer(), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_D_VEHICLE_LIST), SetDataTip(0x0, STR_NULL), SetFill(0, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_STOP_ALL), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_NULL), SetFill(0, 1), NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_D_START_ALL), SetDataTip(SPR_FLAG_VEH_RUNNING, STR_NULL), SetFill(0, 1), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), }; static WindowDesc _train_depot_desc( WDP_AUTO, "depot_train", 362, 123, WC_VEHICLE_DEPOT, WC_NONE, 0, _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) ); static WindowDesc _road_depot_desc( WDP_AUTO, "depot_roadveh", 316, 97, WC_VEHICLE_DEPOT, WC_NONE, 0, _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) ); static WindowDesc _ship_depot_desc( WDP_AUTO, "depot_ship", 306, 99, WC_VEHICLE_DEPOT, WC_NONE, 0, _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) ); static WindowDesc _aircraft_depot_desc( WDP_AUTO, "depot_aircraft", 332, 99, WC_VEHICLE_DEPOT, WC_NONE, 0, _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets) ); extern void DepotSortList(VehicleList *list); /** * This is the Callback method after the cloning attempt of a vehicle * @param result the result of the cloning command * @param tile unused * @param p1 unused * @param p2 unused */ void CcCloneVehicle(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) { if (result.Failed()) return; const Vehicle *v = Vehicle::Get(_new_vehicle_id); ShowVehicleViewWindow(v); } static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Vehicle *head) { const Vehicle *v = Vehicle::Get(sel); if (v == wagon) return; if (wagon == NULL) { if (head != NULL) wagon = head->Last(); } else { wagon = wagon->Previous(); if (wagon == NULL) return; } if (wagon == v) return; DoCommandP(v->tile, v->index | (_ctrl_pressed ? 1 : 0) << 20, wagon == NULL ? INVALID_VEHICLE : wagon->index, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE)); } static VehicleCellSize _base_block_sizes_depot[VEH_COMPANY_END]; ///< Cell size for vehicle images in the depot view. static VehicleCellSize _base_block_sizes_purchase[VEH_COMPANY_END]; ///< Cell size for vehicle images in the purchase list. /** * Get the GUI cell size for a vehicle image. * @param type Vehicle type to get the size for. * @param image_type Image type to get size for. * @pre image_type == EIT_IN_DEPOT || image_type == EIT_PURCHASE * @return Cell dimensions for the vehicle and image type. */ VehicleCellSize GetVehicleImageCellSize(VehicleType type, EngineImageType image_type) { switch (image_type) { case EIT_IN_DEPOT: return _base_block_sizes_depot[type]; case EIT_PURCHASE: return _base_block_sizes_purchase[type]; default: NOT_REACHED(); } } static void InitBlocksizeForVehicles(VehicleType type, EngineImageType image_type) { int max_extend_left = 0; int max_extend_right = 0; uint max_height = 0; const Engine *e; FOR_ALL_ENGINES_OF_TYPE(e, type) { if (!e->IsEnabled()) continue; EngineID eid = e->index; uint x, y; int x_offs, y_offs; switch (type) { default: NOT_REACHED(); case VEH_TRAIN: GetTrainSpriteSize( eid, x, y, x_offs, y_offs, image_type); break; case VEH_ROAD: GetRoadVehSpriteSize( eid, x, y, x_offs, y_offs, image_type); break; case VEH_SHIP: GetShipSpriteSize( eid, x, y, x_offs, y_offs, image_type); break; case VEH_AIRCRAFT: GetAircraftSpriteSize(eid, x, y, x_offs, y_offs, image_type); break; } if (y > max_height) max_height = y; if (-x_offs > max_extend_left) max_extend_left = -x_offs; if ((int)x + x_offs > max_extend_right) max_extend_right = x + x_offs; } int min_extend = ScaleGUITrad(16); int max_extend = ScaleGUITrad(98); switch (image_type) { case EIT_IN_DEPOT: _base_block_sizes_depot[type].height = max(ScaleGUITrad(GetVehicleHeight(type)), max_height); _base_block_sizes_depot[type].extend_left = Clamp(max_extend_left, min_extend, max_extend); _base_block_sizes_depot[type].extend_right = Clamp(max_extend_right, min_extend, max_extend); break; case EIT_PURCHASE: _base_block_sizes_purchase[type].height = max(ScaleGUITrad(GetVehicleHeight(type)), max_height); _base_block_sizes_purchase[type].extend_left = Clamp(max_extend_left, min_extend, max_extend); _base_block_sizes_purchase[type].extend_right = Clamp(max_extend_right, min_extend, max_extend); break; default: NOT_REACHED(); } } /** * Set the size of the blocks in the window so we can be sure that they are big enough for the vehicle sprites in the current game. * @note Calling this function once for each game is enough. */ void InitDepotWindowBlockSizes() { for (VehicleType vt = VEH_BEGIN; vt < VEH_COMPANY_END; vt++) { InitBlocksizeForVehicles(vt, EIT_IN_DEPOT); InitBlocksizeForVehicles(vt, EIT_PURCHASE); } } static void DepotSellAllConfirmationCallback(Window *w, bool confirmed); const Sprite *GetAircraftSprite(EngineID engine); struct DepotWindow : Window { VehicleID sel; VehicleID vehicle_over; ///< Rail vehicle over which another one is dragged, \c INVALID_VEHICLE if none. VehicleType type; bool generate_list; VehicleList vehicle_list; VehicleList wagon_list; uint unitnumber_digits; uint num_columns; ///< Number of columns. Scrollbar *hscroll; ///< Only for trains. Scrollbar *vscroll; DepotWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc) { assert(IsCompanyBuildableVehicleType(type)); // ensure that we make the call with a valid type this->sel = INVALID_VEHICLE; this->vehicle_over = INVALID_VEHICLE; this->generate_list = true; this->type = type; this->num_columns = 1; // for non-trains this gets set in FinishInitNested() this->unitnumber_digits = 2; this->CreateNestedTree(); this->hscroll = (this->type == VEH_TRAIN ? this->GetScrollbar(WID_D_H_SCROLL) : NULL); this->vscroll = this->GetScrollbar(WID_D_V_SCROLL); /* Don't show 'rename button' of aircraft hangar */ this->GetWidget(WID_D_SHOW_RENAME)->SetDisplayedPlane(type == VEH_AIRCRAFT ? SZSP_NONE : 0); /* Only train depots have a horizontal scrollbar and a 'sell chain' button */ if (type == VEH_TRAIN) this->GetWidget(WID_D_MATRIX)->widget_data = 1 << MAT_COL_START; this->GetWidget(WID_D_SHOW_H_SCROLL)->SetDisplayedPlane(type == VEH_TRAIN ? 0 : SZSP_HORIZONTAL); this->GetWidget(WID_D_SHOW_SELL_CHAIN)->SetDisplayedPlane(type == VEH_TRAIN ? 0 : SZSP_NONE); this->SetupWidgetData(type); this->FinishInitNested(tile); this->owner = GetTileOwner(tile); OrderBackup::Reset(); } ~DepotWindow() { DeleteWindowById(WC_BUILD_VEHICLE, this->window_number); OrderBackup::Reset(this->window_number); } /** * Draw a vehicle in the depot window in the box with the top left corner at x,y. * @param v Vehicle to draw. * @param left Left side of the box to draw in. * @param right Right side of the box to draw in. * @param y Top of the box to draw in. */ void DrawVehicleInDepot(const Vehicle *v, int left, int right, int y) const { bool free_wagon = false; int sprite_y = y + (this->resize.step_height - ScaleGUITrad(GetVehicleHeight(v->type))) / 2; bool rtl = _current_text_dir == TD_RTL; int image_left = rtl ? left + this->count_width : left + this->header_width; int image_right = rtl ? right - this->header_width : right - this->count_width; switch (v->type) { case VEH_TRAIN: { const Train *u = Train::From(v); free_wagon = u->IsFreeWagon(); uint x_space = free_wagon ? ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) : 0; DrawTrainImage(u, image_left + (rtl ? 0 : x_space), image_right - (rtl ? x_space : 0), sprite_y - 1, this->sel, EIT_IN_DEPOT, free_wagon ? 0 : this->hscroll->GetPosition(), this->vehicle_over); /* Length of consist in tiles with 1 fractional digit (rounded up) */ SetDParam(0, CeilDiv(u->gcache.cached_total_length * 10, TILE_SIZE)); SetDParam(1, 1); DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_DECIMAL, TC_FROMSTRING, SA_RIGHT); // Draw the counter break; } case VEH_ROAD: DrawRoadVehImage( v, image_left, image_right, sprite_y, this->sel, EIT_IN_DEPOT); break; case VEH_SHIP: DrawShipImage( v, image_left, image_right, sprite_y, this->sel, EIT_IN_DEPOT); break; case VEH_AIRCRAFT: DrawAircraftImage(v, image_left, image_right, sprite_y, this->sel, EIT_IN_DEPOT); break; default: NOT_REACHED(); } uint diff_x, diff_y; if (v->IsGroundVehicle()) { /* Arrange unitnumber and flag horizontally */ diff_x = this->flag_width + WD_FRAMERECT_LEFT; diff_y = (this->resize.step_height - this->flag_height) / 2 - 2; } else { /* Arrange unitnumber and flag vertically */ diff_x = WD_FRAMERECT_LEFT; diff_y = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; } int text_left = rtl ? right - this->header_width - 1 : left + diff_x; int text_right = rtl ? right - diff_x : left + this->header_width - 1; if (free_wagon) { DrawString(text_left, text_right, y + 2, STR_DEPOT_NO_ENGINE); } else { DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, rtl ? right - this->flag_width : left + WD_FRAMERECT_LEFT, y + diff_y); SetDParam(0, v->unitnumber); DrawString(text_left, text_right, y + 2, (uint16)(v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? STR_BLACK_COMMA : STR_RED_COMMA); } } void DrawWidget(const Rect &r, int widget) const { if (widget != WID_D_MATRIX) return; bool rtl = _current_text_dir == TD_RTL; /* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */ const NWidgetCore *wid = this->GetWidget(WID_D_MATRIX); uint16 rows_in_display = wid->current_y / wid->resize_y; uint16 num = this->vscroll->GetPosition() * this->num_columns; int maxval = min(this->vehicle_list.Length(), num + (rows_in_display * this->num_columns)); int y; for (y = r.top + 1; num < maxval; y += this->resize.step_height) { // Draw the rows for (byte i = 0; i < this->num_columns && num < maxval; i++, num++) { /* Draw all vehicles in the current row */ const Vehicle *v = this->vehicle_list[num]; if (this->num_columns == 1) { this->DrawVehicleInDepot(v, r.left, r.right, y); } else { int x = r.left + (rtl ? (this->num_columns - i - 1) : i) * this->resize.step_width; this->DrawVehicleInDepot(v, x, x + this->resize.step_width - 1, y); } } } maxval = min(this->vehicle_list.Length() + this->wagon_list.Length(), (this->vscroll->GetPosition() * this->num_columns) + (rows_in_display * this->num_columns)); /* Draw the train wagons without an engine in front. */ for (; num < maxval; num++, y += this->resize.step_height) { const Vehicle *v = this->wagon_list[num - this->vehicle_list.Length()]; this->DrawVehicleInDepot(v, r.left, r.right, y); } } void SetStringParameters(int widget) const { if (widget != WID_D_CAPTION) return; /* locate the depot struct */ TileIndex tile = this->window_number; SetDParam(0, this->type); SetDParam(1, (this->type == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotIndex(tile)); } struct GetDepotVehiclePtData { const Vehicle *head; const Vehicle *wagon; }; enum DepotGUIAction { MODE_ERROR, MODE_DRAG_VEHICLE, MODE_SHOW_VEHICLE, MODE_START_STOP, }; DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const { const NWidgetCore *matrix_widget = this->GetWidget(WID_D_MATRIX); /* In case of RTL the widgets are swapped as a whole */ if (_current_text_dir == TD_RTL) x = matrix_widget->current_x - x; uint xt = 0, xm = 0, ym = 0; if (this->type == VEH_TRAIN) { xm = x; } else { xt = x / this->resize.step_width; xm = x % this->resize.step_width; if (xt >= this->num_columns) return MODE_ERROR; } ym = y % this->resize.step_height; uint row = y / this->resize.step_height; if (row >= this->vscroll->GetCapacity()) return MODE_ERROR; uint pos = ((row + this->vscroll->GetPosition()) * this->num_columns) + xt; if (this->vehicle_list.Length() + this->wagon_list.Length() <= pos) { /* Clicking on 'line' / 'block' without a vehicle */ if (this->type == VEH_TRAIN) { /* End the dragging */ d->head = NULL; d->wagon = NULL; return MODE_DRAG_VEHICLE; } else { return MODE_ERROR; // empty block, so no vehicle is selected } } bool wagon = false; if (this->vehicle_list.Length() > pos) { *veh = this->vehicle_list[pos]; /* Skip vehicles that are scrolled off the list */ if (this->type == VEH_TRAIN) x += this->hscroll->GetPosition(); } else { pos -= this->vehicle_list.Length(); *veh = this->wagon_list[pos]; /* free wagons don't have an initial loco. */ x -= ScaleGUITrad(VEHICLEINFO_FULL_VEHICLE_WIDTH); wagon = true; } const Train *v = NULL; if (this->type == VEH_TRAIN) { v = Train::From(*veh); d->head = d->wagon = v; } if (xm <= this->header_width) { switch (this->type) { case VEH_TRAIN: if (wagon) return MODE_ERROR; /* FALL THROUGH */ case VEH_ROAD: if (xm <= this->flag_width) return MODE_START_STOP; break; case VEH_SHIP: case VEH_AIRCRAFT: if (xm <= this->flag_width && ym >= (uint)(FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL)) return MODE_START_STOP; break; default: NOT_REACHED(); } return MODE_SHOW_VEHICLE; } if (this->type != VEH_TRAIN) return MODE_DRAG_VEHICLE; /* Clicking on the counter */ if (xm >= matrix_widget->current_x - this->count_width) return wagon ? MODE_ERROR : MODE_SHOW_VEHICLE; /* Account for the header */ x -= this->header_width; /* find the vehicle in this row that was clicked */ for (; v != NULL; v = v->Next()) { x -= v->GetDisplayImageWidth(); if (x < 0) break; } d->wagon = (v != NULL ? v->GetFirstEnginePart() : NULL); return MODE_DRAG_VEHICLE; } /** * Handle click in the depot matrix. * @param x Horizontal position in the matrix widget in pixels. * @param y Vertical position in the matrix widget in pixels. */ void DepotClick(int x, int y) { GetDepotVehiclePtData gdvp = { NULL, NULL }; const Vehicle *v = NULL; DepotGUIAction mode = this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp); if (this->type == VEH_TRAIN) v = gdvp.wagon; switch (mode) { case MODE_ERROR: // invalid return; case MODE_DRAG_VEHICLE: { // start dragging of vehicle if (v != NULL && VehicleClicked(v)) return; VehicleID sel = this->sel; if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) { this->sel = INVALID_VEHICLE; TrainDepotMoveVehicle(v, sel, gdvp.head); } else if (v != NULL) { bool rtl = _current_text_dir == TD_RTL; int image = v->GetImage(rtl ? DIR_E : DIR_W, EIT_IN_DEPOT); SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this); this->sel = v->index; this->SetDirty(); _cursor.short_vehicle_offset = v->IsGroundVehicle() ? (16 - v->GetGroundVehicleCache()->cached_veh_length * 2) * (rtl ? -1 : 1) : 0; _cursor.vehchain = _ctrl_pressed; } break; } case MODE_SHOW_VEHICLE: // show info window ShowVehicleViewWindow(v); break; case MODE_START_STOP: // click start/stop flag StartStopVehicle(v, false); break; default: NOT_REACHED(); } } /** * Function to set up vehicle specific widgets (mainly sprites and strings). * Only use this function to if the widget is used for several vehicle types and each has * different text/sprites. If the widget is only used for a single vehicle type, or the same * text/sprites are used every time, use the nested widget array to initialize the widget. */ void SetupWidgetData(VehicleType type) { this->GetWidget(WID_D_STOP_ALL)->tool_tip = STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP + type; this->GetWidget(WID_D_START_ALL)->tool_tip = STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP + type; this->GetWidget(WID_D_SELL)->tool_tip = STR_DEPOT_TRAIN_SELL_TOOLTIP + type; this->GetWidget(WID_D_SELL_ALL)->tool_tip = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP + type; this->GetWidget(WID_D_BUILD)->SetDataTip(STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON + type, STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP + type); this->GetWidget(WID_D_CLONE)->SetDataTip(STR_DEPOT_CLONE_TRAIN + type, STR_DEPOT_CLONE_TRAIN_DEPOT_INFO + type); this->GetWidget(WID_D_LOCATION)->tool_tip = STR_DEPOT_TRAIN_LOCATION_TOOLTIP + type; this->GetWidget(WID_D_VEHICLE_LIST)->tool_tip = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP + type; this->GetWidget(WID_D_AUTOREPLACE)->tool_tip = STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP + type; this->GetWidget(WID_D_MATRIX)->tool_tip = STR_DEPOT_TRAIN_LIST_TOOLTIP + this->type; switch (type) { default: NOT_REACHED(); case VEH_TRAIN: this->GetWidget(WID_D_VEHICLE_LIST)->widget_data = STR_TRAIN; /* Sprites */ this->GetWidget(WID_D_SELL)->widget_data = SPR_SELL_TRAIN; this->GetWidget(WID_D_SELL_ALL)->widget_data = SPR_SELL_ALL_TRAIN; this->GetWidget(WID_D_AUTOREPLACE)->widget_data = SPR_REPLACE_TRAIN; break; case VEH_ROAD: this->GetWidget(WID_D_VEHICLE_LIST)->widget_data = STR_LORRY; /* Sprites */ this->GetWidget(WID_D_SELL)->widget_data = SPR_SELL_ROADVEH; this->GetWidget(WID_D_SELL_ALL)->widget_data = SPR_SELL_ALL_ROADVEH; this->GetWidget(WID_D_AUTOREPLACE)->widget_data = SPR_REPLACE_ROADVEH; break; case VEH_SHIP: this->GetWidget(WID_D_VEHICLE_LIST)->widget_data = STR_SHIP; /* Sprites */ this->GetWidget(WID_D_SELL)->widget_data = SPR_SELL_SHIP; this->GetWidget(WID_D_SELL_ALL)->widget_data = SPR_SELL_ALL_SHIP; this->GetWidget(WID_D_AUTOREPLACE)->widget_data = SPR_REPLACE_SHIP; break; case VEH_AIRCRAFT: this->GetWidget(WID_D_VEHICLE_LIST)->widget_data = STR_PLANE; /* Sprites */ this->GetWidget(WID_D_SELL)->widget_data = SPR_SELL_AIRCRAFT; this->GetWidget(WID_D_SELL_ALL)->widget_data = SPR_SELL_ALL_AIRCRAFT; this->GetWidget(WID_D_AUTOREPLACE)->widget_data = SPR_REPLACE_AIRCRAFT; break; } } uint count_width; uint header_width; uint flag_width; uint flag_height; virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_D_MATRIX: { uint min_height = 0; if (this->type == VEH_TRAIN) { SetDParamMaxValue(0, 1000, 0, FS_SMALL); SetDParam(1, 1); this->count_width = GetStringBoundingBox(STR_TINY_BLACK_DECIMAL).width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; } else { this->count_width = 0; } SetDParamMaxDigits(0, this->unitnumber_digits); Dimension unumber = GetStringBoundingBox(STR_BLACK_COMMA); const Sprite *spr = GetSprite(SPR_FLAG_VEH_STOPPED, ST_NORMAL); this->flag_width = UnScaleGUI(spr->width) + WD_FRAMERECT_RIGHT; this->flag_height = UnScaleGUI(spr->height); if (this->type == VEH_TRAIN || this->type == VEH_ROAD) { min_height = max(unumber.height + WD_MATRIX_TOP, UnScaleGUI(spr->height)); this->header_width = unumber.width + this->flag_width + WD_FRAMERECT_LEFT; } else { min_height = unumber.height + UnScaleGUI(spr->height) + WD_MATRIX_TOP + WD_PAR_VSEP_NORMAL + WD_MATRIX_BOTTOM; this->header_width = max(unumber.width, this->flag_width) + WD_FRAMERECT_RIGHT; } int base_width = this->count_width + this->header_width; resize->height = max(GetVehicleImageCellSize(this->type, EIT_IN_DEPOT).height, min_height); if (this->type == VEH_TRAIN) { resize->width = 1; size->width = base_width + 2 * ScaleGUITrad(29); // about 2 parts size->height = resize->height * 6; } else { resize->width = base_width + GetVehicleImageCellSize(this->type, EIT_IN_DEPOT).extend_left + GetVehicleImageCellSize(this->type, EIT_IN_DEPOT).extend_right; size->width = resize->width * (this->type == VEH_ROAD ? 5 : 3); size->height = resize->height * (this->type == VEH_ROAD ? 5 : 3); } fill->width = resize->width; fill->height = resize->height; 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) { this->generate_list = true; } virtual void OnPaint() { if (this->generate_list) { /* Generate the vehicle list * It's ok to use the wagon pointers for non-trains as they will be ignored */ BuildDepotVehicleList(this->type, this->window_number, &this->vehicle_list, &this->wagon_list); this->generate_list = false; DepotSortList(&this->vehicle_list); uint new_unitnumber_digits = GetUnitNumberDigits(this->vehicle_list); if (this->unitnumber_digits != new_unitnumber_digits) { this->unitnumber_digits = new_unitnumber_digits; this->ReInit(); } } /* determine amount of items for scroller */ if (this->type == VEH_TRAIN) { uint max_width = ScaleGUITrad(VEHICLEINFO_FULL_VEHICLE_WIDTH); for (uint num = 0; num < this->vehicle_list.Length(); num++) { uint width = 0; for (const Train *v = Train::From(this->vehicle_list[num]); v != NULL; v = v->Next()) { width += v->GetDisplayImageWidth(); } max_width = max(max_width, width); } /* Always have 1 empty row, so people can change the setting of the train */ this->vscroll->SetCount(this->vehicle_list.Length() + this->wagon_list.Length() + 1); this->hscroll->SetCount(max_width); } else { this->vscroll->SetCount(CeilDiv(this->vehicle_list.Length(), this->num_columns)); } /* Setup disabled buttons. */ TileIndex tile = this->window_number; this->SetWidgetsDisabledState(!IsTileOwner(tile, _local_company), WID_D_STOP_ALL, WID_D_START_ALL, WID_D_SELL, WID_D_SELL_CHAIN, WID_D_SELL_ALL, WID_D_BUILD, WID_D_CLONE, WID_D_RENAME, WID_D_AUTOREPLACE, WIDGET_LIST_END); this->DrawWidgets(); } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_D_MATRIX: { // List NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); this->DepotClick(pt.x - nwi->pos_x, pt.y - nwi->pos_y); break; } case WID_D_BUILD: // Build vehicle ResetObjectToPlace(); ShowBuildVehicleWindow(this->window_number, this->type); break; case WID_D_CLONE: // Clone button this->SetWidgetDirty(WID_D_CLONE); this->ToggleWidgetLoweredState(WID_D_CLONE); if (this->IsWidgetLowered(WID_D_CLONE)) { static const CursorID clone_icons[] = { SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH, SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE }; SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, HT_VEHICLE, this); } else { ResetObjectToPlace(); } break; case WID_D_LOCATION: if (_ctrl_pressed) { ShowExtraViewPortWindow(this->window_number); } else { ScrollMainWindowToTile(this->window_number); } break; case WID_D_RENAME: // Rename button SetDParam(0, this->type); SetDParam(1, Depot::GetByTile((TileIndex)this->window_number)->index); ShowQueryString(STR_DEPOT_NAME, STR_DEPOT_RENAME_DEPOT_CAPTION, MAX_LENGTH_DEPOT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS); break; case WID_D_STOP_ALL: case WID_D_START_ALL: { VehicleListIdentifier vli(VL_DEPOT_LIST, this->type, this->owner); DoCommandP(this->window_number, (widget == WID_D_START_ALL ? (1 << 0) : 0), vli.Pack(), CMD_MASS_START_STOP); break; } case WID_D_SELL_ALL: /* Only open the confirmation window if there are anything to sell */ if (this->vehicle_list.Length() != 0 || this->wagon_list.Length() != 0) { TileIndex tile = this->window_number; byte vehtype = this->type; SetDParam(0, vehtype); SetDParam(1, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotIndex(tile)); ShowQuery( STR_DEPOT_CAPTION, STR_DEPOT_SELL_CONFIRMATION_TEXT, this, DepotSellAllConfirmationCallback ); } break; case WID_D_VEHICLE_LIST: ShowVehicleListWindow(GetTileOwner(this->window_number), this->type, (TileIndex)this->window_number); break; case WID_D_AUTOREPLACE: DoCommandP(this->window_number, this->type, 0, CMD_DEPOT_MASS_AUTOREPLACE); break; } } virtual void OnQueryTextFinished(char *str) { if (str == NULL) return; /* Do depot renaming */ DoCommandP(0, GetDepotIndex(this->window_number), 0, CMD_RENAME_DEPOT | CMD_MSG(STR_ERROR_CAN_T_RENAME_DEPOT), NULL, str); } virtual bool OnRightClick(Point pt, int widget) { if (widget != WID_D_MATRIX) return false; GetDepotVehiclePtData gdvp = { NULL, NULL }; const Vehicle *v = NULL; NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp); if (this->type == VEH_TRAIN) v = gdvp.wagon; if (v == NULL || mode != MODE_DRAG_VEHICLE) return false; CargoArray capacity, loaded; /* Display info for single (articulated) vehicle, or for whole chain starting with selected vehicle */ bool whole_chain = (this->type == VEH_TRAIN && _ctrl_pressed); /* loop through vehicle chain and collect cargoes */ uint num = 0; for (const Vehicle *w = v; w != NULL; w = w->Next()) { if (w->cargo_cap > 0 && w->cargo_type < NUM_CARGO) { capacity[w->cargo_type] += w->cargo_cap; loaded [w->cargo_type] += w->cargo.StoredCount(); } if (w->type == VEH_TRAIN && !w->HasArticulatedPart()) { num++; if (!whole_chain) break; } } /* Build tooltipstring */ static char details[1024]; details[0] = '\0'; char *pos = details; for (CargoID cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) { if (capacity[cargo_type] == 0) continue; SetDParam(0, cargo_type); // {CARGO} #1 SetDParam(1, loaded[cargo_type]); // {CARGO} #2 SetDParam(2, cargo_type); // {SHORTCARGO} #1 SetDParam(3, capacity[cargo_type]); // {SHORTCARGO} #2 pos = GetString(pos, STR_DEPOT_VEHICLE_TOOLTIP_CARGO, lastof(details)); } /* Show tooltip window */ uint64 args[2]; args[0] = (whole_chain ? num : v->engine_type); args[1] = (uint64)(size_t)details; GuiShowTooltips(this, whole_chain ? STR_DEPOT_VEHICLE_TOOLTIP_CHAIN : STR_DEPOT_VEHICLE_TOOLTIP, 2, args, TCC_RIGHT_CLICK); return true; } /** * Clones a vehicle * @param v the original vehicle to clone * @return Always true. */ virtual bool OnVehicleSelect(const Vehicle *v) { if (DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), CcCloneVehicle)) { ResetObjectToPlace(); } return true; } virtual void OnPlaceObjectAbort() { /* abort clone */ this->RaiseWidget(WID_D_CLONE); this->SetWidgetDirty(WID_D_CLONE); /* abort drag & drop */ this->sel = INVALID_VEHICLE; this->vehicle_over = INVALID_VEHICLE; this->SetWidgetDirty(WID_D_MATRIX); } virtual void OnMouseDrag(Point pt, int widget) { if (this->type != VEH_TRAIN || this->sel == INVALID_VEHICLE) return; /* A rail vehicle is dragged.. */ if (widget != WID_D_MATRIX) { // ..outside of the depot matrix. if (this->vehicle_over != INVALID_VEHICLE) { this->vehicle_over = INVALID_VEHICLE; this->SetWidgetDirty(WID_D_MATRIX); } return; } NWidgetBase *matrix = this->GetWidget(widget); const Vehicle *v = NULL; GetDepotVehiclePtData gdvp = {NULL, NULL}; if (this->GetVehicleFromDepotWndPt(pt.x - matrix->pos_x, pt.y - matrix->pos_y, &v, &gdvp) != MODE_DRAG_VEHICLE) return; VehicleID new_vehicle_over = INVALID_VEHICLE; if (gdvp.head != NULL) { if (gdvp.wagon == NULL && gdvp.head->Last()->index != this->sel) { // ..at the end of the train. /* NOTE: As a wagon can't be moved at the begin of a train, head index isn't used to mark a drag-and-drop * destination inside a train. This head index is then used to indicate that a wagon is inserted at * the end of the train. */ new_vehicle_over = gdvp.head->index; } else if (gdvp.wagon != NULL && gdvp.head != gdvp.wagon && gdvp.wagon->index != this->sel && gdvp.wagon->Previous()->index != this->sel) { // ..over an existing wagon. new_vehicle_over = gdvp.wagon->index; } } if (this->vehicle_over == new_vehicle_over) return; this->vehicle_over = new_vehicle_over; this->SetWidgetDirty(widget); } virtual void OnDragDrop(Point pt, int widget) { switch (widget) { case WID_D_MATRIX: { const Vehicle *v = NULL; VehicleID sel = this->sel; this->sel = INVALID_VEHICLE; this->SetDirty(); NWidgetBase *nwi = this->GetWidget(WID_D_MATRIX); if (this->type == VEH_TRAIN) { GetDepotVehiclePtData gdvp = { NULL, NULL }; if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) { if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) { DoCommandP(Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE)); } else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) { this->vehicle_over = INVALID_VEHICLE; TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head); } else if (gdvp.head != NULL && gdvp.head->IsFrontEngine()) { ShowVehicleViewWindow(gdvp.head); } } } else if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, NULL) == MODE_DRAG_VEHICLE && v != NULL && sel == v->index) { ShowVehicleViewWindow(v); } break; } case WID_D_SELL: case WID_D_SELL_CHAIN: { if (this->IsWidgetDisabled(widget)) return; if (this->sel == INVALID_VEHICLE) return; this->HandleButtonClick(widget); const Vehicle *v = Vehicle::Get(this->sel); this->sel = INVALID_VEHICLE; this->SetDirty(); int sell_cmd = (v->type == VEH_TRAIN && (widget == WID_D_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0; DoCommandP(v->tile, v->index | sell_cmd << 20 | MAKE_ORDER_BACKUP_FLAG, 0, GetCmdSellVeh(v->type)); break; } default: this->sel = INVALID_VEHICLE; this->SetDirty(); } _cursor.vehchain = false; } virtual void OnTimeout() { if (!this->IsWidgetDisabled(WID_D_SELL)) { this->RaiseWidget(WID_D_SELL); this->SetWidgetDirty(WID_D_SELL); } if (this->nested_array[WID_D_SELL] != NULL && !this->IsWidgetDisabled(WID_D_SELL_CHAIN)) { this->RaiseWidget(WID_D_SELL_CHAIN); this->SetWidgetDirty(WID_D_SELL_CHAIN); } } virtual void OnResize() { this->vscroll->SetCapacityFromWidget(this, WID_D_MATRIX); NWidgetCore *nwi = this->GetWidget(WID_D_MATRIX); if (this->type == VEH_TRAIN) { this->hscroll->SetCapacity(nwi->current_x - this->header_width - this->count_width); } else { this->num_columns = nwi->current_x / nwi->resize_x; } } virtual EventState OnCTRLStateChange() { if (this->sel != INVALID_VEHICLE) { _cursor.vehchain = _ctrl_pressed; this->SetWidgetDirty(WID_D_MATRIX); return ES_HANDLED; } return ES_NOT_HANDLED; } }; static void DepotSellAllConfirmationCallback(Window *win, bool confirmed) { if (confirmed) { DepotWindow *w = (DepotWindow*)win; TileIndex tile = w->window_number; byte vehtype = w->type; DoCommandP(tile, vehtype, 0, CMD_DEPOT_SELL_ALL_VEHICLES); } } /** * Opens a depot window * @param tile The tile where the depot/hangar is located * @param type The type of vehicles in the depot */ void ShowDepotWindow(TileIndex tile, VehicleType type) { if (BringWindowToFrontById(WC_VEHICLE_DEPOT, tile) != NULL) return; WindowDesc *desc; switch (type) { default: NOT_REACHED(); case VEH_TRAIN: desc = &_train_depot_desc; break; case VEH_ROAD: desc = &_road_depot_desc; break; case VEH_SHIP: desc = &_ship_depot_desc; break; case VEH_AIRCRAFT: desc = &_aircraft_depot_desc; break; } new DepotWindow(desc, tile, type); } /** * Removes the highlight of a vehicle in a depot window * @param *v Vehicle to remove all highlights from */ void DeleteDepotHighlightOfVehicle(const Vehicle *v) { DepotWindow *w; /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any depots either * If that is the case, we can skip looping though the windows and save time */ if (_special_mouse_mode != WSM_DRAGDROP) return; w = dynamic_cast(FindWindowById(WC_VEHICLE_DEPOT, v->tile)); if (w != NULL) { if (w->sel == v->index) ResetObjectToPlace(); } } openttd-1.5.3/src/tree_cmd.cpp0000644000000000000000000006050212627373435014767 0ustar rootroot/* $Id: tree_cmd.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 tree_cmd.cpp Handling of tree tiles. */ #include "stdafx.h" #include "clear_map.h" #include "landscape.h" #include "tree_map.h" #include "viewport_func.h" #include "command_func.h" #include "town.h" #include "genworld.h" #include "clear_func.h" #include "company_func.h" #include "sound_func.h" #include "water.h" #include "company_base.h" #include "core/random_func.hpp" #include "newgrf_generic.h" #include "table/strings.h" #include "table/tree_land.h" #include "table/clear_land.h" #include "safeguards.h" /** * List of tree placer algorithm. * * This enumeration defines all possible tree placer algorithm in the game. */ enum TreePlacer { TP_NONE, ///< No tree placer algorithm TP_ORIGINAL, ///< The original algorithm TP_IMPROVED, ///< A 'improved' algorithm }; /** Where to place trees while in-game? */ enum ExtraTreePlacement { ETP_NONE, ///< Place trees on no tiles ETP_RAINFOREST, ///< Place trees only on rainforest tiles ETP_ALL, ///< Place trees on all tiles }; /** Determines when to consider building more trees. */ byte _trees_tick_ctr; static const uint16 DEFAULT_TREE_STEPS = 1000; ///< Default number of attempts for placing trees. static const uint16 DEFAULT_RAINFOREST_TREE_STEPS = 15000; ///< Default number of attempts for placing extra trees at rainforest in tropic. static const uint16 EDITOR_TREE_DIV = 5; ///< Game editor tree generation divisor factor. /** * Tests if a tile can be converted to MP_TREES * This is true for clear ground without farms or rocks. * * @param tile the tile of interest * @param allow_desert Allow planting trees on CLEAR_DESERT? * @return true if trees can be built. */ static bool CanPlantTreesOnTile(TileIndex tile, bool allow_desert) { switch (GetTileType(tile)) { case MP_WATER: return !IsBridgeAbove(tile) && IsCoast(tile) && !IsSlopeWithOneCornerRaised(GetTileSlope(tile)); case MP_CLEAR: return !IsBridgeAbove(tile) && !IsClearGround(tile, CLEAR_FIELDS) && GetRawClearGround(tile) != CLEAR_ROCKS && (allow_desert || !IsClearGround(tile, CLEAR_DESERT)); default: return false; } } /** * Creates a tree tile * Ground type and density is preserved. * * @pre the tile must be suitable for trees. * * @param tile where to plant the trees. * @param treetype The type of the tree * @param count the number of trees (minus 1) * @param growth the growth status */ static void PlantTreesOnTile(TileIndex tile, TreeType treetype, uint count, uint growth) { assert(treetype != TREE_INVALID); assert(CanPlantTreesOnTile(tile, true)); TreeGround ground; uint density = 3; switch (GetTileType(tile)) { case MP_WATER: ground = TREE_GROUND_SHORE; break; case MP_CLEAR: switch (GetClearGround(tile)) { case CLEAR_GRASS: ground = TREE_GROUND_GRASS; break; case CLEAR_ROUGH: ground = TREE_GROUND_ROUGH; break; case CLEAR_SNOW: ground = GetRawClearGround(tile) == CLEAR_ROUGH ? TREE_GROUND_ROUGH_SNOW : TREE_GROUND_SNOW_DESERT; break; default: ground = TREE_GROUND_SNOW_DESERT; break; } if (GetClearGround(tile) != CLEAR_ROUGH) density = GetClearDensity(tile); break; default: NOT_REACHED(); } MakeTree(tile, treetype, count, growth, ground, density); } /** * Get a random TreeType for the given tile based on a given seed * * This function returns a random TreeType which can be placed on the given tile. * The seed for randomness must be less or equal 256, use #GB on the value of Random() * to get such a value. * * @param tile The tile to get a random TreeType from * @param seed The seed for randomness, must be less or equal 256 * @return The random tree type */ static TreeType GetRandomTreeType(TileIndex tile, uint seed) { switch (_settings_game.game_creation.landscape) { case LT_TEMPERATE: return (TreeType)(seed * TREE_COUNT_TEMPERATE / 256 + TREE_TEMPERATE); case LT_ARCTIC: return (TreeType)(seed * TREE_COUNT_SUB_ARCTIC / 256 + TREE_SUB_ARCTIC); case LT_TROPIC: switch (GetTropicZone(tile)) { case TROPICZONE_NORMAL: return (TreeType)(seed * TREE_COUNT_SUB_TROPICAL / 256 + TREE_SUB_TROPICAL); case TROPICZONE_DESERT: return (TreeType)((seed > 12) ? TREE_INVALID : TREE_CACTUS); default: return (TreeType)(seed * TREE_COUNT_RAINFOREST / 256 + TREE_RAINFOREST); } default: return (TreeType)(seed * TREE_COUNT_TOYLAND / 256 + TREE_TOYLAND); } } /** * Make a random tree tile of the given tile * * Create a new tree-tile for the given tile. The second parameter is used for * randomness like type and number of trees. * * @param tile The tile to make a tree-tile from * @param r The randomness value from a Random() value */ static void PlaceTree(TileIndex tile, uint32 r) { TreeType tree = GetRandomTreeType(tile, GB(r, 24, 8)); if (tree != TREE_INVALID) { PlantTreesOnTile(tile, tree, GB(r, 22, 2), min(GB(r, 16, 3), 6)); /* Rerandomize ground, if neither snow nor shore */ TreeGround ground = GetTreeGround(tile); if (ground != TREE_GROUND_SNOW_DESERT && ground != TREE_GROUND_ROUGH_SNOW && ground != TREE_GROUND_SHORE) { SetTreeGroundDensity(tile, (TreeGround)GB(r, 28, 1), 3); } /* Set the counter to a random start value */ SetTreeCounter(tile, (TreeGround)GB(r, 24, 4)); } } /** * Creates a number of tree groups. * The number of trees in each group depends on how many trees are actually placed around the given tile. * * @param num_groups Number of tree groups to place. */ static void PlaceTreeGroups(uint num_groups) { do { TileIndex center_tile = RandomTile(); for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) { uint32 r = Random(); int x = GB(r, 0, 5) - 16; int y = GB(r, 8, 5) - 16; uint dist = abs(x) + abs(y); TileIndex cur_tile = TileAddWrap(center_tile, x, y); IncreaseGeneratingWorldProgress(GWP_TREE); if (cur_tile != INVALID_TILE && dist <= 13 && CanPlantTreesOnTile(cur_tile, true)) { PlaceTree(cur_tile, r); } } } while (--num_groups); } /** * Place a tree at the same height as an existing tree. * * Add a new tree around the given tile which is at the same * height or at some offset (2 units) of it. * * @param tile The base tile to add a new tree somewhere around * @param height The height (like the one from the tile) */ static void PlaceTreeAtSameHeight(TileIndex tile, int height) { for (uint i = 0; i < DEFAULT_TREE_STEPS; i++) { uint32 r = Random(); int x = GB(r, 0, 5) - 16; int y = GB(r, 8, 5) - 16; TileIndex cur_tile = TileAddWrap(tile, x, y); if (cur_tile == INVALID_TILE) continue; /* Keep in range of the existing tree */ if (abs(x) + abs(y) > 16) continue; /* Clear tile, no farm-tiles or rocks */ if (!CanPlantTreesOnTile(cur_tile, true)) continue; /* Not too much height difference */ if (Delta(GetTileZ(cur_tile), height) > 2) continue; /* Place one tree and quit */ PlaceTree(cur_tile, r); break; } } /** * Place some trees randomly * * This function just place some trees randomly on the map. */ void PlaceTreesRandomly() { int i, j, ht; i = ScaleByMapSize(DEFAULT_TREE_STEPS); if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV; do { uint32 r = Random(); TileIndex tile = RandomTileSeed(r); IncreaseGeneratingWorldProgress(GWP_TREE); if (CanPlantTreesOnTile(tile, true)) { PlaceTree(tile, r); if (_settings_game.game_creation.tree_placer != TP_IMPROVED) continue; /* Place a number of trees based on the tile height. * This gives a cool effect of multiple trees close together. * It is almost real life ;) */ ht = GetTileZ(tile); /* The higher we get, the more trees we plant */ j = GetTileZ(tile) * 2; /* Above snowline more trees! */ if (_settings_game.game_creation.landscape == LT_ARCTIC && ht > GetSnowLine()) j *= 3; while (j--) { PlaceTreeAtSameHeight(tile, ht); } } } while (--i); /* place extra trees at rainforest area */ if (_settings_game.game_creation.landscape == LT_TROPIC) { i = ScaleByMapSize(DEFAULT_RAINFOREST_TREE_STEPS); if (_game_mode == GM_EDITOR) i /= EDITOR_TREE_DIV; do { uint32 r = Random(); TileIndex tile = RandomTileSeed(r); IncreaseGeneratingWorldProgress(GWP_TREE); if (GetTropicZone(tile) == TROPICZONE_RAINFOREST && CanPlantTreesOnTile(tile, false)) { PlaceTree(tile, r); } } while (--i); } } /** * Place new trees. * * This function takes care of the selected tree placer algorithm and * place randomly the trees for a new game. */ void GenerateTrees() { uint i, total; if (_settings_game.game_creation.tree_placer == TP_NONE) return; switch (_settings_game.game_creation.tree_placer) { case TP_ORIGINAL: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 15 : 6; break; case TP_IMPROVED: i = _settings_game.game_creation.landscape == LT_ARCTIC ? 4 : 2; break; default: NOT_REACHED(); } total = ScaleByMapSize(DEFAULT_TREE_STEPS); if (_settings_game.game_creation.landscape == LT_TROPIC) total += ScaleByMapSize(DEFAULT_RAINFOREST_TREE_STEPS); total *= i; uint num_groups = (_settings_game.game_creation.landscape != LT_TOYLAND) ? ScaleByMapSize(GB(Random(), 0, 5) + 25) : 0; total += num_groups * DEFAULT_TREE_STEPS; SetGeneratingWorldProgress(GWP_TREE, total); if (num_groups != 0) PlaceTreeGroups(num_groups); for (; i != 0; i--) { PlaceTreesRandomly(); } } /** * Plant a tree. * @param tile start tile of area-drag of tree plantation * @param flags type of operation * @param p1 tree type, TREE_INVALID means random. * @param p2 end tile of area-drag * @param text unused * @return the cost of this operation or an error */ CommandCost CmdPlantTree(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { StringID msg = INVALID_STRING_ID; CommandCost cost(EXPENSES_OTHER); const byte tree_to_plant = GB(p1, 0, 8); // We cannot use Extract as min and max are climate specific. if (p2 >= MapSize()) return CMD_ERROR; /* Check the tree type within the current climate */ if (tree_to_plant != TREE_INVALID && !IsInsideBS(tree_to_plant, _tree_base_by_landscape[_settings_game.game_creation.landscape], _tree_count_by_landscape[_settings_game.game_creation.landscape])) return CMD_ERROR; Company *c = (_game_mode != GM_EDITOR) ? Company::GetIfValid(_current_company) : NULL; int limit = (c == NULL ? INT32_MAX : GB(c->tree_limit, 16, 16)); TileArea ta(tile, p2); TILE_AREA_LOOP(tile, ta) { switch (GetTileType(tile)) { case MP_TREES: /* no more space for trees? */ if (_game_mode != GM_EDITOR && GetTreeCount(tile) == 4) { msg = STR_ERROR_TREE_ALREADY_HERE; continue; } /* Test tree limit. */ if (--limit < 1) { msg = STR_ERROR_TREE_PLANT_LIMIT_REACHED; break; } if (flags & DC_EXEC) { AddTreeCount(tile, 1); MarkTileDirtyByTile(tile); if (c != NULL) c->tree_limit -= 1 << 16; } /* 2x as expensive to add more trees to an existing tile */ cost.AddCost(_price[PR_BUILD_TREES] * 2); break; case MP_WATER: if (!IsCoast(tile) || IsSlopeWithOneCornerRaised(GetTileSlope(tile))) { msg = STR_ERROR_CAN_T_BUILD_ON_WATER; continue; } /* FALL THROUGH */ case MP_CLEAR: { if (IsBridgeAbove(tile)) { msg = STR_ERROR_SITE_UNSUITABLE; continue; } TreeType treetype = (TreeType)tree_to_plant; /* Be a bit picky about which trees go where. */ if (_settings_game.game_creation.landscape == LT_TROPIC && treetype != TREE_INVALID && ( /* No cacti outside the desert */ (treetype == TREE_CACTUS && GetTropicZone(tile) != TROPICZONE_DESERT) || /* No rain forest trees outside the rain forest, except in the editor mode where it makes those tiles rain forest tile */ (IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS) && GetTropicZone(tile) != TROPICZONE_RAINFOREST && _game_mode != GM_EDITOR) || /* And no subtropical trees in the desert/rain forest */ (IsInsideMM(treetype, TREE_SUB_TROPICAL, TREE_TOYLAND) && GetTropicZone(tile) != TROPICZONE_NORMAL))) { msg = STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE; continue; } /* Test tree limit. */ if (--limit < 1) { msg = STR_ERROR_TREE_PLANT_LIMIT_REACHED; break; } if (IsTileType(tile, MP_CLEAR)) { /* Remove fields or rocks. Note that the ground will get barrened */ switch (GetRawClearGround(tile)) { case CLEAR_FIELDS: case CLEAR_ROCKS: { CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); if (ret.Failed()) return ret; cost.AddCost(ret); break; } default: break; } } if (_game_mode != GM_EDITOR && Company::IsValidID(_current_company)) { Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); if (t != NULL) ChangeTownRating(t, RATING_TREE_UP_STEP, RATING_TREE_MAXIMUM, flags); } if (flags & DC_EXEC) { if (treetype == TREE_INVALID) { treetype = GetRandomTreeType(tile, GB(Random(), 24, 8)); if (treetype == TREE_INVALID) treetype = TREE_CACTUS; } /* Plant full grown trees in scenario editor */ PlantTreesOnTile(tile, treetype, 0, _game_mode == GM_EDITOR ? 3 : 0); MarkTileDirtyByTile(tile); if (c != NULL) c->tree_limit -= 1 << 16; /* When planting rainforest-trees, set tropiczone to rainforest in editor. */ if (_game_mode == GM_EDITOR && IsInsideMM(treetype, TREE_RAINFOREST, TREE_CACTUS)) { SetTropicZone(tile, TROPICZONE_RAINFOREST); } } cost.AddCost(_price[PR_BUILD_TREES]); break; } default: msg = STR_ERROR_SITE_UNSUITABLE; break; } /* Tree limit used up? No need to check more. */ if (limit < 0) break; } if (cost.GetCost() == 0) { return_cmd_error(msg); } else { return cost; } } struct TreeListEnt : PalSpriteID { byte x, y; }; static void DrawTile_Trees(TileInfo *ti) { switch (GetTreeGround(ti->tile)) { case TREE_GROUND_SHORE: DrawShoreTile(ti->tileh); break; case TREE_GROUND_GRASS: DrawClearLandTile(ti, GetTreeDensity(ti->tile)); break; case TREE_GROUND_ROUGH: DrawHillyLandTile(ti); break; default: DrawGroundSprite(_clear_land_sprites_snow_desert[GetTreeDensity(ti->tile)] + SlopeToSpriteOffset(ti->tileh), PAL_NONE); break; } /* Do not draw trees when the invisible trees setting is set */ if (IsInvisibilitySet(TO_TREES)) return; uint tmp = CountBits(ti->tile + ti->x + ti->y); uint index = GB(tmp, 0, 2) + (GetTreeType(ti->tile) << 2); /* different tree styles above one of the grounds */ if ((GetTreeGround(ti->tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(ti->tile) == TREE_GROUND_ROUGH_SNOW) && GetTreeDensity(ti->tile) >= 2 && IsInsideMM(index, TREE_SUB_ARCTIC << 2, TREE_RAINFOREST << 2)) { index += 164 - (TREE_SUB_ARCTIC << 2); } assert(index < lengthof(_tree_layout_sprite)); const PalSpriteID *s = _tree_layout_sprite[index]; const TreePos *d = _tree_layout_xy[GB(tmp, 2, 2)]; /* combine trees into one sprite object */ StartSpriteCombine(); TreeListEnt te[4]; /* put the trees to draw in a list */ uint trees = GetTreeCount(ti->tile); for (uint i = 0; i < trees; i++) { SpriteID sprite = s[0].sprite + (i == trees - 1 ? GetTreeGrowth(ti->tile) : 3); PaletteID pal = s[0].pal; te[i].sprite = sprite; te[i].pal = pal; te[i].x = d->x; te[i].y = d->y; s++; d++; } /* draw them in a sorted way */ int z = ti->z + GetSlopeMaxPixelZ(ti->tileh) / 2; for (; trees > 0; trees--) { uint min = te[0].x + te[0].y; uint mi = 0; for (uint i = 1; i < trees; i++) { if ((uint)(te[i].x + te[i].y) < min) { min = te[i].x + te[i].y; mi = i; } } AddSortableSpriteToDraw(te[mi].sprite, te[mi].pal, ti->x + te[mi].x, ti->y + te[mi].y, 16 - te[mi].x, 16 - te[mi].y, 0x30, z, IsTransparencySet(TO_TREES), -te[mi].x, -te[mi].y); /* replace the removed one with the last one */ te[mi] = te[trees - 1]; } EndSpriteCombine(); } static int GetSlopePixelZ_Trees(TileIndex tile, uint x, uint y) { int z; Slope tileh = GetTilePixelSlope(tile, &z); return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh); } static Foundation GetFoundation_Trees(TileIndex tile, Slope tileh) { return FOUNDATION_NONE; } static CommandCost ClearTile_Trees(TileIndex tile, DoCommandFlag flags) { uint num; if (Company::IsValidID(_current_company)) { Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority); if (t != NULL) ChangeTownRating(t, RATING_TREE_DOWN_STEP, RATING_TREE_MINIMUM, flags); } num = GetTreeCount(tile); if (IsInsideMM(GetTreeType(tile), TREE_RAINFOREST, TREE_CACTUS)) num *= 4; if (flags & DC_EXEC) DoClearSquare(tile); return CommandCost(EXPENSES_CONSTRUCTION, num * _price[PR_CLEAR_TREES]); } static void GetTileDesc_Trees(TileIndex tile, TileDesc *td) { TreeType tt = GetTreeType(tile); if (IsInsideMM(tt, TREE_RAINFOREST, TREE_CACTUS)) { td->str = STR_LAI_TREE_NAME_RAINFOREST; } else { td->str = tt == TREE_CACTUS ? STR_LAI_TREE_NAME_CACTUS_PLANTS : STR_LAI_TREE_NAME_TREES; } td->owner[0] = GetTileOwner(tile); } static void TileLoopTreesDesert(TileIndex tile) { switch (GetTropicZone(tile)) { case TROPICZONE_DESERT: if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT) { SetTreeGroundDensity(tile, TREE_GROUND_SNOW_DESERT, 3); MarkTileDirtyByTile(tile); } break; case TROPICZONE_RAINFOREST: { static const SoundFx forest_sounds[] = { SND_42_LOON_BIRD, SND_43_LION, SND_44_MONKEYS, SND_48_DISTANT_BIRD }; uint32 r = Random(); if (Chance16I(1, 200, r) && _settings_client.sound.ambient) SndPlayTileFx(forest_sounds[GB(r, 16, 2)], tile); break; } default: break; } } static void TileLoopTreesAlps(TileIndex tile) { int k = GetTileZ(tile) - GetSnowLine() + 1; if (k < 0) { switch (GetTreeGround(tile)) { case TREE_GROUND_SNOW_DESERT: SetTreeGroundDensity(tile, TREE_GROUND_GRASS, 3); break; case TREE_GROUND_ROUGH_SNOW: SetTreeGroundDensity(tile, TREE_GROUND_ROUGH, 3); break; default: return; } } else { uint density = min(k, 3); if (GetTreeGround(tile) != TREE_GROUND_SNOW_DESERT && GetTreeGround(tile) != TREE_GROUND_ROUGH_SNOW) { TreeGround tg = GetTreeGround(tile) == TREE_GROUND_ROUGH ? TREE_GROUND_ROUGH_SNOW : TREE_GROUND_SNOW_DESERT; SetTreeGroundDensity(tile, tg, density); } else if (GetTreeDensity(tile) != density) { SetTreeGroundDensity(tile, GetTreeGround(tile), density); } else { if (GetTreeDensity(tile) == 3) { uint32 r = Random(); if (Chance16I(1, 200, r) && _settings_client.sound.ambient) { SndPlayTileFx((r & 0x80000000) ? SND_39_HEAVY_WIND : SND_34_WIND, tile); } } return; } } MarkTileDirtyByTile(tile); } static void TileLoop_Trees(TileIndex tile) { if (GetTreeGround(tile) == TREE_GROUND_SHORE) { TileLoop_Water(tile); } else { switch (_settings_game.game_creation.landscape) { case LT_TROPIC: TileLoopTreesDesert(tile); break; case LT_ARCTIC: TileLoopTreesAlps(tile); break; } } AmbientSoundEffect(tile); uint treeCounter = GetTreeCounter(tile); /* Handle growth of grass (under trees/on MP_TREES tiles) at every 8th processings, like it's done for grass on MP_CLEAR tiles. */ if ((treeCounter & 7) == 7 && GetTreeGround(tile) == TREE_GROUND_GRASS) { uint density = GetTreeDensity(tile); if (density < 3) { SetTreeGroundDensity(tile, TREE_GROUND_GRASS, density + 1); MarkTileDirtyByTile(tile); } } if (GetTreeCounter(tile) < 15) { AddTreeCounter(tile, 1); return; } SetTreeCounter(tile, 0); switch (GetTreeGrowth(tile)) { case 3: // regular sized tree if (_settings_game.game_creation.landscape == LT_TROPIC && GetTreeType(tile) != TREE_CACTUS && GetTropicZone(tile) == TROPICZONE_DESERT) { AddTreeGrowth(tile, 1); } else { switch (GB(Random(), 0, 3)) { case 0: // start destructing AddTreeGrowth(tile, 1); break; case 1: // add a tree if (GetTreeCount(tile) < 4) { AddTreeCount(tile, 1); SetTreeGrowth(tile, 0); break; } /* FALL THROUGH */ case 2: { // add a neighbouring tree /* Don't plant extra trees if that's not allowed. */ if ((_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_RAINFOREST) ? _settings_game.construction.extra_tree_placement == ETP_NONE : _settings_game.construction.extra_tree_placement != ETP_ALL) { break; } TreeType treetype = GetTreeType(tile); tile += TileOffsByDir((Direction)(Random() & 7)); /* Cacti don't spread */ if (!CanPlantTreesOnTile(tile, false)) return; /* Don't plant trees, if ground was freshly cleared */ if (IsTileType(tile, MP_CLEAR) && GetClearGround(tile) == CLEAR_GRASS && GetClearDensity(tile) != 3) return; PlantTreesOnTile(tile, treetype, 0, 0); break; } default: return; } } break; case 6: // final stage of tree destruction if (GetTreeCount(tile) > 1) { /* more than one tree, delete it */ AddTreeCount(tile, -1); SetTreeGrowth(tile, 3); } else { /* just one tree, change type into MP_CLEAR */ switch (GetTreeGround(tile)) { case TREE_GROUND_SHORE: MakeShore(tile); break; case TREE_GROUND_GRASS: MakeClear(tile, CLEAR_GRASS, GetTreeDensity(tile)); break; case TREE_GROUND_ROUGH: MakeClear(tile, CLEAR_ROUGH, 3); break; case TREE_GROUND_ROUGH_SNOW: { uint density = GetTreeDensity(tile); MakeClear(tile, CLEAR_ROUGH, 3); MakeSnow(tile, density); break; } default: // snow or desert if (_settings_game.game_creation.landscape == LT_TROPIC) { MakeClear(tile, CLEAR_DESERT, GetTreeDensity(tile)); } else { uint density = GetTreeDensity(tile); MakeClear(tile, CLEAR_GRASS, 3); MakeSnow(tile, density); } break; } } break; default: AddTreeGrowth(tile, 1); break; } MarkTileDirtyByTile(tile); } void OnTick_Trees() { /* Don't place trees if that's not allowed */ if (_settings_game.construction.extra_tree_placement == ETP_NONE) return; uint32 r; TileIndex tile; TreeType tree; /* place a tree at a random rainforest spot */ if (_settings_game.game_creation.landscape == LT_TROPIC && (r = Random(), tile = RandomTileSeed(r), GetTropicZone(tile) == TROPICZONE_RAINFOREST) && CanPlantTreesOnTile(tile, false) && (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { PlantTreesOnTile(tile, tree, 0, 0); } /* byte underflow */ if (--_trees_tick_ctr != 0 || _settings_game.construction.extra_tree_placement != ETP_ALL) return; /* place a tree at a random spot */ r = Random(); tile = RandomTileSeed(r); if (CanPlantTreesOnTile(tile, false) && (tree = GetRandomTreeType(tile, GB(r, 24, 8))) != TREE_INVALID) { PlantTreesOnTile(tile, tree, 0, 0); } } static TrackStatus GetTileTrackStatus_Trees(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { return 0; } static void ChangeTileOwner_Trees(TileIndex tile, Owner old_owner, Owner new_owner) { /* not used */ } void InitializeTrees() { _trees_tick_ctr = 0; } static CommandCost TerraformTile_Trees(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } extern const TileTypeProcs _tile_type_trees_procs = { DrawTile_Trees, // draw_tile_proc GetSlopePixelZ_Trees, // get_slope_z_proc ClearTile_Trees, // clear_tile_proc NULL, // add_accepted_cargo_proc GetTileDesc_Trees, // get_tile_desc_proc GetTileTrackStatus_Trees, // get_tile_track_status_proc NULL, // click_tile_proc NULL, // animate_tile_proc TileLoop_Trees, // tile_loop_proc ChangeTileOwner_Trees, // change_tile_owner_proc NULL, // add_produced_cargo_proc NULL, // vehicle_enter_tile_proc GetFoundation_Trees, // get_foundation_proc TerraformTile_Trees, // terraform_tile_proc }; openttd-1.5.3/src/object_cmd.cpp0000644000000000000000000006734312627373441015305 0ustar rootroot/* $Id: object_cmd.cpp 26879 2014-09-21 11:24:51Z rubidium $ */ /* * 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 object_cmd.cpp Handling of object tiles. */ #include "stdafx.h" #include "landscape.h" #include "command_func.h" #include "viewport_func.h" #include "company_base.h" #include "town.h" #include "bridge_map.h" #include "genworld.h" #include "autoslope.h" #include "clear_func.h" #include "water.h" #include "window_func.h" #include "company_gui.h" #include "cheat_type.h" #include "object.h" #include "cargopacket.h" #include "core/random_func.hpp" #include "core/pool_func.hpp" #include "object_map.h" #include "object_base.h" #include "newgrf_config.h" #include "newgrf_object.h" #include "date_func.h" #include "newgrf_debug.h" #include "vehicle_func.h" #include "table/strings.h" #include "table/object_land.h" #include "safeguards.h" ObjectPool _object_pool("Object"); INSTANTIATE_POOL_METHODS(Object) uint16 Object::counts[NUM_OBJECTS]; /** * Get the object associated with a tile. * @param tile The tile to fetch the object for. * @return The object. */ /* static */ Object *Object::GetByTile(TileIndex tile) { return Object::Get(GetObjectIndex(tile)); } /** * Gets the ObjectType of the given object tile * @param t the tile to get the type from. * @pre IsTileType(t, MP_OBJECT) * @return the type. */ ObjectType GetObjectType(TileIndex t) { assert(IsTileType(t, MP_OBJECT)); return Object::GetByTile(t)->type; } /** Initialize/reset the objects. */ void InitializeObjects() { Object::ResetTypeCounts(); } /** * Actually build the object. * @param type The type of object to build. * @param tile The tile to build the northern tile of the object on. * @param owner The owner of the object. * @param town Town the tile is related with. * @param view The view for the object. * @pre All preconditions for building the object at that location * are met, e.g. slope and clearness of tiles are checked. */ void BuildObject(ObjectType type, TileIndex tile, CompanyID owner, Town *town, uint8 view) { const ObjectSpec *spec = ObjectSpec::Get(type); TileArea ta(tile, GB(spec->size, HasBit(view, 0) ? 4 : 0, 4), GB(spec->size, HasBit(view, 0) ? 0 : 4, 4)); Object *o = new Object(); o->type = type; o->location = ta; o->town = town == NULL ? CalcClosestTownFromTile(tile) : town; o->build_date = _date; o->view = view; /* If nothing owns the object, the colour will be random. Otherwise * get the colour from the company's livery settings. */ if (owner == OWNER_NONE) { o->colour = Random(); } else { const Livery *l = Company::Get(owner)->livery; o->colour = l->colour1 + l->colour2 * 16; } /* If the object wants only one colour, then give it that colour. */ if ((spec->flags & OBJECT_FLAG_2CC_COLOUR) == 0) o->colour &= 0xF; if (HasBit(spec->callback_mask, CBM_OBJ_COLOUR)) { uint16 res = GetObjectCallback(CBID_OBJECT_COLOUR, o->colour, 0, spec, o, tile); if (res != CALLBACK_FAILED) { if (res >= 0x100) ErrorUnknownCallbackResult(spec->grf_prop.grffile->grfid, CBID_OBJECT_COLOUR, res); o->colour = GB(res, 0, 8); } } assert(o->town != NULL); TILE_AREA_LOOP(t, ta) { WaterClass wc = (IsWaterTile(t) ? GetWaterClass(t) : WATER_CLASS_INVALID); /* Update company infrastructure counts for objects build on canals owned by nobody. */ if (wc == WATER_CLASS_CANAL && owner != OWNER_NONE && (IsTileOwner(tile, OWNER_NONE) || IsTileOwner(tile, OWNER_WATER))) { Company::Get(owner)->infrastructure.water++; DirtyCompanyInfrastructureWindows(owner); } MakeObject(t, owner, o->index, wc, Random()); MarkTileDirtyByTile(t); } Object::IncTypeCount(type); if (spec->flags & OBJECT_FLAG_ANIMATION) TriggerObjectAnimation(o, OAT_BUILT, spec); } /** * Increase the animation stage of a whole structure. * @param tile The tile of the structure. */ static void IncreaseAnimationStage(TileIndex tile) { TileArea ta = Object::GetByTile(tile)->location; TILE_AREA_LOOP(t, ta) { SetAnimationFrame(t, GetAnimationFrame(t) + 1); MarkTileDirtyByTile(t); } } /** We encode the company HQ size in the animation stage. */ #define GetCompanyHQSize GetAnimationFrame /** We encode the company HQ size in the animation stage. */ #define IncreaseCompanyHQSize IncreaseAnimationStage /** * Update the CompanyHQ to the state associated with the given score * @param tile The (northern) tile of the company HQ, or INVALID_TILE. * @param score The current (performance) score of the company. */ void UpdateCompanyHQ(TileIndex tile, uint score) { if (tile == INVALID_TILE) return; byte val; (val = 0, score < 170) || (val++, score < 350) || (val++, score < 520) || (val++, score < 720) || (val++, true); while (GetCompanyHQSize(tile) < val) { IncreaseCompanyHQSize(tile); } } /** * Updates the colour of the object whenever a company changes. * @param c The company the company colour changed of. */ void UpdateObjectColours(const Company *c) { Object *obj; FOR_ALL_OBJECTS(obj) { Owner owner = GetTileOwner(obj->location.tile); /* Not the current owner, so colour doesn't change. */ if (owner != c->index) continue; const ObjectSpec *spec = ObjectSpec::GetByTile(obj->location.tile); /* Using the object colour callback, so not using company colour. */ if (HasBit(spec->callback_mask, CBM_OBJ_COLOUR)) continue; const Livery *l = c->livery; obj->colour = ((spec->flags & OBJECT_FLAG_2CC_COLOUR) ? (l->colour2 * 16) : 0) + l->colour1; } } extern CommandCost CheckBuildableTile(TileIndex tile, uint invalid_dirs, int &allowed_z, bool allow_steep, bool check_bridge); static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags); /** * Build an object object * @param tile tile where the object will be located * @param flags type of operation * @param p1 the object type to build * @param p2 the view for the object * @param text unused * @return the cost of this operation or an error */ CommandCost CmdBuildObject(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { CommandCost cost(EXPENSES_PROPERTY); ObjectType type = (ObjectType)GB(p1, 0, 16); if (type >= NUM_OBJECTS) return CMD_ERROR; uint8 view = GB(p2, 0, 2); const ObjectSpec *spec = ObjectSpec::Get(type); if (_game_mode == GM_NORMAL && !spec->IsAvailable() && !_generating_world) return CMD_ERROR; if ((_game_mode == GM_EDITOR || _generating_world) && !spec->WasEverAvailable()) return CMD_ERROR; if ((spec->flags & OBJECT_FLAG_ONLY_IN_SCENEDIT) != 0 && ((!_generating_world && _game_mode != GM_EDITOR) || _current_company != OWNER_NONE)) return CMD_ERROR; if ((spec->flags & OBJECT_FLAG_ONLY_IN_GAME) != 0 && (_generating_world || _game_mode != GM_NORMAL || _current_company > MAX_COMPANIES)) return CMD_ERROR; if (view >= spec->views) return CMD_ERROR; if (!Object::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_OBJECTS); if (Town::GetNumItems() == 0) return_cmd_error(STR_ERROR_MUST_FOUND_TOWN_FIRST); int size_x = GB(spec->size, HasBit(view, 0) ? 4 : 0, 4); int size_y = GB(spec->size, HasBit(view, 0) ? 0 : 4, 4); TileArea ta(tile, size_x, size_y); if (type == OBJECT_OWNED_LAND) { /* Owned land is special as it can be placed on any slope. */ cost.AddCost(DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR)); } else { /* Check the surface to build on. At this time we can't actually execute the * the CLEAR_TILE commands since the newgrf callback later on can check * some information about the tiles. */ bool allow_water = (spec->flags & (OBJECT_FLAG_BUILT_ON_WATER | OBJECT_FLAG_NOT_ON_LAND)) != 0; bool allow_ground = (spec->flags & OBJECT_FLAG_NOT_ON_LAND) == 0; TILE_AREA_LOOP(t, ta) { if (HasTileWaterGround(t)) { if (!allow_water) return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER); if (!IsWaterTile(t)) { /* Normal water tiles don't have to be cleared. For all other tile types clear * the tile but leave the water. */ cost.AddCost(DoCommand(t, 0, 0, flags & ~DC_NO_WATER & ~DC_EXEC, CMD_LANDSCAPE_CLEAR)); } else { /* Can't build on water owned by another company. */ Owner o = GetTileOwner(t); if (o != OWNER_NONE && o != OWNER_WATER) cost.AddCost(CheckOwnership(o, t)); /* However, the tile has to be clear of vehicles. */ cost.AddCost(EnsureNoVehicleOnGround(t)); } } else { if (!allow_ground) return_cmd_error(STR_ERROR_MUST_BE_BUILT_ON_WATER); /* For non-water tiles, we'll have to clear it before building. */ cost.AddCost(DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR)); } } /* So, now the surface is checked... check the slope of said surface. */ int allowed_z; if (GetTileSlope(tile, &allowed_z) != SLOPE_FLAT) allowed_z++; TILE_AREA_LOOP(t, ta) { uint16 callback = CALLBACK_FAILED; if (HasBit(spec->callback_mask, CBM_OBJ_SLOPE_CHECK)) { TileIndex diff = t - tile; callback = GetObjectCallback(CBID_OBJECT_LAND_SLOPE_CHECK, GetTileSlope(t), TileY(diff) << 4 | TileX(diff), spec, NULL, t, view); } if (callback == CALLBACK_FAILED) { cost.AddCost(CheckBuildableTile(t, 0, allowed_z, false, false)); } else { /* The meaning of bit 10 is inverted for a grf version < 8. */ if (spec->grf_prop.grffile->grf_version < 8) ToggleBit(callback, 10); CommandCost ret = GetErrorMessageFromLocationCallbackResult(callback, spec->grf_prop.grffile, STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION); if (ret.Failed()) return ret; } } if (flags & DC_EXEC) { /* This is basically a copy of the loop above with the exception that we now * execute the commands and don't check for errors, since that's already done. */ TILE_AREA_LOOP(t, ta) { if (HasTileWaterGround(t)) { if (!IsWaterTile(t)) { DoCommand(t, 0, 0, (flags & ~DC_NO_WATER) | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR); } } else { DoCommand(t, 0, 0, flags | DC_NO_MODIFY_TOWN_RATING, CMD_LANDSCAPE_CLEAR); } } } } if (cost.Failed()) return cost; /* Finally do a check for bridges. */ TILE_AREA_LOOP(t, ta) { if (IsBridgeAbove(t) && ( !(spec->flags & OBJECT_FLAG_ALLOW_UNDER_BRIDGE) || (GetTileMaxZ(t) + spec->height >= GetBridgeHeight(GetSouthernBridgeEnd(t))))) { return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST); } } int hq_score = 0; switch (type) { case OBJECT_TRANSMITTER: case OBJECT_LIGHTHOUSE: if (!IsTileFlat(tile)) return_cmd_error(STR_ERROR_FLAT_LAND_REQUIRED); break; case OBJECT_OWNED_LAND: if (IsTileType(tile, MP_OBJECT) && IsTileOwner(tile, _current_company) && IsObjectType(tile, OBJECT_OWNED_LAND)) { return_cmd_error(STR_ERROR_YOU_ALREADY_OWN_IT); } break; case OBJECT_HQ: { Company *c = Company::Get(_current_company); if (c->location_of_HQ != INVALID_TILE) { /* We need to persuade a bit harder to remove the old HQ. */ _current_company = OWNER_WATER; cost.AddCost(ClearTile_Object(c->location_of_HQ, flags)); _current_company = c->index; } if (flags & DC_EXEC) { hq_score = UpdateCompanyRatingAndValue(c, false); c->location_of_HQ = tile; SetWindowDirty(WC_COMPANY, c->index); } break; } case OBJECT_STATUE: /* This may never be constructed using this method. */ return CMD_ERROR; default: // i.e. NewGRF provided. break; } if (flags & DC_EXEC) { BuildObject(type, tile, _current_company, NULL, view); /* Make sure the HQ starts at the right size. */ if (type == OBJECT_HQ) UpdateCompanyHQ(tile, hq_score); } cost.AddCost(ObjectSpec::Get(type)->GetBuildCost() * size_x * size_y); return cost; } static Foundation GetFoundation_Object(TileIndex tile, Slope tileh); static void DrawTile_Object(TileInfo *ti) { ObjectType type = GetObjectType(ti->tile); const ObjectSpec *spec = ObjectSpec::Get(type); /* Fall back for when the object doesn't exist anymore. */ if (!spec->enabled) type = OBJECT_TRANSMITTER; if ((spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) == 0) DrawFoundation(ti, GetFoundation_Object(ti->tile, ti->tileh)); if (type < NEW_OBJECT_OFFSET) { const DrawTileSprites *dts = NULL; Owner to = GetTileOwner(ti->tile); PaletteID palette = to == OWNER_NONE ? PAL_NONE : COMPANY_SPRITE_COLOUR(to); if (type == OBJECT_HQ) { TileIndex diff = ti->tile - Object::GetByTile(ti->tile)->location.tile; dts = &_object_hq[GetCompanyHQSize(ti->tile) << 2 | TileY(diff) << 1 | TileX(diff)]; } else { dts = &_objects[type]; } if (spec->flags & OBJECT_FLAG_HAS_NO_FOUNDATION) { /* If an object has no foundation, but tries to draw a (flat) ground * type... we have to be nice and convert that for them. */ switch (dts->ground.sprite) { case SPR_FLAT_BARE_LAND: DrawClearLandTile(ti, 0); break; case SPR_FLAT_1_THIRD_GRASS_TILE: DrawClearLandTile(ti, 1); break; case SPR_FLAT_2_THIRD_GRASS_TILE: DrawClearLandTile(ti, 2); break; case SPR_FLAT_GRASS_TILE: DrawClearLandTile(ti, 3); break; default: DrawGroundSprite(dts->ground.sprite, palette); break; } } else { DrawGroundSprite(dts->ground.sprite, palette); } if (!IsInvisibilitySet(TO_STRUCTURES)) { const DrawTileSeqStruct *dtss; foreach_draw_tile_seq(dtss, dts->seq) { AddSortableSpriteToDraw( dtss->image.sprite, palette, ti->x + dtss->delta_x, ti->y + dtss->delta_y, dtss->size_x, dtss->size_y, dtss->size_z, ti->z + dtss->delta_z, IsTransparencySet(TO_STRUCTURES) ); } } } else { DrawNewObjectTile(ti, spec); } DrawBridgeMiddle(ti); } static int GetSlopePixelZ_Object(TileIndex tile, uint x, uint y) { if (IsObjectType(tile, OBJECT_OWNED_LAND)) { int z; Slope tileh = GetTilePixelSlope(tile, &z); return z + GetPartialPixelZ(x & 0xF, y & 0xF, tileh); } else { return GetTileMaxPixelZ(tile); } } static Foundation GetFoundation_Object(TileIndex tile, Slope tileh) { return IsObjectType(tile, OBJECT_OWNED_LAND) ? FOUNDATION_NONE : FlatteningFoundation(tileh); } /** * Perform the actual removal of the object from the map. * @param o The object to really clear. */ static void ReallyClearObjectTile(Object *o) { Object::DecTypeCount(o->type); TILE_AREA_LOOP(tile_cur, o->location) { DeleteNewGRFInspectWindow(GSF_OBJECTS, tile_cur); MakeWaterKeepingClass(tile_cur, GetTileOwner(tile_cur)); } delete o; } SmallVector _cleared_object_areas; /** * Find the entry in _cleared_object_areas which occupies a certain tile. * @param tile Tile of interest * @return Occupying entry, or NULL if none */ ClearedObjectArea *FindClearedObject(TileIndex tile) { TileArea ta = TileArea(tile, 1, 1); const ClearedObjectArea *end = _cleared_object_areas.End(); for (ClearedObjectArea *coa = _cleared_object_areas.Begin(); coa != end; coa++) { if (coa->area.Intersects(ta)) return coa; } return NULL; } static CommandCost ClearTile_Object(TileIndex tile, DoCommandFlag flags) { /* Get to the northern most tile. */ Object *o = Object::GetByTile(tile); TileArea ta = o->location; ObjectType type = o->type; const ObjectSpec *spec = ObjectSpec::Get(type); CommandCost cost(EXPENSES_CONSTRUCTION, spec->GetClearCost() * ta.w * ta.h / 5); if (spec->flags & OBJECT_FLAG_CLEAR_INCOME) cost.MultiplyCost(-1); // They get an income! /* Towns can't remove any objects. */ if (_current_company == OWNER_TOWN) return CMD_ERROR; /* Water can remove everything! */ if (_current_company != OWNER_WATER) { if ((flags & DC_NO_WATER) && IsTileOnWater(tile)) { /* There is water under the object, treat it as water tile. */ return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER); } else if (!(spec->flags & OBJECT_FLAG_AUTOREMOVE) && (flags & DC_AUTO)) { /* No automatic removal by overbuilding stuff. */ return_cmd_error(type == OBJECT_HQ ? STR_ERROR_COMPANY_HEADQUARTERS_IN : STR_ERROR_OBJECT_IN_THE_WAY); } else if (_game_mode == GM_EDITOR) { /* No further limitations for the editor. */ } else if (GetTileOwner(tile) == OWNER_NONE) { /* Owned by nobody and unremovable, so we can only remove it with brute force! */ if (!_cheats.magic_bulldozer.value && (spec->flags & OBJECT_FLAG_CANNOT_REMOVE) != 0) return CMD_ERROR; } else if (CheckTileOwnership(tile).Failed()) { /* We don't own it!. */ return_cmd_error(STR_ERROR_OWNED_BY); } else if ((spec->flags & OBJECT_FLAG_CANNOT_REMOVE) != 0 && (spec->flags & OBJECT_FLAG_AUTOREMOVE) == 0) { /* In the game editor or with cheats we can remove, otherwise we can't. */ if (!_cheats.magic_bulldozer.value) return CMD_ERROR; /* Removing with the cheat costs more in TTDPatch / the specs. */ cost.MultiplyCost(25); } } else if ((spec->flags & (OBJECT_FLAG_BUILT_ON_WATER | OBJECT_FLAG_NOT_ON_LAND)) != 0) { /* Water can't remove objects that are buildable on water. */ return CMD_ERROR; } switch (type) { case OBJECT_HQ: { Company *c = Company::Get(GetTileOwner(tile)); if (flags & DC_EXEC) { c->location_of_HQ = INVALID_TILE; // reset HQ position SetWindowDirty(WC_COMPANY, c->index); CargoPacket::InvalidateAllFrom(ST_HEADQUARTERS, c->index); } /* cost of relocating company is 1% of company value */ cost = CommandCost(EXPENSES_PROPERTY, CalculateCompanyValue(c) / 100); break; } case OBJECT_STATUE: if (flags & DC_EXEC) { Town *town = o->town; ClrBit(town->statues, GetTileOwner(tile)); SetWindowDirty(WC_TOWN_AUTHORITY, town->index); } break; default: break; } ClearedObjectArea *cleared_area = _cleared_object_areas.Append(); cleared_area->first_tile = tile; cleared_area->area = ta; if (flags & DC_EXEC) ReallyClearObjectTile(o); return cost; } static void AddAcceptedCargo_Object(TileIndex tile, CargoArray &acceptance, uint32 *always_accepted) { if (!IsObjectType(tile, OBJECT_HQ)) return; /* HQ accepts passenger and mail; but we have to divide the values * between 4 tiles it occupies! */ /* HQ level (depends on company performance) in the range 1..5. */ uint level = GetCompanyHQSize(tile) + 1; /* Top town building generates 10, so to make HQ interesting, the top * type makes 20. */ acceptance[CT_PASSENGERS] += max(1U, level); SetBit(*always_accepted, CT_PASSENGERS); /* Top town building generates 4, HQ can make up to 8. The * proportion passengers:mail is different because such a huge * commercial building generates unusually high amount of mail * correspondence per physical visitor. */ acceptance[CT_MAIL] += max(1U, level / 2); SetBit(*always_accepted, CT_MAIL); } static void GetTileDesc_Object(TileIndex tile, TileDesc *td) { const ObjectSpec *spec = ObjectSpec::GetByTile(tile); td->str = spec->name; td->owner[0] = GetTileOwner(tile); td->build_date = Object::GetByTile(tile)->build_date; if (spec->grf_prop.grffile != NULL) { td->grf = GetGRFConfig(spec->grf_prop.grffile->grfid)->GetName(); } } static void TileLoop_Object(TileIndex tile) { const ObjectSpec *spec = ObjectSpec::GetByTile(tile); if (spec->flags & OBJECT_FLAG_ANIMATION) { Object *o = Object::GetByTile(tile); TriggerObjectTileAnimation(o, tile, OAT_TILELOOP, spec); if (o->location.tile == tile) TriggerObjectAnimation(o, OAT_256_TICKS, spec); } if (IsTileOnWater(tile)) TileLoop_Water(tile); if (!IsObjectType(tile, OBJECT_HQ)) return; /* HQ accepts passenger and mail; but we have to divide the values * between 4 tiles it occupies! */ /* HQ level (depends on company performance) in the range 1..5. */ uint level = GetCompanyHQSize(tile) + 1; assert(level < 6); StationFinder stations(TileArea(tile, 2, 2)); uint r = Random(); /* Top town buildings generate 250, so the top HQ type makes 256. */ if (GB(r, 0, 8) < (256 / 4 / (6 - level))) { uint amt = GB(r, 0, 8) / 8 / 4 + 1; if (EconomyIsInRecession()) amt = (amt + 1) >> 1; MoveGoodsToStation(CT_PASSENGERS, amt, ST_HEADQUARTERS, GetTileOwner(tile), stations.GetStations()); } /* Top town building generates 90, HQ can make up to 196. The * proportion passengers:mail is about the same as in the acceptance * equations. */ if (GB(r, 8, 8) < (196 / 4 / (6 - level))) { uint amt = GB(r, 8, 8) / 8 / 4 + 1; if (EconomyIsInRecession()) amt = (amt + 1) >> 1; MoveGoodsToStation(CT_MAIL, amt, ST_HEADQUARTERS, GetTileOwner(tile), stations.GetStations()); } } static TrackStatus GetTileTrackStatus_Object(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side) { return 0; } static bool ClickTile_Object(TileIndex tile) { if (!IsObjectType(tile, OBJECT_HQ)) return false; ShowCompany(GetTileOwner(tile)); return true; } static void AnimateTile_Object(TileIndex tile) { AnimateNewObjectTile(tile); } /** * Helper function for \c CircularTileSearch. * @param tile The tile to check. * @param user Ignored. * @return True iff the tile has a radio tower. */ static bool HasTransmitter(TileIndex tile, void *user) { return IsObjectTypeTile(tile, OBJECT_TRANSMITTER); } /** * Try to build a lighthouse. * @return True iff building a lighthouse succeeded. */ static bool TryBuildLightHouse() { uint maxx = MapMaxX(); uint maxy = MapMaxY(); uint r = Random(); /* Scatter the lighthouses more evenly around the perimeter */ int perimeter = (GB(r, 16, 16) % (2 * (maxx + maxy))) - maxy; DiagDirection dir; for (dir = DIAGDIR_NE; perimeter > 0; dir++) { perimeter -= (DiagDirToAxis(dir) == AXIS_X) ? maxx : maxy; } TileIndex tile; switch (dir) { default: case DIAGDIR_NE: tile = TileXY(maxx - 1, r % maxy); break; case DIAGDIR_SE: tile = TileXY(r % maxx, 1); break; case DIAGDIR_SW: tile = TileXY(1, r % maxy); break; case DIAGDIR_NW: tile = TileXY(r % maxx, maxy - 1); break; } /* Only build lighthouses at tiles where the border is sea. */ if (!IsTileType(tile, MP_WATER)) return false; for (int j = 0; j < 19; j++) { int h; if (IsTileType(tile, MP_CLEAR) && IsTileFlat(tile, &h) && h <= 2 && !IsBridgeAbove(tile)) { BuildObject(OBJECT_LIGHTHOUSE, tile); assert(tile < MapSize()); return true; } tile += TileOffsByDiagDir(dir); if (!IsValidTile(tile)) return false; } return false; } /** * Try to build a transmitter. * @return True iff a transmitter was built. */ static bool TryBuildTransmitter() { TileIndex tile = RandomTile(); int h; if (IsTileType(tile, MP_CLEAR) && IsTileFlat(tile, &h) && h >= 4 && !IsBridgeAbove(tile)) { TileIndex t = tile; if (CircularTileSearch(&t, 9, HasTransmitter, NULL)) return false; BuildObject(OBJECT_TRANSMITTER, tile); return true; } return false; } void GenerateObjects() { /* Set a guestimate on how much we progress */ SetGeneratingWorldProgress(GWP_OBJECT, NUM_OBJECTS); /* Determine number of water tiles at map border needed for freeform_edges */ uint num_water_tiles = 0; if (_settings_game.construction.freeform_edges) { for (uint x = 0; x < MapMaxX(); x++) { if (IsTileType(TileXY(x, 1), MP_WATER)) num_water_tiles++; if (IsTileType(TileXY(x, MapMaxY() - 1), MP_WATER)) num_water_tiles++; } for (uint y = 1; y < MapMaxY() - 1; y++) { if (IsTileType(TileXY(1, y), MP_WATER)) num_water_tiles++; if (IsTileType(TileXY(MapMaxX() - 1, y), MP_WATER)) num_water_tiles++; } } /* Iterate over all possible object types */ for (uint i = 0; i < NUM_OBJECTS; i++) { const ObjectSpec *spec = ObjectSpec::Get(i); /* Continue, if the object was never available till now or shall not be placed */ if (!spec->WasEverAvailable() || spec->generate_amount == 0) continue; uint16 amount = spec->generate_amount; /* Scale by map size */ if ((spec->flags & OBJECT_FLAG_SCALE_BY_WATER) && _settings_game.construction.freeform_edges) { /* Scale the amount of lighthouses with the amount of land at the borders. * The -6 is because the top borders are MP_VOID (-2) and all corners * are counted twice (-4). */ amount = ScaleByMapSize1D(amount * num_water_tiles) / (2 * MapMaxY() + 2 * MapMaxX() - 6); } else if (spec->flags & OBJECT_FLAG_SCALE_BY_WATER) { amount = ScaleByMapSize1D(amount); } else { amount = ScaleByMapSize(amount); } /* Now try to place the requested amount of this object */ for (uint j = ScaleByMapSize(1000); j != 0 && amount != 0 && Object::CanAllocateItem(); j--) { switch (i) { case OBJECT_TRANSMITTER: if (TryBuildTransmitter()) amount--; break; case OBJECT_LIGHTHOUSE: if (TryBuildLightHouse()) amount--; break; default: uint8 view = RandomRange(spec->views); if (CmdBuildObject(RandomTile(), DC_EXEC | DC_AUTO | DC_NO_TEST_TOWN_RATING | DC_NO_MODIFY_TOWN_RATING, i, view, NULL).Succeeded()) amount--; break; } } IncreaseGeneratingWorldProgress(GWP_OBJECT); } } static void ChangeTileOwner_Object(TileIndex tile, Owner old_owner, Owner new_owner) { if (!IsTileOwner(tile, old_owner)) return; if (IsObjectType(tile, OBJECT_OWNED_LAND) && new_owner != INVALID_OWNER) { SetTileOwner(tile, new_owner); } else if (IsObjectType(tile, OBJECT_STATUE)) { Town *t = Object::GetByTile(tile)->town; ClrBit(t->statues, old_owner); if (new_owner != INVALID_OWNER && !HasBit(t->statues, new_owner)) { /* Transfer ownership to the new company */ SetBit(t->statues, new_owner); SetTileOwner(tile, new_owner); } else { ReallyClearObjectTile(Object::GetByTile(tile)); } SetWindowDirty(WC_TOWN_AUTHORITY, t->index); } else { ReallyClearObjectTile(Object::GetByTile(tile)); } } static CommandCost TerraformTile_Object(TileIndex tile, DoCommandFlag flags, int z_new, Slope tileh_new) { ObjectType type = GetObjectType(tile); if (type == OBJECT_OWNED_LAND) { /* Owned land remains unsold */ CommandCost ret = CheckTileOwnership(tile); if (ret.Succeeded()) return CommandCost(); } else if (AutoslopeEnabled() && type != OBJECT_TRANSMITTER && type != OBJECT_LIGHTHOUSE) { /* Behaviour: * - Both new and old slope must not be steep. * - TileMaxZ must not be changed. * - Allow autoslope by default. * - Disallow autoslope if callback succeeds and returns non-zero. */ Slope tileh_old = GetTileSlope(tile); /* TileMaxZ must not be changed. Slopes must not be steep. */ if (!IsSteepSlope(tileh_old) && !IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) { const ObjectSpec *spec = ObjectSpec::Get(type); /* Call callback 'disable autosloping for objects'. */ if (HasBit(spec->callback_mask, CBM_OBJ_AUTOSLOPE)) { /* If the callback fails, allow autoslope. */ uint16 res = GetObjectCallback(CBID_OBJECT_AUTOSLOPE, 0, 0, spec, Object::GetByTile(tile), tile); if (res == CALLBACK_FAILED || !ConvertBooleanCallback(spec->grf_prop.grffile, CBID_OBJECT_AUTOSLOPE, res)) return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } else if (spec->enabled) { /* allow autoslope */ return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]); } } } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } extern const TileTypeProcs _tile_type_object_procs = { DrawTile_Object, // draw_tile_proc GetSlopePixelZ_Object, // get_slope_z_proc ClearTile_Object, // clear_tile_proc AddAcceptedCargo_Object, // add_accepted_cargo_proc GetTileDesc_Object, // get_tile_desc_proc GetTileTrackStatus_Object, // get_tile_track_status_proc ClickTile_Object, // click_tile_proc AnimateTile_Object, // animate_tile_proc TileLoop_Object, // tile_loop_proc ChangeTileOwner_Object, // change_tile_owner_proc NULL, // add_produced_cargo_proc NULL, // vehicle_enter_tile_proc GetFoundation_Object, // get_foundation_proc TerraformTile_Object, // terraform_tile_proc }; openttd-1.5.3/src/water_map.h0000644000000000000000000003274012627373441014631 0ustar rootroot/* $Id: water_map.h 26878 2014-09-21 11:23:33Z rubidium $ */ /* * 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 water_map.h Map accessors for water tiles. */ #ifndef WATER_MAP_H #define WATER_MAP_H #include "depot_type.h" #include "tile_map.h" /** * Bit field layout of m5 for water tiles. */ enum WaterTileTypeBitLayout { WBL_TYPE_BEGIN = 4, ///< Start of the 'type' bitfield. WBL_TYPE_COUNT = 4, ///< Length of the 'type' bitfield. WBL_TYPE_NORMAL = 0x0, ///< Clear water or coast ('type' bitfield). WBL_TYPE_LOCK = 0x1, ///< Lock ('type' bitfield). WBL_TYPE_DEPOT = 0x8, ///< Depot ('type' bitfield). WBL_COAST_FLAG = 0, ///< Flag for coast. WBL_LOCK_ORIENT_BEGIN = 0, ///< Start of lock orientiation bitfield. WBL_LOCK_ORIENT_COUNT = 2, ///< Length of lock orientiation bitfield. WBL_LOCK_PART_BEGIN = 2, ///< Start of lock part bitfield. WBL_LOCK_PART_COUNT = 2, ///< Length of lock part bitfield. WBL_DEPOT_PART = 0, ///< Depot part flag. WBL_DEPOT_AXIS = 1, ///< Depot axis flag. }; /** Available water tile types. */ enum WaterTileType { WATER_TILE_CLEAR, ///< Plain water. WATER_TILE_COAST, ///< Coast. WATER_TILE_LOCK, ///< Water lock. WATER_TILE_DEPOT, ///< Water Depot. }; /** classes of water (for #WATER_TILE_CLEAR water tile type). */ enum WaterClass { WATER_CLASS_SEA, ///< Sea. WATER_CLASS_CANAL, ///< Canal. WATER_CLASS_RIVER, ///< River. WATER_CLASS_INVALID, ///< Used for industry tiles on land (also for oilrig if newgrf says so). }; /** Helper information for extract tool. */ template <> struct EnumPropsT : MakeEnumPropsT {}; /** Sections of the water depot. */ enum DepotPart { DEPOT_PART_NORTH = 0, ///< Northern part of a depot. DEPOT_PART_SOUTH = 1, ///< Southern part of a depot. DEPOT_PART_END }; /** Sections of the water lock. */ enum LockPart { LOCK_PART_MIDDLE = 0, ///< Middle part of a lock. LOCK_PART_LOWER = 1, ///< Lower part of a lock. LOCK_PART_UPPER = 2, ///< Upper part of a lock. }; /** * Get the water tile type at a tile. * @param t Water tile to query. * @return Water tile type at the tile. */ static inline WaterTileType GetWaterTileType(TileIndex t) { assert(IsTileType(t, MP_WATER)); switch (GB(_m[t].m5, WBL_TYPE_BEGIN, WBL_TYPE_COUNT)) { case WBL_TYPE_NORMAL: return HasBit(_m[t].m5, WBL_COAST_FLAG) ? WATER_TILE_COAST : WATER_TILE_CLEAR; case WBL_TYPE_LOCK: return WATER_TILE_LOCK; case WBL_TYPE_DEPOT: return WATER_TILE_DEPOT; default: NOT_REACHED(); } } /** * Checks whether the tile has an waterclass associated. * You can then subsequently call GetWaterClass(). * @param t Tile to query. * @return True if the tiletype has a waterclass. */ static inline bool HasTileWaterClass(TileIndex t) { return IsTileType(t, MP_WATER) || IsTileType(t, MP_STATION) || IsTileType(t, MP_INDUSTRY) || IsTileType(t, MP_OBJECT); } /** * Get the water class at a tile. * @param t Water tile to query. * @pre IsTileType(t, MP_WATER) || IsTileType(t, MP_STATION) || IsTileType(t, MP_INDUSTRY) || IsTileType(t, MP_OBJECT) * @return Water class at the tile. */ static inline WaterClass GetWaterClass(TileIndex t) { assert(HasTileWaterClass(t)); return (WaterClass)GB(_m[t].m1, 5, 2); } /** * Set the water class at a tile. * @param t Water tile to change. * @param wc New water class. * @pre IsTileType(t, MP_WATER) || IsTileType(t, MP_STATION) || IsTileType(t, MP_INDUSTRY) || IsTileType(t, MP_OBJECT) */ static inline void SetWaterClass(TileIndex t, WaterClass wc) { assert(HasTileWaterClass(t)); SB(_m[t].m1, 5, 2, wc); } /** * Tests if the tile was built on water. * @param t the tile to check * @pre IsTileType(t, MP_WATER) || IsTileType(t, MP_STATION) || IsTileType(t, MP_INDUSTRY) || IsTileType(t, MP_OBJECT) * @return true iff on water */ static inline bool IsTileOnWater(TileIndex t) { return (GetWaterClass(t) != WATER_CLASS_INVALID); } /** * Is it a plain water tile? * @param t Water tile to query. * @return \c true if any type of clear water like ocean, river, or canal. * @pre IsTileType(t, MP_WATER) */ static inline bool IsWater(TileIndex t) { return GetWaterTileType(t) == WATER_TILE_CLEAR; } /** * Is it a sea water tile? * @param t Water tile to query. * @return \c true if it is a sea water tile. * @pre IsTileType(t, MP_WATER) */ static inline bool IsSea(TileIndex t) { return IsWater(t) && GetWaterClass(t) == WATER_CLASS_SEA; } /** * Is it a canal tile? * @param t Water tile to query. * @return \c true if it is a canal tile. * @pre IsTileType(t, MP_WATER) */ static inline bool IsCanal(TileIndex t) { return IsWater(t) && GetWaterClass(t) == WATER_CLASS_CANAL; } /** * Is it a river water tile? * @param t Water tile to query. * @return \c true if it is a river water tile. * @pre IsTileType(t, MP_WATER) */ static inline bool IsRiver(TileIndex t) { return IsWater(t) && GetWaterClass(t) == WATER_CLASS_RIVER; } /** * Is it a water tile with plain water? * @param t Tile to query. * @return \c true if it is a plain water tile. */ static inline bool IsWaterTile(TileIndex t) { return IsTileType(t, MP_WATER) && IsWater(t); } /** * Is it a coast tile? * @param t Water tile to query. * @return \c true if it is a sea water tile. * @pre IsTileType(t, MP_WATER) */ static inline bool IsCoast(TileIndex t) { return GetWaterTileType(t) == WATER_TILE_COAST; } /** * Is it a coast tile * @param t Tile to query. * @return \c true if it is a coast. */ static inline bool IsCoastTile(TileIndex t) { return IsTileType(t, MP_WATER) && IsCoast(t); } /** * Is it a water tile with a ship depot on it? * @param t Water tile to query. * @return \c true if it is a ship depot tile. * @pre IsTileType(t, MP_WATER) */ static inline bool IsShipDepot(TileIndex t) { return GetWaterTileType(t) == WATER_TILE_DEPOT; } /** * Is it a ship depot tile? * @param t Tile to query. * @return \c true if it is a ship depot tile. */ static inline bool IsShipDepotTile(TileIndex t) { return IsTileType(t, MP_WATER) && IsShipDepot(t); } /** * Get the axis of the ship depot. * @param t Water tile to query. * @return Axis of the depot. * @pre IsShipDepotTile(t) */ static inline Axis GetShipDepotAxis(TileIndex t) { assert(IsShipDepotTile(t)); return (Axis)GB(_m[t].m5, WBL_DEPOT_AXIS, 1); } /** * Get the part of a ship depot. * @param t Water tile to query. * @return Part of the depot. * @pre IsShipDepotTile(t) */ static inline DepotPart GetShipDepotPart(TileIndex t) { assert(IsShipDepotTile(t)); return (DepotPart)GB(_m[t].m5, WBL_DEPOT_PART, 1); } /** * Get the direction of the ship depot. * @param t Water tile to query. * @return Direction of the depot. * @pre IsShipDepotTile(t) */ static inline DiagDirection GetShipDepotDirection(TileIndex t) { return XYNSToDiagDir(GetShipDepotAxis(t), GetShipDepotPart(t)); } /** * Get the other tile of the ship depot. * @param t Tile to query, containing one section of a ship depot. * @return Tile containing the other section of the depot. * @pre IsShipDepotTile(t) */ static inline TileIndex GetOtherShipDepotTile(TileIndex t) { return t + (GetShipDepotPart(t) != DEPOT_PART_NORTH ? -1 : 1) * (GetShipDepotAxis(t) != AXIS_X ? TileDiffXY(0, 1) : TileDiffXY(1, 0)); } /** * Get the most northern tile of a ship depot. * @param t One of the tiles of the ship depot. * @return The northern tile of the depot. * @pre IsShipDepotTile(t) */ static inline TileIndex GetShipDepotNorthTile(TileIndex t) { assert(IsShipDepot(t)); TileIndex tile2 = GetOtherShipDepotTile(t); return t < tile2 ? t : tile2; } /** * Is there a lock on a given water tile? * @param t Water tile to query. * @return \c true if it is a water lock tile. * @pre IsTileType(t, MP_WATER) */ static inline bool IsLock(TileIndex t) { return GetWaterTileType(t) == WATER_TILE_LOCK; } /** * Get the direction of the water lock. * @param t Water tile to query. * @return Direction of the lock. * @pre IsTileType(t, MP_WATER) && IsLock(t) */ static inline DiagDirection GetLockDirection(TileIndex t) { assert(IsLock(t)); return (DiagDirection)GB(_m[t].m5, WBL_LOCK_ORIENT_BEGIN, WBL_LOCK_ORIENT_COUNT); } /** * Get the part of a lock. * @param t Water tile to query. * @return The part. * @pre IsTileType(t, MP_WATER) && IsLock(t) */ static inline byte GetLockPart(TileIndex t) { assert(IsLock(t)); return GB(_m[t].m5, WBL_LOCK_PART_BEGIN, WBL_LOCK_PART_COUNT); } /** * Get the random bits of the water tile. * @param t Water tile to query. * @return Random bits of the tile. * @pre IsTileType(t, MP_WATER) */ static inline byte GetWaterTileRandomBits(TileIndex t) { assert(IsTileType(t, MP_WATER)); return _m[t].m4; } /** * Checks whether the tile has water at the ground. * That is, it is either some plain water tile, or a object/industry/station/... with water under it. * @return true iff the tile has water at the ground. * @note Coast tiles are not considered waterish, even if there is water on a halftile. */ static inline bool HasTileWaterGround(TileIndex t) { return HasTileWaterClass(t) && IsTileOnWater(t) && !IsCoastTile(t); } /** * Helper function to make a coast tile. * @param t The tile to change into water */ static inline void MakeShore(TileIndex t) { SetTileType(t, MP_WATER); SetTileOwner(t, OWNER_WATER); SetWaterClass(t, WATER_CLASS_SEA); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = WBL_TYPE_NORMAL << WBL_TYPE_BEGIN | 1 << WBL_COAST_FLAG; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } /** * Helper function for making a watery tile. * @param t The tile to change into water * @param o The owner of the water * @param wc The class of water the tile has to be * @param random_bits Eventual random bits to be set for this tile */ static inline void MakeWater(TileIndex t, Owner o, WaterClass wc, uint8 random_bits) { SetTileType(t, MP_WATER); SetTileOwner(t, o); SetWaterClass(t, wc); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = random_bits; _m[t].m5 = WBL_TYPE_NORMAL << WBL_TYPE_BEGIN; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } /** * Make a sea tile. * @param t The tile to change into sea */ static inline void MakeSea(TileIndex t) { MakeWater(t, OWNER_WATER, WATER_CLASS_SEA, 0); } /** * Make a river tile * @param t The tile to change into river * @param random_bits Random bits to be set for this tile */ static inline void MakeRiver(TileIndex t, uint8 random_bits) { MakeWater(t, OWNER_WATER, WATER_CLASS_RIVER, random_bits); } /** * Make a canal tile * @param t The tile to change into canal * @param o The owner of the canal * @param random_bits Random bits to be set for this tile */ static inline void MakeCanal(TileIndex t, Owner o, uint8 random_bits) { assert(o != OWNER_WATER); MakeWater(t, o, WATER_CLASS_CANAL, random_bits); } /** * Make a ship depot section. * @param t Tile to place the ship depot section. * @param o Owner of the depot. * @param did Depot ID. * @param part Depot part (either #DEPOT_PART_NORTH or #DEPOT_PART_SOUTH). * @param a Axis of the depot. * @param original_water_class Original water class. */ static inline void MakeShipDepot(TileIndex t, Owner o, DepotID did, DepotPart part, Axis a, WaterClass original_water_class) { SetTileType(t, MP_WATER); SetTileOwner(t, o); SetWaterClass(t, original_water_class); _m[t].m2 = did; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = WBL_TYPE_DEPOT << WBL_TYPE_BEGIN | part << WBL_DEPOT_PART | a << WBL_DEPOT_AXIS; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } /** * Make a lock section. * @param t Tile to place the water lock section. * @param o Owner of the lock. * @param part Part to place. * @param dir Lock orientation * @param original_water_class Original water class. * @see MakeLock */ static inline void MakeLockTile(TileIndex t, Owner o, LockPart part, DiagDirection dir, WaterClass original_water_class) { SetTileType(t, MP_WATER); SetTileOwner(t, o); SetWaterClass(t, original_water_class); _m[t].m2 = 0; _m[t].m3 = 0; _m[t].m4 = 0; _m[t].m5 = WBL_TYPE_LOCK << WBL_TYPE_BEGIN | part << WBL_LOCK_PART_BEGIN | dir << WBL_LOCK_ORIENT_BEGIN; SB(_me[t].m6, 2, 4, 0); _me[t].m7 = 0; } /** * Make a water lock. * @param t Tile to place the water lock section. * @param o Owner of the lock. * @param d Direction of the water lock. * @param wc_lower Original water class of the lower part. * @param wc_upper Original water class of the upper part. * @param wc_middle Original water class of the middle part. */ static inline void MakeLock(TileIndex t, Owner o, DiagDirection d, WaterClass wc_lower, WaterClass wc_upper, WaterClass wc_middle) { TileIndexDiff delta = TileOffsByDiagDir(d); /* Keep the current waterclass and owner for the tiles. * It allows to restore them after the lock is deleted */ MakeLockTile(t, o, LOCK_PART_MIDDLE, d, wc_middle); MakeLockTile(t - delta, IsWaterTile(t - delta) ? GetTileOwner(t - delta) : o, LOCK_PART_LOWER, d, wc_lower); MakeLockTile(t + delta, IsWaterTile(t + delta) ? GetTileOwner(t + delta) : o, LOCK_PART_UPPER, d, wc_upper); } #endif /* WATER_MAP_H */ openttd-1.5.3/src/sprite.h0000644000000000000000000001514312627373435014161 0ustar rootroot/* $Id: sprite.h 23706 2012-01-01 17:36:19Z smatz $ */ /* * 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 sprite.h Base for drawing complex sprites. */ #ifndef SPRITE_H #define SPRITE_H #include "transparency.h" #include "table/sprites.h" #define GENERAL_SPRITE_COLOUR(colour) ((colour) + PALETTE_RECOLOUR_START) #define COMPANY_SPRITE_COLOUR(owner) (GENERAL_SPRITE_COLOUR(_company_colours[owner])) /* The following describes bunch of sprites to be drawn together in a single 3D * bounding box. Used especially for various multi-sprite buildings (like * depots or stations): */ /** A tile child sprite and palette to draw for stations etc, with 3D bounding box */ struct DrawTileSeqStruct { int8 delta_x; ///< \c 0x80 is sequence terminator int8 delta_y; int8 delta_z; ///< \c 0x80 identifies child sprites byte size_x; byte size_y; byte size_z; PalSpriteID image; /** Make this struct a sequence terminator. */ void MakeTerminator() { this->delta_x = (int8)0x80; } /** Check whether this is a sequence terminator. */ bool IsTerminator() const { return (byte)this->delta_x == 0x80; } /** Check whether this is a parent sprite with a boundingbox. */ bool IsParentSprite() const { return (byte)this->delta_z != 0x80; } }; /** * Ground palette sprite of a tile, together with its sprite layout. * This struct is used for static sprite layouts in the code. * For allocated ones from NewGRF see #NewGRFSpriteLayout. */ struct DrawTileSprites { PalSpriteID ground; ///< Palette and sprite for the ground const DrawTileSeqStruct *seq; ///< Array of child sprites. Terminated with a terminator entry }; /** * This structure is the same for both Industries and Houses. * Buildings here reference a general type of construction */ struct DrawBuildingsTileStruct { PalSpriteID ground; PalSpriteID building; byte subtile_x; byte subtile_y; byte width; byte height; byte dz; byte draw_proc; // this allows to specify a special drawing procedure. }; /** Iterate through all DrawTileSeqStructs in DrawTileSprites. */ #define foreach_draw_tile_seq(idx, list) for (idx = list; !idx->IsTerminator(); idx++) void DrawCommonTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, int32 orig_offset, uint32 newgrf_offset, PaletteID default_palette, bool child_offset_is_unsigned); void DrawCommonTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32 orig_offset, uint32 newgrf_offset, PaletteID default_palette, bool child_offset_is_unsigned); /** * Draw tile sprite sequence on tile with railroad specifics. * @param total_offset Spriteoffset from normal rail to current railtype. * @param newgrf_offset Startsprite of the Action1 to use. */ static inline void DrawRailTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, int32 total_offset, uint32 newgrf_offset, PaletteID default_palette) { DrawCommonTileSeq(ti, dts, to, total_offset, newgrf_offset, default_palette, false); } /** * Draw tile sprite sequence in GUI with railroad specifics. * @param total_offset Spriteoffset from normal rail to current railtype. * @param newgrf_offset Startsprite of the Action1 to use. */ static inline void DrawRailTileSeqInGUI(int x, int y, const DrawTileSprites *dts, int32 total_offset, uint32 newgrf_offset, PaletteID default_palette) { DrawCommonTileSeqInGUI(x, y, dts, total_offset, newgrf_offset, default_palette, false); } /** * Draw TTD sprite sequence on tile. */ static inline void DrawOrigTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, PaletteID default_palette) { DrawCommonTileSeq(ti, dts, to, 0, 0, default_palette, false); } /** * Draw TTD sprite sequence in GUI. */ static inline void DrawOrigTileSeqInGUI(int x, int y, const DrawTileSprites *dts, PaletteID default_palette) { DrawCommonTileSeqInGUI(x, y, dts, 0, 0, default_palette, false); } /** * Draw NewGRF industrytile or house sprite layout * @param stage Sprite inside the Action1 spritesets to use, i.e. construction stage. */ static inline void DrawNewGRFTileSeq(const struct TileInfo *ti, const DrawTileSprites *dts, TransparencyOption to, uint32 stage, PaletteID default_palette) { DrawCommonTileSeq(ti, dts, to, 0, stage, default_palette, true); } /** * Draw NewGRF object in GUI * @param stage Sprite inside the Action1 spritesets to use, i.e. construction stage. */ static inline void DrawNewGRFTileSeqInGUI(int x, int y, const DrawTileSprites *dts, uint32 stage, PaletteID default_palette) { DrawCommonTileSeqInGUI(x, y, dts, 0, stage, default_palette, true); } /** * Applies PALETTE_MODIFIER_TRANSPARENT and PALETTE_MODIFIER_COLOUR to a palette entry of a sprite layout entry * @note for ground sprites use #GroundSpritePaletteTransform * @note Not useable for OTTD internal spritelayouts from table/xxx_land.h as PALETTE_MODIFIER_TRANSPARENT is only set * when to use the default palette. * * @param image The sprite to draw * @param pal The palette from the sprite layout * @param default_pal The default recolour sprite to use (typically company colour resp. random industry/house colour) * @return The palette to use */ static inline PaletteID SpriteLayoutPaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal) { if (HasBit(image, PALETTE_MODIFIER_TRANSPARENT) || HasBit(image, PALETTE_MODIFIER_COLOUR)) { return (pal != 0 ? pal : default_pal); } else { return PAL_NONE; } } /** * Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite * @note Not useable for OTTD internal spritelayouts from table/xxx_land.h as PALETTE_MODIFIER_TRANSPARENT is only set * when to use the default palette. * * @param image The sprite to draw * @param pal The palette from the sprite layout * @param default_pal The default recolour sprite to use (typically company colour resp. random industry/house colour) * @return The palette to use */ static inline PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal) { if (HasBit(image, PALETTE_MODIFIER_COLOUR)) { return (pal != 0 ? pal : default_pal); } else { return PAL_NONE; } } #endif /* SPRITE_H */ openttd-1.5.3/src/statusbar_gui.cpp0000644000000000000000000002214212627373442016055 0ustar rootroot/* $Id: statusbar_gui.cpp 27146 2015-02-13 21:13:45Z frosch $ */ /* * 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 statusbar_gui.cpp The GUI for the bottom status bar. */ #include "stdafx.h" #include "date_func.h" #include "gfx_func.h" #include "news_func.h" #include "company_func.h" #include "string_func.h" #include "strings_func.h" #include "company_base.h" #include "tilehighlight_func.h" #include "news_gui.h" #include "company_gui.h" #include "window_gui.h" #include "saveload/saveload.h" #include "window_func.h" #include "statusbar_gui.h" #include "toolbar_gui.h" #include "core/geometry_func.hpp" #include "widgets/statusbar_widget.h" #include "table/strings.h" #include "table/sprites.h" #include "safeguards.h" static bool DrawScrollingStatusText(const NewsItem *ni, int scroll_pos, int left, int right, int top, int bottom) { CopyInDParam(0, ni->params, lengthof(ni->params)); StringID str = ni->string_id; char buf[512]; GetString(buf, str, lastof(buf)); const char *s = buf; char buffer[256]; char *d = buffer; const char *last = lastof(buffer); for (;;) { WChar c = Utf8Consume(&s); if (c == 0) { break; } else if (c == '\n') { if (d + 4 >= last) break; d[0] = d[1] = d[2] = d[3] = ' '; d += 4; } else if (IsPrintable(c)) { if (d + Utf8CharLen(c) >= last) break; d += Utf8Encode(d, c); } } *d = '\0'; DrawPixelInfo tmp_dpi; if (!FillDrawPixelInfo(&tmp_dpi, left, top, right - left, bottom)) return true; int width = GetStringBoundingBox(buffer).width; int pos = (_current_text_dir == TD_RTL) ? (scroll_pos - width) : (right - scroll_pos - left); DrawPixelInfo *old_dpi = _cur_dpi; _cur_dpi = &tmp_dpi; DrawString(pos, INT16_MAX, 0, buffer, TC_LIGHT_BLUE, SA_LEFT | SA_FORCE); _cur_dpi = old_dpi; return (_current_text_dir == TD_RTL) ? (pos < right - left) : (pos + width > 0); } struct StatusBarWindow : Window { bool saving; int ticker_scroll; int reminder_timeout; static const int TICKER_STOP = 1640; ///< scrolling is finished when counter reaches this value static const int REMINDER_START = 91; ///< initial value of the reminder counter (right dot on the right) static const int REMINDER_STOP = 0; ///< reminder disappears when counter reaches this value static const int COUNTER_STEP = 2; ///< this is subtracted from active counters every tick StatusBarWindow(WindowDesc *desc) : Window(desc) { this->ticker_scroll = TICKER_STOP; this->reminder_timeout = REMINDER_STOP; this->InitNested(); CLRBITS(this->flags, WF_WHITE_BORDER); PositionStatusbar(this); } virtual Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) { Point pt = { 0, _screen.height - sm_height }; return pt; } virtual void FindWindowPlacementAndResize(int def_width, int def_height) { Window::FindWindowPlacementAndResize(_toolbar_width, def_height); } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { Dimension d; switch (widget) { case WID_S_LEFT: SetDParamMaxValue(0, MAX_YEAR * DAYS_IN_YEAR); d = GetStringBoundingBox(STR_WHITE_DATE_LONG); break; case WID_S_RIGHT: { int64 max_money = UINT32_MAX; const Company *c; FOR_ALL_COMPANIES(c) max_money = max(c->money, max_money); SetDParam(0, 100LL * max_money); d = GetStringBoundingBox(STR_COMPANY_MONEY); break; } default: return; } d.width += padding.width; d.height += padding.height; *size = maxdim(d, *size); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_S_LEFT: /* Draw the date */ SetDParam(0, _date); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER); break; case WID_S_RIGHT: { /* Draw company money, if any */ const Company *c = Company::GetIfValid(_local_company); if (c != NULL) { SetDParam(0, c->money); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_COMPANY_MONEY, TC_FROMSTRING, SA_HOR_CENTER); } break; } case WID_S_MIDDLE: /* Draw status bar */ if (this->saving) { // true when saving is active DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_SAVING_GAME, TC_FROMSTRING, SA_HOR_CENTER); } else if (_do_autosave) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_AUTOSAVE, TC_FROMSTRING, SA_HOR_CENTER); } else if (_pause_mode != PM_UNPAUSED) { DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_PAUSED, TC_FROMSTRING, SA_HOR_CENTER); } else if (this->ticker_scroll < TICKER_STOP && FindWindowById(WC_NEWS_WINDOW, 0) == NULL && _statusbar_news_item != NULL && _statusbar_news_item->string_id != 0) { /* Draw the scrolling news text */ if (!DrawScrollingStatusText(_statusbar_news_item, this->ticker_scroll, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, r.bottom)) { InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED); if (Company::IsValidID(_local_company)) { /* This is the default text */ SetDParam(0, _local_company); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_HOR_CENTER); } } } else { if (Company::IsValidID(_local_company)) { /* This is the default text */ SetDParam(0, _local_company); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_STATUSBAR_COMPANY_NAME, TC_FROMSTRING, SA_HOR_CENTER); } } if (this->reminder_timeout > 0) { Dimension icon_size = GetSpriteSize(SPR_UNREAD_NEWS); DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, r.right - WD_FRAMERECT_RIGHT - icon_size.width, r.top + WD_FRAMERECT_TOP + (int)(FONT_HEIGHT_NORMAL - icon_size.height) / 2); } 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; switch (data) { default: NOT_REACHED(); case SBI_SAVELOAD_START: this->saving = true; break; case SBI_SAVELOAD_FINISH: this->saving = false; break; case SBI_SHOW_TICKER: this->ticker_scroll = 0; break; case SBI_SHOW_REMINDER: this->reminder_timeout = REMINDER_START; break; case SBI_NEWS_DELETED: this->ticker_scroll = TICKER_STOP; // reset ticker ... this->reminder_timeout = REMINDER_STOP; // ... and reminder break; } } virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { case WID_S_MIDDLE: ShowLastNewsMessage(); break; case WID_S_RIGHT: if (_local_company != COMPANY_SPECTATOR) ShowCompanyFinances(_local_company); break; default: ResetObjectToPlace(); } } virtual void OnTick() { if (_pause_mode != PM_UNPAUSED) return; if (this->ticker_scroll < TICKER_STOP) { // Scrolling text this->ticker_scroll += COUNTER_STEP; this->SetWidgetDirty(WID_S_MIDDLE); } if (this->reminder_timeout > REMINDER_STOP) { // Red blot to show there are new unread newsmessages this->reminder_timeout -= COUNTER_STEP; } else if (this->reminder_timeout < REMINDER_STOP) { this->reminder_timeout = REMINDER_STOP; this->SetWidgetDirty(WID_S_MIDDLE); } } }; static const NWidgetPart _nested_main_status_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_GREY, WID_S_LEFT), SetMinimalSize(140, 12), EndContainer(), NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_MIDDLE), SetMinimalSize(40, 12), SetDataTip(0x0, STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS), SetResize(1, 0), NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_S_RIGHT), SetMinimalSize(140, 12), EndContainer(), }; static WindowDesc _main_status_desc( WDP_MANUAL, NULL, 0, 0, WC_STATUS_BAR, WC_NONE, WDF_NO_FOCUS, _nested_main_status_widgets, lengthof(_nested_main_status_widgets) ); /** * Checks whether the news ticker is currently being used. */ bool IsNewsTickerShown() { const StatusBarWindow *w = dynamic_cast(FindWindowById(WC_STATUS_BAR, 0)); return w != NULL && w->ticker_scroll < StatusBarWindow::TICKER_STOP; } /** * Show our status bar. */ void ShowStatusBar() { new StatusBarWindow(&_main_status_desc); } openttd-1.5.3/src/landscape_type.h0000644000000000000000000000223412627373435015643 0ustar rootroot/* $Id: landscape_type.h 17248 2009-08-21 20:21:05Z rubidium $ */ /* * 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 landscape_type.h Types related to the landscape. */ #ifndef LANDSCAPE_TYPE_H #define LANDSCAPE_TYPE_H typedef byte LandscapeID; ///< Landscape type. @see LandscapeType /** Landscape types */ enum LandscapeType { LT_TEMPERATE = 0, LT_ARCTIC = 1, LT_TROPIC = 2, LT_TOYLAND = 3, NUM_LANDSCAPE = 4, }; /** * For storing the water borders which shall be retained. */ enum Borders { BORDER_NE = 0, BORDER_SE = 1, BORDER_SW = 2, BORDER_NW = 3, BORDERS_RANDOM = 16, }; #endif /* LANDSCAPE_TYPE_H */ openttd-1.5.3/src/intro_gui.cpp0000644000000000000000000002744212627373435015212 0ustar rootroot/* $Id: intro_gui.cpp 26986 2014-10-09 21:16:29Z frosch $ */ /* * 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 intro_gui.cpp The main menu GUI. */ #include "stdafx.h" #include "error.h" #include "gui.h" #include "window_gui.h" #include "textbuf_gui.h" #include "network/network.h" #include "genworld.h" #include "network/network_gui.h" #include "network/network_content.h" #include "landscape_type.h" #include "strings_func.h" #include "fios.h" #include "ai/ai_gui.hpp" #include "gfx_func.h" #include "core/geometry_func.hpp" #include "language.h" #include "rev.h" #include "highscore.h" #include "widgets/intro_widget.h" #include "table/strings.h" #include "table/sprites.h" #include "safeguards.h" struct SelectGameWindow : public Window { SelectGameWindow(WindowDesc *desc) : Window(desc) { this->CreateNestedTree(); this->FinishInitNested(0); this->OnInvalidateData(); } /** * 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->SetWidgetLoweredState(WID_SGI_TEMPERATE_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_TEMPERATE); this->SetWidgetLoweredState(WID_SGI_ARCTIC_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_ARCTIC); this->SetWidgetLoweredState(WID_SGI_TROPIC_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_TROPIC); this->SetWidgetLoweredState(WID_SGI_TOYLAND_LANDSCAPE, _settings_newgame.game_creation.landscape == LT_TOYLAND); } virtual void OnInit() { bool missing = _current_language->missing >= _settings_client.gui.missing_strings_threshold && !IsReleasedVersion(); this->GetWidget(WID_SGI_TRANSLATION_SELECTION)->SetDisplayedPlane(missing ? 0 : SZSP_NONE); } virtual void DrawWidget(const Rect &r, int widget) const { switch (widget) { case WID_SGI_TRANSLATION: SetDParam(0, _current_language->missing); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_INTRO_TRANSLATION, TC_FROMSTRING, SA_CENTER); break; } } virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_SGI_TRANSLATION: { SetDParam(0, _current_language->missing); int height = GetStringHeight(STR_INTRO_TRANSLATION, size->width); if (height > 3 * FONT_HEIGHT_NORMAL) { /* Don't let the window become too high. */ Dimension textdim = GetStringBoundingBox(STR_INTRO_TRANSLATION); textdim.height *= 3; textdim.width -= textdim.width / 2; *size = maxdim(*size, textdim); } else { size->height = height + padding.height; } break; } } } virtual void OnClick(Point pt, int widget, int click_count) { #ifdef ENABLE_NETWORK /* Do not create a network server when you (just) have closed one of the game * creation/load windows for the network server. */ if (IsInsideMM(widget, WID_SGI_GENERATE_GAME, WID_SGI_EDIT_SCENARIO + 1)) _is_network_server = false; #endif /* ENABLE_NETWORK */ switch (widget) { case WID_SGI_GENERATE_GAME: if (_ctrl_pressed) { StartNewGameWithoutGUI(GENERATE_NEW_SEED); } else { ShowGenerateLandscape(); } break; case WID_SGI_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break; case WID_SGI_PLAY_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break; case WID_SGI_PLAY_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break; case WID_SGI_EDIT_SCENARIO: StartScenarioEditor(); break; case WID_SGI_PLAY_NETWORK: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else { ShowNetworkGameWindow(); } break; case WID_SGI_TEMPERATE_LANDSCAPE: case WID_SGI_ARCTIC_LANDSCAPE: case WID_SGI_TROPIC_LANDSCAPE: case WID_SGI_TOYLAND_LANDSCAPE: SetNewLandscapeType(widget - WID_SGI_TEMPERATE_LANDSCAPE); break; case WID_SGI_OPTIONS: ShowGameOptions(); break; case WID_SGI_HIGHSCORE: ShowHighscoreTable(); break; case WID_SGI_SETTINGS_OPTIONS:ShowGameSettings(); break; case WID_SGI_GRF_SETTINGS: ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break; case WID_SGI_CONTENT_DOWNLOAD: if (!_network_available) { ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR); } else { ShowNetworkContentListWindow(); } break; case WID_SGI_AI_SETTINGS: ShowAIConfigWindow(); break; case WID_SGI_EXIT: HandleExitGameRequest(); break; } } }; static const NWidgetPart _nested_select_game_widgets[] = { NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_INTRO_CAPTION, STR_NULL), NWidget(WWT_PANEL, COLOUR_BROWN), NWidget(NWID_SPACER), SetMinimalSize(0, 8), /* 'generate game' and 'load game' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_GENERATE_GAME), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_NEW_GAME, STR_INTRO_TOOLTIP_NEW_GAME), SetPadding(0, 0, 0, 10), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_LOAD_GAME), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_LOAD_GAME, STR_INTRO_TOOLTIP_LOAD_GAME), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), /* 'play scenario' and 'play heightmap' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_PLAY_SCENARIO), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_PLAY_SCENARIO, STR_INTRO_TOOLTIP_PLAY_SCENARIO), SetPadding(0, 0, 0, 10), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_PLAY_HEIGHTMAP), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_PLAY_HEIGHTMAP, STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), /* 'edit scenario' and 'play multiplayer' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_EDIT_SCENARIO), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_SCENARIO_EDITOR, STR_INTRO_TOOLTIP_SCENARIO_EDITOR), SetPadding(0, 0, 0, 10), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_PLAY_NETWORK), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_MULTIPLAYER, STR_INTRO_TOOLTIP_MULTIPLAYER), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 7), /* climate selection buttons */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(10, 0), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_SGI_TEMPERATE_LANDSCAPE), SetMinimalSize(77, 55), SetDataTip(SPR_SELECT_TEMPERATE, STR_INTRO_TOOLTIP_TEMPERATE), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_SGI_ARCTIC_LANDSCAPE), SetMinimalSize(77, 55), SetDataTip(SPR_SELECT_SUB_ARCTIC, STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_SGI_TROPIC_LANDSCAPE), SetMinimalSize(77, 55), SetDataTip(SPR_SELECT_SUB_TROPICAL, STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), NWidget(WWT_IMGBTN_2, COLOUR_ORANGE, WID_SGI_TOYLAND_LANDSCAPE), SetMinimalSize(77, 55), SetDataTip(SPR_SELECT_TOYLAND, STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE), NWidget(NWID_SPACER), SetMinimalSize(10, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 7), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SGI_TRANSLATION_SELECTION), NWidget(NWID_VERTICAL), NWidget(WWT_EMPTY, COLOUR_ORANGE, WID_SGI_TRANSLATION), SetMinimalSize(316, 12), SetFill(1, 0), SetPadding(0, 10, 7, 10), EndContainer(), EndContainer(), /* 'game options' and 'advanced settings' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_OPTIONS), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_GAME_OPTIONS, STR_INTRO_TOOLTIP_GAME_OPTIONS), SetPadding(0, 0, 0, 10), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_SETTINGS_OPTIONS), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_CONFIG_SETTINGS_TREE, STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), /* 'script settings' and 'newgrf settings' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_AI_SETTINGS), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_SCRIPT_SETTINGS, STR_INTRO_TOOLTIP_SCRIPT_SETTINGS), SetPadding(0, 0, 0, 10), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_GRF_SETTINGS), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_INTRO_TOOLTIP_NEWGRF_SETTINGS), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), /* 'online content' and 'highscore' buttons */ NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_CONTENT_DOWNLOAD), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), SetPadding(0, 0, 0, 10), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_HIGHSCORE), SetMinimalSize(158, 12), SetDataTip(STR_INTRO_HIGHSCORE, STR_INTRO_TOOLTIP_HIGHSCORE), SetPadding(0, 10, 0, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 6), /* 'exit program' button */ NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_ORANGE, WID_SGI_EXIT), SetMinimalSize(128, 12), SetDataTip(STR_INTRO_QUIT, STR_INTRO_TOOLTIP_QUIT), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 8), EndContainer(), }; static WindowDesc _select_game_desc( WDP_CENTER, NULL, 0, 0, WC_SELECT_GAME, WC_NONE, 0, _nested_select_game_widgets, lengthof(_nested_select_game_widgets) ); void ShowSelectGameWindow() { new SelectGameWindow(&_select_game_desc); } static void AskExitGameCallback(Window *w, bool confirmed) { if (confirmed) _exit_game = true; } void AskExitGame() { #if defined(_WIN32) SetDParam(0, STR_OSNAME_WINDOWS); #elif defined(__APPLE__) SetDParam(0, STR_OSNAME_OSX); #elif defined(__BEOS__) SetDParam(0, STR_OSNAME_BEOS); #elif defined(__HAIKU__) SetDParam(0, STR_OSNAME_HAIKU); #elif defined(__MORPHOS__) SetDParam(0, STR_OSNAME_MORPHOS); #elif defined(__AMIGA__) SetDParam(0, STR_OSNAME_AMIGAOS); #elif defined(__OS2__) SetDParam(0, STR_OSNAME_OS2); #elif defined(SUNOS) SetDParam(0, STR_OSNAME_SUNOS); #elif defined(DOS) SetDParam(0, STR_OSNAME_DOS); #else SetDParam(0, STR_OSNAME_UNIX); #endif ShowQuery( STR_QUIT_CAPTION, STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD, NULL, AskExitGameCallback ); } static void AskExitToGameMenuCallback(Window *w, bool confirmed) { if (confirmed) { _switch_mode = SM_MENU; ClearErrorMessages(); } } void AskExitToGameMenu() { ShowQuery( STR_ABANDON_GAME_CAPTION, (_game_mode != GM_EDITOR) ? STR_ABANDON_GAME_QUERY : STR_ABANDON_SCENARIO_QUERY, NULL, AskExitToGameMenuCallback ); } openttd-1.5.3/src/bridge_map.h0000644000000000000000000001311212627373442014734 0ustar rootroot/* $Id: bridge_map.h 26879 2014-09-21 11:24:51Z rubidium $ */ /* * 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 bridge_map.h Map accessor functions for bridges. */ #ifndef BRIDGE_MAP_H #define BRIDGE_MAP_H #include "road_map.h" #include "bridge.h" /** * Checks if this is a bridge, instead of a tunnel * @param t The tile to analyze * @pre IsTileType(t, MP_TUNNELBRIDGE) * @return true if the structure is a bridge one */ static inline bool IsBridge(TileIndex t) { assert(IsTileType(t, MP_TUNNELBRIDGE)); return HasBit(_m[t].m5, 7); } /** * checks if there is a bridge on this tile * @param t The tile to analyze * @return true if a bridge is present */ static inline bool IsBridgeTile(TileIndex t) { return IsTileType(t, MP_TUNNELBRIDGE) && IsBridge(t); } /** * checks if a bridge is set above the ground of this tile * @param t The tile to analyze * @return true if a bridge is detected above */ static inline bool IsBridgeAbove(TileIndex t) { return GB(_m[t].type, 2, 2) != 0; } /** * Determines the type of bridge on a tile * @param t The tile to analyze * @pre IsBridgeTile(t) * @return The bridge type */ static inline BridgeType GetBridgeType(TileIndex t) { assert(IsBridgeTile(t)); return GB(_me[t].m6, 2, 4); } /** * Get the axis of the bridge that goes over the tile. Not the axis or the ramp. * @param t The tile to analyze * @pre IsBridgeAbove(t) * @return the above mentioned axis */ static inline Axis GetBridgeAxis(TileIndex t) { assert(IsBridgeAbove(t)); return (Axis)(GB(_m[t].type, 2, 2) - 1); } TileIndex GetNorthernBridgeEnd(TileIndex t); TileIndex GetSouthernBridgeEnd(TileIndex t); TileIndex GetOtherBridgeEnd(TileIndex t); int GetBridgeHeight(TileIndex tile); /** * Get the height ('z') of a bridge in pixels. * @param tile the bridge ramp tile to get the bridge height from * @return the height of the bridge in pixels */ static inline int GetBridgePixelHeight(TileIndex tile) { return GetBridgeHeight(tile) * TILE_HEIGHT; } /** * Remove the bridge over the given axis. * @param t the tile to remove the bridge from * @param a the axis of the bridge to remove */ static inline void ClearSingleBridgeMiddle(TileIndex t, Axis a) { ClrBit(_m[t].type, 2 + a); } /** * Removes bridges from the given, that is bridges along the X and Y axis. * @param t the tile to remove the bridge from */ static inline void ClearBridgeMiddle(TileIndex t) { ClearSingleBridgeMiddle(t, AXIS_X); ClearSingleBridgeMiddle(t, AXIS_Y); } /** * Set that there is a bridge over the given axis. * @param t the tile to add the bridge to * @param a the axis of the bridge to add */ static inline void SetBridgeMiddle(TileIndex t, Axis a) { SetBit(_m[t].type, 2 + a); } /** * Generic part to make a bridge ramp for both roads and rails. * @param t the tile to make a bridge ramp * @param o the new owner of the bridge ramp * @param bridgetype the type of bridge this bridge ramp belongs to * @param d the direction this ramp must be facing * @param tt the transport type of the bridge * @param rt the road or rail type * @note this function should not be called directly. */ static inline void MakeBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, TransportType tt, uint rt) { SetTileType(t, MP_TUNNELBRIDGE); SetTileOwner(t, o); _m[t].m2 = 0; _m[t].m3 = rt; _m[t].m4 = 0; _m[t].m5 = 1 << 7 | tt << 2 | d; SB(_me[t].m6, 2, 4, bridgetype); _me[t].m7 = 0; } /** * Make a bridge ramp for roads. * @param t the tile to make a bridge ramp * @param o the new owner of the bridge ramp * @param owner_road the new owner of the road on the bridge * @param owner_tram the new owner of the tram on the bridge * @param bridgetype the type of bridge this bridge ramp belongs to * @param d the direction this ramp must be facing * @param r the road type of the bridge */ static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Owner owner_tram, BridgeType bridgetype, DiagDirection d, RoadTypes r) { MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_ROAD, 0); SetRoadOwner(t, ROADTYPE_ROAD, owner_road); if (owner_tram != OWNER_TOWN) SetRoadOwner(t, ROADTYPE_TRAM, owner_tram); SetRoadTypes(t, r); } /** * Make a bridge ramp for rails. * @param t the tile to make a bridge ramp * @param o the new owner of the bridge ramp * @param bridgetype the type of bridge this bridge ramp belongs to * @param d the direction this ramp must be facing * @param r the rail type of the bridge */ static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r) { MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r); } /** * Make a bridge ramp for aqueducts. * @param t the tile to make a bridge ramp * @param o the new owner of the bridge ramp * @param d the direction this ramp must be facing */ static inline void MakeAqueductBridgeRamp(TileIndex t, Owner o, DiagDirection d) { MakeBridgeRamp(t, o, 0, d, TRANSPORT_WATER, 0); } #endif /* BRIDGE_MAP_H */ openttd-1.5.3/src/fileio.cpp0000644000000000000000000012767512627373441014470 0ustar rootroot/* $Id: fileio.cpp 26514 2014-04-25 21:29:54Z rubidium $ */ /* * 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 fileio.cpp Standard In/Out file operations */ #include "stdafx.h" #include "fileio_func.h" #include "debug.h" #include "fios.h" #include "string_func.h" #include "tar_type.h" #ifdef WIN32 #include # define access _taccess #elif defined(__HAIKU__) #include #include #else #include #include #endif #include #include #ifdef WITH_XDG_BASEDIR #include "basedir.h" #endif #include "safeguards.h" /** Size of the #Fio data buffer. */ #define FIO_BUFFER_SIZE 512 /** Structure for keeping several open files with just one data buffer. */ struct Fio { byte *buffer, *buffer_end; ///< position pointer in local buffer and last valid byte of buffer size_t pos; ///< current (system) position in file FILE *cur_fh; ///< current file handle const char *filename; ///< current filename FILE *handles[MAX_FILE_SLOTS]; ///< array of file handles we can have open byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file const char *filenames[MAX_FILE_SLOTS]; ///< array of filenames we (should) have open char *shortnames[MAX_FILE_SLOTS]; ///< array of short names for spriteloader's use #if defined(LIMITED_FDS) uint open_handles; ///< current amount of open handles uint usage_count[MAX_FILE_SLOTS]; ///< count how many times this file has been opened #endif /* LIMITED_FDS */ }; static Fio _fio; ///< #Fio instance. /** Whether the working directory should be scanned. */ static bool _do_scan_working_directory = true; extern char *_config_file; extern char *_highscore_file; /** * Get position in the current file. * @return Position in the file. */ size_t FioGetPos() { return _fio.pos + (_fio.buffer - _fio.buffer_end); } /** * Get the filename associated with a slot. * @param slot Index of queried file. * @return Name of the file. */ const char *FioGetFilename(uint8 slot) { return _fio.shortnames[slot]; } /** * Seek in the current file. * @param pos New position. * @param mode Type of seek (\c SEEK_CUR means \a pos is relative to current position, \c SEEK_SET means \a pos is absolute). */ void FioSeekTo(size_t pos, int mode) { if (mode == SEEK_CUR) pos += FioGetPos(); _fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE; _fio.pos = pos; if (fseek(_fio.cur_fh, _fio.pos, SEEK_SET) < 0) { DEBUG(misc, 0, "Seeking in %s failed", _fio.filename); } } #if defined(LIMITED_FDS) static void FioRestoreFile(int slot) { /* Do we still have the file open, or should we reopen it? */ if (_fio.handles[slot] == NULL) { DEBUG(misc, 6, "Restoring file '%s' in slot '%d' from disk", _fio.filenames[slot], slot); FioOpenFile(slot, _fio.filenames[slot]); } _fio.usage_count[slot]++; } #endif /* LIMITED_FDS */ /** * Switch to a different file and seek to a position. * @param slot Slot number of the new file. * @param pos New absolute position in the new file. */ void FioSeekToFile(uint8 slot, size_t pos) { FILE *f; #if defined(LIMITED_FDS) /* Make sure we have this file open */ FioRestoreFile(slot); #endif /* LIMITED_FDS */ f = _fio.handles[slot]; assert(f != NULL); _fio.cur_fh = f; _fio.filename = _fio.filenames[slot]; FioSeekTo(pos, SEEK_SET); } /** * Read a byte from the file. * @return Read byte. */ byte FioReadByte() { if (_fio.buffer == _fio.buffer_end) { _fio.buffer = _fio.buffer_start; size_t size = fread(_fio.buffer, 1, FIO_BUFFER_SIZE, _fio.cur_fh); _fio.pos += size; _fio.buffer_end = _fio.buffer_start + size; if (size == 0) return 0; } return *_fio.buffer++; } /** * Skip \a n bytes ahead in the file. * @param n Number of bytes to skip reading. */ void FioSkipBytes(int n) { for (;;) { int m = min(_fio.buffer_end - _fio.buffer, n); _fio.buffer += m; n -= m; if (n == 0) break; FioReadByte(); n--; } } /** * Read a word (16 bits) from the file (in low endian format). * @return Read word. */ uint16 FioReadWord() { byte b = FioReadByte(); return (FioReadByte() << 8) | b; } /** * Read a double word (32 bits) from the file (in low endian format). * @return Read word. */ uint32 FioReadDword() { uint b = FioReadWord(); return (FioReadWord() << 16) | b; } /** * Read a block. * @param ptr Destination buffer. * @param size Number of bytes to read. */ void FioReadBlock(void *ptr, size_t size) { FioSeekTo(FioGetPos(), SEEK_SET); _fio.pos += fread(ptr, 1, size, _fio.cur_fh); } /** * Close the file at the given slot number. * @param slot File index to close. */ static inline void FioCloseFile(int slot) { if (_fio.handles[slot] != NULL) { fclose(_fio.handles[slot]); free(_fio.shortnames[slot]); _fio.shortnames[slot] = NULL; _fio.handles[slot] = NULL; #if defined(LIMITED_FDS) _fio.open_handles--; #endif /* LIMITED_FDS */ } } /** Close all slotted open files. */ void FioCloseAll() { for (int i = 0; i != lengthof(_fio.handles); i++) { FioCloseFile(i); } } #if defined(LIMITED_FDS) static void FioFreeHandle() { /* If we are about to open a file that will exceed the limit, close a file */ if (_fio.open_handles + 1 == LIMITED_FDS) { uint i, count; int slot; count = UINT_MAX; slot = -1; /* Find the file that is used the least */ for (i = 0; i < lengthof(_fio.handles); i++) { if (_fio.handles[i] != NULL && _fio.usage_count[i] < count) { count = _fio.usage_count[i]; slot = i; } } assert(slot != -1); DEBUG(misc, 6, "Closing filehandler '%s' in slot '%d' because of fd-limit", _fio.filenames[slot], slot); FioCloseFile(slot); } } #endif /* LIMITED_FDS */ /** * Open a slotted file. * @param slot Index to assign. * @param filename Name of the file at the disk. * @param subdir The sub directory to search this file in. */ void FioOpenFile(int slot, const char *filename, Subdirectory subdir) { FILE *f; #if defined(LIMITED_FDS) FioFreeHandle(); #endif /* LIMITED_FDS */ f = FioFOpenFile(filename, "rb", subdir); if (f == NULL) usererror("Cannot open file '%s'", filename); long pos = ftell(f); if (pos < 0) usererror("Cannot read file '%s'", filename); FioCloseFile(slot); // if file was opened before, close it _fio.handles[slot] = f; _fio.filenames[slot] = filename; /* Store the filename without path and extension */ const char *t = strrchr(filename, PATHSEPCHAR); _fio.shortnames[slot] = stredup(t == NULL ? filename : t); char *t2 = strrchr(_fio.shortnames[slot], '.'); if (t2 != NULL) *t2 = '\0'; strtolower(_fio.shortnames[slot]); #if defined(LIMITED_FDS) _fio.usage_count[slot] = 0; _fio.open_handles++; #endif /* LIMITED_FDS */ FioSeekToFile(slot, (uint32)pos); } static const char * const _subdirs[] = { "", "save" PATHSEP, "save" PATHSEP "autosave" PATHSEP, "scenario" PATHSEP, "scenario" PATHSEP "heightmap" PATHSEP, "gm" PATHSEP, "data" PATHSEP, "baseset" PATHSEP, "newgrf" PATHSEP, "lang" PATHSEP, "ai" PATHSEP, "ai" PATHSEP "library" PATHSEP, "game" PATHSEP, "game" PATHSEP "library" PATHSEP, "screenshot" PATHSEP, }; assert_compile(lengthof(_subdirs) == NUM_SUBDIRS); const char *_searchpaths[NUM_SEARCHPATHS]; TarList _tar_list[NUM_SUBDIRS]; TarFileList _tar_filelist[NUM_SUBDIRS]; typedef std::map TarLinkList; static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links /** * Check whether the given file exists * @param filename the file to try for existence. * @param subdir the subdirectory to look in * @return true if and only if the file can be opened */ bool FioCheckFileExists(const char *filename, Subdirectory subdir) { FILE *f = FioFOpenFile(filename, "rb", subdir); if (f == NULL) return false; FioFCloseFile(f); return true; } /** * Test whether the given filename exists. * @param filename the file to test. * @return true if and only if the file exists. */ bool FileExists(const char *filename) { #if defined(WINCE) /* There is always one platform that doesn't support basic commands... */ HANDLE hand = CreateFile(OTTD2FS(filename), 0, 0, NULL, OPEN_EXISTING, 0, NULL); if (hand == INVALID_HANDLE_VALUE) return 1; CloseHandle(hand); return 0; #else return access(OTTD2FS(filename), 0) == 0; #endif } /** * Close a file in a safe way. */ void FioFCloseFile(FILE *f) { fclose(f); } char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory subdir, const char *filename) { assert(subdir < NUM_SUBDIRS); assert(sp < NUM_SEARCHPATHS); seprintf(buf, last, "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename); return buf; } /** * Find a path to the filename in one of the search directories. * @param buf [out] Destination buffer for the path. * @param last End of the destination buffer. * @param subdir Subdirectory to try. * @param filename Filename to look for. * @return \a buf containing the path if the path was found, else \c NULL. */ char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename) { Searchpath sp; assert(subdir < NUM_SUBDIRS); FOR_ALL_SEARCHPATHS(sp) { FioGetFullPath(buf, last, sp, subdir, filename); if (FileExists(buf)) return buf; #if !defined(WIN32) /* Be, as opening files, aware that sometimes the filename * might be in uppercase when it is in lowercase on the * disk. Of course Windows doesn't care about casing. */ if (strtolower(buf + strlen(_searchpaths[sp]) - 1) && FileExists(buf)) return buf; #endif } return NULL; } char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirectory subdir) { assert(subdir < NUM_SUBDIRS); assert(sp < NUM_SEARCHPATHS); seprintf(buf, last, "%s%s", _searchpaths[sp], _subdirs[subdir]); return buf; } char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir) { Searchpath sp; /* Find and return the first valid directory */ FOR_ALL_SEARCHPATHS(sp) { char *ret = FioAppendDirectory(buf, last, sp, subdir); if (FileExists(buf)) return ret; } /* Could not find the directory, fall back to a base path */ strecpy(buf, _personal_dir, last); return buf; } static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize) { #if defined(WIN32) && defined(UNICODE) /* fopen is implemented as a define with ellipses for * Unicode support (prepend an L). As we are not sending * a string, but a variable, it 'renames' the variable, * so make that variable to makes it compile happily */ wchar_t Lmode[5]; MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, lengthof(Lmode)); #endif FILE *f = NULL; char buf[MAX_PATH]; if (subdir == NO_DIRECTORY) { strecpy(buf, filename, lastof(buf)); } else { seprintf(buf, lastof(buf), "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename); } #if defined(WIN32) if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) return NULL; #endif f = fopen(buf, mode); #if !defined(WIN32) if (f == NULL && strtolower(buf + ((subdir == NO_DIRECTORY) ? 0 : strlen(_searchpaths[sp]) - 1))) { f = fopen(buf, mode); } #endif if (f != NULL && filesize != NULL) { /* Find the size of the file */ fseek(f, 0, SEEK_END); *filesize = ftell(f); fseek(f, 0, SEEK_SET); } return f; } /** * Opens a file from inside a tar archive. * @param entry The entry to open. * @param filesize [out] If not \c NULL, size of the opened file. * @return File handle of the opened file, or \c NULL if the file is not available. * @note The file is read from within the tar file, and may not return \c EOF after reading the whole file. */ FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize) { FILE *f = fopen(entry->tar_filename, "rb"); if (f == NULL) return f; if (fseek(f, entry->position, SEEK_SET) < 0) { fclose(f); return NULL; } if (filesize != NULL) *filesize = entry->size; return f; } /** * Opens a OpenTTD file somewhere in a personal or global directory. * @param filename Name of the file to open. * @param subdir Subdirectory to open. * @param filename Name of the file to open. * @return File handle of the opened file, or \c NULL if the file is not available. */ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize) { FILE *f = NULL; Searchpath sp; assert(subdir < NUM_SUBDIRS || subdir == NO_DIRECTORY); FOR_ALL_SEARCHPATHS(sp) { f = FioFOpenFileSp(filename, mode, sp, subdir, filesize); if (f != NULL || subdir == NO_DIRECTORY) break; } /* We can only use .tar in case of data-dir, and read-mode */ if (f == NULL && mode[0] == 'r' && subdir != NO_DIRECTORY) { static const uint MAX_RESOLVED_LENGTH = 2 * (100 + 100 + 155) + 1; // Enough space to hold two filenames plus link. See 'TarHeader'. char resolved_name[MAX_RESOLVED_LENGTH]; /* Filenames in tars are always forced to be lowercase */ strecpy(resolved_name, filename, lastof(resolved_name)); strtolower(resolved_name); size_t resolved_len = strlen(resolved_name); /* Resolve ONE directory link */ for (TarLinkList::iterator link = _tar_linklist[subdir].begin(); link != _tar_linklist[subdir].end(); link++) { const std::string &src = link->first; size_t len = src.length(); if (resolved_len >= len && resolved_name[len - 1] == PATHSEPCHAR && strncmp(src.c_str(), resolved_name, len) == 0) { /* Apply link */ char resolved_name2[MAX_RESOLVED_LENGTH]; const std::string &dest = link->second; strecpy(resolved_name2, &(resolved_name[len]), lastof(resolved_name2)); strecpy(resolved_name, dest.c_str(), lastof(resolved_name)); strecpy(&(resolved_name[dest.length()]), resolved_name2, lastof(resolved_name)); break; // Only resolve one level } } TarFileList::iterator it = _tar_filelist[subdir].find(resolved_name); if (it != _tar_filelist[subdir].end()) { f = FioFOpenFileTar(&((*it).second), filesize); } } /* Sometimes a full path is given. To support * the 'subdirectory' must be 'removed'. */ if (f == NULL && subdir != NO_DIRECTORY) { switch (subdir) { case BASESET_DIR: f = FioFOpenFile(filename, mode, OLD_GM_DIR, filesize); if (f != NULL) break; /* FALL THROUGH */ case NEWGRF_DIR: f = FioFOpenFile(filename, mode, OLD_DATA_DIR, filesize); break; default: f = FioFOpenFile(filename, mode, NO_DIRECTORY, filesize); break; } } return f; } /** * Create a directory with the given name * @param name the new name of the directory */ static void FioCreateDirectory(const char *name) { /* Ignore directory creation errors; they'll surface later on, and most * of the time they are 'directory already exists' errors anyhow. */ #if defined(WIN32) || defined(WINCE) CreateDirectory(OTTD2FS(name), NULL); #elif defined(OS2) && !defined(__INNOTEK_LIBC__) mkdir(OTTD2FS(name)); #elif defined(__MORPHOS__) || defined(__AMIGAOS__) char buf[MAX_PATH]; strecpy(buf, name, lastof(buf)); size_t len = strlen(name) - 1; if (buf[len] == '/') { buf[len] = '\0'; // Kill pathsep, so mkdir() will not fail } mkdir(OTTD2FS(buf), 0755); #else mkdir(OTTD2FS(name), 0755); #endif } /** * Appends, if necessary, the path separator character to the end of the string. * It does not add the path separator to zero-sized strings. * @param buf string to append the separator to * @param last the last element of \a buf. * @return true iff the operation succeeded */ bool AppendPathSeparator(char *buf, const char *last) { size_t s = strlen(buf); /* Length of string + path separator + '\0' */ if (s != 0 && buf[s - 1] != PATHSEPCHAR) { if (&buf[s] >= last) return false; seprintf(buf + s, last, "%c", PATHSEPCHAR); } return true; } /** * Allocates and files a variable with the full path * based on the given directory. * @param dir the directory to base the path on * @return the malloced full path */ char *BuildWithFullPath(const char *dir) { char *dest = MallocT(MAX_PATH); char *last = dest + MAX_PATH - 1; strecpy(dest, dir, last); /* Check if absolute or relative path */ const char *s = strchr(dest, PATHSEPCHAR); /* Add absolute path */ if (s == NULL || dest != s) { if (getcwd(dest, MAX_PATH) == NULL) *dest = '\0'; AppendPathSeparator(dest, last); strecat(dest, dir, last); } AppendPathSeparator(dest, last); return dest; } /** * Find the first directory in a tar archive. * @param tarname the name of the tar archive to look in. * @param subdir the subdirectory to look in. */ const char *FioTarFirstDir(const char *tarname, Subdirectory subdir) { TarList::iterator it = _tar_list[subdir].find(tarname); if (it == _tar_list[subdir].end()) return NULL; return (*it).second.dirname; } static void TarAddLink(const std::string &srcParam, const std::string &destParam, Subdirectory subdir) { std::string src = srcParam; std::string dest = destParam; /* Tar internals assume lowercase */ std::transform(src.begin(), src.end(), src.begin(), tolower); std::transform(dest.begin(), dest.end(), dest.begin(), tolower); TarFileList::iterator dest_file = _tar_filelist[subdir].find(dest); if (dest_file != _tar_filelist[subdir].end()) { /* Link to file. Process the link like the destination file. */ _tar_filelist[subdir].insert(TarFileList::value_type(src, dest_file->second)); } else { /* Destination file not found. Assume 'link to directory' * Append PATHSEPCHAR to 'src' and 'dest' if needed */ const std::string src_path = ((*src.rbegin() == PATHSEPCHAR) ? src : src + PATHSEPCHAR); const std::string dst_path = (dest.length() == 0 ? "" : ((*dest.rbegin() == PATHSEPCHAR) ? dest : dest + PATHSEPCHAR)); _tar_linklist[subdir].insert(TarLinkList::value_type(src_path, dst_path)); } } void FioTarAddLink(const char *src, const char *dest, Subdirectory subdir) { TarAddLink(src, dest, subdir); } /** * Simplify filenames from tars. * Replace '/' by #PATHSEPCHAR, and force 'name' to lowercase. * @param name Filename to process. */ static void SimplifyFileName(char *name) { /* Force lowercase */ strtolower(name); /* Tar-files always have '/' path-separator, but we want our PATHSEPCHAR */ #if (PATHSEPCHAR != '/') for (char *n = name; *n != '\0'; n++) if (*n == '/') *n = PATHSEPCHAR; #endif } /** * Perform the scanning of a particular subdirectory. * @param subdir The subdirectory to scan. * @return The number of found tar files. */ uint TarScanner::DoScan(Subdirectory sd) { _tar_filelist[sd].clear(); _tar_list[sd].clear(); uint num = this->Scan(".tar", sd, false); if (sd == BASESET_DIR || sd == NEWGRF_DIR) num += this->Scan(".tar", OLD_DATA_DIR, false); return num; } /* static */ uint TarScanner::DoScan(TarScanner::Mode mode) { DEBUG(misc, 1, "Scanning for tars"); TarScanner fs; uint num = 0; if (mode & TarScanner::BASESET) { num += fs.DoScan(BASESET_DIR); } if (mode & TarScanner::NEWGRF) { num += fs.DoScan(NEWGRF_DIR); } if (mode & TarScanner::AI) { num += fs.DoScan(AI_DIR); num += fs.DoScan(AI_LIBRARY_DIR); } if (mode & TarScanner::GAME) { num += fs.DoScan(GAME_DIR); num += fs.DoScan(GAME_LIBRARY_DIR); } if (mode & TarScanner::SCENARIO) { num += fs.DoScan(SCENARIO_DIR); num += fs.DoScan(HEIGHTMAP_DIR); } DEBUG(misc, 1, "Scan complete, found %d files", num); return num; } /** * Add a single file to the scanned files of a tar, circumventing the scanning code. * @param sd The sub directory the file is in. * @param filename The name of the file to add. * @return True if the additions went correctly. */ bool TarScanner::AddFile(Subdirectory sd, const char *filename) { this->subdir = sd; return this->AddFile(filename, 0); } bool TarScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { /* No tar within tar. */ assert(tar_filename == NULL); /* The TAR-header, repeated for every file */ struct TarHeader { char name[100]; ///< Name of the file char mode[8]; char uid[8]; char gid[8]; char size[12]; ///< Size of the file, in ASCII char mtime[12]; char chksum[8]; char typeflag; char linkname[100]; char magic[6]; char version[2]; char uname[32]; char gname[32]; char devmajor[8]; char devminor[8]; char prefix[155]; ///< Path of the file char unused[12]; }; /* Check if we already seen this file */ TarList::iterator it = _tar_list[this->subdir].find(filename); if (it != _tar_list[this->subdir].end()) return false; FILE *f = fopen(filename, "rb"); /* Although the file has been found there can be * a number of reasons we cannot open the file. * Most common case is when we simply have not * been given read access. */ if (f == NULL) return false; const char *dupped_filename = stredup(filename); _tar_list[this->subdir][filename].filename = dupped_filename; _tar_list[this->subdir][filename].dirname = NULL; TarLinkList links; ///< Temporary list to collect links TarHeader th; char buf[sizeof(th.name) + 1], *end; char name[sizeof(th.prefix) + 1 + sizeof(th.name) + 1]; char link[sizeof(th.linkname) + 1]; char dest[sizeof(th.prefix) + 1 + sizeof(th.name) + 1 + 1 + sizeof(th.linkname) + 1]; size_t num = 0, pos = 0; /* Make a char of 512 empty bytes */ char empty[512]; memset(&empty[0], 0, sizeof(empty)); for (;;) { // Note: feof() always returns 'false' after 'fseek()'. Cool, isn't it? size_t num_bytes_read = fread(&th, 1, 512, f); if (num_bytes_read != 512) break; pos += num_bytes_read; /* Check if we have the new tar-format (ustar) or the old one (a lot of zeros after 'link' field) */ if (strncmp(th.magic, "ustar", 5) != 0 && memcmp(&th.magic, &empty[0], 512 - offsetof(TarHeader, magic)) != 0) { /* If we have only zeros in the block, it can be an end-of-file indicator */ if (memcmp(&th, &empty[0], 512) == 0) continue; DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename); fclose(f); return false; } name[0] = '\0'; /* The prefix contains the directory-name */ if (th.prefix[0] != '\0') { strecpy(name, th.prefix, lastof(name)); strecat(name, PATHSEP, lastof(name)); } /* Copy the name of the file in a safe way at the end of 'name' */ strecat(name, th.name, lastof(name)); /* Calculate the size of the file.. for some strange reason this is stored as a string */ strecpy(buf, th.size, lastof(buf)); size_t skip = strtoul(buf, &end, 8); switch (th.typeflag) { case '\0': case '0': { // regular file /* Ignore empty files */ if (skip == 0) break; if (strlen(name) == 0) break; /* Store this entry in the list */ TarFileListEntry entry; entry.tar_filename = dupped_filename; entry.size = skip; entry.position = pos; /* Convert to lowercase and our PATHSEPCHAR */ SimplifyFileName(name); DEBUG(misc, 6, "Found file in tar: %s (" PRINTF_SIZE " bytes, " PRINTF_SIZE " offset)", name, skip, pos); if (_tar_filelist[this->subdir].insert(TarFileList::value_type(name, entry)).second) num++; break; } case '1': // hard links case '2': { // symbolic links /* Copy the destination of the link in a safe way at the end of 'linkname' */ strecpy(link, th.linkname, lastof(link)); if (strlen(name) == 0 || strlen(link) == 0) break; /* Convert to lowercase and our PATHSEPCHAR */ SimplifyFileName(name); SimplifyFileName(link); /* Only allow relative links */ if (link[0] == PATHSEPCHAR) { DEBUG(misc, 1, "Ignoring absolute link in tar: %s -> %s", name, link); break; } /* Process relative path. * Note: The destination of links must not contain any directory-links. */ strecpy(dest, name, lastof(dest)); char *destpos = strrchr(dest, PATHSEPCHAR); if (destpos == NULL) destpos = dest; *destpos = '\0'; char *pos = link; while (*pos != '\0') { char *next = strchr(pos, PATHSEPCHAR); if (next == NULL) { next = pos + strlen(pos); } else { /* Terminate the substring up to the path separator character. */ *next++= '\0'; } if (strcmp(pos, ".") == 0) { /* Skip '.' (current dir) */ } else if (strcmp(pos, "..") == 0) { /* level up */ if (dest[0] == '\0') { DEBUG(misc, 1, "Ignoring link pointing outside of data directory: %s -> %s", name, link); break; } /* Truncate 'dest' after last PATHSEPCHAR. * This assumes that the truncated part is a real directory and not a link. */ destpos = strrchr(dest, PATHSEPCHAR); if (destpos == NULL) destpos = dest; *destpos = '\0'; } else { /* Append at end of 'dest' */ if (destpos != dest) destpos = strecpy(destpos, PATHSEP, lastof(dest)); destpos = strecpy(destpos, pos, lastof(dest)); } if (destpos >= lastof(dest)) { DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename); fclose(f); return false; } pos = next; } /* Store links in temporary list */ DEBUG(misc, 6, "Found link in tar: %s -> %s", name, dest); links.insert(TarLinkList::value_type(name, dest)); break; } case '5': // directory /* Convert to lowercase and our PATHSEPCHAR */ SimplifyFileName(name); /* Store the first directory name we detect */ DEBUG(misc, 6, "Found dir in tar: %s", name); if (_tar_list[this->subdir][filename].dirname == NULL) _tar_list[this->subdir][filename].dirname = stredup(name); break; default: /* Ignore other types */ break; } /* Skip to the next block.. */ skip = Align(skip, 512); if (fseek(f, skip, SEEK_CUR) < 0) { DEBUG(misc, 0, "The file '%s' can't be read as a valid tar-file", filename); fclose(f); return false; } pos += skip; } DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename, num); fclose(f); /* Resolve file links and store directory links. * We restrict usage of links to two cases: * 1) Links to directories: * Both the source path and the destination path must NOT contain any further links. * When resolving files at most one directory link is resolved. * 2) Links to files: * The destination path must NOT contain any links. * The source path may contain one directory link. */ for (TarLinkList::iterator link = links.begin(); link != links.end(); link++) { const std::string &src = link->first; const std::string &dest = link->second; TarAddLink(src, dest, this->subdir); } return true; } /** * Extract the tar with the given filename in the directory * where the tar resides. * @param tar_filename the name of the tar to extract. * @param subdir The sub directory the tar is in. * @return false on failure. */ bool ExtractTar(const char *tar_filename, Subdirectory subdir) { TarList::iterator it = _tar_list[subdir].find(tar_filename); /* We don't know the file. */ if (it == _tar_list[subdir].end()) return false; const char *dirname = (*it).second.dirname; /* The file doesn't have a sub directory! */ if (dirname == NULL) return false; char filename[MAX_PATH]; strecpy(filename, tar_filename, lastof(filename)); char *p = strrchr(filename, PATHSEPCHAR); /* The file's path does not have a separator? */ if (p == NULL) return false; p++; strecpy(p, dirname, lastof(filename)); DEBUG(misc, 8, "Extracting %s to directory %s", tar_filename, filename); FioCreateDirectory(filename); for (TarFileList::iterator it2 = _tar_filelist[subdir].begin(); it2 != _tar_filelist[subdir].end(); it2++) { if (strcmp((*it2).second.tar_filename, tar_filename) != 0) continue; strecpy(p, (*it2).first.c_str(), lastof(filename)); DEBUG(misc, 9, " extracting %s", filename); /* First open the file in the .tar. */ size_t to_copy = 0; FILE *in = FioFOpenFileTar(&(*it2).second, &to_copy); if (in == NULL) { DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, tar_filename); return false; } /* Now open the 'output' file. */ FILE *out = fopen(filename, "wb"); if (out == NULL) { DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, filename); fclose(in); return false; } /* Now read from the tar and write it into the file. */ char buffer[4096]; size_t read; for (; to_copy != 0; to_copy -= read) { read = fread(buffer, 1, min(to_copy, lengthof(buffer)), in); if (read <= 0 || fwrite(buffer, 1, read, out) != read) break; } /* Close everything up. */ fclose(in); fclose(out); if (to_copy != 0) { DEBUG(misc, 6, "Extracting %s failed; still %i bytes to copy", filename, (int)to_copy); return false; } } DEBUG(misc, 9, " extraction successful"); return true; } #if defined(WIN32) || defined(WINCE) /** * Determine the base (personal dir and game data dir) paths * @param exe the path from the current path to the executable * @note defined in the OS related files (os2.cpp, win32.cpp, unix.cpp etc) */ extern void DetermineBasePaths(const char *exe); #else /* defined(WIN32) || defined(WINCE) */ /** * Changes the working directory to the path of the give executable. * For OSX application bundles '.app' is the required extension of the bundle, * so when we crop the path to there, when can remove the name of the bundle * in the same way we remove the name from the executable name. * @param exe the path to the executable */ static bool ChangeWorkingDirectoryToExecutable(const char *exe) { bool success = false; #ifdef WITH_COCOA char *app_bundle = strchr(exe, '.'); while (app_bundle != NULL && strncasecmp(app_bundle, ".app", 4) != 0) app_bundle = strchr(&app_bundle[1], '.'); if (app_bundle != NULL) app_bundle[0] = '\0'; #endif /* WITH_COCOA */ char *s = const_cast(strrchr(exe, PATHSEPCHAR)); if (s != NULL) { *s = '\0'; #if defined(__DJGPP__) /* If we want to go to the root, we can't use cd C:, but we must use '/' */ if (s[-1] == ':') chdir("/"); #endif if (chdir(exe) != 0) { DEBUG(misc, 0, "Directory with the binary does not exist?"); } else { success = true; } *s = PATHSEPCHAR; } #ifdef WITH_COCOA if (app_bundle != NULL) app_bundle[0] = '.'; #endif /* WITH_COCOA */ return success; } /** * Whether we should scan the working directory. * It should not be scanned if it's the root or * the home directory as in both cases a big data * directory can cause huge amounts of unrelated * files scanned. Furthermore there are nearly no * use cases for the home/root directory to have * OpenTTD directories. * @return true if it should be scanned. */ bool DoScanWorkingDirectory() { /* No working directory, so nothing to do. */ if (_searchpaths[SP_WORKING_DIR] == NULL) return false; /* Working directory is root, so do nothing. */ if (strcmp(_searchpaths[SP_WORKING_DIR], PATHSEP) == 0) return false; /* No personal/home directory, so the working directory won't be that. */ if (_searchpaths[SP_PERSONAL_DIR] == NULL) return true; char tmp[MAX_PATH]; seprintf(tmp, lastof(tmp), "%s%s", _searchpaths[SP_WORKING_DIR], PERSONAL_DIR); AppendPathSeparator(tmp, lastof(tmp)); return strcmp(tmp, _searchpaths[SP_PERSONAL_DIR]) != 0; } /** * Determine the base (personal dir and game data dir) paths * @param exe the path to the executable */ void DetermineBasePaths(const char *exe) { char tmp[MAX_PATH]; #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) const char *xdg_data_home = xdgDataHome(NULL); seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", xdg_data_home, PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); free(xdg_data_home); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_PERSONAL_DIR_XDG] = stredup(tmp); #endif #if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) || !defined(WITH_PERSONAL_DIR) _searchpaths[SP_PERSONAL_DIR] = NULL; #else #ifdef __HAIKU__ BPath path; find_directory(B_USER_SETTINGS_DIRECTORY, &path); const char *homedir = stredup(path.Path()); #else /* getenv is highly unsafe; duplicate it as soon as possible, * or at least before something else touches the environment * variables in any way. It can also contain all kinds of * unvalidated data we rather not want internally. */ const char *homedir = getenv("HOME"); if (homedir != NULL) { homedir = stredup(homedir); } if (homedir == NULL) { const struct passwd *pw = getpwuid(getuid()); homedir = (pw == NULL) ? NULL : stredup(pw->pw_dir); } #endif if (homedir != NULL) { ValidateString(homedir); seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", homedir, PERSONAL_DIR); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_PERSONAL_DIR] = stredup(tmp); free(homedir); } else { _searchpaths[SP_PERSONAL_DIR] = NULL; } #endif #if defined(WITH_SHARED_DIR) seprintf(tmp, lastof(tmp), "%s", SHARED_DIR); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_SHARED_DIR] = stredup(tmp); #else _searchpaths[SP_SHARED_DIR] = NULL; #endif #if defined(__MORPHOS__) || defined(__AMIGA__) _searchpaths[SP_WORKING_DIR] = NULL; #else if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_WORKING_DIR] = stredup(tmp); #endif _do_scan_working_directory = DoScanWorkingDirectory(); /* Change the working directory to that one of the executable */ if (ChangeWorkingDirectoryToExecutable(exe)) { if (getcwd(tmp, MAX_PATH) == NULL) *tmp = '\0'; AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_BINARY_DIR] = stredup(tmp); } else { _searchpaths[SP_BINARY_DIR] = NULL; } if (_searchpaths[SP_WORKING_DIR] != NULL) { /* Go back to the current working directory. */ if (chdir(_searchpaths[SP_WORKING_DIR]) != 0) { DEBUG(misc, 0, "Failed to return to working directory!"); } } #if defined(__MORPHOS__) || defined(__AMIGA__) || defined(DOS) || defined(OS2) _searchpaths[SP_INSTALLATION_DIR] = NULL; #else seprintf(tmp, lastof(tmp), "%s", GLOBAL_DATA_DIR); AppendPathSeparator(tmp, lastof(tmp)); _searchpaths[SP_INSTALLATION_DIR] = stredup(tmp); #endif #ifdef WITH_COCOA extern void cocoaSetApplicationBundleDir(); cocoaSetApplicationBundleDir(); #else _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL; #endif } #endif /* defined(WIN32) || defined(WINCE) */ const char *_personal_dir; /** * Acquire the base paths (personal dir and game data dir), * fill all other paths (save dir, autosave dir etc) and * make the save and scenario directories. * @param exe the path from the current path to the executable */ void DeterminePaths(const char *exe) { DetermineBasePaths(exe); #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) char config_home[MAX_PATH]; const char *xdg_config_home = xdgConfigHome(NULL); seprintf(config_home, lastof(config_home), "%s" PATHSEP "%s", xdg_config_home, PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); free(xdg_config_home); AppendPathSeparator(config_home, lastof(config_home)); #endif Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]); } char *config_dir; if (_config_file != NULL) { config_dir = stredup(_config_file); char *end = strrchr(config_dir, PATHSEPCHAR); if (end == NULL) { config_dir[0] = '\0'; } else { end[1] = '\0'; } } else { char personal_dir[MAX_PATH]; if (FioFindFullPath(personal_dir, lastof(personal_dir), BASE_DIR, "openttd.cfg") != NULL) { char *end = strrchr(personal_dir, PATHSEPCHAR); if (end != NULL) end[1] = '\0'; config_dir = stredup(personal_dir); _config_file = str_fmt("%sopenttd.cfg", config_dir); } else { #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) /* No previous configuration file found. Use the configuration folder from XDG. */ config_dir = config_home; #else static const Searchpath new_openttd_cfg_order[] = { SP_PERSONAL_DIR, SP_BINARY_DIR, SP_WORKING_DIR, SP_SHARED_DIR, SP_INSTALLATION_DIR }; config_dir = NULL; for (uint i = 0; i < lengthof(new_openttd_cfg_order); i++) { if (IsValidSearchPath(new_openttd_cfg_order[i])) { config_dir = stredup(_searchpaths[new_openttd_cfg_order[i]]); break; } } assert(config_dir != NULL); #endif _config_file = str_fmt("%sopenttd.cfg", config_dir); } } DEBUG(misc, 3, "%s found as config directory", config_dir); _highscore_file = str_fmt("%shs.dat", config_dir); extern char *_hotkeys_file; _hotkeys_file = str_fmt("%shotkeys.cfg", config_dir); extern char *_windows_file; _windows_file = str_fmt("%swindows.cfg", config_dir); #if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) if (config_dir == config_home) { /* We are using the XDG configuration home for the config file, * then store the rest in the XDG data home folder. */ _personal_dir = _searchpaths[SP_PERSONAL_DIR_XDG]; FioCreateDirectory(_personal_dir); } else #endif { _personal_dir = config_dir; } /* Make the necessary folders */ #if !defined(__MORPHOS__) && !defined(__AMIGA__) && defined(WITH_PERSONAL_DIR) FioCreateDirectory(config_dir); if (config_dir != _personal_dir) FioCreateDirectory(_personal_dir); #endif DEBUG(misc, 3, "%s found as personal directory", _personal_dir); static const Subdirectory default_subdirs[] = { SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR, SCREENSHOT_DIR }; for (uint i = 0; i < lengthof(default_subdirs); i++) { char *dir = str_fmt("%s%s", _personal_dir, _subdirs[default_subdirs[i]]); FioCreateDirectory(dir); free(dir); } /* If we have network we make a directory for the autodownloading of content */ _searchpaths[SP_AUTODOWNLOAD_DIR] = str_fmt("%s%s", _personal_dir, "content_download" PATHSEP); #ifdef ENABLE_NETWORK FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]); /* Create the directory for each of the types of content */ const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR }; for (uint i = 0; i < lengthof(dirs); i++) { char *tmp = str_fmt("%s%s", _searchpaths[SP_AUTODOWNLOAD_DIR], _subdirs[dirs[i]]); FioCreateDirectory(tmp); free(tmp); } extern char *_log_file; _log_file = str_fmt("%sopenttd.log", _personal_dir); #else /* ENABLE_NETWORK */ /* If we don't have networking, we don't need to make the directory. But * if it exists we keep it, otherwise remove it from the search paths. */ if (!FileExists(_searchpaths[SP_AUTODOWNLOAD_DIR])) { free(_searchpaths[SP_AUTODOWNLOAD_DIR]); _searchpaths[SP_AUTODOWNLOAD_DIR] = NULL; } #endif /* ENABLE_NETWORK */ } /** * Sanitizes a filename, i.e. removes all illegal characters from it. * @param filename the "\0" terminated filename */ void SanitizeFilename(char *filename) { for (; *filename != '\0'; filename++) { switch (*filename) { /* The following characters are not allowed in filenames * on at least one of the supported operating systems: */ case ':': case '\\': case '*': case '?': case '/': case '<': case '>': case '|': case '"': *filename = '_'; break; } } } /** * Load a file into memory. * @param filename Name of the file to load. * @param lenp [out] Length of loaded data. * @param maxsize Maximum size to load. * @return Pointer to new memory containing the loaded data, or \c NULL if loading failed. * @note If \a maxsize less than the length of the file, loading fails. */ void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) { FILE *in = fopen(filename, "rb"); if (in == NULL) return NULL; fseek(in, 0, SEEK_END); size_t len = ftell(in); fseek(in, 0, SEEK_SET); if (len > maxsize) { fclose(in); return NULL; } byte *mem = MallocT(len + 1); mem[len] = 0; if (fread(mem, len, 1, in) != 1) { fclose(in); free(mem); return NULL; } fclose(in); *lenp = len; return mem; } /** * Helper to see whether a given filename matches the extension. * @param extension The extension to look for. * @param filename The filename to look in for the extension. * @return True iff the extension is NULL, or the filename ends with it. */ static bool MatchesExtension(const char *extension, const char *filename) { if (extension == NULL) return true; const char *ext = strrchr(filename, extension[0]); return ext != NULL && strcasecmp(ext, extension) == 0; } /** * Scan a single directory (and recursively its children) and add * any graphics sets that are found. * @param fs the file scanner to add the files to * @param extension the extension of files to search for. * @param path full path we're currently at * @param basepath_length from where in the path are we 'based' on the search path * @param recursive whether to recursively search the sub directories */ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, size_t basepath_length, bool recursive) { extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb); uint num = 0; struct stat sb; struct dirent *dirent; DIR *dir; if (path == NULL || (dir = ttd_opendir(path)) == NULL) return 0; while ((dirent = readdir(dir)) != NULL) { const char *d_name = FS2OTTD(dirent->d_name); char filename[MAX_PATH]; if (!FiosIsValidFile(path, dirent, &sb)) continue; seprintf(filename, lastof(filename), "%s%s", path, d_name); if (S_ISDIR(sb.st_mode)) { /* Directory */ if (!recursive) continue; if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; if (!AppendPathSeparator(filename, lastof(filename))) continue; num += ScanPath(fs, extension, filename, basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { /* File */ if (MatchesExtension(extension, filename) && fs->AddFile(filename, basepath_length, NULL)) num++; } } closedir(dir); return num; } /** * Scan the given tar and add graphics sets when it finds one. * @param fs the file scanner to scan for * @param extension the extension of files to search for. * @param tar the tar to search in. */ static uint ScanTar(FileScanner *fs, const char *extension, TarFileList::iterator tar) { uint num = 0; const char *filename = (*tar).first.c_str(); if (MatchesExtension(extension, filename) && fs->AddFile(filename, 0, (*tar).second.tar_filename)) num++; return num; } /** * Scan for files with the given extension in the given search path. * @param extension the extension of files to search for. * @param sd the sub directory to search in. * @param tars whether to search in the tars too. * @param recursive whether to search recursively * @return the number of found files, i.e. the number of times that * AddFile returned true. */ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool recursive) { this->subdir = sd; Searchpath sp; char path[MAX_PATH]; TarFileList::iterator tar; uint num = 0; FOR_ALL_SEARCHPATHS(sp) { /* Don't search in the working directory */ if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; FioAppendDirectory(path, lastof(path), sp, sd); num += ScanPath(this, extension, path, strlen(path), recursive); } if (tars && sd != NO_DIRECTORY) { FOR_ALL_TARS(tar, sd) { num += ScanTar(this, extension, tar); } } switch (sd) { case BASESET_DIR: num += this->Scan(extension, OLD_GM_DIR, tars, recursive); /* FALL THROUGH */ case NEWGRF_DIR: num += this->Scan(extension, OLD_DATA_DIR, tars, recursive); break; default: break; } return num; } /** * Scan for files with the given extension in the given search path. * @param extension the extension of files to search for. * @param directory the sub directory to search in. * @param recursive whether to search recursively * @return the number of found files, i.e. the number of times that * AddFile returned true. */ uint FileScanner::Scan(const char *extension, const char *directory, bool recursive) { char path[MAX_PATH]; strecpy(path, directory, lastof(path)); if (!AppendPathSeparator(path, lastof(path))) return 0; return ScanPath(this, extension, path, strlen(path), recursive); } openttd-1.5.3/src/waypoint.cpp0000644000000000000000000000320112627373434015047 0ustar rootroot/* $Id: waypoint.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 waypoint.cpp Handling of waypoints. */ #include "stdafx.h" #include "order_func.h" #include "window_func.h" #include "newgrf_station.h" #include "waypoint_base.h" #include "safeguards.h" /** * Draw a waypoint * @param x coordinate * @param y coordinate * @param stat_id station id * @param railtype RailType to use for */ void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype) { if (!DrawStationTile(x, y, railtype, AXIS_X, STAT_CLASS_WAYP, stat_id)) { StationPickerDrawSprite(x, y, STATION_WAYPOINT, railtype, INVALID_ROADTYPE, AXIS_X); } } void Waypoint::GetTileArea(TileArea *ta, StationType type) const { switch (type) { case STATION_WAYPOINT: *ta = this->train_station; return; case STATION_BUOY: ta->tile = this->xy; ta->w = 1; ta->h = 1; break; default: NOT_REACHED(); } } Waypoint::~Waypoint() { if (CleaningPool()) return; DeleteWindowById(WC_WAYPOINT_VIEW, this->index); RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, this->index); } openttd-1.5.3/src/gfxinit.h0000644000000000000000000000144012627373446014320 0ustar rootroot/* $Id: gfxinit.h 18028 2009-11-09 10:40:33Z rubidium $ */ /* * 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 gfxinit.h Functions related to the graphics initialization. */ #ifndef GFXINIT_H #define GFXINIT_H void GfxLoadSprites(); #endif /* GFXINIT_H */ openttd-1.5.3/src/strings.cpp0000644000000000000000000021462612627373445014707 0ustar rootroot/* $Id: strings.cpp 27102 2015-01-01 20:50:43Z rubidium $ */ /* * 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 strings.cpp Handling of translated strings. */ #include "stdafx.h" #include "currency.h" #include "station_base.h" #include "town.h" #include "waypoint_base.h" #include "depot_base.h" #include "industry.h" #include "newgrf_text.h" #include "fileio_func.h" #include "signs_base.h" #include "fontdetection.h" #include "error.h" #include "strings_func.h" #include "rev.h" #include "core/endian_func.hpp" #include "date_func.h" #include "vehicle_base.h" #include "engine_base.h" #include "language.h" #include "townname_func.h" #include "string_func.h" #include "company_base.h" #include "smallmap_gui.h" #include "window_func.h" #include "debug.h" #include "game/game_text.hpp" #include #include "table/strings.h" #include "table/control_codes.h" #include "safeguards.h" char _config_language_file[MAX_PATH]; ///< The file (name) stored in the configuration. LanguageList _languages; ///< The actual list of language meta data. const LanguageMetadata *_current_language = NULL; ///< The currently loaded language. TextDirection _current_text_dir; ///< Text direction of the currently selected language. #ifdef WITH_ICU Collator *_current_collator = NULL; ///< Collator for the language currently in use. #endif /* WITH_ICU */ static uint64 _global_string_params_data[20]; ///< Global array of string parameters. To access, use #SetDParam. static WChar _global_string_params_type[20]; ///< Type of parameters stored in #_decode_parameters StringParameters _global_string_params(_global_string_params_data, 20, _global_string_params_type); /** Reset the type array. */ void StringParameters::ClearTypeInformation() { assert(this->type != NULL); MemSetT(this->type, 0, this->num_param); } /** * Read an int64 from the argument array. The offset is increased * so the next time GetInt64 is called the next value is read. */ int64 StringParameters::GetInt64(WChar type) { if (this->offset >= this->num_param) { DEBUG(misc, 0, "Trying to read invalid string parameter"); return 0; } if (this->type != NULL) { assert(this->type[this->offset] == 0 || this->type[this->offset] == type); this->type[this->offset] = type; } return this->data[this->offset++]; } /** * Shift all data in the data array by the given amount to make * room for some extra parameters. */ void StringParameters::ShiftParameters(uint amount) { assert(amount <= this->num_param); MemMoveT(this->data + amount, this->data, this->num_param - amount); } /** * Set DParam n to some number that is suitable for string size computations. * @param n Index of the string parameter. * @param max_value The biggest value which shall be displayed. * For the result only the number of digits of \a max_value matter. * @param min_count Minimum number of digits independent of \a max. * @param size Font of the number */ void SetDParamMaxValue(uint n, uint64 max_value, uint min_count, FontSize size) { uint num_digits = 1; while (max_value >= 10) { num_digits++; max_value /= 10; } SetDParamMaxDigits(n, max(min_count, num_digits), size); } /** * Set DParam n to some number that is suitable for string size computations. * @param n Index of the string parameter. * @param count Number of digits which shall be displayable. * @param size Font of the number */ void SetDParamMaxDigits(uint n, uint count, FontSize size) { uint front, next; GetBroadestDigit(&front, &next, size); uint64 val = count > 1 ? front : next; for (; count > 1; count--) { val = 10 * val + next; } SetDParam(n, val); } /** * Copy \a num string parameters from array \a src into the global string parameter array. * @param offs Index in the global array to copy the first string parameter to. * @param src Source array of string parameters. * @param num Number of string parameters to copy. */ void CopyInDParam(int offs, const uint64 *src, int num) { MemCpyT(_global_string_params.GetPointerToOffset(offs), src, num); } /** * Copy \a num string parameters from the global string parameter array to the \a dst array. * @param dst Destination array of string parameters. * @param offs Index in the global array to copy the first string parameter from. * @param num Number of string parameters to copy. */ void CopyOutDParam(uint64 *dst, int offs, int num) { MemCpyT(dst, _global_string_params.GetPointerToOffset(offs), num); } /** * Copy \a num string parameters from the global string parameter array to the \a dst array. * Furthermore clone raw string parameters into \a strings and amend the data in \a dst. * @param dst Destination array of string parameters. * @param strings Destination array for clone of the raw strings. Must be of same length as dst. Deallocation left to the caller. * @param string The string used to determine where raw strings are and where there are no raw strings. * @param num Number of string parameters to copy. */ void CopyOutDParam(uint64 *dst, const char **strings, StringID string, int num) { char buf[DRAW_STRING_BUFFER]; GetString(buf, string, lastof(buf)); MemCpyT(dst, _global_string_params.GetPointerToOffset(0), num); for (int i = 0; i < num; i++) { if (_global_string_params.HasTypeInformation() && _global_string_params.GetTypeAtOffset(i) == SCC_RAW_STRING_POINTER) { strings[i] = stredup((const char *)(size_t)_global_string_params.GetParam(i)); dst[i] = (size_t)strings[i]; } else { strings[i] = NULL; } } } static char *StationGetSpecialString(char *buff, int x, const char *last); static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last); static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last); static char *FormatString(char *buff, const char *str, StringParameters *args, const char *last, uint case_index = 0, bool game_script = false, bool dry_run = false); struct LanguagePack : public LanguagePackHeader { char data[]; // list of strings }; static char **_langpack_offs; static LanguagePack *_langpack; static uint _langtab_num[TAB_COUNT]; ///< Offset into langpack offs static uint _langtab_start[TAB_COUNT]; ///< Offset into langpack offs static bool _scan_for_gender_data = false; ///< Are we scanning for the gender of the current string? (instead of formatting it) const char *GetStringPtr(StringID string) { switch (GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)) { case GAME_TEXT_TAB: return GetGameStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS)); /* 0xD0xx and 0xD4xx IDs have been converted earlier. */ case 26: NOT_REACHED(); case 28: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS)); case 29: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x0800); case 30: return GetGRFStringPtr(GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS) + 0x1000); default: return _langpack_offs[_langtab_start[GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS)] + GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS)]; } } /** * Get a parsed string with most special stringcodes replaced by the string parameters. * @param buffr Pointer to a string buffer where the formatted string should be written to. * @param string * @param args Arguments for the string. * @param last Pointer just past the end of \a buffr. * @param case_index The "case index". This will only be set when FormatString wants to print the string in a different case. * @param game_script The string is coming directly from a game script. * @return Pointer to the final zero byte of the formatted string. */ char *GetStringWithArgs(char *buffr, StringID string, StringParameters *args, const char *last, uint case_index, bool game_script) { if (string == 0) return GetStringWithArgs(buffr, STR_UNDEFINED, args, last); uint index = GB(string, TAB_SIZE_OFFSET, TAB_SIZE_BITS); uint tab = GB(string, TAB_COUNT_OFFSET, TAB_COUNT_BITS); switch (tab) { case 4: if (index >= 0xC0 && !game_script) { return GetSpecialTownNameString(buffr, index - 0xC0, args->GetInt32(), last); } break; case 14: if (index >= 0xE4 && !game_script) { return GetSpecialNameString(buffr, index - 0xE4, args, last); } break; case 15: /* Old table for custom names. This is no longer used */ if (!game_script) { error("Incorrect conversion of custom name string."); } break; case GAME_TEXT_TAB: return FormatString(buffr, GetGameStringPtr(index), args, last, case_index, true); case 26: NOT_REACHED(); case 28: return FormatString(buffr, GetGRFStringPtr(index), args, last, case_index); case 29: return FormatString(buffr, GetGRFStringPtr(index + 0x0800), args, last, case_index); case 30: return FormatString(buffr, GetGRFStringPtr(index + 0x1000), args, last, case_index); } if (index >= _langtab_num[tab]) { if (game_script) { return GetStringWithArgs(buffr, STR_UNDEFINED, args, last); } error("String 0x%X is invalid. You are probably using an old version of the .lng file.\n", string); } return FormatString(buffr, GetStringPtr(string), args, last, case_index); } char *GetString(char *buffr, StringID string, const char *last) { _global_string_params.ClearTypeInformation(); _global_string_params.offset = 0; return GetStringWithArgs(buffr, string, &_global_string_params, last); } /** * This function is used to "bind" a C string to a OpenTTD dparam slot. * @param n slot of the string * @param str string to bind */ void SetDParamStr(uint n, const char *str) { SetDParam(n, (uint64)(size_t)str); } /** * Shift the string parameters in the global string parameter array by \a amount positions, making room at the beginning. * @param amount Number of positions to shift. */ void InjectDParam(uint amount) { _global_string_params.ShiftParameters(amount); } /** * Format a number into a string. * @param buff the buffer to write to * @param number the number to write down * @param last the last element in the buffer * @param separator the thousands-separator to use * @param zerofill minimum number of digits to print for the integer part. The number will be filled with zeros at the front if necessary. * @param fractional_digits number of fractional digits to display after a decimal separator. The decimal separator is inserted * in front of the \a fractional_digits last digit of \a number. * @return till where we wrote */ static char *FormatNumber(char *buff, int64 number, const char *last, const char *separator, int zerofill = 1, int fractional_digits = 0) { static const int max_digits = 20; uint64 divisor = 10000000000000000000ULL; zerofill += fractional_digits; int thousands_offset = (max_digits - fractional_digits - 1) % 3; if (number < 0) { buff += seprintf(buff, last, "-"); number = -number; } uint64 num = number; uint64 tot = 0; for (int i = 0; i < max_digits; i++) { if (i == max_digits - fractional_digits) { const char *decimal_separator = _settings_game.locale.digit_decimal_separator; if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator; buff += seprintf(buff, last, "%s", decimal_separator); } uint64 quot = 0; if (num >= divisor) { quot = num / divisor; num = num % divisor; } if ((tot |= quot) || i >= max_digits - zerofill) { buff += seprintf(buff, last, "%i", (int)quot); if ((i % 3) == thousands_offset && i < max_digits - 1 - fractional_digits) buff = strecpy(buff, separator, last); } divisor /= 10; } *buff = '\0'; return buff; } static char *FormatCommaNumber(char *buff, int64 number, const char *last, int fractional_digits = 0) { const char *separator = _settings_game.locale.digit_group_separator; if (separator == NULL) separator = _langpack->digit_group_separator; return FormatNumber(buff, number, last, separator, 1, fractional_digits); } static char *FormatNoCommaNumber(char *buff, int64 number, const char *last) { return FormatNumber(buff, number, last, ""); } static char *FormatZerofillNumber(char *buff, int64 number, int64 count, const char *last) { return FormatNumber(buff, number, last, "", count); } static char *FormatHexNumber(char *buff, uint64 number, const char *last) { return buff + seprintf(buff, last, "0x" OTTD_PRINTFHEX64, number); } /** * Format a given number as a number of bytes with the SI prefix. * @param buff the buffer to write to * @param number the number of bytes to write down * @param last the last element in the buffer * @return till where we wrote */ static char *FormatBytes(char *buff, int64 number, const char *last) { assert(number >= 0); /* 1 2^10 2^20 2^30 2^40 2^50 2^60 */ const char * const iec_prefixes[] = {"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei"}; uint id = 1; while (number >= 1024 * 1024) { number /= 1024; id++; } const char *decimal_separator = _settings_game.locale.digit_decimal_separator; if (decimal_separator == NULL) decimal_separator = _langpack->digit_decimal_separator; if (number < 1024) { id = 0; buff += seprintf(buff, last, "%i", (int)number); } else if (number < 1024 * 10) { buff += seprintf(buff, last, "%i%s%02i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 100 / 1024); } else if (number < 1024 * 100) { buff += seprintf(buff, last, "%i%s%01i", (int)number / 1024, decimal_separator, (int)(number % 1024) * 10 / 1024); } else { assert(number < 1024 * 1024); buff += seprintf(buff, last, "%i", (int)number / 1024); } assert(id < lengthof(iec_prefixes)); buff += seprintf(buff, last, NBSP "%sB", iec_prefixes[id]); return buff; } static char *FormatYmdString(char *buff, Date date, const char *last, uint case_index) { YearMonthDay ymd; ConvertDateToYMD(date, &ymd); int64 args[] = {ymd.day + STR_DAY_NUMBER_1ST - 1, STR_MONTH_ABBREV_JAN + ymd.month, ymd.year}; StringParameters tmp_params(args); return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_LONG), &tmp_params, last, case_index); } static char *FormatMonthAndYear(char *buff, Date date, const char *last, uint case_index) { YearMonthDay ymd; ConvertDateToYMD(date, &ymd); int64 args[] = {STR_MONTH_JAN + ymd.month, ymd.year}; StringParameters tmp_params(args); return FormatString(buff, GetStringPtr(STR_FORMAT_DATE_SHORT), &tmp_params, last, case_index); } static char *FormatTinyOrISODate(char *buff, Date date, StringID str, const char *last) { YearMonthDay ymd; ConvertDateToYMD(date, &ymd); char day[3]; char month[3]; /* We want to zero-pad the days and months */ seprintf(day, lastof(day), "%02i", ymd.day); seprintf(month, lastof(month), "%02i", ymd.month + 1); int64 args[] = {(int64)(size_t)day, (int64)(size_t)month, ymd.year}; StringParameters tmp_params(args); return FormatString(buff, GetStringPtr(str), &tmp_params, last); } static char *FormatGenericCurrency(char *buff, const CurrencySpec *spec, Money number, bool compact, const char *last) { /* We are going to make number absolute for printing, so * keep this piece of data as we need it later on */ bool negative = number < 0; const char *multiplier = ""; number *= spec->rate; /* convert from negative */ if (number < 0) { if (buff + Utf8CharLen(SCC_RED) > last) return buff; buff += Utf8Encode(buff, SCC_RED); buff = strecpy(buff, "-", last); number = -number; } /* Add prefix part, following symbol_pos specification. * Here, it can can be either 0 (prefix) or 2 (both prefix and suffix). * The only remaining value is 1 (suffix), so everything that is not 1 */ if (spec->symbol_pos != 1) buff = strecpy(buff, spec->prefix, last); /* for huge numbers, compact the number into k or M */ if (compact) { /* Take care of the 'k' rounding. Having 1 000 000 k * and 1 000 M is inconsistent, so always use 1 000 M. */ if (number >= 1000000000 - 500) { number = (number + 500000) / 1000000; multiplier = NBSP "M"; } else if (number >= 1000000) { number = (number + 500) / 1000; multiplier = NBSP "k"; } } const char *separator = _settings_game.locale.digit_group_separator_currency; if (separator == NULL && !StrEmpty(_currency->separator)) separator = _currency->separator; if (separator == NULL) separator = _langpack->digit_group_separator_currency; buff = FormatNumber(buff, number, last, separator); buff = strecpy(buff, multiplier, last); /* Add suffix part, following symbol_pos specification. * Here, it can can be either 1 (suffix) or 2 (both prefix and suffix). * The only remaining value is 1 (prefix), so everything that is not 0 */ if (spec->symbol_pos != 0) buff = strecpy(buff, spec->suffix, last); if (negative) { if (buff + Utf8CharLen(SCC_PREVIOUS_COLOUR) > last) return buff; buff += Utf8Encode(buff, SCC_PREVIOUS_COLOUR); *buff = '\0'; } return buff; } /** * Determine the "plural" index given a plural form and a number. * @param count The number to get the plural index of. * @param plural_form The plural form we want an index for. * @return The plural index for the given form. */ static int DeterminePluralForm(int64 count, int plural_form) { /* The absolute value determines plurality */ uint64 n = abs(count); switch (plural_form) { default: NOT_REACHED(); /* Two forms: singular used for one only. * Used in: * Danish, Dutch, English, German, Norwegian, Swedish, Estonian, Finnish, * Greek, Hebrew, Italian, Portuguese, Spanish, Esperanto */ case 0: return n != 1 ? 1 : 0; /* Only one form. * Used in: * Hungarian, Japanese, Korean, Turkish */ case 1: return 0; /* Two forms: singular used for 0 and 1. * Used in: * French, Brazilian Portuguese */ case 2: return n > 1 ? 1 : 0; /* Three forms: special cases for 0, and numbers ending in 1 except when ending in 11. * Note: Cases are out of order for hysterical reasons. '0' is last. * Used in: * Latvian */ case 3: return n % 10 == 1 && n % 100 != 11 ? 0 : n != 0 ? 1 : 2; /* Five forms: special cases for 1, 2, 3 to 6, and 7 to 10. * Used in: * Gaelige (Irish) */ case 4: return n == 1 ? 0 : n == 2 ? 1 : n < 7 ? 2 : n < 11 ? 3 : 4; /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 9 except when ending in 12 to 19. * Used in: * Lithuanian */ case 5: return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; /* Three forms: special cases for numbers ending in 1 except when ending in 11, and 2 to 4 except when ending in 12 to 14. * Used in: * Croatian, Russian, Ukrainian */ case 6: return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; /* Three forms: special cases for 1, and numbers ending in 2 to 4 except when ending in 12 to 14. * Used in: * Polish */ case 7: return n == 1 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2; /* Four forms: special cases for numbers ending in 01, 02, and 03 to 04. * Used in: * Slovenian */ case 8: return n % 100 == 1 ? 0 : n % 100 == 2 ? 1 : n % 100 == 3 || n % 100 == 4 ? 2 : 3; /* Two forms: singular used for numbers ending in 1 except when ending in 11. * Used in: * Icelandic */ case 9: return n % 10 == 1 && n % 100 != 11 ? 0 : 1; /* Three forms: special cases for 1, and 2 to 4 * Used in: * Czech, Slovak */ case 10: return n == 1 ? 0 : n >= 2 && n <= 4 ? 1 : 2; /* Two forms: cases for numbers ending with a consonant, and with a vowel. * Korean doesn't have the concept of plural, but depending on how a * number is pronounced it needs another version of a particle. * As such the plural system is misused to give this distinction. */ case 11: switch (n % 10) { case 0: // yeong case 1: // il case 3: // sam case 6: // yuk case 7: // chil case 8: // pal return 0; case 2: // i case 4: // sa case 5: // o case 9: // gu return 1; default: NOT_REACHED(); } /* Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19. * Used in: * Maltese */ case 12: return (n == 1 ? 0 : n == 0 || (n % 100 > 1 && n % 100 < 11) ? 1 : (n % 100 > 10 && n % 100 < 20) ? 2 : 3); /* Four forms: special cases for 1 and 11, 2 and 12, 3 .. 10 and 13 .. 19, other * Used in: * Scottish Gaelic */ case 13: return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3); } } static const char *ParseStringChoice(const char *b, uint form, char **dst, const char *last) { /* {Length of each string} {each string} */ uint n = (byte)*b++; uint pos, i, mypos = 0; for (i = pos = 0; i != n; i++) { uint len = (byte)*b++; if (i == form) mypos = pos; pos += len; } *dst += seprintf(*dst, last, "%s", b + mypos); return b + pos; } /** Helper for unit conversion. */ struct UnitConversion { int multiplier; ///< Amount to multiply upon conversion. int shift; ///< Amount to shift upon conversion. /** * Convert value from OpenTTD's internal unit into the displayed value. * @param input The input to convert. * @param round Whether to round the value or not. * @return The converted value. */ int64 ToDisplay(int64 input, bool round = true) const { return ((input * this->multiplier) + (round && this->shift != 0 ? 1 << (this->shift - 1) : 0)) >> this->shift; } /** * Convert the displayed value back into a value of OpenTTD's internal unit. * @param input The input to convert. * @param round Whether to round the value up or not. * @param divider Divide the return value by this. * @return The converted value. */ int64 FromDisplay(int64 input, bool round = true, int64 divider = 1) const { return ((input << this->shift) + (round ? (this->multiplier * divider) - 1 : 0)) / (this->multiplier * divider); } }; /** Information about a specific unit system. */ struct Units { UnitConversion c; ///< Conversion StringID s; ///< String for the unit }; /** Information about a specific unit system with a long variant. */ struct UnitsLong { UnitConversion c; ///< Conversion StringID s; ///< String for the short variant of the unit StringID l; ///< String for the long variant of the unit }; /** Unit conversions for velocity. */ static const Units _units_velocity[] = { { { 1, 0}, STR_UNITS_VELOCITY_IMPERIAL }, { { 103, 6}, STR_UNITS_VELOCITY_METRIC }, { {1831, 12}, STR_UNITS_VELOCITY_SI }, }; /** Unit conversions for velocity. */ static const Units _units_power[] = { { { 1, 0}, STR_UNITS_POWER_IMPERIAL }, { {4153, 12}, STR_UNITS_POWER_METRIC }, { {6109, 13}, STR_UNITS_POWER_SI }, }; /** Unit conversions for weight. */ static const UnitsLong _units_weight[] = { { {4515, 12}, STR_UNITS_WEIGHT_SHORT_IMPERIAL, STR_UNITS_WEIGHT_LONG_IMPERIAL }, { { 1, 0}, STR_UNITS_WEIGHT_SHORT_METRIC, STR_UNITS_WEIGHT_LONG_METRIC }, { {1000, 0}, STR_UNITS_WEIGHT_SHORT_SI, STR_UNITS_WEIGHT_LONG_SI }, }; /** Unit conversions for volume. */ static const UnitsLong _units_volume[] = { { {4227, 4}, STR_UNITS_VOLUME_SHORT_IMPERIAL, STR_UNITS_VOLUME_LONG_IMPERIAL }, { {1000, 0}, STR_UNITS_VOLUME_SHORT_METRIC, STR_UNITS_VOLUME_LONG_METRIC }, { { 1, 0}, STR_UNITS_VOLUME_SHORT_SI, STR_UNITS_VOLUME_LONG_SI }, }; /** Unit conversions for force. */ static const Units _units_force[] = { { {3597, 4}, STR_UNITS_FORCE_IMPERIAL }, { {3263, 5}, STR_UNITS_FORCE_METRIC }, { { 1, 0}, STR_UNITS_FORCE_SI }, }; /** Unit conversions for height. */ static const Units _units_height[] = { { { 3, 0}, STR_UNITS_HEIGHT_IMPERIAL }, // "Wrong" conversion factor for more nicer GUI values { { 1, 0}, STR_UNITS_HEIGHT_METRIC }, { { 1, 0}, STR_UNITS_HEIGHT_SI }, }; /** * Convert the given (internal) speed to the display speed. * @param speed the speed to convert * @return the converted speed. */ uint ConvertSpeedToDisplaySpeed(uint speed) { /* For historical reasons we don't want to mess with the * conversion for speed. So, don't round it and keep the * original conversion factors instead of the real ones. */ return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed, false); } /** * Convert the given display speed to the (internal) speed. * @param speed the speed to convert * @return the converted speed. */ uint ConvertDisplaySpeedToSpeed(uint speed) { return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed); } /** * Convert the given km/h-ish speed to the display speed. * @param speed the speed to convert * @return the converted speed. */ uint ConvertKmhishSpeedToDisplaySpeed(uint speed) { return _units_velocity[_settings_game.locale.units_velocity].c.ToDisplay(speed * 10, false) / 16; } /** * Convert the given display speed to the km/h-ish speed. * @param speed the speed to convert * @return the converted speed. */ uint ConvertDisplaySpeedToKmhishSpeed(uint speed) { return _units_velocity[_settings_game.locale.units_velocity].c.FromDisplay(speed * 16, true, 10); } /** * Parse most format codes within a string and write the result to a buffer. * @param buff The buffer to write the final string to. * @param str The original string with format codes. * @param args Pointer to extra arguments used by various string codes. * @param case_index * @param last Pointer to just past the end of the buff array. * @param dry_run True when the argt array is not yet initialized. */ static char *FormatString(char *buff, const char *str_arg, StringParameters *args, const char *last, uint case_index, bool game_script, bool dry_run) { uint orig_offset = args->offset; /* When there is no array with types there is no need to do a dry run. */ if (args->HasTypeInformation() && !dry_run) { if (UsingNewGRFTextStack()) { /* Values from the NewGRF text stack are only copied to the normal * argv array at the time they are encountered. That means that if * another string command references a value later in the string it * would fail. We solve that by running FormatString twice. The first * pass makes sure the argv array is correctly filled and the second * pass can reference later values without problems. */ struct TextRefStack *backup = CreateTextRefStackBackup(); FormatString(buff, str_arg, args, last, case_index, game_script, true); RestoreTextRefStackBackup(backup); } else { FormatString(buff, str_arg, args, last, case_index, game_script, true); } /* We have to restore the original offset here to to read the correct values. */ args->offset = orig_offset; } WChar b = '\0'; uint next_substr_case_index = 0; char *buf_start = buff; std::stack str_stack; str_stack.push(str_arg); for (;;) { while (!str_stack.empty() && (b = Utf8Consume(&str_stack.top())) == '\0') { str_stack.pop(); } if (str_stack.empty()) break; const char *&str = str_stack.top(); if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) { /* We need to pass some stuff as it might be modified; oh boy. */ //todo: should argve be passed here too? b = RemapNewGRFStringControlCode(b, buf_start, &buff, &str, (int64 *)args->GetDataPointer(), args->GetDataLeft(), dry_run); if (b == 0) continue; } switch (b) { case SCC_ENCODED: { uint64 sub_args_data[20]; WChar sub_args_type[20]; bool sub_args_need_free[20]; StringParameters sub_args(sub_args_data, 20, sub_args_type); sub_args.ClearTypeInformation(); memset(sub_args_need_free, 0, sizeof(sub_args_need_free)); uint16 stringid; const char *s = str; char *p; stringid = strtol(str, &p, 16); if (*p != ':' && *p != '\0') { while (*p != '\0') p++; str = p; buff = strecat(buff, "(invalid SCC_ENCODED)", last); break; } if (stringid >= TAB_SIZE) { while (*p != '\0') p++; str = p; buff = strecat(buff, "(invalid StringID)", last); break; } int i = 0; while (*p != '\0' && i < 20) { uint64 param; s = ++p; /* Find the next value */ bool instring = false; bool escape = false; for (;; p++) { if (*p == '\\') { escape = true; continue; } if (*p == '"' && escape) { escape = false; continue; } escape = false; if (*p == '"') { instring = !instring; continue; } if (instring) { continue; } if (*p == ':') break; if (*p == '\0') break; } if (*s != '"') { /* Check if we want to look up another string */ WChar l; size_t len = Utf8Decode(&l, s); bool lookup = (l == SCC_ENCODED); if (lookup) s += len; param = strtoull(s, &p, 16); if (lookup) { if (param >= TAB_SIZE) { while (*p != '\0') p++; str = p; buff = strecat(buff, "(invalid sub-StringID)", last); break; } param = (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + param; } sub_args.SetParam(i++, param); } else { char *g = stredup(s); g[p - s] = '\0'; sub_args_need_free[i] = true; sub_args.SetParam(i++, (uint64)(size_t)g); } } /* If we didn't error out, we can actually print the string. */ if (*str != '\0') { str = p; buff = GetStringWithArgs(buff, (GAME_TEXT_TAB << TAB_COUNT_OFFSET) + stringid, &sub_args, last, true); } for (int i = 0; i < 20; i++) { if (sub_args_need_free[i]) free((void *)sub_args.GetParam(i)); } break; } case SCC_NEWGRF_STRINL: { StringID substr = Utf8Consume(&str); str_stack.push(GetStringPtr(substr)); break; } case SCC_NEWGRF_PRINT_WORD_STRING_ID: { StringID substr = args->GetInt32(SCC_NEWGRF_PRINT_WORD_STRING_ID); str_stack.push(GetStringPtr(substr)); case_index = next_substr_case_index; next_substr_case_index = 0; break; } case SCC_GENDER_LIST: { // {G 0 Der Die Das} /* First read the meta data from the language file. */ uint offset = orig_offset + (byte)*str++; int gender = 0; if (!dry_run && args->GetTypeAtOffset(offset) != 0) { /* Now we need to figure out what text to resolve, i.e. * what do we need to draw? So get the actual raw string * first using the control code to get said string. */ char input[4 + 1]; char *p = input + Utf8Encode(input, args->GetTypeAtOffset(offset)); *p = '\0'; /* Now do the string formatting. */ char buf[256]; bool old_sgd = _scan_for_gender_data; _scan_for_gender_data = true; StringParameters tmp_params(args->GetPointerToOffset(offset), args->num_param - offset, NULL); p = FormatString(buf, input, &tmp_params, lastof(buf)); _scan_for_gender_data = old_sgd; *p = '\0'; /* And determine the string. */ const char *s = buf; WChar c = Utf8Consume(&s); /* Does this string have a gender, if so, set it */ if (c == SCC_GENDER_INDEX) gender = (byte)s[0]; } str = ParseStringChoice(str, gender, &buff, last); break; } /* This sets up the gender for the string. * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */ case SCC_GENDER_INDEX: // {GENDER 0} if (_scan_for_gender_data) { buff += Utf8Encode(buff, SCC_GENDER_INDEX); *buff++ = *str++; } else { str++; } break; case SCC_PLURAL_LIST: { // {P} int plural_form = *str++; // contains the plural form for this string uint offset = orig_offset + (byte)*str++; int64 v = *args->GetPointerToOffset(offset); // contains the number that determines plural str = ParseStringChoice(str, DeterminePluralForm(v, plural_form), &buff, last); break; } case SCC_ARG_INDEX: { // Move argument pointer args->offset = orig_offset + (byte)*str++; break; } case SCC_SET_CASE: { // {SET_CASE} /* This is a pseudo command, it's outputted when someone does {STRING.ack} * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */ next_substr_case_index = (byte)*str++; break; } case SCC_SWITCH_CASE: { // {Used to implement case switching} /* <0x9E> * Each LEN is printed using 2 bytes in big endian order. */ uint num = (byte)*str++; while (num) { if ((byte)str[0] == case_index) { /* Found the case, adjust str pointer and continue */ str += 3; break; } /* Otherwise skip to the next case */ str += 3 + (str[1] << 8) + str[2]; num--; } break; } case SCC_REVISION: // {REV} buff = strecpy(buff, _openttd_revision, last); break; case SCC_RAW_STRING_POINTER: { // {RAW_STRING} if (game_script) break; const char *str = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER); buff = FormatString(buff, str, args, last); break; } case SCC_STRING: {// {STRING} StringID str = args->GetInt32(SCC_STRING); if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break; /* WARNING. It's prohibited for the included string to consume any arguments. * For included strings that consume argument, you should use STRING1, STRING2 etc. * To debug stuff you can set argv to NULL and it will tell you */ StringParameters tmp_params(args->GetDataPointer(), args->GetDataLeft(), NULL); buff = GetStringWithArgs(buff, str, &tmp_params, last, next_substr_case_index, game_script); next_substr_case_index = 0; break; } case SCC_STRING1: case SCC_STRING2: case SCC_STRING3: case SCC_STRING4: case SCC_STRING5: case SCC_STRING6: case SCC_STRING7: { // {STRING1..7} /* Strings that consume arguments */ StringID str = args->GetInt32(b); if (game_script && GB(str, TAB_COUNT_OFFSET, TAB_COUNT_BITS) != GAME_TEXT_TAB) break; uint size = b - SCC_STRING1 + 1; if (game_script && size > args->GetDataLeft()) { buff = strecat(buff, "(too many parameters)", last); } else { StringParameters sub_args(*args, size); buff = GetStringWithArgs(buff, str, &sub_args, last, next_substr_case_index, game_script); } next_substr_case_index = 0; break; } case SCC_COMMA: // {COMMA} buff = FormatCommaNumber(buff, args->GetInt64(SCC_COMMA), last); break; case SCC_DECIMAL: {// {DECIMAL} int64 number = args->GetInt64(SCC_DECIMAL); int digits = args->GetInt32(SCC_DECIMAL); buff = FormatCommaNumber(buff, number, last, digits); break; } case SCC_NUM: // {NUM} buff = FormatNoCommaNumber(buff, args->GetInt64(SCC_NUM), last); break; case SCC_ZEROFILL_NUM: { // {ZEROFILL_NUM} int64 num = args->GetInt64(); buff = FormatZerofillNumber(buff, num, args->GetInt64(), last); break; } case SCC_HEX: // {HEX} buff = FormatHexNumber(buff, (uint64)args->GetInt64(SCC_HEX), last); break; case SCC_BYTES: // {BYTES} buff = FormatBytes(buff, args->GetInt64(), last); break; case SCC_CARGO_TINY: { // {CARGO_TINY} /* Tiny description of cargotypes. Layout: * param 1: cargo type * param 2: cargo count */ CargoID cargo = args->GetInt32(SCC_CARGO_TINY); if (cargo >= CargoSpec::GetArraySize()) break; StringID cargo_str = CargoSpec::Get(cargo)->units_volume; int64 amount = 0; switch (cargo_str) { case STR_TONS: amount = _units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64()); break; case STR_LITERS: amount = _units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64()); break; default: { amount = args->GetInt64(); break; } } buff = FormatCommaNumber(buff, amount, last); break; } case SCC_CARGO_SHORT: { // {CARGO_SHORT} /* Short description of cargotypes. Layout: * param 1: cargo type * param 2: cargo count */ CargoID cargo = args->GetInt32(SCC_CARGO_SHORT); if (cargo >= CargoSpec::GetArraySize()) break; StringID cargo_str = CargoSpec::Get(cargo)->units_volume; switch (cargo_str) { case STR_TONS: { assert(_settings_game.locale.units_weight < lengthof(_units_weight)); int64 args_array[] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last); break; } case STR_LITERS: { assert(_settings_game.locale.units_volume < lengthof(_units_volume)); int64 args_array[] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last); break; } default: { StringParameters tmp_params(*args, 1); buff = GetStringWithArgs(buff, cargo_str, &tmp_params, last); break; } } break; } case SCC_CARGO_LONG: { // {CARGO_LONG} /* First parameter is cargo type, second parameter is cargo count */ CargoID cargo = args->GetInt32(SCC_CARGO_LONG); if (cargo != CT_INVALID && cargo >= CargoSpec::GetArraySize()) break; StringID cargo_str = (cargo == CT_INVALID) ? STR_QUANTITY_N_A : CargoSpec::Get(cargo)->quantifier; StringParameters tmp_args(*args, 1); buff = GetStringWithArgs(buff, cargo_str, &tmp_args, last); break; } case SCC_CARGO_LIST: { // {CARGO_LIST} uint32 cmask = args->GetInt32(SCC_CARGO_LIST); bool first = true; const CargoSpec *cs; FOR_ALL_SORTED_CARGOSPECS(cs) { if (!HasBit(cmask, cs->Index())) continue; if (buff >= last - 2) break; // ',' and ' ' if (first) { first = false; } else { /* Add a comma if this is not the first item */ *buff++ = ','; *buff++ = ' '; } buff = GetStringWithArgs(buff, cs->name, args, last, next_substr_case_index, game_script); } /* If first is still true then no cargo is accepted */ if (first) buff = GetStringWithArgs(buff, STR_JUST_NOTHING, args, last, next_substr_case_index, game_script); *buff = '\0'; next_substr_case_index = 0; /* Make sure we detect any buffer overflow */ assert(buff < last); break; } case SCC_CURRENCY_SHORT: // {CURRENCY_SHORT} buff = FormatGenericCurrency(buff, _currency, args->GetInt64(), true, last); break; case SCC_CURRENCY_LONG: // {CURRENCY_LONG} buff = FormatGenericCurrency(buff, _currency, args->GetInt64(SCC_CURRENCY_LONG), false, last); break; case SCC_DATE_TINY: // {DATE_TINY} buff = FormatTinyOrISODate(buff, args->GetInt32(SCC_DATE_TINY), STR_FORMAT_DATE_TINY, last); break; case SCC_DATE_SHORT: // {DATE_SHORT} buff = FormatMonthAndYear(buff, args->GetInt32(SCC_DATE_SHORT), last, next_substr_case_index); next_substr_case_index = 0; break; case SCC_DATE_LONG: // {DATE_LONG} buff = FormatYmdString(buff, args->GetInt32(SCC_DATE_LONG), last, next_substr_case_index); next_substr_case_index = 0; break; case SCC_DATE_ISO: // {DATE_ISO} buff = FormatTinyOrISODate(buff, args->GetInt32(), STR_FORMAT_DATE_ISO, last); break; case SCC_FORCE: { // {FORCE} assert(_settings_game.locale.units_force < lengthof(_units_force)); int64 args_array[1] = {_units_force[_settings_game.locale.units_force].c.ToDisplay(args->GetInt64())}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_force[_settings_game.locale.units_force].s), &tmp_params, last); break; } case SCC_HEIGHT: { // {HEIGHT} assert(_settings_game.locale.units_height < lengthof(_units_height)); int64 args_array[] = {_units_height[_settings_game.locale.units_height].c.ToDisplay(args->GetInt64())}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_height[_settings_game.locale.units_height].s), &tmp_params, last); break; } case SCC_POWER: { // {POWER} assert(_settings_game.locale.units_power < lengthof(_units_power)); int64 args_array[1] = {_units_power[_settings_game.locale.units_power].c.ToDisplay(args->GetInt64())}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_power[_settings_game.locale.units_power].s), &tmp_params, last); break; } case SCC_VELOCITY: { // {VELOCITY} assert(_settings_game.locale.units_velocity < lengthof(_units_velocity)); int64 args_array[] = {ConvertKmhishSpeedToDisplaySpeed(args->GetInt64(SCC_VELOCITY))}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_velocity[_settings_game.locale.units_velocity].s), &tmp_params, last); break; } case SCC_VOLUME_SHORT: { // {VOLUME_SHORT} assert(_settings_game.locale.units_volume < lengthof(_units_volume)); int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64())}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].s), &tmp_params, last); break; } case SCC_VOLUME_LONG: { // {VOLUME_LONG} assert(_settings_game.locale.units_volume < lengthof(_units_volume)); int64 args_array[1] = {_units_volume[_settings_game.locale.units_volume].c.ToDisplay(args->GetInt64(SCC_VOLUME_LONG))}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_volume[_settings_game.locale.units_volume].l), &tmp_params, last); break; } case SCC_WEIGHT_SHORT: { // {WEIGHT_SHORT} assert(_settings_game.locale.units_weight < lengthof(_units_weight)); int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64())}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].s), &tmp_params, last); break; } case SCC_WEIGHT_LONG: { // {WEIGHT_LONG} assert(_settings_game.locale.units_weight < lengthof(_units_weight)); int64 args_array[1] = {_units_weight[_settings_game.locale.units_weight].c.ToDisplay(args->GetInt64(SCC_WEIGHT_LONG))}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(_units_weight[_settings_game.locale.units_weight].l), &tmp_params, last); break; } case SCC_COMPANY_NAME: { // {COMPANY} const Company *c = Company::GetIfValid(args->GetInt32()); if (c == NULL) break; if (c->name != NULL) { int64 args_array[] = {(uint64)(size_t)c->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { int64 args_array[] = {c->name_2}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, c->name_1, &tmp_params, last); } break; } case SCC_COMPANY_NUM: { // {COMPANY_NUM} CompanyID company = (CompanyID)args->GetInt32(); /* Nothing is added for AI or inactive companies */ if (Company::IsValidHumanID(company)) { int64 args_array[] = {company + 1}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_FORMAT_COMPANY_NUM, &tmp_params, last); } break; } case SCC_DEPOT_NAME: { // {DEPOT} VehicleType vt = (VehicleType)args->GetInt32(SCC_DEPOT_NAME); if (vt == VEH_AIRCRAFT) { uint64 args_array[] = {args->GetInt32()}; WChar types_array[] = {SCC_STATION_NAME}; StringParameters tmp_params(args_array, 1, types_array); buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_AIRCRAFT, &tmp_params, last); break; } const Depot *d = Depot::Get(args->GetInt32()); if (d->name != NULL) { int64 args_array[] = {(uint64)(size_t)d->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { int64 args_array[] = {d->town->index, d->town_cn + 1}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_FORMAT_DEPOT_NAME_TRAIN + 2 * vt + (d->town_cn == 0 ? 0 : 1), &tmp_params, last); } break; } case SCC_ENGINE_NAME: { // {ENGINE} const Engine *e = Engine::GetIfValid(args->GetInt32(SCC_ENGINE_NAME)); if (e == NULL) break; if (e->name != NULL && e->IsEnabled()) { int64 args_array[] = {(uint64)(size_t)e->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { StringParameters tmp_params(NULL, 0, NULL); buff = GetStringWithArgs(buff, e->info.string_id, &tmp_params, last); } break; } case SCC_GROUP_NAME: { // {GROUP} const Group *g = Group::GetIfValid(args->GetInt32()); if (g == NULL) break; if (g->name != NULL) { int64 args_array[] = {(uint64)(size_t)g->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { int64 args_array[] = {g->index}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last); } break; } case SCC_INDUSTRY_NAME: { // {INDUSTRY} const Industry *i = Industry::GetIfValid(args->GetInt32(SCC_INDUSTRY_NAME)); if (i == NULL) break; if (_scan_for_gender_data) { /* Gender is defined by the industry type. * STR_FORMAT_INDUSTRY_NAME may have the town first, so it would result in the gender of the town name */ StringParameters tmp_params(NULL, 0, NULL); buff = FormatString(buff, GetStringPtr(GetIndustrySpec(i->type)->name), &tmp_params, last, next_substr_case_index); } else { /* First print the town name and the industry type name. */ int64 args_array[2] = {i->town->index, GetIndustrySpec(i->type)->name}; StringParameters tmp_params(args_array); buff = FormatString(buff, GetStringPtr(STR_FORMAT_INDUSTRY_NAME), &tmp_params, last, next_substr_case_index); } next_substr_case_index = 0; break; } case SCC_PRESIDENT_NAME: { // {PRESIDENT_NAME} const Company *c = Company::GetIfValid(args->GetInt32(SCC_PRESIDENT_NAME)); if (c == NULL) break; if (c->president_name != NULL) { int64 args_array[] = {(uint64)(size_t)c->president_name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { int64 args_array[] = {c->president_name_2}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, c->president_name_1, &tmp_params, last); } break; } case SCC_STATION_NAME: { // {STATION} StationID sid = args->GetInt32(SCC_STATION_NAME); const Station *st = Station::GetIfValid(sid); if (st == NULL) { /* The station doesn't exist anymore. The only place where we might * be "drawing" an invalid station is in the case of cargo that is * in transit. */ StringParameters tmp_params(NULL, 0, NULL); buff = GetStringWithArgs(buff, STR_UNKNOWN_STATION, &tmp_params, last); break; } if (st->name != NULL) { int64 args_array[] = {(uint64)(size_t)st->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { StringID str = st->string_id; if (st->indtype != IT_INVALID) { /* Special case where the industry provides the name for the station */ const IndustrySpec *indsp = GetIndustrySpec(st->indtype); /* Industry GRFs can change which might remove the station name and * thus cause very strange things. Here we check for that before we * actually set the station name. */ if (indsp->station_name != STR_NULL && indsp->station_name != STR_UNDEFINED) { str = indsp->station_name; } } int64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, str, &tmp_params, last); } break; } case SCC_TOWN_NAME: { // {TOWN} const Town *t = Town::GetIfValid(args->GetInt32(SCC_TOWN_NAME)); if (t == NULL) break; if (t->name != NULL) { int64 args_array[] = {(uint64)(size_t)t->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { buff = GetTownName(buff, t, last); } break; } case SCC_WAYPOINT_NAME: { // {WAYPOINT} Waypoint *wp = Waypoint::GetIfValid(args->GetInt32(SCC_WAYPOINT_NAME)); if (wp == NULL) break; if (wp->name != NULL) { int64 args_array[] = {(uint64)(size_t)wp->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { int64 args_array[] = {wp->town->index, wp->town_cn + 1}; StringParameters tmp_params(args_array); StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_FORMAT_BUOY_NAME : STR_FORMAT_WAYPOINT_NAME); if (wp->town_cn != 0) str++; buff = GetStringWithArgs(buff, str, &tmp_params, last); } break; } case SCC_VEHICLE_NAME: { // {VEHICLE} const Vehicle *v = Vehicle::GetIfValid(args->GetInt32(SCC_VEHICLE_NAME)); if (v == NULL) break; if (v->name != NULL) { int64 args_array[] = {(uint64)(size_t)v->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { int64 args_array[] = {v->unitnumber}; StringParameters tmp_params(args_array); StringID str; switch (v->type) { default: str = STR_INVALID_VEHICLE; break; case VEH_TRAIN: str = STR_SV_TRAIN_NAME; break; case VEH_ROAD: str = STR_SV_ROAD_VEHICLE_NAME; break; case VEH_SHIP: str = STR_SV_SHIP_NAME; break; case VEH_AIRCRAFT: str = STR_SV_AIRCRAFT_NAME; break; } buff = GetStringWithArgs(buff, str, &tmp_params, last); } break; } case SCC_SIGN_NAME: { // {SIGN} const Sign *si = Sign::GetIfValid(args->GetInt32()); if (si == NULL) break; if (si->name != NULL) { int64 args_array[] = {(uint64)(size_t)si->name}; StringParameters tmp_params(args_array); buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); } else { StringParameters tmp_params(NULL, 0, NULL); buff = GetStringWithArgs(buff, STR_DEFAULT_SIGN_NAME, &tmp_params, last); } break; } case SCC_STATION_FEATURES: { // {STATIONFEATURES} buff = StationGetSpecialString(buff, args->GetInt32(SCC_STATION_FEATURES), last); break; } default: if (buff + Utf8CharLen(b) < last) buff += Utf8Encode(buff, b); break; } } *buff = '\0'; return buff; } static char *StationGetSpecialString(char *buff, int x, const char *last) { if ((x & FACIL_TRAIN) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN); if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY); if ((x & FACIL_BUS_STOP) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS); if ((x & FACIL_DOCK) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP); if ((x & FACIL_AIRPORT) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE); *buff = '\0'; return buff; } static char *GetSpecialTownNameString(char *buff, int ind, uint32 seed, const char *last) { return GenerateTownNameString(buff, last, ind, seed); } static const char * const _silly_company_names[] = { "Bloggs Brothers", "Tiny Transport Ltd.", "Express Travel", "Comfy-Coach & Co.", "Crush & Bump Ltd.", "Broken & Late Ltd.", "Sam Speedy & Son", "Supersonic Travel", "Mike's Motors", "Lightning International", "Pannik & Loozit Ltd.", "Inter-City Transport", "Getout & Pushit Ltd." }; static const char * const _surname_list[] = { "Adams", "Allan", "Baker", "Bigwig", "Black", "Bloggs", "Brown", "Campbell", "Gordon", "Hamilton", "Hawthorn", "Higgins", "Green", "Gribble", "Jones", "McAlpine", "MacDonald", "McIntosh", "Muir", "Murphy", "Nelson", "O'Donnell", "Parker", "Phillips", "Pilkington", "Quigley", "Sharkey", "Thomson", "Watkins" }; static const char * const _silly_surname_list[] = { "Grumpy", "Dozy", "Speedy", "Nosey", "Dribble", "Mushroom", "Cabbage", "Sniffle", "Fishy", "Swindle", "Sneaky", "Nutkins" }; static const char _initial_name_letters[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'R', 'S', 'T', 'W', }; static char *GenAndCoName(char *buff, uint32 arg, const char *last) { const char * const *base; uint num; if (_settings_game.game_creation.landscape == LT_TOYLAND) { base = _silly_surname_list; num = lengthof(_silly_surname_list); } else { base = _surname_list; num = lengthof(_surname_list); } buff = strecpy(buff, base[num * GB(arg, 16, 8) >> 8], last); buff = strecpy(buff, " & Co.", last); return buff; } static char *GenPresidentName(char *buff, uint32 x, const char *last) { char initial[] = "?. "; const char * const *base; uint num; uint i; initial[0] = _initial_name_letters[sizeof(_initial_name_letters) * GB(x, 0, 8) >> 8]; buff = strecpy(buff, initial, last); i = (sizeof(_initial_name_letters) + 35) * GB(x, 8, 8) >> 8; if (i < sizeof(_initial_name_letters)) { initial[0] = _initial_name_letters[i]; buff = strecpy(buff, initial, last); } if (_settings_game.game_creation.landscape == LT_TOYLAND) { base = _silly_surname_list; num = lengthof(_silly_surname_list); } else { base = _surname_list; num = lengthof(_surname_list); } buff = strecpy(buff, base[num * GB(x, 16, 8) >> 8], last); return buff; } static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, const char *last) { switch (ind) { case 1: // not used return strecpy(buff, _silly_company_names[min(args->GetInt32() & 0xFFFF, lengthof(_silly_company_names) - 1)], last); case 2: // used for Foobar & Co company names return GenAndCoName(buff, args->GetInt32(), last); case 3: // President name return GenPresidentName(buff, args->GetInt32(), last); } /* town name? */ if (IsInsideMM(ind - 6, 0, SPECSTR_TOWNNAME_LAST - SPECSTR_TOWNNAME_START + 1)) { buff = GetSpecialTownNameString(buff, ind - 6, args->GetInt32(), last); return strecpy(buff, " Transport", last); } /* language name? */ if (IsInsideMM(ind, (SPECSTR_LANGUAGE_START - 0x70E4), (SPECSTR_LANGUAGE_END - 0x70E4) + 1)) { int i = ind - (SPECSTR_LANGUAGE_START - 0x70E4); return strecpy(buff, &_languages[i] == _current_language ? _current_language->own_name : _languages[i].name, last); } /* resolution size? */ if (IsInsideMM(ind, (SPECSTR_RESOLUTION_START - 0x70E4), (SPECSTR_RESOLUTION_END - 0x70E4) + 1)) { int i = ind - (SPECSTR_RESOLUTION_START - 0x70E4); buff += seprintf( buff, last, "%ux%u", _resolutions[i].width, _resolutions[i].height ); return buff; } NOT_REACHED(); } #ifdef ENABLE_NETWORK extern void SortNetworkLanguages(); #else /* ENABLE_NETWORK */ static inline void SortNetworkLanguages() {} #endif /* ENABLE_NETWORK */ /** * Check whether the header is a valid header for OpenTTD. * @return true iff the header is deemed valid. */ bool LanguagePackHeader::IsValid() const { return this->ident == TO_LE32(LanguagePackHeader::IDENT) && this->version == TO_LE32(LANGUAGE_PACK_VERSION) && this->plural_form < LANGUAGE_MAX_PLURAL && this->text_dir <= 1 && this->newgrflangid < MAX_LANG && this->num_genders < MAX_NUM_GENDERS && this->num_cases < MAX_NUM_CASES && StrValid(this->name, lastof(this->name)) && StrValid(this->own_name, lastof(this->own_name)) && StrValid(this->isocode, lastof(this->isocode)) && StrValid(this->digit_group_separator, lastof(this->digit_group_separator)) && StrValid(this->digit_group_separator_currency, lastof(this->digit_group_separator_currency)) && StrValid(this->digit_decimal_separator, lastof(this->digit_decimal_separator)); } /** * Read a particular language. * @param lang The metadata about the language. * @return Whether the loading went okay or not. */ bool ReadLanguagePack(const LanguageMetadata *lang) { /* Current language pack */ size_t len; LanguagePack *lang_pack = (LanguagePack *)ReadFileToMem(lang->file, &len, 1U << 20); if (lang_pack == NULL) return false; /* End of read data (+ terminating zero added in ReadFileToMem()) */ const char *end = (char *)lang_pack + len + 1; /* We need at least one byte of lang_pack->data */ if (end <= lang_pack->data || !lang_pack->IsValid()) { free(lang_pack); return false; } #if TTD_ENDIAN == TTD_BIG_ENDIAN for (uint i = 0; i < TAB_COUNT; i++) { lang_pack->offsets[i] = ReadLE16Aligned(&lang_pack->offsets[i]); } #endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */ uint count = 0; for (uint i = 0; i < TAB_COUNT; i++) { uint16 num = lang_pack->offsets[i]; if (num > TAB_SIZE) { free(lang_pack); return false; } _langtab_start[i] = count; _langtab_num[i] = num; count += num; } /* Allocate offsets */ char **langpack_offs = MallocT(count); /* Fill offsets */ char *s = lang_pack->data; len = (byte)*s++; for (uint i = 0; i < count; i++) { if (s + len >= end) { free(lang_pack); free(langpack_offs); return false; } if (len >= 0xC0) { len = ((len & 0x3F) << 8) + (byte)*s++; if (s + len >= end) { free(lang_pack); free(langpack_offs); return false; } } langpack_offs[i] = s; s += len; len = (byte)*s; *s++ = '\0'; // zero terminate the string } free(_langpack); _langpack = lang_pack; free(_langpack_offs); _langpack_offs = langpack_offs; _current_language = lang; _current_text_dir = (TextDirection)_current_language->text_dir; const char *c_file = strrchr(_current_language->file, PATHSEPCHAR) + 1; strecpy(_config_language_file, c_file, lastof(_config_language_file)); SetCurrentGrfLangID(_current_language->newgrflangid); #ifdef WITH_ICU /* Delete previous collator. */ if (_current_collator != NULL) { delete _current_collator; _current_collator = NULL; } /* Create a collator instance for our current locale. */ UErrorCode status = U_ZERO_ERROR; _current_collator = Collator::createInstance(Locale(_current_language->isocode), status); /* Sort number substrings by their numerical value. */ if (_current_collator != NULL) _current_collator->setAttribute(UCOL_NUMERIC_COLLATION, UCOL_ON, status); /* Avoid using the collator if it is not correctly set. */ if (U_FAILURE(status)) { delete _current_collator; _current_collator = NULL; } #endif /* WITH_ICU */ /* Some lists need to be sorted again after a language change. */ ReconsiderGameScriptLanguage(); InitializeSortedCargoSpecs(); SortIndustryTypes(); BuildIndustriesLegend(); SortNetworkLanguages(); InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Build vehicle window. InvalidateWindowClassesData(WC_TRAINS_LIST); // Train group window. InvalidateWindowClassesData(WC_ROADVEH_LIST); // Road vehicle group window. InvalidateWindowClassesData(WC_SHIPS_LIST); // Ship group window. InvalidateWindowClassesData(WC_AIRCRAFT_LIST); // Aircraft group window. InvalidateWindowClassesData(WC_INDUSTRY_DIRECTORY); // Industry directory window. InvalidateWindowClassesData(WC_STATION_LIST); // Station list window. return true; } /* Win32 implementation in win32.cpp. * OS X implementation in os/macosx/macos.mm. */ #if !(defined(WIN32) || defined(__APPLE__)) /** * Determine the current charset based on the environment * First check some default values, after this one we passed ourselves * and if none exist return the value for $LANG * @param param environment variable to check conditionally if default ones are not * set. Pass NULL if you don't want additional checks. * @return return string containing current charset, or NULL if not-determinable */ const char *GetCurrentLocale(const char *param) { const char *env; env = getenv("LANGUAGE"); if (env != NULL) return env; env = getenv("LC_ALL"); if (env != NULL) return env; if (param != NULL) { env = getenv(param); if (env != NULL) return env; } return getenv("LANG"); } #else const char *GetCurrentLocale(const char *param); #endif /* !(defined(WIN32) || defined(__APPLE__)) */ int CDECL StringIDSorter(const StringID *a, const StringID *b) { char stra[512]; char strb[512]; GetString(stra, *a, lastof(stra)); GetString(strb, *b, lastof(strb)); return strnatcmp(stra, strb); } /** * Get the language with the given NewGRF language ID. * @param newgrflangid NewGRF languages ID to check. * @return The language's metadata, or NULL if it is not known. */ const LanguageMetadata *GetLanguage(byte newgrflangid) { for (const LanguageMetadata *lang = _languages.Begin(); lang != _languages.End(); lang++) { if (newgrflangid == lang->newgrflangid) return lang; } return NULL; } /** * Reads the language file header and checks compatibility. * @param file the file to read * @param hdr the place to write the header information to * @return true if and only if the language file is of a compatible version */ static bool GetLanguageFileHeader(const char *file, LanguagePackHeader *hdr) { FILE *f = fopen(file, "rb"); if (f == NULL) return false; size_t read = fread(hdr, sizeof(*hdr), 1, f); fclose(f); bool ret = read == 1 && hdr->IsValid(); /* Convert endianness for the windows language ID */ if (ret) { hdr->missing = FROM_LE16(hdr->missing); hdr->winlangid = FROM_LE16(hdr->winlangid); } return ret; } /** * Gets a list of languages from the given directory. * @param path the base directory to search in */ static void GetLanguageList(const char *path) { DIR *dir = ttd_opendir(path); if (dir != NULL) { struct dirent *dirent; while ((dirent = readdir(dir)) != NULL) { const char *d_name = FS2OTTD(dirent->d_name); const char *extension = strrchr(d_name, '.'); /* Not a language file */ if (extension == NULL || strcmp(extension, ".lng") != 0) continue; LanguageMetadata lmd; seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name); /* Check whether the file is of the correct version */ if (!GetLanguageFileHeader(lmd.file, &lmd)) { DEBUG(misc, 3, "%s is not a valid language file", lmd.file); } else if (GetLanguage(lmd.newgrflangid) != NULL) { DEBUG(misc, 3, "%s's language ID is already known", lmd.file); } else { *_languages.Append() = lmd; } } closedir(dir); } } /** * Make a list of the available language packs. Put the data in * #_languages list. */ void InitializeLanguagePacks() { Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { char path[MAX_PATH]; FioAppendDirectory(path, lastof(path), sp, LANG_DIR); GetLanguageList(path); } if (_languages.Length() == 0) usererror("No available language packs (invalid versions?)"); /* Acquire the locale of the current system */ const char *lang = GetCurrentLocale("LC_MESSAGES"); if (lang == NULL) lang = "en_GB"; const LanguageMetadata *chosen_language = NULL; ///< Matching the language in the configuration file or the current locale const LanguageMetadata *language_fallback = NULL; ///< Using pt_PT for pt_BR locale when pt_BR is not available const LanguageMetadata *en_GB_fallback = _languages.Begin(); ///< Fallback when no locale-matching language has been found /* Find a proper language. */ for (const LanguageMetadata *lng = _languages.Begin(); lng != _languages.End(); lng++) { /* We are trying to find a default language. The priority is by * configuration file, local environment and last, if nothing found, * English. */ const char *lang_file = strrchr(lng->file, PATHSEPCHAR) + 1; if (strcmp(lang_file, _config_language_file) == 0) { chosen_language = lng; break; } if (strcmp (lng->isocode, "en_GB") == 0) en_GB_fallback = lng; if (strncmp(lng->isocode, lang, 5) == 0) chosen_language = lng; if (strncmp(lng->isocode, lang, 2) == 0) language_fallback = lng; } /* We haven't found the language in the config nor the one in the locale. * Now we set it to one of the fallback languages */ if (chosen_language == NULL) { chosen_language = (language_fallback != NULL) ? language_fallback : en_GB_fallback; } if (!ReadLanguagePack(chosen_language)) usererror("Can't read language pack '%s'", chosen_language->file); } /** * Get the ISO language code of the currently loaded language. * @return the ISO code. */ const char *GetCurrentLanguageIsoCode() { return _langpack->isocode; } /** * Check whether there are glyphs missing in the current language. * @param Pointer to an address for storing the text pointer. * @return If glyphs are missing, return \c true, else return \c false. * @post If \c true is returned and str is not NULL, *str points to a string that is found to contain at least one missing glyph. */ bool MissingGlyphSearcher::FindMissingGlyphs(const char **str) { InitFreeType(this->Monospace()); const Sprite *question_mark[FS_END]; for (FontSize size = this->Monospace() ? FS_MONO : FS_BEGIN; size < (this->Monospace() ? FS_END : FS_MONO); size++) { question_mark[size] = GetGlyph(size, '?'); } this->Reset(); for (const char *text = this->NextString(); text != NULL; text = this->NextString()) { FontSize size = this->DefaultSize(); if (str != NULL) *str = text; for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) { if (c == SCC_TINYFONT) { size = FS_SMALL; } else if (c == SCC_BIGFONT) { size = FS_LARGE; } else if (!IsInsideMM(c, SCC_SPRITE_START, SCC_SPRITE_END) && IsPrintable(c) && !IsTextDirectionChar(c) && c != '?' && GetGlyph(size, c) == question_mark[size]) { /* The character is printable, but not in the normal font. This is the case we were testing for. */ return true; } } } return false; } /** Helper for searching through the language pack. */ class LanguagePackGlyphSearcher : public MissingGlyphSearcher { uint i; ///< Iterator for the primary language tables. uint j; ///< Iterator for the secondary language tables. /* virtual */ void Reset() { this->i = 0; this->j = 0; } /* virtual */ FontSize DefaultSize() { return FS_NORMAL; } /* virtual */ const char *NextString() { if (this->i >= TAB_COUNT) return NULL; const char *ret = _langpack_offs[_langtab_start[this->i] + this->j]; this->j++; while (this->i < TAB_COUNT && this->j >= _langtab_num[this->i]) { this->i++; this->j = 0; } return ret; } /* virtual */ bool Monospace() { return false; } /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name) { #ifdef WITH_FREETYPE strecpy(settings->small.font, font_name, lastof(settings->small.font)); strecpy(settings->medium.font, font_name, lastof(settings->medium.font)); strecpy(settings->large.font, font_name, lastof(settings->large.font)); #endif /* WITH_FREETYPE */ } }; /** * Check whether the currently loaded language pack * uses characters that the currently loaded font * does not support. If this is the case an error * message will be shown in English. The error * message will not be localized because that would * mean it might use characters that are not in the * font, which is the whole reason this check has * been added. * @param base_font Whether to look at the base font as well. * @param searcher The methods to use to search for strings to check. * If NULL the loaded language pack searcher is used. */ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher) { static LanguagePackGlyphSearcher pack_searcher; if (searcher == NULL) searcher = &pack_searcher; bool bad_font = !base_font || searcher->FindMissingGlyphs(NULL); #ifdef WITH_FREETYPE if (bad_font) { /* We found an unprintable character... lets try whether we can find * a fallback font that can print the characters in the current language. */ FreeTypeSettings backup; memcpy(&backup, &_freetype, sizeof(backup)); bad_font = !SetFallbackFont(&_freetype, _langpack->isocode, _langpack->winlangid, searcher); memcpy(&_freetype, &backup, sizeof(backup)); if (bad_font && base_font) { /* Our fallback font does miss characters too, so keep the * user chosen font as that is more likely to be any good than * the wild guess we made */ InitFreeType(searcher->Monospace()); } } #endif if (bad_font) { /* All attempts have failed. Display an error. As we do not want the string to be translated by * the translators, we 'force' it into the binary and 'load' it via a BindCString. To do this * properly we have to set the colour of the string, otherwise we end up with a lot of artifacts. * The colour 'character' might change in the future, so for safety we just Utf8 Encode it into * the string, which takes exactly three characters, so it replaces the "XXX" with the colour marker. */ static char *err_str = stredup("XXXThe current font is missing some of the characters used in the texts for this language. Read the readme to see how to solve this."); Utf8Encode(err_str, SCC_YELLOW); SetDParamStr(0, err_str); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_WARNING); /* Reset the font width */ LoadStringWidthTable(searcher->Monospace()); return; } /* Update the font with cache */ LoadStringWidthTable(searcher->Monospace()); #if !defined(WITH_ICU) /* * For right-to-left languages we need the ICU library. If * we do not have support for that library we warn the user * about it with a message. As we do not want the string to * be translated by the translators, we 'force' it into the * binary and 'load' it via a BindCString. To do this * properly we have to set the colour of the string, * otherwise we end up with a lot of artifacts. The colour * 'character' might change in the future, so for safety * we just Utf8 Encode it into the string, which takes * exactly three characters, so it replaces the "XXX" with * the colour marker. */ if (_current_text_dir != TD_LTR) { static char *err_str = stredup("XXXThis version of OpenTTD does not support right-to-left languages. Recompile with icu enabled."); Utf8Encode(err_str, SCC_YELLOW); SetDParamStr(0, err_str); ShowErrorMessage(STR_JUST_RAW_STRING, INVALID_STRING_ID, WL_ERROR); } #endif } openttd-1.5.3/src/crashlog.h0000644000000000000000000001131412627373435014451 0ustar rootroot/* $Id: crashlog.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 crashlog.h Functions to be called to log a crash */ #ifndef CRASHLOG_H #define CRASHLOG_H /** * Helper class for creating crash logs. */ class CrashLog { private: /** Pointer to the error message. */ static const char *message; /** Temporary 'local' location of the buffer. */ static char *gamelog_buffer; /** Temporary 'local' location of the end of the buffer. */ static const char *gamelog_last; static void GamelogFillCrashLog(const char *s); protected: /** * Writes OS' version to the buffer. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ virtual char *LogOSVersion(char *buffer, const char *last) const = 0; /** * Writes compiler (and its version, if available) to the buffer. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ virtual char *LogCompiler(char *buffer, const char *last) const; /** * Writes actually encountered error to the buffer. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @param message Message passed to use for possible errors. Can be NULL. * @return the position of the \c '\0' character after the buffer. */ virtual char *LogError(char *buffer, const char *last, const char *message) const = 0; /** * Writes the stack trace to the buffer, if there is information about it * available. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ virtual char *LogStacktrace(char *buffer, const char *last) const = 0; /** * Writes information about the data in the registers, if there is * information about it available. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ virtual char *LogRegisters(char *buffer, const char *last) const; /** * Writes the dynamically linked libraries/modules to the buffer, if there * is information about it available. * @param buffer The begin where to write at. * @param last The last position in the buffer to write to. * @return the position of the \c '\0' character after the buffer. */ virtual char *LogModules(char *buffer, const char *last) const; char *LogOpenTTDVersion(char *buffer, const char *last) const; char *LogConfiguration(char *buffer, const char *last) const; char *LogLibraries(char *buffer, const char *last) const; char *LogGamelog(char *buffer, const char *last) const; public: /** Stub destructor to silence some compilers. */ virtual ~CrashLog() {} char *FillCrashLog(char *buffer, const char *last) const; bool WriteCrashLog(const char *buffer, char *filename, const char *filename_last) const; /** * Write the (crash) dump to a file. * @note On success the filename will be filled with the full path of the * crash dump file. Make sure filename is at least \c MAX_PATH big. * @param filename Output for the filename of the written file. * @param filename_last The last position in the filename buffer. * @return if less than 0, error. If 0 no dump is made, otherwise the dump * was successful (not all OSes support dumping files). */ virtual int WriteCrashDump(char *filename, const char *filename_last) const; bool WriteSavegame(char *filename, const char *filename_last) const; bool WriteScreenshot(char *filename, const char *filename_last) const; bool MakeCrashLog() const; /** * Initialiser for crash logs; do the appropriate things so crashes are * handled by our crash handler instead of returning straight to the OS. * @note must be implemented by all implementers of CrashLog. */ static void InitialiseCrashLog(); static void SetErrorMessage(const char *message); static void AfterCrashLogCleanup(); }; #endif /* CRASHLOG_H */ openttd-1.5.3/src/direction_type.h0000644000000000000000000001233112627373441015665 0ustar rootroot/* $Id: direction_type.h 24900 2013-01-08 22:46:42Z planetmaker $ */ /* * 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 direction_type.h Different types to 'show' directions. */ #ifndef DIRECTION_TYPE_H #define DIRECTION_TYPE_H #include "core/enum_type.hpp" /** * Defines the 8 directions on the map. * * This enum defines 8 possible directions which are used for * the vehicles in the game. The directions are aligned straight * to the viewport, not to the map. So north points to the top of * your viewport and not rotated by 45 degrees left or right to get * a "north" used in you games. */ enum Direction { DIR_BEGIN = 0, ///< Used to iterate DIR_N = 0, ///< North DIR_NE = 1, ///< Northeast DIR_E = 2, ///< East DIR_SE = 3, ///< Southeast DIR_S = 4, ///< South DIR_SW = 5, ///< Southwest DIR_W = 6, ///< West DIR_NW = 7, ///< Northwest DIR_END, ///< Used to iterate INVALID_DIR = 0xFF, ///< Flag for an invalid direction }; /** Allow incrementing of Direction variables */ DECLARE_POSTFIX_INCREMENT(Direction) /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT DirectionByte; ///< typedefing-enumification of Direction /** * Enumeration for the difference between two directions. * * This enumeration is used to mark differences between * two directions. If you get one direction you can align * a second direction in 8 different ways. This enumeration * only contains 6 of these 8 differences, but the remaining * two can be calculated by adding to differences together. * This also means you can add two differences together and * get the difference you really want to get. The difference * of 45 degrees left + the difference of 45 degrees right results in the * difference of 0 degrees. * * @note To get this mentioned addition of direction you must use * modulo DIR_END or use the #ChangeDirDiff(DirDiff, DirDiff) function. * @see ChangeDirDiff(DirDiff, DirDiff) */ enum DirDiff { DIRDIFF_SAME = 0, ///< Both directions faces to the same direction DIRDIFF_45RIGHT = 1, ///< Angle of 45 degrees right DIRDIFF_90RIGHT = 2, ///< Angle of 90 degrees right DIRDIFF_REVERSE = 4, ///< One direction is the opposite of the other one DIRDIFF_90LEFT = 6, ///< Angle of 90 degrees left DIRDIFF_45LEFT = 7, ///< Angle of 45 degrees left }; /** * Enumeration for diagonal directions. * * This enumeration is used for the 4 direction of the tile-edges. */ enum DiagDirection { DIAGDIR_BEGIN = 0, ///< Used for iterations DIAGDIR_NE = 0, ///< Northeast, upper right on your monitor DIAGDIR_SE = 1, ///< Southeast DIAGDIR_SW = 2, ///< Southwest DIAGDIR_NW = 3, ///< Northwest DIAGDIR_END, ///< Used for iterations INVALID_DIAGDIR = 0xFF, ///< Flag for an invalid DiagDirection }; /** Allow incrementing of DiagDirection variables */ DECLARE_POSTFIX_INCREMENT(DiagDirection) /** Define basic enum properties */ template <> struct EnumPropsT : MakeEnumPropsT {}; typedef TinyEnumT DiagDirectionByte; ///< typedefing-enumification of DiagDirection /** * Enumeration for the difference between to DiagDirection. * * As the DiagDirection only contains 4 possible directions the * difference between two of these directions can only be in 4 ways. * As the DirDiff enumeration the values can be added together and * you will get the resulting difference (use modulo DIAGDIR_END). * * @see DirDiff */ enum DiagDirDiff { DIAGDIRDIFF_SAME = 0, ///< Same directions DIAGDIRDIFF_90RIGHT = 1, ///< 90 degrees right DIAGDIRDIFF_REVERSE = 2, ///< Reverse directions DIAGDIRDIFF_90LEFT = 3, ///< 90 degrees left }; /** Allow incrementing of DiagDirDiff variables */ DECLARE_POSTFIX_INCREMENT(DiagDirDiff) /** * Enumeration for the two axis X and Y * * This enumeration represents the two axis X and Y in the game. * The X axis is the one which goes align the north-west edge * (and south-east edge). The Y axis must be so the one which goes * align the north-east edge (and south-west) edge. */ enum Axis { AXIS_X = 0, ///< The X axis AXIS_Y = 1, ///< The y axis AXIS_END, ///< Used for iterations INVALID_AXIS = 0xFF, ///< Flag for an invalid Axis }; /** Helper information for extract tool. */ template <> struct EnumPropsT : MakeEnumPropsT {}; #endif /* DIRECTION_TYPE_H */ openttd-1.5.3/src/sdl.cpp0000644000000000000000000000511412627373442013763 0ustar rootroot/* $Id: sdl.cpp 26482 2014-04-23 20:13:33Z rubidium $ */ /* * 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 sdl.cpp Implementation of SDL support. */ #include "stdafx.h" #ifdef WITH_SDL #include "sdl.h" #include /** Number of users of the SDL library. */ static int _sdl_usage; #ifdef DYNAMICALLY_LOADED_SDL #include "os/windows/win32.h" #define M(x) x "\0" static const char sdl_files[] = M("sdl.dll") M("SDL_Init") M("SDL_InitSubSystem") M("SDL_GetError") M("SDL_QuitSubSystem") M("SDL_UpdateRect") M("SDL_UpdateRects") M("SDL_SetColors") M("SDL_WM_SetCaption") M("SDL_ShowCursor") M("SDL_FreeSurface") M("SDL_PollEvent") M("SDL_WarpMouse") M("SDL_GetTicks") M("SDL_OpenAudio") M("SDL_PauseAudio") M("SDL_CloseAudio") M("SDL_LockSurface") M("SDL_UnlockSurface") M("SDL_GetModState") M("SDL_Delay") M("SDL_Quit") M("SDL_SetVideoMode") M("SDL_EnableKeyRepeat") M("SDL_EnableUNICODE") M("SDL_VideoDriverName") M("SDL_ListModes") M("SDL_GetKeyState") M("SDL_LoadBMP_RW") M("SDL_RWFromFile") M("SDL_SetColorKey") M("SDL_WM_SetIcon") M("SDL_MapRGB") M("SDL_VideoModeOK") M("SDL_Linked_Version") M("") ; #undef M SDLProcs sdl_proc; static const char *LoadSdlDLL() { if (sdl_proc.SDL_Init != NULL) { return NULL; } if (!LoadLibraryList((Function *)(void *)&sdl_proc, sdl_files)) { return "Unable to load sdl.dll"; } return NULL; } #endif /* DYNAMICALLY_LOADED_SDL */ #include "safeguards.h" /** * Open the SDL library. * @param x The subsystem to load. */ const char *SdlOpen(uint32 x) { #ifdef DYNAMICALLY_LOADED_SDL { const char *s = LoadSdlDLL(); if (s != NULL) return s; } #endif if (_sdl_usage++ == 0) { if (SDL_CALL SDL_Init(x | SDL_INIT_NOPARACHUTE) == -1) return SDL_CALL SDL_GetError(); } else if (x != 0) { if (SDL_CALL SDL_InitSubSystem(x) == -1) return SDL_CALL SDL_GetError(); } return NULL; } /** * Close the SDL library. * @param x The subsystem to close. */ void SdlClose(uint32 x) { if (x != 0) { SDL_CALL SDL_QuitSubSystem(x); } if (--_sdl_usage == 0) { SDL_CALL SDL_Quit(); } } #endif openttd-1.5.3/src/currency.cpp0000644000000000000000000002005212627373435015033 0ustar rootroot/* $Id: currency.cpp 26989 2014-10-10 23:07:59Z planetmaker $ */ /* * 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 currency.cpp Support for different currencies. */ #include "stdafx.h" #include "core/bitmath_func.hpp" #include "currency.h" #include "news_func.h" #include "settings_type.h" #include "date_func.h" #include "string_type.h" #include "table/strings.h" #include "safeguards.h" /* exchange rate prefix symbol_pos * | separator | postfix | * | | Euro year | | | name * | | | | | | | */ /** The original currency specifications. */ static const CurrencySpec origin_currency_specs[CURRENCY_END] = { { 1, "", CF_NOEURO, "\xC2\xA3", "", 0, STR_GAME_OPTIONS_CURRENCY_GBP }, ///< british pound { 2, "", CF_NOEURO, "$", "", 0, STR_GAME_OPTIONS_CURRENCY_USD }, ///< american dollar { 2, "", CF_ISEURO, "\xE2\x82\xAC", "", 0, STR_GAME_OPTIONS_CURRENCY_EUR }, ///< euro { 220, "", CF_NOEURO, "\xC2\xA5", "", 0, STR_GAME_OPTIONS_CURRENCY_JPY }, ///< japanese yen { 27, "", 2002, "", NBSP "S.", 1, STR_GAME_OPTIONS_CURRENCY_ATS }, ///< austrian schilling { 81, "", 2002, "BEF" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_BEF }, ///< belgian franc { 2, "", CF_NOEURO, "CHF" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_CHF }, ///< swiss franc { 41, "", CF_NOEURO, "", NBSP "K\xC4\x8D", 1, STR_GAME_OPTIONS_CURRENCY_CZK }, ///< czech koruna { 4, "", 2002, "DM" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_DEM }, ///< deutsche mark { 11, "", CF_NOEURO, "", NBSP "kr", 1, STR_GAME_OPTIONS_CURRENCY_DKK }, ///< danish krone { 333, "", 2002, "Pts" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_ESP }, ///< spanish peseta { 12, "", 2002, "", NBSP "mk", 1, STR_GAME_OPTIONS_CURRENCY_FIM }, ///< finnish markka { 13, "", 2002, "FF" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_FRF }, ///< french franc { 681, "", 2002, "", "Dr.", 1, STR_GAME_OPTIONS_CURRENCY_GRD }, ///< greek drachma { 378, "", CF_NOEURO, "", NBSP "Ft", 1, STR_GAME_OPTIONS_CURRENCY_HUF }, ///< hungarian forint { 130, "", CF_NOEURO, "", NBSP "Kr", 1, STR_GAME_OPTIONS_CURRENCY_ISK }, ///< icelandic krona { 3873, "", 2002, "", NBSP "L.", 1, STR_GAME_OPTIONS_CURRENCY_ITL }, ///< italian lira { 4, "", 2002, "NLG" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_NLG }, ///< dutch gulden { 12, "", CF_NOEURO, "", NBSP "Kr", 1, STR_GAME_OPTIONS_CURRENCY_NOK }, ///< norwegian krone { 6, "", CF_NOEURO, "", NBSP "z\xC5\x82", 1, STR_GAME_OPTIONS_CURRENCY_PLN }, ///< polish zloty { 5, "", CF_NOEURO, "", NBSP "Lei", 1, STR_GAME_OPTIONS_CURRENCY_RON }, ///< romanian leu { 50, "", CF_NOEURO, "", NBSP "p", 1, STR_GAME_OPTIONS_CURRENCY_RUR }, ///< russian rouble { 479, "", 2007, "", NBSP "SIT", 1, STR_GAME_OPTIONS_CURRENCY_SIT }, ///< slovenian tolar { 13, "", CF_NOEURO, "", NBSP "Kr", 1, STR_GAME_OPTIONS_CURRENCY_SEK }, ///< swedish krona { 3, "", CF_NOEURO, "", NBSP "TL", 1, STR_GAME_OPTIONS_CURRENCY_TRY }, ///< turkish lira { 60, "", 2009, "", NBSP "Sk", 1, STR_GAME_OPTIONS_CURRENCY_SKK }, ///< slovak koruna { 4, "", CF_NOEURO, "R$" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_BRL }, ///< brazil real { 31, "", 2011, "", NBSP "EEK", 1, STR_GAME_OPTIONS_CURRENCY_EEK }, ///< estonian krooni { 4, "", 2015, "", NBSP "Lt", 1, STR_GAME_OPTIONS_CURRENCY_LTL }, ///< lithuanian litas { 1850, "", CF_NOEURO, "\xE2\x82\xA9", "", 0, STR_GAME_OPTIONS_CURRENCY_KRW }, ///< south korean won { 13, "", CF_NOEURO, "R" NBSP, "", 0, STR_GAME_OPTIONS_CURRENCY_ZAR }, ///< south african rand { 1, "", CF_NOEURO, "", "", 2, STR_GAME_OPTIONS_CURRENCY_CUSTOM }, ///< custom currency (add further languages below) { 3, "", CF_NOEURO, "", NBSP "GEL", 1, STR_GAME_OPTIONS_CURRENCY_GEL }, ///< Georgian Lari { 4901, "", CF_NOEURO, "", NBSP "Rls", 1, STR_GAME_OPTIONS_CURRENCY_IRR }, ///< Iranian Rial }; /** Array of currencies used by the system */ CurrencySpec _currency_specs[CURRENCY_END]; /** * This array represent the position of OpenTTD's currencies, * compared to TTDPatch's ones. * When a grf sends currencies, they are based on the order defined by TTDPatch. * So, we must reindex them to our own order. */ const byte TTDPatch_To_OTTDIndex[] = { CURRENCY_GBP, CURRENCY_USD, CURRENCY_FRF, CURRENCY_DEM, CURRENCY_JPY, CURRENCY_ESP, CURRENCY_HUF, CURRENCY_PLN, CURRENCY_ATS, CURRENCY_BEF, CURRENCY_DKK, CURRENCY_FIM, CURRENCY_GRD, CURRENCY_CHF, CURRENCY_NLG, CURRENCY_ITL, CURRENCY_SEK, CURRENCY_RUR, CURRENCY_EUR, }; /** * Will return the ottd's index correspondence to * the ttdpatch's id. If the id is bigger than the array, * it is a grf written for ottd, thus returning the same id. * Only called from newgrf.cpp * @param grfcurr_id currency id coming from newgrf * @return the corrected index */ byte GetNewgrfCurrencyIdConverted(byte grfcurr_id) { return (grfcurr_id >= lengthof(TTDPatch_To_OTTDIndex)) ? grfcurr_id : TTDPatch_To_OTTDIndex[grfcurr_id]; } /** * get a mask of the allowed currencies depending on the year * @return mask of currencies */ uint64 GetMaskOfAllowedCurrencies() { uint64 mask = 0LL; uint i; for (i = 0; i < CURRENCY_END; i++) { Year to_euro = _currency_specs[i].to_euro; if (to_euro != CF_NOEURO && to_euro != CF_ISEURO && _cur_year >= to_euro) continue; if (to_euro == CF_ISEURO && _cur_year < 2000) continue; SetBit(mask, i); } SetBit(mask, CURRENCY_CUSTOM); // always allow custom currency return mask; } /** * Verify if the currency chosen by the user is about to be converted to Euro */ void CheckSwitchToEuro() { if (_currency_specs[_settings_game.locale.currency].to_euro != CF_NOEURO && _currency_specs[_settings_game.locale.currency].to_euro != CF_ISEURO && _cur_year >= _currency_specs[_settings_game.locale.currency].to_euro) { _settings_game.locale.currency = 2; // this is the index of euro above. AddNewsItem(STR_NEWS_EURO_INTRODUCTION, NT_ECONOMY, NF_NORMAL); } } /** * Will fill _currency_specs array with * default values from origin_currency_specs * Called only from newgrf.cpp and settings.cpp. * @param preserve_custom will not reset custom currency */ void ResetCurrencies(bool preserve_custom) { for (uint i = 0; i < CURRENCY_END; i++) { if (preserve_custom && i == CURRENCY_CUSTOM) continue; _currency_specs[i] = origin_currency_specs[i]; } } /** * Build a list of currency names StringIDs to use in a dropdown list * @return Pointer to a (static) array of StringIDs */ StringID *BuildCurrencyDropdown() { /* Allow room for all currencies, plus a terminator entry */ static StringID names[CURRENCY_END + 1]; uint i; /* Add each name */ for (i = 0; i < CURRENCY_END; i++) { names[i] = _currency_specs[i].name; } /* Terminate the list */ names[i] = INVALID_STRING_ID; return names; } openttd-1.5.3/src/lang/0000755000000000000000000000000012627373445013420 5ustar rootrootopenttd-1.5.3/src/lang/croatian.txt0000644000000000000000000156032312627373443015771 0ustar rootroot##name Croatian ##ownname Hrvatski ##isocode hr_HR ##plural 6 ##textdir ltr ##digitsep . ##digitsepcur . ##decimalsep , ##winlangid 0x041a ##grflangid 0x38 ##gender male female middle ##case nom gen dat aku vok lok ins # $Id: croatian.txt 27353 2015-07-31 17:46:09Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(neodređen znakovni niz) STR_JUST_NOTHING :Ništa # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :Putnici STR_CARGO_PLURAL_PASSENGERS.gen :putnika STR_CARGO_PLURAL_COAL :Ugljen STR_CARGO_PLURAL_COAL.gen :ugljena STR_CARGO_PLURAL_MAIL :Pošta STR_CARGO_PLURAL_MAIL.gen :pošte STR_CARGO_PLURAL_OIL :Nafta STR_CARGO_PLURAL_OIL.gen :nafte STR_CARGO_PLURAL_LIVESTOCK :Domaće životinje STR_CARGO_PLURAL_LIVESTOCK.gen :domaćih životinja STR_CARGO_PLURAL_GOODS :Roba STR_CARGO_PLURAL_GOODS.gen :robe STR_CARGO_PLURAL_GRAIN :Žito STR_CARGO_PLURAL_GRAIN.gen :žita STR_CARGO_PLURAL_WOOD :Drvo STR_CARGO_PLURAL_WOOD.gen :drva STR_CARGO_PLURAL_IRON_ORE :Željezna ruda STR_CARGO_PLURAL_IRON_ORE.gen :željezne rude STR_CARGO_PLURAL_STEEL :Čelik STR_CARGO_PLURAL_STEEL.gen :čelika STR_CARGO_PLURAL_VALUABLES :Dragocjenosti STR_CARGO_PLURAL_VALUABLES.gen :dragocjenosti STR_CARGO_PLURAL_COPPER_ORE :Bakrena ruda STR_CARGO_PLURAL_COPPER_ORE.gen :bakrene rude STR_CARGO_PLURAL_MAIZE :Kukuruz STR_CARGO_PLURAL_MAIZE.gen :kukuruza STR_CARGO_PLURAL_FRUIT :Voće STR_CARGO_PLURAL_FRUIT.gen :voća STR_CARGO_PLURAL_DIAMONDS :Dijamanti STR_CARGO_PLURAL_DIAMONDS.gen :dijamanata STR_CARGO_PLURAL_FOOD :Hrana STR_CARGO_PLURAL_FOOD.gen :hrane STR_CARGO_PLURAL_PAPER :Papir STR_CARGO_PLURAL_PAPER.gen :papira STR_CARGO_PLURAL_GOLD :Zlato STR_CARGO_PLURAL_GOLD.gen :zlata STR_CARGO_PLURAL_WATER :Voda STR_CARGO_PLURAL_WATER.gen :vode STR_CARGO_PLURAL_WHEAT :Pšenica STR_CARGO_PLURAL_WHEAT.gen :pšenice STR_CARGO_PLURAL_RUBBER :Guma STR_CARGO_PLURAL_RUBBER.gen :gume STR_CARGO_PLURAL_SUGAR :Šećer STR_CARGO_PLURAL_SUGAR.gen :šećera STR_CARGO_PLURAL_TOYS :Igračke STR_CARGO_PLURAL_TOYS.gen :igračaka STR_CARGO_PLURAL_CANDY :Slatkiši STR_CARGO_PLURAL_CANDY.gen :slatkiša STR_CARGO_PLURAL_COLA :Cola STR_CARGO_PLURAL_COLA.gen :cole STR_CARGO_PLURAL_COTTON_CANDY :Šećerna vuna STR_CARGO_PLURAL_COTTON_CANDY.gen :šećerne vune STR_CARGO_PLURAL_BUBBLES :Baloni STR_CARGO_PLURAL_BUBBLES.gen :balona STR_CARGO_PLURAL_TOFFEE :Mliječne karamele STR_CARGO_PLURAL_TOFFEE.gen :mliječne karamele STR_CARGO_PLURAL_BATTERIES :Baterije STR_CARGO_PLURAL_BATTERIES.gen :baterija STR_CARGO_PLURAL_PLASTIC :Plastika STR_CARGO_PLURAL_PLASTIC.gen :plastike STR_CARGO_PLURAL_FIZZY_DRINKS :Gazirana pića STR_CARGO_PLURAL_FIZZY_DRINKS.gen :gaziranih pića # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :Putnik STR_CARGO_SINGULAR_PASSENGER.gen :putnika STR_CARGO_SINGULAR_PASSENGER.aku :putnika STR_CARGO_SINGULAR_COAL :Ugljen STR_CARGO_SINGULAR_COAL.gen :ugljena STR_CARGO_SINGULAR_COAL.aku :ugljen STR_CARGO_SINGULAR_MAIL :Pošta STR_CARGO_SINGULAR_MAIL.gen :pošte STR_CARGO_SINGULAR_MAIL.aku :poštu STR_CARGO_SINGULAR_OIL :Nafta STR_CARGO_SINGULAR_OIL.gen :nafte STR_CARGO_SINGULAR_OIL.aku :naftu STR_CARGO_SINGULAR_LIVESTOCK :Domaće životinje STR_CARGO_SINGULAR_LIVESTOCK.gen :domaćih životinja STR_CARGO_SINGULAR_LIVESTOCK.aku :domaće životinje STR_CARGO_SINGULAR_GOODS :Roba STR_CARGO_SINGULAR_GOODS.gen :robe STR_CARGO_SINGULAR_GOODS.aku :robu STR_CARGO_SINGULAR_GRAIN :Žito STR_CARGO_SINGULAR_GRAIN.gen :žita STR_CARGO_SINGULAR_GRAIN.aku :žito STR_CARGO_SINGULAR_WOOD :Drvo STR_CARGO_SINGULAR_WOOD.gen :drva STR_CARGO_SINGULAR_WOOD.aku :drvo STR_CARGO_SINGULAR_IRON_ORE :Željezna ruda STR_CARGO_SINGULAR_IRON_ORE.gen :željezne rude STR_CARGO_SINGULAR_IRON_ORE.aku :željeznu rudu STR_CARGO_SINGULAR_STEEL :Čelik STR_CARGO_SINGULAR_STEEL.gen :čelika STR_CARGO_SINGULAR_STEEL.aku :čelik STR_CARGO_SINGULAR_VALUABLES :Dragocjenosti STR_CARGO_SINGULAR_VALUABLES.gen :dragocjenosti STR_CARGO_SINGULAR_VALUABLES.aku :dragocjenosti STR_CARGO_SINGULAR_COPPER_ORE :Bakrena ruda STR_CARGO_SINGULAR_COPPER_ORE.gen :bakrene rude STR_CARGO_SINGULAR_COPPER_ORE.aku :bakrenu rudu STR_CARGO_SINGULAR_MAIZE :Kukuruz STR_CARGO_SINGULAR_MAIZE.gen :kukuruza STR_CARGO_SINGULAR_MAIZE.aku :kukuruz STR_CARGO_SINGULAR_FRUIT :Voće STR_CARGO_SINGULAR_FRUIT.gen :voća STR_CARGO_SINGULAR_FRUIT.aku :voće STR_CARGO_SINGULAR_DIAMOND :Dijamant STR_CARGO_SINGULAR_DIAMOND.gen :dijamanata STR_CARGO_SINGULAR_DIAMOND.aku :dijamant STR_CARGO_SINGULAR_FOOD :Hrana STR_CARGO_SINGULAR_FOOD.gen :hrane STR_CARGO_SINGULAR_FOOD.aku :hranu STR_CARGO_SINGULAR_PAPER :Papir STR_CARGO_SINGULAR_PAPER.gen :papira STR_CARGO_SINGULAR_PAPER.aku :papir STR_CARGO_SINGULAR_GOLD :Zlato STR_CARGO_SINGULAR_GOLD.gen :zlata STR_CARGO_SINGULAR_GOLD.aku :zlato STR_CARGO_SINGULAR_WATER :Voda STR_CARGO_SINGULAR_WATER.gen :vode STR_CARGO_SINGULAR_WATER.aku :vodu STR_CARGO_SINGULAR_WHEAT :Pšenica STR_CARGO_SINGULAR_WHEAT.gen :pšenice STR_CARGO_SINGULAR_WHEAT.aku :pšenicu STR_CARGO_SINGULAR_RUBBER :Guma STR_CARGO_SINGULAR_RUBBER.gen :gume STR_CARGO_SINGULAR_RUBBER.aku :gumu STR_CARGO_SINGULAR_SUGAR :Šećer STR_CARGO_SINGULAR_SUGAR.gen :šećera STR_CARGO_SINGULAR_SUGAR.aku :šećer STR_CARGO_SINGULAR_TOY :Igračka STR_CARGO_SINGULAR_TOY.gen :igračaka STR_CARGO_SINGULAR_TOY.aku :igračku STR_CARGO_SINGULAR_CANDY :Slatkiš STR_CARGO_SINGULAR_CANDY.gen :slatkiša STR_CARGO_SINGULAR_CANDY.aku :slatkiš STR_CARGO_SINGULAR_COLA :Cola STR_CARGO_SINGULAR_COLA.gen :cole STR_CARGO_SINGULAR_COLA.aku :colu STR_CARGO_SINGULAR_COTTON_CANDY :Šećerna vuna STR_CARGO_SINGULAR_COTTON_CANDY.gen :šećerne vune STR_CARGO_SINGULAR_COTTON_CANDY.aku :šećernu vunu STR_CARGO_SINGULAR_BUBBLE :Balon STR_CARGO_SINGULAR_BUBBLE.gen :balona STR_CARGO_SINGULAR_BUBBLE.aku :balon STR_CARGO_SINGULAR_TOFFEE :Mliječna karamela STR_CARGO_SINGULAR_TOFFEE.gen :mliječne karamele STR_CARGO_SINGULAR_TOFFEE.aku :mliječnu karamelu STR_CARGO_SINGULAR_BATTERY :Baterija STR_CARGO_SINGULAR_BATTERY.gen :baterija STR_CARGO_SINGULAR_BATTERY.aku :bateriju STR_CARGO_SINGULAR_PLASTIC :Plastika STR_CARGO_SINGULAR_PLASTIC.gen :plastike STR_CARGO_SINGULAR_PLASTIC.aku :plastiku STR_CARGO_SINGULAR_FIZZY_DRINK :Gazirano piće STR_CARGO_SINGULAR_FIZZY_DRINK.gen :gaziranog pića STR_CARGO_SINGULAR_FIZZY_DRINK.aku :gazirano piće # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA}{NBSP}putnik{P "" a a} STR_QUANTITY_COAL :{WEIGHT_LONG} ugljena STR_QUANTITY_MAIL :{COMMA}{NBSP}poštansk{P a e ih} vreć{P a e a} STR_QUANTITY_OIL :{VOLUME_LONG} nafte STR_QUANTITY_LIVESTOCK :{COMMA}{NBSP}grl{P o a a} stoke STR_QUANTITY_GOODS :{COMMA}{NBSP}sanduk{P "" a a} robe STR_QUANTITY_GRAIN :{WEIGHT_LONG} žita STR_QUANTITY_WOOD :{WEIGHT_LONG} drveta STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} željezne rude STR_QUANTITY_STEEL :{WEIGHT_LONG} čelika STR_QUANTITY_VALUABLES :{COMMA}{NBSP}vreć{P a e a} s vrijednosnicama STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} bakrene rude STR_QUANTITY_MAIZE :{WEIGHT_LONG} kukuruza STR_QUANTITY_FRUIT :{WEIGHT_LONG} voća STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}vreć{P a e a} dijamanata STR_QUANTITY_FOOD :{WEIGHT_LONG} hrane STR_QUANTITY_PAPER :{WEIGHT_LONG} papira STR_QUANTITY_GOLD :{COMMA}{NBSP}vreć{P a e a} zlata STR_QUANTITY_WATER :{VOLUME_LONG} vode STR_QUANTITY_WHEAT :{WEIGHT_LONG} pšenice STR_QUANTITY_RUBBER :{VOLUME_LONG} gume STR_QUANTITY_SUGAR :{WEIGHT_LONG} šećera STR_QUANTITY_TOYS :{COMMA}{NBSP}igrač{P ka ke aka} STR_QUANTITY_SWEETS :{COMMA}{NBSP}vreć{P a e a} slatkiša STR_QUANTITY_COLA :{VOLUME_LONG} cole STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} šećerne vune STR_QUANTITY_BUBBLES :{COMMA} balon{P "" a a} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} mliječne karamele STR_QUANTITY_BATTERIES :{COMMA} baterij{P a e a} STR_QUANTITY_PLASTIC :{VOLUME_LONG} plastike STR_QUANTITY_FIZZY_DRINKS :{COMMA} gaziran{P o a ih} pić{P e a a} STR_QUANTITY_N_A :N/A # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}PU STR_ABBREV_COAL :{TINY_FONT}UG STR_ABBREV_MAIL :{TINY_FONT}PT STR_ABBREV_OIL :{TINY_FONT}NF STR_ABBREV_LIVESTOCK :{TINY_FONT}DŽ STR_ABBREV_GOODS :{TINY_FONT}RB STR_ABBREV_GRAIN :{TINY_FONT}ŽT STR_ABBREV_WOOD :{TINY_FONT}DV STR_ABBREV_IRON_ORE :{TINY_FONT}FE STR_ABBREV_STEEL :{TINY_FONT}ČL STR_ABBREV_VALUABLES :{TINY_FONT}DC STR_ABBREV_COPPER_ORE :{TINY_FONT}CU STR_ABBREV_MAIZE :{TINY_FONT}KK STR_ABBREV_FRUIT :{TINY_FONT}VĆ STR_ABBREV_DIAMONDS :{TINY_FONT}DM STR_ABBREV_FOOD :{TINY_FONT}HN STR_ABBREV_PAPER :{TINY_FONT}PR STR_ABBREV_GOLD :{TINY_FONT}AU STR_ABBREV_WATER :{TINY_FONT}VO STR_ABBREV_WHEAT :{TINY_FONT}PŠ STR_ABBREV_RUBBER :{TINY_FONT}GM STR_ABBREV_SUGAR :{TINY_FONT}ŠĆ STR_ABBREV_TOYS :{TINY_FONT}IG STR_ABBREV_SWEETS :{TINY_FONT}SL STR_ABBREV_COLA :{TINY_FONT}CL STR_ABBREV_CANDYFLOSS :{TINY_FONT}ŠV STR_ABBREV_BUBBLES :{TINY_FONT}BL STR_ABBREV_TOFFEE :{TINY_FONT}MK STR_ABBREV_BATTERIES :{TINY_FONT}BA STR_ABBREV_PLASTIC :{TINY_FONT}PL STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}GP STR_ABBREV_NONE :{TINY_FONT}NI STR_ABBREV_ALL :{TINY_FONT}SVE # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA}{NBSP}putnik{P "" a ""} STR_PASSENGERS.gen :{COMMA} putnika STR_BAGS :{COMMA}{NBSP}vreć{P a e a} STR_TONS :{COMMA}{NBSP}ton{P a e e} STR_LITERS :{COMMA}{NBSP}lit{P ra re ara} STR_ITEMS :{COMMA}{NBSP}predmet{P "" a a} STR_CRATES :{COMMA}{NBSP}sanduk{P "" a a} # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Tamnoplava STR_COLOUR_PALE_GREEN :Blijedozelena STR_COLOUR_PINK :Ružičasta STR_COLOUR_YELLOW :Žuta STR_COLOUR_RED :Crvena STR_COLOUR_LIGHT_BLUE :Svijetloplava STR_COLOUR_GREEN :Zelena STR_COLOUR_DARK_GREEN :Tamnozelena STR_COLOUR_BLUE :Plava STR_COLOUR_CREAM :Kremasta STR_COLOUR_MAUVE :Svijetloljubičasta STR_COLOUR_PURPLE :Ljubičasta STR_COLOUR_ORANGE :Narančasta STR_COLOUR_BROWN :Smeđa STR_COLOUR_GREY :Siva STR_COLOUR_WHITE :Bijela # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mph STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}KS STR_UNITS_POWER_METRIC :{COMMA}{NBSP}KS STR_UNITS_POWER_SI :{COMMA}{NBSP}kW STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}{NBSP}kg STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA}{NBSP}ton{P a e e} STR_UNITS_WEIGHT_LONG_METRIC :{COMMA}{NBSP}ton{P a e a} STR_UNITS_WEIGHT_LONG_SI :{COMMA}{NBSP}kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}{NBSP}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}{NBSP}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}{NBSP}m³ STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA}{NBSP}galon{P "" a a} STR_UNITS_VOLUME_LONG_METRIC :{COMMA}{NBSP}lit{P ra re ara} STR_UNITS_VOLUME_LONG_SI :{COMMA}{NBSP}m³ STR_UNITS_FORCE_IMPERIAL :{COMMA}{NBSP}lbf STR_UNITS_FORCE_METRIC :{COMMA}{NBSP}kgf STR_UNITS_FORCE_SI :{COMMA}{NBSP}kN STR_UNITS_HEIGHT_IMPERIAL :{COMMA}{NBSP}ft STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Filtriraj niz: STR_LIST_FILTER_OSKTITLE :{BLACK}Unesi znak za filter STR_LIST_FILTER_TOOLTIP :{BLACK}Unesite ključnu riječ kako bi filtrirali popis STR_TOOLTIP_GROUP_ORDER :{BLACK}Odaberi naredbu za grupiranje STR_TOOLTIP_SORT_ORDER :{BLACK}Izaberi način sortiranja (silazno/uzlazno) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Izaberi kriterij za sortiranje STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Odaberi kriterij filtriranja STR_BUTTON_SORT_BY :{BLACK}Sortiraj prema STR_BUTTON_LOCATION :{BLACK}Lokacija STR_BUTTON_RENAME :{BLACK}Preimenuj STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Zatvori prozor STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Naslov prozora - povuci ovo za micanje prozora STR_TOOLTIP_SHADE :{BLACK}Zasjeni prozor - prikaži samo naslovnu traku STR_TOOLTIP_DEBUG :{BLACK}Prikaži NewGRF debug informacije STR_TOOLTIP_DEFSIZE :{BLACK}Promijeni veličinu prozora na osnovnu postavljenu veličinu. Ctrl+Klik za spremanje trenutne veličine kao osnovno postavljene veličine STR_TOOLTIP_STICKY :{BLACK}Označi ovaj prozor nezatvorivim prilikom uporabe tipke 'Zatvori sve prozore'. Ctrl+Klik također sprema trenutni status kao osnovni STR_TOOLTIP_RESIZE :{BLACK}Klikni i povuci za promjenu veličine ovog prozora STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Namjesti veliku/malu veličinu prozora STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Klizna traka - lista gore/dolje STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Klizna traka - lista lijevo/desno STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Sruši građevine itd. na kvadratu zemlje. Ctrl selektira područje dijagonalno. Shift mijenja prikaz građenje/procjena troškova. # Show engines button STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Prikaži sakrivene STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Prikaži sakrivene STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP :{BLACK}Prikaži sakrivene STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT :{BLACK}Prikaži sakrivene STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP :{BLACK}Uključivanjem ove opcije, prikazani su i sakriveni vlakovi STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE_TOOLTIP :{BLACK}Uključivanjem ove opcije, prikazana su i sakrivena cestovna vozila STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP_TOOLTIP :{BLACK}Uključivanjem ove opcije, prikazani su i sakriveni brodovi STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Uključivanjem ove opcije, prikazani su i sakriveni zrakoplovi # Query window STR_BUTTON_DEFAULT :{BLACK}Zadano STR_BUTTON_CANCEL :{BLACK}Odustani STR_BUTTON_OK :{BLACK}OK # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}Dužina: {NUM} STR_MEASURE_AREA :{BLACK}Područje: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Dužina: {NUM}{}Visinska razlika: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Područje: {NUM} x {NUM}{}Visinska razlika: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}Ime STR_SORT_BY_CAPTION_DATE :{BLACK}Datum # These are used in dropdowns STR_SORT_BY_NAME :Ime STR_SORT_BY_PRODUCTION :Proizvodnja STR_SORT_BY_TYPE :Vrsta STR_SORT_BY_TRANSPORTED :Prevezeno STR_SORT_BY_NUMBER :Broj STR_SORT_BY_PROFIT_LAST_YEAR :Dobit prošle godine STR_SORT_BY_PROFIT_THIS_YEAR :Dobit ove godine STR_SORT_BY_AGE :Godine STR_SORT_BY_RELIABILITY :Pouzdanost STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Ukupna nosivost prema vrsti tereta STR_SORT_BY_MAX_SPEED :Maksimalna brzina STR_SORT_BY_MODEL :Model STR_SORT_BY_VALUE :Vrijednost STR_SORT_BY_LENGTH :Dužina STR_SORT_BY_LIFE_TIME :Preostali životni vijek STR_SORT_BY_TIMETABLE_DELAY :Kašnjenje voznog reda STR_SORT_BY_FACILITY :Vrsta postaje STR_SORT_BY_WAITING_TOTAL :Ukupni teret na čekanju STR_SORT_BY_WAITING_AVAILABLE :Dostupni teret na čekanju STR_SORT_BY_RATING_MAX :Najviša ocjena tereta STR_SORT_BY_RATING_MIN :Najniža ocjena tereta STR_SORT_BY_ENGINE_ID :MotorID (standardno sortiranje) STR_SORT_BY_COST :Cijena STR_SORT_BY_POWER :Snaga STR_SORT_BY_TRACTIVE_EFFORT :Vučna sila STR_SORT_BY_INTRO_DATE :Datum uvođenja STR_SORT_BY_RUNNING_COST :Tekući trošak STR_SORT_BY_POWER_VS_RUNNING_COST :Snaga/Tekući trošak STR_SORT_BY_CARGO_CAPACITY :Nosivost tereta STR_SORT_BY_RANGE :Domet STR_SORT_BY_POPULATION :Stanovništvo STR_SORT_BY_RATING :Rejting # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Zaustavi igru STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Premotaj igru naprijed STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Postavke STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Spremi igru, napusti igru, izađi STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Prikaži kartu, dodatni pogled ili popis znakova STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Prikaži popis gradova STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Prikaži subvencije STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Prikaži popis postaja u vlasništvu tvrtke STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Prikaži financijske podatke tvrtke STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Prikaži opće podatke tvrtke STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Prikaži priču STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Prikaži listu ciljeva STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Prikaži grafikone STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Prikaži tablicu lige tvrtki STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Financiraj izgradnju nove industrije STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Prikaži popis vlakova u vlasništvu tvrtke. Ctrl+klik aktivira otvaranje grupe/liste vozila. STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Prikaži popis cestovnih vozila u vlasništvu tvrtke. Ctrl+klik određuje otvaranje grupe/liste vozila. STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Prikaži popis brodova u vlasništvu tvrtke. Ctrl+klik određuje otvaranje grupe/liste vozila. STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Prikaži popis zrakoplova u vlasništvu tvrtke. Ctrl+klik određuje otvaranje grupe/liste vozila. STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Približi pogled STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Udalji pogled STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Izgradi željezničku prugu STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Izgradi ceste STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Izgradi pristaništa za brodove STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Izgradi zračne luke STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Otvori alatnu traku za krajolik kako bi spustio/izdignuo zemlju, posadio drveće, itd. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Pokaži prozor za zvuk/glazbu STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Pokaži zadnju poruku/vijest, pokaži postavke poruka STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Podaci o zemlji, konzola, debug skripte, snimke ekrana, o OpenTTD-u STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Promijeni alatne trake # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Spremi scenarij, učitaj scenarij, napusti uređivanje scenarija, izađi STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Uređivanje scenarija STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Pomakni početni datum 1 godinu unatrag STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Pomakni početni datum 1 godinu unaprijed STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Klikni kako bi upisao početnu godinu STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Prikaži kartu, popis gradova STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Stvaranje krajolika STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Stvaranje gradova STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Stvaranje industrije STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Izgradnja ceste STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Posadi drveće. Shift mijenja prikaz građenje/procjena troškova. STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Postavi znak STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Postavi objekt. Shift mijenja prikaz građenje/procjena troškova. ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Spremi scenarij STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Učitaj scenarij STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Spremi visinsku mapu STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Učitaj visinsku kartu STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Odustani od uređivanja scenarija STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Izlaz ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :Postavke igre STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Postavke STR_SETTINGS_MENU_SCRIPT_SETTINGS :Postavke UI-ja/Skripte igre STR_SETTINGS_MENU_NEWGRF_SETTINGS :Postavke za NewGRF STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Postavke prozirnosti STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Prikaži imena gradova STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Prikaži imena postaja STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Imena čvorišta su prikazana STR_SETTINGS_MENU_SIGNS_DISPLAYED :Prikaži znakove STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Prikazani znakovi i imena od konkurenata STR_SETTINGS_MENU_FULL_ANIMATION :Sve animacije STR_SETTINGS_MENU_FULL_DETAIL :Svi detalji STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Prozirne građevine STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Prozirni znakovi ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Spremi igru STR_FILE_MENU_LOAD_GAME :Učitaj igru STR_FILE_MENU_QUIT_GAME :Napusti igru STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Izlaz ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :Karta svijeta STR_MAP_MENU_EXTRA_VIEW_PORT :Dodatni pogled STR_MAP_MENU_LINGRAPH_LEGEND :Legenda protoka tereta STR_MAP_MENU_SIGN_LIST :Popis znakova ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Popis gradova STR_TOWN_MENU_FOUND_TOWN :Osnuj grad ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :Subvencije ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Grafikon operativne dobiti STR_GRAPH_MENU_INCOME_GRAPH :Grafikon prihoda STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Grafikon isporučenog tereta STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Grafikon učinkovitosti STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Grafikon vrijednosti tvrtke STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Iznosi plaćanja tereta ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Tablica lige tvrtki STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detaljna ocjena učinka STR_GRAPH_MENU_HIGHSCORE :Tablica najboljih rezultata ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Popis industrija STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Industrijski lanci STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Financiraj novu industriju ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Izgradnja željeznice STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Izgradnja elektrificirane željeznice STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Izgradnja jednotračne željeznice STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Izgradnja Magleva ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Izgradnja ceste STR_ROAD_MENU_TRAM_CONSTRUCTION :Izgradnja tramvaja ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Izgradnja plovnih kanala ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Izgradnja zračne luke ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :Uređivanje krajolika STR_LANDSCAPING_MENU_PLANT_TREES :Posadi drveće STR_LANDSCAPING_MENU_PLACE_SIGN :Postavi znak ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :Zvuk/glazba ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Poslijednja poruka/vijest STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Povijest poruka ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Podaci o zemljištu STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :Otvori konzolu STR_ABOUT_MENU_AI_DEBUG :Debugiranje UI-ja/Skripte igre STR_ABOUT_MENU_SCREENSHOT :Slika zaslona STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Zumirano do kraja na slici zaslona STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Standardno zumiranje slike zaslona STR_ABOUT_MENU_GIANT_SCREENSHOT :Slika zaslona cijele mape STR_ABOUT_MENU_ABOUT_OPENTTD :O 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Poravnjanje sprite-a STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Odaberi granične okvire STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Mijenjaj boju blatnih blokova ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :1. STR_ORDINAL_NUMBER_2ND :2. STR_ORDINAL_NUMBER_3RD :3. STR_ORDINAL_NUMBER_4TH :4. STR_ORDINAL_NUMBER_5TH :5. STR_ORDINAL_NUMBER_6TH :6. STR_ORDINAL_NUMBER_7TH :7. STR_ORDINAL_NUMBER_8TH :8. STR_ORDINAL_NUMBER_9TH :9. STR_ORDINAL_NUMBER_10TH :10. STR_ORDINAL_NUMBER_11TH :11. STR_ORDINAL_NUMBER_12TH :12. STR_ORDINAL_NUMBER_13TH :13. STR_ORDINAL_NUMBER_14TH :14. STR_ORDINAL_NUMBER_15TH :15. ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :1. STR_DAY_NUMBER_2ND :2. STR_DAY_NUMBER_3RD :3. STR_DAY_NUMBER_4TH :4. STR_DAY_NUMBER_5TH :5. STR_DAY_NUMBER_6TH :6. STR_DAY_NUMBER_7TH :7. STR_DAY_NUMBER_8TH :8. STR_DAY_NUMBER_9TH :9. STR_DAY_NUMBER_10TH :10. STR_DAY_NUMBER_11TH :11. STR_DAY_NUMBER_12TH :12. STR_DAY_NUMBER_13TH :13. STR_DAY_NUMBER_14TH :14. STR_DAY_NUMBER_15TH :15. STR_DAY_NUMBER_16TH :16. STR_DAY_NUMBER_17TH :17. STR_DAY_NUMBER_18TH :18. STR_DAY_NUMBER_19TH :19. STR_DAY_NUMBER_20TH :20. STR_DAY_NUMBER_21ST :21. STR_DAY_NUMBER_22ND :22. STR_DAY_NUMBER_23RD :23. STR_DAY_NUMBER_24TH :24. STR_DAY_NUMBER_25TH :25. STR_DAY_NUMBER_26TH :26. STR_DAY_NUMBER_27TH :27. STR_DAY_NUMBER_28TH :28. STR_DAY_NUMBER_29TH :29. STR_DAY_NUMBER_30TH :30. STR_DAY_NUMBER_31ST :31. ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :Sij STR_MONTH_ABBREV_FEB :Velj STR_MONTH_ABBREV_MAR :Ožu STR_MONTH_ABBREV_APR :Tra STR_MONTH_ABBREV_MAY :Svi STR_MONTH_ABBREV_JUN :Lip STR_MONTH_ABBREV_JUL :Srp STR_MONTH_ABBREV_AUG :Kol STR_MONTH_ABBREV_SEP :Ruj STR_MONTH_ABBREV_OCT :Lis STR_MONTH_ABBREV_NOV :Stu STR_MONTH_ABBREV_DEC :Pro STR_MONTH_JAN :Siječanj STR_MONTH_FEB :Veljača STR_MONTH_MAR :Ožujak STR_MONTH_APR :Travanj STR_MONTH_MAY :Svibanj STR_MONTH_JUN :Lipanj STR_MONTH_JUL :Srpanj STR_MONTH_AUG :Kolovoz STR_MONTH_SEP :Rujan STR_MONTH_OCT :Listopad STR_MONTH_NOV :Studeni STR_MONTH_DEC :Prosinac ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}Ključ STR_GRAPH_KEY_TOOLTIP :{BLACK}Pokaži ključeve na grafikonima STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Grafikon operativne dobiti STR_GRAPH_INCOME_CAPTION :{WHITE}Grafikon prihoda STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Dostavljenih jedinica tereta STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Ocjena učinka tvrtke (najveća ocjena = 1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Vrijednosti tvrtke STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Isplatne rate tereta STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Dana u tranzitu STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Plaćanje za dostavu 10 jedinica (ili 10.000 litara) tereta za udaljenost od 20 kvadrata STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Uključi sve STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Isključi sve STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Prikaži sve terete na grafikonu cijena prijevoza tereta STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Prikaži bez tereta na grafikonu cijena prijevoza tereta STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Uključi/isključi grafikon za vrstu tereta STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Pokaži detaljne ocjene rezultata # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}Ključ za grafikone tvrtke STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Klikni ovdje za uključivanje/isključivanje tvrtke s grafikona # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Tablica lige tvrtki STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Inženjer STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Prijevozni upravitelj STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Prijevozni koordinator STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Prijevozni nadzornik STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Direktor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Izvršni direktor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Predsjedavajući STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :Predsjednik STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Tajkun # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}Detaljna procjena rezultata STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detalji STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}Pogledaj detalje za ovu tvrtku ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Vozila: STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Postaje: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. dobit: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. prihod: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Maks. prihod: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Dostavljeno: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Teret: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Novac: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Zajam: STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Ukupno: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Broj vozila koja su ostvarila dobit prošle godine. Ovo uključuje cestovna vozila, vlakove, brodove i zrakoplove. STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Broj nedavno servisiranih dijelova postaje. Svaki dio postaje (npr. željeznički kolodvor, autobusna postaja, zračna luka) se računa, čak i ako su spojene kao jedna postaja STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}Dobit vozila s najnižim prihodom (u obzir su uzeta samo vozila starija od dvije godine) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Količina gotovine uprihodovana u mjesecu s najnižom dobiti u zadnjih 12 kvartala STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Količina gotovine uprihodovana u mjesecu s najvišom dobiti u zadnjih 12 kvartala STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Jedinice tereta dostavljene u zadnja četiri kvartala STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Broj vrsta tereta dostavljenih u zadnjem kvartalu STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Količina novca koju ova tvrtka ima u banci STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}Iznos novca koji je ova tvrtka pozajmila STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Ukupni broj bodova od mogućih bodova # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Jazz glazbeni automat STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}Sve STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Staromodno STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}Moderno STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Laganica STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Proizvoljno 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Proizvoljno 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Glasnoća glazbe STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Glasnoća zvukova STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}MIN STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}MAX STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Traka STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Naslov STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Miješaj STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Program STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Skoči na prethodnu traku u izboru STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Skoči na sljedeću traku u izboru STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Zaustavi glazbu STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Pokreni glazbu STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Povuci klizače za namještanje glasnoće glazbe i zvukova STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Odaberi program 'sve trake' STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Odaberi program 'staromodna glazba' STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Odaberi program 'moderna glazba' STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Odaberi glazbeni program 'Ezy Street style' STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Odaberi program 'Proizvoljna glazba 1' STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Odaberi program 'Proizvoljna glazba 2' STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Uključi/isključi miješanje programa STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Pokaži prozor za izbor glazbenih traka STR_ERROR_NO_SONGS :{WHITE}Odabran je set glazbe bez pjesama. Ne će se puštati nikakve pjesme # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Izbor glazbenog programa STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Popis traka STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Program- '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Obriši STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Obriši aktivni program (samo Proizvoljno 1 ili Proizvoljno 2) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Klikni na glazbenu traku za dodavanje u aktivni program (samo Proizvoljno 1 ili Proizvoljno 2) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Klikni na glazbenu traku kako bi ju uklonio iz trenutnog programa (samo Proizvoljno 1 ili Proizvoljno 2) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Najbolje tvrtke koje su dosigle razinu {NUM} STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Tablica tvrtki u {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Privrednik STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Poduzetnik STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industrijalist STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Kapitalist STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Velikaš STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Bogataš STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Tajkun stoljeća STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}Tvrtka {COMPANY} postigla je status '{STRING}' ! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} iz tvrtke {COMPANY} postigao je status '{STRING}'! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}Karta - {STRING} STR_SMALLMAP_TYPE_CONTOURS :Obrisi STR_SMALLMAP_TYPE_VEHICLES :Vozila STR_SMALLMAP_TYPE_INDUSTRIES :Industrije STR_SMALLMAP_TYPE_ROUTEMAP :Protok tereta STR_SMALLMAP_TYPE_ROUTES :Trase STR_SMALLMAP_TYPE_VEGETATION :Vegetacija STR_SMALLMAP_TYPE_OWNERS :Vlasnici STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Pokaži obrise zemlje na karti STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Pokaži vozila na karti STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Pokaži industrije na karti STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Prikaži protok tereta na mapi STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Pokaži prijevozne trase na karti STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Pokaži vegetaciju na karti STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Pokaži vlasnike zemlje na karti STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Klikni na tip industrije za njen prikaz. Ctrl+Klik isključuje sve tipove industrije osim odabrane. Ponovni Ctrl+Klik uključuje sve tipove industrije. STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Klikni na tvrtku za prikaz njenog vlasništva. Ctrl+Klik isključuje sve tvrtke osim odabrane. Ponovni Ctrl+Klik uključuje sve tvrtke. STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Klikni na teret za odabir prikaza njegovih svojstava. Ctrl+Klik isključuje sve terete osim odabranog. Ponovljeni Ctrl+Klik opet uključuje sve terete. STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Ceste STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Željeznice STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Postaje/Zračne luke/Pristaništa STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Građevine/Industrije STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Vozila STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Vlakovi STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Cestovna vozila STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Brodovi STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Zrakoplov STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Prijevozne trase STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Šuma STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Željeznička postaja STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Kamionski terminal STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Autobusna postaja STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Zračna luka/Heliodrom STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Pristanište STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Surova zemlja STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Travnjak STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Ogoljena zemlja STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Polja STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Stabla STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Stijenje STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Voda STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}Bez vlasnika STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Gradovi STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Industrije STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Pustinja STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Snijeg STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Prikaži/sakrij imena gradova na karti STR_SMALLMAP_CENTER :{BLACK}Centriraj malu kartu na trenutni položaj STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}Onemogući sve STR_SMALLMAP_ENABLE_ALL :{BLACK}Omogući sve STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Pokaži visinu STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Ne prikazuj industrije na karti STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Prikaži sve industrije na karti STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Aktiviraj prikaz visinske karte STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Prikaži sve što nije vlasništvo tvrtke na karti STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Prikaži sve vlasništvo tvrtke na karti STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Prikaži bez tereta na mapi STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Prikaži sve terete na mapi # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Pokaži zadnju poruku ili vijest STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * STANKA * * STR_STATUSBAR_AUTOSAVE :{RED}AUTOMATSKO SPREMANJE STR_STATUSBAR_SAVING_GAME :{RED}* * SPREMAM IGRU * * # News message history STR_MESSAGE_HISTORY :{WHITE}Povijest poruka STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}Popis nedavnih novinskih poruka STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING} STR_NEWS_MESSAGE_CAPTION :{WHITE}Poruka STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Građani slave . . .{}Prvi vlak je stigao na postaju {STATION}! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Građani slave . . .{}Prvi autobus je stigao na postaju {STATION}! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Građani slave . . .{}Prvi kamion je stigao na postaju {STATION}! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Građani slave . . .{}Prvi putnički tramvaj je stigao na postaju {STATION}! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Građani slave . . .{}Prvi teretni tramvaj je stigao na postaju {STATION}! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Građani slave . . .{}Prvi brod je stigao na pristanište {STATION}! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Građani slave . . .{}Prvi zrakoplov je stigao u zračnu luku {STATION}! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Vlak se sudario!{}{COMMA} poginu{P o la lih} u eksploziji nakon sudara STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Sudar cestovnog vozila!{}Vozač poginuo u eksploziji nakon sudara s vlakom STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Sudar cestovnog vozila!{}{COMMA} poginu{P o la lih} u eksploziji nakon sudara s vlakom STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Pad zrakoplova!{}{COMMA} poginu{P o la lih} u eksploziji na {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Zrakoplovna nesreća!{}Zrakoplov je ostao bez goriva, {COMMA} poginu{P o la lih} u nesreći STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Cepelin je pao kod {STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Cestovno vozilo uništeno u sudaru s NLO-om! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Eksplozija rafinerije nafte blizu grada {TOWN}a! STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Tvornica uništena pod sumnjivim okolnostima u blizini grada {TOWN}a! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'NLO' sletio blizu grada {TOWN}a! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Urušavanje rudnika ugljena ostavilo je trag blizu grada {TOWN}a! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Poplave!{}Najmanje {COMMA} nesta{P o la lih}, pretpostavlja se poginu{P o la lih} nakon značajnih poplava! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Prijevozna tvrtka u nevoljama! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}Tvrtka {STRING} će biti rasprodana ili objaviti bankrot ukoliko se rezultati uskoro ne poboljšaju! STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Spajanje prijevoznih tvrtki! STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}Tvrtka {STRING} je prodana tvrtki {STRING} za {CURRENCY_LONG}! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrot! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}Tvrtka {STRING} je zatvorena od strane vjerovnika i sva je imovina rasprodana! STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}Osnovana je nova prijevozna tvrtka! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}Tvrtka {STRING} započinje gradnju blizu grada {TOWN}a! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}Tvrtka {STRING} je preuzeta od strane tvrtke {STRING}! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Direktor) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}Tvrtka {STRING} sponzorira izgradnju novoga grada {TOWN}! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}Započela je izgradnja nove {STRING.gen} u blizini grada {TOWN}a! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}Nova {STRING} trenutno se sadi blizu grada {TOWN}a! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING} objavljuje skoro zatvaranje! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Zbog problema u nabavi {STRING} se uskoro zatvara! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Manjak drveća u glavni je razlog što se {STRING} se uskoro zatvara! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}Europska Monetarna Unija!{}{}Euro je predstavljen kao jedinstvena valuta za svakodnevnu uporabu u tvojoj zemlji! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}Svjetska recesija!{}{}Financijski stručnjaci strahuju od najgoreg zbog ekonomske krize! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Recesija završena!{}{}Obrat u trgovanju daje samopouzdanje gospodarstvu jer ekonomija jača! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} povećava proizvodnju! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}{INDUSTRY} očekuje udvostručenje proizvodnje!{}Pronađena je nova pukotina ugljena! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}{INDUSTRY} očekuje udvostručenje proizvodnje!{}Pronađene su nove rezerve nafte! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}{INDUSTRY} poboljšava metode uzgoja, očekuje se udvostručenje proizvodnje! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{1:INDUSTRY} povećava proizvodnju {0:STRING.gen} za {2:COMMA}%! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} smanjuje proizvodnju za 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}{INDUSTRY} pod najezdom kukaca! Havarija!{}Proizvodnja je pala za 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{1:INDUSTRY} smanjuje proizvodnju {0:STRING.gen} za {2:COMMA}%! STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} čeka u spremištu STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} čeka u spremištu STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} čeka u brodogradilištu STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} čeka u zrakoplovnom hangaru # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} ima premalo naredbi u rasporedu STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} ima nevažeće naredbe STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} ima duplicirane naredbe STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} ima neispravnu postaju u svojim naredbama STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY :{WHITE}{VEHICLE} ima u naredbama zračunu luku s prekratkom pistom STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} postaje star STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} postaje vrlo star STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} postaje vrlo star i hitno treba zamjenu STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} ne može naći put za nastavak. STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} je izgubljeno. STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}{VEHICLE} je prošle godine zaradio {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} ne može doći do sljedećeg odredišta jer je izvan dometa STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} je zaustavljen zbog neuspjele naredbe za prenamjenu STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Neuspješno automatsko obnavljanje za {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Novi {STRING} je sada dostupan! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Novi {STRING} je sada dostupan! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} više ne prihvaća {STRING.aku} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} više ne prihvaća {STRING.aku} ili {STRING.aku} STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} od sada prihvaća {STRING.aku} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} od sada prihvaća {STRING.aku} i {STRING.aku} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Istekla je ponuda subvencije:{}{}prijevoz {STRING.gen} od {STRING} do {STRING} više neće biti subvencioniran STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subvencija je povučena:{}{}prijevoz {STRING.gen} od {STRING} do {STRING} više nije subvencioniran STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Ponuđena je subvencija:{}{}Prvi koji preveze {STRING.aku} od {STRING} do {STRING} primat će jednogodišnju subvenciju od lokalne samouprave! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Subvencija je dodijeljena tvrtki {STRING}!{}{}Prijevoz {STRING.gen} od postaje {STRING} do postaje {STRING} plaćat će se 50% više sljedećih godinu dana! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Subvencija je dodijeljena tvrtki {STRING}!{}{}Prijevoz {STRING.gen} od postaje {STRING} do postaje {STRING} plaćat će se dvostruko sljedećih godinu dana! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Subvencija je dodijeljena tvrtki {STRING}!{}{}Prijevoz {STRING.gen} od postaje {STRING} do postaje {STRING} plaćat će se trostruko sljedećih godinu dana! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Subvencija je dodijeljena tvrtki {STRING}!{}{}Prijevoz {STRING.gen} od postaje {STRING} do postaje {STRING} plaćat će se četverostruko sljedećih godinu dana! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Grad {TOWN} zahvatio je prometni kaos!{}{}Program rekonstrukcije cesta koji financira tvrtka {STRING} sljedećih će 6 mjeseci zadavati glavobolje motoriziranima! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Monopol transporta! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}Lokalna vlast {TOWN} potpisuje ugovor sa {STRING} za jednogodišnja ekskluzivna prava transporta! # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Mini pogled {COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Kopiraj u mini pogled STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Kopiraj lokaciju globalnog pogleda u ovaj mini pogled STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Zalijepi iz mini pogleda STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Zalijepi lokaciju ovog mini pogleda u globalni pogled # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Postavke igre STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Novčane jedinice STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Izbor novčanih jedinica ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :Funte (£) STR_GAME_OPTIONS_CURRENCY_USD :Američki Dolar (USD) STR_GAME_OPTIONS_CURRENCY_EUR :Euro (EUR) STR_GAME_OPTIONS_CURRENCY_JPY :Japanski Jen (JPY) STR_GAME_OPTIONS_CURRENCY_ATS :Austrijski šiling (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :Belgijski franak (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :Švicarski franak (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :Češka kruna (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :Njemačka marka (DEM) STR_GAME_OPTIONS_CURRENCY_DKK :Danska kruna (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :Španjolska Pezeta (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :Finska marka (FIM) STR_GAME_OPTIONS_CURRENCY_FRF :Francuski Franak (FRF) STR_GAME_OPTIONS_CURRENCY_GRD :Grčka drahma (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :Mađarski forint (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :Islandska kruna (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :Talijanska lira (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :Nizozemski gulden (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :Norveška kruna (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Poljski Zloti (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Rumunjski lev (RON) STR_GAME_OPTIONS_CURRENCY_RUR :Ruske rublje (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Slovenski tolar (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Švedska kruna (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Turska lira (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :Slovačka kruna (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :Brazilski real (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :estonska kruna (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Litvanski Litas (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :Južnokorejski Won (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :Južnoafrički Rand (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :Proizvoljno... STR_GAME_OPTIONS_CURRENCY_GEL :Gruzijski Lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iranski Rial (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Cestovna vozila STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Odaberi na kojoj će strani ceste vozila prometovati STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Vozi na lijevoj strani STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Vozi na desnoj strani STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Imena gradova STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Odaberi stil za imena gradova ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :Engleski (original) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :Francuski STR_GAME_OPTIONS_TOWN_NAME_GERMAN :Njemački STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :Engleski (dodatno) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latinoamerički STR_GAME_OPTIONS_TOWN_NAME_SILLY :Blesavo STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Švedski STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Nizozemski STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finski STR_GAME_OPTIONS_TOWN_NAME_POLISH :Poljski STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovački STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norveški STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Mađarski STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Austrijski STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Rumunjski STR_GAME_OPTIONS_TOWN_NAME_CZECH :Češki STR_GAME_OPTIONS_TOWN_NAME_SWISS :Švicarski STR_GAME_OPTIONS_TOWN_NAME_DANISH :Danski STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Turski STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Talijanski STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Katalonski ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Automatsko spremanje STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Odaberi interval između automatskih spremanja igre ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Isključeno STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Svaki mjesec STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :Svaka 3 mjeseca STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :Svakih 6 mjeseci STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Svakih 12 mjeseci ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}Jezik STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Izaberi jezično sučelje STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Cijeli ekran STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Označi ovu kućicu kako bi igrao OpenTTD preko cijelog ekrana STR_GAME_OPTIONS_RESOLUTION :{BLACK}Razlučivost ekrana STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Izaberi razlučivost ekrana STR_GAME_OPTIONS_RESOLUTION_OTHER :ostalo STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Veličina sučelja STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Odaberite koju ćete veličinu elementa sučelja koristiti STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normalno STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Dvostruka veličina STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Četvorostruka veličina STR_GAME_OPTIONS_BASE_GRF :{BLACK}Osnovni set grafike STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Odaberi osnovni grafički set za igru STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} datotek{P a e a} nedostaj{P e u e}/korumpiran{P a e o} STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Dodatne informacije o osnovnom grafičkom setu STR_GAME_OPTIONS_BASE_SFX :{BLACK}Set osnovnih zvukova STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Odaberite osnovni set zvukova STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Dodatne informacije o setu osnovnih zvukova STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Set osnovne glazbe STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Odaberi set osnovne glazbe za uporabu STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} neispravn{P a e ih} datotek{P a e a} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Dodatne informacije o setu osnovne glazbe STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Povlačenje liste podržanih rezolucija nije uspjelo STR_ERROR_FULLSCREEN_FAILED :{WHITE}Neuspješan prelazak na prikaz na cijelom ekranu # Custom currency window STR_CURRENCY_WINDOW :{WHITE}Proizvoljna valuta STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Devizni tečaj: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Smanjite iznos vaše valute za jednu funtu (£) STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Povećajte iznos vaše valute za jednu funtu (£) STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Postavite omjer zamjene vaše valute za jednu funtu (£) STR_CURRENCY_SEPARATOR :{LTBLUE}Razdjelnik: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Postavite decimalni simbol vaše valute STR_CURRENCY_PREFIX :{LTBLUE}Prefiks: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Postavite prefiks za vašu valutu STR_CURRENCY_SUFFIX :{LTBLUE}Sufiks: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Postavite sufiks za vašu valutu STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Promijeni na Euro: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Promijeni na Euro: {ORANGE}nikad STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Postavite godinu prebacivanja na Euro STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Prebacite se na Euro ranije STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Prebacite se na Euro kasnije STR_CURRENCY_PREVIEW :{LTBLUE}Prikaz: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 funti (£) u vašoj valuti STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Promijeni parametre proizvoljne valute STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Maksimalan broj natjecatelja: {ORANGE}{COMMA} STR_NONE :Ništa STR_FUNDING_ONLY :Samo financiranje STR_MINIMAL :Minimalno STR_NUM_VERY_LOW :Vrlo nisko STR_NUM_LOW :Nisko STR_NUM_NORMAL :Normalno STR_NUM_HIGH :Visoko STR_NUM_CUSTOM :Proizvoljno STR_NUM_CUSTOM_NUMBER :Proizvoljno ({NUM}) STR_VARIETY_NONE :Ništa STR_VARIETY_VERY_LOW :Vrlo nisko STR_VARIETY_LOW :Nisko STR_VARIETY_MEDIUM :Srednje STR_VARIETY_HIGH :Visoko STR_VARIETY_VERY_HIGH :Vrlo visoko STR_AI_SPEED_VERY_SLOW :Vrlo sporo STR_AI_SPEED_SLOW :Sporo STR_AI_SPEED_MEDIUM :Umjereno STR_AI_SPEED_FAST :Brzo STR_AI_SPEED_VERY_FAST :Vrlo brzo STR_SEA_LEVEL_VERY_LOW :Vrlo nisko STR_SEA_LEVEL_LOW :Nisko STR_SEA_LEVEL_MEDIUM :Umjereno STR_SEA_LEVEL_HIGH :Visoko STR_SEA_LEVEL_CUSTOM :Proizvoljno STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Proizvoljno ({NUM}%) STR_RIVERS_NONE :Ništa STR_RIVERS_FEW :Malo STR_RIVERS_MODERATE :Srednje STR_RIVERS_LOT :Puno STR_DISASTER_NONE :Ništa STR_DISASTER_REDUCED :Smanjeno STR_DISASTER_NORMAL :Normalno STR_SUBSIDY_X1_5 :x1.5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 STR_TERRAIN_TYPE_VERY_FLAT :Vrlo ravno STR_TERRAIN_TYPE_FLAT :Ravno STR_TERRAIN_TYPE_HILLY :Brežuljkasto STR_TERRAIN_TYPE_MOUNTAINOUS :Brdovito STR_TERRAIN_TYPE_ALPINIST :Alpinist STR_CITY_APPROVAL_PERMISSIVE :Dopustiv STR_CITY_APPROVAL_TOLERANT :Tolerantan STR_CITY_APPROVAL_HOSTILE :Agresivan STR_WARNING_NO_SUITABLE_AI :{WHITE}Odgovarajuća UI nije dostupna...{}Možete preuzeti nekoliko UI pomoću sustava 'Online sadržaja' # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Postavke STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtriraj slijed: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Otvori sve STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Zatvori sve STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(nema dostupnog pojašnjenja) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Osnovna vrijednost: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Vrsta postavki: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Postavke klijenta (nisu pohranjene u snimljenoj datoteci; utječu na sve igre) STR_CONFIG_SETTING_TYPE_GAME_MENU :Postavke igre (pohranjene u snimljenoj datoteci; utječu samo na nove igre) STR_CONFIG_SETTING_TYPE_GAME_INGAME :Postavke igre (pohranjene u snimljenoj datoteci; utječu samo na trenutnu igru) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Postavke tvrtke (pohranjene u snimljenoj datoteci; utječu samo na nove igre) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Postavke tvrtke (pohranjene u snimljenoj datoteci; utječu samo na trenutnu tvrtku) STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategorija: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tip: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Sužava doljnju listu koristeći samo predpostavljene filtere STR_CONFIG_SETTING_RESTRICT_BASIC :Osnovno (prikaži samo važne postavke) STR_CONFIG_SETTING_RESTRICT_ADVANCED :Napredno (prikaži većinu postavki) STR_CONFIG_SETTING_RESTRICT_ALL :Stručno (prikaži sve postavke, uključujući i one neobične) STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Postavke sa drugačijim vrijednostima od osnovnih STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Postavke sa drugačijim vrijednostima od postavki vaše nove igre STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Dozvoljava popis samo ispod određene postavke STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :Sve vrste postavki STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Postavke klijenta (nisu spremljene prilikom snimanja; utječu na sve igre) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Postavke igre (spremljene prilikom snimanja; utječu samo na nove igre) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Postavke igre (spremljene prilikom snimanja; utječu samo na tekuću igru) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Postavke tvrtke (spremljene prilikom snimanja; utječu samo na nove igre) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Postavke tvrtke (spremljene prilikom snimanja; utječu samo na trenutnu tvrtku) STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Prikaži sve rezultate pretraga po postavkama{}{SILVER}Kategorija {BLACK}do {WHITE}{STRING} STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Prikaži sve rezultate pretraga po postavkama{}{SILVER}Tip {BLACK}do {WHITE}Svi tipovi postavki STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Prikaži sve rezultate pretrage po postavkama{}{SILVER}Kategorija {BLACK}do {WHITE}{STRING} {BLACK}i {SILVER}Tip {BLACK}do {WHITE}Svi tipovi postavki STR_CONFIG_SETTINGS_NONE :{WHITE}- Nijedna - STR_CONFIG_SETTING_OFF :Isključeno STR_CONFIG_SETTING_ON :Uključeno STR_CONFIG_SETTING_DISABLED :Isključeno STR_CONFIG_SETTING_COMPANIES_OFF :Isključeno STR_CONFIG_SETTING_COMPANIES_OWN :Vlastita tvrtka STR_CONFIG_SETTING_COMPANIES_ALL :Sve tvrtke STR_CONFIG_SETTING_NONE :Nema STR_CONFIG_SETTING_ORIGINAL :Original STR_CONFIG_SETTING_REALISTIC :Realističan STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Lijevo STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Sredina STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Desno STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Najveći početni zajam: {STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Najveći iznos koji tvrtka može pozajmiti (ne uzimajući inflaciju u obzir) STR_CONFIG_SETTING_INTEREST_RATE :Kamatna stopa: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Kamatna stopa zajmova; također kontrolira i inflaciju ako je uključena STR_CONFIG_SETTING_RUNNING_COSTS :Troškovi korištenja: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Postavi razinu troškova održavanja i korištenja za vozila i infrastrukturu STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Brzina gradnje: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limitiraj količinu građevinskih akcija za UI-je STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Kvarovi vozila: {STRING} STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Kontroliraj kako često se mogu pokvariti loše servisirana vozila STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Množitelj za subvencije: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Postavi koliko se plaća za subvencionirane veze STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Građevinski troškovi: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Postavi razinu građevinskih troškova i troškova kupnje STR_CONFIG_SETTING_RECESSIONS :Recesije: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Ukoliko je uključeno, recesija se može pojaviti svakih nekoliko godina. Tijekom recesije sva proizvodnja je značajno manja (vraća se na prethodnu razinu kada recesija završi) STR_CONFIG_SETTING_TRAIN_REVERSING :Zabrani okretanje vlakova na stanicama: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Ukoliko je uključeno, vlakovi se neće okretati na stanicama koje nisu krajnje čak i ukoliko postoji kraći put do njihovog sljedećeg odredišta prilikom okretanja STR_CONFIG_SETTING_DISASTERS :Nesreće: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Uključivanje nesreća koje mogu povremeno blokirati ili uništiti vozila ili infrastrukturu STR_CONFIG_SETTING_CITY_APPROVAL :Stav gradske uprave prema restrukturiranju područja: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Odaberi koliko buka i ekološka šteta utječu na gradsku ocjenu pojedine tvrtke i na daljnja građevinska djelovanja u njihovim područjima STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Maksimalna visina mape: {STRING} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Postavi maksimalnu dozvoljenu visinu planina na mapi STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Ne možete postavini maksimalnu visinu mape na ovu vijednost. Barem jedna planina na mapi je viša. STR_CONFIG_SETTING_AUTOSLOPE :Dopusti modeliranje zemlje ispod građevina, tračnica, itd.: {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Dopusti uređivanje terena ispod građevina i pruga bez njihovog uklanjanja STR_CONFIG_SETTING_CATCHMENT :Dopusti realističnije veličine područja zahvaćanja: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Različiti dohvati za različite vrste stanica i zračnih luka STR_CONFIG_SETTING_EXTRADYNAMITE :Dopusti rušenje više cesta, mostova i tunela u vlasništvu grada: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Jednostavnije uklanjanje infrastrukture i građevina u vlasništvu grada STR_CONFIG_SETTING_TRAIN_LENGTH :Najveća dužina vlakova: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Odaberi najveću duljinu vlakova STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} polje STR_CONFIG_SETTING_SMOKE_AMOUNT :Količina dima/iskri za lokomotive: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Odaberi koliko dima ili iskri će vozila izbacivati STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Model ubrzanja vlaka: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Odaberi fizikalni model ubrzanja vlakova. "Originalni" model penalizira nagibe jednako za sva vozila. "Realistični" model penalizira nagibe i zavoje ovisno o raznim karakteristikama vlaka, kao npr. dužini i vučnoj sili. STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Model ubrzavanja za cestovna vozila: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Odaberi fizikalni model za ubrzanje cestovnih vozila. "Originalni" model penalizira nagibe jednako za sva vozila. "Realistični" model penalizira nagibe ovisno o raznim karakteristikama vozila, npr. vučna sila. STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Strmina nagiba za vlakove: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Kosina nagiba polja za vlak. Više vrijednosti čine nagib težim za penjanje STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Strmina nagiba za cestovna vozila: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Kosina nagiba polja za cestovna vozila. Veće vrijednosti čine nagib težim za penjanje STR_CONFIG_SETTING_FORBID_90_DEG :Zabrani vlakovima i brodovima skretanja pod 90 stupnjeva: {STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Okreti za 90 stupnjeva se događaju kada vodoravni dio pruge odmah nastavlja okomiti dio pruge na sljedećem polju, dakle čineći zaokret vlaka od 90 stupnjeva prelaskom ruba polja umjesto uobičajenih 45 stupnjeva kod drugih kombinacija pruge. Ovo se primjenjuje i na radijus okretanja brodova STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Dopusti spajanje postaja koje nisu izravno jedna do druge {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Dozvoli dodavanje dijelova stanice bez direktog dodira s postojećim dijelovima. Potrebno pritisnuti Ctrl+Klik dok se dodaju novi dijelovi STR_CONFIG_SETTING_INFLATION :Inflacija: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Uključi inflaciju u ekonomiji, gdje troškovi rastu malo brže od plaćanja STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Najveća dužina mostova: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Najveća dužina za izgradnju mostova STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Maksimalna visina mostova: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Maksimalna visina za gradnju mostova STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Najveća dužina tunela: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Najveća dužina za izgradnju tunela STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Ručna metoda izgradnje primarne industrije: {STRING} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Metoda financiranja primarnih industrija. "Ništa" znači da nije moguće financirati nijednu, "istraživanje" znači da je financiranje moguće ali da će se izgraditi na slučajno odabranom mjestu na mapi i da ne mora i uspjeti, "kao i druge industrije" znači da se primarne industrije mogu graditi kao i procesne industrije na bilo kojem mjestu STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :Nijedna STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :Kao i druge industrije STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Istraživanje STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Ravnina oko industija: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Količina ravnog prostora oko industrije. Ovo osigurava da će prazno mjesto ostati oko industrije na raspolaganju za izgradnju pruge itd. STR_CONFIG_SETTING_MULTIPINDTOWN :Dopusti više sličnih industrija po gradu: {STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Normalno, grad ne želi više od jedne industrije svake vrste. S ovom postavkom, to će omogućiti nekoliko industrija iste vrste u istom gradu STR_CONFIG_SETTING_SIGNALSIDE :Prikaži signale: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Odaberi s koje strane pruge će se postavljati signali STR_CONFIG_SETTING_SIGNALSIDE_LEFT :Na lijevoj strani STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :Na strani vožnje STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :Na desnoj strani STR_CONFIG_SETTING_SHOWFINANCES :Pokaži financijski prozor na kraju godine: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Ako je omogućeno, financijski prozor se otvara na kraju svake godine kako bi se omogućio jednostavan uvid u financijsko stanje tvrtke STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Za nove naredbe početna je vrijednost 'neprekidno': {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normalno, vozilo će se zaustaviti na svakoj stanici koju prolazi. Uključivanjem ove postavke, vozilo će se voziti kroz sve stanice na putu do konačnog odredišta ali bez zaustavljanja. Imajte na umu da se ova postavka samo definira zadane vrijednosti za nove naredbe. Bez obzira na to, pojedinačne naredbe mogu se postaviti na bilo koje postavke STR_CONFIG_SETTING_STOP_LOCATION :Naredbe za nove vlakove su zaustavljanje kod {STRING} platforme STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Mjesto gdje će se zaustaviti vlak na peronu po defaultu. 'Bliži kraj' znači blizu ulazne točka, "sredina" znači u sredini platforme, i "dalji kraj" znači daleko od ulaznog mjesta. Imajte na umu da ova postavka samo definira zadane vrijednosti za nove naredbe. Bez obzira na to, pojedinačne naredbe mogu se postaviti na bilo koju postavku STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :početka STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :sredine STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :kraja STR_CONFIG_SETTING_AUTOSCROLL :Pomakni prozor kada je miš na rubu: {STRING} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Kada je uključeno, prikazna polja će se početi pomicati kada se miš nalazi blizu ruba prozora STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Isključeno STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Glavno prikazno polje, samo prikaz na punom ekranu STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Glavno prikazno polje STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Svako prikazno polje STR_CONFIG_SETTING_BRIBE :Dopusti potkupljivanje lokalne samouprave: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Omogućiti tvrtkama pokušavanje podmićivanja lokalne gradske vlasti. Ako mito je primjećeno od strane inspektora, tvrtka neće biti u mogućnosti djelovati u gradu na šest mjeseci STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Dopusti kupovinu ekskluzivnih prijevoznih prava: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Ako tvrtka kupi eksluzivna prava prijevoza za neki grad, protivničke postaje (putničke i teretne) neće dobivati ništa tereta tijekom cijele godine STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Dopusti financiranje zgrada: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Dopusti tvrtkama davanje novca gradovima za financiranje novih kuća STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Dopusti financiranje rekonstrukcije lokalnih cesta: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Dopusti tvrtkama davanje novca gradovima za cestovnu rekonstrukciju radi sabotiranja cestovnog prijevoza u gradu STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Dopusti slanje novca drugim tvrtkama: {STRING} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Dopusti prijenose novca između tvrtki u načinu igre za više igrača STR_CONFIG_SETTING_FREIGHT_TRAINS :Težinski množitelj za teret za simulaciju teških vlakova: {STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Odredi utjecaj prijevoza tereta u vlakovima. Veća vrijednost čini prijevoz tereta zahtjevnijim za vlakove, pogotovo na brdima STR_CONFIG_SETTING_PLANE_SPEED :Faktor brzine zrakoplova: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Postavite relativnu brzinu zrakoplova u odnosu na ostale vrste vozila, kako bi se smanjio iznos prihoda od prijevoza zrakoplovom STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Broj padova zrakoplova: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Odredi šansu za događanje zrakoplovne nesreće STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Ništa STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Smanjeno STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normalno STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Dopusti prolazne postaje na cestama u vlasništvu gradova: {STRING} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Dopusti izgradnju prolaznih postaja na cestama u vlasništvu grada STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Dopusti prolazne postaje na cestama koje su u vlasništvu konkurencije: {STRING} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Dopusti izgradnju prolaznih postaja na cestama u vlasništvu drugih tvrtki STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Mijenjanje ovih postavki nije moguće kada postoje vozila STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Održavanje infrastrukture: {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Kada je omogućeno, infrastruktura uzrokuje troškove održavanja. Cijena raste više nego proporcionalno s veličinom mreže, čime utječe veće tvrtke više od manjih STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Zračne luke nikad ne ističu: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Uključivanjem ove postavke čini svaku vrstu zračne luke dostupnom zauvijek nakon uvođenja STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Upozori ako je vozilo izgubljeno: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Uključi poruke o vozilima koje ne mogu naći put do svog odredišta STR_CONFIG_SETTING_ORDER_REVIEW :Pregledaj naredbe vozila: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Kada je omogućeno, naredbe vozila redovito se provjeravaju, a neki očiti problemi biti će prikazani u poruci novosti kada budu otkriveni STR_CONFIG_SETTING_ORDER_REVIEW_OFF :Ne STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Da ali izdvoji zaustavljena vozila STR_CONFIG_SETTING_ORDER_REVIEW_ON :Od svih vozila STR_CONFIG_SETTING_WARN_INCOME_LESS :Upozori ako prihod vozila postane negativan: {STRING} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :Kada je uključeno, poruka vijesti se prikazuje kada vozilo nije uprihodilo ništa tijekom kalendarske godine STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Vozila ne zastarjevaju: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :Kada je uključeno, svi modeli vozila zauvijek ostaju dostupni nakon njihovog uvođenja STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Automatski obnovi vozilo kada postane staro: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :Kada je uključeno, vozilo kojem se bliži kraj vijeka trajanja se automatski obnavlja ukoliko su uvjeti za obnavljanje ispunjeni STR_CONFIG_SETTING_AUTORENEW_MONTHS :Automatska obnova kada je vozilo {STRING} najveće starosti STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relativna starost kod koje bi trebalo razmotriti automatsko obnavljanje vozila STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} mjeseci prije STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} mjeseci nakon STR_CONFIG_SETTING_AUTORENEW_MONEY :Minimum novca potrebnih za automatsko obnavljanje: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimalni iznos novca koji mora ostati u banci prije razmatranja automatske obnove vozila STR_CONFIG_SETTING_ERRMSG_DURATION :Trajanje poruke s greškom: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Trajanje prikaza poruke s greškom u crvenom prozoru. Uzmite u obzir da se neke (kritične) poruke s greškom ne zatvaraju automatski nakon isteka ovog vremena, nego ih je potrebno zatvoriti ručno STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} sekundi STR_CONFIG_SETTING_HOVER_DELAY :Prikaži pojašnjenja alata: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Odgoda prije prikaza objašnjenja alata kada se miš postavi iznad nekog elementa sučelja. Alternativno, objašnjena alata se mogu vezati uz desnu tipku na mišu kada je ova vrijednost postavljena na 0. STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Lebdi na {COMMA} milisekund{P 0 u i i} STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Desni klik STR_CONFIG_SETTING_POPULATION_IN_LABEL :Pokaži broj stanovnika u oznaci imena grada: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Prikaži populaciju gradova u njihovim oznakama na mapi STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Debljina linija u grafikonima: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Debljina linije u grafikonima. Tanja linija je preciznija za čitanje, deblja linija je lakša za vidjeti i boje su lakše za razabrati STR_CONFIG_SETTING_LANDSCAPE :Teren: {STRING} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Tereni definiraju osnovne scenarije za igru sa različitim teretima i preduvjetima za rast gradova. NewGRF-ovi i Skripte Igre dozvoljavaju detaljnije kontrole i postavke. STR_CONFIG_SETTING_LAND_GENERATOR :Generator zemlje: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :Originalni generator ovisi o baznom grafičkom setu i stvara fiksne oblike u terenu. TerraGenesis je generator baziran na Perlinu sa detaljnijim kontrolama i postavkama. STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Izvorni STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_TERRAIN_TYPE :Vrsta terena: {STRING} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Samo TerraGenesis) Brdovitost terena STR_CONFIG_SETTING_INDUSTRY_DENSITY :Gustoća industrija: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Odredite koliko će industrija biti stvoreno i kolika će količina biti održavana tijekom igre. STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Najveća udaljenost rafinerija nafte od rubova mape: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Rafinerije nafte se grade samo uz rubove mape odnosno na obali za otočne mape STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Visina linije snijega: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Upravljajte na kojoj visini počinje snijeg u subarktičkoj klimi. Snijeg također utječe na stvaranje industrija i preduvjeta za rast gradova. STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Grubost terena: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(Samo TerraGenesis) Odaberite učestalost brda: Blaži tereni imaju rjeđa ali raširenija brda. Teži tereni imaju više brda koja bi mogla izgledati kao da se ponavljaju. STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Vrlo glatko STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Glatko STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Grubo STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Vrlo grubo STR_CONFIG_SETTING_VARIETY :Raspodjela raznolikosti: {STRING} STR_CONFIG_SETTING_VARIETY_HELPTEXT :(Samo TerraGenesis) Upravljajte da li će mapa sadržati i planinska i ravna područja. Pošto ovo samo radi mapu ravnijom, druge postavke bi trebali biti podešene na planinske. STR_CONFIG_SETTING_RIVER_AMOUNT :Količina rijeka: {STRING} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Odaberite koliko rijeka želite stvoriti STR_CONFIG_SETTING_TREE_PLACER :Algoritam za sađenje drveća: {STRING} STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Odaberite raspored drveća na mapi: 'Original' sadi drveće ravnomjerno raspoređeno, 'Napredno' ih sadi u skupinama. STR_CONFIG_SETTING_TREE_PLACER_NONE :Nijedan STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Izvorni STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Unaprijeđen STR_CONFIG_SETTING_ROAD_SIDE :Cestovna vozila: {STRING} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Odaberite stranu vožnje STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Rotacija visinske karte: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Obrnuto od smjera kazaljke na satu STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :U smjeru kazaljke na satu STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :Visinski nivo koji ravna mapa u scenariju dobiva: {STRING} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}Jedno ili više polja na sjevernom rubu nisu prazne STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}Jedno ili više polja na jednom od rubova nije voda STR_CONFIG_SETTING_STATION_SPREAD :Najveći raspon postaje: {STRING} STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Najveća površina na kojoj mogu biti dijelovi jedne stanice. Uzmite u obzir da visoke vrijednosti mogu usporiti igru STR_CONFIG_SETTING_SERVICEATHELIPAD :Automatski servisiraj helikoptere na heliodromima: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Servisiraj helikoptere nakon svakog slijetanja, čak i ako nema spremišta u zračnoj luci STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Poveži alatnu traku za krajolik s alatnim trakama za željeznicu/ceste/vodu/zračne luke: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :Kada se otvara alatna traka za građenje neke vrste transporta, istodobno se otvara i alatna traka za uređivanje terena STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Boja polja korištena na maloj karti: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Boja terena na maloj mapi STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :{G=female}Zelena STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :{G=female}Tamno zelena STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :{G=female}Ljubičasta STR_CONFIG_SETTING_REVERSE_SCROLLING :Promijeni smjer klizanja: {STRING} STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :Ponašanje kod pomicanja mape sa desnom tipkom na mišu. Kada je isključeno, miš pomiče kameru. Kada je uključeno, miš pomiče mapu STR_CONFIG_SETTING_SMOOTH_SCROLLING :Glatko klizanje kroz mini pogled: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Kontroliraj kako se glavni prikaz pomiče na neku lokaciju kada se klikne na malu mapu ili kada se izda naredba za pomicanje na određeni objekt na mapi. Ako je uključeno, prikaz se pomiče glatko, ako je isključeno, prikaz odmah preskoči na ciljnu lokaciju STR_CONFIG_SETTING_MEASURE_TOOLTIP :Pokaži mjerni naputak prilikom korištenja raznih alata za izgradnju: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Prikaži udaljenost u poljima i visinsku razliku kod povlačenja prilikom gradnje STR_CONFIG_SETTING_LIVERIES :Pokaži specifične livreje prema tipu vozila: {STRING} STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Kontroliraj korištenje shema boja tipa vozila za određena vozila (u suprotnosti sa shemama boja tvrtke) STR_CONFIG_SETTING_LIVERIES_NONE :Nijedna STR_CONFIG_SETTING_LIVERIES_OWN :Vlastita tvrtka STR_CONFIG_SETTING_LIVERIES_ALL :Sve tvrtke STR_CONFIG_SETTING_PREFER_TEAMCHAT :Preferiraj ekipni razgovor s :{STRING} STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Prebacivanje vezivanja tvrtkinog internog i javnog razgovora na odnosno STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Funkcija kotačića za klizanje: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Uključi pomicanje sa dvodimenzionalnim kotačićima miša STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Zumiraj kartu STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Kliži kartom STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Isključeno STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Brzina kotačića za klizanje: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Kontroliraj osjetljivost pomicanja kotačićima miša STR_CONFIG_SETTING_OSK_ACTIVATION :Tipkovnica na ekranu: {STRING} STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Odaberi metodu otvaranja tipkovnice na ekranu za unošenje teksta u polja korištenjem samo pokazujući uređaj. Ovo je namijenjeno malim uređajima bez prave tipkovnice STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Isključeno STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Dvostruki klik STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Jedan klik (kada je usredotočen) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Jedan klik (odmah) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Emulacija desnog klika mišem: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Odaberi metodu imitiranja klika na desnu tipku miša STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command+klik STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Control+klik STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Isključeno STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Skrolanje lijevim klikom: {STRING} STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :Uključi pomicanje mape povlačenjem sa lijevom tipkom miša. Ovo je posebno korisno kada se koristi ekran na dodir za pomicanje STR_CONFIG_SETTING_AUTOSAVE :Automatsko snimanje: {STRING} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :Odaberite interval između automatskog snimanja igre STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Koristi {STRING} format datuma za ime snimljene pozicije STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Format datuma u imenima datoteka sa snimljenom igrom STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :dugo (31st Dec 2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :kratko (31-12-2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Automatski pauziraj prilikom pokretanja nove igre: {STRING} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Kada je uključeno, igra će se automatski pauzirati prilikom pokretanja nove igre, dopuštajući bolje proučavanje karte STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Kod pauze dopusti: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Odaberi koje se akcije mogu koristiti dok je igra pauzirana STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :Nijedna akcija STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :Sve ne-konstrukcijske akcije STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :Sve osim akcija za izmjenu krajolika STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :Sve akcije STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Koristi grupe u listi vozila: {STRING} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Uključi korištenje naprednih lista vozila za grupiranje vozila STR_CONFIG_SETTING_LOADING_INDICATORS :Koristi pokazatelje utovara: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Odaberi da li će prikazivači utovara biti prikazani iznad vozila koja se utovaruju ili iznad vozila koja se istovaruju STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Pokaži vozni red u otkucajima rađe nego u danima: {STRING} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Prikaži trajanje putovanja u voznim redovima u otkucajima igre umjesto u danima STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Pokaži dolaske i odlaske u voznim redovima: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Prikaži predviđena vremena dolaska i odlaska u voznim redovima STR_CONFIG_SETTING_QUICKGOTO :Brzo kreiranje naredbi vozila: {STRING} STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Pred-odaberi kursor naredbe "otiđi na" kod otvaranja prozora s naredbama STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Inicijalna vrsta pruge (poslije nove igre/podizanja igre): {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Vrsta željeznice koja će biti odabrana prilikom pokretanja ili učitavanja igre. "Prva dostupna" odabire najstariju vrstu, "zadnja dostupna" odabire najnoviju vrstu, "najčešće korištena" odabire vrstu koja je trenutno najviše u upotrebi STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :Prva dostupna STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Zadnja dostupna STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Najčešće korištena STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Pokaži rezervirane tračnice: {STRING} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Prikaži rezervirane pruge u drugoj boji kako bi se olakšalo rješavanje problema sa vlakovima koji ne žele ući u određenu dionicu puta STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Zadrži alate za izradu aktivnima nakon upotrebe: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Zadrži otvorenim alate za mostove, tunele itd. i nakon upotrebe STR_CONFIG_SETTING_EXPENSES_LAYOUT :Grupiraj rashode u financijskom prozoru tvrtke: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Odredi izgled prozora rashoda tvrtke STR_CONFIG_SETTING_SOUND_TICKER :Skraćene novosti: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Sviraj zvuk kod skraćenih poruka novosti STR_CONFIG_SETTING_SOUND_NEWS :Novine: {STRING} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Sviraj zvuk kod prikaza novina STR_CONFIG_SETTING_SOUND_NEW_YEAR :Kraj godine: {STRING} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Sviraj zvučne efekte na kraju godine sumirajući uspjeh tvrtke tijekom godine uspoređujući ga s prethodnom godinom STR_CONFIG_SETTING_SOUND_CONFIRM :Gradnja: {STRING} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Sviraj zvučne efekte kod uspješne gradnje ili drugih akcija STR_CONFIG_SETTING_SOUND_CLICK :Klik na dugmadi: {STRING} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Bip kod klikanja na dugmad STR_CONFIG_SETTING_SOUND_DISASTER :Katastrofe/nesreće: {STRING} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Sviraj zvučne efekte nesreća i katastrofa STR_CONFIG_SETTING_SOUND_VEHICLE :Vozila: {STRING} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Sviraj zvučne efekte vozila STR_CONFIG_SETTING_SOUND_AMBIENT :Okolina: {STRING} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Sviraj zvučne efekte okoline pejzaža, industrija i gradova STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Isključi gradnju infrastrukture kada odgovarajuća vozila nisu dostupna: {STRING} STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :Kada je uključeno, infrastruktura je dostupna samo ako su dostupna i vozila za nju, sprečavajući trošenje vremena i novca na neupotrebljivu infrastrukturu STR_CONFIG_SETTING_MAX_TRAINS :Maksimalni broj vlakova po tvrtki: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Najveći broj vlakova koje tvrtka može imati STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Maksimalni broj cestovnih vozila po tvrtki: {STRING} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Najveći broj cestovnih vozila koje tvrtka može imati STR_CONFIG_SETTING_MAX_AIRCRAFT :Maksimalni broj zrakoplova po tvrtki: {STRING} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Najveći broj zrakoplova koje tvrtka može imati STR_CONFIG_SETTING_MAX_SHIPS :Maksimalni broj brodova po tvrtki: {STRING} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Najveći broj brodova koje tvrtka može imati STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Isključi vlakove za računalo: {STRING} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Uključivanjem ove postavke, računalo-igrač neće moći koristiti vlakove STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Isključi cestovna vozila za računalo: {STRING} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Uključivanjem ove postavke, računalo-igrač neće moći koristiti cestovna vozila STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Isključi zrakoplove za računalo: {STRING} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Uključivanjem ove postavke, računalo-igrač neće moći koristiti zrakoplove STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Isključi brodove za računalo: {STRING} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Uključivanjem ove postavke, računalo-igrač neće moći koristiti brodove STR_CONFIG_SETTING_AI_PROFILE :Profil osnovnih postavki: {STRING} STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Odaberi koji profil postavki će se koristiti za nasumične UI-je ili za početne vrijednosti kada se dodaje nova UI ili Skripta Igre STR_CONFIG_SETTING_AI_PROFILE_EASY :Lako STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Srednje STR_CONFIG_SETTING_AI_PROFILE_HARD :Teško STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Dopusti UI u mrežnoj igri: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Dopusti UI računalnim-igračima da sudjeluju u igrama za više igrača STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#op-kodova prije suspendiranja skripti: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Najveći broj računalnih koraka koje skripta može poduzeti u jednom krugu STR_CONFIG_SETTING_SERVINT_ISPERCENT :Servisni su intervali u postotcima: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Odaberi da li će se servisiranje vozila pokrenuti nakon isteka vremena od zadnjeg servisa ili padom pouzdanosti za određenu vrijednost od najveće pouzdanosti STR_CONFIG_SETTING_SERVINT_TRAINS :Zadani interval servisiranja za vlakove: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Postavi osnovni interval servisa za nova pružna vozila, ako nije postavljen drugi specifični interval za određeno vozilo STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}dan{P 0 "" a a}/% STR_CONFIG_SETTING_SERVINT_DISABLED :Isključeno STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Zadani interval servisiranja za cestovna vozila: {STRING} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Postavi osnovni interval servisa za nova cestovna vozila, ako nije postavljen drugi specifični interval za određeno vozilo STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Zadani interval servisiranja za zrakoplove: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Postavi osnovni interval servisa za nove zrakoplove, ako nije postavljen drugi specifični interval za određeno vozilo STR_CONFIG_SETTING_SERVINT_SHIPS :Zadani interval servisiranja za brodove: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Postavi osnovni interval servisa za nove brodove, ako nije postavljen drugi specifični interval za određeno vozilo STR_CONFIG_SETTING_NOSERVICE :Isključi servisiranje kada su kvarovi postavljeni na nula: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Kada je uključeno, vozila se ne servisiraju kada se ne mogu pokvariti STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Omogući ograničenje brzine za vagone: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Kada je uključeno, koristiti će se i limit brzine vagona kod određivanja najveće brzine nekog vlaka STR_CONFIG_SETTING_DISABLE_ELRAILS :Onemogući električnu prugu: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Uključivanjem ove postavke, isključuje se potreba elektrificiranja pruge da bi po njoj mogli voziti električni vlakovi STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Dolazak prvog vozila na postaju igrača: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Prikaži novine kada prvo vozilo dođe na stanicu novog igrača STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Dolazak prvog vozila na postaju suparnika: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Prikaži novine kada prvo vozilo dođe na suparnikovu stanicu STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Nesreće / katastrofe: {STRING} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Prikaži novine kod nesreća ili katastrofa STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Podaci vezani za tvrtku: {STRING} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Prikaži novine kada se pojavi nova tvrtka ili kada tvrtke riskiraju bankrot STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Otvaranje industrije: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Prikaži novine kada se nove industrije otvaraju STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Zatvaranje industrije: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Prikaži novine kada se industrije zatvaraju STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Promjene u gospodarstvu: {STRING} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Prikaži novine vezano za globalne promjene u ekonomiji STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Promjene u proizvodnji industrija koje opslužuje tvrtka: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Prikaži novine kod promjene proizvodnih razina industrija koje tvrtka opslužuje STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Promjene u proizvodnji industrija koje opslužuju suparnici: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Prikaži novine kod promjene proizvodnih nivoa industrija koje servisiraju suparnici STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Ostale izmjene u proizvodnji industrija: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Prikaži novine kod promjene proizvodnih razina industrija koje tvrtka ili suparnici ne opslužuju STR_CONFIG_SETTING_NEWS_ADVICE :Savjeti / informacije o vozilima tvrtke: {STRING} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Prikaži poruke o vozilima koje trebaju pozornost STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :Nova vozila: {STRING} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Prikaži novine kada neki novi tip vozila postane dostupan STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Promjene u prihvaćanju tereta: {STRING} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Prikaži poruke o stanicama koje mijenjaju prihvaćanje nekih tereta STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subvencije: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Prikaži novine vezano za događaje o subvencijama STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :Opće informacije: {STRING} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Prikaži novine vezano za opće događaje kao za kupnju ekskluzivnih prava ili financiranje rekonstrukcije cesta STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :Isključeno STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Sažetak STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Sve STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Vijesti u boji pojavljuju se: {STRING} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Godina u kojoj će se novine početi izdavati u boji. Prije ove godine, koriste se crno/bijele novine STR_CONFIG_SETTING_STARTING_YEAR :Početna godina: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Uključi tečnu ekonomiju (više manjih izazova): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Kada je uključeno, promjene u industrijskoj proizvodnji su češće ali u manjim rasponima. Ova postavka obično nema efekta ukoliko su industrije postavljene iz nekog NewGRF-a STR_CONFIG_SETTING_ALLOW_SHARES :Dopusti kupovanje udjela u drugim tvrtkama: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Kada je uključeno, dopušta se kupnja i prodaja dionica tvrtki. Dionice će postati dostupne samo za tvrtke određene starosti STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Postotak profita za dionicu koji se plaća kod sistema feeder-a: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Postotak prihoda koji će biti predan srednjim dionicama prijevoza feeder sustavima, daje više kontrole nad prihodima STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Kod povlačenja, postavi signale svakih: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Postavi razmak između signala koji će se graditi do sljedeće prepreke (signal, raskrižje), ukoliko se signali povlače STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} polje STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Prilikom povlačenja, zadrži odabrani razmak između signala: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Odabire ponašanje kod postavljanja signala putem Ctrl+povlačenja. Ukoliko je isključeno, signali se postavljaju oko tunela i mostova kako bi se izbjegla veća područja bez signala. Ukoliko je uključeno, signali se postavljaju svakih N polja, olakšavajući poravnanje signala kod paralelnih pruga STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Automatski izgradi semafore prije: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Postavi godinu kada će se koristiti električni signali za pruge. Prije ove godine, koristiti će se ne-električni signali (imaju iste funkcije samo izgledaju drugačije) STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Omogući signalni GUI: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Prikaži prozor za odabir tipova signala za gradnju, umjesto samo rotacije tipa signala bez prozora sa Ctrl+klik na sagrađenim signalima STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Predodređeni signal za izgradnju: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Osnovni tip signala za korištenje STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Blokirajući signali STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Putni signali STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :Jednosmjerni putni signali STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Kruži kroz vrste signala: {STRING} STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :Odaberi kroz koje tipove signala se može kružiti, kod Ctrl+klikanja na izgrađeni signal uz pomoć alata za signale STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Samo blokirajući signali STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Samo putni signali STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :Sve STR_CONFIG_SETTING_TOWN_LAYOUT :Dizajn ceste za nove gradove: {STRING} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Izgled cestovne mreže gradova STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Originalno STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Bolje ceste STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 mreža STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 mreža STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Nasumično STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Gradovi mogu graditi ceste: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Dozvoli gradovima građenje cesta za rast i širenje. Isključi za sprečavanje da gradske vlasti same grade ceste STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Gradovi smiju graditi pružne prijelaze: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Uključivanje ove postavke dozvoljava se gradovima da grade cestovno-pružne prijelaze STR_CONFIG_SETTING_NOISE_LEVEL :Omogući određivanje razine buke za zračne luke od strane gradova: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :Kada je ova postavka isključena, mogu postojati dvije zračne luke u svakom gradu. Kada je ova postavka uključena, broj zračnih luka u nekom gradu je ograničen količinom dopuštene buke u gradu, koja ovisi o broju stanovnika i udaljenosti i veličini zračne luke STR_CONFIG_SETTING_TOWN_FOUNDING :Osnivanje gradova tijekom igre: {STRING} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Uklučivanje ove postavke dozvoljava igračima osnivanje novih gradova tijekom igre STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Zabranjeno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Dopušteno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Dopušteno, proizvoljan raspored grada STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Smještaj drveća u igri: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Kontroliraj nasumično pojavljivanje stabala tijekom igre. Ovo može utjecati na industrije koje ovise o rastu stabala, npr. pilane STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :Nigdje {RED}(uništava pilanu) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :Samo u kišnim šumama STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :Posvuda STR_CONFIG_SETTING_TOOLBAR_POS :Položaj glavne alatne trake: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Vodoravna pozicija glavne alatne trake na vrhu ekrana STR_CONFIG_SETTING_STATUSBAR_POS :Pozicija status trake: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Vodoravna pozicija statusne trake na dnu ekrana STR_CONFIG_SETTING_SNAP_RADIUS :Radius zahvata prozora: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Razmak između prozora prije nego se pomicani prozor automatski poravna sa drugima prozorima u blizini STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} piksela STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Isključeno STR_CONFIG_SETTING_SOFT_LIMIT :Najveći broj neljepljivih prozora: {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Broj ne-fiksnih otvorenih prozora prije nego se stariji prozori ne počnu automatski zatvarati da bi napravili mjesta za nove prozore STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :isključeno STR_CONFIG_SETTING_ZOOM_MIN :Najveći nivo zumiranja prema unutra: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Najveći nivo zumiranja prema unutra u prikazima. Uzmite u obzir da uključivanje većih nivoa zumiranja prema unutra povećava i korištenje zahtjeva za memorijom STR_CONFIG_SETTING_ZOOM_MAX :Najveći nivo zumiranja prema van: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :Najveći nivo zumiranja na van za prikaze. Veći nivoi zumiranja na van mogu prouzročiti usporavanje igre kada se koriste STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normalno STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x STR_CONFIG_SETTING_TOWN_GROWTH :Brzina rasta gradova: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Brzina rasta gradova STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Nema STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Sporo STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normalno STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Brzo STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Vrlo brzo STR_CONFIG_SETTING_LARGER_TOWNS :Postotak naselja koji će postati gradovi: {STRING} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Broj naselja koji će postati grad, na taj način naselje koje počinje veći i raste brže STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 od {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :Nijedan STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Početni množitelj veličine grada: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Prosječna veličina gradova u donosu na naselja kod početka igre STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Ažuriraj povezni grafikon svakih {STRING}{NBSP}dan{P 0:2 a a a} STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Vrijeme između slijedećih rekalkulacija poveznog grafikona. Svaka rekalkulacija izračunava planove za jednu komponentu grafikona. To znači da vrijednost X za ovu postavku ne mora značiti i ažuriranje kompletnog grafikona unutar X dana. Samo neke komponente će biti ažurirane. Čim kraće vrijeme odredite, više će biti potrebno resursa CPU-a za izračun. Čim duže vrijeme odredite, trebati će više vremena za pokretanje distribucije po novim rutama. STR_CONFIG_SETTING_LINKGRAPH_TIME :Uzmi {STRING}{NBSP}dan{P 0:2 a a a} za rekalkulaciju poveznog grafikona STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Vrijeme potrebno za rekalkulaciju komponente poveznog grafikona. Kada se rekalkulacija pokrene, stvara se slijed koji može raditi broj dana koliko ovdje odredite. Čim kraće vrijeme odredite, postoji mogućnost da slijed neće biti gotov kada bi trebao. Tada se igra usporava odnosno zaustavlja dok ne bude gotovo. Čim duže vrijeme odredite, potrebno je duže da se distribucija ažurira kad se izmijene rute. STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :ručno STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimetrično STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simetrično STR_CONFIG_SETTING_DISTRIBUTION_PAX :Način distribucije za putnike: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"Simetrično" znači da će se otprilike isti broj putnika slati od stanice A prema stanici B ako od B prema A. "Asimetrično" znači da će se proizvoljni brojevi putnika slati u oba smjera. "Ručno" znači da se distribucija za putnike neće vršiti automatski. STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Način distribucije poštu: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"Simetrično" znači da će se otprilike ista količina pošte slati od stanice A prema stanici B ako od B prema A. "Asimetrično" znači da će se proizvoljne količine pošte slati u oba smjera. "Ručno" znači da se distribucija neće vršiti automatski. STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Način distribucije za OKLOPLJENU klasu tereta: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :OKLOPLJENA klasa tereta sadrži vrijednosnice u umjerenoj klimi, dijamante u subtropskoj klimi ili zlato u subarktičkoj klimi. NewGFR-ovi bi mogli ovo izmijeniti. "Simetrično" znači da će se otprilike ista količina tereta slati od stanice A prema stanici B kao od B prema A. "Asimetrično" znači da će se proizvoljne količine tereta slati u oba smjera. "Ručno" znači da se distribucija tih tereta neće vršiti automatski. Preporučljivo je namjestiti ovu postavku na "asimetrično" ili "ručno" kod subarktičke klime jer banke neće slati zlato natrag prema rudnicima zlata. Za umjerenu i subtropsku klimu možete namjestiti i "simetrično" jer će banke slati neke vrijednosnice natrag prema izvorišnoj banci. STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Način distribucije za ostale klase tereta: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Asimetrično" znači da će se proizvoljna količina tereta slati u bilo kojem smjeru. "Ručno" znači da neće biti nikakve automatske distribucije za te terete. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Točnost distribucije: {STRING} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Čim višu vrijednost odaberete, CPU će trebati više vremena za kalkulaciju poveznog grafikona. Ako bude trebalo predugo, mogli bi primijetiti usporavanje igre. U suprotnom, ako namjestite na manju vrijednost, distribucija će biti netočnija i mogli bi primijetiti da se teret šalje na mjesta koja niste očekivali. STR_CONFIG_SETTING_DEMAND_DISTANCE :Efekt udaljenosti na potražnju: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Ako postavite ovo na vrijednost veću od 0, udaljenost između izvorne stanice A nekog tereta i mogućeg odredišta B će imati efekt na količinu tereta poslanu od A do B. Čim je B dalje od A, manje će tereta biti poslano. Čim veću vrijednost postavite, manje tereta će biti slano na dalje stanice a više tereta na bliže stanice. STR_CONFIG_SETTING_DEMAND_SIZE :Količina povratnog tereta za simetrični način: {STRING} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Postavljajući ovo na manje od 100% daje da se simetrična distribucija ponaša sličnije asimetričnoj distribuciji. Manje tereta će se prisilno vraćati ukoliko je određena količina poslana na stanicu. Ako postavku namjestite na 0%, simetrična distribucija se ponaša točno kao asimetrična distribucija. STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Popunjenost kratkih puteva prije korištenja puteva s visokim kapacitetom: {STRING} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Često postoji više puteva izmeđe dvije stanice. Cargodist će prvo popuniti najkraći put, nakon toga koristiti drugi najkraći put dok se ne popuni itd. Popunjenost se određuje procjenom kapaciteta i planirane uporabe. Jednom kad se popune svi putevi i ako i dalje postoji potreba, pretrpati će sve puteve preferirajući one sa visokim kapacitetom. Ipak, algoritam najčešće neće procijeniti kapacitet točno. Ova postavka vam omogućuje da specificirate do kojeg postotka će kraći put biti popunjavan u prvom prolazu prije nego se počne popunjavati sljedeći put. Namjestite ga na manje od 100% da bi izbjegli prenapučene stanice u slučaju previsoko procijenjenog kapaciteta. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Jedinice brzine: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Uvijek kada je brzina prikazana u korisničkom sučelju, prikaži je u odabranim jedinicama STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperijalni (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metrički (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Jedinice snage vozila: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Uvijek kada je snaga vozila prikazana u korisničkom sučelju, prikaži je u odabranim jedinicama STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperijalni (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metrički (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Jedinice mase: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Uvijek kada je masa prikazana u korisničkom sučelju, prikaži je u odabranim jedinicama STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperijalni (short t/ton) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metrički (t/tonne) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Jedinice volumena: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Uvijek kada je volumen prikazan u korisničkom sučelju, prikaži ga u odabranim jedinicama STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperijalni (gal) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metrički (l) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Jedinice vučne snage: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Uvijek kada je vučna snaga (vučna sila) prikazana u korisničnom sučelju, prikaži je u odabranim jedinicama STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperijalni (lbf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metrički (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Jedinice visine: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Uvijek kada je visina prikazana u korisničkom sučelju, prikaži je u odabranim jedinicama STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperijalni (ft) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metrički (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Lokalizacija STR_CONFIG_SETTING_GRAPHICS :{ORANGE}Grafika STR_CONFIG_SETTING_SOUND :{ORANGE}Zvučni efekti STR_CONFIG_SETTING_INTERFACE :{ORANGE}Sučelje STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE}Opće STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Pogledi STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Izgradnja STR_CONFIG_SETTING_ADVISORS :{ORANGE}Novosti / savjetnici STR_CONFIG_SETTING_COMPANY :{ORANGE}Tvrtka STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Računovodstvo STR_CONFIG_SETTING_VEHICLES :{ORANGE}Vozila STR_CONFIG_SETTING_VEHICLES_PHYSICS :{ORANGE}Fizika STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Rutanje STR_CONFIG_SETTING_LIMITATIONS :{ORANGE}Ograničenja STR_CONFIG_SETTING_ACCIDENTS :{ORANGE}Katastrofe / nesreće STR_CONFIG_SETTING_GENWORLD :{ORANGE}Generacija svijeta STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}Okoliš STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :{ORANGE}Vlasti STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}Gradovi STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Industrije STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Distribucija tereta STR_CONFIG_SETTING_AI :{ORANGE}Suparnici STR_CONFIG_SETTING_AI_NPC :{ORANGE}Računalni igrači STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Preporučljivo) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Pronalaženje putanje za vlakove: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Pronalazač puteva koji će se koristiti za vlakove STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Pronalaženje putanje za cestovna vozila: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Pronalazač puteva koji će se koristiti za cestovna vozila STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Pronalaženje putanje za brodove: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Pronalazač puteva koji će se koristiti za brodove STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Automatsko okretanje na signalima: {STRING} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Dozvoli vlakovima okretanje kod signala ako tamo čekaju duže vrijeme STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Promijeni vrijednost postavke # Config errors STR_CONFIG_ERROR :{WHITE}Greška u konfiguraciji datoteke... STR_CONFIG_ERROR_ARRAY :{WHITE}... greška u nizu '{STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... pogrešna vrijednost '{STRING}' za '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... prateći znakovi na kraju postavki '{STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignoriram NewGRF '{STRING}': duplikat od GRF ID sa '{STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignoriram pogrešni NewGRF '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :nije pronađeno STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :nesigurno za statičku uporabu STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :sistemski NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :nekompatibilno sa ovom verzijom OpenTTD-a STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :nepoznat STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... nivo sažimanja '{STRING}' nije važeći STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... format snimljene igre '{STRING}' nije dostupan. Vraćam u '{STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... zaobilazim Osnovni Grafički set '{STRING}': nije pronađen STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... zaobilazim Osnovni Zvukovni set '{STRING}': nije pronađen STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... zaobilazim Osnovni Muzički set '{STRING}': nije pronađen STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Nedostaje memorije STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Dodjeljivanje {BYTES} predmemorije spriteova nije uspjelo. Predmemorija spriteova je smanjena na {BYTES}. Ovo će smanjiti performanse OpenTTD-a. Za smanjivanje potreba memorije you možete pokušati isključiti 32bpp grafiku i/ili razine zumiranja. # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}Nova igra STR_INTRO_LOAD_GAME :{BLACK}Učitaj igru STR_INTRO_PLAY_SCENARIO :{BLACK}Igraj scenarij STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Igraj visinsku kartu STR_INTRO_SCENARIO_EDITOR :{BLACK}Editor scenarija STR_INTRO_MULTIPLAYER :{BLACK}Više igrača STR_INTRO_GAME_OPTIONS :{BLACK}Postavke igre STR_INTRO_HIGHSCORE :{BLACK}Tablica najboljih rezultata STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Postavke STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Postavke STR_INTRO_ONLINE_CONTENT :{BLACK}Provjeri online sadržaj STR_INTRO_SCRIPT_SETTINGS :{BLACK}Postavke UI-ja/Skripte igre STR_INTRO_QUIT :{BLACK}Izlaz STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Započni novu igru. Ctrl+klik preskače konfiguriranje karte STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Učitaj spremljenu igru STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Pokreni novu igru, koristeći visinsku kartu kao krajolik STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Započni novu igru koristeći proizvoljni scenarij STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Izradi proizvoljni igrački svijet/scenarij STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Pokreni igru sa više igrača STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Odaberi 'blagi' stil krajolika STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Odaberi 'subarktički' stil krajolika STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Odaberi 'subtropski' stil krajolika STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Odaberi 'zemlju igračaka' za stil krajolika STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Prikaži postavke igre STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Prikaži tablicu najboljih rezultata STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Prikaži postavke STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Prikaži postavke NewGRF STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Provjeri novi i nadograđeni sadržaj za preuzimanje STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Prikaži postavke UI-ja/Skripte igre STR_INTRO_TOOLTIP_QUIT :{BLACK}Izzađi it 'OpenTTD'-a STR_INTRO_TRANSLATION :{BLACK}Ovom prijevodu nedostaje {NUM} slijed. Molimo, pomognite učiniti OpenTTD boljim tako da se prijavite kao prevoditelj. Pogledajte readme.txt za detalje. # Quit window STR_QUIT_CAPTION :{WHITE}Izlaz STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Jesi li siguran da želiš napustiti OpenTTD i vratiti se u {STRING}e? STR_QUIT_YES :{BLACK}Da STR_QUIT_NO :{BLACK}Ne # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Napusti igru STR_ABANDON_GAME_QUERY :{YELLOW}Jesi li siguran da želiš napustiti ovu igru? STR_ABANDON_SCENARIO_QUERY :{YELLOW}Jesi li siguran da želiš napustiti ovaj scenarij? # Cheat window STR_CHEATS :{WHITE}Varanje STR_CHEATS_TOOLTIP :{BLACK}Kvačice ukazuju na to jesi li koristio ovo varanje prije STR_CHEATS_WARNING :{BLACK}Upozorenje! Upravo se spremaš izdati svoj kolege natjecatelje. Imaj na umu da se takva sramota pamti zauvijek STR_CHEAT_MONEY :{LTBLUE}Povećaj novce za iznos {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Igraj kao tvrtka: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magični buldožer (uklanja industrije, nepokretne objekte): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tuneli se mogu ukrštavati međusobno: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Veliki avioni se ne će rušiti (često) na malim zračnim lukama: {ORANGE} {STRING} STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Uredi maksimalnu visinu mape: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Uredi maksimalnu visinu planina na mapi STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Blagi krajolik STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Subarktički krajolik STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Suptropski krajolik STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Krajolik 'zemlja igračaka' STR_CHEAT_CHANGE_DATE :{LTBLUE}Promijeni datum: {ORANGE} {DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Promijeni tekuću godinu STR_CHEAT_SETUP_PROD :{LTBLUE}Omogući izmjeni produkcijskih vrijednosti: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}Nova boja STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Pokaži generalne sheme boja STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Pokaži sheme boja za vlak STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Pokaži sheme boja za cestovno vozilo STR_LIVERY_SHIP_TOOLTIP :{BLACK}Pokaži sheme boja za brod STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Pokaži sheme boja za zrakoplov STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Izaberi primarnu boju za odabranu shemu. Ctrl+Klik odabire tu boju za sve sheme. STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Odaberi sekundardnu boju za odabranu shemu. Ctrl+Klik odabire tu boju za sve sheme. STR_LIVERY_PANEL_TOOLTIP :{BLACK}Izaberi shemu boja za promjenu, ili višestruke sheme pomoću Ctrl+klik. Klikni na kućicu kako bi odredio uporabu sheme STR_LIVERY_DEFAULT :Standardna boja STR_LIVERY_STEAM :Parna lokomotiva STR_LIVERY_DIESEL :Dizelska lokomotiva STR_LIVERY_ELECTRIC :Električna lokomotiva STR_LIVERY_MONORAIL :Jednotračna lokomotiva STR_LIVERY_MAGLEV :Lokomotiva Maglev STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Putnička kola (parna) STR_LIVERY_PASSENGER_WAGON_DIESEL :Putnička kola (dizelska) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Putnička kola (električna) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Putnička kola (Monorail) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Putnička kola (Maglev) STR_LIVERY_FREIGHT_WAGON :Teretni vagon STR_LIVERY_BUS :Autobus STR_LIVERY_TRUCK :Kamion STR_LIVERY_PASSENGER_SHIP :Putnički trajekt STR_LIVERY_FREIGHT_SHIP :Teretni brod STR_LIVERY_HELICOPTER :Helikopter STR_LIVERY_SMALL_PLANE :Mali zrakoplov STR_LIVERY_LARGE_PLANE :Veliki zrakoplov STR_LIVERY_PASSENGER_TRAM :Putnički tramvaj STR_LIVERY_FREIGHT_TRAM :Teretni tramvaj # Face selection window STR_FACE_CAPTION :{WHITE}Izbor lica STR_FACE_CANCEL_TOOLTIP :{BLACK}Odustani od izbora novog lica STR_FACE_OK_TOOLTIP :{BLACK}Prihvati izbor novog lica STR_FACE_RANDOM :{BLACK}Nasumično STR_FACE_MALE_BUTTON :{BLACK}Muško STR_FACE_MALE_TOOLTIP :{BLACK}Odaberi muška lica STR_FACE_FEMALE_BUTTON :{BLACK}Žensko STR_FACE_FEMALE_TOOLTIP :{BLACK}Odaberi ženska lica STR_FACE_NEW_FACE_BUTTON :{BLACK}Novo lice STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Generiraj nasumično novo lice STR_FACE_ADVANCED :{BLACK}Napredno STR_FACE_ADVANCED_TOOLTIP :{BLACK}Napredan izbor lica STR_FACE_SIMPLE :{BLACK}Jednostavno STR_FACE_SIMPLE_TOOLTIP :{BLACK}Jednostavan izbor lica STR_FACE_LOAD :{BLACK}Učitaj STR_FACE_LOAD_TOOLTIP :{BLACK}Učitaj omiljeno lice STR_FACE_LOAD_DONE :{WHITE}Tvoje omiljeno lice je učitano iz OpenTTD konfiguracijske datoteke. STR_FACE_FACECODE :{BLACK}Broj igračevog lica STR_FACE_FACECODE_TOOLTIP :{BLACK}Pogledaj i/ili postavi broj lica predsjednika tvrtke STR_FACE_FACECODE_CAPTION :{WHITE}Pogledaj i/ili postavi broj predsjednikovog lica STR_FACE_FACECODE_SET :{WHITE}Novi kod za broj igračevog lica je postavljen STR_FACE_FACECODE_ERR :{WHITE}Nemoguće namjestiti broj predsjednikovog lica - mora biti broj između 0 and 4,294,967,295! STR_FACE_SAVE :{BLACK}Spremi STR_FACE_SAVE_TOOLTIP :{BLACK}Izaberi omiljeno lice STR_FACE_SAVE_DONE :{WHITE}Ovo lice bit će spremljeno kao tvoje omiljeno u OpenTTD konfiguracijsku datoteku. STR_FACE_EUROPEAN :{BLACK}Europljanin STR_FACE_SELECT_EUROPEAN :{BLACK}Izaberi europska lica STR_FACE_AFRICAN :{BLACK}Afrikanac STR_FACE_SELECT_AFRICAN :{BLACK}Izaberi afrička lica STR_FACE_YES :Da STR_FACE_NO :Ne STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Uključi brkove ili naušnicu STR_FACE_HAIR :Kosa: STR_FACE_HAIR_TOOLTIP :{BLACK}Promijeni kosu STR_FACE_EYEBROWS :Obrve: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Promijeni obrve STR_FACE_EYECOLOUR :Boja očiju: STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Promijeni boju očiju STR_FACE_GLASSES :Naočale: STR_FACE_GLASSES_TOOLTIP :{BLACK}Omogući naočale STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Promijeni naočale STR_FACE_NOSE :Nos: STR_FACE_NOSE_TOOLTIP :{BLACK}Promijeni nos STR_FACE_LIPS :Usne: STR_FACE_MOUSTACHE :Brkovi: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Promijeni usne ili brkove STR_FACE_CHIN :Brada: STR_FACE_CHIN_TOOLTIP :{BLACK}Promijeni bradu STR_FACE_JACKET :Jakna STR_FACE_JACKET_TOOLTIP :{BLACK}Promijeni jaknu STR_FACE_COLLAR :Kragna: STR_FACE_COLLAR_TOOLTIP :{BLACK}Promijeni kragnu STR_FACE_TIE :Kravata: STR_FACE_EARRING :Naušnica: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Promijeni kravatu ili naušnicu # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Više igrača STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Sa oglasima STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Odaberi između igre s oglasima (internet) i bez oglasa (Local Area Network, LAN) STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Ne STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Da STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ime igrača: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Ovo je ime po kojem će te drugi igrači raspoznavati STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Ime STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Ime igre STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Klijenti STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Klijenata online / klijenata maks{}Tvrtki online / tvrtki maks. STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Veličina karte STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Veličina karte za igru{}Klikni kako bi sortirao prema području STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Datum STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Trenutni datum STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Godine STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Broj godina{}koliko igra traje STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Jezik, verzija poslužitelja, itd. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Klikni na igru s popisa kako bi ju odabrao STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Poslužitelj kojemu si zadnji put pristupio: STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Klikni kako bi izabrao poslužitelj koji si igrao zadnji put STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}INFO O IGRI STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Klijenti: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Jezik: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Krajolik: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Veličina karte: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Verzija poslužitelja: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Adresa poslužitelja: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Datum početka: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Trenutni datum: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Zaštićeno zaporkom! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}POSLUŽITELJ NEDOSTUPAN STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}POSLUŽITELJ PUN STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}RAZLIKA U VERZIJAMA STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF RAZLIKA STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Pridruži se igri STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Osvježi poslužitelj STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Osvježi podatke o poslužitelju STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Pronađi poslužitelj STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Pronađi poslužitelje u mreži STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Dodaj poslužitelj STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Dodaje poslužitelj na popis koji će uvijek biti provjeren postoje li igre u tijeku. STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Pokreni poslužitelj STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Pokreni vlastiti poslužitelj STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Upiši svoje ime STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Unesi adresu domaćina # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}Započni novu igru za više igrača STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Ime igre: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Ime igre bit će prikazno drugim igračima u izborniku za odabir igre s više igrača STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Postavi zaporku STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Zaštiti svoju igru pomoću zaporke ukoliko ne želiš da bude javno dostupna STR_NETWORK_START_SERVER_UNADVERTISED :Ne STR_NETWORK_START_SERVER_ADVERTISED :Da STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klijen{P t ta ata} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimalni broj klijenata: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Izaberi maksimalan broj klijenata. Ne moraju sva mjesta biti popunjena. STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} tvrtk{P a e i} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Maksimalni broj tvrtki: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Ograniči poslužitelj na određeni broj tvrtki STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} gledatelj{P "" a a} STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Maksimalni broj promatrača: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Ograniči poslužitelj na određeni broj gledatelja STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Jezik kojim se govori: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Drugi igrači znat će kojim se jezikom govori na poslužitelju STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Upišite ime mrežne igre # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :Bilo koji STR_NETWORK_LANG_ENGLISH :Engleski STR_NETWORK_LANG_GERMAN :Njemački STR_NETWORK_LANG_FRENCH :Francuski STR_NETWORK_LANG_BRAZILIAN :Brazilski STR_NETWORK_LANG_BULGARIAN :Bugarski STR_NETWORK_LANG_CHINESE :Kineski STR_NETWORK_LANG_CZECH :Češki STR_NETWORK_LANG_DANISH :Danski STR_NETWORK_LANG_DUTCH :Nizozemski STR_NETWORK_LANG_ESPERANTO :Esperanto STR_NETWORK_LANG_FINNISH :Finski STR_NETWORK_LANG_HUNGARIAN :Mađarski STR_NETWORK_LANG_ICELANDIC :Islandski STR_NETWORK_LANG_ITALIAN :Talijanski STR_NETWORK_LANG_JAPANESE :Japanski STR_NETWORK_LANG_KOREAN :Korejski STR_NETWORK_LANG_LITHUANIAN :Litavski STR_NETWORK_LANG_NORWEGIAN :Norveški STR_NETWORK_LANG_POLISH :Poljski STR_NETWORK_LANG_PORTUGUESE :Portugalski STR_NETWORK_LANG_ROMANIAN :Rumunjski STR_NETWORK_LANG_RUSSIAN :Ruski STR_NETWORK_LANG_SLOVAK :Slovački STR_NETWORK_LANG_SLOVENIAN :Slovenski STR_NETWORK_LANG_SPANISH :Španjolski STR_NETWORK_LANG_SWEDISH :Švedski STR_NETWORK_LANG_TURKISH :Turski STR_NETWORK_LANG_UKRAINIAN :Ukrajinski STR_NETWORK_LANG_AFRIKAANS :afrikaanski STR_NETWORK_LANG_CROATIAN :hrvatski STR_NETWORK_LANG_CATALAN :katalonski STR_NETWORK_LANG_ESTONIAN :estonski STR_NETWORK_LANG_GALICIAN :galicijski STR_NETWORK_LANG_GREEK :Grčki STR_NETWORK_LANG_LATVIAN :Latvijski ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Predvorje igre za više igrača STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Pripremanje za pridruživanje: {ORANGE}{STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}Popis svih tvrtki trenutno u igri. Možete se pridružiti jednoj ili osnovati novu ako postoji slobodno mjesto STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}PODACI O TVRTKI STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Ime tvrtke: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Ustoličenje: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Vrijednost tvrtke: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Trenutno stanje: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Prošlogodišnji prihod: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Učinkovitost: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Vozila: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Postaje: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Igrači: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}Nova tvrtka STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Otvori novu tvrtku STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Gledaj igru STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Promatraj igru kao gledatelj STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Pridruži se tvrtki STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Pomozi upravljati ovom tvrtkom # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}Spajanje... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Spajanje u tijeku... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Provjera ovlaštenja... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Čekanje... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Preuzimanje karte... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Obrada podataka... STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Prijavljivanje... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Dohvaćanje podataka o igri... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Dohvaćanje podataka o tvrtki... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} klijen{P t ta ata} {P je su je} prije Vas STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} preuzeto do sada STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} preuzeto do sada STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Odspoji STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Poslužitelj je zaštićen. Unesite zaporku STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Tvrtka je zaštićena. Unesite zaporku # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Popis klijenata STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Promatraj STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}Nova tvrtka # Network client list STR_NETWORK_CLIENTLIST_KICK :Izbaci STR_NETWORK_CLIENTLIST_BAN :Zabrana STR_NETWORK_CLIENTLIST_GIVE_MONEY :Daj novac STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Razgovaraj sa svima STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Razgovaraj s tvrtkom STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privatna poruka STR_NETWORK_SERVER :Poslužitelj STR_NETWORK_CLIENT :Klijent STR_NETWORK_SPECTATORS :Promatrači STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Unesite iznos novca koji želite dati STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Gledatelj # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Nemoj spremiti upisanu zaporku STR_COMPANY_PASSWORD_OK :{BLACK}Daj tvrtci novu zaporku STR_COMPANY_PASSWORD_CAPTION :{WHITE}Zaporka tvrtke STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Inicijalna zaporka tvrtke STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Uporabi zaporku ove tvrtke kao inicijalnu za nove tvrtke # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}Pridruži se STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Pridruži se i igraj kao ova tvrtka STR_COMPANY_VIEW_PASSWORD :{BLACK}Zaporka STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Zaštiti šifrom svoju tvrtku od korištenja od strane neovlaštenih korisnika. STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Postavi zaporku tvrtke # Network chat STR_NETWORK_CHAT_SEND :{BLACK}Pošalji STR_NETWORK_CHAT_COMPANY_CAPTION :[Ekipa]: STR_NETWORK_CHAT_CLIENT_CAPTION :[Privatno] {STRING}: STR_NETWORK_CHAT_ALL_CAPTION :[Svima] : STR_NETWORK_CHAT_COMPANY :[Ekipa] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_COMPANY :[Ekipa] Za {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_CLIENT :[Privatno] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_CLIENT :[Privatno] Za {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_ALL :[Svima] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}Upišite tekst mrežnog razgovora # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Nisu pronađeni mrežni uređaji ili je kompajlirano bez opcije ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}Niti jedna mrežna igra nije pronađena STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Poslužitelj nije odgovorio na zahtjev STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Spajanje nije moguće zbog razlike u NewGRF datotekama STR_NETWORK_ERROR_DESYNC :{WHITE}Neuspješno usklađivanje s mrežnom igrom STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Izgubljena veza s mrežnom igrom STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Nije moguće učitati snimljenu igru STR_NETWORK_ERROR_SERVER_START :{WHITE}Nije moguće pokrenuti poslužitelj STR_NETWORK_ERROR_CLIENT_START :{WHITE}Nije se moguće spojiti STR_NETWORK_ERROR_TIMEOUT :{WHITE}Veza #{NUM} je istekla STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Primijećena je greška u protokolu te je veza prekinuta STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Revizija ovog klijenta ne odgovara reviziji poslužitelja STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Pogrešna zaporka STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Poslužitelj je pun STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Zabranjen ti je pristup ovom poslužitelju STR_NETWORK_ERROR_KICKED :{WHITE}Izbačen si iz igre STR_NETWORK_ERROR_CHEATER :{WHITE}Na ovome poslužitelju varanje nije dopušteno STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Slali ste previše naredbi na server STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Trebalo vam je previše vremena za unošenje lozinke STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Vaše računalo je presporo za držanje koraka sa serverom STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Vašem računalu je trebalo previše vremena za preuzimanje mape STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Vašem računalu je trebalo previše vremena za pridruživanje na server ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :opća greška STR_NETWORK_ERROR_CLIENT_DESYNC :greška u sinkronizaciji STR_NETWORK_ERROR_CLIENT_SAVEGAME :nije moguće učitati kartu STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :veza je izgubljena STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :greška u protokolu STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF nepodudaranje STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :nije ovlašten STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :primljen je nepoznat ili neočekivani paket STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :pogrešna revizija STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :ime se već koristi STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :pogrešna zaporka STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :krivi id tvrtke u DoCommand STR_NETWORK_ERROR_CLIENT_KICKED :izbačen od strane poslužitelja STR_NETWORK_ERROR_CLIENT_CHEATER :je pokušao varati STR_NETWORK_ERROR_CLIENT_SERVER_FULL :poslužitelj je pun STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :slao je previše naredbi STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :lozinka nije zaprimljena na vrijeme STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :opći istek vremena STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :preuzimanje mape je predugo trajalo STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :procesiranje map je predugo trajalo ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Moguć gubitak veze STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}Zadnjih {NUM} sekundi nisu primljeni podaci sa servera # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Igra zaustavljena ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Igra još uvijek zaustavljena ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Igra još uvijek zaustavljena ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Igra je još uvijek zaustavljena ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Igra je još pauzirana ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Igra se nastavlja ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :nema dovoljno igrača STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :spajanje klijenata STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :ručno STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :skripta igre ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :odlazim STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} se pridružio igri STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :{G=female}*** {STRING} se pridružila igri (Client #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} se pridružio tvrtci #{2:NUM} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} se pridružio promatračima STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} je osnovao novu tvrtku (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} je izašao iz igre ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} je promijenio/la ime u {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} je dao vašoj tvrtki {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Dao si {1:STRING} {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Poslužitelj je zatvorio sesiju STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Poslužitelj se ponovno pokreće...{}Molimo pričekajte... # Content downloading window STR_CONTENT_TITLE :{WHITE}Preuzimanje sadržaja STR_CONTENT_TYPE_CAPTION :{BLACK}Vrsta STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Vrsta sadržaja STR_CONTENT_NAME_CAPTION :{BLACK}Ime STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Ime sadržaja STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Kliknite na liniju kako bi vidjeli detalje{}Kliknite na kućicu kako bi ju označili za preuzimanje STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Izaberi sve STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Označi sav sadržaj za preuzimanje STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Izaberi nadogradnje STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Označi sav sadržaj koji je nadogradnja postojećem sadržaju kako bi ga preuzeo STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Odznači sve STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Označi sav sadržaj koji se ne preuzima STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Pretraži vanjske web stranice STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Traženje sadržaja nije dostupno u OpenTTD-ovom servisu za sadržaje za web stranice koje nisu pridružene OpenTTD-u STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Napuštate OpenTTD! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Pravila i uvjeti za preuzimanje sadržaja sa vanjskih web stranica variraju.{}Morate pogledati vanjske stranice za upute kako instalirati sadržaj u OpenTTD.{}Da li želite nastaviti? STR_CONTENT_FILTER_TITLE :{BLACK}Ime/Tag filter: STR_CONTENT_OPEN_URL :{BLACK}Posjetite web-stranicu STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Posjetite web-stranicu za ovaj sadržaj STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Preuzmi STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Počni preuzimanje označenog sadržaja STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Ukupna veličina preuzimanja: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}INFORMACIJA O SADRŽAJU STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Niste odabrali ovo za preuzimanje STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Odabrao si ovo za preuzimanje STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Ovaj sadržaj ovisi o prethodnim sadržajima i odabran je za preuzimanje STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Već imate ovo STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}Ovaj sadržaj je nepoznat i nije ga moguće preuzeti u OpenTTD STR_CONTENT_DETAIL_UPDATE :{SILVER}Ovo je zamjena za postojeći {STRING} STR_CONTENT_DETAIL_NAME :{SILVER}Ime: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Verzija: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Opis: {WHITE}{STRING} STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}Tip: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}Veličina preuzimanja: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Označeno zbog: {WHITE}{STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Ovisi o: {WHITE}{STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Tagovi: {WHITE}{STRING} STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD je napravljen bez podrške za "zlib"... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... preuzimanje sadržaja nije moguće! # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :Osnovna grafika STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :UI STR_CONTENT_TYPE_AI_LIBRARY :Zbirka UI STR_CONTENT_TYPE_SCENARIO :Scenarij STR_CONTENT_TYPE_HEIGHTMAP :Visinska mapa STR_CONTENT_TYPE_BASE_SOUNDS :Osnovni zvukovi STR_CONTENT_TYPE_BASE_MUSIC :Osnovna glazba STR_CONTENT_TYPE_GAME_SCRIPT :Skripta igre STR_CONTENT_TYPE_GS_LIBRARY :GS knjižnica # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Preuzimanje sadržaja STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Zahtjevanje datoteka STR_CONTENT_DOWNLOAD_FILE :{WHITE}Trenutno preuzimam {STRING} ({NUM} of {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Preuzimanje završeno STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} od {BYTES} preuzeto ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Nisam se mogao spojiti na poslužitelj sadržaja STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Preuzimanje nije uspjelo... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... veza izgubljena STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... datoteku nije moguće zapisati STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Nije moguća dekompresija preuzete datoteke STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Nedostaje grafika STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD treba grafiku za funkcioniranje ali nijedna nije pronađena. Da li dozvoljavate da OpenTTD preuzme i instalira potrebne grafike? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Da, preuzmi grafike STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Ne, izađi iz OpenTTD-a # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Postavke prozirnosti STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Namjesti prozirnost za znakove. Ctrl+klik za zaključavanje STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Namjesti prozirnost za drveće. Ctrl+klik za zaključavanje STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Namjesti prozirnost za kuće. Ctrl+klik za zaključavanje STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Namjesti prozirnost za industrije. Ctrl+klik za zaključavanje STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Namjesti prozirnost za građevine poput postaja, spremiša i čvorišta. Ctrl+klik za zaključavanje STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Namjesti prozirnost za mostove. Ctrl+klik za zaključavanje STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Namjesti prozirnost za strukture poput svjetionika i antena. Ctrl+klik za zaključavanje. STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Aktiviraj prozirnost za viseće žice. Ctrl+klik za zaključavanje STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Namjesti prozirnost za indikatore učitavanja. Ctrl+klik za zaključavanje STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Učini objekte nevidljivima umjesto prozirnima # Linkgraph legend window STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Legenda protoka tereta STR_LINKGRAPH_LEGEND_ALL :{BLACK}Sve STR_LINKGRAPH_LEGEND_NONE :{BLACK}Ništa STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Odaberi tvrtke koje će se prikazati # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}nekorišten STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}zasićen STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}prekrcan # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Označavanje područja pokrivanja STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Isključeno STR_STATION_BUILD_COVERAGE_ON :{BLACK}Uključeno STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Nemoj označiti područje koje pokriva željeno mjesto STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Označi područje koje pokriva željeno mjesto STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Prihvaća: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Zalihe: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Spoji postaju STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Izgradi odvojenu postaju STR_JOIN_WAYPOINT_CAPTION :{WHITE}Spoji čvorište STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Izgradi zasebno čvorište # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Izgradnja željeznice STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Izgradnja elektrificirane željeznice STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Izgradnja jednotračne željeznice STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Izgradnja Magleva STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Izgradi željezničku prugu. Ctrl aktivira izgradnju/uklanjanje prilikom gradnje željeznice. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Izgradi željezničku prugu koristeći Autorail način. Ctrl aktivira izgradnju/uklanjanje prilikom gradnje željeznice. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Izgradi spremište vlakova (za kupnju i servisiranje vlakova). Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Pretvori prugu u čvorište. Ctrl omogućava spajanje čvorišta. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Izgradi željezničku postaju. Ctrl omogućava spajanje postaja. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Izgradi željezničke signale. Ctrl aktivira semafore/svjetlosne signale{}Povlačenjem će se izgraditi signali uzduž ravnog dijela pruge. Ctrl će izgraditi signale do sljedećeg križanja ili signala.{}Ctrl+klik aktivira otvaranje prozora za odabir signala. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Izgradi željeznički most. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Izgradi željeznički tunel. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Aktiviraj izgradnju/uklanjanje željezničke pruge, signala, čvorišta i postaja. Držanjem tipke Ctrl također se uklanjaju tračnice na čvorištima i postajama. STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Pretvori/nadogradi vrstu pruge. Shift mijenja prikaz građenje/procjena troškova. STR_RAIL_NAME_RAILROAD :Pruga STR_RAIL_NAME_ELRAIL :Elektrificirana pruga STR_RAIL_NAME_MONORAIL :Pruga s jednim kolosijekom STR_RAIL_NAME_MAGLEV :Maglev # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Smjer spremišta vlakova STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Odaberi smjer željezničkog spremišta # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Čvorište STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Odaberi vrstu čvorišta # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Izbor željezničke postaje STR_STATION_BUILD_ORIENTATION :{BLACK}Smjer STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Odaberi smjer željezničke postaje STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Broj tračnica STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Odaberi broj perona na željezničkoj postaji STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Dužina platforme STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Odaberi dužinu željezničke postaje STR_STATION_BUILD_DRAG_DROP :{BLACK}Povuci i spusti STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Napravi postaju koristeći drag & drop STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Odaberi vrstu postaje za prikazivanje STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Odaberi vrstu postaje za izgradnju STR_STATION_CLASS_DFLT :Zadana postaja STR_STATION_CLASS_WAYP :Čvorišta # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Izbornik signala STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Standardni signal (semafor){}Ovo je najosnovnija vrsta signala, dozvoljava istovremeno samo jedan vlak u bloku STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Ulazni signal (semafor){}Zeleno sve dok je jedan ili više zelenih izlaznih signala na sljedećem dijelu pruge. U protivnom pokazuje crveno STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Izlazni signal (semafor){}Ponaša se na isti način kao i normalni signali, ali je nužno pogoditi točnu boju na ulaznim i kombo pred-signalima STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Kombo signal (semafor){}Kombo signal jednostavno radi kao ulazni i izlazni signal. Ovo omogućava izgradnju velike "mreže" pred-signala. STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Putni signal (semafor){}Putni signal omogućava da više od jednog vlaka uđe istovremeno u signalni blok, ako vlak može rezervirati putanju do sigurnog zaustavnog mjesta. Standardne putne signale moguće je proći iz suprotnog smjera. STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}Jednosmjerni putni signal (semafor){}Putni signal omogućava da više od jednog vlaka uđe istovremeno u signalni blok, ako vlak može rezervirati putanju do sigurnog zaustavnog mjesta. Jednosmjerne putne signale nije moguće proći iz suprotnog smjera STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Standardni signal (električni){}Ovo je najosnovnija vrsta signala, dozvoljava istovremeno samo jedan vlak u bloku STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Ulazni signal (električni){}Zeleno sve dok je jedan ili više zelenih izlaznih signala na sljedećem dijelu pruge. U protivnom pokazuje crveno STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Izlazni signal (električni){}Ponaša se na isti način kao i normalni signali, ali je nužno pogoditi točnu boju na ulaznim i kombo pred-signalima. STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Kombo signal (električni){}Kombo signal jednostavno radi kao ulazni i izlazni signal. Ovo omogućava izgradnju velike "mreže" pred-signala. STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Putni signal (električni){}Putni signal omogućava da više od jednog vlaka uđe istovremeno u signalni blok, ako vlak može rezervirati putanju do sigurnog zaustavnog mjesta. Standardne putne signale moguće je proći iz suprotnog smjera STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Jednosmjerni putni signal (električni){}Putni znak omogućava da više od jednog vlaka uđe istovremeno u signalni blok, ako vlak može rezervirati putanju do sigurnog zaustavnog mjesta. Jednosmjerne putne signale nije moguće proći iz suprotnog smjera. STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Pretvaranje signala{}Kada je odabrano, klikanjem na postojeći signal pretvara taj signal u odabranu vrstu i varijantu, Ctrl+Klik mijenja postojeću varijantu. Shift+Klik prikazuje procjenu troška pretvorbe STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Gustoća signala prilikom izgradnje STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Smanji gustoću signala prilikom izgradnje STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Povećaj gustoću signala prilikom izgradnje # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Odaberi željeznički most STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Odaberi cestovni most STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Izbor mosta - klikni na most koji želiš izgraditi STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :Viseći, čelični STR_BRIDGE_NAME_GIRDER_STEEL :Noseći, čelični STR_BRIDGE_NAME_CANTILEVER_STEEL :Konzolni, čelični STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Viseći, betonski STR_BRIDGE_NAME_WOODEN :Drveni STR_BRIDGE_NAME_CONCRETE :Betonski STR_BRIDGE_NAME_TUBULAR_STEEL :Cijevni, čelični STR_BRIDGE_TUBULAR_SILICON :Cjevni, silikonski # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Izgradnja ceste STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Izgradnja tramvaja STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Izgradi dio ceste. Ctrl aktivira izgradnju/uklanjanje prilikom gradnje ceste. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Izgradi tramvajski dio. Ctrl aktivira izgradnju/uklanjanje prilikom gradnje tramvajske pruge. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Izgradi cestu koristeći Autoroad način gradnje. Ctrl aktivira izgradnju/uklanjanje prilikom gradnje ceste. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Izgradi tramvajsku prugu koristeći Autotram način gradnje. Ctrl aktivira izgradnju/uklanjanje prilikom gradnje tramvajske pruge. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Izgradi spremište cestovnih vozila (za kupnju i servisiranje vozila). Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Izgradi spremište tramvajskih vozila (za kupnju i servisiranje vozila). Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Izgradi autobusnu postaju. Ctrl omogućava spajanje postaja. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Izgradi putničku tramvajsku postaju. Ctrl omogućava spajanje postaja. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Izgradi pretovarni kamionski terminal. Ctrl omogućava spajanje postaja. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Izgradi teretnu tramvajsku postaju. Ctrl omogućava spajanje postaja. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Aktiviraj/deaktiviraj jednosmjerne ceste STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Izgradi cestovni most. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Izgradi tramvajski most. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Izgradi cestovni tunel. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Izgradi tramvajski tunel. Shift mijenja prikaz građenje/procjena troškova. STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Aktiviraj izgradnju/uklanjanje za izgradnju ceste STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Aktiviraj izgradnju/uklanjanje za izgradnju tramvaja # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Smjer cestovnog spremišta STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Odaberi smjer spremišta cestovnih vozila STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Smjer tramvajskog spremišta STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Odaberi smjer tramvajskog spremišta # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Smjer autobusne postaje STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Odaberi smjer autobusne postaje STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Smjer kamionskog terminala STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Odaberi smjer kamionskog terminala STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Orijentacija postaje putničkog tramvaja STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Odaberi smjer putničke tramvajske postaje STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Orijentacija postaje teretnog tramvaja STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Odaberi smjer teretne tramvajske postaje # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Izgradnja plovnih kanala STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Plovni kanali STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Izgradi kanale. Shift mijenja prikaz građenje/procjena troškova. STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Izgradi brane. Shift mijenja prikaz građenje/procjena troškova. STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Izgradi spremište brodova (za kupnju i servisiranje brodova). Shift mijenja prikaz građenje/procjena troškova. STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Izgradi brodsko pristanište. Ctrl omogućava spajanje postaja. Shift mijenja prikaz građenje/procjena troškova. STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Smjesti plutaču koja može biti korištena kao čvorište. Shift mijenja prikaz građenje/procjena troškova. STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Izgradi akvadukt. Shift mijenja prikaz građenje/procjena troškova. STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Odredi vodeno područje.{}Napravi kanal, osim ako Ctrl nije pritisnut na morskom nivou, kada će umjesto toga potopiti okolna područja STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Postavi rijeke # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Smjer spremišta brodova STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Odaberi smjer spremišta brodova # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Pristanište # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Zračne luke STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Izgradi zračnu luku. Ctrl omogućava spajanje postaja. Shift mijenja prikaz građenje/procjena troškova. # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Izbor zračne luke STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Odaberi veličinu/vrstu zračne luke STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Klasa zračne luke STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Raspored {NUM} STR_AIRPORT_SMALL :Mala STR_AIRPORT_CITY :Grad STR_AIRPORT_METRO :Metropolitanska zračna luka STR_AIRPORT_INTERNATIONAL :Međunarodna zračna luka STR_AIRPORT_COMMUTER :Redoviti putnik STR_AIRPORT_INTERCONTINENTAL :Međukontinentalni STR_AIRPORT_HELIPORT :Heliodrom STR_AIRPORT_HELIDEPOT :Spremište helikoptera STR_AIRPORT_HELISTATION :Postaja za helikoptere STR_AIRPORT_CLASS_SMALL :Male zračne luke STR_AIRPORT_CLASS_LARGE :Velike zračne luke STR_AIRPORT_CLASS_HUB :Središnje zračne luke STR_AIRPORT_CLASS_HELIPORTS :Zračne luke za helikoptere STR_STATION_BUILD_NOISE :{BLACK}Proizvedeno buke: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}Uređivanje krajolika STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Snizi jedan kut zemlje. Povlačenje snižava prvi odabrani kut i poravnava selektirano područje na novu visinu prvog kuta. Ctrl selektira područje dijagonalno. Shift mijenja prikaz građenje/procjena troškova. STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Podigni jedan kut zemlje. Povlačenje podiže prvi odabrani kut i poravnava selektirano područje na novu visinu prvog kuta. Ctrl selektira područje dijagonalno. Shift mijenja prikaz građenje/procjena troškova. STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Poravnaj područje zemlje na visinu prvog odabranog kuta. Ctrl selektira područje dijagonalno. Shift mijenja prikaz građenje/procjena troškova. STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Kupi zemlju za buduću uporabu. Shift mijenja prikaz građenje/procjena troškova. # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Odabir objekta STR_OBJECT_BUILD_TOOLTIP :{BLACK}Odaberi objekt za izgradnju. Shift mijenja prikaz građenje/procjena troškova. STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Odaberi vrstu objekta za izgradnju STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Pregled objekta STR_OBJECT_BUILD_SIZE :{BLACK}Veličina: {GOLD}{NUM} x {NUM} polja STR_OBJECT_CLASS_LTHS :Svjetionici STR_OBJECT_CLASS_TRNS :Odašiljači # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Drveće STR_PLANT_TREE_TOOLTIP :{BLACK}Odaberi vrstu drveta za sadnju. Ako polje već ima drvo, ovo će dodati još drveća raznih vrsta neovisno o odabranoj vrsti STR_TREES_RANDOM_TYPE :{BLACK}Raznovrsno drveće STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Posadi raznovrsno drveće. Shift mijenja prikaz građenje/procjena troškova. STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Nasumično odabrano drveće STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Nasumce posadi drveće po krajoliku # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Stvaranje zemljišta STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Stavi stijenje na krajolik STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Odredi pustinjsko područje.{}Pritisni i drži Ctrl za uklanjanje STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Povećaj područje koje će biti povišeno/sniženo STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Smanji područje koje će biti povišeno/sniženo STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Napravi nasumično zemljište STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Kreiraj novi scenarij STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Poništi krajolik STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Obriši s karte sve u vlasništvu tvrtke STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Poništi krajolik STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Jeste li sigurni da želite obrisati sve u vlasništvu tvrtke? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}Stvaranje gradova STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}Novi grad STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Osnuj novi grad. Shift+Klik prikazuje samo trošak. STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Nasumičan grad STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Osnuj grad na nasumično odabranom mjestu STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Brojni nasumični gradovi STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Popuni kartu nasumično raspoređenim gradovima STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Ime grada: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Upišite ime grada STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Kliknite kako bi upisali ime grada STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Nasumično ime STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Generiraj novo nasumično ime STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Veličina grada: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Malo STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Srednje STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Veliko STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Nasumično STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Odaberi veličinu grada STR_FOUND_TOWN_CITY :{BLACK}Grad STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Velegradovi rastu brže od običnih gradova{}Ovisno o postavkama, veći su prilikom osnivanja STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Raspored gradskih cesta STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Odaberi raspored cesta za ovaj grad STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Original STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Bolje ceste STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 mreža STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 mreža STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Nasumično # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Financiraj novu industriju STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Izaberi prikladnu industriju s ovog popisa STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Brojne nasumične industrije STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Popuni kartu nasumce smještenim industrijama STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Cijena: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospekt STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Izgradi STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Financiraj # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Industrijski slijed za {STRING} industriju STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Industrijski slijed za {STRING} teret STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Proizvodne industrije STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Primateljske industrije STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Kuće STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Klinkni na industriju za prikaz njenih dobavljača i klijenata STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Klikni na teret za prikaz dobavljača i klijenata STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Prikaži slijed STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Prikaži industrije koje dobavljaju i primaju teret STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Poveznica na malu mapu STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Odaberi prikazane industrije također i na maloj mapi STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Odaberi teret STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Odaberi teret koji želiš prikazati STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Odaberi industriju STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Odaberi industriju koju želiš prikazati # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Podaci o zemlji STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Troškovi čišćenja: {LTBLUE}Nedostupno STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Troškovi čišćenja: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Prihod kada je očišćeno: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :NIJE DOSTUPNO STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Vlasnik: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Vlasnik ceste: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Vlasnik tramvaja: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Vlasnik željeznice: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Područna nadležnost: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nijedan/Nitko/Ništa STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Izgrađeno: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Klasa postaje: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Vrsta postaje: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Klasa zračne luke: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Ime zračne luke: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Naziv polja zračne luke: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Prihvaćeni teret: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Najveća brzina željeznice: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Ograničenje brzine na cesti: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Stijenje STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Surova zemlja STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Ogoljena zemlja STR_LAI_CLEAR_DESCRIPTION_GRASS :Trava STR_LAI_CLEAR_DESCRIPTION_FIELDS :Polja STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Zemlja pokrivena snijegom STR_LAI_CLEAR_DESCRIPTION_DESERT :Pustinja STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} pruga STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} pruga sa blok-signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} pruga sa pred-signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} pruga sa izlaznim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} pruga sa kombiniranim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} pruga sa putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} pruga sa jednosmjernim putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} pruga sa blok-signalima i pred-signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} pruga sa blok-signalima i izlaznim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} pruga sa blok-signalima i kombiniranim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} pruga sa blok-signalima i putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} pruga sa blok-signalima i jednosmjernim putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} pruga sa pred-signalima i izlaznim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} pruga sa pred-signalima i kombiniranim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} pruga sa pred-signalima i putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} pruga sa pred-signalima i jednosmjernim putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} pruga sa izlaznim i kombiniranim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} pruga sa izlaznim i putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} pruga sa izlaznim i jednosmjernim putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} pruga sa kombiniranim i putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} pruga sa kombiniranim i jednosmjernim putnim signalima STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} pruga sa putnim i jednosmjernim putnim signalima STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} spremište vlaka STR_LAI_ROAD_DESCRIPTION_ROAD :Cesta STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Cesta s javnom rasvjetom STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Cesta s tri trake STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Spremište cestovnih vozila STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Prijelaz ceste preko željezničke pruge STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramvaj # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (u izgradnji) STR_LAI_TREE_NAME_TREES :Drveće STR_LAI_TREE_NAME_RAINFOREST :Kišna šuma STR_LAI_TREE_NAME_CACTUS_PLANTS :Kaktusi STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Željeznička postaja STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Zrakoplovni hangar STR_LAI_STATION_DESCRIPTION_AIRPORT :Zračna luka STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Ukrcajno područje STR_LAI_STATION_DESCRIPTION_BUS_STATION :Autobusna postaja STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Brodsko pristanište STR_LAI_STATION_DESCRIPTION_BUOY :Plutača STR_LAI_STATION_DESCRIPTION_WAYPOINT :Čvorište STR_LAI_WATER_DESCRIPTION_WATER :Voda STR_LAI_WATER_DESCRIPTION_CANAL :Kanal STR_LAI_WATER_DESCRIPTION_LOCK :Brana STR_LAI_WATER_DESCRIPTION_RIVER :Rijeka STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Obala ili riječni nasip STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Spremište brodova # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Željeznički tunel STR_LAI_TUNNEL_DESCRIPTION_ROAD :Cestovni tunel STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Čelični viseći željeznički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Čelični noseći željeznički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Čelični konzolni željeznički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Ojačani betonski viseći željeznički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Drveni željeznički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Betonski željeznički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Cijevni željeznički most STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Čelični viseći cestovni most STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Čelični noseći cestovni most STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Čelični konzolni cestovni most STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Ojačani betonski viseći cestovni most STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Drveni cestovni most STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Betonski cestovni most STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Cijevni cestovni most STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Akvadukt STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Odašiljač STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Svjetionik STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Sjedište tvrtke STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Zemlja u posjedu tvrtke # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}O OpenTTD-u STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Izvorno autorsko pravo {COPYRIGHT} 1995 Chris Sawyer, sva prava pridržana STR_ABOUT_VERSION :{BLACK}OpenTTD verzija {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2015 OpenTTD tim # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Spremi igru STR_SAVELOAD_LOAD_CAPTION :{WHITE}Učitaj igru STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Spremi scenarij STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Učitaj scenarij STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Učitaj visinsku kartu STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Spremi visinsku mapu STR_SAVELOAD_HOME_BUTTON :{BLACK}Klikni ovdje za prelazak u trenutnu pretpostavljenu mapu za snimanje/učitavanje STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} slobod{P an na no} STR_SAVELOAD_LIST_TOOLTIP :{BLACK}Popis diskova, mapa i spremljenih datoteka STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Trenutno odabrano ime za spremanje igre STR_SAVELOAD_DELETE_BUTTON :{BLACK}Obriši STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Obriši trenutno odabranu spremljenu igru STR_SAVELOAD_SAVE_BUTTON :{BLACK}Spremi STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Spremi trenutnu igru koristeći odabrano ime STR_SAVELOAD_LOAD_BUTTON :{BLACK}Učitaj STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Učitaj odabranu igru STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP :{BLACK}Učitaj odabranu visinsku kartu STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Detalji o igri STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Nema dostupnih informacija. STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}Upiši ime za spremanje igre # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}Izrada svijeta STR_MAPGEN_MAPSIZE :{BLACK}Veličina karte: STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Odaberi veličinu mape u poljima. Broj dostupnih polja biti će malo manji STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Broj gradova: STR_MAPGEN_DATE :{BLACK}Datum: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Broj industrija: STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}Maksimalna visina mape: STR_MAPGEN_MAX_HEIGHTLEVEL_UP :{BLACK}Povećaj maksimalnu visinu planina na mapi za jedan STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN :{BLACK}Smanji maksimalnu visinu planina na mapi za jedan STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Visina linije snijega STR_MAPGEN_SNOW_LINE_UP :{BLACK}Pomakni visinu linije snijega za jedan gore STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Pomakni visinu linije snijega za jedan dolje STR_MAPGEN_LAND_GENERATOR :{BLACK}Izrađivač zemljišta: STR_MAPGEN_TREE_PLACER :{BLACK} Algoritam za drveće: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Vrsta terena: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Razina mora: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Rijeke: STR_MAPGEN_SMOOTHNESS :{BLACK}Graduacija: STR_MAPGEN_VARIETY :{BLACK}Distribucija raznovrsnosti: STR_MAPGEN_GENERATE :{WHITE}Izradi # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}Rubovi Karte: STR_MAPGEN_NORTHWEST :{BLACK}Sjeverozapad STR_MAPGEN_NORTHEAST :{BLACK}Sjeveroistok STR_MAPGEN_SOUTHEAST :{BLACK}Jugoistok STR_MAPGEN_SOUTHWEST :{BLACK}Jugozapad STR_MAPGEN_BORDER_FREEFORM :{BLACK}Slobodni oblik STR_MAPGEN_BORDER_WATER :{BLACK}Voda STR_MAPGEN_BORDER_RANDOM :{BLACK}Nasumično STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Nasumično STR_MAPGEN_BORDER_MANUAL :{BLACK}Ručno STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Rotacija visinske mape: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Ime visinske karte: STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Veličina: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT :{WHITE}Promijeni maksimalnu visinu mape STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Promijeni visinu linije snijega STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Promijeni početnu godinu # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}Vrsta scenarija STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Ravna zemlja STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Kreiraj ravan teren STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Nasumični teren STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Visina ravne površine: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Snizi ravnu površinu za jedan korak STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Povisi ravnu površinu za jedan korak STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Promijeni visinu ravne površine # Map generation progress STR_GENERATION_WORLD :{WHITE}Izrada svijeta u toku... STR_GENERATION_ABORT :{BLACK}Prekini STR_GENERATION_ABORT_CAPTION :{WHITE}Poništi izradu svijeta STR_GENERATION_ABORT_MESSAGE :{YELLOW}Želiš li zaista prekinuti izradu? STR_GENERATION_PROGRESS :{WHITE}{NUM}% gotovo STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}Izrada svijeta STR_GENERATION_RIVER_GENERATION :{BLACK}Generiranje rijeka STR_GENERATION_TREE_GENERATION :{BLACK}Generiranje drveća STR_GENERATION_OBJECT_GENERATION :{BLACK}Nepomično generiranje STR_GENERATION_CLEARING_TILES :{BLACK}Generiranje grubog i stjenovitog područja STR_GENERATION_SETTINGUP_GAME :{BLACK}Pripremam igru STR_GENERATION_PREPARING_TILELOOP :{BLACK}Izvršavam tile-petlju STR_GENERATION_PREPARING_SCRIPT :{BLACK}Izvođenje skripte u tijeku STR_GENERATION_PREPARING_GAME :{BLACK}Pripremam igru # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF postavke STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Detaljne NewGRF informacije STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Aktivne NewGRF datoteke STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Neaktivne NewGRF datoteke STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Odaberi predložak: STR_NEWGRF_FILTER_TITLE :{ORANGE}Filter: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Učitaj unaprijed odabrane postavke STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Spremi zadano postavljanje STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Spremi trenutni popis kao zadano postavljanje STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Upiši ime zadanog postavljanja STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Obriši zadano postavljanje STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Obriši trenutno izabrano zadano postavljanje STR_NEWGRF_SETTINGS_ADD :{BLACK}Dodaj STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Dodaj odabrane NewGRF datoteke u svoju konfiguraciju STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Ponovno skeniraj datoteke STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Osvježi popis dostupnih NewGRF datoteka STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Ukloni STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Ukloni odabranu NewGRF datoteku s popisa STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Pomakni gore STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Pomakni odabranu NewGRF datoteku gore na listi STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK} Pomakni dolje STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Pomakni odabranu NewGRF datoteku dolje na listi STR_NEWGRF_SETTINGS_UPGRADE :{BLACK}Nadogradnja STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP :{BLACK}Nadogradite NewGRF datoteke za koje već imate instalirane novije verzije STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}Popis instaliranih NewGRF datoteka STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Postavi parametre STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Prikaži parametre STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Aktiviraj paletu STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Prilagodi paletu izabranog NewGRF-a.{}Učini ovo kada grafike iz ovog NewGRF-a izgledaju ljubičasto tijekom igre. STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Potvrdi promjene STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Pronađi nedostajeći sadržaj online STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Provjeri može li se nedostajeći sadržaj pronaći online STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Datoteka: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Verzija: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Min. kompatibilna verzija: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5 suma: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Paleta: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parametri: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}Nema dostupnih informacija STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Nije pronađena odgovarajuća datoteka STR_NEWGRF_SETTINGS_DISABLED :{RED}Onemogućeno STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Nije kompatibilno sa ovom verzijom OpenTTD-a # NewGRF save preset window STR_SAVE_PRESET_CAPTION :{WHITE}Snimiti predpostavke STR_SAVE_PRESET_LIST_TOOLTIP :{BLACK}Popis dostupnih predpostavki, odaberite jednu za kopiranje pod imenom ispod STR_SAVE_PRESET_TITLE :{BLACK}Unesite ime za predpostavke STR_SAVE_PRESET_EDITBOX_TOOLTIP :{BLACK}Trenutno odabrano ime za snimanje predpostavki STR_SAVE_PRESET_CANCEL :{BLACK}Odustani STR_SAVE_PRESET_CANCEL_TOOLTIP :{BLACK}Ne mijenjati predpostavke STR_SAVE_PRESET_SAVE :{BLACK}Snimanje STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Snimite predpostavke u trenutno odabrano ime # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Promijeni NewGRF parametre STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Zatvori STR_NEWGRF_PARAMETERS_RESET :{BLACK}Resetiraj STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Namjesti sve parametre na osnovne vrijednosti STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parametar {NUM} STR_NEWGRF_PARAMETERS_SETTING :{STRING}: {ORANGE}{STRING} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Broj parametara: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Pregledaj - {STRING} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Matični STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Pregledaj objekt matičnog djelokruga STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING} na {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Objekt STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Vrsta željeznice STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF varijabla 60+x parametar (heksadecimalni) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Poravnanje sprite-a {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Sljedeći sprite STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Otiđi na sljedeći normalni sprite, preskačući svaki pseudo/prebojani/font sprite i nakon dolaska na zadnjeg prebaci na prvi STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Otiđi na sprite STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Otiđi na određeni sprite. Ako sprite nije normalni sprite, otiđi na slijedeći normalni sprite STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Prethodni sprite STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Otiđi na prethodni normalni sprite, preskačući svaki pseudo/prebojani/font sprite i {BLACK}Otiđi na sljedeći normalni sprite, preskačući svaki pseudo/prebojani/font sprite i nakon dolaska na prvi prebaci na zadnjeg STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Prikaz trenutno odabranog spritea. Poravnjanje se ignorira kod crtanja ovog spritea. STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Pomakni sprite mijenjajući X i Y pomake STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Poništi relativne STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Poništi trenutne relativne pomake STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}X pomak: {NUM}, Y pomak: {NUM} (Apsolutni) STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}X pomak: {NUM}, Y pomak: {NUM} (Relativni) STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Odaberi sprite STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Odaberi sprite od bilo gdje na ekranu STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Otiđi na sprite # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Upozorenje: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Greška: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Kobno: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Dogodila se kobna pogreška u NewGRF-u: {}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} neće raditi sa TTDPatch verzijom prijavljenom u OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} je za {STRING} verziju TTD-a. STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} je napravljen da se koristi sa {STRING} STR_NEWGRF_ERROR_INVALID_PARAMETER :Nevažeći parametar za {1:STRING}: parametar {STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} se mora učitati prije {STRING}. STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} se mora učitati nakon {STRING}. STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} zahtijeva OpenTTD verziju {STRING} ili noviju. STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :GRF datoteka je dizajnirana za prijevod STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Previše učitanih NewGRF-ova. STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Učitavanjem {1:STRING} kao statičnog NewGRF s {STRING} može uzrokovati deharmonizaciju STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Neočekivani sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Nepoznata vrijednost Action 0 {4:HEX} (sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Pokušaj korištenja pogrešnog ID-a (sprite {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{STRING} sadrži neispravan sprite. Svi neispravni grafički znakovi bit će pokazani kao crveni upitnik (?). STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Sadrži višestruke unose za Action 8 (sprite {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Pročitaj nakon kraja od pseudo-sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}Baznom grafičkom setu u uporabi nedostaju neki spriteovi.{}Ažurirajte bazni grafički set STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}Trenutno korištenom osnovnom grafičkom setu nedostaju pojedini crteži.{}Molimo da nadogradite osnovni grafički set.{}Pošto igrate {YELLOW}razvojnu inačicu OpenTTD-a{WHITE}, možda će vam trebati i {YELLOW}razvojna inačica osnovnog grafičkog seta{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Zatraženi GRF resursi nisu dostupni (sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} je isključen od strane {STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Pogrešan/nepoznat format raspored sprite-a (sprite {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Oprez! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Spremate se napraviti izmjene u pokrenutoj igri. To može srušiti OpenTTD ili uništiti status same igre. Nemojte prijavljivati moguće smetnje kao bugove.{}Jeste li potpuno sigurni da želite nastaviti? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Ne mogu dodati datoteku: dupli GRF ID STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Odgovarajuća datoteka nije pronađena (kompatibilni GRF podignut) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Nemoguće dodati datoteku: dosegnut limit broja NewGRF datoteka STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Kompatibilni GRF(ovi) učitani umjesto nepronađenih datoteka STR_NEWGRF_DISABLED_WARNING :{WHITE}Nepronađene GRF datoteke su isključene STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Nedostaje GRF datoteka(e) STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Odpauziranje može uzrokovati rušenje OpenTTD-a. Nemojte slati prijave bugova za posljedična rušenja.{}Želite li stvarno odpauzirati? # NewGRF status STR_NEWGRF_LIST_NONE :Nijedan STR_NEWGRF_LIST_ALL_FOUND :Svi fajlovi prisutni STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Pronađeni kompatibilni fajlovi STR_NEWGRF_LIST_MISSING :{RED}Nedostaju fajlovi # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}Ponašanje NewGRF '{0:STRING}' će vjerojatno uzrokovati deharmonizaciju i/ili rušenje igre STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Promijenjen status motoriziranog vagona za '{1:ENGINE}' kad vozilo nije u spremištu. STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Ovo mijenja dužinu vozila za '{1:ENGINE}' kada vozilo nije unutar spremišta STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Promijenilo je kapacitet vozila za '{1:ENGINE}' kada nije u spremšta ili se remontira STR_BROKEN_VEHICLE_LENGTH :{WHITE}Vlak'{VEHICLE}' koji pripada tvrtci '{COMPANY}' neispravne je dužine. Uzrok problema je vjerojatno u NewGRF datotekama. Igra će se možda deharmonizirati ili srušiti STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' daje netočne informacije STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Informacija o teretu/remontu za '{1:ENGINE}' je različita od kupovne liste nakon izgradnje. Zbog toga bi automatsko obnavljanje/zamjena mogla biti neuspješna STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{G=male}{WHITE}'{1:STRING}' je uzrokovao beskonačnu petlju u pozivu za povrat produkcije STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Povratnica {1:HEX} je vratio nepoznat/nemoguć rezultat {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} od STR_NEWGRF_INVALID_ENGINE : STR_NEWGRF_INVALID_INDUSTRYTYPE : # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE : # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}Tražim NewGRFove STR_NEWGRF_SCAN_MESSAGE :{BLACK}Tražim NewGRFove. Ovisno o količini ovo može malo potrajati... STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF skeniran iz procijenjenog {NUM} NewGRF STR_NEWGRF_SCAN_ARCHIVES :Tražim arhive # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}Popis znakova - {COMMA} znak{P "" a ova} STR_SIGN_LIST_MATCH_CASE :{BLACK}Velika i mala slova STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Koristi/ne koristi velika i mala slova kod usporedbe imena oznaka sa imenima sa slijedom filtera # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Izmijeni tekst znaka STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Idi do sljedećeg znaka STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Idi do prethodnog znaka STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Unesi ime znaka # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}Gradovi STR_TOWN_DIRECTORY_NONE :{ORANGE}- Ništa - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Imena gradova - klikni na ime kako bi centrirao pogled na grad. Ctrl+klik otvara novi prozor sa lokacijom grada STR_TOWN_POPULATION :{BLACK}Svjetsko stanovništvo: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (Metropola) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Stanovništvo: {ORANGE}{COMMA}{BLACK} Kuće: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Putnika prošli mjesec: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Pošte prošli mjesec: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Potrebno tereta za rast grada: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} potrebno STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} potrebno zimi STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} isporučeno STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (još potrebno) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (isporučeno) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Grad raste svaki {ORANGE}{COMMA}{BLACK}{NBSP}dan STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Grad raste svaki {ORANGE}{COMMA}{BLACK}{NBSP}dan (financirano) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Grad {RED}ne{BLACK} raste STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Ograničenje buke u gradu: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju grada. Ctrl+klik otvara novi prozor sa lokacijom grada STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Lokalna samouprava STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Pokaži informacije o lokalnoj samoupravi STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Promijeni ime grada STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Proširi STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Povećaj veličinu grada STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Obriši STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Obriši ovaj grad u cjelosti STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Preimenuj grad # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}Lokalna samouprava grada {TOWN}a STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Ocjene prijevoznih tvrtki: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Dostupne radnje: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}Popis stvari koje treba učiniti u ovom gradu - klikni za dodatne informacije STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Učini to STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Izvrši označene radnje na gornjem popisu STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Mala oglasna kampanja STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Srednja oglasna kampanja STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Velika oglasna kampanja STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Financiraj popravljanje lokalne prometnice STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Izgradi kip vlasnika tvrtke STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Financiraj nove građevine STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Kupi ekskluzivna prava prijevoza STR_LOCAL_AUTHORITY_ACTION_BRIBE :Podmiti lokalnu samoupravu STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Pokreni malu oglasnu kampanju, kako bi privukao više putnika i tereta za svoje prijevozne usluge.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Pokreni srednju oglasnu kampanju, kako bi privukao više putnika i tereta za svoje prijevozne usluge.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Pokreni veliku oglasnu kampanju, kako bi privukao više putnika i tereta za svoje prijevozne usluge.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Financiraj popravak gradske mreže prometnica. Uzrokuje značajne poremećaje u cestovnom prometu do 6 mjeseci.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Izgradi kip u čast svoje tvrtke.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Financiraj izgradnju novih poslovnih prostora u gradu.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Kupi jednogodišnje ekskluzivno pravo prijevoza u gradu. Gradska vlast dopustit će putnicima i teretu korištenje isključivo postaja tvoje tvrtke.{} Cijena: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Podmiti lokalnu samoupravu kako bi povećao ugled, riskirajući ozbiljne kazne ako te uhvate.{} Trošak: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Ciljevi STR_GOALS_SPECTATOR_CAPTION :{WHITE}Globalni ciljevi STR_GOALS_GLOBAL_TITLE :{BLACK}Globalni ciljevi: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Nijedan - STR_GOALS_SPECTATOR_NONE :{ORANGE}- Nije primjenjivo - STR_GOALS_PROGRESS :{ORANGE}{STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_COMPANY_TITLE :{BLACK}Ciljevi tvrtke: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikni na cilj za centriranje središnjeg pogleda na industriju/grad/polje. Ctrl+Klik otvara novi prozor s pogledom na lokaciju industrije/grada/polja # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :Pitanje STR_GOAL_QUESTION_CAPTION_INFORMATION :Informacija STR_GOAL_QUESTION_CAPTION_WARNING :Upozorenje STR_GOAL_QUESTION_CAPTION_ERROR :Greška ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Poništi STR_GOAL_QUESTION_BUTTON_OK :OK STR_GOAL_QUESTION_BUTTON_NO :Ne STR_GOAL_QUESTION_BUTTON_YES :Da STR_GOAL_QUESTION_BUTTON_DECLINE :Odbij STR_GOAL_QUESTION_BUTTON_ACCEPT :Prihvati STR_GOAL_QUESTION_BUTTON_IGNORE :Ignoriraj STR_GOAL_QUESTION_BUTTON_RETRY :Pokušaj ponovo STR_GOAL_QUESTION_BUTTON_PREVIOUS :Prethodni STR_GOAL_QUESTION_BUTTON_NEXT :Sljedeći STR_GOAL_QUESTION_BUTTON_STOP :Stani STR_GOAL_QUESTION_BUTTON_START :Kreni STR_GOAL_QUESTION_BUTTON_GO :Započni STR_GOAL_QUESTION_BUTTON_CONTINUE :Nastavi STR_GOAL_QUESTION_BUTTON_RESTART :Ponovi od početka STR_GOAL_QUESTION_BUTTON_POSTPONE :Odgodi STR_GOAL_QUESTION_BUTTON_SURRENDER :Odustani STR_GOAL_QUESTION_BUTTON_CLOSE :Zatvori ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}Subvencije STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Ponuđene subvencije za pružanje usluga: STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} od {STRING} do {STRING}{YELLOW} (do {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- Ništa - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Usluge koje su već subvencionirane: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} iz {STRING} prema {STRING}{YELLOW} ({COMPANY}{YELLOW}, do {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikni na uslugu za centriranje pogleda na industriju/grad. Ctrl+klik otvara novi prozor sa lokacijom industrije/grada # Story book window STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Priča STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Globalna priča STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :Stranica {NUM} STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Preskoči na specifičnu stranicu odabravši je iz liste. STR_STORY_BOOK_PREV_PAGE :{BLACK}Prethodno STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Prethodna stranica STR_STORY_BOOK_NEXT_PAGE :{BLACK}Sljedeće STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Sljedeća stranica STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Neispravna referenca cilja # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Imena postaja - klikni na ime kako bi centrirao glavni pogled na postaju. Ctrl+klik otvara novi prozor sa lokacijom postaje STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Drži Ctrl kako bi odabrao više od jedne stavke STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} postaj{P a e a} STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- Ništa - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Odaberi sva sredstva STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Odaberi sve vrste tereta (uključujući i teret koji ne čeka) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}Nijedna vrsta tereta ne čeka # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} iz {STATION}) STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} rezervirano za ukrcaj) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Prihvaća STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Pokaži popis tereta koji se prihvaća STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Prihvaća: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}Ova stanica ima ekskluzivna prava trasnporta u ovom gradu. STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} kupljena ekskluzivna prava transporta u ovom gradu. STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Ocjene STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Pokaži ocjene postaje STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Mjesečna dostava i lokalni rejting: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}Grupiraj po STR_STATION_VIEW_WAITING_STATION :Stanica: Na čekanju STR_STATION_VIEW_WAITING_AMOUNT :Iznos: Na čekanju STR_STATION_VIEW_PLANNED_STATION :Stanica: Planirana STR_STATION_VIEW_PLANNED_AMOUNT :Iznos: Planirani STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} od {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} putem {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} do {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} od nepoznate stanice STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} do bilo koje stanice STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} putem bilo koje stanice STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} od ove stanice STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} staje na ovoj stanici STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} do ove stanice STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} bez zaustavljanja STR_STATION_VIEW_GROUP_S_V_D :Ishodište-Putem-Odredište STR_STATION_VIEW_GROUP_S_D_V :Ishodište-Odredište-Putem STR_STATION_VIEW_GROUP_V_S_D :Putem-Ishodište-Odredište STR_STATION_VIEW_GROUP_V_D_S :Putem-Odredište-Ishodište STR_STATION_VIEW_GROUP_D_S_V :Odredište-Ishodište-Putem STR_STATION_VIEW_GROUP_D_V_S :Odredište-Putem-Ishodište ############ range for rating starts STR_CARGO_RATING_APPALLING :Užasno STR_CARGO_RATING_VERY_POOR :Vrlo loše STR_CARGO_RATING_POOR :Loše STR_CARGO_RATING_MEDIOCRE :Osrednje STR_CARGO_RATING_GOOD :Dobro STR_CARGO_RATING_VERY_GOOD :Vrlo dobro STR_CARGO_RATING_EXCELLENT :Izvrsno STR_CARGO_RATING_OUTSTANDING :Izvanredno ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju postaje. Ctrl+klik otvara novi prozor sa lokacijom postaje STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Promijeni ime postaje STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Pokaži sve vlakove koji imaju ovu postaju u svom rasporedu STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Pokaži sva cestovna vozila koja imaju ovu postaju u svom rasporedu STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Pokaži sve zrakoplove koji imaju ovu postaju u svom rasporedu STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Pokaži sve brodove koji imaju ovu postaju u svom rasporedu STR_STATION_VIEW_RENAME_STATION_CAPTION :Preimenuj postaju/terminal STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Zatvori zračnu luku STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Spriječi slijetanje zrakoplova u ovu zračnu luku # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju čvorišta. Ctrl+klik otvara novi pogled na lokaciju čvorišta. STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Promijeni ime čvorišta STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju plutače. Ctrl+klik otvara novi pogled na lokaciju plutače. STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Promijeni ime plutače STR_EDIT_WAYPOINT_NAME :{WHITE}Promijeni ime čvorišta # Finances window STR_FINANCES_CAPTION :Financije tvrtke {WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Rashodi/Prihodi STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Izgradnja STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}Nova vozila STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Troškovi uporabe vlakova STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Troškovi uporabe cestovnih vozila STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Troškovi uporabe zrakoplova STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Troškovi uporabe brodova STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Održavanje posjeda STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Prihod od vlakova STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Prihod od cestovnih vozila STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Prihod od zrakoplova STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Prihod od brodova STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Kamate STR_FINANCES_SECTION_OTHER :{GOLD}Ostalo STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}Ukupno: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bankovna bilanca STR_FINANCES_LOAN_TITLE :{WHITE}Zajam STR_FINANCES_MAX_LOAN :{WHITE}Maksimalni kredit: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}Pozajmi {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}Povećaj iznos zajma. Ctrl+klik posuđuje najveći mogući iznos STR_FINANCES_REPAY_BUTTON :{BLACK}Otplati {CURRENCY_LONG} STR_FINANCES_REPAY_TOOLTIP :{BLACK}Otplati dio zajma STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastruktura # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Direktor) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Na poziciji od: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Boja: STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Vozila: STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} vlak{P "" a ova} STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} cestovn{P o a ih} vozil{P o a a} STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} zrakoplov STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} brod{P "" a ova} STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}Ništa STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Vrijednost tvrtke: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% u vlasništvu {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastruktura: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} dijelovi pruge STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} dio ceste STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} polje vode STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} polje postaje STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} zračne luke STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}Ništa STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Izgradi sjedište tvrtke STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Izgradi sjedište tvrtke STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}Pogledaj sjedište tvrtke STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}Pogledaj sjedište tvrtke STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Premjesti sjedište tvrtke STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Izgradi sjedište tvrtke negdje drugdje za 1% troška od cjelokupne vrijednosti tvrtke. Shift+Klik prikazuje trošak bez premještanja sjedišta tvrtke. STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Detalji STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}Pogledaj detaljne podatke infrastrukture STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}Novo lice STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Odaberi novo lice direktora STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Boja STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Promijeni shemu boja za vozila tvrtke STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Ime tvrtke STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Promijeni ime tvrtke STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Ime direktora STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Promjeni ime direktora STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Kupi 25% udjela u tvrtci STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Prodaj 25% udjela u tvrtci STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Kupi 25% udjela u ovoj tvrtci. Shift+Klik prikazuje trošak bez kupnje udjela. STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Prodaj 25% udjela u ovoj tvrtci. Shift+Klik prikazuje trošak bez prodaje udjela. STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Ime tvrtke STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Ime direktora STR_BUY_COMPANY_MESSAGE :{WHITE}Tražimo prijevoznu tvrtku koja bi preuzela našu tvrtku.{}{}Želiš li kupiti tvrtku {COMPANY} za {CURRENCY_LONG}? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastruktura od {COMPANY} STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Dijelovi pruge: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signali STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Dijelovi ceste: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Cesta STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajska pruga STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Polje s vodom: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Postaje: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Polje s postajom STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Zračne luke STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/god # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Industrije STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- Ništa - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}){YELLOW} ({COMMA}% prevezeno) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}/{CARGO_LONG}{STRING}){YELLOW} ({COMMA}%/{COMMA}% prevezeno) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Imena industrija - za centriranje pogleda klikni na ime. Ctrl+klik otvara novi prozor sa lokacijom industrije # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Prošlomjesečna proizvodnja: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% prevezeno) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centriraj glavni pogled na položaj industrije. Ctrl+klik otvara novi prozor sa lokacijom industrije STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Razina proizvodnje: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Industrija je najavila uskoro zatvaranje! ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Treba: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Treba: {YELLOW}{STRING}{STRING}, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Treba: {YELLOW}{STRING}{STRING}, {STRING}{STRING}, {STRING}{STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Teret koji čeka obradu: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Proizvodi: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Proizvodi: {YELLOW}{STRING}{STRING}, {STRING}{STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}Promijeni proizvodnju (višekratnik broja 8, do 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Promijeni razinu proizvodnje (postotak, do najviše 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} - {COMMA} vlak{P "" a ova} STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING} - {COMMA} cestovn{P o a ih} vozil{P o a a} STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING} - {COMMA} brod{P "" a ova} STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING} - {COMMA} zrakoplova STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Vlakovi - klikni na vlak za informacije STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Cestovna vozila - klikni na vozilo za informacije STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Brodovi - klikni na brod za informacije STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Zrakoplov - klikni na zrakoplov za informacije STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Ovogodišnja dobit: {CURRENCY_LONG} (prošlogodišnja: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :Dostupni vlakovi STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Dostupna vozila STR_VEHICLE_LIST_AVAILABLE_SHIPS :Dostupni brodovi STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Dostupni zrakoplovi STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}Pogledaj popis dostupnih dizajna motora za ovu vrstu vozila. STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Uredi popis STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Pošalji upute svim vozilima na ovom popisu STR_VEHICLE_LIST_REPLACE_VEHICLES :Zamjeni vozila STR_VEHICLE_LIST_SEND_FOR_SERVICING :Pošalji na servis STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Pošalji u spremište STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Pošalji u spremište STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Pošalji u spremište STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Pošalji u hangar STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Klikni za zaustavljanje svih vozila na popisu STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Klikni za pokretanje svih vozila na popisu STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Dijeljene naredbe za {COMMA} vozil{P o a a} # Group window STR_GROUP_ALL_TRAINS :Svi vlakovi STR_GROUP_ALL_ROAD_VEHICLES :Sva cestovna vozila STR_GROUP_ALL_SHIPS :Svi brodovi STR_GROUP_ALL_AIRCRAFTS :Svi zrakoplovi STR_GROUP_DEFAULT_TRAINS :Negrupirani vlakovi STR_GROUP_DEFAULT_ROAD_VEHICLES :Negrupirana cestovna vozila STR_GROUP_DEFAULT_SHIPS :Negrupirani brodovi STR_GROUP_DEFAULT_AIRCRAFTS :Negrupirani zrakoplovi STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grupe - kliknite na grupu kako bi izlistali sva vozila ove grupe. Povucite i prenesite grupe za postavljanje hijerarhije. STR_GROUP_CREATE_TOOLTIP :{BLACK}Klikni za kreiranje grupe STR_GROUP_DELETE_TOOLTIP :{BLACK}Obriši odabranu grupu STR_GROUP_RENAME_TOOLTIP :{BLACK}Preimenuj odabranu grupu STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Klikni kako bi zaštitio ovu grupu od globalne automatske zamjene STR_QUERY_GROUP_DELETE_CAPTION :{WHITE}Izbriši grupu STR_GROUP_DELETE_QUERY_TEXT :{WHITE}Da li ste sigurni da želite izbrisati ovu grupu i sve njene podgrupe? STR_GROUP_ADD_SHARED_VEHICLE :Dodaj dijeljena vozila STR_GROUP_REMOVE_ALL_VEHICLES :Ukloni sva vozila STR_GROUP_RENAME_CAPTION :{BLACK}Preimenuj grupu # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :Nova željeznička vozila STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nova električna pružna vozila STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nova jednotračna željeznička vozila STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nova vozila Maglev STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nova pružna vozila STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nova cestovna vozila STR_BUY_VEHICLE_SHIP_CAPTION :Novi brodovi STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Novi zrakoplov STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cijena: {GOLD}{CURRENCY_LONG}{BLACK} Težina {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Brzina: {GOLD}{VELOCITY}{BLACK} Snaga: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Brzina: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Brzina na oceanu: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Brzina na kanalu/rijeci: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Trošak uporabe: {GOLD}{CURRENCY_LONG}/god STR_PURCHASE_INFO_CAPACITY :{BLACK}Nosivost: {GOLD}{CARGO_LONG}{STRING} STR_PURCHASE_INFO_REFITTABLE :(prenamjenjiv) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Dizajnirano: {GOLD}{NUM}{BLACK} Životni vijek: {GOLD}{COMMA} godina STR_PURCHASE_INFO_RELIABILITY :{BLACK}Maks. pouzdanost: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cijena: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Težina: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Trošak: {GOLD}{CURRENCY_LONG}{BLACK} Brzina: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Nosivost: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK} Pokretni vagoni:.{GOLD}+{POWER}{BLACK} Težina: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Prenamjenjivo u: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :Sve vrste tereta STR_PURCHASE_INFO_ALL_BUT :Sve osim {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK} Maks. vučni napor: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Domet: {GOLD}{COMMA} polja STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Popis vlakova za odabir. Klikni na vozilo za informacije. Ctrl+klik za uključivanje ili isključivanje prikaza vrste vozila STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Popis cestovnih vozila za odabir. Klikni na vozilo za informacije. Ctrl+klik za uključivanje ili isključivanje prikaza vrste cestovnog vozila STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Popis brodova za odabir. Klikni na vozilo za informacije. Ctrl+klik za uključivanje ili isključivanje prikaza vrste broda STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Popis zrakoplova za odabir. Klikni na vozilo za informacije. Ctrl+klik za uključivanje ili isključivanje prikaza vrste zrakoplova STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Kupi vozilo STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Kupi vozilo STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Kupi brod STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Kupi zrakoplov STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeni vlak. Shift+Klik prikazuje trošak bez kupnje. STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeno cestovno vozilo. Shift+Klik prikazuje trošak bez kupnje. STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeni brod. Shift+Klik prikazuje trošak bez kupnje. STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Kupi označeni zrakoplov. Shift+Klik prikazuje trošak bez kupnje. STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Preimenuj vrstu vagona STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Preimenuj vrstu cestovnog vozila STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Preimenuj vrstu broda STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Preimenuj vrstu zrakoplova STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Sakrij STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Sakrij STR_BUY_VEHICLE_SHIP_HIDE_TOGGLE_BUTTON :{BLACK}Sakrij STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :{BLACK}Sakrij STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON :{BLACK}Prikaži STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}Prikaži STR_BUY_VEHICLE_SHIP_SHOW_TOGGLE_BUTTON :{BLACK}Prikaži STR_BUY_VEHICLE_AIRCRAFT_SHOW_TOGGLE_BUTTON :{BLACK}Prikaži STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Prebacivanje skrivanja/prikazivanja vrste vlakova STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Prebacivanje skrivanja/prikazivanja vrste cestovnog vozila STR_BUY_VEHICLE_SHIP_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Prebacivanje skrivanja/prikazivanja vrste broda STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Prebacivanje skrivanja/prikazivanja vrste zrakoplova STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Preimenuj vrstu vagona STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Preimenuj vrstu cestovnog vozila STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Preimenuj vrstu broda STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Preimenuj vrstu zrakoplova # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}Promijeniti ime spremišta STR_DEPOT_RENAME_DEPOT_CAPTION :Preimenovati spremište STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} vozil{P o a a}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Vlakovi - drži lijevi klik i vuci vozilo za dodavanje/skidanjed iz vlaka, desni klik za informacije. Drži tipku Ctrl da obje funkcije rade na slijedu STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Vozila - desni klik na vozilo za informacije STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Brodovi - desni klik na brod za informacije STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Zrakoplov - desni klik na zrakoplov za informacije STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Ovdje povuci vlak kako bi ga prodao STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Povuci cestovno vozilo ovdje kako bi ga prodao STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Povuci brod ovdje kako bi ga prodao STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Povuci zrakoplov ovdje kako bi ga prodao STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Ovdje povuci lokomotivu kako bi prodao cijeli vlak STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Prodaj sve vlakove u spremištu STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Prodaj sva cestovna vozila u spremištu STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Prodaj sve brodove u spremištu STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Prodaj sve zrakoplove u hangaru STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Automatski zamijeni sve vlakove u spremištu STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Automatski zamijeni sva cestovna vozikla u spremištu STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Automatski zamijeni sve brodove u spremištu STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Automatski zamijeni sve zrakoplove u hangaru STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}Nova vozila STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}Nova vozila STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}Novi brodovi STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}Novi zrakoplov STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Kupi novo željezničko vozilo STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Kupi novo cestovno vozilo STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Kupi novi brod STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Kupi novi zrakoplov STR_DEPOT_CLONE_TRAIN :{BLACK}Kloniraj vlak STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Kloniraj vozilo STR_DEPOT_CLONE_SHIP :{BLACK}Kloniraj brod STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Kloniraj zrakoplov STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}Ovo će kupiti kopiju vlaka uključujući sve vagone. Kliknite na ovaj gumb i onda na vlak unutar ili izvan spremišta. Ctrl+Klik će dijeliti naredbe. Shift+Klik prikazuje procijenjeni trošak bez kupnje. STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Ovo će kupiti kopiju cestovnog vozila. Klikni na ovaj gumb i onda na cestovno vozilo unutar ili izvan spremišta. CTRL+Klik će dijeliti naredbe. Shift+Klik prikazuje procijenjeni trošak bez kupnje. STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}Ovo će kupiti kopiju broda. Klikni na ovaj gumb i onda na brod unutar ili izvan spremišta. Ctrl+Klik će dijeliti naredbe. Shift+Klik prikazuje trošak bez kupnje. STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}Ovo će kupiti kopiju zrakoplova. Klikni ovaj gumb i onda na zrakoplov unutar ili izvan hangara. Control+Klik će dijeliti naredbe. Shift+Klik prikazuje trošak bez kupnje. STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju spremišta vlakova. Ctrl+klik otvara novi prozor s pogledom na lokaciju spremišta vlakova. STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju spremišta cestovnih vozila. Ctrl+klik otvara novi prozor s pogledom na lokaciju spremišta cestovnih vozila. STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju spremišta brodova. Ctrl+klik otvara novi prozor s pogledom na lokaciju spremišta brodova. STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centriraj glavni pogled na lokaciju hangara. Ctrl+klik otvara novi prozor s pogledom na lokaciju hangara. STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Daje popis svih vlakova koji imaju trenutno spremište među svojim naredbama STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Daje popis svih cestovnih vozila koje imaju trenutno spremište među svojim naredbama STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Daje popis svih brodova koji imaju trenutno spremište među svojim naredbama STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Daje popis svih zrakoplova koji imaju bilo koji hangar ove zračne luke među svojim naredbama STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Klikni za zaustavljanje svih vlakova u spremištu STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klikni za zaustavljanje svih cestovnih vozila u spremištu STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Klikni za zaustavljanje svih brodova u spremištu STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Klikni za zaustavljanje svih zrakoplova u hangaru STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Klikni za pokretanje svih vlakova u spremištu STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klikni za pokretanje svih cestovnih vozila u spremištu STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Klikni za pokretanje svih brodova u spremištu STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Klikni za pokretanje svih zrakoplova u hangaru STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Upravo se spremaš prodati sva vozila u spremištu. Jesi li siguran? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Poruka od proizvođača vozila STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Upravo smo dizajnirali novi {STRING} - jeste li zainteresirani za jednogodišnje ekskluzivno pravo uporabe ovog vozila, kako bi vidjeli kako se vozilo ponaša prije nego što postane univerzalno dostupno? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :željeznička lokomotiva STR_ENGINE_PREVIEW_ROAD_VEHICLE :cestovno vozilo STR_ENGINE_PREVIEW_AIRCRAFT :zrakoplov STR_ENGINE_PREVIEW_SHIP :brod STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :jednotračna željeznička lokomotiva STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev lokomotiva STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cijena: {CURRENCY_LONG} Težina: {WEIGHT_SHORT}{}Brzina: {VELOCITY} Snaga: {POWER}{}Trošak uporabe: {CURRENCY_LONG}/god{}Kapacitet: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Trošak: {CURRENCY_LONG} Težina: {WEIGHT_SHORT}{}Brzina: {VELOCITY} Snaga: {POWER} Maks. T.E.: {6:FORCE}{}Trošak uporabe: {4:CURRENCY_LONG}/god{}Nosivost: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Trošak: {CURRENCY_LONG} Maks. brzina: {VELOCITY}{}Nosivost: {CARGO_LONG}, {CARGO_LONG}{}Trošak uporabe: {CURRENCY_LONG}/god STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Trošak: {CURRENCY_LONG} Maks. brzina: {VELOCITY}{}Nosivost: {CARGO_LONG}{}Trošak uporabe: {CURRENCY_LONG}/god STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cijena: {CURRENCY_LONG} Maks. brzina: {VELOCITY} Domet: {COMMA} tiles{}Kapacitet: {CARGO_LONG}, {CARGO_LONG}{}Trošak vožnje: {CURRENCY_LONG}/god STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Cijena: {CURRENCY_LONG} Maks. Brzina: {VELOCITY} Domet: {COMMA} tiles{}Kapacitet: {CARGO_LONG}{}Trošak vožnje: {CURRENCY_LONG}/god # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}Zamijeni {STRING} - {STRING} STR_REPLACE_VEHICLE_TRAIN :Vlak STR_REPLACE_VEHICLE_ROAD_VEHICLE :Cestovno vozilo STR_REPLACE_VEHICLE_SHIP :Brod STR_REPLACE_VEHICLE_AIRCRAFT :Zrakoplov STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Vozila u uporabi STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP :{BLACK}Stupac s vozilima koje posjedujete STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Dostupna vozila STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP :{BLACK}Stupac sa vozilima dostupnim za zamjenjivanje STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Izaberi vrstu motora koju želiš zamijeniti STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Odaberite novu vrstu lokomotive koji želite koristiti umjesto lijevo odabrane vrste lokomotive STR_REPLACE_VEHICLES_START :{BLACK}Počni zamijenjivati vozila STR_REPLACE_VEHICLES_NOW :Zamijeni sva vozila sada STR_REPLACE_VEHICLES_WHEN_OLD :Zamijeni samo stara vozila STR_REPLACE_HELP_START_BUTTON :{BLACK}Klikni za početak zamjene lijevo odabrane lokomotive sa desno odabranom vrstom STR_REPLACE_NOT_REPLACING :{BLACK}Ne zamijenjujem STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Niti jedno vozilo nije odabrano STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} kada je staro STR_REPLACE_VEHICLES_STOP :{BLACK}Prestani zamijenjivati vozila STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Klikni za zaustavljanje zamjene lijevo odabrane vrste lokomotive STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Zamjenjujem:{ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Prebaci između prozora za izmjenu lokomotiva i vagona STR_REPLACE_ENGINES :Lokomotive STR_REPLACE_WAGONS :Vagoni STR_REPLACE_HELP_RAILTYPE :{BLACK}Odaberite vrstu željeznice za koju želite zamijeniti lokomotive STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Prikazuje sa kojom se lokomotivom zamjenjuje lijevo odabrana lokomotiva, ako postoji koji STR_REPLACE_RAIL_VEHICLES :Pružna vozila STR_REPLACE_ELRAIL_VEHICLES :Električna pružna vozila STR_REPLACE_MONORAIL_VEHICLES :Jednotračna vozila STR_REPLACE_MAGLEV_VEHICLES :Željeznička vozila Maglev STR_REPLACE_REMOVE_WAGON :{BLACK}Uklanjanje vagona: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Automatska zamjena zadržava istu dužinu vlaka tako da ukloni suvišne vagone (počevši od naprijed), ako bi zamjena lokomotive učinila vlak dužim # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Centriranje glavnog prozora na lokaciju vlaka. Ctrl+klik slijedi vlak u glavni prozor STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centriranje glavnog prozora na lokaciju vozila. Ctrl+klik slijedi vozilo u glavni prozor STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Centriranje glavnog prozora na lokaciju broda. Ctrl+klik slijedi brod u glavni prozor STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centriranje glavnog prozora na lokaciju zrakoplova. Ctrl+klik slijedi zrakoplov u glavni prozor STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošalji vlak u spremište. CTRL+klik će samo servisirati STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošalji vozilo u spremište. Ctrl+klik će samo servisirati STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošalji brod u spremište. Ctrl+klik će samo servisirati STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošalji zrakoplov u hangar. Ctrl+klik će samo servisirati STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Ovo će kupiti kopiju vlaka uključujući sve vagone. Control+Klik će dijeliti naredbe. Shift+Klik prikazuje trošak bez kupnje. STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Ovo će kupiti kopiju cestovnog vozila. Control+Klik će dijeliti naredbe. Shift+Klik prikazuje trošak bez kupnje. STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Ovo će kupiti kopiju broda. Control+Klik će dijeliti naredbe. Shift+Klik prikazuje trošak bez kupnje. STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Ovo će kupiti kopiju zrakoplova. Control+Klik će dijeliti naredbe. Shift+Klik prikazuje trošak bez kupnje. STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Natjeraj vlak da nastavi bez čekanja signala odobrenja STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Prenamijeni vlak za prijevoz neke druge vrste tereta STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Prenamijeni cestovno vozilo za prijevoz neke druge vrste tereta STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Prenamijeni teretni brod za prijevoz neke druge vrste tereta STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Prenamijeni zrakoplov za prijevoz neke druge vrste tereta STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Promijeni smjer vlaka STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Natjeraj vozila da se okrene natrag STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Pokaži naredbe vlaka. Ctrl+klik za prikazivanje voznog reda vlaka STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Pokaži naredbe vozila. Ctrl+klik za prikazivanje voznog reda vozila STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Pokaži naredbe broda. Ctrl+klik za prikazivanje voznog reda broda STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Pokaži naredbe zrakoplova. Ctrl+klik za prikazivanje voznog reda zrakoplova STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Pokaži detalje vlaka STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Pokaži detalje cestovnog vozila STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Pokaži detalje broda STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Pokaži detalje zrakoplova STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Trenutna radnja vlaka - pritisni za zaustavljanje/pokretanje vlaka. Ctrl+klik za odlazak do odredišta. STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Trenutna radnja vozila - pritisni za zaustavljanje/pokretanje vozila. Ctlr+klik za odlazak do odredišta. STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Trenutna radnja broda - pritisni za zaustavljanje/pokretanje broda. Ctrl+klik za odlazak do odredišta. STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Trenutna radnja zrakoplova - pritisni za zaustavljanje/pokretanje zrakoplova. Ctrl+klik za odlazak do odredišta. # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Utovar / Istovar STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Odlazeći STR_VEHICLE_STATUS_CRASHED :{RED}Slupan! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Pokvareno STR_VEHICLE_STATUS_STOPPED :{RED}Zaustavljen STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Zaustavljam, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}Nema struje STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Čekanje slobodne putanje STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Predaleko do sljedećeg odredišta STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Kreće se prema {STATION}, {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}Nema naredbi, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Ide prema {WAYPOINT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Na putu za {DEPOT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Servis u {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Zaustavljen STR_VEHICLE_COMMAND_STOPPED :{RED}Zaustavljen STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Pokrenut STR_VEHICLE_COMMAND_STARTED :{GREEN}Pokrenut # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Detalji) STR_VEHICLE_NAME_BUTTON :{BLACK}Ime STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Imenuj vlak STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Imenuj cestovno vozilo STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Imenuj brod STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Imenuj zrakoplov STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Godine: {LTBLUE}{STRING}{BLACK} Trošak uporabe: {LTBLUE}{CURRENCY_LONG}/god # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} godin{P a e a} ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} godin{P a e a} ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Maks. brzina: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Maks. brzina: {LTBLUE}{VELOCITY} {BLACK}Domet: {LTBLUE}{COMMA} polja STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Težina: {LTBLUE}{WEIGHT_SHORT} {BLACK}Snaga: {LTBLUE}{POWER}{BLACK} Maks. brzina: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Težina: {LTBLUE}{WEIGHT_SHORT} {BLACK}Snaga: {LTBLUE}{POWER}{BLACK} Maks. brzina: {LTBLUE}{VELOCITY} {BLACK}Maks. T.E.: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Dobit ove godine: {LTBLUE}{CURRENCY_LONG} (prošle godine: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Pouzdanost: {LTBLUE}{COMMA}% {BLACK}Broj kvarova od posljednjeg servisa: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Izgrađen: {LTBLUE}{NUM}{BLACK} Vrijednost: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Nosivost: {LTBLUE}Ništa{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Nosivost: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Nosivost: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Nosivost: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Prebaci novac: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Servisni interval: {LTBLUE}{COMMA}{NBSP}dana{BLACK} Zadnji servis: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Servisni interval: {LTBLUE}{COMMA}%{BLACK} Zadnji servis: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Povećaj servisni interval za 10. Ctrl+klik povećava servisni interval za 5. STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Smanji servisni interval za 10. Ctrl+klik smanjuje servisni interval za 5. STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Izmijeni vrstu servisnog intervala STR_VEHICLE_DETAILS_DEFAULT :Osnovno STR_VEHICLE_DETAILS_DAYS :Dani STR_VEHICLE_DETAILS_PERCENT :Postotak STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Imenuj vlak STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Imenuj cestovno vozilo STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Imenuj brod STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Imenuj zrakoplov # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Izgrađen: {LTBLUE}{NUM}{BLACK} Vrijednost: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Vrijednost: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Ukupna nosivost tereta ovog vlaka: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Prazan STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} iz {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} iz {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Teret STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Pokaži detalje tereta koji se prevozi STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Informacije STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Pokaži detalje vagona STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Nosivosti STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Pokaži nosivosti svakog vagona STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Ukupni teret STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Pokaži ukupnu nosivost vlaka podijeljenu prema vrsti tereta STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Nosivost: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Prenamijeni) STR_REFIT_TITLE :{GOLD}Odaberi vrstu tereta za prijevoz: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nova nosivost: {GOLD}{CARGO_LONG}{}{BLACK}Cijena prenamjene: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}Novi kapacitet: {GOLD}{CARGO_LONG}{}{BLACK}Prihod od remonta: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Novi kapacitet: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Trošak remonta: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}Novi kapacitet: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Prihod od remonta: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Odaberi vozila za remont. Povlačenje mišem dopušta odabir više vozila. Klik na prazninu će označiti cijelo vozilo. Ctrl+Klik će označiti vozilo i niz koji slijedi. STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Odaberi vrstu tereta koju će vlak prevoziti STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Odaberi vrstu tereta koje će cestovno vozilo prevoziti STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Odaberi vrstu tereta za prijevoz brodom STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Odaberi vrstu tereta koju će zrakoplov prevoziti STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Prenamijeni vlak STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Prenamijeni cestovno vozilo STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Prenamijeni brod STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Prenamijeni zrakoplov STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Prenamijeni vlak za prijevoz označene vrste tereta STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Prenamijeni cestovno vozilo za prijevoz označene vrste tereta STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Prenamijeni brod za prijevoz označene vrste tereta STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Prenamijeni zrakoplov za prijevoz označene vrste tereta # Order view STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Naredbe) STR_ORDERS_TIMETABLE_VIEW :{BLACK}Vozni red STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Promijeni na pogled voznog reda STR_ORDERS_LIST_TOOLTIP :{BLACK}Lista naredbi - klikni na naredbu kako bi je označio. Ctrl+Klik klizi na odredište naredbe STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - Kraj naredbi - - STR_ORDERS_END_OF_SHARED_ORDERS :- - Kraj dijeljenih naredbi - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}Neprekidno STR_ORDER_GO_TO :Idi prema STR_ORDER_GO_NON_STOP_TO :Idi neprekidno prema STR_ORDER_GO_VIA :Idi preko STR_ORDER_GO_NON_STOP_VIA :Idi neprekidno preko STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Promijeni zaustavno ponašanje označene naredbe STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Puni ukrcaj bilo kojeg tereta STR_ORDER_DROP_LOAD_IF_POSSIBLE :Ukrcaj ako je dostupno STR_ORDER_DROP_FULL_LOAD_ALL :Puni ukrcaj svega tereta STR_ORDER_DROP_FULL_LOAD_ANY :Puni ukrcaj bilo kojeg tereta STR_ORDER_DROP_NO_LOADING :Nema iskrcaja STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Promijeni ukrcajno ponašanje označene naredbe STR_ORDER_TOGGLE_UNLOAD :{BLACK}Iskrcaj sve STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Iskrcaj ako je prihvaćeno STR_ORDER_DROP_UNLOAD :Iskrcaj sve STR_ORDER_DROP_TRANSFER :Transferiraj STR_ORDER_DROP_NO_UNLOADING :Nema iskrcaja STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Promijeni iskrcajno ponašanje označene naredbe STR_ORDER_REFIT :{BLACK}Prenamijeni STR_ORDER_REFIT_TOOLTIP :{BLACK}Odaberi vrstu tereta za prenamijenu u ovoj naredbi. Ctrl+klik kako bi uklonio naputak za prenamjenu STR_ORDER_REFIT_AUTO :{BLACK}Auto-remont na postaji STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Odaberi za koji tip tereta odraditi auto-remont. Ctrl+Click za micanje remontnih uputa. Auto-remont će se odraditi samo ako ga vozilo dopušta. STR_ORDER_DROP_REFIT_AUTO :Popravljen teret STR_ORDER_DROP_REFIT_AUTO_ANY :Dostupni teret STR_ORDER_SERVICE :{BLACK}Servis STR_ORDER_DROP_GO_ALWAYS_DEPOT :Idi neprekidno STR_ORDER_DROP_SERVICE_DEPOT :Servisiraj prema potrebi STR_ORDER_DROP_HALT_DEPOT :Stani STR_ORDER_SERVICE_TOOLTIP :{BLACK}Preskoči ovu narudžbu osim ako servis nije potreban STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Podaci vozila prema kojima se zasniva skok # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Postotak ukrcaja STR_ORDER_CONDITIONAL_RELIABILITY :Pouzdanost STR_ORDER_CONDITIONAL_MAX_SPEED :Maksimalna brzina STR_ORDER_CONDITIONAL_AGE :Starost vozila (godine) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Treba servis STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Uvijek STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Preostali životni vijek (godina) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Kako usporediti podatke vozila sa zadanom vrijednošću STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :je jednako STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :nije jednako STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :je manje od STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :je manje ili jednako STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :je više od STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :je više ili jednako STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :je istinito STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :je lažno STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}Vrijednost s kojim se uspoređuju podaci vozila STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Unesi vrijednost s kojom će se porediti STR_ORDERS_SKIP_BUTTON :{BLACK}Preskoči STR_ORDERS_SKIP_TOOLTIP :{BLACK}Preskoči trenutnu naredbu i pokreni slijedeću. CTRL + klik preskače na odabranu naredbu STR_ORDERS_DELETE_BUTTON :{BLACK}Obriši STR_ORDERS_DELETE_TOOLTIP :{BLACK}Obriši označenu naredbu STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Izbriši sve naredbe STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Prekini dijeljenje STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Prekini dijeljenje liste naredbi. Ctrl+Klik dodatno briše sve naredbe za ovo vozilo STR_ORDERS_GO_TO_BUTTON :{BLACK}Idi do STR_ORDER_GO_TO_NEAREST_DEPOT :Idi do najbližeg spremišta STR_ORDER_GO_TO_NEAREST_HANGAR :Idi do najbližeg hangara STR_ORDER_CONDITIONAL :Uvjetovani skok na naredbu STR_ORDER_SHARE :Dijeli naredbe STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Umetni novu naredbu prije označene naredbe, ili dodaj na kraj liste. Ctrl određuje naredbe postaje 'napuni do kraja bilo koji teret', naredbe prolaznih točki 'non-stop', a naredbe spremišta 'servisiraj'. 'Dijeli naredbe' ili Ctrl dopušta da ovo vozilo dijeli naredbe s odabranim vozilom. Klik na vozilo kopira naredbe tog vozila. Naredba spremišta isključuje automatsko servisiranje vozila. STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Pokaži sva vozila koja dijele ovaj raspored. # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Idi preko {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Idi neprekidno preko čvorišta {WAYPOINT} STR_ORDER_SERVICE_AT :Servisiraj kod STR_ORDER_SERVICE_NON_STOP_AT :Servisiraj neprekidno kod STR_ORDER_NEAREST_DEPOT :najbliži STR_ORDER_NEAREST_HANGAR :najbliži hangar STR_ORDER_TRAIN_DEPOT :Spremište vlakova STR_ORDER_ROAD_VEHICLE_DEPOT :Spremište cestovnih vozila STR_ORDER_SHIP_DEPOT :Spremište brodova STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(Prenamijeni u {STRING}) STR_ORDER_REFIT_STOP_ORDER :(Prenamijeni u {STRING} i zaustavi se) STR_ORDER_STOP_ORDER :(Stani) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(Implicitno) STR_ORDER_FULL_LOAD :(Puni ukrcaj) STR_ORDER_FULL_LOAD_ANY :(Puni ukrcaj bilo kojeg tereta) STR_ORDER_NO_LOAD :(Nema ukrcaja) STR_ORDER_UNLOAD :(Iskrcaj i preuzmi teret) STR_ORDER_UNLOAD_FULL_LOAD :(Iskrcaj i čekaj puni ukrcaj) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Iskrcaj i čekaj bilo koji puni ukrcaj) STR_ORDER_UNLOAD_NO_LOAD :(Iskcraj i otiđi prazan) STR_ORDER_TRANSFER :(Transferiraj i preuzmi teret) STR_ORDER_TRANSFER_FULL_LOAD :(Transferiraj i čekaj puni ukrcaj) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transferiraj i čekaj na bilo koji puni ukrcaj) STR_ORDER_TRANSFER_NO_LOAD :(Transferiraj i otiđi prazan) STR_ORDER_NO_UNLOAD :(Preuzmi teret bez iskrcavanja) STR_ORDER_NO_UNLOAD_FULL_LOAD :(Čekaj puni ukrcaj bez iskrcavanja) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Čekaj bilo koji puni ukrcaj bez iskrcavanja) STR_ORDER_NO_UNLOAD_NO_LOAD :(Bez iskrcaja i bez ukrcaja) STR_ORDER_AUTO_REFIT :(Auto-remont u {STRING}) STR_ORDER_FULL_LOAD_REFIT :(Preuzimanje punog tereta sa auto-remontom u {STRING}) STR_ORDER_FULL_LOAD_ANY_REFIT :(Preuzimanje bilo kojeg punog tereta sa auto-remontom u {STRING}) STR_ORDER_UNLOAD_REFIT :(Iskrcaj i preuzimanje tereta sa auto-remontom u {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Iskrcaj i čekanje punog tereta sa auto-remontom u {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Iskrcaj i čekanje bilo kojeg punog tereta sa auto-remontom u {STRING}) STR_ORDER_TRANSFER_REFIT :(Transfer i preuzimanje tereta sa auto-remontom u {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transfer i čekanje punog tereta sa auto-remontom u {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transfer i čekanje bilo kojeg punog tereta sa auto-remontom u {STRING}) STR_ORDER_NO_UNLOAD_REFIT :(Bez iskrcaja i preuzimanje tereta sa auto-remontom u {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Bez iskrcaja i čekanje punog tereta sa auto-remontom u {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Bez iskrcaja i čekanje bilo kojeg punog tereta sa auto-remontom u {STRING}) STR_ORDER_AUTO_REFIT_ANY :dostupan teret STR_ORDER_STOP_LOCATION_NEAR_END :[početak] STR_ORDER_STOP_LOCATION_MIDDLE :[sredina] STR_ORDER_STOP_LOCATION_FAR_END :[kraj] STR_ORDER_OUT_OF_RANGE :{RED} (Sljedeća destinacija je izvan dometa) STR_ORDER_CONDITIONAL_UNCONDITIONAL :Skočin na naredbu {COMMA} STR_ORDER_CONDITIONAL_NUM :Skoči na naredbu {COMMA} kada {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :Skoči na naredbu {COMMA} kada {STRING} {STRING} STR_INVALID_ORDER :{RED} (Neispravna naredba) # Time table window STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Vozni red) STR_TIMETABLE_ORDER_VIEW :{BLACK}Naredbe STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Promijeni na pregled naredbi STR_TIMETABLE_TOOLTIP :{BLACK}Vozni red - klikni na naredbu kako bi ju označio. STR_TIMETABLE_NO_TRAVEL :Nema putovanja STR_TIMETABLE_NOT_TIMETABLEABLE :Putovanje (automatsko; prema rasporedu sljedeće ručno određene naredbe) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Putovanje (izvan voznog reda) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Putovanje (nije mjereno) uz najviše {2:VELOCITY} STR_TIMETABLE_TRAVEL_FOR :Putovanje za {STRING} STR_TIMETABLE_TRAVEL_FOR_SPEED :Putuj prema {STRING} uz najviše {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Putovanje (za {STRING}, nije mjereno) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Putovanje (za {STRING}, nije mjereno) sa najviše {VELOCITY} STR_TIMETABLE_STAY_FOR_ESTIMATED :(stajanje za {STRING}, nije mjereno) STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(putovanje za {STRING}, nije mjereno) STR_TIMETABLE_STAY_FOR :i boravak za {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :i putovanje za {STRING} STR_TIMETABLE_DAYS :{COMMA}{NBSP}dan{P "" a a} STR_TIMETABLE_TICKS :{COMMA}{NBSP}otkucaj{P "" a a} STR_TIMETABLE_TOTAL_TIME :{BLACK}Ovaj vozni red trebat će {STRING} za završetak STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}Ovaj vozni red trebat će najmanje {STRING} za završetak (nije sve raspoređeno) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}Ovo vozilo trenutno vozi na vrijeme STR_TIMETABLE_STATUS_LATE :{BLACK}Ovo vozilo trenutno {STRING} kasni STR_TIMETABLE_STATUS_EARLY :{BLACK}Ovo vozilo trenutno stiže {STRING} ranije STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}Ovaj vozni red još nije započeo STR_TIMETABLE_STATUS_START_AT :{BLACK}Ovaj će vozni red početi u {STRING} STR_TIMETABLE_STARTING_DATE :{BLACK}Početni datum STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Odaberi datum za početak ovog voznog reda. Ctrl+Klik odabire početnu točku ovog voznog reda i ravnomjerno raspodjeljuje sva vozila koja dijele ovu naredbu prema njihovoj relativnoj naredbi, ako je raspored naredbe potpuno određen STR_TIMETABLE_CHANGE_TIME :{BLACK}Promijeni vrijeme STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Promijeni količinu vremena koju bi označena naredba trebala uzeti STR_TIMETABLE_CLEAR_TIME :{BLACK}Obriši vrijeme STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Obriši vrijeme potrebno za označenu naredbu STR_TIMETABLE_CHANGE_SPEED :{BLACK}Izmijeni limit brzine STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Izmijeni maksimalnu putnu brzinu za označenu naredbu STR_TIMETABLE_CLEAR_SPEED :{BLACK}Izbriši limit brzine STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Izbriši maksimalnu putnu brzinu za označenu naredbu STR_TIMETABLE_RESET_LATENESS :{BLACK}Poništi brojač kašnjenja STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Resetiraj brojač kašnjenja, kako bi vozilo stiglo na vrijeme STR_TIMETABLE_AUTOFILL :{BLACK}Automatsko punjenje STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Automatski popuni vozni red s vrijednostima iz sljedećeg putovanja (Ctrl+klik kako bi pokušali zadržati vremena čekanja) STR_TIMETABLE_EXPECTED :{BLACK}Očekivano STR_TIMETABLE_SCHEDULED :{BLACK}Raspoređeno STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Promijeni između očekivanog i zadanog STR_TIMETABLE_ARRIVAL_ABBREVIATION :D: STR_TIMETABLE_DEPARTURE_ABBREVIATION :O: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}Odredi datum STR_DATE_SET_DATE :{BLACK}Odredi datum STR_DATE_SET_DATE_TOOLTIP :{BLACK}Upotrijebi odabrani datum kao početni datum za vozni red STR_DATE_DAY_TOOLTIP :{BLACK}Odaberi dan STR_DATE_MONTH_TOOLTIP :{BLACK}Odaberi mjesec STR_DATE_YEAR_TOOLTIP :{BLACK}Odaberi godinu # AI debug window STR_AI_DEBUG :{WHITE}Debugiranje UI-ja/Skripte igre STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Ime skripte STR_AI_DEBUG_SETTINGS :{BLACK}Postavke STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Promijeni postavke skripte STR_AI_DEBUG_RELOAD :{BLACK}Ponovno učitaj UI STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Ubij UI, ponovno učitaj skriptu i ponovno pokreni UI STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Uključi/isključi prekid kada neka UI poruka odgovara prekidnom nizu STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Prekid kod: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Prekid kod STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Kada zapis UI poruka odgovara ovom nizu, igra se pauzira. STR_AI_DEBUG_MATCH_CASE :{BLACK}Prilagodi veličinu slova STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Prilagodi veličinu slova kod uspoređivanja zapisa UI poruka sa prekidnim nizom STR_AI_DEBUG_CONTINUE :{BLACK}Nastavi STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Prekini pauzu i nastavi UI STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Pogledaj izvještaj otklanjanja neispravnosti za ovu UI STR_AI_GAME_SCRIPT :{BLACK}Skripta Igre STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Provjeri zapis Skripte Igre STR_ERROR_AI_NO_AI_FOUND :Nema prikladne UI za učitavanje.{}Ova UI je samo model i neće ništa učiniti.{}Možete preuzeti nekoliko umjetnih inteligencija pomoću sustava 'Online sadržaji'. STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}Jedna od pokrenutih skripti se srušila. Molimo vas da prijavite ovo autoru skripte sa slikom prozora za debugiranje UI-ja/Skripte igre. STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}Prozor za debugiranje UI-ja/Skripte igre je dopušten samo za poslužitelj # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}Konfiguracija UI-ja/Skripte igre STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}Skripta Igre koja će biti učitana u sljedećoj igri STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}UI-jevi koji će biti učitani u sljedećoj igri STR_AI_CONFIG_HUMAN_PLAYER :Ljudski igrač STR_AI_CONFIG_RANDOM_AI :Nasumična UI STR_AI_CONFIG_NONE :(nijedan) STR_AI_CONFIG_MOVE_UP :{BLACK}Pomakni gore STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Pomakni odabrani UI gore na listi STR_AI_CONFIG_MOVE_DOWN :{BLACK}Pomakni dolje STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Pomakni odabrani UI dolje na listi STR_AI_CONFIG_GAMESCRIPT :{SILVER}Skripta Igre STR_AI_CONFIG_AI :{SILVER}UI-jevi STR_AI_CONFIG_CHANGE :{BLACK}Odaberi {STRING} STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :UI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Skripta Igre STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Učitaj drugu skriptu STR_AI_CONFIG_CONFIGURE :{BLACK}Konfiguriraj STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Konfiguriraj parametre izabrane skripte # Available AIs window STR_AI_LIST_CAPTION :{WHITE}Dostupno {STRING} STR_AI_LIST_CAPTION_AI :UI-jevi STR_AI_LIST_CAPTION_GAMESCRIPT :Skripte Igre STR_AI_LIST_TOOLTIP :{BLACK}Klikni za izbor skripte STR_AI_LIST_AUTHOR :{LTBLUE}Autor: {ORANGE}{STRING} STR_AI_LIST_VERSION :{LTBLUE}Verzija: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{STRING} STR_AI_LIST_ACCEPT :{BLACK}Prihvati STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Odaberi posvijetljenu skriptu STR_AI_LIST_CANCEL :{BLACK}Odustani STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Nemoj mijenjati skriptu # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parametri STR_AI_SETTINGS_CAPTION_AI :UI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Skripta Igre STR_AI_SETTINGS_CLOSE :{BLACK}Zatvori STR_AI_SETTINGS_RESET :{BLACK}Resetiraj STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} STR_AI_SETTINGS_START_DELAY :Broj dana za start ovog UI-ja nakon prethodnog (otprilike): {ORANGE}{STRING} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} "pročitaj me" datoteka od {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} zapis izmjena od {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licenca od {STRING} STR_TEXTFILE_WRAP_TEXT :{WHITE}Posloži tekst STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Posloži tekst u prozorima tako da cijeli stane bez potrebe za skrolanjem STR_TEXTFILE_VIEW_README :{BLACK}Pogledaj "pročitaj me" datoteku STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Zapis izmjena STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenca # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Cijena: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}Cijena: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Prihod: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}Prihod: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Prebaci: {CURRENCY_LONG} STR_FEEDER :{YELLOW}Prebaci: {CURRENCY_LONG} STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Prihod: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Prihod: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Trošak: {CURRENCY_LONG} STR_FEEDER_COST :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Trošak: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Predviđena cijena: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Predviđeni prihod: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Spremanje još u tijeku,{}molimo pričekajte dok se ne završi! STR_ERROR_AUTOSAVE_FAILED :{WHITE}Automatsko spremanje neuspješno STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Ne mogu pročitati disk STR_ERROR_GAME_SAVE_FAILED :{WHITE}Spremanje igre nije uspjelo{}{STRING} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Ne mogu obrisati datoteku STR_ERROR_GAME_LOAD_FAILED :{WHITE}Učitavanje igre nije uspjelo{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Interna greška: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Pokvarena spremljena igra - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Spremljena igra je stvorena s novijom verzijom STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Datoteka nije čitljiva STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Ne mogu pisati u datoteku STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Provjera integriteta podataka nije uspjela STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Igra je bila spremljena u verziji bez podrške za tramvaje. Svi tramvaji su uklonjeni. # Map generation messages STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Generiranje mape prekinuto...{}... ne postoje pogodne lokacije za gradove STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... u ovom scenariju nema gradova STR_ERROR_PNGMAP :{WHITE}Nije moguće učitati krajolik iz PNG-a... STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... datoteka nije pronađena. STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... ne mogu pretvoriti vrstu slike. Potrebna je 8 ili 24-bitna PNG slika. STR_ERROR_PNGMAP_MISC :{WHITE}... nešto je otišlo u krivom smjeru (vjerojatno je pokvarena datoteka) STR_ERROR_BMPMAP :{WHITE}Nije moguće učitati krajolik iz BMP-a... STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... ne mogu pretvoriti vrstu slike. STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... slika je prevelika STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Upozorenje o veličini STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Prekomjerna promjena veličine karte nije preporučena. Nastaviti sa kreiranjem? # Soundset messages STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Pronađen je samo sigurnosni zvučni sustav. Ako želite zvukove, instalirajte set zvukova kroz sustav za preuzimanje sadržaja. # Screenshot related messages STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Velika slika STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}Slika će imati rezoluciju od {COMMA} x {COMMA} piksela. Slikanje može potrajati. Da li želite nastaviti? STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Slika zaslona uspješno spremljena kao '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}Slika zaslona nije uspjela! # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Poruka STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Poruka od {STRING} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Izvan rubova karte STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Preblizu rubu karte STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Nedovoljno gotovine - potrebno je {CURRENCY_LONG} STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Potrebna ravna površina STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Zemlja nakošena u krivom smjeru STR_ERROR_CAN_T_DO_THIS :{WHITE}To nije moguće učiniti... STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Najprije je potrebno srušiti građevinu STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Nije moguće očistiti ovo područje... STR_ERROR_SITE_UNSUITABLE :{WHITE}... neprikladno mjesto STR_ERROR_ALREADY_BUILT :{WHITE}... već izgrađeno STR_ERROR_OWNED_BY :{WHITE}... u vlasništvu {STRING} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... područje je u vlasništvu druge tvrtke STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... dosegnut limit preobrazbe terena STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... dosegnut limit čišćenja polja STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... dosegnut limit sađenja drveća STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Ime mora biti jedinstveno STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} na putu STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Nije dopušteno za vrijeme pauze # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} lokalna samouprava odbija to dopustiti STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}Lokalna samouprava grada {TOWN}a odbija dopustiti izgradnju još jedne zračne luke u ovom gradu STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}{TOWN} ne dopušta izgradnju zračne luke zbog brige o buci STR_ERROR_BRIBE_FAILED :{WHITE}Vaš pokušaj podmićivanja je primijetio regionalni istražitelj # Levelling errors STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}Ovdje nije moguće povisiti zemlju... STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Ovdje nije moguće sniziti zemlju... STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Ovdje nije moguće sravniti zemlju... STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Iskopavanje bi oštetilo tunel STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}Već je na razini mora STR_ERROR_TOO_HIGH :{WHITE}Previsoko STR_ERROR_ALREADY_LEVELLED :{WHITE}... već je sravnjeno STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND :{WHITE}Nakon toga, most iznad toga bi bio previsok. # Company related errors STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Ime tvrtke nije moguće promijeniti... STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Nije moguće promijeniti ime direktora... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... najveći dopušteni zajam iznosi {CURRENCY_LONG} STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Nije moguće posuditi još više novaca... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... nema zajma za otplatu STR_ERROR_CURRENCY_REQUIRED :{WHITE}...{CURRENCY_LONG} potrebno STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Nije moguće otplatiti zajam... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Nije moguće dati novac koji je pozajmljen od banke... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Nije moguće kupiti tvrtku... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Nije moguće izgraditi sjedište tvrtke... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Nije moguće kupiti 25% udjela u ovoj tvrtci... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Nije moguće prodati 25% udjela u ovoj tvrtci... STR_ERROR_PROTECTED :{WHITE}Ova tvrtka još nije dovoljno stara da bi trgovala udjelima... # Town related errors STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Nije moguće graditi gradove STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Nije moguće preimenovati grad... STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Ovdje nije moguće izgraditi grad... STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Nemoguće proširiti grad... STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... preblizu rubu karte STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... preblizu drugome gradu STR_ERROR_TOO_MANY_TOWNS :{WHITE}... previše gradova STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... nema više mjesta na karti STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}Grad neće graditi ceste. Možete uključiti gradnju cesta putem Postavki->Okolina->Gradovi STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Cestovni radovi u tijeku STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Nije moguće izbrisati ovaj grad...{}Postaja ili spremište se pozivaju na grad ili polja u vlasništvu grada nije moguće ukloniti STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... nema odgovarajućeg mjesta za kip u središtu ovog grada # Industry related errors STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... previše industrija STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Nije moguće generirati industrije... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Ovdje nije moguće izgraditi {STRING}... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Ovdje nije moguće izgraditi ovu vrstu industrije... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... preblizu drugoj industriji STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... najprije je potrebno osnovati grad STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... dopušten je samo jedan po gradu STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{G=male}{WHITE}... može biti izgrađen samo u gradovima s najmanje 1.200 stanovnika STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... može biti izgrađen samo u predjelima kišnih šuma STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... može biti izgrađen samo u pustinjskim područjima STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... može biti izgrađen samo u gradovima (zamjenjujući kuće) STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... može biti izgrađen samo blizu središta gradova STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... može biti izgrađen samo u nizinskim područjima STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... može se postaviti samo blizu rubova karte STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... šume mogu biti posađene jedino iznad linije snijega STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... moguće graditi samo iznad razine snijega STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... moguće graditi samo ispod razine snijega STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Nije bilo odgovarajućih mjesta za '{STRING}' industrije STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Izmijenite parametre za generaciju mape kako bi dobili bolju mapu # Station construction related errors STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Ovdje nije moguće izgraditi željezničku postaju... STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Nije moguće izgraditi autobusnu postaju... STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Nije moguće izgraditi kamionski terminal... STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Nije moguće izgraditi putničku tramvajsku postaju... STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Nije moguće izgraditi teretnu tramvajsku postaju... STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Ovdje nije moguće izgraditi pristanište... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Ovdje nije moguće izgraditi zračnu luku... STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Spaja više od jedne postojeće postaje/terminala STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... postaja previše proširena STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Previše postaja/terminala STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Previše dijelova željezničke postaje STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Previše autobusnih postaja STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Previše kamionskih postaja STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Preblizu drugoj postaji/terminalu STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Preblizu drugom pristaništu STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Preblizu drugoj zračnoj luci STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Nije moguće preimenovati postaju... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ovo je gradska cesta STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... cesta je orijentirana u krivom smjeru STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... prolazne postaje ne mogu imati zavoje STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... prolazne postaje ne mogu imati raskrižja # Station destruction related errors STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Nije moguće ukloniti dio postaje... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Najprije je potrebno ukloniti željezničku postaju STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Nije moguće ukloniti autobusnu postaju... STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Nije moguće ukloniti kamionsku postaju... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Nije moguće ukloniti putničku tramvajsku postaju... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Nije moguće ukloniti teretnu tramvajsku postaju... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Najprije je potrebno ukloniti cestovnu postaju STR_ERROR_THERE_IS_NO_STATION :{WHITE}... ovdje nema postaje STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Najprije je potrebno srušiti željezničku postaju STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Najprije je potrebno srušiti autobusnu postaju STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Najprije je potrebno srušiti kamionski terminal STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Najprije je potrebno srušiti putničku tramvajsku postaju STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Najprije je potrebno srušiti teretnu tramvajsku postaju STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Najprije je potrebno srušiti pristanište STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Najprije je potrebno srušiti zračnu luku # Waypoint related errors STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Pridružuje više od jednog postojećeg čvorišta. STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Preblizu drugom čvorištu STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Ovdje nije moguće izgraditi željezničko čvorište... STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Ovdje nije moguće staviti plutaču... STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Nije moguće promijeniti ime čvorišta... STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Nije moguće ukloniti željezničko čvorište odavde... STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Najprije je potrebno ukloniti željezničko čvorište STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... plutača na putu STR_ERROR_BUOY_IS_IN_USE :{WHITE}... plutača je u uporabi od strane druge tvrtke! # Depot related errors STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Ovdje nije moguće izgraditi spremište vlakova... STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Ovdje nije moguće izgraditi spremište cestovnih vozila... STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Ovdje nije moguće izgraditi tramvajsko spremište... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Ovdje nije moguće izgraditi spremište brodova... STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Nije moguće preimenovati spremište... STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... mora biti zaustavljen unutar spremišta STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... mora biti zaustavljen unutar spremišta cestovnih vozila STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... mora biti zaustavljen u spremištu STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... mora biti zaustavljen u hangaru STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Vlakovi mogu biti izmjenjeni jedino kad su zaustavljeni u spremištu STR_ERROR_TRAIN_TOO_LONG :{WHITE}Predugačak vlak STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Nije moguće promjeniti smjer vozila... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... sastoji se od više jedinica STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Nekompatibilna vrsta tračnica STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Nije moguće ukloniti vozilo... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}Stražnja lokomotiva će uvijek pratiti svog prednjeg dvojnika STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Ne može pronaći put do lokalnog spremišta STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Ne mogu pronaći lokalno spremište STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Pogrešna vrsta spremišta # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} je predugačko nakon zamjene STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Pravilo bez autozamjene/obnove je primjenjeno STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(novčano ograničenje) # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Nemoguća kombinacija tračnica STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Najprije je potrebno ukloniti signale STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nije prikladno za želježnicku prugu STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Najprije je potrebno ukloniti željezničku prugu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je jednosmjerna ili je blokirana STR_ERROR_CROSSING_DISALLOWED :{WHITE}Pružni prijelazi nisu dozvoljeni za ovu vrstu pruge STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Ovdje nije moguće postaviti signale... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Ovdje nije moguće izgraditi željezničke tračnice... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nije moguće ukloniti željezničku prugu odavde... STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Nije moguće ukloniti signale odavde... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Ovdje nije moguće pretvoriti signale... STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... nema pruge STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... nema signala STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Ovdje nije moguće pretvoriti vrstu pruge... # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Najprije je potrebno ukloniti cestu STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... jednosmjerne ceste ne mogu imati raskrižja STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Ovdje nije moguće izgraditi cestu... STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Ovdje nije moguće izgraditi tramvaj... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Nije moguće ukloniti cestu odavde... STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Nije moguće ukloniti tramvaj odavde... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... nema ceste STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... nema tramvajske pruge # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Ovdje nije moguće izgraditi kanale... STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Ovdje nije moguće izgraditi brane... STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Ovdje nije moguće postaviti rijeku... STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... mora biti izgrađen na vodi STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... nije moguće graditi na vodi STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... nemoguće graditi na otvorenom moru STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... nemoguće graditi na kanalu STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... nemoguće graditi na rijeci STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Najprije je potrebno srušiti kanal STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Ovdje nije moguće izgraditi akvadukt... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... ovdje već postoji drvo STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... pogrešan teren za tu vrstu drveća STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Ovdje nije moguće posaditi drvo... # Bridge related errors STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Ovdje nije moguće izgraditi most... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Najprije je potrebno srušiti most STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Početak i kraj ne mogu biti na istom mjestu STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Glave mosta nisu na istoj razini STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Most je prenizak za teren STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN :{WHITE}Most je previsok za ovaj teren. STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Početak i kraj moraju biti u ravnini STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... oba kraja mosta moraju biti na zemlji STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... predugačak most STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Most bi završio izvan mape # Tunnel related errors STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Ovdje nije moguće izgraditi tunel... STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Neprikladan teren za ulaz u tunel STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Najprije je potrebno srušiti tunel STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Smeta drugi tunel STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunel bi završio izvan karte STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Ne moguće iskopoati zemlju na drugoj strani tunela STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tunel predugačak # Object related errors STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... previše objekata STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Nemoguće izgraditi objekt... STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Smeta objekt STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... smeta sjedište tvrtke STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Ovu zemlju nije moguće kupiti... STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... već je u tvom vlasništvu! # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Nije moguće kreirati grupu... STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Nije moguće obrisati ovu grupu... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Nije moguće preimenovati ovu grupu... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Ne može se postaviti matična grupa... STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Nije moguće ukloniti sva vozila iz ove grupe... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Nije moguće dodati vozila u ovu grupu STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Nije moguće dodati dijeljena vozila u grupu... # Generic vehicle errors STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Vlak na putu STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Cestovno vozilo na putu STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Smeta brod STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Smeta zrakoplov STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Nije moguće prenamijeniti vlak... STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Nije moguće prenamijeniti cestovno vozilo... STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Nije moguće prenamijeniti brod... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Nije moguće prenamijeniti zrakoplov... STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Nije moguće imenovati vlak... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Nije moguće imenovati cestovno vozilo... STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Nije moguće imenovati brod... STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Nije moguće imenovati zrakoplov... STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Nije moguće zaustaviti/pokrenuti vlak... STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Nije moguće zaustaviti/pokrenuti cestovno vozilo... STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}Nije moguće pokrenuti/zaustaviti brod... STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Nije moguće zaustaviti/pokrenuti zrakoplov... STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Nije moguće poslati vlak u spremište... STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Nije moguće poslati vozilo u spremište... STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Nije moguće poslati brod u spremište... STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Nije moguće poslati zrakoplov u hangar STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Nije moguće kupiti željezničko vozilo... STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Nije moguće kupiti cestovno vozilo... STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Nije moguće kupiti brod... STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Nije moguće kupiti zrakoplov... STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Nije moguće preimenovati vrstu vagona... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Nije moguće preimenovati vrstu cestovnog vozila... STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Nije moguće preimenovati vrstu broda... STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Nije moguće preimenovati vrstu zrakoplova... STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Nije moguće prodati željezničko vozilo STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Nije moguće prodati cestovno vozilo... STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Nije moguće prodati brod... STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Nije moguće prodati zrakoplov... STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Vozilo nije dostupno STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Vozilo nije dostupno STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Brod nije dostupan STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Zrakoplov nije dostupan STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Previše vozila u igri STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Nije moguće promijeniti servisni interval... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... vozilo je uništeno STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Neće biti dostupno nijedno vozilo STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Promijenite konfiguraciju NewGRF-a STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Još nema dostupnih vozila STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Pokreni novu igru nakon {DATE_SHORT} ili upotrijebi NewGRF koji daje vrlo rana vozila # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nije moguće natjerati vlak da ignorira signale dok traje opasnost... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Nije moguće promijeniti smjer vlaka... STR_ERROR_TRAIN_START_NO_POWER :Vlak nema pogonske snage STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Nije moguće okrenuti vozilo na cesti... STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Zrakoplov je u letu # Order related errors STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Nema mjesta za nove naredbe STR_ERROR_TOO_MANY_ORDERS :{WHITE}Previše naredbi STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Nije moguće ubaciti novu naredbu... STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Nije moguće obrisati ovu naredbu... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Nije moguće izmijeniti ovu naredbu... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Nije moguće pomaknuti ovu naredbu... STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Nije moguće preskočiti trenutnu naredbu... STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Nije moguće skočiti na odabranu naredbu... STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... vozilo ne može doći do svih postaja STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... vozilo ne može doći do te postaje STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... vozilo koje dijeli ovu naredbu ne može doći do te postaje STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Nije moguće dijeliti popis naredbi... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Nemoguće prekinuti dijeljenje liste naredbi... STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Nije moguće kopirati popis naredbi... STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... predaleko od prethodnog odredišta STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... avion nema dovoljni domet # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Nije moguće zadati vozni red za vozilo... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vozila mogu čekati samo na postajama. STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Ovo vozilo se ne zaustavlja na ovoj postaji. # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... previše znakova STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Ovdje nije moguće postaviti znak... STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Nije moguće promijeniti ime znaka... STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Nije moguće obrisati znak... # Translatable comment for OpenTTD's desktop shortcut STR_DESKTOP_SHORTCUT_COMMENT :Simulacija na osnovi Transport Tycoon Deluxea # Translatable descriptions in media/baseset/*.ob* files STR_BASEGRAPHICS_DOS_DESCRIPTION :Originalna grafika za Transport Tycoon Deluxe DOS izdanje. STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Originalna grafika za Transport Tycoon Deluxe DOS (Njemački) izdanje. STR_BASEGRAPHICS_WIN_DESCRIPTION :Originalna grafika za Transport Tycoon Deluxe Windows izdanje. STR_BASESOUNDS_DOS_DESCRIPTION :Originalni zvukovi za Transport Tycoon Deluxe DOS izdanje. STR_BASESOUNDS_WIN_DESCRIPTION :Originalni zvukovi za Transport Tycoon Deluxe Windows izdanje. STR_BASESOUNDS_NONE_DESCRIPTION :Zvučni paket bez ikakvih zvukova. STR_BASEMUSIC_WIN_DESCRIPTION :Originalna muzika za Transport Tycoon Deluxe Windows izdanje. STR_BASEMUSIC_NONE_DESCRIPTION :Muzički paket bez ikakve muzike. ##id 0x2000 # Town building names STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Visoki uredski blok STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Uredski blok STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Mali stambeni blok STR_TOWN_BUILDING_NAME_CHURCH_1 :Crkva STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Veliki uredski blok STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Gradske kuće STR_TOWN_BUILDING_NAME_HOTEL_1 :Hotel STR_TOWN_BUILDING_NAME_STATUE_1 :Kip STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Fontana STR_TOWN_BUILDING_NAME_PARK_1 :Park STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Uredski blok STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Trgovine i uredi STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Moderne uredske zgrade STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Skladište STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Uredski blok STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadion STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Stare kuće STR_TOWN_BUILDING_NAME_COTTAGES_1 :Kolibe STR_TOWN_BUILDING_NAME_HOUSES_1 :Kuće STR_TOWN_BUILDING_NAME_FLATS_1 :Stanovi STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Visoki uredski blok STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Trgovine i uredi STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Trgovine i uredi STR_TOWN_BUILDING_NAME_THEATER_1 :Kazalište STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadion STR_TOWN_BUILDING_NAME_OFFICES_1 :Uredi STR_TOWN_BUILDING_NAME_HOUSES_2 :Kuće STR_TOWN_BUILDING_NAME_CINEMA_1 :Kino STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Trgovački centar STR_TOWN_BUILDING_NAME_IGLOO_1 :Iglu STR_TOWN_BUILDING_NAME_TEPEES_1 :Indijanski šator STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Čajnik za stanovanje STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Kasica-Prasica ##id 0x4800 # industry names STR_INDUSTRY_NAME_COAL_MINE :Rudnik ugljena STR_INDUSTRY_NAME_COAL_MINE.gen :rudnika ugljena STR_INDUSTRY_NAME_POWER_STATION :Elektrana STR_INDUSTRY_NAME_POWER_STATION.gen :elektrane STR_INDUSTRY_NAME_SAWMILL :Pilana STR_INDUSTRY_NAME_SAWMILL.gen :pilane STR_INDUSTRY_NAME_FOREST :Šuma STR_INDUSTRY_NAME_FOREST.gen :šume STR_INDUSTRY_NAME_OIL_REFINERY :Naftna rafinerija STR_INDUSTRY_NAME_OIL_REFINERY.gen :naftne rafinerije STR_INDUSTRY_NAME_OIL_RIG :Naftna bušotina STR_INDUSTRY_NAME_OIL_RIG.gen :naftne bušotine STR_INDUSTRY_NAME_FACTORY :Tvornica STR_INDUSTRY_NAME_FACTORY.gen :tvornice STR_INDUSTRY_NAME_PRINTING_WORKS :Tiskara STR_INDUSTRY_NAME_PRINTING_WORKS.gen :tiskare STR_INDUSTRY_NAME_STEEL_MILL :Čeličana STR_INDUSTRY_NAME_STEEL_MILL.gen :čeličane STR_INDUSTRY_NAME_FARM :Farma STR_INDUSTRY_NAME_FARM.gen :farme STR_INDUSTRY_NAME_COPPER_ORE_MINE :Rudnik bakra STR_INDUSTRY_NAME_COPPER_ORE_MINE.gen :rudnika bakra STR_INDUSTRY_NAME_OIL_WELLS :Naftna polja STR_INDUSTRY_NAME_OIL_WELLS.gen :naftnih polja STR_INDUSTRY_NAME_BANK :Banka STR_INDUSTRY_NAME_BANK.gen :banke STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Tvornica hrane STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT.gen :tvornice hrane STR_INDUSTRY_NAME_PAPER_MILL :Tvornica papira STR_INDUSTRY_NAME_PAPER_MILL.gen :tvornice papira STR_INDUSTRY_NAME_GOLD_MINE :Rudnik zlata STR_INDUSTRY_NAME_GOLD_MINE.gen :rudnika zlata STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Banka STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC.gen :banke STR_INDUSTRY_NAME_DIAMOND_MINE :Rudnik dijamanata STR_INDUSTRY_NAME_DIAMOND_MINE.gen :rudnika dijamanata STR_INDUSTRY_NAME_IRON_ORE_MINE :Rudnik željeza STR_INDUSTRY_NAME_IRON_ORE_MINE.gen :rudnika željeza STR_INDUSTRY_NAME_FRUIT_PLANTATION :Plantaža voća STR_INDUSTRY_NAME_FRUIT_PLANTATION.gen :plantaže voća STR_INDUSTRY_NAME_RUBBER_PLANTATION :Plantaža gume STR_INDUSTRY_NAME_RUBBER_PLANTATION.gen :plantaže gume STR_INDUSTRY_NAME_WATER_SUPPLY :Izvor vode STR_INDUSTRY_NAME_WATER_SUPPLY.gen :izvora vode STR_INDUSTRY_NAME_WATER_TOWER :Vodotoranj STR_INDUSTRY_NAME_WATER_TOWER.gen :vodotornja STR_INDUSTRY_NAME_FACTORY_2 :Tvornica STR_INDUSTRY_NAME_FACTORY_2.gen :tvornice STR_INDUSTRY_NAME_FARM_2 :Farma STR_INDUSTRY_NAME_FARM_2.gen :farme STR_INDUSTRY_NAME_LUMBER_MILL :Pilana STR_INDUSTRY_NAME_LUMBER_MILL.gen :pilane STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :Šuma šećerne vune STR_INDUSTRY_NAME_COTTON_CANDY_FOREST.gen :šume šećerne vune STR_INDUSTRY_NAME_CANDY_FACTORY :Tvornica slatkiša STR_INDUSTRY_NAME_CANDY_FACTORY.gen :tvornice slatkiša STR_INDUSTRY_NAME_BATTERY_FARM :Tvornica baterija STR_INDUSTRY_NAME_BATTERY_FARM.gen :tvornice baterija STR_INDUSTRY_NAME_COLA_WELLS :Izvori Cole STR_INDUSTRY_NAME_COLA_WELLS.gen :izvora cole STR_INDUSTRY_NAME_TOY_SHOP :Trgovina igračkama STR_INDUSTRY_NAME_TOY_SHOP.gen :trgovine igračkama STR_INDUSTRY_NAME_TOY_FACTORY :Tvornica igračaka STR_INDUSTRY_NAME_TOY_FACTORY.gen :tvornice igračaka STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :Izvori plastike STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS.gen :izvori plastike STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :Tvornica gaziranih pića STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY.gen :tvornice gaziranih pića STR_INDUSTRY_NAME_BUBBLE_GENERATOR :Generator balona STR_INDUSTRY_NAME_BUBBLE_GENERATOR.gen :generatora balona STR_INDUSTRY_NAME_TOFFEE_QUARRY :Iskop mliječne karamele STR_INDUSTRY_NAME_TOFFEE_QUARRY.gen :iskopa mliječne karamele STR_INDUSTRY_NAME_SUGAR_MINE :Rudnik šećera STR_INDUSTRY_NAME_SUGAR_MINE.gen :rudnika šećera ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Neimenovan STR_SV_TRAIN_NAME :Vlak {COMMA} STR_SV_ROAD_VEHICLE_NAME :Cestovno vozilo {COMMA} STR_SV_SHIP_NAME :Brod {COMMA} STR_SV_AIRCRAFT_NAME :Zrakoplov {COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :{STRING} Sjever STR_SV_STNAME_SOUTH :{STRING} Jug STR_SV_STNAME_EAST :{STRING} Istok STR_SV_STNAME_WEST :{STRING} Zapad STR_SV_STNAME_CENTRAL :Centrala {STRING} STR_SV_STNAME_TRANSFER :Transfer {STRING} STR_SV_STNAME_HALT :{STRING} Zaustav STR_SV_STNAME_VALLEY :{STRING} Dolina STR_SV_STNAME_HEIGHTS :Visine {STRING} STR_SV_STNAME_WOODS :{STRING} šume STR_SV_STNAME_LAKESIDE :Jezero {STRING} STR_SV_STNAME_EXCHANGE :Kolodvor {STRING} STR_SV_STNAME_AIRPORT :Zračna luka {STRING} STR_SV_STNAME_OILFIELD :Naftno polje {STRING} STR_SV_STNAME_MINES :Rudnici {STRING} STR_SV_STNAME_DOCKS :Pristaništa {STRING} STR_SV_STNAME_BUOY :{STRING} STR_SV_STNAME_WAYPOINT :{STRING} ##id 0x6020 STR_SV_STNAME_ANNEXE :Aneks {STRING} STR_SV_STNAME_SIDINGS :{STRING} Krak STR_SV_STNAME_BRANCH :Ogranak {STRING} STR_SV_STNAME_UPPER :Gornji {STRING} STR_SV_STNAME_LOWER :{STRING} donji STR_SV_STNAME_HELIPORT :Heliodrom {STRING} STR_SV_STNAME_FOREST :{STRING} šuma STR_SV_STNAME_FALLBACK :{STRING} Postaja #{NUM} ############ end of savegame specific region! ##id 0x8000 # Vehicle names STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (parni) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (parni) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (parni) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (parni) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (parni) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (Električni) STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Putnički vagon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Poštanski kombi STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Kamion za ugljen STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Naftna cisterna STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Kamion za domaće životinje STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Kamion za robu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Tegljač žita STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Kamion za drva STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Tegljač željeza STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Kamion za čelik STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Blindirani kombi STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Kombi za hranu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Kamion za papir STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Tegljač bakra STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Cisterna za vodu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Kamion za voće STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Kamion za gumu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Kamion za šećer STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Tegljač šećerne vune STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Tegljač mliječne karamele STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Kombi za balone STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Cisterna za colu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Kombi za slatkiše STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Kombi za igračke STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Kamion za baterije STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Kamion za gazirana pića STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Kamion za plastiku STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Putnički vagon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Poštanski kombi STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Kamion za ugljen STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Naftna cisterna STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Kamion za domaće životinje STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Kamion za robu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Tegljač žita STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Kamion za drva STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Tegljač željeza STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Kamion za čelik STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :Blindirani kombi STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Kamion za hranu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Kamion za papir STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Tegljač bakra STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Cisterna za vodu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Kamion za voće STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Kamion za gumu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Kamion za šećer STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Tegljač Šećerne vune STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Tegljač mliječne karamele STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Kombi za balone STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Cisterna za colu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Kombi za slatkiše STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Kombi za igračke STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Kamion za baterije STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Kamion za gazirana pića STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Kamion za plastiku STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Električni) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Putnički vagon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Poštanski kombi STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Kamion za ugljen STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Naftna cisterna STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Kamion za domaće životinje STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Kamion za robu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Tegljač žita STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Kamion za drva STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Tegljač željeza STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Kamion za čelik STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Blindirani kombi STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Kamion za hranu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Kamion za papir STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Tegljač bakra STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Cisterna za vodu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Kamion za voće STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Kamion za gumu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Kamion za šećer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Tegljač šećerne vune STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Tegljač mliječne karamele STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Kombi za balone STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Cisterna za colu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Kombi za slatkiše STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Kombi za igračke STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Kamion za baterije STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Kamion za gazirana pića STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Kamion za plastiku STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Bus STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Kamion za ugljen Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Kamion za ugljen Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :Kamion za ugljen DW STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :Poštanski kamion MPS STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Poštanski kamion Reynard STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Poštanski kamion Perry STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :Poštanski kamion MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Poštanski kamion Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Poštanski kamion Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Naftna cisterna Witcombe STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Naftna cisterna Foster STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Naftna cisterna Perry STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Kamion za domaće životinje Tallbot STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Kamion za domaće životinje Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Kamion za domaće životinje Foster STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Kamion za robu Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Kamion za robu Craighead STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Kamion za robu Goss STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Kamion za žitarice Hereford STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Kamion za žitarice Thomas STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Kamion za žitarice Goss STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Kamion za drva Witcombe STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Kamion za drva Foster STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Kamion za drva Moreland STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :Kamion za željeznu rudu MPS STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Kamion za željeznu rudu Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Kamion za željeznu rudu Chippy STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Kamion za čelik Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Kamion za čelik Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Kamion za čelik Kelling STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Blindirani kamion Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Blindirani kamion Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Blindirani kamion Foster STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Kamion za hranu Foster STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Kamion za hranu Perry STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Kamion za hranu Chippy STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Kamion za papir Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Kamion za papir Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :Kamion za papir MPS STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :Kamion za bakrenu rudu MPS STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Kamion za bakrenu rudu Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Kamion za bakrenu rudu Goss STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Cisterna za vodu Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Cisterna za vodu Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :Cisterna za vodu MPS STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Kamion za voće Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Kamion za voće Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kamion za voće Kelling STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Kamion za gumu Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Kamion za gumu Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :Kamion za gumu RMT STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :Kamion za šećer MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Kamion za šećer Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Kamion za šećer Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :Kamion za colu MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Kamion za colu Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Kamion za colu Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :Kamion za šećernu vatu MighyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Kamion za šećernu vatu Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Kamion za šećernu vatu Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :Kamion za mliječnu karamelu MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Kamion za mliječnu karamelu Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Kamion za mliječnu karamelu Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :Kamion za igračke MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Kamion za igračke Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Kamion za igračke Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :Kamion za slatkiše MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Kamion za slatkiše Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Kamion za slatkiše Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :Kamion za baterije MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Kamion za baterije Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Kamion za baterije Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :Kamion za gazirana pića MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Kamion za gazirana pića Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Kamion za gazirana pića Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :Kamion za plastiku MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Kamion za plastiku Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Kamion za plastiku Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :Kamion za balone MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Kamion za balone Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Kamion za balone Wizzowow STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :Naftna cisterna MPS STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :Naftna cisterna CS-Inc. STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :Putnički trajekt MPS STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :Putnički trajekt FFP STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Lebdjelica Bakewell 300 STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Putnički trajekt Chugger-Chug STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Putnički trajekt Shivershake STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Teretni brod Yate STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Teretni brod Bakewell STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :Teretni brod MightyMover STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Teretni brod Powernaut STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Helikopter Tricario STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Helikopter Guru X2 STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Helikopter Powernaut ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{STRING}-{STRING}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} STR_FORMAT_DATE_ISO :{2:NUM}-{1:STRING}-{0:STRING} STR_FORMAT_BUOY_NAME :{TOWN} Plutača STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Plutača #{COMMA} STR_FORMAT_COMPANY_NUM :(Tvrtka {COMMA}) STR_FORMAT_GROUP_NAME :Groupa {COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :Čvorište {TOWN} STR_FORMAT_WAYPOINT_NAME_SERIAL :Čvorište {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_TRAIN :{TOWN} Spremište vlakova STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :{TOWN} Spremište vlakova #{COMMA} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :{TOWN} Spremište cestovnih vozila STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :{TOWN} Spremište cestovnih vozila #{COMMA} STR_FORMAT_DEPOT_NAME_SHIP :{TOWN} Spremšte za brodove STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :{TOWN} Spremište brodova #{COMMA} STR_FORMAT_DEPOT_NAME_AIRCRAFT :{STATION} Hangar STR_UNKNOWN_STATION :nepoznata postaja STR_DEFAULT_SIGN_NAME :Znak STR_COMPANY_SOMEONE :netko STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING} STR_SAVEGAME_NAME_SPECTATOR :Gledatelj, {1:STRING} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} STR_VIEWPORT_WAYPOINT :{WAYPOINT} STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} STR_DEPOT_NAME :{DEPOT} STR_ENGINE_NAME :{ENGINE} STR_HIDDEN_ENGINE_NAME :{ENGINE} (sakriveno) STR_GROUP_NAME :{GROUP} STR_INDUSTRY_NAME :{INDUSTRY} STR_PRESIDENT_NAME :{PRESIDENT_NAME} STR_SIGN_NAME :{SIGN} STR_STATION_NAME :{STATION} STR_TOWN_NAME :{TOWN} STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} STR_JUST_DATE_LONG :{DATE_LONG} STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} # Slightly 'raw' stringcodes with colour or size STR_BLACK_COMMA :{BLACK}{COMMA} STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} STR_TINY_COMMA :{TINY_FONT}{COMMA} STR_BLUE_COMMA :{BLUE}{COMMA} STR_RED_COMMA :{RED}{COMMA} STR_WHITE_COMMA :{WHITE}{COMMA} STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} STR_TINY_GROUP :{TINY_FONT}{GROUP} STR_BLACK_INT :{BLACK}{NUM} STR_ORANGE_INT :{ORANGE}{NUM} STR_WHITE_SIGN :{WHITE}{SIGN} STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} STR_BLACK_STRING :{BLACK}{STRING} STR_BLACK_RAW_STRING :{BLACK}{STRING} STR_ORANGE_STRING :{ORANGE}{STRING} STR_LTBLUE_STRING :{LTBLUE}{STRING} STR_WHITE_STRING :{WHITE}{STRING} STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING}{WHITE} STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING}{LTBLUE} STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} STR_BLACK_1 :{BLACK}1 STR_BLACK_2 :{BLACK}2 STR_BLACK_3 :{BLACK}3 STR_BLACK_4 :{BLACK}4 STR_BLACK_5 :{BLACK}5 STR_BLACK_6 :{BLACK}6 STR_BLACK_7 :{BLACK}7 STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) openttd-1.5.3/src/lang/afrikaans.txt0000644000000000000000000151020712627373443016124 0ustar rootroot##name Afrikaans ##ownname Afrikaans ##isocode af_ZA ##plural 0 ##textdir ltr ##digitsep . ##digitsepcur . ##decimalsep , ##winlangid 0x0436 ##grflangid 0x1b ##gender male # $Id: afrikaans.txt 27353 2015-07-31 17:46:09Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(undefined string) STR_JUST_NOTHING :Niks # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :Passasiers STR_CARGO_PLURAL_COAL :Steenkool STR_CARGO_PLURAL_MAIL :Pos STR_CARGO_PLURAL_OIL :Olie STR_CARGO_PLURAL_LIVESTOCK :Lewendehawe STR_CARGO_PLURAL_GOODS :Goedere STR_CARGO_PLURAL_GRAIN :Graan STR_CARGO_PLURAL_WOOD :Hout STR_CARGO_PLURAL_IRON_ORE :Ystererts STR_CARGO_PLURAL_STEEL :Staal STR_CARGO_PLURAL_VALUABLES :Edelmetale STR_CARGO_PLURAL_COPPER_ORE :Koper Erts STR_CARGO_PLURAL_MAIZE :Mielies STR_CARGO_PLURAL_FRUIT :Vrugte STR_CARGO_PLURAL_DIAMONDS :Diamante STR_CARGO_PLURAL_FOOD :Kos STR_CARGO_PLURAL_PAPER :Papier STR_CARGO_PLURAL_GOLD :Goud STR_CARGO_PLURAL_WATER :Water STR_CARGO_PLURAL_WHEAT :Koring STR_CARGO_PLURAL_RUBBER :Rubber STR_CARGO_PLURAL_SUGAR :Suiker STR_CARGO_PLURAL_TOYS :Speelgoed STR_CARGO_PLURAL_CANDY :Lekkers STR_CARGO_PLURAL_COLA :Kola STR_CARGO_PLURAL_COTTON_CANDY :Spookasem STR_CARGO_PLURAL_BUBBLES :Borrels STR_CARGO_PLURAL_TOFFEE :Toffie STR_CARGO_PLURAL_BATTERIES :Batterye STR_CARGO_PLURAL_PLASTIC :Plastiek STR_CARGO_PLURAL_FIZZY_DRINKS :Gaskoeldrank # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :Passasier STR_CARGO_SINGULAR_COAL :Steenkool STR_CARGO_SINGULAR_MAIL :Pos STR_CARGO_SINGULAR_OIL :Olie STR_CARGO_SINGULAR_LIVESTOCK :Lewende Hawe STR_CARGO_SINGULAR_GOODS :Goedere STR_CARGO_SINGULAR_GRAIN :Graan STR_CARGO_SINGULAR_WOOD :Hout STR_CARGO_SINGULAR_IRON_ORE :Yster Erts STR_CARGO_SINGULAR_STEEL :Staal STR_CARGO_SINGULAR_VALUABLES :Edelmetale STR_CARGO_SINGULAR_COPPER_ORE :Koper Erts STR_CARGO_SINGULAR_MAIZE :Mielie STR_CARGO_SINGULAR_FRUIT :Vrug STR_CARGO_SINGULAR_DIAMOND :Diamant STR_CARGO_SINGULAR_FOOD :Kos STR_CARGO_SINGULAR_PAPER :Papier STR_CARGO_SINGULAR_GOLD :Goud STR_CARGO_SINGULAR_WATER :Water STR_CARGO_SINGULAR_WHEAT :Koring STR_CARGO_SINGULAR_RUBBER :Rubber STR_CARGO_SINGULAR_SUGAR :Suiker STR_CARGO_SINGULAR_TOY :Speelding STR_CARGO_SINGULAR_CANDY :Lekker STR_CARGO_SINGULAR_COLA :Kola STR_CARGO_SINGULAR_COTTON_CANDY :Spookasem STR_CARGO_SINGULAR_BUBBLE :Borrel STR_CARGO_SINGULAR_TOFFEE :Toffie STR_CARGO_SINGULAR_BATTERY :Battery STR_CARGO_SINGULAR_PLASTIC :Plastiek STR_CARGO_SINGULAR_FIZZY_DRINK :Gaskoeldrank # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA}{NBSP}passasier{P "" s} STR_QUANTITY_COAL :{WEIGHT_LONG} steenkool STR_QUANTITY_MAIL :{COMMA}{NBSP}sak{P "" ke} pos STR_QUANTITY_OIL :{VOLUME_LONG} olie STR_QUANTITY_LIVESTOCK :{COMMA}{NBSP}item{P "" s} lewendehawe STR_QUANTITY_GOODS :{COMMA}{NBSP}krat{P "" te} goedere STR_QUANTITY_GRAIN :{WEIGHT_LONG} graan STR_QUANTITY_WOOD :{WEIGHT_LONG} hout STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} ystererts STR_QUANTITY_STEEL :{WEIGHT_LONG} staal STR_QUANTITY_VALUABLES :{COMMA}{NBSP}sak{P "" ke} edelmetale STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} kopererts STR_QUANTITY_MAIZE :{WEIGHT_LONG} mielies STR_QUANTITY_FRUIT :{WEIGHT_LONG} vrugte STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}sak{P "" ke} diamante STR_QUANTITY_FOOD :{WEIGHT_LONG} kos STR_QUANTITY_PAPER :{WEIGHT_LONG} papier STR_QUANTITY_GOLD :{COMMA}{NBSP}sak{P "" ke} goud STR_QUANTITY_WATER :{VOLUME_LONG} water STR_QUANTITY_WHEAT :{WEIGHT_LONG} koring STR_QUANTITY_RUBBER :{VOLUME_LONG} rubber STR_QUANTITY_SUGAR :{WEIGHT_LONG} suiker STR_QUANTITY_TOYS :{COMMA}{NBSP}ton speelgoed STR_QUANTITY_SWEETS :{COMMA}{NBSP}sak{P "" ke} lekkers STR_QUANTITY_COLA :{VOLUME_LONG} kola STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} spookasem STR_QUANTITY_BUBBLES :{COMMA} borrel{P "" s} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} toffie {P "" s} STR_QUANTITY_BATTERIES :{COMMA} batter{P y ye} STR_QUANTITY_PLASTIC :{VOLUME_LONG} plastiek STR_QUANTITY_FIZZY_DRINKS :{COMMA} koeldran{P k ke} STR_QUANTITY_N_A :n.v.t. # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}PS STR_ABBREV_COAL :{TINY_FONT}SK STR_ABBREV_MAIL :{TINY_FONT}PS STR_ABBREV_OIL :{TINY_FONT}OL STR_ABBREV_LIVESTOCK :{TINY_FONT}LH STR_ABBREV_GOODS :{TINY_FONT}GD STR_ABBREV_GRAIN :{TINY_FONT}GR STR_ABBREV_WOOD :{TINY_FONT}HT STR_ABBREV_IRON_ORE :{TINY_FONT}YE STR_ABBREV_STEEL :{TINY_FONT}ST STR_ABBREV_VALUABLES :{TINY_FONT}EM STR_ABBREV_COPPER_ORE :{TINY_FONT}KE STR_ABBREV_MAIZE :{TINY_FONT}ML STR_ABBREV_FRUIT :{TINY_FONT}VR STR_ABBREV_DIAMONDS :{TINY_FONT}DM STR_ABBREV_FOOD :{TINY_FONT}KO STR_ABBREV_PAPER :{TINY_FONT}PR STR_ABBREV_GOLD :{TINY_FONT}GD STR_ABBREV_WATER :{TINY_FONT}WR STR_ABBREV_WHEAT :{TINY_FONT}KR STR_ABBREV_RUBBER :{TINY_FONT}RB STR_ABBREV_SUGAR :{TINY_FONT}SK STR_ABBREV_TOYS :{TINY_FONT}SG STR_ABBREV_SWEETS :{TINY_FONT}LE STR_ABBREV_COLA :{TINY_FONT}KL STR_ABBREV_CANDYFLOSS :{TINY_FONT}SA STR_ABBREV_BUBBLES :{TINY_FONT}BO STR_ABBREV_TOFFEE :{TINY_FONT}TF STR_ABBREV_BATTERIES :{TINY_FONT}BA STR_ABBREV_PLASTIC :{TINY_FONT}PL STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}GK STR_ABBREV_NONE :{TINY_FONT}NS STR_ABBREV_ALL :{TINY_FONT}ALMAL # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA}{NBSP}passasier{P "" s} STR_BAGS :{COMMA}{NBSP}sak{P "" ke} STR_TONS :{COMMA}{NBSP}ton STR_LITERS :{COMMA}{NBSP}liter STR_ITEMS :{COMMA}{NBSP}item{P "" s} STR_CRATES :{COMMA}{NBSP}krat{P "" te} # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Donkerblou STR_COLOUR_PALE_GREEN :Vaalgroen STR_COLOUR_PINK :Pienk STR_COLOUR_YELLOW :Geel STR_COLOUR_RED :Rooi STR_COLOUR_LIGHT_BLUE :Ligblou STR_COLOUR_GREEN :Groen STR_COLOUR_DARK_GREEN :Donkergroen STR_COLOUR_BLUE :Blou STR_COLOUR_CREAM :Room STR_COLOUR_MAUVE :Ligpers STR_COLOUR_PURPLE :Pers STR_COLOUR_ORANGE :Oranje STR_COLOUR_BROWN :Bruin STR_COLOUR_GREY :Grys STR_COLOUR_WHITE :Wit # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mpu STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}pk STR_UNITS_POWER_METRIC :{COMMA}{NBSP}pk STR_UNITS_POWER_SI :{COMMA}{NBSP}kW STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}{NBSP}kg STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA}{NBSP}ton STR_UNITS_WEIGHT_LONG_METRIC :{COMMA}{NBSP}ton STR_UNITS_WEIGHT_LONG_SI :{COMMA}{NBSP}kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}{NBSP}gelling STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}{NBSP}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}{NBSP}m³ STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA}{NBSP}gelling{P "" s} STR_UNITS_VOLUME_LONG_METRIC :{COMMA}{NBSP}liter STR_UNITS_VOLUME_LONG_SI :{COMMA}{NBSP}m³ STR_UNITS_FORCE_IMPERIAL :{COMMA}{NBSP}lbf STR_UNITS_FORCE_METRIC :{COMMA}{NBSP}kgf STR_UNITS_FORCE_SI :{COMMA}{NBSP}kN STR_UNITS_HEIGHT_IMPERIAL :{COMMA}{NBSP}vt STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Filter string: STR_LIST_FILTER_OSKTITLE :{BLACK}Sleutel filter string in STR_LIST_FILTER_TOOLTIP :{BLACK}Tik 'n sleutelwoord in om die lys te filter STR_TOOLTIP_GROUP_ORDER :{BLACK}Kies groepeervolgorde STR_TOOLTIP_SORT_ORDER :{BLACK}Kies hoe om te rangskik (dalende/stygende) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Kies kriterea om volgens te rangskik STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Kies kriteria om volgens te filter STR_BUTTON_SORT_BY :{BLACK}Sorteer volgens STR_BUTTON_LOCATION :{BLACK}Ligging STR_BUTTON_RENAME :{BLACK}Hernoem STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Maak venster toe STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Venster titel - sleep om venster te beweeg STR_TOOLTIP_SHADE :{BLACK}Versteek venster - wys slegs titel staaf STR_TOOLTIP_DEBUG :{BLACK}Vertoon NewGRF ontfout inligting STR_TOOLTIP_DEFSIZE :{BLACK}Verander venstergrootte na verstek grootte. Ctrl+klik om die huidge skermgrootte as verstek te stoor. STR_TOOLTIP_STICKY :{BLACK}Merk die venster as ontoemaakbaar met die"Sluit Alle Vensters" sleutel. Ctrl+klik om te stoor as verstek STR_TOOLTIP_RESIZE :{BLACK}Klik en sleep om venster te vergroot STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Skakel groot/klein venster groote STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Rolstaaf - rol die lys op/af STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Rolstaaf - rol die lys links/regs STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Vernietig geboue ens. op 'n vierkant van land # Show engines button STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Wys versteekte STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Wys weggesteekde STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP :{BLACK}Wys weggesteekde STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT :{BLACK}Wys weggesteekde STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP :{BLACK}Deur hierdie opsie te aktiveer, sal die weggesteekde treine ook vertoon word STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE_TOOLTIP :{BLACK}Deur hierdie opsie te aktiveer, sal die weggesteekde voertuie ook vertoon word STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP_TOOLTIP :{BLACK}Deur hierdie opsie te aktiveer, sal die weggesteekde skepe ook vertoon word STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Deur hierdie opsie te aktiveer, sal die weggesteekde vliegtuie ook vertoon word # Query window STR_BUTTON_DEFAULT :{BLACK}Gewone STR_BUTTON_CANCEL :{BLACK}Kanselleer STR_BUTTON_OK :{BLACK}OK # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}Lengte: {NUM} STR_MEASURE_AREA :{BLACK}Area: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Lengte: {NUM}{}Hoogte verskil: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Area: {NUM} x {NUM}{}Hoogte verskil: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}Naam STR_SORT_BY_CAPTION_DATE :{BLACK}Datum # These are used in dropdowns STR_SORT_BY_NAME :Naam STR_SORT_BY_PRODUCTION :Produksie STR_SORT_BY_TYPE :Tipe STR_SORT_BY_TRANSPORTED :Vervoer STR_SORT_BY_NUMBER :Nommer STR_SORT_BY_PROFIT_LAST_YEAR :Wins verlede jaar STR_SORT_BY_PROFIT_THIS_YEAR :Wins huidige jaar STR_SORT_BY_AGE :Ouderdom STR_SORT_BY_RELIABILITY :Betroubaarheid STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Totale kapasiteit per vragtipe STR_SORT_BY_MAX_SPEED :Maksimum spoed STR_SORT_BY_MODEL :Model STR_SORT_BY_VALUE :Waarde STR_SORT_BY_LENGTH :Lengte STR_SORT_BY_LIFE_TIME :Oorblywende leeftyd STR_SORT_BY_TIMETABLE_DELAY :Rooster vertraging STR_SORT_BY_FACILITY :Stasie tipe STR_SORT_BY_WAITING_TOTAL :Totale wagtende vrag STR_SORT_BY_WAITING_AVAILABLE :Beskikbare wagtende vrag STR_SORT_BY_RATING_MAX :Hoogste vraggradering STR_SORT_BY_RATING_MIN :Laagste vraggradering STR_SORT_BY_ENGINE_ID :EngineID (klassieke sorteer) STR_SORT_BY_COST :Koste STR_SORT_BY_POWER :Krag STR_SORT_BY_TRACTIVE_EFFORT :Trekker inspanning STR_SORT_BY_INTRO_DATE :Inleiding Datum STR_SORT_BY_RUNNING_COST :Loopkoste STR_SORT_BY_POWER_VS_RUNNING_COST :Krag/Loopkoste STR_SORT_BY_CARGO_CAPACITY :Vrag Kapasiteit STR_SORT_BY_RANGE :Afstand STR_SORT_BY_POPULATION :Bevolking STR_SORT_BY_RATING :Waardering # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Onderbreek spel STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Vinnig vooruit die spel STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Opsies STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Stoor spel, verlaat spel, verlaat STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Vertoon kaart, ekstra uitsig of lys van tekens STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Vertoon stad gids STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Toon subsidies STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Vertoon lys van maatskappy se stasies STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Vertoon maatskappy se finasiële inligting STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Vertoon algemene maatskappy inligting STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Toon storieboek STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Toon doellys STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Vertoon grafieke STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Vertoon maatskappy liga tabel STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Konsolideer konstruksie van nuwe nywerheid STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Vertoon maatskappy se treinlys. Ctrl+klik wissel die vertoning van die groep/voertuiglys STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Vertoon maatskappy se padvoertuiglys. Ctrl+klik wissel die vertoning van die groep/voertuiglys STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Vertoon maatskappy se skiplys. Ctrl+klik wissel die vertoning van die groep/voertuiglys STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Vertoon maatskappy se vliegtuiglys. Ctrl+klik wissel die vertoning van die groep/voertuiglys STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Vergroot die skerm STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Verklein die skerm STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Bou spoorweg spoor STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Bou paaie STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Bou skip hawe STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Bou lughawens STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Maak die landargitektuur nutsbalk oop om, land te verhoog/verlaag, boome beplant, ens. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Vertoon klank/musiek venster STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Vertoon laaste boodskap/nuus verslag, vertoon boodskap opsies STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Land gebied informasie, konsole, skrip ontfouting, skermkiekie, omtrent OpenTTD STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Skakel nutsbalke # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Stoor scenario, laai scenario, verlaat scenario redigeerder, verlaat STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Scenario Redigeerder STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Beweeg die begin datum 1 jaar terug STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Beweeg die begin datum 1 jaar voorentoe STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Klik om die beginjaar in te voer STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Vertoon kaart, dorp gids STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landskap generasie STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Dorp generasie STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Nywerheid generasie STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Pad konstruksie STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant bome. Shift skakel gebou/wys koste beraaming STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Plaas teken STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Plaas voorwerp. Shift skakel tussen bou/aanduiding koste beraming ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Stoor scenario STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Laai scenario STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Stoor reliëfkaart STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Laai reliëfkaart STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Verlaat redigeerder STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Verlaat ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :Spel opsies STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Stellings STR_SETTINGS_MENU_SCRIPT_SETTINGS :AI/Spel skript instellings STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF stellings STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Deursigtigheid opsies STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Dorp name vertoon STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Stasie name vertoon STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Vertoon roetebakens se name STR_SETTINGS_MENU_SIGNS_DISPLAYED :Tekens vertoon STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Vertoon mededinger tekens en name STR_SETTINGS_MENU_FULL_ANIMATION :Volle animasie STR_SETTINGS_MENU_FULL_DETAIL :Volle besonderhede STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Deurskynende geboue STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Deurskynende stasie tekens ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Stoor spel STR_FILE_MENU_LOAD_GAME :Laai spel STR_FILE_MENU_QUIT_GAME :Verlaat spel STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Verlaat ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :Kaart van wêreld STR_MAP_MENU_EXTRA_VIEW_PORT :Ekstra toonvenster STR_MAP_MENU_LINGRAPH_LEGEND :Vragverspreidingsleutel STR_MAP_MENU_SIGN_LIST :Teken lys ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Dorp gids STR_TOWN_MENU_FOUND_TOWN :Stig dorp ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :Subsidies ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Bedryfswins grafiek STR_GRAPH_MENU_INCOME_GRAPH :Inkomste grafiek STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Gelewerde vrag grafiek STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Werkverrigting geskiedenis grafiek STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Maatskappy waarde grafiek STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Vragbetalingstariewe ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Maatskappy verbond tabel STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Omstandig prestasie gradering STR_GRAPH_MENU_HIGHSCORE :Hoogste tellings tafel ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Nywerheid Gids STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Nywerheidsskakels STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Konsolideer nuwe nywerheid ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Spoorwegkonstruksie STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Elekriese spoorwegkonstruksie STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Monospoor konstruksie STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Magneetsweeftrein konstruksie ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Pad konstruksie STR_ROAD_MENU_TRAM_CONSTRUCTION :Tremweg konstruksie ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Waterweg konstruksie ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Lughawe konstruksie ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :Landargitektuur STR_LANDSCAPING_MENU_PLANT_TREES :Plant bome STR_LANDSCAPING_MENU_PLACE_SIGN :Plaas teken ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :Klank/musiek ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Laaste boodskap/nuus verslag STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Boodskapgeskiedenis ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Gebied informasie STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :Skakel terminaal STR_ABOUT_MENU_AI_DEBUG :AI/Spel skript ontfout STR_ABOUT_MENU_SCREENSHOT :Skermskoot STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Ten volle vergrote skermskoot STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Basiese groote skermskoot STR_ABOUT_MENU_GIANT_SCREENSHOT :Hele kaart Skermkiekie (Ctrl+G) STR_ABOUT_MENU_ABOUT_OPENTTD :Oor 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :"Sprite" rigter STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :skakel beperkte bokse STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Skakel inkleur van vuil blokke ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :1ste STR_ORDINAL_NUMBER_2ND :2de STR_ORDINAL_NUMBER_3RD :3de STR_ORDINAL_NUMBER_4TH :4de STR_ORDINAL_NUMBER_5TH :5de STR_ORDINAL_NUMBER_6TH :6de STR_ORDINAL_NUMBER_7TH :7de STR_ORDINAL_NUMBER_8TH :8ste STR_ORDINAL_NUMBER_9TH :9de STR_ORDINAL_NUMBER_10TH :10de STR_ORDINAL_NUMBER_11TH :11de STR_ORDINAL_NUMBER_12TH :12de STR_ORDINAL_NUMBER_13TH :13de STR_ORDINAL_NUMBER_14TH :14de STR_ORDINAL_NUMBER_15TH :15de ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :1ste STR_DAY_NUMBER_2ND :2de STR_DAY_NUMBER_3RD :3de STR_DAY_NUMBER_4TH :4de STR_DAY_NUMBER_5TH :5de STR_DAY_NUMBER_6TH :6de STR_DAY_NUMBER_7TH :7de STR_DAY_NUMBER_8TH :8ste STR_DAY_NUMBER_9TH :9de STR_DAY_NUMBER_10TH :10de STR_DAY_NUMBER_11TH :11de STR_DAY_NUMBER_12TH :12de STR_DAY_NUMBER_13TH :13de STR_DAY_NUMBER_14TH :14de STR_DAY_NUMBER_15TH :15de STR_DAY_NUMBER_16TH :16de STR_DAY_NUMBER_17TH :17de STR_DAY_NUMBER_18TH :18de STR_DAY_NUMBER_19TH :19de STR_DAY_NUMBER_20TH :20ste STR_DAY_NUMBER_21ST :21ste STR_DAY_NUMBER_22ND :22ste STR_DAY_NUMBER_23RD :23ste STR_DAY_NUMBER_24TH :24ste STR_DAY_NUMBER_25TH :25ste STR_DAY_NUMBER_26TH :26ste STR_DAY_NUMBER_27TH :27ste STR_DAY_NUMBER_28TH :28ste STR_DAY_NUMBER_29TH :29ste STR_DAY_NUMBER_30TH :30ste STR_DAY_NUMBER_31ST :31ste ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :Jan STR_MONTH_ABBREV_FEB :Feb STR_MONTH_ABBREV_MAR :Mrt STR_MONTH_ABBREV_APR :Apr STR_MONTH_ABBREV_MAY :Mei STR_MONTH_ABBREV_JUN :Jun STR_MONTH_ABBREV_JUL :Jul STR_MONTH_ABBREV_AUG :Aug STR_MONTH_ABBREV_SEP :Sep STR_MONTH_ABBREV_OCT :Okt STR_MONTH_ABBREV_NOV :Nov STR_MONTH_ABBREV_DEC :Des STR_MONTH_JAN :Januarie STR_MONTH_FEB :Februarie STR_MONTH_MAR :Maart STR_MONTH_APR :April STR_MONTH_MAY :Mei STR_MONTH_JUN :Junie STR_MONTH_JUL :Julie STR_MONTH_AUG :Augustus STR_MONTH_SEP :September STR_MONTH_OCT :Oktober STR_MONTH_NOV :November STR_MONTH_DEC :Desember ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}Sleutel STR_GRAPH_KEY_TOOLTIP :{BLACK}Wys sleutel van grafieke STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Bedryfswins grafiek STR_GRAPH_INCOME_CAPTION :{WHITE}Inkomstegrafiek STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Eenheide van vrag afgelewer STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Maatskappy prestasie graderings (maksimum gradering=1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Maatskappywaarde STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Vragbetalingstariewe STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Dae in deurtog STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Inkomste vir aflewering van 10 eenhede (of 10,000 liter) vrag oor 'n afstand van 20 teëls STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Skakel alles aan STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Skakel alles af STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Vertoon alle vragte op die vrag koste grafiek STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Vertoon geen vragte op die vrag betalingskostes grafiek STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Skakel grafiek vir vrag tipe aan/af STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Vertoon breedvoerige prestasie graderings # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}Sleutel vir maatskappy grafieke STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Klik hier om maatskappy se intrede op grafiek aan/af te skakel # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Maatskappy Liga Tabel STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Ingenieur STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Verkeer Bestuurder STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Vervoer Koordineerder STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Roete Opsiener STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Direkteur STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Hoofbestuursleier STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Voorsitter STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :President STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Magnaat # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}Aanwysend prestasie gradering STR_PERFORMANCE_DETAIL_KEY :{BLACK}Aanwyse STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}Kyk besonderhede van hierdie maatskappy ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Voertuie: STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stasies: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. wins: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. inkomste: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Maks. inkomste: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Afgelewer: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Vrag: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Geld: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Lening: STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Totaal: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Aantal voertuie wat verlede jaar wins gemaak het (insl. padvoertuie, treine, skepe en vliegtuie) STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Aantal stasies wat onlangs herstel is. Treinstasies, busstasies, lughawens ensovoorts word apart getel selfs al behoort hulle aan dieselfde stasie STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}Die wins van die voertuig met die laagste inkomste (van alle voertuie ouer as 2 jaar) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Kontant verdien in die laaste kwartaal met die laagste wins van die laaste 12 kwartale STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Kontant verdien in die laaste kwartaal met die grootste wins van die laaste 12 kwartale STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Eenhede vrag in die laaste vier kwartale afgelewer STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Aantal vragtipes afgelewer in die verlede kwartaal STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Bedrag van geld die maatskappy het in die bank STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}Die bedrag van geld dat die maatskappy het gevat op lening STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Totale punte uit moontlike punte # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Jazz Blêrkas STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}Alle STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Outydse STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}Nuwe Styl STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Ezy Straat STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Op Bestelling 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Op Bestelling 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Musiek Volume STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Effek Volume STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}MIN STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}MAKS STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Liedjie STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Titel STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Skommel STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Musiek lys STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Gaan terug na vorige liedjie in keuse-lys STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Gaan na volgende liedjie in seleksie STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Hou op musiek speel STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Begin musiek speel STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Sleep skyfie om musiek en effekte volumes te stel STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Kies 'alle liedjies' uit program STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Kies 'outydse musiek' program STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Kies 'nuwe styl musiek' program STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Kies 'Ezy Straat styl musiek' program STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Kies 'Bestelling 1' (gebruiker-verklaarde) program STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Kies 'Bestelling 2' (gebruiker-verklaarde) program STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Skakel musiek lys skommel aan/af STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Vertoon musiek snit keuse venster STR_ERROR_NO_SONGS :{WHITE}'n Musiek stel is gekies wat geen liedere bevat nie. Geen liedere sal gespeel word nie # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Musiek Program Keuse STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Liedjie Indeks STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Program - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Maak skoon STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Maak huidige musiek keuse skoon (slegs Bestelling1 of Bestelling2) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Klik op 'n liedjie om by huidige musieklys by te sit (slegs Bestelling1 of Bestelling2) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Klik op musiek lied om te verwyder van huidige program (Slegs Gewoonte1 of Gewoonte2) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Top maatskappye wat {NUM} bereik het STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Maatskappy Liga Tafel in {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Sakeman STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Entrepreneur STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Nyweraar STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Kapitalis STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnaat STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Magnaat STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Magnaat van die Eeu STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} behaal '{STRING}' status! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} van {COMPANY} behaal '{STRING}' status! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}Kaart - {STRING} STR_SMALLMAP_TYPE_CONTOURS :Kontoere STR_SMALLMAP_TYPE_VEHICLES :Voertuie STR_SMALLMAP_TYPE_INDUSTRIES :Nywerhede STR_SMALLMAP_TYPE_ROUTEMAP :Vragverspreiding STR_SMALLMAP_TYPE_ROUTES :Roetes STR_SMALLMAP_TYPE_VEGETATION :Plantegroei STR_SMALLMAP_TYPE_OWNERS :Eienaars STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Vertoon land hoogtelyne op kaart STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Vertoon voertuie op kaart STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Wys nywerhede op kaart STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Vertoon vragverspreiding op kaart STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Wys vervoer roetes op kaart STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Wys plantegroei op kaart STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Wys land eienaars op kaart STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Klik op 'n nywerheidstipe om dit te vertoon. Ctrl+klik deaktiveer alle tipes behalwe die gekose een. Ctrl+klik dit weer om alle nywerheidstipes te aktiveer STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Klik op 'n maatskappy om sy eiendomme te vertoon. Ctrl+klik deaktiveer alle maatskappye behalwe die gekose een. Ctrl+klik op dit weer om alle maatskappye te aktiveer STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Klik op 'n vrag om eienskappe te vertoon of te versteek. Ctrl+klik versteek alle vrag behalwe die een wat op die oomblik gekies is. Ctrl+klik weer om alle vrag te vertoon. STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Paaie STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Spoorweë STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Stasies/Lughawes/Hawens STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Geboue/Nywerhede STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Voertuie STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Treine STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Padvoertuie STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Skepe STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Vliegtuie STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Vervoer Roetes STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Woud STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Treinstasie STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Vragmotor Laai Area STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Bus Stasie STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Lughawe/Helihawe STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Hawe STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Ongelyke Land STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Gras Land STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Kaal Land STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Velde STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Bome STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Rotse STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Water STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}Geen Eienaar STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Dorpe STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Nywerhede STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Woestyn STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Sneeu STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Skakel dorp name aan/af op kaart STR_SMALLMAP_CENTER :{BLACK}Senter die kleinkaart op die huidige posisie STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}Sper alle STR_SMALLMAP_ENABLE_ALL :{BLACK}Aktiveer alle STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Vertoon hoogte STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Moet nie enige nywerheide op die kaart vertoon STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Vertoon alle nywerheide op die kaart STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Skakel vertoning van reliëfkaart STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Vertoon geen maatskappy eiendom op die kaart STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Vertoon alle maatskappy eiendom op die kaart STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Vertoon geen vrag op die kaart STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Vertoon alle vrag op die kaart # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Wys laaste boodskap of nuus verslag STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * GEONDERBREEK * * STR_STATUSBAR_AUTOSAVE :{RED}OUTOSTOOR STR_STATUSBAR_SAVING_GAME :{RED}* * STOOR SPELETJIE * * # News message history STR_MESSAGE_HISTORY :{WHITE}Boodskapgeskiedenis STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}'n Lys van al die onlangs nuus boodskappe STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING} STR_NEWS_MESSAGE_CAPTION :{WHITE}Boodskap STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Burgers vier fees . . .{}Die eerste trein het by {STATION} aangekom! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Burgers vier fees . . .{}Die eerste bus het by {STATION} aangekom! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Burgers vier fees . . .{}Die eerste trok het by {STATION} aangekom! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Burgers vier fees . . .{}Die eerste passasiertrem het by {STATION} aangekom! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Burgers vier fees . . .{}Die eerste vragtrem het by {STATION} aangekom! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Burgers vier fees . . .{}Die eerste boot het by {STATION} aangekom! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Burgers vier fees . . .{}Die eerste vliegtuig het by {STATION} aagekom! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Trein Botsing!{}{COMMA} sterf in vuurbol na botsing STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Pad Voertuig Botsing!{}Bestuurder sterf in vuurbol na botsing met trein STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Pad voertuig Botsing!{}{COMMA} sterf in vuurbol na botsing met trein STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Vliegongeluk!{}{COMMA} sterf in die neerstorting naby {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Vliegongeluk!{}Vliegtuig het nie genoeg brandstof nie, {COMMA} sterf in neerstorting! STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Zeppelin ramp by {STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Pad voertuig vernietig in 'VVV' botsing! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Olie raffinadery het ontplof naby {TOWN}! STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}fabriek vernietig in agterdogtig omstandighede naby {TOWN}! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'VVV' beland naby {TOWN}! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Steenkool myn ongeluk los spoor van vernietiging naby {TOWN}! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Oorstroom!{}Te minste {COMMA} vermis, aangeneem dood na beduidende oorstroom! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Vervoer maatsappy in moelikheid! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} sal binnekort verkoop of bankrot verklaar word tensy prestasie verbeter! STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Vervoer maatskappy samesmelting! STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} is na {STRING} vir {CURRENCY_LONG} verkoop! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrotspeler! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} is deur skuldeisers toegemaak en alle bates is verkoop! STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}Nuwe vervoer maatskappy geloods! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} begin konstruksie naby {TOWN}! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{STRING} is deur {STRING} oorgevat! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Bestuurder) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{STRING} borg konstruksie van nuwe dorp {TOWN}! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}'n Nuwe {STRING} word naby {TOWN} gebou! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}Nuwe {STRING} word naby {TOWN} beplant! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING} het aangekondig dat hulle binnekort gaan sluit! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}{STRING} het aangekondig dat hulle binnekort gaan sluit as gevolg van 'n tekort aan die vereiste rou materiaal! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}{STRING} het aangekondig dat hulle binnekort gaan sluit as gevolg van 'n tekort aan bome in die omgewing! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}Europees Geldelik Samesmelting!{}{}Die Euro is bekend gestel as die enigste geldeenheid vir daagliks transaksies in u land! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}Wêreld Resessie!{}{}Finasiële kenners vrees die ergste terwyl ekonomie val! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Insinking Oor!{}{}Oplewing in sake gee vertroue na nywerhede as ekonomie versterk! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} vermeerder produksie! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}Nuwe steenkool laag gevind by {INDUSTRY}!{}Produksie word voorspel dat dit sal verdubbel! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}Nuwe olie reserwes gevind by {INDUSTRY}!{}Produksie is verwag om te verdubbel! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}Verbeterde boerdery metodes by {INDUSTRY} sal produksie verdubbel! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} produksie by {INDUSTRY} vermeerder {COMMA}%! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} produksie verminder 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Insek plaag veroorsaak verwoesting by {INDUSTRY}!{}Produksie verminder 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} produksie by {INDUSTRY} verminder {COMMA}%! STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} wag in depot STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} wag in depot STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} wag in depot STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} wag in die vliegtuig hangar # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} het te min bevele in skedule STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} het 'n leë bevel STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} het duplikaat bevele STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} het onwettige stasie in sy bevele STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY :{WHITE}{VEHICLE} het 'n bevel om by 'n lughawe te land waar die aanloopbaan te kort is STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} raak oud. STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} raak baie oud. STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} raak baie oud en benodig dringende vervanging. STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} kan nie 'n roete vind om aan te gaan nie. STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} het verdwaal. STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}{VEHICLE} se wins verlede jaar was {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} kan nie die volgende bestemmingpunt bereik nie want dis te ver STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} het gestop omdat 'n herbou opdrag gefaal het STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Automatiese hernuwing het misluk met {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Nuwe {STRING} nou beskikbaar! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Nuwe {STRING} nou beskikbaar! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} aanvaar nie meer {STRING} nie STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} aanvaar nie meer {STRING} of {STRING} nie STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} aanvaar nou {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} aanvaar nou {STRING} en {STRING} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Subsidie-aanbod het verval:{}{}{STRING} van {STRING} tot {STRING} sal nou nie 'n subsidie aantrek nie. STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidie onttrek:{}{}{STRING} diens van {STRING} tot {STRING} is nie meer gesubsideieer nie. STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Diens subsidie aanbod:{}{}Eerste {STRING} diens van {STRING} tot {STRING} sal 'n jaar se subsidie van die plaaslike raad kry! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Diens subsidie toeken aan {STRING}!{}{}{STRING} Diens van {STRING} tot {STRING} sal nou 50% extra vir die volgende jaar betaal! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Diens subsidie toeken aan {STRING}!{}{}{STRING} diens van {STRING} tot {STRING} sal nou dubbel pryse vir die volgende jaar betaal! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Diens subsidie toeken aan {STRING}!{}{}{STRING} diens van {STRING} tot {STRING} sal nou driemaal pryse vir die volgende jaar betaal! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Diens subsidie toeken aan {STRING}!{}{}{STRING} diens van {STRING} tot {STRING} sal nou viervoud pryse vir die volgende jaar betaal! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Verkeer warboel in {TOWN}!{}{}Pad heropbou program befonds deur {STRING} bring 6 maande van ellende na motoriste! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Vervoer monopoly! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK} die dorpsraad van {TOWN} het 'n kontrak met {STRING} aan gegaan vir een jaaar se eksklusiewe vervoer regte # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Toonvenster {COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Kopie na toonvenster STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Dupliseer die ligging van die hooftoonvenster na die toonvenster STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Plak vanaf toonvenster STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Plak die lokasie van die gesigspunt na die hoofskerm # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Spel Opsies STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Geldeenheid STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Geld eendheid keuse ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :Britse Pond (GBP) STR_GAME_OPTIONS_CURRENCY_USD :Amerikaanse Dollar (USD) STR_GAME_OPTIONS_CURRENCY_EUR :Euro (EUR) STR_GAME_OPTIONS_CURRENCY_JPY :Japannese Jen (JPY) STR_GAME_OPTIONS_CURRENCY_ATS :Oostenrykse Schilling (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :Belgiese Frank (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :Switserse Frank (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :Tsjeggiese Kroon (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :Duitse Mark (DEM) STR_GAME_OPTIONS_CURRENCY_DKK :Deense Krone (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :Spaanse Peseta (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :Finse Markka (FIM) STR_GAME_OPTIONS_CURRENCY_FRF :Franse Frank (FRF) STR_GAME_OPTIONS_CURRENCY_GRD :Griekse Dragma (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :Hongaarse Forint (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :Yslandse Kroon (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :Italiaanse Lire (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :Nederlandse Gulde (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :Noorweegse Kroon (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Poolse Zloty (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Roemeense Leu (RON) STR_GAME_OPTIONS_CURRENCY_RUR :Russiese Roebel (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Sloweense Tolar (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Sweedse Kroon (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Turkse Lire (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :Slowaakse Kroon (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :Brasiliaanse Real (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :Estniese Kroon (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Litause Litas (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :Suid Koreanse Won (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :Suid Afrikaanse Rand (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :Pasmaak... STR_GAME_OPTIONS_CURRENCY_GEL :Georgiaanse Lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iraanse Rial (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Pad voertuie STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Kies kant van pad waarop voertuie ry STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Bestuur aan linkerkant STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Bestuur aan regterkant STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Dorp name STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Kies dorp naam styl ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :Engels (Oorspronkilik) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :Frans STR_GAME_OPTIONS_TOWN_NAME_GERMAN :Duits STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :Engels (Addisioneel) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latyns-Amerikaans STR_GAME_OPTIONS_TOWN_NAME_SILLY :Snaaks STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Sweeds STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Hollands STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finnish STR_GAME_OPTIONS_TOWN_NAME_POLISH :Polish STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovak STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norwegian STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Hungarian STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Austrian STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Romanian STR_GAME_OPTIONS_TOWN_NAME_CZECH :Czech STR_GAME_OPTIONS_TOWN_NAME_SWISS :Swiss STR_GAME_OPTIONS_TOWN_NAME_DANISH :Deens STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Turks STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Italiaans STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Catalan ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Outostoor STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Kies interval tussen outomatiese store ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Af STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Elke maand STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :Elke 3 maande STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :Elke 6 maande STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Elke 12 maande ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}Taal STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Kies die koppelvlak taal om te gebruik STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Volskerm STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Kies die blokkie om OpenTTD in volleskerm te speel STR_GAME_OPTIONS_RESOLUTION :{BLACK}Skerm resolusie STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Kies die skerm resolusie om te gebruik STR_GAME_OPTIONS_RESOLUTION_OTHER :ander STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK} Koppelvlak groote STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK} Kies die koppelvlak element groote om te gebruik STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normaal STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Dubbel groote STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Quad grootte STR_GAME_OPTIONS_BASE_GRF :{BLACK}Basis-grafikastel STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Kies die basis-grafikastel stel om te gebruik STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} verlore / korrupte ler{P "" s} STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Meer inligting oor die basis-grafikastel STR_GAME_OPTIONS_BASE_SFX :{BLACK}Basis klank stel STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Kies die basis klank stel om te gebruik STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Addisionele informasie oor die basis klank stel STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Basis musiek stel STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Kies die basis musiek stel om te gebruik STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} korrupte lêer{P "" s} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Addisionele informasie oor die basis musiek stel STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Kon nie 'n lys van beskikbare skermresolusies bepaal nie STR_ERROR_FULLSCREEN_FAILED :{WHITE}Volskerm metode gedop # Custom currency window STR_CURRENCY_WINDOW :{WHITE}Pasmaak geldeenheid STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Wissel koers: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Verlaag die hoeveelheid van jou koers vir een Pond (£) STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Verhoog die hoeveelheid van jou koers vir een Pond (£) STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Stel die wissel koers vir jou koers vir een Pond (£) STR_CURRENCY_SEPARATOR :{LTBLUE}Afskeier {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Stel die skeier vir jou koers STR_CURRENCY_PREFIX :{LTBLUE}Voorvoegsel: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Stel die voorvoegsel teks vir jou koers STR_CURRENCY_SUFFIX :{LTBLUE}Agtervoegsel: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Stel die agtervoegsel teks vir jou koers STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Verwissel na Euro: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Verwissel na Euro: {ORANGE}nooit STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Stel die jaar om na Euro toe te skakel STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Skakel na Euro vroeër STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Skakel na Euro later STR_CURRENCY_PREVIEW :{LTBLUE}Voorskou: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 Pond (£) in jou koers STR_CURRENCY_CHANGE_PARAMETER :{BLACK}verander gebruiklike koers parameter STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Maksimum no. mededingers: {ORANGE}{COMMA} STR_NONE :Geen STR_FUNDING_ONLY :Befondsing alleen STR_MINIMAL :Minimale STR_NUM_VERY_LOW :Baie laag STR_NUM_LOW :Laag STR_NUM_NORMAL :Normaal STR_NUM_HIGH :Hoog STR_NUM_CUSTOM :Pasmaak STR_NUM_CUSTOM_NUMBER :Pasmaak ({NUM}) STR_VARIETY_NONE :Geen STR_VARIETY_VERY_LOW :Baie Laag STR_VARIETY_LOW :Laag STR_VARIETY_MEDIUM :Middelmatig STR_VARIETY_HIGH :Hoog STR_VARIETY_VERY_HIGH :Baie Hoog STR_AI_SPEED_VERY_SLOW :Baie Stadig STR_AI_SPEED_SLOW :Stadig STR_AI_SPEED_MEDIUM :Gemiddel STR_AI_SPEED_FAST :Vinnig STR_AI_SPEED_VERY_FAST :Baie Vinnig STR_SEA_LEVEL_VERY_LOW :Baie Laag STR_SEA_LEVEL_LOW :Laag STR_SEA_LEVEL_MEDIUM :Gemiddel STR_SEA_LEVEL_HIGH :Hoog STR_SEA_LEVEL_CUSTOM :Pasmaak STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Pasmaak ({NUM}%) STR_RIVERS_NONE :Geen STR_RIVERS_FEW :Min STR_RIVERS_MODERATE :Middelmatig STR_RIVERS_LOT :Baie STR_DISASTER_NONE :Geen STR_DISASTER_REDUCED :Verminder STR_DISASTER_NORMAL :Normaal STR_SUBSIDY_X1_5 :x1.5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 STR_TERRAIN_TYPE_VERY_FLAT :Baie Plat STR_TERRAIN_TYPE_FLAT :Plat STR_TERRAIN_TYPE_HILLY :Koppierig STR_TERRAIN_TYPE_MOUNTAINOUS :Bergagtig STR_TERRAIN_TYPE_ALPINIST :Alpinis STR_CITY_APPROVAL_PERMISSIVE :Permissief STR_CITY_APPROVAL_TOLERANT :Toelaatbaar STR_CITY_APPROVAL_HOSTILE :Vyandelik STR_WARNING_NO_SUITABLE_AI :{WHITE}Geen geskikte KI beskikbaar...{}Jy kan verskeie KI's aflaai deur middel van die 'Aanlyn Inhoud' stelsel # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Stellings STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter string: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Brei alles uit STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Krimp alles in STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(geen verduideliking beskikbaar) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standaard waarde: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Stelling tipe: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Kliënt instelling (word nie gestoor in spaarspeletjie nie; raak alle speletjies) STR_CONFIG_SETTING_TYPE_GAME_MENU :Maatskappy instelling (word gestoor in spaarspeletjie; raak net nuwe speletjies) STR_CONFIG_SETTING_TYPE_GAME_INGAME :Maatskappy instelling (word gestoor in spaarspeletjie; raak net die huidige spel) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Maatskappy instelling (word gestoor in Spaarspeletjies; raak net nuwe speletjies) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Maatskappy instelling (word gestoor in spaarspeletjie; raak net die huidige maatskappy) STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategorie: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tipe: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Beperk die lys hier onder deur voorafgestelde "filters" te gebruik slegs veranderde verstellings STR_CONFIG_SETTING_RESTRICT_BASIC :Basiese (wys net belangrik verstellings) STR_CONFIG_SETTING_RESTRICT_ADVANCED :Gevorderde (wys meeste verstellings) STR_CONFIG_SETTING_RESTRICT_ALL :Ekspert (wys alle verstellings, insluitend vreemde verstellings) STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Verstellings met 'n waarde anders as die verstek waarde STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Verstellings met 'n waarde anders as die nuwe spel verstellings STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Beperk die lys hieronder tot net sekere instelling tiepes STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :Alle instellings STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Kliënt-instellings (word nie in spaarspeletjies gestoor nie; raak alle speletjies) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Spel-instellings (word gestoor in spaarspeletjies; raak net nuwe speletjies) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Spel-instellings (word gestoor in spaarspeletjie; raak net die huidige speletjie) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Maatskappy-instellings (word gestoor in spaarspeletjies; raak slegs nuwe speletjies) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Maatskappy-instellings (word gestoor in spaarspeletjie; raak net die huidige maatskappy) STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Wys alle soekresultate deur oprigting{}{SILVER}Kategorie {BLACK}tot {WHITE}{STRING} STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Wys alle soekresultate deur oprigting{}{SILVER}Tik {BLACK}tot {WHITE}Alle opstel tipes STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Wys alle soekresultate deur oprigting{}{SILVER}Kategorie {BLACK}tot {WHITE}{STRING} {BLACK}en {SILVER}Tik {BLACK}tot {WHITE}Alle opstel tipes STR_CONFIG_SETTINGS_NONE :{WHITE}- Geen - STR_CONFIG_SETTING_OFF :Af STR_CONFIG_SETTING_ON :Aan STR_CONFIG_SETTING_DISABLED :Gedeaktiveer STR_CONFIG_SETTING_COMPANIES_OFF :Af STR_CONFIG_SETTING_COMPANIES_OWN :Eie maatskappy STR_CONFIG_SETTING_COMPANIES_ALL :Alle maatskappye STR_CONFIG_SETTING_NONE :Geen STR_CONFIG_SETTING_ORIGINAL :Oorspronlik STR_CONFIG_SETTING_REALISTIC :Realisties STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Links STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Senter STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Regs STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maksimum aanvanklike lening: {STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Maksimum bedrag wat 'n maatskappy kan leen (sonder die inagneming van inflasie) STR_CONFIG_SETTING_INTEREST_RATE :Rentekoers: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Lening rentekoers: beheer ook inflasie indien aangeskakel STR_CONFIG_SETTING_RUNNING_COSTS :Bedryfskostes: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Verstel die vlak van instandhouding en bedryfskoste van voertuie en infrastruktuur STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Konstruksie spoed: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Beperk die hoeveelheid konstruksie aksies vir die AIs STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Voertuig onklaarrakings: {STRING} STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Beheer hoe gereeld voertuie breek as hulle in 'n toestand van swak instandhouding verkeer STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subsidie vermenigvuldiger: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Verstel hoeveel is betaalbaar vir gesubsidieerde aansluitings STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Konstruksie kostes: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Verstel die vlak van konstruksie en aankoop-kostes STR_CONFIG_SETTING_RECESSIONS :Resessies: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :As dit geaktiveer is, kan resessie elke paar jaar voorkom. Gedurende 'n resessie word is vervaardiging drasties minder en aan die einde van die resessie word dit weer herstel na normale vlakke. STR_CONFIG_SETTING_TRAIN_REVERSING :Verhoed dat treine kan omdraai in stasies: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :As dit geaktiveer is, sal treine nie in deurstasies omdraai nie, selfs al is daar 'n korter roete deur om te draai. STR_CONFIG_SETTING_DISASTERS :Rampe: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Skakel rampe aan wat af en toe voertuie of infrastruktuur kan blokkeer of vernietig. STR_CONFIG_SETTING_CITY_APPROVAL :Stadsraad se gesindheid teenoor omgewings-konstruksie: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Kies hoeveel invloed klank en skade aan die omgewing deur maatskappye aan die stadswaardering het en verderde bouwerk in die stad. STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Maksimum kaarthoogte: {STRING} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Stel die maksimum toegelate berghoogte STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Kan nie die berghoogte verander nie - daar is hoër berge as hierdie op die kaart STR_CONFIG_SETTING_AUTOSLOPE :Laat landargitektuur toe onder geboue, spore, ens.: {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Laat Landargitektuur onder geboue en spore sonder om dit te verwyder STR_CONFIG_SETTING_CATCHMENT :Laat meer realisties groote opvangsgebied toe: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Laat verskillende groote opvang gebiede toe vir verskillende tipes stasies en lughawens STR_CONFIG_SETTING_EXTRADYNAMITE :Laat verwydering van meer stad-besite paaie, bruge, ens toe: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Maak dit makliker om dorps eiendom en infrastruktuur te verwyder STR_CONFIG_SETTING_TRAIN_LENGTH :Maximum lengte van treine: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Stel die maximum lente van treine STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} teël{P 0 "" s} STR_CONFIG_SETTING_SMOKE_AMOUNT :Hoeveelheid motor rook/vonke: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Stel vas hoeveel rook en hoeveel vonke deur voertuie gemaak word STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Trein versnelling model: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Kies 'n fisiese model vir die trein versnelling. Die "oorspronklike" model benadeel steilheid ewe vir alle voertuie. Die "realistiese" model benadeel hellings en kurwes, afhangende van die verskillende eienskappe, soos lengte en "tractive force" STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Pad voertuig versnelling model: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Kies 'n fisiese model vir pad vervoer versnelling. Die "oorspronklike" model benadeel steilheid ewe vir alle voertuie. Die "realistiese" model benadeel hellings en kurwes, afhangende van die verskillende eienskappe van die engin, byvoorbeeld "tractive force" STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Krans helling vir treine: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Die steilte van die helling vir treine. Hoër waardes maak dit moeliker om teen die helling uit te klim STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Krans helling vir pad vervoer: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Die steilte van die helling vir 'n pad voertuig. Hoër waardes maak dit moeliker om teen die helling uit te klim STR_CONFIG_SETTING_FORBID_90_DEG :Verbied triene en skepe om 90 graad draaie te maak: {STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 grade draaie kom voor wanneer 'n horisontale spoor direk gevolg deur 'n vertikale spoor op die aangrensende teël, dus waardeur die trein 'n 90 grade draai maak deur die teël rand in plaas van die gewone 45 grade vir 'n ander spoor kombinasies. Dit geld ook vir die draai radius van skepe STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Laat toe dat stasies lanks mekaar gebind kan word: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Laat die toevoeging van dele van 'n stasie sonder om direk aan die bestaande dele te raak toe. Ctrl+klik om die nuwe dele te plaas STR_CONFIG_SETTING_INFLATION :Inflasie: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Aktiveer inflasie in die ekonomie, waar die kostes vinniger styg as betalings STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maximum brug lengte: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Maximum lengte vir die bou van bruë STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Maksimum brughoogte: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Maksimum hoogte om brûe te bou STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maximum tonnel lengte: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Maximum lengte vir die bou van tonnels STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Handmatige primêre nywerheid konstruksie metode: {STRING} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Metode van befondsing van 'n primêre bedryf."Niks" beteken dit nie moontlik is om enige bedryf te finansier, "prospekteer" beteken befondsing is moontlik, maar konstruksie vind plaas in 'n toevallige plek op die kaart en dit kan ook misluk, "ander nywerhede" beteken rou bedrywe kan opgerig word deur ander maatskappye soos verwerking nywerhede. STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :Geen STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :As ander nywerhede STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Vooruitsigting STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Plat area rondom nywerhede: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Hoeveelheid van plat ruimte om 'n bedryf. Dit verseker dat leë ruimte beskikbaar sal bly, om 'n bedryf, vir die bou van spore, ensovoorts STR_CONFIG_SETTING_MULTIPINDTOWN :Laat meer as een soortgelyke nywerhede per dorp toe: {STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Gewoonlik sal 'n dorp nie meer as een bedryf van elke tipe wil hê nie. Met hierdie stelling, sal dorpe toelaat dat verskeie bedrywe van dieselfde tipe gebou word STR_CONFIG_SETTING_SIGNALSIDE :Wys seine: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Selekteer watter kand van die spoor om die seine te plaas STR_CONFIG_SETTING_SIGNALSIDE_LEFT :Aan die linkerkant STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :Aan die bestuurskant STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :Aan die regterkant STR_CONFIG_SETTING_SHOWFINANCES :Toon finansies venster op die einde van die jaar: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Indien geaktiveer, sal die finansies venster verskyn aan die einde van elke jaar om maklik inspeksie van die finansiële state, van die maatskappy, toe te laat STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Nuwe bevele is vooraf 'geen-stop' {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normaalweg stop 'n voertuig by elke stasie wat dit verby gaan. Deur gebruik te maak van hierdie instelling, sal dit verby elke stasie ry oppad na sy finale bestemming sonder om te stop. Let wel, dat hierdie verstelling slegs 'n standaard waarde definieer vir nuwe bevele. Individuele bevele kan uitdruklik gestel word na belang van gedrag STR_CONFIG_SETTING_STOP_LOCATION :Nuwe trein opdragte stop by verstek by die {STRING} van die platform STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Plek waar 'n trein stop by die platform by verstek. Die "naby die einde" naby aan die beginpunt van die platform, "middel", beteken in die middel van die platform, en "ander kant" beteken ver weg van die beginpunt van die platform. Let wel, dat hierdie verstelling definieer slegs 'n standaard waarde vir nuwe bevele. Individuele bevele kan nog ingestel word. STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :naby einde STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :middel STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :ver einde STR_CONFIG_SETTING_AUTOSCROLL :Rol skerm as muis by die kant is: {STRING} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :As dit geaktiveer is, sal subventers begin skuif wanneer die muis naby die kante van die venster is STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Gedeaktiveer STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Hoof skerm, slegs volskerm STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Hoof skerm STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Elke skerm STR_CONFIG_SETTING_BRIBE :Laat omkooping van die plaaslike raad toe: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Laat maatskappye die plaaslike dorpsraad probeer omkoop. Indien 'n inspekteur die omkoopgeld opgemerk, sal die maatskappy nie in staat wees om in die dorp te werk vir ses maande. STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Laat die koop van eksklusief vervoer regte toe: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :As 'n maatskapy alleen transportreg koop vir n' dorp. Die teenstanders se stasies (passesiers en vrag) sal geen vrag kry vir n' jaar STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Laat befondsing van geboue: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Laat geld donasies aan dorpe, deur maatskappye toe, vir die bou van huise STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Laat befondsing toe van plaaslike pad heropbou: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Laat maatskappye toe om geld te gee aan dorpe vir pad rekonstruksie om pad-gebaseerde dienste te saboteer STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Laat die stuur van geld na ander maatskappye toe: {STRING} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Laat die oordra van geld, tussen maatskappye, toe in multi-speler modus STR_CONFIG_SETTING_FREIGHT_TRAINS :Gewig vermenivoud vir vrag om swaar treine te simuleer: {STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Stel die impak van die dravrag op treine. Hoe hoër die hoeveelheid vrag wat gedra word, hoe meer veeleisend is dit vir die treine, veral teen die heuwels uit. STR_CONFIG_SETTING_PLANE_SPEED :Vlegtuig spoed faktor: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Stel die relatiewe spoed van vliegtuie, met vergelyking van ander voertuig tipes, om so die bedrag van die inkomste van vliegtuie te verminder. STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Aantal vliegtuig botsings: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Stel die kans van 'n vliegtuig ongeluk om te gebeur STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Geen STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Verminderd STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normaal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Laat deur-ry padhalte op dorp besite paaie toe: {STRING} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Laat Bouery van deur-ry pad stasies op dorp beheerde paaie STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Laat deur-ry padhalte toe op paaie wat deur ander deelnemers besit word: {STRING} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Laat die konstruksie van die ry-deur pad stasies op paaie toe wat deur ander maatskappye besit word STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Verandering van die stelling is nie moontlik wanneer daar voertuie is nie STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastruktuur onderhoud: {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :As dit geaktiveer is sal dit veroorsaak dat infrastruktuur onderhoudskoste verhoog. Die koste groei oor-proporsioneel met die netwerk grootte, wat groter maatskappye meer as kleiner maatskappye benadeel STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Lughawes verval nooit nie: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Wanner hierdie stelling geaktiveer is, maak dit dat alle lughawens ewig beskikbaar bly, na hul bekendstelling datum STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Waarsku indien voertuig verloor: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :veroorsaak boodskappe oor voertuie wat nie in staat is om 'n pad na hul bestel bestemming te vind nie STR_CONFIG_SETTING_ORDER_REVIEW :Hersien voertuig se opdrae: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :As dit geaktiveer is, word die voertuie se bevel van tyd tot tyd nagegaan, en 'n paar ooglopende kwessies sal berig word, met 'n nuus boodskap, as dit opgespoor word STR_CONFIG_SETTING_ORDER_REVIEW_OFF :Nee STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Ja, maar sluit stilstaande voertuie uit STR_CONFIG_SETTING_ORDER_REVIEW_ON :Van alle voertuie STR_CONFIG_SETTING_WARN_INCOME_LESS :Waarsku as 'n voertuig se inkomste negatief is: {STRING} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :As dit geaktiveer is, word daar 'n nuus boodskap gestuur wanneer, in 'n kalenderjaar, 'n voertuig nie wins gemaak het nie. STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Voertuie verval nooit nie: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :As dit geaktiveer is, sal voertuig modelle altyd beskikbaar bly, na die bekendstelling daarvan STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Outohernuwe voertuig as hy oud raak: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :As dit geaktiveer is, word 'n voertuig wat naby die einde van sy werkslewe kom outomaties vervang, wanneer die hernu voorwaardes vervul is. STR_CONFIG_SETTING_AUTORENEW_MONTHS :Vervang voertuig outomaties na {STRING} maksimum leeftyd STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relatiewe ouderdom waneer voertuie herweeg moet word ver outo-vervanging STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} maand{P 0 "" e} voor STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} maand{P 0 "" e} later STR_CONFIG_SETTING_AUTORENEW_MONEY :Outohernuwe minimum vereisde geld vir hernuwe: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimale bedrag geld wat in die bank moet bly, voor die oorweging van motor-vernuwing voertuie STR_CONFIG_SETTING_ERRMSG_DURATION :Tyd wat fout boodskap wys: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Tydsduur vir die vertoning van foutboodskappe. Kritiese foutboodskappe word nie outomaties toegemaak nie. STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} sekonde{P 0 "" s} STR_CONFIG_SETTING_HOVER_DELAY :wys sleutel-leidraad: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Tydsduur voor nutswenke vertoon words as die muis oor koppelvlakelemente gehou word. Alternatiewelik kan die nutswenke ook aan die regter-muisknoppie verbind word indien die stelling na 0 gestel word. STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Sweef vir {COMMA} sekonde{P 0 "" s} STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Regsklik STR_CONFIG_SETTING_POPULATION_IN_LABEL :Toon stadsbevolking in die naametiket: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Vertoon die bevolking van 'n stad in die naametiket op die kaart STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Dikte van lyn in grafieke: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Wydte van kaartlyne. A dun lyn is meer akkuraat om te lees, maar 'n dikker lyn is makliker om te sien en te onderskei van ander lyne. STR_CONFIG_SETTING_LANDSCAPE :Landskap: {STRING} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Die landskap beheer die basies spelopsies vir verskillende vrag en hoe dorpe groei. NewGRF en spelskrips gee meer opsies. STR_CONFIG_SETTING_LAND_GENERATOR :Land genereerder: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :Hoe die land geskep word, hang af van die grafika stel en skep vaste landskap vorms. TerraGenesis is 'n Perlin-geraas gebasseerde skepper met meer beheerinstellings. STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Oorspronklik STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_TERRAIN_TYPE :Tipe terrein: {STRING} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Slegs TerraGenesis) Bergagtigheid van die land STR_CONFIG_SETTING_INDUSTRY_DENSITY :Nywerheidsdigtheid: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Kies hoeveel nywerhede geskep gaan word en hoeveel gedurende die spel te handhaaf STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maksimum afstand vanaf rand vir olieraffinaderye: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Olieraffinaderye word net naby die kaart kant gebou, dit is, teen die kus vir eiland kaarte STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Sneeu lyn hoogte: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Beheer die hoogte van die sneeuvlak. Die sneeuvlak bepaal ook hoeveel nywerhede geskep word en hoe vinnig dorpe groei. STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Grofheid van terrein: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(Slegs TerraGenesis) Kies die heuwelagtigheid: 'n Vlak land het 'n paar heuwel wat wyd versprei is. 'n Rowwe landskap het baie heuwels wat herhaaldelik voorkom. STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Baie Glad STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Glad STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Rof STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Baie Rof STR_CONFIG_SETTING_VARIETY :Verskeidenheid verspreiding: {STRING} STR_CONFIG_SETTING_VARIETY_HELPTEXT :(Slegs TerraGenesis) Kies of die land berge en vlaktes het. Hierdie instelling maak die landskap vlakker, so ander instellings moet bergagtig wees. STR_CONFIG_SETTING_RIVER_AMOUNT :Aantal riviere: {STRING} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Kies hoeveel riviere geskep gaan word STR_CONFIG_SETTING_TREE_PLACER :Boom plaas algoritme: {STRING} STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Kies vir verspreiding van bome: 'Oorspronklik' versprei bome eweredig, 'Verbeterde' versprei bome in woude STR_CONFIG_SETTING_TREE_PLACER_NONE :Geen STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Oorspronklik STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Verbeter STR_CONFIG_SETTING_ROAD_SIDE :Padvoertuie: {STRING} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Kies die bestuurskant STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Reliëfkaart orientasie: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Anti-kloksgewys STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Kloksgewys STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :Die hoogte vlak wat 'n plat scenario kaart kry: {STRING} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}Een of meer teëls op die Noordelike grens is nie leeg nie STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}Een of meer teëls by een van die kante is nie water nie STR_CONFIG_SETTING_STATION_SPREAD :Maksimum stasiegrootte: {STRING} STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Hoe groot 'n area 'n stasie mag opneem. Groter waardes kan die spel stadig maak. STR_CONFIG_SETTING_SERVICEATHELIPAD :Diens helikopters by helihawes outomaties: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Diens helikopters na elke landing, selfs al is daar nie 'n diensstasie by die lughawe nie STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Verbind landereye werktuigbaan na spoor/pad/water/lughawe werktuigbaan: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :Vertoon die landskapwerktuigbaan wanneer 'n konstruksiewerktuigbaan vertoon word. STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Land kleur gebruik op die klein landkaart: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Kleur van die terrein in die klein landkaart STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Groen STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Donkergroen STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Violet STR_CONFIG_SETTING_REVERSE_SCROLLING :Agteruit rol rigting: {STRING} STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :As dit geaktiveer is, skuif die muis die kaart, andersins skuif die muis die kamera. STR_CONFIG_SETTING_SMOOTH_SCROLLING :Maak kykpoort beweegings glad: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Beheer hoe die hoofvertoonvenster skuif na 'n spesifieke posisie - as dit geaktiveer is, dan skuif die venster glad na die posisie toe, andersins skuif die venster direk na die posisie toe. STR_CONFIG_SETTING_MEASURE_TOOLTIP :Toon 'n meting wanneer jy verskeie bou-gereedskap gebruik: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Vertoon teëlafstand en hoogteverskil gedurende bouwerk. STR_CONFIG_SETTING_LIVERIES :Toon voertuigspesifieke kleure: {STRING} STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Beheer die gebruik van voertuig-gebasseerde kleurskemas (teenoor maatskappy-gebasseerde kleurskemas) STR_CONFIG_SETTING_LIVERIES_NONE :Geen STR_CONFIG_SETTING_LIVERIES_OWN :Eie maatskappy STR_CONFIG_SETTING_LIVERIES_ALL :Alle maatskappye STR_CONFIG_SETTING_PREFER_TEAMCHAT :Verkies span klets met : {STRING} STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Wissel die en sleutels om spanklets en openbare klets oop te maak. STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Funksie van rolwiel: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Aktiveer "scrolling" met twee-dimensieële muis-wiele STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Zoem kaart STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Rol kaart STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Af STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Kaart rolwiel spoed: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Kontroleer die sensitiwiteit van die muis-wiel "scrolling" STR_CONFIG_SETTING_OSK_ACTIVATION :Skerm-sleutelbord: {STRING} STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Kies hoe om die skerm-sleutelbord te vertoon. Hierdie opsie is vir toestelle wat nie 'n fisiese sleutelbord het nie soos tabletrekenaars. STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Gedeaktiveer STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Dubbel-klik STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Enkel klik (met fokus) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Enkel klik (dadelik) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Regs-klik emulasie: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Kies die manier om regs-klik na te maak STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command-klik STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl-klik STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Af STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Links-klik vir skermrol: {STRING} STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :Maak dit moontlik om die kaart te skuif deur met die die linker-muisknoppie te sleep. Hier opsie werk baie goed vir toestelle met raakskerms. STR_CONFIG_SETTING_AUTOSAVE :Outostoor: {STRING} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :Tyd tussen outomatiese spelstore STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Gebruik die {STRING} datum formaat vir gestoorde spel name. STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Formaat van datum van spaar-speletjie naam STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :lank (31ste Des 2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :kort (31-12-2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Outomaties pouse wanneer om te begin 'n nuwe speletjie: {STRING} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :As hierdie opsie geaktiveer is, sal die spel geonderbreek wees wanneer die spel begin. STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Wanneer geonderbreek laat die toe: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Selekteer watter aksies mag gedoen word terwyl die speletjie onderbreek word STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :Geen aksies STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :Alle nie-konstruksie aksies STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :Alles behalwe landskap-veranderende aksies STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :Alle aksies STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Gebruik groepe in die voertuiglys: {STRING} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Aktiveer die gebruik van die gevorderde voertuig lys vir groepering van voertuie STR_CONFIG_SETTING_LOADING_INDICATORS :Gebruik laai aanwysers: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Kies of die ladingswaardes vertoon word wanneer voertuie vrag op- en aflaai STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Vertoon rooster in "ticks" liewer as dae: {STRING} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Wys die rystye in tydroosters in speletjie "ticks" inplaas van dae STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Toon aankoms en vertrek in tydroosters: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Vertoon verwagte aankoms en vertrek tye in tydroosters STR_CONFIG_SETTING_QUICKGOTO :Vinnige skepping van voertuig opdragte: {STRING} STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Pre-selekteer die "gaan na wyser" wanneer die bevele venster oop gemaak word STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Verstek spoor tipe (na nuwe spel/spel laai): {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Spoortipe om te kies wanneer 'n nuwe spel begin. 'Eers beskikbaar' kies die oudste tipe spoor, 'Laas beskikbaar' kies die nuutste tipe spoor, 'Meeste gebruik' kies die spoor wat die meeste in gebruik is. STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :Eers beskikbaar STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Laas beskikbaar STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Meeste gebruik STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Wys spoorreserverings: {STRING} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Wys gereserveerde spore in 'n ander kleur om te help wanneer treine nie die regte roetes kies nie STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Hou bou gereedskap aktief na gebruik: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Hou die bougereedskap vir brûe, tonnels ens. aktief na gebruik STR_CONFIG_SETTING_EXPENSES_LAYOUT :Groep uitgawes in maatskappy finansies venster: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Verstel die uitleg van die maatskappy uitgawes venster STR_CONFIG_SETTING_SOUND_TICKER :Nuustikker: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Speel klank vir opgesomde nuus boodskappe STR_CONFIG_SETTING_SOUND_NEWS :Koerant: {STRING} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Speel klank wanneer koerante vertoon word STR_CONFIG_SETTING_SOUND_NEW_YEAR :Einde van jaar: {STRING} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Speel klankeffek aan die einde van 'n jaar wanneer die maatskappy se jaarresultate vertoon word STR_CONFIG_SETTING_SOUND_CONFIRM :Konstruksie: {STRING} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Speel 'n klank wanneer 'n konstruksie of ander aksie suksesvol voltooi is STR_CONFIG_SETTING_SOUND_CLICK :Knoppieklik: {STRING} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Biep wanneer 'n knoppie geklik word STR_CONFIG_SETTING_SOUND_DISASTER :Rampe/ongelukke: {STRING} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Speel klanke vir ongelukke en rampe STR_CONFIG_SETTING_SOUND_VEHICLE :Voertuie: {STRING} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Speel klanke vir voertuie STR_CONFIG_SETTING_SOUND_AMBIENT :Omgewing: {STRING} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Speel omgewingsklankeffekte van die landskap, industriëe en dorpe STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Deaktiveer infrastruktuur bouery as geen geskikte voertuie beskikbaar is nie: {STRING} STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :As dit geaktiveer is, is infrastruktuur net beskikbaar as daar ook voertuie beskikbaar is om daardie infrastruktuur te gebruik. Dit is om tyd- en geldmors op onbruikbare infrastruktuur te voorkom. STR_CONFIG_SETTING_MAX_TRAINS :Maksimum aantal treine per speler: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Maksimum hoeveelheid treine was 'n besigheid kan hê STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Maksimum aantal padvoertuie per maatskappy: {STRING} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Maksimum hoeveelheid pad voertuie was 'n besigheid kan hê STR_CONFIG_SETTING_MAX_AIRCRAFT :Maksimum aantal vliegtuie per speler: {STRING} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Maksimum hoeveelheid vliegtuie was 'n besigheid kan hê STR_CONFIG_SETTING_MAX_SHIPS :Maksimum aantal skepe per speler: {STRING} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Maksimum hoeveelheid bote was 'n besigheid kan hê STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Sper treine vir rekenaar: {STRING} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Aktiveer om te verhoed dat die rekenaar speler kan treine bou STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Sper pad voertuie vir rekenaar: {STRING} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Aktiveer om te verhoed dat die rekenaar speler kan pad voertuie bou STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Sper vliegtuie vir rekenaar: {STRING} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Aktiveer om te verhoed dat die rekenaar speler kan vliegtuie bou STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Sper skepe vir rekenaar: {STRING} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Aktiveer om te verhoed dat die rekenaar speler kan skepe bou STR_CONFIG_SETTING_AI_PROFILE :Verstek verstellings profiel: {STRING} STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Kies watter stellingsprofiel om te gebruik vir rekenaarspelers of beginwaardes vir nuwe rekenaarspelers STR_CONFIG_SETTING_AI_PROFILE_EASY :Maklik STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Middelmatig STR_CONFIG_SETTING_AI_PROFILE_HARD :Moeilik STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Laat AI in multispeler toe: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Laat AI Rekenaaar spelers by 'n multi-speler spel toe STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes voor die skripte gestaak word: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Die maksimum hoeveelheid berekeningstappe wat 'n skrip kan vat in een beurt STR_CONFIG_SETTING_SERVINT_ISPERCENT :Diens pouse is in persente: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Kies of voertuie gediens word gebasseer op tydsduur vanaf vorige diens of as die voertuig se betroubaarheid met 'n sekere persentasie geval het van die maksimum STR_CONFIG_SETTING_SERVINT_TRAINS :Standaard diens interval vir treine: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Kies die standaard diensskedule vir nuwe treine as geen diensskedule aangedui is nie STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}da{P g e}/% STR_CONFIG_SETTING_SERVINT_DISABLED :Gedeaktiveer STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Standaard diens interval vir pad voertuie: {STRING} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Kies die standaard diensskedule vir nuwe padvoertuie as geen diensskedule aangedui is nie STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Standaard diens interval vir vliegtuie: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Kies die standaard diensskedule vir nuwe vliegtuie as geen diensskedule aangedui is nie STR_CONFIG_SETTING_SERVINT_SHIPS :Standaard diens interval vir bote: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Kies die standaard diensskedule vir nuwe skepe as geen diensskedule aangedui is nie STR_CONFIG_SETTING_NOSERVICE :Sper diens wanneer komplikasies is na geen gestel: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :As dit geaktiveerd is, word voertuie nie gediens as hulle nie kan onklaar raak nie STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Laat wa spoed beperkings toe: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :As dit geaktiveer is bepaal die spoedbeperking van treinwaens ook die maksimum spoed van die hele trein STR_CONFIG_SETTING_DISABLE_ELRAILS :Deaktiveer elektriese spore: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :As dit geaktiveerd is, is dit nie nodig om spore te elektrifiseer voordat elektriese treine die spore kan gebruik nie STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Aankoms van eerste voertuig by speler se stasie: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Vertoon 'n koerantberig waneer die eerste voertuig by 'n nuwe speler se stasie arriveer STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Aankoms van eerste voertuig by mededinger se stasie: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Vertoon 'n koerantberig waneer die eerste voertuig by 'n nuwe teenstander se stasie arriveer STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Ongelukke / rampe: {STRING} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Vertoon 'n koerantberig wanneer daar ongelukke of natuurrampe voorkom STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Maatskappy informasie: {STRING} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Vertoon 'n koerantberig wanneer 'n nuwe maatskappy begin, of wanneer 'n maatskappy in gevaar is om bankkrot te speel STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Opening van industrieë: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Vertoon die koerant wanneer 'n nuwe nywerheid oopmaak STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Toemaak van industrieë: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Vertoon die koerant wanneer 'n nywerheid toemaak STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Ekonomie veranderings: {STRING} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Vertoon die koerant vir enige globale veranderinge aan die ekonomie STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Verandering in produksie van industrieë voorsien deur die maatskapy: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Vertoon die koerant indien enige produksie vlakke van nywerhede bedien deur die maatskappy verander STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Produksie veranderings van nywerhede wat deur mededingers bedien word: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Vertoon die koerant indien enige produksie vlakke van nywerhede bedien deur die kompetisie verander STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Ander nywerheid produksie veranderings: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Vertoon 'n koerant wanner die produksievlak van industriëe verander, wat nie tans bedien word deur die maatskappy of kompeteerders nie STR_CONFIG_SETTING_NEWS_ADVICE :Advies / informasie van maatskappy se voertuie: {STRING} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Vertoon boodskappe aangaande voertuie wat aandag nodig het STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :Nuwe voertuie: {STRING} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Vertoon 'n koerant wanneer 'n nuwe tipe voertuig beskikbaar raak STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Veranderings van vrag aanvaarding: {STRING} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Vertoon boodskappe aangaande stasies wat hul aanvaarde vrag verander STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subsidies: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Vertoon 'n koerant aangaande subsidie-verwante gebeurtenisse STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :Algemene informasie: {STRING} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Vertoon koerant aangaande algemene gebeurtenisse, soos die aankoop van eksklusiewe regte of fondsing van padrekonstruksies STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :Af STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Opsomming STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Vol STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Gekleurde nuus verskyn in: {STRING} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :In watter jaar begin koerante in kleur vertoon. Voor dit is hulle swart en wit. STR_CONFIG_SETTING_STARTING_YEAR :Jaar om te begin: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Aktiveer geleike ekonomie (meer, kleiner veranderings): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :As dit geaktiveer is sal nywerheidsvervaarding meer gereeld verander met kleiner veranderinge elke keer. Hierdie stelling het gewoonlik geen effek met nywerhede van NewGRFs nie. STR_CONFIG_SETTING_ALLOW_SHARES :Laat die koop van aandeele van ander maatskappye toe: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :As dit geaktiveer is, kan aandele in maatskappye gekoop en verkoop word. Aandele is net in maatskappye beskikbaar na 'n sekere aantal jaar. STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Persentasie van wins om te betaal in voerder systeem: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Persentasie wins wat gedeel word met die tussengangerstasies in oordragstelsels vir beter beheer oor die wins STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Wanneer die muis gesleep word, plaas 'n sein elke: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Bepaal die afstand tussen seine wat geplaas word tot by die volgende sein of spooraansluiting STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} teël{P 0 "" s} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Wanneer signale getrek word, behou konstante afstand: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Bepaal wat gebeur as Ctrl ingehou word terwyl seine geplaas word terwyl die muis gesleep word. As dit nie geaktiveer is nie, word seine by tonnels en brûe ook geplaas om lang afstande sonder seine te verhoed. As dit geaktiveer is, word seine elke n teëls geplaas wat dit maklik maak om ooreenstemmende seine oor parallel spore te plaas. STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Outomaties bou semaphores voor: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Stel die jaar wanneer elektriese seine gebruik word vir spore. Voor hierdie jaar word seinpale gebruik (die manier waarop hulle werk is presies dieselfde). STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Aktiveer die sein GUI: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Vertoon 'n venster om te kies watter sein-tipes te bou, eerder as vensterlose sein-tipe met Ctrl+klik te gebruik om te sein-tipes gebou word STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Sein tipe om te bou by verstek: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Standaard sein tipe om te gebruik STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Blok seine STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Pad seine STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :Een-rigting seine STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Wissel deur tiepe seine: {STRING} STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :Selekteer watter sinjaaltipes om deur te wissel, wanneer Ctrl+klik gebruik word om 'n sinjaal te bou met die sinjaal gereedskap STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Blok seine aleenlik STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Pad seinligte alleenlik STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :Alle STR_CONFIG_SETTING_TOWN_LAYOUT :Pad uitleg vir nuwe dorpe: {STRING} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Pad netwerk uitleg van paaie vir dorpe STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Oorspronkilik STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Beter paaie STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 grid STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 grid STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Willekeurig STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Dorpe word toegelaat om paaie te bou: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Laat dorpe toe om paaie te bou vir groei. Deaktiveer om stad owerhede te verhoed om paaie hulself te bou STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Dorpe word toegelaat om vlak kruising te bou: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Aktivering van die stelling laat dorpe toe om vlak kruisings te bou STR_CONFIG_SETTING_NOISE_LEVEL :Laat dorp-beheerede klankvlak vir lughawes toe: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :Met deaktivering van hierdie stelling, kan daar twee lughawens in elke dorp wees. Met hierdie stelling word die getal van lughawens in 'n stad beperk deur die geluid aanvaarding van die dorp, wat afhanklik is van die bevolking en die lughawe grootte en afstand tussen van mekaar STR_CONFIG_SETTING_TOWN_FOUNDING :Stigting van dorpe binne speletjie: {STRING} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Aktiveering van die stelling laat spelers toe om dorpe te stig in die speletjie STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Verbode STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Toegelaat STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Toegelaat, eie dorp uitleg STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Binne speletjie plasing van bome: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Beheer die ewekansige voorkoms van bome tydens die spel. Dit kan 'n invloed op nywerhede hê wat staatmaak op die groei van bome, byvoorbeeld hout meulens STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :Geen {RED}(breek timmerhout meul) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :Slegs in reënwoude STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :Orals STR_CONFIG_SETTING_TOOLBAR_POS :Posisie van hoof werktuigbaan: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horisontale posisie van die hoof nutsbalk aan die bokant van die skerm STR_CONFIG_SETTING_STATUSBAR_POS :Posisie van statusbalk: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Horisontale posisie van die statusbalk aan die onderkant van die skerm STR_CONFIG_SETTING_SNAP_RADIUS :Window klamp radius: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Afstand tussen vensters voor dat die venster outomaties in lyn met die nabygeleë vensters geskuif word STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pixel{P 0 "" s} STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Gedeaktiveer STR_CONFIG_SETTING_SOFT_LIMIT :Maksimum aantal nie-taaierige vensters: {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Aantal non-sticky oop vensters voordat ou vensters outomaties toe gemaak word om die ruimte te maak vir nuwe vensters STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :gedeaktiveer STR_CONFIG_SETTING_ZOOM_MIN :Maximum zoem in level: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Die maksimum zoom-vlak vir vertoon-venster. Let daarop dat hoër Zoom-vlakke verhoogte geheue vereistes te volge het STR_CONFIG_SETTING_ZOOM_MAX :Maximum zoem uit level: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :Die maksimum zoom-vlak vir vertoon-venster. Hoër zoom-vlakke kan tot vertragings lei, wanneer dit gebruik word STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normaal STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x STR_CONFIG_SETTING_TOWN_GROWTH :Dorp groei spoed: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Spoed van dorp groei STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Geen STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Stadig STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normaal STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Vinnig STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Baie vinnig STR_CONFIG_SETTING_LARGER_TOWNS :Verhouding van dorpe wat stede sal word: {STRING} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Hoeveelheid van dorpe wat 'n stad sal word, dus 'n dorp wat groot begin en vinniger groei STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 in {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :Geen STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Aanvanklike stad grootte multiplier: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Normale stede groote relatief na normale dorpe aan die begin van speletjie STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Herreken die verspreingskaart elke {STRING}{NBSP}da{P 0:2 g e} STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Tyd tussen daaropvolgende herrekeninge van die verspreidingskaart. Elke herrekening is vir een komponent van die hele kaart, so net 'n gedeelte is dan op datum, nie die hele kaart nie. Hoe korter hierdie stelling is, hoe meer verwerkingskrag word benodig, hoe langer hierdie stelling is, hoe langer vat dit vir die vrag om op nuwe roetes te versprei. STR_CONFIG_SETTING_LINKGRAPH_TIME :Neem {STRING}{NBSP}da{P 0:2 g e} om verspreidingskaart te herreken STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Tyd benodig vir die herrekening van elke komponent van die verspreidingskaart. Elke berekening kan vir hierdie aantal dae hardloop, as hierdie stelling te kort is en die berekening is nie klaar nie, dan kan die spel stop tot die berekening klaar gedoen is. Hoe meer tyd toegelaat word vir hierdie berekeninge, hoe langer vat dit vir die verspreidingskaart om te verander as roetes verander. STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :handmatig STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimmetries STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simmetries STR_CONFIG_SETTING_DISTRIBUTION_PAX :Verspreidingsmodel vir passasiers: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"simmetries" beteken dat ongeveer dieselfde hoeveelheid passasiers tussen twee stasies gestuur word. "asimmetries" beteken passasiers word na willekeur tussen twee stasies gestuur. "handmatig" beteken dat passasiers nie outomaties versprei word nie. STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Verspreidingsmodel vir pos: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"simmetries" beteken dat ongeveer dieselfde hoeveelheid pos tussen twee stasies gestuur word. "asimmetries" beteken pos word na willekeur tussen twee stasies gestuur. "handmatig" beteken dat geen pos nie outomaties versprei word nie STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Verspreidingsmodel vir pantservoertuie: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :Pantservoertuie word gebruik vir edelmetale in die matige klimaat, diamante in die sub-tropiese klimaat en goud in die sub-arktiese klimaat. NewGRFs kan dit verander. "simmetries" beteken dat ongeveer dieselfde hoeveelheid vrag tussen twee stasies gestuur word. "asimmetries" beteken dat vrag tussen twee stasies na willekeur gestuur word. "handmatig" beteken dat geen vrag nie outomaties versprei word nie. Dit word voorstel om "asimmetries" of "handmatig" te kies in die sub-arktiese klimaat omdat banke nie goud kan terugstuur na 'n myn toe nie. In die matige en sub-tropiese klimaat kan jy ook simmetries kies sodat banke edelmetale kan terugstuur na die bank van oorsprong. STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Verspreidingsmodel vir ander vragkategorieë: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asimmetries" beteken dat vrag tussen twee stasies na willekeur gestuur word. "handmatig" beteken dat geen vrag nie outomaties versprei word nie. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Verspreidingsakkuraatheid: {STRING} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Hoe hoër hierdie waarde is, hoe meer rekenkrag word benodig om die verspreidingskaart te bereken. As die waarde te hoog is, kan dit die spel stadig maak en as die waarde te laag is, kan die verspreidingskaart onakkuraat maak en veroorsaak dat vrag na onverwagte bestemmings gestuur word. STR_CONFIG_SETTING_DEMAND_DISTANCE :Afstandeffek op vragaanvraag: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :As hierdie stelling hoër as 0 is, dan bepaal die afstand van die bron en die bestemming, hoeveel vrag tussen die twee gestuur word. Hoe verder uitmekaar die bron en bestemming, hoe minder vrag sal gestuur word. Hoër waardes beteken minder vrag word gestuur tussen stasies wat verder uitmekaar is. STR_CONFIG_SETTING_DEMAND_SIZE :Hoeveelheid vrag om terug te stuur in die simetriese verspreidingsmodel: {STRING} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Stel hierdie na minder as 100% om die simmetriese verspreidingmodel meer soos die assimetries verspreidingsmodel te laat werk. Minder vrag sal dan teruggestuur word as wat oorspronklik na die stasie toe gestuur is. As die waarde 0% is, dan werk die simmetriese model net soos die assimetriese model. STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Versadigingsvlak van korter roetes voor ander roetes met kapasiteit gebruik word: {STRING} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Daar is gereeld verskeie roetes tussen twee stasies. Cargodist sal die kortste roete eerste versadig, dan die tweede korste roete en so aan. Die beraamde kapasiteit en beplande gebruik van die pad word gebruik om te bepaal of 'n roete versadig is. As daar nogsteeds aanvraag is nadat alle roetes versadig is, sal die huidige roetes oorlaai word met voorrang vir die hoë-kapasiteitsroetes. Die algoritme is nie altyd akuraat om kapasiteit te bepaal nie. Hierdie stelling laat jou toe om te kies hoeveel 'n roete versadig is voordat 'n volgende roete gebruik word. Om oorvol stasies te voorkom, stel hierdie na minder as 'n 100%. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Spoed eenheid: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Wys spoed in die eenheid wat gekies is STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Empiries (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metries (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Trekkrag eenheid: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Wys trekkrag in die eenheid wat gekies is STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Empiries (perdekrag) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metries (perdekrag) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Massa eenheid: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Wys massa in die eenheid wat gekies is STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Empiries (kort ton) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metries (t/ton) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Volume eenheid: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Wanneer 'n volume gewys word in die gebruikerskoppelvlak, wys dit in die geselekteerde eenhede STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Empiries (gelling) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metries (I) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Trekkrag eenhede: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Wanneer 'n trekkrag gewys word in die gebruikerskoppelvlak, wys dit in die geselekteerde eenhede STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Empiries (lbf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metries (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Hoogte eenheid: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Wanneer 'n hoogte word in die gebruikerskoppelvlak, wys dit in die geselekteerde eenhede STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Empiries (vt) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metries (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Eenhede STR_CONFIG_SETTING_GRAPHICS :{ORANGE}Grafika STR_CONFIG_SETTING_SOUND :{ORANGE}Klank STR_CONFIG_SETTING_INTERFACE :{ORANGE}Koppelvlak STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE}Algemeen STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Vertoonvensters STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Konstruksie STR_CONFIG_SETTING_ADVISORS :{ORANGE}Nuus / Raad STR_CONFIG_SETTING_COMPANY :{ORANGE}Maatskappy STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Rekeningkunde STR_CONFIG_SETTING_VEHICLES :{ORANGE}Voertuie STR_CONFIG_SETTING_VEHICLES_PHYSICS :{ORANGE}Fisika STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Roete STR_CONFIG_SETTING_LIMITATIONS :{ORANGE}Beperkings STR_CONFIG_SETTING_ACCIDENTS :{ORANGE}Ongelukke & rampe STR_CONFIG_SETTING_GENWORLD :{ORANGE}Land skepping STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}Omgewing STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :{ORANGE}Stadsrade STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}Dorpe STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Nywerhede STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Vragverspreiding STR_CONFIG_SETTING_AI :{ORANGE}Mededingers STR_CONFIG_SETTING_AI_NPC :{ORANGE}Rekenaar spelers STR_CONFIG_SETTING_PATHFINDER_OPF :Oorspronklik STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Aanbevole) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Padvinder vir treine: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Pad speurder om vir teine te gebruik STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Padvinder vir pad voertuie: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Pad speurder om vir pad vervoer te gebruik STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Padvinder vir skepe: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Pad speurder om vir skepe te gebruik STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Outomatiese rigting verandering op seine: {STRING} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Laat treine toe om agteruit te gaan by signale, as hulle daar lank gewag het STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Verander stel waarde # Config errors STR_CONFIG_ERROR :{WHITE}Fout met die konfigurasie lêer... STR_CONFIG_ERROR_ARRAY :{WHITE}... fout in skikking '{STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... ongeldig waarde '{STRING}' vir '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... sleep karakters aan die einde van die stelling '{STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignoreer NewGRF '{STRING}': duplikaat GRF ID met '{STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignoreer ongeldige NewGRF '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :nie gevind STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :onveilig vir statiese gebruik STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :stelsel NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :onversoenbaar met hierdie weergawe van OpenTTD STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :onbekend STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... kompressie vlak '{STRING}' is ongeldig STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... savegame formaat '{STRING}' is nie beskikbaar. Keer terug na '{STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... gaan die basis-grafikastel '{STRING}' ignoreer: nie gevind nie STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignoreer Basis Klank stel '{STRING}': nie gevind nie STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignoreer Basis Musiek stel '{STRING}': nie gevind STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Program is uit geheue uit STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Allokering van {BYTES} kasgeheue vir grafika het gefaal. Die kasgeheue is verminder na {BYTES}. Dit sal OpenTDD stadiger maak. Om geheue-aanvraag te verminder, kan u 32bpp grafika en/of zoom-vlakke afskakel. # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}Nuwe Spel STR_INTRO_LOAD_GAME :{BLACK}Laai Spel STR_INTRO_PLAY_SCENARIO :{BLACK}Speel Scenario STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Speel reliëfkaart STR_INTRO_SCENARIO_EDITOR :{BLACK}Scenario Redakteur STR_INTRO_MULTIPLAYER :{BLACK}Multispeler STR_INTRO_GAME_OPTIONS :{BLACK}Spel Opsies STR_INTRO_HIGHSCORE :{BLACK}Hoogste Tellings Tafel STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Stellings STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Stellings STR_INTRO_ONLINE_CONTENT :{BLACK}Soek aanlyn STR_INTRO_SCRIPT_SETTINGS :{BLACK}AI/Spel Skript Instellings STR_INTRO_QUIT :{BLACK}Verlaat STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Begin nuwe spel. Ctrl+klik ignoreer kaart konfigurasie STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Laai 'n gestoorde spel STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Begin 'n nuwe spel en gebruik 'n reliëfkaart om die land te skep STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Begin 'n nuwe speletjie, met 'n doelgeboude scenario STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Skep 'n doelgeboude spel wêreld/scenario STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Begin 'n multispeler spel STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Kies 'matige' klimaat STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Kies sub-arktiese' klimaat STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Kies 'subtropiese' klimaat STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Kies 'speelgoedland' klimaat STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Vertoon speletjie opsies STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Vertoon hoogste tellings tafel STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Vertoon instellings STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Wys NewGRF stellings STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Kyk vir nuwe of bygewerkde inhoud om af te laai STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Vertoon AI/Spel skript konfigurasie STR_INTRO_TOOLTIP_QUIT :{BLACK}Verlaat 'OpenTTD' STR_INTRO_TRANSLATION :{BLACK}Die vertaling kort {NUM} string{P "" s}. Help aseblief om OpenTTD beter te maak, deur aan te sluit as 'n vertaaler. Sien die readme.txt vir meer inligting. # Quit window STR_QUIT_CAPTION :{WHITE}Verlaat STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Is u seker u wil OpenTTD verlaat en terug keer na {STRING}? STR_QUIT_YES :{BLACK}Ja STR_QUIT_NO :{BLACK}Nee # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Verlaat Spel STR_ABANDON_GAME_QUERY :{YELLOW}Is jy seker jy wil die speletjie verlaat? STR_ABANDON_SCENARIO_QUERY :{YELLOW}Is jy seker jy wil die scenario verlaat? # Cheat window STR_CHEATS :{WHITE}Kullery STR_CHEATS_TOOLTIP :{BLACK}Keuseblokkies wys aan as jy die kulkode voorheen gebruik het STR_CHEATS_WARNING :{BLACK}Waarskuwing! U staan op die punt om jou mededinger te veraai. Hou in gedagte dat so 'n skande vir ewigheid sal onthou word. STR_CHEAT_MONEY :{LTBLUE}Vermeerder geld met {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Speel as maatskappy: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Tower stootskraper (verwyder nywerhede, onbeweegbare voorwerpe): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tonnels mag vir mekaar kruis: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Straalvliegtuie sal nie (dikwels) op klein lughawe bots nie: {ORANGE} {STRING} STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Verander die maksimum kaarthoogte: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Verander die maksimum berghoogte STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Matige klimaat STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Sub-artiese landskap STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Sub-tropiese landskap STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Speelgoedland landskap STR_CHEAT_CHANGE_DATE :{LTBLUE}Verander datum: {ORANGE} {DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Verander huidige jaar STR_CHEAT_SETUP_PROD :{LTBLUE}Aktiveer modifisering van produksie waardes: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}Nuwe Kleur Skema STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Toon algemene kleurskemas STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Wys trein kleur skemas STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Toon pad voertuig kleur skemas STR_LIVERY_SHIP_TOOLTIP :{BLACK}Toon skip kleur skemas STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Toon vliegtuig kleurskemas STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Kies die primêre kleur vir die gekose skema. Ctrl+Click sal hierdie kleur kies vir elke skema STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Kies die sekondêre kleur vir die gekose skema. Ctrl+Click sal hierdie kleur kies vir elke skema STR_LIVERY_PANEL_TOOLTIP :{BLACK}Kies 'n kleurskema om te verander, of veelvoud skemas met Ctrl+klik op die boks om die gebruik van skema te wissel STR_LIVERY_DEFAULT :Standaard kleure STR_LIVERY_STEAM :Stoomlokomotief STR_LIVERY_DIESEL :Diesellokomotief STR_LIVERY_ELECTRIC :Elektriese lokomotief STR_LIVERY_MONORAIL :Monospoorlokomotief STR_LIVERY_MAGLEV :Maglev lokomotief STR_LIVERY_DMU :Dieseltreinstel STR_LIVERY_EMU :Elektriese treinstel STR_LIVERY_PASSENGER_WAGON_STEAM :Passasierswa (Stoom) STR_LIVERY_PASSENGER_WAGON_DIESEL :Passasierswa (Diesel) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Passasierswa (Elektries) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Passasierswa (Monospoor) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Passasierswa (Maglev) STR_LIVERY_FREIGHT_WAGON :Vragwa STR_LIVERY_BUS :Bus STR_LIVERY_TRUCK :Vragmotor STR_LIVERY_PASSENGER_SHIP :Passasierskip STR_LIVERY_FREIGHT_SHIP :Vragskip STR_LIVERY_HELICOPTER :Helikopter STR_LIVERY_SMALL_PLANE :Klein vliegtuig STR_LIVERY_LARGE_PLANE :Groot vliegtuig STR_LIVERY_PASSENGER_TRAM :Passasier Trem STR_LIVERY_FREIGHT_TRAM :Vrag Trem # Face selection window STR_FACE_CAPTION :{WHITE}Gesig Keuse STR_FACE_CANCEL_TOOLTIP :{BLACK}Kanselleer nuwe gesig keuse STR_FACE_OK_TOOLTIP :{BLACK}Aanvar nuwe gesig keuse STR_FACE_RANDOM :{BLACK}Lukraake STR_FACE_MALE_BUTTON :{BLACK}Manlik STR_FACE_MALE_TOOLTIP :{BLACK}Kies manlik gesigte STR_FACE_FEMALE_BUTTON :{BLACK}Vroulik STR_FACE_FEMALE_TOOLTIP :{BLACK}Kies vroulik gesigte STR_FACE_NEW_FACE_BUTTON :{BLACK}Nuwe Gesig STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Genereer nuwe lukrake gesig STR_FACE_ADVANCED :{BLACK}Voorlopend STR_FACE_ADVANCED_TOOLTIP :{BLACK}Gevordere gesig stellings STR_FACE_SIMPLE :{BLACK}Eenvoudig STR_FACE_SIMPLE_TOOLTIP :{BLACK}Eenvoudige gesig stellings STR_FACE_LOAD :{BLACK}Laai STR_FACE_LOAD_TOOLTIP :{BLACK}Laai gunsteling gesig STR_FACE_LOAD_DONE :{WHITE}Jou gunsteling gesig is van die OpenTTD stellings lêer gelaai. STR_FACE_FACECODE :{BLACK}Speler gesig no. STR_FACE_FACECODE_TOOLTIP :{BLACK}Vertoon en/of stel speler gesig nommer STR_FACE_FACECODE_CAPTION :{WHITE}Bekyk en/of stel speler gesig nommer STR_FACE_FACECODE_SET :{WHITE}Nuwe gesig nommer kode is verstel STR_FACE_FACECODE_ERR :{WHITE}Kon nie speler gesig nommer stel nie - moet 'n nommer tussen 0 en 4,294,967,295 wees! STR_FACE_SAVE :{BLACK}Spaar STR_FACE_SAVE_TOOLTIP :{BLACK}Spaar gunsteling gesig STR_FACE_SAVE_DONE :{WHITE}Die gesig sal as u gunsteling gesig in die OpenTTD stellings lêer gespaar word. STR_FACE_EUROPEAN :{BLACK}Europiese STR_FACE_SELECT_EUROPEAN :{BLACK}Kies europese gesigte STR_FACE_AFRICAN :{BLACK}Afrikaanse STR_FACE_SELECT_AFRICAN :{BLACK}Kies Afrikaanse gesigte STR_FACE_YES :Ja STR_FACE_NO :Nee STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Aktiveer snor of oorbel STR_FACE_HAIR :Hare: STR_FACE_HAIR_TOOLTIP :{BLACK}Verander hare STR_FACE_EYEBROWS :Winkbroue: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Verander winkbroue STR_FACE_EYECOLOUR :Oog kleur: STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Verander oogkleur STR_FACE_GLASSES :Brille: STR_FACE_GLASSES_TOOLTIP :{BLACK}Aktiveer brille STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Verander brille STR_FACE_NOSE :Neus: STR_FACE_NOSE_TOOLTIP :{BLACK}Verander neus STR_FACE_LIPS :Lippe: STR_FACE_MOUSTACHE :Snor: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Verander lippe of snor STR_FACE_CHIN :Ken: STR_FACE_CHIN_TOOLTIP :{BLACK}Verander ken STR_FACE_JACKET :Jas: STR_FACE_JACKET_TOOLTIP :{BLACK}Verander jas STR_FACE_COLLAR :Kraag: STR_FACE_COLLAR_TOOLTIP :{BLACK}Verander kraag STR_FACE_TIE :Das: STR_FACE_EARRING :Oorbel: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Verander das of oorbel # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multispeler STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Openbaar STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Kies tussen 'n openbare (internet) of 'n plaaslike (LAN) spel STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Nee STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Ja STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Speler naam: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Die is die naam waarmee ander spelers sal jou aanwys STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Naam STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Naam van die speletjie STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Kliënte STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Kliënte aanlyn / maks kliënte{}Maatskappye aanlyn / maks maatskappye STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Kaart groote STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Kaartgrootte van die speeletjie{}Klik om volgens area te sorteer STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Datum STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Huidigge datum STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Jare STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Hoeveelheid jaar{}wat die speeletjie hardloop STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Taal, bediender verwerking, ens. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Klik 'n speletjie in die lys om dit te kies STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Die bedienaar wat jy laaste aan deelgeneem het STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Die bedienaar wat jy laaste op gespeel het STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}SPEL INFORMASIE STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Kliënte: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Taal: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Landskap: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Kaart groote: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Verskaffer weergawe: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Verskaffer adres: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Begin datum: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Huidige datum: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Wagwoord beskerm! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}VERSKAFFER AFLYN STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}VERSKAFFER VOL STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}HERSIENING MISPAS STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF MISPAS STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Verbind spel STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Vervris verskaffer STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Vervris die verskaffer inligting STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Soek bediener STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Versoek netwerk vir 'n verskaffer STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Voeg bediender by STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Voeg 'n verskaffer by die lys wat altyd ondersoek sal word vir speletjies wat reeds aan die gang is STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Begin bediener STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Begin u eie verskaffer STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Tik in jou naam STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Invoeg die adres van die gasheer # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}Begin nuwe multispeler speletjie STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Spel naam: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Die spel naam sal vertoon word na ander spelers in die multispeler keuse STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Stel wagwoord STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beskerm jou spel met 'n wagwoord as jy wil dit nie publieke toepassing laat wees nie STR_NETWORK_START_SERVER_UNADVERTISED :Nee STR_NETWORK_START_SERVER_ADVERTISED :Ja STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} Klient{P "" e} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimum aantal kliënte: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Kies die maksimum aantal kliënte. Alle posisies hoef nie vol te wees nie STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} Maatskap{P py pye} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Maksimum aantal maatskappye: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Beperk die verskaffer na 'n sekere bedrag van maatskappye STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} aanskouer{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Maksimum aantal toekouers: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Beperk die verskaffer na 'n sekere bedrag van aanskouers STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Taal gepraat: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Ander spelers sal weet watter taal op die verskaffer gepraat is STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Tik 'n naam in vir die netwerk speeletjie # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :Enige STR_NETWORK_LANG_ENGLISH :Engels STR_NETWORK_LANG_GERMAN :Duits STR_NETWORK_LANG_FRENCH :Frans STR_NETWORK_LANG_BRAZILIAN :Brazilian STR_NETWORK_LANG_BULGARIAN :Bulgarian STR_NETWORK_LANG_CHINESE :Chinese STR_NETWORK_LANG_CZECH :Czech STR_NETWORK_LANG_DANISH :Danish STR_NETWORK_LANG_DUTCH :Dutch STR_NETWORK_LANG_ESPERANTO :Esperanto STR_NETWORK_LANG_FINNISH :Finnish STR_NETWORK_LANG_HUNGARIAN :Hungarian STR_NETWORK_LANG_ICELANDIC :Icelandic STR_NETWORK_LANG_ITALIAN :Italian STR_NETWORK_LANG_JAPANESE :Japanese STR_NETWORK_LANG_KOREAN :Korean STR_NETWORK_LANG_LITHUANIAN :Lithuanian STR_NETWORK_LANG_NORWEGIAN :Norwegian STR_NETWORK_LANG_POLISH :Polish STR_NETWORK_LANG_PORTUGUESE :Portuguese STR_NETWORK_LANG_ROMANIAN :Romanian STR_NETWORK_LANG_RUSSIAN :Russian STR_NETWORK_LANG_SLOVAK :Slovak STR_NETWORK_LANG_SLOVENIAN :Slovenian STR_NETWORK_LANG_SPANISH :Spanish STR_NETWORK_LANG_SWEDISH :Swedish STR_NETWORK_LANG_TURKISH :Turkish STR_NETWORK_LANG_UKRAINIAN :Ukrainian STR_NETWORK_LANG_AFRIKAANS :Afrikaans STR_NETWORK_LANG_CROATIAN :Croatian STR_NETWORK_LANG_CATALAN :Catalan STR_NETWORK_LANG_ESTONIAN :Estonian STR_NETWORK_LANG_GALICIAN :Galician STR_NETWORK_LANG_GREEK :Grieks STR_NETWORK_LANG_LATVIAN :Latvian ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multispeler spel tuiste STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Berei tans voor om te verbind: {ORANGE}{STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}'n Lys van alle ondernemings tans in hierdie speletjie. U kan een van beide sluit aan een of begin 'n nuwe een indien daar is 'n vry maatskappy gleuf STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}MAATSKAPPY INFORMASIE STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Maatskappy naam: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Inwyding: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Maatskappy boekwaarde: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Huidige kontantvloei: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Vorige jaar se inkomste: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Werkverrignting: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Voertuie: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Stasies: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Spelers: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}Nuwe Maatskappy STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Skep 'n nuwe maatskappy STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Aanskou speletjie STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Bekyk die spel as 'n aanskouer STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Verbind maatskappy STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Hulp om die maatskappy te bestuur # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}Besig om the konnek... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Verbind tans... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Word tans geverifieer... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Wagtend... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Laai tans kaart af... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Data word tans verwerk... STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Registreer tans... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Spel inligting word verkry... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Maatskappy inligting word verkry... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} Klient{P "" e} voor jou STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} afgelaai tot dusver STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} afgelaai dusver STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Loskoppel STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Verskaffer is beskerm. Voer wagwoord in STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Maatskappy is beskerm. Voer wagwoord in # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Klient Lys STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Toeskou STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}Nuwe maatskapy # Network client list STR_NETWORK_CLIENTLIST_KICK :Skop STR_NETWORK_CLIENTLIST_BAN :Verbod STR_NETWORK_CLIENTLIST_GIVE_MONEY :Gee geld STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Praat met almal STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Praat met maatskappy STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privaate boodskap STR_NETWORK_SERVER :Verskaffer STR_NETWORK_CLIENT :Klient STR_NETWORK_SPECTATORS :Aanskouers STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Sleutel die bedrag geld in wat u wil gee STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Toeskouer # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Moenie die ingesleutelde wagwoord bewaar nie STR_COMPANY_PASSWORD_OK :{BLACK}Gee die maatskappy die nuwe wagwoord STR_COMPANY_PASSWORD_CAPTION :{WHITE}Maatskappy wagwoord STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Voorbepaalde maatskappy wagwoord STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Gebruik die maatskapy wagwoord as die standaard vir nuwe maatskappye # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}Bind STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Bind en speel as maatskapy STR_COMPANY_VIEW_PASSWORD :{BLACK}Wagwoord STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Beskerm maatskappy met wagwoord om te verhoed dat ongemagtigde spelers toegang verkry STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Stel maatskappy wagwoord # Network chat STR_NETWORK_CHAT_SEND :{BLACK}Stuur STR_NETWORK_CHAT_COMPANY_CAPTION :[Span] : STR_NETWORK_CHAT_CLIENT_CAPTION :[Privaat] {STRING}: STR_NETWORK_CHAT_ALL_CAPTION :[Almal] : STR_NETWORK_CHAT_COMPANY :[Span] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_COMPANY :[Span] Na {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_CLIENT :[Privaat] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_CLIENT :[Privaat] Na {STRING}:{WHITE}{STRING} STR_NETWORK_CHAT_ALL :[Almal] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}Tik boodskap vir klets # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Geen netwerk ontwerp gevind of voldoen sonder ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}Kan nie enige netwerk speletjies vind nie STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Die verskaffer het nie die versoek geantwoord nie STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Kan nie konnekteer te danke aan newgrf mispas nie STR_NETWORK_ERROR_DESYNC :{WHITE}Netwerk-Spel sinchroniseering gedop STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Netwerk-Spel verbinding verloor STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Kan nie spaarspel laai nie STR_NETWORK_ERROR_SERVER_START :{WHITE}Verskaffer kan nie aangesit word nie STR_NETWORK_ERROR_CLIENT_START :{WHITE}Kan nie verbinding kry nie STR_NETWORK_ERROR_TIMEOUT :{WHITE}Verbinding #{NUM} het betyds uitgeloop STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}A protokol-fout was gemaak en die verbinding was verlore STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Die hersiening van die klient is nie gelyk aan die verskaffer se hersiening nie STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Verkeerde wagwoord STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Die verskaffer is vol STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Jy is verban op hierdie server STR_NETWORK_ERROR_KICKED :{WHITE}Jy is van die spel geskop STR_NETWORK_ERROR_CHEATER :{WHITE}Kullery word nie toegelaat op hierdie bediener STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Jy het te veel opdragte na die bediener gestuur STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE} Jy het te lank gevat om die wagwoord in te sleutel STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE} Jou rekenaar is te stadig om met bediener by te hou STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Jou rekenaar het te lank gevat om die kaart af te laai STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Jou rekenaar het te lank gevat om met die bediener te bind ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :algemeen fout STR_NETWORK_ERROR_CLIENT_DESYNC :desync fout STR_NETWORK_ERROR_CLIENT_SAVEGAME :kan nie kaart laai nie STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :verbinding verloor STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :protokol fout STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF mispas STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :nie gemagtig nie STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :vreemde of onverwagte pakket gekry STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :verkeerde hersiening STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :naam reeds in gebruik STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :verkeerde wagwoord STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :verkeerde maatskapy-id in DoenBevel STR_NETWORK_ERROR_CLIENT_KICKED :geskop deur die bediener STR_NETWORK_ERROR_CLIENT_CHEATER :het probeer kul STR_NETWORK_ERROR_CLIENT_SERVER_FULL :verskaffer vol STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :het te veel opdragte gestuur STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :het geen wagwoord betyds gekry nie STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :algemene tyduit STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :die kaart af laai het te lank gevat STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :verwerking van die kaart het te lank gevat ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Moontlike verbinding verlore STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}Die laaste {NUM} seconde{P "" s} geen data het van die bediener gekom nie # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Spel geonderbreek ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Spel nog steeds geonderbreek ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Spel nog steeds geonderbreek ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Spel nog steeds geonderbreek ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Spel steeds onderbreek ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Spel gaan weer aan ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :hoeveelheid spelers STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :besig om kliënte te verbind STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :met die hand STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :speletjie skrif ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :verlaat STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} het by die spel aangesluit STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} het die spel aangesluit (Client #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} het by maatskappy #{2:NUM} aangesluit STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} het aangesluit by die spektators STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} het 'n nuwe maatskappy gestig (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} het die spel verlaat ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} het sy/haar naam verander na {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} het jou besigheid {2:CURRENCY_LONG} gegee STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Jy het {1:STRING} {2:CURRENCY_LONG} gegee STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Die verskaffer het die sessie toegemaak STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Die verskaffer is besig om te weerbegin...{}Wag asb... # Content downloading window STR_CONTENT_TITLE :{WHITE}Laai Inhoud af STR_CONTENT_TYPE_CAPTION :{BLACK}Tipe STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Tipe inhoud STR_CONTENT_NAME_CAPTION :{BLACK}Naam STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Naam van die inhoud STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Klik op 'n ry om besonderhede te sien{}Klik op die merkblokkie om dit te kies vir aflaai STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Selekteer alles STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Merk al die inhoud wat afgelaai moet word STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Selekteer opgraderings STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Merk alle inhoud wat 'n opgradering is vir bestande inhoud om af te laai word STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Onselekteer alles STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Merk alle inhoud wat nie afgelaai moet word nie STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Soek deur eksterne webwerwe STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Soek vir inhoud wat nie op OpenTTD's se inhoudsdiens beskikbaar is nie op bedieners wat geen verbintenis aan OpenTTD het nie STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Jy gaan OpenTDD verlaat! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Die voorwaardes om inhoud van ander bedieners af te laai wissel.{}Verwys na die eksterne webwerf vir instruksies om die inhoud in OpenTTD in te laai.{}Wil jy voortgaan? STR_CONTENT_FILTER_TITLE :{BLACK}Merker/naam filter: STR_CONTENT_OPEN_URL :{BLACK}Besoek webblad STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Besoek die webwerf vir hierdie inhoud STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Laai af STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Begin om die geselekteerde inligting af te laai STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Totale aflaai groote: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}INHOUD INFORMASIE STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Jy het nie dit geselekteer om af te laai nie STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Jy het dit geselekeer om af te laai STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Heirde afhanklikheid was gekies om afgelaai te wees STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Jy het hierdie reeds STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}Heirde inhoud is onbekend en kan afgelaai word in OpenTTD STR_CONTENT_DETAIL_UPDATE :{SILVER}Hierdie is 'n vervanging van 'n bestaande {STRING} STR_CONTENT_DETAIL_NAME :{SILVER}Naam: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Weergawe: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Beskrywing: {WHITE}{STRING} STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}Tipe: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}Aflaai groote: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Geselekteer weens: {WHITE}{STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Afhanklikes: {WHITE}{STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Merkers: {WHITE}{STRING} STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD word gebou sonder "zlib" ondersteuning... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... aflaai van inhoud is nie moentlik nie! # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :Basis-grafikastel STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :AI STR_CONTENT_TYPE_AI_LIBRARY :AI biblioteek STR_CONTENT_TYPE_SCENARIO :Scenario STR_CONTENT_TYPE_HEIGHTMAP :Reliëfkaart STR_CONTENT_TYPE_BASE_SOUNDS :Basis klanke STR_CONTENT_TYPE_BASE_MUSIC :Basis musiek STR_CONTENT_TYPE_GAME_SCRIPT :Speletjie Skrif STR_CONTENT_TYPE_GS_LIBRARY :GS biblioteek # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Laai inhoud af... STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Versoek lêer... STR_CONTENT_DOWNLOAD_FILE :{WHITE}Nou besig om {STRING} af te laai ({NUM} of {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Aflaai voltooi STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} van {BYTES} afgelaai ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Kon nie na die inhoud diener verbind nie... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Aflaai onsuksesvol... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... verbinding verloor STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... lêer nie skryfbaar nie STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Kon nie die afgelaaide lêer dekompakteer STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Vermis grafika STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD het grafike nodig om the funksioneer maar kon niks vind nie. Wil jy hê dat OpenTTD grafike aflaai en instaleer? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Ja, laai die grafika af STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Nee, verlaat OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Deursigtigheid Opsies STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Wissel deursigtigheid vir stasietekens. Ctrl+klik om te sluit STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Wissel deursigtigheid vir bome. Ctrl+klik om te sluit STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Wissel deursigtigheid vir huise. Ctrl+klik om te sluit STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Wissel deursigtigheid van nywerhede. Ctrl+klik om te sluit STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Skakel deursigtigheid vir items soos stasies, diensstasie, roetebakens en kraglyne. Ctrl+klik om te sluit STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Wissel deursigtigheid vir brûe. Ctrl+klik om te sluit STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Wissel deursigtigheid vir strukture soos vuurtorings en seintorings. Ctrl+klik om te sluit STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Wissel deursigtigheid van kraglyne. Ctrl+klik om te sluit. STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Wissel deursigtigheid vir laai aanwysers. Ctrl+klik om te sluit STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Stel voorwerpe onsigbaar inplaas van deursigtig # Linkgraph legend window STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Vragverspreidingsleutel STR_LINKGRAPH_LEGEND_ALL :{BLACK}Almal STR_LINKGRAPH_LEGEND_NONE :{BLACK}Geen STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Kies maatskappye om te ws # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}ongebruik STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}versadig STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}oorlaai # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Dekking area verlig STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Af STR_STATION_BUILD_COVERAGE_ON :{BLACK}Aan STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Moenie die dekking area van die voorgestelde bouterrein verlig nie STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Verlig dekking area van die voorgestelde bouterrein STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Aanvaar: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Verskaf: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Sluit by stasie aan STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Bou 'n aparte stasie STR_JOIN_WAYPOINT_CAPTION :{WHITE}Verbind roetebaken STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Bou 'n aparte roetebaken # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Spoorwegkonstruksie STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Elektriese spoorwegkonstruksie STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Monospoor Konstruksie STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Magneetsweeftrein Konstruksie STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Bou spore. Ctrl skakel Bou/verwydering van spoorwegkonstruksie. Shift skakel Bou/wys koste beraming STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Gebruik Outo-bou om spoorweg te bou. Ctrl kies tussen bou/verwyder. Shift kies tussen bou/kwotasie STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Bou trein diensstasie (om treine te koop en te diens). Shift kies tussen bou/kwotasie STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Verander treinspoor na baken. Druk Ctrl om bakens saam te voeg. Shift kies tussen bou/kwotasie STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Bou treinstasie. Ctrl voeg stasies saam. Shift vir kwotasie STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Bou treinspoor aanwysers. Ctrl kies tussen seinpaal/robot{} Klik en sleep om aanwysers al langs 'n reguit treinspoor te bou. Druk Ctrl om aanwysers tot by die volgende aansluiting te bou{}Ctrl+klik maak die aanwyserstellingvenster oop. Shift kies tussen bou/kwotasie STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Bou spoorweg brug. Shift skakel Bou/wys koste beraming STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Bou spoorweg tonnel. Shift skakel Bou/wys koste beraming STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Wissel bou/verwyder vir spore roetebakens en seinligte STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Verander die treinspoor tipe. Shift kies tussen bou/kwotasie STR_RAIL_NAME_RAILROAD :Spoorweg STR_RAIL_NAME_ELRAIL :Elektriese spoor STR_RAIL_NAME_MONORAIL :Monospoor STR_RAIL_NAME_MAGLEV :Maglev # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Trein Depot Orientasie STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Kies spoorweg depot orientasie # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Roetebaken STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Kies tipe roetebaken # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Spoor Stasie Keuse STR_STATION_BUILD_ORIENTATION :{BLACK}Orientasie STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Kies treinstasie orientasie STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Aantal spore STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Kies die aantal peronne wat in die stasie gebou gaan word STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Perron lengte STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Kies treinstasie lengte STR_STATION_BUILD_DRAG_DROP :{BLACK}Sleep & Drop STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Bou 'n stasie gebruikend sleep & drop STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Kies 'n stasie klas om te vertoon STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Kies die stasie tipe om te bou STR_STATION_CLASS_DFLT :Verstek stasie STR_STATION_CLASS_WAYP :Roetebakens # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Sein seleksie STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Blok aanwyser (seinpaal){}Die eenvoudigste tipe aanwyser, laat slegs een trein in 'n blok toe STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Ingang Sinjaal (semafoor){}Wys groen so lank die volgende gedeelte treinspoor 'n groen uitgang sinjaal het, anders wys dit rooi. STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Uitgang Sinjaal (semafoor){}Werk soos 'n blok sinjaal maar word benodig om die regte kleur te aktiveer op kombinasie en ingang sinjale. STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Kombinasie Sinjaal (semafoor){}Dien as 'n ingang sinjaal sowel as 'n uitgang sinjaal. Groot uitbreidings van pre-sinjale kan hiermee gebou word. STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Pad aanwyser (seinpaal){}Laat meer as een trein per blok toe solank die trein 'n bestemming veilig kan bereik. Gewone pad aanwysers word geïgnoreer as 'n trein in die teenoorgestelde rigting ry STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}Een-rigting pad aanwyser (seinpaal){}Laat meer as een trein per blok toe solank die trein 'n bestemming veilig kan bereik. 'n Een-rigting pad aanwysers laat verkeer slegs in een rigting toe STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Blok aanwyser (robot){}Die eenvoudigste tipe aanwyser, laat slegs een trein per blok toe STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Ingang Sinjaal (elektries){}Vertoon groen solank die volgende gedeelte treinspoor 'n groen uitgang sinjaal het, anders wys dit rooi. STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Uitgang Sinjaal(robot){}Werk soos 'n blok sinjaal maar word benodig om die regte kleur te aktiveer op kombinasie en ingang sinjale. STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Kombinasie Sinjaal (elektries){}Dien as 'n ingang sinjaal sowel as 'n uitgang sinjaal. Groot uitbreidings van pre-sinjale kan hiermee gebou word. STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Pad aanwyser (robot){}Laat meer as een trein per blok toe solank die trein 'n bestemming veilig kan bereik. Gewone pad aanwysers word geïgnoreer as 'n trein in die teenoorgestelde rigting ry STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Een-rigting pad aanwyser (robot){}Laat meer as een trein per blok toe solank die trein 'n bestemming veilig kan bereik. 'n Een-rigting pad aanwysers laat verkeer slegs in een rigting toe STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Verander Sinjaal{}Klik op 'n bestaande sinjaal om dit na die verkose tipe te verander, Ctrl+klik om na die bestaande tipe te verander. Shift+klik vir kwotasie STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Sein sleep digtheid STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Verminder sein sleep digtheid STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Verhoog sein sleep digtheid # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Kies Spoor Brug STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Selekteer Pad Brug STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Brugkeuring - klik op jou verkose brug om dit te bou STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :Kabelstut, Staal STR_BRIDGE_NAME_GIRDER_STEEL :Balk, Staal STR_BRIDGE_NAME_CANTILEVER_STEEL :Vrydraer, Staal STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Kabelstut, Beton STR_BRIDGE_NAME_WOODEN :Houterig STR_BRIDGE_NAME_CONCRETE :Beton STR_BRIDGE_NAME_TUBULAR_STEEL :Buisvormige, Staal STR_BRIDGE_TUBULAR_SILICON :Buis, Silikon # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Pad Konstruksie STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tremweg Konstruksie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Bou pad afdeling. Ctrl skakel bou/verwydering van pad konstruksie. Shift skakel Bou/wys koste beraming STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Bou tremweg afdeling. Ctrl skakel bou/verwydering van tremweg konstruksie. Shift skakel Bou/wys koste beraming STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Gebruik outo-pad om paaie te bou. Ctrl kies tussen bou/verwyder, Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Gebruik outo-tremspoor om tremspoor te bou. Ctrl kies tussen bou/verwyder, Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Bou voertuig diensstasie (om voertuie te koop en te diens). Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Bou trem diensstasie (om trems te koop en te diens). Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Bou bus stasie. Druk Ctrl om stasies aan mekaar te las, Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Bou trem passasier stasie. Druk Ctrl om stasies aan mekaar te las, Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Bou vragmotor stasie. Druk Ctrl om stasies aan mekaar te las, Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Bou trem vrag stasie. Druk Ctrl om stasies aan mekaar te las, Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Aktifeer/Deaktifeer ee-rigting paaie STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Bou pad brug. Shift skakel tussen bou/aanduiding koste beraming STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Bou tremweg brug. Shift skakel Bou/wys koste beraming STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Bou pad tonnel. Shift skakel tussen bou/aanduiding koste beraming STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Bou tonnel. Shift kies tussen bou/kwotasie STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Skakel bou/verwydering van pad konstruksie STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Skakel bou/verwyder vir tremweg konstruksie # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Pad Depot Oriëntering STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Kies pad voertuig depot orientasie STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Trem Depot Orientasie STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Kies trem voertuig depot orientasie # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Bus Stasie Orientasie STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Kies bus stasie orientasie STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Vragmotor Stasie Orientasie STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Kies vragmotor laai area orientasie STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Passasier Trem Stasie Orientasie STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Kies passasier trem stasie orientasie STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Vrag Trem Stasie Orientasie STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Kies vrag trem stasie orientasie # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Kanaal konstruksie STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Waterweë STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Bou kanaale. Shift skakel tussen bou/aanduiding koste beraming STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Bou sluite. Shift skakel Bou/wys koste beraming STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Bou skeepswerf (om skepe te koop en te diens).Shift kies tussen bou/kwotasie STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Bou hawe. Druk Ctrl om hawens aan mekaar te las, Shift kies tussen bou/kwotasie STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Plaas 'n boei wat as 'n baken gebruik kan word. Shift kies tussen bou/kwotasie STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Bou kanaal. Shift kies tussen bou/kwotsie STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Bepaal water area.{}Maak 'n kanaal, tensy CTRL is ingehou teen seevlak, dan sal dit vloed vul die omgewings STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Maak riviere # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Skip Depot Orientasie STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Kies skip depot orientasie # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Werf # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Lughawe STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Bou lughawe. Druk Ctrl om stasies aan mekaar te las, Shift kies tussen bou/kwotsie # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Lughawe Keuse STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Kies groote/tipe van lughawe STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Lughawe klas STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Uitleg {NUM} STR_AIRPORT_SMALL :Klein STR_AIRPORT_CITY :Dorp STR_AIRPORT_METRO :Metropolitaanse STR_AIRPORT_INTERNATIONAL :Internasionaal STR_AIRPORT_COMMUTER :Pendelaar STR_AIRPORT_INTERCONTINENTAL :Tussenkontinentaal STR_AIRPORT_HELIPORT :Helihawe STR_AIRPORT_HELIDEPOT :Helidepot STR_AIRPORT_HELISTATION :Helistasie STR_AIRPORT_CLASS_SMALL :Klein lughawe STR_AIRPORT_CLASS_LARGE :Groot Lughawe STR_AIRPORT_CLASS_HUB :Spilpunt lughawe STR_AIRPORT_CLASS_HELIPORTS :Helikopter lughawe STR_STATION_BUILD_NOISE :{BLACK}Geraas gegenereer: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}Landargitektuur STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Verlaag 'n gedeelte. Klik en sleep om die gekose punt tot die gewenste vlak te verlaag. Druk Ctrl om 'n diagonale gedeelte te kies, Shift gee net 'n kwotasie STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Verhoog 'n gedeelte. Klik en sleep om die gekose punt tot die gewenste vlak te vehoog. Druk Ctrl om 'n diagonale gedeelte te kies, Shift gee net 'n kwotasie STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Klik op 'n area en sleep om die omliggende gedeelte tot dieselfde vlak te bring. Druk Ctrl om 'n diagonale gedeelte te kies, Shift gee net 'n kwotasie STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Koop grond. Shift kies tussen koop/kwotasie # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Voorwerp Keuse STR_OBJECT_BUILD_TOOLTIP :{BLACK}Selekteer voorwerp om te bou. Shift skakel gebou/wys koste beraaming STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Kies klas van die voorwerp te bou STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Voorskou van 'n voorwerp STR_OBJECT_BUILD_SIZE :{BLACK}Grootte: {GOLD}{NUM} x {NUM} teels STR_OBJECT_CLASS_LTHS :Vuurtorings STR_OBJECT_CLASS_TRNS :Stuurders # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Boome STR_PLANT_TREE_TOOLTIP :{BLACK}Kies tipe boom om te plant. Indien die teel reeds 'n boom op het sal enige tipe bome by geplant word, ongeag van die gekose tipe STR_TREES_RANDOM_TYPE :{BLACK}Bome van lukraake tipe STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Plant bome van enige soort. Shift kies tussen bou.kwotasie STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Lukraak Boome STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Beplant bome lukraak oor die landskap # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generasie STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Plaas rots areas op landskap STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Bepaal woestyn gebied.{}Hou Ctrl in om te verwyder STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Vergroot gebied wat verlaag/verhoog moet word STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Verminder gebied wat verlaag/verhoog moet word STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Genereer lukraake land STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Skep 'n nuwe scenario STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Herstel landskap STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Verwyder alle maatskappy eiendom van die kaart af STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Herstel Landskap STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Is jy seker jy wil alle maatskappy eiendom verwyder? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}Dorp Generasie STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}Nuwe Dorp STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Stig nuwe dorp. Shift+klik om kwotasie te wys STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Lukraak Dorp STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Bou dorp op 'n lukraak ligging STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Baie lukraak dorpe STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Maak die kaart vol met wildweg geplaased dorpe STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Dorp naam: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Tik in dorp naam STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Klik om dorpsnaam in te voer STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Lukraak naam STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Genereer nuwe lukrake naam STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Dorp groote: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Klein STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Middelmatig STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Groot STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Lukraak STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Kies dorp groote STR_FOUND_TOWN_CITY :{BLACK}Stad STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Stede groei viniger as gewone dorpe{}Afhangende van stellings, is hulle grooter waneer hulle gestig word STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Straat uitleg van dorp: STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Kies straat uitleg wat vir die dorp gebruik word STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Oorspronklik STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Beter strate STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 grid STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 grid STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Lukraak # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Konsolideer nuwe nywerheid STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Kies die paslike nywerheid van hierdie lys STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Baie luraak nywehede STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Maak die kaart vol met wildweg geplaased nywerhede STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Koste: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospek STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Bou STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Fonds # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Nywerheid ketting vir {STRING} nywerheid STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Nywerheid ketting vir {STRING} vrag STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Vervaardiging van nywerhede STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Aanvaar nywerhede STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Huise STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Klik op die nywerheid om sy verskaffers en kliënte te sien STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Klik op die vrag om verskaffers en kliënte te sien STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Vertoon Ketting STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Vertoon vrag voorsiening en aanvaar nywerhede STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Verbinding na kleinkaart STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Selekteer die vertoonde industrie ook op die kleinkaart STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Selekteer vrag STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Selekteer die vrag om te vertoon STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Kies die nywerheid STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Kies die nywerheid om te vertoon # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Land gebied informasie STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Koste om skoon te maak: {LTBLUE}N/A STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Koste om skoon te maak: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Wins waneer skoon maak: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :N/A STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Eienaar: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Pad eienaar: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tremweg eienaar: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Spoorweg eienaar: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Plaaslike raad: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Geen STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koördinate: {LTBLUE}{NUM}x{NUM}x{NUM} ({STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Gebou: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stasie klas: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stasie tiepe: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Lughawe klas: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Lughawe naam: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Lughawe teel naam: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NuweGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Vrag aangeneem: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Spoorlyn spoed limiet: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Pad spoedgrens: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rotse STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Ongelyke land STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Kaal land STR_LAI_CLEAR_DESCRIPTION_GRASS :Gras STR_LAI_CLEAR_DESCRIPTION_FIELDS :Velde STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Sneeu-bedekte land STR_LAI_CLEAR_DESCRIPTION_DESERT :Woestyn STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} spoor STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} spoor met blok seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} spoor met voor-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} spoor met uitgang-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} spoor met kombinasie-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} spoor met roete seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} spoor met een-rigting pad seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} spoor met blok en voor-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} spoor met blok en uitgang-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} spoor met blok en kombinasie-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} spoor met blok en pad seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} spoor met blok en een-rigting pad seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} spoor met voor en uitgang seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} spoor met voor en kombinasie-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} spoor met voor en pad-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} spoor met voor en een-rigting pad seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} spoor met uitgang en kombinasie-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} spoor met uitgang en pad-seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} spoor met uitgang en een-rigting pad seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} spoor met kombinasie en pad seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} spoor met kombinasie en eenrigting-pad seine STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} spoor met pad en een-rigting pad seine STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} trein diensstasie STR_LAI_ROAD_DESCRIPTION_ROAD :Pad STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Pad met straatligte STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Boom-belynde pad STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Pad voertuig depot STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Pad/spoor vlak kruising STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tremweg # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (onder konstruksie) STR_LAI_TREE_NAME_TREES :Boome STR_LAI_TREE_NAME_RAINFOREST :Reenwoud STR_LAI_TREE_NAME_CACTUS_PLANTS :Kaktus Plante STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Treinstasie STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Vliegtuig hangar STR_LAI_STATION_DESCRIPTION_AIRPORT :Lughawe STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Vragmotor laai area STR_LAI_STATION_DESCRIPTION_BUS_STATION :Bus stasie STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Skip werf STR_LAI_STATION_DESCRIPTION_BUOY :Baken STR_LAI_STATION_DESCRIPTION_WAYPOINT :Roetebaken STR_LAI_WATER_DESCRIPTION_WATER :Water STR_LAI_WATER_DESCRIPTION_CANAL :Kanaal STR_LAI_WATER_DESCRIPTION_LOCK :Sluis STR_LAI_WATER_DESCRIPTION_RIVER :Rivier STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Kus of oewer STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Skip depot # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Spoorweg tonnel STR_LAI_TUNNEL_DESCRIPTION_ROAD :Pad tonnel STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Staal stuspensie spoor brug STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Staal balk spoor brug STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Staal vrydraer spoor brug STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Beton kabelstut spoorwegbrug STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Houterig spoor brug STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Beton spoor brug STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Buis spoor brug STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Staal suspensie pad brug STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Staal balk pad brug STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Staal vrydraer pad brug STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Versterk beton suspensie pad brug STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Houterig pad brug STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Beton pad brug STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Buis pad brug STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Akwamaryn STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Sender STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Vuurtoring STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Maatskappy Hoofkwartier STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Maatskappy-besitte land # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}Oor OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Oorspronklike kopiereg {COPYRIGHT} 1995 Chris Sawyer, Alle regte voorbehou STR_ABOUT_VERSION :{BLACK}OpenTTD uitgawe {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2015 Die OpenTTD span # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Spaar Spel STR_SAVELOAD_LOAD_CAPTION :{WHITE}Laai Spel STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Stoor Scenario STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Laai Scenario STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Laai reliëfkaart STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Stoor reliëfkaart STR_SAVELOAD_HOME_BUTTON :{BLACK}Klik hier om na die huidige spaar/laai lêer te gaan STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} vry STR_SAVELOAD_LIST_TOOLTIP :{BLACK}Lys van skywe, gidse en spaar-speletjie lêers STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Huidige naam vir spaar-speletjie STR_SAVELOAD_DELETE_BUTTON :{BLACK}Uitvee STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Vee die huidige verkieste spaar-speletjie uit STR_SAVELOAD_SAVE_BUTTON :{BLACK}Spaar STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Spaar die huidige speletjie, met die verkieste naame STR_SAVELOAD_LOAD_BUTTON :{BLACK}Laai STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Laai die geselekteerde spel STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP :{BLACK}Laai die gekose reliëfkaart STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Spel Besonderhede STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Geen inligting beskikbaar STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}Tik 'n naam in vir die stoor-speeletjie # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}Wêreld generasie STR_MAPGEN_MAPSIZE :{BLACK}Kaart groote: STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Kies kaartgrootte teëls. Die aantal werklike beskikbare teëls sal ietwat minder wees. STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Hoev. dorpe: STR_MAPGEN_DATE :{BLACK}Datum: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Hoev. nywerhede: STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}Maksimum kaarthoogte STR_MAPGEN_MAX_HEIGHTLEVEL_UP :{BLACK}Verhoog berge met een teël STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN :{BLACK}Verminder berghoogte met een teël STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Sneeu lyn hoogte: STR_MAPGEN_SNOW_LINE_UP :{BLACK}Beweeg die sneeu lyn een op STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Beweeg die sneeu lyn een af STR_MAPGEN_LAND_GENERATOR :{BLACK}Land genereerder: STR_MAPGEN_TREE_PLACER :{BLACK}Boom algoritme: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Terrein tipe: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Seevlak: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Riviere: STR_MAPGEN_SMOOTHNESS :{BLACK}Gladheid: STR_MAPGEN_VARIETY :{BLACK}Verskeidenheid verspreiding: STR_MAPGEN_GENERATE :{WHITE}Genereer # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}Kaart kante: STR_MAPGEN_NORTHWEST :{BLACK}Noordwes STR_MAPGEN_NORTHEAST :{BLACK}Noordoos STR_MAPGEN_SOUTHEAST :{BLACK}Suidoos STR_MAPGEN_SOUTHWEST :{BLACK}Suidwes STR_MAPGEN_BORDER_FREEFORM :{BLACK}Vryeform STR_MAPGEN_BORDER_WATER :{BLACK}Water STR_MAPGEN_BORDER_RANDOM :{BLACK}Lukraak STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Lukraak STR_MAPGEN_BORDER_MANUAL :{BLACK}Handmatig STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Reliëfkaart orientasie: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Reliëfkaart naam: STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Grootte: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT :{WHITE}Verander maksimum kaarthoogte STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Verander sneeu lyn hoogte STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Verander begin jaar # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}Scenario tipe STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Plat terrein STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Genereer 'n plat terrein STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Lukraake land STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Hoogte van plat terrein: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Beweeg die hoogte van plat terrein een af STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Beweeg die hoogte van plat terrein een op STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Verander die hoogte van plat terrein # Map generation progress STR_GENERATION_WORLD :{WHITE}Wêreld word gevorm... STR_GENERATION_ABORT :{BLACK}Staak STR_GENERATION_ABORT_CAPTION :{WHITE}Verlaat Wêreld Generasie STR_GENERATION_ABORT_MESSAGE :{YELLOW}Wil jy rêrig die landskepping verlaat? STR_GENERATION_PROGRESS :{WHITE}{NUM}% klaar STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}Wêreld generasie STR_GENERATION_RIVER_GENERATION :{BLACK}Rivier generasie STR_GENERATION_TREE_GENERATION :{BLACK}Boom generasie STR_GENERATION_OBJECT_GENERATION :{BLACK}Onbeweegbaar generasie STR_GENERATION_CLEARING_TILES :{BLACK}Ru en rotserig area generasie STR_GENERATION_SETTINGUP_GAME :{BLACK}Stel speletjie op STR_GENERATION_PREPARING_TILELOOP :{BLACK}Hardloop teël-herhaling STR_GENERATION_PREPARING_SCRIPT :{BLACK}Lopende skrif STR_GENERATION_PREPARING_GAME :{BLACK}Voorbereiding speletjie # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF stellings STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Gedetaileerde NewGRF inligting STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Aktiewe NewGRF lêers STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Onaktiewe NewGRF lêers STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Selekteer voorafinstelling: STR_NEWGRF_FILTER_TITLE :{ORANGE}Filter string: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Laai die gekose voorafstel STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Stoor voorafinstelling STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Stoor die huidige lys as 'n voorafstel STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Sleutel 'n naam vir die voorafstel in STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Vee voorafinstelling uit STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Vee die huidige gekose voorafstel uit STR_NEWGRF_SETTINGS_ADD :{BLACK}Voeg STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Voeg die verkiesde NewGRF lêer na u configurasie STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Herskandeer lêers STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Bywerk die lys van beskikbaar NewGRF lêers STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Verwyder STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Verwyder die gekose NewGRF lêer van die lys STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Beweeg Op STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Beweeg die gekose NewGRF op in die lys STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Beweeg Af STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Beweeg die gekose NewGRF af in die lys STR_NEWGRF_SETTINGS_UPGRADE :{BLACK}Opgradeer STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP :{BLACK}Gradeer NewGRF lêers op STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}'n Lys van die NewGRF lêers wat geïnstaleer is STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Stel parameters STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Vertoon parameters STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Skakel palet STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Skakel die palet van die geselekteurde NewGRF.{}Doen dit wanneer die grafika van hierdie NewGRF pink lyk in die speletjie. STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Wend veranderings aan STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Vind vermisde inhoud aanlyn STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Kyk of die vermisde inhoud aanlyn kan gevind word STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Lêer naam: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Weergawe: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Min. versoenbare weergawe: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palet: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parameters: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}Geen informasie beskikbaar STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Gelyke lêer nie gevind nie STR_NEWGRF_SETTINGS_DISABLED :{RED}Gedeaktiveer STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Onversoenbaar met hierdie weergawe van OpenTTD # NewGRF save preset window STR_SAVE_PRESET_CAPTION :{WHITE}Stoor voorafinstellings STR_SAVE_PRESET_LIST_TOOLTIP :{BLACK}Beskikbare voorafinstellings, kies een om te gebruik as eksemplaar vir 'n nuwe een STR_SAVE_PRESET_TITLE :{BLACK}Kies 'n naam vir die voorafinstellings STR_SAVE_PRESET_EDITBOX_TOOLTIP :{BLACK}Gekose naam om voorafstellings te stoor STR_SAVE_PRESET_CANCEL :{BLACK}Kanselleer STR_SAVE_PRESET_CANCEL_TOOLTIP :{BLACK}Moenie voorafinstellings verander nie STR_SAVE_PRESET_SAVE :{BLACK}Stoor STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Stoor die voorafinstellings na gekose naam # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Verander NewGRF parameters STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Maak Toe STR_NEWGRF_PARAMETERS_RESET :{BLACK}Herstel STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Stel alle parameters na hul verstek waarde STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parameter {NUM} STR_NEWGRF_PARAMETERS_SETTING :{STRING}: {ORANGE}{STRING} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Hoeveelheid parameters: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspekteer - {STRING} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Ouer STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Inspekteer die voorwerp van die ouer bestek STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING} by {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Voorwerp STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Spoor tipe STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF veranderlike 60+x parameter (heksadesimaal) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Belyn sprite {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Volgende sprite STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Gaan na die volgende "sprite", Ignoreer enige pseudo/her-kleur/font "sprites" en spring terug na die begin STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Gaan na sprite STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Gaan na gegewe sprite. As die sprite nie 'n normale sprite is nie, gaan na die volgende normale sprite STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Vorige sprite STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Gaan na vorige normale sprite, en ignoreer enige pseudo/her-kleur/font sprite en spring terug na die einde STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Voorstelling van geselekteerde sprite. Die belyning word geignoreer waneer sprite geteken word STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Beweeg die sprite rond, verander die X en Y afwyking STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Relatiewe herstel STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Herstel die huidige relatiewe verplasing STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}X verplasing: {NUM}, Y verplasing: {NUM} (Werklik) STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}X verplasing: {NUM}, Y verplasing: {NUM} (Relatief) STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Kies sprite STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Kies 'n sprite van enige plek op die skerm STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Gaan na sprite # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Waarskuwing: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Fout: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fataal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}'n Fataale NewGRF fout het gebeur: {}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} sal nie met die TTDPatch uitgawe rapporteer deur OpenTTD werk nie. STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} is vir die {STRING} uitgawe van TTD. STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} is onderwerp om saam met {STRING} gebruik te word STR_NEWGRF_ERROR_INVALID_PARAMETER :Ongeldig parameter vir {1:STRING}: parameter {STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} moet voor {STRING} gelaai word. STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} moet na {STRING} gelaai word. STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} vereis OpenTTD uitgawe {STRING} of beter. STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :die GRF lêer dit was ontwerp om te vertaal STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Te veel NewGRF's gelaai STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Die laai van {1:STRING} as statiese NewGRF met {STRING} kan desinkroniesasies veroorsaak. STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Onverwagte sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Onbekende Aksie 0 eiendom {4:HEX} (sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Poging on 'n ongeldige ID (sprite {3:NUM}) te gebruik STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{STRING} bevat 'n korrupte prent. Korrupte prente sal as 'n rooi vraagteken gewys word (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Bevat veelvoudige Aksie 8 inskrywings (sprite {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Lees verby die einde van die pseudo-sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :WHITE}Die huidige basis-grafikastel ontbreek sommige sprites.{}Opdateer die basis-grafikastel. STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}Die huidige basis-grafikastel ontbreek sommige sprites.{}Opdateer die basis-grafikastel.{}Aangesien jy 'n {YELLOW}ontwikkelingsweergawe van OpenTTD{WHITE} het, mag jy dalk 'n {YELLOW}ontwikkelingsweergawe{WHITE} van die basis-grafikastel benodig{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Aangevraagde GRF hulpbronne is nie beskikbaar nie (sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} was gedeaktiveer deur {2:STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Ongeldige/onbekende sprite uitleg formaat (sprite {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Versigtig! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Jy wil veranderinge aan 'n lopende spel bring. Dit kan moontlik OpenTTD of die spel toestand laat verongeluk.{}Is jy seker? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Kan nie lêer byvoeg nie: gedupliseerde GRF ID STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Gelyke lêer nie gevind nie (versoenbaar GRF gelaai) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Kan nie lêer byvoeg nie: NewGRF lêer limiet bereik STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Versoenbare GRF(s) gelaai vir vermiste lêers STR_NEWGRF_DISABLED_WARNING :{WHITE}Vermiste GRF lêers is gedeaktiveer STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}GRF leêr(s) ontbreek STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Hervatting kan veroorsaak dat OpenTTD bots. Moet nie daaropeenvolgende botsings verslae rapporteer nie. {}Will jy rêrig unpause? # NewGRF status STR_NEWGRF_LIST_NONE :Geen STR_NEWGRF_LIST_ALL_FOUND :Alle lêers teenwoordig STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Aanpasbare lêers gevind STR_NEWGRF_LIST_MISSING :{RED}Vermiste leêrs # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}Die gedrag van NewGRF '{0:STRING}' kan moontlik sinkroniesasie probleme of program ongelukke veroorsaak STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Dit het die aangedrewe-wa staat vir '{1:ENGINE}' wanneer nie in 'n depot verander STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Het lengte van voertuig verander '{1:ENGINE}' wanneer dit nie in 'n diensstasie is nie STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Dit verander voertuig kapasiteit vir '{1:ENGINE}' wanneer nie binne 'n diensstasie is nie of herstelwerk word gedoen STR_BROKEN_VEHICLE_LENGTH :{WHITE}Trein '{VEHICLE}' wat aan '{COMPANY}' behoort se lengte is ongeldig. Dit is waarskynlik veroorsaak deur 'n NewGRF. Spel kan verongeluk of sinchronisasie verloor STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' verskaf foutiewe inligting. STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Vrag/herbou inligting van '{1:ENGINE}' verskil van spesifikasies. Outo-hernu/-vervang mag moontlik nie reg werk nie STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' het 'n eindelose kring in die produksie-herroep veroorsaak STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Callback {1:HEX} het 'n ongeldige/onbekende resultaat terug gestuur {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} van STR_NEWGRF_INVALID_ENGINE : STR_NEWGRF_INVALID_INDUSTRYTYPE : # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE : # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}Skandeer NewGRFs STR_NEWGRF_SCAN_MESSAGE :{BLACK}Skandeer NewGRFs. Na mate van die hoeveelheid, kan dit 'n tydtjie neem STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF{P "" s} van omtrend {NUM} NewGRF{P "" s} is geskandeer STR_NEWGRF_SCAN_ARCHIVES :Skandering van argiewe # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}Teken Lys - {COMMA} Teken{P "" s} STR_SIGN_LIST_MATCH_CASE :{BLACK}Ooreenstemmende case STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Skakel ooreenstemmende kas wanneer teken naam vergelyk word teen die filter string # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Redigeer teken teks STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Gaan na volgende teken STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Gaan na vorige teken STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Tik 'n naam vir die teken in # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}Dorpe STR_TOWN_DIRECTORY_NONE :{ORANGE}- Geen - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Dorpname - klik op 'n naam om skerm daarna te skuif. Ctrl+klik om 'n nuwe venster vir die dorp oop te maak STR_TOWN_POPULATION :{BLACK}Wêreldbevolking: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (City) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Bevolking: {ORANGE}{COMMA}{BLACK} Huise: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Passasiers verlede maand: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Pos verlede maand: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Vrag nodig om dorp te laat groei: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} vereis STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} vereis in winter STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} afgelewer STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (steeds benodig) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (afgelewer) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Dorp groei elke {ORANGE}{COMMA}{BLACK}{NBSP}da{P g e} STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Dorp groei elke {ORANGE}{COMMA}{BLACK}{NBSP}da{P g e} (befonds) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Dorp groei {RED}nie{BLACK} STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Geraas limiet in dorp: {ORANGE}{COMMA}{BLACK} maks: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Skuif skerm na dorp toe. Ctrl+klik maak 'n nuwe venster vir die dorp oop STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Plaaslike raad STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Vertoon informasie oor plaaslike raad STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Verander dorp naam STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Brei uit STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Vergroot die grootte van dorp STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Vee uit STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Vee hierdie dorp heeltemal uit STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Hernoem Dorp # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} plaaslike raad STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Vervoer maatskappy graderings: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Aksies beskikbaar: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}Lys van dinge om te doen by hierdie dorp - klik op item vir meer besonderhede STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Doen dit STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Voeg die verlig aksie in die lys bo uit STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Klein reklame veldtog STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Medium reklame veldtog STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Groot reklame veldtog STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Befonds plaaslike pad heropbou STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Bou standbeeld van maatskappy eienaar STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Befonds nuwe geboue STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Koop eksklusiewe vervoerregte STR_LOCAL_AUTHORITY_ACTION_BRIBE :Koop die plaaslike raad om STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Begin 'n klein plaaslik advertensie veldtog, om meer passasiers en vragte tot jou vervoer dienste te lok.{}Prys: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Begin 'n middelmatige plaaslik advertensie veldtog, om meer passasiers en vrag te lok om jou diens te gebruik.{}Prys: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Begin 'n groot plaaslik advertensie veldtog, om meer passasiers en vragte tot jou vervoer dienste te lok.{}Prys: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Finansier herstel van stedelike paaie wat aansienlike verkeersprobleme sal veroorsaak.{}Koste: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW} Bou 'n standbeeld in eer van u maatskappy.{} Prys: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Finansier konstruksie van nuwe sake geboue.{}Koste: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW} Koop 1 jaar se eksklusief vervoer regte in dorp. Dorp raad sal slegs passasiers en cargo toelaat om jou maatskappy se stasies te gebruik.{} Prys: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Koop die plaaslike regering om vir 'n gunstige gradering, indien die komplot ontdek word sal 'n groot boete opgelê word.{}Cost: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Doelwitte STR_GOALS_SPECTATOR_CAPTION :{WHITE}Globale Doelwitte STR_GOALS_GLOBAL_TITLE :{BLACK}Globale doelwitte: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Geen - STR_GOALS_SPECTATOR_NONE :{ORANGE}- Nie van toepassing - STR_GOALS_PROGRESS :{ORANGE}{STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_COMPANY_TITLE :{BLACK}Maatskappy doelwitte: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klik op doel om skerm oor die industrie/stad/teël te sentreer. Ctrl+klik maak 'n nuwe venster vir die industrie/stad/teël oop # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :Vraag STR_GOAL_QUESTION_CAPTION_INFORMATION :Inligting STR_GOAL_QUESTION_CAPTION_WARNING :Waarskuwing STR_GOAL_QUESTION_CAPTION_ERROR :Fout ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Kanselleer STR_GOAL_QUESTION_BUTTON_OK :OK STR_GOAL_QUESTION_BUTTON_NO :Nee STR_GOAL_QUESTION_BUTTON_YES :Ja STR_GOAL_QUESTION_BUTTON_DECLINE :Keur af STR_GOAL_QUESTION_BUTTON_ACCEPT :Aanvaar STR_GOAL_QUESTION_BUTTON_IGNORE :Ignoreer STR_GOAL_QUESTION_BUTTON_RETRY :Probeer weer STR_GOAL_QUESTION_BUTTON_PREVIOUS :Vorige STR_GOAL_QUESTION_BUTTON_NEXT :Volgende STR_GOAL_QUESTION_BUTTON_STOP :Stop STR_GOAL_QUESTION_BUTTON_START :Begin STR_GOAL_QUESTION_BUTTON_GO :Gaan STR_GOAL_QUESTION_BUTTON_CONTINUE :Gaan voort STR_GOAL_QUESTION_BUTTON_RESTART :Begin weer STR_GOAL_QUESTION_BUTTON_POSTPONE :Stel uit STR_GOAL_QUESTION_BUTTON_SURRENDER :Gee oor STR_GOAL_QUESTION_BUTTON_CLOSE :Maak toe ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}Subsidies STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subsidies op aanbod vir diens opneming: STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} van {STRING} na {STRING}{YELLOW} (voor {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- Geen - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Dienste reeds gesubsidieer: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} van {STRING} tot {STRING}{YELLOW} ({COMPANY}{YELLOW}, tot {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klik op aanbieding om skerm na nywerheid/dorp te skuif. Ctrl+klik maak 'n nuwe venster vir die nywerheid/dorp oop # Story book window STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Storieboek STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Globale Storieboek STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :Bladsy {NUM} STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Kies 'n bladsy om na toe te gaan in hierdie lys STR_STORY_BOOK_PREV_PAGE :{BLACK}Vorige STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Vorige bladsy STR_STORY_BOOK_NEXT_PAGE :{BLACK}Volgende STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Volgende bladsy STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Ongeldige doelwit verwysing # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Stasiename - klik op 'n naam om skerm na stasie te skuif. Ctrl+klik maak 'n nuwe venster vir die stastie oop STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Hou in Ctrl om meer as een item te selekteer STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Stasie{P "" s} STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- Geen - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Kies alle fakulteite STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Kies alle vrag tipes (geen wag vrag ingesluit) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}Geen vrag van enige tipe is wagtend # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} vanaf {STATION}) STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} gereserveer vir oplaai) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Aanvaar STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Wys lys van aanvaarde vrag STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Aanvaar: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}Die stasie het eksklusiewe vervoer regte vir die dorp STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} het eksklusiewe vervoer regte in die dorp gekoop. STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Graderings STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Toon stasie graderings STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Maandelike verskaffing en plaaslike waardering: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}Groepeer STR_STATION_VIEW_WAITING_STATION :Stasie: Wagtend STR_STATION_VIEW_WAITING_AMOUNT :Hoeveelheid: Wagtend STR_STATION_VIEW_PLANNED_STATION :Stasie: Beplan STR_STATION_VIEW_PLANNED_AMOUNT :Hoeveelheid: Beplan STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} vanaf {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} via {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} na {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} vanaf onbekende stasie STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} na enige stasie STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} via enige stasie STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} vanaf hierdie stasie STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} stop by hierdie stasie STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} na hierdie stasie toe STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} sonder-stop STR_STATION_VIEW_GROUP_S_V_D :Bron-via-bestemming STR_STATION_VIEW_GROUP_S_D_V :Bron-bestemming-via STR_STATION_VIEW_GROUP_V_S_D :Via-bron-bestemming STR_STATION_VIEW_GROUP_V_D_S :Via-bestemming-bron STR_STATION_VIEW_GROUP_D_S_V :Bestemming-bron-via STR_STATION_VIEW_GROUP_D_V_S :Bestemming-via-bron ############ range for rating starts STR_CARGO_RATING_APPALLING :Haglik STR_CARGO_RATING_VERY_POOR :Baie swak STR_CARGO_RATING_POOR :Swak STR_CARGO_RATING_MEDIOCRE :Middelmagtig STR_CARGO_RATING_GOOD :Goed STR_CARGO_RATING_VERY_GOOD :Baie goed STR_CARGO_RATING_EXCELLENT :Uitstekend STR_CARGO_RATING_OUTSTANDING :Treffend ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Skuif skerm na stasie. Ctrl+klik maak 'n nuwe venster oop vir die stasie STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Verander naam van stasie STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Toon alle treine wat hierdie stasie op hul skedule het STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Toon alle pad voertuie wat hierdie stasie op hul skedule het STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Toon alle vliegtuie wat hierdie stasie op hul skedule het STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Toon alle skepe wat hierdie stasie op hul skedule het STR_STATION_VIEW_RENAME_STATION_CAPTION :Hernoem stasie/laai area STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Maak lughawe toe STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Verhoed dat vliegtuie by hierdie lughawe te land # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Senter skerm op roetebaken. Ctrl+klik maak 'n nuwe venster oop vir die roetebaken STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Verander roetebaken se naam STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Sentreer hoofuitsig op boei. Ctrl+klik maak 'n nuwe venster oop vir die boei STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Verander baken naam STR_EDIT_WAYPOINT_NAME :{WHITE}Redigeer roetebaken se naam # Finances window STR_FINANCES_CAPTION :{WHITE}{COMPANY} Finansies {BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Uitgawe/Inkomste STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Konstruksie STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}Nuwe Voertuie STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Trein Loopkoste STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Pad Voertuig Loopkoste STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Vliegtuig Loopkoste STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Skip loopkoste STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Eiendom Onderhoud STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Trein Inkomste STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Pad Voertuig Inkome STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Vliegtuig Inkome STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Skip Inkomste STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Lening Rente STR_FINANCES_SECTION_OTHER :{GOLD}Ander STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}Totaal: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bank Balans STR_FINANCES_LOAN_TITLE :{WHITE}Lening STR_FINANCES_MAX_LOAN :{WHITE}Maksimum Lening: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}Leen {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}Vermeerder groote van lening. Ctrl+Klick leen so veel as moontlik STR_FINANCES_REPAY_BUTTON :{BLACK}Betaal {CURRENCY_LONG} terug STR_FINANCES_REPAY_TOOLTIP :{BLACK}Betaal gedeelte van lening terug. Ctrl+klik betaal so veel as moontlik terug STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastruktuur # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Bestuurder) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Jaar gestig: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Kleur Skema STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Voertuie STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} trein{P "" e} STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} pad voertui{P g e} STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} vliegtuig STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} sk{P ip epe} STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}Geen STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Maatskappy waarde: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% besit by {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastruktuur: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} spoorstuk{P "" ke} STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} padstuk{P "" ke} STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} waterteël{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} stasieteël{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} lughawe{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}Geen STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Bou HK STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Bou maatskappy hoofkantore STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}Wys HK STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}Vertoon maatskappy hoofkantore STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Beweeg HK STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Bou hoofkwartier elders teen 'n koste gelykstaande aan 1% van maatskappy se waarde. Shift+klik vir kwotasie STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Besonderhede STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}Sien gedetaileerde infrastruktuur telling STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}Nuwe Gesig STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Kies nuwe gesig vir bestuurder STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Kleur Skema STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Verander die maatskappy kleure STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Maatskappy Naam STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Verander die maatskappy se naam STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Bestuurder Naam STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Verander bestuurder se naam STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Koop 25% aandeel in maatskappy STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Verkoop 25% aandeel in maatskappy STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Koop 'n 25% aandeel in maatskappy. Shift+klik vir kwotasie STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Verkoop 'n 25% aandeel in maatskappy. Shift+klik vir beraamde inkomste STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Maatskappy Naam STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Bestuurder se Naam STR_BUY_COMPANY_MESSAGE :{WHITE}Ons is opsoek na 'n vervoer maatskappy wat ons se maatskappy sal oorvat.{}{}Wil jy {COMPANY} koop vir {CURRENCY_LONG}? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY} se infrastruktuur STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Spoorstukke: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Seine STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Padstukke: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Pad STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tremweg STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Waterteëls: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanale STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stasies: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Stasieteëls STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Lughawens STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/jr # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Nywerhede STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- Geen - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}){YELLOW} ({COMMA}% vervoer) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}/{CARGO_LONG}{STRING}){YELLOW} ({COMMA}%/{COMMA}% vervoer) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Nywerheidsname - klik op 'n naam om skerm na nywerheid te skuif. Ctrl+klik maak 'n nuwe venster vir die nywerheid oop # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Produksie verlede maand: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% vervoer) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Skuif skerm na nywerheid. Ctrl+klik maak 'n nuwe venster vir die nywerheid oop STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Produksie vlak: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Die nywerheid het aangekondig dat dit binnekort gaan sluit! ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Vereis: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Vereis: {YELLOW}{STRING}{STRING}, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Vereis: {YELLOW}{STRING}{STRING}, {STRING}{STRING}, {STRING}{STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Vrag wag om geprosesseer te word: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Produseer: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Produseer: {YELLOW}{STRING}{STRING}, {STRING}{STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}Verander produksie (veelvoude van 8, tot en met 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Verander produksie vlakke (persentasie, tot 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} - {COMMA} Trein{P "" e} STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING} - {COMMA} Pad voert{P uig uie} STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING} - {COMMA} Skeep{P "" e} STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING} - {COMMA} Vliegtuie STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Treine - klik op trein vir inligting STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Padvoertuie - klik op voertuig vir inligting STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Skepe - klik op skip vir inligting STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Vliegtuie - klik op vliegtuig vir inligting STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Wins die jaar: {CURRENCY_LONG} (verlede jaar: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :Beskikbare treine STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Beskikbare Voertuie STR_VEHICLE_LIST_AVAILABLE_SHIPS :Beskikbare Skepe STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Beskikbare Vliegtuie STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}Vertoon 'n lys van beskikbare enjins vir hierdie voertiug. STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Bestuur lys STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Stuur instruksies na alle voertuie in die lys STR_VEHICLE_LIST_REPLACE_VEHICLES :Vervang voertuie STR_VEHICLE_LIST_SEND_FOR_SERVICING :Stuur vir diens STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Stuur na Depot STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Stuur na Depot STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Stuur na Depot STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Stuur na Hangar STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Klik om alle voertuie in die lys te stop STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Klik om alle voertuie in die lys aan te skakel STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Gedeel opdrae van {COMMA} Voertui{P g e} # Group window STR_GROUP_ALL_TRAINS :Alle triene STR_GROUP_ALL_ROAD_VEHICLES :Alle pad voertuie STR_GROUP_ALL_SHIPS :Alle skepe STR_GROUP_ALL_AIRCRAFTS :Alle vliegtuie STR_GROUP_DEFAULT_TRAINS :Ongegroepeerde treine STR_GROUP_DEFAULT_ROAD_VEHICLES :Ongegroepeerde pad voertuie STR_GROUP_DEFAULT_SHIPS :Ongegroepeerde skepe STR_GROUP_DEFAULT_AIRCRAFTS :Ongegroepeerde vliegtuig STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groepe - klik op 'n groep om alle voertuie in hierdie groep te lys. Sleep en los om te rangskik volgens hiërargie. STR_GROUP_CREATE_TOOLTIP :{BLACK}Klik om groep te skep STR_GROUP_DELETE_TOOLTIP :{BLACK}Vee uit die gekose groep STR_GROUP_RENAME_TOOLTIP :{BLACK}Hernoem die gekose groep STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Klik om hierdie groep teen outovervanging te beskerm STR_QUERY_GROUP_DELETE_CAPTION :{WHITE}Wis groep uit STR_GROUP_DELETE_QUERY_TEXT :{WHITE}Is jy seker jy wil hierdie groep en enige subgroepe uitwis? STR_GROUP_ADD_SHARED_VEHICLE :Voeg gedeelde voertuie STR_GROUP_REMOVE_ALL_VEHICLES :Verwyder alle voertuie STR_GROUP_RENAME_CAPTION :{BLACK}Hernoem 'n groep # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :Nuwe treine STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nuwe Elektries Spoor Voertuie STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nuwe monospoor voertuie STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nuwe Maglev Voertuie STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Spoorweg Voertuie STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nuwe Pad Voertuie STR_BUY_VEHICLE_SHIP_CAPTION :Nuwe Skepe STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nuwe Vliegtuig STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Koste: {GOLD}{CURRENCY_LONG}{BLACK} Gewig: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Spoed: {GOLD}{VELOCITY}{BLACK} Krag: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Spoed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Spoed op oseaan: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Spoed op kanaal/rivier: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Loopkoste: {GOLD}{CURRENCY_LONG}/jr STR_PURCHASE_INFO_CAPACITY :{BLACK}Kapasiteit: {GOLD}{CARGO_LONG} {STRING} STR_PURCHASE_INFO_REFITTABLE :(herboubaar) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Ontwerp: {GOLD}{NUM}{BLACK} Leeftyd: {GOLD}{COMMA} jaar STR_PURCHASE_INFO_RELIABILITY :{BLACK}Maks. betroubaarheid: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Kos: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Massa: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Kos: {GOLD}{CURRENCY_LONG}{BLACK} Spoed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Kapasiteit: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Self Krag Waens: {GOLD}+{POWER}{BLACK} Gewig: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Herboubaar na: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :Alle vrag tipes STR_PURCHASE_INFO_ALL_BUT :Alles behalwe {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Maks. Traktiewe Poging: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Afstand: {GOLD}{COMMA} teëls STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Trein kieslys - klik op voertuig vir inligting. CTRL+kliek vir wegsteek van die voertuig tipe STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Pad voertuig kieslys - klik op voertuig vir inligting. CTRL+kliek vir wegsteek van die voertuig tipe STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK} Skip keuse lys. Klik op die skip vir inligting. CTRL+klik vir die wegsteek van die skip tipe STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Vliegtuig kieslys - klik op vliegtuig vir inligting. CTRL+kliek vir wegsteek van die vliegtuig tipe STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Koop Voertuig STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Koop Voertuig STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Bou skip STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Koop vliegtuig STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose lokomotief/wa. Shift+klik vir kwotasie STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose voertuig. Shift+klik vir kwotasie STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose skip. Shift+klik vir kwotasie STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Koop die gekose vliegtuig. Shift+klik vir kwotasie STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Hernoem STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Hernoem STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Hernoem STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Hernoem STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Hernoem trein voertuig tipe STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Hernoem pad voertuig tipe STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Hernoem skip tipe STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Hernoem vliegtuig tipe STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_SHIP_HIDE_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_SHIP_SHOW_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_AIRCRAFT_SHOW_TOGGLE_BUTTON :{BLACK}Vertoon STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Skakel die wegsteek/vetrooning van die trein tipe STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Skakel die wegsteek/vetrooning van die voertuig tipe STR_BUY_VEHICLE_SHIP_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Skakel die wegsteek/vetrooning van die skip tipe STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Skakel die wegsteek/vetrooning van die vliegtuig tipe STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Hernoem trein voertuig tipe STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Hernoem pad voertuig tipe STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Hernoem skip tipe STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Hernoem vliegtuig tipe # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}Verander naam van depot STR_DEPOT_RENAME_DEPOT_CAPTION :Hernoem depot STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} voertuig{P "" s}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Treine - sleep wa met linkerknoppie om dit by die trein te voeg/wegvat, regs-klik op trein vir inligting. Hou Ctrl om altwee funksies op die volgende ketting toe te pas STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Voertuie - regs-klik op voertuig vir inligting STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Skepe - regs-klik op skip vir inligting STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Vliegtuie - regs-klik op vliegtuig vir inligting STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Sleep trein voertuig hier om dit te verkoop STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Sleep pad voertuig hier om dit te verkoop STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Sleep skip hier om dit te verkoop STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Sleep vliegtuig hier om dit te verkoop STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Sleep trein enjin hier om hele trein te verkoop STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Verkoop allep treine in die depot STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Verkoop alle pad voertuie in die depot STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Verkoop alle skepe in die depot STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Verkoop alle vliegtuie in die hangar STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Outovervang alle treine in die depot STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Outovervang alle pad voertuie in die depot STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Outovervang alle skepe in die depot STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Outovervang alle vlietuie in die hangar STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}Nuwe Voertuie STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}Nuwe Voertuie STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}Nuwe Skepe STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}Nuwe Vliegtuig STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Koop nuwe lokomotief/trok STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Koop nuwe voertuig STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Koop nuwe skip STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Koop nuwe vliegtuig STR_DEPOT_CLONE_TRAIN :{BLACK}Kloon Trein STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Kloon Voertuig STR_DEPOT_CLONE_SHIP :{BLACK}Kloon Skip STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Kloon Vliegtuig STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}Klik hier en dan op 'n bestaande trein om 'n spieëlbeeld van die bestaande trein te koop. Ctrl+Klik om die opdragte tel deel. Shift+klik vir kwotasie STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Klik hier en dan op 'n bestaande voertuig om 'n spieëlbeeld van die bestaande voertuig te koop. Shift+klik vir kwotasie STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}Klik hier en dan op 'n bestaande skip om 'n spieëlbeeld van die bestaande skip te koop. Shift+klik vir kwotasie STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}Klik hier en dan op 'n bestaande vliegtuig om 'n spieëlbeeld van die bestaande vliegtuig te koop. Shift+klik vir kwotasie STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Skuif skerm na trein diensstasie. Ctrl+klik om 'n nuwe venster vir die trein diensstasie oop te maak STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Skuif skerm na voertuigdiensstasie. Ctrl+klik om 'n nuwe venster vir die voertuigdiensstasie oop te maak STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Skuif skerm na skeepswerf. Ctrl+klik om 'n nuwe venster vir die skeepswerf oop te maak STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Skuif skerm na loods. Ctrl+klik om 'n nuwe venster vir die loods oop te maak STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Kry 'n lys van alle treine met die huidige depot in sy opdrae STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Kry 'n lys van alle pad voertuie met die huidige depot in sy opdrae STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Kry 'n lys van alle skepe met die huidige depot in sy opdrae STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Kry 'n lys van alle vliegtuie wat enige hangar by die lughawe in sy opdrae het STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Klik om alle treine in die treindepot te stop STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klik om alle voertuie in die diensstasie te stop STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Klik om alle skepe in die skeepswerf te stop STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Klik om alle vlietuie in die loods te stop STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Klik om alle treine in die treindepot aan te skakel STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klik om alle padvoertuie in die diensstasie aan te skakel STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Klik om alle skepe in die skeepswerf aan te skakel STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Klik om alle vliegtuie in die loods aan te skakel STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}U staan op die punt om al die voertuie in die depot te verkoop. Is jy seker? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Boodskap van voertuig fabrikant STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Ons het sopas 'n nuwe {STRING} ontwerp, sal jy belangstel om hierdie voertuig eksklusief vir 'n jaar te gebruik. Hierdie word gedoen om te kyk hoe die voertuig doen voordat hy wereld wyd in produksie gesit word? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :spoorweg lokomotief STR_ENGINE_PREVIEW_ROAD_VEHICLE :padvoertuig STR_ENGINE_PREVIEW_AIRCRAFT :vliegtuig STR_ENGINE_PREVIEW_SHIP :skip STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monospoor lokomotief STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev lokomotief STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Koste: {CURRENCY_LONG} Massa: {WEIGHT_SHORT}{}Spoed: {VELOCITY} Krag: {POWER}{}Loopkoste: {CURRENCY_LONG}/jr{}Kapasitiet: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Koste: {CURRENCY_LONG} Gewig: {WEIGHT_SHORT}{}Spoed: {VELOCITY} Krag: {POWER} Maks. Treg Krag: {6:FORCE}{}Lopende Koste: {4:CURRENCY_LONG}/jaar{}Kapasitiet: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Koste: {CURRENCY_LONG} Maks. Spoed: {VELOCITY}{}Kapasiteit: {CARGO_LONG}, {CARGO_LONG}{}Lopende Koste: {CURRENCY_LONG}/jaar STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Koste: {CURRENCY_LONG} Maks. Spoed: {VELOCITY}{}Kapasiteit: {CARGO_LONG}{}Lopende Koste: {CURRENCY_LONG}/jaar STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Koste: {CURRENCY_LONG} Max. Spoed: {VELOCITY} Afstand: {COMMA} teëls{}Kapasiteit: {CARGO_LONG}, {CARGO_LONG}{}Hardloop Koste: {CURRENCY_LONG}/jaar STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Koste: {CURRENCY_LONG} Max. Spoed: {VELOCITY} Afstand: {COMMA} teels{}Kapasiteit: {CARGO_LONG}{}Hardloop Koste: {CURRENCY_LONG}/jaar # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}Vervang {STRING} - {STRING} STR_REPLACE_VEHICLE_TRAIN :Trein STR_REPLACE_VEHICLE_ROAD_VEHICLE :Pad voertuig STR_REPLACE_VEHICLE_SHIP :Skip STR_REPLACE_VEHICLE_AIRCRAFT :Vliegtuig STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Voertuie in gebruik STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP :{BLACK}Kolom met voertuie wat jy besit STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Beskikbare voertuie STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP :{BLACK}Kolom met voertuie wat beskikbaar is vir vervanging STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Kies die enjin tipe om te vervang STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Kies die nuwe enjin tipe wat jy wil gebruik in plaas van die linker gekose enjin tipe STR_REPLACE_VEHICLES_START :{BLACK}Vervang voertuie STR_REPLACE_VEHICLES_NOW :Vervand alle voertuie nou STR_REPLACE_VEHICLES_WHEN_OLD :Vervang net ou voertuie STR_REPLACE_HELP_START_BUTTON :{BLACK}Druk om vervanging van die linker gekose enjin tipe met die regter gekose enjin tipe te begin STR_REPLACE_NOT_REPLACING :{BLACK}Word nie vervang nie STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Geen voertuig gekies STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} waneer oud STR_REPLACE_VEHICLES_STOP :{BLACK}Staak vervanging STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Druk om die vervanging van die linker gekose enjin tipe te stop STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Vervang: {ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Skakel tussen enjin en wa vervang vensters STR_REPLACE_ENGINES :Enjin STR_REPLACE_WAGONS :Waens STR_REPLACE_HELP_RAILTYPE :{BLACK}Kies die soort spoor waarvoor lokomotiewe vervang moet word STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Toon aan watter enjin die linker gekose enjin mee vervang moet word , indien enige STR_REPLACE_RAIL_VEHICLES :Treine STR_REPLACE_ELRAIL_VEHICLES :Elektriese treine STR_REPLACE_MONORAIL_VEHICLES :Monospoor voertuie STR_REPLACE_MAGLEV_VEHICLES :Maglev Voertuie STR_REPLACE_REMOVE_WAGON :{BLACK}Wa verwydering: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Maak autovervanging die lengte van 'n trein dieselfde hou deur verwydering waens (deur voor te begin), indien die enjin vervanging die trein langer sal maak # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Skuif skerm na trein. Ctrl+klik om die skerm die trein te laat volg STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Skuif skerm na voertuig. Ctrl+klik om die skerm die voertuig te laat volg STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Skuif skerm na skip. Ctrl+klik om die skerm die skip te laat volg STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Skuif skerm na vliegtuig. Ctrl+klik om die skerm die vliegtuig te laat volg STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Stuur trein na diensstasie. Ctrl+klik om net te diens STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Stuur voertuig na diensstasie. Ctrl+klik om net te diens STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Stuur skip na skeepswerf. Ctrl+klik om net te diens STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Stuur vliegtuig na loods. Ctrl+klik om net te diens STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Dit sal 'n spieëlbeeld van die trein koop. Shift+klik vir kwotasie STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Dit sal 'n spieëlbeeld van die voertuig koop. Shift+klik vir kwotasie STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Dit sal 'n spieëlbeeld van die skip koop. Shift+klik vir kwotasie STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Dit sal 'n spieëlbeeld van die voertuig koop. Ctrl-klik om opdrae te deel. Shift+klik vir kwotasie STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Forseer trein om voort te gaan sonder om vir sien die uit te klaar STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Herbou trein om 'n ander vrag tipe te ontvoer STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Herbou pad voertuig om 'n ander vrag tipe te ontvoer STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Herbou vragskip om 'n ander vrag tipe te vervoer STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Herbou vliegtuig om 'n ander vrag tipe te ontvoer STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Agteruit rigting van trein STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Forseer voertuig om te draai om STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Vertoon trein se opdrae. Ctrl+klik om die trein se rooster te wys STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Vertoon voertuig se opdrae. Ctrl+klik om die voertuig se rooster te wys STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Vertoon skip se opdrae. Ctrl+klik om die skip se rooster te wys STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Vertoon vliegtuig se opdrae. Ctrl+klik om die vliegtuig se rooster te wys STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Toon trein besonderhede STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Wys pad voertuig aanwyse STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Wys skip se aanwyse STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Toon vliegtuig aanwyse STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Huidige treinaksie - klik hier om trein te stop/aanskakel. Ctrl+klik om na bestemming te skuif. STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Huidige voertuigaksie - klik hier om voertuig to stop/aanskakel. Ctrl+klik om na bestemming te skuif. STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Huidige skipaksie - klik hier om skip te stop/aanskakel. Ctrl+klik om na bestemming te skuif. STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Huidige vliegtuigaksie - klik hier om vliegtuig te stop/aanskakel. Ctrl+klik om na bestemming te skuif. # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Laai / Aflaai STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Verlaat STR_VEHICLE_STATUS_CRASHED :{RED}Botsing! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Teenspoed STR_VEHICLE_STATUS_STOPPED :{RED}Gestop STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Ophou, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}Geen Krag STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Wag vir beskikbare pad STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Te ver na volgende bestemming STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Oppad na {STATION}, {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}Geen opdrae, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Oppad na {WAYPOINT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Oppad na {DEPOT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Diens by {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Gestop STR_VEHICLE_COMMAND_STOPPED :{RED}Gestop STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Begin STR_VEHICLE_COMMAND_STARTED :{GREEN}Begin # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Aanwyse) STR_VEHICLE_NAME_BUTTON :{BLACK}Naam STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Benoem trein STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Benoem pad voertuig STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Benoem skip STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Benoem vliegtuig STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Ouderdom: {LTBLUE}{STRING}{BLACK} Lopende koste: {LTBLUE}{CURRENCY_LONG}/jaar # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} ja{P ar re} ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} ja{P ar re} ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Maks. spoed: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Max. spoed: {LTBLUE}{VELOCITY} {BLACK}Afstand: {LTBLUE}{COMMA} teëls STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Gewig: {LTBLUE}{WEIGHT_SHORT} {BLACK}Krag: {LTBLUE}{POWER}{BLACK} Maks. spoed: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Massa: {LTBLUE}{WEIGHT_SHORT} {BLACK}Krag: {LTBLUE}{POWER}{BLACK} Maks. spoed: {LTBLUE}{VELOCITY} {BLACK}Maks. T.E.: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Wins hierdie jaar: {LTBLUE}{CURRENCY_LONG} (vorige jaar: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Betroubaarheid: {LTBLUE}{COMMA}% {BLACK}Hoeveel keer onklaar sedert laaste diens: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Gebou: {LTBLUE}{NUM}{BLACK} Waarde: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Kapasiteit: {LTBLUE}Geen{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Kapasiteit: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Kapasiteit: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Kapasiteit: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Oordragkrediet: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Diens tussentyd: {LTBLUE}{COMMA}{NBSP}dae{BLACK} Laaste diens: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Diens tussentyd: {LTBLUE}{COMMA}%{BLACK} Laaste diens: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Vermeeder diensinterval met 10 dae. Ctrl+klik om interval met 5 dae te vermeerder STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Verminder diensinterval met 10. Ctrl+klik om interval met 5 dae te verminder STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Verander instandhoudings-interval tipe STR_VEHICLE_DETAILS_DEFAULT :Verstek STR_VEHICLE_DETAILS_DAYS :Dae STR_VEHICLE_DETAILS_PERCENT :Persentasie STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Benoem trein STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Benoem pad voertuig STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Benoem skip STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Benoem vliegtuig # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Gebou: {LTBLUE}{NUM}{BLACK} Waarde: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Waarde: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Totale vragkapasiteit van die trein: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Leeg STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} vanaf {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} van {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Vrag STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Wys besonderhede van vrag gedra STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Inligting STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Wys besonderhede van trein voertuie STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Kapasiteite STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Wys kapasiteite van elke voertuig STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Totale Vrag STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Toon totale kapasiteit van trein, per vragtipe STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Kapasiteit: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Herbou) STR_REFIT_TITLE :{GOLD}Kies vrag tipe vir skip te ontvoer: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nuwe kapasiteit: {GOLD}{CARGO_LONG}{}{BLACK}Herboukoste: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}Nuwe kapasiteit: {GOLD}{CARGO_LONG}{}{BLACK}Inkomste vanaf herinrig: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Nuwe Kapasiteit: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Koste om te herbou: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}Nuwe kapasiteit: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Inkomste van herinrig: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Kies die voertuig om te omskep. Sleep die muis om meer as een voertuig te selekteer. Klik op 'n leë spasie om die hele voertuig te kies. Ctrl+klik sal 'n voertuig en die daaropvolgende ketting kies STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Kies vrag tipe vir trein te ontvoer STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Kies vrag tipe vir pad voertuig om te vervoer STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Kies vrag tipe vir skip te ontvoer STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Kies vrag tipe vir vliegtuig om te ontvoer STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Herbou trein STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Herbou pad voertuig STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Herbou skip STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Herbou vliegtuig STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Herbou trein om verlig vrag tipe te ontvoer STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Herbou pad voertuig om beklemtoonde vrat tipe te ontvoer STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Herbou skip om die verligte vrag tipe te ontvoer STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Herbou vliegtuig om verlig vrag tipe te ontvoer # Order view STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Opdrae) STR_ORDERS_TIMETABLE_VIEW :{BLACK}Rooster STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Skakel na die rooster uitsig STR_ORDERS_LIST_TOOLTIP :{BLACK}Roetelys - klik op 'n bestemming om dit te kies. Ctrl+klik skuif die skerm na die bestemming STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - Einde van Opdrae - - STR_ORDERS_END_OF_SHARED_ORDERS :- - Einde van Gedeel Opdrae - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}Sonder-stop STR_ORDER_GO_TO :Gaan na STR_ORDER_GO_NON_STOP_TO :Gaan sonder-stop na STR_ORDER_GO_VIA :Gaan deur STR_ORDER_GO_NON_STOP_VIA :Gaan sonder-stop deur STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Verander die stop gedrag van die geselekteerde bevel STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Vol laai enige vrag STR_ORDER_DROP_LOAD_IF_POSSIBLE :Laai indien beskikbaar STR_ORDER_DROP_FULL_LOAD_ALL :Vol laai alle vrag STR_ORDER_DROP_FULL_LOAD_ANY :Vol laai enige vrag STR_ORDER_DROP_NO_LOADING :Geen laai STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Verander die op-laai gedrag van die geselekteerde bevel STR_ORDER_TOGGLE_UNLOAD :{BLACK}Laai als af STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Laai af indien aanvaar STR_ORDER_DROP_UNLOAD :Laai als af STR_ORDER_DROP_TRANSFER :Verplaas STR_ORDER_DROP_NO_UNLOADING :Geen aflaai STR_ORDER_TOOLTIP_UNLOAD :{BLACK}verander die aflaai gedrag ven die geselekteerde bevel STR_ORDER_REFIT :{BLACK}Herbou STR_ORDER_REFIT_TOOLTIP :{BLACK}Kies na watter vragtipe toe die voegtuig omskep sal word. Ctrl-klik om omskeppingsinstruksie te verwyder STR_ORDER_REFIT_AUTO :{BLACK}Outo-herpas STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Kies watter tipe vrag na herpas moet word vir hierdie opdrag. Ctrl-klik om herpassingsinstruksies te stop. Outo-omskepping sal net toegelaat word as die voertuig dit toelaat STR_ORDER_DROP_REFIT_AUTO :Vaste vrag STR_ORDER_DROP_REFIT_AUTO_ANY :Beskikbare vrag STR_ORDER_SERVICE :{BLACK}Diens STR_ORDER_DROP_GO_ALWAYS_DEPOT :gaan altyd STR_ORDER_DROP_SERVICE_DEPOT :Diens indien nodig STR_ORDER_DROP_HALT_DEPOT :Stop STR_ORDER_SERVICE_TOOLTIP :{BLACK}Ignoreer die opdraag tensy 'n diens nodig is STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Voertuig data om sprong op te baseer # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Vrag persentasie STR_ORDER_CONDITIONAL_RELIABILITY :Betroubaarheid STR_ORDER_CONDITIONAL_MAX_SPEED :Maksimum spoed STR_ORDER_CONDITIONAL_AGE :Ouderdom (jare) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Benodig diens STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Altyd STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Oorblywende leeftyd (jare) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Hoe om die voertuig data te vergelyk met die gegeewe waarde STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :is gelyk aan STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :is nie gelyk aan STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :is minder as STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :is minder as of gelyk aan STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :is meer as STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :is meer as of gelyk aan STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :is waar STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :is fals STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}Die waarde teen die voertuig data te vergelyk STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Tik in die waarde om teen te vergelyk STR_ORDERS_SKIP_BUTTON :{BLACK}Slaan oor STR_ORDERS_SKIP_TOOLTIP :{BLACK}Ignoreer die huidige opdrag, en begin die volgende. Ctrl+klik spring na verkieste opdrag STR_ORDERS_DELETE_BUTTON :{BLACK}Uitvee STR_ORDERS_DELETE_TOOLTIP :{BLACK}Vee die verlig opdrag uit STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Verwyder alle opdragte STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Stop deeling STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Hou op om opdraglys te deel. Ctrl+klik vee alle opdrae vir die voertuig uit STR_ORDERS_GO_TO_BUTTON :{BLACK}Gaan Na STR_ORDER_GO_TO_NEAREST_DEPOT :Gaan na naaste diensstasie STR_ORDER_GO_TO_NEAREST_HANGAR :Gaan na naaste vliegtuigloods STR_ORDER_CONDITIONAL :Voorwaardelike bevel spring STR_ORDER_SHARE :Deel opdragte STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Voeg 'n nuwe opdrag voor die verlig opdrag by, of voeg by na einde van lys STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Toon alle voertuie wat die rooster deel # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Gaan oor {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Gaan sonder-stop via {WAYPOINT} STR_ORDER_SERVICE_AT :Diens by STR_ORDER_SERVICE_NON_STOP_AT :Diens geen-stop by STR_ORDER_NEAREST_DEPOT :die naaste STR_ORDER_NEAREST_HANGAR :die naaste vliegtuigloods STR_ORDER_TRAIN_DEPOT :Treindepot STR_ORDER_ROAD_VEHICLE_DEPOT :Pad Voertuig Diensstasie STR_ORDER_SHIP_DEPOT :Skeepswerf STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(Herbou na {STRING}) STR_ORDER_REFIT_STOP_ORDER :(Herbou na {STRING} en stop) STR_ORDER_STOP_ORDER :(Stop) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(Implesiete) STR_ORDER_FULL_LOAD :(Vol laai) STR_ORDER_FULL_LOAD_ANY :(Vol laai enige vrag) STR_ORDER_NO_LOAD :(Geen oplaai) STR_ORDER_UNLOAD :(Laai af en vat vrag) STR_ORDER_UNLOAD_FULL_LOAD :(Laai af en wag vir 'n vol vrag) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Laai af en wag vir enige vol vrag) STR_ORDER_UNLOAD_NO_LOAD :(Laai af en verlaat leeg) STR_ORDER_TRANSFER :(Verplaas en vat vrag) STR_ORDER_TRANSFER_FULL_LOAD :(Verplaas en wag vir 'n vol vrag) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Verplaas en wag vir enige vol vrag) STR_ORDER_TRANSFER_NO_LOAD :(Verplaas en verlaat leeg) STR_ORDER_NO_UNLOAD :(Moenie aflaai en laai vrag) STR_ORDER_NO_UNLOAD_FULL_LOAD :(Geen aflaai en wag vir vol vrag) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Geen aflaai en wag vir enige vol vrag) STR_ORDER_NO_UNLOAD_NO_LOAD :(Geen aflaai en geen laai) STR_ORDER_AUTO_REFIT :(Herpas vir {STRING}) STR_ORDER_FULL_LOAD_REFIT :(Vollas met herpas vir {STRING}) STR_ORDER_FULL_LOAD_ANY_REFIT :(Vollas enige vrag met herpas vir {STRING}) STR_ORDER_UNLOAD_REFIT :(Laai af en laai vrag op met herpas vir {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Laai af en wag vir 'n vol vrag met herpas vir {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Laai af en wag vir enige vol vrag met herpas vir {STRING}) STR_ORDER_TRANSFER_REFIT :(Plaas oor en laai vrag met herpas vir {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Plaas oor en wag vir 'n vollas met herpas vir {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Plaas oor en wag vir enige vollas met herpas vir {STRING}) STR_ORDER_NO_UNLOAD_REFIT :(Geen aflaai en vat vrag met herpas vir {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Geen aflaai en wag vir 'n vol vrag met herpas vir {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Geen aflaai en wag vir enige vol vrag met herpas vir {STRING}) STR_ORDER_AUTO_REFIT_ANY :beskikbare vrag STR_ORDER_STOP_LOCATION_NEAR_END :[naby einde] STR_ORDER_STOP_LOCATION_MIDDLE :[middel] STR_ORDER_STOP_LOCATION_FAR_END :[ver einde] STR_ORDER_OUT_OF_RANGE :{RED} (Volgende bestemming val buite die limiet) STR_ORDER_CONDITIONAL_UNCONDITIONAL :Spring oor na bevel {COMMA} STR_ORDER_CONDITIONAL_NUM :Spring oor na bevel {COMMA} wanneer {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :Spring oor na bevel {COMMA} wanneer {STRING} {STRING} STR_INVALID_ORDER :{RED} (Ongeldige opdrag) # Time table window STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Rooster) STR_TIMETABLE_ORDER_VIEW :{BLACK}Bevele STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Verander na die bevel lys STR_TIMETABLE_TOOLTIP :{BLACK}Rooster - Klik op 'n bestemming om dit te kies STR_TIMETABLE_NO_TRAVEL :Geen reis STR_TIMETABLE_NOT_TIMETABLEABLE :Reis (outomaties; getabuleer volgens eiehandige bevel) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Reis (Nie op rooster nie) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Reis nie meer as {2:VELOCITY} nie (nie volgens tydrooster nie) STR_TIMETABLE_TRAVEL_FOR :Reis vir {STRING} STR_TIMETABLE_TRAVEL_FOR_SPEED :Reis vir {STRING} met die meeste {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Reis (vir {STRING}, nie volgens tydrooster nie) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Reis (vir {STRING}, nie volgens tydrooster nie) teen nie meer as {VELOCITY} nie STR_TIMETABLE_STAY_FOR_ESTIMATED :(wag vir {STRING}, nie volgens tydrooster nie) STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(reis vir {STRING}, nie volgens tydrooster nie) STR_TIMETABLE_STAY_FOR :en bly vir {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :en reis vir {STRING} STR_TIMETABLE_DAYS :{COMMA}{NBSP}da{P g e} STR_TIMETABLE_TICKS :{COMMA}{NBSP}tik{P "" ke} STR_TIMETABLE_TOTAL_TIME :{BLACK}Die rooster sal {STRING} neem om te voltooi STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}Die rooster sal te minste {STRING} vat om te voltooi (nie alles gerooster nie) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}Die voertuig loop tans op tyd STR_TIMETABLE_STATUS_LATE :{BLACK}Die voertuig loop tans {STRING} laat STR_TIMETABLE_STATUS_EARLY :{BLACK}Die voertuig loop tans {STRING} vroeg STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}Hierdie rooster het nog nie begin nie STR_TIMETABLE_STATUS_START_AT :{BLACK}Hierdie tydrooster sal begin by {STRING} STR_TIMETABLE_STARTING_DATE :{BLACK}Begin datum STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Kies 'n datum as 'n beginpunt vir hierdie rooster. Ctrl+klik stel die begindatum van hierdie rooster en versprei al die voertuie wat hierdie rooster deel eweredig vir 'n volledige rooster. STR_TIMETABLE_CHANGE_TIME :{BLACK}Verander Tyd STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Verander die bedrag van tyd die verlig opdrag moes vat STR_TIMETABLE_CLEAR_TIME :{BLACK}Reinig Tyd STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Vee uit die totaal van tyd vir die gespesiveerde opdrag STR_TIMETABLE_CHANGE_SPEED :{BLACK}Verander Spoedgrens STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Verander die maksimum reis spoed van die verligte bevel STR_TIMETABLE_CLEAR_SPEED :{BLACK}Verwyder Spoedgrens STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}verwyder die maksimum reis spoed van die verligte bevel STR_TIMETABLE_RESET_LATENESS :{BLACK}Herstel Laat Teller STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Herstel die laat teller, so dat die voertuig op tyd is STR_TIMETABLE_AUTOFILL :{BLACK}Outovul STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Vul die rooster outomaties in met die waardes van die volgende reis (Ctrl-klik om die wagtyd te probeer hou) STR_TIMETABLE_EXPECTED :{BLACK}Word vervag STR_TIMETABLE_SCHEDULED :{BLACK}Geskeduleer STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Verander tussen verwagte tyd en geskeduleerde tyd STR_TIMETABLE_ARRIVAL_ABBREVIATION :A: STR_TIMETABLE_DEPARTURE_ABBREVIATION :D: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}Verander datum STR_DATE_SET_DATE :{BLACK}Verander datum STR_DATE_SET_DATE_TOOLTIP :{BLACK}Gebruik geselekteerde datum as begindatum vir die tydrooster STR_DATE_DAY_TOOLTIP :{BLACK}Selekteer dag STR_DATE_MONTH_TOOLTIP :{BLACK}Selekteer maand STR_DATE_YEAR_TOOLTIP :{BLACK}Selekteer jaar # AI debug window STR_AI_DEBUG :{WHITE}Rekenaar speler/Korrigeer Spel Skrip foute STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Naam van skrip STR_AI_DEBUG_SETTINGS :{BLACK}Verstellings STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Verander die stellings van die skrif STR_AI_DEBUG_RELOAD :{BLACK}Herlaai AI STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Maak die AI dood, herlaai die skrif en herlaai die AI STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Aktiveer/deaktiveer 'n breek wanneer 'n AI log boodskap 'n breek string ewenaar STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Breek op: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Breek op STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Wanneer 'n AI log boodskap die string ewenaar, word die spel onderbreuk STR_AI_DEBUG_MATCH_CASE :{BLACK}Ooreenstemmende kas STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Skakel ooreenstemmende kas wanneer AI log boodskap gemeet word teen die breek string STR_AI_DEBUG_CONTINUE :{BLACK}Gaan voort STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Hervat en gaan met die AI voort STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Kyk na die ontfout uitset van die AI STR_AI_GAME_SCRIPT :{BLACK}Speletjie Skrif STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Nagaan die Spel Skrif log STR_ERROR_AI_NO_AI_FOUND :Geen geskikte Rekenaar Speler wat gelaai kon word nie.{}Hierdie Rekernaar Speler is 'dood' en gaan niks doen nie.{}Rekenaar Spelers kan by 'Aanlyn Inhoud' afgelaai word STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}Een van die lopende skripte het verongeluk. Raporteer dit asseblief aan die skrip skrywer saam met 'n skermkiekie van die Rekenaar Speler/Spel Skrip Ontfout Venster STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}Rekenaar Speler/Spel Skrip Ontfout venster is slegs beskikbaar aan die verskaffer # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}AI/Spel Konfigurasie STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}Spel Skrip wat in die volgende spel gelaai sal word STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}Die AIs wat om die volgende spel gelaai sal word STR_AI_CONFIG_HUMAN_PLAYER :Mens Speler STR_AI_CONFIG_RANDOM_AI :Lukraak AI STR_AI_CONFIG_NONE :(geen) STR_AI_CONFIG_MOVE_UP :{BLACK}Beweeg op STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Beweeg gekose AI op in die lys STR_AI_CONFIG_MOVE_DOWN :{BLACK}Beweeg af STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Beweeg gekose AI af in die lys STR_AI_CONFIG_GAMESCRIPT :{SILVER}Spel Skrip STR_AI_CONFIG_AI :{SILVER}AIs STR_AI_CONFIG_CHANGE :{BLACK}Selekteer {STRING} STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :AI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Spel Skrip STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Laai nog 'n script STR_AI_CONFIG_CONFIGURE :{BLACK}Konfigureer STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Konfigureer die parameters van skrif # Available AIs window STR_AI_LIST_CAPTION :{WHITE}Beskikbare {STRING} STR_AI_LIST_CAPTION_AI :AIs STR_AI_LIST_CAPTION_GAMESCRIPT :Speletjie Skrifte STR_AI_LIST_TOOLTIP :{BLACK}Klik om 'n skrip te kies STR_AI_LIST_AUTHOR :{LTBLUE}Skrywer: {ORANGE}{STRING} STR_AI_LIST_VERSION :{LTBLUE}Weergawe: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{STRING} STR_AI_LIST_ACCEPT :{BLACK}Aanvaar STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Kies beligte skrif STR_AI_LIST_CANCEL :{BLACK}Kanseleer STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Moenie skrif verander nie # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parameters STR_AI_SETTINGS_CAPTION_AI :AI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Speletjie Skrif STR_AI_SETTINGS_CLOSE :{BLACK}Maak toe STR_AI_SETTINGS_RESET :{BLACK}Herstel STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} STR_AI_SETTINGS_START_DELAY :Aantal Dae om die AI te begin na die vorige een (omenby): {ORANGE}{STRING} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme van {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} veranderinge-log van {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} lisensie van {STRING} STR_TEXTFILE_WRAP_TEXT :{WHITE}Teksomvouing STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Omvou die teks in die venster sodat alles pas en dit nie nodig is om te rol nie STR_TEXTFILE_VIEW_README :{BLACK}Besigtig readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Veranderinge-log STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lisensie # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Koste: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}Koste: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Inkomste: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}Inkomste: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Oorplaas: {CURRENCY_LONG} STR_FEEDER :{YELLOW}Oordrag: {CURRENCY_LONG} STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Oordrag: {CURRENCY_LONG}{WHITE} / {GREEN}Inkomste: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}Oordrag: {CURRENCY_LONG}{WHITE} / {GREEN}Inkomste: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Oordrag: {CURRENCY_LONG}{WHITE} / {RED}Koste: {CURRENCY_LONG} STR_FEEDER_COST :{YELLOW} Oordrag: {CURRENCY_LONG}{WHITE} / {RED}Koste: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Beraamde Koste: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Beraamde Inkomste: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Stoor van speletjie is nog besig, {}wag asb tot dit klaar is! STR_ERROR_AUTOSAVE_FAILED :{WHITE}Outostoor het misluk STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Kan nie skyf lees nie STR_ERROR_GAME_SAVE_FAILED :{WHITE}Speletjie Spaar Misluk{}{STRING} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Kan nie lêer uitvee nie STR_ERROR_GAME_LOAD_FAILED :{WHITE}Speletjie Laai Misluk{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Interne fout: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Gebreekte gespaarde spel - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Spaarspeletjie is gemaak met nuwer uitgawe STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Lêer nie leesbare STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Lêer nie skryfbaar STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Data integriteit het misluk STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Spel was in 'n weergawe sonder trem ondersteuning gestoor. Alle tremme was verwyder # Map generation messages STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Kaart generasie het gestaak...{}... geen geskikde plekke vir dorpe was gevind nie STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... daar is geen dorp in die scenario nie STR_ERROR_PNGMAP :{WHITE}Kan nie landskap van PNG laai nie... STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... leêr nie gevind nie STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... kon nie prent tipe verander nie. 8 of 24-greep PNG prent benodig STR_ERROR_PNGMAP_MISC :{WHITE}... iets het skeef geloop (moontlik 'n korrupte lêer) STR_ERROR_BMPMAP :{WHITE}Kan nie landskap van BMP laai nie... STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... kon nie prent tipe verander nie. STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... beeld is te groot STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Skaal waarskuwing STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Om die kaart te veel te verstel is nie aanbeveel. Gaan voort met die generasie? # Soundset messages STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Kon slegs 'n nood klank stel op spoor. Gaan na 'Aanlyn Inhoud' om klank stelle af te laai # Screenshot related messages STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Groot skermskoot STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}Die skermskoot sal 'n resolusie van {COMMA} x {COMMA} pixels beslaan. Hierdie skermskoot mag 'n tydjie neem. Wil u aangaan?? STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Skermkiekie suksesvol gestoor as '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}Skermskoot het misluk! # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Boodskap STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Boodskap van {STRING} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Van die kaart af STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Te naby aan die kant van die kaart STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Nie genoeg kontant nie - benodig {CURRENCY_LONG} STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Gelyk grond benodig STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land loop in verkeerde rigting STR_ERROR_CAN_T_DO_THIS :{WHITE}Kan dit nie doen nie... STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Gebou moet eers afgebreek word STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Kan nie hierdie gebied skoon maak nie... STR_ERROR_SITE_UNSUITABLE :{WHITE}... ligging ongeskik STR_ERROR_ALREADY_BUILT :{WHITE}... alreeds gebou STR_ERROR_OWNED_BY :{WHITE}... besit deur {STRING} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... gebied is besit deur 'n ander maatskappy STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... landargitektuur beperking beryk STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... teël skoonmaak limiet bereik STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... bome se plant beperking bereik STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Naam moet unike wees STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in die pad STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Nie toegelaat terwyl onderbreek # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} plaaslike raad weier om dit te toelaat STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}{TOWN} plaaslike raad weier om nog 'n lighawe te bou in hierdie stad STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}{TOWN} plaaslikke raad weier toestemming vir lughawes omdat die dorp oor geraas bekommer STR_ERROR_BRIBE_FAILED :{WHITE}Jou pogin met omkoop is deur 'n plaaslike ondersoeker uit gesniffel # Levelling errors STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}kan nie land hier verhoog nie... STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Kan nie land hier verlaag nie... STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Kan nie grond hier gelyk maak nie... STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Uitgrawings sal tonnel beskadig STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... reeds op seevlak STR_ERROR_TOO_HIGH :{WHITE}... te hoog STR_ERROR_ALREADY_LEVELLED :{WHITE}... klaar gelyk STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND :{WHITE}Die brug bo hierdie een gaan te hoog wees as jy voortgaan # Company related errors STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Maatskappy naam kan nie verander word nie... STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Bestuurder se naam kan nie verander word nie... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... maksimum toegelaate lening groote is {CURRENCY_LONG} STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Kan nie meer geld leen nie... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... geen lening om terug te betaal STR_ERROR_CURRENCY_REQUIRED :{WHITE}... {CURRENCY_LONG} vereis STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Kan nie lening terugbetaal nie... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Kan nie geld wat van die bank geleen is weggee nie... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Maatskappy kan nie aangekoop word nie... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Maatskappy hoofkwartier kan nie hier gebou word nie... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Kan nie 25% aandeel in die maatskappy koop nie... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Kan nie 25% aandeel in die maatskappy verkoop nie... STR_ERROR_PROTECTED :{WHITE}Die maatskappy is nie oud genoeg om aandeele te handel nie... # Town related errors STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Kan nie enige stede bou nie STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Kan nie dorp hernoem nie... STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Dorp kan nie hier gebou word nie... STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Kan nie dorp uitbrei... STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... te naby aan rand van kaart STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... te naby aan 'n ander dorp STR_ERROR_TOO_MANY_TOWNS :{WHITE}... te veel dorpe STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... daar is nie meer spasie oor op die kaart nie STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE} Die dorp sal nie paaie bou nie. Jy kan dit verander deur die bou van paaie via Stellings-> Omgewings-> Dorpe te aktiveer STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Pad werke in verloop STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Kan nie die dorp verwyder nie... {}'n Stasie of depot verwys na die dorp of die blok wat deur die dorp besit word kan nie verwyder word nie. STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... daar is geen plek vir 'n standbeeld in die middel van die dorp # Industry related errors STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... te veel industrieë STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Kan nie nywerhede genereer nie... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Kan nie {STRING} hier bou nie... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Nywerheid tipe kan nie hier gebou word nie... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... te naby aan 'n ander nywerheid STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... moet eers 'n dorp bou STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... slegs een toegelaat per dorp STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... kan slegs in dorpe met te minste 1200 mense gebou word STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... kan slegs in reënwoud gebiede gebou word STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... kan slegs in woestyn gebiede gebou word STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... kan slegs in dorpe gebou word (vervang huise) STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... kan slegs naby die middestad gebou word STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... kan slegs gebou word in lae areas STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... kan net naby aan kant van fkaart geplaas word STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... woud kan net bo sneeu-lyn beplant word STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... kan slegs bo sneeu-lyn gebou word STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... kan slegs onder sneeu-lyn gebou word STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Daar was geen geskikte plek vir '{STRING}' nywerhede STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Verander die kaart generasie parameter om 'n beter kaart te kry # Station construction related errors STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Kan nie treinstasie hier bou nie... STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Kan nie bus stasie hier bou nie... STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Kan nie vragmotor stasie bou nie... STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Kan nie passasier trem stasie bou nie... STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Kan nie vrag trem stasie bou nie... STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Kan nie werf hier bou nie... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Lughawe kan nie hier gebou word nie... STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Grens aan meer as een bestaande stasie/laai area STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... Stasie te ver van mekaar af STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Te veel stasies/laai areas STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Te veel treinstasie deele STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Te veel bushalte STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Te veel vragmotor stasies STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Te naby aan 'n ander stasie/laai area STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Te naby aan 'n ander werf STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Te naby aan 'n ander lughawe STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Stasie kan nie hernoem word nie... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... hierdie is 'n dorp besit pad STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... pad teenoor in die verkeerde rigting STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... deurry haltes kan nie hoeke hê nie STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... deurry haltes kan nie aansluitings hê nie # Station destruction related errors STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Kan nie deel van stasie verwyder nie... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Breek eers die treinstasie af STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Kan nie bus stasie verwyder nie... STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Kan nie vragmotor stasie verwyder stasie... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Kan nie passasier stasie verwyder nie... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Kan nie vrag stasie verwyder nie... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Moet eers pad stop verwyder STR_ERROR_THERE_IS_NO_STATION :{WHITE}... daar is geen stasie hier nie STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Breek eers die treinstasie af STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Moet eers bus stasie afbreek STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Moet eers vragmotor stasie afbreek STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Moet eers passasier trem stasie afbreek STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Moet eers vrag trem stasie afbreek STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Moet eers werf afbreek STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Moet eers lughawe afbreek # Waypoint related errors STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Grens aan meer as een bestaande roetebaken STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Te naby aan 'n ander roetebaken STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Kan nie roetebaken hier bou nie... STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Kan nie baken hier plaas nie... STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Kan nie die roetebaken se naam verander nie... STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Kan nie trein wegpunt van hier werwyder nie... STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Verwyder eers die roetebaken STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... baken in die pad STR_ERROR_BUOY_IS_IN_USE :{WHITE}... baken is in gebruik deur ander maatskappy! # Depot related errors STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Kan nie trein depot hier bou nie... STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Kan nie pad voertuig depot hier bou nie... STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Kan nie trem voertuig depot hier bou nie... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Skip depot kan nie hier gebou word nie... STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Kan nie depot hernoem nie... STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... kan slegs in 'n diensstasie gestop word STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... kan slegs in 'n diensstasie gestop word STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... kan slegs in 'n skeepswerf gestoor word STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... moet binne hangar gestop word STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Treine kan slegs verander word as hulle in die depot gestop is STR_ERROR_TRAIN_TOO_LONG :{WHITE}Trein te lank STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Kan nie rigting van voertuig verander nie... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... bestaan uit verskeie eenhede STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Onversoenbare spoor tipes STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Kan nie voertuig beweeg nie... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}Die agterste motor sal altyd die voorste motor volg STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Kan nie roete na plaaslike depot vind nie STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Kan nie plaaslike depot vind nie STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Verkeerde depot tipe # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} is te lank na vervanging STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Outo-vervang verstellings nie gelaai nie STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(geld perk) # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Onmoontlike spoor kombinasie STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Moet eers die sein verwyder STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Geen geskikte treinspoor STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Moet eers spoor verwyder STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Pad is een rigting of geblok STR_ERROR_CROSSING_DISALLOWED :{WHITE}Vlak kruisings word nie toegelaat vir die spoor tipe nie STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kan nie seinligte hier bou nie... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kan nie spore hier bou nie... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kan nie spore hier verwyder nie... STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Kan nie seinligte vanaf hier verwyder nie... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Kan nie seine hier verander nie... STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... daar is geen trein spoor STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... daar is geen seine STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Kan nie spoor tipe hier verander nie... # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Moet pad eers verwyder word STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... een rigting paaie kan nie aansluitings hê nie STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Kan nie pad hier bou nie... STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Kan nie tremweg hier bou nie... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Kan nie pad vanaf hier verwyder nie... STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Kan nie tremweg van hier af verwyder nie... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... daar is geen pad nie STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... daar is geen tremweg nie # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Kan nie kanaale hier bou nie... STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Kan nie sluite hier bou nie... STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Kan nie riviere hier plaas nie... STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... moet op water gebou word STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... Kan nie op water bou nie STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... kan nie op oop see bou nie STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... kan nie op kanaal bou nie STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... kan nie op rivier bou nie STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Moet eers kanaale afbreek STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Kan nie akwamaryn hier bou nie... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... boom reeds daar STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... verkeerde terrein vir boom tipe STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Kan nie boom hier beplant nie... # Bridge related errors STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Brug kan nie daar gebou word nie... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Moet eers brug afbreek STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Kan nie in die selfde plek begin en eindig nie STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Brug hoofde is nie op die selfde vlak nie STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Brug is te laag vir die terrein STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN :{WHITE}Die brug is te hoog STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Begin en einde moet in lyn wees STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... albei brug eindes moet op land wees STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... brug te lank STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Brug sou eindig buite die kaart # Tunnel related errors STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Tonnel kan nie daar gebou word nie... STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Plek ongeskik vir tonnel ingang STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Moet eers tonnel afbreek STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Ander tonnel in die pad STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tonnel so op die einde van die kaart eindig STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Kan nie die terrein aan die anderkant van die tonnel uitgrawe nie STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tonnel te lank # Object related errors STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... te veel voorwerpe STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Kan nie voorwerp bou nie... STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Voorwerp in die pad STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... maatskappy hoofkwartier in die pad STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Die land area kan nie aangekoop word nie... STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... jy besit dit alreeds! # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Kan nie groep skep nie... STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Kan nie groep uitvee nie... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Kan nie groep hernoem nie... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Kan nie die huidige groep instel nie STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Kan nie alle voertuie van groep verwyder nie... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Kan nie die voertuig tot hierdie groep voeg nie... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Kan nie gedeelde voertuie by groep voeg nie... # Generic vehicle errors STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Trein in die pad STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Pad voertuig in die pad STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Skip in die pad STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Vliegtuig in die pad STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}kan nie trein herbou nie... STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Kan nie pad voertuig herbou nie... STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Skip kan nie herbou word nie... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Vliegtuig kan nie herbou word nie... STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Trein kan nie benoem word nie... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Kan nie pad voertuig 'n naam gee nie... STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Kan nie skip benoem nie... STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Vliegtuig kan nie benoem word nie... STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Trein kan nie stop/begin word nie... STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Kan nie pad voertuig stop/begin nie... STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}Kan nie skip stop/begin nie STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Kan nie vliegtuig stop/begin nie... STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Kan nie trein na depot stuur nie... STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Kan nie voertuig na depot stuur nie... STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Kan nie skip na depot stuur nie... STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Kan nie vlietuig na hangar stuur nie... STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Kan nie spoorweg voertuig koop nie... STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Kan nie pad voertuig koop nie... STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Kan nie skip koop nie... STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Kan nie vliegtuig koop nie... STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Trein voertuig tipe kan nie hernoem word nie... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Pad voertuig tipe kan nie hernoem word nie... STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Kan nie skip tipe hernoem nie... STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Kan nie vliegtuig tipe hernoem nie... STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Kan nie spoorweg voertuig verkoop nie... STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Kan nie pad voertuig verkoop nie STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Skip kan nie verkoop word nie... STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Vliegtuig kan nie verkoop word nie... STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Voertuig is nie beskikbaar nie STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Voertuig is nie beskikbaar nie STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Skip is nie beskikbaar STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Vliegtuig is nie beskikbaar nie STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Te veel voertuie in spel STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Kan nie diens interval verander nie... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... voertuig is vernietig STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Geen voertuie gaan beskikbaar wees nie STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Verander jou NewGRF stellings STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Geen voertuie is op die oomblik beskikbaar nie STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Begin na {DATE_SHORT} of gebruik 'n NewGRF wat voertuie vroeër beskikbaar stel # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kan nie trein forseer om sein te vermy op gevaar... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kan nie rigting van trein verander nie... STR_ERROR_TRAIN_START_NO_POWER :Trein het geen krag STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Kan nie pad voertuig laat omdraai nie... STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Vliegtuig is opvlug # Order related errors STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Geen spasie vir nog opdrae STR_ERROR_TOO_MANY_ORDERS :{WHITE}Te veel opdrae STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Kan nie nuwe opdrag invoeg nie... STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Kan nie die opdrag uitvee nie... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Die opdrag kan nie verander word nie... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Kan nie opdrag beweeg nie... STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Kan nie huidige opdrag ignoreer nie... STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Kan nie verkieste opdrag spring nie... STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... voertuig kan nie na al die stasies toe gaan nie STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... voertuig kan nie na daardie stasie toe gaan STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... 'n voertuig wat hierdie opdrag deel kan nie na daardie stasie toe gaan nie STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Kan nie opdraglys deel nie... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Kan nie opdraglys ophou deel nie...... STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Kan nie opdrag lys kopie nie... STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... te ver van vorige bestemming STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... vliegtuig kan nie so ver vlieg nie # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Kan nie voertuig 'n rooster gee nie... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Voertuie kan slegs by stasies wag STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Die voertuig stop nie by hierdie stasie nie. # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... te veel tekens STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Kan nie teken hier plaas nie... STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Kan nie teken naam verander nie... STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Kan nie teken verwyder nie # Translatable comment for OpenTTD's desktop shortcut STR_DESKTOP_SHORTCUT_COMMENT :'n Simulasie speletjie wat gebaseer is op Transport Tycoon Deluxe # Translatable descriptions in media/baseset/*.ob* files STR_BASEGRAPHICS_DOS_DESCRIPTION :Oorspronklike Transport Tycoon Deluxe DOS uitgawe grafieke. STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Oorspronklike Transport Tycoon Deluxe DOS (German) uitgawe grafieke. STR_BASEGRAPHICS_WIN_DESCRIPTION :Oorspronklike Transport Tycoon Deluxe Windows uitgawe grafieke. STR_BASESOUNDS_DOS_DESCRIPTION :Oorspronklike Transport Tycoon Deluxe DOS uitgawe klanke. STR_BASESOUNDS_WIN_DESCRIPTION :Oorspronklike Transport Tycoon Deluxe Windows uitgawe klanke. STR_BASESOUNDS_NONE_DESCRIPTION :'n Klank stel sonder enige klanke. STR_BASEMUSIC_WIN_DESCRIPTION :Oorspronklike Transport Tycoon Deluxe Windows uitgawe musiek. STR_BASEMUSIC_NONE_DESCRIPTION :'n Musiek stel sonder enige musiek. ##id 0x2000 # Town building names STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Hoog kantoor blok STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Kantoor blok STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Klein blok van woonstelle STR_TOWN_BUILDING_NAME_CHURCH_1 :Kerk STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Groot kantoor blok STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Meenthuise STR_TOWN_BUILDING_NAME_HOTEL_1 :Hotel STR_TOWN_BUILDING_NAME_STATUE_1 :Standbeeld STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Fontein STR_TOWN_BUILDING_NAME_PARK_1 :Park STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Kantoor blok STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Winkels en kantore STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Moderne kantoor gebou STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Pakhuis STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Kantoor blok STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadion STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Ou huise STR_TOWN_BUILDING_NAME_COTTAGES_1 :Kothuise STR_TOWN_BUILDING_NAME_HOUSES_1 :Huise STR_TOWN_BUILDING_NAME_FLATS_1 :Woonstelle STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Hoog kantoor blok STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Winkels en kantoore STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Winkels en kantoore STR_TOWN_BUILDING_NAME_THEATER_1 :Teatre STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadion STR_TOWN_BUILDING_NAME_OFFICES_1 :Kantore STR_TOWN_BUILDING_NAME_HOUSES_2 :Huise STR_TOWN_BUILDING_NAME_CINEMA_1 :Kinema STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Winkelsentrum STR_TOWN_BUILDING_NAME_IGLOO_1 :Igloo STR_TOWN_BUILDING_NAME_TEPEES_1 :Tepees STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Teepot-Huis STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Varkie-Bank ##id 0x4800 # industry names STR_INDUSTRY_NAME_COAL_MINE :Steenkoolmyn STR_INDUSTRY_NAME_POWER_STATION :Kragsentrale STR_INDUSTRY_NAME_SAWMILL :Saagmeul STR_INDUSTRY_NAME_FOREST :Woud STR_INDUSTRY_NAME_OIL_REFINERY :Olieraffinadery STR_INDUSTRY_NAME_OIL_RIG :Olieboor STR_INDUSTRY_NAME_FACTORY :Fabriek STR_INDUSTRY_NAME_PRINTING_WORKS :Drukwerke STR_INDUSTRY_NAME_STEEL_MILL :Staalfabriek STR_INDUSTRY_NAME_FARM :Plaas STR_INDUSTRY_NAME_COPPER_ORE_MINE :Kopermyn STR_INDUSTRY_NAME_OIL_WELLS :Olieboorgat STR_INDUSTRY_NAME_BANK :Bank STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Kosfabriek STR_INDUSTRY_NAME_PAPER_MILL :Papiermeul STR_INDUSTRY_NAME_GOLD_MINE :Goudmyn STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Bank STR_INDUSTRY_NAME_DIAMOND_MINE :Diamantmyn STR_INDUSTRY_NAME_IRON_ORE_MINE :Ystermyn STR_INDUSTRY_NAME_FRUIT_PLANTATION :Vrugte Plantasie STR_INDUSTRY_NAME_RUBBER_PLANTATION :Rubber Plantasie STR_INDUSTRY_NAME_WATER_SUPPLY :Watertoevoer STR_INDUSTRY_NAME_WATER_TOWER :Watertoring STR_INDUSTRY_NAME_FACTORY_2 :Fabriek STR_INDUSTRY_NAME_FARM_2 :Plaas STR_INDUSTRY_NAME_LUMBER_MILL :Houtmeul STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :Spookasemwoud STR_INDUSTRY_NAME_CANDY_FACTORY :Lekkergoedfabriek STR_INDUSTRY_NAME_BATTERY_FARM :Batteryplaas STR_INDUSTRY_NAME_COLA_WELLS :Cola Spruite STR_INDUSTRY_NAME_TOY_SHOP :Speelgoedwinkel STR_INDUSTRY_NAME_TOY_FACTORY :Speelgoedfabriek STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :Plastiekfontein STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :Koeldrankfabriek STR_INDUSTRY_NAME_BUBBLE_GENERATOR :Borrelopwekker STR_INDUSTRY_NAME_TOFFEE_QUARRY :Tamletjie Prooi STR_INDUSTRY_NAME_SUGAR_MINE :Suikermyn ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Onbenaam STR_SV_TRAIN_NAME :Trein {COMMA} STR_SV_ROAD_VEHICLE_NAME :Pad Voertuig {COMMA} STR_SV_SHIP_NAME :Skip {COMMA} STR_SV_AIRCRAFT_NAME :Vliegtuig {COMMA} STR_SV_STNAME :{STRING}-stasie STR_SV_STNAME_NORTH :{STRING}-Noord STR_SV_STNAME_SOUTH :{STRING}-Suid STR_SV_STNAME_EAST :{STRING}-Oos STR_SV_STNAME_WEST :{STRING}-Wes STR_SV_STNAME_CENTRAL :{STRING}-Sentraal STR_SV_STNAME_TRANSFER :{STRING}-oorstap STR_SV_STNAME_HALT :{STRING}-halte STR_SV_STNAME_VALLEY :{STRING}-vallei STR_SV_STNAME_HEIGHTS :{STRING}-hoogte STR_SV_STNAME_WOODS :{STRING}-woud STR_SV_STNAME_LAKESIDE :{STRING}-meer STR_SV_STNAME_EXCHANGE :{STRING}-wisselaar STR_SV_STNAME_AIRPORT :{STRING}-lughawe STR_SV_STNAME_OILFIELD :{STRING}-olieveld STR_SV_STNAME_MINES :{STRING}-myn STR_SV_STNAME_DOCKS :{STRING}-hawe STR_SV_STNAME_BUOY :{STRING} STR_SV_STNAME_WAYPOINT :{STRING} ##id 0x6020 STR_SV_STNAME_ANNEXE :{STRING}-anneks STR_SV_STNAME_SIDINGS :{STRING}-syspoor STR_SV_STNAME_BRANCH :{STRING}-tak STR_SV_STNAME_UPPER :Bo-{STRING} STR_SV_STNAME_LOWER :Onder-{STRING} STR_SV_STNAME_HELIPORT :{STRING}-helihawe STR_SV_STNAME_FOREST :{STRING}-bos STR_SV_STNAME_FALLBACK :{STRING}-stasie #{NUM} ############ end of savegame specific region! ##id 0x8000 # Vehicle names STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Stoom) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (Stoom) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Stoom) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (Stoom) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (Stoom) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (Elektries) STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Passasierswa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Pos Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Steenkool Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Olie Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Lewende Hawe Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Goedere Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Graan Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Hout Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Yster Erts Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Staal Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :pantserwa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Kos Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Papier Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Koper Erts Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Water Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Vrugte Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Gomlastiek Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Suiker Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Spookasem Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Tameletjie Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Borrel Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Cola Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Lekker Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Speelgoed Wa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Battery Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Koeldrank Trok STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Plastiek Trok STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Passasierswa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Pos Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Steenkoolwa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Olie Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Lewende Hawe Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Goedere Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Graan Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Hout Trok STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Yster Erts Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Staal Trok STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :pantserwa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Kos Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Papier Trok STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Coper Erts Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Water Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Vrugte Trok STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Gomlastiek Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Suiker Trok STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Spookasem Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Tameletjie Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Borrel Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Cola Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Lekker Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Speelgoed Wa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Bettery Trok STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Koeldrank Trok STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Plastiek Trok STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Elektries) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Passasierswa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Pos Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Steenkool Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Olie Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Lewende Hawe Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Goedere Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Graan Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Hout Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Yster Erts Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Staal Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :pantserwa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Kos Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Papier Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Koper Erts Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Water Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Vrugte Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Gomlastiek Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Suiker Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Spookasem Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Tameletjie Laai Bak STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Borrel Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Cola Tenkwa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Lekker Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Speelgoed Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Battery Trok STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Koeldrank Wa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Plastiek Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Bus STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Balogh Steenkool Trok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Uhl Kool Trok STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :DW Kool Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :MPS Pos Trok STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Reynard Pos Trok STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Perry Pos Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :MightyMover Pos Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Powernaught Pos Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Wizzowow Pos Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Witcombe Olie Tenkwa STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Foster Olie Tenkwa STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Perry Olie Tenkwa STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Talbott Lewende Hawe Wa STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Uhl Lewende Hawe Wa STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Foster Lewende Hawe Wa STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Balogh Goedere Trok STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Craighead Goedere Trok STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Goss Goedere Trok STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Hereford Graan Trok STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Thomas Graan Trok STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Goss Graan Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Witcombe Hout Trok STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Foster Hout Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Moreland Hout Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :MPS Yster Erts Trok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Uhl Iron Yster Erts Trok STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Chippy Yster Erts Trok STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Balogh Staal Trok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Uhl Staal Trok STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Kelling Staal Trok STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Balogh pantsertrok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Uhl pantsertrok STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Foster pantsertrok STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Foster Kos Wa STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Perry Kos Wa STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Chippy Kos Wa STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Uhl Papier Trok STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Balogh Papier Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :MPS Papier Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :MPS Koper Erts Trok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Uhl Koper Erts Trok STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Goss Koper Erts Trok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Uhl Water Tenkwa STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Balogh Water Tenkwa STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :MPS Water Tenkwa STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Balogh Vrugte Trok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Uhl Vrugte Trok STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kelling Vrugte Trok STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Balogh Gomlastiek Trok STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Uhl Gomlastiek Trok STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :RMT Gomlastiek Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Suiker Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Powernaught Suiker Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Wizzowow Suiker Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :MightyMover Cola Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Powernaught Cola Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Wizzowow Cola Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :MightyMover Spookasem Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Powernaught Spookasem Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Spookasem Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Tameletjie Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Tameletjie Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Tameletjie Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :MightyMover Speelgoed Wa STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Powernaught Speelgoed Wa STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Wizzowow Speelgoed Wa STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :MightyMover Lekker Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Powernaught Lekker Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Wizzowow Lekker Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Battery Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Powernaught Battery Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Wizzowow Battery Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :MightyMover Koeldrank Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Powernaught Koeldrank Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Fizzy Koeldrank Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Plastiek Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Plastiek Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Plastiek Trok STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Borrel Trok STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Borrel Trok STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Borrel Trok STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :MPS Olie Tenkskip STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :CS-Inc. Olie Tenkskip STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :MPS Passasier Veerboot STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :FFP Passasier Veerboot STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Skeertuig STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Chugger-Chug Passasier Veerboot STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Passasier Veerboot STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Yate vragskip STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Bakewell vragskip STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :MightyMover vragskip STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Powernaut vragskip STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Tricario Helikopter STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Guru X2 Helikopter STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut Helikopter ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{STRING}-{STRING}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} STR_FORMAT_DATE_ISO :{2:NUM}-{1:STRING}-{0:STRING} STR_FORMAT_BUOY_NAME :{TOWN} Baken STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Baken #{COMMA} STR_FORMAT_COMPANY_NUM :(Company {COMMA}) STR_FORMAT_GROUP_NAME :Groep {COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :{TOWN}-roetebaken STR_FORMAT_WAYPOINT_NAME_SERIAL :{TOWN}-roetebaken #{COMMA} STR_FORMAT_DEPOT_NAME_TRAIN :{TOWN} Trein Depot STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :{TOWN} Trein Depot #{COMMA} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :{TOWN} Pad Voertuig Depot STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :{TOWN} Pad Voertuig Depot #{COMMA} STR_FORMAT_DEPOT_NAME_SHIP :{TOWN} Skip Depot STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :{TOWN} Skip Depot #{COMMA} STR_FORMAT_DEPOT_NAME_AIRCRAFT :{STATION} Hangar STR_UNKNOWN_STATION :onbekende stasie STR_DEFAULT_SIGN_NAME :Teken STR_COMPANY_SOMEONE :iemand STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING} STR_SAVEGAME_NAME_SPECTATOR :Spektator, {1:STRING} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} STR_VIEWPORT_WAYPOINT :{WAYPOINT} STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} STR_DEPOT_NAME :{DEPOT} STR_ENGINE_NAME :{ENGINE} STR_HIDDEN_ENGINE_NAME :{ENGINE} (weggesteek) STR_GROUP_NAME :{GROUP} STR_INDUSTRY_NAME :{INDUSTRY} STR_PRESIDENT_NAME :{PRESIDENT_NAME} STR_SIGN_NAME :{SIGN} STR_STATION_NAME :{STATION} STR_TOWN_NAME :{TOWN} STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} STR_JUST_DATE_LONG :{DATE_LONG} STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} # Slightly 'raw' stringcodes with colour or size STR_BLACK_COMMA :{BLACK}{COMMA} STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} STR_TINY_COMMA :{TINY_FONT}{COMMA} STR_BLUE_COMMA :{BLUE}{COMMA} STR_RED_COMMA :{RED}{COMMA} STR_WHITE_COMMA :{WHITE}{COMMA} STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} STR_TINY_GROUP :{TINY_FONT}{GROUP} STR_BLACK_INT :{BLACK}{NUM} STR_ORANGE_INT :{ORANGE}{NUM} STR_WHITE_SIGN :{WHITE}{SIGN} STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} STR_BLACK_STRING :{BLACK}{STRING} STR_BLACK_RAW_STRING :{BLACK}{STRING} STR_ORANGE_STRING :{ORANGE}{STRING} STR_LTBLUE_STRING :{LTBLUE}{STRING} STR_WHITE_STRING :{WHITE}{STRING} STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING}{WHITE} STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING}{LTBLUE} STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} STR_BLACK_1 :{BLACK}1 STR_BLACK_2 :{BLACK}2 STR_BLACK_3 :{BLACK}3 STR_BLACK_4 :{BLACK}4 STR_BLACK_5 :{BLACK}5 STR_BLACK_6 :{BLACK}6 STR_BLACK_7 :{BLACK}7 STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) openttd-1.5.3/src/lang/welsh.txt0000644000000000000000000152224312627373445015314 0ustar rootroot##name Welsh ##ownname Cymraeg ##isocode cy_GB ##plural 0 ##textdir ltr ##digitsep , ##digitsepcur , ##decimalsep . ##winlangid 0x0452 ##grflangid 0x0f # $Id: welsh.txt 27429 2015-10-31 17:45:32Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(llinyn anniffiniedig) STR_JUST_NOTHING :Dim # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :Teithwyr STR_CARGO_PLURAL_COAL :Glo STR_CARGO_PLURAL_MAIL :Post STR_CARGO_PLURAL_OIL :Olew STR_CARGO_PLURAL_LIVESTOCK :Da Byw STR_CARGO_PLURAL_GOODS :Nwyddau STR_CARGO_PLURAL_GRAIN :Grawn STR_CARGO_PLURAL_WOOD :Coed STR_CARGO_PLURAL_IRON_ORE :Mwyn Haearn STR_CARGO_PLURAL_STEEL :Dur STR_CARGO_PLURAL_VALUABLES :Trysorau STR_CARGO_PLURAL_COPPER_ORE :Mwyn Copr STR_CARGO_PLURAL_MAIZE :India Corn STR_CARGO_PLURAL_FRUIT :Ffrwythau STR_CARGO_PLURAL_DIAMONDS :Diemwntau STR_CARGO_PLURAL_FOOD :Bwyd STR_CARGO_PLURAL_PAPER :Papur STR_CARGO_PLURAL_GOLD :Aur STR_CARGO_PLURAL_WATER :Dŵr STR_CARGO_PLURAL_WHEAT :Gwenith STR_CARGO_PLURAL_RUBBER :Rwber STR_CARGO_PLURAL_SUGAR :Siwgr STR_CARGO_PLURAL_TOYS :Teganau STR_CARGO_PLURAL_CANDY :Melysion STR_CARGO_PLURAL_COLA :Cola STR_CARGO_PLURAL_COTTON_CANDY :Candifflos STR_CARGO_PLURAL_BUBBLES :Swigod STR_CARGO_PLURAL_TOFFEE :Toffi STR_CARGO_PLURAL_BATTERIES :Baterïau STR_CARGO_PLURAL_PLASTIC :Plastig STR_CARGO_PLURAL_FIZZY_DRINKS :Diodydd Pefriol # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :Teithwyr STR_CARGO_SINGULAR_COAL :Glo STR_CARGO_SINGULAR_MAIL :Post STR_CARGO_SINGULAR_OIL :Olew STR_CARGO_SINGULAR_LIVESTOCK :Da Byw STR_CARGO_SINGULAR_GOODS :Nwyddau STR_CARGO_SINGULAR_GRAIN :Grawn STR_CARGO_SINGULAR_WOOD :Pren STR_CARGO_SINGULAR_IRON_ORE :Mwyn Haearn STR_CARGO_SINGULAR_STEEL :Dur STR_CARGO_SINGULAR_VALUABLES :Trysorau STR_CARGO_SINGULAR_COPPER_ORE :Mwyn Copr STR_CARGO_SINGULAR_MAIZE :India Corn STR_CARGO_SINGULAR_FRUIT :Ffrwyth STR_CARGO_SINGULAR_DIAMOND :Diemwnt STR_CARGO_SINGULAR_FOOD :Bwyd STR_CARGO_SINGULAR_PAPER :Papur STR_CARGO_SINGULAR_GOLD :Aur STR_CARGO_SINGULAR_WATER :Dŵr STR_CARGO_SINGULAR_WHEAT :Gwenith STR_CARGO_SINGULAR_RUBBER :Rwber STR_CARGO_SINGULAR_SUGAR :Siwgr STR_CARGO_SINGULAR_TOY :Tegan STR_CARGO_SINGULAR_CANDY :Melysyn STR_CARGO_SINGULAR_COLA :Cola STR_CARGO_SINGULAR_COTTON_CANDY :Candifflos STR_CARGO_SINGULAR_BUBBLE :Swigen STR_CARGO_SINGULAR_TOFFEE :Toffi STR_CARGO_SINGULAR_BATTERY :Batri STR_CARGO_SINGULAR_PLASTIC :Plastig STR_CARGO_SINGULAR_FIZZY_DRINK :Diod Perfiol # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA}{NBSP}teithiwr STR_QUANTITY_COAL :{WEIGHT_LONG} o lo STR_QUANTITY_MAIL :{COMMA}{NBSP}bag o bost STR_QUANTITY_OIL :{VOLUME_LONG} o olew STR_QUANTITY_LIVESTOCK :{COMMA}{NBSP}eitem o dda byw STR_QUANTITY_GOODS :{COMMA}{NBSP}crât o nwyddau STR_QUANTITY_GRAIN :{WEIGHT_LONG} o rawn STR_QUANTITY_WOOD :{WEIGHT_LONG} o goed STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} o fwyn haearn STR_QUANTITY_STEEL :{WEIGHT_LONG} o ddur STR_QUANTITY_VALUABLES :{COMMA}{NBSP}bag o drysorau STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} o fwyn copr STR_QUANTITY_MAIZE :{WEIGHT_LONG} o india corn STR_QUANTITY_FRUIT :{WEIGHT_LONG} o ffrwyth STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}bag o ddiemwntau STR_QUANTITY_FOOD :{WEIGHT_LONG} o fwyd STR_QUANTITY_PAPER :{WEIGHT_LONG} o bapur STR_QUANTITY_GOLD :{COMMA}{NBSP}bag o aur STR_QUANTITY_WATER :{VOLUME_LONG} o ddŵr STR_QUANTITY_WHEAT :{WEIGHT_LONG} o wenith STR_QUANTITY_RUBBER :{VOLUME_LONG} o rwber STR_QUANTITY_SUGAR :{WEIGHT_LONG} o siwgr STR_QUANTITY_TOYS :{COMMA}{NBSP}tegan STR_QUANTITY_SWEETS :{COMMA}{NBSP}bag o felysion STR_QUANTITY_COLA :{VOLUME_LONG} o gola STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} o gandifflos STR_QUANTITY_BUBBLES :{COMMA} swigen STR_QUANTITY_TOFFEE :{WEIGHT_LONG} o doffi STR_QUANTITY_BATTERIES :{COMMA} batri STR_QUANTITY_PLASTIC :{VOLUME_LONG} o blastig STR_QUANTITY_FIZZY_DRINKS :{COMMA} diod pefriog STR_QUANTITY_N_A :N/A # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}TEI STR_ABBREV_COAL :{TINY_FONT}GLO STR_ABBREV_MAIL :{TINY_FONT}PST STR_ABBREV_OIL :{TINY_FONT}OLW STR_ABBREV_LIVESTOCK :{TINY_FONT}DBW STR_ABBREV_GOODS :{TINY_FONT}NWY STR_ABBREV_GRAIN :{TINY_FONT}GRW STR_ABBREV_WOOD :{TINY_FONT}COE STR_ABBREV_IRON_ORE :{TINY_FONT}HAE STR_ABBREV_STEEL :{TINY_FONT}DUR STR_ABBREV_VALUABLES :{TINY_FONT}TRY STR_ABBREV_COPPER_ORE :{TINY_FONT}CPR STR_ABBREV_MAIZE :{TINY_FONT}CRN STR_ABBREV_FRUIT :{TINY_FONT}FFR STR_ABBREV_DIAMONDS :{TINY_FONT}DMN STR_ABBREV_FOOD :{TINY_FONT}BWD STR_ABBREV_PAPER :{TINY_FONT}PAP STR_ABBREV_GOLD :{TINY_FONT}AUR STR_ABBREV_WATER :{TINY_FONT}DWR STR_ABBREV_WHEAT :{TINY_FONT}GTH STR_ABBREV_RUBBER :{TINY_FONT}RWB STR_ABBREV_SUGAR :{TINY_FONT}SIW STR_ABBREV_TOYS :{TINY_FONT}TEG STR_ABBREV_SWEETS :{TINY_FONT}MEL STR_ABBREV_COLA :{TINY_FONT}COL STR_ABBREV_CANDYFLOSS :{TINY_FONT}CFF STR_ABBREV_BUBBLES :{TINY_FONT}SWI STR_ABBREV_TOFFEE :{TINY_FONT}TFI STR_ABBREV_BATTERIES :{TINY_FONT}BAT STR_ABBREV_PLASTIC :{TINY_FONT}PLS STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}DIO STR_ABBREV_NONE :{TINY_FONT}DIM STR_ABBREV_ALL :{TINY_FONT}OLL # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA}{NBSP}teithiwr STR_BAGS :{COMMA}{NBSP}bag STR_TONS :{COMMA}{NBSP}tunnell STR_LITERS :{COMMA}{NBSP}litr STR_ITEMS :{COMMA}{NBSP}eitem STR_CRATES :{COMMA}{NBSP}crât # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Glas Tywyll STR_COLOUR_PALE_GREEN :Gwyrdd Golau STR_COLOUR_PINK :Pinc STR_COLOUR_YELLOW :Melyn STR_COLOUR_RED :Coch STR_COLOUR_LIGHT_BLUE :Glas Golau STR_COLOUR_GREEN :Gwyrdd STR_COLOUR_DARK_GREEN :Gwyrdd Tywyll STR_COLOUR_BLUE :Glas STR_COLOUR_CREAM :Hufen STR_COLOUR_MAUVE :Porffor Golau STR_COLOUR_PURPLE :Porffor STR_COLOUR_ORANGE :Oren STR_COLOUR_BROWN :Brown STR_COLOUR_GREY :Llwyd STR_COLOUR_WHITE :Gwyn # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mph STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}hp STR_UNITS_POWER_METRIC :{COMMA}{NBSP}hp STR_UNITS_POWER_SI :{COMMA}{NBSP}kW STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}{NBSP}kg STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA}{NBSP}tunell STR_UNITS_WEIGHT_LONG_METRIC :{COMMA}{NBSP}tunnell STR_UNITS_WEIGHT_LONG_SI :{COMMA}{NBSP}kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}{NBSP}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}{NBSP}m³ STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA}{NBSP}galwyn STR_UNITS_VOLUME_LONG_METRIC :{COMMA}{NBSP}litr STR_UNITS_VOLUME_LONG_SI :{COMMA}{NBSP}m³ STR_UNITS_FORCE_IMPERIAL :{COMMA}{NBSP}lbf STR_UNITS_FORCE_METRIC :{COMMA}{NBSP}kgf STR_UNITS_FORCE_SI :{COMMA}{NBSP}kN STR_UNITS_HEIGHT_IMPERIAL :{COMMA}{NBSP}tr STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Llinyn hidlo: STR_LIST_FILTER_OSKTITLE :{BLACK}Rhowch linyn hidlo STR_LIST_FILTER_TOOLTIP :{BLACK}Rhowch allweddair er mwyn ei ddefnyddio i hidlo'r rhestr STR_TOOLTIP_GROUP_ORDER :{BLACK}Dewis trefn grwpio STR_TOOLTIP_SORT_ORDER :{BLACK}Dewiswch drefn trefnu (disgynnol/esgynnol) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Dewiswch drefn trefnu STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Dewis criteria hidlydd STR_BUTTON_SORT_BY :{BLACK}Trefnu yn ôl STR_BUTTON_LOCATION :{BLACK}Lleoliad STR_BUTTON_RENAME :{BLACK}Ailenwi STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Cau ffenestr STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Teitl ffenestr - llusgwch hwn i symud ffenestr STR_TOOLTIP_SHADE :{BLACK}Cysgodi'r ffenest - dangos y bar teitl yn unig STR_TOOLTIP_DEBUG :{BLACK}Dangos gwybodaeth dadnamu NewGRF STR_TOOLTIP_DEFSIZE :{BLACK}Ailfeintio'r ffenestr i'w faint rhagosodedig. Bydd Ctrl+Clic yn storio'r maint presenol fel rhagosodiad STR_TOOLTIP_STICKY :{BLACK}Nodi'r ffenest yma fel un na ellir ei gau can yr allwedd 'Cau Pob Ffenestr'. Bydd Ctrl+Clicio'n cadw'r dewis fel rhagosodiad STR_TOOLTIP_RESIZE :{BLACK}Cliciwch a llusgo er mwyn newid maint y ffenestr STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Toglu maint ffenestri mawr/bach STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Bar sgrolio - sgrolio'r rhestr i fyny neu i lawr STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Bar sgrolio - sgrolio'r rhestr i'r chwith neu i'r dde STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Dymchwel adeiladau ayb. ar sgwâr o dir. Mae Ctrl yn dewis ardal deiagonal. Mae Shift yn toglo adeiladu/dangos amcangyfrif cost # Show engines button STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Dangos rhai cudd STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Dangos rhai cudd STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP :{BLACK}Dangos rhai cudd STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT :{BLACK}Dangos rhai cudd STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP :{BLACK}Drwy alluogi'r botwm yma, fe ddangosir y cerbydau rheilffordd cudd hefyd STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE_TOOLTIP :{BLACK}Drwy alluogi'r botwm yma, fe ddangosir y cerbydau ffordd cudd hefyd STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP_TOOLTIP :{BLACK}Drwy alluogi'r botwm yma, fe ddangosir y llongau cudd hefyd STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Drwy alluogi'r botwm yma, fe ddangosir yr awyrennau cudd hefyd # Query window STR_BUTTON_DEFAULT :{BLACK}Rhagosodiad STR_BUTTON_CANCEL :{BLACK}Diddymu STR_BUTTON_OK :{BLACK}Iawn # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}Hyd: {NUM} STR_MEASURE_AREA :{BLACK}Ardal: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Hyd: {NUM}{}Gwahaniaeth uchder: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Ardal: {NUM} x {NUM}{}Gwahaniaeth uchder: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}Enw STR_SORT_BY_CAPTION_DATE :{BLACK}Dyddiad # These are used in dropdowns STR_SORT_BY_NAME :Enw STR_SORT_BY_PRODUCTION :Cynyrch STR_SORT_BY_TYPE :Math STR_SORT_BY_TRANSPORTED :Wedi'i gludo STR_SORT_BY_NUMBER :Rhif STR_SORT_BY_PROFIT_LAST_YEAR :Elw llynedd STR_SORT_BY_PROFIT_THIS_YEAR :Elw eleni STR_SORT_BY_AGE :Oed STR_SORT_BY_RELIABILITY :Dibynadwyedd STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Cyfanswm Gallu Cludo fesul y math o lwyth STR_SORT_BY_MAX_SPEED :Cyflymder Uchaf STR_SORT_BY_MODEL :Model STR_SORT_BY_VALUE :Gwerth STR_SORT_BY_LENGTH :Hyd STR_SORT_BY_LIFE_TIME :Oes yn weddill STR_SORT_BY_TIMETABLE_DELAY :Oediad amserlen STR_SORT_BY_FACILITY :Math Gorsaf STR_SORT_BY_WAITING_TOTAL :Cyfanswm llwythi sy'n aros STR_SORT_BY_WAITING_AVAILABLE :Llwythi sy'n aros ar gael STR_SORT_BY_RATING_MAX :Safon cludiant uchaf STR_SORT_BY_RATING_MIN :Safon cludiant isaf STR_SORT_BY_ENGINE_ID :ID Injan (math clasurol) STR_SORT_BY_COST :Cost STR_SORT_BY_POWER :Pŵer STR_SORT_BY_TRACTIVE_EFFORT :Grym tynnu STR_SORT_BY_INTRO_DATE :Dyddiad cyflwyno STR_SORT_BY_RUNNING_COST :Cost rhedeg STR_SORT_BY_POWER_VS_RUNNING_COST :Pŵer/Cost rhedeg STR_SORT_BY_CARGO_CAPACITY :Gallu cludo llwyth STR_SORT_BY_RANGE :Maes teithio STR_SORT_BY_POPULATION :Poblogaeth STR_SORT_BY_RATING :Gradd # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Oedi'r gêm STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Cyflymu'r gêm STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Dewisiadau STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Cadw'r gêm, gwaredu a'r gêm, gadael STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Dangos map STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Dangos cyfeiriadur trefi STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Dangos Cymorthdaliadau STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Dangos rhestr o orsafoedd y cwmni STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Dangos gwybodaeth cyllid y cwmni STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Dangos gwybodaeth gyffredinol y cwmni STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Dangos llyfr hanes STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Dangos rhestr amcanion STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Dangos graffiau STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Dangos tabl cynghrair cwmnïau STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Ariannu adeiladu diwydiant newydd STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Dangos rhestr o drenau'r cwmni. Mae Ctrl+Clic yn toglo agor y rhestr grŵp/cerbyd STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Dangos rhestr o gerbydau ffordd y cwmni. Mae Ctrl+Clic yn toglo agor y rhestr grŵp/cerbyd STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :4. {BLACK}Dangos rhestr o longau'r cwmni. Mae Ctrl+Clic yn toglo agor y rhestr grŵp/cerbyd STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Dangos rhestr o awyrennau'r cwmni. Mae Ctrl+Clic yn toglo agor y rhestr grŵp/cerbyd STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Agosáu'r olygfa STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Pellhau'r olygfa STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Adeiladu Rheilffyrdd STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Adeiladu Ffordd STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Adeiladu Doc Llongau STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Adeiladu meysydd awyr STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Agor y bar offer tirweddu er mwyn codi neu ostwng tir, plannu coed ayb. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Dangos y ffenestr Sain/Cerddoriaeth STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Dangos Neges/Adroddiad newyddion ddiwethaf, Dangos Dewisiadau Negeseuon STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Gwybodaeth ardal tir, dadnamu sgriptiau, lluniau sgrin, amdan OpenTTD STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Amnewid bariau offer # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Cadw Senario, llwytho senario, gwaredu a'r golygydd senario, gadael STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Golygydd Senario STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Symud y dyddiad cychwyn yn ôl 1 blwyddyn STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Symud y dyddiad cychwyn ymlaen 2 flynedd STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Cliciwch i fewnbynnu'r flwyddyn dechreuol STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Dangos map, cyfeiriadur trefi STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Cynhyrchu tirwedd STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Cynhyrchu trefi STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Cynhyrchu Diwydiannau STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Cynhyrchu Ffyrdd STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plannu coed. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Gosod arwydd STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Gosod. Mae Shift yn toglo adeiladu/dangos amcangyfrif o'r gost ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Cadw senario STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Llwytho senario STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Cadw siart uchder STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Llwytho siart uchder STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Gwaredu a'r golygydd senario STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Gadael ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :Dewisiadau Gêm STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Gosodiadau STR_SETTINGS_MENU_SCRIPT_SETTINGS :Gosodiadau AI / sgript Gêm STR_SETTINGS_MENU_NEWGRF_SETTINGS :Gosodiadau NewGRF STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Dewisiadau tryloywder STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Dangos enwau trefi STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Dangos enwau gorsafoedd STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Dangos enwau pwyntiau llwybro STR_SETTINGS_MENU_SIGNS_DISPLAYED :Dangos arwyddion STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Dangos arwyddion ac enwau cystadleuwyr STR_SETTINGS_MENU_FULL_ANIMATION :Animeiddiad llawn STR_SETTINGS_MENU_FULL_DETAIL :Manylder llawn STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Adeiladau tryloyw STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Arwyddion tryloyw ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Cadw Gêm STR_FILE_MENU_LOAD_GAME :Llwytho Gêm STR_FILE_MENU_QUIT_GAME :Rhoi'r gorau i'r Gêm STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Gadael ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :Map o'r Byd STR_MAP_MENU_EXTRA_VIEW_PORT :Ffenestr Olygfa Newydd STR_MAP_MENU_LINGRAPH_LEGEND :Allwedd Llif Cargo STR_MAP_MENU_SIGN_LIST :Rhestr Arwyddion ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Cyfeiriadur Trefi STR_TOWN_MENU_FOUND_TOWN :Sefydlu tref ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :Cymorthdaliadau ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Graff Elw Gweithredol STR_GRAPH_MENU_INCOME_GRAPH :Graff Incwm STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Graff Llwythi a Ddanfonwyd STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Graff Hanes Perfformiad STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Graff Gwerth Cwmni STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Cyfraddau Tâl Llwythi ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Tabl Cynghrair Cwmnïau STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Graddfa Fanwl Perfformiad STR_GRAPH_MENU_HIGHSCORE :Tabl sgôr uchaf ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Cyfeiriadur Diwydiannau STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Cadwyni diwydiant STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Ariannu diwydiant newydd ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Adeiladu rheilffordd STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Adeiladu rheilffordd drydan STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Adeiladu monoreilffordd STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Adeiladu maglef ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Adeiladu ffyrdd STR_ROAD_MENU_TRAM_CONSTRUCTION :Adeiladu tramffordd ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Adeiladu camlesi ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Adeiladu maes awyr ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :Tirweddu STR_LANDSCAPING_MENU_PLANT_TREES :Plannu coed STR_LANDSCAPING_MENU_PLACE_SIGN :Gosod arwydd ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :Sain/cerddoriaeth ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Neges/Adroddiad newyddion ddiwethaf STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Hanes negeseuon ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Gwybodaeth ardal tir STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :Toglu Consol STR_ABOUT_MENU_AI_DEBUG :Dadnamu AI / Sgript Gêm STR_ABOUT_MENU_SCREENSHOT :Ciplun STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Ciplun lefel mwyhád uchaf STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Ciplun pellter rhagosodedig STR_ABOUT_MENU_GIANT_SCREENSHOT :Ciplun o'r map cyfan STR_ABOUT_MENU_ABOUT_OPENTTD :Gwybodaeth am 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Aliniwr corluniau STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toglo bocsys ffinio STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toglo llwio blociau budr ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :1af STR_ORDINAL_NUMBER_2ND :2il STR_ORDINAL_NUMBER_3RD :3ydd STR_ORDINAL_NUMBER_4TH :4ydd STR_ORDINAL_NUMBER_5TH :5ed STR_ORDINAL_NUMBER_6TH :6ed STR_ORDINAL_NUMBER_7TH :7fed STR_ORDINAL_NUMBER_8TH :8fed STR_ORDINAL_NUMBER_9TH :9fed STR_ORDINAL_NUMBER_10TH :10fed STR_ORDINAL_NUMBER_11TH :11eg STR_ORDINAL_NUMBER_12TH :12fed STR_ORDINAL_NUMBER_13TH :13eg STR_ORDINAL_NUMBER_14TH :14eg STR_ORDINAL_NUMBER_15TH :15fed ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :1af STR_DAY_NUMBER_2ND :2il STR_DAY_NUMBER_3RD :3ydd STR_DAY_NUMBER_4TH :4ydd STR_DAY_NUMBER_5TH :5ed STR_DAY_NUMBER_6TH :6ed STR_DAY_NUMBER_7TH :7ed STR_DAY_NUMBER_8TH :8ed STR_DAY_NUMBER_9TH :9ed STR_DAY_NUMBER_10TH :10ed STR_DAY_NUMBER_11TH :11eg STR_DAY_NUMBER_12TH :12ed STR_DAY_NUMBER_13TH :13eg STR_DAY_NUMBER_14TH :14eg STR_DAY_NUMBER_15TH :15ed STR_DAY_NUMBER_16TH :16eg STR_DAY_NUMBER_17TH :17eg STR_DAY_NUMBER_18TH :18ed STR_DAY_NUMBER_19TH :19eg STR_DAY_NUMBER_20TH :20ed STR_DAY_NUMBER_21ST :21ain STR_DAY_NUMBER_22ND :22ain STR_DAY_NUMBER_23RD :23ain STR_DAY_NUMBER_24TH :24ain STR_DAY_NUMBER_25TH :25ain STR_DAY_NUMBER_26TH :26ain STR_DAY_NUMBER_27TH :27ain STR_DAY_NUMBER_28TH :28ain STR_DAY_NUMBER_29TH :29ain STR_DAY_NUMBER_30TH :30ain STR_DAY_NUMBER_31ST :31ain ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :Ion STR_MONTH_ABBREV_FEB :Chwe STR_MONTH_ABBREV_MAR :Maw STR_MONTH_ABBREV_APR :Ebr STR_MONTH_ABBREV_MAY :Mai STR_MONTH_ABBREV_JUN :Meh STR_MONTH_ABBREV_JUL :Gor STR_MONTH_ABBREV_AUG :Awst STR_MONTH_ABBREV_SEP :Medi STR_MONTH_ABBREV_OCT :Hyd STR_MONTH_ABBREV_NOV :Tach STR_MONTH_ABBREV_DEC :Rhag STR_MONTH_JAN :Ionawr STR_MONTH_FEB :Chwefror STR_MONTH_MAR :Mawrth STR_MONTH_APR :Ebrill STR_MONTH_MAY :Mai STR_MONTH_JUN :Mehefin STR_MONTH_JUL :Gorffennaf STR_MONTH_AUG :Awst STR_MONTH_SEP :Medi STR_MONTH_OCT :Hydref STR_MONTH_NOV :Tachwedd STR_MONTH_DEC :Rhagfyr ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}Allwedd STR_GRAPH_KEY_TOOLTIP :{BLACK}Dangos allwedd i'r graffiau STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Graff Elw Gweithredol STR_GRAPH_INCOME_CAPTION :{WHITE}Graff Incwm STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Llwythi wedi'u cludo (mewn unedau) STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Graddfeydd Perfformiad Cwmni (gradd uchaf=1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Gwerth Cwmnïau STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Graddfeydd Tâl Llwythi STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Diwrnodau ar daith STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Tâl am gludo llwyth o 10 uned (neu 10,000 litr) pellter o 20 sgwâr STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Galluogi popeth STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Analluogi popeth STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Dangos pob llwyth ar y graff cyfraddau taliadau llwythi STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Peidio a dangos llwythi ar y graff cyfraddau talaidau llwythi STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toglu'r graff ar gyfer math llwyth ymlaen neu i ffwrdd STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Dangos manwl amcangyfrif perfformiad # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}Allwedd i'r graffiau cwmni STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Cliciwch yma i doglu cofnod cwmni ymlaen neu i ffwrdd # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Tablau Cynghrair Cwmnïau STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Peiriannydd STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Rheolwr Traffig STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Cydlynydd Cludiant STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Goruchwyliwr Ffyrdd STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Cyfarwyddwr STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Prif Weithredwr STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Cadeirydd STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :Llywydd STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Teicŵn # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}Graddio perfformiad manwl STR_PERFORMANCE_DETAIL_KEY :{BLACK}Allwedd STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}Gweld manylion y cwmni hwn ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Cerbydau: STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Gorsafoedd: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Lleiafswm elw: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Lleiafswm incwm: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Uchafswm incwm: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Cludwyd: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Llwyth: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Arian: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Benthyciad: STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Cyfanswm: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Nifer y cerbydau Mae hyn yn cynnwys cerbydau a enillodd elw y llynedd. ffordd, trenau, llongau ac awyrennau STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Nifer y gorsafoedd gyda gwasanaeth diweddar. Mae gorsafoedd trenau, gorsafoedd bysiau a meysydd awyr yn cael eu cyfrif yn anibynnol hyd yn oed os ydynt wedi'u cysylltu i'r un gorsaf STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}Elw'r cerbyd gyda'r incwm lleiaf (o'r rhai sydd dros deuflwydd oed) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Cyfanswm yr arian a enillwyd yn y chwarter gyda'r elw isaf o'r 12 chwarter ddiwethaf STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Cyfanswm yr arian a enillwyd yn y chwarter gyda'r elw uchaf o'r 12 chwarter ddiwethaf STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Cyfanswm yr unedau llwyth a gludwyd yn y 4 chwarter diwethaf STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Nifer y mathau gwahanol o lwythi a gludwyd yn y chwarter diwethaf STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Cyfanswm yr arian sydd gan y cwmni hwn yn y banc STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}Cyfanswm yr arian mae'r cwmni hwn wedi ei fenthyg ar hyn o bryd STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Cyfanswm y pwyntiau allan o'r pwyntiau posib # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Jukebox Jazz STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}Pob Arddull STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Arddull Newydd STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}Hen Arddull STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Ezy Scoedent STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Cyfaddas 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Cyfaddas 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Lefel Sain Cerddoriaeth STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Lefel Sain Effeithiau STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}ISAF STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}UCHAF STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Teitl STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Trac STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Cymysgu Trefn STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Rhaglen STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Neidio i'r gân ddiwethaf yn y rhestr STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Neidio i'r gân nesaf yn y rhestr STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Peidio chwarae cerddoriaeth STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Dechrau chwarae cerddoriaeth STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Llusgwch y llithrwyr i osod lefelau'r sain a'r gerddoriaeth STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Dewis y rhaglen 'pob trac' STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Dewis y rhaglen 'cerddoriaeth arddull hen' STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Dewis y rhaglen 'cerddoriaeth arddull newydd' STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Dewis y rhaglen 'Ezy Scoedent style music' STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Dewis y rhaglen 'Cyfaddas 1' (dewis y defnyddiwr) STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Dewis y rhaglen 'Cyfaddas 2' (dewis y defnyddiwr) STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Toglu cymysgu trefn rhaglen ymlaen neu i ffwrdd STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Dangos y ffenestr dewis traciau cerddoriaeth STR_ERROR_NO_SONGS :{WHITE}Dewiswyd set caneuon heb ganeuon ynddo. Ni chwaraeir unrhyw ganeuon # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Dewisiadau Rhaglen Gerddoriaeth STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Indecs Traciau STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Rhaglen - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Clirio STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Clirio'r rhaglen gyfredol (Cyfaddas 1 neu Cyfaddas 2) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Cliciwch i ychwanegu trac cerddoriaeth i'r rhaglen gyfredol (Cyfaddas 1 Neu Cyfaddas 2 yn unig) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Cliciwch i dynnu trac cerddoriaeth o'r rhaglen gyfredol (Cyfaddas 1 Neu Cyfaddas 2 yn unig) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Y Cwmnïau Brig a gyrhaeddodd Lefel {NUM} STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Y Tabl Cynghrair Cwmnïau yn {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Dyn Busnes STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Entrepreneur STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Diwydiannydd STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Cyfalafwr STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnad STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Mogwl STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Teicŵn STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}Mae {COMPANY} wedi cyrraedd statws '{STRING}'! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}Mae {PRESIDENT_NAME} o gwmni {COMPANY} wedi cyrraedd statws '{STRING}'! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}Map - {STRING} STR_SMALLMAP_TYPE_CONTOURS :Cyfuchlin STR_SMALLMAP_TYPE_VEHICLES :Cerbydau STR_SMALLMAP_TYPE_INDUSTRIES :Diwydiannau STR_SMALLMAP_TYPE_ROUTEMAP :Llif Cargo STR_SMALLMAP_TYPE_ROUTES :Ffyrdd STR_SMALLMAP_TYPE_VEGETATION :Llystyfiant STR_SMALLMAP_TYPE_OWNERS :Perchnogion STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Dangos cyfuchlinau tir ar y map STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Dangos cerbydau ar y map STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Dangos diwydiannau ar y map STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Dangos llif cargo ar y map STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Dangos llwybrau cludo ar y map STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Dangos llystyfiant ar y map STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Dangos perchnogion tir ar y map STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Cliciwch ar ddiwydiant i doglo ei arddangos. Mae Ctrl+Clic'n cuddio pob math ond yr un a ddewiswyd. Ctrl+Cliciwch arno eto i ddangos pob diwydiant STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Cliciwch ar gwmni i doglo arddangos ei eiddo. Mae Ctrl+Clic yn cuddio pob cwmni ond yr un a ddewiswyd. Ctrl+Cliciwch arno eto i ddangos pob cwmni STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Cliciwch ar gargo i doglo arddangos ei rinweddau. Mae Ctrl+Clic yn analluogi pob cargo on yr un a glicwyd. Bydd Ctrl+Clicio arno eto'n galluogi pob cargo. STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Ffyrdd STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Rheilffyrdd STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Gorsafoedd/Meysydd Awyr/Dociau STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Adeiladau/Diwydiannau STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Cerbydau STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Trenau STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Cerbydau Ffordd STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Llongau STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Awyrennau STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Llwybrau Cludiant STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Coedwig STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Gorsaf Reilffordd STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Man Llwytho Lorïau STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Gorsaf Fysiau STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Maes Awyr/Glanfa Hofrenyddion STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Doc STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Tir Garw STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Glaswelltir STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Tir Moel STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Caeau STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Coed STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Creigiau STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Dŵr STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}Dim Perchennog STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Trefi STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Diwydiannau STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Anialwch STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Eira STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Toglu dangos enwau trefi ar y map ymlaen neu i ffwrdd STR_SMALLMAP_CENTER :{BLACK}Canoli'r map bach ar y lleoliad presennol STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}Analluogi popeth STR_SMALLMAP_ENABLE_ALL :{BLACK}Galluogi popeth STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Dangos uchder STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Peidio â dangos unrhyw ddiwydiant ar y map STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Dangos pob diwydiant ar y map STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Toglo dangos y map uchder STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Peidio â dangos unrhyw eiddo cwmni ar y map STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Dangos eiddo pob cwmni ar y map STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Peidio â dangos cargo ar y map STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Dangos pob cargo ar y map # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Dangos y neges neu'r adroddiad newyddion ddiwethaf... STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * WEDI'I OEDI * * STR_STATUSBAR_AUTOSAVE :{RED}AWTOGADW STR_STATUSBAR_SAVING_GAME :{RED}* * CADW GÊM * * # News message history STR_MESSAGE_HISTORY :{WHITE}Hanes Negeseuon STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}Rhestr o'r negeseuon newyddion diweddaraf STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING} STR_NEWS_MESSAGE_CAPTION :{WHITE}Neges STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Mae'r trigolion yn dathlu . . .{}Mae'r trên cyntaf wedi cyrraedd {STATION}! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Mae'r trigolion yn dathlu . . .{}Mae'r bws cyntaf wedi cyrraedd {STATION}! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Mae'r trigolion yn dathlu . . .{}Mae'r lori gyntaf wedi cyrraedd {STATION}! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Mae'r trigolion yn dathlu . . .{} Mae'r tram teithwyr cyntaf wedi cyrraedd {STATION}! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Mae'r trigolion yn dathlu . . .{} Mae'r tram nwyddau cyntaf wedi cyrraedd {STATION}! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Mae'r trigolion yn dathlu . . .{}Mae'r llong gyntaf wedi cyrraedd {STATION}! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Mae'r trigolion yn dathlu . . .{}Mae'r awyren gyntaf wedi cyrraedd {STATION}! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Trên wedi crashio!{}Bu {COMMA} farw yn y ddamwain STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Damwain Cerbyd Ffordd!{}Bu gyrrwr farw mewn damwain â thrên STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Damwain Cerbyd Ffordd!{}Bu farw {COMMA} mewn damwain â thrên STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Damwain Awyren!{}Bu farw {COMMA} mewn tanchwa yn {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Damwain Awyren!{}Dim digon o danwydd yn yr awyren, {COMMA} yn marw mewn coelcerth STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Trychineb Zeppelin yn {STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Cerbyd ffordd wedi'i ddinistrio ar ôl taro 'UFO'! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Ffrwydrad purfa olew ger {TOWN}! STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Dinistriwyd ffatri mewn modd amheus ger {TOWN}! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}Glaniodd 'UFO' ger {TOWN}! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Ymsuddiant glofa ger {TOWN} yn creu llanast! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Llifogydd!{}O leiaf {COMMA} ar goll, wedi'i tybio'n farw wedi glaw mawr! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Cwmni cludiant mewn trafferth! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}Bydd {STRING} yn cael ei werthu neu ei ddatgan yn fethdalwr oni bai fod ei berfformiad yn gwella'n fuan! STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Uno cwmnïau cludiant! STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}Mae {STRING} wedi cael ei werthu i {STRING} am {CURRENCY_LONG}! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Methdalwyr! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}Mae {STRING} wedi cael ei gau gan ei gredydwyr a''u hasedau wedi'u gwerthu! STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}Cwmni cludiant newydd wedi'i lansio! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}Mae {STRING} wedi cychwyn adeiladu ger {TOWN}! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}Mae {STRING} wedi cael ei brynu gan {STRING}! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Manager) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}Mae {STRING} wedi noddi sefydlu tref newydd {TOWN}! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}{STRING} newydd wrthi'n cael ei adeiladu wrth {TOWN}! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}{STRING} newydd wrthi'n cael ei phlannu wrth {TOWN}! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}Mae {STRING} yn datgan eu bod ar fin cau! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Mae problemau cyflenwi wedi gorfodi i {STRING} ddatgan ei fod ar fin cau! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Mae diffyg unrhyw goed gerllaw wedi gorfodi i {STRING} ddatgan ei fod ar fin cau! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}Arian Sengl Ewropeaidd!{}{}Cafodd yr Ewro ei gyflwyno fel unig arian cyfred eich gwlad! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}Dirwasgiad Byd-eang!{}{}Arbenigwyr ariannol yn ofni'r gwaethaf wrth i'r economi gwympo! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Dirwasgiad ar Ben!{}{}Cynnydd masnach yn rhoi hyder i ddiwydiant wrth i'r economi gryfhau! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}Mae {INDUSTRY} yn cynyddu ei gynnyrch! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}Darganfuwyd gwythïen newydd o lo yn {INDUSTRY}!{}Disgwylir y bydd y cynnyrch yn dyblu! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}Darganfuwyd ffynhonnell newydd o olew yn {INDUSTRY}!{}Disgwylir y bydd y cynnyrch yn dyblu! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}Mae disgwyl i well ddulliau ffermio yn {INDUSTRY} ddyblu'r cynnyrch! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}Mae cynnyrch {STRING} {INDUSTRY} yn cynyddu {COMMA}%! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}Cynnyrch yn {INDUSTRY} i lawr 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Pla o locustiaid yn peri dinistr yn {INDUSTRY}!{}Cynnyrch 50% yn is STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}Mae cynnyrch {STRING} {INDUSTRY} yn gostwng {COMMA}%! STR_NEWS_TRAIN_IS_WAITING :{WHITE}Mae {VEHICLE} yn aros yn y depo STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}Mae {VEHICLE} yn aros yn y depo STR_NEWS_SHIP_IS_WAITING :{WHITE}Mae {VEHICLE} yn aros yn y depo STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}Mae {VEHICLE} yn aros yn yr awrendy # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}Nid oes gan {VEHICLE} ddigon o orchmynion yn ei amserlen STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}Mae gan {VEHICLE} orchymyn gwallus STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}Mae gan {VEHICLE} orchmynion dyblyg STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}Mae gan {VEHICLE} orsaf annilys yn ei orchmynion STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY :{WHITE}Mae gan {VEHICLE}o fewn ei orchmynion faes awyr sydd â llwybr glanio sy'n rhy fyr STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}Mae {VEHICLE} yn heneiddio STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}Mae {VEHICLE} yn hynod o hen STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}Mae {VEHICLE} yn hynod o hen ac angen ei ddisodli STR_NEWS_TRAIN_IS_STUCK :{WHITE}Mae {VEHICLE} yn methu dod o hyd i lwybr i barhau STR_NEWS_VEHICLE_IS_LOST :{WHITE}Mae {VEHICLE} ar goll STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}Elw {VEHICLE} y flwyddyn diwethaf oedd {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} methu parhau i'r cyrchfan nesaf gan ei fod allan o gyrraedd y cerbyd STR_NEWS_ORDER_REFIT_FAILED :{WHITE}Stopiodd achos methiant hefo trefnu ailffitio {VEHICLE} STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Methwyd ag adnewyddu {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Mae {STRING} newydd yn awr ar gael! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Mae {STRING} newydd yn awr ar gael! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}Nid yw {STATION} bellach yn derbyn {STRING} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}Nid yw {STATION} bellach yn derbyn {STRING} na {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}Mae {STATION} nawr yn derbyn {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}Mae {STATION} nawr yn derbyn {STRING} a {STRING} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Cynnig cymhorthdal ar ben:{}{}Ni fydd cludo {STRING} o {STRING} i {STRING} yn derbyn cymhorthdal bellach STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Cymhorthdal wedi'i dynnu'n ôl: {}{}Ni fydd gwasanaeth {STRING} o {STRING} i {STRING} yn derbyn cymhorthdal bellach STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Cynnig cymhorthdal:{}{}Bydd y gwasanaeth {STRING} cyntaf o {STRING} i {STRING} yn derbyn blwyddyn o gymhorthdal gan yr awdurdod lleol! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Cymhorthdal wedi ei ddyfarnu i {STRING}!{}{}Bydd y gwasanaeth {STRING} o {STRING} i {STRING} yn talu 50% yn fwy am y flwyddyn nesaf! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Cymhorthdal wedi ei ddyfarnu i {STRING}!{}{}Bydd y gwasanaeth {STRING} o {STRING} i {STRING} yn talu dwywaith yn fwy am y flwyddyn nesaf! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Cymhorthdal wedi ei ddyfarnu i {STRING}!{}{}Bydd y gwasanaeth {STRING} o {STRING} i {STRING} yn talu teirgwaith yn fwy am y flwyddyn nesaf! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Cymhorthdal wedi ei ddyfarnu i {STRING}!{}{}Bydd y gwasanaeth {STRING} o {STRING} i {STRING} yn talu pedair gwaith yn fwy am y flwyddyn nesaf! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Anrhefn traffig yn {TOWN}!{}{}Daw gwaith ffordd a ariannwyd gan {STRING} â 6 mis o boen i deithwyr ffordd y dref! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Monopoli cludiant! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}Awdurdog lleol {TOWN} yn arwyddo cytundeb cyfyngol gyda {STRING} am flwyddyn o hawliau cludiant! # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Ffenestr Olygfa{COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Copïo i Ffenestr Olygfa STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Copïo lleoliad y golwg byd-eang i'r ffenestr olygfa STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Gludo o'r Ffenestr Olygfa STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Gludo lleoliad y ffenestr olygfa i'r golwg byd-eang # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Dewisiadau Gêm STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Uned Arian STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Dewis unedau arian ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :Punnoedd Prydeinig (GBP) STR_GAME_OPTIONS_CURRENCY_USD :Doleri America (USD) STR_GAME_OPTIONS_CURRENCY_EUR :Ewro (EUR) STR_GAME_OPTIONS_CURRENCY_JPY :Yen Siapan (JPY) STR_GAME_OPTIONS_CURRENCY_ATS :Swllt Awstriaidd (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :Ffranc Belgaidd (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :Ffranc Swisaidd (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :Koruna Tsecaidd (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :Deutschmark (DEM) STR_GAME_OPTIONS_CURRENCY_DKK :Krone Danaidd (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :Peseta Sbaen (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :Markka Ffinaidd(FIM) STR_GAME_OPTIONS_CURRENCY_FRF :Ffranc Ffrainc (FRF) STR_GAME_OPTIONS_CURRENCY_GRD :Drachma (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :Forint (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :Krona Ynys yr Iâ (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :Lira Eidalaidd (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :Guilder (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :Krone Norwyaidd (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Złoty Pwylaidd (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Leu Rwmanaidd (RON) STR_GAME_OPTIONS_CURRENCY_RUR :Rwbl Rwsaidd (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Tolar Slofenaidd (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Krona Swedaidd (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Lira Twrcaidd (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :Koruna Slofacaidd (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :Real Brazilaidd (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :Krooni Estonia (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Litau Lithiwanaidd (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :Won De Korea (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :Rand De Affrica (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :Addasedig... STR_GAME_OPTIONS_CURRENCY_GEL :Lari Georgia (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Rial Iran (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Cerbydau Ffordd STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Dewiswch ar ba ochr i'r ffordd y dylai cerbydau yrru STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Gyrru ar y chwith STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Gyrru ar y dde STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Enwau Trefi STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Dewis arddull yr enwau trefi ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :Saesneg (Gwreiddiol) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :Ffrangeg STR_GAME_OPTIONS_TOWN_NAME_GERMAN :Almaeneg STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :Saesneg (Ychwanegol) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :America Ladin STR_GAME_OPTIONS_TOWN_NAME_SILLY :Gwirion STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Swedaidd STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Iseldireg STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Ffinnaidd STR_GAME_OPTIONS_TOWN_NAME_POLISH :Pwylaidd STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slofacaidd STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norwyaidd STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Hwngaraidd STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Awstriaidd STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Rwmaniaidd STR_GAME_OPTIONS_TOWN_NAME_CZECH :Tsecaidd STR_GAME_OPTIONS_TOWN_NAME_SWISS :Swisaidd STR_GAME_OPTIONS_TOWN_NAME_DANISH :Danaidd STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Twrcaidd STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Eidalaidd STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Catalanaidd ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Awtogadw STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Dewiswch pa mor aml y dylid awtogadw gemau ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Diffodd Awtogadw STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Bob mis STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :Bob 3 mis STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :Bob 6 mis STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Bob 12 mis ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}Iaith STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Dewiswch yr iaith rhyngwyneb i'w defnyddio STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Sgrin Llawn STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Marciwch y blwch hwn i chwarae Open TTD gyda Sgrin Llawn STR_GAME_OPTIONS_RESOLUTION :{BLACK}Cydraniad Sgrin STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Dewiswch y cydraniad sgrin i'w defnyddio STR_GAME_OPTIONS_RESOLUTION_OTHER :arall STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Maint rhyngwyneb STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Dewis maint yr elfennau rhyngwyneb i'w defnyddio STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Arferol STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Dyblyg STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Pedwarplyg STR_GAME_OPTIONS_BASE_GRF :{BLACK}Set raffeg sylfaenol STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Dewiswch y set raffeg sylfaenol i'w defnyddio STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} ffeil ar goll/llygredig STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Gwybodaeth ychwanegol am y set graffeg sylfaenol STR_GAME_OPTIONS_BASE_SFX :{BLACK}Set sain sylfaenol STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Dewisiwch y set sain sylfaenol i'w ddefnyddio STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Gwybodaeth bellach am y set sain sylfaenol STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Set cerddoriaeth sylfaenol STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Dewisiwch y set cerddoriaeth sylfaenol i'w ddefnyddio STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} ffeil llygredig STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Gwybodaeth bellach am y set gerddoriaeth sylfaenol STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Methu nôl rhestr o cydraniadau cydnaws STR_ERROR_FULLSCREEN_FAILED :{WHITE}Methodd y modd sgrin llawn # Custom currency window STR_CURRENCY_WINDOW :{WHITE}Arian cyfaddas STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Cyfradd gyfnewid: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Llehad yr swm o eich arian cyfred am un Punt (£) STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Amlhau yr swm o eich arian cyfred am un Punt (£) STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}newid y raddfa gyfnewid o eich arian cyfred i un Punt (£) STR_CURRENCY_SEPARATOR :{LTBLUE}Gwahanydd: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Dewis y nod gwahanu ar gyfer eich arian STR_CURRENCY_PREFIX :{LTBLUE}Rhagddodiad: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Dewis y rhagddodiad ar gyfer eich arian STR_CURRENCY_SUFFIX :{LTBLUE}Olddodiad: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Dewis yr ôl-lddodiad ar gyfer eich arian STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Newid i'r Ewro: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Newid i'r Ewro: {ORANGE}byth STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Gosod y flwyddyn i newid i'r Ewro STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Newid i'r Ewro yn gynnar. STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Newid i'r Ewro yn hwyrach STR_CURRENCY_PREVIEW :{LTBLUE}Rhagolwg: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 Punt (£) yn eich arian cyfaddas STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Newid paramedrau arian cyfaddas STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Uchafswm nifer y cystadleuwyr: {ORANGE}{COMMA} STR_NONE :Dim STR_FUNDING_ONLY :Ariannu'n unig STR_MINIMAL :Lleiafsymol STR_NUM_VERY_LOW :Isel Iawn STR_NUM_LOW :Isel STR_NUM_NORMAL :Arferol STR_NUM_HIGH :Uchel STR_NUM_CUSTOM :Addasedig STR_NUM_CUSTOM_NUMBER :Addasiedig ({NUM}) STR_VARIETY_NONE :Dim STR_VARIETY_VERY_LOW :Isel Iawn STR_VARIETY_LOW :Isel STR_VARIETY_MEDIUM :Cymhedrol STR_VARIETY_HIGH :Uchel STR_VARIETY_VERY_HIGH :Uchel Iawn STR_AI_SPEED_VERY_SLOW :Araf Iawn STR_AI_SPEED_SLOW :Araf STR_AI_SPEED_MEDIUM :Cymhedrol STR_AI_SPEED_FAST :Cyflym STR_AI_SPEED_VERY_FAST :Cyflym iawn STR_SEA_LEVEL_VERY_LOW :Isel Iawn STR_SEA_LEVEL_LOW :Isel STR_SEA_LEVEL_MEDIUM :Canolig STR_SEA_LEVEL_HIGH :Uchel STR_SEA_LEVEL_CUSTOM :Addasiedig STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Addasiedig ({NUM}%) STR_RIVERS_NONE :Dim STR_RIVERS_FEW :Ychydig STR_RIVERS_MODERATE :Cymhedrol STR_RIVERS_LOT :Llawer STR_DISASTER_NONE :Dim STR_DISASTER_REDUCED :Llai STR_DISASTER_NORMAL :Arferol STR_SUBSIDY_X1_5 :x1.5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 STR_TERRAIN_TYPE_VERY_FLAT :Gwastad Iawn STR_TERRAIN_TYPE_FLAT :Gwastad STR_TERRAIN_TYPE_HILLY :Bryniog STR_TERRAIN_TYPE_MOUNTAINOUS :Mynyddig STR_TERRAIN_TYPE_ALPINIST :Mynyddwr STR_CITY_APPROVAL_PERMISSIVE :Bodlon STR_CITY_APPROVAL_TOLERANT :Hapus STR_CITY_APPROVAL_HOSTILE :Gwrthwynebus STR_WARNING_NO_SUITABLE_AI :{WHITE}Dim AI addas ar gael...{}Gallwch llawrlwytho sawl AI drwy'r system 'Cynnwys Ar-lein' # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Gosodiadau STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Llinyn hidlo: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Ehangu oll STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Cywasgu oll STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(dim esboniad ar gael) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Gwerth rhagosodedig: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Math o osodiad: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Gosodiad gwestai (ni gedwir yn y ffeiliau cadw; yn effeithio ar pob gêm) STR_CONFIG_SETTING_TYPE_GAME_MENU :Gosodiad gêm (cedwir yn y ffeiliau cadw; yn effeithio ar gemau newydd yn unig) STR_CONFIG_SETTING_TYPE_GAME_INGAME :Gosodiad gêm (cedwir yn y ffeil gadw; yn effeithio ar y gêm bresennol yn unig) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Gosodiad cwmni (cedwir yn y ffeiliau cadw; yn effeithio ar gemau newydd yn unig) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Gosodiad cwmni (cedwir yn y ffeil gadw; yn effeithio ar y cwmni presennol yn unig) STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categori: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Math: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Yn cyfyngu'r rhestr isod drwy hidlau rhagosodedig STR_CONFIG_SETTING_RESTRICT_BASIC :Sylfaenol (gosodiadau pwysig yn unig) STR_CONFIG_SETTING_RESTRICT_ADVANCED :Uwch (y rhan helaeth o'r gosodiadau) STR_CONFIG_SETTING_RESTRICT_ALL :Arbennigwyr (gosodiadau arbennigol, gan gynnwys rhai rhyfedd) STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Gosodiadau sy'n wahanol i'r rhagosodiad STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Gosodiadau gyda gwerth gwahanol i'ch gosodiadau gêm newydd chi STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Yn cyfyngu'r rhestr isod at mathau gosodiad penodol STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :Pob math o osodiad STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Gosodiadau gwestai (cedwir yn y ffeiliau cadw; yn effeithio ar pob gêm) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Gosodiadau gêm (cedwir yn y ffeiliau cadw, gan effeithio ar gemau newydd yn unig) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Gosodiadau gêm (cedwir yn y ffeil cadw, gan effeithio ar y gêm bresennol yn unig) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Gosodiadau cwmni (cedwir yn y ffeiliau cadw, gan effeithio ar gemau newydd yn unig) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Gosodiadau cwmni (cedwir yn y ffeil cadw, gan effeithio ar y cwmni presennol yn unig) STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Dangosir holl ganlyniadau chwilio drwy osod{}{SILVER}Categori {BLACK}i {WHITE}{STRING} STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Dangosir holl ganlyniadau chwilio drwy osod{}{SILVER}Math {BLACK}i {WHITE}Pob math o osodiad STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Dangosir holl ganlyniadau chwilio drwy osod{}{SILVER}Categori {BLACK}at {WHITE}{STRING} {BLACK}a {SILVER}Math {BLACK}i {WHITE}Pob math o osodiad STR_CONFIG_SETTINGS_NONE :{WHITE}- Dim - STR_CONFIG_SETTING_OFF :I Ffwrdd STR_CONFIG_SETTING_ON :Ymlaen STR_CONFIG_SETTING_DISABLED :Analluogwyd STR_CONFIG_SETTING_COMPANIES_OFF :I ffwrdd STR_CONFIG_SETTING_COMPANIES_OWN :Eich cwmni STR_CONFIG_SETTING_COMPANIES_ALL :Cwmnïau eraill STR_CONFIG_SETTING_NONE :Dim STR_CONFIG_SETTING_ORIGINAL :Gwreiddiol STR_CONFIG_SETTING_REALISTIC :Realistig STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Chwith STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Canol STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :De STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Benthyciad agoriadol uchafsymol: {STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Y swm uchaf y gall cwmni fenthyca (heb ustyried chwyddiant) STR_CONFIG_SETTING_INTEREST_RATE :Cyfradd chwyddiant: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Cyfradd chwyddiant y benthyciad; hefyd chwyddiant yr economi os y galluogir STR_CONFIG_SETTING_RUNNING_COSTS :Costau rhedeg: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Gosod lefel costau cynnal a chadw ar gerbydau a thanadeiledd STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Cyflymder adeiladu: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Cyfyngu'r nifer o weithredoedd adeiliadu ar gyfer AIau STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Toriadau cerbydau: {STRING} STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Gosod pa mor aml y gall gerbydau heb eu gwasanaethu'n rheolaidd dorri i lawr STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Lluosydd cymhorthdal: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Gosod faint a delir ar gyfer cysylltiadau gyda chymhorthdal STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Costau adeiladu: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Gosod lefel costau prynnu ac adeiladu STR_CONFIG_SETTING_RECESSIONS :Dirwasgiadau: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Os y galluogir, gall dirwasgiadau ddigwydd ambell flwyddyn. Yn ystod dirwasgiad bydd lefelau gweithgynhyrchu'n is o lawer (gan ddychwelyd at y lefel gwreiddiol wedi diwedd y dirwasgiad) STR_CONFIG_SETTING_TRAIN_REVERSING :Rhwystro trenau rhag gwrthdroi mewn gorsafoedd: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Os y galluogir, ni fydd trenau yn gwrthdroi mewn gorsafoedd nad ydynt yn derfynfeydd, hyd yn oed os oes llwybr byrach i'w cyrchfan drwy wrthdroi STR_CONFIG_SETTING_DISASTERS :Trychinebau: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Toglo trychinebau a all rhwystro neu ddinistrio cerbydau neu tanadeiledd STR_CONFIG_SETTING_CITY_APPROVAL :Agwedd y cyngor tref at ailstrwythuro'r ardal: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Dewis faint y mae sŵn a niwed amgycheddol gan gwmnïau yn effeithio ar eu graddio trefol a gweithredoedd adeiladu pellach yn eu hardal STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Uchder map uchafsymol: {STRING} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Gosod yr uchder uchafsymol a ganiateir ar gyfer mynyddoedd ar y map STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Ni allwch osod uchder uchafsymol y map i'r gwerth yma. Mae o leiaf un mynydd ar y map yn uwch STR_CONFIG_SETTING_AUTOSLOPE :Caniatáu tirffurfio o dan adeiladau, traciau, ayyb.: {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Caniatáu tirffurfio o dan adeiladau a thraciau heb eu chwalu STR_CONFIG_SETTING_CATCHMENT :Caniatáu ardaloedd dalgylch mwy realistig eu maint: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Defnyddio dalgylchoedd o feintiau gwahanol ar gyfer gwahanol fathau o orsafoedd a meysydd awyr STR_CONFIG_SETTING_EXTRADYNAMITE :Caniatáu chwalu mwy o ffyrdd, pontydd ayb. sy'n berthyn i drefi: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Hwyluso chwalu tanadeiledd ac adeiladau sy'n eiddo i drefi STR_CONFIG_SETTING_TRAIN_LENGTH :Hyd uchafsymol trenau: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Gosod yr hyd ychafsymol ar gyfer trenau STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} teil STR_CONFIG_SETTING_SMOKE_AMOUNT :Faint o fŵg/sbarciau gan gerbydau: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Gosod faint o fwg neu sawl sbarc a allyrrir gan gerbydau STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Model cyflymu trenau: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Dewis y model ffiseg ar gyfer cyflymiad trenau. Mae'r model "gwreiddiol" yn arafu cerbydau ar lethrau'n unfath. Mae'r model "realistig" yn arafu cerbydau ar lethrau a throeon yn ôl amryw baramedrau'r trên, megis ei hyd a'i rym tynnu STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Model cyflymiad cerbydau ffordd: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Dewis y model ffiseg ar gyfer cerbydau ffordd. Mae'r model "gwreiddiol" yn arafu cerbydau ar lethrau'n unfath. Mae'r model "realistig" yn arafu cerbydau ar lethrau a throeon yn ôl amryw baramedrau'r injan, megis ei 'rym tynnu' STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Serthrwydd llethrau ar gyfer trenau: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Serthrwydd teil llethr ar gyfer trên. Mae gwerthoedd uwch yn ei gwneud yn anoddach i ddringo allt STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Serthrwydd llethrau ar gyfer cerbydau ffordd: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Serthrwydd teil llethr ar gyfer cerbyd ffordd. Mae gwerthoedd uwch yn ei gwneud yn anoddach i ddringo allt STR_CONFIG_SETTING_FORBID_90_DEG :Rhwystro trenau a llongau rhag troi 90 gradd: {STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Tro 90 gradd yw pan fo trac llorweddol yn cael ei ddilyn yn syth gan drac fertigol at y teil cyfagos, gan wneud i'r trên droi 90 gradd wrth groesi ochr y teil yn hytrach na'r 45 gradd sydd i'w gael gyda chyfuniadau trac eraill. Mae hyn hefyd yn effeithio ar gylch troi llongau STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Caniatáu cyfuno gorsafoedd nad ydynt yn union gyfochrog: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Caniatáu ychwanegu rhannau at orsaf heb gyffwrdd yn uniongyrchol a'r rhai sydd eisioes yn bodoli. STR_CONFIG_SETTING_INFLATION :Chwyddiant: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Galluogi chwyddiant yn yr economi, lle y bydd costau'n codi ychydig yn gyflymach na thaliadau STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Hyd pont uchafsymol: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Hyd uchafsymol ar gyfer adeiladu pontydd STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Uchder pontydd uchafsymol: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Uchder uchafsymol ar gyfer adeiladu pontydd STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Hyd twnel uchafsymol: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Hyd uchafsymol ar gyfer adeiladu twneli STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Prif ddull adeiladu diwydiannau cynradd: {STRING} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Dull o ariannu diwydiant cynradd. Mae 'dim' yn golygu nid yw'n bosib ariannu rhai, 'mwynchwilio' yn golygu fod modd ariannu, ond bydd adeiladu'n digwydd mewn man ar hap ac y gall fethu llawn cystad, ac 'fel diwydiannau eraill' yn golygu fod modd eu hadeiladu gan gwmnïau fel diwydiannau eraill mewn unryw man y mynnent STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :Dim STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :Fel diwydiannau eraill STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Mwynchwilio STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Ardal gwastad o amgylch diwydiannau: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Ardal gwastad o amgylch diwydiant. Mae hyn yn sicrhau fod yna le gwastad o amgylch diwydiant ar gyfer adeiladu traciau a.y.y.b. STR_CONFIG_SETTING_MULTIPINDTOWN :Caniatáu nifer o ddiwydiannau unfath i bob tref: {STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Fel arfer, ni fydd tref eisiau mwy nag un diwydiant o unrhyw fath. Bydd y gosodiad yma'n caniatáu nifer o ddiwydiannau o'r un fath yn yr un dref STR_CONFIG_SETTING_SIGNALSIDE :Dangos signalau: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Dewis pa ochr o'r trac i osod signalau STR_CONFIG_SETTING_SIGNALSIDE_LEFT :Ar y chwith STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :Ar yr ochr gyrru STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :Ar y dde STR_CONFIG_SETTING_SHOWFINANCES :Dangos y ffenestr gyllid ar ddechrau'r flwyddyn: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Os y galluogir, bydd y ffenestr gyllid yn agor ar ddiwedd y flwyddyn i hwyluso archwilio sefyllfa ariannol y cwmni STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Gorchmynion newydd yn 'ddi-stop' fel rhagosodiad: {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Fel rheol, bydd cerbyd yn aros wrth pob gorsaf yr aiff drwyddo. Bydd y gosodiad yma yn peri i'r cerbyd yrru'n syth drwy pob gorsaf ar ei ffordd at ei gyrchfan olaf heb aros. Sylwer fod y gosodiad yma'n diffinio rhagosodiad ar gyfer gorchmynion newydd. Gellir newid gorchmynion penodol at unrhyw ddull a fynnir STR_CONFIG_SETTING_STOP_LOCATION :Gorchmynion trenau newydd yn nodi aros ar y {STRING} o'r platfform fel rhagosodiad STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Y man lle y daw trên at aros wrth blatfform fel rheol. Mae'r 'ochr agos' yn cyfeirio at y pen lle mae'r trên yn myned, 'canol' at ganol y platfform, ac 'ochr bell' yn bell o'r mynedfa. Sylwer fod y gosodiad yma'n diffinio rhagosodiad ar gyfer gorchmynion newydd. Gellir newid gorchmynion penodol at unrhyw ddull a fynnir STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :ochr agos STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :canol STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :ochr bell STR_CONFIG_SETTING_AUTOSCROLL :Tremio'r ffenestr pan fydd y llygoden ar ymyl y sgrin: {STRING} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Pan y galluogir, bydd ffenestri golwg yn dechrau sgrolio pan fo'r llygoden yn agos at ochr y ffenest STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Analluogwyd STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Prif ffenestr olygfa, sgrin llawn yn unig STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Prif ffenestr olygfa STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Pob ffenestr olygfa STR_CONFIG_SETTING_BRIBE :Caniatáu llwgrwobrwyo'r awdurdod lleol: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Caniatáu i gwmnïau geisio llwgrwobrwyo'r awdurdod lleol. Os bydd arolygydd yn sylwi ar yr ymgais ni gaiff y cwmni weithredu yn y dref am chwe mis STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Caniatáu prynu hawliau cludo cyfyngol: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Os yw cwmni'n prynnu hawliau cludiant cyfyngol mewn tref, ni fydd gosafoedd (teithwyr a chargo) gwrthwynebwyr yn derbyn unrhyw gargo am flwyddyn STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Caniatáu ariannu adeiladau: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Caniatáu i gwmnïau rhoi arian i drefi er mwyn adeiladu tai newydd STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Caniatáu ariannu gwaith ffordd lleol: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Caniatáu i gwmnïau rhoi arian i drefi er mwyn ail-adeiladu ffyrdd a drysu gwasanaethau ffordd yn y dref STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Caniatáu trosglwyddo arian i gwmnïau eraill: {STRING} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Caniatáu trosglwyddo arian rhwng cwmnïau mewn gêm amlchwaraewr STR_CONFIG_SETTING_FREIGHT_TRAINS :Lluosogydd pwysau ar gyfer llwythi i adlewyrchu trenau trwm{STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Gosod yr effaith o gario llwythi trom mewn trenau. Bydd gwerth uwch yn gwneud cludo llwythi'n galetach i drenau, yn arbennig ar elltydd STR_CONFIG_SETTING_PLANE_SPEED :Ffactor cyflymder awyrennau: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Gosod cyflymder awyrennau o gymharu â cherbydau eraill, i leihau'r incwm wrth gludo mewn awyren STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Nifer o ddamweiniau awyren: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Gosod y tebygolrwydd o drychineb awyren STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Dim STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Llai STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Arferol STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Caniatáu arosfannau gyrru-trwodd ar ffyrdd sy'n eiddo i drefi: {STRING} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Caniatáu adeiladu arosfannau gyrru-trwodd ar ffyrdd sy'n eiddo i drefi STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Caniatáu arosfannau gyrru-trwodd ar ffyrdd sy'n eiddo i gystadleuwyr: {STRING} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Caniatáu adeiladu arosfannau gyrru-trwodd ar ffyrth sy'n eiddo i gwmnïau eraill STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Nid yw'n bosib newid y gosodiad yma pan fo cerbydau'n bodoli STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Cynnal a chadw tanadeiledd: {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Pan fo wedi'i alluogi, mae tanadeiledd yn creu costau cynnal a chadw. Mae'r cost yn codi'n gyflymach na'i gyfradd gyda thŵf y rhwydwaith, gan effeithio'n fwy ar gwmniau mawr na rhai bychan STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Maes awyr ddim yn dibennu: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Mae galluogi'r dewis yma'n peri i bob math o faes awyr aros ar gael am byth wedi ei gyflwyniad gyntaf STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Rhybuddio os yw cerbyd ar goll: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Creu negeseuon am gerbydau sy'n methu dod o hyd i lwybr at eu cyrchfan gorchymedig STR_CONFIG_SETTING_ORDER_REVIEW :Adolygu gorchmynion y cerbyd: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Pan fo wedi'i alluogi, caiff gorchmynion cerbydau eu gwirio'n aclysurol, ac fe adroddir am rai trafferthion amlwg gyda neges newyddion STR_CONFIG_SETTING_ORDER_REVIEW_OFF :Na STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Ia, ond hepgor cerbydau sydd yn aros STR_CONFIG_SETTING_ORDER_REVIEW_ON :O bob cerbyd STR_CONFIG_SETTING_WARN_INCOME_LESS :Rhybuddio os yw cerbyd yn gwneud colled: {STRING} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :Pan fo wedi'i alluogi, fe yrrir neges newyddion pan fo cerbyd heb wneud elw yn ystod blwyddyn calendr STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Nid yw cerbydau'n darfod: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :Pan fo wedi'i alluogi, bydd bob math o gerbyd yn aros ar gael am byth wedi eu cyflwyniad gyntaf STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Awtoadnewyddu cerbyd pan aiff yn hen: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :Pan fo wedi'i alluogi, bydd cerbyd sy'n agos at ddiwedd ei oes yn cael ei ddisodli'n ddiofyn pan y caiff yr amodau adnewyddu eu cyflawni STR_CONFIG_SETTING_AUTORENEW_MONTHS :Awtoadnewyddu pan fo cerbyd {STRING} ei oed uchafsymol STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Oed cymharol pan y dylid ystyried awtoadnewyddu cerbyd STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} mis cyn STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} mis wedi STR_CONFIG_SETTING_AUTORENEW_MONEY :Isafswm arian awtoadnewyddu ar gyfer adnewyddu: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Lleiafswm arian a ddylai aros yn y banc cyn ystyried awtoadnewyddu cerbydau STR_CONFIG_SETTING_ERRMSG_DURATION :Ystod neges gwall: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Amser i ddangos negeseuon gwall mewn ffenestr coch. Sylwer ni gaiff rhai negeseuon gwall (difrifol) eu cau'n ddiofyn STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} eiliad STR_CONFIG_SETTING_HOVER_DELAY :Dangos cynghorion: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Oediad cyn y dangosir cynghorion wrth ddal y cyrchydd dros rhyw elfen rhyngwyneb. Fel arall rhwymir cynghorion at botwm dde'r llygoden pan fo'r gwerth yma'n 0. STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Oedi am {COMMA} milfed o eiliad STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :De glicio STR_CONFIG_SETTING_POPULATION_IN_LABEL :Dangos poblogaeth tref yn label y dref: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Dangos poblogaeth trefi yn eu label ar y map STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Trwch llinellau graff: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Lled y linell mewn graffiau. Bydd llinell fain yn fwy manwl, tra y bydd llinell trwchus yn haws i'w weld gyda lliwiau'n fwy amlwg STR_CONFIG_SETTING_LANDSCAPE :Tirwedd: {STRING} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Mae tirweddau'n diffinio senario sylfaenol gydag amryw fathau o gargo ac anghenion twf trefi. Mae NewGRF a Sgriptiau Gêm yn cynnig rheolaeth mannach, fodd bynnag STR_CONFIG_SETTING_LAND_GENERATOR :Cynhyrchydd Tir: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :Mae'r crewr gwreiddiol yn ddibynol ar y set graffeg sylfaenol, ac yn creu siapiau tirwedd gosodedig. Mae TerraGenesis yn seiliedig ar generadur said Perlin, gyda gosodiadau manylach STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Gwreiddiol STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_TERRAIN_TYPE :Math tirwedd: {STRING} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(TerraGenesis yn unig) Llyfnder y tirwedd STR_CONFIG_SETTING_INDUSTRY_DENSITY :Dwysedd diwydiant: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Gosod faint o ddiwydiannau y dylid eu creu a pha lefel caiff eu cynnal drwy'r gêm STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Pellter uchafsymol o'r ochr ar gyfer Purfeydd olew: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Codir purfeydd olew ger ymylon y map yn unig, h.y. ar yr arfordir mewn mapiau ynys STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Uchder Llinell Eira: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Rheoli'r uchder y mae eira'n ymddangos mewn tirwedd is-arctig. Mae eira hefyd yn effeitiho ar gynhyrchu diwydiannau a gofynion twf trefi STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Garwder y tirwedd: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(TerraGenesis yn unig) Dewis amlder bryniau: Mae gan tirwedd llyfn nifer isel o fryniau bylchedig. Mae gan dirwedd garw llawer o fryniau, a all edrych yn undonog STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Llyfn Iawn STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Llyfn STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Garw STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Garw Iawn STR_CONFIG_SETTING_VARIETY :Dosraniad amrywiaeth: {STRING} STR_CONFIG_SETTING_VARIETY_HELPTEXT :(TerraGenesis yn unig) Rheoli a yw'r map yn cynnwys ardaloedd mynyddig a gwastad. Gan fod hyn yn gwneud y map yn fwy gwastad, dylid addasu gosodiadau eraill at mynyddig STR_CONFIG_SETTING_RIVER_AMOUNT :Nifer afonydd: {STRING} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Dewis sawl afon i'w creu STR_CONFIG_SETTING_TREE_PLACER :Algorithm gosod coed: {STRING} STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Dewis dosraniad coed ar y map: mae 'Gwreiddiol' yn plannu coed mewn dosraniad unffurf, a 'Gwell' yn eu plannu mewn grwpiau STR_CONFIG_SETTING_TREE_PLACER_NONE :Dim STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Gwreiddiol STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Gwell STR_CONFIG_SETTING_ROAD_SIDE :Cerbydau ffordd: {STRING} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Dewis yr ochr gyrru STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Tro Map Uchder: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Gwrthglocwedd STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Clocwedd STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :Y lefel map uchder mae map senario fflat yn ei dderbyn: {STRING} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}Nid yw un neu fwy o'r teiliau ar ymyl gogleddol y map yn wag STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}Nid yw un neu fwy o'r teiliau ar un o'r ymylon yn ddŵr STR_CONFIG_SETTING_STATION_SPREAD :Gwasgariad gorsaf uchafsymol: {STRING} STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Yr ardal mwyaf y caiff cydrannau gorsaf unigol eu gwasgaru trosto. Sylwer y bydd gwerthoedd uchel yn arafu'r gêm STR_CONFIG_SETTING_SERVICEATHELIPAD :Rhoi gwasanaeth i hofrenyddion ar helepads yn awtomatig: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Gwasanaethu hefrenyddion wedi pop glaniad, hyd yn oed os nad oes depô yn y maes awyr STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Cyfuno'r bar offer tirwedd gyda'r bariau offer ffordd/rheilffordd/maes awyr: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :Wrth agor bar offer adeiladu ar gyfer math o drafnidiaeth, agor y bar offer tirweddu hefyd STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Lliw tir a ddefnyddir ar y map bychan: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Lliw y tirwedd yn y map bychan STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Gwyrdd STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Gwyrdd tywyll STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Fioled STR_CONFIG_SETTING_REVERSE_SCROLLING :Gwrthdroi'r cyfeiriad sgrolio: {STRING} STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :Ymddygiad pan yn sgrolio gyda botwm dde y llygoden. Pan yr analluogir, bydd y llygoden yn symyd y camera. Pan y galluogir, bydd y llygoden yn symyd y map STR_CONFIG_SETTING_SMOOTH_SCROLLING :Sgrolio prif ffenestr llyfn: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Rheoli syt y mae'r prif olygfa'n sgrolio at leoliad penodol pan yn clicio ar y map bychan neu yn rhoi gorchymyn i sgrolio at wrthrych penodol STR_CONFIG_SETTING_MEASURE_TOOLTIP :Dangos cymorth mesur wrth ddefnyddio'r offer adeiladu amrywiol: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Dangos pellterau teil a gwahaniaethau uchder wrth lusgo tra'n adeiladu STR_CONFIG_SETTING_LIVERIES :Defnyddio lifrau cerbyd-benodol: {STRING} STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Rheoli defnydd o lifrau cerbyd-benodol ar gyfer cerbydau (yn hytrach na lliwiau'r cwmni) STR_CONFIG_SETTING_LIVERIES_NONE :Dim STR_CONFIG_SETTING_LIVERIES_OWN :Eich Cwmni STR_CONFIG_SETTING_LIVERIES_ALL :Pob cwmni STR_CONFIG_SETTING_PREFER_TEAMCHAT :Newid Sgwrsio Tîm i : {STRING} STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Newid rhwymiadau sgwrs cwmni a sgwrs cyhoeddus at a yn ôl eu trefn STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Gweithred yr olwyn sgrolio: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Galluogi sgrolio gydag olwynion llygoden â dwy echel STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Mwyhau map STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Sgrolio map STR_CONFIG_SETTING_SCROLLWHEEL_OFF :I ffwrdd STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Cyflymder olwyn sgrolio map: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Rheoli manylder sgrolio olwyn y llygoden STR_CONFIG_SETTING_OSK_ACTIVATION :Allweddfwrdd ar y sgrin: {STRING} STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Dewis y dull i agor yr allweddfwrdd ar-sgrin ar gyfer mewnbynnu testun gan ddefnyddio'r cyrchydd yn unig STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Analluogwyd STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Clic ddwbl STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Clic sengl (pan fo ffocws) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Clic sengl (ar unwaith) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Efelychu de-glicio: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Dewis sut i efelychu cliciau botwm dde y llygoden STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command-clic STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+Clic STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :I ffwrdd STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Sgrolio Clic-chwith: {STRING} STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :Galluogi sgrolio ar y map drwy ei lusgo gyda botwm chwith y llygoden. Mae hyn yn arbennig o ddefnyddiol pan yn defnyddio sgrin-gyffwrdd ar gyfer sgrolio STR_CONFIG_SETTING_AUTOSAVE :Awtogadw: {STRING} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :Dewis pa mor aml y dylid awtogadw gemau STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Defnyddio'r fformat dyddiad {STRING} ar gyfer enwau gemau wedi'u cadw STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Fformat y dyddiad mewn enwau ffeiliau cadw STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :hir (31ain Rhag 2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :byr(31-12-2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Oedi'n awtomatig wrth gychwyn gêm newydd: {STRING} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Pan y galluogir, bydd yn gêm yn oedi ar ddechrau gêm newydd, er mwyn astudio'r map STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Tra fo wedi'i oedi, caniatáu: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Dewis pa weithredoedd y gellid eu gwneud tra fo'r gêm wedi ei oedi STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :Dim gweithredoedd STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :Pob gweithred ac eithro adeiladu STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :Pob gweithred ac eithro addasu tirwedd STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :Pob gweithred STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Defnyddio grwpiau yn y rhestr cerbydau: {STRING} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Galluogi defnydd o'r rhestrau cerbyd uwch ar gyfer grwpio cerbydau STR_CONFIG_SETTING_LOADING_INDICATORS :Dangos llwytho: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Dewis a fydd dangosyddion llwytho'n cael eu dangos uwch cerbydau sy'n llwytho neu dadlwytho STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Dangos amserlen fesul ticiau yn hytrach na dyddiau: {STRING} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Dangos amseroedd teithio mewn amserlenni mewn ticiau yn hytrach na dyddiau STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Dangos cyrraedd a gadael mewn amserlenni: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Dangos amseroedd cyrraedd a gadael rhagdybiedig mewn amserlenni STR_CONFIG_SETTING_QUICKGOTO :Creu cyflym ar gyfer gorchmynion cerbydau: {STRING} STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Rhag-ddewis y 'cyrchydd mynd i' pan yn agor y ffenestr gorchmynion STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Math rheilffordd ragosodedig (ar ôl gêm newydd/llwytho gêm ): {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Math o gledrau i'w ddewis wedi dechrau neu lwytho gêm. Bydd 'y cyntaf ar gael' yn dewis y math hynaf, 'yr olaf ar gael' yn dewis y diweddaraf, a 'defnydd mwyaf' y math mwyaf cyffredin ar hyn o bryd STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :Y cyntaf sydd ar gael STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Yr olaf sydd ar gael STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Defnydd mwyaf STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Dangos llwybrau traciau wedi'u cadw: {STRING} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Rhoi lliw gwahanol ar gledrau lliw gwahanol i gynorthwyo datrys problemau gyda threnau sy'n gwrthod myned blociau llwybro STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Cadw'r offer adeiladu yn weithredol wedi ei ddefnydd: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Cadw'r offer adeiladu pontydd, twneli, a.y.y.b. ar agor wedi eu defnydd STR_CONFIG_SETTING_EXPENSES_LAYOUT :Grwpio costau yn ffenestr cyllid y cwmni: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Diffinio cynllun ffenestr costau'r cwmni STR_CONFIG_SETTING_SOUND_TICKER :Stribyn newyddion: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Chwarae sŵn ar gyfer crynodiadau newyddion STR_CONFIG_SETTING_SOUND_NEWS :Papur newydd: {STRING} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Chwarae sŵn ar ddangos papurau newydd STR_CONFIG_SETTING_SOUND_NEW_YEAR :Diwedd y flwyddyn: {STRING} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Chwarae sŵn ar ddiwedd blwyddyn i adlewyrchu perfformiad y cwmni am y flwyddyn o'i gymharu a'r llynedd STR_CONFIG_SETTING_SOUND_CONFIRM :Adeiladu: {STRING} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Chwarae sŵn wrth adeiladu'n lwyddiannus neu ar weithredoedd eraill STR_CONFIG_SETTING_SOUND_CLICK :Cliciau botwm: {STRING} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Bipio wrth glicio botymau STR_CONFIG_SETTING_SOUND_DISASTER :Trychinebau/damweiniau: {STRING} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Chwarae effeithiau sŵn damweiniau a thrychinebau STR_CONFIG_SETTING_SOUND_VEHICLE :Cerbydau: {STRING} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Chwarae effeithiau sŵn cerbydau STR_CONFIG_SETTING_SOUND_AMBIENT :Cefndir: {STRING} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Chwarae synau cefndirol y tirwedd, diwydiannau a threfi STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Analluogi adeiladu tanadeiledd pan nad oes cerbydau addas ar gael: {STRING} STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :Pan y galluogir, nid yw tanadeiledd ar gael nes fod cerbydau ar gael iddo, gan osgoi gwastraff arian ac amser ar danadeiledd na ellir ei ddefnyddio STR_CONFIG_SETTING_MAX_TRAINS :Uchafswm nifer y trenau i bob cwmni: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Nifer uchafsymol y trenau y gall cwmni fod yn berchen arnynt STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Uchafswm nifer y cerbydau ffordd i bob cwmni: {STRING} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Nifer uchafsymol y cerbydau ffordd y gall cwmni fod yn berchen arnynt STR_CONFIG_SETTING_MAX_AIRCRAFT :Uchafswm nifer yr awyrennau i bob cwmni: {STRING} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Nifer uchafsymol yr awyrennau y gall cwmni fod yn berchen arnynt STR_CONFIG_SETTING_MAX_SHIPS :Uchafswm nifer y llongau i bob cwmni: {STRING} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Nifer uchafsymol y llongau y gall cwmni fod yn berchen arnynt STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Analluogi trenau ar gyfer y cyfrifiadur: {STRING} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Mae galluogi'r gosodiad yma'n ei gwneud yn amhosib i chwaraewr cyfrifiadur adeiladu trenau STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Analluogi cerbyd ffordd ar gyfer y cyfrifiadur: {STRING} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Mae galluogi'r gosodiad yma'n ei gwneud yn amhosib i chwaraewr cyfrifiadur adeiladu cerbydau ffordd STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Analluogi awyren ar gyfer y cyfrifiadur: {STRING} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Mae galluogi'r gosodiad yma'n ei gwneud yn amhosib i chwaraewr cyfrifiadur adeiladu awyrennau STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Analluogi llongau ar gyfer y cyfrifiadur: {STRING} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Mae galluogi'r gosodiad yma'n ei gwneud yn amhosib i chwaraewr cyfrifiadur adeiladu llongau STR_CONFIG_SETTING_AI_PROFILE :Proffil gosodiadau rhagosodedig: {STRING} STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Dewis pa broffil gosodiadau i'w ddefnyddio ar gyfer AIau a gyflwynir ar hap, neu fel gwerthoedd rhagosodedig pan yn ychwanegu AI neu Sgript Gêm newydd STR_CONFIG_SETTING_AI_PROFILE_EASY :Hawdd STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Cymhedrol STR_CONFIG_SETTING_AI_PROFILE_HARD :Anodd STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Caniatáu AIau mewn gemau amlchwaraewr: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Caniatáu i chwaraewyr AI gymeryd rhan mewn gemau amlchwaraewr STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :Nifer y gweithredoedd cyn diarddel sgriptiau: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Uchafswm y nifer o gamau cyfrifo y gall sgript ei gymeryd mewn un tro STR_CONFIG_SETTING_SERVINT_ISPERCENT :Dangos y cyfnod rhwng gwasanaethau mewn canrannau: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Dewis os y bydd gwasanaethu cerbydau'n digwydd yn ôl yr amser ers y gwasanaeth olaf, neu wrth i'w dibynadwyedd ddisgyn islaw ganran penodol o'r dibynadwyedd uchafsymol STR_CONFIG_SETTING_SERVINT_TRAINS :Ystod gwasanaethu rhagosodedig ar gyfer trenau: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Gosod yr ystod gwasanaethu rhagosodedig ar gyfer cerbydau rheilffordd newydd, os na ddynodir ystod gwasanaethu penodol ar gyfer y cerbyd STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}diwrnod/% STR_CONFIG_SETTING_SERVINT_DISABLED :Analluogwyd STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Ystod gwasanethu rhagosodedig ar gyfer cerbydau ffordd: {STRING} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Gosod yr ystod gwasanaethu rhagosodedig ar gyfer cerbydau ffordd newydd, os na ddynodir ystod gwasanaethu penodol ar gyfer y cerbyd STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Ystod gwasanaethu rhagosodedig ar gyfer awyrennau: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Gosod yr ystod gwasanaethu rhagosodedig ar gyfer awyrennau newydd, os na ddynodir ystod gwasanaethu penodol ar gyfer y cerbyd STR_CONFIG_SETTING_SERVINT_SHIPS :Ystod gwasanaethu rhagosodedig ar gyfer llongau: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Gosod yr ystod gwasanaethu rhagosodedig ar gyfer llongau newydd, os na ddynodir ystod gwasanaethu penodol ar gyfer y cerbyd STR_CONFIG_SETTING_NOSERVICE :Analluogi gwasanaethau pan fydd torri i lawr wedi ei osod i Ddim: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Pan y galluogir, ni wasanaethir cerbydau os na allent dorri i lawr STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Galluogi terfynau cyflymder wagenni: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Pan y galluogir, fe ddefnyddir terfynnau cyflymder pob cerbyd mewn trên pan yn cyfrifo ei gyflymder uchafsymol STR_CONFIG_SETTING_DISABLE_ELRAILS :Analluogi cledrau trydan: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Mae galluogi'r gosodiad yma yn gwaredu a'r angen i drydaneiddio traciau cyn y gall injan drydan redeg arnynt STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Y cerbyd cyntaf yn cyrraedd gorsaf y chwaraewr: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Dangos papur newydd pan fo'r cerbyd cyntaf yn cyrraedd gorsaf newydd y chwaraewr STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Y cerbyd cyntaf yn cyrraedd gorsaf cystadleuydd: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Dangos papur newydd pan fo'r cerbyd cyntaf yn cyrraedd gorsaf newydd cystadleuwr STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Damweiniau / trychinebau: {STRING} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Dangos papur newydd pan fo damweiniau neu drychinebau'n digwydd STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Gwybodaeth Cwmnïau: {STRING} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Dangos papur newydd pan fo cwmni newydd yn dechrau, neu pan fo cwmnïau ar fin taro'r wal STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Cychwyn diwydiannau: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Dangos papur newydd pan fo diwydiannau newydd yn agor STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Cau diwydiannau: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Dangos papur newydd pan fo diwydiannau'n cau i lawr STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Newidiadau yn yr economi: {STRING} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Dangos papur newydd am newidiadau fyd-eang i'r economi STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Newid yng nghynyrch diwydiannau a wasanaethir gan y cwmni: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Dangos papur newydd pan fo lefel gweithgynhyrchu diwydiannau'n newid, a rheiny yn cael eu gwasanaethu gan y cwmni STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Newid yng nghynyrch diwydiannau a wasanaethir gan gystadleuw(y)r: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Dangos papur newydd pan fo lefel gweithgynhyrchu diwydiannau'n newid, a rheiny yn cael eu gwasanaethu gan gystadleuwyr STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Newidiadau cynyrch diwydiannau eraill: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Dangos papur newydd pan fo lefel gweithgynhyrchu diwydiannau'n newid, a rheiny heb eu gwasanaethu gan y cwmni na'i gystadleuwyr STR_CONFIG_SETTING_NEWS_ADVICE :Cyngor / gwybodaeth am gerbydau cwmni: {STRING} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Dangos negeseuon am gerbydau sydd angen sylw STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :Cerbydau Newydd: {STRING} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Dangos papur newydd pan fo math newydd o gerbyd ar gael STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Newidiadau i'r llwythi a dderbynir: {STRING} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Dangos negeseuon am orsafoedd yn newid y nwyddau y maent yn derbyn STR_CONFIG_SETTING_NEWS_SUBSIDIES :Cymorthdaliadau: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Dangos papur newydd am ddigwyddiadau ynghylch cymorthdaliadau STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :Gwybodaeth Gyffredinol: {STRING} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Dangos papur newydd ar gyfer digwyddiadau cyffredinol, megis prynnu hawliau cyfyngol neu ariannu ailadeiladu ffyrdd STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :I Ffwrdd STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Crynodeb STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Llawn STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Bydd newyddion lliw yn ymddangos yn: {STRING} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Y blwyddyn y caiff cyhoeddiadau newyddion eu hargraffu mewn lliw. Cyn y dyddiad yma rhai du a gwyn fyddent STR_CONFIG_SETTING_STARTING_YEAR :Blwyddyn dechreuol: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Galluogi economi llyfn (mwy o newidiadau llai): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Pan fe wedi'i alluogi, mae gweithgynhyrchiant diwydiant yn newid yn fwy aml, ac mewn cammau llai. Ni fydd y gosodiad yma yn cael effaith os y defnyddir diwydiannau NewGRF, fel rheol STR_CONFIG_SETTING_ALLOW_SHARES :Caniatáu prynu cyfranddaliadau mewn cwmnïau eraill: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Pan fo wedi'i alluogi, fe ganiateir prynnu a gwerthu cyfrandalaidau cwmni. Rhaid i gwmni gyrraedd oed penodol cyn y daw eu cyfrandaliadau ar gael STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Canran elw y cymal i'w dalu mewn systemau trosglwyddo: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Y canran o elw a ddyfarnir i'r cymalau rhyngol mewn systemau trosglwyddo, gan rhoi fwy o reolaeth dros yr elw STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Wrth lusgo, gosod signalau bob: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Gosod y pellter y codir signalau ar drac hyd at y rhwystr nesaf (signal, cyffordd), os y llusgir signalau STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} teil STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Pan yn llusgo, cadw pellter cyson rhwng y signalau: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Gosod ymddygiad gosod signalau pan yn Ctrl+llusgo signalau. Os analluogir, caiff signalau eu gosod o amgylch twneli a phontydd i osgoi ystodau hir heb signalau. Os y galluogir, caiff signalau eu gosod bob n teil, gan rwyddhau alinio signalau ar traciau paralel STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Adeiladu semafforau cyn: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Gosod y flwyddyn pan y defnyddir signalau trydan ar draciau. Cyn y flwyddyn hon, fe ddefnyddir signalau semaffor (sydd â gweithred unfath, ond edrychiad gwahanol) STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Galluogi'r GUI signalau: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Dangos ffenestr ar gyfer dewis y math o signalau i ddewis, yn hytrach na chylchu drwy mathau signal heb ffenest wrth Ctrl+clicio ar signalau eisoes wedi'u hadeiladu STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Y math o signal i'w adeiladu fel rhagosodiad: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Signal rhagosodedig i'w ddefnyddio STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Signalau Bloc STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Signalau Llwybr STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :Signalau Llwybr Un-ffordd STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Cylchu trwy mathau signal: {STRING} STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :Dewis pa fathau o signalau i gylchu drwyddynt, pan yn Ctrl+clicio i adeiladu signalau gyda'r offer signal STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Signalau bloc yn unig STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Signalau llwybr yn unig STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :Pob math STR_CONFIG_SETTING_TOWN_LAYOUT :Cynllun ffyrdd ar gyfer trefi newydd: {STRING} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Cynllun rhwydwaith ffyrdd trefi STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Gwreiddiol STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Ffyrdd gwell STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :grid 2x2 STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :grid 3x3 STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Ar hap STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Caiff trefi adeiladu ffyrdd: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Caniatáu i drefi adeiladu ffyrdd er mwyn tyfu. Bydd analluogi yn rhwystro awdurdodau trefi rhag adeiladu ffyrdd eu hunain STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Caniatáu i drefi adeiladau croesfannau rheilffordd: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Galluogwch y gosodiad yma i ganiatáu i drefi adeiladu croesfannau rheilffordd STR_CONFIG_SETTING_NOISE_LEVEL :Caniatáu i drefi reoli lefel swn meysydd awyrenau: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :Os analluogir y gosodiad yma, gellir cael dau faes awyr ymhob tref. Os y galluogir, fe gyfyngir y nifer o feysydd awyr gan y lefel sŵn mae'r dref am dderbyn, sydd yn dibynnu ar y boblogaeth a maint a phellter y maes awyr STR_CONFIG_SETTING_TOWN_FOUNDING :Sefydlu trefi mewn gêm: {STRING} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Mae galluogi'r gosodiad yma'n caniatáu i chwaraewyr sefydlu trefi newydd yn y gêm STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Gwahardd STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Caniatáu STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Caniatáu, cynllun tref addasiedig STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Gosod coed mewn gêm: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Rheoli ymddangosiad coed ar hap yn ystod y gêm. Gall hyn effeithio ar ddiwydiannau sy'n ddibynnol ar dyfiant coed, megis melinau coed STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :Dim {RED}(yn torri'r felin goed) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :Mewn glawgoedwigoedd yn unig STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :Pob man STR_CONFIG_SETTING_TOOLBAR_POS :Safle'r prif far offer: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Lleoliad llorweddol y brif bar offer ar frig y sgrin STR_CONFIG_SETTING_STATUSBAR_POS :Lleoliad y bar statws: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Lleoliad llorweddol y bar statws ar waelod y sgrin STR_CONFIG_SETTING_SNAP_RADIUS :Pellter snapio ffenestr: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Y pellter rhwng ffenestri cyn y bydd y ffenest sy'n cael ei symyd ei alinio'n ddiofyn at ffenestri gerllaw STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} picsel STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Analluogwyd STR_CONFIG_SETTING_SOFT_LIMIT :Uchafswm ffenestri (nad yw'n ludiog): {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Y nifer o ffenestri agored (nad ydynt yn ludiog) cyn y caiff hen ffenestri eu cau'n ddiofyn i wneud lle ar gyfer ffenestri newydd STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :analluogwyd STR_CONFIG_SETTING_ZOOM_MIN :Lefel mwyháu uchafsymol: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Y lefel agosáu uchaf ar gyfer ffenestri olygfa. Sylwer y bydd galluogi lefelau uwch yn codi 'r gofynion côf STR_CONFIG_SETTING_ZOOM_MAX :Lefel mwyháu isafsymol: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :Y lefel pellhau uchaf ar gyfer ffenestri golygfa. Gall lefelau pellhau uwch beri oediadau pan y defnyddient STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Arferol STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x STR_CONFIG_SETTING_TOWN_GROWTH :Cyflymder twf tref: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Cyflymder tyfiant trefi STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Dim STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Araf STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Arferol STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Cyflym STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Cyflym iawn STR_CONFIG_SETTING_LARGER_TOWNS :Cyfran o drefi a dyf yn ddinasoedd: {STRING} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Nifer o drefi a dyf yn ddinasoedd, ac felly yn dechrau fel trefi mwy sy'n tyfu'n gyflymach STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 mewn {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :Dim STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Lluosydd cychwynol maint dinas: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Maint cymhedrol dinasoedd o gymharu â threfi arferol ar ddechrau'r gêm STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Diweddaru'r graff dosraniad bob {STRING}{NBSP}diwrnod STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Amser rhwng pob ailgifrifiad o'r graff cyswllt. Bydd pob ailgyfrifiad yn cyfrifio'r cynllun ar gyfer un cydran o'r graff. O ganlyn ni fydd dwis gwerth o X yn golygu y bydd y graff cyfan yn cael ei ddiweddaru bob X diwrnod, ond y bydd rhai cydrannau. Bydd ystod byr yn defnyddio mwy o amser y prosesydd yn ailgyfrio graffiau. Bydd ystor hir yn cynyddu'r amser cyn y daw'r dosraniad i ryn ar lwybrau newydd. STR_CONFIG_SETTING_LINKGRAPH_TIME :Cymryd {STRING}{NBSP}diwrnod ar gyfer ar gyfer ailgyfrifo graff dosraniad STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Yr amser ar gyfer ailgyfrifo pob cydran o raff cyswllt. Pan y dechreuir ailgyfrifo, fe grëir llinyn gwaith a gaiff redeg am nifer penodol o ddiwrnodau. Bydd gosodiad byr yn ei gwneud yn fwy tebygol na fydd y llinyn wedi gorffen mewn pryd. Yna bydd y gêm yn oedi new y bydd yn barod. Bydd gosodiad hir yn cynyddu'r amser y cymerir i'r dosranaid gael ei ddiweddaru pan fo llwybrau'n newid. STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :â llaw STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :anghymesur STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :cymesur STR_CONFIG_SETTING_DISTRIBUTION_PAX :Dull dosrannu ar gyfer teithwyr: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :Mae "cymesur" yn golygu y bydd tua'r un faint o deithwyr yn mynd o orsaf A i orsaf B ac yr aiff o B i A. Mae "anghymesur" yn golygu y gall niferoedd mympwyol fynd yn y naill cyfeiriad neu'r llall. Mae "â llaw" yn golygu ni fydd dosrannu diofyn yn digwydd ar gyfer teithwyr. STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Dull dosrannu ar gyfer post: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :Mae "cymesur" yn golygu y bydd tua'r un faint o bost yn cael ei yrru o orsaf A i orsaf B ac y gyrrir o B i A. Mae "anghymesur" yn golygu y gall llwythi mympwyol eu gyrru yn y naill cyfeiriad neu'r llall. Mae "â llaw" yn golygu ni fydd dosrannu diofyn yn digwydd ar gyfer post. STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Dull dosrannu ar gyfer llwythi ARFOG: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :Mae llwythi ARFOG yn cynnwys trysorau mewn ardaloedd tymherus, diemwntau yn y trofannau, ac aur yn yr is-arctig. Gall NewGRFau newid hyn, Mae "cymesur" yn golygu y bydd tua'r un faint o lwythi'n cael eu gyrru o orsaf A i orsaf B ac y gyrrir o B i A. Mae "anghymesur" yn golygu y gall llwythi mympwyol eu gyrru yn y naill cyfeiriad neu'r llall. Mae "â llaw" yn golygu ni fydd dosrannu diofyn yn digwydd ar gyfer y llwythi yma. Fe argymhellir eich bod yn dewis anghymesur neu â llaw pan yn chwarae mewn ardal is-arctig, gan na fydd banciau'n gyrru aur yn ôl i gloddfeydd aur. Ar gyfer ardaloedd tymherus neu trofannol gallwch hefyd ddewis cymesur gan y bydd banciau'n gyrru trysorau'n ôl i rai banciau tardd. STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Dull dosrannu ar gyfer llwythi eraill: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :Mae "anghymesur" yn golygu y gall llwythi mympwyol eu gyrru yn y naill cyfeiriad neu'r llall. Mae "â llaw" yn golygu ni fydd dosrannu diofyn yn digwydd ar gyfer y llwythi hyn. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Manylder dosrannu: {STRING} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Mae'r gosodiad yma'n pennu faint o amser prosesydd y bydd cyfrifo'r graff cyswllt yn ei gymeryd. Os yw'n cymryd gormod o amser efallai bydd peth oedi ar y gêm. Os ydych yn gosod gwerth isel, fodd bynnag, ni fyddy dosraniad yn fanwl gywir, a gallwch nodi nad yw llwythi'n cael ei yrru i'r mannau y bydddech y disgwyl. STR_CONFIG_SETTING_DEMAND_DISTANCE :Effaith pellter ar y galw am lwythi: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Os ydych yn gosod at werth yn uwch na 0, bydd y pellter rhwng gorsaf tardd rhyw gargo a cyrchfan posibl B yn dylanwadu ar faint o llwythi a yrrir o A i B. Y pellaf y mae B o A, y lleiaf o gargo a yrrir. Gyda gosodiad uwch, bydd llai o gargo yn cael ei yrru i orsafoedd pell a mwy'n cael ei yrru at orsafoedd agos. STR_CONFIG_SETTING_DEMAND_SIZE :Cyfanswm y llwythi'n dychwelyd ar gyfer modd cymesur: {STRING} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Bydd gosod hwn at llai na 100% yn gwneud y dosraniad cymesur yn fwy fel yr un anghymesur. Caiff llai o llwythi eu gyrru'n ôl yn orfodol os y bydd peth penodol yn cael ei yrru i orsaf. Gyda gosodiad o 0% bydd y dosraniad cymesur yn ymddwyn fel yr un anghymesur. STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Llenwi llwybrau byr cyn troi at rhai uwch eu cynhwysedd: {STRING} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Yn aml mae mwy nag un llwybr rhwng dwy orsaf. Bydd Cargodist yn llenwi'r llwybr byrraf yn gyntaf, yna'n symyd at yr ail fyrraf nes ei fod yn llawn, ayyb. Fe ystyrir llwybr yn llawn yn ôl amcangyfrif o gynhwysedd y llwybr a'r defnydd a gynllunwyd. Gyda fod pob llwybr wedi ei lenwi, os oes galw o hyd, bydd yn gorlwytho pob llwybr, gan ffafrio'r rhai gyda chynhwysedd uchel. Ni fydd yr algorithm yn amcangyfrif y cynhwysedd yn fanwl gywir. Mae'r gosodiad yma'n eich galluogi i nodi pa mor llawn y dylai llwybr byrrach fod (fel canran) cyn dewis y llwybr nesaf. Gosodwch at llai na 100% i osgoi tagfeydd mewn gorsafoedd oherwydd goramcangyfrif cynhwysedd. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Unedau cyflymder: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Pan y dangosir cyflymder yn y rhyngwyneb defnyddiwr, ei ddangos yn yr unedau a ddewiswyd STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metrig (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Unedau pŵer cerbyd: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Pan y dangosir pŵer yn y rhyngwyneb defnyddiwr, ei ddangos yn yr unedau a ddewiswyd STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperial (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metrig (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Unedau pwysau: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Pan y dangosir pwysau yn y rhyngwyneb defnyddiwr, ei ddangos yn yr unedau a ddewiswyd STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperial (t/tunnell byr) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metrig (t/tunell) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Unedau cyfaint: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Pan y dangosir cyfaint yn y rhyngwyneb defnyddiwr, ei ddangos yn yr unedau a ddewiswyd STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperial (gal) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metrig (l) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Unedau grym tynnu: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Pan y dangosir grym tynnu yn y rhyngwyneb defnyddiwr, ei ddangos yn yr unedau a ddewiswyd STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperial (lbf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metrig (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Unedau uchder: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Pan y dangosir uchder yn y rhyngwyneb defnyddiwr, ei ddangos yn yr unedau a ddewiswyd STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperial (ft) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metrig (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Unedau Lleol STR_CONFIG_SETTING_GRAPHICS :{ORANGE}Graffeg STR_CONFIG_SETTING_SOUND :{ORANGE}Sain STR_CONFIG_SETTING_INTERFACE :{ORANGE}Rhyngwyneb STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE}Cyffredinol STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Ffenestri Golygfa STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Adeiladu STR_CONFIG_SETTING_ADVISORS :{ORANGE}Newyddion a Chyngor STR_CONFIG_SETTING_COMPANY :{ORANGE}Cwmni STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Cyfrifo STR_CONFIG_SETTING_VEHICLES :{ORANGE}Cerbydau STR_CONFIG_SETTING_VEHICLES_PHYSICS :{ORANGE}Ffiseg STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Llwybro STR_CONFIG_SETTING_LIMITATIONS :{ORANGE}Cyfyngiadau STR_CONFIG_SETTING_ACCIDENTS :{ORANGE}Trychinebau a Damweiniau STR_CONFIG_SETTING_GENWORLD :{ORANGE}Cread byd STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}Amgylchedd STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :{ORANGE}Awdurdodau STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}Trefi STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Diwydiannau STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Dosraniad cargo STR_CONFIG_SETTING_AI :{ORANGE}Cystadleuwyr STR_CONFIG_SETTING_AI_NPC :{ORANGE}Chwaraewyr Cyfrifiadurol STR_CONFIG_SETTING_PATHFINDER_OPF :Gwreiddiol STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Argymellir) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Llwybrwr ar gyfer trenau: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Llwybrwr i'w ddefnyddio ar gyfer trenau STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Llwybrwr ar gyfer cerbydau ffordd: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Llwybrwr i'w ddefnyddio ar gyfer cerbydau ffordd STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Llwybrwr ar gyfer llongau: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Llwybrwr i'w ddefnyddio ar gyfer llongau STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Troi'n ôl yn awtomatig wrth signalau: {STRING} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Caniatáu i drenau gwrthdroi wrth signal, os ydynt wedi aros yno am beth amser STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Newid gwerth gosodiad # Config errors STR_CONFIG_ERROR :{WHITE}Gwall gyda'r ffeil ffurfweddu... STR_CONFIG_ERROR_ARRAY :{WHITE}... gwall yn arae '{STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... gwerth annilys '{STRING}' ar gyfer '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... cymeriadau gormodol ar ddiwedd '{STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... yn anwybyddu NewGRF '{STRING}': GRF ID unfath â '{STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... yn annwybyddu NewGRF annilys '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :ni ganfuwyd STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :anniogel ar gyfer defnydd statig STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :system NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :anghydnaws gyda'r fersiwn yma o OpenTTD STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :anhysbys STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... nid yw'r lefel cywasgu '{STRING}' yn ddilys STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... nid yw'r fformat ffeil cadw gêm '{STRING}' ar gael. Yn dychwelyd at '{STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... yn anwybyddu set Graffeg Sylfaenol '{STRING}': ni ganfuwyd STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... yn anwybyddu setiau Sain Sylfaenol '{STRING}': ni ganfuwyd STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... yn anwybyddu set Sain Sylfaenol '{STRING}': ni ganfuwyd STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Allan o gof STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Methwyd dyroddi {BYTES} o storfa corluniau. Lleihawyd y storfa corluniau at {BYTES}. Bydd hyn yn lleihau perfformiad OpenTTD. I leihau gofynion cof gallwch roi cynnig ar analluogi graffigiau 32 did a/neu lefelau mwyháu # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}Gêm Newydd STR_INTRO_LOAD_GAME :{BLACK}Llwytho Gêm STR_INTRO_PLAY_SCENARIO :{BLACK}Chwarae Senario STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Chwarae Map Uchder STR_INTRO_SCENARIO_EDITOR :{BLACK}Golygydd Senario STR_INTRO_MULTIPLAYER :{BLACK}Amlchwaraewr STR_INTRO_GAME_OPTIONS :{BLACK}Dewisiadau Gêm STR_INTRO_HIGHSCORE :{BLACK}Tabl Sgôr Uchaf STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Gosodiadau STR_INTRO_NEWGRF_SETTINGS :{BLACK}Gosodiadau NewGRF STR_INTRO_ONLINE_CONTENT :{BLACK}Gwirio Cynnwys Ar-lein STR_INTRO_SCRIPT_SETTINGS :{BLACK}Gosodiadau AI / Sgript Gêm STR_INTRO_QUIT :{BLACK}Gadael STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Dechrau gêm newydd. Mae Ctrl+Clic yn hepgor dewisiadau map STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Llwytho Gêm sydd wedi'i Gadw STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Dechrau gêm newydd, gan ddefnyddio'r map uchder fel tirwedd STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Dechrau gêm newydd, gan ddefnyddio senario wedi'i haddasu STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Creu byd gêm/senario addasiedig STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Cychwyn gêm amlchwaraewr STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Dewis tirwedd tymherus STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Dewis tirwedd is-arctig STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Dewis tirwedd trofannol STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Dewis tirwedd teganau STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Dangos dewisiadau'r gêm STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Dangos y tabl sgôr uchaf STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Gosodiadau arddangos STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Dangos gosodiadau NewGRF STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Gwirio am gynnwys newydd neu wedi'i ddiweddaru i'w lwytho i lawr STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Dangos gosodiadau AI a sgript Gêm STR_INTRO_TOOLTIP_QUIT :{BLACK}Gadael 'OpenTTD' STR_INTRO_TRANSLATION :{BLACK}Mae'r cyfieithiad yma'n brin o {NUM} llinyn. Helpwch wella OpenTTD drwy ymaelodi fel cyfieithydd. Gweler readme.txt am fanylion. # Quit window STR_QUIT_CAPTION :{WHITE}Gadael STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Ydych chi eisiau gadael y gêm a dychwelyd i {STRING}? STR_QUIT_YES :{BLACK}Iawn STR_QUIT_NO :{BLACK}Na # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Rhoi'r gorau i Gêm STR_ABANDON_GAME_QUERY :{YELLOW}Ydych chi'n siwr eich bod chi eisiau rhoi'r gorau i'r gêm? STR_ABANDON_SCENARIO_QUERY :{YELLOW}Ydych chi'n siwr eich bod chi eisiau gadael y senario hwn? # Cheat window STR_CHEATS :{WHITE}Twyllo STR_CHEATS_TOOLTIP :{BLACK}Mae'r blychau marcio'n dangos os ydych chi wedi twyllo neu beidio, gan nodi sut STR_CHEATS_WARNING :{BLACK}Rhybudd! Rydych ar fin bradychu eich cydgystadleuwyr. Cofiwch y bydd y fath gywilydd yn cael ei gofio o'r awr hon hyd byth STR_CHEAT_MONEY :{LTBLUE}Cynyddu arian {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Chwarae fel cwmni: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Tarw Dur Hud (chwalu diwydiannau, gwrthrychau nad oes modd eu chwalu): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Caiff twneli groesi eu gilydd: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Ni fydd awyrennau jet yn crashio (yn aml) ar feysydd awyr bychain: {ORANGE}{STRING} STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Golygu uchder uchafsymol y map: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Golygu uchder uchafsymol mynyddoedd ar y map STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Tirwedd Tymherus STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Tirwedd Is-arctig STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Tirwedd trofannol STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Tirwedd Teganau STR_CHEAT_CHANGE_DATE :{LTBLUE}Newid dyddiad: {ORANGE}{DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Newid y flwyddyn bresennol STR_CHEAT_SETUP_PROD :{LTBLUE}Galluogi newid graddfeydd cynhyrchu: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}Cynllun Lliw Newydd STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Dangos cynllun lliw cyffredinol STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Dangos cynllun lliw trenau STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Dangos cynllun lliw cerbydau ffordd STR_LIVERY_SHIP_TOOLTIP :{BLACK}Dangos cynllun lliw llongau STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Dangos cynllun lliw awyrennau STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Dewiswch brif lliw y cynllun sydd wedi'i ddewis. Bydd Ctrl+Clic yn gosod y lliw yma ar gyfer pob cynllun STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Dewiswch ail liw y cynllun sydd wedi'i ddewis. Bydd Ctrl+Clic yn gosod y lliw yma ar gyfer pob cynllun STR_LIVERY_PANEL_TOOLTIP :{BLACK}Dewiswch gynllun lliw i'w newid, neu nifer o gynlluniau lliw trwy glicio ar CTRL+clic. Cliciwch ar y bocs i doglu defnydd y cynllun STR_LIVERY_DEFAULT :Lifrau cyffredin STR_LIVERY_STEAM :Injan Stêm STR_LIVERY_DIESEL :Injan Ddiesel STR_LIVERY_ELECTRIC :Injan Drydan STR_LIVERY_MONORAIL :Injan Monoreilffordd STR_LIVERY_MAGLEV :Injan Maglef STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Cerbyd Teithwyr (Stêm) STR_LIVERY_PASSENGER_WAGON_DIESEL :Cerbyd Teithwyr (Diesel) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Cerbyd Teithwyr (Trydan) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Cerbyd Teithwyr (Monoreil) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Cerbyd Teithwyr (Maglef) STR_LIVERY_FREIGHT_WAGON :Wagen Lwyth STR_LIVERY_BUS :Bws STR_LIVERY_TRUCK :Lori STR_LIVERY_PASSENGER_SHIP :Fferi Teithwyr STR_LIVERY_FREIGHT_SHIP :Llong Lwyth STR_LIVERY_HELICOPTER :Hofrennydd STR_LIVERY_SMALL_PLANE :Awyren Fach STR_LIVERY_LARGE_PLANE :Awyren Fawr STR_LIVERY_PASSENGER_TRAM :Tram Teithwyr STR_LIVERY_FREIGHT_TRAM :Tram Nwyddau # Face selection window STR_FACE_CAPTION :{WHITE}Dewiswch Wyneb STR_FACE_CANCEL_TOOLTIP :{BLACK}Diddymu dewis wyneb STR_FACE_OK_TOOLTIP :{BLACK}Derbyn y dewis newydd o wyneb STR_FACE_RANDOM :{BLACK}Ar hap STR_FACE_MALE_BUTTON :{BLACK}Gwrywaidd STR_FACE_MALE_TOOLTIP :{BLACK}Dewis gwyneb gwrywaidd STR_FACE_FEMALE_BUTTON :{BLACK}Benywaidd STR_FACE_FEMALE_TOOLTIP :{BLACK}Dewis gwyneb benywaidd STR_FACE_NEW_FACE_BUTTON :{BLACK}Gwyneb Newydd STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Cynhyrchu wyneb newydd ar hap STR_FACE_ADVANCED :{BLACK}Uwch STR_FACE_ADVANCED_TOOLTIP :{BLACK}Dewis wyneb manwl STR_FACE_SIMPLE :{BLACK}Syml STR_FACE_SIMPLE_TOOLTIP :{BLACK}Dewis wyneb syml STR_FACE_LOAD :{BLACK}Llwytho STR_FACE_LOAD_TOOLTIP :{BLACK}Llwytho hoff wyneb STR_FACE_LOAD_DONE :{WHITE}Llwythwyd eich hoff wyneb o'r ffeil ffurfweddu OpenTTD STR_FACE_FACECODE :{BLACK}Wyneb chwaraewr rhif: STR_FACE_FACECODE_TOOLTIP :{BLACK}Gweld ac/neu osod rhif wyneb llywydd y cwmni STR_FACE_FACECODE_CAPTION :{WHITE}Gweld ac/neu osod rhif gwyneb llywydd STR_FACE_FACECODE_SET :{WHITE}Cafodd rhif wyneb newydd ei osod STR_FACE_FACECODE_ERR :{WHITE}Methu gosod rhif wyneb llywydd - rhaid iddo fod yn rhif rhwng 0 a 4,294,967,295! STR_FACE_SAVE :{BLACK}Cadw STR_FACE_SAVE_TOOLTIP :{BLACK}Cadw hoff wyneb STR_FACE_SAVE_DONE :{WHITE}Bydd yr wyneb hwn yn cael ei gadw fel eich ffefryn yn y ffeil ffurfweddu OpenTTD STR_FACE_EUROPEAN :{BLACK}Ewropeiaidd STR_FACE_SELECT_EUROPEAN :{BLACK}Dewis gwyneb Ewropeaidd STR_FACE_AFRICAN :{BLACK}Affricanaidd STR_FACE_SELECT_AFRICAN :{BLACK}Dewis gwyneb Affricanaidd STR_FACE_YES :Ie STR_FACE_NO :Na STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Galluogi mwstásh neu glustdlws STR_FACE_HAIR :Gwallt: STR_FACE_HAIR_TOOLTIP :{BLACK}Newid gwallt STR_FACE_EYEBROWS :Aeliau: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Newid aeliau STR_FACE_EYECOLOUR :Lliw llygaid STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Newid lliw llygaid STR_FACE_GLASSES :Sbectol: STR_FACE_GLASSES_TOOLTIP :{BLACK}Galluogi sbectol STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Newid sbectol STR_FACE_NOSE :Trwyn: STR_FACE_NOSE_TOOLTIP :{BLACK}Newid trwyn STR_FACE_LIPS :Gwefusau: STR_FACE_MOUSTACHE :Mwstásh: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Newid gwefusau neu fwstásh STR_FACE_CHIN :Gen: STR_FACE_CHIN_TOOLTIP :{BLACK}Newid gen STR_FACE_JACKET :Siaced: STR_FACE_JACKET_TOOLTIP :{BLACK}Newid siaced STR_FACE_COLLAR :Coler: STR_FACE_COLLAR_TOOLTIP :{BLACK}Newid coler STR_FACE_TIE :Tei: STR_FACE_EARRING :Clustlws: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Newid tei neu glustlws # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Amlchwaraewr STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Hysbys STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Dewis rhwyd gêm a hysbysebir (rhyngrwyd) neu un anhysbys (rhwydwaith leol) STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Na STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Ia STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Enw chwaraewr: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Byddwch chi'n ymddangos i'r chwaraewyr eraill dan yr enw hwn STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Enw STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Enwi'r gêm STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Gwesteion STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Gwesteion ar-lein / uchafswm gwesteion{}Cwmnïau ar-lein / uchafswm cwmnïau STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Maint map STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Maint map y gêm{}Cliciwch i drefnu'n ôl ardal STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Dyddiadau STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Dyddiad cyfredol STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Blynyddoedd STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Nifer y blynyddoedd{}y bu'r gêm yn rhedeg STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Iaith, fersiwn gweinydd, ayb. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Cliciwch gêm o'r rhestr i'w ddewis STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Y gweinydd yr ymunoch chi ag o ddiwethaf: STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Cliciwch i ddewis y gweinydd y chwaraeoch chi ddiwethaf STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}GWYBODAETH AM Y GÊM STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Gwesteion: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Iaith: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Tirwedd: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Maint map: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Fersiwn gweinydd: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Cyfeiriad gweinydd: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Dyddiad cychwyn: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Dyddiad presennol: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Wedi'i Ddiogelu gan Gyfrinair! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}GWEINYDD ALL-LEIN STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}GWEINYDD LLAWN STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}FERSIWN ANGHYDNAWS STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF ANGHYDNAWS STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Ymuno â gêm STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Adnewyddu'r gweinydd STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Adnewyddu'r wybodaeth am y gweinydd STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Canfod gweinydd STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Chwilio'r rhwydwaith am weinydd STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Ychwanegu gweinydd STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Ychwanegu gweinydd i'r rhestr a gaiff ei wirio bob tro am gemau sy'n rhedeg STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Dechrau gweinydd STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Dechrau eich gweinydd eich hun STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Rhowch eich enw STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Rhowch gyfeiriad y gwesteiwr # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}Dechrau gêm newydd amlchwaraewr STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Enw gêm: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Bydd y gêm yn weladwy i chwaraewyr amlchwaraewr eraill yn y ddewislen dewis gêm STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Gosod cyfrinair STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Diogelwch eich gêm â chyfrinair os nad ydych am i fynediad ato fod yn gyhoeddus STR_NETWORK_START_SERVER_UNADVERTISED :Na STR_NETWORK_START_SERVER_ADVERTISED :Ia STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} gwestai STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Uchafswm nifer gwesteion: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Dewiswch uchafswm y gwesteion. Does dim rhaid llanw pob slot STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} cwmni STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Uchafswm nifer cwmnïau: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}rhoi cyfyngiad penodol ar sawl cwmni mae'r gweinydd yn ei ganiatáu STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} gwyliwr STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Uchafswm nifer gwylwyr: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}rhoi cyfyngiad penodol ar sawl gwyliwr mae'r gweinydd yn ei ganiatáu STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Iaith i'w siarad: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Rhoi gwybod i'r chwaraewyr pa iaith y dylid ei siarad ar y gweinydd STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Rhowch enw ar gyfer y gêm rhwydwaith # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :Unrhyw STR_NETWORK_LANG_ENGLISH :Saesneg STR_NETWORK_LANG_GERMAN :Almaeneg STR_NETWORK_LANG_FRENCH :Ffrangeg STR_NETWORK_LANG_BRAZILIAN :Brasilaidd STR_NETWORK_LANG_BULGARIAN :Bwlgaraidd STR_NETWORK_LANG_CHINESE :Tseineeg STR_NETWORK_LANG_CZECH :Tsiecaidd STR_NETWORK_LANG_DANISH :Daneg STR_NETWORK_LANG_DUTCH :Iseldireg STR_NETWORK_LANG_ESPERANTO :Esperanto STR_NETWORK_LANG_FINNISH :Ffineg STR_NETWORK_LANG_HUNGARIAN :Hwngareg STR_NETWORK_LANG_ICELANDIC :Islandaidd STR_NETWORK_LANG_ITALIAN :Eidaleg STR_NETWORK_LANG_JAPANESE :Siapaneaidd STR_NETWORK_LANG_KOREAN :Coreeg STR_NETWORK_LANG_LITHUANIAN :Lithiwaneg STR_NETWORK_LANG_NORWEGIAN :Norwyeg STR_NETWORK_LANG_POLISH :Pwyleg STR_NETWORK_LANG_PORTUGUESE :Portiwgaleg STR_NETWORK_LANG_ROMANIAN :Rwmaneg STR_NETWORK_LANG_RUSSIAN :Rwsieg STR_NETWORK_LANG_SLOVAK :Slofaceg STR_NETWORK_LANG_SLOVENIAN :Slofeneg STR_NETWORK_LANG_SPANISH :Sbaeneg STR_NETWORK_LANG_SWEDISH :Swedeg STR_NETWORK_LANG_TURKISH :Twrceg STR_NETWORK_LANG_UKRAINIAN :Wcraneg STR_NETWORK_LANG_AFRIKAANS :Affricâns STR_NETWORK_LANG_CROATIAN :Croatieg STR_NETWORK_LANG_CATALAN :Catalaneg STR_NETWORK_LANG_ESTONIAN :Estoneg STR_NETWORK_LANG_GALICIAN :Galiseg STR_NETWORK_LANG_GREEK :Groeg STR_NETWORK_LANG_LATVIAN :Latfieg ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Cyntedd Gemau Amlchwaraewr STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Paratoi i ymuno: {ORANGE}{STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}Rhestr o'r holl gwmnïau yn y gêm. Gellwch unai ymuno ag un neu ddechrau un newydd os oes slot cwmni'n rhydd STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}GWYBODAETH CWMNI STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Enw cwmni: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Sefydlwyd: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Gwerth cwmni: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Balans presennol: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Incwm y llynedd: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Perfformiad: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Cerbydau: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Gorsafoedd: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Chwaraewyr: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}Cwmni newydd STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Creu cwmni newydd STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Gwylio gêm STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Gwylio'r gêm fel gwyliwr STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Ymuno â chwmni STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Helpu rheoli'r cwmni hwn # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}Wrthi'n Cysylltu... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Wrthi'n cysylltu... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Wrthi'n awdurdodi... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Wrthi'n aros... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Wrthi'n llawrlwytho map... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Wrthi'n prosesu data.. STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Cofrestru... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Estyn gwybodaeth gêm... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Estyn gwybodaeth cwmnïau... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} gwestai o'ch blaen STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} wedi'i lawrlwytho hyd yn hyn STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} wedi eu llwytho i lawr hyd yn hyn STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Datgysylltu STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Mae'r gweinydd wedi'i ddiogelu. Rhowch y cyfrinair. STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Mae'r cwmni wedi'i ddiogelu. rhowch y cyfrinair. # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Rhestr Cleientiaid STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Gwylio STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}Cwmni newydd # Network client list STR_NETWORK_CLIENTLIST_KICK :Cicio STR_NETWORK_CLIENTLIST_BAN :Gwahardd STR_NETWORK_CLIENTLIST_GIVE_MONEY :Rhoi arian STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Siarad â phawb STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Siarad a'r cwmni STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Neges breifat STR_NETWORK_SERVER :Gweinydd STR_NETWORK_CLIENT :Gwestai STR_NETWORK_SPECTATORS :Gwylwyr STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Nodwch faint o arian yr hoffech chi ei roi STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Gwyliwr # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Peidio cadw'r cyfrinair a roddwyd STR_COMPANY_PASSWORD_OK :{BLACK}Rhoi'r cyfrinair newydd i'r cwmni STR_COMPANY_PASSWORD_CAPTION :{WHITE}Cyfrinair cwmni STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Cyfrinair rhagosodedig cwmni STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Defnyddio'r cyfrinair cwmni hwn fel y rhagosodiad ar gyfer cwmnïau # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}Ymuno STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Ymuno a chwarae fel y cwmni hwn STR_COMPANY_VIEW_PASSWORD :{BLACK}Cyfrinair STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Diogelwch eich cwmni gyda cyfrinair er mwyn rhwystro rhai heb awdurdod rhag ymuno STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Gosod cyfrinair cwmni # Network chat STR_NETWORK_CHAT_SEND :{BLACK}Anfon STR_NETWORK_CHAT_COMPANY_CAPTION :[Tîm] : STR_NETWORK_CHAT_CLIENT_CAPTION :[Preifat] {STRING}: STR_NETWORK_CHAT_ALL_CAPTION :[Pawb] : STR_NETWORK_CHAT_COMPANY :[Tîm] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_COMPANY :[Tîm] i {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_CLIENT :[Preifat] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_CLIENT :[Preifat] To {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_ALL :[Pawb] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}teipiwch destun ar gyfer sgwrs rwydwaith # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Ni ddaethpwyd o hyd i ddyfeisiau rhwydwaith, neu ni chafodd y gêm ei chrynhoi gyda ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}Methu darganfod unrhyw gemau rhwydwaith STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Ni atebodd y gweinydd y cais STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Doedd dim modd cysylltu oherwydd nid oedd y NewGRF yn cyfateb STR_NETWORK_ERROR_DESYNC :{WHITE}Methodd y cydamseru rhwng y rhwydwaith a'r gêm STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Collwyd cysylltiad rhwydwaith y gêm STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Doedd dim modd llwytho'r gêm a gadwyd STR_NETWORK_ERROR_SERVER_START :{WHITE}Methwyd a chychwyn y gweinydd STR_NETWORK_ERROR_CLIENT_START :{WHITE}Doedd dim modd cysylltu STR_NETWORK_ERROR_TIMEOUT :{WHITE}Mae cysylltiad #{NUM} wedi amseru allan STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Caewyd y cyswllt oherwydd gwall protocol STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Nid y fersiwn y gwestai yn cyfateb i fersiwn y gweinydd STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Cyfrinair anghywir STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Mae'r gweinydd yn llawn STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Rydych chi wedi'ch gwahardd o'r gweinydd hwn STR_NETWORK_ERROR_KICKED :{WHITE}YCafoch chi eich cicio o'r gêm STR_NETWORK_ERROR_CHEATER :{WHITE}Ni chaniateir twyllo ar y gweinydd hwn STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Roeddech yn gyrru gormod o orchmynion i'r gweinydd STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Fe gymeroch ormod o amser i fewnbynnu'r cyfrinair STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Mae'ch cyfrifiadur rhy araf i gadw amser gyda'r gweinydd STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Fe gymerodd eich cyfrifiadur gormod o amser i lawrlwytho'r map STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Fe gymerodd eich cyfrifiadur gormod o amser i ymuno a'r gweinydd ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :gwall cyffredinol STR_NETWORK_ERROR_CLIENT_DESYNC :gwall dadgydamseru STR_NETWORK_ERROR_CLIENT_SAVEGAME :methwyd llwytho'r map STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :collwyd y cysylltiad STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :gwall protocol STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF ddim yn cyfateb STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :heb ei awdurdodi STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :wedi derbyn paced od neu anghywir STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :fersiwn anghywir STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :enw eisoes mewn defnydd STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :cyfrinair anghywir STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :id-cwmni anghywir yn DoCommand STR_NETWORK_ERROR_CLIENT_KICKED :wedi cael cic gan y gweinydd STR_NETWORK_ERROR_CLIENT_CHEATER :yn ceisio twyllo STR_NETWORK_ERROR_CLIENT_SERVER_FULL :gweinydd llawn STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :yn gyrru gormod o orchmynion STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :ni dderbyniwyd cyfrinair mewn amser STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :goramseriad cyffredinol STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :goramseru wrth lawrlwytho'r map STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :goramseru wrth brosesu'r map ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Colled cysylltiad o bosib STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}Am y {NUM} eiliad diwethaf nid oes data wedi cyrraedd o'r gweinydd # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Gêm wedi'i oedi ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Gêm wedi'i oedi o hyd ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Gêm wedi'i oedi o hyd ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Gêm wedi'i oedi o hyd ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Gêm wedi'i oedi o hyd ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Gêm yn rhedeg eto ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :nifer chwaraewyr STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :cysylltu gwesteion STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :â llaw STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :sgript gêm ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :wrthi'n gadael STR_NETWORK_MESSAGE_CLIENT_JOINED :*** Mae {STRING} wedi ymuno â'r gêm STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** Mae {STRING} wedi ymuno a'r gêm (Gwestai #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** Mae {STRING} wedi ymuno â chwmni #{2:NUM} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** Mae {STRING} wedi ymuno â'r gwylwyr STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** Mae {STRING} wedi dechrau cwmni newydd (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** Mae {STRING} wedi gadael y gêm ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** Mae {STRING} wedi newid ei (h)enw i {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** Rhoddodd {STRING} {2:CURRENCY_LONG} i'ch cwmni STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Fe roddoch chi {2:CURRENCY_LONG} {1:STRING} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Fe gaewyd y sesiwn gan y gweinydd STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Mae'r gweinydd yn ailgychwyn...{}Arhoswch... # Content downloading window STR_CONTENT_TITLE :{WHITE}Llawrlwytho cynnwys STR_CONTENT_TYPE_CAPTION :{BLACK}Math STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Math y cynnwys STR_CONTENT_NAME_CAPTION :{BLACK}Enw STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Enw'r cynnwys STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Cliciwch ar linell i weld ei fanylion{}Ticiwch y blwch i'w ddewis ar gyfer llawrlwytho STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Dewis y cyfan STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Marcio'r cynnwys i gyd er mwyn cael ei lwytho i lawr STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Dewis uwchraddiadau STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Marcio'r holl gynnwys sydd yn uwchraddiad ar gyfer cynnwys sydd eisioes yn bodoli ac i'w lwytho i lawr STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Dad-ddewis y cyfan STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Marcio'r holl gynnwys nad yw i'w lwytho i lawr STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Chwilio gwefannau allanol STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Nid yw cynnwys chwilio ar gael ar wasannaeth cynnwys OpenTTD ar gyfer gwefannau nad ydynt yn gysylltiedig ag OpenTTD STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Rydych yn gadael OpenTTD! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Mae'r termau ac amodau ar gyfer llawrlwytho cynnwys o wefannau allanolyn amrywio.{}Bydd yn rhaid i chi gyfeirio at y gwefannau allanol ar gyfer cyfarwyddiadau a sut i lwytho'r cynnwys yn OpenTTD.{}A ydych am barhau? STR_CONTENT_FILTER_TITLE :{BLACK}Hidlydd enw/tag: STR_CONTENT_OPEN_URL :{BLACK}Gwefan STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Llwytho'r gwefan ar gyfer y cynnwys yma STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Llwytho i lawr STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Dechrau lwytho'r cynnwys a ddewiswyd i lawr STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Cyfanswm maint y llwyth: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}GWYBODAETH AM Y CYNNWYS STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Ni ddewisoch chi hwn i'w lwytho i lawr STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Dewisoch chi hwn i'w lwytho i lawr STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Cafodd y dibyniaeth hwn ei ddewis i'w lwytho i lawr STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Mae hwn eisoes gennych STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}Mae'r cynnwys yma'n anhysbys ac nid oes modd ei lawrlwytho yn OpenTTD STR_CONTENT_DETAIL_UPDATE :{SILVER}Mae hwn yn disodli {STRING} STR_CONTENT_DETAIL_NAME :{SILVER}Enw: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Fersiwn: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Disgrifiad: {WHITE}{STRING} STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}Math: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}Maint Llwyth: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Dewiswyd oherwydd: {WHITE}{STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Dibyniaethau: {WHITE}{STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Tagiau: {WHITE}{STRING} STR_CONTENT_NO_ZLIB :{WHITE}Adeiladwyd OpenTTD heb gefnogaeth "zlib"... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... nid yw llwytho cynnwys i lawr yn bosibl! # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :Graffeg sylfaenol STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :AI STR_CONTENT_TYPE_AI_LIBRARY :llyfrgell AI STR_CONTENT_TYPE_SCENARIO :Senario STR_CONTENT_TYPE_HEIGHTMAP :Map Uchder STR_CONTENT_TYPE_BASE_SOUNDS :Seiniau sylfaenol STR_CONTENT_TYPE_BASE_MUSIC :Cerddoriaeth sylfaenol STR_CONTENT_TYPE_GAME_SCRIPT :Sgript gêm STR_CONTENT_TYPE_GS_LIBRARY :Llyfrgell GS # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Wrthi'n llwytho cynnwys i lawr... STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Wrthi'n gwneud cais am ffeiliau... STR_CONTENT_DOWNLOAD_FILE :{WHITE}Wrthi'n llwytho i lawr {STRING} ({NUM} o {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Llwytho i lawr wedi'i gwblhau STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} o {BYTES} wedi'i llawrlwytho ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Methwyd â chysylltu i'r gweinydd cynnwys... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Methodd y llwytho i lawr... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... collwyd y cysylltiad STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... dim modd ysgrifennu'r ffeil STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Doedd dim modd datgywasgu'r ffeil STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Graffigau coll STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}Mae OpenTTD angen graffigau i weithio ond ni ganfuwyd rhai. Ydych eisiau i OpenTTD lawrlwytho a gosod y graffigau yma? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Ia, llawrlwytho'r graffigau STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Na, gadael OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Dewisiadau Tryloywder STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer arwyddion. Mae Ctrl+Clic yn cloi STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer coed. Ctrl+Clic i gloi STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer tai. Ctrl+Clic i gloi STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer diwydiannau. Ctrl+Clic i gloi STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer eitemau adeiladwy fel gorsafoedd, depos a phwyntiau llwybro. Ctrl+Clic i gloi STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer pontydd. Ctrl+Clic i gloi STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer adeiledau fel goleudai ac antenau. Ctrl+Clic i gloi STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer gwifrau. Ctrl+Clic i gloi STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Toglu tryloywder ar gyfer dangosyddion llwytho. Ctrl+Clic i gloi STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Gosod gwrthrychau'n anweledig yn hytrach nac yn dryloyw # Linkgraph legend window STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Allwedd Llif Cargo STR_LINKGRAPH_LEGEND_ALL :{BLACK}Oll STR_LINKGRAPH_LEGEND_NONE :{BLACK}Dim STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Dewis cwmnïau i'w dangos # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}diddefnydd STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}dirlawn STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}gorlwythiedig # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Amlygu ardal ddylanwad STR_STATION_BUILD_COVERAGE_OFF :{BLACK}I Ffwrdd STR_STATION_BUILD_COVERAGE_ON :{BLACK}Ymlaen STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Peidio amlygu'r ardal fydd yn cael ei ddylanwadu STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Amlygu'r ardal fydd yn cael ei ddylanwadu STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Derbyn: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Deunydd crai yn weddill: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Uno gorsaf STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Adeiladu gorsaf ar wahân STR_JOIN_WAYPOINT_CAPTION :{WHITE}Uno pwynt llwybro STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Adeiladu pwynt llwybro annibynnol # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Adeiladu Rheilffyrdd STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Adeiladu Rheilffyrdd Drydan STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Adeiladu Monoreilffyrdd STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Adeiladu Maglef STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Adeiladu trac rheilffordd. Mae Ctrl yn toglo adeiladu/codi'r rheilffordd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Adeiladu trac yn defnyddio'r modd Awtoreilffordd. Mae Ctrl yn toglo adeiladu/codi'r rheilffordd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Adeiladu trên depo (ar gyfer adeiladu a rhoi gwasanaeth i drenau). Mae Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Newid rheilffordd yn bwynt llwybro. Mae Ctrl yn galluogi uno pwyntiau llwybro, tra fod Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Adeiladu gorsaf reilffordd. Mae Ctrl yn galluogi uno gorsafoedd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Adeiladu signalau rheilffordd. Mae Ctrl yn toglo signalau semafor/golau lliw{}Mae llusgo'n adeiladu signalau ar hyd trac syth. Mae Ctrl yn adeiladu signalau hyd y gyffordd nesaf{}Mae Ctrl+Clic yn toglo agor y ffenestr dewis signalau. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Adeiladu pont reilffordd. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Adeiladu twnnel rheilffordd. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Toglu adeiladu/tynnu ar gyfer traciau, signalau, a pwyntiau llwybro. Wrth ddal Ctrl, caiff cledrau pwyntiau llwybro a gorsafoedd eu tynnu hefyd STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Trosi/Diweddaru math y rheilffordd. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_RAIL_NAME_RAILROAD :Rheilffordd STR_RAIL_NAME_ELRAIL :rheilffordd drydan STR_RAIL_NAME_MONORAIL :monoreilffordd STR_RAIL_NAME_MAGLEV :maglef # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Cyfeiriad Depo Trên STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Dewiswch gyfeiriad depo rheilffordd # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Pwynt Llwybro STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Dewis math o bwynt llwybro # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Dewiswch Orsaf Reilffordd STR_STATION_BUILD_ORIENTATION :{BLACK}Cyfeiriad STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Dewiswch gyfeiriad gorsaf reilffordd STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Nifer y traciau STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Dewiswch nifer y platfformau ar gyfer yr orsaf reilffordd STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Hyd y platfform STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Dewiswch hyd yr orsaf reilffordd STR_STATION_BUILD_DRAG_DROP :{BLACK}Llusgo a Gollwng STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Adeiladu gorsaf gan ddefnyddio llusgo a gollwng STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Dewiswch y dosbarth o orsaf i'w dangos STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Dewiswch y math o orsaf i'w hadeiladu STR_STATION_CLASS_DFLT :Gorsaf Ddiofyn STR_STATION_CLASS_WAYP :Pwyntiau llwybro # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Dewis Signal STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Signal Bloc (semaffor){}Dyma'r math mwyaf sylfaenol o signal, sy'n caniatáu un trên yn unig ymhob bloc ar unrhyw adeg STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Signal Mynediad (semaffor){}Gwyrdd cyhyd y bod un neu fwy o signalau gadael yn wyrdd yn yr ardal nesaf o drac. Dangosir coch fel arall STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Signal Gadael (semaffor){}Yn ymddwyn fel signal bloc, ond yn angenrheidiol ar gyfer gweithredu'r lliw cywir ar signalau mynediad a chyfun STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Signal Cyfun (semaffor){}Mae'r signal cyfun yn gweithredu fel signal mynediad ac fel signal gadael. Mae hyn yn eich galluogi i adeiladu "coed" o ragsignalau STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Signal Llwybr (semaffor){}Mae signal llwybr yn caniatáu i fwy nag un trên symud i mewn i floc signal ar yr un pryd, os oes modd i'r trên gofrestru llwybr clir at fan aros diogel. Gellir pasio signalau llwybro cyffredin o'r ochr gefn STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}Signal Llwybr Unffordd (semaffor){}Mae signal llwybr yn caniatáu i fwy nag un trên symud i mewn i floc signal ar yr un pryd, os oes modd i'r trên gofrestru llwybr clir at fan aros diogel. Ni ellir pasio signalau llwybro unffordd o'r ochr gefn STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Signal Bloc (trydan){}Dyma'r math mwyaf sylfaenol o signal, sy'n caniatáu un trên yn unig ymhob bloc ar unrhyw adeg STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Signal Mynediad (trydan){}Gwyrdd cyhyd y bod un neu fwy o signalau gadael yn wyrdd yn yr ardal nesaf o drac. Dangosai coch fel arall STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Signal Gadael (trydan){}Yn ymddwyn fel signal bloc, ond yn angenrheidiol ar gyfer gweithredu'r lliw cywir ar signalau mynediad a chyfun STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Signal Cyfun (trydan){}Mae'r signal cyfun yn gweithredu fel signal mynediad ac fel signal gadael. Mae hyn yn eich galluogi i adeiladu "coed" o ragsignalau STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Signal Llwybr (trydan){}Mae signal llwybr yn caniatáu i fwy nag un trên symud i mewn i floc signal ar yr un pryd, os oes modd i'r trên gofrestru llwybr clir at fan aros diogel. Gellir pasio signalau llwybro cyffredin o'r ochr gefn STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Signal Llwybr Unffordd (trydan){}Mae signal llwybr yn caniatáu i fwy nag un trên symud i mewn i floc signal ar yr un pryd, os oes modd i'r trên gofrestru llwybr clir at fan aros diogel. Ni ellir pasio signalau llwybro unffordd o'r ochr gefn STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Trosi Signal{}Pan fydd wedi'i ddewis, bydd clicio ar signal sy'n bodoli yn ei drosi i'r math ac amrywiad a ddewiswyd, Mae Shift+Clic yn dangos amcangyfrif o'r gost STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dwysedd llusgo signalau STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Cynyddu dwysedd llusgo signalau STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Cynyddu amlder y signalau wrth lusgo # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Dewiswch Bont Rheilffordd STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Dewiswch Bont Ffordd STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Dewis pont - cliciwch ar y eich dewis i'w hadeiladu STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :Crog, Dur STR_BRIDGE_NAME_GIRDER_STEEL :Hytrawst, Dur STR_BRIDGE_NAME_CANTILEVER_STEEL :Canttilifer, Dur STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Crog, Concrit STR_BRIDGE_NAME_WOODEN :Pren STR_BRIDGE_NAME_CONCRETE :Concrit STR_BRIDGE_NAME_TUBULAR_STEEL :Tiwbaidd, Dur STR_BRIDGE_TUBULAR_SILICON :Tiwbaidd, Silicon # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Adeiladu Ffyrdd STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Adeiladu Tramffordd STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Adeiladu darn o ffordd. Mae ctrl yn toglo adeiladu/clirio'r ffordd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Adeiladu darn tramffordd. Mae Ctrl yn toglo adeiladu/codi tramffordd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Adeiladu darnau ffordd gan ddefnyddio'r modd Awtoffordd. Mae Ctrl yn toglo adeiladu/clirio ffordd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Adeiladu darn tramffordd gan ddefnyddio'r modd Awtoffordd. Mae Ctrl yn toglo adeiladu/codi tramffordd, tra fo Shift yn toglo adeiladu/amcangyfrif y gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Adeiladu depo cerbydau ffordd (ar gyfer adeiladu a gwasanaethu cerbydau ffordd). Mae Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Adeiladu garej cerbyd tram (ar gyfer adeiladu a gwasanaethu cerbydau tram). Mae Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Adeiladu gorsaf fysiau. Mae Ctrl yn galluogi uno gorsafoedd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Adeiladu gorsaf tramiau teithwyr. Mae Ctrl yn galluogi uno gorsafoedd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Adeiladu bae llwytho lorïau. Mae Ctrl yn galluogi uno gorsafoedd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Adeiladu gorsaf tramiau nwyddau. Mae Ctrl yn galluogi uno gorsafoedd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Gweithredu/dadweithredu ffyrdd un-ffordd STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Adeiladu pont ffordd. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Adeiladu pont tramffordd. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Adeiladu twnnel ffordd. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Adeiladu twnel tramffordd. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}toglu adeiladu/clirio ar gyfer adeiladu ffyrdd STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toglu adeiladu/dileu ar gyfer adeiladu tramffordd # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Cyfeiriad Depo Ffordd STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Dewiswch gyfeiriad depo cerbyd ffordd STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Cyfeiriad Depo Tramiau STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Dewis cyfeiriad y garej cerbyd tram # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Cyfeiriad Gorsaf Fysiau STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Dewiswch gyfeiriad yr orsaf fysiau STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Cyfeiriad Gorsaf Lorïau STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Dewiswch gyfeiriad y bae llwytho lorïau STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Cyfeiriad Gorsaf Tramiau Teithwyr STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Dewiswch gyfeiriad yr orsaf tramiau teithwyr STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Cyfeiriad Gorsaf Tramiau Nwyddau STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Dewiswch gyfeiriad yr orsaf tramiau nwyddau # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Adeiladu Camlesi STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Camlesi STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Adeiladu camlesi. Mae Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Adeiladu lociau. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Adeiladu depo llongau (ar gyfer adeiladu a gwasanaethu llongau). Mae Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Adeiladu doc llongau. Mae Ctrl yn galluogi uno gorsafoedd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Gosod bwï a ellir ei ddefnyddio fel pwynt llwybro. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Adeiladu traphont. Mae Shift yn toglo adeiladu/amcangyfrif y gost STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Pennu ardal dŵr.{}Creu camlas, oni bai fod Ctrl yn cael ei ddal i lawr ar lefel y môr, pan fydd yn boddi'r ardal o'i gwmpas STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Creu afonydd # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Cyfeiriad Depo Llong STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Dewiswch gyfeiriad y depo llong # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Doc # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Meysydd Awyr STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Adeiladu maes awyr. Mae Ctrl yn galluogi uno gorsafoedd, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Dewiswch Faes Awyr STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Dewiswch maint/math y maes awyr STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Maint maes awyr STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Cynllun {NUM} STR_AIRPORT_SMALL :Bach STR_AIRPORT_CITY :Dinas STR_AIRPORT_METRO :Maes awyr metropolitan STR_AIRPORT_INTERNATIONAL :Rhyngwladol STR_AIRPORT_COMMUTER :Cymudol STR_AIRPORT_INTERCONTINENTAL :Rhyng-gyfandirol STR_AIRPORT_HELIPORT :Porth Hofrennydd STR_AIRPORT_HELIDEPOT :Depo Hofrennydd STR_AIRPORT_HELISTATION :Gorsaf Hofrennydd STR_AIRPORT_CLASS_SMALL :Meysydd awyr bach STR_AIRPORT_CLASS_LARGE :Meysydd awyr mawr STR_AIRPORT_CLASS_HUB :Meysydd awyr cyfnewid STR_AIRPORT_CLASS_HELIPORTS :Meysydd awyr hofrennydd STR_STATION_BUILD_NOISE :{BLACK}Swn a gynhyrchir: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}Tirweddu STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Gostwng cornel o dir. Mae llusgo'n gostwng y gornel gyntaf a ddewisir ac yna'n lefelu'r ardal a ddewisir i uchder newydd y gornel. Mae Ctrl yn dewis ardal yn ddeiagonal, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Codi cornel o dir. Mae llusgo'n codi'r gornel gyntaf a ddewisir ac yna'n lefelu'r ardal a ddewisir i uchder newydd y gornel. Mae Ctrl yn dewis ardal yn ddeiagonal, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Gwastatáu ardal o dir i uchder y gornel gyntaf a ddewisir. Mae Ctrl yn dewis ardal yn ddeiagonal, tra fo Shift yn toglo adeiladu/dangos amcangyfrif o'r gost STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Prynu tir ar gyfer defnydd yn y dyfodol. Mae Shift yn toglo adeiladu/amcangyfrif y gost # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Dewis Gwrthrych STR_OBJECT_BUILD_TOOLTIP :{BLACK}Dewisiwch wrthrych i'w hadeiladu. Mae Shift yn toglo adeiladu/dangor amcangyfrif o'r gost STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Dewisiwch dosbarth y gwrthrych i'w hadeiladu STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Rhagolwg o'r gwrthrych STR_OBJECT_BUILD_SIZE :{BLACK}Maint: {GOLD}{NUM} x {NUM} teil STR_OBJECT_CLASS_LTHS :Goleudai STR_OBJECT_CLASS_TRNS :Tyrrau Darlledu # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Coed STR_PLANT_TREE_TOOLTIP :{BLACK}Dewiswch y math o goeden i'w phlannu. Os oes coeden yno'n barod, bydd hyn yn plannu mwy o goed o fath ar hap STR_TREES_RANDOM_TYPE :{BLACK}Coed o fath ar hap STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Gosod coed o fath ar hap. Mae Shift yn toglo adeiladu/dangos amcangyfrif cost STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Coed ar hap STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plannu coed ar hap ar draws y tirwedd # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Cynhyrchu Tirwedd STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Gosod ardaloedd creigiog ar y tirwedd STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Pennu ardal anialwch.{}Dal CTRL i gael gwared ohono STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Cynyddu'r arwynebedd tir i'w godi neu ostwng STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Lleihau'r arwynebedd tir i'w godi neu ostwng STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Cynhyrchu Tir ar Hap STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Creu senario newydd STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Ailosod Tirwedd STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Dileu holl eiddo'r cwmni o'r map STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Ailosod Tirwedd STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Ydych chi'n siwr eich bod eisiau dileu holl eiddo'r cwmni o'r map? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}Cynhyrchu Trefi STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}Tref Newydd STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Sefydlu tref newydd. Mae Shift+Clic yn dangos amcangyfrif o'r gost STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Tref ar hap STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Sefydlu tref mewn safle ar hap STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Llawer o drefi ar hap STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Gorchuddio'r map gyda threfi wedi'i lleoli ar hap STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Enw tref: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Rhowch enw'r dref STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Cliciwch i fewnbynnu enw'r dref STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Enw ar hap STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Cynhyrchu enw newydd ar hap STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Maint tref: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Bach STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Cymhedrol STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Mawr STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Ar hap STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Dewiswch maint y dref STR_FOUND_TOWN_CITY :{BLACK}Dinas STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Mae dinasoedd yn tyfu'n gynt na threfi arferol{}Yn dibynnu ar y gosodiadau, maent hefyd yn fwy pan gânt eu sefydlu STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Cynllun ffyrdd tref STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Dewiswch y cynllun ffyrdd i'w ddefnyddio ar gyfer y dref hon STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Gwreiddiol STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Gwell ffyrdd STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}Grid 2x2 STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}Grid 3x3 STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Ar hap # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Ariannu diwydiant newydd STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Dewiswch ddiwydiant o'r rhestr STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Llawer o ddiwydiannau ar hap STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Gorchuddio'r map gyda diwydiannau wedi'i lleoli ar hap STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Côst: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Mwynchwilio STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Adeiladu STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Ariannu # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Cadwyn ddiwydiant ar gyfer diwydiant {STRING} STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Cadwyn ddiwydiant ar gyfer llwythi {STRING} STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Diwydiannau'n creu STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Diwydiannau'n derbyn STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Tai STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Cliciwch ar ddiwydiant i weld ei gyflenwyr a chwsmeriaid STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Cliciwch ar math llwyth i weld ei gyflenwyr a'i chwsmeriaid STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Dangos cadwyn STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Dangos diwydiannau sy'n cyflenwi a derbyn llwythi STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Cyfuno a'r map bychan STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Dewis y diwydiannau a ddangosir ar y map bychan hefyd STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Dewis cargo STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Dewis y cargo yr ydych am ei ddangos STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Dewis diwydiant STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Dewis y diwydiant yr ydych am ei ddangos # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Gwybodath Ardal Tir STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Cost i'w glirio: {LTBLUE}Amherthnasol STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Cost i'w glirio: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Elw o'i glirio: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :N/A STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Perchennog: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Perchennog ffordd: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Perchennog ffordd: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Perchennog rheilffordd: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Awdurdod Lleol: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Dim STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Cyfeirnodau: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Adeiladwyd: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Dosbarth gorsaf: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Math gorsaf: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Dosbarth maes awyr: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Enw'r maes awyr: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Enw teil maes awyr: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Llwythi a dderbynir: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Terfyn cyflymder rheilffordd: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Terfyn cyflymder ffordd: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Creigiau STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Tir garw STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Tir moel STR_LAI_CLEAR_DESCRIPTION_GRASS :Gwair STR_LAI_CLEAR_DESCRIPTION_FIELDS :Caeau STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Tir ag eira STR_LAI_CLEAR_DESCRIPTION_DESERT :Anialdir STR_LAI_RAIL_DESCRIPTION_TRACK :Cledrau {STRING} STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Cledrau {STRING} gyda signalau bloc STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :Cledrau {STRING} gyda rhagsignalau STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :Cledrau {STRING} gyda signalau gadael STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :Cledrau {STRING} gyda signalau cyfun STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :Cledrau {STRING} gyda signalau llwybro STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :Cledrau {STRING} gyda signalau llwybro unffordd STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :Cledrau {STRING} gyda signalau bloc a rhagsignalau STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :Cledrau {STRING} gyda signalau bloc a signalau gadael STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :Cledrau {STRING} gyda signalau bloc a signalau cyfun STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :Cledrau {STRING} gyda signalau bloc a signalau llwybro STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :Cledrau {STRING} gyda signalau bloc a signalau llwybro unffordd STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :Cledrau {STRING} gyda rhagsignalau a signalau gadael STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :Cledrau {STRING} gyda rhagsignalau a signalau cyfun STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :Cledrau {STRING} gyda rhagsignalau a signalau llwybro STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :Cledrau {STRING} gyda rhag-signalau a signalau llwybro unffordd STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :Cledrau {STRING} gyda signalau gadael a signalau cyfun STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :Cledrau {STRING} gyda signalau gadael a signalau llwybro STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :Cledrau {STRING} gyda signalau gadael a signalau llwybro unffordd STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :Cledrau {STRING} gyda signalau cyfun a llwybro STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :Cledrau {STRING} gyda signalau cyfun a signalau llwybr unffordd STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :Cledrau {STRING} gyda signalau llwybro a signalau llwybro unffordd STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :Depo trên {STRING} STR_LAI_ROAD_DESCRIPTION_ROAD :Ffordd STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Ffordd gyda goleuadau stryd STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Ffordd gyda coed wedi'u plannu STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Depo cerbyd ffordd STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Croesfan wastad ffordd/rheilffordd STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramffordd # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (wrthi'n cael ei adeiladu) STR_LAI_TREE_NAME_TREES :Coed STR_LAI_TREE_NAME_RAINFOREST :Coedwig law STR_LAI_TREE_NAME_CACTUS_PLANTS :Planhigion Cactws STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Gorsaf reilffordd STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Awyrendy STR_LAI_STATION_DESCRIPTION_AIRPORT :Maes awyr STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Ardal llwytho lorïau STR_LAI_STATION_DESCRIPTION_BUS_STATION :Gorsaf fysiau STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Doc llongau STR_LAI_STATION_DESCRIPTION_BUOY :Bwï STR_LAI_STATION_DESCRIPTION_WAYPOINT :Pwynt Llwybro STR_LAI_WATER_DESCRIPTION_WATER :Dŵr STR_LAI_WATER_DESCRIPTION_CANAL :Camlas STR_LAI_WATER_DESCRIPTION_LOCK :Loc STR_LAI_WATER_DESCRIPTION_RIVER :Afon STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Arfordir neu lan afon STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Depo Llong # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Twnnel rheilffordd STR_LAI_TUNNEL_DESCRIPTION_ROAD :Twnnel ffordd STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Pont reilffordd grog o ddur STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Pont reilffordd hytrawst o ddur STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Pont reilffordd cantilifer o ddur STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Pont reilffordd grog o goncrit cyfnerth STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Pont reilffordd bren STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Pont reilffordd goncrit STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Pont reilffordd diwbaidd STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Pont ffordd grog o ddur STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Pont ffordd hytrawst o ddur STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Pont ffordd cantilifer o ddur STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Pont ffordd grog o goncrit cyfnerth STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Pont ffordd bren STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Pont ffordd goncrit STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Pont ffordd diwbaidd STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Traphont STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Darlledydd STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Goleudy STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Pencadlys Cwmni STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Tir cwmni # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}Gwybodaeth am OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Hawlfraint Wreiddiol {COPYRIGHT} 1995 Chris Sawyer, Holl cedwir pob hawl STR_ABOUT_VERSION :{BLACK}fersiwn OpenTTD {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT}2002-2015 Y tîm OpenTTD # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Cadw Gêm STR_SAVELOAD_LOAD_CAPTION :{WHITE}Llwytho Gêm STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Cadw Senario STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Llwytho Senario STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Llwytho Heightmap STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Cadw Siart Uchder STR_SAVELOAD_HOME_BUTTON :{BLACK}Cliciwch yma i newid i'r cyfeiriadur cadw/llwytho diofyn cyfredol STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} yn rhydd STR_SAVELOAD_LIST_TOOLTIP :{BLACK}Rhestr o yriannau, cyfeiriaduron ffeiliau gemau wedi'i cadw STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Enw sydd wedi'i dewis ar gyfer gêm wedi'i chadw STR_SAVELOAD_DELETE_BUTTON :{BLACK}Dileu STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Dileu'r gêm wedi'i chadw sydd wedi'i dewis STR_SAVELOAD_SAVE_BUTTON :{BLACK}Cadw STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Cadw'r gêm hwn gan ddefnyddio'r enw sydd wedi'i dewis STR_SAVELOAD_LOAD_BUTTON :{BLACK}Llwytho STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Llwytho'r gêm a ddewiswyd STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP :{BLACK}Llwytho'r map uchder a ddewiswyd STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Manylion Gêm STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Dim gwybodaeth ar gael STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}Rhowch enw ar gyfer y gêm a gadwyd # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}Cynhyrchu Byd STR_MAPGEN_MAPSIZE :{BLACK}Maint Map: STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Dewis maint y map mewn teiliau. Bydd y nifer o deiliau sydd ara gael ychydig yn llai STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Nifer trefi: STR_MAPGEN_DATE :{BLACK}Dyddiad: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Nifer diwydiannau: STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}Uchder map uchafsymol: STR_MAPGEN_MAX_HEIGHTLEVEL_UP :{BLACK}Cynyddu uchder uchafsymol mynyddoedd ar y map un uned STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN :{BLACK}Lleihau uchder uchafsymol mynyddoedd ar y map un uned STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Uchder Llinell Eira: STR_MAPGEN_SNOW_LINE_UP :{BLACK}Symud y llinell eira un yn uwch STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Symud y llinell eira un yn is STR_MAPGEN_LAND_GENERATOR :{BLACK}Cynhyrchydd Tir: STR_MAPGEN_TREE_PLACER :{BLACK}Algorithm Coed: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Math Tirwedd: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Lefel y Môr: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Afonydd: STR_MAPGEN_SMOOTHNESS :{BLACK}Llyfnder: STR_MAPGEN_VARIETY :{BLACK}Dosbarthiad amrywiaeth: STR_MAPGEN_GENERATE :{WHITE}Cynhyrchu # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}Ymylon mapiau: STR_MAPGEN_NORTHWEST :{BLACK}Gog. Orllewin STR_MAPGEN_NORTHEAST :{BLACK}Gog. Ddwyrain STR_MAPGEN_SOUTHEAST :{BLACK}De Ddwyrain STR_MAPGEN_SOUTHWEST :{BLACK}De Orllewin STR_MAPGEN_BORDER_FREEFORM :{BLACK}Ffurfrydd STR_MAPGEN_BORDER_WATER :{BLACK}Dŵr STR_MAPGEN_BORDER_RANDOM :{BLACK}Ar hap STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Ar hap STR_MAPGEN_BORDER_MANUAL :{BLACK} Llaw STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Cylchdro Map Uchder: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Enw'r Map Uchder STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Maint: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT :{WHITE}Newid uchder uchafsymol y map STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Newid uchder Llinell Eira STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Newid y flwyddyn gychwyn # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}math senario STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Tir Gwastad STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Cynhyrchu Tir Gwastad STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Tir ar hap STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}uchder tir gwastad: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Symud uchder tir gwastad un yn uwch STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Symud uchder tir gwastad un yn is STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Newid uchder tir gwastad # Map generation progress STR_GENERATION_WORLD :{WHITE}Wrthi'n Cynhyrchu'r Byd... STR_GENERATION_ABORT :{BLACK}Diddymu STR_GENERATION_ABORT_CAPTION :{WHITE}Diddymu Cynhyrchu Byd STR_GENERATION_ABORT_MESSAGE :{YELLOW}Ydych chi eisiau diddymu cynhyrchu'r byd? STR_GENERATION_PROGRESS :{WHITE}{NUM}% cyflawn STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}Cynhyrchu byd STR_GENERATION_RIVER_GENERATION :{BLACK}Cynhyrchu afonydd STR_GENERATION_TREE_GENERATION :{BLACK}Cynhyrchu coed STR_GENERATION_OBJECT_GENERATION :{BLACK}Cynhyrchu gwrthrych STR_GENERATION_CLEARING_TILES :{BLACK}Cynhyrchu ardaloedd creigiog a chnapiog STR_GENERATION_SETTINGUP_GAME :{BLACK}Gosod gêm yn ei le STR_GENERATION_PREPARING_TILELOOP :{BLACK}Rhedeg dolen teiliau STR_GENERATION_PREPARING_SCRIPT :{BLACK}Rhedeg sgript STR_GENERATION_PREPARING_GAME :{BLACK}Paratoi gêm # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}Gosodiadau NewGRF STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Gwybodaeth NewGRF manwl STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Ffeiliau NewGRF gweithredol STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Ffeiliau NewGRF anweithredol STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Dewis rhagosodiad: STR_NEWGRF_FILTER_TITLE :{ORANGE}Llinyn hidlo: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Llwytho'r rhagosodiad a ddewiswyd STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Cadw rhagosodiad STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Cadw'r rhestr gyfredol fel rhagosodiad STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Rhoi enw ar gyfer y rhagosodiad STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Dileu rhagosodiad STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Dileu'r rhagosodiad a ddewiswyd STR_NEWGRF_SETTINGS_ADD :{BLACK}Ychwanegu STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Ychwanegu'r ffeil NewGRF a ddewiswyd i'ch ffurfwedd STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Ailsganio ffeiliau STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Diweddaru'r rhestr o ffeiliau NewGRF sydd ar gael STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Tynnu STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Tynnu'r ffeil NewGRF sydd wedi'i ddewis o'r rhestr STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Symud i Fyny STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Symud y ffeil NewGRF sydd wedi'i ddewis i fyny'r rhestr STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Symud i Lawr STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Symud y ffeil NewGRF sydd wedi'i ddewis i lawr y rhestr STR_NEWGRF_SETTINGS_UPGRADE :{BLACK}Uwchraddio STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP :{BLACK}Uwchraddio ffeiliau NewGRF lle fo gennych fersiwn diweddarach wedi ei lwytho STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}Rhestr o bob ffeil NewGRF sydd wedi'u gosod STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Gosod paramedrau STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Dangos paramedrau STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Toglu palet STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Toglu palet y NewGRFa ddewiswyd.{}Gwnech hyn pan fo graffegau'r NewGRF yn edrych yn binc yn y gêm STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Gweithredu newidiadau STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Canfod cynnwys coll arlein STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Gwirio a ellir cael hyd i'r cynnwys coll arlein STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Enw Ffeil: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Fersiwn: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Fersiwn cydnaws lleiaf: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palet: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Paramedrau: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}Dim gwybodaeth newydd ar gael STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Ni ddarganfuwyd ffeil sy'n cyfateb STR_NEWGRF_SETTINGS_DISABLED :{RED}Analluogwyd STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Anghydnaws gyda'r fersiwn yma o OpenTTD # NewGRF save preset window STR_SAVE_PRESET_CAPTION :{WHITE}Cadw rhagosodiad STR_SAVE_PRESET_LIST_TOOLTIP :{BLACK}Rhestr o ragosodiadau ar gael, Dewiswch un i'w gopïo i'r enw cadw isod STR_SAVE_PRESET_TITLE :{BLACK}Rhowch enw ar gyfer y rhagosodiad STR_SAVE_PRESET_EDITBOX_TOOLTIP :{BLACK}Enw a ddewiswyd ar gyfer cadw'r rhagosodiad STR_SAVE_PRESET_CANCEL :{BLACK}Canslo STR_SAVE_PRESET_CANCEL_TOOLTIP :{BLACK}Peidio newid y rhagosodiad STR_SAVE_PRESET_SAVE :{BLACK}Cadw STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Cadw'r rhagosodiad i'r enw a ddewiswyd # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Newid paramedrau NewGRF STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Cau STR_NEWGRF_PARAMETERS_RESET :{BLACK}Ailosod STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Gosod pob paramedr i'w werth rhagosodedig STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Paramedr {NUM} STR_NEWGRF_PARAMETERS_SETTING :{STRING}: {ORANGE}{STRING} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Nifer y paramedrau: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Arolygu - {STRING} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Rhiant STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Arolygu'r gwrthrych rhiant STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING} yn {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Gwrthrych STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Math rheilffordd STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}Paramedr newidyn NewGRF 60+x (hecsaddigidol) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Alinio corlun {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Corlun nesaf STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Mynd i'r corlun cyffredin nesaf, gan hepgor unrhyw gorluniau ailliwio/ffont/llidgorluniau, ac amlapio o'r corlun olaf i'r gyntaf STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Mynd i gorlun STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Mynd i'r corlun a ddynodir. Os nad yw'r corlun yn gorlun cyffredin, mynd i'r corlun gyffredin nesaf STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Corlun blaenorol STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Mynd i'r corlun cyffredin blaenorol, gan hepgor unrhyw gorluniau ailliwio/ffont/llidgorluniau, ac amlapio o'r corlun cyntaf i'r olaf STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Cynrychioliad o'r corlun a ddewiswyd. Fe anwybyddir yr aliniad wrth lunio'r corlun STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Symud y corlun, gan newid yr atredau X ac Y STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Ailosod perthyniad STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Ailosod y dodiadau perthynol STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}Dodiad X: {NUM}, Dodiad Y: {NUM} (Absoliwt) STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}Dodiad X: {NUM}, Dodiad Y: {NUM} (Perthynol) STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Dewis corlun STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Dewis corlun o ynrhyw fan ar y sgrïn STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Mynd i gorlun # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Rhybudd: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Gwall: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Angheuol: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Mae gwall angheuol NewGRF wedi digwydd: {}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :Ni fydd {1:STRING} yn gweithio gyda'r fersiwn o TTDPatch yr adroddir gan OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :Mae {1:STRING} ar gyfer y fersiwn {STRING} o TTD STR_NEWGRF_ERROR_UNSET_SWITCH :Mae {1:STRING} wedi ei gynllunio i gael ei ddefnyddio gyda {STRING} STR_NEWGRF_ERROR_INVALID_PARAMETER :Paramedr Annilys ar gyfer {1:STRING}: paramedr {STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :Rhaid i {1:STRING} fod wedi ei lwytho cyn {STRING} STR_NEWGRF_ERROR_LOAD_AFTER :Rhaid i {1:STRING} fod wedi ei lwytho ar ôl {STRING} STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :Mae {1:STRING} angen OpenTTD fersiwn {STRING} neu'n well STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :y ffeil GRF y gynllunio i gyfieithu STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Mae gormod o NewGRFau wedi'u llwytho STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Gallai llwytho {1:STRING} fel NewGRF statig gyda {STRING} achosi dadsyncroneiddio STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Corlun annisgwyliedig (corlun {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Priodwedd Gweithred 0 anhysbys {4:HEX} (corlun {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Ceisio defnyddio ID annilys (corlun {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}Mae'r {STRING} yn cynnwys corlun llygredig. Bydd corluniau llygredig yn cael eu dynodi gan farc cwestiwn coch (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Yn cynnwys sawl cofnod Gweithred 8 (corlun {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Darllen heibio i ddiwedd llid-gorlun (corlun {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}Mae'r set raffeg sylfaenol a ddefnyddir ar hyn o bryd yn brin o sawl corlun{}Diweddarwch y set raffeg sylfaenol i ddatrys hyn STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}Mae nifer o gorluniau ar goll o'r set graffeg sylfaenol mewn defnydd.{}Diweddarwch y set graffeg sylfaenol.{}Gane eich bod yn chwarae {YELLOW}ciplun datblygiadol o OpenTTD{WHITE}, efallai y byddwch angen {YELLOW}ciplun ddatblygiadol o'r grafffeg sylfaenol{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Nid yw'r adnoddau GRF a geisiwyd ar gael (corlun {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :Fe analluogwyd {1:STRING} gan {STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Fformat cynllun corlun annilys/anhysbys (corlun {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Rhybudd! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Rydych ar fin gwneud newidiadau i gêm sy'n rhedeg. Gall hyn beri i OpenTTD chwalu, neu dorri stâd y gêm. Peidiwch a gyrru adroddiadau am y namau yma.{}Ydych chi'n hollol siŵr am hyn? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Methu ychwanegu'r ffeil: ID GRF dyblyg STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Ni ddarganfuwyd ffeil sy'n cydweddu (GRF cydnaws wedi'i lwytho) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Methu ychwanegu ffeil: Wedi cyrraedd terfyn ffeiliau NewGRF STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Llwythwyd GRF(au) cydnaws yn lle'r rhai coll STR_NEWGRF_DISABLED_WARNING :{WHITE}Analluogwyd y ffeiliau GRF coll STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Ffeil(iau) GRF coll STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Gall dadseibio beri i OpenTTD grasio. Peidiwch ag anfon adroddiadau am fygiau ar gyfer crasiau pellach.{}Ydych chi wir eisiau dadseibio? # NewGRF status STR_NEWGRF_LIST_NONE :Dim STR_NEWGRF_LIST_ALL_FOUND :Pob ffeil yn bresennol STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Canfuwyd ffeiliau cydnaws STR_NEWGRF_LIST_MISSING :{RED}Ffeiliau coll # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}Mae ymddygiad NewGRF '{0:STRING}' yn debygol o beri dadsyncroneiddio a/neu chwalfa STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Fe newidiodd stâd wagen-bŵer '{1:ENGINE}' pan nad oedd mewn depo STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Wedi newid hyd cerbyd i '{1:ENGINE}' pan na fyddai mewn depo. STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Fe newidiodd cynhwysedd cerbyd '{1:ENGINE}' pan nad oedd mewn depo neu'n ail-ffitio STR_BROKEN_VEHICLE_LENGTH :{WHITE}Mae gan y trên' {VEHICLE}' sy'n eiddo i '{COMPANY}' hyd annilys. Mwy na thebyg fe'u hachoswyd gan NewGRFau. Gall y gêm ddadsyncroneiddio neu chwalu. STR_NEWGRF_BUGGY :{WHITE}Mae NewGRF '{0:STRING}' yn darparu gwybodaeth anghywir STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Mae'r wybodaeth llwyth/ailffitio ar gyfer '{1:ENGINE}' yn wahanol i'r rhestr brynu wedi'r adeiladu. Gall hyn beri i awtoadnewyddu/-ddisodli fethu ag ailfitio'n gywir STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' wedi creu lŵp diddiwedd yn y system adalw cynhyrchu STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Dychwelodd adalwad {1:HEX} ganlyniad anhysbys/annilys {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} o STR_NEWGRF_INVALID_ENGINE : STR_NEWGRF_INVALID_INDUSTRYTYPE : # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE : # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}Yn sganio NewGRFau STR_NEWGRF_SCAN_MESSAGE :{BLACK}Yn sganio NewGRFau. Gall gymeryd peth amser yn ddibynnol ar eu nifer... STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF wedi ei sganio allan o gyfanswm o {NUM} rhagdybiedig STR_NEWGRF_SCAN_ARCHIVES :Sganio am archifau # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}Rhestr Arwyddion - {COMMA} Arwydd STR_SIGN_LIST_MATCH_CASE :{BLACK}Cydweddu priflythrennu STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Toglo cydweddu prif lythrennau pan yn cymharu enwau arwyddion yn erbyn y llinyn hidlo # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Golygu testun arwydd STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Mynd i'r arwydd nesaf STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Mynd i'r arwydd blaenorol STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Rhowch enw ar gyfer yr arwydd # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}Trefi STR_TOWN_DIRECTORY_NONE :{ORANGE}- Dim - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Enwau trefi - cliciwch ar enw tref i ganoli'r brif olygfa ar y dref. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y dref STR_TOWN_POPULATION :{BLACK}Poblogaeth y Byd: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (Dinas) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Poblogaeth: {ORANGE}{COMMA}{BLACK} Tai: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Teithwyr mis diwethaf: {ORANGE}{COMMA}{BLACK} uchafswm: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Post mis diwethaf: {ORANGE}{COMMA}{BLACK} uchafswm: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Nwyddau angenrheidiol ar gyfer tyfiant y dref: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{RED}Angen {ORANGE}{STRING} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} ei angen yn y gaeaf STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} wedi ei dderbyn STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (angen o hyd) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (wedi ei dderbyn) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Tref yn tyfu bob {ORANGE}{COMMA}{BLACK}{NBSP}diwrnod STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Tref yn tyfu bob {ORANGE}{COMMA}{BLACK}{NBSP}diwrnod (wedi ei ariannu) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}{RED}Nid{BLACK} yw'r tref yn tyfu STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Uchafswm swn mewn trefi: {ORANGE}{COMMA}{BLACK} uchafswm: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Canoli'r prif olygfa ar y dref. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y dref STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Awdurdod lleol STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Dangos gwybodaeth am yr awdurdod lleol STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}newid enw'r dref STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Ehangu STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Cynyddu maint tref STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Dileu STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Dileu'r dref hon yn llwyr STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Ailenwi Tref # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}Awdurdod lleol {TOWN} STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Graddfeydd cwmnïau lleol: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY}{COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Gweithredoedd posib: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}Rhestr o weithredoedd mae modd eu gwneud yn y dref hon - cliciwch ar eitem am fwy o fanylion STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Gwneud hynny STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Gweithredu'r dewis uchod STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Ymgyrch hysbysebu fach STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Ymgyrch hysbysebu gymhedrol STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Ymgyrch hysbysebu fawr STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Ariannu gwaith ffordd lleol STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Adeiladu cerflun o berchennog y cwmni STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Ariannu adeiladau newydd STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Prynu hawliau cludiant cyfyngol STR_LOCAL_AUTHORITY_ACTION_BRIBE :Llwgrwobrwyo awdurdod lleol STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Dechrau ymgyrch hysbyseb bach yn yr ardal, er mwyn denu mwy o deithwyr a llwythi i'ch gorsafoedd.{} Côst: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Dechrau ymgyrch hysbyseb gymhedrol yn yr ardal, er mwyn denu mwy o deithwyr a llwythi i'ch gorsafoedd.{} Côst: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Dechrau ymgyrch hysbyseb fawr yn yr adral, er mwyn denu mwy o deithwyr a llwythi i'ch gorsafoedd .{} Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW} Ariannu gwaith ffordd ar y rhwydwaith ffyrdd trefol. Bydd yn amharu'n fawr ar drafnidiaeth y dref am hyd at 6 mis .{} Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW} Adeiladu cerflun er clod eich cwmni.{} Côst: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW} Ariannu adeiladu adeiladau masnachol newydd yn y dref.{} Côst: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Prynu'r hawl i fod yr unig gyflenwr cludiant yn y dref am flwyddyn. Bydd awdurdod y dref ond yn caniatáy i deithwyr a chargo ddefnyddio eich gorsafoedd chi {} Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW} Llwgrwobrwyo'r awdurdod lleol i wella'ch gradd, ond byddwch mewn perygl o dderbyn côsb sylweddol os cewch chi'ch dal.{} Côst: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}Amcanion {COMPANY} STR_GOALS_SPECTATOR_CAPTION :{WHITE}Amcanion Bydol STR_GOALS_GLOBAL_TITLE :{BLACK}Amcanion bydol: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Dim - STR_GOALS_SPECTATOR_NONE :{ORANGE}- Amherthnasol - STR_GOALS_PROGRESS :{ORANGE}{STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_COMPANY_TITLE :{BLACK}Amcanion cwmni: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Cliciwch ar amcan i ganoli'r brif olygfa ar y diwydiant/tref/teil Mae Ctrl+Clic yn agor ffenestr golwg newydd ar leoliad y diwydiant/tref/teil # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :Cwestiwn STR_GOAL_QUESTION_CAPTION_INFORMATION :Gwybodaeth STR_GOAL_QUESTION_CAPTION_WARNING :Rhybudd STR_GOAL_QUESTION_CAPTION_ERROR :Gwall ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Canslo STR_GOAL_QUESTION_BUTTON_OK :Iawn STR_GOAL_QUESTION_BUTTON_NO :Na STR_GOAL_QUESTION_BUTTON_YES :Ia STR_GOAL_QUESTION_BUTTON_DECLINE :Gwrthod STR_GOAL_QUESTION_BUTTON_ACCEPT :Derbyn STR_GOAL_QUESTION_BUTTON_IGNORE :Anwybyddu STR_GOAL_QUESTION_BUTTON_RETRY :Ail-geisio STR_GOAL_QUESTION_BUTTON_PREVIOUS :Blaenorol STR_GOAL_QUESTION_BUTTON_NEXT :Nesaf STR_GOAL_QUESTION_BUTTON_STOP :Aros STR_GOAL_QUESTION_BUTTON_START :Dechrau STR_GOAL_QUESTION_BUTTON_GO :Mynd STR_GOAL_QUESTION_BUTTON_CONTINUE :Parhau STR_GOAL_QUESTION_BUTTON_RESTART :Ailddechrau STR_GOAL_QUESTION_BUTTON_POSTPONE :Gohirio STR_GOAL_QUESTION_BUTTON_SURRENDER :Ildio STR_GOAL_QUESTION_BUTTON_CLOSE :Cau ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}Cymorthdaliadau STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Cymorthdaliadau sy'n cael eu cynnig ar gyfer cludo: STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} o {STRING} i {STRING}{YELLOW} (erbyn {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- Dim - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Gwasanaethau sydd eisoes yn derbyn cymhorthdal: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} o {STRING} i {STRING}{YELLOW} ({COMPANY}{YELLOW}, tan {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Cliciwch ar y gwasanaeth i ganoli'r olygfa ar y diwydiant/tref. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y diwydiant/tref # Story book window STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Llyfr Hanes STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Llyfr Hanes Bydol STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :Tudalen {NUM} STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Neidio i dudalen benodol dwy ei ddewis o'r cwymplen yma. STR_STORY_BOOK_PREV_PAGE :{BLACK}Blaenorol STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Mynd i'r dudalen blaenorol STR_STORY_BOOK_NEXT_PAGE :{BLACK}Nesaf STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Mynd i'r dudalen nesaf STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Cyfeiriad amcan annilys # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Enwau gorsafoedd - cliciwch ar enw i ganoli'r brif olygfa ar yr orsaf. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad yr orsaf STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Daliwch CTRL i ddewis mwy nag un eitem STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Gorsaf STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- Dim - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Dewis pob cyfleuster STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Dewis pob math llwyth (gan gynnwys llwythi dim aros) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}Nid oes llwyth o unrhyw fath yn disgwyl # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} o {STATION}) STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} wedi ei gadw ar gyfer llwytho) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Derbyn STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Dangos rhestr o'r llwythi sy'n cael eu derbyn STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Derbyn: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}Mae gan yr orsaf hon hawliau cludo cyfyngol yn y dref hon. STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :Mae {YELLOW}{COMPANY}{BLACK} wedi prynnu hawliau cludo cyfyngol yn y dref hon. STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Perfformiad STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Dangos graddfeydd gorsaf STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Graddio lleol a cyflenwi misol: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}Grwpio yn ôl STR_STATION_VIEW_WAITING_STATION :Gorsaf: Yn aros STR_STATION_VIEW_WAITING_AMOUNT :Cyfanswn: Yn aros STR_STATION_VIEW_PLANNED_STATION :Gorsaf: Cynllunwyd STR_STATION_VIEW_PLANNED_AMOUNT :Cyfanswm: Cynllunwyd STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} o {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} drwy {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} i {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} o orsaf anhysbys STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} i unrhyw orsaf STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} drwy unrhyw orsaf STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} o'r orsaf yma STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} yn galw yn yr orsaf yma STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} i'r orsaf yma STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} heb stop STR_STATION_VIEW_GROUP_S_V_D :Tardd-Trwy-Cyrchfan STR_STATION_VIEW_GROUP_S_D_V :Tardd-Cyrchfan-Trwy STR_STATION_VIEW_GROUP_V_S_D :Trwy-Tardd-Cyrchfan STR_STATION_VIEW_GROUP_V_D_S :Trwy-Cyrchfan-Tardd STR_STATION_VIEW_GROUP_D_S_V :Cyrchfan-Tardd-Trwy STR_STATION_VIEW_GROUP_D_V_S :Cyrchfan-Trwy-Tardd ############ range for rating starts STR_CARGO_RATING_APPALLING :Erchyll STR_CARGO_RATING_VERY_POOR :Gwael Iawn STR_CARGO_RATING_POOR :Gwael STR_CARGO_RATING_MEDIOCRE :Canolig STR_CARGO_RATING_GOOD :Da STR_CARGO_RATING_VERY_GOOD :Da Iawn STR_CARGO_RATING_EXCELLENT :Gwych STR_CARGO_RATING_OUTSTANDING :Rhagorol ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad yr orsaf. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad yr orsaf STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Newid enw'r orsaf STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Dangos pob trên sydd â'r orsaf hon yn eu hamserlen STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Dangos pob cerbyd ffordd sydd â'r orsaf hon yn eu hamserlen STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Dangos pob awyren sydd â'r orsaf hon yn eu hamserlen STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Dangos pob llong sydd â'r orsaf hon yn eu hamserlen STR_STATION_VIEW_RENAME_STATION_CAPTION :Ailenwi gorsaf/ardal lwytho STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Cau'r maes awyr STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Rhwystro awyrennau rhag glanio ar y maes awyr yma # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad y pwynt llwybro. Mae Ctrl+Clic yn agor ffenest olygfa newydd ar leoliad y pwynt llwybro STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Newid enw pwynt llwybro STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad y bwï. Mae Ctrl+Clic yn agor ffenestr olygfa newydd ar leoliad y bwï STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Newid enw bwï STR_EDIT_WAYPOINT_NAME :{WHITE}Golygu enw pwynt llwybro # Finances window STR_FINANCES_CAPTION :{WHITE}Cyllid {COMPANY}{BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Gwariant/Incwm STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Adeiladu STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}Cerbydau Newydd STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Costau Rhedeg Trenau STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Costau Rhedeg Cerbydau Ffordd STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Costau Rhedeg Awyrennau STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Costau Rhedeg Llongau STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Cynnal Eiddo STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Incwm Trenau STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Incwm Cerbydau Ffordd STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Incwm Awyrennau STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Incwm Llongau STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Llog y Benthyciad STR_FINANCES_SECTION_OTHER :{GOLD}Arall STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}Cyfanswm: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Balans Banc STR_FINANCES_LOAN_TITLE :{WHITE}Benthyciad STR_FINANCES_MAX_LOAN :{WHITE}Uchafswm Benthyciad: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}Benthyg {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}Cynyddu maint y benthyciad. Mae Ctrl+Clic yn benthyca gymait ag y sydd bosib STR_FINANCES_REPAY_BUTTON :{BLACK}Ad-dalu {CURRENCY_LONG} STR_FINANCES_REPAY_TOOLTIP :{BLACK}Ad-dalu rhan o'r benthyciad. Mae Ctrl+Clic yn ad-dalu gymaint ag y sydd bosib STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Tanadeiledd # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Rheolwr) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Sefydlwyd: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Cynllun Lliw: STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Cerbydau: STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} trên STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} cerbyd ffordd STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} awyren STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} llong STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}Dim STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Gwerth cwmni: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% yn eiddo {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Tanadeiledd: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} darn{P "" au} rheilffordd STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} darn{P "" au} ffordd STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} teil{P "" iau} dŵr STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} teil{P "" iau} gorsaf STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} {P maes meysydd} awyr STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}Dim STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Adeiladu Pencadlys STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Adeiladu pencadlys cwmni STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}Gweld pencadlys cwmni STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}Gweld pencadlys y cwmni STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Ail-leoli pencadlys cwmni STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Ailadeiladu pencadlys cwmni mewn man arall am 1% o werth y cwmni. Mae Shift+Clic yn dangos amcangyfrif o'r gost heb adleoli STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Manylion STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}Gweld cyfansymau tanadeiledd manwl STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}Gwyneb Newydd STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Dewiswch wyneb newydd ar gyfer y rheolwr STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Cynllun Lliw STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Newid lifrau cerbydau'r cwmni STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Enw Cwmni STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Newid enw'r cwmni STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Enw Rheolwr STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Newid enw'r rheolwr STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Prynu cyfran o 25% o'r cwmni STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Gwerthu cyfran o 25% o'r cwmni STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Prynu cyfran o 25% yn y cwmni yma. Mae Shift+Clic yn dangos amcangyfrif o'r gost heb brynnu cyfran STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Gwerthu cyfran o 25% yn y cwmni yma. Mae Shift+Clic yn dangos amcangyfrif o'r elw heb werthu cyfran STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Enw Cwmni STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Enw Rheolwr STR_BUY_COMPANY_MESSAGE :{WHITE}Rydyn ni'n chwilio am rywun i gymryd ein cwmni ni drosodd.{}{}Hoffech chi brynu {COMPANY} am {CURRENCY_LONG}? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Tanadeiledd {COMPANY} STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Darnau rheilffordd: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signalau STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Darnau ffordd: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Ffordd STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramffordd STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Teiliau dŵr: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Camlesi STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Gorsafoedd: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Teiliau gorsaf STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Meysydd Awyr STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/bl # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Diwydiannau STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- Dim - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}){YELLOW} ({COMMA}% wedi'i gludo) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}/{CARGO_LONG}{STRING}){YELLOW} ({COMMA}%/{COMMA}% wedi'i gludo) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Enwau diwydiannau - cliciwch ar enw i ganoli'r sgrin ar ddiwydiant. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y diwydiant # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Cynnyrch mis diwethaf: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% wedi'i gludo) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Canoli'r brif olygfa ar y diwydiant. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y diwydiant STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Lefel cynhyrchu: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Mae'r diwydiant wedi datgan ei fod ar fin cau! ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Angen: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Angen: {YELLOW}{STRING}{STRING}, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Angen: {YELLOW}{STRING}{STRING}, {STRING}{STRING}, {STRING}{STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Llwythi yn aros i gael ei brosesu: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Cynhyrchu: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Cynhyrchu: {YELLOW}{STRING}{STRING}, {STRING}{STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}Newid cynnyrch (lluosrif o 8, hyd at 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Newid y lefel cynhyrchu (canran, hyd at 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} - {COMMA} Trên STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING} - {COMMA} Cerbyd Ffordd STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING} - {COMMA} Llong STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING} - {COMMA} Awyrennau STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Trenau - cliciwch ar trên i gael gwybodaeth STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Cerbydau ffordd - cliciwch ar cerbyd am wybodaeth STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Llongau - cliciwch ar long am wybodaeth STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Awyrennau - cliciwch ar awyren am wybodaeth STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Elw eleni: {CURRENCY_LONG} (llynedd: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :Trenau sydd ar gael STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Cerbydau sydd ar gael STR_VEHICLE_LIST_AVAILABLE_SHIPS :Llongau sydd ar gael STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Awyrennau sydd ar gael STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}Gweld rhestr o'r dyluniau modur sydd ar gael ar gyfer y math yma o gerbyd STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Golygu'r rhestr STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Anfon y cyfarwyddiadau at bob cerbyd yn y rhestr STR_VEHICLE_LIST_REPLACE_VEHICLES :Cyfnewid Cerbydau STR_VEHICLE_LIST_SEND_FOR_SERVICING :Gyrru i dderbyn Gwasanaeth STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Gyrru i Ddepo STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Gyrru i Ddepo STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Gyrru i Ddepo STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Gyrru i Awyrendy STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Clicio i stopio pob cerbyd yn y rhestr STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Clicio i gychwyn pob cerbyd yn y rhestr STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Gorchmynion wedi'u rhannu rhwng {COMMA} cerbyd # Group window STR_GROUP_ALL_TRAINS :Pob trên STR_GROUP_ALL_ROAD_VEHICLES :Pob cerbyd ffordd STR_GROUP_ALL_SHIPS :Pob llong STR_GROUP_ALL_AIRCRAFTS :Pob awyren STR_GROUP_DEFAULT_TRAINS :Trenau heb eu grwpio STR_GROUP_DEFAULT_ROAD_VEHICLES :Cerbydau ffordd heb eu grwpio STR_GROUP_DEFAULT_SHIPS :Llongau heb eu grwpio STR_GROUP_DEFAULT_AIRCRAFTS :Awyrenau heb eu grwpio STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grŵp - cliciwch ar grŵp i restru pob cerbyd yn y grŵp hwn. Gallwch glico a llusgo grwpiau i drefnu'r hierarchaeth. STR_GROUP_CREATE_TOOLTIP :{BLACK}Cliciwch i greu grŵp STR_GROUP_DELETE_TOOLTIP :{BLACK}Dileu'r grŵp a ddewiswyd STR_GROUP_RENAME_TOOLTIP :{BLACK}Ailenwi'r grŵp a ddewiswyd STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Cliciwch i amddiffyn y grŵp rhag awtoddisodli gêm-eang STR_QUERY_GROUP_DELETE_CAPTION :{WHITE}Dileu Grŵp STR_GROUP_DELETE_QUERY_TEXT :{WHITE} Ydych chi'n siwer eich bod am ddileu'r grŵp yma ac unrhyw ddisgynyddion? STR_GROUP_ADD_SHARED_VEHICLE :Ychwanegu cerbyd a rennir STR_GROUP_REMOVE_ALL_VEHICLES :Dileu pob cerbyd STR_GROUP_RENAME_CAPTION :{BLACK}Ailenwi grŵp # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :Cerbydau Rheilffordd Newydd STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Cerbydau Rheilffordd Trydan Newydd STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Cerbydau Monoreilffordd Newydd STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Cerbydau Maglef Newydd STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Cerbydau Rheilffordd STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Cerbydau Ffordd Newydd STR_BUY_VEHICLE_SHIP_CAPTION :Llongau Newydd STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Awyrennau Newydd STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Pwysau: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Cyflymder: {GOLD}{VELOCITY}{BLACK} Pŵer: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Cyflymder: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Cyflymder ar y môr: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Cyflymder ar gamlas/afon: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Cost Rhedeg: {GOLD}{CURRENCY_LONG}/bl STR_PURCHASE_INFO_CAPACITY :{BLACK}Gallu cludo: {GOLD}{CARGO_LONG} {STRING} STR_PURCHASE_INFO_REFITTABLE :(gallu ailffitio) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Cynlluniwyd: {GOLD}{NUM}{BLACK} Bywyd: {GOLD}{COMMA} mlynedd STR_PURCHASE_INFO_RELIABILITY :{BLACK}Dibynadwyedd Uchaf: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cost: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Pwysau: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Cyflymder: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Gallu cludo: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Wageni Pŵer: {GOLD}+{POWER}{BLACK} Pwysau: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Modd ei ailffitio i: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :Pob math o lwyth STR_PURCHASE_INFO_ALL_BUT :Popeth ond{CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Grym Tynnu Uchaf: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Pellter cyrhaeddiad: {GOLD}{COMMA} teil STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Rhestr dewis trenau. Cliciwch ar gerbyd am wybodaeth. Mae Ctrl+Clicio'n toglu cuddio'r math cerbyd STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Rhestr dewis cerbydau ffordd. Cliciwch ar gerbyd am wybodaeth. Mae Ctrl+Clicio'n toglu cuddio'r math cerbyd STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Rhestr ddewis llongau. Cliciwch ar long am wybodaeth. Mae Ctrl+Clicio'n toglu cuddio'r math llong STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Rhestr ddewis awyrennau. Cliciwch ar awyren am wybodaeth. Mae Ctrl+Clicio'n toglu cuddio'r math awyren STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Prynu Cerbyd STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Prynu Cerbyd STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Prynu Llong STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Prynu Awyren STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Adeiladu'r cerbyd trên sydd wedi'i amlygu. Mae Shift+Clic yn dangos amcangyfrif o'r gost STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Adeiladu'r cerbyd ffordd sydd wedi'i amlygu. Mae Shift+Clic yn dangos amcangyfrif o'r gost STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Adeiladu'r llong sydd wedi'i hamlygu. Mae Shift+Clic yn dfangos amcangyfrif o'r gost STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Adeiladu'r awyren sydd wedi'i hamlygu. Mae Shift+Clic yn dangos amcangyfrif o'r gost STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Ailenwi STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Ailenwi STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Ailenwi STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Ailenwi STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Ailenwi math y cerbyd trên STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Ailenwi'r math cerbyd ffordd STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Ailenwi'r math llong STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Ailenwi'r math awyren STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Cuddio STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Cuddio STR_BUY_VEHICLE_SHIP_HIDE_TOGGLE_BUTTON :{BLACK}Cuddio STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :{BLACK}Cuddio STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON :{BLACK}Dangos STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}Dangos STR_BUY_VEHICLE_SHIP_SHOW_TOGGLE_BUTTON :{BLACK}Dangos STR_BUY_VEHICLE_AIRCRAFT_SHOW_TOGGLE_BUTTON :{BLACK}Dangos STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toglu cuddio/arddangos math y cerbyd rheilffordd STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toglu cuddio/arddangos math y cerbyd ffordd STR_BUY_VEHICLE_SHIP_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toglu cuddio/arddangos math y llong STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toglu cuddio/arddangos math yr awyren STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Ailenwi math y cerbyd trên STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Ailenwi'r math cerbyd ffordd STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Ailenwi'r math llong STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Ailenwi'r math awyren # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}Newid enw'r depo STR_DEPOT_RENAME_DEPOT_CAPTION :Ailenwi depo STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} cerbyd{P "" au}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Trenau - cliciwch ar y trên am wybodaeth, llusgwch gerbyd i'w ychwanegu neu i'w dynnu o'r trên. Daliwch Ctrl i symyd pob cerbyd y tu ôl hefyd STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Cerbydau - cliciwch ar gerbyd am wybodaeth STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Llongau - cliciwch ar long am wybodaeth STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Awyrennau - cliciwch ar awyren am wybodaeth STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Llusgwch gerbyd trên yma i'w werthu STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Llusgwch gerbyd ffordd to yma i'w werthu STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Llusgwch long yma i'w gwerthu STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Llusgwch awyren yma i'w gwerthu STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Llusgwch injan y trên yma i werthu'r holl drên STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Gwerthu pob trên yn y depo STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Gwerthu pob cerbyd ffordd yn y depo STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Gwerthu pob llong yn y depo STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Gwerthu pob awyren yn yr awyrendy STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Awtoddisodli pob trên yn y depo STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Awtoddisodli pob cerbyd ffordd yn y depo STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Awtoddisodli pob llong yn y depo STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Awtoddisodli pob awyren yn yr awyrendy STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}Cerbyd Newydd STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}Cerbyd Newydd STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}Llong Newydd STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}Awyrennau Newydd STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Prynu cerbyd trên newydd STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Prynu cerbyd ffordd newydd STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Prynu llong newydd STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Prynu awyren newydd STR_DEPOT_CLONE_TRAIN :{BLACK}Dyblygu Trên STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Dyblygu Cerbyd STR_DEPOT_CLONE_SHIP :{BLACK}Dyblygu Llong STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Dyblygu Awyren STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}Bydd hyn yn prynu copi o'r trên gan gynnwys pob cerbyd. Cliciwch ar y botwm hwn ac yna ar drên sydd tu fewn neu tu allan i'r depo. Bydd Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Bydd hyn yn adeiladu copi o gerbyd ffordd. Cliciwch ar y botwm hwn ac yna ar gerbyd sydd tu fewn neu tu allan i'r depo. Mae Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost heb brynnu STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}Bydd hyn yn adeiladu copi o long. Cliciwch ar y botwm hwn ac yna ar long sydd tu fewn neu tu allan i'r depo. Mae Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}Bydd hyn yn adeiladu copi o awyren. Cliciwch ar y botwm hwn ac yna ar awyren sydd tu fewn neu tu allan i'r awyrendy. Mae Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Canoli'r prif olygfa ar leoliad y depo trên. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y depo STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad y depo cerbyd ffordd. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y depo STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad depo'r llong. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad y depo STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Canoli'r prif olygfa ar leoliad yr awyrendy. Mae Ctrl+Clic yn agor ffenest golwg newydd ar leoliad yr awyrendy STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Dangos rhestr o bob trên gyda'r depo presennol yn eu gorchmynion STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Dangos rhestr o bob cerbyd ffordd gyda'r depo presennol yn eu gorchmynion STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Dangos rhestr o bob llong gyda'r depo presennol yn eu gorchmynion STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Dangos rhestr o bob awyren gyda unrhyw awyrendy yn y maes awyr hwn yn eu gorchmynion STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Clicio i stopio pob trên sydd tu mewn i'r depo STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Clicio i stopio pob cerbyd ffordd sydd tu mewn i'r depo STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Clicio i stopio pob llong sydd tu mewn i'r depo STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Clicio i stopio pob awyren sydd tu mewn i'r awyrendy STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Clicio i gychwyn pob trên sydd tu mewn i'r depo STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Clicio i gychwyn pob cerbyd ffordd sydd tu mewn i'r depo STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Clicio i gychwyn pob llong sydd tu mewn i'r depo STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Clicio i gychwyn pob awyren sydd tu mewn i'r awyrendy STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Rydych chi ar fin gwerthu pob cerbyd yn y depo. Ydych chi'n siwr? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Neges gan wneuthurwr cerbydau STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Rydyn ni newydd gynllunio {STRING} newydd - a fyddai gennych chi ddiddordeb mewn cael defnydd cyfyngol o'r cerbyd hwn am flwyddyn er mwyn i ni gael profi ei berfformiad cyn y bydd ar gael i bawb? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :trên STR_ENGINE_PREVIEW_ROAD_VEHICLE :cerbyd ffordd STR_ENGINE_PREVIEW_AIRCRAFT :awyren STR_ENGINE_PREVIEW_SHIP :llong STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :trên monoreilffordd STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :trên maglef STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Côst: {CURRENCY_LONG} Pwysau: {WEIGHT_SHORT}{}Cyflymder: {VELOCITY} Pŵer: {POWER}{}Côst Rhedeg: {CURRENCY_LONG}/bl{}Gallu cludo: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Pwysau: {WEIGHT_SHORT}{}Cyflymder: {VELOCITY} Pŵer: {POWER} Grym Uchaf: {6:FORCE}{}Cost Rhedeg: {4:CURRENCY_LONG}/bl{}Cynhwysedd: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Cyflym. Uchaf: {VELOCITY}{}Cynhwysedd: {CARGO_LONG}, {CARGO_LONG}{}Côst Rhedeg: {CURRENCY_LONG}/bl STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Cyflym. Uchaf: {VELOCITY}{}Cynhwysedd: {CARGO_LONG}{}Cost Rhedeg: {CURRENCY_LONG}/bl STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cost: {CURRENCY_LONG} Cyf. Uchaf: {VELOCITY} Pellter: {COMMA} teil{}Cynhwysedd: {CARGO_LONG}, {CARGO_LONG}{}Cost Rhedeg: {CURRENCY_LONG}/bl STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Cyf. Uchaf: {VELOCITY} Pellter: {COMMA} teil{}Cynhwysedd: {CARGO_LONG}{}Cost Rhedeg: {CURRENCY_LONG}/bl # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}Disodli {STRING} - {STRING} STR_REPLACE_VEHICLE_TRAIN :Trên STR_REPLACE_VEHICLE_ROAD_VEHICLE :Mae Cerbyd Ffordd STR_REPLACE_VEHICLE_SHIP :Mae Llong STR_REPLACE_VEHICLE_AIRCRAFT :Mae Awyren STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Cerbydau mewn defnydd STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP :{BLACK}Colofn gyda cherbydau rydych yn berchen STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Cerbydau ar gael STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP :{BLACK}Colofn gyda cherbydau ar gael ar gyfer disodli STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Dewiswch y math injan i'w ddisodli STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Dewiswch y math injan newydd yr hoffech chi ei ddefnyddio yn lle'r math injan ar y chwith STR_REPLACE_VEHICLES_START :{BLACK}Dechrau Disodli Cerbydau STR_REPLACE_VEHICLES_NOW :Disodli pob cerbyd yn awr STR_REPLACE_VEHICLES_WHEN_OLD :Disodli hen gerbydau yn unig STR_REPLACE_HELP_START_BUTTON :{BLACK}Pwyswch i ddechrau disodli'r math injan a ddewiswyd ar y chwith gyda'r math injan a ddewiswyd ar y dde STR_REPLACE_NOT_REPLACING :{BLACK}Ddim yn disodli STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Dim cerbyd wedi'i ddewis STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} pan yn hen STR_REPLACE_VEHICLES_STOP :{BLACK}Gorffen Disodli Cerbydau STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Gwasgwch i atal disodli'r math injan sydd wedi'i ddewis ar y chwith STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Disodli: {ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Newid rhwng y ffenest disodli wagenni a'r un injanau STR_REPLACE_ENGINES :Injanau STR_REPLACE_WAGONS :Wagenni STR_REPLACE_HELP_RAILTYPE :{BLACK}Dewiswch y math o reilffordd yr hoffech chi ddisodli injans ar ei gyfer STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Dangoswch pa injan (os unrhyw) y mae'r injan ar y chwith yn cael ei disodli gyda STR_REPLACE_RAIL_VEHICLES :Cerbydau Rheilffordd STR_REPLACE_ELRAIL_VEHICLES :Cerbydau Rheilffordd Drydan STR_REPLACE_MONORAIL_VEHICLES :Cerbydau Monoreilffordd STR_REPLACE_MAGLEV_VEHICLES :Cerbydau Maglef STR_REPLACE_REMOVE_WAGON :{BLACK}Tynnu wagenni: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Gwneud i awtoddisodli gadw hyd y trên yr un peth drwy dynnu wagenni (gan ddechrau yn y blaen), os byddai newid yr injan yn gwneud y trên yn hirach # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad y trên. Bydd Ctrl+Clic yn dilyn yn ffenestr bennaf STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad y cerbyd, Bydd Ctrl+Clic yn dilyn yn ffenestr bennaf STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Canol'r prif olygfa ar leoliad yr long. Bydd Ctrl+Clic yn dilyn yn ffenestr bennaf STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Canoli'r brif olygfa ar leoliad yr awyren. Bydd Ctrl+Clic yn dilyn yn ffenestr bennaf STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Anfon trên i'r depo. Bydd CTRL+clic yn rhoi gwasanaeth iddo'n unig STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Anfon cerbyd i'r depo. Bydd CTRL+clic yn rhoi gwasanaeth iddo'n unig STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Gyrru'r llong i ddepo. Bydd CTRL+clic yn rhoi gwasanaeth iddo'n unig STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Anfon awyren to awyrendy. Bydd CTRL+click yn rhoi gwasanaeth iddo'n unig STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Bydd hyn yn adeiladu copi o'r trên gan gynnwys pob un o'i gerbydau. Mae Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Bydd hyn yn adeiladu copi o'r cerbyd ffordd. Mae Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Bydd hyn yn adeiladu copi o'r llong. Mae Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Bydd hyn yn adeiladu copi o'r awyren. Mae Ctrl+Clic yn rhannu'r gorchmynion, tra fo Shift+Clic yn dangos amcangyfrif o'r gost STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Gorfodi trên i barhau heb fod signal yn ei glirio STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Ailffitio trên i gario llwyth o fath gwahanol STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Ailffitio cerbyd ffordd i gario llwyth o fath gwahanol STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Ailffitio llong i gario llwyth o fath gwahanol STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Ailffitio awyren i gario llwyth o fath gwahanol STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Gwrthdroi cyfeiriad trên STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Gorfodi cerbyd i droi rownd STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Dangos gorchmynion trên. Mae Ctrl+Clic yn ddangos amserlen y trên STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Dangos gorchmynion cerbyd. Mae Ctrl+Clic yn ddangos amserlen y cerbyd STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Dangos gorchmynion llong. Mae Ctrl+Clic yn ddangos amserlen y long STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Dangos gorchmynion awyren. Mae Ctrl + clic yn ddangos amserlen y awyren STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Dangos manylion trên STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Dangos manylion cerbyd ffordd STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Dangos manylion llong STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Dangos manylion awyren STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Gweithred y trên - cliciwch yma stopio/cychwyn y trên. Ctrl+Clic i sgrolio i'r gyrchfan STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Gweithred y cerbyd - cliciwch yma stopio/cychwyn y cerbyd. Ctrl+Clic i sgrolio i'r gyrchfan STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Gweithred y llong - cliciwch yma stopio/cychwyn y llong. Ctrl+Clic i sgrolio i'r gyrchfan STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Gweithred yr awyren - cliciwch yma stopio/cychwyn yr awyren. Ctrl+Clic i sgrolio i'r gyrchfan # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Llwytho / Dadlwytho STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Gadael STR_VEHICLE_STATUS_CRASHED :{RED}Wedi crashio! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Torri lawr STR_VEHICLE_STATUS_STOPPED :{RED}Wedi stopio STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Yn dod at aros, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}Dim Pŵer STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Aros am lwybr clir STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Rhy bell i'r cyrchfan nesaf STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Mynd tua {STATION}, {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}Dim gorchmynion, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Mynd tua {WAYPOINT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Mynd tua {DEPOT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Mynd am wasanaeth yn {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Wedi aros STR_VEHICLE_COMMAND_STOPPED :{RED}Wedi aros STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Wedi dechrau STR_VEHICLE_COMMAND_STARTED :{GREEN}Wedi dechrau # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Manylion) STR_VEHICLE_NAME_BUTTON :{BLACK}Enw STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Enwi trên STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Enwi cerbyd ffordd STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Enwi llong STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Enwi awyren STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Oed: {LTBLUE}{STRING}{BLACK} Cost Rhedeg: {LTBLUE}{CURRENCY_LONG}/bl # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} blwyddyn ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} blwyddyn ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}cyflymder uchaf: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Cyf. uchaf: {LTBLUE}{VELOCITY} {BLACK}Pell. Cyrraedd: {LTBLUE}{COMMA} teil STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Pwys: {LTBLUE}{WEIGHT_SHORT} {BLACK}Pŵer: {LTBLUE}{POWER}{BLACK} Cyflym. Max: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Pwys: {LTBLUE}{WEIGHT_SHORT} {BLACK}Pŵer: {LTBLUE}{POWER}{BLACK} Cyflym. Max: {LTBLUE}{VELOCITY} {BLACK}Max. T.E.: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Elw eleni: {LTBLUE}{CURRENCY_LONG} (llynedd: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Dibynadwyedd: {LTBLUE}{COMMA}% {BLACK}Toriadau ers gwasanaeth olaf: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Codi: {LTBLUE}{NUM}{BLACK} Pris: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Cynhwysedd: {LTBLUE}Dim{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Cynhwysedd: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Cynhwysedd: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Cynhwysedd: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Credydau Trosglwyddo: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Bwlch rhwng gwasanaeth: {LTBLUE}{COMMA}{NBSP}diwrnod{BLACK} Gwasanaeth diwethaf: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Bwlch rhwng gwasanaethu: {LTBLUE}{COMMA}%{BLACK} Gwasanaeth diwethaf: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Cynyddu'r bwlch rhwng gwasanaethau fesul 10. Mae Ctrl+Clic yn gostwng y bwlch rhwng gwasanaethau fesul 5. STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Gostwng y bwlch rhwng gwasanaethau fesul 10. Mae Ctrl+Clic yn gostwng y bwlch rhwng gwasanaethau fesul 5. STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Newid dull ystod gwasanaethu STR_VEHICLE_DETAILS_DEFAULT :Rhagosodedig STR_VEHICLE_DETAILS_DAYS :Diwrnod STR_VEHICLE_DETAILS_PERCENT :Canran STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Enwi trên STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Enwi cerbyd ffordd STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Enwi llong STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Enwi awyren # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Adeiladwyd: {LTBLUE}{NUM}{BLACK} Gwerth: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Gwerth: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Cyfanswm cynhwysedd cludo'r trên hwn: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Gwag STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} o {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} o {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Llwyth STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Dangos manylion y llwyth sy'n cael ei gludo STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Gwybodaeth STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Dangos manylion cerbydau'r trên STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Cyfansymau Gallu Cludo STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Dangos cynwyseddau pob cerbyd STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Cyfanswm Llwyth STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Dangos cynhwysedd y trên, wedi'i rannu yn ôl math nwyddau STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Cynhwysedd: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Ailffitio) STR_REFIT_TITLE :{GOLD}Dewiswch y math o lwyth i'w gario: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}bellach yn gallu cario: {GOLD}{CARGO_LONG}{}{BLACK}Côst o ailffitio: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}Cynhwysedd newydd: {GOLD}{CARGO_LONG}{}{BLACK}Incwm drwy ailffitio: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Cynhwysedd newydd: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Cost ailffitio: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}Cynhwysedd newydd: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Incwm drwy ailffitio: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Dewisiwch y cerbydau i ailffitio. Mae llusgo'r llygoden yn galluogi dewis sawl cerbyd. Mae clicio ar wagle'n dewis y cerbydres gyfan. Mae Ctrl+Clic yn dewis cerbyd a phob un ar ei hôl STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Dewiswch fath o lwyth i'r trên ei gario STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Dewiswch y math o lwyth i'r cerbyd ffordd gario STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Dewiswch lwyth i'r llong ei gario STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Dewiswch y math o lwyth i'r awyren ei chario STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Ailffitio trên STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Ailffitio cerbyd ffordd STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Ailffitio llong STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Ailffitio awyren STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Ailffitio'r trên i gario'r math o llwyth sydd wedi'i ddewis STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Ailffitio cerbyd ffordd i gario'r llwyth sydd wedi'i amlygu STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Ailffitio llong i gario'r llwyth sydd wedi'i amlygu STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Ailffitio awyren i gario'r math o lwyth sydd wedi'i amlygu # Order view STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Gorchmynion) STR_ORDERS_TIMETABLE_VIEW :{BLACK}Amserlen STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Newid i'r golwg amserlen STR_ORDERS_LIST_TOOLTIP :{BLACK}Rhestr orchmynion - cliciwch orchymyn i'w amlygu. Mae Ctrl+Clic yn sgrolio i gyrchfan yr orchymyn STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - Diwedd Gorchmynion - - STR_ORDERS_END_OF_SHARED_ORDERS :- - Diwedd y Gorchmynion sydd wedi'u Rhannu - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}Heb stop STR_ORDER_GO_TO :Mynd i STR_ORDER_GO_NON_STOP_TO :Mynd heb stop i STR_ORDER_GO_VIA :Mynd trwy STR_ORDER_GO_NON_STOP_VIA :Mynd heb stop trwy STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Newid ymddygiad stopio o'r gorchymyn a amlygwyd STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Llwyth llawn, unrhyw gargo STR_ORDER_DROP_LOAD_IF_POSSIBLE :Llwytho os yw ar gael STR_ORDER_DROP_FULL_LOAD_ALL :Llwyth llawn, pob cargo STR_ORDER_DROP_FULL_LOAD_ANY :Llwyth llawn, unrhyw gargo STR_ORDER_DROP_NO_LOADING :Dim llwytho STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Newid ymddygiad llwytho'r gorchymyn a amlygwyd STR_ORDER_TOGGLE_UNLOAD :{BLACK}Dadlwytho'r cyfan STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Dadlwytho os y derbynnir STR_ORDER_DROP_UNLOAD :Dadlwytho'r cyfan STR_ORDER_DROP_TRANSFER :Trosglwyddo STR_ORDER_DROP_NO_UNLOADING :Dim dadlwytho STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Newid ymddygiad dadlwythio'r gorchymyn a amlygwyd STR_ORDER_REFIT :{BLACK}Ailffitio STR_ORDER_REFIT_TOOLTIP :{BLACK}Dewiswch y math o lwyth yr hoffech chi ailffitio gyda'r gorchymyn hwn. Cliciwch Ctrl-clic er mwyn diddymu'r cyfarwyddyd hwn. STR_ORDER_REFIT_AUTO :{BLACK}Ailffitio mewn gorsaf STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Dewis y math o lwyth i ailffitio ar ei gyfer yn y gorchymyn yma. Mae Ctrl+Clic yn tynnu'r gorchymyn. Bydd ailffitio ond yn digwydd os yw'r cerbyd yn caniatáu hynny STR_ORDER_DROP_REFIT_AUTO :Llwyth gosodedig STR_ORDER_DROP_REFIT_AUTO_ANY :Llwythi ar gael STR_ORDER_SERVICE :{BLACK}Gwasanaeth STR_ORDER_DROP_GO_ALWAYS_DEPOT :Mynd bob tro STR_ORDER_DROP_SERVICE_DEPOT :Gwasanaethu os oes angen STR_ORDER_DROP_HALT_DEPOT :Stopio STR_ORDER_SERVICE_TOOLTIP :{BLACK}Hepgor y gorchymyn hwn os nad oes angen gwasanaeth STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Data cerbyd i seilio'r naid arno # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Canran llwyth STR_ORDER_CONDITIONAL_RELIABILITY :Dibynadwyedd STR_ORDER_CONDITIONAL_MAX_SPEED :Cyflymder uchaf STR_ORDER_CONDITIONAL_AGE :Oed (blynyddoedd) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Angen gwasanaeth STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Bob tro STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Oes yn weddill (blynyddoedd) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Sut i gymharu'r data cerbyd i'r gwerth a roddwyd STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :yn hafal i STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :ddim yn hafal i STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :yn llai na STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :yn llai na neu'n fwy na STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :yn fwy na STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :yn fwy neu'n llai na STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :yn wir STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :yn anghywir STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK} Y gwerth i gymharu data'r cerbyd yn ei erbyn STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Rhowch y gwerth i'w gymharu'n ei erbyn STR_ORDERS_SKIP_BUTTON :{BLACK}Hepgor STR_ORDERS_SKIP_TOOLTIP :{BLACK}hepgor y gorchymyn cyfredol, a chychwyn y nesaf STR_ORDERS_DELETE_BUTTON :{BLACK}Dileu STR_ORDERS_DELETE_TOOLTIP :{BLACK}Dileu y gorchymyn sydd wedi'i amlygu STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Dileu pob gorchymyn STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Peidio â rhannu STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Peidio â rhannu rhestr gorchmynion. Mae Ctrl+Clic hefyd yn dileu holl orchmynion y cerbyd hwn STR_ORDERS_GO_TO_BUTTON :{BLACK}Mynd i STR_ORDER_GO_TO_NEAREST_DEPOT :Mynd i'r depo agosaf STR_ORDER_GO_TO_NEAREST_HANGAR :Mynd i'r awyrendy agosaf STR_ORDER_CONDITIONAL :Naid gorchymyn amodol STR_ORDER_SHARE :Rhannu gorchmynion STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Mewnosod gorchymyn newydd cyn yr orchymyn a amlygwyd, neu greu ar ddiwedd y rhestr. Mae Ctrl yn gwneud gorchymynion orsaf yn rhai 'llwyth llawn unrhyw nwyddau', gorchymynion pwyntiau llwybro 'heb aros' a gorchmynion depot 'gwasanaethu'. Mae 'Rhannu gorchmynion' neu Ctrl yn galluogi i'r cerbyd yma rannu gorchmynion gyda'r cerbyd a ddewisir. Mae clicio ar gerbyd yn copïo gorchmynion o'r cerbyd hwnnw. Mae gorchymyn depo'n analluogi gwasanaethu diofyn ar gyfer y cerbyd STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Dangos pob cerbydau sy'n rhannu'r amserlen hon # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Mynd trwy {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Mynd heb stop trwy {WAYPOINT} STR_ORDER_SERVICE_AT :Gwasanaethu yn STR_ORDER_SERVICE_NON_STOP_AT :Gwasanaethu heb stopio yn STR_ORDER_NEAREST_DEPOT :agosaf STR_ORDER_NEAREST_HANGAR :yr Awyrendy agosaf STR_ORDER_TRAIN_DEPOT :Depo Trên STR_ORDER_ROAD_VEHICLE_DEPOT :Depo Cerbydau Ffordd STR_ORDER_SHIP_DEPOT :Depo Llongau STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{0:STRING} {2:STRING} {1:STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(Ailffitio i {STRING}) STR_ORDER_REFIT_STOP_ORDER :(Ailfitio i {STRING} a stopio) STR_ORDER_STOP_ORDER :(Stopio) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(Ymhlyg) STR_ORDER_FULL_LOAD :(Llwyth llawn) STR_ORDER_FULL_LOAD_ANY :(Llwyth llawn, unrhyw gargo) STR_ORDER_NO_LOAD :(Dim llwytho) STR_ORDER_UNLOAD :(Dadlwytho a llwytho) STR_ORDER_UNLOAD_FULL_LOAD :(Dadlwytho ac aros am lwyth llawn) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Dadlwytho ac aros am lwyth llawn) STR_ORDER_UNLOAD_NO_LOAD :(Dadlwytho a gadael yn wag) STR_ORDER_TRANSFER :(Trosglwyddo a llwytho) STR_ORDER_TRANSFER_FULL_LOAD :(Trosglwyddo ac aros am lwyth llawn) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Trosglwyddo ac aros am lwyth llawn) STR_ORDER_TRANSFER_NO_LOAD :(Trosglwyddo a gadael yn wag) STR_ORDER_NO_UNLOAD :(Dim dadlwytho ond llwytho) STR_ORDER_NO_UNLOAD_FULL_LOAD :(Dim dadlwytho, aros am lwyth llawn) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Dim dadlwytho, aros am unrhyw lwyth llawn) STR_ORDER_NO_UNLOAD_NO_LOAD :(Dim llwytho na dadlwytho) STR_ORDER_AUTO_REFIT :(Ailffitio i {STRING}) STR_ORDER_FULL_LOAD_REFIT :(Llwyth llawn gan ailffitio i {STRING}) STR_ORDER_FULL_LOAD_ANY_REFIT :(Llwyth llawn o unrhyw gargo gan ailffitio i {STRING}) STR_ORDER_UNLOAD_REFIT :(Dadlwytho a llwytho gan ailffitio i {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Dadlwytho ac aros am lwyth llawn o gargo gan ailffitio i {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Dadlwytho ac aros am unrhyw lwyth llawn gan ailffitio o {STRING}) STR_ORDER_TRANSFER_REFIT :(Trosglwyddo a llwytho gan ailffitio i {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Trosglwyddo ac aros am lwyth llawn gan ailffitio i {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Trosglwyddo ac aros am unrhyw lwyth llawn gan ailffitio i {STRING}) STR_ORDER_NO_UNLOAD_REFIT :(Dim dadlwytho ond llwytho gan ailffitio i {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Dim dadlwytho ac aros am lwyth llawn gan ailffitio i {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Dim dadlwytho ac aros am unrhyw lwyth llawn gan ailffitio i {STRING}) STR_ORDER_AUTO_REFIT_ANY :llwythi ar gael STR_ORDER_STOP_LOCATION_NEAR_END :[ochr agos] STR_ORDER_STOP_LOCATION_MIDDLE :[canol] STR_ORDER_STOP_LOCATION_FAR_END :[ochr bell] STR_ORDER_OUT_OF_RANGE :{RED} (Mae'r cyrchfan nesaf allan o gyrraedd y cerbyd) STR_ORDER_CONDITIONAL_UNCONDITIONAL :Neidio i orchymyn {COMMA} STR_ORDER_CONDITIONAL_NUM :Neidio i orchymyn {COMMA} pan fo {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :Neidio i orchymyn {COMMA} pan fo {STRING} {STRING} STR_INVALID_ORDER :{RED} (Gorchymyn Annilys) # Time table window STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Amserlen) STR_TIMETABLE_ORDER_VIEW :{BLACK}Gorchmynion STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Newid i'r golwg gorchmynion STR_TIMETABLE_TOOLTIP :{BLACK}Amserlen - cliciwch ar orchymyn i'w amlygu STR_TIMETABLE_NO_TRAVEL :Dim teithio STR_TIMETABLE_NOT_TIMETABLEABLE :Teithio (awtomatig; amserlennir gan y gorchymyn defnyddiwr nesaf) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Teithio (heb ei amserlenu) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Teithio heb oresgyn {2:VELOCITY} (heb ei amserlenu) STR_TIMETABLE_TRAVEL_FOR :Teithio am{STRING} STR_TIMETABLE_TRAVEL_FOR_SPEED :Teithio am {STRING} heb oresgyn {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Teithio (am {STRING}, heb ei amserlennu) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Teitho (am {STRING}, heb ei amserlennu) dim cyflymach na {VELOCITY} STR_TIMETABLE_STAY_FOR_ESTIMATED :(aros am {STRING}, heb ei amserlennu) STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(teitiho am {STRING}, heb ei amserlennu) STR_TIMETABLE_STAY_FOR :aros am {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :a theithio am {STRING} STR_TIMETABLE_DAYS :{COMMA}{NBSP}diwrnod STR_TIMETABLE_TICKS :{COMMA}{NBSP}tic STR_TIMETABLE_TOTAL_TIME :{BLACK}Bydd yr amserlen hon yn cymryd {STRING} i'w chwblhau STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}Bydd yr amserlen hon yn cymryd o leiaf {STRING} i'w chwblhau (heb ei hamserlennu'n llwyr) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}Mae'r cerbyd hwn yn rhedeg ar amser ar hyn o bryd STR_TIMETABLE_STATUS_LATE :{BLACK}Mae'r cerbyd hwn yn rhedeg {STRING} yn hwyr ar hyn o bryd STR_TIMETABLE_STATUS_EARLY :{BLACK}Mae'r cerbyd hwn yn rhedeg {STRING} yn gynnar ar hyn o bryd STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}Nid yw'r amserlen yma wedi dechrau STR_TIMETABLE_STATUS_START_AT :{BLACK}Bydd yr amserlen yma'n dechrau ar {STRING} STR_TIMETABLE_STARTING_DATE :{BLACK}Dyddiad dechrau STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Dewis dyddiad fel pwynt dechrau ar gyfer yr amserlen yma. Mae Ctrl+Clic yn gosod pwynt dechrau yr amselen yma ac yn dosbarthu'r holl gerbydau sy'n rhannu'r gorchymyn yma yn gyson yn ôl eu trefn cymharol, os yw'r gorchymyn wedi ei amserlennu'n llwyr STR_TIMETABLE_CHANGE_TIME :{BLACK}Newid Amser STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Newid faint o amser y dylai'r gorchymyn a amlygwyd ei gymryd STR_TIMETABLE_CLEAR_TIME :{BLACK}Clirio Amser STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clirio faint o amser y dylai'r gorchymyn a amlygwyd ei gymryd. STR_TIMETABLE_CHANGE_SPEED :{BLACK}Newid Terfyn Cyflymder STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Newid cyflymder teithio uchafsymol y gorchymyn a amlygwyd STR_TIMETABLE_CLEAR_SPEED :{BLACK}Clirio Terfyn Cyflymder STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clirio cyflymder teithio uchafsymol y gorchymyn a amlygwyd STR_TIMETABLE_RESET_LATENESS :{BLACK}Ailosod Mesurydd Hwyrni STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Ailosod y mesurydd hwyrni, fel y bydd y cerbyd ar amser STR_TIMETABLE_AUTOFILL :{BLACK}Awtolenwi STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Llenwch yr amserlen yn awtomatig gyda gwerthoedd o'r daith nesaf (Ctrl+Clic er mwyn ceisio cadw amserau aros) STR_TIMETABLE_EXPECTED :{BLACK}Disgwylir STR_TIMETABLE_SCHEDULED :{BLACK}Amserlenwyd STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Newid rhwng yr amser a ddisgwylir a'r amserlen STR_TIMETABLE_ARRIVAL_ABBREVIATION :Cyr: STR_TIMETABLE_DEPARTURE_ABBREVIATION :Gad: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}Gosod dyddiad STR_DATE_SET_DATE :{BLACK}Gososd dyddiad STR_DATE_SET_DATE_TOOLTIP :{BLACK}Defnyddio'r dyddiad a ddewisir fel dyddiad dechrau ar gyfer yr amserlen STR_DATE_DAY_TOOLTIP :{BLACK}Dewis diwrnod STR_DATE_MONTH_TOOLTIP :{BLACK}Dewis mis STR_DATE_YEAR_TOOLTIP :{BLACK}Dewis blwyddyn # AI debug window STR_AI_DEBUG :{WHITE}Dadnamu AI / Sgript Gêm STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Enw'r sgript STR_AI_DEBUG_SETTINGS :{BLACK}Gosodiadau STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Newid gosodiadau'r sgript STR_AI_DEBUG_RELOAD :{BLACK}Ail-lwytho AI STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}lladd yr AI, ail-lwytho'r sgript ac ailgychwyn yr AI STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Galluogi/analluogi toriadau pan fo neges log AI yn cydweddu a'r llinyn torri STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Torri ar: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Torri ar STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Pan fo neges log AI yn cydweddu a'r llinyn yma, bydd y gêm yn oedi STR_AI_DEBUG_MATCH_CASE :{BLACK}Cydweddu priflythrennu STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Toglo cydweddu priflythrennu tra'n cymharu negeseuon log AI gyda'r llinyn torri STR_AI_DEBUG_CONTINUE :{BLACK}Parhau STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Dadoedi a rhedeg yr AI STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Gweld allbwn dadnamu'r AI yma STR_AI_GAME_SCRIPT :{BLACK}Game Script STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Gwirio'r log Game Script STR_ERROR_AI_NO_AI_FOUND :Ni ganfuwyd AI addas i lwytho.{}AI ffug yw hwn na wnai unrhyw beth.{}Gallwch lawrlwytho sawl AI drwy'r system 'Cynnwys Arlein' STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}Mae sgript a oedd yn rhedeg wedi chwalu. A fyddwch cystad ag adrodd am hyn i awdur yr sgript ynghyd â sgrin-gipiad o'r Ffenestr Ddadnamu AI/Sgript Gêm STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}Mae'r Ffenestr Ddadnamu AI / Sgript Gêm ar gael ar gyfer y gweinydd yn unig # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}Ffurfweddiad AI / Sgript Gêm STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}Y Sgriptiau Gêm a lwythir yn y gêm nesaf STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}Yr AIau a lwythir yn y gêm nesaf STR_AI_CONFIG_HUMAN_PLAYER :Chwaraewr dynol STR_AI_CONFIG_RANDOM_AI :AI ar hap STR_AI_CONFIG_NONE :(dim) STR_AI_CONFIG_MOVE_UP :{BLACK}Symud i Fyny STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Symud yr AI a ddewiswyd i fyny'r rhestr STR_AI_CONFIG_MOVE_DOWN :{BLACK}Symud i Lawr STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Symud yr AI a ddewiswyd i lawr y rhestr STR_AI_CONFIG_GAMESCRIPT :{SILVER}Sgript Gêm STR_AI_CONFIG_AI :{SILVER}AIau STR_AI_CONFIG_CHANGE :{BLACK}Dewis {STRING} STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :AI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Sgript Gêm STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Llwytho sgript arall STR_AI_CONFIG_CONFIGURE :{BLACK}Ffurfweddu STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}ffurfweddu paramedrau'r sgript # Available AIs window STR_AI_LIST_CAPTION :{WHITE}{STRING} ar gael STR_AI_LIST_CAPTION_AI :AIau STR_AI_LIST_CAPTION_GAMESCRIPT :Sgriptiau Gêm STR_AI_LIST_TOOLTIP :{BLACK}Cliciwch i ddewis sgript STR_AI_LIST_AUTHOR :{LTBLUE}Awdur: {ORANGE}{STRING} STR_AI_LIST_VERSION :{LTBLUE}Fersiwn: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{STRING} STR_AI_LIST_ACCEPT :{BLACK}Derbyn STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Dewis y sgript a amlygwyd STR_AI_LIST_CANCEL :{BLACK}Canslo STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Peidio newid y sgript # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Paramedrau STR_AI_SETTINGS_CAPTION_AI :AI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Sgript Gêm STR_AI_SETTINGS_CLOSE :{BLACK}Cau STR_AI_SETTINGS_RESET :{BLACK}Ailosod STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} STR_AI_SETTINGS_START_DELAY :Nifer o ddiwrnodau i aros wedi dechrau AI blaenorol cyn dechrau hon (fwy neu lai): {ORANGE}{STRING} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}Dogfenyddiaeth {STRING} {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}Log newidiadau {STRING} {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}Trwydded {STRING} {STRING} STR_TEXTFILE_WRAP_TEXT :{WHITE}Amlapio testun STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Amlapio testun y ffenestr fel ei fod i'w weld heb sgrolio STR_TEXTFILE_VIEW_README :{BLACK}Gweld dogfenyddiaeth STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Log Newidiadau STR_TEXTFILE_VIEW_LICENCE :{BLACK}Trwydded # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Cost: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}Cost: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Incwm: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}Incwm: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Trosglwyddo: {CURRENCY_LONG} STR_FEEDER :{YELLOW}Trosglwyddo: {CURRENCY_LONG} STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Trosglwyddo: {CURRENCY_LONG}{WHITE} / {GREEN}Incwm: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}Trosglwyddo: {CURRENCY_LONG}{WHITE} / {GREEN}Incwm: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Trosglwyddo: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} STR_FEEDER_COST :{YELLOW}Trosglwyddo: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Amcangyfrif Côst: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Amcangyfrif Incwm: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Mae'r gêm wrthi'n cael ei chadw,{}Arhoswch nes y bydd y broses wedi'i chwblhau! STR_ERROR_AUTOSAVE_FAILED :{WHITE}Methodd yr Awtogadw STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Methu darllen y gyriant STR_ERROR_GAME_SAVE_FAILED :{WHITE}Methwyd â Chadw Gêm{}{STRING} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Methu Dileu Ffeil STR_ERROR_GAME_LOAD_FAILED :{WHITE}Methwyd â Llwytho Gêm{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Gwall mewnol: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Mae'r gêm a gadwyd wedi torri - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Mae'r gêm a gadwyd wedi ei chadw mewn fersiwn ddiweddarach STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Ffeil annarllenadwy STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Ffeil anysgrifenadwy STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Methodd y gwirio cyfanrwydd data STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Cafodd y gêm ei gadw mewn fersiwn heb gynhaliaeth tramiau. Dileuwyd y tramiau # Map generation messages STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Ataliwyd creu map...{}... nid oedd lleoliadau addas ar gyfer trefi STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... nid oes tref yn y senario hwn STR_ERROR_PNGMAP :{WHITE}Methwyd llwytho tirwedd o PNG... STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... ni ganfuwyd y ffeil STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... nid oedd modd trosi math y ddelwedd. Rhaid cael delwedd PNG 8 neu 24-did. STR_ERROR_PNGMAP_MISC :{WHITE}... aeth rhywbeth o'i le (ffeil lygredig fwy na thebyg) STR_ERROR_BMPMAP :{WHITE}Methu llwytho delwedd o BMP... STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... ni fu modd trosi math y ddelwedd STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... delwedd yn rhy fawr STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Rhybudd Graddfa STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Ni argymhellir newid gormod ar faint y map gwreiddiol. Parhau gyda'r cynhyrchu? # Soundset messages STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Dim ond set sain wrth gefn a ganfuwyd. Os ydych am gael sain, llawrlwythwch set sain drwy'r system llawrlwytho cynnwys # Screenshot related messages STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Ciplun anferth STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}Bydd gan y ciplun faint o {COMMA} x {COMMA} pcsel. Gall cymeryd peth amser i greu'r ciplun. A ydych am barhau? STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Cadwyd y ciplun yn llwyddiannus fel '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}Methodd y ciplun! # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Neges STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Neges gan {STRING} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Oddi ar ymyl y map STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Rhy agos i ymyl y map STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Dim digon o arian - angen {CURRENCY_LONG} STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Rhaid i'r tir fod yn wastad STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Mae'r tir yn goleddu i'r cyfeiriad anghywir STR_ERROR_CAN_T_DO_THIS :{WHITE}Does dim modd gwneud hynny... STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Rhaid dymchwel adeilad yn gyntaf STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Does dim modd clirio’r ardal hon... STR_ERROR_SITE_UNSUITABLE :{WHITE}... safle anaddas STR_ERROR_ALREADY_BUILT :{WHITE}... eisoes wedi'i adeiladu STR_ERROR_OWNED_BY :{WHITE}... eiddo {STRING} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... mae'r ardal yn eiddo i gwmni arall STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... wedi cyrraedd y diben tirffurfio STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... diben clirio teiliau wedi ei gyrraedd STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... wedi cyrraedd y diben planu coed STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Rhaid i'r enw fod yn unigryw STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} yn y ffordd STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Ni chaniateir hynny tra fo'r gêm wedi ei oedi # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}Nid yw awdurdod lleol {TOWN} yn caniatáu hyn STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}Mae awdurdod lleol {TOWN} yn gwrthod caniatáu i faes awyr arall gael ei adeiladu ger y dref hon STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}Mae awdurdod lleol {TOWN} wedi gwrthod caniatâd ar gyfer maes awyr oherwydd pryderon ynglŷn â sŵn STR_ERROR_BRIBE_FAILED :{WHITE}Cawsoch eich dal gan ymchwilydd rhanbarth wrth geisio llwgrwobrwyo # Levelling errors STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}Does dim modd codi tir yma... STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Does dim modd gostwng tir yma... STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Does dim modd lefelu tir yma... STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Byddai cloddio yno'n difrodi twnnel STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... eisoes ar lefel y môr STR_ERROR_TOO_HIGH :{WHITE}Rhy uchel STR_ERROR_ALREADY_LEVELLED :{WHITE}... mae eisoes yn fflat STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND :{WHITE}Byddai'r bont wedyn yn rhy uchel. # Company related errors STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Does dim modd newid enw'r cwmni... STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Does dim modd newid enw'r rheolwr... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... mae'r uchafswm benthyciad posib yn {CURRENCY_LONG} STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Does dim modd i chi fenthyg rhagor o arian... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... nid oes benthyciad i'w ad-dalu STR_ERROR_CURRENCY_REQUIRED :{WHITE}... angen {CURRENCY_LONG} STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Does dim modd ad-dalu benthyciad... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Does dim modd rhoi arian sydd wedi ei fenthyg gan y banc i ffwrdd... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Methu prynu cwmni... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Methu adeiladu pencadlys cwmni... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Methu prynu cyfran o 25% o'r cwmni hwn... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Methu gwerthu cyfran o 25% o'r cwmni ... STR_ERROR_PROTECTED :{WHITE}Nid yw'r cwmni hwn yn ddigon da ar gyfer cyfnewid cyfrandaliadau eto... # Town related errors STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Methu adeiladu unrhyw drefi STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Methu ailenwi tref... STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Methu adeiladu tref yma... STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Methu ehangu'r dref... STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... rhy agos i ymyl y map STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... rhy agos i dref arall STR_ERROR_TOO_MANY_TOWNS :{WHITE}... gormod o drefi STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... nid oes mwy o le ar y map STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}Ni fydd y dref yn adeiladu ffyrdd. Gallwch alluogi adeiladu ffyrdd yn Gosodiadau->Amgylchedd->Trefi STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Mae gwaith yn cael ei wneud ar y ffordd STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Methu dileu'r dref...{}Mae gorsaf neu depo sy'n cyfeirio i'r dref neu deil ym mherchnogaeth y dref na ellir ei ddileu STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... nid oes man addas i'r cerflun yn nghanol y ddinas yma # Industry related errors STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... gormod o ddiwydiannau STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Doedd dim modd cynhyrchu diwydiannau... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Ni ellir adeiladu {STRING} yma... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Does dim modd adeiladu diwydiant o'r math hwn yma... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... rhy agos i ddiwydiant arall STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... rhaid adeiladu tref yn gyntaf STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... un yn unig a ganiateir ym mhob tref STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... gellir ei adeiladu'n unig mewn trefi gyda phoblogaeth o 1200 neu fwy STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... gellir ei adeiladu mewn ardal coedwig glaw yn unig STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... gellir ei adeiladu mewn ardal anialwch yn unig STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... gellir ei adeiladu mewn trefi'n unig (gan ddisodli tai) STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... gellir ei adeiladu ger canol trefi'n unig STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... gellir ei adeiladu mewn manau isel yn unig STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... dim ond ger ymyl y map y gellir ei leoli STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... dim ond uwch ben y llinell eira mae modd plannu fforest STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... gellir ei adeiladu uwchben yr eirlin yn unig STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... gellir ei adeiladu islaw i'r eirlin yn unig STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Nid oedd manau addas ar gyfer diwydiannau '{STRING}' STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Newidwch y paramedrau cynhyrchu map er mwyn cael map gwell # Station construction related errors STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Methu adeiladu gorsaf reilffordd yma... STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Methu adeiladu gorsaf fysiau... STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Methu adeiladu gorsaf lorïau... STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Methu adeiladu gorsaf tramiau teithwyr... STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Methu adeiladu gorsaf tramiau nwyddau... STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Methu adeiladu doc yma... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Methu adeiladu maes awyr yma... STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Mae'n ymylu ar fwy nag un gorsaf/ardal lwytho sydd eisoes yn bodoli STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... mae'r orsaf yn rhy wasgaredig STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Gormod o orsafoedd/ardaloedd llwytho STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Mae gan yr orsaf ormod o rannau STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Gormod o arosfannau bysus STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Gormod o orsafoedd lorïau STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Rhy agos i orsaf/ardal lwytho STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Rhy agos i ddoc arall STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Rhy agos i faes awyr arall STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Methu ailenwi gorsaf... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... mae'r ffordd hon yn eiddo i dref STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... mae'r ffordd yn gorwedd yn y cyfeiriad anghywir STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... ni all arosfannau gyrru-trwodd fod â chorneli STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... ni all arosfannau gyrru-trwodd fod â chyffyrdd # Station destruction related errors STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Methu tynnu rhan o orsaf... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Rhaid dymchwel yr orsaf yn gyntaf STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Methu dileu gorsaf fysiau... STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Methu dileu gorsaf lorïau... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Methu dileu gorsaf tramiau teithwyr... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Methu dileu gorsaf tramiau nwyddau... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Rhaid tynnu'r arhosfan ffordd gyntaf STR_ERROR_THERE_IS_NO_STATION :{WHITE}... nid oes gorsaf yma STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Rhaid dymchwel gorsaf reilffordd yn gyntaf STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Rhaid dymchwel gorsaf fysiau yn gyntaf STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Rhaid dymchwel gorsaf lorïau yn gyntaf STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Rhaid dileu gorsaf tramiau teithwyr yn gyntaf STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Rhaid dymchwel yr orsaf tramiau nwyddau'n gyntaf STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Rhaid dymchwel doc yn gyntaf STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Rhaid dymchwel maes awyr yn gyntaf # Waypoint related errors STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Cyfagos â mwy nag un pwynt llwybro STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Rhy agos at bwynt llwybro arall STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Does dim modd adeiladu pwynt llwybro trên yma... STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Methu gosod bwï yma... STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Does dim modd newid enw pwynt llwybro... STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Does dim modd tynnu'r pwynt llwybro trên yma... STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Rhaid tynnu'r pwynt llwybro rheilffordd yn gyntaf STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... bwï yn y ffordd STR_ERROR_BUOY_IS_IN_USE :{WHITE}... bwï mewn defnydd gan cwmni arall! # Depot related errors STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Methu adeiladu trên depo yma... STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Methu adeiladu depo cerbydau ffordd yma... STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Methu adeiladu depo cerbyd tramiau yma... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Methu adeiladu depo llong yma... STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Methu ailenwi depo... STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... nid yw wedi'i stopio mewn depo STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... nid yw wedi'i stopio mewn depo STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... nid yw wedi'i stopio mewn depo STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... nid yw wedi'i stopio mewn awyrendy STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Gellir newid trenau yn unig pan fyddan nhw wedi stopio tu mewn i ddepo STR_ERROR_TRAIN_TOO_LONG :{WHITE}Trên yn rhy hir STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Methu gwrthdroi'r cerbyd... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... mae'n cynnwys sawl uned STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Mathau rheilffordd anghydnaws STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Methu symud y cerbyd... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}Bydd yr injan ôl wastad yn dilyn ei gymar blaen STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Methu dod o hyd i ffordd i'r depo lleol STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Methu dod o hyd i'r depo lleol STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :math depo anghywir # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}Aeth gormod o amser heibio i allu adnewyddu {VEHICLE} STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Ni weithredwyd unrhyw reolau awtogyfnewid/adnewyddu STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(terfyn arian) # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Cyfuniad trac amhosib STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Rhaid tynnu signalau yn gyntaf STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Dim trac rheilffordd addas STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Rhaid tynnu'r trac rheilffordd yn gyntaf STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Mae'r ffordd yn ffordd un-ffordd, neu wedi'i blocio STR_ERROR_CROSSING_DISALLOWED :{WHITE}Ni chaniateir croesfannau ar y cledrau yma STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Methu adeiladu signalau yma... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Methu adeiladu trac rheilffordd yma... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Methu tynnu trac rheilffordd oddi yma... STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Methu tynnu signalau oddi yma... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Methu trosi signalau yma... STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... nid oes cledrau yno STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... nid oes signalau STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Methu trosi'r math rheilffordd yma... # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Rhaid clirio'r ffordd yn gyntaf STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... ni ellir cael cyffyrdd ar ffyrdd un-ffordd STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Methu adeiladu ffordd yma... STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Methu adeiladu tramffordd yma... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Methu clirio'r ffordd oddi yma... STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Methu dileu tramffordd oddi yma... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... nid oes ffordd yno STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... nid oes tramffordd yno # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Methu adeiladu camlesi yma... STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Methu adeiladu lociau yma... STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Methu gosod afonydd yma... STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... rhaid ei adeiladu ar ddŵr STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... methu adeiladu ar ddŵr STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... methu adeiladu ynghanol y môr STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... methu adeiladu ar gamlas STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... methu adeiladu ar afon STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Rhaid dymchwel camlas yn gyntaf STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Methu adeiladu traphont yma... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... coeden eisoes yma STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... tirwedd anghywir ar gyfer y math o goeden STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Methu plannu coeden yma... # Bridge related errors STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Methu adeiladu pont yma... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Rhaid dymchwel pont yn gyntaf STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Does dim modd cychwyn a gorffen yn yr un man STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Nid yw dau ben y bont ar yr un lefel STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Mae'r bont yn rhy isel ar gyfer y tirwedd STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN :{WHITE}Pont rhy uchel ar gyfer y tirwedd yma. STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Rhaid i'r cychwyn a'r diwedd fod mewn llinell STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... rhaid i ddau ben y bont orffwys ar y tir STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... pont rhy hir STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Byddai'r bont yn gorffen y tu allan i'r map # Tunnel related errors STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Methu adeiladu twnnel yma... STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Mae'r safle'n anaddas ar gyfer mynedfa twnnel STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Rhaid dymchwel twnnel yn gyntaf STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}mae twnnel arall yn y ffordd STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Byddai'r twnel yn gorffen y tu allan i'r map STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Does dim modd cloddio'r tir ar ben arall y twnnel STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... twnel rhy hir # Object related errors STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... gormod o wrthrychau STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Methu adeiladu gwrthrych... STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Gwrthrych yn y ffordd STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... pencadlys cwmni yn y ffordd STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Does dim modd prynu'r darn yma o dir... STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... rydych chi eisoes yn berchen arno! # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Methu creu grŵp STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Methu dileu'r grŵp hwn... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Methu ailenwi'r grŵp... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Methu gosod grŵp rhiant... STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Methu dileu pob cerbyd o'r grŵp hwn... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Methu ychawnegu'r cerbyd i'r grŵp hwn... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Methu ychwanegu cerbyd a rennir i'r grŵp... # Generic vehicle errors STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Trên yn y ffordd STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Cerbyd ffordd yn y ffordd STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Llong yn y ffordd STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Awyren yn y ffordd STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Methu ailffitio trên... STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Methu ailffitio cerbyd ffordd... STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Methu ailffitio llong... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Methu ailffitio awyren... STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Methu enwi trên... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Methu enwi cerbyd ffordd... STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Methu enwi llong... STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Methu enwi awyren... STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Methu cychwyn/stopio trên... STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Methu aros/dechrau'r cerbyd ffordd... STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}methu cychwyn/stopio llong... STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Methu stopio/cychwyn awyren... STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Methu gyrru trên i depo... STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Methu gyrru cerbyd i'r depo... STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Methu gyrru llong i ddepo... STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Methu gyrru awyren i awyrendy... STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Methu prynnu cerbyd rheilffordd... STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Methu prynnu cerbyd ffordd... STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Methu prynnu llong... STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Methu prynnu awyren... STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Methu ailenwi math y cerbyd trên... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Methu ailenwi cerbyd ffordd... STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Methu ailenwi math llong... STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Methu ailenwi'r math awyren... STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Methu gwerthu cerbyd rheilffordd... STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Methu gwerthu cerbyd ffordd... STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Methu gwerthu llong... STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}methu gwerthu awyren... STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Nid yw'r cerbyd ar gael STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Nid yw'r cerbyd ar gael STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Nid yw'r llong ar gael STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Nid yw'r awyren ar gael STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Mae gormod o gerbydau yn y gêm STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Methu newid hyd y cyfnod rhwng pob gwasanaeth... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... cerbyd wedi ei ddinistrio STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Ni fydd cerbydau ar gael o gwbl STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Newid eich ffurfweddiad NewGRF STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Dim cerbydau ar gael eto STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Dechreuwch gêm newydd wedi {DATE_SHORT} neu defnyddiwch NewGRF sy'n darparu cerbydau cynnar # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Does dim modd gwneud i drên basio signal pan fo perygl... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Methu gwrthdroi'r trên... STR_ERROR_TRAIN_START_NO_POWER :Mae'r trên heb bŵer STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Methu troi'r cerbyd... STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}mae'r awyren yn hedfan # Order related errors STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Dim mwy o le ar gyfer gorchmynion STR_ERROR_TOO_MANY_ORDERS :{WHITE}Gormod o orchmynion STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Methu ychwanegu gorchymyn newydd... STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Methu dileu'r gorchymyn hwn... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Methu newid y gorchymyn hwn... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Methu symud y gorchymyn hwn... STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Methu hepgor y gorchymyn cyfredol... STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Does dim modd hepgor y gorchymyn a ddewiswyd... STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... ni all y cerbyd fynd i bob gorsaf STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... ni all y cerbyd fynd i'r orsaf honno STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... ni all cerbyd sy'n rhannu'r gorchymyn hwn fynd i'r orsaf honno STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Does dim modd rhannu'r rhestr gorchmynion... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Methu rhoi'r gorau i rannu rhestr gorchmynion... STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Does dim modd copïo'r rhestr gorchmynion... STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... rhy bell o'r gyrchfan flaenorol STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... nid yw o fewn cyrraedd yr awyren # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Methu amserlennu cerbyd... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Dim ond mewn gorsafoedd y gall cerbydau aros STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Nid yw'r cerbyd hwn yn galw yn yr orsaf hon # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... gormod o arwyddion STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Methu gosod arwydd yma... STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Methu newid enw arwydd... STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Methu dileu arwydd... # Translatable comment for OpenTTD's desktop shortcut STR_DESKTOP_SHORTCUT_COMMENT :Gêm efelychu wedi ei seilio ar Transport Tycoon Deluxe # Translatable descriptions in media/baseset/*.ob* files STR_BASEGRAPHICS_DOS_DESCRIPTION :Graffeg gwreiddiol fersiwn DOS o Transport Tycoon Deluxe. STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Graffeg gwreiddiol fersiwn DOS (Almaenig) o Transport Tycoon Deluxe. STR_BASEGRAPHICS_WIN_DESCRIPTION :Graffeg gwreiddiol fersiwn Windows o Transport Tycoon Deluxe. STR_BASESOUNDS_DOS_DESCRIPTION :Effeithiau sain gwreiddiol fersiwn DOS o Transport Tycoon Deluxe. STR_BASESOUNDS_WIN_DESCRIPTION :Effeithiau sain gwreiddiol fersiwn Windows o Transport Tycoon Deluxe. STR_BASESOUNDS_NONE_DESCRIPTION :Pecyn sain heb unrhyw effeithiau sain ynddo. STR_BASEMUSIC_WIN_DESCRIPTION :Cerddoriaeth gwreiddiol fersion Windows o Transport Tycoon Deluxe. STR_BASEMUSIC_NONE_DESCRIPTION :Pecyn cerddoriaeth heb unrhyw gerddoriaeth ynddo. ##id 0x2000 # Town building names STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Bloc swyddfa uchel STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Bloc swyddfa STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Bloc bach o fflatiau STR_TOWN_BUILDING_NAME_CHURCH_1 :Eglwys STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Bloc swyddfa mawr STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Tai tref STR_TOWN_BUILDING_NAME_HOTEL_1 :Gwesty STR_TOWN_BUILDING_NAME_STATUE_1 :Cerflun STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Pistyll STR_TOWN_BUILDING_NAME_PARK_1 :Parc STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Bloc swyddfa STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Swyddfeydd a siopau STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Adeilad swyddfa modern STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Warws STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Bloc swyddfa STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadiwm STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Hen dai STR_TOWN_BUILDING_NAME_COTTAGES_1 :Bythynnod STR_TOWN_BUILDING_NAME_HOUSES_1 :Tai STR_TOWN_BUILDING_NAME_FLATS_1 :Fflatiau STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Bloc swyddfa uchel STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Swyddfeydd a siopau STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Swyddfeydd a siopau STR_TOWN_BUILDING_NAME_THEATER_1 :Theatr STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadiwm STR_TOWN_BUILDING_NAME_OFFICES_1 :Swyddfeydd STR_TOWN_BUILDING_NAME_HOUSES_2 :Tai STR_TOWN_BUILDING_NAME_CINEMA_1 :Sinema STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Canolfan Siopa STR_TOWN_BUILDING_NAME_IGLOO_1 :Iglw STR_TOWN_BUILDING_NAME_TEPEES_1 :Tipi STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Tŷ Tebot STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Cadwmigei ##id 0x4800 # industry names STR_INDUSTRY_NAME_COAL_MINE :Glofa STR_INDUSTRY_NAME_POWER_STATION :Gorsaf Bŵer STR_INDUSTRY_NAME_SAWMILL :Melin Goed STR_INDUSTRY_NAME_FOREST :Coedwig STR_INDUSTRY_NAME_OIL_REFINERY :Purfa Olew STR_INDUSTRY_NAME_OIL_RIG :Rig Olew STR_INDUSTRY_NAME_FACTORY :Ffatri STR_INDUSTRY_NAME_PRINTING_WORKS :Gwaith Argraffu STR_INDUSTRY_NAME_STEEL_MILL :Melin Ddur STR_INDUSTRY_NAME_FARM :Fferm STR_INDUSTRY_NAME_COPPER_ORE_MINE :Cloddfa Gopr STR_INDUSTRY_NAME_OIL_WELLS :Ffynhonnau Olew STR_INDUSTRY_NAME_BANK :Banc STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Gwaith Prosesu Bwyd STR_INDUSTRY_NAME_PAPER_MILL :Melin Bapur STR_INDUSTRY_NAME_GOLD_MINE :Cloddfa Aur STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Banc STR_INDUSTRY_NAME_DIAMOND_MINE :Cloddfa Diemwntau STR_INDUSTRY_NAME_IRON_ORE_MINE :Cloddfa Haearn STR_INDUSTRY_NAME_FRUIT_PLANTATION :Planhigfa Ffrwythau STR_INDUSTRY_NAME_RUBBER_PLANTATION :Planhigfa Rwber STR_INDUSTRY_NAME_WATER_SUPPLY :Ffynhonell Ddŵr STR_INDUSTRY_NAME_WATER_TOWER :Storfa Ddŵr STR_INDUSTRY_NAME_FACTORY_2 :Ffatri STR_INDUSTRY_NAME_FARM_2 :Fferm STR_INDUSTRY_NAME_LUMBER_MILL :Melin Goed STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :Coedwig Candifflos STR_INDUSTRY_NAME_CANDY_FACTORY :Ffatri Felysion STR_INDUSTRY_NAME_BATTERY_FARM :Fferm Fatrïau STR_INDUSTRY_NAME_COLA_WELLS :Ffynhonnau Cola STR_INDUSTRY_NAME_TOY_SHOP :Siop Deganau STR_INDUSTRY_NAME_TOY_FACTORY :Ffatri Deganau STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :Ffynhonnau Plastig STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :Ffatri Ddŵr Pefriol STR_INDUSTRY_NAME_BUBBLE_GENERATOR :Cynhyrchydd Swigod STR_INDUSTRY_NAME_TOFFEE_QUARRY :Chwarel Doffi STR_INDUSTRY_NAME_SUGAR_MINE :Cloddfa Siwgr ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Dienw STR_SV_TRAIN_NAME :Trên {COMMA} STR_SV_ROAD_VEHICLE_NAME :Cerbyd Ffordd {COMMA} STR_SV_SHIP_NAME :Llong {COMMA} STR_SV_AIRCRAFT_NAME :Awyren {COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :Gogledd {STRING} STR_SV_STNAME_SOUTH :De {STRING} STR_SV_STNAME_EAST :Dwyrain {STRING} STR_SV_STNAME_WEST :Gorllewin {STRING} STR_SV_STNAME_CENTRAL :Canol {STRING} STR_SV_STNAME_TRANSFER :Cyffordd {STRING} STR_SV_STNAME_HALT :Terfynfa {STRING} STR_SV_STNAME_VALLEY :{STRING} Isaf STR_SV_STNAME_HEIGHTS :{STRING} Uchaf STR_SV_STNAME_WOODS :Coed {STRING} STR_SV_STNAME_LAKESIDE :Glan {STRING} STR_SV_STNAME_EXCHANGE :Cyfnewidfa {STRING} STR_SV_STNAME_AIRPORT :Maes Awyr {STRING} STR_SV_STNAME_OILFIELD :Maes Olew {STRING} STR_SV_STNAME_MINES :Mwynglawdd {STRING} STR_SV_STNAME_DOCKS :Dociau {STRING} STR_SV_STNAME_BUOY :{STRING} STR_SV_STNAME_WAYPOINT :{STRING} ##id 0x6020 STR_SV_STNAME_ANNEXE :Rhandre {STRING} STR_SV_STNAME_SIDINGS :Cilffordd {STRING} STR_SV_STNAME_BRANCH :Cangen {STRING} STR_SV_STNAME_UPPER :Blaenau {STRING} STR_SV_STNAME_LOWER :Dyffryn {STRING} STR_SV_STNAME_HELIPORT :Hofrenyddborth {STRING} STR_SV_STNAME_FOREST :Coedwig {STRING} STR_SV_STNAME_FALLBACK :{STRING} Gorsaf #{NUM} ############ end of savegame specific region! ##id 0x8000 # Vehicle names STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Injan Danc Kirby Paul (Stêm) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (Stêm) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Stêm) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (Stêm) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (Stêm) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (Trydan) STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Cerbyd Teithwyr STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Cerbyd Post STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Cerbyd Glo STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Tancer Olew STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Cerbyd Da Byw STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Cerbyd Nwyddau STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Cerbyd Grawn STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Cerbyd Coed STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Cerbyd Mwyn Haearn STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Cerbyd Dur STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Cerbyd Diogel STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Cerbyd Bwyd STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Cerbyd Papur STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Cerbyd Mwyn Copr STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Tancer Dŵr STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Cerbyd Ffrwythau STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Cerbyd Rwber STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Cerbyd Siwgr STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Cerbyd Candifflos STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Cerbyd Toffi STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Cerbyd Swigod STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Cerbyd Cola STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Cerbyd Melysion STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Cerbyd Teganau STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Cerbyd Batrïau STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Cerbyd Diodydd Pefriol STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Cerbyd Plastig STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Cerbyd Teithwyr STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Cerbyd Post STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Cerbyd Glo STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Tancer Olew STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Cerbyd Da Byw STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Cerbyd Nwyddau STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Cerbyd Grawn STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Cerbyd Coed STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Cerbyd Mwyn Haearn STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Cerbyd Dur STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :Cerbyd Diogel STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Cerbyd Bwyd STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Cerbyd Papur STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Cerbyd Mwyn Copr STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Cerbyd Dŵr STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Cerbyd Ffrwythau STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Cerbyd Rwber STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Cerbyd Siwgr STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Cerbyd Candifflos STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Cerbyd Toffi STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Cerbyd Swigod STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Tancer Cola STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Cerbyd Melysion STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Cerbyd Teganau STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Cerbyd Batrïau STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Cerbyd Diodydd Pefriog STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Cerbyd Plastig STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Trydan) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Cerbyd Teithwyr STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Cerbyd Post STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Cerbyd Glo STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Tancer Olew STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Cerbyd Da Byw STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Cerbyd Nwyddau STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Cerbyd Grawn STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Cerbyd Coed STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Cerbyd Mwyn Haearn STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Cerbyd Dur STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Cerbyd Diogel STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Cerbyd Bwyd STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Cerbyd Papur STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Cerbyd Mwyn Copr STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Cerbyd Dŵr STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Cerbyd Ffrwythau STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Cerbyd Rwber STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Cerbyd Siwgr STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Cerbyd Candifflos STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Cerbyd Toffi STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Cerbyd Swigod STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Tancer Cola STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Cerbyd Melysion STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Cerbyd Teganau STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Cerbyd Batrïau STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Cerbyd Diodydd Pefriog STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Cerbyd Plastig STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :Bws MPS Regal STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Bws Leopard Hereford STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Bws Foster STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Hyperfws Foster MkII STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Bws Ploddyphut MkI STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :BwsPloddyphut MkII STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Bws Ploddyphut MkIII STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Cerbyd Glo Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Cerbyd Glo Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :Cerbyd Glo DW STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :Cerbyd Post MPS STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Cerbyd Post Reynard STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Cerbyd Post Perry STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :Cerbyd Post MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Cerbyd Post Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Cerbyd Post Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Tancer Olew Witcombe STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Tancer Olew Foster STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Tancer Olew Perry STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Cerbyd Da Byw Talbott STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Cerbyd Da Byw Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Cerbyd Da Byw Foster STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Cerbyd Nwyddau Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Cerbyd Nwyddau Craighead STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Cerbyd Nwyddau Goss STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Cerbyd Grawn Hereford STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Cerbyd Grawn Thomas STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Cerbyd Grawn Goss STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Cerbyd Coed Witcombe STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Cerbyd Coed Foster STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Cerbyd Coed Moreland STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :Cerbyd Mwyn Haearn MPS STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Cerbyd Mwyn Haearn Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Cerbyd Mwyn Haearn Chippy STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Cerbyd Dur Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Cerbyd Dur Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Cerbyd Dur Kelling STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Cerbyd Diogel Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Cerbyd Diogel Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Cerbyd Diogel Foster STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Cerbyd Bwyd Foster STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Cerbyd Bwyd Perry STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Cerbyd Bwyd Chippy STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Cerbyd Papur Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Cerbyd Papur Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :Cerbyd Papur MPS STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :Cerbyd Mwyn Copr MPS STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Cerbyd Mwyn Copr Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Cerbyd Mwyn Copr Goss STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Tancer Dŵr Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Tancer Dŵr Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :Tancer Dŵr MPS STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Cerbyd Ffrwythau Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Cerbyd Ffrwythau Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Cerbyd Ffrwythau Kelling STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Cerbyd Rwber Balogh STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Cerbyd Rwber Uhl STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :Cerbyd Rwber RMT STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :Cerbyd Siwgr MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Cerbyd Siwgr Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Cerbyd Siwgr Wizzowow Cerbyd STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :Cerbyd Cola MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Cerbyd Cola Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Cerbyd Cola Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :Cerbyd Candifflos MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Cerbyd Candifflos Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Cerbyd Candifflos Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :Cerbyd Toffi MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Cerbyd Toffi Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Cerbyd Toffi Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :Cerbyd Teganau MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Cerbyd Teganau Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Cerbyd Teganau Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :Cerbyd Melysion MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Cerbyd Melysion Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Cerbyd Melysion Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :Cerbyd Batrïau MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Cerbyd Batrïau Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Cerbyd Batrïau Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :Cerbyd Diodydd Pefriog MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Cerbyd Diodydd Pefriog Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Cerbyd Diodydd Pefriog Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :Cerbyd Plastig MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Cerbyd Plastig Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Cerbyd Plastig Wizzowow STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :Cerbyd Swigod MightyMover STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Cerbyd Swigod Powernaught STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Cerbyd Swigod Wizzowow STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :Tancer Olew MPS STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :Tancer Olew CS-Inc. STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :Fferi Teithwyr MPS STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :Fferi Teithwyr FFP STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Hofrenfad Bakewell 300 STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Fferi Teithwyr Chugger-Chug STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Fferi Teithwyr Shivershake STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Llong Gargo Yate STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Llong Gargo Bakewell STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :Llong Gargo MightyMover STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Llong Gargo Powernaut STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Hofrennydd Tricario STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Hofrennydd Guru X2 STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Hofrennydd Powernaut ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{STRING}-{STRING}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} STR_FORMAT_DATE_ISO :{2:NUM}-{1:STRING}-{0:STRING} STR_FORMAT_BUOY_NAME :Bwï {TOWN} STR_FORMAT_BUOY_NAME_SERIAL :Bwï {TOWN} #{COMMA} STR_FORMAT_COMPANY_NUM :(Cwmni {COMMA}) STR_FORMAT_GROUP_NAME :Grŵp {COMMA} STR_FORMAT_INDUSTRY_NAME :{1:STRING} {0:TOWN} STR_FORMAT_WAYPOINT_NAME :Pwynt Llwybro {TOWN} STR_FORMAT_WAYPOINT_NAME_SERIAL :Pwynt Llwybro {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_TRAIN :Depo Trenau {TOWN} STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :Depo Trenau {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :Depo Ffordd {TOWN} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :Depo Ffordd {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_SHIP :Depo Llongau {TOWN} STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :Depo Llong {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_AIRCRAFT :Awyrendy {STATION} STR_UNKNOWN_STATION :gorsaf anhysbys STR_DEFAULT_SIGN_NAME :Arwydd STR_COMPANY_SOMEONE :rhywun STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING} STR_SAVEGAME_NAME_SPECTATOR :Gwyliwr, {1:STRING} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} STR_VIEWPORT_WAYPOINT :{WAYPOINT} STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} STR_COMPANY_NAME_COMPANY_NUM :{COMPANY}{COMPANY_NUM} STR_DEPOT_NAME :{DEPOT} STR_ENGINE_NAME :{ENGINE} STR_HIDDEN_ENGINE_NAME :{ENGINE} (cudd) STR_GROUP_NAME :{GROUP} STR_INDUSTRY_NAME :{INDUSTRY} STR_PRESIDENT_NAME :{PRESIDENT_NAME} STR_SIGN_NAME :{SIGN} STR_STATION_NAME :{STATION} STR_TOWN_NAME :{TOWN} STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} STR_JUST_DATE_LONG :{DATE_LONG} STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} # Slightly 'raw' stringcodes with colour or size STR_BLACK_COMMA :{BLACK}{COMMA} STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} STR_TINY_COMMA :{TINY_FONT}{COMMA} STR_BLUE_COMMA :{BLUE}{COMMA} STR_RED_COMMA :{RED}{COMMA} STR_WHITE_COMMA :{WHITE}{COMMA} STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} STR_TINY_GROUP :{TINY_FONT}{GROUP} STR_BLACK_INT :{BLACK}{NUM} STR_ORANGE_INT :{ORANGE}{NUM} STR_WHITE_SIGN :{WHITE}{SIGN} STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} STR_BLACK_STRING :{BLACK}{STRING} STR_BLACK_RAW_STRING :{BLACK}{STRING} STR_ORANGE_STRING :{ORANGE}{STRING} STR_LTBLUE_STRING :{LTBLUE}{STRING} STR_WHITE_STRING :{WHITE}{STRING} STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING}{WHITE} STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING}{LTBLUE} STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} STR_BLACK_1 :{BLACK}1 STR_BLACK_2 :{BLACK}2 STR_BLACK_3 :{BLACK}3 STR_BLACK_4 :{BLACK}4 STR_BLACK_5 :{BLACK}5 STR_BLACK_6 :{BLACK}6 STR_BLACK_7 :{BLACK}7 STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) openttd-1.5.3/src/lang/serbian.txt0000644000000000000000000151224712627373445015620 0ustar rootroot##name Serbian ##ownname Srpski ##isocode sr_RS ##plural 6 ##textdir ltr ##digitsep . ##digitsepcur . ##decimalsep , ##winlangid 0x7c1a ##grflangid 0x0d ##gender muški ženski srednji ##case nom big gen dat aku vok lok ins # $Id: serbian.txt 27353 2015-07-31 17:46:09Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(nedefinisani niz znakova) STR_JUST_NOTHING :Ništa # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :putnici STR_CARGO_PLURAL_PASSENGERS.big :Putnici STR_CARGO_PLURAL_PASSENGERS.gen :putnika STR_CARGO_PLURAL_PASSENGERS.aku :putnike STR_CARGO_PLURAL_COAL :ugalj STR_CARGO_PLURAL_COAL.big :Ugalj STR_CARGO_PLURAL_COAL.gen :uglja STR_CARGO_PLURAL_COAL.aku :ugalj STR_CARGO_PLURAL_MAIL :pošta STR_CARGO_PLURAL_MAIL.big :Pošta STR_CARGO_PLURAL_MAIL.gen :pošte STR_CARGO_PLURAL_MAIL.aku :poštu STR_CARGO_PLURAL_OIL :nafta STR_CARGO_PLURAL_OIL.big :Nafta STR_CARGO_PLURAL_OIL.gen :nafte STR_CARGO_PLURAL_OIL.aku :naftu STR_CARGO_PLURAL_LIVESTOCK :stoka STR_CARGO_PLURAL_LIVESTOCK.big :Stoka STR_CARGO_PLURAL_LIVESTOCK.gen :stoke STR_CARGO_PLURAL_LIVESTOCK.aku :stoku STR_CARGO_PLURAL_GOODS :roba STR_CARGO_PLURAL_GOODS.big :Roba STR_CARGO_PLURAL_GOODS.gen :robe STR_CARGO_PLURAL_GOODS.aku :robu STR_CARGO_PLURAL_GRAIN :žito STR_CARGO_PLURAL_GRAIN.big :Žito STR_CARGO_PLURAL_GRAIN.gen :žita STR_CARGO_PLURAL_GRAIN.aku :žito STR_CARGO_PLURAL_WOOD :drva STR_CARGO_PLURAL_WOOD.big :Drva STR_CARGO_PLURAL_WOOD.gen :drva STR_CARGO_PLURAL_WOOD.aku :drva STR_CARGO_PLURAL_IRON_ORE :ruda gvožđa STR_CARGO_PLURAL_IRON_ORE.big :Ruda gvožđa STR_CARGO_PLURAL_IRON_ORE.gen :rude gvožđa STR_CARGO_PLURAL_IRON_ORE.aku :rudu gvožđa STR_CARGO_PLURAL_STEEL :čelik STR_CARGO_PLURAL_STEEL.big :Čelik STR_CARGO_PLURAL_STEEL.gen :čelika STR_CARGO_PLURAL_STEEL.aku :čelik STR_CARGO_PLURAL_VALUABLES :dragocenosti STR_CARGO_PLURAL_VALUABLES.big :Dragocenosti STR_CARGO_PLURAL_VALUABLES.gen :dragocenosti STR_CARGO_PLURAL_VALUABLES.aku :dragocenosti STR_CARGO_PLURAL_COPPER_ORE :ruda bakra STR_CARGO_PLURAL_COPPER_ORE.big :Ruda bakra STR_CARGO_PLURAL_COPPER_ORE.gen :rude bakra STR_CARGO_PLURAL_COPPER_ORE.aku :rudu bakra STR_CARGO_PLURAL_MAIZE :kukuruz STR_CARGO_PLURAL_MAIZE.big :Kukuruz STR_CARGO_PLURAL_MAIZE.gen :kukuruza STR_CARGO_PLURAL_MAIZE.aku :kukuruz STR_CARGO_PLURAL_FRUIT :voće STR_CARGO_PLURAL_FRUIT.big :Voće STR_CARGO_PLURAL_FRUIT.gen :voća STR_CARGO_PLURAL_FRUIT.aku :voće STR_CARGO_PLURAL_DIAMONDS :dijamanti STR_CARGO_PLURAL_DIAMONDS.big :Dijamanti STR_CARGO_PLURAL_DIAMONDS.gen :dijamanata STR_CARGO_PLURAL_DIAMONDS.aku :dijamante STR_CARGO_PLURAL_FOOD :hrana STR_CARGO_PLURAL_FOOD.big :Hrana STR_CARGO_PLURAL_FOOD.gen :hrane STR_CARGO_PLURAL_FOOD.aku :hranu STR_CARGO_PLURAL_PAPER :papir STR_CARGO_PLURAL_PAPER.big :Papir STR_CARGO_PLURAL_PAPER.gen :papira STR_CARGO_PLURAL_PAPER.aku :papir STR_CARGO_PLURAL_GOLD :zlato STR_CARGO_PLURAL_GOLD.big :Zlato STR_CARGO_PLURAL_GOLD.gen :zlata STR_CARGO_PLURAL_GOLD.aku :zlato STR_CARGO_PLURAL_WATER :voda STR_CARGO_PLURAL_WATER.big :Voda STR_CARGO_PLURAL_WATER.gen :vode STR_CARGO_PLURAL_WATER.aku :vodu STR_CARGO_PLURAL_WHEAT :pšenica STR_CARGO_PLURAL_WHEAT.big :Pšenica STR_CARGO_PLURAL_WHEAT.gen :pšenice STR_CARGO_PLURAL_WHEAT.aku :pšenicu STR_CARGO_PLURAL_RUBBER :kaučuk STR_CARGO_PLURAL_RUBBER.big :Kaučuk STR_CARGO_PLURAL_RUBBER.gen :kaučuka STR_CARGO_PLURAL_RUBBER.aku :kaučuk STR_CARGO_PLURAL_SUGAR :šećer STR_CARGO_PLURAL_SUGAR.big :Šećer STR_CARGO_PLURAL_SUGAR.gen :šećera STR_CARGO_PLURAL_SUGAR.aku :šećer STR_CARGO_PLURAL_TOYS :igračke STR_CARGO_PLURAL_TOYS.big :Igračke STR_CARGO_PLURAL_TOYS.gen :igračaka STR_CARGO_PLURAL_TOYS.aku :igračke STR_CARGO_PLURAL_CANDY :slatkiši STR_CARGO_PLURAL_CANDY.big :Slatkiši STR_CARGO_PLURAL_CANDY.gen :slatkiša STR_CARGO_PLURAL_CANDY.aku :slatkiše STR_CARGO_PLURAL_COLA :kola STR_CARGO_PLURAL_COLA.big :Kola STR_CARGO_PLURAL_COLA.gen :kole STR_CARGO_PLURAL_COLA.aku :kolu STR_CARGO_PLURAL_COTTON_CANDY :šećerna vuna STR_CARGO_PLURAL_COTTON_CANDY.big :Šećerna vuna STR_CARGO_PLURAL_COTTON_CANDY.gen :šećerne vune STR_CARGO_PLURAL_COTTON_CANDY.aku :šećernu vunu STR_CARGO_PLURAL_BUBBLES :mehurići STR_CARGO_PLURAL_BUBBLES.big :Mehurići STR_CARGO_PLURAL_BUBBLES.gen :mehurića STR_CARGO_PLURAL_BUBBLES.aku :mehuriće STR_CARGO_PLURAL_TOFFEE :karamele STR_CARGO_PLURAL_TOFFEE.big :Karamele STR_CARGO_PLURAL_TOFFEE.gen :karamela STR_CARGO_PLURAL_TOFFEE.aku :karamele STR_CARGO_PLURAL_BATTERIES :baterije STR_CARGO_PLURAL_BATTERIES.big :Baterije STR_CARGO_PLURAL_BATTERIES.gen :baterija STR_CARGO_PLURAL_BATTERIES.aku :baterije STR_CARGO_PLURAL_PLASTIC :plastika STR_CARGO_PLURAL_PLASTIC.big :Plastika STR_CARGO_PLURAL_PLASTIC.gen :plastike STR_CARGO_PLURAL_PLASTIC.aku :plastiku STR_CARGO_PLURAL_FIZZY_DRINKS :gazirana pića STR_CARGO_PLURAL_FIZZY_DRINKS.big :Gazirana pića STR_CARGO_PLURAL_FIZZY_DRINKS.gen :gaziranih pića STR_CARGO_PLURAL_FIZZY_DRINKS.aku :gazirana pića # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :putnik STR_CARGO_SINGULAR_PASSENGER.big :Putnik STR_CARGO_SINGULAR_PASSENGER.gen :putnika STR_CARGO_SINGULAR_PASSENGER.aku :putnika STR_CARGO_SINGULAR_COAL :ugalj STR_CARGO_SINGULAR_COAL.big :Ugalj STR_CARGO_SINGULAR_COAL.gen :uglja STR_CARGO_SINGULAR_COAL.aku :ugalj STR_CARGO_SINGULAR_MAIL :pošta STR_CARGO_SINGULAR_MAIL.big :Pošta STR_CARGO_SINGULAR_MAIL.gen :pošte STR_CARGO_SINGULAR_MAIL.aku :poštu STR_CARGO_SINGULAR_OIL :nafta STR_CARGO_SINGULAR_OIL.big :Nafta STR_CARGO_SINGULAR_OIL.gen :nafte STR_CARGO_SINGULAR_OIL.aku :naftu STR_CARGO_SINGULAR_LIVESTOCK :stoka STR_CARGO_SINGULAR_LIVESTOCK.big :Stoka STR_CARGO_SINGULAR_LIVESTOCK.gen :stoke STR_CARGO_SINGULAR_LIVESTOCK.aku :stoku STR_CARGO_SINGULAR_GOODS :roba STR_CARGO_SINGULAR_GOODS.big :Roba STR_CARGO_SINGULAR_GOODS.gen :robe STR_CARGO_SINGULAR_GOODS.aku :robu STR_CARGO_SINGULAR_GRAIN :žito STR_CARGO_SINGULAR_GRAIN.big :Žito STR_CARGO_SINGULAR_GRAIN.gen :žita STR_CARGO_SINGULAR_GRAIN.aku :žito STR_CARGO_SINGULAR_WOOD :drvo STR_CARGO_SINGULAR_WOOD.big :Drvo STR_CARGO_SINGULAR_WOOD.gen :drva STR_CARGO_SINGULAR_WOOD.aku :drvo STR_CARGO_SINGULAR_IRON_ORE :ruda gvožđa STR_CARGO_SINGULAR_IRON_ORE.big :Ruda gvožđa STR_CARGO_SINGULAR_IRON_ORE.gen :rude gvožđa STR_CARGO_SINGULAR_IRON_ORE.aku :rudu gvožđa STR_CARGO_SINGULAR_STEEL :čelik STR_CARGO_SINGULAR_STEEL.big :Čelik STR_CARGO_SINGULAR_STEEL.gen :čelika STR_CARGO_SINGULAR_STEEL.aku :čelik STR_CARGO_SINGULAR_VALUABLES :dragocenosti STR_CARGO_SINGULAR_VALUABLES.big :Dragocenosti STR_CARGO_SINGULAR_VALUABLES.gen :dragocenosti STR_CARGO_SINGULAR_VALUABLES.aku :dragocenosti STR_CARGO_SINGULAR_COPPER_ORE :ruda bakra STR_CARGO_SINGULAR_COPPER_ORE.big :Ruda bakra STR_CARGO_SINGULAR_COPPER_ORE.gen :rude bakra STR_CARGO_SINGULAR_COPPER_ORE.aku :rudu bakra STR_CARGO_SINGULAR_MAIZE :kukuruz STR_CARGO_SINGULAR_MAIZE.big :Kukuruz STR_CARGO_SINGULAR_MAIZE.gen :kukuruza STR_CARGO_SINGULAR_MAIZE.aku :kukuruz STR_CARGO_SINGULAR_FRUIT :voće STR_CARGO_SINGULAR_FRUIT.big :Voće STR_CARGO_SINGULAR_FRUIT.gen :voća STR_CARGO_SINGULAR_FRUIT.aku :voće STR_CARGO_SINGULAR_DIAMOND :dijamant STR_CARGO_SINGULAR_DIAMOND.big :Dijamant STR_CARGO_SINGULAR_DIAMOND.gen :dijamanta STR_CARGO_SINGULAR_DIAMOND.aku :dijamant STR_CARGO_SINGULAR_FOOD :hrana STR_CARGO_SINGULAR_FOOD.big :Hrana STR_CARGO_SINGULAR_FOOD.gen :hrane STR_CARGO_SINGULAR_FOOD.aku :hranu STR_CARGO_SINGULAR_PAPER :papir STR_CARGO_SINGULAR_PAPER.big :Papir STR_CARGO_SINGULAR_PAPER.gen :papira STR_CARGO_SINGULAR_PAPER.aku :papir STR_CARGO_SINGULAR_GOLD :zlato STR_CARGO_SINGULAR_GOLD.big :Zlato STR_CARGO_SINGULAR_GOLD.gen :zlata STR_CARGO_SINGULAR_GOLD.aku :zlato STR_CARGO_SINGULAR_WATER :voda STR_CARGO_SINGULAR_WATER.big :Voda STR_CARGO_SINGULAR_WATER.gen :vode STR_CARGO_SINGULAR_WATER.aku :vodu STR_CARGO_SINGULAR_WHEAT :pšenica STR_CARGO_SINGULAR_WHEAT.big :Pšenica STR_CARGO_SINGULAR_WHEAT.gen :pšenice STR_CARGO_SINGULAR_WHEAT.aku :pšenicu STR_CARGO_SINGULAR_RUBBER :kaučuk STR_CARGO_SINGULAR_RUBBER.big :Kaučuk STR_CARGO_SINGULAR_RUBBER.gen :kaučuka STR_CARGO_SINGULAR_RUBBER.aku :kaučuk STR_CARGO_SINGULAR_SUGAR :šećer STR_CARGO_SINGULAR_SUGAR.big :Šećer STR_CARGO_SINGULAR_SUGAR.gen :šećera STR_CARGO_SINGULAR_SUGAR.aku :šećer STR_CARGO_SINGULAR_TOY :igračka STR_CARGO_SINGULAR_TOY.big :Igračka STR_CARGO_SINGULAR_TOY.gen :igračke STR_CARGO_SINGULAR_TOY.aku :igračku STR_CARGO_SINGULAR_CANDY :slatkiš STR_CARGO_SINGULAR_CANDY.big :Slatkiš STR_CARGO_SINGULAR_CANDY.gen :slatkiša STR_CARGO_SINGULAR_CANDY.aku :slatkiš STR_CARGO_SINGULAR_COLA :kola STR_CARGO_SINGULAR_COLA.big :Kola STR_CARGO_SINGULAR_COLA.gen :kole STR_CARGO_SINGULAR_COLA.aku :kolu STR_CARGO_SINGULAR_COTTON_CANDY :šećerna vuna STR_CARGO_SINGULAR_COTTON_CANDY.big :Šećerna vuna STR_CARGO_SINGULAR_COTTON_CANDY.gen :šećerne vune STR_CARGO_SINGULAR_COTTON_CANDY.aku :šećernu vunu STR_CARGO_SINGULAR_BUBBLE :mehurić STR_CARGO_SINGULAR_BUBBLE.big :Mehurić STR_CARGO_SINGULAR_BUBBLE.gen :mehurića STR_CARGO_SINGULAR_BUBBLE.aku :mehurić STR_CARGO_SINGULAR_TOFFEE :karamela STR_CARGO_SINGULAR_TOFFEE.big :Karamela STR_CARGO_SINGULAR_TOFFEE.gen :karamele STR_CARGO_SINGULAR_TOFFEE.aku :karamelu STR_CARGO_SINGULAR_BATTERY :baterija STR_CARGO_SINGULAR_BATTERY.big :Baterija STR_CARGO_SINGULAR_BATTERY.gen :baterije STR_CARGO_SINGULAR_BATTERY.aku :bateriju STR_CARGO_SINGULAR_PLASTIC :plastika STR_CARGO_SINGULAR_PLASTIC.big :Plastika STR_CARGO_SINGULAR_PLASTIC.gen :plastike STR_CARGO_SINGULAR_PLASTIC.aku :plastiku STR_CARGO_SINGULAR_FIZZY_DRINK :gazirano piće STR_CARGO_SINGULAR_FIZZY_DRINK.big :Gazirano piće STR_CARGO_SINGULAR_FIZZY_DRINK.gen :gaziranog pića STR_CARGO_SINGULAR_FIZZY_DRINK.aku :gazirano piće # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA} putnik{P "" a a} STR_QUANTITY_COAL :{WEIGHT_LONG} uglja STR_QUANTITY_MAIL :{COMMA} džak{P "" a ova} pošte STR_QUANTITY_OIL :{VOLUME_LONG} nafte STR_QUANTITY_LIVESTOCK :{COMMA} grl{P o a a} stoke STR_QUANTITY_GOODS :{COMMA} sanduk{P "" a a} robe STR_QUANTITY_GRAIN :{WEIGHT_LONG} žitarica STR_QUANTITY_WOOD :{WEIGHT_LONG} drva STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} rude gvožđa STR_QUANTITY_STEEL :{WEIGHT_LONG} čelika STR_QUANTITY_VALUABLES :{COMMA} džak{P "" a ova} dragocenosti STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} rude bakra STR_QUANTITY_MAIZE :{WEIGHT_LONG} kukuruza STR_QUANTITY_FRUIT :{WEIGHT_LONG} voća STR_QUANTITY_DIAMONDS :{COMMA} džak{P "" a ova} dijamanata STR_QUANTITY_FOOD :{WEIGHT_LONG} hrane STR_QUANTITY_PAPER :{WEIGHT_LONG} papira STR_QUANTITY_GOLD :{COMMA} džak{P "" a ova} zlata STR_QUANTITY_WATER :{VOLUME_LONG} vode STR_QUANTITY_WHEAT :{WEIGHT_LONG} pšenice STR_QUANTITY_RUBBER :{VOLUME_LONG} kaučuka STR_QUANTITY_SUGAR :{WEIGHT_LONG} šećera STR_QUANTITY_TOYS :{COMMA} igrač{P ka ke aka} STR_QUANTITY_SWEETS :{COMMA} džak{P "" a ova} slatkiša STR_QUANTITY_COLA :{VOLUME_LONG} kole STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} šećerne vune STR_QUANTITY_BUBBLES :{COMMA} balon{P "" a a} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} karamele STR_QUANTITY_BATTERIES :{COMMA} baterij{P a e a} STR_QUANTITY_PLASTIC :{VOLUME_LONG} plastike STR_QUANTITY_FIZZY_DRINKS :{COMMA} gaziran{P o a a} pić{P 0 e a a} STR_QUANTITY_N_A :Nepoznato # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}PT STR_ABBREV_COAL :{TINY_FONT}UG STR_ABBREV_MAIL :{TINY_FONT}PO STR_ABBREV_OIL :{TINY_FONT}NF STR_ABBREV_LIVESTOCK :{TINY_FONT}ST STR_ABBREV_GOODS :{TINY_FONT}RB STR_ABBREV_GRAIN :{TINY_FONT}ŽT STR_ABBREV_WOOD :{TINY_FONT}DR STR_ABBREV_IRON_ORE :{TINY_FONT}RG STR_ABBREV_STEEL :{TINY_FONT}ČE STR_ABBREV_VALUABLES :{TINY_FONT}DG STR_ABBREV_COPPER_ORE :{TINY_FONT}BR STR_ABBREV_MAIZE :{TINY_FONT}KZ STR_ABBREV_FRUIT :{TINY_FONT}VĆ STR_ABBREV_DIAMONDS :{TINY_FONT}DT STR_ABBREV_FOOD :{TINY_FONT}HR STR_ABBREV_PAPER :{TINY_FONT}PR STR_ABBREV_GOLD :{TINY_FONT}ZL STR_ABBREV_WATER :{TINY_FONT}VD STR_ABBREV_WHEAT :{TINY_FONT}PŠ STR_ABBREV_RUBBER :{TINY_FONT}KČ STR_ABBREV_SUGAR :{TINY_FONT}ŠĆ STR_ABBREV_TOYS :{TINY_FONT}IG STR_ABBREV_SWEETS :{TINY_FONT}SL STR_ABBREV_COLA :{TINY_FONT}KL STR_ABBREV_CANDYFLOSS :{TINY_FONT}ŠV STR_ABBREV_BUBBLES :{TINY_FONT}BA STR_ABBREV_TOFFEE :{TINY_FONT}KA STR_ABBREV_BATTERIES :{TINY_FONT}BT STR_ABBREV_PLASTIC :{TINY_FONT}PL STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}GP STR_ABBREV_NONE :{TINY_FONT}NŠT STR_ABBREV_ALL :{TINY_FONT}SVE # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA} putnik{P "" a a} STR_BAGS :{COMMA} džak{P "" a ova} STR_TONS :{COMMA} ton{P a e a} STR_LITERS :{COMMA} lit{P ra e ara} STR_ITEMS :{COMMA} komad{P "" a a} STR_CRATES :{COMMA} sanduk{P "" a a} # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Tamno plava STR_COLOUR_PALE_GREEN :Bledo zelena STR_COLOUR_PINK :Ružičasta STR_COLOUR_YELLOW :Žuta STR_COLOUR_RED :Crvena STR_COLOUR_LIGHT_BLUE :Svetlo plava STR_COLOUR_GREEN :Zelena STR_COLOUR_DARK_GREEN :Tamno zelena STR_COLOUR_BLUE :Plava STR_COLOUR_CREAM :Krem STR_COLOUR_MAUVE :Lavanda STR_COLOUR_PURPLE :Ljubičasta STR_COLOUR_ORANGE :Narandžasta STR_COLOUR_BROWN :Braon STR_COLOUR_GREY :Siva STR_COLOUR_WHITE :Bela # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA} milja na sat STR_UNITS_VELOCITY_METRIC :{COMMA} km/h STR_UNITS_VELOCITY_SI :{COMMA} m/s STR_UNITS_POWER_IMPERIAL :{COMMA}ks STR_UNITS_POWER_METRIC :{COMMA}ks STR_UNITS_POWER_SI :{COMMA}kW STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}kg STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton{P a e a} STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} ton{P a e a} STR_UNITS_WEIGHT_LONG_SI :{COMMA} kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}m³ STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} galon{P "" a a} STR_UNITS_VOLUME_LONG_METRIC :{COMMA} lit{P ar ra ara} STR_UNITS_VOLUME_LONG_SI :{COMMA} m³ STR_UNITS_FORCE_IMPERIAL :{COMMA} lbf STR_UNITS_FORCE_METRIC :{COMMA} kgf STR_UNITS_FORCE_SI :{COMMA} kN STR_UNITS_HEIGHT_IMPERIAL :{COMMA} ft STR_UNITS_HEIGHT_METRIC :{COMMA} m STR_UNITS_HEIGHT_SI :{COMMA} m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Filtriraj po: STR_LIST_FILTER_OSKTITLE :{BLACK}Unesite tekst za filter STR_LIST_FILTER_TOOLTIP :{BLACK}Unesite ključnu reč kako bi se filtriralo spisak STR_TOOLTIP_GROUP_ORDER :{BLACK}Izaberi red sortiranja STR_TOOLTIP_SORT_ORDER :{BLACK}Odaberite način sortiranja (opadajući/rastući) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Odaberite kriterijum za sortiranje STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Izaberite način filtriranja STR_BUTTON_SORT_BY :{BLACK}Sortiraj po STR_BUTTON_LOCATION :{BLACK}Mesto STR_BUTTON_RENAME :{BLACK}Preimenuj STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Zatvori prozor STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Naslov - povucite mišem da biste pomerili prozor STR_TOOLTIP_SHADE :{BLACK}Zamotaj prozor - prikazuje se samo naslov STR_TOOLTIP_DEBUG :{BLACK}Prikazuje NewGRF podatake o otklanjanju grešaka STR_TOOLTIP_DEFSIZE :{BLACK}Menja veličinu prozora na podrazumevanu. Ctrl+Klik da sačuvate tekuću veličinu kao podrazumevanu STR_TOOLTIP_STICKY :{BLACK}Markirajte ovaj prozor kao ne za zatvaranje tipkom 'Zatvaranje svih prozora'. Uz Ctrl+Click to stanje će biti zapamćeno. STR_TOOLTIP_RESIZE :{BLACK}Pritisnite i povucite kako bi prozor promenio veličinu STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Izbor velikog/malog prozora STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Skrol - pomera spisak gore/dole STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Klizač - pomera spisak levo/desno STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Uklanja građevinu i dr. na kvadratu tla. Ctrl obeležava dijagonalno područje. Shift prebacuje između izgradnje i prikaza procene troškova # Show engines button STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Prikaži skriveni vozovi STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Prikaži skrivena drumska vozila STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP :{BLACK}Prikaži skrivene brodove STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT :{BLACK}Prikaži skrivene letilice STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP :{BLACK}Omogućavanje ovog podešavanja znači da će se i skriveni vozevi biti prikazani. STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE_TOOLTIP :{BLACK}Omugućavanjem ovog dogmeta, sakrivena drumska vozila će takođe biti prikazan STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP_TOOLTIP :{BLACK}Omugućavanjem ovog dogmeta, sakriveni brod će takođe biti prikazan STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Omugućavanjem ovog dogmeta, sakriveni avion će takođe biti prikazan # Query window STR_BUTTON_DEFAULT :{BLACK}Prvobitno STR_BUTTON_CANCEL :{BLACK}Otkaži STR_BUTTON_OK :{BLACK}OK # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertzuiopšđasdfghjklčćž yxcvbnm,./'. STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTZUIOPŠĐASDFGHJKLČĆŽ YXCVBNM;:?". # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}Dužina: {NUM} STR_MEASURE_AREA :{BLACK}Područje: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Dužina: {NUM}{}Visinska razlika: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Područje: {NUM} x {NUM}{}Visinska razlika: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}Imenu STR_SORT_BY_CAPTION_DATE :{BLACK}Datumu # These are used in dropdowns STR_SORT_BY_NAME :Nazivu STR_SORT_BY_PRODUCTION :Proizvodnji STR_SORT_BY_TYPE :Vrsti STR_SORT_BY_TRANSPORTED :Prevezeno STR_SORT_BY_NUMBER :Broju STR_SORT_BY_PROFIT_LAST_YEAR :Zaradi prošle godine STR_SORT_BY_PROFIT_THIS_YEAR :Zaradi ove godine STR_SORT_BY_AGE :Starosti STR_SORT_BY_RELIABILITY :Pouzdanosti STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Ukupnoj nosivosti po vrsti tovara STR_SORT_BY_MAX_SPEED :Najvećoj brzini STR_SORT_BY_MODEL :Modelu STR_SORT_BY_VALUE :Vrednosti STR_SORT_BY_LENGTH :Dužini STR_SORT_BY_LIFE_TIME :Isticanju životnog veka STR_SORT_BY_TIMETABLE_DELAY :Kašnjenje u rasporedu STR_SORT_BY_FACILITY :Vrsti stanice STR_SORT_BY_WAITING_TOTAL :Ukupan teret na čekanju STR_SORT_BY_WAITING_AVAILABLE :Dostupan teret na čekanju STR_SORT_BY_RATING_MAX :Najvišoj oceni tereta STR_SORT_BY_RATING_MIN :Najnižoj oceni tereta STR_SORT_BY_ENGINE_ID :ID mašine (standardno) STR_SORT_BY_COST :Ceni STR_SORT_BY_POWER :Snazi STR_SORT_BY_TRACTIVE_EFFORT :Vučnoj snazi STR_SORT_BY_INTRO_DATE :Datum uvođenja STR_SORT_BY_RUNNING_COST :Troškovima održavanja STR_SORT_BY_POWER_VS_RUNNING_COST :Snazi/Troškovima održavanja STR_SORT_BY_CARGO_CAPACITY :Nosivosti tereta STR_SORT_BY_RANGE :Dometu STR_SORT_BY_POPULATION :Naseljenosti STR_SORT_BY_RATING :Rejtingu # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pauziranje partije STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Ubrzavanje igre STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Opcije STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Čuvanje pozicije, napuštanje partije, izlaz STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Prikazuje kartu, dodatne poglede, spisak znakova STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Prikaži popis naselja STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Prikaži subvencije STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Prikaži spisak svih stanica preduzeća STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Prikaži finansijsko stanje preduzeća STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Prikaži opšte podatke preduzeća STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Pokaži listu ciljeva STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Prikaži grafikone STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Prikaži tabele lige preduzeća STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Finansiranje izgradnje nove fabrike, spisak svih fabrika STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Prikaži spisak svih vozova preduzeća. Ctrl+Klik uključuje prikaz spiska grupe/vozila STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Prikaži spisak svih drumskih vozila preduzeća. Ctrl+Klik uključuje otvaranje spiska grupe/vozila STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Prikaži spisak svih brodova preduzeća. Ctrl+Klik uključuje otvaranje spiska grupe/vozila STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Prikaži spisak svih letelica preduzeća. Ctrl+Klik uključuje otvaranje spiska grupe/vozila STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Približi pogled STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Udalji pogled STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Izgradnja železničke pruge STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Izgradnja puteva STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Izgradnja pristaništa STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Izgradnja aerodroma STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Otvaranjem trake za oblikovanje terena moguće je posaditi drveće, menjati reljef, itd. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Prikaži prozor za zvuk i muziku STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Prikaži poslednju poruku/izveštaj, prikaži opcije poruka STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Podaci o zemljištu, konzola, korekcija skripti, slika sa ekrana, o OpenTTD-u STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Zamenjuje trake sa alatima # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Čuvanje scenarija, učitavanje scenarija, napuštanje editora, izlaz STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Editor scenarija STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Pomeranje datuma početka za jednu godinu unazad STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Pomeranje datuma početka za jednu godinu unapred STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Kliknite za unos početne godine STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Prikazuje kartu, popis naselja STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Oblikovanje reljefa STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Stvaranje naselja STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Stvaranje fabrika STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Izgradnja puteva STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Sadnja drveća. Shift prebacuje između sadnje i prikaza procene troškova STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Postavljanje znaka STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Postavlja objekat. Shift prebacuje između postavljanja i prikaza procene troškova ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Sačuvaj scenario STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Učitaj scenario STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Sačuvaj elevacionu kartu STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Učitaj elevacionu kartu STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Napusti editor STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Izađi ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :Opcije STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Podešavanja STR_SETTINGS_MENU_SCRIPT_SETTINGS :Podešavanja VI/Skripte partije STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF podešavanja STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Opcije transparentnosti STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Prikazana imena naselja STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Prikazana imena stanica STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Prikazana imena putanja STR_SETTINGS_MENU_SIGNS_DISPLAYED :Prikazani znakovi STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Prikazani znakovi i imena od drugih preduzeća STR_SETTINGS_MENU_FULL_ANIMATION :Puna animacija STR_SETTINGS_MENU_FULL_DETAIL :Svi detalji STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Transparentne zgrade STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Transparentni znakovi ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Sačuvaj igru STR_FILE_MENU_LOAD_GAME :Učitaj partiju STR_FILE_MENU_QUIT_GAME :Napusti partiju STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Izađi ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :Karta sveta STR_MAP_MENU_EXTRA_VIEW_PORT :Dodatno gledište STR_MAP_MENU_SIGN_LIST :Lista Znakova ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Popis naselja STR_TOWN_MENU_FOUND_TOWN :Osnivanje naselja ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :Subvencije ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Grafikon operativnog profita STR_GRAPH_MENU_INCOME_GRAPH :Grafikon prihoda STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Grafikon dostavljenog tovara STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Grafikon istorije učinka STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Grafikon vrednosti preduzeća STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Stope naplate tovara ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Tabela lige preduzeća STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detaljan pregled poslovanja STR_GRAPH_MENU_HIGHSCORE :Tabela najboljih rezultata ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Spisak fabrika STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Lanci fabrika STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Finansiranje nove fabrike ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Izgradnja železnice STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Izgradnja elektrifikovane železnice STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Izgradnja jednošinske železnice STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Izgradnja magnetne železnice ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Izgradnja drumskog sistema STR_ROAD_MENU_TRAM_CONSTRUCTION :Izgradnja tramvajskog sistema ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Izgradnja plovnog sistema ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Izgradnja aerodroma ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :Oblikovanje terena STR_LANDSCAPING_MENU_PLANT_TREES :Posadi drvo STR_LANDSCAPING_MENU_PLACE_SIGN :Postavi znak ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :Zvuk/muzika ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Poslednja poruka/izveštaj STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Istorija Obaveštenja ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Podaci o zemljištu STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :Uključi/isključi konzolu STR_ABOUT_MENU_AI_DEBUG :Korekcija veštačke inteligencije / skripte partije STR_ABOUT_MENU_SCREENSHOT :Sačuvaj sliku STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Čuva sliku skroz približenog terena STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Podrazumevani nivo zuma za sliku ekrana STR_ABOUT_MENU_GIANT_SCREENSHOT :Sačuvaj sliku celog terena STR_ABOUT_MENU_ABOUT_OPENTTD :O OpenTTD-u STR_ABOUT_MENU_SPRITE_ALIGNER :Poravnjavanje sprajta STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Uključi/isključi granične linije STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Uključi/Isključi bojenje nesređenih blokova ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :1. STR_ORDINAL_NUMBER_2ND :2. STR_ORDINAL_NUMBER_3RD :3. STR_ORDINAL_NUMBER_4TH :4. STR_ORDINAL_NUMBER_5TH :5. STR_ORDINAL_NUMBER_6TH :6. STR_ORDINAL_NUMBER_7TH :7. STR_ORDINAL_NUMBER_8TH :8. STR_ORDINAL_NUMBER_9TH :9. STR_ORDINAL_NUMBER_10TH :10. STR_ORDINAL_NUMBER_11TH :11. STR_ORDINAL_NUMBER_12TH :12. STR_ORDINAL_NUMBER_13TH :13. STR_ORDINAL_NUMBER_14TH :14. STR_ORDINAL_NUMBER_15TH :15. ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :1. STR_DAY_NUMBER_2ND :2. STR_DAY_NUMBER_3RD :3. STR_DAY_NUMBER_4TH :4. STR_DAY_NUMBER_5TH :5. STR_DAY_NUMBER_6TH :6. STR_DAY_NUMBER_7TH :7. STR_DAY_NUMBER_8TH :8. STR_DAY_NUMBER_9TH :9. STR_DAY_NUMBER_10TH :10. STR_DAY_NUMBER_11TH :11. STR_DAY_NUMBER_12TH :12. STR_DAY_NUMBER_13TH :13. STR_DAY_NUMBER_14TH :14. STR_DAY_NUMBER_15TH :15. STR_DAY_NUMBER_16TH :16. STR_DAY_NUMBER_17TH :17. STR_DAY_NUMBER_18TH :18. STR_DAY_NUMBER_19TH :19. STR_DAY_NUMBER_20TH :20. STR_DAY_NUMBER_21ST :21. STR_DAY_NUMBER_22ND :22. STR_DAY_NUMBER_23RD :23. STR_DAY_NUMBER_24TH :24. STR_DAY_NUMBER_25TH :25. STR_DAY_NUMBER_26TH :26. STR_DAY_NUMBER_27TH :27. STR_DAY_NUMBER_28TH :28. STR_DAY_NUMBER_29TH :29. STR_DAY_NUMBER_30TH :30. STR_DAY_NUMBER_31ST :31. ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :Jan STR_MONTH_ABBREV_FEB :Feb STR_MONTH_ABBREV_MAR :Mar STR_MONTH_ABBREV_APR :Apr STR_MONTH_ABBREV_MAY :Maj STR_MONTH_ABBREV_JUN :Jun STR_MONTH_ABBREV_JUL :Jul STR_MONTH_ABBREV_AUG :Avg STR_MONTH_ABBREV_SEP :Sep STR_MONTH_ABBREV_OCT :Okt STR_MONTH_ABBREV_NOV :Nov STR_MONTH_ABBREV_DEC :Dec STR_MONTH_JAN :Januar STR_MONTH_FEB :Februar STR_MONTH_MAR :Mart STR_MONTH_APR :April STR_MONTH_MAY :Maj STR_MONTH_JUN :Jun STR_MONTH_JUL :Jul STR_MONTH_AUG :Avgust STR_MONTH_SEP :Septembar STR_MONTH_OCT :Oktobar STR_MONTH_NOV :Novembar STR_MONTH_DEC :Decembar ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}Legenda STR_GRAPH_KEY_TOOLTIP :{BLACK}Prikaži legendu STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Grafikon operativnog profita STR_GRAPH_INCOME_CAPTION :{WHITE}Grafikon prihoda STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Isporučene jedinice tovara STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Rejting učinka preduzeća (najveći je 1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Vrednosti preduzeća STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Stope prihoda od tovara STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Dana u tranzitu STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Isplata za dostavu 10 jedinica (ili 10 hiljada litara) tovara na razdaljinu od 20 kvadrata STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Prikaži sve STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Sakri sve STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Prikazuje sve vrste tovara na grafikonu prihoda STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Sakrij sve vrste tovara na grafikonu prihoda STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Uključi/Isključi grafikone po vrsti tovara STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Prikaži detaljne ocene učinka # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}Legenda grafikona preduzeća STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Kliknite ovde za uključenje/isključenje prikaza preduzeća na grafikonu # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Tabela lige preduzeća STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Inženjer STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Šef saobraćaja STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Koordinator prevoza STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Supervizor itinerera STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Direktor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Izvršni direktor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Generalni direktor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :Predsednik STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Tajkun # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}Detaljan pergled poslovanja STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detalji STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}Prikazuje detalje o ovom preduzeću ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Vozila: STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stanice: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Najmanja dobit: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Najmanji prihod: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Najviši prihod: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Dostavljeno: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Teret: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Novac: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Zajam: STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Ukupno: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Broj vozila koja su imala dobit prošle godine. Ovo uključuje drumska, železnička vozila, brodove i letilice STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Broj nedavno opsluženih stanica. Posebno se broji svaki deo stanice (npr. železničko, autobusko stajalište ili aerodrom) STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}Dobit vozila sa najmanjim prihodom (samo vozila starijih od 2 godine) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Zarađen novac u tromesečju sa najmanjom dobiti u proteklih 12 tromesečja STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Zarađen novac u tromesečju sa najvećom dobiti u proteklih 12 tromesečja STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Jedinica tereta dostavljenih u proteklih četiri tromesečja STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Broj vrsta tereta dostavljenih u proteklom tromesečju STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Količina novca koje ovo preduzeće ima u banci STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}Količina novca koje je ovo preduzeće pozajmilo STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Ukupno bodova od najviše mogućih # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Džez džuboks STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}Sve STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Stari zvuk STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}Novi zvuk STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Lagane stvari STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Lični raspored 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Lični raspored 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Jačina muzike STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Jačina ambijenta STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}Tiho STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}Glasno STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Numera STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Naziv STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Puštaj nasumično STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Program STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Skoči na prethodnu numeru u izboru STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Skoči na sledeću numeru u izboru STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Prekini muziku STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Pusti muziku STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Pomerajte klizače za promenu jačine muzike i zvučnih efekata STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Izaberi program 'sve numere' STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Izaberi program 'stari zvuk' STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Izaberi program 'novi zvuk' STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Izbor programa 'lagane stvari' STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Izaberi program 'Lični raspored 1' (korisnički-definisan) STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Izaberi program 'Lični raspored 2' (korisnički-definisan) STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Uključi/isključi nasumičan izbor pri puštanju STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Prikaži prozor za izbor muzičkih numera STR_ERROR_NO_SONGS :{WHITE}Izabran je skup muzike bez ijedne numere. Neće biti puštena nikakva muzika # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Izbor muzičkog programa STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Indeks numera STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Program - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Obriši STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Obriši tekući program (samo korisnički-definisani programi) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Klik na numeru je dodaje u tekući program (samo za korisnički-definisane programe) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Pritisnite na muzičku numeru kako biste je uklonili sa trenutnog rasporeda (samo za Custom1 ili Custom2) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Najbolja preduzeća koja su dostigla {NUM} STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}{NUM} u Tabeli Lige Preduzeća STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Biznismen STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN.gen :biznismena STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Privrednik STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR.gen :privrednika STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industrijalac STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST.gen :industrijalca STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Kapitalista STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST.gen :kapitaliste STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnat STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE.gen :magnata STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Mogul STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL.gen :mogula STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Tajkun veka STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY.gen :tajkuna veka STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} dostiže status '{STRING}'! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME}, vlasnik preduzeća {COMPANY} je dostigao status '{STRING}'! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}Karta - {STRING} STR_SMALLMAP_TYPE_CONTOURS :Reljef STR_SMALLMAP_TYPE_VEHICLES :Vozila STR_SMALLMAP_TYPE_INDUSTRIES :Fabrike STR_SMALLMAP_TYPE_ROUTES :Rute STR_SMALLMAP_TYPE_VEGETATION :Vegetacija STR_SMALLMAP_TYPE_OWNERS :Vlasnici STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Prikazuje reljef na karti STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Prikazuje vozila na karti STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Prikazuje fabrike na karti STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Prikazuje protok tereta na karti STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Prikazuje putne rute na karti STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Prikazuje vegetaciju na karti STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Prikazuje vlasništva na karti STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Klikom na industriju se prikazuju/ne prikazuju njene fabrike. Ctrl+Klik prikazuje fabrike samo odabrane. Sa ponovnim Ctrl+Klik prikazuju se fabrike svih industrija STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Klikom na preduzeće se prikazuje/ne prikazuje njeno vlasništvo. Ctrl+Klik prikazuje vlasništvo samo odabranog. Sa ponovnim Ctrl+Klik prikazuju se vlasništva svih preduzeća STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Putevi STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Pruge STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Stanice/Aerodromi/Pristaništa STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Građevine/Industrije STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Vozila STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Vozovi STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Drumska vozila STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Brodovi STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Letelice STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Rute Prevoza STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Šuma STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Železnička stanica STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Utovar kamiona STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Autobuska stanica STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Aerodrom/Heliodrom STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Pristanište STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Grubo tlo STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Travnato tlo STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Ogoljeno tlo STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Polja STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Drveće STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Stene STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Voda STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}Nema vlasnika STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Naselja STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Industrije STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Pustinja STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Sneg STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Prikazuje imena naselja na karti STR_SMALLMAP_CENTER :{BLACK}Pozicionira kartu na trenutnu poziciju STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}Sva sakrivena STR_SMALLMAP_ENABLE_ALL :{BLACK}Sva prikazana STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Prikaži visine STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Sakrij sve fabrike na karti STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Prikaži na karti sve fabrike STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Promena prikaza elevacije STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Uklanja prikaz vlasništva preduzeća sa karte STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Prikazuje vlasništvo preduzeća na karti STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Ne prikazuje nijedan teret na mapi STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Prikazuje sve terete na mapi # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Prikaži poslednju poruku ili izveštaj STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUZA * * STR_STATUSBAR_AUTOSAVE :{RED}AUTO-ČUVANJE STR_STATUSBAR_SAVING_GAME :{RED}* * ČUVAM PARTIJU * * # News message history STR_MESSAGE_HISTORY :{WHITE}Arhiva Vesti STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}Spisak skorašnjih novosti STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING} STR_NEWS_MESSAGE_CAPTION :{WHITE}Poruka STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Građani proslavljaju . . .{}Dolazak prvog voza na stanicu {STATION}! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Građani proslavljaju . . .{}Dolazak prvog autobusa na stanicu {STATION}! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Građani proslavljaju . . .{}Dolazak prvog kamiona na stanicu {STATION}! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Građani proslavljaju . . .{}Dolazak prvog tramvaja na stanicu {STATION}! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Građani proslavljaju . . .{}Dolazak prvog teretnog tamvaja na stanicu {STATION}! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Građani proslavljaju . . .{}Dolazak prvog broda na pristanište {STATION}! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Građani proslavljaju . . .{}Dolazak prve letilice na aerodrom {STATION}! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Sudar vozova!{}{COMMA} {P "" su je} poginu{P o la lo} u eksploziji nakon sudara STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Saobraćajna nesreća!{}Vozač je poginuo u eksploziji nakon sudara sa vozom STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Saobraćajna nesreća!{}{COMMA} {P "" je su} poginu{P o la lo} u eksploziji nakon sudara sa vozom STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Avionska nesraća!{}{COMMA} {P "" su je} poginu{P o la lo} u eksploziji kod {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Avionska nesreća!{}Letilici je nestalo goriva, {COMMA} {P "" su je} poginu{P o la lo} u padu! STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Cepelin se srušio kod {STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Drumskom vozilo uništeno pri sudaru sa 'NLO'! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Eksplozija naftne rafinerije blizu naselja {TOWN}! STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Fabrika uništena pri nepoznatim okolnostima blizu naselja {TOWN}! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'NLO' sleteo blizu naselja {TOWN}! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Urušavanje rudnika uglja uništilo je svoju okolinu blizu naselja {TOWN}! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Poplave!{}{COMMA} je barem nesta{P o lo lo}, pretpostavlja se da {P je su su} poginu{P o li li} zbog velike nepogode! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Preduzeće za prevoz u nevolji! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}Preduzeće {STRING} će biti prodato ili zatvoreno zbog bankrota ukoliko se poslovanje ne popravi! STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Spajanje preduzeća za prevoz! STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} je prodato preduzeću {STRING} za {CURRENCY_LONG}! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrot! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}Preduzeće {STRING} je zatvoreno od strane njenih kreditera, a vlasništvo je rasprodato! STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}Otvoreno novo preduzeće za prevoz! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} počinje sa gradnjom blizu naselja {TOWN}! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{STRING} je preuzeto od strane preduzeća {STRING}! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(vlasnik) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{STRING} je sponzorisao izgradnju novog naselja {TOWN}! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}Nov{G i a o} {STRING} je u izgradnji kod naselja {TOWN}! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}Nov{G i a o} {STRING} je posađen{G 0 "" a o} kod naselja {TOWN}! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING} objavljuje prestanak sa daljim radom! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Problem sa zalihama je prouzrokovao da {STRING} objavi prestanak sa daljim radom! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Nedostatak obližnjeg drveća je prouzrokovao da {STRING} objavi prestanak sa daljim radom! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}Evropska Monetarna Unija!{}{}Euro je uveden kao jedina valuta za uobičajene transakcije u vašoj zemlji! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}Svetska recesija!{}{}Finansijski eksperti se plaše najgoreg dok ekonomija slabi sve više! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Recesija završena!{}{}Preokret u trgovini pruža podršku industrijama dok ekonomija jača! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} povećava proizvodnju! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}Pronađena nova ležišta uglja u {INDUSTRY}!{}Očekuje se duplo veća proizvodnja! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}Nove rezerve nafte otkrivene u {INDUSTRY}!{}Očekuje se duplo veća proizvodnja! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}Od unapređenih poljoprivrednih metoda u {INDUSTRY} očekuje se dupliranje prinosa! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{1:INDUSTRY} povećava proizvodnju {0:STRING.gen} za {2:COMMA}%! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} proizvodnja je opala za 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Najezda insekata u {INDUSTRY}!{}Proizvodnja opala za 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{1:INDUSTRY} smanjuje proizvodnju {0:STRING.gen} za {2:COMMA}%! STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} čeka u depou STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} čeka u depou STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} čeka u depou STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} čeka u hangaru # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} ima premalo naredbi u voznom redu STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} ima neodređenu naredbu STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} ima dupliciranu naredbu STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} ima neodgovarajuću stanicu u naredbi STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} zastareva STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} previše zastareva STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} previše zastareva i hitno bi ga/je trebalo zameniti STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} ne može za dalje da pronađe put STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} se izgubio STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}{VEHICLE} je prošle godine imao dobit od {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} ne može da stigne do sledeće destinacije, izvan dometa je STR_NEWS_ORDER_REFIT_FAILED :{WHITE}Neuspešna primena naredbe preuređivanja {VEHICLE} STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Automatska obnova nije uspela za {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Nov{G "" a o} {STRING} od sada u prodaji! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Nov{G "" a o} {STRING} od sada u prodaji! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} više ne prihvata {STRING} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} više ne prihvata ni {STRING} ni {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} od sada prihvata {STRING.aku} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} od sada prihvata {STRING.aku} i {STRING.aku} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Ponuda subvencije istekla:{}{}Prevoz {STRING.gen} iz {STRING} u {STRING} se više neće stimulisati STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subvencija povučena:{}{}Usluga prevoza {STRING.gen} između stanica {STRING} i {STRING} više nije u opticaju STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Ponuda subvencije:{}{}Preduzimač koji prvi preveze {STRING.aku} od {STRING} do {STRING} stiče pravo na dodatnu zaradu tokom sledeća 24 meseca! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Subvencija odobrena preduzeću {STRING}!{}{}Za prevoz {STRING.gen} između stanica {STRING} i {STRING} zarada će vredeti 50% više u narednih godinu dana! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Subvencija odobrena preduzeću {STRING}!{}{}Za prevoz {STRING.gen} između stanica {STRING} i {STRING} zarada će vredeti duplo više u narednih godinu dana! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Subvencija odobrena preduzeću {STRING}!{}{}Za prevoz {STRING.gen} između stanica {STRING} i {STRING} zarada će vredeti trostruko više u narednih godinu dana! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Subvencija odobrena preduzeću {STRING}!{}{}Za prevoz {STRING.gen} između stanica {STRING} i {STRING} zarada će vredeti četvorostruko više u narednih godinu dana! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}{TOWN} - haos na ulicama!{}{}Program rekonstrukcije puteva sponzorisan od strane preduzeća {STRING} donosi vozačima 6 meseci agonije! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Prevoznički monopol! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}Vlasti grada {TOWN} su potpisale ugovor sa preduzećem {STRING} o ekskluzivnom pravu prevoza na godinu dana! # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Pogled{COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Premesti u pogled STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Premešta pogled na trenutnu poziciju glavnog pogleda STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Prebaci se STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Premešta glavni pogled na lokaciju na kojoj je ovaj pogled # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Opcije STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Valuta STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Izbor valute ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :Funta (GBP) STR_GAME_OPTIONS_CURRENCY_USD :Dolar (USD) STR_GAME_OPTIONS_CURRENCY_EUR :Euro (EUR) STR_GAME_OPTIONS_CURRENCY_JPY :Jen (JPY) STR_GAME_OPTIONS_CURRENCY_ATS :Austrijski Šiling (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :Belgijski Franak (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :Švajcarski Franak (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :Češka Kruna (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :Nemačka Marka (DEM) STR_GAME_OPTIONS_CURRENCY_DKK :Danska Kruna (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :Španska Pezeta (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :Finska Marka (FIM) STR_GAME_OPTIONS_CURRENCY_FRF :Francuski Franak (FRF) STR_GAME_OPTIONS_CURRENCY_GRD :Grčka Drahma (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :Mađarska Forinta (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :Islandska Kruna (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :Italijanska Lira (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :Holandski Gulden (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :Norveška Kruna (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Poljski Zlot (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Rumunski Lej (RON) STR_GAME_OPTIONS_CURRENCY_RUR :Ruska Rublja (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Slovenački Tolar (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Švedska Kruna (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Turska Lira (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :Slovačka Kruna (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :Brazilski Real (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :Estonska Kruna (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Litvanski Litas (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :Južnokorejski Von (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :Južnoafrički Rand (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :Sopstvena... STR_GAME_OPTIONS_CURRENCY_GEL :Gruzijski Lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iranski Rijal (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Drumska vozila STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Izaberi stranu puta kojom će se kretati drumska vozila STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Levom stranom STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Desnom stranom STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Imena naselja STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Izaberi stil imena gradova ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :Engleska (Originalna) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :Francuska STR_GAME_OPTIONS_TOWN_NAME_GERMAN :Nemačka STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :Engleska (Dodatna) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latinoamerička STR_GAME_OPTIONS_TOWN_NAME_SILLY :Šašava STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Švedska STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Holandska STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finska STR_GAME_OPTIONS_TOWN_NAME_POLISH :Poljska STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovačka STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norveška STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Mađarska STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Austrijanska STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Rumunska STR_GAME_OPTIONS_TOWN_NAME_CZECH :Češka STR_GAME_OPTIONS_TOWN_NAME_SWISS :Švajcarska STR_GAME_OPTIONS_TOWN_NAME_DANISH :Danska STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Turska STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Italijanska STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Katalonska ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Auto čuvanje pozicije STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Izbor vremenskog intervala između dve automatski sačuvane pozicije ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Isključeno STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Svakog meseca STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :Svaka 3 meseca STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :Svakih 6 meseci STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Svakih 12 meseci ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}Jezik STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Odaberite jezik koji će se koristiti STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Ceo ekran STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Pritisnite ovde kako biste igrali OpenTTD na celom ekranu STR_GAME_OPTIONS_RESOLUTION :{BLACK}Veličina ekrana STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Odaberite željenu veličinu ekrana STR_GAME_OPTIONS_RESOLUTION_OTHER :drugo STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Veličina interfejsa STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Izaberite većinu elementa koja će se koristiti STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normalna veličina STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Uvećavajte veličinu dva puta STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Uvećavajte veličinu četiri puta STR_GAME_OPTIONS_BASE_GRF :{BLACK}Osnovni skup grafika STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Odaberite željeni skup osnovnih grafika STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} datotek{P a e a} nedostaj{P e u e}/neispravn{P a o o} STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Dodatni podaci o osnovnom skupu grafika STR_GAME_OPTIONS_BASE_SFX :{BLACK}Osnovni skup zvukova STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Odaberite željeni skup osnovnih zvukova STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Dodatni podaci o osnovnom skupu zvukova STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Osnovni skup muzike STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Odaberite željeni skup osnovne muzike STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} oštećen{P a e ih} datotek{P a e a} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Dodatni podaci o osnovnom skupu muzike STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Neuspešno dobijanje spiska podržanih rezolucija STR_ERROR_FULLSCREEN_FAILED :{WHITE}Neuspešno prebacivanje u ceo ekran # Custom currency window STR_CURRENCY_WINDOW :{WHITE}Sopstvena moneta STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Devizni kurs: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Smanjite vrednost vaše monete u odnosu na jednu funtu (£) STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Povećajte vrednost vaše monete u odnosu na jednu funtu (£) STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Postavite vrednost vaše monete u odnosu na jednu funtu (£) STR_CURRENCY_SEPARATOR :{LTBLUE}Razdelnik: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Postavite razdelnik za vašu monetu STR_CURRENCY_PREFIX :{LTBLUE}Prefiks: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Postavite prefiks za vašu monetu STR_CURRENCY_SUFFIX :{LTBLUE}Sufiks: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Postavite sufiks za vašu monetu STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Prelazak na Euro: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Prelazak na Euro: {ORANGE}nikada STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Odredite godinu za prelazak na euro STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Raniji prelazak na euro STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Kasniji prelazak na euro STR_CURRENCY_PREVIEW :{LTBLUE}Primer: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 funti (£) u vašoj moneti STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Promena parametara sopstvene monete STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Najveći broj suparnika: {ORANGE}{COMMA} STR_NONE :Nijedan STR_FUNDING_ONLY :Samo finansiranje STR_MINIMAL :Najmanji STR_NUM_VERY_LOW :Veoma mali STR_NUM_LOW :Mali STR_NUM_NORMAL :Normalan STR_NUM_HIGH :Veliki STR_NUM_CUSTOM :Podešen STR_NUM_CUSTOM_NUMBER :Prilagođeno ({NUM}) STR_VARIETY_NONE :Neizmenjena STR_VARIETY_VERY_LOW :Veoma Mala STR_VARIETY_LOW :Mala STR_VARIETY_MEDIUM :Srednja STR_VARIETY_HIGH :Velika STR_VARIETY_VERY_HIGH :Veoma Velika STR_AI_SPEED_VERY_SLOW :jako spora STR_AI_SPEED_SLOW :spora STR_AI_SPEED_MEDIUM :srednja STR_AI_SPEED_FAST :brza STR_AI_SPEED_VERY_FAST :jako brza STR_SEA_LEVEL_VERY_LOW :Vrlo nizak STR_SEA_LEVEL_LOW :Nizak STR_SEA_LEVEL_MEDIUM :Srednji STR_SEA_LEVEL_HIGH :Visok STR_SEA_LEVEL_CUSTOM :Prilagođen STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Prilagođen ({NUM}%) STR_RIVERS_NONE :Nijedna STR_RIVERS_FEW :Nekoliko STR_RIVERS_MODERATE :Prosečno STR_RIVERS_LOT :Mnogo STR_DISASTER_NONE :nema STR_DISASTER_REDUCED :redukovani STR_DISASTER_NORMAL :normalni STR_SUBSIDY_X1_5 :x1.5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 STR_TERRAIN_TYPE_VERY_FLAT :Ravničarski STR_TERRAIN_TYPE_FLAT :Brdski STR_TERRAIN_TYPE_HILLY :Brdsko-planinski STR_TERRAIN_TYPE_MOUNTAINOUS :Planinski STR_TERRAIN_TYPE_ALPINIST :Planinar STR_CITY_APPROVAL_PERMISSIVE :Popustljiv STR_CITY_APPROVAL_TOLERANT :Tolerantan STR_CITY_APPROVAL_HOSTILE :Neprijateljski STR_WARNING_NO_SUITABLE_AI :{WHITE}Nisu dostupne odgovarajuće VI...{}Možete preuzeti nekoliko VI preko sistema za preuzimanje dodataka # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Podešavanja STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtriraj po: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Proširi sve STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Skupi sve STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(nema objašnjenja) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Podrazumevana vrednost: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Vrsta podešavanja: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Klijentska podešavanja (ne čuvaju se prilikom snimanja; utiču na sve igre) STR_CONFIG_SETTING_TYPE_GAME_MENU :Podešavanja igre (čuvaju se prilikom snimanja; utiču samo na nove igre) STR_CONFIG_SETTING_TYPE_GAME_INGAME :Podešavanja igre (čuvaju se prilikom snimanja; utiču samo na tekuću igru) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Podešavanja preduzeća (čuvaju se prilikom snimanja; utiču samo na nove igre) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Podešavanja preduzeća (čuvaju se prilikom snimanja; utiču samo tekuće preduzeće) STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Ograničava donju listu tako da prikazuje samo promenjena podešavanja STR_CONFIG_SETTING_RESTRICT_BASIC :Osnovna podešavanja STR_CONFIG_SETTING_RESTRICT_ADVANCED :Napredna podešavanja STR_CONFIG_SETTING_RESTRICT_ALL :Ekspertska / sva podešavanja STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Podešavanja sa vrednošću različitom od podrazumevane STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Podešavanja sa vrednošću različitom od vrednosti za novu igru STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Ograničava donju listu na određen tip podešavanja STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :Tipovi svih podešavanja STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Podešavanja klijenta (nisu uskladištena u sačuvanoj igri; utiču na sve partije) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Podešavanja igre (biće uskladištena u sačuvanoj igri; ima efekta samo na nove partije) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Podešavanja igre (biće uskladištena u sačuvanoj igri; ima efekta samo na nove partije) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Kompanijska podešavanja (biće uskladištena u sačuvanoj igri; ima efekta samo na nove partije) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Podešavanja kompanije (uskladištena u sačuvanoj igri; utiču samo na trenutnu kompaniju) STR_CONFIG_SETTING_OFF :Ne STR_CONFIG_SETTING_ON :Da STR_CONFIG_SETTING_DISABLED :isključeno STR_CONFIG_SETTING_COMPANIES_OFF :Ne STR_CONFIG_SETTING_COMPANIES_OWN :Za svoje preduzeće STR_CONFIG_SETTING_COMPANIES_ALL :Za sva preduzeća STR_CONFIG_SETTING_NONE :Nema STR_CONFIG_SETTING_ORIGINAL :Originalna STR_CONFIG_SETTING_REALISTIC :Realistična STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Levo STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Sredina STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Desno STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Najveći zajam na početku: {STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Najveći iznos koji preduzeće može da pozajmi (ne uzimajući u obzir inflaciju) STR_CONFIG_SETTING_INTEREST_RATE :Kamatna stopa: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Kamatna stopa na zajam; ako je omogućena, kontroliše inflaciju STR_CONFIG_SETTING_RUNNING_COSTS :Rashod: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Podesi cene za održavanje i radni proces vozila i infrastrukture STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Brzina gradnje: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Ograniči količinu akcija gradnje za VI STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Kvarovi vozila: {STRING} STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Koliko često mogu da se pokvare neodgovarajuće servisirana vozila STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Množilac subvencije: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Podešava koliko se plaća za subvencionisane konekcije STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Troškovi gradnje: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Podešava nivo troškova gradnje i kupovine STR_CONFIG_SETTING_RECESSIONS :Recesije: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Ako je omogućeno, recesije mogu da se jave svakih nekoliko godina. Proizvodnja je značajno smanjena tokom recesije (vraća se na prethodni nivo kada se recesija završi) STR_CONFIG_SETTING_TRAIN_REVERSING :Onemogući okretanje voza u stanicama: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Ako je uključeno i ako postoji kraća putanja do sledećeg odredišta, vozovi se neće okretati u neterminalnim stanicama STR_CONFIG_SETTING_DISASTERS :Katastrofe: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Uključuje i isključuje katastrofe koje s vremena na vreme mogu blokirati ili uništiti vozila i infrastrukturu STR_CONFIG_SETTING_CITY_APPROVAL :Stav gradskog odbora u pogledu restrukturiranja zone: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Izbor koliko će buka i zagađenje koje proizvode kompanije uticati na njihov gradski rejting i dalje građevinske akcije u toj zoni STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Maksimalna visina mape: {STRING} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Namestite dozvoljen maksimum visine planina na ovoj mapi STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Ne mozete namestiti maksimalnu visinu mape ovoj vrednosti. Barem još jedna planina je veća STR_CONFIG_SETTING_AUTOSLOPE :Dozvoljena izmena nagiba ispod zgrada, koloseka, itd. (autoslope): {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Dozvoli iskopavanja ispod građevina i pruge bez da se uklone STR_CONFIG_SETTING_CATCHMENT :Realističnije veličine prihvatnih površina: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Drugačije veličine podnožja za različite vrste stanica i aerodroma STR_CONFIG_SETTING_EXTRADYNAMITE :Dozvoljeno uklanjanje više gradskih kolovoza, mostova i tunela: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Olakšava uklanjanje infrastrukture i zgrada u gradskom vlasništvu STR_CONFIG_SETTING_TRAIN_LENGTH :Najveća dužina vozova: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Podešava najveću dužinu vozova STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} pločic{P a e a} STR_CONFIG_SETTING_SMOKE_AMOUNT :Količina dima/varnica vozila: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Podešava količinu dima ili varnica koje emituju vozila STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Model ubrzavanja vozova: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Bira fizički model za ubrzanje vozova. "Originalni" model ima istovetni penal na usponima za sa vozila. "Realistični" model ima različit penal u zavisnosti od osobina kompozicije poput dužine i sile potrebne za pokretanje voza STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Model ubrzavanja drumskih vozila: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Bira fizički model za ubrzanje drumskih vozila. "Originalni" model ima istovetni penal na usponima za sa vozila. "Realistični" model ima različit penal u zavisnosti od osobina motora i sile potrebne za pokretanje vozila STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Nagib uspona za vozove: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Nagib uspona za voz. Veće vrednosti čine težim penjanje uzbrdo STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Nagib uspona za drumska vozila: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Nagib uspona za drumsko vozilo. Veće vrednosti čine težim penjanje uzbrdo STR_CONFIG_SETTING_FORBID_90_DEG :Zabranjeno okretanje brodova i vozova za 90 stepeni: {STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :Okretanje za 90 stepeni se dešava kada se uspravna pruga nalazi odmah posle vodoravne pruge na susednoj pločici i time čini da voz skreće pod 90 stepeni kad prelazi sa pločice na pločicu, umesto uobičajenih 45 stepeni kod drugih kombinacija pruge. Ovo takođe važi i za radijus zaokreta brodova STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Dozvoljeno sjedinjavanje udaljenih stanica: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Dozvoljava dodavanje delova stanici bez da oni dodiruju postojeće delove stanice. Zahteva Ctrl+Klik kod postavljanja novih delova STR_CONFIG_SETTING_INFLATION :Inflacija: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Omogućuje inflaciju tako da troškovi rastu malo brže od isplata STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Najveća dužina mosta: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Maksimalna dužina za podizanje mostova STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Najveća visina mosta: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Maksimalna visina za dradjenje mostova STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Najveća dužina tunela: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Maksimalna dužina za iskopavanje tunela STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Metod izgradnje finansiranih primarnih industrija: {STRING} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Način izgradnje primarnih industrija. 'nikakav' znači da finansiranje nije moguće, 'istraživački' znači da jeste moguće ali se izgradnja odvija na slučajnom mestu na karti i može da ne uspe, 'uobičajen' znači da preduzeća mogu da postave primarnu industriju na bilo koju poziciju na karti STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :nikakav STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :uobičajen STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :istraživački STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Ravna površina oko industrija: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Količina ravne površine u okružini jedne industrije. Ovo osigurava da će u okolini industrije biti dovoljno slobodnog mesta za konstrukciju pruga, i tako dalje. STR_CONFIG_SETTING_MULTIPINDTOWN :Dozvoljeno više industrija iste vrste na teritoriji jednog naselja: {STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Naselje uobičajeno ne dozvoljava više industrija iste vrste. Sa ovim podešavanjem će biti dozvoljeno više industrija iste vrste na teritoriji jednog naselja STR_CONFIG_SETTING_SIGNALSIDE :Prikaži signale: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Odaberi na kojoj strani koloseka se postavlja signalizacija STR_CONFIG_SETTING_SIGNALSIDE_LEFT :Na levoj STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :Na strani na kojoj se vozi STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :Na desnoj STR_CONFIG_SETTING_SHOWFINANCES :Prikazivanje finansijskog stanja na kraju godine: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Ako je omogućeno, na kraju svake godine će se prikazati prozor sa finansijskim stanjem što omogućava lakše praćenje finansija preduzeća STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Nove naredbe su postavljene sa 'direktno': {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Vozilo će uobičajeno stati u svakoj stanici kroz koju prolazi. Ako se ovo podešavanje omogući, vozilo će samo proći kroz stanicu bez zaustavljanja sve do krajnje stanice. Ovo podešavanje menja samo podrazumevanu vrednost za nove naredbe. Pojedinačne naredbe mogu da imaju i jedno i drugo ponašanje STR_CONFIG_SETTING_STOP_LOCATION :Nove naredbe zaustavljaju voz na {STRING} stanice STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Mesto gde će se voz zaustaviti u stanici. 'početak' znači blizu ulaska, 'sredina' znači na sredini platforme a 'kraj' znači najdalje od ulaska. Ovo podešavanje menja samo podrazumevanu vrednost za nove naredbe. Pojedinačne naredbe za vozove mogu da imaju bilo koje od ova tri ponašanja STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :početak STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :sredina STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :kraj STR_CONFIG_SETTING_AUTOSCROLL :Pomeranje prozora kada miš priđe ivicama: {STRING} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Ako je omogućeno, prikaz će početi da skroluje kada je kursor miša blizu ivice prozora STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Isključeno STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Glavni prikaz, samo u režimu preko celog ekrana STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Glavni prikaz STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Svaki prikaz STR_CONFIG_SETTING_BRIBE :Dozvoljeno podmićivanje lokalnih vlasti: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Dozvoljava preduzećima da pokušaju da podmite lokalne vlasti. Ako inspektor primeti podmićivanje, preduzeće neće moći da deluje u naselju sledećih šest meseci STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Dozvoljena kupovina ekskluzivnih prava prevoza: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Ako preduzeće kupi ekskluzivna prava prevoza u naselju, protivničke stanice neće primati nikakav tovar ni putnike cele godine STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Dozvoljeno finansiranje zgrada: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Dozvoljava preduzećima da naselju daju novac za gradnju novih kuća STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Dozvoljeno finansiranje rekonstrukcije lokalnih puteva: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Dozvoljava preduzećima da daju novac naseljima za rekonstrukciju puteva kako bi sabotirali drumski saobraćaj STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Dozvoljeno slanje novca drugim preduzećima: {STRING} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Dozvoljava prenos novca između preduzeća u modu za više igrača STR_CONFIG_SETTING_FREIGHT_TRAINS :Množilac težine tovara za simulaciju opterećenja vozova: {STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Podesi uticaj nošenje tereta u vozovima. Veća vrednost čini nošenje tereta zahtevniji za vozove, posebno na brdima STR_CONFIG_SETTING_PLANE_SPEED :Faktor brzine aviona: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Postavlja brzinu aviona relativno u odnosu na druge vrste vozila kako bi se ograničio prihod od avio saobraćaja STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Broj avionskih nesreća: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Postavlja šansu da se dogodi avionska nesreća STR_CONFIG_SETTING_PLANE_CRASHES_NONE :nikakav STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :umanjen STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :normalan STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Dozvoljene ulične stanice na kolovozima u vlasništvu naselja: {STRING} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Dozvoljava izgradnju protočnih drumskih stanica na putevima čiji je vlasnik naselje STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Dozvoljene ulične stanice na kolovozima u vlasništvu drugih preduzeća: {STRING} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Dozvoljava izgradnju protočnih drumskih stanica na putevima čiji je vlasnik drugo preduzeće STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Promena ovog podešavanja nije moguća dok postoje vozila STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Održavanje infrastrukture: {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Ako je omogućeno, infrastruktura će imati troškove održavanja. Trošak raste brže sa porastom veličine putne mreže i time više pogađa veća preduzeća od manjih STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Nezastarevanje aerodroma: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Omogućavanje ovog podešavanja čini svaki tip aerodroma zauvek pristupan nakon njegovog uvođenja STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Upozorenje ukoliko se vozilo izgubi: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Prikazuje poruke o vozilima koja ne mogu da nađu put do odredišta STR_CONFIG_SETTING_ORDER_REVIEW :Provera naredbi vozila: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Kada je omogućeno, naređenja vozila se periodično proveravaju, i neke jasne probleme su izveštavane sa vestnom porukom kada su detektovane STR_CONFIG_SETTING_ORDER_REVIEW_OFF :nijedno STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :da, osim zaustavljenih vozila STR_CONFIG_SETTING_ORDER_REVIEW_ON :svih vozila STR_CONFIG_SETTING_WARN_INCOME_LESS :Upozorenje ukoliko vozilo pravi gubitke: {STRING} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :Ako je omogućeno, šalje vest kada vozilo u toku kalendarske godine nije ostvarilo zaradu STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Vozila nikad ne zastarevaju: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :Ako je omogućeno, svi modeli vozila ostaju zauvek dostupni (posle njihovog predstavljanja) STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Automatska zamena kada vozilo ostari: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :Kada je omogućeno, vozilo blizu kraja života će se automatski zameniti kada su ispunjeni uslovi obnavljanja STR_CONFIG_SETTING_AUTORENEW_MONTHS :Automatska zamena kada je vozilo staro najviše {STRING} STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Starost vozila pri kojoj postaje kandidat za automatsku zamenu STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} mesec{P "" a i} pre STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} mesec{P "" a i} posle STR_CONFIG_SETTING_AUTORENEW_MONEY :Najmanja potrebna količina novca za zamenu: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Najmanji iznos novca koji mora ostati u banci pre automatskog obnavljanja vozila STR_CONFIG_SETTING_ERRMSG_DURATION :Trajanje poruke o greški: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Trajanje prikazivanja poruka o greškama u crvenom prozoru. Neke (kritične) poruke o greškama se ne zatvaraju automatski posle ovog vremena nego moraju da se zatvore ručno STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} sekund{P a e i} STR_CONFIG_SETTING_HOVER_DELAY :Prikaži poruke u balončićima: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Desni klik STR_CONFIG_SETTING_POPULATION_IN_LABEL :Prikazivati br. stanovnika pored naziva naselja: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Prikazuje broj stanovnika naselja na njihovoj oznaci na karti STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Debljina linija u grafikonima: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Širina linije na grafiku. Tanka linija je preciznija a debelu je lakše videti i lakše je razlikovati boje STR_CONFIG_SETTING_LAND_GENERATOR :Oblikovanje reljefa: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Originalno STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Najveće rastojanje od ivice za Rafinerije Nafte: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Nivo snežnog pokrivača: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Vrste terena (samo za TerraGenesis) : {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Ravnomerna STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Malo valovita STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Valovita STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Vrlo valovita STR_CONFIG_SETTING_TREE_PLACER :Posađivanje drveća: {STRING} STR_CONFIG_SETTING_TREE_PLACER_NONE :Nikakav STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Originalni STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Unapređen STR_CONFIG_SETTING_ROAD_SIDE :Drumskih vozila: {STRING} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Odaberite stranu saobraćaja STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Orijentacija elevacione karte: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Nalevo STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Nadesno STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :Visina ravnog terena je: {STRING} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}Jedan ili više sektora na severnoj ivici nije prazan STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}Jedan ili više sektora na jednoj od ivica nije voda STR_CONFIG_SETTING_SERVICEATHELIPAD :Automatsko servisiranje helikoptera na heliodromima: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Servisiraj helikoptere posle svakog sletanja, čak i kada nema depoa na aerodromu STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Poveži traku alatki za reljef sa železničkim/drumskim/brodskim/avionskim trakama: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Boja tla na karti: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Boja terena na karti STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Zelena STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Tamno zelena STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Ljubičasta STR_CONFIG_SETTING_REVERSE_SCROLLING :Suprotan smer pomeranja prozora: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING :Ravnomeran prelaz prozora: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP :Prikazivati mere dok se koriste alati za gradnju: {STRING} STR_CONFIG_SETTING_LIVERIES :Prikazivati boje preduzeća: {STRING} STR_CONFIG_SETTING_LIVERIES_NONE :Ne STR_CONFIG_SETTING_LIVERIES_OWN :Samo sopstvene STR_CONFIG_SETTING_LIVERIES_ALL :Svih STR_CONFIG_SETTING_PREFER_TEAMCHAT :Slanje poruka svojoj ekipi sa : {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Uloga točkića na mišu: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Omogući skrolovanje sa dvodimenzionalnim točkićima na mišu STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Promena uvećanja terena STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Pomeranje terena STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Nikakva STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Osetljivost točkića: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Kontroliše osetljivost skrolovanja preko točkića na mišu STR_CONFIG_SETTING_OSK_ACTIVATION :Tastatura na ekranu: {STRING} STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Onemogućeno STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Dupli klik STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Klik (ako je u fokusu) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Klik (odmah) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Oponašanje desnog klika: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command+Klik STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+Klik STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Nikakvo STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Pomeranje sa levim klikom: {STRING} STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Koristiti {STRING} oblik datuma u nazivima sačuvanih partija STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Format datuma u imenima fajlova sačuvanih partija STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :dugačak (31st Dec 2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :kratak (31-12-2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Pauzirati odmah po pokretanju nove partije : {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Tokom pauze dozvoljene su: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :nikakve aktivnosti STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :sve negrađevinske aktivnosti STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :sve aktivnosti sem izmene reljefa STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :sve aktivnosti STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Koristiti napredan spisak vozila: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS :Koristiti pokazatelj utovarivanja: {STRING} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Prikazati red vožnje u diskretnim otkucajima: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Prikazivanje polaska i dolaska u rasporedima: {STRING} STR_CONFIG_SETTING_QUICKGOTO :Zadržati aktivno 'Idi do' dugme: {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Podešena vrsta pruge (posle učitavanja/nove partije): {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :Prva dostupna STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Zadnja dostupna STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Najčešće korišćena STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Prikazivati rezervisane pruge: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Zadržati aktivne alate za gradnju posle upotrebe: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Ostavi alate za gradnju mostova, tunela itd. otvorene nakon korišćenja STR_CONFIG_SETTING_EXPENSES_LAYOUT :Grupisati troškove u finansijskom prozoru preduzeća: {STRING} STR_CONFIG_SETTING_SOUND_TICKER :Telegrafski zvuk: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Reprodukuj zvučne efekte pri prikazu sažetih novinskih poruka STR_CONFIG_SETTING_SOUND_NEWS :Novinski naslovi: {STRING} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Reprodukuj zvučne efekte prilikom prikazivanja novinskih naslova STR_CONFIG_SETTING_SOUND_NEW_YEAR :Kraj godine: {STRING} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Reprodukuj zvučne efekte prilikom ispisa rezultata poslovanja kompanije na kraju svake godine STR_CONFIG_SETTING_SOUND_CONFIRM :Izgradnja: {STRING} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Reprodukuj zvučne efekte pri uspešnoj izgradnji i sličnim akcijama STR_CONFIG_SETTING_SOUND_CLICK :Klik na tastere: {STRING} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Reprodukuj zvuk prilikom klika na tastere STR_CONFIG_SETTING_SOUND_DISASTER :Nezgode/katastrofe: {STRING} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Reprodukuj zvučne efekte nezgoda i katastrofa STR_CONFIG_SETTING_SOUND_VEHICLE :Vozila: {STRING} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Reprodukuj zvučne efekte vozila STR_CONFIG_SETTING_SOUND_AMBIENT :Okruženje: {STRING} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Reprodukuj ambijentalne zvučne efekte za teren, industrije i gradove STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Onemogućena izgradnja infrastrukture kada nema odgovarajućih vozila: {STRING} STR_CONFIG_SETTING_MAX_TRAINS :Najviše vozova po preduzeću: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Najveći broj vozova koje preduzeće može da ima STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Najviše drumskih vozila po preduzeću: {STRING} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Najveći broj drumskih vozila koje preduzeće može da ima STR_CONFIG_SETTING_MAX_AIRCRAFT :Najviše letilica po preduzeću: {STRING} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Najveći broj letilica koje preduzeće može da ima STR_CONFIG_SETTING_MAX_SHIPS :Najviše brodova po preduzeću: {STRING} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Najveći broj brodova koje preduzeće može da ima STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Računar ne može da koristi železnički prevoz: {STRING} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Omogućavanje ovog podešavanja znači da računar ne može da stvara vozove STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Računar ne može da koristi drumski prevoz: {STRING} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Omogućavanje ovog podešavanja znači da računar ne može da stvara drumska vozila STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Računar ne može da koristi vazdušni prevoz: {STRING} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Omogućavanje ovog podešavanja znači da računar ne može da stvara letilice STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Računar ne može da koristi vodni prevoz: {STRING} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Omogućavanje ovog podešavanja znači da računar ne može da stvara brodove STR_CONFIG_SETTING_AI_PROFILE :Podrazumevani profil podešavanja: {STRING} STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Odaberi koji profil podešavanja se koristi za proizvoljne VI ili za početne vrednosti kada se dodaje nova AI ili skript STR_CONFIG_SETTING_AI_PROFILE_EASY :Lak STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Srednji STR_CONFIG_SETTING_AI_PROFILE_HARD :Težak STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Dozvoljena VI u mrežnoj partiji: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Dozvoljava računarskoj VI da učestvuje u mrežnoj partiji STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :Suspendovanje #opkodova pre skripti: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Najveći broj koraka računanja koje skript može da izvede u jednom krugu STR_CONFIG_SETTING_SERVINT_ISPERCENT :Intervali servisiranja u procentima: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Da li se intervali servisiranja vozila okidaju vremenom proteklim od prošlog servisiranja ili padom pouzdanosti za određeni procenat u odnosu na najveću pouzdanost STR_CONFIG_SETTING_SERVINT_TRAINS :Podrazumevani servisni interval za vozove: {STRING} STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA} dan{P 0 "" a a}/% STR_CONFIG_SETTING_SERVINT_DISABLED :Onemogućeno STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Podrazumevani servisni interval za drumska vozila: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Podrazumevani servisni interval za letilice: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS :Podrazumevani servisni interval za brodove: {STRING} STR_CONFIG_SETTING_NOSERVICE :Isključeno servisiranje kada ne postoje kvarovi: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Uključeno ograničenje brzine kod vagona: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS :Ne postoji posebna električna pruga: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Dolazak prvog vozila na igračevu stanicu: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Prikazuje novinske naslove kada prvo vozilo pristigne u novu stanicu igrača STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Dolazak prvog vozila na suparničku stanicu: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Prikazuje novinske naslove kada prvo vozilo pristigne u konkurentsku novu stanicu STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Udesi/nepogode: {STRING} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Prikazuje novinske naslove kada se dese nezgode ili katastrofe STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Podaci o preduzeću: {STRING} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Prikazuje novinske naslove kada se otvori nova kompanija, ili kada postojeća rizikuje bankrot STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Otvaranje nove fabrike: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Prikazuje novinske naslove kada se otvori nova fabrika STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Zatvaranje fabrike: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Prikazuje novinske naslove o zatvaranju fabrika STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Promene u ekonomiji: {STRING} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Prikazuje novinske naslove o globalnim ekonomskim promenama STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Promene u proizvodnji usluženih industrija: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Prikazuje novinske naslove kada se promeni nivo proizvodnje u industriji koju naša kompanija pokriva STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Promene u proizvodnji industrija usluženih konkurencijom: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Prikazuje novinske naslove kada se promeni nivo proizvodnje u industriji koju konkurencija pokriva STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Promene u proizvodnji ostalih industrija: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Prikazuje novinske naslove kada se promeni nivo proizvodnje u industriji koju ne pokriva ni naša kompanija, ni konkurencija STR_CONFIG_SETTING_NEWS_ADVICE :Savet / Izveštaji o vozilima preduzeća: {STRING} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Prikaži poruke o događajima na vozilima koji zahtevaju intervenciju STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :Nova vozila: {STRING} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Prikazuje novinske naslove kada postane dostupan novi tip vozila STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Promene u prihvatanju tovara: {STRING} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Prikaži poruke kada stanice promene tip prijema robe i putnika STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subvencije: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Prikazuje novinske naslove o događajima u vezi sa subvencijama STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :Opšta obaveštenja: {STRING} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Prikazuje novinske naslove o opštim događajima, kao što su kupovina ekskluzivnih prava ili finansiranje rekonstrukcije puteva STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :Isključeno STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Sažeto STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Potpuno STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Vesti u boji se objavljuju počev od godine: {STRING} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Godina počev od koje se vesti objavljuju u boji. Pre ove godine se objavljuju u crno/beloj tehnici. STR_CONFIG_SETTING_STARTING_YEAR :Početna godina: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Uključena glatka ekonomija (više, manjih promena): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Ako je omogućeno, industrijska proizvodnja se češće menja u manjim koracima. Ako se vrste industrija učitavaju preko NewGRF dodataka ovo podešavanje uglavnom nema efekta STR_CONFIG_SETTING_ALLOW_SHARES :Dozvoljena kupovina deonica drugih preduzeća: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Ako je omogućeno, dozvoljava kupovinu i prodaju deonica preduzeća. Deonice su dostupne tek kad preduzeće dostigne određenu starost STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Prilikom prevlačenja, postavi signale na svakih: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} pločic{P 0 u e e} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Prilikom prevlačenja, čuvaj fiksno rastojanje između signala: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Automatsko postavljanje semafora do: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Omogućena traka za signalizaciju:{STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Uobičajena vrsta signalizacije za izgradnju: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Podrazumevani tip signala STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Blok signalizacija STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Putna signalizacija STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :Jednosmerna putna signalizacija STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Ciklični izbor vrste signalizacije: {STRING} STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Samo blok STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Samo putna STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :Sva STR_CONFIG_SETTING_TOWN_LAYOUT :Plan gradnje novih puteva u naseljima: {STRING} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Menja način izgradnje puteva u naseljima STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :originalno STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :unapređeni putevi STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 mreže STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 mreže STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :proizvoljan plan STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Naseljima je dozvoljeno da grade kolovoze: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Naseljima je dozvoljeno da grade putne prelaze: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Omogućava naseljima da grade prelaz pruge preko puta STR_CONFIG_SETTING_NOISE_LEVEL :Naseljima je dozvoljeno da kontrolišu nivo buke aerodroma: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :Ako je ovo podešavanje onemogućeno mogu postojati 2 aerodroma u svakom naselju. Ako je podešavanje omogućeno, broj aerodroma u gradu je ograničen dozvoljenim nivoom buke u gradu koji zavisi od populacije i od veličine i udaljenosti aerodroma STR_CONFIG_SETTING_TOWN_FOUNDING :Osnivanje naselja u toku partije: {STRING} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Dozvoljava igračima osnivanje novih naselja u toku igre STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :zabranjeno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :dozvoljeno STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :dozvoljeno, zaseban plan gradnje STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Rasejavanje drveća tokom partije: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :{G=srednji}nikakvo {RED}(onesposobljava rad drvnih kombinata) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :samo u tropskim šumama STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :svuda STR_CONFIG_SETTING_TOOLBAR_POS :Lokacija glavne trake sa alatima: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horizontalna pozicija glavne trake s alatkama na vrhu ekrana STR_CONFIG_SETTING_STATUSBAR_POS :Položaj statusne linije: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Horizontalna pozicija statusne linije na dnu ekrana STR_CONFIG_SETTING_SNAP_RADIUS :Udaljenost na kojoj će prozor da se prilepi uz susedni: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} piksel{P 0 "" a a} STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Isključeno STR_CONFIG_SETTING_SOFT_LIMIT :Najviše nepridenutih prozora: {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_ZOOM_MIN :Najbliži nivo: {STRING} STR_CONFIG_SETTING_ZOOM_MAX :Najudaljeniji nivo: {STRING} STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Uobičajen STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x STR_CONFIG_SETTING_TOWN_GROWTH :Brzina razvoja naselja: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Brzina kojom se naselje razvija STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Nimalo STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Sporo STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normalno STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Brzo STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Veoma brzo STR_CONFIG_SETTING_LARGER_TOWNS :Odnos naselja koja će postati gradovi: {STRING} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Broj naselja koja će postati gradovi i time počinju veća od ostalih i brže rastu STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 u {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :Nijedan STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Inicijalni množilac razvoja gradova: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Prosečna veličina naselja relativno u odnosu na gradove na početku partije STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :ručno STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimetrično STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simetrično STR_CONFIG_SETTING_DEMAND_DISTANCE :Uticaj daljine na zahteve: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Ako podesite ovu vrednost veće od 0, daljina između porekla stanice A nekog tereta i moguće destinacije B će imati uticaj na iznos poslatog tereta od A do B. Što daljnije B je od A, smaniće se iznos tereta što će biti poslat. Ako vrednost povećavate, manji iznos tereta će biti poslat dalekim mestima i veći iznos tereta će biti poslat bližnjim stanicama. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Mere brzine: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Kada brzina bude pokazana u interfejsu, pokaži u željenoj meri STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperijalne mere (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metričke mere (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Mere za snagu vozila: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperijalne mere (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metričke mere (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Mere težine: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Kad težine budu pokazane u interfejsu, pokazi u željenoj meri STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperijalne (short t/ton) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metričke mere (t/toni) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Mere zapremine: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperijalne mere (gal) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metričke mere (l) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Mere za silu trenja: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperijalne mere (lbf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metričke mere (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Mere visine: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Kad visine budu pokazane u interfejsu, pokazi u željenoj meri STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperijalne mere (ft) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metričke mere (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Prevod STR_CONFIG_SETTING_SOUND :{ORANGE}Zvučni efekti STR_CONFIG_SETTING_INTERFACE :{ORANGE}Okruženje STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Izgradnja STR_CONFIG_SETTING_VEHICLES :{ORANGE}Vozila STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Rutiranje STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}Naselja STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Industrije STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Distribucija Tovara STR_CONFIG_SETTING_AI :{ORANGE}Suparnici STR_CONFIG_SETTING_AI_NPC :{ORANGE}Računar STR_CONFIG_SETTING_PATHFINDER_OPF :Originalno STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Preporučuje se) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Pretraživanje putanja vozova: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Algoritam pronalaženja puta za vozove STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Pretraživanje putanja drumskih vozila: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Algoritam pronalaženja puta za drumska vozila STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Pretraživanje putanja brodova: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Algoritam pronalaženja puta za brodove STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Automatska promena smera kod signalizacije: {STRING} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Dozvoljeno okretanje vozova na signalu, ako su dugo čekali STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Promena vrednosti # Config errors STR_CONFIG_ERROR :{WHITE}Greška sa konfiguracionom datotekom... STR_CONFIG_ERROR_ARRAY :{WHITE}... greška u nizu '{STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... neispravna vrednost '{STRING}' za '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... prateći karakteri na kraju podešavanja '{STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignorisanje NewGRF-a '{STRING}': identični GRF ID sa '{STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignorisanje neispravnog NewGRF-a '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :nije nađen STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :nesigurno za stalno korišćenje STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :sistem NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :nekompatibilno sa ovom OpenTTD verzijom STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :nepoznato STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... nivo kompresije '{STRING}' nije ispravan STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... format sačuvane partije '{STRING}' nije dostupan. Vraćanje na '{STRING}' STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Nema više memorije # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}Nova Partija STR_INTRO_LOAD_GAME :{BLACK}Učitavanje Partije STR_INTRO_PLAY_SCENARIO :{BLACK}Partija sa Scenarijom STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Partija sa Elevacionom kartom STR_INTRO_SCENARIO_EDITOR :{BLACK}Editor Scenarija STR_INTRO_MULTIPLAYER :{BLACK}Partija preko Mreže STR_INTRO_GAME_OPTIONS :{BLACK}Opcije STR_INTRO_HIGHSCORE :{BLACK}Tabela najboljih rezultata STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Podešavanja STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Podešavanja STR_INTRO_ONLINE_CONTENT :{BLACK}Spisak Dodataka na Mreži STR_INTRO_SCRIPT_SETTINGS :{BLACK}Podešavanja VI/Skripte Partije STR_INTRO_QUIT :{BLACK}Izađi STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Započinje novu partiju. Ctrl+Klik preskače konfiguraciju mape STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Učitavanje stare pozicije STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Pokreće novu partiju, koristeći elevacionu kartu kao teren STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Započinje novu partiju, koristeći prethodno napravljen scenario STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Kreiranje sveta/scenarija u igri po svom ukusu STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Pokreće mrežnu partiju sa više igrača STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Izbor umerenog klimatskog pojasa STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Izbor subpolarnog klimatskog pojasa STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Izbor suptropskog klimatskog pojasa STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Izbor 'zemlje igračaka' STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Prikazuje opcije igre STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Prikazuje tabelu najboljih rezultata STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Prikaži podešavanje STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Prikazuje NewGRF podešavanja STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Pregled novih i ažureiranih dodatka za preuzimanje STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Prikazuje podešavanja za VI/Skriptu partije STR_INTRO_TOOLTIP_QUIT :{BLACK}Napušta 'OpenTTD' STR_INTRO_TRANSLATION :{BLACK}Ovom prevodu nedostaje {NUM} nisk{P a e i}. Pomozite da OpenTTD bude bolji - prijavite se kao prevodilac. Za detalje pogledajte readme.txt. # Quit window STR_QUIT_CAPTION :{WHITE}Izlaz STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Da li ste sigurni da želite da napustite OpenTTD i vratite se u {STRING}? STR_QUIT_YES :{BLACK}Da STR_QUIT_NO :{BLACK}Ne # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Napuštanje partije STR_ABANDON_GAME_QUERY :{YELLOW}Da li stvarno želite da napustite ovu partiju? STR_ABANDON_SCENARIO_QUERY :{YELLOW}Da li ste sigurni da želite da izađete iz ovog scenarija? # Cheat window STR_CHEATS :{WHITE}Varanja STR_CHEATS_TOOLTIP :{BLACK}Štiklirano polje označava da ste i ranije koristili ovu opciju STR_CHEATS_WARNING :{BLACK}Upozorenje! Upravo ćete prevariti vaše saradnike. Imajte na umu da će takav loš postupak biti trajno upamćen STR_CHEAT_MONEY :{LTBLUE}Dodati još {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Upravljanje preduzećem: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magični buldožer (uklanja fabrike, nepokretnosti): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tuneli mogu da se ukrštaju: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Veliki avioni se neće (često) rušiti kod malih aerodorma: {ORANGE} {STRING} STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Promenite maksimalnu visinu mape: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Promenite maksimalnu visinu planina na mapi STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Umereni klimatski pojas STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Subpolarni klimatski pojas STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Suptropski klimatski pojas STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Zemlja igračaka STR_CHEAT_CHANGE_DATE :{LTBLUE}Promena datuma: {ORANGE} {DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Promena trenutne godine STR_CHEAT_SETUP_PROD :{LTBLUE}Dozvoliti promenu količine proizvodnje: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}Nova šema boja STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Prikaži generalnu mustru boja STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Prikaži mustre boja vozova STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Prikaži mustre boja drumskih vozila STR_LIVERY_SHIP_TOOLTIP :{BLACK}Prikaži mustre boja brodova STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Prikaži mustre boja letilica STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Izaberite osnovnu boju za označenu kategoriju. Ctrl+klik će izabrati ovu boju za sve kategorije STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Izaberite dodatnu boju za označenu kategoriju. Ctrl+klik će izabrati ovu boju za sve kategorije STR_LIVERY_PANEL_TOOLTIP :{BLACK}Označite kategoriju za izmenu boje, ili više njih koristeći Ctrl+Klik. Kliknite na kvadratić kako biste aktivirali korišćenje boje STR_LIVERY_DEFAULT :Uobičajene Boje STR_LIVERY_STEAM :Parna Lokomotiva STR_LIVERY_DIESEL :Dizel Lokomotiva STR_LIVERY_ELECTRIC :Električna Lokomotiva STR_LIVERY_MONORAIL :Jednošinska Lokomotiva STR_LIVERY_MAGLEV :Maglev Lokomotiva STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Putnička Kola (Parna) STR_LIVERY_PASSENGER_WAGON_DIESEL :Putnička Kola (Dizel) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Putnička Kola (Električna) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Putnička Kola (Jednošinska) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Putnička Kola (Maglev) STR_LIVERY_FREIGHT_WAGON :Teretni Vagon STR_LIVERY_BUS :Autobus STR_LIVERY_TRUCK :Kamion STR_LIVERY_PASSENGER_SHIP :Putnički Brod STR_LIVERY_FREIGHT_SHIP :Teretni Brod STR_LIVERY_HELICOPTER :Helikopter STR_LIVERY_SMALL_PLANE :Mali Avion STR_LIVERY_LARGE_PLANE :Veliki Avion STR_LIVERY_PASSENGER_TRAM :Putnički Tramvaj STR_LIVERY_FREIGHT_TRAM :Teretni Tramvaj # Face selection window STR_FACE_CAPTION :{WHITE}Izbor lica STR_FACE_CANCEL_TOOLTIP :{BLACK}Poništi ovo lice STR_FACE_OK_TOOLTIP :{BLACK}Prihvati ovo lice STR_FACE_RANDOM :{BLACK}Proizvoljno STR_FACE_MALE_BUTTON :{BLACK}Muško STR_FACE_MALE_TOOLTIP :{BLACK}Izbor muškog lica STR_FACE_FEMALE_BUTTON :{BLACK}Žensko STR_FACE_FEMALE_TOOLTIP :{BLACK}Izbor ženskog lica STR_FACE_NEW_FACE_BUTTON :{BLACK}Novo lice STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Nasumično izabira novo lice STR_FACE_ADVANCED :{BLACK}Napredno STR_FACE_ADVANCED_TOOLTIP :{BLACK}Napredni odabir lica STR_FACE_SIMPLE :{BLACK}Jednostavno STR_FACE_SIMPLE_TOOLTIP :{BLACK}Jednostavan odabir lica STR_FACE_LOAD :{BLACK}Učitaj STR_FACE_LOAD_TOOLTIP :{BLACK}Učitavanje omiljenog lica STR_FACE_LOAD_DONE :{WHITE}Vaše omiljeno lice je učitano iz OpenTTD datoteke podešavanja STR_FACE_FACECODE :{BLACK}Redni broj lica STR_FACE_FACECODE_TOOLTIP :{BLACK}Pregled i/ili postavljanje rednog broja lica vlasnika preduzeća STR_FACE_FACECODE_CAPTION :{WHITE}Pregled i/ili postavljanje rednog broja lica vlasnika STR_FACE_FACECODE_SET :{WHITE}Novi redni broj lica je postavljen STR_FACE_FACECODE_ERR :{WHITE}Redni broj lica se ne može postaviti - vrednost mora biti broj između 0 i 4,294,967,295! STR_FACE_SAVE :{BLACK}Sačuvaj STR_FACE_SAVE_TOOLTIP :{BLACK}Čuvanje omiljenog lica STR_FACE_SAVE_DONE :{WHITE}Ovo lice će biti sačuvano kao omiljeno u OpenTTD datoteci podešavanja STR_FACE_EUROPEAN :{BLACK}Evropski STR_FACE_SELECT_EUROPEAN :{BLACK}Evropski izgled lica STR_FACE_AFRICAN :{BLACK}Afrički STR_FACE_SELECT_AFRICAN :{BLACK}Afrički izgled lica STR_FACE_YES :Da STR_FACE_NO :Ne STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Dodavanje brkova ili minđuša STR_FACE_HAIR :Kosa: STR_FACE_HAIR_TOOLTIP :{BLACK}Promena kose STR_FACE_EYEBROWS :Obrve: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Promena obrva STR_FACE_EYECOLOUR :Boja očiju: STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Promena boje očiju STR_FACE_GLASSES :Naočare: STR_FACE_GLASSES_TOOLTIP :{BLACK}Dodavanje naočara STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Promena naočara STR_FACE_NOSE :Nos: STR_FACE_NOSE_TOOLTIP :{BLACK}Promena nosa STR_FACE_LIPS :Usna: STR_FACE_MOUSTACHE :Brkovi: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Promena usana ili brkova STR_FACE_CHIN :Brada: STR_FACE_CHIN_TOOLTIP :{BLACK}Promena brade STR_FACE_JACKET :Sako: STR_FACE_JACKET_TOOLTIP :{BLACK}Promena dezena sakoa STR_FACE_COLLAR :Kragna: STR_FACE_COLLAR_TOOLTIP :{BLACK}Promena dezena kragne STR_FACE_TIE :Kravata: STR_FACE_EARRING :Minđuše: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Promena kravate ili minđuša # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Mrežna partija STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Ne STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Da STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ime igrača: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Sa ovim imenom će Vas drugi igrači (pre)poznavati STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Naziv STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Naziv partije STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Igrači STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Priključeno igrača / najviše igrača{}Aktivnia preduzeća / najviše preduzeća STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Veličina terena STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Veličina terena u partiji{}Klikom će se poređati po veličini STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Datum STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Trenutni datum u partiji STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Godina STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Ukupan broj godina{}koliko traje partija STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Jezik, verzija servera, itd. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Kliknite na partiju sa spiska da biste je obeležili STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Server na koji ste se priključili prošli put: STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Kliknite kako biste označili server na kome ste igrali prošli put STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}PODACI O PARTIJI STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Igrača: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Jezik: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Klima: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Veličina terena: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Verzija servera: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Adresa servera: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Početni datum: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Trenutni datum: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Zaštićeno šifrom! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVER JE VAN MREŽE STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}SERVER JE POPUNJEN STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}NEODGOVARAJUĆA VERZIJA STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF NEPOKLAPANJE STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Priključi se STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Ažuriranje servera STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Ažurirajte podatke sa servera STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Pronađi server STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Pretražuje mrežu kako bi pronašao servere STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Dodaj server STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Dodaje server na spisak na kojem se uvek proverava za aktivne partije STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Pokreni server STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Pokrenite sopstveni server STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Unesite Vaše ime STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Unesite adresu računara-servera # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}Pokreni novu mrežnu partiju STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Naziv partije: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Naziv partije će se prikazati na spisku izbora mrežnih partija drugih igrača STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Postavi lozinku STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Ukoliko ne želite da bude javno dostupna zaštitite Vašu partiju lozinkom STR_NETWORK_START_SERVER_UNADVERTISED :Ne STR_NETWORK_START_SERVER_ADVERTISED :Da STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} igrač{P "" a a} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Najviše igrača: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Odaberite koliko najviše može da ima igrača. Nemoraju sva mesta da budu popunjena STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} preduzeć{P e a a} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Najviše preduzeća: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Odaberite koliko najviše može biti preduzeća na serveru STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} posmatrač{P "" a a} STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Najviše posmatrača: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Odaberite koliko najviše može biti posmatrača na serveru STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Govorni jezik: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Drugi igrači će znati sa kojim jezikom se razgovara na serveru STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Unos naziva mrežne partije # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :Bilo koji STR_NETWORK_LANG_ENGLISH :Engleski STR_NETWORK_LANG_GERMAN :Nemački STR_NETWORK_LANG_FRENCH :Francuski STR_NETWORK_LANG_BRAZILIAN :Brazilski STR_NETWORK_LANG_BULGARIAN :Bugarski STR_NETWORK_LANG_CHINESE :Kineski STR_NETWORK_LANG_CZECH :Češki STR_NETWORK_LANG_DANISH :Danski STR_NETWORK_LANG_DUTCH :Holandski STR_NETWORK_LANG_ESPERANTO :Esperanto STR_NETWORK_LANG_FINNISH :Finski STR_NETWORK_LANG_HUNGARIAN :Mađarski STR_NETWORK_LANG_ICELANDIC :Islandski STR_NETWORK_LANG_ITALIAN :Italijanski STR_NETWORK_LANG_JAPANESE :Japanski STR_NETWORK_LANG_KOREAN :Koreanski STR_NETWORK_LANG_LITHUANIAN :Litvanski STR_NETWORK_LANG_NORWEGIAN :Norveški STR_NETWORK_LANG_POLISH :Poljski STR_NETWORK_LANG_PORTUGUESE :Portugalski STR_NETWORK_LANG_ROMANIAN :Rumunski STR_NETWORK_LANG_RUSSIAN :Ruski STR_NETWORK_LANG_SLOVAK :Slovački STR_NETWORK_LANG_SLOVENIAN :Slovenački STR_NETWORK_LANG_SPANISH :Španski STR_NETWORK_LANG_SWEDISH :Švedski STR_NETWORK_LANG_TURKISH :Turski STR_NETWORK_LANG_UKRAINIAN :Ukrajinski STR_NETWORK_LANG_AFRIKAANS :Afrikans STR_NETWORK_LANG_CROATIAN :Hrvatski STR_NETWORK_LANG_CATALAN :Katalonski STR_NETWORK_LANG_ESTONIAN :Estonski STR_NETWORK_LANG_GALICIAN :Galicijski STR_NETWORK_LANG_GREEK :Grčki STR_NETWORK_LANG_LATVIAN :Letonski ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Predvorje partije sa više igrača STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Pripremanje za ulazak: {ORANGE}{STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}Spisak svih preduzeća u ovoj partiji. Možete se priključiti nekom ili osnovati novo ukoliko postoji slobodno mesto STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}PODACI O PREDUZEĆU STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Naziv preduzeća: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Inauguracija: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Vrednost preduzeća: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Trenutni balans: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Prošlogodišnji prihod: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Uspešnost: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Vozila: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Stanice: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Igrači: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}Novo preduzeće STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Osnujte novo preduzeće STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Posmatranje partije STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Priključite se partiji kao posmatrač STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Pridruženje preduzeću STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Pomozite upravljanje ovoim preduzećem # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}Povezivanje... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Spajam se... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Čekam odobrenje... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Čekam... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Preuzimam teren... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Obrađujem podatke... STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Prijavljujem se... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Tražim podatke o partiji... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Tražim podatke o preduzećima... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} igrač{P "" a a} je ispred Vas STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} preuzeto do sada STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} preuzeto do sada STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Isključenje STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server je zaštićen. Unesite lozinku STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Preduzeće je zaštićeno. Unesite lozinku # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Spisak klijenata STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Praćenje STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}Novo preduzeće # Network client list STR_NETWORK_CLIENTLIST_KICK :Izbaci STR_NETWORK_CLIENTLIST_BAN :Zabrani pristup STR_NETWORK_CLIENTLIST_GIVE_MONEY :Daj novac STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Razgovaraj sa svima STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Razgovaraj sa ekipom STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privatna poruka STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Igrač STR_NETWORK_SPECTATORS :Posmatrači STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Unesite svotu novca koju želite dati # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Otkaži unetu lozinku STR_COMPANY_PASSWORD_OK :{BLACK}Postavi preduzeću novu lozinku STR_COMPANY_PASSWORD_CAPTION :{WHITE}Lozinka za preduzeće STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Uobičajena lozinka za preduzeće STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Koristite ovu lozinku kao uobičajenu za nova preduzeća # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}Pridružite se STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Pridruži se i igraj kao ovo preduzeće STR_COMPANY_VIEW_PASSWORD :{BLACK}Lozinka STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Zaštitite vaše preduzeće lozinkom kako se ne bi drugi korisnici neovlašćeno pridruživali STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Postavi lozinku za preduzeće # Network chat STR_NETWORK_CHAT_SEND :{BLACK}Pošalji STR_NETWORK_CHAT_COMPANY_CAPTION :[Ekipi] : STR_NETWORK_CHAT_CLIENT_CAPTION :[Privatno] {STRING} STR_NETWORK_CHAT_ALL_CAPTION :[Svima] : STR_NETWORK_CHAT_COMPANY :[Ekipi] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_COMPANY :[Ekipi] Za {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_CLIENT :[Privatno] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_CLIENT :[Privatno] Za {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_ALL :[Svima] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}Unesite tekst poruke za razgovor # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Nijedan mrežni uređaj nije nađen ili je igra kompajlirana bez ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}Nijedna mrežna partija nije nađena STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Server nije odgovorio na zahtev STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Povezivanje je neuspešno zbog nepoklapanja NewGRF-ova STR_NETWORK_ERROR_DESYNC :{WHITE}Neuspešna sinhronizacija mrežne partije STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Veza sa mrežnom partijom je pukla STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Neuspešno učitavanje sačuvane partije STR_NETWORK_ERROR_SERVER_START :{WHITE}Neuspešno pokretanje servera STR_NETWORK_ERROR_CLIENT_START :{WHITE}Neuspešno povezivanje STR_NETWORK_ERROR_TIMEOUT :{WHITE}Istekao rok čekanja za Vezu #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Nastala je greška u protokolu i veza je zatvorena STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Revizija igre ovog klijenta se ne poklapa sa revizijom servera STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Pogrešna lozinka STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Server je pun STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Vi ste zauvek izbačeni sa ovog servera STR_NETWORK_ERROR_KICKED :{WHITE}Vi ste izbačeni iz ove partije STR_NETWORK_ERROR_CHEATER :{WHITE}Varanja nisu dozvoljena na ovom serveru STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Slali ste previše naredbi na server STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Trebalo vam je previše vremena da unesete lozinku STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Računar je suviše spor da bi ispratio rad servera STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Računaru je suviše dugo trebalo da preuzme mapu STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Računaru je suviše dugo trebalo da se priključi serveru ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :opšta greška STR_NETWORK_ERROR_CLIENT_DESYNC :desinhronizacija STR_NETWORK_ERROR_CLIENT_SAVEGAME :neuspešno učitavanje terena STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :veza je izgubljena STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :protokolna greška STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :neusaglašenost NewGRF-a STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :neovlašćeno STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :primljen neispravan ili nepoznat paket STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :pogrešna revizija STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :ime se već koristi STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :pogrešna lozinka STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :pogrešan id preduzeća u mrežnom paketu (DoCommand) STR_NETWORK_ERROR_CLIENT_KICKED :izbačen od strane servera STR_NETWORK_ERROR_CLIENT_CHEATER :pokušaj korišćenja varanja STR_NETWORK_ERROR_CLIENT_SERVER_FULL :server je pun STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :je slao previše naredbi STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :lozinka nije primljena na vreme STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :istekao veremnski rok STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :preuzimanje terena je previše dugo trajalo STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :obrađivanje terena je previše dugo trajalo ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Moguć gubitak veze STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}U poslednj{P 0 oj e ih} {NUM} sekund{P i e i} nije primljen nijedan podatak sa servera # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Partija je pauzirana ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Partija je još uvek pauzirana ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Partija je još uvek pauzirana ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Partija je još uvek pauzirana ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Partija je još uvek pauzirana ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Partija je nastavljena ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :nema dovoljno igrača STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :priključivanje igrača STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :ručno STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :skripta partije ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :napušta STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} se priključio partiji STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} se pridružio partiji (Igrač #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} se pridružio preduzeću #{2:NUM} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} se pridružio posmatračima STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} je osnovao novo preduzeće (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} je napustio partiju ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} je promenio/la ime u {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} je dao vašem preduzeću {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Dali ste {1:STRING} {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Server je zatvorio sesiju STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Server se ponovo pokreće...{}Molimo sačekajte... # Content downloading window STR_CONTENT_TITLE :{WHITE}Dodaci za preuzimanje STR_CONTENT_TYPE_CAPTION :{BLACK}Vrsta STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Vrsta dodatka STR_CONTENT_NAME_CAPTION :{BLACK}Naziv STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Naziv dodatka STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Kliknite kako biste videli detalje{}Kliknite na kvadratić kako biste ga označili za skidanje STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Označi sve STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Obeležava sve dodatke za preuzimanje STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Obeleži ažurirana STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Obeležava sve preuzete dodatke koje imaju novija izdanja za preuzimanje STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Poništi izbor svega STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Otkazuje preuzimanje svih dodataka STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Pretraži eksterne web stranice STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Vi napuštate OpenTTD! STR_CONTENT_FILTER_TITLE :{BLACK}Filter po oznaci/nazivu: STR_CONTENT_OPEN_URL :{BLACK}Idi na Web lokaciju STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Ovaj sadržaj nalazi se na Web lokaciji STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Preuzmi STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Započinje preuzimanje odabranih dodataka STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Ukupna količina za preuzimanje: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}PODACI O DODATKU STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Dodatak nije označen preuzimanje STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Dodatak je označen za preuzimanje STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Ovaj dodatak je označen za preuzimanje zbog zavisnosti STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Ovo već imate STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}Ovaj dodatak je nepoznat i ne može se preuzeti sa OpenTTD STR_CONTENT_DETAIL_UPDATE :{SILVER}Ovaj dodatak je zamena za postojeći {STRING} STR_CONTENT_DETAIL_NAME :{SILVER}Naziv: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Izdanje: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Opis: {WHITE}{STRING} STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}Vrsta: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}Veličina: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Označeno zbog: {WHITE}{STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Zavisnosti: {WHITE}{STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Oznake: {WHITE}{STRING} STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD je kompajliran bez podrške za "zlib"... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... preuzimanje dodataka nije moguće! # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :Osnovna grafika STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :VI STR_CONTENT_TYPE_AI_LIBRARY :VI biblioteke STR_CONTENT_TYPE_SCENARIO :Scenario STR_CONTENT_TYPE_HEIGHTMAP :Elevaciona karta STR_CONTENT_TYPE_BASE_SOUNDS :Osnovni zvukovi STR_CONTENT_TYPE_BASE_MUSIC :Osnovna muzika STR_CONTENT_TYPE_GAME_SCRIPT :Skripta partije STR_CONTENT_TYPE_GS_LIBRARY :SP biblioteka # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Preuzimanje dodataka... STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Zahtevanje datoteka... STR_CONTENT_DOWNLOAD_FILE :{WHITE}Trenutno se preuzima {STRING} ({NUM} od {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Preuzimanje je završeno STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} od {BYTES} preuzetih ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Neuspešno povezivanje sa serverom sa dodacima... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Neuspešno preuzimanje... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... prekinula se veza STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... datoteka se nije mogla zapisati STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Preuzeta datoteka se ne može otpakovati STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Nedostajuće grafike STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD zahteva grafike kako bi radio ali nijedne nisu nađene. Da li dozvoljavate da OpenTTD preuzme i instalira te neophodne grafike? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Da, preuzmi grafike STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Ne, napusti OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Podešavanja Prozirnosti STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Promena prozirnosti znakova. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Promena prozirnosti drveća. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Promena prozirnosti zgrada. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Promena prozirnosti fabrika. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Promena prozirnosti građevina poput stanica, depoa i putanja. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Promena prozirnosti mostova. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Promena prozirnosti građevina poput svetionika i repetitora. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Promena prozirnosti kontaktnih mreža. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Promena prozirnosti pokazatelja utovara. Sa Ctrl+Klik se zaključava STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Čini objekte nevidljivim umesto prozirnim # Linkgraph legend window # Linkgraph legend window and linkgraph legend in smallmap # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Označavanje zahvaćenog područja STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Isključeno STR_STATION_BUILD_COVERAGE_ON :{BLACK}Uključeno STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Isključi označavanje zahvaćenog područja STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Uključi označavanje zahvaćenog područja STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Prihvata: {GOLD}{CARGO_LIST.aku} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Snabdeva: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Pridruži stanicu STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Izgradi zasebnu stanicu STR_JOIN_WAYPOINT_CAPTION :{WHITE}Spoji putanje STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Napravi zasebnu putanju # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Izgradnja železnice STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Izgradnja elektrifikovane železnice STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Izgradnja jednošinske železnice STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Izgradnja magnetne železnice STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Izgradnja železničke pruge. Ctrl uključuje izgradnju/uklanjanje. Shift prebacuje između izgradnje i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Izgradnja pruge pomoću automatskog određivanja pravca. Ctrl uključuje izgradnju/uklanjanje. Shift prebacuje između izgradnje i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Izgradnja voznog depoa (za pravljenje novih, kao i za servis starih vozova). Shift prebacuje između izgradnje i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Promena pruge u čvorište. Uz Ctrl se spaja sa drugim čvorištima. Shift prebacuje između promene i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Izgradnja železničke stanice. Uz Ctrl se spaja sa drugim stanicama. Shift prebacuje između izgradnje i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Izgradnja železničke signalizacije. Ctrl uključuje semafore/svetlosne signale{}Prevlačenjem se grade signali duž prave linije pruge. Ctrl gradi signale do sledeće raskrsnice{}Ctrl+Klik uključuje otvaranje prozora za izbor signala. Shift prebacuje između izgradnje i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Izgradnja železničkog mosta. Shift prebacuje između izgradnje i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Izgradnja železničkog tunela. Shift prebacuje između izgradnje i prikaza procene troškova STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Izgradnja/Uklanjanje železničkih pruga, signalizacije, putnih tačaka i stanica (kad je uključeno). Držanjem Ctrl takođe se uklanja pruga sa putnih tačaka i stanica STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Promena/Nadogradnja vrste pruge. Shift prebacuje između promene/nadogradnje i prikaza procene troškova STR_RAIL_NAME_RAILROAD :Železnica STR_RAIL_NAME_ELRAIL :Elektrifikovana železnica STR_RAIL_NAME_MONORAIL :Jednošinska železnica STR_RAIL_NAME_MAGLEV :Magnetna železnica # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Orijentacija železničkog depoa STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Izbor orijentacije železničkog depoa # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Putanja STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Odaberite tip putanje # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Izbor železničke stanice STR_STATION_BUILD_ORIENTATION :{BLACK}Orijentacija STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Izbor orijentacije železničke stanice STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Broj koloseka STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Izbor broja koloseka STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Dužina platforme STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Izbor dužine stanice STR_STATION_BUILD_DRAG_DROP :{BLACK}Prevlačenje STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Gradnja stanice prevlačenjem STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Izbor klase stanica za prikaz STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Odaberite vrstu stanice za gradnju STR_STATION_CLASS_DFLT :Podrazumevana stanica STR_STATION_CLASS_WAYP :Putanje # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Izbor Signalizacije STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Blok Signalizacija (semafor){}Ovo je najosnovnija vrsta signalizacije, dozvoljava samo jedan voz da bude u istoj deonici STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Ulazna Signalizacija (semafor){}Otvoren prolaz ukoliko postoji jedna ili više otvorenih izlaznih signalizacija sa nastupajuće deonice. U suprotnom je zatvoren STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Izlazna Signalizacija (semafor){}Ponaša se isto kao i blok signalizacija ali je neophodan za uparivanje sa ulaznom i/ili kombinovanom signalizacijom STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Kombinovana Signalizacija (semafor){}Kombinovana signalizacija se ponaša kao ulazna i izlazna signalizacija. Ovim se omogućava gradnja velikih "stabala" predsignalizacije STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Putna Signalizacija (semafor){}Putna signalizacija omogućava da više vozova istovremeno uđe u istu deonicu, ukoliko mogu da obezbede put do zasebnog zaustavnog koloseka. Standardnu putnu signalizaciju moguće je proći i sa suprotnog smera STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}Jednosmerna Putna Signalizacija (semafor){}Putna signalizacija omogućava da više vozova istovremeno uđe u istu deonicu, ukoliko mogu da obezbede put do zasebnog zaustavnog koloseka. Jednosmerna putna signalizacija zabranjuje prolaz sa suprotnog smera STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Blok Signalizacija (svetlosni semafor){}Ovo je najosnovnija vrsta signalizacije, dozvoljava samo jedan voz da bude u istoj deonici STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Ulazna Signalizacija (svetlosni semafor){}Otvoren prolaz ukoliko postoji jedna ili više otvorenih izlaznih signalizacija sa nastupajuće deonice. U suprotnom je zatvoren STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Izlazna Signalizacija (svetlosni semafor){}Ponaša se isto kao i blok signalizacija ali je neophodan za uparivanje sa ulaznom i/ili kombinovanom signalizacijom STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Kombinovana Signalizacija (svetlosni semafor){}Kombinovana signalizacija se ponaša kao ulazna i izlazna signalizacija. Ovim se omogućava gradnja velikih "stabala" predsignalizacije STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Putna Signalizacija (svetlosni semafor){}Putna signalizacija omogućava da više vozova istovremeno uđe u istu deonicu, ukoliko mogu da obezbede put do zasebnog zaustavnog koloseka. Standardnu putnu signalizaciju moguće je proći i sa suprotnog smera STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Jednosmerna Putna Signalizacija (svetlosni semafor){}Putna signalizacija omogućava da više vozova istovremeno uđe u istu deonicu, ukoliko mogu da obezbede put do zasebnog zaustavnog koloseka. Jednosmerna putna signalizacija zabranjuje prolaz sa suprotnog smera STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Promena Signalizacije{}Kada je označeno, klikom na postojeću signalizaciju promeniće je na izabranu vrstu i podvrstu, sa Ctrl+Klik će se označiti postojeća podvrsta. Shift+Klik prikazuje procenu troškova promene STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Razmak između signalizacija tokom povlačenja STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Smanjivanje razmaka između signalizacija STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Povećavanje razmaka između signalizacija # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Izbor železničkog mosta STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Izbor drumskog mosta STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Izbor mosta - gradnja se potvrđuje klikom na željeni most STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :Viseći, čelični STR_BRIDGE_NAME_GIRDER_STEEL :Gredni, čelični STR_BRIDGE_NAME_CANTILEVER_STEEL :Obešeni, čelični STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Viseći, betonski STR_BRIDGE_NAME_WOODEN :Drveni STR_BRIDGE_NAME_CONCRETE :Betonski STR_BRIDGE_NAME_TUBULAR_STEEL :Cevasti, čelični STR_BRIDGE_TUBULAR_SILICON :Cevni, Silicijumski # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Izgradnja drumskog sistema STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Izgradnja tramvajskog sistema STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Izgradnja deonice kolovoza. Ctrl uključuje izgradnju/uklanjanje. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Izgradnja deonice tramvajske pruge. Ctrl uključuje izgradnju/uklanjanje. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Gradnja kolovoza koristeći automatsko određivanje pravca. Ctrl uključuje izgradnju/uklanjanje. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Gradnja tramvajske pruge koristeći automatsko određivanje pravca. Ctrl uključuje izgradnju/uklanjanje tramvajske pruge. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Izgradnja drumskog depoa (za izgradnju novih i servis starih vozila). Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Izgradnja tramvajskog depoa (za izgradnju novih i servis starih tramvaja). Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Izgradnja autobuske stanice. Uz Ctrl se spaja sa drugim stanicama. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Izgradnja putničke tamvajske stanice. Uz Ctrl se spaja sa drugim stanicama. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Izgradnja tovarne stanice. Uz Ctrl se spaja sa drugim stanicama. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Izgradnja teretne tamvajske stanice. Uz Ctrl se spaja sa drugim stanicama. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Izgradnja jednosmernih puteva (kada je uključeno) STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Izgradnja drumskog mosta. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Izgradnja tramvajskog mosta. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Izgradnja drumskog tunela. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Izgradnja tramvajskog tunela. Shift prebacuje između izgradnje i prikaza procene troškova STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Uključi građenje/rušenje drumskih puteva STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Uključi građenje/rušenje tramvajskih građevina # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Orijentacija drumskog depoa STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Izbor orijentacije drumskog depoa STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Izbor orijentacije tramvajskog depoa STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Izbor orijentacije tramvajskog depoa # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Orijentacija autobuske stanice STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Izbor orijentacije autobuske stanice STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Orijentacija stanice za utovar kamiona STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Izbor orijentacije stanice za utovar kamiona STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Orijentacija tramvajske putničke stanice STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Odaberite orijentaciju putničke tramvajske stanice STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Orijentacija tramvajske teretne stanice STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Odaberite orijentaciju teretne tamvajske stanice # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Izgradnja plovnog sistema STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Plovni kanali STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Gradnja kanala. Shift prebacuje između izgradnje i prikaza procene troškova STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Izgradnja prevodnica. Shift prebacuje između izgradnje i prikaza procene troškova STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Gradnja brodskog depoa (za kupovinu i servisiranje brodova). Shift prebacuje između izgradnje i prikaza procene troškova STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Gradnja pristaništa. Uz Ctrl se spaja sa drugim stanicama. Shift prebacuje između izgradnje i prikaza procene troškova STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Postavlja bovu kako bi služila kao putokaz. Shift prebacuje između postavljanja i prikaza procene troškova STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Izgradnja akvadukta. Shift prebacuje između izgradnje i prikaza procene troškova STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Vodena površina.{}Napravite kanal, ukoliko držite i Ctrl dok ste na nivou mora, tada popunjavate okolinu vodom STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Postavljanje reka # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Orijentacija brodskog hangara STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Izbor orijentacije brodskog hangara # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Pristanište # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Aerodromi STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Izgradnja aerodroma. Uz Ctrl se spaja sa drugim stanicama. Shift prebacuje između izgradnje i prikaza procene troškova # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Izbor aerodroma STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Izbor veličine/tipa aerodroma STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Tip aerodroma STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Raspored {NUM} STR_AIRPORT_SMALL :Poljski aerodrom STR_AIRPORT_CITY :Gradski aerodrom STR_AIRPORT_METRO :Regionalni aerodrom STR_AIRPORT_INTERNATIONAL :Međunarodni aerodrom STR_AIRPORT_COMMUTER :Lokalni aerodrom STR_AIRPORT_INTERCONTINENTAL :Interkontinentalni aerodrom STR_AIRPORT_HELIPORT :Helipad STR_AIRPORT_HELIDEPOT :Helihangar STR_AIRPORT_HELISTATION :Helidrom STR_AIRPORT_CLASS_SMALL :Tercijarni promet STR_AIRPORT_CLASS_LARGE :Sekundarni promet STR_AIRPORT_CLASS_HUB :Primarni promet STR_AIRPORT_CLASS_HELIPORTS :Helidromi STR_STATION_BUILD_NOISE :{BLACK}Proizvedena buka: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}Oblikovanje terena STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Spušta ugao tla. Povlačenjem spušta prvi obeleženi ugao i izjednačava ostatk područja na nov nivo. Ctrl obeležava dijagonalno područje. Shift prebacuje između spuštanja i prikaza procene troškova STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Podiže ugao tla. Povlačenjem podiže prvi obeleženi ugao i izjednačava ostatk područja na nov nivo. Ctrl obeležava dijagonalno područje. Shift prebacuje između podizanja i prikaza procene troškova STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Izjednačava područje na najviši nivo prvo označenog ugla. Ctrl obeležava dijagonalno područje. Shift prebacuje između izjednačavanja i prikaza procene troškova STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Kupovina zemljišta za kasnije korišćenje. Shift prebacuje između kupovine i prikaza procene troškova kupovine # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Izbor Objekta STR_OBJECT_BUILD_TOOLTIP :{BLACK}Odabir objekta za izgradnju. Shift prebacuje između izgradnje i prikaza procene troškova STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Izbor klase objekata za izgradnju STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Privremeno prikazuje objekat STR_OBJECT_BUILD_SIZE :{BLACK}Veličina: {GOLD}{NUM} x {NUM} pločica STR_OBJECT_CLASS_LTHS :Svetionici STR_OBJECT_CLASS_TRNS :Repetitori # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Drveće STR_PLANT_TREE_TOOLTIP :{BLACK}Izbor vrste drveća za sađenje. Ako pločica već ima drveće, ovim će se dodati još drveća ali mešanih vrsta, bez obzira na odabranu vrstu STR_TREES_RANDOM_TYPE :{BLACK}Drveće proizvoljne vrste STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Sađenje drveća proizvoljne vrste. Shift prebacuje između sadnje i prikaza procene troškova STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Nasumično postavljeno drveće STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Zasadi drveće nasumično preko čitavog terena # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Oblikovanje reljefa STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Postavi stenovita područja na reljef STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Definisanje pustinjske oblasti.{}Držanjem Ctrl se uklanja STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Uvećaj područje koje treba sniziti/povisiti STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Smanji područje koje treba sniziti/povisiti STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Pravi zemljište nasumičnog reljefa STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Napravi novi scenario STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Obnovi reljef STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Uklanja sve objekte u vlasništvu preduzeća sa terena STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Obnovi reljef STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Da li sigurno želite da uklonite sve objekte u vlasništvu preduzeća? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}Stvaranje naselja STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}Novo naselje STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Osnivanje novog naselja. Shift+Klik prikazuje samo procenu troškova STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Nasumično naselje STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Osnuj naselje na nasumičnoj lokaciji STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Mnogo nasumičnih naselja STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Popunjava teren sa nasumično raspoređenim naseljima STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Ime grada: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Unos imena grada STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Kliknite za unos imena naselja STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Proizvoljno ime STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Daje gradu proizvoljno ime STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Veličina naselja: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Malo STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Srednje STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Veliko STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Slučajan STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Izbor veličine naselja STR_FOUND_TOWN_CITY :{BLACK}Grad STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Gradovi se razvijaju brže nego uobičajena naselja{}U zavisnosti od podešavanja, veći su prilikom osnivanja STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Mreža puteva u naselju: STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Izbor plana mreže puteva u naselju STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Originalno STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Napredno STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 mreža STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 mreža STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Slučajan # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Finansiranje nove fabrike STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Izaberite odgovarajuću fabriku sa spiska STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Mnogo nasumičnih fabrika STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Popunjava teren sa nasumično rasporđenim fabrikama STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Trošak: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Istraži STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Izgradi STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Finansiraj # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Lanac snabdevanja - {STRING} STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Lanac proizvodnje - {STRING} STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Snabdevačke industrije STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Potrošačke industrije STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Domaćinstva STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Klikom na industriju prikazuju se njegovi snabdevači i potrošači STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Klikom na tovar prikazuju se njegovi snabdevači i potrošači STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Lanac STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Prikazuje lanac snabdevanja industrija STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Obeleži na karti STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Obeležava prikazane industrije i na karti STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Odaberite tovar STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Odaberite fabriku STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Odaberite fabriku koju želite da prikažete # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Prikaži podatke o zemljištu STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Cena čišćenja: {LTBLUE}N/A STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Cena čišćenja: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Dobit po uklanjanju: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :N/A STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Vlasnik: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Vlasnik kolovoza: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Vlasnik tramvajske pruge: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Vlasnik železničke pruge: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Lokalna vlast: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Nema STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinate: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Sagrađeno: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Klasa stanice: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Vrsta stanice: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Klasa aerodroma: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Naziv aerodroma: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Naziv dela aerodroma: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Tovar prihvaćen: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Najveća brzina na pruzi: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Stene STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Grub teren STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Ogoljeno tlo STR_LAI_CLEAR_DESCRIPTION_GRASS :Trava STR_LAI_CLEAR_DESCRIPTION_FIELDS :Polja STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Snegom prekrivena zemlja STR_LAI_CLEAR_DESCRIPTION_DESERT :Pustinja STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} kolosek STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} kolosek sa blok signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} kolosek sa predsignalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} kolosek sa izlaznom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} kolosek sa kombinovanom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} kolosek sa putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} kolosek sa jednosmernom putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} kolosek sa blok i predsignalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} kolosek sa blok i izlaznom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} kolosek sa blok i kombinovanom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} kolosek sa blok i putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} kolosek sa blok i jednosmernom putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} kolosek sa pred i izlaznom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} kolosek sa pred i kombinovanom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} kolosek sa pred i putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} kolosek sa pred i jednosmernom putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} kolosek sa izlaznom i kombinovanom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} kolosek sa izlaznom i putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} kolosek sa izlaznom i jednosmernom putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} kolosek sa kombinovanom i putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} kolosek sa kombinovanom i jednosmernom putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} kolosek sa putnom i jednosmernom putnom signalizacijom STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} železnički depo STR_LAI_ROAD_DESCRIPTION_ROAD :Put STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Kolovoz sa uličnom rasvetom STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Put sa drvoredom STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Drumski depo STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Ukrštanje pruge i puta STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramvaj # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (izgradnja u toku) STR_LAI_TREE_NAME_TREES :Drveće STR_LAI_TREE_NAME_RAINFOREST :Tropska šuma STR_LAI_TREE_NAME_CACTUS_PLANTS :Kaktusi STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Železnička stanica STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Hangar STR_LAI_STATION_DESCRIPTION_AIRPORT :Aerodrom STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Stanica za utovar kamiona STR_LAI_STATION_DESCRIPTION_BUS_STATION :Autobuska stanica STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Pristanište STR_LAI_STATION_DESCRIPTION_BUOY :Bova STR_LAI_STATION_DESCRIPTION_WAYPOINT :Putanja STR_LAI_WATER_DESCRIPTION_WATER :Voda STR_LAI_WATER_DESCRIPTION_CANAL :Kanal STR_LAI_WATER_DESCRIPTION_LOCK :Prevodnica STR_LAI_WATER_DESCRIPTION_RIVER :Reka STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Obala STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Brodski hangar # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Železnički tunel STR_LAI_TUNNEL_DESCRIPTION_ROAD :Drumski tunel STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Čelični viseći železnički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Čelični gredni železnički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Čelični obešeni železnički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Viseći železnički most od prednapregnutog betona STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Drveni železnički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Betonski železnički most STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Cevasti železnički most STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Čelični viseći drumski most STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Čelični gredni drumski most STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Čelični obešeni drumski most STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Viseći drumski most od prednapregnutog betona STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Drveni drumski most STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Betonski drumski most STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Cevasti drumski most STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Akvadukt STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Predajnik STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Svetionik STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Upravna zgrada preduzeća STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Zemljište u posedu preduzeća # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}O OpenTTD-u STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Originalni kopirajt {COPYRIGHT} 1995 Chris Sawyer, Sva prava zadržana STR_ABOUT_VERSION :{BLACK}OpenTTD verzija {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2015 OpenTTD tim # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Sačuvaj poziciju STR_SAVELOAD_LOAD_CAPTION :{WHITE}Učitavanje Partije STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Sačuvaj scenario STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Učitaj scenario STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Učitavanje Elevacione karte STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Sačuvaj Elevacionu kartu STR_SAVELOAD_HOME_BUTTON :{BLACK}Pritisnite ovde kako biste otišli u uobičajeni direktorijum za čuvanje pozicije STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} slobodno STR_SAVELOAD_LIST_TOOLTIP :{BLACK}Spisak diskova, direktorijuma i datoteka sa sačuvanim pozicijama STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Ime sačuvane pozicije STR_SAVELOAD_DELETE_BUTTON :{BLACK}Obriši STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Obriši trenutno označenu sačuvanu poziciju STR_SAVELOAD_SAVE_BUTTON :{BLACK}Sačuvaj STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Sačuvaj tekuću igru, koristeći odabrano ime STR_SAVELOAD_LOAD_BUTTON :{BLACK}Učitaj STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Učitava označenu partiju STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Detalji partije STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Podaci ne postoje STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}Unesite naziv sačuvane partije # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}Stvaranje sveta STR_MAPGEN_MAPSIZE :{BLACK}Veličina terena: STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Izaberite veličinu mape u pločicama. Broj dostupnih pločica će biti neznatno manji STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Broj naselja: STR_MAPGEN_DATE :{BLACK}Datum: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Broj fabrika: STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}Maksimalna visina mape STR_MAPGEN_MAX_HEIGHTLEVEL_UP :{BLACK}Povećaj maksimalnu visinu planina na mapi za jedan STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN :{BLACK}Smanji maksimalnu visinu planina na mapi za jedan STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Nivo snežnog pokrivača: STR_MAPGEN_SNOW_LINE_UP :{BLACK}Sužava snežni pokrivač naviše za jedan STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Proširuje snežni pojas naniže za jedan STR_MAPGEN_LAND_GENERATOR :{BLACK}Oblikovanje reljefa: STR_MAPGEN_TREE_PLACER :{BLACK}Algoritam za drveća: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Vrsta terena: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Nivo mora: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Broj reka: STR_MAPGEN_SMOOTHNESS :{BLACK}Postepenost: STR_MAPGEN_VARIETY :{BLACK}Raznolikost: STR_MAPGEN_GENERATE :{WHITE}Napravi # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}Ivice terena: STR_MAPGEN_NORTHWEST :{BLACK}Severozapad STR_MAPGEN_NORTHEAST :{BLACK}Severoistok STR_MAPGEN_SOUTHEAST :{BLACK}Jugoistok STR_MAPGEN_SOUTHWEST :{BLACK}Jugozapad STR_MAPGEN_BORDER_FREEFORM :{BLACK}Kopno STR_MAPGEN_BORDER_WATER :{BLACK}More STR_MAPGEN_BORDER_RANDOM :{BLACK}Proizvoljno STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Proizvoljno STR_MAPGEN_BORDER_MANUAL :{BLACK}Podešeno STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Orijentacija elevacione karte: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Naziv elevacione karte: STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Veličina: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT :{WHITE}Promenite maksimalnu visinu mape STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Promena donjeg nivoa snežnog pojasa STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Promena početne godine # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}Vrsta scenarija STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Ravan teren STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Postavlja ravno zemljište STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Proizvoljan oblik terena STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Visina ravnog terena: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Smanjuje visinu ravnog terena za jedan STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Povećava visinu ravnog terena za jedan STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Promena visine ravnog terena # Map generation progress STR_GENERATION_WORLD :{WHITE}Stvaranje Sveta... STR_GENERATION_ABORT :{BLACK}Prekini STR_GENERATION_ABORT_CAPTION :{WHITE}Prekid Stvaranja Sveta STR_GENERATION_ABORT_MESSAGE :{YELLOW}Da li stvarno želite da prekinete stvaranje? STR_GENERATION_PROGRESS :{WHITE}{NUM}% završeno STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}Stvaranje sveta STR_GENERATION_RIVER_GENERATION :{BLACK}Određivanje toka reka STR_GENERATION_TREE_GENERATION :{BLACK}Postavljanje drveća STR_GENERATION_OBJECT_GENERATION :{BLACK}Postavljenje nepomičnih objekata STR_GENERATION_CLEARING_TILES :{BLACK}Dodavanje grubih i stenovitih područja STR_GENERATION_SETTINGUP_GAME :{BLACK}Podešavanje partije STR_GENERATION_PREPARING_TILELOOP :{BLACK}Razrađivanje pločica STR_GENERATION_PREPARING_SCRIPT :{BLACK}Pokretanje skripte STR_GENERATION_PREPARING_GAME :{BLACK}Pripremanje partije # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF podešavanja STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Detaljni NewGRF podaci STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Aktivne NewGRF datoteke STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Neaktivne NewGRF datoteke STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Odabir postavke: STR_NEWGRF_FILTER_TITLE :{ORANGE}Filter niska: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Učitava označenu postavku STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Sačuvaj postavku STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Sačuvajte trenutni spisak u postavku STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Unesite ime za postavku STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Izbriši postavku STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Izbrišite trenutno označenu postavku STR_NEWGRF_SETTINGS_ADD :{BLACK}Dodaj STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Dodajte odabranu NewGRF datoteku na vaš listu STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Osveži izbor STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Osvežite izbor dostupnih NewGRF datoteka STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Ukloni STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Uklanja označenu NewGRF datoteku sa spiska STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Naviše STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Pomera označenu NewGRF datoteku više na spisku STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Naniže STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Pomera označenu NewGRF datoteku niže na spisku STR_NEWGRF_SETTINGS_UPGRADE :{BLACK}Ažuriraj STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}Spisak instaliranih NewGRF datoteka. STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Postavi parametre STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Prikaži parametre STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Promeni paletu STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Menja paletu označenog NewGRF-a.{}Promenite paletu ako grafici iz NewGRF-a su ružičasti tokom igre STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Primeni promene STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Traži nedostajući dodatak STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Proverite da li se nedostajući dodaci mogu naći na mreži STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Datoteka: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Izdanje: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Najranije kompatibilno izdanje: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Paleta: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parametri: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}Podaci ne postoje STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Odabrana datoteka nije nađena STR_NEWGRF_SETTINGS_DISABLED :{RED}Isključen STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Nije kompatibilno sa ovom OpenTTD verzijom # NewGRF save preset window # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Promena NewGRF parametara STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Zatvori STR_NEWGRF_PARAMETERS_RESET :{BLACK}Poništi STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Postavlja parametre na njihove početne vrednosti STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parametar {NUM} STR_NEWGRF_PARAMETERS_SETTING :{STRING}: {ORANGE}{STRING} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Broj parametara: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Provera - {STRING} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Roditelj STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Provera objekta na roditeljskom opsegu STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING} kod {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Objekat STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Vrsta železnice STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF promenljiva 60+x parametar (heksadecimalno) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Poravnjavanje sprajta {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Sledeći sprajt STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Prelazi na sledeći normalan sprajt, preskačući sve pseudo/prebojavajuće/font sprajtove i vraća se na početak posle zadnjeg STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Idi na sprajt STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Ide na dati sprajt. Ako taj sprajt nije normalan sprajt, prelazi na prvi sledeći normalni STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Prethodni sprajt STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Vraća se na prethodni normalan sprajt, preskačući sve pseudo/prebojavajuće/font sprajtove i prelazi na kraj posle početnog STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Prikaz trenutno odabranog sprajta. Poravnanje se ignoriše tokom iscrtavanja ovog sprajta STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Premeštanje sprajta po kordinatama, menjanjem X i Y pomeraja STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Odabiranje sprajta STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Odabiranje sprajta bilo gde sa ekrana STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Prelazak na sprajt # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Upozorenje: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Greška: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Kobno: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Došlo je do neotklonljive NewGRF greške: {}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} neće raditi sa TTDPatch verzijom prema prijavi OpenTTD-a STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} je za {STRING} verziju TTD-a STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} je napravljen za korišćenje sa {STRING} STR_NEWGRF_ERROR_INVALID_PARAMETER :Neispravan parametar za {1:STRING}: parametar {STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} mora biti učitan pre {STRING} STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} mora biti učitan posle {STRING} STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} zahteva {STRING} ili višu verziju OpenTTD-a STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :GRF datoteka nije prilagođena za prevod STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Previše učitanih NewGRF-ova STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Učitavanje {1:STRING} kao statične NewGRF sa {STRING} može da izazove desinhronizacije STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Neočekivani sprajt (sprajt {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Nepoznato svojstvo Akcije 0 {4:HEX} (sprajt {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Pokušaj korišćenja neispravnog ID-ja (sprajt {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{STRING} sadrži neispravan sprajt. Svi neispravni sprajtovi će biti prikazani kao crveni znakovi pitanja (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Sadrži više Akcija 8 ulaza (sprajt {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Čitanje iza završetka pseudo-sprajta (sprajt {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}Odabranom skupu osnovnih grafika nedostaje neki broj sprajtova.{}Molimo Vas da ga ažurirate STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}Grafičkom setu koji je trenutno u upotrebi nedostaje određen broj sprajtova.{}Osvežite grafički set.{}S obzirom da igrate {YELLOW}razvojnu verziju OpenTTD-a{WHITE}, treba vam i {YELLOW}razvojna verzija grafičkog seta{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Traženi GRF resursi nisu dostupni (sprajt {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} je isključen od strane {STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Neispravan/nepoznat format prikazivanja sprajta (sprajt {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Oprez! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Upravo ćete načiniti izmene na tekućoj partiji. To može srušiti OpenTTD ili narušiti stanje partije. Oko ovog problema nemojte prijavljivati greške.{}Da li ste apsolutno sigurni da ovo želite? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Nemoguće dodati: duplicirani GRF ID STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Odabrana datoteka nije nađena (kompatibilan GRF učitan) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Ne mogu da dodam datoteku: dostignuta je granica za NewGRF datoteke STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Kompatibilni GRF(ovi) učitani umesto nepronađenih datoteka STR_NEWGRF_DISABLED_WARNING :{WHITE}Nepronađene GRF datoteke su isključene STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Nepronađene GRF datoteke STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Nastavljenje može da krahira OpenTTD. Nemojte čuvati izveštaje o ovom mogućem krahu.{}Da li stvarno želite da nastavite? # NewGRF status STR_NEWGRF_LIST_NONE :Nema STR_NEWGRF_LIST_ALL_FOUND :Sve datoteke su prisutne STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Pronađene su kompatibilne datoteke STR_NEWGRF_LIST_MISSING :{RED}Nedostaju datoteke # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}NewGRF '{0:STRING}' može izazvati desinhronizacije i/ili krahove STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Vagon '{1:ENGINE}' je promenio motorno stanje izvan depoa STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Promenio je dužinu vozila '{1:ENGINE}' dok je izvan depoa STR_BROKEN_VEHICLE_LENGTH :{WHITE}Voz '{VEHICLE}' preduzeća '{COMPANY}' je neispravne dužine. Verovatno je izazvana nekim problemima sa NewGRF(ovima). Igra može da krahira ili da se desinhronizuje STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' sadrži neispravne podatke STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Podaci o tovaru/prenameni za '{1:ENGINE}' se posle izgradnje razlikuju od nabavne liste. Ovo može izazvati neispravnu automatsku zamenu/preuređenje STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' je izazvao beskrajnu petlju tokom povratnog poziva proizvodnje STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Povratni poziv {1:HEX} vratio je nepoznatu/neispravnu vrednost {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} STR_NEWGRF_INVALID_ENGINE : STR_NEWGRF_INVALID_INDUSTRYTYPE : # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE : # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}Pregledanje NewGRF-ova STR_NEWGRF_SCAN_MESSAGE :{BLACK}Pregledanje NewGRF-ova. U zavisnosti od količine ovo može i da potraje... STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF{P "" -a -ova} pregledano od odprilike procenjeno {NUM} NewGRF{P -a -a -ova} STR_NEWGRF_SCAN_ARCHIVES :Pretraživanje arhiva # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}Spisak Znakova - {COMMA} Znak{P "" a ova} STR_SIGN_LIST_MATCH_CASE :{BLACK}Podudaranje vel. slova STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Uključuje/isključuje podudaranje malih i velikih slova tokom poređenja naziva znakova sa filter niskom # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Unos teksta znaka STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Položaj sledećeg znaka STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Položaj prethodnog znaka STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Unos naziva znaka # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}Naselja STR_TOWN_DIRECTORY_NONE :{ORANGE}- Prazno - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Imena naselja - klikom na ime se centrira glavni pogled na to naselje. Ctrl+Klik otvara novi pogled na lokaciju naselja STR_TOWN_POPULATION :{BLACK}Svetska populacija: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (Grad) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Populacija: {ORANGE}{COMMA}{BLACK} Zgrada: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Broj putnika tokom meseca: {ORANGE}{COMMA}{BLACK} najviše: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Količina pošte tokom meseca: {ORANGE}{COMMA}{BLACK} najviše: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Tovar potreban za razvoj naselja: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} potrebno STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} potrebno zimi STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} dostavljeno STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (potrebno) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (dostavljeno) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Naselje se razvija u periodu od {ORANGE}{COMMA}{BLACK} dan{P a a a} STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Naselje se razvija u periodu od {ORANGE}{COMMA}{BLACK} dan{P a a a} (sponzorisano) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Naselje se {RED}ne{BLACK} razvija STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Nivo buke u naselju: {ORANGE}{COMMA}{BLACK} najviše: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Pozicionira glavni pogled na lokaciju naselja. Ctrl+Klik otvara novi pogled na lokaciju naselja STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Lokalna vlast STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Prikaži podatke o lokalnoj vlasti STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Promeni ime naselja STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Proširi STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Uvećaj površinu naselja STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Obriši STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Potpuno ukloni ovo naselje STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Preimenuj naselje # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}Lokalna vlast naselja {TOWN} STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Kotiranje preduzeća: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Raspoložive akcije: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}Spisak akcija na raspolaganju u ovom naselju - klik na akciju pruža uvid u više detalja STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Uradi STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Sprovedi izabranu akciju STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Manja reklamna kampanja STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Srednja reklamna kampanja STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Veća reklamna kampanja STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Finansiranje rekonstrukcije puteva STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Izgradnja statue vlasnika preduzeća STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Finansiranje novih zgrada STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Kupovina ekskluzivnih prava prevoza STR_LOCAL_AUTHORITY_ACTION_BRIBE :Podmićivanje lokalne vlasti STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Ulaganje u malu reklamnu kampanju će doneti preduzeću više putnika i robe iz ovog naselja.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Ulaganje u reklamnu kampanju srednje veličine će doneti preduzeću više putnika i robe iz ovog naselja.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Ulaganje u veliku reklamnu kampanju će doneti preduzeću više putnika i robe iz ovog naselja.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Finansiranje rekonstrukcije lokalne mreže puteva. Može prouzrokovati kolaps u drumskom saobraćaju u trajanju do 6 meseci.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Otkrivanje spomenika preduzeća.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW} Finansiranje izgradnje novih komercijalnih objekata u naselju.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Kupovina ekskluzivnih prava prevoza od lokalne vlasti na godinu dana, osigurava da će lokalni korisnici prevoza koristiti isključivo usluge vašeg preduzeća.{} Trošak: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Davanje mita lokalnoj vlasti kako bi porastao rejting vašeg preduzeća, uz rizik velike štete ukoliko se otkrije.{} Cena: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Ciljevi STR_GOALS_SPECTATOR_CAPTION :{WHITE}Globalni ciljevi STR_GOALS_GLOBAL_TITLE :{BLACK}Opšti ciljevi: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Nema - STR_GOALS_PROGRESS :{ORANGE}{STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_COMPANY_TITLE :{BLACK}Ciljevi preduzeća: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikom na cilj premešta se glavni pogled na fabriku/naselje/pločicu. Ctrl+Kilk otvara novi pogled na lokaciju fabrike/naselja/pločice # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :Pitanje STR_GOAL_QUESTION_CAPTION_INFORMATION :Obaveštenje STR_GOAL_QUESTION_CAPTION_WARNING :Upozorenje STR_GOAL_QUESTION_CAPTION_ERROR :Greška ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Otkaži STR_GOAL_QUESTION_BUTTON_OK :U redu STR_GOAL_QUESTION_BUTTON_NO :Ne STR_GOAL_QUESTION_BUTTON_YES :Da STR_GOAL_QUESTION_BUTTON_DECLINE :Odbaci STR_GOAL_QUESTION_BUTTON_ACCEPT :Prihvati STR_GOAL_QUESTION_BUTTON_IGNORE :Ignoriši STR_GOAL_QUESTION_BUTTON_RETRY :Ponovi STR_GOAL_QUESTION_BUTTON_PREVIOUS :Predhodno STR_GOAL_QUESTION_BUTTON_NEXT :Sledeće STR_GOAL_QUESTION_BUTTON_STOP :Zaustavi STR_GOAL_QUESTION_BUTTON_START :Startuj STR_GOAL_QUESTION_BUTTON_GO :Idi STR_GOAL_QUESTION_BUTTON_CONTINUE :Nastavi STR_GOAL_QUESTION_BUTTON_RESTART :Restartuj STR_GOAL_QUESTION_BUTTON_POSTPONE :Odloži STR_GOAL_QUESTION_BUTTON_SURRENDER :Predaja STR_GOAL_QUESTION_BUTTON_CLOSE :Zatvori ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}Subvencije STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subvencije u toku (u vezi preuzimanja navedenog tovara): STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING.big} od {STRING} do {STRING}{YELLOW} (pre {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- Prazno - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Odobrene subvencije: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} između stanica {STRING} i {STRING}{YELLOW} ({COMPANY}{YELLOW}, do {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikom na uslugu prebacuje glavni pogled na lokaciju fabrike/naselja. Ctrl+Klik otvara novi pogled na to mesto # Story book window STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :Stranica {NUM} STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Idi do željene stranice uz izbor te stranice u ovoj listi. STR_STORY_BOOK_PREV_PAGE :{BLACK}Prethodni STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Idi do prethodne stranice STR_STORY_BOOK_NEXT_PAGE :{BLACK}Sledeće STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Idi do sledeće stranice # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Imena stanica - klikom na ime se centrira glavni pogled na stanicu. Ctrl+Klik otvara novi pogled na lokaciju stanice STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Držanjem Ctrl moguće je označiti više od jedne stavke STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Stanic{P a e a} STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- Prazno - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Odaberi sve objekte STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Odaberi sve vrste tovara (uključujući i one bez tovara) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}Ni jedna vrsta tovara nije na čekanju # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} na putu iz {STATION}) STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} rezervisan za utovar) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Prihvata STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Prikaži spisak tovara koje stanica prihvata STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Prihvata: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}Ova stanica ima ekskluzivna transportna prava u ovom gradu. STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} je kupio ekskluzivna prava prevoza u ovom gradu. STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Ocene STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Prikaži ocene stanice STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Mesečna proizvodnja i rejting preduzeća: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}Sortiraj po STR_STATION_VIEW_WAITING_STATION :Stanica: Čekajuća STR_STATION_VIEW_WAITING_AMOUNT :Količina: Čekajuća STR_STATION_VIEW_PLANNED_STATION :Stanica: Planirana STR_STATION_VIEW_PLANNED_AMOUNT :Količina: Planirana STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} od {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} preko {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} do {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} od nepoznate stanice STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} do bilo koje stanice STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} preko bilo koje stanice STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} od ove stanice STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} uz stajanje na ovoj stanici STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} do te stanice STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} bez prekida STR_STATION_VIEW_GROUP_S_V_D :Polazište-Via-Odredište STR_STATION_VIEW_GROUP_S_D_V :Polazište-Odredište-Via STR_STATION_VIEW_GROUP_V_S_D :Via-Polazište-Odredište STR_STATION_VIEW_GROUP_V_D_S :Via-Odredište-Polazište STR_STATION_VIEW_GROUP_D_S_V :Odredište-Polazište-Via STR_STATION_VIEW_GROUP_D_V_S :Odredište-Via-Polazište ############ range for rating starts STR_CARGO_RATING_APPALLING :užas STR_CARGO_RATING_VERY_POOR :jako loše STR_CARGO_RATING_POOR :loše STR_CARGO_RATING_MEDIOCRE :osrednje STR_CARGO_RATING_GOOD :dobro STR_CARGO_RATING_VERY_GOOD :veoma dobro STR_CARGO_RATING_EXCELLENT :odlično STR_CARGO_RATING_OUTSTANDING :izvanredno ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centrira glavni pogled na lokaciju stanice. Ctrl+Klik otvara novi pogled na lokaciju stanice STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Preimenuj stanicu STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Prikazuje sve vozove koji imaju ovu stanicu u svom voznom redu STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Prikazuje sva drumka vozila koja imaju ovu stanicu u svom voznom redu STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Prikazuje sve letilice koje imaju ovu stanicu u svom voznom redu STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Prikazuje sve brodove koji imaju ovu stanicu u svom voznom redu STR_STATION_VIEW_RENAME_STATION_CAPTION :Preimenuj stanicu STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Zatvori aerodrom STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Spreči letelicu da sleti na ovaj aerodrom # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju čvorišta. Ctrl+Klik otvara novi pogled na čvorište STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Promena naziva putanje STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju bove. Ctrl+Klik otvara novi pogled na bovu STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Promeni naziv bove STR_EDIT_WAYPOINT_NAME :{WHITE}Promena naziva putanje # Finances window STR_FINANCES_CAPTION :{WHITE}{COMPANY} Finansije {BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Rashodi/Prihodi STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Izgradnja STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}Nova vozila STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Vozovi - Rashod STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Drumska vozila - Rashod STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Letelice - Rashod STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Brodovi - Rashod STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Održavanje vlasništva STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Vozovi - Prihod STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Drumska vozila - Prihod STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Letelice - Prihod STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Brodovi - Prihod STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Kamata na zajam STR_FINANCES_SECTION_OTHER :{GOLD}Ostalo STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}Ukupno: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Stanje na računu STR_FINANCES_LOAN_TITLE :{WHITE}Zajam STR_FINANCES_MAX_LOAN :{WHITE}Najviša Pozajmica: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}Pozajmi {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}Uvećanje količine zajma. Sa Ctrl+Klik se pozajmljuje najviši mogući iznos STR_FINANCES_REPAY_BUTTON :{BLACK}Vrati {CURRENCY_LONG} STR_FINANCES_REPAY_TOOLTIP :{BLACK}Otplati deo duga. Sa Ctrl+Klik se otplaćuje največi mogući iznos duga STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastruktura # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(vlasnik) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Osnovano: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Šema boja: STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Vozila: STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} voz{P "" a ova} STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} drumsk{P o a ih} vozil{P o a a} STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} letilic{P a e a} STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} brod{P "" a ova} STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}Nema STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Vrednost preduzeća: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% u vlasništvu preduzeća {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastruktura: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} de{P o la lova} pruge STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} de{P o la lova} druma STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} pločic{P a e a} sa vodom STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} pločic{P a e a} sa stanicom STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} aerodrom{P "" a a} STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}Nema STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Izgradnja upravne zgrade STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Izgrađuje upravnu zgradu preduzeća STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}Prikaži upravnu zgradu STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}Prebacuje pogled na upravnu zgradu preduzeća STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Preseli upravnu zgradu STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Premešta sedište preduzeća na drugu lokaciju za cenu od 1% vrednosti preduzeća. Shift+Klik prikazuje procenu troškova bez premeštanja zgrade STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Detalji STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}Detaljni pregled računa za infrastrukturu STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}Novo lice STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Izbor novog lica za vlasnika STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Šema boja STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Promena izgleda vozila preduzeća STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Ime preduzeća STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Promena imena preduzeća STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Ime vlasnika STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Promena imena vlasnika STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Otkupi 25% udela u preduzeću STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Prodaj 25% udela u preduzeću STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Otkup 25% udela u ovom preduzeću. Shift+Klik prikazuje procenu troškova bez kupovine udela STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Prodaja 25% udela u ovom preduzeću. Shift+Klik prikazuje procenu zarade bez prodaje udela STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Ime Preduzeća STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Ime vlasnika STR_BUY_COMPANY_MESSAGE :{WHITE}U potrazi smo za preduzećem koje bi preuzelo naše.{}{}Da li biste kupili {COMPANY} za {CURRENCY_LONG}? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastruktura preduzeća {COMPANY} STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Delova pruge: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signalizacija STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Delova druma: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Drum STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajska pruga STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Pločica sa vodom: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanali STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stanice: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Pločica sa stanicom STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Aerodromi STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/god # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Fabrike STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- Nema - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}){YELLOW} ({COMMA}% prevezeno) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}/{CARGO_LONG}{STRING}){YELLOW} ({COMMA}%/{COMMA}% prevezeno) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Imena fabrika - klikom na ime premešta se glavni pogled na fabriku. Ctrl+Klik otvara novi pogled na lokaciju fabrike # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Prošlomesečna proizvodnja: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% prevezeno) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju fabrike. Ctrl+Klik otvara novi pogled na lokaciju fabrike STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Nivo proizvodnje: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Fabrika je objavila da može svakog trenutka da se zatvori! ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Potražuje: {YELLOW}{STRING.aku}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Potražuje: {YELLOW}{STRING.aku}{STRING}, {STRING.aku}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Potražuje: {YELLOW}{STRING.aku}{STRING}, {STRING.aku}{STRING}, {STRING.aku}{STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Tovar koji čeka na obradu: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Proizvodi: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Proizvodi: {YELLOW}{STRING}{STRING}, {STRING}{STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}Promena proizvodnje STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Promena nivoa proizvodnje (u procentima, do 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} - {COMMA} Voz{P "" a ova} STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING} - {COMMA} Drumsk{P o a ih} Vozil{P o a a} STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING} - {COMMA} Brod{P "" a ova} STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING} - {COMMA} Leteluca STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Vozovi - kliknite na voz za podatke STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Drumska vozila - kliknite na vozilo za podatke STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Brodovi - kliknite na brod za podatke STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Letilice - kliknite na letilicu za podatke STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Ovogodišnja zarada: {CURRENCY_LONG} (prošle godine: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :Dostupni Vozovi STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Dostupna Drumska Vozila STR_VEHICLE_LIST_AVAILABLE_SHIPS :Dostupni Brodovi STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Dostupne Letelice STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}Prikazuje listu raspoloživih mašina za ovu vrstu vozila STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Upravljanje STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Pošaljite naredbu svim vozilima na ovoj listi STR_VEHICLE_LIST_REPLACE_VEHICLES :Obnovi vozila STR_VEHICLE_LIST_SEND_FOR_SERVICING :Pošalji na Servisiranje STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Pošalji u Depo STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Pošalji u Depo STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Pošalji u Depo STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Pošalji u Hangar STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Klikom se zaustavljaju sva vozila na spisku STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Klikom se pokreću sva vozila na spisku STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Deljene naredbe {COMMA} Vozil{P o a a} # Group window STR_GROUP_ALL_TRAINS :Svi vozovi STR_GROUP_ALL_ROAD_VEHICLES :Sva drumska vozila STR_GROUP_ALL_SHIPS :Svi brodovi STR_GROUP_ALL_AIRCRAFTS :Sve letilice STR_GROUP_DEFAULT_TRAINS :Negrupisani vozovi STR_GROUP_DEFAULT_ROAD_VEHICLES :Negrupisana drumska vozila STR_GROUP_DEFAULT_SHIPS :Negrupisani brodovi STR_GROUP_DEFAULT_AIRCRAFTS :Negrupisane letilice STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grupe - klikom na grupu se prikazuje spisak vozila u grupi. Hijerarhija grupa se uređuje metodom "prevuci i pusti" STR_GROUP_CREATE_TOOLTIP :{BLACK}Klikom se pravi nova grupa STR_GROUP_DELETE_TOOLTIP :{BLACK}Briše se označena grupa STR_GROUP_RENAME_TOOLTIP :{BLACK}Preimenovanje označene grupe STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Klikom se ova grupa štiti od globalne automatske zamene STR_GROUP_ADD_SHARED_VEHICLE :Dodaj deljeno vozilo STR_GROUP_REMOVE_ALL_VEHICLES :Ukloni sva vozila STR_GROUP_RENAME_CAPTION :{BLACK}Preimenuj grupu # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :Nova Železnička Vozila STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nova Železnička Električna Vozila STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nova Jednošinska Vozila STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nova Maglev Vozila STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Šinska Vozila STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nova Drumska Vozila STR_BUY_VEHICLE_SHIP_CAPTION :Novi Brodovi STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Nove Letilice STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Težina: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Brzina: {GOLD}{VELOCITY}{BLACK} Snaga: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Brzina: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Brzina na moru: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Brzina na kanalu/reci: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Cena održavanja: {GOLD}{CURRENCY_LONG}/god STR_PURCHASE_INFO_CAPACITY :{BLACK}Nosivost: {GOLD}{CARGO_LONG} {STRING} STR_PURCHASE_INFO_REFITTABLE :(prepravljiv) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Projektovan: {GOLD}{NUM}{BLACK} Životni vek: {GOLD}{COMMA} godin{P a e a} STR_PURCHASE_INFO_RELIABILITY :{BLACK}Najviša pouzdanost: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cena: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Težina: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Brzina: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Nosivost: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Motorni vagoni: {GOLD}+{POWER}{BLACK} Težina: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Prepravljivo za: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :Sve vrste tereta STR_PURCHASE_INFO_ALL_BUT :Sve sem {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Najveća vučna snaga: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Domet: {GOLD}{COMMA} pločica STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Spisak probranih šinskih vozila - kliknite na vozilo za više podataka STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Spisak probranih drumskih vozila - kliknite na vozilo za više podataka STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Spisak probranih brodova - kliknite na brod za više podataka STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Spisak probranih letilica - kliknite na vozilo za više podataka STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Kupi Vozilo STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Kupi Vozilo STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Kupi Brod STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Kupi Letelicu STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Kupuje označeno šinsko vozilo. Shift+Klik prikazuje procenu troškova bez kupovine STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Kupuje označeno drumsko vozilo. Shift+Klik prikazuje procenu troškova bez kupovine STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Kupuje označeni brod. Shift+Klik prikazuje procenu troškova bez kupovine STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Kupuje označenu letilicu. Shift+Klik prikazuje procenu troškova bez kupovine STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Promena naziva STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Preimenuj STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Preimenujte vrstu šinskog vozila STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Promenite naziv vrste drumskog vozila STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Promenite naziv vrste broda STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Promenite naziv vrste letilice STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Uključi skrivanje/prikazivanje tip voza STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Uključi skrivanje/prikazivanje tip drumskog vozila STR_BUY_VEHICLE_SHIP_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Uključi skrivanje/prikazivanje tip broda STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Uključi skrivanje/prikazivanje tip letilice STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Promena naziva vrste šinskog vozila STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Naziv vrste drumskog vozila STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Promena naziva vrste broda STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Promena naziva vrste letilice # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}Promena imena depoa STR_DEPOT_RENAME_DEPOT_CAPTION :Preimenuj depo STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} vozil{P o a a}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Vozovi - prevlačenjem se vozila dodaju/uklanjaju iz kompozicije, desni klik na voz za podatke o njemu, CTRL i desni klik za podatke o kompoziciji STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Vozila - desni klik na vozilo za podatke o njemu STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Brodovi - desni klik na brod za podatke o njemu STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Letilice - desni klik na letilicu za podatke o njoj STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Ovde prevucite šinsko vozilo kako biste ga prodali STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Ovde prevucite drumsko vozilo kako biste ga prodali STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Ovde prevucite brod kako biste ga prodali STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Ovde prevucite letilicu kako biste je prodali STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Prevucite ovde lokomotivu kako bi prodali ceo voz STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Prodaje sve vozove u depou STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Prodaje sva drumska vozila u depou STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Prodaje sve brodove u depou STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Prodaje sve letilice u hangaru STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Automatsko obnavljanje svih vozova u depou STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Automatsko obnavljanje svih drumskih vozila u depou STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Automatsko obnavljanje svih brodova u depou STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Automatsko obnavljanje svih letelica u hangaru STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}Nova Vozila STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}Nova Vozila STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}Novi Brodovi STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}Nova Letilica STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Kupovina novog šinskog vozila STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Kupovina novog drumskog vozila STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Kupovina novog broda STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Kupovina nove letilice STR_DEPOT_CLONE_TRAIN :{BLACK}Kopiraj Voz STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Kopiraj Vozilo STR_DEPOT_CLONE_SHIP :{BLACK}Kopiraj Brod STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Kopiraj Letilicu STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}Ovim ćete kupiti istu kompoziciju. Kliknite na dugme i potom na voz koji je u ili van depoa. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Ovim ćete kupiti isto drumsko vozilo. Kliknite na dugme i potom na drumsko vozilo koje je u ili van depoa. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}Ovim ćete kupiti isti brod. Kliknite na dugme i potom na brod koji je u ili van depoa. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}Ovim ćete kupiti istu letilicu. Kliknite na dugme i potom na letilicu koje je u ili van depoa. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju železničkog depoa. Ctrl+Klik otvara novi pogled na železnički depo STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju drumskog depoa. Ctrl+Klik otvara novi pogled na drumski depo STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju brodskog depoa. Ctrl+Klik otvara novi pogled na brodski depo STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju hangara. Ctrl+Klik otvara novi pogled na hangar STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Dohvata spisak svih vozova sa ovim depoom u naredbama STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Dohvata spisak svih drumskih vozila sa ovim depoom u naredbama STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Dohvata spisak svih brodova sa ovim depoom u naredbama STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Dohvata spisak svih letilica sa hangarom na ovoj stanici u naredbama STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Klikom se zaustavljaju svi vozovi unutar depoa STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klikom se zaustavljaju sva drumska vozila unutar depoa STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Klikom se zaustavljaju svi brodovi unutar depoa STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Klikom se zaustavljaju sve letilice unutar hangara STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Klikom se pokreću svi vozovi u depoima STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klikom se pokreću sva drumska vozila u depoima STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Klikom se pokreću svi brodovi u depoima STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Klikom se pokreću sve letilice u hangarima STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Upravo ćete prodati sva vozila u depou. Da li ste sigurni? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Poruka od proizvođača vozila STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Upravo smo završili projektovanje nov{G og e og} {STRING.aku} - da li ste zainteresovani za jednogodišnja eksluzivna prava upotrebe ovog vozila, kako bi smo proverili radne osobine pre puštanja u masovnu proizvodnju? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :{G=srednji}železničko vučno vozilo STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE.aku :železničkog vučnog vozila STR_ENGINE_PREVIEW_ROAD_VEHICLE :{G=srednji}drumsko vozilo STR_ENGINE_PREVIEW_ROAD_VEHICLE.aku :drumskog vozila STR_ENGINE_PREVIEW_AIRCRAFT :{G=ženski}letilica STR_ENGINE_PREVIEW_AIRCRAFT.aku :letilice STR_ENGINE_PREVIEW_SHIP :{G=muški}brod STR_ENGINE_PREVIEW_SHIP.aku :broda STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :{G=srednji}jednopružno žel. vučno vozilo STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE.aku :jednopružnog žel. vučnog vozila STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :{G=srednji}megnetno žel. vučno vozilo STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE.aku :magnetnog žel. vučnog vozila STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cena: {CURRENCY_LONG} Težina: {WEIGHT_SHORT}{}Brzina: {VELOCITY} Snaga: {POWER}{}Cena Održavanja: {CURRENCY_LONG}/god.{}Nosivost: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cena: {CURRENCY_LONG} Težina: {WEIGHT_SHORT}{}Brzina: {VELOCITY} Snaga: {POWER} Najveća vučna snaga: {6:FORCE}{}Cena Održavanja: {4:CURRENCY_LONG}/god{}Nosivost: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Najveća Brzina: {VELOCITY}{}Nosivost: {CARGO_LONG}, {CARGO_LONG}{}Cena Održavanja: {CURRENCY_LONG}/god. STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Najveća Brzina: {VELOCITY}{}Nosivost: {CARGO_LONG}{}Cena Održavanja: {CURRENCY_LONG}/god. STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cena: {CURRENCY_LONG} Najveća Brzina: {VELOCITY} Domet: {COMMA} pločica{}Nosivost: {CARGO_LONG}, {CARGO_LONG}{}Cena Održavanja: {CURRENCY_LONG}/god. STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Najveća Brzina: {VELOCITY} Domet: {COMMA} pločica{}Nosivost: {CARGO_LONG}{}Cena Održavanja: {CURRENCY_LONG}/god. # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}Zameni {STRING} - {STRING} STR_REPLACE_VEHICLE_TRAIN :voz STR_REPLACE_VEHICLE_TRAIN.big :Voz STR_REPLACE_VEHICLE_TRAIN.gen :voza STR_REPLACE_VEHICLE_TRAIN.aku :voz STR_REPLACE_VEHICLE_ROAD_VEHICLE :drumsko vozilo STR_REPLACE_VEHICLE_ROAD_VEHICLE.big :Drumsko vozilo STR_REPLACE_VEHICLE_ROAD_VEHICLE.gen :drumskog vozila STR_REPLACE_VEHICLE_ROAD_VEHICLE.aku :drumsko vozilo STR_REPLACE_VEHICLE_SHIP :brod STR_REPLACE_VEHICLE_SHIP.big :Brod STR_REPLACE_VEHICLE_SHIP.gen :broda STR_REPLACE_VEHICLE_SHIP.aku :brod STR_REPLACE_VEHICLE_AIRCRAFT :letelica STR_REPLACE_VEHICLE_AIRCRAFT.aku :letelicu STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Upotrebljena vozila STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Dostupna vozila STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Izaberite vrstu lokomotive za zamenu STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Izaberite novu vrstu lokomotive koju biste želeli da koristite umesto obeležene s leve strane STR_REPLACE_VEHICLES_START :{BLACK}Počni Zamenu Vozila STR_REPLACE_VEHICLES_NOW :Zameni sva vozila sada STR_REPLACE_VEHICLES_WHEN_OLD :Zameni samo stara vozila STR_REPLACE_HELP_START_BUTTON :{BLACK}Pritisnite kako bi počela zamena vrste lokomotive označena sa leve strane sa vrstom označenom sa desne STR_REPLACE_NOT_REPLACING :{BLACK}Nezamenjuje se STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Nijedno vozilo nije označeno STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} kada prethodni STR_REPLACE_VEHICLES_STOP :{BLACK}Zaustavi Zamenu Vozila STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Pritisnite kako bi se zaustavila zamena vrsta lokomotive označene sa leve strane STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Zamenjuje se: {ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Prebacuje između prikaza zamene lokomotiva i zamene vagona STR_REPLACE_ENGINES :Lokomotive STR_REPLACE_WAGONS :Vagoni STR_REPLACE_HELP_RAILTYPE :{BLACK}Izaberite vrstu pruge za koju želite zamenu kompozicije STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Prikazuje koja lokomotiva će se zameniti označenom sa leve strane, ako ih ima STR_REPLACE_RAIL_VEHICLES :Šinska Vozila STR_REPLACE_ELRAIL_VEHICLES :Elektrošinska Vozila STR_REPLACE_MONORAIL_VEHICLES :Jednošinska Vozila STR_REPLACE_MAGLEV_VEHICLES :Magnetnošinska Vozila STR_REPLACE_REMOVE_WAGON :{BLACK}Ukanjanje vagona: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Ukoliko bi se zamenom kompozicija produžila, automatska obnova će ukloniti vagone (sa početka) kako bi se zadržala dužina kompozicije # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju voza. Ctrl+Klik će pratiti voz u glavnom pogledu STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju vozila. Ctrl+Klik će pratiti vozilo u glavnom pogledu STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju broda. Ctrl+Klik će pratiti brod u glavnom pogledu STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Prebacuje glavni pogled na lokaciju letilice. Ctrl+Klik će pratiti letelicu u glavnom pogledu STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošaljite voz u depo. Sa Ctrl+Klik će otići samo na servis STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošaljite vozilo u depo. Sa Ctrl+Klik će otići samo na servis STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošaljite brod u depo. Sa Ctrl+Klik će otići samo na servis STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Pošaljite letilicu u hangar. Sa Ctrl+Klik će otići samo na servis STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Ovim ćete kupiti istu kompoziciju. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Ovim ćete kupiti isto drumsko vozilo. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Ovim ćete kupiti isti brod. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Ovim ćete kupiti kopiju letilice. Sa Ctrl+Klik će imati zajedničke naredbe. Shift+Klik prikazuje procenu troškova bez kupovine STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Nateraj voza da krene bez čekanja na signal za slobodan kolosek STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Prepravlja voz kako bi prevozio drugu vrstu tereta STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Prepravite drumsko vozilo kako bi prevozio drugu vrstu tovara STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Prepravite brod kako bi prevozio drugu vrstu tereta STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Prepravite letilicu kako bi prevozila drugu vrstu tereta STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Promena smera kretanja voza STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Naterajte vozilo da okrene STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Prikazuje naredbe vozu. Ctrl+Klik za prikaz reda vožnje STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Prikazuje naredbe vozilu. Ctrl+Klik za prikaz reda vožnje STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Prikazuje naredbe brodu. Ctrl+Klik za prikaz reda vožnje STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Prikazuje naredbe letilici. Ctrl+Klik za prikaz reda vožnje STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Prikazuje podatke o vozu STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Prikazuje detalje drumskog vozila STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Prikazuje podatke o brodu STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Prikazuje podatke o letilici STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Trenutno stanje voza - kliknite ovde za zaustavljanje/pokretanje voza. Ctrl+Klik pomera pogled na odredište STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Trenutno stanje vozila - kliknite ovde za zaustavljanje/pokretanje vozila. Ctrl+Klik pomera pogled na odredište STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Trenutno stanje broda - kliknite ovde za zaustavljanje/pokretanje broda. Ctrl+Klik pomera pogled na odredište STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Trenutno stanje letilice - kliknite ovde za zaustavljanje/pokretanje letilice. Ctrl+Klik pomera pogled na odredište # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Utovarivanje / Istovarivanje STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Kreće STR_VEHICLE_STATUS_CRASHED :{RED}Havarisan! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Pokvaren STR_VEHICLE_STATUS_STOPPED :{RED}Zaustavljen STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Zaustavlja se, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}Nema struje STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Čekanje za slobodan prolaz STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Previše je daleko do sledeće destinacije STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Ide ka {STATION}, {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}Nema naredbi, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Ide ka {WAYPOINT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Ide ka {DEPOT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Servisiranje u {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Zaustavljeno STR_VEHICLE_COMMAND_STOPPED :{RED}Zaustavljeno STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Pokrenuto STR_VEHICLE_COMMAND_STARTED :{GREEN}Pokrenuto # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Opširnije) STR_VEHICLE_NAME_BUTTON :{BLACK}Ime STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Naziv voza STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Naziv drumskog vozila STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Naziv broda STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Naziv letilice STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Starost: {LTBLUE}{STRING}{BLACK} Cena Održavanja: {LTBLUE}{CURRENCY_LONG}/god. # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} godin{P a e a} ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} godin{P a e a} ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Najveća brzina: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Najveća brzina: {LTBLUE}{VELOCITY} {BLACK}Domet: {LTBLUE}{COMMA} pločica STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Težina: {LTBLUE}{WEIGHT_SHORT} {BLACK}Snaga: {LTBLUE}{POWER}{BLACK} Najveća brzina: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Težina: {LTBLUE}{WEIGHT_SHORT} {BLACK}Snaga: {LTBLUE}{POWER}{BLACK} Najveća brzina: {LTBLUE}{VELOCITY} {BLACK} Najveća vučna snaga: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Ovogodišnja zarada: {LTBLUE}{CURRENCY_LONG} (prošlogodišnja: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Pouzdanost: {LTBLUE}{COMMA}% {BLACK}Kvarova od poslednjeg servisa: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Kupljen: {LTBLUE}{NUM}{BLACK} Vrednost: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Nosivost: {LTBLUE}Nula{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Nosivost: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Nosivost: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Nosivost: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Zarada od transfera: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Period servisiranja: {LTBLUE}{COMMA}dana{BLACK} Poslednji servis: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Period servisiranja: {LTBLUE}{COMMA}%{BLACK} Poslednji servis: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Povećava period servisiranja za 10. Ctrl+Klik povećava period servisiranja za 5 STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Smanjuje period servisiranja za 10. Ctrl+Klik smanjuje period servisiranja za 5 STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Promeni tip intervala za servis STR_VEHICLE_DETAILS_DEFAULT :Standard STR_VEHICLE_DETAILS_DAYS :dani STR_VEHICLE_DETAILS_PERCENT :Procenat STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Naziv voza STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Naziv drumskog vozila STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Naziv broda STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Naziv letilice # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Kupljen: {LTBLUE}{NUM}{BLACK} Vrednost: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Vrednost: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Ukupna nosivost ovog voza: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Prazno STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} sa {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} sa {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Tovar STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Prikazuje podatke o tovaru koji se prevozi STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Podaci STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Prikazuje podatke o kompoziciji STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Kapaciteti STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Prikazuje nosivost svih vozila u kompoziciji STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Ukupni tovar STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Prikazuje ukupnu nosivost voza, podeljenu po vrsti tovara STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Nosivost: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Prepravljanje) STR_REFIT_TITLE :{GOLD}Izaberite vrstu tereta za prevoz: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nova nosivost: {GOLD}{CARGO_LONG}{}{BLACK}Cena prepravke: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}Nova nosivost: {GOLD}{CARGO_LONG}{}{BLACK}Prihod od prepravke: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Nova nosivost: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Cena prepravke: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}Nova nosivost: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Prihod od prepravke: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Obeležavanje vozila za prepravku. Povlačenjem miša moguće je obležiti više vozila. Klikom na prazan prostor obležava celo vozilo. Sa Ctrl+Klik će se obeležiti vozilo i prateći lanac STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Označite vrstu tovara za prepravljanje voza STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Označite vrstu tovara za prepravljanje drumskog vozila STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Označite vrstu tovara za prepravljanje broda STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Odaberite vrstu tereta koju će letilica prevoziti STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Prepavi voz STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Prepravi drumsko vozilo STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Prepravi brod STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Prepravi letilicu STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Prepravlja voz za prevoz označene vrste tovara STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Prepravlja drumsko vozilo za prevoz označene vrste tovara STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Prepravlja brod za prevoz označene vrste tovara STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Prepravite letilicu kako bi prevozila označenu vrstu tereta # Order view STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Naredbe) STR_ORDERS_TIMETABLE_VIEW :{BLACK}Raspored STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Prelazi na raspored STR_ORDERS_LIST_TOOLTIP :{BLACK}Spisak naredbi - klikom se obeležava naredba. Sa Ctrl+Klik se prelazi na lokaciju stanice STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - Kraj Naredbi - - STR_ORDERS_END_OF_SHARED_ORDERS :- - Kraj Zajedničkih Naredbi - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}Direktno STR_ORDER_GO_TO :Idi do STR_ORDER_GO_NON_STOP_TO :Idi direktno do STR_ORDER_GO_VIA :Idi preko STR_ORDER_GO_NON_STOP_VIA :Idi direktno preko STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Promena načina zaustavljnja u označenoj naredbi STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Pun utovar bilo kog STR_ORDER_DROP_LOAD_IF_POSSIBLE :Utovar ako ima STR_ORDER_DROP_FULL_LOAD_ALL :Pun utovar svega STR_ORDER_DROP_FULL_LOAD_ANY :Pun utovar bilo kog STR_ORDER_DROP_NO_LOADING :Bez utovara STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Promena načina utovara u označenoj naredbi STR_ORDER_TOGGLE_UNLOAD :{BLACK}Istovar svega STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Istovar ako se prihvata STR_ORDER_DROP_UNLOAD :Istovar svega STR_ORDER_DROP_TRANSFER :Prevoz STR_ORDER_DROP_NO_UNLOADING :Bez istovara STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Promena načina istovara u označenoj naredbi STR_ORDER_REFIT :{BLACK}Prepravi STR_ORDER_REFIT_TOOLTIP :{BLACK}Označite za koji tovar da se prepravi u ovoj naredbi. Ctrl+Klik za uklanjanje prepravljanja STR_ORDER_REFIT_AUTO :{BLACK}Samo-prepravljanje STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Odabir vrste tereta za samo-prepravljanje po redosledu. Ctrl+Klik za uklanjanje komande za prepravljanje. Samo-prepravljanje će se izvršiti samo ako vozilo to dozvoljava STR_ORDER_DROP_REFIT_AUTO :Određen tovar STR_ORDER_DROP_REFIT_AUTO_ANY :Dostupan tovar STR_ORDER_SERVICE :{BLACK}Servis STR_ORDER_DROP_GO_ALWAYS_DEPOT :Uvek STR_ORDER_DROP_SERVICE_DEPOT :Servis po potrebi STR_ORDER_DROP_HALT_DEPOT :Zaustavljanje STR_ORDER_SERVICE_TOOLTIP :{BLACK}Preskače ovu naredbu ukoliko servis nije potreban STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Skok na osnovu podatka o vozilu # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Procenat natovarenog STR_ORDER_CONDITIONAL_RELIABILITY :Pouzdanost STR_ORDER_CONDITIONAL_MAX_SPEED :Najveća brzina STR_ORDER_CONDITIONAL_AGE :Starost (godine) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Servis STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Uvek STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Isticanje životnog veka (godine) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Kako se upoređuje podatak o vozilu sa unetom vrednošću STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :jednako STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :različito od STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :manje od STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :manje ili jednako STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :veće od STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :veće ili jednako STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :potreban STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :nepotreban STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}Vrednost za poređenje sa podatkom o vozilu STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Unos vrednosti za poređenje STR_ORDERS_SKIP_BUTTON :{BLACK}Preskoči STR_ORDERS_SKIP_TOOLTIP :{BLACK}Preskoči tekuću naredbu, i prelazi na sledeću. Ctrl+Klik preskače naredbe do obeležene STR_ORDERS_DELETE_BUTTON :{BLACK}Izbriši STR_ORDERS_DELETE_TOOLTIP :{BLACK}Uklanja obeleženu naredbu STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Uklanja sva naređenja STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Prekini deljenje STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Prekida deljenje liste naredbi. Sa Ctrl+Klik se još i briše cela lista naredbi STR_ORDERS_GO_TO_BUTTON :{BLACK}Idi do STR_ORDER_GO_TO_NEAREST_DEPOT :Idi do najbližeg depoa STR_ORDER_GO_TO_NEAREST_HANGAR :Idi do najbližeg hangara STR_ORDER_CONDITIONAL :Uslovna naredba skoka STR_ORDER_SHARE :Deli naredbe STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Ubacuje novu naredbu pre obeležene, ili je dodaje na kraju spiska. Ctrl čini da stanica naredi "pun bilo koji tovar", putna tačka naredi "non-stop" i depo naredi "servis". "Deli naredbe" ili Ctrl omogućava da vozilo deli naredbe sa drugim odabranim vozilom. Klikom na drugo vozilo kopiraju se njegove naredbe. Naredbom za depo se isključuje automatsko servisiranje STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Prikazuje sva vozila koja dele ovaj red vožnje # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Idi preko {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Idi direktno preko {WAYPOINT} STR_ORDER_SERVICE_AT :Servisiranje u STR_ORDER_SERVICE_NON_STOP_AT :Diektno na servisiranje u STR_ORDER_NEAREST_DEPOT :najbliži STR_ORDER_NEAREST_HANGAR :najbliži Hangar STR_ORDER_TRAIN_DEPOT :Železnički Depo STR_ORDER_ROAD_VEHICLE_DEPOT :Drumski Depo STR_ORDER_SHIP_DEPOT :Brodogradilište STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(Prepravi za {STRING}) STR_ORDER_REFIT_STOP_ORDER :(Prepravi za {STRING} i stani) STR_ORDER_STOP_ORDER :(Stani) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(Podrazumevano) STR_ORDER_FULL_LOAD :(Pun utovar) STR_ORDER_FULL_LOAD_ANY :(Pun utovar bilo kog) STR_ORDER_NO_LOAD :(Bez utovara) STR_ORDER_UNLOAD :(Istovar i utovar) STR_ORDER_UNLOAD_FULL_LOAD :(Istovar i pun utovar svega) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Istovar i pun utovar bilo kog) STR_ORDER_UNLOAD_NO_LOAD :(Istovar bez utovara) STR_ORDER_TRANSFER :(Prevoz i utovar) STR_ORDER_TRANSFER_FULL_LOAD :(Prevoz i pun utovar svega) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Prevoz i pun utovar bilo kog) STR_ORDER_TRANSFER_NO_LOAD :(Prevoz bez utovara) STR_ORDER_NO_UNLOAD :(Bez istovara i utovar) STR_ORDER_NO_UNLOAD_FULL_LOAD :(Bez istovara i pun utovar) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Bez istovara i pun utovar bilo kog) STR_ORDER_NO_UNLOAD_NO_LOAD :(Bez istovara i bez utovara) STR_ORDER_AUTO_REFIT :(Samo-prepravljanje za {STRING}) STR_ORDER_FULL_LOAD_REFIT :(Pun utovar sa samo-prepravljanjem za {STRING}) STR_ORDER_FULL_LOAD_ANY_REFIT :(Pun utovar bilo kog sa samo-prepravljanjem za {STRING}) STR_ORDER_UNLOAD_REFIT :(Istovar i utovar sa samo-prepravljanjem za {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Istovar i pun utovar svega sa samo-prepravljanjem za {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Istovar i pun utovar bilo kog sa samo-prepravljanjem za {STRING}) STR_ORDER_TRANSFER_REFIT :(Prevoz i utovar sa samo-prepravljanjem za {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Prevoz i pun utovar svega sa samo-prepravljanjem za {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Prevoz i pun utovar bilo kog sa samo-prepravljanjem za {STRING}) STR_ORDER_NO_UNLOAD_REFIT :(Bez istovara i utovar sa samo-prepravljanjem za {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Bez istovara i pun utovar sa samo-prepravljanjem za {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Bez istovara i pun utovar bilo kog sa samo-prepravljanjem za {STRING}) STR_ORDER_AUTO_REFIT_ANY :dostupni tovar STR_ORDER_STOP_LOCATION_NEAR_END :[pri početku] STR_ORDER_STOP_LOCATION_MIDDLE :[na sredini] STR_ORDER_STOP_LOCATION_FAR_END :[pri kraju] STR_ORDER_OUT_OF_RANGE :{RED} (Sledeća destinacija je van dometa) STR_ORDER_CONDITIONAL_UNCONDITIONAL :Pređi na naredbu {COMMA} STR_ORDER_CONDITIONAL_NUM :Pređi na naredbu {COMMA} kada je {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :Pređi na naredbu {COMMA} kada je {STRING} {STRING} STR_INVALID_ORDER :{RED} (Neispravna Naredba) # Time table window STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Raspored) STR_TIMETABLE_ORDER_VIEW :{BLACK}Naredbe STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Prelazi na naredbe STR_TIMETABLE_TOOLTIP :{BLACK}Raspored - klikom se obeležava naredba STR_TIMETABLE_NO_TRAVEL :Nema putovanja STR_TIMETABLE_NOT_TIMETABLEABLE :Putovanje (automatski; raspored po redu naredbi) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Putovanje (bez rasporeda) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Putovanje sa najviše {2:VELOCITY} (bez rasporeda) STR_TIMETABLE_TRAVEL_FOR :Putovanje za {STRING} STR_TIMETABLE_TRAVEL_FOR_SPEED :Putovanje do {STRING} sa najviše {VELOCITY} STR_TIMETABLE_STAY_FOR :i ostani {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :i putuj {STRING} STR_TIMETABLE_DAYS :{COMMA} dan{P "" a a} STR_TIMETABLE_TICKS :{COMMA} utkucaj{P "" a a} STR_TIMETABLE_TOTAL_TIME :{BLACK}Za završetak rasporeda trebaće {STRING} STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}Za završetak rasporeda trebaće barem {STRING} (merenja nisu završena) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}Vozilo trenutno ide po rasporedu STR_TIMETABLE_STATUS_LATE :{BLACK}Vozilo trenutno kasni za {STRING} od rasporeda STR_TIMETABLE_STATUS_EARLY :{BLACK}Vozilo trenutno žuri za {STRING} od rasporeda STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}Ovaj raspored još nije počeo STR_TIMETABLE_STATUS_START_AT :{BLACK}Ovaj raspored počinje {STRING} STR_TIMETABLE_STARTING_DATE :{BLACK}Datum početka STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Izaberi datum kao početak ovog rasporeda. Ctrl+Click namešta polaznu tačku ovog rasporeda i deli ovaj raspored sa svim povezanim rasporedima STR_TIMETABLE_CHANGE_TIME :{BLACK}Promena Vremena STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Menjanje količine vremena za koje će obeležena naredba trajati STR_TIMETABLE_CLEAR_TIME :{BLACK}Ukloni Vreme STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Uklanja vreme koje je određeno za obeleženu naredbu STR_TIMETABLE_CHANGE_SPEED :{BLACK}Promeni Ograničenje Brzine STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Menjanje ograničenja najviše brzine putovanja onznačene naredbe STR_TIMETABLE_CLEAR_SPEED :{BLACK}Ukloni Ograničenje Brzine STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Uklanja ograničenje najviše brzine putovanja označene naredbe STR_TIMETABLE_RESET_LATENESS :{BLACK}Poništi Merač Kašnjenja STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Poništava merač kašnjenja, tako da vozilo ide na vreme STR_TIMETABLE_AUTOFILL :{BLACK}Automatsko popunjavanje STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Popunjava raspored sa vrednostima iz sledećeg putovanja (Ctrl+Klik za zadržavanje vremena čekanja) STR_TIMETABLE_EXPECTED :{BLACK}Očekivano STR_TIMETABLE_SCHEDULED :{BLACK}Po planu STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Prebacivanje između prikaza očekivanog i po planu STR_TIMETABLE_ARRIVAL_ABBREVIATION :D: STR_TIMETABLE_DEPARTURE_ABBREVIATION :P: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}Postavljanje datuma STR_DATE_SET_DATE :{BLACK}Postavi datum STR_DATE_SET_DATE_TOOLTIP :{BLACK}Koristi izabrani datum kao početni datum ovog rasporeda STR_DATE_DAY_TOOLTIP :{BLACK}Izbor dana STR_DATE_MONTH_TOOLTIP :{BLACK}Izbor meseca STR_DATE_YEAR_TOOLTIP :{BLACK}Izbor godine # AI debug window STR_AI_DEBUG :{WHITE}Korekcija veštačke inteligencije / skripte partije STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Naziv skripte STR_AI_DEBUG_SETTINGS :{BLACK}Podešavanja STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Promena podešavanja vezanih za skriptu STR_AI_DEBUG_RELOAD :{BLACK}Ponovno učitavanje STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Zaustavlja Veštačku Inteligenciju, ponovo učitava skriptu, i restartuje je STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Uključuje/isključuje prekidanje kada VI ispiše poruku koja se poklapa sa prekidnom niskom STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Prekid na: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Prekid na STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Kada VI ispiše poruku koja se poklapa sa ovom niskom, partija se pauzira STR_AI_DEBUG_MATCH_CASE :{BLACK}Podudaranje vel. slova STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Uključuje/isključuje podudaranje malih i velikih slova tokom poređenja zapisanih VI poruka sa prekidnom niskom STR_AI_DEBUG_CONTINUE :{BLACK}Nastavi STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Nastavlja partiju i VI STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Prikazuje podatke radi korekcije ove VI STR_AI_GAME_SCRIPT :{BLACK}Skripta Partije STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Pregled zapisnika Skripte partije STR_ERROR_AI_NO_AI_FOUND :Nije pronađena nijedna prikladna VI.{}Učitana zamena neće raditi ništa.{}Možete preuzeti nekoliko VI preko sistema za preuzimanje dodataka STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}Jedna od pokrenutih skripti je pukla. Molimo vas da prijavite grešku autoru skripte sa slikom prozora za korigovanje VI / Skripte Partije STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}Prozor za korigovanje VI / Skripte Partije je dostupan samo na serveru # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}Podešavanja VI / Skripte Partije STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}Skripta parije koja će biti pokrenuta u sledećoj partiji STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}Veštačke inteligencije koje će biti pokrenute u sledećoj partiji STR_AI_CONFIG_HUMAN_PLAYER :Ljudsko biće STR_AI_CONFIG_RANDOM_AI :Proizvoljna VI STR_AI_CONFIG_NONE :(nijedna) STR_AI_CONFIG_MOVE_UP :{BLACK}Pomeri Naviše STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Pomera obeleženu VI naviše u listi STR_AI_CONFIG_MOVE_DOWN :{BLACK}Pomeri Naniže STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Pomera obeleženu VI naniže u listi STR_AI_CONFIG_GAMESCRIPT :{SILVER}Skripta Partije STR_AI_CONFIG_AI :{SILVER}VIe STR_AI_CONFIG_CHANGE :{BLACK}Izaberi {STRING} STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :VI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Skripta Partije STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Učitava drugu skriptu STR_AI_CONFIG_CONFIGURE :{BLACK}Podešavanje STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Podešavanje parametara skripte # Available AIs window STR_AI_LIST_CAPTION :{WHITE}Dostupno {STRING} STR_AI_LIST_CAPTION_AI :VIe STR_AI_LIST_CAPTION_GAMESCRIPT :Skripte Partije STR_AI_LIST_TOOLTIP :{BLACK}Klikom se označava skripta STR_AI_LIST_AUTHOR :{LTBLUE}Autor: {ORANGE}{STRING} STR_AI_LIST_VERSION :{LTBLUE}Izdanje: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{STRING} STR_AI_LIST_ACCEPT :{BLACK}Prihvati STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Izabira označenu skriptu STR_AI_LIST_CANCEL :{BLACK}Otkaži STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Ne menja skriptu # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parametri STR_AI_SETTINGS_CAPTION_AI :VI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Skripta Partije STR_AI_SETTINGS_CLOSE :{BLACK}Zatvori STR_AI_SETTINGS_RESET :{BLACK}Poništi STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} STR_AI_SETTINGS_START_DELAY :Broj dana za pokretanje ove VI posle prethodne (otprilike): {ORANGE}{STRING} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} uputstvo za {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} izmene od {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licenca od {STRING} STR_TEXTFILE_VIEW_README :{BLACK}Prikaži uputstvo STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Izmene STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licenca # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Trošak: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}Trošak: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Prihod: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}Prihod: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG} STR_FEEDER :{YELLOW}Transfer: {CURRENCY_LONG} STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Prihod: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Prihod: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Trošak: {CURRENCY_LONG} STR_FEEDER_COST :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Trošak: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Procena troška: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Procena zarade: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Čuvanje je još u toku,{}molim sačekajte dok se ne završi! STR_ERROR_AUTOSAVE_FAILED :{WHITE}Neuspešno automatsko čuvanje STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Čitanje sa diska nije uspelo STR_ERROR_GAME_SAVE_FAILED :{WHITE}Čuvanje pozicije nije uspelo{}{STRING} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Brisanje datoteke nije uspelo STR_ERROR_GAME_LOAD_FAILED :{WHITE}Učitavanje pozicije nije uspelo{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Unutrašnja greška: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Neispravna sačuvana partija - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Partija je sačuvana sa novijom verzijom igre STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Datoteka se ne može pročitati STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Ne može se upisivati u datoteku STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Integritet podataka je narušen STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Partija je sačuvana u vreziji bez podrške za tramvaje. Svi tramvaji su uklonjeni # Map generation messages STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Kreiranje terena otkazano...{}... nepostoje prikladne lokacije za naselja STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... nepostoji nijedno naselje u ovom scenariju STR_ERROR_PNGMAP :{WHITE}Ne može se naparaviti reljef iz PNG slike... STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... datoteka nije nađena STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... ne može se preraditi vrsta slike. Potrebna je 8 ili 24-bitna PNG slika STR_ERROR_PNGMAP_MISC :{WHITE}... nešto nije uredu (verovatno je datoteka oštećena) STR_ERROR_BMPMAP :{WHITE}Ne može se naparaviti reljef iz BMP slike... STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... ne može se preraditi vrsta slike STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... slika je previše velika STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Upozorenje o veličini STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Preterana promena veličine karte nije preporučljiva. Da li da se nastavi generisanje? # Soundset messages STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Pronađen je samo rezervni skup zvukova. Ukoliko želite zvukove, preuzmite skup zvukova preko sistema za dodatke # Screenshot related messages STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Ogromna slika ekrana STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}Slika ekrana će imati rezoluciju {COMMA} x {COMMA} tačaka. Snimanje slike će možda malo potrajati. Da li hoćete da nastavite? STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Slika je snimljena pod imenom '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}Slika nije snimljena! # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Poruka STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}{STRING} je poslao/la poruku # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Izvan terena STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Previše je blizu ivici terena STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Nema dovoljno novca - potrebno je {CURRENCY_LONG} STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Neophodno je ravno tlo STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Teren je nagnut na lošu stranu STR_ERROR_CAN_T_DO_THIS :{WHITE}Neizvodljivo... STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Zgradu bi trebalo srušiti prethodno STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Područje ne može biti očišćeno... STR_ERROR_SITE_UNSUITABLE :{WHITE}... mesto je neadekvatno STR_ERROR_ALREADY_BUILT :{WHITE}... već izgrađeno STR_ERROR_OWNED_BY :{WHITE}... je u vlasništvu igrača {STRING} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... zemljište je u vlasništvu drugog preduzeća STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... dostignuto ograničenje u izmeni reljefa STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... dostignuto ograničenje u čišćenju pločica STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... dosegnut limit u sadnji stabala STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Naziv mora biti jedinstven STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} je na putu STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Nije dozvoljeno tokom pauze # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} vlast odbija da izda dozvolu STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}Lokalna uprava naselja {TOWN} ne namerava da izda dozvolu za gradnju još jednog aerodroma STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}{TOWN} lokalna vlast odbija da dâ dozvolu za aerodrom zbog visokog nivoa buke STR_ERROR_BRIBE_FAILED :{WHITE}Pokušaj podmićivanja otkrio je regionalni finansijski istražitelj # Levelling errors STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}Nije izvodljivo ovde podići zemljište... STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Nije izvodljivo ovde spustiti zemljište... STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Nije izvodljivo ovde poravnati zemljište... STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Iskopavanje bi oštetilo tunel STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... teren je već na nivou mora STR_ERROR_TOO_HIGH :{WHITE}... previsoko STR_ERROR_ALREADY_LEVELLED :{WHITE}... već je ravno STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND :{WHITE}Posle toga most bi bio previše visok. # Company related errors STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Preduzeće se ne može preimenovati... STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Vlasnik se ne može preimenovati... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... maksimalan dozvoljen zajam iznosi: {CURRENCY_LONG} STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Nije moguće pozajmiti još novca... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... nema duga STR_ERROR_CURRENCY_REQUIRED :{WHITE}... potrebno {CURRENCY_LONG} STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Nije moguće vratiti deo zajma... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Nemoguće je dati novac koji je pozajmljen od banke... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Nije moguće kupiti preduzeće... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Nije moguće izgraditi upravnu zgradu... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Otkup 25% udela ovog preduzeća nije moguć... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Prodaja 25% udela ovog preduzeća nije moguća... STR_ERROR_PROTECTED :{WHITE}Ovo preduzeće nije dovoljno dugo aktivno za trgovinu akcijama... # Town related errors STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Ne mogu da napravim naselje STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Naselje nije moguće preimenovati... STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Ovde je nemoguće izgraditi naselje... STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Naselje se ne može proširiti... STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... previše blizu ivici terena STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... drugo naselje je previše blizu STR_ERROR_TOO_MANY_TOWNS :{WHITE}... ima previše naselja STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... više ne postoji slobodnog prostora na terenu STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}Naselje neće graditi kolovoze. Možete uključiti gradnju kolovoza preko Napredna Podešavalja->Ekonomija->Naselja STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Putni radovi u toku STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Ovo naselje se ne može ukloniti...{}Stanica ili depo na zemljištvu naselja se ne može ukloniti STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... ne postoji prikladno mesto za spomenik u centru ovog naselja # Industry related errors STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... ima previše fabrika STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Nemoguće stvaranje fabrika... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}{STRING} je nemoguće izgraditi ovde... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Nije moguće ovde izgraditi taj tip industrije... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... previše blizu druge fabrike STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... prvo bi trebalo podići naselje STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... dozvoljena je samo jedna ovakva gradnja po naselju STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... dozvoljeno izgraditi samo u naseljima sa populacijom od najmanje 1200 STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... gradnja je dozvoljena samo u područjima pod tropskim šumama STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... gradnja je dozvoljena samo u pustinjskim oblastima STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... može da se izgradi samo u naseljima (zamenjujući kuće) STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... može da se izgradi samo blizu centra naselja STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... gradnja je dozvoljena samo u nizijskim oblastima STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... može biti postavljeno samo blizu ivica terena STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... šuma može biti posađena samo iznad linije snega STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... može biti izgrađena samo iznad linije snega STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... može biti izgrađena samo ispod linije snega STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Nije bilo odgovarajućih mesta za '{STRING}' fabrike # Station construction related errors STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Izgradnja železničke stanice ovde nije moguća... STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Izgradnja autobuske stanice ovde nije moguća... STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Izgradnja stanice za utovar/istovar kamiona ovde nije moguća... STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Izgradnja putničke tramvajske stanice ovde nije moguća... STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Izgradnja teretne tramvajske stanice ovde nije moguća... STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Izgradnja pristaništa ovde nije moguća... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Aerodrom se ovde ne može izgraditi... STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Stanica se spaja sa najmanje dve postojeće stanice STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... stanica je previše rasprostranjena STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Previše je stanica STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Previše delova železničke stanice STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Previše autobuskih stanica STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Previše tovarnih stanica STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Previše je blizu druge stanice STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Previše je blizu drugog pristaništa STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Previše je blizu drugog aerodroma STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Ova stanica ne može biti preimenovana... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... ova ulica je u vlasništvu naselja STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... ulica je okrenuta u drugom pravcu STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... stajalište ne može biti na krivini STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... stajalište ne može biti na raskrsnici # Station destruction related errors STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Deo stanice se ne može ukloniti... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Mora se prvo ukloniti železnička stanica STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Nemoguće je ukloniti autobusku stanicu odatle... STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Nemoguće je ukloniti teretnu stanicu odatle... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Nemoguće je ukloniti putničku tramvajsku stanicu odatle... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Nemoguće je ukloniti teretnu tramvajsku stanicu odatle... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Potrebno je prvo ukloniti stajalište STR_ERROR_THERE_IS_NO_STATION :{WHITE}... ovde nema stanice STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Potrebno je prvo srušiti železničku stanicu STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Potrebno je prvo srušiti autobusku stanicu STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Potrebno je prvo srušiti stanicu za utovar kamiona STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Prvo se mora ukloniti putnička tamvajska stanica STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Prvo se mora ukloniti tovarna tamvajska stanica STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Potrebno je prvo srušiti pristanište STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Potrebno je prvo srušiti aerodrom # Waypoint related errors STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Spajanje više od jedne postojeće putanje STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Suviše blizu druge putanje STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Ovde se ne može izgraditi putanja za prugu... STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Bova se ovde ne može postaviti... STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Neuspešna promena naziva putanje... STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Odavde se ne može ukloniti putanja za prugu... STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Prvo se mora ukloniti putanja za prugu STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... bova stoji na putu STR_ERROR_BUOY_IS_IN_USE :{WHITE}... plovak koristi drugo preduzeće! # Depot related errors STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Izgradnja železničkog depoa ovde nije moguća... STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Izgradnja drumskog depoa ovde nije moguća... STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Izgradnja tramvajskog depoa ovde nije moguća... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Ovde nije moguće izgraditi brodski hangar STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Ovaj depo se ne može preimenovati... STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... mora se zaustaviti u nekom depou STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... mora se zaustaviti u nekom depou STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... mora se zaustaviti u nekom depou STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... mora se zaustaviti u nekom hangaru STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Vozovi se mogu izmeniti samo kada su zaustavljeni u depou STR_ERROR_TRAIN_TOO_LONG :{WHITE}Voz je predugačak STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Voz ne može da promeni smer... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... sastoji se od više jedinica STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Različite vrste železnice STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Ne može se ukloniti vozilo... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}Zadnja lokomotiva u kompoziciji uvek prati prednju STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Nepostoji putanja do lokalnog depoa STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Neuspešan pronalazak lokalnog depoa STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Pogrešna vrsta depoa # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} je predugačak posle zamene STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Automatska zamena/obnova nije primenjena STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(novčano ograničenje) # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Nemoguća kombinacija šina STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Neophodno je prvo ukloniti signalizaciju STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Nedostaje odgovarajuća železnička pruga STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Potrebno je prvo ukloniti železničku prugu STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Put je jednosmeran ili je blokiran STR_ERROR_CROSSING_DISALLOWED :{WHITE}Putni prelaz nije dozvoljen za ovu vrstu pruge STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Izgradnja signalizacije ovde nije moguća... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Izgradnja železničke pruge ovde nije moguća... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nemoguće je ukloniti železničku prugu odatle... STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Nemoguće je ukloniti signalizaciju odatle... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Signalizacije se ovde ne može promeniti... STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... ovde nema železničke pruge STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... ovde nema signalizacije STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Vrsta pruge se ovde ne može promeniti... # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Neophodno je prvo ukloniti put STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... jednosmerni putevi ne mogu imati raskrsnice STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Izgradnja puta ovde nije moguća... STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Izgradnja tramvajske pruge ovde nije moguća... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Nemoguće je ukloniti put odatle... STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Nemoguće je ukloniti tramvajsku prugu odatle... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... ovde nema puta STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... ovde nema tramvajske pruge # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Ovde je nemoguća izgradnja kanala... STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Ovde nije moguće izgraditi prevodnicu... STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Ovde je nemoguće postavljanje reke... STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... mora biti izgrađen na vodi STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... Ne može se graditi na vodi STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... ne može se izgraditi na moru STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... ne može se izgraditi na kanalu STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... ne može se izgraditi na reci STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Potrebno je prvo ukloniti kanal STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Akvadukt se ovde ne može izgraditi... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... drvo je već na tom mestu STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... teren ne odgovara vrsti drveća STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Ovde je nemoguće posaditi drvo... # Bridge related errors STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Nije moguće ovde izgraditi most... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Potrebno je prvo srušiti most STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Ne može da se završava na istom mestu gde i počinje STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Krajevi mosta nisu na istom nivou STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Most je nizak u odnosu na teren STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN :{WHITE}Most je previše visok zaovaj teren STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Početak i kraj moraju biti u istoj liniji STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... oba kraja mosta moraju biti na čvrstom tlu STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... most je previše dugačak STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Most bi završio van okvira terena # Tunnel related errors STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Nije moguće ovde izgraditi tunel... STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Lokacija neadekvatna za ulaz tunela STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Potrebno je prvo ukloniti tunel STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Drugi tunel je na putu STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunel bi završio van okvira terena STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Nije moguće iskopati drugi kraj tunela STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tunel je predugačak # Object related errors STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... ima previše objekata STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Objekat se ne može izgraditi... STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Objekat na putu STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... upravna zgrada preduzeća na putu STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Ovo zemljište se ne može kupiti... STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... već pripada preduzeću! # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Grupa se ne može napraviti... STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Grupa se ne može izbrisati... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Grupa se ne može preimenovati... STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Ne mogu se sva vozila ukloniti iz grupe... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Vozilo se ne može dodati u ovu grupu... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Deljena vozila se ne mogu dodati u grupu... # Generic vehicle errors STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Voz se tu upravo nalazi STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Drumsko vozilo na putu STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Brod se tu upravo nalazi STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Letilica se tu nalazi STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Voz se ne može prepraviti... STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Nemoguće prepravljanje drumskog vozila... STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Brod se ne može prepraviti... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Nemoguće je prepraviti letilicu... STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Nemoguće nazvati voz... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Ne može se promeniti naziv vozila... STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Ne može se promeniti naziv broda... STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Ne može se promeniti naziv letilice... STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Ne može se pokrenuti/zaustaviti voz... STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Ne može se pokrenuti/zaustaviti drumsko vozilo... STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}Ne može se pokrenuti/zaustaviti brod... STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Ne može se pokrenuti/zaustaviti letilica... STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Voz ne može da ode u depo... STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Vozilo ne može da ode u depo... STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Brod ne može da ode u depo... STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Letilica ne može da ode u hangar... STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Nemoguća kupovina šinskog vozila... STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Ne može se kupiti drumsko vozilo... STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Brod se ne može kupiti... STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Ne može se kupiti letelica... STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Nemoguća promena naziva vrste šinskog vozila... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Nemoguća promena naziva vrste drumskog vozila... STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Nemoguća promena naziva vrste broda... STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Nemoguća promena naziva vrste letilice... STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Ne može se prodati šinsko vozilo... STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Nemoguća prodaja drumskog vozila... STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Brod se ne može prodati... STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Letilica se ne može prodati... STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Šinsko vozilo nije dostupno STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Drumsko vozilo nije dostupno STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Brod nije dostupan STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Letilica nije dostupna STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Previše je vozila u igri STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Servisni interval nije moguće promeniti... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... vozilo je uništeno STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Nijedno vozilo neće biti dostupno STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Promenite konfiguraciju za NewGRF STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nijedno vozilo još uvek nije dostupno STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Pokrenite novu igru koja počinje posle {DATE_SHORT} ili koristite NewGRF koji omogućava ranija vozila # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Nemoguć je prolaz voza na signal opasnosti... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}... vozilo je uništeno STR_ERROR_TRAIN_START_NO_POWER :Voz nema struju STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Drumsko vozilo ne može da se okrene... STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Letilica je u vazduhu # Order related errors STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Nema više mesta za naredbe STR_ERROR_TOO_MANY_ORDERS :{WHITE}Previše naredbi STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Ne može se dodati nova naredba... STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Ne može da se izbriše ova naredba... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Ne može da se izmeni ova naredba... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Ne može da se pomeri ova naredba... STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Ne može se preskočiti tekuća naredba... STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Ne može da se preskoči označena naredba... STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}vozilo ne može da ide na sve stanice STR_ERROR_CAN_T_ADD_ORDER :{WHITE}vozilo ne može da ide na tu stanicu STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}vozilo koje takođe ima ovu naredbu ne može da ide na tu stanicu STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Lista naredbi se ne može deliti... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Deljenje naredbi se ne može prekinuti... STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Lista naredbi se ne može kopirati... STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... previše udaljeno od prethodne destinacije STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... letilica nema dometa # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Raspored se ne može dodeliti vozilu... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vozila mogu čekati samo na stanicama STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Ovo vozilo ne staje na tu stanicu # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... ima previše znakova STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Ovde je nemoguće postaviti znak... STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Ime znaka se ne može promeniti... STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Nemoguće je izbrisati znak... # Translatable comment for OpenTTD's desktop shortcut STR_DESKTOP_SHORTCUT_COMMENT :Simulacija bazirana na igri Transport Tycoon Deluxe # Translatable descriptions in media/baseset/*.ob* files STR_BASEGRAPHICS_DOS_DESCRIPTION :Originalni skup grafika Transport Tycoon Deluxe DOS izdanja. STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Originalni skup grafika nemačkog Transport Tycoon Deluxe DOS izdanja. STR_BASEGRAPHICS_WIN_DESCRIPTION :Originalni skup grafika Transport Tycoon Deluxe Windows izdanja. STR_BASESOUNDS_DOS_DESCRIPTION :Originalni skup zvukova Transport Tycoon Deluxe DOS izdanja. STR_BASESOUNDS_WIN_DESCRIPTION :Originalni skup zvukova Transport Tycoon Deluxe Windows izdanja. STR_BASESOUNDS_NONE_DESCRIPTION :Prazan skup zvukova. STR_BASEMUSIC_WIN_DESCRIPTION :Originalni skup muzičkih numera Transport Tycoon Deluxe Windows izdanja. STR_BASEMUSIC_NONE_DESCRIPTION :Prazan skup muzičkih numera. ##id 0x2000 # Town building names STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Visoka radionica STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Radionica STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Male blagoste STR_TOWN_BUILDING_NAME_CHURCH_1 :Crkva STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Velika radionica STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Gradska kuća STR_TOWN_BUILDING_NAME_HOTEL_1 :Hotel STR_TOWN_BUILDING_NAME_STATUE_1 :Statua STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Fontana STR_TOWN_BUILDING_NAME_PARK_1 :Park STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Poslovna zgrada STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Radnje i kancelarije STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Moderna poslovna zgrada STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Stovarište STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Poslovna zgrada STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadion STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Stare kuće STR_TOWN_BUILDING_NAME_COTTAGES_1 :Brvnare STR_TOWN_BUILDING_NAME_HOUSES_1 :Kuće STR_TOWN_BUILDING_NAME_FLATS_1 :Stambene zgrade STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Visok blok komercijalnih zgrada STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Prodavnice i poslovni prostor STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Prodavnice i poslovni prostor STR_TOWN_BUILDING_NAME_THEATER_1 :Pozorište STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadion STR_TOWN_BUILDING_NAME_OFFICES_1 :Poslovni prostor STR_TOWN_BUILDING_NAME_HOUSES_2 :Kuće STR_TOWN_BUILDING_NAME_CINEMA_1 :Bioskop STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Tržni centar STR_TOWN_BUILDING_NAME_IGLOO_1 :Iglo STR_TOWN_BUILDING_NAME_TEPEES_1 :Vigvami STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Čajnik-kuća STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Kasica-prasica ##id 0x4800 # industry names STR_INDUSTRY_NAME_COAL_MINE :{G=muški}Rudnik uglja STR_INDUSTRY_NAME_POWER_STATION :{G=ženski}Termoelektrana STR_INDUSTRY_NAME_SAWMILL :{G=ženski}Pilana STR_INDUSTRY_NAME_FOREST :{G=ženski}Šuma STR_INDUSTRY_NAME_OIL_REFINERY :{G=ženski}Rafinerija nafte STR_INDUSTRY_NAME_OIL_RIG :{G=ženski}Naftna platforma STR_INDUSTRY_NAME_FACTORY :{G=ženski}Fabrika STR_INDUSTRY_NAME_PRINTING_WORKS :{G=ženski}Štamparija STR_INDUSTRY_NAME_STEEL_MILL :{G=ženski}Čeličana STR_INDUSTRY_NAME_FARM :{G=ženski}Farma STR_INDUSTRY_NAME_COPPER_ORE_MINE :{G=muški}Rudnik bakra STR_INDUSTRY_NAME_OIL_WELLS :{G=ženski}Naftna bušotina STR_INDUSTRY_NAME_BANK :{G=ženski}Banka STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :{G=muški}Prehrambeni kombinat STR_INDUSTRY_NAME_PAPER_MILL :{G=ženski}Fabrika papira STR_INDUSTRY_NAME_GOLD_MINE :{G=muški}Rudnik zlata STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :{G=ženski}Banka STR_INDUSTRY_NAME_DIAMOND_MINE :{G=muški}Rudnik dijamanata STR_INDUSTRY_NAME_IRON_ORE_MINE :{G=muški}Rudnik gvožđa STR_INDUSTRY_NAME_FRUIT_PLANTATION :{G=ženski}Plantaža voća STR_INDUSTRY_NAME_RUBBER_PLANTATION :{G=ženski}Plantaža kaučuka STR_INDUSTRY_NAME_WATER_SUPPLY :{G=muški}Izvor vode STR_INDUSTRY_NAME_WATER_TOWER :{G=muški}Vodotoranj STR_INDUSTRY_NAME_FACTORY_2 :{G=ženski}Fabrika STR_INDUSTRY_NAME_FARM_2 :{G=ženski}Farma STR_INDUSTRY_NAME_LUMBER_MILL :{G=muški}Drvni kombinat STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :{G=ženski}Šuma šećerne vune STR_INDUSTRY_NAME_CANDY_FACTORY :{G=ženski}Fabrika slatkiša STR_INDUSTRY_NAME_BATTERY_FARM :{G=ženski}Farma baterija STR_INDUSTRY_NAME_COLA_WELLS :{G=muški}Izvor kole STR_INDUSTRY_NAME_TOY_SHOP :{G=ženski}Prodavnica igračaka STR_INDUSTRY_NAME_TOY_FACTORY :{G=ženski}Fabrika igračaka STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :{G=muški}Gejziri plastike STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :{G=ženski}Fabrika gaziranih pića STR_INDUSTRY_NAME_BUBBLE_GENERATOR :{G=muški}Generator mehurića STR_INDUSTRY_NAME_TOFFEE_QUARRY :{G=muški}Karamenolom STR_INDUSTRY_NAME_SUGAR_MINE :{G=muški}Rudnik šećera ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Neimenovan STR_SV_TRAIN_NAME :Voz {COMMA} STR_SV_ROAD_VEHICLE_NAME :Drumsko Vozilo {COMMA} STR_SV_SHIP_NAME :Brod {COMMA} STR_SV_AIRCRAFT_NAME :Letilica {COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :{STRING} Sever STR_SV_STNAME_SOUTH :{STRING} Jug STR_SV_STNAME_EAST :{STRING} Istok STR_SV_STNAME_WEST :{STRING} Zapad STR_SV_STNAME_CENTRAL :{STRING} Centar STR_SV_STNAME_TRANSFER :{STRING} Transfer STR_SV_STNAME_HALT :{STRING} Zadnja STR_SV_STNAME_VALLEY :{STRING} Udolina STR_SV_STNAME_HEIGHTS :{STRING} Visoravan STR_SV_STNAME_WOODS :{STRING} Šume STR_SV_STNAME_LAKESIDE :{STRING} Priobalje STR_SV_STNAME_EXCHANGE :{STRING} Razmena STR_SV_STNAME_AIRPORT :{STRING} Aerodrom STR_SV_STNAME_OILFIELD :{STRING} Naftna polja STR_SV_STNAME_MINES :{STRING} Rudnici STR_SV_STNAME_DOCKS :{STRING} Pristaništa STR_SV_STNAME_BUOY :{STRING} STR_SV_STNAME_WAYPOINT :{STRING} ##id 0x6020 STR_SV_STNAME_ANNEXE :{STRING} Dodatna STR_SV_STNAME_SIDINGS :{STRING} Skretnica STR_SV_STNAME_BRANCH :{STRING} Grana STR_SV_STNAME_UPPER :Viša {STRING} STR_SV_STNAME_LOWER :Niža {STRING} STR_SV_STNAME_HELIPORT :{STRING} Heliodrom STR_SV_STNAME_FOREST :{STRING} Lovište STR_SV_STNAME_FALLBACK :{STRING} Stanica #{NUM} ############ end of savegame specific region! ##id 0x8000 # Vehicle names STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (para) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (dizel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (električna) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (električna) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (električna) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (električna) STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Putnička Kola STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Poštanski Vagon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Vagon za Ugalj STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Cisterna za Naftu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Vagon za Živu Stoku STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Vagon za Robu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Vagon za Žito STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Vagon za Drvo STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Vagon za Rude gvožđa STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Vagon za Čelik STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Oklopljeni Vagon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Vagon za Hranu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Vagon za Papir STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Vagon za Rude bakra STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Cisterna za Vodu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Vagon za Voće STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Vagon za Kaučuk STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Vagon za Šećer STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Vagon za Šećernu vunu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Vagon za Karamele STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Vagon za Mehuriće STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Cisterna za Kolu STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Vagon za Slatkiše STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Vagon za Igračke STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Vagon za Baterije STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Cisterna za Gazirana pića STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Vagon za Plastiku STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (električna) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Električna) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Putnička Kola STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Poštanski Vagon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Vagon za Ugalj STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Cisterna za Naftu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Vagon za Živu Stoku STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Vagon za Robu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Vagon za Žitarice STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Vagon za Drva STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Vagon za Rude Gvožđa STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Vagon za Čelik STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :Oklopljeni Vagon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Vagon za Hranu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Vagon za Papir STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Vagon za Rude Bakra STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Cisterna za Vodu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Vagon za Voće STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Vagon za Kaučuk STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Vagon za Šećer STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Vagon za Šećernu Vatu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Vagon za Karamele STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Vagon za Balone STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Cisterna za Kolu STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Vagon za Slatkiše STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Vagon za Igračke STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Vagon za Baterije STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Vagon za Bezalkoholna Pića STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Vagon za Plastiku STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :{G=ženski}Lev1 'Leviathan' (Electrična) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :{G=ženski}Lev2 'Cyclops' (Električna) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :{G=ženski}Lev3 'Pegasus' (Električna) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :{G=ženski}Lev4 'Chimaera' (Električna) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Putnička Kola STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Poštanski Vagon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Vagon za Ugalj STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Cisterna za Naftu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Vagon za Živu Stoku STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Vagon za Robu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Vagon za Žitarice STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Vagon za Drva STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Vagon za Rude Gvožđa STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Vagon za Čelik STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Oklopljeni Vagon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Vagon za Hranu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Vagon za Papir STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Vagon za Rude Bakra STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Cisterna za Vodu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Vagon za Voće STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Vagon za Kaučuk STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Vagon za Šećer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Vagon za Šećernu Vunu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Vagon za Karamele STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Vagon za Balone STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Cisterna za Kolu STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Vagon za Slatkiš STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Vagon za Igračke STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Vagon za Baterije STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Vagon za Bezalkoholna Pića STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Vagon za Plastiku STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Autobus STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Autobus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Autobus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Autobus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Autobus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Autobus STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Balogh Kamion za ugalj STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Uhl Kamion za ugalj STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :DW Kamion za ugalj STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :MPS Kamion za poštu STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Reynard Poštanski Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Perry Poštanski Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :MightyMover Poštanski Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Powernaught Poštanski Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Wizzowow Poštanski Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Witcombe Naftna Cisterna STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Foster Naftna Cisterna STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Perry Naftna Cisterna STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Talbott Stočni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Uhl Stočni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Foster Stočni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Balogh Robni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Craighead Robni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Goss Robni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Hereford Kamion za žitarice STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Thomas Kamion za žitarice STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Goss Kamion za žitarice STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Witcombe Kamion za drvo STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Foster Kamion za drvo STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Moreland Kamion za drvo STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :MPS Kamion za rude gvožđa STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Uhl Kamion za rude gvožđa STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Chippy Kamion za rude gvožđa STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Balogh Kamion za čelik STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Uhl Kamion za čelik STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Kelling Kamion za čelik STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Balogh Oklopljeni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Uhl Oklopljeni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Foster Oklopljeni Kamion STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Foster Kamion za hranu STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Perry Kamion za hranu STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Chippy Kamion za hranu STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Uhl Kamion za papir STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Balogh Kamion za papir STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :MPS Kamion za papir STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :MPS Kamion za rude bakra STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Uhl Kamion za rude bakra STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Goss Kamion za rude bakra STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Uhl Cisterna za vodu STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Balogh Cisterna za vodu STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :MPS Cisterna za vodu STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Balogh Kamion za voće STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Uhl Kamion za voće STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kelling Kamion za voće STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Balogh Kamion za kaučuk STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Uhl Kamion za kaučuk STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :RMT Kamion za kaučuk STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Kamion za šećer STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Powernaught Kamion za šećer STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Wizzowow Kamion za šećer STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :MightyMover Kamion za kolu STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Powernaught Kamion za kolu STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Wizzowow Kamion za kolu STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :MightyMover Kamion za šećernu vunu STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Powernaught Kamion za šećernu vunu STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Kamion za šećernu vunu STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Kamion za karamele STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Kamion za karamele STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Kamion za karamele STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :MightyMover Kamion za igračke STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Powernaught Kamion za igračke STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Wizzowow Kamion za igračke STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :MightyMover Kamion za slatkiše STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Powernaught Kamion za slatkiše STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Wizzowow Kamion za slatkiše STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Kamion za baterije STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Powernaught Kamion za baterije STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Wizzowow Kamion za baterije STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :MightyMover Kamion za gazirana pića STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Powernaught Kamion za gazirana pića STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Kamion za gazirana pića STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Kamion za plastiku STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Kamion za plastiku STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Kamion za plastiku STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Kamion za balone STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Kamion za balone STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Kamion za balone STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :MPS Naftni Tanker STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :CS-Inc. Naftni Tanker STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :MPS Putnički Feribot STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :FFP Putnički Feribot STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Hoverkraft STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Chugger-Chug Putnički Feribot STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Putnički Feribot STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Yate Teretni brod STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Bakewell Teretni brod STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :MightyMover Teretni brod STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Powernaut Teretni brod STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Šatl STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Tricario Helikopter STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Guru X2 Helikopter STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut Helikopter ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{STRING}-{STRING}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} STR_FORMAT_DATE_ISO :{2:NUM}-{1:STRING}-{0:STRING} STR_FORMAT_BUOY_NAME :{TOWN} Bova STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Bova #{COMMA} STR_FORMAT_COMPANY_NUM :(Preduzeće {COMMA}) STR_FORMAT_GROUP_NAME :Grupa {COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :{TOWN} Putanja STR_FORMAT_WAYPOINT_NAME_SERIAL :{TOWN} Putanja #{COMMA} STR_FORMAT_DEPOT_NAME_TRAIN :{TOWN} Železnički depo STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :{TOWN} Železnički depo #{COMMA} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :{TOWN} Drumski depo STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :{TOWN} Drumski depo #{COMMA} STR_FORMAT_DEPOT_NAME_SHIP :{TOWN} Brodski hangar STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :{TOWN} Brodski hangar #{COMMA} STR_FORMAT_DEPOT_NAME_AIRCRAFT :{STATION} Hangar STR_UNKNOWN_STATION :nepoznata stanica STR_DEFAULT_SIGN_NAME :Znak STR_COMPANY_SOMEONE :neko STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING} STR_SAVEGAME_NAME_SPECTATOR :Posmatrač, {1:STRING} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} STR_VIEWPORT_WAYPOINT :{WAYPOINT} STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} STR_DEPOT_NAME :{DEPOT} STR_ENGINE_NAME :{ENGINE} STR_HIDDEN_ENGINE_NAME :{ENGINE} (sakriveno) STR_GROUP_NAME :{GROUP} STR_INDUSTRY_NAME :{INDUSTRY} STR_PRESIDENT_NAME :{PRESIDENT_NAME} STR_SIGN_NAME :{SIGN} STR_STATION_NAME :{STATION} STR_TOWN_NAME :{TOWN} STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} STR_JUST_DATE_LONG :{DATE_LONG} STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} # Slightly 'raw' stringcodes with colour or size STR_BLACK_COMMA :{BLACK}{COMMA} STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} STR_TINY_COMMA :{TINY_FONT}{COMMA} STR_BLUE_COMMA :{BLUE}{COMMA} STR_RED_COMMA :{RED}{COMMA} STR_WHITE_COMMA :{WHITE}{COMMA} STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} STR_TINY_GROUP :{TINY_FONT}{GROUP} STR_BLACK_INT :{BLACK}{NUM} STR_ORANGE_INT :{ORANGE}{NUM} STR_WHITE_SIGN :{WHITE}{SIGN} STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} STR_BLACK_STRING :{BLACK}{STRING} STR_BLACK_RAW_STRING :{BLACK}{STRING} STR_ORANGE_STRING :{ORANGE}{STRING} STR_LTBLUE_STRING :{LTBLUE}{STRING} STR_WHITE_STRING :{WHITE}{STRING} STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING}{WHITE} STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING}{LTBLUE} STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} STR_BLACK_1 :{BLACK}1 STR_BLACK_2 :{BLACK}2 STR_BLACK_3 :{BLACK}3 STR_BLACK_4 :{BLACK}4 STR_BLACK_5 :{BLACK}5 STR_BLACK_6 :{BLACK}6 STR_BLACK_7 :{BLACK}7 STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) openttd-1.5.3/src/lang/luxembourgish.txt0000644000000000000000000152136312627373443017067 0ustar rootroot##name Luxembourgish ##ownname Lëtzebuergesch ##isocode lb_LU ##plural 0 ##textdir ltr ##digitsep . ##digitsepcur . ##decimalsep , ##winlangid 0x046e ##grflangid 0x23 # $Id: luxembourgish.txt 27353 2015-07-31 17:46:09Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(ondefinéierten string) STR_JUST_NOTHING :Näischt # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :Passagéier STR_CARGO_PLURAL_COAL :Kuelen STR_CARGO_PLURAL_MAIL :Post STR_CARGO_PLURAL_OIL :Ueleg STR_CARGO_PLURAL_LIVESTOCK :Véi STR_CARGO_PLURAL_GOODS :Wueren STR_CARGO_PLURAL_GRAIN :Kar STR_CARGO_PLURAL_WOOD :Holz STR_CARGO_PLURAL_IRON_ORE :Eisenäerz STR_CARGO_PLURAL_STEEL :Stol STR_CARGO_PLURAL_VALUABLES :Wäertsaachen STR_CARGO_PLURAL_COPPER_ORE :Kofferäerz STR_CARGO_PLURAL_MAIZE :Mais STR_CARGO_PLURAL_FRUIT :Friichten STR_CARGO_PLURAL_DIAMONDS :Diamanten STR_CARGO_PLURAL_FOOD :Iesswueren STR_CARGO_PLURAL_PAPER :Pabeier STR_CARGO_PLURAL_GOLD :Gold STR_CARGO_PLURAL_WATER :Waasser STR_CARGO_PLURAL_WHEAT :Weess STR_CARGO_PLURAL_RUBBER :Kautschuk STR_CARGO_PLURAL_SUGAR :Zocker STR_CARGO_PLURAL_TOYS :Spillsaachen STR_CARGO_PLURAL_CANDY :Séissegkeeten STR_CARGO_PLURAL_COLA :Cola STR_CARGO_PLURAL_COTTON_CANDY :Zockerwatt STR_CARGO_PLURAL_BUBBLES :Blosen STR_CARGO_PLURAL_TOFFEE :Karamell STR_CARGO_PLURAL_BATTERIES :Batterien STR_CARGO_PLURAL_PLASTIC :Plastik STR_CARGO_PLURAL_FIZZY_DRINKS :Spruddel-Gedrénks # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :Passagéier STR_CARGO_SINGULAR_COAL :Kuelen STR_CARGO_SINGULAR_MAIL :Post STR_CARGO_SINGULAR_OIL :Ueleg STR_CARGO_SINGULAR_LIVESTOCK :Véi STR_CARGO_SINGULAR_GOODS :Wueren STR_CARGO_SINGULAR_GRAIN :Kar STR_CARGO_SINGULAR_WOOD :Holz STR_CARGO_SINGULAR_IRON_ORE :Eisenäerz STR_CARGO_SINGULAR_STEEL :Stol STR_CARGO_SINGULAR_VALUABLES :Wäertsaachen STR_CARGO_SINGULAR_COPPER_ORE :Kofferäerz STR_CARGO_SINGULAR_MAIZE :Mais STR_CARGO_SINGULAR_FRUIT :Friichten STR_CARGO_SINGULAR_DIAMOND :Diamanten STR_CARGO_SINGULAR_FOOD :Iessen STR_CARGO_SINGULAR_PAPER :Pabeier STR_CARGO_SINGULAR_GOLD :Gold STR_CARGO_SINGULAR_WATER :Waasser STR_CARGO_SINGULAR_WHEAT :Weess STR_CARGO_SINGULAR_RUBBER :Kautschuck STR_CARGO_SINGULAR_SUGAR :Zocker STR_CARGO_SINGULAR_TOY :Spillsaach STR_CARGO_SINGULAR_CANDY :Séissegkeet STR_CARGO_SINGULAR_COLA :Cola STR_CARGO_SINGULAR_COTTON_CANDY :Zockerwatt STR_CARGO_SINGULAR_BUBBLE :Blos STR_CARGO_SINGULAR_TOFFEE :Karamell STR_CARGO_SINGULAR_BATTERY :Batterie STR_CARGO_SINGULAR_PLASTIC :Plastik STR_CARGO_SINGULAR_FIZZY_DRINK :Spruddel-Gedrénks # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA}{NBSP}Passagéier STR_QUANTITY_COAL :{WEIGHT_LONG} Kuel STR_QUANTITY_MAIL :{COMMA}{NBSP}Posts{P ak äck} STR_QUANTITY_OIL :{VOLUME_LONG} Ueleg STR_QUANTITY_LIVESTOCK :{COMMA}{NBSP}Eenheet{P "" e} Véi STR_QUANTITY_GOODS :{COMMA}{NBSP}Wuerekëscht{P "" en} STR_QUANTITY_GRAIN :{WEIGHT_LONG} Kar STR_QUANTITY_WOOD :{WEIGHT_LONG} Holz STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} Eisenäerz STR_QUANTITY_STEEL :{WEIGHT_LONG} Stol STR_QUANTITY_VALUABLES :{COMMA}{NBSP}S{P ak äck} mat Wäertsaachen STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} Kofferäerz STR_QUANTITY_MAIZE :{WEIGHT_LONG} Mais STR_QUANTITY_FRUIT :{WEIGHT_LONG} Friichten STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}S{P ak äck} mat Diamanten STR_QUANTITY_FOOD :{WEIGHT_LONG} Iesswueren STR_QUANTITY_PAPER :{WEIGHT_LONG} Pabeier STR_QUANTITY_GOLD :{COMMA}{NBSP}S{P ak äck} mat Gold STR_QUANTITY_WATER :{VOLUME_LONG} Waasser STR_QUANTITY_WHEAT :{WEIGHT_LONG} Weess STR_QUANTITY_RUBBER :{VOLUME_LONG} Kautschuck STR_QUANTITY_SUGAR :{WEIGHT_LONG} Zocker STR_QUANTITY_TOYS :{COMMA}{NBSP}Spillsaach{P "" en} STR_QUANTITY_SWEETS :{COMMA}{NBSP}S{P ak äck} mat Séissegkeeten STR_QUANTITY_COLA :{VOLUME_LONG} Cola STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} Zockerwatt STR_QUANTITY_BUBBLES :{COMMA} Blos{P "" en} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} Karamell STR_QUANTITY_BATTERIES :{COMMA} Batterie{P "" n} STR_QUANTITY_PLASTIC :{VOLUME_LONG} Plastik STR_QUANTITY_FIZZY_DRINKS :{COMMA} Spruddelgedrénks STR_QUANTITY_N_A :N/A # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}PS STR_ABBREV_COAL :{TINY_FONT}KU STR_ABBREV_MAIL :{TINY_FONT}PO STR_ABBREV_OIL :{TINY_FONT}UL STR_ABBREV_LIVESTOCK :{TINY_FONT}VE STR_ABBREV_GOODS :{TINY_FONT}WU STR_ABBREV_GRAIN :{TINY_FONT}KA STR_ABBREV_WOOD :{TINY_FONT}HO STR_ABBREV_IRON_ORE :{TINY_FONT}EA STR_ABBREV_STEEL :{TINY_FONT}ST STR_ABBREV_VALUABLES :{TINY_FONT}WS STR_ABBREV_COPPER_ORE :{TINY_FONT}KE STR_ABBREV_MAIZE :{TINY_FONT}MA STR_ABBREV_FRUIT :{TINY_FONT}FR STR_ABBREV_DIAMONDS :{TINY_FONT}DM STR_ABBREV_FOOD :{TINY_FONT}IE STR_ABBREV_PAPER :{TINY_FONT}PB STR_ABBREV_GOLD :{TINY_FONT}GD STR_ABBREV_WATER :{TINY_FONT}WA STR_ABBREV_WHEAT :{TINY_FONT}WE STR_ABBREV_RUBBER :{TINY_FONT}KT STR_ABBREV_SUGAR :{TINY_FONT}ZO STR_ABBREV_TOYS :{TINY_FONT}SP STR_ABBREV_SWEETS :{TINY_FONT}SE STR_ABBREV_COLA :{TINY_FONT}CO STR_ABBREV_CANDYFLOSS :{TINY_FONT}ZW STR_ABBREV_BUBBLES :{TINY_FONT}BL STR_ABBREV_TOFFEE :{TINY_FONT}KA STR_ABBREV_BATTERIES :{TINY_FONT}BA STR_ABBREV_PLASTIC :{TINY_FONT}PL STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}KG STR_ABBREV_NONE :{TINY_FONT}KG STR_ABBREV_ALL :{TINY_FONT}ALL # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA}{NBSP}Passagéier STR_BAGS :{COMMA}{NBSP}S{P ak äck} STR_TONS :{COMMA}{NBSP}Tonn{P "" en} STR_LITERS :{COMMA}{NBSP}Liter STR_ITEMS :{COMMA}{NBSP}Eenheet{P "" en} STR_CRATES :{COMMA}{NBSP}Këscht{P "" en} # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Donkelblo STR_COLOUR_PALE_GREEN :Bleechgréng STR_COLOUR_PINK :Pink STR_COLOUR_YELLOW :Giel STR_COLOUR_RED :Rout STR_COLOUR_LIGHT_BLUE :Hellblo STR_COLOUR_GREEN :Gréng STR_COLOUR_DARK_GREEN :Donkelgréng STR_COLOUR_BLUE :Blo STR_COLOUR_CREAM :Beige STR_COLOUR_MAUVE :Mof STR_COLOUR_PURPLE :Purpur STR_COLOUR_ORANGE :Orange STR_COLOUR_BROWN :Brong STR_COLOUR_GREY :Gro STR_COLOUR_WHITE :Wäiss # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mph STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}bhp STR_UNITS_POWER_METRIC :{COMMA}{NBSP}ps STR_UNITS_POWER_SI :{COMMA}{NBSP}kW STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}{NBSP}kg STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA}{NBSP}Tonn{P "" en} STR_UNITS_WEIGHT_LONG_METRIC :{COMMA}{NBSP}Tonn{P "" en} STR_UNITS_WEIGHT_LONG_SI :{COMMA}{NBSP}kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}{NBSP}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}{NBSP}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}{NBSP}m³ STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA}{NBSP}Galloun{P "" en} STR_UNITS_VOLUME_LONG_METRIC :{COMMA}{NBSP}Liter{P "" ""} STR_UNITS_VOLUME_LONG_SI :{COMMA}{NBSP}m³ STR_UNITS_FORCE_IMPERIAL :{COMMA}{NBSP}lbf STR_UNITS_FORCE_METRIC :{COMMA}{NBSP}kgf STR_UNITS_FORCE_SI :{COMMA}{NBSP}kN STR_UNITS_HEIGHT_IMPERIAL :{COMMA}{NBSP}ft STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Filter String: STR_LIST_FILTER_OSKTITLE :{BLACK}Filter String STR_LIST_FILTER_TOOLTIP :{BLACK}Filter d'Lëscht op e Wuert STR_TOOLTIP_GROUP_ORDER :{BLACK}Wiel Gruppéierreihefollëg STR_TOOLTIP_SORT_ORDER :{BLACK}Richtung fir ze sortéieren (ofsteigend/opsteigend) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Argument fir ze sortéieren STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Filterkritère wielen STR_BUTTON_SORT_BY :{BLACK}Sortéier no STR_BUTTON_LOCATION :{BLACK}Plaz STR_BUTTON_RENAME :{BLACK}Ëmbenennen STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Fënster zoumaachen STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Fënstertitel - hei zéien fir d'Fënster ze bewegen STR_TOOLTIP_SHADE :{BLACK}Fenster verklengeren - Weis nëmmen Titelbar STR_TOOLTIP_DEBUG :{BLACK}Weis NewGRF Debug Informatioun STR_TOOLTIP_DEFSIZE :{BLACK}Änner d'Fënster op d'Standardgréisst. Ctrl+Klick fir déi aktuell Gréisst als Standard ze späichern STR_TOOLTIP_STICKY :{BLACK}Markéier dës Fënster fir net zougemeet ze ginn vun dem "All Fënsteren zoumaachen" Knäppchen. Ctrl+Klick späichert déi Actioun als Standard STR_TOOLTIP_RESIZE :{BLACK}Klicken an zéihen fir d'Fënstergréisst ze änneren STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Wiesselt grouss/kleng Fënstergréisst STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Scrollbar - scrollt d'Lëscht erop/erof STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Scrollbar - scrollt d'Lëscht no lénks/riets STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Objeten op engem Stëck Land zerstéieren. Ctrl wielt d'Land diagonal. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen # Show engines button STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Verstoppten uweisen STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Verstoppten uweisen STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP :{BLACK}Verstoppten uweisen STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT :{BLACK}Verstoppten uweisen STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP :{BLACK}Mat dësem Knäppchen ginn verstoppten Zich och ugewisen STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE_TOOLTIP :{BLACK}Mat dësem Knäppchen ginn verstoppte Gefierer och ugewisen STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP_TOOLTIP :{BLACK}Mat dësem Knäppchen ginn verstoppte Schëffer och ugewisen STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Mat dësem Knäppchen ginn verstoppte Fliger och ugewisen # Query window STR_BUTTON_DEFAULT :{BLACK}Standard STR_BUTTON_CANCEL :{BLACK}Ofbriechen STR_BUTTON_OK :{BLACK}OK # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :§1234567890'^\qwertzuiopè¨asdfghjkléà yxcvbnm,.- . STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTZUIOP{{}}ASDFGHJKL:" YXCVBNM<>? . # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}Längt: {NUM} STR_MEASURE_AREA :{BLACK}Areal: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Längt: {NUM}{}Héichtenënnerscheed: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Areal: {NUM} x {NUM}{}Héichtenënnerscheed: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}Numm STR_SORT_BY_CAPTION_DATE :{BLACK}Datum # These are used in dropdowns STR_SORT_BY_NAME :Numm STR_SORT_BY_PRODUCTION :Produktioun STR_SORT_BY_TYPE :Typ STR_SORT_BY_TRANSPORTED :Transportéiert STR_SORT_BY_NUMBER :Nummer STR_SORT_BY_PROFIT_LAST_YEAR :Profit am leschten Joer STR_SORT_BY_PROFIT_THIS_YEAR :Profit dëst Joer STR_SORT_BY_AGE :Alter STR_SORT_BY_RELIABILITY :Zouverlässegkeet STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Total Kapazitéit pro Luedungstyp STR_SORT_BY_MAX_SPEED :Maximal Geschwindegkeet STR_SORT_BY_MODEL :Model STR_SORT_BY_VALUE :Wäert STR_SORT_BY_LENGTH :Längt STR_SORT_BY_LIFE_TIME :Reschtlaafzäit STR_SORT_BY_TIMETABLE_DELAY :Zäitplangverspéidung STR_SORT_BY_FACILITY :Statiounstyp STR_SORT_BY_WAITING_TOTAL :Gesamt waardend Gidder STR_SORT_BY_WAITING_AVAILABLE :Verfügbar waardend Gidder STR_SORT_BY_RATING_MAX :Héchste Luedungsbewäertung STR_SORT_BY_RATING_MIN :Niddregst Luedungsbewäertung STR_SORT_BY_ENGINE_ID :ID (klassësch Sortéierung) STR_SORT_BY_COST :Käschten STR_SORT_BY_POWER :Kraaft STR_SORT_BY_TRACTIVE_EFFORT :Zéikraaft STR_SORT_BY_INTRO_DATE :Aféirungsdatum STR_SORT_BY_RUNNING_COST :Betribskäschten STR_SORT_BY_POWER_VS_RUNNING_COST :Kraaft/Betribskäschten STR_SORT_BY_CARGO_CAPACITY :Luedungskapazitéit STR_SORT_BY_RANGE :Längt STR_SORT_BY_POPULATION :Bevölkerung STR_SORT_BY_RATING :Rating # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Spill pausen STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Spill schnell lafe loossen STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Optiounen STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Spill späicheren, Spill ophalen, Eraus STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Weis d'Kaart, extra Usiicht oder d'Lëscht vun den Zeeschen STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Weis d'Stiedverzeeschnëss STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Subventiounen uweisen STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Weis d'Lëscht vun de Firmestatiounen STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Informatiounen zu de Firmefinanzen STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Generell Firmeninformatioun STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Weis d'Storybuch STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Weis d'Zillëscht STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Weis Grafiken STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Weis d'Firmen-Ranglëscht STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Finanzéiert de Bau vun enger neier Industrie oder lëscht all d'Industrien op STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Lëscht vun de Firmenzich. Ctrl+Klick wiesselt tëscht Grupp/Zuch Lëscht STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Lëscht vun de Stroossegefierer vun der Firma. Ctrl+Klick wiesselt tëscht Gruppe/Stroossegefiererlescht STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Lëscht vun de Firmeschëffer. Ctrl+Klick wiesselt tëscht Gruppen/Schëfflëscht. STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Lëscht vun de Firmefligeren. Ctrl+Klick wiesselt tëscht Gruppen/Fligerlëscht. STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Vergréisser d'Sicht STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Verklenger d'Sicht STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Schinne bauen STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Stroosse bauen STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Schëffhafe bauen STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Fluchhafe bauen STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Landschafts-Toolbar opman fir Land ze erhéijen/senken, Beem planzen, etc. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Sound/Musik Fënster STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Weis déi lescht Meldung/Neiegkeet, oder d'Astellungen STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Informatiounen zum Land, Konsole, Script debug, Screenshots, iwwer OpenTTD STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Wiessel Toolbars # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Szenario späicheren, Szenario lueden, Eraus aus dem Szenarioeditor, Eraus STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Szenarien Editor STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Änner de Startdatum 1 Joer nohannen STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Änner de Startdatum 1 Joer no vir STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Klick fir d'Startjoer festzeleeën STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Weis d'Kaart, Stiedverzeeschnëss STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landschaftserstellung STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Stiederstellung STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industrieerstellung STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Stroossebau STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Beem planzen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Schëld opstellen STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Objet plazéiren. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Szenario späicheren STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Szenario lueden STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Héichtekaart späicheren STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Lued Héichtekaart STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Eraus aus dem Editor STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Eraus ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :Spilloptiounen STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Astellungen STR_SETTINGS_MENU_SCRIPT_SETTINGS :KI / Spill-Script Astellungen STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF Astellungen STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparenz Optiounen STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Stiednimm uweisen STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Statiounsnimm uweisen STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Weepunktnimm uweisen STR_SETTINGS_MENU_SIGNS_DISPLAYED :Schëlder uweisen STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Géignerschëlder an Nimm uweisen STR_SETTINGS_MENU_FULL_ANIMATION :Ganz Animatiounen STR_SETTINGS_MENU_FULL_DETAIL :Ganz Detailer STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Transparent Gebaier STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Transparent Schëlder ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Spill späicheren STR_FILE_MENU_LOAD_GAME :Spill lueden STR_FILE_MENU_QUIT_GAME :Spill ophalen STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Eraus ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :Weltkaart STR_MAP_MENU_EXTRA_VIEW_PORT :Extra Usiicht STR_MAP_MENU_LINGRAPH_LEGEND :Cargo Flow Legend STR_MAP_MENU_SIGN_LIST :Schëlderlëscht ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Stiedverzeeschnëss STR_TOWN_MENU_FOUND_TOWN :Stad grënnen ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :Subventiounen ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Grafik: Operative Gewënn STR_GRAPH_MENU_INCOME_GRAPH :Grafik: Akommes STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Grafik: Geliwwert Luedungen STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Grafik: Performance STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Grafik: Betribswäert STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Luedungs Bezuelraten ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Betribsranglëscht STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detailléiert Leeschtungsbewäertung STR_GRAPH_MENU_HIGHSCORE :Beschtelëscht ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Industrielëscht STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Industrieketten STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Finanzéiert eng nei Industrie ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Schinnebau STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Elektrësche Schinnebau STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Monorailbau STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Magnéitbunnbau ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Stroossebau STR_ROAD_MENU_TRAM_CONSTRUCTION :Trambau ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Waasserstroosse bauen ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Fluchhafebau ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :Landschaftsbau STR_LANDSCAPING_MENU_PLANT_TREES :Beem planzen STR_LANDSCAPING_MENU_PLACE_SIGN :Schëld opstellen ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :Sound/Musik ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Läscht Meldung/Neiegkeet STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Meldungshistorie ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Landinformatiounen STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :Konsole un/aus STR_ABOUT_MENU_AI_DEBUG :KI / Spill-Script Debug STR_ABOUT_MENU_SCREENSHOT :Screenshot (Ctrl+S) STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Voll eragezoomte Screenshot STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Standard Zoom Screenshot STR_ABOUT_MENU_GIANT_SCREENSHOT :Screenshot vun der ganzer Kaart STR_ABOUT_MENU_ABOUT_OPENTTD :Iwwert 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite Alignéirer STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Zeechen-Boxen un/aus STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Knaschteg blocks fierwen un/aus ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :1ten STR_ORDINAL_NUMBER_2ND :2ten STR_ORDINAL_NUMBER_3RD :3ten STR_ORDINAL_NUMBER_4TH :4ten STR_ORDINAL_NUMBER_5TH :5ten STR_ORDINAL_NUMBER_6TH :6ten STR_ORDINAL_NUMBER_7TH :7ten STR_ORDINAL_NUMBER_8TH :8ten STR_ORDINAL_NUMBER_9TH :9ten STR_ORDINAL_NUMBER_10TH :10ten STR_ORDINAL_NUMBER_11TH :11ten STR_ORDINAL_NUMBER_12TH :12ten STR_ORDINAL_NUMBER_13TH :13ten STR_ORDINAL_NUMBER_14TH :14ten STR_ORDINAL_NUMBER_15TH :15ten ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :1ten STR_DAY_NUMBER_2ND :2ten STR_DAY_NUMBER_3RD :3ten STR_DAY_NUMBER_4TH :4ten STR_DAY_NUMBER_5TH :5ten STR_DAY_NUMBER_6TH :6ten STR_DAY_NUMBER_7TH :7ten STR_DAY_NUMBER_8TH :8ten STR_DAY_NUMBER_9TH :9ten STR_DAY_NUMBER_10TH :10ten STR_DAY_NUMBER_11TH :11ten STR_DAY_NUMBER_12TH :12ten STR_DAY_NUMBER_13TH :13ten STR_DAY_NUMBER_14TH :14ten STR_DAY_NUMBER_15TH :15ten STR_DAY_NUMBER_16TH :16ten STR_DAY_NUMBER_17TH :17ten STR_DAY_NUMBER_18TH :18ten STR_DAY_NUMBER_19TH :19ten STR_DAY_NUMBER_20TH :20ten STR_DAY_NUMBER_21ST :21ten STR_DAY_NUMBER_22ND :22ten STR_DAY_NUMBER_23RD :23ten STR_DAY_NUMBER_24TH :24ten STR_DAY_NUMBER_25TH :25ten STR_DAY_NUMBER_26TH :26ten STR_DAY_NUMBER_27TH :27ten STR_DAY_NUMBER_28TH :28ten STR_DAY_NUMBER_29TH :29ten STR_DAY_NUMBER_30TH :30ten STR_DAY_NUMBER_31ST :31ten ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :Jan STR_MONTH_ABBREV_FEB :Feb STR_MONTH_ABBREV_MAR :Mär STR_MONTH_ABBREV_APR :Abr STR_MONTH_ABBREV_MAY :Mee STR_MONTH_ABBREV_JUN :Jun STR_MONTH_ABBREV_JUL :Jul STR_MONTH_ABBREV_AUG :Aug STR_MONTH_ABBREV_SEP :Sep STR_MONTH_ABBREV_OCT :Oct STR_MONTH_ABBREV_NOV :Nov STR_MONTH_ABBREV_DEC :Dez STR_MONTH_JAN :Januar STR_MONTH_FEB :Februar STR_MONTH_MAR :Mäerz STR_MONTH_APR :Abrëll STR_MONTH_MAY :Mee STR_MONTH_JUN :Juni STR_MONTH_JUL :Juli STR_MONTH_AUG :August STR_MONTH_SEP :September STR_MONTH_OCT :Oktober STR_MONTH_NOV :November STR_MONTH_DEC :Dezember ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}Legend STR_GRAPH_KEY_TOOLTIP :{BLACK}Weis d'Legend vun der Grafik STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Grafik: Betribsgewënn STR_GRAPH_INCOME_CAPTION :{WHITE}Grafik: Akommes STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Eenheete vu Luedung geliwwert STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Firmen Performancebewäertung (max Bewäertung=1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Firmewäert STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Luedungs Bezuelraten STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Deeg am Emlaf STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Bezuelung fir Liwwerung vun 10 Eenheeten (oder 10.000 liter) Luedungen op Distanz vun 20 Felder STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}All wielen STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}All ofwielen STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}All Wueren op der Wuerenwäertgrafik weisen STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Keng Wuer op der Wuerenwäertgrafik weisen STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Schalt d'Grafik fir de Luedungstyp un/aus STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Weis detailléiert performance Astellungen # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}Legend vun de Firmegrafiken STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Klick hei fir d'Firma an der Grafik an/aus zeschalten # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Firmeliga Tabell STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Techniker STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Verkéiersmanager STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Transportkoordinator STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Stroossenopsiicht STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Direkter STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Firmechef STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Virsëtzenden STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :President STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Tycoon # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}Detailléiert Leeschtungsbewäertung STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detail STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}Detailer fir des Firma uweisen ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Gefierer: STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Statiounen: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. Profit: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. Akommes: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Max. Akommes: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Geliwwert: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Luedung: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Suen: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Kredit: STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Total: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Unzuel Gefierer déi lescht Joer Profit gemeet hunn; dëst betrëfft Stroossegefierer, Zich, Schëffer a Fligeren. STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Unzuel un kierzlech beliwwerte Statiounsdeeler. All Deel vun enger Statioun (z.B. Gare, Busarret, Fluchhafen) gëtt gezielt,och wann déi als eng Statioun verbonne sinn. STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}Profit vum Gefier mam mannsten Akommes (vun alle Gefierer déi méi wéi 2 Joer al sinn) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Betrag u Geld den am Mount mam mansten Profit gemeet gouf an de leschten 12 Quartaler STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Betrag u Geld den am Mount mam héchsten Profit gemeet gouf an de leschten 12 Quartaler STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Unzuel un Type Wueren déi déi 4 lescht Quartaler geliwwert goufen STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Unzuel un Type Wueren déi lescht Quartal geliwwert goufen STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Betrag u Suen den des Firma op der Bank huet STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}Betrag u Geld den des Firma geléint huet STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Total Punkte vu méigleche Punkten # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Jazz Jukebox STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}All STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Ale Stil STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}Neie Stil STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Ezy Street STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Benotzerdéf. 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Benotzerdéf. 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Musikvolume STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Volume vun den Effekter STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}MIN STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}MAX STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Nummer STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Titel STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Shuffle STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Programm STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Sprang op d'Stéck firdrun vun der Selektioun STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Sprang op dat nächst Stéck vun der Selektioun STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Stop d'Musik STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Start d'Musik STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Zéi de Regler fir de Volume vun der Musik an den Effekter anzestellen STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Wielt den 'all Lidder' Programm STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Wielt den 'ale Stil' Musiksprogramm STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Wielt den 'neie Stil' Musiksprogramm STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Wielt den 'Ezy Street style music' Programm STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Wielt den 'Benotzerdéf. 1' Programm STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Wielt den 'Benotzerdéf. 2' Programm STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Schalt den "shuffle" un/aus STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Weis d'Fënster fir Musik ze wielen STR_ERROR_NO_SONGS :{WHITE}E Music Set ouni Lidder gouf gewielt. Et wäerten keng Lidder gespillt ginn # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Musiksprogramm Auswiel STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Lidder Index STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Programm - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Läschen STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}De gewielte Program reseten (nëmmen Benotzerdéf.1 oder Benotzerdéf.2) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Klick op d'Lidd fir et zum aktuellen Program dobäi zesetzen (nëmme Benotzerdéf.1 oder Benotzerdéf.2) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Klick op d'Lidd fir et vum aktuellen Programm ze läschen (Benotzerdefinéiert 1 an 2 nëmmen) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Top Firmen déi {NUM} erreecht hunn STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Firmeligatabell {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Kafmann STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Entrepreneur STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industriellen STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Kapitalist STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnat STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Mogul STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Tycoon vum Jorhonnert STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} erreecht de Status '{STRING}'! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} vun {COMPANY} erreecht de Status '{STRING}'! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}Kaart - {STRING} STR_SMALLMAP_TYPE_CONTOURS :Konturen STR_SMALLMAP_TYPE_VEHICLES :Gefierer STR_SMALLMAP_TYPE_INDUSTRIES :Industrien STR_SMALLMAP_TYPE_ROUTEMAP :Cargo Flow STR_SMALLMAP_TYPE_ROUTES :Routen STR_SMALLMAP_TYPE_VEGETATION :Vegetatioun STR_SMALLMAP_TYPE_OWNERS :Besëtzer STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Weis d'Landkonturen op der Kaart STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Weis d'Gefierer op der Kaart STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Weis d'Industrien op der Kaart STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Weis de Cargo Flow op der Kaart STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Weis d'Transportrouten op der Kaart STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Weis d'Vegetatioun op der Kaart STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Weis d'Landbesëtzer op der Kaart STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Klick op en Industrietyp fir en unzeweisen. Ctrl+Klick weist just déi ugewielte Wuer. Ctrl+Klick nach emol fir all Wueren unzeweisen STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Klick op eng Firma fir de Besëtz unzeweisen. Ctrl+Klick weist just déi ugewielten aus. Ctrl+Klick nach emol fir all Firmen ze weisen STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Klick op eng Wuer fir tëscht den Eegenschaften ze wiesselen. Ctrl+Klick wielt Alles of ausser déi gewielte Wuer. Ctrl+Klick nach emol fir erëm Alles unzeweisen STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Stroossen STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Schinnen STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Statiounen/Fluchhafen/Hafen STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Gebaier/Industrien STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Gefierer STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Zich STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Stroossegefierer STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Schëffer STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Fligeren STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Transport Routen STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Bësch STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Gare STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Camionsluedeplaz STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Busarrêt STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Fluchhafen/Helikopterlandeplaz STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Hafen STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Knubbelegt Land STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Grasland STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Onerschlossend Land STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Felder STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Beem STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Fielsen STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Waasser STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}Kee Besëtzer STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Stied STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Industrien STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Wüst STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Schnéi STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Schalt d'Stiednimm op der Kaart un/aus STR_SMALLMAP_CENTER :{BLACK}Zentréiert d'kleng Kaart op déi aktuell Positioun STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}All ausschalten STR_SMALLMAP_ENABLE_ALL :{BLACK}All uschalten STR_SMALLMAP_SHOW_HEIGHT :{BLACK}D'Héicht uweisen STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Keng Industrien op der Kaart uweisen STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}All Industrien op der Kaart uweisen STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Wiessel d'Usiicht vun der Héichtenkaart STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Weis kee Besëtz vun der Firma op der Kaart un STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Weis de ganze Besëtz vun der Firma op der Kaart un STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Weis keng Wueren op der Kaart STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Weis all Wueren op der Kaart # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Lescht Meldung oder News STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUSEIERT * * STR_STATUSBAR_AUTOSAVE :{RED}AUTOSPÄICHEREN STR_STATUSBAR_SAVING_GAME :{RED}* * SPÄICHERT D'SPILL * * # News message history STR_MESSAGE_HISTORY :{WHITE}Meldungshistorie STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}Eng Lëscht vun de leschten Meldungen STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING} STR_NEWS_MESSAGE_CAPTION :{WHITE}Meldung STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Bierger feieren . . .{}Éischten Zuch kënnt zu {STATION} un! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Bierger feieren . . .{}Éischte Bus kënnt zu {STATION} un! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Bierger feieren . . .{}Eischte Camion kënnt zu {STATION} un! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Bierger feieren . . .{}Eischten Tram kënnt zu {STATION} un! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Bierger feieren . . .{}Eischte Wueren-Tram kënnt zu {STATION} un! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Bierger feieren . . .{}Éischt Schëff kënnt zu {STATION} un! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Bierger feieren . . .{}Éischte Fliger kënnt zu {STATION} un! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Zuchakzident!{}{COMMA} Leit stiewen an der Explosioun nom Akzident STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Stroossenakzident!{}Fuerer stierft an der Explosioun no Akzident mat Zuch STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Stroossegefierakzident!{}{COMMA} Leit stiewen an der Explosioun no Akzident mam Zuch STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Fligerakzident!{}{COMMA} Leit stiewen an der Explosioun bei {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Fligerakzident!{}Fliger hat kee Bensin méi, {COMMA} Leit stiewen an Explosioun! STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Zeppelinkatastroph zu {STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Stroossegefier bei 'UFO'-Zesummestouss zerstéiert! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Uelegraffinerie bei {TOWN} explodéiert! STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Fabrik ass zu {TOWN} ënner verdächtegen Ëmmstänn zerstéiert ginn! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'UFO' bei {TOWN} geland! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Kuelestollenzesummebroch hannerléisst eng Spuer vu Verwüstung bei {TOWN}! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Flut!{}Opmanst {COMMA} Leit vermësst, wahrscheinlech doud no grousser Flut! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Transportfirma huet Problemer! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} gëtt verkaf oder Bankrott erklärt, wann sëch d'Performance net verbessert! STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Transportfirme-Fusioun! STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} ass un {STRING} fir {CURRENCY_LONG} verkaf ginn! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrott! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} ass zougemaach ginn, an all Reschtposte si verkaf! STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}Nei Transportfirma gegrënnt! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} baut bei {TOWN}! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{STRING} ass vun {STRING} iwwerholl ginn! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Manager) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{STRING} huet Kontruktioun vun der Stad {TOWN} gesponsort! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}{STRING} gëtt bei {TOWN} gebaut! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}{STRING} gëtt bei {TOWN} geplanzt! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING} gëtt glaich zougemaach! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Liwwerungsproblemer féieren dozou dass {STRING} gläich zougemach gëtt! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Mangel u Beem féiert dozou dass {STRING} gläich zougemaach gëtt! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}Europäesch Währungsunioun!{}{}Den Euro ass als nei Währung am Land agefouert ginn! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}Wirtschaftsréckgang!{}{}Finanzexperten rechnen mat schlëmmsten Abrëch! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Wirtschaftsflaut eriwwer!{}{}Verbesserung am Handel bréngt Hoffnung fir Industrien an d'Economie gëtt gestäerkt! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} erhéicht d'Produktioun! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}Nei Kuelenvirkommes bei {INDUSTRY} fonnt!{}Verdueblung vun der Produktioun erwaart! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}Nei Uelegreserven bei {INDUSTRY} font!{}Verdueblung vun der Produktioun erwaart! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}{INDUSTRY} huet verbessert Ofbaumethoden erfonnt!{}Verdueblung vun der Produktioun erwaard! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} Produktioun vun {INDUSTRY} geet ëm {COMMA}% erop! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} Produktioun geet ëm 50% erof STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Insektebefall mat héijem Schued zu {INDUSTRY}!{}Produktioun geet ëm 50% erof STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} Produktioun vun {INDUSTRY} geet ëm {COMMA}% erof! STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} waard am Schapp STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} waard am Schapp STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} waard am Schapp STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} waard am Hangar # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} huet ze mann Opträg am Plang STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} huet en eidelen Optrag STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} huet duebel Opträg STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} huet eng falsch Statioun an den Opträg STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY :{WHITE}{VEHICLE} huet an séngen Opträg en Fluchhafen dem séng Landebunn ze kuerz ass STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} gëtt al STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} gëtt ganz al STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} ass ganz al, an sollt schnellstens ersaat ginn STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} kann de Wee fir weider ze fueren net fannen STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} ass verluer STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}Dëm {VEHICLE} säin Profit vum leschten Joer war {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} kann net op d'nächst Destinatioun kommen, se ass ze wäit ewech STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} huet gestoppt well eng Optragennerung net geklappt huet STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Fehler beim Autoerneieren vum {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Neie {STRING} verfügbar! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Neie/Neit {STRING} verfügbar! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} akzeptéiert {STRING} net méi STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} akzeptéiert {STRING} oder {STRING} net méi STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} akzeptéiert elo {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} akzeptéiert elo {STRING} an {STRING} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Subventioun ofgelaaf:{}{}{STRING} vun {STRING} op {STRING} gëtt net méi subventionéiert STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subventioun entzunn:{}{}{STRING} Service vun {STRING} op {STRING} gëtt net méi subventionéiert STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Subventioun offréiert:{}{}Eischten {STRING} Service vun {STRING} op {STRING} gëtt mat énger Subventioun vun 1 Joer belount.! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Subventioun geet un {STRING}!{}{}{STRING} Service vun {STRING} op {STRING} gëtt nächst Joer mat 50% Bonus bezuelt! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Subventioun geet un {STRING}!{}{}{STRING} Service vun {STRING} op {STRING} gëtt nächst Joer duebel bezuelt! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Subventioun geet un {STRING}!{}{}{STRING} Service vun {STRING} op {STRING} gëtt nächst Joer dräifach bezuelt! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Subventioun geet un {STRING}!{}{}{STRING} Service vun {STRING} op {STRING} gëtt nächst Joer mat 400% bezuelt! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Trafficchaos an {TOWN}!{}{}Stroossenneibau deen vun {STRING} finanzéiert ginn ass bréngt 6 Méint Misère fir d'Autosfuerer! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Transportmonopol! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}D'Gemeng {TOWN} ënnerschreiwt Kontrakt mat {STRING} fir ee Joer laang exklusiv Transportrechter! # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Usiicht {COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Kopéiert op d'Usiicht STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Kopéiert d'Plaz vun der globaler Usiicht op des Usiicht STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Vun der Usiicht drasetzen STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Setzt d'Plaz vun dëser Usiicht op déi global Usiicht # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Spill Optiounen STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Währungseenheet STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Währungseenheet wielen ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :Pond (£) STR_GAME_OPTIONS_CURRENCY_USD :Dollar ($) STR_GAME_OPTIONS_CURRENCY_EUR :Euro (€) STR_GAME_OPTIONS_CURRENCY_JPY :Yen (¥) STR_GAME_OPTIONS_CURRENCY_ATS :Eisträichesche Schilling (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :Belsch Frang (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :Schwäizer Frang (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :Tschechesch Kroun (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :Däitsch Mark (DM) STR_GAME_OPTIONS_CURRENCY_DKK :Dänesch Kroun (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :Peseten (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :Finnesch Mark (FIM) STR_GAME_OPTIONS_CURRENCY_FRF :Franséische Frang (FRF) STR_GAME_OPTIONS_CURRENCY_GRD :Griechësch Drachme (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :Ungaresche Forint (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :Isländesch Kroun (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :Italienesch Lire (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :Holländesche Gulden (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :Norwegesch Kroun (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Polnesch Zloty (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Rumänesch Leu (RON) STR_GAME_OPTIONS_CURRENCY_RUR :Russesche Rubel (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Sloweneschen Tolar (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Schwedesch Kroun (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Türkesch Lire (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :Slovakesch Kroun (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :Brasilianesche Real (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :Estnesch Kroun (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Litauesch Litas (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :Südkoreanesche Won (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :Südafrikanesche Rand (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :Eegen... STR_GAME_OPTIONS_CURRENCY_GEL :Georgesche Lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iranësche Rial (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Stroossegefierer STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Wéi eng Stroossesäit sollen d'Gefierer fueren STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Lénks fueren STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Riets fueren STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Stiednimm STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Stil vun de Stiednimm wielen ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :Englesch (Original) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :Franséisch STR_GAME_OPTIONS_TOWN_NAME_GERMAN :Däitsch STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :Englesch (Erweidert) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Lateinamerikanesch STR_GAME_OPTIONS_TOWN_NAME_SILLY :Blöd STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Schwedesch STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Holländesch STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finnesch STR_GAME_OPTIONS_TOWN_NAME_POLISH :Polnesch STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovakesch STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norwegesch STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Ungaresch STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Éisträichesch STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Rumänesch STR_GAME_OPTIONS_TOWN_NAME_CZECH :Tschechesch STR_GAME_OPTIONS_TOWN_NAME_SWISS :Schwäitzer STR_GAME_OPTIONS_TOWN_NAME_DANISH :Dänesch STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Türkesch STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Italienesch STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Katalanesch ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Autospäicheren STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Wiel den Intervall aus fir d'Autospäicherung ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Aus STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :All Mount STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :All 3 Méint STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :All 6 Méint STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :All 12 Méint ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}Sprooch STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Wielt d'Interfacesprooch aus STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Vollbild STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Klick dës Optioun un fir OpenTTD am Vollbild ze spillen STR_GAME_OPTIONS_RESOLUTION :{BLACK}Bildopléisung STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Wielt d'Bildopléisung STR_GAME_OPTIONS_RESOLUTION_OTHER :Aaner STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interfacegréisst STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Wiel d'Gréisst déi fir den Interface soll benotzt ginn STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normal STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Duebel STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Véierfach STR_GAME_OPTIONS_BASE_GRF :{BLACK}Basis Grafikset STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Wielt de Basis Grafikset dee soll benotzt ginn STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} fehlend/korrupt Datei{P "" en} STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Méi Infos iwwert de Basis Grafikset STR_GAME_OPTIONS_BASE_SFX :{BLACK}Basis Soundset STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Wiel de Basis Soundset dee soll benotzt ginn STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Méi Informatiounen iwwer d'Basis Soundset STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Basis Musikset STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Wiel de Basis Musikset dee soll benotzt ginn STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} korrupt Datei{P "" en} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Méi Informatiounen iwwer de Basis Musikset STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Konnt keng Lëscht vun supportéierten Opléisunge fannen STR_ERROR_FULLSCREEN_FAILED :{WHITE}Fehler beim Vollbild # Custom currency window STR_CURRENCY_WINDOW :{WHITE}Eegen Währung STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Wiesselkuer: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Setz de Betrag Suen dee fir 1 Pond (£) gebraucht gëtt erof STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Setz de Betrag Suen dee fir 1 Pond (£) gebraucht gëtt erop STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Setzt de Wiesselcours fir deng Währung fir 1 Pond (£) STR_CURRENCY_SEPARATOR :{LTBLUE}Komma-Stil: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Setzt de Separateur fir deng Währung STR_CURRENCY_PREFIX :{LTBLUE}Prefix: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Setzt de Prefix fir deng Währung STR_CURRENCY_SUFFIX :{LTBLUE}Suffix: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Setzt de Suffix fir deng Währung STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Op Euro wiesselen ab: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Zum Euro wiesselen: {ORANGE}nie STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Wielt d'Joer wou op den Euro gewiesselt gëtt STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Wiessel éischter op den Euro STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Wiessel méi spéit op den Euro STR_CURRENCY_PREVIEW :{LTBLUE}Prouf: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 Pond (£) an denger Währung STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Änner Währungsparameter STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Maximal Unzuel vu Géigner: {ORANGE}{COMMA} STR_NONE :Keng STR_FUNDING_ONLY :Nëmmen finanzéiren STR_MINIMAL :Minimal STR_NUM_VERY_LOW :Ganz niddreg STR_NUM_LOW :Wéineg STR_NUM_NORMAL :Normal STR_NUM_HIGH :Vill STR_NUM_CUSTOM :Benotzerdefinéiert STR_NUM_CUSTOM_NUMBER :Eegen ({NUM}) STR_VARIETY_NONE :Keng STR_VARIETY_VERY_LOW :Ganz niddreg STR_VARIETY_LOW :Niddreg STR_VARIETY_MEDIUM :Mëttel STR_VARIETY_HIGH :Héich STR_VARIETY_VERY_HIGH :Ganz héich STR_AI_SPEED_VERY_SLOW :Ganz lues STR_AI_SPEED_SLOW :Lues STR_AI_SPEED_MEDIUM :Mëttel STR_AI_SPEED_FAST :Séier STR_AI_SPEED_VERY_FAST :Ganz séier STR_SEA_LEVEL_VERY_LOW :Ganz niddreg STR_SEA_LEVEL_LOW :Niddreg STR_SEA_LEVEL_MEDIUM :Mëttel STR_SEA_LEVEL_HIGH :Héich STR_SEA_LEVEL_CUSTOM :Eegen STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Eegen ({NUM}%) STR_RIVERS_NONE :Keng STR_RIVERS_FEW :Wéineg STR_RIVERS_MODERATE :Mëttel STR_RIVERS_LOT :Vill STR_DISASTER_NONE :Keng STR_DISASTER_REDUCED :Manner STR_DISASTER_NORMAL :Normal STR_SUBSIDY_X1_5 :x1.5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 STR_TERRAIN_TYPE_VERY_FLAT :Ganz Flaach STR_TERRAIN_TYPE_FLAT :Flaach STR_TERRAIN_TYPE_HILLY :Hiwwelech STR_TERRAIN_TYPE_MOUNTAINOUS :Bierger STR_TERRAIN_TYPE_ALPINIST :Alpin STR_CITY_APPROVAL_PERMISSIVE :Fräizügeg STR_CITY_APPROVAL_TOLERANT :Tolerant STR_CITY_APPROVAL_HOSTILE :Ofleenend STR_WARNING_NO_SUITABLE_AI :{WHITE}Keng KI fonnt...{}KI kënnen iwwert den 'Online Content' system downgeload ginn # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Astellungen STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter-String: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Alles erweideren STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Alles reduzéiren STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(keng Erklärung verfügbar) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standardwäert: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Astellungstyp: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Clientastellung (net am Save gespäichert; betrëfft all Spiller) STR_CONFIG_SETTING_TYPE_GAME_MENU :Spillastellung (am Save gespäichert; betrëfft just nei Spiller) STR_CONFIG_SETTING_TYPE_GAME_INGAME :Spillastellung (am Save gespäichert; betrëfft just aktuellt Spill) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Firmenastellung (am Save gespäichert; betrëfft just nei Spiller) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Firmenastellung (am Save gespäichert; betrëfft just déi aktuell Firma) STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategorie: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Typ: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Limitéiert d'Lëscht mat virdefinéierten Filter STR_CONFIG_SETTING_RESTRICT_BASIC :Basis (nëmmen wichteg Astellungen) STR_CONFIG_SETTING_RESTRICT_ADVANCED :Erweidert (weist déi meescht Astellungen) STR_CONFIG_SETTING_RESTRICT_ALL :Expertenastellungen (all Astellungen, och komescher) STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Astellungen mat engem aneren Wäert wéi de Standardwäert STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Astellungen mat engem aneren Wäert wéi d'Neit-Spill-Astellungen STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Beschränkt déi folgend Lëscht op bestëmmten Astellungstypen STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :All Astellungen STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Clientastellung (net am Save gespäichert; betrëfft all Spiller) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Spillastellungen (am Save gespäichert; betrëfft just nei Spiller) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Spillastellungen (am Save gespäichert; betrëfft just aktuellt Spill) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Firmenastellungen (am Save gespäichert; betrëfft just nei Spiller) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Firmenastellungen (am Save gespäichert; betrëfft just déi aktuell Firma) STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Weis all Sich-Resultater no der Astellung{}{SILVER}Kategorie {BLACK}bis {WHITE}{STRING} STR_CONFIG_SETTING_TYPE_HIDES :Weis all Sich-Resultater no der Astellung{}{SILVER}Typ {BLACK}bis {WHITE}All Astellungstypen STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Weis all Sich-Resultater no der Astellung{}{SILVER}Kategorie {BLACK}bis {WHITE}{STRING} {BLACK}an {SILVER}Typ {BLACK}bis {WHITE}All Astellungstypen STR_CONFIG_SETTINGS_NONE :{WHITE}- Keng - STR_CONFIG_SETTING_OFF :Aus STR_CONFIG_SETTING_ON :Un STR_CONFIG_SETTING_DISABLED :ausgeschalt STR_CONFIG_SETTING_COMPANIES_OFF :Aus STR_CONFIG_SETTING_COMPANIES_OWN :Eege Firma STR_CONFIG_SETTING_COMPANIES_ALL :All Firmen STR_CONFIG_SETTING_NONE :Keng STR_CONFIG_SETTING_ORIGINAL :Original STR_CONFIG_SETTING_REALISTIC :Realistesch STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Lénks STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Zentréiert STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Riets STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maximalen Ufanksloun: {STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Maximalwäert den eng Firma kann léinen (ouni Inflatioun matzerechnen) STR_CONFIG_SETTING_INTEREST_RATE :Zënssaz: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Zënssaz; kontrolléiert och d'Inflatioun wann ugeschalt STR_CONFIG_SETTING_RUNNING_COSTS :Betribskäschten: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Fixéier den Niveau vun de Betribskäschten vu Gefierer an Infrastruktur STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Baugeschwindegkeet: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limitéier d'Unzuel u Bauaktiounen fir d'KI STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Gefierpannen: {STRING} STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Kontrolléirt wéi oft Gefierer eng Pann hunn déi net ordentlech an der Revisioun waren STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subventiounemultiplikator: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Fixéiert wéivill fir subsidéiert Verbindunge bezuelt gëtt STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Konstruktiounskäschten: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Bestëmm den Niveau vu Bau- a Kafkäschten STR_CONFIG_SETTING_RECESSIONS :Rezessiounen: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Wann ugeschalt kann all puer Joer eng Rezessioun kommen. Während enger Rezessioun ass d'Produktioun däitlech méi niddreg (an klëmmt erëm op den alen Niveau no der Rezessioun) STR_CONFIG_SETTING_TRAIN_REVERSING :Den Zich verbidden an enger Statioun emzedréinen: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :Wann ugeschalt kënnen Zich net an Net-Terminusen emdréinen, och wann et en méi kuerzen Wee op d'Destinatioun gëtt wann en emdréint STR_CONFIG_SETTING_DISASTERS :Katastrophen: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Stell Katastrophen un oder aus déi eventuell Gefierer an Industrien blockéiren oder zerstéiren STR_CONFIG_SETTING_CITY_APPROVAL :Dem Stadrot seng Astellung géigeniwwer dem Embau vun der Landschaft: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Wielt aus, wéivill vun der Firma verursachten Kaméidi an Emweltschiedegung sech op d'Stadbewäertung an op weider Bauaktiounen auswierkt STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Maximal Kaartenhéicht: {STRING} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Setzt déi maximal erlabten Héicht fir Bierger op dëser Kaart STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Du kanns d'maximal Kaartenhéischt net op dësen Wäert setzen. Op manst ee Bierg op der Kaart ass méi héich STR_CONFIG_SETTING_AUTOSLOPE :Erlaabt Landformung ënnert Gebaier, Stroossen, etc.: {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Erlaabt Terraintransformatioun ënnert Gebaier an Schinnen ouni dës ewechzehuelen STR_CONFIG_SETTING_CATCHMENT :Erlaabt méi realistësch Einzugsberäicher: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Statiounen a Fluchhäfen hunn verschidde grouss Einzugsberäicher STR_CONFIG_SETTING_EXTRADYNAMITE :Erlaabt d'Ewechhuelen vu méi Stroossen, Brécken, etc. vun der Stad: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Mach et méi einfach fir Infrastruktur oder Gebaier ewechzehuelen déi enger Stad gehéiren STR_CONFIG_SETTING_TRAIN_LENGTH :Maximal Längt vun Zich: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Maximal Längt vun Zich fixéiren STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} Feld{P 0 "" er} STR_CONFIG_SETTING_SMOKE_AMOUNT :Unzuel vu Gefierdamp/funken: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Fixéiert wéivill Damp oder Funken vu Gefierer ausgestouss gëtt STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Zuchbeschleunegung: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Wielt de physesche Modell fir d'Zuchbeschleunegung. Den "Orginalmodell" bestroft Häng fir all Gefierer d'selwecht. Den "realistëschen" bestroft Häng a Kéiren ofhängeg vu verschiddenen Eegenschaften, wéi Längt an Stäerkt vum Gefier STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Stroossegefier Beschleunegungsmodell: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Wielt de physesche Modell fir d'Stroossegefierbeschleunegung. Den "Orginalmodell" bestroft Häng fir all Gefierer d'selwecht. Den "realistëschen" bestroft Häng an Kéiren ofhängeg vu verschiddenen Eegenschaften, wéi Längt a Stäerkt vum Gefier STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Hangsteigung fir Zich: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Steigung vun engem Hang fir Zich. Méi grouss Wäerter mécht et méi schwéier den Hang ropzefueren STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Hangsteigung fir Stroossegefierer: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Steigung vun engem Hang fir Stroossegefierer. Méi grouss Wäerter mécht et méi schwéier den Hang ropzefueren STR_CONFIG_SETTING_FORBID_90_DEG :Verbidd Zich an Schëffer fir 90°-Kéieren ze maachen: {STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90°-Kéieren entsti wann eng horizontal Spur direkt op eng vertikal trëfft, sou dass den Zuch misst ëm 90 Grad dréinen fir op dat nächst Stéck ze kommen, amplaz vun den üblechen 45 Grad. Dëst zielt och fir d'Weeër vu Schëffer STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Erlaabt Statiounen zesummen ze setzen och wann se net direkt uneneen leien: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Erlaabt Statiounsdeeler un eng Statioun unzehenken ouni déi existéiernd Statioun ze beréiren. Ctr+Klick fir déi nei Deeler unzehenken STR_CONFIG_SETTING_INFLATION :Inflatioun: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Erlab Inflatioun an der Economie, wou d'Käschten méi séier klammen wéi d'Bezuelungen STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maximal Bréckelängt: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Maximal Längt déi eng Bréck dierf hunn STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Maximal Bréckenhéicht: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Maximalhéicht fir Brécken ze bauen STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maximal Tunnellängt: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Maximal Längt déi en Tunnel dierf hunn STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Manuell Primär Industriebau Method: {STRING} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Method fir eng primär Industrie ze finanzéiren. 'keng' heescht, dass een guer keng kann finanzéiren. 'fördern' bedeit, dass eng nei Industrie gebaut gëtt, op enger zoufällëger Plaz op der Kaart, mee kann och schief goën. 'wéi aner Industrien' bedeit, dass Quellenindustrie kënne vu Firmen op enger gewënschter Plaz gebaut ginn wéi verschaffend Industrien STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :Keng STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :Wéi aaner Industrien STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Förderung STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Flaacht Land ronderëm Industrien: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Unzuel vu flaache Felder ronderëm eng Industrie. Dëst garantéiert, dass eidel Felder ronderëm eng Industrie fräi bleiwen fir Schinnen etc. ze bauen STR_CONFIG_SETTING_MULTIPINDTOWN :Erlaabt méi der selwecht Industrien pro Stad: {STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Normalerweis well eng Stad net méi wéi eng Industrie vun all Typ. Mat dëser Astellung erlaabt d'Stad méi Industrien vun dem selwëschten Typ STR_CONFIG_SETTING_SIGNALSIDE :Signaler uweisen: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Wielt opp wéienger Säit vun der Schinn d'Signaler plazéiert ginn STR_CONFIG_SETTING_SIGNALSIDE_LEFT :Lénks STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :Op der Fuerersäit STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :Riets STR_CONFIG_SETTING_SHOWFINANCES :Weis de Bilan um Enn vum Joer: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Wann ugeschalt, gëtt eng Fënster um Enn vum Joer gewisen, déi eng einfach Iwwersicht iwwert d'Finanzen vun der Firma erlaabt STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Nei Opträg sinn standardméisseg 'non-stop': {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normalerweis stoppt en Gefier op all Statioun op sengem Wee. Wann des Astellung ageschalt ass, bleift et op kenger Statioun stoen bis op seng final Statioun STR_CONFIG_SETTING_STOP_LOCATION :Nei Zichuerder stoppen um {STRING} vun der Plattform STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Plaz wou en Zuch standardméisseg op enger Gare stoe bleift. 'No um Ufank' bedeit no beim Agangspunkt, 'an der Mëtt' bedeit an der Mëtt vun der Plattform, 'wäit Enn' bedeit wäit ewech vum Agangspunkt. Dëst gëllt fir Standardopträg, individuell Opträg kënnen explizit gesat ginn STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :no um Enn STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :an der Mëtt STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :um Enn STR_CONFIG_SETTING_AUTOSCROLL :D'Fënster schwenken wann d'Maus um Rand ass: {STRING} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Wann ugeschalt, scrollt d'Usiicht wann d'Maus no um Rand vun der Fënster ass STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Ausgeschalt STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Haptusiicht, nëmmen Vollbild STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Haptusiicht STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :All Usiicht STR_CONFIG_SETTING_BRIBE :Erlaabt d'Gemengen ze bestiechen: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Erlaabt Firmen d'Stad ze bestiechen. Wann et opflitt, kann d'Firma während 6 Méint net mat der Stad agéiren STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Erlaabt exklusiv Transportrechter ze kafen: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Wann eng Firma exklusiv Transportrechter fir eng Stad keeft, kréien géignerësch Statiounen (Passagéier an Wueren) keng Wueren fir e ganzt Joer STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Gebaier finanzéiren erlaben: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Erlaabt Firmen de Stied Geld ze ginn fir nei Haiser ze bauen STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Erlab Stroossenrenovatiounen ze finanzéiren: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Erlaabt Firmen de Stied Geld ze ginn fir d'Stroossen ze renovéieren an sou de Stroosseverkéier ze sabotéieren STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Erlaabt d'Schécken vu Suen un aner Firmen: {STRING} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Erlaabt den Transfert vu Geld tëschent Firmen am Multiplayermodus STR_CONFIG_SETTING_FREIGHT_TRAINS :Gewiichtsmultiplikator fir Luedunge fir schwéier Zich: {STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Leet den Impakt fest dee schwéier Fracht op Zich huet. En méi héije Wäert bréngt d'Zich éischter un d'Schaffen, speziell bei Bierger STR_CONFIG_SETTING_PLANE_SPEED :Fligergeschwindegkeetsfaktor: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Leet d'relativ Geschwindegkeet vu Fligeren am Verglach mat anere Gefierer fest, fir d'Akomme vum Transport vu Fligeren ze reduzéiren STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Unzuel Fligerakzidenter: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Leet d'Chance fir en Fligerakzident fest STR_CONFIG_SETTING_PLANE_CRASHES_NONE :Keng STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduzéiert STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Erlaabt d'Iwwerfueren vu Stopschëlder op Stroossen vun der Stad: {STRING} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Erlaabt d'Bauen vu säitlechen Busarrêten op Stroossen déi der Stad gehéieren STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Erlaabt d'Iwwerfueren vu Stopschëlder op Stroossen vun der Konkurrenz: {STRING} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Erlaabt d'Bauen vu säitlechen Busarrêten op Stroossen déi enger anerer Firma gehéieren STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Déi Astellung kann net geännert ginn wann et Gefierer gëtt STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastrukturënnerhalt {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Wann ugeschalt, kaschten Infrastrukturen Ennerhaltskäschten. D'Käschten wuessen iwwerproportional zu der Netzwierkgréisst, an treffen sou grouss Firmen méi wéi klenger STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Fluchhäfen lafen nie of: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Wann ugeschalt, bleift all Fluchhafentyp säit senger Aféierung bestoen STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Warnen wann en Gefier verluer ass: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Messagen uweisen wann Gefierer keen Wee op hiert Ziel fannen STR_CONFIG_SETTING_ORDER_REVIEW :Opträg vun de Gefierer nopréifen: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Wann ugeschalt, ginn d'Opträg vu Gefierer periodesch kontrolléiert, an e puer evident Fehler ginn mat enger Noriichtenmessage gemellt wann se fonnt ginn STR_CONFIG_SETTING_ORDER_REVIEW_OFF :Nee STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Jo, mee net déi gestoppten Gefierer STR_CONFIG_SETTING_ORDER_REVIEW_ON :Vun allen Gefierer STR_CONFIG_SETTING_WARN_INCOME_LESS :Warnen wann en Gefier en negativt Akommes huet: {STRING} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :Wann ugeschalt, gëtt eng Noorichtenmessage gesent , wann en Gefier een Joer laang keen Profit gemeet huet STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Gefierer lafen nie of: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :Wann ugeschalt, bleiwen all Modeller vu Gefierer éiweg verfügbar STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Gefier automatesch ernéieren wann et al gëtt: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :Wann ugeschalt, gëtt e Gefier wat un säin Lafzäitenn kënnt, automatesch ausgetosch STR_CONFIG_SETTING_AUTORENEW_MONTHS :Automatesch erneieren wann d'Gefier maximal {STRING} Joer al ass STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relativen Alter wann en Gefier an Fro kennt fir auto-erneiert ze ginn STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} M{P ount éint} firdrun STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} M{P ount éint} dono STR_CONFIG_SETTING_AUTORENEW_MONEY :Minimalen Budget fir d'automatesch Erneierung: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimalt Geld wat um Konto muss bleiwen, iert en Gefier kann ausgetosch ginn STR_CONFIG_SETTING_ERRMSG_DURATION :Dauer vun der Feelermeldung: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Zäit déi eng Feelermeldung an enger rouder Fënster ugewisen gëtt. E puer kritesch Meldungen ginn net zougemeet STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} Sekonn{P 0 "" en} STR_CONFIG_SETTING_HOVER_DELAY :Weis Tooltips: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Verzögerung bis d'Tooltips ugewisen ginn, wann een mat der Maus iwwert en Element geet. Alternativ kënnen d'Tooltips och op d'riets Maustast geluet ginn wann dësen Wäert op 0 gesat gouf. STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Fir {COMMA} Millisekonn{P 0 "" en} dropbleiwen STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Rietsklick STR_CONFIG_SETTING_POPULATION_IN_LABEL :Weis d'Awunnerzuel am Numm vun der Stad: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Weis d'Awunnerzuel vu Stied an deenen hirem Label un op der Kaart STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Déckt vun de Linnen vun de Grafiken: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Breed vun de Linnen an de Grafiken. Eng dënn Linn kann méi präzis gelies ginn, eng méi déck kann besser gesinn ginn an d'Faarwen sinn besser ze ënnerscheeden STR_CONFIG_SETTING_LANDSCAPE :Landschaft: {STRING} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Landschaften definéiren basis Spillszenarien mat verschiddenen Wueren an Stiedwuesstumviraussetzungen. NewGRF an Gamescripter erlaben méi fein Astellungen. STR_CONFIG_SETTING_LAND_GENERATOR :Landgenerator: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :Den original Generator henkt vum basis Grafikset of, an erstellt fixéiert Landschaftstypen. TerraGenesis ass en op Perlin noise baséierten Generator mat méi feinen Astellungen. STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_TERRAIN_TYPE :Terraintyp: {STRING} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Nëmmen TerraGenesis) Hiwwelegkeet vun der Landschaft STR_CONFIG_SETTING_INDUSTRY_DENSITY :Industriedicht: {STRING} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Definéiert wéivill Industrien generéiert sollen ginn an wéivill der während dem Spill sollen behalen ginn. STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maximal Distanz vum Kaartenenn bis zu enger Uelegraffinerie: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Uelëgraffinerien ginn nëmmen um Rand gebaut, dat ass un der Küst fir Inselkaarten STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Schnéigrenz Héicht: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Kontrolléiert ab welcher Héicht de Schnéi ufenkt an der subarktëscher Landschaft. Schnéi affektéiert och Industriegeneratioun an de Wuesstum vu Stied. STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Knubbelegkeet vum Terrain (nëmmen TerraGenesis) : {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(Nëmmen TerraGenesis) Wiel d'Heefegkeet vun Hiwwelen: Mëll Landschafter hunn manner, breed verdeelten Hiwwelen. Rau Landschaften hunn méi Bierger déi repetitiv ausgesinn kënnen. STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Ganz Flaach STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Flaach STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Fielseg STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Ganz Fielseg STR_CONFIG_SETTING_VARIETY :Vielfaltverdeelung: {STRING} STR_CONFIG_SETTING_VARIETY_HELPTEXT :(Nëmmen TerraGenesis) Kontrolléiert op d'Kaart flaach Stécker an och Bierger huet. Wëll dëst d'Kaart méi flaach mécht, sollen aner Astellungen op Bierger gesat ginn STR_CONFIG_SETTING_RIVER_AMOUNT :Unzuel Flëss: {STRING} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Wiel wéivill Flëss generéiert ginn STR_CONFIG_SETTING_TREE_PLACER :Baamplanzalgorithmus: {STRING} STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Wiel d'Verdeelung vun de Beem op der Kaart: 'Orginal' setzt d'Beem uniform verspreet, 'Verbessert' setzt se an Gruppen STR_CONFIG_SETTING_TREE_PLACER_NONE :Keen STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Original STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Verbessert STR_CONFIG_SETTING_ROAD_SIDE :Stroossegefierer: {STRING} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Wiel d'Säit op där gefuer gëtt STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Héichtenkaartrotatioun: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Géint d'Auer STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Matt der Auer STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :Héichtenintervall den eng flaach Szenariokaart kritt: {STRING} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}Een oder méi Felder um nördlechsten Rand sinn net eidel STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}Een oder méi Felder op engem Eck sinn keen Waasser STR_CONFIG_SETTING_STATION_SPREAD :Maximal Ausdehnung vu Statiounen: {STRING} STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Maximal Distanz déi eenzel Statiounsdeeler dierfen auseneenleien. Méi héich Wäerter maachen d'Spill méi lues STR_CONFIG_SETTING_SERVICEATHELIPAD :Automatesch Maintenance vun Helikopteren: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Schéck Helikopter no all Landung an d'Revisioun, och wann keen Schapp um Fluchhafen ass STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Landschaft-Toolbar op Zuch/Strooss/Schëff/Fluchhafen-Toolbar linken: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :Wann eng Toolbar fir Konstruktiounen opgemeet gëtt, gëtt och d'Toolbar fir d'Terrainverännerung opgemeet STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Landfaarf déi op der klénger Kaart benotzt get: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Faarf vum Terrain vun der klenger Kaart STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Gréng STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Donkelgréng STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Mof STR_CONFIG_SETTING_REVERSE_SCROLLING :Deen anere Wee scrollen: {STRING} STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :Verhalen beim Scrollen vun der Kaart mat der rietser Maustast. Wann ausgeschalt, beweegt d'Maus d'Kamera. Wann ugeschalt, beweegt d'Maus d'Kaart STR_CONFIG_SETTING_SMOOTH_SCROLLING :Feine Scrolling: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Kontrolléiert wéi d'Haptusiicht op eng bestëmmten Positioun scrollt, wann een op déi kléng Kaart klickt oder en Befehl fir ob en spezifescht Objet ze scrollen gëtt. Wann ugeschalt, gëtt bis dohin gescrollt, wann ausgeschalt, spréngt d'Vue op den Zielobjet STR_CONFIG_SETTING_MEASURE_TOOLTIP :Weis en Mooss-Tooltip wann verschidde Bau-Tools benotzt ginn: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Weis Felderdistanzen an Héichtenënnerscheed beim Zéien während dem Bauen un STR_CONFIG_SETTING_LIVERIES :Weis Faarwen je no Gefiertyp: {STRING} STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Definéiert de Gebrauch vu gefierspezifesch Lackéirungen fir Gefierer (am Géigensaz zu firmenspezifëschen Lackéirungen) STR_CONFIG_SETTING_LIVERIES_NONE :Keng STR_CONFIG_SETTING_LIVERIES_OWN :Eege Firma STR_CONFIG_SETTING_LIVERIES_ALL :All Firmen STR_CONFIG_SETTING_PREFER_TEAMCHAT :Preferéier Teamchat mat : {STRING} STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Wiessel d'Firmen-intern Chat-Tast an Effentlechen-Chat op resp. STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Fonktioun vum Scrollrad: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Schalt d'Scrollen mat zwee-dimensionalen Mausrieder un STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Kaart Zoomen STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Kaart Scrollen STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Aus STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Geschw. vum Scrollrad op der Kaart : {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Kontrolléier d'Sensibilitéit vum scrollen mam Mausrad STR_CONFIG_SETTING_OSK_ACTIVATION :Onscreen-Tastatur: {STRING} STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Wiel d'Method fir d'Onscreentastatur unzeman fir Text an eng Textbox ze schreiwen andems just eng Maus benotzt gëtt. Dëst as geduet fir kleng Geräter ouni richteg Tastatur STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Ausgeschalt STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Duebelklick STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Ee Klick (wann fokusséiert) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Ee Klick (direkt) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Rietsklickemulatioun: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Wiel d'Method aus fir déi riets Maustast ze emuléiren STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :COMM+Klick STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :CTRL+Klick STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Aus STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Lénksklickscroll: {STRING} STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :Schalt d'Scrollen vun der Kaart un, wann se mat der lénker Maustast gezunn gëtt STR_CONFIG_SETTING_AUTOSAVE :Autospäicheren: {STRING} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :Setz den Interval tëschend automateschen Späicherstänn STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Benotz {STRING} Datumsformat fir Späichernimm STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Format vum Datum am Numm vum Späicherstand STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :laangen (31ten Dez 2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :kuerzen (31-12-2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Paus d'Spill beim Start vun enger neier Partie: {STRING} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Wann ugeschalt, pauséiert d'Spill automatesch wann en neit Spill gestart gëtt, wat erlaabt d'Kaart besser ze studéieren STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Wa Paus ass, erlab: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Wielt aus, wat kann gemeet ginn wann d'Spill pauséiert gouf STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :Keng Aktiounen STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :All Net-Bauaktiounen STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :All ausser Landëmformungen STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :All Aktiounen STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Benotz Gruppen an der Gefierlëscht: {STRING} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Schalt d'erweidert Gefiererlëscht un fir Gefierer ze gruppéieren STR_CONFIG_SETTING_LOADING_INDICATORS :Weist de Luedstatus un: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Wielt aus, ob Luedindikatoren iwwert engem Gefier ugewise ginn oder net, wann et beluede gëtt STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Weis den Zäitplang an Ticken amplaz vun Deeg: {STRING} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Weist d'Transportdauer an der Zäittafel als Gameticks un, amplaz an Deeg STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Weis Arrivée an Départ am Zäitplang un: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Weis d'geplangten Departen an Arrivéeën an der Zäittafel un STR_CONFIG_SETTING_QUICKGOTO :Schnellkreatioun vu Gefieropträg: {STRING} STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Wiel den 'géi op Zeiger' un, wann d'Optragsfënster opgemeet gëtt STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Standard Schinnentyp (no neiem Spill/geluedenem Spill): {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Schinnentyp de gewielt gëtt nom starten oder luede vun engem Spill. 'éischt verfügbar' wielt den eelsten Typ Schinnen, 'lescht verfügbar' wielt den neisten Typ Schinnen, an 'meescht gebraucht' wielt den Typ de grad am meeschten gebraucht gëtt STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :Eischt verfügbar STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Läscht verfügbar STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Meescht benotzten STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Weis de reservéierte Wee op de Schinnen: {STRING} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Fierf reservéiert Schinnen an enger anerer Faarf fir engem ze hëllefen wann Zich refuséieren fir an Wee-baséiert Bléck ze fueren STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Bau-Tools nom Gebrauch aktiv loossen: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Looss d'Bauoptiounen fir Brécken, Tunnelen etc. nom Gebrauch op STR_CONFIG_SETTING_EXPENSES_LAYOUT :Ausgaben vun der Firma an der Finanzfënster gruppéiren: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Definéiert de Layout fir d'Firmenausgabefënster STR_CONFIG_SETTING_SOUND_TICKER :Newsticker: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Spill Sound of fir resuméiert Neiegkeeten STR_CONFIG_SETTING_SOUND_NEWS :Zeitung: {STRING} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Spill Soundeffekt of wann eng Zeitung rauskënnt STR_CONFIG_SETTING_SOUND_NEW_YEAR :Enn vum Joer: {STRING} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Spill Soundeffekt of um Enn vum Joer, wann d'Performance vun der Firma resuméiert gëtt am Verglach mam Viirjoer STR_CONFIG_SETTING_SOUND_CONFIRM :Konstruktioun: {STRING} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Spill Soundeffekter of wa Konstruktiounen an aner Aktiounen ausgefouert goufen STR_CONFIG_SETTING_SOUND_CLICK :Kneppercherklicks: {STRING} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Beep beim Klicken vu Kneppercher STR_CONFIG_SETTING_SOUND_DISASTER :Katastrophen/Akzidenter: {STRING} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Spill Soundeffekter vun Akzidenter a Katastrophen of STR_CONFIG_SETTING_SOUND_VEHICLE :Gefierer: {STRING} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Spill Soundeffekter vu Gefierer of STR_CONFIG_SETTING_SOUND_AMBIENT :Ambiance: {STRING} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Spillt Ambience Soundeffekter vun der Landschaft, Industrien an Stied of STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Gebai ausschalten wann keng passend Gefierer verfügbar sinn: {STRING} STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :Wann ugeschalt, ass d'Infrastruktur just verfügbar, wann och Gefierer verfügbar sinn, fir dass keen Geld an keng Zäit verschwend gëtt, sënnlos Infrastrukturen ze bauen STR_CONFIG_SETTING_MAX_TRAINS :Maximum un Zich pro Firma: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Maximal Unzuel un Zich déi eng Firma kann hunn STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Maximum un Stroossegefierer pro Firma: {STRING} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Maximal Unzuel u Gefierer déi eng Firma kann hunn STR_CONFIG_SETTING_MAX_AIRCRAFT :Maximum un Fligeren pro Firma: {STRING} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Maximal Unzuel u Fligeren déi eng Firma kann hunn STR_CONFIG_SETTING_MAX_SHIPS :Maximum u Schëffer pro Firma: {STRING} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Maximal Unzuel u Schëffer déi eng Firma kann hunn STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Zich fir de Computer ausschalten: {STRING} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Wann des Astellung ugeschalt ass, kann e Computergéigner keng Zich bauen STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Stroossegefierer fir de Computer ausschalten: {STRING} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Wann des Astellung ugeschalt ass, kann e Computergéigner keng Gefierer bauen STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Fligeren fir de Computer ausschalten: {STRING} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Wann des Astellung ugeschalt ass, kann e Computergéigner keng Fligeren bauen STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Schëffer fir de Computer ausschalten: {STRING} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Wann des Astellung ugeschalt ass, kann e Computergéigner keng Schëffer bauen STR_CONFIG_SETTING_AI_PROFILE :Standard Astellungsprofil: {STRING} STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Wielt aus wellechen Astellungsprofil benotzt gëtt fir d'zoufälleg KI oder fir Ufankswäerter wann eng nei KI oder Spillscript ugeschalt ginn STR_CONFIG_SETTING_AI_PROFILE_EASY :Einfach STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Normal STR_CONFIG_SETTING_AI_PROFILE_HARD :Schwéier STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Erlaabt KI am Multiplayer: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Erlaabt Computergéigner a Multiplayer Spiller matzeman STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes befier de Script suspendéiert gëtt: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximal Unzuel u Rechenschrëtt déi e Script kann an engem Tuer man STR_CONFIG_SETTING_SERVINT_ISPERCENT :Revisiounsintervallen a Prozenter: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Wiel op eng Revisioun ausgeléist gëtt durch Zäit déi säit der leschter Revisioun vergangen ass oder well Zouverlessëgkeet en gewëssen Prozentsaz vun der maximaler Zouverlässëgkeet erofgaang ass STR_CONFIG_SETTING_SERVINT_TRAINS :Standard Revisiounsintervall fir Zich: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Definéiert de Standardrevisiounsintervall fir nei Zich, wann keen expliziten Revisiounsintervall uginn ass STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}D{P 0 ag eeg}/% STR_CONFIG_SETTING_SERVINT_DISABLED :Ausgeschalt STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Standard Revisiounsintervall fir Gefierer: {STRING} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Definéiert de Standardrevisiounsintervall fir nei Gefierer, wann keen spezifëschen Revisiounsintervall uginn ass STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Standard Revisiounsintervall fir Fligeren: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Definéiert de Standardrevisiounsintervall fir nei Fligeren, wann keen expliziten Revisiounsintervall uginn ass STR_CONFIG_SETTING_SERVINT_SHIPS :Standard Revisiounsintervall fir Schëffer: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Definéiert de Standardrevisiounsintervall fir nei Schëffer, wann keen expliziten Revisiounsintervall uginn ass STR_CONFIG_SETTING_NOSERVICE :Revisiounen ausschalten wann Pannen op "Keng" gestallt sinn: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Wann ugeschalt, ginn Gefierer net an d'Revisioun geschéckt, wann se keng Pann kënne kréien STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Geschwindegkeetsbegrenzungen fir Waggonen: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Wann ugeschalt, benotz och Geschwindegkeetslimitatiounen fir Waggonen fir d'maximal Geschwindegkeet vun engem Zuch ze definéiren STR_CONFIG_SETTING_DISABLE_ELRAILS :Elektreschschinnen ausschalten: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Wann dës Astellung ugeschalt ass, ginn keng elektresch Schinnen gebraucht fir mat elektreschen Zich ze fueren STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Ukonft vum éischte Gefier op enger Statioun vum Spiller: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Weis d'Zeitung wann dat éischt Gefier op enger eegener Statioun ukënnt STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Ukonft vum éischten Gefier op enger Géigenspillerstatioun: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Weis d'Zeitung wann dat éischt Gefier op enger géignerescher Statioun ukënnt STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Akzidenter / Katastrophen: {STRING} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Weis d'Zeitung wann Akzidenter oder Katastrophen passéiren STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Firmeninformatiounen: {STRING} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Weis d'Zeitung wann eng nei Firma opgeet, oder wann ee riskéiert Bankrott ze goen STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Grënnung vun enger Industrie: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Weis d'Zeitung wann eng nei Industrie opmécht STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Industrie gëtt zougemaach: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Weis d'Zeitung wann eng Industrie zoumécht STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Wiertschaftsännerungen: {STRING} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Weis d'Zeitung iwwert d'global Wiertschaft STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Produktiounswiessel vun der Industrie dei vun der Firma beliwwert gëtt: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Weis d'Zeitung wann d'Produktioun vun enger Industrie ännert, déi vun der Firma beliwwert gëtt STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Produktiounswiessel vun der Industrie dei vun der Konkurrenz beliwwert gëtt: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Weis d'Zeitung wann d'Produktioun vun enger Industrie ännert, déi vun engem Spiller beliwwert gëtt STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Aaneren industrielle Produktiounswiessel: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Weis d'Zeitung wann d'Produktioun vun enger Industrie ännert, déi vu kengem Spiller beliwwert gëtt STR_CONFIG_SETTING_NEWS_ADVICE :Hinweis / Informatioun iwwert Firmegefierer: {STRING} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Weis Messagen wa Gefierer Opmierksamkeet brauchen STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :Nei Gefierer: {STRING} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Weis d'Zeitung wann en neit Gefier rauskënnt STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Ännerung vun akzeptéierte Luedungen: {STRING} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Weis Messagen wa Statiounen Gidder akzeptéiren / net méi akzeptéiren STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subventiounen: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Weis d'Zeitung a Relatioun mat Subventiounen STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :Generell Informatiounen: {STRING} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Weis Zeitung iwwert generell Evenementer, wéi z.b de Kaf vun exklusiven Transportrechter oder Stroosserenovéierungen STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :Aus STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Resumé STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Ganz STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Faarweg News ab: {STRING} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Joer vun dem uns d'Zeitung farweg erauskënnt. Firun dësem Joer ass se schwarz/wäiss STR_CONFIG_SETTING_STARTING_YEAR :Startjoer: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Gläichméisseg Wiertschaft aschalten (méi oft an kleng Wiessel): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Wann ugeschalt, ännert d'Industrieproduktioun méi oft, an méi kléngen Schrëtter. Dës Astellung huet keng Auswierkung op NewGRF-Industrien STR_CONFIG_SETTING_ALLOW_SHARES :Undeeler vun aaneren Firmen kafen: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Wann ugeschalt, dierfen Aktien vu Firmen kaf an verkaf ginn. Aktien si just fir Firme verfügbar, déi en gewëssen Alter erreecht hunn STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Prozentsaz vum Etappenprofit den am Feeder-System bezuelt gëtt: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Prozentsaz vum Akommes déi un d'Zwëschenetappen an engem Feeder-System gi ginn, wat méi Kontroll iwwert d'Akommes erméiglegt STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Wa gezunn gëtt, setz en Signal all: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Definéiert d'Distanz an däer Signaler gesat ginn, bis zum nächsten Obstakel (Signal, Kräizung), wa Signaler gezu ginn STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} Feld{P 0 "" er} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Beim Zéien, behal eng fix Distanz tëscht Signaler: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Wielt d'Verhale vum Signalsetzen, wa mat Ctrl gezu gëtt. Wann ausgeschalt, gi Signaler firu laange Streckenabschnitter wéi Brécken an Tunnelen gesat. Wann ugeschalt, gi Signaler all N Felder gesat, fir e parallelt Setzen vu Signaler ze erméiglechen STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Automatesch Diksen bauen firun: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Definéiert d'Joer wou elektresch Signaler benotzt ginn. Firun dësem Joer ginn nët-elektresch Signaler benotzt (déi déi selwescht Funktioun hunn, an just anescht ausgesinn) STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Signaler GUI uschalten: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Weist eng Fënster an däer den Typ vu Signaler déi gebaut kënne ginn, amplaz ouni Fënster an durch Ctrl-klicken op d'Signaler STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Standard Signal-Typ: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Standard Signaltyp dee soll benotzt ginn STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Blocksignaler STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Wee-Signaler STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :Einbahn-Wee-Signaler STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Wiessel duerch Signal-Typen: {STRING} STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :Wielt Signaltypen déi durchgewielt ginn, wann ee mat Ctrl op e gebaute Signal dréckt STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Nëmmen Blocksignaler STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Nëmmen Wee-Signaler STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :Alleguerten STR_CONFIG_SETTING_TOWN_LAYOUT :Stroosselayout an neie Stied: {STRING} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Layout fir d'Stroossennetz vun enger Stad STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Original STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Besser Stroossen STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 Gitter STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 Gitter STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Zoufälleg STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Stied däerfen Stroossen bauen: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Erlaabt Stied Stroossen ze bauen fir ze wuessen. Ausschalten fir d'Stiedréid dorun ze hënneren fir Stroossen selwer ze bauen STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Stied dierfen Barrièren bauen: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Wann dës Astellung ugeschalt ass, kënnen Stied Stroossen iwwert Schinne bauen STR_CONFIG_SETTING_NOISE_LEVEL :Erlab e stadkontrolléierte Kaméidisniveau fir Fluchhäfen: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :Wann dës Astellung ausgeschalt ass, kënnen zwee Fluchhäfen an all Stad gebaut ginn. Wann dës Astellung ugeschalt ass, henkt et vun der Fluchhafengréisst, Distanz, Kaméidisniveau of wéivill Fluchhäfen kënne gebaut ginn STR_CONFIG_SETTING_TOWN_FOUNDING :Stiedgrënnung am Spill: {STRING} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Wann dës Astellung ugeschalt ass, kënnen Spiller nei Stied am Spill grënnen STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Verbueden STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Erlaabt STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Erlaabt, custom Stad-Layout STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Bamplazéirung: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Kontrolléiert zoufälleg Optauche vu Beem während dem Spill. Dëst kann Industrie beaflossen, déi op d'Wuessen vu Beem ugewisen sinn STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :Keng{RED}(zerstéiert Bauholzfabrik) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :Nëmmen am Reebësch STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :Iwwerall STR_CONFIG_SETTING_TOOLBAR_POS :Positioun vun der Haapt-Toolbar: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horizontal Positioun vun der Haapt-Toolbar uewen um Schierm STR_CONFIG_SETTING_STATUSBAR_POS :Positioun vun der Statusbar: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Horizontal Positioun vun der Statusbar ënnen um Schierm STR_CONFIG_SETTING_SNAP_RADIUS :Radius wou d'Fënsteren uschnapen: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Distanz tëscht Fënsteren befier d'Fënsteren automatesch alignéiert ginn STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} Pixel STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Ausgeschalt STR_CONFIG_SETTING_SOFT_LIMIT :Maximal Unzuel vun net-gepinnte Fënster: {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Unzuel un net-gepinnten openen Fënster befier al Fënsteren automatesch zougemaach ginn fir nei Plaz ze man fir nei Fënsteren STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :ausgeschalt STR_CONFIG_SETTING_ZOOM_MIN :Maximalen Ranzoom Level: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Maximal Ranzoomstuf fir Usiichtsfënsteren. Et gëtt méi Späicher gebraucht wann d'Stufen ze grouss ginn STR_CONFIG_SETTING_ZOOM_MAX :Maximalen Rauszoom Level: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :Maximal Rauszoom-Stuf fir Usiichtsfënsteren. Méi grouss Rauszoom-Stufen kënnen Ruckeler verursaachen STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normal STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x STR_CONFIG_SETTING_TOWN_GROWTH :Geschw. vum Stad-Wuesstem: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Geschwindegkeet mat däer Stied wuessen STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Keen STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Lues STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normal STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Schnell STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Ganz schnell STR_CONFIG_SETTING_LARGER_TOWNS :Proportioun vun Dierfer déi kënne Stied ginn: {STRING} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Unzuel un Dierfer déi eng Stad kënne ginn, folglesch start en Duerf méi grouss an wiisst méi séier STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 zu {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :Keng STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Ufangs-Gréisst vu Stied multiplizéiren mat: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Duerchschnëttsgréisst vu Stied an Proportioun zu normalen Dierfer um Spillstart STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Aktualiséier d'Distributiounsgrafik all {STRING}{NBSP}D{P 0:2 ag eeg} STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Zäit tëscht nofolgenden Neiberechnungen vun der Linkgrafik. All Neiberechnung rechent d'Pläng fir eng Komponent vun der Grafik. Dat heescht dass en Wert X fir dës Astellung net all X Deeg aktualiséiert gëtt. Nëmmen een Komponent gëtt aktualiséiert. Wat méi kuerz gesat, wat méi CPU Rechenzäit gebraucht gëtt. Wat se méi laang gesat gëtt, wat méi Zäit vergeet bis Wuerendistributioun op enger neier Route gestart gëtt. STR_CONFIG_SETTING_LINKGRAPH_TIME :Benotz {STRING}{NBSP}D{P 0:2 ag eeg} fir d'Neiberechnung vum Distributiounsgraf STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Zäit déi gebraucht gëtt fir all Neiberechnung vun enger Linkgrafikkomponent. Wann eng Neiberechnung ufenkt, gëtt en Thread erstallt dee fir dës Unzuel un Deeg leeft. Wann de Wäert ze kleng ass, kann den Thread net an der gewënschter Zäit faerdeg ginn an et kënnt zu engem Lag. Wann de Wäert méi héich gesat gëtt, brauch d'Distributioun méi lang fir erneiert ze ginn wann eng Streck ännert STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manuell STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asymmetresch STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetresch STR_CONFIG_SETTING_DISTRIBUTION_PAX :Distributiounsmodus fir Passagéier: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"symmetresch" heescht, dass ongeféier d'selwecht vill Passagéier vun A op B wéi vu B op A geschéckt ginn. "asymmetresch" heescht, dass eng arbiträr Unzuel u Wueren an d'jeweileg Richtung geschéckt ginn. "manuell" heescht dass keng automatësch Distributioun stattfënnt fir Passagéier STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Distributiounsmodus fir Post: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"symmetresch" heescht, dass ongeféier d'selwecht vill vun A op B wéi vu B op A geschéckt ginn. "asymmetresch" heescht, dass eng arbiträr Unzuel u Wueren an d'jeweileg Richtung geschéckt ginn. "manuell" heescht dass keng automatësch Distributioun stattfënnt fir Post STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Distributiounsmodus fir d'GEPANZERT Wuereklass: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :D'GEPANZERT Wuereklass huet Wäertsaachen am geméissegte Klima, Diamanten am Sub-Tropenklima an Gold am sub-arktësche Klima. NewGRFen kënnen dat änneren. "Symmetrësch" heescht, dass ongeféier d'selwecht vill vun A op B wéi vu B op A geschéckt ginn. "asymmetrësch" heescht, dass eng arbiträr Unzuel u Wueren an d'jeweileg Richtung geschéckt ginn. "manuell" heescht dass keng automatësch Distributioun stattfënnt. Et gëtt emfuelen dëst op asymmetrësch oder manuell ze loossen wann ee sub-arktësch spillt, well Banken kee Gold zréck an d’Minen liwweren. Fir geméissegt Klima an sub-tropësch Klima kann eng Bank mat der anerer Wäertsachen zeréckschécken. STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Distributiounsmodus fir aner Wuerenklassen: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asymmetresch" heescht dass eng beléiweg Unzuel un Wueren an béid Richtungen verschéckt ginn. "manuell" heescht dass keng automatësch Distributioun stattfënnt. Meeschtens gëtt "asymmetresch" oder manuell gewielt. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Distributiounsgenauegkeet: {STRING} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Wat de Wäert méi héich ass, wat méi CPU benotzt gëtt fir d'Linkgrafik ze zeechnen. Wann ze héich gesat, kann et zu Lags kommen. Ze niddreg gesat kann d'Distributioun ongenau ginn an d'Wueren net sou verdeelt ginn wéi geduet STR_CONFIG_SETTING_DEMAND_DISTANCE :Afloss vun der Distanz op d'Nofro: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Wann's de en méi héije Wäert wéi 0 wiels, huet d'Differenz tëscht 2 Statiounen A an B en Afloss dorop wéivill Wueren geschéckt ginn. Wat B méi wäit ewech vun A ass, wat manner Wueren geschéckt ginn. Wat de Wäert méi héich gesat gëtt, wat manner Wueren op eng Statioun wait ewech an méi Wueren op eng Statioun méi no geschéckt ginn. STR_CONFIG_SETTING_DEMAND_SIZE :Unzuel vun zeréckgeschéckte Wueren fir de symmetreschen Modus: {STRING} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Wann een dëst op manner wéi 100% setzt, gëtt déi symmetresch Distributioun méi wéi eng asymmetrësch behandelt. Manner Wueren ginn zeréckgeschéckt wann en bestëmmten Wäert op eng Statioun geschéckt gouf. Bei 0% verhält sech d'symmetresch Distributioun wéi eng asymmetresch STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Sättegung vu kuerzen Weeër befier grouss Weeër benotzt ginn: {STRING} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Oft gëtt et e puer Weeër tëscht zwou Statiounen. Cargodist siedegt fir d'éischt de kierzten, dann den zweetkierzten a.s.w. Siedegung gëtt bestemmt durch Kapazitéit an geplangten Notzung. Wann all Wee gesiedegt ass, an nach emmer eng Nofro do ass, ginn all d'Weeër iwwersiedegt, mat Präferenz déi mat grousser Kapazitéit. Gréissten Deel vun der Zäit rechent den Algorithmus d'Kapazitéit allerdéngs net richteg. Des Astellung erlabt engem en Prozentsaz ze bestëmmen fir den éischten Wee befier en zweeten Wee benotzt gëtt. Setz en enner 100% fir iwwerfëllten Statiounen ze vermeide wann d'Kapazitéit iwwerschat gouf. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Geschwindegkeetseenheeten: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Emmer wann eng Geschwindegkeet am Userinterface ugewisen gëtt, weis se an den ausgewielten Eenheeten un STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Britesch (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metresch (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Kraafteenheeten: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Emmer wann d'Kraaft vun engem Gefier am Userinterface ugewisen gëtt, weis se an den ausgewielten Eenheeten un STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Britesch (PS) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metresch (PS) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Gewichtseenheeten: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Emmer wann Gewiichter am Userinterface ugewisen ginn, weis se an den ausgewielten Eenheeten un STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Britesch (kuerz t/Tonn) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metresch (t/Tonn) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Volumeneenheeten: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Emmer wann Volumen am Userinterface ugewisen ginn, weis se an den ausgewielten Eenheeten un STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Britesch (gal) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metresch (l) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Zuchkraaft Eenheeten: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Emmer wann eng Zuchkraaft am Userinterface ugewisen gëtt, weis se an den ugewielten Eenheeten un STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Britesch (lbf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metresch (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Héichteneenheeten: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Emmer wann Héichten am Userinterface ugewisen ginn, weis se an den ausgewielten Eenheeten un STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Britesch (ft) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metresch (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Lokaliséirung STR_CONFIG_SETTING_GRAPHICS :{ORANGE}Grafik STR_CONFIG_SETTING_SOUND :{ORANGE}Soundeffekter STR_CONFIG_SETTING_INTERFACE :{ORANGE}Interface STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE}Generell STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Usiicht STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Konstruktioun STR_CONFIG_SETTING_ADVISORS :{ORANGE}News / Meldungen STR_CONFIG_SETTING_COMPANY :{ORANGE}Firma STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Compta STR_CONFIG_SETTING_VEHICLES :{ORANGE}Gefierer STR_CONFIG_SETTING_VEHICLES_PHYSICS :{ORANGE}Physik STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Routeplangung STR_CONFIG_SETTING_LIMITATIONS :{ORANGE}Limitatiounen STR_CONFIG_SETTING_ACCIDENTS :{ORANGE}Katastrophen / Akzidenter STR_CONFIG_SETTING_GENWORLD :{ORANGE}Welt Generatioun STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}Emwelt STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :{ORANGE}Autoritéiten STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}Stied STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Industrien STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Wuereverdeelung STR_CONFIG_SETTING_AI :{ORANGE}Géigner STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computerspiller STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(recommandéiert) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Pfadfinder fir Zich: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Pfadfinder dee fir Zich benotzt gëtt STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Pfadfinder fir Stroossegefierer: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Pfadfinder dee fir Gefierer benotzt gëtt STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Pfadfinder fir Schëffer: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Pfadfinder dee fir Schëffer benotzt gëtt STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Automatescht Emdréinen bei Signaler: {STRING} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Erlab Zich bei engem Signal emzedréinen, wann se eng laang Zäit geward hunn STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Astellung änneren # Config errors STR_CONFIG_ERROR :{WHITE}Fehler mat der Konfiguratiounsdatei... STR_CONFIG_ERROR_ARRAY :{WHITE}... Fehler am Array '{STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... falsche Wäert '{STRING}' fir '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... Trailing-characters um Enn vun der Astellung '{STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignoréiren NewGRF '{STRING}': Duplikat-GRF ID wéi '{STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignoréiren ongültëgen NewGRF '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :net fonnt STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :onsécher fir statesche Gebrauch STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :System NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :net mat dëser Versioun vun OpenTTD kompatibel STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :onbekannt STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... Kompressiounslevel '{STRING}' ass net gültëg. STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... Spillstand format '{STRING}' gëtt et net. Revertéiren zu '{STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignoréiren Basis Grafik Set '{STRING}': net fonnt STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignoréiren Basis Sound Set '{STRING}': net fonnt STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignoréiren Basis Musik Set '{STRING}': net fonnt STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Net genuch Mémoire STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Reservéirung vun {BYTES} Spritecache versot. De Spritecache gouf reduzéiert op {BYTES}. Dëst reduzéiert d'Performance vun OpenTTD. Fir Späicher ze spueren kann een probéiren 32bpp Grafiken auszeschalten an/oder Zoom-Eran Stufen # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}Neit Spill STR_INTRO_LOAD_GAME :{BLACK}Spill lueden STR_INTRO_PLAY_SCENARIO :{BLACK}Szenario spillen STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Héichtekaart spillen STR_INTRO_SCENARIO_EDITOR :{BLACK}Szenarien Editor STR_INTRO_MULTIPLAYER :{BLACK}Multiplayer STR_INTRO_GAME_OPTIONS :{BLACK}Spilloptiounen STR_INTRO_HIGHSCORE :{BLACK}Beschtelëscht STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Astellungen STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Astellungen STR_INTRO_ONLINE_CONTENT :{BLACK}Check Online Inhalt STR_INTRO_SCRIPT_SETTINGS :{BLACK}KI / Spill-Script Astellungen STR_INTRO_QUIT :{BLACK}Eraus STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Start en neit Spill. Ctrl+Klick iwwerspréngt Kaartenkonfiguratioun STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Spill lueden STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Nei Partie starten, mat enger Héichtekaart als Landschaft STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Start eng nei Partie, mat engem eegenen Szenario STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Erstell eng eegen Spillwelt/Szenario STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Start en Multiplayer-Spill STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Wielt de Landschaftsstil 'temperéiert' STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Wielt de Landschaftsstil 'sub-arktesch' STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Wielt de Landschaftsstil 'sub-tropesch' STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Wielt de Landschaftsstil 'Spillsaacheland' STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Spilloptiounen STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Beschtelëscht uweisen STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Displayastellungen STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}NewGRF Astellungen uweisen STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Check op neien Inhalt kann downgeload gin STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Weis KI an Spill-Script-Astellungen STR_INTRO_TOOLTIP_QUIT :{BLACK}Aus 'OpenTTD' eraus goen STR_INTRO_TRANSLATION :{BLACK}Dës Iwwersetzung huet {NUM} String{P "" s}. Hëllef OpenTTD besser ze man andems du dech als Iwwersetzer mells! Lies readme.txt fir d'Detailer. # Quit window STR_QUIT_CAPTION :{WHITE}Eraus STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Bass du sécher, dass du aus OpenTTD eraus wëlls, an an den {STRING} zeréck? STR_QUIT_YES :{BLACK}Jo STR_QUIT_NO :{BLACK}Nee # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Spill ofbriechen STR_ABANDON_GAME_QUERY :{YELLOW}Bass du sécher dass du des Partie ofbrieche wëlls? STR_ABANDON_SCENARIO_QUERY :{YELLOW}Sécher dass du aus dësem Szenario eraus wëlls ? # Cheat window STR_CHEATS :{WHITE}Cheater STR_CHEATS_TOOLTIP :{BLACK}Checkboxen weisen un dass du den Cheat schon eng Kéier benotzt hues STR_CHEATS_WARNING :{BLACK}Warnung! Du bass um Wee de Géigner ze verroden. Sou eng Ongnod gëtt bis an all Éiwegkeet behalen STR_CHEAT_MONEY :{LTBLUE}Suen ëm {CURRENCY_LONG} erhéijen STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Als Firma {ORANGE}{COMMA} spillen STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magësche Bulldozer (Industrien ofrappen, onzerstéierbar Objeten): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tunnelle kënne sech kräizen: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Jet'en maachen net regelméisseg en Akzident op klenge Fluchhäfen: {ORANGE} {STRING} STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Änner d'Maximalhéicht vu Bierger op der Kaart: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Änner d'Maximalhéicht vu Bierger op der Kaart STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Gemässegt Klima Landschaft STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Sub-Arktesch Landschaft STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Sub-Tropesch Landschaft STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Spillsaacheland Landschaft STR_CHEAT_CHANGE_DATE :{LTBLUE}Datum wiesselen: {ORANGE} {DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Wiessel d'aktuellt Joer STR_CHEAT_SETUP_PROD :{LTBLUE}Erlaabt d'ännere vun de Produktiounswäerter: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}Neie Faarfschema STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Weis generell Faarfschemen STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Weis Zuch Faarfschemen STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Weis Stroossegefierer Faarfschemen STR_LIVERY_SHIP_TOOLTIP :{BLACK}Weis d'Schëff Faarfschemen STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Weis Fliger Faarfschemen STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Wiel d'Primärfaarf fir den ausgewieltene Schema. Ctrl+Klick wielt dës Faarf fir all Schema STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Wiel d'Sekundärfaarf fir den ausgewieltenen Schema. Ctrl+Klick wielt dës Faarf fir all Schema STR_LIVERY_PANEL_TOOLTIP :{BLACK}Wiel en Faarfschema fir ze änneren, oder e puer Schemen mat Ctrl+Klick. Klick op d'Këscht fir d'Schemanotzung ze wiesselen STR_LIVERY_DEFAULT :Standard Firmefaarwen STR_LIVERY_STEAM :Damplok STR_LIVERY_DIESEL :Diesellok STR_LIVERY_ELECTRIC :Elektrolok STR_LIVERY_MONORAIL :Monorail Lok STR_LIVERY_MAGLEV :Magnéitbunnlok STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Passagéierwaggon (Damp) STR_LIVERY_PASSENGER_WAGON_DIESEL :Passagéierwaggon (Diesel) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Passagéierwaggon (Elektresch) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Passagéierwaggon (Monorail) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Passagéierwaggon (Magnéitbunn) STR_LIVERY_FREIGHT_WAGON :Gidderwaggon STR_LIVERY_BUS :Bus STR_LIVERY_TRUCK :Camion STR_LIVERY_PASSENGER_SHIP :Passagéierfähr STR_LIVERY_FREIGHT_SHIP :Frachtschëff STR_LIVERY_HELICOPTER :Helikopter STR_LIVERY_SMALL_PLANE :Klenge Fliger STR_LIVERY_LARGE_PLANE :Grousse Fliger STR_LIVERY_PASSENGER_TRAM :Passagéiertram STR_LIVERY_FREIGHT_TRAM :Wuerentram # Face selection window STR_FACE_CAPTION :{WHITE}Gesiichtsauswiel STR_FACE_CANCEL_TOOLTIP :{BLACK}Briech d'Auswiel vum Gesiicht of STR_FACE_OK_TOOLTIP :{BLACK}Neit Gesiicht akzeptéieren STR_FACE_RANDOM :{BLACK}Duercherneen wierfelen STR_FACE_MALE_BUTTON :{BLACK}Männlech STR_FACE_MALE_TOOLTIP :{BLACK}Wielt männlech Gesiichter STR_FACE_FEMALE_BUTTON :{BLACK}Weiblech STR_FACE_FEMALE_TOOLTIP :{BLACK}Wielt weiblech Gesiichter STR_FACE_NEW_FACE_BUTTON :{BLACK}Neit Gesiicht STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Generéiert zoufällegt neit Gesiicht STR_FACE_ADVANCED :{BLACK}Erweidert STR_FACE_ADVANCED_TOOLTIP :{BLACK}Erweidert Gesiichtsauswiel STR_FACE_SIMPLE :{BLACK}Einfach STR_FACE_SIMPLE_TOOLTIP :{BLACK}Einfach Gesiichtsauswiel STR_FACE_LOAD :{BLACK}Lueden STR_FACE_LOAD_TOOLTIP :{BLACK}Favoriséiert Gesiicht lueden STR_FACE_LOAD_DONE :{WHITE}Äert favoriséiert Gesiicht ass aus der OpenTTD Konfiguratiounsdatei geluede ginn. STR_FACE_FACECODE :{BLACK}Gesiicht N°. STR_FACE_FACECODE_TOOLTIP :{BLACK}Kuckt an wielt d'Gesiichtsnummer vum Firmepresident STR_FACE_FACECODE_CAPTION :{WHITE}Kuckt an wielt d'Gesiichtsnummer STR_FACE_FACECODE_SET :{WHITE}Nei Gesiichtsnummer ass agestallt ginn STR_FACE_FACECODE_ERR :{WHITE}Konnt d'Gesiichtsnummer net setzen - muss en numereschen Wäert tëscht 0 an 4,294,967,295 sinn! STR_FACE_SAVE :{BLACK}Späicheren STR_FACE_SAVE_TOOLTIP :{BLACK}Späichert favoriséiert Gesiicht STR_FACE_SAVE_DONE :{WHITE}Dëst Gesiicht gëtt als favoriséiert an der OpenTTD Konfiguratiounsdatei gespäichert. STR_FACE_EUROPEAN :{BLACK}Europäesch STR_FACE_SELECT_EUROPEAN :{BLACK}Wielt europäesch Gesiichter STR_FACE_AFRICAN :{BLACK}Afrikanesch STR_FACE_SELECT_AFRICAN :{BLACK}Wielt afrikanesch Gesiichter STR_FACE_YES :Jo STR_FACE_NO :Nee STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Schalt Schnauz oder Ouerréng un STR_FACE_HAIR :Hoer: STR_FACE_HAIR_TOOLTIP :{BLACK}Hoer änneren STR_FACE_EYEBROWS :Aperhoer: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Apenhoer änneren STR_FACE_EYECOLOUR :Aafaarf: STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Aafaarf änneren STR_FACE_GLASSES :Brëll: STR_FACE_GLASSES_TOOLTIP :{BLACK}Brëll aschalten STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Brëll änneren STR_FACE_NOSE :Nues: STR_FACE_NOSE_TOOLTIP :{BLACK}Nues änneren STR_FACE_LIPS :Lëpsen: STR_FACE_MOUSTACHE :Schnauz: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Lëpsen oder Schnauz änneren STR_FACE_CHIN :Kënn: STR_FACE_CHIN_TOOLTIP :{BLACK}Kënn änneren STR_FACE_JACKET :Paltong: STR_FACE_JACKET_TOOLTIP :{BLACK}Paltong änneren STR_FACE_COLLAR :Halsband: STR_FACE_COLLAR_TOOLTIP :{BLACK}Halsband änneren STR_FACE_TIE :Krawatt: STR_FACE_EARRING :Ouerréng: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Krawatt oder Ouerréng änneren # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Ugekënnegt STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Wiel tëschent engem ugekënnegten (Internet) an net ugekënnegten (LAN) Spill STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Nee STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Jo STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spillernumm: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Daat ass den Numm mat deem iech déi aner Spiller Identifizéieren kënnen STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Numm STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Numm vum Spill STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Spiller STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Spiller online / max Spiller{}Firmen online / max Firmen STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Kaartegréisst STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Kaartegréisst vum Spill{}Klicken fir dorop ze sortéieren STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Datum STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Momentanen Datum STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Joer STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Unzuel u Joer wou{}daat Spill leeft STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Sprooch, Serverversioun, etc. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Klick op en Spill aus der Lëscht fir et auszewielen STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Server deems du d'leschte Kéier bäigetruede bass: STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Klick fir de Server ze wielen deens du d'leschte Kéier haas STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}SPILL INFO STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Spiller: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Sprooch: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Landschaft: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Kaartegréisst: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Serverversioun: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Serveradress: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Startdatum: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Momentanen Datum: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Passwuertgeschützt! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVER OFFLINE STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}SERVER VOLL STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}VERSIOUNSËNNERSCHEED STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF ËNNERSCHEEDLECH STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Spill bäitrieden STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Server erneieren STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Serverinfo erneieren STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Server sichen STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Am Netzwierk no engem Server sichen STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Server bäisetzen STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Setzt en Server op d'Lëscht wou ëmmer no enger Partie gesicht gëtt STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Server starten STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Eegenen Server starten STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Gëff däin Numm an STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}D'Address vum Host uginn # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}Nei Multiplayerpartie starten STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Spillnumm: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Den Numm deen an der Lëscht vun de Spiller ugewisen gëtt STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Passwuert setzen STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}En Passwuert fir d'Spill setzen, dass et net Public accessibel ass STR_NETWORK_START_SERVER_UNADVERTISED :Nee STR_NETWORK_START_SERVER_ADVERTISED :Jo STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} Spiller STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximal Spiller: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Maximal Unzuel vun de Clients. Et muss net all Slot gefëllt sinn. STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} Firm{P a en} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Maximal Firmen: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}D'Unzuel vun de Firme limitéieren STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} Zuschauer STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Maximal Zuschauer: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}D'Unzuel vun den Zuschauer limitéiren STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Geschwate Sprooch: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Aner Leit gesinn wéieng Sprooch um Server geschwat gëtt STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Gëff en Numm fir d'Spill un # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :Egal STR_NETWORK_LANG_ENGLISH :Englesch STR_NETWORK_LANG_GERMAN :Däitsch STR_NETWORK_LANG_FRENCH :Franséisch STR_NETWORK_LANG_BRAZILIAN :Brasilianesch STR_NETWORK_LANG_BULGARIAN :Bulgaresch STR_NETWORK_LANG_CHINESE :Chinesesch STR_NETWORK_LANG_CZECH :Tschechesch STR_NETWORK_LANG_DANISH :Dänesch STR_NETWORK_LANG_DUTCH :Holländesch STR_NETWORK_LANG_ESPERANTO :Esperanto STR_NETWORK_LANG_FINNISH :Finnesch STR_NETWORK_LANG_HUNGARIAN :Ungaresch STR_NETWORK_LANG_ICELANDIC :Isländesch STR_NETWORK_LANG_ITALIAN :Italienesch STR_NETWORK_LANG_JAPANESE :Japanesch STR_NETWORK_LANG_KOREAN :Koreanesch STR_NETWORK_LANG_LITHUANIAN :Litauesch STR_NETWORK_LANG_NORWEGIAN :Norwegesch STR_NETWORK_LANG_POLISH :Polnesch STR_NETWORK_LANG_PORTUGUESE :Portugiesesch STR_NETWORK_LANG_ROMANIAN :Rumänesch STR_NETWORK_LANG_RUSSIAN :Russesch STR_NETWORK_LANG_SLOVAK :Slovakesch STR_NETWORK_LANG_SLOVENIAN :Slovenesch STR_NETWORK_LANG_SPANISH :Spuenesch STR_NETWORK_LANG_SWEDISH :Schwedesch STR_NETWORK_LANG_TURKISH :Türkesch STR_NETWORK_LANG_UKRAINIAN :Ukrainesch STR_NETWORK_LANG_AFRIKAANS :Afrikaans STR_NETWORK_LANG_CROATIAN :Kroatesch STR_NETWORK_LANG_CATALAN :Katalanesch STR_NETWORK_LANG_ESTONIAN :Estnesch STR_NETWORK_LANG_GALICIAN :Gälesch STR_NETWORK_LANG_GREEK :Griechesch STR_NETWORK_LANG_LATVIAN :Lettesch ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer-Spill Lobby STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Preparéiert fir bäizetrieden: {ORANGE}{STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}Eng Lëscht vun de Firmen an dësem Spill. Du kanns enger bäitrieden oder eng nei opmaachen. STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}FIRMENINFO STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Firmennumm: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Grënnung: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Firmewäert: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Kontostand: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Akommes vum leschte Joer: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Performance: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Gefierer: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Statiounen: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Spiller: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}Nei Firma STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Nei Firma erstellen STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Dem Spill nokucken STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Dem Spill als Zuschauer nokucken STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Firma bäitrieden STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Des Firma matverwalten # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}Connectioun... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Connectéiert... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Authoriséiert... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Waarden... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Kaart eroflueden... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Daten verarbëschten... STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Registréierung... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Ruffen d'Spillinfo of.. STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Ruffen d'Firmeninfos of... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} Spiller firun dir STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} souwäit erofgelueden STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} erofgelueden STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Verbindung trennen STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server ass geschützt. Passwuert aginn STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Firma ass geschützt. Passwuert aginn # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Spillerlëscht STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Nokucken STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}Nei Firma # Network client list STR_NETWORK_CLIENTLIST_KICK :Kicken STR_NETWORK_CLIENTLIST_BAN :Bannen STR_NETWORK_CLIENTLIST_GIVE_MONEY :Sue ginn STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Mat alle schwetzen STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Mat der Firma schwetzen STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privatmessage STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Spiller STR_NETWORK_SPECTATORS :Zuschauer STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Gëff de Betrag un deens du wëlls ginn STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Zuschauer # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Späicher d'Passwuert net STR_COMPANY_PASSWORD_OK :{BLACK}Benotz daat neit Passwuert fir d'Firma STR_COMPANY_PASSWORD_CAPTION :{WHITE}Firme-Passwuert STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Standard Firme-Passwuert STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Benotzt dëst Passwuert als Standard fir nei Firmen # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}Bäitrieden STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Bäitrieden an mat deser Firma spillen STR_COMPANY_VIEW_PASSWORD :{BLACK}Passwuert STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Setzt en Passwuert fir nëmmen authoriséiert Benotzer spillen ze loossen STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Setzt d'Firmen-Passwuert # Network chat STR_NETWORK_CHAT_SEND :{BLACK}Ofschécken STR_NETWORK_CHAT_COMPANY_CAPTION :[Team] : STR_NETWORK_CHAT_CLIENT_CAPTION :[Privat] {STRING}: STR_NETWORK_CHAT_ALL_CAPTION :[All] : STR_NETWORK_CHAT_COMPANY :[Team] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_COMPANY :[Team] Un: {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_CLIENT :[Privat] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_CLIENT :[Privat] Un: {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_ALL :[All] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}Text fir Chat aginn # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Keng Netzwierkgeräter fonnt oder compiléiert ouni ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}Konnt keng Netzwierkspiller fannen STR_NETWORK_ERROR_NOCONNECTION :{WHITE}De Server huet net op d'Ufro geäntwert STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Konnt sech wéinst ënnerscheedlechen NewGRF net connectéieren STR_NETWORK_ERROR_DESYNC :{WHITE}Netzwierksyncronisatiouns-Fehler STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Netzwierkverbindung verluer STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Konnt de Spillstand net lueden STR_NETWORK_ERROR_SERVER_START :{WHITE}Konnt de Server net starten STR_NETWORK_ERROR_CLIENT_START :{WHITE}Konnt sech net connectéieren STR_NETWORK_ERROR_TIMEOUT :{WHITE}Connectioun #{NUM} ofgelaaf STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}En Protokolfehler ass entstaanen an d'Connectioun ass getrennt ginn STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}D'Versioun vum Client stëmmt net mat däer vum Server iwwereneen STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Falscht Passwuert STR_NETWORK_ERROR_SERVER_FULL :{WHITE}De Server ass voll STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Du bass vun dësem Server gebannt STR_NETWORK_ERROR_KICKED :{WHITE}Du goufs aus dem Spill geheit STR_NETWORK_ERROR_CHEATER :{WHITE}Cheaten ass op dësem Server net erlaabt STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Du hues zevill Befehler un de Server geschéckt STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Du hues ze laang gebraucht fir e Passwuert anzeginn STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Däin Computer brauch ze laang fir bäizetrieden STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Du hues ze laang gebraucht fir d'Kaart rofzelueden STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Du hues ze laang gebraucht fir dem Server bäizetrieden ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :generellen Fehler STR_NETWORK_ERROR_CLIENT_DESYNC :desync Fehler STR_NETWORK_ERROR_CLIENT_SAVEGAME :konnt d'Kaart net lueden STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :Connectioun verluer STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :Protokollfehler STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF ënnerscheedlech STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :net authoriséiert STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :invaliden oder onerwaarte Packet kritt STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :Falsch Versioun STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :Numm gëtt schon benotzt STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :falscht Passwuert STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :falsch Firmen-ID am "DoCommand" STR_NETWORK_ERROR_CLIENT_KICKED :vum Server gekickt STR_NETWORK_ERROR_CLIENT_CHEATER :huet probéiert ze cheaten STR_NETWORK_ERROR_CLIENT_SERVER_FULL :Server voll STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :huet zevill Befehler geschéckt STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :krut keen Passwuert mat Zäit STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :generellen Timeout STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :Kaart rofzelueden huet ze laang gedauert STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :Kaart ze verarbëschten huet ze laang gedauert ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Méiglechen Verbindungsverloscht STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}Déi lescht {NUM} Sekonnen{P "" s} sinn keng Daten vum Server komm # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Spill pauséiert ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Spill nach ëmmer pauséiert ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Spill nach ëmmer pauséiert ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Spill nach ëmmer pauséiert ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Spill nach pauséiert ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Spill geet weider ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :Unzuel Spiller STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :Spiller verbannen STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manuell STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :Spill-Script ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :verloossen STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} ass dem Spill bäigetrueden STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} ass an d'Spill komm (Client #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} ass bei d'Firma #{2:NUM} gaangen STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} ass als Zuschauer do STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} huet eng nei Firma gegrënnt (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} huet d'Spill verlooss ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} huet säin Numm op {STRING} gewiesselt STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} huet ärer Firma {2:CURRENCY_LONG} ginn STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Du hues dem {1:STRING} {2:CURRENCY_LONG} ginn STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}De Server huet d'Sessioun zougemaach STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}De Server gëtt nei gestart...{}W.e.g. waarden... # Content downloading window STR_CONTENT_TITLE :{WHITE}Lueden Inhalt erof STR_CONTENT_TYPE_CAPTION :{BLACK}Typ STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Typ vum Inhalt STR_CONTENT_NAME_CAPTION :{BLACK}Numm STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Numm vum Inhalt STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Klick op eng Linn fir Detailer{}Klick Checkbox fir et downzeloaden STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Alles uwielen STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Wiel all Inhalt fir den Download STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Upgrades uwielen STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Markéier all Inhalt,den en Upgrade fir existéirenden Inhalt ass als Download STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Alles ofwielen STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Alles markéiren fir net downzeloaden STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Extern Websäiten durchsichen STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Sich Inhalter déi net op der OpenTTD Downloadwebsäit stin op aneren Websäiten STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Du verléiss OpenTTD! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}Terms and conditions fir Inhalter vun externe Websäiten ze downloade goufe geännert.{}Du muss op där Säit nokucken wéi een den Inhalt installéiert.{}Wellsde weiderman? STR_CONTENT_FILTER_TITLE :{BLACK}Tag-/Nummfilter: STR_CONTENT_OPEN_URL :{BLACK}Websäit besichen STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Besicht d'Websäit vun dësem Inhalt STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Download STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Start den Download vum ausgewielten Inhalt STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Total Downloadgréisst: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}INFO STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Dest gouf net fir den Download gewielt STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Du hues dest fir den Download gewielt STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Des Ofhängegkeet gouf ausgewielt fir den Download STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Du hues dest schon STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}Dësen Inhalt ass net bekannt an kann net an OpenTTD downgeload ginn STR_CONTENT_DETAIL_UPDATE :{SILVER}Dest ass en Austausch fir en existent/en {STRING} STR_CONTENT_DETAIL_NAME :{SILVER}Numm: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Versioun: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Beschreiwung: {WHITE}{STRING} STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}Typ: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}Downloadgréisst: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Ausgewielt wéinst: {WHITE}{STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Ofhängegkeeten: {WHITE}{STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Tags: {WHITE}{STRING} STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD ass ouni "zlib" Support compiléiert... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... Inhalt eroflueden ass net méiglech! # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :Standard Grafiken STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :KI STR_CONTENT_TYPE_AI_LIBRARY :KI Librairie STR_CONTENT_TYPE_SCENARIO :Szenario STR_CONTENT_TYPE_HEIGHTMAP :Héischtekaart STR_CONTENT_TYPE_BASE_SOUNDS :Basis Sounds STR_CONTENT_TYPE_BASE_MUSIC :Basis Musik STR_CONTENT_TYPE_GAME_SCRIPT :Spill-Script STR_CONTENT_TYPE_GS_LIBRARY :GS Librairie # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Lueden Inhalt erof... STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Froen Daten un... STR_CONTENT_DOWNLOAD_FILE :{WHITE}Lueden grad {STRING} erof. ({NUM} vun {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Download fäerdeg STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} vun {BYTES} downgeload ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Konnt net op de Contentserver konnektéiren... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Download mësslong... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... Connectioun verluer STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... Datei net beschreiwbar STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Konnt d'erofgelueden Datei net dekompriméiren STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Fehlend Grafiken STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD brauch Grafiken fir ze funktionéiren, mee et konnten keng fonnt ginn. Wëllsde OpenTTD se downloaden an installéiren loossen ? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Jo, download d'Grafiken STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Nee, verlooss OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Transparenzoptiounen STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Schëlder. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Beem. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Haiser. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Industrien. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Firmegebaier. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Brécken. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Gebaier wéi d'Liichttierm oder Antennen. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Catenaire. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Wiesselt d'Transparenz fir d'Luedungsindikatoren. Ctrl+Klick fir festzesetzen STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Setzt d'Objeten op onsichtbar amplaz transparent # Linkgraph legend window STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Cargo Flow Legend STR_LINKGRAPH_LEGEND_ALL :{BLACK}All STR_LINKGRAPH_LEGEND_NONE :{BLACK}Keng STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Wiel d'Firmen aus déi ugewise ginn # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}onbenotzt STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}gesättegt STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}iwwerlaascht # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Reechwäit markéieren STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Aus STR_STATION_BUILD_COVERAGE_ON :{BLACK}Un STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Weis d'Reechwäit vun dem Gebäi net un STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Weis d'Reechwäit vun dem Gebäi un STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Akzeptéiert: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Liwwert: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Statioun verbannen STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Eng separat Statioun bauen STR_JOIN_WAYPOINT_CAPTION :{WHITE}Weepunkt verbannen STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Separate Weepunkt bauen # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Schinnebau STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Elektresche Schinnebau STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Monorailbau STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Magnéitbunnbau STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Schinne bauen. Ctrl wiesselt tëscht bauen/ofrappen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Schinnen am automatesche Modus bauen. Ctrl wiesselt tëscht bauen/ofrappen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Zuchschapp bauen (fir Zich ze kafen an ze flécken). Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Konvertéiert d'Schinnen zum Weepunkt. Ctrl aktivéiert Weepunkter ze verbannen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Gare bauen. Ctrl aktivéiert fir d'Statioun unzebauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Zuchsignaler bauen. Ctrl wiesselt tëscht Diks/Luuten{}Zéien baut Signaler laanscht eng Zuchstreck. Ctrl baut Signaler bis déi nächst Weich{}Ctrl+Klick mécht Auswielfënster op.Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Zuchbréck bauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Zuchtunnel bauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Wiesselt tëscht bauen/ofrappe vu Schinnen, Signaler a Statiounen. Ctrl unhale rappt och Schinne vu Weepunkter a Statiounen of STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Konvertéiert/upgrade den Typ vu Schinnen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_RAIL_NAME_RAILROAD :Schinnen STR_RAIL_NAME_ELRAIL :Elektresch Schinnen STR_RAIL_NAME_MONORAIL :Monorail STR_RAIL_NAME_MAGLEV :Magnéitbunn # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Richtung vum Zuchschapp STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Wielt d'Richtung vum Zuchschapp # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Weepunkt STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Wielt de Weepunktyp # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Gare Auswiel STR_STATION_BUILD_ORIENTATION :{BLACK}Richtung STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Wielt d'Richtung vun der Gare STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Unzuel vu Schinnen STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Wielt d'Unzuel vun de Gleisen fir d'Gare STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Plattformlängt STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Wielt d'Längt vun der Gare STR_STATION_BUILD_DRAG_DROP :{BLACK}Drag & Drop STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}D'Statioun per drag & drop bauen STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Wielt eng Statiounsklass déi ugewise gëtt STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Wielt den Typ vu Statioun dee gebaut gëtt STR_STATION_CLASS_DFLT :Standard Statioun STR_STATION_CLASS_WAYP :Weepunkten # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Signalauswiel STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Block Signal (Diks){} Dest ass e Basis-Signal, wat nëmmen engem Zuch zur selwechter Zait erlaabt an engem Block ze sinn STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Agangs-Signal (Diks){}Gréng soulaang een oder méi gréng Ausgangs-Signaler op dem nächsten Streckenabschnitt sinn. Anescht ass et rout. STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Ausgangs-Signal (Diks){}Verhält sech wéi en Block-Signal mee gëtt gebraucht fir déi korrekt Faarf ob Agangs- an Combo-Pre-Signaler ze setzen STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Combo-Signal (Diks){}E Combo-Signal agéiert wéi en Agangs- a wéi en Ausgangs-Signal. Dest erlaabt engem vill "Beem" vu Pre-Signaler ze bauen STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Wee-Signal (Diks){}E Wee-Signal erlaabt méi wéi engem Zuch an en Block ze fueren zur selweschter Zäit, wann den Zuch en Wee op en sécheren Stop-Punkt kann reservéiren. Standard Wee-Signaler kënne vu béide Säiten duerchfuer ginn STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}Einbahn-Wee-Signal (Diks){}E Wee-Signal erlaabt méi wéi engem Zuch an en Block ze fueren zur selweschter Zäit, wann den Zuch en Wee op en sécheren Stop-Punkt kann reservéiren. Einbahn-Wee-Signaler kënnen net de falsche Wee duerchfuer ginn STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Block Signal (Elektresch){}Dest ass e Basis-Signal, mat dem een en Zuch an engem selwechten Block zur selwechter Zäit erlaabt STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Agangs-Signal (Elektresch){}Gréng soulaang een oder méi gréng Ausgangssignaler vum nächsten Streckenabschnitt kommen. Anescht ass et rout STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Ausgangs-Signal (Elektresch){}Verhält sech wéi e Block-Signal mee gëtt gebraucht fir déi korrekt Faarf vun den Agangs- an Combo Pre-Signaler ze setzen STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Combo-Signal (Elektresch){}D'Combo-Signal ass einfach en An- an Ausgangssignal. Dëst erlaabt grouss "Beem" Presignaler ze bauen STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Wee-Signal (Elektresch){}E Wee-Signal erlaabt méi wéi engem Zuch an e Block eranzefueren, wann den Zuch e Wee op en Stop-Punkt reservéiren kann. Standard Wee-Signaler kënne vu béide Säiten duerchfuer ginn STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Einbahn-Wee-Signal (Elektresch){}En Einbahn-Signal erlaabt méi wéi een Zuch zur selwechter Zäit an engem Block ze sin, wann den Zuch en Wee op en sécheren Stop-Punkt reservéiren kann. Einbahn-Signaler kënnen net vun der falscher Säit duerchfuer ginn STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signal konvertéiren{}Wann gewielt, gëtt en geklickten Signal an dat gewielten Signal konvertéiert, Ctrl+Klick wiesselt tëscht de Varianten. Shift weist ongeféier Konvertéirungskäschten STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dicht vu Signaler beim Zéien STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Setzt Signaldicht erof STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Setzt Signaldicht erop # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Zuchbréck auswielen STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Stroossebréck auswielen STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Bréckenauswiel - Wiel deng Bréck aus STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :Stolen Hängebréck STR_BRIDGE_NAME_GIRDER_STEEL :Stoldréier Bréck STR_BRIDGE_NAME_CANTILEVER_STEEL :Fräidroend Stolbréck STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Betons Hängebréck STR_BRIDGE_NAME_WOODEN :Holze Bréck STR_BRIDGE_NAME_CONCRETE :Betons Bréck STR_BRIDGE_NAME_TUBULAR_STEEL :Rouerstol Bréck STR_BRIDGE_TUBULAR_SILICON :Rouer, Silikon # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Stroossebau STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tramkonstruktioun STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Baut Stroossen.Ctrl+Klick wiësselt tëscht Stroosse bauen/ofrappen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Tramschinne bauen. Ctrl+Klick wiësselt tëscht Tramschinne bauen/ofrappen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}D'Strooss mat der Bau-Automatik bauen. Ctrl wiësselt tëscht Stroossen bauen/ofrappen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Tramschinne mam "Autotram" Modus bauen. Ctrl wiesselt tëscht Tramschinne bauen/ofrappen. Shift wiesselt tëschtbauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Baut Stroossendepot (fir Gefierer ze kafen an ze flécken). Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Tramschapp bauen (fir Gefierer ze kafen an d'Revisioun). Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Baut Busarrêt. Ctrl aktivéiert ubaue vu Statiounen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Tramarrêt bauen. Ctrl aktivéiert ubaue vu Statiounen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Baut Camionsgare. Ctrl aktivéiert ubaue vu Statiounen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Wueren-Tramstatioun bauen. Ctrl aktivéiert ubaue vu Statiounen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Einbahnstroossen aktivéieren/déaktivéieren STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Baut Stroossebréck. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Tramsbréck bauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Baut Stroossentunnel. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Tramtunnel bauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Wiesselt bauen/ofrappen vu Stroossekonstruktiounen STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Wiesselt tëscht bauen/ofrappen beim Trambau # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Ausriichtung vum Stroossendepot STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Wielt d'Stroossendepot Ausriichtung STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Ausriichtung vum Tramschapp STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Tramschapp Ausriichtung wielen # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Ausriichtung vum Busarrêt STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Wielt Busarrêtsausriichtung STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Ausriichtung vun der Camionsgare STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Wielt d'Camionsgareausriichtung STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Ausriichtung vun dem Passagéier-Tramsarrêt STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Passagéier-Tramsarrêt Ausriichtung wielen STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Ausriichtung vun der Wueren-Tramstatioun STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Wueren-Tramstatioun Ausriichtung wielen # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Waasserstroosse bauen STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Waasserstroossen STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Kanäl bauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Schleise bauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Schëffsschapp bauen (fir Schëffer ze bauen an ze reparéiren). Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Schëffsquai bauen. Ctrl aktivéiert ubaue vu Statiounen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Plazéiert eng Boje, déi als Weepunkt kann benotzt ginn. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Aquadukt bauen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Waasserareal definéieren.{}Mécht en Kanal. Mat Ctrl gedréckt halen um Mieresspigel klicken, iwwerflut d'Géigent STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Plazéier Flëss # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Schëffsschapp Ausriichtung STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Wielt d'Ausriichtung vum Schëffsschapp # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Hafen # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Fluchhäfen STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Fluchhafe bauen. Ctrl aktivéiert ubaue vu Statiounen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Fluchhafen Auswiel STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Wielt Gréisst/Typ vum Fluchhafen STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Fluchhafeklass STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Layout {NUM} STR_AIRPORT_SMALL :Kleng STR_AIRPORT_CITY :City STR_AIRPORT_METRO :Metropole Fluchhafen STR_AIRPORT_INTERNATIONAL :Internationale Fluchhafen STR_AIRPORT_COMMUTER :Pendler STR_AIRPORT_INTERCONTINENTAL :Interkontinental STR_AIRPORT_HELIPORT :Heliport STR_AIRPORT_HELIDEPOT :Helidepot STR_AIRPORT_HELISTATION :Helistatioun STR_AIRPORT_CLASS_SMALL :Kleng Fluchhäfen STR_AIRPORT_CLASS_LARGE :Grouss Fluchhäfen STR_AIRPORT_CLASS_HUB :Fluchhafeverdeeler STR_AIRPORT_CLASS_HELIPORTS :Helikopter Fluchhafen STR_STATION_BUILD_NOISE :{BLACK}Kaméidi: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}Landschaftsbau STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}En Eck vum Land erofsetzen. Zéien setzt den éischten ugewielten Eck erof an planéiert d'ugewielten Land op déi nei Eckhéicht. Ctrl wielt d'Land diagonal. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}En Eck vum Land unhiewen. Zéien wielt den éischten Eck an planéiert d'ugewielten Land ob déi nei Eckhéicht. Ctrl wielt d'Land diagonal. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Land planéiren. Ctrl wielt d'Land diagonal aus. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Kaf Land fir zukünftëg Benotzung. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Objetsauswiel STR_OBJECT_BUILD_TOOLTIP :{BLACK}Wiel den Objet dee gebaut gëtt. Shift wiesselt tescht bauen / ongeféier Käschten uweisen STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Wiel d'Klass vun dem Objet dee sollt gebaut ginn STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Preview vum Objet STR_OBJECT_BUILD_SIZE :{BLACK}Gréisst: {GOLD}{NUM} x {NUM} Felder STR_OBJECT_CLASS_LTHS :Liichttierm STR_OBJECT_CLASS_TRNS :Antennen # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Beem STR_PLANT_TREE_TOOLTIP :{BLACK}Wielt de Baamtyp. Wann d'Feld schons e Baam huet, ginn méi Beem vu verschiddenen Arten gesat STR_TREES_RANDOM_TYPE :{BLACK}Zoufälleg Beem STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Zoufälleg Beem planzen. Shift wiesselt tëscht bauen an ongeféier Käschten uweisen STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Zoufälleg Beem STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Beem zoufälleg iwwert d'Landschaft setzen # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Landerstellung STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Fielsen iwwert d'Landschaft setzen STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Zone fir Wüst défineieren.{}CTRL unhalen fir se ze läschen STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Vergréisser d'Zone fir d'Land unzehiewen/erofzesetzen STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Verklenger d'Zone fir d'Land unzehiewen/erofzesetzen STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Generéier en Zoufallsland STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Neie Szenario erstellen STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Setz d'Landschaft zeréck STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Huel all Grondstécker vun der Firma ewech STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Setz d'Landschaft zeréck STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Bass du sécher dass du all Grondstécker vun der Firma ewechhuelen wëlls? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}Staderstellung STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}Nei Stad STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Grënn eng nei Stad. Shift+Klick weist ongeféier Käschten STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Zoufallsstad STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Grënn d'Stad op enger zoufälleger Plaz STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Vill zoufälleg Dierfer STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}D'Kaart zoufälleg mat Dierfer fëllen STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Stadnumm: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Stadnumm agin STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Klick fir Stad ze benennen STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Zoufällegen Numm STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Neien Zoufallsnumm generéiren STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Stadgréisst: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Kleng STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Mëttel STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Grouss STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Zoufall STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Wiel d'Stadgréisst STR_FOUND_TOWN_CITY :{BLACK}Stad STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Stied wuessen méi schnell wéi Dierfer{}Ofhängeg vun den Astellungen, sinn se méi grouss am Ufank STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Stroosselayout vun der Stad: STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Stroosselayout fir des Stad wielen STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Original STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Besser Stroossen STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 Gitter STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 Gitter STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Zoufall # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Nei Industrie finanzéieren STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Wielt déi gewënschten Industrie op der Lëscht aus STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Vill zoufälleg Industrien STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}D'Kaart mat villen zoufällegen Industrien fëllen STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Käschten: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Förderen STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Bauen STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Grënnen # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Industrieketten fir {STRING} Industrie STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Industrieketten fir {STRING} Wueren STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Produzéirent Industrien STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Akzeptéirend Industrien STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Haiser STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Klick op d'Industrie fir d'Liwweranten an Verbraucher ze gesinn STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Klick op d'Wueren fir d'Liwweranten an Verbraucher ze gesinn STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Wuereketten uweisen STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Weis Industrien un déi Wueren liwweren an akzeptéiren STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Link op déi kleng Kaart STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Wiel déi ugewisen Industrien och op der klenger Kaart aus STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Gidder wielen STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Wiel d'Gidder déis du wëlls uweisen STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Industrie auswielen STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Wiel d'Industrie aus déis du wëlls uweisen # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Land Informatiounen STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Käschte fir ze raumen: {LTBLUE}Keng STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Käschte fir ze raumen: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Akommes wann ofgerappt: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :Keen STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Besëtzer: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Stroossebesëtzer: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramschinnebesëtzer: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Schinnebesëtzer: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Gemeng: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Keng STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinaten: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Gebaut: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Statiounsklass: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Statiounstyp: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Fluchhafeklass: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Fluchhafennumm: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Fluchhafefeldnumm: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Akzeptéiert Wuer: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Schinne-Geschw.-Limit: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Stroosse-Geschw.-Limit: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Fielsen STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Knubbelegt Land STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Eidelt Land STR_LAI_CLEAR_DESCRIPTION_GRASS :Gras STR_LAI_CLEAR_DESCRIPTION_FIELDS :Felder STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Schnéibedeckt Land STR_LAI_CLEAR_DESCRIPTION_DESERT :Wüst STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} Schinn STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} Schinn mat Blocksignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} Schinn mat Presignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} Schinn mat Ausgangs-Signaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} Schinn mat Kombo-Signaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} Schinn mat Weesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} Schinn mat Einbahnsignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} Schinn mat Block- an Presignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} Schinn mat Block- an Ausgangssignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} Schinn mat Block- a Kombosignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} Schinn mat Block- a Weesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} Schinn mat Block- a Einbahnsignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} Schinn mat Pre- an Ausgangssignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} Schinn mat Pre- a Kombosignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} Schinn mat Pre- a Weesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} Schinn mat Pre- an Einbahnweesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} Schinn mat Ausgangs- a Kombosignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} Schinn mat Ausgangs- a Weesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} Schinn mat Ausgang- an Einbahnweesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} Schinn mat Kombo- an Weesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} Schinn mat Kombo- an Einbahnweesignaler STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} Schinn mat Wee- and Einbahnweesignaler STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} Zuchschapp STR_LAI_ROAD_DESCRIPTION_ROAD :Strooss STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Strooss mat Luuchten STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Strooss mat Beem STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Stroossendepot STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Zuche/Stroosse-Barrière STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tram # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (gëtt gebaut) STR_LAI_TREE_NAME_TREES :Beem STR_LAI_TREE_NAME_RAINFOREST :Reebësch STR_LAI_TREE_NAME_CACTUS_PLANTS :Kaktus STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Gare STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Fligerhangar STR_LAI_STATION_DESCRIPTION_AIRPORT :Fluchhafen STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Camionsgare STR_LAI_STATION_DESCRIPTION_BUS_STATION :Busarrêt STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Schëffshafen STR_LAI_STATION_DESCRIPTION_BUOY :Boje STR_LAI_STATION_DESCRIPTION_WAYPOINT :Weepunkt STR_LAI_WATER_DESCRIPTION_WATER :Waasser STR_LAI_WATER_DESCRIPTION_CANAL :Kanal STR_LAI_WATER_DESCRIPTION_LOCK :Schleis STR_LAI_WATER_DESCRIPTION_RIVER :Floss STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Küst oder Flossufer STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Schëffsschapp # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Zuchtunnel STR_LAI_TUNNEL_DESCRIPTION_ROAD :Stroossentunnel STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Stolen Zuchhängebréck STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Stoldréier Zuchbréck STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Stole fräidroend Zuchbréck STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Stolbeton Zuchhängebréck STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Holzen Zuchbréck STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Betons Zuchbréck STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Rouerstol Zuchbréck STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Stolen Hängebréck STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Stoldréier Bréck STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Fräidroend Stolbréck STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Stolbetons Hängebréck STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Holze Bréck STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Betons Bréck STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Rouerstol Brèck STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Aquadukt STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Antenne STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Liichttuerm STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Firmen Haaptgebai STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Land am Firmenbesëtz # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}Iwwert OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Original Copyright {COPYRIGHT} 1995 Chris Sawyer, All Rechter virbehalen STR_ABOUT_VERSION :{BLACK}OpenTTD Versioun {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2015 D'OpenTTD team # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Spill späicheren STR_SAVELOAD_LOAD_CAPTION :{WHITE}Spill lueden STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Szenario späicheren STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Szenario lueden STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Héichtekaart lueden STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Héichtenkaart späichern STR_SAVELOAD_HOME_BUTTON :{BLACK}Klick hei fir op d'Standard Späicher-/Luedverzeeschnis ze goen STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} fräi STR_SAVELOAD_LIST_TOOLTIP :{BLACK}Lëscht vun de Lafwierker, Dossieren a Späicherstänn STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Momentan gewielten Numm fir de Spillstand STR_SAVELOAD_DELETE_BUTTON :{BLACK}Läschen STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Läscht de momentan gewielte Spillstand STR_SAVELOAD_SAVE_BUTTON :{BLACK}Späicheren STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Späichert dei aktuell Partie ënnert dem gewielten Numm STR_SAVELOAD_LOAD_BUTTON :{BLACK}Lueden STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Lued d'ugewielten Spill STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP :{BLACK}Ugewielten Héichtekaart lueden STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Detailer vum Spill STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Keng Informatioun do STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}Gëff dem Spillstand en Numm # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}Welt Generatioun STR_MAPGEN_MAPSIZE :{BLACK}Kaartegréisst: STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Wiel d'Gréisst vun der Kaart a Felder. D'Unzuel vu benotzbare Felder wäert e bësse méi kleng sinn STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Unz. Dierfer: STR_MAPGEN_DATE :{BLACK}Datum: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Unz. Industrien: STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}Maximal Kaartenhéicht: STR_MAPGEN_MAX_HEIGHTLEVEL_UP :{BLACK}Setzt d'Maximalhéicht vu Bierger op der Kaart em 1 erop STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN :{BLACK}Setzt d'Maximalhéicht vu Bierger op der Kaart em 1 erof STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Weis d'Schnéilinnhéicht STR_MAPGEN_SNOW_LINE_UP :{BLACK}Beweg Schnéilinnhéicht erop STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Beweg Schnéilinnhéicht erof STR_MAPGEN_LAND_GENERATOR :{BLACK}Landgenerator: STR_MAPGEN_TREE_PLACER :{BLACK}Baam Algorithmus: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Terrain Typ: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Mieresspigel: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Flëss: STR_MAPGEN_SMOOTHNESS :{BLACK}Mëllt: STR_MAPGEN_VARIETY :{BLACK}Vielfaltverdeelung: STR_MAPGEN_GENERATE :{WHITE}Generéiren # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}Kaartenenner: STR_MAPGEN_NORTHWEST :{BLACK}Nordwest STR_MAPGEN_NORTHEAST :{BLACK}Nordost STR_MAPGEN_SOUTHEAST :{BLACK}Südost STR_MAPGEN_SOUTHWEST :{BLACK}Südwest STR_MAPGEN_BORDER_FREEFORM :{BLACK}Fräiform STR_MAPGEN_BORDER_WATER :{BLACK}Waasser STR_MAPGEN_BORDER_RANDOM :{BLACK}Zoufälleg STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Zoufall STR_MAPGEN_BORDER_MANUAL :{BLACK}Manuell STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Héichtekaart-Rotatioun: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Héichtekaart-Numm: STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Gréisst: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT :{WHITE}Maximal Kaartenhéicht änneren STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Ännert d'Schnéilinnhéicht STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Änner d'Startjoer # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}Szenarientyp STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Flaachland STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Generéier e flaacht Land STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Zoufallsland STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Héicht vum flaache Land: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Héicht vum flaache Land 1 erofsetzen STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Héicht vum flaache Land 1 eropsetzen STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Héicht vum flaache Land änneren # Map generation progress STR_GENERATION_WORLD :{WHITE}Generéiren d'Welt... STR_GENERATION_ABORT :{BLACK}Ofbriechen STR_GENERATION_ABORT_CAPTION :{WHITE}Welt-Generatioun ofbriechen STR_GENERATION_ABORT_MESSAGE :{YELLOW}Wëlls du wierklech d'Generatioun ofbriechen? STR_GENERATION_PROGRESS :{WHITE}{NUM}% komplett STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}Welt-Generatioun STR_GENERATION_RIVER_GENERATION :{BLACK}Generéiren vu Flëss STR_GENERATION_TREE_GENERATION :{BLACK}Baam Generatioun STR_GENERATION_OBJECT_GENERATION :{BLACK}Objets-Generatioun STR_GENERATION_CLEARING_TILES :{BLACK}Generatioun vu knubbelegem a stengege Land STR_GENERATION_SETTINGUP_GAME :{BLACK}Spill gëtt opgestallt STR_GENERATION_PREPARING_TILELOOP :{BLACK}Felder-Verdeelung STR_GENERATION_PREPARING_SCRIPT :{BLACK}Lafende Script STR_GENERATION_PREPARING_GAME :{BLACK}Preparéiren d'Spill # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF Astellungen STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Detailléiert NewGRF Informatioun STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Aktiv NewGRF Dateien STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Inaktiv NewGRF Dateien STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Preset auswielen: STR_NEWGRF_FILTER_TITLE :{ORANGE}String filteren: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Gewielte Preset lueden STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Preset späichern STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Aktuell Lëscht als Preset späichern STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Presetnumm uginn STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Preset läschen STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Gewielte Preset läschen STR_NEWGRF_SETTINGS_ADD :{BLACK}Baifügen STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Ausgewielte NewGRF an d'Config bäisetzen STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Dateien nei scannen STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Update d'Lëscht vu verfügbare NewGRF Dateien. STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Wechhhuelen STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Ausgewielten NewGRF aus der Lëscht huelen STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Rop STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Setzt den NewGRF an der Lëscht erop STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Rof STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Setzt d'NewGRF an der Lëscht erof STR_NEWGRF_SETTINGS_UPGRADE :{BLACK}Upgrade STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP :{BLACK}Upgrade NewGRF Dateien fir déis du eng méi nei Versioun installéiert hues STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}Eng Lëscht vun NewGRF Dateien déi installéiert sinn. STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Parameter setzen STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Parameter uweisen STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Palette wiesselen STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Wiessel d'Palette vun den ausgewielten NewGRF.{} Maach dat wann d'Grafiken vun deser NewGRF rosa am Spill ausgesinn STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Ännerungen unhuelen STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Fehlenden Inhalt online downloaden STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Check op den Inhalt de fehlt online ka fonnt ginn STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Dateinumm: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Versioun: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Min. kompatibel Versioun: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palette: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parameter: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}Keng Info verfügbar STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Datei net fonnt. STR_NEWGRF_SETTINGS_DISABLED :{RED}Ausgeschalt STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Onkompatibel mat deser Versioun vun OpenTTD # NewGRF save preset window STR_SAVE_PRESET_CAPTION :{WHITE}Preset späichern STR_SAVE_PRESET_LIST_TOOLTIP :{BLACK}Lëscht vu Presets, wiel een den op den Numm ënnendrënner kopéiert gëtt STR_SAVE_PRESET_TITLE :{BLACK}Wiel en Numm fir de Preset STR_SAVE_PRESET_EDITBOX_TOOLTIP :{BLACK}Grad ausgewielten Numm fir de Preset dee gespäichert soll ginn STR_SAVE_PRESET_CANCEL :{BLACK}Ofbriechen STR_SAVE_PRESET_CANCEL_TOOLTIP :{BLACK}Den Preset net änneren STR_SAVE_PRESET_SAVE :{BLACK}Späichern STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Späicher de Preset op dee grad ausgewielten Numm # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}NewGRF Parameter änneren STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Zoumaachen STR_NEWGRF_PARAMETERS_RESET :{BLACK}Reset STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Setzt all Paramater op de Standard zréck STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parameter {NUM} STR_NEWGRF_PARAMETERS_SETTING :{STRING}: {ORANGE}{STRING} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Unzuel Parameter: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspizéier - {STRING} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Parent STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Inspizéier den Objet vun der "parent scope" STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING} op {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Objet STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Schinnentyp STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF Variabel 60+x Parameter (hexadezimal) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Alignéiren d'Sprite {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Nächst Sprite STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Géi weider op déi nächst normal Sprite, iwwersprang all pseudo/recolour/font Sprite an sprang un den Ufank no der leschter. STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Géi op Sprite STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Géi op d'Sprite. Wann d'Sprite keng normal Sprite ass, géi op déi nächst normal Sprite STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Viregt Sprite STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Géi weider op déi nächst normal Sprite, iwwersprang all pseudo/recolour/font Sprite an sprang zréck op den Ufank no der leschter. STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representatioun vun der grad gewielter Sprite. Den Alignement gëtt ignoréiert wann d'Sprite gezun gëtt STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Beweg Sprite, X an Y offsets enneren sech STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Relativ zerécksetzen STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Momentan relativ Offsets zerécksetzen STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}X-Offset: {NUM}, Y-Offset: {NUM} (Absolut) STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}X-Offset: {NUM}, Y-Offset: {NUM} (Relativ) STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Wiel Sprite STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Wiel en Sprite egalwou um Schierm aus STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Géi op Sprite # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warnung: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Fehler: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}E fatalen NewGRF Fehler ass geschitt: {}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} wärt net mat der TTDPatch Versioun déi vun OpenTTD erkannt gouf funktionéiren STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} ass fir {STRING} Versioun vun TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ass designed fir mat {STRING} benotzt ze ginn STR_NEWGRF_ERROR_INVALID_PARAMETER :Invalide Parameter fir {1:STRING}: Parameter {STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} muss firun {STRING} geluede ginn STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} muss no {STRING} geluede ginn STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} brauch OpenTTD Versioun {STRING} oder méi nei STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :GRF Datei déi designed gouf fir ze iwwersetzen STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Zevill NewGRFen gelueden. STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :{1:STRING} als statesch NewGRF lueden mat {STRING} kann Desyncs verursaachen STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Onerwaarte Sprite (Sprite {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Onbekannten Aktioun 0 property {4:HEX} (Sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Versicht invalid ID ze benotzen (Sprite {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{STRING} huet eng korrupt Sprite. All korrupt Sprites ginn als Fragezeichen (?) duergestallt STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Huet eng Rei Action 8 Einträg (Sprite {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Lanscht d'Enn vum Pseudo-Sprite gelies (Sprite {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}D'momentan benotzten Grafikset huet e puer Sprites ze mann. {}W.e.g d'Basisgrafikset updaten STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}Am grad benotzten Basis-Grafikset fehlen e puer Sprites.{}W.e.g Basis-Grafikset updaten.{}Wellsde en {YELLOW}Development Snapshot vun OpenTTD spills{WHITE}, brauchsde och en {YELLOW}Development Snapshot vum Basis-Grafikset{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Ugefroten GRF Ressource net verfügbar (sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} gouf ausgeschalt vun {STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Invalid/onbekannten Sprite Layout Format (Sprite {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Opgepasst! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Du mëss Ännerungen an engem lafende Spill. Dest kann OpenTTD crashen.W.e.g dest net als Bug melden.{}Bass du sécher? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Kann Datei net bäisetzen: Duplikat GRF ID STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Passend Datei net fonnt (kompatibel GRF gelued) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Kann Fichier net dobäisetzen : NewGRF Limite erreecht STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Kompatibel GRF(s) geluede fir fehlend Dateien STR_NEWGRF_DISABLED_WARNING :{WHITE}Fehlend GRF Datei(en) sinn ausgeschalt STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Fehlend GRF Datei(en) STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Entpausen kann OpenTTD crashen.{} Wellsde wierklech entpausen ? # NewGRF status STR_NEWGRF_LIST_NONE :Keng STR_NEWGRF_LIST_ALL_FOUND :All Dateien fonnt STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Kompatibel Dateien fonnt STR_NEWGRF_LIST_MISSING :{RED}Dateien fehlen # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}Verhalen vun der NewGRF '{0:STRING}' kann Desyncs oder Crashen verursachen STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Ännert den Zoustand fir '{1:ENGINE}' wann net an engem Schapp STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Ännert d'Gefierlängt fir '{1:ENGINE}' wann net an engem Schapp STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Geännerte Gefierkapazitéit vun '{1:ENGINE}' wann net an engem Schapp oder amgaang emgebaut ze ginn STR_BROKEN_VEHICLE_LENGTH :{WHITE}Zuch'{VEHICLE}' vun der Firma '{COMPANY}' huet eng falsch Längt. Et kënnt wahrscheinlech wéinst den NewGRFs. Spill kann desyncroniséiren oder ofstierzen STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' huet Fehlinformatiounen STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit Informatioun fir '{1:ENGINE}' ass anescht wéi an der Kaflëscht no der Constructioun. Dëst kann en Autoerneirung/-ersetzen Fehler oprufen STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' huet eng Endlosschläif am Production callback verursaacht STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Callback {1:HEX} huet en onbekannten/invalid Resultat {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} vun STR_NEWGRF_INVALID_ENGINE : STR_NEWGRF_INVALID_INDUSTRYTYPE : # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE : # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}Scannen NewGRFen STR_NEWGRF_SCAN_MESSAGE :{BLACK}Scannen NewGRFen. Dest kann eng Weil dauern... STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF{P "" en} gescanned vun ongeféier {NUM} NewGRF{P "" en} STR_NEWGRF_SCAN_ARCHIVES :Archiver scannen # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}Schëlderlëscht - {COMMA} Schëld{P "" er} STR_SIGN_LIST_MATCH_CASE :{BLACK}Passende Fall STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Zoutreffend Fäll wiesselen wann Schëldernimm mam String-Filter verglach ginn # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Schëldtext änneren STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Géi bei d'nächst Schëld STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Géi bei d'Schëld firdrun STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Gëff en Numm fir d'Schëld an # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}Stied STR_TOWN_DIRECTORY_NONE :{ORANGE}- Keng - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Stiednimm - klick op den Numm fir d'Usiicht drop ze zentréieren. Ctrl+Klick erstellt eng nei Usiicht vun der Stad STR_TOWN_POPULATION :{BLACK}Weltbevölkerung: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (Stad) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Awunner: {ORANGE}{COMMA}{BLACK} Haiser: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Passagéier leschte Mount: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Post leschte Mount: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Gidder gebraucht fir Stadwuesstem: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} gebraucht STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} gebraucht am Wanter STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} geliwwert STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (nach gebraucht) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (geliwwert) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Stad wiisst all {ORANGE}{COMMA}{BLACK}{NBSP}D{P ag eeg} STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Stad wiisst all {ORANGE}{COMMA}{BLACK}{NBSP}D{P ag eeg} (finanzéiert) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Stad wiisst{RED} net{BLACK} STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Kaméidislimit an der Stad: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Zentréiert d'Usiicht op d'Stad. Ctrl+Klick erstellt eng nei Usiicht op d'Stad STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Gemeng STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Weist d'Informatiounen zu der Gemeng STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Wiesselt de Stadnumm STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Erweideren STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Stad méi grouss maachen STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Läschen STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Des Stad ganz läschen STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Stad ëmbenennen # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}Gemeng {TOWN} STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transportfirme-Bewäertung: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Verfügbar Aktiounen: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}Lëscht vu Saachen déi an der Stad gemaach kënne ginn - klick op eng Optioun fir méi Informatiounen STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Maach et STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Féiert déi gewielten Aktioun aus STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Kleng Marketingaktioun STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Mëttel Marketingsaktioun STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Grouss Marketingsaktioun STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Stroossenneibau finanzéieren STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Statu vum Firmenbesëtzer bauen STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Nei Gebaier finanzéieren STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Exklusiv Transportrechter kafen STR_LOCAL_AUTHORITY_ACTION_BRIBE :D'Gemeng bestiechen STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Eng kleng Marketingaktioun starten, fir méi Passagéier a Wueren ze gewannen.{} Käschten: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Eng mëttel Marketingaktioun starten, fir méi Passagéier a Wueren ze gewannen.{} Käschten: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Eng grouss Marketingaktioun starten, fir méi Passagéier a Wueren ze gewannen.{} Käschten: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Stroossenneibau an der Stad finanzéieren. Stéiert den Traffic op de Stroossen fir déi nächst 6 Méint.{} Käschten: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Eng Statu zur Éier vun der Firma bauen.{} Käschten: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}De Bau vun neie Kommerzgebaier finanzéieren.{} Käschten: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Kaaft fir 1 Joer exklusiv Transportrechter an deser Stad. D'Gemeng erlaabt den Transport vu Passagéier a Wueren nëmmen äerer Firma.{} Käschten: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}D'Gemeng bestiechen fir d'Bewäertung ze erhéijen, mam Risiko fir eng grouss Bestrofung, falls der erwëscht gitt.{} Käschten: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Ziler STR_GOALS_SPECTATOR_CAPTION :{WHITE}Global Ziler STR_GOALS_GLOBAL_TITLE :{BLACK}Global Ziler: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Keng - STR_GOALS_SPECTATOR_NONE :{ORANGE}- Net uwendbar - STR_GOALS_PROGRESS :{ORANGE}{STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_COMPANY_TITLE :{BLACK}Firmenziler: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klick op Ziel fir d'Haptfënster op d'Industrie/Stad/Feld ze zentréiren. Ctrl+Klick mëcht eng nei Fënster op der Industrie/Stad/Feld-Positioun op # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :Fro STR_GOAL_QUESTION_CAPTION_INFORMATION :Informatioun STR_GOAL_QUESTION_CAPTION_WARNING :Warnung STR_GOAL_QUESTION_CAPTION_ERROR :Fehler ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Ofbriechen STR_GOAL_QUESTION_BUTTON_OK :OK STR_GOAL_QUESTION_BUTTON_NO :Nee STR_GOAL_QUESTION_BUTTON_YES :Jo STR_GOAL_QUESTION_BUTTON_DECLINE :Ofleenen STR_GOAL_QUESTION_BUTTON_ACCEPT :Unhuelen STR_GOAL_QUESTION_BUTTON_IGNORE :Ignoréiren STR_GOAL_QUESTION_BUTTON_RETRY :Nach emol.. STR_GOAL_QUESTION_BUTTON_PREVIOUS :Zeréck STR_GOAL_QUESTION_BUTTON_NEXT :Nächst STR_GOAL_QUESTION_BUTTON_STOP :Stop STR_GOAL_QUESTION_BUTTON_START :Start STR_GOAL_QUESTION_BUTTON_GO :Lass STR_GOAL_QUESTION_BUTTON_CONTINUE :Weiderman STR_GOAL_QUESTION_BUTTON_RESTART :Nei man STR_GOAL_QUESTION_BUTTON_POSTPONE :Ofwaarden STR_GOAL_QUESTION_BUTTON_SURRENDER :Opginn STR_GOAL_QUESTION_BUTTON_CLOSE :Zouman ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}Subventiounen STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subventiounen fir de Service: STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} vun {STRING} op {STRING}{YELLOW} (bis {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- Keng - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Servicer mat Subventiounen: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} vun {STRING} op {STRING}{YELLOW} ({COMPANY}{YELLOW}, bis {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klick op de Service fir d'Usiicht op d'Industrie/Stad ze zentréieren. Ctrl+Klick erstellt eng nei Usiicht op d'Industrie/Stad # Story book window STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Storybuch STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Globalt Storybuch STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :Säit {NUM} STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Géi op eng spezifësch Säit andems se aus der Dropdownlëscht ausgewielt gëtt STR_STORY_BOOK_PREV_PAGE :{BLACK}Zeréck STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Géi op d'Säit firdrun STR_STORY_BOOK_NEXT_PAGE :{BLACK}Nächst STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Géi op déi nächst Säit STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Ongültëg Zil Referenz # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Statiounennimm - klick op den Numm fir d'Usiicht dorop ze zentréieren. Ctrl+Klick erstellt eng nei Usiicht op d'Statioun STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Hal Ctrl un fir méi wéi 1 Objet auszewielen STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Statioun{P "" en} STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- Näischt - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Wiel all d'Fabriken STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Wielt all Luedungstyp (ouni Luedung déi waard) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}Keng Luedung # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} ënnerwee vun {STATION}) STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} reservéiert fir gelueden ze ginn) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Akzeptéiert STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Weis d'Lëscht vun den akzptéierten Wueren STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Akzeptéiert: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}Des Statioun huet exklusiv Transportrechter an deser Stad STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} huet exklusiv Transportrechter an deser Stad kaf. STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Bewäertungen STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Weis d'Statiounsbewäertungen STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Lokal Bewäertung an Liwwerung pro Mount STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}Gruppéier no STR_STATION_VIEW_WAITING_STATION :Statioun: Waardend STR_STATION_VIEW_WAITING_AMOUNT :Unzuel: Waardend STR_STATION_VIEW_PLANNED_STATION :Statioun: Geplangt STR_STATION_VIEW_PLANNED_AMOUNT :Unzuel: Geplangt STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} vun {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} via {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} op {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} vun iergendenger Statioun STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} op iergendeng Statioun STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} via iergendeng Statioun STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} vun deser Statioun STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} stoppt op deser Statioun STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} op des Statioun STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} non-stop STR_STATION_VIEW_GROUP_S_V_D :Quell-Via-Destinatioun STR_STATION_VIEW_GROUP_S_D_V :Quell-Destinatioun-Via STR_STATION_VIEW_GROUP_V_S_D :Via-Quell-Destinatioun STR_STATION_VIEW_GROUP_V_D_S :Via-Destinatioun-Quell STR_STATION_VIEW_GROUP_D_S_V :Destinatioun-Quell-Via STR_STATION_VIEW_GROUP_D_V_S :Destinatioun-Via-Quell ############ range for rating starts STR_CARGO_RATING_APPALLING :Schrecklech STR_CARGO_RATING_VERY_POOR :Ganz schlecht STR_CARGO_RATING_POOR :Schlecht STR_CARGO_RATING_MEDIOCRE :Mëttelméisseg STR_CARGO_RATING_GOOD :Gutt STR_CARGO_RATING_VERY_GOOD :Ganz gutt STR_CARGO_RATING_EXCELLENT :Exzellent STR_CARGO_RATING_OUTSTANDING :Perfekt ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Zentréiert d'Usiicht op d'Statioun. Ctrl+Klick erstellt eng nei Usiicht op d'Statioun STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Den Numm vun der Statioun änneren STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Weis all Zich déi des Statioun an hierem Zäitplang hunn STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Weis all Stroossegefierer déi des Statioun an hierem Zäitplang hunn STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Weis all Fliger déi des Statioun an hierem Zäitplang hunn STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Weis all Schëffer déi des Statioun an hierem Zäitplang hunn STR_STATION_VIEW_RENAME_STATION_CAPTION :D'Gare ëmbenennen STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Fluchhafen zoumaachen STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Hal de Fliger dovun of op dësem Fluchhafen ze landen # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Zentréiert d'Usiicht op de Weepunkt. Ctrl+Klick erstellt eng nei Usiicht um Weepunkt STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Weepunkt Numm änneren STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Zentréiert d'Usiicht op d'Boje. Ctrl+Klick erstellt eng nei Usiicht op der Boje STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Boje ëmbenennen STR_EDIT_WAYPOINT_NAME :{WHITE}Weepunktnumm # Finances window STR_FINANCES_CAPTION :{WHITE}{COMPANY} Finanzen {BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Ausgaben/Akommes STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Konstruktioun STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}Nei Gefierer STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Zuch Betribskäschten STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Stroossegefierer Betribskäschten STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Fliger Betribskäschten STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Schëff Betribskäschten STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Ennerhaltskäschte vum Besëtz STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Zuch Akommes STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Stroossegefierer Akommes STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Fliger Akommes STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Schëff Akommes STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Zënssaz STR_FINANCES_SECTION_OTHER :{GOLD}Aaner STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}Total: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Kontostand STR_FINANCES_LOAN_TITLE :{WHITE}Kredit STR_FINANCES_MAX_LOAN :{WHITE}Maximale Kredit: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}{CURRENCY_LONG} léinen STR_FINANCES_BORROW_TOOLTIP :{BLACK}Erhéicht de Kredit. Ctrl+Klick léint de Maximum STR_FINANCES_REPAY_BUTTON :{BLACK}{CURRENCY_LONG} zeréckbezuelen STR_FINANCES_REPAY_TOOLTIP :{BLACK}Bezuelt en Deel vum Kredit zeréck. Ctrl+Klick bezillt sou vill wéi méiglech zeréck STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastruktur # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Manager) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Gegrënnt: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Faarfschema: STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Gefierer: STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} Z{P uch ich} STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} Stroossegefier{P "" er} STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} Fliger STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} Schëff{P "" er} STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}Keng STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Firmewäert: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% am Besëtz vun {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastruktur: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} Schinnendeel{P "" er} STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} Stroossendeel{P "" er} STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} Waasserdeel{P "" er} STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} Statiounendeel{P "" er} STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} Fluchh{P afen äfen} STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}Keng STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Haaptgebai bauen STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Haaptgebai bauen STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}Weis d'Haaptgebai STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}Haaptgebai uweisen STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Firmenhaaptgebai réckelen STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Bau d'Firmenhaaptgebai op eng aaner Plaz.Käschten: 1% vun dem Firmewäert. Shift+Klick weist ongeféier Käschten ouni ze réckelen STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Detailer STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}Detailléiert Infrastrukturen uweisen STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}Neit Gesiicht STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Wielt en neit Gesiicht fir de Manager STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Faarfschema STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Ännert d'Firmengefiererfaarf STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Firmennumm STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Ännert de Firmennumm STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Managernumm STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Ännert den Numm vum Manager STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Kaaft 25% Undeel vun der Firma STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Verkaaft 25% Undeel vun der Firma STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Kaaft 25% Undeel vun deser Firma. Shift+Klick weist ongeféier Käschten ouni Kaf vun Aktien STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Verkaaft 25% Undeel vun deser Firma. Shift+Klick weist ongeféier Käschten ouni Verkaf vun Aktien STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Firmennumm STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Numm vum Manager STR_BUY_COMPANY_MESSAGE :{WHITE}Mir sichen eng Transportfirma déi eis Firma iwwerhuelen wëll.{}{}Wëlls du {COMPANY} fir {CURRENCY_LONG} kafen? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastruktur vun {COMPANY} STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Schinnestécker: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signaler STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Stroossestécker: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Strooss STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tram STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Waasserfelder: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanäl STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Statiounen: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Statiounsfelder STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Fluchhäfen STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/Jr # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Industrien STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- Keng - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}){YELLOW} ({COMMA}% transportéiert) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}/{CARGO_LONG}{STRING}){YELLOW} ({COMMA}%/{COMMA}% transportéiert) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Industrienimm - klick op en Numm fir d'Usiicht do drop ze zentréieren. Ctrl+Klick erstellt eng nei Usiicht op d'Industrie # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Produktioun läschte Mount: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% transportéiert) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Siicht op d'Industrie. Ctrl+Klick erstellt eng nei Usiicht op d'Industrie STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Produktiounslevel: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}D'Industrie annoncéiert dass se zougemaach gëtt ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Brauch: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Brauch: {YELLOW}{STRING}{STRING}, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Brauch: {YELLOW}{STRING}{STRING}, {STRING}{STRING}, {STRING}{STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Luedunge déi nach verschafft musse ginn: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Produzéiert: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Produzéiert: {YELLOW}{STRING}{STRING}, {STRING}{STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}D'Produktioun änneren (Multipel vun 8, bis op 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Änner de Produktiounslevel (Prozenter, bis zu 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} - {COMMA} Z{P uch ich} STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING} - {COMMA} Gefier{P "" er} STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING} - {COMMA} Schëff{P "" er} STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING} - {COMMA} Fliger STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Zich - klick op den Zuch fir Informatiounen STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Stroossegefierer - klick op e Gefier fir Informatiounen STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Schëffer - klick op d'Schëff fir Informatiounen STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Fliger - klick op de Fliger fir Informatiounen STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Profit dëst Joer: {CURRENCY_LONG} (lescht Joer: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :Verfügbar Zich STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Verfügbar Gefierer STR_VEHICLE_LIST_AVAILABLE_SHIPS :Verfügbar Schëffer STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Verfügbar Fligern STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}Lëscht vun alle Maschinen fir dësen Typ weisen STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Verwaltungslëscht STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Schéckt d'Instructiounen un all Gefierer an der Lëscht STR_VEHICLE_LIST_REPLACE_VEHICLES :Gefierer ersetzen STR_VEHICLE_LIST_SEND_FOR_SERVICING :An d'Revisioun schécken STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :An de Schapp schécken STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :An den Depot schécken STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :An de Schapp schécken STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :An den Hangar schécken STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Klick fir all Gefierer an der Lëscht ze stoppen STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Klick fir all Gefirer an der Lëscht ze starten STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Gedeelten Opträg vun {COMMA} Gefier{P "" er} # Group window STR_GROUP_ALL_TRAINS :All Zich STR_GROUP_ALL_ROAD_VEHICLES :All Stroossegefierer STR_GROUP_ALL_SHIPS :All Schëffer STR_GROUP_ALL_AIRCRAFTS :All Fligeren STR_GROUP_DEFAULT_TRAINS :Ongruppéiert Zich STR_GROUP_DEFAULT_ROAD_VEHICLES :Ongruppéiert Stroossegefierer STR_GROUP_DEFAULT_SHIPS :Ongruppéiert Schëffer STR_GROUP_DEFAULT_AIRCRAFTS :Ongruppéiert Fligeren STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Gruppen - klick op eng Grupp fir d'Gefierer aus der Grupp ze gesinn. Per Drag and Drop d'Hierarchie änneren. STR_GROUP_CREATE_TOOLTIP :{BLACK}Klick fir eng Grupp ze maachen STR_GROUP_DELETE_TOOLTIP :{BLACK}Déi ungewielte Grupp läschen STR_GROUP_RENAME_TOOLTIP :{BLACK}Déi ungewielte Grupp ëmbenennen STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Klick fir déi Grupp vum globalen "Autoersetzen" auszeschléissen STR_QUERY_GROUP_DELETE_CAPTION :{WHITE}Grupp läschen STR_GROUP_DELETE_QUERY_TEXT :{WHITE}Bassde sécher, dass du des Grupp an all Ennergruppen läsche wëlls? STR_GROUP_ADD_SHARED_VEHICLE :Gedeelte Gefierer bäisetzen STR_GROUP_REMOVE_ALL_VEHICLES :All Gefierer ewechhuelen STR_GROUP_RENAME_CAPTION :{BLACK}Eng Grupp ëmbenennen # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :Nei Zich STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Nei Elektrozich STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Nei Monorailgefierer STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Nei Magnéitbunngefierer STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Nei Zich STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Nei Stroossegefierer STR_BUY_VEHICLE_SHIP_CAPTION :Nei Schëffer STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Neie Fliger STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Käschten: {GOLD}{CURRENCY_LONG}{BLACK} Gewiicht: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Geschw.: {GOLD}{VELOCITY}{BLACK} Kraaft: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Geschw.: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Geschwindegkeet um Ozean: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Geschwindegkeet um Kanal/Floss: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Betribskäschten: {GOLD}{CURRENCY_LONG}/Jr STR_PURCHASE_INFO_CAPACITY :{BLACK}Kapazitéit: {GOLD}{CARGO_LONG} {STRING} STR_PURCHASE_INFO_REFITTABLE :(ëmbaubar) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designt: {GOLD}{NUM}{BLACK} Liewenszäit: {GOLD}{COMMA} Joer STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. Zouverläss.: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Käschten: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Gewiicht: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Käschten: {GOLD}{CURRENCY_LONG}{BLACK} Geschw.: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Kapazitéit: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Ugedriwwen Waggonen: {GOLD}+{POWER}{BLACK} Gewiicht: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Embaubar zu: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :All Wuerentyp STR_PURCHASE_INFO_ALL_BUT :Alles ausser {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. Zéikraaft: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Distanz: {GOLD}{COMMA} Felder STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Zuchlëscht - klick op en Zuch fir Informatiounen. Ctrl+Klick fir tëscht dem Verstoppen hin an hier ze sprangen STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Stroossegefierlëscht - klick op en Gefier fir Informatiounen. Ctrl+Klick fir tëscht dem Verstoppen hin an hier ze sprangen STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Schëffslëscht - Klick op d'Schëff fir Informatiounen. Ctrl+Klick fir tëscht dem Verstoppen hin an hier ze sprangen STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Fligerlëscht - Klick op de Fliger fir Informatiounen. Ctrl+Klick fir tëscht dem Verstoppen hin an hier ze sprangen STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Gefier kafen STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Gefier kafen STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Schëff kafen STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Fliger kafen STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Keeft den ungewielten Zuch. Shift+Klick weist ongeféier Käschten ouni Kaf STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Keeft dat ugewielte Stroossegefier. Shift+Klick weist ongeféier Käschten ouni Kaf STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Keeft dat ugewielte Schëff. Shift+Klick weist ongeféier Käschten ouni Kaf STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Keeft den ungewielte Fliger. Shift+Klick weist ongeféier Käschten ouni Kaf STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Ëmbenennen STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Ëmbenennen STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Ëmbenennen STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Ëmbenennen STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Zuch ëmbenennen STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Gefiertyp ëmbenennen STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Schëffstyp ëmbenennen STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Fligertyp ëmbenennen STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Verstoppen STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Verstoppen STR_BUY_VEHICLE_SHIP_HIDE_TOGGLE_BUTTON :{BLACK}Verstoppen STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :{BLACK}Verstoppen STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON :{BLACK}Uweisen STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}Uweisen STR_BUY_VEHICLE_SHIP_SHOW_TOGGLE_BUTTON :{BLACK}Uweisen STR_BUY_VEHICLE_AIRCRAFT_SHOW_TOGGLE_BUTTON :{BLACK}Uweisen STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Emschalten tëscht uweise/verstoppe vun Zuchtypen STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Emschalten tëscht uweise/verstoppe vu Gefiertypen STR_BUY_VEHICLE_SHIP_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Emschalten tëscht uweise/verstoppe vu Schëfftypen STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Emschalten tëscht uweise/verstoppe vu Fligertypen STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Zuchgefiertyp ëmbenennen STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Gefiertyp ëmbenennen STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Schëffstyp ëmbenennen STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Fligertyp ëmbenennen # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}Enner den Numm vum Schapp STR_DEPOT_RENAME_DEPOT_CAPTION :Schapp ëmbenennen STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} Gefier{P "" er}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Zich - zidd d'Gefier fir en unzehänken/wechzehuelen, Rietsklick fir Informatiounen. Ctrl unhalen dass béid Fonktiounen fir déi nächst Ketten gëllen STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Gefierer - Rietsklick op en Gefier fir Informatiounen STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Schëffer - Rietsklick op d'Schëff fir Informatiounen STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Fliger - Rietsklick op de Fliger fir Informatiounen STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Zéi den Zuch heihin fir en ze verkafen STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Zéi d'Stroossegefier heihin fir et ze verkafen STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Zéi d'Schëff heihin fir et ze verkafen STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Zéi de Fliger heihin fir en ze verkafen STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Lokomotiv heihinner zéien fir de ganzen Zuch ze läschen STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}All Zich am Schapp verkafen STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}All Gefier am Depot verkafen STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}All Schëff am Schapp verkafen STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}All Fliger am Hangar verkafen STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}All Zich am Schapp automatesch ersetzen STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}All Gefierer am Depot automatesch ersetzen STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}All Schëffer am Schapp automatesch ersetzen STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}All Fliger am Hangar automatesch ersetzen STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}Nei Zich STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}Nei Gefierer STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}Nei Schëffer STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}Nei Fligeren STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Kaf en neien Zuch STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Neit Stroossegefier kafen STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Neit Schëff kafen STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Neie Fliger kafen STR_DEPOT_CLONE_TRAIN :{BLACK}Zuch klonen STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Gefier klonen STR_DEPOT_CLONE_SHIP :{BLACK}Schëff klonen STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Fliger klonen STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}Dest baut eng Kopie vun engem Zuch mat all de Waggonen. Klick op dese Knäppchen an dann op en Zuch am Schapp oder baussen. Ctrl+Klick fir Opträg ze deelen. Shift+Klick weist ongeféier Käschten ouni Kaf STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Keeft eng Kopie vum Stroossegefier. Klick dese Kneppchen an dann op e Stroossegefier am oder baussent dem Depot. Ctrl+Klick deelt och d'Opträg. Shift+Klick weist ongeféier Käschten ouni Kaf STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}Dest baut eng Kopie vum Schëff. Klick op dese Knäppchen an dann op en Schëff am Schapp oder baussen.Ctrl+Klick kopéiert och d'Opträg. Shift+Klick weist ongeféier Käschten ouni Kaf STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}Dest baut eng Kopie vun engem Fliger. Klick op dese Knäppchen, an dann op en Fliger am Hangar oder baussen. Ctrl+Klick fir Uerder ze deelen. Shift+Klick weist ongeféier Käschten ouni Kaf STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op de Schapp. Ctrl+Klick erstellt eng nei Usiicht op de Schapp STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op den Depot. Ctrl+Klick erstellt eng nei Usiicht op den Depot STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op de Schapp. Ctrl+Klick erstellt eng nei Usiicht op de Schapp STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op den Hangar. Ctrl+Klick erstellt eng nei Usiicht op den Hangar STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Lëscht mat all Zich an dësem Schapp STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Lëscht mat all Gefierer an dësem Depot STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Lëscht mat all Schëffer an dësem Schapp STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Lëscht mat all Fliger am Hangar op dësem Fluchhafen STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Klick fir all Zich am Schapp ze stoppen STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klick fir all Gefierer am Depot ze stoppen STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Klick fir all Schëffer am Schapp ze stoppen STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Klick fir all Fliger am Hangar ze stoppen STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Klick fir all Zich am Schapp ze starten STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klick fir all Gefierer am Depot ze starten STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Klick fir all Schëff am Schapp ze starten STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Klick fir all Fliger am Hangar ze starten STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Du verkeefs grad all Gefierer am Schapp. Bass du sécher ? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Meldung vum Gefierkonstrukteur STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Mir hunn elo en neien {STRING} gebaut - bass du dorun interesséiert dëst Gefier 1 Joer exklusiv ze notzen, fir ze testen op et komplett maarträif ass? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :Lokomotiv STR_ENGINE_PREVIEW_ROAD_VEHICLE :Stroossegefier STR_ENGINE_PREVIEW_AIRCRAFT :Fliger STR_ENGINE_PREVIEW_SHIP :Schëff STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :Monorail Lokomotiv STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :Magnéitbunnlokomotiv STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Käschten: {CURRENCY_LONG} Gewiicht: {WEIGHT_SHORT}{}Geschwindegkeet: {VELOCITY} Kraaft: {POWER}{}Betribskäschten {CURRENCY_LONG}/Joer{}Kapazitéit: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Käschten: {CURRENCY_LONG} Gewicht: {WEIGHT_SHORT}{}Geschw.: {VELOCITY} Kraaft: {POWER} Max. T.E.: {6:FORCE}{}Betribskäschten: {4:CURRENCY_LONG}/Jr{}Kapazitéit: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Käschten: {CURRENCY_LONG} Max. Geschwindegkeet: {VELOCITY}{}Kapazitéit: {CARGO_LONG}, {CARGO_LONG}{}Betribskäschten {CURRENCY_LONG}/Joer STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Käschten: {CURRENCY_LONG} Max. Geschwindegkeet: {VELOCITY}{}Kapazitéit: {CARGO_LONG}{}Betribskäschten: {CURRENCY_LONG}/Joer STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Käschten: {CURRENCY_LONG} Max. Geschw.: {VELOCITY} Distanz: {COMMA} Felder{}Kapazitéit: {CARGO_LONG}, {CARGO_LONG}{}Betribskäschten: {CURRENCY_LONG}/Jr STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Käschten: {CURRENCY_LONG} Max. Geschw.: {VELOCITY} Distanz: {COMMA} Felder{}Kapazitéit: {CARGO_LONG}{}Betribskäschten: {CURRENCY_LONG}/Jr # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}Ersetz {STRING} - {STRING} STR_REPLACE_VEHICLE_TRAIN :Zuch STR_REPLACE_VEHICLE_ROAD_VEHICLE :Stroossegefier STR_REPLACE_VEHICLE_SHIP :Schëff STR_REPLACE_VEHICLE_AIRCRAFT :Fliger STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Gefierer am Gebrauch STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP :{BLACK}Kolonn mat Gefierer déis du hues STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Verfügbar Gefierer STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP :{BLACK}Kolonn mat Gefierer déi prett fir ze ersetze sinn STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Wielt de Maschinentyp fir auszetauschen STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Wielt den neien Typ de benotzt soll ginn amplaz vun der lénks gewielter Maschin STR_REPLACE_VEHICLES_START :{BLACK}Start Gefieraustosch STR_REPLACE_VEHICLES_NOW :All Gefier elo ersetzen STR_REPLACE_VEHICLES_WHEN_OLD :Nëmmen al Gefierer ersetzen STR_REPLACE_HELP_START_BUTTON :{BLACK}Drécken fir den Austosch vun der lénker mat der rietser Maschin unzefenken STR_REPLACE_NOT_REPLACING :{BLACK}Net ausgetosch: STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Keen gefier gewielt STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} wann al STR_REPLACE_VEHICLES_STOP :{BLACK}Stop Gefieraustosch STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Drécken fir den Austosch ze stoppen STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Tauschen aus: {ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Wiessel tëscht Maschin- an Waggonaustosch-Fënster STR_REPLACE_ENGINES :Lokomotiven STR_REPLACE_WAGONS :Waggonen STR_REPLACE_HELP_RAILTYPE :{BLACK}Wielt de Schinnentyp fir déi Lokomotiven ausgetosch ginn STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Weist un wellech Lokomotiv vun der lénks ugewielter Lokomotiv ausgetosch soll ginn, wann et zoutrëfft STR_REPLACE_RAIL_VEHICLES :Zich STR_REPLACE_ELRAIL_VEHICLES :Elektresch Zich STR_REPLACE_MONORAIL_VEHICLES :Monorail Gefierer STR_REPLACE_MAGLEV_VEHICLES :Magnéitbunn Gefierer STR_REPLACE_REMOVE_WAGON :{BLACK}Waggon raushuelen: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Mécht dass d'automatescht Austauschen d'Längt vum Zuch behält, an dem e Waggonen (vu lénks un) wechhëllt, wann d'Lok den Zuch ze laang mécht # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op den Zuch. Ctrl+Klick follegt dem Zuch an der Haaptusiicht STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op d'Gefier. Ctrl+Klick follegt dem Gefier an der Haaptusiicht STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op d'Schëff. Ctrl+Klick follegt dem Schëff an der Haaptusiicht STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Zentréiert d'Usiicht op de Fliger. Ctrl+Klick follegt dem Fliger an der Haaptusiicht STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Schéckt den Zuch an de Schapp. Ctrl+Klick fir nëmmen Revisioun STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Schéckt d'Gefier an den Depot. Ctrl+Klick fir nëmmen Revisioun STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Schéckt d'Schëff an de Schapp. Ctrl+Klick fir nëmmen Revisioun STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Schéckt de Fliger an den Hangar. Ctrl+Klick mécht nëmmen eng Revisioun STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Dëst baut eng Kopie vun engem Zuch mat all de Waggonen. Ctrl+Klick kopéiert och d'Opträg. Shift+Klick weist ongeféier Käschten ouni Kaf STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Baut eng Kopie vum Stroossegefier. Ctrl+Klick kopéiert och d'Opträg. Shift+Klick weist ongeféier Käschten ouni Kaf STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Dëst baut eng Kopie vum Schëff. Ctrl+Klick kopéiert och d'Opträg. Shift+Klick weist ongeféier Käschten ouni Kaf STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Dëst baut eng Kopie vum Fliger. Ctrl+Klick kopéiert och d'Opträg. Shift+Klick weist ongeféier Käschten ouni Kaf STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Zwéngt den Zuch durch d'Signal ze fueren STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Den Zuch upassen fir aaner Luedungen ze transportéieren STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Stroossegefier ëmbauen fir eng aner Wuer ze transportéiren STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Schëff ëmbauen fir aaner Luedungen ze transportéieren STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Fliger ëmbauen fir aaner Wueren ze transportéieren STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Richtung vum Zuch wiesselen STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Zwéngt d'Gefier ze dréinen STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Weist d'Opträg vum Zuch. Ctrl+Klick weist den Zäitplang STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Weist d'Opträg vum Gefier. Ctrl+Klick weist den Zäitplang STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Weist d'Opträg vum Schëff. Ctrl+Klick weist den Zäitplang STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Weist d'Opträg vum Fliger. Ctrl+Klick weist den Zäitplang STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Weist d'Detailer vum Zuch STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Weist Stroossegefier Detailer STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Weis Schëffsdetailer STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Weist d'Fligerdetailer STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Momentan Aktioun - klick hei fir den Zuch ze stoppen/starten. Ctrl+Klick fir op Destinatioun ze scrollen STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Momentan Aktioun - klick hei fir d'Gefier ze stoppen/starten. Ctrl+Klick fir op Destinatioun ze scrollen STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Momentan Aktioun - Klick hei fir d'Schëff ze stoppen/starten. Ctrl+Klick fir op Destinatioun ze scrollen STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Momentan Aktioun - Klick hei fir de Fliger ze stoppen/starten. Ctrl+Klick fir op Destinatioun ze scrollen # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Lueden / Entlueden STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Verloossen STR_VEHICLE_STATUS_CRASHED :{RED}Akzident! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Pann STR_VEHICLE_STATUS_STOPPED :{RED}Gestoppt STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Stoppt, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}Keng Energie STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Waard op en fräie Wee STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Ze wäit op nächst Destinatioun STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Ennerwee op {STATION}, {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}Keng Opträg, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Ennerwee op {WAYPOINT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Ennerwee an den {DEPOT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Revisioun am {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Gestoppt STR_VEHICLE_COMMAND_STOPPED :{RED}Gestoppt STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Gestart STR_VEHICLE_COMMAND_STARTED :{GREEN}Gestart # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Detailer) STR_VEHICLE_NAME_BUTTON :{BLACK}Numm STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Zuch benennen STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Stroossegefier benennen STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Schëff benennen STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Fliger benennen STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Alter: {LTBLUE}{STRING}{BLACK} Betribskäschten: {LTBLUE}{CURRENCY_LONG}/Joer # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} Joer ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} Joer ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Max. Geschwindegkeet: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Max. Geschw.: {LTBLUE}{VELOCITY} {BLACK}Distanz: {LTBLUE}{COMMA} Felder STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Gewiicht: {LTBLUE}{WEIGHT_SHORT} {BLACK}Kraaft: {LTBLUE}{POWER}{BLACK} Max. Geschwindegkeet: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Gewiicht: {LTBLUE}{WEIGHT_SHORT} {BLACK}Kraaft: {LTBLUE}{POWER}{BLACK} Max. Geschwindegkeet: {LTBLUE}{VELOCITY} {BLACK}Max. T.E.: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit dëst Joer: {LTBLUE}{CURRENCY_LONG} (lescht Joer: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Zouverlässegkeet: {LTBLUE}{COMMA}% {BLACK}Pannen säit leschter Revisioun: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Gebaut: {LTBLUE}{NUM}{BLACK} Wäert: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Kapazitéit: {LTBLUE}Keng{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Kapazitéit: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Kapazitéit: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Kapazitéit: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Transferts-Suen: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Revisiounsintervall: {LTBLUE}{COMMA}{NBSP}Deeg{BLACK} Lescht Revisioun: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Revisiounsintervall: {LTBLUE}{COMMA}%{BLACK} Lescht Revisioun: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Revisiounsintervall em 10 erhéijen. Ctrl+Klick erhéicht Intervall em 5 STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Revisiounsintervall em 10 erofsetzen. Ctrl+Klick setzt den Intervall em 5 rof STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Wiesselt de Revisiounsintervall STR_VEHICLE_DETAILS_DEFAULT :Standard STR_VEHICLE_DETAILS_DAYS :Deeg STR_VEHICLE_DETAILS_PERCENT :Prozent STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Zuch benennen STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Stroossegefier benennen STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Schëff benennen STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Fliger benennen # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Gebaut: {LTBLUE}{NUM}{BLACK} Wäert: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Wäert: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Total Kapazitéit fir dësen Zuch: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Eidel STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} vun {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} vun {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Luedung STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Weis d'Detailer vun der Luedung STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Informatioun STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Weist d'Detailer vun de Waggonen STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Kapazitéiten STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Weist d'Kapazitéite vun de Waggonen STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Total Luedung STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Weist d'Total Kapazitéit vum Zuch, opgedeelt op d'Wuerentypen STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Kapazitéit: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Refit) STR_REFIT_TITLE :{GOLD}Wielt de Luedungstyp: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Nei Kapazitéit: {GOLD}{CARGO_LONG}{}{BLACK}Käschten fir ëmzebauen: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}Nei Kapazitéit: {GOLD}{CARGO_LONG}{}{BLACK}Akommes vum Embau: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Nei Kapazitéit: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Käschten fir den Embau: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}Nei Kapazitéit: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Akommes vum Embau: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Wiel d'Gefierer fir den Embau. Mat der Maus zéien erlaabt den Embau vu méi Gefierer. Op eng eidel Plaz klicken wielt d'ganzt Gefier. Ctrl+Klick wielt e Gefier an de Rescht vun der Ketten STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Wielt d'Wuer déi transportéiert soll ginn STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Wielt den Typ vu Wueren fir d'Stroossegefier STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Wielt de Wuerentyp fir d'Schëff STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Wielt de Wuerentyp aus STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Zuch ëmbauen STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Stroossegefier ëmbauen STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Schëff ëmbauen STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Fliger ëmbauen STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Passt den Zuch un den ugewielten Luedungstyp un STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Stroossegefier ëmbauen fir déi gewielte Wuer ze transportéiren STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Schëff fir déi ugewielte Wuer ëmbauen STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Baut de Fliger fir den ugewieltenen Luedungstyp ëm # Order view STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Opträg) STR_ORDERS_TIMETABLE_VIEW :{BLACK}Zäitplang STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Wiesselt op d'Zäitplangunzeig STR_ORDERS_LIST_TOOLTIP :{BLACK}Optragslëscht - Klick op en Optrag fir en ze wielen. Ctrl+Klick scrollt op d'Optragdestinatioun STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - Enn vun den Opträg - - STR_ORDERS_END_OF_SHARED_ORDERS :- - Enn vun der Optragslëscht - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}Non-stop STR_ORDER_GO_TO :Géi op STR_ORDER_GO_NON_STOP_TO :Géi non-stop op STR_ORDER_GO_VIA :Géi via STR_ORDER_GO_NON_STOP_VIA :Géi non-stop iwwert STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Wiesselt d'Stoppen vun dem ungewielten Optrag STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Voll luede mat all Wuer STR_ORDER_DROP_LOAD_IF_POSSIBLE :Luede wa méiglech STR_ORDER_DROP_FULL_LOAD_ALL :Mat Allem voll lueden STR_ORDER_DROP_FULL_LOAD_ANY :Voll lueden mat all Wuer STR_ORDER_DROP_NO_LOADING :Net belueden STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Wiesselt d'Luedverhale vun dem ungewielten Optrag STR_ORDER_TOGGLE_UNLOAD :{BLACK}Alles entlueden STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Entluede wann akzeptéiert STR_ORDER_DROP_UNLOAD :Alles entlueden STR_ORDER_DROP_TRANSFER :Transferéieren STR_ORDER_DROP_NO_UNLOADING :Net entlueden STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Wiesselt d'Entluedverhale vun dem ungewielten Optrag STR_ORDER_REFIT :{BLACK}Ëmbauen STR_ORDER_REFIT_TOOLTIP :{BLACK}Wielt an wéi een Luedungstyp sollt emgebaut ginn. Ctrl+Klick fir den Ëmbau ze läschen STR_ORDER_REFIT_AUTO :{BLACK}Embauen an der Statioun STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Wiel wellëch Wuerentypen sollen auto-ersat ginn an dësem Optrag. Ctrl+Klick fir all Auto-Erneierungen wechzehuelen. Auto-Erneiern geht just wann d'Gefier ët erlaabt STR_ORDER_DROP_REFIT_AUTO :Festgelueten Wuer STR_ORDER_DROP_REFIT_AUTO_ANY :Verfügbar Wueren STR_ORDER_SERVICE :{BLACK}Revisioun STR_ORDER_DROP_GO_ALWAYS_DEPOT :Géi ëmmer STR_ORDER_DROP_SERVICE_DEPOT :Revisioun falls néideg STR_ORDER_DROP_HALT_DEPOT :Stop STR_ORDER_SERVICE_TOOLTIP :{BLACK}Iwwersprang dësen Optrag wann keng Revisioun néideg ass STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Gefierdaten als Basis fir den Optragssprong # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Prozent gelueden STR_ORDER_CONDITIONAL_RELIABILITY :Zouverlässegkeet STR_ORDER_CONDITIONAL_MAX_SPEED :Maximal Geschwindegkeet STR_ORDER_CONDITIONAL_AGE :Alter (Joer) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Brauch eng Revisioun STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Ëmmer STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Reschtlaafzäit (Joer) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Wéi Gefierdaten verglach solle ginn STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :ass gläich STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :ass net gläich STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :ass manner wéi STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :ass manner oder gläich wéi STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :ass méi wéi STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :ass méi oder gläich wéi STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :ass richteg (true) STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :ass falsch (false) STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}De Wäert dee mat de Gefierdaten verglach gëtt STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Wäert aginn fir ze vergläichen STR_ORDERS_SKIP_BUTTON :{BLACK}Iwwersprangen STR_ORDERS_SKIP_TOOLTIP :{BLACK}Iwwersprang de momentanen Optrag. CTRL+Klick iwwerspréngt op den ungewieltenen Optrag STR_ORDERS_DELETE_BUTTON :{BLACK}Läschen STR_ORDERS_DELETE_TOOLTIP :{BLACK}Läscht den ungewielten Optrag STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}All Opträg läschen STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}D'Deele stoppen STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Stop d'Deele vun der Optragslëscht. Ctrl+Klick lescht ausserdem all Opträg vun dësem Gefier STR_ORDERS_GO_TO_BUTTON :{BLACK}Géi op STR_ORDER_GO_TO_NEAREST_DEPOT :Géi an den nooste Schapp STR_ORDER_GO_TO_NEAREST_HANGAR :Géi an den noosten Hangar STR_ORDER_CONDITIONAL :Bedéngten Optragssprong STR_ORDER_SHARE :Opträg deelen STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Setzt en neien Optrag firun den ungewielten Optrag, oder un d'Enn vun der Lëscht. Ctrl setzt Statioun Opträg op voll lueden, Weepunkter op 'non-stop', an Schapp Opträg 'Revisioun'. Op en Gefier klicken, kopéiert d'Opträg vun dem Gefier STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Weis all Gefierer déi dësen Plang deelen # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Iwwert {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Géi non-stop via {WAYPOINT} STR_ORDER_SERVICE_AT :Revisioun am/an STR_ORDER_SERVICE_NON_STOP_AT :Revisioun non-stop am/an STR_ORDER_NEAREST_DEPOT :den noosten STR_ORDER_NEAREST_HANGAR :den noosten Hangar STR_ORDER_TRAIN_DEPOT :Zuchschapp STR_ORDER_ROAD_VEHICLE_DEPOT :Stroossegefier-Depot STR_ORDER_SHIP_DEPOT :Schëffsschapp STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(Ëmbau op {STRING}) STR_ORDER_REFIT_STOP_ORDER :(Ëmbau op {STRING} an stoppen) STR_ORDER_STOP_ORDER :(Stop) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(Implizit) STR_ORDER_FULL_LOAD :(Voll lueden) STR_ORDER_FULL_LOAD_ANY :(Voll lueden mat all Wuer) STR_ORDER_NO_LOAD :(Net lueden) STR_ORDER_UNLOAD :(Entlueden an Luedung huelen) STR_ORDER_UNLOAD_FULL_LOAD :(Entlueden an erem voll lueden) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Entlueden an mat all Wuer voll lueden) STR_ORDER_UNLOAD_NO_LOAD :(Entlueden an eidel loosen) STR_ORDER_TRANSFER :(Transferéieren an Lueden) STR_ORDER_TRANSFER_FULL_LOAD :(Transferéieren an voll lueden) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transferéieren an mat all Wuer voll lueden) STR_ORDER_TRANSFER_NO_LOAD :(Transferéieren an eidel loosen) STR_ORDER_NO_UNLOAD :(Net entlueden an Wueren lueden) STR_ORDER_NO_UNLOAD_FULL_LOAD :(Net entlueden an op voll Beluedung waarden) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Net entlueden an op iergendeng voll Beluedung waarden) STR_ORDER_NO_UNLOAD_NO_LOAD :(Keen Ent- an Belueden) STR_ORDER_AUTO_REFIT :(Embauen op {STRING}) STR_ORDER_FULL_LOAD_REFIT :(Voll lueden mat Embauen op {STRING}) STR_ORDER_FULL_LOAD_ANY_REFIT :(Voll lueden mat all Wueren mat Embauen op {STRING}) STR_ORDER_UNLOAD_REFIT :(Entlueden an Wueren lueden mat Embauen op {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Entlueden an op voll Luedung waarden mat Embauen op {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Entlueden an waard op iergendeng Volluedung mat Embauen op {STRING}) STR_ORDER_TRANSFER_REFIT :(Transfer an lued Wueren mat Auto-Embauen zu {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transfer an waard op Vollueden mat Auto-Embauen op {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transfer an waard op iergendeng Volluedung mat Auto-Embauen op {STRING}) STR_ORDER_NO_UNLOAD_REFIT :(Keen Entlueden an huel Wueren mat Auto-Embauen op {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Keen Entlueden an waard op Vollueden mat Auto-Embauen op {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Keen Entlueden an waard op iergendend Volluedung mat Auto-Embauen op {STRING}) STR_ORDER_AUTO_REFIT_ANY :verfügbar Wueren STR_ORDER_STOP_LOCATION_NEAR_END :[noosten Enn] STR_ORDER_STOP_LOCATION_MIDDLE :[Mëtt] STR_ORDER_STOP_LOCATION_FAR_END :[wäit Enn] STR_ORDER_OUT_OF_RANGE :{RED} (Nächst Destinatioun ass ze wäit fort) STR_ORDER_CONDITIONAL_UNCONDITIONAL :Sprang zum Optrag {COMMA} STR_ORDER_CONDITIONAL_NUM :Sprang zum Optrag {COMMA} wann {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :Sprang zum Optrag {COMMA} wann {STRING} {STRING} STR_INVALID_ORDER :{RED} (ongültegen Optrag) # Time table window STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Zäitplang) STR_TIMETABLE_ORDER_VIEW :{BLACK}Opträg STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Wiesselt op d'Opträgunzeig STR_TIMETABLE_TOOLTIP :{BLACK}Zäitplang - klick op en Optrag fir en ze wielen STR_TIMETABLE_NO_TRAVEL :Net ënnerwee STR_TIMETABLE_NOT_TIMETABLEABLE :Rees (automatesch; Zäitplang durch manuell Opträg) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Ënnerwee (ouni Zäitplang) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Fuer maximal {2:VELOCITY} (ouni Zäitplang) STR_TIMETABLE_TRAVEL_FOR :Ënnerwee während {STRING} STR_TIMETABLE_TRAVEL_FOR_SPEED :Fiert während {STRING} mat maximal {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Fuer (während {STRING}, ouni Zäitplang) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Fuer (während {STRING}, ouni Zäitplang) mat maximal {VELOCITY} STR_TIMETABLE_STAY_FOR_ESTIMATED :(bleif während {STRING}, ouni Zäitplang) STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(fuer während {STRING}, ouni Zäitplang) STR_TIMETABLE_STAY_FOR :an bleif fir {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :an ënnerwee während {STRING} STR_TIMETABLE_DAYS :{COMMA}{NBSP}D{P ag eeg} STR_TIMETABLE_TICKS :{COMMA}{NBSP}Tick{P "" en} STR_TIMETABLE_TOTAL_TIME :{BLACK}Dësen Zäitplang brauch {STRING} fir faërdeg ze ginn STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}Dësen Zäitplang brauch op manst {STRING} (net all geplangt) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}D'Gefier ass mat Zäit STR_TIMETABLE_STATUS_LATE :{BLACK}D'Gefier ass grad {STRING} ze spéit STR_TIMETABLE_STATUS_EARLY :{BLACK}D'Gefier ass grad {STRING} ze fréi STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}Dësen Zäitplang gouf nach net gestart STR_TIMETABLE_STATUS_START_AT :{BLACK}Dësen Zäitplang start um {STRING} STR_TIMETABLE_STARTING_DATE :{BLACK}Start Datum STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Wiel en Datum als Startpunkt fir dësen Zäitplang. Ctrl+Klick setzt de Startpunkt vun dësem Zäitplang an verdeelt et en gläichméisseg op all Gefierer déi dësen Optrag hunn, wann den Optrag komplett mat engem Zäitplang versinn ass STR_TIMETABLE_CHANGE_TIME :{BLACK}Zäit wiesselen STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Änner Zäit déi den ugewielten Optrag brauche soll STR_TIMETABLE_CLEAR_TIME :{BLACK}Zäit läschen STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Läsch Zäit fir de gewielten Optrag STR_TIMETABLE_CHANGE_SPEED :{BLACK}Änner de Geschwindegkeetslimit STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Änner d'maximal Reesgeschwindëgkeet fir de gewielten Optrag STR_TIMETABLE_CLEAR_SPEED :{BLACK}Geschwindegkeetslimit läschen STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Maximal Reesgeschwindegkeet vum gewielten Optrag läschen STR_TIMETABLE_RESET_LATENESS :{BLACK}Verspeidungszieler zerécksetzen STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Setzt de Verspéidungszieler zréck, sou dass d'Gefier mat Zäit ukënnt STR_TIMETABLE_AUTOFILL :{BLACK}Autofëllen STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fëll den Zäitplang automatesch mat de Wäerter vum nächsten Trajet (Ctrl+Klick fir Wardzäiten probéiren bäizehalen) STR_TIMETABLE_EXPECTED :{BLACK}Erwaard STR_TIMETABLE_SCHEDULED :{BLACK}Geplangt STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Tëschent erwaard a geplangt wiesselen STR_TIMETABLE_ARRIVAL_ABBREVIATION :A: STR_TIMETABLE_DEPARTURE_ABBREVIATION :D: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}Datum setzen STR_DATE_SET_DATE :{BLACK}Datum setzen STR_DATE_SET_DATE_TOOLTIP :{BLACK}De gewielten Datum als Startdatum fir den Zäitplang benotzen STR_DATE_DAY_TOOLTIP :{BLACK}Dag wielen STR_DATE_MONTH_TOOLTIP :{BLACK}Mount wielen STR_DATE_YEAR_TOOLTIP :{BLACK}Joer wielen # AI debug window STR_AI_DEBUG :{WHITE}KI /Spill-Script Debug STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Numm vun dem Script STR_AI_DEBUG_SETTINGS :{BLACK}Astellungen STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Script Astellungen änneren STR_AI_DEBUG_RELOAD :{BLACK}KI nei lueden STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}KI stoppen, Skript nei lueden, KI nei starten STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Erlab/Verbidd breaks wann en KI Log Message zum break string passt STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Break un/op: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Break un STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Wann en KI Log message zum String passt, pauséiert d'Spill STR_AI_DEBUG_MATCH_CASE :{BLACK}Passende Fall STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Wiessel tëscht passende Fäll beim vergläichen vu KI Log Messagen mam Break-String STR_AI_DEBUG_CONTINUE :{BLACK}Weider STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Entpaus an fuer weider mat der KI STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Debug-output fir dës KI uweisen STR_AI_GAME_SCRIPT :{BLACK}Spill-Script STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Check de Spill-Scipt-Log STR_ERROR_AI_NO_AI_FOUND :Keng passend KI fonnt fir ze lueden.{}Dës KI ass en Dummy an wäert näischt maachen.{}KI'en kënnen iwwert den 'Online Content' System downgeload ginn. STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}En Script ass ofgestierzt. W.e.g mellt dës dem Autor mat engem Screenshot vun der KI/Spill-Script Debugfënster STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}KI / Spill-Script Debugfënster ass nëmmen fir Serveren verfügbar # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}KI /Spill-Script Konfiguratioun STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}D'Spill-Script dat am nächsten Spill geluede gëtt STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}D'KIën déi am nächsten Spill geluede ginn STR_AI_CONFIG_HUMAN_PLAYER :Mënschleche Spiller STR_AI_CONFIG_RANDOM_AI :Zoufälleg KI STR_AI_CONFIG_NONE :(keng) STR_AI_CONFIG_MOVE_UP :{BLACK}No uewen setzen STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Gewielte KI an der Lëscht no uewen setzen STR_AI_CONFIG_MOVE_DOWN :{BLACK}Erof setzen STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Gewielte KI an der Lëscht no ënne setzen STR_AI_CONFIG_GAMESCRIPT :{SILVER}Spill-Script STR_AI_CONFIG_AI :{SILVER}KIën STR_AI_CONFIG_CHANGE :{BLACK}Wiel {STRING} aus STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :KI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Spill-Script STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Lued en aneren Script STR_AI_CONFIG_CONFIGURE :{BLACK}Konfiguréieren STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}All Parameter vun dem Script konfiguréieren # Available AIs window STR_AI_LIST_CAPTION :{WHITE}Verfügbar {STRING} STR_AI_LIST_CAPTION_AI :KIs STR_AI_LIST_CAPTION_GAMESCRIPT :Spill-Scripter STR_AI_LIST_TOOLTIP :{BLACK}Klick fir en Script auszewielen STR_AI_LIST_AUTHOR :{LTBLUE}Autor: {ORANGE}{STRING} STR_AI_LIST_VERSION :{LTBLUE}Versioun: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{STRING} STR_AI_LIST_ACCEPT :{BLACK}Akzeptéiert STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Wiel de markéierten Script STR_AI_LIST_CANCEL :{BLACK}Ofbriechen STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Script net änneren # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parameter STR_AI_SETTINGS_CAPTION_AI :KI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Spill-Script STR_AI_SETTINGS_CLOSE :{BLACK}Zoumaachen STR_AI_SETTINGS_RESET :{BLACK}Reset STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} STR_AI_SETTINGS_START_DELAY :Unzuel un Deeg wou des KI gestart gëtt no der leschter: {ORANGE}{STRING} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme vun {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} Changelog vun {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} Lizenz vun {STRING} STR_TEXTFILE_WRAP_TEXT :{WHITE}Text änneren STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Ännert den Text vun der Fënster esou dass alles erapasst ouni ze scrollen STR_TEXTFILE_VIEW_README :{BLACK}Readme liesen STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog STR_TEXTFILE_VIEW_LICENCE :{BLACK}Lizenz # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Käschten: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}Käschten: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Akommes: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}Akommes: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Transfert: {CURRENCY_LONG} STR_FEEDER :{YELLOW}Transfert: {CURRENCY_LONG} STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Transfert: {CURRENCY_LONG}{WHITE} / {GREEN}Akommes: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}Transfert: {CURRENCY_LONG}{WHITE} / {GREEN}Akommes: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Transfert: {CURRENCY_LONG}{WHITE} / {RED}Käschten: {CURRENCY_LONG} STR_FEEDER_COST :{YELLOW}Transfert: {CURRENCY_LONG}{WHITE} / {RED}Käschten: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Geschätzte Käschten: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Geschätzten Akommes: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Nach amgaangen ze späicheren. {} W.e.g. waarde bis daat fäerdeg ass! STR_ERROR_AUTOSAVE_FAILED :{WHITE}Fehler beim Autospäicheren STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Kann net um Laafwierk liesen STR_ERROR_GAME_SAVE_FAILED :{WHITE}Fehler beim Späicheren{}{STRING} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Kann d'Datei net läschen STR_ERROR_GAME_LOAD_FAILED :{WHITE}Fehler beim Lueden{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Interne Fehler: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Futtissen Spillstand - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Spillstand ass mat enger méi neier Versioun gemaach STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Datei net liesbar STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Datei net beschreiwbar STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Datenintegritéitfehler STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Spill gouf an enger Versioun ouni Tram support gesaved. All Tram gouf wechgeholl # Map generation messages STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Kaartenerstellung ofgebrach...{}... keng passend Stadplazen STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... et ass keng Stad an dësem Szenario STR_ERROR_PNGMAP :{WHITE}Kann d'Landschaft net vum PNG lueden... STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... Datei net fonnt STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... konnt de Bildtyp net konvertéieren. Brauch en 8 oder 24-bit PNG Bild. STR_ERROR_PNGMAP_MISC :{WHITE}... eppes ass schief gaangen (warscheinlech eng korrupt Datei) STR_ERROR_BMPMAP :{WHITE}Kann d'Landschaft net aus der BMP lueden... STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... konnt de Bildtyp net konvertéieren STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... Bild ass ze grouss STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Scaléirungswarnung STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Quellekaart zevill an der Gréisst änneren ass net ugeroden. Weiderman ? # Soundset messages STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Et gouf nëmmen en Ersatzsoundset fonnt. Wann Sounds erwënscht sinn, kënnen se iwwer den Downloadsystem installéiert ginn. # Screenshot related messages STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Riesenscreenshot STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}De Screenshot wäert eng Opléisung vun {COMMA} x {COMMA} Pixel hunn. Et kann e bëssen dauere bis en gemet ass. Wëllsde weiderman? STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Screenshot gespäichert als '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}Screenshotfehler! # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Meldung STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Matdeelung vun {STRING} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Ausserhalb vun der Kaart STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Ze noo um Rand vun der Kaart STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Net genuch Geld - des Aktioun kascht {CURRENCY_LONG} STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}D'Land muss flaach sinn STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land ass an déi falsch Richtung geneigt STR_ERROR_CAN_T_DO_THIS :{WHITE}Kann dat net maachen... STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Gebai muss fir d'éischt ofgerapt ginn STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Kann des Plaz net raumen... STR_ERROR_SITE_UNSUITABLE :{WHITE}... Plaz net gëeegent STR_ERROR_ALREADY_BUILT :{WHITE}... scho gebaut STR_ERROR_OWNED_BY :{WHITE}... am Besëtz vun {STRING} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... d'Plaz ass am Besëtz vun enger aanerer Firma STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... Limit fir d'Emformen vu Land erreecht STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... Limit fir d'Raume vu Felder erreecht STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... Limit fir Beem ze planzen erreecht STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Numm muss eenzegarteg sinn STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} am Wee STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Net erlaabt an der Paus # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}D'Gemeng {TOWN} wëll dat net erlaben STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}D'Gemeng {TOWN} erlaabt keen weidere Fluchhafen an der Stad STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}D'Gemeng {TOWN} refuséiert de Bau vum Fluchhafen wéinst Kaméidi STR_ERROR_BRIBE_FAILED :{WHITE}D'Bestiechung as enger regionaler Ennersichung opgefall # Levelling errors STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}Kann d'Land hei net unhiewen... STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Kann d'Land hei net erofsetzen... STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Kann d'Land net ebenen... STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Verdéiwung géif den Tunnel beschiedegen STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... schon op Mieresspigel STR_ERROR_TOO_HIGH :{WHITE}... ze héich STR_ERROR_ALREADY_LEVELLED :{WHITE}... scho flaach STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND :{WHITE}Dono wier d'Bréck ze héich fir dësen Terrain. # Company related errors STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Kann de Firmennumm net änneren... STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Kann den Numm vum Manager net änneren... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... maximale Kredit ass {CURRENCY_LONG} STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Kann net méi Geld léinen... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... keen Kredit zeréckzebezuelen STR_ERROR_CURRENCY_REQUIRED :{WHITE}... et ginn {CURRENCY_LONG} gebraucht STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Kann de Kredit net zeréckbezuelen... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Kann keng Suen ginn déi vun der Bank geléint sinn... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Kann d'Firma net kafen... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Kann d'Firmenhaaptgebai net bauen... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Kann keng 25% Undeeler vun dëser Firma kafen... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Kann keng 25% Undeeler vun dëser Firma verkafen... STR_ERROR_PROTECTED :{WHITE}Des Firma ass nach net al genuch fir Undeeler ze handelen... # Town related errors STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Ka keng Stied bauen STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Kann d'Stad net ëmbenennen... STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Kann d'Stad hei net bauen... STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Kann d'Stad net vergréisseren... STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... ze noo um Enn vun der Kaart STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... ze noo un enger anerer Stad STR_ERROR_TOO_MANY_TOWNS :{WHITE}... ze vill Stied STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... et ass keng Plaz méi op der Kaart STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}Stied bauen keng Stroossen. Du kanns de Bau iwwert Astellungen->Economie->Stied aschalten STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Stroossenarbeschten amgaangen STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Kann des Stad net läschen...{}Eng Statioun oder Schapp huet den Numm vun dëser Stad oder en Stéck dat der Stad gehéiert kann net ewechgeholl ginn STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... et gëtt keng gëeegent Plaz fir eng Statu am Stadzentrum # Industry related errors STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... zevill Industrien STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Kann keng Industrien bauen... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Kann {STRING} net hei bauen... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Kann deen Industrietyp hei net bauen... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... ze noo bei enger anerer Fabrik STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... muss fir d'éischt eng Stad bauen STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... nëmmen 1 pro Stad erlaabt STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... kann nëmmen an Stied mat op mannst 1200 Anwunner gebaut ginn STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... kann nëmmen am Reebësch gebaut ginn STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... kann nëmmen an der Wüst gebaut ginn STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... kann nëmmen a Stied gebaut ginn (ersetzt Haiser) STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... kann nëmmen an der Géigend vum Zentrum vun der Stad gebaut ginn STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... kann nëmmen an niddregen Beräicher gebaut ginn STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... kann nëmmen no un den Ecker vun der Kaart positionéiert ginn STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... Bësch kann nëmmen iwwert der Schnéilinn geplanzt ginn STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... kann nëmmen iwwert der Schnéilinn gebaut ginn STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... kann nëmmen ënnert der Schnéilinn gebaut ginn STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Et gouf keng brauchbar Plaz fir '{STRING}' Industrien fonnt STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Änner d'Parameter fir d'Kaartegeneratioun fir eng besser Kaart ze erstellen # Station construction related errors STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Kann d'Gare hei net bauen... STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Kann de Busarrêt hei net bauen... STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Kann d'Camionsgare net bauen... STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Kann d'Passagéier-Tramsarrêt net bauen... STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Kann d'Wueren-Tramstatioun net bauen... STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Kann den Dock hei net bauen... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Kann de Fluchhafen hei net bauen... STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Grenzt un méi wéi eng Gare un STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... Statioun ze ausgebreed STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Ze vill Garen/Luedstatiounen STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Ze vill Garesdeeler STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Ze vill Busarrêten STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Ze vill Camionsgaren STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Ze noo un enger aanerer Gare/Luedstatioun STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Ze noo un engem aanerem Hafen STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Ze noo un engem aaneren Fluchhafen STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Kann d'Statioun net ëmbenennen... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... d'Strooss ass am Besëtz vun der Stad STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... Strooss geet an dei falsch Richtung STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... Duerchfahrtstops kënnen keng Kéiren hunn STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... Duerchfahrtstops kënnen keng Kräizungen hunn # Station destruction related errors STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Kann den Deel vun der Gare net ofrappen... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Muss d'Gare fir d'éischt ofrappen STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Kann de Busarrêt net ofrappen... STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Kann d'Camionsgare net ofrappen... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Kann d'Tramstatioun net ofrappen... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Kann d'Wueren-Tramstatioun net ofrappen... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Busarrêt muss fir d'éischt wechgeholl ginn STR_ERROR_THERE_IS_NO_STATION :{WHITE}... et ass keng Statioun do STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Muss d'Gare fir d'éischt ofrappen STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Busarrêt muss fir d'éischt ofgerapt ginn STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Muss d'Camionsgare fir d'éischt ofrappen STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Muss d'Tramstatioun fir d'éischt ofrappen STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Muss d'Tramstatioun fir d'éischt ofrappen STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Muss den Hafen fir déischt ofrappen STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Muss de Fluchhafe fir d'éischt ofrappen # Waypoint related errors STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Grenzt un méi wéi een Weepunkt STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Ze no un engem aneren Weepunkt STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Kann keen Zuchweepunkt héi bauen... STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Kann Boje net hei plazéieren... STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Kann de Weepunktnumm net änneren... STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Kann de Wee-Punkt hei net ofrappen... STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Zuchweepunkt muss fir d'éischt ofgerappt ginn STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... Boje am Wee STR_ERROR_BUOY_IS_IN_USE :{WHITE}... Boje ass am Gebrauch vun enger anerer Firma! # Depot related errors STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Kann den Zuchschapp hei net bauen... STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Kann de Schapp hei net bauen... STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Kann den Tramschapp hei net bauen... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Kann de Schëffsschapp hei net bauen... STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Kann de Schapp net ëmbenennen STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... muss an engem Schapp gestoppt ginn STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... muss an engem Depot gestoppt ginn STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... muss an engem Schëffsschapp gestoppt ginn STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... muss an engem Hangar gestoppt ginn STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Zich kënnen nëmmen an engem Schapp verännert ginn STR_ERROR_TRAIN_TOO_LONG :{WHITE}Zuch ze laang STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Kann d'Gefier hei net ëmdréinen... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... ass aus e puer Eenheeten zesummegesat STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Onkompatibel Schinnentypen STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Kann d'Gefier net réckelen... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}D'hënnescht Maschinn geet ëmmer der viischter no. STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Kann de Wee an de Schapp net fannen STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Kann de Schapp net fannen STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Falschen Schapp-Typ # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} ass ze laang nom Auswiesselen STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Keng Autoerneierungsregel festgeluet. STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(Geldlimit) # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Onméiglech Streckenkombinatioun STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Signaler mussen fir d'éischt ewechgeholl ginn STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}Keng gëeegent Schinnen STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}D'Schinne musse fir d'éischt ewech STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}D'Strooss ass eng Einbahn oder blockéiert STR_ERROR_CROSSING_DISALLOWED :{WHITE}Barrièren si fir dësen Schinnentyp net erlaabt STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Kann d'Signaler hei net bauen... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Kann d'Schinnen hei net bauen... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Kann d'Schinnen hei net ewech huelen... STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Kann d'Signaler hei net ewech huelen... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Kann d'Signal hei net konvertéieren... STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... et si keng Schinnen do STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... et si keng Signaler do STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Kann de Schinnentyp hei net konvertéiren... # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Muss d'Strooss ewech huelen STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... Einbahnstroossen kënnen keng Kräizung hunn STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Kann d'Strooss hei net bauen... STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Kann den Tram hei net bauen... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Kann d'Strooss hei net ewech huelen... STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Kann den Tram net ewech huelen... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... et ass keng Strooss do STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... et ass keen Tram do # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Kann hei keen Kanal bauen... STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Kann d'Schleis hei net bauen... STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Kann hei kee Floss plazéiren... STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... muss op Waasser gebaut ginn STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... kann net op d'Waasser gebaut ginn STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... kann net op opener Séi bauen STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... kann net um Kanal bauen STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... kann net um Floss bauen STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Muss de Kanal fir d'éischt ofrappen STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Kann den Aquadukt hei net bauen... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... et ass schon e Bam hei STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... falschen Terrain fir dësen Typ bam STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Kann d'Beem hei net planzen... # Bridge related errors STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Kann d'Bréck hei net bauen... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Muss d'Bréck fir d'éischt ofrappen STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Kann net op der selwechter Plaz ufänken an ophalen STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Bréckenenner net op der selwechter Héicht STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Bréck ass ze déif fir dësen Terrain STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN :{WHITE}Bréck ass ze héich fir dësen Terrain. STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Start an Enn mussen op enger Linn sinn STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... dei zwee Enner vun der Bréck mussen u Land sinn STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... Bréck ze laang STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Bréck géif ausserhalb der Kaart ukommen # Tunnel related errors STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Kann den Tunnel hei net bauen... STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Plaz onpassend fir den Tunnelsagang STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Muss den Tunnel fir d'éischt ofrappen STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Aaneren Tunnel am Wee STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunnel géif ausserhalb der Kaart erauskommen STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Kann d'Land net fir dei aaner Säit vum Tunnel fräi leen STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... Tunnel ze laang # Object related errors STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... zevill Objeten STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Kann Objet net bauen... STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Objet am Wee STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... Firmen Haaptgebai am Wee STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Kann dat Land net kafen... STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... schon am Besëtz! # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Kann d'Grupp net erstellen... STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Kann d'Grupp net läschen... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Kann d'Grupp net ëmbenennen... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Kann iwwergeuerdent Grupp net setzen... STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Kann net all d'Gefierer aus der Grupp läschen... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Kann d'Gefier net bei d'Grupp bäisetzen... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Kann dei gedeelten Gefierer net bei d'Grupp bäisetzen... # Generic vehicle errors STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Zuch am Wee STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Stroossegefier am Wee STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Schëff am Wee STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Fliger am Wee STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Kann den Zuch net ëmbauen... STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Kann Stroossegefier net ëmbauen... STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Kann d'Schëff net ëmbauen... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Kann de Fliger net ëmbauen... STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Kann den Zuch net benennen... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Kann d'Stroossegefier net benennen... STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Kann d'Schëff net benennen... STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Kann de Fliger net benennen... STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Kann den Zuch net stoppen/starten... STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Kann d'Stroossegefier net stoppen/starten... STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}Kann d'Schëff net stoppen/starten... STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Kann de Fliger net stoppen/starten... STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Kann den Zuch net an de Schapp schécken... STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Kann d'Gefier net an den Depot schécken... STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Kann d'Schëff net an de Schapp schécken... STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Kann de Fliger net an den Hangar schécken... STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Kann den Zuch net bauen... STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Kann d'Stroossegefier net kafen... STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Kann Schëff net kafen... STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Kann de Fliger net kafen... STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Kann den Zuchgefiertyp net ëmbenennen... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Kann de Gefiertyp net ëmbenennen... STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Kann de Schëffstyp net ëmbenennen... STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Kann de Fligertyp net ëmbenennen... STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Kann den Zuch net verkafen... STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Kann d'Stroossegefier net verkafen... STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Kann Schëff net verkafen... STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Kann de Fliger net verkafen... STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Gefier net verfügbar STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Stroossegefier net verfügbar STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Schëff net verfügbar STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Fliger net verfügbar STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Ze vill Gefierer am Spill STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}De Service-Intervall kann net geännert ginn... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... Gefier ass zerstéiert STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}Keng Gefierer verfügbar STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Änner d'NewGRF Konfiguratioun STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}Nach keng Gefierer verfügbar STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}En neit Spill no {DATE_SHORT} ufenken oder benotz en NewGRF den al Gefierer erlaabt # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Kann den Zuch net bei Gefor durch d'Signal schécken... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Kann d'Richtung vum Zuch net änneren... STR_ERROR_TRAIN_START_NO_POWER :Zuch huet keng Kraaft STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Kann d'Stroossegefier net ëmdréinen... STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Fliger ass an der Loft # Order related errors STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}Keng Plaz méi fir Opträg STR_ERROR_TOO_MANY_ORDERS :{WHITE}Ze vill Opträg STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Kann keen neien Optrag bäisetzen... STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Kann den Optrag net läschen... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Kann den Optrag net änneren... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Kann den Optrag net réckelen... STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Kann den Optrag net iwwersprangen... STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Kann net op den ugewieltenen Optrag iwwersprangen... STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... Gefier kann net op all Statioun goen STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... Gefier kann net op déi Statioun goen STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... en Gefier dat dësen Optrag deelt kann net op déi Statioun goen STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Kann d'Optragslëscht net deelen... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Kann d'Deelen vun der Optragslëscht net stoppen... STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Kann d'Optragslëscht net kopéieren... STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... ze wäit ewech vu leschter Destinatioun STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... Fliger huet net genuch Distanz # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Kann dem Gefier keen Zäitplang ginn... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Gefierer kënnen nëmmen op Statiounen halen. STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}Dëst Gefier bleift net op dëser Statioun stoën. # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... ze vill Schëlder STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Kann d'Schëld hei net opriichten... STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Kann den Numm vum Schëld net änneren... STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Kann d'Schëld net läschen... # Translatable comment for OpenTTD's desktop shortcut STR_DESKTOP_SHORTCUT_COMMENT :Eng Simulatioun déi op Transport Tycoon Deluxe baséiert # Translatable descriptions in media/baseset/*.ob* files STR_BASEGRAPHICS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS Editioun Grafik. STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Original Transport Tycoon Deluxe DOS (Däitsch) Editioun Grafik. STR_BASEGRAPHICS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows Editioun Grafik. STR_BASESOUNDS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS Editioun Sound. STR_BASESOUNDS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows Editioun Sound. STR_BASESOUNDS_NONE_DESCRIPTION :E Soundpack ouni iergendee Sound. STR_BASEMUSIC_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows Editioun Musik. STR_BASEMUSIC_NONE_DESCRIPTION :E Musikpack ouni aktuell Musik. ##id 0x2000 # Town building names STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Héije Büroblock STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Büroblock STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Klengen Appartementsblock STR_TOWN_BUILDING_NAME_CHURCH_1 :Kierch STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Grousse Büroblock STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Stadhaiser STR_TOWN_BUILDING_NAME_HOTEL_1 :Hotel STR_TOWN_BUILDING_NAME_STATUE_1 :Statu STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Sprangbuer STR_TOWN_BUILDING_NAME_PARK_1 :Park STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Büroblock STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Geschäfter a Büroen STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Modernt Bürosgebai STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Lagerhaus STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Büroblock STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadion STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Al Haiser STR_TOWN_BUILDING_NAME_COTTAGES_1 :Hütten STR_TOWN_BUILDING_NAME_HOUSES_1 :Haiser STR_TOWN_BUILDING_NAME_FLATS_1 :Appartementer STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Héije Bürosblock STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Geschäfter a Büroen STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Geschäfter a Büroen STR_TOWN_BUILDING_NAME_THEATER_1 :Theater STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadion STR_TOWN_BUILDING_NAME_OFFICES_1 :Büroen STR_TOWN_BUILDING_NAME_HOUSES_2 :Haiser STR_TOWN_BUILDING_NAME_CINEMA_1 :Kino STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Akaafszentrum STR_TOWN_BUILDING_NAME_IGLOO_1 :Iglu STR_TOWN_BUILDING_NAME_TEPEES_1 :Tipien STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Téikaan-Haus STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Spuerschwäin-Bank ##id 0x4800 # industry names STR_INDUSTRY_NAME_COAL_MINE :Kuelestollen STR_INDUSTRY_NAME_POWER_STATION :Kraaftwierk STR_INDUSTRY_NAME_SAWMILL :Seeërei STR_INDUSTRY_NAME_FOREST :Bësch STR_INDUSTRY_NAME_OIL_REFINERY :Uelegraffinerie STR_INDUSTRY_NAME_OIL_RIG :Uelegbuerinsel STR_INDUSTRY_NAME_FACTORY :Fabrik STR_INDUSTRY_NAME_PRINTING_WORKS :Dréckerei STR_INDUSTRY_NAME_STEEL_MILL :Stolwierk STR_INDUSTRY_NAME_FARM :Bauerenhaff STR_INDUSTRY_NAME_COPPER_ORE_MINE :Kofferäerzstollen STR_INDUSTRY_NAME_OIL_WELLS :Uelegquellen STR_INDUSTRY_NAME_BANK :Bank STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Iessensverarbeschtungsfabrik STR_INDUSTRY_NAME_PAPER_MILL :Pabeierfabrik STR_INDUSTRY_NAME_GOLD_MINE :Goldstollen STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Bank STR_INDUSTRY_NAME_DIAMOND_MINE :Diamantstollen STR_INDUSTRY_NAME_IRON_ORE_MINE :Eisenäerzstollen STR_INDUSTRY_NAME_FRUIT_PLANTATION :Uebstplantage STR_INDUSTRY_NAME_RUBBER_PLANTATION :Kautschuckplantage STR_INDUSTRY_NAME_WATER_SUPPLY :Waasserwierk STR_INDUSTRY_NAME_WATER_TOWER :Waassertuerm STR_INDUSTRY_NAME_FACTORY_2 :Fabrik STR_INDUSTRY_NAME_FARM_2 :Bauerenhaff STR_INDUSTRY_NAME_LUMBER_MILL :Seewierk STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :Zockerwattbësch STR_INDUSTRY_NAME_CANDY_FACTORY :Séissegkeetenfabrik STR_INDUSTRY_NAME_BATTERY_FARM :Batteriefarm STR_INDUSTRY_NAME_COLA_WELLS :Colaquellen STR_INDUSTRY_NAME_TOY_SHOP :Spillgeschäft STR_INDUSTRY_NAME_TOY_FACTORY :Spillsaachen Fabrik STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :Plastikpëtz STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :Spruddelgedrenks Fabrik STR_INDUSTRY_NAME_BUBBLE_GENERATOR :Blosegenerator STR_INDUSTRY_NAME_TOFFEE_QUARRY :Karamellbroch STR_INDUSTRY_NAME_SUGAR_MINE :Zockerminn ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Onbenannt STR_SV_TRAIN_NAME :Zuch {COMMA} STR_SV_ROAD_VEHICLE_NAME :Stroossegefier {COMMA} STR_SV_SHIP_NAME :Schëff {COMMA} STR_SV_AIRCRAFT_NAME :Fliger {COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :{STRING} Norden STR_SV_STNAME_SOUTH :{STRING} Süden STR_SV_STNAME_EAST :{STRING} Osten STR_SV_STNAME_WEST :{STRING} Westen STR_SV_STNAME_CENTRAL :{STRING} Zentrum STR_SV_STNAME_TRANSFER :{STRING}er Transfert STR_SV_STNAME_HALT :{STRING}er Stopp STR_SV_STNAME_VALLEY :{STRING}er Dall STR_SV_STNAME_HEIGHTS :{STRING}er Bierg STR_SV_STNAME_WOODS :{STRING} beim Bësch STR_SV_STNAME_LAKESIDE :{STRING} um Séi STR_SV_STNAME_EXCHANGE :{STRING}er Wiessel STR_SV_STNAME_AIRPORT :{STRING}er Fluchhafen STR_SV_STNAME_OILFIELD :{STRING}er Uelegfeld STR_SV_STNAME_MINES :{STRING}er Minnen STR_SV_STNAME_DOCKS :{STRING} Hafen STR_SV_STNAME_BUOY :{STRING} STR_SV_STNAME_WAYPOINT :{STRING} ##id 0x6020 STR_SV_STNAME_ANNEXE :{STRING} Annex STR_SV_STNAME_SIDINGS :{STRING}er Ofstellgleis STR_SV_STNAME_BRANCH :{STRING}er Ofzweigung STR_SV_STNAME_UPPER :Uewer {STRING} STR_SV_STNAME_LOWER :Nidder {STRING} STR_SV_STNAME_HELIPORT :{STRING}er Heliport STR_SV_STNAME_FOREST :{STRING} Bësch STR_SV_STNAME_FALLBACK :{STRING} Statioun #{NUM} ############ end of savegame specific region! ##id 0x8000 # Vehicle names STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Damp) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Chu-Chu STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Chu-Chu STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Chu-Chu STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (Damp) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Damp) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Gresley 'A4' (Damp) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :BR '8P' (Damp) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Sprinter' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :EE '37' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Brush '47' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :BR 'IC125' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :BR '30' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :BR '40' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.G.V.' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'EuroStar' (Elektresch) STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Passagéierwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Postwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Kuelewaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Uelegwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Véiwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Wuerewaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Karwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Holzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Eisenäerzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Stolwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Gepanzerten Waggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Iesswuerenwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Pabeierwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Kofferäerzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Waasserwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Friichtewaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Kautschuckwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Zockerwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Zockerwattwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Karamellwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Blosenwaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Colawaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Séissegkeetewaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Spillsaachewaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Batteriewaggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Spruddelgedrénks Waggon STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Plastikwaggon STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Passagéierwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Postwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Kuelenwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Uelegwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Véiwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Wuerewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Karwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Holzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Eisenäerzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Stolwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :Gepanzerte Waggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Iesswuerewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Pabeierwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Kofferäerzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Waasserwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Friichtewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Kautschuckwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Zockerwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Zockerwattwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Karamellwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Blosenwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Colawaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Séissegkeetewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Spillsaachewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Batteriewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Spruddelgedrénkswaggon STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Plastikwaggon STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Elektresch) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Passagéierwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Postwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Kuelewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Uelegwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Véiwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Wuerewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Karwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Holzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Eisenäerzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Stolwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Gepanzerten Waggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Iesswuerewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Pabeierwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Kofferäerzwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Waasserwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Friichtewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Kautschuckwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Zockerwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Zockerwattwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Karamellwaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Blosewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Colawaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Séissegkeetewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Spillsaachewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Batteriewaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Spruddelgedrénkswaggon STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Plastikwaggon STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Bus STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Balogh Kuelecamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Uhl Kuelecamion STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :DW Kuelecamion STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :MPS Postcamion STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Reynard Postcamion STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Perry Postcamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :MightyMover Postcamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Powernaught Postcamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Wizzowow Postcamion STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Witcombe Uelegcamion STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Foster Uelegcamion STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Perry Uelegcamion STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Talbott Véitransporter STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Uhl Véitransporter STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Foster Véitransporter STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Balogh Wuerecamion STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Craighead Wuerecamion STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Goss Wuerecamion STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Hereford Karcamion STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Thomas Karcamion STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Goss Karcamion STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Witcombe Holzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Foster Holzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Moreland Holzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :MPS Eisenäerzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Uhl Eisenäerzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Chippy Eisenäerzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Balogh Stolcamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Uhl Stolcamion STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Kelling Stolcamion STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Balogh gepanzerte Camion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Uhl gepanzerte Camion STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Foster gepanzerte Camion STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Foster Iessenscamion STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Perry Iessenscamion STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Chippy Iessenscamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Uhl Pabeiercamion STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Balogh Pabeiercamion STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :MPS Pabeiercamion STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :MPS Kofferäerzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Uhl Kofferäerzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Goss Kofferäerzcamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Uhl Waassercamion STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Balogh Waassercamion STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :MPS Waassercamion STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Balogh Friichtecamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Uhl Friichtecamion STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kelling Friichtecamion STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Balogh Kautschuckcamion STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Uhl Kautschuckcamion STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :RMT Kautschuckcamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Zockercamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Powernaught Zockercamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Wizzowow Zockercamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :MightyMover Colacamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Powernaught Colacamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Wizzowow Colacamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :MightyMover Zockerwattcamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Powernaught Zockerwattcamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Zockerwattcamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Karamellcamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Karamellcamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Karamellcamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :MightyMover Spillsaachecamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Powernaught Spillsaachecamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Wizzowow Spillsaachecamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :MightyMover Séissegkeetecamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Powernaught Séissegkeetecamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Wizzowow Séissegkeetecamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Batteriecamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Powernaught Batteriecamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Wizzowow Batteriecamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :MightyMover Spruddelgedrénks Camion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Powernaught Spruddelgedrénks Camion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Spruddelgedrénks Camion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Plastikcamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Plastikcamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Plastikcamion STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Blosecamion STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Blosecamion STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Blosecamion STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :MPS Uelegtanker STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :CS-Inc. Uelegtanker STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :MPS Passagéierfähr STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :FFP Passagéierfähr STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Loftkësseboot STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Chugger-Chug Passagéierfähr STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Passagéierfähr STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Yate Frachtschëff STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Bakewell Frachtschëff STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :MightyMover Frachtschëff STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Powernaut Frachtschëff STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Boeing 727 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Boeing 737 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Boeing 747 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Boeing 757 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Boeing 767 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Boeing 777 STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airbus A300 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airbus A310 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airbus A320 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airbus A330 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :Airbus A340-1000 STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Tricario Helikopter STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Guru X2 Helikopter STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut Helikopter ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{STRING}-{STRING}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} STR_FORMAT_DATE_ISO :{2:NUM}-{1:STRING}-{0:STRING} STR_FORMAT_BUOY_NAME :{TOWN}-Boje STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Boje #{COMMA} STR_FORMAT_COMPANY_NUM :(Firma {COMMA}) STR_FORMAT_GROUP_NAME :Grupp {COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :Weepunkt {TOWN} STR_FORMAT_WAYPOINT_NAME_SERIAL :Weepunkt {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_TRAIN :Zuchschapp vun {TOWN} STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :{TOWN} Zuchschapp #{COMMA} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :Stroossegefierdepot vun {TOWN} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :{TOWN} Stroossendepot #{COMMA} STR_FORMAT_DEPOT_NAME_SHIP :Schëffsschapp vun {TOWN} STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :{TOWN} Schëffsschapp #{COMMA} STR_FORMAT_DEPOT_NAME_AIRCRAFT :{STATION} Hangar STR_UNKNOWN_STATION :onbekannt Statioun STR_DEFAULT_SIGN_NAME :Schëld STR_COMPANY_SOMEONE :iergendeen STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING} STR_SAVEGAME_NAME_SPECTATOR :Zuschauer, {1:STRING} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} STR_VIEWPORT_WAYPOINT :{WAYPOINT} STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} STR_DEPOT_NAME :{DEPOT} STR_ENGINE_NAME :{ENGINE} STR_HIDDEN_ENGINE_NAME :{ENGINE} (verstoppt) STR_GROUP_NAME :{GROUP} STR_INDUSTRY_NAME :{INDUSTRY} STR_PRESIDENT_NAME :{PRESIDENT_NAME} STR_SIGN_NAME :{SIGN} STR_STATION_NAME :{STATION} STR_TOWN_NAME :{TOWN} STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} STR_JUST_DATE_LONG :{DATE_LONG} STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} # Slightly 'raw' stringcodes with colour or size STR_BLACK_COMMA :{BLACK}{COMMA} STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} STR_TINY_COMMA :{TINY_FONT}{COMMA} STR_BLUE_COMMA :{BLUE}{COMMA} STR_RED_COMMA :{RED}{COMMA} STR_WHITE_COMMA :{WHITE}{COMMA} STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} STR_TINY_GROUP :{TINY_FONT}{GROUP} STR_BLACK_INT :{BLACK}{NUM} STR_ORANGE_INT :{ORANGE}{NUM} STR_WHITE_SIGN :{WHITE}{SIGN} STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} STR_BLACK_STRING :{BLACK}{STRING} STR_BLACK_RAW_STRING :{BLACK}{STRING} STR_ORANGE_STRING :{ORANGE}{STRING} STR_LTBLUE_STRING :{LTBLUE}{STRING} STR_WHITE_STRING :{WHITE}{STRING} STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING}{WHITE} STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING}{LTBLUE} STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} STR_BLACK_1 :{BLACK}1 STR_BLACK_2 :{BLACK}2 STR_BLACK_3 :{BLACK}3 STR_BLACK_4 :{BLACK}4 STR_BLACK_5 :{BLACK}5 STR_BLACK_6 :{BLACK}6 STR_BLACK_7 :{BLACK}7 STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) openttd-1.5.3/src/lang/english.txt0000644000000000000000000150317312627373445015624 0ustar rootroot##name English (UK) ##ownname English (UK) ##isocode en_GB ##plural 0 ##textdir ltr ##digitsep , ##digitsepcur , ##decimalsep . ##winlangid 0x0809 ##grflangid 0x01 # $Id: english.txt 27353 2015-07-31 17:46:09Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(undefined string) STR_JUST_NOTHING :Nothing # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :Passengers STR_CARGO_PLURAL_COAL :Coal STR_CARGO_PLURAL_MAIL :Mail STR_CARGO_PLURAL_OIL :Oil STR_CARGO_PLURAL_LIVESTOCK :Livestock STR_CARGO_PLURAL_GOODS :Goods STR_CARGO_PLURAL_GRAIN :Grain STR_CARGO_PLURAL_WOOD :Wood STR_CARGO_PLURAL_IRON_ORE :Iron Ore STR_CARGO_PLURAL_STEEL :Steel STR_CARGO_PLURAL_VALUABLES :Valuables STR_CARGO_PLURAL_COPPER_ORE :Copper Ore STR_CARGO_PLURAL_MAIZE :Maize STR_CARGO_PLURAL_FRUIT :Fruit STR_CARGO_PLURAL_DIAMONDS :Diamonds STR_CARGO_PLURAL_FOOD :Food STR_CARGO_PLURAL_PAPER :Paper STR_CARGO_PLURAL_GOLD :Gold STR_CARGO_PLURAL_WATER :Water STR_CARGO_PLURAL_WHEAT :Wheat STR_CARGO_PLURAL_RUBBER :Rubber STR_CARGO_PLURAL_SUGAR :Sugar STR_CARGO_PLURAL_TOYS :Toys STR_CARGO_PLURAL_CANDY :Sweets STR_CARGO_PLURAL_COLA :Cola STR_CARGO_PLURAL_COTTON_CANDY :Candyfloss STR_CARGO_PLURAL_BUBBLES :Bubbles STR_CARGO_PLURAL_TOFFEE :Toffee STR_CARGO_PLURAL_BATTERIES :Batteries STR_CARGO_PLURAL_PLASTIC :Plastic STR_CARGO_PLURAL_FIZZY_DRINKS :Fizzy Drinks # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :Passenger STR_CARGO_SINGULAR_COAL :Coal STR_CARGO_SINGULAR_MAIL :Mail STR_CARGO_SINGULAR_OIL :Oil STR_CARGO_SINGULAR_LIVESTOCK :Livestock STR_CARGO_SINGULAR_GOODS :Goods STR_CARGO_SINGULAR_GRAIN :Grain STR_CARGO_SINGULAR_WOOD :Wood STR_CARGO_SINGULAR_IRON_ORE :Iron Ore STR_CARGO_SINGULAR_STEEL :Steel STR_CARGO_SINGULAR_VALUABLES :Valuables STR_CARGO_SINGULAR_COPPER_ORE :Copper Ore STR_CARGO_SINGULAR_MAIZE :Maize STR_CARGO_SINGULAR_FRUIT :Fruit STR_CARGO_SINGULAR_DIAMOND :Diamond STR_CARGO_SINGULAR_FOOD :Food STR_CARGO_SINGULAR_PAPER :Paper STR_CARGO_SINGULAR_GOLD :Gold STR_CARGO_SINGULAR_WATER :Water STR_CARGO_SINGULAR_WHEAT :Wheat STR_CARGO_SINGULAR_RUBBER :Rubber STR_CARGO_SINGULAR_SUGAR :Sugar STR_CARGO_SINGULAR_TOY :Toy STR_CARGO_SINGULAR_CANDY :Sweet STR_CARGO_SINGULAR_COLA :Cola STR_CARGO_SINGULAR_COTTON_CANDY :Candyfloss STR_CARGO_SINGULAR_BUBBLE :Bubble STR_CARGO_SINGULAR_TOFFEE :Toffee STR_CARGO_SINGULAR_BATTERY :Battery STR_CARGO_SINGULAR_PLASTIC :Plastic STR_CARGO_SINGULAR_FIZZY_DRINK :Fizzy Drink # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA}{NBSP}passenger{P "" s} STR_QUANTITY_COAL :{WEIGHT_LONG} of coal STR_QUANTITY_MAIL :{COMMA}{NBSP}bag{P "" s} of mail STR_QUANTITY_OIL :{VOLUME_LONG} of oil STR_QUANTITY_LIVESTOCK :{COMMA}{NBSP}item{P "" s} of livestock STR_QUANTITY_GOODS :{COMMA}{NBSP}crate{P "" s} of goods STR_QUANTITY_GRAIN :{WEIGHT_LONG} of grain STR_QUANTITY_WOOD :{WEIGHT_LONG} of wood STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} of iron ore STR_QUANTITY_STEEL :{WEIGHT_LONG} of steel STR_QUANTITY_VALUABLES :{COMMA}{NBSP}bag{P "" s} of valuables STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} of copper ore STR_QUANTITY_MAIZE :{WEIGHT_LONG} of maize STR_QUANTITY_FRUIT :{WEIGHT_LONG} of fruit STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}bag{P "" s} of diamonds STR_QUANTITY_FOOD :{WEIGHT_LONG} of food STR_QUANTITY_PAPER :{WEIGHT_LONG} of paper STR_QUANTITY_GOLD :{COMMA}{NBSP}bag{P "" s} of gold STR_QUANTITY_WATER :{VOLUME_LONG} of water STR_QUANTITY_WHEAT :{WEIGHT_LONG} of wheat STR_QUANTITY_RUBBER :{VOLUME_LONG} of rubber STR_QUANTITY_SUGAR :{WEIGHT_LONG} of sugar STR_QUANTITY_TOYS :{COMMA}{NBSP}toy{P "" s} STR_QUANTITY_SWEETS :{COMMA}{NBSP}bag{P "" s} of sweets STR_QUANTITY_COLA :{VOLUME_LONG} of cola STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} of candyfloss STR_QUANTITY_BUBBLES :{COMMA} bubble{P "" s} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} of toffee STR_QUANTITY_BATTERIES :{COMMA} batter{P y ies} STR_QUANTITY_PLASTIC :{VOLUME_LONG} of plastic STR_QUANTITY_FIZZY_DRINKS :{COMMA} fizzy drink{P "" s} STR_QUANTITY_N_A :N/A # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}PS STR_ABBREV_COAL :{TINY_FONT}CL STR_ABBREV_MAIL :{TINY_FONT}ML STR_ABBREV_OIL :{TINY_FONT}OL STR_ABBREV_LIVESTOCK :{TINY_FONT}LV STR_ABBREV_GOODS :{TINY_FONT}GD STR_ABBREV_GRAIN :{TINY_FONT}GR STR_ABBREV_WOOD :{TINY_FONT}WD STR_ABBREV_IRON_ORE :{TINY_FONT}OR STR_ABBREV_STEEL :{TINY_FONT}ST STR_ABBREV_VALUABLES :{TINY_FONT}VL STR_ABBREV_COPPER_ORE :{TINY_FONT}CO STR_ABBREV_MAIZE :{TINY_FONT}MZ STR_ABBREV_FRUIT :{TINY_FONT}FT STR_ABBREV_DIAMONDS :{TINY_FONT}DM STR_ABBREV_FOOD :{TINY_FONT}FD STR_ABBREV_PAPER :{TINY_FONT}PR STR_ABBREV_GOLD :{TINY_FONT}GD STR_ABBREV_WATER :{TINY_FONT}WR STR_ABBREV_WHEAT :{TINY_FONT}WH STR_ABBREV_RUBBER :{TINY_FONT}RB STR_ABBREV_SUGAR :{TINY_FONT}SG STR_ABBREV_TOYS :{TINY_FONT}TY STR_ABBREV_SWEETS :{TINY_FONT}SW STR_ABBREV_COLA :{TINY_FONT}CL STR_ABBREV_CANDYFLOSS :{TINY_FONT}CF STR_ABBREV_BUBBLES :{TINY_FONT}BU STR_ABBREV_TOFFEE :{TINY_FONT}TF STR_ABBREV_BATTERIES :{TINY_FONT}BA STR_ABBREV_PLASTIC :{TINY_FONT}PL STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}FZ STR_ABBREV_NONE :{TINY_FONT}NO STR_ABBREV_ALL :{TINY_FONT}ALL # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA}{NBSP}passenger{P "" s} STR_BAGS :{COMMA}{NBSP}bag{P "" s} STR_TONS :{COMMA}{NBSP}tonne{P "" s} STR_LITERS :{COMMA}{NBSP}litre{P "" s} STR_ITEMS :{COMMA}{NBSP}item{P "" s} STR_CRATES :{COMMA}{NBSP}crate{P "" s} # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Dark Blue STR_COLOUR_PALE_GREEN :Pale Green STR_COLOUR_PINK :Pink STR_COLOUR_YELLOW :Yellow STR_COLOUR_RED :Red STR_COLOUR_LIGHT_BLUE :Light Blue STR_COLOUR_GREEN :Green STR_COLOUR_DARK_GREEN :Dark Green STR_COLOUR_BLUE :Blue STR_COLOUR_CREAM :Cream STR_COLOUR_MAUVE :Mauve STR_COLOUR_PURPLE :Purple STR_COLOUR_ORANGE :Orange STR_COLOUR_BROWN :Brown STR_COLOUR_GREY :Grey STR_COLOUR_WHITE :White # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mph STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}hp STR_UNITS_POWER_METRIC :{COMMA}{NBSP}hp STR_UNITS_POWER_SI :{COMMA}{NBSP}kW STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}{NBSP}kg STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA}{NBSP}ton{P "" s} STR_UNITS_WEIGHT_LONG_METRIC :{COMMA}{NBSP}tonne{P "" s} STR_UNITS_WEIGHT_LONG_SI :{COMMA}{NBSP}kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}{NBSP}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}{NBSP}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}{NBSP}m³ STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA}{NBSP}gallon{P "" s} STR_UNITS_VOLUME_LONG_METRIC :{COMMA}{NBSP}litre{P "" s} STR_UNITS_VOLUME_LONG_SI :{COMMA}{NBSP}m³ STR_UNITS_FORCE_IMPERIAL :{COMMA}{NBSP}lbf STR_UNITS_FORCE_METRIC :{COMMA}{NBSP}kgf STR_UNITS_FORCE_SI :{COMMA}{NBSP}kN STR_UNITS_HEIGHT_IMPERIAL :{COMMA}{NBSP}ft STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Filter string: STR_LIST_FILTER_OSKTITLE :{BLACK}Enter filter string STR_LIST_FILTER_TOOLTIP :{BLACK}Enter a keyword to filter the list for STR_TOOLTIP_GROUP_ORDER :{BLACK}Select grouping order STR_TOOLTIP_SORT_ORDER :{BLACK}Select sorting order (descending/ascending) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Select sorting criteria STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Select filtering criteria STR_BUTTON_SORT_BY :{BLACK}Sort by STR_BUTTON_LOCATION :{BLACK}Location STR_BUTTON_RENAME :{BLACK}Rename STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Close window STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Window title - drag this to move window STR_TOOLTIP_SHADE :{BLACK}Shade window - only show the title bar STR_TOOLTIP_DEBUG :{BLACK}Show NewGRF debug information STR_TOOLTIP_DEFSIZE :{BLACK}Resize window to default size. Ctrl+Click to store current size as default STR_TOOLTIP_STICKY :{BLACK}Mark this window as uncloseable by the 'Close All Windows' key. Ctrl+Click to also save state as default STR_TOOLTIP_RESIZE :{BLACK}Click and drag to resize this window STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Toggle large/small window size STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll bar - scrolls list up/down STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Scroll bar - scrolls list left/right STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Demolish buildings etc. on a square of land. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate # Show engines button STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Show hidden STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Show hidden STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP :{BLACK}Show hidden STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT :{BLACK}Show hidden STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP :{BLACK}By enabling this button, the hidden train vehicles are also displayed STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE_TOOLTIP :{BLACK}By enabling this button, the hidden road vehicles are also displayed STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP_TOOLTIP :{BLACK}By enabling this button, the hidden ships are also displayed STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}By enabling this button, the hidden aircraft are also displayed # Query window STR_BUTTON_DEFAULT :{BLACK}Default STR_BUTTON_CANCEL :{BLACK}Cancel STR_BUTTON_OK :{BLACK}OK # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}Length: {NUM} STR_MEASURE_AREA :{BLACK}Area: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Length: {NUM}{}Height difference: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Area: {NUM} x {NUM}{}Height difference: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}Name STR_SORT_BY_CAPTION_DATE :{BLACK}Date # These are used in dropdowns STR_SORT_BY_NAME :Name STR_SORT_BY_PRODUCTION :Production STR_SORT_BY_TYPE :Type STR_SORT_BY_TRANSPORTED :Transported STR_SORT_BY_NUMBER :Number STR_SORT_BY_PROFIT_LAST_YEAR :Profit last year STR_SORT_BY_PROFIT_THIS_YEAR :Profit this year STR_SORT_BY_AGE :Age STR_SORT_BY_RELIABILITY :Reliability STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :Total capacity per cargo type STR_SORT_BY_MAX_SPEED :Maximum speed STR_SORT_BY_MODEL :Model STR_SORT_BY_VALUE :Value STR_SORT_BY_LENGTH :Length STR_SORT_BY_LIFE_TIME :Remaining lifetime STR_SORT_BY_TIMETABLE_DELAY :Timetable delay STR_SORT_BY_FACILITY :Station type STR_SORT_BY_WAITING_TOTAL :Total waiting cargo STR_SORT_BY_WAITING_AVAILABLE :Available waiting cargo STR_SORT_BY_RATING_MAX :Highest cargo rating STR_SORT_BY_RATING_MIN :Lowest cargo rating STR_SORT_BY_ENGINE_ID :EngineID (classic sort) STR_SORT_BY_COST :Cost STR_SORT_BY_POWER :Power STR_SORT_BY_TRACTIVE_EFFORT :Tractive effort STR_SORT_BY_INTRO_DATE :Introduction date STR_SORT_BY_RUNNING_COST :Running cost STR_SORT_BY_POWER_VS_RUNNING_COST :Power/Running cost STR_SORT_BY_CARGO_CAPACITY :Cargo capacity STR_SORT_BY_RANGE :Range STR_SORT_BY_POPULATION :Population STR_SORT_BY_RATING :Rating # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pause game STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Fast forward the game STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Options STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Save game, abandon game, exit STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Display map, extra viewport or list of signs STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Display town directory STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Display subsidies STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Display list of company's stations STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Display company finances information STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Display general company information STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Display story book STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Display goal list STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Display graphs STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Display company league table STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Fund construction of new industry or list all industries STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Display list of company's trains. Ctrl+Click toggles opening the group/vehicle list STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Display list of company's road vehicles. Ctrl+Click toggles opening the group/vehicle list STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Display list of company's ships. Ctrl+Click toggles opening the group/vehicle list STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Display list of company's aircraft. Ctrl+Click toggles opening the group/vehicle list STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Zoom the view in STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Zoom the view out STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Build roads STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Build ship docks STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Build airports STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Open the landscaping toolbar to raise/lower land, plant trees, etc. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Show sound/music window STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Show last message/news report, show message options STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Land area information, console, script debug, screenshots, about OpenTTD STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Switch toolbars # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Save scenario, load scenario, abandon scenario editor, exit STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}Scenario Editor STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Move the starting date backward 1 year STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Move the starting date forward 1 year STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Click to enter the starting year STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Display map, town directory STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Landscape generation STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Town generation STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Industry generation STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Road construction STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plant trees. Shift toggles building/showing cost estimate STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Place sign STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Place object. Shift toggles building/showing cost estimate ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Save scenario STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Load scenario STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Save heightmap STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Load heightmap STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Abandon scenario editor STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Exit ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :Game options STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Settings STR_SETTINGS_MENU_SCRIPT_SETTINGS :AI/Game script settings STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF settings STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparency options STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Town names displayed STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Station names displayed STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Waypoint names displayed STR_SETTINGS_MENU_SIGNS_DISPLAYED :Signs displayed STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Competitor signs and names displayed STR_SETTINGS_MENU_FULL_ANIMATION :Full animation STR_SETTINGS_MENU_FULL_DETAIL :Full detail STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Transparent buildings STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Transparent signs ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Save game STR_FILE_MENU_LOAD_GAME :Load game STR_FILE_MENU_QUIT_GAME :Abandon game STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Exit ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :Map of world STR_MAP_MENU_EXTRA_VIEW_PORT :Extra viewport STR_MAP_MENU_LINGRAPH_LEGEND :Cargo Flow Legend STR_MAP_MENU_SIGN_LIST :Sign list ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Town directory STR_TOWN_MENU_FOUND_TOWN :Found town ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :Subsidies ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Operating profit graph STR_GRAPH_MENU_INCOME_GRAPH :Income graph STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Delivered cargo graph STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Performance history graph STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Company value graph STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Cargo payment rates ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Company league table STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detailed performance rating STR_GRAPH_MENU_HIGHSCORE :Highscore table ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Industry directory STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Industry chains STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Fund new industry ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Railway construction STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Electrified railway construction STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Monorail construction STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Maglev construction ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Road construction STR_ROAD_MENU_TRAM_CONSTRUCTION :Tramway construction ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Waterways construction ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Airport construction ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :Landscaping STR_LANDSCAPING_MENU_PLANT_TREES :Plant trees STR_LANDSCAPING_MENU_PLACE_SIGN :Place sign ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :Sound/music ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Last message/news report STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Message history ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Land area information STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :Toggle console STR_ABOUT_MENU_AI_DEBUG :AI/Game script debug STR_ABOUT_MENU_SCREENSHOT :Screenshot STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Fully zoomed in screenshot STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Default zoom screenshot STR_ABOUT_MENU_GIANT_SCREENSHOT :Whole map screenshot STR_ABOUT_MENU_ABOUT_OPENTTD :About 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Sprite aligner STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Toggle bounding boxes STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Toggle colouring of dirty blocks ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :1st STR_ORDINAL_NUMBER_2ND :2nd STR_ORDINAL_NUMBER_3RD :3rd STR_ORDINAL_NUMBER_4TH :4th STR_ORDINAL_NUMBER_5TH :5th STR_ORDINAL_NUMBER_6TH :6th STR_ORDINAL_NUMBER_7TH :7th STR_ORDINAL_NUMBER_8TH :8th STR_ORDINAL_NUMBER_9TH :9th STR_ORDINAL_NUMBER_10TH :10th STR_ORDINAL_NUMBER_11TH :11th STR_ORDINAL_NUMBER_12TH :12th STR_ORDINAL_NUMBER_13TH :13th STR_ORDINAL_NUMBER_14TH :14th STR_ORDINAL_NUMBER_15TH :15th ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :1st STR_DAY_NUMBER_2ND :2nd STR_DAY_NUMBER_3RD :3rd STR_DAY_NUMBER_4TH :4th STR_DAY_NUMBER_5TH :5th STR_DAY_NUMBER_6TH :6th STR_DAY_NUMBER_7TH :7th STR_DAY_NUMBER_8TH :8th STR_DAY_NUMBER_9TH :9th STR_DAY_NUMBER_10TH :10th STR_DAY_NUMBER_11TH :11th STR_DAY_NUMBER_12TH :12th STR_DAY_NUMBER_13TH :13th STR_DAY_NUMBER_14TH :14th STR_DAY_NUMBER_15TH :15th STR_DAY_NUMBER_16TH :16th STR_DAY_NUMBER_17TH :17th STR_DAY_NUMBER_18TH :18th STR_DAY_NUMBER_19TH :19th STR_DAY_NUMBER_20TH :20th STR_DAY_NUMBER_21ST :21st STR_DAY_NUMBER_22ND :22nd STR_DAY_NUMBER_23RD :23rd STR_DAY_NUMBER_24TH :24th STR_DAY_NUMBER_25TH :25th STR_DAY_NUMBER_26TH :26th STR_DAY_NUMBER_27TH :27th STR_DAY_NUMBER_28TH :28th STR_DAY_NUMBER_29TH :29th STR_DAY_NUMBER_30TH :30th STR_DAY_NUMBER_31ST :31st ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :Jan STR_MONTH_ABBREV_FEB :Feb STR_MONTH_ABBREV_MAR :Mar STR_MONTH_ABBREV_APR :Apr STR_MONTH_ABBREV_MAY :May STR_MONTH_ABBREV_JUN :Jun STR_MONTH_ABBREV_JUL :Jul STR_MONTH_ABBREV_AUG :Aug STR_MONTH_ABBREV_SEP :Sep STR_MONTH_ABBREV_OCT :Oct STR_MONTH_ABBREV_NOV :Nov STR_MONTH_ABBREV_DEC :Dec STR_MONTH_JAN :January STR_MONTH_FEB :February STR_MONTH_MAR :March STR_MONTH_APR :April STR_MONTH_MAY :May STR_MONTH_JUN :June STR_MONTH_JUL :July STR_MONTH_AUG :August STR_MONTH_SEP :September STR_MONTH_OCT :October STR_MONTH_NOV :November STR_MONTH_DEC :December ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}Key STR_GRAPH_KEY_TOOLTIP :{BLACK}Show key to graphs STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING2} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Operating Profit Graph STR_GRAPH_INCOME_CAPTION :{WHITE}Income Graph STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Units of cargo delivered STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Company performance ratings (maximum rating=1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Company values STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Cargo Payment Rates STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Days in transit STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Payment for delivering 10 units (or 10,000 litres) of cargo a distance of 20 squares STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Enable all STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Disable all STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Display all cargoes on the cargo payment rates graph STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Display no cargoes on the cargo payment rates graph STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Toggle graph for cargo type on/off STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Show detailed performance ratings # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}Key to company graphs STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Click here to toggle company's entry on graph on/off # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Company League Table STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Engineer STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Traffic Manager STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Transport Coordinator STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Route Supervisor STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Director STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Chief Executive STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Chairman STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :President STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Tycoon # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}Detailed performance rating STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detail STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}View details about this company ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Vehicles: STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stations: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. profit: STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. income: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Max. income: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Delivered: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Cargo: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Money: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Loan: STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Total: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Number of vehicles that turned a profit last year. This includes road vehicles, trains, ships and aircraft STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Number of recently-serviced stations. Train stations, bus stops, airports and so on are counted separately even if they belong to the same station STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}The profit of the vehicle with the lowest income (only vehicles older than two years are considered) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Amount of cash made in the quarter with the lowest profit of the last 12 quarters STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Amount of cash made in the quarter with the highest profit of the last 12 quarters STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Units of cargo delivered in the last four quarters STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Number of types of cargo delivered in the last quarter STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Amount of money this company has in the bank STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}The amount of money this company has taken on loan STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Total points out of possible points # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Jazz Jukebox STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}All STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Old Style STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}New Style STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Ezy Street STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Custom 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Custom 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Music Volume STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Effects Volume STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}MIN STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}MAX STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{RAW_STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Track STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Title STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Shuffle STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Programme STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Skip to previous track in selection STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Skip to next track in selection STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Stop playing music STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Start playing music STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Drag sliders to set music and sound effect volumes STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Select 'all tracks' programme STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Select 'old style music' programme STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Select 'new style music' programme STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Select 'Ezy Street style music' programme STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Select 'Custom 1' (user-defined) programme STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Select 'Custom 2' (user-defined) programme STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Toggle programme shuffle on/off STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Show music track selection window STR_ERROR_NO_SONGS :{WHITE}A music set without songs has been selected. No songs will be played # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Music Programme Selection STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{RAW_STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Track Index STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Programme - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Clear STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Clear current programme (Custom1 or Custom2 only) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Click on music track to add to current programme (Custom1 or Custom2 only) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Click on music track to remove it from current programme (Custom1 or Custom2 only) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Top companies who reached {NUM} STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Company League Table in {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Businessman STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Entrepreneur STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industrialist STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Capitalist STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnate STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Mogul STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Tycoon of the Century STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} achieves '{STRING}' status! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} of {COMPANY} achieves '{STRING}' status! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}Map - {STRING} STR_SMALLMAP_TYPE_CONTOURS :Contours STR_SMALLMAP_TYPE_VEHICLES :Vehicles STR_SMALLMAP_TYPE_INDUSTRIES :Industries STR_SMALLMAP_TYPE_ROUTEMAP :Cargo Flow STR_SMALLMAP_TYPE_ROUTES :Routes STR_SMALLMAP_TYPE_VEGETATION :Vegetation STR_SMALLMAP_TYPE_OWNERS :Owners STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Show land contours on map STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Show vehicles on map STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Show industries on map STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Show cargo flow on map STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Show transport routes on map STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Show vegetation on map STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Show land owners on map STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Click on an industry type to toggle displaying it. Ctrl+Click disables all types except the selected one. Ctrl+Click on it again to enable all industry types STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Click on a company to toggle displaying its property. Ctrl+Click disables all companies except the selected one. Ctrl+Click on it again to enable all companies STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Click on a cargo to toggle displaying its property. Ctrl+Click disables all cargoes except the selected one. Ctrl+Click on it again to enable all cargoes STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Roads STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Railways STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Stations/Airports/Docks STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Buildings/Industries STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Vehicles STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Trains STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Road Vehicles STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Ships STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Aircraft STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Transport Routes STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Forest STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Railway Station STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Lorry Loading Bay STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Bus Station STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Airport/Heliport STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Dock STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Rough Land STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Grass Land STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Bare Land STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Fields STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Trees STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Rocks STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Water STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}No Owner STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Towns STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Industries STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Desert STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Snow STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Toggle town names on/off on map STR_SMALLMAP_CENTER :{BLACK}Centre the smallmap on the current position STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}Disable all STR_SMALLMAP_ENABLE_ALL :{BLACK}Enable all STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Show height STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Display no industries on the map STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Display all industries on the map STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Toggle display of heightmap STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Display no company property on the map STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Display all company property on the map STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Display no cargoes on the map STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Display all cargoes on the map # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Show last message or news report STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUSED * * STR_STATUSBAR_AUTOSAVE :{RED}AUTOSAVE STR_STATUSBAR_SAVING_GAME :{RED}* * SAVING GAME * * # News message history STR_MESSAGE_HISTORY :{WHITE}Message History STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}A list of the recent news messages STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING5} STR_NEWS_MESSAGE_CAPTION :{WHITE}Message STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{RAW_STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First train arrives at {STATION}! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First bus arrives at {STATION}! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First truck arrives at {STATION}! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First passenger tram arrives at {STATION}! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First freight tram arrives at {STATION}! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First ship arrives at {STATION}! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Citizens celebrate . . .{}First aircraft arrives at {STATION}! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Train Crash!{}{COMMA} die in fireball after collision STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Road Vehicle Crash!{}Driver dies in fireball after collision with train STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Road Vehicle Crash!{}{COMMA} die in fireball after collision with train STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Plane Crash!{}{COMMA} die in fireball at {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Plane Crash!{}Aircraft ran out of fuel, {COMMA} die in fireball STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Zeppelin disaster at {STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Road vehicle destroyed in 'UFO' collision! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Oil refinery explosion near {TOWN}! STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Factory destroyed in suspicious circumstances near {TOWN}! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'UFO' lands near {TOWN}! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Coal mine subsidence leaves trail of destruction near {TOWN}! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Floods!{}At least {COMMA} missing, presumed dead after significant flooding! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Transport company in trouble! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} will be sold off or declared bankrupt unless performance increases soon! STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Transport company merger! STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} has been sold to {RAW_STRING} for {CURRENCY_LONG}! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrupt! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} has been closed down by creditors and all assets sold off! STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}New transport company launched! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{RAW_STRING} starts construction near {TOWN}! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{RAW_STRING} has been taken over by {RAW_STRING}! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Manager) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{RAW_STRING} sponsored construction of new town {TOWN}! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}New {STRING} under construction near {TOWN}! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}New {STRING} being planted near {TOWN}! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING2} announces imminent closure! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Supply problems cause {STRING2} to announce imminent closure! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Lack of nearby trees causes {STRING2} to announce imminent closure! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}European Monetary Union!{}{}The Euro is introduced as the sole currency for everyday transactions in your country! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}World Recession!{}{}Financial experts fear worst as economy slumps! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Recession Over!{}{}Upturn in trade gives confidence to industries as economy strengthens! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} increases production! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}New coal seam found at {INDUSTRY}!{}Production is expected to double! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}New oil reserves found at {INDUSTRY}!{}Production is expected to double! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}Improved farming methods at {INDUSTRY} are expected to double production! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} production at {INDUSTRY} increases {COMMA}%! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} production down by 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Insect infestation causes havoc at {INDUSTRY}!{}Production down by 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} production at {INDUSTRY} decreases {COMMA}%! STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} is waiting in depot STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} is waiting in the aircraft hangar # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} has too few orders in the schedule STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} has a void order STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} has duplicate orders STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} has an invalid station in its orders STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY :{WHITE}{VEHICLE} has in its orders an airport whose runway is too short STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} is getting old STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} is getting very old STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} is getting very old and urgently needs replacing STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} can't find a path to continue STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} is lost STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}{VEHICLE}'s profit last year was {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} can't get to the next destination because it is out of range STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} stopped because an ordered refit failed STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Autorenew failed on {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}New {STRING} now available! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}New {STRING} now available! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} no longer accepts {STRING} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} no longer accepts {STRING} or {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} now accepts {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} now accepts {STRING} and {STRING} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Offer of subsidy expired:{}{}{STRING} from {STRING2} to {STRING2} will now not attract a subsidy STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidy withdrawn:{}{}{STRING} service from {STRING2} to {STRING2} is no longer subsidised STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Service subsidy offered:{}{}First {STRING} service from {STRING2} to {STRING2} will attract a year's subsidy from the local authority! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay 50% extra for the next year! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay double rates for the next year! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay triple rates for the next year! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Service subsidy awarded to {RAW_STRING}!{}{}{STRING} service from {STRING2} to {STRING2} will pay quadruple rates for the next year! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Traffic chaos in {TOWN}!{}{}Road rebuilding programme funded by {RAW_STRING} brings 6 months of misery to motorists! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Transport monopoly! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}Local authority of {TOWN} signs contract with {RAW_STRING} for one year of exclusive transport rights! # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Viewport {COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Copy to viewport STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Copy the location of the main view to this viewport STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Paste from viewport STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Paste the location of this viewport to the main view # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Game Options STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Currency units STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Currency units selection ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :British Pound (GBP) STR_GAME_OPTIONS_CURRENCY_USD :American Dollar (USD) STR_GAME_OPTIONS_CURRENCY_EUR :Euro (EUR) STR_GAME_OPTIONS_CURRENCY_JPY :Japanese Yen (JPY) STR_GAME_OPTIONS_CURRENCY_ATS :Austrian Shilling (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :Belgian Franc (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :Swiss Franc (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :Czech Koruna (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :Deutschmark (DEM) STR_GAME_OPTIONS_CURRENCY_DKK :Danish Krone (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :Spanish Peseta (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :Finnish Markka (FIM) STR_GAME_OPTIONS_CURRENCY_FRF :French Franc (FRF) STR_GAME_OPTIONS_CURRENCY_GRD :Greek Drachma (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :Hungarian Forint (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :Icelandic Krona (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :Italian Lira (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :Dutch Guilder (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :Norwegian Krone (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Polish Złoty (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Romanian Leu (RON) STR_GAME_OPTIONS_CURRENCY_RUR :Russian Rubles (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Slovenian Tolar (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Swedish Krona (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Turkish Lira (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :Slovak Koruna (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :Brazilian Real (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :Estonian Krooni (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Lithuanian Litas (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :South Korean Won (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :South African Rand (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :Custom... STR_GAME_OPTIONS_CURRENCY_GEL :Georgian Lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iranian Rial (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Road vehicles STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Select side of road for vehicles to drive on STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Drive on left STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Drive on right STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Town names STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Select style of town names ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :English (Original) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :French STR_GAME_OPTIONS_TOWN_NAME_GERMAN :German STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :English (Additional) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latin-American STR_GAME_OPTIONS_TOWN_NAME_SILLY :Silly STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Swedish STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Dutch STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Finnish STR_GAME_OPTIONS_TOWN_NAME_POLISH :Polish STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovak STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norwegian STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Hungarian STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Austrian STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Romanian STR_GAME_OPTIONS_TOWN_NAME_CZECH :Czech STR_GAME_OPTIONS_TOWN_NAME_SWISS :Swiss STR_GAME_OPTIONS_TOWN_NAME_DANISH :Danish STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Turkish STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Italian STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Catalan ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Autosave STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Select interval between automatic game saves ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Off STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Every month STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :Every 3 months STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :Every 6 months STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Every 12 months ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}Language STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Select the interface language to use STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullscreen STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Check this box to play OpenTTD fullscreen mode STR_GAME_OPTIONS_RESOLUTION :{BLACK}Screen resolution STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Select the screen resolution to use STR_GAME_OPTIONS_RESOLUTION_OTHER :other STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interface size STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Select the interface element size to use STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normal STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Double size STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Quad size STR_GAME_OPTIONS_BASE_GRF :{BLACK}Base graphics set STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Select the base graphics set to use STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} missing/corrupted file{P "" s} STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base graphics set STR_GAME_OPTIONS_BASE_SFX :{BLACK}Base sounds set STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Select the base sounds set to use STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base sounds set STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Base music set STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Select the base music set to use STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} corrupted file{P "" s} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Additional information about the base music set STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Failed to retrieve a list of supported resolutions STR_ERROR_FULLSCREEN_FAILED :{WHITE}Fullscreen mode failed # Custom currency window STR_CURRENCY_WINDOW :{WHITE}Custom currency STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Exchange rate: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Decrease the amount of your currency for one Pound (£) STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Increase the amount of your currency for one Pound (£) STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Set the exchange rate of your currency for one Pound (£) STR_CURRENCY_SEPARATOR :{LTBLUE}Separator: {ORANGE}{RAW_STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Set the separator for your currency STR_CURRENCY_PREFIX :{LTBLUE}Prefix: {ORANGE}{RAW_STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Set the prefix string for your currency STR_CURRENCY_SUFFIX :{LTBLUE}Suffix: {ORANGE}{RAW_STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Set the suffix string for your currency STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Switch to Euro: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Switch to Euro: {ORANGE}never STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Set the year to switch to Euro STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Switch to Euro earlier STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Switch to Euro later STR_CURRENCY_PREVIEW :{LTBLUE}Preview: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 Pound (£) in your currency STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Change custom currency parameter STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Maximum no. competitors: {ORANGE}{COMMA} STR_NONE :None STR_FUNDING_ONLY :Funding only STR_MINIMAL :Minimal STR_NUM_VERY_LOW :Very Low STR_NUM_LOW :Low STR_NUM_NORMAL :Normal STR_NUM_HIGH :High STR_NUM_CUSTOM :Custom STR_NUM_CUSTOM_NUMBER :Custom ({NUM}) STR_VARIETY_NONE :None STR_VARIETY_VERY_LOW :Very Low STR_VARIETY_LOW :Low STR_VARIETY_MEDIUM :Medium STR_VARIETY_HIGH :High STR_VARIETY_VERY_HIGH :Very High STR_AI_SPEED_VERY_SLOW :Very Slow STR_AI_SPEED_SLOW :Slow STR_AI_SPEED_MEDIUM :Medium STR_AI_SPEED_FAST :Fast STR_AI_SPEED_VERY_FAST :Very Fast STR_SEA_LEVEL_VERY_LOW :Very Low STR_SEA_LEVEL_LOW :Low STR_SEA_LEVEL_MEDIUM :Medium STR_SEA_LEVEL_HIGH :High STR_SEA_LEVEL_CUSTOM :Custom STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Custom ({NUM}%) STR_RIVERS_NONE :None STR_RIVERS_FEW :Few STR_RIVERS_MODERATE :Medium STR_RIVERS_LOT :Many STR_DISASTER_NONE :None STR_DISASTER_REDUCED :Reduced STR_DISASTER_NORMAL :Normal STR_SUBSIDY_X1_5 :x1.5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 STR_TERRAIN_TYPE_VERY_FLAT :Very Flat STR_TERRAIN_TYPE_FLAT :Flat STR_TERRAIN_TYPE_HILLY :Hilly STR_TERRAIN_TYPE_MOUNTAINOUS :Mountainous STR_TERRAIN_TYPE_ALPINIST :Alpinist STR_CITY_APPROVAL_PERMISSIVE :Permissive STR_CITY_APPROVAL_TOLERANT :Tolerant STR_CITY_APPROVAL_HOSTILE :Hostile STR_WARNING_NO_SUITABLE_AI :{WHITE}No suitable AIs available...{}You can download several AIs via the 'Online Content' system # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Settings STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter string: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Expand all STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Collapse all STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(no explanation available) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Default value: {ORANGE}{STRING1} STR_CONFIG_SETTING_TYPE :{LTBLUE}Setting type: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :Client setting (not stored in saves; affects all games) STR_CONFIG_SETTING_TYPE_GAME_MENU :Game setting (stored in saves; affects only new games) STR_CONFIG_SETTING_TYPE_GAME_INGAME :Game setting (stored in save; affects only current game) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Company setting (stored in saves; affects only new games) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Company setting (stored in save; affects only current company) STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Category: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Restricts the list below using predefined filters STR_CONFIG_SETTING_RESTRICT_BASIC :Basic (show only important settings) STR_CONFIG_SETTING_RESTRICT_ADVANCED :Advanced (show most settings) STR_CONFIG_SETTING_RESTRICT_ALL :Expert (show all settings, including weird ones) STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Settings with a different value than the default STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Settings with a different value than your new-game settings STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Restricts the list below to certain setting types STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :All setting types STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Client settings (not stored in saves; affect all games) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Game settings (stored in saves; affect only new games) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Game settings (stored in save; affect only current game) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Company settings (stored in saves; affect only new games) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Company settings (stored in save; affect only current company) STR_CONFIG_SETTING_CATEGORY_HIDES :{BLACK}Show all search results by setting{}{SILVER}Category {BLACK}to {WHITE}{STRING} STR_CONFIG_SETTING_TYPE_HIDES :{BLACK}Show all search results by setting{}{SILVER}Type {BLACK}to {WHITE}All setting types STR_CONFIG_SETTING_CATEGORY_AND_TYPE_HIDES :{BLACK}Show all search results by setting{}{SILVER}Category {BLACK}to {WHITE}{STRING} {BLACK}and {SILVER}Type {BLACK}to {WHITE}All setting types STR_CONFIG_SETTINGS_NONE :{WHITE}- None - STR_CONFIG_SETTING_OFF :Off STR_CONFIG_SETTING_ON :On STR_CONFIG_SETTING_DISABLED :Disabled STR_CONFIG_SETTING_COMPANIES_OFF :Off STR_CONFIG_SETTING_COMPANIES_OWN :Own company STR_CONFIG_SETTING_COMPANIES_ALL :All companies STR_CONFIG_SETTING_NONE :None STR_CONFIG_SETTING_ORIGINAL :Original STR_CONFIG_SETTING_REALISTIC :Realistic STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :Left STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :Centre STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :Right STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maximum initial loan: {STRING2} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :Maximum amount a company can loan (without taking inflation into account) STR_CONFIG_SETTING_INTEREST_RATE :Interest rate: {STRING2} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Loan interest rate; also controls inflation, if enabled STR_CONFIG_SETTING_RUNNING_COSTS :Running costs: {STRING2} STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Set level of maintainance and running costs of vehicles and infrastructure STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Construction speed: {STRING2} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Limit the amount of construction actions for AIs STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Vehicle breakdowns: {STRING2} STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :Control how often inadequately serviced vehicles may break down STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subsidy multiplier: {STRING2} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :Set how much is paid for subsidised connections STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Construction costs: {STRING2} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Set level of construction and purchase costs STR_CONFIG_SETTING_RECESSIONS :Recessions: {STRING2} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :If enabled, recessions may occur every few years. During a recession all production is significantly lower (it returns to previous level when the recession is over) STR_CONFIG_SETTING_TRAIN_REVERSING :Disallow train reversing in stations: {STRING2} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :If enabled, trains will not reverse in non-terminus stations, even if there is a shorter path to their next destination when reversing STR_CONFIG_SETTING_DISASTERS :Disasters: {STRING2} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Toggle disasters which may occasionally block or destroy vehicles or infrastructure STR_CONFIG_SETTING_CITY_APPROVAL :Town council's attitude towards area restructuring: {STRING2} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Choose how much noise and environmental damage by companies affect their town rating and further construction actions in their area STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Maximum map height: {STRING2} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Set the maximum allowed height for mountains on the map STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}You can't set the maximum map height to this value. At least one mountain on the map is higher STR_CONFIG_SETTING_AUTOSLOPE :Allow landscaping under buildings, tracks, etc.: {STRING2} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Allow landscaping under buildings and tracks without removing them STR_CONFIG_SETTING_CATCHMENT :Allow more realistically sized catchment areas: {STRING2} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Have differently sized catchment areas for different types of stations and airports STR_CONFIG_SETTING_EXTRADYNAMITE :Allow removal of more town-owned roads, bridges and tunnels: {STRING2} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Make it easier to remove town-owned infrastructure and buildings STR_CONFIG_SETTING_TRAIN_LENGTH :Maximum length of trains: {STRING2} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Set the maximum length of trains STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} tile{P 0 "" s} STR_CONFIG_SETTING_SMOKE_AMOUNT :Amount of vehicle smoke/sparks: {STRING2} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Set how much smoke or how many sparks are emitted by vehicles STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Train acceleration model: {STRING2} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Select the physics model for train acceleration. The "original" model penalises slopes equally for all vehicles. The "realistic" model penalises slopes and curves depending on various properties of the consist, like length and tractive effort STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Road vehicle acceleration model: {STRING2} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Select the physics model for road vehicle acceleration. The "original" model penalises slopes equally for all vehicles. The "realistic" model penalises slopes depending on various properties of the engine, for example 'tractive effort' STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Slope steepness for trains: {STRING2} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a train. Higher values make it more difficult to climb a hill STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Slope steepness for road vehicles: {STRING2} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Steepness of a sloped tile for a road vehicle. Higher values make it more difficult to climb a hill STR_CONFIG_SETTING_FORBID_90_DEG :Forbid trains and ships from making 90° turns: {STRING2} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 degree turns occur when a horizontal track is directly followed by a vertical track piece on the adjacent tile, thus making the train turn by 90 degree when traversing the tile edge instead of the usual 45 degrees for other track combinations. This also applies to the turning radius of ships STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Allow to join stations not directly adjacent: {STRING2} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Allow adding parts to a station without directly touching the existing parts. Needs Ctrl+Click while placing the new parts STR_CONFIG_SETTING_INFLATION :Inflation: {STRING2} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Enable inflation in the economy, where costs are slightly faster rising than payments STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maximum bridge length: {STRING2} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Maximum length for building bridges STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Maximum bridge height: {STRING2} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Maximum height for building bridges STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maximum tunnel length: {STRING2} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Maximum length for building tunnels STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Manual primary industry construction method: {STRING2} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Method of funding a primary industry. 'none' means it is not possible to fund any, 'prospecting' means funding is possible, but construction occurs in a random spot on the map and may as well fail, 'as other industries' means raw industries can be constructed by companies like processing industries in any position they like STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :None STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :As other industries STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Prospecting STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Flat area around industries: {STRING2} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Amount of flat space around an industry. This ensures empty space will remain available around an industry for building tracks, et cetera STR_CONFIG_SETTING_MULTIPINDTOWN :Allow multiple similar industries per town: {STRING2} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Normally, a town does not want more than one industry of each type. With this setting, it will allow several industries of the same type in the same town STR_CONFIG_SETTING_SIGNALSIDE :Show signals: {STRING2} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Select on which side of the track to place signals STR_CONFIG_SETTING_SIGNALSIDE_LEFT :On the left STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :On the driving side STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :On the right STR_CONFIG_SETTING_SHOWFINANCES :Show finances window at the end of the year: {STRING2} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :If enabled, the finances window pops up at the end of each year to allow easy inspection of the financial status of the company STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :New orders are 'non-stop' by default: {STRING2} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normally, a vehicle will stop at every station it passes. By enabling this setting, it will drive through all station on the way to its final destination without stopping. Note, that this setting only defines a default value for new orders. Individual orders can be set explicitly to either behaviour nevertheless STR_CONFIG_SETTING_STOP_LOCATION :New train orders stop by default at the {STRING2} of the platform STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Place where a train will stop at the platform by default. The 'near end' means close to the entry point, 'middle' means in the middle of the platform, and 'far end' means far away from the entry point. Note, that this setting only defines a default value for new orders. Individual orders can be set explicitly to either behaviour nevertheless STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :near end STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :middle STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :far end STR_CONFIG_SETTING_AUTOSCROLL :Pan window when mouse is at the edge: {STRING2} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :When enabled, viewports will start to scroll when the mouse is near the edge of the window STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :Disabled STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :Main viewport, full-screen only STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :Main viewport STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :Every viewport STR_CONFIG_SETTING_BRIBE :Allow bribing of the local authority: {STRING2} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Allow companies to try bribing the local town authority. If the bribe is noticed by an inspector, the company will not be able to act in the town for six months STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Allow buying exclusive transport rights: {STRING2} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :If a company buys exclusive transport rights for a town, opponents' stations (passenger and cargo) won't receive any cargo for a whole year STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Allow funding buildings: {STRING2} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Allow companies to give money to towns for funding new houses STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Allow funding local road reconstruction: {STRING2} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Allow companies to give money to towns for road re-construction to sabotage road-based services in the town STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Allow sending money to other companies: {STRING2} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Allow transfer of money between companies in multiplayer mode STR_CONFIG_SETTING_FREIGHT_TRAINS :Weight multiplier for freight to simulate heavy trains: {STRING2} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Set the impact of carrying freight in trains. A higher value makes carrying freight more demanding for trains, especially at hills STR_CONFIG_SETTING_PLANE_SPEED :Plane speed factor: {STRING2} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Set the relative speed of planes compared to other vehicle types, to reduce the amount of income of transport by aircraft STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Number of plane crashes: {STRING2} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Set the chance of an aircraft crash happening STR_CONFIG_SETTING_PLANE_CRASHES_NONE :None STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :Reduced STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :Normal STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Allow drive-through road stops on town owned roads: {STRING2} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Allow construction of drive-through road stops on town-owned roads STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Allow drive-through road stops on roads owned by competitors: {STRING2} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Allow construction of drive-through road stops on roads owned by other companies STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Changing this setting is not possible when there are vehicles STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastructure maintenance: {STRING2} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :When enabled, infrastructure causes maintenance costs. The cost grows over-proportional with the network size, thus affecting bigger companies more than smaller ones STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Airports never expire: {STRING2} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Enabling this setting makes each airport type stay available forever after its introduction STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Warn if vehicle is lost: {STRING2} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Trigger messages about vehicles unable to find a path to their ordered destination STR_CONFIG_SETTING_ORDER_REVIEW :Review vehicles' orders: {STRING2} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :When enabled, the orders of the vehicles are periodically checked, and some obvious issues are reported with a news message when detected STR_CONFIG_SETTING_ORDER_REVIEW_OFF :No STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Yes, but exclude stopped vehicles STR_CONFIG_SETTING_ORDER_REVIEW_ON :Of all vehicles STR_CONFIG_SETTING_WARN_INCOME_LESS :Warn if a vehicle's income is negative: {STRING2} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :When enabled, a news message gets sent when a vehicle has not made any profit within a calendar year STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Vehicles never expire: {STRING2} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :When enabled, all vehicle models remain available forever after their introduction STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Autorenew vehicle when it gets old: {STRING2} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :When enabled, a vehicle nearing its end of life gets automatically replaced when the renew conditions are fulfilled STR_CONFIG_SETTING_AUTORENEW_MONTHS :Autorenew when vehicle is {STRING2} maximum age STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Relative age when a vehicle should be considered for auto-renewing STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} month{P 0 "" s} before STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} month{P 0 "" s} after STR_CONFIG_SETTING_AUTORENEW_MONEY :Autorenew minimum needed money for renew: {STRING2} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimal amount of money that must remain in the bank before considering auto-renewing vehicles STR_CONFIG_SETTING_ERRMSG_DURATION :Duration of error message: {STRING2} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Duration for displaying error messages in a red window. Note that some (critical) error messages are not closed automatically after this time, but must be closed manually STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} second{P 0 "" s} STR_CONFIG_SETTING_HOVER_DELAY :Show tooltips: {STRING2} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Delay before tooltips are displayed when hovering the mouse over some interface element. Alternatively tooltips are bound to the right mouse button when this value is set to 0. STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Hover for {COMMA} millisecond{P 0 "" s} STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Right click STR_CONFIG_SETTING_POPULATION_IN_LABEL :Show town population in the town name label: {STRING2} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Display the population of towns in their label on the map STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Thickness of lines in graphs: {STRING2} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Width of the line in the graphs. A thin line is more precisely readable, a thicker line is easier to see and colours are easier to distinguish STR_CONFIG_SETTING_LANDSCAPE :Landscape: {STRING2} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Landscapes define basic gameplay scenarios with different cargos and town growth requirements. NewGRF and Game Scripts allow finer control though STR_CONFIG_SETTING_LAND_GENERATOR :Land generator: {STRING2} STR_CONFIG_SETTING_LAND_GENERATOR_HELPTEXT :The original generator depends on the base graphics set, and composes fixed landscape shapes. TerraGenesis is a Perlin noise based generator with finer control settings STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Original STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_TERRAIN_TYPE :Terrain type: {STRING2} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(TerraGenesis only) Hilliness of the landscape STR_CONFIG_SETTING_INDUSTRY_DENSITY :Industry density: {STRING2} STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Set how many industries should be generated and what level should be maintained during the game STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maximum distance from edge for Oil refineries: {STRING2} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Oil refineries are only constructed near the map border, that is at the coast for island maps STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Snow line height: {STRING2} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Control at what height snow starts in sub-arctic landscape. Snow also affects industry generation and town growth requirements STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Roughness of terrain: {STRING2} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(TerraGenesis only) Choose the frequency of hills: Smooth landscapes have fewer, more wide-spread hills. Rough landscapes have many hills, which may look repetitive STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Very Smooth STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Smooth STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Rough STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Very Rough STR_CONFIG_SETTING_VARIETY :Variety distribution: {STRING2} STR_CONFIG_SETTING_VARIETY_HELPTEXT :(TerraGenesis only) Control whether the map contains both mountainous and flat areas. Since this only makes the map flatter, other settings should be set to mountainous STR_CONFIG_SETTING_RIVER_AMOUNT :River amount: {STRING2} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Choose how many rivers to generate STR_CONFIG_SETTING_TREE_PLACER :Tree placer algorithm: {STRING2} STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Choose the distribution of trees on the map: 'Original' plants trees uniformly scattered, 'Improved' plants them in groups STR_CONFIG_SETTING_TREE_PLACER_NONE :None STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Original STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Improved STR_CONFIG_SETTING_ROAD_SIDE :Road vehicles: {STRING2} STR_CONFIG_SETTING_ROAD_SIDE_HELPTEXT :Choose the driving side STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Heightmap rotation: {STRING2} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Counter clockwise STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Clockwise STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :The height level a flat scenario map gets: {STRING2} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}One or more tiles at the northern edge are not empty STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}One or more tiles at one of the edges is not water STR_CONFIG_SETTING_STATION_SPREAD :Maximum station spread: {STRING2} STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Maximum area the parts of a single station may be spread out on. Note that high values will slow the game STR_CONFIG_SETTING_SERVICEATHELIPAD :Service helicopters at helipads automatically: {STRING2} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Service helicopters after every landing, even if there is no depot at the airport STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Link landscape toolbar to rail/road/water/airport toolbars: {STRING2} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :When opening a construction toolbar for a transport type, also open the toolbar for terraforming STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Land colour used at the smallmap: {STRING2} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Colour of the terrain in the smallmap STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Green STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Dark green STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Violet STR_CONFIG_SETTING_REVERSE_SCROLLING :Reverse scroll direction: {STRING2} STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :Behaviour when scrolling the map with the right mouse button. When disabled, the mouse moves the camera. When enabled, the mouse moves the map STR_CONFIG_SETTING_SMOOTH_SCROLLING :Smooth viewport scrolling: {STRING2} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Control how the main view scrolls to a specific position when clicking on the smallmap or when issuing a command to scroll to a specific object on the map. If enabled, the viewport scrolls smoothly, if disabled it jumps directly to the targeted spot STR_CONFIG_SETTING_MEASURE_TOOLTIP :Show a measurement tooltip when using various build-tools: {STRING2} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Display tile-distances and height differences when dragging during construction operations STR_CONFIG_SETTING_LIVERIES :Show vehicle-type specific liveries: {STRING2} STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Control usage of vehicle-type specific liveries for vehicles (in contrary to company specific) STR_CONFIG_SETTING_LIVERIES_NONE :None STR_CONFIG_SETTING_LIVERIES_OWN :Own company STR_CONFIG_SETTING_LIVERIES_ALL :All companies STR_CONFIG_SETTING_PREFER_TEAMCHAT :Prefer team chat with : {STRING2} STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Switch the binding of company-internal and public chat to resp. STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Function of scrollwheel: {STRING2} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Enable scrolling with two-dimensional mouse-wheels STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :Zoom map STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :Scroll map STR_CONFIG_SETTING_SCROLLWHEEL_OFF :Off STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Map scrollwheel speed: {STRING2} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Control the sensitivity of mouse-wheel scrolling STR_CONFIG_SETTING_OSK_ACTIVATION :On screen keyboard: {STRING2} STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :Select the method to open the on screen keyboard for entering text into editboxes only using the pointing device. This is meant for small devices without actual keyboard STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :Disabled STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :Double click STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :Single click (when focussed) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :Single click (immediately) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Right-click emulation: {STRING2} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Select the method to emulate right mouse-button clicks STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command+Click STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+Click STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Off STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Left-click scrolling: {STRING2} STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :Enable scrolling the map by dragging it with the left mouse button. This is especially useful when using a touch-screen for scrolling STR_CONFIG_SETTING_AUTOSAVE :Autosave: {STRING2} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :Select interval between automatic game saves STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Use the {STRING2} date format for savegame names STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Format of the date in save game filenames STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :long (31st Dec 2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :short (31-12-2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Automatically pause when starting a new game: {STRING2} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :When enabled, the game will automatically pause when starting a new game, allowing for closer study of the map STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :When paused allow: {STRING2} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Select what actions may be done while the game is paused STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :No actions STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :All non-construction actions STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :All but landscape modifying actions STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :All actions STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Use groups in vehicle list: {STRING2} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Enable usage of the advanced vehicle lists for grouping vehicles STR_CONFIG_SETTING_LOADING_INDICATORS :Use loading indicators: {STRING2} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Select whether loading indicators are displayed above loading or unloading vehicles STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Show timetable in ticks rather than days: {STRING2} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Show travel times in time tables in game ticks instead of days STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Show arrival and departure in timetables: {STRING2} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Display anticipated arrival and departure times in timetables STR_CONFIG_SETTING_QUICKGOTO :Quick creation of vehicle orders: {STRING2} STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :Pre-select the 'goto cursor' when opening the orders window STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Default rail type (after new game/game load): {STRING2} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Rail type to select after starting or loading a game. 'first available' selects the oldest type of tracks, 'last available' selects the newest type of tracks, and 'most used' selects the type which is currently most in use STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :First available STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :Last available STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :Most used STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Show path reservations for tracks: {STRING2} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Give reserved tracks a different colour to assist in problems with trains refusing to enter path-based blocks STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Keep building tools active after usage: {STRING2} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Keep the building tools for bridges, tunnels, etc. open after use STR_CONFIG_SETTING_EXPENSES_LAYOUT :Group expenses in company finance window: {STRING2} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Define the layout for the company expenses window STR_CONFIG_SETTING_SOUND_TICKER :News ticker: {STRING2} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Play sound for summarised news messages STR_CONFIG_SETTING_SOUND_NEWS :Newspaper: {STRING2} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Play sound upon display of newspapers STR_CONFIG_SETTING_SOUND_NEW_YEAR :End of year: {STRING2} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Play sound at the end of a year summarising the company's performance during the year compared to the previous year STR_CONFIG_SETTING_SOUND_CONFIRM :Construction: {STRING2} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Play sound on successful constructions or other actions STR_CONFIG_SETTING_SOUND_CLICK :Button clicks: {STRING2} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Beep when clicking buttons STR_CONFIG_SETTING_SOUND_DISASTER :Disasters/accidents: {STRING2} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Play sound effects of accidents and disasters STR_CONFIG_SETTING_SOUND_VEHICLE :Vehicles: {STRING2} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Play sound effects of vehicles STR_CONFIG_SETTING_SOUND_AMBIENT :Ambient: {STRING2} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Play ambient sounds of landscape, industries and towns STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Disable infrastructure building when no suitable vehicles are available: {STRING2} STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :When enabled, infrastructure is only available if there are also vehicles available, preventing waste of time and money on unusable infrastructure STR_CONFIG_SETTING_MAX_TRAINS :Maximum number of trains per company: {STRING2} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Maximum number of trains that a company can have STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Maximum number of road vehicles per company: {STRING2} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Maximum number of road vehicles that a company can have STR_CONFIG_SETTING_MAX_AIRCRAFT :Maximum number of aircraft per company: {STRING2} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Maximum number of aircraft that a company can have STR_CONFIG_SETTING_MAX_SHIPS :Maximum number of ships per company: {STRING2} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Maximum number of ships that a company can have STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Disable trains for computer: {STRING2} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Enabling this setting makes building trains impossible for a computer player STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Disable road vehicles for computer: {STRING2} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Enabling this setting makes building road vehicles impossible for a computer player STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Disable aircraft for computer: {STRING2} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Enabling this setting makes building aircraft impossible for a computer player STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Disable ships for computer: {STRING2} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Enabling this setting makes building ships impossible for a computer player STR_CONFIG_SETTING_AI_PROFILE :Default settings profile: {STRING2} STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :Choose which settings profile to use for random AIs or for initial values when adding a new AI or Game Script STR_CONFIG_SETTING_AI_PROFILE_EASY :Easy STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :Medium STR_CONFIG_SETTING_AI_PROFILE_HARD :Hard STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Allow AIs in multiplayer: {STRING2} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Allow AI computer players to participate in multiplayer games STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#opcodes before scripts are suspended: {STRING2} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Maximum number of computation steps that a script can take in one turn STR_CONFIG_SETTING_SERVINT_ISPERCENT :Service intervals are in percents: {STRING2} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Choose whether servicing of vehicles is triggered by the time passed since last service or by reliability dropping by a certain percentage of the maximum reliability STR_CONFIG_SETTING_SERVINT_TRAINS :Default service interval for trains: {STRING2} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Set the default service interval for new rail vehicles, if no explicit service interval is set for the vehicle STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}day{P 0 "" s}/% STR_CONFIG_SETTING_SERVINT_DISABLED :Disabled STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Default service interval for road vehicles: {STRING2} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Set the default service interval for new road vehicles, if no explicit service interval is set for the vehicle STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Default service interval for aircraft: {STRING2} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Set the default service interval for new aircraft, if no explicit service interval is set for the vehicle STR_CONFIG_SETTING_SERVINT_SHIPS :Default service interval for ships: {STRING2} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Set the default service interval for new ships, if no explicit service interval is set for the vehicle STR_CONFIG_SETTING_NOSERVICE :Disable servicing when breakdowns set to none: {STRING2} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :When enabled, vehicles do not get serviced if they cannot break down STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Enable wagon speed limits: {STRING2} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :When enabled, also use speed limits of wagons for deciding the maximum speed of a train STR_CONFIG_SETTING_DISABLE_ELRAILS :Disable electric rails: {STRING2} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Enabling this setting disables the requirement to electrify tracks to make electric engines run on them STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Arrival of first vehicle at player's station: {STRING2} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Display a newspaper when the first vehicle arrives at a new player's station STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Arrival of first vehicle at competitor's station: {STRING2} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Display a newspaper when the first vehicle arrives at a new competitor's station STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Accidents / disasters: {STRING2} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Display a newspaper when accidents or disasters occur STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Company information: {STRING2} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Display a newspaper when a new company starts, or when companies are risking to bankrupt STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Opening of industries: {STRING2} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Display a newspaper when new industries open STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Closing of industries: {STRING2} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Display a newspaper when industries close down STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Economy changes: {STRING2} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Display a newspaper about global changes to economy STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Production changes of industries served by the company: {STRING2} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Display a newspaper when the production level of industries change, which are served by the company STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Production changes of industries served by competitor(s): {STRING2} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Display a newspaper when the production level of industries change, which are served by the competitors STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Other industry production changes: {STRING2} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Display a newspaper when the production level of industries change, which are not served by the company or competitors STR_CONFIG_SETTING_NEWS_ADVICE :Advice / information on company's vehicles: {STRING2} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Display messages about vehicles needing attention STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :New vehicles: {STRING2} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Display a newspaper when a new vehicle type becomes available STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Changes to cargo acceptance: {STRING2} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Display messages about stations changing acceptance of some cargoes STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subsidies: {STRING2} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Display a newspaper about subsidy related events STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :General information: {STRING2} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Display newspaper about general events, such as purchase of exclusive rights or funding of road reconstruction STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :Off STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :Summary STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Full STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Coloured news appears in: {STRING2} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Year that the newspaper announcements get printed in colour. Before this year, it uses monochrome black/white STR_CONFIG_SETTING_STARTING_YEAR :Starting year: {STRING2} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Enable smooth economy (more, smaller changes): {STRING2} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :When enabled, industry production changes more often, and in smaller steps. This setting has usually no effect, if industry types are provided by a NewGRF STR_CONFIG_SETTING_ALLOW_SHARES :Allow buying shares from other companies: {STRING2} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :When enabled, allow buying and selling of company shares. Shares will only be available for companies reaching a certain age STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Percentage of leg profit to pay in feeder systems: {STRING2} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Percentage of income given to the intermediate legs in feeder systems, giving more control over the income STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :When dragging, place signals every: {STRING2} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Set the distance at which signals will be built on a track up to the next obstacle (signal, junction), if signals are dragged STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} tile{P 0 "" s} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :When dragging, keep fixed distance between signals: {STRING2} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Select the behaviour of signal placement when Ctrl+dragging signals. If disabled, signals are placed around tunnels or bridges to avoid long stretches without signals. If enabled, signals are placed every n tiles, making alignment of signals at parallel tracks easier STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Automatically build semaphores before: {STRING2} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Set the year when electric signals will be used for tracks. Before this year, non-electric signals will be used (which have the exact same function, but different looks) STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Enable the signal GUI: {STRING2} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :Display a window for choosing signal types to build, instead of only window-less signal-type rotation with Ctrl+clicking on built signals STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Signal type to build by default: {STRING2} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Default signal type to use STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :Block signals STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :Path signals STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :One-way path signals STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Cycle through signal types: {STRING2} STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :Select which signal types to cycle through, when Ctrl+clicking on a build signal with the signal tool STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :Block signals only STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :Path signals only STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :All STR_CONFIG_SETTING_TOWN_LAYOUT :Road layout for new towns: {STRING2} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Layout for the road network of towns STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :Original STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :Better roads STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 grid STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 grid STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Random STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Towns are allowed to build roads: {STRING2} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Allow towns to build roads for growth. Disable to prevent town authorities from building roads themselves STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Towns are allowed to build level crossings: {STRING2} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Enabling this setting allows towns to build level crossings STR_CONFIG_SETTING_NOISE_LEVEL :Allow town controlled noise level for airports: {STRING2} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :With this setting disabled, there can be two airports in each town. With this setting enabled, the number of airports in a town is limited by the noise acceptance of the town, which depends on population and airport size and distance STR_CONFIG_SETTING_TOWN_FOUNDING :Founding towns in game: {STRING2} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Enabling this setting allows players to found new towns in the game STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Forbidden STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Allowed STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Allowed, custom town layout STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :In game placement of trees: {STRING2} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Control random appearance of trees during the game. This might affect industries which rely on tree growth, for example lumber mills STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :None {RED}(breaks lumber mill) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :Only in rain forests STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :Everywhere STR_CONFIG_SETTING_TOOLBAR_POS :Position of main toolbar: {STRING2} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Horizontal position of the main toolbar at the top of the screen STR_CONFIG_SETTING_STATUSBAR_POS :Position of status bar: {STRING2} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Horizontal position of the status bar at the bottom of the screen STR_CONFIG_SETTING_SNAP_RADIUS :Window snap radius: {STRING2} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Distance between windows before the window being moved is automatically aligned to nearby windows STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pixel{P 0 "" s} STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Disabled STR_CONFIG_SETTING_SOFT_LIMIT :Maximum number of non-sticky windows: {STRING2} STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Number of non-sticky open windows before old windows get automatically closed to make room for new windows STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :disabled STR_CONFIG_SETTING_ZOOM_MIN :Maximum zoom in level: {STRING2} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :The maximum zoom-in level for viewports. Note that enabling higher zoom-in levels increases memory requirements STR_CONFIG_SETTING_ZOOM_MAX :Maximum zoom out level: {STRING2} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :The maximum zoom-out level for viewports. Higher zoom-out levels might cause lag when used STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normal STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x STR_CONFIG_SETTING_TOWN_GROWTH :Town growth speed: {STRING2} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Speed of town growth STR_CONFIG_SETTING_TOWN_GROWTH_NONE :None STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :Slow STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :Normal STR_CONFIG_SETTING_TOWN_GROWTH_FAST :Fast STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :Very fast STR_CONFIG_SETTING_LARGER_TOWNS :Proportion of towns that will become cities: {STRING2} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Amount of towns which will become a city, thus a town which starts out larger and grows faster STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 in {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :None STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Initial city size multiplier: {STRING2} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Average size of cities relative to normal towns at start of the game STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Update distribution graph every {STRING2}{NBSP}day{P 0:2 "" s} STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Time between subsequent recalculations of the link graph. Each recalculation calculates the plans for one component of the graph. That means that a value X for this setting does not mean the whole graph will be updated every X days. Only some component will. The shorter you set it the more CPU time will be necessary to calculate it. The longer you set it the longer it will take until the cargo distribution starts on new routes. STR_CONFIG_SETTING_LINKGRAPH_TIME :Take {STRING2}{NBSP}day{P 0:2 "" s} for recalculation of distribution graph STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Time taken for each recalculation of a link graph component. When a recalculation is started, a thread is spawned which is allowed to run for this number of days. The shorter you set this the more likely it is that the thread is not finished when it's supposed to. Then the game stops until it is ("lag"). The longer you set it the longer it takes for the distribution to be updated when routes change. STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manual STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asymmetric STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symmetric STR_CONFIG_SETTING_DISTRIBUTION_PAX :Distribution mode for passengers: {STRING2} STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :"symmetric" means that roughly the same number of passengers will go from a station A to a station B as from B to A. "asymmetric" means that arbitrary numbers of passengers can go in either direction. "manual" means that no automatic distribution will take place for passengers. STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Distribution mode for mail: {STRING2} STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"symmetric" means that roughly the same amount of mail will be sent from a station A to a station B as from B to A. "asymmetric" means that arbitrary amounts of mail can be sent in either direction. "manual" means that no automatic distribution will take place for mail. STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Distribution mode for the ARMOURED cargo class: {STRING2} STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :The ARMOURED cargo class contains valuables in the temperate, diamonds in the subtropical or gold in subarctic climate. NewGRFs may change that. "symmetric" means that roughly the same amount of that cargo will be sent from a station A to a station B as from B to A. "asymmetric" means that arbitrary amounts of that cargo can be sent in either direction. "manual" means that no automatic distribution will take place for that cargo. It is recommended to set this to asymmetric or manual when playing subarctic, as banks won't send any gold back to gold mines. For temperate and subtropical you can also choose symmetric as banks will send valuables back to the origin bank of some load of valuables. STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Distribution mode for other cargo classes: {STRING2} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asymmetric" means that arbitrary amounts of cargo can be sent in either direction. "manual" means that no automatic distribution will take place for those cargoes. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Distribution accuracy: {STRING2} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :The higher you set this the more CPU time the calculation of the link graph will take. If it takes too long you may notice lag. If you set it to a low value, however, the distribution will be inaccurate, and you may notice cargo not being sent to the places you expect it to go. STR_CONFIG_SETTING_DEMAND_DISTANCE :Effect of distance on demands: {STRING2} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :If you set this to a value higher than 0, the distance between the origin station A of some cargo and a possible destination B will have an effect on the amount of cargo sent from A to B. The further away B is from A the less cargo will be sent. The higher you set it, the less cargo will be sent to far away stations and the more cargo will be sent to near stations. STR_CONFIG_SETTING_DEMAND_SIZE :Amount of returning cargo for symmetric mode: {STRING2} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Setting this to less than 100% makes the symmetric distribution behave more like the asymmetric one. Less cargo will be forcibly sent back if a certain amount is sent to a station. If you set it to 0% the symmetric distribution behaves just like the asymmetric one. STR_CONFIG_SETTING_SHORT_PATH_SATURATION :Saturation of short paths before using high-capacity paths: {STRING2} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :Frequently there are multiple paths between two given stations. Cargodist will saturate the shortest path first, then use the second shortest path until that is saturated and so on. Saturation is determined by an estimation of capacity and planned usage. Once it has saturated all paths, if there is still demand left, it will overload all paths, prefering the ones with high capacity. Most of the time the algorithm will not estimate the capacity accurately, though. This setting allows you to specify up to which percentage a shorter path must be saturated in the first pass before choosing the next longer one. Set it to less than 100% to avoid overcrowded stations in case of overestimated capacity. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Speed units: {STRING2} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Whenever a speed is shown in the user interface, show it in the selected units STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metric (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Vehicle power units: {STRING2} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Whenever a vehicle's power is shown in the user interface, show it in the selected units STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperial (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Metric (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Weights units: {STRING2} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Whenever a weight is shown in the user interface, show it in the selected units STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :Imperial (short t/ton) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :Metric (t/tonne) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Volumes units: {STRING2} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Whenever a volume is shown in the user interface, show it in the selected units STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :Imperial (gal) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :Metric (l) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Tractive effort units: {STRING2} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Whenever a tractive effort (also known as tractive force) is shown in the user interface, show it in the selected units STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :Imperial (lbf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :Metric (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Heights units: {STRING2} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Whenever a height is shown in the user interface, show it in the selected units STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :Imperial (ft) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :Metric (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Localisation STR_CONFIG_SETTING_GRAPHICS :{ORANGE}Graphics STR_CONFIG_SETTING_SOUND :{ORANGE}Sound STR_CONFIG_SETTING_INTERFACE :{ORANGE}Interface STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE}General STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Viewports STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Construction STR_CONFIG_SETTING_ADVISORS :{ORANGE}News / Advisors STR_CONFIG_SETTING_COMPANY :{ORANGE}Company STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Accounting STR_CONFIG_SETTING_VEHICLES :{ORANGE}Vehicles STR_CONFIG_SETTING_VEHICLES_PHYSICS :{ORANGE}Physics STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Routing STR_CONFIG_SETTING_LIMITATIONS :{ORANGE}Limitations STR_CONFIG_SETTING_ACCIDENTS :{ORANGE}Disasters / Accidents STR_CONFIG_SETTING_GENWORLD :{ORANGE}World generation STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}Environment STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :{ORANGE}Authorities STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}Towns STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Industries STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Cargo distribution STR_CONFIG_SETTING_AI :{ORANGE}Competitors STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players STR_CONFIG_SETTING_PATHFINDER_OPF :Original STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(Recommended) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Pathfinder for trains: {STRING2} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Path finder to use for trains STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Pathfinder for road vehicles: {STRING2} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Path finder to use for road vehicles STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Pathfinder for ships: {STRING2} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Path finder to use for ships STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Automatic reversing at signals: {STRING2} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Allow trains to reverse on a signal, if they waited there a long time STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value # Config errors STR_CONFIG_ERROR :{WHITE}Error with the configuration file... STR_CONFIG_ERROR_ARRAY :{WHITE}... error in array '{RAW_STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... invalid value '{RAW_STRING}' for '{RAW_STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... trailing characters at end of setting '{RAW_STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignoring NewGRF '{RAW_STRING}': duplicate GRF ID with '{RAW_STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignoring invalid NewGRF '{RAW_STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :not found STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :unsafe for static use STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :system NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :incompatible to this version of OpenTTD STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :unknown STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... compression level '{RAW_STRING}' is not valid STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... savegame format '{RAW_STRING}' is not available. Reverting to '{RAW_STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignoring Base Graphics set '{RAW_STRING}': not found STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignoring Base Sounds set '{RAW_STRING}': not found STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignoring Base Music set '{RAW_STRING}': not found STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Out of memory STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Allocating {BYTES} of spritecache failed. The spritecache was reduced to {BYTES}. This will reduce the performance of OpenTTD. To reduce memory requirements you can try to disable 32bpp graphics and/or zoom-in levels # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}New Game STR_INTRO_LOAD_GAME :{BLACK}Load Game STR_INTRO_PLAY_SCENARIO :{BLACK}Play Scenario STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Play Heightmap STR_INTRO_SCENARIO_EDITOR :{BLACK}Scenario Editor STR_INTRO_MULTIPLAYER :{BLACK}Multiplayer STR_INTRO_GAME_OPTIONS :{BLACK}Game Options STR_INTRO_HIGHSCORE :{BLACK}Highscore Table STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Settings STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Settings STR_INTRO_ONLINE_CONTENT :{BLACK}Check Online Content STR_INTRO_SCRIPT_SETTINGS :{BLACK}AI/Game Script Settings STR_INTRO_QUIT :{BLACK}Exit STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Start a new game. Ctrl+Click skips map configuration STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Load a saved game STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Start a new game, using a heightmap as landscape STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Start a new game, using a customised scenario STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Create a customised game world/scenario STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Start a multiplayer game STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Select 'temperate' landscape style STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Select 'sub-arctic' landscape style STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Select 'sub-tropical' landscape style STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Select 'toyland' landscape style STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Display game options STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Display highscore table STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Display settings STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Display NewGRF settings STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Check for new and updated content to download STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Display AI/Game script settings STR_INTRO_TOOLTIP_QUIT :{BLACK}Exit 'OpenTTD' STR_INTRO_TRANSLATION :{BLACK}This translation misses {NUM} string{P "" s}. Please help make OpenTTD better by signing up as translator. See readme.txt for details. # Quit window STR_QUIT_CAPTION :{WHITE}Exit STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Are you sure you want to exit OpenTTD and return to {STRING}? STR_QUIT_YES :{BLACK}Yes STR_QUIT_NO :{BLACK}No # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Abandon Game STR_ABANDON_GAME_QUERY :{YELLOW}Are you sure you want to abandon this game? STR_ABANDON_SCENARIO_QUERY :{YELLOW}Are you sure you want to abandon this scenario? # Cheat window STR_CHEATS :{WHITE}Cheats STR_CHEATS_TOOLTIP :{BLACK}Checkboxes indicate if you have used this cheat before STR_CHEATS_WARNING :{BLACK}Warning! You are about to betray your fellow competitors. Keep in mind that such a disgrace will be remembered for eternity STR_CHEAT_MONEY :{LTBLUE}Increase money by {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Playing as company: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magic bulldozer (remove industries, unmovable objects): {ORANGE}{STRING1} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tunnels may cross each other: {ORANGE}{STRING1} STR_CHEAT_NO_JETCRASH :{LTBLUE}Jetplanes will not crash (frequently) on small airports: {ORANGE}{STRING} STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Edit the maximum map height: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Edit the maximum height of mountains on the map STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Temperate landscape STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Sub-arctic landscape STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Sub-tropical landscape STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Toyland landscape STR_CHEAT_CHANGE_DATE :{LTBLUE}Change date: {ORANGE}{DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Change current year STR_CHEAT_SETUP_PROD :{LTBLUE}Enable modifying production values: {ORANGE}{STRING1} # Livery window STR_LIVERY_CAPTION :{WHITE}New Colour Scheme STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Show general colour schemes STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Show train colour schemes STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Show road vehicle colour schemes STR_LIVERY_SHIP_TOOLTIP :{BLACK}Show ship colour schemes STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Show aircraft colour schemes STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Choose the primary colour for the selected scheme. Ctrl+Click will set this colour for every scheme STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Choose the secondary colour for the selected scheme. Ctrl+Click will set this colour for every scheme STR_LIVERY_PANEL_TOOLTIP :{BLACK}Select a colour scheme to change, or multiple schemes with Ctrl+Click. Click on the box to toggle use of the scheme STR_LIVERY_DEFAULT :Standard Livery STR_LIVERY_STEAM :Steam Engine STR_LIVERY_DIESEL :Diesel Engine STR_LIVERY_ELECTRIC :Electric Engine STR_LIVERY_MONORAIL :Monorail Engine STR_LIVERY_MAGLEV :Maglev Engine STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Passenger Coach (Steam) STR_LIVERY_PASSENGER_WAGON_DIESEL :Passenger Coach (Diesel) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Passenger Coach (Electric) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Passenger Coach (Monorail) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Passenger Coach (Maglev) STR_LIVERY_FREIGHT_WAGON :Freight Wagon STR_LIVERY_BUS :Bus STR_LIVERY_TRUCK :Lorry STR_LIVERY_PASSENGER_SHIP :Passenger Ferry STR_LIVERY_FREIGHT_SHIP :Freight Ship STR_LIVERY_HELICOPTER :Helicopter STR_LIVERY_SMALL_PLANE :Small Aeroplane STR_LIVERY_LARGE_PLANE :Large Aeroplane STR_LIVERY_PASSENGER_TRAM :Passenger Tram STR_LIVERY_FREIGHT_TRAM :Freight Tram # Face selection window STR_FACE_CAPTION :{WHITE}Face Selection STR_FACE_CANCEL_TOOLTIP :{BLACK}Cancel new face selection STR_FACE_OK_TOOLTIP :{BLACK}Accept new face selection STR_FACE_RANDOM :{BLACK}Randomise STR_FACE_MALE_BUTTON :{BLACK}Male STR_FACE_MALE_TOOLTIP :{BLACK}Select male faces STR_FACE_FEMALE_BUTTON :{BLACK}Female STR_FACE_FEMALE_TOOLTIP :{BLACK}Select female faces STR_FACE_NEW_FACE_BUTTON :{BLACK}New Face STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Generate random new face STR_FACE_ADVANCED :{BLACK}Advanced STR_FACE_ADVANCED_TOOLTIP :{BLACK}Advanced face selection STR_FACE_SIMPLE :{BLACK}Simple STR_FACE_SIMPLE_TOOLTIP :{BLACK}Simple face selection STR_FACE_LOAD :{BLACK}Load STR_FACE_LOAD_TOOLTIP :{BLACK}Load favourite face STR_FACE_LOAD_DONE :{WHITE}Your favourite face has been loaded from the OpenTTD configuration file STR_FACE_FACECODE :{BLACK}Player face no. STR_FACE_FACECODE_TOOLTIP :{BLACK}View and/or set face number of the company president STR_FACE_FACECODE_CAPTION :{WHITE}View and/or set president face number STR_FACE_FACECODE_SET :{WHITE}New face number code has been set STR_FACE_FACECODE_ERR :{WHITE}Couldn't set president face number - must be a number between 0 and 4,294,967,295! STR_FACE_SAVE :{BLACK}Save STR_FACE_SAVE_TOOLTIP :{BLACK}Save favourite face STR_FACE_SAVE_DONE :{WHITE}This face will be saved as your favourite in the OpenTTD configuration file STR_FACE_EUROPEAN :{BLACK}European STR_FACE_SELECT_EUROPEAN :{BLACK}Select European faces STR_FACE_AFRICAN :{BLACK}African STR_FACE_SELECT_AFRICAN :{BLACK}Select African faces STR_FACE_YES :Yes STR_FACE_NO :No STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Enable moustache or earring STR_FACE_HAIR :Hair: STR_FACE_HAIR_TOOLTIP :{BLACK}Change hair STR_FACE_EYEBROWS :Eyebrows: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Change eyebrows STR_FACE_EYECOLOUR :Eye colour: STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Change eye colour STR_FACE_GLASSES :Glasses: STR_FACE_GLASSES_TOOLTIP :{BLACK}Enable glasses STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Change glasses STR_FACE_NOSE :Nose: STR_FACE_NOSE_TOOLTIP :{BLACK}Change nose STR_FACE_LIPS :Lips: STR_FACE_MOUSTACHE :Moustache: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Change lips or moustache STR_FACE_CHIN :Chin: STR_FACE_CHIN_TOOLTIP :{BLACK}Change chin STR_FACE_JACKET :Jacket: STR_FACE_JACKET_TOOLTIP :{BLACK}Change jacket STR_FACE_COLLAR :Collar: STR_FACE_COLLAR_TOOLTIP :{BLACK}Change collar STR_FACE_TIE :Tie: STR_FACE_EARRING :Earring: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Advertised STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}Choose between an advertised (internet) and a not advertised (Local Area Network, LAN) game STR_NETWORK_SERVER_LIST_ADVERTISED_NO :No STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Yes STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Player name: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}This is the name other players will identify you by STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Name STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Name of the game STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Clients STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Clients online / clients max{}Companies online / companies max STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Map size STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Map size of the game{}Click to sort by area STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Date STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Current date STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Years STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Number of years{}the game is running STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Language, server version, etc. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Click a game from the list to select it STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}The server you joined last time: STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Click to select the server you played last time STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}GAME INFO STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Clients: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Language: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Landscape: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Map size: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Server version: {WHITE}{RAW_STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Server address: {WHITE}{RAW_STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Start date: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Current date: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Password protected! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVER OFFLINE STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}SERVER FULL STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}VERSION MISMATCH STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF MISMATCH STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Join game STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Refresh server STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Refresh the server info STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Find server STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Search network for a server STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Add server STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adds a server to the list which will always be checked for running games STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Start server STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Start your own server STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Enter your name STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Enter the address of the host # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}Start new multiplayer game STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Game name: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}The game name will be displayed to other players in the multiplayer game selection menu STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set password STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible STR_NETWORK_START_SERVER_UNADVERTISED :No STR_NETWORK_START_SERVER_ADVERTISED :Yes STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximum number of clients: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} compan{P y ies} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Maximum number of companies: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Limit the server to a certain amount of companies STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} spectator{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Maximum number of spectators: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Limit the server to a certain amount of spectators STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Language spoken: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Other players will know which language is spoken on the server STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Enter a name for the network game # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :Any STR_NETWORK_LANG_ENGLISH :English STR_NETWORK_LANG_GERMAN :German STR_NETWORK_LANG_FRENCH :French STR_NETWORK_LANG_BRAZILIAN :Brazilian STR_NETWORK_LANG_BULGARIAN :Bulgarian STR_NETWORK_LANG_CHINESE :Chinese STR_NETWORK_LANG_CZECH :Czech STR_NETWORK_LANG_DANISH :Danish STR_NETWORK_LANG_DUTCH :Dutch STR_NETWORK_LANG_ESPERANTO :Esperanto STR_NETWORK_LANG_FINNISH :Finnish STR_NETWORK_LANG_HUNGARIAN :Hungarian STR_NETWORK_LANG_ICELANDIC :Icelandic STR_NETWORK_LANG_ITALIAN :Italian STR_NETWORK_LANG_JAPANESE :Japanese STR_NETWORK_LANG_KOREAN :Korean STR_NETWORK_LANG_LITHUANIAN :Lithuanian STR_NETWORK_LANG_NORWEGIAN :Norwegian STR_NETWORK_LANG_POLISH :Polish STR_NETWORK_LANG_PORTUGUESE :Portuguese STR_NETWORK_LANG_ROMANIAN :Romanian STR_NETWORK_LANG_RUSSIAN :Russian STR_NETWORK_LANG_SLOVAK :Slovak STR_NETWORK_LANG_SLOVENIAN :Slovenian STR_NETWORK_LANG_SPANISH :Spanish STR_NETWORK_LANG_SWEDISH :Swedish STR_NETWORK_LANG_TURKISH :Turkish STR_NETWORK_LANG_UKRAINIAN :Ukrainian STR_NETWORK_LANG_AFRIKAANS :Afrikaans STR_NETWORK_LANG_CROATIAN :Croatian STR_NETWORK_LANG_CATALAN :Catalan STR_NETWORK_LANG_ESTONIAN :Estonian STR_NETWORK_LANG_GALICIAN :Galician STR_NETWORK_LANG_GREEK :Greek STR_NETWORK_LANG_LATVIAN :Latvian ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer game lobby STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Preparing to join: {ORANGE}{RAW_STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}A list of all companies currently in this game. You can either join one or start a new one if there is a free company slot STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}COMPANY INFO STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Company name: {WHITE}{RAW_STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Inauguration: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Company value: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Current balance: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Last year's income: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Performance: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Vehicles: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Stations: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Players: {WHITE}{RAW_STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}New company STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Spectate game STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Watch the game as a spectator STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Join company STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Help manage this company # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}Connecting... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Connecting... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Authorising... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Waiting... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Downloading map... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Processing data... STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Registering... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Fetching game info... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Fetching company info... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} client{P "" s} in front of you STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} downloaded so far STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} downloaded so far STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disconnect STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server is protected. Enter password STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Company is protected. Enter password # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Client list STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Spectate STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}New company # Network client list STR_NETWORK_CLIENTLIST_KICK :Kick STR_NETWORK_CLIENTLIST_BAN :Ban STR_NETWORK_CLIENTLIST_GIVE_MONEY :Give money STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Speak to all STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Speak to company STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private message STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Client STR_NETWORK_SPECTATORS :Spectators STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Enter the amount of money you want to give STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Spectator # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Do not save the entered password STR_COMPANY_PASSWORD_OK :{BLACK}Give the company the new password STR_COMPANY_PASSWORD_CAPTION :{WHITE}Company password STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Default company password STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Use this company password as default for new companies # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}Join STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Join and play as this company STR_COMPANY_VIEW_PASSWORD :{BLACK}Password STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Password-protect your company to prevent unauthorised users from joining STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Set company password # Network chat STR_NETWORK_CHAT_SEND :{BLACK}Send STR_NETWORK_CHAT_COMPANY_CAPTION :[Team] : STR_NETWORK_CHAT_CLIENT_CAPTION :[Private] {RAW_STRING}: STR_NETWORK_CHAT_ALL_CAPTION :[All] : STR_NETWORK_CHAT_COMPANY :[Team] {RAW_STRING}: {WHITE}{RAW_STRING} STR_NETWORK_CHAT_TO_COMPANY :[Team] To {RAW_STRING}: {WHITE}{RAW_STRING} STR_NETWORK_CHAT_CLIENT :[Private] {RAW_STRING}: {WHITE}{RAW_STRING} STR_NETWORK_CHAT_TO_CLIENT :[Private] To {RAW_STRING}: {WHITE}{RAW_STRING} STR_NETWORK_CHAT_ALL :[All] {RAW_STRING}: {WHITE}{RAW_STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}Enter text for network chat # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}No network devices found or compiled without ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}Could not find any network games STR_NETWORK_ERROR_NOCONNECTION :{WHITE}The server didn't answer the request STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Could not connect due to NewGRF mismatch STR_NETWORK_ERROR_DESYNC :{WHITE}Network-Game synchronisation failed STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Network-Game connection lost STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Could not load savegame STR_NETWORK_ERROR_SERVER_START :{WHITE}Could not start the server STR_NETWORK_ERROR_CLIENT_START :{WHITE}Could not connect STR_NETWORK_ERROR_TIMEOUT :{WHITE}Connection #{NUM} timed out STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}A protocol error was detected and the connection was closed STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took too long to enter the password STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your computer is too slow to keep up with the server STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :general error STR_NETWORK_ERROR_CLIENT_DESYNC :desync error STR_NETWORK_ERROR_CLIENT_SAVEGAME :could not load map STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :connection lost STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :protocol error STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF mismatch STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :not authorized STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :received invalid or unexpected packet STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :wrong revision STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :name already in use STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :wrong password STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :wrong company in DoCommand STR_NETWORK_ERROR_CLIENT_KICKED :kicked by server STR_NETWORK_ERROR_CLIENT_CHEATER :was trying to use a cheat STR_NETWORK_ERROR_CLIENT_SERVER_FULL :server full STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :was sending too many commands STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :received no password in time STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :general timeout STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloading map took too long STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :processing map took too long ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}The last {NUM} second{P "" s} no data has arrived from the server # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:RAW_STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Game paused ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Game still paused ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Game still paused ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Game still paused ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Game still paused ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Game unpaused ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :number of players STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :connecting clients STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manual STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :game script ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :leaving STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {RAW_STRING} has joined the game STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {RAW_STRING} has joined the game (Client #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {RAW_STRING} has joined company #{2:NUM} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {RAW_STRING} has joined spectators STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {RAW_STRING} has started a new company (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {RAW_STRING} has left the game ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {RAW_STRING} has changed his/her name to {RAW_STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {RAW_STRING} gave your company {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** You gave {1:RAW_STRING} {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}The server closed the session STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait... # Content downloading window STR_CONTENT_TITLE :{WHITE}Content downloading STR_CONTENT_TYPE_CAPTION :{BLACK}Type STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Type of the content STR_CONTENT_NAME_CAPTION :{BLACK}Name STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Name of the content STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Click on a line to see the details{}Click on the checkbox to select it for downloading STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Select all STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Mark all content to be downloaded STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Select upgrades STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Mark all content that is an upgrade for existing content to be downloaded STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Unselect all STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Mark all content to be not downloaded STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Search external websites STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Search content not available on OpenTTD's content service on websites not associated to OpenTTD STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}You are leaving OpenTTD! STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}The terms and conditions for downloading content from external websites vary.{}You will have to refer to the external sites for instructions how to install the content into OpenTTD.{}Do you want to continue? STR_CONTENT_FILTER_TITLE :{BLACK}Tag/name filter: STR_CONTENT_OPEN_URL :{BLACK}Visit website STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Visit the website for this content STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Download STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Start downloading the selected content STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Total download size: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}CONTENT INFO STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}You have not selected this to be downloaded STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}You have selected this to be downloaded STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}This dependency has been selected to be downloaded STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}You already have this STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}This content is unknown and can't be downloaded in OpenTTD STR_CONTENT_DETAIL_UPDATE :{SILVER}This is a replacement for an existing {STRING} STR_CONTENT_DETAIL_NAME :{SILVER}Name: {WHITE}{RAW_STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Version: {WHITE}{RAW_STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Description: {WHITE}{RAW_STRING} STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{RAW_STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}Type: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}Download size: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Selected because of: {WHITE}{RAW_STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Dependencies: {WHITE}{RAW_STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Tags: {WHITE}{RAW_STRING} STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD is built without "zlib" support... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... downloading content is not possible! # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :Base graphics STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :AI STR_CONTENT_TYPE_AI_LIBRARY :AI library STR_CONTENT_TYPE_SCENARIO :Scenario STR_CONTENT_TYPE_HEIGHTMAP :Heightmap STR_CONTENT_TYPE_BASE_SOUNDS :Base sounds STR_CONTENT_TYPE_BASE_MUSIC :Base music STR_CONTENT_TYPE_GAME_SCRIPT :Game script STR_CONTENT_TYPE_GS_LIBRARY :GS library # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Downloading content... STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Requesting files... STR_CONTENT_DOWNLOAD_FILE :{WHITE}Currently downloading {RAW_STRING} ({NUM} of {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Download complete STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} of {BYTES} downloaded ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Could not connect to the content server... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Downloading failed... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... connection lost STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... file not writable STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Could not decompress the downloaded file STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Missing graphics STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD requires graphics to function but none could be found. Do you allow OpenTTD to download and install these graphics? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Yes, download the graphics STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}No, exit OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Transparency Options STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Toggle transparency for signs. Ctrl+Click to lock STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Toggle transparency for trees. Ctrl+Click to lock STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Toggle transparency for houses. Ctrl+Click to lock STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Toggle transparency for industries. Ctrl+Click to lock STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Toggle transparency for buildables like stations, depots and waypoints. Ctrl+Click to lock STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Toggle transparency for bridges. Ctrl+Click to lock STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Toggle transparency for structures like lighthouses and antennas. Ctrl+Click to lock STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Toggle transparency for catenary. Ctrl+Click to lock STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Toggle transparency for loading indicators. Ctrl+Click to lock STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Set objects invisible instead of transparent # Linkgraph legend window STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Cargo Flow Legend STR_LINKGRAPH_LEGEND_ALL :{BLACK}All STR_LINKGRAPH_LEGEND_NONE :{BLACK}None STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Select companies to be displayed # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}unused STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}saturated STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}overloaded # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Coverage area highlight STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Off STR_STATION_BUILD_COVERAGE_ON :{BLACK}On STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Don't highlight coverage area of proposed site STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Highlight coverage area of proposed site STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Accepts: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Supplies: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Join station STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Build a separate station STR_JOIN_WAYPOINT_CAPTION :{WHITE}Join waypoint STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Build a separate waypoint # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Railway Construction STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Electrified Railway Construction STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Monorail Construction STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Maglev Construction STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Build railway track. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Build railway track using the Autorail mode. Ctrl toggles build/remove for railway construction. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Build train depot (for buying and servicing trains). Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Convert rail to waypoint. Ctrl enables joining waypoints. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Build railway station. Ctrl enables joining stations. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Build railway signals. Ctrl toggles semaphore/light signals{}Dragging builds signals along a straight stretch of rail. Ctrl builds signals up to the next junction or signal{}Ctrl+Click toggles opening the signal selection window. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Build railway bridge. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Build railway tunnel. Shift toggles building/showing cost estimate STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Toggle build/remove for railway track, signals, waypoints and stations. Hold Ctrl to also remove the rail of waypoints and stations STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Convert/Upgrade the type of rail. Shift toggles building/showing cost estimate STR_RAIL_NAME_RAILROAD :Railway STR_RAIL_NAME_ELRAIL :Electrified railway STR_RAIL_NAME_MONORAIL :Monorail STR_RAIL_NAME_MAGLEV :Maglev # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Train Depot Orientation STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Select railway depot orientation # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Waypoint STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Select waypoint type # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Rail Station Selection STR_STATION_BUILD_ORIENTATION :{BLACK}Orientation STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Select railway station orientation STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Number of tracks STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Select number of platforms for railway station STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Platform length STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Select length of railway station STR_STATION_BUILD_DRAG_DROP :{BLACK}Drag & Drop STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Build a station using drag & drop STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Select a station class to display STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Select the station type to build STR_STATION_CLASS_DFLT :Default station STR_STATION_CLASS_WAYP :Waypoints # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Signal Selection STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Block Signal (semaphore){}This is the most basic type of signal, allowing only one train to be in the same block at the same time STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Entry Signal (semaphore){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Exit Signal (semaphore){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Combo Signal (semaphore){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of pre-signals STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (semaphore){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Block Signal (electric){}This is the most basic type of signal, allowing only one train to be in the same block at the same time STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Entry Signal (electric){}Green as long as there is one or more green exit-signal from the following section of track. Otherwise it shows red STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Exit Signal (electric){}Behaves in the same way as a block signal but is necessary to trigger the correct colour on entry & combo pre-signals STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Combo Signal (electric){}The combo signal simply acts as both an entry and exit signal. This allows you to build large "trees" of pre-signals STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. Standard path signals can be passed from the back side STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}One-way Path Signal (electric){}A path signal allows more than one train to enter a signal block at the same time, if the train can reserve a path to a safe stopping point. One-way path signals can't be passed from the back side STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signal Convert{}When selected, clicking an existing signal will convert it to the selected signal type and variant. Ctrl+Click will toggle the existing variant. Shift+Click shows estimated conversion cost STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Dragging signal density STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Decrease dragging signal density STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Increase dragging signal density # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Select Rail Bridge STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Select Road Bridge STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Bridge selection - click on your preferred bridge to build it STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :Suspension, Steel STR_BRIDGE_NAME_GIRDER_STEEL :Girder, Steel STR_BRIDGE_NAME_CANTILEVER_STEEL :Cantilever, Steel STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Suspension, Concrete STR_BRIDGE_NAME_WOODEN :Wooden STR_BRIDGE_NAME_CONCRETE :Concrete STR_BRIDGE_NAME_TUBULAR_STEEL :Tubular, Steel STR_BRIDGE_TUBULAR_SILICON :Tubular, Silicon # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Road Construction STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tramway Construction STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Build road section. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Build tramway section. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Build road section using the Autoroad mode. Ctrl toggles build/remove for road construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Build tramway section using the Autotram mode. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Build bus station. Ctrl enables joining stations. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Build passenger tram station. Ctrl enables joining stations. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Build lorry loading bay. Ctrl enables joining stations. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Build freight tram station. Ctrl enables joining stations. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Activate/Deactivate one way roads STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Build road bridge. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Build tramway bridge. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Build road tunnel. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Build tramway tunnel. Shift toggles building/showing cost estimate STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Toggle build/remove for road construction STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Toggle build/remove for tramway construction # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Road Depot Orientation STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select road vehicle depot orientation STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Tram Depot Orientation STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Select tram vehicle depot orientation # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Bus Station Orientation STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Select bus station orientation STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Lorry Station Orientation STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Select lorry loading bay orientation STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Passenger Tram Station Orientation STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Select passenger tram station orientation STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Freight Tram Station Orientation STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Select freight tram station orientation # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Waterways Construction STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Waterways STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Build canals. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Build locks. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Build ship depot (for buying and servicing ships). Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Build ship dock. Ctrl enables joining stations. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Place a buoy which can be used as a waypoint. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Build aqueduct. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Define water area.{}Make a canal, unless Ctrl is held down at sea level, when it will flood the surroundings instead STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Place rivers # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ship Depot Orientation STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Select ship depot orientation # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Dock # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Airports STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Build airport. Ctrl enables joining stations. Shift toggles building/showing cost estimate # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Airport Selection STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Select size/type of airport STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Airport class STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}Layout {NUM} STR_AIRPORT_SMALL :Small STR_AIRPORT_CITY :City STR_AIRPORT_METRO :Metropolitan STR_AIRPORT_INTERNATIONAL :International STR_AIRPORT_COMMUTER :Commuter STR_AIRPORT_INTERCONTINENTAL :Intercontinental STR_AIRPORT_HELIPORT :Heliport STR_AIRPORT_HELIDEPOT :Helidepot STR_AIRPORT_HELISTATION :Helistation STR_AIRPORT_CLASS_SMALL :Small airports STR_AIRPORT_CLASS_LARGE :Large airports STR_AIRPORT_CLASS_HUB :Hub airports STR_AIRPORT_CLASS_HELIPORTS :Helicopter airports STR_STATION_BUILD_NOISE :{BLACK}Noise generated: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}Landscaping STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Lower a corner of land. Dragging lowers the first selected corner and levels the selected area to the new corner height. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Raise a corner of land. Dragging raises the first selected corner and levels the selected area to the new corner height. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Level an area of land to the height of the first selected corner. Ctrl selects the area diagonally. Shift toggles building/showing cost estimate STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Purchase land for future use. Shift toggles building/showing cost estimate # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Object Selection STR_OBJECT_BUILD_TOOLTIP :{BLACK}Select object to build. Shift toggles building/showing cost estimate STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Select class of the object to build STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Preview of the object STR_OBJECT_BUILD_SIZE :{BLACK}Size: {GOLD}{NUM} x {NUM} tiles STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Place trees of random type. Shift toggles building/showing cost estimate STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Random Trees STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plant trees randomly throughout the landscape # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generation STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Place rocky areas on landscape STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Define desert area.{}Hold Ctrl to remove it STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Increase area of land to lower/raise STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Decrease area of land to lower/raise STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Generate random land STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Create new scenario STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Reset landscape STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Remove all company-owned property from the map STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Reset Landscape STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Are you sure you want to remove all company-owned property? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}Town Generation STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}New Town STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Found new town. Shift+Click shows only estimated cost STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Random Town STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Found town in random location STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Many random towns STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cover the map with randomly placed towns STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Town name: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Enter town name STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Click to enter town name STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Random name STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Generate new random name STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Town size: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Small STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Medium STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Large STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Random STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Select town size STR_FOUND_TOWN_CITY :{BLACK}City STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Cities grow faster than regular towns{}Depending on settings, they are bigger when founded STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Town road layout: STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Select road layout used for this town STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Original STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Better roads STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 grid STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 grid STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Random # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Fund new industry STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Choose the appropriate industry from this list STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Many random industries STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Cover the map with randomly placed industries STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Cost: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospect STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Build STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Fund # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Industry chain for {STRING} industry STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}Industry chain for {STRING} cargo STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Producing industries STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Accepting industries STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Houses STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Click at the industry to see its suppliers and customers STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Click at the cargo to see its suppliers and customers STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Display chain STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Display cargo supplying and accepting industries STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Link to smallmap STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Select the displayed industries at the smallmap as well STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Select cargo STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Select the cargo you want to display STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Select industry STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Select the industry you want to display # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Land Area Information STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Cost to clear: {LTBLUE}N/A STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Cost to clear: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Revenue when cleared: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :N/A STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Owner: {LTBLUE}{STRING1} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Road owner: {LTBLUE}{STRING1} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramway owner: {LTBLUE}{STRING1} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Railway owner: {LTBLUE}{STRING1} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Local authority: {LTBLUE}{STRING1} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :None STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Coordinates: {LTBLUE}{NUM} x {NUM} x {NUM} ({RAW_STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Built: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Station class: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Station type: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Airport class: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Airport name: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Airport tile name: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{RAW_STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Cargo accepted: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Rail speed limit: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Road speed limit: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rocks STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Rough land STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Bare land STR_LAI_CLEAR_DESCRIPTION_GRASS :Grass STR_LAI_CLEAR_DESCRIPTION_FIELDS :Fields STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Snow-covered land STR_LAI_CLEAR_DESCRIPTION_DESERT :Desert STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} track STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} track with block signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} track with pre-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} track with exit-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} track with combo-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} track with path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} track with one-way path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} track with block and pre-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} track with block and exit-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} track with block and combo-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} track with block and path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} track with block and one-way path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} track with pre- and exit-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} track with pre- and combo-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} track with pre- and path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} track with pre- and one-way path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} track with exit- and combo-signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} track with exit- and path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} track with exit- and one-way path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} track with combo- and path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} track with combo- and one-way path signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} track with path and one-way path signals STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} train depot STR_LAI_ROAD_DESCRIPTION_ROAD :Road STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Road with street lights STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Tree-lined road STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Road vehicle depot STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Road/rail level crossing STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramway # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (under construction) STR_LAI_TREE_NAME_TREES :Trees STR_LAI_TREE_NAME_RAINFOREST :Rainforest STR_LAI_TREE_NAME_CACTUS_PLANTS :Cactus plants STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Railway station STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Aircraft hangar STR_LAI_STATION_DESCRIPTION_AIRPORT :Airport STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Lorry loading area STR_LAI_STATION_DESCRIPTION_BUS_STATION :Bus station STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Ship dock STR_LAI_STATION_DESCRIPTION_BUOY :Buoy STR_LAI_STATION_DESCRIPTION_WAYPOINT :Waypoint STR_LAI_WATER_DESCRIPTION_WATER :Water STR_LAI_WATER_DESCRIPTION_CANAL :Canal STR_LAI_WATER_DESCRIPTION_LOCK :Lock STR_LAI_WATER_DESCRIPTION_RIVER :River STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Coast or riverbank STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Ship depot # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Railway tunnel STR_LAI_TUNNEL_DESCRIPTION_ROAD :Road tunnel STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Steel suspension rail bridge STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Steel girder rail bridge STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Steel cantilever rail bridge STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Reinforced concrete suspension rail bridge STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Wooden rail bridge STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Concrete rail bridge STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Tubular rail bridge STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Steel suspension road bridge STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Steel girder road bridge STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Steel cantilever road bridge STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Reinforced concrete suspension road bridge STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Wooden road bridge STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Concrete road bridge STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Tubular road bridge STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Aqueduct STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Transmitter STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Lighthouse STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Company headquarters STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Company-owned land # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}About OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Original copyright {COPYRIGHT} 1995 Chris Sawyer, All rights reserved STR_ABOUT_VERSION :{BLACK}OpenTTD version {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2015 The OpenTTD team # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Save Game STR_SAVELOAD_LOAD_CAPTION :{WHITE}Load Game STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Save Scenario STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Load Scenario STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Load Heightmap STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Save Heightmap STR_SAVELOAD_HOME_BUTTON :{BLACK}Click here to jump to the current default save/load directory STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} free STR_SAVELOAD_LIST_TOOLTIP :{BLACK}List of drives, directories and saved-game files STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Currently selected name for saved-game STR_SAVELOAD_DELETE_BUTTON :{BLACK}Delete STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Delete the currently selected saved-game STR_SAVELOAD_SAVE_BUTTON :{BLACK}Save STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Save the current game, using the selected name STR_SAVELOAD_LOAD_BUTTON :{BLACK}Load STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Load the selected game STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP :{BLACK}Load the selected heightmap STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Game Details STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}No information available STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING1} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}Enter a name for the savegame # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}World Generation STR_MAPGEN_MAPSIZE :{BLACK}Map size: STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}Select the size of the map in tiles. The number of available tiles will be slightly smaller STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}No. of towns: STR_MAPGEN_DATE :{BLACK}Date: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}No. of industries: STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}Maximum map height: STR_MAPGEN_MAX_HEIGHTLEVEL_UP :{BLACK}Increase the maximum height of mountains on the map by one STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN :{BLACK}Decrease the maximum height of mountains on the map by one STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Snow line height: STR_MAPGEN_SNOW_LINE_UP :{BLACK}Move the snow line height one up STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Move the snow line height one down STR_MAPGEN_LAND_GENERATOR :{BLACK}Land generator: STR_MAPGEN_TREE_PLACER :{BLACK}Tree algorithm: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Terrain type: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Sea level: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Rivers: STR_MAPGEN_SMOOTHNESS :{BLACK}Smoothness: STR_MAPGEN_VARIETY :{BLACK}Variety distribution: STR_MAPGEN_GENERATE :{WHITE}Generate # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}Map edges: STR_MAPGEN_NORTHWEST :{BLACK}Northwest STR_MAPGEN_NORTHEAST :{BLACK}Northeast STR_MAPGEN_SOUTHEAST :{BLACK}Southeast STR_MAPGEN_SOUTHWEST :{BLACK}Southwest STR_MAPGEN_BORDER_FREEFORM :{BLACK}Freeform STR_MAPGEN_BORDER_WATER :{BLACK}Water STR_MAPGEN_BORDER_RANDOM :{BLACK}Random STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Random STR_MAPGEN_BORDER_MANUAL :{BLACK}Manual STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Heightmap rotation: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Heightmap name: STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Size: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT :{WHITE}Change maximum map height STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Change snow line height STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Change starting year # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}Scenario Type STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Flat land STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Generate a flat land STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Random land STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Height of flat land: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Move the height of flat land one down STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Move the height of flat land one up STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Change height of flat land # Map generation progress STR_GENERATION_WORLD :{WHITE}Generating World... STR_GENERATION_ABORT :{BLACK}Abort STR_GENERATION_ABORT_CAPTION :{WHITE}Abort World Generation STR_GENERATION_ABORT_MESSAGE :{YELLOW}Do you really want to abort the generation? STR_GENERATION_PROGRESS :{WHITE}{NUM}% complete STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}World generation STR_GENERATION_RIVER_GENERATION :{BLACK}River generation STR_GENERATION_TREE_GENERATION :{BLACK}Tree generation STR_GENERATION_OBJECT_GENERATION :{BLACK}Object generation STR_GENERATION_CLEARING_TILES :{BLACK}Rough and rocky area generation STR_GENERATION_SETTINGUP_GAME :{BLACK}Setting up game STR_GENERATION_PREPARING_TILELOOP :{BLACK}Running tile-loop STR_GENERATION_PREPARING_SCRIPT :{BLACK}Running script STR_GENERATION_PREPARING_GAME :{BLACK}Preparing game # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF Settings STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}Detailed NewGRF information STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Active NewGRF files STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Inactive NewGRF files STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Select preset: STR_NEWGRF_FILTER_TITLE :{ORANGE}Filter string: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Load the selected preset STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Save preset STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Save the current list as a preset STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Enter name for preset STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Delete preset STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Delete the currently selected preset STR_NEWGRF_SETTINGS_ADD :{BLACK}Add STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Add the selected NewGRF file to your configuration STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Rescan files STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Update the list of available NewGRF files STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Remove STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Remove the selected NewGRF file from the list STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Move Up STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Move the selected NewGRF file up the list STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Move Down STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Move the selected NewGRF file down the list STR_NEWGRF_SETTINGS_UPGRADE :{BLACK}Upgrade STR_NEWGRF_SETTINGS_UPGRADE_TOOLTIP :{BLACK}Upgrade NewGRF files for which you have a newer version installed STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}A list of the NewGRF files that are installed STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Set parameters STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Show parameters STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Toggle palette STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Toggle the palette of the selected NewGRF.{}Do this when the graphics from this NewGRF look pink in-game STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Apply changes STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Find missing content online STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Check whether the missing content can be found online STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Filename: {SILVER}{RAW_STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{RAW_STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Version: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Min. compatible version: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{RAW_STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palette: {SILVER}{RAW_STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parameters: {SILVER}{STRING1} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}No information available STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Matching file not found STR_NEWGRF_SETTINGS_DISABLED :{RED}Disabled STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Incompatible with this version of OpenTTD # NewGRF save preset window STR_SAVE_PRESET_CAPTION :{WHITE}Save preset STR_SAVE_PRESET_LIST_TOOLTIP :{BLACK}List of available presets, select one to copy it to the save name below STR_SAVE_PRESET_TITLE :{BLACK}Enter a name for the preset STR_SAVE_PRESET_EDITBOX_TOOLTIP :{BLACK}Currently selected name for the preset to save STR_SAVE_PRESET_CANCEL :{BLACK}Cancel STR_SAVE_PRESET_CANCEL_TOOLTIP :{BLACK}Don't change the preset STR_SAVE_PRESET_SAVE :{BLACK}Save STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Save the preset to the current selected name # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Change NewGRF parameters STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Close STR_NEWGRF_PARAMETERS_RESET :{BLACK}Reset STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Set all parameters to their default value STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parameter {NUM} STR_NEWGRF_PARAMETERS_SETTING :{STRING1}: {ORANGE}{STRING1} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Number of parameters: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspect - {STRING5} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Parent STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Inspect the object of the parent scope STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING1} at {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Object STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Rail type STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF variable 60+x parameter (hexadecimal) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Aligning sprite {COMMA} ({RAW_STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Next sprite STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Proceed to the next normal sprite, skipping any pseudo/recolour/font sprites and wrapping around from the last sprite to the first STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Go to sprite STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Go to the given sprite. If the sprite is not a normal sprite, proceed to the next normal sprite STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Previous sprite STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Proceed to the previous normal sprite, skipping any pseudo/recolour/font sprites and wrapping around from the first sprite to the last STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representation of the currently selected sprite. The alignment is ignored when drawing this sprite STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Move the sprite around, changing the X and Y offsets STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Reset relative STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Reset the current relative offsets STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}X offset: {NUM}, Y offset: {NUM} (Absolute) STR_SPRITE_ALIGNER_OFFSETS_REL :{BLACK}X offset: {NUM}, Y offset: {NUM} (Relative) STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Pick sprite STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Pick a sprite from anywhere on the screen STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Go to sprite # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{RAW_STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: {SILVER}{RAW_STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{RAW_STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{RAW_STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred: {}{STRING5} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:RAW_STRING} will not work with the TTDPatch version reported by OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:RAW_STRING} is for the {RAW_STRING} version of TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:RAW_STRING} is designed to be used with {RAW_STRING} STR_NEWGRF_ERROR_INVALID_PARAMETER :Invalid parameter for {1:RAW_STRING}: parameter {RAW_STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :{1:RAW_STRING} must be loaded before {RAW_STRING} STR_NEWGRF_ERROR_LOAD_AFTER :{1:RAW_STRING} must be loaded after {RAW_STRING} STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:RAW_STRING} requires OpenTTD version {RAW_STRING} or better STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :the GRF file it was designed to translate STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Too many NewGRFs are loaded STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Loading {1:RAW_STRING} as static NewGRF with {RAW_STRING} could cause desyncs STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Unexpected sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Unknown Action 0 property {4:HEX} (sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Attempt to use invalid ID (sprite {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{RAW_STRING} contains a corrupt sprite. All corrupt sprites will be shown as a red question mark (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Contains multiple Action 8 entries (sprite {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Read past end of pseudo-sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}The currently used base graphics set is missing a number of sprites.{}Please update the base graphics set.{}Since you are playing a {YELLOW}development snapshot of OpenTTD{WHITE}, you might also need a {YELLOW}development snapshot of the base graphics{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Requested GRF resources not available (sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:RAW_STRING} was disabled by {2:RAW_STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Invalid/unknown sprite layout format (sprite {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Caution! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}You are about to make changes to a running game. This can crash OpenTTD or break the game state. Do not file bug reports about these issues.{}Are you absolutely sure about this? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Can't add file: duplicate GRF ID STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Matching file not found (compatible GRF loaded) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}Can't add file: NewGRF file limit reached STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Compatible GRF(s) loaded for missing files STR_NEWGRF_DISABLED_WARNING :{WHITE}Missing GRF file(s) have been disabled STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Missing GRF file(s) STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Unpausing can crash OpenTTD. Do not file bug reports for subsequent crashes.{}Do you really want to unpause? # NewGRF status STR_NEWGRF_LIST_NONE :None STR_NEWGRF_LIST_ALL_FOUND :All files present STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Found compatible files STR_NEWGRF_LIST_MISSING :{RED}Missing files # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}Behaviour of NewGRF '{0:RAW_STRING}' is likely to cause desyncs and/or crashes STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}It changed powered-wagon state for '{1:ENGINE}' when not inside a depot STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}It changed vehicle length for '{1:ENGINE}' when not inside a depot STR_NEWGRF_BROKEN_CAPACITY :{WHITE}It changed vehicle capacity for '{1:ENGINE}' when not inside a depot or refitting STR_BROKEN_VEHICLE_LENGTH :{WHITE}Train '{VEHICLE}' belonging to '{COMPANY}' has invalid length. It is probably caused by problems with NewGRFs. Game may desync or crash STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:RAW_STRING}' provides incorrect information STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit information for '{1:ENGINE}' differs from purchase list after construction. This might cause autorenew/-replace to fail refitting correctly STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' caused an endless loop in the production callback STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Callback {1:HEX} returned unknown/invalid result {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} of STR_NEWGRF_INVALID_ENGINE : STR_NEWGRF_INVALID_INDUSTRYTYPE : # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE : # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}Scanning NewGRFs STR_NEWGRF_SCAN_MESSAGE :{BLACK}Scanning NewGRFs. Depending on the amount this can take a while... STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF{P "" s} scanned out of an estimated {NUM} NewGRF{P "" s} STR_NEWGRF_SCAN_ARCHIVES :Scanning for archives # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}Sign List - {COMMA} Sign{P "" s} STR_SIGN_LIST_MATCH_CASE :{BLACK}Match case STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing sign names against the filter string # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Edit sign text STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Go to next sign STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Go to previous sign STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Enter a name for the sign # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}Towns STR_TOWN_DIRECTORY_NONE :{ORANGE}- None - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Town names - click on name to centre main view on town. Ctrl+Click opens a new viewport on town location STR_TOWN_POPULATION :{BLACK}World population: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (City) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Population: {ORANGE}{COMMA}{BLACK} Houses: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Passengers last month: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Mail last month: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Cargo needed for town growth: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} required STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} required in winter STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} delivered STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (still required) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (delivered) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Town grows every {ORANGE}{COMMA}{BLACK}{NBSP}day{P "" s} STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Town grows every {ORANGE}{COMMA}{BLACK}{NBSP}day{P "" s} (funded) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Town is {RED}not{BLACK} growing STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Noise limit in town: {ORANGE}{COMMA}{BLACK} max: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centre the main view on town location. Ctrl+Click opens a new viewport on town location STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Local authority STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Show information on local authority STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Change town name STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Expand STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Increase size of town STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Delete STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Delete this town completely STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Rename Town # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} local authority STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transport company ratings: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Actions available: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}List of things to do at this town - click on item for more details STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Do it STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Carry out the highlighted action in the list above STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Small advertising campaign STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Medium advertising campaign STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Large advertising campaign STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Fund local road reconstruction STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Build statue of company owner STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Fund new buildings STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Buy exclusive transport rights STR_LOCAL_AUTHORITY_ACTION_BRIBE :Bribe the local authority STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Initiate a small local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Initiate a medium local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Initiate a large local advertising campaign, to attract more passengers and cargo to your transport services.{}Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Fund the reconstruction of the urban road network. Causes considerable disruption to road traffic for up to 6 months.{}Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Build a statue in honour of your company.{}Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Fund the construction of new commercial buildings in the town.{}Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Buy 1 year's exclusive transport rights in town. Town authority will only allow passengers and cargo to use your company's stations.{}Cost: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Bribe the local authority to increase your rating, at the risk of a severe penalty if caught.{}Cost: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} Goals STR_GOALS_SPECTATOR_CAPTION :{WHITE}Global Goals STR_GOALS_GLOBAL_TITLE :{BLACK}Global goals: STR_GOALS_TEXT :{ORANGE}{RAW_STRING} STR_GOALS_NONE :{ORANGE}- None - STR_GOALS_SPECTATOR_NONE :{ORANGE}- Not applicable - STR_GOALS_PROGRESS :{ORANGE}{RAW_STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{RAW_STRING} STR_GOALS_COMPANY_TITLE :{BLACK}Company goals: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on goal to centre main view on industry/town/tile. Ctrl+Click opens a new viewport on industry/town/tile location # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :Question STR_GOAL_QUESTION_CAPTION_INFORMATION :Information STR_GOAL_QUESTION_CAPTION_WARNING :Warning STR_GOAL_QUESTION_CAPTION_ERROR :Error ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Cancel STR_GOAL_QUESTION_BUTTON_OK :OK STR_GOAL_QUESTION_BUTTON_NO :No STR_GOAL_QUESTION_BUTTON_YES :Yes STR_GOAL_QUESTION_BUTTON_DECLINE :Decline STR_GOAL_QUESTION_BUTTON_ACCEPT :Accept STR_GOAL_QUESTION_BUTTON_IGNORE :Ignore STR_GOAL_QUESTION_BUTTON_RETRY :Retry STR_GOAL_QUESTION_BUTTON_PREVIOUS :Previous STR_GOAL_QUESTION_BUTTON_NEXT :Next STR_GOAL_QUESTION_BUTTON_STOP :Stop STR_GOAL_QUESTION_BUTTON_START :Start STR_GOAL_QUESTION_BUTTON_GO :Go STR_GOAL_QUESTION_BUTTON_CONTINUE :Continue STR_GOAL_QUESTION_BUTTON_RESTART :Restart STR_GOAL_QUESTION_BUTTON_POSTPONE :Postpone STR_GOAL_QUESTION_BUTTON_SURRENDER :Surrender STR_GOAL_QUESTION_BUTTON_CLOSE :Close ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}Subsidies STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Subsidies on offer for services taking: STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} (by {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- None - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Services already subsidised: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} ({COMPANY}{YELLOW}, until {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on service to centre main view on industry/town. Ctrl+Click opens a new viewport on industry/town location # Story book window STR_STORY_BOOK_CAPTION :{WHITE}{COMPANY} Story Book STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Global Story Book STR_STORY_BOOK_TITLE :{YELLOW}{RAW_STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :Page {NUM} STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Jump to a specific page by selecting it in this drop down list. STR_STORY_BOOK_PREV_PAGE :{BLACK}Previous STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Go to previous page STR_STORY_BOOK_NEXT_PAGE :{BLACK}Next STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Go to next page STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Invalid goal reference # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Station names - click on name to centre main view on station. Ctrl+Click opens a new viewport on station location STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Hold Ctrl to select more than one item STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Station{P "" s} STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- None - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Select all facilities STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Select all cargo types (including no waiting cargo) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}No cargo of any type is waiting # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} from {STATION}) STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} reserved for loading) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Accepts STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Show list of accepted cargo STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Accepts: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}This station has exclusive transport rights in this town. STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} bought exclusive transport rights in this town. STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Ratings STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Show station ratings STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Monthly supply and local rating: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}Group by STR_STATION_VIEW_WAITING_STATION :Station: Waiting STR_STATION_VIEW_WAITING_AMOUNT :Amount: Waiting STR_STATION_VIEW_PLANNED_STATION :Station: Planned STR_STATION_VIEW_PLANNED_AMOUNT :Amount: Planned STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} from {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} via {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} to {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} from unknown station STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} to any station STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} via any station STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} from this station STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} stopping at this station STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} to this station STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} non-stop STR_STATION_VIEW_GROUP_S_V_D :Source-Via-Destination STR_STATION_VIEW_GROUP_S_D_V :Source-Destination-Via STR_STATION_VIEW_GROUP_V_S_D :Via-Source-Destination STR_STATION_VIEW_GROUP_V_D_S :Via-Destination-Source STR_STATION_VIEW_GROUP_D_S_V :Destination-Source-Via STR_STATION_VIEW_GROUP_D_V_S :Destination-Via-Source ############ range for rating starts STR_CARGO_RATING_APPALLING :Appalling STR_CARGO_RATING_VERY_POOR :Very Poor STR_CARGO_RATING_POOR :Poor STR_CARGO_RATING_MEDIOCRE :Mediocre STR_CARGO_RATING_GOOD :Good STR_CARGO_RATING_VERY_GOOD :Very Good STR_CARGO_RATING_EXCELLENT :Excellent STR_CARGO_RATING_OUTSTANDING :Outstanding ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on station location. Ctrl+Click opens a new viewport on station location STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Change name of station STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Show all trains which have this station on their schedule STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Show all road vehicles which have this station on their schedule STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Show all aircraft which have this station on their schedule STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Show all ships which have this station on their schedule STR_STATION_VIEW_RENAME_STATION_CAPTION :Rename station/loading area STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Close airport STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Prevent aircraft from landing on this airport # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on waypoint location. Ctrl+Click opens a new viewport on waypoint location STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Change waypoint name STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centre main view on buoy location. Ctrl+Click opens a new viewport on buoy location STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Change buoy name STR_EDIT_WAYPOINT_NAME :{WHITE}Edit waypoint name # Finances window STR_FINANCES_CAPTION :{WHITE}{COMPANY} Finances {BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Expenditure/Income STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Construction STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}New Vehicles STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Train Running Costs STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Road Vehicle Running Costs STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Aircraft Running Costs STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Ship Running Costs STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Property Maintenance STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Train Income STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Road Vehicle Income STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Aircraft Income STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Ship Income STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Loan Interest STR_FINANCES_SECTION_OTHER :{GOLD}Other STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}Total: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bank Balance STR_FINANCES_LOAN_TITLE :{WHITE}Loan STR_FINANCES_MAX_LOAN :{WHITE}Maximum Loan: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}Borrow {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}Increase size of loan. Ctrl+Click borrows as much as possible STR_FINANCES_REPAY_BUTTON :{BLACK}Repay {CURRENCY_LONG} STR_FINANCES_REPAY_TOOLTIP :{BLACK}Repay part of loan. Ctrl+Click repays as much loan as possible STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastructure # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(Manager) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Inaugurated: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Colour Scheme: STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Vehicles: STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} train{P "" s} STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} road vehicle{P "" s} STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} aircraft STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} ship{P "" s} STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}None STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Company value: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% owned by {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastructure: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} rail piece{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} road piece{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} water tile{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} station tile{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} airport{P "" s} STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}None STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Build HQ STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Build company headquarters STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}View HQ STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}View company headquarters STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Relocate HQ STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Rebuild company headquarters elsewhere for 1% cost of company value. Shift+Click shows estimated cost without relocating HQ STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Details STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}View detailed infrastructure counts STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}New Face STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Select new face for manager STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Colour Scheme STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Change the company vehicle livery STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Company Name STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Change the company name STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Manager Name STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Change the manager's name STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Buy 25% share in company STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Sell 25% share in company STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Buy 25% share in this company. Shift+Click shows estimated cost without purchasing any share STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Sell 25% share in this company. Shift+Click shows estimated income without selling any share STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Company Name STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Manager's Name STR_BUY_COMPANY_MESSAGE :{WHITE}We are looking for a transport company to take-over our company.{}{}Do you want to purchase {COMPANY} for {CURRENCY_LONG}? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}Infrastructure of {COMPANY} STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Rail pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signals STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Road pieces: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Road STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramway STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Water tiles: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Canals STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stations: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Station tiles STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Airports STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/yr # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Industries STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- None - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{RAW_STRING}){YELLOW} ({COMMA}% transported) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{RAW_STRING}/{CARGO_LONG}{RAW_STRING}){YELLOW} ({COMMA}%/{COMMA}% transported) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Industry names - click on name to centre main view on industry. Ctrl+Click opens a new viewport on industry location # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Production last month: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} ({COMMA}% transported) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centre the main view on industry location. Ctrl+Click opens a new viewport on industry location STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Production level: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}The industry has announced imminent closure! ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Requires: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING}, {STRING}{RAW_STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Cargo waiting to be processed: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{RAW_STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Produces: {YELLOW}{STRING}{RAW_STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Produces: {YELLOW}{STRING}{RAW_STRING}, {STRING}{RAW_STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}Change production (multiple of 8, up to 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Change production level (percentage, up to 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING2} - {COMMA} Train{P "" s} STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING2} - {COMMA} Road Vehicle{P "" s} STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING2} - {COMMA} Ship{P "" s} STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING2} - {COMMA} Aircraft STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Trains - click on train for information STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Road vehicles - click on vehicle for information STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Ships - click on ship for information STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Aircraft - click on aircraft for information STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Profit this year: {CURRENCY_LONG} (last year: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :Available Trains STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Available Vehicles STR_VEHICLE_LIST_AVAILABLE_SHIPS :Available Ships STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Available Aircraft STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}See a list of available engine designs for this vehicle type STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Manage list STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Send instructions to all vehicles in this list STR_VEHICLE_LIST_REPLACE_VEHICLES :Replace vehicles STR_VEHICLE_LIST_SEND_FOR_SERVICING :Send for Servicing STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Send to Depot STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Send to Depot STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Send to Depot STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Send to Hangar STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Click to stop all the vehicles in the list STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Click to start all the vehicles in the list STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Shared orders of {COMMA} Vehicle{P "" s} # Group window STR_GROUP_ALL_TRAINS :All trains STR_GROUP_ALL_ROAD_VEHICLES :All road vehicles STR_GROUP_ALL_SHIPS :All ships STR_GROUP_ALL_AIRCRAFTS :All aircraft STR_GROUP_DEFAULT_TRAINS :Ungrouped trains STR_GROUP_DEFAULT_ROAD_VEHICLES :Ungrouped road vehicles STR_GROUP_DEFAULT_SHIPS :Ungrouped ships STR_GROUP_DEFAULT_AIRCRAFTS :Ungrouped aircraft STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Groups - click on a group to list all vehicles of this group. Drag and drop groups to arrange hierarchy. STR_GROUP_CREATE_TOOLTIP :{BLACK}Click to create a group STR_GROUP_DELETE_TOOLTIP :{BLACK}Delete the selected group STR_GROUP_RENAME_TOOLTIP :{BLACK}Rename the selected group STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Click to protect this group from global autoreplace STR_QUERY_GROUP_DELETE_CAPTION :{WHITE}Delete Group STR_GROUP_DELETE_QUERY_TEXT :{WHITE}Are you sure you want to delete this group and any descendants? STR_GROUP_ADD_SHARED_VEHICLE :Add shared vehicles STR_GROUP_REMOVE_ALL_VEHICLES :Remove all vehicles STR_GROUP_RENAME_CAPTION :{BLACK}Rename a group # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :New Rail Vehicles STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :New Electric Rail Vehicles STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :New Monorail Vehicles STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :New Maglev Vehicles STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :New Rail Vehicles STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :New Road Vehicles STR_BUY_VEHICLE_SHIP_CAPTION :New Ships STR_BUY_VEHICLE_AIRCRAFT_CAPTION :New Aircraft STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Weight: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Speed: {GOLD}{VELOCITY}{BLACK} Power: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Speed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Speed on ocean: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Speed on canal/river: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Running Cost: {GOLD}{CURRENCY_LONG}/yr STR_PURCHASE_INFO_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG} {STRING} STR_PURCHASE_INFO_REFITTABLE :(refittable) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Designed: {GOLD}{NUM}{BLACK} Life: {GOLD}{COMMA} year{P "" s} STR_PURCHASE_INFO_RELIABILITY :{BLACK}Max. Reliability: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cost: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Weight: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cost: {GOLD}{CURRENCY_LONG}{BLACK} Speed: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Capacity: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Powered Wagons: {GOLD}+{POWER}{BLACK} Weight: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Refittable to: {GOLD}{STRING2} STR_PURCHASE_INFO_ALL_TYPES :All cargo types STR_PURCHASE_INFO_ALL_BUT :All but {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. Tractive Effort: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Range: {GOLD}{COMMA} tiles STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Train vehicle selection list. Click on vehicle for information. Ctrl+Click for toggling hiding of the vehicle type STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Road vehicle selection list. Click on vehicle for information. Ctrl+Click for toggling hiding of the vehicle type STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Ship selection list. Click on ship for information. Ctrl+Click for toggling hiding of the ship type STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Aircraft selection list. Click on aircraft for information. Ctrl+Click for toggling hiding of the aircraft type STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehicle STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Buy Vehicle STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Buy Ship STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Buy Aircraft STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted train vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted road vehicle. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted ship. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Buy the highlighted aircraft. Shift+Click shows estimated cost without purchase STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Rename STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Rename train vehicle type STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Rename road vehicle type STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Rename ship type STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Rename aircraft type STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Hide STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Hide STR_BUY_VEHICLE_SHIP_HIDE_TOGGLE_BUTTON :{BLACK}Hide STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :{BLACK}Hide STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON :{BLACK}Display STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}Display STR_BUY_VEHICLE_SHIP_SHOW_TOGGLE_BUTTON :{BLACK}Display STR_BUY_VEHICLE_AIRCRAFT_SHOW_TOGGLE_BUTTON :{BLACK}Display STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toggle hiding/displaying of the train vehicle type STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toggle hiding/displaying of the road vehicle type STR_BUY_VEHICLE_SHIP_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toggle hiding/displaying of the ship type STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Toggle hiding/displaying of the aircraft type STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Rename train vehicle type STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Rename road vehicle type STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Rename ship type STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Rename aircraft type # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}Change name of depot STR_DEPOT_RENAME_DEPOT_CAPTION :Rename depot STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{RAW_STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} vehicle{P "" s}{RAW_STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Trains - drag vehicle with left-click to add/remove from train, right-click for information. Hold Ctrl to make both functions apply to the following chain STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Vehicles - right-click on vehicle for information STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Ships - right-click on ship for information STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Aircraft - right-click on aircraft for information STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Drag train vehicle to here to sell it STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Drag road vehicle to here to sell it STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Drag ship to here to sell it STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Drag aircraft to here to sell it STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Drag train engine here to sell the whole train STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Sell all trains in the depot STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Sell all road vehicles in the depot STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Sell all ships in the depot STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Sell all aircraft in the hangar STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Autoreplace all trains in the depot STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Autoreplace all road vehicles in the depot STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Autoreplace all ships in the depot STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Autoreplace all aircraft in the hangar STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}New Vehicles STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}New Vehicles STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}New Ships STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}New Aircraft STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new train vehicle STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new road vehicle STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new ship STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Buy new aircraft STR_DEPOT_CLONE_TRAIN :{BLACK}Clone Train STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Clone Vehicle STR_DEPOT_CLONE_SHIP :{BLACK}Clone Ship STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Clone Aircraft STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}This will buy a copy of a train including all cars. Click this button and then on a train inside or outside the depot. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}This will buy a copy of a road vehicle. Click this button and then on a road vehicle inside or outside the depot. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}This will buy a copy of a ship. Click this button and then on a ship inside or outside the depot. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}This will buy a copy of an aircraft. Click this button and then on an aircraft inside or outside the hangar. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Centre main view on train depot location. Ctrl+Click opens a new viewport on train depot location STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centre main view on road vehicle depot location. Ctrl+Click opens a new viewport on road depot location STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Centre main view on ship depot location. Ctrl+Click opens a new viewport on ship depot location STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centre main view on hangar location. Ctrl+Click opens a new viewport on hangar location STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Get a list of all trains with the current depot in their orders STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Get a list of all road vehicles with the current depot in their orders STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Get a list of all ships with the current depot in their orders STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Get a list of all aircraft with any hangar at this airport in their orders STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Click to stop all the trains inside the depot STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Click to stop all the road vehicles inside the depot STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Click to stop all the ships inside the depot STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Click to stop all the aircraft inside the hangar STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Click to start all the trains inside the depot STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Click to start all the road vehicles inside the depot STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Click to start all the ships inside the depot STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Click to start all the aircraft inside the hangar STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}You are about to sell all the vehicles in the depot. Are you sure? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Message from vehicle manufacturer STR_ENGINE_PREVIEW_MESSAGE :{GOLD}We have just designed a new {STRING} - would you be interested in a year's exclusive use of this vehicle, so we can see how it performs before making it universally available? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :railway locomotive STR_ENGINE_PREVIEW_ROAD_VEHICLE :road vehicle STR_ENGINE_PREVIEW_AIRCRAFT :aircraft STR_ENGINE_PREVIEW_SHIP :ship STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :monorail locomotive STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :maglev locomotive STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER}{}Running Cost: {CURRENCY_LONG}/yr{}Capacity: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cost: {CURRENCY_LONG} Weight: {WEIGHT_SHORT}{}Speed: {VELOCITY} Power: {POWER} Max. T.E.: {6:FORCE}{}Running Cost: {4:CURRENCY_LONG}/yr{}Capacity: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY}{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {COMMA} tiles{}Capacity: {CARGO_LONG}, {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Cost: {CURRENCY_LONG} Max. Speed: {VELOCITY} Range: {COMMA} tiles{}Capacity: {CARGO_LONG}{}Running Cost: {CURRENCY_LONG}/yr # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}Replace {STRING} - {STRING1} STR_REPLACE_VEHICLE_TRAIN :Train STR_REPLACE_VEHICLE_ROAD_VEHICLE :Road Vehicle STR_REPLACE_VEHICLE_SHIP :Ship STR_REPLACE_VEHICLE_AIRCRAFT :Aircraft STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Vehicles in use STR_REPLACE_VEHICLE_VEHICLES_IN_USE_TOOLTIP :{BLACK}Column with vehicles that you own STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Available vehicles STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES_TOOLTIP :{BLACK}Column with vehicles available for replacement STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Select the engine type to replace STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Select the new engine type you would like to use in place of the left selected engine type STR_REPLACE_VEHICLES_START :{BLACK}Start Replacing Vehicles STR_REPLACE_VEHICLES_NOW :Replace all vehicles now STR_REPLACE_VEHICLES_WHEN_OLD :Replace only old vehicles STR_REPLACE_HELP_START_BUTTON :{BLACK}Press to begin replacement of the left selected engine type with the right selected engine type STR_REPLACE_NOT_REPLACING :{BLACK}Not replacing STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}No vehicle selected STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} when old STR_REPLACE_VEHICLES_STOP :{BLACK}Stop Replacing Vehicles STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Press to stop the replacement of the engine type selected on the left STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Replacing: {ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Switch between engine and wagon replacement windows STR_REPLACE_ENGINES :Engines STR_REPLACE_WAGONS :Wagons STR_REPLACE_HELP_RAILTYPE :{BLACK}Choose the rail type you want to replace engines for STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left selected engine is being replaced with, if any STR_REPLACE_RAIL_VEHICLES :Rail Vehicles STR_REPLACE_ELRAIL_VEHICLES :Electrified Rail Vehicles STR_REPLACE_MONORAIL_VEHICLES :Monorail Vehicles STR_REPLACE_MAGLEV_VEHICLES :Maglev Vehicles STR_REPLACE_REMOVE_WAGON :{BLACK}Wagon removal: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Make autoreplace keep the length of a train the same by removing wagons (starting at the front), if replacing the engine would make the train longer # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Centre main view on train's location. Ctrl+Click will follow train in main view STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centre main view on vehicle's location. Ctrl+Click will follow vehicle in main view STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Centre main view on ship's location. Ctrl+Click will follow ship in main view STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centre main view on aircraft's location. Ctrl+Click will follow aircraft in main view STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send train to depot. Ctrl+Click will only service STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send vehicle to depot. Ctrl+Click will only service STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send ship to depot. Ctrl+Click will only service STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Send aircraft to hangar. Ctrl+Click will only service STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}This will buy a copy of the train including all cars. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}This will buy a copy of the road vehicle. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}This will buy a copy of the ship. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}This will buy a copy of the aircraft. Ctrl+Click will share the orders. Shift+Click shows estimated cost without purchase STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Force train to proceed without waiting for signal to clear it STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Refit train to carry a different cargo type STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Refit road vehicle to carry a different cargo type STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Refit ship to carry a different cargo type STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Refit aircraft to carry a different cargo type STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Reverse direction of train STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Force vehicle to turn around STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Show train's orders. Ctrl+Click to show train's timetable STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Show vehicle's orders. Ctrl+Click to show vehicle's timetable STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Show ship's orders. Ctrl+Click to show ship's timetable STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Show aircraft's orders. Ctrl+Click to show aircraft's timetable STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Show train details STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Show road vehicle details STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Show ship details STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Show aircraft details STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Current train action - click to stop/start train. Ctrl+Click to scroll to destination STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Current vehicle action - click to stop/start vehicle. Ctrl+Click to scroll to destination STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Current ship action - click to stop/start ship. Ctrl+Click to scroll to destination STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Current aircraft action - click to stop/start aircraft. Ctrl+Click to scroll to destination # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Loading / Unloading STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Leaving STR_VEHICLE_STATUS_CRASHED :{RED}Crashed! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Broken down STR_VEHICLE_STATUS_STOPPED :{RED}Stopped STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Stopping, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}No power STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Waiting for free path STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Too far to next destination STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Heading for {STATION}, {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}No orders, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Heading for {WAYPOINT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Heading for {DEPOT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Service at {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Stopped STR_VEHICLE_COMMAND_STOPPED :{RED}Stopped STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Started STR_VEHICLE_COMMAND_STARTED :{GREEN}Started # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Details) STR_VEHICLE_NAME_BUTTON :{BLACK}Name STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Name train STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Name road vehicle STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Name ship STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Name aircraft STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Age: {LTBLUE}{STRING2}{BLACK} Running Cost: {LTBLUE}{CURRENCY_LONG}/yr # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} year{P "" s} ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} year{P "" s} ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Max. speed: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Max. speed: {LTBLUE}{VELOCITY} {BLACK}Range: {LTBLUE}{COMMA} tiles STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Weight: {LTBLUE}{WEIGHT_SHORT} {BLACK}Power: {LTBLUE}{POWER}{BLACK} Max. speed: {LTBLUE}{VELOCITY} {BLACK}Max. T.E.: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Profit this year: {LTBLUE}{CURRENCY_LONG} (last year: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Reliability: {LTBLUE}{COMMA}% {BLACK}Breakdowns since last service: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Capacity: {LTBLUE}None{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Capacity: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Transfer Credits: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Servicing interval: {LTBLUE}{COMMA}{NBSP}days{BLACK} Last service: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Servicing interval: {LTBLUE}{COMMA}%{BLACK} Last service: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Increase servicing interval by 10. Ctrl+Click increases servicing interval by 5 STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Decrease servicing interval by 10. Ctrl+Click decreases servicing interval by 5 STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Change servicing interval type STR_VEHICLE_DETAILS_DEFAULT :Default STR_VEHICLE_DETAILS_DAYS :Days STR_VEHICLE_DETAILS_PERCENT :Percentage STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Name train STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Name road vehicle STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Name ship STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Name aircraft # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Built: {LTBLUE}{NUM}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Value: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Total cargo capacity of this train: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Empty STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} from {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} from {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Cargo STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Show details of cargo carried STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Information STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Show details of train vehicles STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Capacities STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Show capacities of each vehicle STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Total Cargo STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Show total capacity of train, split by cargo type STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Capacity: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Refit) STR_REFIT_TITLE :{GOLD}Select cargo type to carry: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}{}{BLACK}Cost of refit: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}{}{BLACK}Income from refit: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Cost of refit: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}New capacity: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Income from refit: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Select the vehicles to refit. Dragging with the mouse allows to select multiple vehicles. Clicking on an empty space will select the whole vehicle. Ctrl+Click will select a vehicle and the following chain STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Select type of cargo for train to carry STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Select type of cargo for road vehicle to carry STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Select type of cargo for ship to carry STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Select type of cargo for aircraft to carry STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Refit train STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Refit road vehicle STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Refit ship STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Refit aircraft STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Refit train to carry highlighted cargo type STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Refit road vehicle to carry highlighted cargo type STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Refit ship to carry highlighted cargo type STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Refit aircraft to carry highlighted cargo type # Order view STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Orders) STR_ORDERS_TIMETABLE_VIEW :{BLACK}Timetable STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Switch to the timetable view STR_ORDERS_LIST_TOOLTIP :{BLACK}Order list - click on an order to highlight it. Ctrl+Click scrolls to the order's destination STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING4} {STRING2} {STRING} STR_ORDERS_END_OF_ORDERS :- - End of Orders - - STR_ORDERS_END_OF_SHARED_ORDERS :- - End of Shared Orders - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}Non-stop STR_ORDER_GO_TO :Go to STR_ORDER_GO_NON_STOP_TO :Go non-stop to STR_ORDER_GO_VIA :Go via STR_ORDER_GO_NON_STOP_VIA :Go non-stop via STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Change the stopping behaviour of the highlighted order STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Full load any cargo STR_ORDER_DROP_LOAD_IF_POSSIBLE :Load if available STR_ORDER_DROP_FULL_LOAD_ALL :Full load all cargo STR_ORDER_DROP_FULL_LOAD_ANY :Full load any cargo STR_ORDER_DROP_NO_LOADING :No loading STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Change the loading behaviour of the highlighted order STR_ORDER_TOGGLE_UNLOAD :{BLACK}Unload all STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Unload if accepted STR_ORDER_DROP_UNLOAD :Unload all STR_ORDER_DROP_TRANSFER :Transfer STR_ORDER_DROP_NO_UNLOADING :No unloading STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Change the unloading behaviour of the highlighted order STR_ORDER_REFIT :{BLACK}Refit STR_ORDER_REFIT_TOOLTIP :{BLACK}Select what cargo type to refit to in this order. Ctrl+Click to remove refit instruction STR_ORDER_REFIT_AUTO :{BLACK}Refit at station STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Select what cargo type to refit to in this order. Ctrl+Click to remove refit instruction. Refitting at stations will only be done if the vehicle allows it STR_ORDER_DROP_REFIT_AUTO :Fixed cargo STR_ORDER_DROP_REFIT_AUTO_ANY :Available cargo STR_ORDER_SERVICE :{BLACK}Service STR_ORDER_DROP_GO_ALWAYS_DEPOT :Always go STR_ORDER_DROP_SERVICE_DEPOT :Service if needed STR_ORDER_DROP_HALT_DEPOT :Stop STR_ORDER_SERVICE_TOOLTIP :{BLACK}Skip this order unless a service is needed STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Vehicle data to base jumping on # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Load percentage STR_ORDER_CONDITIONAL_RELIABILITY :Reliability STR_ORDER_CONDITIONAL_MAX_SPEED :Maximum speed STR_ORDER_CONDITIONAL_AGE :Age (years) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Requires service STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Always STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Remaining lifetime (years) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}How to compare the vehicle data to the given value STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :is equal to STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :is not equal to STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :is less than STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :is less or equal to STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :is more than STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :is more or equal to STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :is true STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :is false STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}The value to compare the vehicle data against STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Enter value to compare against STR_ORDERS_SKIP_BUTTON :{BLACK}Skip STR_ORDERS_SKIP_TOOLTIP :{BLACK}Skip the current order, and start the next. Ctrl+Click skips to the selected order STR_ORDERS_DELETE_BUTTON :{BLACK}Delete STR_ORDERS_DELETE_TOOLTIP :{BLACK}Delete the highlighted order STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Delete all orders STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Stop sharing STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Stop sharing the order list. Ctrl+Click additionally deletes all orders for this vehicle STR_ORDERS_GO_TO_BUTTON :{BLACK}Go To STR_ORDER_GO_TO_NEAREST_DEPOT :Go to nearest depot STR_ORDER_GO_TO_NEAREST_HANGAR :Go to nearest hangar STR_ORDER_CONDITIONAL :Conditional order jump STR_ORDER_SHARE :Share orders STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Insert a new order before the highlighted order, or add to end of list. Ctrl makes station orders 'full load any cargo', waypoint orders 'non-stop' and depot orders 'service'. 'Share orders' or Ctrl lets this vehicle share orders with the selected vehicle. Clicking a vehicle copies the orders from that vehicle. A depot order disables automatic servicing of the vehicle STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Show all vehicles that share this schedule # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Go via {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT} STR_ORDER_SERVICE_AT :Service at STR_ORDER_SERVICE_NON_STOP_AT :Service non-stop at STR_ORDER_NEAREST_DEPOT :the nearest STR_ORDER_NEAREST_HANGAR :the nearest Hangar STR_ORDER_TRAIN_DEPOT :Train Depot STR_ORDER_ROAD_VEHICLE_DEPOT :Road Vehicle Depot STR_ORDER_SHIP_DEPOT :Ship Depot STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(Refit to {STRING}) STR_ORDER_REFIT_STOP_ORDER :(Refit to {STRING} and stop) STR_ORDER_STOP_ORDER :(Stop) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING1} STR_ORDER_IMPLICIT :(Implicit) STR_ORDER_FULL_LOAD :(Full load) STR_ORDER_FULL_LOAD_ANY :(Full load any cargo) STR_ORDER_NO_LOAD :(No loading) STR_ORDER_UNLOAD :(Unload and take cargo) STR_ORDER_UNLOAD_FULL_LOAD :(Unload and wait for full load) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Unload and wait for any full load) STR_ORDER_UNLOAD_NO_LOAD :(Unload and leave empty) STR_ORDER_TRANSFER :(Transfer and take cargo) STR_ORDER_TRANSFER_FULL_LOAD :(Transfer and wait for full load) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transfer and wait for any full load) STR_ORDER_TRANSFER_NO_LOAD :(Transfer and leave empty) STR_ORDER_NO_UNLOAD :(No unloading and take cargo) STR_ORDER_NO_UNLOAD_FULL_LOAD :(No unloading and wait for full load) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(No unloading and wait for any full load) STR_ORDER_NO_UNLOAD_NO_LOAD :(No unloading and no loading) STR_ORDER_AUTO_REFIT :(Refit to {STRING}) STR_ORDER_FULL_LOAD_REFIT :(Full load with refit to {STRING}) STR_ORDER_FULL_LOAD_ANY_REFIT :(Full load any cargo with refit to {STRING}) STR_ORDER_UNLOAD_REFIT :(Unload and take cargo with refit to {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Unload and wait for full load with refit to {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Unload and wait for any full load with refit to {STRING}) STR_ORDER_TRANSFER_REFIT :(Transfer and take cargo with refit to {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transfer and wait for full load with refit to {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transfer and wait for any full load with refit to {STRING}) STR_ORDER_NO_UNLOAD_REFIT :(No unloading and take cargo with refit to {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(No unloading and wait for full load with refit to {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(No unloading and wait for any full load with refit to {STRING}) STR_ORDER_AUTO_REFIT_ANY :available cargo STR_ORDER_STOP_LOCATION_NEAR_END :[near end] STR_ORDER_STOP_LOCATION_MIDDLE :[middle] STR_ORDER_STOP_LOCATION_FAR_END :[far end] STR_ORDER_OUT_OF_RANGE :{RED} (Next destination is out of range) STR_ORDER_CONDITIONAL_UNCONDITIONAL :Jump to order {COMMA} STR_ORDER_CONDITIONAL_NUM :Jump to order {COMMA} when {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :Jump to order {COMMA} when {STRING} {STRING} STR_INVALID_ORDER :{RED} (Invalid Order) # Time table window STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Timetable) STR_TIMETABLE_ORDER_VIEW :{BLACK}Orders STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Switch to the order view STR_TIMETABLE_TOOLTIP :{BLACK}Timetable - click on an order to highlight it STR_TIMETABLE_NO_TRAVEL :No travel STR_TIMETABLE_NOT_TIMETABLEABLE :Travel (automatic; timetabled by next manual order) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Travel (not timetabled) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Travel (not timetabled) with at most {2:VELOCITY} STR_TIMETABLE_TRAVEL_FOR :Travel for {STRING1} STR_TIMETABLE_TRAVEL_FOR_SPEED :Travel for {STRING1} with at most {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Travel (for {STRING1}, not timetabled) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Travel (for {STRING1}, not timetabled) with at most {VELOCITY} STR_TIMETABLE_STAY_FOR_ESTIMATED :(stay for {STRING1}, not timetabled) STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(travel for {STRING1}, not timetabled) STR_TIMETABLE_STAY_FOR :and stay for {STRING1} STR_TIMETABLE_AND_TRAVEL_FOR :and travel for {STRING1} STR_TIMETABLE_DAYS :{COMMA}{NBSP}day{P "" s} STR_TIMETABLE_TICKS :{COMMA}{NBSP}tick{P "" s} STR_TIMETABLE_TOTAL_TIME :{BLACK}This timetable will take {STRING1} to complete STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}This timetable will take at least {STRING1} to complete (not all timetabled) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}This vehicle is currently running on time STR_TIMETABLE_STATUS_LATE :{BLACK}This vehicle is currently running {STRING1} late STR_TIMETABLE_STATUS_EARLY :{BLACK}This vehicle is currently running {STRING1} early STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}This timetable has not yet started STR_TIMETABLE_STATUS_START_AT :{BLACK}This timetable will start at {STRING1} STR_TIMETABLE_STARTING_DATE :{BLACK}Start date STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Select a date as starting point of this timetable. Ctrl+Click sets the starting point of this timetable and distributes all vehicles sharing this order evenly based on their relative order, if the order is completely timetabled STR_TIMETABLE_CHANGE_TIME :{BLACK}Change Time STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take STR_TIMETABLE_CLEAR_TIME :{BLACK}Clear Time STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order STR_TIMETABLE_CHANGE_SPEED :{BLACK}Change Speed Limit STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order STR_TIMETABLE_CLEAR_SPEED :{BLACK}Clear Speed Limit STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order STR_TIMETABLE_RESET_LATENESS :{BLACK}Reset Late Counter STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reset the lateness counter, so the vehicle will be on time STR_TIMETABLE_AUTOFILL :{BLACK}Autofill STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times) STR_TIMETABLE_EXPECTED :{BLACK}Expected STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Switch between expected and scheduled STR_TIMETABLE_ARRIVAL_ABBREVIATION :A: STR_TIMETABLE_DEPARTURE_ABBREVIATION :D: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}Set date STR_DATE_SET_DATE :{BLACK}Set date STR_DATE_SET_DATE_TOOLTIP :{BLACK}Use the selected date as starting date for the timetable STR_DATE_DAY_TOOLTIP :{BLACK}Select day STR_DATE_MONTH_TOOLTIP :{BLACK}Select month STR_DATE_YEAR_TOOLTIP :{BLACK}Select year # AI debug window STR_AI_DEBUG :{WHITE}AI/Game Script Debug STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{RAW_STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Name of the script STR_AI_DEBUG_SETTINGS :{BLACK}Settings STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Change the settings of the script STR_AI_DEBUG_RELOAD :{BLACK}Reload AI STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Kill the AI, reload the script, and restart the AI STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Enable/disable breaking when an AI log message matches the break string STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Break on: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Break on STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}When an AI log message matches this string, the game is paused STR_AI_DEBUG_MATCH_CASE :{BLACK}Match case STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Toggle matching case when comparing AI log messages against the break string STR_AI_DEBUG_CONTINUE :{BLACK}Continue STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Unpause and continue the AI STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}View debug output of this AI STR_AI_GAME_SCRIPT :{BLACK}Game Script STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Check the Game Script log STR_ERROR_AI_NO_AI_FOUND :No suitable AI found to load.{}This AI is a dummy AI and won't do anything.{}You can download several AIs via the 'Online Content' system STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}One of the running scripts crashed. Please report this to the script author with a screenshot of the AI/Game Script Debug Window STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}AI/Game Script Debug window is only available for the server # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}AI/Game Script Configuration STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}The Game Script that will be loaded in the next game STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}The AIs that will be loaded in the next game STR_AI_CONFIG_HUMAN_PLAYER :Human player STR_AI_CONFIG_RANDOM_AI :Random AI STR_AI_CONFIG_NONE :(none) STR_AI_CONFIG_MOVE_UP :{BLACK}Move Up STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Move selected AI up in the list STR_AI_CONFIG_MOVE_DOWN :{BLACK}Move Down STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Move selected AI down in the list STR_AI_CONFIG_GAMESCRIPT :{SILVER}Game Script STR_AI_CONFIG_AI :{SILVER}AIs STR_AI_CONFIG_CHANGE :{BLACK}Select {STRING} STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :AI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Game Script STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Load another script STR_AI_CONFIG_CONFIGURE :{BLACK}Configure STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Configure the parameters of the Script # Available AIs window STR_AI_LIST_CAPTION :{WHITE}Available {STRING} STR_AI_LIST_CAPTION_AI :AIs STR_AI_LIST_CAPTION_GAMESCRIPT :Game Scripts STR_AI_LIST_TOOLTIP :{BLACK}Click to select a script STR_AI_LIST_AUTHOR :{LTBLUE}Author: {ORANGE}{RAW_STRING} STR_AI_LIST_VERSION :{LTBLUE}Version: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{RAW_STRING} STR_AI_LIST_ACCEPT :{BLACK}Accept STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Select highlighted script STR_AI_LIST_CANCEL :{BLACK}Cancel STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Don't change the script # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parameters STR_AI_SETTINGS_CAPTION_AI :AI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Game Script STR_AI_SETTINGS_CLOSE :{BLACK}Close STR_AI_SETTINGS_RESET :{BLACK}Reset STR_AI_SETTINGS_SETTING :{RAW_STRING}: {ORANGE}{STRING1} STR_AI_SETTINGS_START_DELAY :Number of days to start this AI after the previous one (give or take): {ORANGE}{STRING1} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme of {RAW_STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog of {RAW_STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} licence of {RAW_STRING} STR_TEXTFILE_WRAP_TEXT :{WHITE}Wrap text STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Wrap the text of the window so it all fits without having to scroll STR_TEXTFILE_VIEW_README :{BLACK}View readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Changelog STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Cost: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}Cost: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Income: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}Income: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG} STR_FEEDER :{YELLOW}Transfer: {CURRENCY_LONG} STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Income: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {GREEN}Income: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} STR_FEEDER_COST :{YELLOW}Transfer: {CURRENCY_LONG}{WHITE} / {RED}Cost: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Estimated Cost: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Estimated Income: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Saving still in progress,{}please wait until it is finished! STR_ERROR_AUTOSAVE_FAILED :{WHITE}Autosave failed STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Unable to read drive STR_ERROR_GAME_SAVE_FAILED :{WHITE}Game Save Failed{}{STRING1} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Unable to delete file STR_ERROR_GAME_LOAD_FAILED :{WHITE}Game Load Failed{}{STRING1} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Internal error: {RAW_STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Broken savegame - {RAW_STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Savegame is made with newer version STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :File not readable STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :File not writeable STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Data integrity check failed STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Game was saved in version without tram support. All trams have been removed # Map generation messages STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Map generation aborted...{}... no suitable town locations STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... there is no town in this scenario STR_ERROR_PNGMAP :{WHITE}Can't load landscape from PNG... STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... file not found STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... could not convert image type. 8 or 24-bit PNG image needed STR_ERROR_PNGMAP_MISC :{WHITE}... something just went wrong (probably corrupted file) STR_ERROR_BMPMAP :{WHITE}Can't load landscape from BMP... STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... could not convert image type STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... image is too large STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}Scale warning STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}Resizing source map too much is not recommended. Continue with the generation? # Soundset messages STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Only a fallback sound set was found. If you want sounds, install a sound set via the content download system # Screenshot related messages STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Huge screenshot STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}The screenshot will have a resolution of {COMMA} x {COMMA} pixels. Taking the screenshot may take a while. Do you want to continue? STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Screenshot successfully saved as '{RAW_STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}Screenshot failed! # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Message STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Message from {STRING1} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Off edge of map STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}Too close to edge of map STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}Not enough cash - requires {CURRENCY_LONG} STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Flat land required STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Land sloped in wrong direction STR_ERROR_CAN_T_DO_THIS :{WHITE}Can't do this... STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Building must be demolished first STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Can't clear this area... STR_ERROR_SITE_UNSUITABLE :{WHITE}... site unsuitable STR_ERROR_ALREADY_BUILT :{WHITE}... already built STR_ERROR_OWNED_BY :{WHITE}... owned by {STRING2} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... area is owned by another company STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... landscaping limit reached STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... tile clearing limit reached STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... tree planting limit reached STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Name must be unique STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} in the way STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Not allowed while paused # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN} local authority refuses to allow this STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}{TOWN} local authority refuses to allow another airport to be built in this town STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}{TOWN} local authority refuses permission for airport due to noise concerns STR_ERROR_BRIBE_FAILED :{WHITE}Your attempted bribe has been discovered by a regional investigator # Levelling errors STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}Can't raise land here... STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}Can't lower land here... STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}Can't level land here... STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}Excavation would damage tunnel STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... already at sea level STR_ERROR_TOO_HIGH :{WHITE}... too high STR_ERROR_ALREADY_LEVELLED :{WHITE}... already flat STR_ERROR_BRIDGE_TOO_HIGH_AFTER_LOWER_LAND :{WHITE}Afterwards the bridge above it would be too high. # Company related errors STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Can't change company name... STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Can't change manager's name... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... maximum permitted loan size is {CURRENCY_LONG} STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Can't borrow any more money... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... no loan to repay STR_ERROR_CURRENCY_REQUIRED :{WHITE}... {CURRENCY_LONG} required STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Can't repay loan... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Can't give away money that is loaned from the bank... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Can't buy company... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Can't build company headquarters... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Can't buy 25% share in this company... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}Can't sell 25% share in this company... STR_ERROR_PROTECTED :{WHITE}This company is not old enough to trade shares yet... # Town related errors STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}Can't build any towns STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}Can't rename town... STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}Can't found town here... STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}Can't expand town... STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... too close to edge of map STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... too close to another town STR_ERROR_TOO_MANY_TOWNS :{WHITE}... too many towns STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... there is no more space on the map STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}The town will not build roads. You can enable building of roads via Settings->Environment->Towns STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Road works in progress STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Can't delete this town...{}A station or depot is referring to the town or a town owned tile can't be removed STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... there is no suitable place for a statue in the centre of this town # Industry related errors STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too many industries STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Can't generate industries... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Can't build {STRING} here... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Can't construct this industry type here... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... too close to another industry STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... must found town first STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... only one allowed per town STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... can only be built in towns with a population of at least 1200 STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... can only be built in rainforest areas STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... can only be built in desert areas STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... can only be built in towns (replacing houses) STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... can only be built near the center of towns STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}... can only be built in low areas STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... can only be positioned near edges of map STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... forest can only be planted above snow-line STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... can only be built above the snow-line STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... can only be built below the snow-line STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}There were no suitable places for '{STRING}' industries STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Change the map generation parameters to get a better map # Station construction related errors STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Can't build railway station here... STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Can't build bus station... STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Can't build lorry station... STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Can't build passenger tram station... STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Can't build freight tram station... STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Can't build dock here... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Can't build airport here... STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins more than one existing station/loading area STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... station too spread out STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Too many stations/loading areas STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Too many railway station parts STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}Too many bus stops STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}Too many lorry stations STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}Too close to another station/loading area STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Too close to another dock STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}Too close to another airport STR_ERROR_CAN_T_RENAME_STATION :{WHITE}Can't rename station... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... this is a town owned road STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... road facing in the wrong direction STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... drive through stops can't have corners STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... drive through stops can't have junctions # Station destruction related errors STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}Can't remove part of station... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Must remove railway station first STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Can't remove bus station... STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Can't remove lorry station... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Can't remove passenger tram station... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Can't remove freight tram station... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Must remove road stop first STR_ERROR_THERE_IS_NO_STATION :{WHITE}... there is no station here STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Must demolish railway station first STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Must demolish bus station first STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}Must demolish lorry station first STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}Must demolish passenger tram station first STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Must demolish freight tram station first STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Must demolish dock first STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Must demolish airport first # Waypoint related errors STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins more than one existing waypoint STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Too close to another waypoint STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Can't build train waypoint here... STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Can't place buoy here... STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Can't change waypoint name... STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Can't remove train waypoint here... STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Must remove rail waypoint first STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... buoy in the way STR_ERROR_BUOY_IS_IN_USE :{WHITE}... buoy is in use by another company! # Depot related errors STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Can't build train depot here... STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Can't build road vehicle depot here... STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Can't build tram vehicle depot here... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Can't build ship depot here... STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}Can't rename depot... STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... must be stopped inside a depot STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... must be stopped inside a hangar STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Trains can only be altered when stopped inside a depot STR_ERROR_TRAIN_TOO_LONG :{WHITE}Train too long STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Can't reverse direction of vehicle... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... consists of multiple units STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Incompatible rail types STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Can't move vehicle... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}The rear engine will always follow its front counterpart STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}Unable to find route to local depot STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}Unable to find local depot STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Wrong depot type # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} is too long after replacement STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}No autoreplace/renew rules applied STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(money limit) # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Impossible track combination STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}Must remove signals first STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}No suitable railway track STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}Must remove railway track first STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Road is one way or blocked STR_ERROR_CROSSING_DISALLOWED :{WHITE}Level crossings not allowed for this rail type STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Can't build signals here... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Can't build railway track here... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Can't remove railway track from here... STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Can't remove signals from here... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Can't convert signals here... STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... there is no railway track STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... there are no signals STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Can't convert rail type here... # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Must remove road first STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... one way roads can't have junctions STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Can't build road here... STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Can't build tramway here... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Can't remove road from here... STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Can't remove tramway from here... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... there is no road STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... there is no tramway # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Can't build canals here... STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Can't build locks here... STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Can't place rivers here... STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... must be built on water STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... can't build on water STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... can't build on open sea STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... can't build on canal STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... can't build on river STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Must demolish canal first STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Can't build aqueduct here... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... tree already here STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... wrong terrain for tree type STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Can't plant tree here... # Bridge related errors STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Can't build bridge here... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Must demolish bridge first STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Can't start and end in the same spot STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Bridge heads not at the same level STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}Bridge is too low for the terrain STR_ERROR_BRIDGE_TOO_HIGH_FOR_TERRAIN :{WHITE}Bridge is too high for this terrain. STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Start and end must be in line STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... ends of bridge must both be on land STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... bridge too long STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Bridge would end out of the map # Tunnel related errors STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Can't build tunnel here... STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}Site unsuitable for tunnel entrance STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}Must demolish tunnel first STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Another tunnel in the way STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunnel would end out of the map STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Unable to excavate land for other end of tunnel STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tunnel too long # Object related errors STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... too many objects STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}Can't build object... STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}Object in the way STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... company headquarters in the way STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}Can't purchase this land area... STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... you already own it! # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Can't create group... STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Can't delete this group... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Can't rename group... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Can't set parent group... STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Can't remove all vehicles from this group... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Can't add the vehicle to this group... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Can't add shared vehicles to group... # Generic vehicle errors STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}Train in the way STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}Road vehicle in the way STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Ship in the way STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Aircraft in the way STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Can't refit train... STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Can't refit road vehicle... STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Can't refit ship... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Can't refit aircraft... STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}Can't name train... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}Can't name road vehicle... STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}Can't name ship... STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}Can't name aircraft... STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}Can't stop/start train... STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}Can't stop/start road vehicle... STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}Can't stop/start ship... STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}Can't stop/start aircraft... STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}Can't send train to depot... STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}Can't send road vehicle to depot... STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}Can't send ship to depot... STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}Can't send aircraft to hangar... STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}Can't buy railway vehicle... STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}Can't buy road vehicle... STR_ERROR_CAN_T_BUY_SHIP :{WHITE}Can't buy ship... STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}Can't buy aircraft... STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}Can't rename train vehicle type... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}Can't rename road vehicle type... STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}Can't rename ship type... STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}Can't rename aircraft type... STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}Can't sell railway vehicle... STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}Can't sell road vehicle... STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Can't sell ship... STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Can't sell aircraft... STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}Vehicle is not available STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}Vehicle is not available STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}Ship is not available STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}Aircraft is not available STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Too many vehicles in game STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}Can't change servicing interval... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... vehicle is destroyed STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}No vehicles will be available at all STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}Change your NewGRF configuration STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}No vehicles are available yet STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}Start a new game after {DATE_SHORT} or use a NewGRF that provides early vehicles # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}Can't make train pass signal at danger... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}Can't reverse direction of train... STR_ERROR_TRAIN_START_NO_POWER :Train has no power STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}Can't make road vehicle turn around... STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}Aircraft is in flight # Order related errors STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}No more space for orders STR_ERROR_TOO_MANY_ORDERS :{WHITE}Too many orders STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Can't insert new order... STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Can't delete this order... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Can't modify this order... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Can't move this order... STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Can't skip current order... STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Can't skip to selected order... STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... vehicle can't go to all stations STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... vehicle can't go to that station STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... a vehicle sharing this order can't go to that station STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Can't share order list... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Can't stop sharing order list... STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Can't copy order list... STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... too far from previous destination STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... aircraft has not enough range # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Can't timetable vehicle... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehicles can only wait at stations STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}This vehicle is not stopping at this station # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... too many signs STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}Can't place sign here... STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}Can't change sign name... STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Can't delete sign... # Translatable comment for OpenTTD's desktop shortcut STR_DESKTOP_SHORTCUT_COMMENT :A simulation game based on Transport Tycoon Deluxe # Translatable descriptions in media/baseset/*.ob* files STR_BASEGRAPHICS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS edition graphics. STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Original Transport Tycoon Deluxe DOS (German) edition graphics. STR_BASEGRAPHICS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition graphics. STR_BASESOUNDS_DOS_DESCRIPTION :Original Transport Tycoon Deluxe DOS edition sounds. STR_BASESOUNDS_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition sounds. STR_BASESOUNDS_NONE_DESCRIPTION :A sound pack without any sounds. STR_BASEMUSIC_WIN_DESCRIPTION :Original Transport Tycoon Deluxe Windows edition music. STR_BASEMUSIC_NONE_DESCRIPTION :A music pack without actual music. ##id 0x2000 # Town building names STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :Tall office block STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :Office block STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :Small block of flats STR_TOWN_BUILDING_NAME_CHURCH_1 :Church STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :Large office block STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :Town houses STR_TOWN_BUILDING_NAME_HOTEL_1 :Hotel STR_TOWN_BUILDING_NAME_STATUE_1 :Statue STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :Fountain STR_TOWN_BUILDING_NAME_PARK_1 :Park STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :Office block STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :Shops and offices STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :Modern office building STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :Warehouse STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :Office block STR_TOWN_BUILDING_NAME_STADIUM_1 :Stadium STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :Old houses STR_TOWN_BUILDING_NAME_COTTAGES_1 :Cottages STR_TOWN_BUILDING_NAME_HOUSES_1 :Houses STR_TOWN_BUILDING_NAME_FLATS_1 :Flats STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :Tall office block STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :Shops and offices STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :Shops and offices STR_TOWN_BUILDING_NAME_THEATER_1 :Theatre STR_TOWN_BUILDING_NAME_STADIUM_2 :Stadium STR_TOWN_BUILDING_NAME_OFFICES_1 :Offices STR_TOWN_BUILDING_NAME_HOUSES_2 :Houses STR_TOWN_BUILDING_NAME_CINEMA_1 :Cinema STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :Shopping centre STR_TOWN_BUILDING_NAME_IGLOO_1 :Igloo STR_TOWN_BUILDING_NAME_TEPEES_1 :Tepees STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :Teapot-House STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :Piggy-Bank ##id 0x4800 # industry names STR_INDUSTRY_NAME_COAL_MINE :Coal Mine STR_INDUSTRY_NAME_POWER_STATION :Power Station STR_INDUSTRY_NAME_SAWMILL :Sawmill STR_INDUSTRY_NAME_FOREST :Forest STR_INDUSTRY_NAME_OIL_REFINERY :Oil Refinery STR_INDUSTRY_NAME_OIL_RIG :Oil Rig STR_INDUSTRY_NAME_FACTORY :Factory STR_INDUSTRY_NAME_PRINTING_WORKS :Printing Works STR_INDUSTRY_NAME_STEEL_MILL :Steel Mill STR_INDUSTRY_NAME_FARM :Farm STR_INDUSTRY_NAME_COPPER_ORE_MINE :Copper Ore Mine STR_INDUSTRY_NAME_OIL_WELLS :Oil Wells STR_INDUSTRY_NAME_BANK :Bank STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Food Processing Plant STR_INDUSTRY_NAME_PAPER_MILL :Paper Mill STR_INDUSTRY_NAME_GOLD_MINE :Gold Mine STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Bank STR_INDUSTRY_NAME_DIAMOND_MINE :Diamond Mine STR_INDUSTRY_NAME_IRON_ORE_MINE :Iron Ore Mine STR_INDUSTRY_NAME_FRUIT_PLANTATION :Fruit Plantation STR_INDUSTRY_NAME_RUBBER_PLANTATION :Rubber Plantation STR_INDUSTRY_NAME_WATER_SUPPLY :Water Supply STR_INDUSTRY_NAME_WATER_TOWER :Water Tower STR_INDUSTRY_NAME_FACTORY_2 :Factory STR_INDUSTRY_NAME_FARM_2 :Farm STR_INDUSTRY_NAME_LUMBER_MILL :Lumber Mill STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :Candyfloss Forest STR_INDUSTRY_NAME_CANDY_FACTORY :Sweet Factory STR_INDUSTRY_NAME_BATTERY_FARM :Battery Farm STR_INDUSTRY_NAME_COLA_WELLS :Cola Wells STR_INDUSTRY_NAME_TOY_SHOP :Toy Shop STR_INDUSTRY_NAME_TOY_FACTORY :Toy Factory STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :Plastic Fountains STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :Fizzy Drink Factory STR_INDUSTRY_NAME_BUBBLE_GENERATOR :Bubble Generator STR_INDUSTRY_NAME_TOFFEE_QUARRY :Toffee Quarry STR_INDUSTRY_NAME_SUGAR_MINE :Sugar Mine ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Unnamed STR_SV_TRAIN_NAME :Train {COMMA} STR_SV_ROAD_VEHICLE_NAME :Road Vehicle {COMMA} STR_SV_SHIP_NAME :Ship {COMMA} STR_SV_AIRCRAFT_NAME :Aircraft {COMMA} STR_SV_STNAME :{STRING1} STR_SV_STNAME_NORTH :{STRING1} North STR_SV_STNAME_SOUTH :{STRING1} South STR_SV_STNAME_EAST :{STRING1} East STR_SV_STNAME_WEST :{STRING1} West STR_SV_STNAME_CENTRAL :{STRING1} Central STR_SV_STNAME_TRANSFER :{STRING1} Transfer STR_SV_STNAME_HALT :{STRING1} Halt STR_SV_STNAME_VALLEY :{STRING1} Valley STR_SV_STNAME_HEIGHTS :{STRING1} Heights STR_SV_STNAME_WOODS :{STRING1} Woods STR_SV_STNAME_LAKESIDE :{STRING1} Lakeside STR_SV_STNAME_EXCHANGE :{STRING1} Exchange STR_SV_STNAME_AIRPORT :{STRING1} Airport STR_SV_STNAME_OILFIELD :{STRING1} Oilfield STR_SV_STNAME_MINES :{STRING1} Mines STR_SV_STNAME_DOCKS :{STRING1} Docks STR_SV_STNAME_BUOY :{STRING2} STR_SV_STNAME_WAYPOINT :{STRING2} ##id 0x6020 STR_SV_STNAME_ANNEXE :{STRING1} Annexe STR_SV_STNAME_SIDINGS :{STRING1} Sidings STR_SV_STNAME_BRANCH :{STRING1} Branch STR_SV_STNAME_UPPER :Upper {STRING1} STR_SV_STNAME_LOWER :Lower {STRING1} STR_SV_STNAME_HELIPORT :{STRING1} Heliport STR_SV_STNAME_FOREST :{STRING1} Forest STR_SV_STNAME_FALLBACK :{STRING1} Station #{NUM} ############ end of savegame specific region! ##id 0x8000 # Vehicle names STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (Electric) STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Passenger Carriage STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Mail Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :Coal Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Oil Tanker STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Livestock Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Goods Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Grain Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :Wood Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Iron Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :Steel Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Armoured Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Food Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :Paper Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Copper Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :Water Tanker STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :Fruit Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :Rubber Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :Sugar Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Toffee Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Bubble Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :Cola Tanker STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :Sweet Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :Toy Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Battery Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Plastic Truck STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Passenger Carriage STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :Mail Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Coal Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Oil Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Livestock Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Goods Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Grain Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Wood Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Iron Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :Steel Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :Armoured Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :Food Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Paper Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Copper Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Water Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Fruit Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Rubber Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Sugar Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Toffee Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :Bubble Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Cola Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Sweet Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Toy Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Battery Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Plastic Truck STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Passenger Carriage STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Mail Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Coal Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Oil Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Livestock Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Goods Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Grain Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Wood Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Iron Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :Steel Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Armoured Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Food Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Paper Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Copper Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Water Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Fruit Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Rubber Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Sugar Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Candyfloss Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Toffee Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Bubble Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Cola Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Sweet Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Toy Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Battery Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Fizzy Drink Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Bus STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Balogh Coal Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Uhl Coal Truck STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :DW Coal Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :MPS Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Reynard Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Perry Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :MightyMover Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Powernaught Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Wizzowow Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Witcombe Oil Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Foster Oil Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Perry Oil Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Talbott Livestock Van STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Uhl Livestock Van STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Foster Livestock Van STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Balogh Goods Truck STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Craighead Goods Truck STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Goss Goods Truck STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Hereford Grain Truck STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Thomas Grain Truck STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Goss Grain Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Witcombe Wood Truck STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :Foster Wood Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :Moreland Wood Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :MPS Iron Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :Uhl Iron Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :Chippy Iron Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :Balogh Steel Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :Uhl Steel Truck STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :Kelling Steel Truck STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :Balogh Armoured Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :Uhl Armoured Truck STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Foster Armoured Truck STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Foster Food Van STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Perry Food Van STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Chippy Food Van STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Uhl Paper Truck STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Balogh Paper Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :MPS Paper Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :MPS Copper Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Uhl Copper Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Goss Copper Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Uhl Water Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Balogh Water Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :MPS Water Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Balogh Fruit Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Uhl Fruit Truck STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kelling Fruit Truck STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Balogh Rubber Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Uhl Rubber Truck STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :RMT Rubber Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Sugar Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Powernaught Sugar Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Wizzowow Sugar Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :MightyMover Cola Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Powernaught Cola Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Wizzowow Cola Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :MightyMover Candyfloss Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Powernaught Candyfloss Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Candyfloss Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Toffee Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Toffee Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Toffee Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :MightyMover Toy Van STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Powernaught Toy Van STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Wizzowow Toy Van STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :MightyMover Sweet Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Powernaught Sweet Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Wizzowow Sweet Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Battery Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Powernaught Battery Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Wizzowow Battery Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :MightyMover Fizzy Drink Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Powernaught Fizzy Drink Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Fizzy Drink Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Bubble Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Bubble Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Bubble Truck STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :MPS Oil Tanker STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :CS-Inc. Oil Tanker STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :MPS Passenger Ferry STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :FFP Passenger Ferry STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Hovercraft STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Chugger-Chug Passenger Ferry STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Passenger Ferry STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Yate Cargo Ship STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Bakewell Cargo Ship STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :MightyMover Cargo Ship STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Powernaut Cargo Ship STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Tricario Helicopter STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Guru X2 Helicopter STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut Helicopter ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{RAW_STRING}-{RAW_STRING}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} STR_FORMAT_DATE_ISO :{2:NUM}-{1:RAW_STRING}-{0:RAW_STRING} STR_FORMAT_BUOY_NAME :{TOWN} Buoy STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Buoy #{COMMA} STR_FORMAT_COMPANY_NUM :(Company {COMMA}) STR_FORMAT_GROUP_NAME :Group {COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :{TOWN} Waypoint STR_FORMAT_WAYPOINT_NAME_SERIAL :{TOWN} Waypoint #{COMMA} STR_FORMAT_DEPOT_NAME_TRAIN :{TOWN} Train Depot STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :{TOWN} Train Depot #{COMMA} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :{TOWN} Road Vehicle Depot STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :{TOWN} Road Vehicle Depot #{COMMA} STR_FORMAT_DEPOT_NAME_SHIP :{TOWN} Ship Depot STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :{TOWN} Ship Depot #{COMMA} STR_FORMAT_DEPOT_NAME_AIRCRAFT :{STATION} Hangar STR_UNKNOWN_STATION :unknown station STR_DEFAULT_SIGN_NAME :Sign STR_COMPANY_SOMEONE :someone STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING1} STR_SAVEGAME_NAME_SPECTATOR :Spectator, {1:STRING1} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} STR_VIEWPORT_WAYPOINT :{WAYPOINT} STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} STR_DEPOT_NAME :{DEPOT} STR_ENGINE_NAME :{ENGINE} STR_HIDDEN_ENGINE_NAME :{ENGINE} (hidden) STR_GROUP_NAME :{GROUP} STR_INDUSTRY_NAME :{INDUSTRY} STR_PRESIDENT_NAME :{PRESIDENT_NAME} STR_SIGN_NAME :{SIGN} STR_STATION_NAME :{STATION} STR_TOWN_NAME :{TOWN} STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} STR_JUST_DATE_LONG :{DATE_LONG} STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{RAW_STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{RAW_STRING} # Slightly 'raw' stringcodes with colour or size STR_BLACK_COMMA :{BLACK}{COMMA} STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} STR_TINY_COMMA :{TINY_FONT}{COMMA} STR_BLUE_COMMA :{BLUE}{COMMA} STR_RED_COMMA :{RED}{COMMA} STR_WHITE_COMMA :{WHITE}{COMMA} STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} STR_TINY_GROUP :{TINY_FONT}{GROUP} STR_BLACK_INT :{BLACK}{NUM} STR_ORANGE_INT :{ORANGE}{NUM} STR_WHITE_SIGN :{WHITE}{SIGN} STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} STR_BLACK_STRING :{BLACK}{STRING} STR_BLACK_RAW_STRING :{BLACK}{RAW_STRING} STR_ORANGE_STRING :{ORANGE}{STRING} STR_LTBLUE_STRING :{LTBLUE}{STRING} STR_WHITE_STRING :{WHITE}{STRING} STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING1}{WHITE} STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING1}{LTBLUE} STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} STR_BLACK_1 :{BLACK}1 STR_BLACK_2 :{BLACK}2 STR_BLACK_3 :{BLACK}3 STR_BLACK_4 :{BLACK}4 STR_BLACK_5 :{BLACK}5 STR_BLACK_6 :{BLACK}6 STR_BLACK_7 :{BLACK}7 STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) openttd-1.5.3/src/lang/thai.txt0000644000000000000000000215110312627373445015111 0ustar rootroot##name Thai ##ownname Thai ##isocode th_TH ##plural 1 ##textdir ltr ##digitsep , ##digitsepcur , ##decimalsep . ##winlangid 0x041e ##grflangid 0x42 # $Id: thai.txt 27353 2015-07-31 17:46:09Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(undefined string) STR_JUST_NOTHING :ไม่มีอะไร # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :ผู้โดยสาร STR_CARGO_PLURAL_COAL :ถ่านหิน STR_CARGO_PLURAL_MAIL :พัสดุ STR_CARGO_PLURAL_OIL :น้ำมันดิบ STR_CARGO_PLURAL_LIVESTOCK :ปศุสัตว์ STR_CARGO_PLURAL_GOODS :สินค้าแปรรูป STR_CARGO_PLURAL_GRAIN :ข้าวเปลือก STR_CARGO_PLURAL_WOOD :ท่อนซุง STR_CARGO_PLURAL_IRON_ORE :แร่เหล็ก STR_CARGO_PLURAL_STEEL :เหล็กกล้า STR_CARGO_PLURAL_VALUABLES :สินค้ามูลค่าสูง STR_CARGO_PLURAL_COPPER_ORE :แร่ทองแดง STR_CARGO_PLURAL_MAIZE :ข้าวโพด STR_CARGO_PLURAL_FRUIT :ผลไม้ STR_CARGO_PLURAL_DIAMONDS :เพชร STR_CARGO_PLURAL_FOOD :อาหาร STR_CARGO_PLURAL_PAPER :กระดาษ STR_CARGO_PLURAL_GOLD :ทองคำ STR_CARGO_PLURAL_WATER :น้ำ STR_CARGO_PLURAL_WHEAT :ข้าวสาลี STR_CARGO_PLURAL_RUBBER :ยางพารา STR_CARGO_PLURAL_SUGAR :น้ำตาล STR_CARGO_PLURAL_TOYS :ของเล่น STR_CARGO_PLURAL_CANDY :ขนมสายไหม STR_CARGO_PLURAL_COLA :โคล่า STR_CARGO_PLURAL_COTTON_CANDY :ขนมสายไหม STR_CARGO_PLURAL_BUBBLES :ฟอง STR_CARGO_PLURAL_TOFFEE :ลูกอม STR_CARGO_PLURAL_BATTERIES :ถ่านไฟฉาย STR_CARGO_PLURAL_PLASTIC :พลาสติก STR_CARGO_PLURAL_FIZZY_DRINKS :น้ำอัดลม # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :ผู้โดยสาร STR_CARGO_SINGULAR_COAL :ถ่านหิน STR_CARGO_SINGULAR_MAIL :ไปรษณีย์ STR_CARGO_SINGULAR_OIL :น้ำมันดิบ STR_CARGO_SINGULAR_LIVESTOCK :ปศุสัตว์ STR_CARGO_SINGULAR_GOODS :สินค้าแปรรูป STR_CARGO_SINGULAR_GRAIN :ข้าวสาลี STR_CARGO_SINGULAR_WOOD :ท่อนซุง STR_CARGO_SINGULAR_IRON_ORE :แร่เหล็ก STR_CARGO_SINGULAR_STEEL :เหล็กกล้า STR_CARGO_SINGULAR_VALUABLES :สินค้ามูลค่าสูง STR_CARGO_SINGULAR_COPPER_ORE :แร่ทองแดง STR_CARGO_SINGULAR_MAIZE :ข้าวโพด STR_CARGO_SINGULAR_FRUIT :ผลไม้ STR_CARGO_SINGULAR_DIAMOND :เพชร STR_CARGO_SINGULAR_FOOD :อาหาร STR_CARGO_SINGULAR_PAPER :กระดาษ STR_CARGO_SINGULAR_GOLD :ทองคำ STR_CARGO_SINGULAR_WATER :น้ำ STR_CARGO_SINGULAR_WHEAT :ข้าวสาลี STR_CARGO_SINGULAR_RUBBER :ยางพารา STR_CARGO_SINGULAR_SUGAR :น้ำตาล STR_CARGO_SINGULAR_TOY :ของเล่น STR_CARGO_SINGULAR_CANDY :ขนมสายไหม STR_CARGO_SINGULAR_COLA :โคล่า STR_CARGO_SINGULAR_COTTON_CANDY :ขนมสายไหม STR_CARGO_SINGULAR_BUBBLE :ฟอง STR_CARGO_SINGULAR_TOFFEE :ลูกอม STR_CARGO_SINGULAR_BATTERY :ถ่านไฟฉาย STR_CARGO_SINGULAR_PLASTIC :พลาสติก STR_CARGO_SINGULAR_FIZZY_DRINK :น้ำอัดลม # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :ผู้โดยสาร {COMMA} คน STR_QUANTITY_COAL :ถ่านหิน {WEIGHT_LONG} STR_QUANTITY_MAIL :ไปรษณีย์ {COMMA} ถุง STR_QUANTITY_OIL :น้ำมันดิบ {VOLUME_LONG} STR_QUANTITY_LIVESTOCK :ปศุสัตว์ {COMMA} ตัว STR_QUANTITY_GOODS :สินค้าแปรรูป {COMMA} ลัง STR_QUANTITY_GRAIN :ข้าวสาลี {WEIGHT_LONG} STR_QUANTITY_WOOD :ท่อนซุง {WEIGHT_LONG} STR_QUANTITY_IRON_ORE :แร่เหล็ก {WEIGHT_LONG} STR_QUANTITY_STEEL :เหล็กกล้า {WEIGHT_LONG} STR_QUANTITY_VALUABLES :สินค้ามูลค่าสูง {COMMA} ถุง STR_QUANTITY_COPPER_ORE :แร่ทองแดง {WEIGHT_LONG} STR_QUANTITY_MAIZE :ข้าวโพด {WEIGHT_LONG} STR_QUANTITY_FRUIT :ผลไม้ {WEIGHT_LONG} STR_QUANTITY_DIAMONDS :เพชร {COMMA} ถุง STR_QUANTITY_FOOD :อาหาร {WEIGHT_LONG} STR_QUANTITY_PAPER :กระดาษ {WEIGHT_LONG} STR_QUANTITY_GOLD :ทองคำ {COMMA} ถุง STR_QUANTITY_WATER :น้ำ {VOLUME_LONG} STR_QUANTITY_WHEAT :ข้าวสาลี {WEIGHT_LONG} STR_QUANTITY_RUBBER :ยางพารา {VOLUME_LONG} สิตร STR_QUANTITY_SUGAR :น้ำตาล {WEIGHT_LONG} STR_QUANTITY_TOYS :ของเล่น {COMMA} ชิ้น STR_QUANTITY_SWEETS :ขนมหวาน {COMMA} ถุง STR_QUANTITY_COLA :โคล่า {VOLUME_LONG} ลิตร STR_QUANTITY_CANDYFLOSS :ขนมสายไหม {WEIGHT_LONG} STR_QUANTITY_BUBBLES :ฟอง {COMMA} ลูก STR_QUANTITY_TOFFEE :ลูกอม {WEIGHT_LONG} STR_QUANTITY_BATTERIES :ถ่านไฟฉาย {COMMA} ก้อน STR_QUANTITY_PLASTIC :พลาสติก {VOLUME_LONG} STR_QUANTITY_FIZZY_DRINKS :น้ำอัดลม {COMMA} ชุด STR_QUANTITY_N_A :N/A # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}คน STR_ABBREV_COAL :{TINY_FONT}ถ่าน STR_ABBREV_MAIL :{TINY_FONT}พัสดุ STR_ABBREV_OIL :{TINY_FONT}น้ำมัน STR_ABBREV_LIVESTOCK :{TINY_FONT}สัตว์ STR_ABBREV_GOODS :{TINY_FONT}สินค้า STR_ABBREV_GRAIN :{TINY_FONT}ข้าวเปลือก STR_ABBREV_WOOD :{TINY_FONT}ไม้ STR_ABBREV_IRON_ORE :{TINY_FONT}เหล็ก STR_ABBREV_STEEL :{TINY_FONT}เหล็กกล้า STR_ABBREV_VALUABLES :{TINY_FONT}มีค่า STR_ABBREV_COPPER_ORE :{TINY_FONT}ทองแดง STR_ABBREV_MAIZE :{TINY_FONT}ข้าวโพด STR_ABBREV_FRUIT :{TINY_FONT}ผลไม้ STR_ABBREV_DIAMONDS :{TINY_FONT}เพชร STR_ABBREV_FOOD :{TINY_FONT}อาหาร STR_ABBREV_PAPER :{TINY_FONT}กระดาษ STR_ABBREV_GOLD :{TINY_FONT}ทอง STR_ABBREV_WATER :{TINY_FONT}น้ำ STR_ABBREV_WHEAT :{TINY_FONT}ข้าวสาลี STR_ABBREV_RUBBER :{TINY_FONT}ยาง STR_ABBREV_SUGAR :{TINY_FONT}น้ำตาล STR_ABBREV_TOYS :{TINY_FONT}ของเล่น STR_ABBREV_SWEETS :{TINY_FONT}ขนม STR_ABBREV_COLA :{TINY_FONT}โคล่า STR_ABBREV_CANDYFLOSS :{TINY_FONT}สายไหม STR_ABBREV_BUBBLES :{TINY_FONT}ฟอง STR_ABBREV_TOFFEE :{TINY_FONT}ลูกอม STR_ABBREV_BATTERIES :{TINY_FONT}ถ่าน STR_ABBREV_PLASTIC :{TINY_FONT}พลาสติก STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}น้ำอัดลม STR_ABBREV_NONE :{TINY_FONT}ว่าง STR_ABBREV_ALL :{TINY_FONT}ทั้งหมด # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA} คน STR_BAGS :{COMMA} ถุง STR_TONS :{COMMA} ตัน STR_LITERS :{COMMA} ลิตร STR_ITEMS :{COMMA} ชิ้น STR_CRATES :{COMMA} ลัง # Colours, do not shuffle STR_COLOUR_DARK_BLUE :น้ำเงินเข้ม STR_COLOUR_PALE_GREEN :เขียวอ่อน STR_COLOUR_PINK :ชมพู STR_COLOUR_YELLOW :เหลือง STR_COLOUR_RED :แดง STR_COLOUR_LIGHT_BLUE :ฟ้า STR_COLOUR_GREEN :เขียว STR_COLOUR_DARK_GREEN :เขียวเข้ม STR_COLOUR_BLUE :น้ำเงิน STR_COLOUR_CREAM :ครีม STR_COLOUR_MAUVE :ม่วงอ่อน STR_COLOUR_PURPLE :ม่วง STR_COLOUR_ORANGE :ส้ม STR_COLOUR_BROWN :น้ำตาล STR_COLOUR_GREY :เทา STR_COLOUR_WHITE :ขาว # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA} ไมล์/ชม. STR_UNITS_VELOCITY_METRIC :{COMMA} กม./ชม. STR_UNITS_VELOCITY_SI :{COMMA} ม./วิ. STR_UNITS_POWER_IMPERIAL :{COMMA} แรงม้า STR_UNITS_POWER_METRIC :{COMMA} แรงม้า STR_UNITS_POWER_SI :{COMMA} กิโลวัตต์ STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}ตัน STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA} ตัน STR_UNITS_WEIGHT_SHORT_SI :{COMMA} กิโลกรัม STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ตัน STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} ตัน STR_UNITS_WEIGHT_LONG_SI :{COMMA} กิโลกรัม STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}แกลลอน STR_UNITS_VOLUME_SHORT_METRIC :{COMMA} ลิตร STR_UNITS_VOLUME_SHORT_SI :{COMMA} ลบ.ม. STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} แกลลอน STR_UNITS_VOLUME_LONG_METRIC :{COMMA} ลิตร STR_UNITS_VOLUME_LONG_SI :{COMMA} ลบ.ม. STR_UNITS_FORCE_IMPERIAL :{COMMA} ปอนด์ STR_UNITS_FORCE_METRIC :{COMMA} กิโลกรัม STR_UNITS_FORCE_SI :{COMMA} กิโลนิวตัน STR_UNITS_HEIGHT_IMPERIAL :{COMMA} ฟุต STR_UNITS_HEIGHT_METRIC :{COMMA} เมตร STR_UNITS_HEIGHT_SI :{COMMA} ม. # Common window strings STR_LIST_FILTER_TITLE :{BLACK}คำกรอง: STR_LIST_FILTER_OSKTITLE :{BLACK}ใส่คำกรอง STR_LIST_FILTER_TOOLTIP :{BLACK}ป้อนคำค้นเพื่อกรองรายการ STR_TOOLTIP_GROUP_ORDER :{BLACK}เลือกใช้คำสั่งสำหรับกลุ่ม STR_TOOLTIP_SORT_ORDER :{BLACK}เลือกการเรียงลำดับ (จากบนลงล่าง/จากล่างขึ้นบน) STR_TOOLTIP_SORT_CRITERIA :{BLACK}เลือกเกณฑ์การเรียงลำดับ STR_TOOLTIP_FILTER_CRITERIA :{BLACK}เลือกเกณฑ์การกรอง STR_BUTTON_SORT_BY :{BLACK}เรียงตาม STR_BUTTON_LOCATION :{BLACK}ที่ตั้ง STR_BUTTON_RENAME :{BLACK}เปลี่ยนชื่อ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}ปิดหน้าต่าง STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}ชื่อของหน้าต่าง - คลิกค้างแล้วลากเพื่อเลื่อนหน้าต่าง STR_TOOLTIP_SHADE :{BLACK}Shade window - แสดงเฉพาะแถบด้านบน STR_TOOLTIP_DEBUG :{BLACK}แสดงข้อมูล debug NewGRF STR_TOOLTIP_DEFSIZE :{BLACK}ปรับขนาดหน้าจอเป็นแรกเริ่ม. กดปุ่ม Ctrl+Click เพื่อบันทึกหน้าจอปัจจุบันเป็นขนาดแรกเริ่ม STR_TOOLTIP_STICKY :{BLACK}กำหนดไม่ให้ปิดหน้าต่างนี้เมื่อใช้ปุ่ม 'ปิดทุกหน้าต่าง' Ctrl+Click เพื่อบันทึกเป็นค่าปริยาย STR_TOOLTIP_RESIZE :{BLACK}คลิกค้างแล้วลากเพื่อเปลี่ยนขนาดของหน้าต่าง STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}เปลี่ยนขนาดหน้าต่าง ใหญ่/เล็ก STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}แถบเลื่อน - ใช้เลื่อนรายการ ขึ้น/ลง STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}แถบเลื่อน - ใช้เลื่อนรายการ ซ้าย/ขวา STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}ทำลายสิ่งก่อสร้าง และสิ่งต่างๆ ในพื้นที่ช่องหนึ่ง. กด Ctrl เพื่อเลือกพื้นที่แบบทะแยง. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้างและแสดงมูลค่า # Show engines button # Query window STR_BUTTON_DEFAULT :{BLACK}ค่าปกติ STR_BUTTON_CANCEL :{BLACK}ยกเลิก STR_BUTTON_OK :{BLACK}ตกลง # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}ความยาว: {NUM} STR_MEASURE_AREA :{BLACK}ขนาดพื้นที่: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}ความยาว: {NUM}{}ความแตกต่างของความสูง: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}ขนาดพื้นที่: {NUM} x {NUM}{}ความแตกต่างของคสามสูง: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}ชื่อ STR_SORT_BY_CAPTION_DATE :{BLACK}วันที่ # These are used in dropdowns STR_SORT_BY_NAME :ชื่อ STR_SORT_BY_PRODUCTION :ผลผลิต STR_SORT_BY_TYPE :ประเภท STR_SORT_BY_TRANSPORTED :ขนส่งแล้ว STR_SORT_BY_NUMBER :ลำดับการเข้าประจำการ STR_SORT_BY_PROFIT_LAST_YEAR :กำไรปีก่อน STR_SORT_BY_PROFIT_THIS_YEAR :กำไรปีนี้ STR_SORT_BY_AGE :อายุการใช้งาน STR_SORT_BY_RELIABILITY :ประสิทธิภาพ STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :ความจุรวมในแต่ละชนิดบรรทุก STR_SORT_BY_MAX_SPEED :ความเร็วสูงสุด STR_SORT_BY_MODEL :รุ่น STR_SORT_BY_VALUE :มูลค่า STR_SORT_BY_LENGTH :ความยาว STR_SORT_BY_LIFE_TIME :อายุการใช้งานคงเหลือ STR_SORT_BY_TIMETABLE_DELAY :ความล่าช้าจากตารางเวลา STR_SORT_BY_FACILITY :ประเภทสถานี STR_SORT_BY_WAITING_TOTAL :สินค้าที่รออยู่ทั้งหมด STR_SORT_BY_WAITING_AVAILABLE :สินค้าที่รอการขนส่งอยู่ STR_SORT_BY_RATING_MAX :สินค้ายอดนิยม STR_SORT_BY_RATING_MIN :สินค้านิยมน้อยสุด STR_SORT_BY_ENGINE_ID :EngineID (เรียงแบบดั้งเดิม) STR_SORT_BY_COST :ราคา STR_SORT_BY_POWER :พลังขับเคลื่อน STR_SORT_BY_TRACTIVE_EFFORT :กำลังลากจูง STR_SORT_BY_INTRO_DATE :วันเปิดตัว STR_SORT_BY_RUNNING_COST :ค่าใช้จ่าย STR_SORT_BY_POWER_VS_RUNNING_COST :กำลังต่อค่าใช้จ่าย STR_SORT_BY_CARGO_CAPACITY :ความจุบรรทุก STR_SORT_BY_RANGE :ช่วง STR_SORT_BY_POPULATION :ประชากร STR_SORT_BY_RATING :ความพึงพอใจ # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}หยุดเกมชั่วคราว STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}เร่งความเร็วเกม STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}ตัวเลือก STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}บันทึกและเลิกเกมนี้ STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}แสดงจุดสังเกต, แผนที่และป้าย STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}แสดงทำเนียบชื่อเมือง STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}แสดงเงินสมทบ STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}แสดงรายการสถานีของบริษัท STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}แสดงข้อมูลทางการเงินของบริษัท STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}แสดงข้อมูลทั่วไปของบริษัท STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}แสดงสมุดบันทึก STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :แสดงรายการเป้าหมายที่ต้องทำ STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}แสดงกราฟ STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}แสดงตารางอันดับบริษัท STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}ลงทุนก่อสร้างอุตสาหกรรมใหม่ หรือ แสดงรายชื่ออุตสาหกรรมทั้งหมด STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}แสดงรายการรถไฟของบริษัท, Ctrl+คลิก เพื่อเปลี่ยนดู กลุ่ม/รายการ ยานพาหนะ STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}แสดงรายการรถยนต์ของบริษัท, Ctrl+คลิก เพื่อเปลี่ยนดู กลุ่ม/รายการ ยานพาหนะ STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}แสดงรายการเรือของบริษัท, Ctrl+คลิก เพื่อเปลี่ยนดู กลุ่ม/รายการ ยานพาหนะ STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}แสดงรายการอากาศยานของบริษัท, Ctrl+คลิก เพื่อเปลี่ยนดู กลุ่ม/รายการ ยานพาหนะ STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}ขยายวิว STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}ย่อวิว STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}เครื่องมือสร้างทางรถไฟ STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}สร้างถนน STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}สร้างท่าเรือ STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}สร้างท่าอากาศยาน STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}เปิดแถบเครื่องมือภูมิประเทศเพื่อปรับความสูงต่ำของพื้นดิน, ปลูกต้นไม้ ฯลฯ STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}แสดงหน้าต่างเสียงและดนตรี STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}แสดงข้อความล่าสุด/รายงานข่าว, แสดงตัวเลือกข้อความ STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}ข้อมูลที่ดิน, คอนโซล, ดีบัก AI, จับภาพหน้าจอ, เกี่ยวกับ OpenTTD STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}เปลี่ยนกล่องเครื่องมือ # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}บันทึกฉาก, โหลดฉาก, ยกเลิกการแก้ไขฉาก, ออก STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}โปรแกรมแก้ไขแผนที่ STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}เลื่อนวันที่เริ่มต้นย้อนไป 1 ปี STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}เลือนวันที่เริ่มต้นไปอีก 1 ปี STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}คลิกเพื่อใส่ปีเริ่มต้น STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}แสดงแผนที่และทำเนียบชื่อเมือง STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}สร้างภูมิประเทศ STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}สร้างเมือง STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}สร้างอุตสาหกรรม STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}สร้างถนน STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}ปลูกต้นไม้. กด Shift เพื่อเปิด-ปิดสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}ปักป้าย STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}วางวัตถุ. กด Shift เพื่อปิด-เปิดสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :บันทึกแผนที่ STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :โหลดแผนที่ STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :บันทึกแผนที่ความสูง STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :โหลดแผนที่ความสูง STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :ออกจากโปรแกรมแก้ไขแผนที่ STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :ออก ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :ตัวเลือกเกม STR_SETTINGS_MENU_SCRIPT_SETTINGS :กำหนดค่าสคริปต์ AI/Game STR_SETTINGS_MENU_NEWGRF_SETTINGS :กำหนดค่า NewGRF STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :แถบเมนูตั้งค่าวัตถุโปร่งใส STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :แสดงชื่อเมือง STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :แสดงชื่อสถานี STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :แสดงจุดผ่าน STR_SETTINGS_MENU_SIGNS_DISPLAYED :แสดงป้าย STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :แสดงชื่อและป้ายของคู่แข่ง STR_SETTINGS_MENU_FULL_ANIMATION :แสดงภาพเคลื่อนไหวทั้งหมด STR_SETTINGS_MENU_FULL_DETAIL :แสดงรายละเอียดทั้งหมด STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :สิ่งก่อสร้างแบบโปร่งใส STR_SETTINGS_MENU_TRANSPARENT_SIGNS :ป้ายแบบโปร่งใส ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :บันทึกเกม STR_FILE_MENU_LOAD_GAME :โหลดเกม STR_FILE_MENU_QUIT_GAME :กลับไปยังเมนูหลักของเกม STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :ออกจากเกม ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :แผนที่โลก STR_MAP_MENU_EXTRA_VIEW_PORT :มุมมองเพิ่มเติม STR_MAP_MENU_LINGRAPH_LEGEND :เส้นทางการกระจายสินค้า STR_MAP_MENU_SIGN_LIST :รายการป้าย ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :ทำเนียบชื่อเมือง STR_TOWN_MENU_FOUND_TOWN :ตั้งเมือง ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :การสนับสนุน ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :กราฟแสดงผลประกอบการ STR_GRAPH_MENU_INCOME_GRAPH :กราฟแสดงรายได้ STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :กราฟแสดงปริมาณการขนส่งสินค้า STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :กราฟแสดงประสิทธิภาพของบริษัท STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :กราฟแสดงมูลค่าบริษัท STR_GRAPH_MENU_CARGO_PAYMENT_RATES :อัตราผลตอบแทนของการส่งสินค้า ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :ตารางแสดงอันดับบริษัท STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :การวัดผลประสิทธิภาพอย่างละเอียด STR_GRAPH_MENU_HIGHSCORE :ตารางคะแนนสูงสุด ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :ทำเนียบอุตสาหกรรม STR_INDUSTRY_MENU_INDUSTRY_CHAIN :ห่วงโซ่อุตสาหกรรม STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :ลงทุนอุตสาหกรรมใหม่ ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :การก่อสร้างทางรถไฟ STR_RAIL_MENU_ELRAIL_CONSTRUCTION :การก่อสร้างทางรถไฟพลังไฟฟ้า STR_RAIL_MENU_MONORAIL_CONSTRUCTION :การก่อสร้างทางรถไฟรางเดี่ยว STR_RAIL_MENU_MAGLEV_CONSTRUCTION :การก่อสร้างทางรถไฟพลังแม่เหล็ก ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :การก่อสร้างถนน STR_ROAD_MENU_TRAM_CONSTRUCTION :การก่อสร้างทางรถราง ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :การก่อสร้างคลอง ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :การก่อสร้างท่าอากาศยาน ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :การปรับพื้นที่ STR_LANDSCAPING_MENU_PLANT_TREES :ปลูกต้นไม้ STR_LANDSCAPING_MENU_PLACE_SIGN :ปักป้าย ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :เสียงและดนตรี ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :ข้อความล่าสุด/รายงานข่าว STR_NEWS_MENU_MESSAGE_HISTORY_MENU :ดูข้อความย้อนหลัง ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :ข้อมูลพื้นที่ STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :เปิด/ปิด คอนโซล STR_ABOUT_MENU_AI_DEBUG :ดีบัก สคริปต์ AI/Game STR_ABOUT_MENU_SCREENSHOT :จับภาพหน้าจอ (Ctrl+S) STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :จับภาพหน้าจอในแบบขยายใหญ่สุด STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :ค่าเริ่มต้นของการขยายภาพในการจับหน้าจอ STR_ABOUT_MENU_GIANT_SCREENSHOT :จับภาพหน้าจอทั้งแผนที่ (Ctrl+G) STR_ABOUT_MENU_ABOUT_OPENTTD :เกี่ยวกับ 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :ตัวจัดแนว Sprite STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :เปิด/ปิด bounding boxes STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :เปิด/เปิด สีของ dirty blocks ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :วันที่ 1 STR_ORDINAL_NUMBER_2ND :วันที่ 2 STR_ORDINAL_NUMBER_3RD :วันที่ 3 STR_ORDINAL_NUMBER_4TH :วันที่ 4 STR_ORDINAL_NUMBER_5TH :วันที่ 5 STR_ORDINAL_NUMBER_6TH :วันที่ 6 STR_ORDINAL_NUMBER_7TH :วันที่ 7 STR_ORDINAL_NUMBER_8TH :วันที่ 8 STR_ORDINAL_NUMBER_9TH :วันที่ 9 STR_ORDINAL_NUMBER_10TH :วันที่ 10 STR_ORDINAL_NUMBER_11TH :วันที่ 11 STR_ORDINAL_NUMBER_12TH :วันที่ 12 STR_ORDINAL_NUMBER_13TH :วันที่ 13 STR_ORDINAL_NUMBER_14TH :วันที่ 14 STR_ORDINAL_NUMBER_15TH :วันที่ 15 ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :วันที่ 1 STR_DAY_NUMBER_2ND :วันที่ 2 STR_DAY_NUMBER_3RD :วันที่ 3 STR_DAY_NUMBER_4TH :วันที่ 4 STR_DAY_NUMBER_5TH :วันที่ 5 STR_DAY_NUMBER_6TH :วันที่ 6 STR_DAY_NUMBER_7TH :วันที่ 7 STR_DAY_NUMBER_8TH :วันที่ 8 STR_DAY_NUMBER_9TH :วันที่ 9 STR_DAY_NUMBER_10TH :วันที่ 10 STR_DAY_NUMBER_11TH :วันที่ 11 STR_DAY_NUMBER_12TH :วันที่ 12 STR_DAY_NUMBER_13TH :วันที่ 13 STR_DAY_NUMBER_14TH :วันที่ 14 STR_DAY_NUMBER_15TH :วันที่ 15 STR_DAY_NUMBER_16TH :วันที่ 16 STR_DAY_NUMBER_17TH :วันที่ 17 STR_DAY_NUMBER_18TH :วันที่ 18 STR_DAY_NUMBER_19TH :วันที่ 19 STR_DAY_NUMBER_20TH :วันที่ 20 STR_DAY_NUMBER_21ST :วันที่ 21 STR_DAY_NUMBER_22ND :วันที่ 22 STR_DAY_NUMBER_23RD :วันที่ 23 STR_DAY_NUMBER_24TH :วันที่ 24 STR_DAY_NUMBER_25TH :วันที่ 25 STR_DAY_NUMBER_26TH :วันที่ 26 STR_DAY_NUMBER_27TH :วันที่ 27 STR_DAY_NUMBER_28TH :วันที่ 28 STR_DAY_NUMBER_29TH :วันที่ 29 STR_DAY_NUMBER_30TH :วันที่ 30 STR_DAY_NUMBER_31ST :วันที่ 31 ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :มกราคม STR_MONTH_ABBREV_FEB :กุมภาพันธ์ STR_MONTH_ABBREV_MAR :มีนาคม STR_MONTH_ABBREV_APR :เมษายน STR_MONTH_ABBREV_MAY :พฤษภาคม STR_MONTH_ABBREV_JUN :มิถุนายน STR_MONTH_ABBREV_JUL :กรกฎาคม STR_MONTH_ABBREV_AUG :สิงหาคม STR_MONTH_ABBREV_SEP :กันยายน STR_MONTH_ABBREV_OCT :ตุลาคม STR_MONTH_ABBREV_NOV :พฤศจิกายน STR_MONTH_ABBREV_DEC :ธันวาคม STR_MONTH_JAN :มกราคม STR_MONTH_FEB :กุมภาพันธ์ STR_MONTH_MAR :มีนาคม STR_MONTH_APR :เมษายน STR_MONTH_MAY :พฤษภาคม STR_MONTH_JUN :มิถุนายน STR_MONTH_JUL :กรกฎาคม STR_MONTH_AUG :สิงหาคม STR_MONTH_SEP :กันยายน STR_MONTH_OCT :ตุลาคม STR_MONTH_NOV :พฤศจิกายน STR_MONTH_DEC :ธันวาคม ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}ตัวเลือก STR_GRAPH_KEY_TOOLTIP :{BLACK}แสดงตัวเลือกกราฟ STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}กราฟแสดงผลประกอบการ STR_GRAPH_INCOME_CAPTION :{WHITE}กราฟแสดงรายได้ STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}หน่วยของสินค้าที่ขนส่งแล้ว STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}คะแนนประสิทธิภาพของบริษัท (คะแนนสูงสุด=1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}มูลค่าทรัพย์สินบริษัท STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}อัตราค่าตอบแทนการขนส่ง STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}จำนวนวันในการเดินทาง STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}ค่าขนส่งจากการขนส่งสินค้า 10 หน่วย (หรือ 10,000 ลิตร) ต่อระยะทาง 20 ช่องตาราง STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}เปิดทั้งหมด STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}ปิดทั้งหมด all STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}แสดงสินค้าทั้งหมดในกราฟผลตอบแทนการขนส่งสินค้า STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}ไม่แสดงสินค้าทั้งหมดในกราฟผลตอบแทนการขนส่งสินค้า STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}เปิด/ปิด กราฟสำหรับประเภทของสินค้า STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}แสดงรายละเอียดความพึงพอใจของผู้ใช้บริการ # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}ตัวเลือกกราฟของบริษัท STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}คลิก เพื่อเปิด/ปิดการแสดงบันทึกของบริษัทในกราฟ # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}ตารางแสดงอันดับบรัษัท STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :วิศวกรบำรุงทาง STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :ผังควบคุมการเดินรถ STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :ผู้เชี่ยวชาญการขนส่ง STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :ที่ปรึกษาพิเศษด้านการเดินรถ STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :ผู้จัดการภาค STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :กรรมการผู้ัจัดการใหญ่ STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :ประธาน STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :ประธานบริษัท STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :เจ้าของบริษัท # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}รายละเอียดความนิยม STR_PERFORMANCE_DETAIL_KEY :{BLACK}รายละเอียด STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}ดูรายละเอียดของบริษัทนี้ ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}จำนวนยานพาหนะ STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}จำนวนสถานี STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}กำไรต่ำสุด STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}รายได้ต่ำสุด STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}รายได้สูงสุด STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}ปริมาณการขนส่ง STR_PERFORMANCE_DETAIL_CARGO :{BLACK}ประเภทสินค้า STR_PERFORMANCE_DETAIL_MONEY :{BLACK}เงินในธนาคาร STR_PERFORMANCE_DETAIL_LOAN :{BLACK}หนี้สิน STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}รวมทั้งสิ้น ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}จำนวนของยานพาหนะที่ทำกำไรในปีที่ผ่านมา ทั้ง รถ รถไฟ เรือ และ เครื่องบิน STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}ตัวเลขแสดงสถานีที่รองรับการซ่อมแซมในปัจจุบัน สถานีรถไฟ ป้ายรถประจำทาง ท่าอากาศยาน และอื่นๆ จะนับแยกกันจนกระทั่งสถานีเหล่านั้นจะรวมกันเป็นสถานีเดียว STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}รายได้จากยานพาหนะนี้รวมกับรายได้ต่ำสุด (แสดงเฉพาะยานพาหนะที่มีอายุมากกว่าสองปีขึ้นไป) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}รายได้รวมทั้งหมดในฟนึ่งไตรมาส กับรายได้ต่ำสุดในรอบ 12 ไตรมาส STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}รายได้รวมทั้งหมดในหนึ่งไตรมาส กับรายได้สูงสุดในรอบ 12 ไตรมาส STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}หน่วยของสินค้าที่ส่งถึงปลายทางในรอบหนึ่งปี STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}จำนวนประเภทของสินค้าที่ส่งถึงปลายทางในไตรมาสที่ผ่านมา STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}จำนวนเงินของบริษัทที่มีในธนาคาร STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}จำนวนเงินของบริษัทที่มีการกู้ยืมมาจากธนาคาร STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}คะแนนรวมทั้งหมดนอกเหนือจากคะแนนที่เป็นไปได้ # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}ตู้เพลงแจ๊ส STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}ทั้งหมด STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}แนวดั้งเดิม STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}แนวใหม่ STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}อีซี่สตรีท STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}กำหนดเอง 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}กำหนดเอง 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}ระดับเสียงดนตรี STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}ระดับเสียงเอฟเฟกต์ STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}ต่ำสุด STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}สูงสุด STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}เพลงที่ STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}ชื่อเพลง STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}สลับลำดับ STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}โปรแกรม STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}ย้อนไปฟังเพลงก่อนหน้า STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}ข้ามไปฟังเพลงถัดไป STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}หยุดเล่นเพลง STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}เริ่มเล่นเพลง STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}คลิกและลากตัวเลื่อนเพื่อปรับระดับเสียงดนตรีและเอฟเฟกต์ STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}เลือกโปรแกรม 'ทุกเพลง' STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}เลือกโปรแกรม 'เพลงแนวเก่า' STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}เลือกโปรแกรม 'เพลงแนวใหม่' STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}เลือกเพลงฟังรายการเพลง Ezy Street STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}เลือกโปรแกรม 'กำหนดเอง 1' STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}เลือกโปรแกรม 'กำหนดเอง 2' STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}เปิด/ปิด Toggle programme shuffle on/off STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}แสดงหน้าต่างเลือกรายการเพลง STR_ERROR_NO_SONGS :{WHITE}ชุดเพลงประกอบนี้ไม่มีการเลือกเพลงไว้ # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}รายการเลือกโปรแกรมเพลง STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}รายการเพลง STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}โปรแกรม - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}ลบทั้งหมด STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}ลบโปรแกรมปัจจุบัน (สำหรับโปรแกรมกำหนดเอง 1 หรือ กำหนดเอง 2 เท่านั้น) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}คลิกที่รายการเพลงเพื่อเพิ่มไปยังโปรแกรมปัจจุบัน (สำหรับโปรแกรมกำหนดเอง 1 หรือ กำหนดเอง 2 เท่านั้น) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}คลิกที่ชื่อเพลงเพื่อลบออกจากโปรแกรม (Custom1 or Custom2 เท่านั้น) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}บริษัทชั้นนำที่ก้าวไปสู่ {NUM} STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}ตารางแสดงการแข่งขันของบริษัทใน {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :นักธุรกิจ STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :ผู้ประกอบการ STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :นักอุตสาหกรรม STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :นักลงทุน STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :เจ้าสัว STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :ผู้มีอำนาจ STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :นักธุรกิจผู้ร่ำรวยและมีอิทธิพลมากแห่งศตวรรษ STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} ได้ก้าวไปสู่ขั้น '{STRING}'! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} จาก {COMPANY} ได้ก้าวไปสู่ขั้น '{STRING}'! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}แผนที่ - {STRING} STR_SMALLMAP_TYPE_CONTOURS :โครงร่าง STR_SMALLMAP_TYPE_VEHICLES :ยานยนต์ STR_SMALLMAP_TYPE_INDUSTRIES :อุตสาหกรรม STR_SMALLMAP_TYPE_ROUTEMAP :เส้นทางการกระจายสินค้า STR_SMALLMAP_TYPE_ROUTES :เส้นทาง STR_SMALLMAP_TYPE_VEGETATION :ภาวะหยุดนิ่ง STR_SMALLMAP_TYPE_OWNERS :ผู้ครอบครอง STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}แสดงโครงร่างของพื้นดินบนแผนที่ STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}แสดงยานยนต์บนแผนที่ STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}แสดงอุตสาหกรรมบนแผนที่ STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}แสดงเส้นทางและความหนาแน่นบนแผนที่ STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}แสดงเส้นทางการเดินทางบนแผนที่ STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}แสดงพืชพันธุ์บนแผนที่ STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}แสดงเจ้าของที่ดินบนแผนที่ STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}กดเลือกที่ประเภทของอุตสาหกรรมเพื่อแสดงผล. Ctrl+Click เพื่อปิดทุกประเภทยกเว้นประเภทที่เลือก. Ctrl+Click อีกครั้งเพื่อแสดงทุกอุตสาหกรรม STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}กดเลือกที่บริษัทเพื่อปิด/เปิดการแสดงข้อมูลของบริษัท. Ctrl+กดเลือก เพื่อปิดแสดงผลทุกบริษัทยกเว้นอันที่เลือก. Ctrl+กดเลือกอีกครั้งเพื่อเปิดแสดงผลบริษัททั้งหมด STR_SMALLMAP_TOOLTIP_CARGO_SELECTION :{BLACK}Click on a cargo to toggle displaying its property. Ctrl+Click disables all cargoes except the selected one. Ctrl+Click on it again to enable all cargoes STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}ถนน STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}รางรถไฟ STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}สถานี/ท่าอากาศยาน/ท่าเรือ STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}สิ่งก่อสร้าง/อุตสาหกรรม STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}ยานยนต์ STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}รถไฟ STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}รถยนต์ STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}เรือ STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}อากาศยาน STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}เส้นทางการขนส่ง STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}ป่าไม้ STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}สถานีรถไฟ STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}สถานีถ่ายของรถบรรทุก STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}ป้ายรถเมล์ STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}ท่าอากาศยาน/ลานจอดเฮลิคอปเตอร์ STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}ท่าเรือ STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}พื้นลูกรัง STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}พื้นหญ้า STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}ที่ดินเปล่า STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}ทุ้งหญ้า STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}ต้นไม้ STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}หิน STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}ผืนน้ำ STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}ไม่มีเจ้าของ STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}เมือง STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}อุตสาหกรรม STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}ทะเลทราย STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}หิมะ STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}เปิด/ปิด ชื่อเมืองบนแผนที่ STR_SMALLMAP_CENTER :{BLACK}ให้จุดที่อยู่ ณ ปัจจุบันมาแสดงตำแหน่งในแผนที่ย่อ STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}ไม่เรียกใช้งานทั้งหมด STR_SMALLMAP_ENABLE_ALL :{BLACK}เรียกใช้งานทั้งหมด STR_SMALLMAP_SHOW_HEIGHT :{BLACK}แสดงความสูง STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}ไม่แสดงอุตสาหกรรมใดๆบนแผนที่ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}เปิดการแสดงอุตสาหกรรมทุกชนิดบนแผนที่ STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}เปลี่ยนการแสดง heightmap STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}ไม่แสดงทรัพย์สินของบริษัทใดๆบนแผนที่ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}แสดงทรัพย์สินของทุกบริษัทบนแผนที่ STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}ไม่แสดงสินค้าบนแผนที่ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}แสดงประเภทสินค้าทั้งหมดบนแผนที่ # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}แสดงข้อความล่าสุด STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * หยุดเกม * * STR_STATUSBAR_AUTOSAVE :{RED}กำลังทำการเซฟอัตโนมัติ STR_STATUSBAR_SAVING_GAME :{RED}* * กำลังบันทึกเกม * * # News message history STR_MESSAGE_HISTORY :{WHITE}ข้อความย้อนหลัง STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}รายการแสดงข้อความข่าวเมื่อเร็วๆนี้ STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING} STR_NEWS_MESSAGE_CAPTION :{WHITE}ข้อความ STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}ผู้คนต่างยินดีปรีดา. . .{}ที่รถไฟขบวนปฐมฤกษ์เทียบชานชาลาที่ {STATION}! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}ผู้คนต่างยินดีปรีดา. . .{}ที่รถโดยสารเที่ยวปฐมฤกษ์ได้มาถึง {STATION}! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}ผู้คนต่างยินดีปรีดา. . .{}ที่รถสินค้าเที่ยวปฐมฤกษ์ได้มาถึง {STATION}! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}ผู้คนต่างยินดีปรีดา. . .{}ที่รถรางเที่ยวปฐมฤกษ์ได้มาถึง {STATION}! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}ผู้คนต่างยินดีปรีดา. . .{}ที่รถรางสินค้าเที่ยวปฐมฤกษ์ได้มาถึง {STATION}! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}ผู้คนต่างยินดีปรีดา. . .{}ที่เรือเที่ยวปฐมฤกษ์ได้เทียบท่าที่ {STATION}! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}ผู้คนต่างยินดีปรีดา. . .{}ที่เที่ยวบินปฐมฤกษ์ได้มาถึง{STATION}! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}อุบัติเหตุรถไฟชนกัน!!{}มีผู้เสียชีวิต{COMMA}คนจากอุบัติเหตุครั้งนี้ STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}เกิดอุบัติเหตุรถไฟชนรถยนต์!!{}หลังจากเจ้าหน้าที่เข้าตรวจสอบพื้นที่ พบว่าคนขับรถยนต์เสียชีวิต STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}เกิดอุบัติเหตุรถไฟชนรถยนต์ {}มีผู้เสียชีวิต {COMMA} คนหลังรถไฟมรณะพุ่งชน STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}เกิดอุบัติเหตุเครื่องบินตก{}คร่าชีวิตผู้โดยสารและลูกเรือรวม {COMMA} ศพที่ {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}เครื่องบินตกตก!{}ด้วยสาเหตุ เชื้อเพลิงหมดกลางอากาศ, ผู้โดยสารและลูกเรือ {COMMA} ชีวิตตายอนาถ STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}เกิดเหตุบอลลูนระเบิดที่{STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}รถยนต์ถูกทำลายโดย UFO! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}เกิดเหตุโรงกลั่นน้ำมันระเบิดใกล้เมือง {TOWN}! {}ทางการกำลังสั่งอพยพผู้คนในละแวกใกล้เคียงออกนอกพื้นที่ STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}โรงงานอุตสาหกรรมถูกทำลายอย่างไม่ทราบสาเหตุใกล้ {TOWN}! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}มี 'UFO' มาลงใกล้ๆ{TOWN}! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}เกิดเหตุเหมืองถ่านหินถล่มใกล้กับเมืองเมือง {TOWN}! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}น้ำท่วม!{}ประชาชนอย่างน้อย {COMMA} สูญหาย ด้วยกระแสน้ำที่แรงมาก คาดว่าจะเสียชีวิตแล้วจากการจมน้ำ! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}วิกฤติการการเงินบริษัท!!! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} ด้วยสภาวะขาดทุนสะสมต่อเนื่อง บริษัทจะถูกขายหรือประกาศล้มละลาย ยกเว้นเสียแต่จะฟื้นตัวได้ในเวลาอันสั้น STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}ยุบรวมบริษัทขนส่งแล้ว STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} ถูกขายให้ {STRING} เป็นจำนวนเงิน {CURRENCY_LONG}! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}ล้มละลาย! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} ถูกปิดตัวโดยนายทุนและทรัพย์สินทั้งหมดจะถูกขายทอดตลาด STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}บริษัทขนส่งใหม่เริ่มกิจการแล้ว! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} เริ่มการก่อสร้างใกล้ {TOWN}! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{STRING} ถูกเซ้งโดย {STRING}! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(ประธานบริษัท) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{STRING} ผู้สนับสนุนก่อสร้างเมืองใหม่ในชื่อ {TOWN}! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}{STRING}ใหม่ กำลังถูกสร้างใกล้ ๆ เมือง {TOWN}! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK} {STRING}กำลังปลูกใหม่ใกล้ {TOWN}! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING} ประกาศเลิกกิจการ! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}เกิดปัญหาเกี่ยวกับวัตถุดิบทำให้ {STRING} ต้องประกาศเลิกกิจการ! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}ต้นไม้บริเวณใกล้เคียงขาดแคลนทำให้ {STRING} ต้องประกาศเลิกกิจการ! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}เงินสกุลยูโรเริ่มใช้แล้ว!{}{}สหภาพยุโรปได้เริ่มใช้เงินสกุลเดียวกันแล้ว นั่นคือเงินสกุลยูโร รวมถึงในประเทศนี้ตั้งแต่วันนี้เป็นต้นไป! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}เกิดภาวะเศรฐกิจถดถอยทั่วโลก!{}{}ผู้เชี่ยวชาญทางการเงินต่างหวาดกลัวเนื่องจากเศรฐกิจตกต่ำ! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}สิ้นสุดภาวะเศรฐกิจถดถอย!{}{}การค้าขายเริ่มเป็นบวกเกิดความเชื่อมั่นในอุตสาหกรรมต่างๆ จากการที่เศรฐกิจเข้มแข็งขึ้น! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} เพิ่มกำลังการผลิต! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}พบสายแร่ถ่านหินใหม่ที่ {INDUSTRY}!คาดว่าผลผลิต{}จะเพิ่มขึ้นเท่าตัว! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}พบแหล่งน้ำมันใหม่ที่ {INDUSTRY}!คาดว่าผลผลิต{}จะเพิ่มขึ้นเท่าตัว! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}เกษตรกรรมที่ได้รับการปรับปรุงแล้วที่ {INDUSTRY} คาดว่าจะทำให้ผลผลิตเพิ่มขึ้นเท่าตัว! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} ผลผลิต {INDUSTRY} เพิ่มขึ้น {COMMA}%! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}ผลผลิต {INDUSTRY} ลดลง 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}เกิดแมลงศัตรูพืชอย่างหนักที่ {INDUSTRY}!ผลผลิต{}ลงลง 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} ผลผลิตของ {INDUSTRY} ลดลง {COMMA}%! STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} กำลังรอในอู่ STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} กำลังรออยู่ในโรงซ่อม STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} กำลังรออยู่ในอู่ STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} กำลังรออยู่ในโรงจอด # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} มีคำสั่งน้อยเกินไปในกำหนดการเดินทาง STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} มีคำสั่งว่าง STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} มีคำสั่งซ้ำซ้อน STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} มีสถานีที่ใช้ไม่ได้ในคำสั่ง STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} เริ่มเก่าแล้ว STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} เก่ามากแล้ว STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} เก่ามากแล้ว และควรเปลี่ยนใหม่ในทันที STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} ไม่สามารถหาเส้นทางไปต่อได้. STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} กำลังหลงทาง. STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}กำไรของ {VEHICLE} เมื่อปีที่ผ่านมา {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} ไม่สามารถไปยังจุดหมายถัดไปได้เนื่องจากไม่อยู่ในระยะ STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} หยุดเนื่องจากการดัดแปลงไม่สำเร็จ STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}เปลี่ยนใหม่อัตโนมัติไม่สำเร็จบน {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}{STRING}รุ่นใหม่ขณะนี้มีให้สั่งผลิตแล้ว! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}ใหม่ {STRING} มีจำหน่ายแล้ว - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} ไม่ต้องการรับ {STRING} อีกต่อไป STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} ไม่รับ {STRING} หรือ {STRING} แล้ว STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} ขณะนี้ยอมรับ {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} ขณะนี้ยอมรับ {STRING} และ {STRING} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}ข้อเสนอสำหรับการอุดหนุนสิ้นสุด:{}{}{STRING} จาก {STRING} ถึง {STRING} จะไม่ได้รับการอุดหนุนอีกต่อไป. STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}การอุดหนุนถูกถอดถอน:{}{}บริการ {STRING} จาก {STRING} ถึง {STRING} จะไม่ได้รับการสนับสนุนอีกต่อไป. STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}มีการสนับสนุนในการทำโครงการ:{}{} ขนส่ง {STRING} เที่ยวปฐมฤกษ์ จาก {STRING} ถึง {STRING} หากดำเนินการจะได้รับเงินอุดหนุนพิเศษรายปีจากเจ้าหน้าที่ในท้องถิ่น! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}เงินสนับสนุนโครงการถูกมอบให้กับ {STRING}!{}{} โดยการขนส่ง {STRING} จาก {STRING} ถึง {STRING} จะได้รับเงินอุดหนุนเพิ่มขึ้น 50% สำหรับปีหน้า! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}การอุดหนุนบริการถูกมอบแก่ {STRING}!{}{}บริการ {STRING} จาก {STRING} ถึง {STRING} จะได้รับเงินสองเท่าในปีหน้า! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}การอุดหนุนบริการถูกมอบแก่ {STRING}!{}{}บริการ {STRING} จาก {STRING} ถึง {STRING} จะได้รับเงินสามเท่าในปีหน้า! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}การอุดหนุนบริการถูกมอบแก่ {STRING}!{}{} บริการ {STRING} จาก {STRING} ถึง {STRING} จะได้รับเงินสี่เท่าในปีหน้า! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}การจราจรยุ่งเหยิงใน {TOWN}!{}{}การสร้างถนนใหม่ที่ได้รับการสนับสนุนโดย {STRING} นำมาซึ่งหกเดือนแห่งความสงสัยแก่ผู้ใช้ถนน! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}เจ้าพ่อวงการขนส่ง! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}ฝ่ายบริหารของเมือง {TOWN} ลงนามสัญญากับ {STRING} เป็นะระยเวลา 1 ปีสำหรับสัมปทานขนส่งพิเศษ # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}มุมมอง {COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}คัดลอกไปยังมุมมอง STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}คัดลอกตำแหน่งของมุมมองหลังมายังมุมมองนี้ STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}วางจากมุมมอง STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}วางตำแหน่งจากมุมมองนี้ไปยังมุมมองหลัก # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}ตัวเลือกเกม STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}หน่วยสกุลเงิน STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}การเลือกสกุลเงิน ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :ปอนด์สเตอร์ลิง (£) STR_GAME_OPTIONS_CURRENCY_USD :ดอลลาร์สหรัฐ ($) STR_GAME_OPTIONS_CURRENCY_EUR :ยูโร STR_GAME_OPTIONS_CURRENCY_JPY :เยน (¥) STR_GAME_OPTIONS_CURRENCY_ATS :ชิลลิ่งออสเตรีย (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :ฟรังก์เบลเยี่ยม (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :ฟรังก์สวิส (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :โครูนาเช็ค (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :ดอยช์มาร์ค (DEM) STR_GAME_OPTIONS_CURRENCY_DKK :โครนเดนมาร์ค (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :เพเซต้า (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :มาร์คคา ฟินแลนด์ (FIM) STR_GAME_OPTIONS_CURRENCY_FRF :ฟรังก์ฝรั่งเศส(FRF) STR_GAME_OPTIONS_CURRENCY_GRD :ดรากช์มา กรีซ (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :ฟอรินท์ ฮังการี (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :โครนา ไอซแลนด์ (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :ลิรา อิตาลี (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :กิลเดอร์ ดัชต์ (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :โครน นอร์เวย์ (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :ซโลตี โปแลนด์ (PLN) STR_GAME_OPTIONS_CURRENCY_RON :ลิว โรมาเนีย (RON) STR_GAME_OPTIONS_CURRENCY_RUR :รูเบิ้ลส์ รัสเซีย (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :โทลาร์ สโลวีเนีย (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :โครนา สวีเดน (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :ลิรา ตุรกี (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :โครูนา สโลวาเกีย (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :เรียล บราซิล (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :ครูนิ เอสโทเนีย (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Lithuanian Litas (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :วอน เกาหลีใต้ (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :South African Rand (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :ระบุเอง... STR_GAME_OPTIONS_CURRENCY_GEL :Georgian Lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Iranian Rial (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}ยานยนต์ STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}เลือกฝั่งถนนในการขับยานพาหนะ STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :ขับชิดซ้าย STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :ขับชิดขวา STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}ชื่อเมือง STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}เลือกรูปแบบของชื่อเมือง ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :อังกฤษ (ดั้งเดิม) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :ฝรั่งเศส STR_GAME_OPTIONS_TOWN_NAME_GERMAN :เยอรมัน STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :อังกฤษ (ตัวเสริม) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :ลาติน-อเมริกัน STR_GAME_OPTIONS_TOWN_NAME_SILLY :อังกฤษอย่างง่าย STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :สวีดิช STR_GAME_OPTIONS_TOWN_NAME_DUTCH :ดัชต์ STR_GAME_OPTIONS_TOWN_NAME_FINNISH :ฟินน์ STR_GAME_OPTIONS_TOWN_NAME_POLISH :โปลิช STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :สโลวากิช STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :นอร์วิเจียน STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :ฮังกาเรียน STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :ออสเตรียน STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :โรมาเนียน STR_GAME_OPTIONS_TOWN_NAME_CZECH :เช็ค STR_GAME_OPTIONS_TOWN_NAME_SWISS :สวิส STR_GAME_OPTIONS_TOWN_NAME_DANISH :เดนมาร์ค STR_GAME_OPTIONS_TOWN_NAME_TURKISH :ตุรกี STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :อิตาเลียน STR_GAME_OPTIONS_TOWN_NAME_CATALAN :คาตาลัน ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}บันทึกเกมอัตโนมัติ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}เลือกระยะห่างระหว่างการบันทึกเกมอัตโนมัติแต่ละครั้ง ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :ปิด STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :ทุกๆเดือน STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :ทุก 3 เดือน STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :ทุก 6 เดือน STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :ทุก 12 เดือน ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}ภาษา STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}เลือกภาษาที่จะใช้ STR_GAME_OPTIONS_FULLSCREEN :{BLACK}เต็มหน้าจอ STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}ทำเครื่องหมายที่ช่องนี้เพื่อเล่น OpenTTD fullscreen โหมด STR_GAME_OPTIONS_RESOLUTION :{BLACK}ความละเอียดของหน้าจอ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}เลือกความละเอียดของหน้าจอที่จะใช้ STR_GAME_OPTIONS_RESOLUTION_OTHER :อื่นๆ STR_GAME_OPTIONS_BASE_GRF :{BLACK}ตั้งค่า Graphic พื้นฐาน STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}เลือกและตั้งค่าฐานกราฟิกที่จะใช้ STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} ไฟล์สูญหายหรือไม่สมบูรณ์ STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}ข้อมูลเพิ่มเติมเกี่ยวกับชุดกราฟฟิคพื้นฐาน STR_GAME_OPTIONS_BASE_SFX :{BLACK}เลือกชุด Effect เสียงประกอบ STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}ปรับและเลือกเสียงที่จะใช้ STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}ปรับข้อมูลเพิ่มเติมเกี่ยวกับโหมดเสียง STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}ชุดเพลงประกอบพื้นฐาน STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}เลือกเพลงประกอบพื้นฐานเพื่อใช้งาน STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} ไฟล์ไม่สมบูรณ์ STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}ข้อมูลเพิ่มเติมเกี่ยวกับชุดเพลงประกอบพื้นฐาน STR_ERROR_FULLSCREEN_FAILED :{WHITE}Fullscreen โหมดล้มเหลว # Custom currency window STR_CURRENCY_WINDOW :{WHITE}สกุลเงิน STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}อัตราแลกเปลี่ยน: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}ลดจํานวนสกุลเงินของคุณสำหรับหนึ่งปอนด์ (£) STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}เพิ่มจำนวนสกุลเงินของคุณสำหรับหนึ่งปอนด์ (£) STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}กำหนดอัตราแลกเปลี่ยนของสกุลเงินหนึ่งปอนด์ (£) STR_CURRENCY_SEPARATOR :{LTBLUE}ตัวแบ่ง: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}สัญลักษณ์แบ่งหลักสกุลเงินของท่าน STR_CURRENCY_PREFIX :{LTBLUE}คำนำหน้า: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}สัญลักษณ์หน้าสกุลเงินของท่าน STR_CURRENCY_SUFFIX :{LTBLUE}คำเสริมท้าย: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}สัญลักษณ์ต่อท้ายสกุลเงินของท่าน STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}เปลี่ยนเป็นเงินสกุลยูโร: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}เปลี่ยนเป็นเงินสกุลยูโร: {ORANGE}ไม่เปลี่ยน STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}ตั้งปีเพื่อเปลี่ยนสกุลเงินเป็นยูโร STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}เปลี่ยนสกุลเงินเป็นยูโรก่อน STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}เปลี่ยนสกุลเงินเป็นยูโรทีหลัง STR_CURRENCY_PREVIEW :{LTBLUE}แสดงตัวอย่าง: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 ปอนด์สเตอร์ลิง (£) ในสกุลเงินของคุณ STR_CURRENCY_CHANGE_PARAMETER :{BLACK}เปลี่ยนการกำหนดค่าตัวแปรสกุลเงิน STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}จำนวนผู้ร่วมแข่งขันสูงสุด: {ORANGE}{COMMA} STR_NONE :ไม่มี STR_FUNDING_ONLY :ระดมทุนเท่านั้น STR_MINIMAL :ขั้นต่ำ STR_NUM_VERY_LOW :ต่ำมาก STR_NUM_LOW :ต่ำ STR_NUM_NORMAL :ปกติ STR_NUM_HIGH :สูง STR_NUM_CUSTOM :กำหนดเอง STR_NUM_CUSTOM_NUMBER :กำหนดเอง ({NUM}) STR_VARIETY_NONE :ไม่มี STR_VARIETY_VERY_LOW :ต่ำมาก STR_VARIETY_LOW :ต่ำ STR_VARIETY_MEDIUM :ปานกลาง STR_VARIETY_HIGH :สูง STR_VARIETY_VERY_HIGH :สูงมาก STR_AI_SPEED_VERY_SLOW :ช้ามาก STR_AI_SPEED_SLOW :ช้า STR_AI_SPEED_MEDIUM :ปานกลาง STR_AI_SPEED_FAST :เร็ว STR_AI_SPEED_VERY_FAST :เร็วมาก STR_SEA_LEVEL_VERY_LOW :ต่ำมาก STR_SEA_LEVEL_LOW :ต่ำ STR_SEA_LEVEL_MEDIUM :ปานกลาง STR_SEA_LEVEL_HIGH :สูง STR_SEA_LEVEL_CUSTOM :กำหนดเอง STR_SEA_LEVEL_CUSTOM_PERCENTAGE :กำหนดเอง ({NUM}%) STR_RIVERS_NONE :ไม่มี STR_RIVERS_FEW :น้อย STR_RIVERS_MODERATE :ปานกลาง STR_RIVERS_LOT :หลาย STR_DISASTER_NONE :ไม่มี STR_DISASTER_REDUCED :ภาวะลดลง STR_DISASTER_NORMAL :ภาวะปกติ STR_SUBSIDY_X1_5 :1.5 เท่า STR_SUBSIDY_X2 :2 เท่า STR_SUBSIDY_X3 :3 เท่า STR_SUBSIDY_X4 :4 เท่า STR_TERRAIN_TYPE_VERY_FLAT :แบนราบมาก STR_TERRAIN_TYPE_FLAT :แบนราบ STR_TERRAIN_TYPE_HILLY :เนินเขา STR_TERRAIN_TYPE_MOUNTAINOUS :ภูเขาสูง STR_CITY_APPROVAL_PERMISSIVE :อนุญาต STR_CITY_APPROVAL_TOLERANT :พอผ่อนผันให้ได้ STR_CITY_APPROVAL_HOSTILE :ไม่เป็นมิตร STR_WARNING_NO_SUITABLE_AI :{WHITE}ไม่มี AI ที่เหมาะสมปรากฎ...{}คุณสามารถดาวน์โหลด AI จากระบบ 'Online Content' # Settings tree window STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}เติม string: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}ขยายทั้งหมด STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}ยุบลงทั้งหมด STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(ไม่สามารถขยายได้) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}ค่าเริ่มต้น: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}ประเภทการตั้งค่า: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :ตั้งค่าผู้ใช้ (ไม่ถูกเก็บไว้ในการบันทึกเกม; มีผลครอบคลุมทั้งหมด) STR_CONFIG_SETTING_TYPE_GAME_MENU :ตั้งค่าเกม(ถูกเก็บไว้ในการบันทึกเกม; มีผลเฉพาะการเริ่มเกมใหม่) STR_CONFIG_SETTING_TYPE_GAME_INGAME :ตั้งค่าเกม(ถูกเก็บไว้ในการบันทึกเกม; มีผลเฉพาะเกมปัจจุบัน) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :ตั้งค่าองค์กร (ถูกเก็บไว้ในการบันทึกเกม; มีผลเฉพาะการเริ่มเกมใหม่) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :ตั้งค่าองค์กร (ถูกเก็บไว้ในการบันทึกเกม; มีผลเฉพาะเกมปัจจุบัน) STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}จำกัดรายการด้านล่างให้แสดงเฉพาะการตั้งค่าที่มีการเปลี่ยนแปลง STR_CONFIG_SETTING_RESTRICT_BASIC :ตั้งค่าพื้นฐาน STR_CONFIG_SETTING_RESTRICT_ADVANCED :ตั้งค่าขั้นสูง STR_CONFIG_SETTING_RESTRICT_ALL :การตั้งค่าแบบผู้เชี่ยวชาญ / การตั้งค่าทั้งหมด STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :การตั้งค่าที่มีค่าที่แตกต่างกันกับค่าเริ่มต้น STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :การตั้งค่าที่มีค่าที่แตกต่างกันกับการตั้งค่าใหม่เกมของคุณ STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}เลือกรูปแบบการตั้งค่า STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :การตั้งค่าทั้งหมด STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :ตั้งค่าผู้ใช้งาน (ไม่เก็บในเซฟ มีผลกับทุกเกม) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :ตั้งค่าเกี่ยวกับเกม(เก็บในเซฟ มีผลเมื่อเริ่มเกมใหม่) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :ตั้งค่าเกี่ยวกับเกม(เก็บในเซฟ มีผลเฉพาะเกมปัจจุบัน) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :ตั้งค่าบริษัท (เก็บในเซฟ มีผลเมื่อเริ่มเกมใหม่) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :ตั้งค่าเกี่ยวกับบริษัท(เก็บในเซฟ มีผลแค่บริษัทปัจจุบัน) STR_CONFIG_SETTING_OFF :ปิด STR_CONFIG_SETTING_ON :เปิด STR_CONFIG_SETTING_DISABLED :ไม่ให้เรียกใช้งาน STR_CONFIG_SETTING_COMPANIES_OFF :ปิด STR_CONFIG_SETTING_COMPANIES_OWN :บริษัทในเครือ STR_CONFIG_SETTING_COMPANIES_ALL :บริษัททั้งหมด STR_CONFIG_SETTING_NONE :ไม่มี STR_CONFIG_SETTING_ORIGINAL :ดั้งเดิม STR_CONFIG_SETTING_REALISTIC :เสมือนจริง STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :ซ้าย STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :กลาง STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :ขวา STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :เงินกู้เริ่มต้นสูงสุด: {STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :บริษัท สามารถกู้ยืมเงินจำนวนสูงสุด (โดยไม่คำนึงถึงอัตราเงินเฟ้อเข้าบัญชี) STR_CONFIG_SETTING_INTEREST_RATE :ดอกเบี้ย: {STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :อัตราดอกเบี้ยเงินกู้; มีผลกับอัตราเงินเฟ้อถ้าเปิดใช้งาน STR_CONFIG_SETTING_RUNNING_COSTS :ระดับของค่าปฎิบัติการของยานพาหนะต่างๆ: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :กำหนดระดับของการบำรุงรักษาและค่าใช้จ่ายของยานพาหนะและโครงสร้างพื้นฐาน STR_CONFIG_SETTING_CONSTRUCTION_SPEED :ควานเร็วในการก่อสร้าง: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :จำกัด จำนวนของการกระทำก่อสร้างสำหรับ AIs STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :ยานพาหนะขัดข้อง: {STRING} STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS_HELPTEXT :ควบคุมความถี่ในการตรวจสภาพยานพาหนะ หากได้รับการตรวจสภาพไม่เพียงพออาจเกิดอาการขัดข้องบ่อยครั้งได้ STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :อัตราของการให้เงินสนับสนุนโครงการ: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER_HELPTEXT :ตั้งค่าเงินสนับสนุนสำหรับการเชื่อมต่อ STR_CONFIG_SETTING_CONSTRUCTION_COSTS :ค่าใช้จ่ายในการก่อสร้า: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :การตั้งค่าระดับของค่าใช้จ่ายในการก่อสร้างและซื้อ STR_CONFIG_SETTING_RECESSIONS :เศรษฐกิจถดถอย: {STRING} STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :หากเปิดใช้งาน การถดถอย อาจเกิดขึ้นทุก 2 - 3 ปี ในช่วงเศรษฐกิจตกต่ำในการผลิตทั้งหมด อย่างมีนัยสำคัญต่ำกว่า (มันจะกลับไปที่ระดับก่อนหน้านี้เมื่อภาวะถดถอยจบลง) STR_CONFIG_SETTING_TRAIN_REVERSING :ไม่อนุญาตให้รถไฟกลับขบวนในสถานี: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING_HELPTEXT :หากเปิดใช้งานรถไฟจะไม่ย้อนกลับในสถานีที่ไม่ใช่ปลายทางถ้ามีเส้นทางที่สั้นไปยังปลายทางต่อไปของพวกเขา จะย้อนกลับ STR_CONFIG_SETTING_DISASTERS :ภัยพิบัติ: {STRING} STR_CONFIG_SETTING_DISASTERS_HELPTEXT :ภัยพิบัติซึ่งบางครั้งสลับอาจปิดกั้นหรือทำลายยานพาหนะหรือโครงสร้างพื้นฐาน STR_CONFIG_SETTING_CITY_APPROVAL :ทัศนคติสภาเทศบาลเมืองที่มีต่อการปรับโครงสร้างพื้นที่: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :เลือกความรุนแรงของการทำลายสิ่งแวดล้อมและเสียงรบกวนจากบริษัทที่ส่งผลต่อความนิยมในเมืองและการก่อสร้างของพวกเขา STR_CONFIG_SETTING_AUTOSLOPE :อนุญาตให้เปลี่ยนสภาพพื้นผิวใต้สิ่งก่อสร้าง, ราง, ฯลฯ (ปรับความชันอัตโนมัติ): {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :อนุญาตให้ปรับสภาพพื้นที่ได้โดยไม่ต้องรื้อถอนสาธารณูปโภค STR_CONFIG_SETTING_CATCHMENT :อนุญาตให้มีขนาดของพื้นที่บริการของสถานีที่สมเหตุสมผลมากขึ้น: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :สร้างความแตกต่างของพื้นที่บริการสำหรับสถานีในประเภทที่แตกต่างกัน STR_CONFIG_SETTING_EXTRADYNAMITE :อนุญาตให้ทำลายถนน, สะพาน, สิ่งก่อสร้างของเมืองได้มากขึ้น: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :ทำให้ง่ายขึ้นสำหรับการรื้อถอนสาธารณูปโภคและสิ่งปลูกสร้างของเมือง STR_CONFIG_SETTING_TRAIN_LENGTH :ความยาวสูงสุดของขบวนรถไฟ: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :เลือกตั้งค่าความยาวสูงสุดของขบวนรถไฟ STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} ช่อง STR_CONFIG_SETTING_SMOKE_AMOUNT :ปริมาณของ Effect ไอเสีย/การSpark: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :ตั้งค่าปริมาณของไอเสีย หรือการ spark ที่สร้างโดยยานพาหนะ STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :รูปแบบของการเร่งความเร็วของรถไฟ: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :เลือกตั้งค่าอัตราเร่งเสมือนจริง สำหรับการทำให้การเคลื่อนที่ของขบวนรถไฟสมจริงมากยิ่งขึ้น ในการขึ้นเนิน หรือจากการที่ขบวนรถมีความยาวมากๆ ซึ่งกำลังขับ(Tractive Effort) ของรถจักรมีผลโดยตรง STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :รูปแบบการเร่งของรถยนต์: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :เลือกตั้งค่าอัตราเร่งเสมือนจริง สำหรับการทำให้การเคลื่อนที่ของขบวนรถสมจริงมากยิ่งขึ้น ในการขึ้นเนิน หรือจากการที่รถบรรทุกน้ำหนักมากๆ STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :ตั้งค่าการฉุดความเร็วขณะขึ้นเนินของรถไฟ: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :การฉุดรั้งความเร็วของขบวนรถไฟขณะขึ้นเนิน หากค่ายิ่งมากยิ่งทำให้รถไฟไต่เนินได้ยากขึ้น STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :ตั้งค่าการฉุดความเร็วขณะขึ้นเนินของรถยนต์: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :การฉุดรั้งความเร็วขอรถขณะขึ้นเนิน หากค่ายิ่งมากยิ่งทำให้รถไต่เนินได้ยากขึ้น STR_CONFIG_SETTING_FORBID_90_DEG :ห้ามรถไฟและเรือเลี้ยวในมุม 90 องศา: {STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :ไม่อนุญาตให้รถไฟเลี้ยวโค้งแบบ 90 องศาได้ STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :อนุญาตให้เป็นสถานีเดียวกันแม้ไม่ได้ติดกัน: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :อนุญาตให้มีการสร้างชิ้นส่วนที่เป็นของสถานีให้แยกออกจากกันโดยไม่ต้องมีชิ้นส่วนอื่นๆที่เชื่อมต่อถึงกันได้ ต้องกด Ctrl+Click ในการใช้งาน STR_CONFIG_SETTING_INFLATION :ภาวะเงินเฟ้อ: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :เมื่อเปิดการใช้งานอัตราเงินเฟ้อ ค่าเงินจะถูกลงและต้องใช้เงินมากขึ้นในการซื้อหรือสร้าง แต่ผลตอบแทนจากการขนส่งก็จะเพิ่มขึ้นด้วยเช่นกัน STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :ความยาวสูงสุดของสะพาน: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :ปรับความยาวสูงสุดสำหรับการสร้างสะพาน STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :ความยาวสูงสุดของอุโมงค์: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :ปรับความยาวสูงสุดสำหรับการสร้างอุโมงค์ STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :กำหนดวิธีหลักในการก่อสร้างอุตสาหกรรมเอง: {STRING} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :การเลือกช่องทางการสร้างโรงงานอุตสาหกรรมหลัก เลือก "ไม่มี" จะทำให้ไม่สามารถสร้างอุตสาหกรรมเพิ่มได้ เลือก "สุมที่ตั้ง" จะเป็นการสุ่มตำแหน่งที่ตั้ง "เหมือนกับอุตสาหกรรมอื่น" ก็จะสามารถกำหนดสถานที่ตั้งได้เลย STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :ไม่อนุญาตให้ก่อตั้ง STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :ก่อตั้งได้เหมือนกับอุตสาหกรรมอื่นๆ STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :สุ่มตำแหน่งที่ตั้ง STR_CONFIG_SETTING_INDUSTRY_PLATFORM :พื้นที่ราบเรียบรอบโรงงานอุตสาหกรรม: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :การปรับระยะของพื้นที่ราบเรียบโดยรอบของโรงงานอุตสาหกรรมต่างๆ STR_CONFIG_SETTING_MULTIPINDTOWN :อนุญาตให้มีหลายอุตสาหกรรมที่เหมือนกันต่อหนึ่งเมือง: {STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :โดยปกติแล้ว จะสามารถสร้างอุตสาหกรรมในประเภทเดียวกันได้เพียงแห่งเดียวต่อเมืองหนึ่งเมือง แต่หากเปิดการใช้งาน จะสามารถสร้างอุตสาหกรรมประเภทเดียวกันได้หลายแห่งในเมืองหนึ่งเมือง STR_CONFIG_SETTING_SIGNALSIDE :เสาอาณัติสัญญาณ: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :เลือกว่าจะแสดงการตั้งเสาอาณัติสัญญาณว่าเป็นฝั่งซ้ายหรือฝั่งขวา STR_CONFIG_SETTING_SIGNALSIDE_LEFT :ฝั่งซ้าย STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :ฝั่งเดียวกับการขับขี่ STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :ฝั่งขวา STR_CONFIG_SETTING_SHOWFINANCES :แสดงหน้าต่างสภาวะการเงินบริษัทเมื่อสิ้นสุดแต่ละปี: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :เมื่อเปิดใช้งาน จะแสดงรายงานผลประกอบการมาให้ชมทุกสิ้นปี STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :ตั้งให้คำสั่งที่เพิ่มใหม่เป็น 'ไม่หยุด' โดยปริยาย: {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :โดยปกติ ยานพาหนะจะหยุดทุกสถานีที่วิ่งผ่าน เมื่อเปิดใช้งานส่วนนี้ยานพาหนะจะวิ่งผ่านโดยไม่จอดไปจนกว่าจะถึงที่หมายถัดไปตามตารางที่กำหนดให้จอด STR_CONFIG_SETTING_STOP_LOCATION :คำสั่งแรกเริ่มของขบวนรถ ให้หยุดที่ {STRING} ของชานชาลา STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :เลือกกำหนดจุดจอดบนชานชาลาของรถไฟว่าจะเป็นกึ่งกลาง หรือหัว-ท้ายชานชาลา STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :ฝั่งใกล้ STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :ตรงกลาง STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :ฝั่งไกล STR_CONFIG_SETTING_AUTOSCROLL :เลื่อนหน้าต่างเมื่อเม้าส์อยู่ใกล้ขอบหน้าจอ: {STRING} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :เมื่อเปิดใช้งานจะสามารถเลื่อนหน้าจอโดยการใช้เมาส์ไปแตะที่ขอบจอได้ STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :ไม่ใช้งาน STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :มุมมองหลัก เฉพาะในโหมด Full-Screen STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :มุมมองหลัก STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :ทุกๆมุมมอง STR_CONFIG_SETTING_BRIBE :อนุญาตให้ติดสินบนเจ้าหน้าที่ในท้องถิ่น: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :อนุญาตให้สามารถใส่เงินใต้โต๊ะกับเจ้าหน้าที่ท้องถิ่นได้ เพื่อเพิ่มระดับความถึงพอใจ STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :อนุญาตให้ซื้อสัมปทานการขนส่งแต่เพียงผู้เดียว: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :เมื่อบริษัทซื้อสัมปทานขนส่ง สินค้าและผู้โดยสารจะใช้งานในสถานีของบริษัทนั้นๆบริษัทเดียว STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :อนุญาตให้สามารถบริจาคเงินเพื่อสร้างสิ่งปลูกสร้างในเมือง: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :ทำให้สามารถให้เงินกับเมืองเพื่อสร้างสิ่งปลูกสร้างใหม่ขึ้นมาได้ STR_CONFIG_SETTING_ALLOW_FUND_ROAD :อนุญาตให้ใช้เงินทุนในการก่อสร้างถนนใหม่: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :ให้เงินกับเมืองเพื่อทำถนนใหม่ สำหรับขีดขวางการจราจรในเมืองที่บริษัทคู่แข่งให้บริการอยู่ STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :อนุญาตให้ส่งเงินแก่บริษัทอื่นๆ: {STRING} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :ให้สามารถส่งเงินระหว่างบริษัทได้ในระบบผู้เล่นหลายคน STR_CONFIG_SETTING_FREIGHT_TRAINS :ตัวคูณสำหรับการขนส่งสินค้า เพื่อจำลองน้ำหนักของขบวน: {STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :ตั้งค่าน้ำหนักของรถไฟสินค้า ค่ายิ่งมากยิ่งทำให้ออกตัวช้าและขึ้นเนินได้ยากขึ้น STR_CONFIG_SETTING_PLANE_SPEED :เลือกความเร็วของเครื่องบิน: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :ตั้งค่าความเร็วของเครื่องบินให้สมดุลกับขนาดและความเร็วของยานพาหนะประเภทอื่นๆ STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :จำนวนเครื่องบินที่ตก: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :ตั้งค่าการสุ่มอัตราเครื่่องบินตก STR_CONFIG_SETTING_PLANE_CRASHES_NONE :ไม่มี STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :ลดลง STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :ปกติ STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :อนุญาตให้มีที่หยุดรถแบบขับผ่านบนถนนที่เมืองเป็นเจ้าของ: {STRING} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :สามารถสร้างป้ายหยุดรถบนถนนของเมืองได้ STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :อนุญาตให้มีที่หยุดรถแบบขับผ่านบนถนนของบริษัทอื่นๆ: {STRING} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :สามารถสร้างป้ายหยุดรถบนถนนที่สร้างโดยบริษัทอื่นได้ STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}ไม่สามารถเปลี่ยนการตั้งค่านี้ได้เมื่อมียานพาหนะ STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :ค่าบำรุงรักษาโครงสร้างพื้นฐาน: {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :เมื่อเปิดใช้งาน สาธารณูประโภคที่สร้างโดยบริษัทจะมีค่าบำรุงรักษา ยิ่งเครือข่ายยิ่งมากจะยิ่งเสียค่าใช้จ่ายมากขึ้น STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :ท่าอากาศยานไม่มีวันหมดอายุ: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :เปิดใช้งานสิ่งนี้ จะทำให้สามารถสร้างท่าอากาศยานแบบเก่าๆได้แม้เวลาจะผ่านไปนานแล้วก็ตาม STR_CONFIG_SETTING_WARN_LOST_VEHICLE :เตือนหากยานพาหนะหลงทาง: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :แสดงข้อความเตือน เมื่อพาหนะไม่สามารถค้นหาเส้นทางไปยังที่หมายตามที่กำหนดไว้ได้ STR_CONFIG_SETTING_ORDER_REVIEW :การแจ้งเตือนความผิดปกติของยานพาหนะ: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :เมื่อเปิดใช้งาน คำสั่งที่ใช้สำหรับยานพาหนะจะถูกตรวจสอบเป็นช่สงๆ และจะมีรายงานมาเป็นระยะๆ STR_CONFIG_SETTING_ORDER_REVIEW_OFF :ไม่ต้องเตือน STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :ให้เตือน แต่ยกเว้นยานพาหนะที่หยุดวิ่ง STR_CONFIG_SETTING_ORDER_REVIEW_ON :แจ้งเตือนทั้งหมด STR_CONFIG_SETTING_WARN_INCOME_LESS :เตือนเมื่อรายได้ของยานพาหนะติดลบ: {STRING} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :เมื่อเปิดใช้งาน จะแสดงข้อความแจ้งเตือนเมื่อพาหนะไม่สามารถทำกำไรได้เมื่อครบกำหนดสิ้นปี STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :ยานพาหนะไม่หมดอายุ: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :เมื่อเปิดใช้งาน พาหนะทั้งหมดจะยังสามารถซื้อได้ตลอดไปหลังจากหมดช่วงระยะเวลา STR_CONFIG_SETTING_AUTORENEW_VEHICLE :เปลี่ยนยานพาหนะใหม่โดยอัตโนมัติเมื่อเก่าเกินไป: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :เมื่อเปิดใช้งาน พาหนะที่ใกล้หมดอายุการใช้งาน จะทำการแทนที่ใหม่เอง STR_CONFIG_SETTING_AUTORENEW_MONTHS :ซื้่อใหม่อัตโนมัตเมื่อ {STRING} ครบอายุการใช้งาน STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :อายุการใช้งานเมื่อยานพาหนะต้องทำการซื้อใหม่ STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} เดือน ก่อน STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} เดือน หลังจากที่ STR_CONFIG_SETTING_AUTORENEW_MONEY :จำนวนเงินขั้นต่ำที่ให้เปลี่ยนยานพาหนะโดยอัตโนมัติ: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :จำนวนเงินสำรองต่ำสุดที่ต้องมีสำหรับการซื้อยานพาหนะใหม่โดยอัตโนมัติ STR_CONFIG_SETTING_ERRMSG_DURATION :ระยะเวลาแสดงของข้อความแจ้งความผิดพลาด: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :เป็นระยะเวลาที่จะคงแสดงข้อความแจ้งความผิดพลาดของเกม จะคงอยู่ตามระยะเวลาที่ตั้งค่าไว้ข้างต้น STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} วินาที STR_CONFIG_SETTING_HOVER_DELAY :แสดงบอลลูนข้อความช่วยเหลือ: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :หน่วงระยะเวลาเป็นวินาทีเมื่อนำเมาส์วางไว้เหนือปุ่มต่างๆเพื่อแสดงข้อความช่วยเหลือ STR_CONFIG_SETTING_HOVER_DELAY_VALUE :วางค้างไว้เป็นเวลา {COMMA} วินาที{P 0 s} STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :คลิ๊กเมาส์ขวา STR_CONFIG_SETTING_POPULATION_IN_LABEL :แสดงจำนวนประชากรของเมืองในป้ายชื่อเมือง: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :แสดงจำนวนประชากรของเมืองหลังชื่อเมืองบนแผนที่ จะมีกรอบวงเล็บแสดงจำนวนประชากรในเมืองนั้นๆอยู่ด้วย STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :ความหนาของเส้นกราฟ: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :ความกว้างของเส้นกราฟ สามารถปรับขนาดได้เพื่อสะดวกในการมองเห็น STR_CONFIG_SETTING_LAND_GENERATOR :ตัวสังเคราะห์ภูมิประเทศ: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :ดั้งเดิม STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :ระยะห่างที่สุดจากขอบแผนที่ของโรงกลั่นน้ำมัน: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :โรงกลั่นน้ำมันจะสามารถตั้งได้เฉพาะบริเวณใกล้ๆขอบแผนที่เท่านั้น การตั้งค่านี้จะสามารถตั้งให้สร้างโรงกลั่นน้ำมันได้ห่างสูงสุดเท่าใดจากของแผนที่ STR_CONFIG_SETTING_SNOWLINE_HEIGHT :ระดับความสูงแนวหิมะ: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :ความหยาบของพื้นที่ (เฉพาะ TerraGenesis): {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :ราบเรียบมาก STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :ราบเรียบ STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :หยาบ STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :หยาบมาก STR_CONFIG_SETTING_TREE_PLACER :อัลกอริธึมสำหรับการวางต้นไม้: {STRING} STR_CONFIG_SETTING_TREE_PLACER_NONE :ไม่มี STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :ดั้งเดิม STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :ปรังปรุงแล้ว STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :ทิศการหมุน Heightmap: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :ทวนเข็มนาฬิกา STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :ตามเข็มนาฬิกา STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :ค่าระดับความสูงต่ำสุดของพื้นราบ: {STRING} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}ขอบทางเหนือมีอย่างน้อยหนึ่งช่องหรือมากกว่านั้นที่ไม่ว่าง STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}หนึ่งช่องหรือมากกว่านั้นที่ขอบด้านในด้านหนึ่งไม่ใช่น้ำ STR_CONFIG_SETTING_STATION_SPREAD :ความกว้างสูงสุดของสถานี: {STRING} STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :ความกว้างและความยาวสูงสุดของสถานีที่สามารถขยายออก STR_CONFIG_SETTING_SERVICEATHELIPAD :ซ่อมบำรุง เฮลิคอปเตอร์ ที่ลานจอด ฮ. โดยอัตโนมัติ: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :ซ่อมบำรุงเฮลิคอปเตอร์ทุกครั้งที่ลงจอด STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :โยงแถบเครื่องมือปรับภูมิประเทศกับแถบเครื่องมือสร้างต่างๆ: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :เมื่อเปิดเครื่องมือสร้างที่เกี่ยวข้องกับการขนส่งต่างๆ จะเป็นการเปิดกล่องเครื่องมือปรับสภาพภูมิประเทศมาด้วยทุกครั้ง STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :สีของพื้นดินที่ใช้ในแผนที่ย่อ: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :สีของพื้นดินในแผนที่ย่อ STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :สีเขียว STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :สีเขียวแก่ STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :สีม่วง STR_CONFIG_SETTING_REVERSE_SCROLLING :กลับทิศการเลื่อนหน้าจอ: {STRING} STR_CONFIG_SETTING_REVERSE_SCROLLING_HELPTEXT :เลือกลักษณะการเลื่อนแผนที่ เมื่อใช้ปุ่มคลิ๊กเมาส์ขวา หากเปิดการใช้งาน หน้าจอจะเคลื่อนที่ไปในทิศตรงกันข้ามกับการคลิ๊กเมาส์ค้างแล้วลากเมาส์ไป STR_CONFIG_SETTING_SMOOTH_SCROLLING :เลื่อนอย่างนิ่มนวลบนจอภาพ: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :ควบคุมการเคลื่อนที่ของจอภาพ เวลาคลิ๊กเลือกตำแหน่งในแผนที่ย่อ หากไม่เปิดใช้งาน ตำแหน่งของจอจะย้ายไปที่ตำแหน่งที่เลือกทันที แต่หากเปิดใช้งาน จะเคลื่อนที่ไปยังตำแหน่งอย่างนุ่มนวล STR_CONFIG_SETTING_MEASURE_TOOLTIP :แสดงบอลลูนข้อความแสดงระยะทางหรือข้อมูลอื่นๆ เมื่อใช่เครื่องมือสร้าง: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :เปิดบอลลูนข้อความแสดงระยะทางหรือความสูง ขณะใช้เครื่องมือในการสร้างต่างๆ เพื่อให้ได้เห็นรายละเอียดที่เรากระทำการ ว่าเราวางรางรถไฟมาไกลแค่ไหน หรือปรับพื้นดินขึ้นไปสูงเท่าใดแล้ว STR_CONFIG_SETTING_LIVERIES :แสดงเครื่องแบบบริษัท: {STRING} STR_CONFIG_SETTING_LIVERIES_HELPTEXT :เปิดเพื่อใช้งานการตั้งสีประจำบริษัทแยกย่อยตามประเภทยานพาหนะ STR_CONFIG_SETTING_LIVERIES_NONE :ไม่เลย STR_CONFIG_SETTING_LIVERIES_OWN :บริษัทของท่าน STR_CONFIG_SETTING_LIVERIES_ALL :ทุกบริษัท STR_CONFIG_SETTING_PREFER_TEAMCHAT :ใช้การคุยระหว่างทีมด้วย : {STRING} STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :สลับการพูดคุยระหว่างภายใน และภายนอก และ STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :รูปแบบการใช้ลูกกลิ้งเมาส์ในแผนที่ย่อ: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :ปรับเปลี่ยนลักษณะการใช้งานลูกกลิ้งเมาส์บนแผนที่ย่อ STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :ขยายแผนที่ STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :เลื่อนแผนที่ STR_CONFIG_SETTING_SCROLLWHEEL_OFF :ปิด STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :ความเร็วการเลื่อนของแผนที่: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :ควบคุมความเสถียรของลูกกลิ้งเม้าส์ STR_CONFIG_SETTING_OSK_ACTIVATION :เปิดใช้งาน On-Screen Keyboard: {STRING} STR_CONFIG_SETTING_OSK_ACTIVATION_HELPTEXT :เลือกวิธีการที่จะเปิดแป้นพิมพ์หน้าจอสำหรับการป้อนเมื่อข้อความใน editboxes เพียงแค่ใช้อุปกรณ์ชี้ตำแหน่ง นี่หมายความว่าสำหรับอุปกรณ์ขนาดเล็กโดยไม่ต้องใช้แป้นพิมพ์ที่เกิดขึ้นจริง STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :ไม่ใช้งาน STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :คลิกสองครั้ง STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :คลิกครั้งเดียว (เมื่อเพ่งความสนใจไป) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :คลิกครั้งเดียว (ทันที) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :จำลองคลิกขวา: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :เลือกผลของการใช้การคลิ๊กเมาส์ขวา STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Command+คลิก STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+Click STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :ปิด STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :เลื่อนหน้าจอด้วยการคลิ๊กเมาส์ซ้าย: {STRING} STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING_HELPTEXT :เปิดใช้งานเพื่อให้สามารถใช้การคลิ๊กเมาส์ซ้ายในการเลื่อนภาพหน้าจอได้ STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :ใช้รูปแบบวันที่ {STRING} เป็นชื่อเซฟของเกม STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :เพิ่มวันที่ในเกมลงไปในชื่อเซฟเกม เมื่อมีการเซฟเกมจะแนบวันที่ในเกมลงไปในชื่อเซฟเกมด้วยโดยอัตโนมัติ แต่หากผู้เล่นต้องการเปลี่ยนแปลงชื่อเซฟเกมก็สามารถกระทำได้ตามสะดวก STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :ยาว (31 ธันวาคม 2013) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :สั้น (31-12-2013) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :มาตรฐาน (2013-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :หยุดเกมอัตโนมัติเมื่อเริ่มเกมใหม่: {STRING} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :เมื่อเปิดใช้งาน เกมจะหยุดอัตโนมัติเมื่อมีการเริ่มเกมใหม่ STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :อนุญาตให้ทำสิ่งเหล่านี้เมื่อหยุดเกม: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :เลือกเปิดใช้งานคำสั่งบางคำสั่งต่อไปนี้ขณะหยุดเกม STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :ไม่อนุญาตให้ทำใดๆทั้งสิ้น STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :ทุกการกระทำที่ไม่ใช่การก่อสร้าง STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :ทุกอย่างยกเว้นการปรับปรุงระดับพื้นดิน STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :ทุกการกระทำ STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :ใช้รายการยานพาหนะขั้นสุง: {STRING} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :เปิดใช้งานรายการยานพาหนะขั้นสูงสำหรับจัดกลุ่มของยานพาหนะต่างๆ STR_CONFIG_SETTING_LOADING_INDICATORS :แสดงสถานะการขนถ่ายเมื่อกำลังขนถ่ายที่สถานี: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :เลือกเพื่อแสดงตัวเลขปริมาณการบรรทุกขณะขนถ่ายที่สถานีของพาหนะ STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :แสดงตารางเวลาในแบบติ๊กแทนแบบวัน: {STRING} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :แสดงเวลาในการเดินทางในตารางเวลาเป็น ticks แทนที่ days STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :แสดงเวลามาถึงและออกไปในตารางเวลา: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :แสดงการคาดการณ์เวลาในการเดินทางไปถึงหรือเวลาออกของยานพาหนะในตารางเวลา STR_CONFIG_SETTING_QUICKGOTO :เลือกคำสั่ง "ไปยัง" ไว้เสมอในการออกคำสั่งให้พาหนะ: {STRING} STR_CONFIG_SETTING_QUICKGOTO_HELPTEXT :เลือกคำสั่ง "ไปยัง" ไว้เป็นปกติเมื่อมีการเลือกปลายทาง STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :การเลือกทางรถไฟที่เป็นแบบแรกเริ่มเมื่อคลิ๊กเครื่องมือสร้าง (เริ่มเกมใหม่/โหลดเกม): {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :ประเภทของทางรถไฟหลังจากเริ่มเกมใหม่ หรือโหลดเซฟเกม STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :มีใช้ครั้งแรก STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :มีใช้ครั้งสุดท้าย STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :ใช้มากที่สุด STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :แสดงทางรถไฟที่ขบวนรถขอทางไว้: {STRING} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :แสดงการขอทางของขบวนรถไฟ โดยแสดงสีที่แตกต่างจากสีทางปกติเพื่อช่วยตรวจหาจุดบกพร่อง เมื่อขบวนรถไฟเข้าสู่ทางตอนที่ใช้สัญญาณระบบ Path-Based STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :ให้คงการแสดงเครื่องมือการสร้างหลังการใช้: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :ไม่ปิดเครื่องมือสร้างสะพาน หรืออุโมง หลังจากใช้งาน STR_CONFIG_SETTING_EXPENSES_LAYOUT :จัดกลุ่มแยกประเภท รายรับ/รายจ่าย ในหน้าต่างแสดงข้อมูลการเงินของบริษัท: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :จัดการแยกประเภท รายรับ/รายจ่าย เพื่อให้ง่ายต่อการตรวจทาน ในหน้าต่างแสดงสถานะการเงินบริษัท STR_CONFIG_SETTING_SOUND_TICKER :ข่าวสาร: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :เล่นเสียงเมื่อมีข่าวย่อ STR_CONFIG_SETTING_SOUND_NEWS :หนังสือพิมพ์: {STRING} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :เล่นเสียงเมื่อแสดงหน้าหนังสือพิมพ์ STR_CONFIG_SETTING_SOUND_NEW_YEAR :เสียงเตือนเมื่อถึงสิ้นปี: {STRING} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :เล่นเสียงเมื่อแสดงรายงานผลประกอบการเปรียบเทียบกับปีที่แล้ว STR_CONFIG_SETTING_SOUND_CONFIRM :การก่อสร้าง: {STRING} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :เล่นเสียงเมื่อการก่อสร้างเสร็จหรือการกระทำอื่นๆ STR_CONFIG_SETTING_SOUND_CLICK :เมื่อคลิ๊กเมาส์: {STRING} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :มีเสียง Effect เมื่อคลิกเมาส์ในหน้าต่างเกม STR_CONFIG_SETTING_SOUND_DISASTER :ภัยพิบัติ/อุบัติเหตุ: {STRING} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :เล่นเสียงประกอบของอุบัติเหตุและภัยพิบัติ STR_CONFIG_SETTING_SOUND_VEHICLE :ยานพาหนะ: {STRING} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :เล่นเสียงประกอบของยานพาหนะ STR_CONFIG_SETTING_SOUND_AMBIENT :สิ่งแวดล้อม:{STRING} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :เปิดเสียงของสิ่งแวดล้อมต่างๆ STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :ปิดการใช้งานในส่วนของสิ่งปลูกสร้างสาธารณูปโภคเมื่อไม่มียานพาหนะที่เหมาะสม: {STRING} STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :เมื่อเปิดใช้งาน สาธารณูประโทค และเส้นทางการคมนาคมที่จะสร้างได้ มีเฉพาะที่เหมาะสมกับประเภทยานพาหนะที่รองรับ STR_CONFIG_SETTING_MAX_TRAINS :ขบวนรถไฟมากที่สุดต่อผู้เล่น: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :จำนวนขบวนรถไฟสูงสุดที่บริษัทสามารถมีได้ STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :ยานพาหนะทางบกมากที่สุดต่อผู้เล่น: {STRING} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :จำนวนยานพาหนะบนทางราบสูงสุดที่บริษัทสามารถมีได้ STR_CONFIG_SETTING_MAX_AIRCRAFT :อากาศยานมากที่สุดต่อผู้เล่น: {STRING} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :จำนวนอากาศยานสูงสุดที่บริษัทสามารถมีได้ STR_CONFIG_SETTING_MAX_SHIPS :ยานพาหนะทางน้ำมากที่สุดต่อผู้เล่น: {STRING} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :จำนวนยานพาหนะทางน้ำสูงสุดที่บริษัทสามารถมีได้ STR_CONFIG_SETTING_AI_BUILDS_TRAINS :ไม่ยอมให้มีรถไฟสำหรับคอมพิวเตอร์: {STRING} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :เมื่อเปิดใช้งาน จะทำให้ AI สามารถสร้างขบวนรถไฟได้ STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :ไม่ยอมให้มียานพาหนะทางบกสำหรับคอมพิวเตอร์: {STRING} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :เมื่อเปิดใช้งาน จะทำให้ AI สามารถสร้างยานพาหนะทางบกได้ STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :ไม่ยอมให้มีอากาศยานสำหรับคอมพิวเตอร์: {STRING} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :เมื่อเปิดใช้งาน จะทำให้ AI สามารถสร้างอากาศยานได้ STR_CONFIG_SETTING_AI_BUILDS_SHIPS :ไม่ยอมให้มีเรือสำหรับคอมพิวเตอร์: {STRING} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :เมื่อเปิดใช้งาน จะทำให้ AI สามารถสร้างยานพาหนะทางน้ำได้ STR_CONFIG_SETTING_AI_PROFILE :รูปแบบการตั้งค่าพื้นฐาน: {STRING} STR_CONFIG_SETTING_AI_PROFILE_HELPTEXT :เลือกที่ตั้งค่าโปรไฟล์ที่จะใช้สำหรับเอไอเอสแบบสุ่มหรือค่าเริ่มต้นสำหรับการเพิ่มสคริปต์ AI หรือเกมใหม่ STR_CONFIG_SETTING_AI_PROFILE_EASY :ง่าย STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :ปานกลาง STR_CONFIG_SETTING_AI_PROFILE_HARD :ยาก STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :อนุญาตให้ใช้ปัญญาประดิษฐ์ (AI) สำหรับหลายผู้เล่น: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :อนุญาตให้มี AI ในโหมดผู้เล่นหลายคน STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :จำนวน opcodes ก่อนที่สคริปต์ถูกหยุด: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :ตัวเลขสูงสุดของการคำนวณลำดับขั้น script สามารถใช้งานได้แค่ครั้งเดียว STR_CONFIG_SETTING_SERVINT_ISPERCENT :ใช้การซ่อมบำรุงโดยการคิดจากเปอร์เซนต์ของประสิทธิภาพ: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :เลือกการซ่อมบำรุงหลังจากซ่อมบำรุงครั้งล่าสุดตามค่าประสิทธิภาพที่ลดลง แทนที่การซ่อมบำรุงตามวงรอบวัน STR_CONFIG_SETTING_SERVINT_TRAINS :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงของขบวนรถไฟ: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงสำหรับขบวนรถไฟ เป็นหน่วยวัน หรือหากเลือกการตั้งค่าโดยคิดจากเปอร์เซนต์ของประสิทธิภาพ จะเปลี่ยนไปใช้่หน่วยเปอร์เซนต์แทน STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA} วัน/% STR_CONFIG_SETTING_SERVINT_DISABLED :ไม่ตั้ง STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงของพาหนะทางบก: {STRING} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงสำหรับพาหนะทางบก เป็นหน่วยวัน หรือหากเลือกการตั้งค่าโดยคิดจากเปอร์เซนต์ของประสิทธิภาพ จะเปลี่ยนไปใช้่หน่วยเปอร์เซนต์แทน STR_CONFIG_SETTING_SERVINT_AIRCRAFT :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงของอากาศยาน: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงสำหรับอากาศยาน เป็นหน่วยวัน หรือหากเลือกการตั้งค่าโดยคิดจากเปอร์เซนต์ของประสิทธิภาพ จะเปลี่ยนไปใช้่หน่วยเปอร์เซนต์แทน STR_CONFIG_SETTING_SERVINT_SHIPS :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงของพาหนะทางน้ำ: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :ตั้งค่าแรกเริ่มสำหรับการเข้าซ่อมบำรุงสำหรับพาหนะทางน้ำ เป็นหน่วยวัน หรือหากเลือกการตั้งค่าโดยคิดจากเปอร์เซนต์ของประสิทธิ์ภาพ จะเปลี่ยนไปใช้่หน่วยเปอร์เซนต์แทน STR_CONFIG_SETTING_NOSERVICE :ไม่ใช้งานการซ่อมบำรุงเมื่อตั้งเป็นไม่มีการขัดข้อง: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :เมื่อเปิดใช้งาน ยานพาหนะจะไม่เข้ารับการซ่อมบำรุงหากตั้งค่าไว้ไม่ให้มีการชำรุด STR_CONFIG_SETTING_WAGONSPEEDLIMITS :จำกัดความเร็วของรถจักร/รถพ่วง: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :เมื่อเปิดใช้งาน จะทำให้มีจำกัดความเร็วสูงสุดของยานพาหนะและรถพ่วงต่างๆ STR_CONFIG_SETTING_DISABLE_ELRAILS :ปิดระบบสายส่งไฟฟ้า(Electricfield): {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :เมื่อเปิดการใช้งาน จะทำการปิดความต้องการการใช้งานระบบ Electrifield ของรถจักรหรือรถไฟฟ้า STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :เมื่อมีพาหนะแรกแรกมาถึงสถานีของผู้เล่น: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :แสดงข่าวเมื่อมีพาหนะมาถึงสถานีของบริษัทเรา STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :เมื่อมีพาหนะแรกมาถึงสถานีของบริษัทคู่แข่ง: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :แสดงข่าวเมื่อมีพาหนะถึงที่สถานีของศัตรู STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :ภัยพิบัติ / อุบัติเหตุ: {STRING} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :แสดงข่าวเกี่ยวกับภัยพิบัติและอุบัติเหตุ STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :ข้อมูลข่าวสารของบริษัท: {STRING} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :แสดงข่าวเมื่อมีบริษัทเปิดใหม่หรือบริษัทใกล้ล้มละลาย STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :อุตสาหกรรมเปิดตัวใหม่: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :แสดงข่าวเกี่ยวกับโรงงานเปิดใหม่ STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :อุตสาหกรรมปิดตัวลง: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :แสดงข่าวเกี่ยวกับโรงงานที่ปิดตัว STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :การเปลี่ยนแปลงทางเศรษฐกิจ: {STRING} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :แสดงข่าวเกี่ยวกับการเปลี่ยนแปลงทางเศรษฐศาสตร์ของโลก STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :การเปลี่ยนแปลงของสินค้าที่ส่งให้บริษัทเราเป็นผู้ขนส่ง: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :แสดงข่าวเกี่ยวกับผลผลิตที่เปลี่ยนไปของโรงงานต่างๆที่บริษัทเราขนส่งสินค้าอยู่ STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :การเปลี่ยนแปลงของสินค้าที่ส่งให้บริษัทคู่แข่งเป็นผู้ขนส่ง: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :แสดงข่าวเกี่ยวกับผลผลิตที่เปลี่ยนไปของโรงงานต่างๆที่คู่แข่งขนส่งสินค้าอยู่ STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :การเปลี่ยนแปลงการผลิตสินค้าของอุตสาหกรรมอื่นๆ: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :แสดงข่าวเกี่ยวกับการผลิตที่เปลี่ยนไปของโรงงานต่างๆที่ยังไม่มีผู้ขนส่งสินค้า STR_CONFIG_SETTING_NEWS_ADVICE :คำแนะนำ / ข้อมูลเกี่ยวกับยานยนต์ของบริษัท: {STRING} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :แสดงข้อความเมื่อยานพาหนะเกิดเหตุฉุกเฉิน STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :ยานพาหนะชนิดใหม่: {STRING} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :แสดงหนังสือพิมพ์เมื่อมียานพาหนะรุ่นใหม่ STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :การเปลี่ยนแปลงการรับสินค้าของสถานี: {STRING} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :แสดงเมื่อมีการเปลี่ยนแปลงการรับสินค้าของสถานี STR_CONFIG_SETTING_NEWS_SUBSIDIES :โครงการที่มีงบประมาณสนับสนุน: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :แสดงข่าวเกี่ยวกับเงินสมทบของโครงการที่มีงบประมาณสนับสนุน STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :ข้อมูลทั่วไป: {STRING} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :แสดงหนังสือพิมพ์เกี่ยวกับเหตุการณ์ทั่วไป เช่นการซื้อสิทธิพิเศษหรือการปรับปรุงถนน STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :ปิด STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :แสดงข้อความในแถบเลื่อน STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :แสดงข้อความแบบเต็ม STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :เริ่มใช้งานหนังสือพิมพ์สีในปี: {STRING} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :เป็นการกำหนดว่าจะเริ่มต้นการใช้งานหนังสือพิมพ์แบบสีเมื่อปีใด STR_CONFIG_SETTING_STARTING_YEAR :ปีที่เริ่มต้น: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :ยอมให้มีเศรษฐกิจที่ราบรื่น (มากขึ้น, เปลี่ยนแปลงเล็กน้อย): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :เมื่อเปิดใช้งาน อุดสาหกรรมจะมีการเปลี่ยนแปลงผลผลผลิต STR_CONFIG_SETTING_ALLOW_SHARES :อนุญาตให้ซื้อหุ้นจากบริษัทอื่นได้: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :เมื่อเปิดการใช้งาน จะสามารถซื้่อชขายหุ้นระหว่างบริษัท จะสามารถซื้อขายหุ้นได้ต่อเมื่อบริษัทเปิดตัวมานานแล้วเท่านั้น STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :เปอเซนต์ของผลกำไรที่จะส่งเข้าสู่ระบบกระจายรายได้: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :เปอร์เซนต์ของรายได้ที่ส่งให้ฐานของระบบกระจายรายได้ ส่งผลต่อการควบคุมรายได้ทั้งหมด STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :เมื่อลากเมาส์จะทำการวางเสาอาณัติสัญญาณโดยอัตโนมัติทุกๆ: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :ตั้งค่าระยะที่จะให้ตั้งเสาอาณัติสัญญาณเมื่อทำการลากเมาส์ค้างเป็นระยะทางยาวๆ STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} ช่อง STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :เมื่อลากเมาส์ จะทำการจัดระยะของเสาสัญญาณใหม่: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :เลือกระยะห่างระหว่างเสาอาณัติสัญญาณแต่ละต้นหากมีการลากเมาส์ต่อเนื่อง โดยหลีกเลี่ยงสะพานและอุโมงค์ ตามที่กำหนดค่าไว้ STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :เลือกใช้เสาอาณัติสัญญาณไฟสีอัตโนมัติในปี: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :เลือกปีที่เริ่มต้นการใช้งานเสาอาณัติสัญญาณไฟสี ซึ่งก่อนหน้าปีนี้จะเป็นการใช้งานเสาสัญญาณแบบหางปลา STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :เปิดใช้งานตัวเลือกรูปแบบเสาอาณัติสัญญาณ: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :แสดงหน้าต่างเพื่อเลือกประเภทเสาอาณัติสัญญาณ หากไม่เปิดใช้งานใช้การกดปุ่ม Ctrl+คลิ๊กเมาส์ซ้าย STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :ชนิดของเสาอาณัติสัญญาณปริยายที่จะใช้: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :รูปแบบเสาอาณัติสัญญาณปริยายที่จะใช้งานทุกครั้ง STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :เสาอาณัติสัญญาณอย่างง่าย STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :เสาอาณัติสัญญาณตอนอัตโนมัติ STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :เสาอาณัติสัญญาณตอนอัตโนมัติ แบบทางเดียว STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :วนชนิดเสาอาณัติสัญญาณ: {STRING} STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES_HELPTEXT :เลือกประเภทเสาอาณัติสัญญาณที่จะเปลี่ยนไปในวงรอบ STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :สัญญาณอย่างง่ายเท่านั้น STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :เสาอาณัติสัญญาณตอนอัตโนมัติ แบบทางเดียว STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :ทั้งหมด STR_CONFIG_SETTING_TOWN_LAYOUT :รูปแบบถนนสำหรับเมืองใหม่: {STRING} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :แบบแปลนของเครือข่ายถนนในเมือง STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :ดั้งเดิม STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :ถนนที่ดีกว่า STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :ตาราง 2x2 STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :ตาราง 3x3 STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :สุ่ม STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :ยอมให้เมืองสร้างถนนได้: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :อนุญาตให้เมืองสามารถขยายถนนเพื่อรองรับการขยายตัว STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :ยอมให้เมืองสร้างทางข้ามระดับดินได้: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :เปิดการใช้งาน เพื่ออนุญาตให้เมืองสามารถสร้างทางตัดเสมอระดับทางรถไฟได้ STR_CONFIG_SETTING_NOISE_LEVEL :เปิดใช้งานให้เมืองมีการควบคุมมลภาวะทางเสียงของท่าอากาศยาน: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :เมื่อปิดการใช้งานนี้ จะสามารถสร้างท่าอากาศยานได้มากกว่า 1 STR_CONFIG_SETTING_TOWN_FOUNDING :ก่อตั้งเมืองใหม่ในเกม: {STRING} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :เปิดการใช้งาน จะสามารถเลือกตั้งเมืองใหม่ได้ขณะเล่นเกม STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :ห้าม STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :ยอม STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :ยอม, รูปแบบเมืองกำหนดเอง STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :การปลูกป่า: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :ควบคุมการสุ่มการเจริญเติบโตของต้นไม้ระหว่างเล่นเกม STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :ไม่มี {RED}(ไม่มีโรงเลื่อยไม้) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :เฉพาะในป่าฝนเท่านั้น STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :ทุกหนทุกแห่ง STR_CONFIG_SETTING_TOOLBAR_POS :ตำแหน่งแถบเครื่องมือหลัก: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :ตำแหน่งของปุ่มเครื่องมือต่างๆด้านบนของจอภาพ STR_CONFIG_SETTING_STATUSBAR_POS :ตำแหน่งของแถบแสดงสถานะ: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :ตำแหน่งของแถบแสดงผลต่างๆด้านล่างของจอภาพ STR_CONFIG_SETTING_SNAP_RADIUS :รัศมีของหน้าต่าง: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :ปรับความกว้างหรือความยาวของหน้าต่างต่างๆ หากถูกนำมาเรียงติดกันและขยายขนาดให้ใกล้เคียงกัน STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pixel{P 0 s} STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :ไม่ใช้งาน STR_CONFIG_SETTING_SOFT_LIMIT :จำนวนมากสุดของหน้าต่างที่ไม่ปักหมุด: {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :จำนวนของหน้าต่างที่จะสามารถเปิดได้จนกว่าจะถึงขีดจำกัดและจะปิดหน้าต่างก่อนหน้านี้ลงตามลำดับ STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :ไม่ใช้งาน STR_CONFIG_SETTING_ZOOM_MIN :ระดับการซูมเข้าจากปกติ: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :ระยะซูมเข้าสูงสุด เมื่อเลือกการใช้งานแล้ว จะทำให้สามารถซูมเข้าไปใกล้ๆได้มากกว่าปกติของเกม STR_CONFIG_SETTING_ZOOM_MAX :ระดับการซูมออกสูงสุด: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :ระดับของการซูมออกสูงสุด เดิมจะมีข้อจำกัด แต่สามารถเพิ่มระยะการซูมออกได้มากขึ้นจากตัวเลือกนี้ STR_CONFIG_SETTING_ZOOM_LVL_MIN :4 เท่า STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2 เท่า STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :ปกติ STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2 เท่า STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4 เท่า STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8 เท่า STR_CONFIG_SETTING_TOWN_GROWTH :ความเร็วการขยายตัวของเมือง: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :ความเร็วในการขยายตัวของเมือง STR_CONFIG_SETTING_TOWN_GROWTH_NONE :ไม่มี STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :ช้า STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :ปกติ STR_CONFIG_SETTING_TOWN_GROWTH_FAST :เร็ว STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :เร็วมาก STR_CONFIG_SETTING_LARGER_TOWNS :สัดส่วนระหว่างจำนวนเมืองเล็กกับเมืองใหญ่: {STRING} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :สัดส่วนระหว่างจำนวนเมืองเล็กกับเมืองใหญ่ STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 ใน {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :ไม่มี STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :ตัวคูณขนาดเมืองเริ่มต้น: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :ขนาดโดยเฉลี่ยของเมืองใหญ่ที่สัมพันธ์กับเมืองปกติ STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :อัพเดทกราฟการกระจายสินค้าทุกๆ {STRING} วัน STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :เวลาระหว่างการคำนวณหาเส้นทางการเชื่อมต่อของกราฟ. ทุกครั้งที่มีำการคำนวณใหม่ มีการวางแผนสำหรับหนึ่งชิ้นส่วนในกราฟ ค่าที่ตั้งไว้นี้ คือค่าที่จะให้มีการอัพเดททุกๆเวลากี่วัน การตั้งให้คำนวณถี่มากๆจะกินทรัพยากรเครื่องของท่าน STR_CONFIG_SETTING_LINKGRAPH_TIME :ใช้เวลา {STRING} วัน{P 0:2 s} ในการคำนวนกราฟการกระจายสินค้า STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :เวลาในการคำนวณการกระจายสินค้าสู่จุดหมายต่างๆที่แสดงเป็นเส้นกราฟบนแผนที่ การตั้งค่าถี่เกินไปอาจก่อให้เกิดอาการ lag ได้ STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :ไม่กำหนด STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :อสมมาตร STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :สมมาตร STR_CONFIG_SETTING_DISTRIBUTION_PAX :โหมตการกระจายสินค้าสำหรับผู้โดยสาร: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_PAX_HELPTEXT :ผู้โดยสารจากเมืองหนึ่งเมื่อเดินทางออกไปที่ใดก็ตาม จะต้องย้อนกลับเข้ามายังจุดเริ่มค้น การตั้งค่าเป็นแบบ "สมมาตร" จะทำให้เกิดวงจรปกติเหมือนกับการโดยสารของผู้โดยสาร STR_CONFIG_SETTING_DISTRIBUTION_MAIL :โหมตการกระจายสินค้าสำหรับสินค้าประเภทพัสดุ: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :การขนส่งพัสดุ เหมือนกับการขนส่งผู้โดยสาร การตั้งค่าเป็นแบบ "สมมาตร" จึงเป็นทางเลือกที่ดีในการใช้งาน STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :โหมตการกระจายสินค้าสำหรับสินค้าประเภทต้องคุ้มครองเป็นพิเศษ: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :สินค้าที่ต้องได้รับการคุ้มครองเป็นพิเศษ เช่นทอง หรือเพชร สำหรับทองนั้นในภูมิประเทศปกติการขนส่งทองคำระหว่างธนาคารเป็นเรื่องปกติ การตั้งค่าเป็นแบบ "สมมาตร" จึงเป็นทางเลือกที่ดีเพื่อความสมจริง แต่สำหรับอุตสาหกรรมเพชรในเขตทะเลทรายหรือเขตหนาวเย็นนั้น เป็นผลผลิตจากอุตสาหกรรมที่ต้องส่งให้กับปลายทางเพียงอย่างเดียว หากจะเลือกเป็นแบบ "อสมมาตร" ก็คงจะเหมาะสมมากกว่า STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :โหมตการกระจายสินค้าสำหรับสินค้าประเภทอื่นๆ: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"สมมาตร" หมายถึงการที่ส่งสินค้าออกไปจากจุดเริ่มต้นไม่ว่าจะออกไปในที่ใดก็ตาม ก็จะมีการส่งกลับมายังต้นทางในบริมาณที่เท่าๆกัน ส่วนแบบ "อสมมาตร" คือการส่งออกไปแล้วไปเลย ไม่มีการย้อนกลับมายังจุดเริ่มต้น STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :ความแม่นยำในการกระจายสินค้า: {STRING} STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :การตั้งค่าความแม่นยำในการคำนวณของระบบการกระจายสินค้า ยิ่งตั้งค่าสูงมากจะยิ่งใช้ทรัพยากรของเครื่องคอมพิวเตอร์มากขึ้น แต่จะเพิ่มความแม่นยำในการคำนวณหาเส้นทางสินค้าที่จะไปมากขึ้น STR_CONFIG_SETTING_DEMAND_DISTANCE :ผลของสัดส่วนระยะทางต่อปริมาณ: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :โดยปกติสินค้ามักจะเลือกไปยังที่หมายที่อยู่ใกล้มากกว่า แต่หากตั้งค่าส่วนนี้เข้าใกล้ 0 สินค้าจะยิ่งกระจายออกไปในพื้นที่ห่างไกลมากยิ่งขึ้น STR_CONFIG_SETTING_DEMAND_SIZE :ปริมาณการส่งกลับของสินค้าในโหมตสมมาตร: {STRING} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :เมื่อตั้งค่าให้ต่ำกว่า 100% ระบบกระจายสินค้าแบบสมมาตรจะยิ่งมีความคล้ายคลึงกับแบบอสมมาตร สินค้าที่ถูกส่งออกไปที่จะย้อนกลับเข้ามายังจุดเริ่มต้นจะลดลง ถ้าตั้งค่าเป็น 0% ก็จะกลายเป็นเหมือนกับระบบการกระจายแบบอสมมาตรไปโดยปริยาย STR_CONFIG_SETTING_SHORT_PATH_SATURATION :ความเข้มข้นของการเลือกทางที่สั้นที่สุดก่อนเลือกทางที่มีการรองรับมากสุด: {STRING} STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :ความถี่ของเส้นทางสองเส้นทางระหว่างสถานีสองสถานี สินค้าและผู้โดยสารจะให้ความถี่กับเส้นทางที่สุั้นที่สุดก่อนเป็นอันดับแรก STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :หน่วยวัดความเร็ว: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :หน่วยวัดความเร็ว แสดงผลในหน้าต่างรายละเอียดยานพาหนะ STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :อิมพิเรียล (ไมล์ต่อชั่วโมง) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :เมตริก (กิโลเมตรต่อชั่วโมง) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :มาตรฐานสากล (เมตร/วินาที) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :หน่วยวัดกำลัง: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :หน่วยวัดกำลัง แสดงผลในหน้าต่างรายละเอียดยานพาหานะ STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :อิมพีเีรียล (แรงม้า) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :เมตริก (แรงม้า) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :มาตรฐานสากล (กิโลวัตต์) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :หน่วยวัดน้ำหนัก: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :หน่วยวัดน้ำหนัก แสดงผลในหน้าต่างรายละเอียดยานพาหนะ STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :อิมพีเรียล (ตัน) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :เมตริก (ตัน) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :มาตรฐานสากล (กิโลกรัม) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :หน่วยวัดปริมาณความจุ: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :หน่วยวัดความจุ แสดงผลในหน้าต่างรายละเอียดยานพาหนะ STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :อิมพีเรียล (แกลลอน) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :เมตริก (ลิตร) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :มาตรฐานสากล (ลูกบาศก์เมตร) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :หน่วยวัดกำลังลากจูง: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :หน่วยวัดกำลังลากจูง ที่แสดงผลในหน้าต่างรายละเอียดยานพาหานะ STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :อิมพีเรียล (ปอนด์) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :เมตริก (กิโลกรัม) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :มาตรฐานสากล (กิโลนิวตัน) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :หน่วยวัดความสูง: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :การแสดงหน่วยวัดความสูงเมื่อกดดูรายละเอียดของวัตถุต่างๆ STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :อิมพีเรียล (ฟุต) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :เมตริก (เมตร) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :มาตรฐานสากล (เมตร) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}มาตราวัดต่างๆ STR_CONFIG_SETTING_SOUND :{ORANGE}เสียงเอฟเฟกต์ STR_CONFIG_SETTING_INTERFACE :{ORANGE}ส่วนเชื่อมต่อผู้ใช้ STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}การก่อสร้าง STR_CONFIG_SETTING_VEHICLES :{ORANGE}ยานพาหนะ STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}การค้นหาเส้นทางของพาหนะ STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}เมือง STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}อุตสาหกรรม STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}การกระจายสินค้า STR_CONFIG_SETTING_AI :{ORANGE}คู่แข่ง STR_CONFIG_SETTING_AI_NPC :{ORANGE}ผู้เล่นคอมพิวเตอร์ STR_CONFIG_SETTING_PATHFINDER_OPF :ดั้งเดิม STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(แนะนำ) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :ตัวค้นหาเส้นทางสำหรับรถไฟ: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :การหาค้นหาเส้นทางของขบวนรถไฟ STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :ตัวค้นหาเส้นทางสำหรับรถยนต์: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :การค้นหาเส้นทางของยานพาหนะทางบก STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :ตัวค้นหาเส้นทางสำหรับเรือ: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :การค้นหาเส้นทางของยานพาหนะทางน้ำ STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :หมุนกลับขบวนอัตโนมัติที่เสาอาณัติสัญญาณ: {STRING} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :อนุญาตให้ขบวนรถไฟกลับขบวนที่เสาอาณัติสัญญาณเมื่อมีการรอสัญญาณอนุญาตเป็นเวลานาน STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}เปลี่ยนค่าการตั้งค่า # Config errors STR_CONFIG_ERROR :{WHITE}เกิดข้อผิดพลาดกับไฟล์ที่เก็บข้อมูลการตั้งค่า STR_CONFIG_ERROR_ARRAY :{WHITE}... เกิดข้อผิดพลาดในอาร์เรย์ '{STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}...ค่านี้ไม่ถูกต้อง '{STRING}' สำหรับ '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... ติดตามตัวอักษรที่จุดสิ้นสุดของการตั้งค่า '{STRING}' STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... กำลังเพิกเฉย NewGRF '{STRING}': GRF ID ซ้ำกับ '{STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... กำลังเพิกเฉย NewGRF ที่ไม่ถูกต้อง '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :ไม่พบ STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :ไม่ปลอดภัยสำหรับการใช้แบบคงที่ STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :NewGRF ของระบบ STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :ไม่รองรับกับ OpenTTD เวอร์ชันนี้ STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :ไม่ทราบ STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... ระดับการบับอัด '{STRING}' ไม่ถูกต้อง STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... รูปแบบการเซฟเกม '{STRING}' ใช้ไม่ได้... กำลังปรับค่ากลับเป็น '{STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ไม่สนใน Base Graphics set '{STRING}': หาไม่พบ STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ไม่สนใน Base Sounds set '{STRING}': หาไม่พบ STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ไม่สนใจ Base Music set '{STRING}': หาไม่พบ STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}หน่วยความจำไม่เพียงพอ STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}การกำหนดพื้นที่ {BYTES} ของ Spritecache ล้มเหลว Spritecache ได้ลดลง {BYTES}. นี่คือการทำให้ประสิทธิภาพของเกม OpenTTD ลดลง. เพื่อลดความต้องการของหน่วยความจำ ให้ทำการปิดการใช้งานระบบ 32bpp graphics # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}เริ่มเกมใหม่ STR_INTRO_LOAD_GAME :{BLACK}โหลดเกม STR_INTRO_PLAY_SCENARIO :{BLACK}เล่นโหมดเรื่องราว STR_INTRO_PLAY_HEIGHTMAP :{BLACK}เล่นแผนที่จากภาพชั้นความสูง STR_INTRO_SCENARIO_EDITOR :{BLACK}โปรแกรมแก้ไขแผนที่ STR_INTRO_MULTIPLAYER :{BLACK}เล่นหลายคน STR_INTRO_GAME_OPTIONS :{BLACK}ตัวเลือกเกม STR_INTRO_HIGHSCORE :{BLACK}ตารางคะแนนสูงสุด STR_INTRO_NEWGRF_SETTINGS :{BLACK}การตั้งค่า NewGRF STR_INTRO_ONLINE_CONTENT :{BLACK}ตรวจสอบเนื้อหาออนไลน์ STR_INTRO_SCRIPT_SETTINGS :{BLACK}ตั้งค่า AI/Game Script STR_INTRO_QUIT :{BLACK}ออก STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}เริ่มเกมใหม่, Ctrl+Click เพื่อข้ามการตั้งค่าแผนที่ STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}เปิดเกมที่บันทึกไว้ STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}เริ่มเกมใหม่โดยใช้ heightmap เป็นภูมิประเทศ STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}เริ่มเกมใหม่ โดยใช้ฉากที่กำหนดเอง STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}สร้างเกมที่มี โลก/ฉาก ที่กำหนดเอง STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}เริ่มเกมผู้เล่นหลายคน STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}เลือกรูปแบบภูมิประเทศ 'เขตอบอุ่น' STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}เลือกรูปแบบภูมิประเทศ 'เขตกึ่งขั้วโลก' STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}เลือกรูปแบบภูมิประเทศ 'เขตกึ่งมรสุม' STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}เลือกสภาพภูมิประเทศ 'เมืองของเล่น' STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}แสดงตัวเลือกเกม STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}แสดงตารางคะแนนสูงสุด STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}แสดงการกำหนดค่า NewGRF STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}ตรวจสอบเนื้อหาใหม่และการปรับปรุงสำหรับดาวโหลด STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}แสดงการตั้งค่า AI/Game script STR_INTRO_TOOLTIP_QUIT :{BLACK}ออกจากเกม OpenTTD STR_INTRO_TRANSLATION :{BLACK} การแปลภาษาส่วนนี้หายไป {NUM} string{P ""}. โปรดช่วยทำให้ OpenTTD ดีขึ้นโดยการสมัครเป็นผู้แปล. ดูใน readme.txt สำหรับรายละเอียด. # Quit window STR_QUIT_CAPTION :{WHITE}ออกจากเกม STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}คุณแน่ใจว่าจะออกจากเกม OpenTTD แล้วกลับสู่ {STRING}? STR_QUIT_YES :{BLACK}ใช่ STR_QUIT_NO :{BLACK}ไม่ # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :ระบบปฏิบัติการ Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}ออกไปสู่เมนูหลัก STR_ABANDON_GAME_QUERY :{YELLOW}เกมยังดำเนินอยู่แน่ใจหรือไม่ว่าจะกลับไปสู่เมนูหลัก? STR_ABANDON_SCENARIO_QUERY :{YELLOW}คุณแน่ใจหรือที่จะยกเลิกแผนที่นี้? # Cheat window STR_CHEATS :{WHITE}สูตรโกงเกม STR_CHEATS_TOOLTIP :{BLACK}กล่องตัวเลือกจะแสดงว่าคุณโกงมาก่อนหรือไม่ STR_CHEATS_WARNING :{BLACK}คำเตือน! คุณกำลังหักหลังคู่แข่งของคุณ พึงระลึกว่าการกระทำเช่นนี้จะถูกจดจำไปอีกนาน STR_CHEAT_MONEY :{LTBLUE}เพิ่มเงิน {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}เล่นเป็นบริษัท: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}เครื่องมือทำลายพิเศษ (ทำลายส่วนอุตสาหกรรม, ของที่เคลื่อนย้ายไม่ได้): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}อุโมงค์สามารถตัดกันได้: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}เครื่องบินไอพ่นจะไม่ตกบ่อยๆ ในท่าอากาศยานขนาดขนาดเล็ก: {ORANGE}{STRING} STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :ภูมิประเทศเขตอบอุ่น STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :ภูมิประเทศเขตกึ่งขั้วโลก STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :ภูมิประเทศเขตกึ่งมรสุม STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :ภูมิประเทศเมืองของเล่น STR_CHEAT_CHANGE_DATE :{LTBLUE}เปลี่ยนวันที่: {ORANGE}{DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}เปลี่ยนปีปัจจุบัน STR_CHEAT_SETUP_PROD :{LTBLUE}เปิดใช้งานการแก้ไขปริมาณผลผลิต: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}สร้างแบบสีใหม่ STR_LIVERY_GENERAL_TOOLTIP :{BLACK}แสดงแบบสีทั่วไป STR_LIVERY_TRAIN_TOOLTIP :{BLACK}แสดงแบบสีรถไฟ STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}แสดงแบบสีรถยนต์ STR_LIVERY_SHIP_TOOLTIP :{BLACK}แสดงแบบสีเรือ STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}แสดงแบบสีเครื่องบิน STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}เลือกสีหลักของแบบสีที่เลือก Ctrl+Click จะปรับสีในทุกๆแบบ STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}เลือกสีรองของแบบสีที่เลือก Ctrl+Click จะปรับสีในทุกๆแบบ STR_LIVERY_PANEL_TOOLTIP :{BLACK}เลือกแบบสีที่จะเปลี่ยน หรือหลายแบบโดย Ctrl+คลิก คลิกบนกล่องเพิ่อปิดเปิดการใช้งานแบบสีนั้น STR_LIVERY_DEFAULT :ชุดสีมาตรฐาน STR_LIVERY_STEAM :รถจักรไอน้ำ STR_LIVERY_DIESEL :รถจักรดีเซล STR_LIVERY_ELECTRIC :รถจักรไฟฟ้า STR_LIVERY_MONORAIL :รถไฟรางเดี่ยว STR_LIVERY_MAGLEV :รถไฟแมคเลฟ STR_LIVERY_DMU :รถดีเซลราง STR_LIVERY_EMU :รถไฟฟ้า STR_LIVERY_PASSENGER_WAGON_STEAM :รถโดยสารของรถจักรไอน้ำ STR_LIVERY_PASSENGER_WAGON_DIESEL :รถโดยสารของรถจักรดีเซล STR_LIVERY_PASSENGER_WAGON_ELECTRIC :รถโดยสารของรถจักรไฟฟ้า STR_LIVERY_PASSENGER_WAGON_MONORAIL :รถไฟรางเดี่ยว STR_LIVERY_PASSENGER_WAGON_MAGLEV :รถไฟแมคเลฟ STR_LIVERY_FREIGHT_WAGON :รถสินค้า STR_LIVERY_BUS :รถโดยสาร STR_LIVERY_TRUCK :รถบรรทุก STR_LIVERY_PASSENGER_SHIP :เรือเฟอรี่/เรือโดยสาร STR_LIVERY_FREIGHT_SHIP :เรือสินค้า STR_LIVERY_HELICOPTER :เฮลิคอปเตอร์ STR_LIVERY_SMALL_PLANE :อากาศยานขนาดเล็ก STR_LIVERY_LARGE_PLANE :อากาศยานขนาดใหญ่ STR_LIVERY_PASSENGER_TRAM :รถรางโดยสาร STR_LIVERY_FREIGHT_TRAM :รถรางขนส่งสินค้า # Face selection window STR_FACE_CAPTION :{WHITE}เลือกใบหน้า STR_FACE_CANCEL_TOOLTIP :{BLACK}ยกเลิการเลือกใบหน้าใหม่ STR_FACE_OK_TOOLTIP :{BLACK}ยอมรับการเลือกใบหน้าใหม่ STR_FACE_RANDOM :{BLACK}สุ่ม STR_FACE_MALE_BUTTON :{BLACK}ผู้ชาย STR_FACE_MALE_TOOLTIP :{BLACK}เลือกใบหน้าผู้ชาย STR_FACE_FEMALE_BUTTON :{BLACK}ผู้หญิง STR_FACE_FEMALE_TOOLTIP :{BLACK}เลือกใบหน้าผู้หญิง STR_FACE_NEW_FACE_BUTTON :{BLACK}ใบหน้าใหม่ STR_FACE_NEW_FACE_TOOLTIP :{BLACK}ทำใบหน้าสุ่มใหม่ STR_FACE_ADVANCED :{BLACK}ขั้นสูง STR_FACE_ADVANCED_TOOLTIP :{BLACK}เลือกใบหน้าขั้นสูง STR_FACE_SIMPLE :{BLACK}อย่างง่าย STR_FACE_SIMPLE_TOOLTIP :{BLACK}เลือกใบหน้าอย่างง่าย STR_FACE_LOAD :{BLACK}โหลด STR_FACE_LOAD_TOOLTIP :{BLACK}โหลดใบหน้าที่ชอบ STR_FACE_LOAD_DONE :{WHITE}ใบหน้าที่ชอบถูกโหลดจากไฟล์กำหนดค่าของ OpenTTD แล้ว STR_FACE_FACECODE :{BLACK}ใบหน้าผู้เล่นเบอร์ STR_FACE_FACECODE_TOOLTIP :{BLACK}ดู และ/หรือ ตั้งหมายเลขใบหน้าผู้เล่น STR_FACE_FACECODE_CAPTION :{WHITE}ดู และ/หรือ ตั้งหมายเลขใบหน้าผู้เล่น STR_FACE_FACECODE_SET :{WHITE}กำหนดหมายเลขใบหน้าใหม่ให้แล้ว STR_FACE_FACECODE_ERR :{WHITE}ไม่สามารถเปลี่ยนหมายเลขใบหน้าได้ - ช่วงตัวเลขต้องอยู่ระหว่าง 0 และ 4,294,967,295! STR_FACE_SAVE :{BLACK}บันทึก STR_FACE_SAVE_TOOLTIP :{BLACK}บันทึกใบหน้าโปรด STR_FACE_SAVE_DONE :{WHITE}ใบหน้านี้จะถูกบันทึกเป็นใบหน้าโปรดในไฟล์การตั้งค่าของ OpenTTD STR_FACE_EUROPEAN :{BLACK}ยุโรป STR_FACE_SELECT_EUROPEAN :{BLACK}เลือกใบหน้ายุโรป STR_FACE_AFRICAN :{BLACK}แอฟริกัน STR_FACE_SELECT_AFRICAN :{BLACK}เลือกใบหน้าแอฟริกัน STR_FACE_YES :ใช่ STR_FACE_NO :ไม่ STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}เปิดใช้งานหนวด STR_FACE_HAIR :ผม: STR_FACE_HAIR_TOOLTIP :{BLACK}เปลี่ยนผม STR_FACE_EYEBROWS :คิ้ว: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}เปลี่ยนคิ้ว STR_FACE_EYECOLOUR :สีตา: STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}เปลี่ยนสีตา STR_FACE_GLASSES :แว่น: STR_FACE_GLASSES_TOOLTIP :{BLACK}เปิดใช้งานแว่นตา STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}เปลี่ยนแว่นตา STR_FACE_NOSE :จมูก: STR_FACE_NOSE_TOOLTIP :{BLACK}เปลี่ยนจมูก STR_FACE_LIPS :ปาก: STR_FACE_MOUSTACHE :หนวด: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}เปลี่ยนปากหรือหนวด STR_FACE_CHIN :คาง: STR_FACE_CHIN_TOOLTIP :{BLACK}เปลี่ยนคาง STR_FACE_JACKET :เสื้อ: STR_FACE_JACKET_TOOLTIP :{BLACK}เปลี่ยนเสื้อ STR_FACE_COLLAR :คอเสื้อ: STR_FACE_COLLAR_TOOLTIP :{BLACK}เปลี่ยนคอเสื้อ STR_FACE_TIE :เนคไท: STR_FACE_EARRING :ต่างหู: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}เปลี่ยนเนคไทหรือต่างหู # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}เล่นหลายคน STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}การประกาศ STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP :{BLACK}เลือกระหว่างการโฆษณา (internet) หรือไม่โฆษณา (Local Area Network, LAN) เกม STR_NETWORK_SERVER_LIST_ADVERTISED_NO :ไม่ใช่ STR_NETWORK_SERVER_LIST_ADVERTISED_YES :ใช่ STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}ชื่อผู้เล่น: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}เป็นชื่อที่ผู้เล่นคนอื่นจะมองเห็น STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}ชื่อ STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}ชื่อของเกม STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}ลูกข่าย STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}จำนวนลูกข่ายออนไลน์ / จำนวนลูกข่ายสูงสุด{}จำนวนบริษัทออนไลน์ / จำนวนบริษัทสูงสุด STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}ขนาดแผนที่ STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}ขนาดแผนที่ของเกม{}คลิกเพื่อเรียงตามขนาดพื้นที่ STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}วันที่ STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}วันที่ปัจจุบัน STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}ปี STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}จำนวนปีที่ผ่านไปในเกม{}ตั้งแต่เริ่มเล่น STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}ภาษา, เวอร์ชันของเซิร์ฟเวอร์, และอื่นๆ STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}คลิกที่เกมจากรายการเพื่อเลือก STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}เซิร์ฟเวอร์ที่เข้าร่วมล่าสุด: STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}คลิกเพื่อเลือกเซิร์ฟเวอร์ที่เล่นล่าสุด STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}ข้อมูลเกม STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}ลูกข่าย: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}ภาษา: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}ภูมิทัศน์: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}ขนาดแผนที่: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}เวอร์ชันของเซิร์ฟเวอร์: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}ที่อยู่เซิร์ฟเวอร์: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}วันที่เริ่ม: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}วันที่ปัจจุบัน: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}ป้องกันด้วยรหัสผ่าน! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}เซิร์ฟเวอร์ออฟไลน์ STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}เซิร์ฟเวอร์เต็ม STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}เวอร์ชันไม่ถูกต้อง STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF ไม่ถูกต้อง STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}เข้าร่วมเกม STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}เรียกดูเซิร์ฟเวอร์ใหม่ STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}เรียกดูข้อมูลเซิร์ฟเวอร์ใหม่ STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}หาเซิร์ฟเวอร์ STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}ค้นหาเซิร์ฟเวอร์ในเครือข่าย STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}เพิ่มเซิร์ฟเวอร์ STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}เพิ่มเซิร์ฟเวอร์เข้าไปในรายการซึ่งจะถูกตรวจสอบเพื่อเข้าเล่นเกม STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}เริ่มเซิร์ฟเวอร์ใหม่ STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}เริ่มเซิร์ฟเวอร์ใหม่ของคุณ STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}ป้อนชื่อของคุณ STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}ป้อนที่อยู่ของโฮสต์ # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}เริ่มเกมผู้เล่นหลายคนใหม่ STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}ชื่อเกม: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}ชื่อเกมจะถูกแสดงให้ผู้เล่นอื่นเห็นในเกมที่มีการเล่นหลายคน STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}กำหนดรหัสผ่าน STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}ป้องกันเกมด้วยรหัสผ่านหากไม่ต้องการให้มีการเข้าร่วมจากบุคคลทั่วไป STR_NETWORK_START_SERVER_UNADVERTISED :ไม่ใช่ STR_NETWORK_START_SERVER_ADVERTISED :ใช่ STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} ลูกข่าย STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}ลูกข่ายสูงสุด: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}เลือกจำนวนมากสุดของลูกข่าย (ไม่จำเป็นต้องครบตามจำนวนนี้) STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} บริษัท STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}จำนวนบริษัทสูงสุด: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}จำกัดจำนวนบริษัทที่อยู่ในเซิร์ฟเวอร์ STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} ผู้ชม STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}ผู้ชมสูงสุด: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}จำกัดจำนวนผู้ชมที่อยู่ในเซิร์ฟเวอร์ STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}ภาษาที่ใช้พูดคุย: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}ผู้เล่นทุกคนจะสามารถทราบถึงภาษาที่ใช้พูดคุยในเซิร์ฟเวอร์นี้ STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}พิมพ์ชื่อสำหรับเล่นในเครือข่าย # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :อะไรก็ได้ STR_NETWORK_LANG_ENGLISH :ภาษาอังกฤษ STR_NETWORK_LANG_GERMAN :ภาษาเยอรมัน STR_NETWORK_LANG_FRENCH :ภาษาฝรั่งเศส STR_NETWORK_LANG_BRAZILIAN :ภาษาบราซิล STR_NETWORK_LANG_BULGARIAN :ภาษาบัลกาเรีย STR_NETWORK_LANG_CHINESE :จีน STR_NETWORK_LANG_CZECH :เช็ก STR_NETWORK_LANG_DANISH :เดนมาร์ก STR_NETWORK_LANG_DUTCH :เนเธอร์แลนด์ STR_NETWORK_LANG_ESPERANTO :ภาษาโลก(Esperanto) STR_NETWORK_LANG_FINNISH :ฟินแลนด์ STR_NETWORK_LANG_HUNGARIAN :ฮังการี STR_NETWORK_LANG_ICELANDIC :ไอร์แลนด์ STR_NETWORK_LANG_ITALIAN :อิตาลี STR_NETWORK_LANG_JAPANESE :ญี่ปุ่น STR_NETWORK_LANG_KOREAN :เกาหลี STR_NETWORK_LANG_LITHUANIAN :ลิทัวเนีย STR_NETWORK_LANG_NORWEGIAN :นอร์เวย์ STR_NETWORK_LANG_POLISH :โปแลนด์ STR_NETWORK_LANG_PORTUGUESE :โปรตุเกส STR_NETWORK_LANG_ROMANIAN :โรมาเนีย STR_NETWORK_LANG_RUSSIAN :รัสเซีย STR_NETWORK_LANG_SLOVAK :สโลวัก STR_NETWORK_LANG_SLOVENIAN :สโลวาเนีย STR_NETWORK_LANG_SPANISH :สเปน STR_NETWORK_LANG_SWEDISH :สวีเดน STR_NETWORK_LANG_TURKISH :ตุรกี STR_NETWORK_LANG_UKRAINIAN :ยูเครน STR_NETWORK_LANG_AFRIKAANS :อัฟกานิสถาน STR_NETWORK_LANG_CROATIAN :โครเอเชีย STR_NETWORK_LANG_CATALAN :คาตาลัน STR_NETWORK_LANG_ESTONIAN :เอสโตเนีย STR_NETWORK_LANG_GALICIAN :กาลีเซีย STR_NETWORK_LANG_GREEK :กรีก STR_NETWORK_LANG_LATVIAN :ลัทเวีย ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}ห้องรับรองโหมดผู้เล่นหลายคน STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}กำลังเตรียมการเข้าร่วม: {ORANGE}{STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}รายการของบริษัททั้งหมดที่อยู่ในเกมนี้ คุณสามารถที่จะเข้าร่วมหนึ่งในรายชื่อบริษัทเหล่านี้ได้หรือสามารถที่จะสร้างบริษัทใหม่ได้หากมีช่องว่างให้คุณ STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}ข้อมูลบริษัท STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}ชื่อบริษัท: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}วันที่เริ่มเปิด: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}มูลค่าของบริษัท: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}งบดุลปัจจุบัน: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}รายได้ของปีที่แล้ว: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}สมรรถภาพ: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}ภาหนะ: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}สถานี: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}ผู้เล่น: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}บริษัทใหม่ STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}สร้างบริษัทใหม่ STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}เข้าชมเกม STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}ดูเกมในฐานะผู้ชม STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}เข้าร่วมบริษัท STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}ช่วยบริหารจัดการบริษัทนี้ # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}กำลังเชื่อมต่อ... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) กำลังเชื่อมต่อ... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) กำลังตรวจสอบการเข้าร่วม... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) กรุณารอ... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) ดาวโหลดแผนที่... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) ประมวลข้อมูล... STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) ลงทะเบียน... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}รวบรวมข้อมูลเกม... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}รวบรวมข้อมูลบริษัท... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} client{P ""} อยู่ข้างหน้าคุณ STR_NETWORK_CONNECTING_DOWNLOADING_1 :ดาวน์โหลดไปแล้ว {BLACK}{BYTES} STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} ดาวโหลดไปแล้วทั้งสิ้น STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}ตัดการเชื่อมต่อ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}เซิฟเวอร์มีการป้องกัน กรุณากรอกพาสเวิร์ด STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}บริษัทมีการป้องกัน. กรุณากรอกพาสเวิร์ด # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}รายการลูกข่าย STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}ผู้ชม STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}บริษัทใหม่ # Network client list STR_NETWORK_CLIENTLIST_KICK :เตะ STR_NETWORK_CLIENTLIST_BAN :แบน STR_NETWORK_CLIENTLIST_GIVE_MONEY :ให้เงิน STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :พูดกับผู้เล่นทั้งหมด STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :พูดกับผู้เล่นในบริษัทเดียวกัน STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :ข้อความส่วนตัว STR_NETWORK_SERVER :เซิฟเวอร์ STR_NETWORK_CLIENT :ลูกข่าย STR_NETWORK_SPECTATORS :ผู้ชม STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}กรอกจำนวนเงินที่ต้องการจะให้ STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}ผู้สังเกตุการณ์ # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}ไม่ทำการเก็บพาสเวิร์ดที่กรอกไว้แล้ว STR_COMPANY_PASSWORD_OK :{BLACK}ตั้งพาสเวิร์ดของบริษัทใหม่ STR_COMPANY_PASSWORD_CAPTION :{WHITE}พาสเวิร์ดของบริษัท STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}พาสเวิร์ดตั้งต้นของบริษัท STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}ใช้พาสเวิร์ดของบริษัทนี้เป็นพาสเวิร์ดตั้งต้นของบริษัทใหม่ # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}เข้าร่วม STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}เข้าร่วมและเล่นเป็นบริษัทนี้ STR_COMPANY_VIEW_PASSWORD :{BLACK}พาสเวิร์ด STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}รหัสผ่านป้องกันบริษัทของคุณจากผู้เล่นที่ไม่ได้รับอนุญาตให้เข้าร่วม STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}ตั้งพาสเวิร์ดของบริษัท # Network chat STR_NETWORK_CHAT_SEND :{BLACK}ส่ง STR_NETWORK_CHAT_COMPANY_CAPTION :[ทีม]: STR_NETWORK_CHAT_CLIENT_CAPTION :[ส่วนตัว] {STRING}: STR_NETWORK_CHAT_ALL_CAPTION :[ทั้งหมด]: STR_NETWORK_CHAT_COMPANY :[ทีม] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_COMPANY :[ทีม] ถึง {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_CLIENT :[ส่วนตัว] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_CLIENT :[ส่วนตัว] ถึง {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_ALL :[ทั้งหมด] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}พิมพ์ข้อความสำหรับการคุยในเครือข่าย # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}ไม่พบอุปกรณ์เน็ทเวิร์กหรือได้ผ่านการคอมไพล์โดยไม่ได้ตัวเลือกนี้ ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}ไม่พบเกมในระบบเน็ทเวิร์ก STR_NETWORK_ERROR_NOCONNECTION :{WHITE}เซิฟเวอร์ไม่ตอบรับคำขอ STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}ไม่สามารถติดต่อได้เนื่องจาก NewGRF ไม่ตรงกัน STR_NETWORK_ERROR_DESYNC :{WHITE}การประสานเวลากับเกม ไม่สำเร็จ(synchronisation failed) STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}การเชื่อมต่อกับเกมสูญหาย STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}ไม่สามารถโหลดเซฟเกมได้ STR_NETWORK_ERROR_SERVER_START :{WHITE}ไม่สามารถเริ่มเซิฟเวอร์ได้ STR_NETWORK_ERROR_CLIENT_START :{WHITE}ไม่สามารถเชื่อมต่อ STR_NETWORK_ERROR_TIMEOUT :{WHITE}เชื่อมต่อครั้งที่ #{NUM} เกินเวลาที่กำหนด STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}ตรวจเจอการขัดข้องของโพรโทคอลและการเชื่อต่อถูกปิดลง STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}revision ของลูกข่ายไม่ตรงกับของเซิฟเวอร์ STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}พาสเวิร์ดผิด STR_NETWORK_ERROR_SERVER_FULL :{WHITE}เซิฟเวอร์เต็ม STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}คุณถูกแบนจากเซิฟเวอร์นี้ STR_NETWORK_ERROR_KICKED :{WHITE}คุณถูกเตะออกจากเซิฟเวอร์ STR_NETWORK_ERROR_CHEATER :{WHITE}ไม่อนุญาตให้โกงในเซิฟเวอร์นี้ STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}คุณส่งคำสั่งให้เซิฟเวอร์มากเกินไป STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}คุณใช้เวลานานเกินไปสำหรับป้อนรหัสผ่าน STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}คอมพิวเตอร์ของคุณช้าไปในการติดต่อกับเครื่องแม่ข่าย STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}คอมพิวเตอร์ของคุณใช้เวลามากเกินไปสำหรับการดาวน์โหลดแผนที่ STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}คอมพิวเตอร์ของคุณใช้เวลามากเกินไปสำหรับการเข้าร่วมกับเซิร์ฟเวอร์ ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :การผิดพลาดทั่วไป STR_NETWORK_ERROR_CLIENT_DESYNC :desync ผิดพลาด STR_NETWORK_ERROR_CLIENT_SAVEGAME :ไม่สามารถโหลดแผนที่ได้ STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :การเชื่อมต่อสูญหาย STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :โปรโทคอลผิดพลาด STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF ไม่ตรง STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :ไม่ผ่านการตรวจสอบ STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :ได้รับแพกเก็ตที่ผิดพลาดหรือไม่คาดหวัง STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :revistion ผิด STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :ชื่อนี้ถูกใช้แล้ว STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :พาสเวิร์ดผิด STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :บริษัทผิดใน DoCommand STR_NETWORK_ERROR_CLIENT_KICKED :ถูกเตะโดยเซิฟเวอร์ STR_NETWORK_ERROR_CLIENT_CHEATER :กำลังพยายามที่จะโกง STR_NETWORK_ERROR_CLIENT_SERVER_FULL :เซิฟเวอร์เต็ม STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :ส่งคำสั่งมากเกินไป STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :ไม่ได้รับรหัสผ่านในเวลาที่กำหนด STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :หมดเวลา STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :ใช้เวลามากไปในการดาวน์โหลดแผนที่ STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :ใช้เวลามากไปในการประมวลผลแผนที่ ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}การเชื่อมต่อล้มเหลว STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}{NUM} วินาทีสุดท้ายไม่มีข้อมูลส่งถึงเครื่องแม่ข่าย # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :เกมหยุด ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :เกมยังหยุดอยู่ ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :เกมยังหยุดอยู่ ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :เกมยังหยุดอยู่ ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :เกมยังถูกหยุดอยู่ ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :เกมเริ่มต่อแล้ว ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :จำนวนผู้เล่น STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :ลูกข่ายกำลังเชื่อมต่อ STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :กำหนดเอง STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :เกมสคริปต์ ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :กำลังออก STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} ได้เข้าร่วมเกม STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} ได้เข้าร่วมเกม (Client #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} ได้เข้าร่วมบริษัท #{2:NUM} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} ได้เข้าเป็นผู้ชม STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} ได้ทำการสร้างบริษัทใหม่ (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} ได้ออกจากเกม ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} ได้ทำการเปลี่ยนชื่อเป็น {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} ยกบริษัทให้คุณ {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** คุณให้ {1:STRING} {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}เซิฟเวอร์ปืดเซสซั่นนี้ STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}เซิฟเวอร์กำลังทำการเริ่มต้นใหม่...{}กรุณารอซักครู่... # Content downloading window STR_CONTENT_TITLE :{WHITE}กำลังโหลดเนื้อหา STR_CONTENT_TYPE_CAPTION :{BLACK}ประเภท STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}ประเภทของเนื้อหา STR_CONTENT_NAME_CAPTION :{BLACK}ชื่อ STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}ชื่อของเนื้อหา STR_CONTENT_MATRIX_TOOLTIP :{BLACK}กดลงบนบรรทัดเพื่อดูรายละเอียด{}ติ๊กบนกล่องเพื่อที่จะเลือกสำหรับการดาวโหลด STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}เลือกทั้งหมด STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}ทำการเลือกเนื้อหาทั้งหมดสำหรับดาวโหลด STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}เลือกอัพเกรด STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}เลือกเนื้อหาทั้งหมดที่เป็นการอัพเกรดของเนื้อหาเดิมที่มีอยู่แล้ว STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}ยกเลิกการเลือกทั้งหมด STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}เลือกทั้งหมดให้ไม่ทำการดาวโหลด STR_CONTENT_SEARCH_EXTERNAL :{BLACK}ค้นหาจากเว็บไซต์ภายนอก STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}สิ่งที่ต้องการหานั้นไม่มีในช่องทาง OpenTTD's content service STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}คุณต้องการออกจากเกมหรือไม่ ? STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER :{WHITE}ข้อกำหนดและข้อความระวังสำหรับการดาวโหลดข้อมูลจากเว็บไซต์ภายนอก.{}คุณต้องหาข้อมูลสำหรับการติดตั้งข้อมูลส่วนนั้นเข้าสู่ OpenTTD.{}ต้องการทำต่อหรือไม่? STR_CONTENT_FILTER_TITLE :{BLACK}Tag/name ตัวกรอง: STR_CONTENT_OPEN_URL :{BLACK}เยี่ยมชมเว็บไซต์ STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}เยี่ยมชมเว็บไซต์ของเนื้อหานี้ STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}ดาวโหลด STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}เริ่มทำการดาวโหลดเนื้อหาที่ได้เลือกไว้ STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}ขนาดทั้งหมด: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}ข้อมูลของเนื้อหา STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}คุณไม่ได้เลือกตัวนี้ให้ทำการดาวโหลด STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}คุณได้ทำการเลือกตัวนี้สำหรับดาวโหลด STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}dependency ตัวนี้ได้ทำการถูกเลือกไว้สำหรับดาวโหลด STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}คุณมีเนื้อหาตัวนี้แล้ว STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}ไม่รู้จักเนื้อหานี้และไม่สามารถดาวโหลดได้ทาง OpenTTD STR_CONTENT_DETAIL_UPDATE :{SILVER}เนื้อหานี้จะทำการติดตั้งทับกับเนื้อหาก่อนหน้านี้ {STRING} STR_CONTENT_DETAIL_NAME :{SILVER}ชื่อ: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}เวอร์ชัน: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}คำบรรยาย: {WHITE}{STRING} STR_CONTENT_DETAIL_URL :{SILVER}URL: {WHITE}{STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}ประเภท: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}ขนาดที่ต้องดาวโหลด: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}ถูกเลือกเนื่องจาก: {WHITE}{STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Dependencies: {WHITE}{STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Tags: {WHITE}{STRING} STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD สร้างขึ้นโดยไม่ได้รองรับ "zlib" ... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... ไม่สามารถดาวโหลดเนื้อหาได้ # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :กราฟฟิคพื้นฐาน STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :AI STR_CONTENT_TYPE_AI_LIBRARY :AI library STR_CONTENT_TYPE_SCENARIO :การจำลอง STR_CONTENT_TYPE_HEIGHTMAP :Heightmap STR_CONTENT_TYPE_BASE_SOUNDS :เสียง STR_CONTENT_TYPE_BASE_MUSIC :เพลงประกอบพื้นฐาน STR_CONTENT_TYPE_GAME_SCRIPT :เกมสคริปต์ STR_CONTENT_TYPE_GS_LIBRARY :GS library # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}กำลังดาวโหลดเนื้อหา STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}ทำการร้องขอไฟล์... STR_CONTENT_DOWNLOAD_FILE :{WHITE}ตอนนี้กำลังดาวโหลด {STRING} ({NUM} จากทั้งหมด {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}ดาวโหลดเสร็จสิ้น STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} จากทั้งหมด {BYTES} ดาวโหลดไปแล้ว ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}ไม่สามารถเชื่อมต่อกับเซิฟเวอร์เนื้อหาเสริมได้.. STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}ดาวโหลดผิดพลาด... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... การเชื่อมต่อสูญหาย STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... ไม่สามารถเขียนทับไฟล์ได้ STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}ไม่สามารถทำการแตกไฟล์ที่ดาวโหลดมาแล้วได้ STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}กราฟฟิกขาดหาย STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD ไม่พบกราฟฟิกที่ใช้ในการทำงาน. คุณต้องการให้ OpenTTD ดาวน์โหลดและติดตั้งกราฟฟิกหรือไม่? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}ดาวน์โหลดกราฟฟิก STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}ออกจาก OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}ตัวเลือกค่าโปร่งใส STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของป้าย. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของต้นไม้. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของบ้าน. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของอุตสาหกรรม. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของสิ่งปลูกสร้างที่สามารถสร้างได้เช่น สถานี, โรงซ่อมบำรุง และที่หมาย เป็นต้น. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของสะพาน. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของสิ่งปลูกสร้างอย่างเช่น ประภาคารและเสาส่งสัญญาณวิทยุ. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของสายจ่ายไฟรถไฟฟ้า. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}เปิด/ปิด การโปร่งใสของตัวบอกการบรรทุกของ. กด Ctrl+Click สำหรับการล็อก STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}ตั้งให้วัตถุมองไม่เห็นแทนการโปร่งใส # Linkgraph legend window STR_LINKGRAPH_LEGEND_CAPTION :{WHITE}แสดงเส้นทางและความหนาแน่น STR_LINKGRAPH_LEGEND_ALL :{BLACK}ทั้งหมด STR_LINKGRAPH_LEGEND_NONE :{BLACK}ไม่เลือก STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}เลือกบริษัทที่จะแสดง # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}น้อย STR_LINKGRAPH_LEGEND_SATURATED :{TINY_FONT}{BLACK}สมดุล STR_LINKGRAPH_LEGEND_OVERLOADED :{TINY_FONT}{BLACK}หนาแน่น # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}แสดงพื้นที่ให้บริการ STR_STATION_BUILD_COVERAGE_OFF :{BLACK}ปิด STR_STATION_BUILD_COVERAGE_ON :{BLACK}เปิด STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}ปิดการแสดงพื้นที่ให้บริการ STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}เปิดการแสดงพื้นที่ให้บริการ STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}สินค้าที่ต้องการ: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}สินค้าที่่จะส่งออกไป: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}รวมสถานี STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}สร้างสถานีแยกต่างหาก STR_JOIN_WAYPOINT_CAPTION :{WHITE}รวมจุดตรวจ STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}สร้างจุดตรวจแยกต่างหาก # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :การก่อสร้างทางรถไฟ STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :การก่อสร้างทางรถไฟพลังไฟฟ้า STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :การก่อสร้างทางรถไฟรางเดี่ยว STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :การก่อสร้างทางรถไฟพลังแม่เหล็ก STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}สร้างทางรถไฟ. กด Ctrl เพื่อสลับการสร้าง/รื้อถอน รางรถไฟ. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/การประเมินค่าใช้จ่าย STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}สร้างทางรถไฟโดยใช้โหมดการสร้างอัตโนมัติ. กด Ctrl เพื่อสลับการสร้าง/รื้อถอน รางรถไฟ STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}สร้างโรงซ่อมบำรุงรถไฟ (สำหรับซื้อขายและซ่อมบำรุงรถไฟ). กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินราคา STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}เปลี่ยนรางรถไฟเป็นที่หมาย. กด Ctrl สามารถรวมที่หมายได้. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}สร้างสถานีรถไฟ. กด Ctrl เพื่อทำการรวมสถานี. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช่จ่าย STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}สร้างเสาอาณัติสัญญาณรถไฟ. กด Ctrl เพื่อสลับระหว่างระบบเสาหางปลา/เสาสัญญาณไฟสี{}สามารถสร้างโดยลากไปกับรางรถไฟได้. กด Ctrl เพื่อสร้างสัญญาณไปจนถึงจุดตัดด้านหน้า{}กด Ctrl+Click เพื่อ เปิด/ปิด หน้าต่างเลือกเสาสัญญาณ. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}สร้างสะพานรถไฟ. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}สร้างอุโมงค์รถไฟ. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}เปลี่ยนระหว่าง สร้าง/รื้อถอน รางรถไฟ, อาณัติสัญญาณ, จุดตรวจและสถานี. กด Ctrl ค้างไว้เพื่อทำการถอนรางรถไฟที่เป็นจุดหมายและสถานี STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}เปลี่ยน/อัพเกรด ชนิดของรางรถไฟ. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_RAIL_NAME_RAILROAD :รางรถไฟ STR_RAIL_NAME_ELRAIL :รางรถไฟฟ้า STR_RAIL_NAME_MONORAIL :รถไฟรางเดียว STR_RAIL_NAME_MAGLEV :รถไฟพลังแม่เหล็ก # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}ทิศทางของโรงซ่อมบำรุง STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}เลือกทิศทางของโรงซ่อมบำรุงรถไฟ # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}จุดตรวจ STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}เลือกชนิดของจุดตรวจ # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}ตัวเลือกของสถานีรถไฟ STR_STATION_BUILD_ORIENTATION :{BLACK}ทิศทาง STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}เลือกทิศทางของสถานีรถไฟ STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}จำนวนชานชาลา STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}เลือกจำนวนของชานชาลา STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}ความยาวของชานชาลา STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}เลือกความยาวของชานชาลา STR_STATION_BUILD_DRAG_DROP :{BLACK}ลากและวาง STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}สร้างสถานีโดยใช้การลากและวาง STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}เลือกชนิดของสถานีที่จะแสดง STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}เลือกชนิดของสถานีที่จะสร้าง STR_STATION_CLASS_DFLT :สถานีมาตรฐาน STR_STATION_CLASS_WAYP :จุดตรวจ # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}เลือกชนิดของเสาอาณัติสัญญาณ STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}เสาอาณัติสัญญาณปกติ (แบบหางปลา){}เสาอาณัติสัญญาณแบบนี้เป็นประเภทพื้นฐานที่สุด, อนุญาตให้มีรถไฟเพียงขบวนเดียวเท่านั้นที่อยู่ในบล็อกสัญญาณนี้ STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}เสาอาณัติสัญญาณขาเข้า (แบบหางปลา){}ให้สัญญาณผ่านตลอดหากเสาขาออกต้นข้างหน้ายังปล่อยผ่านตลอดอยู่ นอกเหนือจากนั้นจะเป็นสัญญาญห้ามผ่าน STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}เสาอาณัติสัญญาณขาออก (แบบหางปลา){}มีผลแบบเดียวกับเสาอาณัติสัญญาณปกติแต่จำเป็นที่จะต้องเปิดสีที่ถูกต้องตรงขาเข้าและสัญญาณต่อเนื่องที่อยู่ก่อนหน้านั้น STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}เสาอาณัติสัญญาณต่อเนื่อง (แบบหางปลา){}สัญญาณต่อเนื่องทำงานง่ายๆโดยทำหน้าที่เสมือนทั้งสัญญาณทางเข้าและทางออก. ซึ่งทำให้สามารถสร้างโครงข่ายขนาดใหญ่ของสัญญาณล่วงหน้าได้ STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}เสาอาณัติสัญญาณตอนอัตโนมัติ (แบบหางปลา){}เสาอาณัติสัญญาณตอนอัตโนมัติ อนุญาตให้รถไฟมากกว่าหนึ่งขบวนเข้าในบล็อกสัญญาณในเวลาเดียวกัน, ถ้ารถไฟสามารถรักษาเส้นทางไว้สำหรับจุดจอดที่ปลอดภัย. Patch Signal ธรรมดาสามารถผ่านจากด้านหลังได้ STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}เสาอาณัติสัญญาณตอนอัตโนมัติ แบบเดินรถทางเดียว (แบบหางปลา){}เสาอาณัติสัญญาณตอนอัตโนมัติ แบบเดินรถทางเดียวอนุญาตให้รถไฟมากกว่าหนึ่งขบวนเข้ามาในบล็อกสัญญาณ, ถ้ารถไฟสามารถรักษาจุดจอดที่ปลอดภัยไว้ได้.เสาอาณัติสัญญาณตอนอัตโนมัติ แบบทางเดียว ไม่สามารถเดินรถย้อนได้ STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}เสาอาณัติสัญญาณปกติ (แบบไฟสี){}เป็นสัญญาณประเภทที่พื้นฐานที่สุด, อนุญาตให้รถไฟแค่ขบวนเดียวอยู่ในบล็อกสัญญาณ ณ ขณะนั้น STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}เสาอาณัติสัญญาณขาเข้า (แบบไฟสี){}ให้สัญญาณผ่านตลอดตราบเท่าที่เสาขาออกต้นใดต้นหนึ่งเป็นสีเขียวจากเขตของรางตรงนั้น. นอกเหนือจากนั้นจะเป็นสีแดง STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}เสาอาณัติสัญญาณขาออก (แบบไฟสี){}มีผลแบบเดียวกับสัญญาณกั้นแต่จำเป็นที่จะต้องเปิดสีที่ถูกต้องตรงขาเข้าและสัญญาณต่อเนื่องที่อยู่ก่อนหน้านั้น STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}เสาอาณัติสัญญาณต่อเนื่อง (แบบไฟสี){}เสาสัญญาณที่มีผลเหมือนกันเสา เข้า และ เสาออก STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}เสาอาณัติสัญญาณตอนอัตโนมัติ (แบบไฟสี){}อนุญาตให้รถไฟหลายขบวนสามารถเข้าไปใน Block เดียวกันได้ โดยใช้ระบบ reserve track เพื่อป้องกันไม่ให้ขบวนรถชนกัน STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}เสาอาณัติสัญญาณตอนอัตโนมัติ แบบเดินรถทางเดียว (แบบไฟสี){}คือ Path Signal ประเภทเดินรถผ่านได้ทางเดียว STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}เปลี่ยนประเภทเสาอาณัติสัญญาณ{}เมื่อเลือกเมนูนี้ คลิ๊กเลือกที่เสาอาณัติสัญญาณที่ตั้งไว้อยู่แล้ว จะเป็นการเปลี่ยนเสาอาณัติสัญญาณเป็นแบบที่เลือกในกล่องเครื่องมือสร้าง STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}จำนวนของเสาอาณัติสัญญาณตั้งแต่ที่เริ่มลากเมาส์มา STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}ลดความหนาแน่นของเสาสัญญาณที่ลากมา STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}เพิ่มปริมาณของเสาสัญญาณที่ลากมา # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}เลือกสะพานรถไฟ STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}เลือกสะพานสำหรับรถยนต์ STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}เลือกสะพาน - คลิกสะพานที่ท่านชื่นชอบเพื่อก่อสร้าง STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :สะพานแขวนแบบคอนกรีต STR_BRIDGE_NAME_GIRDER_STEEL :สะพานนั่งร้านแบบเหล็กกล้า STR_BRIDGE_NAME_CANTILEVER_STEEL :สะพานคานแบบเหล็กกล้า STR_BRIDGE_NAME_SUSPENSION_CONCRETE :สะพานแขวนแบบคอนกรีต STR_BRIDGE_NAME_WOODEN :สะพานไม้ STR_BRIDGE_NAME_CONCRETE :สะพานคอนกรีต STR_BRIDGE_NAME_TUBULAR_STEEL :สะพานท่อแบบเหล็กกล้า STR_BRIDGE_TUBULAR_SILICON :สะพานท่อแบบซิลิคอน # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}สร้างถนน STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}การก่อสร้างรถราง STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}สร้างถนน. กด Ctrl เพื่อสร้าง/รื้อถอนถนน. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}สร้างทางส่วนของรถราง กด CTRL + คลิก เพื่อรื้อถอน กด Shift + คลิก เพื่อแสดงประมาณการค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}สร้างทางส่วนของถนนอัตโนมัติ กด CTRL + คลิก เพื่อรื้อถอน กด Shift + คลิก เพื่อแสดงประมาณการค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}สร้างทางส่วนของรถรางอัตโนมัติ กด CTRL + คลิก เพื่อรื้อถอน กด Shift + คลิก เพื่อแสดงประมาณการค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}สร้างโรงซ่อมบำรุงรถ (สำหรับซื้อและบำรุงรักษารถ). กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}สร้างโรงซ่อมบำรุงรถราง (สำหรับซื้อและบำรุงรักษารถราง). กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}สร้างสถานีรถ. กด Ctrl เพื่อใช้สถานีร่วมกับที่อื่น. กด Shift เพื่อแสดงมูลค่าการก่อสร้าง STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}สร้างสถานีรถราง. กด Ctrl เพื่อใช้สถานีร่วมกับที่อื่น. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}สร้างสถานีรถบรรทุกสินค้า STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}สร้างสถานีสินค้ารถราง. กด Ctrl เพื่อทำการรวมสถานี. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}เลือกใช้ / ยกเลิกการใช้ ถนนวันเวย์ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}สร้างสะพานสำหรับรถยนต์ กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้างและการแสดงมูลค่าโดยประมาณ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}สร้างสะพานสำหรับรถราง. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}สร้างอุโมงค์รถ. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}สร้างอุโมงค์รถราง. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}สลับโหมด สร้าง/ลบ ถนน STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}สลับโหมด สร้าง/ลบ รางสำหรับรถราง # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}ทิศทางของอู่รถ STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}เลือกทิศทางของอู่รถ STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}ทิศทางของโรงซ่อมบำรุงรถราง STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}เลือกทิศทา # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}ทิศทางของโรงซ่อมบำรุงรถ STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}เลือกทิศทางของอู่รถเมล์ STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}ทิศทางของท่าขนส่งสินค้า STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}เลือกทิศทางของท่าขนส่งสินค้า STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}ทิศทางของป้ายหยุดรถราง STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}เลือกทิษทางสำหรับผู้โดยสารรถราง STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}ทิศทางของสถานีรถรางขนส่งสินค้า STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}เลือกทิศทางของสถานีรถรางขนส่งสินค้า # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}การก่อสร้างทางน้ำ STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}คลอง STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}สร้างคลอง กด Shift + คลิก เพื่อประมาณการค่าใช้จ่าย STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}สร้างประตูกั้นน้ำ. แสดง building/showing ราคาประมาณการ STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}สร้างอู่เรือ (สำหรับซื้อขายและซ่อมบำรุงเรือ). กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}สร้างอู่เรือ. กด Ctrl เพื่อใช้สถานีร่วมกับที่อื่น. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}วางทุ่นเพื่อใช้เป็นเวย์พอยต์. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}สร้างสะพานน้ำ. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}สร้างพื้นน้ำ.{}สร้างคลอง หรือหากกด Ctrl ที่ระดับน้ำทะเลจะทำให้ระดับนั้นเป็นน้ำทั้งบริเวณ STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}ปักป้ายบนน้ำ # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}ทิศทางของอู่เรือ STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}เลือกทิศทางของอู่เรือ # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}ท่าเรือ # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}ท่าอากาศยาน STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}สร้างท่าอากาศยาน. กด Ctrl เพื่อใช้สถานีร่วมกับที่อื่น. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}การเลือกประเภทท่าอากาศยาน STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}เลือกขนาด/ชนิดของท่าอากาศยาน STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}ประเภทของท่าอากาศยาน STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}โครงสร้าง {NUM} STR_AIRPORT_SMALL :ลานบินขนาดเล็ก STR_AIRPORT_CITY :เมืองใหญ่ STR_AIRPORT_METRO :ระดับภาคท้องถิ่น STR_AIRPORT_INTERNATIONAL :นานาชาติ STR_AIRPORT_COMMUTER :สนามบินเทศบาล STR_AIRPORT_INTERCONTINENTAL :ระดับภูมิภาค STR_AIRPORT_HELIPORT :จุดจอดเฮลิคอปเตอร์ STR_AIRPORT_HELIDEPOT :โรงซ่อมเฮลิคอปเตอร์ STR_AIRPORT_HELISTATION :สถานีจอดเฮลิคอปเตอร์ STR_AIRPORT_CLASS_SMALL :ท่าอากาศยานขนาดเล็ก STR_AIRPORT_CLASS_LARGE :ท่าอากาศยานขนาดใหญ่ STR_AIRPORT_CLASS_HUB :ท่าอากาศยานนานาชาติ STR_AIRPORT_CLASS_HELIPORTS :ลานจอดเฮลิคอปเตอร์ STR_STATION_BUILD_NOISE :{BLACK}สร้างเสียงรบกวน: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}การปรับภูมิประเทศ STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}ลดระดับมุมของที่ดิน. ลากเพื่อลดระดับมุมที่เลือกและปรับระดับบริเวณที่เลือกใหม่. กด Ctrl เพื่อเลือกบริเวณเป็นแนวทแยง. กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้าง/แสดงการประเมินค่าใช้จ่าย STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}ถมส่วนมุมของที่ดินให้สูงขึ้น STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}ปรับระดับพื้นดินให้เท่ากับความสูงของพื้นที่เลือกเป็นมุมแรก กด Ctrl เพื่อวิเคราะห์พื้นที่ กด Shift เพื่อดูราคาประมาณการ STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}ซื้อพื้นที่สำหรับใช้ในอนาคต. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}การเลือกวัตถุ STR_OBJECT_BUILD_TOOLTIP :{BLACK}เลือกวัตถุเพื่อสร้าง กด Shift เพื่อสลับระหว่างสิ่งปลูกสร้างและการแสดงมูลค่าโดยประมาณ STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}เลือกชนิดของวัตถุที่จะสร้าง STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}ตัวอย่างวัตถุ STR_OBJECT_BUILD_SIZE :{BLACK}ขนาด: {GOLD}{NUM} x {NUM} ช่อง STR_OBJECT_CLASS_LTHS :ประภาคาร STR_OBJECT_CLASS_TRNS :เครื่องส่งสัญญาณ # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}ต้นไม้ STR_PLANT_TREE_TOOLTIP :{BLACK}เลือกชนิดของต้นไม้ STR_TREES_RANDOM_TYPE :{BLACK}สุ่มชนิดของต้นไม้ STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}วางต้นไม้แบบสุ่มชนิด. กด Shift เพื่อแสดงการประเมินค่าใช้จ่าย STR_TREES_RANDOM_TREES_BUTTON :{BLACK}สุ่มต้นไม้ STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}ปลูกต้นไม้โดยการสุ่มทั่วทุกบริเวณ # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}สร้างแผ่นดิน STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}วางพื้นที่แบบหินบนภูมิประเทศ STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}สร้างเขตทะเลทราบ{}กด CTRL เพื่อถอนทิ้ง STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}เพิ่มพื้นที่ในการปรับระดับแผ่นดิน STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}ลดพื้นที่ในการปรับระดับแผ่นดิน STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}สร้างแผ่นดินแบบสุ่ม STR_TERRAFORM_SE_NEW_WORLD :{BLACK}สร้างแผนที่ใหม่ STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}ยกเลิกภูมิทัศน์ทังหมด STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}ลบทรัพย์สินทั้งหมดที่เป็นของบริษัทออกจากแผนที่ STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}ยกเลิกภูมิทัศน์ทังหมด STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}คุณต้องการลบทรัพย์สินทั้งหมดของบริษัทออกหรือไม่? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}สร้างเมือง STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}เมืองใหม่ STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}ก่อสร้างเมืองใหม่ เมื่อกด Shift+คลิกเมาส์ จะแสดงมูลค่าโดยประมาณ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}สุ่มเมือง STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}สร้างเมืองโดยการสุ่มที่ตั้ง STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}สุ่มหลายๆ เมือง STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}สุ่มสร้างเมืองครอบคลุมแผนที่ทั้งหมด STR_FOUND_TOWN_NAME_TITLE :{YELLOW}ชื่อเมือง: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}ใส่ชื่อเมือง STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}คลิกเพื่อใส่ชื่อเมือง STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}สุ่มชื่อ STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}สุ่มสร้างชื่อใหม่ STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}ขนาดเมือง: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}เล็ก STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}ปานกลาง STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}ใหญ่ STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}สุ่ม STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}เลือกขนาดเมือง STR_FOUND_TOWN_CITY :{BLACK}เมืองใหญ่ STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}เมืองใหญ่ขยายตัวเร็วกว่าเมืองเล็ก{}เลือกค่านี้ เมืองที่สร้างจะใหญ่ขึ้นเมื่อสร้างใหม่ STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}รูปแบบถนนของเมือง: STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}เลือกรูปแบบถนนสำหรับเมืองนี้ STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}ดั้งเดิม STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}ถนนดีขึ้น STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}ตาราง 2x2 STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}ตาราง 3x3 STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}สุ่ม # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}ก่อตั้งอุตสาหกรรมใหม่ STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}เลือกอุตสาหกรรมที่เหมาะสมจากรายการนี้ STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :สุ่มหลากหลายอุตสาหกรรม STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}วางโรงงานอุตสาหกรรมแบบสุ่มทั่วแผนที่ STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}ราคา: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}สำรวจ STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}สร้าง STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}ก่อตั้ง # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}สายการผลิตสำหรับอุตสาหกรรม{STRING} STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}สายการผลิตสำหรับสินค้า {STRING} STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}อุตสาหกรรมการผลิต STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}อุตสาหกรรมที่รองรับ STR_INDUSTRY_CARGOES_HOUSES :{WHITE}บ้านเรือน STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}คลิกที่อุตสาหกรรมเพื่อแสดงผู้ผลิตสินค้าและลูกค้า STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}คลิกที่สินค้าเพื่อแสดงผู้ผลิตสินค้าและลูกค้า STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}แสดงห่วงโซ่ STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}แสดงอุปทานและการรับเข้าของอุตสาหกรรม STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}เชื่อมโยงกับแผนที่ย่อ STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}เลือกเพื่อแสดงอุตสาหกรรมในแผนที่ย่อ STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}เลือกประเภทสินค้า STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}เลือกสินค้าที่ต้องการแสดง STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}เลือกอุตสาหกรรม STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}เลือกอุตสาหกรรมที่คุณต้องการแสดง # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}ข้อมูลพื้นที่ STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}มูลค่าของการรื้อถอน: {LTBLUE}ไม่สามารถทำได้ STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}มูลค่าของการรื้อถอน: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}รายได้จากการเคลียร์: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :ไม่มีผู้ครอบครอง STR_LAND_AREA_INFORMATION_OWNER :{BLACK}ผู้ครอบครอง: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}ผู้ครอบครองถนน: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}ผู้ครอบครองทางรถราง: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}ผู้ครอบครองทางรถไฟ: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}ขึ้นตรงกับผู้ดูแลในท้องถิ่น: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :ไม่มี STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}ตำแหน่ง: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}สร้างเมื่อ: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}ประเภทของสถานี: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}รูปแบบของสถานี: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}ระดับท่าอากาศยาน: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}ชื่อท่าอากาศยาน: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}ชื่อท่าอากาศยาน: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}สินค้าที่รับ: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}จำกัดความเร็วรถไฟ: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :หิน STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :พื้นที่หยาบ STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :พื้นที่เปล่า STR_LAI_CLEAR_DESCRIPTION_GRASS :หญ้า STR_LAI_CLEAR_DESCRIPTION_FIELDS :ทุ่งหญ้า STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :พื้นที่หิมะปกคลุม STR_LAI_CLEAR_DESCRIPTION_DESERT :ทะเลทราย STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} ราง STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING}ทางรถไฟกับ Block Signal STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING}ทางรถไฟกับ Pre-Signal STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING}ทางรถไฟกับ Exit-Signal STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING}ทางรถไฟกับ Combo-Signal STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING}ทางรถไฟกับ Path Signal STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING}ทางรถไฟกับ Path Signal แบบเดินทางเดียว STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING}ทางรถไฟกับ Block และ Pre-Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING}ทางรถไฟกับ Block และ Exit-Signal STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING}ทางรถไฟกับ Block และ Combo-Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING}ทางรถไฟกับ Block และ Path Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING}ทางรถไฟกับ Block และ Path Signals แบบเดินรถทางเดียว STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING}ทางรถไฟกับ Pre- และ Exit-Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING}ทางรถไฟกับ Pre- และ Combo-Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING}ทางรถไฟกับ Pre- และ Path Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING}ทางรถไฟและ Pre- และ Path Signals แบบเดินรถทางเดียว STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING}ทางรถไฟกับ Exit- และ Combo-Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING}ทางรถไฟกับ Exit- และ Path Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING}ทางรถไฟและ Exit- และ Path Signals แบบเดินรถทางเดียว STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING}ทางรถไฟและ Combo- และ Path Signals STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING}ทางรถไฟและ Combo- และ Path Signals แบบเดินรถทางเดียว STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING}ทางรถไฟกับ Path และ Path Signals แบบเดินรถทางเดียว STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} โรงซ่อมบำรุงรถไฟ STR_LAI_ROAD_DESCRIPTION_ROAD :ถนน STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :ถนนพร้อมไฟถนน STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :ถนนพร้อมต้นไม้ STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :โรงรถ STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :ทางตัดเสมอระดับ STR_LAI_ROAD_DESCRIPTION_TRAMWAY :ทางรถราง # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (กำลังก่อสร้าง) STR_LAI_TREE_NAME_TREES :ต้นไม้ STR_LAI_TREE_NAME_RAINFOREST :ป่าดิบชื้น STR_LAI_TREE_NAME_CACTUS_PLANTS :ตะบองเพชร STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :สถานีรถไฟ STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :โรงเก็บเครื่องบิน STR_LAI_STATION_DESCRIPTION_AIRPORT :ท่าอากาศยาน STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :จุดโหลดสำหรับรถบรรทุก STR_LAI_STATION_DESCRIPTION_BUS_STATION :สถานีขนส่ง STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :ท่าเรือ STR_LAI_STATION_DESCRIPTION_BUOY :ทุ่น STR_LAI_STATION_DESCRIPTION_WAYPOINT :จุดตรวจ STR_LAI_WATER_DESCRIPTION_WATER :น้ำ STR_LAI_WATER_DESCRIPTION_CANAL :คลอง STR_LAI_WATER_DESCRIPTION_LOCK :ล็อค STR_LAI_WATER_DESCRIPTION_RIVER :แม่น้ำ STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :ชายฝั่ง STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :อู่เรือ # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :อุโมงค์รถไฟ STR_LAI_TUNNEL_DESCRIPTION_ROAD :อุโมงค์รถยนต์ STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :สะพานแขวนแบบเหล็กสำหรับรถไฟ STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :สะพานนั่งร้านแบบเหล็กสำหรับรถไฟ STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :สะพานคานแบบเหล็กกล้าสำหรับรถไฟ STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :สะพานแขวนแบบคอนกรีตเสริมเหล็กสำหรับรถไฟ STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :สะพานแบบไม้สำหรับรถไฟ STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :สะพานแบบคอนกรีตสำหรับรถไฟ STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :สะพานแบบท่อสำหรับรถไฟ STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :สะพานแขวนแบบเหล็กสำหรับรถยนต์ STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :สะพานนั่งร้านแบบเหล็กสำหรับรถยนต์ STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :สะพานคานแบบเหล็กกล้าสำหรับรถยนต์ STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :สะพานแขวนแบบคอนกรีตเสริมเหล็กสำหรับรถยนต์ STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :สะพานเแบบไม้สำหรับรถยนต์ STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :สะพานแบบคอนกรีตสำหรับรถยนต์ STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :สะพานแบบท่อสำหรับรถยนต์ STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :ทางระบายน้ำ STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :เครื่องส่งสัญญาณ STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :ประภาคาร STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :สำนักงานใหญ่บริษัท STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :บริษัทเจ้าของพื้นที่ # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}เกี่ยวกับ OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}ลิขสิทธิ์เดิม {COPYRIGHT} ค.ศ.1995 ของ Chris Sawyer, สงวนลิขสิทธิ์ STR_ABOUT_VERSION :{BLACK}OpenTTD รุ่นที่ {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}ลิขสิทธิ์ OpenTTD {COPYRIGHT}2002-2015 ของ The OpenTTD team # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}บันทึกเกม STR_SAVELOAD_LOAD_CAPTION :{WHITE}โหลดเกม STR_SAVELOAD_SAVE_SCENARIO :{WHITE}บันทึกแผนที่ STR_SAVELOAD_LOAD_SCENARIO :{WHITE}โหลดแผนที่ STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}โหลดแผนที่ระดับสูง STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}บันทึกแผนที่จำลองเสมือนจริง STR_SAVELOAD_HOME_BUTTON :{BLACK}กดที่นี่เพื่อเข้าสู่ตำแหน่งบันทึกเกม/โหลดเกมที่ใช้อยู่ STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} ฟรี STR_SAVELOAD_LIST_TOOLTIP :{BLACK}แสดงไดรฟ์, โฟลเดอร์, และไฟล์เซฟ STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}ชื่อที่กำลังถูกเลือกสำหรับเซฟเกม STR_SAVELOAD_DELETE_BUTTON :{BLACK}ลบ STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}ลบเซฟเกมสำหรับชื่อที่เลือก STR_SAVELOAD_SAVE_BUTTON :{BLACK}บันทึก STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}บันทึกเกมปัจจุบัน กรุณาเลือกชื่อที่ต้องการ STR_SAVELOAD_LOAD_BUTTON :{BLACK}โหลด STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}โหลดเกมที่เลือก STR_SAVELOAD_DETAIL_CAPTION :{BLACK}รายละเอียดเกม STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}ไม่พบข้อมูล STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}ป้อนชื่อเพื่อบันทึกเกม # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}สร้างโลก STR_MAPGEN_MAPSIZE :{BLACK}ขนาดแผนที่: STR_MAPGEN_MAPSIZE_TOOLTIP :{BLACK}เลือกขนาดของแผนที่(ตาราง) จำนวนของตารางที่สามารถมองเห็นจะมีจำนวนน้อยกว่าเล็กน้อย STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}จำนวนเมือง STR_MAPGEN_DATE :{BLACK}วันที่: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}จำนวนอุตสาหกรรม: STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}เส้นความสูงเขตหิมะ: STR_MAPGEN_SNOW_LINE_UP :{BLACK}ปรับเปลี่ยนความสูงของหิมะขึ้นไป 1 ระดับ STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}ปรับเปลี่ยนความสูงของหิมะลงมา 1 ระดับ STR_MAPGEN_LAND_GENERATOR :{BLACK}เครื่องมือสร้างสภาพพื้นดิน: STR_MAPGEN_TREE_PLACER :{BLACK}Tอัลกอริธึมต้นไม้: STR_MAPGEN_TERRAIN_TYPE :{BLACK}ประเภทภูมิประเทศ: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}ระดับทะเล: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}แม่น้ำ: STR_MAPGEN_SMOOTHNESS :{BLACK}ความเรียบ: STR_MAPGEN_VARIETY :{BLACK}การกระจายความแตกต่าง: STR_MAPGEN_GENERATE :{WHITE}สร้างสภาพภูมิประเทศ # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}ขอบแผนที่: STR_MAPGEN_NORTHWEST :{BLACK}ตะวันตกเฉียงเหนือ STR_MAPGEN_NORTHEAST :{BLACK}ตะวันออกเฉียงเหนือ STR_MAPGEN_SOUTHEAST :{BLACK}ตะวันออกเฉียงใต้ STR_MAPGEN_SOUTHWEST :{BLACK}ตะวันตกเฉียงใต้ STR_MAPGEN_BORDER_FREEFORM :{BLACK}ไม่ยึดติดรูปแบบ STR_MAPGEN_BORDER_WATER :{BLACK}น้ำ STR_MAPGEN_BORDER_RANDOM :{BLACK}สุ่ม STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}สุ่ม STR_MAPGEN_BORDER_MANUAL :{BLACK}ปรับแต่งเอง STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}การหมุุนของแผนที่แบบ Heightmap: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}ชื่อของแผนที่ Heightmap: STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}ขนาด: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}ปรับเปลี่ยนความสูงของระดับหิมะ STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}เปลี่ยนปีที่เริ่มต้นเกม # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}ประเภทของแผ่นที่เรื่องราว STR_SE_MAPGEN_FLAT_WORLD :{WHITE}ที่ราบ STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}สร้างที่ราบ STR_SE_MAPGEN_RANDOM_LAND :{WHITE}สุ่มพื้นดิน STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}ระดับความสูงของพื้นราบ: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}ปรับเปลี่ยนความสูงพื้นราบลงมา 1 ระดับ STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}ปรับเปลี่ยนความสูงพื้นราบขึ้นไป 1 ระดับ STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}เปลี่ยนความสูงของพื้นราบ # Map generation progress STR_GENERATION_WORLD :{WHITE}สร้างสภาพภูมิประเทศ... STR_GENERATION_ABORT :{BLACK}ยกเลิก STR_GENERATION_ABORT_CAPTION :{WHITE}ยกเลิกการสร้างภูมิประเทศ STR_GENERATION_ABORT_MESSAGE :{YELLOW}คุณแน่ใจหรือไม่ที่จะยกเลิกการสร้าง? STR_GENERATION_PROGRESS :{WHITE}{NUM}% เสร็จสิ้น STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}เครื่องมือสร้างแผนที่ STR_GENERATION_RIVER_GENERATION :{BLACK}สร้างแม่น้ำ STR_GENERATION_TREE_GENERATION :{BLACK}สร้างต้นไม่ STR_GENERATION_OBJECT_GENERATION :{BLACK}สร้างวัตถุ STR_GENERATION_CLEARING_TILES :{BLACK}สร้างพื้นหิน STR_GENERATION_SETTINGUP_GAME :{BLACK}ตั้งค่าให้กับเกม STR_GENERATION_PREPARING_TILELOOP :{BLACK}Running tile-loop STR_GENERATION_PREPARING_SCRIPT :{BLACK}Running script STR_GENERATION_PREPARING_GAME :{BLACK}กำลังเตรียมพร้อมสำหรับเกม # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}กำหนดค่า NewGRF STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}รายบะเอียดเกี่ยวกับข้อมูลของ NewGRF STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}ใช้งาน NewGRF STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}ไม่ใช้งาน NewGRF STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}เลือกกลุ่มของการตั้งค่า: STR_NEWGRF_FILTER_TITLE :{ORANGE}กรองจากชื่อ: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}โหลดข้อมูลกลุ่มที่ตั้งค่าไว้ STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}บันทึกกลุ่มที่ตั้งค่า STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}บันทึกรายการปัจจุบันเป็นกลุ่มการตั้งค่า STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}ใส่ค่าของกลุ่ม STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}ลบกลุ่ม STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}ลบกลุ่มที่เลือกไว้ปัจจุบัน STR_NEWGRF_SETTINGS_ADD :{BLACK}เพิ่ม STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}เพิ่ม NewGRF ที่เลือกไว้เข้าสู่การตั้งค่าของคุณ STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}สแกนไฟล์ใหม่อีกครั้ง STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}อัพเดตรายการของ NewGRF ที่มีอยู่ STR_NEWGRF_SETTINGS_REMOVE :{BLACK}ลบทิ้ง STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}ลบ NewGRF ที่เลือกไว้ในรายการ STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}ย้ายคำแหน่งขึ้น STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}เลื่อน NewGRF ที่เลือกไว้ขึ้นไปในรายการ STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}ย้ายตำแหน่งลง STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}เลื่อน NewGRF ที่เลือกไว้ลงไปในรายการ STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}รายการของ NewGRF ที่มีการติดตั้งในปัจจุบัน STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}ตั้งค่า parameters STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}แสดง parameters STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}สลับ palette STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}สลับ palette ของ NewGRF ที่เลือก{} ปรับเปลี่ยนหาก NewGRF แสดงผลเป็นสีชมพูในเกม STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}ยืนยันการเปลี่ยนแปลง STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}ค้นหาข้อมูลที่สูญหาย STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}ตรวจสอบเมื่อมีข้อมูลบางส่วนสูญหายผ่าน internet STR_NEWGRF_SETTINGS_FILENAME :{BLACK}ชื่อไฟล์: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Version: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}เวอร์ชันต่ำสุดที่รองรับ: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palette: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parameters: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}ไม่มีข้อมูลรายละเอียดที่จะแสดง STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}หาไฟล์ที่เข้ากันได้ไม่พบ STR_NEWGRF_SETTINGS_DISABLED :{RED}ไม่ใช้งาน STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}ไม่รองรับกับ OpenTTD เวอร์ชั่นนี้ # NewGRF save preset window # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}เปลี่ยนแปลง NewGRF parameters STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}ปิด STR_NEWGRF_PARAMETERS_RESET :{BLACK}ตั้งค่าใหม่ STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}ตั้งค่าพารามิเตอร์ทุกตัวให้เป็นแบบค่าดั้งเดิม STR_NEWGRF_PARAMETERS_DEFAULT_NAME :Parameter {NUM} STR_NEWGRF_PARAMETERS_SETTING :{STRING}: {ORANGE}{STRING} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}จำนวนพารามิเตอร์: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspect - {STRING} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Parent STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}ตรวจสอบชิ้นส่วนของ parent scope STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING} ที่ตำแหน่ง {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :วัตถุ STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :ประเภทของทางรถไฟ STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF ตัวแปร 60+x parameter (hexadecimal) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Aligning sprite {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}sprite ถัดไป STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}เคลื่อนไปยัง sprite ปกติอันถัดไป โดยข้าม pseudo/recolour/font และวกกลับเมื่อถึงจุดสิ้นสุด STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}ไปยัง sprite STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}ไปยัง sprite ที่เลือก ถ้าไม่ใช่ sprite ปกติ จะทำการข้ามไปยัง sprite ถัดไป STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}sprite ก่อนหน้า STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}เคลื่อนไปยัง sprite ปกติอันก่อนหน้า โดยข้าม pseudo/recolour/font และวกกลับเมื่อถึงจุดเริ่มต้น STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}แสดง sprite ที่เลือกใหม่อีกครั้ง STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}ย้าย sprite wxiv[q, แก้ไขแกน X และ Y สำหรับความคลาดเคลื่อน STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}หยิบ sprite STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}หยิบ sprite จากที่ใดก็ตามในหน้าจอ STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}ไปยัง sprite # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}อันตราย: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}ร้ายแรง: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}เกิดความผิดพลาดร้ายแรงเกี่ยวกับ NewGRF: {}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING}ไม่สามารถทำงานได้บน TTDPatchเวอร์ชั่นนี่ รายงานโดย OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} สำหรับ {STRING} version of TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ออกแบบมาสำหรับใช้งานกับ {STRING} STR_NEWGRF_ERROR_INVALID_PARAMETER :parameter ไม่ถูกต้องสำหรับ {1:STRING}: parameter {STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} ต้องโหลดก่อน {STRING} STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} ต้องโหลดหลัง {STRING} STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} ต้องการ OpenTTD version {STRING} หรือสูงกว่า STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :GRF ไฟล์ถูกออกแบบมาเพื่อการแปล STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :มีการเปิดใช้งาน NewGRFs มากเกินไป STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :กำลังทำการโหลด {1:STRING} สำหรับเป็น NewGRF โดย {STRING} could cause desyncs STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :ไม่สามารถคาดการณ์ sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Unknown Action 0 property {4:HEX} (sprite {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Attempt to use invalid ID (sprite {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{STRING} บรรจุ sprites ที่สูญหาย. สิ่งที่สูญหายจะแสดงเป็นเครื่องหมายตกใจสีแดง (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Contains multiple Action 8 entries (sprite {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Read past end of pseudo-sprite (sprite {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}กราฟิกพื้นฐานที่ใช้อยู่มี Sprite ไม่สมบูรณ์{}กรุณาปรับรุ่นของ Base Graphic STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}ไฟล์ในกราฟฟิคพื้นฐานหายไปบางส่วน{}กรุณาอัพเดตกราฟฟิคพื้นฐาน.{}ตั้งแต่คุณเริ่มเล่น {YELLOW}ภาพของ OpenTTD{WHITE},คุณอาจต้องการ {YELLOW}ภาพของกราฟฟิคพื้นฐาน{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :ต้นแบบ GRF ที่ต้องการสามารถใช้การได้(sprite {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} ถูกยกเลิกโดย {STRING} STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :ไม่ถูกต้อง/ไม่ทราบ รูปแบบ sprite (sprite {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}คำเตือน! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}คุณต้องการที่จะปรับเปลี่ยนในเกมที่กำลังทำงานอยู่. การกระทำนี้สามารถทำให้เกมเสียหาย หรือหยุดการทำงานของเกม หากพบปัญหา ไม่ต้องทำการแจ้งบั๊กเข้ามาเกี่ยวกับประเด็นนี้ {} คุณยังต้องการดำเนินการต่อหรือไม่? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}ไม่สามารถเพิ่มเข้าไปได้: GRF ID ซ้ำกัน STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}หาไฟล์ที่เข้ากันได้ไม่ครบ (compatible GRF loaded) STR_NEWGRF_TOO_MANY_NEWGRFS :{WHITE}ไม่สามารถเพิ่ม NewGRF เนื่องจากมี NewGRF มากเกินไป STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}GRF(s) ที่ทำงานร่วมกันได้ ถูกโหลดมาสำหรับไฟล์ที่สูญหาย STR_NEWGRF_DISABLED_WARNING :{WHITE}GRF file(s)ที่สูญหาย ถูกปิดการใช้งาน STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW} GRF file(s) สูญหาย STR_NEWGRF_UNPAUSE_WARNING :{WHITE}การยกเลิกการหยุดเกมอาจจะทำให้เกมเสีย. ไม่ต้องทำการแจ้งปัญหานี้มา.{}คุณยังต้องการกระทำการต่อหรือไม่? # NewGRF status STR_NEWGRF_LIST_NONE :ไม่มี STR_NEWGRF_LIST_ALL_FOUND :แสดงครบทุกไฟล์ STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}ค้นพบ compatible files STR_NEWGRF_LIST_MISSING :{RED}ไฟล์สูญหาย # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}พฤติกรรม NewGRF '{0:STRING}' มีลักษะเหมือนจะมีปัญหา STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}It changed powered-wagon state for '{1:ENGINE}' when not inside a depot STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}เปลี่ยนความยาวของยานพาหนะ '{1:ENGINE}' เมื่อไม่อยู่ภายในโรงซ่อม STR_BROKEN_VEHICLE_LENGTH :{WHITE} รถไฟ '{VEHICLE}' ที่เป็นของ '{COMPANY}' มีความยาวไม่ถูกต้องซึ่งอาจทำให้เกิดปัญหากับ NewGRF และอาจะทำให้เกิดปัญหากับเกมได้ STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' ให้รายละเอียดไม่ถูกต้อง. STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}ข้อมูลของ สินค้า/ดัดแปลง '{1:ENGINE}' จะแตกต่างจากรายการซื้อหลังจากมีการซื้อ. นี่จะส่งผลให้การแทนที่ล้มเหลว STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' caused an endless loop in the production callback STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Callback {1:HEX} returned unknown/invalid result {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO :<สินค้่าไม่ถูกต้อง> STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} ของ STR_NEWGRF_INVALID_ENGINE :<ตัวยานพาหนะไม่ถูกต้อง> STR_NEWGRF_INVALID_INDUSTRYTYPE :<อุตสาหกรรมไม่ถูกต้อง> # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE :<ตัวยานพาหนะไม่ถูกต้อง> # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}ตรวจสอบ NewGRFs STR_NEWGRF_SCAN_MESSAGE :{BLACK}ตรวจสอบ NewGRFs. ขึ้นอยู่กับจำนวนที่มี อาจใช้เวลาสักครู่... STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF ค้นหาเสร็จสิ้น อยู่นอกเหนือการประเมิน {NUM} NewGRF STR_NEWGRF_SCAN_ARCHIVES :ตรวจหาแฟ้มข้อมูล # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}รายชื่อป้าย - {COMMA} ป้าย STR_SIGN_LIST_MATCH_CASE :{BLACK}ตรงกัน STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}แสดงข้อมูลที่ตรงกันเมื่อเปรียบเทียบกับชื่อที่กรองไว้ # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}แก้ไขข้อความของป้าย STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}ไปยังป้ายถัดไป STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}ไปยังป้ายก่อนหน้า STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}กรอกชื่อสำหรับป้าย # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}เมือง STR_TOWN_DIRECTORY_NONE :{ORANGE}- ไม่มี - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}ชื่อเมือง - คลิ๊กเมาส์ที่ชื่อเมือง STR_TOWN_POPULATION :{BLACK}ประชากรโดยรวมทั้งแผนที่: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}นคร {TOWN} STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}จำนวนประชากร: {ORANGE}{COMMA}{BLACK} จำนวนอาคาร: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}ผู้โดยสารเมื่อเดือนที่แล้ว: {ORANGE}{COMMA}{BLACK} จำนวนสูงสุด: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}ไปรษณีย์ภัณฑ์เมื่อเดือนที่แล้ว: {ORANGE}{COMMA}{BLACK} จำนวนสูงสุด: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}ความต้องการสินค้าสำหรับการขยายตัวของเมือง: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} required STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} ต้องการหิมะ STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} จัดส่งมา STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (still required) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (delivered) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}เมืองขยายตัวทุกๆ {ORANGE}{COMMA}{BLACK} วัน STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}เมืองเติบโตทุกๆ {ORANGE}{COMMA}{BLACK} วัน (funded) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}เมือง {RED}ไม่{BLACK} ขยายตัว STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}มีมลภาวะทางเสียง: {ORANGE}{COMMA}{BLACK} สูงสุดที่มีได้: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}กดเมื่อไปยังมุมมองใจกลางเมือง STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}เจ้าหน้าที่ท้องถิ่น STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}ดูข้อมูลเกี่ยวกับเจ้าหน้าที่ในท้องถิ่น STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อเมือง STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}ขยาย STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}ขยายขนาดของเมือง STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}ลบ STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}ลบเมืองเรียบร้อยแล้ว STR_TOWN_VIEW_RENAME_TOWN_BUTTON :เปลี่ยนชื่อเมือง # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}เจ้าหน้าที่ท้องถิ่นของ {TOWN} STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}ความพึงพอใจต่อบริษัท: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}การกระทำที่สามารถทำได้: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}รายการสิ่งที่สามารถทำได้กับเมืองนี้ - กดเพื่อดูรายละเอียดเพิ่มเติม STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}ดำเนินการ STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}กระทำตามที่เลือกไว้ในรายการด้านบน STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :โฆษณาโดยใช้สื่อสิ่งพิมพ์ STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :โฆษณาโดยใช้สื่อกระจายเสียง STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :โฆษณาโดยใช้สื่อโทรทัศน์และอินเตอร์เนต STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :ให้เงินสนับสนุนแก่เมืองเพื่อปรับปรุงถนนใหม่ STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :จ่ายเงินเพื่อสร้างอนุเสาวรีย์ของบริษัท STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :บริจาคเงินให้แก่เมืองเพื่อสร้างสิ่งก่อสร้างใหม่ๆ STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :ลงนามซื้อสัมปทานขนส่ง STR_LOCAL_AUTHORITY_ACTION_BRIBE :ติดสินบนกับเจ้าหน้าที่ท้องถิ่น STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}การโฆษณาระดับเริ่มต้น โดยใช่สื่อสิ่งพิมพ์ ใบปลิวและหนังสือพิมพ์ท้องถิ่น เพิ่มปริมาณผู้โดยสารและสินค้าของเมืองเล็กน้อย{}ใช้งบประมาณ: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}การโฆษณาระดับปานกลาง โดยใช่สื่อวิทยุกระจายเสียง โดยสถานีวิทยุท้องถิ่น เพิ่มปริมาณผู้โดยสารและสินค้าของเมืองปานกลาง.{}ใช้งบประมาณ: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}การโฆษณาในวงกว้าง โดยใช้สื่อโทรทัศน์ และอินเตอร์เนต ทำให้เข้าถึงประชาชนได้มากกว่า เพิ่มปริมาณผู้โดยสารและสินค้าของเมืองปริมาณสูง.{}ใช้งบประมาณ: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}ให้เงินกับเมืองเพื่อทำถนนใหม่,การจราจรจะเป็นอัมพาทเป็นเวลา 6 เดือน. ส่งผลทำให้การจราจรในเมืองเป็นอัมพาธ{}ใช้งบประมาณ: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}สร้างอนุเสาวรีย์แห่งความภาคภูมิใจของบริษัท.{}ใช้งบประมาณ: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}ให้เงินเพื่อสร้างสิ่งปลูกสร้างทางธุรกิจแห่งใหม่ของเมือง.{}ใช้งบประมาณ: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}ซื้อสัมปทานเป็นเวลา 1 ปีสำหรับเมืองเมืองหนึ่ง ผู้โดยสารและสินค้าจะใช้บริการเฉพาะของบริษัทเราเพียงอย่างเดียว {}ใช้งบประมาณ: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}จ่ายเงินใต้โต๊ะติดสินบนให้เจ้าหน้าที่ในท้องถิ่น เพื่อเพิ่มความพึงพอใจ ทำให้สามารถสร้างสิ่งก่อสร้าง รื้อถอนสิ่งก่อสร้างของเมืองได้โดยไม่ติดขัด.{}ใช้งบประมาณ: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} เป้าหมาย STR_GOALS_SPECTATOR_CAPTION :{WHITE}เป้าหมายรวม STR_GOALS_GLOBAL_TITLE :{BLACK}เป้าหมายโดยรวม: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- ไม่มี - STR_GOALS_SPECTATOR_NONE :{ORANGE}- ไม่มี - STR_GOALS_PROGRESS :{ORANGE}{STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_COMPANY_TITLE :{BLACK}เป้าหมายบริษัท: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}คลิ๊กเลือกที่เป้าหมายเพื่อพาไปยังจุดเริ่มต้นที่จะทำตามเป้าหมาย # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :คำถาม STR_GOAL_QUESTION_CAPTION_INFORMATION :ข้อมูล STR_GOAL_QUESTION_CAPTION_WARNING :คำเตือน STR_GOAL_QUESTION_CAPTION_ERROR :ข้อผิดพลาด ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :ยกเลิก STR_GOAL_QUESTION_BUTTON_OK :OK STR_GOAL_QUESTION_BUTTON_NO :ไม่ STR_GOAL_QUESTION_BUTTON_YES :ใช่ STR_GOAL_QUESTION_BUTTON_DECLINE :ไม่ต้องการ STR_GOAL_QUESTION_BUTTON_ACCEPT :ต้องการ STR_GOAL_QUESTION_BUTTON_IGNORE :ไม่สนใจ STR_GOAL_QUESTION_BUTTON_RETRY :ลองใหม่ STR_GOAL_QUESTION_BUTTON_PREVIOUS :ก่อนหน้านี้ STR_GOAL_QUESTION_BUTTON_NEXT :ถัดไป STR_GOAL_QUESTION_BUTTON_STOP :หยุด STR_GOAL_QUESTION_BUTTON_START :เริ่ม STR_GOAL_QUESTION_BUTTON_GO :ไป STR_GOAL_QUESTION_BUTTON_CONTINUE :ทำต่อ STR_GOAL_QUESTION_BUTTON_RESTART :เริ่มใหม่ STR_GOAL_QUESTION_BUTTON_POSTPONE :เลื่อนออกไป STR_GOAL_QUESTION_BUTTON_SURRENDER :ยอมจำนน STR_GOAL_QUESTION_BUTTON_CLOSE :ปิด ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}เงินอุดหนุน STR_SUBSIDIES_OFFERED_TITLE :{BLACK}โครงการที่จะได้รับเงินทุนสนับสนุน: STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} จาก {STRING} ถึง {STRING}{YELLOW} (ก่อน {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- ไม่มี - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}โครงการที่ได้เงินสนับสนุนเรียบร้อยแล้ว: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} จาก {STRING} ถึง {STRING}{YELLOW} ({COMPANY}{YELLOW}, จนกว่าจะถึง {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}กดที่บริการเพื่อไปยังจุดกึ่งกลางของจุดเริ่มต้น # Story book window STR_STORY_BOOK_CAPTION :{WHITE}สมุดบันทึกของ{COMPANY} STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}สมุดบันทึกโดยรวม STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :หน้า {NUM} STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}เลือกข้ามไปยังหน้าที่เลือกโดยการเลือกที่กล่องข้อความ drop down STR_STORY_BOOK_PREV_PAGE :{BLACK}ก่อนหน้า STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}หน้าก่อนหน้า STR_STORY_BOOK_NEXT_PAGE :{BLACK}ถัดไป STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}หน้าถัดไป STR_STORY_BOOK_INVALID_GOAL_REF :{RED}จุดอ้างอิงเป้าหมายผิดพลาด # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}ชื่อสถานี - กดที่ชื่อเพื่อไปยังจุดกึ่งกลาง STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}กด Crtl เพื่อเลือกมากกว่า 1 รายการ STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} สถานี STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- ไม่มี - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}เลือกทั้งหมด STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}เลือกประเภทสินค้าทั้งหมด (รวมถึงสินค้าที่ไม่ได้รอการส่ง) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}ไม่มีสินค้ารออยู่เลย # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} จาก {STATION}) STR_STATION_VIEW_RESERVED :{YELLOW}({CARGO_SHORT} สำรองไว้สำหรับการขนถ่าย) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}ปิดหน้าต่างความนิยม STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}ปิดหน้าต่างความนิยมลงและแสดงเฉพาะรายการสินค้าที่สถานีรองรับและรอการขนส่ง STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}กำลังต้องการ: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}สถานนีนี้มีสัมปทานขนส่งจากเมืองนี้ STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} ซื้อสัมปทานขนส่งที่เมืองนี้ STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}ความพึงพอใจ STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}แสดงความพึงพอใจของสถานี STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}อัตราของการขนส่งและความพึงพอใจในท้องถิ่น: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}จัดกลุ่มโดย STR_STATION_VIEW_WAITING_STATION :จำนวนที่รอ: เรียงตามชื่อสถานี STR_STATION_VIEW_WAITING_AMOUNT :จำนวนที่รอ: เรียงตามจำนวน STR_STATION_VIEW_PLANNED_STATION :ตามแผน: เรียงตามชื่อสถานี STR_STATION_VIEW_PLANNED_AMOUNT :ตามแผน: เรียงตามจำนวน STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} จาก {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} ผ่าน {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} ไปยัง {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} ไม่ทราบต้นทาง STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} ไปยังสถานีอื่นๆ STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} ผ่านสถานีอื่นๆ STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} จากที่นี่ STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} หยุดที่นี่ STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} มายังที่นี่ STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} โดยไม่แวะพักที่อื่น STR_STATION_VIEW_GROUP_S_V_D :ต้นทาง-ผ่าน-ปลายทาง STR_STATION_VIEW_GROUP_S_D_V :ต้นทาง-ปลายทาง-ผ่าน STR_STATION_VIEW_GROUP_V_S_D :ผ่าน-ต้นทาง-ปลายทาง STR_STATION_VIEW_GROUP_V_D_S :ผ่าน-ปลายทาง-ต้นทาง STR_STATION_VIEW_GROUP_D_S_V :ปลายทาง-ต้นทาง-ผ่าน STR_STATION_VIEW_GROUP_D_V_S :ปลายทาง-ผ่าน-ต้นทาง ############ range for rating starts STR_CARGO_RATING_APPALLING :แย่ที่สุด STR_CARGO_RATING_VERY_POOR :แย่มาก STR_CARGO_RATING_POOR :แย่ STR_CARGO_RATING_MEDIOCRE :ปานกลาง STR_CARGO_RATING_GOOD :ดี STR_CARGO_RATING_VERY_GOOD :ดีมาก STR_CARGO_RATING_EXCELLENT :ยอดเยี่ยม STR_CARGO_RATING_OUTSTANDING :เกินความคาดหมาย ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}จุดศูนย์กลางมุมมองสถานี STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อสถานี STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}แสดงขบวนรถไฟที่มีรายการเข้าจอดที่สถานีนี้ STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :แสดงยานพาหนะทางบกที่มีรายการเข้าจอดที่สถานีนี้ STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :แสดงอากาศยานที่มีรายการลงจอดจอดที่สถานีนี้ STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :แสดงเรือที่มีรายการเข้าเทียบท่าที่ท่านี้ STR_STATION_VIEW_RENAME_STATION_CAPTION :เปลี่ยนชื่อสถานี/พื้นที่รับส่งสินค้า STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}ปิดท่าอากาศยาน STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}ไม่ให้เที่ยวบินมาลงจอดที่ท่าอากาศยานนี้ # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}จุดศูนย์กลางมุมมองสถานี STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}เปลี่ยนชื่อ Waypoint STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}จุดศูนย์กลางมุมมองสถานี STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}เปลี่ยนชื่อทุ่มลอยน้ำ STR_EDIT_WAYPOINT_NAME :{WHITE}เปลี่ยนชื่อ Waypoint # Finances window STR_FINANCES_CAPTION :{WHITE} สภาวะการเงินของ {COMPANY}{BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}รายจ่าย/รายรับ STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}ค่าก่อสร้างต่างๆ STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}ค่ายานพาหนะใหม่ STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}ค่าปฏิบัติการต่างๆเกี่ยวกับการเดินรถไฟ STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}ค่าปฏิบัติการต่างๆเกี่ยวกับรถยนต์ STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}ค่าปฏิบัติการต่างๆเกี่ยวกับอากาศยาน STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}ค่าปฏิบัติการต่างๆเกี่ยวกับเรือ STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}ค่าบำรุงรักษาอสังหาริมทรัพย์ STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}รายได้จากการให้บริการเดินรถไฟ STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}รายได้จากการให้บริการขนส่งทางรถยนต์ STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}รายได้จากการให้บริการขนส่งทางอากาศ STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}รายได้จากการให้บริการขนส่งทางน้ำ STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}ดอกเบี้ยเงินกู้ STR_FINANCES_SECTION_OTHER :{GOLD}อื่นๆ STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}รวมทั้งสิ้น: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}ยอดเงินในธนาคาร STR_FINANCES_LOAN_TITLE :{WHITE}เงินกู้ STR_FINANCES_MAX_LOAN :{WHITE}สามารถกู้เงินได้สูงสุด: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}กู้ยืม {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}เพิ่มปริมาณเงินกู้ STR_FINANCES_REPAY_BUTTON :{BLACK}ใช้คืน {CURRENCY_LONG} STR_FINANCES_REPAY_TOOLTIP :{BLACK}ใช้คืนเงินกู้ที่กู้มา STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}โครงสร้างพื้นฐาน # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(ประธานบริษัท) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}ก่อตั้งอย่างเป็นทางการเมื่อ: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}สีของบริษัท: STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}ยานพาหนะ: STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} รถไฟ STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} พาหนะทางบก STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} อากาศยาน STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} พาหนะทางน้ำ STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}ไม่มี STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}ทรัพสินสุทธิ: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}(หุ้น {COMMA}% เป็นของ {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}โครงสร้างพื้นฐาน: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} ทางรถไฟ STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} ถนน STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} คลอง STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} สถานี STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} ท่าอากาศยาน STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}ไม่มี STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}สร้างที่ทำการบริษัท STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}สร้างอาคารที่ทำการบริษัท STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}ไปยังที่ทำการบริษัท STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}เคลื่อนย้ายไปยังที่ทำการบริษัท STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}ย้ายที่ตั้งที่ทำการบริษัท STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}ย้ายที่ตั้งที่ทำการบริษัท STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}รายละเอียด STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}ดูรายละเอียดเกี่ยวกับโครงสร้างพื้นฐาน STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}เลือกใบหน้าใหม่ STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}เลือกใบหน้าใหม่ของผู้ประธานบริษัท STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}เลือกสี STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}เปลี่ยนสีของยานพาหนะบริษัท STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}ชื่อบริษัท STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}เปลี่ยนชื่อบริษัท STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}ชื่อประธานบริษัท STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}เปลี่ยนชื่อประธานบริษัท STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}ซื้อหุ้น 25% STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}ขายหุ้น 25% STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}ซื้อหุ้น 25% จากบริษัทนี้ STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}ขายหุ้น 25% คืนให้บริษัทนี้ STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :ชื่อบริษัท STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :ชื่อประธานบริษัท STR_BUY_COMPANY_MESSAGE :{WHITE}เรากำลังมองหาบริษัทขนส่งอื่นๆที่จะเข้ามากู้วิกฤตบริษัทเรา และซื้อกิจการเราไป.{}{}คุณต้องการจะซื้อกิจการของเราหรือไม่ ? {COMPANY} for {CURRENCY_LONG}? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}โครงสร้างพื้นฐานของ {COMPANY} STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}ชิ้นส่วนทางรถไฟ: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}เสาอาณัติสัญญาณ STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}ชิ้นส่วนถนน: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}ถนน STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}ทางรถราง STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}คลอง: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}คลอง STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}สถานี: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}ชิ้นส่วนสถานี STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}ท่าอากาศยาน STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG}/ปี # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}อุตสาหกรรม STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- ไม่มี - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}){YELLOW} ({COMMA}% ได้รับการขนส่ง) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}/{CARGO_LONG}{STRING}){YELLOW} ({COMMA}%/{COMMA}% ได้รับการขนส่ง) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}ชื่อของอุตสาหกรรม - คลิ๊กที่ชื่อเพื่อไปยังจุดศูนย์กลาง # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}ผลผลิตในเดือนที่แล้ว: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% ได้รับการขนส่ง) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}กดเมื่อไปยังมุมมองจุดศูนย์กลางของอุตสาหกรรม STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}ระดับการผลิต: {YELLOW}{COMMA}% STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}อุตสาหกรรมนี้ได้มีการประกาศปิดตัวลงอย่างเป็นทางการ! ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}มีความต้องการ: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}มีความต้องการ: {YELLOW}{STRING}{STRING}, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}มีความต้องการ: {YELLOW}{STRING}{STRING}, {STRING}{STRING}, {STRING}{STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}พัสดุและสิ่งของที่รอการผลิต: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}ผลผลิต: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}ผลผลิต: {YELLOW}{STRING}{STRING}, {STRING}{STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}ปรับเปลี่ยนปริมาณผลผลิต (ระหว่าง 8 ถึง 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}เปลี่ยนระดับการผลิต (เปอร์เซ็นต์เพิ่มมากสุดถึง 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} - {COMMA} รถไฟ STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING} - {COMMA} พาหนะทางบก STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING} - {COMMA} พาหนะทางน้ำ STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING} - {COMMA} อากาศยาน STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}ขบวนรถไฟ - คลิ๊กเพื่อดูรายละเอียด STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}ยานพาหนะทางบก - คลิ๊กเพื่อดูรายละเอียด STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}ยานพาหนะทางน้ำ - คลิ๊กเพื่อดูรายละเอียด STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}อากาศยาน - คลิ๊กเพื่อดูรายละเอียด STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}กำไรของปีนี้: {CURRENCY_LONG} (ปีที่ผ่านมา: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :รถไฟที่สามารถซื้อได้ STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :ยานพาหนะทางบกที่สามารถซื้อได้ STR_VEHICLE_LIST_AVAILABLE_SHIPS :ยานพาหานะทางน้ำที่สามารถซื้อได้ STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :อากาศยานที่สามารถซื้อได้ STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}กดเพื่อดูรายการสิ่งที่สามารถซื้อได้สำหรับแต่ละประเภทยานพาหนะ STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}จัดการรายการ STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}ส่งการดำเนินการไปยังพาหนะทั้งหมดในรายการนี้ STR_VEHICLE_LIST_REPLACE_VEHICLES :แทนที่ยานพาหนะเดิม STR_VEHICLE_LIST_SEND_FOR_SERVICING :ส่งไปอู่เพื่อซ่อมบำรุง STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :ส่งไปจอดในโรงซ่อมบำรุง STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :ส่งเข้าโรงซ่อมบำรุงรถ STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :ส่งเข้าอู่ต่อเรือ STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :ส่งเข้าโรงเก็บเครื่องบิน STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}กดเพื่อหยุดยานพาหนะทั้งหมดในรายการ STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}กดเพื่อเริมต้นให้ยานพาหนะทั้งหมดในรายการทำงานตามปกติ STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}ยานพาหนะที่ใช้งานคำสั่งร่วมกัน{COMMA} # Group window STR_GROUP_ALL_TRAINS :รถไฟทั้งหมด STR_GROUP_ALL_ROAD_VEHICLES :ยานพาหนะทางบกทั้งหมด STR_GROUP_ALL_SHIPS :ยานพาหนะทางน้ำทั้งหมด STR_GROUP_ALL_AIRCRAFTS :อากาศยานทั้งหมด STR_GROUP_DEFAULT_TRAINS :พาหนะที่ไม่ได้จัดกลุ่ม STR_GROUP_DEFAULT_ROAD_VEHICLES :พาหนะที่ไม่ได้จัดกลุ่ม STR_GROUP_DEFAULT_SHIPS :พาหนะที่ไม่ได้จัดกลุ่ม STR_GROUP_DEFAULT_AIRCRAFTS :พาหนะที่ไม่ได้จัดกลุ่ม STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}กลุ่ม - คลิ๊กที่กลุ่มเพื่อดูรายการยานพาหนะในกลุ่ม STR_GROUP_CREATE_TOOLTIP :{BLACK}กดเพื่อสร้างกลุ่ม STR_GROUP_DELETE_TOOLTIP :{BLACK}ลบกลุ่มที่เลือก STR_GROUP_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อกลุ่มที่เลือก STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}กดเพื่อป้องกันกลุ่มนี้จากการใช้งาน แทนที่ใหม่อัตโนมัติ STR_GROUP_ADD_SHARED_VEHICLE :เพิ่มยานพาหนะที่ใช้รายการคำสั่งเดียวกัน STR_GROUP_REMOVE_ALL_VEHICLES :ลบยานพาหนะทั้งหมด STR_GROUP_RENAME_CAPTION :{BLACK}เปลี่ยนชื่อกลุ่ม # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :รถไฟใหม่ STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :รถไฟฟ้าใหม่ STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :รถไฟฟ้ารางเดี่ยวใหม่ STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Maglev (รถไฟพลังแม่เหล็ก) ใหม่ STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :ประเถทไฟที่สามารถซื้อได้ STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :ประเถทรถที่สามารถซื้อได้ STR_BUY_VEHICLE_SHIP_CAPTION :ประเถทเรือที่สามารถซื้อได้ STR_BUY_VEHICLE_AIRCRAFT_CAPTION :ประเถทอากาศยานที่สามารถซื้อได้ STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}มูลค่า: {GOLD}{CURRENCY_LONG}{BLACK} น้ำหนัก: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}ความเร็ว: {GOLD}{VELOCITY}{BLACK} พลังขับเคลื่อน: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}ความเร็ว: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}ความเร็วบนทะเล: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}ความเร็วบนคลอง/แม่น้ำ: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}ค่าปฏิบัติการ: {GOLD}{CURRENCY_LONG}/ปี STR_PURCHASE_INFO_CAPACITY :{BLACK}ความจุ: {GOLD}{CARGO_LONG} {STRING} STR_PURCHASE_INFO_REFITTABLE :(ดัดแปลงได้) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}สร้างครั้งแรก: {GOLD}{NUM}{BLACK} อายุการใช้งาน: {GOLD}{COMMA} ปี STR_PURCHASE_INFO_RELIABILITY :{BLACK}ประสิทธิภาพสูงสุด: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}มูลค่า: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}น้ำหนัก: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}มูลค่า: {GOLD}{CURRENCY_LONG}{BLACK} ความเร็ว: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}ความจุ: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}รถเสริมกำลัง: {GOLD}+{POWER}{BLACK} น้ำหนัก: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}ดัดแปลงเป็น: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :สินค้าทุกประเภท STR_PURCHASE_INFO_ALL_BUT :ทั้งหมด ยกเว้น {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}กำลังลากจูงสูงสุด: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}พิสัยทำการ: {GOLD}{COMMA} ช่อง STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}รายการรถไฟ - คลิกที่รถไฟเพื่อดูรายละเอียด STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}รายการรถ - คลิกที่รถเพื่อดูรายละเอียด STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}รายการเรือ - คลิกที่เรือเพื่อดูรายละเอียด STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}รายการเครื่องบิน - คลิกที่เครื่องบินเพื่อดูรายละเอียด STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}ซื้อเรือรถ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}ซื้อรถ STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}ซื้อเรือ STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}ซื้อเครื่องบิน STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}ซื้อรถไฟที่เลือกไว้ เมื่อกด Shift+คลิกเมาส์ จะแสดงมูลค่าโดยประมาณโดยไม่ทำการซื้อ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}ซื้อรถที่เลือกไว้ เมื่อกด Shift+คลิกเมาส์ จะแสดงมูลค่าโดยประมาณโดยไม่ทำการซื้อ STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}ซื้อเรือที่เลือกไว้ เมื่อกด Shift+คลิกเมาส์ จะแสดงมูลค่าโดยประมาณโดยไม่ทำการซื้อ STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}ซื้อเครื่องบินที่เลือกไว้ เมื่อกด Shift+คลิกเมาส์ จะแสดงมูลค่าโดยประมาณโดยไม่ทำการซื้อ STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}เปลี่ยนชื่อ STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}เปลี่ยนชื่อ STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}เปลี่ยนชื่อ STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}เปลี่ยนชื่อ STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อชนิดของรถไฟ STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อชนิดของรถ STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อชนิดของเรือ STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อชนิดของเครื่องบิน STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}เปลี่ยนชื่อชนิดของรถไฟ STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}เปลี่ยนชื่อชนิดของรถ STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}เปลี่ยนชื่อชนิดของเรือ STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}เปลี่ยนชื่อชนิดของเครื่องบิน # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อของโรงซ่อมบำรุง STR_DEPOT_RENAME_DEPOT_CAPTION :เปลี่ยนชื่อโรงซ่อมบำรุง STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} ยานพาหนะ{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}รถไฟ - ลากพาหนะด้วยคลิกซ้ายสำหรับ เพิ่ม/ลด จากขบวนรถไฟ, คลิกขวาสำหรับข้อมูล, กด Ctrl ค้างไว้เพื่อกำหนดให้กับขบวนต่อไป STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}รถ - คลิกขวาที่รถเพื่อดูรายละเอียด STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}เรือ - คลิกขวาที่เรือเพื่อดูรายละเอียด STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}เครื่องบิน - คลิกขวาที่เครื่องบินเพื่อดูรายละเอียด STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}คลิกค้างที่ตู้รถไฟแล้วลากมาวางที่นี่เพื่อขาย STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}คลิกค้างที่รถแล้วลากมาวางที่นี่เพื่อขาย STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}คลิกค้างที่เรือแล้วลากมาวางที่นี่เพื่อขาย STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}คลิกค้างที่เครื่องบินแล้วลากมาวางที่นี่เพื่อขาย STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}คลิกค้างที่หัวรถจักรแล้วลากมาวางที่นี่เพื่อขายรถไฟทั้งขบวน STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}ขายรถไฟทั้งหมดที่อยู่ในโรงนี้ STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}ขายพาหนะทางบกทั้งหมดในโรงซ่อมบำรุง STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}ขายพาหนะทางน้ำทั้งหมดในโรงซ่อมบำรุง STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}ขายอากาศยานทั้งหมดในโรงซ่อมบำรุง STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}แทนที่อัตโนมัติสำหรับรถไฟทั้งหมดในโรงซ่อมบำรุง STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :แทนที่อัตโนมัติสำหรับยานพาหนะทางบกทั้งหมดในโรงซ่อมบำรุง STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}แทนที่อัตโนมัติสำหรับยานพาหนะทางน้ำทั้งหมดในอู่ STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}แทนที่อัตโนมัติสำหรับอากาศยานทั้งหมดในโรงซ่อมบำรุง STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}ดูเพื่อซื้อรถไฟใหม่ STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}ดูเพื่อซื้อยานพาหนะทางบกใหม่ STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}ดูเพื่อซื้อยานพาหนะทางน้ำใหม่ STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}ดูเพื่อซื้ออากาศยานใหม่ STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}ซื้อรถจักร/ล้อเลื่อนใหม่ STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}ซื้อยานพาหนะทางบกใหม่ STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}ซื้อยานพาหนะทางน้ำใหม่ STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}ซื้ออากาศยานใหม่ STR_DEPOT_CLONE_TRAIN :{BLACK}คัดลอกขบวนรถไฟ STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}คัดลอกยานพาหนะ STR_DEPOT_CLONE_SHIP :{BLACK}คัดลอกยานพาหนะ STR_DEPOT_CLONE_AIRCRAFT :{BLACK}คัดลอกอากาศยาน STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}กดเพื่อซื้อแบบคัดลอกขบวนรถไฟทั้งขบวน STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}กดเพื่อซื้อแบบคัดลอกยานพาหนะ STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}กดเพื่อซื้อแบบคัดลอกยานพาหนะทางน้ำ STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}กดเพื่อซื้อแบบคัดลอกอากาศยาน STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของโรงซ่อมบำรุง STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของโรงซ่อมบำรุง STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของโรงซ่อมบำรุง STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของโรงซ่อมบำรุง STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}กดเพื่อดูรายการของรถไฟที่มีรายการเข้าซ่อมบำรุงที่โรงซ่อมนี้ STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}กดเพื่อดูรายการของรถที่มีรายการเข้าซ่อมบำรุงที่โรงซ่อมนี้ STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}กดเพื่อดูรายการของเรือที่มีรายการเข้าซ่อมบำรุงที่โรงซ่อมนี้ STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}กดเพื่อดูรายการของอากาศยานที่มีรายการเข้าซ่อมบำรุงที่โรงซ่อมนี้ STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}คลิ๊กเพื่อหยุดรถไฟทุกขบวนที่อยู่ในโรงซ่อมบำรุง STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}คลิ๊กเพื่อหยุดรถทุกคันที่อยู่ในโรงซ่อมบำรุง STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}คลิ๊กเพื่อหยุดเรือทุกลำที่อยู่ในโรงซ่อมบำรุง STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}คลิ๊กเพื่อหยุดอากาศยานทุกลำที่อยู่ในโรงซ่อมบำรุง STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}คลิ๊กให้รถไฟทุกขบวนที่อยู่ในโรงซ่อมบำรุงเริ่มต้นทำงาน STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}คลิ๊กให้รถทุกคันที่อยู่ในโรงซ่อมบำรุงเริ่มต้นทำงาน STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}คลิ๊กให้เรือทุกลำที่อยู่ในโรงซ่อมบำรุงเริ่มต้นทำงาน STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}คลิ๊กให้อากาศยานทุกลำที่อยู่ในโรงซ่อมบำรุงเริ่มต้นทำงาน STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}คุณต้องการขายยานพาหนะทั้งหมด{}ที่อยู่ในโรงซ่อมบำรุง{}{}คุณแน่ใจหรือไม่? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}ข้อความจากผู้ผลิตยานพาหนะ STR_ENGINE_PREVIEW_MESSAGE :{GOLD}เราได้ออกแบบ {STRING} ใหม่ - หากคุณต้องการที่จะนำไปทดลองใช้ เราจะให้คุณนำไปใช้งานก่อนที่จะนำออกไปจำหน่ายในตลาดปกติ {}คุณต้องการนำไปทดลองใช้หรือไม่ ? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :หัวรถจักร STR_ENGINE_PREVIEW_ROAD_VEHICLE :ยานพาหนะทางบก STR_ENGINE_PREVIEW_AIRCRAFT :อากาศยาน STR_ENGINE_PREVIEW_SHIP :ยานพาหนะทางน้ำ STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :รถไฟรางเดี่ยว STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :รถไฟรางแม่เหล็กไฟฟ้า STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}มูลค่า: {CURRENCY_LONG} น้ำหนัก: {WEIGHT_SHORT}{}ความเร็ว: {VELOCITY}พลังขับเคลื่อน: {POWER}{}ค่าปฏิบัติการ: {CURRENCY_LONG}/ปี{}ความจุ: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}มูลค่า: {CURRENCY_LONG} น้ำหนัก: {WEIGHT_SHORT}{}ความเร็ว: {VELOCITY}พลังขับเคลื่อน: {POWER} กำัลังลากจูงสูงสุด: {6:FORCE}{}ค่าปฎิบัติการ: {4:CURRENCY_LONG}/ปี{}ความจุ: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}มูลค่า: {CURRENCY_LONG} ความเร็วสูงสุด: {VELOCITY}{}ความจุ: {CARGO_LONG}, {CARGO_LONG}{}ค่าปฎิบัติการ: {CURRENCY_LONG}/ปี STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}มูลค่า: {CURRENCY_LONG} ความเร็วสูงสุด: {VELOCITY}{}ความจุ: {CARGO_LONG}{}ค่าปฏิบัติการ: {CURRENCY_LONG}/ปี STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}มูลค่า: {CURRENCY_LONG} ความเร็วสูงสุด: {VELOCITY} พิสัย: {COMMA} ช่อง{}ความจุ: {CARGO_LONG}, {CARGO_LONG}{}ค่าปฏิบัติการ: {CURRENCY_LONG}/ปี STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}มูลค่า: {CURRENCY_LONG} ความเร็วสูงสุด: {VELOCITY} พิสัย: {COMMA} tiles{}ความจุ: {CARGO_LONG}{}ค่าปฏิบัติการ: {CURRENCY_LONG}/ปี # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}เปลี่ยน {STRING} - {STRING} STR_REPLACE_VEHICLE_TRAIN :รถไฟ STR_REPLACE_VEHICLE_ROAD_VEHICLE :ยานพาหนะทางบก STR_REPLACE_VEHICLE_SHIP :ยานพาหนะทางน้ำ STR_REPLACE_VEHICLE_AIRCRAFT :อากาศยาน STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}เลือกประเภทของรถจักรที่จะแทนที่ STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}เลือกประเภทของพาหนะที่จะแทนที่ทางซ้ายมือ STR_REPLACE_VEHICLES_START :{BLACK}เริ่มต้นการแทนที่ยานพาหนะ STR_REPLACE_VEHICLES_NOW :แทนที่ยานพาหนะทั้งหมดเดี๋ยวนี้ STR_REPLACE_VEHICLES_WHEN_OLD :แทนที่เฉพาะยานพาหนะที่เก่าแล้ว STR_REPLACE_HELP_START_BUTTON :{BLACK}กดเพื่อเริ่มต้นการแทนที่ยานพาหนะตามที่เลือกไว้ในรายการ STR_REPLACE_NOT_REPLACING :{BLACK}ไม่เปลี่ยน STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}ไม่มียานพาหนะที่เลือกไว้ STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} เมื่อเก่า STR_REPLACE_VEHICLES_STOP :{BLACK}หยุดการแทนที่ยานพาหนะ STR_REPLACE_HELP_STOP_BUTTON :{BLACK}กดเพื่อเริ่มหยุดการแทนที่ยานพาหนะตามที่เลือกไว้ในรายการ STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}กำลังแทนที่: {ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}สลับระหว่างหน้าต่างการแทนที่ของรถจักรและรถพ่วง STR_REPLACE_ENGINES :รถจักร STR_REPLACE_WAGONS :รถพ่วง STR_REPLACE_HELP_RAILTYPE :{BLACK}เลือกประเภทของรถจักรและรถพ่วงที่จะแทนที่ใหม่ STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}แสดงพาหนะที่จะแทนที่ทางด้านซ้าย STR_REPLACE_RAIL_VEHICLES :ยานพาหนะประเภทรถไฟ STR_REPLACE_ELRAIL_VEHICLES :ยานพาหนะที่ใช้ไฟฟ้า STR_REPLACE_MONORAIL_VEHICLES :ยานพาหนะประเภทรถไฟรางเดี่ยว STR_REPLACE_MAGLEV_VEHICLES :รถไฟพลังงานแม่แหล็ก STR_REPLACE_REMOVE_WAGON :{BLACK}ขายรถพ่วง: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}ทำให้การแทนที่ขบวนรถไฟทำให้ความยาวของขบวนยังเท่าเดิม # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของขบวนรถ STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของพาหนะ STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของเรือ STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}กดเพื่อไปยังจุดศูนย์กลางของอากาศยาน STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}ส่งขบวนรถไปยังโรงซ่อมบำรุง STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}ส่งยานพาหนะไปยังโรงซ่อมบำรุง STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}ส่งเรือไปยังโรงซ่อมบำรุง STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}ส่งอากาศยานไปยังโรงซ่อมบำรุง STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}กดเพื่อซื้อแบบคัดลอกขบวนรถไฟทั้งขบวน STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}กดเพื่อซื้อแบบคัดลอกยานพาหนะ STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}กดเพื่อซื้อแบบคัดลอกยานพาหนะทางน้ำ STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}กดเพื่อซื้อแบบคัดลอกอากาศยาน STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}ให้อำนาจขบวนรถไม่ต้องรอเสาอาณัติสัญญาณต้นนี้ (ไม่สามารถใช้กับ Path Signal ได้) STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}ปรับเปลี่ยนการบรรจุเพื่อบรรทุกประเภทสินค้าที่แตกต่าง STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}ปรับเปลี่ยนการบรรจุเพื่อบรรทุกประเภทสินค้าที่แตกต่าง STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}ปรับเปลี่ยนการบรรจุเพื่อบรรทุกประเภทสินค้าที่แตกต่าง STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}ปรับเปลี่ยนการบรรจุเพื่อบรรทุกประเภทสินค้าที่แตกต่าง STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}กลับขบวนรถไฟ STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}กลับรถ STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}แสดงตารางเดินรถ STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}แสดงตารางรายการคำสั่งของยานพาหนะ STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}แสดงตารางรายการคำสั่งของยานพาหนะ STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}แสดงตารางรายการคำสั่งของยานพาหนะ STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}แสดงรายละเอียดของขบวนรถไฟ STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}แสดงรายละเอียดของยานพาหนะนี้ STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}{BLACK}แสดงรายละเอียดของเรือลำนี้ STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}{BLACK}แสดงรายละเอียดของอากาศยานลำนี้ STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}สภาพการปัจจุบันของขบวนรถนี้ STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}สภาพการปัจจุบันของรถคันนี้ STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}สภาพการปัจจุบันของเรือลำนี้ STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}สภาพการปัจจุบันของเครื่องบินลำนี้ # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}อยู่ระหว่างการขนถ่าย STR_VEHICLE_STATUS_LEAVING :{LTBLUE}เริ่มออกเดินทาง STR_VEHICLE_STATUS_CRASHED :{RED}เสีย! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}เสีย! STR_VEHICLE_STATUS_STOPPED :{RED}หยุด STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}กำหลังหยุด, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED}ไม่มีกำลัง STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}รอทาง STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}เกินพิสัยการบิน STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}มุ่งหน้าสู่ {STATION} ด้วยความเร็ว {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}ไม่มีสถานที่ที่ต้องไป, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}มุ่งหน้าสู่ {WAYPOINT} ด้วยความเร็ว {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}มุ่งหน้าสู่ {DEPOT} ด้วยความเร็ว {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}ซ่อมบำรุงที่ {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}หยุด STR_VEHICLE_COMMAND_STOPPED :{RED}หยุด STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}เริ่ม STR_VEHICLE_COMMAND_STARTED :{GREEN}เริ่ม # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}รายละเอียดของ {VEHICLE} STR_VEHICLE_NAME_BUTTON :{BLACK}ชื่อ STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}ชื่อ STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}ชื่อ STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}ชื่อ STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}ชื่อ STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}ใช้งานมาแล้ว: {LTBLUE}{STRING}{BLACK} ค่าปฏิบัติการ: {LTBLUE}{CURRENCY_LONG}/ปี # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} ปี ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} ปี ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}ความเร็วสูงสุด: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}ความเร็วสูงสุด: {LTBLUE}{VELOCITY} {BLACK}พิสัย: {LTBLUE}{COMMA} ช่อง STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}น้ำหนัก: {LTBLUE}{WEIGHT_SHORT} {BLACK}พลังขับเคลื่อน: {LTBLUE}{POWER}{BLACK} ความเร็วสูงสุด: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}น้ำหนัก: {LTBLUE}{WEIGHT_SHORT} {BLACK}พลังขับเคลื่อน: {LTBLUE}{POWER}{BLACK} ความเร็วสูงสุด: {LTBLUE}{VELOCITY} {BLACK}กำลังลากจูงสูงสุด: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}ผลประกอบการปีนี้: {LTBLUE}{CURRENCY_LONG} (ปีที่แล้ว: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}ประสิทธิภาพ: {LTBLUE}{COMMA}% {BLACK}เกิดการชำรุดหลังจากเข้าซ่อมบำรุงครั้งที่แล้ว: {LTBLUE}{COMMA} {BLACK}ครั้ง STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}สร้างเมื่อ: {LTBLUE}{NUM}{BLACK} มูลค่า: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}บรรทุก: {LTBLUE}ไม่มี{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}บรรทุก: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}บรรทุก: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}บรรทุก: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}รายได้จากการส่งต่อ: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}เข้าซ่อมบำรุงทุก: {LTBLUE}{COMMA}วัน{BLACK} ครั้งสุดท้ายเมื่อ: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}เข้าซ่อมบำรุงเมื่อประสิทธิภาพ: {LTBLUE}{COMMA}%{BLACK} เข้าซ่อมบำรุงครั้งสุดท้ายเมื่อ: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}เพิ่มระยะการซ่อมบำรุงครั้งละ 10 . Ctrl+Click เพิ่มทีละ5 STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}ลดระยะการซ่อมบำรุงครั้งละ 10 . Ctrl+Click ลดทีละ5 STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}ปรับเปลี่ยนประเภทการวัดค่าที่ควรซ่อมบำรุง STR_VEHICLE_DETAILS_DEFAULT :ค่าเริ่มต้น STR_VEHICLE_DETAILS_DAYS :วัน STR_VEHICLE_DETAILS_PERCENT :เปอร์เซนต์ STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}ชื่อรถ STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}ชื่อรถ STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}ชื่อเรือ STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}ชื่ออากาศยาน # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} สร้างเมื่อ: {LTBLUE}{NUM}{BLACK} มูลค่า: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} มูลค่า: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}ความจุสินค้าทั้งหมดของรถไฟขบวนนี้: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}ว่างเปล่า STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} จาก {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} จาก {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}สินค้า STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}แสดงรายละเอียดสิ่งของที่บรรทุกมา STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}ข้อมูล STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}แสดงรายละเอียดของรถไฟ STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}ปริมาณที่รับได้ STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}แสดงความจุของขบวนรถ STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}แสดงความจุรวมทั้งหมดของขบวนรถ STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}แสดงความจุรวมทั้งหมดของขบวนรถ แยกตามประเภทสินค้า STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}ความจุ: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (ดัดแปลง) STR_REFIT_TITLE :{GOLD}เลือกประเภทสินค้าที่จะบรรทุก: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}ความจุใหม่: {GOLD}{CARGO_LONG}{}{BLACK}มูลค่าในการดัดแปลง: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}ความจุใหม่: {GOLD}{CARGO_LONG}{}{BLACK}กำไรจากการดัดแปลง: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}ความจุใหม่: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}มูลค่าการดัดแปลง: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}ความจุใหม่: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}กำไรจากการดัดแปลง: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}เลือกส่วนที่จะดัดแปลง กดเม้าส์แล้วลากเพื่อเลือกหลายๆคัน STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}เลือกประเภทของสินค้าสำหรับรถไฟที่จะบรรทุก STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}เลือกประเภทของสินค้าสำหรับรถจะบรรทุก STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}{BLACK}เลือกประเภทของสินค้าสำหรับเรือจะบรรทุก STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}{BLACK}เลือกประเภทของสินค้าสำหรับอากาศยานที่จะบรรทุก STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}ดัดแปลงรถไฟ STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}ดัดแปลงรถ STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}ดัดแปลงเรือ STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}ดัดแปลงเครื่องบิน STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}ดัดแปลงตามที่เลือกประเภทสินค้าไว้ STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}ดัดแปลงตามที่เลือกประเภทสินค้าไว้ STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}ดัดแปลงตามที่เลือกประเภทสินค้าไว้ STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}ดัดแปลงตามที่เลือกประเภทสินค้าไว้ # Order view STR_ORDERS_CAPTION :{WHITE}รายการคำสั่งของ {VEHICLE} STR_ORDERS_TIMETABLE_VIEW :{BLACK}ตารางเวลา STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}สลับไปยังตารางเวลา STR_ORDERS_LIST_TOOLTIP :{BLACK}รายการต้นทางปลายทาง STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - สิ้นสุดรายการ - - STR_ORDERS_END_OF_SHARED_ORDERS :- - สิ้นสุดคำสั่งที่ใช้ร่วมกัน - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}ไม่หยุด STR_ORDER_GO_TO :ไปยัง STR_ORDER_GO_NON_STOP_TO :ไม่หยุดจนถึง STR_ORDER_GO_VIA :ผ่าน STR_ORDER_GO_NON_STOP_VIA :ไม่หยุดจนไปผ่าน STR_ORDER_TOOLTIP_NON_STOP :{BLACK}เปลี่ยนรูปแบบการหยุดตามรายการที่เลือก STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}รอจนสินค้าบางประเภทเต็ม STR_ORDER_DROP_LOAD_IF_POSSIBLE :รับสินค้าตามที่บรรทุกได้ STR_ORDER_DROP_FULL_LOAD_ALL :รอจนเต็ม STR_ORDER_DROP_FULL_LOAD_ANY :รอจนสินค้าบางประเภทเต็ม STR_ORDER_DROP_NO_LOADING :ไม่มีการขนถ่าย STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}เลือกรูปแบบการรับส่งสินค้าตามที่เลือกในรายการ STR_ORDER_TOGGLE_UNLOAD :{BLACK}ถ่ายสินค้าลงทั้งหมด STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :ถ่ายสินค้าลงถ้าสถานีรับ STR_ORDER_DROP_UNLOAD :ถ่ายสินค้าออกทั้งหมด STR_ORDER_DROP_TRANSFER :ส่งต่อ STR_ORDER_DROP_NO_UNLOADING :ไม่ถ่ายสินค้าลง STR_ORDER_TOOLTIP_UNLOAD :{BLACK}เปลี่ยนรูปแบบการถ่ายออกตามที่เลือกไว้ในรายการ STR_ORDER_REFIT :{BLACK}ดัดแปลง STR_ORDER_REFIT_TOOLTIP :{BLACK}เลือกประเภทสินค้าที่จะเปลี่ยนไปทำการบรรทุก STR_ORDER_REFIT_AUTO :{BLACK}ดัดแปลงอัตโนมัติ STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}ดัดแปลงเพื่อปรับเปลี่ยนการบรรทุกสินค้าประเภทอื่นอัตโนมัติ STR_ORDER_DROP_REFIT_AUTO :เลือกประเภทตามกำหนด STR_ORDER_DROP_REFIT_AUTO_ANY :ตามสินค้าที่ต้องการการขนส่ง STR_ORDER_SERVICE :{BLACK}ซ่อมบำรุง STR_ORDER_DROP_GO_ALWAYS_DEPOT :ไปทุกครั้ง STR_ORDER_DROP_SERVICE_DEPOT :เข้าซ่อมบำรุงหากต้องการ STR_ORDER_DROP_HALT_DEPOT :หยุด STR_ORDER_SERVICE_TOOLTIP :{BLACK}จะข้ามรายการนี้ไปเมื่อยังไม่มีความต้องการซ่อมบำรุง STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}ข้อมูลยานพาหนะที่จะข้ามไป # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :ปริมาณการบรรทุกรวม STR_ORDER_CONDITIONAL_RELIABILITY :ประสิทธิภาพของพาหนะ STR_ORDER_CONDITIONAL_MAX_SPEED :ความเร็วสูงสุด STR_ORDER_CONDITIONAL_AGE :อายุการใช้งาน(ปี) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :ต้องการการซ่อมบำรุง STR_ORDER_CONDITIONAL_UNCONDITIONALLY :ตลอดเวลา STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :เหลืออายุการใช้งาน(ปี) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}วิธีการเปรียบเทียบข้อมูลยานพาหนะเพื่อใส่ค่า STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :เท่ากับ STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :ไม่เท่ากับ STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :น้อยกว่า STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :น้อยกว่าหรือเท่ากับ STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :มากกว่า STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :มากกว่าหรือเท่ากับ STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :คือใช่ STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :คือไม่ใช่ STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}ค่าที่จะเปรียบเทียบกับระหว่างยานพาหนะทั้งสอง STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}ใส่ค่า่ที่จะเปรียบเีทียบ STR_ORDERS_SKIP_BUTTON :{BLACK}ข้าม STR_ORDERS_SKIP_TOOLTIP :{BLACK}ข้ามรายการที่กำลังทำไปยังรายการถัดไป STR_ORDERS_DELETE_BUTTON :{BLACK}ลบ STR_ORDERS_DELETE_TOOLTIP :{BLACK}ลบรายการที่เลือก STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}ลบคำสั่งทั้งหมด STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}หยุดการใช้คำสั่งร่วมกัน STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}หยุดการ Share รายการที่ต้องทำ STR_ORDERS_GO_TO_BUTTON :{BLACK}ไปยัง STR_ORDER_GO_TO_NEAREST_DEPOT :ไปยังโรงซ่อมบำรุงที่ใกล้ที่สุด STR_ORDER_GO_TO_NEAREST_HANGAR :ไปยังโรงซ่อมบำรุงที่ใกล้ที่สุด STR_ORDER_CONDITIONAL :สั่งให้ข้ามรายการในคำสั่ง STR_ORDER_SHARE :Share รายการที่ต้องทำ STR_ORDERS_GO_TO_TOOLTIP :{BLACK}เพิ่มรายการที่ต้องทำก่อนหน้ารายการที่เลือก หรือเพิ่มในท้ายรายการที่มีอยู่แล้ว STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}แสดงยานพาหนะทั้งหมดที่ใช้คำสั่งนี้ # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :ผ่าน {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :ไม่หยุดจนกว่าจะผ่าน {WAYPOINT} STR_ORDER_SERVICE_AT :ซ่อมบำรุงที่ STR_ORDER_SERVICE_NON_STOP_AT :ไม่หยุดจนไปซ่อมบำรุงที่ STR_ORDER_NEAREST_DEPOT :ใกล้ที่สุด STR_ORDER_NEAREST_HANGAR :โรงซ่อมที่ใกล้ที่สุด STR_ORDER_TRAIN_DEPOT :โรงซ่อมบำรุง STR_ORDER_ROAD_VEHICLE_DEPOT :โรงซ่อมบำรุงรถ STR_ORDER_SHIP_DEPOT :อู่เรือ STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(ดัดแปลงเป็น {STRING}) STR_ORDER_REFIT_STOP_ORDER :(ดัดแปลงเป็น {STRING} และหยุด) STR_ORDER_STOP_ORDER :(หยุด) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(อัตโนมัติ) STR_ORDER_FULL_LOAD :(รับจนเต็ม) STR_ORDER_FULL_LOAD_ANY :(รับสินค้าบางชนิดจนเต็ม) STR_ORDER_NO_LOAD :(ไม่รับสินค้า) STR_ORDER_UNLOAD :(ถ่ายสินค้าออกทั้งหมดและรับสินค้าใหม่) STR_ORDER_UNLOAD_FULL_LOAD :(ถ่ายสินค้าออกทั้งหมดแล้วรอสินค้าใหม่เต็ม) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(ถ่ายสินค้าทั้งหมดออกแล้วรอสินค้าใหม่บางอย่างเต็ม) STR_ORDER_UNLOAD_NO_LOAD :(ถ่ายสินค้าออกทั้งหมดแล้วออกไปแบบว่างเปล่า) STR_ORDER_TRANSFER :(ส่งต่อสินค้าและรับสินค้าใหม่) STR_ORDER_TRANSFER_FULL_LOAD :(ส่งต่อสินค้าและรอรับสินค้าจนเต็ม) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(ส่งต่อสินค้าและรอรับสินค้าบางชนิดเต็ม) STR_ORDER_TRANSFER_NO_LOAD :(ส่งต่อสินค้าแล้วออกมาแบบว่างเปล่า) STR_ORDER_NO_UNLOAD :(ไม่ถ่ายสินค้าลงและรับสินค้าเพิ่ม) STR_ORDER_NO_UNLOAD_FULL_LOAD :(ไม่ถ่ายสินค้าลงและรอจนสินค้าเต็ม) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(ไม่ถ่ายสินค้าลงและรอจนบางอย่างเต็ม) STR_ORDER_NO_UNLOAD_NO_LOAD :(ไม่มีการขนถ่ายสินค้า) STR_ORDER_AUTO_REFIT :(ดัดแปลงอัตโนมัติเป็น {STRING}) STR_ORDER_FULL_LOAD_REFIT :(ดัดแปลงอัตโนมัติเป็น {STRING} และรอจนเต็ม) STR_ORDER_FULL_LOAD_ANY_REFIT :(ดัดแปลงอัตโนมัติเป็น {STRING} และรอจนบางอย่างเต็ม) STR_ORDER_UNLOAD_REFIT :(ถ่ายสินค้าลง ดัดแปลงอัตโนมัติเป็น {STRING} และรับสินค้า) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(ถ่ายสินค้าลง ดัดแปลงอัตโนมัติเป็น {STRING} และรอสินค้าเต็ม) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(ถ่ายสินค้าลง ดัดแปลงอัตโนมัติเป็น {STRING} และรอสินค้าบางอย่างเต็ม) STR_ORDER_TRANSFER_REFIT :(ส่งต่อสินค้า ดัดแปลงอัตโนมัติเป็น {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(ส่งต่อสินค้า ดัดแปลงอัตโนมัติเป็น {STRING} และรอจนเต็ม) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(ส่งต่อสินค้า ดัดแปลงอัตโนมัติเป็น {STRING} และรอจนบางอย่างเต็ม) STR_ORDER_NO_UNLOAD_REFIT :(ไม่ถ่ายสินค้าลง แต่ดัดแปลงเป็น {STRING} และรับสินค้าเพิ่ม) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(ไม่ถ่ายสินค้าลง แต่ดัดแปลงเป็น {STRING} และรับสินค้าเพิ่มจนเต็ม) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(ไม่ถ่ายสินค้าลง แต่ดัดแปลงเป็น {STRING} และรับสินค้าบางอย่างจนเต็ม) STR_ORDER_AUTO_REFIT_ANY :สินค้าที่มี STR_ORDER_STOP_LOCATION_NEAR_END :[จอดที่ปลายสุด] STR_ORDER_STOP_LOCATION_MIDDLE :[จอดกึ่งกลาง] STR_ORDER_STOP_LOCATION_FAR_END :[จอดพอดีท้ายขบวน] STR_ORDER_OUT_OF_RANGE :{RED} (ที่หมายถัดไปไกลเกินพิสัย) STR_ORDER_CONDITIONAL_UNCONDITIONAL :ข้ามไปยังคำสั่งที่ {COMMA} STR_ORDER_CONDITIONAL_NUM :ข้ามไปยังคำสั่งที่ {COMMA} เมื่อ {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :ข้ามไปยังคำสั่งที่ {COMMA} เมื่อ {STRING} {STRING} STR_INVALID_ORDER :{RED} (คำสั่งไม่ถูกต้อง) # Time table window STR_TIMETABLE_TITLE :{WHITE}ตารางเวลาของ {VEHICLE} STR_TIMETABLE_ORDER_VIEW :{BLACK}คำสั่ง STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}สลับไปยังรายการคำสั่ง STR_TIMETABLE_TOOLTIP :{BLACK}ตารางเวลา - กดบนรายการที่ไฮไลท์ STR_TIMETABLE_NO_TRAVEL :ไม่มีการเดินทาง STR_TIMETABLE_NOT_TIMETABLEABLE :เดินทาง (อัตโนมัติ; ตามตารางเวลาต่อไปที่ตั้งไว้) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :>>>ไปยังที่หมายถัดไป(ไม่ได้กำหนดเวลา)<<< STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :>>>ความเร็วไม่เกิน {2:VELOCITY} (ไม่มีกำหนดเวลา)<<< STR_TIMETABLE_TRAVEL_FOR :เวลาในการเดินทางคือ {STRING} STR_TIMETABLE_TRAVEL_FOR_SPEED :เวลาในการเดินทางคือ {STRING} ความเร็วสูงสุดไม่เกิน {VELOCITY} STR_TIMETABLE_STAY_FOR :หยุดเป็นเวลา {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :และเดินทาง {STRING} STR_TIMETABLE_DAYS :{COMMA} วัน STR_TIMETABLE_TICKS :{COMMA} tick STR_TIMETABLE_TOTAL_TIME :{BLACK}ตารางเวลานี้เสร็จสิ้นโดยใช้เวลาทั้งหมด {STRING} STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}ตารางเวลานี้ใช้เวลารวมทั้งสิ้น {STRING} (และยังไม่สมบูรณ์) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}ยานพาหนะนี้เดินทางได้ตามเวลา STR_TIMETABLE_STATUS_LATE :{BLACK}ยานพาหนะนี้เดินทางช้ากว่าเวลาปกติอยู่ {STRING} STR_TIMETABLE_STATUS_EARLY :{BLACK}ยานพาหนะนี้เดินทางเร็วกว่าเวลาปกติอยู่ {STRING} STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}ตารางเวลายังไม่เริ่มต้น STR_TIMETABLE_STATUS_START_AT :{BLACK}ตารางเวลานี้จะเริ่มใน {STRING} STR_TIMETABLE_STARTING_DATE :{BLACK}วันที่เริ่มต้น STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}เลือกวันที่ที่จะให้เริ่มต้นตารางเวลา. Ctrl+Click เพื่อให้ยานพาหนะที่ใช้ตารางเวลานี้เริ่มต้นที่จุดเดียวกัน, ถ้าตารางเวลาสมบูรณ์แล้ว STR_TIMETABLE_CHANGE_TIME :{BLACK}ปรับเปลี่ยนเวลา STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}เปลี่ยนเวลาที่ตำแหน่งไฮไลท์ในรายการ STR_TIMETABLE_CLEAR_TIME :{BLACK}ลบเวลา STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}ลบเวลาในรายการที่ไฮไลท์ STR_TIMETABLE_CHANGE_SPEED :{BLACK}ตั้งจำกัดความเร็ว STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}เปลี่ยนความเร็วการเดินทางสูงสุดของลำดับที่ถูกไฮไลท์ STR_TIMETABLE_CLEAR_SPEED :{BLACK}ยกเลิกการจำกัดความเร็ว STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}ยกเลิกความเร็วการเดินทางสูงสุดของลำดับที่ถูกไฮไลท์ STR_TIMETABLE_RESET_LATENESS :{BLACK}รีเซตเวลาที่ช้า STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}รีเซตเวลาที่ล่าช้าเพื่อให้ยานพาหนะเริ่มต้นตามเวลาใหม่ STR_TIMETABLE_AUTOFILL :{BLACK}เติมอัตโนมัติ STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}เติมตารางเวลาอัตโนมัติ (Ctrl+Click เพื่อปรับระยะเวลารอ) STR_TIMETABLE_EXPECTED :{BLACK}การคาดการณ์ STR_TIMETABLE_SCHEDULED :{BLACK}ตารางเวลา STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}สลับระหว่างการดูรายการตารางเวลาและการคาดการณ์ STR_TIMETABLE_ARRIVAL_ABBREVIATION :ถึง: STR_TIMETABLE_DEPARTURE_ABBREVIATION :ออก: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}กำหนดวัน STR_DATE_SET_DATE :{BLACK}กำหนดวัน STR_DATE_SET_DATE_TOOLTIP :{BLACK}เลือกวันที่จะเริ่มต้นใช้งานตารางเวลา STR_DATE_DAY_TOOLTIP :{BLACK}เลือกวัน STR_DATE_MONTH_TOOLTIP :{BLACK}เลือกเดือน STR_DATE_YEAR_TOOLTIP :{BLACK}เลือกปี # AI debug window STR_AI_DEBUG :{WHITE}AI/Game Script Debug STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}ชื่อ script STR_AI_DEBUG_SETTINGS :{BLACK}ตั้งค่า AI STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}เปลี่ยนการตั้งค่า AI STR_AI_DEBUG_RELOAD :{BLACK}โหลด AI อีกครั้งหนึ่ง STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}ปิด AI ทั้งหมด,ทำการ Reload Script, และทำการเริ่มต้น AI ใหม่อีกครั้ง STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}เปิด/ปิด การหยุด เมื่อ Log แสดงข้อมูล AI ตรงกับข้อมูลใน Break String STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Break on: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Break on STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}เมื่อข้อความใน AI Log ตรงกับ string นี้ ให้ทำการหยุดเกม STR_AI_DEBUG_MATCH_CASE :{BLACK}ตรงกัน STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}แสดงกรณีที่ตรงเมื่อมีการเปรียบเทียบข้อความใน AI log ที่ตรงกับ Braek string STR_AI_DEBUG_CONTINUE :{BLACK}ต่อเนื่อง STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}ยกเลิกการหยุดเกม และเปิดทำงาน AI ต่อไป STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}ดูการผลลัพธ์การดีบักของ AI นี้ STR_AI_GAME_SCRIPT :{BLACK}Game Script STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}ตรวจสอบ Script log ของเกม STR_ERROR_AI_NO_AI_FOUND :ไม่มี AI ที่เหมาะสมที่จะโหลดขึ้นมา.{}AI นี้เป็นเพียงตัวแทนไม่สามารถทำอะไรได้.{} คุณสามารถดาวโหลดเพิ่มเติมจากระบบ Online Content STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}ถ้ามีกรณี Script เสีย กรุณารายงานไปยังผู้เขียน Script พร้อม Screenshot ของหน้าต่าง AI และ Game script debug STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}AI/Game Script Debug window จะใช้งานได้เฉพาะที่เป็น Server # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}ปรับแต่ง AI/Game Script STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}Game Script จะเปิดใช้งานในเกมถัดไป STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}AI จะทำการเปิดใช้งานในเกมถัดไป STR_AI_CONFIG_HUMAN_PLAYER :ผู้เล่น STR_AI_CONFIG_RANDOM_AI :คอมพิวเตอร์ STR_AI_CONFIG_NONE :(ไม่มี) STR_AI_CONFIG_MOVE_UP :{BLACK}เลื่อนขึ้น STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}ย้าย AI ที่เลือกขึ้นด้านบนของรายชื่อ STR_AI_CONFIG_MOVE_DOWN :{BLACK}เลื่อนลง STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}ย้าย AI ที่เลือกลงด้านล่างของรายชื่อ STR_AI_CONFIG_GAMESCRIPT :{SILVER}Game Script STR_AI_CONFIG_AI :{SILVER}AI STR_AI_CONFIG_CHANGE :{BLACK}เลือก {STRING} STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :AI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Game Script STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}โหลดscriptอื่น STR_AI_CONFIG_CONFIGURE :{BLACK}Configure STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}ปรับแต่ง parameters ของ Script # Available AIs window STR_AI_LIST_CAPTION :{WHITE}ที่เปิดใช้งาน {STRING} STR_AI_LIST_CAPTION_AI :AI STR_AI_LIST_CAPTION_GAMESCRIPT :Game Scripts STR_AI_LIST_TOOLTIP :{BLACK}คลิ๊กเพื่อเลือก script STR_AI_LIST_AUTHOR :{LTBLUE}ผู้เขียน: {ORANGE}{STRING} STR_AI_LIST_VERSION :{LTBLUE}เวอร์ชั่น: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}URL: {ORANGE}{STRING} STR_AI_LIST_ACCEPT :{BLACK}ยืนยัน STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}เลือก script ที่ไฮไลท์ไว้ STR_AI_LIST_CANCEL :{BLACK}ยกเลิก STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}ไม่สามารถเปลี่ยน script # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parameters STR_AI_SETTINGS_CAPTION_AI :AI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Game Script STR_AI_SETTINGS_CLOSE :{BLACK}ปิด STR_AI_SETTINGS_RESET :{BLACK}เริ่มใหม่ STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} STR_AI_SETTINGS_START_DELAY :จำนวนที่จะให้เริ่มต้น AI นี้หลังจากที่มีการเริ่มต้น AI ก่อนหน้านี้ไป: {ORANGE}{STRING} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} readme ของ {STRING} STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} changelog ของ {STRING} STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} การอนุญาตของ {STRING} STR_TEXTFILE_WRAP_TEXT :{WHITE}Wrap อักษร STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}จัดตัวอักษรให้พอดีกับหน้าต่าง จะได้พอดีโดยไม่ต้อง scroll STR_TEXTFILE_VIEW_README :{BLACK}แสดง readme STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}ข้อมูลการอัพเดต STR_TEXTFILE_VIEW_LICENCE :{BLACK}การอนุญาต # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}รายจ่าย: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}รายจ่าย: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}รายได้: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}รายได้: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}ส่งต่อ: {CURRENCY_LONG} STR_FEEDER :{YELLOW}ส่งต่อ: {CURRENCY_LONG} STR_FEEDER_INCOME_TINY :{TINY_FONT}{YELLOW}ส่งต่อ: {CURRENCY_LONG}{WHITE} / {GREEN}รายได้: {CURRENCY_LONG} STR_FEEDER_INCOME :{YELLOW}ส่งต่อ: {CURRENCY_LONG}{WHITE} / {GREEN}รายได้: {CURRENCY_LONG} STR_FEEDER_COST_TINY :{TINY_FONT}{YELLOW}ส่งต่อ: {CURRENCY_LONG}{WHITE} / {RED}รายจ่าย: {CURRENCY_LONG} STR_FEEDER_COST :{YELLOW}ส่งต่อ: {CURRENCY_LONG}{WHITE} / {RED}รายจ่าย: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}มูลค่าประมาณการ: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}รายได้ประมาณการ: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}ขณะนี้กำลังบันทึก,{}โปรดรอจนกว่าจะเสร็จ! STR_ERROR_AUTOSAVE_FAILED :{WHITE}บันทึกอัตโนมัติล้มเหลว!!! STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}ไม่สามารถอ่านข้อมูลได้ STR_ERROR_GAME_SAVE_FAILED :{WHITE}บันทึกเกมล้มเหลว!!!{}{STRING} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}ไม่สามารถทำการลบไฟล์ STR_ERROR_GAME_LOAD_FAILED :{WHITE}โหลดเกมล้มเหลว{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :ข้อผิดพลาดจากภายใน: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :เกมที่บันทึกไว้ เสีย - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :เกมที่บันทึกไว้ สำหรับเวอร์ชันใหม่ STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :ไม่สามารถโหลดไฟล์ได้ STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :ไม่สามารถเขียนไฟล์ได้ STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :การตรวจสอบความสมบูรณ์ของข้อมูลล้มเหลว STR_GAME_SAVELOAD_NOT_AVAILABLE :<ไม่สามารถใช้งาน> STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}บันทึกนี้บันทึกเป็นเวอร์ชั่นที่ยังไม่สนับสนุนระบบรถราง. ทั้งหมดจะถูกลบออก # Map generation messages STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}การสร้างแผนที่ถูกยกเลิก...{}... ไม่มีสถานที่เมืองที่เหมาะสม STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... ไม่มีเมืองในแผนที่จำลอง STR_ERROR_PNGMAP :{WHITE}ไม่สามารถโหลดสภาพภูมิประเทศจากไฟล์ PNG... STR_ERROR_PNGMAP_FILE_NOT_FOUND :{WHITE}... หาไฟล์ไม่พบ STR_ERROR_PNGMAP_IMAGE_TYPE :{WHITE}... ไม่สามารถแปลงประเภทของภาพได้. ต้องการภาพ 8-bit หรือ 24-bit PNG STR_ERROR_PNGMAP_MISC :{WHITE}... มีบางอย่างไม่ถูกต้อง (เป็นไปได้ว่าไฟล์เสียหาย) STR_ERROR_BMPMAP :{WHITE}ไม่สามารถโหลดสภาพภูมิประเทศจากไฟล์ BMP... STR_ERROR_BMPMAP_IMAGE_TYPE :{WHITE}... ไม่สามารถแปลงประเภทของภาพได้ STR_ERROR_HEIGHTMAP_TOO_LARGE :{WHITE}... ภาพมีขนาดใหญ่เกินไป STR_WARNING_HEIGHTMAP_SCALE_CAPTION :{WHITE}สเกลภาพไม่ตรงกับการตั้งค่าแผนที่ STR_WARNING_HEIGHTMAP_SCALE_MESSAGE :{YELLOW}ไม่แนะนำให้ทำการลดขนาดภาพต้นฉบับ. แน่ใจหรือไม่ว่าต้องการทำต่อ? # Soundset messages STR_WARNING_FALLBACK_SOUNDSET :{WHITE}พบเฉพาะไฟล์เสียงสำรอง. หากต้องการฟังเสียงอื่นๆ โปรดดาวน์โหลดและติดตั้งจาก Content Download System # Screenshot related messages STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}ภาพถ่ายขนาดใหญ่ STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}ความละเอียดของภาพ:{COMMA} x {COMMA} พิกเซล. การถ่ายภาพอาจใช้เวลาซักพัก. คุณต้องการดำเนินการต่อหรือไม่? STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Screenshot บันทึกเรียบร้อยแล้ว ที่ '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}การบันทึก Screenshot ล้มเหลว! # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}ข้อความ STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}ข้อความจาก {STRING} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}อยู่นอกขอบแผนที่ STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP :{WHITE}ใกล้กับขอบแผนที่เกินไป STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY :{WHITE}มีเงินไม่พอ - ต้องการอีก {CURRENCY_LONG} STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}ต้องใช้พื้นที่ราบ STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}เนินดินในทิศทางที่ผิด STR_ERROR_CAN_T_DO_THIS :{WHITE}ไม่สามารถทำได้... STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}มีสิ่งปลูกสร้างที่ต้องทำลายก่อน STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}ไม่สามารถรื้อถอนได้... STR_ERROR_SITE_UNSUITABLE :{WHITE}... พื้นที่นั้นไม่เหมาะสม STR_ERROR_ALREADY_BUILT :{WHITE}... พร้อมที่จะทำการสร้าง STR_ERROR_OWNED_BY :{WHITE}... เป็นของ {STRING} STR_ERROR_AREA_IS_OWNED_BY_ANOTHER :{WHITE}... พื้นที่นี้ถูกจับจองโดยบริษัทอื่น STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... การจัดการภูมิประเทศถึงขีดจำกัด STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... การเคลียพื้่นที่ถึงขีดจำักัด STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... การปลูกต้นไม้ถึงขีดจำกัด STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}ชื่อนี้มีอยู่แล้ว!! STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{1:STRING} ในเส้นทาง STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}ไม่อนุญาตให้ สร้าง/รื้อถอน ขณะหยุดเกม # Local authority errors STR_ERROR_LOCAL_AUTHORITY_REFUSES_TO_ALLOW_THIS :{WHITE}{TOWN}{} เจ้าหน้าที่ในท้องถิ่นไม่อนุญาตให้ท่านดำเนินการ STR_ERROR_LOCAL_AUTHORITY_REFUSES_AIRPORT :{WHITE}{TOWN}เจ้าหน้าที่ท้องถิ่นปฏิเสธที่จะอนุญาตให้สร้างท่าอากาศยานเพิ่มในท้องถิ่น STR_ERROR_LOCAL_AUTHORITY_REFUSES_NOISE :{WHITE}{TOWN}เจ้าหน้าที่ท้องถิ่นปฏิเสธที่จะอนุญาตให้สร้างท่าอากาศยานเนื่องจากมลภาวะทางเีสียงเกินปริมาณ STR_ERROR_BRIBE_FAILED :{WHITE}สินบนของคุณถูกตรวจพบโดย{}ผู้รักษากฎหมายในท้องที่ # Levelling errors STR_ERROR_CAN_T_RAISE_LAND_HERE :{WHITE}ตรงนี้ไม่สามารถยกระดับพื้นดินได้ STR_ERROR_CAN_T_LOWER_LAND_HERE :{WHITE}ตรงนี้ไม่สามารถลดระดับพื้นดินได้... STR_ERROR_CAN_T_LEVEL_LAND_HERE :{WHITE}ตรงนี้ไม่สามารถปรับระดับพื้นดินให้เท่ากันได้... STR_ERROR_EXCAVATION_WOULD_DAMAGE :{WHITE}การขุดลงไปจะทำให้อุโมงค์เสียหาย STR_ERROR_ALREADY_AT_SEA_LEVEL :{WHITE}... ตอนนี้อยู่ที่ระดับน้ำทะเลแล้ว STR_ERROR_TOO_HIGH :{WHITE}... สูงเกินไป STR_ERROR_ALREADY_LEVELLED :{WHITE}... อยู่ในสภาพที่ต่ำที่สุดแล้ว # Company related errors STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}ไม่สามารถเปลี่ยนชื่อบริษัทได้ STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}ไม่สามารถเปลี่ยนชื่อประธานบริษัทได้... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... ปริมาณเงินสูงสุดที่สามารถกู้ได้ {CURRENCY_LONG} STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}ไม่สามารถกู้เงินเพิ่มได้จากนี้แล้ว... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... ไม่มีหนี้ที่ค้างชำระแล้ว STR_ERROR_CURRENCY_REQUIRED :{WHITE}... {CURRENCY_LONG} ต้องการ STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}ไม่สามารถใช้หนี้ได้... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}ไม่สามารถส่งเงินได้ นี่คือเงินกู้ที่มาจากธนาคาร... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}ไม่สามารถซื้อกิจการได้... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}ไม่สามารถสร้างสำนักงานได้... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}ไม่สามารถซื้อหุ้น 25% จากบริษัทนี้ได้... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}ไม่สามารถขายหุ้น 25% จากบริษัทนี้ได้... STR_ERROR_PROTECTED :{WHITE}บริษัทนี้ยังไม่เก่าแก่พอที่จะซื้อหุ้นหรือซื้อกิจการได้... # Town related errors STR_ERROR_CAN_T_GENERATE_TOWN :{WHITE}ไม่สามารถสร้างเมืองใดได้อีก STR_ERROR_CAN_T_RENAME_TOWN :{WHITE}ไม่สามารถเปลี่ยนชื่อเมืองได้... STR_ERROR_CAN_T_FOUND_TOWN_HERE :{WHITE}ไม่สามารถสร้างเมืองที่นี่ได้... STR_ERROR_CAN_T_EXPAND_TOWN :{WHITE}ไม่สามารถขยายเมืองได้ STR_ERROR_TOO_CLOSE_TO_EDGE_OF_MAP_SUB :{WHITE}... ติดกับขอบแผนที่มากเกินไป STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... ใกล้กับเมืองอื่นมากเกินไป STR_ERROR_TOO_MANY_TOWNS :{WHITE}... มีเมืองมากเกินไป STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... มีพื้นที่บนแผนที่ไม่มากพอ STR_ERROR_TOWN_EXPAND_WARN_NO_ROADS :{WHITE}เมืองจะไม่สามารถสร้างถนนได้ในอนาคต. คุณสามารถเปิดใช้งานสร้างถนนของเมือง ใน Advanced Settings->Economy->Towns STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}กำลังอยู่ระหว่างการปรับปรุงถนน STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}ไม่สามารถทำลายเมืองได้{}สถานีหรือโรงเก็บนี้เป็นทรัพย์สินของเมืองไม่สามารถทำลายหรือเคลื่อนย้ายได้ STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... ที่นี่ไม่มีสถานที่เหมาะสมในการสร้างอนุเสาวรีย์ในใจกลางเมือง # Industry related errors STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... มีอุตสาหกรรมมากเกินไป STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}ไม่สามารถสร้างอุตสาหกรรมได้... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}บริเวณนี้ไม่สามารถสร้าง {STRING} ได้... STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}ไม่สามารถสร้างอุตสาหกรรมประเภทนี้่ได้ที่นี่... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... ใกล้กับอุตสาหกรรมอื่นมากเกินไป STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... ต้องสร้างเมืองก่อน STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... อนุญาตให้สร้างได้แค่หนึ่งเดียวต่อเมืองหนึ่งเมือง STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... จะสามารถสร้างได้ต่อเมื่อเมืองมีประชากรอย่างน้อย 1200 คน STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... สามารถสร้างได้เฉพาะพื้นที่ป่าฝนเขตร้อน STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... สามารถสร้างได้เฉพาะในทะเลทราย STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS :{WHITE}... สามารถสร้างได้เฉพาะในเมืองเท่านั้น (แทนที่บ้าน) STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER :{WHITE}... สามารถสร้างได้บริเวณใกล้จุดศูนย์กลางของเมืองเท่านั้น STR_ERROR_CAN_ONLY_BE_BUILT_IN_LOW_AREAS :{WHITE}สามารถสร้างได้เฉพาะพื้นที่ต่ำกว่าเท่านั้น STR_ERROR_CAN_ONLY_BE_POSITIONED :{WHITE}... สามารถวางตำแหน่งบริเวณขอบของแผนที่เท่านั้น STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... สามารถปลูกป่าได้ที่ระดับเหนือกว่าระดับหิมะเท่านั้น STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... สามารถสร้างได้ที่ระดับเหนือกว่าระดับหิมะเท่านั้น STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... สามารถสร้างได้ที่ระดับต่ำกว่าระดับหิมะเท่านั้น # Station construction related errors STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}บริเวณนี้ไม่สามารถสร้างสถานีรถไฟได้ STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}ไม่สามารถสร้าง ป้ายหยุดรถ/สถานีขนส่ง STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}ไม่สามารถสร้างสถานีรถบรรทุกได้ STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}ไม่สามารถสร้างสถานีผู้โดยสารรถรางได้ STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}ไม่สามารถสร้างสถานีรถรางขนส่งสินค้าได้ STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}ตรงนี้ไม่สามารถสร้างอู่เรือได้ STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}ตรงนี้ไม่สามารถสร้างท่าอากาศยานได้ STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}มากเกิน 1 สำหรับสถานที่ขนส่งสินค้า STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... ขอบเขตของสถานีกว้างเกินไป STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}มีสถานีหรือจุดโหลด มากเกินไปแล้วในเกม STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}ชิ้นส่วนสถานีมากเกินไป STR_ERROR_TOO_MANY_BUS_STOPS :{WHITE}ป้ายรถเมล์มากเกินไป STR_ERROR_TOO_MANY_TRUCK_STOPS :{WHITE}มีจุดขนถ่ายสินค้ามากเกินไป STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION :{WHITE}ใกล้กับสถานี/จุดขนถ่ายสินค้าอื่นเกินไป STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}ใกล้กับท่าเทียบเรืออื่นมากเกินไป STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT :{WHITE}ใกล้กับท่าอากาศยานอื่นมากเกินไป STR_ERROR_CAN_T_RENAME_STATION :{WHITE}ไม่สามารถเปลี่ยนชื่อได้... STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD :{WHITE}... นี่เป็นถนนซึ่งเมืองนี้เป็นเจ้าของ STR_ERROR_DRIVE_THROUGH_DIRECTION :{WHITE}... ถนนหันไปผิดทิศทาง STR_ERROR_DRIVE_THROUGH_CORNER :{WHITE}... ป้ายจอดรถแบบวิ่งผ่านไม่สามารถสร้างบนทางโค้งได้ STR_ERROR_DRIVE_THROUGH_JUNCTION :{WHITE}... ป้ายจอดรถแบบวิ่งผ่านไม่สามารถสร้างบนทางแยกได้ # Station destruction related errors STR_ERROR_CAN_T_REMOVE_PART_OF_STATION :{WHITE}ไม่สามารถลบบางส่วนของสถานีได้... STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}ต้องลบสถานีรถไฟทิ้งก่อนเป็นอันดับแรก STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}ไม่สามารถลบสถานีขนส่งได้... STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}ไม่สามารถลบสถานีขนสินค้าได้... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}ไม่สามารถลบสถานีรถรางโดยสารได้... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}ไม่สามารถลบสถานีรถรางขนสินค้าได้... STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}ต้องลบถนนออกก่อน STR_ERROR_THERE_IS_NO_STATION :{WHITE}... ไม่มีสถานี STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}ต้องทำลายสถานีรถไฟก่อน STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}ต้องทำลายสถานีขนส่งก่อน STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST :{WHITE}ต้องทำลายสถานีส่งสินค้าก่อน STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST :{WHITE}ต้องทำลายสถานีรถรางโดยสารก่อน STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}ต้องทำลายสถานีรถรางขนสินค้าก่อน STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}ต้องทำลายท่าเทียบเรือก่อน STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}ต้องทำลายท่าอากาศยานก่อน # Waypoint related errors STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}มากเกิน 1 สำหรับ Waypoint STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}ใกล้กับ Waypoint อื่นมากเกินไป STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}ไม่สามารถสร้าง Waypoint ที่นี่ได้... STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}ไม่สามารถวางทุ่นลอยน้ำที่นี่ได้... STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}ไม่สามารถเปลี่ยนชื่อ Waypoint... STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}ไม่สามารถลบ Waypoint ได้... STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}ต้องลบ Waypoint ก่อน STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... มีทุ่นอยู่ระหว่างทาง STR_ERROR_BUOY_IS_IN_USE :{WHITE}... เป็นทุ่นของบริษัทอื่น # Depot related errors STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}ไม่สามารถสร้างอู่รถไฟได้ STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}บริเวณนี้ไม่สามารถสร้างอู่รถได้ STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}ไม่สามารถสร้างโรงซ่อมบำรุงรถรางได้... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}บริเวณนี้ไม่สามารถสร้างอู่เรือได้... STR_ERROR_CAN_T_RENAME_DEPOT :{WHITE}ไม่สามารถเปลี่ยนชื่ออู่ได้.. STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... ต้องจอดสนิทอยู่ในอู่ STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... ต้องจอดสนิทอยู่ในอู่ STR_ERROR_SHIP_MUST_BE_STOPPED_INSIDE_DEPOT :{WHITE}... ต้องจอดสนิทอยู่ในอู่ STR_ERROR_AIRCRAFT_MUST_BE_STOPPED_INSIDE_HANGAR :{WHITE}... ต้องหยุดในโรงเก็บ STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}สามารถปรับเปลี่ยนรถไฟได้ต่อเมื่อจอดสนิทในอู่เท่านั้น STR_ERROR_TRAIN_TOO_LONG :{WHITE}ขบวนรถยาวเกินไป STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}ไม่สามารถกลับขบวนรถได้ STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... ไม่สามารถกลับข้างของรถที่พ่วงพหุกันอยู่ได้ STR_ERROR_INCOMPATIBLE_RAIL_TYPES :ไม่สามารถระบุประเภทรถได้ STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}ไม่สามารถลบยานพาหนะได้... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}รถจักรตามหลังจะตามรถจักรคันหน้าแบบกลับข้างกันเสมอ STR_ERROR_UNABLE_TO_FIND_ROUTE_TO :{WHITE}ไม่สามารถหาทางที่จะไปยังอู่ในละแวกได้ STR_ERROR_UNABLE_TO_FIND_LOCAL_DEPOT :{WHITE}ไม่สามารถค้นหาอู่ในละแวกได้ STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :อู่ผิดประเภท # Autoreplace related errors STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} จะยาวเกินไปหลังจากแทนที่ใหม่ STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}ไม่มีกฏเกี่ยวกับการแทนที่ครอบคลุม STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(จำนวนเงินถึงขีดจำกัด) # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}เป็นไปไม่ได้ที่จะทำทางทับกัน STR_ERROR_MUST_REMOVE_SIGNALS_FIRST :{WHITE}ต้องถอดเสาอาณัติสัญญาณออกก่อน STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}ไม่มีรางรถไฟที่เหมาะสม STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}ต้องทำลายทางรถไฟทิ้งเสียก่อน STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}ถนนเป็นทางเดียวหรือถูกปิดกั้น STR_ERROR_CROSSING_DISALLOWED :{WHITE}ทางตัดเสมอระดับทางไม่อนุญาตให้ตัดผ่านทางประเภทนี้ STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}ไม่สามารถสร้างเสาอาณัติสัญญาณได้... STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}บริเวณนี้ไม่สามารถสร้างรางรถไฟได้... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}ตรงนี้ไม่สามารถลบรางรถไฟออกไปได้ STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}ไม่สามารถลบเสาอาณัติสัญญาณได้... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}ไม่สามารถแปลงเสาอาณัติสัญญาณได้... STR_ERROR_THERE_IS_NO_RAILROAD_TRACK :{WHITE}... ที่นั่นไม่มีทางรถไฟ STR_ERROR_THERE_ARE_NO_SIGNALS :{WHITE}... ที่ตรงนี้ไม่มีเสาอาณัติสัญญาณ STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}ไม่สามารถแปลงประเภททางรถไฟได้... # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}ต้องทำลายถนนเสียก่อน STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... ทางเดินรถทางเดียวไม่สามารถมีทางเชื่อมได้ STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}ตรงนี้ไม่สามารถสร้างถนนได้ STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}ตรงนี้ไม่สามารถสร้างรถรางได้ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}ตรงนี้ไม่สามารถลบถนนออกไปได้ STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}ตรงนี้ไม่สามารถลบทางรถรางออกไปได้ STR_ERROR_THERE_IS_NO_ROAD :{WHITE}... ไม่มีถนน STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}... ไม่มีทางรถราง # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}ตรงนี้ไม่สามารถสร้างคลองได้ STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}ตรงนี้ไม่สามารถสร้างประตูน้ำได้ STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}ตรงนี้ไม่สามารถวางแม่น้ำได้ STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... สร้างได้เฉพาะบนน้ำเท่านั้น STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... สร้างบนน้ำไม่ได้ STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... สร้างบนทะเลเปิดไม่ได้นะจ๊ะ STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... สร้างบนคลองไม่ได้นะจ๊ะ STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... สร้างบนแม่น้ำไม่ได้นะจ๊ะ STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}ต้องทำการถมคลองเป็นอันดับแรก STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}ไม่สามารถสร้างทางน้ำได้... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... มีต้นไม้อยู่แล้วที่นี่ STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... สภาพพื้นที่ไม่เหมาะสมกับประเภทต้นไม้ STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}ไม่สามารถปลูกต้นไม่ได้ที่นี่... # Bridge related errors STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}ตรงนี้ไม่สามารถสร้างสะพานได้... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}ต้องทำลายสะพานทิ้งเสียก่อน STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}จุดเริ่มต้นและจุดสิ้นสุดไม่สามารถเป็นจุดเดียวกันได้ STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}หัวสะพานไม่อยู่ในระดับเดียวกัน STR_ERROR_BRIDGE_TOO_LOW_FOR_TERRAIN :{WHITE}สะพานอยู่ในตำแหน่งที่ต่ำเกินไป STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}เริ่มต้นและสิ้นสุดต้องอยู่ในเส้น STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... จุดเริ่มต้นและจุดสิ้นสุดของสะพานต้องอยู่บนพื้นดิน STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... สะพานมีความยาวมากเกินไป STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}สะพานเลยออกไปนอกแผนที่ # Tunnel related errors STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}ไม่สามารถสร้างอุโมงค์ได้... STR_ERROR_SITE_UNSUITABLE_FOR_TUNNEL :{WHITE}สภาพไม่เหมาะสมสำหรับปากอุโมงค์ STR_ERROR_MUST_DEMOLISH_TUNNEL_FIRST :{WHITE}ต้องทำการทำลายอุโมงค์ก่อน STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}มีอุโมงค์อื่นอยู่ในเส้นทาง STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}อุโมงค์เลยออกไปนอกแผนที่ STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}ไม่สามารถขุดปลายทางเพื่อสร้างปากอุโมงค์อีกฝั่งได้ STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... อุโมงค์มีความยาวมากเกินไป # Object related errors STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... มีวัตถุมากเกินไป STR_ERROR_CAN_T_BUILD_OBJECT :{WHITE}ไม่สามารถสร้างวัตถุได้ STR_ERROR_OBJECT_IN_THE_WAY :{WHITE}มีบางสิ่งอยู่ในเส้นทาง STR_ERROR_COMPANY_HEADQUARTERS_IN :{WHITE}... สำนักงานของบริษัทอยู่ในเส้นทาง STR_ERROR_CAN_T_PURCHASE_THIS_LAND :{WHITE}ไม่สามารถซื้อที่ดินตรงนี้ได้... STR_ERROR_YOU_ALREADY_OWN_IT :{WHITE}... คุณเป็นเจ้าของมันอยู่แล้ว!!! # Group related errors STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}ไม่สามารถตั้งกลุ่มได้... STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}ไม่สามารถลบกลุ่มนี้ได้... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}ไม่สามารถเปลี่ยนชื่อกลุ่มได้... STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}ไม่สามารถลบยานพาหนะทั้งหมดจากกลุ่มนี้ได้... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}ไม่สามารถเพิ่มยานพาหนะเข้าสู่กลุ่มนี้ได้... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}ไม่สามารถเพิ่มยานพาหนะที่ใช้คำสั่งร่วมกันเข้ากลุ่มนี้ได้... # Generic vehicle errors STR_ERROR_TRAIN_IN_THE_WAY :{WHITE}มีขบวนรถอยู่ในทาง STR_ERROR_ROAD_VEHICLE_IN_THE_WAY :{WHITE}มีรถอยู่ในทาง STR_ERROR_SHIP_IN_THE_WAY :{WHITE}มีเรืออยู่ในเส้นทาง STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}มีอากาศยานอยู่ในทาง STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}ไม่สามารถดัดแปลงขบวนรถ... STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}ไม่สามารถดัดแปลงรถ... STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}ไม่สามารถดัดแปลงเรือ... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}ไม่สามารถดัดแปลงอากาศยาน... STR_ERROR_CAN_T_RENAME_TRAIN :{WHITE}ไม่สามารถเปลี่นนชื่อรถไฟ... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE :{WHITE}ไม่สามารถเปลี่ยนชื่อรถ... STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}ไม่สามารถเปลี่ยนชื่อเรือ... STR_ERROR_CAN_T_RENAME_AIRCRAFT :{WHITE}ไม่สามารถเปลี่ยนชื่ออากาศยาน... STR_ERROR_CAN_T_STOP_START_TRAIN :{WHITE}ไม่สามารถ หยุด/เริ่ม ขบวนรถ... STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE :{WHITE}ไม่สามารถ หยุด/เริ่ม รถ... STR_ERROR_CAN_T_STOP_START_SHIP :{WHITE}ไม่สามารถ หยุด/เริ่ม เรือ... STR_ERROR_CAN_T_STOP_START_AIRCRAFT :{WHITE}ไม่สามารถ หยุด/เริ่ม อากาศยาน... STR_ERROR_CAN_T_SEND_TRAIN_TO_DEPOT :{WHITE}ไม่สามารถส่่งรถไฟไปยังอู่ STR_ERROR_CAN_T_SEND_ROAD_VEHICLE_TO_DEPOT :{WHITE}ไม่สามารถส่่งรถไปยังโรงซ่อมบำรุง... STR_ERROR_CAN_T_SEND_SHIP_TO_DEPOT :{WHITE}ไม่สามารถส่่งเรือไปยังโรงซ่อมบำรุง... STR_ERROR_CAN_T_SEND_AIRCRAFT_TO_HANGAR :{WHITE}ไม่สามารถส่่งอากาศยานไปยังโรงซ่อมบำรุง... STR_ERROR_CAN_T_BUY_TRAIN :{WHITE}ไม่สามารถซื้อรถไฟได้... STR_ERROR_CAN_T_BUY_ROAD_VEHICLE :{WHITE}ไม่สามารถซื้อรถได้... STR_ERROR_CAN_T_BUY_SHIP :{WHITE}ไม่สามารถซื้อเรือได้... STR_ERROR_CAN_T_BUY_AIRCRAFT :{WHITE}ไม่สามารถซื้อเครื่องบินได้... STR_ERROR_CAN_T_RENAME_TRAIN_TYPE :{WHITE}ไม่สามารถเปลี่ยนชื่อประเภทของรถไฟ... STR_ERROR_CAN_T_RENAME_ROAD_VEHICLE_TYPE :{WHITE}ไม่สามารถเปลี่ยนชื่อประเภทของรถ... STR_ERROR_CAN_T_RENAME_SHIP_TYPE :{WHITE}ไม่สามารถเปลี่ยนชื่อประเภทของเรือ... STR_ERROR_CAN_T_RENAME_AIRCRAFT_TYPE :{WHITE}ไม่สามารถเปลี่ยนชื่อประเภทของอากาศยาน... STR_ERROR_CAN_T_SELL_TRAIN :{WHITE}ไม่สามารถขายรถไฟ... STR_ERROR_CAN_T_SELL_ROAD_VEHICLE :{WHITE}ไม่สามารถขายรถ... STR_ERROR_CAN_T_SELL_SHIP :{WHITE}ไม่สามารถขายเรือ... STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}ไม่สามารถขายอากาศยาน... STR_ERROR_RAIL_VEHICLE_NOT_AVAILABLE :{WHITE}ยานพาหนะไม่สามารถใช้ได้ STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE :{WHITE}ยานพาหนะไม่สามารถใช้ได้ STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}ยานพาหนะไม่สามารถใช้ได้ STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}ยานพาหนะไม่สามารถใช้ได้ STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}ขณะนี้มียานยนต์มากเกินไปแล้วในเกม STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}ไม่สามารถเปลี่ยนระยะเวลาการซ่อมบำรุงได้... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... ยานพาหนะถูกทำลาย STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL :{WHITE}ไม่มียานพาหานะให้เลือก STR_ERROR_NO_VEHICLES_AVAILABLE_AT_ALL_EXPLANATION :{WHITE}เปลี่ยนการกำหนดค่าสำหรับ NewGRF STR_ERROR_NO_VEHICLES_AVAILABLE_YET :{WHITE}ยังไม่มียานพาหานะให้เลือก STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}เริ่มเกมหลังจาก {DATE_SHORT} หรือเลือกใช้งาน NewGRF ของยานพาหนะที่จัดเตรียมไว้ก่อนหน้านี้ # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}ไม่สามารถสั่งให้รถไฟวิ่งผ่านเสาอาณัติสัญญาณที่แสดงท่า "ห้าม"... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}ไม่สามารถกลับทิศขบวนรถไฟได้... STR_ERROR_TRAIN_START_NO_POWER :ขบวนรถไม่ได้รับการจ่ายพลังงานไฟฟ้า STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}ไม่สามารถกลับรถได้... STR_ERROR_AIRCRAFT_IS_IN_FLIGHT :{WHITE}อากาศยานอยู่ระหว่างทำการบิน # Order related errors STR_ERROR_NO_MORE_SPACE_FOR_ORDERS :{WHITE}ไม่มีพื้นที่ว่างสำหรับเพิ่มคำสั่ง STR_ERROR_TOO_MANY_ORDERS :{WHITE}ได้รับคำสั่งมากเกินไป STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}ไม่สามารถเพิ่มเติมคำสั่งได้แล้ว... STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}ไม่สามารถลบคำสั่งได้... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}ไม่สามารถปรับปรุงคำสั่งได้... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}ไม่สามารถเคลื่อนย้ายคำสั่งได้... STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}ไม่สามารถข้ามคำสั่งปัจจุบันได้... STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}ไม่สามารถข้ามไปยังคำสั่งที่เลือกไว้ได้.. STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... พาหนะไม่สามารถไปยังสถานีทั้งหมดได้ STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... ยานพาหนะไม่สามารถไปยังสถานีนั้นได้ STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... ยานพาหนะใช้คำสั่งเหมือนกับยานพาหานะนี้ไม่สามารถไปยังสถานีบางสถานีได้ STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}ไม่สามารถใช้รายการสถานที่ร่วมกันได้ STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}ไม่สามารถหยุดการ Share คำสั่งในรายการ STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}ไม่สามารถคัดลอกรายการสถานที่ได้ STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... ไกลจากจุดก่อนหน้านี้มากเกินไป STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... อากาศยานมีพิสัยการบินไม่พอ # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}ไม่สามารถจัดตารางเวลาให้ยานพาหนะนี้ได้... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}พาหนะสามารถหยุดรอได้เฉพาะที่สถานี STR_ERROR_TIMETABLE_NOT_STOPPING_HERE :{WHITE}พาหนะนี้ไม่สามารถหยุดที่่่่สถานีนี้ได้ # Sign related errors STR_ERROR_TOO_MANY_SIGNS :{WHITE}... มีป้ายมากเกินไป STR_ERROR_CAN_T_PLACE_SIGN_HERE :{WHITE}ไม่สามารถวางป้่ายที่นี่ได้... STR_ERROR_CAN_T_CHANGE_SIGN_NAME :{WHITE}ไม่สามารถเปลี่ยนชื่อป้ายได้... STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}ไม่สามารถลบป้ายได้... # Translatable comment for OpenTTD's desktop shortcut STR_DESKTOP_SHORTCUT_COMMENT :เป็นเกมวางแผนและจำลอง ซึ่งมีต้นฉบับมาจาก Transport Tycoon Deluxe # Translatable descriptions in media/baseset/*.ob* files STR_BASEGRAPHICS_DOS_DESCRIPTION :กราฟฟิกต้นตำหรับของ Transport Tycoon Deluxe DOS edition STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :กราฟฟิกต้นตำหรับของ Transport Tycoon Deluxe DOS (German) edition STR_BASEGRAPHICS_WIN_DESCRIPTION :กราฟฟิกต้ำตำหรับของ Transport Tycoon Deluxe Windows edition STR_BASESOUNDS_DOS_DESCRIPTION :เสียงต้นตำหรับของ Transport Tycoon Deluxe DOS edition STR_BASESOUNDS_WIN_DESCRIPTION :เสียงต้นตำหรับของ Transport Tycoon Deluxe Windows edition STR_BASESOUNDS_NONE_DESCRIPTION :ชุดเสียงแบบไร้เสียง STR_BASEMUSIC_WIN_DESCRIPTION :เพลงต้นตำหรับชอง Transport Tycoon Deluxe Windows edition STR_BASEMUSIC_NONE_DESCRIPTION :ชุดเพลงประกอบแบบไม่มีเสียงเพลง ##id 0x2000 # Town building names STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1 :ตึกสูง STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_1 :อาคารสำนักงาน STR_TOWN_BUILDING_NAME_SMALL_BLOCK_OF_FLATS_1 :แฟลต STR_TOWN_BUILDING_NAME_CHURCH_1 :โบส์ถ STR_TOWN_BUILDING_NAME_LARGE_OFFICE_BLOCK_1 :อาคารสำนักงานขนาดใหญ่ STR_TOWN_BUILDING_NAME_TOWN_HOUSES_1 :ทาวน์เฮ้าส์ STR_TOWN_BUILDING_NAME_HOTEL_1 :โรงแรม STR_TOWN_BUILDING_NAME_STATUE_1 :อนุสาวรีย์ STR_TOWN_BUILDING_NAME_FOUNTAIN_1 :น้ำพุ STR_TOWN_BUILDING_NAME_PARK_1 :สวนสาธารณะ STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_2 :อาคารสำนักงาน STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_1 :ร้านค้าและสำนักงาน STR_TOWN_BUILDING_NAME_MODERN_OFFICE_BUILDING_1 :อาคารสำนักงานสมัยใหม่ STR_TOWN_BUILDING_NAME_WAREHOUSE_1 :โกดัง STR_TOWN_BUILDING_NAME_OFFICE_BLOCK_3 :อาคารสำนักงาน STR_TOWN_BUILDING_NAME_STADIUM_1 :สนามกีฬา STR_TOWN_BUILDING_NAME_OLD_HOUSES_1 :บ้านโบราณ STR_TOWN_BUILDING_NAME_COTTAGES_1 :กระท่อม STR_TOWN_BUILDING_NAME_HOUSES_1 :บ้าน STR_TOWN_BUILDING_NAME_FLATS_1 :แฟลต STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_2 :อาคารสูง STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_2 :ร้านค้าและสำนักงาน STR_TOWN_BUILDING_NAME_SHOPS_AND_OFFICES_3 :ร้านค้าและสำนักงาน STR_TOWN_BUILDING_NAME_THEATER_1 :โรงภาพยนตร์ STR_TOWN_BUILDING_NAME_STADIUM_2 :สนามกีฬา STR_TOWN_BUILDING_NAME_OFFICES_1 :สำนักงาน STR_TOWN_BUILDING_NAME_HOUSES_2 :บ้าน STR_TOWN_BUILDING_NAME_CINEMA_1 :โรงภาพยนตร์ STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1 :ห้างสรรพสินค้า STR_TOWN_BUILDING_NAME_IGLOO_1 :อิกลู STR_TOWN_BUILDING_NAME_TEPEES_1 :กระโจม STR_TOWN_BUILDING_NAME_TEAPOT_HOUSE_1 :บ้านพักตากอากาศ STR_TOWN_BUILDING_NAME_PIGGY_BANK_1 :ธนาคารเล็กๆ ##id 0x4800 # industry names STR_INDUSTRY_NAME_COAL_MINE :เหมือนถ่านหิน STR_INDUSTRY_NAME_POWER_STATION :โรงผลิตไฟฟ้า STR_INDUSTRY_NAME_SAWMILL :โรงเลื่อย STR_INDUSTRY_NAME_FOREST :ป่าไม้ STR_INDUSTRY_NAME_OIL_REFINERY :โรงกลั่นน้ำมัน STR_INDUSTRY_NAME_OIL_RIG :แท่นขุดเจาะน้ำมันกลางทะเล STR_INDUSTRY_NAME_FACTORY :โรงงานแปรรูป STR_INDUSTRY_NAME_PRINTING_WORKS :โรงผลิตกระดาษ STR_INDUSTRY_NAME_STEEL_MILL :โรงงานเหล็กกล้า STR_INDUSTRY_NAME_FARM :ฟาร์ม STR_INDUSTRY_NAME_COPPER_ORE_MINE :เหมืองแร่ทองแดง STR_INDUSTRY_NAME_OIL_WELLS :แท่นขุดเจาะน้ำมัน STR_INDUSTRY_NAME_BANK :ธนาคาร STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :โรงงานแปรรูปอาหาร STR_INDUSTRY_NAME_PAPER_MILL :โรงงานกระดาษ STR_INDUSTRY_NAME_GOLD_MINE :เหมืองทองคำ STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :ธนาคาร STR_INDUSTRY_NAME_DIAMOND_MINE :เหมืองเพชร STR_INDUSTRY_NAME_IRON_ORE_MINE :เหมืองแร่เหล็ก STR_INDUSTRY_NAME_FRUIT_PLANTATION :สวนอินทผาลัม STR_INDUSTRY_NAME_RUBBER_PLANTATION :สวนยาง STR_INDUSTRY_NAME_WATER_SUPPLY :โรงทำน้ำสะอาด STR_INDUSTRY_NAME_WATER_TOWER :หอประปา STR_INDUSTRY_NAME_FACTORY_2 :โรงงาน STR_INDUSTRY_NAME_FARM_2 :ฟาร์ม STR_INDUSTRY_NAME_LUMBER_MILL :โรงแปรรูปไม้ STR_INDUSTRY_NAME_COTTON_CANDY_FOREST :ป่าสายไหม STR_INDUSTRY_NAME_CANDY_FACTORY :โรงงานขนมหวาน STR_INDUSTRY_NAME_BATTERY_FARM :ฟาร์มพลังงาน STR_INDUSTRY_NAME_COLA_WELLS :แท่นขุดเจาะโคล่า STR_INDUSTRY_NAME_TOY_SHOP :ร้านค้าของเล่น STR_INDUSTRY_NAME_TOY_FACTORY :โรงงานของเล่น STR_INDUSTRY_NAME_PLASTIC_FOUNTAINS :น้ำพุพลาสติก STR_INDUSTRY_NAME_FIZZY_DRINK_FACTORY :โรงงานผลิตน้ำอัดลม STR_INDUSTRY_NAME_BUBBLE_GENERATOR :เครื่องกำเนิดฟองลูกโป่ง STR_INDUSTRY_NAME_TOFFEE_QUARRY :บ่อทอฟฟี่ STR_INDUSTRY_NAME_SUGAR_MINE :เหมืองน้ำตาล ############ WARNING, using range 0x6000 for strings that are stored in the savegame ############ These strings may never get a new id, or savegames will break! ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :ไม่มีชื่อ STR_SV_TRAIN_NAME :รถไฟ {COMMA} STR_SV_ROAD_VEHICLE_NAME :พาหนะทางบก {COMMA} STR_SV_SHIP_NAME :พาหนะทางน้ำ {COMMA} STR_SV_AIRCRAFT_NAME :อากาศยาน {COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :{STRING} เหนือ STR_SV_STNAME_SOUTH :{STRING} ใต้ STR_SV_STNAME_EAST :{STRING} ตะวันออก STR_SV_STNAME_WEST :{STRING} ตะวันตก STR_SV_STNAME_CENTRAL :{STRING} กลาง STR_SV_STNAME_TRANSFER :จุดขนถ่าย {STRING} STR_SV_STNAME_HALT :ป้ายหยุด {STRING} STR_SV_STNAME_VALLEY :หมู่บ้าน {STRING} STR_SV_STNAME_HEIGHTS :เนิน {STRING} STR_SV_STNAME_WOODS :ป่า {STRING} STR_SV_STNAME_LAKESIDE :ชายหาด {STRING} STR_SV_STNAME_EXCHANGE :จุดแลกเปลี่ยน {STRING} STR_SV_STNAME_AIRPORT :ท่าอากาศยาน {STRING} STR_SV_STNAME_OILFIELD :แท่นขุดเจาะ {STRING} STR_SV_STNAME_MINES :เหมือง {STRING} STR_SV_STNAME_DOCKS :ท่าเทียบเรือ {STRING} STR_SV_STNAME_BUOY :{STRING} STR_SV_STNAME_WAYPOINT :{STRING} ##id 0x6020 STR_SV_STNAME_ANNEXE :ชานเมือง {STRING} STR_SV_STNAME_SIDINGS :ในเมือง {STRING} STR_SV_STNAME_BRANCH :ขนส่งสาขา {STRING} STR_SV_STNAME_UPPER :{STRING} ตอนบน STR_SV_STNAME_LOWER :{STRING} ตอนล่าง STR_SV_STNAME_HELIPORT :ลานจอด ฮ {STRING} STR_SV_STNAME_FOREST :ป่าไม้ {STRING} STR_SV_STNAME_FALLBACK :จุดขนส่งเมือง {STRING} #{NUM} ############ end of savegame specific region! ##id 0x8000 # Vehicle names STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_250_DIESEL :MJS 250 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_CHOO_CHOO :Ploddyphut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_CHOO_CHOO :Powernaut Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MIGHTYMOVER_CHOO_CHOO :MightyMover Choo-Choo STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_PLODDYPHUT_DIESEL :Ploddyphut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_POWERNAUT_DIESEL :Powernaut Diesel STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_WILLS_2_8_0_STEAM :Wills 2-8-0 (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CHANEY_JUBILEE_STEAM :Chaney 'Jubilee' (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_GINZU_A4_STEAM :Ginzu 'A4' (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_8P_STEAM :SH '8P' (Steam) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MANLEY_MOREL_DMU_DIESEL :Manley-Morel DMU (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_DASH_DIESEL :'Dash' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_HENDRY_25_DIESEL :SH/Hendry '25' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_UU_37_DIESEL :UU '37' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_FLOSS_47_DIESEL :Floss '47' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_4000_DIESEL :CS 4000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CS_2400_DIESEL :CS 2400 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_CENTENNIAL_DIESEL :Centennial (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_KELLING_3100_DIESEL :Kelling 3100 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_TURNER_TURBO_DIESEL :Turner Turbo (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_MJS_1000_DIESEL :MJS 1000 (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_125_DIESEL :SH '125' (Diesel) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_30_ELECTRIC :SH '30' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_SH_40_ELECTRIC :SH '40' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_T_I_M_ELECTRIC :'T.I.M.' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_RAIL_ASIASTAR_ELECTRIC :'AsiaStar' (Electric) STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PASSENGER_CAR :Passenger Carriage STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_MAIL_VAN :Mail Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :รถบรรทุกถ่านหิน STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_OIL_TANKER :Oil Tanker STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_LIVESTOCK_VAN :Livestock Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GOODS_VAN :Goods Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_GRAIN_HOPPER :Grain Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WOOD_TRUCK :รถบรรทุกซุง STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_IRON_ORE_HOPPER :Iron Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_STEEL_TRUCK :รถบรรทุกเหล็กกล้า STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_ARMORED_VAN :Armoured Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FOOD_VAN :Food Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PAPER_TRUCK :รถบรรทุกกระดาษ STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COPPER_ORE_HOPPER :Copper Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_WATER_TANKER :ถังเก็บน้ำ STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :รถบรรทุกผลไม้ STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_RUBBER_TRUCK :รถบรรทุกยางพารา STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_SUGAR_TRUCK :รถบรรทุกน้ำตาล STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOFFEE_HOPPER :Toffee Hopper STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BUBBLE_VAN :Bubble Van STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COLA_TANKER :ถังเก็บโคล่า STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_CANDY_VAN :รถขนส่งขนม STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_TOY_VAN :รถขนส่งของเล่น STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_BATTERY_TRUCK :Battery Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_PLASTIC_TRUCK :Plastic Truck STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_X2001_ELECTRIC :'X2001' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_MILLENNIUM_Z1_ELECTRIC :'Millennium Z1' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MONORAIL_WIZZOWOW_Z99 :Wizzowow Z99 STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PASSENGER_CAR :Passenger Carriage STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_MAIL_VAN :รถขนส่งไปรษณีย์ STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COAL_CAR :Coal Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_OIL_TANKER :Oil Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_LIVESTOCK_VAN :Livestock Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GOODS_VAN :Goods Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_GRAIN_HOPPER :Grain Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WOOD_TRUCK :Wood Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_IRON_ORE_HOPPER :Iron Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_STEEL_TRUCK :รถบรรทุกเหล็กกล้า STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_ARMORED_VAN :รถขนส่งหุ้มเกราะ STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FOOD_VAN :รถขนส่งอาหาร STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PAPER_TRUCK :Paper Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COPPER_ORE_HOPPER :Copper Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_WATER_TANKER :Water Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FRUIT_TRUCK :Fruit Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_RUBBER_TRUCK :Rubber Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_SUGAR_TRUCK :Sugar Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COTTON_CANDY_HOPPER :Candyfloss Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOFFEE_HOPPER :Toffee Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BUBBLE_VAN :รถขนส่งฟอง STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_COLA_TANKER :Cola Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_CANDY_VAN :Sweet Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_TOY_VAN :Toy Van STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_BATTERY_TRUCK :Battery Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_FIZZY_DRINK_TRUCK :Fizzy Drink Truck STR_VEHICLE_NAME_TRAIN_WAGON_MONORAIL_PLASTIC_TRUCK :Plastic Truck STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV1_LEVIATHAN_ELECTRIC :Lev1 'Leviathan' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV2_CYCLOPS_ELECTRIC :Lev2 'Cyclops' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV3_PEGASUS_ELECTRIC :Lev3 'Pegasus' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_LEV4_CHIMAERA_ELECTRIC :Lev4 'Chimaera' (Electric) STR_VEHICLE_NAME_TRAIN_ENGINE_MAGLEV_WIZZOWOW_ROCKETEER :Wizzowow Rocketeer STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PASSENGER_CAR :Passenger Carriage STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_MAIL_VAN :Mail Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COAL_CAR :Coal Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_OIL_TANKER :Oil Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_LIVESTOCK_VAN :Livestock Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GOODS_VAN :Goods Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_GRAIN_HOPPER :Grain Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WOOD_TRUCK :Wood Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_IRON_ORE_HOPPER :Iron Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_STEEL_TRUCK :รถบรรทุกเหล็กกล้า STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_ARMORED_VAN :Armoured Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FOOD_VAN :Food Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PAPER_TRUCK :Paper Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COPPER_ORE_HOPPER :Copper Ore Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_WATER_TANKER :Water Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FRUIT_TRUCK :Fruit Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_RUBBER_TRUCK :Rubber Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_SUGAR_TRUCK :Sugar Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COTTON_CANDY_HOPPER :Candyfloss Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOFFEE_HOPPER :Toffee Hopper STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :Bubble Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_COLA_TANKER :Cola Tanker STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_CANDY_VAN :Sweet Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_TOY_VAN :Toy Van STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BATTERY_TRUCK :Battery Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_FIZZY_DRINK_TRUCK :Fizzy Drink Truck STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_PLASTIC_TRUCK :Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_REGAL_BUS :MPS Regal Bus STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_LEOPARD_BUS :Hereford Leopard Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_BUS :Foster Bus STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_MKII_SUPERBUS :Foster MkII Superbus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKI_BUS :Ploddyphut MkI Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKII_BUS :Ploddyphut MkII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :Ploddyphut MkIII Bus STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_COAL_TRUCK :Balogh Coal Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COAL_TRUCK :Uhl Coal Truck STR_VEHICLE_NAME_ROAD_VEHICLE_DW_COAL_TRUCK :DW Coal Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_MAIL_TRUCK :MPS Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_REYNARD_MAIL_TRUCK :Reynard Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_MAIL_TRUCK :Perry Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_MAIL_TRUCK :MightyMover Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_MAIL_TRUCK :Powernaught Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_MAIL_TRUCK :Wizzowow Mail Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_OIL_TANKER :Witcombe Oil Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_OIL_TANKER :Foster Oil Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_OIL_TANKER :Perry Oil Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_TALBOTT_LIVESTOCK_VAN :Talbott Livestock Van STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_LIVESTOCK_VAN :Uhl Livestock Van STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_LIVESTOCK_VAN :Foster Livestock Van STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_GOODS_TRUCK :Balogh Goods Truck STR_VEHICLE_NAME_ROAD_VEHICLE_CRAIGHEAD_GOODS_TRUCK :Craighead Goods Truck STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GOODS_TRUCK :Goss Goods Truck STR_VEHICLE_NAME_ROAD_VEHICLE_HEREFORD_GRAIN_TRUCK :Hereford Grain Truck STR_VEHICLE_NAME_ROAD_VEHICLE_THOMAS_GRAIN_TRUCK :Thomas Grain Truck STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_GRAIN_TRUCK :Goss Grain Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WITCOMBE_WOOD_TRUCK :Witcombe Wood Truck STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_WOOD_TRUCK :รถบรรทุกไม้รุ่นฟอสเตอร์ STR_VEHICLE_NAME_ROAD_VEHICLE_MORELAND_WOOD_TRUCK :รถบรรทุกไม้รุ่นมัวร์แลนด์ STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_IRON_ORE_TRUCK :รถบรรทุกแร่เหล็กรุ่นเอ็มพีเอส STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_IRON_ORE_TRUCK :รถบรรทุกแร่เหล็กรุ่นยูเอชแอล STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_IRON_ORE_TRUCK :รถบรรทุกแร่เหล็กรุ่นชิปปี้ STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_STEEL_TRUCK :รถบรรทุกเหล็กกล้ารุ่นบัลล๊อก STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_STEEL_TRUCK :รถบรรทุกเหล็กกล้ารุ่นยูเอชแอล STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_STEEL_TRUCK :รถบรรทุกเหล็กกล้ารุ่นเคลลิ่ง STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_ARMORED_TRUCK :รถหุ้มเกราะรุ่นบัลล๊อก STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_ARMORED_TRUCK :รถหุ้มเกราะรุ่นยูเอชแอล STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_ARMORED_TRUCK :Foster Armoured Truck STR_VEHICLE_NAME_ROAD_VEHICLE_FOSTER_FOOD_VAN :Foster Food Van STR_VEHICLE_NAME_ROAD_VEHICLE_PERRY_FOOD_VAN :Perry Food Van STR_VEHICLE_NAME_ROAD_VEHICLE_CHIPPY_FOOD_VAN :Chippy Food Van STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_PAPER_TRUCK :Uhl Paper Truck STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_PAPER_TRUCK :Balogh Paper Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_PAPER_TRUCK :MPS Paper Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_COPPER_ORE_TRUCK :MPS Copper Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_COPPER_ORE_TRUCK :Uhl Copper Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_GOSS_COPPER_ORE_TRUCK :Goss Copper Ore Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_WATER_TANKER :Uhl Water Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_WATER_TANKER :Balogh Water Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_MPS_WATER_TANKER :MPS Water Tanker STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_FRUIT_TRUCK :Balogh Fruit Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_FRUIT_TRUCK :Uhl Fruit Truck STR_VEHICLE_NAME_ROAD_VEHICLE_KELLING_FRUIT_TRUCK :Kelling Fruit Truck STR_VEHICLE_NAME_ROAD_VEHICLE_BALOGH_RUBBER_TRUCK :Balogh Rubber Truck STR_VEHICLE_NAME_ROAD_VEHICLE_UHL_RUBBER_TRUCK :Uhl Rubber Truck STR_VEHICLE_NAME_ROAD_VEHICLE_RMT_RUBBER_TRUCK :RMT Rubber Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_SUGAR_TRUCK :MightyMover Sugar Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_SUGAR_TRUCK :Powernaught Sugar Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_SUGAR_TRUCK :Wizzowow Sugar Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COLA_TRUCK :MightyMover Cola Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COLA_TRUCK :Powernaught Cola Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COLA_TRUCK :Wizzowow Cola Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_COTTON_CANDY :MightyMover Candyfloss Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_COTTON_CANDY :Powernaught Candyfloss Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_COTTON_CANDY_TRUCK :Wizzowow Candyfloss Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOFFEE_TRUCK :MightyMover Toffee Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOFFEE_TRUCK :Powernaught Toffee Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOFFEE_TRUCK :Wizzowow Toffee Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_TOY_VAN :MightyMover Toy Van STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_TOY_VAN :Powernaught Toy Van STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_TOY_VAN :Wizzowow Toy Van STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_CANDY_TRUCK :MightyMover Sweet Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_CANDY_TRUCK :Powernaught Sweet Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_CANDY_TRUCK :Wizzowow Sweet Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BATTERY_TRUCK :MightyMover Battery Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BATTERY_TRUCK :Powernaught Battery Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BATTERY_TRUCK :Wizzowow Battery Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_FIZZY_DRINK :MightyMover Fizzy Drink Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_FIZZY_DRINK :Powernaught Fizzy Drink Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_FIZZY_DRINK_TRUCK :Wizzowow Fizzy Drink Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_PLASTIC_TRUCK :MightyMover Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_PLASTIC_TRUCK :Powernaught Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_PLASTIC_TRUCK :Wizzowow Plastic Truck STR_VEHICLE_NAME_ROAD_VEHICLE_MIGHTYMOVER_BUBBLE_TRUCK :MightyMover Bubble Truck STR_VEHICLE_NAME_ROAD_VEHICLE_POWERNAUGHT_BUBBLE_TRUCK :Powernaught Bubble Truck STR_VEHICLE_NAME_ROAD_VEHICLE_WIZZOWOW_BUBBLE_TRUCK :Wizzowow Bubble Truck STR_VEHICLE_NAME_SHIP_MPS_OIL_TANKER :MPS Oil Tanker STR_VEHICLE_NAME_SHIP_CS_INC_OIL_TANKER :CS-Inc. Oil Tanker STR_VEHICLE_NAME_SHIP_MPS_PASSENGER_FERRY :MPS Passenger Ferry STR_VEHICLE_NAME_SHIP_FFP_PASSENGER_FERRY :FFP Passenger Ferry STR_VEHICLE_NAME_SHIP_BAKEWELL_300_HOVERCRAFT :Bakewell 300 Hovercraft STR_VEHICLE_NAME_SHIP_CHUGGER_CHUG_PASSENGER :Chugger-Chug Passenger Ferry STR_VEHICLE_NAME_SHIP_SHIVERSHAKE_PASSENGER_FERRY :Shivershake Passenger Ferry STR_VEHICLE_NAME_SHIP_YATE_CARGO_SHIP :Yate Cargo ship STR_VEHICLE_NAME_SHIP_BAKEWELL_CARGO_SHIP :Bakewell Cargo ship STR_VEHICLE_NAME_SHIP_MIGHTYMOVER_CARGO_SHIP :MightyMover Cargo ship STR_VEHICLE_NAME_SHIP_POWERNAUT_CARGO_SHIP :Powernaut Cargo ship STR_VEHICLE_NAME_AIRCRAFT_SAMPSON_U52 :Sampson U52 STR_VEHICLE_NAME_AIRCRAFT_COLEMAN_COUNT :Coleman Count STR_VEHICLE_NAME_AIRCRAFT_FFP_DART :FFP Dart STR_VEHICLE_NAME_AIRCRAFT_YATE_HAUGAN :Yate Haugan STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :Bakewell Cotswald LB-3 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_8 :Bakewell Luckett LB-8 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :Bakewell Luckett LB-9 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :Bakewell Luckett LB80 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_10 :Bakewell Luckett LB-10 STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :Bakewell Luckett LB-11 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAC_1_11 :Yate Aerospace YAC 1-11 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_100 :Darwin 100 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_200 :Darwin 200 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_300 :Darwin 300 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_400 :Darwin 400 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_500 :Darwin 500 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :Darwin 600 STR_VEHICLE_NAME_AIRCRAFT_GURU_GALAXY :Guru Galaxy STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A21 :Airtaxi A21 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A31 :Airtaxi A31 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A32 :Airtaxi A32 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A33 :Airtaxi A33 STR_VEHICLE_NAME_AIRCRAFT_YATE_AEROSPACE_YAE46 :Yate Aerospace YAe46 STR_VEHICLE_NAME_AIRCRAFT_DINGER_100 :Dinger 100 STR_VEHICLE_NAME_AIRCRAFT_AIRTAXI_A34_1000 :AirTaxi A34-1000 STR_VEHICLE_NAME_AIRCRAFT_YATE_Z_SHUTTLE :Yate Z-Shuttle STR_VEHICLE_NAME_AIRCRAFT_KELLING_K1 :Kelling K1 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K6 :Kelling K6 STR_VEHICLE_NAME_AIRCRAFT_KELLING_K7 :Kelling K7 STR_VEHICLE_NAME_AIRCRAFT_DARWIN_700 :Darwin 700 STR_VEHICLE_NAME_AIRCRAFT_FFP_HYPERDART_2 :FFP Hyperdart 2 STR_VEHICLE_NAME_AIRCRAFT_DINGER_200 :Dinger 200 STR_VEHICLE_NAME_AIRCRAFT_DINGER_1000 :Dinger 1000 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_100 :Ploddyphut 100 STR_VEHICLE_NAME_AIRCRAFT_PLODDYPHUT_500 :Ploddyphut 500 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_X1 :Flashbang X1 STR_VEHICLE_NAME_AIRCRAFT_JUGGERPLANE_M1 :Juggerplane M1 STR_VEHICLE_NAME_AIRCRAFT_FLASHBANG_WIZZER :Flashbang Wizzer STR_VEHICLE_NAME_AIRCRAFT_TRICARIO_HELICOPTER :Tricario Helicopter STR_VEHICLE_NAME_AIRCRAFT_GURU_X2_HELICOPTER :Guru X2 Helicopter STR_VEHICLE_NAME_AIRCRAFT_POWERNAUT_HELICOPTER :Powernaut Helicopter ##id 0x8800 # Formatting of some strings STR_FORMAT_DATE_TINY :{STRING}-{STRING}-{NUM} STR_FORMAT_DATE_SHORT :{STRING} {NUM} STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} STR_FORMAT_DATE_ISO :{2:NUM}-{1:STRING}-{0:STRING} STR_FORMAT_BUOY_NAME :ทุ่น {TOWN} STR_FORMAT_BUOY_NAME_SERIAL :ทุ่น {TOWN} #{COMMA} STR_FORMAT_COMPANY_NUM :(บริษัท {COMMA}) STR_FORMAT_GROUP_NAME :กลุ่ม {COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :จุดตรวจ {TOWN} STR_FORMAT_WAYPOINT_NAME_SERIAL :จุดตรวจ {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_TRAIN :โรงซ่อมบำรุงรถไฟ {TOWN} STR_FORMAT_DEPOT_NAME_TRAIN_SERIAL :โรงซ่อมบำรุงรถไฟ {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE :โรงซ่อมบำรุงรถ {TOWN} STR_FORMAT_DEPOT_NAME_ROAD_VEHICLE_SERIAL :โรงซ่อมบำรุงรถ {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_SHIP :อู่เรือ {TOWN} STR_FORMAT_DEPOT_NAME_SHIP_SERIAL :อู่เรือ {TOWN} #{COMMA} STR_FORMAT_DEPOT_NAME_AIRCRAFT :โรงเก็บเครื่องบิน {STATION} STR_UNKNOWN_STATION :ไม่ทราบสถานี STR_DEFAULT_SIGN_NAME :ป้าย STR_COMPANY_SOMEONE :บางคน STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING} STR_SAVEGAME_NAME_SPECTATOR :ผู้ชม, {1:STRING} # Viewport strings STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) STR_VIEWPORT_TOWN :{WHITE}{TOWN} STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} STR_VIEWPORT_WAYPOINT :{WAYPOINT} STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} # Simple strings to get specific types of data STR_COMPANY_NAME :{COMPANY} STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} STR_DEPOT_NAME :{DEPOT} STR_ENGINE_NAME :{ENGINE} STR_GROUP_NAME :{GROUP} STR_INDUSTRY_NAME :{INDUSTRY} STR_PRESIDENT_NAME :{PRESIDENT_NAME} STR_SIGN_NAME :{SIGN} STR_STATION_NAME :{STATION} STR_TOWN_NAME :{TOWN} STR_VEHICLE_NAME :{VEHICLE} STR_WAYPOINT_NAME :{WAYPOINT} STR_JUST_CARGO :{CARGO_LONG} STR_JUST_CHECKMARK :{CHECKMARK} STR_JUST_COMMA :{COMMA} STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} STR_JUST_CARGO_LIST :{CARGO_LIST} STR_JUST_INT :{NUM} STR_JUST_DATE_TINY :{DATE_TINY} STR_JUST_DATE_SHORT :{DATE_SHORT} STR_JUST_DATE_LONG :{DATE_LONG} STR_JUST_DATE_ISO :{DATE_ISO} STR_JUST_STRING :{STRING} STR_JUST_STRING_STRING :{STRING}{STRING} STR_JUST_RAW_STRING :{STRING} STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} # Slightly 'raw' stringcodes with colour or size STR_BLACK_COMMA :{BLACK}{COMMA} STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} STR_TINY_COMMA :{TINY_FONT}{COMMA} STR_BLUE_COMMA :{BLUE}{COMMA} STR_RED_COMMA :{RED}{COMMA} STR_WHITE_COMMA :{WHITE}{COMMA} STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} STR_COMPANY_MONEY :{WHITE} {CURRENCY_LONG} STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} STR_SHORT_DATE :{WHITE}{DATE_TINY} STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} STR_TINY_GROUP :{TINY_FONT}{GROUP} STR_BLACK_INT :{BLACK}{NUM} STR_ORANGE_INT :{ORANGE}{NUM} STR_WHITE_SIGN :{WHITE}{SIGN} STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} STR_BLACK_STRING :{BLACK}{STRING} STR_BLACK_RAW_STRING :{BLACK}{STRING} STR_ORANGE_STRING :{ORANGE}{STRING} STR_LTBLUE_STRING :{LTBLUE}{STRING} STR_WHITE_STRING :{WHITE}{STRING} STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING}{WHITE} STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING}{LTBLUE} STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} STR_BLACK_1 :{BLACK}1 STR_BLACK_2 :{BLACK}2 STR_BLACK_3 :{BLACK}3 STR_BLACK_4 :{BLACK}4 STR_BLACK_5 :{BLACK}5 STR_BLACK_6 :{BLACK}6 STR_BLACK_7 :{BLACK}7 STR_TRAIN :{BLACK}{TRAIN} STR_BUS :{BLACK}{BUS} STR_LORRY :{BLACK}{LORRY} STR_PLANE :{BLACK}{PLANE} STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) openttd-1.5.3/src/lang/latvian.txt0000644000000000000000000151127012627373443015624 0ustar rootroot##name Latvian ##ownname Latviešu ##isocode lv_LV ##plural 3 ##textdir ltr ##digitsep . ##digitsepcur . ##decimalsep , ##winlangid 0x0426 ##grflangid 0x2a ##gender m f ##case kas # $Id: latvian.txt 27353 2015-07-31 17:46:09Z rubidium $ # 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 . ##id 0x0000 STR_NULL : STR_EMPTY : STR_UNDEFINED :(nedefinēta virkne) STR_JUST_NOTHING :Neko # Cargo related strings # Plural cargo name STR_CARGO_PLURAL_NOTHING : STR_CARGO_PLURAL_PASSENGERS :Pasažieri STR_CARGO_PLURAL_COAL :Ogles STR_CARGO_PLURAL_MAIL :Pasts STR_CARGO_PLURAL_OIL :Nafta STR_CARGO_PLURAL_LIVESTOCK :Mājlopi STR_CARGO_PLURAL_GOODS :Preces STR_CARGO_PLURAL_GRAIN :Graudi STR_CARGO_PLURAL_WOOD :Koksne STR_CARGO_PLURAL_IRON_ORE :Dzelzsrūda STR_CARGO_PLURAL_STEEL :Tērauds STR_CARGO_PLURAL_VALUABLES :Vērtslietas STR_CARGO_PLURAL_COPPER_ORE :Vara rūda STR_CARGO_PLURAL_MAIZE :Kukurūza STR_CARGO_PLURAL_FRUIT :Augļi STR_CARGO_PLURAL_DIAMONDS :Dimanti STR_CARGO_PLURAL_FOOD :Pārtika STR_CARGO_PLURAL_PAPER :Papīrs STR_CARGO_PLURAL_GOLD :Zelts STR_CARGO_PLURAL_WATER :Ūdens STR_CARGO_PLURAL_WHEAT :Kvieši STR_CARGO_PLURAL_RUBBER :Kaučuks STR_CARGO_PLURAL_SUGAR :Cukurs STR_CARGO_PLURAL_TOYS :Rotaļlietas STR_CARGO_PLURAL_CANDY :Saldumi STR_CARGO_PLURAL_COLA :Kola STR_CARGO_PLURAL_COTTON_CANDY :Cukurvate STR_CARGO_PLURAL_BUBBLES :Burbuļi STR_CARGO_PLURAL_TOFFEE :Īriss STR_CARGO_PLURAL_BATTERIES :Baterijas STR_CARGO_PLURAL_PLASTIC :Plastmasas STR_CARGO_PLURAL_FIZZY_DRINKS :Limonādes # Singular cargo name STR_CARGO_SINGULAR_NOTHING : STR_CARGO_SINGULAR_PASSENGER :Pasažieris STR_CARGO_SINGULAR_COAL :Ogles STR_CARGO_SINGULAR_MAIL :Pasts STR_CARGO_SINGULAR_OIL :Nafta STR_CARGO_SINGULAR_LIVESTOCK :Mājlopi STR_CARGO_SINGULAR_GOODS :Preces STR_CARGO_SINGULAR_GRAIN :Graudi STR_CARGO_SINGULAR_WOOD :Koksne STR_CARGO_SINGULAR_IRON_ORE :Dzelzsrūda STR_CARGO_SINGULAR_STEEL :Tērauds STR_CARGO_SINGULAR_VALUABLES :Vērtslietas STR_CARGO_SINGULAR_COPPER_ORE :Vara rūda STR_CARGO_SINGULAR_MAIZE :Kukurūza STR_CARGO_SINGULAR_FRUIT :Augļi STR_CARGO_SINGULAR_DIAMOND :Dimants STR_CARGO_SINGULAR_FOOD :Pārtika STR_CARGO_SINGULAR_PAPER :Papīrs STR_CARGO_SINGULAR_GOLD :Zelts STR_CARGO_SINGULAR_WATER :Ūdens STR_CARGO_SINGULAR_WHEAT :Kvieši STR_CARGO_SINGULAR_RUBBER :Kaučuks STR_CARGO_SINGULAR_SUGAR :Cukurs STR_CARGO_SINGULAR_TOY :Rotaļlieta STR_CARGO_SINGULAR_CANDY :Saldumi STR_CARGO_SINGULAR_COLA :Kola STR_CARGO_SINGULAR_COTTON_CANDY :Cukurvate STR_CARGO_SINGULAR_BUBBLE :Burbuļi STR_CARGO_SINGULAR_TOFFEE :Īriss STR_CARGO_SINGULAR_BATTERY :Baterijas STR_CARGO_SINGULAR_PLASTIC :Plastmasa STR_CARGO_SINGULAR_FIZZY_DRINK :Limonāde # Quantity of cargo STR_QUANTITY_NOTHING : STR_QUANTITY_PASSENGERS :{COMMA}{NBSP}pasažier{P is i u} STR_QUANTITY_COAL :{WEIGHT_LONG} ogļu STR_QUANTITY_MAIL :{COMMA}{NBSP}pasta mais{P s i u} STR_QUANTITY_OIL :{VOLUME_LONG} naftas STR_QUANTITY_LIVESTOCK :{COMMA}{NBSP}mājlop{P s i u} STR_QUANTITY_GOODS :{COMMA}{NBSP}preču kast{P e es u} STR_QUANTITY_GRAIN :{WEIGHT_LONG} graudu STR_QUANTITY_WOOD :{WEIGHT_LONG} kokmateriālu STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} dzelzsrūdas STR_QUANTITY_STEEL :{WEIGHT_LONG} tērauda STR_QUANTITY_VALUABLES :{COMMA}{NBSP}mais{P s i u} ar vērtslietām STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} vara rūdas STR_QUANTITY_MAIZE :{WEIGHT_LONG} kukurūzas STR_QUANTITY_FRUIT :{WEIGHT_LONG} augļu STR_QUANTITY_DIAMONDS :{COMMA}{NBSP}mais{P s i u} ar dimantiem STR_QUANTITY_FOOD :{WEIGHT_LONG} pārtikas preču STR_QUANTITY_PAPER :{WEIGHT_LONG} papīra STR_QUANTITY_GOLD :{COMMA}{NBSP}zelta mais{P s i u} STR_QUANTITY_WATER :{VOLUME_LONG} ūdens STR_QUANTITY_WHEAT :{WEIGHT_LONG} kviešu STR_QUANTITY_RUBBER :{VOLUME_LONG} kaučuka STR_QUANTITY_SUGAR :{WEIGHT_LONG} cukura STR_QUANTITY_TOYS :{COMMA}{NBSP}rotaļliet{P a as u} STR_QUANTITY_SWEETS :{COMMA}{NBSP}saldumu mais{P s i u} STR_QUANTITY_COLA :{VOLUME_LONG} kolas STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} cukurvates STR_QUANTITY_BUBBLES :{COMMA} burbu{P lis ļi ļu} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} īrisa konfekšu STR_QUANTITY_BATTERIES :{COMMA} baterij{P a as u} STR_QUANTITY_PLASTIC :{VOLUME_LONG} plastmasu STR_QUANTITY_FIZZY_DRINKS :{COMMA} limonād{P e s žu} STR_QUANTITY_N_A :nav informācijas # Two letter abbreviation of cargo name STR_ABBREV_NOTHING : STR_ABBREV_PASSENGERS :{TINY_FONT}PA STR_ABBREV_COAL :{TINY_FONT}OG STR_ABBREV_MAIL :{TINY_FONT}PT STR_ABBREV_OIL :{TINY_FONT}NF STR_ABBREV_LIVESTOCK :{TINY_FONT}LL STR_ABBREV_GOODS :{TINY_FONT}PR STR_ABBREV_GRAIN :{TINY_FONT}GR STR_ABBREV_WOOD :{TINY_FONT}KM STR_ABBREV_IRON_ORE :{TINY_FONT}DZ STR_ABBREV_STEEL :{TINY_FONT}TR STR_ABBREV_VALUABLES :{TINY_FONT}VL STR_ABBREV_COPPER_ORE :{TINY_FONT}VR STR_ABBREV_MAIZE :{TINY_FONT}KU STR_ABBREV_FRUIT :{TINY_FONT}AU STR_ABBREV_DIAMONDS :{TINY_FONT}DM STR_ABBREV_FOOD :{TINY_FONT}PP STR_ABBREV_PAPER :{TINY_FONT}PR STR_ABBREV_GOLD :{TINY_FONT}ZE STR_ABBREV_WATER :{TINY_FONT}ŪD STR_ABBREV_WHEAT :{TINY_FONT}KV STR_ABBREV_RUBBER :{TINY_FONT}KČ STR_ABBREV_SUGAR :{TINY_FONT}CU STR_ABBREV_TOYS :{TINY_FONT}RT STR_ABBREV_SWEETS :{TINY_FONT}SA STR_ABBREV_COLA :{TINY_FONT}KO STR_ABBREV_CANDYFLOSS :{TINY_FONT}CV STR_ABBREV_BUBBLES :{TINY_FONT}BB STR_ABBREV_TOFFEE :{TINY_FONT}CP STR_ABBREV_BATTERIES :{TINY_FONT}BT STR_ABBREV_PLASTIC :{TINY_FONT}PL STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}LM STR_ABBREV_NONE :{TINY_FONT}NAV STR_ABBREV_ALL :{TINY_FONT}VISI # 'Mode' of transport for cargoes STR_PASSENGERS :{COMMA}{NBSP}pasažier{P is i u} STR_BAGS :{COMMA}{NBSP}mais{P s i u} STR_TONS :{COMMA}{NBSP}tonn{P a as u} STR_LITERS :{COMMA}{NBSP}litr{P s i u} STR_ITEMS :{COMMA}{NBSP}vienīb{P a as u} STR_CRATES :{COMMA}{NBSP}kast{P e es u} # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Tumši zila STR_COLOUR_PALE_GREEN :Gaiši zaļa STR_COLOUR_PINK :Sārta STR_COLOUR_YELLOW :Dzeltena STR_COLOUR_RED :Sarkana STR_COLOUR_LIGHT_BLUE :Gaiši zila STR_COLOUR_GREEN :Zaļa STR_COLOUR_DARK_GREEN :Tumši zaļa STR_COLOUR_BLUE :Zila STR_COLOUR_CREAM :Krēmkrāsa STR_COLOUR_MAUVE :Gaišsārti violeta STR_COLOUR_PURPLE :Purpura STR_COLOUR_ORANGE :Oranža STR_COLOUR_BROWN :Brūna STR_COLOUR_GREY :Pelēka STR_COLOUR_WHITE :Balta # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}jūdzes stundā STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}ZS STR_UNITS_POWER_METRIC :{COMMA}{NBSP}ZS STR_UNITS_POWER_SI :{COMMA}{NBSP}kW STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}{NBSP}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}{NBSP}kg STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA}{NBSP}tonn{P a as u} STR_UNITS_WEIGHT_LONG_METRIC :{COMMA}{NBSP}tonn{P a as u} STR_UNITS_WEIGHT_LONG_SI :{COMMA}{NBSP}kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}{NBSP}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}{NBSP}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}{NBSP}m³ STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA}{NBSP}galon{P s i u} STR_UNITS_VOLUME_LONG_METRIC :{COMMA}{NBSP}litr{P s i u} STR_UNITS_VOLUME_LONG_SI :{COMMA}{NBSP}m³ STR_UNITS_FORCE_IMPERIAL :{COMMA}{NBSP}lbf STR_UNITS_FORCE_METRIC :{COMMA}{NBSP}kgf STR_UNITS_FORCE_SI :{COMMA}{NBSP}kN STR_UNITS_HEIGHT_IMPERIAL :{COMMA}{NBSP}pēdas STR_UNITS_HEIGHT_METRIC :{COMMA}{NBSP}m STR_UNITS_HEIGHT_SI :{COMMA}{NBSP}m # Common window strings STR_LIST_FILTER_TITLE :{BLACK}Filtra virkne: STR_LIST_FILTER_OSKTITLE :{BLACK}Ievadīt filtra virkni STR_LIST_FILTER_TOOLTIP :{BLACK}Ievadīt atslēgvārdu, lai filtrētu sarakstu STR_TOOLTIP_GROUP_ORDER :{BLACK}Izvēlēties grupēšanas kārtību STR_TOOLTIP_SORT_ORDER :{BLACK}Izvēlēties kārtošanas secību (dilstoša/augoša) STR_TOOLTIP_SORT_CRITERIA :{BLACK}Izvēlēties kārtošanas pazīmes STR_TOOLTIP_FILTER_CRITERIA :{BLACK}Izvēlēties filtrēšanas pazīmes STR_BUTTON_SORT_BY :{BLACK}Kārtot pēc STR_BUTTON_LOCATION :{BLACK}Atrašanās vieta STR_BUTTON_RENAME :{BLACK}Pārdēvēt STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Aizvērt logu STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Loga virsraksts - vilkt to, lai pārvietotu logu STR_TOOLTIP_SHADE :{BLACK}Aizēnot logu - rādīt tikai virsrakstu STR_TOOLTIP_DEBUG :{BLACK}Rādīt NewGRF atkļūdošanas informāciju STR_TOOLTIP_STICKY :{BLACK}Atzīmēt šo logu kā neaizveramu ar "Aizvērt visus logus" taustiņu. Ctrl+klikšķis, lai saglabātu stāvokli kā noklusējumu STR_TOOLTIP_RESIZE :{BLACK}Klikšķināt un vilkt, lai mainītu šī loga lielumu STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Pārslēgties starp lielu/mazu loga izmēru STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Ritjosla - ritina sarakstu augšup/lejup STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST :{BLACK}Ritjosla - ritina sarakstu pa kreisi/pa labi STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}Nojaukt celtnes u.c. objektus no zemes platības. Ctrl iezīmē diagonālu laukumu. Shift pārslēdz nojaukšanu/izmaksu tāmes attēlošanu # Show engines button STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN :{BLACK}Parādīt paslēptos STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE :{BLACK}Parādīt paslēptos STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP :{BLACK}Parādīt paslēptos STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT :{BLACK}Parādīt paslēptos STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP :{BLACK}Ieslēdzot šo iestatījumu tiks parādīti arī paslēptie vilcieni STR_SHOW_HIDDEN_ENGINES_VEHICLE_ROAD_VEHICLE_TOOLTIP :{BLACK}Ieslēdzot šo iestatījumu tiks parādīti arī paslēptie autotransporta līdzekļi STR_SHOW_HIDDEN_ENGINES_VEHICLE_SHIP_TOOLTIP :{BLACK}Ieslēdzot šo iestatījumu tiks parādīti arī paslēptie kuģi STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Ieslēdzot šo iestatījumu tiks parādīti arī paslēptie lidaparāti # Query window STR_BUTTON_DEFAULT :{BLACK}Noklusējums STR_BUTTON_CANCEL :{BLACK}Atcelt STR_BUTTON_OK :{BLACK}Labi # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP{{}}ASDFGHJKL:" ZXCVBNM<>? . # Measurement tooltip STR_MEASURE_LENGTH :{BLACK}Garums: {NUM} STR_MEASURE_AREA :{BLACK}Laukums: {NUM} x {NUM} STR_MEASURE_LENGTH_HEIGHTDIFF :{BLACK}Garums: {NUM}{}Augstuma atšķirība: {HEIGHT} STR_MEASURE_AREA_HEIGHTDIFF :{BLACK}Laukums: {NUM} x {NUM}{}Augstuma atšķirība: {HEIGHT} # These are used in buttons STR_SORT_BY_CAPTION_NAME :{BLACK}Nosaukums STR_SORT_BY_CAPTION_DATE :{BLACK}Datums # These are used in dropdowns STR_SORT_BY_NAME :nosaukuma STR_SORT_BY_PRODUCTION :ražojumiem STR_SORT_BY_TYPE :veida STR_SORT_BY_TRANSPORTED :pārvadājuma STR_SORT_BY_NUMBER :numura STR_SORT_BY_PROFIT_LAST_YEAR :peļņas pērn STR_SORT_BY_PROFIT_THIS_YEAR :peļņas šogad STR_SORT_BY_AGE :vecuma STR_SORT_BY_RELIABILITY :uzticamības STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE :kravu veidu kopējās ietilpības STR_SORT_BY_MAX_SPEED :maksimālā ātruma STR_SORT_BY_MODEL :modeļa STR_SORT_BY_VALUE :vērtības STR_SORT_BY_LENGTH :garuma STR_SORT_BY_LIFE_TIME :atlikušā kalpošanas laika STR_SORT_BY_TIMETABLE_DELAY :saraksta kavējuma STR_SORT_BY_FACILITY :stacijas veida STR_SORT_BY_WAITING_TOTAL :Gaidošā krava kopā STR_SORT_BY_WAITING_AVAILABLE :Piejamā gaidošā krava STR_SORT_BY_RATING_MAX :augstākā kravu vērtējuma STR_SORT_BY_RATING_MIN :zemākā kravu vērtējuma STR_SORT_BY_ENGINE_ID :dzinēja ID (klasiskais veids) STR_SORT_BY_COST :izmaksas STR_SORT_BY_POWER :jaudas STR_SORT_BY_TRACTIVE_EFFORT :vilcējspēka STR_SORT_BY_INTRO_DATE :ieviešanas datuma STR_SORT_BY_RUNNING_COST :kārtējām izmaksām STR_SORT_BY_POWER_VS_RUNNING_COST :jaudas/kārtējām izmaksām STR_SORT_BY_CARGO_CAPACITY :kravnesības STR_SORT_BY_RANGE :apgabala STR_SORT_BY_POPULATION :iedzīvotāju skaita STR_SORT_BY_RATING :vērtējuma # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pauzēt spēli STR_TOOLBAR_TOOLTIP_FORWARD :{BLACK}Paātrināta spēle STR_TOOLBAR_TOOLTIP_OPTIONS :{BLACK}Opcijas STR_TOOLBAR_TOOLTIP_SAVE_GAME_ABANDON_GAME :{BLACK}Saglabāt spēli, pamest spēli, iziet STR_TOOLBAR_TOOLTIP_DISPLAY_MAP :{BLACK}Rādīt karti, papildu skatvietu vai zīmju sarakstu STR_TOOLBAR_TOOLTIP_DISPLAY_TOWN_DIRECTORY :{BLACK}Rādīt pilsētu sarakstu STR_TOOLBAR_TOOLTIP_DISPLAY_SUBSIDIES :{BLACK}Rādīt subsīdijas STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_STATIONS :{BLACK}Rādīt uzņēmuma staciju sarakstu STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_FINANCES :{BLACK}Rādīt uzņēmuma finanšu stāvokli STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_GENERAL :{BLACK}Rādīt uzņēmuma vispārējo informāciju STR_TOOLBAR_TOOLTIP_DISPLAY_STORY_BOOK :{BLACK}Rādīt stāstu grāmatu STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Rādīt mērķu sarakstu STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Rādīt diagrammas STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Rādīt uzņēmumu rangu sarakstu STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Finansēt jaunas ražotnes būvniecību vai uzskaitīt visas ražotnes STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Rādīt uzņēmuma vilcienu sarakstu. Ctrl+klikšķis pārslēdz grupu/transportlīdzekļu saraksta atvēršanu STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Rādīt uzņēmuma autotransporta sarakstu. Ctrl+klikšķis pārslēdz grupu/transportlīdzekļu saraksta atvēršanu STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Rādīt uzņēmuma kuģu sarakstu. Ctrl+klikšķis pārslēdz grupu/transportlīdzekļu saraksta atvēršanu STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Rādīt uzņēmuma lidaparātu sarakstu. Ctrl+klikšķis pārslēdz grupu/transportlīdzekļu saraksta atvēršanu STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Pietuvināt skatu STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Attālināt skatu STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Būvēt sliežu ceļu STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Būvēt ceļus STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Būvēt kuģu piestātnes STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Būvēt lidostas STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Atvērt ainavas rīkjoslu, lai paceltu/nolaistu zemes līmeni, stādītu kokus utt. STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW :{BLACK}Rādīt skaņas/mūzikas logu STR_TOOLBAR_TOOLTIP_SHOW_LAST_MESSAGE_NEWS :{BLACK}Rādīt pēdējos ziņojumus/avīžu ziņas, ziņojumu rādīšanas opcijas STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION :{BLACK}Informācija par zemes platību, konsole, skriptu atkļūdošana, ekrānuzņēmumi, par OpenTTD STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR :{BLACK}Pārslēgt rīkjoslas # Extra tooltips for the scenario editor toolbar STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO :{BLACK}Saglabāt scenāriju, ielādēt scenāriju, pamest scenāriju redaktoru, iziet STR_SCENEDIT_TOOLBAR_OPENTTD :{YELLOW}OpenTTD STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR :{YELLOW}scenāriju redaktors STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD :{BLACK}Pārvietot sākuma datumu 1 gadu atpakaļ STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD :{BLACK}Pārvietot sākuma datumu 1 gadu uz priekšu STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE :{BLACK}Klikšķināt, lai ievadītu sākuma gadu STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY :{BLACK}Rādīt karti, pilsētu sarakstu STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Ainavas radīšana STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Pilsētu radīšana STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Ražotņu radīšana STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Ceļu būvēšana STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Stādīt kokus. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Novietot zīmi STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Novietot objektu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu ############ range for SE file menu starts STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Saglabāt scenāriju STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Ielādēt scenāriju STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Saglabāt augstumu karti STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Ielādēt augstumu karti STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Pamest scenāriju redaktoru STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Iziet ############ range for SE file menu starts ############ range for settings menu starts STR_SETTINGS_MENU_GAME_OPTIONS :Spēles opcijas STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE :Iestatījumi STR_SETTINGS_MENU_SCRIPT_SETTINGS :MI/spēles skriptu iestatījumi STR_SETTINGS_MENU_NEWGRF_SETTINGS :NewGRF iestatījumi STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Caurspīdības opcijas STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Rādīt pilsētu nosaukumus STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Rādīt staciju nosaukumus STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Rādīt pieturas punktu nosaukumus STR_SETTINGS_MENU_SIGNS_DISPLAYED :Rādīt zīmes STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Rādīt sāncenšu zīmes un nosaukumus STR_SETTINGS_MENU_FULL_ANIMATION :Pilna animācija STR_SETTINGS_MENU_FULL_DETAIL :Visas detaļas STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS :Caurspīdīgas ēkas STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Caurspīdīgas zīmes ############ range ends here ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Saglabāt spēli STR_FILE_MENU_LOAD_GAME :Ielādēt spēli STR_FILE_MENU_QUIT_GAME :Pamest spēli STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Iziet ############ range ends here # map menu STR_MAP_MENU_MAP_OF_WORLD :Pasaules karte STR_MAP_MENU_EXTRA_VIEW_PORT :Papildu skatvieta STR_MAP_MENU_SIGN_LIST :Zīmju saraksts ############ range for town menu starts STR_TOWN_MENU_TOWN_DIRECTORY :Pilsētu saraksts STR_TOWN_MENU_FOUND_TOWN :Dibināt pilsētu ############ range ends here ############ range for subsidies menu starts STR_SUBSIDIES_MENU_SUBSIDIES :Subsīdijas ############ range ends here ############ range for graph menu starts STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH :Darbības peļņas diagramma STR_GRAPH_MENU_INCOME_GRAPH :Ienākumu diagramma STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH :Piegādāto kravu diagramma STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH :Uzņēmējdarbības vēstures diagramma STR_GRAPH_MENU_COMPANY_VALUE_GRAPH :Uzņēmuma vērtības diagramma STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Kravas apmaksas cenas ############ range ends here ############ range for company league menu starts STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Uzņēmumu rangu saraksts STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detalizēts uzņēmējdarbības vērtējums STR_GRAPH_MENU_HIGHSCORE :Sasniegumu tabula ############ range ends here ############ range for industry menu starts STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY :Ražotņu saraksts STR_INDUSTRY_MENU_INDUSTRY_CHAIN :Ražotņu ķēdes STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY :Finansēt jaunu ražotni ############ range ends here ############ range for railway construction menu starts STR_RAIL_MENU_RAILROAD_CONSTRUCTION :Dzelzceļa būvniecība STR_RAIL_MENU_ELRAIL_CONSTRUCTION :Elektrificētā dzelzceļa būvniecība STR_RAIL_MENU_MONORAIL_CONSTRUCTION :Viensliedes būvniecība STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Magleva būvniecība ############ range ends here ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Ceļu būvēšana STR_ROAD_MENU_TRAM_CONSTRUCTION :Tramvaju ceļa būvniecība ############ range ends here ############ range for waterways construction menu starts STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION :Ūdensceļu būvniecība ############ range ends here ############ range for airport construction menu starts STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION :Lidostas būvniecība ############ range ends here ############ range for landscaping menu starts STR_LANDSCAPING_MENU_LANDSCAPING :Ainavas veidošana STR_LANDSCAPING_MENU_PLANT_TREES :Stādīt kokus STR_LANDSCAPING_MENU_PLACE_SIGN :Novietot zīmi ############ range ends here ############ range for music menu starts STR_TOOLBAR_SOUND_MUSIC :Skaņa/mūzika ############ range ends here ############ range for message menu starts STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT :Pēdējais ziņojums/avīzes raksts STR_NEWS_MENU_MESSAGE_HISTORY_MENU :Ziņojumu vēsture ############ range ends here ############ range for about menu starts STR_ABOUT_MENU_LAND_BLOCK_INFO :Zemes platības informācija STR_ABOUT_MENU_SEPARATOR : STR_ABOUT_MENU_TOGGLE_CONSOLE :Atvērt/aizvērt konsoli STR_ABOUT_MENU_AI_DEBUG :MI/spēles skriptu atkļūdošana STR_ABOUT_MENU_SCREENSHOT :Ekrānuzņēmums STR_ABOUT_MENU_ZOOMIN_SCREENSHOT :Pilnībā pietuvināts ekrānuzņēmums STR_ABOUT_MENU_DEFAULTZOOM_SCREENSHOT :Noklusējuma mēroga ekrānuzņēmums STR_ABOUT_MENU_GIANT_SCREENSHOT :Visas kartes ekrānuzņēmums STR_ABOUT_MENU_ABOUT_OPENTTD :Par 'OpenTTD' STR_ABOUT_MENU_SPRITE_ALIGNER :Gariņu līdzinātājs STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES :Pārslēgt saistītās kastes STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS :Pārslēgt netīru bloku krāsojumu ############ range ends here ############ range for ordinal numbers used for the place in the highscore window STR_ORDINAL_NUMBER_1ST :1. STR_ORDINAL_NUMBER_2ND :2. STR_ORDINAL_NUMBER_3RD :3. STR_ORDINAL_NUMBER_4TH :4. STR_ORDINAL_NUMBER_5TH :5. STR_ORDINAL_NUMBER_6TH :6. STR_ORDINAL_NUMBER_7TH :7. STR_ORDINAL_NUMBER_8TH :8. STR_ORDINAL_NUMBER_9TH :9. STR_ORDINAL_NUMBER_10TH :10. STR_ORDINAL_NUMBER_11TH :11. STR_ORDINAL_NUMBER_12TH :12. STR_ORDINAL_NUMBER_13TH :13. STR_ORDINAL_NUMBER_14TH :14. STR_ORDINAL_NUMBER_15TH :15. ############ range for ordinal numbers ends ############ range for days starts STR_DAY_NUMBER_1ST :1. STR_DAY_NUMBER_2ND :2. STR_DAY_NUMBER_3RD :3. STR_DAY_NUMBER_4TH :4. STR_DAY_NUMBER_5TH :5. STR_DAY_NUMBER_6TH :6. STR_DAY_NUMBER_7TH :7. STR_DAY_NUMBER_8TH :8. STR_DAY_NUMBER_9TH :9. STR_DAY_NUMBER_10TH :10. STR_DAY_NUMBER_11TH :11. STR_DAY_NUMBER_12TH :12. STR_DAY_NUMBER_13TH :13. STR_DAY_NUMBER_14TH :14. STR_DAY_NUMBER_15TH :15. STR_DAY_NUMBER_16TH :16. STR_DAY_NUMBER_17TH :17. STR_DAY_NUMBER_18TH :18. STR_DAY_NUMBER_19TH :19. STR_DAY_NUMBER_20TH :20. STR_DAY_NUMBER_21ST :21. STR_DAY_NUMBER_22ND :22. STR_DAY_NUMBER_23RD :23. STR_DAY_NUMBER_24TH :24. STR_DAY_NUMBER_25TH :25. STR_DAY_NUMBER_26TH :26. STR_DAY_NUMBER_27TH :27. STR_DAY_NUMBER_28TH :28. STR_DAY_NUMBER_29TH :29. STR_DAY_NUMBER_30TH :30. STR_DAY_NUMBER_31ST :31. ############ range for days ends ############ range for months starts STR_MONTH_ABBREV_JAN :Jan STR_MONTH_ABBREV_FEB :Feb STR_MONTH_ABBREV_MAR :Mar STR_MONTH_ABBREV_APR :Apr STR_MONTH_ABBREV_MAY :Mai STR_MONTH_ABBREV_JUN :Jūn STR_MONTH_ABBREV_JUL :Jūl STR_MONTH_ABBREV_AUG :Aug STR_MONTH_ABBREV_SEP :Sep STR_MONTH_ABBREV_OCT :Okt STR_MONTH_ABBREV_NOV :Nov STR_MONTH_ABBREV_DEC :Dec STR_MONTH_JAN :Janvāris STR_MONTH_FEB :Februāris STR_MONTH_MAR :Marts STR_MONTH_APR :Aprīlis STR_MONTH_MAY :Maijs STR_MONTH_JUN :Jūnijs STR_MONTH_JUL :Jūlijs STR_MONTH_AUG :Augusts STR_MONTH_SEP :Septembris STR_MONTH_OCT :Oktobris STR_MONTH_NOV :Novembris STR_MONTH_DEC :Decembris ############ range for months ends # Graph window STR_GRAPH_KEY_BUTTON :{BLACK}Leģenda STR_GRAPH_KEY_TOOLTIP :{BLACK}Diagrammās rādīt leģendas STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING}{} {STRING} STR_GRAPH_X_LABEL_MONTH_YEAR :{TINY_FONT}{STRING}{} {STRING}{}{NUM} STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} STR_GRAPH_OPERATING_PROFIT_CAPTION :{WHITE}Darbības peļņas diagramma STR_GRAPH_INCOME_CAPTION :{WHITE}Ienākumu diagramma STR_GRAPH_CARGO_DELIVERED_CAPTION :{WHITE}Pārvadātās kravas vienības STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION :{WHITE}Uzņēmuma darbības vērtējumi (maksimālais ir 1000) STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Uzņēmuma vērtības STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Kravas apmaksas cenas STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL :{TINY_FONT}{BLACK}Dienas pārvadājumos STR_GRAPH_CARGO_PAYMENT_RATES_TITLE :{TINY_FONT}{BLACK}Izmaksas par 10 vienību (vai 10,000 litru) kravas pārvadāšanu par 20mit lauciņiem STR_GRAPH_CARGO_ENABLE_ALL :{TINY_FONT}{BLACK}Iespējot visu STR_GRAPH_CARGO_DISABLE_ALL :{TINY_FONT}{BLACK}Atspējot visu STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL :{BLACK}Rādīt visas kravas samaksu salīdzināšanas diagrammā STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Nerādīt nevienu kravu samaksu salīdzināšanas diagrammā STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Ieslēgt/izslēgt kravu veidu diagrammu STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Rādīt detalizētus uzņēmējdarbības vērtējumus # Graph key window STR_GRAPH_KEY_CAPTION :{WHITE}Leģendas uzņēmumu diagrammās STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP :{BLACK}Klikšķināt šeit, lai izslēgtu/ieslēgtu uzņēmuma iekļaušanu diagrammā # Company league window STR_COMPANY_LEAGUE_TABLE_CAPTION :{WHITE}Uzņēmumu rangu saraksts STR_COMPANY_LEAGUE_COMPANY_NAME :{ORANGE}{COMPANY} {BLACK}{COMPANY_NUM} '{STRING}' STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER :Inženieris STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER :Satiksmes vadītājs STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR :Pārvadājumu koordinators STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR :Maršrutu uzraugs STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR :Direktors STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE :Rīkotājdirektors STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN :Priekšsēdētājs STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT :Prezidents STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON :Magnāts # Performance detail window STR_PERFORMANCE_DETAIL :{WHITE}Detalizēts uzņēmējdarbības vērtējums STR_PERFORMANCE_DETAIL_KEY :{BLACK}Detalizēti STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY :{BLACK}({CURRENCY_SHORT}/{CURRENCY_SHORT}) STR_PERFORMANCE_DETAIL_AMOUNT_INT :{BLACK}({COMMA}/{COMMA}) STR_PERFORMANCE_DETAIL_PERCENT :{WHITE}{NUM}% STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP :{BLACK}Apskatīt šā uzņēmuma informāciju ############ Those following lines need to be in this order!! STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}Transportlīdzekļi: STR_PERFORMANCE_DETAIL_STATIONS :{BLACK}Stacijas: STR_PERFORMANCE_DETAIL_MIN_PROFIT :{BLACK}Min. pelņa STR_PERFORMANCE_DETAIL_MIN_INCOME :{BLACK}Min. ienākumi: STR_PERFORMANCE_DETAIL_MAX_INCOME :{BLACK}Maks. ienākumi: STR_PERFORMANCE_DETAIL_DELIVERED :{BLACK}Piegādāts: STR_PERFORMANCE_DETAIL_CARGO :{BLACK}Krava: STR_PERFORMANCE_DETAIL_MONEY :{BLACK}Nauda: STR_PERFORMANCE_DETAIL_LOAN :{BLACK}Aizdevums: STR_PERFORMANCE_DETAIL_TOTAL :{BLACK}Kopā: ############ End of order list STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP :{BLACK}Transportlīdzekļi, kuri iepriekšējā gadā ir nesuši peļņu. Ietver autotransporta līdzekļus, vilcienus, kuģus un lidaparātus STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP :{BLACK}Nesen apkalpoto staciju skaits. Dzelzceļa stacijas, autoostas, lidostas un tamlīdzīgas tiek skaitītas kā atsevišķas, pat ja tās ir savienotas kā viena stacija STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP :{BLACK}Transportlīdzekļa, kuram ir mazākie ienākumi, peļņa (ņemti vērā tikai transportlīdzekļi, kuri vecāki par 2 gadiem) STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP :{BLACK}Nopelnītās naudas daudzums ceturksnī ar vismazāko peļņu pēdējos 12 ceturkšņos STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP :{BLACK}Nopelnītās naudas daudzums ceturksnī ar vislielāko peļņu pēdējos 12 ceturkšņos STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP :{BLACK}Kravu vienības , kas piegādātas pēdējos četros ceturkšņos STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP :{BLACK}Kravu veidu daudzums, kas piegādāti pēdējā ceturksnī STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP :{BLACK}Šā uzņēmuma naudas daudzums bankā STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP :{BLACK}Naudas daudzums, ko šis uzņēmums ir aizņēmies STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP :{BLACK}Iespējamie punkti kopā # Music window STR_MUSIC_JAZZ_JUKEBOX_CAPTION :{WHITE}Džeza mūzikas automāts STR_MUSIC_PLAYLIST_ALL :{TINY_FONT}{BLACK}Visi STR_MUSIC_PLAYLIST_OLD_STYLE :{TINY_FONT}{BLACK}Vecā stila STR_MUSIC_PLAYLIST_NEW_STYLE :{TINY_FONT}{BLACK}Jaunā stila STR_MUSIC_PLAYLIST_EZY_STREET :{TINY_FONT}{BLACK}Ezy ielas STR_MUSIC_PLAYLIST_CUSTOM_1 :{TINY_FONT}{BLACK}Pielāgotā 1 STR_MUSIC_PLAYLIST_CUSTOM_2 :{TINY_FONT}{BLACK}Pielāgotā 2 STR_MUSIC_MUSIC_VOLUME :{TINY_FONT}{BLACK}Mūzikas skaļums STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLACK}Efektu skaļums STR_MUSIC_RULER_MIN :{TINY_FONT}{BLACK}MIN STR_MUSIC_RULER_MAX :{TINY_FONT}{BLACK}MAKS STR_MUSIC_RULER_MARKER :{TINY_FONT}{BLACK}' STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Celiņš STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Nosaukums STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Sajaukt STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Programma STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Pārlekt uz iepriekšējo celiņu STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Pārlekt uz nākamo celiņu STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Apturēt mūzikas atskaņošanu STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Sākt mūzikas atskaņošanu STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Bīdīt slīdņus, lai mainītu mūzikas un skaņas efektu skaļumu STR_MUSIC_TOOLTIP_SELECT_ALL_TRACKS_PROGRAM :{BLACK}Izvēlēties programmu 'visi celiņi' STR_MUSIC_TOOLTIP_SELECT_OLD_STYLE_MUSIC :{BLACK}Izvēlēties programmu 'vecā stila mūzika' STR_MUSIC_TOOLTIP_SELECT_NEW_STYLE_MUSIC :{BLACK}Izvēlēties programmu 'jaunā stila mūzika' STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Izvēlēties programmu 'Ezy Ielas stila mūzika' STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Izvēlēties programmu 'Pielāgotā 1' (lietotāja sastādīto) STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Izvēlēties programmu 'Pielāgotā 2' (lietotāja sastādīto) STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Ieslēgt/izslēgt mūzikas saraksta jaukšanu STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Rādīt mūzikas celiņu atlases logu STR_ERROR_NO_SONGS :{WHITE}Izvēlēts komplekts bez mūzikas. Mūzika netiks atskaņota # Playlist window STR_PLAYLIST_MUSIC_PROGRAM_SELECTION :{WHITE}Mūzikas programmas izvēle STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}Celiņu rādītājs STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Programma - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Notīrīt STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Dzēst pašreizējo programmu (tikai Pielāgoto 1 vai Pielāgoto 2) STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Klikšķināt uz mūzikas celiņa, lai to pievienotu pašreizējai programmai (tikai Pielāgotā 1 vai Pielāgotā 2) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Klikšķināt uz mūzikas celiņa, lai to izdzēstu no pašreizējās programmas (tikai Pielāgotā1 un Pielāgotā2) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Labākie uzņēmumi, kuri sasnieguši {NUM} STR_HIGHSCORE_TOP_COMPANIES_NETWORK_GAME :{BIG_FONT}{BLACK}Uzņēmumu rangu sarakstā {NUM} STR_HIGHSCORE_POSITION :{BIG_FONT}{BLACK}{COMMA}. STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN :Darījumu cilvēks STR_HIGHSCORE_PERFORMANCE_TITLE_ENTREPRENEUR :Uzņēmējs STR_HIGHSCORE_PERFORMANCE_TITLE_INDUSTRIALIST :Industriālists STR_HIGHSCORE_PERFORMANCE_TITLE_CAPITALIST :Kapitālists STR_HIGHSCORE_PERFORMANCE_TITLE_MAGNATE :Magnāts STR_HIGHSCORE_PERFORMANCE_TITLE_MOGUL :Moguls STR_HIGHSCORE_PERFORMANCE_TITLE_TYCOON_OF_THE_CENTURY :Gadsimta biržas magnāts STR_HIGHSCORE_NAME :{PRESIDENT_NAME}, {COMPANY} STR_HIGHSCORE_STATS :{BIG_FONT}'{STRING}' ({COMMA}) STR_HIGHSCORE_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{BLACK}{COMPANY} sasniedzis '{STRING}' stāvokli! STR_HIGHSCORE_PRESIDENT_OF_COMPANY_ACHIEVES_STATUS :{BIG_FONT}{WHITE}{PRESIDENT_NAME} no {COMPANY} sasnieguši '{STRING}' stāvokli! # Smallmap window STR_SMALLMAP_CAPTION :{WHITE}Karte - {STRING} STR_SMALLMAP_TYPE_CONTOURS :kontūras STR_SMALLMAP_TYPE_VEHICLES :transportlīdzekļi STR_SMALLMAP_TYPE_INDUSTRIES :ražotnes STR_SMALLMAP_TYPE_ROUTES :maršruti STR_SMALLMAP_TYPE_VEGETATION :augu valsts STR_SMALLMAP_TYPE_OWNERS :īpašnieki STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP :{BLACK}Rādīt zemes kontūras uz kartes STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP :{BLACK}Rādīt transportlīdzekļus uz kartes STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP :{BLACK}Rādīt ražotnes uz kartes STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP :{BLACK}Rādīt kravas plūsmu uz kartes STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON :{BLACK}Rādīt pārvadājumu maršrutus uz kartes STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP :{BLACK}Rādīt augu valsti uz kartes STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP :{BLACK}Rādīt zemes īpašniekus uz kartes STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION :{BLACK}Klikšķināt uz rūpnīcas veida, lai pārslēgtu tā atainošanu. Ctrl+klikšķis atslēdz visas rūpnīcas, izņemot izvēlēto veidu. Atkārtots Ctrl+klikšķis uz tā ieslēgs visus rūpnīcu veidus STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION :{BLACK}Klikšķināt uz uzņēmuma, lai pārslēgtu tā īpašumu attēlošanu. Ctrl+klikšķis atslēdz visus uzņēmumus, izņemot izvēlēto. Atkārtots Ctrl+klikšķis uz tā ieslēgs visus uzņēmumus STR_SMALLMAP_LEGENDA_ROADS :{TINY_FONT}{BLACK}Ceļi STR_SMALLMAP_LEGENDA_RAILROADS :{TINY_FONT}{BLACK}Dzelzsceļi STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS :{TINY_FONT}{BLACK}Stacijas/lidostas/piestātnes STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES :{TINY_FONT}{BLACK}Celtnes/ražotnes STR_SMALLMAP_LEGENDA_VEHICLES :{TINY_FONT}{BLACK}Transportlīdzekļi STR_SMALLMAP_LEGENDA_TRAINS :{TINY_FONT}{BLACK}Vilcieni STR_SMALLMAP_LEGENDA_ROAD_VEHICLES :{TINY_FONT}{BLACK}Autotransporta līdzekļi STR_SMALLMAP_LEGENDA_SHIPS :{TINY_FONT}{BLACK}Kuģi STR_SMALLMAP_LEGENDA_AIRCRAFT :{TINY_FONT}{BLACK}Lidaparāti STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES :{TINY_FONT}{BLACK}Pārvadājumu maršruti STR_SMALLMAP_LEGENDA_FOREST :{TINY_FONT}{BLACK}Mežs STR_SMALLMAP_LEGENDA_RAILROAD_STATION :{TINY_FONT}{BLACK}Dzelzsceļa stacija STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY :{TINY_FONT}{BLACK}Kravas automobiļu iekrautuve STR_SMALLMAP_LEGENDA_BUS_STATION :{TINY_FONT}{BLACK}Autobusa stacija STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT :{TINY_FONT}{BLACK}Lidosta/Helikopteru osta STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLACK}Piestātne STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}Nelīdzena zeme STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}Zālāju zeme STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}Kaila zeme STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}Lauki STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}Koki STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}Akmeņi STR_SMALLMAP_LEGENDA_WATER :{TINY_FONT}{BLACK}Ūdens STR_SMALLMAP_LEGENDA_NO_OWNER :{TINY_FONT}{BLACK}Nav īpašnieka STR_SMALLMAP_LEGENDA_TOWNS :{TINY_FONT}{BLACK}Pilsētas STR_SMALLMAP_LEGENDA_INDUSTRIES :{TINY_FONT}{BLACK}Ražotnes STR_SMALLMAP_LEGENDA_DESERT :{TINY_FONT}{BLACK}Tuksnesis STR_SMALLMAP_LEGENDA_SNOW :{TINY_FONT}{BLACK}Sniegs STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF :{BLACK}Rādīt/nerādīt pilsētu nosaukumus uz kartes STR_SMALLMAP_CENTER :{BLACK}Centrēt minikarti uz pašreizējo pozīciju STR_SMALLMAP_INDUSTRY :{TINY_FONT}{STRING} ({NUM}) STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} STR_SMALLMAP_DISABLE_ALL :{BLACK}Atspējot visu STR_SMALLMAP_ENABLE_ALL :{BLACK}Iespējot visu STR_SMALLMAP_SHOW_HEIGHT :{BLACK}Rādīt augstumu STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES :{BLACK}Nerādīt uz kartes ražotnes STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES :{BLACK}Rādīt uz kartes visas ražotnes STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT :{BLACK}Pārslēgt augstumu kartes attēlošanu STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES :{BLACK}Nerādīt neviena uzņēmuma īpašumus uz kartes STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES :{BLACK}Rādīt visu uzņēmumu īpašumus uz kartes STR_SMALLMAP_TOOLTIP_DISABLE_ALL_CARGOS :{BLACK}Nerādīt kravas uz kartes # Status bar messages STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Rādīt pēdējo ziņojumu vai avīzes rakstu STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUZE * * STR_STATUSBAR_AUTOSAVE :{RED}AUTOMĀTISKĀ SAGLABĀŠANA STR_STATUSBAR_SAVING_GAME :{RED}* * SPĒLE TIEK SAGLABĀTA * * # News message history STR_MESSAGE_HISTORY :{WHITE}Ziņojumu vēsture STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}Neseno ziņojumu saraksts STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING} STR_NEWS_MESSAGE_CAPTION :{WHITE}Ziņojums STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} STR_NEWS_FIRST_TRAIN_ARRIVAL :{BIG_FONT}{BLACK}Pilsētnieki līksmo . . .{}Pirmais vilciens ierodas {STATION}! STR_NEWS_FIRST_BUS_ARRIVAL :{BIG_FONT}{BLACK}Pilsētnieki līksmo . . .{}Pirmais autobuss ierodas {STATION}! STR_NEWS_FIRST_TRUCK_ARRIVAL :{BIG_FONT}{BLACK}Pilsētnieki līksmo . . .{}Pirmā kravas automašīna ierodas {STATION}! STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Pilsētnieki līksmo . . .{}Pirmais pasažieru tramvajs ierodas {STATION}! STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL :{BIG_FONT}{BLACK}Pilsētnieki līksmo . . .{}Pirmais kravas tramvajs ierodas {STATION}! STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLACK}Pilsētnieki līksmo . . .{}Pirmais kuģis ierodas {STATION}! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}Pilsētnieki līksmo . . .{}Pirmais lidaparāts ierodas {STATION}! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}Vilciena avārija!{}Pēc sadursmei sekojoša sprādziena {COMMA} bojāgājušie STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}Autotransporta līdzekļa avārija!{}Vadītājs mirst sprādzienā pēc sadursmes ar vilcienu STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}Autotransporta līdzekļa avārija!{}{COMMA} mirst sprādzienā pēc sadursmes ar vilcienu STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}Lidmašīna nogāzusies!{}{COMMA} iet bojā sprādzienā {STATION} STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}Lidaparāta avārija!{}Lidaparātam beidzās degviela, {COMMA} bojāgājušie! STR_NEWS_DISASTER_ZEPPELIN :{BIG_FONT}{BLACK}Dirižabļa katastrofa {STATION}! STR_NEWS_DISASTER_SMALL_UFO :{BIG_FONT}{BLACK}Autotransporta līdzeklis ir gājis bojā sadursmē ar 'NLO'! STR_NEWS_DISASTER_AIRPLANE_OIL_REFINERY :{BIG_FONT}{BLACK}Ir uzsprāgusi naftas pārstrādes rūpnīca netālu no {TOWN}! STR_NEWS_DISASTER_HELICOPTER_FACTORY :{BIG_FONT}{BLACK}Netālu no {TOWN} mīklainos apstākļos ir iznīcināta rūpnīca! STR_NEWS_DISASTER_BIG_UFO :{BIG_FONT}{BLACK}'NLO' nolaižas netālu no {TOWN}! STR_NEWS_DISASTER_COAL_MINE_SUBSIDENCE :{BIG_FONT}{BLACK}Ogļu raktuves iebrukšana atstāj bojājumu joslu netālu no {TOWN}! STR_NEWS_DISASTER_FLOOD_VEHICLE :{BIG_FONT}{BLACK}Plūdi!{}Vismaz {COMMA} pazuduši bez vēsts, iespējams gājuši bojā plūdos! STR_NEWS_COMPANY_IN_TROUBLE_TITLE :{BIG_FONT}{BLACK}Transporta uzņēmumam ir grūtības! STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} tiks izpārdots vai pasludināts bankrots, ja tuvākajā laikā neuzlabosies tā darbības rādītāji! STR_NEWS_COMPANY_MERGER_TITLE :{BIG_FONT}{BLACK}Transporta uzņēmumi apvienojas! STR_NEWS_COMPANY_MERGER_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} tika pārdots {STRING} par {CURRENCY_LONG}! STR_NEWS_COMPANY_BANKRUPT_TITLE :{BIG_FONT}{BLACK}Bankrots! STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} kreditori slēdza un visi īpašumi tika izpārdoti! STR_NEWS_COMPANY_LAUNCH_TITLE :{BIG_FONT}{BLACK}Darbu sāk jauns transporta uzņēmums! STR_NEWS_COMPANY_LAUNCH_DESCRIPTION :{BIG_FONT}{BLACK}{STRING} sāk būvdarbus netālu no {TOWN}! STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLACK}{STRING} tiek pārņemts {STRING} izpildījumā! STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(vadītājs) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{STRING} pabalstīja jaunas pilsētas - {TOWN} dibināšanu! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}Tiek būvēta jauna {STRING} netālu no {TOWN}! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}Jauns {STRING} tiek stādīts netālu no {TOWN}! STR_NEWS_INDUSTRY_CLOSURE_GENERAL :{BIG_FONT}{BLACK}{STRING} paziņo par tūlītēju darbības pārtraukšanu! STR_NEWS_INDUSTRY_CLOSURE_SUPPLY_PROBLEMS :{BIG_FONT}{BLACK}Piegādes problēmas {STRING} izraisa tūlītēju darbības pārtraukšanu! STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES :{BIG_FONT}{BLACK}Tuvumā esošu koku trūkums ir iemesls paziņojumam par draudošu {STRING} darbības slēgšanu! STR_NEWS_EURO_INTRODUCTION :{BIG_FONT}{BLACK}Eiropas naudas apvienība!{}{}Eiro ir ieviests, kā vienīgā valūta jūsu valstī! STR_NEWS_BEGIN_OF_RECESSION :{BIG_FONT}{BLACK}Krīze pasaulē!{}{}Finanšu eksperti ekonomikai paredz sliktākos attīstības scenārijus! STR_NEWS_END_OF_RECESSION :{BIG_FONT}{BLACK}Krīze ir beigusies!{}{}Tirdzniecības apjomu pieaugums dod pārliecību par ekonomikas nostiprināšanos! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} palielina ražošanas apjomu! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_COAL :{BIG_FONT}{BLACK}Atklāts jauns ogļu slānis {INDUSTRY}!{}Paredzams ogļu ieguves apjoma dubultošanās! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_OIL :{BIG_FONT}{BLACK}Atrastas jaunas naftas rezerves {INDUSTRY}!{}Paredzams naftas ieguves apjoma dubultošanās! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM :{BIG_FONT}{BLACK}Uzlaboti zemkopības paņēmieni {INDUSTRY} divkārtīgi palielinās saražoto! STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} {INDUSTRY} ražošanas apjoms palielinās par {COMMA}%! STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL :{BIG_FONT}{BLACK}{INDUSTRY} saražotā apjoms samazinās par 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM :{BIG_FONT}{BLACK}Kukaiņu uzbrukums {INDUSTRY}!{} Saražotā apjoms samazinās par 50% STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_SMOOTH :{BIG_FONT}{BLACK}{STRING} {INDUSTRY} ražošanas apjoms samazinās par {COMMA}%! STR_NEWS_TRAIN_IS_WAITING :{WHITE}{VEHICLE} gaida depo STR_NEWS_ROAD_VEHICLE_IS_WAITING :{WHITE}{VEHICLE} gaida depo STR_NEWS_SHIP_IS_WAITING :{WHITE}{VEHICLE} gaida depo STR_NEWS_AIRCRAFT_IS_WAITING :{WHITE}{VEHICLE} gaida aviācijas angārā # Order review system / warnings STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS :{WHITE}{VEHICLE} sarakstā ir pārāk maz rīkojumu STR_NEWS_VEHICLE_HAS_VOID_ORDER :{WHITE}{VEHICLE} ir nederīgs maršruts STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY :{WHITE}{VEHICLE} ir divi vienādi maršruti STR_NEWS_VEHICLE_HAS_INVALID_ENTRY :{WHITE}{VEHICLE} rīkojumā ir nederīga stacija STR_NEWS_VEHICLE_IS_GETTING_OLD :{WHITE}{VEHICLE} pamazām noveco STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD :{WHITE}{VEHICLE} ir kļuvis ļoti vecs STR_NEWS_VEHICLE_IS_GETTING_VERY_OLD_AND :{WHITE}{VEHICLE} ir kļuvis ļoti vecs un tam steidzami nepieciešama nomaiņa STR_NEWS_TRAIN_IS_STUCK :{WHITE}{VEHICLE} nevar atrast ceļu, lai turpinātu STR_NEWS_VEHICLE_IS_LOST :{WHITE}{VEHICLE} ir apmaldījies STR_NEWS_VEHICLE_IS_UNPROFITABLE :{WHITE}{VEHICLE} iepriekšējā gada peļņa bija {CURRENCY_LONG} STR_NEWS_AIRCRAFT_DEST_TOO_FAR :{WHITE}{VEHICLE} nevar doties uz nākamo galamērķi, jo tas ir ārpus apgabala STR_NEWS_ORDER_REFIT_FAILED :{WHITE}{VEHICLE} ir apstājies, jo neizdevās pasūtītā pielāgošana STR_NEWS_VEHICLE_AUTORENEW_FAILED :{WHITE}Automātiskās atjaunošanas kļūda {VEHICLE}{}{STRING} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE :{BIG_FONT}{BLACK}Tagad ir pieejams jauns {STRING}! STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE :{BLACK}Tagad ir pieejams jauns {STRING}! - {ENGINE} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO :{WHITE}{STATION} vairs nepieņem {STRING} STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_OR_CARGO :{WHITE}{STATION} vairs nepieņem {STRING} vai {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO :{WHITE}{STATION} pieņem {STRING} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_AND_CARGO :{WHITE}{STATION} pieņem {STRING} un {STRING} STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Subsīdijas piedāvājums beidzies:{}{}{STRING} no {STRING} uz {STRING} subsidēšana ir atcelta STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subsidēšana atcelta:{}{}{STRING} pārvadājumi no {STRING} uz {STRING} turpmāk vairs netiek subsidēti STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Subsīdijas piedāvājums:{}{}Pirmais {STRING} pārvadātājs no {STRING} uz {STRING} vienu gadu saņems pašvaldības subsīdijas! STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF :{BIG_FONT}{BLACK}Pārvadājumu subsīdija piešķirta {STRING}!{}{}{STRING} pārvadājumi no {STRING} uz {STRING} saņems 50% piemaksu vienu gadu! STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLACK}Pārvadājumu subsīdija piešķirta {STRING}!{}{}{STRING} pārvadājumi no {STRING} uz {STRING} saņems divkāršu samaksu vienu gadu! STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Pārvadājumu subsīdija piešķirta {STRING}!{}{}{STRING} pārvadājumi no {STRING} uz {STRING} saņems trīskāršu samaksu vienu gadu! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Pārvadājumu subsīdija piešķirta {STRING}!{}{}{STRING} pārvadājumi no {STRING} uz {STRING} saņems četrkāršu samaksu vienu gadu! STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Satiksmes haoss {TOWN}!{}{}{STRING} apmaksātie ielu pārbūves darbi rada vājprātu uz ielām pusgada garumā! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Pārvadājumu monopols! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}{TOWN} vietējā pašvaldība panāk vienošanos ar {STRING} par pārvadājumu izņēmuma tiesībām uz vienu gadu! # Extra view window STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Skatvieta {COMMA} STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN :{BLACK}Kopēt uz skatvietu STR_EXTRA_VIEW_MOVE_VIEW_TO_MAIN_TT :{BLACK}Kopēt galvenā skata atrašanās vietu uz šo skatvietu STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW :{BLACK}Kopēt no skatvietas STR_EXTRA_VIEW_MOVE_MAIN_TO_VIEW_TT :{BLACK}Ielīmēt šīs skatvietas atrašanās vietu uz galveno skatu # Game options window STR_GAME_OPTIONS_CAPTION :{WHITE}Spēles opcijas STR_GAME_OPTIONS_CURRENCY_UNITS_FRAME :{BLACK}Naudas vienības STR_GAME_OPTIONS_CURRENCY_UNITS_DROPDOWN_TOOLTIP :{BLACK}Naudas vienību izvēle ############ start of currency region STR_GAME_OPTIONS_CURRENCY_GBP :Lielbritānijas sterliņu mārciņas (GBP) STR_GAME_OPTIONS_CURRENCY_USD :ASV dolāri (USD) STR_GAME_OPTIONS_CURRENCY_EUR :Eiro (EUR) STR_GAME_OPTIONS_CURRENCY_JPY :Japānas jenas (JPY) STR_GAME_OPTIONS_CURRENCY_ATS :Austrijas šiliņi (ATS) STR_GAME_OPTIONS_CURRENCY_BEF :Beļģijas franki (BEF) STR_GAME_OPTIONS_CURRENCY_CHF :Šveices franki (CHF) STR_GAME_OPTIONS_CURRENCY_CZK :Čehijas kronas (CZK) STR_GAME_OPTIONS_CURRENCY_DEM :Vācijas markas (DEM) STR_GAME_OPTIONS_CURRENCY_DKK :Dānijas kronas (DKK) STR_GAME_OPTIONS_CURRENCY_ESP :Spānijas pesetas (ESP) STR_GAME_OPTIONS_CURRENCY_FIM :Somijas markas (FIM) STR_GAME_OPTIONS_CURRENCY_FRF :Francijas franki (FRF) STR_GAME_OPTIONS_CURRENCY_GRD :Grieķijas drahmas (GRD) STR_GAME_OPTIONS_CURRENCY_HUF :Ungārijas forinti (HUF) STR_GAME_OPTIONS_CURRENCY_ISK :Īslandes kronas (ISK) STR_GAME_OPTIONS_CURRENCY_ITL :Itālijas liras (ITL) STR_GAME_OPTIONS_CURRENCY_NLG :Nīderlandes guldeņi (NLG) STR_GAME_OPTIONS_CURRENCY_NOK :Norvēģijas kronas (NOK) STR_GAME_OPTIONS_CURRENCY_PLN :Polijas zloti (PLN) STR_GAME_OPTIONS_CURRENCY_RON :Rumānijas lejas (RON) STR_GAME_OPTIONS_CURRENCY_RUR :Krievijas rubļi (RUR) STR_GAME_OPTIONS_CURRENCY_SIT :Slovēnijas tolāri (SIT) STR_GAME_OPTIONS_CURRENCY_SEK :Zviedrijas kronas (SEK) STR_GAME_OPTIONS_CURRENCY_TRY :Turcijas liras (TRY) STR_GAME_OPTIONS_CURRENCY_SKK :Slovākijas kronas (SKK) STR_GAME_OPTIONS_CURRENCY_BRL :Brazīlijas reāli (BRL) STR_GAME_OPTIONS_CURRENCY_EEK :Igaunijas kronas (EEK) STR_GAME_OPTIONS_CURRENCY_LTL :Lietuvas liti (LTL) STR_GAME_OPTIONS_CURRENCY_KRW :Dienvidkorejas vonas (KRW) STR_GAME_OPTIONS_CURRENCY_ZAR :Dienvidāfrikas rendi (ZAR) STR_GAME_OPTIONS_CURRENCY_CUSTOM :Cita... STR_GAME_OPTIONS_CURRENCY_GEL :Gruzijas lari (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Irānas riāli (IRR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_FRAME :{BLACK}Autotransporta līdzekļi STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_TOOLTIP :{BLACK}Ceļa braucamās puses izvēle STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Brauc pa kreiso pusi STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Brauc pa labo pusi STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Pilsētu nosaukumi STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Pilsētu nosaukumu stila izvēle ############ start of townname region STR_GAME_OPTIONS_TOWN_NAME_ORIGINAL_ENGLISH :Angļu (sākotnējie) STR_GAME_OPTIONS_TOWN_NAME_FRENCH :Franču STR_GAME_OPTIONS_TOWN_NAME_GERMAN :Vācu STR_GAME_OPTIONS_TOWN_NAME_ADDITIONAL_ENGLISH :Angļu (papildu) STR_GAME_OPTIONS_TOWN_NAME_LATIN_AMERICAN :Latīņamerikāņu STR_GAME_OPTIONS_TOWN_NAME_SILLY :Muļķīgie STR_GAME_OPTIONS_TOWN_NAME_SWEDISH :Zviedru STR_GAME_OPTIONS_TOWN_NAME_DUTCH :Holandiešu STR_GAME_OPTIONS_TOWN_NAME_FINNISH :Somu STR_GAME_OPTIONS_TOWN_NAME_POLISH :Poļu STR_GAME_OPTIONS_TOWN_NAME_SLOVAK :Slovāku STR_GAME_OPTIONS_TOWN_NAME_NORWEGIAN :Norvēģu STR_GAME_OPTIONS_TOWN_NAME_HUNGARIAN :Ungāru STR_GAME_OPTIONS_TOWN_NAME_AUSTRIAN :Austriešu STR_GAME_OPTIONS_TOWN_NAME_ROMANIAN :Rumāņu STR_GAME_OPTIONS_TOWN_NAME_CZECH :Čehu STR_GAME_OPTIONS_TOWN_NAME_SWISS :Šveiciešu STR_GAME_OPTIONS_TOWN_NAME_DANISH :Dāņu STR_GAME_OPTIONS_TOWN_NAME_TURKISH :Turku STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :Itāļu STR_GAME_OPTIONS_TOWN_NAME_CATALAN :Kataloņu ############ end of townname region STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Automātiskā saglabāšana STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Izvēlēties spēles automātiskās saglabāšanas starplaikus ############ start of autosave dropdown STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_OFF :Izslēgta STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :katru mēnesi STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_3_MONTHS :katrus 3 mēnešus STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_6_MONTHS :katrus 6 mēnešus STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :katrus 12 mēnešus ############ end of autosave dropdown STR_GAME_OPTIONS_LANGUAGE :{BLACK}Valoda STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Saskarnes valodas izvēle STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pilnekrāna spēle STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Noklikšķināt uz šīs pogas, lai spēlētu pilnekrāna OpenTTD STR_GAME_OPTIONS_RESOLUTION :{BLACK}Ekrāna izšķirtspēja STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Ekrāna izšķirtspējas izvēle STR_GAME_OPTIONS_RESOLUTION_OTHER :Cita STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Lietotāja saskarnes lielums STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Lietotāja saskarnes elementu lieluma izvēle STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Parasts STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Divkāršs STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Četrkāršs STR_GAME_OPTIONS_BASE_GRF :{BLACK}Pamata grafikas kopa STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Atlasīt lietošanai pamata grafikas kopu STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} iztrūkstošs/bojāts fail{P s i ""} STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Papildinformācija par pamata grafikas kopu STR_GAME_OPTIONS_BASE_SFX :{BLACK}Pamata skaņas kopa STR_GAME_OPTIONS_BASE_SFX_TOOLTIP :{BLACK}Atlasīt lietošanai pamata skaņas kopu STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Papildinformācija par pamata skaņas kopu STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Pamata mūzikas kopa STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Atlasīt lietošanai pamata mūzikas kopu STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} bojāt{P s i u} fail{P s i u} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Papildinformācija par pamata mūzikas kopu STR_ERROR_FULLSCREEN_FAILED :{WHITE}Pilnekrāna spēles iestatīšana neizdevās # Custom currency window STR_CURRENCY_WINDOW :{WHITE}Pielāgota valūta STR_CURRENCY_EXCHANGE_RATE :{LTBLUE}Maiņas kurss: {ORANGE}{CURRENCY_LONG} = £ {COMMA} STR_CURRENCY_DECREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Samazināt savas valūtas vienību daudzumu attiecībā pret vienu mārciņu (£) STR_CURRENCY_INCREASE_EXCHANGE_RATE_TOOLTIP :{BLACK}Palielināt savas valūtas vienību daudzumu attiecībā pret vienu mārciņu (£) STR_CURRENCY_SET_EXCHANGE_RATE_TOOLTIP :{BLACK}Uzstādīt savas valūtas maiņas kursu pret vienu mārciņu (£) STR_CURRENCY_SEPARATOR :{LTBLUE}Atdalītājs: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SEPARATOR_TOOLTIP :{BLACK}Uzstādīt savas valūtas atdalītājsimbolu STR_CURRENCY_PREFIX :{LTBLUE}Priedēklis: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_PREFIX_TOOLTIP :{BLACK}Uzstādīt priedēkli savai valūtai STR_CURRENCY_SUFFIX :{LTBLUE}Piedēklis: {ORANGE}{STRING} STR_CURRENCY_SET_CUSTOM_CURRENCY_SUFFIX_TOOLTIP :{BLACK}Uzstādīt piedēkli savai valūtai STR_CURRENCY_SWITCH_TO_EURO :{LTBLUE}Pāriet uz eiro: {ORANGE}{NUM} STR_CURRENCY_SWITCH_TO_EURO_NEVER :{LTBLUE}Pāriet uz eiro: {ORANGE}nekad STR_CURRENCY_SET_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Uzstādīt gadu, kad pāriet uz eiro STR_CURRENCY_DECREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Pāriet uz eiro agrāk STR_CURRENCY_INCREASE_CUSTOM_CURRENCY_TO_EURO_TOOLTIP :{BLACK}Pāriet uz eiro vēlāk STR_CURRENCY_PREVIEW :{LTBLUE}Priekšskatījums: {ORANGE}{CURRENCY_LONG} STR_CURRENCY_CUSTOM_CURRENCY_PREVIEW_TOOLTIP :{BLACK}10000 mārciņas (£) jūsu valūtā STR_CURRENCY_CHANGE_PARAMETER :{BLACK}Mainīt pielāgotās valūtas rādītāju STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS :{LTBLUE}Maksimālais sāncenšu daudzums: {ORANGE}{COMMA} STR_NONE :Nav STR_FUNDING_ONLY :Tikai līdzekļu piešķiršana STR_MINIMAL :Minimāls STR_NUM_VERY_LOW :Ļoti zems STR_NUM_LOW :Zems STR_NUM_NORMAL :Parasts STR_NUM_HIGH :Augsts STR_NUM_CUSTOM :Pielāgots STR_NUM_CUSTOM_NUMBER :Pielāgots ({NUM}) STR_VARIETY_NONE :Nav STR_VARIETY_VERY_LOW :Ļoti zema STR_VARIETY_LOW :Zema STR_VARIETY_MEDIUM :Vidēja STR_VARIETY_HIGH :Augsta STR_VARIETY_VERY_HIGH :Ļoti augsta STR_AI_SPEED_VERY_SLOW :Ļoti lēns STR_AI_SPEED_SLOW :Lēns STR_AI_SPEED_MEDIUM :Vidējs STR_AI_SPEED_FAST :Ātrs STR_AI_SPEED_VERY_FAST :Ļoti ātrs STR_SEA_LEVEL_VERY_LOW :Ļoti zems STR_SEA_LEVEL_LOW :Zems STR_SEA_LEVEL_MEDIUM :Vidējs STR_SEA_LEVEL_HIGH :Augsts STR_SEA_LEVEL_CUSTOM :Cits STR_SEA_LEVEL_CUSTOM_PERCENTAGE :Cits ({NUM}%) STR_RIVERS_NONE :Neviena STR_RIVERS_FEW :Nedaudzas STR_RIVERS_MODERATE :Vidējs daudzums STR_RIVERS_LOT :Daudzas STR_DISASTER_NONE :Nav STR_DISASTER_REDUCED :samazināta STR_DISASTER_NORMAL :Parasta STR_SUBSIDY_X1_5 :x1.5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 STR_TERRAIN_TYPE_VERY_FLAT :Ļoti līdzens STR_TERRAIN_TYPE_FLAT :Līdzens STR_TERRAIN_TYPE_HILLY :Paugurains STR_TERRAIN_TYPE_MOUNTAINOUS :Kalnains STR_TERRAIN_TYPE_ALPINIST :Alpu STR_CITY_APPROVAL_PERMISSIVE :pieļaujoša STR_CITY_APPROVAL_TOLERANT :iecietīga STR_CITY_APPROVAL_HOSTILE :naidīga STR_WARNING_NO_SUITABLE_AI :{WHITE}Nav pieejami derīgi MI...{}Jūs varat lejuplādēt dažādus MI, izmantojot sistēmu 'Tiešsaistes saturs' # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Iestatījumi STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtra virkne: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Izvērst visu STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Sakļaut visu STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(skaidrojums nav pieejams) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Noklusējuma vērtība: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Iestatījuma veids: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE_CLIENT :lietotāja iestatījums (netiek iekļauts saglabājumos, ietekmē visas spēles) STR_CONFIG_SETTING_TYPE_GAME_MENU :spēles iestatījums (tiek iekļauts saglabājumos, ietekmē tikai jaunās spēles) STR_CONFIG_SETTING_TYPE_GAME_INGAME :spēles iestatījums (tiek iekļauts saglabājumā, ietekmē tikai pašreizējo spēli) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :uzņēmuma iestatījums (tiek iekļauts saglabājumos, ietekmē tikai jaunās spēles) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :uzņēmuma iestatījums (tiek iekļauts saglabājumā, ietekmē tikai pašreizējo uzņēmumu) STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategorija: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Veids: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Ierobežo turpmāko sarakstu, rādot tikai izmainītos iestatījumus STR_CONFIG_SETTING_RESTRICT_BASIC :Pamatiestatījumi (parādīt tikai svarīgākos iestatījumus) STR_CONFIG_SETTING_RESTRICT_ADVANCED :Papildu iestatījumi (parādīt iestatījumu vairākumu) STR_CONFIG_SETTING_RESTRICT_ALL :Lietpratēju iestatījumi (parādīt visus iestatījumus, tai skaitā arī nestandarta) STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_DEFAULT :Iestatījumi ar atšķirīgu vērtību nekā noklusējuma STR_CONFIG_SETTING_RESTRICT_CHANGED_AGAINST_NEW :Iestatījumi ar atšķirīgu vērtību nekā jūsu jaunajai spēlei STR_CONFIG_SETTING_TYPE_DROPDOWN_HELPTEXT :{BLACK}Ierobežo zemāk esošo sarakstu ar noteiktiem iestatījumu veidiem STR_CONFIG_SETTING_TYPE_DROPDOWN_ALL :Visi iestatījumu veidi STR_CONFIG_SETTING_TYPE_DROPDOWN_CLIENT :Klienta programmas iestatījumi (netiek iekļauti saglabājumos, ietekmē visas spēles) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_MENU :Spēles iestatījumi (tiek iekļauti saglabājumos, ietekmē tikai jaunās spēles) STR_CONFIG_SETTING_TYPE_DROPDOWN_GAME_INGAME :Spēles iestatījumi (tiek iekļauti saglabājumā, ietekmē tikai pašreizējo spēli) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_MENU :Uzņēmuma iestatījumi (tiek iekļauti saglabājumos, ietekmē tikai jaunās spēles) STR_CONFIG_SETTING_TYPE_DROPDOWN_COMPANY_INGAME :Uzņēmuma iestatījumi (tiek iekļauti saglabājumā, ietekmē tikai pašreizējo uzņēmumu) STR_CONFIG_SETTINGS_NONE :{WHITE}-Nav- STR_CONFIG_SETTING_OFF :izslēgts STR_CONFIG_SETTING_ON :ieslēgts STR_CONFIG_SETTING_DISABLED :atspējots STR_CONFIG_SETTING_COMPANIES_OFF :izslēgts STR_CONFIG_SETTING_COMPANIES_OWN :savam uzņēmumam STR_CONFIG_SETTING_COMPANIES_ALL :visiem uzņēmumiem STR_CONFIG_SETTING_NONE :nekāds STR_CONFIG_SETTING_ORIGINAL :sākotnējais STR_CONFIG_SETTING_REALISTIC :reālistiskais STR_CONFIG_SETTING_HORIZONTAL_POS_LEFT :pa kreisi STR_CONFIG_SETTING_HORIZONTAL_POS_CENTER :centrā STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :pa labi STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :Maksimālais sākotnējais aizdevums: {STRING} STR_CONFIG_SETTING_INTEREST_RATE :Procentu likme: {STRING} STR_CONFIG_SETTING_RUNNING_COSTS :Kārtējās izmaksas: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Būvēšanas ātrums: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :MI (mākslīgā intelekta) būvniecības darbību daudzuma ierobežošana STR_CONFIG_SETTING_VEHICLE_BREAKDOWNS :Transportlīdzekļu bojāšanās: {STRING} STR_CONFIG_SETTING_SUBSIDY_MULTIPLIER :Subsīdiju reizinātājs: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Būvēšanas izmaksas: {STRING} STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Iestatīt būvēšanas un pirkumu izmaksas STR_CONFIG_SETTING_RECESSIONS :Lejupslīde: {STRING} STR_CONFIG_SETTING_TRAIN_REVERSING :Neatļaut vilcienu apgriešanos stacijās: {STRING} STR_CONFIG_SETTING_DISASTERS :Katastrofas: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL :Pilsētu domju attieksme pret platības pārstrukturēšanu: {STRING} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL :Maksimālais kartes augstums: {STRING} STR_CONFIG_SETTING_MAX_HEIGHTLEVEL_HELPTEXT :Uzstādīt maksimālo atļauto kalnu augstumu kartē STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Jūs nevarat izmantot šo maksimālo kartes augstumu. Vismaz viens kalns uz kartes ir augstāks. STR_CONFIG_SETTING_AUTOSLOPE :Atļaut ainavas veidošanu zem ekām, ceļiem, utt. (automāt. nogāzes): {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Atļauj ainavas veidošanu zem ekām un ceļiem bez to nojaukšanas STR_CONFIG_SETTING_CATCHMENT :Atļaut realistiskākas, palielinātas apkalpojamās platības: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :Atšķirīga lieluma apkalpojamās platības dažādu veidu stacijām un lidostām STR_CONFIG_SETTING_EXTRADYNAMITE :Atļaut pilsētai piederošo ceļu, tiltu un tuneļu nojaukšanu: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Padara vieglāku pilsētai piederošas infrastruktūras un ēku nojaukšanu STR_CONFIG_SETTING_TRAIN_LENGTH :Maksimālais vilcienu garums: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Izvēlēties vilcienu maksimālo garumu STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} lauciņ{P 0 š i u} STR_CONFIG_SETTING_SMOKE_AMOUNT :Transportlīdzekļu izmešu efektu daudzums: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Nosaka transportlīdzekļu izmesto dūmu un dzirksteļu daudzumu STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Vilcienu paātrinājuma modelis: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Vilcienu paātrinājuma fizikas modeļa izvēle. 'Sākotnējais' modelis apgrūtina pārvietošanos nogāzēs visiem transportlīdzekļiem vienādi. 'Reālistiskais' modelis apgrūtina pārvietošanos nogāzēs un līkumos atkarībā no dažādām sastāva īpašībām. Piemēram, no garuma un vilcējspēka STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Autotransporta līdzekļu paātrinājuma modelis: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Autotransporta līdzekļu paātrinājuma fizikas modeļa izvēle. 'Sākotnējais' modelis apgrūtina pārvietošanos nogāzēs visiem transportlīdzekļiem vienādi. 'Reālistiskais' modelis apgrūtina pārvietošanos nogāzēs un līkumos atkarībā no dažādām dzinēja īpašībām. Piemēram, no vilcējspēka STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Nogāžu stāvums vilcieniem: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Slīpu lauciņu nogāžu stāvums vilcieniem. Augstākas vērtības apgrūtina uzbraukšanu uzkalnā STR_CONFIG_SETTING_PERCENTAGE :{COMMA}% STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS :Nogāžu stāvums autotransporta līdzekļiem: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_SLOPE_STEEPNESS_HELPTEXT :Slīpu lauciņu nogāžu stāvums autotransporta līdzekļiem. Augstākas vērtības apgrūtina uzbraukšanu uzkalnā STR_CONFIG_SETTING_FORBID_90_DEG :Aizliegt vilcieniem un kuģiem veikt 90 grādu pagriezienus: {STRING} STR_CONFIG_SETTING_FORBID_90_DEG_HELPTEXT :90 grādu pagriezieni rodas, ja horizontālam sliežu ceļa posmam tieši seko vertikāls sliežu ceļa posms uz blakus esošā lauciņa. Tādējādi vilciens, šķērsojot lauciņu malas, veic 90 grādu pagriezienu, nevis parasto 45 grādu kā citām sliežu ceļu kombinācijām. Tas attiecas arī uz kuģu pagrieziena lenķiem STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS :Atļaut savienot stacijas, kas neatrodas tieši blakus: {STRING} STR_CONFIG_SETTING_DISTANT_JOIN_STATIONS_HELPTEXT :Atļaut pievienot staciju daļas, tām nesaskaroties ar jau esošajām. Novietojot jaunās daļas, ir nepieciešams nospiest Ctrl+klikšķis STR_CONFIG_SETTING_INFLATION :Inflācija: {STRING} STR_CONFIG_SETTING_INFLATION_HELPTEXT :Atļaut inflāciju ekonomikā, kur izmaksu celšanās nedaudz apsteidz ienākumus STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Maksimālais tiltu garums: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Būvējamo tiltu maksimālais garums STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Maksimālais tiltu augstums: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Būvējamo tiltu maksimālais augstums STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Maksimālais tuneļu garums: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Būvējamo tuneļu maksimālais garums STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Izejvielu ražotņu manuālā būvniecības metode: {STRING} STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Izejvielu ražotņu finansēšanas metode. 'nav' nozīmē ka nav iespējams finansēt jebkuru ražotni. Izvēloties 'ģeoloģiskā izpēte' finansējums ir iespējams, bet būvniecība notiek nejaušās kartes vietās, un var arī neizdoties. Ja ir iestatīts 'kā citām ražotnēm', tad uzņēmumi būvē izejvielu ražotnes tāpat kā pārstrādes, izvēloties jebkuru vēlamo vietu STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :nav STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :kā citām ražotnēm STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :ģeoloģiskā izpēte STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Līdzens laukums ap ražotnēm: {STRING} STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Līdzenas platības lielums ap ražotni. Tas nodrošina ka ap ražotni būs pieejama tukša platība ceļu utt. būvniecībai STR_CONFIG_SETTING_MULTIPINDTOWN :Atļaut vairākas līdzīgas ražotnes vienā pilsētā: {STRING} STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :Parasti pilsēta nevēlas vairāk par vienu ražotni no katra veida. Šis iestatījums atļaus vairākas vienāda veida ražotnes tajā pašā pilsētā STR_CONFIG_SETTING_SIGNALSIDE :Rādīt signālus: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :Izvēlēties kurā ceļa pusē izvietot signālierīces STR_CONFIG_SETTING_SIGNALSIDE_LEFT :kreisajā pusē STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :braukšanas pusē STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :labajā pusē STR_CONFIG_SETTING_SHOWFINANCES :Gada beigās rādīt finanšu pārskatu: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Ja ieslēgts, katra gada beigās uznirst finanšu logs, lai varētu viegli pārbaudīt uzņēmuma finansiālo stāvokli STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Jaunie rīkojumi noklusējumā ir 'bez pieturām': {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Transportlīdzeklis parasti pietur pie katras caurbraucamās stacijas. Ieslēdzot šo iestatījumu, tas dosies cauri visām ceļa stacijām uz savu galamērķi bez pieturām. Ņemiet vērā, ka šis iestatījums nosaka noklusējuma vērtību tikai jaunajiem rīkojumiem. Tomēr ir iespējams katru rīkojumu iestatīt arī atsevišķi STR_CONFIG_SETTING_STOP_LOCATION :Jaunie vilcienu rīkojumi noklusējumā liek apstāties perona {STRING} STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Vieta, kur vilciens apstāsies pie perona noklusējumā. 'Sākumā' ir pie ieejas stacijā, 'vidū' nozīmē perona vidū, un 'beigās' ir tālu prom no ieejas. Ņemiet vērā, ka šis iestatījums nosaka noklusējuma vērtību tikai jaunajiem rīkojumiem. Taču individuālos rīkojumos var noteikt atšķirīgu rīcību STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :sākumā STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :vidū STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :beigās STR_CONFIG_SETTING_AUTOSCROLL :Bīdīt logu, kad peles kursors atrodas tā malā: {STRING} STR_CONFIG_SETTING_AUTOSCROLL_HELPTEXT :Ja iespējots, skatvieta sāk ritināties kad peles kursors ir pie loga malas STR_CONFIG_SETTING_AUTOSCROLL_DISABLED :atspējots STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT_FULLSCREEN :galveno skatvietu, tikai pilnekrāna spēlei STR_CONFIG_SETTING_AUTOSCROLL_MAIN_VIEWPORT :galveno skatvietu STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :katru skatvietu STR_CONFIG_SETTING_BRIBE :Atļaut piekukuļot vietējās pašvaldības: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Lauj uzņēmumiem mēģināt piekukuļot pilsētu vietējo pašvaldību. Ja inspektors paziņo par kukuli, tad uzņēmums pilsētā nevarēs darboties sešus mēnešus STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Atļaut pirkt pārvadājumu izņēmuma tiesības: {STRING} STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Ja uzņēmums pērk pārvadājumu izņēmuma tiesības pilsētā, pretinieku stacijas (pasažieru un kravas) veselu gadu nesaņems nekādu kravu STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Atļaut ēku finansēšanu: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Atļauj uzņēmumiem dot naudu pilsētām jaunu ēku finansēšanai STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Atļaut finansēt vietējo ceļu atjaunošanu: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_ROAD_HELPTEXT :Atļaut uzņēmumiem dot pilsētām naudu ceļu rekonstrukcijai, lai kaitētu ceļu pakalpojumiem pilsētās STR_CONFIG_SETTING_ALLOW_GIVE_MONEY :Atļaut pārsūtīt naudu citiem uzņēmumiem: {STRING} STR_CONFIG_SETTING_ALLOW_GIVE_MONEY_HELPTEXT :Atļauj naudas pārskaitījumus starp uzņēmumiem vairākspēlētāju spēlēs STR_CONFIG_SETTING_FREIGHT_TRAINS :Svara koeficients kravām, lai simulētu smagus vilcienus: {STRING} STR_CONFIG_SETTING_FREIGHT_TRAINS_HELPTEXT :Iestatīt pārvadājamo kravu ietekmi uz vilcieniem. Lielāka vērtība izvirza augstākas kravnesības prasības vilcieniem, sevišķi kalnos STR_CONFIG_SETTING_PLANE_SPEED :Lidmašīnu ātruma pakāpe: {STRING} STR_CONFIG_SETTING_PLANE_SPEED_HELPTEXT :Iestatīt lidmašīnu nosacīto ātrumu salīdzinājumā ar citu veidu transportlīdzekļiem, lai samazinātu lidaparātu ienākumus STR_CONFIG_SETTING_PLANE_SPEED_VALUE :1 / {COMMA} STR_CONFIG_SETTING_PLANE_CRASHES :Lidmašīnu avāriju daudzums: {STRING} STR_CONFIG_SETTING_PLANE_CRASHES_HELPTEXT :Iestatīt lidaparātu avāriju notikšanas iespējamību STR_CONFIG_SETTING_PLANE_CRASHES_NONE :neviena STR_CONFIG_SETTING_PLANE_CRASHES_REDUCED :samazināts STR_CONFIG_SETTING_PLANE_CRASHES_NORMAL :parasts STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD :Atļaut caurbraucamas pieturvietas uz pilsētai piederošiem ceļiem: {STRING} STR_CONFIG_SETTING_STOP_ON_TOWN_ROAD_HELPTEXT :Ļauj būvēt caurbraucamas pieturvietas uz pilsētai piederošiem ceļiem STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD :Atļaut caurbraucamas pieturvietas uz sāncenšu ceļiem: {STRING} STR_CONFIG_SETTING_STOP_ON_COMPETITOR_ROAD_HELPTEXT :Ļauj būvēt caurbraucamas pieturvietas uz citiem uzņēmumiem piederošiem ceļiem STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Šo iestatījumu nav iespējams mainīt, kad tur ir transportlīdzekļi STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Infrastruktūras uzturēšana: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Lidostas darbosies mūžīgi: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Ieslēdzot šo iestatījumu, katrs lidostas veids pēc tā ieviešanas vienmēr ir pieejams STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Brīdināt, ja transportlīdzeklis ir noklīdis: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Ieslēdz ziņojumus par transportlīdzekļiem, kas nespēj atrast ceļu uz norīkoto galamērķi STR_CONFIG_SETTING_ORDER_REVIEW :Pārbaudīt transportlīdzekļu rīkojumus: {STRING} STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Ja ieslēgts, tad transportlīdzekļu rīkojumus pastāvīgi pārbauda, un par dažām atklātajām problēmām tiek saņemti ziņojumi STR_CONFIG_SETTING_ORDER_REVIEW_OFF :nē STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :jā, izņemot apturētajiem STR_CONFIG_SETTING_ORDER_REVIEW_ON :visiem transportlīdzekļiem STR_CONFIG_SETTING_WARN_INCOME_LESS :Brīdināt, ja transportlīdzekļa ienākumi ir negatīvi: {STRING} STR_CONFIG_SETTING_WARN_INCOME_LESS_HELPTEXT :Ja ieslēgts, tiks sūtīts ziņojums gadījumā kad transportlīdzeklis negūst nekādu peļņu kalendārā gada laikā STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES :Transportlīdzekļi nekad "nemirst": {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_VEHICLES_HELPTEXT :Kad ieslēgts, visi transportlīdzekļu modeļi pēc to ieviešanas vienmēr ir pieejami STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Automātiski atjaunot transportlīdzekļus, kad tie ir kļuvuši veci: {STRING} STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :Ja ieslēgts, kad ir atbilstoši atjaunošanas apstākļi, automātiski tiek nomainīti transportlīdzekļi kuru kalpošanas laiks tuvojas beigām STR_CONFIG_SETTING_AUTORENEW_MONTHS :Automātiski atjaunot transportlīdzekļus {STRING} maksimālā vecuma STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Nosacītais vecums, kad transportlīdzeklis ir uzskatāms par automātiski atjaunojamu STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :{COMMA} mēne{P 0 si šus šu} pirms STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :{COMMA} mēne{P 0 si šus šu} pēc STR_CONFIG_SETTING_AUTORENEW_MONEY :Automātiski papildināt minimālo naudas daudzumu atjaunošanai: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Minimālais naudas atlikuma lielums bankā, pirms apsver transportlīdzekļu automātisko atjaunošanu STR_CONFIG_SETTING_ERRMSG_DURATION :Kļūdas ziņojuma ilgums: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Kļūdas ziņojuma sarkanā logā rādīšanas ilgums. Jāņem vērā ka daži (kritiskie) kļūdu ziņojumi pēc šī laika netiek slēgti automātiski, bet tos ir jāaizver manuāli STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} sekun{P 0 di des žu} STR_CONFIG_SETTING_HOVER_DELAY :Rādīt rīku padomus: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Aizkaves ilgums, pirms tiek rādīti rīku padomi, kad peles kursors atrodas virs kāda saskarnes elementa. Rīku padomu rādīšanu pārmaiņus var saistīt ar peles labās pogas klikšķi STR_CONFIG_SETTING_HOVER_DELAY_VALUE :{COMMA} sekun{P 0 di des žu} STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :labais klikšķis STR_CONFIG_SETTING_POPULATION_IN_LABEL :Rādīt pilsētas iedzīvotāju skaitu pie tās nosaukuma apzīmējuma: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Rāda pilsētu iedzīvotāju daudzumu pie to apzīmējumiem uz kartes STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Diagrammu līniju platums: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Diagrammu līniju platums. Šauras līnijas ir precīzāk nolasāmas, platākas vieglāk saskatīt un atšķirt to krāsas STR_CONFIG_SETTING_LANDSCAPE :Ainava: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR :Zemes radītājs: {STRING} STR_CONFIG_SETTING_LAND_GENERATOR_ORIGINAL :Sākotnējais STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Maksimālais attālums no kartes malas naftas pārstrādes rūpnīcām: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Naftas pārstrādes rūpnīcas ir būvējamas tikai kartes malu tuvumā, salu kartēm tas ir pie krasta STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Sniega līnijas augstums: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Apvidus nelīdzenums: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Ļoti gluda STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Gluda STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Nelīdzena STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Ļoti nelīdzena STR_CONFIG_SETTING_TREE_PLACER :Koku izvietošanas algoritms: {STRING} STR_CONFIG_SETTING_TREE_PLACER_NONE :Nav STR_CONFIG_SETTING_TREE_PLACER_ORIGINAL :Sākotnējais STR_CONFIG_SETTING_TREE_PLACER_IMPROVED :Uzlabotais STR_CONFIG_SETTING_ROAD_SIDE :Autotransporta līdzekļi: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION :Augstumu kartes pagriešana: {STRING} STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_COUNTER_CLOCKWISE :Pret pulksteņa rādītāja virzienu STR_CONFIG_SETTING_HEIGHTMAP_ROTATION_CLOCKWISE :Pulksteņa rādītāja virzienā STR_CONFIG_SETTING_SE_FLAT_WORLD_HEIGHT :Augstuma līmenis līdzenai scenārija kartei: {STRING} STR_CONFIG_SETTING_EDGES_NOT_EMPTY :{WHITE}Viens vai vairāki lauciņi pie ziemeļu malas nav tukši STR_CONFIG_SETTING_EDGES_NOT_WATER :{WHITE}Vienam vai vairākiem lauciņiem kādā malā nav ūdens STR_CONFIG_SETTING_STATION_SPREAD :Maksimālais staciju lielums: {STRING} STR_CONFIG_SETTING_STATION_SPREAD_HELPTEXT :Maksimālais laukums kuru var aizņemt atsevišķas stacijas izvietotās daļas. Jāņem vērā ka lielas vērtības palēninās spēli STR_CONFIG_SETTING_SERVICEATHELIPAD :Veikt helikopteru automātisko apkopi nolaišanās laukumos: {STRING} STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :Helikopteriem veikt apkopi pēc katras nolaišanās, arī ja lidostā nav helikopteru bāzes STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :Sasaitēt ainavas rīkjoslu ar sliežu/ceļu/ūdens/lidostu rīkjoslām: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :Atverot būvniecības rīkjoslas transportlīdzekļu veidiem, tiek atvērta arī ainavu veidošanas rīkjosla STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :Kartes zemes krāsa: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Apvidus krāsa minikartē STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :zaļa STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :{G=f}tumši zaļa STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :{G=f}violeta STR_CONFIG_SETTING_REVERSE_SCROLLING :Pretējs ritināšanas virziens: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING :Plūdena skatvietas ritināšana: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP :Rādīt mērījumu rīkjoslu, izmantojot dažādus būvniecības rīkus: {STRING} STR_CONFIG_SETTING_MEASURE_TOOLTIP_HELPTEXT :Rāda lauciņu attālumus un augstuma starpības, ar vilkšanu veicot būvniecības darbības STR_CONFIG_SETTING_LIVERIES :Rādīt uzņēmuma identitātes krāsas: {STRING} STR_CONFIG_SETTING_LIVERIES_HELPTEXT :Atšķirīga krāsojuma izmantošana dažādiem transportlīdzekļu veidiem (pretēji uzņēmuma identifikācijas krāsām) STR_CONFIG_SETTING_LIVERIES_NONE :nerādīt STR_CONFIG_SETTING_LIVERIES_OWN :savam uzņēmumam STR_CONFIG_SETTING_LIVERIES_ALL :visiem uzņēmumiem STR_CONFIG_SETTING_PREFER_TEAMCHAT :Dot priekšroku komandas tērzēšanai ar : {STRING} STR_CONFIG_SETTING_PREFER_TEAMCHAT_HELPTEXT :Ieslēgt uzņēmuma iekšējās tērzēšanas piesaisti ar un publiskās ar STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING :Peles ritenīša funkcija: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_SCROLLING_HELPTEXT :Ieslēgt ritināšanu ar divdimensiju peles ritenīti STR_CONFIG_SETTING_SCROLLWHEEL_ZOOM :pietuvināt karti STR_CONFIG_SETTING_SCROLLWHEEL_SCROLL :ritināt karti STR_CONFIG_SETTING_SCROLLWHEEL_OFF :izslēgts STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER :Peles ritenīša ātrums: {STRING} STR_CONFIG_SETTING_SCROLLWHEEL_MULTIPLIER_HELPTEXT :Vadīt peles ritenīša ritināšanas jutīgumu STR_CONFIG_SETTING_OSK_ACTIVATION :Ekrāntastatūra: {STRING} STR_CONFIG_SETTING_OSK_ACTIVATION_DISABLED :atspējota STR_CONFIG_SETTING_OSK_ACTIVATION_DOUBLE_CLICK :dubultklikšķis STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK_FOCUS :viens klikšķis (kad fokusēta) STR_CONFIG_SETTING_OSK_ACTIVATION_SINGLE_CLICK :viens klikšķis (nekavējoties) STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU :Labā klikšķa emulēšana: {STRING} STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_HELPTEXT :Izvēlēties peles labās pogas klikšķu emulēšanas paņēmienu STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Komanda+klikšķis STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Ctrl+klikšķis STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Izslēgta STR_CONFIG_SETTING_LEFT_MOUSE_BTN_SCROLLING :Kreisā klikšķa ritināšana: {STRING} STR_CONFIG_SETTING_AUTOSAVE :Automātiskā saglabāšana: {STRING} STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Lietot {STRING} datuma formātu saglabāto spēļu nosaukumos STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Datuma formāts spēļu saglabājuma failu nosaukumos STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :garu (31. Dec 2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :īsu (31-12-2008) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_ISO :ISO (2008-12-31) STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME :Automātiski pauzēt sākot jaunu spēli: {STRING} STR_CONFIG_SETTING_PAUSE_ON_NEW_GAME_HELPTEXT :Ja ir ieslēgts, sākot jaunu spēli, tā tiek automātiski pauzēta. Tas ļauj rūpīgāk izpētīt karti STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL :Pauzes režīmā atļaut: {STRING} STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_HELPTEXT :Izvēlēties veicamās darbības pauzētas spēles brīdī STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_NO_ACTIONS :nē, neatļaut darbības STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_CONSTRUCTION :visas, izņemot būvniecības darbības STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_NON_LANDSCAPING :visas, izņemot ainavas pārveidošanas darbības STR_CONFIG_SETTING_COMMAND_PAUSE_LEVEL_ALL_ACTIONS :visas darbības STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS :Lietot papildināto transportlīdzekļu sarakstu: {STRING} STR_CONFIG_SETTING_ADVANCED_VEHICLE_LISTS_HELPTEXT :Ieslēgt papildināto transportlīdzekļu sarakstu grupētiem transportlīdzekļiem STR_CONFIG_SETTING_LOADING_INDICATORS :Lietot piekraušanas rādītājus: {STRING} STR_CONFIG_SETTING_LOADING_INDICATORS_HELPTEXT :Izvēlēties piekraušanas rādītāju attēlošanu virs iekraujamiem un izkraujamiem transportlīdzekļiem STR_CONFIG_SETTING_TIMETABLE_IN_TICKS :Kustības sarakstu rādīt mirkļos nevis dienās: {STRING} STR_CONFIG_SETTING_TIMETABLE_IN_TICKS_HELPTEXT :Kustības sarakstos laikus rādīt spēles mirkļos, nevis dienās STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE :Kustības sarakstos rādīt pienākšanu un atiešanu: {STRING} STR_CONFIG_SETTING_TIMETABLE_SHOW_ARRIVAL_DEPARTURE_HELPTEXT :Kustības sarakstos rādīt paredzamos pienākšanas un atiešanas laikus STR_CONFIG_SETTING_QUICKGOTO :Transportlīdzekļu rīkojumu ātrā veidošana: {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE :Noklusējuma sliežu veids (pēc jaunas spēles/spēles ielādes): {STRING} STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_HELPTEXT :Izvēlētais sliežu veids sākot vai ielādējot spēli. 'Pirmās pieejamās' ir vecākā veida, 'pēdējās pieejamās' ir jaunākā veida, un 'visbiežāk lietotās' ir pašlaik visvairāk lietoto sliežu ceļu izvēlnes STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_FIRST :pirmās pieejamās STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_LAST :pēdējās pieejamās STR_CONFIG_SETTING_DEFAULT_RAIL_TYPE_MOST_USED :visbiežāk lietotās STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION :Rādīt rezerves sliežu ceļus: {STRING} STR_CONFIG_SETTING_SHOW_TRACK_RESERVATION_HELPTEXT :Piešķirt rezerves sliežu ceļiem atšķirīgu krāsojumu, lai palīdzētu grūtībās ar atteikumiem vilcieniem iebraukt ceļu blokos STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :Būvniecības rīkus pēc lietošanas paturēt darbīgus: {STRING} STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Pēc lietošanas patur atvērtus tiltu, tuneļu un citus būvniecības rīkus STR_CONFIG_SETTING_EXPENSES_LAYOUT :Grupēt izdevumu sadaļas uzņēmuma finanšu informācijas logā: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Noteikt uzņēmuma izdevumu loga izkārtojumu STR_CONFIG_SETTING_SOUND_TICKER :Jaunumu josla: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Atskaņot apkopotu jaunumu ziņojumu skaņu STR_CONFIG_SETTING_SOUND_NEWS :Avīze: {STRING} STR_CONFIG_SETTING_SOUND_NEWS_HELPTEXT :Atskaņot skaņu kad tiek rādītas avīzes STR_CONFIG_SETTING_SOUND_NEW_YEAR :Gada beigas: {STRING} STR_CONFIG_SETTING_SOUND_NEW_YEAR_HELPTEXT :Atskaņot skaņu gada beigās, apkopojot uzņēmuma darbības sasniegumus gada laikā salīdzinājumā ar iepriekšējo gadu STR_CONFIG_SETTING_SOUND_CONFIRM :Būvniecība: {STRING} STR_CONFIG_SETTING_SOUND_CONFIRM_HELPTEXT :Atskaņot skaņu pēc sekmīgas būvēšanas vai citām darbībām STR_CONFIG_SETTING_SOUND_CLICK :Pogu klikšķi: {STRING} STR_CONFIG_SETTING_SOUND_CLICK_HELPTEXT :Skan signāls, kad noklikšķina uz pogas STR_CONFIG_SETTING_SOUND_DISASTER :Katastrofas/negadījumi: {STRING} STR_CONFIG_SETTING_SOUND_DISASTER_HELPTEXT :Atskaņot negadījumu un katastrofu skaņu efektus STR_CONFIG_SETTING_SOUND_VEHICLE :Transportlīdzekļi: {STRING} STR_CONFIG_SETTING_SOUND_VEHICLE_HELPTEXT :Atskaņot transportlīdzekļu skaņu efektus STR_CONFIG_SETTING_SOUND_AMBIENT :Apkārtne: {STRING} STR_CONFIG_SETTING_SOUND_AMBIENT_HELPTEXT :Atskaņot ainavas, ražotņu un pilsētu apkārtējās skaņas STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING :Atspējot infrastruktūras būvēšanu, ja nav piemērotu transportlīdzekļu: {STRING} STR_CONFIG_SETTING_DISABLE_UNSUITABLE_BUILDING_HELPTEXT :Ja ieslēgts, infrastruktūra ir pieejama tikai tad, ja tur ir pieejami arī transportlīdzekļi, novēršot laika un naudas izšķiešanu par nelietojamu infrastruktūru STR_CONFIG_SETTING_MAX_TRAINS :Maksimālais vilcienu skaits uzņēmumā: {STRING} STR_CONFIG_SETTING_MAX_TRAINS_HELPTEXT :Maksimālais vilcienu skaits, kas var piederēt uzņēmumam STR_CONFIG_SETTING_MAX_ROAD_VEHICLES :Maksimālais autotransporta līdzekļu skaits uzņēmumā: {STRING} STR_CONFIG_SETTING_MAX_ROAD_VEHICLES_HELPTEXT :Maksimālais autotransporta līdzekļu skaits, kas var piederēt uzņēmumam STR_CONFIG_SETTING_MAX_AIRCRAFT :Maksimālais lidaparātu skaits uzņēmumā: {STRING} STR_CONFIG_SETTING_MAX_AIRCRAFT_HELPTEXT :Maksimālais lidaparātu skaits, kas var piederēt uzņēmumam STR_CONFIG_SETTING_MAX_SHIPS :Maksimālais kuģu skaits uzņēmumā: {STRING} STR_CONFIG_SETTING_MAX_SHIPS_HELPTEXT :Maksimālais kuģu skaits, kas var piederēt uzņēmumam STR_CONFIG_SETTING_AI_BUILDS_TRAINS :Atspējot datoram vilcienus: {STRING} STR_CONFIG_SETTING_AI_BUILDS_TRAINS_HELPTEXT :Šā iestatījuma ieslēgšana padara neiespējamu vilcienu būvēšanu datoram STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES :Atspējot datoram autotransporta līdzekļus: {STRING} STR_CONFIG_SETTING_AI_BUILDS_ROAD_VEHICLES_HELPTEXT :Šā iestatījuma ieslēgšana padara neiespējamu autotransporta līdzekļu būvēšanu datoram STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT :Atspējot datoram lidaparātus: {STRING} STR_CONFIG_SETTING_AI_BUILDS_AIRCRAFT_HELPTEXT :Šā iestatījuma ieslēgšana padara neiespējamu lidaparātu būvēšanu datoram STR_CONFIG_SETTING_AI_BUILDS_SHIPS :Atspējot datoram kuģus: {STRING} STR_CONFIG_SETTING_AI_BUILDS_SHIPS_HELPTEXT :Šā iestatījuma ieslēgšana padara neiespējamu kuģu būvēšanu datoram STR_CONFIG_SETTING_AI_PROFILE :Noklusējuma iestatījumu profils: {STRING} STR_CONFIG_SETTING_AI_PROFILE_EASY :viegls STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :vidējs STR_CONFIG_SETTING_AI_PROFILE_HARD :smags STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Atļaut MI vairākspēlētāju spēlēs: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Atļaut MI (mākslīgā intelekta) nespēlētāju tēliem (datora vadītiem) piedalīties vairākspēlētāju spēlēs STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :#darbību kodi, pirms skripti tiek apstādināti: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT :Apkopju starplaiki procentos: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS :Vilcienu apkopju noklusējuma starplaiks: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Izvēlēties jaunajiem sliežu transportlīdzekļiem apkopju noklusējuma starplaiku, ja tiem tas nav noteikts STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}dien{P 0 a as u}/% STR_CONFIG_SETTING_SERVINT_DISABLED :izslēgts STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Autotransporta līdzekļu apkopju noklusējuma starplaiks: {STRING} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Izvēlēties jauniem autotransporta līdzekļiem apkopju noklusējuma starplaiku, ja transportlīdzeklim tas nav noteikts STR_CONFIG_SETTING_SERVINT_AIRCRAFT :Lidaparātu apkopju noklusējuma starplaiks: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :Izvēlēties jauniem lidaparātiem apkopju noklusējuma starplaiku, ja transportlīdzeklim tas nav noteikts STR_CONFIG_SETTING_SERVINT_SHIPS :Kuģu apkopju noklusējuma starplaiks: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :Izvēlēties jauniem kuģiem apkopju noklusējuma starplaiku, ja transportlīdzeklim tas nav noteikts STR_CONFIG_SETTING_NOSERVICE :Aizliegt apkopi, kad bojāšanās ir izslēgta: {STRING} STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :Ja ieslēgts, transportlīdzekļiem netiek veikta apkope. Jo tie nebojājas STR_CONFIG_SETTING_WAGONSPEEDLIMITS :Ieslēgt vagonu ātruma ierobežojumus: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :Ja ieslēgts, var izmantot vagonu ātruma ierobežojumus, lai lemtu par vilcienu maksimālo ātrumu STR_CONFIG_SETTING_DISABLE_ELRAILS :Atspējot elektrificēto dzelzceļu: {STRING} STR_CONFIG_SETTING_DISABLE_ELRAILS_HELPTEXT :Šī iestatījuma ieslēgšana atcels ceļu elektrifikācijas prasību, lai pa tiem varētu pārvietoties elektrolokomotīves STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN :Spēlētaja stacijā ierodas pirmais transportlīdzeklis: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OWN_HELPTEXT :Rādīt avīzi kad spēlētāja jaunajā stacijā ierodas pirmais transportlīdzeklis STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER :Sāncenša stacijā ierodas pirmais transportlīdzeklis: {STRING} STR_CONFIG_SETTING_NEWS_ARRIVAL_FIRST_VEHICLE_OTHER_HELPTEXT :Rādīt avīzi kad sāncenša jaunajā stacijā ierodas pirmais transportlīdzeklis STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS :Negadījumi / katastrofas: {STRING} STR_CONFIG_SETTING_NEWS_ACCIDENTS_DISASTERS_HELPTEXT :Rādīt avīzi, kad notiek nelaimes gadījumi vai katastrofas STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION :Uzņēmuma informācija: {STRING} STR_CONFIG_SETTING_NEWS_COMPANY_INFORMATION_HELPTEXT :Rādīt avīzi kad darbību sāk jauns uzņēmums, vai kad uzņēmumi riskē bankrotēt STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN :Ražotņu atklāšana: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_OPEN_HELPTEXT :Rādīt avīzi, kad tiek atklāti jauni uzņēmumi STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE :Ražotņu slēgšana: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CLOSE_HELPTEXT :Rādīt avīzi, kad uzņēmumi tiek slēgti STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES :Ekonomikas izmaiņas: {STRING} STR_CONFIG_SETTING_NEWS_ECONOMY_CHANGES_HELPTEXT :Rādīt avīzi par globālām izmaiņām ekonomikā STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY :Ražošanas izmaiņas uzņēmuma apkalpotajās ražotnēs: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_COMPANY_HELPTEXT :Rādīt avīzi kad mainās uzņēmuma darbināto ražotņu ražošanas līmenis STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER :Ražošanas izmaiņas sāncenšu apkalpotajās ražotnēs: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_OTHER_HELPTEXT :Rādīt avīzi kad mainās sāncenšu darbināto ražotņu ražošanas līmenis STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED :Citas ražošanas apjomu izmaiņas: {STRING} STR_CONFIG_SETTING_NEWS_INDUSTRY_CHANGES_UNSERVED_HELPTEXT :Rādīt avīzi kad mainās uzņēmuma vai sāncenšu nedarbināto ražotņu ražošanas līmenis STR_CONFIG_SETTING_NEWS_ADVICE :Padomi / informācija par uzņēmuma transportlīdzekļiem: {STRING} STR_CONFIG_SETTING_NEWS_ADVICE_HELPTEXT :Rādīt ziņojumus par transportlīdzekļiem, kuriem ir jāpievērš uzmanību STR_CONFIG_SETTING_NEWS_NEW_VEHICLES :Jauni transportlīdzekļi: {STRING} STR_CONFIG_SETTING_NEWS_NEW_VEHICLES_HELPTEXT :Rādīt avīzi kad transportlīdzekļa veids ir kļuvis pieejams STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE :Izmaiņas kravu pieņemšanā: {STRING} STR_CONFIG_SETTING_NEWS_CHANGES_ACCEPTANCE_HELPTEXT :Rādīt ziņojumus par izmaiņām dažu kravu pieņemšanā stacijās STR_CONFIG_SETTING_NEWS_SUBSIDIES :Subsīdijas: {STRING} STR_CONFIG_SETTING_NEWS_SUBSIDIES_HELPTEXT :Rādīt avīzi par notikumiem, saistītiem ar subsīdijām STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION :Vispārējā informācija: {STRING} STR_CONFIG_SETTING_NEWS_GENERAL_INFORMATION_HELPTEXT :Rādīt avīzi par vispārējiem pasākumiem, tādiem kā izņēmuma tiesību pirkšana vai ceļu rekonstrukcijas finansēšana STR_CONFIG_SETTING_NEWS_MESSAGES_OFF :izslēgts STR_CONFIG_SETTING_NEWS_MESSAGES_SUMMARY :kopsavilkums STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :pilns STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Krāsaini avīžu raksti parādās: {STRING} gadā STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Gads kad sāk drukāt krāsainas avīzes. Pirms šā gada tās ir melnbaltas STR_CONFIG_SETTING_STARTING_YEAR :Sākuma gads: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Atļaut vienmērīgas izmaiņas ekonomikā: {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Ja ieslēgts, ražošanas izmaiņas notiek biežāk un ar mazākiem soļiem. Šim iestatījumam parasti nav ietekmes, ja ražotņu veidi ir ieviesti ar NewGRF STR_CONFIG_SETTING_ALLOW_SHARES :Atļaut akciju pirkšanu no citiem uzņēmumiem: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Ja iespējots, ir atļauts pirkt un pārdodot uzņēmumu akcijas. Akcijas būs pieejamas tikai atbilstošu vecumu sasniegušiem uzņēmumiem STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Procenti no kopējās peļņas, ko maksā tranzītstacijās: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Velkot izvietot signālierīces uz katra: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Iestatīt attālumus, kādos līdz nākamajam šķērslim (signālierīcei, dzelzceļa mezglam) uz ceļa tiks būvētas signālierīces, ja tās tiek vilktas STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} lauciņ{P 0 a a a} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :Velkot paturēt vienādu attālumu starp signālierīcēm: {STRING} STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :Signālierīču izvietošanas uzvedības izvēle, kad to veic ar Ctrl+velkot. Ja izslēgts, signālierīces tiek novietotas pie tuneļiem un tiltiem, lai izvairītos no gariem posmiem bez signālierīcēm. Ja ieslēgts, signālierīces tiek izvietotas uz katra N lauciņa, atvieglojot to izkārtošanu uz paralēliem sliežu ceļiem STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Automātiski būvēt semaforus pirms: {STRING} gada STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Izvēlēties gadu, kad ceļiem sāks izmantot elektriskās signālierīces. Pirms šā gada tiks izmantotas neelektriskās signālierīces (kam ir tieši tāda pati funkcija, bet ar atšķirīgu izskatu) STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :Ieslēgt signālierīču grafisko lietotāja saskarni: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :Noklusējuma signālu veids: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :Izmantotais noklusējuma signālu veids STR_CONFIG_SETTING_DEFAULT_SIGNAL_NORMAL :bloķēšanas signāli STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBS :ceļa signāli STR_CONFIG_SETTING_DEFAULT_SIGNAL_PBSOWAY :vienvirziena ceļa signāli STR_CONFIG_SETTING_CYCLE_SIGNAL_TYPES :Braukt garām signālu veidiem: {STRING} STR_CONFIG_SETTING_CYCLE_SIGNAL_NORMAL :tikai bloķēšanas signāliem STR_CONFIG_SETTING_CYCLE_SIGNAL_PBS :tikai ceļa signāliem STR_CONFIG_SETTING_CYCLE_SIGNAL_ALL :visiem STR_CONFIG_SETTING_TOWN_LAYOUT :Ceļu izkārtojums jaunajām pilsētām: {STRING} STR_CONFIG_SETTING_TOWN_LAYOUT_HELPTEXT :Pilsētu ceļu tīkla izkārtojums STR_CONFIG_SETTING_TOWN_LAYOUT_DEFAULT :sākotnējais STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :labāki ceļi STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 režģis STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 režģis STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :nejaušs STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Pilsētām ir atļauts būvēt ceļus: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Ļauj pilsētām būvēt ceļus izaugsmes sekmēšanai. Izslēgt, lai pilsētu vietējās pašvaldības pašas nebūvētu ceļus STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Pilsētam ir atļauts būvēt vienlīmeņa krustojumus: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Šā iestatījuma ieslēgšana pilsētām atļauj būvēt vienlīmeņa krustojumus STR_CONFIG_SETTING_NOISE_LEVEL :Atļaut pilsētām kontrolēt trokšņu līmeni lidostās: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :Ja šis iestatījums ir izslēgts, tad katrā pilsētā var būt divas lidostas. Ja šis iestatījums ir ieslēgts, tad lidostu daudzums pilsētā ir ierobežots ar pilsētas piekrišanu troksnim, kas ir atkarīga no iedzīvotāju skaita, lidostas lieluma un attāluma STR_CONFIG_SETTING_TOWN_FOUNDING :Pilsētu dibināšana: {STRING} STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Šā iestatījuma ieslēgšana atļauj spēlētājiem spēlē nodibināt jaunas pilsētas STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :aizliegta STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :atļauta STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :atļauta, ar brīvi izvēlētu izkārtojumu STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Koku izvietojums spēlē: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Vadīt nejaušu koku parādīšanos spēles laikā. Tas var ietekmēt no kokaudzēšanas atkarīgas ražotnes, piemēram kokzāģētavas STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NONE :nav {RED}(nedarbosies kokzāģētavas) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_RAINFOREST :tikai lietusmežos STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_ALL :visur STR_CONFIG_SETTING_TOOLBAR_POS :Galvenās rīkjoslas novietojums: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Galvenās rīkjoslas horizontālais novietojums ekrāna augšējā daļā STR_CONFIG_SETTING_STATUSBAR_POS :Stāvokļa joslas novietojums: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Stāvokļa joslas horizontālais novietojums ekrāna apakšējā daļā STR_CONFIG_SETTING_SNAP_RADIUS :Logu pielipšanas rādiuss: {STRING} STR_CONFIG_SETTING_SNAP_RADIUS_HELPTEXT :Attālums starp logiem, kad pārvietojamais logs tiek automātiski pielīdzināts tuvākajiem STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pikse{P 0 lis ļi ļu} STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :izslēgts STR_CONFIG_SETTING_SOFT_LIMIT :Maksimālais logu skaits: {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Atvērtu nepielipušo logu skaits, pirms tie tiek automātiski aizvērti lai atbrīvotu vietu jauniem logiem STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :izslēgts STR_CONFIG_SETTING_ZOOM_MIN :Maksimālais pietuvinājuma līmenis: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Maksimālais pietuvinājuma līmenis skatvietām. Ir jāievēro ka paaugstinot pietuvinājuma līmeni, pieaug operatīvās atmiņas izlietojums STR_CONFIG_SETTING_ZOOM_MAX :Maksimālais attālinājuma līmenis: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :Maksimālais attālinājuma līmenis skatvietām. Lielāka attālinājuma līmeņa pielietošana var būt iemesls aizkavējumiem STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Parasts STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x STR_CONFIG_SETTING_TOWN_GROWTH :Pilsētu attīstības ātrums: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Ātrums ar kuru attīstīsies pilsētas STR_CONFIG_SETTING_TOWN_GROWTH_NONE :nav STR_CONFIG_SETTING_TOWN_GROWTH_SLOW :mazs STR_CONFIG_SETTING_TOWN_GROWTH_NORMAL :vidējs STR_CONFIG_SETTING_TOWN_GROWTH_FAST :liels STR_CONFIG_SETTING_TOWN_GROWTH_VERY_FAST :ļoti liels STR_CONFIG_SETTING_LARGER_TOWNS :Pilsētu daļa kas kļūs par lielpilsētām: {STRING} STR_CONFIG_SETTING_LARGER_TOWNS_HELPTEXT :Pilsētu daudzums kas kļūs par lielpilsētām, tādēļ tās sākumā ir lielākas un attīstās ātrāk STR_CONFIG_SETTING_LARGER_TOWNS_VALUE :1 pret {COMMA} STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :neviena STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Lielpilsētu sākuma lieluma reizinātājs: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Lielpilsētu vidējais lielums attiecībā pret parastām pilsētām spēles sākumā STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manuāli STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimetriska STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simetriska STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Sadales precizitāte: {STRING} STR_CONFIG_SETTING_DEMAND_SIZE_HELPTEXT :Uzstādod šo mazāk par 100% liks simetriskajai sadalei izturēties vairāk kā asimetriskajai. Mazāk kravas ar varu tiks sūtīts atpakaļ ja noteikts daudzums tiks sūtīts uz piestātni. Ja jūs uzstādīsiet to uz 0% simetriskā sadale izturēsies tā pat kā asimetriskā. STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :Ātruma mērvienības: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Vai lietotāja saskarnē rāda ātrumu, rādīt norādītajās mērvienībās STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :impērijas, britu (jūdzes stundā) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :metriskās (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI, starptautiskās (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Transportlīdzekļu jaudas mērvienības: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Vai lietotāja saskarnē rāda transporta līdzekļa jaudu, rādīt norādītajās mērvienībās STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :impērijas, britu (ZS) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :metriskās (ZS) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI, starptautiskās (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :Svara mērvienības: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :Kad lietotāja saskarnē rāda svaru, uzrādīt to norādītajās mērvienībās STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :impērijas, britu (t/tonna) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :metriskās (t/tonna) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :SI, starptautiskās (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :Tilpuma mērvienības: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :Kad lietotāja saskarnē rāda tilpumu, uzrādīt to norādītajās mērvienībās STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :impērijas, britu (galons) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :metriskās (l) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :SI, starptautiskās (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI.kas :SI, starptautiskās (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :Vilces spēka mērvienības: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE.kas :Vilces spēka mērvienības: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :Kad lietotāja saskarnē rāda vilcējspēku, uzrādīt to norādītajās mērvienībās STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :impērijas, britu (mārciņa) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :metriskās (spēka kilograms) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :SI, starptautiskās (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :Augstuma mērvienības: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :Kad lietotāja saskarnē rāda augstumu, uzrādīt to norādītajās mērvienībās STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :impērijas, britu (pēda) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :metriskās (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI, starptautiskās (m) STR_CONFIG_SETTING_LOCALISATION :{ORANGE}Lokalizēšana STR_CONFIG_SETTING_GRAPHICS :{ORANGE}Grafika STR_CONFIG_SETTING_SOUND :{ORANGE}Skaņa STR_CONFIG_SETTING_INTERFACE :{ORANGE}Saskarne STR_CONFIG_SETTING_INTERFACE_GENERAL :{ORANGE}Vispārīgi STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :{ORANGE}Skatvietas STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}Būvniecība STR_CONFIG_SETTING_ADVISORS :{ORANGE}Avīžu raksti / padomnieki STR_CONFIG_SETTING_COMPANY :{ORANGE}Uzņēmums STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Grāmatvedība STR_CONFIG_SETTING_VEHICLES :{ORANGE}Transportlīdzekļi STR_CONFIG_SETTING_VEHICLES_PHYSICS :{ORANGE}Fizika STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Pārvietošanās STR_CONFIG_SETTING_LIMITATIONS :{ORANGE}Ierobežojumi STR_CONFIG_SETTING_ACCIDENTS :{ORANGE}Katastrofas / negadījumi STR_CONFIG_SETTING_GENWORLD :{ORANGE}Pasaules radīšana STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}Apkārtējā vide STR_CONFIG_SETTING_ENVIRONMENT_AUTHORITIES :{ORANGE}Pašvaldības STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}Pilsētas STR_CONFIG_SETTING_ENVIRONMENT_INDUSTRIES :{ORANGE}Ražotnes STR_CONFIG_SETTING_ENVIRONMENT_CARGODIST :{ORANGE}Kravu sadale STR_CONFIG_SETTING_AI :{ORANGE}Sāncenši STR_CONFIG_SETTING_AI_NPC :{ORANGE}Nespēlētāju tēli (datora vadīti) STR_CONFIG_SETTING_PATHFINDER_OPF :Sākotnējais STR_CONFIG_SETTING_PATHFINDER_NPF :NPF STR_CONFIG_SETTING_PATHFINDER_YAPF_RECOMMENDED :YAPF {BLUE}(ieteicamais) STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS :Vilcienu ceļa meklētājs: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_TRAINS_HELPTEXT :Vilcieniem pielietotais ceļa meklētājs STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES :Autotransporta līdzekļu ceļa meklētājs: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_ROAD_VEHICLES_HELPTEXT :Autotransporta līdzekļiem pielietotais ceļa meklētājs STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS :Kuģu ceļa meklētājs: {STRING} STR_CONFIG_SETTING_PATHFINDER_FOR_SHIPS_HELPTEXT :Kuģiem pielietotais ceļa meklētājs STR_CONFIG_SETTING_REVERSE_AT_SIGNALS :Automātiska apgriešanās pie luksoforiem: {STRING} STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Atļauj vilcieniem apgriezties pie signālierīcēm, ja tie te ir gaidījuši ilgu laiku STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Mainīt iestatījuma vērtību # Config errors STR_CONFIG_ERROR :{WHITE}Kļūda konfigurācijas failā... STR_CONFIG_ERROR_ARRAY :{WHITE}... kļūda masīvā '{STRING}' STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... nederīga vērtība '{STRING}' priekš '{STRING}' STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... sekojošās rakstzīmes iestatījuma '{STRING}' beigās STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... ignorē NewGRF '{STRING}': dublējošs GRF ID ar '{STRING}' STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... ignorē nederīgu NewGRF '{STRING}': {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :nav atrasts STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :nav drošs statiskai lietošanai STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :sistēmas NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :nav savietojams ar šo OpenTTD versiju STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :nezināms STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... saspiešanas līmenis '{STRING}' ir nederīgs STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... spēles saglabāšanas formāts '{STRING}' nav pieejams. Atkāpjas uz '{STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignorē pamata grafikas kopu '{STRING}': nav atrasta STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignorē pamata skaņas kopu '{STRING}': nav atrasta STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignorē pamata mūzikas kopu '{STRING}': nav atrasta STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Nepietiek atmiņas # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} STR_INTRO_NEW_GAME :{BLACK}Jauna spēle STR_INTRO_LOAD_GAME :{BLACK}Ielādēt spēli STR_INTRO_PLAY_SCENARIO :{BLACK}Spēlēt scenāriju STR_INTRO_PLAY_HEIGHTMAP :{BLACK}Spēlēt augstumu karti STR_INTRO_SCENARIO_EDITOR :{BLACK}Scenāriju redaktors STR_INTRO_MULTIPLAYER :{BLACK}Vairākspēlētāju spēle STR_INTRO_GAME_OPTIONS :{BLACK}Spēles opcijas STR_INTRO_HIGHSCORE :{BLACK}Sasniegumu tabula STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Iestatījumi STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF iestatījumi STR_INTRO_ONLINE_CONTENT :{BLACK}Pārbaudīt tiešsaistes saturu STR_INTRO_SCRIPT_SETTINGS :{BLACK}MI/spēles skriptu iestatījumi STR_INTRO_QUIT :{BLACK}Iziet STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Sākt jaunu spēli. Ctrl+klikšķis izlaiž kartes konfigurēšanu STR_INTRO_TOOLTIP_LOAD_GAME :{BLACK}Ielādēt saglabāto spēli STR_INTRO_TOOLTIP_PLAY_HEIGHTMAP :{BLACK}Sākt jaunu spēli, ainavai izmantojot augstumu karti STR_INTRO_TOOLTIP_PLAY_SCENARIO :{BLACK}Sākt jaunu spēli ar pielāgotu scenāriju STR_INTRO_TOOLTIP_SCENARIO_EDITOR :{BLACK}Izveidot pielāgotu spēles pasauli/scenāriju STR_INTRO_TOOLTIP_MULTIPLAYER :{BLACK}Sākt vairākspēlētāju spēli STR_INTRO_TOOLTIP_TEMPERATE :{BLACK}Izvēlēties 'mērena klimata' ainavas stilu STR_INTRO_TOOLTIP_SUB_ARCTIC_LANDSCAPE :{BLACK}Izvēlēties 'subarktikas klimata' ainavas stilu STR_INTRO_TOOLTIP_SUB_TROPICAL_LANDSCAPE :{BLACK}Izvēlēties 'subtropu klimata' ainavas stilu STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}Izvēlēties 'rotaļlietu zemes' ainavas stilu STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}Rādīt spēles opcijas STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}Rādīt sasniegumu tabulu STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}Displeja iestatījumi STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}Rādīt NewGRF iestatījumus STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Pārbaudīt vai lejupielādei nav pieejams jauns un atjaunināts saturs STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Rādīt MI un spēles skriptu iestatījumus STR_INTRO_TOOLTIP_QUIT :{BLACK}Iziet no 'OpenTTD' STR_INTRO_TRANSLATION :{BLACK}Šim tulkojumam trūkst {NUM} virk{P ne nes ņu}. Lūdzu palīdziet OpenTTD veidot labāku piesakoties par tulkotāju. Informācijai skatīt readme.txt. # Quit window STR_QUIT_CAPTION :{WHITE}Iziet STR_QUIT_ARE_YOU_SURE_YOU_WANT_TO_EXIT_OPENTTD :{YELLOW}Vai jūs tiešām vēlaties iziet no OpenTTD un atgriezties uz {STRING}? STR_QUIT_YES :{BLACK}Jā STR_QUIT_NO :{BLACK}Nē # Supported OSes STR_OSNAME_WINDOWS :Windows STR_OSNAME_DOS :DOS STR_OSNAME_UNIX :Unix STR_OSNAME_OSX :OS{NBSP}X STR_OSNAME_BEOS :BeOS STR_OSNAME_HAIKU :Haiku STR_OSNAME_MORPHOS :MorphOS STR_OSNAME_AMIGAOS :AmigaOS STR_OSNAME_OS2 :OS/2 STR_OSNAME_SUNOS :SunOS # Abandon game STR_ABANDON_GAME_CAPTION :{WHITE}Pamest spēli STR_ABANDON_GAME_QUERY :{YELLOW}Vai jūs tiešām vēlaties pamest šo spēli? STR_ABANDON_SCENARIO_QUERY :{YELLOW}Vai esat pārliecināts, ka vēlaties pamest šo scenāriju? # Cheat window STR_CHEATS :{WHITE}Blēdības STR_CHEATS_TOOLTIP :{BLACK}Atzīmētās rūtiņas norāda uz to, vai esat jau izmantojis šo blēdību STR_CHEATS_WARNING :{BLACK}Brīdinājums! Jūs grasāties būt neuzticams saviem spēles biedriem, sāncenšiem. Iegaumējiet, ka šādu negodu viņi atcerēsies mūžīgi STR_CHEAT_MONEY :{LTBLUE}Palielināt naudas līdzekļus par {CURRENCY_LONG} STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Spēlēt kā uzņēmumam: {ORANGE}{COMMA} STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Burvju buldozers (nojauc ražotnes, nepārvietojamus objektus): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tuneļi drīkst krustoties: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Reaktīvās lidmašīnas mazajās lidostās neavarēs (bieži): {ORANGE}{STRING} STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Izmainīt maksimālo kartes augstumu: {ORANGE}{NUM} STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Izmainīt kalnu maksimālo augstumu kartē STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :Mērena klimata ainava STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :Subarktikas klimata ainava STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :Subtropu klimata ainava STR_CHEAT_SWITCH_CLIMATE_TOYLAND_LANDSCAPE :Rotaļlietu zemes ainava STR_CHEAT_CHANGE_DATE :{LTBLUE}Nomainīt datumu: {ORANGE} {DATE_SHORT} STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Mainīt pašreizējo gadu STR_CHEAT_SETUP_PROD :{LTBLUE}Ieslēgt ražojumu vērtības maiņu: {ORANGE}{STRING} # Livery window STR_LIVERY_CAPTION :{WHITE}Jauna identitātes krāsu shēma STR_LIVERY_GENERAL_TOOLTIP :{BLACK}Rādīt vispārējo identitates krāsu shēmas STR_LIVERY_TRAIN_TOOLTIP :{BLACK}Rādīt vilcienu identitātes krāsu shēmas STR_LIVERY_ROAD_VEHICLE_TOOLTIP :{BLACK}Rādīt autotransporta identitātes krāsu shēmas STR_LIVERY_SHIP_TOOLTIP :{BLACK}Rādīt kuģu identitātes krāsu shēmas STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Rādīt lidaparātu identitātes krāsu shēmas STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Izvēlēties galveno identitātes krāsu atlasītajai shēmai. Ctrl+klikšķis iestatīs šo krāsu katrai shēmai STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Izvēlēties papildu identitātes krāsu atlasītajai shēmai. Ctrl+klikšķis iestatīs šo krāsu katrai shēmai STR_LIVERY_PANEL_TOOLTIP :{BLACK}Izvēlēties kuru identitātes krāsu shēmu mainīt, vai vairākas ar Ctrl+klikšķi. Klikšķināt uz rūtiņas, lai pārslēgtu shēmas izmantošanu STR_LIVERY_DEFAULT :Vispārpieņemtā identitātes krāsa STR_LIVERY_STEAM :Tvaika lokomotīve STR_LIVERY_DIESEL :Dīzeļlokomotīve STR_LIVERY_ELECTRIC :Elektrolokomotīve STR_LIVERY_MONORAIL :Viensliedes lokomotīve STR_LIVERY_MAGLEV :Magleva lokomotīve STR_LIVERY_DMU :Dīzeļvilciens STR_LIVERY_EMU :Elektrovilciens STR_LIVERY_PASSENGER_WAGON_STEAM :Pasažieru vagons (tvaika) STR_LIVERY_PASSENGER_WAGON_DIESEL :Pasažieru vagons (dīzeļa) STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Pasažieru vagons (elektriskais) STR_LIVERY_PASSENGER_WAGON_MONORAIL :Pasažieru vagons (viensliedes) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Pasažieru vagons (magleva) STR_LIVERY_FREIGHT_WAGON :Kravas vagons STR_LIVERY_BUS :Autobuss STR_LIVERY_TRUCK :Smagā mašīna STR_LIVERY_PASSENGER_SHIP :Pasažieru prāmis STR_LIVERY_FREIGHT_SHIP :Kravas kuģis STR_LIVERY_HELICOPTER :Helikopters STR_LIVERY_SMALL_PLANE :Maza lidmašīna STR_LIVERY_LARGE_PLANE :Liela lidmašīna STR_LIVERY_PASSENGER_TRAM :Pasažieru tramvajs STR_LIVERY_FREIGHT_TRAM :Kravas tramvajs # Face selection window STR_FACE_CAPTION :{WHITE}Sejas izvēle STR_FACE_CANCEL_TOOLTIP :{BLACK}Pārtraukt jaunas sejas izvēli STR_FACE_OK_TOOLTIP :{BLACK}Apstiprināt izvēlēto seju STR_FACE_RANDOM :{BLACK}Nejaušs STR_FACE_MALE_BUTTON :{BLACK}Vīrietis STR_FACE_MALE_TOOLTIP :{BLACK}Izvēlēties vīriešu sejas STR_FACE_FEMALE_BUTTON :{BLACK}Sieviete STR_FACE_FEMALE_TOOLTIP :{BLACK}Izvēlēties sieviešu sejas STR_FACE_NEW_FACE_BUTTON :{BLACK}Jauna seja STR_FACE_NEW_FACE_TOOLTIP :{BLACK}Radīt nejaušu seju STR_FACE_ADVANCED :{BLACK}Papildu STR_FACE_ADVANCED_TOOLTIP :{BLACK}Papildu seju izvēle STR_FACE_SIMPLE :{BLACK}Vienkāršs STR_FACE_SIMPLE_TOOLTIP :{BLACK}Vienkārša seju izvēle STR_FACE_LOAD :{BLACK}Ielādēt STR_FACE_LOAD_TOOLTIP :{BLACK}Ielādēt iecienīto seju STR_FACE_LOAD_DONE :{WHITE}Jūsu iecienītā seja tika ielādēta no OpenTDD konfigurācijas faila STR_FACE_FACECODE :{BLACK}Spēlētāja sejas nr. STR_FACE_FACECODE_TOOLTIP :{BLACK}Skatīt un/vai pielikt uzņēmuma prezidenta sejas numuru STR_FACE_FACECODE_CAPTION :{WHITE}Skatīt un/vai pielikt prezidenta sejas numuru STR_FACE_FACECODE_SET :{WHITE}Jauns sejas numurs ir pielikts STR_FACE_FACECODE_ERR :{WHITE}Nevar pielikt numuru spēlētāja sejai - tam ir jābūt skaitlim no 0 līdz 4,294,967,295! STR_FACE_SAVE :{BLACK}Saglabāt STR_FACE_SAVE_TOOLTIP :{BLACK}Saglabāt iecienīto seju STR_FACE_SAVE_DONE :{WHITE}Šī seja tiks saglabāta OpenTDD konfigurācijas failā kā iecienītā seja STR_FACE_EUROPEAN :{BLACK}Eiropietis STR_FACE_SELECT_EUROPEAN :{BLACK}Izvēlēties eiropiešu sejas STR_FACE_AFRICAN :{BLACK}Afrikānis STR_FACE_SELECT_AFRICAN :{BLACK}Izvēlēties afrikāņu sejas STR_FACE_YES :Ir STR_FACE_NO :Nav STR_FACE_MOUSTACHE_EARRING_TOOLTIP :{BLACK}Iespējot ūsas vai auskarus STR_FACE_HAIR :Mati: STR_FACE_HAIR_TOOLTIP :{BLACK}Mainīt matus STR_FACE_EYEBROWS :Uzacis: STR_FACE_EYEBROWS_TOOLTIP :{BLACK}Mainīt uzacis STR_FACE_EYECOLOUR :Acu krāsa: STR_FACE_EYECOLOUR_TOOLTIP :{BLACK}Mainīt acu krāsu STR_FACE_GLASSES :Brilles: STR_FACE_GLASSES_TOOLTIP :{BLACK}Iespējot brilles STR_FACE_GLASSES_TOOLTIP_2 :{BLACK}Mainīt brilles STR_FACE_NOSE :Deguns: STR_FACE_NOSE_TOOLTIP :{BLACK}Mainīt degunu STR_FACE_LIPS :Lūpas: STR_FACE_MOUSTACHE :Ūsas: STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}Mainīt lūpas vai ūsas STR_FACE_CHIN :Zods: STR_FACE_CHIN_TOOLTIP :{BLACK}Mainīt zodu STR_FACE_JACKET :Jaka: STR_FACE_JACKET_TOOLTIP :{BLACK}Mainīt jaku STR_FACE_COLLAR :Apkakle: STR_FACE_COLLAR_TOOLTIP :{BLACK}Mainīt apkakli STR_FACE_TIE :Kaklasaite: STR_FACE_EARRING :Auskars: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Mainīt kaklasaiti vai auskarus # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Vairākspēlētāju spēle STR_NETWORK_SERVER_LIST_ADVERTISED :{BLACK}Izsludināt STR_NETWORK_SERVER_LIST_ADVERTISED_NO :Nē STR_NETWORK_SERVER_LIST_ADVERTISED_YES :Jā STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spēlētāja vārds: STR_NETWORK_SERVER_LIST_ENTER_NAME_TOOLTIP :{BLACK}Pēc šā vārda jūs atpazīs citi spēlētāji STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}Nosaukums STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP :{BLACK}Spēles nosaukums STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION :{BLACK}Spēlētāji STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP :{BLACK}Spēlētāji tiešsaistē / maksimālais spēlētāju skaits{}Uzņēmumi tiešsaistē / maksimālais uzņēmumu skaits STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION :{BLACK}Kartes izmēri STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP :{BLACK}Spēles kartes izmērs{}Klikšķināt, lai šķirotu laukumos STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Datums STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Šībrīža datums STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Gadi STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Gadu skaits{}spēle ir palaista STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Valoda, servera versija utt. STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Klikšķināt sarakstā uz spēles, lai to izvēlētos STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Serveris, kuram jūs pievienojāties pēdējoreiz: STR_NETWORK_SERVER_LIST_CLICK_TO_SELECT_LAST :{BLACK}Klikšķis, lai izvēlētos serveri kurā jūs spēlējāt pēdējoreiz STR_NETWORK_SERVER_LIST_GAME_INFO :{SILVER}SPĒLES INFORMĀCIJA STR_NETWORK_SERVER_LIST_CLIENTS :{SILVER}Spēlētāji: {WHITE}{COMMA} / {COMMA} - {COMMA} / {COMMA} STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}Valoda: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_LANDSCAPE :{SILVER}Ainava: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_MAP_SIZE :{SILVER}Kartes izmērs: {WHITE}{COMMA}x{COMMA} STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Servera versija: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Servera adrese: {WHITE}{STRING} STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Sākuma datums: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Šībrīža datums: {WHITE}{DATE_SHORT} STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Aizsargāts ar paroli! STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}SERVERIS NAV TIEŠSAISTĒ STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}SERVERIS IR PILNS STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}VERSIJU NEATBILSTĪBA STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}NEWGRF NEATBILSTĪBA STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Pievienoties spēlei STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Atsvaidzināt serveri STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Atsvaidzināt servera informāciju STR_NETWORK_SERVER_LIST_FIND_SERVER :{BLACK}Atrast serveri STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP :{BLACK}Meklēt serveri tīklā STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Pievienot serveri STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Pievienot serveri sarakstam, kurš vienmēr tiks pārbaudīts vai tajā nav palaistas spēles STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Palaist serveri STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Palaist jūsu personīgo serveri STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Ievadīt savu vārdu STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Ievadīt servera adresi # Start new multiplayer server STR_NETWORK_START_SERVER_CAPTION :{WHITE}Sākt jaunu vairākspēlētāju spēli STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Spēles nosaukums: STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Spēles nosaukums, kas tiks attēlots citiem spēlētajiem vairākspēlētāju spēļu izvēlnē STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Uzstādīt paroli STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Aizsargā jūsu spēli ar paroli, ja nevēlaties lai tā būtu publiski pieejama STR_NETWORK_START_SERVER_UNADVERTISED :Nē STR_NETWORK_START_SERVER_ADVERTISED :Jā STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} spēlētāj{P s i u} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimālais spēlētāju skaits: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Izvēlēties maksimālo spēlētāju skaitu. Ne visiem slotiem ir jābūt aizpildītiem STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} uzņēmum{P s i u} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Maksimālais uzņēmumu skaits: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Ierobežo serveri noteiktam uzņēmumu skaitam STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} novērotāj{P s i u} STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Maksimālais novērotāju skaits: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Ierobežo serveri noteiktam novērotāju skaitam STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Valoda, kurā runā: STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Citi lietotāji zinās, kurā valodā tiek runāts uz servera STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Ievadīt tīkla spēles nosaukumu # Network game languages ############ Leave those lines in this order!! STR_NETWORK_LANG_ANY :Jebkura STR_NETWORK_LANG_ENGLISH :Angļu STR_NETWORK_LANG_GERMAN :Vācu STR_NETWORK_LANG_FRENCH :Franču STR_NETWORK_LANG_BRAZILIAN :Brazīļu STR_NETWORK_LANG_BULGARIAN :Bulgāru STR_NETWORK_LANG_CHINESE :Ķīniešu STR_NETWORK_LANG_CZECH :Čehu STR_NETWORK_LANG_DANISH :Dāņu STR_NETWORK_LANG_DUTCH :Holandiešu STR_NETWORK_LANG_ESPERANTO :Esperanto STR_NETWORK_LANG_FINNISH :Somu STR_NETWORK_LANG_HUNGARIAN :Ungāru STR_NETWORK_LANG_ICELANDIC :Īslandiešu STR_NETWORK_LANG_ITALIAN :Itāliešu STR_NETWORK_LANG_JAPANESE :Japāņu STR_NETWORK_LANG_KOREAN :Korejiešu STR_NETWORK_LANG_LITHUANIAN :Lietuviešu STR_NETWORK_LANG_NORWEGIAN :Norvēģu STR_NETWORK_LANG_POLISH :Poļu STR_NETWORK_LANG_PORTUGUESE :Portugāļu STR_NETWORK_LANG_ROMANIAN :Rumāņu STR_NETWORK_LANG_RUSSIAN :Krievu STR_NETWORK_LANG_SLOVAK :Slovāku STR_NETWORK_LANG_SLOVENIAN :Slovēņu STR_NETWORK_LANG_SPANISH :Spāņu STR_NETWORK_LANG_SWEDISH :Zviedru STR_NETWORK_LANG_TURKISH :Turku STR_NETWORK_LANG_UKRAINIAN :Ukraiņu STR_NETWORK_LANG_AFRIKAANS :Āfrikāņu STR_NETWORK_LANG_CROATIAN :Horvātu STR_NETWORK_LANG_CATALAN :Kataloņu STR_NETWORK_LANG_ESTONIAN :Igauņu STR_NETWORK_LANG_GALICIAN :Galisiešu STR_NETWORK_LANG_GREEK :Grieķu STR_NETWORK_LANG_LATVIAN :Latviešu ############ End of leave-in-this-order # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Vairākspēlētāju spēles vestibils STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}Gatavojos pievienoties: {ORANGE}{STRING} STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}Spēlē esošo uzņēmumu saraksts. Jūs varat vai nu kādam pievienoties, vai arī sākt jaunu, ja ir brīvs uzņēmuma slots STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}UZŅĒMUMA INFORMĀCIJA STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}Uzņēmuma nosaukums: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}Atklāšana: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VALUE :{SILVER}Uzņēmuma vērtība: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_CURRENT_BALANCE :{SILVER}Šībrīža bilance: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_LAST_YEARS_INCOME :{SILVER}Ienākumi pērn: {WHITE}{CURRENCY_LONG} STR_NETWORK_GAME_LOBBY_PERFORMANCE :{SILVER}Veiktspēja: {WHITE}{NUM} STR_NETWORK_GAME_LOBBY_VEHICLES :{SILVER}Satiksmes līdzekļi: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_STATIONS :{SILVER}Stacijas: {WHITE}{NUM} {TRAIN}, {NUM} {LORRY}, {NUM} {BUS}, {NUM} {SHIP}, {NUM} {PLANE} STR_NETWORK_GAME_LOBBY_PLAYERS :{SILVER}Spēlētāji: {WHITE}{STRING} STR_NETWORK_GAME_LOBBY_NEW_COMPANY :{BLACK}Jauns uzņēmums STR_NETWORK_GAME_LOBBY_NEW_COMPANY_TOOLTIP :{BLACK}Izveidot jaunu uzņēmumu STR_NETWORK_GAME_LOBBY_SPECTATE_GAME :{BLACK}Novērot spēli STR_NETWORK_GAME_LOBBY_SPECTATE_GAME_TOOLTIP :{BLACK}Skatīties spēli kā novērotājam STR_NETWORK_GAME_LOBBY_JOIN_COMPANY :{BLACK}Pievienoties uzņēmumam STR_NETWORK_GAME_LOBBY_JOIN_COMPANY_TOOLTIP :{BLACK}Palīdzēt vadīt šo uzņēmumu # Network connecting window STR_NETWORK_CONNECTING_CAPTION :{WHITE}Savienojas... ############ Leave those lines in this order!! STR_NETWORK_CONNECTING_1 :{BLACK}(1/6) Savienojas... STR_NETWORK_CONNECTING_2 :{BLACK}(2/6) Autorizējas... STR_NETWORK_CONNECTING_3 :{BLACK}(3/6) Gaida... STR_NETWORK_CONNECTING_4 :{BLACK}(4/6) Lejupielādē karti... STR_NETWORK_CONNECTING_5 :{BLACK}(5/6) Apstrādā datus... STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Reģistrējas... STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Pieņem spēles informāciju... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Pieņem uzņēmuma informāciju... ############ End of leave-in-this-order STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} klient{P s i u} ir jūsu priekšā STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}Līdz šim lejupielādēti {BYTES} STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} lejuplādēti līdz šim STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Atvienoties STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Serveris ir aizsargāts. Ievadiet paroli STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Uzņēmums ir aizsargāts. Ievadiet paroli # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Spēlētāju saraksts STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Skatīt STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}Jauns uzņēmums # Network client list STR_NETWORK_CLIENTLIST_KICK :Izmest STR_NETWORK_CLIENTLIST_BAN :Aizliegt STR_NETWORK_CLIENTLIST_GIVE_MONEY :Iedot naudu STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Runāt ar visiem STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Runāt ar uzņēmumu STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privāts ziņojums STR_NETWORK_SERVER :Serveris STR_NETWORK_CLIENT :Spēlētājs STR_NETWORK_SPECTATORS :Novērotāji STR_NETWORK_GIVE_MONEY_CAPTION :{WHITE}Ievadiet cik daudz naudas vēlaties dot STR_NETWORK_TOOLBAR_LIST_SPECTATOR :{BLACK}Novērotājs # Network set password STR_COMPANY_PASSWORD_CANCEL :{BLACK}Nesaglabāt ievadīto paroli STR_COMPANY_PASSWORD_OK :{BLACK}Piešķirt uzņēmumam jaunu paroli STR_COMPANY_PASSWORD_CAPTION :{WHITE}Uzņēmuma parole STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}Uzņēmuma noklusējuma parole STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}Izmantot šo paroli kā noklusējuma jauniem uzņēmumiem # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}Pievienoties STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}Pievienoties un spēlēt ar šo uzņēmumu STR_COMPANY_VIEW_PASSWORD :{BLACK}Parole STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}Aizsargājiet savu uzņēmumu ar paroli, lai novērstu neatļautu lietotāju pievienošanos STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}Iestatīt uzņēmuma paroli # Network chat STR_NETWORK_CHAT_SEND :{BLACK}Sūtīt STR_NETWORK_CHAT_COMPANY_CAPTION :[Komanda] : STR_NETWORK_CHAT_CLIENT_CAPTION :[Privāti] {STRING}: STR_NETWORK_CHAT_ALL_CAPTION :[Visiem] : STR_NETWORK_CHAT_COMPANY :[Komanda] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_COMPANY :[Komanda] Uz {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_CLIENT :[Privāti] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_TO_CLIENT :[Privāti] Uz {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_ALL :[Visiem] {STRING}: {WHITE}{STRING} STR_NETWORK_CHAT_OSKTITLE :{BLACK}Ievadīt tekstu tīkla tērzēšanai # Network messages STR_NETWORK_ERROR_NOTAVAILABLE :{WHITE}Neviena tīkla iekārta nav atrasta vai kompilēta bez ENABLE_NETWORK STR_NETWORK_ERROR_NOSERVER :{WHITE}Nevar atrast nevienu tīkla spēli STR_NETWORK_ERROR_NOCONNECTION :{WHITE}Serveris neatbild uz pieprasījumu STR_NETWORK_ERROR_NEWGRF_MISMATCH :{WHITE}Nevar pieslēgties sakarā ar NewGRF neatbilstību STR_NETWORK_ERROR_DESYNC :{WHITE}Tīkla spēles sinhronizācija neizdevās STR_NETWORK_ERROR_LOSTCONNECTION :{WHITE}Tīkla spēlei zudis savienojums STR_NETWORK_ERROR_SAVEGAMEERROR :{WHITE}Nevar ielādēt saglabāto spēli STR_NETWORK_ERROR_SERVER_START :{WHITE}Nevar uzsākt servera darbību STR_NETWORK_ERROR_CLIENT_START :{WHITE}Nevar savienot STR_NETWORK_ERROR_TIMEOUT :{WHITE}Savienojuma #{NUM} laiks ir beidzies STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Tika pielaista protokola kļūda un savienojums tika slēgts STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Klienta pārskats neatbilst servera pārskatam STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Nepareiza parole STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Serveris ir pilns STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Šajā serverī jums ir aizliegums STR_NETWORK_ERROR_KICKED :{WHITE}Jūs esat izmests no šīs spēles STR_NETWORK_ERROR_CHEATER :{WHITE}Uz šī servera blēdības nav atļautas STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Jūs sūtījāt uz serveri pārak daudz rīkojumu STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Jūs pārāk ilgi neievadījāt paroli STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Jūsu dators ir pārāk lēns lai turētos līdzi servera ātrumam STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Jūsu dators pārāk ilgi lejupielādēja karti STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Jūsu dators pārāk ilgi pievienojās serverim ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :galvenā kļūda STR_NETWORK_ERROR_CLIENT_DESYNC :asinhronizācijas kļūda STR_NETWORK_ERROR_CLIENT_SAVEGAME :nevar ielādēt karti STR_NETWORK_ERROR_CLIENT_CONNECTION_LOST :pazudis savienojums STR_NETWORK_ERROR_CLIENT_PROTOCOL_ERROR :protokola kļūda STR_NETWORK_ERROR_CLIENT_NEWGRF_MISMATCH :NewGRF neatbilstība STR_NETWORK_ERROR_CLIENT_NOT_AUTHORIZED :nav autorizēts STR_NETWORK_ERROR_CLIENT_NOT_EXPECTED :saņemta nederīga vai neparedzēta pakete STR_NETWORK_ERROR_CLIENT_WRONG_REVISION :nepareiza versija STR_NETWORK_ERROR_CLIENT_NAME_IN_USE :šo vārdu jau lieto STR_NETWORK_ERROR_CLIENT_WRONG_PASSWORD :nepareiza parole STR_NETWORK_ERROR_CLIENT_COMPANY_MISMATCH :VeiktKomandā nepareizs uzņēmums STR_NETWORK_ERROR_CLIENT_KICKED :serveris jūs izmeta STR_NETWORK_ERROR_CLIENT_CHEATER :mēģināja blēdīties STR_NETWORK_ERROR_CLIENT_SERVER_FULL :serveris pilns STR_NETWORK_ERROR_CLIENT_TOO_MANY_COMMANDS :sūtīja pārak daudz rīkojumu STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :parole nav saņemta laikā STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :vispārējā noildze STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :kartes lejupielāde bija pārāk ilga STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :kartes apstrāde bija pārāk ilga ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Iespējams savienojuma zudums STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}Nav datu no servera jau {NUM} sekund{P i es ""} # Network related errors STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Spēle pauzēta ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Spēle joprojām pauzēta ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Spēle joprojām pauzēta ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Spēle joprojām pauzēta ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Spēle vēl aizvien ir pauzēta ({STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Spēle atsākta ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :spēlētāju skaits STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :savieno spēlētājus STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manuālā STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :spēles skripts ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :aizeju STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} ir pievienojies spēlei STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} ir pievienojies spēlei (Client #{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} ir pievienojies uzņēmumam #{2:NUM} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} ir pievienojies novērotājiem STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} ir nodibinājis jaunu uzņēmumu (#{2:NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} ir pametis spēli ({2:STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} ir nomainījis savu nosaukumu uz {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} iedeva jūsu uzņēmumam {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Jūs iedevāt {1:STRING} {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Serveris beidza sesiju STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Serveris pārstartējas...{}Lūdzu uzgaidiet... # Content downloading window STR_CONTENT_TITLE :{WHITE}Satura lejupielāde STR_CONTENT_TYPE_CAPTION :{BLACK}Tips STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Satura tips STR_CONTENT_NAME_CAPTION :{BLACK}Nosaukums STR_CONTENT_NAME_CAPTION_TOOLTIP :{BLACK}Satura nosaukums STR_CONTENT_MATRIX_TOOLTIP :{BLACK}Klikšķināt uz rindiņas, lai redzētu īpašības{}Klikšķināt uz izvēles rūtiņas, lai to atzīmētu lejupielādei STR_CONTENT_SELECT_ALL_CAPTION :{BLACK}Atlasīt visu STR_CONTENT_SELECT_ALL_CAPTION_TOOLTIP :{BLACK}Atzīmēt visu saturu lejupielādei STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Atlasīt jauninājumus STR_CONTENT_SELECT_UPDATES_CAPTION_TOOLTIP :{BLACK}Atzīmēt visu saturu lejupielādei, lai tas ir jauninājums jau esošajam STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Atcelt visu atlasi STR_CONTENT_UNSELECT_ALL_CAPTION_TOOLTIP :{BLACK}Noņemt visas satura lejupielādes atzīmes STR_CONTENT_SEARCH_EXTERNAL :{BLACK}Meklēt ārējās vietnēs STR_CONTENT_SEARCH_EXTERNAL_TOOLTIP :{BLACK}Meklēt OpenTTD pakalpojumos nepieejamu saturu ar OpenTTD nesaistītās vietnēs STR_CONTENT_SEARCH_EXTERNAL_DISCLAIMER_CAPTION :{WHITE}Jūs aizejat no OpenTTD! STR_CONTENT_FILTER_TITLE :{BLACK}Atzīmju/nosaukumu filtrs: STR_CONTENT_OPEN_URL :{BLACK}Apmeklēt tīmekļa vietni STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Apmeklēt tīmekļa vietni, lai tiktu pie šī satura STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Lejupielādēt STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Sākt atlasītā lejupielādi STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Lejupielādes kopējais lielums: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}SATURA INFORMĀCIJA STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Šo jūs neesat atlasījis lejupielādei STR_CONTENT_DETAIL_SUBTITLE_SELECTED :{SILVER}Šo jūs esat atlasījis lejupielādei STR_CONTENT_DETAIL_SUBTITLE_AUTOSELECTED :{SILVER}Šis atkarīgais materiāls ir iezīmēts lejupielādei. STR_CONTENT_DETAIL_SUBTITLE_ALREADY_HERE :{SILVER}Šis jums jau ir STR_CONTENT_DETAIL_SUBTITLE_DOES_NOT_EXIST :{SILVER}Šī materiāla saturs ir nezināms, tādēļ to nav iespejams lejupielādēt OpenTTD STR_CONTENT_DETAIL_UPDATE :{SILVER}Šis ir jau esoša {STRING} aizstāšanai STR_CONTENT_DETAIL_NAME :{SILVER}Nosaukums: {WHITE}{STRING} STR_CONTENT_DETAIL_VERSION :{SILVER}Versija: {WHITE}{STRING} STR_CONTENT_DETAIL_DESCRIPTION :{SILVER}Apraksts: {WHITE}{STRING} STR_CONTENT_DETAIL_URL :{SILVER}Tīmekļa adrese: {WHITE}{STRING} STR_CONTENT_DETAIL_TYPE :{SILVER}Tips: {WHITE}{STRING} STR_CONTENT_DETAIL_FILESIZE :{SILVER}Lejupielādes lielums: {WHITE}{BYTES} STR_CONTENT_DETAIL_SELECTED_BECAUSE_OF :{SILVER}Atlasīts, jo: {WHITE}{STRING} STR_CONTENT_DETAIL_DEPENDENCIES :{SILVER}Atkarības: {WHITE}{STRING} STR_CONTENT_DETAIL_TAGS :{SILVER}Atzīmes: {WHITE}{STRING} STR_CONTENT_NO_ZLIB :{WHITE}OpenTTD ir būvēta bez ''zlib'' atbalsta... STR_CONTENT_NO_ZLIB_SUB :{WHITE}... lejuplādēt saturu nav iespējams! # Order of these is important! STR_CONTENT_TYPE_BASE_GRAPHICS :Pamata grafika STR_CONTENT_TYPE_NEWGRF :NewGRF STR_CONTENT_TYPE_AI :MI STR_CONTENT_TYPE_AI_LIBRARY :MI bibliotēka STR_CONTENT_TYPE_SCENARIO :Scenārijs STR_CONTENT_TYPE_HEIGHTMAP :Augstumu karte STR_CONTENT_TYPE_BASE_SOUNDS :Pamata skaņas efekti STR_CONTENT_TYPE_BASE_MUSIC :Pamata mūzika STR_CONTENT_TYPE_GAME_SCRIPT :Spēles skripts STR_CONTENT_TYPE_GS_LIBRARY :SS bibliotēka # Content downloading progress window STR_CONTENT_DOWNLOAD_TITLE :{WHITE}Lejupielādē saturu... STR_CONTENT_DOWNLOAD_INITIALISE :{WHITE}Pieprasa failus... STR_CONTENT_DOWNLOAD_FILE :{WHITE}Šobrīd lejupielādē {STRING} ({NUM} no {NUM}) STR_CONTENT_DOWNLOAD_COMPLETE :{WHITE}Lejupielāde pabeigta STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} no {BYTES} lejupielādēts ({NUM} %) # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Nav iespējams savienoties ar satura serveri... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Lejupielāde neizdevās... STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... pazudis savienojums STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... fails nav rakstāms STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Neizdevās atspiest lejupielādēto failu STR_MISSING_GRAPHICS_SET_CAPTION :{WHITE}Trūkst grafikas STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD vajag grafiku, lai strādātu, bet tādu nevarēja atrast. Vai ļaujat OpenTTD lejupielādēt un instalēt tādu grafiku? STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Jā, lejupielādēt grafiku STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Nē, iziet no OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Caurspīdības opcijas STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Pārslēgt zīmju caurspīdību. Ctrl+klikšķis lai slēgtu STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Pārslēgt koku caurspīdību. Ctrl+klikšķis lai slēgtu STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Pārslēgt ēku caurspīdību. Ctrl+klikšķis lai slēgtu STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Pārslēgt ražotņu caurspīdību. Ctrl+klikšķis lai slēgtu STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Pārslēgt caurspīdību tādām ēkām kā depo, stacijas un pieturas punkti. Ctrl+klikšķis lai slēgtu. STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Pārslēgt tiltu caurspīdību. Ctrl+klikšķis, lai slēgtu STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Pārslēgt caurspīdību tādām celtnēm kā bākas un antenas. Ctrl+klikšķis, lai slēgtu STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Pārslēgt piekartroses caurspīdību. Ctrl+klikšķis, lai slēgtu STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Pārslēgt piekraušanas rādītāju caurspīdību. Ctrl+klikšķis, lai slēgtu STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Caurspīdības vietā objektus padarīt neredzamus # Linkgraph legend window STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Atzīmēt kompānijas kuras uzrādīt # Linkgraph legend window and linkgraph legend in smallmap # Base for station construction window(s) STR_STATION_BUILD_COVERAGE_AREA_TITLE :{BLACK}Pārklājuma iezīmēšana STR_STATION_BUILD_COVERAGE_OFF :{BLACK}Nav STR_STATION_BUILD_COVERAGE_ON :{BLACK}Ir STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP :{BLACK}Neiezīmēt jaunceļamā objekta pārklājumu STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP :{BLACK}Iezīmēt jaunceļamā objekta pārklājumu STR_STATION_BUILD_ACCEPTS_CARGO :{BLACK}Pieņem: {GOLD}{CARGO_LIST} STR_STATION_BUILD_SUPPLIES_CARGO :{BLACK}Piegādā: {GOLD}{CARGO_LIST} # Join station window STR_JOIN_STATION_CAPTION :{WHITE}Pievienot staciju STR_JOIN_STATION_CREATE_SPLITTED_STATION :{YELLOW}Būvēt atdalītu staciju STR_JOIN_WAYPOINT_CAPTION :{WHITE}Pievienot pieturas punktu STR_JOIN_WAYPOINT_CREATE_SPLITTED_WAYPOINT :{YELLOW}Uzbūvēt jaunu maršruta punktu # Rail construction toolbar STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION :Dzelzceļa būvniecība STR_RAIL_TOOLBAR_ELRAIL_CONSTRUCTION_CAPTION :Elektrificētā dzelzceļa būvniecība STR_RAIL_TOOLBAR_MONORAIL_CONSTRUCTION_CAPTION :Viensliedes būvniecība STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :Magleva būvēšana STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Būvēt sliedes. Ctrl pārslēdz sliežu būvniecību/nojaukšanu. Shift pārslēdz būve/rādīt izmaksu tāmi STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}Būvēt dzelzceļu, izmantojot automātisko sliežu režīmu. Ctrl pārslēdz sliežu būvniecību/demolēšanu STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}Būvēt vilcienu depo (vilcienu pirkšanai un apkopei). Shift pārslēdz būvi/rādīt izmaksu tāmi STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}Pārveidot sliedes par pieturas punktu. Ctrl iespējo pieturas punktu apvienošanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}Būvēt dzelzceļa staciju. Ctrl iespējo staciju apvienošanu. Shift pārslēdz būve/rādīt izmaksu tāmi STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}Būvēt dzelzceļa signālus. Ctrl pārslēdz semaforus/luksoforus{}Vilkšana uzbūvē signālus uz taisna sliežu posma. Ctrl uzbūvē signālus līdz nākamajam sazarojumam vai signālam{}Ctrl+Klikšķis pārslēdz signālu izvēles loga atvēršanu. Shift pārslēdz starp būvet/rādīt izmaksu tāmi STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}Būvēt dzelzceļa tiltu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL :{BLACK}Būvēt dzelzceļa tuneli. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR :{BLACK}Pārslēgties starp sliežu, signālierīču, pieturas punktu būvēšanu/noņemšanu. Aizturēt Ctrl, lai noņemtu arī sliedes no pieturas punktiem un stacijām STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL :{BLACK}Pārveidot/uzlabot sliežu veidu. Shift pārslēdz būvēšanu/izmaksu novērtējumu rādīšanu STR_RAIL_NAME_RAILROAD :Dzelzceļš STR_RAIL_NAME_ELRAIL :Elektrificēts dzelzceļš STR_RAIL_NAME_MONORAIL :Viensliedes STR_RAIL_NAME_MAGLEV :Maglevs # Rail depot construction window STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION :{WHITE}Vilcienu depo virziens STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP :{BLACK}Izvēlēties vilcienu depo virzienu # Rail waypoint construction window STR_WAYPOINT_CAPTION :{WHITE}Pieturas punkts STR_WAYPOINT_GRAPHICS_TOOLTIP :{BLACK}Izvēlēties pieturas punkta veidu # Rail station construction window STR_STATION_BUILD_RAIL_CAPTION :{WHITE}Dzelzceļa stacijas izvēle STR_STATION_BUILD_ORIENTATION :{BLACK}Virziens STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP :{BLACK}Izvēlēties dzelzceļa stacijas virzienu STR_STATION_BUILD_NUMBER_OF_TRACKS :{BLACK}Platformu skaits STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP :{BLACK}Izvēlēties platformu skaitu dzelzceļa stacijai STR_STATION_BUILD_PLATFORM_LENGTH :{BLACK}Platformas garums STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP :{BLACK}Izvēlēties dzelzceļa stacijas garumu STR_STATION_BUILD_DRAG_DROP :{BLACK}Vilkt un nomest STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Būvēt staciju izmantojot "vilkt un nomest" STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Izvēlēties kuru stacijas klasi rādīt STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Izvēlēties kuru stacijas veidu būvēt STR_STATION_CLASS_DFLT :Noklusējuma stacija STR_STATION_CLASS_WAYP :Pieturas punkti # Signal window STR_BUILD_SIGNAL_CAPTION :{WHITE}Signāla izvēle STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP :{BLACK}Bloka signālierīce (semafors){}Šis ir pats vienkāršākais signālierīces veids, kas ļauj uz bloka vienlaicīgi atrasties tikai vienam vilcienam STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP :{BLACK}Ieejas signālierīce (semafors){}Zaļš kamēr ir viens vai vairāki zaļi izejas signāli no sekojošās sliežu sekcijas. Citādi signāls būs sarkans STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP :{BLACK}Izejas signālierīce (semafors){}Uzvedas tāpat kā bloka signālierīce, bet tā ir nepieciešama, lai pirmssignālu ierīces rādītu pareizās krāsas STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP :{BLACK}Kombinētā signālierīce (semafors){} Kombinētā signālierīce darbojas gan kā izejas, gan ieejas signāls. Tas ļauj radīt lielus pirmssignālu tīklus STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP :{BLACK}Ceļa signāls (semafors){}Ceļa signāls ļauj vairāk kā vienam vilcienam iebraukt signāla blokā vienlaicīgi, ja vien vilciens var rezervēt drošu apstāšanās punktu. Parastiem ceļa signāliem var pabraukt garām no aizmugures STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP :{BLACK}Viena virziena ceļa signālierīce (semafors){}Viena virziena ceļa signāls ļauj vairāk kā vienam vilcienam iebraukt signāla blokā vienlaicīgi, ja vien vilciens var rezervēt drošu apstāšanās punktu. Šai signālierīcei nevar pabraukt garām no aizmugures STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP :{BLACK}Bloka signāls (luksofors){}Šis ir vienkāršākais, kas ļauj atrasties uz bloka vienlaicīgi tikai vienam vilcienam STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP :{BLACK}Ieejas signāls (luksofors){}Zaļš līdz parādās vēl viens vai vairāki zaļi izejas signāli no šīs sliežu sekcijas. Citādi tas parādās sarkans STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP :{BLACK}Izejas signālierīce (luksofors){}Uzvedas tāpat kā bloka signālierīce, bet tā ir nepieciešama, lai pirmssignālu ierīces rādītu pareizās krāsas STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP :{BLACK}Kombinētā signālierīce (luksofors){} Kombinētā signālierīce darbojas gan kā izejas, gan ieejas signāls. Tas ļauj radīt lielus pirmssignālu tīklus STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP :{BLACK}Ceļa signāls (luksofors){}Ceļa signāls ļauj vairāk kā vienam vilcienam iebraukt signāla blokā vienlaicīgi, ja vien vilciens var rezervēt drošu apstāšanās punktu. Parastiem ceļa signāliem var pabraukt garām no aizmugures STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP :{BLACK}Vienvirziena ceļa signālierīce (elektriska){}Ceļa signāls ļauj iebraukt signāla blokā vairāk kā vienam vilcienam vienlaicīgi, ja vien vilciens var rezervēt drošu apstāšanās punktu. Vienvirziena ceļa signālierīcēm nevar pabraukt garām no aizmugures STR_BUILD_SIGNAL_CONVERT_TOOLTIP :{BLACK}Signālierīču pārveidotājs{}Kad ieslēgts, klikšķis uz jau esošas signālierīces pārveidos to uz norādīto signāla tipu un variantu. Ctrl+klikšķis pārslēgs pašreizējo variantu. Shift+klikšķis rāda pārveidošanas tāmes vērtību STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP :{BLACK}Vilkt signālu biežumu STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP :{BLACK}Samazināt signālierīču biežumu STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP :{BLACK}Palielināt signālierīču biežumu # Bridge selection window STR_SELECT_RAIL_BRIDGE_CAPTION :{WHITE}Izvēlēties dzelzceļa tiltu STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Izvēlēties tiltu STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Tiltu izvēle - klikšķināt uz vēlamo tiltu, lai to uzbūvētu STR_SELECT_BRIDGE_INFO :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_SCENEDIT_INFO :{GOLD}{STRING},{} {VELOCITY} STR_BRIDGE_NAME_SUSPENSION_STEEL :Vanšu, tērauda STR_BRIDGE_NAME_GIRDER_STEEL :Siju, tērauda STR_BRIDGE_NAME_CANTILEVER_STEEL :Izgriežamais, tērauda STR_BRIDGE_NAME_SUSPENSION_CONCRETE :Vanšu, betona STR_BRIDGE_NAME_WOODEN :Koka STR_BRIDGE_NAME_CONCRETE :Betona STR_BRIDGE_NAME_TUBULAR_STEEL :Cauruļveida, tērauda STR_BRIDGE_TUBULAR_SILICON :Cauruļveida, silīcija # Road construction toolbar STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION :{WHITE}Ceļu būvniecība STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION :{WHITE}Tramvaju sliežu ceļu būvniecība STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}Ceļu būves izvēle. Ctrl pārslēdz ceļa būvešanu/nojaukšanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}Tramvaju sliežu būves izvēle. Ctrl pārslēdz tramvaju sliežu būvešanu/nojaukšanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Būvēt ceļu izmantojot automātiskā ceļa paņēmienu. Ctrl pārslēdz ceļu būvēšanu/nojaukšanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Būvēt tramvaju sliedes izmantojot automātisko paņēmienu. Ctrl pārslēdz tramvaju sliežu būvēšanu/nojaukšanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Būvēt autotransporta depo (autotransporta līdzekļu pirkšanai un apkopei). Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Būvēt tramvaju depo (tramvaju pirkšanai un apkopei). Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Būvēt autobusu pieturvietu. Ctrl ieslēdz pieturvietu apvienošanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Būvēt pasažieru tramvaju pieturvietu. Ctrl ieslēdz pieturvietu apvienošanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Būvēt kravas automobiļu iekraušanas laukumu. Ctrl ieslēdz iekraušanas laukumu apvienošanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION :{BLACK}Būvēt kravas tramvaju pieturvietu. Ctrl ieslēdz pieturvietu apvienošanu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD :{BLACK}Ieslēgt/izslēgt vienvirziena ceļus STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE :{BLACK}Būvēt ceļa tiltu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE :{BLACK}Būvēt tramvaju tiltu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Būvēt ceļa tuneli. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Būvēt tramvaju tuneli. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Pārslēgties starp ceļa būvēšanas/nojaukšanas režīmiem STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Pārslēgt būvēt/novākt tramvaju būvei # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Autotransporta depo virziens STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP :{BLACK}Izvēlēties autotransporta depo virzienu STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION :{WHITE}Tramvaju depo virziens STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP :{BLACK}Izvēlēties tramvaju depo virzienu # Road vehicle station construction window STR_STATION_BUILD_BUS_ORIENTATION :{WHITE}Autoostas virziens STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP :{BLACK}Izvēlēties autoostas virzienu STR_STATION_BUILD_TRUCK_ORIENTATION :{WHITE}Kravas stacijas virziens STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP :{BLACK}Izvēlēties kravas iekraušanas laukuma virzienu STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION :{WHITE}Pasažieru tramvaju pieturvietasas virziens STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP :{BLACK}Izvēlēties pasažieru tramvaju pieturvietas virzienu STR_STATION_BUILD_CARGO_TRAM_ORIENTATION :{WHITE}Kravas tramvaju pieturvietas virziens STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Izvēlēties kravas tramvaju pieturvietas virzienu # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Ūdensceļu būvniecība STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Ūdensceļi STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Būvēt kanālus. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Būvēt slūžas. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Būvēt kuģu depo (kuģu būvēšanai un apkopei). Shift pārslēdz būvēšanu/izmaksu novērtējuma rādīšanu STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Būvēt kuģu piestātni. Ctrl ieslēdz staciju apvienošanu. Shift pārslēdz būvēšanu/izmaksu novērtējuma rādīšanu STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Izvietot boju, kura var kalpot kā pieturas punkts. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Būvēt akveduktu. Shift pārslēdz būvēšanu/izmaksu tāmes rādīšanu STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Norādīt ūdens laukumu.{}Būvēt kanālu. Ja tur nospiestu Ctrl jūras līmenī, tad appludinās apkārtni STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Izvietot upes # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Kuģu depo virziens STR_DEPOT_BUILD_SHIP_ORIENTATION_TOOLTIP :{BLACK}Izvēlēties kuģu depo virzienu # Dock construction window STR_STATION_BUILD_DOCK_CAPTION :{WHITE}Piestātne # Airport toolbar STR_TOOLBAR_AIRCRAFT_CAPTION :{WHITE}Lidostas STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP :{BLACK}Būvēt lidostu. Ctrl ieslēdz staciju apvienošanu. Shift pārslēdz būvēšanu/izmaksu novērtējuma rādīšanu # Airport construction window STR_STATION_BUILD_AIRPORT_CAPTION :{WHITE}Lidostas izvēle STR_STATION_BUILD_AIRPORT_TOOLTIP :{BLACK}Izvēlēties lidostas lielumu/veidu STR_STATION_BUILD_AIRPORT_CLASS_LABEL :{BLACK}Lidostas klase STR_STATION_BUILD_AIRPORT_LAYOUT_NAME :{BLACK}{NUM}. izkārtojums STR_AIRPORT_SMALL :Maza STR_AIRPORT_CITY :Lielpilsēta STR_AIRPORT_METRO :Metropolitēns STR_AIRPORT_INTERNATIONAL :Starptautiskā lidosta STR_AIRPORT_COMMUTER :Ikdienas satiksme STR_AIRPORT_INTERCONTINENTAL :Starpkontinentālā STR_AIRPORT_HELIPORT :Helikopteru osta STR_AIRPORT_HELIDEPOT :Helikopteru depo STR_AIRPORT_HELISTATION :Helikopteru stacija STR_AIRPORT_CLASS_SMALL :Mazas lidostas STR_AIRPORT_CLASS_LARGE :Lielās lidostas STR_AIRPORT_CLASS_HUB :Centra lidostas STR_AIRPORT_CLASS_HELIPORTS :Helikopteru lidostas STR_STATION_BUILD_NOISE :{BLACK}Radītais troksnis: {GOLD}{COMMA} # Landscaping toolbar STR_LANDSCAPING_TOOLBAR :{WHITE}Ainavas veidošana STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}Pazemināt zemes stūri. Vilkšana pazemina pirmo izvēlēto stūri un nolīdzina izvēlēto laukumu uz stūra jauno augstumu. Ctrl iezīmē laukumu diagonāli. Shift pārslēdz būvēšanu/izmaksu novērtējuma rādīšanu STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}Pacelt zemes stūri. Vilkšana paceļ pirmo izvēlēto stūri un nolīdzina izvēlēto laukumu uz stūra jauno augstumu. Ctrl iezīmē laukumu diagonāli. Shift pārslēdz būvēšanu/izmaksu novērtējuma rādīšanu STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}Izlīdzināt zemes laukumu pirmā izvēlētā stūra augstumā. Ctrl iezīmē laukumu diagonāli. Shift pārslēdz būvēšanu/izmaksu novērtējuma rādīšanu STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}Pirkt zemi vēlākai lietošanai. Shift pārslēdz būvēšanu/izmaksu novērtējuma rādīšanu # Object construction window STR_OBJECT_BUILD_CAPTION :{WHITE}Objektu izvēle STR_OBJECT_BUILD_TOOLTIP :{BLACK}Izvēlēties objektu būvniecībai. Shift pārslēdz būvniecību/izmaksu attēlošanu STR_OBJECT_BUILD_CLASS_TOOLTIP :{BLACK}Izvēlēties būvējamā objekta klasi STR_OBJECT_BUILD_PREVIEW_TOOLTIP :{BLACK}Objekta priekšskatījums STR_OBJECT_BUILD_SIZE :{BLACK}Izmērs: {GOLD}{NUM} x {NUM} lauciņi STR_OBJECT_CLASS_LTHS :Bākas STR_OBJECT_CLASS_TRNS :Raidītāji # Tree planting window (last two for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Koki STR_PLANT_TREE_TOOLTIP :{BLACK}Izvēlēties koka veidu stādīšanai. Ja lauciņš jau ir koks, tas pievienos vairāk jauktu veidu kokus neatkarīgi no izvēlētā veida STR_TREES_RANDOM_TYPE :{BLACK}Nejauši izvēlēta veida koki STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Izvietot nejaušus kokus. Shift pārslēdz būve/rādīt izmaksu tāmi STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Nejauši koki STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Stādīt nejaušus kokus visā ainavā # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Zemes radīšana STR_TERRAFORM_TOOLTIP_PLACE_ROCKY_AREAS_ON_LANDSCAPE :{BLACK}Ainavā novietot akmeņainus apvidus STR_TERRAFORM_TOOLTIP_DEFINE_DESERT_AREA :{BLACK}Norādīt tuksneša laukumu.{}Turēt nospiestu Ctrl, lai to noņemtu STR_TERRAFORM_TOOLTIP_INCREASE_SIZE_OF_LAND_AREA :{BLACK}Palielināt zemes apgabalu pazemināšanai/paaugstināšanai STR_TERRAFORM_TOOLTIP_DECREASE_SIZE_OF_LAND_AREA :{BLACK}Samazināt zemes apgabalu pazemināšanai/paaugstināšanai STR_TERRAFORM_TOOLTIP_GENERATE_RANDOM_LAND :{BLACK}Radīt nejaušu zemi STR_TERRAFORM_SE_NEW_WORLD :{BLACK}Izveidot jaunu scenāriju STR_TERRAFORM_RESET_LANDSCAPE :{BLACK}Atiestatīt ainavu STR_TERRAFORM_RESET_LANDSCAPE_TOOLTIP :{BLACK}Novākt visus spēlētājam piederošos īpašumus no kartes STR_QUERY_RESET_LANDSCAPE_CAPTION :{WHITE}Atiestatīt ainavu STR_RESET_LANDSCAPE_CONFIRMATION_TEXT :{WHITE}Vai tiešām vēlaties novākt visus uzņēmumam piederošos īpašumus? # Town generation window (SE) STR_FOUND_TOWN_CAPTION :{WHITE}Pilsētu radīšana STR_FOUND_TOWN_NEW_TOWN_BUTTON :{BLACK}Jauna pilsēta STR_FOUND_TOWN_NEW_TOWN_TOOLTIP :{BLACK}Dibināt jaunu pilsētu. Shift+klikšķis rāda tikai izmaksu tāmi STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Nejauša pilsēta STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Dibināt pilsētu nejaušā vietā STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Daudz nejauši izveidotu pilsētu STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Pārklāt karti ar nejauši izvietotām pilsētām STR_FOUND_TOWN_NAME_TITLE :{YELLOW} Pilsētas nosaukums: STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Ievadīt pilsētas nosaukumu STR_FOUND_TOWN_NAME_EDITOR_HELP :{BLACK}Klikšķināt, lai ievadītu pilsētas nosaukumu STR_FOUND_TOWN_NAME_RANDOM_BUTTON :{BLACK}Gadījuma nosaukums STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP :{BLACK}Radīt jaunu gadījuma nosaukumu STR_FOUND_TOWN_INITIAL_SIZE_TITLE :{YELLOW}Pilsētas izmēri: STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}Mazs STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON :{BLACK}Vidējs STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON :{BLACK}Liels STR_FOUND_TOWN_SIZE_RANDOM :{BLACK}Nejaušs STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Izvēlēties pilsētas izmērus STR_FOUND_TOWN_CITY :{BLACK}Lielpilsēta STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Lielpilsētas attīstās ātrāk kā pilsētas{}Atkarībā no iestatījumiem, dibināšanas brīdī tās ir lielākas STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Pilsētas ceļu izskats: STR_FOUND_TOWN_SELECT_TOWN_ROAD_LAYOUT :{BLACK}Atlasīt šajā pilsētā lietojamo ceļu izkārtojumu STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL :{BLACK}Sākotnēji STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS :{BLACK}Labāki ceļi STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID :{BLACK}2x2 režģis STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID :{BLACK}3x3 režģis STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}Nejaušs # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}Finansēt jaunu ražotni STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}Izvēlēties no saraksta atbilstošu ražotni STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :Daudz nejauši izveidotu ražotņu STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Pārklāt karti ar nejauši izvietotām ražotnēm STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Izmaksā: {YELLOW}{CURRENCY_LONG} STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Pētīt STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Būvēt STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Finansēt # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Ražotnes '{STRING}' kravu ķēde STR_INDUSTRY_CARGOES_CARGO_CAPTION :{WHITE}{STRING} kravas ražotņu ķēde STR_INDUSTRY_CARGOES_PRODUCERS :{WHITE}Ražotāji STR_INDUSTRY_CARGOES_CUSTOMERS :{WHITE}Patērētāji STR_INDUSTRY_CARGOES_HOUSES :{WHITE}Mājas STR_INDUSTRY_CARGOES_INDUSTRY_TOOLTIP :{BLACK}Klikšķināt uz ražotnes, lai redzētu tās piegādātājus un patērētājus STR_INDUSTRY_CARGOES_CARGO_TOOLTIP :{BLACK}{STRING}{}Klikšķināt uz kravas, lai redzētu tās piegādātājus un patērētājus STR_INDUSTRY_DISPLAY_CHAIN :{BLACK}Rādīt ķēdi STR_INDUSTRY_DISPLAY_CHAIN_TOOLTIP :{BLACK}Rādīt kravas ražojošās un patērējošās ražotnes STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP :{BLACK}Piesaistīt minikartei STR_INDUSTRY_CARGOES_NOTIFY_SMALLMAP_TOOLTIP :{BLACK}Izvēlēties arī minikartē attēlotās rūpnīcas STR_INDUSTRY_CARGOES_SELECT_CARGO :{BLACK}Atlasīt kravu STR_INDUSTRY_CARGOES_SELECT_CARGO_TOOLTIP :{BLACK}Izvēlēties, kuru kravu ir jāattēlo STR_INDUSTRY_CARGOES_SELECT_INDUSTRY :{BLACK}Atlasīt ražotni STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Izvēlēties, kuru ražotni ir jāattēlo # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Zemes platības informācija STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Notīrīšanas izmaksa: {LTBLUE}nav zināma STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Notīrīšanas izmaksa: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Ieņēmumi pēc notīrīšanas: {LTBLUE}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_OWNER_N_A :Nav STR_LAND_AREA_INFORMATION_OWNER :{BLACK}Īpašnieks: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_ROAD_OWNER :{BLACK}Ceļa īpašnieks: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_TRAM_OWNER :{BLACK}Tramvaju ceļa īpašnieks: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER :{BLACK}Dzelzceļa īpašnieks: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_RAIL_OWNER.kas :{G=f}{BLACK}Dzelzceļa īpašniece: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY :{BLACK}Pašvaldība: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE :Neviena STR_LAND_AREA_INFORMATION_LANDINFO_COORDS :{BLACK}Koordinātes: {LTBLUE}{NUM} x {NUM} x {NUM} ({STRING}) STR_LAND_AREA_INFORMATION_BUILD_DATE :{BLACK}Uzbūvēts: {LTBLUE}{DATE_LONG} STR_LAND_AREA_INFORMATION_STATION_CLASS :{BLACK}Stacijas klase: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_STATION_TYPE :{BLACK}Stacijas tips: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_CLASS :{BLACK}Lidostas klase: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORT_NAME :{BLACK}Lidostas nosaukums: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_AIRPORTTILE_NAME :{BLACK}Lidostas lauciņa nosaukums: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_NEWGRF_NAME :{BLACK}NewGRF: {LTBLUE}{STRING} STR_LAND_AREA_INFORMATION_CARGO_ACCEPTED :{BLACK}Pieņem kravu: {LTBLUE} STR_LAND_AREA_INFORMATION_CARGO_EIGHTS :({COMMA}/8 {STRING}) STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Sliežu ātruma ierobežojums: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Ceļa ātruma ierobežojums: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Akmeņi STR_LAI_CLEAR_DESCRIPTION_ROUGH_LAND :Nelīdzena zeme STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Kaila zeme STR_LAI_CLEAR_DESCRIPTION_GRASS :Zālājs STR_LAI_CLEAR_DESCRIPTION_FIELDS :Lauki STR_LAI_CLEAR_DESCRIPTION_SNOW_COVERED_LAND :Apsnigusi zeme STR_LAI_CLEAR_DESCRIPTION_DESERT :Tuksnesis STR_LAI_RAIL_DESCRIPTION_TRACK :{STRING} sliedes STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :{STRING} ceļš ar bloķēšanas signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRESIGNALS :{STRING} sliedes ar pirmssignālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXITSIGNALS :{STRING} sliedes ar izejas signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBOSIGNALS :{STRING} sliedes ar kombinētajām signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBSSIGNALS :{STRING} sliedes ar ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NOENTRYSIGNALS :{STRING} sliedes ar vienvirziena ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PRESIGNALS :{STRING} sliedes ar bloka un pirmssignālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_EXITSIGNALS :{STRING} sliedes ar bloka un izejas signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_COMBOSIGNALS :{STRING} sliedes ar bloka un kombinētajām signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_PBSSIGNALS :{STRING} sliedes ar bloka un ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_NOENTRYSIGNALS :{STRING} sliedes ar bloka un vienvirziena ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_EXITSIGNALS :{STRING} sliedes ar izejas un pirmssignālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_COMBOSIGNALS :{STRING} sliedes ar kombinētajām un pirmssignālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_PBSSIGNALS :{STRING} sliedes ar ceļu un pirmssignālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PRE_NOENTRYSIGNALS :{STRING} sliedes ar vienvirziena ceļu un pirmssignālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_COMBOSIGNALS :{STRING} sliedes ar izejas un kombinētajām signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_PBSSIGNALS :{STRING} sliedes ar izejas un ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_EXIT_NOENTRYSIGNALS :{STRING} sliedes ar izejas un vienvirziena ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_PBSSIGNALS :{STRING} sliedes ar kombinētajām un ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_COMBO_NOENTRYSIGNALS :{STRING} sliedes ar kombinētajām un vienvirziena ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_PBS_NOENTRYSIGNALS :{STRING} sliedes ar ceļa un vienvirziena ceļa signālierīcēm STR_LAI_RAIL_DESCRIPTION_TRAIN_DEPOT :{STRING} vilcienu depo STR_LAI_ROAD_DESCRIPTION_ROAD :Ceļš STR_LAI_ROAD_DESCRIPTION_ROAD_WITH_STREETLIGHTS :Ceļš ar ielu apgaismojumu STR_LAI_ROAD_DESCRIPTION_TREE_LINED_ROAD :Aleja STR_LAI_ROAD_DESCRIPTION_ROAD_VEHICLE_DEPOT :Autotransporta depo STR_LAI_ROAD_DESCRIPTION_ROAD_RAIL_LEVEL_CROSSING :Dzelzceļa pārbrauktuve STR_LAI_ROAD_DESCRIPTION_TRAMWAY :Tramvajs # Houses come directly from their building names STR_LAI_TOWN_INDUSTRY_DESCRIPTION_UNDER_CONSTRUCTION :{STRING} (notiek būvdarbi) STR_LAI_TREE_NAME_TREES :Koki STR_LAI_TREE_NAME_RAINFOREST :Lietus meži STR_LAI_TREE_NAME_CACTUS_PLANTS :Kaktusi STR_LAI_STATION_DESCRIPTION_RAILROAD_STATION :Dzelzceļa stacija STR_LAI_STATION_DESCRIPTION_AIRCRAFT_HANGAR :Lidaparātu angārs STR_LAI_STATION_DESCRIPTION_AIRPORT :Lidosta STR_LAI_STATION_DESCRIPTION_TRUCK_LOADING_AREA :Kravas iekraušanas zona STR_LAI_STATION_DESCRIPTION_BUS_STATION :Autoosta STR_LAI_STATION_DESCRIPTION_SHIP_DOCK :Kuģu piestātne STR_LAI_STATION_DESCRIPTION_BUOY :Boja STR_LAI_STATION_DESCRIPTION_WAYPOINT :Pieturas punkts STR_LAI_WATER_DESCRIPTION_WATER :Ūdens STR_LAI_WATER_DESCRIPTION_CANAL :Kanāls STR_LAI_WATER_DESCRIPTION_LOCK :Slūžas STR_LAI_WATER_DESCRIPTION_RIVER :Upe STR_LAI_WATER_DESCRIPTION_COAST_OR_RIVERBANK :Jūras vai upes krasts STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Kuģu depo # Industries come directly from their industry names STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Dzelzceļa tunelis STR_LAI_TUNNEL_DESCRIPTION_ROAD :Autoceļa tunelis STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Tērauda vanšu dzelzceļa tilts STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL :Tērauda dzelzceļa tilts STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL :Tērauda konsoles dzelzceļa tilts STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE :Dzelzbetona vanšu dzelzceļa tilts STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN :Koka dzelzeļa tilts STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE :Betona dzelzceļa tilts STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL :Cauruļveida dzelzceļa tilts STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL :Tērauda vanšu tilts STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL :Tērauda tilts STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL :Tērauda konsoles tilts STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE :Dzelzbetona vanšu tilts STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN :Koka tilts STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE :Betona tilts STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL :Cauruļveida tilts STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT :Akvadukts STR_LAI_OBJECT_DESCRIPTION_TRANSMITTER :Raidītājs STR_LAI_OBJECT_DESCRIPTION_LIGHTHOUSE :Bāka STR_LAI_OBJECT_DESCRIPTION_COMPANY_HEADQUARTERS :Uzņēmuma birojs STR_LAI_OBJECT_DESCRIPTION_COMPANY_OWNED_LAND :Uzņēmumam piederoša zeme # About OpenTTD window STR_ABOUT_OPENTTD :{WHITE}Par OpenTTD STR_ABOUT_ORIGINAL_COPYRIGHT :{BLACK}Oriģināla autortiesības {COPYRIGHT} 1995 Kriss Sojers. Visas tiesības paturētas STR_ABOUT_VERSION :{BLACK}OpenTTD versija {REV} STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD {COPYRIGHT} 2002-2015 OpenTTD darba grupa # Save/load game/scenario STR_SAVELOAD_SAVE_CAPTION :{WHITE}Saglabāt spēli STR_SAVELOAD_LOAD_CAPTION :{WHITE}Ielādēt spēli STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Saglabāt scenāriju STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Ielādēt scenāriju STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Ielādēt augstumu karti STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Saglabāt augstumu karti STR_SAVELOAD_HOME_BUTTON :{BLACK}Klikšķināt šeit, lai pārietu uz pašreizējo saglabāšanas/ielādēšanas mapi STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} brīv{P s i u} STR_SAVELOAD_LIST_TOOLTIP :{BLACK}Disku, mapju un saglabāto spēļu failu saraksts STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Šobrīd izvēlētais saglabājamās spēles nosaukums STR_SAVELOAD_DELETE_BUTTON :{BLACK}Dzēst STR_SAVELOAD_DELETE_TOOLTIP :{BLACK}Dzēst šobrīd atlasīto saglabāto spēli STR_SAVELOAD_SAVE_BUTTON :{BLACK}Saglabāt STR_SAVELOAD_SAVE_TOOLTIP :{BLACK}Saglabāt šo spēli izmantojot izvēlēto nosaukumu STR_SAVELOAD_LOAD_BUTTON :{BLACK}Ielādēt STR_SAVELOAD_LOAD_TOOLTIP :{BLACK}Ielādēt izvēlēto spēli STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP :{BLACK}Ielādēt atlasīto augstumu karti STR_SAVELOAD_DETAIL_CAPTION :{BLACK}Spēles īpašības STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Nav pieejamas informācijas STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_OSKTITLE :{BLACK}Ievadīt saglabātās spēles nosaukumu # World generation STR_MAPGEN_WORLD_GENERATION_CAPTION :{WHITE}Pasaules radīšana STR_MAPGEN_MAPSIZE :{BLACK}Kartes izmēri: STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Pilsētu daudzums: STR_MAPGEN_DATE :{BLACK}Datums: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Ražotņu daudzums: STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}Maksimālais kartes augstums STR_MAPGEN_MAX_HEIGHTLEVEL_UP :{BLACK}Palielināt kalnu maksimālo augstumu kartē par vienu vienību STR_MAPGEN_MAX_HEIGHTLEVEL_DOWN :{BLACK}Samazināt kalnu maksimālu augstumu kartē par vienu vienību STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}Sniega līnijas augstums STR_MAPGEN_SNOW_LINE_UP :{BLACK}Paaugstināt sniega līnijas augstumu STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}Pazemināt sniega līnijas augstumu STR_MAPGEN_LAND_GENERATOR :{BLACK}Zemes radītājs: STR_MAPGEN_TREE_PLACER :{BLACK}Koku algoritms: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Apvidus reljefs: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Jūras līmenis: STR_MAPGEN_QUANTITY_OF_RIVERS :{BLACK}Upes: STR_MAPGEN_SMOOTHNESS :{BLACK}Gludums: STR_MAPGEN_VARIETY :{BLACK}Dažādības sadalījums: STR_MAPGEN_GENERATE :{WHITE}Radīt # Strings for map borders at game generation STR_MAPGEN_BORDER_TYPE :{BLACK}Kartes malas: STR_MAPGEN_NORTHWEST :{BLACK}Ziemeļrietumi STR_MAPGEN_NORTHEAST :{BLACK}Ziemeļaustrumi STR_MAPGEN_SOUTHEAST :{BLACK}Dienvidaustrumi STR_MAPGEN_SOUTHWEST :{BLACK}Dienvidrietumi STR_MAPGEN_BORDER_FREEFORM :{BLACK}Brīvā forma STR_MAPGEN_BORDER_WATER :{BLACK}Ūdens STR_MAPGEN_BORDER_RANDOM :{BLACK}Nejauša STR_MAPGEN_BORDER_RANDOMIZE :{BLACK}Nejaušas STR_MAPGEN_BORDER_MANUAL :{BLACK}Manuāli STR_MAPGEN_HEIGHTMAP_ROTATION :{BLACK}Augstumu kartes pagriešana: STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Augstumu kartes nosaukums: STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Lielums: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} STR_MAPGEN_MAX_HEIGHTLEVEL_QUERY_CAPT :{WHITE}Mainīt kartes maksimālo augstumu STR_MAPGEN_SNOW_LINE_QUERY_CAPT :{WHITE}Mainīt sniega līnijas augstumu STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Mainīt sākuma gadu # SE Map generation STR_SE_MAPGEN_CAPTION :{WHITE}Scenārija veids STR_SE_MAPGEN_FLAT_WORLD :{WHITE}Līdzena zeme STR_SE_MAPGEN_FLAT_WORLD_TOOLTIP :{BLACK}Radīt līdzenu zemi STR_SE_MAPGEN_RANDOM_LAND :{WHITE}Nejauša zeme STR_SE_MAPGEN_FLAT_WORLD_HEIGHT :{BLACK}Līdzenas zemes augstums: STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_DOWN :{BLACK}Par vienu līmeni samazināt līdzenas zemes augstumu STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_UP :{BLACK}Par vienu līmeni palielināt līdzenas zemes augstumu STR_SE_MAPGEN_FLAT_WORLD_HEIGHT_QUERY_CAPT :{WHITE}Mainīt zemes augstumu # Map generation progress STR_GENERATION_WORLD :{WHITE}Pasaules radīšana... STR_GENERATION_ABORT :{BLACK}Atcelt STR_GENERATION_ABORT_CAPTION :{WHITE}Atcelt pasaules radīšanu STR_GENERATION_ABORT_MESSAGE :{YELLOW}Vai jūs patiešām vēlaties atcelt radīšanu? STR_GENERATION_PROGRESS :{WHITE}{NUM}% pabeigti STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} STR_GENERATION_WORLD_GENERATION :{BLACK}Pasaules radīšana STR_GENERATION_RIVER_GENERATION :{BLACK}Upes radīšana STR_GENERATION_TREE_GENERATION :{BLACK}Koka radīšana STR_GENERATION_OBJECT_GENERATION :{BLACK}Objekta radīšana STR_GENERATION_CLEARING_TILES :{BLACK}Nelīdzena un akmeņaina apvidus radīšana STR_GENERATION_SETTINGUP_GAME :{BLACK}Iestatīt spēli STR_GENERATION_PREPARING_TILELOOP :{BLACK}Skrejošs nosaukums STR_GENERATION_PREPARING_SCRIPT :{BLACK}Strādājošs skripts STR_GENERATION_PREPARING_GAME :{BLACK}Sagatavo spēli # NewGRF settings STR_NEWGRF_SETTINGS_CAPTION :{WHITE}NewGRF iestatījumi STR_NEWGRF_SETTINGS_INFO_TITLE :{WHITE}NewGRF detalizēta informācija STR_NEWGRF_SETTINGS_ACTIVE_LIST :{WHITE}Aktīvie NewGRF faili STR_NEWGRF_SETTINGS_INACTIVE_LIST :{WHITE}Neaktīvie NewGRF faili STR_NEWGRF_SETTINGS_SELECT_PRESET :{ORANGE}Izvēlēties paraugu: STR_NEWGRF_FILTER_TITLE :{ORANGE}Filtra virkne: STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP :{BLACK}Ielādēt atlasīto iepriekšiestatījumu STR_NEWGRF_SETTINGS_PRESET_SAVE :{BLACK}Saglabāt iepriekšiestatījumu STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP :{BLACK}Saglabāt šo sarakstu kā iepriekšiestatījumu STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY :{BLACK}Ievadīt iepriekšiestatījuma nosaukumu STR_NEWGRF_SETTINGS_PRESET_DELETE :{BLACK}Dzēst iepriekšiestatījumu STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP :{BLACK}Dzēst šobrīd atlasīto iepriekšiestatījumu STR_NEWGRF_SETTINGS_ADD :{BLACK}Pievienot STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP :{BLACK}Pievienot atlasītos NewGRF failus jūsu konfigurācijai STR_NEWGRF_SETTINGS_RESCAN_FILES :{BLACK}Pārskenēt failus STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP :{BLACK}Atjaunināt pieejamo NewGRF failu sarakstu STR_NEWGRF_SETTINGS_REMOVE :{BLACK}Noņemt STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP :{BLACK}Noņemt atlasīto NewGRF failu no saraksta STR_NEWGRF_SETTINGS_MOVEUP :{BLACK}Uz augšu STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP :{BLACK}Pārvietot atlasīto NewGRF failu saraksta augšā STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Uz leju STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Pārvietot atlasīto NewGRF failu saraksta apakšā STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}Instalēto NewGRF failu saraksts. STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Iestatīt parametrus STR_NEWGRF_SETTINGS_SHOW_PARAMETERS :{BLACK}Rādīt parametrus STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Pārslēgt paleti STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP :{BLACK}Mainīt atlasītā New GRF paleti.{}Tas jādara ja NewGRF grafika izskatās sārta STR_NEWGRF_SETTINGS_APPLY_CHANGES :{BLACK}Lietot izmaiņas STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON :{BLACK}Meklēt pazudušo saturu tiešaisaistē STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP :{BLACK}Pārbaudīt vai pazudušais saturs nav atrodams tiešsaistē. STR_NEWGRF_SETTINGS_FILENAME :{BLACK}Faila nosaukums: {SILVER}{STRING} STR_NEWGRF_SETTINGS_GRF_ID :{BLACK}GRF ID: {SILVER}{STRING} STR_NEWGRF_SETTINGS_VERSION :{BLACK}Versija: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Zemākā savietojamā versija: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Palete: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parametri: {SILVER}{STRING} STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}Informācija nav pieejama STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Nevar atrast saskanīgu failu STR_NEWGRF_SETTINGS_DISABLED :{RED}Atspējots STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Nav savietojams ar šo OpenTTD versiju # NewGRF save preset window STR_SAVE_PRESET_CAPTION :{WHITE}Iepriekšiestatījuma saglabāšana STR_SAVE_PRESET_EDITBOX_TOOLTIP :{BLACK}Pašlaik izvēlētā iepriekšiestatījuma nosaukums saglabāšanai STR_SAVE_PRESET_CANCEL :{BLACK}Atcelt STR_SAVE_PRESET_CANCEL_TOOLTIP :{BLACK}Nemainīt iepriekšiestatījumu STR_SAVE_PRESET_SAVE :{BLACK}Saglabāt # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}Mainīt NewGRF parametrus STR_NEWGRF_PARAMETERS_CLOSE :{BLACK}Aizvērt STR_NEWGRF_PARAMETERS_RESET :{BLACK}Atjaunot STR_NEWGRF_PARAMETERS_RESET_TOOLTIP :{BLACK}Iestatīt visiem parametriem to noklusējuma vērtības STR_NEWGRF_PARAMETERS_DEFAULT_NAME :{NUM}. parametrs STR_NEWGRF_PARAMETERS_SETTING :{STRING}: {ORANGE}{STRING} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Parametru skaits: {ORANGE}{NUM} # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Pārbaude - {STRING} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Īpašnieks STR_NEWGRF_INSPECT_PARENT_TOOLTIP :{BLACK}Pārbaudīt objektu no īpašnieka līmeņa STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT :{STRING} adresē {HEX} STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_OBJECT :Objekts STR_NEWGRF_INSPECT_CAPTION_OBJECT_AT_RAIL_TYPE :Sliežu veids STR_NEWGRF_INSPECT_QUERY_CAPTION :{WHITE}NewGRF mainīgā 60+x parametrs (heksadecimāls) # Sprite aligner window STR_SPRITE_ALIGNER_CAPTION :{WHITE}Gariņa līdzināšana {COMMA} ({STRING}) STR_SPRITE_ALIGNER_NEXT_BUTTON :{BLACK}Nākamais gariņš STR_SPRITE_ALIGNER_NEXT_TOOLTIP :{BLACK}Pāriet uz nākamo parasto gariņu, izlaižot visus pseido/pārkrāsotos/fonta gariņus STR_SPRITE_ALIGNER_GOTO_BUTTON :{BLACK}Iet pie gariņa STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Iet pie dotā gariņa. Ja tas nav parastais gariņš, tad pāriet pie nākamā STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Iepriekšējais gariņš STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Iet pie iepriekšējā parastā gariņa, izlaižot visus pseido/pārkrāsotos/fonta gariņus STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Atlasītā gariņa attēlojums. To attēlojot, izkārtojums netiek ievērots STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Pārvietot gariņu, lai mainītu X un Y vērtības STR_SPRITE_ALIGNER_PICKER_BUTTON :{BLACK}Paņemt gariņu STR_SPRITE_ALIGNER_PICKER_TOOLTIP :{BLACK}Paņemt gariņu no jebkuras vietas ekrānā STR_SPRITE_ALIGNER_GOTO_CAPTION :{WHITE}Iet pie gariņa # NewGRF (self) generated warnings/errors STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_WARNING :{RED}Brīdinājums: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Kļūda: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatāls: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Notikusi fatāla NewGRF kļūda: {}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} nedarbosies kopā ar TTDPatch versiju (par ko ziņoja OpenTTD). STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} ir TTD {STRING} versijai STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ir paredzēts lietošanai kopā ar {STRING} STR_NEWGRF_ERROR_INVALID_PARAMETER :Nepareizs parametrs priekš {1:STRING}: parametrs {STRING} ({NUM}) STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING} jābūt ielādētam pirms {STRING}. STR_NEWGRF_ERROR_LOAD_BEFORE.kas :{G=f}{1:STRING} jābūt ielādētai pirms {STRING}. STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING} jābūt ielādētam pēc {STRING}. STR_NEWGRF_ERROR_LOAD_AFTER.kas :{G=f}{1:STRING} jābūt ielādētai pēc {STRING}. STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING} ir vajadzīga Open TTD versija {STRING} vai labāka STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :GRF fails radīts tulkošanai STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :Ir ielādēti pārāk daudzi NewGRF STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :Ielādē {1:STRING} kā statisks NewGRF {STRING} var radīt desinhronizāciju STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :Neparedzēts gariņš (gariņš {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :Nezināma Action 0 īpašība {4:HEX} (gariņš {3:NUM}) STR_NEWGRF_ERROR_INVALID_ID :Mēģinājums izmantot nederīgu ID (gariņš {3:NUM}) STR_NEWGRF_ERROR_CORRUPT_SPRITE :{YELLOW}{STRING} satur bojātu gariņu. Visi bojātie gariņi tiks parādīti ar sarkanu jautājuma zīmi (?) STR_NEWGRF_ERROR_MULTIPLE_ACTION_8 :Satur vairākus Action 8 ierakstus (gariņš {3:NUM}) STR_NEWGRF_ERROR_READ_BOUNDS :Lasīt aiz pseidogariņa beigām (gariņš {3:NUM}) STR_NEWGRF_ERROR_MISSING_SPRITES :{WHITE}Pašlaik lietotajai pamata grafikas kopai trūkst daļa gariņu.{}Lūdzu atjauniniet pamata grafikas kopu STR_NEWGRF_ERROR_MISSING_SPRITES_UNSTABLE :{WHITE}Pašlaik lietotajai pamata grafikas kopai trūkst daļa gariņu.{}Lūdzu atjauniniet pamata grafikas kopu.{}Tā kā jūs spēlējat {YELLOW}OpenTTD izstrādes momentuzņēmumu{WHITE}, jums varētu būt nepieciešams arī {YELLOW}pamata grafikas izstrādes momentuzņēmums{WHITE} STR_NEWGRF_ERROR_GRM_FAILED :Pieprasītie GRF resursi nav pieejami (gariņš {3:NUM}) STR_NEWGRF_ERROR_FORCEFULLY_DISABLED :{1:STRING} ar {2:STRING} tika atspējots STR_NEWGRF_ERROR_INVALID_SPRITE_LAYOUT :Nederīgs/nezināms gariņa izkārtojuma formāts (gariņš {3:NUM}) # NewGRF related 'general' warnings STR_NEWGRF_POPUP_CAUTION_CAPTION :{WHITE}Uzmanību! STR_NEWGRF_CONFIRMATION_TEXT :{YELLOW}Jūs grasāties veikt izmaiņas palaistai spēlei. Tas var izraisīt OpenTTD avāriju vai salauzt spēles stāvokli. Par šīm problēmām kļūdu ziņojumus nesūtiet.{}Vai jūs esat par to pilnībā pārliecināts? STR_NEWGRF_DUPLICATE_GRFID :{WHITE}Nevar pievienot failu: vienādi GRF ID STR_NEWGRF_COMPATIBLE_LOADED :{ORANGE}Atbilstošs fails nav atrasts (ielādēts saderīgs GRF) STR_NEWGRF_COMPATIBLE_LOAD_WARNING :{WHITE}Saderīgs GRF(s) ielādēts pazudušajiem failiem STR_NEWGRF_DISABLED_WARNING :{WHITE}Trūkstošie GRF faili tikuši atspējoti STR_NEWGRF_UNPAUSE_WARNING_TITLE :{YELLOW}Trūkst GRF fails(i) STR_NEWGRF_UNPAUSE_WARNING :{WHITE}Atpauzēšana var izraisīt OpenTTD avāriju. Neziņot izstrādātājiem par šo kļudu.{}Vai patiešām vēlies atpauzēt? # NewGRF status STR_NEWGRF_LIST_NONE :Nekas STR_NEWGRF_LIST_ALL_FOUND :Visi faili ir pieejami STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Atrasti savietojami faili STR_NEWGRF_LIST_MISSING :{RED}Trūkst faili # NewGRF 'it's broken' warnings STR_NEWGRF_BROKEN :{WHITE}NewGRF uzvedība '{0:STRING}' visticamāk izraisīs desinhronizācijas vai avārijas STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Tas mainīja '{1:ENGINE}' vilcējvagona stāvokli ārpus depo STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Tas mainīja transportlīdzekļa '{1:ENGINE}' garumu, kad tas neatradās depo STR_BROKEN_VEHICLE_LENGTH :{WHITE}Vilciens '{VEHICLE}', kas pieder '{COMPANY}' ir ar nepareizu garumu. Iespējams, vainīga problēma ar NewGRF. Spēle var desinhronizēties vai avarēt STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' sniedz nepareizu informāciju STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}'{1:ENGINE}' kravas pielāgošanas informācija pēc izbūves atšķiras no pārdošanas sarakstā norādītās. Tas var liegt automātiskai atjaunošanai/aizvietošanai pareizi pielāgot kravas STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' izraisīja bezgalīgu ražošanas izsaukumu ciklu STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Izsaukums {1:HEX} atgrieza nezināmu vai nederīgu rezultātu {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : STR_NEWGRF_INVALID_CARGO_ABBREV :?? STR_NEWGRF_INVALID_CARGO_QUANTITY :{COMMA} STR_NEWGRF_INVALID_ENGINE : STR_NEWGRF_INVALID_INDUSTRYTYPE : # Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). STR_INVALID_VEHICLE : # NewGRF scanning window STR_NEWGRF_SCAN_CAPTION :{WHITE}Skenē NewGRF STR_NEWGRF_SCAN_MESSAGE :{BLACK}Skenē NewGRF. Atkarībā no apjoma, tas var aizņemt kādu brīdi... STR_NEWGRF_SCAN_STATUS :{BLACK}{NUM} NewGRF noskenēja apmēram {NUM} NewGRF STR_NEWGRF_SCAN_ARCHIVES :Skenē arhīvus # Sign list window STR_SIGN_LIST_CAPTION :{WHITE}Zīmju saraksts - {COMMA} zīm{P e es ju} STR_SIGN_LIST_MATCH_CASE :{BLACK}Saskaņot lielos/mazos burtus STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}Pārslēgt lielo/mazo burtu ievērošanu, filtrējot zīmju nosaukumus # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}Labot zīmi STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}Doties uz nākamo zīmi STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}Doties uz iepriekšējo zīmi STR_EDIT_SIGN_SIGN_OSKTITLE :{BLACK}Ievadīt zīmes nosaukumu # Town directory window STR_TOWN_DIRECTORY_CAPTION :{WHITE}Pilsētas STR_TOWN_DIRECTORY_NONE :{G=m}{ORANGE}- Neviens - STR_TOWN_DIRECTORY_NONE.kas :{G=f}{ORANGE}- Neviena - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Pilsētu nosaukumi - klikšķināt uz nosaukuma, lai centrētu skatu uz to. Ctrl+klikšķis atvērs jaunu skatu lauku uz pilsētu STR_TOWN_POPULATION :{BLACK}Pasaules iedzīvotāju skaits: {COMMA} # Town view window STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} STR_TOWN_VIEW_CITY_CAPTION :{WHITE}{TOWN} (lielpilsēta) STR_TOWN_VIEW_POPULATION_HOUSES :{BLACK}Iedzīvotāji: {ORANGE}{COMMA}{BLACK} Mājas: {ORANGE}{COMMA} STR_TOWN_VIEW_PASSENGERS_LAST_MONTH_MAX :{BLACK}Pasažieri pagājušajā mēnesī: {ORANGE}{COMMA}{BLACK} maksimāli: {ORANGE}{COMMA} STR_TOWN_VIEW_MAIL_LAST_MONTH_MAX :{BLACK}Pasts pagājušajā mēnesī: {ORANGE}{COMMA}{BLACK} maksimāli: {ORANGE}{COMMA} STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH :{BLACK}Krava nepieciešama pilsētas attīstībai: STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_GENERAL :{ORANGE}{STRING}{RED} nepieciešams STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED_WINTER :{ORANGE}{STRING}{BLACK} nepieciešams ziemā STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED_GENERAL :{ORANGE}{STRING}{GREEN} piegādāts STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_REQUIRED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{RED} (joprojām pieprasīts) STR_TOWN_VIEW_CARGO_FOR_TOWNGROWTH_DELIVERED :{ORANGE}{CARGO_TINY} / {CARGO_LONG}{GREEN} (piegādāts) STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}Pilsēta aug katr{P 0 u as u} {ORANGE}{COMMA}{BLACK}{NBSP}dien{P u as u} STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}Pilsēta aug katr{P 0 u as u} {ORANGE}{COMMA}{BLACK}{NBSP}dien{P u as u} (finansēta) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}Pilsēta {RED}neattīstās{BLACK} STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Trokšņu ierobežojums pilsētā: {ORANGE}{COMMA}{BLACK} maks.: {ORANGE}{COMMA} STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centrēt galveno skatu uz pilsētu. Ctrl+klikšķis atvērs skatu uz pilsētu jaunā skatlaukā STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Pašvaldība STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Rādīt informāciju par pašvaldību STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Pārdēvēt pilsētu STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Paplašināt STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Palielināt pilsētas izmērus STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Izdzēst STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Pilnībā dzēst šo pilsētu STR_TOWN_VIEW_RENAME_TOWN_BUTTON :Pārdēvēt pilsētu # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} pašvaldība STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}Transporta uzņēmumu vērtējumi: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}Pieejamās darbības: STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP :{BLACK}Šajā pilsētā atļauto darbību saraksts - klikšķināt uz atsevišķa priekšmeta, lai uzzinātu vairāk STR_LOCAL_AUTHORITY_DO_IT_BUTTON :{BLACK}Darīt STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP :{BLACK}Veikt iezīmēto darbību no augstāk esošā saraksta STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN :Maza reklāmas kampaņa STR_LOCAL_AUTHORITY_ACTION_MEDIUM_ADVERTISING_CAMPAIGN :Vidēja reklāmas kampaņa STR_LOCAL_AUTHORITY_ACTION_LARGE_ADVERTISING_CAMPAIGN :Liela reklāmas kampaņa STR_LOCAL_AUTHORITY_ACTION_ROAD_RECONSTRUCTION :Finansēt vietējo ceļu rekonstrukciju STR_LOCAL_AUTHORITY_ACTION_STATUE_OF_COMPANY :Uzbūvēt uzņēmuma vadītāja statuju STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Finansēt jaunas ēkas STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Pirkt pārvadājumu izņēmuma tiesības STR_LOCAL_AUTHORITY_ACTION_BRIBE :Dot kukuli pašvaldībai STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Veikt mazu reklāmas kampaņu, lai piesaistītu vairāk pasažieru un kravu savam uzņēmumam.{}Izmaksas: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Veikt vidēju reklāmas kampaņu, lai piesaistītu vairāk pasažieru un kravu savam uzņēmumam.{}Izmaksas: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Veikt lielu reklāmas kampaņu, lai piesaistītu vairāk pasažieru un kravu savam uzņēmumam.{}Izmaksas: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Finansēt ceļu remontdarbus. Rada satiksmes traucējumus līdz pat pusgadam.{}Izmaksas: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Uzbūvēt statuju par godu savam uzņēmumam.{}Izmaksas: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Finansēt jaunu komercēku būvniecību šajā pilsētā.{}Izmaksas: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Pirkt 1 gada izņēmuma tiesības uz kravu un pasažieru transportēšanu. Pašvaldība atļaus pasažieriem un kravas pārvešanai izmantot tkai jūsu uzņēmuma stacijas.{}Izmaksas: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Piekukuļot vietējo pašvaldību lai paceltu reitingu, riskējot saņemt lielu sodu.{}Izmaksas: {CURRENCY_LONG} # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} mērķi STR_GOALS_SPECTATOR_CAPTION :{WHITE}Globālie mērķi STR_GOALS_GLOBAL_TITLE :{BLACK}Globālie mērķi: STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Nav - STR_GOALS_SPECTATOR_NONE :{ORANGE}- Nav attiecināms - STR_GOALS_PROGRESS :{ORANGE}{STRING} STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_COMPANY_TITLE :{BLACK}Uzņēmuma mērķi: STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikšķināt uz mērķa, lai centrētu galveno skatu uz ražotni/pilsētu/lauciņu. Ctrl+klikšķis atver jaunu skatvietu uz ražotni/pilsētu/lauciņu # Goal question window STR_GOAL_QUESTION_CAPTION_QUESTION :Jautājums STR_GOAL_QUESTION_CAPTION_INFORMATION :Informācija STR_GOAL_QUESTION_CAPTION_WARNING :Brīdinājums STR_GOAL_QUESTION_CAPTION_ERROR :Kļūda ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Atcelt STR_GOAL_QUESTION_BUTTON_OK :Labi STR_GOAL_QUESTION_BUTTON_NO :Nē STR_GOAL_QUESTION_BUTTON_YES :Jā STR_GOAL_QUESTION_BUTTON_DECLINE :Noraidīt STR_GOAL_QUESTION_BUTTON_ACCEPT :Pieņemt STR_GOAL_QUESTION_BUTTON_IGNORE :Neievērot STR_GOAL_QUESTION_BUTTON_RETRY :Mēģināt vēl STR_GOAL_QUESTION_BUTTON_PREVIOUS :Iepriekšējais STR_GOAL_QUESTION_BUTTON_PREVIOUS.kas :{G=f}Iepriekšējā STR_GOAL_QUESTION_BUTTON_NEXT :Nākamais STR_GOAL_QUESTION_BUTTON_NEXT.kas :{G=f}Nākamā STR_GOAL_QUESTION_BUTTON_STOP :Apturēt STR_GOAL_QUESTION_BUTTON_START :Sākt STR_GOAL_QUESTION_BUTTON_GO :Doties STR_GOAL_QUESTION_BUTTON_CONTINUE :Turpināt STR_GOAL_QUESTION_BUTTON_RESTART :Pārstartēt STR_GOAL_QUESTION_BUTTON_POSTPONE :Atlikt STR_GOAL_QUESTION_BUTTON_SURRENDER :Padoties STR_GOAL_QUESTION_BUTTON_CLOSE :Aizvērt ############ End of Goal Question button list # Subsidies window STR_SUBSIDIES_CAPTION :{WHITE}Subsīdijas STR_SUBSIDIES_OFFERED_TITLE :{BLACK}Piedāvājumā esošās subsīdijas par pakalpojumu nodrošināšanu: STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING} no {STRING} līdz {STRING}{YELLOW} (no {DATE_SHORT}) STR_SUBSIDIES_NONE :{ORANGE}- Neviens - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Pašlaik subsidētie pakalpojumi: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} no {STRING} uz {STRING}{YELLOW} ({COMPANY}{YELLOW}, līdz {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Klikšķināt uz servisa, lai iecentrētu skatu uz rūpnīcu/pilsētu. Ctrl+klikšķis atvērs jaunu skatu lauku uz pilsētu/rūpnīcu # Story book window STR_STORY_BOOK_SPECTATOR_CAPTION :{WHITE}Globālā stāstu grāmata STR_STORY_BOOK_TITLE :{YELLOW}{STRING} STR_STORY_BOOK_GENERIC_PAGE_ITEM :{NUM} lapa STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Pārlēkt uz specifisku lapu spiežot to zemāk esošajā sarakstā. STR_STORY_BOOK_PREV_PAGE :{BLACK}Iepriekšējā STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Doties uz iepriekšējo lapu STR_STORY_BOOK_NEXT_PAGE :{BLACK}Nākamā STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Doties uz nākamo lapu STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Mērķa norāde ir nederīga # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Staciju nosaukumi - klikšķināt uz nosaukuma, lai centrētu galveno skatu uz staciju. Ctrl+klikšķis atvērs jaunu skatvietu pie stacijas STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Aizturēt Ctrl, lai izvēlētos vairākus STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} stacij{P a as u} STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- Nav - STR_STATION_LIST_SELECT_ALL_FACILITIES :{BLACK}Izvēlēties visu aprīkojumu STR_STATION_LIST_SELECT_ALL_TYPES :{BLACK}Izvēlēties visus kravas veidus (ieskaitot tos kas negaida) STR_STATION_LIST_NO_WAITING_CARGO :{BLACK}Neviena veida krava negaida # Station view window STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} STR_STATION_VIEW_EN_ROUTE_FROM :{YELLOW}({CARGO_SHORT} no {STATION}) STR_STATION_VIEW_ACCEPTS_BUTTON :{BLACK}Pieņem STR_STATION_VIEW_ACCEPTS_TOOLTIP :{BLACK}Rādīt pieņemamo kravu sarakstu STR_STATION_VIEW_ACCEPTS_CARGO :{BLACK}Pieņem: {WHITE}{CARGO_LIST} STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_SELF :{BLACK}Šai stacijai pieder izņēmuma pārvadājumu tiesības šajā pilsētā. STR_STATIOV_VIEW_EXCLUSIVE_RIGHTS_COMPANY :{YELLOW}{COMPANY}{BLACK} ir nopirktas izņēmuma pārvadājumu tiesības šajā pilsētā. STR_STATION_VIEW_RATINGS_BUTTON :{BLACK}Vērtējumi STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Rādīt stacijas vērtējumus STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Mēneša apgāde un vietējais vērtējums: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}%) STR_STATION_VIEW_GROUP :{BLACK}Grupēt pēc STR_STATION_VIEW_WAITING_STATION :Piestātne: Gaida STR_STATION_VIEW_WAITING_AMOUNT :Daudzums: Gaida STR_STATION_VIEW_PLANNED_STATION :Stacija: plānots STR_STATION_VIEW_PLANNED_AMOUNT :Apjoms: plānots STR_STATION_VIEW_FROM :{YELLOW}{CARGO_SHORT} no {STATION} STR_STATION_VIEW_VIA :{YELLOW}{CARGO_SHORT} caur {STATION} STR_STATION_VIEW_TO :{YELLOW}{CARGO_SHORT} uz {STATION} STR_STATION_VIEW_FROM_ANY :{RED}{CARGO_SHORT} no nezināmas piestātnes STR_STATION_VIEW_TO_ANY :{RED}{CARGO_SHORT} uz jebkuru staciju STR_STATION_VIEW_VIA_ANY :{RED}{CARGO_SHORT} caur jebkuru piestātni STR_STATION_VIEW_FROM_HERE :{GREEN}{CARGO_SHORT} no šīs stacijas STR_STATION_VIEW_VIA_HERE :{GREEN}{CARGO_SHORT} stājas šajā piestātnē STR_STATION_VIEW_TO_HERE :{GREEN}{CARGO_SHORT} uz šo piestātni STR_STATION_VIEW_NONSTOP :{YELLOW}{CARGO_SHORT} bez apstājas STR_STATION_VIEW_GROUP_S_V_D :Sākums-Caur-Mērķis STR_STATION_VIEW_GROUP_S_D_V :Sākums-Mērķis-Caur STR_STATION_VIEW_GROUP_V_S_D :Caur-Sākums-Mērķis STR_STATION_VIEW_GROUP_V_D_S :Caur-Mērķis-Sākums STR_STATION_VIEW_GROUP_D_S_V :Mērķis-Sākums-Caur STR_STATION_VIEW_GROUP_D_V_S :Mērķis-Caur-Sākums ############ range for rating starts STR_CARGO_RATING_APPALLING :drausmīgs STR_CARGO_RATING_VERY_POOR :ļoti vājš STR_CARGO_RATING_POOR :vājš STR_CARGO_RATING_MEDIOCRE :viduvējs STR_CARGO_RATING_GOOD :labs STR_CARGO_RATING_VERY_GOOD :ļoti labs STR_CARGO_RATING_EXCELLENT :lielisks STR_CARGO_RATING_OUTSTANDING :izcils ############ range for rating ends STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centrēt galveno skatu uz staciju. Ctrl+klikšķis atvērs skatu uz staciju jaunā skatlaukā STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Pārdēvēt staciju STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Rādīt vilcienus, kuru rīkojumu sarakstos ir šī stacija STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP :{BLACK}Rādīt autotransporta līdzekļus, kuru rīkojumu sarakstos ir šī stacija STR_STATION_VIEW_SCHEDULED_AIRCRAFT_TOOLTIP :{BLACK}Rādīt lidaparātus, kuru rīkojumu sarakstos ir šī stacija STR_STATION_VIEW_SCHEDULED_SHIPS_TOOLTIP :{BLACK}Rādīt kuģus, kuru rīkojumu sarakstos ir šī stacija STR_STATION_VIEW_RENAME_STATION_CAPTION :Pārdēvēt staciju/iekraušanas zonu STR_STATION_VIEW_CLOSE_AIRPORT :{BLACK}Slēgt lidostu STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Novērst lidaparātu nolaišanos šajā lidostā # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centrēt galveno skatu uz pieturas punktu. Ctrl+klikšķis atvērs skatu uz pieturas punktu jaunā skatulaukā STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Mainīt pieturas punkta nosaukumu STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centrēt galveno skatu uz boju. Ctrl+klikšķis atvērs skatu uz boju jaunā skatulaukā STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Mainīt bojas nosaukumu STR_EDIT_WAYPOINT_NAME :{WHITE}Labot pieturas punkta nosaukumu # Finances window STR_FINANCES_CAPTION :{WHITE}{COMPANY} finanses {BLACK}{COMPANY_NUM} STR_FINANCES_EXPENDITURE_INCOME_TITLE :{WHITE}Izdevumi/ienākumi STR_FINANCES_YEAR :{WHITE}{NUM} STR_FINANCES_SECTION_CONSTRUCTION :{GOLD}Būvniecība STR_FINANCES_SECTION_NEW_VEHICLES :{GOLD}Jauni transportlīdzekļi STR_FINANCES_SECTION_TRAIN_RUNNING_COSTS :{GOLD}Vilcienu kārtējās izmaksas STR_FINANCES_SECTION_ROAD_VEHICLE_RUNNING_COSTS :{GOLD}Autotransporta kārtējās izmaksas STR_FINANCES_SECTION_AIRCRAFT_RUNNING_COSTS :{GOLD}Lidaparātu kārtējās izmaksas STR_FINANCES_SECTION_SHIP_RUNNING_COSTS :{GOLD}Kuģu kārtējās izmaksas STR_FINANCES_SECTION_PROPERTY_MAINTENANCE :{GOLD}Īpašumu uzturēšana STR_FINANCES_SECTION_TRAIN_INCOME :{GOLD}Vilcienu ienākumi STR_FINANCES_SECTION_ROAD_VEHICLE_INCOME :{GOLD}Autotransporta ienākumi STR_FINANCES_SECTION_AIRCRAFT_INCOME :{GOLD}Lidaparātu ienākumi STR_FINANCES_SECTION_SHIP_INCOME :{GOLD}Kuģu ienākumi STR_FINANCES_SECTION_LOAN_INTEREST :{GOLD}Aizdevuma procents STR_FINANCES_SECTION_OTHER :{GOLD}Citi STR_FINANCES_NEGATIVE_INCOME :{BLACK}-{CURRENCY_LONG} STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} STR_FINANCES_TOTAL_CAPTION :{WHITE}Kopā: STR_FINANCES_BANK_BALANCE_TITLE :{WHITE}Bankas bilance STR_FINANCES_LOAN_TITLE :{WHITE}Aizdevums STR_FINANCES_MAX_LOAN :{WHITE}Maksimālais aizdevums: {BLACK}{CURRENCY_LONG} STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} STR_FINANCES_BORROW_BUTTON :{BLACK}Aizņemties {CURRENCY_LONG} STR_FINANCES_BORROW_TOOLTIP :{BLACK}Palielināt aizdevuma apmēru. Ctrl+klikšķis lai aizņemtos cik daudz vien iespējams STR_FINANCES_REPAY_BUTTON :{BLACK}Atmaksāt {CURRENCY_LONG} STR_FINANCES_REPAY_TOOLTIP :{BLACK}Atmaksāt daļu aizdevuma. Ctrl+klikšķis atmaksā cik daudz vien iespējams STR_FINANCES_INFRASTRUCTURE_BUTTON :{BLACK}Infrastruktūra # Company view STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(vadītājs) STR_COMPANY_VIEW_INAUGURATED_TITLE :{GOLD}Dibināts: {WHITE}{NUM} STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE :{GOLD}Identitātes krāsu shēma STR_COMPANY_VIEW_VEHICLES_TITLE :{GOLD}Transportlīdzekļi: STR_COMPANY_VIEW_TRAINS :{WHITE}{COMMA} vilcien{P s i u} STR_COMPANY_VIEW_ROAD_VEHICLES :{WHITE}{COMMA} mašīn{P a as u} STR_COMPANY_VIEW_AIRCRAFT :{WHITE}{COMMA} lidaparāt{P s i u} STR_COMPANY_VIEW_SHIPS :{WHITE}{COMMA} kuģ{P is i u} STR_COMPANY_VIEW_VEHICLES_NONE :{WHITE}Neviens STR_COMPANY_VIEW_COMPANY_VALUE :{GOLD}Uzņēmuma vērtība: {WHITE}{CURRENCY_LONG} STR_COMPANY_VIEW_SHARES_OWNED_BY :{WHITE}({COMMA}% piederoši {COMPANY}) STR_COMPANY_VIEW_INFRASTRUCTURE :{GOLD}Infrastruktūra: STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL :{WHITE}{COMMA} sliežu gabal{P s i u} STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD :{WHITE}{COMMA} ceļa gabal{P s i u} STR_COMPANY_VIEW_INFRASTRUCTURE_WATER :{WHITE}{COMMA} ūdens lauciņ{P š i u} STR_COMPANY_VIEW_INFRASTRUCTURE_STATION :{WHITE}{COMMA} stacijas lauciņ{P š i u} STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT :{WHITE}{COMMA} lidosta{P "" s u} STR_COMPANY_VIEW_INFRASTRUCTURE_NONE :{WHITE}Nav STR_COMPANY_VIEW_BUILD_HQ_BUTTON :{BLACK}Būvēt biroju STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP :{BLACK}Būvēt uzņēmuma vadības ēku STR_COMPANY_VIEW_VIEW_HQ_BUTTON :{BLACK}Skatīt biroju STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP :{BLACK}Rādīt uzņēmuma vadības ēku STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Pārvietot biroju STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Pārcelt uzņēmuma centrālo biroju uz citu vietu samaksājot 1% no uzņēmuma vērtības. Shift+klikšķis parāda izmaksu novērtējumu, nemainot biroja atrašanās vietu STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Sīkāk STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}Skatīt detalizētāku infrastruktūras uzskaiti STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}Jauna seja STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}Izvēlēties jaunu seju vadītājam STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON :{BLACK}Identitātes krāsu shēma STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP :{BLACK}Mainīt uzņēmuma transportlīdzekļu identitātes krāsas STR_COMPANY_VIEW_COMPANY_NAME_BUTTON :{BLACK}Uzņēmuma nosaukums STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP :{BLACK}Mainīt uzņēmuma nosaukumu STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON :{BLACK}Vadītāja vārds STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP :{BLACK}Mainīt vadītāja vārdu STR_COMPANY_VIEW_BUY_SHARE_BUTTON :{BLACK}Nopirkt 25% daļu uzņēmumā STR_COMPANY_VIEW_SELL_SHARE_BUTTON :{BLACK}Pārdot 25% daļu uzņēmumā STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP :{BLACK}Nopirkt 25% daļu šajā uzņēmumā. Shift+klikšķis rāda izmaksu novērtējumu, nepērkot akcijas STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}Pārdot 25% daļu uzņēmumā. Shift+Ctrl rāda izmaksu novērtējumu, nepārdodot nevienu akciju STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :Uzņēmuma nosaukums STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :Vadītāja vārds STR_BUY_COMPANY_MESSAGE :{WHITE}Mēs meklējam transporta uzņēmumu, kurš vēlētos pārņemt mūsējo.{}{}Vai Jūs vēlaties pirkt {COMPANY} par {CURRENCY_LONG}? # Company infrastructure window STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY} infrastruktūra STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}Sliežu gabali: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}Signālierīces STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}Ceļa gabali: STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD :{WHITE}Ceļš STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY :{WHITE}Tramvajs STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}Ūdens lauciņi: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}Kanāli STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}Stacijas: STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS :{WHITE}Staciju lauciņi STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS :{WHITE}Lidostas STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENCY_LONG} gadā # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Ražotnes STR_INDUSTRY_DIRECTORY_NONE :{G=m}{ORANGE}- Neviens - STR_INDUSTRY_DIRECTORY_NONE.kas :{G=f}{ORANGE}- Neviena - STR_INDUSTRY_DIRECTORY_ITEM :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}){YELLOW} ({COMMA}% pārvadāts) STR_INDUSTRY_DIRECTORY_ITEM_TWO :{ORANGE}{INDUSTRY}{BLACK} ({CARGO_LONG}{STRING}/{CARGO_LONG}{STRING}){YELLOW} ({COMMA}%/{COMMA}% pārvadāts) STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Ražotņu nosaukumi - klikšķināt uz nosaukuma, lai centrētu skatu uz ražotni. Ctrl+klikšķis atvērs jaunu skatvietu pie ražotnes # Industry view STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Iepriekšējā mēnesī saražots: STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} (aizvests {COMMA}%) STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz ražotni. Ctrl+klikšķis atvērs skatu uz ražotni jaunā skatlaukā STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Ražošanas līmenis: {YELLOW}{COMMA}% ############ range for requires starts STR_INDUSTRY_VIEW_REQUIRES_CARGO :{BLACK}Nepieciešams: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO :{BLACK}Nepieciešams: {YELLOW}{STRING}{STRING}, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES_CARGO_CARGO_CARGO :{BLACK}Nepieciešams: {YELLOW}{STRING}{STRING}, {STRING}{STRING}, {STRING}{STRING} ############ range for requires ends ############ range for produces starts STR_INDUSTRY_VIEW_WAITING_FOR_PROCESSING :{BLACK}Krava, kuru ir jāapstrādā: STR_INDUSTRY_VIEW_WAITING_STOCKPILE_CARGO :{YELLOW}{CARGO_LONG}{STRING}{BLACK} STR_INDUSTRY_VIEW_PRODUCES_CARGO :{BLACK}Ražo: {YELLOW}{STRING}{STRING} STR_INDUSTRY_VIEW_PRODUCES_CARGO_CARGO :{BLACK}Ražo: {YELLOW}{STRING}{STRING}, {STRING}{STRING} ############ range for produces ends STR_CONFIG_GAME_PRODUCTION :{WHITE}Mainīt ražošanu (dalāmais ar 8, līdz pat 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Mainīt ražošanas līmeni (procentos, līdz 800%) # Vehicle lists STR_VEHICLE_LIST_TRAIN_CAPTION :{WHITE}{STRING} - {COMMA} vilcien{P s i u} STR_VEHICLE_LIST_ROAD_VEHICLE_CAPTION :{WHITE}{STRING} - {COMMA} autotransporta līdzek{P lis ļi ļu} STR_VEHICLE_LIST_SHIP_CAPTION :{WHITE}{STRING} - {COMMA} kuģ{P is i u} STR_VEHICLE_LIST_AIRCRAFT_CAPTION :{WHITE}{STRING} - {COMMA} lidaparāt{P s i u} STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP :{BLACK}Vilcieni - klikšķināt uz vilciena, lai uzzinātu vairāk STR_VEHICLE_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Autotransporta līdzekļi - klikšķināt uz transportlīdzekļa, lai uzzinātu vairāk STR_VEHICLE_LIST_SHIP_TOOLTIP :{BLACK}Kuģi - klikšķināt uz kuģa, lai uzzinātu vairāk STR_VEHICLE_LIST_AIRCRAFT_TOOLTIP :{BLACK}Lidaparāts - klikšķināt uz lidaparāta, lai uzzinātu vairāk STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR :{TINY_FONT}{BLACK}Peļņa šogad: {CURRENCY_LONG} (pērn: {CURRENCY_LONG}) STR_VEHICLE_LIST_AVAILABLE_TRAINS :Pieejamie vilcieni STR_VEHICLE_LIST_AVAILABLE_ROAD_VEHICLES :Pieejamie transportlīdzekļi STR_VEHICLE_LIST_AVAILABLE_SHIPS :Pieejamie kuģi STR_VEHICLE_LIST_AVAILABLE_AIRCRAFT :Pieejamie lidaparāti STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}Apskatīties visus dzinējus projektējumus, kas pieejami šim transportlīdzekļu veidam. STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}Labot sarakstu STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}Sūtīt norādījumus visiem transportlīdzekļiem, kas ir šajā sarakstā STR_VEHICLE_LIST_REPLACE_VEHICLES :Nomainīt transportlīdzekļus STR_VEHICLE_LIST_SEND_FOR_SERVICING :Sūtīt uz apkopi STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :Sūtīt uz depo STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :Sūtīt uz depo STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT :Sūtīt uz depo STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR :Sūtīt uz angāru STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP :{BLACK}Klikšķināt, lai apstādinātu visas mašīnas, kas ir sarakstā STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP :{BLACK}Klikšķināt, lai iedarbinātu visas mašīnas, kas ir saraks STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION :{WHITE}Koplietojamie rīkojumi {COMMA} transportlīdzek{P lim ļiem ļiem} # Group window STR_GROUP_ALL_TRAINS :Visi vilcieni STR_GROUP_ALL_ROAD_VEHICLES :Visi autotransporta līdzekļi STR_GROUP_ALL_SHIPS :Visi kuģi STR_GROUP_ALL_AIRCRAFTS :Visi lidaparāti STR_GROUP_DEFAULT_TRAINS :Negrupēti vilcieni STR_GROUP_DEFAULT_ROAD_VEHICLES :Negrupēti autotransporta līdzekļi STR_GROUP_DEFAULT_SHIPS :Negrupēti kuģi STR_GROUP_DEFAULT_AIRCRAFTS :Negrupēti lidaparāti STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP :{BLACK}Grupas - klikšķināt uz grupas, lai iegūtu tās transportlīdzekļu sarakstu STR_GROUP_CREATE_TOOLTIP :{BLACK}Klikšķināt, lai izveidotu grupu STR_GROUP_DELETE_TOOLTIP :{BLACK}Dzēst izvēlēto grupu STR_GROUP_RENAME_TOOLTIP :{BLACK}Pārdēvēt izvēlēto grupu STR_GROUP_REPLACE_PROTECTION_TOOLTIP :{BLACK}Klikšķināt, lai pasargātu šo grupu no vispārējās automātiskās aizstāšanas STR_QUERY_GROUP_DELETE_CAPTION :{WHITE}Grupas dzēšana STR_GROUP_ADD_SHARED_VEHICLE :Pievienot kopīgos transportlīdzekļus STR_GROUP_REMOVE_ALL_VEHICLES :Novākt visus transportlīdzekļus STR_GROUP_RENAME_CAPTION :{BLACK}Pārdēvēt grupu # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :Jauni dzelzceļa transportlīdzekļi STR_BUY_VEHICLE_TRAIN_ELRAIL_CAPTION :Jauni elektrificētā dzelzceļa transportlīdzekļi STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :Jauni viensliedes vilcieni STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :Jauni magleva vilcieni STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :Jauni vilcieni STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :Jauni autotransporta līdzekļi STR_BUY_VEHICLE_SHIP_CAPTION :Jauni kuģi STR_BUY_VEHICLE_AIRCRAFT_CAPTION :Jauns lidaparāts STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Svars: {GOLD}{WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}Ātrums: {GOLD}{VELOCITY}{BLACK} Jauda: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}Ātrums: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}Ātrums okeānā: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_CANAL :{BLACK}Ātrums kanālā/upē: {GOLD}{VELOCITY} STR_PURCHASE_INFO_RUNNINGCOST :{BLACK}Kārtējās izmaksas: {GOLD}{CURRENCY_LONG} gadā STR_PURCHASE_INFO_CAPACITY :{BLACK}Ietilpība: {GOLD}{CARGO_LONG} {STRING} STR_PURCHASE_INFO_REFITTABLE :(pielāgojams) STR_PURCHASE_INFO_DESIGNED_LIFE :{BLACK}Projektēts: {GOLD}{NUM}{BLACK} Kalpošanas laiks: {GOLD}{COMMA} gad{P s i u} STR_PURCHASE_INFO_RELIABILITY :{BLACK}Maksimālā uzticamība: {GOLD}{COMMA}% STR_PURCHASE_INFO_COST :{BLACK}Cena: {GOLD}{CURRENCY_LONG} STR_PURCHASE_INFO_WEIGHT_CWEIGHT :{BLACK}Svars: {GOLD}{WEIGHT_SHORT} ({WEIGHT_SHORT}) STR_PURCHASE_INFO_COST_SPEED :{BLACK}Cena: {GOLD}{CURRENCY_LONG}{BLACK} Ātrums: {GOLD}{VELOCITY} STR_PURCHASE_INFO_AIRCRAFT_CAPACITY :{BLACK}Ietilpība: {GOLD}{CARGO_LONG}, {CARGO_LONG} STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Motorvagoni: {GOLD}+{POWER}zs{BLACK} Svars: {GOLD}+{WEIGHT_SHORT} STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Pielāgojams uz: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :Visi kravu veidi STR_PURCHASE_INFO_ALL_BUT :visu, izņemot {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Maksimālais vilces spēks: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Apgabas: {GOLD}{COMMA} lauciņi STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}Vilciena vagonu atlasīšanas saraksts - klikšķināt uz transportlīdzekļa, lai iegūtu informāciju STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Autotransporta atlasīšanas saraksts - klikšķināt uz transportlīdzekļa, lai iegūtu informāciju STR_BUY_VEHICLE_SHIP_LIST_TOOLTIP :{BLACK}Kuģu atlasīšanas saraksts - klikšķināt uz transportlīdzekļa, lai iegūtu informāciju STR_BUY_VEHICLE_AIRCRAFT_LIST_TOOLTIP :{BLACK}Lidaparātu atlasīšanas saraksts - klikšķināt uz transportlīdzekļa, lai iegūtu informāciju STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON :{BLACK}Pirkt transportlīdzekli STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}Pirkt autotransporta līdzekli STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}Pirkt kuģi STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}Pirkt lidaparātu STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}Pirkt atzīmēto vilciena vagonu. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}Pirkt atzīmēto transportlīdzekli. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}Pirkt atzīmēto kuģi. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}Pirkt izvēlēto lidaparātu. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}Pārdēvēt STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}Pārdēvēt STR_BUY_VEHICLE_SHIP_RENAME_BUTTON :{BLACK}Pārdēvēt STR_BUY_VEHICLE_AIRCRAFT_RENAME_BUTTON :{BLACK}Pārdēvēt STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP :{BLACK}Pārdēvēt vilciena vagona tipu STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}Pārdēvēt autotransporta līdzekļa tipu STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}Pārdēvēt kuģa tipu STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}Pārdēvēt lidaparāta tipu STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON :{BLACK}Paslēpt STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_TOGGLE_BUTTON :{BLACK}Paslēpt STR_BUY_VEHICLE_SHIP_HIDE_TOGGLE_BUTTON :{BLACK}Paslēpt STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :{BLACK}Paslēpt STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON :{BLACK}Rādīt STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}Rādīt STR_BUY_VEHICLE_SHIP_SHOW_TOGGLE_BUTTON :{BLACK}Rādīt STR_BUY_VEHICLE_AIRCRAFT_SHOW_TOGGLE_BUTTON :{BLACK}Rādīt STR_BUY_VEHICLE_TRAIN_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Pārslēgt starp rādīt/nerādīt vilciena tipu STR_BUY_VEHICLE_ROAD_VEHICLE_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Pārslēgt starp rādīt/nerādīt autotransporta līdzekļu tipu STR_BUY_VEHICLE_SHIP_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Pārslēgt starp rādīt/nerādīt kuģa tipu STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}Pārslēgt starp rādīt/nerādīt lidaparāta tipu STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}Pārdēvēt vilciena vagona tipu STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}Pārdēvēt autotransporta līdzekļa tipu STR_QUERY_RENAME_SHIP_TYPE_CAPTION :{WHITE}Pārdēvēt kuģa tipu STR_QUERY_RENAME_AIRCRAFT_TYPE_CAPTION :{WHITE}Pārdēvēt lidaparāta tipu # Depot window STR_DEPOT_CAPTION :{WHITE}{DEPOT} STR_DEPOT_RENAME_TOOLTIP :{BLACK}Nomainīt depo nosaukumu STR_DEPOT_RENAME_DEPOT_CAPTION :Pārdēvēt depo STR_DEPOT_NO_ENGINE :{BLACK}- STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CHAIN :{BLACK}{NUM} transportlīdzek{P lis ļi ļu}{STRING} STR_DEPOT_VEHICLE_TOOLTIP_CARGO :{}{CARGO_LONG} ({CARGO_SHORT}) STR_DEPOT_TRAIN_LIST_TOOLTIP :{BLACK}Vilcieni - villkt sastāva daļu, lai pievienotu/atvienotu no vilciena. Klikšķināt uz vilciena, lai iegūtu informāciju. Turēt piespiestu Ctrl, lai attiecinātu abas funkcijas sekojošajai ķēdei STR_DEPOT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Transportlīdzekļi - labais klikšķis uz transportlīdzekļa, lai uzzinātu vairāk STR_DEPOT_SHIP_LIST_TOOLTIP :{BLACK}Kuģi - labais klikšķis uz kuģa, lai uzzinātu vairāk STR_DEPOT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Lidaparāti - labais klikšķis uz lidaparāta, lai uzzinātu vairāk STR_DEPOT_TRAIN_SELL_TOOLTIP :{BLACK}Pārvilkt vilciena vagonu uz šejieni, lai to pārdotu STR_DEPOT_ROAD_VEHICLE_SELL_TOOLTIP :{BLACK}Pārvilkt autotransporta līdzekli uz šejieni, lai to pārdotu STR_DEPOT_SHIP_SELL_TOOLTIP :{BLACK}Pārvilkt kuģi uz šejieni, lai to pārdotu STR_DEPOT_AIRCRAFT_SELL_TOOLTIP :{BLACK}Pārvilkt lidaparātu uz šejieni, lai to pārdotu STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP :{BLACK}Pārvilkt vilciena lokomotīvi uz šejieni, lai pārdotu visu vilcienu STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP :{BLACK}Pārdot visus vilcienus, kas atrodas depo STR_DEPOT_SELL_ALL_BUTTON_ROAD_VEHICLE_TOOLTIP :{BLACK}Pārdot visu autotransportu, kas atrodas depo STR_DEPOT_SELL_ALL_BUTTON_SHIP_TOOLTIP :{BLACK}Pārdot visus kuģus, kas atrodas depo STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TOOLTIP :{BLACK}Pārdot visus lidaparātus, kas atrodas angārā STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP :{BLACK}Automātiski nomainīt visus vilcienu depo STR_DEPOT_AUTOREPLACE_ROAD_VEHICLE_TOOLTIP :{BLACK}Automātiski nomainīt visus transportus depo STR_DEPOT_AUTOREPLACE_SHIP_TOOLTIP :{BLACK}Automātiski nomainīt visus kuģus depo STR_DEPOT_AUTOREPLACE_AIRCRAFT_TOOLTIP :{BLACK}Automātiski nomainīt visus lidaparātus angārā STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON :{BLACK}Jauni transportlīdzekļi STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_BUTTON :{BLACK}Jauni transportlīdzekļi STR_DEPOT_SHIP_NEW_VEHICLES_BUTTON :{BLACK}Jauni kuģi STR_DEPOT_AIRCRAFT_NEW_VEHICLES_BUTTON :{BLACK}Jauns lidaparāts STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP :{BLACK}Pirkt jaunu vilciena vagonu STR_DEPOT_ROAD_VEHICLE_NEW_VEHICLES_TOOLTIP :{BLACK}Pirkt jaunu autortansporta līdzekli STR_DEPOT_SHIP_NEW_VEHICLES_TOOLTIP :{BLACK}Pirkt jaunu kuģi STR_DEPOT_AIRCRAFT_NEW_VEHICLES_TOOLTIP :{BLACK}Pirkt jaunu lidaparātu STR_DEPOT_CLONE_TRAIN :{BLACK}Klonēt vilcienu STR_DEPOT_CLONE_ROAD_VEHICLE :{BLACK}Klonēt transportīdzekli STR_DEPOT_CLONE_SHIP :{BLACK}Klonēt kuģi STR_DEPOT_CLONE_AIRCRAFT :{BLACK}Klonēt lidaparātu STR_DEPOT_CLONE_TRAIN_DEPOT_INFO :{BLACK}Nopirkt vilciena kopiju ar visiem vagoniem. Spiediet šo pogu, un pēc tam uz vilciena, kas atrodas depo vai ārpus tā. Ctrl+Klikšķis, lai koplietotu rīkojumus. Shift+Klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_DEPOT_CLONE_ROAD_VEHICLE_DEPOT_INFO :{BLACK}Tas nopirks autotransporta kopiju. Spiediet uz pogas un pēc tam uz autotransporta, kas atrodas depo vai ārpus tā. Ctrl+klikšķis, lai koplietotu rīkojumus. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_DEPOT_CLONE_SHIP_DEPOT_INFO :{BLACK}Tas nopirks kuģa kopiju. Spiediet šo pogu un pēc tam uz kuģa, kas atrodas depo vai ārpus tā. Ctrl+klikšķis, lai koplietotu rīkojumus. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_DEPOT_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW :{BLACK}Tas pirks lidaparāta kopiju. Spiediet uz pogas un pēc tam uz lidaparāta, kas atrodas angārā vai ārpus tā. Ctrl+klikšķis, lai koplietotu rīkojumus. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_DEPOT_TRAIN_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz vilcienu depo. Ctrl+klikšķis atvērs skatu uz depo jaunā skatlaukā STR_DEPOT_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz autotransporta depo. Ctrl+klikšķis atvērs skatu uz depo jaunā skatlaukā STR_DEPOT_SHIP_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz kuģu depo. Ctrl+klikšķis atvērs skatu uz depo jaunā skatlaukā STR_DEPOT_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz angāru. Ctrl+klikšķis atvērs skatu uz angāru jaunā skatlaukā STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP :{BLACK}Iegūt visu vilcienu sarakstu, kuru rīkojumos ir pašreizējais depo STR_DEPOT_VEHICLE_ORDER_LIST_ROAD_VEHICLE_TOOLTIP :{BLACK}Iegūt visu autotransporta līdzekļu sarakstu, kuru rīkojumos ir pašreizējais depo STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TOOLTIP :{BLACK}Iegūt visu kuģu sarakstu, kuru rīkojumos ir pašreizējais depo STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TOOLTIP :{BLACK}Iegūt visu lidaparātu sarakstu, kuru rīkojumos ir šīs lidostas angāri STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP :{BLACK}Klikšķināt lai apturētu visus vilcienus, kas atrodas depo STR_DEPOT_MASS_STOP_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klikšķināt lai apturētu visus autotransporta līdzekļus, kas atrodas depo STR_DEPOT_MASS_STOP_DEPOT_SHIP_TOOLTIP :{BLACK}Klikšķināt lai apturētu visus kuģus, kas atrodas depo STR_DEPOT_MASS_STOP_HANGAR_TOOLTIP :{BLACK}Klikšķināt lai apturētu visus lidaparātus, kas atrodas angārā STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP :{BLACK}Klikšķināt lai palaistu visus vilcienus, kas atrodas depo STR_DEPOT_MASS_START_DEPOT_ROAD_VEHICLE_TOOLTIP :{BLACK}Klikšķināt lai palaistu visus autotransporta līdzekļus, kas atrodas depo STR_DEPOT_MASS_START_DEPOT_SHIP_TOOLTIP :{BLACK}Klikšķināt lai palaistu visus kuģus, kas atrodas depo STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}Klikšķināt lai palaistu visus lidaparātus, kas atrodas angārā STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}Jūs grasāties pārdot visus transportlīdzekļus, kas atrodas depo. Vai esat pārliecināts? # Engine preview window STR_ENGINE_PREVIEW_CAPTION :{WHITE}Ziņojums no transportlīdzekļu ražotāja STR_ENGINE_PREVIEW_MESSAGE :{GOLD}Mēs tikko esam izstrādājuši jaunu transportlīdzekli - {STRING}. Vai esat ieinteresēts iegūt izņēmuma tiesības izmantot šo transportlīdzekli uz vienu gadu, lai mēs redzētu tā iespējas pirms padaram pieejamu visiem? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :dzelzceļa lokomotīve STR_ENGINE_PREVIEW_ROAD_VEHICLE :autotransporta līdzeklis STR_ENGINE_PREVIEW_AIRCRAFT :lidaparāts STR_ENGINE_PREVIEW_SHIP :kuģis STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :viensliedes lokomotīve STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :magleva lokomotīve STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Cena: {CURRENCY_LONG} Svars: {WEIGHT_SHORT}{}Ātrums: {VELOCITY} Jauda: {POWER}{}Kārtējās izmaksas: {CURRENCY_LONG} gadā{}Ietilpība: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Cena: {CURRENCY_LONG} Svars: {WEIGHT_SHORT}{}Ātrums: {VELOCITY} Jauda: {POWER} Maks. spēks: {6:FORCE}{}Kārtējās izmaksas: {4:CURRENCY_LONG} gadā{}Ietilpība: {5:CARGO_LONG} STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY}{}Ietilpība: {CARGO_LONG}, {CARGO_LONG}{}Kārtējās izmaksas: {CURRENCY_LONG} gadā STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY}{}Ietilpība: {CARGO_LONG}{}Kārtējās izmaksas: {CURRENCY_LONG} gadā STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST:{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY} Apgabals: {COMMA} lauciņi{}Ietilpība: {CARGO_LONG}, {CARGO_LONG}{}Kārtējās izmaksas: {CURRENCY_LONG} gadā STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST :{BLACK}Cena: {CURRENCY_LONG} Maks. ātrums: {VELOCITY} Apgabals: {COMMA} lauciņi{}Ietilpība: {CARGO_LONG}{} Kārtējās izmaksas : {CURRENCY_LONG} gadā # Autoreplace window STR_REPLACE_VEHICLES_WHITE :{WHITE}Nomainīt {STRING} - {STRING} STR_REPLACE_VEHICLE_TRAIN :Vilciens STR_REPLACE_VEHICLE_ROAD_VEHICLE :Autotransporta līdzeklis STR_REPLACE_VEHICLE_SHIP :Kuģis STR_REPLACE_VEHICLE_AIRCRAFT :Lidaparāts STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}Lietošanā esošie transportlīdzekļi STR_REPLACE_VEHICLE_AVAILABLE_VEHICLES :{YELLOW}Pieejamie transportlīdzekļi STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Izvēlēties lokomotīves veidu, kuru vēlaties mainīt STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Izvēlēties jaunu lokomotīves veidu, kuru vēlaties lietot kreisajā pusē atlasītās lokomotīves vietā STR_REPLACE_VEHICLES_START :{BLACK}Sākt transportlīdzekļu nomaiņu STR_REPLACE_VEHICLES_NOW :Nomainīt visus transportlīdzekļus STR_REPLACE_VEHICLES_WHEN_OLD :Nomainīt tikai vecos transportlīdzekļus STR_REPLACE_HELP_START_BUTTON :{BLACK}Nospiest, lai sāktu kreisajā pusē atlasītās lokomotīves aizstāšanu ar labajā pusē atlasīto lokomotīvi STR_REPLACE_NOT_REPLACING :{BLACK}Netiks nomainīts STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}Nav atlasītu transportlīdzekļu STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} kad vecs STR_REPLACE_VEHICLES_STOP :{BLACK}Pārtraukt transportlīdzekļu nomaiņu STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Nospiest, lai apturētu kreisajā pusē atlasītās lokomotīves aizstāšanu STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Nomainīt: {ORANGE}{STRING} STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Parslēgties starp lokomotīves un vagona aizstāšanas logiem STR_REPLACE_ENGINES :Lokomotīves STR_REPLACE_WAGONS :Vagoni STR_REPLACE_HELP_RAILTYPE :{BLACK}Izvēlēties sliežu veidu, kuram vēlaties nomainīt lokomotīves STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Parāda kura lokomotīve no kreisajā pusē atlasītajām tiek nomainīta, ja vien kāda ir STR_REPLACE_RAIL_VEHICLES :Sliežu transportlīdzekļi STR_REPLACE_ELRAIL_VEHICLES :Elektrificētā dzelzceļa transportlīdzekļi STR_REPLACE_MONORAIL_VEHICLES :Viensliedes transportlīdzekļi STR_REPLACE_MAGLEV_VEHICLES :Magleva transportlīdzekļi STR_REPLACE_REMOVE_WAGON :{BLACK}Vagona noņemšana: {ORANGE}{STRING} STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}Automātiskā aizvietošana saglabās esošo vilciena garumu noņemot vagonus (sākot no priekšgala), ja mainot lokomotīvi tas kļūtu garāks # Vehicle view STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz vilcienu. Ctrl+klikšķis sekos vilcienam galvenajā skatā STR_VEHICLE_VIEW_ROAD_VEHICLE_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz transportlīdzekli. Ctrl+klikšķis sekos transportlīdzeklim galvenajā skatā STR_VEHICLE_VIEW_SHIP_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz kuģi. Ctrl+klikšķis sekos kuģim galvenajā skatā STR_VEHICLE_VIEW_AIRCRAFT_LOCATION_TOOLTIP :{BLACK}Centrēt galveno skatu uz lidaparātu. Ctrl+klikšķis sekos lidaparātam galvenajā skatā STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Sūtīt vilcienu uz depo. Ctrl+klikšķis - izvēlēties tikai apkopi STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Sūtīt autotransporta līdzekli uz depo. Ctrl+klikšķis - izvēlēties tikai apkopi STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Sūtīt kuģi uz depo. Ctrl+klikšķis - izvēlēties tikai apkopi STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Sūtīt lidaparātu uz angāru. Ctrl+klikšķis - izvēlēties tikai apkopi STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Tas nopirks vilciena kopiju ar visiem vagoniem. Izmantojot Ctrl+klikšķis, vilcieni rīkojumus lietos kopīgi. Shift+klikšķis rāda izmaksu vērtību, neveicot pirkumu STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Tas nopirks autotransporta līdzekļa kopiju. Izmantojot Ctrl+klikšķis, autotransporta līdzekļi rīkojumus lietos kopīgi. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Tas nopirks kuģa kopiju. Izmantojot Ctrl+klikšķis, kuģi rīkojumus lietos kopīgi. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Tas nopirks lidaparāta kopiju. Izmantojot Ctrl+klikšķis, lidaparāti rīkojumus lietos kopīgi. Shift+klikšķis rāda izmaksu novērtējumu, neveicot pirkumu STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Piespiest vilcienu doties tālāk, neievērojot signālu STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP :{BLACK}Pielāgot vilcienu citam kravas veidam STR_VEHICLE_VIEW_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Pielāgot autotransporta līdzekli citam kravas veidam STR_VEHICLE_VIEW_SHIP_REFIT_TOOLTIP :{BLACK}Pielāgot kuģi citam kravas veidam STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Pielāgot lidaparātu citam kravas veidam STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Apgriezt vilcienu pretējā virzienā STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Piespiest transportlīdzekli apgriezties STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Rādīt vilcienu rīkojumus. Ctrl+klikšķis, lai rādītu vilcienu kustības sarakstu STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Rādīt transportīdzekļu rīkojumus. Ctrl+klikšķis, lai rādītu transportlīdzekļu kustības sarakstu STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Rādīt kuģu rīkojumus. Ctrl+klikšķis, lai rādītu kuģu kustības sarakstu STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Rādīt lidaparātu rīkojumus. Ctrl+klikšķis, lai rādītu lidaparātu lidojumu sarakstu STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Rādīt vilciena informāciju STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Rādīt autotransporta līdzekļa informāciju STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Rādīt kuģa informāciju STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Rādīt lidaparāta informāciju STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP :{BLACK}Vilciena pašreizējā darbība - klikšķināt šeit, lai apturētu/palaistu vilcienu. Ctrl+klikšķis, lai ritinātu līdz galamērķim STR_VEHICLE_VIEW_ROAD_VEHICLE_STATE_START_STOP_TOOLTIP :{BLACK}Transportlīdzekļa pašreizējā darbība - klikšķināt šeit, lai to apturētu/palaistu. Ctrl+klikšķis, lai ritinātu līdz galamērķim STR_VEHICLE_VIEW_SHIP_STATE_START_STOP_TOOLTIP :{BLACK}Kuģa pašreizējā darbība - klikšķināt šeit, lai apturētu/palaistu kuģi. Ctrl+klikšķis, lai ritinātu līdz galamērķim STR_VEHICLE_VIEW_AIRCRAFT_STATE_START_STOP_TOOLTIP :{BLACK}Lidaparāta pašreizējā darbība - klikšķināt šeit, lai apturētu/palaistu lidaparātu. Ctrl+klikšķis, lai ritinātu līdz galamērķim # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}Iekraušana / Izkraušana STR_VEHICLE_STATUS_LEAVING :{LTBLUE}Aizbrauc STR_VEHICLE_STATUS_CRASHED :{RED}Cietis avārijā! STR_VEHICLE_STATUS_BROKEN_DOWN :{RED}Salūzis STR_VEHICLE_STATUS_STOPPED :{RED}Apstādināts STR_VEHICLE_STATUS_TRAIN_STOPPING_VEL :{RED}Apstājas, {VELOCITY} STR_VEHICLE_STATUS_TRAIN_NO_POWER :{RED} Nav jaudas STR_VEHICLE_STATUS_TRAIN_STUCK :{ORANGE}Gaida brīvu ceļu STR_VEHICLE_STATUS_AIRCRAFT_TOO_FAR :{ORANGE}Pārāk tālu līdz nākamajam galamērķim STR_VEHICLE_STATUS_HEADING_FOR_STATION_VEL :{LTBLUE}Dodas uz {STATION}, {VELOCITY} STR_VEHICLE_STATUS_NO_ORDERS_VEL :{LTBLUE}Nav rīkojumu, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Dodas uz {WAYPOINT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_VEL :{ORANGE}Dodas uz {DEPOT}, {VELOCITY} STR_VEHICLE_STATUS_HEADING_FOR_DEPOT_SERVICE_VEL :{LTBLUE}Veikt apkopi {DEPOT}, {VELOCITY} # Vehicle stopped/started animations STR_VEHICLE_COMMAND_STOPPED_SMALL :{TINY_FONT}{RED}Apturēts STR_VEHICLE_COMMAND_STOPPED :{RED}Apturēts STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GREEN}Iedarbināts STR_VEHICLE_COMMAND_STARTED :{GREEN}Iedarbināts # Vehicle details STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Sīkāka informācija) STR_VEHICLE_NAME_BUTTON :{BLACK}Nosaukums STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Nosaukt vilcienu STR_VEHICLE_DETAILS_ROAD_VEHICLE_RENAME :{BLACK}Nosaukt autotransporta līdzekli STR_VEHICLE_DETAILS_SHIP_RENAME :{BLACK}Nosaukt kuģi STR_VEHICLE_DETAILS_AIRCRAFT_RENAME :{BLACK}Nosaukt lidaparātu STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Vecums: {LTBLUE}{STRING}{BLACK} Izmaksas: {LTBLUE}{CURRENCY_LONG} gadā # The next two need to stay in this order STR_VEHICLE_INFO_AGE :{COMMA} gad{P s i u} ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} gad{P s i u} ({COMMA}) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Maks. ātrums: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_RANGE :{BLACK}Maks. ātrums: {LTBLUE}{VELOCITY} {BLACK}Apgabals: {LTBLUE}{COMMA} flīzes STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Svars: {LTBLUE}{WEIGHT_SHORT} {BLACK}Jauda: {LTBLUE}{POWER}{BLACK} Maks. ātrums: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Svars: {LTBLUE}{WEIGHT_SHORT} {BLACK}Jauda: {LTBLUE}{POWER}{BLACK} Maks. ātrums: {LTBLUE}{VELOCITY} {BLACK}Maks. spēks: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Peļņa šogad: {LTBLUE}{CURRENCY_LONG} (pagājušajā gadā: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Drošums: {LTBLUE}{COMMA}% {BLACK}Ķibeles kopš pēdējās apkopes: {LTBLUE}{COMMA} STR_VEHICLE_INFO_BUILT_VALUE :{LTBLUE}{ENGINE} {BLACK}Uzbūvēts: {LTBLUE}{NUM}{BLACK} Vērtība: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_INFO_NO_CAPACITY :{BLACK}Ietilpība: {LTBLUE}Nav{STRING} STR_VEHICLE_INFO_CAPACITY :{BLACK}Ietilpība: {LTBLUE}{CARGO_LONG}{3:STRING} STR_VEHICLE_INFO_CAPACITY_MULT :{BLACK}Ietilpība: {LTBLUE}{CARGO_LONG}{3:STRING} (x{4:NUM}) STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}Ietilpība: {LTBLUE}{CARGO_LONG}, {CARGO_LONG}{STRING} STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Pārvadājumu ieņēmumi: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Apkopes starplaiks: {LTBLUE}{COMMA}{NBSP}dienas{BLACK} Pēdējā apkope: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Apkopes starplaiks: {LTBLUE}{COMMA}%{BLACK} Pēdējā apkope: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Palielināt apkopes starplaiku par 10. Ctrl+klikšķis palielina apkopes starplaiku par 5 STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Samazināt apkopes starplaiku par 10. Ctrl+klikšķis samazina apkopes starplaiku par 5 STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Mainīt apkopes starplaiku veidu STR_VEHICLE_DETAILS_DEFAULT :Noklusējuma STR_VEHICLE_DETAILS_DAYS :Dienas STR_VEHICLE_DETAILS_PERCENT :Procenti STR_QUERY_RENAME_TRAIN_CAPTION :{WHITE}Nosaukt vilcienu STR_QUERY_RENAME_ROAD_VEHICLE_CAPTION :{WHITE}Nosaukt autotransporta līdzekli STR_QUERY_RENAME_SHIP_CAPTION :{WHITE}Nosaukt kuģi STR_QUERY_RENAME_AIRCRAFT_CAPTION :{WHITE}Nosaukt lidaparātu # Extra buttons for train details windows STR_VEHICLE_DETAILS_TRAIN_ENGINE_BUILT_AND_VALUE :{LTBLUE}{ENGINE}{BLACK} Uzbūvēts: {LTBLUE}{NUM}{BLACK} Vērtība: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_WAGON_VALUE :{LTBLUE}{ENGINE}{BLACK} Vērtība: {LTBLUE}{CURRENCY_LONG} STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_TEXT :{BLACK}Kopējā kravas ietilpība: STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) STR_VEHICLE_DETAILS_TRAIN_TOTAL_CAPACITY_MULT :{LTBLUE}- {CARGO_LONG} ({CARGO_SHORT}) (x{NUM}) STR_VEHICLE_DETAILS_CARGO_EMPTY :{LTBLUE}Tukšs STR_VEHICLE_DETAILS_CARGO_FROM :{LTBLUE}{CARGO_LONG} no {STATION} STR_VEHICLE_DETAILS_CARGO_FROM_MULT :{LTBLUE}{CARGO_LONG} no {STATION} (x{NUM}) STR_VEHICLE_DETAIL_TAB_CARGO :{BLACK}Krava STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP :{BLACK}Rādīt informāciju par pārvadājamo kravu STR_VEHICLE_DETAIL_TAB_INFORMATION :{BLACK}Informācija STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP :{BLACK}Rādīt informāciju par vilciena sastāvu STR_VEHICLE_DETAIL_TAB_CAPACITIES :{BLACK}Ietilpība STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP :{BLACK}Rādīt katra vagona ietilpību STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO :{BLACK}Krava kopā STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP :{BLACK}Rādīt kopējo vilciena ietilpību, sadalīt to kravu veidos STR_VEHICLE_DETAILS_TRAIN_ARTICULATED_RV_CAPACITY :{BLACK}Ietilpība: {LTBLUE} # Vehicle refit STR_REFIT_CAPTION :{WHITE}{VEHICLE} (Pielāgot) STR_REFIT_TITLE :{GOLD}Izvēlēties pārvadājamās kravas veidu: STR_REFIT_NEW_CAPACITY_COST_OF_REFIT :{BLACK}Jaunā ietilpība: {GOLD}{CARGO_LONG}{}{BLACK}Pielāgošanas izmaksas: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_REFIT :{BLACK}Jaunā ietilpība: {GOLD}{CARGO_LONG}{}{BLACK}Ienākumi no pielāgošanas: {GREEN}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_COST_OF_AIRCRAFT_REFIT :{BLACK}Jaunā ietilpība: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Pielāgošanas izmaksas: {RED}{CURRENCY_LONG} STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT :{BLACK}Jaunā ietilpība: {GOLD}{CARGO_LONG}, {GOLD}{CARGO_LONG}{}{BLACK}Ienākumi no pielāgošanas: {GREEN}{CURRENCY_LONG} STR_REFIT_SELECT_VEHICLES_TOOLTIP :{BLACK}Izvēlēties transportlīdzekļus pielāgošanai. Vilkšana ar peli ļauj izvēlēties vairākus transportlīdzekļus. Klikšķināšana tukšumā atzīmēs visus transportlīdzekļus. Ctrl+klikšķis atzīmēs izvēlēto un visus tam sekojošus transportlīdzekļus STR_REFIT_TRAIN_LIST_TOOLTIP :{BLACK}Izvēlēties, kuru kravas veidu vilciens pārvadās STR_REFIT_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}Izvēlēties, kuru kravas veidu autotransports pārvadās STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Izvēlēties, kuru kravas veidu kuģis pārvadās STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Izvēlēties, kuru kravas veidu lidaparāts pārvadās STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Pielāgot vilcienu STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Pielāgot autotransporta līdzekli STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Pielāgot kuģi STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Pielāgot lidaparātu STR_REFIT_TRAIN_REFIT_TOOLTIP :{BLACK}Pielāgot vilcienu iezīmētā kravas veida pārvadāšanai STR_REFIT_ROAD_VEHICLE_REFIT_TOOLTIP :{BLACK}Pielāgot autotransporta līdzekli iezīmētā kravas veida pārvadāšanai STR_REFIT_SHIP_REFIT_TOOLTIP :{BLACK}Pielāgot kuģi iezīmētā kravas veida pārvadāšanai STR_REFIT_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Pielāgot lidaparātu iezīmētā kravas veida pārvadāšanai # Order view STR_ORDERS_CAPTION :{WHITE}{VEHICLE} (Rīkojumi) STR_ORDERS_TIMETABLE_VIEW :{BLACK}Saraksts STR_ORDERS_TIMETABLE_VIEW_TOOLTIP :{BLACK}Pārslēgt uz saraksta skatu STR_ORDERS_LIST_TOOLTIP :{BLACK}Rīkojumu saraksts - klikšķināt uz rīkojuma, lai to atzīmētu. Ctrl+klikšķis ritina uz rīkojuma galamērķi STR_ORDER_INDEX :{COMMA}:{NBSP} STR_ORDER_TEXT :{STRING} {STRING} {STRING} STR_ORDERS_END_OF_ORDERS :- - Rīkojumu beigas - - STR_ORDERS_END_OF_SHARED_ORDERS :- - Koplietojamo rīkojumu beigas - - # Order bottom buttons STR_ORDER_NON_STOP :{BLACK}Nestāties STR_ORDER_GO_TO :Doties uz STR_ORDER_GO_NON_STOP_TO :Braukt bez pieturām uz STR_ORDER_GO_VIA :Braukt caur STR_ORDER_GO_NON_STOP_VIA :Braukt bez pieturām caur STR_ORDER_TOOLTIP_NON_STOP :{BLACK}Mainīt apstāšanās veidu atlasītajā rīkojumā STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}Piekraut pilnu ar jebkuru kravu STR_ORDER_DROP_LOAD_IF_POSSIBLE :Piekraut, ja ir pieejams STR_ORDER_DROP_FULL_LOAD_ALL :Visu kravu pilna piekraušana STR_ORDER_DROP_FULL_LOAD_ANY :Piekraut pilnu ar jebkuru kravu STR_ORDER_DROP_NO_LOADING :Bez iekraušanas STR_ORDER_TOOLTIP_FULL_LOAD :{BLACK}Mainīt iekraušanas veidu atlasītajā rīkojumā STR_ORDER_TOGGLE_UNLOAD :{BLACK}Izkraut visu STR_ORDER_DROP_UNLOAD_IF_ACCEPTED :Izkraut, ja kravu pieņem STR_ORDER_DROP_UNLOAD :Izkraut visu STR_ORDER_DROP_TRANSFER :Pārkraut STR_ORDER_DROP_NO_UNLOADING :Bez izkraušanas STR_ORDER_TOOLTIP_UNLOAD :{BLACK}Mainīt izkraušanas veidu atlasītajā rīkojumā STR_ORDER_REFIT :{BLACK}Pielāgot STR_ORDER_REFIT_TOOLTIP :{BLACK}Izvēlēties, uz kuru kravas veidu pārveidot rīkojumu. Ctrl+klikšķis, lai atceltu pārveidošanas norādījumu STR_ORDER_REFIT_AUTO :{BLACK}Automātiska pielāgošana STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}Izvēlēties kravas veidu, ko automātiski pielāgot šim rīkojumam. Ctrl+klikšķis, lai noņemtu pielāgošanas norādījumu. Automātiskā pielāgošana tiks veikta tikai tad, ja transportlīdzeklis to pieļauj STR_ORDER_DROP_REFIT_AUTO :Pastāvīga krava STR_ORDER_DROP_REFIT_AUTO_ANY :Pieejamā krava STR_ORDER_SERVICE :{BLACK}Apkope STR_ORDER_DROP_GO_ALWAYS_DEPOT :Vienmēr doties STR_ORDER_DROP_SERVICE_DEPOT :Apkope, ja nepieciešama STR_ORDER_DROP_HALT_DEPOT :Apstādināt STR_ORDER_SERVICE_TOOLTIP :{BLACK}Izlaist šo rīkojumu, izņemot ja vajadzīga apkope STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}Vehicle data to base jumping on # Conditional order variables, must follow order of OrderConditionVariable enum STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :Iekraušanas procenti STR_ORDER_CONDITIONAL_RELIABILITY :Uzticamība STR_ORDER_CONDITIONAL_MAX_SPEED :Maksimālais ātrums STR_ORDER_CONDITIONAL_AGE :Vecums (gadi) STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :Nepieciešama apkope STR_ORDER_CONDITIONAL_UNCONDITIONALLY :Vienmēr STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :Atlikušais kalpošanas laiks (gadi) STR_ORDER_CONDITIONAL_COMPARATOR_TOOLTIP :{BLACK}Kā salīdzināt transportlīdzekļa datus ar norādītajām vērtībām STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :ir vienāds ar STR_ORDER_CONDITIONAL_COMPARATOR_NOT_EQUALS :nav vienāds ar STR_ORDER_CONDITIONAL_COMPARATOR_LESS_THAN :ir mazāks par STR_ORDER_CONDITIONAL_COMPARATOR_LESS_EQUALS :ir mazāks vai vienāds ar STR_ORDER_CONDITIONAL_COMPARATOR_MORE_THAN :ir lielāks par STR_ORDER_CONDITIONAL_COMPARATOR_MORE_EQUALS :ir lielāks vai vienāds ar STR_ORDER_CONDITIONAL_COMPARATOR_IS_TRUE :ir patiess STR_ORDER_CONDITIONAL_COMPARATOR_IS_FALSE :ir nepatiess STR_ORDER_CONDITIONAL_VALUE_TOOLTIP :{BLACK}Vērtība transportlīdzekļa datu salīdzināšanai pret STR_ORDER_CONDITIONAL_VALUE_CAPT :{WHITE}Ievadīt vērtību ar kuru salīdzināt STR_ORDERS_SKIP_BUTTON :{BLACK}Izlaist STR_ORDERS_SKIP_TOOLTIP :{BLACK}Izlaist pašreizējo rīkojumu un doties pie nākamā. Ctrl+klikšķis izlaiž līdz atlasītajam rīkojumam STR_ORDERS_DELETE_BUTTON :{BLACK}Izdzēst STR_ORDERS_DELETE_TOOLTIP :{BLACK}Dzēst atzīmēto rīkojumu STR_ORDERS_DELETE_ALL_TOOLTIP :{BLACK}Dzēst visus rīkojumus STR_ORDERS_STOP_SHARING_BUTTON :{BLACK}Pārtraukt koplietošanu STR_ORDERS_STOP_SHARING_TOOLTIP :{BLACK}Pārtraukt rīkojumu koplietošanu. Ctrl+klikšķis papildus dzēš arī šī transportlīdzekļa rīkojumus STR_ORDERS_GO_TO_BUTTON :{BLACK}Doties uz STR_ORDER_GO_TO_NEAREST_DEPOT :Doties uz tuvāko depo STR_ORDER_GO_TO_NEAREST_HANGAR :Doties uz tuvāko angāru STR_ORDER_CONDITIONAL :Nosacītais rīkojuma lēciens STR_ORDER_SHARE :Koplietot rīkojumus STR_ORDERS_GO_TO_TOOLTIP :{BLACK}Ievietot jaunu rīkojumu pirms iezīmētā rīkojuma vai saraksta beigās. Ctrl izveido stacijas rīkojumu 'piekraut pilnu ar jebkuru kravu', liek braukt cauri pieturas punktam 'neapstājoties' un depo veikt 'apkopi'. 'Koplietot rīkojumus' vai Ctrl ļauj šim transportlīdzeklim lietot rīkojumus kopīgi ar atlasīto transportlīdzekli. Klikšķināšana uz transportlīdzekļa kopēs tā rīkojumus. Depo rīkojums izslēdz automātisko apkopi. STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}Rādīt visus ar šo plānu saistītos transportlīdzekļus # String parts to build the order string STR_ORDER_GO_TO_WAYPOINT :Dodas caur {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :Dodas caur {WAYPOINT} bez apstāšanās STR_ORDER_SERVICE_AT :Veikt apkopi STR_ORDER_SERVICE_NON_STOP_AT :Bezapstājas apkope STR_ORDER_NEAREST_DEPOT :tuvākais STR_ORDER_NEAREST_HANGAR :tuvākais angārs STR_ORDER_TRAIN_DEPOT :Vilcienu depo STR_ORDER_ROAD_VEHICLE_DEPOT :Autotransporta depo STR_ORDER_SHIP_DEPOT :Kuģu depo STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} STR_ORDER_REFIT_ORDER :(Pielāgot uz {STRING}) STR_ORDER_REFIT_STOP_ORDER :(Pielāgot uz {STRING} un apstāties) STR_ORDER_STOP_ORDER :(Apstādināt) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(Netieši) STR_ORDER_FULL_LOAD :(Piekraut pilnu) STR_ORDER_FULL_LOAD_ANY :(Piekraut pilnu ar jebkuru kravu) STR_ORDER_NO_LOAD :(Bez iekraušanas) STR_ORDER_UNLOAD :(Izkraut un paņemt kravu) STR_ORDER_UNLOAD_FULL_LOAD :(Izkraut un gaidīt pilnu piekraušanu) STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Izkraut un gaidīt jebkuru pilnu piekraušanu) STR_ORDER_UNLOAD_NO_LOAD :(Izkraut un atstāt tukšu) STR_ORDER_TRANSFER :(Pārkraut un paņemt kravu) STR_ORDER_TRANSFER_FULL_LOAD :(Pārkraut un gaidīt pilnu piekraušanu) STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Pārcelt un gaidīt jebkuru pilnu piekraušanu) STR_ORDER_TRANSFER_NO_LOAD :(Pārkraut un atstāt tukšu) STR_ORDER_NO_UNLOAD :(Neizkraut un paņemt kravu) STR_ORDER_NO_UNLOAD_FULL_LOAD :(Neizkraut un gaidīt pilnu kravu) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Neizkraut un gaidīt jebkuru pilnu kravu) STR_ORDER_NO_UNLOAD_NO_LOAD :(Bez izkraušanas un bez iekraušanas) STR_ORDER_AUTO_REFIT :(Automātiski pielāgot uz {STRING}) STR_ORDER_FULL_LOAD_REFIT :(Piekraut pilnu, ar automātisku pielāgošanu uz {STRING}) STR_ORDER_FULL_LOAD_ANY_REFIT :(Piekraut pilnu ar jebkuru kravu, ar automātisku pielāgošanu uz {STRING}) STR_ORDER_UNLOAD_REFIT :(Izkraut un paņemt kravu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Izkraut un gaidīt pilnu iekraušanu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Izkraut un gaidīt jebkuru pilnu iekraušanu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_TRANSFER_REFIT :(Pārsūtīt un paņemt kravu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Pārsūtīt un gaidīt pilnu iekraušanu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Izkraut un gaidīt pilnu iekraušanu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_NO_UNLOAD_REFIT :(Neizkraut un ņemt kravu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Neizkraut un gaidīt pilnu iekraušanu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Neizkraut un gaidīt jebkuru pilnu iekraušanu ar automātisku pielāgošanu uz {STRING}) STR_ORDER_AUTO_REFIT_ANY :pieejamā krava STR_ORDER_STOP_LOCATION_NEAR_END :[tuvākais gals] STR_ORDER_STOP_LOCATION_MIDDLE :[vidus] STR_ORDER_STOP_LOCATION_FAR_END :[tālākais gals] STR_ORDER_OUT_OF_RANGE :{RED} (Nākamais galamērķis ir ārpus apgabala) STR_ORDER_CONDITIONAL_UNCONDITIONAL :Lekt uz rīkojumu nr. {COMMA} STR_ORDER_CONDITIONAL_NUM :Lekt uz rīkojumu nr. {COMMA}, kad {STRING} {STRING} {COMMA} STR_ORDER_CONDITIONAL_TRUE_FALSE :Lekt uz rīkojumu nr. {COMMA}, kad {STRING} {STRING} STR_INVALID_ORDER :{RED} (Nederīgs rīkojums) # Time table window STR_TIMETABLE_TITLE :{WHITE}{VEHICLE} (Laiku saraksts) STR_TIMETABLE_ORDER_VIEW :{BLACK}Rīkojumi STR_TIMETABLE_ORDER_VIEW_TOOLTIP :{BLACK}Pārslēgt uz rīkojumu skatu STR_TIMETABLE_TOOLTIP :{BLACK}Saraksts - klikšķināt uz rīkojuma, lai to atlasītu STR_TIMETABLE_NO_TRAVEL :Bez braukšanas STR_TIMETABLE_NOT_TIMETABLEABLE :Ceļot (automātiski; pēc nākamā manuālā rīkojuma saraksta) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Braukšana (nav pēc saraksta) STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Braukt ar ne vairāk kā {2:VELOCITY} (nav sarakstā) STR_TIMETABLE_TRAVEL_FOR :Braukt līdz {STRING} STR_TIMETABLE_TRAVEL_FOR_SPEED :Braukt uz {STRING} ar ne vairāk kā {VELOCITY} STR_TIMETABLE_STAY_FOR :un palikt līdz {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :un braukt līdz {STRING} STR_TIMETABLE_DAYS :{COMMA}{NBSP}dien{P a as u} STR_TIMETABLE_TICKS :{COMMA}{NBSP}tik{P s i u} STR_TIMETABLE_TOTAL_TIME :{BLACK}Šis saraksts aizņems {STRING}, lai pabeigtu STR_TIMETABLE_TOTAL_TIME_INCOMPLETE :{BLACK}Šis saraksts aizņems vismaz {STRING} lai pabeigtu (nav viss pēc saraksta) STR_TIMETABLE_STATUS_ON_TIME :{BLACK}Šis transportlīdzeklis pašlaik iekļaujas laikā STR_TIMETABLE_STATUS_LATE :{BLACK}Šis transportlīdzeklis pašlaik {STRING} kavē STR_TIMETABLE_STATUS_EARLY :{BLACK}Šis transportlīdzeklis pašlaik {STRING} par agru STR_TIMETABLE_STATUS_NOT_STARTED :{BLACK}Šis saraksts vēl nav sācies STR_TIMETABLE_STATUS_START_AT :{BLACK}Šis saraksts sāksies {STRING} STR_TIMETABLE_STARTING_DATE :{BLACK}Sākuma datums STR_TIMETABLE_CHANGE_TIME :{BLACK}Mainīt laiku STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Mainīt iezīmētajam maršrutam nepieciešamo laiku STR_TIMETABLE_CLEAR_TIME :{BLACK}Notīrīt laiku STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Dzēst laiku atlasītajam rīkojumam STR_TIMETABLE_CHANGE_SPEED :{BLACK}Mainīt ātruma ierobežojumu STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Mainīt maksimālo braukšanas ātrumu atlasītajā rīkojumā STR_TIMETABLE_CLEAR_SPEED :{BLACK}Nodzēst ātruma ierobežojumu STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Nodzēst maksimālo braukšanas ātrumu atlasītajā rīkojumā STR_TIMETABLE_RESET_LATENESS :{BLACK}Atiestatīt kavējuma skaitītāju STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Atslēgt skaitītāju, lai transportlīdzeklis būtu laikā STR_TIMETABLE_AUTOFILL :{BLACK}Automātiska aizpildīšana STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Aizpildīt sarakstu automātiski ar vērtībām no nākošā ceļojuma (Ctrl+klikšķis lai mēģinātu paturēt gaidīšanas laikus) STR_TIMETABLE_EXPECTED :{BLACK}Paredzēts STR_TIMETABLE_SCHEDULED :{BLACK}Ieplānots STR_TIMETABLE_EXPECTED_TOOLTIP :{BLACK}Pārslēgties starp sagaidāmo un ieplānoto STR_TIMETABLE_ARRIVAL_ABBREVIATION :Ie: STR_TIMETABLE_DEPARTURE_ABBREVIATION :Iz: # Date window (for timetable) STR_DATE_CAPTION :{WHITE}Uzlikt datumu STR_DATE_SET_DATE :{BLACK}Uzlikt datumu STR_DATE_SET_DATE_TOOLTIP :{BLACK}Lietot izvēlēto datumu kā sākuma datumu sarakstam STR_DATE_DAY_TOOLTIP :{BLACK}Izvēlēties dienu STR_DATE_MONTH_TOOLTIP :{BLACK}Izvēlēties mēnesi STR_DATE_YEAR_TOOLTIP :{BLACK}Izvēlēties gadu # AI debug window STR_AI_DEBUG :{WHITE}MI/spēles skriptu atkļūdošana STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) STR_AI_DEBUG_NAME_TOOLTIP :{BLACK}Skripta nosaukums STR_AI_DEBUG_SETTINGS :{BLACK}Iestatījumi STR_AI_DEBUG_SETTINGS_TOOLTIP :{BLACK}Mainīt skripta iestatījumus STR_AI_DEBUG_RELOAD :{BLACK}Pārlādēt MI STR_AI_DEBUG_RELOAD_TOOLTIP :{BLACK}Apturēt MI, pārlādēt skriptu, un restartēt MI STR_AI_DEBUG_BREAK_STR_ON_OFF_TOOLTIP :{BLACK}Pārslēgt slēgšanu, kad MI ziņojums saskan ar slēgšanas ziņojumu STR_AI_DEBUG_BREAK_ON_LABEL :{BLACK}Slēgt, kad: STR_AI_DEBUG_BREAK_STR_OSKTITLE :{BLACK}Slēgt, kad STR_AI_DEBUG_BREAK_STR_TOOLTIP :{BLACK}Kad MI ziņojums saskanēs ar šo tekstu, spēle tiks pauzēta STR_AI_DEBUG_MATCH_CASE :{BLACK}Ievērot reģistru STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Pārslēgt lielo/mazo burtu ievērošanu, kad salīdzināt MI ziņojumus ar slēgšanas tekstu STR_AI_DEBUG_CONTINUE :{BLACK}Turpināt STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Atsākt un turpināt šo MI STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Attēlot šī MI atkļūdošanas izvadu STR_AI_GAME_SCRIPT :{BLACK}Spēles skripts STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Pārbaudīt spēles skriptu žurnālu STR_ERROR_AI_NO_AI_FOUND :Nav atrasts ielādei piemērots MI.{}Šis ir MI makets un spēlē tas neko nedarīs.{}Jūs varat lejupielādēt dažus MI no 'Tiešsaistes satura' sistēmas STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}Viens no strādājošiem skriptiem nobruka. Lūdzu, paziņojiet par šo gadījumu skripta autoram, pievienojot ekrānuzņēmumu ar MI/spēles skriptu atkļūdošanas logu STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}MI/spēles skriptu atkļūdošanas logs ir pieejams tikai serverim # AI configuration window STR_AI_CONFIG_CAPTION :{WHITE}MI/spēles skriptu konfigurācija STR_AI_CONFIG_GAMELIST_TOOLTIP :{BLACK}Spēles skripts, kas tiks ielādēts nākamajā spēlē STR_AI_CONFIG_AILIST_TOOLTIP :{BLACK}MI, kas tiks ielādēts nākamajā spēlē STR_AI_CONFIG_HUMAN_PLAYER :Spēlētājs (cilvēks) STR_AI_CONFIG_RANDOM_AI :Nejaušs MI STR_AI_CONFIG_NONE :(nav) STR_AI_CONFIG_MOVE_UP :{BLACK}Pacelt uz augšu STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Pacelt izvēlētos MI sarakstā uz augšu STR_AI_CONFIG_MOVE_DOWN :{BLACK}Nolaist uz leju STR_AI_CONFIG_MOVE_DOWN_TOOLTIP :{BLACK}Nolaist izvēlētos MI sarakstā uz leju STR_AI_CONFIG_GAMESCRIPT :{SILVER}Spēles skripti STR_AI_CONFIG_AI :{SILVER}MI STR_AI_CONFIG_CHANGE :{BLACK}Izvēlēties {STRING} STR_AI_CONFIG_CHANGE_NONE : STR_AI_CONFIG_CHANGE_AI :MI STR_AI_CONFIG_CHANGE_GAMESCRIPT :Spēles skripts STR_AI_CONFIG_CHANGE_TOOLTIP :{BLACK}Ielādēt citu skriptu STR_AI_CONFIG_CONFIGURE :{BLACK}Konfigurēt STR_AI_CONFIG_CONFIGURE_TOOLTIP :{BLACK}Konfigurēt skripta parametrus # Available AIs window STR_AI_LIST_CAPTION :{WHITE}Pieejamie {STRING} STR_AI_LIST_CAPTION_AI :MI STR_AI_LIST_CAPTION_GAMESCRIPT :Spēles skripti STR_AI_LIST_TOOLTIP :{BLACK}Klikšķināt, lai izvēlētos skriptu STR_AI_LIST_AUTHOR :{LTBLUE}Autors: {ORANGE}{STRING} STR_AI_LIST_VERSION :{LTBLUE}Versija: {ORANGE}{NUM} STR_AI_LIST_URL :{LTBLUE}Tīmekļa adrese: {ORANGE}{STRING} STR_AI_LIST_ACCEPT :{BLACK}Apstiprināt STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Izvēlēties izcelto skriptu STR_AI_LIST_CANCEL :{BLACK}Atcelt STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Nemainīt skriptu # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} parametri STR_AI_SETTINGS_CAPTION_AI :MI STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Spēles skripts STR_AI_SETTINGS_CLOSE :{BLACK}Aizvērt STR_AI_SETTINGS_RESET :{BLACK}Atiestatīt STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} STR_AI_SETTINGS_START_DELAY :Aptuvenais dienu skaits, līdz palaist šo MI pēc iepriekšējā: {ORANGE}{STRING} # Textfile window STR_TEXTFILE_README_CAPTION :{WHITE}{STRING} kopas {STRING} fails Lasi_mani STR_TEXTFILE_CHANGELOG_CAPTION :{WHITE}{STRING} kopas {STRING} izmaiņu žurnāls STR_TEXTFILE_LICENCE_CAPTION :{WHITE}{STRING} kopas {STRING} licence STR_TEXTFILE_WRAP_TEXT :{WHITE}Aplauzt tekstu STR_TEXTFILE_WRAP_TEXT_TOOLTIP :{BLACK}Aplauzt tekstu logā, lai tas viss iekļautos un nevajadzētu ritināt STR_TEXTFILE_VIEW_README :{BLACK}Skatīt failu Lasi_mani STR_TEXTFILE_VIEW_CHANGELOG :{BLACK}Izmaiņu žurnāls STR_TEXTFILE_VIEW_LICENCE :{BLACK}Licence # Vehicle loading indicators STR_PERCENT_UP_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_UP :{WHITE}{NUM}%{UP_ARROW} STR_PERCENT_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_DOWN :{WHITE}{NUM}%{DOWN_ARROW} STR_PERCENT_UP_DOWN_SMALL :{TINY_FONT}{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_UP_DOWN :{WHITE}{NUM}%{UP_ARROW}{DOWN_ARROW} STR_PERCENT_NONE_SMALL :{TINY_FONT}{WHITE}{NUM}% STR_PERCENT_NONE :{WHITE}{NUM}% # Income 'floats' STR_INCOME_FLOAT_COST_SMALL :{TINY_FONT}{RED}Izmaksas: {CURRENCY_LONG} STR_INCOME_FLOAT_COST :{RED}Izmaksas: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME_SMALL :{TINY_FONT}{GREEN}Ienākumi: {CURRENCY_LONG} STR_INCOME_FLOAT_INCOME :{GREEN}Ienākumi: {CURRENCY_LONG} STR_FEEDER_TINY :{TINY_FONT}{YELLOW}Pārskaita: {CURRENCY_LONG} STR_FEEDER :{YELLOW}Pārskaita: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_COST :{WHITE}Plānotās izmaksas: {CURRENCY_LONG} STR_MESSAGE_ESTIMATED_INCOME :{WHITE}Plānotie ienākumi: {CURRENCY_LONG} # Saveload messages STR_ERROR_SAVE_STILL_IN_PROGRESS :{WHITE}Notiek saglabāšana,{}lLūdzu uzgaidiet! STR_ERROR_AUTOSAVE_FAILED :{WHITE}Automātiskā saglabāšana neizdevās STR_ERROR_UNABLE_TO_READ_DRIVE :{BLACK}Nevar lasīt disku STR_ERROR_GAME_SAVE_FAILED :{WHITE}Spēles saglabāšana neizdevās{}{STRING} STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Nevar dzēst failu STR_ERROR_GAME_LOAD_FAILED :{WHITE}Spēles ielādēšana neizdevās{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Iekšēja kļūda: {STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Bojāts saglabātās spēles fails - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Spēle ir saglabāta ar jaunāku versiju STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Failu nevar nolasīt STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Failā nevar ierakstīt STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Datu integritātes pārbaude neizdevās STR_GAME_SAVELOAD_NOT_AVAILABLE :